diff --git a/clang/docs/analyzer/developer-docs/DebugChecks.rst b/clang/docs/analyzer/developer-docs/DebugChecks.rst index 3f9bed78604f0..05b3e2480d3b7 100644 --- a/clang/docs/analyzer/developer-docs/DebugChecks.rst +++ b/clang/docs/analyzer/developer-docs/DebugChecks.rst @@ -275,6 +275,28 @@ ExprInspection checks See clang_analyzer_denote(). +- ``void clang_analyzer_isTainted(a single argument of any type);`` + + Queries the analyzer whether the expression used as argument is tainted or not. + This is useful in tests, where we don't want to issue warning for all tainted + expressions but only check for certain expressions. + This would help to reduce the *noise* that the `TaintTest` debug checker would + introduce and let you focus on the `expected-warning`s that you really care + about. + + Example usage:: + + int read_integer() { + int n; + clang_analyzer_isTainted(n); // expected-warning{{NO}} + scanf("%d", &n); + clang_analyzer_isTainted(n); // expected-warning{{YES}} + clang_analyzer_isTainted(n + 2); // expected-warning{{YES}} + clang_analyzer_isTainted(n > 0); // expected-warning{{YES}} + int next_tainted_value = n; // no-warning + return n; + } + Statistics ========== diff --git a/clang/include/clang/AST/ASTImporter.h b/clang/include/clang/AST/ASTImporter.h index 490b34bf95e82..205d7ec67754f 100644 --- a/clang/include/clang/AST/ASTImporter.h +++ b/clang/include/clang/AST/ASTImporter.h @@ -16,6 +16,7 @@ #include "clang/AST/DeclBase.h" #include "clang/AST/DeclarationName.h" +#include "clang/AST/ExprCXX.h" #include "clang/AST/NestedNameSpecifier.h" #include "clang/AST/TemplateName.h" #include "clang/AST/Type.h" @@ -349,6 +350,10 @@ class TypeSourceInfo; return ToOrErr.takeError(); } + /// Import cleanup objects owned by ExprWithCleanup. + llvm::Expected + Import(ExprWithCleanups::CleanupObject From); + /// Import the given type from the "from" context into the "to" /// context. A null type is imported as a null type (no error). /// diff --git a/clang/include/clang/AST/Decl.h b/clang/include/clang/AST/Decl.h index 256daf1c13969..f5f5a0840b4dc 100644 --- a/clang/include/clang/AST/Decl.h +++ b/clang/include/clang/AST/Decl.h @@ -3500,6 +3500,7 @@ class EnumDecl : public TagDecl { /// negative enumerators of this enum. (see getNumNegativeBits) void setNumNegativeBits(unsigned Num) { EnumDeclBits.NumNegativeBits = Num; } +public: /// True if this tag declaration is a scoped enumeration. Only /// possible in C++11 mode. void setScoped(bool Scoped = true) { EnumDeclBits.IsScoped = Scoped; } @@ -3516,6 +3517,7 @@ class EnumDecl : public TagDecl { /// Microsoft-style enumeration with a fixed underlying type. void setFixed(bool Fixed = true) { EnumDeclBits.IsFixed = Fixed; } +private: /// True if a valid hash is stored in ODRHash. bool hasODRHash() const { return EnumDeclBits.HasODRHash; } void setHasODRHash(bool Hash = true) { EnumDeclBits.HasODRHash = Hash; } diff --git a/clang/include/clang/AST/DeclBase.h b/clang/include/clang/AST/DeclBase.h index 6dcebb4c5807b..dd639dec9ef02 100644 --- a/clang/include/clang/AST/DeclBase.h +++ b/clang/include/clang/AST/DeclBase.h @@ -626,7 +626,16 @@ class alignas(8) Decl { setModuleOwnershipKind(ModuleOwnershipKind::ModulePrivate); } - /// Set the owning module ID. +public: + /// Set the FromASTFile flag. This indicates that this declaration + /// was deserialized and not parsed from source code and enables + /// features such as module ownership information. + void setFromASTFile() { + FromASTFile = true; + } + + /// Set the owning module ID. This may only be called for + /// deserialized Decls. void setOwningModuleID(unsigned ID) { assert(isFromASTFile() && "Only works on a deserialized declaration"); *((unsigned*)this - 2) = ID; diff --git a/clang/include/clang/AST/DeclCXX.h b/clang/include/clang/AST/DeclCXX.h index 7e8b27626af31..3fd329393ec82 100644 --- a/clang/include/clang/AST/DeclCXX.h +++ b/clang/include/clang/AST/DeclCXX.h @@ -2387,17 +2387,6 @@ class CXXConstructorDecl final : ExplicitSpecKind::ResolvedFalse); } - void setExplicitSpecifier(ExplicitSpecifier ES) { - assert((!ES.getExpr() || - CXXConstructorDeclBits.HasTrailingExplicitSpecifier) && - "cannot set this explicit specifier. no trail-allocated space for " - "explicit"); - if (ES.getExpr()) - *getCanonicalDecl()->getTrailingObjects() = ES; - else - CXXConstructorDeclBits.IsSimpleExplicit = ES.isExplicit(); - } - enum TraillingAllocKind { TAKInheritsConstructor = 1, TAKHasTailExplicit = 1 << 1, @@ -2422,6 +2411,17 @@ class CXXConstructorDecl final ConstexprSpecKind ConstexprKind, InheritedConstructor Inherited = InheritedConstructor()); + void setExplicitSpecifier(ExplicitSpecifier ES) { + assert((!ES.getExpr() || + CXXConstructorDeclBits.HasTrailingExplicitSpecifier) && + "cannot set this explicit specifier. no trail-allocated space for " + "explicit"); + if (ES.getExpr()) + *getCanonicalDecl()->getTrailingObjects() = ES; + else + CXXConstructorDeclBits.IsSimpleExplicit = ES.isExplicit(); + } + ExplicitSpecifier getExplicitSpecifier() { return getCanonicalDecl()->getExplicitSpecifierInternal(); } @@ -2688,8 +2688,6 @@ class CXXConversionDecl : public CXXMethodDecl { ExplicitSpecifier ExplicitSpec; - void setExplicitSpecifier(ExplicitSpecifier ES) { ExplicitSpec = ES; } - public: friend class ASTDeclReader; friend class ASTDeclWriter; @@ -2711,6 +2709,7 @@ class CXXConversionDecl : public CXXMethodDecl { /// Return true if the declartion is already resolved to be explicit. bool isExplicit() const { return getExplicitSpecifier().isExplicit(); } + void setExplicitSpecifier(ExplicitSpecifier ES) { ExplicitSpec = ES; } /// Returns the type that this conversion function is converting to. QualType getConversionType() const { diff --git a/clang/include/clang/AST/DeclTemplate.h b/clang/include/clang/AST/DeclTemplate.h index 8b2c271fbf25c..a974c8baad9b9 100755 --- a/clang/include/clang/AST/DeclTemplate.h +++ b/clang/include/clang/AST/DeclTemplate.h @@ -1730,6 +1730,10 @@ class ClassTemplateSpecializationDecl return *TemplateArgs; } + void setTemplateArgs(TemplateArgumentList *Args) { + TemplateArgs = Args; + } + /// Determine the kind of specialization that this /// declaration represents. TemplateSpecializationKind getSpecializationKind() const { @@ -1762,6 +1766,10 @@ class ClassTemplateSpecializationDecl getTemplateSpecializationKind()); } + void setSpecializedTemplate(ClassTemplateDecl *Specialized) { + SpecializedTemplate = Specialized; + } + void setSpecializationKind(TemplateSpecializationKind TSK) { SpecializationKind = TSK; } diff --git a/clang/include/clang/AST/ExprCXX.h b/clang/include/clang/AST/ExprCXX.h index 1a16aa7aacec6..d16bd27edc23e 100644 --- a/clang/include/clang/AST/ExprCXX.h +++ b/clang/include/clang/AST/ExprCXX.h @@ -3306,13 +3306,15 @@ class DependentScopeDeclRefExpr final /// literal is the extent of the enclosing scope. class ExprWithCleanups final : public FullExpr, - private llvm::TrailingObjects { + private llvm::TrailingObjects< + ExprWithCleanups, + llvm::PointerUnion> { public: /// The type of objects that are kept in the cleanup. - /// It's useful to remember the set of blocks; we could also - /// remember the set of temporaries, but there's currently - /// no need. - using CleanupObject = BlockDecl *; + /// It's useful to remember the set of blocks and block-scoped compound + /// literals; we could also remember the set of temporaries, but there's + /// currently no need. + using CleanupObject = llvm::PointerUnion; private: friend class ASTStmtReader; diff --git a/clang/include/clang/AST/ExternalASTSource.h b/clang/include/clang/AST/ExternalASTSource.h index 899ac3f669371..68888fb02b3dd 100644 --- a/clang/include/clang/AST/ExternalASTSource.h +++ b/clang/include/clang/AST/ExternalASTSource.h @@ -173,7 +173,7 @@ class ExternalASTSource : public RefCountedBase { StringRef Path; StringRef ASTFile; ASTFileSignature Signature; - const Module *ClangModule = nullptr; + Module *ClangModule = nullptr; public: ASTSourceDescriptor() = default; @@ -181,13 +181,13 @@ class ExternalASTSource : public RefCountedBase { ASTFileSignature Signature) : PCHModuleName(std::move(Name)), Path(std::move(Path)), ASTFile(std::move(ASTFile)), Signature(Signature) {} - ASTSourceDescriptor(const Module &M); + ASTSourceDescriptor(Module &M); std::string getModuleName() const; StringRef getPath() const { return Path; } StringRef getASTFile() const { return ASTFile; } ASTFileSignature getSignature() const { return Signature; } - const Module *getModuleOrNull() const { return ClangModule; } + Module *getModuleOrNull() const { return ClangModule; } }; /// Return a descriptor for the corresponding module, if one exists. diff --git a/clang/include/clang/AST/NonTrivialTypeVisitor.h b/clang/include/clang/AST/NonTrivialTypeVisitor.h index ce389178b7b22..e9403763ab78b 100644 --- a/clang/include/clang/AST/NonTrivialTypeVisitor.h +++ b/clang/include/clang/AST/NonTrivialTypeVisitor.h @@ -1,4 +1,4 @@ -//===-- NonTrivialTypeVisitor.h - Visitor for non-trivial Types *- C++ --*-===// +//===-- NonTrivialTypeVisitor.h - Visitor for non-trivial Types -*- C++ -*-===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. diff --git a/clang/include/clang/AST/TextNodeDumper.h b/clang/include/clang/AST/TextNodeDumper.h index d293ea190aa43..c675beef63553 100644 --- a/clang/include/clang/AST/TextNodeDumper.h +++ b/clang/include/clang/AST/TextNodeDumper.h @@ -184,6 +184,7 @@ class TextNodeDumper void dumpBareDeclRef(const Decl *D); void dumpName(const NamedDecl *ND); void dumpAccessSpecifier(AccessSpecifier AS); + void dumpCleanupObject(const ExprWithCleanups::CleanupObject &C); void dumpDeclRef(const Decl *D, StringRef Label = {}); diff --git a/clang/include/clang/Analysis/AnalysisDeclContext.h b/clang/include/clang/Analysis/AnalysisDeclContext.h index 9faa78cde89c2..ed554feedead6 100644 --- a/clang/include/clang/Analysis/AnalysisDeclContext.h +++ b/clang/include/clang/Analysis/AnalysisDeclContext.h @@ -1,4 +1,4 @@ -// AnalysisDeclContext.h - Analysis context for Path Sens analysis -*- C++ -*-// +//===- AnalysisDeclContext.h - Context for path sensitivity -----*- C++ -*-===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. @@ -6,8 +6,11 @@ // //===----------------------------------------------------------------------===// // -// This file defines AnalysisDeclContext, a class that manages the analysis -// context data for path sensitive analysis. +/// \file +/// This file defines AnalysisDeclContext, a class that manages the analysis +/// context data for context sensitive and path sensitive analysis. +/// It also defines the helper classes to model entering, leaving or inlining +/// function calls. // //===----------------------------------------------------------------------===// @@ -64,14 +67,14 @@ class ManagedAnalysis { // which creates the analysis object given an AnalysisDeclContext. }; -/// AnalysisDeclContext contains the context data for the function or method -/// under analysis. +/// AnalysisDeclContext contains the context data for the function, method +/// or block under analysis. class AnalysisDeclContext { - /// Backpoint to the AnalysisManager object that created this - /// AnalysisDeclContext. This may be null. - AnalysisDeclContextManager *Manager; + // Backpoint to the AnalysisManager object that created this + // AnalysisDeclContext. This may be null. + AnalysisDeclContextManager *ADCMgr; - const Decl * const D; + const Decl *const D; std::unique_ptr cfg, completeCFG; std::unique_ptr cfgStmtMap; @@ -86,45 +89,36 @@ class AnalysisDeclContext { llvm::BumpPtrAllocator A; - llvm::DenseMap *ReferencedBlockVars = nullptr; + llvm::DenseMap *ReferencedBlockVars = nullptr; void *ManagedAnalyses = nullptr; public: - AnalysisDeclContext(AnalysisDeclContextManager *Mgr, - const Decl *D); + AnalysisDeclContext(AnalysisDeclContextManager *Mgr, const Decl *D); - AnalysisDeclContext(AnalysisDeclContextManager *Mgr, - const Decl *D, - const CFG::BuildOptions &BuildOptions); + AnalysisDeclContext(AnalysisDeclContextManager *Mgr, const Decl *D, + const CFG::BuildOptions &BuildOptions); ~AnalysisDeclContext(); ASTContext &getASTContext() const { return D->getASTContext(); } + const Decl *getDecl() const { return D; } - /// Return the AnalysisDeclContextManager (if any) that created - /// this AnalysisDeclContext. - AnalysisDeclContextManager *getManager() const { - return Manager; - } + AnalysisDeclContextManager *getManager() const { return ADCMgr; } - /// Return the build options used to construct the CFG. - CFG::BuildOptions &getCFGBuildOptions() { - return cfgBuildOptions; - } + CFG::BuildOptions &getCFGBuildOptions() { return cfgBuildOptions; } const CFG::BuildOptions &getCFGBuildOptions() const { return cfgBuildOptions; } - /// getAddEHEdges - Return true iff we are adding exceptional edges from - /// callExprs. If this is false, then try/catch statements and blocks - /// reachable from them can appear to be dead in the CFG, analysis passes must - /// cope with that. + /// \returns Whether we are adding exception handling edges from CallExprs. + /// If this is false, then try/catch statements and blocks reachable from them + /// can appear to be dead in the CFG, analysis passes must cope with that. bool getAddEHEdges() const { return cfgBuildOptions.AddEHEdges; } bool getUseUnoptimizedCFG() const { - return !cfgBuildOptions.PruneTriviallyFalseEdges; + return !cfgBuildOptions.PruneTriviallyFalseEdges; } bool getAddImplicitDtors() const { return cfgBuildOptions.AddImplicitDtors; } bool getAddInitializers() const { return cfgBuildOptions.AddInitializers; } @@ -132,25 +126,25 @@ class AnalysisDeclContext { void registerForcedBlockExpression(const Stmt *stmt); const CFGBlock *getBlockForRegisteredExpression(const Stmt *stmt); - /// Get the body of the Declaration. + /// \returns The body of the stored Decl \c D. Stmt *getBody() const; - /// Get the body of the Declaration. + /// \copydoc AnalysisDeclContext::getBody() /// \param[out] IsAutosynthesized Specifies if the body is auto-generated /// by the BodyFarm. Stmt *getBody(bool &IsAutosynthesized) const; - /// Checks if the body of the Decl is generated by the BodyFarm. + /// \returns Whether the body of the Decl \c D is generated by the BodyFarm. /// - /// Note, the lookup is not free. We are going to call getBody behind + /// \note The lookup is not free. We are going to call getBody behind /// the scenes. /// \sa getBody bool isBodyAutosynthesized() const; - /// Checks if the body of the Decl is generated by the BodyFarm from a - /// model file. + /// \returns Whether the body of the Decl \c D is generated by the BodyFarm + /// from a model file. /// - /// Note, the lookup is not free. We are going to call getBody behind + /// \note The lookup is not free. We are going to call getBody behind /// the scenes. /// \sa getBody bool isBodyAutosynthesizedFromModelFile() const; @@ -161,40 +155,41 @@ class AnalysisDeclContext { CFGReverseBlockReachabilityAnalysis *getCFGReachablityAnalysis(); - /// Return a version of the CFG without any edges pruned. + /// \returns A version of the CFG without any edges pruned. CFG *getUnoptimizedCFG(); void dumpCFG(bool ShowColors); - /// Returns true if we have built a CFG for this analysis context. - /// Note that this doesn't correspond to whether or not a valid CFG exists, it + /// \returns Whether we have built a CFG for this analysis context. + /// + /// \note This doesn't correspond to whether or not a valid CFG exists, it /// corresponds to whether we *attempted* to build one. bool isCFGBuilt() const { return builtCFG; } ParentMap &getParentMap(); - using referenced_decls_iterator = const VarDecl * const *; + using referenced_decls_iterator = const VarDecl *const *; llvm::iterator_range getReferencedBlockVars(const BlockDecl *BD); - /// Return the ImplicitParamDecl* associated with 'self' if this - /// AnalysisDeclContext wraps an ObjCMethodDecl. Returns NULL otherwise. + /// \returns The ImplicitParamDecl associated with \c self if this + /// AnalysisDeclContext wraps an ObjCMethodDecl or nullptr otherwise. const ImplicitParamDecl *getSelfDecl() const; - const StackFrameContext *getStackFrame(LocationContext const *Parent, + /// \copydoc LocationContextManager::getStackFrame() + const StackFrameContext *getStackFrame(LocationContext const *ParentLC, const Stmt *S, const CFGBlock *Blk, - unsigned BlockCount, unsigned Idx); + unsigned BlockCount, unsigned Index); + /// \copydoc LocationContextManager::getBlockInvocationContext() const BlockInvocationContext * - getBlockInvocationContext(const LocationContext *parent, - const BlockDecl *BD, - const void *ContextData); - - /// Return the specified analysis object, lazily running the analysis if - /// necessary. Return NULL if the analysis could not run. - template - T *getAnalysis() { + getBlockInvocationContext(const LocationContext *ParentLC, + const BlockDecl *BD, const void *Data); + + /// \returns The specified analysis object, lazily running the analysis if + /// necessary or nullptr if the analysis could not run. + template T *getAnalysis() { const void *tag = T::getTag(); ManagedAnalysis *&data = getAnalysisImpl(tag); if (!data) { @@ -203,19 +198,22 @@ class AnalysisDeclContext { return static_cast(data); } - /// Returns true if the root namespace of the given declaration is the 'std' - /// C++ namespace. + /// \returns Whether the root namespace of \p D is the \c std C++ namespace. static bool isInStdNamespace(const Decl *D); private: - ManagedAnalysis *&getAnalysisImpl(const void* tag); + ManagedAnalysis *&getAnalysisImpl(const void *tag); LocationContextManager &getLocationContextManager(); }; +/// It wraps the AnalysisDeclContext to represent both the call stack with +/// the help of StackFrameContext and inside the function calls the +/// BlockInvocationContext. It is needed for context sensitive analysis to +/// model entering, leaving or inlining function calls. class LocationContext : public llvm::FoldingSetNode { public: - enum ContextKind { StackFrame, Scope, Block }; + enum ContextKind { StackFrame, Block }; private: ContextKind Kind; @@ -229,8 +227,7 @@ class LocationContext : public llvm::FoldingSetNode { protected: LocationContext(ContextKind k, AnalysisDeclContext *ctx, - const LocationContext *parent, - int64_t ID) + const LocationContext *parent, int64_t ID) : Kind(k), Ctx(ctx), Parent(parent), ID(ID) {} public: @@ -238,9 +235,7 @@ class LocationContext : public llvm::FoldingSetNode { ContextKind getKind() const { return Kind; } - int64_t getID() const { - return ID; - } + int64_t getID() const { return ID; } AnalysisDeclContext *getAnalysisDeclContext() const { return Ctx; } @@ -248,58 +243,61 @@ class LocationContext : public llvm::FoldingSetNode { bool isParentOf(const LocationContext *LC) const; - const Decl *getDecl() const { return getAnalysisDeclContext()->getDecl(); } + const Decl *getDecl() const { return Ctx->getDecl(); } - CFG *getCFG() const { return getAnalysisDeclContext()->getCFG(); } + CFG *getCFG() const { return Ctx->getCFG(); } - template - T *getAnalysis() const { - return getAnalysisDeclContext()->getAnalysis(); - } + template T *getAnalysis() const { return Ctx->getAnalysis(); } - const ParentMap &getParentMap() const { - return getAnalysisDeclContext()->getParentMap(); - } + const ParentMap &getParentMap() const { return Ctx->getParentMap(); } - const ImplicitParamDecl *getSelfDecl() const { - return Ctx->getSelfDecl(); - } + /// \copydoc AnalysisDeclContext::getSelfDecl() + const ImplicitParamDecl *getSelfDecl() const { return Ctx->getSelfDecl(); } const StackFrameContext *getStackFrame() const; - /// Return true if the current LocationContext has no caller context. + /// \returns Whether the current LocationContext has no caller context. virtual bool inTopFrame() const; virtual void Profile(llvm::FoldingSetNodeID &ID) = 0; - void dumpStack( - raw_ostream &Out, const char *NL = "\n", - std::function printMoreInfoPerContext = - [](const LocationContext *) {}) const; + /// Prints out the call stack. + /// + /// \param Out The out stream. + LLVM_DUMP_METHOD void dumpStack(raw_ostream &Out) const; + /// Prints out the call stack in \c json format. + /// + /// \param Out The out stream. + /// \param NL The newline. + /// \param Space The space count for indentation. + /// \param IsDot Whether the output format is \c dot. + /// \param printMoreInfoPerContext + /// A callback to print more information for each context, for example: + /// \code + /// [&](const LocationContext *LC) { LC->dump(); } + /// \endcode void printJson( raw_ostream &Out, const char *NL = "\n", unsigned int Space = 0, bool IsDot = false, std::function printMoreInfoPerContext = [](const LocationContext *) {}) const; - void dump() const; + LLVM_DUMP_METHOD void dump() const; -public: - static void ProfileCommon(llvm::FoldingSetNodeID &ID, - ContextKind ck, + static void ProfileCommon(llvm::FoldingSetNodeID &ID, ContextKind ck, AnalysisDeclContext *ctx, - const LocationContext *parent, - const void *data); + const LocationContext *parent, const void *data); }; +/// It represents a stack frame of the call stack (based on CallEvent). class StackFrameContext : public LocationContext { friend class LocationContextManager; - // The callsite where this stack frame is established. + // The call site where this stack frame is established. const Stmt *CallSite; - // The parent block of the callsite. + // The parent block of the call site. const CFGBlock *Block; // The number of times the 'Block' has been visited. @@ -307,14 +305,14 @@ class StackFrameContext : public LocationContext { // called multiple times in a loop. const unsigned BlockCount; - // The index of the callsite in the CFGBlock. + // The index of the call site in the CFGBlock. const unsigned Index; - StackFrameContext(AnalysisDeclContext *ctx, const LocationContext *parent, - const Stmt *s, const CFGBlock *blk, unsigned blockCount, - unsigned idx, int64_t ID) - : LocationContext(StackFrame, ctx, parent, ID), CallSite(s), Block(blk), - BlockCount(blockCount), Index(idx) {} + StackFrameContext(AnalysisDeclContext *ADC, const LocationContext *ParentLC, + const Stmt *S, const CFGBlock *Block, unsigned BlockCount, + unsigned Index, int64_t ID) + : LocationContext(StackFrame, ADC, ParentLC, ID), CallSite(S), + Block(Block), BlockCount(BlockCount), Index(Index) {} public: ~StackFrameContext() override = default; @@ -323,117 +321,98 @@ class StackFrameContext : public LocationContext { const CFGBlock *getCallSiteBlock() const { return Block; } - /// Return true if the current LocationContext has no caller context. - bool inTopFrame() const override { return getParent() == nullptr; } + bool inTopFrame() const override { return getParent() == nullptr; } unsigned getIndex() const { return Index; } void Profile(llvm::FoldingSetNodeID &ID) override; - static void Profile(llvm::FoldingSetNodeID &ID, AnalysisDeclContext *ctx, - const LocationContext *parent, const Stmt *s, - const CFGBlock *blk, unsigned blockCount, unsigned idx) { - ProfileCommon(ID, StackFrame, ctx, parent, s); - ID.AddPointer(blk); - ID.AddInteger(blockCount); - ID.AddInteger(idx); + static void Profile(llvm::FoldingSetNodeID &ID, AnalysisDeclContext *ADC, + const LocationContext *ParentLC, const Stmt *S, + const CFGBlock *Block, unsigned BlockCount, + unsigned Index) { + ProfileCommon(ID, StackFrame, ADC, ParentLC, S); + ID.AddPointer(Block); + ID.AddInteger(BlockCount); + ID.AddInteger(Index); } - static bool classof(const LocationContext *Ctx) { - return Ctx->getKind() == StackFrame; - } -}; - -class ScopeContext : public LocationContext { - friend class LocationContextManager; - - const Stmt *Enter; - - ScopeContext(AnalysisDeclContext *ctx, const LocationContext *parent, - const Stmt *s, int64_t ID) - : LocationContext(Scope, ctx, parent, ID), Enter(s) {} - -public: - ~ScopeContext() override = default; - - void Profile(llvm::FoldingSetNodeID &ID) override; - - static void Profile(llvm::FoldingSetNodeID &ID, AnalysisDeclContext *ctx, - const LocationContext *parent, const Stmt *s) { - ProfileCommon(ID, Scope, ctx, parent, s); - } - - static bool classof(const LocationContext *Ctx) { - return Ctx->getKind() == Scope; + static bool classof(const LocationContext *LC) { + return LC->getKind() == StackFrame; } }; +/// It represents a block invocation (based on BlockCall). class BlockInvocationContext : public LocationContext { friend class LocationContextManager; const BlockDecl *BD; // FIXME: Come up with a more type-safe way to model context-sensitivity. - const void *ContextData; + const void *Data; - BlockInvocationContext(AnalysisDeclContext *ctx, - const LocationContext *parent, const BlockDecl *bd, - const void *contextData, int64_t ID) - : LocationContext(Block, ctx, parent, ID), BD(bd), - ContextData(contextData) {} + BlockInvocationContext(AnalysisDeclContext *ADC, + const LocationContext *ParentLC, const BlockDecl *BD, + const void *Data, int64_t ID) + : LocationContext(Block, ADC, ParentLC, ID), BD(BD), Data(Data) {} public: ~BlockInvocationContext() override = default; const BlockDecl *getBlockDecl() const { return BD; } - const void *getContextData() const { return ContextData; } + const void *getData() const { return Data; } void Profile(llvm::FoldingSetNodeID &ID) override; - static void Profile(llvm::FoldingSetNodeID &ID, AnalysisDeclContext *ctx, - const LocationContext *parent, const BlockDecl *bd, - const void *contextData) { - ProfileCommon(ID, Block, ctx, parent, bd); - ID.AddPointer(contextData); + static void Profile(llvm::FoldingSetNodeID &ID, AnalysisDeclContext *ADC, + const LocationContext *ParentLC, const BlockDecl *BD, + const void *Data) { + ProfileCommon(ID, Block, ADC, ParentLC, BD); + ID.AddPointer(Data); } - static bool classof(const LocationContext *Ctx) { - return Ctx->getKind() == Block; + static bool classof(const LocationContext *LC) { + return LC->getKind() == Block; } }; class LocationContextManager { llvm::FoldingSet Contexts; - /// ID used for generating a new location context. + // ID used for generating a new location context. int64_t NewID = 0; public: ~LocationContextManager(); - const StackFrameContext *getStackFrame(AnalysisDeclContext *ctx, - const LocationContext *parent, - const Stmt *s, const CFGBlock *blk, - unsigned blockCount, unsigned idx); - - const ScopeContext *getScope(AnalysisDeclContext *ctx, - const LocationContext *parent, - const Stmt *s); - + /// Obtain a context of the call stack using its parent context. + /// + /// \param ADC The AnalysisDeclContext. + /// \param ParentLC The parent context of this newly created context. + /// \param S The call. + /// \param Block The basic block. + /// \param BlockCount The current count of entering into \p Blk. + /// \param Index The index of \p Blk. + /// \returns The context for \p D with parent context \p ParentLC. + const StackFrameContext *getStackFrame(AnalysisDeclContext *ADC, + const LocationContext *ParentLC, + const Stmt *S, const CFGBlock *Block, + unsigned BlockCount, unsigned Index); + + /// Obtain a context of the block invocation using its parent context. + /// + /// \param ADC The AnalysisDeclContext. + /// \param ParentLC The parent context of this newly created context. + /// \param BD The BlockDecl. + /// \param Data The raw data to store as part of the context. const BlockInvocationContext * - getBlockInvocationContext(AnalysisDeclContext *ctx, - const LocationContext *parent, - const BlockDecl *BD, - const void *ContextData); + getBlockInvocationContext(AnalysisDeclContext *ADC, + const LocationContext *ParentLC, + const BlockDecl *BD, const void *Data); /// Discard all previously created LocationContext objects. void clear(); -private: - template - const LOC *getLocationContext(AnalysisDeclContext *ctx, - const LocationContext *parent, - const DATA *d); }; class AnalysisDeclContextManager { @@ -441,36 +420,31 @@ class AnalysisDeclContextManager { llvm::DenseMap>; ContextMap Contexts; - LocationContextManager LocContexts; + LocationContextManager LocCtxMgr; CFG::BuildOptions cfgBuildOptions; - /// Pointer to an interface that can provide function bodies for - /// declarations from external source. + // Pointer to an interface that can provide function bodies for + // declarations from external source. std::unique_ptr Injector; - /// A factory for creating and caching implementations for common - /// methods during the analysis. + // A factory for creating and caching implementations for common + // methods during the analysis. BodyFarm FunctionBodyFarm; - /// Flag to indicate whether or not bodies should be synthesized - /// for well-known functions. + // Flag to indicate whether or not bodies should be synthesized + // for well-known functions. bool SynthesizeBodies; public: - AnalysisDeclContextManager(ASTContext &ASTCtx, bool useUnoptimizedCFG = false, - bool addImplicitDtors = false, - bool addInitializers = false, - bool addTemporaryDtors = false, - bool addLifetime = false, - bool addLoopExit = false, - bool addScopes = false, - bool synthesizeBodies = false, - bool addStaticInitBranches = false, - bool addCXXNewAllocator = true, - bool addRichCXXConstructors = true, - bool markElidedCXXConstructors = true, - bool addVirtualBaseBranches = true, - CodeInjector *injector = nullptr); + AnalysisDeclContextManager( + ASTContext &ASTCtx, bool useUnoptimizedCFG = false, + bool addImplicitDtors = false, bool addInitializers = false, + bool addTemporaryDtors = false, bool addLifetime = false, + bool addLoopExit = false, bool addScopes = false, + bool synthesizeBodies = false, bool addStaticInitBranches = false, + bool addCXXNewAllocator = true, bool addRichCXXConstructors = true, + bool markElidedCXXConstructors = true, bool addVirtualBaseBranches = true, + CodeInjector *injector = nullptr); AnalysisDeclContext *getContext(const Decl *D); @@ -478,37 +452,27 @@ class AnalysisDeclContextManager { return !cfgBuildOptions.PruneTriviallyFalseEdges; } - CFG::BuildOptions &getCFGBuildOptions() { - return cfgBuildOptions; - } + CFG::BuildOptions &getCFGBuildOptions() { return cfgBuildOptions; } - /// Return true if faux bodies should be synthesized for well-known - /// functions. + /// \returns Whether faux bodies should be synthesized for known functions. bool synthesizeBodies() const { return SynthesizeBodies; } - const StackFrameContext *getStackFrame(AnalysisDeclContext *Ctx, - const LocationContext *Parent, - const Stmt *S, const CFGBlock *Blk, - unsigned BlockCount, unsigned Idx) { - return LocContexts.getStackFrame(Ctx, Parent, S, Blk, BlockCount, Idx); - } - - // Get the top level stack frame. + /// Obtain the beginning context of the analysis. + /// + /// \returns The top level stack frame for \p D. const StackFrameContext *getStackFrame(const Decl *D) { - return LocContexts.getStackFrame(getContext(D), nullptr, nullptr, nullptr, - 0, 0); + return LocCtxMgr.getStackFrame(getContext(D), nullptr, nullptr, nullptr, 0, + 0); } - // Get a stack frame with parent. - StackFrameContext const *getStackFrame(const Decl *D, + /// \copydoc LocationContextManager::getStackFrame() + const StackFrameContext *getStackFrame(AnalysisDeclContext *ADC, const LocationContext *Parent, - const Stmt *S, const CFGBlock *Blk, - unsigned BlockCount, unsigned Idx) { - return LocContexts.getStackFrame(getContext(D), Parent, S, Blk, BlockCount, - Idx); + const Stmt *S, const CFGBlock *Block, + unsigned BlockCount, unsigned Index) { + return LocCtxMgr.getStackFrame(ADC, Parent, S, Block, BlockCount, Index); } - /// Get a reference to {@code BodyFarm} instance. BodyFarm &getBodyFarm(); /// Discard all previously created AnalysisDeclContexts. @@ -517,9 +481,7 @@ class AnalysisDeclContextManager { private: friend class AnalysisDeclContext; - LocationContextManager &getLocationContextManager() { - return LocContexts; - } + LocationContextManager &getLocationContextManager() { return LocCtxMgr; } }; } // namespace clang diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td index daf581f6dae60..c849b224c01b2 100644 --- a/clang/include/clang/Basic/DiagnosticSemaKinds.td +++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td @@ -770,6 +770,11 @@ def err_ptrauth_string_not_literal : Error< def err_ptrauth_type_disc_variably_modified : Error< "cannot pass variably-modified type %0 to " "'__builtin_ptrauth_type_discriminator'">; +def note_ptrauth_virtual_function_pointer_incomplete_arg_ret : + Note<"cannot take an address of a virtual member function if its return or " + "argument types are incomplete">; +def note_ptrauth_virtual_function_incomplete_arg_ret_type : + Note<"%0 is incomplete">; // __ptrauth qualifier def err_ptrauth_qualifier_return : Error< @@ -4130,6 +4135,10 @@ def note_ovl_candidate_bad_ownership : Note< "%select{no|__unsafe_unretained|__strong|__weak|__autoreleasing}4 ownership," " but parameter has %select{no|__unsafe_unretained|__strong|__weak|" "__autoreleasing}5 ownership">; +def note_ovl_candidate_bad_ptrauth : Note< + "candidate %sub{select_ovl_candidate_kind}0,1,2 not viable: " + "%ordinal8 argument (%3) has %select{no ptrauth|%5}4 qualifier," + " but parameter has %select{no ptrauth|%7}6 qualifier">; def note_ovl_candidate_bad_cvr_this : Note< "candidate %sub{select_ovl_candidate_kind}0,1,2 not viable: " "'this' argument has type %3, but method is not marked " @@ -5500,6 +5509,8 @@ def note_enters_block_captures_weak : Note< def note_enters_block_captures_non_trivial_c_struct : Note< "jump enters lifetime of block which captures a C struct that is non-trivial " "to destroy">; +def note_enters_compound_literal_scope : Note< + "jump enters lifetime of a compound literal that is non-trivial to destruct">; def note_exits_cleanup : Note< "jump exits scope of variable with __attribute__((cleanup))">; @@ -5543,6 +5554,8 @@ def note_exits_block_captures_weak : Note< def note_exits_block_captures_non_trivial_c_struct : Note< "jump exits lifetime of block which captures a C struct that is non-trivial " "to destroy">; +def note_exits_compound_literal_scope : Note< + "jump exits lifetime of a compound literal that is non-trivial to destruct">; def err_func_returning_qualified_void : ExtWarn< "function cannot return qualified void type %0">, diff --git a/clang/include/clang/Frontend/FrontendAction.h b/clang/include/clang/Frontend/FrontendAction.h index e994e24cf5afa..c9f9f080c1413 100644 --- a/clang/include/clang/Frontend/FrontendAction.h +++ b/clang/include/clang/Frontend/FrontendAction.h @@ -312,6 +312,7 @@ class WrapperFrontendAction : public FrontendAction { bool BeginSourceFileAction(CompilerInstance &CI) override; void ExecuteAction() override; void EndSourceFileAction() override; + bool shouldEraseOutputFiles() override; public: /// Construct a WrapperFrontendAction from an existing action, taking diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h index a260aec2a536b..64c467acce8c2 100644 --- a/clang/include/clang/Sema/Sema.h +++ b/clang/include/clang/Sema/Sema.h @@ -603,9 +603,8 @@ class Sema final { CleanupInfo Cleanup; /// ExprCleanupObjects - This is the stack of objects requiring - /// cleanup that are created by the current full expression. The - /// element type here is ExprWithCleanups::Object. - SmallVector ExprCleanupObjects; + /// cleanup that are created by the current full expression. + SmallVector ExprCleanupObjects; /// Store a set of either DeclRefExprs or MemberExprs that contain a reference /// to a variable (constant) that may or may not be odr-used in this Expr, and diff --git a/clang/include/clang/Serialization/ASTBitCodes.h b/clang/include/clang/Serialization/ASTBitCodes.h index f748f04298a9b..e2e057714742d 100644 --- a/clang/include/clang/Serialization/ASTBitCodes.h +++ b/clang/include/clang/Serialization/ASTBitCodes.h @@ -1876,6 +1876,9 @@ namespace serialization { CTOR_INITIALIZER_INDIRECT_MEMBER }; + /// Kinds of cleanup objects owned by ExprWithCleanups. + enum CleanupObjectKind { COK_Block, COK_CompoundLiteral }; + /// Describes the redeclarations of a declaration. struct LocalRedeclarationsInfo { // The ID of the first declaration diff --git a/clang/include/clang/StaticAnalyzer/Core/AnalyzerOptions.def b/clang/include/clang/StaticAnalyzer/Core/AnalyzerOptions.def index 00febf6881954..ee67f60df9488 100644 --- a/clang/include/clang/StaticAnalyzer/Core/AnalyzerOptions.def +++ b/clang/include/clang/StaticAnalyzer/Core/AnalyzerOptions.def @@ -306,8 +306,8 @@ ANALYZER_OPTION(bool, ShouldTrackConditionsDebug, "track-conditions-debug", "Whether to place an event at each tracked condition.", false) -ANALYZER_OPTION(bool, ShouldEmitFixItHintsAsRemarks, "fixits-as-remarks", - "Emit fix-it hints as remarks for testing purposes", +ANALYZER_OPTION(bool, ShouldApplyFixIts, "apply-fixits", + "Apply the fix-it hints to the files", false) //===----------------------------------------------------------------------===// diff --git a/clang/include/clang/StaticAnalyzer/Core/BugReporter/BugReporter.h b/clang/include/clang/StaticAnalyzer/Core/BugReporter/BugReporter.h index 69593e2b6c931..7112fa125ef0e 100644 --- a/clang/include/clang/StaticAnalyzer/Core/BugReporter/BugReporter.h +++ b/clang/include/clang/StaticAnalyzer/Core/BugReporter/BugReporter.h @@ -722,7 +722,8 @@ class BugReporterContext { class NoteTag : public ProgramPointTag { public: using Callback = - std::function; + std::function; private: static int Kind; @@ -739,7 +740,7 @@ class NoteTag : public ProgramPointTag { } Optional generateMessage(BugReporterContext &BRC, - BugReport &R) const { + PathSensitiveBugReport &R) const { std::string Msg = Cb(BRC, R); if (Msg.empty()) return None; diff --git a/clang/include/clang/StaticAnalyzer/Core/CheckerManager.h b/clang/include/clang/StaticAnalyzer/Core/CheckerManager.h index 246ff8f90d354..4454d7603b27f 100644 --- a/clang/include/clang/StaticAnalyzer/Core/CheckerManager.h +++ b/clang/include/clang/StaticAnalyzer/Core/CheckerManager.h @@ -140,14 +140,14 @@ class CheckerManager { void finishedCheckerRegistration(); const LangOptions &getLangOpts() const { return LangOpts; } - AnalyzerOptions &getAnalyzerOptions() { return AOptions; } - ASTContext &getASTContext() { return Context; } + AnalyzerOptions &getAnalyzerOptions() const { return AOptions; } + ASTContext &getASTContext() const { return Context; } /// Emits an error through a DiagnosticsEngine about an invalid user supplied /// checker option value. void reportInvalidCheckerOptionValue(const CheckerBase *C, StringRef OptionName, - StringRef ExpectedValueDesc); + StringRef ExpectedValueDesc) const; using CheckerRef = CheckerBase *; using CheckerTag = const void *; @@ -620,7 +620,7 @@ class CheckerManager { /// Returns the checkers that have registered for callbacks of the /// given \p Kind. const std::vector & - getObjCMessageCheckers(ObjCMessageVisitKind Kind); + getObjCMessageCheckers(ObjCMessageVisitKind Kind) const; std::vector PreObjCMessageCheckers; std::vector PostObjCMessageCheckers; diff --git a/clang/include/clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h b/clang/include/clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h index ab6a704ab8cf5..323a1a212bce8 100644 --- a/clang/include/clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h +++ b/clang/include/clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h @@ -889,6 +889,23 @@ class CXXConstructorCall : public AnyCXXConstructorCall { /// Represents a call to a C++ inherited constructor. /// /// Example: \c class T : public S { using S::S; }; T(1); +/// +// Note, it is difficult to model the parameters. This is one of the reasons +// why we skip analysis of inheriting constructors as top-level functions. +// CXXInheritedCtorInitExpr doesn't take arguments and doesn't model parameter +// initialization because there is none: the arguments in the outer +// CXXConstructExpr directly initialize the parameters of the base class +// constructor, and no copies are made. (Making a copy of the parameter is +// incorrect, at least if it's done in an observable way.) The derived class +// constructor doesn't even exist in the formal model. +/// E.g., in: +/// +/// struct X { X *p = this; ~X() {} }; +/// struct A { A(X x) : b(x.p == &x) {} bool b; }; +/// struct B : A { using A::A; }; +/// B b = X{}; +/// +/// ... b.b is initialized to true. class CXXInheritedConstructorCall : public AnyCXXConstructorCall { friend class CallEventManager; diff --git a/clang/include/clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h b/clang/include/clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h index bd8760cf0ce0c..f4181f3beab99 100644 --- a/clang/include/clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h +++ b/clang/include/clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h @@ -256,10 +256,12 @@ class CheckerContext { /// @param IsPrunable Whether the note is prunable. It allows BugReporter /// to omit the note from the report if it would make the displayed /// bug path significantly shorter. - const NoteTag *getNoteTag(std::function &&Cb, - bool IsPrunable = false) { + const NoteTag + *getNoteTag(std::function &&Cb, + bool IsPrunable = false) { return getNoteTag( - [Cb](BugReporterContext &, BugReport &BR) { return Cb(BR); }, + [Cb](BugReporterContext &, + PathSensitiveBugReport &BR) { return Cb(BR); }, IsPrunable); } @@ -272,7 +274,8 @@ class CheckerContext { /// bug path significantly shorter. const NoteTag *getNoteTag(std::function &&Cb, bool IsPrunable = false) { - return getNoteTag([Cb](BugReporterContext &, BugReport &) { return Cb(); }, + return getNoteTag([Cb](BugReporterContext &, + PathSensitiveBugReport &) { return Cb(); }, IsPrunable); } @@ -284,7 +287,9 @@ class CheckerContext { /// bug path significantly shorter. const NoteTag *getNoteTag(StringRef Note, bool IsPrunable = false) { return getNoteTag( - [Note](BugReporterContext &, BugReport &) { return Note; }, IsPrunable); + [Note](BugReporterContext &, + PathSensitiveBugReport &) { return std::string(Note); }, + IsPrunable); } /// Returns the word that should be used to refer to the declaration diff --git a/clang/include/clang/StaticAnalyzer/Frontend/CheckerRegistry.h b/clang/include/clang/StaticAnalyzer/Frontend/CheckerRegistry.h index bc258160ada49..269c226f2e1d1 100644 --- a/clang/include/clang/StaticAnalyzer/Frontend/CheckerRegistry.h +++ b/clang/include/clang/StaticAnalyzer/Frontend/CheckerRegistry.h @@ -204,16 +204,14 @@ class CheckerRegistry { using PackageInfoList = llvm::SmallVector; -private: - template static void initializeManager(CheckerManager &mgr) { + template static void addToCheckerMgr(CheckerManager &mgr) { mgr.registerChecker(); } - template static bool returnTrue(const LangOptions &LO) { + static bool returnTrue(const LangOptions &LO) { return true; } -public: /// Adds a checker to the registry. Use this non-templated overload when your /// checker requires custom initialization. void addChecker(InitializationFunction Fn, ShouldRegisterFunction sfn, @@ -227,9 +225,8 @@ class CheckerRegistry { bool IsHidden = false) { // Avoid MSVC's Compiler Error C2276: // http://msdn.microsoft.com/en-us/library/850cstw1(v=VS.80).aspx - addChecker(&CheckerRegistry::initializeManager, - &CheckerRegistry::returnTrue, FullName, Desc, DocsUri, - IsHidden); + addChecker(&CheckerRegistry::addToCheckerMgr, + &CheckerRegistry::returnTrue, FullName, Desc, DocsUri, IsHidden); } /// Makes the checker with the full name \p fullName depends on the checker diff --git a/clang/lib/AST/ASTImporter.cpp b/clang/lib/AST/ASTImporter.cpp index f1d97c96916e6..b6cc8e0592198 100644 --- a/clang/lib/AST/ASTImporter.cpp +++ b/clang/lib/AST/ASTImporter.cpp @@ -8045,6 +8045,18 @@ void ASTImporter::RegisterImportedDecl(Decl *FromD, Decl *ToD) { MapImported(FromD, ToD); } +llvm::Expected +ASTImporter::Import(ExprWithCleanups::CleanupObject From) { + if (auto *CLE = From.dyn_cast()) { + if (Expected R = Import(CLE)) + return ExprWithCleanups::CleanupObject(cast(*R)); + } + + // FIXME: Handle BlockDecl when we implement importing BlockExpr in + // ASTNodeImporter. + return make_error(ImportError::UnsupportedConstruct); +} + Expected ASTImporter::Import(QualType FromT) { if (FromT.isNull()) return QualType{}; diff --git a/clang/lib/AST/Expr.cpp b/clang/lib/AST/Expr.cpp index 73ddbc62482dd..b25afb87bb5d0 100644 --- a/clang/lib/AST/Expr.cpp +++ b/clang/lib/AST/Expr.cpp @@ -1685,6 +1685,11 @@ MemberExpr *MemberExpr::Create( CXXRecordDecl *RD = dyn_cast_or_null(DC); if (RD && RD->isDependentContext() && RD->isCurrentInstantiation(DC)) E->setTypeDependent(T->isDependentType()); + + // Bitfield with value-dependent width is type-dependent. + FieldDecl *FD = dyn_cast(MemberDecl); + if (FD && FD->isBitField() && FD->getBitWidth()->isValueDependent()) + E->setTypeDependent(true); } if (HasQualOrFound) { @@ -3206,6 +3211,9 @@ bool Expr::isConstantInitializer(ASTContext &Ctx, bool IsForRef, switch (getStmtClass()) { default: break; + case Stmt::ExprWithCleanupsClass: + return cast(this)->getSubExpr()->isConstantInitializer( + Ctx, IsForRef, Culprit); case StringLiteralClass: case ObjCEncodeExprClass: return true; diff --git a/clang/lib/AST/ExternalASTSource.cpp b/clang/lib/AST/ExternalASTSource.cpp index 837be5527fce3..656d22e6d5aa2 100644 --- a/clang/lib/AST/ExternalASTSource.cpp +++ b/clang/lib/AST/ExternalASTSource.cpp @@ -38,7 +38,7 @@ ExternalASTSource::hasExternalDefinitions(const Decl *D) { return EK_ReplyHazy; } -ExternalASTSource::ASTSourceDescriptor::ASTSourceDescriptor(const Module &M) +ExternalASTSource::ASTSourceDescriptor::ASTSourceDescriptor(Module &M) : Signature(M.Signature), ClangModule(&M) { if (M.Directory) Path = M.Directory->getName(); diff --git a/clang/lib/AST/JSONNodeDumper.cpp b/clang/lib/AST/JSONNodeDumper.cpp index fa5fe0bcbc0ba..569ac14c8f90a 100644 --- a/clang/lib/AST/JSONNodeDumper.cpp +++ b/clang/lib/AST/JSONNodeDumper.cpp @@ -1335,7 +1335,16 @@ void JSONNodeDumper::VisitExprWithCleanups(const ExprWithCleanups *EWC) { if (EWC->getNumObjects()) { JOS.attributeArray("cleanups", [this, EWC] { for (const ExprWithCleanups::CleanupObject &CO : EWC->getObjects()) - JOS.value(createBareDeclRef(CO)); + if (auto *BD = CO.dyn_cast()) { + JOS.value(createBareDeclRef(BD)); + } else if (auto *CLE = CO.dyn_cast()) { + llvm::json::Object Obj; + Obj["id"] = createPointerRepresentation(CLE); + Obj["kind"] = CLE->getStmtClassName(); + JOS.value(std::move(Obj)); + } else { + llvm_unreachable("unexpected cleanup object type"); + } }); } } diff --git a/clang/lib/AST/TextNodeDumper.cpp b/clang/lib/AST/TextNodeDumper.cpp index 5ad8fd77d5eb0..86ae7eedfed68 100644 --- a/clang/lib/AST/TextNodeDumper.cpp +++ b/clang/lib/AST/TextNodeDumper.cpp @@ -447,6 +447,23 @@ void TextNodeDumper::dumpAccessSpecifier(AccessSpecifier AS) { } } +void TextNodeDumper::dumpCleanupObject( + const ExprWithCleanups::CleanupObject &C) { + if (auto *BD = C.dyn_cast()) + dumpDeclRef(BD, "cleanup"); + else if (auto *CLE = C.dyn_cast()) + AddChild([=] { + OS << "cleanup "; + { + ColorScope Color(OS, ShowColors, StmtColor); + OS << CLE->getStmtClassName(); + } + dumpPointer(CLE); + }); + else + llvm_unreachable("unexpected cleanup type"); +} + void TextNodeDumper::dumpDeclRef(const Decl *D, StringRef Label) { if (!D) return; @@ -952,7 +969,7 @@ void TextNodeDumper::VisitMaterializeTemporaryExpr( void TextNodeDumper::VisitExprWithCleanups(const ExprWithCleanups *Node) { for (unsigned i = 0, e = Node->getNumObjects(); i != e; ++i) - dumpDeclRef(Node->getObject(i), "cleanup"); + dumpCleanupObject(Node->getObject(i)); } void TextNodeDumper::VisitSizeOfPackExpr(const SizeOfPackExpr *Node) { diff --git a/clang/lib/Analysis/AnalysisDeclContext.cpp b/clang/lib/Analysis/AnalysisDeclContext.cpp index 9f58b5079c760..96d5807bcdfc0 100644 --- a/clang/lib/Analysis/AnalysisDeclContext.cpp +++ b/clang/lib/Analysis/AnalysisDeclContext.cpp @@ -52,16 +52,16 @@ using namespace clang; using ManagedAnalysisMap = llvm::DenseMap; -AnalysisDeclContext::AnalysisDeclContext(AnalysisDeclContextManager *Mgr, - const Decl *d, - const CFG::BuildOptions &buildOptions) - : Manager(Mgr), D(d), cfgBuildOptions(buildOptions) { +AnalysisDeclContext::AnalysisDeclContext(AnalysisDeclContextManager *ADCMgr, + const Decl *D, + const CFG::BuildOptions &Options) + : ADCMgr(ADCMgr), D(D), cfgBuildOptions(Options) { cfgBuildOptions.forcedBlkExprs = &forcedBlkExprs; } -AnalysisDeclContext::AnalysisDeclContext(AnalysisDeclContextManager *Mgr, - const Decl *d) - : Manager(Mgr), D(d) { +AnalysisDeclContext::AnalysisDeclContext(AnalysisDeclContextManager *ADCMgr, + const Decl *D) + : ADCMgr(ADCMgr), D(D) { cfgBuildOptions.forcedBlkExprs = &forcedBlkExprs; } @@ -96,8 +96,8 @@ Stmt *AnalysisDeclContext::getBody(bool &IsAutosynthesized) const { Stmt *Body = FD->getBody(); if (auto *CoroBody = dyn_cast_or_null(Body)) Body = CoroBody->getBody(); - if (Manager && Manager->synthesizeBodies()) { - Stmt *SynthesizedBody = Manager->getBodyFarm().getBody(FD); + if (ADCMgr && ADCMgr->synthesizeBodies()) { + Stmt *SynthesizedBody = ADCMgr->getBodyFarm().getBody(FD); if (SynthesizedBody) { Body = SynthesizedBody; IsAutosynthesized = true; @@ -107,8 +107,8 @@ Stmt *AnalysisDeclContext::getBody(bool &IsAutosynthesized) const { } else if (const auto *MD = dyn_cast(D)) { Stmt *Body = MD->getBody(); - if (Manager && Manager->synthesizeBodies()) { - Stmt *SynthesizedBody = Manager->getBodyFarm().getBody(MD); + if (ADCMgr && ADCMgr->synthesizeBodies()) { + Stmt *SynthesizedBody = ADCMgr->getBodyFarm().getBody(MD); if (SynthesizedBody) { Body = SynthesizedBody; IsAutosynthesized = true; @@ -309,19 +309,17 @@ AnalysisDeclContext *AnalysisDeclContextManager::getContext(const Decl *D) { BodyFarm &AnalysisDeclContextManager::getBodyFarm() { return FunctionBodyFarm; } const StackFrameContext * -AnalysisDeclContext::getStackFrame(LocationContext const *Parent, const Stmt *S, - const CFGBlock *Blk, unsigned BlockCount, - unsigned Idx) { - return getLocationContextManager().getStackFrame(this, Parent, S, Blk, - BlockCount, Idx); +AnalysisDeclContext::getStackFrame(const LocationContext *ParentLC, + const Stmt *S, const CFGBlock *Blk, + unsigned BlockCount, unsigned Index) { + return getLocationContextManager().getStackFrame(this, ParentLC, S, Blk, + BlockCount, Index); } -const BlockInvocationContext * -AnalysisDeclContext::getBlockInvocationContext(const LocationContext *parent, - const BlockDecl *BD, - const void *ContextData) { - return getLocationContextManager().getBlockInvocationContext(this, parent, - BD, ContextData); +const BlockInvocationContext *AnalysisDeclContext::getBlockInvocationContext( + const LocationContext *ParentLC, const BlockDecl *BD, const void *Data) { + return getLocationContextManager().getBlockInvocationContext(this, ParentLC, + BD, Data); } bool AnalysisDeclContext::isInStdNamespace(const Decl *D) { @@ -340,9 +338,10 @@ bool AnalysisDeclContext::isInStdNamespace(const Decl *D) { } LocationContextManager &AnalysisDeclContext::getLocationContextManager() { - assert(Manager && - "Cannot create LocationContexts without an AnalysisDeclContextManager!"); - return Manager->getLocationContextManager(); + assert( + ADCMgr && + "Cannot create LocationContexts without an AnalysisDeclContextManager!"); + return ADCMgr->getLocationContextManager(); } //===----------------------------------------------------------------------===// @@ -365,36 +364,14 @@ void StackFrameContext::Profile(llvm::FoldingSetNodeID &ID) { BlockCount, Index); } -void ScopeContext::Profile(llvm::FoldingSetNodeID &ID) { - Profile(ID, getAnalysisDeclContext(), getParent(), Enter); -} - void BlockInvocationContext::Profile(llvm::FoldingSetNodeID &ID) { - Profile(ID, getAnalysisDeclContext(), getParent(), BD, ContextData); + Profile(ID, getAnalysisDeclContext(), getParent(), BD, Data); } //===----------------------------------------------------------------------===// // LocationContext creation. //===----------------------------------------------------------------------===// -template -const LOC* -LocationContextManager::getLocationContext(AnalysisDeclContext *ctx, - const LocationContext *parent, - const DATA *d) { - llvm::FoldingSetNodeID ID; - LOC::Profile(ID, ctx, parent, d); - void *InsertPos; - - LOC *L = cast_or_null(Contexts.FindNodeOrInsertPos(ID, InsertPos)); - - if (!L) { - L = new LOC(ctx, parent, d, ++NewID); - Contexts.InsertNode(L, InsertPos); - } - return L; -} - const StackFrameContext *LocationContextManager::getStackFrame( AnalysisDeclContext *ctx, const LocationContext *parent, const Stmt *s, const CFGBlock *blk, unsigned blockCount, unsigned idx) { @@ -410,26 +387,17 @@ const StackFrameContext *LocationContextManager::getStackFrame( return L; } -const ScopeContext * -LocationContextManager::getScope(AnalysisDeclContext *ctx, - const LocationContext *parent, - const Stmt *s) { - return getLocationContext(ctx, parent, s); -} - -const BlockInvocationContext * -LocationContextManager::getBlockInvocationContext(AnalysisDeclContext *ctx, - const LocationContext *parent, - const BlockDecl *BD, - const void *ContextData) { +const BlockInvocationContext *LocationContextManager::getBlockInvocationContext( + AnalysisDeclContext *ADC, const LocationContext *ParentLC, + const BlockDecl *BD, const void *Data) { llvm::FoldingSetNodeID ID; - BlockInvocationContext::Profile(ID, ctx, parent, BD, ContextData); + BlockInvocationContext::Profile(ID, ADC, ParentLC, BD, Data); void *InsertPos; auto *L = cast_or_null(Contexts.FindNodeOrInsertPos(ID, InsertPos)); if (!L) { - L = new BlockInvocationContext(ctx, parent, BD, ContextData, ++NewID); + L = new BlockInvocationContext(ADC, ParentLC, BD, Data, ++NewID); Contexts.InsertNode(L, InsertPos); } return L; @@ -473,9 +441,7 @@ static void printLocation(raw_ostream &Out, const SourceManager &SM, Loc.print(Out, SM); } -void LocationContext::dumpStack(raw_ostream &Out, const char *NL, - std::function - printMoreInfoPerContext) const { +void LocationContext::dumpStack(raw_ostream &Out) const { ASTContext &Ctx = getAnalysisDeclContext()->getASTContext(); PrintingPolicy PP(Ctx.getLangOpts()); PP.TerseOutput = 1; @@ -498,9 +464,6 @@ void LocationContext::dumpStack(raw_ostream &Out, const char *NL, printLocation(Out, SM, S->getBeginLoc()); } break; - case Scope: - Out << "Entering scope"; - break; case Block: Out << "Invoking block"; if (const Decl *D = cast(LCtx)->getDecl()) { @@ -509,9 +472,7 @@ void LocationContext::dumpStack(raw_ostream &Out, const char *NL, } break; } - Out << NL; - - printMoreInfoPerContext(LCtx); + Out << '\n'; } } @@ -548,9 +509,6 @@ void LocationContext::printJson(raw_ostream &Out, const char *NL, Out << ", \"items\": "; break; - case Scope: - Out << "Entering scope\" "; - break; case Block: Out << "Invoking block\" "; if (const Decl *D = cast(LCtx)->getDecl()) { diff --git a/clang/lib/Analysis/RetainSummaryManager.cpp b/clang/lib/Analysis/RetainSummaryManager.cpp index 05f3e388d806f..583be169c8024 100644 --- a/clang/lib/Analysis/RetainSummaryManager.cpp +++ b/clang/lib/Analysis/RetainSummaryManager.cpp @@ -145,7 +145,9 @@ static bool isSubclass(const Decl *D, } static bool isOSObjectSubclass(const Decl *D) { - return D && isSubclass(D, "OSMetaClassBase"); + // OSSymbols are particular OSObjects that are allocated globally + // and therefore aren't really refcounted, so we ignore them. + return D && isSubclass(D, "OSMetaClassBase") && !isSubclass(D, "OSSymbol"); } static bool isOSObjectDynamicCast(StringRef S) { diff --git a/clang/lib/CodeGen/CGBlocks.cpp b/clang/lib/CodeGen/CGBlocks.cpp index 8a1d67b466ceb..ca6ff0a80a7d6 100644 --- a/clang/lib/CodeGen/CGBlocks.cpp +++ b/clang/lib/CodeGen/CGBlocks.cpp @@ -868,13 +868,13 @@ static void enterBlockScope(CodeGenFunction &CGF, BlockDecl *block) { } /// Enter a full-expression with a non-trivial number of objects to -/// clean up. This is in this file because, at the moment, the only -/// kind of cleanup object is a BlockDecl*. +/// clean up. void CodeGenFunction::enterNonTrivialFullExpression(const FullExpr *E) { if (const auto EWC = dyn_cast(E)) { assert(EWC->getNumObjects() != 0); for (const ExprWithCleanups::CleanupObject &C : EWC->getObjects()) - enterBlockScope(*this, C); + if (auto *BD = C.dyn_cast()) + enterBlockScope(*this, BD); } } diff --git a/clang/lib/CodeGen/CGCall.cpp b/clang/lib/CodeGen/CGCall.cpp index 5375f45e09924..bfb7977e35162 100644 --- a/clang/lib/CodeGen/CGCall.cpp +++ b/clang/lib/CodeGen/CGCall.cpp @@ -2080,6 +2080,7 @@ void CodeGenModule::ConstructAttributeList( hasUsedSRet = true; if (RetAI.getInReg()) SRETAttrs.addAttribute(llvm::Attribute::InReg); + SRETAttrs.addAlignmentAttr(RetAI.getIndirectAlign().getQuantity()); ArgAttrs[IRFunctionArgs.getSRetArgNo()] = llvm::AttributeSet::get(getLLVMContext(), SRETAttrs); } @@ -4691,6 +4692,11 @@ RValue CodeGenFunction::EmitCall(const CGFunctionInfo &CallInfo, for (CallLifetimeEnd &LifetimeEnd : CallLifetimeEndAfterCall) LifetimeEnd.Emit(*this, /*Flags=*/{}); + if (!ReturnValue.isExternallyDestructed() && + RetTy.isDestructedType() == QualType::DK_nontrivial_c_struct) + pushDestroy(QualType::DK_nontrivial_c_struct, Ret.getAggregateAddress(), + RetTy); + return Ret; } diff --git a/clang/lib/CodeGen/CGCall.h b/clang/lib/CodeGen/CGCall.h index 6cdd5fb1a0728..ba3a6e4c0a674 100644 --- a/clang/lib/CodeGen/CGCall.h +++ b/clang/lib/CodeGen/CGCall.h @@ -401,27 +401,26 @@ class FunctionArgList : public SmallVector {}; /// ReturnValueSlot - Contains the address where the return value of a /// function can be stored, and whether the address is volatile or not. class ReturnValueSlot { - llvm::PointerIntPair Value; - CharUnits Alignment; + Address Addr = Address::invalid(); // Return value slot flags - enum Flags { - IS_VOLATILE = 0x1, - IS_UNUSED = 0x2, - }; + unsigned IsVolatile : 1; + unsigned IsUnused : 1; + unsigned IsExternallyDestructed : 1; public: - ReturnValueSlot() {} - ReturnValueSlot(Address Addr, bool IsVolatile, bool IsUnused = false) - : Value(Addr.isValid() ? Addr.getPointer() : nullptr, - (IsVolatile ? IS_VOLATILE : 0) | (IsUnused ? IS_UNUSED : 0)), - Alignment(Addr.isValid() ? Addr.getAlignment() : CharUnits::Zero()) {} - - bool isNull() const { return !getValue().isValid(); } - - bool isVolatile() const { return Value.getInt() & IS_VOLATILE; } - Address getValue() const { return Address(Value.getPointer(), Alignment); } - bool isUnused() const { return Value.getInt() & IS_UNUSED; } + ReturnValueSlot() + : IsVolatile(false), IsUnused(false), IsExternallyDestructed(false) {} + ReturnValueSlot(Address Addr, bool IsVolatile, bool IsUnused = false, + bool IsExternallyDestructed = false) + : Addr(Addr), IsVolatile(IsVolatile), IsUnused(IsUnused), + IsExternallyDestructed(IsExternallyDestructed) {} + + bool isNull() const { return !Addr.isValid(); } + bool isVolatile() const { return IsVolatile; } + Address getValue() const { return Addr; } + bool isUnused() const { return IsUnused; } + bool isExternallyDestructed() const { return IsExternallyDestructed; } }; } // end namespace CodeGen diff --git a/clang/lib/CodeGen/CGClass.cpp b/clang/lib/CodeGen/CGClass.cpp index 58b866ecafbe5..4dedfc02f551b 100644 --- a/clang/lib/CodeGen/CGClass.cpp +++ b/clang/lib/CodeGen/CGClass.cpp @@ -2874,7 +2874,9 @@ void CodeGenFunction::EmitForwardingCallToLambda( if (!resultType->isVoidType() && calleeFnInfo.getReturnInfo().getKind() == ABIArgInfo::Indirect && !hasScalarEvaluationKind(calleeFnInfo.getReturnType())) - returnSlot = ReturnValueSlot(ReturnValue, resultType.isVolatileQualified()); + returnSlot = + ReturnValueSlot(ReturnValue, resultType.isVolatileQualified(), + /*IsUnused=*/false, /*IsExternallyDestructed=*/true); // We don't need to separately arrange the call arguments because // the call can't be variadic anyway --- it's impossible to forward diff --git a/clang/lib/CodeGen/CGDebugInfo.cpp b/clang/lib/CodeGen/CGDebugInfo.cpp index d45dce9e13142..a965528e471dd 100644 --- a/clang/lib/CodeGen/CGDebugInfo.cpp +++ b/clang/lib/CodeGen/CGDebugInfo.cpp @@ -609,9 +609,15 @@ void CGDebugInfo::CreateCompileUnit() { remapDIPath(MainFileName), remapDIPath(getCurrentDirname()), CSInfo, getSource(SM, SM.getMainFileID())); - StringRef Sysroot; - if (CGM.getCodeGenOpts().getDebuggerTuning() == llvm::DebuggerKind::LLDB) + StringRef Sysroot, SDK; + if (CGM.getCodeGenOpts().getDebuggerTuning() == llvm::DebuggerKind::LLDB) { Sysroot = CGM.getHeaderSearchOpts().Sysroot; + auto B = llvm::sys::path::rbegin(Sysroot); + auto E = llvm::sys::path::rend(Sysroot); + auto It = std::find_if(B, E, [](auto SDK) { return SDK.endswith(".sdk"); }); + if (It != E) + SDK = *It; + } // Create new compile unit. TheCU = DBuilder.createCompileUnit( @@ -623,7 +629,7 @@ void CGDebugInfo::CreateCompileUnit() { ? llvm::DICompileUnit::DebugNameTableKind::None : static_cast( CGOpts.DebugNameTable), - CGOpts.DebugRangesBaseAddress, Sysroot); + CGOpts.DebugRangesBaseAddress, remapDIPath(Sysroot), SDK); } llvm::DIType *CGDebugInfo::CreateType(const BuiltinType *BT) { @@ -2440,6 +2446,17 @@ CGDebugInfo::getOrCreateModuleRef(ExternalASTSource::ASTSourceDescriptor Mod, assert(StringRef(M->Name).startswith(CGM.getLangOpts().ModuleName) && "clang module without ASTFile must be specified by -fmodule-name"); + // Return a StringRef to the remapped Path. + auto RemapPath = [this](StringRef Path) -> std::string { + std::string Remapped = remapDIPath(Path); + StringRef Relative(Remapped); + StringRef CompDir = TheCU->getDirectory(); + if (Relative.consume_front(CompDir)) + Relative.consume_front(llvm::sys::path::get_separator()); + + return Relative.str(); + }; + if (CreateSkeletonCU && IsRootModule && !Mod.getASTFile().empty()) { // PCH files don't have a signature field in the control block, // but LLVM detects skeleton CUs by looking for a non-zero DWO id. @@ -2449,12 +2466,16 @@ CGDebugInfo::getOrCreateModuleRef(ExternalASTSource::ASTSourceDescriptor Mod, ? (uint64_t)Mod.getSignature()[1] << 32 | Mod.getSignature()[0] : ~1ULL; llvm::DIBuilder DIB(CGM.getModule()); - DIB.createCompileUnit(TheCU->getSourceLanguage(), - // TODO: Support "Source" from external AST providers? - DIB.createFile(Mod.getModuleName(), Mod.getPath()), - TheCU->getProducer(), true, StringRef(), 0, - Mod.getASTFile(), llvm::DICompileUnit::FullDebug, - Signature); + SmallString<0> PCM; + if (!llvm::sys::path::is_absolute(Mod.getASTFile())) + PCM = Mod.getPath(); + llvm::sys::path::append(PCM, Mod.getASTFile()); + DIB.createCompileUnit( + TheCU->getSourceLanguage(), + // TODO: Support "Source" from external AST providers? + DIB.createFile(Mod.getModuleName(), TheCU->getDirectory()), + TheCU->getProducer(), false, StringRef(), 0, RemapPath(PCM), + llvm::DICompileUnit::FullDebug, Signature); DIB.finalize(); } @@ -2463,9 +2484,10 @@ CGDebugInfo::getOrCreateModuleRef(ExternalASTSource::ASTSourceDescriptor Mod, : getOrCreateModuleRef( ExternalASTSource::ASTSourceDescriptor(*M->Parent), CreateSkeletonCU); + std::string IncludePath = Mod.getPath().str(); llvm::DIModule *DIMod = DBuilder.createModule(Parent, Mod.getModuleName(), ConfigMacros, - Mod.getPath(), M ? M->APINotesFile : ""); + RemapPath(IncludePath), M ? M->APINotesFile : ""); ModuleCache[M].reset(DIMod); return DIMod; } diff --git a/clang/lib/CodeGen/CGExpr.cpp b/clang/lib/CodeGen/CGExpr.cpp index 6ed796046ef29..3914cd23ce573 100644 --- a/clang/lib/CodeGen/CGExpr.cpp +++ b/clang/lib/CodeGen/CGExpr.cpp @@ -860,8 +860,12 @@ void CodeGenFunction::EmitTypeCheck(TypeCheckKind TCK, SourceLocation Loc, static bool isFlexibleArrayMemberExpr(const Expr *E) { // For compatibility with existing code, we treat arrays of length 0 or // 1 as flexible array members. + // FIXME: This is inconsistent with the warning code in SemaChecking. Unify + // the two mechanisms. const ArrayType *AT = E->getType()->castAsArrayTypeUnsafe(); if (const auto *CAT = dyn_cast(AT)) { + // FIXME: Sema doesn't treat [1] as a flexible array member if the bound + // was produced by macro expansion. if (CAT->getSize().ugt(1)) return false; } else if (!isa(AT)) @@ -874,6 +878,10 @@ static bool isFlexibleArrayMemberExpr(const Expr *E) { // FIXME: If the base type of the member expr is not FD->getParent(), // this should not be treated as a flexible array member access. if (const auto *FD = dyn_cast(ME->getMemberDecl())) { + // FIXME: Sema doesn't treat a T[1] union member as a flexible array + // member, only a T[0] or T[] member gets that treatment. + if (FD->getParent()->isUnion()) + return true; RecordDecl::field_iterator FI( DeclContext::decl_iterator(const_cast(FD))); return ++FI == FD->getParent()->field_end(); @@ -4272,6 +4280,14 @@ LValue CodeGenFunction::EmitCompoundLiteralLValue(const CompoundLiteralExpr *E){ EmitAnyExprToMem(InitExpr, DeclPtr, E->getType().getQualifiers(), /*Init*/ true); + // Block-scope compound literals are destroyed at the end of the enclosing + // scope in C. + if (!getLangOpts().CPlusPlus) + if (QualType::DestructionKind DtorKind = E->getType().isDestructedType()) + pushLifetimeExtendedDestroy(getCleanupKind(DtorKind), DeclPtr, + E->getType(), getDestroyer(DtorKind), + DtorKind & EHCleanup); + return Result; } diff --git a/clang/lib/CodeGen/CGExprAgg.cpp b/clang/lib/CodeGen/CGExprAgg.cpp index 8de609a2ccd98..df576decd69d6 100644 --- a/clang/lib/CodeGen/CGExprAgg.cpp +++ b/clang/lib/CodeGen/CGExprAgg.cpp @@ -249,7 +249,7 @@ void AggExprEmitter::withReturnValueSlot( const Expr *E, llvm::function_ref EmitCall) { QualType RetTy = E->getType(); bool RequiresDestruction = - Dest.isIgnored() && + !Dest.isExternallyDestructed() && RetTy.isDestructedType() == QualType::DK_nontrivial_c_struct; // If it makes no observable difference, save a memcpy + temporary. @@ -287,10 +287,8 @@ void AggExprEmitter::withReturnValueSlot( } RValue Src = - EmitCall(ReturnValueSlot(RetAddr, Dest.isVolatile(), IsResultUnused)); - - if (RequiresDestruction) - CGF.pushDestroy(RetTy.isDestructedType(), Src.getAggregateAddress(), RetTy); + EmitCall(ReturnValueSlot(RetAddr, Dest.isVolatile(), IsResultUnused, + Dest.isExternallyDestructed())); if (!UseTemp) return; @@ -659,7 +657,21 @@ AggExprEmitter::VisitCompoundLiteralExpr(CompoundLiteralExpr *E) { } AggValueSlot Slot = EnsureSlot(E->getType()); + + // Block-scope compound literals are destroyed at the end of the enclosing + // scope in C. + bool Destruct = + !CGF.getLangOpts().CPlusPlus && !Slot.isExternallyDestructed(); + if (Destruct) + Slot.setExternallyDestructed(); + CGF.EmitAggExpr(E->getInitializer(), Slot); + + if (Destruct) + if (QualType::DestructionKind DtorKind = E->getType().isDestructedType()) + CGF.pushLifetimeExtendedDestroy( + CGF.getCleanupKind(DtorKind), Slot.getAddress(), E->getType(), + CGF.getDestroyer(DtorKind), DtorKind & EHCleanup); } /// Attempt to look through various unimportant expressions to find a @@ -813,8 +825,19 @@ void AggExprEmitter::VisitCastExpr(CastExpr *E) { // If we're loading from a volatile type, force the destination // into existence. if (E->getSubExpr()->getType().isVolatileQualified()) { + bool Destruct = + !Dest.isExternallyDestructed() && + E->getType().isDestructedType() == QualType::DK_nontrivial_c_struct; + if (Destruct) + Dest.setExternallyDestructed(); EnsureDest(E->getType()); - return Visit(E->getSubExpr()); + Visit(E->getSubExpr()); + + if (Destruct) + CGF.pushDestroy(QualType::DK_nontrivial_c_struct, Dest.getAddress(), + E->getType()); + + return; } LLVM_FALLTHROUGH; diff --git a/clang/lib/CodeGen/CGExprConstant.cpp b/clang/lib/CodeGen/CGExprConstant.cpp index a4e6e470a9055..3377f7d9b0888 100644 --- a/clang/lib/CodeGen/CGExprConstant.cpp +++ b/clang/lib/CodeGen/CGExprConstant.cpp @@ -1167,9 +1167,7 @@ class ConstExprEmitter : } llvm::Constant *VisitExprWithCleanups(ExprWithCleanups *E, QualType T) { - if (!E->cleanupsHaveSideEffects()) - return Visit(E->getSubExpr(), T); - return nullptr; + return Visit(E->getSubExpr(), T); } llvm::Constant *VisitMaterializeTemporaryExpr(MaterializeTemporaryExpr *E, diff --git a/clang/lib/CodeGen/CGExprScalar.cpp b/clang/lib/CodeGen/CGExprScalar.cpp index 82618367ed003..e427847ddb4a0 100644 --- a/clang/lib/CodeGen/CGExprScalar.cpp +++ b/clang/lib/CodeGen/CGExprScalar.cpp @@ -556,6 +556,11 @@ class ScalarExprEmitter Value *VisitMemberExpr(MemberExpr *E); Value *VisitExtVectorElementExpr(Expr *E) { return EmitLoadOfLValue(E); } Value *VisitCompoundLiteralExpr(CompoundLiteralExpr *E) { + // Strictly speaking, we shouldn't be calling EmitLoadOfLValue, which + // transitively calls EmitCompoundLiteralLValue, here in C++ since compound + // literals aren't l-values in C++. We do so simply because that's the + // cleanest way to handle compound literals in C++. + // See the discussion here: https://reviews.llvm.org/D64464 return EmitLoadOfLValue(E); } diff --git a/clang/lib/CodeGen/CGNonTrivialStruct.cpp b/clang/lib/CodeGen/CGNonTrivialStruct.cpp index 4d0992410478a..61b8cad76d3ae 100644 --- a/clang/lib/CodeGen/CGNonTrivialStruct.cpp +++ b/clang/lib/CodeGen/CGNonTrivialStruct.cpp @@ -254,6 +254,10 @@ struct GenBinaryFuncName : CopyStructVisitor, IsMove>, void visitVolatileTrivial(QualType FT, const FieldDecl *FD, CharUnits CurStructOffset) { + // Zero-length bit-fields don't need to be copied/assigned. + if (FD && FD->isZeroLengthBitField(this->Ctx)) + return; + // Because volatile fields can be bit-fields and are individually copied, // their offset and width are in bits. uint64_t OffsetInBits = @@ -553,6 +557,10 @@ struct GenBinaryFunc : CopyStructVisitor, std::array Addrs) { LValue DstLV, SrcLV; if (FD) { + // No need to copy zero-length bit-fields. + if (FD->isZeroLengthBitField(this->CGF->getContext())) + return; + QualType RT = QualType(FD->getParent()->getTypeForDecl(), 0); llvm::PointerType *PtrTy = this->CGF->ConvertType(RT)->getPointerTo(); Address DstAddr = this->getAddrWithOffset(Addrs[DstIdx], Offset); diff --git a/clang/lib/CodeGen/CGVTables.cpp b/clang/lib/CodeGen/CGVTables.cpp index 0409434961379..6ec05d64be385 100644 --- a/clang/lib/CodeGen/CGVTables.cpp +++ b/clang/lib/CodeGen/CGVTables.cpp @@ -364,7 +364,8 @@ void CodeGenFunction::EmitCallAndReturnForThunk(llvm::FunctionCallee Callee, ReturnValueSlot Slot; if (!ResultType->isVoidType() && CurFnInfo->getReturnInfo().getKind() == ABIArgInfo::Indirect) - Slot = ReturnValueSlot(ReturnValue, ResultType.isVolatileQualified()); + Slot = ReturnValueSlot(ReturnValue, ResultType.isVolatileQualified(), + /*IsUnused=*/false, /*IsExternallyDestructed=*/true); // Now emit our call. llvm::CallBase *CallOrInvoke; diff --git a/clang/lib/Driver/ToolChains/Darwin.cpp b/clang/lib/Driver/ToolChains/Darwin.cpp index 8a0d6e34b2458..24750b79521aa 100644 --- a/clang/lib/Driver/ToolChains/Darwin.cpp +++ b/clang/lib/Driver/ToolChains/Darwin.cpp @@ -434,6 +434,75 @@ static bool isObjCRuntimeLinked(const ArgList &Args) { return Args.hasArg(options::OPT_fobjc_link_runtime); } +static bool checkRemarksOptions(const Driver &D, const ArgList &Args, + const llvm::Triple &Triple) { + // When enabling remarks, we need to error if: + // * The remark file is specified but we're targeting multiple architectures, + // which means more than one remark file is being generated. + bool hasMultipleInvocations = + Args.getAllArgValues(options::OPT_arch).size() > 1; + bool hasExplicitOutputFile = + Args.getLastArg(options::OPT_foptimization_record_file_EQ); + if (hasMultipleInvocations && hasExplicitOutputFile) { + D.Diag(diag::err_drv_invalid_output_with_multiple_archs) + << "-foptimization-record-file"; + return false; + } + return true; +} + +static void renderRemarksOptions(const ArgList &Args, ArgStringList &CmdArgs, + const llvm::Triple &Triple, + const InputInfo &Output, const JobAction &JA) { + StringRef Format = "yaml"; + if (const Arg *A = Args.getLastArg(options::OPT_fsave_optimization_record_EQ)) + Format = A->getValue(); + + CmdArgs.push_back("-mllvm"); + CmdArgs.push_back("-lto-pass-remarks-output"); + CmdArgs.push_back("-mllvm"); + + const Arg *A = Args.getLastArg(options::OPT_foptimization_record_file_EQ); + if (A) { + CmdArgs.push_back(A->getValue()); + } else { + assert(Output.isFilename() && "Unexpected ld output."); + SmallString<128> F; + F = Output.getFilename(); + F += ".opt."; + F += Format; + + CmdArgs.push_back(Args.MakeArgString(F)); + } + + if (const Arg *A = + Args.getLastArg(options::OPT_foptimization_record_passes_EQ)) { + CmdArgs.push_back("-mllvm"); + std::string Passes = + std::string("-lto-pass-remarks-filter=") + A->getValue(); + CmdArgs.push_back(Args.MakeArgString(Passes)); + } + + if (!Format.empty()) { + CmdArgs.push_back("-mllvm"); + Twine FormatArg = Twine("-lto-pass-remarks-format=") + Format; + CmdArgs.push_back(Args.MakeArgString(FormatArg)); + } + + if (getLastProfileUseArg(Args)) { + CmdArgs.push_back("-mllvm"); + CmdArgs.push_back("-lto-pass-remarks-with-hotness"); + + if (const Arg *A = + Args.getLastArg(options::OPT_fdiagnostics_hotness_threshold_EQ)) { + CmdArgs.push_back("-mllvm"); + std::string Opt = + std::string("-lto-pass-remarks-hotness-threshold=") + A->getValue(); + CmdArgs.push_back(Args.MakeArgString(Opt)); + } + } +} + void darwin::Linker::ConstructJob(Compilation &C, const JobAction &JA, const InputInfo &Output, const InputInfoList &Inputs, @@ -472,55 +541,10 @@ void darwin::Linker::ConstructJob(Compilation &C, const JobAction &JA, // we follow suite for ease of comparison. AddLinkArgs(C, Args, CmdArgs, Inputs); - // For LTO, pass the name of the optimization record file and other - // opt-remarks flags. - if (Args.hasFlag(options::OPT_fsave_optimization_record, - options::OPT_fsave_optimization_record_EQ, - options::OPT_fno_save_optimization_record, false)) { - CmdArgs.push_back("-mllvm"); - CmdArgs.push_back("-lto-pass-remarks-output"); - CmdArgs.push_back("-mllvm"); - - SmallString<128> F; - F = Output.getFilename(); - F += ".opt."; - if (const Arg *A = - Args.getLastArg(options::OPT_fsave_optimization_record_EQ)) - F += A->getValue(); - else - F += "yaml"; - - CmdArgs.push_back(Args.MakeArgString(F)); - - if (getLastProfileUseArg(Args)) { - CmdArgs.push_back("-mllvm"); - CmdArgs.push_back("-lto-pass-remarks-with-hotness"); - - if (const Arg *A = - Args.getLastArg(options::OPT_fdiagnostics_hotness_threshold_EQ)) { - CmdArgs.push_back("-mllvm"); - std::string Opt = - std::string("-lto-pass-remarks-hotness-threshold=") + A->getValue(); - CmdArgs.push_back(Args.MakeArgString(Opt)); - } - } - - if (const Arg *A = - Args.getLastArg(options::OPT_foptimization_record_passes_EQ)) { - CmdArgs.push_back("-mllvm"); - std::string Passes = - std::string("-lto-pass-remarks-filter=") + A->getValue(); - CmdArgs.push_back(Args.MakeArgString(Passes)); - } - - if (const Arg *A = - Args.getLastArg(options::OPT_fsave_optimization_record_EQ)) { - CmdArgs.push_back("-mllvm"); - std::string Format = - std::string("-lto-pass-remarks-format=") + A->getValue(); - CmdArgs.push_back(Args.MakeArgString(Format)); - } - } + if (willEmitRemarks(Args) && + checkRemarksOptions(getToolChain().getDriver(), Args, + getToolChain().getTriple())) + renderRemarksOptions(Args, CmdArgs, getToolChain().getTriple(), Output, JA); // Propagate the -moutline flag to the linker in LTO. if (Arg *A = @@ -1110,8 +1134,8 @@ StringRef Darwin::getPlatformFamily() const { StringRef Darwin::getSDKName(StringRef isysroot) { // Assume SDK has path: SOME_PATH/SDKs/PlatformXX.YY.sdk - auto BeginSDK = llvm::sys::path::begin(isysroot); - auto EndSDK = llvm::sys::path::end(isysroot); + auto BeginSDK = llvm::sys::path::rbegin(isysroot); + auto EndSDK = llvm::sys::path::rend(isysroot); for (auto IT = BeginSDK; IT != EndSDK; ++IT) { StringRef SDK = *IT; if (SDK.endswith(".sdk")) diff --git a/clang/lib/Frontend/FrontendAction.cpp b/clang/lib/Frontend/FrontendAction.cpp index 5195f7c60dc51..31988d5155be8 100644 --- a/clang/lib/Frontend/FrontendAction.cpp +++ b/clang/lib/Frontend/FrontendAction.cpp @@ -364,6 +364,7 @@ static std::error_code collectModuleHeaderIncludes( llvm::sys::path::native(UmbrellaDir.Entry->getName(), DirNative); llvm::vfs::FileSystem &FS = FileMgr.getVirtualFileSystem(); + SmallVector, 8> Headers; for (llvm::vfs::recursive_directory_iterator Dir(FS, DirNative, EC), End; Dir != End && !EC; Dir.increment(EC)) { // Check whether this entry has an extension typically associated with @@ -395,13 +396,25 @@ static std::error_code collectModuleHeaderIncludes( ++It) llvm::sys::path::append(RelativeHeader, *It); - // Include this header as part of the umbrella directory. - Module->addTopHeader(*Header); - addHeaderInclude(RelativeHeader, Includes, LangOpts, Module->IsExternC); + std::string RelName = RelativeHeader.c_str(); + Headers.push_back(std::make_pair(RelName, *Header)); } if (EC) return EC; + + // Sort header paths and make the header inclusion order deterministic + // across different OSs and filesystems. + llvm::sort(Headers.begin(), Headers.end(), []( + const std::pair &LHS, + const std::pair &RHS) { + return LHS.first > RHS.first; + }); + for (auto &H : Headers) { + // Include this header as part of the umbrella directory. + Module->addTopHeader(H.second); + addHeaderInclude(H.first, Includes, LangOpts, Module->IsExternC); + } } // Recurse into submodules. @@ -1083,6 +1096,9 @@ void WrapperFrontendAction::ExecuteAction() { void WrapperFrontendAction::EndSourceFileAction() { WrappedAction->EndSourceFileAction(); } +bool WrapperFrontendAction::shouldEraseOutputFiles() { + return WrappedAction->shouldEraseOutputFiles(); +} bool WrapperFrontendAction::usesPreprocessorOnly() const { return WrappedAction->usesPreprocessorOnly(); diff --git a/clang/lib/Headers/module.modulemap b/clang/lib/Headers/module.modulemap index 7954a77a41258..d6887bc63997f 100644 --- a/clang/lib/Headers/module.modulemap +++ b/clang/lib/Headers/module.modulemap @@ -40,6 +40,47 @@ module _Builtin_intrinsics [system] [extern_c] { textual header "avx512fintrin.h" textual header "avx512erintrin.h" textual header "fmaintrin.h" + textual header "adxintrin.h" + textual header "avx512bf16intrin.h" + textual header "avx512bitalgintrin.h" + textual header "avx512bwintrin.h" + textual header "avx512cdintrin.h" + textual header "avx512dqintrin.h" + textual header "avx512ifmaintrin.h" + textual header "avx512ifmavlintrin.h" + textual header "avx512pfintrin.h" + textual header "avx512vbmi2intrin.h" + textual header "avx512vbmiintrin.h" + textual header "avx512vbmivlintrin.h" + textual header "avx512vlbf16intrin.h" + textual header "avx512vlbitalgintrin.h" + textual header "avx512vlbwintrin.h" + textual header "avx512vlcdintrin.h" + textual header "avx512vldqintrin.h" + textual header "avx512vlintrin.h" + textual header "avx512vlvbmi2intrin.h" + textual header "avx512vlvnniintrin.h" + textual header "avx512vlvp2intersectintrin.h" + textual header "avx512vnniintrin.h" + textual header "avx512vp2intersectintrin.h" + textual header "avx512vpopcntdqintrin.h" + textual header "avx512vpopcntdqvlintrin.h" + textual header "cetintrin.h" + textual header "clflushoptintrin.h" + textual header "clwbintrin.h" + textual header "enqcmdintrin.h" + textual header "fxsrintrin.h" + textual header "gfniintrin.h" + textual header "pkuintrin.h" + textual header "rtmintrin.h" + textual header "shaintrin.h" + textual header "vaesintrin.h" + textual header "vpclmulqdqintrin.h" + textual header "xsavecintrin.h" + textual header "xsaveintrin.h" + textual header "xsaveoptintrin.h" + textual header "xsavesintrin.h" + textual header "xtestintrin.h" header "x86intrin.h" textual header "bmiintrin.h" @@ -57,6 +98,15 @@ module _Builtin_intrinsics [system] [extern_c] { textual header "sgxintrin.h" textual header "ptwriteintrin.h" textual header "invpcidintrin.h" + textual header "ia32intrin.h" + textual header "lwpintrin.h" + textual header "prfchwintrin.h" + textual header "rdseedintrin.h" + textual header "tbmintrin.h" + textual header "lwpintrin.h" + textual header "prfchwintrin.h" + textual header "rdseedintrin.h" + textual header "tbmintrin.h" textual header "__wmmintrin_aes.h" textual header "__wmmintrin_pclmul.h" diff --git a/clang/lib/Sema/JumpDiagnostics.cpp b/clang/lib/Sema/JumpDiagnostics.cpp index 960e62d4a2db8..b34243edea35e 100644 --- a/clang/lib/Sema/JumpDiagnostics.cpp +++ b/clang/lib/Sema/JumpDiagnostics.cpp @@ -75,6 +75,7 @@ class JumpScopeChecker { void BuildScopeInformation(Decl *D, unsigned &ParentScope); void BuildScopeInformation(VarDecl *D, const BlockDecl *BDecl, unsigned &ParentScope); + void BuildScopeInformation(CompoundLiteralExpr *CLE, unsigned &ParentScope); void BuildScopeInformation(Stmt *S, unsigned &origParentScope); void VerifyJumps(); @@ -276,6 +277,16 @@ void JumpScopeChecker::BuildScopeInformation(VarDecl *D, } } +/// Build scope information for compound literals of C struct types that are +/// non-trivial to destruct. +void JumpScopeChecker::BuildScopeInformation(CompoundLiteralExpr *CLE, + unsigned &ParentScope) { + unsigned InDiag = diag::note_enters_compound_literal_scope; + unsigned OutDiag = diag::note_exits_compound_literal_scope; + Scopes.push_back(GotoScope(ParentScope, InDiag, OutDiag, CLE->getExprLoc())); + ParentScope = Scopes.size() - 1; +} + /// BuildScopeInformation - The statements from CI to CE are known to form a /// coherent VLA scope with a specified parent node. Walk through the /// statements, adding any labels or gotos to LabelAndGotoScopes and recursively @@ -529,11 +540,15 @@ void JumpScopeChecker::BuildScopeInformation(Stmt *S, // implementable but a lot of work which we haven't felt up to doing. ExprWithCleanups *EWC = cast(S); for (unsigned i = 0, e = EWC->getNumObjects(); i != e; ++i) { - const BlockDecl *BDecl = EWC->getObject(i); - for (const auto &CI : BDecl->captures()) { - VarDecl *variable = CI.getVariable(); - BuildScopeInformation(variable, BDecl, origParentScope); - } + if (auto *BDecl = EWC->getObject(i).dyn_cast()) + for (const auto &CI : BDecl->captures()) { + VarDecl *variable = CI.getVariable(); + BuildScopeInformation(variable, BDecl, origParentScope); + } + else if (auto *CLE = EWC->getObject(i).dyn_cast()) + BuildScopeInformation(CLE, origParentScope); + else + llvm_unreachable("unexpected cleanup object type"); } break; } diff --git a/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp index 73428b8209b14..c96f3764dad1d 100644 --- a/clang/lib/Sema/SemaDecl.cpp +++ b/clang/lib/Sema/SemaDecl.cpp @@ -11380,6 +11380,9 @@ bool Sema::DeduceVariableDeclarationType(VarDecl *VDecl, bool DirectInit, void Sema::checkNonTrivialCUnionInInitializer(const Expr *Init, SourceLocation Loc) { + if (auto *EWC = dyn_cast(Init)) + Init = EWC->getSubExpr(); + if (auto *CE = dyn_cast(Init)) Init = CE->getSubExpr(); @@ -13598,13 +13601,12 @@ static void RebuildLambdaScopeInfo(CXXMethodDecl *CallOperator, VarDecl *VD = C.getCapturedVar(); if (VD->isInitCapture()) S.CurrentInstantiationScope->InstantiatedLocal(VD, VD); - QualType CaptureType = VD->getType(); const bool ByRef = C.getCaptureKind() == LCK_ByRef; LSI->addCapture(VD, /*IsBlock*/false, ByRef, /*RefersToEnclosingVariableOrCapture*/true, C.getLocation(), /*EllipsisLoc*/C.isPackExpansion() ? C.getEllipsisLoc() : SourceLocation(), - CaptureType, /*Invalid*/false); + I->getType(), /*Invalid*/false); } else if (C.capturesThis()) { LSI->addThisCapture(/*Nested*/ false, C.getLocation(), I->getType(), diff --git a/clang/lib/Sema/SemaDeclAttr.cpp b/clang/lib/Sema/SemaDeclAttr.cpp index 3607b0d4543c2..d1e71e0d33075 100644 --- a/clang/lib/Sema/SemaDeclAttr.cpp +++ b/clang/lib/Sema/SemaDeclAttr.cpp @@ -7008,7 +7008,9 @@ static void handleObjCExternallyRetainedAttr(Sema &S, Decl *D, // If D is a function-like declaration (method, block, or function), then we // make every parameter psuedo-strong. - for (unsigned I = 0, E = getFunctionOrMethodNumParams(D); I != E; ++I) { + unsigned NumParams = + hasFunctionProto(D) ? getFunctionOrMethodNumParams(D) : 0; + for (unsigned I = 0; I != NumParams; ++I) { auto *PVD = const_cast(getFunctionOrMethodParam(D, I)); QualType Ty = PVD->getType(); diff --git a/clang/lib/Sema/SemaDeclObjC.cpp b/clang/lib/Sema/SemaDeclObjC.cpp index ef49e5718e9ad..d1e5189015ec4 100644 --- a/clang/lib/Sema/SemaDeclObjC.cpp +++ b/clang/lib/Sema/SemaDeclObjC.cpp @@ -4636,6 +4636,62 @@ static void checkObjCMethodX86VectorTypes(Sema &SemaRef, << (Triple.isMacOSX() ? "macOS 10.11" : "iOS 9"); } +static void mergeObjCDirectMembers(Sema &S, Decl *CD, ObjCMethodDecl *Method) { + if (!Method->isDirectMethod() && !Method->hasAttr() && + CD->hasAttr()) { + Method->addAttr( + ObjCDirectAttr::CreateImplicit(S.Context, Method->getLocation())); + } +} + +static void checkObjCDirectMethodClashes(Sema &S, ObjCInterfaceDecl *IDecl, + ObjCMethodDecl *Method, + ObjCImplDecl *ImpDecl = nullptr) { + auto Sel = Method->getSelector(); + bool isInstance = Method->isInstanceMethod(); + bool diagnosed = false; + + auto diagClash = [&](const ObjCMethodDecl *IMD) { + if (diagnosed || IMD->isImplicit()) + return; + if (Method->isDirectMethod() || IMD->isDirectMethod()) { + S.Diag(Method->getLocation(), diag::err_objc_direct_duplicate_decl) + << Method->isDirectMethod() << /* method */ 0 << IMD->isDirectMethod() + << Method->getDeclName(); + S.Diag(IMD->getLocation(), diag::note_previous_declaration); + diagnosed = true; + } + }; + + // Look for any other declaration of this method anywhere we can see in this + // compilation unit. + // + // We do not use IDecl->lookupMethod() because we have specific needs: + // + // - we absolutely do not need to walk protocols, because + // diag::err_objc_direct_on_protocol has already been emitted + // during parsing if there's a conflict, + // + // - when we do not find a match in a given @interface container, + // we need to attempt looking it up in the @implementation block if the + // translation unit sees it to find more clashes. + + if (auto *IMD = IDecl->getMethod(Sel, isInstance)) + diagClash(IMD); + else if (auto *Impl = IDecl->getImplementation()) + if (Impl != ImpDecl) + if (auto *IMD = IDecl->getImplementation()->getMethod(Sel, isInstance)) + diagClash(IMD); + + for (const auto *Cat : IDecl->visible_categories()) + if (auto *IMD = Cat->getMethod(Sel, isInstance)) + diagClash(IMD); + else if (auto CatImpl = Cat->getImplementation()) + if (CatImpl != ImpDecl) + if (auto *IMD = Cat->getMethod(Sel, isInstance)) + diagClash(IMD); +} + Decl *Sema::ActOnMethodDeclaration( Scope *S, SourceLocation MethodLoc, SourceLocation EndLoc, tok::TokenKind MethodType, ObjCDeclSpec &ReturnQT, ParsedType ReturnType, @@ -4866,9 +4922,9 @@ Decl *Sema::ActOnMethodDeclaration( Diag(ObjCMethod->getLocation(), diag::warn_dealloc_in_category) << ObjCMethod->getDeclName(); } - } else if (ImpDecl->hasAttr()) { - ObjCMethod->addAttr( - ObjCDirectAttr::CreateImplicit(Context, ObjCMethod->getLocation())); + } else { + mergeObjCDirectMembers(*this, ClassDecl, ObjCMethod); + checkObjCDirectMethodClashes(*this, IDecl, ObjCMethod, ImpDecl); } // Warn if a method declared in a protocol to which a category or @@ -4889,39 +4945,16 @@ Decl *Sema::ActOnMethodDeclaration( } } else { if (!isa(ClassDecl)) { - if (!ObjCMethod->isDirectMethod() && - ClassDecl->hasAttr()) { - ObjCMethod->addAttr( - ObjCDirectAttr::CreateImplicit(Context, ObjCMethod->getLocation())); - } + mergeObjCDirectMembers(*this, ClassDecl, ObjCMethod); - // There can be a single declaration in any @interface container - // for a given direct method, look for clashes as we add them. - // - // For valid code, we should always know the primary interface - // declaration by now, however for invalid code we'll keep parsing - // but we won't find the primary interface and IDecl will be nil. ObjCInterfaceDecl *IDecl = dyn_cast(ClassDecl); if (!IDecl) IDecl = cast(ClassDecl)->getClassInterface(); - + // For valid code, we should always know the primary interface + // declaration by now, however for invalid code we'll keep parsing + // but we won't find the primary interface and IDecl will be nil. if (IDecl) - if (auto *IMD = IDecl->lookupMethod(ObjCMethod->getSelector(), - ObjCMethod->isInstanceMethod(), - /*shallowCategoryLookup=*/false, - /*followSuper=*/false)) { - if (isa(IMD->getDeclContext())) { - // Do not emit a diagnostic for the Protocol case: - // diag::err_objc_direct_on_protocol has already been emitted - // during parsing for these with a nicer diagnostic. - } else if (ObjCMethod->isDirectMethod() || IMD->isDirectMethod()) { - Diag(ObjCMethod->getLocation(), - diag::err_objc_direct_duplicate_decl) - << ObjCMethod->isDirectMethod() << /* method */ 0 - << IMD->isDirectMethod() << ObjCMethod->getDeclName(); - Diag(IMD->getLocation(), diag::note_previous_declaration); - } - } + checkObjCDirectMethodClashes(*this, IDecl, ObjCMethod); } cast(ClassDecl)->addDecl(ObjCMethod); diff --git a/clang/lib/Sema/SemaExpr.cpp b/clang/lib/Sema/SemaExpr.cpp index 95d5e25515321..4898f279a44fb 100644 --- a/clang/lib/Sema/SemaExpr.cpp +++ b/clang/lib/Sema/SemaExpr.cpp @@ -637,6 +637,9 @@ ExprResult Sema::DefaultLvalueConversion(Expr *E) { if (E->getType().getObjCLifetime() == Qualifiers::OCL_Weak) Cleanup.setExprNeedsCleanups(true); + if (E->getType().isDestructedType() == QualType::DK_nontrivial_c_struct) + Cleanup.setExprNeedsCleanups(true); + // C++ [conv.lval]p3: // If T is cv std::nullptr_t, the result is a null pointer constant. CastKind CK = T->isNullPtrType() ? CK_NullToPointer : CK_LValueToRValue; @@ -6231,14 +6234,24 @@ Sema::BuildCompoundLiteralExpr(SourceLocation LParenLoc, TypeSourceInfo *TInfo, return ExprError(); } - // Compound literals that have automatic storage duration are destroyed at - // the end of the scope. Emit diagnostics if it is or contains a C union type - // that is non-trivial to destruct. - if (!isFileScope) + if (!isFileScope && !getLangOpts().CPlusPlus) { + // Compound literals that have automatic storage duration are destroyed at + // the end of the scope in C; in C++, they're just temporaries. + + // Emit diagnostics if it is or contains a C union type that is non-trivial + // to destruct. if (E->getType().hasNonTrivialToPrimitiveDestructCUnion()) checkNonTrivialCUnion(E->getType(), E->getExprLoc(), NTCUC_CompoundLiteral, NTCUK_Destruct); + // Diagnose jumps that enter or exit the lifetime of the compound literal. + if (literalType.isDestructedType()) { + Cleanup.setExprNeedsCleanups(true); + ExprCleanupObjects.push_back(E); + getCurFunction()->setHasBranchProtectedScope(); + } + } + if (E->getType().hasNonTrivialToPrimitiveDefaultInitializeCUnion() || E->getType().hasNonTrivialToPrimitiveCopyCUnion()) checkNonTrivialCUnionInInitializer(E->getInitializer(), @@ -8251,7 +8264,7 @@ Sema::CheckAssignmentConstraints(SourceLocation Loc, /// type ElementType. static bool isVector(QualType QT, QualType ElementType) { if (const VectorType *VT = QT->getAs()) - return VT->getElementType() == ElementType; + return VT->getElementType().getCanonicalType() == ElementType; return false; } @@ -12529,6 +12542,39 @@ QualType Sema::CheckAddressOfOperand(ExprResult &OrigOp, SourceLocation OpLoc) { QualType MPTy = Context.getMemberPointerType( op->getType(), Context.getTypeDeclType(MD->getParent()).getTypePtr()); + + if (getLangOpts().PointerAuthCalls && MD->isVirtual() && + !isUnevaluatedContext() && !MPTy->isDependentType()) { + // When pointer authentication is enabled, argument and return types of + // vitual member functions must be complete. This is because vitrual + // member function pointers are implemented using virtual dispatch + // thunks and the thunks cannot be emitted if the argument or return + // types are incomplete. + auto ReturnOrParamTypeIsIncomplete = [&](QualType T, + SourceLocation DeclRefLoc, + SourceLocation RetArgTypeLoc) { + if (RequireCompleteType(DeclRefLoc, T, diag::err_incomplete_type)) { + Diag(DeclRefLoc, + diag::note_ptrauth_virtual_function_pointer_incomplete_arg_ret); + Diag(RetArgTypeLoc, + diag::note_ptrauth_virtual_function_incomplete_arg_ret_type) + << T; + return true; + } + return false; + }; + QualType RetTy = MD->getReturnType(); + bool IsIncomplete = + !RetTy->isVoidType() && + ReturnOrParamTypeIsIncomplete( + RetTy, OpLoc, MD->getReturnTypeSourceRange().getBegin()); + for (auto *PVD : MD->parameters()) + IsIncomplete |= ReturnOrParamTypeIsIncomplete(PVD->getType(), OpLoc, + PVD->getBeginLoc()); + if (IsIncomplete) + return QualType(); + } + // Under the MS ABI, lock down the inheritance model now. if (Context.getTargetInfo().getCXXABI().isMicrosoft()) (void)isCompleteType(OpLoc, MPTy); @@ -12908,10 +12954,27 @@ CorrectDelayedTyposInBinOp(Sema &S, BinaryOperatorKind Opc, Expr *LHSExpr, /// Returns true if conversion between vectors of halfs and vectors of floats /// is needed. static bool needsConversionOfHalfVec(bool OpRequiresConversion, ASTContext &Ctx, - QualType SrcType) { - return OpRequiresConversion && !Ctx.getLangOpts().NativeHalfType && - !Ctx.getTargetInfo().useFP16ConversionIntrinsics() && - isVector(SrcType, Ctx.HalfTy); + Expr *E0, Expr *E1 = nullptr) { + if (!OpRequiresConversion || Ctx.getLangOpts().NativeHalfType || + Ctx.getTargetInfo().useFP16ConversionIntrinsics()) + return false; + + auto HasVectorOfHalfType = [&Ctx](Expr *E) { + QualType Ty = E->IgnoreImplicit()->getType(); + + // Don't promote half precision neon vectors like float16x4_t in arm_neon.h + // to vectors of floats. Although the element type of the vectors is __fp16, + // the vectors shouldn't be treated as storage-only types. See the + // discussion here: https://reviews.llvm.org/rG825235c140e7 + if (const VectorType *VT = Ty->getAs()) { + if (VT->getVectorKind() == VectorType::NeonVector) + return false; + return VT->getElementType().getCanonicalType() == Ctx.HalfTy; + } + return false; + }; + + return HasVectorOfHalfType(E0) && (!E1 || HasVectorOfHalfType(E1)); } /// CreateBuiltinBinOp - Creates a new built-in binary operation with @@ -13146,8 +13209,8 @@ ExprResult Sema::CreateBuiltinBinOp(SourceLocation OpLoc, assert(isVector(RHS.get()->getType(), Context.HalfTy) == isVector(LHS.get()->getType(), Context.HalfTy) && "both sides are half vectors or neither sides are"); - ConvertHalfVec = needsConversionOfHalfVec(ConvertHalfVec, Context, - LHS.get()->getType()); + ConvertHalfVec = + needsConversionOfHalfVec(ConvertHalfVec, Context, LHS.get(), RHS.get()); // Check for array bounds violations for both sides of the BinaryOperator CheckArrayAccess(LHS.get()); @@ -13639,8 +13702,7 @@ ExprResult Sema::CreateBuiltinUnaryOp(SourceLocation OpLoc, // float vector and truncating the result back to a half vector. For now, we // do this only when HalfArgsAndReturns is set (that is, when the target is // arm or arm64). - ConvertHalfVec = - needsConversionOfHalfVec(true, Context, Input.get()->getType()); + ConvertHalfVec = needsConversionOfHalfVec(true, Context, Input.get()); // If the operand is a half vector, promote it to a float vector. if (ConvertHalfVec) diff --git a/clang/lib/Sema/SemaExprCXX.cpp b/clang/lib/Sema/SemaExprCXX.cpp index cfb3a05e9c146..5ccf9fe73a348 100644 --- a/clang/lib/Sema/SemaExprCXX.cpp +++ b/clang/lib/Sema/SemaExprCXX.cpp @@ -6208,6 +6208,7 @@ QualType Sema::FindCompositePointerType(SourceLocation Loc, // exists. SmallVector QualifierUnion; SmallVector, 4> MemberOfClass; + SmallVector PtrAuthQualifier; QualType Composite1 = T1; QualType Composite2 = T2; unsigned NeedConstBefore = 0; @@ -6226,6 +6227,9 @@ QualType Sema::FindCompositePointerType(SourceLocation Loc, QualifierUnion.push_back( Composite1.getCVRQualifiers() | Composite2.getCVRQualifiers()); MemberOfClass.push_back(std::make_pair(nullptr, nullptr)); + PtrAuthQualifier.resize(PtrAuthQualifier.size() + 1); + if (Composite1.getPointerAuth() == Composite2.getPointerAuth()) + PtrAuthQualifier.back() = Composite1.getPointerAuth(); continue; } @@ -6244,6 +6248,9 @@ QualType Sema::FindCompositePointerType(SourceLocation Loc, Composite1.getCVRQualifiers() | Composite2.getCVRQualifiers()); MemberOfClass.push_back(std::make_pair(MemPtr1->getClass(), MemPtr2->getClass())); + PtrAuthQualifier.resize(PtrAuthQualifier.size() + 1); + if (Composite1.getPointerAuth() == Composite2.getPointerAuth()) + PtrAuthQualifier.back() = Composite1.getPointerAuth(); continue; } @@ -6299,8 +6306,11 @@ QualType Sema::FindCompositePointerType(SourceLocation Loc, // Rewrap the composites as pointers or member pointers with the union CVRs. auto MOC = MemberOfClass.rbegin(); + auto PtrAuthQualIt = PtrAuthQualifier.rbegin(); for (unsigned CVR : llvm::reverse(QualifierUnion)) { Qualifiers Quals = Qualifiers::fromCVRMask(CVR); + if (PointerAuthQualifier PtrAuthQual = *PtrAuthQualIt++) + Quals.setPointerAuth(PtrAuthQual); auto Classes = *MOC++; if (Classes.first && Classes.second) { // Rebuild member pointer type @@ -6475,6 +6485,9 @@ ExprResult Sema::MaybeBindToTemporary(Expr *E) { VK_RValue); } + if (E->getType().isDestructedType() == QualType::DK_nontrivial_c_struct) + Cleanup.setExprNeedsCleanups(true); + if (!getLangOpts().CPlusPlus) return E; diff --git a/clang/lib/Sema/SemaOverload.cpp b/clang/lib/Sema/SemaOverload.cpp index 83b7f497f99d9..6a066a3f17de1 100644 --- a/clang/lib/Sema/SemaOverload.cpp +++ b/clang/lib/Sema/SemaOverload.cpp @@ -10041,6 +10041,17 @@ static void DiagnoseBadConversion(Sema &S, OverloadCandidate *Cand, return; } + if (FromQs.getPointerAuth() != ToQs.getPointerAuth()) { + S.Diag(Fn->getLocation(), diag::note_ovl_candidate_bad_ptrauth) + << (unsigned)FnKindPair.first << (unsigned)FnKindPair.second << FnDesc + << FromTy + << !!FromQs.getPointerAuth() << FromQs.getPointerAuth().getAsString() + << !!ToQs.getPointerAuth() << ToQs.getPointerAuth().getAsString() + << I + 1 << (FromExpr ? FromExpr->getSourceRange() : SourceRange()); + MaybeEmitInheritedConstructorNote(S, Cand->FoundDecl); + return; + } + unsigned CVR = FromQs.getCVRQualifiers() & ~ToQs.getCVRQualifiers(); assert(CVR && "unexpected qualifiers mismatch"); diff --git a/clang/lib/Serialization/ASTReader.cpp b/clang/lib/Serialization/ASTReader.cpp index 00d2e7e882a99..97c6990f4be0c 100644 --- a/clang/lib/Serialization/ASTReader.cpp +++ b/clang/lib/Serialization/ASTReader.cpp @@ -8488,7 +8488,7 @@ unsigned ASTReader::getModuleFileID(ModuleFile *F) { llvm::Optional ASTReader::getSourceDescriptor(unsigned ID) { - if (const Module *M = getSubmodule(ID)) + if (Module *M = getSubmodule(ID)) return ExternalASTSource::ASTSourceDescriptor(*M); // If there is only a single PCH, return it instead. diff --git a/clang/lib/Serialization/ASTReaderStmt.cpp b/clang/lib/Serialization/ASTReaderStmt.cpp index 533502116ed76..8367472feee08 100644 --- a/clang/lib/Serialization/ASTReaderStmt.cpp +++ b/clang/lib/Serialization/ASTReaderStmt.cpp @@ -1689,9 +1689,17 @@ void ASTStmtReader::VisitExprWithCleanups(ExprWithCleanups *E) { unsigned NumObjects = Record.readInt(); assert(NumObjects == E->getNumObjects()); - for (unsigned i = 0; i != NumObjects; ++i) - E->getTrailingObjects()[i] = - readDeclAs(); + for (unsigned i = 0; i != NumObjects; ++i) { + unsigned CleanupKind = Record.readInt(); + ExprWithCleanups::CleanupObject Obj; + if (CleanupKind == COK_Block) + Obj = readDeclAs(); + else if (CleanupKind == COK_CompoundLiteral) + Obj = cast(Record.readSubExpr()); + else + llvm_unreachable("unexpected cleanup object type"); + E->getTrailingObjects()[i] = Obj; + } E->ExprWithCleanupsBits.CleanupsHaveSideEffects = Record.readInt(); E->SubExpr = Record.readSubExpr(); diff --git a/clang/lib/Serialization/ASTWriterStmt.cpp b/clang/lib/Serialization/ASTWriterStmt.cpp index e671c78fe97b8..f73108de92c79 100644 --- a/clang/lib/Serialization/ASTWriterStmt.cpp +++ b/clang/lib/Serialization/ASTWriterStmt.cpp @@ -1642,8 +1642,15 @@ void ASTStmtWriter::VisitCXXPseudoDestructorExpr(CXXPseudoDestructorExpr *E) { void ASTStmtWriter::VisitExprWithCleanups(ExprWithCleanups *E) { VisitExpr(E); Record.push_back(E->getNumObjects()); - for (unsigned i = 0, e = E->getNumObjects(); i != e; ++i) - Record.AddDeclRef(E->getObject(i)); + for (auto &Obj : E->getObjects()) { + if (auto *BD = Obj.dyn_cast()) { + Record.push_back(serialization::COK_Block); + Record.AddDeclRef(BD); + } else if (auto *CLE = Obj.dyn_cast()) { + Record.push_back(serialization::COK_CompoundLiteral); + Record.AddStmt(CLE); + } + } Record.push_back(E->cleanupsHaveSideEffects()); Record.AddStmt(E->getSubExpr()); diff --git a/clang/lib/Serialization/GeneratePCH.cpp b/clang/lib/Serialization/GeneratePCH.cpp index 002233e49bb06..d869796b82c12 100644 --- a/clang/lib/Serialization/GeneratePCH.cpp +++ b/clang/lib/Serialization/GeneratePCH.cpp @@ -57,6 +57,11 @@ void PCHGenerator::HandleTranslationUnit(ASTContext &Ctx) { } } + // Errors that do not prevent the PCH from being written should not cause the + // overall compilation to fail either. + if (AllowASTWithErrors) + PP.getDiagnostics().getClient()->clear(); + // Emit the PCH file to the Buffer. assert(SemaPtr && "No Sema?"); Buffer->Signature = diff --git a/clang/lib/StaticAnalyzer/Checkers/CXXSelfAssignmentChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/CXXSelfAssignmentChecker.cpp index 01f5b9c889e32..dc6f7722a8e62 100644 --- a/clang/lib/StaticAnalyzer/Checkers/CXXSelfAssignmentChecker.cpp +++ b/clang/lib/StaticAnalyzer/Checkers/CXXSelfAssignmentChecker.cpp @@ -53,7 +53,7 @@ void CXXSelfAssignmentChecker::checkBeginFunction(CheckerContext &C) const { ProgramStateRef SelfAssignState = State->bindLoc(Param, ThisVal, LCtx); const NoteTag *SelfAssignTag = - C.getNoteTag([MD](BugReport &BR) -> std::string { + C.getNoteTag([MD](PathSensitiveBugReport &BR) -> std::string { SmallString<256> Msg; llvm::raw_svector_ostream Out(Msg); Out << "Assuming " << MD->getParamDecl(0)->getName() << " == *this"; @@ -63,7 +63,7 @@ void CXXSelfAssignmentChecker::checkBeginFunction(CheckerContext &C) const { ProgramStateRef NonSelfAssignState = State->bindLoc(Param, ParamVal, LCtx); const NoteTag *NonSelfAssignTag = - C.getNoteTag([MD](BugReport &BR) -> std::string { + C.getNoteTag([MD](PathSensitiveBugReport &BR) -> std::string { SmallString<256> Msg; llvm::raw_svector_ostream Out(Msg); Out << "Assuming " << MD->getParamDecl(0)->getName() << " != *this"; diff --git a/clang/lib/StaticAnalyzer/Checkers/ExprInspectionChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/ExprInspectionChecker.cpp index 17c813962a234..c65cbf2767159 100644 --- a/clang/lib/StaticAnalyzer/Checkers/ExprInspectionChecker.cpp +++ b/clang/lib/StaticAnalyzer/Checkers/ExprInspectionChecker.cpp @@ -6,6 +6,7 @@ // //===----------------------------------------------------------------------===// +#include "Taint.h" #include "clang/StaticAnalyzer/Checkers/BuiltinCheckerRegistration.h" #include "clang/StaticAnalyzer/Checkers/SValExplainer.h" #include "clang/StaticAnalyzer/Core/BugReporter/BugType.h" @@ -45,6 +46,7 @@ class ExprInspectionChecker : public Checker(C.getCalleeName(CE)) - .Case("clang_analyzer_eval", &ExprInspectionChecker::analyzerEval) - .Case("clang_analyzer_checkInlined", - &ExprInspectionChecker::analyzerCheckInlined) - .Case("clang_analyzer_crash", &ExprInspectionChecker::analyzerCrash) - .Case("clang_analyzer_warnIfReached", - &ExprInspectionChecker::analyzerWarnIfReached) - .Case("clang_analyzer_warnOnDeadSymbol", - &ExprInspectionChecker::analyzerWarnOnDeadSymbol) - .StartsWith("clang_analyzer_explain", &ExprInspectionChecker::analyzerExplain) - .StartsWith("clang_analyzer_dump", &ExprInspectionChecker::analyzerDump) - .Case("clang_analyzer_getExtent", &ExprInspectionChecker::analyzerGetExtent) - .Case("clang_analyzer_printState", - &ExprInspectionChecker::analyzerPrintState) - .Case("clang_analyzer_numTimesReached", - &ExprInspectionChecker::analyzerNumTimesReached) - .Case("clang_analyzer_hashDump", &ExprInspectionChecker::analyzerHashDump) - .Case("clang_analyzer_denote", &ExprInspectionChecker::analyzerDenote) - .Case("clang_analyzer_express", &ExprInspectionChecker::analyzerExpress) - .Default(nullptr); + FnCheck Handler = + llvm::StringSwitch(C.getCalleeName(CE)) + .Case("clang_analyzer_eval", &ExprInspectionChecker::analyzerEval) + .Case("clang_analyzer_checkInlined", + &ExprInspectionChecker::analyzerCheckInlined) + .Case("clang_analyzer_crash", &ExprInspectionChecker::analyzerCrash) + .Case("clang_analyzer_warnIfReached", + &ExprInspectionChecker::analyzerWarnIfReached) + .Case("clang_analyzer_warnOnDeadSymbol", + &ExprInspectionChecker::analyzerWarnOnDeadSymbol) + .StartsWith("clang_analyzer_explain", + &ExprInspectionChecker::analyzerExplain) + .StartsWith("clang_analyzer_dump", + &ExprInspectionChecker::analyzerDump) + .Case("clang_analyzer_getExtent", + &ExprInspectionChecker::analyzerGetExtent) + .Case("clang_analyzer_printState", + &ExprInspectionChecker::analyzerPrintState) + .Case("clang_analyzer_numTimesReached", + &ExprInspectionChecker::analyzerNumTimesReached) + .Case("clang_analyzer_hashDump", + &ExprInspectionChecker::analyzerHashDump) + .Case("clang_analyzer_denote", &ExprInspectionChecker::analyzerDenote) + .Case("clang_analyzer_express", + &ExprInspectionChecker::analyzerExpress) + .StartsWith("clang_analyzer_isTainted", + &ExprInspectionChecker::analyzerIsTainted) + .Default(nullptr); if (!Handler) return false; @@ -410,6 +420,17 @@ void ExprInspectionChecker::analyzerExpress(const CallExpr *CE, reportBug(*Str, C); } +void ExprInspectionChecker::analyzerIsTainted(const CallExpr *CE, + CheckerContext &C) const { + if (CE->getNumArgs() != 1) { + reportBug("clang_analyzer_isTainted() requires exactly one argument", C); + return; + } + const bool IsTainted = + taint::isTainted(C.getState(), CE->getArg(0), C.getLocationContext()); + reportBug(IsTainted ? "YES" : "NO", C); +} + void ento::registerExprInspectionChecker(CheckerManager &Mgr) { Mgr.registerChecker(); } diff --git a/clang/lib/StaticAnalyzer/Checkers/FuchsiaHandleChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/FuchsiaHandleChecker.cpp index 861dfef02393a..67a4c7fb82d05 100644 --- a/clang/lib/StaticAnalyzer/Checkers/FuchsiaHandleChecker.cpp +++ b/clang/lib/StaticAnalyzer/Checkers/FuchsiaHandleChecker.cpp @@ -357,8 +357,8 @@ void FuchsiaHandleChecker::checkPostCall(const CallEvent &Call, } const NoteTag *T = nullptr; if (!Notes.empty()) { - T = C.getNoteTag( - [this, Notes{std::move(Notes)}](BugReport &BR) -> std::string { + T = C.getNoteTag([this, Notes{std::move(Notes)}]( + PathSensitiveBugReport &BR) -> std::string { if (&BR.getBugType() != &UseAfterReleaseBugType && &BR.getBugType() != &LeakBugType && &BR.getBugType() != &DoubleReleaseBugType) diff --git a/clang/lib/StaticAnalyzer/Checkers/GenericTaintChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/GenericTaintChecker.cpp index 302d5bb1bea86..564f7e850b1b0 100644 --- a/clang/lib/StaticAnalyzer/Checkers/GenericTaintChecker.cpp +++ b/clang/lib/StaticAnalyzer/Checkers/GenericTaintChecker.cpp @@ -22,11 +22,14 @@ #include "clang/StaticAnalyzer/Core/BugReporter/BugType.h" #include "clang/StaticAnalyzer/Core/Checker.h" #include "clang/StaticAnalyzer/Core/CheckerManager.h" +#include "clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h" #include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h" #include "clang/StaticAnalyzer/Core/PathSensitive/ProgramStateTrait.h" #include "llvm/Support/YAMLTraits.h" + #include #include +#include #include #include @@ -35,17 +38,15 @@ using namespace ento; using namespace taint; namespace { -class GenericTaintChecker - : public Checker, check::PreStmt> { +class GenericTaintChecker : public Checker { public: static void *getTag() { static int Tag; return &Tag; } - void checkPostStmt(const CallExpr *CE, CheckerContext &C) const; - - void checkPreStmt(const CallExpr *CE, CheckerContext &C) const; + void checkPreCall(const CallEvent &Call, CheckerContext &C) const; + void checkPostCall(const CallEvent &Call, CheckerContext &C) const; void printState(raw_ostream &Out, ProgramStateRef State, const char *NL, const char *Sep) const override; @@ -81,7 +82,7 @@ class GenericTaintChecker /// Convert SignedArgVector to ArgVector. ArgVector convertToArgVector(CheckerManager &Mgr, const std::string &Option, - SignedArgVector Args); + const SignedArgVector &Args); /// Parse the config. void parseConfiguration(CheckerManager &Mgr, const std::string &Option, @@ -96,7 +97,8 @@ class GenericTaintChecker mutable std::unique_ptr BT; void initBugType() const { if (!BT) - BT.reset(new BugType(this, "Use of Untrusted Data", "Untrusted Data")); + BT = std::make_unique(this, "Use of Untrusted Data", + "Untrusted Data"); } struct FunctionData { @@ -106,9 +108,10 @@ class GenericTaintChecker FunctionData &operator=(const FunctionData &) = delete; FunctionData &operator=(FunctionData &&) = delete; - static Optional create(const CallExpr *CE, + static Optional create(const CallEvent &Call, const CheckerContext &C) { - const FunctionDecl *FDecl = C.getCalleeDecl(CE); + assert(Call.getDecl()); + const FunctionDecl *FDecl = Call.getDecl()->getAsFunction(); if (!FDecl || (FDecl->getKind() != Decl::Function && FDecl->getKind() != Decl::CXXMethod)) return None; @@ -132,33 +135,33 @@ class GenericTaintChecker /// Catch taint related bugs. Check if tainted data is passed to a /// system call etc. Returns true on matching. - bool checkPre(const CallExpr *CE, const FunctionData &FData, + bool checkPre(const CallEvent &Call, const FunctionData &FData, CheckerContext &C) const; /// Add taint sources on a pre-visit. Returns true on matching. - bool addSourcesPre(const CallExpr *CE, const FunctionData &FData, + bool addSourcesPre(const CallEvent &Call, const FunctionData &FData, CheckerContext &C) const; /// Mark filter's arguments not tainted on a pre-visit. Returns true on /// matching. - bool addFiltersPre(const CallExpr *CE, const FunctionData &FData, + bool addFiltersPre(const CallEvent &Call, const FunctionData &FData, CheckerContext &C) const; /// Propagate taint generated at pre-visit. Returns true on matching. - bool propagateFromPre(const CallExpr *CE, CheckerContext &C) const; + static bool propagateFromPre(const CallEvent &Call, CheckerContext &C); /// Check if the region the expression evaluates to is the standard input, /// and thus, is tainted. static bool isStdin(const Expr *E, CheckerContext &C); /// Given a pointer argument, return the value it points to. - static Optional getPointedToSVal(CheckerContext &C, const Expr *Arg); + static Optional getPointeeOf(CheckerContext &C, const Expr *Arg); /// Check for CWE-134: Uncontrolled Format String. static constexpr llvm::StringLiteral MsgUncontrolledFormatString = "Untrusted data is used as a format string " "(CWE-134: Uncontrolled Format String)"; - bool checkUncontrolledFormatString(const CallExpr *CE, + bool checkUncontrolledFormatString(const CallEvent &Call, CheckerContext &C) const; /// Check for: @@ -167,7 +170,7 @@ class GenericTaintChecker static constexpr llvm::StringLiteral MsgSanitizeSystemArgs = "Untrusted data is passed to a system call " "(CERT/STR02-C. Sanitize data passed to complex subsystems)"; - bool checkSystemCall(const CallExpr *CE, StringRef Name, + bool checkSystemCall(const CallEvent &Call, StringRef Name, CheckerContext &C) const; /// Check if tainted data is used as a buffer size ins strn.. functions, @@ -176,13 +179,12 @@ class GenericTaintChecker "Untrusted data is used to specify the buffer size " "(CERT/STR31-C. Guarantee that storage for strings has sufficient space " "for character data and the null terminator)"; - bool checkTaintedBufferSize(const CallExpr *CE, const FunctionDecl *FDecl, - CheckerContext &C) const; + bool checkTaintedBufferSize(const CallEvent &Call, CheckerContext &C) const; /// Check if tainted data is used as a custom sink's parameter. static constexpr llvm::StringLiteral MsgCustomSink = "Untrusted data is passed to a user-defined sink"; - bool checkCustomSinks(const CallExpr *CE, const FunctionData &FData, + bool checkCustomSinks(const CallEvent &Call, const FunctionData &FData, CheckerContext &C) const; /// Generate a report if the expression is tainted or points to tainted data. @@ -212,7 +214,7 @@ class GenericTaintChecker /// ReturnValueIndex is added to the dst list, the return value will be /// tainted. struct TaintPropagationRule { - using PropagationFuncType = bool (*)(bool IsTainted, const CallExpr *, + using PropagationFuncType = bool (*)(bool IsTainted, const CallEvent &Call, CheckerContext &C); /// List of arguments which can be taint sources and should be checked. @@ -256,7 +258,8 @@ class GenericTaintChecker return (llvm::find(DstArgs, ArgNum) != DstArgs.end()); } - static bool isTaintedOrPointsToTainted(const Expr *E, ProgramStateRef State, + static bool isTaintedOrPointsToTainted(const Expr *E, + const ProgramStateRef &State, CheckerContext &C) { if (isTainted(State, E, C.getLocationContext()) || isStdin(E, C)) return true; @@ -264,16 +267,16 @@ class GenericTaintChecker if (!E->getType().getTypePtr()->isPointerType()) return false; - Optional V = getPointedToSVal(C, E); + Optional V = getPointeeOf(C, E); return (V && isTainted(State, *V)); } /// Pre-process a function which propagates taint according to the /// taint rule. - ProgramStateRef process(const CallExpr *CE, CheckerContext &C) const; + ProgramStateRef process(const CallEvent &Call, CheckerContext &C) const; // Functions for custom taintedness propagation. - static bool postSocket(bool IsTainted, const CallExpr *CE, + static bool postSocket(bool IsTainted, const CallEvent &Call, CheckerContext &C); }; @@ -351,8 +354,10 @@ template <> struct MappingTraits { /// points to data, which should be tainted on return. REGISTER_SET_WITH_PROGRAMSTATE(TaintArgsOnPostVisit, unsigned) -GenericTaintChecker::ArgVector GenericTaintChecker::convertToArgVector( - CheckerManager &Mgr, const std::string &Option, SignedArgVector Args) { +GenericTaintChecker::ArgVector +GenericTaintChecker::convertToArgVector(CheckerManager &Mgr, + const std::string &Option, + const SignedArgVector &Args) { ArgVector Result; for (int Arg : Args) { if (Arg == -1) @@ -419,125 +424,125 @@ GenericTaintChecker::TaintPropagationRule::getTaintPropagationRule( llvm::StringSwitch(FData.FullName) // Source functions // TODO: Add support for vfscanf & family. - .Case("fdopen", TaintPropagationRule({}, {ReturnValueIndex})) - .Case("fopen", TaintPropagationRule({}, {ReturnValueIndex})) - .Case("freopen", TaintPropagationRule({}, {ReturnValueIndex})) - .Case("getch", TaintPropagationRule({}, {ReturnValueIndex})) - .Case("getchar", TaintPropagationRule({}, {ReturnValueIndex})) - .Case("getchar_unlocked", - TaintPropagationRule({}, {ReturnValueIndex})) - .Case("getenv", TaintPropagationRule({}, {ReturnValueIndex})) - .Case("gets", TaintPropagationRule({}, {0, ReturnValueIndex})) - .Case("scanf", TaintPropagationRule({}, {}, VariadicType::Dst, 1)) - .Case("socket", - TaintPropagationRule({}, {ReturnValueIndex}, VariadicType::None, - InvalidArgIndex, - &TaintPropagationRule::postSocket)) - .Case("wgetch", TaintPropagationRule({}, {ReturnValueIndex})) + .Case("fdopen", {{}, {ReturnValueIndex}}) + .Case("fopen", {{}, {ReturnValueIndex}}) + .Case("freopen", {{}, {ReturnValueIndex}}) + .Case("getch", {{}, {ReturnValueIndex}}) + .Case("getchar", {{}, {ReturnValueIndex}}) + .Case("getchar_unlocked", {{}, {ReturnValueIndex}}) + .Case("getenv", {{}, {ReturnValueIndex}}) + .Case("gets", {{}, {0, ReturnValueIndex}}) + .Case("scanf", {{}, {}, VariadicType::Dst, 1}) + .Case("socket", {{}, + {ReturnValueIndex}, + VariadicType::None, + InvalidArgIndex, + &TaintPropagationRule::postSocket}) + .Case("wgetch", {{}, {ReturnValueIndex}}) // Propagating functions - .Case("atoi", TaintPropagationRule({0}, {ReturnValueIndex})) - .Case("atol", TaintPropagationRule({0}, {ReturnValueIndex})) - .Case("atoll", TaintPropagationRule({0}, {ReturnValueIndex})) - .Case("fgetc", TaintPropagationRule({0}, {ReturnValueIndex})) - .Case("fgetln", TaintPropagationRule({0}, {ReturnValueIndex})) - .Case("fgets", TaintPropagationRule({2}, {0, ReturnValueIndex})) - .Case("fscanf", TaintPropagationRule({0}, {}, VariadicType::Dst, 2)) - .Case("getc", TaintPropagationRule({0}, {ReturnValueIndex})) - .Case("getc_unlocked", TaintPropagationRule({0}, {ReturnValueIndex})) - .Case("getdelim", TaintPropagationRule({3}, {0})) - .Case("getline", TaintPropagationRule({2}, {0})) - .Case("getw", TaintPropagationRule({0}, {ReturnValueIndex})) - .Case("pread", - TaintPropagationRule({0, 1, 2, 3}, {1, ReturnValueIndex})) - .Case("read", TaintPropagationRule({0, 2}, {1, ReturnValueIndex})) - .Case("strchr", TaintPropagationRule({0}, {ReturnValueIndex})) - .Case("strrchr", TaintPropagationRule({0}, {ReturnValueIndex})) - .Case("tolower", TaintPropagationRule({0}, {ReturnValueIndex})) - .Case("toupper", TaintPropagationRule({0}, {ReturnValueIndex})) - .Default(TaintPropagationRule()); + .Case("atoi", {{0}, {ReturnValueIndex}}) + .Case("atol", {{0}, {ReturnValueIndex}}) + .Case("atoll", {{0}, {ReturnValueIndex}}) + .Case("fgetc", {{0}, {ReturnValueIndex}}) + .Case("fgetln", {{0}, {ReturnValueIndex}}) + .Case("fgets", {{2}, {0, ReturnValueIndex}}) + .Case("fscanf", {{0}, {}, VariadicType::Dst, 2}) + .Case("sscanf", {{0}, {}, VariadicType::Dst, 2}) + .Case("getc", {{0}, {ReturnValueIndex}}) + .Case("getc_unlocked", {{0}, {ReturnValueIndex}}) + .Case("getdelim", {{3}, {0}}) + .Case("getline", {{2}, {0}}) + .Case("getw", {{0}, {ReturnValueIndex}}) + .Case("pread", {{0, 1, 2, 3}, {1, ReturnValueIndex}}) + .Case("read", {{0, 2}, {1, ReturnValueIndex}}) + .Case("strchr", {{0}, {ReturnValueIndex}}) + .Case("strrchr", {{0}, {ReturnValueIndex}}) + .Case("tolower", {{0}, {ReturnValueIndex}}) + .Case("toupper", {{0}, {ReturnValueIndex}}) + .Default({}); if (!Rule.isNull()) return Rule; + assert(FData.FDecl); // Check if it's one of the memory setting/copying functions. // This check is specialized but faster then calling isCLibraryFunction. const FunctionDecl *FDecl = FData.FDecl; unsigned BId = 0; - if ((BId = FDecl->getMemoryFunctionKind())) + if ((BId = FDecl->getMemoryFunctionKind())) { switch (BId) { case Builtin::BImemcpy: case Builtin::BImemmove: case Builtin::BIstrncpy: case Builtin::BIstrncat: - return TaintPropagationRule({1, 2}, {0, ReturnValueIndex}); + return {{1, 2}, {0, ReturnValueIndex}}; case Builtin::BIstrlcpy: case Builtin::BIstrlcat: - return TaintPropagationRule({1, 2}, {0}); + return {{1, 2}, {0}}; case Builtin::BIstrndup: - return TaintPropagationRule({0, 1}, {ReturnValueIndex}); + return {{0, 1}, {ReturnValueIndex}}; default: break; - }; + } + } // Process all other functions which could be defined as builtins. if (Rule.isNull()) { - if (C.isCLibraryFunction(FDecl, "snprintf")) - return TaintPropagationRule({1}, {0, ReturnValueIndex}, VariadicType::Src, - 3); - else if (C.isCLibraryFunction(FDecl, "sprintf")) - return TaintPropagationRule({}, {0, ReturnValueIndex}, VariadicType::Src, - 2); - else if (C.isCLibraryFunction(FDecl, "strcpy") || - C.isCLibraryFunction(FDecl, "stpcpy") || - C.isCLibraryFunction(FDecl, "strcat")) - return TaintPropagationRule({1}, {0, ReturnValueIndex}); - else if (C.isCLibraryFunction(FDecl, "bcopy")) - return TaintPropagationRule({0, 2}, {1}); - else if (C.isCLibraryFunction(FDecl, "strdup") || - C.isCLibraryFunction(FDecl, "strdupa")) - return TaintPropagationRule({0}, {ReturnValueIndex}); - else if (C.isCLibraryFunction(FDecl, "wcsdup")) - return TaintPropagationRule({0}, {ReturnValueIndex}); + const auto OneOf = [FDecl](const auto &... Name) { + // FIXME: use fold expression in C++17 + using unused = int[]; + bool ret = false; + static_cast(unused{ + 0, (ret |= CheckerContext::isCLibraryFunction(FDecl, Name), 0)...}); + return ret; + }; + if (OneOf("snprintf")) + return {{1}, {0, ReturnValueIndex}, VariadicType::Src, 3}; + if (OneOf("sprintf")) + return {{}, {0, ReturnValueIndex}, VariadicType::Src, 2}; + if (OneOf("strcpy", "stpcpy", "strcat")) + return {{1}, {0, ReturnValueIndex}}; + if (OneOf("bcopy")) + return {{0, 2}, {1}}; + if (OneOf("strdup", "strdupa", "wcsdup")) + return {{0}, {ReturnValueIndex}}; } - // Skipping the following functions, since they might be used for cleansing - // or smart memory copy: + // Skipping the following functions, since they might be used for cleansing or + // smart memory copy: // - memccpy - copying until hitting a special character. auto It = findFunctionInConfig(CustomPropagations, FData); - if (It != CustomPropagations.end()) { - const auto &Value = It->second; - return Value.second; - } - - return TaintPropagationRule(); + if (It != CustomPropagations.end()) + return It->second.second; + return {}; } -void GenericTaintChecker::checkPreStmt(const CallExpr *CE, +void GenericTaintChecker::checkPreCall(const CallEvent &Call, CheckerContext &C) const { - Optional FData = FunctionData::create(CE, C); + Optional FData = FunctionData::create(Call, C); if (!FData) return; // Check for taintedness related errors first: system call, uncontrolled // format string, tainted buffer size. - if (checkPre(CE, *FData, C)) + if (checkPre(Call, *FData, C)) return; // Marks the function's arguments and/or return value tainted if it present in // the list. - if (addSourcesPre(CE, *FData, C)) + if (addSourcesPre(Call, *FData, C)) return; - addFiltersPre(CE, *FData, C); + addFiltersPre(Call, *FData, C); } -void GenericTaintChecker::checkPostStmt(const CallExpr *CE, +void GenericTaintChecker::checkPostCall(const CallEvent &Call, CheckerContext &C) const { // Set the marked values as tainted. The return value only accessible from // checkPostStmt. - propagateFromPre(CE, C); + propagateFromPre(Call, C); } void GenericTaintChecker::printState(raw_ostream &Out, ProgramStateRef State, @@ -545,14 +550,14 @@ void GenericTaintChecker::printState(raw_ostream &Out, ProgramStateRef State, printTaint(State, Out, NL, Sep); } -bool GenericTaintChecker::addSourcesPre(const CallExpr *CE, +bool GenericTaintChecker::addSourcesPre(const CallEvent &Call, const FunctionData &FData, CheckerContext &C) const { // First, try generating a propagation rule for this function. TaintPropagationRule Rule = TaintPropagationRule::getTaintPropagationRule( this->CustomPropagations, FData, C); if (!Rule.isNull()) { - ProgramStateRef State = Rule.process(CE, C); + ProgramStateRef State = Rule.process(Call, C); if (State) { C.addTransition(State); return true; @@ -561,7 +566,7 @@ bool GenericTaintChecker::addSourcesPre(const CallExpr *CE, return false; } -bool GenericTaintChecker::addFiltersPre(const CallExpr *CE, +bool GenericTaintChecker::addFiltersPre(const CallEvent &Call, const FunctionData &FData, CheckerContext &C) const { auto It = findFunctionInConfig(CustomFilters, FData); @@ -572,11 +577,11 @@ bool GenericTaintChecker::addFiltersPre(const CallExpr *CE, const auto &Value = It->second; const ArgVector &Args = Value.second; for (unsigned ArgNum : Args) { - if (ArgNum >= CE->getNumArgs()) + if (ArgNum >= Call.getNumArgs()) continue; - const Expr *Arg = CE->getArg(ArgNum); - Optional V = getPointedToSVal(C, Arg); + const Expr *Arg = Call.getArgExpr(ArgNum); + Optional V = getPointeeOf(C, Arg); if (V) State = removeTaint(State, *V); } @@ -588,8 +593,8 @@ bool GenericTaintChecker::addFiltersPre(const CallExpr *CE, return false; } -bool GenericTaintChecker::propagateFromPre(const CallExpr *CE, - CheckerContext &C) const { +bool GenericTaintChecker::propagateFromPre(const CallEvent &Call, + CheckerContext &C) { ProgramStateRef State = C.getState(); // Depending on what was tainted at pre-visit, we determined a set of @@ -602,16 +607,16 @@ bool GenericTaintChecker::propagateFromPre(const CallExpr *CE, for (unsigned ArgNum : TaintArgs) { // Special handling for the tainted return value. if (ArgNum == ReturnValueIndex) { - State = addTaint(State, CE, C.getLocationContext()); + State = addTaint(State, Call.getReturnValue()); continue; } // The arguments are pointer arguments. The data they are pointing at is // tainted after the call. - if (CE->getNumArgs() < (ArgNum + 1)) + if (Call.getNumArgs() < (ArgNum + 1)) return false; - const Expr *Arg = CE->getArg(ArgNum); - Optional V = getPointedToSVal(C, Arg); + const Expr *Arg = Call.getArgExpr(ArgNum); + Optional V = getPointeeOf(C, Arg); if (V) State = addTaint(State, *V); } @@ -626,27 +631,23 @@ bool GenericTaintChecker::propagateFromPre(const CallExpr *CE, return false; } -bool GenericTaintChecker::checkPre(const CallExpr *CE, +bool GenericTaintChecker::checkPre(const CallEvent &Call, const FunctionData &FData, CheckerContext &C) const { - - if (checkUncontrolledFormatString(CE, C)) + if (checkUncontrolledFormatString(Call, C)) return true; - if (checkSystemCall(CE, FData.Name, C)) + if (checkSystemCall(Call, FData.Name, C)) return true; - if (checkTaintedBufferSize(CE, FData.FDecl, C)) + if (checkTaintedBufferSize(Call, C)) return true; - if (checkCustomSinks(CE, FData, C)) - return true; - - return false; + return checkCustomSinks(Call, FData, C); } -Optional GenericTaintChecker::getPointedToSVal(CheckerContext &C, - const Expr *Arg) { +Optional GenericTaintChecker::getPointeeOf(CheckerContext &C, + const Expr *Arg) { ProgramStateRef State = C.getState(); SVal AddrVal = C.getSVal(Arg->IgnoreParens()); if (AddrVal.isUnknownOrUndef()) @@ -671,31 +672,33 @@ Optional GenericTaintChecker::getPointedToSVal(CheckerContext &C, } ProgramStateRef -GenericTaintChecker::TaintPropagationRule::process(const CallExpr *CE, +GenericTaintChecker::TaintPropagationRule::process(const CallEvent &Call, CheckerContext &C) const { ProgramStateRef State = C.getState(); // Check for taint in arguments. bool IsTainted = true; for (unsigned ArgNum : SrcArgs) { - if (ArgNum >= CE->getNumArgs()) + if (ArgNum >= Call.getNumArgs()) continue; - if ((IsTainted = isTaintedOrPointsToTainted(CE->getArg(ArgNum), State, C))) + if ((IsTainted = + isTaintedOrPointsToTainted(Call.getArgExpr(ArgNum), State, C))) break; } // Check for taint in variadic arguments. if (!IsTainted && VariadicType::Src == VarType) { // Check if any of the arguments is tainted - for (unsigned i = VariadicIndex; i < CE->getNumArgs(); ++i) { - if ((IsTainted = isTaintedOrPointsToTainted(CE->getArg(i), State, C))) + for (unsigned i = VariadicIndex; i < Call.getNumArgs(); ++i) { + if ((IsTainted = + isTaintedOrPointsToTainted(Call.getArgExpr(i), State, C))) break; } } if (PropagationFunc) - IsTainted = PropagationFunc(IsTainted, CE, C); + IsTainted = PropagationFunc(IsTainted, Call, C); if (!IsTainted) return State; @@ -708,7 +711,7 @@ GenericTaintChecker::TaintPropagationRule::process(const CallExpr *CE, continue; } - if (ArgNum >= CE->getNumArgs()) + if (ArgNum >= Call.getNumArgs()) continue; // Mark the given argument. @@ -721,14 +724,15 @@ GenericTaintChecker::TaintPropagationRule::process(const CallExpr *CE, // If they are not pointing to const data, mark data as tainted. // TODO: So far we are just going one level down; ideally we'd need to // recurse here. - for (unsigned i = VariadicIndex; i < CE->getNumArgs(); ++i) { - const Expr *Arg = CE->getArg(i); + for (unsigned i = VariadicIndex; i < Call.getNumArgs(); ++i) { + const Expr *Arg = Call.getArgExpr(i); // Process pointer argument. const Type *ArgTy = Arg->getType().getTypePtr(); QualType PType = ArgTy->getPointeeType(); if ((!PType.isNull() && !PType.isConstQualified()) || - (ArgTy->isReferenceType() && !Arg->getType().isConstQualified())) + (ArgTy->isReferenceType() && !Arg->getType().isConstQualified())) { State = State->add(i); + } } } @@ -736,16 +740,14 @@ GenericTaintChecker::TaintPropagationRule::process(const CallExpr *CE, } // If argument 0(protocol domain) is network, the return value should get taint. -bool GenericTaintChecker::TaintPropagationRule::postSocket(bool /*IsTainted*/, - const CallExpr *CE, - CheckerContext &C) { - SourceLocation DomLoc = CE->getArg(0)->getExprLoc(); +bool GenericTaintChecker::TaintPropagationRule::postSocket( + bool /*IsTainted*/, const CallEvent &Call, CheckerContext &C) { + SourceLocation DomLoc = Call.getArgExpr(0)->getExprLoc(); StringRef DomName = C.getMacroNameOrSpelling(DomLoc); // White list the internal communication protocols. if (DomName.equals("AF_SYSTEM") || DomName.equals("AF_LOCAL") || DomName.equals("AF_UNIX") || DomName.equals("AF_RESERVED_36")) return false; - return true; } @@ -757,16 +759,15 @@ bool GenericTaintChecker::isStdin(const Expr *E, CheckerContext &C) { const MemRegion *MemReg = Val.getAsRegion(); // The region should be symbolic, we do not know it's value. - const SymbolicRegion *SymReg = dyn_cast_or_null(MemReg); + const auto *SymReg = dyn_cast_or_null(MemReg); if (!SymReg) return false; // Get it's symbol and find the declaration region it's pointing to. - const SymbolRegionValue *Sm = - dyn_cast(SymReg->getSymbol()); + const auto *Sm = dyn_cast(SymReg->getSymbol()); if (!Sm) return false; - const DeclRegion *DeclReg = dyn_cast_or_null(Sm->getRegion()); + const auto *DeclReg = dyn_cast_or_null(Sm->getRegion()); if (!DeclReg) return false; @@ -784,23 +785,24 @@ bool GenericTaintChecker::isStdin(const Expr *E, CheckerContext &C) { return false; } -static bool getPrintfFormatArgumentNum(const CallExpr *CE, +static bool getPrintfFormatArgumentNum(const CallEvent &Call, const CheckerContext &C, unsigned &ArgNum) { // Find if the function contains a format string argument. // Handles: fprintf, printf, sprintf, snprintf, vfprintf, vprintf, vsprintf, // vsnprintf, syslog, custom annotated functions. - const FunctionDecl *FDecl = C.getCalleeDecl(CE); + const FunctionDecl *FDecl = Call.getDecl()->getAsFunction(); if (!FDecl) return false; for (const auto *Format : FDecl->specific_attrs()) { ArgNum = Format->getFormatIdx() - 1; - if ((Format->getType()->getName() == "printf") && CE->getNumArgs() > ArgNum) + if ((Format->getType()->getName() == "printf") && + Call.getNumArgs() > ArgNum) return true; } // Or if a function is named setproctitle (this is a heuristic). - if (C.getCalleeName(CE).find("setproctitle") != StringRef::npos) { + if (C.getCalleeName(FDecl).find("setproctitle") != StringRef::npos) { ArgNum = 0; return true; } @@ -814,7 +816,7 @@ bool GenericTaintChecker::generateReportIfTainted(const Expr *E, StringRef Msg, // Check for taint. ProgramStateRef State = C.getState(); - Optional PointedToSVal = getPointedToSVal(C, E); + Optional PointedToSVal = getPointeeOf(C, E); SVal TaintedSVal; if (PointedToSVal && isTainted(State, *PointedToSVal)) TaintedSVal = *PointedToSVal; @@ -836,19 +838,19 @@ bool GenericTaintChecker::generateReportIfTainted(const Expr *E, StringRef Msg, } bool GenericTaintChecker::checkUncontrolledFormatString( - const CallExpr *CE, CheckerContext &C) const { + const CallEvent &Call, CheckerContext &C) const { // Check if the function contains a format string argument. unsigned ArgNum = 0; - if (!getPrintfFormatArgumentNum(CE, C, ArgNum)) + if (!getPrintfFormatArgumentNum(Call, C, ArgNum)) return false; // If either the format string content or the pointer itself are tainted, // warn. - return generateReportIfTainted(CE->getArg(ArgNum), + return generateReportIfTainted(Call.getArgExpr(ArgNum), MsgUncontrolledFormatString, C); } -bool GenericTaintChecker::checkSystemCall(const CallExpr *CE, StringRef Name, +bool GenericTaintChecker::checkSystemCall(const CallEvent &Call, StringRef Name, CheckerContext &C) const { // TODO: It might make sense to run this check on demand. In some cases, // we should check if the environment has been cleansed here. We also might @@ -866,21 +868,22 @@ bool GenericTaintChecker::checkSystemCall(const CallExpr *CE, StringRef Name, .Case("dlopen", 0) .Default(InvalidArgIndex); - if (ArgNum == InvalidArgIndex || CE->getNumArgs() < (ArgNum + 1)) + if (ArgNum == InvalidArgIndex || Call.getNumArgs() < (ArgNum + 1)) return false; - return generateReportIfTainted(CE->getArg(ArgNum), MsgSanitizeSystemArgs, C); + return generateReportIfTainted(Call.getArgExpr(ArgNum), MsgSanitizeSystemArgs, + C); } // TODO: Should this check be a part of the CString checker? // If yes, should taint be a global setting? -bool GenericTaintChecker::checkTaintedBufferSize(const CallExpr *CE, - const FunctionDecl *FDecl, +bool GenericTaintChecker::checkTaintedBufferSize(const CallEvent &Call, CheckerContext &C) const { + const auto *FDecl = Call.getDecl()->getAsFunction(); // If the function has a buffer size argument, set ArgNum. unsigned ArgNum = InvalidArgIndex; unsigned BId = 0; - if ((BId = FDecl->getMemoryFunctionKind())) + if ((BId = FDecl->getMemoryFunctionKind())) { switch (BId) { case Builtin::BImemcpy: case Builtin::BImemmove: @@ -892,26 +895,29 @@ bool GenericTaintChecker::checkTaintedBufferSize(const CallExpr *CE, break; default: break; - }; + } + } if (ArgNum == InvalidArgIndex) { - if (C.isCLibraryFunction(FDecl, "malloc") || - C.isCLibraryFunction(FDecl, "calloc") || - C.isCLibraryFunction(FDecl, "alloca")) + using CCtx = CheckerContext; + if (CCtx::isCLibraryFunction(FDecl, "malloc") || + CCtx::isCLibraryFunction(FDecl, "calloc") || + CCtx::isCLibraryFunction(FDecl, "alloca")) ArgNum = 0; - else if (C.isCLibraryFunction(FDecl, "memccpy")) + else if (CCtx::isCLibraryFunction(FDecl, "memccpy")) ArgNum = 3; - else if (C.isCLibraryFunction(FDecl, "realloc")) + else if (CCtx::isCLibraryFunction(FDecl, "realloc")) ArgNum = 1; - else if (C.isCLibraryFunction(FDecl, "bcopy")) + else if (CCtx::isCLibraryFunction(FDecl, "bcopy")) ArgNum = 2; } - return ArgNum != InvalidArgIndex && CE->getNumArgs() > ArgNum && - generateReportIfTainted(CE->getArg(ArgNum), MsgTaintedBufferSize, C); + return ArgNum != InvalidArgIndex && Call.getNumArgs() > ArgNum && + generateReportIfTainted(Call.getArgExpr(ArgNum), MsgTaintedBufferSize, + C); } -bool GenericTaintChecker::checkCustomSinks(const CallExpr *CE, +bool GenericTaintChecker::checkCustomSinks(const CallEvent &Call, const FunctionData &FData, CheckerContext &C) const { auto It = findFunctionInConfig(CustomSinks, FData); @@ -921,10 +927,10 @@ bool GenericTaintChecker::checkCustomSinks(const CallExpr *CE, const auto &Value = It->second; const GenericTaintChecker::ArgVector &Args = Value.second; for (unsigned ArgNum : Args) { - if (ArgNum >= CE->getNumArgs()) + if (ArgNum >= Call.getNumArgs()) continue; - if (generateReportIfTainted(CE->getArg(ArgNum), MsgCustomSink, C)) + if (generateReportIfTainted(Call.getArgExpr(ArgNum), MsgCustomSink, C)) return true; } diff --git a/clang/lib/StaticAnalyzer/Checkers/MIGChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/MIGChecker.cpp index d73e2eb92d420..794d74c54b730 100644 --- a/clang/lib/StaticAnalyzer/Checkers/MIGChecker.cpp +++ b/clang/lib/StaticAnalyzer/Checkers/MIGChecker.cpp @@ -210,15 +210,17 @@ void MIGChecker::checkPostCall(const CallEvent &Call, CheckerContext &C) const { if (!PVD || State->contains(PVD)) return; - const NoteTag *T = C.getNoteTag([this, PVD](BugReport &BR) -> std::string { - if (&BR.getBugType() != &BT) - return ""; - SmallString<64> Str; - llvm::raw_svector_ostream OS(Str); - OS << "Value passed through parameter '" << PVD->getName() - << "\' is deallocated"; - return OS.str(); - }); + const NoteTag *T = + C.getNoteTag([this, PVD](PathSensitiveBugReport &BR) -> std::string { + if (&BR.getBugType() != &BT) + return ""; + SmallString<64> Str; + llvm::raw_svector_ostream OS(Str); + OS << "Value passed through parameter '" << PVD->getName() + << "\' is deallocated"; + return std::string(OS.str()); + }); + C.addTransition(State->set(true), T); } diff --git a/clang/lib/StaticAnalyzer/Checkers/NSErrorChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/NSErrorChecker.cpp index 85370bf133cd7..fe7ede8101889 100644 --- a/clang/lib/StaticAnalyzer/Checkers/NSErrorChecker.cpp +++ b/clang/lib/StaticAnalyzer/Checkers/NSErrorChecker.cpp @@ -95,6 +95,15 @@ class CFErrorFunctionChecker }; } +static bool hasReservedReturnType(const FunctionDecl *D) { + if (isa(D)) + return true; + + // operators delete and delete[] are required to have 'void' return type + auto OperatorKind = D->getOverloadedOperator(); + return OperatorKind == OO_Delete || OperatorKind == OO_Array_Delete; +} + void CFErrorFunctionChecker::checkASTDecl(const FunctionDecl *D, AnalysisManager &mgr, BugReporter &BR) const { @@ -102,6 +111,8 @@ void CFErrorFunctionChecker::checkASTDecl(const FunctionDecl *D, return; if (!D->getReturnType()->isVoidType()) return; + if (hasReservedReturnType(D)) + return; if (!II) II = &D->getASTContext().Idents.get("CFErrorRef"); diff --git a/clang/lib/StaticAnalyzer/Checkers/NullabilityChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/NullabilityChecker.cpp index 922048733c7c4..d793474cac34a 100644 --- a/clang/lib/StaticAnalyzer/Checkers/NullabilityChecker.cpp +++ b/clang/lib/StaticAnalyzer/Checkers/NullabilityChecker.cpp @@ -508,13 +508,7 @@ void NullabilityChecker::checkEvent(ImplicitNullDerefEvent Event) const { /// return expressions of ObjC types when the return type of the function or /// method is non-null but the express is not. static const Expr *lookThroughImplicitCasts(const Expr *E) { - assert(E); - - while (auto *ICE = dyn_cast(E)) { - E = ICE->getSubExpr(); - } - - return E; + return E->IgnoreImpCasts(); } /// This method check when nullable pointer or null value is returned from a diff --git a/clang/lib/StaticAnalyzer/Checkers/ReturnValueChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/ReturnValueChecker.cpp index 103208d8b5a51..eec26728347f9 100644 --- a/clang/lib/StaticAnalyzer/Checkers/ReturnValueChecker.cpp +++ b/clang/lib/StaticAnalyzer/Checkers/ReturnValueChecker.cpp @@ -99,7 +99,7 @@ void ReturnValueChecker::checkPostCall(const CallEvent &Call, std::string Name = getName(Call); const NoteTag *CallTag = C.getNoteTag( - [Name, ExpectedValue](BugReport &) -> std::string { + [Name, ExpectedValue](PathSensitiveBugReport &) -> std::string { SmallString<128> Msg; llvm::raw_svector_ostream Out(Msg); diff --git a/clang/lib/StaticAnalyzer/Checkers/StreamChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/StreamChecker.cpp index 47099f2afb6a4..292a12fd129aa 100644 --- a/clang/lib/StaticAnalyzer/Checkers/StreamChecker.cpp +++ b/clang/lib/StaticAnalyzer/Checkers/StreamChecker.cpp @@ -49,6 +49,15 @@ struct StreamState { } }; +class StreamChecker; + +using FnCheck = std::function; + +struct FnDescription { + FnCheck EvalFn; +}; + class StreamChecker : public Checker { mutable std::unique_ptr BT_nullfp, BT_illegalwhence, @@ -59,35 +68,33 @@ class StreamChecker : public Checker; - - CallDescriptionMap Callbacks = { - {{"fopen"}, &StreamChecker::evalFopen}, - {{"freopen", 3}, &StreamChecker::evalFreopen}, - {{"tmpfile"}, &StreamChecker::evalFopen}, - {{"fclose", 1}, &StreamChecker::evalFclose}, + + CallDescriptionMap FnDescriptions = { + {{"fopen"}, {&StreamChecker::evalFopen}}, + {{"freopen", 3}, {&StreamChecker::evalFreopen}}, + {{"tmpfile"}, {&StreamChecker::evalFopen}}, + {{"fclose", 1}, {&StreamChecker::evalFclose}}, {{"fread", 4}, - std::bind(&StreamChecker::checkArgNullStream, _1, _2, _3, 3)}, + {std::bind(&StreamChecker::checkArgNullStream, _1, _2, _3, 3)}}, {{"fwrite", 4}, - std::bind(&StreamChecker::checkArgNullStream, _1, _2, _3, 3)}, - {{"fseek", 3}, &StreamChecker::evalFseek}, + {std::bind(&StreamChecker::checkArgNullStream, _1, _2, _3, 3)}}, + {{"fseek", 3}, {&StreamChecker::evalFseek}}, {{"ftell", 1}, - std::bind(&StreamChecker::checkArgNullStream, _1, _2, _3, 0)}, + {std::bind(&StreamChecker::checkArgNullStream, _1, _2, _3, 0)}}, {{"rewind", 1}, - std::bind(&StreamChecker::checkArgNullStream, _1, _2, _3, 0)}, + {std::bind(&StreamChecker::checkArgNullStream, _1, _2, _3, 0)}}, {{"fgetpos", 2}, - std::bind(&StreamChecker::checkArgNullStream, _1, _2, _3, 0)}, + {std::bind(&StreamChecker::checkArgNullStream, _1, _2, _3, 0)}}, {{"fsetpos", 2}, - std::bind(&StreamChecker::checkArgNullStream, _1, _2, _3, 0)}, + {std::bind(&StreamChecker::checkArgNullStream, _1, _2, _3, 0)}}, {{"clearerr", 1}, - std::bind(&StreamChecker::checkArgNullStream, _1, _2, _3, 0)}, + {std::bind(&StreamChecker::checkArgNullStream, _1, _2, _3, 0)}}, {{"feof", 1}, - std::bind(&StreamChecker::checkArgNullStream, _1, _2, _3, 0)}, + {std::bind(&StreamChecker::checkArgNullStream, _1, _2, _3, 0)}}, {{"ferror", 1}, - std::bind(&StreamChecker::checkArgNullStream, _1, _2, _3, 0)}, + {std::bind(&StreamChecker::checkArgNullStream, _1, _2, _3, 0)}}, {{"fileno", 1}, - std::bind(&StreamChecker::checkArgNullStream, _1, _2, _3, 0)}, + {std::bind(&StreamChecker::checkArgNullStream, _1, _2, _3, 0)}}, }; void evalFopen(const CallEvent &Call, CheckerContext &C) const; @@ -125,11 +132,11 @@ bool StreamChecker::evalCall(const CallEvent &Call, CheckerContext &C) const { return false; } - const FnCheck *Callback = Callbacks.lookup(Call); - if (!Callback) + const FnDescription *Description = FnDescriptions.lookup(Call); + if (!Description) return false; - (*Callback)(this, Call, C); + (Description->EvalFn)(this, Call, C); return C.isDifferent(); } diff --git a/clang/lib/StaticAnalyzer/Core/AnalyzerOptions.cpp b/clang/lib/StaticAnalyzer/Core/AnalyzerOptions.cpp index 01ac2bc83bb6b..99e16752b51a4 100644 --- a/clang/lib/StaticAnalyzer/Core/AnalyzerOptions.cpp +++ b/clang/lib/StaticAnalyzer/Core/AnalyzerOptions.cpp @@ -134,9 +134,9 @@ StringRef AnalyzerOptions::getCheckerStringOption(StringRef CheckerName, CheckerName = CheckerName.substr(0, Pos); } while (!CheckerName.empty() && SearchInParents); - llvm_unreachable("Unknown checker option! Did you call getChecker*Option " - "with incorrect parameters? User input must've been " - "verified by CheckerRegistry."); + assert(false && "Unknown checker option! Did you call getChecker*Option " + "with incorrect parameters? User input must've been " + "verified by CheckerRegistry."); return ""; } diff --git a/clang/lib/StaticAnalyzer/Core/CheckerManager.cpp b/clang/lib/StaticAnalyzer/Core/CheckerManager.cpp index a9361837cf68b..ce5e4a46d3e2c 100644 --- a/clang/lib/StaticAnalyzer/Core/CheckerManager.cpp +++ b/clang/lib/StaticAnalyzer/Core/CheckerManager.cpp @@ -61,7 +61,8 @@ void CheckerManager::finishedCheckerRegistration() { } void CheckerManager::reportInvalidCheckerOptionValue( - const CheckerBase *C, StringRef OptionName, StringRef ExpectedValueDesc) { + const CheckerBase *C, StringRef OptionName, + StringRef ExpectedValueDesc) const { Context.getDiagnostics() .Report(diag::err_analyzer_checker_option_invalid_input) @@ -249,7 +250,7 @@ void CheckerManager::runCheckersForObjCMessage(ObjCMessageVisitKind visitKind, } const std::vector & -CheckerManager::getObjCMessageCheckers(ObjCMessageVisitKind Kind) { +CheckerManager::getObjCMessageCheckers(ObjCMessageVisitKind Kind) const { switch (Kind) { case ObjCMessageVisitKind::Pre: return PreObjCMessageCheckers; diff --git a/clang/lib/StaticAnalyzer/Core/CoreEngine.cpp b/clang/lib/StaticAnalyzer/Core/CoreEngine.cpp index 94cf74de82931..5a49b18aecf12 100644 --- a/clang/lib/StaticAnalyzer/Core/CoreEngine.cpp +++ b/clang/lib/StaticAnalyzer/Core/CoreEngine.cpp @@ -221,7 +221,7 @@ void CoreEngine::HandleBlockEdge(const BlockEdge &L, ExplodedNode *Pred) { if (L.getSrc()->getTerminator().isVirtualBaseBranch() && L.getDst() == *L.getSrc()->succ_begin()) { ProgramPoint P = L.withTag(getNoteTags().makeNoteTag( - [](BugReporterContext &, BugReport &) -> std::string { + [](BugReporterContext &, PathSensitiveBugReport &) -> std::string { // TODO: Just call out the name of the most derived class // when we know it. return "Virtual base initialization skipped because " diff --git a/clang/lib/StaticAnalyzer/Core/MemRegion.cpp b/clang/lib/StaticAnalyzer/Core/MemRegion.cpp index a10d7e69ad7e7..1482c627cdd4c 100644 --- a/clang/lib/StaticAnalyzer/Core/MemRegion.cpp +++ b/clang/lib/StaticAnalyzer/Core/MemRegion.cpp @@ -825,8 +825,7 @@ getStackOrCaptureRegionForDeclContext(const LocationContext *LC, return SFC; } if (const auto *BC = dyn_cast(LC)) { - const auto *BR = - static_cast(BC->getContextData()); + const auto *BR = static_cast(BC->getData()); // FIXME: This can be made more efficient. for (BlockDataRegion::referenced_vars_iterator I = BR->referenced_vars_begin(), diff --git a/clang/lib/StaticAnalyzer/Frontend/AnalysisConsumer.cpp b/clang/lib/StaticAnalyzer/Frontend/AnalysisConsumer.cpp index fea8100c3b3bc..c15cee410c74f 100644 --- a/clang/lib/StaticAnalyzer/Frontend/AnalysisConsumer.cpp +++ b/clang/lib/StaticAnalyzer/Frontend/AnalysisConsumer.cpp @@ -12,7 +12,6 @@ #include "clang/StaticAnalyzer/Frontend/AnalysisConsumer.h" #include "ModelInjector.h" -#include "clang/Analysis/PathDiagnostic.h" #include "clang/AST/Decl.h" #include "clang/AST/DeclCXX.h" #include "clang/AST/DeclObjC.h" @@ -21,10 +20,12 @@ #include "clang/Analysis/CFG.h" #include "clang/Analysis/CallGraph.h" #include "clang/Analysis/CodeInjector.h" +#include "clang/Analysis/PathDiagnostic.h" #include "clang/Basic/SourceManager.h" #include "clang/CrossTU/CrossTranslationUnit.h" #include "clang/Frontend/CompilerInstance.h" #include "clang/Lex/Preprocessor.h" +#include "clang/Rewrite/Core/Rewriter.h" #include "clang/StaticAnalyzer/Checkers/LocalCheckers.h" #include "clang/StaticAnalyzer/Core/AnalyzerOptions.h" #include "clang/StaticAnalyzer/Core/BugReporter/BugReporter.h" @@ -33,6 +34,8 @@ #include "clang/StaticAnalyzer/Core/PathSensitive/AnalysisManager.h" #include "clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h" #include "clang/StaticAnalyzer/Frontend/CheckerRegistration.h" +#include "clang/Tooling/Core/Replacement.h" +#include "clang/Tooling/Tooling.h" #include "llvm/ADT/PostOrderIterator.h" #include "llvm/ADT/Statistic.h" #include "llvm/Support/FileSystem.h" @@ -46,6 +49,7 @@ using namespace clang; using namespace ento; +using namespace tooling; #define DEBUG_TYPE "AnalysisConsumer" @@ -83,11 +87,15 @@ void ento::createTextPathDiagnosticConsumer( namespace { class ClangDiagPathDiagConsumer : public PathDiagnosticConsumer { DiagnosticsEngine &Diag; - bool IncludePath = false, ShouldEmitAsError = false, FixitsAsRemarks = false; + LangOptions LO; + + bool IncludePath = false; + bool ShouldEmitAsError = false; + bool ApplyFixIts = false; public: - ClangDiagPathDiagConsumer(DiagnosticsEngine &Diag) - : Diag(Diag) {} + ClangDiagPathDiagConsumer(DiagnosticsEngine &Diag, LangOptions LO) + : Diag(Diag), LO(LO) {} ~ClangDiagPathDiagConsumer() override {} StringRef getName() const override { return "ClangDiags"; } @@ -100,7 +108,7 @@ class ClangDiagPathDiagConsumer : public PathDiagnosticConsumer { void enablePaths() { IncludePath = true; } void enableWerror() { ShouldEmitAsError = true; } - void enableFixitsAsRemarks() { FixitsAsRemarks = true; } + void enableApplyFixIts() { ApplyFixIts = true; } void FlushDiagnosticsImpl(std::vector &Diags, FilesMade *filesMade) override { @@ -109,30 +117,27 @@ class ClangDiagPathDiagConsumer : public PathDiagnosticConsumer { ? Diag.getCustomDiagID(DiagnosticsEngine::Error, "%0") : Diag.getCustomDiagID(DiagnosticsEngine::Warning, "%0"); unsigned NoteID = Diag.getCustomDiagID(DiagnosticsEngine::Note, "%0"); - unsigned RemarkID = Diag.getCustomDiagID(DiagnosticsEngine::Remark, "%0"); - - auto reportPiece = - [&](unsigned ID, SourceLocation Loc, StringRef String, - ArrayRef Ranges, ArrayRef Fixits) { - if (!FixitsAsRemarks) { - Diag.Report(Loc, ID) << String << Ranges << Fixits; - } else { - Diag.Report(Loc, ID) << String << Ranges; - for (const FixItHint &Hint : Fixits) { - SourceManager &SM = Diag.getSourceManager(); - llvm::SmallString<128> Str; - llvm::raw_svector_ostream OS(Str); - // FIXME: Add support for InsertFromRange and - // BeforePreviousInsertion. - assert(!Hint.InsertFromRange.isValid() && "Not implemented yet!"); - assert(!Hint.BeforePreviousInsertions && "Not implemented yet!"); - OS << SM.getSpellingColumnNumber(Hint.RemoveRange.getBegin()) - << "-" << SM.getSpellingColumnNumber(Hint.RemoveRange.getEnd()) - << ": '" << Hint.CodeToInsert << "'"; - Diag.Report(Loc, RemarkID) << OS.str(); - } - } - }; + SourceManager &SM = Diag.getSourceManager(); + + Replacements Repls; + auto reportPiece = [&](unsigned ID, FullSourceLoc Loc, StringRef String, + ArrayRef Ranges, + ArrayRef Fixits) { + if (!ApplyFixIts) { + Diag.Report(Loc, ID) << String << Ranges << Fixits; + return; + } + + Diag.Report(Loc, ID) << String << Ranges; + for (const FixItHint &Hint : Fixits) { + Replacement Repl(SM, Hint.RemoveRange, Hint.CodeToInsert); + + if (llvm::Error Err = Repls.add(Repl)) { + llvm::errs() << "Error applying replacement " << Repl.toString() + << ": " << Err << "\n"; + } + } + }; for (std::vector::iterator I = Diags.begin(), E = Diags.end(); @@ -164,6 +169,16 @@ class ClangDiagPathDiagConsumer : public PathDiagnosticConsumer { Piece->getString(), Piece->getRanges(), Piece->getFixits()); } } + + if (!ApplyFixIts || Repls.empty()) + return; + + Rewriter Rewrite(SM, LO); + if (!applyAllReplacements(Repls, Rewrite)) { + llvm::errs() << "An error occured during applying fix-it.\n"; + } + + Rewrite.overwriteChangedFiles(); } }; } // end anonymous namespace @@ -256,14 +271,14 @@ class AnalysisConsumer : public AnalysisASTConsumer, if (Opts->AnalysisDiagOpt != PD_NONE) { // Create the PathDiagnosticConsumer. ClangDiagPathDiagConsumer *clangDiags = - new ClangDiagPathDiagConsumer(PP.getDiagnostics()); + new ClangDiagPathDiagConsumer(PP.getDiagnostics(), PP.getLangOpts()); PathConsumers.push_back(clangDiags); if (Opts->AnalyzerWerror) clangDiags->enableWerror(); - if (Opts->ShouldEmitFixItHintsAsRemarks) - clangDiags->enableFixitsAsRemarks(); + if (Opts->ShouldApplyFixIts) + clangDiags->enableApplyFixIts(); if (Opts->AnalysisDiagOpt == PD_TEXT) { clangDiags->enablePaths(); @@ -503,6 +518,13 @@ static bool shouldSkipFunction(const Decl *D, if (VisitedAsTopLevel.count(D)) return true; + // Skip analysis of inheriting constructors as top-level functions. These + // constructors don't even have a body written down in the code, so even if + // we find a bug, we won't be able to display it. + if (const auto *CD = dyn_cast(D)) + if (CD->isInheritingConstructor()) + return true; + // We want to re-analyse the functions as top level in the following cases: // - The 'init' methods should be reanalyzed because // ObjCNonNilReturnValueChecker assumes that '[super init]' never returns diff --git a/clang/lib/StaticAnalyzer/Frontend/CMakeLists.txt b/clang/lib/StaticAnalyzer/Frontend/CMakeLists.txt index 5e7dd8f18cd73..6f1151ab0c111 100644 --- a/clang/lib/StaticAnalyzer/Frontend/CMakeLists.txt +++ b/clang/lib/StaticAnalyzer/Frontend/CMakeLists.txt @@ -21,4 +21,6 @@ add_clang_library(clangStaticAnalyzerFrontend clangLex clangStaticAnalyzerCheckers clangStaticAnalyzerCore + clangRewrite + clangToolingCore ) diff --git a/clang/lib/Tooling/Refactor/ASTSlice.cpp b/clang/lib/Tooling/Refactor/ASTSlice.cpp index de6de11485c82..f096876fe97e8 100644 --- a/clang/lib/Tooling/Refactor/ASTSlice.cpp +++ b/clang/lib/Tooling/Refactor/ASTSlice.cpp @@ -182,6 +182,9 @@ ASTSlice::ASTSlice(SourceLocation Location, SourceRange SelectionRange, ASTSliceFinder Visitor(Location, SelectionRange, Context); SourceLocation EndLoc; for (auto *CurrDecl : Context.getTranslationUnitDecl()->decls()) { + if (CurrDecl->getBeginLoc().isInvalid()) + continue; + if (EndLoc.isValid() && !Context.getSourceManager().isBeforeInTranslationUnit( CurrDecl->getBeginLoc(), EndLoc)) diff --git a/clang/test/AST/ast-dump-objc-arc-json.m b/clang/test/AST/ast-dump-objc-arc-json.m new file mode 100644 index 0000000000000..bb9268b28ef65 --- /dev/null +++ b/clang/test/AST/ast-dump-objc-arc-json.m @@ -0,0 +1,36 @@ +// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -x objective-c -fobjc-arc -ast-dump=json -ast-dump-filter Test %s | FileCheck %s + +typedef struct { + id f; +} S; + +id TestCompoundLiteral(id a) { + return ((S){ .f = a }).f; +} + +// CHECK: "kind": "ExprWithCleanups", +// CHECK-NEXT: "range": { +// CHECK-NEXT: "begin": { +// CHECK-NEXT: "offset": 202, +// CHECK-NEXT: "col": 10, +// CHECK-NEXT: "tokLen": 1 +// CHECK-NEXT: }, +// CHECK-NEXT: "end": { +// CHECK-NEXT: "offset": 218, +// CHECK-NEXT: "col": 26, +// CHECK-NEXT: "tokLen": 1 +// CHECK-NEXT: } +// CHECK-NEXT: }, +// CHECK-NEXT: "type": { +// CHECK-NEXT: "desugaredQualType": "id", +// CHECK-NEXT: "qualType": "id", +// CHECK-NEXT: "typeAliasDeclId": "0x{{.*}}" +// CHECK-NEXT: }, +// CHECK-NEXT: "valueCategory": "rvalue", +// CHECK-NEXT: "cleanupsHaveSideEffects": true, +// CHECK-NEXT: "cleanups": [ +// CHECK-NEXT: { +// CHECK-NEXT: "id": "0x{{.*}}", +// CHECK-NEXT: "kind": "CompoundLiteralExpr" +// CHECK-NEXT: } +// CHECK-NEXT: ], diff --git a/clang/test/AST/ast-dump-stmt.m b/clang/test/AST/ast-dump-stmt.m index 8c0ca897e5114..9744e7a43c3e8 100644 --- a/clang/test/AST/ast-dump-stmt.m +++ b/clang/test/AST/ast-dump-stmt.m @@ -1,4 +1,4 @@ -// RUN: %clang_cc1 -Wno-unused -fblocks -fobjc-exceptions -ast-dump -ast-dump-filter Test %s | FileCheck -strict-whitespace %s +// RUN: %clang_cc1 -Wno-unused -fobjc-arc -fblocks -fobjc-exceptions -ast-dump -ast-dump-filter Test %s | FileCheck -strict-whitespace %s void TestBlockExpr(int x) { ^{ x; }; @@ -34,3 +34,16 @@ void TestObjCAtCatchStmt() { // CHECK-NEXT: ObjCAtCatchStmt{{.*}} catch all // CHECK-NEXT: CompoundStmt // CHECK-NEXT: ObjCAtFinallyStmt + +typedef struct { + id f; +} S; + +id TestCompoundLiteral(id a) { + return ((S){ .f = a }).f; +} + +// CHECK: FunctionDecl{{.*}}TestCompoundLiteral +// CHECK: ExprWithCleanups +// CHECK-NEXT: cleanup CompoundLiteralExpr +// CHECK: CompoundLiteralExpr{{.*}}'S':'S' lvalue diff --git a/clang/test/Analysis/SpecialFunctionsCFError.cpp b/clang/test/Analysis/SpecialFunctionsCFError.cpp new file mode 100644 index 0000000000000..3517933f6bcc6 --- /dev/null +++ b/clang/test/Analysis/SpecialFunctionsCFError.cpp @@ -0,0 +1,28 @@ +// RUN: %clang_analyze_cc1 -analyzer-checker=core,osx.coreFoundation.CFError \ +// RUN: -verify %s + +typedef unsigned long size_t; +struct __CFError {}; +typedef struct __CFError *CFErrorRef; +void *malloc(size_t); + +class Foo { +public: + Foo(CFErrorRef *error) {} // no-warning + + void operator delete(void *pointer, CFErrorRef *error) { // no-warning + return; + } + + void operator delete[](void *pointer, CFErrorRef *error) { // no-warning + return; + } + + // Check that we report warnings for operators when it can be useful + void operator()(CFErrorRef *error) {} // expected-warning {{Function accepting CFErrorRef* should have a non-void return value to indicate whether or not an error occurred}} +}; + +// Check that global delete operator is not bothered as well +void operator delete(void *pointer, CFErrorRef *error) { // no-warning + return; +} diff --git a/clang/test/Analysis/analyzer-config.c b/clang/test/Analysis/analyzer-config.c index 4707da3b9a3a3..edd4fac7f8b24 100644 --- a/clang/test/Analysis/analyzer-config.c +++ b/clang/test/Analysis/analyzer-config.c @@ -10,6 +10,7 @@ // CHECK-NEXT: alpha.security.MmapWriteExec:MmapProtExec = 0x04 // CHECK-NEXT: alpha.security.MmapWriteExec:MmapProtRead = 0x01 // CHECK-NEXT: alpha.security.taint.TaintPropagation:Config = "" +// CHECK-NEXT: apply-fixits = false // CHECK-NEXT: avoid-suppressing-null-argument-paths = false // CHECK-NEXT: c++-allocator-inlining = true // CHECK-NEXT: c++-container-inlining = false @@ -57,7 +58,6 @@ // CHECK-NEXT: experimental-enable-naive-ctu-analysis = false // CHECK-NEXT: exploration_strategy = unexplored_first_queue // CHECK-NEXT: faux-bodies = true -// CHECK-NEXT: fixits-as-remarks = false // CHECK-NEXT: graph-trim-interval = 1000 // CHECK-NEXT: inline-lambdas = true // CHECK-NEXT: ipa = dynamic-bifurcate diff --git a/clang/test/Analysis/check-analyzer-fixit.py b/clang/test/Analysis/check-analyzer-fixit.py new file mode 100644 index 0000000000000..6a8f6859f816b --- /dev/null +++ b/clang/test/Analysis/check-analyzer-fixit.py @@ -0,0 +1,121 @@ +#!/usr/bin/env python +# +#===- check-analyzer-fixit.py - Static Analyzer test helper ---*- python -*-===# +# +# Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +# See https://llvm.org/LICENSE.txt for license information. +# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +# +#===------------------------------------------------------------------------===# +# +# This file copy-pasted mostly from the Clang-Tidy's 'check_clang_tidy.py'. +# +#===------------------------------------------------------------------------===# + +r""" +Clang Static Analyzer test helper +================================= + +This script runs the Analyzer in fix-it mode and verify fixes, warnings, notes. + +Usage: + check-analyzer-fixit.py [analyzer arguments] + +Example: + // RUN: %check-analyzer-fixit %s %t -analyzer-checker=core +""" + +import argparse +import os +import re +import subprocess +import sys + + +def write_file(file_name, text): + with open(file_name, 'w') as f: + f.write(text) + + +def run_test_once(args, extra_args): + input_file_name = args.input_file_name + temp_file_name = args.temp_file_name + clang_analyzer_extra_args = extra_args + + file_name_with_extension = input_file_name + _, extension = os.path.splitext(file_name_with_extension) + if extension not in ['.c', '.hpp', '.m', '.mm']: + extension = '.cpp' + temp_file_name = temp_file_name + extension + + with open(input_file_name, 'r') as input_file: + input_text = input_file.read() + + # Remove the contents of the CHECK lines to avoid CHECKs matching on + # themselves. We need to keep the comments to preserve line numbers while + # avoiding empty lines which could potentially trigger formatting-related + # checks. + cleaned_test = re.sub('// *CHECK-[A-Z0-9\-]*:[^\r\n]*', '//', input_text) + write_file(temp_file_name, cleaned_test) + + original_file_name = temp_file_name + ".orig" + write_file(original_file_name, cleaned_test) + + try: + builtin_include_dir = subprocess.check_output( + ['clang', '-print-file-name=include'], stderr=subprocess.STDOUT).decode() + except subprocess.CalledProcessError as e: + print('Cannot print Clang include directory: ' + e.output.decode()) + + builtin_include_dir = os.path.normpath(builtin_include_dir) + + args = (['clang', '-cc1', '-internal-isystem', builtin_include_dir, + '-nostdsysteminc', '-analyze', '-analyzer-constraints=range', + '-analyzer-config', 'apply-fixits=true'] + + clang_analyzer_extra_args + ['-verify', temp_file_name]) + + print('Running ' + str(args) + '...') + + try: + clang_analyzer_output = \ + subprocess.check_output(args, stderr=subprocess.STDOUT).decode() + except subprocess.CalledProcessError as e: + print('Clang Static Analyzer test failed:\n' + e.output.decode()) + raise + + print('----------------- Clang Static Analyzer output -----------------\n' + + clang_analyzer_output + + '\n--------------------------------------------------------------') + + try: + diff_output = subprocess.check_output( + ['diff', '-u', original_file_name, temp_file_name], + stderr=subprocess.STDOUT) + except subprocess.CalledProcessError as e: + diff_output = e.output + + print('----------------------------- Fixes ----------------------------\n' + + diff_output.decode() + + '\n--------------------------------------------------------------') + + try: + subprocess.check_output( + ['FileCheck', '-input-file=' + temp_file_name, input_file_name, + '-check-prefixes=CHECK-FIXES', '-strict-whitespace'], + stderr=subprocess.STDOUT) + except subprocess.CalledProcessError as e: + print('FileCheck failed:\n' + e.output.decode()) + raise + + +def main(): + parser = argparse.ArgumentParser() + parser.add_argument('input_file_name') + parser.add_argument('temp_file_name') + + args, extra_args = parser.parse_known_args() + run_test_once(args, extra_args) + + +if __name__ == '__main__': + main() diff --git a/clang/test/Analysis/cxx-inherited-ctor-init-expr.cpp b/clang/test/Analysis/cxx-inherited-ctor-init-expr.cpp index ff82c129bc700..8370ebfbde09b 100644 --- a/clang/test/Analysis/cxx-inherited-ctor-init-expr.cpp +++ b/clang/test/Analysis/cxx-inherited-ctor-init-expr.cpp @@ -57,3 +57,19 @@ void test_B() { clang_analyzer_eval(b.z == 3); // expected-warning{{TRUE}} } } // namespace arguments_with_constructors + +namespace inherited_constructor_crash { +class a { +public: + a(int); +}; +struct b : a { + using a::a; // Ihnerited ctor. +}; +void c() { + int d; + // This construct expr utilizes the inherited ctor. + // Note that d must be uninitialized to cause the crash. + (b(d)); // expected-warning{{1st function call argument is an uninitialized value}} +} +} // namespace inherited_constructor_crash diff --git a/clang/test/Analysis/cxx-inherited-ctor-is-skipped-as-top-level.cpp b/clang/test/Analysis/cxx-inherited-ctor-is-skipped-as-top-level.cpp new file mode 100644 index 0000000000000..be7982e641148 --- /dev/null +++ b/clang/test/Analysis/cxx-inherited-ctor-is-skipped-as-top-level.cpp @@ -0,0 +1,20 @@ +// RUN: %clang_analyze_cc1 -analyzer-checker=core -analyzer-display-progress %s 2>&1 | FileCheck %s + +// Test that inheriting constructors are not analyzed as top-level functions. + +// CHECK: ANALYZE (Path, Inline_Regular): {{.*}} c() +// CHECK: ANALYZE (Path, Inline_Regular): {{.*}} a::a(int) +// CHECK-NOT: ANALYZE (Path, Inline_Regular): {{.*}} b::a(int) + +class a { +public: + a(int) {} +}; +struct b : a { + using a::a; // Ihnerited ctor. +}; +void c() { + int d; + (b(d)); + (a(d)); +} diff --git a/clang/test/Analysis/dead-stores.c b/clang/test/Analysis/dead-stores.c index cbfdabdcec632..a17e1692496da 100644 --- a/clang/test/Analysis/dead-stores.c +++ b/clang/test/Analysis/dead-stores.c @@ -1,16 +1,16 @@ -// RUN: %clang_analyze_cc1 -Wunused-variable -fblocks -Wno-unreachable-code \ +// RUN: %check_analyzer_fixit %s %t \ +// RUN: -Wunused-variable -fblocks -Wno-unreachable-code \ // RUN: -analyzer-checker=core,deadcode.DeadStores \ // RUN: -analyzer-config deadcode.DeadStores:ShowFixIts=true \ -// RUN: -analyzer-config fixits-as-remarks=true \ // RUN: -analyzer-config \ // RUN: deadcode.DeadStores:WarnForDeadNestedAssignments=false \ -// RUN: -verify=non-nested %s +// RUN: -verify=non-nested -// RUN: %clang_analyze_cc1 -Wunused-variable -fblocks -Wno-unreachable-code \ +// RUN: %check_analyzer_fixit %s %t \ +// RUN: -Wunused-variable -fblocks -Wno-unreachable-code \ // RUN: -analyzer-checker=core,deadcode.DeadStores \ // RUN: -analyzer-config deadcode.DeadStores:ShowFixIts=true \ -// RUN: -analyzer-config fixits-as-remarks=true \ -// RUN: -verify=non-nested,nested %s +// RUN: -verify=non-nested,nested void f1() { int k, y; // non-nested-warning {{unused variable 'k'}} @@ -18,14 +18,17 @@ void f1() { int abc = 1; long idx = abc + 3 * 5; // non-nested-warning {{never read}} // non-nested-warning@-1 {{unused variable 'idx'}} - // non-nested-remark@-2 {{11-24: ''}} + // CHECK-FIXES: int abc = 1; + // CHECK-FIXES-NEXT: long idx; } void f2(void *b) { char *c = (char *)b; // no-warning char *d = b + 1; // non-nested-warning {{never read}} // non-nested-warning@-1 {{unused variable 'd'}} - // non-nested-remark@-2 {{10-17: ''}} + // CHECK-FIXES: char *c = (char *)b; + // CHECK-FIXES-NEXT: char *d; + printf("%s", c); // non-nested-warning@-1 {{implicitly declaring library function 'printf' with type 'int (const char *, ...)'}} // non-nested-note@-2 {{include the header or explicitly provide a declaration for 'printf'}} @@ -51,7 +54,8 @@ void f5() { int x = 4; // no-warning int *p = &x; // non-nested-warning {{never read}} // non-nested-warning@-1 {{unused variable 'p'}} - // non-nested-remark@-2 {{9-13: ''}} + // CHECK-FIXES: int x = 4; + // CHECK-FIXES-NEXT: int *p; } int f6() { @@ -415,7 +419,8 @@ void f23_pos(int argc, char **argv) { int shouldLog = (argc > 1); // non-nested-warning@-1 {{Value stored to 'shouldLog' during its initialization is never read}} // non-nested-warning@-2 {{unused variable 'shouldLog'}} - // non-nested-remark@-3 {{16-28: ''}} + // CHECK-FIXES: void f23_pos(int argc, char **argv) { + // CHECK-FIXES-NEXT: int shouldLog; ^{ f23_aux("I did too use it!\n"); }(); @@ -428,7 +433,11 @@ void f24_A(int y) { int z = x + y; // non-nested-warning@-1 {{Value stored to 'z' during its initialization is never read}} // non-nested-warning@-2 {{unused variable 'z'}} - // non-nested-remark@-3 {{10-17: ''}} + // CHECK-FIXES: void f24_A(int y) { + // CHECK-FIXES-NEXT: // + // CHECK-FIXES-NEXT: int x = (y > 2); + // CHECK-FIXES-NEXT: ^{ + // CHECK-FIXES-NEXT: int z; }(); } diff --git a/clang/test/Analysis/debug-exprinspection-istainted.c b/clang/test/Analysis/debug-exprinspection-istainted.c new file mode 100644 index 0000000000000..e2f6821e4aa9a --- /dev/null +++ b/clang/test/Analysis/debug-exprinspection-istainted.c @@ -0,0 +1,27 @@ +// RUN: %clang_analyze_cc1 -verify %s \ +// RUN: -analyzer-checker=core \ +// RUN: -analyzer-checker=debug.ExprInspection \ +// RUN: -analyzer-checker=alpha.security.taint + +int scanf(const char *restrict format, ...); +void clang_analyzer_isTainted(char); +void clang_analyzer_isTainted_any_suffix(char); +void clang_analyzer_isTainted_many_arguments(char, int, int); + +void foo() { + char buf[32] = ""; + clang_analyzer_isTainted(buf[0]); // expected-warning {{NO}} + clang_analyzer_isTainted_any_suffix(buf[0]); // expected-warning {{NO}} + scanf("%s", buf); + clang_analyzer_isTainted(buf[0]); // expected-warning {{YES}} + clang_analyzer_isTainted_any_suffix(buf[0]); // expected-warning {{YES}} + + int tainted_value = buf[0]; // no-warning +} + +void exactly_one_argument_required() { + char buf[32] = ""; + scanf("%s", buf); + clang_analyzer_isTainted_many_arguments(buf[0], 42, 42); + // expected-warning@-1 {{clang_analyzer_isTainted() requires exactly one argument}} +} diff --git a/clang/test/Analysis/osobject-retain-release.cpp b/clang/test/Analysis/osobject-retain-release.cpp index 41606a30c39f4..d88349dcd807e 100644 --- a/clang/test/Analysis/osobject-retain-release.cpp +++ b/clang/test/Analysis/osobject-retain-release.cpp @@ -53,6 +53,9 @@ struct MyArray : public OSArray { OSObject *generateObject(OSObject *input) override; }; +// These are never refcounted. +struct OSSymbol : OSObject {}; + struct OtherStruct { static void doNothingToArray(OSArray *array); OtherStruct(OSArray *arr); @@ -754,3 +757,10 @@ void test() { b(0); } } // namespace inherited_constructor_crash + +namespace ossymbol_suppression { +OSSymbol *createSymbol(); +void test() { + OSSymbol *sym = createSymbol(); // no-warning +} +} // namespace ossymbol_suppression diff --git a/clang/test/Analysis/virtualcall-fixits.cpp b/clang/test/Analysis/virtualcall-fixits.cpp index ea149d52fcd21..b68fcbfea93d5 100644 --- a/clang/test/Analysis/virtualcall-fixits.cpp +++ b/clang/test/Analysis/virtualcall-fixits.cpp @@ -1,10 +1,11 @@ // RUN: %clang_analyze_cc1 -analyzer-checker=core,optin.cplusplus.VirtualCall \ // RUN: -analyzer-config optin.cplusplus.VirtualCall:ShowFixIts=true \ // RUN: %s 2>&1 | FileCheck -check-prefix=TEXT %s -// RUN: %clang_analyze_cc1 -analyzer-checker=core,optin.cplusplus.VirtualCall \ + +// RUN: %check_analyzer_fixit %s %t \ +// RUN: -analyzer-checker=core,optin.cplusplus.VirtualCall \ // RUN: -analyzer-config optin.cplusplus.VirtualCall:ShowFixIts=true \ -// RUN: -analyzer-config fixits-as-remarks=true \ -// RUN: -analyzer-output=plist -o %t.plist -verify %s +// RUN: -analyzer-output=plist -o %t.plist // RUN: cat %t.plist | FileCheck -check-prefix=PLIST %s struct S { @@ -12,7 +13,9 @@ struct S { S() { foo(); // expected-warning@-1{{Call to virtual method 'S::foo' during construction bypasses virtual dispatch}} - // expected-remark@-2{{5-5: 'S::'}} + // CHECK-FIXES: S() { + // CHECK-FIXES-NEXT: S::foo(); + // CHECK-FIXES-NEXT: } } ~S(); }; @@ -30,12 +33,12 @@ struct S { // PLIST-NEXT: remove_range // PLIST-NEXT: // PLIST-NEXT: -// PLIST-NEXT: line13 +// PLIST-NEXT: line14 // PLIST-NEXT: col5 // PLIST-NEXT: file0 // PLIST-NEXT: // PLIST-NEXT: -// PLIST-NEXT: line13 +// PLIST-NEXT: line14 // PLIST-NEXT: col4 // PLIST-NEXT: file0 // PLIST-NEXT: diff --git a/clang/test/CodeGen/2006-05-19-SingleEltReturn.c b/clang/test/CodeGen/2006-05-19-SingleEltReturn.c index dfc23f84ab424..d3f9e4e00acde 100644 --- a/clang/test/CodeGen/2006-05-19-SingleEltReturn.c +++ b/clang/test/CodeGen/2006-05-19-SingleEltReturn.c @@ -24,7 +24,7 @@ struct Y bar() { // X86_32: define void @foo(%struct.Y* %P) -// X86_32: call void @bar(%struct.Y* sret %{{[^),]*}}) +// X86_32: call void @bar(%struct.Y* sret align 4 %{{[^),]*}}) -// X86_32: define void @bar(%struct.Y* noalias sret %{{[^,)]*}}) +// X86_32: define void @bar(%struct.Y* noalias sret align 4 %{{[^,)]*}}) // X86_32: ret void diff --git a/clang/test/CodeGen/aarch64-varargs.c b/clang/test/CodeGen/aarch64-varargs.c index c213f5b9375ba..27bb602e75de1 100644 --- a/clang/test/CodeGen/aarch64-varargs.c +++ b/clang/test/CodeGen/aarch64-varargs.c @@ -639,7 +639,7 @@ typedef struct __attribute__((aligned(32))) { __int128 val; } overaligned_int128_struct; overaligned_int128_struct overaligned_int128_struct_test() { -// CHECK-LABEL: define void @overaligned_int128_struct_test(%struct.overaligned_int128_struct* noalias sret %agg.result) +// CHECK-LABEL: define void @overaligned_int128_struct_test(%struct.overaligned_int128_struct* noalias sret align 32 %agg.result) return va_arg(the_list, overaligned_int128_struct); // CHECK: [[GR_OFFS:%[a-z_0-9]+]] = load i32, i32* getelementptr inbounds (%struct.__va_list, %struct.__va_list* @the_list, i32 0, i32 3) // CHECK: [[EARLY_ONSTACK:%[a-z_0-9]+]] = icmp sge i32 [[GR_OFFS]], 0 @@ -853,7 +853,7 @@ typedef struct { __int128 val __attribute__((aligned(32))); } overaligned_int128_struct_member; overaligned_int128_struct_member overaligned_int128_struct_member_test() { -// CHECK-LABEL: define void @overaligned_int128_struct_member_test(%struct.overaligned_int128_struct_member* noalias sret %agg.result) +// CHECK-LABEL: define void @overaligned_int128_struct_member_test(%struct.overaligned_int128_struct_member* noalias sret align 32 %agg.result) return va_arg(the_list, overaligned_int128_struct_member); // CHECK: [[GR_OFFS:%[a-z_0-9]+]] = load i32, i32* getelementptr inbounds (%struct.__va_list, %struct.__va_list* @the_list, i32 0, i32 3) // CHECK: [[EARLY_ONSTACK:%[a-z_0-9]+]] = icmp sge i32 [[GR_OFFS]], 0 diff --git a/clang/test/CodeGen/aggregate-assign-call.c b/clang/test/CodeGen/aggregate-assign-call.c index d00cb90c09407..9616e6d22562f 100644 --- a/clang/test/CodeGen/aggregate-assign-call.c +++ b/clang/test/CodeGen/aggregate-assign-call.c @@ -62,8 +62,8 @@ struct S baz(int i, volatile int *j) { // O1-NEWPM: %[[TMP3:.*]] = bitcast %struct.S* %[[TMP2_ALLOCA]] to i8* // O1-NEWPM: call void @llvm.lifetime.end.p0i8({{[^,]*}}, i8* nonnull %[[P]]) // - // O1-LEGACY: call void @foo_int(%struct.S* sret %[[TMP1_ALLOCA]], - // O1-NEWPM: call void @foo_int(%struct.S* nonnull sret %[[TMP1_ALLOCA]], + // O1-LEGACY: call void @foo_int(%struct.S* sret align 4 %[[TMP1_ALLOCA]], + // O1-NEWPM: call void @foo_int(%struct.S* nonnull sret align 4 %[[TMP1_ALLOCA]], // O1: call void @llvm.memcpy // O1-LEGACY: %[[P:[^ ]+]] = bitcast %struct.S* %[[TMP1_ALLOCA]] to i8* // O1-LEGACY: call void @llvm.lifetime.end.p0i8({{[^,]*}}, i8* %[[P]]) @@ -71,8 +71,8 @@ struct S baz(int i, volatile int *j) { // O1-LEGACY: %[[P:[^ ]+]] = bitcast %struct.S* %[[TMP2_ALLOCA]] to i8* // O1-LEGACY: call void @llvm.lifetime.start.p0i8({{[^,]*}}, i8* %[[P]]) // O1-NEWPM: call void @llvm.lifetime.start.p0i8({{[^,]*}}, i8* nonnull %[[TMP3]]) - // O1-LEGACY: call void @foo_int(%struct.S* sret %[[TMP2_ALLOCA]], - // O1-NEWPM: call void @foo_int(%struct.S* nonnull sret %[[TMP2_ALLOCA]], + // O1-LEGACY: call void @foo_int(%struct.S* sret align 4 %[[TMP2_ALLOCA]], + // O1-NEWPM: call void @foo_int(%struct.S* nonnull sret align 4 %[[TMP2_ALLOCA]], // O1: call void @llvm.memcpy // O1-LEGACY: %[[P:[^ ]+]] = bitcast %struct.S* %[[TMP2_ALLOCA]] to i8* // O1-LEGACY: call void @llvm.lifetime.end.p0i8({{[^,]*}}, i8* %[[P]]) diff --git a/clang/test/CodeGen/aligned-sret.c b/clang/test/CodeGen/aligned-sret.c new file mode 100644 index 0000000000000..c459fe730163c --- /dev/null +++ b/clang/test/CodeGen/aligned-sret.c @@ -0,0 +1,10 @@ +// RUN: %clang_cc1 -triple x86_64-apple-macos %s -S -emit-llvm -o- | FileCheck %s + +typedef __attribute__((__ext_vector_type__(4),__aligned__(16))) double simd_double4; +typedef struct { simd_double4 columns[4]; } simd_double4x4; +typedef simd_double4x4 matrix_double4x4; + +// CHECK: define void @ident(%struct.simd_double4x4* noalias sret align 16 %agg.result +matrix_double4x4 ident(matrix_double4x4 x) { + return x; +} diff --git a/clang/test/CodeGen/arc/arguments.c b/clang/test/CodeGen/arc/arguments.c index fdc6037da730a..9c9b553b1be45 100644 --- a/clang/test/CodeGen/arc/arguments.c +++ b/clang/test/CodeGen/arc/arguments.c @@ -22,7 +22,7 @@ void cf1(cs1 i) {} typedef struct { int cc; } s2; -// CHECK: define void @f2(%struct.s2* noalias sret %agg.result) +// CHECK: define void @f2(%struct.s2* noalias sret align 4 %agg.result) s2 f2() { s2 foo; return foo; @@ -32,7 +32,7 @@ typedef struct { int cc; int dd; } s3; -// CHECK: define void @f3(%struct.s3* noalias sret %agg.result) +// CHECK: define void @f3(%struct.s3* noalias sret align 4 %agg.result) s3 f3() { s3 foo; return foo; @@ -128,8 +128,8 @@ void st3(s16 a, s16 b, s16 c) {} // 1 sret + 1 i32 + 2*(i32 coerce) + 4*(i32 coerce) + 1 byval s16 st4(int x, s8 a, s16 b, s16 c) { return b; } -// CHECK: define void @st4(%struct.s16* noalias sret %agg.result, i32 inreg %x, i32 inreg %a.coerce0, i32 inreg %a.coerce1, i32 inreg %b.coerce0, i32 inreg %b.coerce1, i32 inreg %b.coerce2, i32 inreg %b.coerce3, { i32, i32, i32, i32 } %c.coerce) +// CHECK: define void @st4(%struct.s16* noalias sret align 4 %agg.result, i32 inreg %x, i32 inreg %a.coerce0, i32 inreg %a.coerce1, i32 inreg %b.coerce0, i32 inreg %b.coerce1, i32 inreg %b.coerce2, i32 inreg %b.coerce3, { i32, i32, i32, i32 } %c.coerce) // 1 sret + 2*(i32 coerce) + 4*(i32 coerce) + 4*(i32 coerce) s16 st5(s8 a, s16 b, s16 c) { return b; } -// CHECK: define void @st5(%struct.s16* noalias sret %agg.result, i32 inreg %a.coerce0, i32 inreg %a.coerce1, i32 inreg %b.coerce0, i32 inreg %b.coerce1, i32 inreg %b.coerce2, i32 inreg %b.coerce3, { i32, i32, i32, i32 } %c.coerce) +// CHECK: define void @st5(%struct.s16* noalias sret align 4 %agg.result, i32 inreg %a.coerce0, i32 inreg %a.coerce1, i32 inreg %b.coerce0, i32 inreg %b.coerce1, i32 inreg %b.coerce2, i32 inreg %b.coerce3, { i32, i32, i32, i32 } %c.coerce) diff --git a/clang/test/CodeGen/arm-aapcs-vfp.c b/clang/test/CodeGen/arm-aapcs-vfp.c index 69581fcab2479..486ed6ab94fd4 100644 --- a/clang/test/CodeGen/arm-aapcs-vfp.c +++ b/clang/test/CodeGen/arm-aapcs-vfp.c @@ -125,7 +125,7 @@ void test_vfp_stack_gpr_split_1(double a, double b, double c, double d, double e // CHECK: define arm_aapcs_vfpcc void @test_vfp_stack_gpr_split_2(double %a, double %b, double %c, double %d, double %e, double %f, double %g, double %h, double %i, i32 %j, [2 x i64] %k.coerce) void test_vfp_stack_gpr_split_2(double a, double b, double c, double d, double e, double f, double g, double h, double i, int j, struct_long_long_int k) {} -// CHECK: define arm_aapcs_vfpcc void @test_vfp_stack_gpr_split_3(%struct.struct_long_long_int* noalias sret %agg.result, double %a, double %b, double %c, double %d, double %e, double %f, double %g, double %h, double %i, [2 x i64] %k.coerce) +// CHECK: define arm_aapcs_vfpcc void @test_vfp_stack_gpr_split_3(%struct.struct_long_long_int* noalias sret align 8 %agg.result, double %a, double %b, double %c, double %d, double %e, double %f, double %g, double %h, double %i, [2 x i64] %k.coerce) struct_long_long_int test_vfp_stack_gpr_split_3(double a, double b, double c, double d, double e, double f, double g, double h, double i, struct_long_long_int k) {} typedef struct { int a; int b:4; int c; } struct_int_bitfield_int; diff --git a/clang/test/CodeGen/arm-homogenous.c b/clang/test/CodeGen/arm-homogenous.c index 42a9bc1c16435..d321fc974c52e 100644 --- a/clang/test/CodeGen/arm-homogenous.c +++ b/clang/test/CodeGen/arm-homogenous.c @@ -27,7 +27,7 @@ void test_union_with_first_floats(void) { void test_return_union_with_first_floats(void) { g_u_f = returns_union_with_first_floats(); } -// CHECK: declare arm_aapcs_vfpcc void @returns_union_with_first_floats(%union.union_with_first_floats* sret) +// CHECK: declare arm_aapcs_vfpcc void @returns_union_with_first_floats(%union.union_with_first_floats* sret align 4) /* This is not a homogenous aggregate - fundamental types are different */ typedef union { @@ -47,7 +47,7 @@ void test_union_with_non_first_floats(void) { void test_return_union_with_non_first_floats(void) { g_u_nf_f = returns_union_with_non_first_floats(); } -// CHECK: declare arm_aapcs_vfpcc void @returns_union_with_non_first_floats(%union.union_with_non_first_floats* sret) +// CHECK: declare arm_aapcs_vfpcc void @returns_union_with_non_first_floats(%union.union_with_non_first_floats* sret align 4) /* This is not a homogenous aggregate - fundamental types are different */ typedef struct { @@ -67,7 +67,7 @@ void test_struct_with_union_with_first_floats(void) { void test_return_struct_with_union_with_first_floats(void) { g_s_f = returns_struct_with_union_with_first_floats(); } -// CHECK: declare arm_aapcs_vfpcc void @returns_struct_with_union_with_first_floats(%struct.struct_with_union_with_first_floats* sret) +// CHECK: declare arm_aapcs_vfpcc void @returns_struct_with_union_with_first_floats(%struct.struct_with_union_with_first_floats* sret align 4) /* This is not a homogenous aggregate - fundamental types are different */ typedef struct { @@ -87,7 +87,7 @@ void test_struct_with_union_with_non_first_floats(void) { void test_return_struct_with_union_with_non_first_floats(void) { g_s_nf_f = returns_struct_with_union_with_non_first_floats(); } -// CHECK: declare arm_aapcs_vfpcc void @returns_struct_with_union_with_non_first_floats(%struct.struct_with_union_with_non_first_floats* sret) +// CHECK: declare arm_aapcs_vfpcc void @returns_struct_with_union_with_non_first_floats(%struct.struct_with_union_with_non_first_floats* sret align 4) /* Plain array is not a homogenous aggregate */ extern void takes_array_of_floats(float a[4]); diff --git a/clang/test/CodeGen/arm-neon-vld.c b/clang/test/CodeGen/arm-neon-vld.c index 2c7af92f4796a..8d3d61c250a92 100644 --- a/clang/test/CodeGen/arm-neon-vld.c +++ b/clang/test/CodeGen/arm-neon-vld.c @@ -9,7 +9,7 @@ // CHECK-LABEL: @test_vld1_f16_x2( // CHECK-A64: [[RETVAL:%.*]] = alloca %struct.float16x4x2_t, align 8 -// CHECK-A32: %struct.float16x4x2_t* noalias sret [[RETVAL:%.*]], +// CHECK-A32: %struct.float16x4x2_t* noalias sret align 8 [[RETVAL:%.*]], // CHECK: [[__RET:%.*]] = alloca %struct.float16x4x2_t, align 8 // CHECK: [[TMP0:%.*]] = bitcast %struct.float16x4x2_t* [[__RET]] to i8* // CHECK: [[TMP1:%.*]] = bitcast half* %a to i8* @@ -29,7 +29,7 @@ float16x4x2_t test_vld1_f16_x2(float16_t const *a) { // CHECK-LABEL: @test_vld1_f16_x3( // CHECK-A64: [[RETVAL:%.*]] = alloca %struct.float16x4x3_t, align 8 -// CHECK-A32: %struct.float16x4x3_t* noalias sret [[RETVAL:%.*]], +// CHECK-A32: %struct.float16x4x3_t* noalias sret align 8 [[RETVAL:%.*]], // CHECK: [[__RET:%.*]] = alloca %struct.float16x4x3_t, align 8 // CHECK: [[TMP0:%.*]] = bitcast %struct.float16x4x3_t* [[__RET]] to i8* // CHECK: [[TMP1:%.*]] = bitcast half* %a to i8* @@ -49,7 +49,7 @@ float16x4x3_t test_vld1_f16_x3(float16_t const *a) { // CHECK-LABEL: @test_vld1_f16_x4( // CHECK-A64: [[RETVAL:%.*]] = alloca %struct.float16x4x4_t, align 8 -// CHECK-A32: %struct.float16x4x4_t* noalias sret [[RETVAL:%.*]], +// CHECK-A32: %struct.float16x4x4_t* noalias sret align 8 [[RETVAL:%.*]], // CHECK: [[__RET:%.*]] = alloca %struct.float16x4x4_t, align 8 // CHECK: [[TMP0:%.*]] = bitcast %struct.float16x4x4_t* [[__RET]] to i8* // CHECK: [[TMP1:%.*]] = bitcast half* %a to i8* @@ -69,7 +69,7 @@ float16x4x4_t test_vld1_f16_x4(float16_t const *a) { // CHECK-LABEL: @test_vld1_f32_x2( // CHECK-A64: [[RETVAL:%.*]] = alloca %struct.float32x2x2_t, align 8 -// CHECK-A32: %struct.float32x2x2_t* noalias sret [[RETVAL:%.*]], +// CHECK-A32: %struct.float32x2x2_t* noalias sret align 8 [[RETVAL:%.*]], // CHECK: [[__RET:%.*]] = alloca %struct.float32x2x2_t, align 8 // CHECK: [[TMP0:%.*]] = bitcast %struct.float32x2x2_t* [[__RET]] to i8* // CHECK: [[TMP1:%.*]] = bitcast float* %a to i8* @@ -89,7 +89,7 @@ float32x2x2_t test_vld1_f32_x2(float32_t const *a) { // CHECK-LABEL: @test_vld1_f32_x3( // CHECK-A64: [[RETVAL:%.*]] = alloca %struct.float32x2x3_t, align 8 -// CHECK-A32: %struct.float32x2x3_t* noalias sret [[RETVAL:%.*]], +// CHECK-A32: %struct.float32x2x3_t* noalias sret align 8 [[RETVAL:%.*]], // CHECK: [[__RET:%.*]] = alloca %struct.float32x2x3_t, align 8 // CHECK: [[TMP0:%.*]] = bitcast %struct.float32x2x3_t* [[__RET]] to i8* // CHECK: [[TMP1:%.*]] = bitcast float* %a to i8* @@ -108,7 +108,7 @@ float32x2x3_t test_vld1_f32_x3(float32_t const *a) { // CHECK-LABEL: @test_vld1_f32_x4( // CHECK-A64: [[RETVAL:%.*]] = alloca %struct.float32x2x4_t, align 8 -// CHECK-A32: %struct.float32x2x4_t* noalias sret [[RETVAL:%.*]], +// CHECK-A32: %struct.float32x2x4_t* noalias sret align 8 [[RETVAL:%.*]], // CHECK: [[__RET:%.*]] = alloca %struct.float32x2x4_t, align 8 // CHECK: [[TMP0:%.*]] = bitcast %struct.float32x2x4_t* [[__RET]] to i8* // CHECK: [[TMP1:%.*]] = bitcast float* %a to i8* @@ -128,7 +128,7 @@ float32x2x4_t test_vld1_f32_x4(float32_t const *a) { // CHECK-LABEL: @test_vld1_p16_x2( // CHECK-A64: [[RETVAL:%.*]] = alloca %struct.poly16x4x2_t, align 8 -// CHECK-A32: %struct.poly16x4x2_t* noalias sret [[RETVAL:%.*]], +// CHECK-A32: %struct.poly16x4x2_t* noalias sret align 8 [[RETVAL:%.*]], // CHECK: [[__RET:%.*]] = alloca %struct.poly16x4x2_t, align 8 // CHECK: [[TMP0:%.*]] = bitcast %struct.poly16x4x2_t* [[__RET]] to i8* // CHECK: [[TMP1:%.*]] = bitcast i16* %a to i8* @@ -148,7 +148,7 @@ poly16x4x2_t test_vld1_p16_x2(poly16_t const *a) { // CHECK-LABEL: @test_vld1_p16_x3( // CHECK-A64: [[RETVAL:%.*]] = alloca %struct.poly16x4x3_t, align 8 -// CHECK-A32: %struct.poly16x4x3_t* noalias sret [[RETVAL:%.*]], +// CHECK-A32: %struct.poly16x4x3_t* noalias sret align 8 [[RETVAL:%.*]], // CHECK: [[__RET:%.*]] = alloca %struct.poly16x4x3_t, align 8 // CHECK: [[TMP0:%.*]] = bitcast %struct.poly16x4x3_t* [[__RET]] to i8* // CHECK: [[TMP1:%.*]] = bitcast i16* %a to i8* @@ -168,7 +168,7 @@ poly16x4x3_t test_vld1_p16_x3(poly16_t const *a) { // CHECK-LABEL: @test_vld1_p16_x4( // CHECK-A64: [[RETVAL:%.*]] = alloca %struct.poly16x4x4_t, align 8 -// CHECK-A32: %struct.poly16x4x4_t* noalias sret [[RETVAL:%.*]], +// CHECK-A32: %struct.poly16x4x4_t* noalias sret align 8 [[RETVAL:%.*]], // CHECK: [[__RET:%.*]] = alloca %struct.poly16x4x4_t, align 8 // CHECK: [[TMP0:%.*]] = bitcast %struct.poly16x4x4_t* [[__RET]] to i8* // CHECK: [[TMP1:%.*]] = bitcast i16* %a to i8* @@ -188,7 +188,7 @@ poly16x4x4_t test_vld1_p16_x4(poly16_t const *a) { // CHECK-LABEL: @test_vld1_p8_x2( // CHECK-A64: [[RETVAL:%.*]] = alloca %struct.poly8x8x2_t, align 8 -// CHECK-A32: %struct.poly8x8x2_t* noalias sret [[RETVAL:%.*]], +// CHECK-A32: %struct.poly8x8x2_t* noalias sret align 8 [[RETVAL:%.*]], // CHECK: [[__RET:%.*]] = alloca %struct.poly8x8x2_t, align 8 // CHECK: [[TMP0:%.*]] = bitcast %struct.poly8x8x2_t* [[__RET]] to i8* // CHECK: [[VLD1XN:%.*]] = call { <8 x i8>, <8 x i8> } @llvm.{{aarch64.neon.ld1x2|arm.neon.vld1x2}}.v8i8.p0i8(i8* %a) @@ -206,7 +206,7 @@ poly8x8x2_t test_vld1_p8_x2(poly8_t const *a) { // CHECK-LABEL: @test_vld1_p8_x3( // CHECK-A64: [[RETVAL:%.*]] = alloca %struct.poly8x8x3_t, align 8 -// CHECK-A32: %struct.poly8x8x3_t* noalias sret [[RETVAL:%.*]], +// CHECK-A32: %struct.poly8x8x3_t* noalias sret align 8 [[RETVAL:%.*]], // CHECK: [[__RET:%.*]] = alloca %struct.poly8x8x3_t, align 8 // CHECK: [[TMP0:%.*]] = bitcast %struct.poly8x8x3_t* [[__RET]] to i8* // CHECK: [[VLD1XN:%.*]] = call { <8 x i8>, <8 x i8>, <8 x i8> } @llvm.{{aarch64.neon.ld1x3|arm.neon.vld1x3}}.v8i8.p0i8(i8* %a) @@ -224,7 +224,7 @@ poly8x8x3_t test_vld1_p8_x3(poly8_t const *a) { // CHECK-LABEL: @test_vld1_p8_x4( // CHECK-A64: [[RETVAL:%.*]] = alloca %struct.poly8x8x4_t, align 8 -// CHECK-A32: %struct.poly8x8x4_t* noalias sret [[RETVAL:%.*]], +// CHECK-A32: %struct.poly8x8x4_t* noalias sret align 8 [[RETVAL:%.*]], // CHECK: [[__RET:%.*]] = alloca %struct.poly8x8x4_t, align 8 // CHECK: [[TMP0:%.*]] = bitcast %struct.poly8x8x4_t* [[__RET]] to i8* // CHECK: [[VLD1XN:%.*]] = call { <8 x i8>, <8 x i8>, <8 x i8>, <8 x i8> } @llvm.{{aarch64.neon.ld1x4|arm.neon.vld1x4}}.v8i8.p0i8(i8* %a) @@ -242,7 +242,7 @@ poly8x8x4_t test_vld1_p8_x4(poly8_t const *a) { // CHECK-LABEL: @test_vld1_s16_x2( // CHECK-A64: [[RETVAL:%.*]] = alloca %struct.int16x4x2_t, align 8 -// CHECK-A32: %struct.int16x4x2_t* noalias sret [[RETVAL:%.*]], +// CHECK-A32: %struct.int16x4x2_t* noalias sret align 8 [[RETVAL:%.*]], // CHECK: [[__RET:%.*]] = alloca %struct.int16x4x2_t, align 8 // CHECK: [[TMP0:%.*]] = bitcast %struct.int16x4x2_t* [[__RET]] to i8* // CHECK: [[TMP1:%.*]] = bitcast i16* %a to i8* @@ -262,7 +262,7 @@ int16x4x2_t test_vld1_s16_x2(int16_t const *a) { // CHECK-LABEL: @test_vld1_s16_x3( // CHECK-A64: [[RETVAL:%.*]] = alloca %struct.int16x4x3_t, align 8 -// CHECK-A32: %struct.int16x4x3_t* noalias sret [[RETVAL:%.*]], +// CHECK-A32: %struct.int16x4x3_t* noalias sret align 8 [[RETVAL:%.*]], // CHECK: [[__RET:%.*]] = alloca %struct.int16x4x3_t, align 8 // CHECK: [[TMP0:%.*]] = bitcast %struct.int16x4x3_t* [[__RET]] to i8* // CHECK: [[TMP1:%.*]] = bitcast i16* %a to i8* @@ -282,7 +282,7 @@ int16x4x3_t test_vld1_s16_x3(int16_t const *a) { // CHECK-LABEL: @test_vld1_s16_x4( // CHECK-A64: [[RETVAL:%.*]] = alloca %struct.int16x4x4_t, align 8 -// CHECK-A32: %struct.int16x4x4_t* noalias sret [[RETVAL:%.*]], +// CHECK-A32: %struct.int16x4x4_t* noalias sret align 8 [[RETVAL:%.*]], // CHECK: [[__RET:%.*]] = alloca %struct.int16x4x4_t, align 8 // CHECK: [[TMP0:%.*]] = bitcast %struct.int16x4x4_t* [[__RET]] to i8* // CHECK: [[TMP1:%.*]] = bitcast i16* %a to i8* @@ -302,7 +302,7 @@ int16x4x4_t test_vld1_s16_x4(int16_t const *a) { // CHECK-LABEL: @test_vld1_s32_x2( // CHECK-A64: [[RETVAL:%.*]] = alloca %struct.int32x2x2_t, align 8 -// CHECK-A32: %struct.int32x2x2_t* noalias sret [[RETVAL:%.*]], +// CHECK-A32: %struct.int32x2x2_t* noalias sret align 8 [[RETVAL:%.*]], // CHECK: [[__RET:%.*]] = alloca %struct.int32x2x2_t, align 8 // CHECK: [[TMP0:%.*]] = bitcast %struct.int32x2x2_t* [[__RET]] to i8* // CHECK: [[TMP1:%.*]] = bitcast i32* %a to i8* @@ -322,7 +322,7 @@ int32x2x2_t test_vld1_s32_x2(int32_t const *a) { // CHECK-LABEL: @test_vld1_s32_x3( // CHECK-A64: [[RETVAL:%.*]] = alloca %struct.int32x2x3_t, align 8 -// CHECK-A32: %struct.int32x2x3_t* noalias sret [[RETVAL:%.*]], +// CHECK-A32: %struct.int32x2x3_t* noalias sret align 8 [[RETVAL:%.*]], // CHECK: [[__RET:%.*]] = alloca %struct.int32x2x3_t, align 8 // CHECK: [[TMP0:%.*]] = bitcast %struct.int32x2x3_t* [[__RET]] to i8* // CHECK: [[TMP1:%.*]] = bitcast i32* %a to i8* @@ -342,7 +342,7 @@ int32x2x3_t test_vld1_s32_x3(int32_t const *a) { // CHECK-LABEL: @test_vld1_s32_x4( // CHECK-A64: [[RETVAL:%.*]] = alloca %struct.int32x2x4_t, align 8 -// CHECK-A32: %struct.int32x2x4_t* noalias sret [[RETVAL:%.*]], +// CHECK-A32: %struct.int32x2x4_t* noalias sret align 8 [[RETVAL:%.*]], // CHECK: [[__RET:%.*]] = alloca %struct.int32x2x4_t, align 8 // CHECK: [[TMP0:%.*]] = bitcast %struct.int32x2x4_t* [[__RET]] to i8* // CHECK: [[TMP1:%.*]] = bitcast i32* %a to i8* @@ -362,7 +362,7 @@ int32x2x4_t test_vld1_s32_x4(int32_t const *a) { // CHECK-LABEL: @test_vld1_s64_x2( // CHECK-A64: [[RETVAL:%.*]] = alloca %struct.int64x1x2_t, align 8 -// CHECK-A32: %struct.int64x1x2_t* noalias sret [[RETVAL:%.*]], +// CHECK-A32: %struct.int64x1x2_t* noalias sret align 8 [[RETVAL:%.*]], // CHECK: [[__RET:%.*]] = alloca %struct.int64x1x2_t, align 8 // CHECK: [[TMP0:%.*]] = bitcast %struct.int64x1x2_t* [[__RET]] to i8* // CHECK: [[TMP1:%.*]] = bitcast i64* %a to i8* @@ -382,7 +382,7 @@ int64x1x2_t test_vld1_s64_x2(int64_t const *a) { // CHECK-LABEL: @test_vld1_s64_x3( // CHECK-A64: [[RETVAL:%.*]] = alloca %struct.int64x1x3_t, align 8 -// CHECK-A32: %struct.int64x1x3_t* noalias sret [[RETVAL:%.*]], +// CHECK-A32: %struct.int64x1x3_t* noalias sret align 8 [[RETVAL:%.*]], // CHECK: [[__RET:%.*]] = alloca %struct.int64x1x3_t, align 8 // CHECK: [[TMP0:%.*]] = bitcast %struct.int64x1x3_t* [[__RET]] to i8* // CHECK: [[TMP1:%.*]] = bitcast i64* %a to i8* @@ -402,7 +402,7 @@ int64x1x3_t test_vld1_s64_x3(int64_t const *a) { // CHECK-LABEL: @test_vld1_s64_x4( // CHECK-A64: [[RETVAL:%.*]] = alloca %struct.int64x1x4_t, align 8 -// CHECK-A32: %struct.int64x1x4_t* noalias sret [[RETVAL:%.*]], +// CHECK-A32: %struct.int64x1x4_t* noalias sret align 8 [[RETVAL:%.*]], // CHECK: [[__RET:%.*]] = alloca %struct.int64x1x4_t, align 8 // CHECK: [[TMP0:%.*]] = bitcast %struct.int64x1x4_t* [[__RET]] to i8* // CHECK: [[TMP1:%.*]] = bitcast i64* %a to i8* @@ -422,7 +422,7 @@ int64x1x4_t test_vld1_s64_x4(int64_t const *a) { // CHECK-LABEL: @test_vld1_s8_x2( // CHECK-A64: [[RETVAL:%.*]] = alloca %struct.int8x8x2_t, align 8 -// CHECK-A32: %struct.int8x8x2_t* noalias sret [[RETVAL:%.*]], +// CHECK-A32: %struct.int8x8x2_t* noalias sret align 8 [[RETVAL:%.*]], // CHECK: [[__RET:%.*]] = alloca %struct.int8x8x2_t, align 8 // CHECK: [[TMP0:%.*]] = bitcast %struct.int8x8x2_t* [[__RET]] to i8* // CHECK: [[VLD1XN:%.*]] = call { <8 x i8>, <8 x i8> } @llvm.{{aarch64.neon.ld1x2|arm.neon.vld1x2}}.v8i8.p0i8(i8* %a) @@ -440,7 +440,7 @@ int8x8x2_t test_vld1_s8_x2(int8_t const *a) { // CHECK-LABEL: @test_vld1_s8_x3( // CHECK-A64: [[RETVAL:%.*]] = alloca %struct.int8x8x3_t, align 8 -// CHECK-A32: %struct.int8x8x3_t* noalias sret [[RETVAL:%.*]], +// CHECK-A32: %struct.int8x8x3_t* noalias sret align 8 [[RETVAL:%.*]], // CHECK: [[__RET:%.*]] = alloca %struct.int8x8x3_t, align 8 // CHECK: [[TMP0:%.*]] = bitcast %struct.int8x8x3_t* [[__RET]] to i8* // CHECK: [[VLD1XN:%.*]] = call { <8 x i8>, <8 x i8>, <8 x i8> } @llvm.{{aarch64.neon.ld1x3|arm.neon.vld1x3}}.v8i8.p0i8(i8* %a) @@ -458,7 +458,7 @@ int8x8x3_t test_vld1_s8_x3(int8_t const *a) { // CHECK-LABEL: @test_vld1_s8_x4( // CHECK-A64: [[RETVAL:%.*]] = alloca %struct.int8x8x4_t, align 8 -// CHECK-A32: %struct.int8x8x4_t* noalias sret [[RETVAL:%.*]], +// CHECK-A32: %struct.int8x8x4_t* noalias sret align 8 [[RETVAL:%.*]], // CHECK: [[__RET:%.*]] = alloca %struct.int8x8x4_t, align 8 // CHECK: [[TMP0:%.*]] = bitcast %struct.int8x8x4_t* [[__RET]] to i8* // CHECK: [[VLD1XN:%.*]] = call { <8 x i8>, <8 x i8>, <8 x i8>, <8 x i8> } @llvm.{{aarch64.neon.ld1x4|arm.neon.vld1x4}}.v8i8.p0i8(i8* %a) @@ -476,7 +476,7 @@ int8x8x4_t test_vld1_s8_x4(int8_t const *a) { // CHECK-LABEL: @test_vld1_u16_x2( // CHECK-A64: [[RETVAL:%.*]] = alloca %struct.uint16x4x2_t, align 8 -// CHECK-A32: %struct.uint16x4x2_t* noalias sret [[RETVAL:%.*]], +// CHECK-A32: %struct.uint16x4x2_t* noalias sret align 8 [[RETVAL:%.*]], // CHECK: [[__RET:%.*]] = alloca %struct.uint16x4x2_t, align 8 // CHECK: [[TMP0:%.*]] = bitcast %struct.uint16x4x2_t* [[__RET]] to i8* // CHECK: [[TMP1:%.*]] = bitcast i16* %a to i8* @@ -496,7 +496,7 @@ uint16x4x2_t test_vld1_u16_x2(uint16_t const *a) { // CHECK-LABEL: @test_vld1_u16_x3( // CHECK-A64: [[RETVAL:%.*]] = alloca %struct.uint16x4x3_t, align 8 -// CHECK-A32: %struct.uint16x4x3_t* noalias sret [[RETVAL:%.*]], +// CHECK-A32: %struct.uint16x4x3_t* noalias sret align 8 [[RETVAL:%.*]], // CHECK: [[__RET:%.*]] = alloca %struct.uint16x4x3_t, align 8 // CHECK: [[TMP0:%.*]] = bitcast %struct.uint16x4x3_t* [[__RET]] to i8* // CHECK: [[TMP1:%.*]] = bitcast i16* %a to i8* @@ -516,7 +516,7 @@ uint16x4x3_t test_vld1_u16_x3(uint16_t const *a) { // CHECK-LABEL: @test_vld1_u16_x4( // CHECK-A64: [[RETVAL:%.*]] = alloca %struct.uint16x4x4_t, align 8 -// CHECK-A32: %struct.uint16x4x4_t* noalias sret [[RETVAL:%.*]], +// CHECK-A32: %struct.uint16x4x4_t* noalias sret align 8 [[RETVAL:%.*]], // CHECK: [[__RET:%.*]] = alloca %struct.uint16x4x4_t, align 8 // CHECK: [[TMP0:%.*]] = bitcast %struct.uint16x4x4_t* [[__RET]] to i8* // CHECK: [[TMP1:%.*]] = bitcast i16* %a to i8* @@ -536,7 +536,7 @@ uint16x4x4_t test_vld1_u16_x4(uint16_t const *a) { // CHECK-LABEL: @test_vld1_u32_x2( // CHECK-A64: [[RETVAL:%.*]] = alloca %struct.uint32x2x2_t, align 8 -// CHECK-A32: %struct.uint32x2x2_t* noalias sret [[RETVAL:%.*]], +// CHECK-A32: %struct.uint32x2x2_t* noalias sret align 8 [[RETVAL:%.*]], // CHECK: [[__RET:%.*]] = alloca %struct.uint32x2x2_t, align 8 // CHECK: [[TMP0:%.*]] = bitcast %struct.uint32x2x2_t* [[__RET]] to i8* // CHECK: [[TMP1:%.*]] = bitcast i32* %a to i8* @@ -556,7 +556,7 @@ uint32x2x2_t test_vld1_u32_x2(uint32_t const *a) { // CHECK-LABEL: @test_vld1_u32_x3( // CHECK-A64: [[RETVAL:%.*]] = alloca %struct.uint32x2x3_t, align 8 -// CHECK-A32: %struct.uint32x2x3_t* noalias sret [[RETVAL:%.*]], +// CHECK-A32: %struct.uint32x2x3_t* noalias sret align 8 [[RETVAL:%.*]], // CHECK: [[__RET:%.*]] = alloca %struct.uint32x2x3_t, align 8 // CHECK: [[TMP0:%.*]] = bitcast %struct.uint32x2x3_t* [[__RET]] to i8* // CHECK: [[TMP1:%.*]] = bitcast i32* %a to i8* @@ -576,7 +576,7 @@ uint32x2x3_t test_vld1_u32_x3(uint32_t const *a) { // CHECK-LABEL: @test_vld1_u32_x4( // CHECK-A64: [[RETVAL:%.*]] = alloca %struct.uint32x2x4_t, align 8 -// CHECK-A32: %struct.uint32x2x4_t* noalias sret [[RETVAL:%.*]], +// CHECK-A32: %struct.uint32x2x4_t* noalias sret align 8 [[RETVAL:%.*]], // CHECK: [[__RET:%.*]] = alloca %struct.uint32x2x4_t, align 8 // CHECK: [[TMP0:%.*]] = bitcast %struct.uint32x2x4_t* [[__RET]] to i8* // CHECK: [[TMP1:%.*]] = bitcast i32* %a to i8* @@ -596,7 +596,7 @@ uint32x2x4_t test_vld1_u32_x4(uint32_t const *a) { // CHECK-LABEL: @test_vld1_u64_x2( // CHECK-A64: [[RETVAL:%.*]] = alloca %struct.uint64x1x2_t, align 8 -// CHECK-A32: %struct.uint64x1x2_t* noalias sret [[RETVAL:%.*]], +// CHECK-A32: %struct.uint64x1x2_t* noalias sret align 8 [[RETVAL:%.*]], // CHECK: [[__RET:%.*]] = alloca %struct.uint64x1x2_t, align 8 // CHECK: [[TMP0:%.*]] = bitcast %struct.uint64x1x2_t* [[__RET]] to i8* // CHECK: [[TMP1:%.*]] = bitcast i64* %a to i8* @@ -616,7 +616,7 @@ uint64x1x2_t test_vld1_u64_x2(uint64_t const *a) { // CHECK-LABEL: @test_vld1_u64_x3( // CHECK-A64: [[RETVAL:%.*]] = alloca %struct.uint64x1x3_t, align 8 -// CHECK-A32: %struct.uint64x1x3_t* noalias sret [[RETVAL:%.*]], +// CHECK-A32: %struct.uint64x1x3_t* noalias sret align 8 [[RETVAL:%.*]], // CHECK: [[__RET:%.*]] = alloca %struct.uint64x1x3_t, align 8 // CHECK: [[TMP0:%.*]] = bitcast %struct.uint64x1x3_t* [[__RET]] to i8* // CHECK: [[TMP1:%.*]] = bitcast i64* %a to i8* @@ -636,7 +636,7 @@ uint64x1x3_t test_vld1_u64_x3(uint64_t const *a) { // CHECK-LABEL: @test_vld1_u64_x4( // CHECK-A64: [[RETVAL:%.*]] = alloca %struct.uint64x1x4_t, align 8 -// CHECK-A32: %struct.uint64x1x4_t* noalias sret [[RETVAL:%.*]], +// CHECK-A32: %struct.uint64x1x4_t* noalias sret align 8 [[RETVAL:%.*]], // CHECK: [[__RET:%.*]] = alloca %struct.uint64x1x4_t, align 8 // CHECK: [[TMP0:%.*]] = bitcast %struct.uint64x1x4_t* [[__RET]] to i8* // CHECK: [[TMP1:%.*]] = bitcast i64* %a to i8* @@ -656,7 +656,7 @@ uint64x1x4_t test_vld1_u64_x4(uint64_t const *a) { // CHECK-LABEL: @test_vld1_u8_x2( // CHECK-A64: [[RETVAL:%.*]] = alloca %struct.uint8x8x2_t, align 8 -// CHECK-A32: %struct.uint8x8x2_t* noalias sret [[RETVAL:%.*]], +// CHECK-A32: %struct.uint8x8x2_t* noalias sret align 8 [[RETVAL:%.*]], // CHECK: [[__RET:%.*]] = alloca %struct.uint8x8x2_t, align 8 // CHECK: [[TMP0:%.*]] = bitcast %struct.uint8x8x2_t* [[__RET]] to i8* // CHECK: [[VLD1XN:%.*]] = call { <8 x i8>, <8 x i8> } @llvm.{{aarch64.neon.ld1x2|arm.neon.vld1x2}}.v8i8.p0i8(i8* %a) @@ -674,7 +674,7 @@ uint8x8x2_t test_vld1_u8_x2(uint8_t const *a) { // CHECK-LABEL: @test_vld1_u8_x3( // CHECK-A64: [[RETVAL:%.*]] = alloca %struct.uint8x8x3_t, align 8 -// CHECK-A32: %struct.uint8x8x3_t* noalias sret [[RETVAL:%.*]], +// CHECK-A32: %struct.uint8x8x3_t* noalias sret align 8 [[RETVAL:%.*]], // CHECK: [[__RET:%.*]] = alloca %struct.uint8x8x3_t, align 8 // CHECK: [[TMP0:%.*]] = bitcast %struct.uint8x8x3_t* [[__RET]] to i8* // CHECK: [[VLD1XN:%.*]] = call { <8 x i8>, <8 x i8>, <8 x i8> } @llvm.{{aarch64.neon.ld1x3|arm.neon.vld1x3}}.v8i8.p0i8(i8* %a) @@ -692,7 +692,7 @@ uint8x8x3_t test_vld1_u8_x3(uint8_t const *a) { // CHECK-LABEL: @test_vld1_u8_x4( // CHECK-A64: [[RETVAL:%.*]] = alloca %struct.uint8x8x4_t, align 8 -// CHECK-A32: %struct.uint8x8x4_t* noalias sret [[RETVAL:%.*]], +// CHECK-A32: %struct.uint8x8x4_t* noalias sret align 8 [[RETVAL:%.*]], // CHECK: [[__RET:%.*]] = alloca %struct.uint8x8x4_t, align 8 // CHECK: [[TMP0:%.*]] = bitcast %struct.uint8x8x4_t* [[__RET]] to i8* // CHECK: [[VLD1XN:%.*]] = call { <8 x i8>, <8 x i8>, <8 x i8>, <8 x i8> } @llvm.{{aarch64.neon.ld1x4|arm.neon.vld1x4}}.v8i8.p0i8(i8* %a) @@ -710,7 +710,7 @@ uint8x8x4_t test_vld1_u8_x4(uint8_t const *a) { // CHECK-LABEL: @test_vld1q_f16_x2( // CHECK-A64: [[RETVAL:%.*]] = alloca %struct.float16x8x2_t, align 16 -// CHECK-A32: %struct.float16x8x2_t* noalias sret [[RETVAL:%.*]], +// CHECK-A32: %struct.float16x8x2_t* noalias sret align 8 [[RETVAL:%.*]], // CHECK: [[__RET:%.*]] = alloca %struct.float16x8x2_t, align {{16|8}} // CHECK: [[TMP0:%.*]] = bitcast %struct.float16x8x2_t* [[__RET]] to i8* // CHECK: [[TMP1:%.*]] = bitcast half* %a to i8* @@ -730,7 +730,7 @@ float16x8x2_t test_vld1q_f16_x2(float16_t const *a) { // CHECK-LABEL: @test_vld1q_f16_x3( // CHECK-A64: [[RETVAL:%.*]] = alloca %struct.float16x8x3_t, align 16 -// CHECK-A32: %struct.float16x8x3_t* noalias sret [[RETVAL:%.*]], +// CHECK-A32: %struct.float16x8x3_t* noalias sret align 8 [[RETVAL:%.*]], // CHECK: [[__RET:%.*]] = alloca %struct.float16x8x3_t, align {{16|8}} // CHECK: [[TMP0:%.*]] = bitcast %struct.float16x8x3_t* [[__RET]] to i8* // CHECK: [[TMP1:%.*]] = bitcast half* %a to i8* @@ -750,7 +750,7 @@ float16x8x3_t test_vld1q_f16_x3(float16_t const *a) { // CHECK-LABEL: @test_vld1q_f16_x4( // CHECK-A64: [[RETVAL:%.*]] = alloca %struct.float16x8x4_t, align 16 -// CHECK-A32: %struct.float16x8x4_t* noalias sret [[RETVAL:%.*]], +// CHECK-A32: %struct.float16x8x4_t* noalias sret align 8 [[RETVAL:%.*]], // CHECK: [[__RET:%.*]] = alloca %struct.float16x8x4_t, align {{16|8}} // CHECK: [[TMP0:%.*]] = bitcast %struct.float16x8x4_t* [[__RET]] to i8* // CHECK: [[TMP1:%.*]] = bitcast half* %a to i8* @@ -770,7 +770,7 @@ float16x8x4_t test_vld1q_f16_x4(float16_t const *a) { // CHECK-LABEL: @test_vld1q_f32_x2( // CHECK-A64: [[RETVAL:%.*]] = alloca %struct.float32x4x2_t, align 16 -// CHECK-A32: %struct.float32x4x2_t* noalias sret [[RETVAL:%.*]], +// CHECK-A32: %struct.float32x4x2_t* noalias sret align 8 [[RETVAL:%.*]], // CHECK: [[__RET:%.*]] = alloca %struct.float32x4x2_t, align {{16|8}} // CHECK: [[TMP0:%.*]] = bitcast %struct.float32x4x2_t* [[__RET]] to i8* // CHECK: [[TMP1:%.*]] = bitcast float* %a to i8* @@ -790,7 +790,7 @@ float32x4x2_t test_vld1q_f32_x2(float32_t const *a) { // CHECK-LABEL: @test_vld1q_f32_x3( // CHECK-A64: [[RETVAL:%.*]] = alloca %struct.float32x4x3_t, align 16 -// CHECK-A32: %struct.float32x4x3_t* noalias sret [[RETVAL:%.*]], +// CHECK-A32: %struct.float32x4x3_t* noalias sret align 8 [[RETVAL:%.*]], // CHECK: [[__RET:%.*]] = alloca %struct.float32x4x3_t, align {{16|8}} // CHECK: [[TMP0:%.*]] = bitcast %struct.float32x4x3_t* [[__RET]] to i8* // CHECK: [[TMP1:%.*]] = bitcast float* %a to i8* @@ -810,7 +810,7 @@ float32x4x3_t test_vld1q_f32_x3(float32_t const *a) { // CHECK-LABEL: @test_vld1q_f32_x4( // CHECK-A64: [[RETVAL:%.*]] = alloca %struct.float32x4x4_t, align 16 -// CHECK-A32: %struct.float32x4x4_t* noalias sret [[RETVAL:%.*]], +// CHECK-A32: %struct.float32x4x4_t* noalias sret align 8 [[RETVAL:%.*]], // CHECK: [[__RET:%.*]] = alloca %struct.float32x4x4_t, align {{16|8}} // CHECK: [[TMP0:%.*]] = bitcast %struct.float32x4x4_t* [[__RET]] to i8* // CHECK: [[TMP1:%.*]] = bitcast float* %a to i8* @@ -830,7 +830,7 @@ float32x4x4_t test_vld1q_f32_x4(float32_t const *a) { // CHECK-LABEL: @test_vld1q_p16_x2( // CHECK-A64: [[RETVAL:%.*]] = alloca %struct.poly16x8x2_t, align 16 -// CHECK-A32: %struct.poly16x8x2_t* noalias sret [[RETVAL:%.*]], +// CHECK-A32: %struct.poly16x8x2_t* noalias sret align 8 [[RETVAL:%.*]], // CHECK: [[__RET:%.*]] = alloca %struct.poly16x8x2_t, align {{16|8}} // CHECK: [[TMP0:%.*]] = bitcast %struct.poly16x8x2_t* [[__RET]] to i8* // CHECK: [[TMP1:%.*]] = bitcast i16* %a to i8* @@ -850,7 +850,7 @@ poly16x8x2_t test_vld1q_p16_x2(poly16_t const *a) { // CHECK-LABEL: @test_vld1q_p16_x3( // CHECK-A64: [[RETVAL:%.*]] = alloca %struct.poly16x8x3_t, align 16 -// CHECK-A32: %struct.poly16x8x3_t* noalias sret [[RETVAL:%.*]], +// CHECK-A32: %struct.poly16x8x3_t* noalias sret align 8 [[RETVAL:%.*]], // CHECK: [[__RET:%.*]] = alloca %struct.poly16x8x3_t, align {{16|8}} // CHECK: [[TMP0:%.*]] = bitcast %struct.poly16x8x3_t* [[__RET]] to i8* // CHECK: [[TMP1:%.*]] = bitcast i16* %a to i8* @@ -870,7 +870,7 @@ poly16x8x3_t test_vld1q_p16_x3(poly16_t const *a) { // CHECK-LABEL: @test_vld1q_p16_x4( // CHECK-A64: [[RETVAL:%.*]] = alloca %struct.poly16x8x4_t, align 16 -// CHECK-A32: %struct.poly16x8x4_t* noalias sret [[RETVAL:%.*]], +// CHECK-A32: %struct.poly16x8x4_t* noalias sret align 8 [[RETVAL:%.*]], // CHECK: [[__RET:%.*]] = alloca %struct.poly16x8x4_t, align {{16|8}} // CHECK: [[TMP0:%.*]] = bitcast %struct.poly16x8x4_t* [[__RET]] to i8* // CHECK: [[TMP1:%.*]] = bitcast i16* %a to i8* @@ -890,7 +890,7 @@ poly16x8x4_t test_vld1q_p16_x4(poly16_t const *a) { // CHECK-LABEL: @test_vld1q_p8_x2( // CHECK-A64: [[RETVAL:%.*]] = alloca %struct.poly8x16x2_t, align 16 -// CHECK-A32: %struct.poly8x16x2_t* noalias sret [[RETVAL:%.*]], +// CHECK-A32: %struct.poly8x16x2_t* noalias sret align 8 [[RETVAL:%.*]], // CHECK: [[__RET:%.*]] = alloca %struct.poly8x16x2_t, align {{16|8}} // CHECK: [[TMP0:%.*]] = bitcast %struct.poly8x16x2_t* [[__RET]] to i8* // CHECK: [[VLD1XN:%.*]] = call { <16 x i8>, <16 x i8> } @llvm.{{aarch64.neon.ld1x2|arm.neon.vld1x2}}.v16i8.p0i8(i8* %a) @@ -908,7 +908,7 @@ poly8x16x2_t test_vld1q_p8_x2(poly8_t const *a) { // CHECK-LABEL: @test_vld1q_p8_x3( // CHECK-A64: [[RETVAL:%.*]] = alloca %struct.poly8x16x3_t, align 16 -// CHECK-A32: %struct.poly8x16x3_t* noalias sret [[RETVAL:%.*]], +// CHECK-A32: %struct.poly8x16x3_t* noalias sret align 8 [[RETVAL:%.*]], // CHECK: [[__RET:%.*]] = alloca %struct.poly8x16x3_t, align {{16|8}} // CHECK: [[TMP0:%.*]] = bitcast %struct.poly8x16x3_t* [[__RET]] to i8* // CHECK: [[VLD1XN:%.*]] = call { <16 x i8>, <16 x i8>, <16 x i8> } @llvm.{{aarch64.neon.ld1x3|arm.neon.vld1x3}}.v16i8.p0i8(i8* %a) @@ -926,7 +926,7 @@ poly8x16x3_t test_vld1q_p8_x3(poly8_t const *a) { // CHECK-LABEL: @test_vld1q_p8_x4( // CHECK-A64: [[RETVAL:%.*]] = alloca %struct.poly8x16x4_t, align 16 -// CHECK-A32: %struct.poly8x16x4_t* noalias sret [[RETVAL:%.*]], +// CHECK-A32: %struct.poly8x16x4_t* noalias sret align 8 [[RETVAL:%.*]], // CHECK: [[__RET:%.*]] = alloca %struct.poly8x16x4_t, align {{16|8}} // CHECK: [[TMP0:%.*]] = bitcast %struct.poly8x16x4_t* [[__RET]] to i8* // CHECK: [[VLD1XN:%.*]] = call { <16 x i8>, <16 x i8>, <16 x i8>, <16 x i8> } @llvm.{{aarch64.neon.ld1x4|arm.neon.vld1x4}}.v16i8.p0i8(i8* %a) @@ -944,7 +944,7 @@ poly8x16x4_t test_vld1q_p8_x4(poly8_t const *a) { // CHECK-LABEL: @test_vld1q_s16_x2( // CHECK-A64: [[RETVAL:%.*]] = alloca %struct.int16x8x2_t, align 16 -// CHECK-A32: %struct.int16x8x2_t* noalias sret [[RETVAL:%.*]], +// CHECK-A32: %struct.int16x8x2_t* noalias sret align 8 [[RETVAL:%.*]], // CHECK: [[__RET:%.*]] = alloca %struct.int16x8x2_t, align {{16|8}} // CHECK: [[TMP0:%.*]] = bitcast %struct.int16x8x2_t* [[__RET]] to i8* // CHECK: [[TMP1:%.*]] = bitcast i16* %a to i8* @@ -964,7 +964,7 @@ int16x8x2_t test_vld1q_s16_x2(int16_t const *a) { // CHECK-LABEL: @test_vld1q_s16_x3( // CHECK-A64: [[RETVAL:%.*]] = alloca %struct.int16x8x3_t, align 16 -// CHECK-A32: %struct.int16x8x3_t* noalias sret [[RETVAL:%.*]], +// CHECK-A32: %struct.int16x8x3_t* noalias sret align 8 [[RETVAL:%.*]], // CHECK: [[__RET:%.*]] = alloca %struct.int16x8x3_t, align {{16|8}} // CHECK: [[TMP0:%.*]] = bitcast %struct.int16x8x3_t* [[__RET]] to i8* // CHECK: [[TMP1:%.*]] = bitcast i16* %a to i8* @@ -984,7 +984,7 @@ int16x8x3_t test_vld1q_s16_x3(int16_t const *a) { // CHECK-LABEL: @test_vld1q_s16_x4( // CHECK-A64: [[RETVAL:%.*]] = alloca %struct.int16x8x4_t, align 16 -// CHECK-A32: %struct.int16x8x4_t* noalias sret [[RETVAL:%.*]], +// CHECK-A32: %struct.int16x8x4_t* noalias sret align 8 [[RETVAL:%.*]], // CHECK: [[__RET:%.*]] = alloca %struct.int16x8x4_t, align {{16|8}} // CHECK: [[TMP0:%.*]] = bitcast %struct.int16x8x4_t* [[__RET]] to i8* // CHECK: [[TMP1:%.*]] = bitcast i16* %a to i8* @@ -1004,7 +1004,7 @@ int16x8x4_t test_vld1q_s16_x4(int16_t const *a) { // CHECK-LABEL: @test_vld1q_s32_x2( // CHECK-A64: [[RETVAL:%.*]] = alloca %struct.int32x4x2_t, align 16 -// CHECK-A32: %struct.int32x4x2_t* noalias sret [[RETVAL:%.*]], +// CHECK-A32: %struct.int32x4x2_t* noalias sret align 8 [[RETVAL:%.*]], // CHECK: [[__RET:%.*]] = alloca %struct.int32x4x2_t, align {{16|8}} // CHECK: [[TMP0:%.*]] = bitcast %struct.int32x4x2_t* [[__RET]] to i8* // CHECK: [[TMP1:%.*]] = bitcast i32* %a to i8* @@ -1024,7 +1024,7 @@ int32x4x2_t test_vld1q_s32_x2(int32_t const *a) { // CHECK-LABEL: @test_vld1q_s32_x3( // CHECK-A64: [[RETVAL:%.*]] = alloca %struct.int32x4x3_t, align 16 -// CHECK-A32: %struct.int32x4x3_t* noalias sret [[RETVAL:%.*]], +// CHECK-A32: %struct.int32x4x3_t* noalias sret align 8 [[RETVAL:%.*]], // CHECK: [[__RET:%.*]] = alloca %struct.int32x4x3_t, align {{16|8}} // CHECK: [[TMP0:%.*]] = bitcast %struct.int32x4x3_t* [[__RET]] to i8* // CHECK: [[TMP1:%.*]] = bitcast i32* %a to i8* @@ -1044,7 +1044,7 @@ int32x4x3_t test_vld1q_s32_x3(int32_t const *a) { // CHECK-LABEL: @test_vld1q_s32_x4( // CHECK-A64: [[RETVAL:%.*]] = alloca %struct.int32x4x4_t, align 16 -// CHECK-A32: %struct.int32x4x4_t* noalias sret [[RETVAL:%.*]], +// CHECK-A32: %struct.int32x4x4_t* noalias sret align 8 [[RETVAL:%.*]], // CHECK: [[__RET:%.*]] = alloca %struct.int32x4x4_t, align {{16|8}} // CHECK: [[TMP0:%.*]] = bitcast %struct.int32x4x4_t* [[__RET]] to i8* // CHECK: [[TMP1:%.*]] = bitcast i32* %a to i8* @@ -1064,7 +1064,7 @@ int32x4x4_t test_vld1q_s32_x4(int32_t const *a) { // CHECK-LABEL: @test_vld1q_s64_x2( // CHECK-A64: [[RETVAL:%.*]] = alloca %struct.int64x2x2_t, align 16 -// CHECK-A32: %struct.int64x2x2_t* noalias sret [[RETVAL:%.*]], +// CHECK-A32: %struct.int64x2x2_t* noalias sret align 8 [[RETVAL:%.*]], // CHECK: [[__RET:%.*]] = alloca %struct.int64x2x2_t, align {{16|8}} // CHECK: [[TMP0:%.*]] = bitcast %struct.int64x2x2_t* [[__RET]] to i8* // CHECK: [[TMP1:%.*]] = bitcast i64* %a to i8* @@ -1084,7 +1084,7 @@ int64x2x2_t test_vld1q_s64_x2(int64_t const *a) { // CHECK-LABEL: @test_vld1q_s64_x3( // CHECK-A64: [[RETVAL:%.*]] = alloca %struct.int64x2x3_t, align 16 -// CHECK-A32: %struct.int64x2x3_t* noalias sret [[RETVAL:%.*]], +// CHECK-A32: %struct.int64x2x3_t* noalias sret align 8 [[RETVAL:%.*]], // CHECK: [[__RET:%.*]] = alloca %struct.int64x2x3_t, align {{16|8}} // CHECK: [[TMP0:%.*]] = bitcast %struct.int64x2x3_t* [[__RET]] to i8* // CHECK: [[TMP1:%.*]] = bitcast i64* %a to i8* @@ -1104,7 +1104,7 @@ int64x2x3_t test_vld1q_s64_x3(int64_t const *a) { // CHECK-LABEL: @test_vld1q_s64_x4( // CHECK-A64: [[RETVAL:%.*]] = alloca %struct.int64x2x4_t, align 16 -// CHECK-A32: %struct.int64x2x4_t* noalias sret [[RETVAL:%.*]], +// CHECK-A32: %struct.int64x2x4_t* noalias sret align 8 [[RETVAL:%.*]], // CHECK: [[__RET:%.*]] = alloca %struct.int64x2x4_t, align {{16|8}} // CHECK: [[TMP0:%.*]] = bitcast %struct.int64x2x4_t* [[__RET]] to i8* // CHECK: [[TMP1:%.*]] = bitcast i64* %a to i8* @@ -1124,7 +1124,7 @@ int64x2x4_t test_vld1q_s64_x4(int64_t const *a) { // CHECK-LABEL: @test_vld1q_s8_x2( // CHECK-A64: [[RETVAL:%.*]] = alloca %struct.int8x16x2_t, align 16 -// CHECK-A32: %struct.int8x16x2_t* noalias sret [[RETVAL:%.*]], +// CHECK-A32: %struct.int8x16x2_t* noalias sret align 8 [[RETVAL:%.*]], // CHECK: [[__RET:%.*]] = alloca %struct.int8x16x2_t, align {{16|8}} // CHECK: [[TMP0:%.*]] = bitcast %struct.int8x16x2_t* [[__RET]] to i8* // CHECK: [[VLD1XN:%.*]] = call { <16 x i8>, <16 x i8> } @llvm.{{aarch64.neon.ld1x2|arm.neon.vld1x2}}.v16i8.p0i8(i8* %a) @@ -1142,7 +1142,7 @@ int8x16x2_t test_vld1q_s8_x2(int8_t const *a) { // CHECK-LABEL: @test_vld1q_s8_x3( // CHECK-A64: [[RETVAL:%.*]] = alloca %struct.int8x16x3_t, align 16 -// CHECK-A32: %struct.int8x16x3_t* noalias sret [[RETVAL:%.*]], +// CHECK-A32: %struct.int8x16x3_t* noalias sret align 8 [[RETVAL:%.*]], // CHECK: [[__RET:%.*]] = alloca %struct.int8x16x3_t, align {{16|8}} // CHECK: [[TMP0:%.*]] = bitcast %struct.int8x16x3_t* [[__RET]] to i8* // CHECK: [[VLD1XN:%.*]] = call { <16 x i8>, <16 x i8>, <16 x i8> } @llvm.{{aarch64.neon.ld1x3|arm.neon.vld1x3}}.v16i8.p0i8(i8* %a) @@ -1160,7 +1160,7 @@ int8x16x3_t test_vld1q_s8_x3(int8_t const *a) { // CHECK-LABEL: @test_vld1q_s8_x4( // CHECK-A64: [[RETVAL:%.*]] = alloca %struct.int8x16x4_t, align 16 -// CHECK-A32: %struct.int8x16x4_t* noalias sret [[RETVAL:%.*]], +// CHECK-A32: %struct.int8x16x4_t* noalias sret align 8 [[RETVAL:%.*]], // CHECK: [[__RET:%.*]] = alloca %struct.int8x16x4_t, align {{16|8}} // CHECK: [[TMP0:%.*]] = bitcast %struct.int8x16x4_t* [[__RET]] to i8* // CHECK: [[VLD1XN:%.*]] = call { <16 x i8>, <16 x i8>, <16 x i8>, <16 x i8> } @llvm.{{aarch64.neon.ld1x4|arm.neon.vld1x4}}.v16i8.p0i8(i8* %a) @@ -1178,7 +1178,7 @@ int8x16x4_t test_vld1q_s8_x4(int8_t const *a) { // CHECK-LABEL: @test_vld1q_u16_x2( // CHECK-A64: [[RETVAL:%.*]] = alloca %struct.uint16x8x2_t, align 16 -// CHECK-A32: %struct.uint16x8x2_t* noalias sret [[RETVAL:%.*]], +// CHECK-A32: %struct.uint16x8x2_t* noalias sret align 8 [[RETVAL:%.*]], // CHECK: [[__RET:%.*]] = alloca %struct.uint16x8x2_t, align {{16|8}} // CHECK: [[TMP0:%.*]] = bitcast %struct.uint16x8x2_t* [[__RET]] to i8* // CHECK: [[TMP1:%.*]] = bitcast i16* %a to i8* @@ -1198,7 +1198,7 @@ uint16x8x2_t test_vld1q_u16_x2(uint16_t const *a) { // CHECK-LABEL: @test_vld1q_u16_x3( // CHECK-A64: [[RETVAL:%.*]] = alloca %struct.uint16x8x3_t, align 16 -// CHECK-A32: %struct.uint16x8x3_t* noalias sret [[RETVAL:%.*]], +// CHECK-A32: %struct.uint16x8x3_t* noalias sret align 8 [[RETVAL:%.*]], // CHECK: [[__RET:%.*]] = alloca %struct.uint16x8x3_t, align {{16|8}} // CHECK: [[TMP0:%.*]] = bitcast %struct.uint16x8x3_t* [[__RET]] to i8* // CHECK: [[TMP1:%.*]] = bitcast i16* %a to i8* @@ -1218,7 +1218,7 @@ uint16x8x3_t test_vld1q_u16_x3(uint16_t const *a) { // CHECK-LABEL: @test_vld1q_u16_x4( // CHECK-A64: [[RETVAL:%.*]] = alloca %struct.uint16x8x4_t, align 16 -// CHECK-A32: %struct.uint16x8x4_t* noalias sret [[RETVAL:%.*]], +// CHECK-A32: %struct.uint16x8x4_t* noalias sret align 8 [[RETVAL:%.*]], // CHECK: [[__RET:%.*]] = alloca %struct.uint16x8x4_t, align {{16|8}} // CHECK: [[TMP0:%.*]] = bitcast %struct.uint16x8x4_t* [[__RET]] to i8* // CHECK: [[TMP1:%.*]] = bitcast i16* %a to i8* @@ -1238,7 +1238,7 @@ uint16x8x4_t test_vld1q_u16_x4(uint16_t const *a) { // CHECK-LABEL: @test_vld1q_u32_x2( // CHECK-A64: [[RETVAL:%.*]] = alloca %struct.uint32x4x2_t, align 16 -// CHECK-A32: %struct.uint32x4x2_t* noalias sret [[RETVAL:%.*]], +// CHECK-A32: %struct.uint32x4x2_t* noalias sret align 8 [[RETVAL:%.*]], // CHECK: [[__RET:%.*]] = alloca %struct.uint32x4x2_t, align {{16|8}} // CHECK: [[TMP0:%.*]] = bitcast %struct.uint32x4x2_t* [[__RET]] to i8* // CHECK: [[TMP1:%.*]] = bitcast i32* %a to i8* @@ -1258,7 +1258,7 @@ uint32x4x2_t test_vld1q_u32_x2(uint32_t const *a) { // CHECK-LABEL: @test_vld1q_u32_x3( // CHECK-A64: [[RETVAL:%.*]] = alloca %struct.uint32x4x3_t, align 16 -// CHECK-A32: %struct.uint32x4x3_t* noalias sret [[RETVAL:%.*]], +// CHECK-A32: %struct.uint32x4x3_t* noalias sret align 8 [[RETVAL:%.*]], // CHECK: [[__RET:%.*]] = alloca %struct.uint32x4x3_t, align {{16|8}} // CHECK: [[TMP0:%.*]] = bitcast %struct.uint32x4x3_t* [[__RET]] to i8* // CHECK: [[TMP1:%.*]] = bitcast i32* %a to i8* @@ -1278,7 +1278,7 @@ uint32x4x3_t test_vld1q_u32_x3(uint32_t const *a) { // CHECK-LABEL: @test_vld1q_u32_x4( // CHECK-A64: [[RETVAL:%.*]] = alloca %struct.uint32x4x4_t, align 16 -// CHECK-A32: %struct.uint32x4x4_t* noalias sret [[RETVAL:%.*]], +// CHECK-A32: %struct.uint32x4x4_t* noalias sret align 8 [[RETVAL:%.*]], // CHECK: [[__RET:%.*]] = alloca %struct.uint32x4x4_t, align {{16|8}} // CHECK: [[TMP0:%.*]] = bitcast %struct.uint32x4x4_t* [[__RET]] to i8* // CHECK: [[TMP1:%.*]] = bitcast i32* %a to i8* @@ -1298,7 +1298,7 @@ uint32x4x4_t test_vld1q_u32_x4(uint32_t const *a) { // CHECK-LABEL: @test_vld1q_u64_x2( // CHECK-A64: [[RETVAL:%.*]] = alloca %struct.uint64x2x2_t, align 16 -// CHECK-A32: %struct.uint64x2x2_t* noalias sret [[RETVAL:%.*]], +// CHECK-A32: %struct.uint64x2x2_t* noalias sret align 8 [[RETVAL:%.*]], // CHECK: [[__RET:%.*]] = alloca %struct.uint64x2x2_t, align {{16|8}} // CHECK: [[TMP0:%.*]] = bitcast %struct.uint64x2x2_t* [[__RET]] to i8* // CHECK: [[TMP1:%.*]] = bitcast i64* %a to i8* @@ -1318,7 +1318,7 @@ uint64x2x2_t test_vld1q_u64_x2(uint64_t const *a) { // CHECK-LABEL: @test_vld1q_u64_x3( // CHECK-A64: [[RETVAL:%.*]] = alloca %struct.uint64x2x3_t, align 16 -// CHECK-A32: %struct.uint64x2x3_t* noalias sret [[RETVAL:%.*]], +// CHECK-A32: %struct.uint64x2x3_t* noalias sret align 8 [[RETVAL:%.*]], // CHECK: [[__RET:%.*]] = alloca %struct.uint64x2x3_t, align {{16|8}} // CHECK: [[TMP0:%.*]] = bitcast %struct.uint64x2x3_t* [[__RET]] to i8* // CHECK: [[TMP1:%.*]] = bitcast i64* %a to i8* @@ -1338,7 +1338,7 @@ uint64x2x3_t test_vld1q_u64_x3(uint64_t const *a) { // CHECK-LABEL: @test_vld1q_u64_x4( // CHECK-A64: [[RETVAL:%.*]] = alloca %struct.uint64x2x4_t, align 16 -// CHECK-A32: %struct.uint64x2x4_t* noalias sret [[RETVAL:%.*]], +// CHECK-A32: %struct.uint64x2x4_t* noalias sret align 8 [[RETVAL:%.*]], // CHECK: [[__RET:%.*]] = alloca %struct.uint64x2x4_t, align {{16|8}} // CHECK: [[TMP0:%.*]] = bitcast %struct.uint64x2x4_t* [[__RET]] to i8* // CHECK: [[TMP1:%.*]] = bitcast i64* %a to i8* @@ -1358,7 +1358,7 @@ uint64x2x4_t test_vld1q_u64_x4(uint64_t const *a) { // CHECK-LABEL: @test_vld1q_u8_x2( // CHECK-A64: [[RETVAL:%.*]] = alloca %struct.uint8x16x2_t, align 16 -// CHECK-A32: %struct.uint8x16x2_t* noalias sret [[RETVAL:%.*]], +// CHECK-A32: %struct.uint8x16x2_t* noalias sret align 8 [[RETVAL:%.*]], // CHECK: [[__RET:%.*]] = alloca %struct.uint8x16x2_t, align {{16|8}} // CHECK: [[TMP0:%.*]] = bitcast %struct.uint8x16x2_t* [[__RET]] to i8* // CHECK: [[VLD1XN:%.*]] = call { <16 x i8>, <16 x i8> } @llvm.{{aarch64.neon.ld1x2|arm.neon.vld1x2}}.v16i8.p0i8(i8* %a) @@ -1376,7 +1376,7 @@ uint8x16x2_t test_vld1q_u8_x2(uint8_t const *a) { // CHECK-LABEL: @test_vld1q_u8_x3( // CHECK-A64: [[RETVAL:%.*]] = alloca %struct.uint8x16x3_t, align 16 -// CHECK-A32: %struct.uint8x16x3_t* noalias sret [[RETVAL:%.*]], +// CHECK-A32: %struct.uint8x16x3_t* noalias sret align 8 [[RETVAL:%.*]], // CHECK: [[__RET:%.*]] = alloca %struct.uint8x16x3_t, align {{16|8}} // CHECK: [[TMP0:%.*]] = bitcast %struct.uint8x16x3_t* [[__RET]] to i8* // CHECK: [[VLD1XN:%.*]] = call { <16 x i8>, <16 x i8>, <16 x i8> } @llvm.{{aarch64.neon.ld1x3|arm.neon.vld1x3}}.v16i8.p0i8(i8* %a) @@ -1394,7 +1394,7 @@ uint8x16x3_t test_vld1q_u8_x3(uint8_t const *a) { // CHECK-LABEL: @test_vld1q_u8_x4( // CHECK-A64: [[RETVAL:%.*]] = alloca %struct.uint8x16x4_t, align 16 -// CHECK-A32: %struct.uint8x16x4_t* noalias sret [[RETVAL:%.*]], +// CHECK-A32: %struct.uint8x16x4_t* noalias sret align 8 [[RETVAL:%.*]], // CHECK: [[__RET:%.*]] = alloca %struct.uint8x16x4_t, align {{16|8}} // CHECK: [[TMP0:%.*]] = bitcast %struct.uint8x16x4_t* [[__RET]] to i8* // CHECK: [[VLD1XN:%.*]] = call { <16 x i8>, <16 x i8>, <16 x i8>, <16 x i8> } @llvm.{{aarch64.neon.ld1x4|arm.neon.vld1x4}}.v16i8.p0i8(i8* %a) diff --git a/clang/test/CodeGen/arm-varargs.c b/clang/test/CodeGen/arm-varargs.c index 1f5c07ef57dad..dff62568b6cae 100644 --- a/clang/test/CodeGen/arm-varargs.c +++ b/clang/test/CodeGen/arm-varargs.c @@ -24,7 +24,7 @@ struct bigstruct { }; struct bigstruct simple_struct(void) { -// CHECK-LABEL: define void @simple_struct(%struct.bigstruct* noalias sret %agg.result) +// CHECK-LABEL: define void @simple_struct(%struct.bigstruct* noalias sret align 4 %agg.result) return va_arg(the_list, struct bigstruct); // CHECK: [[CUR:%[a-z0-9._]+]] = load i8*, i8** getelementptr inbounds (%struct.__va_list, %struct.__va_list* @the_list, i32 0, i32 0), align 4 // CHECK: [[NEXT:%[a-z0-9._]+]] = getelementptr inbounds i8, i8* [[CUR]], i32 40 @@ -42,7 +42,7 @@ struct aligned_bigstruct { }; struct aligned_bigstruct simple_aligned_struct(void) { -// CHECK-LABEL: define void @simple_aligned_struct(%struct.aligned_bigstruct* noalias sret %agg.result) +// CHECK-LABEL: define void @simple_aligned_struct(%struct.aligned_bigstruct* noalias sret align 8 %agg.result) return va_arg(the_list, struct aligned_bigstruct); // CHECK: [[CUR:%[a-z0-9._]+]] = load i8*, i8** getelementptr inbounds (%struct.__va_list, %struct.__va_list* @the_list, i32 0, i32 0), align 4 // CHECK: [[CUR_INT:%[a-z0-9._]+]] = ptrtoint i8* [[CUR]] to i32 @@ -78,7 +78,7 @@ struct hfa { }; struct hfa simple_hfa(void) { -// CHECK-LABEL: define void @simple_hfa(%struct.hfa* noalias sret %agg.result) +// CHECK-LABEL: define void @simple_hfa(%struct.hfa* noalias sret align 4 %agg.result) return va_arg(the_list, struct hfa); // CHECK: [[CUR:%[a-z0-9._]+]] = load i8*, i8** getelementptr inbounds (%struct.__va_list, %struct.__va_list* @the_list, i32 0, i32 0), align 4 // CHECK: [[NEXT:%[a-z0-9._]+]] = getelementptr inbounds i8, i8* [[CUR]], i32 8 @@ -185,7 +185,7 @@ typedef struct __attribute__((aligned(16))) { int val; } overaligned_int_struct; overaligned_int_struct overaligned_int_struct_test() { -// CHECK-LABEL: define void @overaligned_int_struct_test(%struct.overaligned_int_struct* noalias sret %agg.result) +// CHECK-LABEL: define void @overaligned_int_struct_test(%struct.overaligned_int_struct* noalias sret align 16 %agg.result) return va_arg(the_list, overaligned_int_struct); // CHECK: [[CUR:%[a-z0-9._]+]] = load i8*, i8** getelementptr inbounds (%struct.__va_list, %struct.__va_list* @the_list, i32 0, i32 0), align 4 // CHECK: [[NEXT:%[a-z0-9._]+]] = getelementptr inbounds i8, i8* [[CUR]], i32 16 @@ -201,7 +201,7 @@ typedef struct __attribute__((packed,aligned(2))) { long long val; } underaligned_long_long_struct; underaligned_long_long_struct underaligned_long_long_struct_test() { -// CHECK-LABEL: define void @underaligned_long_long_struct_test(%struct.underaligned_long_long_struct* noalias sret %agg.result) +// CHECK-LABEL: define void @underaligned_long_long_struct_test(%struct.underaligned_long_long_struct* noalias sret align 2 %agg.result) return va_arg(the_list, underaligned_long_long_struct); // CHECK: [[CUR:%[a-z0-9._]+]] = load i8*, i8** getelementptr inbounds (%struct.__va_list, %struct.__va_list* @the_list, i32 0, i32 0), align 4 // CHECK: [[NEXT:%[a-z0-9._]+]] = getelementptr inbounds i8, i8* [[CUR]], i32 8 @@ -217,7 +217,7 @@ typedef struct __attribute__((aligned(16))) { long long val; } overaligned_long_long_struct; overaligned_long_long_struct overaligned_long_long_struct_test() { -// CHECK-LABEL: define void @overaligned_long_long_struct_test(%struct.overaligned_long_long_struct* noalias sret %agg.result) +// CHECK-LABEL: define void @overaligned_long_long_struct_test(%struct.overaligned_long_long_struct* noalias sret align 16 %agg.result) return va_arg(the_list, overaligned_long_long_struct); // CHECK: [[CUR:%[a-z0-9._]+]] = load i8*, i8** getelementptr inbounds (%struct.__va_list, %struct.__va_list* @the_list, i32 0, i32 0), align 4 // CHECK: [[CUR_INT:%[a-z0-9._]+]] = ptrtoint i8* [[CUR]] to i32 @@ -259,7 +259,7 @@ typedef struct { int val __attribute__((aligned(16))); } overaligned_int_struct_member; overaligned_int_struct_member overaligned_int_struct_member_test() { -// CHECK-LABEL: define void @overaligned_int_struct_member_test(%struct.overaligned_int_struct_member* noalias sret %agg.result) +// CHECK-LABEL: define void @overaligned_int_struct_member_test(%struct.overaligned_int_struct_member* noalias sret align 16 %agg.result) return va_arg(the_list, overaligned_int_struct_member); // CHECK: [[CUR:%[a-z0-9._]+]] = load i8*, i8** getelementptr inbounds (%struct.__va_list, %struct.__va_list* @the_list, i32 0, i32 0), align 4 // CHECK: [[CUR_INT:%[a-z0-9._]+]] = ptrtoint i8* [[CUR]] to i32 @@ -279,7 +279,7 @@ typedef struct { long long val __attribute__((packed,aligned(2))); } underaligned_long_long_struct_member; underaligned_long_long_struct_member underaligned_long_long_struct_member_test() { -// CHECK-LABEL: define void @underaligned_long_long_struct_member_test(%struct.underaligned_long_long_struct_member* noalias sret %agg.result) +// CHECK-LABEL: define void @underaligned_long_long_struct_member_test(%struct.underaligned_long_long_struct_member* noalias sret align 2 %agg.result) return va_arg(the_list, underaligned_long_long_struct_member); // CHECK: [[CUR:%[a-z0-9._]+]] = load i8*, i8** getelementptr inbounds (%struct.__va_list, %struct.__va_list* @the_list, i32 0, i32 0), align 4 // CHECK: [[NEXT:%[a-z0-9._]+]] = getelementptr inbounds i8, i8* [[CUR]], i32 8 @@ -295,7 +295,7 @@ typedef struct { long long val __attribute__((aligned(16))); } overaligned_long_long_struct_member; overaligned_long_long_struct_member overaligned_long_long_struct_member_test() { -// CHECK-LABEL: define void @overaligned_long_long_struct_member_test(%struct.overaligned_long_long_struct_member* noalias sret %agg.result) +// CHECK-LABEL: define void @overaligned_long_long_struct_member_test(%struct.overaligned_long_long_struct_member* noalias sret align 16 %agg.result) return va_arg(the_list, overaligned_long_long_struct_member); // CHECK: [[CUR:%[a-z0-9._]+]] = load i8*, i8** getelementptr inbounds (%struct.__va_list, %struct.__va_list* @the_list, i32 0, i32 0), align 4 // CHECK: [[CUR_INT:%[a-z0-9._]+]] = ptrtoint i8* [[CUR]] to i32 diff --git a/clang/test/CodeGen/arm-vector-arguments.c b/clang/test/CodeGen/arm-vector-arguments.c index 9bdddb72696e3..aa8e65ba366f4 100644 --- a/clang/test/CodeGen/arm-vector-arguments.c +++ b/clang/test/CodeGen/arm-vector-arguments.c @@ -9,7 +9,7 @@ #include -// CHECK: define void @f0(%struct.int8x16x2_t* noalias sret %agg.result, <16 x i8> %{{.*}}, <16 x i8> %{{.*}}) +// CHECK: define void @f0(%struct.int8x16x2_t* noalias sret align 16 %agg.result, <16 x i8> %{{.*}}, <16 x i8> %{{.*}}) int8x16x2_t f0(int8x16_t a0, int8x16_t a1) { return vzipq_s8(a0, a1); } @@ -25,7 +25,7 @@ typedef float T_float32x16 __attribute__ ((__vector_size__ (64))); T_float32x2 f1_0(T_float32x2 a0) { return a0; } // CHECK: define <4 x float> @f1_1(<4 x float> %{{.*}}) T_float32x4 f1_1(T_float32x4 a0) { return a0; } -// CHECK: define void @f1_2(<8 x float>* noalias sret %{{.*}}, <8 x float> %{{.*}}) +// CHECK: define void @f1_2(<8 x float>* noalias sret align 32 %{{.*}}, <8 x float> %{{.*}}) T_float32x8 f1_2(T_float32x8 a0) { return a0; } -// CHECK: define void @f1_3(<16 x float>* noalias sret %{{.*}}, <16 x float> %{{.*}}) +// CHECK: define void @f1_3(<16 x float>* noalias sret align 64 %{{.*}}, <16 x float> %{{.*}}) T_float32x16 f1_3(T_float32x16 a0) { return a0; } diff --git a/clang/test/CodeGen/arm-vfp16-arguments.c b/clang/test/CodeGen/arm-vfp16-arguments.c index 32f1bb7b2a775..42d990d970862 100644 --- a/clang/test/CodeGen/arm-vfp16-arguments.c +++ b/clang/test/CodeGen/arm-vfp16-arguments.c @@ -71,6 +71,6 @@ void test_hfa(hfa_t a) {} hfa_t ghfa; hfa_t test_ret_hfa(void) { return ghfa; } -// CHECK-SOFT: define void @test_ret_hfa(%struct.hfa_t* noalias nocapture sret %agg.result) +// CHECK-SOFT: define void @test_ret_hfa(%struct.hfa_t* noalias nocapture sret align 8 %agg.result) // CHECK-HARD: define arm_aapcs_vfpcc [2 x <2 x i32>] @test_ret_hfa() // CHECK-FULL: define arm_aapcs_vfpcc %struct.hfa_t @test_ret_hfa() diff --git a/clang/test/CodeGen/arm-vfp16-arguments2.cpp b/clang/test/CodeGen/arm-vfp16-arguments2.cpp index e436a5ecd6abd..ccc81a3bfdd92 100644 --- a/clang/test/CodeGen/arm-vfp16-arguments2.cpp +++ b/clang/test/CodeGen/arm-vfp16-arguments2.cpp @@ -37,27 +37,27 @@ struct S5 : B1 { B1 M[1]; }; -// CHECK-SOFT: define void @_Z2f12S1(%struct.S1* noalias nocapture sret %agg.result, [2 x i64] %s1.coerce) +// CHECK-SOFT: define void @_Z2f12S1(%struct.S1* noalias nocapture sret align 8 %agg.result, [2 x i64] %s1.coerce) // CHECK-HARD: define arm_aapcs_vfpcc [2 x <2 x i32>] @_Z2f12S1([2 x <2 x i32>] returned %s1.coerce) // CHECK-FULL: define arm_aapcs_vfpcc %struct.S1 @_Z2f12S1(%struct.S1 returned %s1.coerce) struct S1 f1(struct S1 s1) { return s1; } -// CHECK-SOFT: define void @_Z2f22S2(%struct.S2* noalias nocapture sret %agg.result, [4 x i32] %s2.coerce) +// CHECK-SOFT: define void @_Z2f22S2(%struct.S2* noalias nocapture sret align 8 %agg.result, [4 x i32] %s2.coerce) // CHECK-HARD: define arm_aapcs_vfpcc [2 x <2 x i32>] @_Z2f22S2([2 x <2 x i32>] returned %s2.coerce) // CHECK-FULL: define arm_aapcs_vfpcc %struct.S2 @_Z2f22S2(%struct.S2 returned %s2.coerce) struct S2 f2(struct S2 s2) { return s2; } -// CHECK-SOFT: define void @_Z2f32S3(%struct.S3* noalias nocapture sret %agg.result, [2 x i64] %s3.coerce) +// CHECK-SOFT: define void @_Z2f32S3(%struct.S3* noalias nocapture sret align 8 %agg.result, [2 x i64] %s3.coerce) // CHECK-HARD: define arm_aapcs_vfpcc [2 x <2 x i32>] @_Z2f32S3([2 x <2 x i32>] returned %s3.coerce) // CHECK-FULL: define arm_aapcs_vfpcc %struct.S3 @_Z2f32S3(%struct.S3 returned %s3.coerce) struct S3 f3(struct S3 s3) { return s3; } -// CHECK-SOFT: define void @_Z2f42S4(%struct.S4* noalias nocapture sret %agg.result, [2 x i64] %s4.coerce) +// CHECK-SOFT: define void @_Z2f42S4(%struct.S4* noalias nocapture sret align 8 %agg.result, [2 x i64] %s4.coerce) // CHECK-HARD: define arm_aapcs_vfpcc [2 x <2 x i32>] @_Z2f42S4([2 x <2 x i32>] returned %s4.coerce) // CHECK-FULL: define arm_aapcs_vfpcc %struct.S4 @_Z2f42S4(%struct.S4 returned %s4.coerce) struct S4 f4(struct S4 s4) { return s4; } -// CHECK-SOFT: define void @_Z2f52S5(%struct.S5* noalias nocapture sret %agg.result, [2 x i64] %s5.coerce) +// CHECK-SOFT: define void @_Z2f52S5(%struct.S5* noalias nocapture sret align 8 %agg.result, [2 x i64] %s5.coerce) // CHECK-HARD: define arm_aapcs_vfpcc %struct.S5 @_Z2f52S5(%struct.S5 returned %s5.coerce) // CHECK-FULL: define arm_aapcs_vfpcc %struct.S5 @_Z2f52S5(%struct.S5 returned %s5.coerce) struct S5 f5(struct S5 s5) { return s5; } diff --git a/clang/test/CodeGen/arm64-arguments.c b/clang/test/CodeGen/arm64-arguments.c index 5c8474cae7be8..97332deb7c807 100644 --- a/clang/test/CodeGen/arm64-arguments.c +++ b/clang/test/CodeGen/arm64-arguments.c @@ -181,9 +181,9 @@ T_float32x2 f1_0(T_float32x2 a0) { return a0; } // CHECK: define <4 x float> @f1_1(<4 x float> %{{.*}}) T_float32x4 f1_1(T_float32x4 a0) { return a0; } // Vector with length bigger than 16-byte is illegal and is passed indirectly. -// CHECK: define void @f1_2(<8 x float>* noalias sret %{{.*}}, <8 x float>* %0) +// CHECK: define void @f1_2(<8 x float>* noalias sret align 16 %{{.*}}, <8 x float>* %0) T_float32x8 f1_2(T_float32x8 a0) { return a0; } -// CHECK: define void @f1_3(<16 x float>* noalias sret %{{.*}}, <16 x float>* %0) +// CHECK: define void @f1_3(<16 x float>* noalias sret align 16 %{{.*}}, <16 x float>* %0) T_float32x16 f1_3(T_float32x16 a0) { return a0; } // Testing alignment with aggregates: HFA, aggregates with size <= 16 bytes and diff --git a/clang/test/CodeGen/arm64-microsoft-arguments.cpp b/clang/test/CodeGen/arm64-microsoft-arguments.cpp index bca7cc94b3937..f5bcda756b061 100644 --- a/clang/test/CodeGen/arm64-microsoft-arguments.cpp +++ b/clang/test/CodeGen/arm64-microsoft-arguments.cpp @@ -28,8 +28,8 @@ S2 f2() { } // Pass and return for type size > 16 bytes. -// CHECK: define {{.*}} void @{{.*}}f3{{.*}}(%struct.S3* noalias sret %agg.result) -// CHECK: call void {{.*}}func3{{.*}}(%struct.S3* sret %agg.result, %struct.S3* %agg.tmp) +// CHECK: define {{.*}} void @{{.*}}f3{{.*}}(%struct.S3* noalias sret align 4 %agg.result) +// CHECK: call void {{.*}}func3{{.*}}(%struct.S3* sret align 4 %agg.result, %struct.S3* %agg.tmp) struct S3 { int a[5]; }; @@ -42,8 +42,8 @@ S3 f3() { // Pass and return aggregate (of size < 16 bytes) with non-trivial destructor. // Passed directly but returned indirectly. -// CHECK: define {{.*}} void {{.*}}f4{{.*}}(%struct.S4* inreg noalias sret %agg.result) -// CHECK: call void {{.*}}func4{{.*}}(%struct.S4* inreg sret %agg.result, [2 x i64] %5) +// CHECK: define {{.*}} void {{.*}}f4{{.*}}(%struct.S4* inreg noalias sret align 4 %agg.result) +// CHECK: call void {{.*}}func4{{.*}}(%struct.S4* inreg sret align 4 %agg.result, [2 x i64] %5) struct S4 { int a[3]; ~S4(); @@ -56,8 +56,8 @@ S4 f4() { } // Pass and return from instance method called from instance method. -// CHECK: define {{.*}} void @{{.*}}bar@Q1{{.*}}(%class.Q1* %this, %class.P1* inreg noalias sret %agg.result) -// CHECK: call void {{.*}}foo@P1{{.*}}(%class.P1* %ref.tmp, %class.P1* inreg sret %agg.result, i8 %1) +// CHECK: define {{.*}} void @{{.*}}bar@Q1{{.*}}(%class.Q1* %this, %class.P1* inreg noalias sret align 1 %agg.result) +// CHECK: call void {{.*}}foo@P1{{.*}}(%class.P1* %ref.tmp, %class.P1* inreg sret align 1 %agg.result, i8 %1) class P1 { public: @@ -76,7 +76,7 @@ P1 Q1::bar() { // Pass and return from instance method called from free function. // CHECK: define {{.*}} void {{.*}}bar{{.*}}() -// CHECK: call void {{.*}}foo@P2{{.*}}(%class.P2* %ref.tmp, %class.P2* inreg sret %retval, i8 %0) +// CHECK: call void {{.*}}foo@P2{{.*}}(%class.P2* %ref.tmp, %class.P2* inreg sret align 1 %retval, i8 %0) class P2 { public: P2 foo(P2 x); @@ -89,8 +89,8 @@ P2 bar() { // Pass and return an object with a user-provided constructor (passed directly, // returned indirectly) -// CHECK: define {{.*}} void @{{.*}}f5{{.*}}(%struct.S5* inreg noalias sret %agg.result) -// CHECK: call void {{.*}}func5{{.*}}(%struct.S5* inreg sret %agg.result, i64 {{.*}}) +// CHECK: define {{.*}} void @{{.*}}f5{{.*}}(%struct.S5* inreg noalias sret align 4 %agg.result) +// CHECK: call void {{.*}}func5{{.*}}(%struct.S5* inreg sret align 4 %agg.result, i64 {{.*}}) struct S5 { S5(); int x; @@ -146,8 +146,8 @@ struct S8 { int y; }; -// CHECK: define {{.*}} void {{.*}}?f8{{.*}}(%struct.S8* inreg noalias sret {{.*}}) -// CHECK: call void {{.*}}func8{{.*}}(%struct.S8* inreg sret {{.*}}, i64 {{.*}}) +// CHECK: define {{.*}} void {{.*}}?f8{{.*}}(%struct.S8* inreg noalias sret align 4 {{.*}}) +// CHECK: call void {{.*}}func8{{.*}}(%struct.S8* inreg sret align 4 {{.*}}, i64 {{.*}}) S8 func8(S8 x); S8 f8() { S8 x; @@ -157,8 +157,8 @@ S8 f8() { // Pass and return an object with a non-trivial copy-assignment operator and // a trivial copy constructor (passed directly, returned indirectly) -// CHECK: define {{.*}} void @"?f9@@YA?AUS9@@XZ"(%struct.S9* inreg noalias sret {{.*}}) -// CHECK: call void {{.*}}func9{{.*}}(%struct.S9* inreg sret {{.*}}, i64 {{.*}}) +// CHECK: define {{.*}} void @"?f9@@YA?AUS9@@XZ"(%struct.S9* inreg noalias sret align 4 {{.*}}) +// CHECK: call void {{.*}}func9{{.*}}(%struct.S9* inreg sret align 4 {{.*}}, i64 {{.*}}) struct S9 { S9& operator=(const S9&); int x; @@ -174,8 +174,8 @@ S9 f9() { // Pass and return an object with a base class (passed directly, returned // indirectly). -// CHECK: define dso_local void {{.*}}f10{{.*}}(%struct.S10* inreg noalias sret {{.*}}) -// CHECK: call void {{.*}}func10{{.*}}(%struct.S10* inreg sret {{.*}}, [2 x i64] {{.*}}) +// CHECK: define dso_local void {{.*}}f10{{.*}}(%struct.S10* inreg noalias sret align 4 {{.*}}) +// CHECK: call void {{.*}}func10{{.*}}(%struct.S10* inreg sret align 4 {{.*}}, [2 x i64] {{.*}}) struct S10 : public S1 { int x; }; @@ -189,8 +189,8 @@ S10 f10() { // Pass and return a non aggregate object exceeding > 128 bits (passed // indirectly, returned indirectly) -// CHECK: define dso_local void {{.*}}f11{{.*}}(%struct.S11* inreg noalias sret {{.*}}) -// CHECK: call void {{.*}}func11{{.*}}(%struct.S11* inreg sret {{.*}}, %struct.S11* {{.*}}) +// CHECK: define dso_local void {{.*}}f11{{.*}}(%struct.S11* inreg noalias sret align 8 {{.*}}) +// CHECK: call void {{.*}}func11{{.*}}(%struct.S11* inreg sret align 8 {{.*}}, %struct.S11* {{.*}}) struct S11 { virtual void f(); int a[5]; diff --git a/clang/test/CodeGen/arm64_32.c b/clang/test/CodeGen/arm64_32.c index 245dfefc99e3b..1fb121cfcfb14 100644 --- a/clang/test/CodeGen/arm64_32.c +++ b/clang/test/CodeGen/arm64_32.c @@ -27,4 +27,4 @@ long double LongDoubleVar = 0.0; typedef float __attribute__((ext_vector_type(16))) v16f32; v16f32 func(v16f32 in) { return in; } -// CHECK: define void @func(<16 x float>* noalias sret {{%.*}}, <16 x float> {{%.*}}) +// CHECK: define void @func(<16 x float>* noalias sret align 16 {{%.*}}, <16 x float> {{%.*}}) diff --git a/clang/test/CodeGen/arm_neon_intrinsics.c b/clang/test/CodeGen/arm_neon_intrinsics.c index 9f1a64554155c..17aa39fb4ae19 100644 --- a/clang/test/CodeGen/arm_neon_intrinsics.c +++ b/clang/test/CodeGen/arm_neon_intrinsics.c @@ -20079,7 +20079,7 @@ poly8x8_t test_vtbx4_p8(poly8x8_t a, poly8x8x4_t b, uint8x8_t c) { return vtbx4_p8(a, b, c); } -// CHECK: @test_vtrn_s8({{.*}} sret [[AGG_RESULT:%[0-9a-zA-Z.]+]], +// CHECK: @test_vtrn_s8({{.*}} sret align 8 [[AGG_RESULT:%[0-9a-zA-Z.]+]], // CHECK: [[TMP0:%.*]] = bitcast %struct.int8x8x2_t* [[AGG_RESULT]] to i8* // CHECK: [[TMP1:%.*]] = bitcast i8* [[TMP0]] to <8 x i8>* // CHECK: [[VTRN_I:%.*]] = shufflevector <8 x i8> %a, <8 x i8> %b, <8 x i32> @@ -20092,7 +20092,7 @@ int8x8x2_t test_vtrn_s8(int8x8_t a, int8x8_t b) { return vtrn_s8(a, b); } -// CHECK: @test_vtrn_s16({{.*}} sret [[AGG_RESULT:%[0-9a-zA-Z.]+]], +// CHECK: @test_vtrn_s16({{.*}} sret align 8 [[AGG_RESULT:%[0-9a-zA-Z.]+]], // CHECK: [[TMP0:%.*]] = bitcast %struct.int16x4x2_t* [[AGG_RESULT]] to i8* // CHECK: [[TMP1:%.*]] = bitcast <4 x i16> %a to <8 x i8> // CHECK: [[TMP2:%.*]] = bitcast <4 x i16> %b to <8 x i8> @@ -20107,7 +20107,7 @@ int16x4x2_t test_vtrn_s16(int16x4_t a, int16x4_t b) { return vtrn_s16(a, b); } -// CHECK: @test_vtrn_s32({{.*}} sret [[AGG_RESULT:%[0-9a-zA-Z.]+]], +// CHECK: @test_vtrn_s32({{.*}} sret align 8 [[AGG_RESULT:%[0-9a-zA-Z.]+]], // CHECK: [[TMP0:%.*]] = bitcast %struct.int32x2x2_t* [[AGG_RESULT]] to i8* // CHECK: [[TMP1:%.*]] = bitcast <2 x i32> %a to <8 x i8> // CHECK: [[TMP2:%.*]] = bitcast <2 x i32> %b to <8 x i8> @@ -20122,7 +20122,7 @@ int32x2x2_t test_vtrn_s32(int32x2_t a, int32x2_t b) { return vtrn_s32(a, b); } -// CHECK: @test_vtrn_u8({{.*}} sret [[AGG_RESULT:%[0-9a-zA-Z.]+]], +// CHECK: @test_vtrn_u8({{.*}} sret align 8 [[AGG_RESULT:%[0-9a-zA-Z.]+]], // CHECK: [[TMP0:%.*]] = bitcast %struct.uint8x8x2_t* [[AGG_RESULT]] to i8* // CHECK: [[TMP1:%.*]] = bitcast i8* [[TMP0]] to <8 x i8>* // CHECK: [[VTRN_I:%.*]] = shufflevector <8 x i8> %a, <8 x i8> %b, <8 x i32> @@ -20135,7 +20135,7 @@ uint8x8x2_t test_vtrn_u8(uint8x8_t a, uint8x8_t b) { return vtrn_u8(a, b); } -// CHECK: @test_vtrn_u16({{.*}} sret [[AGG_RESULT:%[0-9a-zA-Z.]+]], +// CHECK: @test_vtrn_u16({{.*}} sret align 8 [[AGG_RESULT:%[0-9a-zA-Z.]+]], // CHECK: [[TMP0:%.*]] = bitcast %struct.uint16x4x2_t* [[AGG_RESULT]] to i8* // CHECK: [[TMP1:%.*]] = bitcast <4 x i16> %a to <8 x i8> // CHECK: [[TMP2:%.*]] = bitcast <4 x i16> %b to <8 x i8> @@ -20150,7 +20150,7 @@ uint16x4x2_t test_vtrn_u16(uint16x4_t a, uint16x4_t b) { return vtrn_u16(a, b); } -// CHECK: @test_vtrn_u32({{.*}} sret [[AGG_RESULT:%[0-9a-zA-Z.]+]], +// CHECK: @test_vtrn_u32({{.*}} sret align 8 [[AGG_RESULT:%[0-9a-zA-Z.]+]], // CHECK: [[TMP0:%.*]] = bitcast %struct.uint32x2x2_t* [[AGG_RESULT]] to i8* // CHECK: [[TMP1:%.*]] = bitcast <2 x i32> %a to <8 x i8> // CHECK: [[TMP2:%.*]] = bitcast <2 x i32> %b to <8 x i8> @@ -20165,7 +20165,7 @@ uint32x2x2_t test_vtrn_u32(uint32x2_t a, uint32x2_t b) { return vtrn_u32(a, b); } -// CHECK: @test_vtrn_f32({{.*}} sret [[AGG_RESULT:%[0-9a-zA-Z.]+]], +// CHECK: @test_vtrn_f32({{.*}} sret align 8 [[AGG_RESULT:%[0-9a-zA-Z.]+]], // CHECK: [[TMP0:%.*]] = bitcast %struct.float32x2x2_t* [[AGG_RESULT]] to i8* // CHECK: [[TMP1:%.*]] = bitcast <2 x float> %a to <8 x i8> // CHECK: [[TMP2:%.*]] = bitcast <2 x float> %b to <8 x i8> @@ -20180,7 +20180,7 @@ float32x2x2_t test_vtrn_f32(float32x2_t a, float32x2_t b) { return vtrn_f32(a, b); } -// CHECK: @test_vtrn_p8({{.*}} sret [[AGG_RESULT:%[0-9a-zA-Z.]+]], +// CHECK: @test_vtrn_p8({{.*}} sret align 8 [[AGG_RESULT:%[0-9a-zA-Z.]+]], // CHECK: [[TMP0:%.*]] = bitcast %struct.poly8x8x2_t* [[AGG_RESULT]] to i8* // CHECK: [[TMP1:%.*]] = bitcast i8* [[TMP0]] to <8 x i8>* // CHECK: [[VTRN_I:%.*]] = shufflevector <8 x i8> %a, <8 x i8> %b, <8 x i32> @@ -20193,7 +20193,7 @@ poly8x8x2_t test_vtrn_p8(poly8x8_t a, poly8x8_t b) { return vtrn_p8(a, b); } -// CHECK: @test_vtrn_p16({{.*}} sret [[AGG_RESULT:%[0-9a-zA-Z.]+]], +// CHECK: @test_vtrn_p16({{.*}} sret align 8 [[AGG_RESULT:%[0-9a-zA-Z.]+]], // CHECK: [[TMP0:%.*]] = bitcast %struct.poly16x4x2_t* [[AGG_RESULT]] to i8* // CHECK: [[TMP1:%.*]] = bitcast <4 x i16> %a to <8 x i8> // CHECK: [[TMP2:%.*]] = bitcast <4 x i16> %b to <8 x i8> @@ -20208,7 +20208,7 @@ poly16x4x2_t test_vtrn_p16(poly16x4_t a, poly16x4_t b) { return vtrn_p16(a, b); } -// CHECK: @test_vtrnq_s8({{.*}} sret [[AGG_RESULT:%[0-9a-zA-Z.]+]], +// CHECK: @test_vtrnq_s8({{.*}} sret align 16 [[AGG_RESULT:%[0-9a-zA-Z.]+]], // CHECK: [[TMP0:%.*]] = bitcast %struct.int8x16x2_t* [[AGG_RESULT]] to i8* // CHECK: [[TMP1:%.*]] = bitcast i8* [[TMP0]] to <16 x i8>* // CHECK: [[VTRN_I:%.*]] = shufflevector <16 x i8> %a, <16 x i8> %b, <16 x i32> @@ -20221,7 +20221,7 @@ int8x16x2_t test_vtrnq_s8(int8x16_t a, int8x16_t b) { return vtrnq_s8(a, b); } -// CHECK: @test_vtrnq_s16({{.*}} sret [[AGG_RESULT:%[0-9a-zA-Z.]+]], +// CHECK: @test_vtrnq_s16({{.*}} sret align 16 [[AGG_RESULT:%[0-9a-zA-Z.]+]], // CHECK: [[TMP0:%.*]] = bitcast %struct.int16x8x2_t* [[AGG_RESULT]] to i8* // CHECK: [[TMP1:%.*]] = bitcast <8 x i16> %a to <16 x i8> // CHECK: [[TMP2:%.*]] = bitcast <8 x i16> %b to <16 x i8> @@ -20236,7 +20236,7 @@ int16x8x2_t test_vtrnq_s16(int16x8_t a, int16x8_t b) { return vtrnq_s16(a, b); } -// CHECK: @test_vtrnq_s32({{.*}} sret [[AGG_RESULT:%[0-9a-zA-Z.]+]], +// CHECK: @test_vtrnq_s32({{.*}} sret align 16 [[AGG_RESULT:%[0-9a-zA-Z.]+]], // CHECK: [[TMP0:%.*]] = bitcast %struct.int32x4x2_t* [[AGG_RESULT]] to i8* // CHECK: [[TMP1:%.*]] = bitcast <4 x i32> %a to <16 x i8> // CHECK: [[TMP2:%.*]] = bitcast <4 x i32> %b to <16 x i8> @@ -20251,7 +20251,7 @@ int32x4x2_t test_vtrnq_s32(int32x4_t a, int32x4_t b) { return vtrnq_s32(a, b); } -// CHECK: @test_vtrnq_u8({{.*}} sret [[AGG_RESULT:%[0-9a-zA-Z.]+]], +// CHECK: @test_vtrnq_u8({{.*}} sret align 16 [[AGG_RESULT:%[0-9a-zA-Z.]+]], // CHECK: [[TMP0:%.*]] = bitcast %struct.uint8x16x2_t* [[AGG_RESULT]] to i8* // CHECK: [[TMP1:%.*]] = bitcast i8* [[TMP0]] to <16 x i8>* // CHECK: [[VTRN_I:%.*]] = shufflevector <16 x i8> %a, <16 x i8> %b, <16 x i32> @@ -20264,7 +20264,7 @@ uint8x16x2_t test_vtrnq_u8(uint8x16_t a, uint8x16_t b) { return vtrnq_u8(a, b); } -// CHECK: @test_vtrnq_u16({{.*}} sret [[AGG_RESULT:%[0-9a-zA-Z.]+]], +// CHECK: @test_vtrnq_u16({{.*}} sret align 16 [[AGG_RESULT:%[0-9a-zA-Z.]+]], // CHECK: [[TMP0:%.*]] = bitcast %struct.uint16x8x2_t* [[AGG_RESULT]] to i8* // CHECK: [[TMP1:%.*]] = bitcast <8 x i16> %a to <16 x i8> // CHECK: [[TMP2:%.*]] = bitcast <8 x i16> %b to <16 x i8> @@ -20279,7 +20279,7 @@ uint16x8x2_t test_vtrnq_u16(uint16x8_t a, uint16x8_t b) { return vtrnq_u16(a, b); } -// CHECK: @test_vtrnq_u32({{.*}} sret [[AGG_RESULT:%[0-9a-zA-Z.]+]], +// CHECK: @test_vtrnq_u32({{.*}} sret align 16 [[AGG_RESULT:%[0-9a-zA-Z.]+]], // CHECK: [[TMP0:%.*]] = bitcast %struct.uint32x4x2_t* [[AGG_RESULT]] to i8* // CHECK: [[TMP1:%.*]] = bitcast <4 x i32> %a to <16 x i8> // CHECK: [[TMP2:%.*]] = bitcast <4 x i32> %b to <16 x i8> @@ -20294,7 +20294,7 @@ uint32x4x2_t test_vtrnq_u32(uint32x4_t a, uint32x4_t b) { return vtrnq_u32(a, b); } -// CHECK: @test_vtrnq_f32({{.*}} sret [[AGG_RESULT:%[0-9a-zA-Z.]+]], +// CHECK: @test_vtrnq_f32({{.*}} sret align 16 [[AGG_RESULT:%[0-9a-zA-Z.]+]], // CHECK: [[TMP0:%.*]] = bitcast %struct.float32x4x2_t* [[AGG_RESULT]] to i8* // CHECK: [[TMP1:%.*]] = bitcast <4 x float> %a to <16 x i8> // CHECK: [[TMP2:%.*]] = bitcast <4 x float> %b to <16 x i8> @@ -20309,7 +20309,7 @@ float32x4x2_t test_vtrnq_f32(float32x4_t a, float32x4_t b) { return vtrnq_f32(a, b); } -// CHECK: @test_vtrnq_p8({{.*}} sret [[AGG_RESULT:%[0-9a-zA-Z.]+]], +// CHECK: @test_vtrnq_p8({{.*}} sret align 16 [[AGG_RESULT:%[0-9a-zA-Z.]+]], // CHECK: [[TMP0:%.*]] = bitcast %struct.poly8x16x2_t* [[AGG_RESULT]] to i8* // CHECK: [[TMP1:%.*]] = bitcast i8* [[TMP0]] to <16 x i8>* // CHECK: [[VTRN_I:%.*]] = shufflevector <16 x i8> %a, <16 x i8> %b, <16 x i32> @@ -20322,7 +20322,7 @@ poly8x16x2_t test_vtrnq_p8(poly8x16_t a, poly8x16_t b) { return vtrnq_p8(a, b); } -// CHECK: @test_vtrnq_p16({{.*}} sret [[AGG_RESULT:%[0-9a-zA-Z.]+]], +// CHECK: @test_vtrnq_p16({{.*}} sret align 16 [[AGG_RESULT:%[0-9a-zA-Z.]+]], // CHECK: [[TMP0:%.*]] = bitcast %struct.poly16x8x2_t* [[AGG_RESULT]] to i8* // CHECK: [[TMP1:%.*]] = bitcast <8 x i16> %a to <16 x i8> // CHECK: [[TMP2:%.*]] = bitcast <8 x i16> %b to <16 x i8> @@ -20501,7 +20501,7 @@ uint16x8_t test_vtstq_p16(poly16x8_t a, poly16x8_t b) { return vtstq_p16(a, b); } -// CHECK: @test_vuzp_s8({{.*}} sret [[AGG_RESULT:%[0-9a-zA-Z.]+]], +// CHECK: @test_vuzp_s8({{.*}} sret align 8 [[AGG_RESULT:%[0-9a-zA-Z.]+]], // CHECK: [[TMP0:%.*]] = bitcast %struct.int8x8x2_t* [[AGG_RESULT]] to i8* // CHECK: [[TMP1:%.*]] = bitcast i8* [[TMP0]] to <8 x i8>* // CHECK: [[VUZP_I:%.*]] = shufflevector <8 x i8> %a, <8 x i8> %b, <8 x i32> @@ -20514,7 +20514,7 @@ int8x8x2_t test_vuzp_s8(int8x8_t a, int8x8_t b) { return vuzp_s8(a, b); } -// CHECK: @test_vuzp_s16({{.*}} sret [[AGG_RESULT:%[0-9a-zA-Z.]+]], +// CHECK: @test_vuzp_s16({{.*}} sret align 8 [[AGG_RESULT:%[0-9a-zA-Z.]+]], // CHECK: [[TMP0:%.*]] = bitcast %struct.int16x4x2_t* [[AGG_RESULT]] to i8* // CHECK: [[TMP1:%.*]] = bitcast <4 x i16> %a to <8 x i8> // CHECK: [[TMP2:%.*]] = bitcast <4 x i16> %b to <8 x i8> @@ -20529,7 +20529,7 @@ int16x4x2_t test_vuzp_s16(int16x4_t a, int16x4_t b) { return vuzp_s16(a, b); } -// CHECK: @test_vuzp_s32({{.*}} sret [[AGG_RESULT:%[0-9a-zA-Z.]+]], +// CHECK: @test_vuzp_s32({{.*}} sret align 8 [[AGG_RESULT:%[0-9a-zA-Z.]+]], // CHECK: [[TMP0:%.*]] = bitcast %struct.int32x2x2_t* [[AGG_RESULT]] to i8* // CHECK: [[TMP1:%.*]] = bitcast <2 x i32> %a to <8 x i8> // CHECK: [[TMP2:%.*]] = bitcast <2 x i32> %b to <8 x i8> @@ -20544,7 +20544,7 @@ int32x2x2_t test_vuzp_s32(int32x2_t a, int32x2_t b) { return vuzp_s32(a, b); } -// CHECK: @test_vuzp_u8({{.*}} sret [[AGG_RESULT:%[0-9a-zA-Z.]+]], +// CHECK: @test_vuzp_u8({{.*}} sret align 8 [[AGG_RESULT:%[0-9a-zA-Z.]+]], // CHECK: [[TMP0:%.*]] = bitcast %struct.uint8x8x2_t* [[AGG_RESULT]] to i8* // CHECK: [[TMP1:%.*]] = bitcast i8* [[TMP0]] to <8 x i8>* // CHECK: [[VUZP_I:%.*]] = shufflevector <8 x i8> %a, <8 x i8> %b, <8 x i32> @@ -20557,7 +20557,7 @@ uint8x8x2_t test_vuzp_u8(uint8x8_t a, uint8x8_t b) { return vuzp_u8(a, b); } -// CHECK: @test_vuzp_u16({{.*}} sret [[AGG_RESULT:%[0-9a-zA-Z.]+]], +// CHECK: @test_vuzp_u16({{.*}} sret align 8 [[AGG_RESULT:%[0-9a-zA-Z.]+]], // CHECK: [[TMP0:%.*]] = bitcast %struct.uint16x4x2_t* [[AGG_RESULT]] to i8* // CHECK: [[TMP1:%.*]] = bitcast <4 x i16> %a to <8 x i8> // CHECK: [[TMP2:%.*]] = bitcast <4 x i16> %b to <8 x i8> @@ -20572,7 +20572,7 @@ uint16x4x2_t test_vuzp_u16(uint16x4_t a, uint16x4_t b) { return vuzp_u16(a, b); } -// CHECK: @test_vuzp_u32({{.*}} sret [[AGG_RESULT:%[0-9a-zA-Z.]+]], +// CHECK: @test_vuzp_u32({{.*}} sret align 8 [[AGG_RESULT:%[0-9a-zA-Z.]+]], // CHECK: [[TMP0:%.*]] = bitcast %struct.uint32x2x2_t* [[AGG_RESULT]] to i8* // CHECK: [[TMP1:%.*]] = bitcast <2 x i32> %a to <8 x i8> // CHECK: [[TMP2:%.*]] = bitcast <2 x i32> %b to <8 x i8> @@ -20587,7 +20587,7 @@ uint32x2x2_t test_vuzp_u32(uint32x2_t a, uint32x2_t b) { return vuzp_u32(a, b); } -// CHECK: @test_vuzp_f32({{.*}} sret [[AGG_RESULT:%[0-9a-zA-Z.]+]], +// CHECK: @test_vuzp_f32({{.*}} sret align 8 [[AGG_RESULT:%[0-9a-zA-Z.]+]], // CHECK: [[TMP0:%.*]] = bitcast %struct.float32x2x2_t* [[AGG_RESULT]] to i8* // CHECK: [[TMP1:%.*]] = bitcast <2 x float> %a to <8 x i8> // CHECK: [[TMP2:%.*]] = bitcast <2 x float> %b to <8 x i8> @@ -20602,7 +20602,7 @@ float32x2x2_t test_vuzp_f32(float32x2_t a, float32x2_t b) { return vuzp_f32(a, b); } -// CHECK: @test_vuzp_p8({{.*}} sret [[AGG_RESULT:%[0-9a-zA-Z.]+]], +// CHECK: @test_vuzp_p8({{.*}} sret align 8 [[AGG_RESULT:%[0-9a-zA-Z.]+]], // CHECK: [[TMP0:%.*]] = bitcast %struct.poly8x8x2_t* [[AGG_RESULT]] to i8* // CHECK: [[TMP1:%.*]] = bitcast i8* [[TMP0]] to <8 x i8>* // CHECK: [[VUZP_I:%.*]] = shufflevector <8 x i8> %a, <8 x i8> %b, <8 x i32> @@ -20615,7 +20615,7 @@ poly8x8x2_t test_vuzp_p8(poly8x8_t a, poly8x8_t b) { return vuzp_p8(a, b); } -// CHECK: @test_vuzp_p16({{.*}} sret [[AGG_RESULT:%[0-9a-zA-Z.]+]], +// CHECK: @test_vuzp_p16({{.*}} sret align 8 [[AGG_RESULT:%[0-9a-zA-Z.]+]], // CHECK: [[TMP0:%.*]] = bitcast %struct.poly16x4x2_t* [[AGG_RESULT]] to i8* // CHECK: [[TMP1:%.*]] = bitcast <4 x i16> %a to <8 x i8> // CHECK: [[TMP2:%.*]] = bitcast <4 x i16> %b to <8 x i8> @@ -20630,7 +20630,7 @@ poly16x4x2_t test_vuzp_p16(poly16x4_t a, poly16x4_t b) { return vuzp_p16(a, b); } -// CHECK: @test_vuzpq_s8({{.*}} sret [[AGG_RESULT:%[0-9a-zA-Z.]+]], +// CHECK: @test_vuzpq_s8({{.*}} sret align 16 [[AGG_RESULT:%[0-9a-zA-Z.]+]], // CHECK: [[TMP0:%.*]] = bitcast %struct.int8x16x2_t* [[AGG_RESULT]] to i8* // CHECK: [[TMP1:%.*]] = bitcast i8* [[TMP0]] to <16 x i8>* // CHECK: [[VUZP_I:%.*]] = shufflevector <16 x i8> %a, <16 x i8> %b, <16 x i32> @@ -20643,7 +20643,7 @@ int8x16x2_t test_vuzpq_s8(int8x16_t a, int8x16_t b) { return vuzpq_s8(a, b); } -// CHECK: @test_vuzpq_s16({{.*}} sret [[AGG_RESULT:%[0-9a-zA-Z.]+]], +// CHECK: @test_vuzpq_s16({{.*}} sret align 16 [[AGG_RESULT:%[0-9a-zA-Z.]+]], // CHECK: [[TMP0:%.*]] = bitcast %struct.int16x8x2_t* [[AGG_RESULT]] to i8* // CHECK: [[TMP1:%.*]] = bitcast <8 x i16> %a to <16 x i8> // CHECK: [[TMP2:%.*]] = bitcast <8 x i16> %b to <16 x i8> @@ -20658,7 +20658,7 @@ int16x8x2_t test_vuzpq_s16(int16x8_t a, int16x8_t b) { return vuzpq_s16(a, b); } -// CHECK: @test_vuzpq_s32({{.*}} sret [[AGG_RESULT:%[0-9a-zA-Z.]+]], +// CHECK: @test_vuzpq_s32({{.*}} sret align 16 [[AGG_RESULT:%[0-9a-zA-Z.]+]], // CHECK: [[TMP0:%.*]] = bitcast %struct.int32x4x2_t* [[AGG_RESULT]] to i8* // CHECK: [[TMP1:%.*]] = bitcast <4 x i32> %a to <16 x i8> // CHECK: [[TMP2:%.*]] = bitcast <4 x i32> %b to <16 x i8> @@ -20673,7 +20673,7 @@ int32x4x2_t test_vuzpq_s32(int32x4_t a, int32x4_t b) { return vuzpq_s32(a, b); } -// CHECK: @test_vuzpq_u8({{.*}} sret [[AGG_RESULT:%[0-9a-zA-Z.]+]], +// CHECK: @test_vuzpq_u8({{.*}} sret align 16 [[AGG_RESULT:%[0-9a-zA-Z.]+]], // CHECK: [[TMP0:%.*]] = bitcast %struct.uint8x16x2_t* [[AGG_RESULT]] to i8* // CHECK: [[TMP1:%.*]] = bitcast i8* [[TMP0]] to <16 x i8>* // CHECK: [[VUZP_I:%.*]] = shufflevector <16 x i8> %a, <16 x i8> %b, <16 x i32> @@ -20686,7 +20686,7 @@ uint8x16x2_t test_vuzpq_u8(uint8x16_t a, uint8x16_t b) { return vuzpq_u8(a, b); } -// CHECK: @test_vuzpq_u16({{.*}} sret [[AGG_RESULT:%[0-9a-zA-Z.]+]], +// CHECK: @test_vuzpq_u16({{.*}} sret align 16 [[AGG_RESULT:%[0-9a-zA-Z.]+]], // CHECK: [[TMP0:%.*]] = bitcast %struct.uint16x8x2_t* [[AGG_RESULT]] to i8* // CHECK: [[TMP1:%.*]] = bitcast <8 x i16> %a to <16 x i8> // CHECK: [[TMP2:%.*]] = bitcast <8 x i16> %b to <16 x i8> @@ -20701,7 +20701,7 @@ uint16x8x2_t test_vuzpq_u16(uint16x8_t a, uint16x8_t b) { return vuzpq_u16(a, b); } -// CHECK: @test_vuzpq_u32({{.*}} sret [[AGG_RESULT:%[0-9a-zA-Z.]+]], +// CHECK: @test_vuzpq_u32({{.*}} sret align 16 [[AGG_RESULT:%[0-9a-zA-Z.]+]], // CHECK: [[TMP0:%.*]] = bitcast %struct.uint32x4x2_t* [[AGG_RESULT]] to i8* // CHECK: [[TMP1:%.*]] = bitcast <4 x i32> %a to <16 x i8> // CHECK: [[TMP2:%.*]] = bitcast <4 x i32> %b to <16 x i8> @@ -20716,7 +20716,7 @@ uint32x4x2_t test_vuzpq_u32(uint32x4_t a, uint32x4_t b) { return vuzpq_u32(a, b); } -// CHECK: @test_vuzpq_f32({{.*}} sret [[AGG_RESULT:%[0-9a-zA-Z.]+]], +// CHECK: @test_vuzpq_f32({{.*}} sret align 16 [[AGG_RESULT:%[0-9a-zA-Z.]+]], // CHECK: [[TMP0:%.*]] = bitcast %struct.float32x4x2_t* [[AGG_RESULT]] to i8* // CHECK: [[TMP1:%.*]] = bitcast <4 x float> %a to <16 x i8> // CHECK: [[TMP2:%.*]] = bitcast <4 x float> %b to <16 x i8> @@ -20731,7 +20731,7 @@ float32x4x2_t test_vuzpq_f32(float32x4_t a, float32x4_t b) { return vuzpq_f32(a, b); } -// CHECK: @test_vuzpq_p8({{.*}} sret [[AGG_RESULT:%[0-9a-zA-Z.]+]], +// CHECK: @test_vuzpq_p8({{.*}} sret align 16 [[AGG_RESULT:%[0-9a-zA-Z.]+]], // CHECK: [[TMP0:%.*]] = bitcast %struct.poly8x16x2_t* [[AGG_RESULT]] to i8* // CHECK: [[TMP1:%.*]] = bitcast i8* [[TMP0]] to <16 x i8>* // CHECK: [[VUZP_I:%.*]] = shufflevector <16 x i8> %a, <16 x i8> %b, <16 x i32> @@ -20744,7 +20744,7 @@ poly8x16x2_t test_vuzpq_p8(poly8x16_t a, poly8x16_t b) { return vuzpq_p8(a, b); } -// CHECK: @test_vuzpq_p16({{.*}} sret [[AGG_RESULT:%[0-9a-zA-Z.]+]], +// CHECK: @test_vuzpq_p16({{.*}} sret align 16 [[AGG_RESULT:%[0-9a-zA-Z.]+]], // CHECK: [[TMP0:%.*]] = bitcast %struct.poly16x8x2_t* [[AGG_RESULT]] to i8* // CHECK: [[TMP1:%.*]] = bitcast <8 x i16> %a to <16 x i8> // CHECK: [[TMP2:%.*]] = bitcast <8 x i16> %b to <16 x i8> @@ -20759,7 +20759,7 @@ poly16x8x2_t test_vuzpq_p16(poly16x8_t a, poly16x8_t b) { return vuzpq_p16(a, b); } -// CHECK: @test_vzip_s8({{.*}} sret [[AGG_RESULT:%[0-9a-zA-Z.]+]], +// CHECK: @test_vzip_s8({{.*}} sret align 8 [[AGG_RESULT:%[0-9a-zA-Z.]+]], // CHECK: [[TMP0:%.*]] = bitcast %struct.int8x8x2_t* [[AGG_RESULT]] to i8* // CHECK: [[TMP1:%.*]] = bitcast i8* [[TMP0]] to <8 x i8>* // CHECK: [[VZIP_I:%.*]] = shufflevector <8 x i8> %a, <8 x i8> %b, <8 x i32> @@ -20772,7 +20772,7 @@ int8x8x2_t test_vzip_s8(int8x8_t a, int8x8_t b) { return vzip_s8(a, b); } -// CHECK: @test_vzip_s16({{.*}} sret [[AGG_RESULT:%[0-9a-zA-Z.]+]], +// CHECK: @test_vzip_s16({{.*}} sret align 8 [[AGG_RESULT:%[0-9a-zA-Z.]+]], // CHECK: [[TMP0:%.*]] = bitcast %struct.int16x4x2_t* [[AGG_RESULT]] to i8* // CHECK: [[TMP1:%.*]] = bitcast <4 x i16> %a to <8 x i8> // CHECK: [[TMP2:%.*]] = bitcast <4 x i16> %b to <8 x i8> @@ -20787,7 +20787,7 @@ int16x4x2_t test_vzip_s16(int16x4_t a, int16x4_t b) { return vzip_s16(a, b); } -// CHECK: @test_vzip_s32({{.*}} sret [[AGG_RESULT:%[0-9a-zA-Z.]+]], +// CHECK: @test_vzip_s32({{.*}} sret align 8 [[AGG_RESULT:%[0-9a-zA-Z.]+]], // CHECK: [[TMP0:%.*]] = bitcast %struct.int32x2x2_t* [[AGG_RESULT]] to i8* // CHECK: [[TMP1:%.*]] = bitcast <2 x i32> %a to <8 x i8> // CHECK: [[TMP2:%.*]] = bitcast <2 x i32> %b to <8 x i8> @@ -20802,7 +20802,7 @@ int32x2x2_t test_vzip_s32(int32x2_t a, int32x2_t b) { return vzip_s32(a, b); } -// CHECK: @test_vzip_u8({{.*}} sret [[AGG_RESULT:%[0-9a-zA-Z.]+]], +// CHECK: @test_vzip_u8({{.*}} sret align 8 [[AGG_RESULT:%[0-9a-zA-Z.]+]], // CHECK: [[TMP0:%.*]] = bitcast %struct.uint8x8x2_t* [[AGG_RESULT]] to i8* // CHECK: [[TMP1:%.*]] = bitcast i8* [[TMP0]] to <8 x i8>* // CHECK: [[VZIP_I:%.*]] = shufflevector <8 x i8> %a, <8 x i8> %b, <8 x i32> @@ -20815,7 +20815,7 @@ uint8x8x2_t test_vzip_u8(uint8x8_t a, uint8x8_t b) { return vzip_u8(a, b); } -// CHECK: @test_vzip_u16({{.*}} sret [[AGG_RESULT:%[0-9a-zA-Z.]+]], +// CHECK: @test_vzip_u16({{.*}} sret align 8 [[AGG_RESULT:%[0-9a-zA-Z.]+]], // CHECK: [[TMP0:%.*]] = bitcast %struct.uint16x4x2_t* [[AGG_RESULT]] to i8* // CHECK: [[TMP1:%.*]] = bitcast <4 x i16> %a to <8 x i8> // CHECK: [[TMP2:%.*]] = bitcast <4 x i16> %b to <8 x i8> @@ -20830,7 +20830,7 @@ uint16x4x2_t test_vzip_u16(uint16x4_t a, uint16x4_t b) { return vzip_u16(a, b); } -// CHECK: @test_vzip_u32({{.*}} sret [[AGG_RESULT:%[0-9a-zA-Z.]+]], +// CHECK: @test_vzip_u32({{.*}} sret align 8 [[AGG_RESULT:%[0-9a-zA-Z.]+]], // CHECK: [[TMP0:%.*]] = bitcast %struct.uint32x2x2_t* [[AGG_RESULT]] to i8* // CHECK: [[TMP1:%.*]] = bitcast <2 x i32> %a to <8 x i8> // CHECK: [[TMP2:%.*]] = bitcast <2 x i32> %b to <8 x i8> @@ -20845,7 +20845,7 @@ uint32x2x2_t test_vzip_u32(uint32x2_t a, uint32x2_t b) { return vzip_u32(a, b); } -// CHECK: @test_vzip_f32({{.*}} sret [[AGG_RESULT:%[0-9a-zA-Z.]+]], +// CHECK: @test_vzip_f32({{.*}} sret align 8 [[AGG_RESULT:%[0-9a-zA-Z.]+]], // CHECK: [[TMP0:%.*]] = bitcast %struct.float32x2x2_t* [[AGG_RESULT]] to i8* // CHECK: [[TMP1:%.*]] = bitcast <2 x float> %a to <8 x i8> // CHECK: [[TMP2:%.*]] = bitcast <2 x float> %b to <8 x i8> @@ -20860,7 +20860,7 @@ float32x2x2_t test_vzip_f32(float32x2_t a, float32x2_t b) { return vzip_f32(a, b); } -// CHECK: @test_vzip_p8({{.*}} sret [[AGG_RESULT:%[0-9a-zA-Z.]+]], +// CHECK: @test_vzip_p8({{.*}} sret align 8 [[AGG_RESULT:%[0-9a-zA-Z.]+]], // CHECK: [[TMP0:%.*]] = bitcast %struct.poly8x8x2_t* [[AGG_RESULT]] to i8* // CHECK: [[TMP1:%.*]] = bitcast i8* [[TMP0]] to <8 x i8>* // CHECK: [[VZIP_I:%.*]] = shufflevector <8 x i8> %a, <8 x i8> %b, <8 x i32> @@ -20873,7 +20873,7 @@ poly8x8x2_t test_vzip_p8(poly8x8_t a, poly8x8_t b) { return vzip_p8(a, b); } -// CHECK: @test_vzip_p16({{.*}} sret [[AGG_RESULT:%[0-9a-zA-Z.]+]], +// CHECK: @test_vzip_p16({{.*}} sret align 8 [[AGG_RESULT:%[0-9a-zA-Z.]+]], // CHECK: [[TMP0:%.*]] = bitcast %struct.poly16x4x2_t* [[AGG_RESULT]] to i8* // CHECK: [[TMP1:%.*]] = bitcast <4 x i16> %a to <8 x i8> // CHECK: [[TMP2:%.*]] = bitcast <4 x i16> %b to <8 x i8> @@ -20888,7 +20888,7 @@ poly16x4x2_t test_vzip_p16(poly16x4_t a, poly16x4_t b) { return vzip_p16(a, b); } -// CHECK: @test_vzipq_s8({{.*}} sret [[AGG_RESULT:%[0-9a-zA-Z.]+]], +// CHECK: @test_vzipq_s8({{.*}} sret align 16 [[AGG_RESULT:%[0-9a-zA-Z.]+]], // CHECK: [[TMP0:%.*]] = bitcast %struct.int8x16x2_t* [[AGG_RESULT]] to i8* // CHECK: [[TMP1:%.*]] = bitcast i8* [[TMP0]] to <16 x i8>* // CHECK: [[VZIP_I:%.*]] = shufflevector <16 x i8> %a, <16 x i8> %b, <16 x i32> @@ -20901,7 +20901,7 @@ int8x16x2_t test_vzipq_s8(int8x16_t a, int8x16_t b) { return vzipq_s8(a, b); } -// CHECK: @test_vzipq_s16({{.*}} sret [[AGG_RESULT:%[0-9a-zA-Z.]+]], +// CHECK: @test_vzipq_s16({{.*}} sret align 16 [[AGG_RESULT:%[0-9a-zA-Z.]+]], // CHECK: [[TMP0:%.*]] = bitcast %struct.int16x8x2_t* [[AGG_RESULT]] to i8* // CHECK: [[TMP1:%.*]] = bitcast <8 x i16> %a to <16 x i8> // CHECK: [[TMP2:%.*]] = bitcast <8 x i16> %b to <16 x i8> @@ -20916,7 +20916,7 @@ int16x8x2_t test_vzipq_s16(int16x8_t a, int16x8_t b) { return vzipq_s16(a, b); } -// CHECK: @test_vzipq_s32({{.*}} sret [[AGG_RESULT:%[0-9a-zA-Z.]+]], +// CHECK: @test_vzipq_s32({{.*}} sret align 16 [[AGG_RESULT:%[0-9a-zA-Z.]+]], // CHECK: [[TMP0:%.*]] = bitcast %struct.int32x4x2_t* [[AGG_RESULT]] to i8* // CHECK: [[TMP1:%.*]] = bitcast <4 x i32> %a to <16 x i8> // CHECK: [[TMP2:%.*]] = bitcast <4 x i32> %b to <16 x i8> @@ -20931,7 +20931,7 @@ int32x4x2_t test_vzipq_s32(int32x4_t a, int32x4_t b) { return vzipq_s32(a, b); } -// CHECK: @test_vzipq_u8({{.*}} sret [[AGG_RESULT:%[0-9a-zA-Z.]+]], +// CHECK: @test_vzipq_u8({{.*}} sret align 16 [[AGG_RESULT:%[0-9a-zA-Z.]+]], // CHECK: [[TMP0:%.*]] = bitcast %struct.uint8x16x2_t* [[AGG_RESULT]] to i8* // CHECK: [[TMP1:%.*]] = bitcast i8* [[TMP0]] to <16 x i8>* // CHECK: [[VZIP_I:%.*]] = shufflevector <16 x i8> %a, <16 x i8> %b, <16 x i32> @@ -20944,7 +20944,7 @@ uint8x16x2_t test_vzipq_u8(uint8x16_t a, uint8x16_t b) { return vzipq_u8(a, b); } -// CHECK: @test_vzipq_u16({{.*}} sret [[AGG_RESULT:%[0-9a-zA-Z.]+]], +// CHECK: @test_vzipq_u16({{.*}} sret align 16 [[AGG_RESULT:%[0-9a-zA-Z.]+]], // CHECK: [[TMP0:%.*]] = bitcast %struct.uint16x8x2_t* [[AGG_RESULT]] to i8* // CHECK: [[TMP1:%.*]] = bitcast <8 x i16> %a to <16 x i8> // CHECK: [[TMP2:%.*]] = bitcast <8 x i16> %b to <16 x i8> @@ -20959,7 +20959,7 @@ uint16x8x2_t test_vzipq_u16(uint16x8_t a, uint16x8_t b) { return vzipq_u16(a, b); } -// CHECK: @test_vzipq_u32({{.*}} sret [[AGG_RESULT:%[0-9a-zA-Z.]+]], +// CHECK: @test_vzipq_u32({{.*}} sret align 16 [[AGG_RESULT:%[0-9a-zA-Z.]+]], // CHECK: [[TMP0:%.*]] = bitcast %struct.uint32x4x2_t* [[AGG_RESULT]] to i8* // CHECK: [[TMP1:%.*]] = bitcast <4 x i32> %a to <16 x i8> // CHECK: [[TMP2:%.*]] = bitcast <4 x i32> %b to <16 x i8> @@ -20974,7 +20974,7 @@ uint32x4x2_t test_vzipq_u32(uint32x4_t a, uint32x4_t b) { return vzipq_u32(a, b); } -// CHECK: @test_vzipq_f32({{.*}} sret [[AGG_RESULT:%[0-9a-zA-Z.]+]], +// CHECK: @test_vzipq_f32({{.*}} sret align 16 [[AGG_RESULT:%[0-9a-zA-Z.]+]], // CHECK: [[TMP0:%.*]] = bitcast %struct.float32x4x2_t* [[AGG_RESULT]] to i8* // CHECK: [[TMP1:%.*]] = bitcast <4 x float> %a to <16 x i8> // CHECK: [[TMP2:%.*]] = bitcast <4 x float> %b to <16 x i8> @@ -20989,7 +20989,7 @@ float32x4x2_t test_vzipq_f32(float32x4_t a, float32x4_t b) { return vzipq_f32(a, b); } -// CHECK: @test_vzipq_p8({{.*}} sret [[AGG_RESULT:%[0-9a-zA-Z.]+]], +// CHECK: @test_vzipq_p8({{.*}} sret align 16 [[AGG_RESULT:%[0-9a-zA-Z.]+]], // CHECK: [[TMP0:%.*]] = bitcast %struct.poly8x16x2_t* [[AGG_RESULT]] to i8* // CHECK: [[TMP1:%.*]] = bitcast i8* [[TMP0]] to <16 x i8>* // CHECK: [[VZIP_I:%.*]] = shufflevector <16 x i8> %a, <16 x i8> %b, <16 x i32> @@ -21002,7 +21002,7 @@ poly8x16x2_t test_vzipq_p8(poly8x16_t a, poly8x16_t b) { return vzipq_p8(a, b); } -// CHECK: @test_vzipq_p16({{.*}} sret [[AGG_RESULT:%[0-9a-zA-Z.]+]], +// CHECK: @test_vzipq_p16({{.*}} sret align 16 [[AGG_RESULT:%[0-9a-zA-Z.]+]], // CHECK: [[TMP0:%.*]] = bitcast %struct.poly16x8x2_t* [[AGG_RESULT]] to i8* // CHECK: [[TMP1:%.*]] = bitcast <8 x i16> %a to <16 x i8> // CHECK: [[TMP2:%.*]] = bitcast <8 x i16> %b to <16 x i8> diff --git a/clang/test/CodeGen/blocks.c b/clang/test/CodeGen/blocks.c index fd348c98f65fe..3f1f2502652cd 100644 --- a/clang/test/CodeGen/blocks.c +++ b/clang/test/CodeGen/blocks.c @@ -18,7 +18,7 @@ struct s0 { int a[64]; }; -// CHECK: define internal void @__f2_block_invoke(%struct.s0* noalias sret {{%.*}}, i8* {{%.*}}, %struct.s0* byval(%struct.s0) align 4 {{.*}}) +// CHECK: define internal void @__f2_block_invoke(%struct.s0* noalias sret align 4 {{%.*}}, i8* {{%.*}}, %struct.s0* byval(%struct.s0) align 4 {{.*}}) struct s0 f2(struct s0 a0) { return ^(struct s0 a1){ return a1; }(a0); } diff --git a/clang/test/CodeGen/bounds-checking.c b/clang/test/CodeGen/bounds-checking.c index 2e6a08650dd97..15cef8c007a55 100644 --- a/clang/test/CodeGen/bounds-checking.c +++ b/clang/test/CodeGen/bounds-checking.c @@ -1,7 +1,7 @@ // RUN: %clang_cc1 -fsanitize=local-bounds -emit-llvm -triple x86_64-apple-darwin10 %s -o - | FileCheck %s // RUN: %clang_cc1 -fsanitize=local-bounds -fexperimental-new-pass-manager -emit-llvm -triple x86_64-apple-darwin10 %s -o - | FileCheck %s -// RUN: %clang_cc1 -fsanitize=array-bounds -O -fsanitize-trap=array-bounds -emit-llvm -triple x86_64-apple-darwin10 -DNO_DYNAMIC %s -o - | FileCheck %s -// RUN: %clang_cc1 -fsanitize=array-bounds -O -fsanitize-trap=array-bounds -fexperimental-new-pass-manager -emit-llvm -triple x86_64-apple-darwin10 -DNO_DYNAMIC %s -o - | FileCheck %s +// RUN: %clang_cc1 -fsanitize=array-bounds -O -fsanitize-trap=array-bounds -emit-llvm -triple x86_64-apple-darwin10 -DNO_DYNAMIC %s -o - | FileCheck %s --check-prefixes=CHECK,NONLOCAL +// RUN: %clang_cc1 -fsanitize=array-bounds -O -fsanitize-trap=array-bounds -fexperimental-new-pass-manager -emit-llvm -triple x86_64-apple-darwin10 -DNO_DYNAMIC %s -o - | FileCheck %s --check-prefixes=CHECK,NONLOCAL // // REQUIRES: x86-registered-target @@ -31,3 +31,21 @@ void f3() { // CHECK: call {{.*}} @llvm.trap a[2] = 1; } + +union U { int a[0]; int b[1]; int c[2]; }; + +// CHECK-LABEL: define {{.*}} @f4 +int f4(union U *u, int i) { + // a and b are treated as flexible array members. + // CHECK-NOT: @llvm.trap + return u->a[i] + u->b[i]; + // CHECK: } +} + +// CHECK-LABEL: define {{.*}} @f5 +int f5(union U *u, int i) { + // c is not a flexible array member. + // NONLOCAL: call {{.*}} @llvm.trap + return u->c[i]; + // CHECK: } +} diff --git a/clang/test/CodeGen/c11atomics-ios.c b/clang/test/CodeGen/c11atomics-ios.c index f48e10e4aa430..92d318dac1c35 100644 --- a/clang/test/CodeGen/c11atomics-ios.c +++ b/clang/test/CodeGen/c11atomics-ios.c @@ -203,7 +203,7 @@ void testPromotedStruct(_Atomic(PS) *fp) { } PS test_promoted_load(_Atomic(PS) *addr) { - // CHECK-LABEL: @test_promoted_load(%struct.PS* noalias sret %agg.result, { %struct.PS, [2 x i8] }* %addr) + // CHECK-LABEL: @test_promoted_load(%struct.PS* noalias sret align 2 %agg.result, { %struct.PS, [2 x i8] }* %addr) // CHECK: [[ADDR_ARG:%.*]] = alloca { %struct.PS, [2 x i8] }*, align 4 // CHECK: [[ATOMIC_RES:%.*]] = alloca { %struct.PS, [2 x i8] }, align 8 // CHECK: store { %struct.PS, [2 x i8] }* %addr, { %struct.PS, [2 x i8] }** [[ADDR_ARG]], align 4 @@ -245,7 +245,7 @@ void test_promoted_store(_Atomic(PS) *addr, PS *val) { } PS test_promoted_exchange(_Atomic(PS) *addr, PS *val) { - // CHECK-LABEL: @test_promoted_exchange(%struct.PS* noalias sret %agg.result, { %struct.PS, [2 x i8] }* %addr, %struct.PS* %val) + // CHECK-LABEL: @test_promoted_exchange(%struct.PS* noalias sret align 2 %agg.result, { %struct.PS, [2 x i8] }* %addr, %struct.PS* %val) // CHECK: [[ADDR_ARG:%.*]] = alloca { %struct.PS, [2 x i8] }*, align 4 // CHECK: [[VAL_ARG:%.*]] = alloca %struct.PS*, align 4 // CHECK: [[NONATOMIC_TMP:%.*]] = alloca %struct.PS, align 2 diff --git a/clang/test/CodeGen/c11atomics.c b/clang/test/CodeGen/c11atomics.c index cf251738be55e..cb97c67e485f8 100644 --- a/clang/test/CodeGen/c11atomics.c +++ b/clang/test/CodeGen/c11atomics.c @@ -368,7 +368,7 @@ void testPromotedStruct(_Atomic(PS) *fp) { } PS test_promoted_load(_Atomic(PS) *addr) { - // CHECK-LABEL: @test_promoted_load(%struct.PS* noalias sret %agg.result, { %struct.PS, [2 x i8] }* %addr) + // CHECK-LABEL: @test_promoted_load(%struct.PS* noalias sret align 2 %agg.result, { %struct.PS, [2 x i8] }* %addr) // CHECK: [[ADDR_ARG:%.*]] = alloca { %struct.PS, [2 x i8] }*, align 4 // CHECK: [[ATOMIC_RES:%.*]] = alloca { %struct.PS, [2 x i8] }, align 8 // CHECK: store { %struct.PS, [2 x i8] }* %addr, { %struct.PS, [2 x i8] }** [[ADDR_ARG]], align 4 @@ -411,7 +411,7 @@ void test_promoted_store(_Atomic(PS) *addr, PS *val) { } PS test_promoted_exchange(_Atomic(PS) *addr, PS *val) { - // CHECK-LABEL: @test_promoted_exchange(%struct.PS* noalias sret %agg.result, { %struct.PS, [2 x i8] }* %addr, %struct.PS* %val) + // CHECK-LABEL: @test_promoted_exchange(%struct.PS* noalias sret align 2 %agg.result, { %struct.PS, [2 x i8] }* %addr, %struct.PS* %val) // CHECK: [[ADDR_ARG:%.*]] = alloca { %struct.PS, [2 x i8] }*, align 4 // CHECK: [[VAL_ARG:%.*]] = alloca %struct.PS*, align 4 // CHECK: [[NONATOMIC_TMP:%.*]] = alloca %struct.PS, align 2 diff --git a/clang/test/CodeGen/debug-info-sysroot-sdk.c b/clang/test/CodeGen/debug-info-sysroot-sdk.c new file mode 100644 index 0000000000000..5c4d201d69047 --- /dev/null +++ b/clang/test/CodeGen/debug-info-sysroot-sdk.c @@ -0,0 +1,16 @@ +// RUN: %clang_cc1 -debug-info-kind=limited -triple %itanium_abi_triple \ +// RUN: %s -isysroot /CLANG_SYSROOT/MacOSX.sdk -emit-llvm -o - \ +// RUN: -debugger-tuning=lldb | FileCheck %s --check-prefix=LLDB +// RUN: %clang_cc1 -debug-info-kind=limited -triple %itanium_abi_triple \ +// RUN: %s -isysroot /CLANG_SYSROOT/MacOSX.sdk -emit-llvm -o - \ +// RUN: -debugger-tuning=gdb | FileCheck %s --check-prefix=GDB + +void foo() {} + +// The sysroot and sdk are LLDB-tuning-specific attributes. + +// LLDB: distinct !DICompileUnit({{.*}}sysroot: "/CLANG_SYSROOT/MacOSX.sdk", +// LLDB-SAME: sdk: "MacOSX.sdk" +// GDB: distinct !DICompileUnit( +// GDB-NOT: sysroot: "/CLANG_SYSROOT/MacOSX.sdk" +// GDB-NOT: sdk: "MacOSX.sdk" diff --git a/clang/test/CodeGen/debug-info-sysroot.c b/clang/test/CodeGen/debug-info-sysroot.c deleted file mode 100644 index bb3c0c820cee6..0000000000000 --- a/clang/test/CodeGen/debug-info-sysroot.c +++ /dev/null @@ -1,15 +0,0 @@ -// RUN: %clang_cc1 -debug-info-kind=limited -triple %itanium_abi_triple \ -// RUN: %s -isysroot /CLANG_SYSROOT -emit-llvm -o - \ -// RUN: -debugger-tuning=lldb | FileCheck %s --check-prefix=LLDB -// RUN: %clang_cc1 -debug-info-kind=limited -triple %itanium_abi_triple \ -// RUN: %s -isysroot /CLANG_SYSROOT -emit-llvm -o - \ -// RUN: -debugger-tuning=gdb | FileCheck %s --check-prefix=GDB - -void foo() {} - -// The sysroot is an LLDB-tuning-specific attribute. - -// LLDB: distinct !DICompileUnit({{.*}}sysroot: "/CLANG_SYSROOT" -// GDB: distinct !DICompileUnit( -// GDB-NOT: sysroot: "/CLANG_SYSROOT" - diff --git a/clang/test/CodeGen/debug-prefix-map.c b/clang/test/CodeGen/debug-prefix-map.c index 5366e19447ae2..354110d1b0da7 100644 --- a/clang/test/CodeGen/debug-prefix-map.c +++ b/clang/test/CodeGen/debug-prefix-map.c @@ -2,6 +2,7 @@ // RUN: %clang_cc1 -debug-info-kind=standalone -fdebug-prefix-map=%p=/UNLIKELY_PATH=empty %s -emit-llvm -o - | FileCheck %s -check-prefix CHECK-EVIL // RUN: %clang_cc1 -debug-info-kind=standalone -fdebug-prefix-map=%p=/UNLIKELY_PATH/empty %s -emit-llvm -o - -main-file-name debug-prefix-map.c | FileCheck %s // RUN: %clang_cc1 -debug-info-kind=standalone -fdebug-prefix-map=%p=/UNLIKELY_PATH/empty %s -emit-llvm -o - -fdebug-compilation-dir %p | FileCheck %s -check-prefix CHECK-COMPILATION-DIR +// RUN: %clang_cc1 -debug-info-kind=standalone -fdebug-prefix-map=%p=/UNLIKELY_PATH/empty %s -emit-llvm -o - -isysroot %p -debugger-tuning=lldb | FileCheck %s -check-prefix CHECK-SYSROOT // RUN: %clang -g -fdebug-prefix-map=%p=/UNLIKELY_PATH/empty -S -c %s -emit-llvm -o - | FileCheck %s // RUN: %clang -g -ffile-prefix-map=%p=/UNLIKELY_PATH/empty -S -c %s -emit-llvm -o - | FileCheck %s @@ -40,3 +41,4 @@ void test_rewrite_includes() { // CHECK-COMPILATION-DIR: !DIFile(filename: "{{.*}}", directory: "/UNLIKELY_PATH/empty") // CHECK-COMPILATION-DIR: !DIFile(filename: "{{.*}}Inputs/stdio.h", directory: "/UNLIKELY_PATH/empty") // CHECK-COMPILATION-DIR-NOT: !DIFile(filename: +// CHECK-SYSROOT: !DICompileUnit({{.*}}sysroot: "/UNLIKELY_PATH/empty" diff --git a/clang/test/CodeGen/fp16-ops.c b/clang/test/CodeGen/fp16-ops.c index f74552b85921c..6401dd125d2a5 100644 --- a/clang/test/CodeGen/fp16-ops.c +++ b/clang/test/CodeGen/fp16-ops.c @@ -11,6 +11,7 @@ // RUN: %clang_cc1 -emit-llvm -o - -x renderscript %s \ // RUN: | FileCheck %s --check-prefix=NATIVE-HALF typedef unsigned cond_t; +typedef __fp16 float16_t; volatile cond_t test; volatile int i0; @@ -541,3 +542,15 @@ void foo(void) { // NOTNATIVE: store volatile half [[TRUNC]], half* @h0 h0 = s0; } + +// CHECK-LABEL: define void @testTypeDef( +// CHECK: %[[CONV:.*]] = fpext <4 x half> %{{.*}} to <4 x float> +// CHECK: %[[CONV1:.*]] = fpext <4 x half> %{{.*}} to <4 x float> +// CHECK: %[[ADD:.*]] = fadd <4 x float> %[[CONV]], %[[CONV1]] +// CHECK: fptrunc <4 x float> %[[ADD]] to <4 x half> + +void testTypeDef() { + __fp16 t0 __attribute__((vector_size(8))); + float16_t t1 __attribute__((vector_size(8))); + t1 = t0 + t1; +} diff --git a/clang/test/CodeGen/lanai-arguments.c b/clang/test/CodeGen/lanai-arguments.c index 9ce4ed98a78ce..ef06b3221bc52 100644 --- a/clang/test/CodeGen/lanai-arguments.c +++ b/clang/test/CodeGen/lanai-arguments.c @@ -16,7 +16,7 @@ void f1(s1 i) {} typedef struct { int cc; } s2; -// CHECK: define void @f2(%struct.s2* noalias sret %agg.result) +// CHECK: define void @f2(%struct.s2* noalias sret align 4 %agg.result) s2 f2() { s2 foo; return foo; @@ -26,7 +26,7 @@ typedef struct { int cc; int dd; } s3; -// CHECK: define void @f3(%struct.s3* noalias sret %agg.result) +// CHECK: define void @f3(%struct.s3* noalias sret align 4 %agg.result) s3 f3() { s3 foo; return foo; diff --git a/clang/test/CodeGen/le32-arguments.c b/clang/test/CodeGen/le32-arguments.c index 9e6908d7fc41c..ad368e1a3941a 100644 --- a/clang/test/CodeGen/le32-arguments.c +++ b/clang/test/CodeGen/le32-arguments.c @@ -17,7 +17,7 @@ typedef struct { int cc; } s2; // Structs should be returned sret and not simplified by the frontend -// CHECK-LABEL: define void @f2(%struct.s2* noalias sret %agg.result) +// CHECK-LABEL: define void @f2(%struct.s2* noalias sret align 4 %agg.result) s2 f2() { s2 foo; return foo; diff --git a/clang/test/CodeGen/mcu-struct-return.c b/clang/test/CodeGen/mcu-struct-return.c index 353c963dadb01..93325254bc8db 100644 --- a/clang/test/CodeGen/mcu-struct-return.c +++ b/clang/test/CodeGen/mcu-struct-return.c @@ -42,7 +42,7 @@ struct S1 bar1() { return s1; } struct S2 bar2() { return s2; } struct S1 bar3(union U1 u) { return s1; } // CHECK: define void @foo1() -// CHECK: define void @foo2([[UNION2_TYPE]]* noalias sret %{{.+}}) +// CHECK: define void @foo2([[UNION2_TYPE]]* noalias sret align 4 %{{.+}}) // CHECK: define i32 @foo3() // CHECK: define void @bar1() // CHECK: define i32 @bar2() @@ -62,7 +62,7 @@ void run() { // CHECK: [[Y1:%.+]] = alloca [[STRUCT1_TYPE]] // CHECK: [[Y2:%.+]] = alloca [[STRUCT2_TYPE]] // CHECK: call void @foo1() - // CHECK: call void @foo2([[UNION2_TYPE]]* sret [[X2]]) + // CHECK: call void @foo2([[UNION2_TYPE]]* sret align 4 [[X2]]) // CHECK: {{.+}} = call i32 @foo3() // CHECK: call void @bar1() // CHECK: {{.+}} = call i32 @bar2() diff --git a/clang/test/CodeGen/mingw-long-double.c b/clang/test/CodeGen/mingw-long-double.c index 57e4adaa5fabe..08e3ac754d6b3 100644 --- a/clang/test/CodeGen/mingw-long-double.c +++ b/clang/test/CodeGen/mingw-long-double.c @@ -32,15 +32,15 @@ long double TestLD(long double x) { return x * x; } // GNU32: define dso_local x86_fp80 @TestLD(x86_fp80 %x) -// GNU64: define dso_local void @TestLD(x86_fp80* noalias sret %agg.result, x86_fp80* %0) +// GNU64: define dso_local void @TestLD(x86_fp80* noalias sret align 16 %agg.result, x86_fp80* %0) // MSC64: define dso_local double @TestLD(double %x) long double _Complex TestLDC(long double _Complex x) { return x * x; } -// GNU32: define dso_local void @TestLDC({ x86_fp80, x86_fp80 }* noalias sret %agg.result, { x86_fp80, x86_fp80 }* byval({ x86_fp80, x86_fp80 }) align 4 %x) -// GNU64: define dso_local void @TestLDC({ x86_fp80, x86_fp80 }* noalias sret %agg.result, { x86_fp80, x86_fp80 }* %x) -// MSC64: define dso_local void @TestLDC({ double, double }* noalias sret %agg.result, { double, double }* %x) +// GNU32: define dso_local void @TestLDC({ x86_fp80, x86_fp80 }* noalias sret align 4 %agg.result, { x86_fp80, x86_fp80 }* byval({ x86_fp80, x86_fp80 }) align 4 %x) +// GNU64: define dso_local void @TestLDC({ x86_fp80, x86_fp80 }* noalias sret align 16 %agg.result, { x86_fp80, x86_fp80 }* %x) +// MSC64: define dso_local void @TestLDC({ double, double }* noalias sret align 8 %agg.result, { double, double }* %x) // GNU32: declare dso_local void @__mulxc3 // GNU64: declare dso_local void @__mulxc3 diff --git a/clang/test/CodeGen/mips-zero-sized-struct.c b/clang/test/CodeGen/mips-zero-sized-struct.c index 08ebf9df3e93b..5f0e660cf395b 100644 --- a/clang/test/CodeGen/mips-zero-sized-struct.c +++ b/clang/test/CodeGen/mips-zero-sized-struct.c @@ -19,7 +19,7 @@ // RUN: %clang_cc1 -triple mipsisa64r6-unknown-linux-gnuabi64 -S -emit-llvm -o - %s | FileCheck -check-prefix=N64 %s // RUN: %clang_cc1 -triple mipsisa64r6el-unknown-linux-gnuabi64 -S -emit-llvm -o - %s | FileCheck -check-prefix=N64 %s -// O32: define void @fn28(%struct.T2* noalias sret %agg.result, i8 signext %arg0) +// O32: define void @fn28(%struct.T2* noalias sret align 1 %agg.result, i8 signext %arg0) // N32: define void @fn28(i8 signext %arg0) // N64: define void @fn28(i8 signext %arg0) diff --git a/clang/test/CodeGen/mips64-padding-arg.c b/clang/test/CodeGen/mips64-padding-arg.c index a7c8f0ff6fdc0..d440743fd7238 100644 --- a/clang/test/CodeGen/mips64-padding-arg.c +++ b/clang/test/CodeGen/mips64-padding-arg.c @@ -33,9 +33,9 @@ void foo3(int a0, long double a1) { // Insert padding after hidden argument. // -// N64-LABEL: define void @foo5(%struct.S0* noalias sret %agg.result, i64 %0, fp128 %a0) -// N64: call void @foo6(%struct.S0* sret %agg.result, i32 signext 1, i32 signext 2, i64 undef, fp128 %a0) -// N64: declare void @foo6(%struct.S0* sret, i32 signext, i32 signext, i64, fp128) +// N64-LABEL: define void @foo5(%struct.S0* noalias sret align 16 %agg.result, i64 %0, fp128 %a0) +// N64: call void @foo6(%struct.S0* sret align 16 %agg.result, i32 signext 1, i32 signext 2, i64 undef, fp128 %a0) +// N64: declare void @foo6(%struct.S0* sret align 16, i32 signext, i32 signext, i64, fp128) extern S0 foo6(int, int, long double); diff --git a/clang/test/CodeGen/ms_abi.c b/clang/test/CodeGen/ms_abi.c index 75e1caf922df9..8c66c5dc43610 100644 --- a/clang/test/CodeGen/ms_abi.c +++ b/clang/test/CodeGen/ms_abi.c @@ -155,7 +155,7 @@ struct i128 { }; __attribute__((ms_abi)) struct i128 f7(struct i128 a) { - // WIN64: define dso_local void @f7(%struct.i128* noalias sret %agg.result, %struct.i128* %a) - // FREEBSD: define win64cc void @f7(%struct.i128* noalias sret %agg.result, %struct.i128* %a) + // WIN64: define dso_local void @f7(%struct.i128* noalias sret align 8 %agg.result, %struct.i128* %a) + // FREEBSD: define win64cc void @f7(%struct.i128* noalias sret align 8 %agg.result, %struct.i128* %a) return a; } diff --git a/clang/test/CodeGen/ppc64-align-struct.c b/clang/test/CodeGen/ppc64-align-struct.c index bcff4920d0c49..3435a6e429396 100644 --- a/clang/test/CodeGen/ppc64-align-struct.c +++ b/clang/test/CodeGen/ppc64-align-struct.c @@ -48,7 +48,7 @@ void test7 (int x, struct test7 y) { } -// CHECK: define void @test1va(%struct.test1* noalias sret %[[AGG_RESULT:.*]], i32 signext %x, ...) +// CHECK: define void @test1va(%struct.test1* noalias sret align 4 %[[AGG_RESULT:.*]], i32 signext %x, ...) // CHECK: %[[CUR:[^ ]+]] = load i8*, i8** %ap // CHECK: %[[NEXT:[^ ]+]] = getelementptr inbounds i8, i8* %[[CUR]], i64 8 // CHECK: store i8* %[[NEXT]], i8** %ap @@ -66,7 +66,7 @@ struct test1 test1va (int x, ...) return y; } -// CHECK: define void @test2va(%struct.test2* noalias sret %[[AGG_RESULT:.*]], i32 signext %x, ...) +// CHECK: define void @test2va(%struct.test2* noalias sret align 16 %[[AGG_RESULT:.*]], i32 signext %x, ...) // CHECK: %[[CUR:[^ ]+]] = load i8*, i8** %ap // CHECK: %[[TMP0:[^ ]+]] = ptrtoint i8* %[[CUR]] to i64 // CHECK: %[[TMP1:[^ ]+]] = add i64 %[[TMP0]], 15 @@ -88,7 +88,7 @@ struct test2 test2va (int x, ...) return y; } -// CHECK: define void @test3va(%struct.test3* noalias sret %[[AGG_RESULT:.*]], i32 signext %x, ...) +// CHECK: define void @test3va(%struct.test3* noalias sret align 32 %[[AGG_RESULT:.*]], i32 signext %x, ...) // CHECK: %[[CUR:[^ ]+]] = load i8*, i8** %ap // CHECK: %[[TMP0:[^ ]+]] = ptrtoint i8* %[[CUR]] to i64 // CHECK: %[[TMP1:[^ ]+]] = add i64 %[[TMP0]], 15 @@ -110,7 +110,7 @@ struct test3 test3va (int x, ...) return y; } -// CHECK: define void @test4va(%struct.test4* noalias sret %[[AGG_RESULT:.*]], i32 signext %x, ...) +// CHECK: define void @test4va(%struct.test4* noalias sret align 4 %[[AGG_RESULT:.*]], i32 signext %x, ...) // CHECK: %[[CUR:[^ ]+]] = load i8*, i8** %ap // CHECK: %[[NEXT:[^ ]+]] = getelementptr inbounds i8, i8* %[[CUR]], i64 16 // CHECK: store i8* %[[NEXT]], i8** %ap @@ -128,7 +128,7 @@ struct test4 test4va (int x, ...) return y; } -// CHECK: define void @testva_longdouble(%struct.test_longdouble* noalias sret %[[AGG_RESULT:.*]], i32 signext %x, ...) +// CHECK: define void @testva_longdouble(%struct.test_longdouble* noalias sret align 16 %[[AGG_RESULT:.*]], i32 signext %x, ...) // CHECK: %[[CUR:[^ ]+]] = load i8*, i8** %ap // CHECK: %[[NEXT:[^ ]+]] = getelementptr inbounds i8, i8* %[[CUR]], i64 16 // CHECK: store i8* %[[NEXT]], i8** %ap @@ -147,7 +147,7 @@ struct test_longdouble testva_longdouble (int x, ...) return y; } -// CHECK: define void @testva_vector(%struct.test_vector* noalias sret %[[AGG_RESULT:.*]], i32 signext %x, ...) +// CHECK: define void @testva_vector(%struct.test_vector* noalias sret align 16 %[[AGG_RESULT:.*]], i32 signext %x, ...) // CHECK: %[[CUR:[^ ]+]] = load i8*, i8** %ap // CHECK: %[[TMP0:[^ ]+]] = ptrtoint i8* %[[CUR]] to i64 // CHECK: %[[TMP1:[^ ]+]] = add i64 %[[TMP0]], 15 diff --git a/clang/test/CodeGen/ppc64-elf-abi.c b/clang/test/CodeGen/ppc64-elf-abi.c index 59112a0baf4a7..4270ba2c799b8 100644 --- a/clang/test/CodeGen/ppc64-elf-abi.c +++ b/clang/test/CodeGen/ppc64-elf-abi.c @@ -17,7 +17,7 @@ // RUN: %clang_cc1 -triple powerpc64le-unknown-linux-gnu -emit-llvm -o - %s \ // RUN: -target-abi elfv2 | FileCheck %s --check-prefix=CHECK-ELFv2 -// CHECK-ELFv1: define void @func_fab(%struct.fab* noalias sret %agg.result, i64 %x.coerce) +// CHECK-ELFv1: define void @func_fab(%struct.fab* noalias sret align 4 %agg.result, i64 %x.coerce) // CHECK-ELFv2: define [2 x float] @func_fab([2 x float] %x.coerce) struct fab { float a; float b; }; struct fab func_fab(struct fab x) { return x; } diff --git a/clang/test/CodeGen/ppc64-qpx-vector.c b/clang/test/CodeGen/ppc64-qpx-vector.c index e7c009328b232..0e55851b9f33e 100644 --- a/clang/test/CodeGen/ppc64-qpx-vector.c +++ b/clang/test/CodeGen/ppc64-qpx-vector.c @@ -24,6 +24,6 @@ v4df foo2(struct sdf a, v4df b, struct sdf2 c) { // QPX-LABEL: define <4 x double> @foo2(<4 x double> inreg %a.coerce, <4 x double> %b, [2 x i256] %c.coerce) // QPX: ret <4 x double> -// NORMAL-LABEL: define void @foo2(<4 x double>* noalias sret %agg.result, [2 x i128] %a.coerce, <4 x double>* %0, [4 x i128] %c.coerce) +// NORMAL-LABEL: define void @foo2(<4 x double>* noalias sret align 32 %agg.result, [2 x i128] %a.coerce, <4 x double>* %0, [4 x i128] %c.coerce) // NORMAL: ret void diff --git a/clang/test/CodeGen/ppc64-soft-float.c b/clang/test/CodeGen/ppc64-soft-float.c index 84ac2d55b636f..b033dea68fe20 100644 --- a/clang/test/CodeGen/ppc64-soft-float.c +++ b/clang/test/CodeGen/ppc64-soft-float.c @@ -30,53 +30,53 @@ struct fabc { float a; float b; float c; }; struct f2a2b { float a[2]; float b[2]; }; // CHECK-LE: define i32 @func_f1(float inreg %x.coerce) -// CHECK-BE: define void @func_f1(%struct.f1* noalias sret %agg.result, float inreg %x.coerce) +// CHECK-BE: define void @func_f1(%struct.f1* noalias sret align 4 %agg.result, float inreg %x.coerce) struct f1 func_f1(struct f1 x) { return x; } // CHECK-LE: define i64 @func_f2(i64 %x.coerce) -// CHECK-BE: define void @func_f2(%struct.f2* noalias sret %agg.result, i64 %x.coerce) +// CHECK-BE: define void @func_f2(%struct.f2* noalias sret align 4 %agg.result, i64 %x.coerce) struct f2 func_f2(struct f2 x) { return x; } // CHECK-LE: define { i64, i64 } @func_f3([2 x i64] %x.coerce) -// CHECK-BE: define void @func_f3(%struct.f3* noalias sret %agg.result, [2 x i64] %x.coerce) +// CHECK-BE: define void @func_f3(%struct.f3* noalias sret align 4 %agg.result, [2 x i64] %x.coerce) struct f3 func_f3(struct f3 x) { return x; } // CHECK-LE: define { i64, i64 } @func_f4([2 x i64] %x.coerce) -// CHECK-BE: define void @func_f4(%struct.f4* noalias sret %agg.result, [2 x i64] %x.coerce) +// CHECK-BE: define void @func_f4(%struct.f4* noalias sret align 4 %agg.result, [2 x i64] %x.coerce) struct f4 func_f4(struct f4 x) { return x; } -// CHECK: define void @func_f5(%struct.f5* noalias sret %agg.result, [3 x i64] %x.coerce) +// CHECK: define void @func_f5(%struct.f5* noalias sret align 4 %agg.result, [3 x i64] %x.coerce) struct f5 func_f5(struct f5 x) { return x; } -// CHECK: define void @func_f6(%struct.f6* noalias sret %agg.result, [3 x i64] %x.coerce) +// CHECK: define void @func_f6(%struct.f6* noalias sret align 4 %agg.result, [3 x i64] %x.coerce) struct f6 func_f6(struct f6 x) { return x; } -// CHECK: define void @func_f7(%struct.f7* noalias sret %agg.result, [4 x i64] %x.coerce) +// CHECK: define void @func_f7(%struct.f7* noalias sret align 4 %agg.result, [4 x i64] %x.coerce) struct f7 func_f7(struct f7 x) { return x; } -// CHECK: define void @func_f8(%struct.f8* noalias sret %agg.result, [4 x i64] %x.coerce) +// CHECK: define void @func_f8(%struct.f8* noalias sret align 4 %agg.result, [4 x i64] %x.coerce) struct f8 func_f8(struct f8 x) { return x; } -// CHECK: define void @func_f9(%struct.f9* noalias sret %agg.result, [5 x i64] %x.coerce) +// CHECK: define void @func_f9(%struct.f9* noalias sret align 4 %agg.result, [5 x i64] %x.coerce) struct f9 func_f9(struct f9 x) { return x; } // CHECK-LE: define i64 @func_fab(i64 %x.coerce) -// CHECK-BE: define void @func_fab(%struct.fab* noalias sret %agg.result, i64 %x.coerce) +// CHECK-BE: define void @func_fab(%struct.fab* noalias sret align 4 %agg.result, i64 %x.coerce) struct fab func_fab(struct fab x) { return x; } // CHECK-LE: define { i64, i64 } @func_fabc([2 x i64] %x.coerce) -// CHECK-BE: define void @func_fabc(%struct.fabc* noalias sret %agg.result, [2 x i64] %x.coerce) +// CHECK-BE: define void @func_fabc(%struct.fabc* noalias sret align 4 %agg.result, [2 x i64] %x.coerce) struct fabc func_fabc(struct fabc x) { return x; } // CHECK-LE: define { i64, i64 } @func_f2a2b([2 x i64] %x.coerce) -// CHECK-BE: define void @func_f2a2b(%struct.f2a2b* noalias sret %agg.result, [2 x i64] %x.coerce) +// CHECK-BE: define void @func_f2a2b(%struct.f2a2b* noalias sret align 4 %agg.result, [2 x i64] %x.coerce) struct f2a2b func_f2a2b(struct f2a2b x) { return x; } // CHECK-LABEL: @call_f1 // CHECK-BE: %[[TMP0:[^ ]+]] = alloca %struct.f1, align 4 // CHECK: %[[TMP:[^ ]+]] = load float, float* getelementptr inbounds (%struct.f1, %struct.f1* @global_f1, i32 0, i32 0, i32 0), align 4 // CHECK-LE: call i32 @func_f1(float inreg %[[TMP]]) -// CHECK-BE: call void @func_f1(%struct.f1* sret %[[TMP0]], float inreg %[[TMP]]) +// CHECK-BE: call void @func_f1(%struct.f1* sret align 4 %[[TMP0]], float inreg %[[TMP]]) struct f1 global_f1; void call_f1(void) { global_f1 = func_f1(global_f1); } @@ -84,7 +84,7 @@ void call_f1(void) { global_f1 = func_f1(global_f1); } // CHECK-BE: %[[TMP0:[^ ]+]] = alloca %struct.f2, align 4 // CHECK: %[[TMP:[^ ]+]] = load i64, i64* bitcast (%struct.f2* @global_f2 to i64*), align 4 // CHECK-LE: call i64 @func_f2(i64 %[[TMP]]) -// CHECK-BE: call void @func_f2(%struct.f2* sret %[[TMP0]], i64 %[[TMP]]) +// CHECK-BE: call void @func_f2(%struct.f2* sret align 4 %[[TMP0]], i64 %[[TMP]]) struct f2 global_f2; void call_f2(void) { global_f2 = func_f2(global_f2); } @@ -95,7 +95,7 @@ void call_f2(void) { global_f2 = func_f2(global_f2); } // CHECK: call void @llvm.memcpy.p0i8.p0i8.i64(i8* align 8 %[[TMP2]], i8* align 4 bitcast (%struct.f3* @global_f3 to i8*), i64 12, i1 false) // CHECK: %[[TMP3:[^ ]+]] = load [2 x i64], [2 x i64]* %[[TMP1]] // CHECK-LE: call { i64, i64 } @func_f3([2 x i64] %[[TMP3]]) -// CHECK-BE: call void @func_f3(%struct.f3* sret %[[TMP0]], [2 x i64] %[[TMP3]]) +// CHECK-BE: call void @func_f3(%struct.f3* sret align 4 %[[TMP0]], [2 x i64] %[[TMP3]]) struct f3 global_f3; void call_f3(void) { global_f3 = func_f3(global_f3); } @@ -103,7 +103,7 @@ void call_f3(void) { global_f3 = func_f3(global_f3); } // CHECK-BE: %[[TMP0:[^ ]+]] = alloca %struct.f4, align 4 // CHECK: %[[TMP:[^ ]+]] = load [2 x i64], [2 x i64]* bitcast (%struct.f4* @global_f4 to [2 x i64]*), align 4 // CHECK-LE: call { i64, i64 } @func_f4([2 x i64] %[[TMP]]) -// CHECK-BE: call void @func_f4(%struct.f4* sret %[[TMP0]], [2 x i64] %[[TMP]]) +// CHECK-BE: call void @func_f4(%struct.f4* sret align 4 %[[TMP0]], [2 x i64] %[[TMP]]) struct f4 global_f4; void call_f4(void) { global_f4 = func_f4(global_f4); } @@ -113,14 +113,14 @@ void call_f4(void) { global_f4 = func_f4(global_f4); } // CHECK: %[[TMP2:[^ ]+]] = bitcast [3 x i64]* %[[TMP1]] to i8* // CHECK: call void @llvm.memcpy.p0i8.p0i8.i64(i8* align 8 %[[TMP2]], i8* align 4 bitcast (%struct.f5* @global_f5 to i8*), i64 20, i1 false) // CHECK: %[[TMP3:[^ ]+]] = load [3 x i64], [3 x i64]* %[[TMP1]] -// CHECK: call void @func_f5(%struct.f5* sret %[[TMP0]], [3 x i64] %[[TMP3]]) +// CHECK: call void @func_f5(%struct.f5* sret align 4 %[[TMP0]], [3 x i64] %[[TMP3]]) struct f5 global_f5; void call_f5(void) { global_f5 = func_f5(global_f5); } // CHECK-LABEL: @call_f6 // CHECK: %[[TMP0:[^ ]+]] = alloca %struct.f6, align 4 // CHECK: %[[TMP:[^ ]+]] = load [3 x i64], [3 x i64]* bitcast (%struct.f6* @global_f6 to [3 x i64]*), align 4 -// CHECK: call void @func_f6(%struct.f6* sret %[[TMP0]], [3 x i64] %[[TMP]]) +// CHECK: call void @func_f6(%struct.f6* sret align 4 %[[TMP0]], [3 x i64] %[[TMP]]) struct f6 global_f6; void call_f6(void) { global_f6 = func_f6(global_f6); } @@ -130,14 +130,14 @@ void call_f6(void) { global_f6 = func_f6(global_f6); } // CHECK: %[[TMP2:[^ ]+]] = bitcast [4 x i64]* %[[TMP1]] to i8* // CHECK: call void @llvm.memcpy.p0i8.p0i8.i64(i8* align 8 %[[TMP2]], i8* align 4 bitcast (%struct.f7* @global_f7 to i8*), i64 28, i1 false) // CHECK: %[[TMP3:[^ ]+]] = load [4 x i64], [4 x i64]* %[[TMP1]], align 8 -// CHECK: call void @func_f7(%struct.f7* sret %[[TMP0]], [4 x i64] %[[TMP3]]) +// CHECK: call void @func_f7(%struct.f7* sret align 4 %[[TMP0]], [4 x i64] %[[TMP3]]) struct f7 global_f7; void call_f7(void) { global_f7 = func_f7(global_f7); } // CHECK-LABEL: @call_f8 // CHECK: %[[TMP0:[^ ]+]] = alloca %struct.f8, align 4 // CHECK: %[[TMP:[^ ]+]] = load [4 x i64], [4 x i64]* bitcast (%struct.f8* @global_f8 to [4 x i64]*), align 4 -// CHECK: call void @func_f8(%struct.f8* sret %[[TMP0]], [4 x i64] %[[TMP]]) +// CHECK: call void @func_f8(%struct.f8* sret align 4 %[[TMP0]], [4 x i64] %[[TMP]]) struct f8 global_f8; void call_f8(void) { global_f8 = func_f8(global_f8); } @@ -146,7 +146,7 @@ void call_f8(void) { global_f8 = func_f8(global_f8); } // CHECK: %[[TMP2:[^ ]+]] = bitcast [5 x i64]* %[[TMP1]] to i8* // CHECK: call void @llvm.memcpy.p0i8.p0i8.i64(i8* align 8 %[[TMP2]], i8* align 4 bitcast (%struct.f9* @global_f9 to i8*), i64 36, i1 false) // CHECK: %[[TMP3:[^ ]+]] = load [5 x i64], [5 x i64]* %[[TMP1]] -// CHECK: call void @func_f9(%struct.f9* sret %{{[^ ]+}}, [5 x i64] %[[TMP3]]) +// CHECK: call void @func_f9(%struct.f9* sret align 4 %{{[^ ]+}}, [5 x i64] %[[TMP3]]) struct f9 global_f9; void call_f9(void) { global_f9 = func_f9(global_f9); } @@ -154,7 +154,7 @@ void call_f9(void) { global_f9 = func_f9(global_f9); } // CHECK: %[[TMP0:[^ ]+]] = alloca %struct.fab, align 4 // CHECK: %[[TMP:[^ ]+]] = load i64, i64* bitcast (%struct.fab* @global_fab to i64*), align 4 // CHECK-LE: %call = call i64 @func_fab(i64 %[[TMP]]) -// CHECK-BE: call void @func_fab(%struct.fab* sret %[[TMP0]], i64 %[[TMP]]) +// CHECK-BE: call void @func_fab(%struct.fab* sret align 4 %[[TMP0]], i64 %[[TMP]]) struct fab global_fab; void call_fab(void) { global_fab = func_fab(global_fab); } @@ -165,7 +165,7 @@ void call_fab(void) { global_fab = func_fab(global_fab); } // CHECK: call void @llvm.memcpy.p0i8.p0i8.i64(i8* align 8 %[[TMP2]], i8* align 4 bitcast (%struct.fabc* @global_fabc to i8*), i64 12, i1 false) // CHECK: %[[TMP3:[^ ]+]] = load [2 x i64], [2 x i64]* %[[TMP0]], align 8 // CHECK-LE: %call = call { i64, i64 } @func_fabc([2 x i64] %[[TMP3]]) -// CHECK-BE: call void @func_fabc(%struct.fabc* sret %[[TMPX]], [2 x i64] %[[TMP3]]) +// CHECK-BE: call void @func_fabc(%struct.fabc* sret align 4 %[[TMPX]], [2 x i64] %[[TMP3]]) struct fabc global_fabc; void call_fabc(void) { global_fabc = func_fabc(global_fabc); } diff --git a/clang/test/CodeGen/ppc64-vector.c b/clang/test/CodeGen/ppc64-vector.c index 7ed0beade4cd0..7ea5b007d5bfc 100644 --- a/clang/test/CodeGen/ppc64-vector.c +++ b/clang/test/CodeGen/ppc64-vector.c @@ -39,13 +39,13 @@ v8i16 test_v8i16(v8i16 x) return x; } -// CHECK: define void @test_v16i16(<16 x i16>* noalias sret %agg.result, <16 x i16>* %0) +// CHECK: define void @test_v16i16(<16 x i16>* noalias sret align 32 %agg.result, <16 x i16>* %0) v16i16 test_v16i16(v16i16 x) { return x; } -// CHECK: define void @test_struct_v16i16(%struct.v16i16* noalias sret %agg.result, [2 x i128] %x.coerce) +// CHECK: define void @test_struct_v16i16(%struct.v16i16* noalias sret align 32 %agg.result, [2 x i128] %x.coerce) struct v16i16 test_struct_v16i16(struct v16i16 x) { return x; diff --git a/clang/test/CodeGen/ppc64le-aggregates.c b/clang/test/CodeGen/ppc64le-aggregates.c index e36faa2b80258..ea32d69b7cf95 100644 --- a/clang/test/CodeGen/ppc64le-aggregates.c +++ b/clang/test/CodeGen/ppc64le-aggregates.c @@ -41,7 +41,7 @@ struct f7 func_f7(struct f7 x) { return x; } // CHECK: define [8 x float] @func_f8([8 x float] %x.coerce) struct f8 func_f8(struct f8 x) { return x; } -// CHECK: define void @func_f9(%struct.f9* noalias sret %agg.result, [5 x i64] %x.coerce) +// CHECK: define void @func_f9(%struct.f9* noalias sret align 4 %agg.result, [5 x i64] %x.coerce) struct f9 func_f9(struct f9 x) { return x; } // CHECK: define [2 x float] @func_fab([2 x float] %x.coerce) @@ -106,7 +106,7 @@ void call_f8(void) { global_f8 = func_f8(global_f8); } // CHECK: %[[TMP2:[^ ]+]] = bitcast [5 x i64]* %[[TMP1]] to i8* // CHECK: call void @llvm.memcpy.p0i8.p0i8.i64(i8* align 8 %[[TMP2]], i8* align 4 bitcast (%struct.f9* @global_f9 to i8*), i64 36, i1 false) // CHECK: %[[TMP3:[^ ]+]] = load [5 x i64], [5 x i64]* %[[TMP1]] -// CHECK: call void @func_f9(%struct.f9* sret %{{[^ ]+}}, [5 x i64] %[[TMP3]]) +// CHECK: call void @func_f9(%struct.f9* sret align 4 %{{[^ ]+}}, [5 x i64] %[[TMP3]]) struct f9 global_f9; void call_f9(void) { global_f9 = func_f9(global_f9); } @@ -162,7 +162,7 @@ struct v7 func_v7(struct v7 x) { return x; } // CHECK: define [8 x <4 x i32>] @func_v8([8 x <4 x i32>] %x.coerce) struct v8 func_v8(struct v8 x) { return x; } -// CHECK: define void @func_v9(%struct.v9* noalias sret %agg.result, %struct.v9* byval(%struct.v9) align 16 %x) +// CHECK: define void @func_v9(%struct.v9* noalias sret align 16 %agg.result, %struct.v9* byval(%struct.v9) align 16 %x) struct v9 func_v9(struct v9 x) { return x; } // CHECK: define [2 x <4 x i32>] @func_vab([2 x <4 x i32>] %x.coerce) @@ -220,7 +220,7 @@ struct v8 global_v8; void call_v8(void) { global_v8 = func_v8(global_v8); } // CHECK-LABEL: @call_v9 -// CHECK: call void @func_v9(%struct.v9* sret %{{[^ ]+}}, %struct.v9* byval(%struct.v9) align 16 @global_v9) +// CHECK: call void @func_v9(%struct.v9* sret align 16 %{{[^ ]+}}, %struct.v9* byval(%struct.v9) align 16 @global_v9) struct v9 global_v9; void call_v9(void) { global_v9 = func_v9(global_v9); } @@ -279,7 +279,7 @@ struct v3f7 func_v3f7(struct v3f7 x) { return x; } // CHECK: define [8 x <4 x float>] @func_v3f8([8 x <4 x float>] %x.coerce) struct v3f8 func_v3f8(struct v3f8 x) { return x; } -// CHECK: define void @func_v3f9(%struct.v3f9* noalias sret %agg.result, %struct.v3f9* byval(%struct.v3f9) align 16 %x) +// CHECK: define void @func_v3f9(%struct.v3f9* noalias sret align 16 %agg.result, %struct.v3f9* byval(%struct.v3f9) align 16 %x) struct v3f9 func_v3f9(struct v3f9 x) { return x; } // CHECK: define [2 x <4 x float>] @func_v3fab([2 x <4 x float>] %x.coerce) @@ -337,7 +337,7 @@ struct v3f8 global_v3f8; void call_v3f8(void) { global_v3f8 = func_v3f8(global_v3f8); } // CHECK-LABEL: @call_v3f9 -// CHECK: call void @func_v3f9(%struct.v3f9* sret %{{[^ ]+}}, %struct.v3f9* byval(%struct.v3f9) align 16 @global_v3f9) +// CHECK: call void @func_v3f9(%struct.v3f9* sret align 16 %{{[^ ]+}}, %struct.v3f9* byval(%struct.v3f9) align 16 @global_v3f9) struct v3f9 global_v3f9; void call_v3f9(void) { global_v3f9 = func_v3f9(global_v3f9); } diff --git a/clang/test/CodeGen/ppc64le-f128Aggregates.c b/clang/test/CodeGen/ppc64le-f128Aggregates.c index 3b363bf0f2eac..acebea69b31dc 100644 --- a/clang/test/CodeGen/ppc64le-f128Aggregates.c +++ b/clang/test/CodeGen/ppc64le-f128Aggregates.c @@ -42,7 +42,7 @@ struct fp7 func_f7(struct fp7 x) { return x; } // CHECK: define [8 x fp128] @func_f8([8 x fp128] %x.coerce) struct fp8 func_f8(struct fp8 x) { return x; } -// CHECK: define void @func_f9(%struct.fp9* noalias sret %agg.result, %struct.fp9* byval(%struct.fp9) align 16 %x) +// CHECK: define void @func_f9(%struct.fp9* noalias sret align 16 %agg.result, %struct.fp9* byval(%struct.fp9) align 16 %x) struct fp9 func_f9(struct fp9 x) { return x; } // CHECK: define [2 x fp128] @func_fab([2 x fp128] %x.coerce) @@ -104,7 +104,7 @@ void call_fp8(void) { global_f8 = func_f8(global_f8); } // CHECK-LABEL: @call_fp9 // CHECK: %[[TMP1:[^ ]+]] = alloca %struct.fp9, align 16 -// CHECK: call void @func_f9(%struct.fp9* sret %[[TMP2:[^ ]+]], %struct.fp9* byval(%struct.fp9) align 16 @global_f9 +// CHECK: call void @func_f9(%struct.fp9* sret align 16 %[[TMP2:[^ ]+]], %struct.fp9* byval(%struct.fp9) align 16 @global_f9 // CHECK: %[[TMP3:[^ ]+]] = bitcast %struct.fp9* %[[TMP2]] to i8* // CHECK: call void @llvm.memcpy.p0i8.p0i8.i64(i8* align 16 bitcast (%struct.fp9* @global_f9 to i8*), i8* align 16 %[[TMP3]], i64 144, i1 false // CHECK: ret void diff --git a/clang/test/CodeGen/ptrauth-in-c-struct.c b/clang/test/CodeGen/ptrauth-in-c-struct.c index a6fd4ba2bd7c9..1b914d29b662d 100644 --- a/clang/test/CodeGen/ptrauth-in-c-struct.c +++ b/clang/test/CodeGen/ptrauth-in-c-struct.c @@ -132,7 +132,7 @@ void test_argument_SA(SA *a) { calleeSA(*a); } -// CHECK: define void @test_return_SA(%[[STRUCT_SA]]* noalias sret %[[AGG_RESULT:.*]], %[[STRUCT_SA]]* %[[A:.*]]) +// CHECK: define void @test_return_SA(%[[STRUCT_SA]]* noalias sret align 8 %[[AGG_RESULT:.*]], %[[STRUCT_SA]]* %[[A:.*]]) // CHECK: %[[A_ADDR:.*]] = alloca %[[STRUCT_SA]]*, align 8 // CHECK: store %[[STRUCT_SA]]* %[[A]], %[[STRUCT_SA]]** %[[A_ADDR]], align 8 // CHECK: %[[V0:.*]] = load %[[STRUCT_SA]]*, %[[STRUCT_SA]]** %[[A_ADDR]], align 8 diff --git a/clang/test/CodeGen/regparm-struct.c b/clang/test/CodeGen/regparm-struct.c index 7f56ae094a69c..8c74c8b1f0586 100644 --- a/clang/test/CodeGen/regparm-struct.c +++ b/clang/test/CodeGen/regparm-struct.c @@ -159,7 +159,7 @@ void g16(void) { } __attribute__((regparm(3))) struct s12 f17(int a, int b, int c); -// CHECK: declare void @f17(%struct.s12* inreg sret, i32 inreg, i32 inreg, i32) +// CHECK: declare void @f17(%struct.s12* inreg sret align 4, i32 inreg, i32 inreg, i32) void g17(void) { f17(41, 42, 43); } diff --git a/clang/test/CodeGen/renderscript.c b/clang/test/CodeGen/renderscript.c index a85dc35c61496..fee97a154344e 100644 --- a/clang/test/CodeGen/renderscript.c +++ b/clang/test/CodeGen/renderscript.c @@ -83,15 +83,15 @@ void argLongInt(sLongInt s) {} // and coerced to [a x iNN] for 64-bit RenderScript // ============================================================================= -// CHECK-RS32: void @retShortCharShort(%struct.sShortCharShort* noalias sret %agg.result) +// CHECK-RS32: void @retShortCharShort(%struct.sShortCharShort* noalias sret align 2 %agg.result) // CHECK-RS64: [3 x i16] @retShortCharShort() sShortCharShort retShortCharShort() { sShortCharShort r; return r; } -// CHECK-RS32: void @retIntShortChar(%struct.sIntShortChar* noalias sret %agg.result) +// CHECK-RS32: void @retIntShortChar(%struct.sIntShortChar* noalias sret align 4 %agg.result) // CHECK-RS64: [2 x i32] @retIntShortChar() sIntShortChar retIntShortChar() { sIntShortChar r; return r; } -// CHECK-RS32: void @retLongInt(%struct.sLongInt* noalias sret %agg.result) +// CHECK-RS32: void @retLongInt(%struct.sLongInt* noalias sret align 8 %agg.result) // CHECK-RS64: [2 x i64] @retLongInt() sLongInt retLongInt() { sLongInt r; return r; } @@ -116,12 +116,12 @@ void argLong2Char(sLong2Char s) {} // 64-bit RenderScript // ============================================================================= -// CHECK-RS32: void @retInt5(%struct.sInt5* noalias sret %agg.result) -// CHECK-RS64: void @retInt5(%struct.sInt5* noalias sret %agg.result) +// CHECK-RS32: void @retInt5(%struct.sInt5* noalias sret align 4 %agg.result) +// CHECK-RS64: void @retInt5(%struct.sInt5* noalias sret align 4 %agg.result) sInt5 retInt5() { sInt5 r; return r;} -// CHECK-RS32: void @retLong2Char(%struct.sLong2Char* noalias sret %agg.result) -// CHECK-RS64: void @retLong2Char(%struct.sLong2Char* noalias sret %agg.result) +// CHECK-RS32: void @retLong2Char(%struct.sLong2Char* noalias sret align 8 %agg.result) +// CHECK-RS64: void @retLong2Char(%struct.sLong2Char* noalias sret align 8 %agg.result) sLong2Char retLong2Char() { sLong2Char r; return r;} // ============================================================================= @@ -135,6 +135,6 @@ typedef struct {long l1, l2, l3, l4, l5, l6, l7, l8, l9; } sLong9; // CHECK-RS64: void @argLong9(%struct.sLong9* %s) void argLong9(sLong9 s) {} -// CHECK-RS32: void @retLong9(%struct.sLong9* noalias sret %agg.result) -// CHECK-RS64: void @retLong9(%struct.sLong9* noalias sret %agg.result) +// CHECK-RS32: void @retLong9(%struct.sLong9* noalias sret align 8 %agg.result) +// CHECK-RS64: void @retLong9(%struct.sLong9* noalias sret align 8 %agg.result) sLong9 retLong9() { sLong9 r; return r; } diff --git a/clang/test/CodeGen/riscv32-ilp32-abi.c b/clang/test/CodeGen/riscv32-ilp32-abi.c index 59f0bb5683726..1b32024f51582 100644 --- a/clang/test/CodeGen/riscv32-ilp32-abi.c +++ b/clang/test/CodeGen/riscv32-ilp32-abi.c @@ -35,7 +35,7 @@ int f_scalar_stack_1(int32_t a, int64_t b, float c, double d, long double e, // the presence of large return values that consume a register due to the need // to pass a pointer. -// CHECK-LABEL: define void @f_scalar_stack_2(%struct.large* noalias sret %agg.result, float %a, i64 %b, double %c, fp128 %d, i8 zeroext %e, i8 %f, i8 %g) +// CHECK-LABEL: define void @f_scalar_stack_2(%struct.large* noalias sret align 4 %agg.result, float %a, i64 %b, double %c, fp128 %d, i8 zeroext %e, i8 %f, i8 %g) struct large f_scalar_stack_2(float a, int64_t b, double c, long double d, uint8_t e, int8_t f, uint8_t g) { return (struct large){a, e, f, g}; diff --git a/clang/test/CodeGen/riscv32-ilp32-ilp32f-abi.c b/clang/test/CodeGen/riscv32-ilp32-ilp32f-abi.c index 677040626f578..225b12358a0e3 100644 --- a/clang/test/CodeGen/riscv32-ilp32-ilp32f-abi.c +++ b/clang/test/CodeGen/riscv32-ilp32-ilp32f-abi.c @@ -37,7 +37,7 @@ int f_scalar_stack_1(int32_t a, int64_t b, int32_t c, double d, long double e, // the presence of large return values that consume a register due to the need // to pass a pointer. -// CHECK-LABEL: define void @f_scalar_stack_2(%struct.large* noalias sret %agg.result, i32 %a, i64 %b, double %c, fp128 %d, i8 zeroext %e, i8 %f, i8 %g) +// CHECK-LABEL: define void @f_scalar_stack_2(%struct.large* noalias sret align 4 %agg.result, i32 %a, i64 %b, double %c, fp128 %d, i8 zeroext %e, i8 %f, i8 %g) struct large f_scalar_stack_2(int32_t a, int64_t b, double c, long double d, uint8_t e, int8_t f, uint8_t g) { return (struct large){a, e, f, g}; diff --git a/clang/test/CodeGen/riscv32-ilp32-ilp32f-ilp32d-abi.c b/clang/test/CodeGen/riscv32-ilp32-ilp32f-ilp32d-abi.c index 86ad8fd370bca..740079d28d3be 100644 --- a/clang/test/CodeGen/riscv32-ilp32-ilp32f-ilp32d-abi.c +++ b/clang/test/CodeGen/riscv32-ilp32-ilp32f-ilp32d-abi.c @@ -177,7 +177,7 @@ void f_agg_large(struct large x) { // The address where the struct should be written to will be the first // argument -// CHECK-LABEL: define void @f_agg_large_ret(%struct.large* noalias sret %agg.result, i32 %i, i8 signext %j) +// CHECK-LABEL: define void @f_agg_large_ret(%struct.large* noalias sret align 4 %agg.result, i32 %i, i8 signext %j) struct large f_agg_large_ret(int32_t i, int8_t j) { return (struct large){1, 2, 3, 4}; } @@ -189,7 +189,7 @@ void f_vec_large_v16i8(v16i8 x) { x[0] = x[7]; } -// CHECK-LABEL: define void @f_vec_large_v16i8_ret(<16 x i8>* noalias sret %agg.result) +// CHECK-LABEL: define void @f_vec_large_v16i8_ret(<16 x i8>* noalias sret align 16 %agg.result) v16i8 f_vec_large_v16i8_ret() { return (v16i8){1, 2, 3, 4, 5, 6, 7, 8}; } @@ -207,7 +207,7 @@ int f_scalar_stack_1(struct tiny a, struct small b, struct small_aligned c, // the presence of large return values that consume a register due to the need // to pass a pointer. -// CHECK-LABEL: define void @f_scalar_stack_2(%struct.large* noalias sret %agg.result, i32 %a, i64 %b, i64 %c, fp128 %d, i8 zeroext %e, i8 %f, i8 %g) +// CHECK-LABEL: define void @f_scalar_stack_2(%struct.large* noalias sret align 4 %agg.result, i32 %a, i64 %b, i64 %c, fp128 %d, i8 zeroext %e, i8 %f, i8 %g) struct large f_scalar_stack_2(int32_t a, int64_t b, int64_t c, long double d, uint8_t e, int8_t f, uint8_t g) { return (struct large){a, e, f, g}; diff --git a/clang/test/CodeGen/riscv32-ilp32d-abi.c b/clang/test/CodeGen/riscv32-ilp32d-abi.c index 078fcb6b5ab11..bc4a1b58aaf83 100644 --- a/clang/test/CodeGen/riscv32-ilp32d-abi.c +++ b/clang/test/CodeGen/riscv32-ilp32d-abi.c @@ -119,7 +119,7 @@ struct double_int32_s f_ret_double_int32_s() { // CHECK: define void @f_double_int64_s_arg(%struct.double_int64_s* %a) void f_double_int64_s_arg(struct double_int64_s a) {} -// CHECK: define void @f_ret_double_int64_s(%struct.double_int64_s* noalias sret %agg.result) +// CHECK: define void @f_ret_double_int64_s(%struct.double_int64_s* noalias sret align 8 %agg.result) struct double_int64_s f_ret_double_int64_s() { return (struct double_int64_s){1.0, 2}; } @@ -243,7 +243,7 @@ struct int_double_int_s { int a; double b; int c; }; // CHECK: define void @f_int_double_int_s_arg(%struct.int_double_int_s* %a) void f_int_double_int_s_arg(struct int_double_int_s a) {} -// CHECK: define void @f_ret_int_double_int_s(%struct.int_double_int_s* noalias sret %agg.result) +// CHECK: define void @f_ret_int_double_int_s(%struct.int_double_int_s* noalias sret align 8 %agg.result) struct int_double_int_s f_ret_int_double_int_s() { return (struct int_double_int_s){1, 2.0, 3}; } @@ -253,7 +253,7 @@ struct int64_double_s { int64_t a; double b; }; // CHECK: define void @f_int64_double_s_arg(%struct.int64_double_s* %a) void f_int64_double_s_arg(struct int64_double_s a) {} -// CHECK: define void @f_ret_int64_double_s(%struct.int64_double_s* noalias sret %agg.result) +// CHECK: define void @f_ret_int64_double_s(%struct.int64_double_s* noalias sret align 8 %agg.result) struct int64_double_s f_ret_int64_double_s() { return (struct int64_double_s){1, 2.0}; } @@ -263,7 +263,7 @@ struct char_char_double_s { char a; char b; double c; }; // CHECK-LABEL: define void @f_char_char_double_s_arg(%struct.char_char_double_s* %a) void f_char_char_double_s_arg(struct char_char_double_s a) {} -// CHECK: define void @f_ret_char_char_double_s(%struct.char_char_double_s* noalias sret %agg.result) +// CHECK: define void @f_ret_char_char_double_s(%struct.char_char_double_s* noalias sret align 8 %agg.result) struct char_char_double_s f_ret_char_char_double_s() { return (struct char_char_double_s){1, 2, 3.0}; } diff --git a/clang/test/CodeGen/riscv32-ilp32f-abi.c b/clang/test/CodeGen/riscv32-ilp32f-abi.c index 76092958aeddf..c8e6418b9daae 100644 --- a/clang/test/CodeGen/riscv32-ilp32f-abi.c +++ b/clang/test/CodeGen/riscv32-ilp32f-abi.c @@ -26,7 +26,7 @@ struct double_double_s { double d; double e; }; // CHECK: define void @f_double_double_s_arg(%struct.double_double_s* %a) void f_double_double_s_arg(struct double_double_s a) {} -// CHECK: define void @f_ret_double_double_s(%struct.double_double_s* noalias sret %agg.result) +// CHECK: define void @f_ret_double_double_s(%struct.double_double_s* noalias sret align 8 %agg.result) struct double_double_s f_ret_double_double_s() { return (struct double_double_s){1.0, 2.0}; } @@ -38,7 +38,7 @@ struct int_double_s { int a; double b; }; // CHECK: define void @f_int_double_s_arg(%struct.int_double_s* %a) void f_int_double_s_arg(struct int_double_s a) {} -// CHECK: define void @f_ret_int_double_s(%struct.int_double_s* noalias sret %agg.result) +// CHECK: define void @f_ret_int_double_s(%struct.int_double_s* noalias sret align 8 %agg.result) struct int_double_s f_ret_int_double_s() { return (struct int_double_s){1, 2.0}; } diff --git a/clang/test/CodeGen/riscv32-ilp32f-ilp32d-abi.c b/clang/test/CodeGen/riscv32-ilp32f-ilp32d-abi.c index e9705ca3d62b3..419bd87fdecfa 100644 --- a/clang/test/CodeGen/riscv32-ilp32f-ilp32d-abi.c +++ b/clang/test/CodeGen/riscv32-ilp32f-ilp32d-abi.c @@ -112,7 +112,7 @@ struct float_int32_s f_ret_float_int32_s() { // CHECK: define void @f_float_int64_s_arg(%struct.float_int64_s* %a) void f_float_int64_s_arg(struct float_int64_s a) {} -// CHECK: define void @f_ret_float_int64_s(%struct.float_int64_s* noalias sret %agg.result) +// CHECK: define void @f_ret_float_int64_s(%struct.float_int64_s* noalias sret align 8 %agg.result) struct float_int64_s f_ret_float_int64_s() { return (struct float_int64_s){1.0, 2}; } @@ -236,7 +236,7 @@ struct int_float_int_s { int a; float b; int c; }; // CHECK: define void @f_int_float_int_s_arg(%struct.int_float_int_s* %a) void f_int_float_int_s_arg(struct int_float_int_s a) {} -// CHECK: define void @f_ret_int_float_int_s(%struct.int_float_int_s* noalias sret %agg.result) +// CHECK: define void @f_ret_int_float_int_s(%struct.int_float_int_s* noalias sret align 4 %agg.result) struct int_float_int_s f_ret_int_float_int_s() { return (struct int_float_int_s){1, 2.0, 3}; } @@ -246,7 +246,7 @@ struct int64_float_s { int64_t a; float b; }; // CHECK: define void @f_int64_float_s_arg(%struct.int64_float_s* %a) void f_int64_float_s_arg(struct int64_float_s a) {} -// CHECK: define void @f_ret_int64_float_s(%struct.int64_float_s* noalias sret %agg.result) +// CHECK: define void @f_ret_int64_float_s(%struct.int64_float_s* noalias sret align 8 %agg.result) struct int64_float_s f_ret_int64_float_s() { return (struct int64_float_s){1, 2.0}; } diff --git a/clang/test/CodeGen/riscv64-lp64-abi.c b/clang/test/CodeGen/riscv64-lp64-abi.c index bae5470c377d9..8347056c54d35 100644 --- a/clang/test/CodeGen/riscv64-lp64-abi.c +++ b/clang/test/CodeGen/riscv64-lp64-abi.c @@ -25,7 +25,7 @@ int f_scalar_stack_1(int32_t a, __int128_t b, float c, long double d, v32i8 e, // the presence of large return values that consume a register due to the need // to pass a pointer. -// CHECK-LABEL: define void @f_scalar_stack_2(%struct.large* noalias sret %agg.result, double %a, i128 %b, fp128 %c, <32 x i8>* %0, i8 zeroext %e, i8 %f, i8 %g) +// CHECK-LABEL: define void @f_scalar_stack_2(%struct.large* noalias sret align 8 %agg.result, double %a, i128 %b, fp128 %c, <32 x i8>* %0, i8 zeroext %e, i8 %f, i8 %g) struct large f_scalar_stack_2(double a, __int128_t b, long double c, v32i8 d, uint8_t e, int8_t f, uint8_t g) { return (struct large){a, e, f, g}; diff --git a/clang/test/CodeGen/riscv64-lp64-lp64f-abi.c b/clang/test/CodeGen/riscv64-lp64-lp64f-abi.c index d9c909e88bd8f..489d0e83dcbc5 100644 --- a/clang/test/CodeGen/riscv64-lp64-lp64f-abi.c +++ b/clang/test/CodeGen/riscv64-lp64-lp64f-abi.c @@ -27,7 +27,7 @@ int f_scalar_stack_1(int32_t a, __int128_t b, double c, long double d, v32i8 e, // the presence of large return values that consume a register due to the need // to pass a pointer. -// CHECK-LABEL: define void @f_scalar_stack_2(%struct.large* noalias sret %agg.result, double %a, i128 %b, fp128 %c, <32 x i8>* %0, i8 zeroext %e, i8 %f, i8 %g) +// CHECK-LABEL: define void @f_scalar_stack_2(%struct.large* noalias sret align 8 %agg.result, double %a, i128 %b, fp128 %c, <32 x i8>* %0, i8 zeroext %e, i8 %f, i8 %g) struct large f_scalar_stack_2(double a, __int128_t b, long double c, v32i8 d, uint8_t e, int8_t f, uint8_t g) { return (struct large){a, e, f, g}; diff --git a/clang/test/CodeGen/riscv64-lp64-lp64f-lp64d-abi.c b/clang/test/CodeGen/riscv64-lp64-lp64f-lp64d-abi.c index f50a8ca905757..8e263aeba25c5 100644 --- a/clang/test/CodeGen/riscv64-lp64-lp64f-lp64d-abi.c +++ b/clang/test/CodeGen/riscv64-lp64-lp64f-lp64d-abi.c @@ -166,7 +166,7 @@ void f_agg_large(struct large x) { // The address where the struct should be written to will be the first // argument -// CHECK-LABEL: define void @f_agg_large_ret(%struct.large* noalias sret %agg.result, i32 signext %i, i8 signext %j) +// CHECK-LABEL: define void @f_agg_large_ret(%struct.large* noalias sret align 8 %agg.result, i32 signext %i, i8 signext %j) struct large f_agg_large_ret(int32_t i, int8_t j) { return (struct large){1, 2, 3, 4}; } @@ -178,7 +178,7 @@ void f_vec_large_v32i8(v32i8 x) { x[0] = x[7]; } -// CHECK-LABEL: define void @f_vec_large_v32i8_ret(<32 x i8>* noalias sret %agg.result) +// CHECK-LABEL: define void @f_vec_large_v32i8_ret(<32 x i8>* noalias sret align 32 %agg.result) v32i8 f_vec_large_v32i8_ret() { return (v32i8){1, 2, 3, 4, 5, 6, 7, 8}; } @@ -202,7 +202,7 @@ int f_scalar_stack_2(int32_t a, __int128_t b, int64_t c, long double d, v32i8 e, // the presence of large return values that consume a register due to the need // to pass a pointer. -// CHECK-LABEL: define void @f_scalar_stack_3(%struct.large* noalias sret %agg.result, i32 signext %a, i128 %b, fp128 %c, <32 x i8>* %0, i8 zeroext %e, i8 %f, i8 %g) +// CHECK-LABEL: define void @f_scalar_stack_3(%struct.large* noalias sret align 8 %agg.result, i32 signext %a, i128 %b, fp128 %c, <32 x i8>* %0, i8 zeroext %e, i8 %f, i8 %g) struct large f_scalar_stack_3(uint32_t a, __int128_t b, long double c, v32i8 d, uint8_t e, int8_t f, uint8_t g) { return (struct large){a, e, f, g}; diff --git a/clang/test/CodeGen/riscv64-lp64d-abi.c b/clang/test/CodeGen/riscv64-lp64d-abi.c index 83947def30851..ec47428e6ccab 100644 --- a/clang/test/CodeGen/riscv64-lp64d-abi.c +++ b/clang/test/CodeGen/riscv64-lp64d-abi.c @@ -243,7 +243,7 @@ struct int_double_int_s { int a; double b; int c; }; // CHECK: define void @f_int_double_int_s_arg(%struct.int_double_int_s* %a) void f_int_double_int_s_arg(struct int_double_int_s a) {} -// CHECK: define void @f_ret_int_double_int_s(%struct.int_double_int_s* noalias sret %agg.result) +// CHECK: define void @f_ret_int_double_int_s(%struct.int_double_int_s* noalias sret align 8 %agg.result) struct int_double_int_s f_ret_int_double_int_s() { return (struct int_double_int_s){1, 2.0, 3}; } diff --git a/clang/test/CodeGen/sparcv9-abi.c b/clang/test/CodeGen/sparcv9-abi.c index 5984fa558c83c..2d97001ab1ae4 100644 --- a/clang/test/CodeGen/sparcv9-abi.c +++ b/clang/test/CodeGen/sparcv9-abi.c @@ -53,7 +53,7 @@ struct large { int x; }; -// CHECK-LABEL: define void @f_large(%struct.large* noalias sret %agg.result, %struct.large* %x) +// CHECK-LABEL: define void @f_large(%struct.large* noalias sret align 8 %agg.result, %struct.large* %x) struct large f_large(struct large x) { x.a += *x.b; x.b = 0; diff --git a/clang/test/CodeGen/struct-passing.c b/clang/test/CodeGen/struct-passing.c index 80847b9fea64f..e3108b964bd26 100644 --- a/clang/test/CodeGen/struct-passing.c +++ b/clang/test/CodeGen/struct-passing.c @@ -18,8 +18,8 @@ void *ps[] = { f0, f1, f2, f3, f4, f5 }; // CHECK: declare i32 @f0() [[RN:#[0-9]+]] // CHECK: declare i32 @f1() [[RO:#[0-9]+]] -// CHECK: declare void @f2({{.*}} sret) -// CHECK: declare void @f3({{.*}} sret) +// CHECK: declare void @f2({{.*}} sret align 4) +// CHECK: declare void @f3({{.*}} sret align 4) // CHECK: declare void @f4({{.*}} byval({{.*}}) align 4) // CHECK: declare void @f5({{.*}} byval({{.*}}) align 4) diff --git a/clang/test/CodeGen/systemz-abi-vector.c b/clang/test/CodeGen/systemz-abi-vector.c index f2e6c13c718f5..896cc0994d6df 100644 --- a/clang/test/CodeGen/systemz-abi-vector.c +++ b/clang/test/CodeGen/systemz-abi-vector.c @@ -50,91 +50,91 @@ unsigned int align = __alignof__ (v16i8); // CHECK-VECTOR: @align = global i32 8 v1i8 pass_v1i8(v1i8 arg) { return arg; } -// CHECK-LABEL: define void @pass_v1i8(<1 x i8>* noalias sret %{{.*}}, <1 x i8>* %0) +// CHECK-LABEL: define void @pass_v1i8(<1 x i8>* noalias sret align 1 %{{.*}}, <1 x i8>* %0) // CHECK-VECTOR-LABEL: define <1 x i8> @pass_v1i8(<1 x i8> %{{.*}}) v2i8 pass_v2i8(v2i8 arg) { return arg; } -// CHECK-LABEL: define void @pass_v2i8(<2 x i8>* noalias sret %{{.*}}, <2 x i8>* %0) +// CHECK-LABEL: define void @pass_v2i8(<2 x i8>* noalias sret align 2 %{{.*}}, <2 x i8>* %0) // CHECK-VECTOR-LABEL: define <2 x i8> @pass_v2i8(<2 x i8> %{{.*}}) v4i8 pass_v4i8(v4i8 arg) { return arg; } -// CHECK-LABEL: define void @pass_v4i8(<4 x i8>* noalias sret %{{.*}}, <4 x i8>* %0) +// CHECK-LABEL: define void @pass_v4i8(<4 x i8>* noalias sret align 4 %{{.*}}, <4 x i8>* %0) // CHECK-VECTOR-LABEL: define <4 x i8> @pass_v4i8(<4 x i8> %{{.*}}) v8i8 pass_v8i8(v8i8 arg) { return arg; } -// CHECK-LABEL: define void @pass_v8i8(<8 x i8>* noalias sret %{{.*}}, <8 x i8>* %0) +// CHECK-LABEL: define void @pass_v8i8(<8 x i8>* noalias sret align 8 %{{.*}}, <8 x i8>* %0) // CHECK-VECTOR-LABEL: define <8 x i8> @pass_v8i8(<8 x i8> %{{.*}}) v16i8 pass_v16i8(v16i8 arg) { return arg; } -// CHECK-LABEL: define void @pass_v16i8(<16 x i8>* noalias sret %{{.*}}, <16 x i8>* %0) +// CHECK-LABEL: define void @pass_v16i8(<16 x i8>* noalias sret align 16 %{{.*}}, <16 x i8>* %0) // CHECK-VECTOR-LABEL: define <16 x i8> @pass_v16i8(<16 x i8> %{{.*}}) v32i8 pass_v32i8(v32i8 arg) { return arg; } -// CHECK-LABEL: define void @pass_v32i8(<32 x i8>* noalias sret %{{.*}}, <32 x i8>* %0) -// CHECK-VECTOR-LABEL: define void @pass_v32i8(<32 x i8>* noalias sret %{{.*}}, <32 x i8>* %0) +// CHECK-LABEL: define void @pass_v32i8(<32 x i8>* noalias sret align 32 %{{.*}}, <32 x i8>* %0) +// CHECK-VECTOR-LABEL: define void @pass_v32i8(<32 x i8>* noalias sret align 8 %{{.*}}, <32 x i8>* %0) v1i16 pass_v1i16(v1i16 arg) { return arg; } -// CHECK-LABEL: define void @pass_v1i16(<1 x i16>* noalias sret %{{.*}}, <1 x i16>* %0) +// CHECK-LABEL: define void @pass_v1i16(<1 x i16>* noalias sret align 2 %{{.*}}, <1 x i16>* %0) // CHECK-VECTOR-LABEL: define <1 x i16> @pass_v1i16(<1 x i16> %{{.*}}) v2i16 pass_v2i16(v2i16 arg) { return arg; } -// CHECK-LABEL: define void @pass_v2i16(<2 x i16>* noalias sret %{{.*}}, <2 x i16>* %0) +// CHECK-LABEL: define void @pass_v2i16(<2 x i16>* noalias sret align 4 %{{.*}}, <2 x i16>* %0) // CHECK-VECTOR-LABEL: define <2 x i16> @pass_v2i16(<2 x i16> %{{.*}}) v4i16 pass_v4i16(v4i16 arg) { return arg; } -// CHECK-LABEL: define void @pass_v4i16(<4 x i16>* noalias sret %{{.*}}, <4 x i16>* %0) +// CHECK-LABEL: define void @pass_v4i16(<4 x i16>* noalias sret align 8 %{{.*}}, <4 x i16>* %0) // CHECK-VECTOR-LABEL: define <4 x i16> @pass_v4i16(<4 x i16> %{{.*}}) v8i16 pass_v8i16(v8i16 arg) { return arg; } -// CHECK-LABEL: define void @pass_v8i16(<8 x i16>* noalias sret %{{.*}}, <8 x i16>* %0) +// CHECK-LABEL: define void @pass_v8i16(<8 x i16>* noalias sret align 16 %{{.*}}, <8 x i16>* %0) // CHECK-VECTOR-LABEL: define <8 x i16> @pass_v8i16(<8 x i16> %{{.*}}) v1i32 pass_v1i32(v1i32 arg) { return arg; } -// CHECK-LABEL: define void @pass_v1i32(<1 x i32>* noalias sret %{{.*}}, <1 x i32>* %0) +// CHECK-LABEL: define void @pass_v1i32(<1 x i32>* noalias sret align 4 %{{.*}}, <1 x i32>* %0) // CHECK-VECTOR-LABEL: define <1 x i32> @pass_v1i32(<1 x i32> %{{.*}}) v2i32 pass_v2i32(v2i32 arg) { return arg; } -// CHECK-LABEL: define void @pass_v2i32(<2 x i32>* noalias sret %{{.*}}, <2 x i32>* %0) +// CHECK-LABEL: define void @pass_v2i32(<2 x i32>* noalias sret align 8 %{{.*}}, <2 x i32>* %0) // CHECK-VECTOR-LABEL: define <2 x i32> @pass_v2i32(<2 x i32> %{{.*}}) v4i32 pass_v4i32(v4i32 arg) { return arg; } -// CHECK-LABEL: define void @pass_v4i32(<4 x i32>* noalias sret %{{.*}}, <4 x i32>* %0) +// CHECK-LABEL: define void @pass_v4i32(<4 x i32>* noalias sret align 16 %{{.*}}, <4 x i32>* %0) // CHECK-VECTOR-LABEL: define <4 x i32> @pass_v4i32(<4 x i32> %{{.*}}) v1i64 pass_v1i64(v1i64 arg) { return arg; } -// CHECK-LABEL: define void @pass_v1i64(<1 x i64>* noalias sret %{{.*}}, <1 x i64>* %0) +// CHECK-LABEL: define void @pass_v1i64(<1 x i64>* noalias sret align 8 %{{.*}}, <1 x i64>* %0) // CHECK-VECTOR-LABEL: define <1 x i64> @pass_v1i64(<1 x i64> %{{.*}}) v2i64 pass_v2i64(v2i64 arg) { return arg; } -// CHECK-LABEL: define void @pass_v2i64(<2 x i64>* noalias sret %{{.*}}, <2 x i64>* %0) +// CHECK-LABEL: define void @pass_v2i64(<2 x i64>* noalias sret align 16 %{{.*}}, <2 x i64>* %0) // CHECK-VECTOR-LABEL: define <2 x i64> @pass_v2i64(<2 x i64> %{{.*}}) v1i128 pass_v1i128(v1i128 arg) { return arg; } -// CHECK-LABEL: define void @pass_v1i128(<1 x i128>* noalias sret %{{.*}}, <1 x i128>* %0) +// CHECK-LABEL: define void @pass_v1i128(<1 x i128>* noalias sret align 16 %{{.*}}, <1 x i128>* %0) // CHECK-VECTOR-LABEL: define <1 x i128> @pass_v1i128(<1 x i128> %{{.*}}) v1f32 pass_v1f32(v1f32 arg) { return arg; } -// CHECK-LABEL: define void @pass_v1f32(<1 x float>* noalias sret %{{.*}}, <1 x float>* %0) +// CHECK-LABEL: define void @pass_v1f32(<1 x float>* noalias sret align 4 %{{.*}}, <1 x float>* %0) // CHECK-VECTOR-LABEL: define <1 x float> @pass_v1f32(<1 x float> %{{.*}}) v2f32 pass_v2f32(v2f32 arg) { return arg; } -// CHECK-LABEL: define void @pass_v2f32(<2 x float>* noalias sret %{{.*}}, <2 x float>* %0) +// CHECK-LABEL: define void @pass_v2f32(<2 x float>* noalias sret align 8 %{{.*}}, <2 x float>* %0) // CHECK-VECTOR-LABEL: define <2 x float> @pass_v2f32(<2 x float> %{{.*}}) v4f32 pass_v4f32(v4f32 arg) { return arg; } -// CHECK-LABEL: define void @pass_v4f32(<4 x float>* noalias sret %{{.*}}, <4 x float>* %0) +// CHECK-LABEL: define void @pass_v4f32(<4 x float>* noalias sret align 16 %{{.*}}, <4 x float>* %0) // CHECK-VECTOR-LABEL: define <4 x float> @pass_v4f32(<4 x float> %{{.*}}) v1f64 pass_v1f64(v1f64 arg) { return arg; } -// CHECK-LABEL: define void @pass_v1f64(<1 x double>* noalias sret %{{.*}}, <1 x double>* %0) +// CHECK-LABEL: define void @pass_v1f64(<1 x double>* noalias sret align 8 %{{.*}}, <1 x double>* %0) // CHECK-VECTOR-LABEL: define <1 x double> @pass_v1f64(<1 x double> %{{.*}}) v2f64 pass_v2f64(v2f64 arg) { return arg; } -// CHECK-LABEL: define void @pass_v2f64(<2 x double>* noalias sret %{{.*}}, <2 x double>* %0) +// CHECK-LABEL: define void @pass_v2f64(<2 x double>* noalias sret align 16 %{{.*}}, <2 x double>* %0) // CHECK-VECTOR-LABEL: define <2 x double> @pass_v2f64(<2 x double> %{{.*}}) v1f128 pass_v1f128(v1f128 arg) { return arg; } -// CHECK-LABEL: define void @pass_v1f128(<1 x fp128>* noalias sret %{{.*}}, <1 x fp128>* %0) +// CHECK-LABEL: define void @pass_v1f128(<1 x fp128>* noalias sret align 16 %{{.*}}, <1 x fp128>* %0) // CHECK-VECTOR-LABEL: define <1 x fp128> @pass_v1f128(<1 x fp128> %{{.*}}) @@ -142,62 +142,62 @@ v1f128 pass_v1f128(v1f128 arg) { return arg; } struct agg_v1i8 { v1i8 a; }; struct agg_v1i8 pass_agg_v1i8(struct agg_v1i8 arg) { return arg; } -// CHECK-LABEL: define void @pass_agg_v1i8(%struct.agg_v1i8* noalias sret %{{.*}}, i8 %{{.*}}) -// CHECK-VECTOR-LABEL: define void @pass_agg_v1i8(%struct.agg_v1i8* noalias sret %{{.*}}, <1 x i8> %{{.*}}) +// CHECK-LABEL: define void @pass_agg_v1i8(%struct.agg_v1i8* noalias sret align 1 %{{.*}}, i8 %{{.*}}) +// CHECK-VECTOR-LABEL: define void @pass_agg_v1i8(%struct.agg_v1i8* noalias sret align 1 %{{.*}}, <1 x i8> %{{.*}}) struct agg_v2i8 { v2i8 a; }; struct agg_v2i8 pass_agg_v2i8(struct agg_v2i8 arg) { return arg; } -// CHECK-LABEL: define void @pass_agg_v2i8(%struct.agg_v2i8* noalias sret %{{.*}}, i16 %{{.*}}) -// CHECK-VECTOR-LABEL: define void @pass_agg_v2i8(%struct.agg_v2i8* noalias sret %{{.*}}, <2 x i8> %{{.*}}) +// CHECK-LABEL: define void @pass_agg_v2i8(%struct.agg_v2i8* noalias sret align 2 %{{.*}}, i16 %{{.*}}) +// CHECK-VECTOR-LABEL: define void @pass_agg_v2i8(%struct.agg_v2i8* noalias sret align 2 %{{.*}}, <2 x i8> %{{.*}}) struct agg_v4i8 { v4i8 a; }; struct agg_v4i8 pass_agg_v4i8(struct agg_v4i8 arg) { return arg; } -// CHECK-LABEL: define void @pass_agg_v4i8(%struct.agg_v4i8* noalias sret %{{.*}}, i32 %{{.*}}) -// CHECK-VECTOR-LABEL: define void @pass_agg_v4i8(%struct.agg_v4i8* noalias sret %{{.*}}, <4 x i8> %{{.*}}) +// CHECK-LABEL: define void @pass_agg_v4i8(%struct.agg_v4i8* noalias sret align 4 %{{.*}}, i32 %{{.*}}) +// CHECK-VECTOR-LABEL: define void @pass_agg_v4i8(%struct.agg_v4i8* noalias sret align 4 %{{.*}}, <4 x i8> %{{.*}}) struct agg_v8i8 { v8i8 a; }; struct agg_v8i8 pass_agg_v8i8(struct agg_v8i8 arg) { return arg; } -// CHECK-LABEL: define void @pass_agg_v8i8(%struct.agg_v8i8* noalias sret %{{.*}}, i64 %{{.*}}) -// CHECK-VECTOR-LABEL: define void @pass_agg_v8i8(%struct.agg_v8i8* noalias sret %{{.*}}, <8 x i8> %{{.*}}) +// CHECK-LABEL: define void @pass_agg_v8i8(%struct.agg_v8i8* noalias sret align 8 %{{.*}}, i64 %{{.*}}) +// CHECK-VECTOR-LABEL: define void @pass_agg_v8i8(%struct.agg_v8i8* noalias sret align 8 %{{.*}}, <8 x i8> %{{.*}}) struct agg_v16i8 { v16i8 a; }; struct agg_v16i8 pass_agg_v16i8(struct agg_v16i8 arg) { return arg; } -// CHECK-LABEL: define void @pass_agg_v16i8(%struct.agg_v16i8* noalias sret %{{.*}}, %struct.agg_v16i8* %{{.*}}) -// CHECK-VECTOR-LABEL: define void @pass_agg_v16i8(%struct.agg_v16i8* noalias sret %{{.*}}, <16 x i8> %{{.*}}) +// CHECK-LABEL: define void @pass_agg_v16i8(%struct.agg_v16i8* noalias sret align 16 %{{.*}}, %struct.agg_v16i8* %{{.*}}) +// CHECK-VECTOR-LABEL: define void @pass_agg_v16i8(%struct.agg_v16i8* noalias sret align 8 %{{.*}}, <16 x i8> %{{.*}}) struct agg_v32i8 { v32i8 a; }; struct agg_v32i8 pass_agg_v32i8(struct agg_v32i8 arg) { return arg; } -// CHECK-LABEL: define void @pass_agg_v32i8(%struct.agg_v32i8* noalias sret %{{.*}}, %struct.agg_v32i8* %{{.*}}) -// CHECK-VECTOR-LABEL: define void @pass_agg_v32i8(%struct.agg_v32i8* noalias sret %{{.*}}, %struct.agg_v32i8* %{{.*}}) +// CHECK-LABEL: define void @pass_agg_v32i8(%struct.agg_v32i8* noalias sret align 32 %{{.*}}, %struct.agg_v32i8* %{{.*}}) +// CHECK-VECTOR-LABEL: define void @pass_agg_v32i8(%struct.agg_v32i8* noalias sret align 8 %{{.*}}, %struct.agg_v32i8* %{{.*}}) // Verify that the following are *not* vector-like aggregate types struct agg_novector1 { v4i8 a; v4i8 b; }; struct agg_novector1 pass_agg_novector1(struct agg_novector1 arg) { return arg; } -// CHECK-LABEL: define void @pass_agg_novector1(%struct.agg_novector1* noalias sret %{{.*}}, i64 %{{.*}}) -// CHECK-VECTOR-LABEL: define void @pass_agg_novector1(%struct.agg_novector1* noalias sret %{{.*}}, i64 %{{.*}}) +// CHECK-LABEL: define void @pass_agg_novector1(%struct.agg_novector1* noalias sret align 4 %{{.*}}, i64 %{{.*}}) +// CHECK-VECTOR-LABEL: define void @pass_agg_novector1(%struct.agg_novector1* noalias sret align 4 %{{.*}}, i64 %{{.*}}) struct agg_novector2 { v4i8 a; float b; }; struct agg_novector2 pass_agg_novector2(struct agg_novector2 arg) { return arg; } -// CHECK-LABEL: define void @pass_agg_novector2(%struct.agg_novector2* noalias sret %{{.*}}, i64 %{{.*}}) -// CHECK-VECTOR-LABEL: define void @pass_agg_novector2(%struct.agg_novector2* noalias sret %{{.*}}, i64 %{{.*}}) +// CHECK-LABEL: define void @pass_agg_novector2(%struct.agg_novector2* noalias sret align 4 %{{.*}}, i64 %{{.*}}) +// CHECK-VECTOR-LABEL: define void @pass_agg_novector2(%struct.agg_novector2* noalias sret align 4 %{{.*}}, i64 %{{.*}}) struct agg_novector3 { v4i8 a; int : 0; }; struct agg_novector3 pass_agg_novector3(struct agg_novector3 arg) { return arg; } -// CHECK-LABEL: define void @pass_agg_novector3(%struct.agg_novector3* noalias sret %{{.*}}, i32 %{{.*}}) -// CHECK-VECTOR-LABEL: define void @pass_agg_novector3(%struct.agg_novector3* noalias sret %{{.*}}, i32 %{{.*}}) +// CHECK-LABEL: define void @pass_agg_novector3(%struct.agg_novector3* noalias sret align 4 %{{.*}}, i32 %{{.*}}) +// CHECK-VECTOR-LABEL: define void @pass_agg_novector3(%struct.agg_novector3* noalias sret align 4 %{{.*}}, i32 %{{.*}}) struct agg_novector4 { v4i8 a __attribute__((aligned (8))); }; struct agg_novector4 pass_agg_novector4(struct agg_novector4 arg) { return arg; } -// CHECK-LABEL: define void @pass_agg_novector4(%struct.agg_novector4* noalias sret %{{.*}}, i64 %{{.*}}) -// CHECK-VECTOR-LABEL: define void @pass_agg_novector4(%struct.agg_novector4* noalias sret %{{.*}}, i64 %{{.*}}) +// CHECK-LABEL: define void @pass_agg_novector4(%struct.agg_novector4* noalias sret align 8 %{{.*}}, i64 %{{.*}}) +// CHECK-VECTOR-LABEL: define void @pass_agg_novector4(%struct.agg_novector4* noalias sret align 8 %{{.*}}, i64 %{{.*}}) // Accessing variable argument lists v1i8 va_v1i8(__builtin_va_list l) { return __builtin_va_arg(l, v1i8); } -// CHECK-LABEL: define void @va_v1i8(<1 x i8>* noalias sret %{{.*}}, %struct.__va_list_tag* %{{.*}}) +// CHECK-LABEL: define void @va_v1i8(<1 x i8>* noalias sret align 1 %{{.*}}, %struct.__va_list_tag* %{{.*}}) // CHECK: [[REG_COUNT_PTR:%[^ ]+]] = getelementptr inbounds %struct.__va_list_tag, %struct.__va_list_tag* %{{.*}}, i32 0, i32 0 // CHECK: [[REG_COUNT:%[^ ]+]] = load i64, i64* [[REG_COUNT_PTR]] // CHECK: [[FITS_IN_REGS:%[^ ]+]] = icmp ult i64 [[REG_COUNT]], 5 @@ -229,7 +229,7 @@ v1i8 va_v1i8(__builtin_va_list l) { return __builtin_va_arg(l, v1i8); } // CHECK-VECTOR: ret <1 x i8> [[RET]] v2i8 va_v2i8(__builtin_va_list l) { return __builtin_va_arg(l, v2i8); } -// CHECK-LABEL: define void @va_v2i8(<2 x i8>* noalias sret %{{.*}}, %struct.__va_list_tag* %{{.*}}) +// CHECK-LABEL: define void @va_v2i8(<2 x i8>* noalias sret align 2 %{{.*}}, %struct.__va_list_tag* %{{.*}}) // CHECK: [[REG_COUNT_PTR:%[^ ]+]] = getelementptr inbounds %struct.__va_list_tag, %struct.__va_list_tag* %{{.*}}, i32 0, i32 0 // CHECK: [[REG_COUNT:%[^ ]+]] = load i64, i64* [[REG_COUNT_PTR]] // CHECK: [[FITS_IN_REGS:%[^ ]+]] = icmp ult i64 [[REG_COUNT]], 5 @@ -261,7 +261,7 @@ v2i8 va_v2i8(__builtin_va_list l) { return __builtin_va_arg(l, v2i8); } // CHECK-VECTOR: ret <2 x i8> [[RET]] v4i8 va_v4i8(__builtin_va_list l) { return __builtin_va_arg(l, v4i8); } -// CHECK-LABEL: define void @va_v4i8(<4 x i8>* noalias sret %{{.*}}, %struct.__va_list_tag* %{{.*}}) +// CHECK-LABEL: define void @va_v4i8(<4 x i8>* noalias sret align 4 %{{.*}}, %struct.__va_list_tag* %{{.*}}) // CHECK: [[REG_COUNT_PTR:%[^ ]+]] = getelementptr inbounds %struct.__va_list_tag, %struct.__va_list_tag* %{{.*}}, i32 0, i32 0 // CHECK: [[REG_COUNT:%[^ ]+]] = load i64, i64* [[REG_COUNT_PTR]] // CHECK: [[FITS_IN_REGS:%[^ ]+]] = icmp ult i64 [[REG_COUNT]], 5 @@ -293,7 +293,7 @@ v4i8 va_v4i8(__builtin_va_list l) { return __builtin_va_arg(l, v4i8); } // CHECK-VECTOR: ret <4 x i8> [[RET]] v8i8 va_v8i8(__builtin_va_list l) { return __builtin_va_arg(l, v8i8); } -// CHECK-LABEL: define void @va_v8i8(<8 x i8>* noalias sret %{{.*}}, %struct.__va_list_tag* %{{.*}}) +// CHECK-LABEL: define void @va_v8i8(<8 x i8>* noalias sret align 8 %{{.*}}, %struct.__va_list_tag* %{{.*}}) // CHECK: [[REG_COUNT_PTR:%[^ ]+]] = getelementptr inbounds %struct.__va_list_tag, %struct.__va_list_tag* %{{.*}}, i32 0, i32 0 // CHECK: [[REG_COUNT:%[^ ]+]] = load i64, i64* [[REG_COUNT_PTR]] // CHECK: [[FITS_IN_REGS:%[^ ]+]] = icmp ult i64 [[REG_COUNT]], 5 @@ -325,7 +325,7 @@ v8i8 va_v8i8(__builtin_va_list l) { return __builtin_va_arg(l, v8i8); } // CHECK-VECTOR: ret <8 x i8> [[RET]] v16i8 va_v16i8(__builtin_va_list l) { return __builtin_va_arg(l, v16i8); } -// CHECK-LABEL: define void @va_v16i8(<16 x i8>* noalias sret %{{.*}}, %struct.__va_list_tag* %{{.*}}) +// CHECK-LABEL: define void @va_v16i8(<16 x i8>* noalias sret align 16 %{{.*}}, %struct.__va_list_tag* %{{.*}}) // CHECK: [[REG_COUNT_PTR:%[^ ]+]] = getelementptr inbounds %struct.__va_list_tag, %struct.__va_list_tag* %{{.*}}, i32 0, i32 0 // CHECK: [[REG_COUNT:%[^ ]+]] = load i64, i64* [[REG_COUNT_PTR]] // CHECK: [[FITS_IN_REGS:%[^ ]+]] = icmp ult i64 [[REG_COUNT]], 5 @@ -357,7 +357,7 @@ v16i8 va_v16i8(__builtin_va_list l) { return __builtin_va_arg(l, v16i8); } // CHECK-VECTOR: ret <16 x i8> [[RET]] v32i8 va_v32i8(__builtin_va_list l) { return __builtin_va_arg(l, v32i8); } -// CHECK-LABEL: define void @va_v32i8(<32 x i8>* noalias sret %{{.*}}, %struct.__va_list_tag* %{{.*}}) +// CHECK-LABEL: define void @va_v32i8(<32 x i8>* noalias sret align 32 %{{.*}}, %struct.__va_list_tag* %{{.*}}) // CHECK: [[REG_COUNT_PTR:%[^ ]+]] = getelementptr inbounds %struct.__va_list_tag, %struct.__va_list_tag* %{{.*}}, i32 0, i32 0 // CHECK: [[REG_COUNT:%[^ ]+]] = load i64, i64* [[REG_COUNT_PTR]] // CHECK: [[FITS_IN_REGS:%[^ ]+]] = icmp ult i64 [[REG_COUNT]], 5 @@ -379,7 +379,7 @@ v32i8 va_v32i8(__builtin_va_list l) { return __builtin_va_arg(l, v32i8); } // CHECK: [[VA_ARG_ADDR:%[^ ]+]] = phi <32 x i8>** [ [[REG_ADDR]], %{{.*}} ], [ [[MEM_ADDR]], %{{.*}} ] // CHECK: [[INDIRECT_ARG:%[^ ]+]] = load <32 x i8>*, <32 x i8>** [[VA_ARG_ADDR]] // CHECK: ret void -// CHECK-VECTOR-LABEL: define void @va_v32i8(<32 x i8>* noalias sret %{{.*}}, %struct.__va_list_tag* %{{.*}}) +// CHECK-VECTOR-LABEL: define void @va_v32i8(<32 x i8>* noalias sret align 8 %{{.*}}, %struct.__va_list_tag* %{{.*}}) // CHECK-VECTOR: [[REG_COUNT_PTR:%[^ ]+]] = getelementptr inbounds %struct.__va_list_tag, %struct.__va_list_tag* %{{.*}}, i32 0, i32 0 // CHECK-VECTOR: [[REG_COUNT:%[^ ]+]] = load i64, i64* [[REG_COUNT_PTR]] // CHECK-VECTOR: [[FITS_IN_REGS:%[^ ]+]] = icmp ult i64 [[REG_COUNT]], 5 @@ -403,7 +403,7 @@ v32i8 va_v32i8(__builtin_va_list l) { return __builtin_va_arg(l, v32i8); } // CHECK-VECTOR: ret void struct agg_v1i8 va_agg_v1i8(__builtin_va_list l) { return __builtin_va_arg(l, struct agg_v1i8); } -// CHECK-LABEL: define void @va_agg_v1i8(%struct.agg_v1i8* noalias sret %{{.*}}, %struct.__va_list_tag* %{{.*}}) +// CHECK-LABEL: define void @va_agg_v1i8(%struct.agg_v1i8* noalias sret align 1 %{{.*}}, %struct.__va_list_tag* %{{.*}}) // CHECK: [[REG_COUNT_PTR:%[^ ]+]] = getelementptr inbounds %struct.__va_list_tag, %struct.__va_list_tag* %{{.*}}, i32 0, i32 0 // CHECK: [[REG_COUNT:%[^ ]+]] = load i64, i64* [[REG_COUNT_PTR]] // CHECK: [[FITS_IN_REGS:%[^ ]+]] = icmp ult i64 [[REG_COUNT]], 5 @@ -424,7 +424,7 @@ struct agg_v1i8 va_agg_v1i8(__builtin_va_list l) { return __builtin_va_arg(l, st // CHECK: store i8* [[OVERFLOW_ARG_AREA2]], i8** [[OVERFLOW_ARG_AREA_PTR]] // CHECK: [[VA_ARG_ADDR:%[^ ]+]] = phi %struct.agg_v1i8* [ [[REG_ADDR]], %{{.*}} ], [ [[MEM_ADDR]], %{{.*}} ] // CHECK: ret void -// CHECK-VECTOR-LABEL: define void @va_agg_v1i8(%struct.agg_v1i8* noalias sret %{{.*}}, %struct.__va_list_tag* %{{.*}}) +// CHECK-VECTOR-LABEL: define void @va_agg_v1i8(%struct.agg_v1i8* noalias sret align 1 %{{.*}}, %struct.__va_list_tag* %{{.*}}) // CHECK-VECTOR: [[OVERFLOW_ARG_AREA_PTR:%[^ ]+]] = getelementptr inbounds %struct.__va_list_tag, %struct.__va_list_tag* %{{.*}}, i32 0, i32 2 // CHECK-VECTOR: [[OVERFLOW_ARG_AREA:%[^ ]+]] = load i8*, i8** [[OVERFLOW_ARG_AREA_PTR]] // CHECK-VECTOR: [[MEM_ADDR:%[^ ]+]] = bitcast i8* [[OVERFLOW_ARG_AREA]] to %struct.agg_v1i8* @@ -433,7 +433,7 @@ struct agg_v1i8 va_agg_v1i8(__builtin_va_list l) { return __builtin_va_arg(l, st // CHECK-VECTOR: ret void struct agg_v2i8 va_agg_v2i8(__builtin_va_list l) { return __builtin_va_arg(l, struct agg_v2i8); } -// CHECK-LABEL: define void @va_agg_v2i8(%struct.agg_v2i8* noalias sret %{{.*}}, %struct.__va_list_tag* %{{.*}}) +// CHECK-LABEL: define void @va_agg_v2i8(%struct.agg_v2i8* noalias sret align 2 %{{.*}}, %struct.__va_list_tag* %{{.*}}) // CHECK: [[REG_COUNT_PTR:%[^ ]+]] = getelementptr inbounds %struct.__va_list_tag, %struct.__va_list_tag* %{{.*}}, i32 0, i32 0 // CHECK: [[REG_COUNT:%[^ ]+]] = load i64, i64* [[REG_COUNT_PTR]] // CHECK: [[FITS_IN_REGS:%[^ ]+]] = icmp ult i64 [[REG_COUNT]], 5 @@ -454,7 +454,7 @@ struct agg_v2i8 va_agg_v2i8(__builtin_va_list l) { return __builtin_va_arg(l, st // CHECK: store i8* [[OVERFLOW_ARG_AREA2]], i8** [[OVERFLOW_ARG_AREA_PTR]] // CHECK: [[VA_ARG_ADDR:%[^ ]+]] = phi %struct.agg_v2i8* [ [[REG_ADDR]], %{{.*}} ], [ [[MEM_ADDR]], %{{.*}} ] // CHECK: ret void -// CHECK-VECTOR-LABEL: define void @va_agg_v2i8(%struct.agg_v2i8* noalias sret %{{.*}}, %struct.__va_list_tag* %{{.*}}) +// CHECK-VECTOR-LABEL: define void @va_agg_v2i8(%struct.agg_v2i8* noalias sret align 2 %{{.*}}, %struct.__va_list_tag* %{{.*}}) // CHECK-VECTOR: [[OVERFLOW_ARG_AREA_PTR:%[^ ]+]] = getelementptr inbounds %struct.__va_list_tag, %struct.__va_list_tag* %{{.*}}, i32 0, i32 2 // CHECK-VECTOR: [[OVERFLOW_ARG_AREA:%[^ ]+]] = load i8*, i8** [[OVERFLOW_ARG_AREA_PTR]] // CHECK-VECTOR: [[MEM_ADDR:%[^ ]+]] = bitcast i8* [[OVERFLOW_ARG_AREA]] to %struct.agg_v2i8* @@ -463,7 +463,7 @@ struct agg_v2i8 va_agg_v2i8(__builtin_va_list l) { return __builtin_va_arg(l, st // CHECK-VECTOR: ret void struct agg_v4i8 va_agg_v4i8(__builtin_va_list l) { return __builtin_va_arg(l, struct agg_v4i8); } -// CHECK-LABEL: define void @va_agg_v4i8(%struct.agg_v4i8* noalias sret %{{.*}}, %struct.__va_list_tag* %{{.*}}) +// CHECK-LABEL: define void @va_agg_v4i8(%struct.agg_v4i8* noalias sret align 4 %{{.*}}, %struct.__va_list_tag* %{{.*}}) // CHECK: [[REG_COUNT_PTR:%[^ ]+]] = getelementptr inbounds %struct.__va_list_tag, %struct.__va_list_tag* %{{.*}}, i32 0, i32 0 // CHECK: [[REG_COUNT:%[^ ]+]] = load i64, i64* [[REG_COUNT_PTR]] // CHECK: [[FITS_IN_REGS:%[^ ]+]] = icmp ult i64 [[REG_COUNT]], 5 @@ -484,7 +484,7 @@ struct agg_v4i8 va_agg_v4i8(__builtin_va_list l) { return __builtin_va_arg(l, st // CHECK: store i8* [[OVERFLOW_ARG_AREA2]], i8** [[OVERFLOW_ARG_AREA_PTR]] // CHECK: [[VA_ARG_ADDR:%[^ ]+]] = phi %struct.agg_v4i8* [ [[REG_ADDR]], %{{.*}} ], [ [[MEM_ADDR]], %{{.*}} ] // CHECK: ret void -// CHECK-VECTOR-LABEL: define void @va_agg_v4i8(%struct.agg_v4i8* noalias sret %{{.*}}, %struct.__va_list_tag* %{{.*}}) +// CHECK-VECTOR-LABEL: define void @va_agg_v4i8(%struct.agg_v4i8* noalias sret align 4 %{{.*}}, %struct.__va_list_tag* %{{.*}}) // CHECK-VECTOR: [[OVERFLOW_ARG_AREA_PTR:%[^ ]+]] = getelementptr inbounds %struct.__va_list_tag, %struct.__va_list_tag* %{{.*}}, i32 0, i32 2 // CHECK-VECTOR: [[OVERFLOW_ARG_AREA:%[^ ]+]] = load i8*, i8** [[OVERFLOW_ARG_AREA_PTR]] // CHECK-VECTOR: [[MEM_ADDR:%[^ ]+]] = bitcast i8* [[OVERFLOW_ARG_AREA]] to %struct.agg_v4i8* @@ -493,7 +493,7 @@ struct agg_v4i8 va_agg_v4i8(__builtin_va_list l) { return __builtin_va_arg(l, st // CHECK-VECTOR: ret void struct agg_v8i8 va_agg_v8i8(__builtin_va_list l) { return __builtin_va_arg(l, struct agg_v8i8); } -// CHECK-LABEL: define void @va_agg_v8i8(%struct.agg_v8i8* noalias sret %{{.*}}, %struct.__va_list_tag* %{{.*}}) +// CHECK-LABEL: define void @va_agg_v8i8(%struct.agg_v8i8* noalias sret align 8 %{{.*}}, %struct.__va_list_tag* %{{.*}}) // CHECK: [[REG_COUNT_PTR:%[^ ]+]] = getelementptr inbounds %struct.__va_list_tag, %struct.__va_list_tag* %{{.*}}, i32 0, i32 0 // CHECK: [[REG_COUNT:%[^ ]+]] = load i64, i64* [[REG_COUNT_PTR]] // CHECK: [[FITS_IN_REGS:%[^ ]+]] = icmp ult i64 [[REG_COUNT]], 5 @@ -514,7 +514,7 @@ struct agg_v8i8 va_agg_v8i8(__builtin_va_list l) { return __builtin_va_arg(l, st // CHECK: store i8* [[OVERFLOW_ARG_AREA2]], i8** [[OVERFLOW_ARG_AREA_PTR]] // CHECK: [[VA_ARG_ADDR:%[^ ]+]] = phi %struct.agg_v8i8* [ [[REG_ADDR]], %{{.*}} ], [ [[MEM_ADDR]], %{{.*}} ] // CHECK: ret void -// CHECK-VECTOR-LABEL: define void @va_agg_v8i8(%struct.agg_v8i8* noalias sret %{{.*}}, %struct.__va_list_tag* %{{.*}}) +// CHECK-VECTOR-LABEL: define void @va_agg_v8i8(%struct.agg_v8i8* noalias sret align 8 %{{.*}}, %struct.__va_list_tag* %{{.*}}) // CHECK-VECTOR: [[OVERFLOW_ARG_AREA_PTR:%[^ ]+]] = getelementptr inbounds %struct.__va_list_tag, %struct.__va_list_tag* %{{.*}}, i32 0, i32 2 // CHECK-VECTOR: [[OVERFLOW_ARG_AREA:%[^ ]+]] = load i8*, i8** [[OVERFLOW_ARG_AREA_PTR]] // CHECK-VECTOR: [[MEM_ADDR:%[^ ]+]] = bitcast i8* [[OVERFLOW_ARG_AREA]] to %struct.agg_v8i8* @@ -523,7 +523,7 @@ struct agg_v8i8 va_agg_v8i8(__builtin_va_list l) { return __builtin_va_arg(l, st // CHECK-VECTOR: ret void struct agg_v16i8 va_agg_v16i8(__builtin_va_list l) { return __builtin_va_arg(l, struct agg_v16i8); } -// CHECK-LABEL: define void @va_agg_v16i8(%struct.agg_v16i8* noalias sret %{{.*}}, %struct.__va_list_tag* %{{.*}}) +// CHECK-LABEL: define void @va_agg_v16i8(%struct.agg_v16i8* noalias sret align 16 %{{.*}}, %struct.__va_list_tag* %{{.*}}) // CHECK: [[REG_COUNT_PTR:%[^ ]+]] = getelementptr inbounds %struct.__va_list_tag, %struct.__va_list_tag* %{{.*}}, i32 0, i32 0 // CHECK: [[REG_COUNT:%[^ ]+]] = load i64, i64* [[REG_COUNT_PTR]] // CHECK: [[FITS_IN_REGS:%[^ ]+]] = icmp ult i64 [[REG_COUNT]], 5 @@ -545,7 +545,7 @@ struct agg_v16i8 va_agg_v16i8(__builtin_va_list l) { return __builtin_va_arg(l, // CHECK: [[VA_ARG_ADDR:%[^ ]+]] = phi %struct.agg_v16i8** [ [[REG_ADDR]], %{{.*}} ], [ [[MEM_ADDR]], %{{.*}} ] // CHECK: [[INDIRECT_ARG:%[^ ]+]] = load %struct.agg_v16i8*, %struct.agg_v16i8** [[VA_ARG_ADDR]] // CHECK: ret void -// CHECK-VECTOR-LABEL: define void @va_agg_v16i8(%struct.agg_v16i8* noalias sret %{{.*}}, %struct.__va_list_tag* %{{.*}}) +// CHECK-VECTOR-LABEL: define void @va_agg_v16i8(%struct.agg_v16i8* noalias sret align 8 %{{.*}}, %struct.__va_list_tag* %{{.*}}) // CHECK-VECTOR: [[OVERFLOW_ARG_AREA_PTR:%[^ ]+]] = getelementptr inbounds %struct.__va_list_tag, %struct.__va_list_tag* %{{.*}}, i32 0, i32 2 // CHECK-VECTOR: [[OVERFLOW_ARG_AREA:%[^ ]+]] = load i8*, i8** [[OVERFLOW_ARG_AREA_PTR]] // CHECK-VECTOR: [[MEM_ADDR:%[^ ]+]] = bitcast i8* [[OVERFLOW_ARG_AREA]] to %struct.agg_v16i8* @@ -554,7 +554,7 @@ struct agg_v16i8 va_agg_v16i8(__builtin_va_list l) { return __builtin_va_arg(l, // CHECK-VECTOR: ret void struct agg_v32i8 va_agg_v32i8(__builtin_va_list l) { return __builtin_va_arg(l, struct agg_v32i8); } -// CHECK-LABEL: define void @va_agg_v32i8(%struct.agg_v32i8* noalias sret %{{.*}}, %struct.__va_list_tag* %{{.*}}) +// CHECK-LABEL: define void @va_agg_v32i8(%struct.agg_v32i8* noalias sret align 32 %{{.*}}, %struct.__va_list_tag* %{{.*}}) // CHECK: [[REG_COUNT_PTR:%[^ ]+]] = getelementptr inbounds %struct.__va_list_tag, %struct.__va_list_tag* %{{.*}}, i32 0, i32 0 // CHECK: [[REG_COUNT:%[^ ]+]] = load i64, i64* [[REG_COUNT_PTR]] // CHECK: [[FITS_IN_REGS:%[^ ]+]] = icmp ult i64 [[REG_COUNT]], 5 @@ -576,7 +576,7 @@ struct agg_v32i8 va_agg_v32i8(__builtin_va_list l) { return __builtin_va_arg(l, // CHECK: [[VA_ARG_ADDR:%[^ ]+]] = phi %struct.agg_v32i8** [ [[REG_ADDR]], %{{.*}} ], [ [[MEM_ADDR]], %{{.*}} ] // CHECK: [[INDIRECT_ARG:%[^ ]+]] = load %struct.agg_v32i8*, %struct.agg_v32i8** [[VA_ARG_ADDR]] // CHECK: ret void -// CHECK-VECTOR-LABEL: define void @va_agg_v32i8(%struct.agg_v32i8* noalias sret %{{.*}}, %struct.__va_list_tag* %{{.*}}) +// CHECK-VECTOR-LABEL: define void @va_agg_v32i8(%struct.agg_v32i8* noalias sret align 8 %{{.*}}, %struct.__va_list_tag* %{{.*}}) // CHECK-VECTOR: [[REG_COUNT_PTR:%[^ ]+]] = getelementptr inbounds %struct.__va_list_tag, %struct.__va_list_tag* %{{.*}}, i32 0, i32 0 // CHECK-VECTOR: [[REG_COUNT:%[^ ]+]] = load i64, i64* [[REG_COUNT_PTR]] // CHECK-VECTOR: [[FITS_IN_REGS:%[^ ]+]] = icmp ult i64 [[REG_COUNT]], 5 diff --git a/clang/test/CodeGen/systemz-abi.c b/clang/test/CodeGen/systemz-abi.c index 3511983e32d76..88fd4bf9c1269 100644 --- a/clang/test/CodeGen/systemz-abi.c +++ b/clang/test/CodeGen/systemz-abi.c @@ -33,7 +33,7 @@ long long pass_longlong(long long arg) { return arg; } // CHECK-LABEL: define i64 @pass_longlong(i64 %{{.*}}) __int128 pass_int128(__int128 arg) { return arg; } -// CHECK-LABEL: define void @pass_int128(i128* noalias sret %{{.*}}, i128* %0) +// CHECK-LABEL: define void @pass_int128(i128* noalias sret align 16 %{{.*}}, i128* %0) float pass_float(float arg) { return arg; } // CHECK-LABEL: define float @pass_float(float %{{.*}}) @@ -42,111 +42,111 @@ double pass_double(double arg) { return arg; } // CHECK-LABEL: define double @pass_double(double %{{.*}}) long double pass_longdouble(long double arg) { return arg; } -// CHECK-LABEL: define void @pass_longdouble(fp128* noalias sret %{{.*}}, fp128* %0) +// CHECK-LABEL: define void @pass_longdouble(fp128* noalias sret align 8 %{{.*}}, fp128* %0) // Complex types _Complex char pass_complex_char(_Complex char arg) { return arg; } -// CHECK-LABEL: define void @pass_complex_char({ i8, i8 }* noalias sret %{{.*}}, { i8, i8 }* %{{.*}}arg) +// CHECK-LABEL: define void @pass_complex_char({ i8, i8 }* noalias sret align 1 %{{.*}}, { i8, i8 }* %{{.*}}arg) _Complex short pass_complex_short(_Complex short arg) { return arg; } -// CHECK-LABEL: define void @pass_complex_short({ i16, i16 }* noalias sret %{{.*}}, { i16, i16 }* %{{.*}}arg) +// CHECK-LABEL: define void @pass_complex_short({ i16, i16 }* noalias sret align 2 %{{.*}}, { i16, i16 }* %{{.*}}arg) _Complex int pass_complex_int(_Complex int arg) { return arg; } -// CHECK-LABEL: define void @pass_complex_int({ i32, i32 }* noalias sret %{{.*}}, { i32, i32 }* %{{.*}}arg) +// CHECK-LABEL: define void @pass_complex_int({ i32, i32 }* noalias sret align 4 %{{.*}}, { i32, i32 }* %{{.*}}arg) _Complex long pass_complex_long(_Complex long arg) { return arg; } -// CHECK-LABEL: define void @pass_complex_long({ i64, i64 }* noalias sret %{{.*}}, { i64, i64 }* %{{.*}}arg) +// CHECK-LABEL: define void @pass_complex_long({ i64, i64 }* noalias sret align 8 %{{.*}}, { i64, i64 }* %{{.*}}arg) _Complex long long pass_complex_longlong(_Complex long long arg) { return arg; } -// CHECK-LABEL: define void @pass_complex_longlong({ i64, i64 }* noalias sret %{{.*}}, { i64, i64 }* %{{.*}}arg) +// CHECK-LABEL: define void @pass_complex_longlong({ i64, i64 }* noalias sret align 8 %{{.*}}, { i64, i64 }* %{{.*}}arg) _Complex float pass_complex_float(_Complex float arg) { return arg; } -// CHECK-LABEL: define void @pass_complex_float({ float, float }* noalias sret %{{.*}}, { float, float }* %{{.*}}arg) +// CHECK-LABEL: define void @pass_complex_float({ float, float }* noalias sret align 4 %{{.*}}, { float, float }* %{{.*}}arg) _Complex double pass_complex_double(_Complex double arg) { return arg; } -// CHECK-LABEL: define void @pass_complex_double({ double, double }* noalias sret %{{.*}}, { double, double }* %{{.*}}arg) +// CHECK-LABEL: define void @pass_complex_double({ double, double }* noalias sret align 8 %{{.*}}, { double, double }* %{{.*}}arg) _Complex long double pass_complex_longdouble(_Complex long double arg) { return arg; } -// CHECK-LABEL: define void @pass_complex_longdouble({ fp128, fp128 }* noalias sret %{{.*}}, { fp128, fp128 }* %{{.*}}arg) +// CHECK-LABEL: define void @pass_complex_longdouble({ fp128, fp128 }* noalias sret align 8 %{{.*}}, { fp128, fp128 }* %{{.*}}arg) // Aggregate types struct agg_1byte { char a[1]; }; struct agg_1byte pass_agg_1byte(struct agg_1byte arg) { return arg; } -// CHECK-LABEL: define void @pass_agg_1byte(%struct.agg_1byte* noalias sret %{{.*}}, i8 %{{.*}}) +// CHECK-LABEL: define void @pass_agg_1byte(%struct.agg_1byte* noalias sret align 1 %{{.*}}, i8 %{{.*}}) struct agg_2byte { char a[2]; }; struct agg_2byte pass_agg_2byte(struct agg_2byte arg) { return arg; } -// CHECK-LABEL: define void @pass_agg_2byte(%struct.agg_2byte* noalias sret %{{.*}}, i16 %{{.*}}) +// CHECK-LABEL: define void @pass_agg_2byte(%struct.agg_2byte* noalias sret align 1 %{{.*}}, i16 %{{.*}}) struct agg_3byte { char a[3]; }; struct agg_3byte pass_agg_3byte(struct agg_3byte arg) { return arg; } -// CHECK-LABEL: define void @pass_agg_3byte(%struct.agg_3byte* noalias sret %{{.*}}, %struct.agg_3byte* %{{.*}}) +// CHECK-LABEL: define void @pass_agg_3byte(%struct.agg_3byte* noalias sret align 1 %{{.*}}, %struct.agg_3byte* %{{.*}}) struct agg_4byte { char a[4]; }; struct agg_4byte pass_agg_4byte(struct agg_4byte arg) { return arg; } -// CHECK-LABEL: define void @pass_agg_4byte(%struct.agg_4byte* noalias sret %{{.*}}, i32 %{{.*}}) +// CHECK-LABEL: define void @pass_agg_4byte(%struct.agg_4byte* noalias sret align 1 %{{.*}}, i32 %{{.*}}) struct agg_5byte { char a[5]; }; struct agg_5byte pass_agg_5byte(struct agg_5byte arg) { return arg; } -// CHECK-LABEL: define void @pass_agg_5byte(%struct.agg_5byte* noalias sret %{{.*}}, %struct.agg_5byte* %{{.*}}) +// CHECK-LABEL: define void @pass_agg_5byte(%struct.agg_5byte* noalias sret align 1 %{{.*}}, %struct.agg_5byte* %{{.*}}) struct agg_6byte { char a[6]; }; struct agg_6byte pass_agg_6byte(struct agg_6byte arg) { return arg; } -// CHECK-LABEL: define void @pass_agg_6byte(%struct.agg_6byte* noalias sret %{{.*}}, %struct.agg_6byte* %{{.*}}) +// CHECK-LABEL: define void @pass_agg_6byte(%struct.agg_6byte* noalias sret align 1 %{{.*}}, %struct.agg_6byte* %{{.*}}) struct agg_7byte { char a[7]; }; struct agg_7byte pass_agg_7byte(struct agg_7byte arg) { return arg; } -// CHECK-LABEL: define void @pass_agg_7byte(%struct.agg_7byte* noalias sret %{{.*}}, %struct.agg_7byte* %{{.*}}) +// CHECK-LABEL: define void @pass_agg_7byte(%struct.agg_7byte* noalias sret align 1 %{{.*}}, %struct.agg_7byte* %{{.*}}) struct agg_8byte { char a[8]; }; struct agg_8byte pass_agg_8byte(struct agg_8byte arg) { return arg; } -// CHECK-LABEL: define void @pass_agg_8byte(%struct.agg_8byte* noalias sret %{{.*}}, i64 %{{.*}}) +// CHECK-LABEL: define void @pass_agg_8byte(%struct.agg_8byte* noalias sret align 1 %{{.*}}, i64 %{{.*}}) struct agg_16byte { char a[16]; }; struct agg_16byte pass_agg_16byte(struct agg_16byte arg) { return arg; } -// CHECK-LABEL: define void @pass_agg_16byte(%struct.agg_16byte* noalias sret %{{.*}}, %struct.agg_16byte* %{{.*}}) +// CHECK-LABEL: define void @pass_agg_16byte(%struct.agg_16byte* noalias sret align 1 %{{.*}}, %struct.agg_16byte* %{{.*}}) // Float-like aggregate types struct agg_float { float a; }; struct agg_float pass_agg_float(struct agg_float arg) { return arg; } -// CHECK-LABEL: define void @pass_agg_float(%struct.agg_float* noalias sret %{{.*}}, float %{{.*}}) +// CHECK-LABEL: define void @pass_agg_float(%struct.agg_float* noalias sret align 4 %{{.*}}, float %{{.*}}) struct agg_double { double a; }; struct agg_double pass_agg_double(struct agg_double arg) { return arg; } -// CHECK-LABEL: define void @pass_agg_double(%struct.agg_double* noalias sret %{{.*}}, double %{{.*}}) +// CHECK-LABEL: define void @pass_agg_double(%struct.agg_double* noalias sret align 8 %{{.*}}, double %{{.*}}) struct agg_longdouble { long double a; }; struct agg_longdouble pass_agg_longdouble(struct agg_longdouble arg) { return arg; } -// CHECK-LABEL: define void @pass_agg_longdouble(%struct.agg_longdouble* noalias sret %{{.*}}, %struct.agg_longdouble* %{{.*}}) +// CHECK-LABEL: define void @pass_agg_longdouble(%struct.agg_longdouble* noalias sret align 8 %{{.*}}, %struct.agg_longdouble* %{{.*}}) struct agg_float_a8 { float a __attribute__((aligned (8))); }; struct agg_float_a8 pass_agg_float_a8(struct agg_float_a8 arg) { return arg; } -// CHECK-LABEL: define void @pass_agg_float_a8(%struct.agg_float_a8* noalias sret %{{.*}}, double %{{.*}}) +// CHECK-LABEL: define void @pass_agg_float_a8(%struct.agg_float_a8* noalias sret align 8 %{{.*}}, double %{{.*}}) struct agg_float_a16 { float a __attribute__((aligned (16))); }; struct agg_float_a16 pass_agg_float_a16(struct agg_float_a16 arg) { return arg; } -// CHECK-LABEL: define void @pass_agg_float_a16(%struct.agg_float_a16* noalias sret %{{.*}}, %struct.agg_float_a16* %{{.*}}) +// CHECK-LABEL: define void @pass_agg_float_a16(%struct.agg_float_a16* noalias sret align 16 %{{.*}}, %struct.agg_float_a16* %{{.*}}) // Verify that the following are *not* float-like aggregate types struct agg_nofloat1 { float a; float b; }; struct agg_nofloat1 pass_agg_nofloat1(struct agg_nofloat1 arg) { return arg; } -// CHECK-LABEL: define void @pass_agg_nofloat1(%struct.agg_nofloat1* noalias sret %{{.*}}, i64 %{{.*}}) +// CHECK-LABEL: define void @pass_agg_nofloat1(%struct.agg_nofloat1* noalias sret align 4 %{{.*}}, i64 %{{.*}}) struct agg_nofloat2 { float a; int b; }; struct agg_nofloat2 pass_agg_nofloat2(struct agg_nofloat2 arg) { return arg; } -// CHECK-LABEL: define void @pass_agg_nofloat2(%struct.agg_nofloat2* noalias sret %{{.*}}, i64 %{{.*}}) +// CHECK-LABEL: define void @pass_agg_nofloat2(%struct.agg_nofloat2* noalias sret align 4 %{{.*}}, i64 %{{.*}}) struct agg_nofloat3 { float a; int : 0; }; struct agg_nofloat3 pass_agg_nofloat3(struct agg_nofloat3 arg) { return arg; } -// CHECK-LABEL: define void @pass_agg_nofloat3(%struct.agg_nofloat3* noalias sret %{{.*}}, i32 %{{.*}}) +// CHECK-LABEL: define void @pass_agg_nofloat3(%struct.agg_nofloat3* noalias sret align 4 %{{.*}}, i32 %{{.*}}) // Accessing variable argument lists @@ -248,7 +248,7 @@ double va_double(__builtin_va_list l) { return __builtin_va_arg(l, double); } // CHECK: ret double [[RET]] long double va_longdouble(__builtin_va_list l) { return __builtin_va_arg(l, long double); } -// CHECK-LABEL: define void @va_longdouble(fp128* noalias sret %{{.*}}, %struct.__va_list_tag* %{{.*}}) +// CHECK-LABEL: define void @va_longdouble(fp128* noalias sret align 8 %{{.*}}, %struct.__va_list_tag* %{{.*}}) // CHECK: [[REG_COUNT_PTR:%[^ ]+]] = getelementptr inbounds %struct.__va_list_tag, %struct.__va_list_tag* %{{.*}}, i32 0, i32 0 // CHECK: [[REG_COUNT:%[^ ]+]] = load i64, i64* [[REG_COUNT_PTR]] // CHECK: [[FITS_IN_REGS:%[^ ]+]] = icmp ult i64 [[REG_COUNT]], 5 @@ -274,7 +274,7 @@ long double va_longdouble(__builtin_va_list l) { return __builtin_va_arg(l, long // CHECK: ret void _Complex char va_complex_char(__builtin_va_list l) { return __builtin_va_arg(l, _Complex char); } -// CHECK-LABEL: define void @va_complex_char({ i8, i8 }* noalias sret %{{.*}}, %struct.__va_list_tag* %{{.*}} +// CHECK-LABEL: define void @va_complex_char({ i8, i8 }* noalias sret align 1 %{{.*}}, %struct.__va_list_tag* %{{.*}} // CHECK: [[REG_COUNT_PTR:%[^ ]+]] = getelementptr inbounds %struct.__va_list_tag, %struct.__va_list_tag* %{{.*}}, i32 0, i32 0 // CHECK: [[REG_COUNT:%[^ ]+]] = load i64, i64* [[REG_COUNT_PTR]] // CHECK: [[FITS_IN_REGS:%[^ ]+]] = icmp ult i64 [[REG_COUNT]], 5 @@ -298,7 +298,7 @@ _Complex char va_complex_char(__builtin_va_list l) { return __builtin_va_arg(l, // CHECK: ret void struct agg_1byte va_agg_1byte(__builtin_va_list l) { return __builtin_va_arg(l, struct agg_1byte); } -// CHECK-LABEL: define void @va_agg_1byte(%struct.agg_1byte* noalias sret %{{.*}}, %struct.__va_list_tag* %{{.*}} +// CHECK-LABEL: define void @va_agg_1byte(%struct.agg_1byte* noalias sret align 1 %{{.*}}, %struct.__va_list_tag* %{{.*}} // CHECK: [[REG_COUNT_PTR:%[^ ]+]] = getelementptr inbounds %struct.__va_list_tag, %struct.__va_list_tag* %{{.*}}, i32 0, i32 0 // CHECK: [[REG_COUNT:%[^ ]+]] = load i64, i64* [[REG_COUNT_PTR]] // CHECK: [[FITS_IN_REGS:%[^ ]+]] = icmp ult i64 [[REG_COUNT]], 5 @@ -321,7 +321,7 @@ struct agg_1byte va_agg_1byte(__builtin_va_list l) { return __builtin_va_arg(l, // CHECK: ret void struct agg_2byte va_agg_2byte(__builtin_va_list l) { return __builtin_va_arg(l, struct agg_2byte); } -// CHECK-LABEL: define void @va_agg_2byte(%struct.agg_2byte* noalias sret %{{.*}}, %struct.__va_list_tag* %{{.*}} +// CHECK-LABEL: define void @va_agg_2byte(%struct.agg_2byte* noalias sret align 1 %{{.*}}, %struct.__va_list_tag* %{{.*}} // CHECK: [[REG_COUNT_PTR:%[^ ]+]] = getelementptr inbounds %struct.__va_list_tag, %struct.__va_list_tag* %{{.*}}, i32 0, i32 0 // CHECK: [[REG_COUNT:%[^ ]+]] = load i64, i64* [[REG_COUNT_PTR]] // CHECK: [[FITS_IN_REGS:%[^ ]+]] = icmp ult i64 [[REG_COUNT]], 5 @@ -344,7 +344,7 @@ struct agg_2byte va_agg_2byte(__builtin_va_list l) { return __builtin_va_arg(l, // CHECK: ret void struct agg_3byte va_agg_3byte(__builtin_va_list l) { return __builtin_va_arg(l, struct agg_3byte); } -// CHECK-LABEL: define void @va_agg_3byte(%struct.agg_3byte* noalias sret %{{.*}}, %struct.__va_list_tag* %{{.*}} +// CHECK-LABEL: define void @va_agg_3byte(%struct.agg_3byte* noalias sret align 1 %{{.*}}, %struct.__va_list_tag* %{{.*}} // CHECK: [[REG_COUNT_PTR:%[^ ]+]] = getelementptr inbounds %struct.__va_list_tag, %struct.__va_list_tag* %{{.*}}, i32 0, i32 0 // CHECK: [[REG_COUNT:%[^ ]+]] = load i64, i64* [[REG_COUNT_PTR]] // CHECK: [[FITS_IN_REGS:%[^ ]+]] = icmp ult i64 [[REG_COUNT]], 5 @@ -368,7 +368,7 @@ struct agg_3byte va_agg_3byte(__builtin_va_list l) { return __builtin_va_arg(l, // CHECK: ret void struct agg_4byte va_agg_4byte(__builtin_va_list l) { return __builtin_va_arg(l, struct agg_4byte); } -// CHECK-LABEL: define void @va_agg_4byte(%struct.agg_4byte* noalias sret %{{.*}}, %struct.__va_list_tag* %{{.*}} +// CHECK-LABEL: define void @va_agg_4byte(%struct.agg_4byte* noalias sret align 1 %{{.*}}, %struct.__va_list_tag* %{{.*}} // CHECK: [[REG_COUNT_PTR:%[^ ]+]] = getelementptr inbounds %struct.__va_list_tag, %struct.__va_list_tag* %{{.*}}, i32 0, i32 0 // CHECK: [[REG_COUNT:%[^ ]+]] = load i64, i64* [[REG_COUNT_PTR]] // CHECK: [[FITS_IN_REGS:%[^ ]+]] = icmp ult i64 [[REG_COUNT]], 5 @@ -391,7 +391,7 @@ struct agg_4byte va_agg_4byte(__builtin_va_list l) { return __builtin_va_arg(l, // CHECK: ret void struct agg_8byte va_agg_8byte(__builtin_va_list l) { return __builtin_va_arg(l, struct agg_8byte); } -// CHECK-LABEL: define void @va_agg_8byte(%struct.agg_8byte* noalias sret %{{.*}}, %struct.__va_list_tag* %{{.*}} +// CHECK-LABEL: define void @va_agg_8byte(%struct.agg_8byte* noalias sret align 1 %{{.*}}, %struct.__va_list_tag* %{{.*}} // CHECK: [[REG_COUNT_PTR:%[^ ]+]] = getelementptr inbounds %struct.__va_list_tag, %struct.__va_list_tag* %{{.*}}, i32 0, i32 0 // CHECK: [[REG_COUNT:%[^ ]+]] = load i64, i64* [[REG_COUNT_PTR]] // CHECK: [[FITS_IN_REGS:%[^ ]+]] = icmp ult i64 [[REG_COUNT]], 5 @@ -414,7 +414,7 @@ struct agg_8byte va_agg_8byte(__builtin_va_list l) { return __builtin_va_arg(l, // CHECK: ret void struct agg_float va_agg_float(__builtin_va_list l) { return __builtin_va_arg(l, struct agg_float); } -// CHECK-LABEL: define void @va_agg_float(%struct.agg_float* noalias sret %{{.*}}, %struct.__va_list_tag* %{{.*}} +// CHECK-LABEL: define void @va_agg_float(%struct.agg_float* noalias sret align 4 %{{.*}}, %struct.__va_list_tag* %{{.*}} // CHECK: [[REG_COUNT_PTR:%[^ ]+]] = getelementptr inbounds %struct.__va_list_tag, %struct.__va_list_tag* %{{.*}}, i32 0, i32 1 // CHECK: [[REG_COUNT:%[^ ]+]] = load i64, i64* [[REG_COUNT_PTR]] // CHECK: [[FITS_IN_REGS:%[^ ]+]] = icmp ult i64 [[REG_COUNT]], 4 @@ -437,7 +437,7 @@ struct agg_float va_agg_float(__builtin_va_list l) { return __builtin_va_arg(l, // CHECK: ret void struct agg_double va_agg_double(__builtin_va_list l) { return __builtin_va_arg(l, struct agg_double); } -// CHECK-LABEL: define void @va_agg_double(%struct.agg_double* noalias sret %{{.*}}, %struct.__va_list_tag* %{{.*}} +// CHECK-LABEL: define void @va_agg_double(%struct.agg_double* noalias sret align 8 %{{.*}}, %struct.__va_list_tag* %{{.*}} // CHECK: [[REG_COUNT_PTR:%[^ ]+]] = getelementptr inbounds %struct.__va_list_tag, %struct.__va_list_tag* %{{.*}}, i32 0, i32 1 // CHECK: [[REG_COUNT:%[^ ]+]] = load i64, i64* [[REG_COUNT_PTR]] // CHECK: [[FITS_IN_REGS:%[^ ]+]] = icmp ult i64 [[REG_COUNT]], 4 @@ -460,7 +460,7 @@ struct agg_double va_agg_double(__builtin_va_list l) { return __builtin_va_arg(l // CHECK: ret void struct agg_longdouble va_agg_longdouble(__builtin_va_list l) { return __builtin_va_arg(l, struct agg_longdouble); } -// CHECK-LABEL: define void @va_agg_longdouble(%struct.agg_longdouble* noalias sret %{{.*}}, %struct.__va_list_tag* %{{.*}} +// CHECK-LABEL: define void @va_agg_longdouble(%struct.agg_longdouble* noalias sret align 8 %{{.*}}, %struct.__va_list_tag* %{{.*}} // CHECK: [[REG_COUNT_PTR:%[^ ]+]] = getelementptr inbounds %struct.__va_list_tag, %struct.__va_list_tag* %{{.*}}, i32 0, i32 0 // CHECK: [[REG_COUNT:%[^ ]+]] = load i64, i64* [[REG_COUNT_PTR]] // CHECK: [[FITS_IN_REGS:%[^ ]+]] = icmp ult i64 [[REG_COUNT]], 5 @@ -484,7 +484,7 @@ struct agg_longdouble va_agg_longdouble(__builtin_va_list l) { return __builtin_ // CHECK: ret void struct agg_float_a8 va_agg_float_a8(__builtin_va_list l) { return __builtin_va_arg(l, struct agg_float_a8); } -// CHECK-LABEL: define void @va_agg_float_a8(%struct.agg_float_a8* noalias sret %{{.*}}, %struct.__va_list_tag* %{{.*}} +// CHECK-LABEL: define void @va_agg_float_a8(%struct.agg_float_a8* noalias sret align 8 %{{.*}}, %struct.__va_list_tag* %{{.*}} // CHECK: [[REG_COUNT_PTR:%[^ ]+]] = getelementptr inbounds %struct.__va_list_tag, %struct.__va_list_tag* %{{.*}}, i32 0, i32 1 // CHECK: [[REG_COUNT:%[^ ]+]] = load i64, i64* [[REG_COUNT_PTR]] // CHECK: [[FITS_IN_REGS:%[^ ]+]] = icmp ult i64 [[REG_COUNT]], 4 @@ -507,7 +507,7 @@ struct agg_float_a8 va_agg_float_a8(__builtin_va_list l) { return __builtin_va_a // CHECK: ret void struct agg_float_a16 va_agg_float_a16(__builtin_va_list l) { return __builtin_va_arg(l, struct agg_float_a16); } -// CHECK-LABEL: define void @va_agg_float_a16(%struct.agg_float_a16* noalias sret %{{.*}}, %struct.__va_list_tag* %{{.*}} +// CHECK-LABEL: define void @va_agg_float_a16(%struct.agg_float_a16* noalias sret align 16 %{{.*}}, %struct.__va_list_tag* %{{.*}} // CHECK: [[REG_COUNT_PTR:%[^ ]+]] = getelementptr inbounds %struct.__va_list_tag, %struct.__va_list_tag* %{{.*}}, i32 0, i32 0 // CHECK: [[REG_COUNT:%[^ ]+]] = load i64, i64* [[REG_COUNT_PTR]] // CHECK: [[FITS_IN_REGS:%[^ ]+]] = icmp ult i64 [[REG_COUNT]], 5 @@ -531,7 +531,7 @@ struct agg_float_a16 va_agg_float_a16(__builtin_va_list l) { return __builtin_va // CHECK: ret void struct agg_nofloat1 va_agg_nofloat1(__builtin_va_list l) { return __builtin_va_arg(l, struct agg_nofloat1); } -// CHECK-LABEL: define void @va_agg_nofloat1(%struct.agg_nofloat1* noalias sret %{{.*}}, %struct.__va_list_tag* %{{.*}} +// CHECK-LABEL: define void @va_agg_nofloat1(%struct.agg_nofloat1* noalias sret align 4 %{{.*}}, %struct.__va_list_tag* %{{.*}} // CHECK: [[REG_COUNT_PTR:%[^ ]+]] = getelementptr inbounds %struct.__va_list_tag, %struct.__va_list_tag* %{{.*}}, i32 0, i32 0 // CHECK: [[REG_COUNT:%[^ ]+]] = load i64, i64* [[REG_COUNT_PTR]] // CHECK: [[FITS_IN_REGS:%[^ ]+]] = icmp ult i64 [[REG_COUNT]], 5 @@ -554,7 +554,7 @@ struct agg_nofloat1 va_agg_nofloat1(__builtin_va_list l) { return __builtin_va_a // CHECK: ret void struct agg_nofloat2 va_agg_nofloat2(__builtin_va_list l) { return __builtin_va_arg(l, struct agg_nofloat2); } -// CHECK-LABEL: define void @va_agg_nofloat2(%struct.agg_nofloat2* noalias sret %{{.*}}, %struct.__va_list_tag* %{{.*}} +// CHECK-LABEL: define void @va_agg_nofloat2(%struct.agg_nofloat2* noalias sret align 4 %{{.*}}, %struct.__va_list_tag* %{{.*}} // CHECK: [[REG_COUNT_PTR:%[^ ]+]] = getelementptr inbounds %struct.__va_list_tag, %struct.__va_list_tag* %{{.*}}, i32 0, i32 0 // CHECK: [[REG_COUNT:%[^ ]+]] = load i64, i64* [[REG_COUNT_PTR]] // CHECK: [[FITS_IN_REGS:%[^ ]+]] = icmp ult i64 [[REG_COUNT]], 5 @@ -577,7 +577,7 @@ struct agg_nofloat2 va_agg_nofloat2(__builtin_va_list l) { return __builtin_va_a // CHECK: ret void struct agg_nofloat3 va_agg_nofloat3(__builtin_va_list l) { return __builtin_va_arg(l, struct agg_nofloat3); } -// CHECK-LABEL: define void @va_agg_nofloat3(%struct.agg_nofloat3* noalias sret %{{.*}}, %struct.__va_list_tag* %{{.*}} +// CHECK-LABEL: define void @va_agg_nofloat3(%struct.agg_nofloat3* noalias sret align 4 %{{.*}}, %struct.__va_list_tag* %{{.*}} // CHECK: [[REG_COUNT_PTR:%[^ ]+]] = getelementptr inbounds %struct.__va_list_tag, %struct.__va_list_tag* %{{.*}}, i32 0, i32 0 // CHECK: [[REG_COUNT:%[^ ]+]] = load i64, i64* [[REG_COUNT_PTR]] // CHECK: [[FITS_IN_REGS:%[^ ]+]] = icmp ult i64 [[REG_COUNT]], 5 diff --git a/clang/test/CodeGen/systemz-abi.cpp b/clang/test/CodeGen/systemz-abi.cpp index 0249e9f63c9bf..5589c7eba1abd 100644 --- a/clang/test/CodeGen/systemz-abi.cpp +++ b/clang/test/CodeGen/systemz-abi.cpp @@ -5,5 +5,4 @@ struct agg_float_cpp { float a; int : 0; }; struct agg_float_cpp pass_agg_float_cpp(struct agg_float_cpp arg) { return arg; } -// CHECK-LABEL: define void @_Z18pass_agg_float_cpp13agg_float_cpp(%struct.agg_float_cpp* noalias sret %{{.*}}, float %{{.*}}) - +// CHECK-LABEL: define void @_Z18pass_agg_float_cpp13agg_float_cpp(%struct.agg_float_cpp* noalias sret align 4 %{{.*}}, float %{{.*}}) diff --git a/clang/test/CodeGen/systemz-inline-asm.c b/clang/test/CodeGen/systemz-inline-asm.c index 7c273dac579e8..2dc5023c55cb0 100644 --- a/clang/test/CodeGen/systemz-inline-asm.c +++ b/clang/test/CodeGen/systemz-inline-asm.c @@ -123,7 +123,7 @@ double test_f64(double f, double g) { long double test_f128(long double f, long double g) { asm("axbr %0, %2" : "=f" (f) : "0" (f), "f" (g)); return f; -// CHECK: define void @test_f128(fp128* noalias nocapture sret [[DEST:%.*]], fp128* nocapture readonly %0, fp128* nocapture readonly %1) +// CHECK: define void @test_f128(fp128* noalias nocapture sret align 8 [[DEST:%.*]], fp128* nocapture readonly %0, fp128* nocapture readonly %1) // CHECK: %f = load fp128, fp128* %0 // CHECK: %g = load fp128, fp128* %1 // CHECK: [[RESULT:%.*]] = tail call fp128 asm "axbr $0, $2", "=f,0,f"(fp128 %f, fp128 %g) diff --git a/clang/test/CodeGen/vectorcall.c b/clang/test/CodeGen/vectorcall.c index c8e8931a084c5..0aa4346fcc5c2 100644 --- a/clang/test/CodeGen/vectorcall.c +++ b/clang/test/CodeGen/vectorcall.c @@ -86,8 +86,8 @@ struct HVA4 __vectorcall hva6(struct HVA4 a, struct HVA4 b) { return b;} // X64: define dso_local x86_vectorcallcc %struct.HVA4 @"\01hva6@@128"(%struct.HVA4 inreg %a.coerce, %struct.HVA4* %b) struct HVA5 __vectorcall hva7() {struct HVA5 a = {}; return a;} -// X32: define dso_local x86_vectorcallcc void @"\01hva7@@0"(%struct.HVA5* inreg noalias sret %agg.result) -// X64: define dso_local x86_vectorcallcc void @"\01hva7@@0"(%struct.HVA5* noalias sret %agg.result) +// X32: define dso_local x86_vectorcallcc void @"\01hva7@@0"(%struct.HVA5* inreg noalias sret align 16 %agg.result) +// X64: define dso_local x86_vectorcallcc void @"\01hva7@@0"(%struct.HVA5* noalias sret align 16 %agg.result) v4f32 __vectorcall hva8(v4f32 a, v4f32 b, v4f32 c, v4f32 d, int e, v4f32 f) {return f;} // X32: define dso_local x86_vectorcallcc <4 x float> @"\01hva8@@84"(<4 x float> %a, <4 x float> %b, <4 x float> %c, <4 x float> %d, i32 inreg %e, <4 x float> %f) diff --git a/clang/test/CodeGen/wasm-arguments.c b/clang/test/CodeGen/wasm-arguments.c index c92028bae2db0..2ee3c3f4cecfb 100644 --- a/clang/test/CodeGen/wasm-arguments.c +++ b/clang/test/CodeGen/wasm-arguments.c @@ -34,8 +34,8 @@ typedef struct { int dd; } s3; // Structs should be returned sret and not simplified by the frontend. -// WEBASSEMBLY32: define void @f3(%struct.s3* noalias sret %agg.result) -// WEBASSEMBLY64: define void @f3(%struct.s3* noalias sret %agg.result) +// WEBASSEMBLY32: define void @f3(%struct.s3* noalias sret align 4 %agg.result) +// WEBASSEMBLY64: define void @f3(%struct.s3* noalias sret align 4 %agg.result) s3 f3(void) { s3 foo; return foo; diff --git a/clang/test/CodeGen/wasm-varargs.c b/clang/test/CodeGen/wasm-varargs.c index 23506875ac9d7..ba1f2d632b4ec 100644 --- a/clang/test/CodeGen/wasm-varargs.c +++ b/clang/test/CodeGen/wasm-varargs.c @@ -80,7 +80,7 @@ struct S test_struct(char *fmt, ...) { return v; } -// CHECK: define void @test_struct([[STRUCT_S:%[^,=]+]]*{{.*}} noalias sret [[AGG_RESULT:%.*]], i8*{{.*}} %fmt, ...) {{.*}} { +// CHECK: define void @test_struct([[STRUCT_S:%[^,=]+]]*{{.*}} noalias sret align 4 [[AGG_RESULT:%.*]], i8*{{.*}} %fmt, ...) {{.*}} { // CHECK: [[FMT_ADDR:%[^,=]+]] = alloca i8*, align 4 // CHECK-NEXT: [[VA:%[^,=]+]] = alloca i8*, align 4 // CHECK-NEXT: store i8* %fmt, i8** [[FMT_ADDR]], align 4 @@ -112,7 +112,7 @@ struct S test_empty_struct(char *fmt, ...) { return v; } -// CHECK: define void @test_empty_struct([[STRUCT_S:%[^,=]+]]*{{.*}} noalias sret [[AGG_RESULT:%.*]], i8*{{.*}} %fmt, ...) {{.*}} { +// CHECK: define void @test_empty_struct([[STRUCT_S:%[^,=]+]]*{{.*}} noalias sret align 4 [[AGG_RESULT:%.*]], i8*{{.*}} %fmt, ...) {{.*}} { // CHECK: [[FMT_ADDR:%[^,=]+]] = alloca i8*, align 4 // CHECK-NEXT: [[VA:%[^,=]+]] = alloca i8*, align 4 // CHECK-NEXT: [[U:%[^,=]+]] = alloca [[STRUCT_Z:%[^,=]+]], align 1 diff --git a/clang/test/CodeGen/windows-struct-abi.c b/clang/test/CodeGen/windows-struct-abi.c index 5ffc4fad64730..9fa175f136587 100644 --- a/clang/test/CodeGen/windows-struct-abi.c +++ b/clang/test/CodeGen/windows-struct-abi.c @@ -34,7 +34,7 @@ struct f4 { struct f4 return_f4(void) { while (1); } -// CHECK: define dso_local void @return_f4(%struct.f4* noalias sret %agg.result) +// CHECK: define dso_local void @return_f4(%struct.f4* noalias sret align 4 %agg.result) void receive_f4(struct f4 a0) { } diff --git a/clang/test/CodeGen/x86_32-arguments-darwin.c b/clang/test/CodeGen/x86_32-arguments-darwin.c index 71b8a2b9fc848..c88c1b8603b67 100644 --- a/clang/test/CodeGen/x86_32-arguments-darwin.c +++ b/clang/test/CodeGen/x86_32-arguments-darwin.c @@ -71,7 +71,7 @@ struct s10 { // Small vectors and 1 x {i64,double} are returned in registers // CHECK: i32 @f11() -// CHECK: void @f12(<2 x i32>* noalias sret %agg.result) +// CHECK: void @f12(<2 x i32>* noalias sret align 8 %agg.result) // CHECK: i64 @f13() // CHECK: i64 @f14() // CHECK: <2 x i64> @f15() @@ -93,11 +93,11 @@ T16 f16(void) { while (1) {} } // 128-bits). // CHECK: i32 @f17() -// CHECK: void @f18(%{{.*}}* noalias sret %agg.result) -// CHECK: void @f19(%{{.*}}* noalias sret %agg.result) -// CHECK: void @f20(%{{.*}}* noalias sret %agg.result) -// CHECK: void @f21(%{{.*}}* noalias sret %agg.result) -// CHECK: void @f22(%{{.*}}* noalias sret %agg.result) +// CHECK: void @f18(%{{.*}}* noalias sret align 8 %agg.result) +// CHECK: void @f19(%{{.*}}* noalias sret align 8 %agg.result) +// CHECK: void @f20(%{{.*}}* noalias sret align 8 %agg.result) +// CHECK: void @f21(%{{.*}}* noalias sret align 16 %agg.result) +// CHECK: void @f22(%{{.*}}* noalias sret align 16 %agg.result) struct { T11 a; } f17(void) { while (1) {} } struct { T12 a; } f18(void) { while (1) {} } struct { T13 a; } f19(void) { while (1) {} } @@ -116,11 +116,11 @@ struct { struct {} a; struct { float a[1]; } b; } f25(void) { while (1) {} } // Small structures are handled recursively // CHECK: i32 @f26() -// CHECK: void @f27(%struct.s27* noalias sret %agg.result) +// CHECK: void @f27(%struct.s27* noalias sret align 1 %agg.result) struct s26 { struct { char a, b; } a; struct { char a, b; } b; } f26(void) { while (1) {} } struct s27 { struct { char a, b, c; } a; struct { char a; } b; } f27(void) { while (1) {} } -// CHECK: void @f28(%struct.s28* noalias sret %agg.result) +// CHECK: void @f28(%struct.s28* noalias sret align 4 %agg.result) struct s28 { int a; int b[]; } f28(void) { while (1) {} } // CHECK-LABEL: define i16 @f29() @@ -150,7 +150,7 @@ struct s36 { struct { int : 0; } a[2][10]; char b; char c; } f36(void) { while ( // CHECK-LABEL: define float @f37() struct s37 { float c[1][1]; } f37(void) { while (1) {} } -// CHECK-LABEL: define void @f38(%struct.s38* noalias sret %agg.result) +// CHECK-LABEL: define void @f38(%struct.s38* noalias sret align 2 %agg.result) struct s38 { char a[3]; short b; } f38(void) { while (1) {} } // CHECK-LABEL: define void @f39(%struct.s39* byval(%struct.s39) align 16 %x) diff --git a/clang/test/CodeGen/x86_32-arguments-iamcu.c b/clang/test/CodeGen/x86_32-arguments-iamcu.c index e391c711ea101..a134f5d84a77b 100644 --- a/clang/test/CodeGen/x86_32-arguments-iamcu.c +++ b/clang/test/CodeGen/x86_32-arguments-iamcu.c @@ -58,7 +58,7 @@ st4_t retSmallStruct(st4_t r) { return r; } // CHECK-LABEL: define i64 @retPaddedStruct(i32 %r.coerce0, i32 %r.coerce1) st5_t retPaddedStruct(st5_t r) { return r; } -// CHECK-LABEL: define void @retLargeStruct(%struct.st12_t* noalias sret %agg.result, i32 %i1, %struct.st12_t* byval(%struct.st12_t) align 4 %r) +// CHECK-LABEL: define void @retLargeStruct(%struct.st12_t* noalias sret align 4 %agg.result, i32 %i1, %struct.st12_t* byval(%struct.st12_t) align 4 %r) st12_t retLargeStruct(int i1, st12_t r) { return r; } // CHECK-LABEL: define i32 @varArgs(i32 %i1, ...) diff --git a/clang/test/CodeGen/x86_64-arguments-nacl.c b/clang/test/CodeGen/x86_64-arguments-nacl.c index ea4483422dfe2..e7287a90765bd 100644 --- a/clang/test/CodeGen/x86_64-arguments-nacl.c +++ b/clang/test/CodeGen/x86_64-arguments-nacl.c @@ -61,7 +61,7 @@ void f12_1(struct s12 a0) {} // Check that sret parameter is accounted for when checking available integer // registers. -// CHECK: define void @f13(%struct.s13_0* noalias sret %agg.result, i32 %a, i32 %b, i32 %c, i32 %d, {{.*}}* byval({{.*}}) align 8 %e, i32 %f) +// CHECK: define void @f13(%struct.s13_0* noalias sret align 8 %agg.result, i32 %a, i32 %b, i32 %c, i32 %d, {{.*}}* byval({{.*}}) align 8 %e, i32 %f) struct s13_0 { long long f0[3]; }; struct s13_1 { long long f0[2]; }; diff --git a/clang/test/CodeGen/x86_64-arguments-win32.c b/clang/test/CodeGen/x86_64-arguments-win32.c index b43107c65ef64..4f7c4ded4b167 100644 --- a/clang/test/CodeGen/x86_64-arguments-win32.c +++ b/clang/test/CodeGen/x86_64-arguments-win32.c @@ -27,5 +27,5 @@ void f6(_Complex double a) {} // CHECK-LABEL: define dso_local i64 @f7() _Complex float f7() { return 1.0; } -// CHECK-LABEL: define dso_local void @f8({ double, double }* noalias sret %agg.result) +// CHECK-LABEL: define dso_local void @f8({ double, double }* noalias sret align 8 %agg.result) _Complex double f8() { return 1.0; } diff --git a/clang/test/CodeGen/x86_64-arguments.c b/clang/test/CodeGen/x86_64-arguments.c index 107571d8140bb..273b2706f10a9 100644 --- a/clang/test/CodeGen/x86_64-arguments.c +++ b/clang/test/CodeGen/x86_64-arguments.c @@ -47,7 +47,7 @@ void f7(e7 a0) { // Test merging/passing of upper eightbyte with X87 class. // -// CHECK-LABEL: define void @f8_1(%union.u8* noalias sret %agg.result) +// CHECK-LABEL: define void @f8_1(%union.u8* noalias sret align 16 %agg.result) // CHECK-LABEL: define void @f8_2(%union.u8* byval(%union.u8) align 16 %a0) union u8 { long double a; @@ -63,7 +63,7 @@ struct s9 { int a; int b; int : 0; } f9(void) { while (1) {} } struct s10 { int a; int b; int : 0; }; void f10(struct s10 a0) {} -// CHECK-LABEL: define void @f11(%union.anon* noalias sret %agg.result) +// CHECK-LABEL: define void @f11(%union.anon* noalias sret align 16 %agg.result) union { long double a; float b; } f11() { while (1) {} } // CHECK-LABEL: define i32 @f12_0() @@ -74,7 +74,7 @@ void f12_1(struct s12 a0) {} // Check that sret parameter is accounted for when checking available integer // registers. -// CHECK: define void @f13(%struct.s13_0* noalias sret %agg.result, i32 %a, i32 %b, i32 %c, i32 %d, {{.*}}* byval({{.*}}) align 8 %e, i32 %f) +// CHECK: define void @f13(%struct.s13_0* noalias sret align 8 %agg.result, i32 %a, i32 %b, i32 %c, i32 %d, {{.*}}* byval({{.*}}) align 8 %e, i32 %f) struct s13_0 { long long f0[3]; }; struct s13_1 { long long f0[2]; }; diff --git a/clang/test/CodeGenCXX/arm-cc.cpp b/clang/test/CodeGenCXX/arm-cc.cpp index 6027746b9ae80..e738cd31fb544 100644 --- a/clang/test/CodeGenCXX/arm-cc.cpp +++ b/clang/test/CodeGenCXX/arm-cc.cpp @@ -16,5 +16,5 @@ void baz() { zed(a); } -// CHECK: declare void @_Z3fooPv(%class.SMLoc* sret, i8*) +// CHECK: declare void @_Z3fooPv(%class.SMLoc* sret align 4, i8*) // CHECK: declare void @_Z3zed5SMLoc(%class.SMLoc*) diff --git a/clang/test/CodeGenCXX/builtin-source-location.cpp b/clang/test/CodeGenCXX/builtin-source-location.cpp index f8bfd7d940b91..cdc896209c85b 100644 --- a/clang/test/CodeGenCXX/builtin-source-location.cpp +++ b/clang/test/CodeGenCXX/builtin-source-location.cpp @@ -65,7 +65,7 @@ SL const_init_global = SL::current(); // // CHECK-GLOBAL-TWO: define internal void @__cxx_global_var_init() // CHECK-GLOBAL-TWO-NOT: ret -// CHECK-GLOBAL-TWO: call void @_ZN15source_location11bad_currentEjjPKcS1_(%struct.source_location* sret @runtime_init_global, +// CHECK-GLOBAL-TWO: call void @_ZN15source_location11bad_currentEjjPKcS1_(%struct.source_location* sret align 8 @runtime_init_global, // CHECK-GLOBAL-TWO-SAME: i32 1100, i32 {{[0-9]+}}, {{[^@]*}}@[[FILE]], {{[^@]*}}@[[FUNC]], #line 1100 "test_runtime_init.cpp" SL runtime_init_global = SL::bad_current(); @@ -77,7 +77,7 @@ extern "C" void test_function() { // CHECK-LOCAL-ONE-DAG: @[[FILE:.*]] = {{.*}}c"test_current.cpp\00" // CHECK-LOCAL-ONE-DAG: @[[FUNC:.*]] = {{.*}}c"test_function\00" // -// CHECK-LOCAL-ONE: call void @_ZN15source_location7currentEjjPKcS1_(%struct.source_location* sret %local, +// CHECK-LOCAL-ONE: call void @_ZN15source_location7currentEjjPKcS1_(%struct.source_location* sret align 8 %local, // CHECK-LOCAL-ONE-SAME: i32 2100, i32 {{[0-9]+}}, // CHECK-LOCAL-ONE-SAME: {{[^@]*}}@[[FILE]], {{[^@]*}}@[[FUNC]], #line 2100 "test_current.cpp" @@ -102,7 +102,7 @@ struct TestInit { // CHECK-CTOR-GLOBAL: define internal void @__cxx_global_var_init.{{[0-9]+}}() // CHECK-CTOR-GLOBAL-NOT: ret // -// CHECK-CTOR-GLOBAL: call void @_ZN15source_location7currentEjjPKcS1_(%struct.source_location* sret %[[TMP_ONE:[^,]*]], +// CHECK-CTOR-GLOBAL: call void @_ZN15source_location7currentEjjPKcS1_(%struct.source_location* sret align 8 %[[TMP_ONE:[^,]*]], // CHECK-CTOR-GLOBAL-SAME: i32 3400, i32 {{[0-9]+}}, {{[^@]*}}@[[FILE]], {{[^@]*}}@[[FUNC]], // CHECK-CTOR-GLOBAL-NEXT: call void @_ZN8TestInitC1E15source_location(%struct.TestInit* @GlobalInitVal, %struct.source_location* {{.*}}%[[TMP_ONE]]) #line 3400 "GlobalInitVal.cpp" @@ -117,7 +117,7 @@ extern "C" void test_init_function() { // CHECK-CTOR-LOCAL: define void @test_init_function() // CHECK-CTOR-LOCAL-NOT: ret // -// CHECK-CTOR-LOCAL: call void @_ZN15source_location7currentEjjPKcS1_(%struct.source_location* sret %[[TMP:[^,]*]], +// CHECK-CTOR-LOCAL: call void @_ZN15source_location7currentEjjPKcS1_(%struct.source_location* sret align 8 %[[TMP:[^,]*]], // CHECK-CTOR-LOCAL-SAME: i32 3500, i32 {{[0-9]+}}, {{[^@]*}}@[[FILE]], {{[^@]*}}@[[FUNC]], // CHECK-CTOR-LOCAL-NEXT: call void @_ZN8TestInitC1E15source_location(%struct.TestInit* %init_local, %struct.source_location* {{.*}}%[[TMP]]) #line 3500 "LocalInitVal.cpp" @@ -153,7 +153,7 @@ extern "C" void test_init_function_constexpr() { // CHECK-CONSTEXPR-LOCAL-DAG: @[[FILE:.*]] = {{.*}}c"ConstexprLocal.cpp\00" // // CHECK-CONSTEXPR-LOCAL: define void @test_init_function_constexpr() -// CHECK-CONSTEXPR-LOCAL: call void @_ZN15source_location7currentEjjPKcS1_(%struct.source_location* sret %[[TMP:[^,]*]], +// CHECK-CONSTEXPR-LOCAL: call void @_ZN15source_location7currentEjjPKcS1_(%struct.source_location* sret align 8 %[[TMP:[^,]*]], // CHECK-CONSTEXPR-LOCAL-SAME: i32 4600, i32 {{[0-9]+}}, {{[^@]*}}@[[FILE]], {{[^@]*}}@[[FUNC]] // CHECK-CONSTEXPR-LOCAL: call void @_ZN17TestInitConstexprC1E15source_location(%struct.TestInitConstexpr* %local_val, {{.*}}%[[TMP]]) #line 4600 "ConstexprLocal.cpp" @@ -189,7 +189,7 @@ extern "C" void test_agg_init() { // // CHECK-AGG-BRACE: define void @test_agg_init() // CHECK-AGG-BRACE: %[[I2:.*]] = getelementptr inbounds %struct.TestInitAgg, %struct.TestInitAgg* %local_brace_init, i32 0, i32 1 -// CHECK-AGG-BRACE-NEXT: call void @_ZN15source_location7currentEjjPKcS1_(%struct.source_location* sret %[[I2]], +// CHECK-AGG-BRACE-NEXT: call void @_ZN15source_location7currentEjjPKcS1_(%struct.source_location* sret align 8 %[[I2]], // CHECK-AGG-BRACE-SAME: i32 5700, i32 {{[0-9]+}}, {{[^@]*}}@[[FILE]], {{[^@]*}}@[[FUNC]] #line 5600 "BraceInitStart.cpp" TestInitAgg local_brace_init{ @@ -203,7 +203,7 @@ extern "C" void test_agg_init() { // // CHECK-AGG-EQUAL: define void @test_agg_init() // CHECK-AGG-EQUAL: %[[I2:.*]] = getelementptr inbounds %struct.TestInitAgg, %struct.TestInitAgg* %local_equal_init, i32 0, i32 1 -// CHECK-AGG-EQUAL-NEXT: call void @_ZN15source_location7currentEjjPKcS1_(%struct.source_location* sret %[[I2]], +// CHECK-AGG-EQUAL-NEXT: call void @_ZN15source_location7currentEjjPKcS1_(%struct.source_location* sret align 8 %[[I2]], // CHECK-AGG-EQUAL-SAME: i32 5900, i32 {{[0-9]+}}, {{[^@]*}}@[[FILE]], {{[^@]*}}@[[FUNC]] #line 5800 "EqualInitStart.cpp" TestInitAgg local_equal_init = @@ -220,11 +220,11 @@ extern "C" void test_agg_init() { // CHECK-AGG-LIST: define void @test_agg_init() // // CHECK-AGG-LIST: %[[I1:.*]] = getelementptr inbounds %struct.TestInitAgg, %struct.TestInitAgg* %local_list_init, i32 0, i32 0 -// CHECK-AGG-LIST-NEXT: call void @_ZN15source_location7currentEjjPKcS1_(%struct.source_location* sret %[[I1]], +// CHECK-AGG-LIST-NEXT: call void @_ZN15source_location7currentEjjPKcS1_(%struct.source_location* sret align 8 %[[I1]], // CHECK-AGG-LIST-SAME: i32 6100, i32 {{[0-9]+}}, {{[^@]*}}@[[FILE_ELEM]], {{[^@]*}}@[[FUNC]] // // CHECK-AGG-LIST: %[[I2:.*]] = getelementptr inbounds %struct.TestInitAgg, %struct.TestInitAgg* %local_list_init, i32 0, i32 1 -// CHECK-AGG-LIST-NEXT: call void @_ZN15source_location7currentEjjPKcS1_(%struct.source_location* sret %[[I2]], +// CHECK-AGG-LIST-NEXT: call void @_ZN15source_location7currentEjjPKcS1_(%struct.source_location* sret align 8 %[[I2]], // CHECK-AGG-LIST-SAME: i32 6200, i32 {{[0-9]+}}, {{[^@]*}}@[[FILE_DEFAULT]], {{[^@]*}}@[[FUNC]] #line 6000 "InitListStart.cpp" TestInitAgg local_list_init = @@ -258,7 +258,7 @@ void test_template() { // CHECK-TEMPL-NEXT: entry: // CHECK-TEMPL-NOT: ret // -// CHECK-TEMPL: call void @_ZN15source_location7currentEjjPKcS1_(%struct.source_location* sret %[[TMP:[^,]*]], +// CHECK-TEMPL: call void @_ZN15source_location7currentEjjPKcS1_(%struct.source_location* sret align 8 %[[TMP:[^,]*]], // CHECK-TEMPL-SAME: i32 7300, i32 {{[0-9]+}}, {{[^@]*}}@[[FILE]], {{[^@]*}}@[[FUNC]] #line 7300 "local_templ.cpp" TestTemplate local_templ; diff --git a/clang/test/CodeGenCXX/call-with-static-chain.cpp b/clang/test/CodeGenCXX/call-with-static-chain.cpp index ac1149b52eddf..17e676433e1a4 100644 --- a/clang/test/CodeGenCXX/call-with-static-chain.cpp +++ b/clang/test/CodeGenCXX/call-with-static-chain.cpp @@ -25,8 +25,8 @@ void test() { // CHECK64: call i32 bitcast (i32 (i64, i64, i64, i64, i64, i64, %struct.A*)* @f1 to i32 (i8*, i64, i64, i64, i64, i64, i64, %struct.A*)*)(i8* nest bitcast (i32 (i64, i64, i64, i64, i64, i64, %struct.A*)* @f1 to i8*) __builtin_call_with_static_chain(f1(a, a, a, a), f1); - // CHECK32: call void bitcast (void (%struct.B*)* @f2 to void (%struct.B*, i8*)*)(%struct.B* sret %{{[0-9a-z]+}}, i8* nest bitcast (void (%struct.B*)* @f2 to i8*)) - // CHECK64: call void bitcast (void (%struct.B*)* @f2 to void (%struct.B*, i8*)*)(%struct.B* sret %{{[0-9a-z]+}}, i8* nest bitcast (void (%struct.B*)* @f2 to i8*)) + // CHECK32: call void bitcast (void (%struct.B*)* @f2 to void (%struct.B*, i8*)*)(%struct.B* sret align 4 %{{[0-9a-z]+}}, i8* nest bitcast (void (%struct.B*)* @f2 to i8*)) + // CHECK64: call void bitcast (void (%struct.B*)* @f2 to void (%struct.B*, i8*)*)(%struct.B* sret align 8 %{{[0-9a-z]+}}, i8* nest bitcast (void (%struct.B*)* @f2 to i8*)) __builtin_call_with_static_chain(f2(), f2); // CHECK32: call i64 bitcast (i64 ()* @f3 to i64 (i8*)*)(i8* nest bitcast (i64 ()* @f3 to i8*)) diff --git a/clang/test/CodeGenCXX/conditional-gnu-ext.cpp b/clang/test/CodeGenCXX/conditional-gnu-ext.cpp index 613dd65ee7c96..ec6d097994183 100644 --- a/clang/test/CodeGenCXX/conditional-gnu-ext.cpp +++ b/clang/test/CodeGenCXX/conditional-gnu-ext.cpp @@ -94,7 +94,7 @@ namespace test3 { B test1() { // CHECK-LABEL: define void @_ZN5test35test1Ev( // CHECK: [[TEMP:%.*]] = alloca [[B]], - // CHECK: call void @_ZN5test312test1_helperEv([[B]]* sret [[TEMP]]) + // CHECK: call void @_ZN5test312test1_helperEv([[B]]* sret align 1 [[TEMP]]) // CHECK-NEXT: [[BOOL:%.*]] = call zeroext i1 @_ZN5test31BcvbEv([[B]]* [[TEMP]]) // CHECK-NEXT: br i1 [[BOOL]] // CHECK: call void @_ZN5test31BC1ERKS0_([[B]]* [[RESULT:%.*]], [[B]]* dereferenceable({{[0-9]+}}) [[TEMP]]) @@ -115,7 +115,7 @@ namespace test3 { // CHECK-NEXT: [[T0:%.*]] = load [[B]]*, [[B]]** [[X]] // CHECK-NEXT: [[BOOL:%.*]] = call zeroext i1 @_ZN5test31BcvbEv([[B]]* [[T0]]) // CHECK-NEXT: br i1 [[BOOL]] - // CHECK: call void @_ZN5test31BcvNS_1AEEv([[A:%.*]]* sret [[RESULT:%.*]], [[B]]* [[T0]]) + // CHECK: call void @_ZN5test31BcvNS_1AEEv([[A:%.*]]* sret align 1 [[RESULT:%.*]], [[B]]* [[T0]]) // CHECK-NEXT: br label // CHECK: call void @_ZN5test31AC1Ev([[A]]* [[RESULT]]) // CHECK-NEXT: br label @@ -126,10 +126,10 @@ namespace test3 { A test3() { // CHECK-LABEL: define void @_ZN5test35test3Ev( // CHECK: [[TEMP:%.*]] = alloca [[B]], - // CHECK: call void @_ZN5test312test3_helperEv([[B]]* sret [[TEMP]]) + // CHECK: call void @_ZN5test312test3_helperEv([[B]]* sret align 1 [[TEMP]]) // CHECK-NEXT: [[BOOL:%.*]] = call zeroext i1 @_ZN5test31BcvbEv([[B]]* [[TEMP]]) // CHECK-NEXT: br i1 [[BOOL]] - // CHECK: call void @_ZN5test31BcvNS_1AEEv([[A]]* sret [[RESULT:%.*]], [[B]]* [[TEMP]]) + // CHECK: call void @_ZN5test31BcvNS_1AEEv([[A]]* sret align 1 [[RESULT:%.*]], [[B]]* [[TEMP]]) // CHECK-NEXT: br label // CHECK: call void @_ZN5test31AC1Ev([[A]]* [[RESULT]]) // CHECK-NEXT: br label diff --git a/clang/test/CodeGenCXX/cxx1z-copy-omission.cpp b/clang/test/CodeGenCXX/cxx1z-copy-omission.cpp index b33a21808175a..dd821949772a7 100644 --- a/clang/test/CodeGenCXX/cxx1z-copy-omission.cpp +++ b/clang/test/CodeGenCXX/cxx1z-copy-omission.cpp @@ -19,7 +19,7 @@ void g() { // CHECK: %[[A:.*]] = alloca // CHECK-NOT: alloca // CHECK-NOT: call - // CHECK: call {{.*}} @_Z1fv({{.*}}* sret %[[A]]) + // CHECK: call {{.*}} @_Z1fv({{.*}}* sret align 4 %[[A]]) A a = A( A{ f() } ); // CHECK-NOT: call @@ -40,7 +40,7 @@ void h() { // CHECK-NOT: alloca // CHECK-NOT: call - // CHECK: call {{.*}} @_Z1fv({{.*}}* sret %[[A]]) + // CHECK: call {{.*}} @_Z1fv({{.*}}* sret align 4 %[[A]]) // CHECK-NOT: call // CHECK: call {{.*}} @_Z1f1A({{.*}}* %[[A]]) f(f()); diff --git a/clang/test/CodeGenCXX/cxx1z-lambda-star-this.cpp b/clang/test/CodeGenCXX/cxx1z-lambda-star-this.cpp index 114791c6558b3..fc13c197076f4 100644 --- a/clang/test/CodeGenCXX/cxx1z-lambda-star-this.cpp +++ b/clang/test/CodeGenCXX/cxx1z-lambda-star-this.cpp @@ -10,7 +10,7 @@ namespace ns1 { int X = A{}.foo()(); } //end ns1 -//CHECK: @"?foo@A@@QAE?A?@@XZ"(%struct.A* %this, %class.anon* noalias sret %[[A_LAMBDA_RETVAL:.*]]) +//CHECK: @"?foo@A@@QAE?A?@@XZ"(%struct.A* %this, %class.anon* noalias sret align 8 %[[A_LAMBDA_RETVAL:.*]]) // get the first object with the closure type, which is of type 'struct.A' //CHECK: %[[I0:.+]] = getelementptr inbounds %[[A_LAMBDA]], %[[A_LAMBDA]]* %[[A_LAMBDA_RETVAL]], i32 0, i32 0 //CHECK: %[[I1:.+]] = bitcast %struct.A* %[[I0]] to i8* @@ -26,6 +26,6 @@ struct B { namespace ns2 { int X = B{}.bar()(); } -//CHECK: @"?bar@B@@QAE?A?@@XZ"(%struct.B* %this, %class.anon.0* noalias sret %agg.result) +//CHECK: @"?bar@B@@QAE?A?@@XZ"(%struct.B* %this, %class.anon.0* noalias sret align 4 %agg.result) //CHECK: %[[I20:.+]] = getelementptr inbounds %class.anon.0, %class.anon.0* %agg.result, i32 0, i32 0 //CHECK: store %struct.B* %this1, %struct.B** %[[I20]], align 4 diff --git a/clang/test/CodeGenCXX/exceptions.cpp b/clang/test/CodeGenCXX/exceptions.cpp index 302488aa568d2..da3a87a4b0da3 100644 --- a/clang/test/CodeGenCXX/exceptions.cpp +++ b/clang/test/CodeGenCXX/exceptions.cpp @@ -146,12 +146,12 @@ namespace test1 { // CHECK: [[NEW:%.*]] = call i8* @_Znwm(i64 8) // CHECK-NEXT: store i1 true, i1* [[ACTIVE]] // CHECK-NEXT: [[CAST:%.*]] = bitcast i8* [[NEW]] to [[A]]* - // CHECK-NEXT: invoke void @_ZN5test15makeBEv([[B:%.*]]* sret [[T0:%.*]]) + // CHECK-NEXT: invoke void @_ZN5test15makeBEv([[B:%.*]]* sret align 4 [[T0:%.*]]) // CHECK: [[T1:%.*]] = invoke i32 @_ZN5test11BcviEv([[B]]* [[T0]]) // CHECK: invoke void @_ZN5test11AC1Ei([[A]]* [[CAST]], i32 [[T1]]) // CHECK: store i1 false, i1* [[ACTIVE]] // CHECK-NEXT: store [[A]]* [[CAST]], [[A]]** [[X]], align 8 - // CHECK: invoke void @_ZN5test15makeBEv([[B:%.*]]* sret [[T2:%.*]]) + // CHECK: invoke void @_ZN5test15makeBEv([[B:%.*]]* sret align 4 [[T2:%.*]]) // CHECK: [[RET:%.*]] = load [[A]]*, [[A]]** [[X]], align 8 // CHECK98: invoke void @_ZN5test11BD1Ev([[B]]* [[T2]]) @@ -239,7 +239,7 @@ namespace test3 { // CHECK-NEXT: store i8* [[FOO]], i8** [[SAVED1]] // CHECK-NEXT: store i1 true, i1* [[CLEANUPACTIVE]] // CHECK-NEXT: [[CAST:%.*]] = bitcast i8* [[NEW]] to [[A]]* - // CHECK-NEXT: invoke void @_ZN5test35makeAEv([[A]]* sret [[CAST]]) + // CHECK-NEXT: invoke void @_ZN5test35makeAEv([[A]]* sret align 8 [[CAST]]) // CHECK: br label // -> cond.end new(foo(),10.0) A(makeA()) : diff --git a/clang/test/CodeGenCXX/homogeneous-aggregates.cpp b/clang/test/CodeGenCXX/homogeneous-aggregates.cpp index 05fb7f1d20a4b..51a4549d38d76 100644 --- a/clang/test/CodeGenCXX/homogeneous-aggregates.cpp +++ b/clang/test/CodeGenCXX/homogeneous-aggregates.cpp @@ -38,10 +38,10 @@ struct I2 : Base2 {}; struct I3 : Base2 {}; struct D5 : I1, I2, I3 {}; // homogeneous aggregate -// PPC: define void @_Z7func_D12D1(%struct.D1* noalias sret %agg.result, [3 x i64] %x.coerce) -// ARM32: define arm_aapcs_vfpcc void @_Z7func_D12D1(%struct.D1* noalias sret %agg.result, [3 x i64] %x.coerce) -// ARM64: define void @_Z7func_D12D1(%struct.D1* noalias sret %agg.result, %struct.D1* %x) -// X64: define dso_local x86_vectorcallcc void @"\01_Z7func_D12D1@@24"(%struct.D1* noalias sret %agg.result, %struct.D1* %x) +// PPC: define void @_Z7func_D12D1(%struct.D1* noalias sret align 8 %agg.result, [3 x i64] %x.coerce) +// ARM32: define arm_aapcs_vfpcc void @_Z7func_D12D1(%struct.D1* noalias sret align 8 %agg.result, [3 x i64] %x.coerce) +// ARM64: define void @_Z7func_D12D1(%struct.D1* noalias sret align 8 %agg.result, %struct.D1* %x) +// X64: define dso_local x86_vectorcallcc void @"\01_Z7func_D12D1@@24"(%struct.D1* noalias sret align 8 %agg.result, %struct.D1* %x) D1 CC func_D1(D1 x) { return x; } // PPC: define [3 x double] @_Z7func_D22D2([3 x double] %x.coerce) @@ -50,9 +50,9 @@ D1 CC func_D1(D1 x) { return x; } // X64: define dso_local x86_vectorcallcc %struct.D2 @"\01_Z7func_D22D2@@24"(%struct.D2 inreg %x.coerce) D2 CC func_D2(D2 x) { return x; } -// PPC: define void @_Z7func_D32D3(%struct.D3* noalias sret %agg.result, [4 x i64] %x.coerce) -// ARM32: define arm_aapcs_vfpcc void @_Z7func_D32D3(%struct.D3* noalias sret %agg.result, [4 x i64] %x.coerce) -// ARM64: define void @_Z7func_D32D3(%struct.D3* noalias sret %agg.result, %struct.D3* %x) +// PPC: define void @_Z7func_D32D3(%struct.D3* noalias sret align 8 %agg.result, [4 x i64] %x.coerce) +// ARM32: define arm_aapcs_vfpcc void @_Z7func_D32D3(%struct.D3* noalias sret align 8 %agg.result, [4 x i64] %x.coerce) +// ARM64: define void @_Z7func_D32D3(%struct.D3* noalias sret align 8 %agg.result, %struct.D3* %x) D3 CC func_D3(D3 x) { return x; } // PPC: define [4 x double] @_Z7func_D42D4([4 x double] %x.coerce) diff --git a/clang/test/CodeGenCXX/lambda-expressions.cpp b/clang/test/CodeGenCXX/lambda-expressions.cpp index 566132ad64e30..c75f84f038715 100644 --- a/clang/test/CodeGenCXX/lambda-expressions.cpp +++ b/clang/test/CodeGenCXX/lambda-expressions.cpp @@ -194,8 +194,8 @@ namespace pr28595 { // CHECK-NEXT: call i32 @"_ZZ1fvENK3$_6clEii" // CHECK-NEXT: ret i32 -// CHECK-LABEL: define internal void @"_ZZ1hvEN4$_118__invokeEv"(%struct.A* noalias sret %agg.result) {{.*}} { -// CHECK: call void @"_ZZ1hvENK4$_11clEv"(%struct.A* sret %agg.result, +// CHECK-LABEL: define internal void @"_ZZ1hvEN4$_118__invokeEv"(%struct.A* noalias sret align 1 %agg.result) {{.*}} { +// CHECK: call void @"_ZZ1hvENK4$_11clEv"(%struct.A* sret align 1 %agg.result, // CHECK-NEXT: ret void struct A { ~A(); }; void h() { diff --git a/clang/test/CodeGenCXX/microsoft-abi-byval-sret.cpp b/clang/test/CodeGenCXX/microsoft-abi-byval-sret.cpp index 2c940d22010bd..a92049c3a7996 100644 --- a/clang/test/CodeGenCXX/microsoft-abi-byval-sret.cpp +++ b/clang/test/CodeGenCXX/microsoft-abi-byval-sret.cpp @@ -49,7 +49,7 @@ A B::qux(A x) { } // CHECK-LABEL: define dso_local x86_fastcallcc void @"?qux@B@@QAI?AUA@@U2@@Z" -// CHECK: (%struct.B* inreg %this, %struct.A* inreg noalias sret %agg.result, <{ %struct.A }>* inalloca %0) +// CHECK: (%struct.B* inreg %this, %struct.A* inreg noalias sret align 4 %agg.result, <{ %struct.A }>* inalloca %0) // CHECK: ret void int main() { @@ -67,4 +67,4 @@ int main() { // CHECK: call x86_stdcallcc %struct.A* @"?baz@B@@QAG?AUA@@U2@@Z" // CHECK: (<{ %struct.B*, %struct.A*, %struct.A }>* inalloca %{{[^,]*}}) // CHECK: call x86_fastcallcc void @"?qux@B@@QAI?AUA@@U2@@Z" -// CHECK: (%struct.B* inreg %{{[^,]*}}, %struct.A* inreg sret %{{.*}}, <{ %struct.A }>* inalloca %{{[^,]*}}) +// CHECK: (%struct.B* inreg %{{[^,]*}}, %struct.A* inreg sret align 4 %{{.*}}, <{ %struct.A }>* inalloca %{{[^,]*}}) diff --git a/clang/test/CodeGenCXX/microsoft-abi-byval-thunks.cpp b/clang/test/CodeGenCXX/microsoft-abi-byval-thunks.cpp index ed4e1fbb36fdb..0ca68cccb7906 100644 --- a/clang/test/CodeGenCXX/microsoft-abi-byval-thunks.cpp +++ b/clang/test/CodeGenCXX/microsoft-abi-byval-thunks.cpp @@ -86,10 +86,10 @@ C::C() {} // force emission // CHECK32-NEXT: ret %"struct.sret_thunk::Agg"* %[[rv]] // CHECK64-LABEL: define linkonce_odr dso_local void @"?foo@C@sret_thunk@@W7EAA?AUAgg@2@U32@@Z" -// CHECK64: (%"struct.sret_thunk::C"* %this, %"struct.sret_thunk::Agg"* noalias sret %agg.result, %"struct.sret_thunk::Agg"* %x) +// CHECK64: (%"struct.sret_thunk::C"* %this, %"struct.sret_thunk::Agg"* noalias sret align 4 %agg.result, %"struct.sret_thunk::Agg"* %x) // CHECK64: getelementptr i8, i8* %{{.*}}, i32 -8 // CHECK64: call void @"?foo@C@sret_thunk@@UEAA?AUAgg@2@U32@@Z" -// CHECK64: (%"struct.sret_thunk::C"* %{{.*}}, %"struct.sret_thunk::Agg"* sret %agg.result, %"struct.sret_thunk::Agg"* %x) +// CHECK64: (%"struct.sret_thunk::C"* %{{.*}}, %"struct.sret_thunk::Agg"* sret align 4 %agg.result, %"struct.sret_thunk::Agg"* %x) // CHECK64-NOT: call // CHECK64: ret void } diff --git a/clang/test/CodeGenCXX/microsoft-abi-cdecl-method-sret.cpp b/clang/test/CodeGenCXX/microsoft-abi-cdecl-method-sret.cpp index 5a8bdf78100f4..534aa7f804695 100644 --- a/clang/test/CodeGenCXX/microsoft-abi-cdecl-method-sret.cpp +++ b/clang/test/CodeGenCXX/microsoft-abi-cdecl-method-sret.cpp @@ -19,9 +19,9 @@ S C::variadic_sret(const char *f, ...) { return S(); } S C::cdecl_sret() { return S(); } S C::byval_and_sret(S a) { return S(); } -// CHECK: define dso_local void @"?variadic_sret@C@@QAA?AUS@@PBDZZ"(%struct.C* %this, %struct.S* noalias sret %agg.result, i8* %f, ...) -// CHECK: define dso_local void @"?cdecl_sret@C@@QAA?AUS@@XZ"(%struct.C* %this, %struct.S* noalias sret %agg.result) -// CHECK: define dso_local void @"?byval_and_sret@C@@QAA?AUS@@U2@@Z"(%struct.C* %this, %struct.S* noalias sret %agg.result, %struct.S* byval(%struct.S) align 4 %a) +// CHECK: define dso_local void @"?variadic_sret@C@@QAA?AUS@@PBDZZ"(%struct.C* %this, %struct.S* noalias sret align 4 %agg.result, i8* %f, ...) +// CHECK: define dso_local void @"?cdecl_sret@C@@QAA?AUS@@XZ"(%struct.C* %this, %struct.S* noalias sret align 4 %agg.result) +// CHECK: define dso_local void @"?byval_and_sret@C@@QAA?AUS@@U2@@Z"(%struct.C* %this, %struct.S* noalias sret align 4 %agg.result, %struct.S* byval(%struct.S) align 4 %a) int main() { C c; @@ -41,4 +41,4 @@ struct A { S A::f(int x) { return S(); } -// CHECK-LABEL: define dso_local x86_fastcallcc void @"?f@A@@QAI?AUS@@H@Z"(%struct.A* inreg %this, %struct.S* inreg noalias sret %agg.result, i32 %x) +// CHECK-LABEL: define dso_local x86_fastcallcc void @"?f@A@@QAI?AUS@@H@Z"(%struct.A* inreg %this, %struct.S* inreg noalias sret align 4 %agg.result, i32 %x) diff --git a/clang/test/CodeGenCXX/microsoft-abi-eh-cleanups.cpp b/clang/test/CodeGenCXX/microsoft-abi-eh-cleanups.cpp index 7e8619b8b0ecf..60fa5c7991119 100644 --- a/clang/test/CodeGenCXX/microsoft-abi-eh-cleanups.cpp +++ b/clang/test/CodeGenCXX/microsoft-abi-eh-cleanups.cpp @@ -18,9 +18,9 @@ void HasEHCleanup() { // WIN32-LABEL: define dso_local void @"?HasEHCleanup@@YAXXZ"() {{.*}} { // WIN32: %[[base:.*]] = call i8* @llvm.stacksave() // If this call throws, we have to restore the stack. -// WIN32: call void @"?getA@@YA?AUA@@XZ"(%struct.A* sret %{{.*}}) +// WIN32: call void @"?getA@@YA?AUA@@XZ"(%struct.A* sret align 4 %{{.*}}) // If this call throws, we have to cleanup the first temporary. -// WIN32: invoke void @"?getA@@YA?AUA@@XZ"(%struct.A* sret %{{.*}}) +// WIN32: invoke void @"?getA@@YA?AUA@@XZ"(%struct.A* sret align 4 %{{.*}}) // If this call throws, we have to cleanup the stacksave. // WIN32: call i32 @"?TakesTwo@@YAHUA@@0@Z" // WIN32: call void @llvm.stackrestore diff --git a/clang/test/CodeGenCXX/microsoft-abi-sret-and-byval.cpp b/clang/test/CodeGenCXX/microsoft-abi-sret-and-byval.cpp index 9fb9f39cb0832..8c8d4b7383d63 100644 --- a/clang/test/CodeGenCXX/microsoft-abi-sret-and-byval.cpp +++ b/clang/test/CodeGenCXX/microsoft-abi-sret-and-byval.cpp @@ -84,45 +84,45 @@ void call_bools_and_chars() { // Returning structs that fit into a register. Small small_return() { return Small(); } -// LINUX-LABEL: define void @_Z12small_returnv(%struct.Small* noalias sret %agg.result) +// LINUX-LABEL: define void @_Z12small_returnv(%struct.Small* noalias sret align 4 %agg.result) // WIN32: define dso_local i32 @"?small_return@@YA?AUSmall@@XZ"() // WIN64: define dso_local i32 @"?small_return@@YA?AUSmall@@XZ"() Medium medium_return() { return Medium(); } -// LINUX-LABEL: define void @_Z13medium_returnv(%struct.Medium* noalias sret %agg.result) +// LINUX-LABEL: define void @_Z13medium_returnv(%struct.Medium* noalias sret align 4 %agg.result) // WIN32: define dso_local i64 @"?medium_return@@YA?AUMedium@@XZ"() // WIN64: define dso_local i64 @"?medium_return@@YA?AUMedium@@XZ"() // Returning structs that fit into a register but are not POD. SmallCpp11NotCpp03Pod small_non_pod_return() { return SmallCpp11NotCpp03Pod(); } -// LINUX-LABEL: define void @_Z20small_non_pod_returnv(%struct.SmallCpp11NotCpp03Pod* noalias sret %agg.result) -// WIN32: define dso_local void @"?small_non_pod_return@@YA?AUSmallCpp11NotCpp03Pod@@XZ"(%struct.SmallCpp11NotCpp03Pod* noalias sret %agg.result) -// WIN64: define dso_local void @"?small_non_pod_return@@YA?AUSmallCpp11NotCpp03Pod@@XZ"(%struct.SmallCpp11NotCpp03Pod* noalias sret %agg.result) +// LINUX-LABEL: define void @_Z20small_non_pod_returnv(%struct.SmallCpp11NotCpp03Pod* noalias sret align 4 %agg.result) +// WIN32: define dso_local void @"?small_non_pod_return@@YA?AUSmallCpp11NotCpp03Pod@@XZ"(%struct.SmallCpp11NotCpp03Pod* noalias sret align 4 %agg.result) +// WIN64: define dso_local void @"?small_non_pod_return@@YA?AUSmallCpp11NotCpp03Pod@@XZ"(%struct.SmallCpp11NotCpp03Pod* noalias sret align 4 %agg.result) SmallWithCtor small_with_ctor_return() { return SmallWithCtor(); } -// LINUX-LABEL: define void @_Z22small_with_ctor_returnv(%struct.SmallWithCtor* noalias sret %agg.result) -// WIN32: define dso_local void @"?small_with_ctor_return@@YA?AUSmallWithCtor@@XZ"(%struct.SmallWithCtor* noalias sret %agg.result) -// WIN64: define dso_local void @"?small_with_ctor_return@@YA?AUSmallWithCtor@@XZ"(%struct.SmallWithCtor* noalias sret %agg.result) +// LINUX-LABEL: define void @_Z22small_with_ctor_returnv(%struct.SmallWithCtor* noalias sret align 4 %agg.result) +// WIN32: define dso_local void @"?small_with_ctor_return@@YA?AUSmallWithCtor@@XZ"(%struct.SmallWithCtor* noalias sret align 4 %agg.result) +// WIN64: define dso_local void @"?small_with_ctor_return@@YA?AUSmallWithCtor@@XZ"(%struct.SmallWithCtor* noalias sret align 4 %agg.result) // FIXME: The 'sret' mark here doesn't seem to be enough to convince LLVM to // preserve the hidden sret pointer in R0 across the function. -// WOA: define dso_local arm_aapcs_vfpcc void @"?small_with_ctor_return@@YA?AUSmallWithCtor@@XZ"(%struct.SmallWithCtor* noalias sret %agg.result) +// WOA: define dso_local arm_aapcs_vfpcc void @"?small_with_ctor_return@@YA?AUSmallWithCtor@@XZ"(%struct.SmallWithCtor* noalias sret align 4 %agg.result) SmallWithVftable small_with_vftable_return() { return SmallWithVftable(); } -// LINUX-LABEL: define void @_Z25small_with_vftable_returnv(%struct.SmallWithVftable* noalias sret %agg.result) -// WIN32: define dso_local void @"?small_with_vftable_return@@YA?AUSmallWithVftable@@XZ"(%struct.SmallWithVftable* noalias sret %agg.result) -// WIN64: define dso_local void @"?small_with_vftable_return@@YA?AUSmallWithVftable@@XZ"(%struct.SmallWithVftable* noalias sret %agg.result) +// LINUX-LABEL: define void @_Z25small_with_vftable_returnv(%struct.SmallWithVftable* noalias sret align 4 %agg.result) +// WIN32: define dso_local void @"?small_with_vftable_return@@YA?AUSmallWithVftable@@XZ"(%struct.SmallWithVftable* noalias sret align 4 %agg.result) +// WIN64: define dso_local void @"?small_with_vftable_return@@YA?AUSmallWithVftable@@XZ"(%struct.SmallWithVftable* noalias sret align 8 %agg.result) MediumWithCopyCtor medium_with_copy_ctor_return() { return MediumWithCopyCtor(); } -// LINUX-LABEL: define void @_Z28medium_with_copy_ctor_returnv(%struct.MediumWithCopyCtor* noalias sret %agg.result) -// WIN32: define dso_local void @"?medium_with_copy_ctor_return@@YA?AUMediumWithCopyCtor@@XZ"(%struct.MediumWithCopyCtor* noalias sret %agg.result) -// WIN64: define dso_local void @"?medium_with_copy_ctor_return@@YA?AUMediumWithCopyCtor@@XZ"(%struct.MediumWithCopyCtor* noalias sret %agg.result) -// WOA: define dso_local arm_aapcs_vfpcc void @"?medium_with_copy_ctor_return@@YA?AUMediumWithCopyCtor@@XZ"(%struct.MediumWithCopyCtor* noalias sret %agg.result) +// LINUX-LABEL: define void @_Z28medium_with_copy_ctor_returnv(%struct.MediumWithCopyCtor* noalias sret align 4 %agg.result) +// WIN32: define dso_local void @"?medium_with_copy_ctor_return@@YA?AUMediumWithCopyCtor@@XZ"(%struct.MediumWithCopyCtor* noalias sret align 4 %agg.result) +// WIN64: define dso_local void @"?medium_with_copy_ctor_return@@YA?AUMediumWithCopyCtor@@XZ"(%struct.MediumWithCopyCtor* noalias sret align 4 %agg.result) +// WOA: define dso_local arm_aapcs_vfpcc void @"?medium_with_copy_ctor_return@@YA?AUMediumWithCopyCtor@@XZ"(%struct.MediumWithCopyCtor* noalias sret align 4 %agg.result) // Returning a large struct that doesn't fit into a register. Big big_return() { return Big(); } -// LINUX-LABEL: define void @_Z10big_returnv(%struct.Big* noalias sret %agg.result) -// WIN32: define dso_local void @"?big_return@@YA?AUBig@@XZ"(%struct.Big* noalias sret %agg.result) -// WIN64: define dso_local void @"?big_return@@YA?AUBig@@XZ"(%struct.Big* noalias sret %agg.result) +// LINUX-LABEL: define void @_Z10big_returnv(%struct.Big* noalias sret align 4 %agg.result) +// WIN32: define dso_local void @"?big_return@@YA?AUBig@@XZ"(%struct.Big* noalias sret align 4 %agg.result) +// WIN64: define dso_local void @"?big_return@@YA?AUBig@@XZ"(%struct.Big* noalias sret align 4 %agg.result) void small_arg(Small s) {} @@ -181,7 +181,7 @@ void small_arg_with_dtor(SmallWithDtor s) {} // Test that the eligible non-aggregate is passed directly, but returned // indirectly on ARM64 Windows. -// WOA64: define dso_local void @"?small_arg_with_private_member@@YA?AUSmallWithPrivate@@U1@@Z"(%struct.SmallWithPrivate* inreg noalias sret %agg.result, i64 %s.coerce) {{.*}} { +// WOA64: define dso_local void @"?small_arg_with_private_member@@YA?AUSmallWithPrivate@@U1@@Z"(%struct.SmallWithPrivate* inreg noalias sret align 4 %agg.result, i64 %s.coerce) {{.*}} { SmallWithPrivate small_arg_with_private_member(SmallWithPrivate s) { return s; } void call_small_arg_with_dtor() { @@ -281,24 +281,24 @@ void pass_ref_field() { class Class { public: Small thiscall_method_small() { return Small(); } - // LINUX: define {{.*}} void @_ZN5Class21thiscall_method_smallEv(%struct.Small* noalias sret %agg.result, %class.Class* %this) - // WIN32: define {{.*}} x86_thiscallcc void @"?thiscall_method_small@Class@@QAE?AUSmall@@XZ"(%class.Class* %this, %struct.Small* noalias sret %agg.result) - // WIN64: define linkonce_odr dso_local void @"?thiscall_method_small@Class@@QEAA?AUSmall@@XZ"(%class.Class* %this, %struct.Small* noalias sret %agg.result) + // LINUX: define {{.*}} void @_ZN5Class21thiscall_method_smallEv(%struct.Small* noalias sret align 4 %agg.result, %class.Class* %this) + // WIN32: define {{.*}} x86_thiscallcc void @"?thiscall_method_small@Class@@QAE?AUSmall@@XZ"(%class.Class* %this, %struct.Small* noalias sret align 4 %agg.result) + // WIN64: define linkonce_odr dso_local void @"?thiscall_method_small@Class@@QEAA?AUSmall@@XZ"(%class.Class* %this, %struct.Small* noalias sret align 4 %agg.result) SmallWithCtor thiscall_method_small_with_ctor() { return SmallWithCtor(); } - // LINUX: define {{.*}} void @_ZN5Class31thiscall_method_small_with_ctorEv(%struct.SmallWithCtor* noalias sret %agg.result, %class.Class* %this) - // WIN32: define {{.*}} x86_thiscallcc void @"?thiscall_method_small_with_ctor@Class@@QAE?AUSmallWithCtor@@XZ"(%class.Class* %this, %struct.SmallWithCtor* noalias sret %agg.result) - // WIN64: define linkonce_odr dso_local void @"?thiscall_method_small_with_ctor@Class@@QEAA?AUSmallWithCtor@@XZ"(%class.Class* %this, %struct.SmallWithCtor* noalias sret %agg.result) + // LINUX: define {{.*}} void @_ZN5Class31thiscall_method_small_with_ctorEv(%struct.SmallWithCtor* noalias sret align 4 %agg.result, %class.Class* %this) + // WIN32: define {{.*}} x86_thiscallcc void @"?thiscall_method_small_with_ctor@Class@@QAE?AUSmallWithCtor@@XZ"(%class.Class* %this, %struct.SmallWithCtor* noalias sret align 4 %agg.result) + // WIN64: define linkonce_odr dso_local void @"?thiscall_method_small_with_ctor@Class@@QEAA?AUSmallWithCtor@@XZ"(%class.Class* %this, %struct.SmallWithCtor* noalias sret align 4 %agg.result) Small __cdecl cdecl_method_small() { return Small(); } - // LINUX: define {{.*}} void @_ZN5Class18cdecl_method_smallEv(%struct.Small* noalias sret %agg.result, %class.Class* %this) - // WIN32: define {{.*}} void @"?cdecl_method_small@Class@@QAA?AUSmall@@XZ"(%class.Class* %this, %struct.Small* noalias sret %agg.result) - // WIN64: define linkonce_odr dso_local void @"?cdecl_method_small@Class@@QEAA?AUSmall@@XZ"(%class.Class* %this, %struct.Small* noalias sret %agg.result) + // LINUX: define {{.*}} void @_ZN5Class18cdecl_method_smallEv(%struct.Small* noalias sret align 4 %agg.result, %class.Class* %this) + // WIN32: define {{.*}} void @"?cdecl_method_small@Class@@QAA?AUSmall@@XZ"(%class.Class* %this, %struct.Small* noalias sret align 4 %agg.result) + // WIN64: define linkonce_odr dso_local void @"?cdecl_method_small@Class@@QEAA?AUSmall@@XZ"(%class.Class* %this, %struct.Small* noalias sret align 4 %agg.result) Big __cdecl cdecl_method_big() { return Big(); } - // LINUX: define {{.*}} void @_ZN5Class16cdecl_method_bigEv(%struct.Big* noalias sret %agg.result, %class.Class* %this) - // WIN32: define {{.*}} void @"?cdecl_method_big@Class@@QAA?AUBig@@XZ"(%class.Class* %this, %struct.Big* noalias sret %agg.result) - // WIN64: define linkonce_odr dso_local void @"?cdecl_method_big@Class@@QEAA?AUBig@@XZ"(%class.Class* %this, %struct.Big* noalias sret %agg.result) + // LINUX: define {{.*}} void @_ZN5Class16cdecl_method_bigEv(%struct.Big* noalias sret align 4 %agg.result, %class.Class* %this) + // WIN32: define {{.*}} void @"?cdecl_method_big@Class@@QAA?AUBig@@XZ"(%class.Class* %this, %struct.Big* noalias sret align 4 %agg.result) + // WIN64: define linkonce_odr dso_local void @"?cdecl_method_big@Class@@QEAA?AUBig@@XZ"(%class.Class* %this, %struct.Big* noalias sret align 4 %agg.result) void thiscall_method_arg(Empty s) {} // LINUX: define {{.*}} void @_ZN5Class19thiscall_method_argE5Empty(%class.Class* %this) diff --git a/clang/test/CodeGenCXX/microsoft-abi-vmemptr-conflicts.cpp b/clang/test/CodeGenCXX/microsoft-abi-vmemptr-conflicts.cpp index 607ec816aefb5..1ab60a5261287 100644 --- a/clang/test/CodeGenCXX/microsoft-abi-vmemptr-conflicts.cpp +++ b/clang/test/CodeGenCXX/microsoft-abi-vmemptr-conflicts.cpp @@ -65,7 +65,7 @@ void f(C *c) { // CHECK-LABEL: define dso_local void @"?f@sret@@YAXPAUC@1@@Z"(%"struct.sret::C"* %c) // CHECK: call x86_thiscallcc i32 bitcast (void (%"struct.sret::C"*, ...)* @"??_9C@sret@@$BA@AE" to i32 (%"struct.sret::C"*)*)(%"struct.sret::C"* %{{.*}}) -// CHECK: call x86_thiscallcc void bitcast (void (%"struct.sret::C"*, ...)* @"??_9C@sret@@$BA@AE" to void (%"struct.sret::C"*, %"struct.sret::Big"*)*)(%"struct.sret::C"* %{{.*}}, %"struct.sret::Big"* sret %{{.*}}) +// CHECK: call x86_thiscallcc void bitcast (void (%"struct.sret::C"*, ...)* @"??_9C@sret@@$BA@AE" to void (%"struct.sret::C"*, %"struct.sret::Big"*)*)(%"struct.sret::C"* %{{.*}}, %"struct.sret::Big"* sret align 4 %{{.*}}) // CHECK-LABEL: define linkonce_odr x86_thiscallcc void @"??_9C@sret@@$BA@AE"(%"struct.sret::C"* %this, ...) {{.*}} comdat // CHECK: musttail call x86_thiscallcc void (%"struct.sret::C"*, ...) %{{.*}}(%"struct.sret::C"* %{{.*}}, ...) diff --git a/clang/test/CodeGenCXX/ptrauth-member-function-pointer.cpp b/clang/test/CodeGenCXX/ptrauth-member-function-pointer.cpp index 9e2c10d8a3337..d219e8f5a351e 100644 --- a/clang/test/CodeGenCXX/ptrauth-member-function-pointer.cpp +++ b/clang/test/CodeGenCXX/ptrauth-member-function-pointer.cpp @@ -168,8 +168,8 @@ typedef void (Derived0::*MethodTy1)(); // Check that the sret pointer passed to the caller is forwarded to the musttail // call. -// CHECK: define linkonce_odr hidden void @_ZN8Derived04sretEv_vfpthunk_(%[[STRUCT_A1]]* noalias sret %[[AGG_RESULT:.*]], %[[STRUCT_DERIVED0]]* %{{.*}}) -// CHECK: musttail call void %{{.*}}(%[[STRUCT_A1]]* sret %[[AGG_RESULT]], %[[STRUCT_DERIVED0]]* %{{.*}}) [ "ptrauth"(i32 0, i64 %{{.*}}) ] +// CHECK: define linkonce_odr hidden void @_ZN8Derived04sretEv_vfpthunk_(%[[STRUCT_A1]]* noalias sret align 4 %[[AGG_RESULT:.*]], %[[STRUCT_DERIVED0]]* %{{.*}}) +// CHECK: musttail call void %{{.*}}(%[[STRUCT_A1]]* sret align 4 %[[AGG_RESULT]], %[[STRUCT_DERIVED0]]* %{{.*}}) [ "ptrauth"(i32 0, i64 %{{.*}}) ] // CHECK-NEXT: ret void // Check that the thunk function doesn't destruct the trivial_abi argument. diff --git a/clang/test/CodeGenCXX/regcall.cpp b/clang/test/CodeGenCXX/regcall.cpp index bdf76964bf231..9eca868fc31d2 100644 --- a/clang/test/CodeGenCXX/regcall.cpp +++ b/clang/test/CodeGenCXX/regcall.cpp @@ -74,8 +74,8 @@ bool __regcall operator ==(const test_class&, const test_class&){ --x; return fa // CHECK-WIN32-DAG: define dso_local x86_regcallcc zeroext i1 @"??8@Yw_NABVtest_class@@0@Z" test_class __regcall operator""_test_class (unsigned long long) { ++x; return test_class{};} -// CHECK-LIN64-DAG: define x86_regcallcc void @_Zli11_test_classy(%class.test_class* noalias sret %agg.result, i64 %0) -// CHECK-LIN32-DAG: define x86_regcallcc void @_Zli11_test_classy(%class.test_class* inreg noalias sret %agg.result, i64 %0) +// CHECK-LIN64-DAG: define x86_regcallcc void @_Zli11_test_classy(%class.test_class* noalias sret align 4 %agg.result, i64 %0) +// CHECK-LIN32-DAG: define x86_regcallcc void @_Zli11_test_classy(%class.test_class* inreg noalias sret align 4 %agg.result, i64 %0) // CHECK-WIN64-DAG: ??__K_test_class@@Yw?AVtest_class@@_K@Z" // CHECK-WIN32-DAG: ??__K_test_class@@Yw?AVtest_class@@_K@Z" @@ -99,7 +99,7 @@ void force_gen() { long double _Complex __regcall foo(long double _Complex f) { return f; } -// CHECK-LIN64-DAG: define x86_regcallcc void @_Z15__regcall3__fooCe({ x86_fp80, x86_fp80 }* noalias sret %agg.result, { x86_fp80, x86_fp80 }* byval({ x86_fp80, x86_fp80 }) align 16 %f) -// CHECK-LIN32-DAG: define x86_regcallcc void @_Z15__regcall3__fooCe({ x86_fp80, x86_fp80 }* inreg noalias sret %agg.result, { x86_fp80, x86_fp80 }* byval({ x86_fp80, x86_fp80 }) align 4 %f) +// CHECK-LIN64-DAG: define x86_regcallcc void @_Z15__regcall3__fooCe({ x86_fp80, x86_fp80 }* noalias sret align 16 %agg.result, { x86_fp80, x86_fp80 }* byval({ x86_fp80, x86_fp80 }) align 16 %f) +// CHECK-LIN32-DAG: define x86_regcallcc void @_Z15__regcall3__fooCe({ x86_fp80, x86_fp80 }* inreg noalias sret align 4 %agg.result, { x86_fp80, x86_fp80 }* byval({ x86_fp80, x86_fp80 }) align 4 %f) // CHECK-WIN64-DAG: define dso_local x86_regcallcc { double, double } @"?foo@@YwU?$_Complex@O@__clang@@U12@@Z"(double %f.0, double %f.1) // CHECK-WIN32-DAG: define dso_local x86_regcallcc { double, double } @"?foo@@YwU?$_Complex@O@__clang@@U12@@Z"(double %f.0, double %f.1) diff --git a/clang/test/CodeGenCXX/stack-reuse-miscompile.cpp b/clang/test/CodeGenCXX/stack-reuse-miscompile.cpp index 4e824d94f510e..7d86ea8447b41 100644 --- a/clang/test/CodeGenCXX/stack-reuse-miscompile.cpp +++ b/clang/test/CodeGenCXX/stack-reuse-miscompile.cpp @@ -39,7 +39,7 @@ const char * f(S s) // CHECK: call void @llvm.lifetime.start.p0i8(i64 16, i8* [[T3i8]]) // CHECK: [[T5:%.*]] = call %class.T* @_ZN1TC1E1S(%class.T* [[T3]], [2 x i32] %{{.*}}) // -// CHECK: call void @_ZNK1T6concatERKS_(%class.T* sret [[T1]], %class.T* [[T2]], %class.T* dereferenceable(16) [[T3]]) +// CHECK: call void @_ZNK1T6concatERKS_(%class.T* sret align 4 [[T1]], %class.T* [[T2]], %class.T* dereferenceable(16) [[T3]]) // CHECK: [[T6:%.*]] = call i8* @_ZNK1T3strEv(%class.T* [[T1]]) // // CHECK: call void @llvm.lifetime.end.p0i8( diff --git a/clang/test/CodeGenCXX/stack-reuse.cpp b/clang/test/CodeGenCXX/stack-reuse.cpp index 35dcb5b349c3e..94e5e3d9b364b 100644 --- a/clang/test/CodeGenCXX/stack-reuse.cpp +++ b/clang/test/CodeGenCXX/stack-reuse.cpp @@ -135,7 +135,7 @@ int large_combiner_test(S_large s) { // CHECK: [[T2:%.*]] = alloca %struct.Combiner // CHECK: [[T1:%.*]] = alloca %struct.Combiner // CHECK: [[T3:%.*]] = call %struct.Combiner* @_ZN8CombinerC1E7S_large(%struct.Combiner* nonnull [[T1]], [9 x i32] %s.coerce) -// CHECK: call void @_ZN8Combiner1fEv(%struct.Combiner* nonnull sret [[T2]], %struct.Combiner* nonnull [[T1]]) +// CHECK: call void @_ZN8Combiner1fEv(%struct.Combiner* nonnull sret align 4 [[T2]], %struct.Combiner* nonnull [[T1]]) // CHECK: [[T4:%.*]] = getelementptr inbounds %struct.Combiner, %struct.Combiner* [[T2]], i32 0, i32 0, i32 0, i32 0 // CHECK: [[T5:%.*]] = load i32, i32* [[T4]] // CHECK: ret i32 [[T5]] diff --git a/clang/test/CodeGenCXX/temporaries.cpp b/clang/test/CodeGenCXX/temporaries.cpp index d15e0fa05bd86..175b475c8cd7f 100644 --- a/clang/test/CodeGenCXX/temporaries.cpp +++ b/clang/test/CodeGenCXX/temporaries.cpp @@ -403,13 +403,13 @@ namespace Elision { // CHECK-NEXT: call void @_ZN7Elision1AC1Ev([[A]]* [[I]]) A i = (foo(), A()); - // CHECK-NEXT: call void @_ZN7Elision4fooAEv([[A]]* sret [[T0]]) + // CHECK-NEXT: call void @_ZN7Elision4fooAEv([[A]]* sret align 8 [[T0]]) // CHECK-NEXT: call void @_ZN7Elision1AC1Ev([[A]]* [[J]]) // CHECK-NEXT: call void @_ZN7Elision1AD1Ev([[A]]* [[T0]]) A j = (fooA(), A()); // CHECK-NEXT: call void @_ZN7Elision1AC1Ev([[A]]* [[T1]]) - // CHECK-NEXT: call void @_ZN7Elision4fooAEv([[A]]* sret [[K]]) + // CHECK-NEXT: call void @_ZN7Elision4fooAEv([[A]]* sret align 8 [[K]]) // CHECK-NEXT: call void @_ZN7Elision1AD1Ev([[A]]* [[T1]]) A k = (A(), fooA()); @@ -436,7 +436,7 @@ namespace Elision { // CHECK-NEXT: call void @_ZN7Elision1AD1Ev([[A]]* [[I]]) } - // CHECK: define void @_ZN7Elision5test2Ev([[A]]* noalias sret + // CHECK: define void @_ZN7Elision5test2Ev([[A]]* noalias sret align 8 A test2() { // CHECK: call void @_ZN7Elision3fooEv() // CHECK-NEXT: call void @_ZN7Elision1AC1Ev([[A]]* [[RET:%.*]]) @@ -444,7 +444,7 @@ namespace Elision { return (foo(), A()); } - // CHECK: define void @_ZN7Elision5test3EiNS_1AE([[A]]* noalias sret + // CHECK: define void @_ZN7Elision5test3EiNS_1AE([[A]]* noalias sret align 8 A test3(int v, A x) { if (v < 5) // CHECK: call void @_ZN7Elision1AC1Ev([[A]]* [[RET:%.*]]) @@ -485,7 +485,7 @@ namespace Elision { } // rdar://problem/8433352 - // CHECK: define void @_ZN7Elision5test5Ev([[A]]* noalias sret + // CHECK: define void @_ZN7Elision5test5Ev([[A]]* noalias sret align 8 struct B { A a; B(); }; A test5() { // CHECK: [[AT0:%.*]] = alloca [[A]], align 8 @@ -523,7 +523,7 @@ namespace Elision { void test6(const C *x) { // CHECK: [[T0:%.*]] = alloca [[A]], align 8 // CHECK: [[X:%.*]] = load [[C]]*, [[C]]** {{%.*}}, align 8 - // CHECK-NEXT: call void @_ZNK7Elision1CcvNS_1AEEv([[A]]* sret [[T0]], [[C]]* [[X]]) + // CHECK-NEXT: call void @_ZNK7Elision1CcvNS_1AEEv([[A]]* sret align 8 [[T0]], [[C]]* [[X]]) // CHECK-NEXT: call void @_ZNK7Elision1A3fooEv([[A]]* [[T0]]) // CHECK-NEXT: call void @_ZN7Elision1AD1Ev([[A]]* [[T0]]) // CHECK-NEXT: ret void diff --git a/clang/test/CodeGenCXX/thiscall-struct-return.cpp b/clang/test/CodeGenCXX/thiscall-struct-return.cpp index a6be5aa494e1b..35d5cc479177a 100644 --- a/clang/test/CodeGenCXX/thiscall-struct-return.cpp +++ b/clang/test/CodeGenCXX/thiscall-struct-return.cpp @@ -34,8 +34,8 @@ void test( void ) { // CHECK: call void @_ZN1CC1Ev(%class.C* [[C:%.+]]) C c; -// CHECK: call x86_thiscallcc void @_ZNK1C5SmallEv(%struct.S* sret %{{.+}}, %class.C* [[C]]) +// CHECK: call x86_thiscallcc void @_ZNK1C5SmallEv(%struct.S* sret align 4 %{{.+}}, %class.C* [[C]]) (void)c.Small(); -// CHECK: call x86_thiscallcc void @_ZNK1C6MediumEv(%struct.M* sret %{{.+}}, %class.C* [[C]]) +// CHECK: call x86_thiscallcc void @_ZNK1C6MediumEv(%struct.M* sret align 4 %{{.+}}, %class.C* [[C]]) (void)c.Medium(); } diff --git a/clang/test/CodeGenCXX/thunk-returning-memptr.cpp b/clang/test/CodeGenCXX/thunk-returning-memptr.cpp index 0b7870c6d6582..63bb3d68472d7 100644 --- a/clang/test/CodeGenCXX/thunk-returning-memptr.cpp +++ b/clang/test/CodeGenCXX/thunk-returning-memptr.cpp @@ -23,5 +23,5 @@ C::C() {} // Because of the tail call, the return value cannot be copied into a local // alloca. (PR39901) -// CHECK-LABEL: define linkonce_odr void @_ZThn4_N1C1fEv({ i32, i32 }* noalias sret %agg.result, %struct.C* %this) -// CHECK: tail call void @_ZN1C1fEv({ i32, i32 }* sret %agg.result +// CHECK-LABEL: define linkonce_odr void @_ZThn4_N1C1fEv({ i32, i32 }* noalias sret align 4 %agg.result, %struct.C* %this) +// CHECK: tail call void @_ZN1C1fEv({ i32, i32 }* sret align 4 %agg.result diff --git a/clang/test/CodeGenCXX/thunks.cpp b/clang/test/CodeGenCXX/thunks.cpp index fe7d656eb7e52..b5c2852f87703 100644 --- a/clang/test/CodeGenCXX/thunks.cpp +++ b/clang/test/CodeGenCXX/thunks.cpp @@ -206,13 +206,13 @@ namespace Test6 { // CHECK-LABEL: define void @_ZThn16_N5Test66Thunks1fEv // CHECK-DBG-NOT: dbg.declare // CHECK-NOT: memcpy - // CHECK: {{call void @_ZN5Test66Thunks1fEv.*sret}} + // CHECK: {{call void @_ZN5Test66Thunks1fEv.*sret align 1}} // CHECK: ret void X Thunks::f() { return X(); } - // WIN64-LABEL: define linkonce_odr dso_local void @"?f@Thunks@Test6@@WBA@EAA?AUX@2@XZ"({{.*}} sret %{{.*}}) + // WIN64-LABEL: define linkonce_odr dso_local void @"?f@Thunks@Test6@@WBA@EAA?AUX@2@XZ"({{.*}} sret align 1 %{{.*}}) // WIN64-NOT: memcpy - // WIN64: tail call void @"?f@Thunks@Test6@@UEAA?AUX@2@XZ"({{.*}} sret %{{.*}}) + // WIN64: tail call void @"?f@Thunks@Test6@@UEAA?AUX@2@XZ"({{.*}} sret align 1 %{{.*}}) } namespace Test7 { diff --git a/clang/test/CodeGenCXX/trivial_abi.cpp b/clang/test/CodeGenCXX/trivial_abi.cpp index 2cf07b22581a2..23c589dacd7e2 100644 --- a/clang/test/CodeGenCXX/trivial_abi.cpp +++ b/clang/test/CodeGenCXX/trivial_abi.cpp @@ -126,7 +126,7 @@ void testIgnoredSmall() { void testParamLarge(Large a) noexcept { } -// CHECK: define void @_Z15testReturnLargev(%[[STRUCT_LARGE:.*]]* noalias sret %[[AGG_RESULT:.*]]) +// CHECK: define void @_Z15testReturnLargev(%[[STRUCT_LARGE:.*]]* noalias sret align 8 %[[AGG_RESULT:.*]]) // CHECK: %[[CALL:.*]] = call %[[STRUCT_LARGE]]* @_ZN5LargeC1Ev(%[[STRUCT_LARGE]]* %[[AGG_RESULT]]) // CHECK: ret void // CHECK: } @@ -153,7 +153,7 @@ void testCallLarge0() { // CHECK: define void @_Z14testCallLarge1v() // CHECK: %[[AGG_TMP:.*]] = alloca %[[STRUCT_LARGE:.*]], align 8 -// CHECK: call void @_Z15testReturnLargev(%[[STRUCT_LARGE]]* sret %[[AGG_TMP]]) +// CHECK: call void @_Z15testReturnLargev(%[[STRUCT_LARGE]]* sret align 8 %[[AGG_TMP]]) // CHECK: call void @_Z14testParamLarge5Large(%[[STRUCT_LARGE]]* %[[AGG_TMP]]) // CHECK: ret void // CHECK: } @@ -164,7 +164,7 @@ void testCallLarge1() { // CHECK: define void @_Z16testIgnoredLargev() // CHECK: %[[AGG_TMP_ENSURED:.*]] = alloca %[[STRUCT_LARGE:.*]], align 8 -// CHECK: call void @_Z15testReturnLargev(%[[STRUCT_LARGE]]* sret %[[AGG_TMP_ENSURED]]) +// CHECK: call void @_Z15testReturnLargev(%[[STRUCT_LARGE]]* sret align 8 %[[AGG_TMP_ENSURED]]) // CHECK: %[[CALL:.*]] = call %[[STRUCT_LARGE]]* @_ZN5LargeD1Ev(%[[STRUCT_LARGE]]* %[[AGG_TMP_ENSURED]]) // CHECK: ret void // CHECK: } @@ -186,7 +186,7 @@ Trivial testReturnHasTrivial() { return t; } -// CHECK: define void @_Z23testReturnHasNonTrivialv(%[[STRUCT_NONTRIVIAL:.*]]* noalias sret %[[AGG_RESULT:.*]]) +// CHECK: define void @_Z23testReturnHasNonTrivialv(%[[STRUCT_NONTRIVIAL:.*]]* noalias sret align 4 %[[AGG_RESULT:.*]]) // CHECK: %[[CALL:.*]] = call %[[STRUCT_NONTRIVIAL]]* @_ZN10NonTrivialC1Ev(%[[STRUCT_NONTRIVIAL]]* %[[AGG_RESULT]]) // CHECK: ret void // CHECK: } diff --git a/clang/test/CodeGenCXX/unknown-anytype.cpp b/clang/test/CodeGenCXX/unknown-anytype.cpp index 42ed472380b15..0a7ab53b7af6c 100644 --- a/clang/test/CodeGenCXX/unknown-anytype.cpp +++ b/clang/test/CodeGenCXX/unknown-anytype.cpp @@ -71,7 +71,7 @@ struct Test7 { }; extern "C" __unknown_anytype test7_any(int); Test7 test7() { - // COMMON: call void @test7_any({{%.*}}* sret {{%.*}}, i32 5) + // COMMON: call void @test7_any({{%.*}}* sret align 1 {{%.*}}, i32 5) return (Test7) test7_any(5); } diff --git a/clang/test/CodeGenCXX/wasm-args-returns.cpp b/clang/test/CodeGenCXX/wasm-args-returns.cpp index c547eb85390da..3c57961eb2fcc 100644 --- a/clang/test/CodeGenCXX/wasm-args-returns.cpp +++ b/clang/test/CodeGenCXX/wasm-args-returns.cpp @@ -30,52 +30,52 @@ struct two_fields { double d, e; }; test(two_fields); -// CHECK: define void @_Z7forward10two_fields(%struct.two_fields* noalias nocapture sret %{{.*}}, %struct.two_fields* nocapture readonly byval(%struct.two_fields) align 8 %{{.*}}) +// CHECK: define void @_Z7forward10two_fields(%struct.two_fields* noalias nocapture sret align 8 %{{.*}}, %struct.two_fields* nocapture readonly byval(%struct.two_fields) align 8 %{{.*}}) // // CHECK: define void @_Z15test_two_fieldsv() // CHECK: %[[tmp:.*]] = alloca %struct.two_fields, align 8 -// CHECK: call void @_Z14def_two_fieldsv(%struct.two_fields* nonnull sret %[[tmp]]) +// CHECK: call void @_Z14def_two_fieldsv(%struct.two_fields* nonnull sret align 8 %[[tmp]]) // CHECK: call void @_Z3use10two_fields(%struct.two_fields* nonnull byval(%struct.two_fields) align 8 %[[tmp]]) // CHECK: ret void // // CHECK: declare void @_Z3use10two_fields(%struct.two_fields* byval(%struct.two_fields) align 8) -// CHECK: declare void @_Z14def_two_fieldsv(%struct.two_fields* sret) +// CHECK: declare void @_Z14def_two_fieldsv(%struct.two_fields* sret align 8) struct copy_ctor { double d; copy_ctor(copy_ctor const &); }; test(copy_ctor); -// CHECK: define void @_Z7forward9copy_ctor(%struct.copy_ctor* noalias sret %{{.*}}, %struct.copy_ctor* nonnull %{{.*}}) +// CHECK: define void @_Z7forward9copy_ctor(%struct.copy_ctor* noalias sret align 8 %{{.*}}, %struct.copy_ctor* nonnull %{{.*}}) // // CHECK: declare %struct.copy_ctor* @_ZN9copy_ctorC1ERKS_(%struct.copy_ctor* returned, %struct.copy_ctor* dereferenceable(8)) // // CHECK: define void @_Z14test_copy_ctorv() // CHECK: %[[tmp:.*]] = alloca %struct.copy_ctor, align 8 -// CHECK: call void @_Z13def_copy_ctorv(%struct.copy_ctor* nonnull sret %[[tmp]]) +// CHECK: call void @_Z13def_copy_ctorv(%struct.copy_ctor* nonnull sret align 8 %[[tmp]]) // CHECK: call void @_Z3use9copy_ctor(%struct.copy_ctor* nonnull %[[tmp]]) // CHECK: ret void // // CHECK: declare void @_Z3use9copy_ctor(%struct.copy_ctor*) -// CHECK: declare void @_Z13def_copy_ctorv(%struct.copy_ctor* sret) +// CHECK: declare void @_Z13def_copy_ctorv(%struct.copy_ctor* sret align 8) struct __attribute__((aligned(16))) aligned_copy_ctor { double d, e; aligned_copy_ctor(aligned_copy_ctor const &); }; test(aligned_copy_ctor); -// CHECK: define void @_Z7forward17aligned_copy_ctor(%struct.aligned_copy_ctor* noalias sret %{{.*}}, %struct.aligned_copy_ctor* nonnull %{{.*}}) +// CHECK: define void @_Z7forward17aligned_copy_ctor(%struct.aligned_copy_ctor* noalias sret align 16 %{{.*}}, %struct.aligned_copy_ctor* nonnull %{{.*}}) // // CHECK: declare %struct.aligned_copy_ctor* @_ZN17aligned_copy_ctorC1ERKS_(%struct.aligned_copy_ctor* returned, %struct.aligned_copy_ctor* dereferenceable(16)) // // CHECK: define void @_Z22test_aligned_copy_ctorv() // CHECK: %[[tmp:.*]] = alloca %struct.aligned_copy_ctor, align 16 -// CHECK: call void @_Z21def_aligned_copy_ctorv(%struct.aligned_copy_ctor* nonnull sret %[[tmp]]) +// CHECK: call void @_Z21def_aligned_copy_ctorv(%struct.aligned_copy_ctor* nonnull sret align 16 %[[tmp]]) // CHECK: call void @_Z3use17aligned_copy_ctor(%struct.aligned_copy_ctor* nonnull %[[tmp]]) // CHECK: ret void // // CHECK: declare void @_Z3use17aligned_copy_ctor(%struct.aligned_copy_ctor*) -// CHECK: declare void @_Z21def_aligned_copy_ctorv(%struct.aligned_copy_ctor* sret) +// CHECK: declare void @_Z21def_aligned_copy_ctorv(%struct.aligned_copy_ctor* sret align 16) struct empty {}; test(empty); diff --git a/clang/test/CodeGenCXX/x86_32-arguments.cpp b/clang/test/CodeGenCXX/x86_32-arguments.cpp index 830168635b529..c7ff59e943d2e 100644 --- a/clang/test/CodeGenCXX/x86_32-arguments.cpp +++ b/clang/test/CodeGenCXX/x86_32-arguments.cpp @@ -6,7 +6,7 @@ struct S { short s; }; -// CHECK-LABEL: define void @_Z1fv(%struct.S* noalias sret % +// CHECK-LABEL: define void @_Z1fv(%struct.S* noalias sret align 2 % S f() { return S(); } // CHECK-LABEL: define void @_Z1f1S(%struct.S* %0) void f(S) { } @@ -18,7 +18,7 @@ class C { double c; }; -// CHECK-LABEL: define void @_Z1gv(%class.C* noalias sret % +// CHECK-LABEL: define void @_Z1gv(%class.C* noalias sret align 4 % C g() { return C(); } // CHECK-LABEL: define void @_Z1f1C(%class.C* %0) @@ -103,13 +103,13 @@ struct s7_1 { double x; }; struct s7 : s7_0, s7_1 { }; s7 f7() { return s7(); } -// CHECK-LABEL: define void @_Z2f8v(%struct.s8* noalias sret %agg.result) +// CHECK-LABEL: define void @_Z2f8v(%struct.s8* noalias sret align 4 %agg.result) struct s8_0 { }; struct s8_1 { double x; }; struct s8 { s8_0 a; s8_1 b; }; s8 f8() { return s8(); } -// CHECK-LABEL: define void @_Z2f9v(%struct.s9* noalias sret %agg.result) +// CHECK-LABEL: define void @_Z2f9v(%struct.s9* noalias sret align 4 %agg.result) struct s9_0 { unsigned : 0; }; struct s9_1 { double x; }; struct s9 { s9_0 a; s9_1 b; }; diff --git a/clang/test/CodeGenCXX/x86_64-arguments.cpp b/clang/test/CodeGenCXX/x86_64-arguments.cpp index e905907788950..f7a898b220af7 100644 --- a/clang/test/CodeGenCXX/x86_64-arguments.cpp +++ b/clang/test/CodeGenCXX/x86_64-arguments.cpp @@ -176,7 +176,7 @@ namespace test9 { // CHECK: define void @_ZN5test93fooEPNS_1SEPNS_1TE([[S:%.*]]* %0, [[T:%.*]]* %1) void foo(S*, T*) {} - // CHECK: define void @_ZN5test91aEiiiiNS_1TEPv([[S]]* noalias sret {{%.*}}, i32 %0, i32 %1, i32 %2, i32 %3, [[T]]* byval([[T]]) align 8 %4, i8* %5) + // CHECK: define void @_ZN5test91aEiiiiNS_1TEPv([[S]]* noalias sret align 8 {{%.*}}, i32 %0, i32 %1, i32 %2, i32 %3, [[T]]* byval([[T]]) align 8 %4, i8* %5) S a(int, int, int, int, T, void*) { return S(); } @@ -186,7 +186,7 @@ namespace test9 { return sret; } - // CHECK: define void @_ZN5test91cEiiiNS_1TEPv([[S]]* noalias sret {{%.*}}, i32 %0, i32 %1, i32 %2, i8* {{%.*}}, i8* {{%.*}}, i8* %3) + // CHECK: define void @_ZN5test91cEiiiNS_1TEPv([[S]]* noalias sret align 8 {{%.*}}, i32 %0, i32 %1, i32 %2, i8* {{%.*}}, i8* {{%.*}}, i8* %3) S c(int, int, int, T, void*) { return S(); } diff --git a/clang/test/CodeGenCoroutines/coro-await.cpp b/clang/test/CodeGenCoroutines/coro-await.cpp index 86bacc766db3f..99097f376aa57 100644 --- a/clang/test/CodeGenCoroutines/coro-await.cpp +++ b/clang/test/CodeGenCoroutines/coro-await.cpp @@ -130,7 +130,7 @@ extern "C" void f1(int) { // CHECK: %[[PROMISE:.+]] = alloca %"struct.std::experimental::coroutine_traits::promise_type" // CHECK: %[[FRAME:.+]] = call i8* @llvm.coro.begin( co_yield 42; - // CHECK: call void @_ZNSt12experimental16coroutine_traitsIJviEE12promise_type11yield_valueEi(%struct.suspend_maybe* sret %[[AWAITER:.+]], %"struct.std::experimental::coroutine_traits::promise_type"* %[[PROMISE]], i32 42) + // CHECK: call void @_ZNSt12experimental16coroutine_traitsIJviEE12promise_type11yield_valueEi(%struct.suspend_maybe* sret align 4 %[[AWAITER:.+]], %"struct.std::experimental::coroutine_traits::promise_type"* %[[PROMISE]], i32 42) // See if we need to suspend: // -------------------------- @@ -197,20 +197,20 @@ extern "C" void UseAggr(Aggr&&); extern "C" void TestAggr() { UseAggr(co_await AggrAwaiter{}); Whatever(); - // CHECK: call void @_ZN11AggrAwaiter12await_resumeEv(%struct.Aggr* sret %[[AwaitResume:.+]], + // CHECK: call void @_ZN11AggrAwaiter12await_resumeEv(%struct.Aggr* sret align 4 %[[AwaitResume:.+]], // CHECK: call void @UseAggr(%struct.Aggr* dereferenceable(12) %[[AwaitResume]]) // CHECK: call void @_ZN4AggrD1Ev(%struct.Aggr* %[[AwaitResume]]) // CHECK: call void @Whatever() co_await AggrAwaiter{}; Whatever(); - // CHECK: call void @_ZN11AggrAwaiter12await_resumeEv(%struct.Aggr* sret %[[AwaitResume2:.+]], + // CHECK: call void @_ZN11AggrAwaiter12await_resumeEv(%struct.Aggr* sret align 4 %[[AwaitResume2:.+]], // CHECK: call void @_ZN4AggrD1Ev(%struct.Aggr* %[[AwaitResume2]]) // CHECK: call void @Whatever() Aggr Val = co_await AggrAwaiter{}; Whatever(); - // CHECK: call void @_ZN11AggrAwaiter12await_resumeEv(%struct.Aggr* sret %[[AwaitResume3:.+]], + // CHECK: call void @_ZN11AggrAwaiter12await_resumeEv(%struct.Aggr* sret align 4 %[[AwaitResume3:.+]], // CHECK: call void @Whatever() // CHECK: call void @_ZN4AggrD1Ev(%struct.Aggr* %[[AwaitResume3]]) } @@ -253,7 +253,7 @@ extern "C" void TestOpAwait() { co_await MyAgg{}; // CHECK: call void @_ZN5MyAggawEv(%struct.MyAgg* % - // CHECK: call void @_ZN11AggrAwaiter12await_resumeEv(%struct.Aggr* sret % + // CHECK: call void @_ZN11AggrAwaiter12await_resumeEv(%struct.Aggr* sret align 4 % } // CHECK-LABEL: EndlessLoop( diff --git a/clang/test/CodeGenCoroutines/coro-gro-nrvo.cpp b/clang/test/CodeGenCoroutines/coro-gro-nrvo.cpp index f4a71864ea0ec..890dc85991206 100644 --- a/clang/test/CodeGenCoroutines/coro-gro-nrvo.cpp +++ b/clang/test/CodeGenCoroutines/coro-gro-nrvo.cpp @@ -34,14 +34,14 @@ struct coro { }; // Verify that the NRVO is applied to the Gro object. -// CHECK-LABEL: define void @_Z1fi(%struct.coro* noalias sret %agg.result, i32 %0) +// CHECK-LABEL: define void @_Z1fi(%struct.coro* noalias sret align 8 %agg.result, i32 %0) coro f(int) { // CHECK: %call = call i8* @_Znwm( // CHECK-NEXT: br label %[[CoroInit:.*]] // CHECK: {{.*}}[[CoroInit]]: // CHECK: store i1 false, i1* %gro.active -// CHECK: call void @{{.*get_return_objectEv}}(%struct.coro* sret %agg.result +// CHECK: call void @{{.*get_return_objectEv}}(%struct.coro* sret align 8 %agg.result // CHECK-NEXT: store i1 true, i1* %gro.active co_return; } @@ -65,7 +65,7 @@ struct coro_two { }; // Verify that the NRVO is applied to the Gro object. -// CHECK-LABEL: define void @_Z1hi(%struct.coro_two* noalias sret %agg.result, i32 %0) +// CHECK-LABEL: define void @_Z1hi(%struct.coro_two* noalias sret align 8 %agg.result, i32 %0) coro_two h(int) { // CHECK: %call = call i8* @_ZnwmRKSt9nothrow_t @@ -73,12 +73,12 @@ struct coro_two { // CHECK-NEXT: br i1 %[[CheckNull]], label %[[InitOnSuccess:.*]], label %[[InitOnFailure:.*]] // CHECK: {{.*}}[[InitOnFailure]]: -// CHECK-NEXT: call void @{{.*get_return_object_on_allocation_failureEv}}(%struct.coro_two* sret %agg.result +// CHECK-NEXT: call void @{{.*get_return_object_on_allocation_failureEv}}(%struct.coro_two* sret align 8 %agg.result // CHECK-NEXT: br label %[[RetLabel:.*]] // CHECK: {{.*}}[[InitOnSuccess]]: // CHECK: store i1 false, i1* %gro.active -// CHECK: call void @{{.*get_return_objectEv}}(%struct.coro_two* sret %agg.result +// CHECK: call void @{{.*get_return_objectEv}}(%struct.coro_two* sret align 8 %agg.result // CHECK-NEXT: store i1 true, i1* %gro.active // CHECK: [[RetLabel]]: diff --git a/clang/test/CodeGenObjC/arc-ternary-op.m b/clang/test/CodeGenObjC/arc-ternary-op.m index 4883143791a24..28567fcbe22e6 100644 --- a/clang/test/CodeGenObjC/arc-ternary-op.m +++ b/clang/test/CodeGenObjC/arc-ternary-op.m @@ -1,5 +1,7 @@ // RUN: %clang_cc1 -triple x86_64-apple-darwin10 -emit-llvm -fblocks -fobjc-arc -fobjc-runtime-has-weak -O2 -disable-llvm-passes -o - %s | FileCheck %s +id g0, g1; + void test0(_Bool cond) { id test0_helper(void) __attribute__((ns_returns_retained)); @@ -147,4 +149,58 @@ void test2(int cond) { // CHECK: call void @llvm.objc.release(i8* [[RESULT]]) } +void test3(int cond) { + __strong id *p = cond ? (__strong id[]){g0, g1} : (__strong id[]){g1, g0}; + test2(cond); + + // CHECK: define void @test3( + // CHECK: %[[P:.*]] = alloca i8**, align 8 + // CHECK: %[[_COMPOUNDLITERAL:.*]] = alloca [2 x i8*], align 8 + // CHECK: %[[CLEANUP_COND:.*]] = alloca i1, align 1 + // CHECK: %[[_COMPOUNDLITERAL1:.*]] = alloca [2 x i8*], align 8 + // CHECK: %[[CLEANUP_COND4:.*]] = alloca i1, align 1 + + // CHECK: %[[ARRAYINIT_BEGIN:.*]] = getelementptr inbounds [2 x i8*], [2 x i8*]* %[[_COMPOUNDLITERAL]], i64 0, i64 0 + // CHECK: %[[V2:.*]] = load i8*, i8** @g0, align 8 + // CHECK: %[[V3:.*]] = call i8* @llvm.objc.retain(i8* %[[V2]]) + // CHECK: store i8* %[[V3]], i8** %[[ARRAYINIT_BEGIN]], align 8 + // CHECK: %[[ARRAYINIT_ELEMENT:.*]] = getelementptr inbounds i8*, i8** %[[ARRAYINIT_BEGIN]], i64 1 + // CHECK: %[[V4:.*]] = load i8*, i8** @g1, align 8 + // CHECK: %[[V5:.*]] = call i8* @llvm.objc.retain(i8* %[[V4]]) + // CHECK: store i8* %[[V5]], i8** %[[ARRAYINIT_ELEMENT]], align 8 + // CHECK: store i1 true, i1* %[[CLEANUP_COND]], align 1 + // CHECK: %[[ARRAYDECAY:.*]] = getelementptr inbounds [2 x i8*], [2 x i8*]* %[[_COMPOUNDLITERAL]], i64 0, i64 0 + + // CHECK: %[[ARRAYINIT_BEGIN2:.*]] = getelementptr inbounds [2 x i8*], [2 x i8*]* %[[_COMPOUNDLITERAL1]], i64 0, i64 0 + // CHECK: %[[V6:.*]] = load i8*, i8** @g1, align 8 + // CHECK: %[[V7:.*]] = call i8* @llvm.objc.retain(i8* %[[V6]]) + // CHECK: store i8* %[[V7]], i8** %[[ARRAYINIT_BEGIN2]], align 8 + // CHECK: %[[ARRAYINIT_ELEMENT3:.*]] = getelementptr inbounds i8*, i8** %[[ARRAYINIT_BEGIN2]], i64 1 + // CHECK: %[[V8:.*]] = load i8*, i8** @g0, align 8 + // CHECK: %[[V9:.*]] = call i8* @llvm.objc.retain(i8* %[[V8]]) + // CHECK: store i8* %[[V9]], i8** %[[ARRAYINIT_ELEMENT3]], align 8 + // CHECK: store i1 true, i1* %[[CLEANUP_COND4]], align 1 + // CHECK: %[[ARRAYDECAY5:.*]] = getelementptr inbounds [2 x i8*], [2 x i8*]* %[[_COMPOUNDLITERAL1]], i64 0, i64 0 + + // CHECK: %[[COND6:.*]] = phi i8** [ %[[ARRAYDECAY]], %{{.*}} ], [ %[[ARRAYDECAY5]], %{{.*}} ] + // CHECK: store i8** %[[COND6]], i8*** %[[P]], align 8 + // CHECK: call void @test2( + + // CHECK: %[[ARRAY_BEGIN:.*]] = getelementptr inbounds [2 x i8*], [2 x i8*]* %[[_COMPOUNDLITERAL1]], i32 0, i32 0 + // CHECK: %[[V11:.*]] = getelementptr inbounds i8*, i8** %[[ARRAY_BEGIN]], i64 2 + + // CHECK: %[[ARRAYDESTROY_ELEMENTPAST:.*]] = phi i8** [ %[[V11]], %{{.*}} ], [ %[[ARRAYDESTROY_ELEMENT:.*]], %{{.*}} ] + // CHECK: %[[ARRAYDESTROY_ELEMENT]] = getelementptr inbounds i8*, i8** %[[ARRAYDESTROY_ELEMENTPAST]], i64 -1 + // CHECK: %[[V12:.*]] = load i8*, i8** %[[ARRAYDESTROY_ELEMENT]], align 8 + // CHECK: call void @llvm.objc.release(i8* %[[V12]]) + + // CHECK: %[[ARRAY_BEGIN10:.*]] = getelementptr inbounds [2 x i8*], [2 x i8*]* %[[_COMPOUNDLITERAL]], i32 0, i32 0 + // CHECK: %[[V13:.*]] = getelementptr inbounds i8*, i8** %[[ARRAY_BEGIN10]], i64 2 + + // CHECK: %[[ARRAYDESTROY_ELEMENTPAST12:.*]] = phi i8** [ %[[V13]], %{{.*}} ], [ %[[ARRAYDESTROY_ELEMENT13:.*]], %{{.*}} ] + // CHECK: %[[ARRAYDESTROY_ELEMENT13]] = getelementptr inbounds i8*, i8** %[[ARRAYDESTROY_ELEMENTPAST12]], i64 -1 + // CHECK: %[[V14:.*]] = load i8*, i8** %[[ARRAYDESTROY_ELEMENT13]], align 8 + // CHECK: call void @llvm.objc.release(i8* %[[V14]]) +} + // CHECK: attributes [[NUW]] = { nounwind } diff --git a/clang/test/CodeGenObjC/arc.m b/clang/test/CodeGenObjC/arc.m index 31ecb53713be8..375ad8ed7b416 100644 --- a/clang/test/CodeGenObjC/arc.m +++ b/clang/test/CodeGenObjC/arc.m @@ -1536,27 +1536,61 @@ void test70(id i) { // CHECK-LABEL: define void @test71 void test71(void) { - // FIXME: It would be nice if the __destructor_8_s40 for the first call (and - // the following lifetime.end) came before the second call. - // // CHECK: %[[T:[^ ]+]] = bitcast %struct.AggDtor* %[[TMP1:[^ ]+]] to i8* // CHECK: call void @llvm.lifetime.start.p0i8({{[^,]+}}, i8* %[[T]]) - // CHECK: call void @getAggDtor(%struct.AggDtor* sret %[[TMP1]]) + // CHECK: call void @getAggDtor(%struct.AggDtor* sret align 8 %[[TMP1]]) + // CHECK: %[[T:[^ ]+]] = bitcast %struct.AggDtor* %[[TMP1]] to i8** + // CHECK: call void @__destructor_8_s40(i8** %[[T]]) + // CHECK: %[[T:[^ ]+]] = bitcast %struct.AggDtor* %[[TMP1:[^ ]+]] to i8* + // CHECK: call void @llvm.lifetime.end.p0i8({{[^,]+}}, i8* %[[T]]) // CHECK: %[[T:[^ ]+]] = bitcast %struct.AggDtor* %[[TMP2:[^ ]+]] to i8* // CHECK: call void @llvm.lifetime.start.p0i8({{[^,]+}}, i8* %[[T]]) - // CHECK: call void @getAggDtor(%struct.AggDtor* sret %[[TMP2]]) + // CHECK: call void @getAggDtor(%struct.AggDtor* sret align 8 %[[TMP2]]) // CHECK: %[[T:[^ ]+]] = bitcast %struct.AggDtor* %[[TMP2]] to i8** // CHECK: call void @__destructor_8_s40(i8** %[[T]]) // CHECK: %[[T:[^ ]+]] = bitcast %struct.AggDtor* %[[TMP2:[^ ]+]] to i8* // CHECK: call void @llvm.lifetime.end.p0i8({{[^,]+}}, i8* %[[T]]) - // CHECK: %[[T:[^ ]+]] = bitcast %struct.AggDtor* %[[TMP1]] to i8** - // CHECK: call void @__destructor_8_s40(i8** %[[T]]) - // CHECK: %[[T:[^ ]+]] = bitcast %struct.AggDtor* %[[TMP1:[^ ]+]] to i8* - // CHECK: call void @llvm.lifetime.end.p0i8({{[^,]+}}, i8* %[[T]]) getAggDtor(); getAggDtor(); } +// Check that no extra release calls are emitted to detruct the compond literal. + +// CHECK: define void @test72(i8* %[[A:.*]], i8* %[[B:.*]]) +// CHECK: %[[A_ADDR:.*]] = alloca i8*, align 8 +// CHECK: %[[B_ADDR:.*]] = alloca i8*, align 8 +// CHECK: %[[T:.*]] = alloca [2 x i8*], align 16 +// CHECK: %[[V0:.*]] = call i8* @llvm.objc.retain(i8* %[[A]]) +// CHECK: %[[V1:.*]] = call i8* @llvm.objc.retain(i8* %[[B]]) #2 +// CHECK: %[[ARRAYINIT_BEGIN:.*]] = getelementptr inbounds [2 x i8*], [2 x i8*]* %[[T]], i64 0, i64 0 +// CHECK: %[[V3:.*]] = load i8*, i8** %[[A_ADDR]], align 8, !tbaa !7 +// CHECK: %[[V4:.*]] = call i8* @llvm.objc.retain(i8* %[[V3]]) #2 +// CHECK: store i8* %[[V4]], i8** %[[ARRAYINIT_BEGIN]], align 8, !tbaa !7 +// CHECK: %[[ARRAYINIT_ELEMENT:.*]] = getelementptr inbounds i8*, i8** %[[ARRAYINIT_BEGIN]], i64 1 +// CHECK: %[[V5:.*]] = load i8*, i8** %[[B_ADDR]], align 8, !tbaa !7 +// CHECK: %[[V6:.*]] = call i8* @llvm.objc.retain(i8* %[[V5]]) #2 +// CHECK: store i8* %[[V6]], i8** %[[ARRAYINIT_ELEMENT]], align 8, !tbaa !7 +// CHECK: %[[ARRAY_BEGIN:.*]] = getelementptr inbounds [2 x i8*], [2 x i8*]* %[[T]], i32 0, i32 0 +// CHECK: %[[V7:.*]] = getelementptr inbounds i8*, i8** %[[ARRAY_BEGIN]], i64 2 + +// CHECK-NOT: call void @llvm.objc.release + +// CHECK: %[[ARRAYDESTROY_ELEMENTPAST:.*]] = phi i8** [ %[[V7]], %{{.*}} ], [ %[[ARRAYDESTROY_ELEMENT:.*]], %{{.*}} ] +// CHECK: %[[ARRAYDESTROY_ELEMENT]] = getelementptr inbounds i8*, i8** %[[ARRAYDESTROY_ELEMENTPAST]], i64 -1 +// CHECK: %[[V8:.*]] = load i8*, i8** %[[ARRAYDESTROY_ELEMENT]], align 8 +// CHECK: call void @llvm.objc.release(i8* %[[V8]]) #2, !clang.imprecise_release !10 + +// CHECK-NOT: call void @llvm.objc.release + +// CHECK: %[[V10:.*]] = load i8*, i8** %[[B_ADDR]], align 8 +// CHECK: call void @llvm.objc.release(i8* %[[V10]]) #2, !clang.imprecise_release !10 +// CHECK: %[[V11:.*]] = load i8*, i8** %[[A_ADDR]], align 8 +// CHECK: call void @llvm.objc.release(i8* %[[V11]]) #2, !clang.imprecise_release !10 + +void test72(id a, id b) { + __strong id t[] = (__strong id[]){a, b}; +} + // ARC-ALIEN: attributes [[NLB]] = { nonlazybind } // ARC-NATIVE: attributes [[NLB]] = { nonlazybind } // CHECK: attributes [[NUW]] = { nounwind } diff --git a/clang/test/CodeGenObjC/direct-method.m b/clang/test/CodeGenObjC/direct-method.m index e53c99bc0f5e8..5bb84de1ddb58 100644 --- a/clang/test/CodeGenObjC/direct-method.m +++ b/clang/test/CodeGenObjC/direct-method.m @@ -120,7 +120,7 @@ + (struct my_complex_struct)classGetComplex __attribute__((objc_direct)) { // CHECK-LABEL: define hidden void @"\01-[Root getAggregate]"( - (struct my_aggregate_struct)getAggregate __attribute__((objc_direct)) { - // CHECK: %struct.my_aggregate_struct* noalias sret [[RETVAL:%[^,]*]], + // CHECK: %struct.my_aggregate_struct* noalias sret align 4 [[RETVAL:%[^,]*]], // loading parameters // CHECK-LABEL: entry: diff --git a/clang/test/CodeGenObjC/nontrivial-c-struct-exception.m b/clang/test/CodeGenObjC/nontrivial-c-struct-exception.m index 1733a019026c0..8d66485959a8c 100644 --- a/clang/test/CodeGenObjC/nontrivial-c-struct-exception.m +++ b/clang/test/CodeGenObjC/nontrivial-c-struct-exception.m @@ -41,8 +41,8 @@ void testStrongException(void) { // CHECK: define void @testWeakException() // CHECK: %[[AGG_TMP:.*]] = alloca %[[STRUCT_WEAK]], align 8 // CHECK: %[[AGG_TMP1:.*]] = alloca %[[STRUCT_WEAK]], align 8 -// CHECK: call void @genWeak(%[[STRUCT_WEAK]]* sret %[[AGG_TMP]]) -// CHECK: invoke void @genWeak(%[[STRUCT_WEAK]]* sret %[[AGG_TMP1]]) +// CHECK: call void @genWeak(%[[STRUCT_WEAK]]* sret align 8 %[[AGG_TMP]]) +// CHECK: invoke void @genWeak(%[[STRUCT_WEAK]]* sret align 8 %[[AGG_TMP1]]) // CHECK: call void @calleeWeak(%[[STRUCT_WEAK]]* %[[AGG_TMP]], %[[STRUCT_WEAK]]* %[[AGG_TMP1]]) // CHECK: ret void diff --git a/clang/test/CodeGenObjC/objc-non-trivial-struct-nrvo.m b/clang/test/CodeGenObjC/objc-non-trivial-struct-nrvo.m index 53ff433989e29..93f348185412a 100644 --- a/clang/test/CodeGenObjC/objc-non-trivial-struct-nrvo.m +++ b/clang/test/CodeGenObjC/objc-non-trivial-struct-nrvo.m @@ -37,7 +37,7 @@ Trivial testTrivial(void) { void func1(TrivialBig *); -// CHECK: define void @testTrivialBig(%[[STRUCT_TRIVIALBIG]]* noalias sret %[[AGG_RESULT:.*]]) +// CHECK: define void @testTrivialBig(%[[STRUCT_TRIVIALBIG]]* noalias sret align 4 %[[AGG_RESULT:.*]]) // CHECK: call void @func1(%[[STRUCT_TRIVIALBIG]]* %[[AGG_RESULT]]) // CHECK-NEXT: ret void @@ -69,7 +69,7 @@ Strong testStrong(void) { return a; } -// CHECK: define void @testWeak(%[[STRUCT_WEAK]]* noalias sret %[[AGG_RESULT:.*]]) +// CHECK: define void @testWeak(%[[STRUCT_WEAK]]* noalias sret align 8 %[[AGG_RESULT:.*]]) // CHECK: %[[NRVO:.*]] = alloca i1, align 1 // CHECK: %[[V0:.*]] = bitcast %[[STRUCT_WEAK]]* %[[AGG_RESULT]] to i8** // CHECK: call void @__default_constructor_8_w0(i8** %[[V0]]) @@ -105,7 +105,7 @@ Weak testWeak2(int c) { return b; } -// CHECK: define internal void @"\01-[C1 foo1]"(%[[STRUCT_WEAK]]* noalias sret %[[AGG_RESULT:.*]], %{{.*}}* %{{.*}}, i8* %{{.*}}) +// CHECK: define internal void @"\01-[C1 foo1]"(%[[STRUCT_WEAK]]* noalias sret align 8 %[[AGG_RESULT:.*]], %{{.*}}* %{{.*}}, i8* %{{.*}}) // CHECK: %[[NRVO:.*]] = alloca i1, align 1 // CHECK: %[[V0:.*]] = bitcast %[[STRUCT_WEAK]]* %[[AGG_RESULT]] to i8** // CHECK: call void @__default_constructor_8_w0(i8** %[[V0]]) diff --git a/clang/test/CodeGenObjC/stret-1.m b/clang/test/CodeGenObjC/stret-1.m index 1122c28a468bd..f25c40438e590 100644 --- a/clang/test/CodeGenObjC/stret-1.m +++ b/clang/test/CodeGenObjC/stret-1.m @@ -14,19 +14,19 @@ int main(int argc, const char **argv) { struct stret s; s = [(id)(argc&~255) method]; - // CHECK: call void bitcast (i8* (i8*, i8*, ...)* @objc_msgSend to void (%struct.stret*, i8*, i8*)*)(%struct.stret* sret [[T0:%[^,]+]] + // CHECK: call void bitcast (i8* (i8*, i8*, ...)* @objc_msgSend to void (%struct.stret*, i8*, i8*)*)(%struct.stret* sret align 4 [[T0:%[^,]+]] // CHECK: [[T0P:%.*]] = bitcast %struct.stret* [[T0]] to i8* // CHECK: call void @llvm.memset.p0i8.i64(i8* align 4 [[T0P]], i8 0, i64 400, i1 false) s = [Test method]; - // CHECK: call void bitcast (i8* (i8*, i8*, ...)* @objc_msgSend to void (%struct.stret*, i8*, i8*)*)(%struct.stret* sret [[T1:%[^,]+]] + // CHECK: call void bitcast (i8* (i8*, i8*, ...)* @objc_msgSend to void (%struct.stret*, i8*, i8*)*)(%struct.stret* sret align 4 [[T1:%[^,]+]] // CHECK-NOT: call void @llvm.memset.p0i8.i64( [(id)(argc&~255) method]; - // CHECK: call void bitcast (i8* (i8*, i8*, ...)* @objc_msgSend to void (%struct.stret*, i8*, i8*)*)(%struct.stret* sret [[T1:%[^,]+]] + // CHECK: call void bitcast (i8* (i8*, i8*, ...)* @objc_msgSend to void (%struct.stret*, i8*, i8*)*)(%struct.stret* sret align 4 [[T1:%[^,]+]] // CHECK-NOT: call void @llvm.memset.p0i8.i64( [Test method]; - // CHECK: call void bitcast (i8* (i8*, i8*, ...)* @objc_msgSend to void (%struct.stret*, i8*, i8*)*)(%struct.stret* sret [[T1:%[^,]+]] + // CHECK: call void bitcast (i8* (i8*, i8*, ...)* @objc_msgSend to void (%struct.stret*, i8*, i8*)*)(%struct.stret* sret align 4 [[T1:%[^,]+]] // CHECK-NOT: call void @llvm.memset.p0i8.i64( } diff --git a/clang/test/CodeGenObjC/strong-in-c-struct.m b/clang/test/CodeGenObjC/strong-in-c-struct.m index eae5013dd3fcb..f0227119279f4 100644 --- a/clang/test/CodeGenObjC/strong-in-c-struct.m +++ b/clang/test/CodeGenObjC/strong-in-c-struct.m @@ -89,6 +89,13 @@ void calleeStrongSmall(StrongSmall); void func(Strong *); +@interface C +- (StrongSmall)getStrongSmall; ++ (StrongSmall)getStrongSmallClass; +@end + +id g0; + // CHECK: %[[STRUCT_STRONGOUTER:.*]] = type { %[[STRUCT_STRONG:.*]], i8*, double } // CHECK: %[[STRUCT_STRONG]] = type { %[[STRUCT_TRIVIAL:.*]], i8* } // CHECK: %[[STRUCT_TRIVIAL]] = type { [4 x i32] } @@ -476,6 +483,18 @@ void test_destructor_ignored_result(void) { getStrongSmall(); } +// CHECK: define void @test_destructor_ignored_result2(%{{.*}}* %[[C:.*]]) +// CHECK: %[[TMP:.*]] = alloca %[[STRUCT_STRONGSMALL]], align 8 +// CHECK: %[[CALL:.*]] = call [2 x i64]{{.*}}@objc_msgSend +// CHECK: %[[V5:.*]] = bitcast %[[STRUCT_STRONGSMALL]]* %[[TMP]] to [2 x i64]* +// CHECK: store [2 x i64] %[[CALL]], [2 x i64]* %[[V5]], align 8 +// CHECK: %[[V6:.*]] = bitcast %[[STRUCT_STRONGSMALL]]* %[[TMP]] to i8** +// CHECK: call void @__destructor_8_s8(i8** %[[V6]]) + +void test_destructor_ignored_result2(C *c) { + [c getStrongSmall]; +} + // CHECK: define void @test_copy_constructor_StrongBlock( // CHECK: call void @__copy_constructor_8_8_sb0( // CHECK: call void @__destructor_8_sb0( @@ -520,7 +539,9 @@ void test_copy_assignment_StrongBlock(StrongBlock *d, StrongBlock *s) { // CHECK: define void @test_copy_constructor_StrongVolatile0( // CHECK: call void @__copy_constructor_8_8_t0w4_sv8( +// CHECK-NOT: call // CHECK: call void @__destructor_8_sv8( +// CHECK-NOT: call // CHECK: define linkonce_odr hidden void @__copy_constructor_8_8_t0w4_sv8( // CHECK: %[[V8:.*]] = load volatile i8*, i8** %{{.*}}, align 8 @@ -709,4 +730,174 @@ void test_copy_constructor_VolatileArray(VolatileArray *a) { VolatileArray t = *a; } +// CHECK: define void @test_compound_literal0( +// CHECK: %[[P:.*]] = alloca %[[STRUCT_STRONGSMALL]]*, align 8 +// CHECK: %[[_COMPOUNDLITERAL:.*]] = alloca %[[STRUCT_STRONGSMALL]], align 8 +// CHECK: %[[CLEANUP_COND:.*]] = alloca i1, align 1 +// CHECK: %[[_COMPOUNDLITERAL1:.*]] = alloca %[[STRUCT_STRONGSMALL]], align 8 +// CHECK: %[[CLEANUP_COND4:.*]] = alloca i1, align 1 + +// CHECK: %[[I:.*]] = getelementptr inbounds %[[STRUCT_STRONGSMALL]], %[[STRUCT_STRONGSMALL]]* %[[_COMPOUNDLITERAL]], i32 0, i32 0 +// CHECK: store i32 1, i32* %[[I]], align 8 +// CHECK: %[[F1:.*]] = getelementptr inbounds %[[STRUCT_STRONGSMALL]], %[[STRUCT_STRONGSMALL]]* %[[_COMPOUNDLITERAL]], i32 0, i32 1 +// CHECK: store i8* null, i8** %[[F1]], align 8 +// CHECK: store i1 true, i1* %[[CLEANUP_COND]], align 1 + +// CHECK: %[[I2:.*]] = getelementptr inbounds %[[STRUCT_STRONGSMALL]], %[[STRUCT_STRONGSMALL]]* %[[_COMPOUNDLITERAL1]], i32 0, i32 0 +// CHECK: store i32 2, i32* %[[I2]], align 8 +// CHECK: %[[F13:.*]] = getelementptr inbounds %[[STRUCT_STRONGSMALL]], %[[STRUCT_STRONGSMALL]]* %[[_COMPOUNDLITERAL1]], i32 0, i32 1 +// CHECK: store i8* null, i8** %[[F13]], align 8 +// CHECK: store i1 true, i1* %[[CLEANUP_COND4]], align 1 + +// CHECK: %[[COND:.*]] = phi %[[STRUCT_STRONGSMALL]]* [ %[[_COMPOUNDLITERAL]], %{{.*}} ], [ %[[_COMPOUNDLITERAL1]], %{{.*}} ] +// CHECK: store %[[STRUCT_STRONGSMALL]]* %[[COND]], %[[STRUCT_STRONGSMALL]]** %[[P]], align 8 +// CHECK: call void @func( + +// CHECK: %[[V1:.*]] = bitcast %[[STRUCT_STRONGSMALL]]* %[[_COMPOUNDLITERAL1]] to i8** +// CHECK: call void @__destructor_8_s8(i8** %[[V1]]) + +// CHECK: %[[V2:.*]] = bitcast %[[STRUCT_STRONGSMALL]]* %[[_COMPOUNDLITERAL]] to i8** +// CHECK: call void @__destructor_8_s8(i8** %[[V2]]) + +void test_compound_literal0(int c) { + StrongSmall *p = c ? &(StrongSmall){ 1, 0 } : &(StrongSmall){ 2, 0 }; + func(0); +} + +// Check that there is only one destructor call, which destructs 't'. + +// CHECK: define void @test_compound_literal1( +// CHECK: %[[T:.*]] = alloca %[[STRUCT_STRONGSMALL]], align 8 + +// CHECK: %[[I:.*]] = getelementptr inbounds %[[STRUCT_STRONGSMALL]], %[[STRUCT_STRONGSMALL]]* %[[T]], i32 0, i32 0 +// CHECK: store i32 1, i32* %[[I]], align 8 +// CHECK: %[[F1:.*]] = getelementptr inbounds %[[STRUCT_STRONGSMALL]], %[[STRUCT_STRONGSMALL]]* %[[T]], i32 0, i32 1 +// CHECK: store i8* null, i8** %[[F1]], align 8 + +// CHECK: %[[I1:.*]] = getelementptr inbounds %[[STRUCT_STRONGSMALL]], %[[STRUCT_STRONGSMALL]]* %[[T]], i32 0, i32 0 +// CHECK: store i32 2, i32* %[[I1]], align 8 +// CHECK: %[[F12:.*]] = getelementptr inbounds %[[STRUCT_STRONGSMALL]], %[[STRUCT_STRONGSMALL]]* %[[T]], i32 0, i32 1 +// CHECK: store i8* null, i8** %[[F12]], align 8 + +// CHECK: call void @func( +// CHECK-NOT: call void +// CHECK: %[[V1:.*]] = bitcast %[[STRUCT_STRONGSMALL]]* %[[T]] to i8** +// CHECK: call void @__destructor_8_s8(i8** %[[V1]]) +// CHECK-NOT: call void + +void test_compound_literal1(int c) { + StrongSmall t = c ? (StrongSmall){ 1, 0 } : (StrongSmall){ 2, 0 }; + func(0); +} + +// CHECK: define void @test_compound_literal2( +// CHECK: %[[P_ADDR:.*]] = alloca %[[STRUCT_STRONGSMALL]]*, align 8 +// CHECK: %[[_COMPOUNDLITERAL:.*]] = alloca %[[STRUCT_STRONGSMALL]], align 8 +// CHECK: %[[CLEANUP_COND:.*]] = alloca i1, align 1 +// CHECK: %[[_COMPOUNDLITERAL1:.*]] = alloca %[[STRUCT_STRONGSMALL]], align 8 +// CHECK: %[[CLEANUP_COND4:.*]] = alloca i1, align 1 +// CHECK: %[[V0:.*]] = load %[[STRUCT_STRONGSMALL]]*, %[[STRUCT_STRONGSMALL]]** %[[P_ADDR]], align 8 + +// CHECK: %[[I:.*]] = getelementptr inbounds %[[STRUCT_STRONGSMALL]], %[[STRUCT_STRONGSMALL]]* %[[_COMPOUNDLITERAL]], i32 0, i32 0 +// CHECK: store i32 1, i32* %[[I]], align 8 +// CHECK: %[[F1:.*]] = getelementptr inbounds %[[STRUCT_STRONGSMALL]], %[[STRUCT_STRONGSMALL]]* %[[_COMPOUNDLITERAL]], i32 0, i32 1 +// CHECK: store i8* null, i8** %[[F1]], align 8 +// CHECK: store i1 true, i1* %[[CLEANUP_COND]], align 1 +// CHECK: %[[V2:.*]] = bitcast %[[STRUCT_STRONGSMALL]]* %[[V0]] to i8** +// CHECK: %[[V3:.*]] = bitcast %[[STRUCT_STRONGSMALL]]* %[[_COMPOUNDLITERAL]] to i8** +// CHECK: call void @__copy_assignment_8_8_t0w4_s8(i8** %[[V2]], i8** %[[V3]]) + +// CHECK: %[[I2:.*]] = getelementptr inbounds %[[STRUCT_STRONGSMALL]], %[[STRUCT_STRONGSMALL]]* %[[_COMPOUNDLITERAL1]], i32 0, i32 0 +// CHECK: store i32 2, i32* %[[I2]], align 8 +// CHECK: %[[F13:.*]] = getelementptr inbounds %[[STRUCT_STRONGSMALL]], %[[STRUCT_STRONGSMALL]]* %[[_COMPOUNDLITERAL1]], i32 0, i32 1 +// CHECK: store i8* null, i8** %[[F13]], align 8 +// CHECK: store i1 true, i1* %[[CLEANUP_COND4]], align 1 +// CHECK: %[[V4:.*]] = bitcast %[[STRUCT_STRONGSMALL]]* %[[V0]] to i8** +// CHECK: %[[V5:.*]] = bitcast %[[STRUCT_STRONGSMALL]]* %[[_COMPOUNDLITERAL1]] to i8** +// CHECK: call void @__copy_assignment_8_8_t0w4_s8(i8** %[[V4]], i8** %[[V5]]) + +// CHECK: call void @func( + +// CHECK: %[[V6:.*]] = bitcast %[[STRUCT_STRONGSMALL]]* %[[_COMPOUNDLITERAL1]] to i8** +// CHECK: call void @__destructor_8_s8(i8** %[[V6]]) + +// CHECK: %[[V7:.*]] = bitcast %[[STRUCT_STRONGSMALL]]* %[[_COMPOUNDLITERAL]] to i8** +// CHECK: call void @__destructor_8_s8(i8** %[[V7]]) + +void test_compound_literal2(int c, StrongSmall *p) { + *p = c ? (StrongSmall){ 1, 0 } : (StrongSmall){ 2, 0 }; + func(0); +} + +// CHECK: define void @test_member_access( +// CHECK: %[[TMP:.*]] = alloca %[[STRUCT_STRONGSMALL]], +// CHECK: %[[V3:.*]] = bitcast %[[STRUCT_STRONGSMALL]]* %[[TMP]] to i8** +// CHECK: call void @__destructor_8_s8(i8** %[[V3]]) +// CHECK: call void @func( + +void test_member_access(void) { + g0 = getStrongSmall().f1; + func(0); +} + +// CHECK: define void @test_member_access2(%{{.*}}* %[[C:.*]]) +// CHECK: %[[COERCE:.*]] = alloca %[[STRUCT_STRONGSMALL]], align 8 +// CHECK: %[[V8:.*]] = bitcast %[[STRUCT_STRONGSMALL]]* %[[COERCE]] to i8** +// CHECK: call void @__destructor_8_s8(i8** %[[V8]]) +// CHECK: call void @func( + +void test_member_access2(C *c) { + g0 = [c getStrongSmall].f1; + func(0); +} + +// CHECK: define void @test_member_access3( +// CHECK: %[[COERCE:.*]] = alloca %[[STRUCT_STRONGSMALL]], align 8 +// CHECK: %[[V8:.*]] = bitcast %[[STRUCT_STRONGSMALL]]* %[[COERCE]] to i8** +// CHECK: call void @__destructor_8_s8(i8** %[[V8]]) +// CHECK: call void @func( + +void test_member_access3(void) { + g0 = [C getStrongSmallClass].f1; + func(0); +} + +// CHECK: define void @test_member_access4() +// CHECK: %[[COERCE:.*]] = alloca %[[STRUCT_STRONGSMALL]], align 8 +// CHECK: %[[V5:.*]] = bitcast %[[STRUCT_STRONGSMALL]]* %[[COERCE]] to i8** +// CHECK: call void @__destructor_8_s8(i8** %[[V5]]) +// CHECK: call void @func( + +void test_member_access4(void) { + g0 = ^{ StrongSmall s; return s; }().f1; + func(0); +} + +// CHECK: define void @test_volatile_variable_reference( +// CHECK: %[[AGG_TMP_ENSURED:.*]] = alloca %[[STRUCT_STRONGSMALL]], +// CHECK: %[[V1:.*]] = bitcast %[[STRUCT_STRONGSMALL]]* %[[AGG_TMP_ENSURED]] to i8** +// CHECK: %[[V2:.*]] = bitcast %[[STRUCT_STRONGSMALL]]* %{{.*}} to i8** +// CHECK: call void @__copy_constructor_8_8_tv0w32_sv8(i8** %[[V1]], i8** %[[V2]]) +// CHECK: %[[V3:.*]] = bitcast %[[STRUCT_STRONGSMALL]]* %[[AGG_TMP_ENSURED]] to i8** +// CHECK: call void @__destructor_8_s8(i8** %[[V3]]) +// CHECK: call void @func( + +void test_volatile_variable_reference(volatile StrongSmall *a) { + (void)*a; + func(0); +} + +struct ZeroBitfield { + int : 0; + id strong; +}; + + +// CHECK: define linkonce_odr hidden void @__default_constructor_8_sv0 +// CHECK: define linkonce_odr hidden void @__copy_assignment_8_8_sv0 +void test_zero_bitfield() { + struct ZeroBitfield volatile a, b; + a = b; +} + #endif /* USESTRUCT */ diff --git a/clang/test/CodeGenObjC/weak-in-c-struct.m b/clang/test/CodeGenObjC/weak-in-c-struct.m index 001a7ed96dec8..90c799298253b 100644 --- a/clang/test/CodeGenObjC/weak-in-c-struct.m +++ b/clang/test/CodeGenObjC/weak-in-c-struct.m @@ -179,7 +179,7 @@ void test_argument_Weak(Weak *a) { calleeWeak(*a); } -// COMMON: define void @test_return_Weak(%[[STRUCT_WEAK]]* noalias sret %[[AGG_RESULT:.*]], %[[STRUCT_WEAK]]* %[[A:.*]]) +// COMMON: define void @test_return_Weak(%[[STRUCT_WEAK]]* noalias sret align {{.*}} %[[AGG_RESULT:.*]], %[[STRUCT_WEAK]]* %[[A:.*]]) // COMMON: %[[A_ADDR:.*]] = alloca %[[STRUCT_WEAK]]* // COMMON: store %[[STRUCT_WEAK]]* %[[A]], %[[STRUCT_WEAK]]** %[[A_ADDR]] // COMMON: %[[V0:.*]] = load %[[STRUCT_WEAK]]*, %[[STRUCT_WEAK]]** %[[A_ADDR]] diff --git a/clang/test/CodeGenObjCXX/block-nested-in-lambda.mm b/clang/test/CodeGenObjCXX/block-nested-in-lambda.mm index be1ad8117cd25..c7b9a043a9e95 100644 --- a/clang/test/CodeGenObjCXX/block-nested-in-lambda.mm +++ b/clang/test/CodeGenObjCXX/block-nested-in-lambda.mm @@ -1,6 +1,9 @@ -// RUN: %clang_cc1 -triple=x86_64-apple-darwin10 -emit-llvm -std=c++11 -fblocks -fobjc-arc -o - %s | FileCheck %s +// RUN: %clang_cc1 -triple=x86_64-apple-darwin10 -emit-llvm -std=c++14 -fblocks -fobjc-arc -o - %s | FileCheck %s // CHECK: %[[STRUCT_BLOCK_DESCRIPTOR:.*]] = type { i64, i64 } +// CHECK: %[[S:.*]] = type { i32 } +// CHECK: %[[CLASS_ANON_2:.*]] = type { %[[S]]* } +// CHECK: %[[CLASS_ANON_3:.*]] = type { %[[S]] } // CHECK: %[[BLOCK_CAPTURED0:.*]] = getelementptr inbounds <{ i8*, i32, i32, i8*, %struct.__block_descriptor*, i32*, i32* }>, <{ i8*, i32, i32, i8*, %struct.__block_descriptor*, i32*, i32* }>* %[[BLOCK:.*]], i32 0, i32 5 // CHECK: %[[V0:.*]] = getelementptr inbounds %[[LAMBDA_CLASS:.*]], %[[LAMBDA_CLASS]]* %[[THIS:.*]], i32 0, i32 0 @@ -33,7 +36,7 @@ void block_in_lambda(int &s1, int &s2) { // reference. // CHECK-LABEL: define void @_ZN18CaptureByReference5test0Ev( -// CHECK-LABEL: define internal void @"_ZZN18CaptureByReference5test0EvENK3$_1clEv"( +// CHECK-LABEL: define internal void @"_ZZN18CaptureByReference5test0EvENK3$_3clEv"( // CHECK: %[[BLOCK_DESCRIPTOR:.*]] = getelementptr inbounds <{ i8*, i32, i32, i8*, %[[STRUCT_BLOCK_DESCRIPTOR]]*, i8** }>, <{ i8*, i32, i32, i8*, %[[STRUCT_BLOCK_DESCRIPTOR]]*, i8** }>* %{{.*}}, i32 0, i32 4 // CHECK: store %[[STRUCT_BLOCK_DESCRIPTOR]]* bitcast ({ i64, i64, i8*, i64 }* @"__block_descriptor_40_e5_v8\01?0ls32l8" to %[[STRUCT_BLOCK_DESCRIPTOR]]*), %[[STRUCT_BLOCK_DESCRIPTOR]]** %[[BLOCK_DESCRIPTOR]], align 8 @@ -46,10 +49,60 @@ void test0() { // is captured by reference. // CHECK-LABEL: define void @_ZN18CaptureByReference5test1Ev( -// CHECK-LABEL: define internal void @"_ZZN18CaptureByReference5test1EvENK3$_2clEv"( +// CHECK-LABEL: define internal void @"_ZZN18CaptureByReference5test1EvENK3$_4clEv"( // CHECK: %[[BLOCK_DESCRIPTOR:.*]] = getelementptr inbounds <{ i8*, i32, i32, i8*, %[[STRUCT_BLOCK_DESCRIPTOR]]*, i8*, i8*, i8** }>, <{ i8*, i32, i32, i8*, %[[STRUCT_BLOCK_DESCRIPTOR]]*, i8*, i8*, i8** }>* %{{.*}}, i32 0, i32 4 // CHECK: store %[[STRUCT_BLOCK_DESCRIPTOR]]* bitcast ({ i64, i64, i8*, i8*, i8*, i64 }* @"__block_descriptor_56_8_32s40s_e5_v8\01?0l" to %[[STRUCT_BLOCK_DESCRIPTOR]]*), %[[STRUCT_BLOCK_DESCRIPTOR]]** %[[BLOCK_DESCRIPTOR]], align 8 +void test1() { + id a = getObj(), b = getObj(), c = getObj(); + [&a, b, c]{ ^{ a = 0; use(b); use(c); }(); }(); +} + +struct S { + int val() const; + int a; + S(); + S(const S&); + S &operator=(const S&); + S(S&&); + S &operator=(S&&); +}; + +S getS(); + +// CHECK: define internal i32 @"_ZZN18CaptureByReference5test2EvENK3$_1clIiEEDaT_"(%[[CLASS_ANON_2]]* %{{.*}}, i32 %{{.*}}) +// CHECK: %[[BLOCK:.*]] = alloca <{ i8*, i32, i32, i8*, %{{.*}}, %[[S]]* }>, align 8 +// CHECK: %[[BLOCK_CAPTURED:.*]] = getelementptr inbounds <{ i8*, i32, i32, i8*, %{{.*}}, %[[S]]* }>, <{ i8*, i32, i32, i8*, %{{.*}}, %[[S]]* }>* %[[BLOCK]], i32 0, i32 5 +// CHECK: %[[V0:.*]] = getelementptr inbounds %[[CLASS_ANON_2]], %[[CLASS_ANON_2]]* %{{.*}}, i32 0, i32 0 +// CHECK: %[[V1:.*]] = load %[[S]]*, %[[S]]** %[[V0]], align 8 +// CHECK: store %[[S]]* %[[V1]], %[[S]]** %[[BLOCK_CAPTURED]], align 8 + +int test2() { + S s; + auto fn = [&](const auto a){ + return ^{ + return s.val(); + }(); + }; + return fn(123); +} + +// CHECK: define internal i32 @"_ZZN18CaptureByReference5test3EvENK3$_2clIiEEDaT_"(%[[CLASS_ANON_3]]* %{{.*}}, i32 %{{.*}}) +// CHECK: %[[BLOCK:.*]] = alloca <{ i8*, i32, i32, i8*, %{{.*}}*, %[[S]] }>, align 8 +// CHECK: %[[BLOCK_CAPTURED:.*]] = getelementptr inbounds <{ i8*, i32, i32, i8*, %{{.*}}*, %[[S]] }>, <{ i8*, i32, i32, i8*, %{{.*}}*, %[[S]] }>* %[[BLOCK]], i32 0, i32 5 +// CHECK: %[[V0:.*]] = getelementptr inbounds %[[CLASS_ANON_3]], %[[CLASS_ANON_3]]* %{{.*}}, i32 0, i32 0 +// CHECK: call void @_ZN18CaptureByReference1SC1ERKS0_(%[[S]]* %[[BLOCK_CAPTURED]], %[[S]]* {{.*}} %[[V0]]) + +int test3() { + const S &s = getS(); + auto fn = [=](const auto a){ + return ^{ + return s.val(); + }(); + }; + return fn(123); +} + // CHECK-LABEL: define linkonce_odr hidden void @__copy_helper_block_8_32s40s( // CHECK-NOT: call void @llvm.objc.storeStrong( // CHECK: %[[V4:.*]] = getelementptr inbounds <{ i8*, i32, i32, i8*, %[[STRUCT_BLOCK_DESCRIPTOR]]*, i8*, i8*, i8** }>, <{ i8*, i32, i32, i8*, %[[STRUCT_BLOCK_DESCRIPTOR]]*, i8*, i8*, i8** }>* %{{.*}}, i32 0, i32 5 @@ -74,9 +127,4 @@ void test0() { // CHECK-NOT: call void @llvm.objc.storeStrong( // CHECK: ret void -void test1() { - id a = getObj(), b = getObj(), c = getObj(); - [&a, b, c]{ ^{ a = 0; use(b); use(c); }(); }(); -} - } diff --git a/clang/test/CodeGenObjCXX/objc-struct-cxx-abi.mm b/clang/test/CodeGenObjCXX/objc-struct-cxx-abi.mm index dd9b88b0234d0..8bb694705fef1 100644 --- a/clang/test/CodeGenObjCXX/objc-struct-cxx-abi.mm +++ b/clang/test/CodeGenObjCXX/objc-struct-cxx-abi.mm @@ -90,7 +90,7 @@ void testCallStrongWeak(StrongWeak *a) { testParamStrongWeak(*a); } -// CHECK: define void @_Z20testReturnStrongWeakP10StrongWeak(%[[STRUCT_STRONGWEAK:.*]]* noalias sret %[[AGG_RESULT:.*]], %[[STRUCT_STRONGWEAK]]* %[[A:.*]]) +// CHECK: define void @_Z20testReturnStrongWeakP10StrongWeak(%[[STRUCT_STRONGWEAK:.*]]* noalias sret align 8 %[[AGG_RESULT:.*]], %[[STRUCT_STRONGWEAK]]* %[[A:.*]]) // CHECK: %[[A_ADDR:.*]] = alloca %[[STRUCT_STRONGWEAK]]*, align 8 // CHECK: store %[[STRUCT_STRONGWEAK]]* %[[A]], %[[STRUCT_STRONGWEAK]]** %[[A_ADDR]], align 8 // CHECK: %[[V0:.*]] = load %[[STRUCT_STRONGWEAK]]*, %[[STRUCT_STRONGWEAK]]** %[[A_ADDR]], align 8 diff --git a/clang/test/CodeGenOpenCL/addr-space-struct-arg.cl b/clang/test/CodeGenOpenCL/addr-space-struct-arg.cl index cdbf28bbcad87..35cc54c50d6f2 100644 --- a/clang/test/CodeGenOpenCL/addr-space-struct-arg.cl +++ b/clang/test/CodeGenOpenCL/addr-space-struct-arg.cl @@ -43,7 +43,7 @@ struct LargeStructTwoMember { struct LargeStructOneMember g_s; #endif -// X86-LABEL: define void @foo(%struct.Mat4X4* noalias sret %agg.result, %struct.Mat3X3* byval(%struct.Mat3X3) align 4 %in) +// X86-LABEL: define void @foo(%struct.Mat4X4* noalias sret align 4 %agg.result, %struct.Mat3X3* byval(%struct.Mat3X3) align 4 %in) // AMDGCN-LABEL: define %struct.Mat4X4 @foo([9 x i32] %in.coerce) Mat4X4 __attribute__((noinline)) foo(Mat3X3 in) { Mat4X4 out; @@ -63,8 +63,8 @@ kernel void ker(global Mat3X3 *in, global Mat4X4 *out) { out[0] = foo(in[1]); } -// X86-LABEL: define void @foo_large(%struct.Mat64X64* noalias sret %agg.result, %struct.Mat32X32* byval(%struct.Mat32X32) align 4 %in) -// AMDGCN-LABEL: define void @foo_large(%struct.Mat64X64 addrspace(5)* noalias sret %agg.result, %struct.Mat32X32 addrspace(5)* byval(%struct.Mat32X32) align 4 %in) +// X86-LABEL: define void @foo_large(%struct.Mat64X64* noalias sret align 4 %agg.result, %struct.Mat32X32* byval(%struct.Mat32X32) align 4 %in) +// AMDGCN-LABEL: define void @foo_large(%struct.Mat64X64 addrspace(5)* noalias sret align 4 %agg.result, %struct.Mat32X32 addrspace(5)* byval(%struct.Mat32X32) align 4 %in) Mat64X64 __attribute__((noinline)) foo_large(Mat32X32 in) { Mat64X64 out; return out; diff --git a/clang/test/CodeGenOpenCL/amdgpu-abi-struct-coerce.cl b/clang/test/CodeGenOpenCL/amdgpu-abi-struct-coerce.cl index 0a7f289cb2f7c..fd46d3cce22e4 100644 --- a/clang/test/CodeGenOpenCL/amdgpu-abi-struct-coerce.cl +++ b/clang/test/CodeGenOpenCL/amdgpu-abi-struct-coerce.cl @@ -404,14 +404,14 @@ struct_arr16 func_ret_struct_arr16() return s; } -// CHECK: define void @func_ret_struct_arr32(%struct.struct_arr32 addrspace(5)* noalias nocapture sret %agg.result) +// CHECK: define void @func_ret_struct_arr32(%struct.struct_arr32 addrspace(5)* noalias nocapture sret align 4 %agg.result) struct_arr32 func_ret_struct_arr32() { struct_arr32 s = { 0 }; return s; } -// CHECK: define void @func_ret_struct_arr33(%struct.struct_arr33 addrspace(5)* noalias nocapture sret %agg.result) +// CHECK: define void @func_ret_struct_arr33(%struct.struct_arr33 addrspace(5)* noalias nocapture sret align 4 %agg.result) struct_arr33 func_ret_struct_arr33() { struct_arr33 s = { 0 }; @@ -440,7 +440,7 @@ different_size_type_pair func_different_size_type_pair_ret() return s; } -// CHECK: define void @func_flexible_array_ret(%struct.flexible_array addrspace(5)* noalias nocapture sret %agg.result) +// CHECK: define void @func_flexible_array_ret(%struct.flexible_array addrspace(5)* noalias nocapture sret align 4 %agg.result) flexible_array func_flexible_array_ret() { flexible_array s = { 0 }; diff --git a/clang/test/CodeGenOpenCLCXX/addrspace-of-this.cl b/clang/test/CodeGenOpenCLCXX/addrspace-of-this.cl index 07e3b0b7314ea..16495d38b9421 100644 --- a/clang/test/CodeGenOpenCLCXX/addrspace-of-this.cl +++ b/clang/test/CodeGenOpenCLCXX/addrspace-of-this.cl @@ -114,7 +114,7 @@ __kernel void test__global() { // Test the address space of 'this' when invoking the operator+ // COMMON: [[C1GEN:%[.a-z0-9]+]] = addrspacecast %class.C* %c1 to %class.C addrspace(4)* // COMMON: [[C2GEN:%[.a-z0-9]+]] = addrspacecast %class.C* %c2 to %class.C addrspace(4)* -// COMMON: call spir_func void @_ZNU3AS41CplERU3AS4KS_(%class.C* sret %c3, %class.C addrspace(4)* [[C1GEN]], %class.C addrspace(4)* dereferenceable(4) [[C2GEN]]) +// COMMON: call spir_func void @_ZNU3AS41CplERU3AS4KS_(%class.C* sret align 4 %c3, %class.C addrspace(4)* [[C1GEN]], %class.C addrspace(4)* dereferenceable(4) [[C2GEN]]) // Test the address space of 'this' when invoking the move constructor // COMMON: [[C4GEN:%[.a-z0-9]+]] = addrspacecast %class.C* %c4 to %class.C addrspace(4)* @@ -134,7 +134,7 @@ __kernel void test__global() { // Tests address space of inline members //COMMON: @_ZNU3AS41C3getEv(%class.C addrspace(4)* %this) -//COMMON: @_ZNU3AS41CplERU3AS4KS_(%class.C* noalias sret %agg.result, %class.C addrspace(4)* %this +//COMMON: @_ZNU3AS41CplERU3AS4KS_(%class.C* noalias sret align 4 %agg.result, %class.C addrspace(4)* %this #define TEST(AS) \ __kernel void test##AS() { \ AS C c; \ diff --git a/clang/test/Driver/darwin-ld.c b/clang/test/Driver/darwin-ld.c index dee3df0337e92..63764c4a97755 100644 --- a/clang/test/Driver/darwin-ld.c +++ b/clang/test/Driver/darwin-ld.c @@ -321,32 +321,6 @@ // LINK_VERSION_DIGITS: invalid version number in '-mlinker-version=133.3.0.1.a' // LINK_VERSION_DIGITS: invalid version number in '-mlinker-version=133.3.0.1a' -// Check that we're passing -lto-pass-remarks-output for LTO -// RUN: %clang -target x86_64-apple-darwin12 %t.o -fsave-optimization-record -### -o foo/bar.out 2> %t.log -// RUN: FileCheck -check-prefix=PASS_REMARKS_OUTPUT %s < %t.log -// PASS_REMARKS_OUTPUT: "-mllvm" "-lto-pass-remarks-output" "-mllvm" "foo/bar.out.opt.yaml" -// PASS_REMARKS_OUTPUT-NOT: -lto-pass-remarks-with-hotness - -// RUN: %clang -target x86_64-apple-darwin12 %t.o -fsave-optimization-record -### 2> %t.log -// RUN: FileCheck -check-prefix=PASS_REMARKS_OUTPUT_NO_O %s < %t.log -// PASS_REMARKS_OUTPUT_NO_O: "-mllvm" "-lto-pass-remarks-output" "-mllvm" "a.out.opt.yaml" - -// RUN: %clang -target x86_64-apple-darwin12 %t.o -fsave-optimization-record -fprofile-instr-use=blah -### -o foo/bar.out 2> %t.log -// RUN: FileCheck -check-prefix=PASS_REMARKS_WITH_HOTNESS %s < %t.log -// PASS_REMARKS_WITH_HOTNESS: "-mllvm" "-lto-pass-remarks-output" "-mllvm" "foo/bar.out.opt.yaml" "-mllvm" "-lto-pass-remarks-with-hotness" - -// RUN: %clang -target x86_64-apple-darwin12 %t.o -fsave-optimization-record -fprofile-instr-use=blah -fdiagnostics-hotness-threshold=100 -### -o foo/bar.out 2> %t.log -// RUN: FileCheck -check-prefix=PASS_REMARKS_WITH_HOTNESS_THRESHOLD %s < %t.log -// PASS_REMARKS_WITH_HOTNESS_THRESHOLD: "-mllvm" "-lto-pass-remarks-output" "-mllvm" "foo/bar.out.opt.yaml" "-mllvm" "-lto-pass-remarks-with-hotness" "-mllvm" "-lto-pass-remarks-hotness-threshold=100" - -// RUN: %clang -target x86_64-apple-darwin12 %t.o -fsave-optimization-record -foptimization-record-passes=inline -### -o foo/bar.out 2> %t.log -// RUN: FileCheck -check-prefix=PASS_REMARKS_WITH_PASSES %s < %t.log -// PASS_REMARKS_WITH_PASSES: "-mllvm" "-lto-pass-remarks-output" "-mllvm" "foo/bar.out.opt.yaml" "-mllvm" "-lto-pass-remarks-filter=inline" -// -// RUN: %clang -target x86_64-apple-darwin12 %t.o -fsave-optimization-record=some-format -### -o foo/bar.out 2> %t.log -// RUN: FileCheck -check-prefix=PASS_REMARKS_WITH_FORMAT %s < %t.log -// PASS_REMARKS_WITH_FORMAT: "-mllvm" "-lto-pass-remarks-output" "-mllvm" "foo/bar.out.opt.some-format" "-mllvm" "-lto-pass-remarks-format=some-format" - // RUN: %clang -target x86_64-apple-ios6.0 -miphoneos-version-min=6.0 -fprofile-instr-generate -### %t.o 2> %t.log // RUN: FileCheck -check-prefix=LINK_PROFILE_FIRST %s < %t.log // RUN: %clang -target x86_64-apple-darwin12 -fprofile-instr-generate -### %t.o 2> %t.log diff --git a/clang/test/Driver/darwin-opt-record-ld.c b/clang/test/Driver/darwin-opt-record-ld.c new file mode 100644 index 0000000000000..83630ed01da8b --- /dev/null +++ b/clang/test/Driver/darwin-opt-record-ld.c @@ -0,0 +1,46 @@ +// REQUIRES: system-darwin + +// RUN: touch %t.o +// +// Check that we're not passing -lto-pass-remarks-output if not requested +// RUN: %clang -target x86_64-apple-darwin12 %t.o -### -o foo/bar.out 2> %t.log +// RUN: FileCheck -check-prefix=NO_PASS_REMARKS_OUTPUT %s < %t.log +// NO_PASS_REMARKS_OUTPUT-NOT: -lto-pass-remarks +// Check that we're passing -lto-pass-remarks-output for LTO +// RUN: %clang -target x86_64-apple-darwin12 %t.o -fsave-optimization-record -### -o foo/bar.out 2> %t.log +// RUN: FileCheck -check-prefix=PASS_REMARKS_OUTPUT %s < %t.log +// PASS_REMARKS_OUTPUT: "-mllvm" "-lto-pass-remarks-output" "-mllvm" "foo/bar.out.opt.yaml" "-mllvm" "-lto-pass-remarks-format=yaml" +// PASS_REMARKS_OUTPUT-NOT: -lto-pass-remarks-with-hotness + +// RUN: %clang -target x86_64-apple-darwin12 %t.o -fsave-optimization-record -### 2> %t.log +// RUN: FileCheck -check-prefix=PASS_REMARKS_OUTPUT_NO_O %s < %t.log +// PASS_REMARKS_OUTPUT_NO_O: "-mllvm" "-lto-pass-remarks-output" "-mllvm" "a.out.opt.yaml" + +// RUN: %clang -target x86_64-apple-darwin12 %t.o -fsave-optimization-record -fprofile-instr-use=blah -### -o foo/bar.out 2> %t.log +// RUN: FileCheck -check-prefix=PASS_REMARKS_WITH_HOTNESS %s < %t.log +// PASS_REMARKS_WITH_HOTNESS: "-mllvm" "-lto-pass-remarks-output" "-mllvm" "foo/bar.out.opt.yaml" "-mllvm" "-lto-pass-remarks-format=yaml" "-mllvm" "-lto-pass-remarks-with-hotness" + +// RUN: %clang -target x86_64-apple-darwin12 %t.o -fsave-optimization-record -fprofile-instr-use=blah -fdiagnostics-hotness-threshold=100 -### -o foo/bar.out 2> %t.log +// RUN: FileCheck -check-prefix=PASS_REMARKS_WITH_HOTNESS_THRESHOLD %s < %t.log +// PASS_REMARKS_WITH_HOTNESS_THRESHOLD: "-mllvm" "-lto-pass-remarks-output" "-mllvm" "foo/bar.out.opt.yaml" "-mllvm" "-lto-pass-remarks-format=yaml" "-mllvm" "-lto-pass-remarks-with-hotness" "-mllvm" "-lto-pass-remarks-hotness-threshold=100" + +// RUN: %clang -target x86_64-apple-darwin12 %t.o -fsave-optimization-record -foptimization-record-passes=inline -### -o foo/bar.out 2> %t.log +// RUN: FileCheck -check-prefix=PASS_REMARKS_WITH_PASSES %s < %t.log +// PASS_REMARKS_WITH_PASSES: "-mllvm" "-lto-pass-remarks-output" "-mllvm" "foo/bar.out.opt.yaml" "-mllvm" "-lto-pass-remarks-filter=inline" +// +// RUN: %clang -target x86_64-apple-darwin12 %t.o -fsave-optimization-record=some-format -### -o foo/bar.out 2> %t.log +// RUN: FileCheck -check-prefix=PASS_REMARKS_WITH_FORMAT %s < %t.log +// PASS_REMARKS_WITH_FORMAT: "-mllvm" "-lto-pass-remarks-output" "-mllvm" "foo/bar.out.opt.some-format" "-mllvm" "-lto-pass-remarks-format=some-format" + +// RUN: %clang -target x86_64-apple-darwin12 %t.o -foptimization-record-file=remarks-custom.opt.yaml -### -o foo/bar.out 2> %t.log +// RUN: FileCheck -check-prefix=PASS_REMARKS_WITH_FILE %s < %t.log +// PASS_REMARKS_WITH_FILE: "-mllvm" "-lto-pass-remarks-output" "-mllvm" "remarks-custom.opt.yaml" + +// RUN: %clang -target x86_64-apple-darwin12 -arch x86_64 -arch x86_64h %t.o -fsave-optimization-record -### -o foo/bar.out 2> %t.log +// RUN: FileCheck -check-prefix=PASS_REMARKS_WITH_FAT %s < %t.log +// PASS_REMARKS_WITH_FAT: "-arch" "x86_64"{{.*}}"-mllvm" "-lto-pass-remarks-output" +// PASS_REMARKS_WITH_FAT-NEXT: "-arch" "x86_64h"{{.*}}"-mllvm" "-lto-pass-remarks-output" +// +// RUN: %clang -target x86_64-apple-darwin12 -arch x86_64 -arch x86_64h %t.o -foptimization-record-file=custom.opt.yaml -### -o foo/bar.out 2> %t.log +// RUN: FileCheck -check-prefix=PASS_REMARKS_WITH_FILE_FAT %s < %t.log +// PASS_REMARKS_WITH_FILE_FAT: error: cannot use '-foptimization-record-file' output with multiple -arch options diff --git a/clang/test/Import/objc-arc/Inputs/cleanup-objects.m b/clang/test/Import/objc-arc/Inputs/cleanup-objects.m new file mode 100644 index 0000000000000..9c18399259f9d --- /dev/null +++ b/clang/test/Import/objc-arc/Inputs/cleanup-objects.m @@ -0,0 +1,10 @@ +typedef struct { + id x; +} S; + +id getObj(int c, id a) { + // Commenting out the following line because AST importer crashes when trying + // to import a BlockExpr. + // return c ? ^{ return a; }() : ((S){ .x = a }).x; + return ((S){ .x = a }).x; +} diff --git a/clang/test/Import/objc-arc/test-cleanup-object.m b/clang/test/Import/objc-arc/test-cleanup-object.m new file mode 100644 index 0000000000000..aab1cd377a2e7 --- /dev/null +++ b/clang/test/Import/objc-arc/test-cleanup-object.m @@ -0,0 +1,10 @@ +// RUN: clang-import-test -x objective-c -objc-arc -import %S/Inputs/cleanup-objects.m -dump-ast -expression %s | FileCheck %s + +// CHECK: FunctionDecl {{.*}} getObj ' +// CHECK: ExprWithCleanups +// CHECK-NEXT: cleanup CompoundLiteralExpr + +void test(int c, id a) { + (void)getObj(c, a); +} + diff --git a/clang/test/Index/pch-with-errors.c b/clang/test/Index/pch-with-errors.c index 5c94a8a8e4d38..e8711c8e26a9b 100644 --- a/clang/test/Index/pch-with-errors.c +++ b/clang/test/Index/pch-with-errors.c @@ -42,3 +42,6 @@ void foo(void) { // RUN: not c-index-test -write-pch %t.pch foobar.c 2>&1 | FileCheck -check-prefix=NONEXISTENT %s // NONEXISTENT: Unable to load translation unit + +// RUN: %clang -x c-header %s -o %t-clang.h.pch -Xclang -detailed-preprocessing-record -Xclang -fallow-pch-with-compiler-errors +// RUN: c-index-test -index-file %s -include %t-clang.h -Xclang -detailed-preprocessing-record | FileCheck -check-prefix=CHECK-INDEX %s diff --git a/clang/test/Modules/ExtDebugInfo.m b/clang/test/Modules/ExtDebugInfo.m index 41247b00a49f8..380bc4c9bb983 100644 --- a/clang/test/Modules/ExtDebugInfo.m +++ b/clang/test/Modules/ExtDebugInfo.m @@ -6,13 +6,16 @@ // RUN: -fmodule-format=obj -fimplicit-module-maps -DMODULES \ // RUN: -fmodules-cache-path=%t %s -I %S/Inputs -I %t -emit-llvm -o %t-mod.ll // RUN: cat %t-mod.ll | FileCheck %s +// RUN: cat %t-mod.ll | FileCheck %s --check-prefix=DWOID // PCH: // RUN: %clang_cc1 -x objective-c -fmodule-format=obj -emit-pch -I%S/Inputs \ // RUN: -o %t.pch %S/Inputs/DebugObjC.h -// RUN: %clang_cc1 -x objective-c -debug-info-kind=limited -dwarf-ext-refs -fmodule-format=obj \ +// RUN: %clang_cc1 -x objective-c -debug-info-kind=limited -dwarf-ext-refs \ +// RUN: -fmodule-format=obj \ // RUN: -include-pch %t.pch %s -emit-llvm -o %t-pch.ll %s // RUN: cat %t-pch.ll | FileCheck %s +// RUN: cat %t-pch.ll | FileCheck %s --check-prefix=DWOID #ifdef MODULES @import DebugObjC; @@ -34,6 +37,8 @@ int foo(ObjCClass *c) { return [c property]; } +// DWOID: !DICompileUnit(language: DW_LANG_ObjC,{{.*}}isOptimized: false,{{.*}}dwoId: + // CHECK: ![[MOD:.*]] = !DIModule(scope: null, name: "DebugObjC // CHECK: !DIGlobalVariable(name: "GlobalUnion", diff --git a/clang/test/Modules/debug-info-moduleimport.m b/clang/test/Modules/debug-info-moduleimport.m index f07c6fce784d5..5787ffe227513 100644 --- a/clang/test/Modules/debug-info-moduleimport.m +++ b/clang/test/Modules/debug-info-moduleimport.m @@ -1,11 +1,19 @@ // RUN: rm -rf %t -// RUN: %clang_cc1 -debug-info-kind=limited -fmodules -DGREETING="Hello World" -UNDEBUG -fimplicit-module-maps -fmodules-cache-path=%t %s -I %S/Inputs -isysroot /tmp/.. -I %t -emit-llvm -o - | FileCheck %s --check-prefix=NOIMPORT +// RUN: %clang_cc1 -debug-info-kind=limited -fmodules \ +// RUN: -DGREETING="Hello World" -UNDEBUG \ +// RUN: -fimplicit-module-maps -fmodules-cache-path=%t %s \ +// RUN: -I %S/Inputs -isysroot /tmp/.. -I %t -emit-llvm -o - \ +// RUN: | FileCheck %s --check-prefix=NOIMPORT // NOIMPORT-NOT: !DIImportedEntity // NOIMPORT-NOT: !DIModule // RUN: rm -rf %t -// RUN: %clang_cc1 -debug-info-kind=limited -fmodules -DGREETING="Hello World" -UNDEBUG -fimplicit-module-maps -fmodules-cache-path=%t %s -I %S/Inputs -isysroot /tmp/.. -I %t -emit-llvm -debugger-tuning=lldb -o - | FileCheck %s +// RUN: %clang_cc1 -debug-info-kind=limited -fmodules \ +// RUN: -DGREETING="Hello World" -UNDEBUG \ +// RUN: -fimplicit-module-maps -fmodules-cache-path=%t %s \ +// RUN: -I %S/Inputs -isysroot /tmp/.. -I %t -emit-llvm \ +// RUN: -debugger-tuning=lldb -o - | FileCheck %s // CHECK: ![[CU:.*]] = distinct !DICompileUnit // CHECK-SAME: sysroot: "/tmp/..") @@ -18,15 +26,20 @@ // CHECK-SAME: includePath: "{{.*}}test{{.*}}Modules{{.*}}Inputs" // CHECK: ![[F]] = !DIFile(filename: {{.*}}debug-info-moduleimport.m -// RUN: %clang_cc1 -debug-info-kind=limited -fmodules -fimplicit-module-maps -fmodules-cache-path=%t \ -// RUN: %s -I %S/Inputs -isysroot /tmp/.. -I %t -emit-llvm -o - \ -// RUN: | FileCheck %s --check-prefix=NO-SKEL-CHECK +// RUN: %clang_cc1 -debug-info-kind=limited -fmodules -fimplicit-module-maps \ +// RUN: -fmodules-cache-path=%t %s -I %S/Inputs -isysroot /tmp/.. -I %t \ +// RUN: -emit-llvm -o - | FileCheck %s --check-prefix=NO-SKEL-CHECK // NO-SKEL-CHECK: distinct !DICompileUnit // NO-SKEL-CHECK-NOT: distinct !DICompileUnit -// RUN: %clang_cc1 -debug-info-kind=limited -fmodules -fimplicit-module-maps -fmodules-cache-path=%t \ +// RUN: %clang_cc1 -debug-info-kind=limited -fmodules -fimplicit-module-maps \ +// RUN: -fmodules-cache-path=%t -fdebug-prefix-map=%t=/MODULE-CACHE \ +// RUN: -fdebug-prefix-map=%S=/SRCDIR \ // RUN: -fmodule-format=obj -dwarf-ext-refs \ // RUN: %s -I %S/Inputs -isysroot /tmp/.. -I %t -emit-llvm -o - \ // RUN: | FileCheck %s --check-prefix=SKEL-CHECK -// SKEL-CHECK: distinct !DICompileUnit -// SKEL-CHECK: distinct !DICompileUnit{{.*}}dwoId +// SKEL-CHECK: includePath: "/SRCDIR/Inputs" +// SKEL-CHECK: distinct !DICompileUnit({{.*}}file: ![[CUFILE:[0-9]+]] +// SKEL-CHECK: ![[CUFILE]] = !DIFile({{.*}}directory: "[[COMP_DIR:.*]]" +// SKEL-CHECK: distinct !DICompileUnit({{.*}}file: ![[DWOFILE:[0-9]+]]{{.*}}splitDebugFilename: "/MODULE-CACHE{{.*}}dwoId +// SKEL-CHECK: ![[DWOFILE]] = !DIFile({{.*}}directory: "[[COMP_DIR]]" diff --git a/clang/test/Modules/templates.mm b/clang/test/Modules/templates.mm index 78206a980a8fb..9d4e4b9d16173 100644 --- a/clang/test/Modules/templates.mm +++ b/clang/test/Modules/templates.mm @@ -125,7 +125,7 @@ void testWithAttributes() { // Check that returnNonTrivial doesn't return Class0 directly in registers. -// CHECK: declare void @_Z16returnNonTrivialv(%struct.Class0* sret) +// CHECK: declare void @_Z16returnNonTrivialv(%struct.Class0* sret align 8) @import template_nontrivial0; @import template_nontrivial1; diff --git a/clang/test/PCH/debug-info-pch-path.c b/clang/test/PCH/debug-info-pch-path.c index dcf7ed41f50ef..272d9ac1ab7cf 100644 --- a/clang/test/PCH/debug-info-pch-path.c +++ b/clang/test/PCH/debug-info-pch-path.c @@ -47,8 +47,8 @@ // CHECK-REL: ![[C]] = !DIFile({{.*}}directory: "[[DIR:.*]]" // CHECK-REL: !DICompileUnit( // CHECK-REL-SAME: file: ![[PCH:[0-9]+]] -// CHECK-REL-SAME: splitDebugFilename: "prefix.pch" -// CHECK-REL: ![[PCH]] = !DIFile({{.*}}directory: "[[DIR]]{{.*}}pchdir" +// CHECK-REL-SAME: splitDebugFilename: "pchdir{{.*}}prefix.pch" +// CHECK-REL: ![[PCH]] = !DIFile({{.*}}directory: "[[DIR]]" // --------------------------------------------------------------------- // Absolute PCH. diff --git a/clang/test/PCH/non-trivial-c-compound-literal.m b/clang/test/PCH/non-trivial-c-compound-literal.m new file mode 100644 index 0000000000000..d4e3c1f12df27 --- /dev/null +++ b/clang/test/PCH/non-trivial-c-compound-literal.m @@ -0,0 +1,29 @@ +// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -x objective-c -fobjc-arc -emit-pch -o %t %s +// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -x objective-c -fobjc-arc -include-pch %t -emit-llvm -o - %s | FileCheck %s + +#ifndef HEADER +#define HEADER + +typedef struct { + id f; +} S; + +static inline id getObj(id a) { + S *p = &(S){ .f = a }; + return p->f; +} + +#else + +// CHECK: %[[STRUCT_S:.*]] = type { i8* } + +// CHECK: define internal i8* @getObj( +// CHECK: %[[_COMPOUNDLITERAL:.*]] = alloca %[[STRUCT_S]], +// CHECK: %[[V5:.*]] = bitcast %[[STRUCT_S]]* %[[_COMPOUNDLITERAL]] to i8** +// CHECK: call void @__destructor_8_s0(i8** %[[V5]]) + +id test(id a) { + return getObj(a); +} + +#endif diff --git a/clang/test/SemaCXX/ptrauth-qualifier.cpp b/clang/test/SemaCXX/ptrauth-qualifier.cpp index e1fd10121ec84..673d381577f86 100644 --- a/clang/test/SemaCXX/ptrauth-qualifier.cpp +++ b/clang/test/SemaCXX/ptrauth-qualifier.cpp @@ -1,6 +1,7 @@ // RUN: %clang_cc1 -triple arm64-apple-ios -std=c++11 -fptrauth-calls -fptrauth-intrinsics -verify -fsyntax-only %s #define AQ __ptrauth(1,1,50) +#define AQ2 __ptrauth(1,1,51) #define IQ __ptrauth(1,0,50) struct __attribute__((trivial_abi)) AddrDisc { // expected-warning {{'trivial_abi' cannot be applied to 'AddrDisc'}} @@ -118,3 +119,23 @@ namespace test_union { *x4 = static_cast(*s1); // expected-error {{cannot be assigned because its copy assignment operator is implicitly deleted}} } } + +bool test_composite_type0(bool c, int * AQ * a0, int * AQ * a1) { + auto t = c ? a0 : a1; + return a0 == a1; +} + +bool test_composite_type1(bool c, int * AQ * a0, int * AQ2 * a1) { + auto t = c ? a0 : a1; // expected-error {{incompatible operand types ('int *__ptrauth(1,1,50) *' and 'int *__ptrauth(1,1,51) *')}} + return a0 == a1; // expected-error {{comparison of distinct pointer types ('int *__ptrauth(1,1,50) *' and 'int *__ptrauth(1,1,51) *')}} +} + +void test_bad_call_diag(void *AQ* ptr); // expected-note{{candidate function not viable: 1st argument ('void *__ptrauth(1,1,51) *') has __ptrauth(1,1,51) qualifier, but parameter has __ptrauth(1,1,50) qualifier}} expected-note{{candidate function not viable: 1st argument ('void **') has no ptrauth qualifier, but parameter has __ptrauth(1,1,50) qualifier}} +void test_bad_call_diag2(void ** ptr); // expected-note{{1st argument ('void *__ptrauth(1,1,50) *') has __ptrauth(1,1,50) qualifier, but parameter has no ptrauth qualifier}} + +int test_call_diag() { + void *AQ ptr1, *AQ2 ptr2, *ptr3; + test_bad_call_diag(&ptr2); // expected-error {{no matching function for call to 'test_bad_call_diag'}} + test_bad_call_diag(&ptr3); // expected-error {{no matching function for call to 'test_bad_call_diag'}} + test_bad_call_diag2(&ptr1); // expected-error {{no matching function for call to 'test_bad_call_diag2'}} +} diff --git a/clang/test/SemaCXX/ptrauth.cpp b/clang/test/SemaCXX/ptrauth.cpp index 691edc9a2e576..48763f7160d76 100644 --- a/clang/test/SemaCXX/ptrauth.cpp +++ b/clang/test/SemaCXX/ptrauth.cpp @@ -1,7 +1,41 @@ -// RUN: %clang_cc1 -triple arm64-apple-ios -std=c++17 -fsyntax-only -verify -fptrauth-intrinsics %s +// RUN: %clang_cc1 -triple arm64-apple-ios -std=c++17 -fsyntax-only -verify -fptrauth-intrinsics -fptrauth-calls %s + +struct Incomplete0; // expected-note 3 {{forward declaration of 'Incomplete0'}} + +template +struct Incomplete1; // expected-note {{template is declared here}} + +struct Complete0 { +}; + +template +struct Complete1 { +}; struct S { virtual int foo(); + virtual Incomplete0 virtual0(); // expected-note 2 {{'Incomplete0' is incomplete}} + virtual void virtual1(Incomplete1); // expected-note {{'Incomplete1' is incomplete}} + virtual Complete0 virtual2(); + virtual Complete1 virtual3(); + Incomplete0 nonvirtual0(); + template + void m0() { + (void)&S::virtual0; // expected-error {{incomplete type 'Incomplete0'}} expected-note {{cannot take an address of a virtual}} + } +}; + +template +struct S2 { + virtual Incomplete0 virtual0() noexcept(T); // expected-note {{'Incomplete0' is incomplete}} + + void m0() { + (void)&S2::virtual0; + } + + void m1() { + (void)&S2::virtual0; // expected-error {{incomplete type 'Incomplete0'}} expected-note {{cannot take an address of a virtual}} + } }; template @@ -31,3 +65,13 @@ void test_builtin_ptrauth_type_discriminator(unsigned s) { __builtin_ptrauth_type_discriminator(&t); // expected-error {{expected a type}} __builtin_ptrauth_type_discriminator(decltype(vmarray)); // expected-error {{cannot pass variably-modified type 'decltype(vmarray)'}} } + +void test_incomplete_virtual_member_function_return_arg_type() { + (void)&S::virtual0; // expected-error {{incomplete type 'Incomplete0}} expected-note {{cannot take an address of a virtual member function}} + (void)&S::virtual1; // expected-error {{implicit instantiation of undefined template 'Incomplete1'}} expected-note {{cannot take an address of a virtual member function}} + (void)&S::virtual2; + (void)&S::virtual3; + (void)&S::nonvirtual0; + int s = sizeof(&S::virtual0); + S2().m1(); // expected-note {{in instantiation of}} +} diff --git a/clang/test/SemaObjC/externally-retained.m b/clang/test/SemaObjC/externally-retained.m index 24c531ccf7396..f9fbdb0689443 100644 --- a/clang/test/SemaObjC/externally-retained.m +++ b/clang/test/SemaObjC/externally-retained.m @@ -118,3 +118,6 @@ void test13(ObjCTy *first, __weak ObjCTy *second, __unsafe_unretained ObjCTy *th } #pragma clang attribute ext_ret.pop + +__attribute__((objc_externally_retained)) +void unprototyped(); diff --git a/clang/test/SemaObjC/method-direct-one-definition.m b/clang/test/SemaObjC/method-direct-one-definition.m index e6355d2cb7bac..3dcf89d784cf1 100644 --- a/clang/test/SemaObjC/method-direct-one-definition.m +++ b/clang/test/SemaObjC/method-direct-one-definition.m @@ -30,6 +30,15 @@ @interface B (OtherCat) - (void)B_OtherCat __attribute__((objc_direct)); // expected-note {{previous declaration is here}} @end +@implementation B +- (void)B_primary { +} +- (void)B_extension { +} +- (void)B_implOnly __attribute__((objc_direct)) { // expected-note {{previous declaration is here}} +} +@end + @implementation B (Cat) - (void)B_primary { // expected-error {{direct method was declared in the primary interface but is implemented in a category}} } @@ -39,6 +48,8 @@ - (void)B_Cat { } - (void)B_OtherCat { // expected-error {{direct method was declared in a category but is implemented in a different category}} } +- (void)B_implOnly __attribute__((objc_direct)) { // expected-error {{direct method declaration conflicts with previous direct declaration of method 'B_implOnly'}} +} @end __attribute__((objc_root_class)) diff --git a/clang/test/SemaObjC/method-direct.m b/clang/test/SemaObjC/method-direct.m index 9aef9808abbda..80ca5b2e6ebe1 100644 --- a/clang/test/SemaObjC/method-direct.m +++ b/clang/test/SemaObjC/method-direct.m @@ -12,6 +12,7 @@ + (void)classProtoMethod __attribute__((objc_direct)); // expected-error {{'objc __attribute__((objc_root_class)) @interface Root +- (void)unavailableInChild; - (void)rootRegular; // expected-note {{previous declaration is here}} + (void)classRootRegular; // expected-note {{previous declaration is here}} - (void)rootDirect __attribute__((objc_direct)); // expected-note {{previous declaration is here}}; @@ -52,6 +53,7 @@ + (void)classRootCategoryDirect2 __attribute__((objc_direct)); // expected-note __attribute__((objc_direct_members)) @interface SubDirectMembers : Root @property int foo; // expected-note {{previous declaration is here}} +- (void)unavailableInChild __attribute__((unavailable)); // should not warn - (instancetype)init; @end @@ -81,6 +83,8 @@ + (void)classRootCategoryDirect2; // expected-error {{cannot override a method __attribute__((objc_direct_members)) @implementation Root +- (void)unavailableInChild { +} - (void)rootRegular { } + (void)classRootRegular { diff --git a/clang/test/SemaObjC/strong-in-c-struct.m b/clang/test/SemaObjC/strong-in-c-struct.m index 5dd5f94af8301..5d2f4e496c2e3 100644 --- a/clang/test/SemaObjC/strong-in-c-struct.m +++ b/clang/test/SemaObjC/strong-in-c-struct.m @@ -54,3 +54,21 @@ void test_block_scope1(void) { func(^{ func2(x); }); goto *ips; // expected-error {{cannot jump}} } + +void test_compound_literal0(int cond, id x) { + switch (cond) { + case 0: + (void)(Strong){ .a = x }; // expected-note {{jump enters lifetime of a compound literal that is non-trivial to destruct}} + break; + default: // expected-error {{cannot jump from switch statement to this case label}} + break; + } +} + +void test_compound_literal1(id x) { + static void *ips[] = { &&L0 }; +L0: // expected-note {{possible target of indirect goto}} + ; + (void)(Strong){ .a = x }; // expected-note {{jump exits lifetime of a compound literal that is non-trivial to destruct}} + goto *ips; // expected-error {{cannot jump}} +} diff --git a/clang/test/SemaTemplate/enum-argument.cpp b/clang/test/SemaTemplate/enum-argument.cpp index a79ed8403e9f4..7ff4196139901 100644 --- a/clang/test/SemaTemplate/enum-argument.cpp +++ b/clang/test/SemaTemplate/enum-argument.cpp @@ -1,4 +1,5 @@ // RUN: %clang_cc1 -fsyntax-only -verify %s +// expected-no-diagnostics enum Enum { val = 1 }; template struct C { @@ -30,7 +31,7 @@ namespace rdar8020920 { unsigned long long bitfield : e0; void f(int j) { - bitfield + j; // expected-warning {{expression result unused}} + bitfield + j; } }; } diff --git a/clang/test/SemaTemplate/value-dependent-bitfield-cond.cpp b/clang/test/SemaTemplate/value-dependent-bitfield-cond.cpp new file mode 100644 index 0000000000000..873e4d48e8374 --- /dev/null +++ b/clang/test/SemaTemplate/value-dependent-bitfield-cond.cpp @@ -0,0 +1,13 @@ +// RUN: %clang_cc1 -fsyntax-only -verify %s +// expected-no-diagnostics + +template +class A { + int c : b; + +public: + void f() { + if (c) + ; + } +}; diff --git a/clang/test/lit.cfg.py b/clang/test/lit.cfg.py index 3fc75105fb797..1a819c6ded387 100644 --- a/clang/test/lit.cfg.py +++ b/clang/test/lit.cfg.py @@ -77,6 +77,11 @@ if config.clang_staticanalyzer_z3 == '1': config.available_features.add('z3') + check_analyzer_fixit_path = os.path.join( + config.test_source_root, "Analysis", "check-analyzer-fixit.py") + config.substitutions.append( + ('%check_analyzer_fixit', + '%s %s' % (config.python_executable, check_analyzer_fixit_path))) llvm_config.add_tool_substitutions(tools, tool_dirs) diff --git a/clang/tools/clang-import-test/clang-import-test.cpp b/clang/tools/clang-import-test/clang-import-test.cpp index b42c93e8d3819..f76f850ff41f3 100644 --- a/clang/tools/clang-import-test/clang-import-test.cpp +++ b/clang/tools/clang-import-test/clang-import-test.cpp @@ -64,6 +64,9 @@ static llvm::cl::opt llvm::cl::desc("The language to parse (default: c++)"), llvm::cl::init("c++")); +static llvm::cl::opt ObjCARC("objc-arc", llvm::cl::init(false), + llvm::cl::desc("Emable ObjC ARC")); + static llvm::cl::opt DumpAST("dump-ast", llvm::cl::init(false), llvm::cl::desc("Dump combined AST")); @@ -183,6 +186,8 @@ std::unique_ptr BuildCompilerInstance() { Inv->getLangOpts()->ObjC = 1; } } + Inv->getLangOpts()->ObjCAutoRefCount = ObjCARC; + Inv->getLangOpts()->Bool = true; Inv->getLangOpts()->WChar = true; Inv->getLangOpts()->Blocks = true; diff --git a/clang/unittests/StaticAnalyzer/CheckerRegistration.h b/clang/unittests/StaticAnalyzer/CheckerRegistration.h new file mode 100644 index 0000000000000..0bbed9b7784ff --- /dev/null +++ b/clang/unittests/StaticAnalyzer/CheckerRegistration.h @@ -0,0 +1,81 @@ +//===- unittests/StaticAnalyzer/RegisterCustomCheckersTest.cpp ------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "clang/Frontend/CompilerInstance.h" +#include "clang/StaticAnalyzer/Core/BugReporter/BugReporter.h" +#include "clang/StaticAnalyzer/Core/BugReporter/BugType.h" +#include "clang/StaticAnalyzer/Core/Checker.h" +#include "clang/StaticAnalyzer/Core/PathSensitive/AnalysisManager.h" +#include "clang/StaticAnalyzer/Frontend/AnalysisConsumer.h" +#include "clang/StaticAnalyzer/Frontend/CheckerRegistry.h" +#include "clang/Tooling/Tooling.h" + +namespace clang { +namespace ento { + +class DiagConsumer : public PathDiagnosticConsumer { + llvm::raw_ostream &Output; + +public: + DiagConsumer(llvm::raw_ostream &Output) : Output(Output) {} + void FlushDiagnosticsImpl(std::vector &Diags, + FilesMade *filesMade) override { + for (const auto *PD : Diags) + Output << PD->getCheckerName() << ":" << PD->getShortDescription() << '\n'; + } + + StringRef getName() const override { return "Test"; } +}; + +using AddCheckerFn = void(AnalysisASTConsumer &AnalysisConsumer, + AnalyzerOptions &AnOpts); + +template +void addChecker(AnalysisASTConsumer &AnalysisConsumer, + AnalyzerOptions &AnOpts) { + Fn1(AnalysisConsumer, AnOpts); + addChecker(AnalysisConsumer, AnOpts); +} + +template +void addChecker(AnalysisASTConsumer &AnalysisConsumer, + AnalyzerOptions &AnOpts) { + Fn1(AnalysisConsumer, AnOpts); +} + +template +class TestAction : public ASTFrontendAction { + llvm::raw_ostream &DiagsOutput; + +public: + TestAction(llvm::raw_ostream &DiagsOutput) : DiagsOutput(DiagsOutput) {} + + std::unique_ptr CreateASTConsumer(CompilerInstance &Compiler, + StringRef File) override { + std::unique_ptr AnalysisConsumer = + CreateAnalysisConsumer(Compiler); + AnalysisConsumer->AddDiagnosticConsumer(new DiagConsumer(DiagsOutput)); + addChecker(*AnalysisConsumer, *Compiler.getAnalyzerOpts()); + return std::move(AnalysisConsumer); + } +}; + +template +bool runCheckerOnCode(const std::string &Code, std::string &Diags) { + llvm::raw_string_ostream OS(Diags); + return tooling::runToolOnCode(std::make_unique>(OS), Code); +} + +template +bool runCheckerOnCode(const std::string &Code) { + std::string Diags; + return runCheckerOnCode(Code, Diags); +} + +} // namespace ento +} // namespace clang diff --git a/clang/unittests/StaticAnalyzer/RegisterCustomCheckersTest.cpp b/clang/unittests/StaticAnalyzer/RegisterCustomCheckersTest.cpp index 4f504d2384cf0..d0cf291eb2b8e 100644 --- a/clang/unittests/StaticAnalyzer/RegisterCustomCheckersTest.cpp +++ b/clang/unittests/StaticAnalyzer/RegisterCustomCheckersTest.cpp @@ -6,11 +6,13 @@ // //===----------------------------------------------------------------------===// +#include "CheckerRegistration.h" #include "clang/Frontend/CompilerInstance.h" #include "clang/StaticAnalyzer/Core/BugReporter/BugReporter.h" #include "clang/StaticAnalyzer/Core/BugReporter/BugType.h" #include "clang/StaticAnalyzer/Core/Checker.h" #include "clang/StaticAnalyzer/Core/PathSensitive/AnalysisManager.h" +#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h" #include "clang/StaticAnalyzer/Frontend/AnalysisConsumer.h" #include "clang/StaticAnalyzer/Frontend/CheckerRegistry.h" #include "clang/Tooling/Tooling.h" @@ -20,53 +22,10 @@ namespace clang { namespace ento { namespace { -template -class TestAction : public ASTFrontendAction { - class DiagConsumer : public PathDiagnosticConsumer { - llvm::raw_ostream &Output; - - public: - DiagConsumer(llvm::raw_ostream &Output) : Output(Output) {} - void FlushDiagnosticsImpl(std::vector &Diags, - FilesMade *filesMade) override { - for (const auto *PD : Diags) - Output << PD->getCheckerName() << ":" << PD->getShortDescription(); - } - - StringRef getName() const override { return "Test"; } - }; - - llvm::raw_ostream &DiagsOutput; - -public: - TestAction(llvm::raw_ostream &DiagsOutput) : DiagsOutput(DiagsOutput) {} - - std::unique_ptr CreateASTConsumer(CompilerInstance &Compiler, - StringRef File) override { - std::unique_ptr AnalysisConsumer = - CreateAnalysisConsumer(Compiler); - AnalysisConsumer->AddDiagnosticConsumer(new DiagConsumer(DiagsOutput)); - Compiler.getAnalyzerOpts()->CheckersAndPackages = { - {"custom.CustomChecker", true}}; - AnalysisConsumer->AddCheckerRegistrationFn([](CheckerRegistry &Registry) { - Registry.addChecker("custom.CustomChecker", "Description", ""); - }); - return std::move(AnalysisConsumer); - } -}; - -template -bool runCheckerOnCode(const std::string &Code, std::string &Diags) { - llvm::raw_string_ostream OS(Diags); - return tooling::runToolOnCode(std::make_unique>(OS), - Code); -} -template -bool runCheckerOnCode(const std::string &Code) { - std::string Diags; - return runCheckerOnCode(Code, Diags); -} - +//===----------------------------------------------------------------------===// +// Just a minimal test for how checker registration works with statically +// linked, non TableGen generated checkers. +//===----------------------------------------------------------------------===// class CustomChecker : public Checker { public: @@ -78,12 +37,25 @@ class CustomChecker : public Checker { } }; +void addCustomChecker(AnalysisASTConsumer &AnalysisConsumer, + AnalyzerOptions &AnOpts) { + AnOpts.CheckersAndPackages = {{"custom.CustomChecker", true}}; + AnalysisConsumer.AddCheckerRegistrationFn([](CheckerRegistry &Registry) { + Registry.addChecker("custom.CustomChecker", "Description", + ""); + }); +} + TEST(RegisterCustomCheckers, RegisterChecker) { std::string Diags; - EXPECT_TRUE(runCheckerOnCode("void f() {;}", Diags)); - EXPECT_EQ(Diags, "custom.CustomChecker:Custom diagnostic description"); + EXPECT_TRUE(runCheckerOnCode("void f() {;}", Diags)); + EXPECT_EQ(Diags, "custom.CustomChecker:Custom diagnostic description\n"); } +//===----------------------------------------------------------------------===// +// Pretty much the same. +//===----------------------------------------------------------------------===// + class LocIncDecChecker : public Checker { public: void checkLocation(SVal Loc, bool IsLoad, const Stmt *S, @@ -95,11 +67,20 @@ class LocIncDecChecker : public Checker { } }; +void addLocIncDecChecker(AnalysisASTConsumer &AnalysisConsumer, + AnalyzerOptions &AnOpts) { + AnOpts.CheckersAndPackages = {{"test.LocIncDecChecker", true}}; + AnalysisConsumer.AddCheckerRegistrationFn([](CheckerRegistry &Registry) { + Registry.addChecker("test.LocIncDecChecker", "Description", + ""); + }); +} + TEST(RegisterCustomCheckers, CheckLocationIncDec) { EXPECT_TRUE( - runCheckerOnCode("void f() { int *p; (*p)++; }")); + runCheckerOnCode("void f() { int *p; (*p)++; }")); } -} -} -} +} // namespace +} // namespace ento +} // namespace clang diff --git a/compiler-rt/lib/asan/asan_report.cpp b/compiler-rt/lib/asan/asan_report.cpp index 2e6ce436d0306..99e8678aa7857 100644 --- a/compiler-rt/lib/asan/asan_report.cpp +++ b/compiler-rt/lib/asan/asan_report.cpp @@ -160,6 +160,9 @@ class ScopedInErrorReport { BlockingMutexLock l(&error_message_buf_mutex); internal_memcpy(buffer_copy.data(), error_message_buffer, kErrorMessageBufferSize); + // Clear error_message_buffer so that if we find other errors + // we don't re-log this error. + error_message_buffer_pos = 0; } LogFullErrorReport(buffer_copy.data()); diff --git a/compiler-rt/lib/sanitizer_common/sanitizer_file.h b/compiler-rt/lib/sanitizer_common/sanitizer_file.h index 4a78a0e0ac881..26681f0493d73 100644 --- a/compiler-rt/lib/sanitizer_common/sanitizer_file.h +++ b/compiler-rt/lib/sanitizer_common/sanitizer_file.h @@ -87,8 +87,8 @@ bool IsAbsolutePath(const char *path); // The child process will close all fds after STDERR_FILENO // before passing control to a program. pid_t StartSubprocess(const char *filename, const char *const argv[], - fd_t stdin_fd = kInvalidFd, fd_t stdout_fd = kInvalidFd, - fd_t stderr_fd = kInvalidFd); + const char *const envp[], fd_t stdin_fd = kInvalidFd, + fd_t stdout_fd = kInvalidFd, fd_t stderr_fd = kInvalidFd); // Checks if specified process is still running bool IsProcessRunning(pid_t pid); // Waits for the process to finish and returns its exit code. diff --git a/compiler-rt/lib/sanitizer_common/sanitizer_mac.cpp b/compiler-rt/lib/sanitizer_common/sanitizer_mac.cpp index ea4bd02aa92e4..c7a111c38ae57 100644 --- a/compiler-rt/lib/sanitizer_common/sanitizer_mac.cpp +++ b/compiler-rt/lib/sanitizer_common/sanitizer_mac.cpp @@ -242,7 +242,8 @@ int internal_sysctlbyname(const char *sname, void *oldp, uptr *oldlenp, (size_t)newlen); } -static fd_t internal_spawn_impl(const char *argv[], pid_t *pid) { +static fd_t internal_spawn_impl(const char *argv[], const char *envp[], + pid_t *pid) { fd_t master_fd = kInvalidFd; fd_t slave_fd = kInvalidFd; @@ -298,8 +299,8 @@ static fd_t internal_spawn_impl(const char *argv[], pid_t *pid) { // posix_spawn char **argv_casted = const_cast(argv); - char **env = GetEnviron(); - res = posix_spawn(pid, argv[0], &acts, &attrs, argv_casted, env); + char **envp_casted = const_cast(envp); + res = posix_spawn(pid, argv[0], &acts, &attrs, argv_casted, envp_casted); if (res != 0) return kInvalidFd; // Disable echo in the new terminal, disable CR. @@ -316,7 +317,7 @@ static fd_t internal_spawn_impl(const char *argv[], pid_t *pid) { return fd; } -fd_t internal_spawn(const char *argv[], pid_t *pid) { +fd_t internal_spawn(const char *argv[], const char *envp[], pid_t *pid) { // The client program may close its stdin and/or stdout and/or stderr thus // allowing open/posix_openpt to reuse file descriptors 0, 1 or 2. In this // case the communication is broken if either the parent or the child tries to @@ -331,7 +332,7 @@ fd_t internal_spawn(const char *argv[], pid_t *pid) { break; } - fd_t fd = internal_spawn_impl(argv, pid); + fd_t fd = internal_spawn_impl(argv, envp, pid); for (; count > 0; count--) { internal_close(low_fds[count]); diff --git a/compiler-rt/lib/sanitizer_common/sanitizer_posix.h b/compiler-rt/lib/sanitizer_common/sanitizer_posix.h index 05fb0f630207c..4ea6263d56bfb 100644 --- a/compiler-rt/lib/sanitizer_common/sanitizer_posix.h +++ b/compiler-rt/lib/sanitizer_common/sanitizer_posix.h @@ -63,7 +63,7 @@ uptr internal_ptrace(int request, int pid, void *addr, void *data); uptr internal_waitpid(int pid, int *status, int options); int internal_fork(); -fd_t internal_spawn(const char *argv[], pid_t *pid); +fd_t internal_spawn(const char *argv[], const char *envp[], pid_t *pid); int internal_sysctl(const int *name, unsigned int namelen, void *oldp, uptr *oldlenp, const void *newp, uptr newlen); diff --git a/compiler-rt/lib/sanitizer_common/sanitizer_posix_libcdep.cpp b/compiler-rt/lib/sanitizer_common/sanitizer_posix_libcdep.cpp index 304b3a01a08b6..f920172c06d63 100644 --- a/compiler-rt/lib/sanitizer_common/sanitizer_posix_libcdep.cpp +++ b/compiler-rt/lib/sanitizer_common/sanitizer_posix_libcdep.cpp @@ -426,7 +426,8 @@ void AdjustStackSize(void *attr_) { #endif // !SANITIZER_GO pid_t StartSubprocess(const char *program, const char *const argv[], - fd_t stdin_fd, fd_t stdout_fd, fd_t stderr_fd) { + const char *const envp[], fd_t stdin_fd, fd_t stdout_fd, + fd_t stderr_fd) { auto file_closer = at_scope_exit([&] { if (stdin_fd != kInvalidFd) { internal_close(stdin_fd); @@ -469,7 +470,8 @@ pid_t StartSubprocess(const char *program, const char *const argv[], for (int fd = sysconf(_SC_OPEN_MAX); fd > 2; fd--) internal_close(fd); - execv(program, const_cast(&argv[0])); + internal_execve(program, const_cast(&argv[0]), + const_cast(envp)); internal__exit(1); } diff --git a/compiler-rt/lib/sanitizer_common/sanitizer_symbolizer.cpp b/compiler-rt/lib/sanitizer_common/sanitizer_symbolizer.cpp index ce2ece5f4d512..0c4b84c767aa1 100644 --- a/compiler-rt/lib/sanitizer_common/sanitizer_symbolizer.cpp +++ b/compiler-rt/lib/sanitizer_common/sanitizer_symbolizer.cpp @@ -126,4 +126,10 @@ Symbolizer::SymbolizerScope::~SymbolizerScope() { sym_->end_hook_(); } +void Symbolizer::LateInitializeTools() { + for (auto &tool : tools_) { + tool.LateInitialize(); + } +} + } // namespace __sanitizer diff --git a/compiler-rt/lib/sanitizer_common/sanitizer_symbolizer.h b/compiler-rt/lib/sanitizer_common/sanitizer_symbolizer.h index 51648e2d0e8d7..2476b0ea7bf7d 100644 --- a/compiler-rt/lib/sanitizer_common/sanitizer_symbolizer.h +++ b/compiler-rt/lib/sanitizer_common/sanitizer_symbolizer.h @@ -209,6 +209,9 @@ class Symbolizer final { private: const Symbolizer *sym_; }; + + // Calls `LateInitialize()` on all items in `tools_`. + void LateInitializeTools(); }; #ifdef SANITIZER_WINDOWS diff --git a/compiler-rt/lib/sanitizer_common/sanitizer_symbolizer_internal.h b/compiler-rt/lib/sanitizer_common/sanitizer_symbolizer_internal.h index c04797dd61b8b..e4c351e667b4d 100644 --- a/compiler-rt/lib/sanitizer_common/sanitizer_symbolizer_internal.h +++ b/compiler-rt/lib/sanitizer_common/sanitizer_symbolizer_internal.h @@ -69,6 +69,11 @@ class SymbolizerTool { virtual const char *Demangle(const char *name) { return nullptr; } + + // Called during the LateInitialize phase of Sanitizer initialization. + // Usually this is a safe place to call code that might need to use user + // memory allocators. + virtual void LateInitialize() {} }; // SymbolizerProcess encapsulates communication between the tool and @@ -86,6 +91,8 @@ class SymbolizerProcess { // Customizable by subclasses. virtual bool StartSymbolizerSubprocess(); virtual bool ReadFromSymbolizer(char *buffer, uptr max_length); + // Return the environment to run the symbolizer in. + virtual char **GetEnvP() { return GetEnviron(); } private: virtual bool ReachedEndOfOutput(const char *buffer, uptr length) const { diff --git a/compiler-rt/lib/sanitizer_common/sanitizer_symbolizer_mac.cpp b/compiler-rt/lib/sanitizer_common/sanitizer_symbolizer_mac.cpp index f26efe5c50b55..4623c3f76b120 100644 --- a/compiler-rt/lib/sanitizer_common/sanitizer_symbolizer_mac.cpp +++ b/compiler-rt/lib/sanitizer_common/sanitizer_symbolizer_mac.cpp @@ -20,6 +20,7 @@ #include #include +#include #include #include #include @@ -50,18 +51,59 @@ bool DlAddrSymbolizer::SymbolizeData(uptr addr, DataInfo *datainfo) { return true; } +#define K_ATOS_ENV_VAR "__check_mach_ports_lookup" + class AtosSymbolizerProcess : public SymbolizerProcess { public: - explicit AtosSymbolizerProcess(const char *path, pid_t parent_pid) + explicit AtosSymbolizerProcess(const char *path) : SymbolizerProcess(path, /*use_posix_spawn*/ true) { - // Put the string command line argument in the object so that it outlives - // the call to GetArgV. - internal_snprintf(pid_str_, sizeof(pid_str_), "%d", parent_pid); + pid_str_[0] = '\0'; + } + + void LateInitialize() { + if (SANITIZER_IOSSIM) { + // `putenv()` may call malloc/realloc so it is only safe to do this + // during LateInitialize() or later (i.e. we can't do this in the + // constructor). We also can't do this in `StartSymbolizerSubprocess()` + // because in TSan we switch allocators when we're symbolizing. + // We use `putenv()` rather than `setenv()` so that we can later directly + // write into the storage without LibC getting involved to change what the + // variable is set to + int result = putenv(mach_port_env_var_entry_); + CHECK_EQ(result, 0); + } } private: bool StartSymbolizerSubprocess() override { // Configure sandbox before starting atos process. + + // Put the string command line argument in the object so that it outlives + // the call to GetArgV. + internal_snprintf(pid_str_, sizeof(pid_str_), "%d", internal_getpid()); + + if (SANITIZER_IOSSIM) { + // `atos` in the simulator is restricted in its ability to retrieve the + // task port for the target process (us) so we need to do extra work + // to pass our task port to it. + mach_port_t ports[]{mach_task_self()}; + kern_return_t ret = + mach_ports_register(mach_task_self(), ports, /*count=*/1); + CHECK_EQ(ret, KERN_SUCCESS); + + // Set environment variable that signals to `atos` that it should look + // for our task port. We can't call `setenv()` here because it might call + // malloc/realloc. To avoid that we instead update the + // `mach_port_env_var_entry_` variable with our current PID. + uptr count = internal_snprintf(mach_port_env_var_entry_, + sizeof(mach_port_env_var_entry_), + K_ATOS_ENV_VAR "=%s", pid_str_); + CHECK_GE(count, sizeof(K_ATOS_ENV_VAR) + internal_strlen(pid_str_)); + // Document our assumption but without calling `getenv()` in normal + // builds. + DCHECK_EQ(internal_strcmp(getenv(K_ATOS_ENV_VAR), pid_str_), 0); + } + return SymbolizerProcess::StartSymbolizerSubprocess(); } @@ -85,8 +127,13 @@ class AtosSymbolizerProcess : public SymbolizerProcess { } char pid_str_[16]; + // Space for `\0` in `kAtosEnvVar_` is reused for `=`. + char mach_port_env_var_entry_[sizeof(K_ATOS_ENV_VAR) + sizeof(pid_str_)] = + K_ATOS_ENV_VAR "=0"; }; +#undef K_ATOS_ENV_VAR + static bool ParseCommandOutput(const char *str, uptr addr, char **out_name, char **out_module, char **out_file, uptr *line, uptr *start_address) { @@ -138,7 +185,7 @@ static bool ParseCommandOutput(const char *str, uptr addr, char **out_name, } AtosSymbolizer::AtosSymbolizer(const char *path, LowLevelAllocator *allocator) - : process_(new(*allocator) AtosSymbolizerProcess(path, getpid())) {} + : process_(new (*allocator) AtosSymbolizerProcess(path)) {} bool AtosSymbolizer::SymbolizePC(uptr addr, SymbolizedStack *stack) { if (!process_) return false; @@ -188,6 +235,8 @@ bool AtosSymbolizer::SymbolizeData(uptr addr, DataInfo *info) { return true; } +void AtosSymbolizer::LateInitialize() { process_->LateInitialize(); } + } // namespace __sanitizer #endif // SANITIZER_MAC diff --git a/compiler-rt/lib/sanitizer_common/sanitizer_symbolizer_mac.h b/compiler-rt/lib/sanitizer_common/sanitizer_symbolizer_mac.h index 68521375e64c4..8996131fc1385 100644 --- a/compiler-rt/lib/sanitizer_common/sanitizer_symbolizer_mac.h +++ b/compiler-rt/lib/sanitizer_common/sanitizer_symbolizer_mac.h @@ -35,6 +35,7 @@ class AtosSymbolizer : public SymbolizerTool { bool SymbolizePC(uptr addr, SymbolizedStack *stack) override; bool SymbolizeData(uptr addr, DataInfo *info) override; + void LateInitialize() override; private: AtosSymbolizerProcess *process_; diff --git a/compiler-rt/lib/sanitizer_common/sanitizer_symbolizer_markup.cpp b/compiler-rt/lib/sanitizer_common/sanitizer_symbolizer_markup.cpp index 57b4d0c9d9613..2963af953609e 100644 --- a/compiler-rt/lib/sanitizer_common/sanitizer_symbolizer_markup.cpp +++ b/compiler-rt/lib/sanitizer_common/sanitizer_symbolizer_markup.cpp @@ -94,7 +94,9 @@ Symbolizer *Symbolizer::PlatformInit() { return new (symbolizer_allocator_) Symbolizer({}); } -void Symbolizer::LateInitialize() { Symbolizer::GetOrInit(); } +void Symbolizer::LateInitialize() { + Symbolizer::GetOrInit()->LateInitializeTools(); +} void StartReportDeadlySignal() {} void ReportDeadlySignal(const SignalContext &sig, u32 tid, diff --git a/compiler-rt/lib/sanitizer_common/sanitizer_symbolizer_posix_libcdep.cpp b/compiler-rt/lib/sanitizer_common/sanitizer_symbolizer_posix_libcdep.cpp index c123ecb11206c..d7b931bc23795 100644 --- a/compiler-rt/lib/sanitizer_common/sanitizer_symbolizer_posix_libcdep.cpp +++ b/compiler-rt/lib/sanitizer_common/sanitizer_symbolizer_posix_libcdep.cpp @@ -151,9 +151,19 @@ bool SymbolizerProcess::StartSymbolizerSubprocess() { GetArgV(path_, argv); pid_t pid; + // Report how symbolizer is being launched for debugging purposes. + if (Verbosity() >= 3) { + // Only use `Report` for first line so subsequent prints don't get prefixed + // with current PID. + Report("Launching Symbolizer process: "); + for (unsigned index = 0; index < kArgVMax && argv[index]; ++index) + Printf("%s ", argv[index]); + Printf("\n"); + } + if (use_posix_spawn_) { #if SANITIZER_MAC - fd_t fd = internal_spawn(argv, &pid); + fd_t fd = internal_spawn(argv, const_cast(GetEnvP()), &pid); if (fd == kInvalidFd) { Report("WARNING: failed to spawn external symbolizer (errno: %d)\n", errno); @@ -173,7 +183,7 @@ bool SymbolizerProcess::StartSymbolizerSubprocess() { return false; } - pid = StartSubprocess(path_, argv, /* stdin */ outfd[0], + pid = StartSubprocess(path_, argv, GetEnvP(), /* stdin */ outfd[0], /* stdout */ infd[1]); if (pid < 0) { internal_close(infd[0]); @@ -478,7 +488,7 @@ Symbolizer *Symbolizer::PlatformInit() { } void Symbolizer::LateInitialize() { - Symbolizer::GetOrInit(); + Symbolizer::GetOrInit()->LateInitializeTools(); InitializeSwiftDemangler(); } diff --git a/compiler-rt/lib/sanitizer_common/sanitizer_symbolizer_win.cpp b/compiler-rt/lib/sanitizer_common/sanitizer_symbolizer_win.cpp index 2808779156edd..373437e7ee2ad 100644 --- a/compiler-rt/lib/sanitizer_common/sanitizer_symbolizer_win.cpp +++ b/compiler-rt/lib/sanitizer_common/sanitizer_symbolizer_win.cpp @@ -310,7 +310,7 @@ Symbolizer *Symbolizer::PlatformInit() { } void Symbolizer::LateInitialize() { - Symbolizer::GetOrInit(); + Symbolizer::GetOrInit()->LateInitializeTools(); } } // namespace __sanitizer diff --git a/compiler-rt/lib/sanitizer_common/sanitizer_win.cpp b/compiler-rt/lib/sanitizer_common/sanitizer_win.cpp index 36dde49d87083..1d6b914618a5c 100644 --- a/compiler-rt/lib/sanitizer_common/sanitizer_win.cpp +++ b/compiler-rt/lib/sanitizer_common/sanitizer_win.cpp @@ -1060,7 +1060,8 @@ char **GetEnviron() { } pid_t StartSubprocess(const char *program, const char *const argv[], - fd_t stdin_fd, fd_t stdout_fd, fd_t stderr_fd) { + const char *const envp[], fd_t stdin_fd, fd_t stdout_fd, + fd_t stderr_fd) { // FIXME: implement on this platform // Should be implemented based on // SymbolizerProcess::StarAtSymbolizerSubprocess diff --git a/compiler-rt/lib/sanitizer_common/tests/sanitizer_linux_test.cpp b/compiler-rt/lib/sanitizer_common/tests/sanitizer_linux_test.cpp index 1d8e7e8af26ca..cb6c0724ac884 100644 --- a/compiler-rt/lib/sanitizer_common/tests/sanitizer_linux_test.cpp +++ b/compiler-rt/lib/sanitizer_common/tests/sanitizer_linux_test.cpp @@ -264,7 +264,7 @@ TEST(SanitizerCommon, StartSubprocessTest) { const char *shell = "/bin/sh"; #endif const char *argv[] = {shell, "-c", "echo -n 'hello'", (char *)NULL}; - int pid = StartSubprocess(shell, argv, + int pid = StartSubprocess(shell, argv, GetEnviron(), /* stdin */ kInvalidFd, /* stdout */ pipe_fds[1]); ASSERT_GT(pid, 0); diff --git a/compiler-rt/test/asan/TestCases/Darwin/duplicate_os_log_reports.cpp b/compiler-rt/test/asan/TestCases/Darwin/duplicate_os_log_reports.cpp new file mode 100644 index 0000000000000..5f923d22a9a41 --- /dev/null +++ b/compiler-rt/test/asan/TestCases/Darwin/duplicate_os_log_reports.cpp @@ -0,0 +1,68 @@ +// UNSUPPORTED: ios +// REQUIRES: shell +// REQUIRES: darwin_log_cmd +// RUN: %clangxx_asan -fsanitize-recover=address %s -o %t +// RUN: { %env_asan_opts=halt_on_error=0,log_to_syslog=1 %run %t > %t.process_output.txt 2>&1 & } \ +// RUN: ; export TEST_PID=$! ; wait ${TEST_PID} + +// Check process output. +// RUN: FileCheck %s --check-prefixes CHECK,CHECK-PROC -input-file=%t.process_output.txt + +// Check syslog output. We filter recent system logs based on PID to avoid +// getting the logs of previous test runs. +// RUN: log show --debug --last 2m --predicate "processID == ${TEST_PID}" --style syslog > %t.process_syslog_output.txt +// RUN: FileCheck %s -input-file=%t.process_syslog_output.txt +#include +#include +#include + +const int kBufferSize = 512; +char *buffer; + +// `readZero` and `readOne` exist so that we can distinguish the two +// error reports based on the symbolized stacktrace. +void readZero() { + assert(__asan_address_is_poisoned(buffer)); + char c = buffer[0]; + printf("Read %c\n", c); +} + +void readOne() { + assert(__asan_address_is_poisoned(buffer + 1)); + char c = buffer[1]; + printf("Read %c\n", c); +} + +int main() { + buffer = static_cast(malloc(kBufferSize)); + assert(buffer); + // Deliberately poison `buffer` so that we have a deterministic way + // triggering two ASan reports in a row in the no halt_on_error mode (e.g. Two + // heap-use-after free in a row might not be deterministic). + __asan_poison_memory_region(buffer, kBufferSize); + + // This sequence of ASan reports are designed to catch an old bug in the way + // ASan's internal syslog buffer was handled after reporting an issue. + // Previously in the no halt_on_error mode the internal buffer wasn't cleared + // after reporting an issue. When another issue was encountered everything + // that was already in the buffer would be written to the syslog again + // leading to duplicate reports in the syslog. + + // First bad access. + // CHECK: use-after-poison + // CHECK-NEXT: READ of size 1 + // CHECK-NEXT: #0 0x{{[0-9a-f]+}} in readZero + // CHECK: SUMMARY: {{.*}} use-after-poison {{.*}} in readZero + readZero(); + + // Second bad access. + // CHECK: use-after-poison + // CHECK-NEXT: READ of size 1 + // CHECK-NEXT: #0 0x{{[0-9a-f]+}} in readOne + // CHECK: SUMMARY: {{.*}} use-after-poison {{.*}} in readOne + readOne(); + + // CHECK-PROC: DONE + printf("DONE\n"); + return 0; +} diff --git a/compiler-rt/test/lit.common.cfg.py b/compiler-rt/test/lit.common.cfg.py index 622261535fa2e..cc4ef031108ec 100644 --- a/compiler-rt/test/lit.common.cfg.py +++ b/compiler-rt/test/lit.common.cfg.py @@ -537,6 +537,19 @@ def is_windows_lto_supported(): # much slower. Let's override this and run lit tests with 'abort_on_error=0'. config.default_sanitizer_opts += ['abort_on_error=0'] config.default_sanitizer_opts += ['log_to_syslog=0'] + if lit.util.which('log'): + # Querying the log can only done by a privileged user so + # so check if we can query the log. + exit_code = -1 + with open('/dev/null', 'r') as f: + # Run a `log show` command the should finish fairly quickly and produce very little output. + exit_code = subprocess.call(['log', 'show', '--last', '1m', '--predicate', '1 == 0'], stdout=f, stderr=f) + if exit_code == 0: + config.available_features.add('darwin_log_cmd') + else: + lit_config.warning('log command found but cannot queried') + else: + lit_config.warning('log command not found. Some tests will be skipped.') elif config.android: config.default_sanitizer_opts += ['abort_on_error=0'] diff --git a/compiler-rt/test/sanitizer_common/TestCases/Darwin/print-stack-trace-in-code-loaded-after-fork.cpp b/compiler-rt/test/sanitizer_common/TestCases/Darwin/print-stack-trace-in-code-loaded-after-fork.cpp new file mode 100644 index 0000000000000..db4cdf8f9b6da --- /dev/null +++ b/compiler-rt/test/sanitizer_common/TestCases/Darwin/print-stack-trace-in-code-loaded-after-fork.cpp @@ -0,0 +1,60 @@ +// RUN: %clangxx %s -g -DSHARED_LIB -shared -o %t_shared_lib.dylib +// RUN: %clangxx %s -g -USHARED_LIB -o %t_loader +// RUN: %env_tool_opts=verbosity=3 %run %t_loader %t_shared_lib.dylib > %t_loader_output.txt 2>&1 +// RUN: FileCheck -input-file=%t_loader_output.txt %s +// RUN: FileCheck -check-prefix=CHECK-STACKTRACE -input-file=%t_loader_output.txt %s + +#include + +#ifdef SHARED_LIB +#include + +extern "C" void PrintStack() { + fprintf(stderr, "Calling __sanitizer_print_stack_trace\n"); + // CHECK-STACKTRACE: #0{{( *0x.* *in *)?}} __sanitizer_print_stack_trace + // CHECK-STACKTRACE: #1{{( *0x.* *in *)?}} PrintStack {{.*}}print-stack-trace-in-code-loaded-after-fork.cpp:[[@LINE+1]] + __sanitizer_print_stack_trace(); +} +#else +#include +#include +#include +#include +#include + +typedef void (*PrintStackFnPtrTy)(void); + +int main(int argc, char **argv) { + assert(argc == 2); + pid_t pid = fork(); + if (pid != 0) { + // Parent + pid_t parent_pid = getpid(); + fprintf(stderr, "parent: %d\n", parent_pid); + int status = 0; + pid_t child = waitpid(pid, &status, /*options=*/0); + assert(pid == child); + bool clean_exit = WIFEXITED(status) && WEXITSTATUS(status) == 0; + return !clean_exit; + } + // Child. + pid = getpid(); + // CHECK: child: [[CHILD_PID:[0-9]+]] + fprintf(stderr, "child: %d\n", pid); + // We load new code into the child process that isn't loaded into the parent. + // When we symbolize in `PrintStack` if the symbolizer is told to symbolize + // the parent (an old bug) rather than the child then symbolization will + // fail. + const char *library_to_load = argv[1]; + void *handle = dlopen(library_to_load, RTLD_NOW | RTLD_LOCAL); + assert(handle); + PrintStackFnPtrTy PrintStackFnPtr = (PrintStackFnPtrTy)dlsym(handle, "PrintStack"); + assert(PrintStackFnPtr); + // Check that the symbolizer is told examine the child process. + // CHECK: Launching Symbolizer process: {{.+}}atos -p [[CHILD_PID]] + // CHECK-STACKTRACE: #2{{( *0x.* *in *)?}} main {{.*}}print-stack-trace-in-code-loaded-after-fork.cpp:[[@LINE+1]] + PrintStackFnPtr(); + return 0; +} + +#endif diff --git a/compiler-rt/test/sanitizer_common/TestCases/symbolize_debug_argv.cpp b/compiler-rt/test/sanitizer_common/TestCases/symbolize_debug_argv.cpp new file mode 100644 index 0000000000000..262e50bf7be2c --- /dev/null +++ b/compiler-rt/test/sanitizer_common/TestCases/symbolize_debug_argv.cpp @@ -0,0 +1,9 @@ +// RUN: %clangxx %s -g -o %t +// RUN: %env_tool_opts=verbosity=3 %run %t 2>&1 | FileCheck %s +#include + +int main(int argc, char **argv) { + // CHECK: Launching Symbolizer process: {{.+}} + __sanitizer_print_stack_trace(); + return 0; +} diff --git a/compiler-rt/test/tsan/Darwin/no_call_setenv_in_symbolize.cpp b/compiler-rt/test/tsan/Darwin/no_call_setenv_in_symbolize.cpp new file mode 100644 index 0000000000000..1e31693cc74d5 --- /dev/null +++ b/compiler-rt/test/tsan/Darwin/no_call_setenv_in_symbolize.cpp @@ -0,0 +1,43 @@ +// RUN: %clangxx_tsan -O1 %s -o %t +// `handle_sigbus=0` is required because when the rdar://problem/58789439 bug was +// present TSan's runtime could derefence bad memory leading to SIGBUS being raised. +// If the signal was caught TSan would deadlock because it would try to run the +// symbolizer again. +// RUN: %env_tsan_opts=handle_sigbus=0,symbolize=1 %run %t 2>&1 | FileCheck %s +// RUN: %env_tsan_opts=handle_sigbus=0,symbolize=1 __check_mach_ports_lookup=some_value %run %t 2>&1 | FileCheck %s +#include +#include +#include + +const char *kEnvName = "__UNLIKELY_ENV_VAR_NAME__"; + +int main() { + if (getenv(kEnvName)) { + fprintf(stderr, "Env var %s should not be set\n", kEnvName); + abort(); + } + + // This will set an environment variable that isn't already in + // the environment array. This will cause Darwin's Libc to + // malloc() a new array. + if (setenv(kEnvName, "some_value", /*overwrite=*/1)) { + fprintf(stderr, "Failed to set %s \n", kEnvName); + abort(); + } + + // rdar://problem/58789439 + // Now trigger symbolization. If symbolization tries to call + // to `setenv` that adds a new environment variable, then Darwin + // Libc will call `realloc()` and TSan's runtime will hit + // an assertion failure because TSan's runtime uses a different + // allocator during symbolization which leads to `realloc()` being + // called on a pointer that the allocator didn't allocate. + // + // CHECK: #{{[0-9]}} main {{.*}}no_call_setenv_in_symbolize.cpp:[[@LINE+1]] + __sanitizer_print_stack_trace(); + + // CHECK: DONE + fprintf(stderr, "DONE\n"); + + return 0; +} diff --git a/lldb/bindings/interface/SBAddress.i b/lldb/bindings/interface/SBAddress.i index 4658534d153ea..de277607d8f5e 100644 --- a/lldb/bindings/interface/SBAddress.i +++ b/lldb/bindings/interface/SBAddress.i @@ -154,7 +154,7 @@ public: def __int__(self): '''Convert an address to a load address if there is a process and that process is alive, or to a file address otherwise.''' - if process.is_alive: + if process and process.is_alive: return self.GetLoadAddress (target) else: return self.GetFileAddress () diff --git a/lldb/docs/use/variable.rst b/lldb/docs/use/variable.rst index f3bde2de4144d..00b384a368eb3 100644 --- a/lldb/docs/use/variable.rst +++ b/lldb/docs/use/variable.rst @@ -845,7 +845,7 @@ adheres to a given interface (the word is italicized because Python has no explicit notion of interface, by that word we mean a given set of methods must be implemented by the Python class): -:: +.. code-block:: python class SyntheticChildrenProvider: def __init__(self, valobj, internal_dict): @@ -882,9 +882,30 @@ As a shortcut for this, you can inherit from lldb.SBSyntheticValueProvider, and just define get_value as other methods are defaulted in the superclass as returning default no-children responses. -If a synthetic child provider supplies a special child named $$dereference$$ -then it will be used when evaluating opertaor* and operator-> in the frame -variable command and related SB API functions. +If a synthetic child provider supplies a special child named +``$$dereference$$`` then it will be used when evaluating ``operator *`` and +``operator ->`` in the frame variable command and related SB API +functions. It is possible to declare this synthetic child without +including it in the range of children displayed by LLDB. For example, +this subset of a synthetic children provider class would allow the +synthetic value to be dereferenced without actually showing any +synthtic children in the UI: + +.. code-block:: python + + class SyntheticChildrenProvider: + [...] + def num_children(self): + return 0 + def get_child_index(self, name): + if name == '$$dereference$$': + return 0 + return -1 + def get_child_at_index(self, index): + if index == 0: + return + return None + For examples of how synthetic children are created, you are encouraged to look at examples/synthetic in the LLDB trunk. Please, be aware that the code in diff --git a/lldb/include/lldb/API/SBTarget.h b/lldb/include/lldb/API/SBTarget.h index da2246f7a4eb3..cc6b5a23bb2b9 100644 --- a/lldb/include/lldb/API/SBTarget.h +++ b/lldb/include/lldb/API/SBTarget.h @@ -127,7 +127,9 @@ class LLDB_API SBTarget { /// The argument array. /// /// \param[in] envp - /// The environment array. + /// The environment array. If this is null, the default + /// environment values (provided through `settings set + /// target.env-vars`) will be used. /// /// \param[in] stdin_path /// The path to use when re-directing the STDIN of the new @@ -175,7 +177,9 @@ class LLDB_API SBTarget { /// The argument array. /// /// \param[in] envp - /// The environment array. + /// The environment array. If this isn't provided, the default + /// environment values (provided through `settings set + /// target.env-vars`) will be used. /// /// \param[in] working_directory /// The working directory to have the child process run in diff --git a/lldb/include/lldb/Core/Module.h b/lldb/include/lldb/Core/Module.h index cad95afcee243..8cde45ad6c784 100644 --- a/lldb/include/lldb/Core/Module.h +++ b/lldb/include/lldb/Core/Module.h @@ -19,6 +19,7 @@ #include "lldb/Utility/ConstString.h" #include "lldb/Utility/FileSpec.h" #include "lldb/Utility/Status.h" +#include "lldb/Utility/XcodeSDK.h" #include "lldb/Utility/UUID.h" #include "lldb/lldb-defines.h" #include "lldb/lldb-enumerations.h" @@ -508,6 +509,12 @@ class Module : public std::enable_shared_from_this, m_mod_time = mod_time; } + /// This callback will be called by SymbolFile implementations when + /// parsing a compile unit that contains SDK information. + /// \param sdk will be merged with \p m_sdk. + /// \param sysroot will be added to the path remapping dictionary. + void RegisterXcodeSDK(llvm::StringRef sdk, llvm::StringRef sysroot); + /// Tells whether this module is capable of being the main executable for a /// process. /// @@ -982,6 +989,10 @@ class Module : public std::enable_shared_from_this, ///when you have debug info for a module ///that doesn't match where the sources ///currently are + + /// The (Xcode) SDK this module was compiled with. + XcodeSDK m_xcode_sdk; + lldb::SectionListUP m_sections_up; ///< Unified section list for module that /// is used by the ObjectFile and and /// ObjectFile instances for the debug info diff --git a/lldb/include/lldb/Core/ModuleList.h b/lldb/include/lldb/Core/ModuleList.h index c47317af70439..5e17b07bd6fdb 100644 --- a/lldb/include/lldb/Core/ModuleList.h +++ b/lldb/include/lldb/Core/ModuleList.h @@ -49,7 +49,9 @@ class ModuleListProperties : public Properties { public: ModuleListProperties(); - bool GetUseDWARFImporter() const; + bool GetUseSwiftClangImporter() const; + bool GetUseSwiftDWARFImporter() const; + bool SetUseSwiftDWARFImporter(bool new_value); FileSpec GetClangModulesCachePath() const; bool SetClangModulesCachePath(llvm::StringRef path); SwiftModuleLoadingMode GetSwiftModuleLoadingMode() const; diff --git a/lldb/include/lldb/Core/UserSettingsController.h b/lldb/include/lldb/Core/UserSettingsController.h index 6ae3bdec16650..5374137a8d639 100644 --- a/lldb/include/lldb/Core/UserSettingsController.h +++ b/lldb/include/lldb/Core/UserSettingsController.h @@ -9,6 +9,7 @@ #ifndef liblldb_UserSettingsController_h_ #define liblldb_UserSettingsController_h_ +#include "lldb/Core/Value.h" #include "lldb/Utility/Status.h" #include "lldb/lldb-forward.h" #include "lldb/lldb-private-enumerations.h" diff --git a/lldb/include/lldb/DataFormatters/FormattersHelpers.h b/lldb/include/lldb/DataFormatters/FormattersHelpers.h index 79bd376c76eb6..c9d13726be97c 100644 --- a/lldb/include/lldb/DataFormatters/FormattersHelpers.h +++ b/lldb/include/lldb/DataFormatters/FormattersHelpers.h @@ -56,6 +56,8 @@ size_t ExtractIndexFromString(const char *item_name); lldb::addr_t GetArrayAddressOrPointerValue(ValueObject &valobj); +lldb::ValueObjectSP GetValueOfLibCXXCompressedPair(ValueObject &pair); + time_t GetOSXEpoch(); struct InferiorSizedWord { diff --git a/lldb/include/lldb/DataFormatters/StringPrinter.h b/lldb/include/lldb/DataFormatters/StringPrinter.h index 67b31f13a3cbd..03035ea934ee9 100644 --- a/lldb/include/lldb/DataFormatters/StringPrinter.h +++ b/lldb/include/lldb/DataFormatters/StringPrinter.h @@ -115,9 +115,15 @@ class StringPrinter { lldb::ProcessSP GetProcessSP() const { return m_process_sp; } + void SetHasSourceSize(bool e) { m_has_source_size = e; } + + bool HasSourceSize() const { return m_has_source_size; } + private: uint64_t m_location = 0; lldb::ProcessSP m_process_sp; + /// True iff we know the source size of the string. + bool m_has_source_size = false; }; class ReadBufferAndDumpToStreamOptions : public DumpToStreamOptions { diff --git a/lldb/include/lldb/Host/FileSystem.h b/lldb/include/lldb/Host/FileSystem.h index 528c43519a326..32aa548e8420f 100644 --- a/lldb/include/lldb/Host/FileSystem.h +++ b/lldb/include/lldb/Host/FileSystem.h @@ -186,6 +186,9 @@ class FileSystem { return m_fs; } + void Collect(const FileSpec &file_spec); + void Collect(const llvm::Twine &file); + private: static llvm::Optional &InstanceImpl(); llvm::IntrusiveRefCntPtr m_fs; diff --git a/lldb/include/lldb/Host/Host.h b/lldb/include/lldb/Host/Host.h index 884c5cf632134..f19cb85d2329c 100644 --- a/lldb/include/lldb/Host/Host.h +++ b/lldb/include/lldb/Host/Host.h @@ -27,8 +27,8 @@ namespace lldb_private { class FileAction; class ProcessLaunchInfo; class ProcessInstanceInfo; -class ProcessInstanceInfoList; class ProcessInstanceInfoMatch; +typedef std::vector ProcessInstanceInfoList; // Exit Type for inferior processes struct WaitStatus { @@ -232,6 +232,10 @@ class Host { static std::unique_ptr CreateDefaultConnection(llvm::StringRef url); + +protected: + static uint32_t FindProcessesImpl(const ProcessInstanceInfoMatch &match_info, + ProcessInstanceInfoList &proc_infos); }; } // namespace lldb_private diff --git a/lldb/include/lldb/Host/HostInfoBase.h b/lldb/include/lldb/Host/HostInfoBase.h index c59050cb34e97..ff328783d4b7e 100644 --- a/lldb/include/lldb/Host/HostInfoBase.h +++ b/lldb/include/lldb/Host/HostInfoBase.h @@ -12,6 +12,7 @@ #include "lldb/Utility/ArchSpec.h" #include "lldb/Utility/FileSpec.h" #include "lldb/Utility/UserIDResolver.h" +#include "lldb/Utility/XcodeSDK.h" #include "lldb/lldb-enumerations.h" #include "llvm/ADT/StringRef.h" @@ -91,6 +92,9 @@ class HostInfoBase { static bool ComputePathRelativeToLibrary(FileSpec &file_spec, llvm::StringRef dir); + /// Return the directory containing a specific Xcode SDK. + static std::string GetXcodeSDK(XcodeSDK sdk) { return {}; } + protected: static bool ComputeSharedLibraryDirectory(FileSpec &file_spec); static bool ComputeSupportExeDirectory(FileSpec &file_spec); diff --git a/lldb/include/lldb/Host/macosx/HostInfoMacOSX.h b/lldb/include/lldb/Host/macosx/HostInfoMacOSX.h index 217ca5bf1fce9..b21de371a3973 100644 --- a/lldb/include/lldb/Host/macosx/HostInfoMacOSX.h +++ b/lldb/include/lldb/Host/macosx/HostInfoMacOSX.h @@ -11,6 +11,7 @@ #include "lldb/Host/posix/HostInfoPosix.h" #include "lldb/Utility/FileSpec.h" +#include "lldb/Utility/XcodeSDK.h" #include "llvm/Support/VersionTuple.h" namespace lldb_private { @@ -31,7 +32,10 @@ class HostInfoMacOSX : public HostInfoPosix { static bool GetOSBuildString(std::string &s); static bool GetOSKernelDescription(std::string &s); static FileSpec GetProgramFileSpec(); + static std::string FindXcodeContentsDirectoryInPath(llvm::StringRef path); + /// Query xcrun to find an Xcode SDK directory. + static std::string GetXcodeSDK(XcodeSDK sdk); protected: static bool ComputeSupportExeDirectory(FileSpec &file_spec); static void ComputeHostArchitectureSupport(ArchSpec &arch_32, diff --git a/lldb/include/lldb/Symbol/Function.h b/lldb/include/lldb/Symbol/Function.h index 19f4ac91f90ab..8bb81b4204092 100644 --- a/lldb/include/lldb/Symbol/Function.h +++ b/lldb/include/lldb/Symbol/Function.h @@ -284,19 +284,33 @@ class CallEdge { /// Like \ref GetReturnPCAddress, but returns an unresolved file address. lldb::addr_t GetUnresolvedReturnPCAddress() const { return return_pc; } + /// Get the load PC address of the call instruction (or LLDB_INVALID_ADDRESS). + lldb::addr_t GetCallInstPC(Function &caller, Target &target) const; + /// Get the call site parameters available at this call edge. llvm::ArrayRef GetCallSiteParameters() const { return parameters; } protected: - CallEdge(lldb::addr_t return_pc, CallSiteParameterArray &¶meters) - : return_pc(return_pc), parameters(std::move(parameters)) {} + CallEdge(lldb::addr_t return_pc, lldb::addr_t call_inst_pc, + CallSiteParameterArray &¶meters) + : return_pc(return_pc), call_inst_pc(call_inst_pc), + parameters(std::move(parameters)) {} + + /// Helper that finds the load address of \p unresolved_pc, a file address + /// which refers to an instruction within \p caller. + static lldb::addr_t GetLoadAddress(lldb::addr_t unresolved_pc, + Function &caller, Target &target); /// An invalid address if this is a tail call. Otherwise, the return PC for /// the call. Note that this is a file address which must be resolved. lldb::addr_t return_pc; + /// The address of the call instruction. Usually an invalid address, unless + /// this is a tail call. + lldb::addr_t call_inst_pc; + CallSiteParameterArray parameters; }; @@ -308,8 +322,8 @@ class DirectCallEdge : public CallEdge { /// Construct a call edge using a symbol name to identify the callee, and a /// return PC within the calling function to identify a specific call site. DirectCallEdge(const char *symbol_name, lldb::addr_t return_pc, - CallSiteParameterArray &¶meters) - : CallEdge(return_pc, std::move(parameters)) { + lldb::addr_t call_inst_pc, CallSiteParameterArray &¶meters) + : CallEdge(return_pc, call_inst_pc, std::move(parameters)) { lazy_callee.symbol_name = symbol_name; } @@ -339,8 +353,9 @@ class IndirectCallEdge : public CallEdge { /// Construct a call edge using a DWARFExpression to identify the callee, and /// a return PC within the calling function to identify a specific call site. IndirectCallEdge(DWARFExpression call_target, lldb::addr_t return_pc, + lldb::addr_t call_inst_pc, CallSiteParameterArray &¶meters) - : CallEdge(return_pc, std::move(parameters)), + : CallEdge(return_pc, call_inst_pc, std::move(parameters)), call_target(std::move(call_target)) {} Function *GetCallee(ModuleList &images, ExecutionContext &exe_ctx) override; diff --git a/lldb/include/lldb/Symbol/SwiftASTContext.h b/lldb/include/lldb/Symbol/SwiftASTContext.h index e2fe629459e95..5cd9fccc68cf4 100644 --- a/lldb/include/lldb/Symbol/SwiftASTContext.h +++ b/lldb/include/lldb/Symbol/SwiftASTContext.h @@ -20,6 +20,7 @@ #include "lldb/Core/ThreadSafeDenseSet.h" #include "lldb/Symbol/CompilerType.h" #include "lldb/Symbol/TypeSystem.h" +#include "lldb/Symbol/SymbolFile.h" #include "lldb/Utility/ConstString.h" #include "lldb/lldb-private.h" @@ -47,6 +48,11 @@ class ModuleDecl; class SourceFile; struct PrintOptions; class MemoryBufferSerializedModuleLoader; +namespace Demangle { +class Demangler; +class Node; +using NodePointer = Node *; +} // namespace Demangle namespace irgen { class FixedTypeInfo; class TypeInfo; @@ -69,6 +75,30 @@ struct SourceModule; class SwiftASTContext; CompilerType ToCompilerType(swift::Type qual_type); +/// The implementation of lldb::Type's m_payload field for TypeSystemSwift. +class TypePayloadSwift { + /// Layout: bit 1 ... IsFixedValueBuffer. + Type::Payload m_payload = 0; + + static constexpr unsigned FixedValueBufferBit = 1; +public: + TypePayloadSwift() = default; + explicit TypePayloadSwift(bool is_fixed_value_buffer); + explicit TypePayloadSwift(Type::Payload opaque_payload) + : m_payload(opaque_payload) {} + operator Type::Payload() { return m_payload; } + + /// \return whether this is a Swift fixed-size buffer. Resilient variables in + /// fixed-size buffers may be indirect depending on the runtime size of the + /// type. This is more a property of the value than of its type. + bool IsFixedValueBuffer() { return Flags(m_payload).Test(FixedValueBufferBit); } + void SetIsFixedValueBuffer(bool is_fixed_value_buffer) { + m_payload = is_fixed_value_buffer + ? Flags(m_payload).Set(FixedValueBufferBit) + : Flags(m_payload).Clear(FixedValueBufferBit); + } +}; + /// Abstract base class for all Swift TypeSystems. /// /// Swift CompilerTypes are either a mangled name or a Swift AST @@ -125,6 +155,65 @@ class TypeSystemSwift : public TypeSystem { bool print_help_if_available, bool print_extensions_if_available) = 0; + /// Unavailable hardcoded functions that don't make sense for Swift. + /// \{ + ConstString DeclContextGetName(void *opaque_decl_ctx) override { return {}; } + ConstString DeclContextGetScopeQualifiedName(void *opaque_decl_ctx) override { + return {}; + } + bool + DeclContextIsClassMethod(void *opaque_decl_ctx, + lldb::LanguageType *language_ptr, + bool *is_instance_method_ptr, + ConstString *language_object_name_ptr) override { + return false; + } + bool IsRuntimeGeneratedType(void *type) override { return false; } + bool IsCharType(void *type) override { return false; } + bool IsCompleteType(void *type) override { return true; } + bool IsConst(void *type) override { return false; } + bool IsCStringType(void *type, uint32_t &length) override { return false; } + bool IsVectorType(void *type, CompilerType *element_type, + uint64_t *size) override { + return false; + } + uint32_t IsHomogeneousAggregate(void *type, + CompilerType *base_type_ptr) override { + return 0; + } + bool IsBlockPointerType(void *type, + CompilerType *function_pointer_type_ptr) override { + return false; + } + bool IsPolymorphicClass(void *type) override { return false; } + bool IsBeingDefined(void *type) override { return false; } + bool CanPassInRegisters(const CompilerType &type) override { + // FIXME: Implement this. There was an abort() here to figure out which + // tests where hitting this code. At least TestSwiftReturns and + // TestSwiftStepping were failing because of this Darwin. + return false; + } + unsigned GetTypeQualifiers(void *type) override { return 0; } + CompilerType GetTypeForDecl(void *opaque_decl) override { + llvm_unreachable("GetTypeForDecl not implemented"); + } + CompilerType GetBasicTypeFromAST(lldb::BasicType basic_type) override { + return {}; + } + const llvm::fltSemantics &GetFloatTypeSemantics(size_t byte_size) override { + // See: https://reviews.llvm.org/D67239. At this time of writing this API + // is only used by DumpDataExtractor for the C type system. + llvm_unreachable("GetFloatTypeSemantics not implemented."); + } + lldb::BasicType GetBasicTypeEnumeration(void *type) override { + return lldb::eBasicTypeInvalid; + } + uint32_t GetNumVirtualBaseClasses(void *opaque_type) override { return 0; } + CompilerType GetVirtualBaseClassAtIndex(void *opaque_type, size_t idx, + uint32_t *bit_offset_ptr) override { + return {}; + } + /// \} protected: /// Used in the logs. std::string m_description; @@ -150,6 +239,7 @@ class TypeSystemSwiftTypeRef : public TypeSystemSwift { swift::CanType GetCanonicalSwiftType(CompilerType compiler_type); swift::Type GetSwiftType(CompilerType compiler_type); CompilerType ReconstructType(CompilerType type); + CompilerType GetTypeFromMangledTypename(ConstString mangled_typename); // PluginInterface functions ConstString GetPluginName() override; @@ -172,12 +262,6 @@ class TypeSystemSwiftTypeRef : public TypeSystemSwift { return {}; } - ConstString DeclContextGetName(void *opaque_decl_ctx) override; - ConstString DeclContextGetScopeQualifiedName(void *opaque_decl_ctx) override; - bool DeclContextIsClassMethod(void *opaque_decl_ctx, - lldb::LanguageType *language_ptr, - bool *is_instance_method_ptr, - ConstString *language_object_name_ptr) override; bool DeclContextIsContainedInLookup(void *opaque_decl_ctx, void *other_opaque_decl_ctx) override { if (opaque_decl_ctx == other_opaque_decl_ctx) @@ -192,8 +276,6 @@ class TypeSystemSwiftTypeRef : public TypeSystemSwift { bool IsArrayType(void *type, CompilerType *element_type, uint64_t *size, bool *is_incomplete) override; bool IsAggregateType(void *type) override; - bool IsCharType(void *type) override; - bool IsCompleteType(void *type) override; bool IsDefined(void *type) override; bool IsFloatingPointType(void *type, uint32_t &count, bool &is_complex) override; @@ -202,8 +284,6 @@ class TypeSystemSwiftTypeRef : public TypeSystemSwift { CompilerType GetFunctionArgumentAtIndex(void *type, const size_t index) override; bool IsFunctionPointerType(void *type) override; - bool IsBlockPointerType(void *type, - CompilerType *function_pointer_type_ptr) override; bool IsIntegerType(void *type, bool &is_signed) override; bool IsPossibleDynamicType(void *type, CompilerType *target_type, // Can pass NULL @@ -211,7 +291,6 @@ class TypeSystemSwiftTypeRef : public TypeSystemSwift { bool IsPointerType(void *type, CompilerType *pointee_type) override; bool IsScalarType(void *type) override; bool IsVoidType(void *type) override; - bool CanPassInRegisters(const CompilerType &type) override; // Type Completion bool GetCompleteType(void *type) override; // AST related queries @@ -238,7 +317,6 @@ class TypeSystemSwiftTypeRef : public TypeSystemSwift { CompilerType GetPointerType(void *type) override; // Exploring the type - const llvm::fltSemantics &GetFloatTypeSemantics(size_t byte_size) override; llvm::Optional GetBitSize(lldb::opaque_compiler_type_t type, ExecutionContextScope *exe_scope) override; @@ -249,7 +327,6 @@ class TypeSystemSwiftTypeRef : public TypeSystemSwift { lldb::Format GetFormat(void *type) override; uint32_t GetNumChildren(void *type, bool omit_empty_base_classes, const ExecutionContext *exe_ctx) override; - lldb::BasicType GetBasicTypeEnumeration(void *type) override; uint32_t GetNumFields(void *type) override; CompilerType GetFieldAtIndex(void *type, size_t idx, std::string &name, uint64_t *bit_offset_ptr, @@ -297,41 +374,26 @@ class TypeSystemSwiftTypeRef : public TypeSystemSwift { void DumpTypeDescription(void *type) override; void DumpTypeDescription(void *type, Stream *s) override; - bool IsRuntimeGeneratedType(void *type) override; void DumpSummary(void *type, ExecutionContext *exe_ctx, Stream *s, const DataExtractor &data, lldb::offset_t data_offset, size_t data_byte_size) override; bool IsPointerOrReferenceType(void *type, CompilerType *pointee_type) override; - unsigned GetTypeQualifiers(void *type) override; - bool IsCStringType(void *type, uint32_t &length) override; llvm::Optional GetTypeBitAlign(void *type, ExecutionContextScope *exe_scope) override; - CompilerType GetBasicTypeFromAST(lldb::BasicType basic_type) override; CompilerType GetBuiltinTypeForEncodingAndBitSize(lldb::Encoding encoding, size_t bit_size) override { return CompilerType(); } - bool IsBeingDefined(void *type) override; - bool IsConst(void *type) override; - uint32_t IsHomogeneousAggregate(void *type, - CompilerType *base_type_ptr) override; - bool IsPolymorphicClass(void *type) override; bool IsTypedefType(void *type) override; CompilerType GetTypedefedType(void *type) override; - CompilerType GetTypeForDecl(void *opaque_decl) override; - bool IsVectorType(void *type, CompilerType *element_type, - uint64_t *size) override; CompilerType GetFullyUnqualifiedType(void *type) override; CompilerType GetNonReferenceType(void *type) override; CompilerType GetLValueReferenceType(void *type) override; CompilerType GetRValueReferenceType(void *opaque_type) override; uint32_t GetNumDirectBaseClasses(void *opaque_type) override; - uint32_t GetNumVirtualBaseClasses(void *opaque_type) override; CompilerType GetDirectBaseClassAtIndex(void *opaque_type, size_t idx, uint32_t *bit_offset_ptr) override; - CompilerType GetVirtualBaseClassAtIndex(void *opaque_type, size_t idx, - uint32_t *bit_offset_ptr) override; bool IsReferenceType(void *type, CompilerType *pointee_type, bool *is_rvalue) override; bool @@ -354,8 +416,23 @@ class TypeSystemSwiftTypeRef : public TypeSystemSwift { bool print_extensions_if_available) override; private: + /// Helper that creates an AST type from \p type. void *ReconstructType(void *type); + /// Cast \p opaque_type as a mangled name. + const char *AsMangledName(void *opaque_type); + + /// Wrap \p node as \p Global(TypeMangling(node)), remangle the type + /// and create a CompilerType from it. + CompilerType RemangleAsType(swift::Demangle::Demangler &Dem, + swift::Demangle::NodePointer node); + /// Demangle the mangled name of the canonical type of \p type and + /// drill into the Global(TypeMangling(Type())). + /// + /// \return the child of Type or a nullptr. + swift::Demangle::NodePointer + DemangleCanonicalType(swift::Demangle::Demangler &Dem, void *opaque_type); + /// The sibling SwiftASTContext. SwiftASTContext *m_swift_ast_context = nullptr; }; @@ -583,6 +660,7 @@ class SwiftASTContext : public TypeSystemSwift { /// Reconstruct a Swift AST type from a mangled name by looking its /// components up in Swift modules. + swift::TypeBase *ReconstructType(ConstString mangled_typename); swift::TypeBase *ReconstructType(ConstString mangled_typename, Status &error); CompilerType GetTypeFromMangledTypename(ConstString mangled_typename); @@ -638,6 +716,7 @@ class SwiftASTContext : public TypeSystemSwift { void ClearDiagnostics(); bool SetColorizeDiagnostics(bool b); + void AddErrorStatusAsGenericDiagnostic(Status error); void PrintDiagnostics(DiagnosticManager &diagnostic_manager, uint32_t bufferID = UINT32_MAX, uint32_t first_line = 0, @@ -695,15 +774,6 @@ class SwiftASTContext : public TypeSystemSwift { return {}; } - ConstString DeclContextGetName(void *opaque_decl_ctx) override; - - ConstString DeclContextGetScopeQualifiedName(void *opaque_decl_ctx) override; - - bool DeclContextIsClassMethod(void *opaque_decl_ctx, - lldb::LanguageType *language_ptr, - bool *is_instance_method_ptr, - ConstString *language_object_name_ptr) override; - bool DeclContextIsContainedInLookup(void *opaque_decl_ctx, void *other_opaque_decl_ctx) override { if (opaque_decl_ctx == other_opaque_decl_ctx) @@ -722,10 +792,6 @@ class SwiftASTContext : public TypeSystemSwift { bool IsAggregateType(void *type) override; - bool IsCharType(void *type) override; - - bool IsCompleteType(void *type) override; - bool IsDefined(void *type) override; bool IsFloatingPointType(void *type, uint32_t &count, @@ -740,9 +806,6 @@ class SwiftASTContext : public TypeSystemSwift { bool IsFunctionPointerType(void *type) override; - bool IsBlockPointerType(void *type, - CompilerType *function_pointer_type_ptr) override; - bool IsIntegerType(void *type, bool &is_signed) override; bool IsPossibleDynamicType(void *type, @@ -755,8 +818,6 @@ class SwiftASTContext : public TypeSystemSwift { bool IsVoidType(void *type) override; - bool CanPassInRegisters(const CompilerType &type) override; - static bool IsGenericType(const CompilerType &compiler_type); bool IsErrorType(CompilerType compiler_type) override; @@ -849,8 +910,6 @@ class SwiftASTContext : public TypeSystemSwift { // Exploring the type - const llvm::fltSemantics &GetFloatTypeSemantics(size_t byte_size) override; - llvm::Optional GetBitSize(lldb::opaque_compiler_type_t type, ExecutionContextScope *exe_scope) override; @@ -866,8 +925,6 @@ class SwiftASTContext : public TypeSystemSwift { uint32_t GetNumChildren(void *type, bool omit_empty_base_classes, const ExecutionContext *exe_ctx) override; - lldb::BasicType GetBasicTypeEnumeration(void *type) override; - uint32_t GetNumFields(void *type) override; CompilerType GetFieldAtIndex(void *type, size_t idx, std::string &name, @@ -952,8 +1009,6 @@ class SwiftASTContext : public TypeSystemSwift { // TODO: These methods appear unused. Should they be removed? - bool IsRuntimeGeneratedType(void *type) override; - void DumpSummary(void *type, ExecutionContext *exe_ctx, Stream *s, const DataExtractor &data, lldb::offset_t data_offset, size_t data_byte_size) override; @@ -963,29 +1018,14 @@ class SwiftASTContext : public TypeSystemSwift { bool IsPointerOrReferenceType(void *type, CompilerType *pointee_type) override; - unsigned GetTypeQualifiers(void *type) override; - - bool IsCStringType(void *type, uint32_t &length) override; - llvm::Optional GetTypeBitAlign(void *type, ExecutionContextScope *exe_scope) override; - CompilerType GetBasicTypeFromAST(lldb::BasicType basic_type) override; - CompilerType GetBuiltinTypeForEncodingAndBitSize(lldb::Encoding encoding, size_t bit_size) override { return CompilerType(); } - bool IsBeingDefined(void *type) override; - - bool IsConst(void *type) override; - - uint32_t IsHomogeneousAggregate(void *type, - CompilerType *base_type_ptr) override; - - bool IsPolymorphicClass(void *type) override; - bool IsTypedefType(void *type) override; // If the current object represents a typedef type, get the underlying type @@ -995,11 +1035,6 @@ class SwiftASTContext : public TypeSystemSwift { std::string GetSuperclassName(const CompilerType &superclass_type); - CompilerType GetTypeForDecl(void *opaque_decl) override; - - bool IsVectorType(void *type, CompilerType *element_type, - uint64_t *size) override; - CompilerType GetFullyUnqualifiedType(void *type) override; CompilerType GetNonReferenceType(void *type) override; @@ -1010,14 +1045,9 @@ class SwiftASTContext : public TypeSystemSwift { uint32_t GetNumDirectBaseClasses(void *opaque_type) override; - uint32_t GetNumVirtualBaseClasses(void *opaque_type) override; - CompilerType GetDirectBaseClassAtIndex(void *opaque_type, size_t idx, uint32_t *bit_offset_ptr) override; - CompilerType GetVirtualBaseClassAtIndex(void *opaque_type, size_t idx, - uint32_t *bit_offset_ptr) override; - bool IsReferenceType(void *type, CompilerType *pointee_type, bool *is_rvalue) override; diff --git a/lldb/include/lldb/Symbol/Type.h b/lldb/include/lldb/Symbol/Type.h index 3c424f43f7e71..61adff96c9147 100644 --- a/lldb/include/lldb/Symbol/Type.h +++ b/lldb/include/lldb/Symbol/Type.h @@ -97,7 +97,7 @@ class Type : public std::enable_shared_from_this, public UserID { llvm::Optional byte_size, SymbolContextScope *context, lldb::user_id_t encoding_uid, EncodingDataType encoding_uid_type, const Declaration &decl, const CompilerType &compiler_qual_type, - ResolveState compiler_type_resolve_state); + ResolveState compiler_type_resolve_state, uint32_t opaque_payload = 0); // This makes an invalid type. Used for functions that return a Type when // they get an error. @@ -197,22 +197,11 @@ class Type : public std::enable_shared_from_this, public UserID { uint32_t GetEncodingMask(); - bool IsCompleteObjCClass() { return m_is_complete_objc_class; } - - void SetIsCompleteObjCClass(bool is_complete_objc_class) { - m_is_complete_objc_class = is_complete_objc_class; - } - - /// \return whether this is a Swift fixed-size buffer. Resilient variables in - /// fixed-size buffers may be indirect depending on the runtime size of the - /// type. This is more a property of the value than of its type. - bool IsSwiftFixedValueBuffer() const { - return m_is_swift_fixed_value_buffer; - } - - void SetSwiftFixedValueBuffer(bool is_swift_fixed_value_buffer) { - m_is_swift_fixed_value_buffer = is_swift_fixed_value_buffer; - } + typedef uint32_t Payload; + /// Return the language-specific payload. + Payload GetPayload() { return m_payload; } + /// Return the language-specific payload. + void SetPayload(Payload opaque_payload) { m_payload = opaque_payload; } protected: ConstString m_name; @@ -227,8 +216,8 @@ class Type : public std::enable_shared_from_this, public UserID { Declaration m_decl; CompilerType m_compiler_type; ResolveState m_compiler_type_resolve_state; - bool m_is_complete_objc_class; - bool m_is_swift_fixed_value_buffer = false; + /// Language-specific flags. + Payload m_payload; Type *GetEncodingType(); diff --git a/lldb/include/lldb/Symbol/TypeSystem.h b/lldb/include/lldb/Symbol/TypeSystem.h index 5ab0d09857cb9..53c618b5665c5 100644 --- a/lldb/include/lldb/Symbol/TypeSystem.h +++ b/lldb/include/lldb/Symbol/TypeSystem.h @@ -217,11 +217,8 @@ class TypeSystem : public PluginInterface { virtual ConstString GetTypeName(lldb::opaque_compiler_type_t type) = 0; - // Defaults to GetTypeName(type). Override if your language desires - // specialized behavior. - // \param sc An optional symbol context of the function the type appears in. virtual ConstString GetDisplayTypeName(lldb::opaque_compiler_type_t type, - const SymbolContext *sc = nullptr); + const SymbolContext *sc = nullptr) = 0; // Defaults to GetTypeName(type). Override if your language desires // specialized behavior. diff --git a/lldb/include/lldb/Target/Platform.h b/lldb/include/lldb/Target/Platform.h index 780b7156eb009..521f7c8f4afe1 100644 --- a/lldb/include/lldb/Target/Platform.h +++ b/lldb/include/lldb/Target/Platform.h @@ -26,6 +26,7 @@ #include "lldb/Utility/StructuredData.h" #include "lldb/Utility/Timeout.h" #include "lldb/Utility/UserIDResolver.h" +#include "lldb/Utility/XcodeSDK.h" #include "lldb/lldb-private-forward.h" #include "lldb/lldb-public.h" #include "llvm/Support/VersionTuple.h" @@ -33,8 +34,8 @@ namespace lldb_private { class ProcessInstanceInfo; -class ProcessInstanceInfoList; class ProcessInstanceInfoMatch; +typedef std::vector ProcessInstanceInfoList; class ModuleCache; enum MmapFlags { eMmapFlagsPrivate = 1, eMmapFlagsAnon = 2 }; @@ -431,6 +432,10 @@ class Platform : public PluginInterface { return lldb_private::ConstString(); } + virtual llvm::StringRef GetSDKPath(lldb_private::XcodeSDK sdk) { + return {}; + } + const std::string &GetRemoteURL() const { return m_remote_url; } bool IsHost() const { diff --git a/lldb/include/lldb/Target/Process.h b/lldb/include/lldb/Target/Process.h index bc1578be147e8..70c870db2ee2a 100644 --- a/lldb/include/lldb/Target/Process.h +++ b/lldb/include/lldb/Target/Process.h @@ -37,6 +37,7 @@ #include "lldb/Target/Memory.h" #include "lldb/Target/QueueList.h" #include "lldb/Target/ThreadList.h" +#include "lldb/Target/ThreadPlanStack.h" #include "lldb/Utility/ArchSpec.h" #include "lldb/Utility/Broadcaster.h" #include "lldb/Utility/Event.h" @@ -2214,6 +2215,75 @@ class Process : public std::enable_shared_from_this, void SetDynamicCheckers(DynamicCheckerFunctions *dynamic_checkers); +/// Prune ThreadPlanStacks for unreported threads. +/// +/// \param[in] tid +/// The tid whose Plan Stack we are seeking to prune. +/// +/// \return +/// \b true if the TID is found or \b false if not. +bool PruneThreadPlansForTID(lldb::tid_t tid); + +/// Prune ThreadPlanStacks for all unreported threads. +void PruneThreadPlans(); + + /// Find the thread plan stack associated with thread with \a tid. + /// + /// \param[in] tid + /// The tid whose Plan Stack we are seeking. + /// + /// \return + /// Returns a ThreadPlan if the TID is found or nullptr if not. + ThreadPlanStack *FindThreadPlans(lldb::tid_t tid); + + /// Dump the thread plans associated with thread with \a tid. + /// + /// \param[in/out] strm + /// The stream to which to dump the output + /// + /// \param[in] tid + /// The tid whose Plan Stack we are dumping + /// + /// \param[in] desc_level + /// How much detail to dump + /// + /// \param[in] internal + /// If \b true dump all plans, if false only user initiated plans + /// + /// \param[in] condense_trivial + /// If true, only dump a header if the plan stack is just the base plan. + /// + /// \param[in] skip_unreported_plans + /// If true, only dump a plan if it is currently backed by an + /// lldb_private::Thread *. + /// + /// \return + /// Returns \b true if TID was found, \b false otherwise + bool DumpThreadPlansForTID(Stream &strm, lldb::tid_t tid, + lldb::DescriptionLevel desc_level, bool internal, + bool condense_trivial, bool skip_unreported_plans); + + /// Dump all the thread plans for this process. + /// + /// \param[in/out] strm + /// The stream to which to dump the output + /// + /// \param[in] desc_level + /// How much detail to dump + /// + /// \param[in] internal + /// If \b true dump all plans, if false only user initiated plans + /// + /// \param[in] condense_trivial + /// If true, only dump a header if the plan stack is just the base plan. + /// + /// \param[in] skip_unreported_plans + /// If true, skip printing all thread plan stacks that don't currently + /// have a backing lldb_private::Thread *. + void DumpThreadPlans(Stream &strm, lldb::DescriptionLevel desc_level, + bool internal, bool condense_trivial, + bool skip_unreported_plans); + /// Call this to set the lldb in the mode where it breaks on new thread /// creations, and then auto-restarts. This is useful when you are trying /// to run only one thread, but either that thread or the kernel is creating @@ -2683,6 +2753,10 @@ class Process : public std::enable_shared_from_this, ///see them. This is usually the same as ///< m_thread_list_real, but might be different if there is an OS plug-in ///creating memory threads + ThreadPlanStackMap m_thread_plans; ///< This is the list of thread plans for + /// threads in m_thread_list, as well as + /// threads we knew existed, but haven't + /// determined that they have died yet. ThreadList m_extended_thread_list; ///< Owner for extended threads that may be ///generated, cleared on natural stops uint32_t m_extended_thread_stop_id; ///< The natural stop id when diff --git a/lldb/include/lldb/Target/StackFrameRecognizer.h b/lldb/include/lldb/Target/StackFrameRecognizer.h index 92cfca4227cf5..a21a631f0300b 100644 --- a/lldb/include/lldb/Target/StackFrameRecognizer.h +++ b/lldb/include/lldb/Target/StackFrameRecognizer.h @@ -101,8 +101,8 @@ class ScriptedStackFrameRecognizer : public StackFrameRecognizer { class StackFrameRecognizerManager { public: static void AddRecognizer(lldb::StackFrameRecognizerSP recognizer, - ConstString module, ConstString symbol, - ConstString alternate_symbol, + ConstString module, + llvm::ArrayRef symbols, bool first_instruction_only = true); static void AddRecognizer(lldb::StackFrameRecognizerSP recognizer, @@ -110,11 +110,11 @@ class StackFrameRecognizerManager { lldb::RegularExpressionSP symbol, bool first_instruction_only = true); - static void ForEach( - std::function const - &callback); + static void + ForEach(std::function symbols, + bool regexp)> const &callback); static bool RemoveRecognizerWithID(uint32_t recognizer_id); diff --git a/lldb/include/lldb/Target/SwiftLanguageRuntime.h b/lldb/include/lldb/Target/SwiftLanguageRuntime.h index 7124386fc3ace..f659b8586d7f1 100644 --- a/lldb/include/lldb/Target/SwiftLanguageRuntime.h +++ b/lldb/include/lldb/Target/SwiftLanguageRuntime.h @@ -23,6 +23,7 @@ #include "Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntimeV2.h" #include "lldb/Breakpoint/BreakpointPrecondition.h" #include "lldb/Core/PluginInterface.h" +#include "lldb/Symbol/SwiftASTContext.h" #include "lldb/Target/LanguageRuntime.h" #include "lldb/lldb-private.h" diff --git a/lldb/include/lldb/Target/Target.h b/lldb/include/lldb/Target/Target.h index 377baf9f4fbda..d83493f946e8d 100644 --- a/lldb/include/lldb/Target/Target.h +++ b/lldb/include/lldb/Target/Target.h @@ -16,8 +16,6 @@ #include #include -#include "Plugins/ExpressionParser/Clang/ClangModulesDeclVendor.h" -#include "Plugins/ExpressionParser/Clang/ClangPersistentVariables.h" #include "lldb/Breakpoint/BreakpointList.h" #include "lldb/Breakpoint/BreakpointName.h" #include "lldb/Breakpoint/WatchpointList.h" @@ -25,12 +23,12 @@ #include "lldb/Core/Disassembler.h" #include "lldb/Core/ModuleList.h" #include "lldb/Core/UserSettingsController.h" +#include "lldb/Core/SwiftASTContextReader.h" #include "lldb/Expression/Expression.h" #include "lldb/Host/ProcessLaunchInfo.h" #include "lldb/Interpreter/OptionValueBoolean.h" #include "lldb/Interpreter/OptionValueEnumeration.h" #include "lldb/Interpreter/OptionValueFileSpec.h" -#include "lldb/Symbol/SwiftASTContext.h" #include "lldb/Symbol/SymbolContext.h" #include "lldb/Symbol/TypeSystem.h" #include "lldb/Target/ABI.h" @@ -46,6 +44,11 @@ namespace lldb_private { +class ClangModulesDeclVendor; +class SwiftPersistentExpressionState; +class SharedMutex; +class SwiftASTContextForExpressions; + OptionEnumValues GetDynamicValueTypes(); enum InlineStrategy { @@ -224,11 +227,18 @@ class TargetProperties : public Properties { bool GetInjectLocalVariables(ExecutionContext *exe_ctx) const; void SetInjectLocalVariables(ExecutionContext *exe_ctx, bool b); + + bool GetOSPluginReportsAllThreads() const; + + void SetOSPluginReportsAllThreads(bool does_report); void SetRequireHardwareBreakpoints(bool b); bool GetRequireHardwareBreakpoints() const; + void UpdateLaunchInfoFromProperties(); + + private: // Callbacks for m_launch_info. static void Arg0ValueChangedCallback(void *target_property_ptr, @@ -252,9 +262,12 @@ class TargetProperties : public Properties { static void DisableSTDIOValueChangedCallback(void *target_property_ptr, OptionValue *); + Environment ComputeEnvironment() const; + // Member variables. ProcessLaunchInfo m_launch_info; std::unique_ptr m_experimental_properties_up; + Target *m_target; }; class EvaluateExpressionOptions { diff --git a/lldb/include/lldb/Target/Thread.h b/lldb/include/lldb/Target/Thread.h index 3ae023c461d3b..2e54a527e378b 100644 --- a/lldb/include/lldb/Target/Thread.h +++ b/lldb/include/lldb/Target/Thread.h @@ -28,6 +28,8 @@ namespace lldb_private { +class ThreadPlanStack; + class ThreadProperties : public Properties { public: ThreadProperties(bool is_global); @@ -119,7 +121,7 @@ class Thread : public std::enable_shared_from_this, // bit of data. lldb::StopInfoSP stop_info_sp; // You have to restore the stop info or you // might continue with the wrong signals. - std::vector m_completed_plan_stack; + size_t m_completed_plan_checkpoint; lldb::RegisterCheckpointSP register_backup_sp; // You need to restore the registers, of course... uint32_t current_inlined_depth; @@ -921,7 +923,7 @@ class Thread : public std::enable_shared_from_this, /// /// \return /// A pointer to the next executed plan. - ThreadPlan *GetCurrentPlan(); + ThreadPlan *GetCurrentPlan() const; /// Unwinds the thread stack for the innermost expression plan currently /// on the thread plan stack. @@ -936,7 +938,7 @@ class Thread : public std::enable_shared_from_this, /// /// \return /// A pointer to the last completed plan. - lldb::ThreadPlanSP GetCompletedPlan(); + lldb::ThreadPlanSP GetCompletedPlan() const; /// Gets the outer-most return value from the completed plans /// @@ -955,7 +957,7 @@ class Thread : public std::enable_shared_from_this, /// A ExpressionVariableSP, either empty if there is no /// plan completed an expression during the current stop /// or the expression variable that was made for the completed expression. - lldb::ExpressionVariableSP GetExpressionVariable(); + lldb::ExpressionVariableSP GetExpressionVariable() const; /// Checks whether the given plan is in the completed plans for this /// stop. @@ -966,7 +968,7 @@ class Thread : public std::enable_shared_from_this, /// \return /// Returns true if the input plan is in the completed plan stack, /// false otherwise. - bool IsThreadPlanDone(ThreadPlan *plan); + bool IsThreadPlanDone(ThreadPlan *plan) const; /// Checks whether the given plan is in the discarded plans for this /// stop. @@ -977,14 +979,14 @@ class Thread : public std::enable_shared_from_this, /// \return /// Returns true if the input plan is in the discarded plan stack, /// false otherwise. - bool WasThreadPlanDiscarded(ThreadPlan *plan); + bool WasThreadPlanDiscarded(ThreadPlan *plan) const; /// Check if we have completed plan to override breakpoint stop reason /// /// \return /// Returns true if completed plan stack is not empty /// false otherwise. - bool CompletedPlanOverridesBreakpoint(); + bool CompletedPlanOverridesBreakpoint() const; /// Queues a generic thread plan. /// @@ -1030,16 +1032,6 @@ class Thread : public std::enable_shared_from_this, /// otherwise. bool DiscardUserThreadPlansUpToIndex(uint32_t thread_index); - /// Prints the current plan stack. - /// - /// \param[in] s - /// The stream to which to dump the plan stack info. - /// - void DumpThreadPlans( - Stream *s, - lldb::DescriptionLevel desc_level = lldb::eDescriptionLevelVerbose, - bool include_internal = true, bool ignore_boring = false) const; - virtual bool CheckpointThreadState(ThreadStateCheckpoint &saved_state); virtual bool @@ -1198,15 +1190,15 @@ class Thread : public std::enable_shared_from_this, // be called by classes that derive from Thread in their destructor. virtual void DestroyThread(); - void PushPlan(lldb::ThreadPlanSP &plan_sp); + ThreadPlanStack &GetPlans() const; + + void PushPlan(lldb::ThreadPlanSP plan_sp); void PopPlan(); void DiscardPlan(); - ThreadPlan *GetPreviousPlan(ThreadPlan *plan); - - typedef std::vector plan_stack; + ThreadPlan *GetPreviousPlan(ThreadPlan *plan) const; virtual lldb_private::Unwind *GetUnwinder(); @@ -1251,13 +1243,6 @@ class Thread : public std::enable_shared_from_this, lldb::StateType m_state; ///< The state of our process. mutable std::recursive_mutex m_state_mutex; ///< Multithreaded protection for m_state. - plan_stack m_plan_stack; ///< The stack of plans this thread is executing. - plan_stack m_completed_plan_stack; ///< Plans that have been completed by this - ///stop. They get deleted when the thread - ///resumes. - plan_stack m_discarded_plan_stack; ///< Plans that have been discarded by this - ///stop. They get deleted when the thread - ///resumes. mutable std::recursive_mutex m_frame_mutex; ///< Multithreaded protection for m_state. lldb::StackFrameListSP m_curr_frames_sp; ///< The stack frames that get lazily @@ -1278,6 +1263,7 @@ class Thread : public std::enable_shared_from_this, bool m_destroy_called; // This is used internally to make sure derived Thread // classes call DestroyThread. LazyBool m_override_should_notify; + mutable std::unique_ptr m_null_plan_stack_up; private: bool m_extended_info_fetched; // Have we tried to retrieve the m_extended_info @@ -1285,8 +1271,6 @@ class Thread : public std::enable_shared_from_this, StructuredData::ObjectSP m_extended_info; // The extended info for this thread private: - bool PlanIsBasePlan(ThreadPlan *plan_ptr); - void BroadcastSelectedFrameChange(StackID &new_frame_id); DISALLOW_COPY_AND_ASSIGN(Thread); diff --git a/lldb/include/lldb/Target/ThreadPlan.h b/lldb/include/lldb/Target/ThreadPlan.h index 7889cdb01fea6..8ddb3891349cd 100644 --- a/lldb/include/lldb/Target/ThreadPlan.h +++ b/lldb/include/lldb/Target/ThreadPlan.h @@ -369,16 +369,16 @@ class ThreadPlan : public std::enable_shared_from_this, /// /// \return /// A pointer to the thread plan's owning thread. - Thread &GetThread() { return m_thread; } + Thread &GetThread(); - const Thread &GetThread() const { return m_thread; } + Target &GetTarget(); - Target &GetTarget() { return m_thread.GetProcess()->GetTarget(); } - - const Target &GetTarget() const { return m_thread.GetProcess()->GetTarget(); } + const Target &GetTarget() const; /// Print a description of this thread to the stream \a s. - /// \a thread. + /// \a thread. Don't expect that the result of GetThread is valid in + /// the description method. This might get called when the underlying + /// Thread has not been reported, so we only know the TID and not the thread. /// /// \param[in] s /// The stream to which to print the description. @@ -464,7 +464,7 @@ class ThreadPlan : public std::enable_shared_from_this, // Also sets the plans to private and not master plans. A plan pushed by // another thread plan is never either of the above. void PushPlan(lldb::ThreadPlanSP &thread_plan_sp) { - m_thread.PushPlan(thread_plan_sp); + GetThread().PushPlan(thread_plan_sp); thread_plan_sp->SetPrivate(false); thread_plan_sp->SetIsMasterPlan(false); } @@ -497,7 +497,9 @@ class ThreadPlan : public std::enable_shared_from_this, // original stop reason so that stopping and calling a few functions won't // lose the history of the run. This call can be implemented to get you back // to the real stop info. - virtual lldb::StopInfoSP GetRealStopInfo() { return m_thread.GetStopInfo(); } + virtual lldb::StopInfoSP GetRealStopInfo() { + return GetThread().GetStopInfo(); + } // If the completion of the thread plan stepped out of a function, the return // value of the function might have been captured by the thread plan @@ -562,17 +564,17 @@ class ThreadPlan : public std::enable_shared_from_this, // This is mostly a formal requirement, it allows us to make the Thread's // GetPreviousPlan protected, but only friend ThreadPlan to thread. - ThreadPlan *GetPreviousPlan() { return m_thread.GetPreviousPlan(this); } + ThreadPlan *GetPreviousPlan() { return GetThread().GetPreviousPlan(this); } // This forwards the private Thread::GetPrivateStopInfo which is generally // what ThreadPlan's need to know. lldb::StopInfoSP GetPrivateStopInfo() { - return m_thread.GetPrivateStopInfo(); + return GetThread().GetPrivateStopInfo(); } void SetStopInfo(lldb::StopInfoSP stop_reason_sp) { - m_thread.SetStopInfo(stop_reason_sp); + GetThread().SetStopInfo(stop_reason_sp); } void CachePlanExplainsStop(bool does_explain) { @@ -588,7 +590,8 @@ class ThreadPlan : public std::enable_shared_from_this, bool IsUsuallyUnexplainedStopReason(lldb::StopReason); Status m_status; - Thread &m_thread; + Process &m_process; + lldb::tid_t m_tid; Vote m_stop_vote; Vote m_run_vote; bool m_takes_iteration_count; @@ -599,6 +602,9 @@ class ThreadPlan : public std::enable_shared_from_this, // For ThreadPlan only static lldb::user_id_t GetNextID(); + Thread *m_thread; // Stores a cached value of the thread, which is set to + // nullptr when the thread resumes. Don't use this anywhere + // but ThreadPlan::GetThread(). ThreadPlanKind m_kind; std::string m_name; std::recursive_mutex m_plan_complete_mutex; diff --git a/lldb/include/lldb/Target/ThreadPlanPython.h b/lldb/include/lldb/Target/ThreadPlanPython.h index 0ee559b12960b..247a0e3c62187 100644 --- a/lldb/include/lldb/Target/ThreadPlanPython.h +++ b/lldb/include/lldb/Target/ThreadPlanPython.h @@ -55,6 +55,8 @@ class ThreadPlanPython : public ThreadPlan { bool DoPlanExplainsStop(Event *event_ptr) override; lldb::StateType GetPlanRunState() override; + + ScriptInterpreter *GetScriptInterpreter(); private: std::string m_class_name; diff --git a/lldb/include/lldb/Target/ThreadPlanStack.h b/lldb/include/lldb/Target/ThreadPlanStack.h new file mode 100644 index 0000000000000..342195346806b --- /dev/null +++ b/lldb/include/lldb/Target/ThreadPlanStack.h @@ -0,0 +1,173 @@ +//===-- ThreadPlanStack.h ---------------------------------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef LLDB_TARGET_THREADPLANSTACK_H +#define LLDB_TARGET_THREADPLANSTACK_H + +#include +#include +#include +#include + +#include "lldb/Target/Target.h" +#include "lldb/Target/Thread.h" +#include "lldb/lldb-private-forward.h" +#include "lldb/lldb-private.h" + +namespace lldb_private { + +// The ThreadPlans have a thread for use when they are asked all the ThreadPlan +// state machine questions, but they should never cache any pointers from their +// owning lldb_private::Thread. That's because we want to be able to detach +// them from an owning thread, then reattach them by TID. +// The ThreadPlanStack holds the ThreadPlans for a given TID. All its methods +// are private, and it should only be accessed through the owning thread. When +// it is detached from a thread, all you can do is reattach it or delete it. +class ThreadPlanStack { + friend class lldb_private::Thread; + +public: + ThreadPlanStack(const Thread &thread, bool make_empty = false); + ~ThreadPlanStack() {} + + enum StackKind { ePlans, eCompletedPlans, eDiscardedPlans }; + + using PlanStack = std::vector; + + void DumpThreadPlans(Stream &s, lldb::DescriptionLevel desc_level, + bool include_internal) const; + + size_t CheckpointCompletedPlans(); + + void RestoreCompletedPlanCheckpoint(size_t checkpoint); + + void DiscardCompletedPlanCheckpoint(size_t checkpoint); + + void ThreadDestroyed(Thread *thread); + + void EnableTracer(bool value, bool single_stepping); + + void SetTracer(lldb::ThreadPlanTracerSP &tracer_sp); + + void PushPlan(lldb::ThreadPlanSP new_plan_sp); + + lldb::ThreadPlanSP PopPlan(); + + lldb::ThreadPlanSP DiscardPlan(); + + // If the input plan is nullptr, discard all plans. Otherwise make sure this + // plan is in the stack, and if so discard up to and including it. + void DiscardPlansUpToPlan(ThreadPlan *up_to_plan_ptr); + + void DiscardAllPlans(); + + void DiscardConsultingMasterPlans(); + + lldb::ThreadPlanSP GetCurrentPlan() const; + + lldb::ThreadPlanSP GetCompletedPlan(bool skip_private = true) const; + + lldb::ThreadPlanSP GetPlanByIndex(uint32_t plan_idx, + bool skip_private = true) const; + + lldb::ValueObjectSP GetReturnValueObject(bool &is_error) const; + + lldb::ExpressionVariableSP GetExpressionVariable() const; + + bool AnyPlans() const; + + bool AnyCompletedPlans() const; + + bool AnyDiscardedPlans() const; + + bool IsPlanDone(ThreadPlan *plan) const; + + bool WasPlanDiscarded(ThreadPlan *plan) const; + + ThreadPlan *GetPreviousPlan(ThreadPlan *current_plan) const; + + ThreadPlan *GetInnermostExpression() const; + + void WillResume(); + +private: + const PlanStack &GetStackOfKind(ThreadPlanStack::StackKind kind) const; + + void PrintOneStack(Stream &s, llvm::StringRef stack_name, + const PlanStack &stack, lldb::DescriptionLevel desc_level, + bool include_internal) const; + + PlanStack m_plans; ///< The stack of plans this thread is executing. + PlanStack m_completed_plans; ///< Plans that have been completed by this + /// stop. They get deleted when the thread + /// resumes. + PlanStack m_discarded_plans; ///< Plans that have been discarded by this + /// stop. They get deleted when the thread + /// resumes. + size_t m_completed_plan_checkpoint = 0; // Monotonically increasing token for + // completed plan checkpoints. + std::unordered_map m_completed_plan_store; +}; + +class ThreadPlanStackMap { +public: + ThreadPlanStackMap(Process &process) : m_process(process) {} + ~ThreadPlanStackMap() {} + + // Prune the map using the current_threads list. + void Update(ThreadList ¤t_threads, bool delete_missing, + bool check_for_new = true); + + void AddThread(Thread &thread) { + lldb::tid_t tid = thread.GetID(); + m_plans_list.emplace(tid, thread); + } + + bool RemoveTID(lldb::tid_t tid) { + auto result = m_plans_list.find(tid); + if (result == m_plans_list.end()) + return false; + result->second.ThreadDestroyed(nullptr); + m_plans_list.erase(result); + return true; + } + + ThreadPlanStack *Find(lldb::tid_t tid) { + auto result = m_plans_list.find(tid); + if (result == m_plans_list.end()) + return nullptr; + else + return &result->second; + } + + void Clear() { + for (auto plan : m_plans_list) + plan.second.ThreadDestroyed(nullptr); + m_plans_list.clear(); + } + + // Implements Process::DumpThreadPlans + void DumpPlans(Stream &strm, lldb::DescriptionLevel desc_level, bool internal, + bool ignore_boring, bool skip_unreported); + + // Implements Process::DumpThreadPlansForTID + bool DumpPlansForTID(Stream &strm, lldb::tid_t tid, + lldb::DescriptionLevel desc_level, bool internal, + bool ignore_boring, bool skip_unreported); + + bool PrunePlansForTID(lldb::tid_t tid); + +private: + Process &m_process; + using PlansList = std::unordered_map; + PlansList m_plans_list; +}; + +} // namespace lldb_private + +#endif // LLDB_TARGET_THREADPLANSTACK_H diff --git a/lldb/include/lldb/Target/ThreadPlanTracer.h b/lldb/include/lldb/Target/ThreadPlanTracer.h index 80b08078e975e..a7db53debfe01 100644 --- a/lldb/include/lldb/Target/ThreadPlanTracer.h +++ b/lldb/include/lldb/Target/ThreadPlanTracer.h @@ -57,9 +57,12 @@ class ThreadPlanTracer { } bool SingleStepEnabled() { return m_single_step; } + + Thread &GetThread(); protected: - Thread &m_thread; + Process &m_process; + lldb::tid_t m_tid; Stream *GetLogStream(); @@ -71,6 +74,7 @@ class ThreadPlanTracer { bool m_single_step; bool m_enabled; lldb::StreamSP m_stream_sp; + Thread *m_thread; }; class ThreadPlanAssemblyTracer : public ThreadPlanTracer { diff --git a/lldb/include/lldb/Utility/ArchSpec.h b/lldb/include/lldb/Utility/ArchSpec.h index 15e2fdb10c324..cc8d6222e9239 100644 --- a/lldb/include/lldb/Utility/ArchSpec.h +++ b/lldb/include/lldb/Utility/ArchSpec.h @@ -16,6 +16,7 @@ #include "lldb/lldb-private-enumerations.h" #include "llvm/ADT/StringRef.h" #include "llvm/ADT/Triple.h" +#include "llvm/Support/YAMLTraits.h" #include #include #include @@ -537,4 +538,16 @@ bool ParseMachCPUDashSubtypeTriple(llvm::StringRef triple_str, ArchSpec &arch); } // namespace lldb_private -#endif // #ifndef LLDB_UTILITY_ARCHSPEC_H +namespace llvm { +namespace yaml { +template <> struct ScalarTraits { + static void output(const lldb_private::ArchSpec &, void *, raw_ostream &); + static StringRef input(StringRef, void *, lldb_private::ArchSpec &); + static QuotingType mustQuote(StringRef S) { return QuotingType::Double; } +}; +} // namespace yaml +} // namespace llvm + +LLVM_YAML_IS_SEQUENCE_VECTOR(lldb_private::ArchSpec) + +#endif // LLDB_UTILITY_ARCHSPEC_H diff --git a/lldb/include/lldb/Utility/ConstString.h b/lldb/include/lldb/Utility/ConstString.h index 74750459d16fb..cff191135934b 100644 --- a/lldb/include/lldb/Utility/ConstString.h +++ b/lldb/include/lldb/Utility/ConstString.h @@ -9,9 +9,10 @@ #ifndef liblldb_ConstString_h_ #define liblldb_ConstString_h_ -#include "llvm/ADT/StringRef.h" #include "llvm/ADT/DenseMapInfo.h" +#include "llvm/ADT/StringRef.h" #include "llvm/Support/FormatVariadic.h" +#include "llvm/Support/YAMLTraits.h" #include @@ -481,6 +482,16 @@ template <> struct DenseMapInfo { } }; /// \} -} + +namespace yaml { +template <> struct ScalarTraits { + static void output(const lldb_private::ConstString &, void *, raw_ostream &); + static StringRef input(StringRef, void *, lldb_private::ConstString &); + static QuotingType mustQuote(StringRef S) { return QuotingType::Double; } +}; +} // namespace yaml +} // namespace llvm + +LLVM_YAML_IS_SEQUENCE_VECTOR(lldb_private::ConstString) #endif // liblldb_ConstString_h_ diff --git a/lldb/include/lldb/Utility/FileSpec.h b/lldb/include/lldb/Utility/FileSpec.h index 533426671cc6a..5e2002e525219 100644 --- a/lldb/include/lldb/Utility/FileSpec.h +++ b/lldb/include/lldb/Utility/FileSpec.h @@ -18,6 +18,7 @@ #include "llvm/Support/FileSystem.h" #include "llvm/Support/FormatVariadic.h" #include "llvm/Support/Path.h" +#include "llvm/Support/YAMLTraits.h" #include #include @@ -397,6 +398,8 @@ class FileSpec { ConstString GetLastPathComponent() const; protected: + friend struct llvm::yaml::MappingTraits; + // Convenience method for setting the file without changing the style. void SetFile(llvm::StringRef path); @@ -410,6 +413,8 @@ class FileSpec { /// Dump a FileSpec object to a stream Stream &operator<<(Stream &s, const FileSpec &f); +/// Prevent ODR violations with traits for llvm::sys::path::Style. +LLVM_YAML_STRONG_TYPEDEF(FileSpec::Style, FileSpecStyle) } // namespace lldb_private namespace llvm { @@ -436,6 +441,16 @@ template <> struct format_provider { static void format(const lldb_private::FileSpec &F, llvm::raw_ostream &Stream, StringRef Style); }; + +namespace yaml { +template <> struct ScalarEnumerationTraits { + static void enumeration(IO &io, lldb_private::FileSpecStyle &style); +}; + +template <> struct MappingTraits { + static void mapping(IO &io, lldb_private::FileSpec &f); +}; +} // namespace yaml } // namespace llvm #endif // liblldb_FileSpec_h_ diff --git a/lldb/include/lldb/Utility/ProcessInfo.h b/lldb/include/lldb/Utility/ProcessInfo.h index 9188bf3b70900..ec91060cda54e 100644 --- a/lldb/include/lldb/Utility/ProcessInfo.h +++ b/lldb/include/lldb/Utility/ProcessInfo.h @@ -9,13 +9,13 @@ #ifndef LLDB_UTILITY_PROCESSINFO_H #define LLDB_UTILITY_PROCESSINFO_H -// LLDB headers #include "lldb/Utility/ArchSpec.h" #include "lldb/Utility/Args.h" #include "lldb/Utility/Environment.h" #include "lldb/Utility/FileSpec.h" #include "lldb/Utility/NameMatches.h" - +#include "lldb/Utility/Reproducer.h" +#include "llvm/Support/YAMLTraits.h" #include namespace lldb_private { @@ -89,6 +89,7 @@ class ProcessInfo { const Environment &GetEnvironment() const { return m_environment; } protected: + template friend struct llvm::yaml::MappingTraits; FileSpec m_executable; std::string m_arg0; // argv[0] if supported. If empty, then use m_executable. // Not all process plug-ins support specifying an argv[0] that differs from @@ -150,46 +151,13 @@ class ProcessInstanceInfo : public ProcessInfo { bool verbose) const; protected: + friend struct llvm::yaml::MappingTraits; uint32_t m_euid; uint32_t m_egid; lldb::pid_t m_parent_pid; }; -class ProcessInstanceInfoList { -public: - ProcessInstanceInfoList() = default; - - void Clear() { m_infos.clear(); } - - size_t GetSize() { return m_infos.size(); } - - void Append(const ProcessInstanceInfo &info) { m_infos.push_back(info); } - - llvm::StringRef GetProcessNameAtIndex(size_t idx) { - return ((idx < m_infos.size()) ? m_infos[idx].GetNameAsStringRef() : ""); - } - - lldb::pid_t GetProcessIDAtIndex(size_t idx) { - return ((idx < m_infos.size()) ? m_infos[idx].GetProcessID() : 0); - } - - bool GetInfoAtIndex(size_t idx, ProcessInstanceInfo &info) { - if (idx < m_infos.size()) { - info = m_infos[idx]; - return true; - } - return false; - } - - // You must ensure "idx" is valid before calling this function - const ProcessInstanceInfo &GetProcessInfoAtIndex(size_t idx) const { - assert(idx < m_infos.size()); - return m_infos[idx]; - } - -protected: - std::vector m_infos; -}; +typedef std::vector ProcessInstanceInfoList; // ProcessInstanceInfoMatch // @@ -248,6 +216,52 @@ class ProcessInstanceInfoMatch { bool m_match_all_users; }; +namespace repro { +class ProcessInfoRecorder : public AbstractRecorder { +public: + ProcessInfoRecorder(const FileSpec &filename, std::error_code &ec) + : AbstractRecorder(filename, ec) {} + + static llvm::Expected> + Create(const FileSpec &filename); + + void Record(const ProcessInstanceInfoList &process_infos); +}; + +class ProcessInfoProvider : public repro::Provider { +public: + struct Info { + static const char *name; + static const char *file; + }; + + ProcessInfoProvider(const FileSpec &directory) : Provider(directory) {} + + ProcessInfoRecorder *GetNewProcessInfoRecorder(); + + void Keep() override; + void Discard() override; + + static char ID; + +private: + std::unique_ptr m_stream_up; + std::vector> m_process_info_recorders; +}; + +llvm::Optional GetReplayProcessInstanceInfoList(); + +} // namespace repro } // namespace lldb_private -#endif // #ifndef LLDB_UTILITY_PROCESSINFO_H +LLVM_YAML_IS_SEQUENCE_VECTOR(lldb_private::ProcessInstanceInfo) + +namespace llvm { +namespace yaml { +template <> struct MappingTraits { + static void mapping(IO &io, lldb_private::ProcessInstanceInfo &PII); +}; +} // namespace yaml +} // namespace llvm + +#endif // LLDB_UTILITY_PROCESSINFO_H diff --git a/lldb/include/lldb/Utility/XcodeSDK.h b/lldb/include/lldb/Utility/XcodeSDK.h new file mode 100644 index 0000000000000..9b9f1d226bf09 --- /dev/null +++ b/lldb/include/lldb/Utility/XcodeSDK.h @@ -0,0 +1,63 @@ +//===-- XcodeSDK.h ----------------------------------------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef LLDB_UTILITY_SDK_H +#define LLDB_UTILITY_SDK_H + +#include "llvm/ADT/StringRef.h" +#include "llvm/Support/VersionTuple.h" +#include + +namespace lldb_private { + +/// An abstraction for Xcode-style SDKs that works like \ref ArchSpec. +class XcodeSDK { + std::string m_name; + +public: + XcodeSDK() = default; + XcodeSDK(std::string &&name) : m_name(std::move(name)) {} + static XcodeSDK GetAnyMacOS() { return XcodeSDK("MacOSX.sdk"); } + + enum Type : int { + MacOSX = 0, + iPhoneSimulator, + iPhoneOS, + AppleTVSimulator, + AppleTVOS, + WatchSimulator, + watchOS, + bridgeOS, + Linux, + numSDKTypes, + unknown = -1 + }; + static llvm::StringRef GetNameForType(Type type); + + /// The merge function follows a strict order to maintain monotonicity: + /// 1. SDK with the higher SDKType wins. + /// 2. The newer SDK wins. + void Merge(XcodeSDK other); + + XcodeSDK &operator=(XcodeSDK other); + bool operator==(XcodeSDK other); + + /// Return parsed SDK number, and SDK version number. + std::tuple Parse() const; + llvm::VersionTuple GetVersion() const; + Type GetType() const; + llvm::StringRef GetString() const; + + static bool SDKSupportsModules(Type type, llvm::VersionTuple version); + static bool SDKSupportsModules(Type desired_type, const FileSpec &sdk_path); + static llvm::StringRef GetSDKNameForType(Type type); +}; + +} // namespace lldb_private + +#endif diff --git a/lldb/include/lldb/lldb-forward.h b/lldb/include/lldb/lldb-forward.h index f5e345d22419b..be8b03ea85285 100644 --- a/lldb/include/lldb/lldb-forward.h +++ b/lldb/include/lldb/lldb-forward.h @@ -169,7 +169,6 @@ class ProcessAttachInfo; class ProcessModID; class ProcessInfo; class ProcessInstanceInfo; -class ProcessInstanceInfoList; class ProcessInstanceInfoMatch; class ProcessLaunchInfo; class Property; diff --git a/lldb/packages/Python/lldbsuite/test/decorators.py b/lldb/packages/Python/lldbsuite/test/decorators.py index 0fc866a3df4b7..ba85383125da6 100644 --- a/lldb/packages/Python/lldbsuite/test/decorators.py +++ b/lldb/packages/Python/lldbsuite/test/decorators.py @@ -159,7 +159,8 @@ def _decorateTest(mode, debug_info=None, swig_version=None, py_version=None, macos_version=None, - remote=None, dwarf_version=None): + remote=None, dwarf_version=None, + setting=None): def fn(self): skip_for_os = _match_decorator_property( lldbplatform.translate(oslist), self.getPlatform()) @@ -197,6 +198,8 @@ def fn(self): skip_for_dwarf_version = (dwarf_version is None) or ( _check_expected_version(dwarf_version[0], dwarf_version[1], self.getDwarfVersion())) + skip_for_setting = (setting is None) or ( + setting in configuration.settings) # For the test to be skipped, all specified (e.g. not None) parameters must be True. # An unspecified parameter means "any", so those are marked skip by default. And we skip @@ -211,7 +214,8 @@ def fn(self): (py_version, skip_for_py_version, "python version"), (macos_version, skip_for_macos_version, "macOS version"), (remote, skip_for_remote, "platform locality (remote/local)"), - (dwarf_version, skip_for_dwarf_version, "dwarf version")] + (dwarf_version, skip_for_dwarf_version, "dwarf version"), + (setting, skip_for_setting, "setting")] reasons = [] final_skip_result = True for this_condition in conditions: @@ -255,7 +259,8 @@ def expectedFailureAll(bugnumber=None, debug_info=None, swig_version=None, py_version=None, macos_version=None, - remote=None, dwarf_version=None): + remote=None, dwarf_version=None, + setting=None): return _decorateTest(DecorateMode.Xfail, bugnumber=bugnumber, oslist=oslist, hostoslist=hostoslist, @@ -264,7 +269,8 @@ def expectedFailureAll(bugnumber=None, debug_info=debug_info, swig_version=swig_version, py_version=py_version, macos_version=None, - remote=remote,dwarf_version=dwarf_version) + remote=remote,dwarf_version=dwarf_version, + setting=setting) # provide a function to skip on defined oslist, compiler version, and archs @@ -280,7 +286,8 @@ def skipIf(bugnumber=None, debug_info=None, swig_version=None, py_version=None, macos_version=None, - remote=None, dwarf_version=None): + remote=None, dwarf_version=None, + setting=None): return _decorateTest(DecorateMode.Skip, bugnumber=bugnumber, oslist=oslist, hostoslist=hostoslist, @@ -289,7 +296,8 @@ def skipIf(bugnumber=None, debug_info=debug_info, swig_version=swig_version, py_version=py_version, macos_version=macos_version, - remote=remote, dwarf_version=dwarf_version) + remote=remote, dwarf_version=dwarf_version, + setting=setting) def _skip_for_android(reason, api_levels, archs): diff --git a/lldb/packages/Python/lldbsuite/test/dotest.py b/lldb/packages/Python/lldbsuite/test/dotest.py index bdb20705fe66e..7315820561eda 100644 --- a/lldb/packages/Python/lldbsuite/test/dotest.py +++ b/lldb/packages/Python/lldbsuite/test/dotest.py @@ -333,9 +333,6 @@ def parseOptionsAndInitTestdirs(): if args.swiftcompiler: configuration.swiftCompiler = args.swiftcompiler - if args.swiftlibrary: - configuration.swiftLibrary = args.swiftlibrary - cflags_extras = "" if args.E: os.environ['CFLAGS_EXTRAS'] = args.E @@ -352,7 +349,8 @@ def parseOptionsAndInitTestdirs(): logging.error('"%s" is not a setting in the form "key=value"', setting[0]) sys.exit(-1) - configuration.settings.append(setting[0].split('=', 1)) + setting_list = setting[0].split('=', 1) + configuration.settings.append((setting_list[0], setting_list[1])) if args.d: sys.stdout.write( @@ -1099,8 +1097,6 @@ def run_suite(): os.environ["CC"] = configuration.compiler if configuration.swiftCompiler: os.environ["SWIFTC"] = configuration.swiftCompiler - if configuration.swiftLibrary: - os.environ["USERSWIFTLIBRARY"] = configuration.swiftLibrary configString = "arch=%s compiler=%s" % (configuration.arch, configuration.compiler) diff --git a/lldb/packages/Python/lldbsuite/test/dotest_args.py b/lldb/packages/Python/lldbsuite/test/dotest_args.py index 84885a6fafbde..30537befdcad9 100644 --- a/lldb/packages/Python/lldbsuite/test/dotest_args.py +++ b/lldb/packages/Python/lldbsuite/test/dotest_args.py @@ -44,10 +44,6 @@ def create_parser(): '--swift-compiler', dest='swiftcompiler', help='The path to a valid Swift compiler') - group.add_argument( - '--swift-library', - dest='swiftlibrary', - help='The path to a folder that contains valid Swift library files') if sys.platform == 'darwin': group.add_argument('--apple-sdk', metavar='apple_sdk', dest='apple_sdk', default="macosx", help=textwrap.dedent( '''Specify the name of the Apple SDK (macosx, macosx.internal, iphoneos, iphoneos.internal, or path to SDK) and use the appropriate tools from that SDK's toolchain.''')) diff --git a/lldb/packages/Python/lldbsuite/test/lang/cpp/covariant-return-types/Makefile b/lldb/packages/Python/lldbsuite/test/lang/cpp/covariant-return-types/Makefile new file mode 100644 index 0000000000000..99998b20bcb05 --- /dev/null +++ b/lldb/packages/Python/lldbsuite/test/lang/cpp/covariant-return-types/Makefile @@ -0,0 +1,3 @@ +CXX_SOURCES := main.cpp + +include Makefile.rules diff --git a/lldb/packages/Python/lldbsuite/test/lang/cpp/covariant-return-types/TestCovariantReturnTypes.py b/lldb/packages/Python/lldbsuite/test/lang/cpp/covariant-return-types/TestCovariantReturnTypes.py new file mode 100644 index 0000000000000..6f2b3eafd2e9c --- /dev/null +++ b/lldb/packages/Python/lldbsuite/test/lang/cpp/covariant-return-types/TestCovariantReturnTypes.py @@ -0,0 +1,42 @@ +import lldb +from lldbsuite.test.lldbtest import * +import lldbsuite.test.lldbutil as lldbutil + +class TestCase(TestBase): + + mydir = TestBase.compute_mydir(__file__) + NO_DEBUG_INFO_TESTCASE = True + + def test(self): + self.build() + lldbutil.run_to_source_breakpoint(self,"// break here", lldb.SBFileSpec("main.cpp")) + + # Test covariant return types for pointers to class that contains the called function. + self.expect_expr("derived.getPtr()", result_type="Derived *") + self.expect_expr("base_ptr_to_derived->getPtr()", result_type="Base *") + self.expect_expr("base.getPtr()", result_type="Base *") + # The same tests with reference types. LLDB drops the reference when it turns the + # result into a SBValue so check for the the underlying type of the result. + self.expect_expr("derived.getRef()", result_type="Derived") + self.expect_expr("base_ptr_to_derived->getRef()", result_type="Base") + self.expect_expr("base.getRef()", result_type="Base") + + # Test covariant return types for pointers to class that does *not* contain the called function. + self.expect_expr("derived.getOtherPtr()", result_type="OtherDerived *") + self.expect_expr("base_ptr_to_derived->getOtherPtr()", result_type="OtherBase *") + self.expect_expr("base.getOtherPtr()", result_type="OtherBase *") + # The same tests with reference types. LLDB drops the reference when it turns the + # result into a SBValue so check for the the underlying type of the result. + self.expect_expr("derived.getOtherRef()", result_type="OtherDerived") + self.expect_expr("base_ptr_to_derived->getOtherRef()", result_type="OtherBase") + self.expect_expr("base.getOtherRef()", result_type="OtherBase") + + # Test that we call the right function and get the right value back. + self.expect_expr("derived.getOtherPtr()->value()", result_summary='"derived"') + self.expect_expr("base_ptr_to_derived->getOtherPtr()->value()", result_summary='"derived"') + self.expect_expr("base.getOtherPtr()->value()", result_summary='"base"') + self.expect_expr("derived.getOtherRef().value()", result_summary='"derived"') + self.expect_expr("base_ptr_to_derived->getOtherRef().value()", result_summary='"derived"') + self.expect_expr("base.getOtherRef().value()", result_summary='"base"') + + self.expect_expr("referencing_derived.getOther()->get()->a", result_value='42') diff --git a/lldb/packages/Python/lldbsuite/test/lang/cpp/covariant-return-types/main.cpp b/lldb/packages/Python/lldbsuite/test/lang/cpp/covariant-return-types/main.cpp new file mode 100644 index 0000000000000..ea05043d6cf9e --- /dev/null +++ b/lldb/packages/Python/lldbsuite/test/lang/cpp/covariant-return-types/main.cpp @@ -0,0 +1,59 @@ +struct OtherBase { + // Allow checking actual type from the test by giving + // this class and the subclass unique values here. + virtual const char *value() { return "base"; } +}; +struct OtherDerived : public OtherBase { + const char *value() override { return "derived"; } +}; + +// Those have to be globals as they would be completed if they +// are members (which would make this test always pass). +OtherBase other_base; +OtherDerived other_derived; + +struct Base { + // Function with covariant return type that is same class. + virtual Base* getPtr() { return this; } + virtual Base& getRef() { return *this; } + // Function with covariant return type that is a different class. + virtual OtherBase* getOtherPtr() { return &other_base; } + virtual OtherBase& getOtherRef() { return other_base; } +}; + +struct Derived : public Base { + Derived* getPtr() override { return this; } + Derived& getRef() override { return *this; } + OtherDerived* getOtherPtr() override { return &other_derived; } + OtherDerived& getOtherRef() override { return other_derived; } +}; + +// A regression test for a class with at least two members containing a +// covariant function, which is referenced through another covariant function. +struct BaseWithMembers { + int a = 42; + int b = 47; + virtual BaseWithMembers *get() { return this; } +}; +struct DerivedWithMembers: BaseWithMembers { + DerivedWithMembers *get() override { return this; } +}; +struct ReferencingBase { + virtual BaseWithMembers *getOther() { return new BaseWithMembers(); } +}; +struct ReferencingDerived: ReferencingBase { + DerivedWithMembers *getOther() { return new DerivedWithMembers(); } +}; + +int main() { + Derived derived; + Base base; + Base *base_ptr_to_derived = &derived; + (void)base_ptr_to_derived->getPtr(); + (void)base_ptr_to_derived->getRef(); + (void)base_ptr_to_derived->getOtherPtr(); + (void)base_ptr_to_derived->getOtherRef(); + + ReferencingDerived referencing_derived; + return 0; // break here +} diff --git a/lldb/packages/Python/lldbsuite/test/lldbtest.py b/lldb/packages/Python/lldbsuite/test/lldbtest.py index be92ea4b5a62f..3776a1ad81c70 100644 --- a/lldb/packages/Python/lldbsuite/test/lldbtest.py +++ b/lldb/packages/Python/lldbsuite/test/lldbtest.py @@ -2402,7 +2402,7 @@ def expect_expr( "Unexpected failure with msg: " + eval_result.GetError().GetCString()) if result_type: - self.assertEqual(result_type, eval_result.GetTypeName()) + self.assertEqual(result_type, eval_result.GetDisplayTypeName()) if result_value: self.assertEqual(result_value, eval_result.GetValue()) diff --git a/lldb/packages/Python/lldbsuite/test/lldbutil.py b/lldb/packages/Python/lldbsuite/test/lldbutil.py index c65488416fdb8..42e603d72a9fb 100644 --- a/lldb/packages/Python/lldbsuite/test/lldbutil.py +++ b/lldb/packages/Python/lldbsuite/test/lldbutil.py @@ -798,7 +798,7 @@ def run_to_breakpoint_do_run(test, target, bkpt, launch_info = None, test.assertEqual(num_threads, 1, "Expected 1 thread to stop at breakpoint, %d did."%(num_threads)) else: test.assertGreater(num_threads, 0, "No threads stopped at breakpoint") - + thread = threads[0] return (target, process, thread, bkpt) diff --git a/lldb/source/API/SBTarget.cpp b/lldb/source/API/SBTarget.cpp index 8e19aeb16bc3e..d814aeb05e74b 100644 --- a/lldb/source/API/SBTarget.cpp +++ b/lldb/source/API/SBTarget.cpp @@ -11,6 +11,7 @@ #include "lldb/lldb-public.h" +#include "Plugins/TypeSystem/Clang/TypeSystemClang.h" #include "lldb/API/SBBreakpoint.h" #include "lldb/API/SBDebugger.h" #include "lldb/API/SBEvent.h" @@ -43,7 +44,6 @@ #include "lldb/Core/ValueObjectList.h" #include "lldb/Core/ValueObjectVariable.h" #include "lldb/Host/Host.h" -#include "lldb/Symbol/TypeSystemClang.h" #include "lldb/Symbol/DeclVendor.h" #include "lldb/Symbol/ObjectFile.h" #include "lldb/Symbol/SymbolFile.h" @@ -376,10 +376,19 @@ SBProcess SBTarget::Launch(SBListener &listener, char const **argv, Module *exe_module = target_sp->GetExecutableModulePointer(); if (exe_module) launch_info.SetExecutableFile(exe_module->GetPlatformFileSpec(), true); - if (argv) + if (argv) { launch_info.GetArguments().AppendArguments(argv); - if (envp) + } else { + auto default_launch_info = target_sp->GetProcessLaunchInfo(); + launch_info.GetArguments().AppendArguments( + default_launch_info.GetArguments()); + } + if (envp) { launch_info.GetEnvironment() = Environment(envp); + } else { + auto default_launch_info = target_sp->GetProcessLaunchInfo(); + launch_info.GetEnvironment() = default_launch_info.GetEnvironment(); + } if (listener.IsValid()) launch_info.SetListener(listener.GetSP()); diff --git a/lldb/source/API/SystemInitializerFull.cpp b/lldb/source/API/SystemInitializerFull.cpp index 7a203aa905750..abd443880bf2a 100644 --- a/lldb/source/API/SystemInitializerFull.cpp +++ b/lldb/source/API/SystemInitializerFull.cpp @@ -22,7 +22,6 @@ #include "lldb/Host/Host.h" #include "lldb/Initialization/SystemInitializerCommon.h" #include "lldb/Interpreter/CommandInterpreter.h" -#include "lldb/Symbol/TypeSystemClang.h" #include "lldb/Utility/Timer.h" #include "Plugins/ABI/MacOSX-arm/ABIMacOSX_arm.h" @@ -95,6 +94,7 @@ #include "Plugins/SymbolFile/Symtab/SymbolFileSymtab.h" #include "Plugins/SymbolVendor/ELF/SymbolVendorELF.h" #include "Plugins/SystemRuntime/MacOSX/SystemRuntimeMacOSX.h" +#include "Plugins/TypeSystem/Clang/TypeSystemClang.h" #include "Plugins/UnwindAssembly/InstEmulation/UnwindAssemblyInstEmulation.h" #include "Plugins/UnwindAssembly/x86/UnwindAssembly-x86.h" diff --git a/lldb/source/Commands/CommandObjectExpression.cpp b/lldb/source/Commands/CommandObjectExpression.cpp index 997b1a59d439a..1f90f7f2b3648 100644 --- a/lldb/source/Commands/CommandObjectExpression.cpp +++ b/lldb/source/Commands/CommandObjectExpression.cpp @@ -363,29 +363,13 @@ CanBeUsedForElementCountPrinting(ValueObject &valobj) { return Status(); } -bool CommandObjectExpression::EvaluateExpression(llvm::StringRef expr, - Stream *output_stream, - Stream *error_stream, - CommandReturnObject *result) { - // Don't use m_exe_ctx as this might be called asynchronously after the - // command object DoExecute has finished when doing multi-line expression - // that use an input reader... - ExecutionContext exe_ctx(m_interpreter.GetExecutionContext()); - - Target *target = exe_ctx.GetTargetPtr(); - - if (!target) - target = &GetDummyTarget(); - - lldb::ValueObjectSP result_valobj_sp; - bool keep_in_memory = true; - StackFrame *frame = exe_ctx.GetFramePtr(); - +EvaluateExpressionOptions +CommandObjectExpression::GetEvalOptions(const Target &target) { EvaluateExpressionOptions options; options.SetCoerceToId(m_varobj_options.use_objc); options.SetUnwindOnError(m_command_options.unwind_on_error); options.SetIgnoreBreakpoints(m_command_options.ignore_breakpoints); - options.SetKeepInMemory(keep_in_memory); + options.SetKeepInMemory(true); options.SetUseDynamic(m_varobj_options.use_dynamic); options.SetTryAllThreads(m_command_options.try_all_threads); options.SetDebug(m_command_options.debug); @@ -408,7 +392,7 @@ bool CommandObjectExpression::EvaluateExpression(llvm::StringRef expr, bool auto_apply_fixits; if (m_command_options.auto_apply_fixits == eLazyBoolCalculate) - auto_apply_fixits = target->GetEnableAutoApplyFixIts(); + auto_apply_fixits = target.GetEnableAutoApplyFixIts(); else auto_apply_fixits = m_command_options.auto_apply_fixits == eLazyBoolYes; @@ -427,17 +411,36 @@ bool CommandObjectExpression::EvaluateExpression(llvm::StringRef expr, options.SetTimeout(std::chrono::microseconds(m_command_options.timeout)); else options.SetTimeout(llvm::None); + return options; +} + +bool CommandObjectExpression::EvaluateExpression(llvm::StringRef expr, + Stream &output_stream, + Stream &error_stream, + CommandReturnObject &result) { + // Don't use m_exe_ctx as this might be called asynchronously after the + // command object DoExecute has finished when doing multi-line expression + // that use an input reader... + ExecutionContext exe_ctx(m_interpreter.GetExecutionContext()); + + Target *target = exe_ctx.GetTargetPtr(); + + if (!target) + target = &GetDummyTarget(); + + lldb::ValueObjectSP result_valobj_sp; + StackFrame *frame = exe_ctx.GetFramePtr(); + const EvaluateExpressionOptions options = GetEvalOptions(*target); ExpressionResults success = target->EvaluateExpression( expr, frame, result_valobj_sp, options, &m_fixed_expression); // We only tell you about the FixIt if we applied it. The compiler errors // will suggest the FixIt if it parsed. - if (error_stream && !m_fixed_expression.empty() && - target->GetEnableNotifyAboutFixIts()) { + if (!m_fixed_expression.empty() && target->GetEnableNotifyAboutFixIts()) { if (success == eExpressionCompleted) - error_stream->Printf(" Fix-it applied, fixed expression was: \n %s\n", - m_fixed_expression.c_str()); + error_stream.Printf(" Fix-it applied, fixed expression was: \n %s\n", + m_fixed_expression.c_str()); } if (result_valobj_sp) { @@ -451,10 +454,10 @@ bool CommandObjectExpression::EvaluateExpression(llvm::StringRef expr, if (m_varobj_options.elem_count > 0) { Status error(CanBeUsedForElementCountPrinting(*result_valobj_sp)); if (error.Fail()) { - result->AppendErrorWithFormat( + result.AppendErrorWithFormat( "expression cannot be used with --element-count %s\n", error.AsCString("")); - result->SetStatus(eReturnStatusFailed); + result.SetStatus(eReturnStatusFailed); return false; } } @@ -464,41 +467,39 @@ bool CommandObjectExpression::EvaluateExpression(llvm::StringRef expr, options.SetVariableFormatDisplayLanguage( result_valobj_sp->GetPreferredDisplayLanguage()); - result_valobj_sp->Dump(*output_stream, options); + result_valobj_sp->Dump(output_stream, options); - if (result) - result->SetStatus(eReturnStatusSuccessFinishResult); + result.SetStatus(eReturnStatusSuccessFinishResult); } } else { if (result_valobj_sp->GetError().GetError() == UserExpression::kNoResult) { if (format != eFormatVoid && GetDebugger().GetNotifyVoid()) { - error_stream->PutCString("(void)\n"); + error_stream.PutCString("(void)\n"); } - if (result) - result->SetStatus(eReturnStatusSuccessFinishResult); + result.SetStatus(eReturnStatusSuccessFinishResult); } else { const char *error_cstr = result_valobj_sp->GetError().AsCString(); if (error_cstr && error_cstr[0]) { const size_t error_cstr_len = strlen(error_cstr); const bool ends_with_newline = error_cstr[error_cstr_len - 1] == '\n'; if (strstr(error_cstr, "error:") != error_cstr) - error_stream->PutCString("error: "); - error_stream->Write(error_cstr, error_cstr_len); + error_stream.PutCString("error: "); + error_stream.Write(error_cstr, error_cstr_len); if (!ends_with_newline) - error_stream->EOL(); + error_stream.EOL(); } else { - error_stream->PutCString("error: unknown error\n"); + error_stream.PutCString("error: unknown error\n"); } - if (result) - result->SetStatus(eReturnStatusFailed); + result.SetStatus(eReturnStatusFailed); } } } - return true; + return (success != eExpressionSetupError && + success != eExpressionParseError); } void CommandObjectExpression::IOHandlerInputComplete(IOHandler &io_handler, @@ -510,7 +511,8 @@ void CommandObjectExpression::IOHandlerInputComplete(IOHandler &io_handler, StreamFileSP output_sp = io_handler.GetOutputStreamFileSP(); StreamFileSP error_sp = io_handler.GetErrorStreamFileSP(); - EvaluateExpression(line.c_str(), output_sp.get(), error_sp.get()); + CommandReturnObject return_obj; + EvaluateExpression(line.c_str(), *output_sp, *error_sp, return_obj); if (output_sp) output_sp->Flush(); if (error_sp) @@ -686,8 +688,8 @@ bool CommandObjectExpression::DoExecute(llvm::StringRef command, } Target &target = GetSelectedOrDummyTarget(); - if (EvaluateExpression(expr, &(result.GetOutputStream()), - &(result.GetErrorStream()), &result)) { + if (EvaluateExpression(expr, result.GetOutputStream(), + result.GetErrorStream(), result)) { if (!m_fixed_expression.empty() && target.GetEnableNotifyAboutFixIts()) { CommandHistory &history = m_interpreter.GetCommandHistory(); diff --git a/lldb/source/Commands/CommandObjectExpression.h b/lldb/source/Commands/CommandObjectExpression.h index de159863b43a2..96c6881a12ef7 100644 --- a/lldb/source/Commands/CommandObjectExpression.h +++ b/lldb/source/Commands/CommandObjectExpression.h @@ -14,7 +14,9 @@ #include "lldb/Interpreter/OptionGroupBoolean.h" #include "lldb/Interpreter/OptionGroupFormat.h" #include "lldb/Interpreter/OptionGroupValueObjectDisplay.h" +#include "lldb/Target/Target.h" #include "lldb/lldb-private-enumerations.h" + namespace lldb_private { class CommandObjectExpression : public CommandObjectRaw, @@ -65,9 +67,22 @@ class CommandObjectExpression : public CommandObjectRaw, bool DoExecute(llvm::StringRef command, CommandReturnObject &result) override; - bool EvaluateExpression(llvm::StringRef expr, Stream *output_stream, - Stream *error_stream, - CommandReturnObject *result = nullptr); + /// Return the appropriate expression options used for evaluating the + /// expression in the given target. + EvaluateExpressionOptions GetEvalOptions(const Target &target); + + /// Evaluates the given expression. + /// \param output_stream The stream to which the evaluation result will be + /// printed. + /// \param error_stream Contains error messages that should be displayed to + /// the user in case the evaluation fails. + /// \param result A CommandReturnObject which status will be set to the + /// appropriate value depending on evaluation success and + /// whether the expression produced any result. + /// \return Returns true iff the expression was successfully evaluated, + /// executed and the result could be printed to the output stream. + bool EvaluateExpression(llvm::StringRef expr, Stream &output_stream, + Stream &error_stream, CommandReturnObject &result); void GetMultilineExpression(); diff --git a/lldb/source/Commands/CommandObjectFrame.cpp b/lldb/source/Commands/CommandObjectFrame.cpp index c2bced631674f..3a96078277d4b 100644 --- a/lldb/source/Commands/CommandObjectFrame.cpp +++ b/lldb/source/Commands/CommandObjectFrame.cpp @@ -747,7 +747,7 @@ class CommandObjectFrameRecognizerAdd : public CommandObjectParsed { m_module = std::string(option_arg); break; case 'n': - m_function = std::string(option_arg); + m_symbols.push_back(std::string(option_arg)); break; case 'x': m_regex = true; @@ -761,7 +761,7 @@ class CommandObjectFrameRecognizerAdd : public CommandObjectParsed { void OptionParsingStarting(ExecutionContext *execution_context) override { m_module = ""; - m_function = ""; + m_symbols.clear(); m_class_name = ""; m_regex = false; } @@ -773,7 +773,7 @@ class CommandObjectFrameRecognizerAdd : public CommandObjectParsed { // Instance variables to hold the values for command options. std::string m_class_name; std::string m_module; - std::string m_function; + std::vector m_symbols; bool m_regex; }; @@ -855,9 +855,18 @@ bool CommandObjectFrameRecognizerAdd::DoExecute(Args &command, return false; } - if (m_options.m_function.empty()) { - result.AppendErrorWithFormat("%s needs a function name (-n argument).\n", - m_cmd_name.c_str()); + if (m_options.m_symbols.empty()) { + result.AppendErrorWithFormat( + "%s needs at least one symbol name (-n argument).\n", + m_cmd_name.c_str()); + result.SetStatus(eReturnStatusFailed); + return false; + } + + if (m_options.m_regex && m_options.m_symbols.size() > 1) { + result.AppendErrorWithFormat( + "%s needs only one symbol regular expression (-n argument).\n", + m_cmd_name.c_str()); result.SetStatus(eReturnStatusFailed); return false; } @@ -877,12 +886,13 @@ bool CommandObjectFrameRecognizerAdd::DoExecute(Args &command, auto module = RegularExpressionSP(new RegularExpression(m_options.m_module)); auto func = - RegularExpressionSP(new RegularExpression(m_options.m_function)); + RegularExpressionSP(new RegularExpression(m_options.m_symbols.front())); StackFrameRecognizerManager::AddRecognizer(recognizer_sp, module, func); } else { auto module = ConstString(m_options.m_module); - auto func = ConstString(m_options.m_function); - StackFrameRecognizerManager::AddRecognizer(recognizer_sp, module, func, {}); + std::vector symbols(m_options.m_symbols.begin(), + m_options.m_symbols.end()); + StackFrameRecognizerManager::AddRecognizer(recognizer_sp, module, symbols); } #endif @@ -959,9 +969,9 @@ class CommandObjectFrameRecognizerList : public CommandObjectParsed { bool DoExecute(Args &command, CommandReturnObject &result) override { bool any_printed = false; StackFrameRecognizerManager::ForEach( - [&result, &any_printed](uint32_t recognizer_id, std::string name, - std::string module, std::string symbol, - std::string alternate_symbol, bool regexp) { + [&result, &any_printed]( + uint32_t recognizer_id, std::string name, std::string module, + llvm::ArrayRef symbols, bool regexp) { Stream &stream = result.GetOutputStream(); if (name.empty()) @@ -970,10 +980,9 @@ class CommandObjectFrameRecognizerList : public CommandObjectParsed { stream << std::to_string(recognizer_id) << ": " << name; if (!module.empty()) stream << ", module " << module; - if (!symbol.empty()) - stream << ", function " << symbol; - if (!alternate_symbol.empty()) - stream << ", symbol " << alternate_symbol; + if (!symbols.empty()) + for (auto &symbol : symbols) + stream << ", symbol " << symbol; if (regexp) stream << " (regexp)"; diff --git a/lldb/source/Commands/CommandObjectPlatform.cpp b/lldb/source/Commands/CommandObjectPlatform.cpp index 10e6a4aa17930..4accf4a9aaa34 100644 --- a/lldb/source/Commands/CommandObjectPlatform.cpp +++ b/lldb/source/Commands/CommandObjectPlatform.cpp @@ -1128,7 +1128,7 @@ class CommandObjectPlatformProcessList : public CommandObjectParsed { ProcessInstanceInfo::DumpTableHeader(ostrm, m_options.show_args, m_options.verbose); for (uint32_t i = 0; i < matches; ++i) { - proc_infos.GetProcessInfoAtIndex(i).DumpAsTableRow( + proc_infos[i].DumpAsTableRow( ostrm, platform_sp->GetUserIDResolver(), m_options.show_args, m_options.verbose); } @@ -1462,12 +1462,12 @@ class CommandObjectPlatformProcessAttach : public CommandObjectParsed { match_info.SetNameMatchType(NameMatch::StartsWith); } platform_sp->FindProcesses(match_info, process_infos); - const uint32_t num_matches = process_infos.GetSize(); + const uint32_t num_matches = process_infos.size(); if (num_matches == 0) return; for (uint32_t i = 0; i < num_matches; ++i) { - request.AddCompletion(process_infos.GetProcessNameAtIndex(i)); + request.AddCompletion(process_infos[i].GetNameAsStringRef()); } return; } diff --git a/lldb/source/Commands/CommandObjectProcess.cpp b/lldb/source/Commands/CommandObjectProcess.cpp index fb7b061ce5599..4ec889833f980 100644 --- a/lldb/source/Commands/CommandObjectProcess.cpp +++ b/lldb/source/Commands/CommandObjectProcess.cpp @@ -348,11 +348,11 @@ class CommandObjectProcessAttach : public CommandObjectProcessLaunchOrAttach { match_info.SetNameMatchType(NameMatch::StartsWith); } platform_sp->FindProcesses(match_info, process_infos); - const size_t num_matches = process_infos.GetSize(); + const size_t num_matches = process_infos.size(); if (num_matches == 0) return; for (size_t i = 0; i < num_matches; ++i) { - request.AddCompletion(process_infos.GetProcessNameAtIndex(i)); + request.AddCompletion(process_infos[i].GetNameAsStringRef()); } } diff --git a/lldb/source/Commands/CommandObjectReproducer.cpp b/lldb/source/Commands/CommandObjectReproducer.cpp index 52c42a7336a48..3c410aec6635e 100644 --- a/lldb/source/Commands/CommandObjectReproducer.cpp +++ b/lldb/source/Commands/CommandObjectReproducer.cpp @@ -8,13 +8,14 @@ #include "CommandObjectReproducer.h" +#include "lldb/Host/HostInfo.h" #include "lldb/Host/OptionParser.h" -#include "lldb/Utility/GDBRemote.h" -#include "lldb/Utility/Reproducer.h" - #include "lldb/Interpreter/CommandInterpreter.h" #include "lldb/Interpreter/CommandReturnObject.h" #include "lldb/Interpreter/OptionArgParser.h" +#include "lldb/Utility/GDBRemote.h" +#include "lldb/Utility/ProcessInfo.h" +#include "lldb/Utility/Reproducer.h" #include @@ -27,6 +28,7 @@ enum ReproducerProvider { eReproducerProviderCommands, eReproducerProviderFiles, eReproducerProviderGDB, + eReproducerProviderProcessInfo, eReproducerProviderVersion, eReproducerProviderWorkingDirectory, eReproducerProviderNone @@ -48,6 +50,11 @@ static constexpr OptionEnumValueElement g_reproducer_provider_type[] = { "gdb", "GDB Remote Packets", }, + { + eReproducerProviderProcessInfo, + "processes", + "Process Info", + }, { eReproducerProviderVersion, "version", @@ -97,6 +104,24 @@ static constexpr OptionEnumValues ReproducerSignalType() { #define LLDB_OPTIONS_reproducer_xcrash #include "CommandOptions.inc" +template +llvm::Expected static ReadFromYAML(StringRef filename) { + auto error_or_file = MemoryBuffer::getFile(filename); + if (auto err = error_or_file.getError()) { + return errorCodeToError(err); + } + + T t; + yaml::Input yin((*error_or_file)->getBuffer()); + yin >> t; + + if (auto err = yin.error()) { + return errorCodeToError(err); + } + + return t; +} + class CommandObjectReproducerGenerate : public CommandObjectParsed { public: CommandObjectReproducerGenerate(CommandInterpreter &interpreter) @@ -450,23 +475,41 @@ class CommandObjectReproducerDump : public CommandObjectParsed { repro::MultiLoader::Create(loader); llvm::Optional gdb_file; while ((gdb_file = multi_loader->GetNextFile())) { - auto error_or_file = MemoryBuffer::getFile(*gdb_file); - if (auto err = error_or_file.getError()) { - SetError(result, errorCodeToError(err)); + if (llvm::Expected> packets = + ReadFromYAML>(*gdb_file)) { + for (GDBRemotePacket &packet : *packets) { + packet.Dump(result.GetOutputStream()); + } + } else { + SetError(result, packets.takeError()); return false; } + } - std::vector packets; - yaml::Input yin((*error_or_file)->getBuffer()); - yin >> packets; + result.SetStatus(eReturnStatusSuccessFinishResult); + return true; + } + case eReproducerProviderProcessInfo: { + std::unique_ptr> + multi_loader = + repro::MultiLoader::Create(loader); - if (auto err = yin.error()) { - SetError(result, errorCodeToError(err)); - return false; - } + if (!multi_loader) { + SetError(result, make_error( + llvm::inconvertibleErrorCode(), + "Unable to create process info loader.")); + return false; + } - for (GDBRemotePacket &packet : packets) { - packet.Dump(result.GetOutputStream()); + llvm::Optional process_file; + while ((process_file = multi_loader->GetNextFile())) { + if (llvm::Expected infos = + ReadFromYAML(*process_file)) { + for (ProcessInstanceInfo info : *infos) + info.Dump(result.GetOutputStream(), HostInfo::GetUserIDResolver()); + } else { + SetError(result, infos.takeError()); + return false; } } diff --git a/lldb/source/Commands/CommandObjectTarget.cpp b/lldb/source/Commands/CommandObjectTarget.cpp index 8a5f75ab4d4cc..957bc81037f5c 100644 --- a/lldb/source/Commands/CommandObjectTarget.cpp +++ b/lldb/source/Commands/CommandObjectTarget.cpp @@ -682,6 +682,41 @@ class CommandObjectTargetDelete : public CommandObjectParsed { OptionGroupBoolean m_cleanup_option; }; +class CommandObjectTargetShowLaunchEnvironment : public CommandObjectParsed { +public: + CommandObjectTargetShowLaunchEnvironment(CommandInterpreter &interpreter) + : CommandObjectParsed( + interpreter, "target show-launch-environment", + "Shows the environment being passed to the process when launched, " + "taking info account 3 settings: target.env-vars, " + "target.inherit-env and target.unset-env-vars.", + nullptr, eCommandRequiresTarget) {} + + ~CommandObjectTargetShowLaunchEnvironment() override = default; + +protected: + bool DoExecute(Args &args, CommandReturnObject &result) override { + Target *target = m_exe_ctx.GetTargetPtr(); + Environment env = target->GetEnvironment(); + + std::vector env_vector; + env_vector.reserve(env.size()); + for (auto &KV : env) + env_vector.push_back(&KV); + std::sort(env_vector.begin(), env_vector.end(), + [](Environment::value_type *a, Environment::value_type *b) { + return a->first() < b->first(); + }); + + auto &strm = result.GetOutputStream(); + for (auto &KV : env_vector) + strm.Format("{0}={1}\n", KV->first(), KV->second); + + result.SetStatus(eReturnStatusSuccessFinishResult); + return result.Succeeded(); + } +}; + #pragma mark CommandObjectTargetVariable // "target variable" @@ -4885,6 +4920,9 @@ CommandObjectMultiwordTarget::CommandObjectMultiwordTarget( CommandObjectSP(new CommandObjectTargetList(interpreter))); LoadSubCommand("select", CommandObjectSP(new CommandObjectTargetSelect(interpreter))); + LoadSubCommand("show-launch-environment", + CommandObjectSP(new CommandObjectTargetShowLaunchEnvironment( + interpreter))); LoadSubCommand( "stop-hook", CommandObjectSP(new CommandObjectMultiwordTargetStopHooks(interpreter))); diff --git a/lldb/source/Commands/CommandObjectThread.cpp b/lldb/source/Commands/CommandObjectThread.cpp index 83c7cb50d142f..a9c81176e1666 100644 --- a/lldb/source/Commands/CommandObjectThread.cpp +++ b/lldb/source/Commands/CommandObjectThread.cpp @@ -1833,25 +1833,36 @@ class CommandObjectThreadPlanList : public CommandObjectIterateOverThreads { Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg, ExecutionContext *execution_context) override { - Status error; const int short_option = m_getopt_table[option_idx].val; switch (short_option) { case 'i': m_internal = true; break; + case 't': + lldb::tid_t tid; + if (option_arg.getAsInteger(0, tid)) + return Status("invalid tid: '%s'.", option_arg.str().c_str()); + m_tids.push_back(tid); + break; + case 'u': + m_unreported = false; + break; case 'v': m_verbose = true; break; default: llvm_unreachable("Unimplemented option"); } - return error; + return {}; } void OptionParsingStarting(ExecutionContext *execution_context) override { m_verbose = false; m_internal = false; + m_unreported = true; // The variable is "skip unreported" and we want to + // skip unreported by default. + m_tids.clear(); } llvm::ArrayRef GetDefinitions() override { @@ -1861,6 +1872,8 @@ class CommandObjectThreadPlanList : public CommandObjectIterateOverThreads { // Instance variables to hold the values for command options. bool m_verbose; bool m_internal; + bool m_unreported; + std::vector m_tids; }; CommandObjectThreadPlanList(CommandInterpreter &interpreter) @@ -1879,25 +1892,59 @@ class CommandObjectThreadPlanList : public CommandObjectIterateOverThreads { Options *GetOptions() override { return &m_options; } + bool DoExecute(Args &command, CommandReturnObject &result) override { + // If we are reporting all threads, dispatch to the Process to do that: + if (command.GetArgumentCount() == 0 && m_options.m_tids.empty()) { + Stream &strm = result.GetOutputStream(); + DescriptionLevel desc_level = m_options.m_verbose + ? eDescriptionLevelVerbose + : eDescriptionLevelFull; + m_exe_ctx.GetProcessPtr()->DumpThreadPlans( + strm, desc_level, m_options.m_internal, true, m_options.m_unreported); + result.SetStatus(eReturnStatusSuccessFinishResult); + return true; + } else { + // Do any TID's that the user may have specified as TID, then do any + // Thread Indexes... + if (!m_options.m_tids.empty()) { + Process *process = m_exe_ctx.GetProcessPtr(); + StreamString tmp_strm; + for (lldb::tid_t tid : m_options.m_tids) { + bool success = process->DumpThreadPlansForTID( + tmp_strm, tid, eDescriptionLevelFull, m_options.m_internal, + true /* condense_trivial */, m_options.m_unreported); + // If we didn't find a TID, stop here and return an error. + if (!success) { + result.SetError("Error dumping plans:"); + result.AppendError(tmp_strm.GetString()); + result.SetStatus(eReturnStatusFailed); + return false; + } + // Otherwise, add our data to the output: + result.GetOutputStream() << tmp_strm.GetString(); + } + } + return CommandObjectIterateOverThreads::DoExecute(command, result); + } + } + protected: bool HandleOneThread(lldb::tid_t tid, CommandReturnObject &result) override { - ThreadSP thread_sp = - m_exe_ctx.GetProcessPtr()->GetThreadList().FindThreadByID(tid); - if (!thread_sp) { - result.AppendErrorWithFormat("thread no longer exists: 0x%" PRIx64 "\n", - tid); - result.SetStatus(eReturnStatusFailed); - return false; - } + // If we have already handled this from a -t option, skip it here. + if (std::find(m_options.m_tids.begin(), m_options.m_tids.end(), tid) != + m_options.m_tids.end()) + return true; - Thread *thread = thread_sp.get(); + Process *process = m_exe_ctx.GetProcessPtr(); Stream &strm = result.GetOutputStream(); DescriptionLevel desc_level = eDescriptionLevelFull; if (m_options.m_verbose) desc_level = eDescriptionLevelVerbose; - thread->DumpThreadPlans(&strm, desc_level, m_options.m_internal, true); + process->DumpThreadPlansForTID(strm, tid, desc_level, m_options.m_internal, + true /* condense_trivial */, + m_options.m_unreported); return true; } @@ -1974,6 +2021,74 @@ class CommandObjectThreadPlanDiscard : public CommandObjectParsed { } }; +class CommandObjectThreadPlanPrune : public CommandObjectParsed { +public: + CommandObjectThreadPlanPrune(CommandInterpreter &interpreter) + : CommandObjectParsed(interpreter, "thread plan prune", + "Removes any thread plans associated with " + "currently unreported threads. " + "Specify one or more TID's to remove, or if no " + "TID's are provides, remove threads for all " + "unreported threads", + nullptr, + eCommandRequiresProcess | + eCommandTryTargetAPILock | + eCommandProcessMustBeLaunched | + eCommandProcessMustBePaused) { + CommandArgumentEntry arg; + CommandArgumentData tid_arg; + + // Define the first (and only) variant of this arg. + tid_arg.arg_type = eArgTypeThreadID; + tid_arg.arg_repetition = eArgRepeatStar; + + // There is only one variant this argument could be; put it into the + // argument entry. + arg.push_back(tid_arg); + + // Push the data for the first argument into the m_arguments vector. + m_arguments.push_back(arg); + } + + ~CommandObjectThreadPlanPrune() override = default; + + bool DoExecute(Args &args, CommandReturnObject &result) override { + Process *process = m_exe_ctx.GetProcessPtr(); + + if (args.GetArgumentCount() == 0) { + process->PruneThreadPlans(); + result.SetStatus(eReturnStatusSuccessFinishNoResult); + return true; + } + + const size_t num_args = args.GetArgumentCount(); + + std::lock_guard guard( + process->GetThreadList().GetMutex()); + + for (size_t i = 0; i < num_args; i++) { + bool success; + + lldb::tid_t tid = StringConvert::ToUInt64( + args.GetArgumentAtIndex(i), 0, 0, &success); + if (!success) { + result.AppendErrorWithFormat("invalid thread specification: \"%s\"\n", + args.GetArgumentAtIndex(i)); + result.SetStatus(eReturnStatusFailed); + return false; + } + if (!process->PruneThreadPlansForTID(tid)) { + result.AppendErrorWithFormat("Could not find unreported tid: \"%s\"\n", + args.GetArgumentAtIndex(i)); + result.SetStatus(eReturnStatusFailed); + return false; + } + } + result.SetStatus(eReturnStatusSuccessFinishNoResult); + return true; + } +}; + // CommandObjectMultiwordThreadPlan class CommandObjectMultiwordThreadPlan : public CommandObjectMultiword { @@ -1988,6 +2103,9 @@ class CommandObjectMultiwordThreadPlan : public CommandObjectMultiword { LoadSubCommand( "discard", CommandObjectSP(new CommandObjectThreadPlanDiscard(interpreter))); + LoadSubCommand( + "prune", + CommandObjectSP(new CommandObjectThreadPlanPrune(interpreter))); } ~CommandObjectMultiwordThreadPlan() override = default; diff --git a/lldb/source/Commands/CommandObjectWatchpoint.cpp b/lldb/source/Commands/CommandObjectWatchpoint.cpp index c965d354f7346..78fee94621f2d 100644 --- a/lldb/source/Commands/CommandObjectWatchpoint.cpp +++ b/lldb/source/Commands/CommandObjectWatchpoint.cpp @@ -41,7 +41,7 @@ static bool CheckTargetForWatchpointOperations(Target *target, bool process_is_valid = target->GetProcessSP() && target->GetProcessSP()->IsAlive(); if (!process_is_valid) { - result.AppendError("Thre's no process or it is not alive."); + result.AppendError("There's no process or it is not alive."); result.SetStatus(eReturnStatusFailed); return false; } diff --git a/lldb/source/Commands/Options.td b/lldb/source/Commands/Options.td index b1465297e2938..b0929ebc9474e 100644 --- a/lldb/source/Commands/Options.td +++ b/lldb/source/Commands/Options.td @@ -396,7 +396,8 @@ let Command = "frame recognizer add" in { "to.">; def frame_recognizer_function : Option<"function", "n">, Arg<"Name">, Completion<"Symbol">, - Desc<"Name of the function that this recognizer applies to.">; + Desc<"Name of the function that this recognizer applies to. " + "Can be specified more than once except if -x|--regex is provided.">; def frame_recognizer_python_class : Option<"python-class", "l">, Group<2>, Arg<"PythonClass">, Desc<"Give the name of a Python class to use for this frame recognizer.">; @@ -975,6 +976,11 @@ let Command = "thread plan list" in { Desc<"Display more information about the thread plans">; def thread_plan_list_internal : Option<"internal", "i">, Group<1>, Desc<"Display internal as well as user thread plans">; + def thread_plan_list_thread_id : Option<"thread-id", "t">, Group<1>, + Arg<"ThreadID">, Desc<"List the thread plans for this TID, can be " + "specified more than once.">; + def thread_plan_list_unreported : Option<"unreported", "u">, Group<1>, + Desc<"Display thread plans for unreported threads">; } let Command = "type summary add" in { diff --git a/lldb/source/Core/CoreProperties.td b/lldb/source/Core/CoreProperties.td index 91da39bf47c05..c7543873cc597 100644 --- a/lldb/source/Core/CoreProperties.td +++ b/lldb/source/Core/CoreProperties.td @@ -10,7 +10,10 @@ let Definition = "modulelist" in { DefaultStringValue<"">, Desc<"The path to the clang modules cache directory (-fmodules-cache-path).">; // BEGIN SWIFT - def UseDWARFImporter: Property<"use-swift-dwarfimporter", "Boolean">, + def UseSwiftClangImporter: Property<"use-swift-clangimporter", "Boolean">, + DefaultTrue, + Desc<"Reconstruct Clang module dependencies from headers when debugging Swift code">; + def UseSwiftDWARFImporter: Property<"use-swift-dwarfimporter", "Boolean">, DefaultTrue, Desc<"Reconstruct Clang module dependencies from DWARF when debugging Swift code">; def SwiftModuleLoadingMode: Property<"swift-module-loading-mode", "Enum">, diff --git a/lldb/source/Core/Module.cpp b/lldb/source/Core/Module.cpp index 4dff53583eae3..4d18edd66f625 100644 --- a/lldb/source/Core/Module.cpp +++ b/lldb/source/Core/Module.cpp @@ -1631,6 +1631,24 @@ bool Module::RemapSourceFile(llvm::StringRef path, return m_source_mappings.RemapPath(path, new_path); } +void Module::RegisterXcodeSDK(llvm::StringRef sdk_name, llvm::StringRef sysroot) { + XcodeSDK sdk(sdk_name.str()); + if (m_xcode_sdk == sdk) + return; + m_xcode_sdk.Merge(sdk); + PlatformSP module_platform = + Platform::GetPlatformForArchitecture(GetArchitecture(), nullptr); + ConstString sdk_path(module_platform->GetSDKPath(sdk)); + if (!sdk_path) + return; + // If merged SDK changed for a previously registered source path, update it. + // This could happend with -fdebug-prefix-map, otherwise it's unlikely. + ConstString sysroot_cs(sysroot); + if (!m_source_mappings.Replace(sysroot_cs, sdk_path, true)) + // In the general case, however, append it to the list. + m_source_mappings.Append(sysroot_cs, sdk_path, false); +} + bool Module::MergeArchitecture(const ArchSpec &arch_spec) { if (!arch_spec.IsValid()) return false; diff --git a/lldb/source/Core/ModuleList.cpp b/lldb/source/Core/ModuleList.cpp index df8610c222523..1d986210df2fa 100644 --- a/lldb/source/Core/ModuleList.cpp +++ b/lldb/source/Core/ModuleList.cpp @@ -125,11 +125,22 @@ FileSpec ModuleListProperties::GetClangModulesCachePath() const { } // BEGIN SWIFT -bool ModuleListProperties::GetUseDWARFImporter() const { - const uint32_t idx = ePropertyUseDWARFImporter; +bool ModuleListProperties::GetUseSwiftClangImporter() const { + const uint32_t idx = ePropertyUseSwiftClangImporter; return m_collection_sp->GetPropertyAtIndexAsBoolean( NULL, idx, g_modulelist_properties[idx].default_uint_value != 0); } + +bool ModuleListProperties::GetUseSwiftDWARFImporter() const { + const uint32_t idx = ePropertyUseSwiftDWARFImporter; + return m_collection_sp->GetPropertyAtIndexAsBoolean( + NULL, idx, g_modulelist_properties[idx].default_uint_value != 0); +} + +bool ModuleListProperties::SetUseSwiftDWARFImporter(bool new_value) { + return m_collection_sp->SetPropertyAtIndexAsBoolean( + nullptr, ePropertyUseSwiftDWARFImporter, new_value); +} // END SWIFT bool ModuleListProperties::SetClangModulesCachePath(llvm::StringRef path) { diff --git a/lldb/source/Core/ValueObject.cpp b/lldb/source/Core/ValueObject.cpp index 37b8ce4704e3c..d3084de0be90d 100644 --- a/lldb/source/Core/ValueObject.cpp +++ b/lldb/source/Core/ValueObject.cpp @@ -26,7 +26,6 @@ #include "lldb/DataFormatters/ValueObjectPrinter.h" #include "lldb/Expression/ExpressionVariable.h" #include "lldb/Host/Config.h" -#include "lldb/Symbol/TypeSystemClang.h" #include "lldb/Symbol/CompileUnit.h" #include "lldb/Symbol/CompilerType.h" #include "lldb/Symbol/Declaration.h" @@ -51,6 +50,8 @@ #include "lldb/Utility/Stream.h" #include "lldb/Utility/StreamString.h" #include "lldb/lldb-private-types.h" +#include "Plugins/TypeSystem/Clang/TypeSystemClang.h" +#include "Plugins/ExpressionParser/Clang/ClangModulesDeclVendor.h" // BEGIN SWIFT #include "lldb/Symbol/SwiftASTContext.h" @@ -362,23 +363,24 @@ CompilerType ValueObject::MaybeCalculateCompleteType() { } // then try the runtime - std::vector compiler_decls; - auto *objc_language_runtime = ObjCLanguageRuntime::Get(*process_sp); - if (auto runtime_vendor = objc_language_runtime->GetDeclVendor()) { - if (runtime_vendor->FindDecls(class_name, false, UINT32_MAX, - compiler_decls) > 0 && - compiler_decls.size() > 0) { - auto *ctx = llvm::dyn_cast(compiler_decls[0].GetTypeSystem()); - if (ctx) { - CompilerType runtime_type = - ctx->GetTypeForDecl(compiler_decls[0].GetOpaqueDecl()); - m_override_type = - is_pointer_type ? runtime_type.GetPointerType() : runtime_type; + if (auto *objc_language_runtime = ObjCLanguageRuntime::Get(*process_sp)) { + if (auto *runtime_vendor = objc_language_runtime->GetDeclVendor()) { + std::vector compiler_decls; + runtime_vendor->FindDecls(class_name, false, UINT32_MAX, compiler_decls); + if (!compiler_decls.empty()) { + auto *ctx = + llvm::dyn_cast(compiler_decls[0].GetTypeSystem()); + if (ctx) { + CompilerType runtime_type = + ctx->GetTypeForDecl(compiler_decls[0].GetOpaqueDecl()); + m_override_type = + is_pointer_type ? runtime_type.GetPointerType() : runtime_type; + } } - } - if (m_override_type.IsValid()) - return m_override_type; + if (m_override_type.IsValid()) + return m_override_type; + } } return compiler_type; } @@ -2900,6 +2902,9 @@ ValueObjectSP ValueObject::Dereference(Status &error) { GetSyntheticValue() ->GetChildMemberWithName(ConstString("$$dereference$$"), true) .get(); + } else if (IsSynthetic()) { + m_deref_valobj = + GetChildMemberWithName(ConstString("$$dereference$$"), true).get(); } if (m_deref_valobj) { diff --git a/lldb/source/Core/ValueObjectDynamicValue.cpp b/lldb/source/Core/ValueObjectDynamicValue.cpp index a0abbf54e7c45..1b1d6163325e3 100644 --- a/lldb/source/Core/ValueObjectDynamicValue.cpp +++ b/lldb/source/Core/ValueObjectDynamicValue.cpp @@ -10,6 +10,7 @@ #include "lldb/Core/Value.h" #include "lldb/Core/ValueObject.h" #include "lldb/Symbol/CompilerType.h" +#include "lldb/Symbol/SwiftASTContext.h" #include "lldb/Symbol/Type.h" #include "lldb/Target/ExecutionContext.h" #include "lldb/Target/LanguageRuntime.h" diff --git a/lldb/source/Core/ValueObjectVariable.cpp b/lldb/source/Core/ValueObjectVariable.cpp index 027b891bd59c6..0dcbcd9cddfc6 100644 --- a/lldb/source/Core/ValueObjectVariable.cpp +++ b/lldb/source/Core/ValueObjectVariable.cpp @@ -16,6 +16,7 @@ #include "lldb/Symbol/Declaration.h" #include "lldb/Symbol/Function.h" #include "lldb/Symbol/ObjectFile.h" +#include "lldb/Symbol/SwiftASTContext.h" #include "lldb/Symbol/SymbolContext.h" #include "lldb/Symbol/SymbolContextScope.h" #include "lldb/Symbol/Type.h" @@ -258,22 +259,26 @@ bool ValueObjectVariable::UpdateValue() { } // BEGIN Swift - if (variable->GetType() && variable->GetType()->IsSwiftFixedValueBuffer()) - if (auto process_sp = GetProcessSP()) - if (auto runtime = process_sp->GetLanguageRuntime( - compiler_type.GetMinimumLanguage())) { - if (!runtime->IsStoredInlineInBuffer(compiler_type)) { - lldb::addr_t addr = - m_value.GetScalar().ULongLong(LLDB_INVALID_ADDRESS); - if (addr != LLDB_INVALID_ADDRESS) { - Target &target = process_sp->GetTarget(); - size_t ptr_size = process_sp->GetAddressByteSize(); - lldb::addr_t deref_addr; - target.ReadMemory(addr, false, &deref_addr, ptr_size, m_error); - m_value.GetScalar() = deref_addr; + if (auto type = variable->GetType()) + if (llvm::dyn_cast_or_null( + type->GetForwardCompilerType().GetTypeSystem()) && + TypePayloadSwift(type->GetPayload()).IsFixedValueBuffer()) + if (auto process_sp = GetProcessSP()) + if (auto runtime = process_sp->GetLanguageRuntime( + compiler_type.GetMinimumLanguage())) { + if (!runtime->IsStoredInlineInBuffer(compiler_type)) { + lldb::addr_t addr = + m_value.GetScalar().ULongLong(LLDB_INVALID_ADDRESS); + if (addr != LLDB_INVALID_ADDRESS) { + Target &target = process_sp->GetTarget(); + size_t ptr_size = process_sp->GetAddressByteSize(); + lldb::addr_t deref_addr; + target.ReadMemory(addr, false, &deref_addr, ptr_size, + m_error); + m_value.GetScalar() = deref_addr; + } } } - } // END Swift switch (value_type) { diff --git a/lldb/source/DataFormatters/FormatManager.cpp b/lldb/source/DataFormatters/FormatManager.cpp index 13d9950ede4b5..15a8ab2bd9ac4 100644 --- a/lldb/source/DataFormatters/FormatManager.cpp +++ b/lldb/source/DataFormatters/FormatManager.cpp @@ -18,6 +18,8 @@ #include "lldb/Target/Language.h" #include "lldb/Utility/Log.h" +#include "Plugins/TypeSystem/Clang/TypeSystemClang.h" + using namespace lldb; using namespace lldb_private; using namespace lldb_private::formatters; @@ -193,14 +195,17 @@ void FormatManager::GetPossibleMatches( entries.push_back( {type_name, reason, did_strip_ptr, did_strip_ref, did_strip_typedef}); - const SymbolContext *sc = nullptr; - if (valobj.GetFrameSP()) - sc = &valobj.GetFrameSP()->GetSymbolContext(eSymbolContextFunction); + TypeSystem *ts = compiler_type.GetTypeSystem(); + if (ts && !llvm::isa(ts)) { + const SymbolContext *sc = nullptr; + if (valobj.GetFrameSP()) + sc = &valobj.GetFrameSP()->GetSymbolContext(eSymbolContextFunction); - ConstString display_type_name(compiler_type.GetDisplayTypeName(sc)); - if (display_type_name != type_name) - entries.push_back({display_type_name, reason, did_strip_ptr, - did_strip_ref, did_strip_typedef}); + ConstString display_type_name(compiler_type.GetDisplayTypeName(sc)); + if (display_type_name != type_name) + entries.push_back({display_type_name, reason, did_strip_ptr, + did_strip_ref, did_strip_typedef}); + } } for (bool is_rvalue_ref = true, j = true; diff --git a/lldb/source/DataFormatters/FormattersHelpers.cpp b/lldb/source/DataFormatters/FormattersHelpers.cpp index b2a5a17595c8f..6fafcdabdd3dc 100644 --- a/lldb/source/DataFormatters/FormattersHelpers.cpp +++ b/lldb/source/DataFormatters/FormattersHelpers.cpp @@ -143,3 +143,14 @@ lldb_private::formatters::GetArrayAddressOrPointerValue(ValueObject &valobj) { return data_addr; } + +lldb::ValueObjectSP +lldb_private::formatters::GetValueOfLibCXXCompressedPair(ValueObject &pair) { + ValueObjectSP value = + pair.GetChildMemberWithName(ConstString("__value_"), true); + if (!value) { + // pre-r300140 member name + value = pair.GetChildMemberWithName(ConstString("__first_"), true); + } + return value; +} diff --git a/lldb/source/DataFormatters/StringPrinter.cpp b/lldb/source/DataFormatters/StringPrinter.cpp index f8ff23e1d039d..602710554efe4 100644 --- a/lldb/source/DataFormatters/StringPrinter.cpp +++ b/lldb/source/DataFormatters/StringPrinter.cpp @@ -526,27 +526,33 @@ static bool ReadUTFBufferAndDumpToStream( if (!options.GetStream()) return false; - uint32_t sourceSize = options.GetSourceSize(); + uint32_t sourceSize; bool needs_zero_terminator = options.GetNeedsZeroTermination(); bool is_truncated = false; const auto max_size = process_sp->GetTarget().GetMaximumSizeOfStringSummary(); - if (!sourceSize) { + if (options.HasSourceSize()) { + sourceSize = options.GetSourceSize(); + if (!options.GetIgnoreMaxLength()) { + if (sourceSize > max_size) { + sourceSize = max_size; + is_truncated = true; + } + } + } else { sourceSize = max_size; needs_zero_terminator = true; - } else if (!options.GetIgnoreMaxLength()) { - if (sourceSize > max_size) { - sourceSize = max_size; - is_truncated = true; - } } const int bufferSPSize = sourceSize * type_width; lldb::DataBufferSP buffer_sp(new DataBufferHeap(bufferSPSize, 0)); - if (!buffer_sp->GetBytes()) + // Check if we got bytes. We never get any bytes if we have an empty + // string, but we still continue so that we end up actually printing + // an empty string (""). + if (sourceSize != 0 && !buffer_sp->GetBytes()) return false; Status error; diff --git a/lldb/source/Expression/DWARFExpression.cpp b/lldb/source/Expression/DWARFExpression.cpp index c67e35b145189..3f2b3a87426d7 100644 --- a/lldb/source/Expression/DWARFExpression.cpp +++ b/lldb/source/Expression/DWARFExpression.cpp @@ -2332,6 +2332,12 @@ bool DWARFExpression::Evaluate( // rather is a constant value. The value from the top of the stack is the // value to be used. This is the actual object value and not the location. case DW_OP_stack_value: + if (stack.empty()) { + if (error_ptr) + error_ptr->SetErrorString( + "Expression stack needs at least 1 item for DW_OP_stack_value."); + return false; + } stack.back().SetValueType(Value::eValueTypeScalar); break; diff --git a/lldb/source/Expression/Materializer.cpp b/lldb/source/Expression/Materializer.cpp index 808d1b4ca723f..8780cd45ec80a 100644 --- a/lldb/source/Expression/Materializer.cpp +++ b/lldb/source/Expression/Materializer.cpp @@ -12,6 +12,7 @@ #include "lldb/Core/ValueObjectVariable.h" #include "lldb/Expression/ExpressionVariable.h" #include "lldb/Symbol/Symbol.h" +#include "lldb/Symbol/SwiftASTContext.h" #include "lldb/Symbol/Type.h" #include "lldb/Symbol/Variable.h" #include "lldb/Target/ExecutionContext.h" diff --git a/lldb/source/Expression/UserExpression.cpp b/lldb/source/Expression/UserExpression.cpp index 1a1c595a129da..2b327ee867aac 100644 --- a/lldb/source/Expression/UserExpression.cpp +++ b/lldb/source/Expression/UserExpression.cpp @@ -30,6 +30,7 @@ #include "lldb/Symbol/Block.h" #include "lldb/Symbol/Function.h" #include "lldb/Symbol/ObjectFile.h" +#include "lldb/Symbol/SwiftASTContext.h" #include "lldb/Symbol/SymbolVendor.h" #include "lldb/Symbol/Type.h" #include "lldb/Symbol/TypeSystem.h" diff --git a/lldb/source/Host/common/FileSystem.cpp b/lldb/source/Host/common/FileSystem.cpp index 2db5bff3207fd..debfba5efd32a 100644 --- a/lldb/source/Host/common/FileSystem.cpp +++ b/lldb/source/Host/common/FileSystem.cpp @@ -279,8 +279,7 @@ void FileSystem::Resolve(FileSpec &file_spec) { std::shared_ptr FileSystem::CreateDataBuffer(const llvm::Twine &path, uint64_t size, uint64_t offset) { - if (m_collector) - m_collector->addFile(path); + Collect(path); const bool is_volatile = !IsLocal(path); const ErrorOr external_path = GetExternalPath(path); @@ -418,8 +417,7 @@ static mode_t GetOpenMode(uint32_t permissions) { Expected FileSystem::Open(const FileSpec &file_spec, File::OpenOptions options, uint32_t permissions, bool should_close_fd) { - if (m_collector) - m_collector->addFile(file_spec.GetPath()); + Collect(file_spec.GetPath()); const int open_flags = GetOpenFlags(options); const mode_t open_mode = @@ -466,3 +464,13 @@ ErrorOr FileSystem::GetExternalPath(const llvm::Twine &path) { ErrorOr FileSystem::GetExternalPath(const FileSpec &file_spec) { return GetExternalPath(file_spec.GetPath()); } + +void FileSystem::Collect(const FileSpec &file_spec) { + Collect(file_spec.GetPath()); +} + +void FileSystem::Collect(const llvm::Twine &file) { + if (m_collector && !llvm::sys::fs::is_directory(file)) { + m_collector->addFile(file); + } +} diff --git a/lldb/source/Host/common/Host.cpp b/lldb/source/Host/common/Host.cpp index 5fbb655fc7937..aa7f87aab58e3 100644 --- a/lldb/source/Host/common/Host.cpp +++ b/lldb/source/Host/common/Host.cpp @@ -678,3 +678,23 @@ void llvm::format_provider::format(const WaitStatus &WS, } OS << desc << " " << int(WS.status); } + +uint32_t Host::FindProcesses(const ProcessInstanceInfoMatch &match_info, + ProcessInstanceInfoList &process_infos) { + + if (llvm::Optional infos = + repro::GetReplayProcessInstanceInfoList()) { + process_infos = *infos; + return process_infos.size(); + } + + uint32_t result = FindProcessesImpl(match_info, process_infos); + + if (repro::Generator *g = repro::Reproducer::Instance().GetGenerator()) { + g->GetOrCreate() + .GetNewProcessInfoRecorder() + ->Record(process_infos); + } + + return result; +} diff --git a/lldb/source/Host/freebsd/Host.cpp b/lldb/source/Host/freebsd/Host.cpp index 99d728d63bc04..7c4c42e75ba74 100644 --- a/lldb/source/Host/freebsd/Host.cpp +++ b/lldb/source/Host/freebsd/Host.cpp @@ -150,8 +150,8 @@ static bool GetFreeBSDProcessUserAndGroup(ProcessInstanceInfo &process_info) { return false; } -uint32_t Host::FindProcesses(const ProcessInstanceInfoMatch &match_info, - ProcessInstanceInfoList &process_infos) { +uint32_t Host::FindProcessesImpl(const ProcessInstanceInfoMatch &match_info, + ProcessInstanceInfoList &process_infos) { const ::pid_t our_pid = ::getpid(); const ::uid_t our_uid = ::getuid(); std::vector kinfos; @@ -196,10 +196,10 @@ uint32_t Host::FindProcesses(const ProcessInstanceInfoMatch &match_info, bool already_registered = false; for (uint32_t pi = 0; !already_registered && (const int)kinfo.ki_numthreads > 1 && - pi < (const uint32_t)process_infos.GetSize(); + pi < (const uint32_t)process_infos.size(); pi++) already_registered = - (process_infos.GetProcessIDAtIndex(pi) == (uint32_t)kinfo.ki_pid); + (process_infos[pi].GetProcessID() == (uint32_t)kinfo.ki_pid); if (already_registered) continue; @@ -217,11 +217,11 @@ uint32_t Host::FindProcesses(const ProcessInstanceInfoMatch &match_info, GetFreeBSDProcessArgs(&match_info, process_info)) { GetFreeBSDProcessCPUType(process_info); if (match_info.Matches(process_info)) - process_infos.Append(process_info); + process_infos.push_back(process_info); } } - return process_infos.GetSize(); + return process_infos.size(); } bool Host::GetProcessInfo(lldb::pid_t pid, ProcessInstanceInfo &process_info) { diff --git a/lldb/source/Host/linux/Host.cpp b/lldb/source/Host/linux/Host.cpp index fe60d1fd8a730..1589e21a3cc4c 100644 --- a/lldb/source/Host/linux/Host.cpp +++ b/lldb/source/Host/linux/Host.cpp @@ -221,8 +221,8 @@ static bool GetProcessAndStatInfo(::pid_t pid, return true; } -uint32_t Host::FindProcesses(const ProcessInstanceInfoMatch &match_info, - ProcessInstanceInfoList &process_infos) { +uint32_t Host::FindProcessesImpl(const ProcessInstanceInfoMatch &match_info, + ProcessInstanceInfoList &process_infos) { static const char procdir[] = "/proc/"; DIR *dirproc = opendir(procdir); @@ -262,14 +262,14 @@ uint32_t Host::FindProcesses(const ProcessInstanceInfoMatch &match_info, continue; if (match_info.Matches(process_info)) { - process_infos.Append(process_info); + process_infos.push_back(process_info); } } closedir(dirproc); } - return process_infos.GetSize(); + return process_infos.size(); } bool Host::FindProcessThreads(const lldb::pid_t pid, TidMap &tids_to_attach) { diff --git a/lldb/source/Host/macosx/objcxx/Host.mm b/lldb/source/Host/macosx/objcxx/Host.mm index 233734109c41c..f106bc1005b0e 100644 --- a/lldb/source/Host/macosx/objcxx/Host.mm +++ b/lldb/source/Host/macosx/objcxx/Host.mm @@ -9,13 +9,9 @@ #include "lldb/Host/Host.h" #include +#include -// On device doesn't have supporty for XPC. -#if defined(__APPLE__) && (defined(__arm64__) || defined(__aarch64__)) -#define NO_XPC_SERVICES 1 -#endif - -#if !defined(NO_XPC_SERVICES) +#if TARGET_OS_OSX #define __XPC_PRIVATE_H__ #include @@ -135,6 +131,8 @@ return false; } +#if TARGET_OS_OSX + static void *AcceptPIDFromInferior(void *arg) { const char *connect_url = (const char *)arg; ConnectionFileDescriptor file_conn; @@ -153,8 +151,6 @@ return NULL; } -#if !defined(__arm__) && !defined(__arm64__) && !defined(__aarch64__) - const char *applscript_in_new_tty = "tell application \"Terminal\"\n" " activate\n" " do script \"/bin/bash -c '%s';exit\"\n" @@ -307,13 +303,13 @@ repeat with the_window in (get windows)\n\ return error; } -#endif // #if !defined(__arm__) && !defined(__arm64__) && !defined(__aarch64__) +#endif // TARGET_OS_OSX bool Host::OpenFileInExternalEditor(const FileSpec &file_spec, uint32_t line_no) { -#if defined(__arm__) || defined(__arm64__) || defined(__aarch64__) +#if !TARGET_OS_OSX return false; -#else +#else // !TARGET_OS_OSX // We attach this to an 'odoc' event to specify a particular selection typedef struct { int16_t reserved0; // must be zero @@ -404,7 +400,7 @@ repeat with the_window in (get windows)\n\ } return true; -#endif // #if !defined(__arm__) && !defined(__arm64__) && !defined(__aarch64__) +#endif // TARGET_OS_OSX } Environment Host::GetEnvironment() { return Environment(*_NSGetEnviron()); } @@ -591,8 +587,8 @@ static bool GetMacOSXProcessUserAndGroup(ProcessInstanceInfo &process_info) { return false; } -uint32_t Host::FindProcesses(const ProcessInstanceInfoMatch &match_info, - ProcessInstanceInfoList &process_infos) { +uint32_t Host::FindProcessesImpl(const ProcessInstanceInfoMatch &match_info, + ProcessInstanceInfoList &process_infos) { std::vector kinfos; int mib[3] = {CTL_KERN, KERN_PROC, KERN_PROC_ALL}; @@ -660,11 +656,11 @@ static bool GetMacOSXProcessUserAndGroup(ProcessInstanceInfo &process_info) { if (GetMacOSXProcessCPUType(process_info)) { if (GetMacOSXProcessArgs(&match_info, process_info)) { if (match_info.Matches(process_info)) - process_infos.Append(process_info); + process_infos.push_back(process_info); } } } - return process_infos.GetSize(); + return process_infos.size(); } bool Host::GetProcessInfo(lldb::pid_t pid, ProcessInstanceInfo &process_info) { @@ -689,7 +685,7 @@ static bool GetMacOSXProcessUserAndGroup(ProcessInstanceInfo &process_info) { return false; } -#if !NO_XPC_SERVICES +#if TARGET_OS_OSX static void PackageXPCArguments(xpc_object_t message, const char *prefix, const Args &args) { size_t count = args.GetArgumentCount(); @@ -841,7 +837,7 @@ static short GetPosixspawnFlags(const ProcessLaunchInfo &launch_info) { static Status LaunchProcessXPC(const char *exe_path, ProcessLaunchInfo &launch_info, lldb::pid_t &pid) { -#if !NO_XPC_SERVICES +#if TARGET_OS_OSX Status error = getXPCAuthorization(launch_info); if (error.Fail()) return error; @@ -1231,7 +1227,7 @@ static Status LaunchProcessPosixSpawn(const char *exe_path, static bool ShouldLaunchUsingXPC(ProcessLaunchInfo &launch_info) { bool result = false; -#if !NO_XPC_SERVICES +#if TARGET_OS_OSX bool launchingAsRoot = launch_info.GetUserID() == 0; bool currentUserIsRoot = HostInfo::GetEffectiveUserID() == 0; @@ -1263,7 +1259,7 @@ static bool ShouldLaunchUsingXPC(ProcessLaunchInfo &launch_info) { } if (launch_info.GetFlags().Test(eLaunchFlagLaunchInTTY)) { -#if !defined(__arm__) && !defined(__arm64__) && !defined(__aarch64__) +#if TARGET_OS_OSX return LaunchInNewTerminalWithAppleScript(exe_spec.GetPath().c_str(), launch_info); #else diff --git a/lldb/source/Host/macosx/objcxx/HostInfoMacOSX.mm b/lldb/source/Host/macosx/objcxx/HostInfoMacOSX.mm index e73d2ffe9b9ab..c09339e8c6731 100644 --- a/lldb/source/Host/macosx/objcxx/HostInfoMacOSX.mm +++ b/lldb/source/Host/macosx/objcxx/HostInfoMacOSX.mm @@ -8,6 +8,7 @@ #include "lldb/Host/macosx/HostInfoMacOSX.h" #include "lldb/Host/FileSystem.h" +#include "lldb/Host/Host.h" #include "lldb/Host/HostInfo.h" #include "lldb/Utility/Args.h" #include "lldb/Utility/Log.h" @@ -295,3 +296,39 @@ static void ParseOSVersion(llvm::VersionTuple &version, NSString *Key) { } } } + +std::string HostInfoMacOSX::GetXcodeSDK(XcodeSDK sdk) { + std::string xcrun_cmd = "xcrun --show-sdk-path --sdk " + + XcodeSDK::GetSDKNameForType(sdk.GetType()).str(); + llvm::VersionTuple version = sdk.GetVersion(); + if (!version.empty()) + xcrun_cmd += version.getAsString(); + + int status = 0; + int signo = 0; + std::string output_str; + lldb_private::Status error = + Host::RunShellCommand(xcrun_cmd.c_str(), FileSpec(), &status, &signo, + &output_str, std::chrono::seconds(15)); + + // Check that xcrun return something useful. + if (status != 0 || output_str.empty()) + return {}; + + // Convert to a StringRef so we can manipulate the string without modifying + // the underlying data. + llvm::StringRef output(output_str); + + // Remove any trailing newline characters. + output = output.rtrim(); + + // Strip any leading newline characters and everything before them. + const size_t last_newline = output.rfind('\n'); + if (last_newline != llvm::StringRef::npos) + output = output.substr(last_newline + 1); + + // Whatever is left in output should be a valid path. + if (!FileSystem::Instance().Exists(output)) + return {}; + return output.str(); +} diff --git a/lldb/source/Host/netbsd/Host.cpp b/lldb/source/Host/netbsd/Host.cpp index 20f3db3c22c1d..83d8c49499658 100644 --- a/lldb/source/Host/netbsd/Host.cpp +++ b/lldb/source/Host/netbsd/Host.cpp @@ -154,8 +154,8 @@ static bool GetNetBSDProcessUserAndGroup(ProcessInstanceInfo &process_info) { return false; } -uint32_t Host::FindProcesses(const ProcessInstanceInfoMatch &match_info, - ProcessInstanceInfoList &process_infos) { +uint32_t Host::FindProcessesImpl(const ProcessInstanceInfoMatch &match_info, + ProcessInstanceInfoList &process_infos) { const ::pid_t our_pid = ::getpid(); const ::uid_t our_uid = ::getuid(); @@ -197,8 +197,8 @@ uint32_t Host::FindProcesses(const ProcessInstanceInfoMatch &match_info, // list if a process with given identifier is already registered there. if (proc_kinfo[i].p_nlwps > 1) { bool already_registered = false; - for (size_t pi = 0; pi < process_infos.GetSize(); pi++) { - if (process_infos.GetProcessIDAtIndex(pi) == proc_kinfo[i].p_pid) { + for (size_t pi = 0; pi < process_infos.size(); pi++) { + if (process_infos[pi].GetProcessID() == proc_kinfo[i].p_pid) { already_registered = true; break; } @@ -219,13 +219,13 @@ uint32_t Host::FindProcesses(const ProcessInstanceInfoMatch &match_info, GetNetBSDProcessArgs(&match_info, process_info)) { GetNetBSDProcessCPUType(process_info); if (match_info.Matches(process_info)) - process_infos.Append(process_info); + process_infos.push_back(process_info); } } kvm_close(kdp); /* XXX: we don't check for error here */ - return process_infos.GetSize(); + return process_infos.size(); } bool Host::GetProcessInfo(lldb::pid_t pid, ProcessInstanceInfo &process_info) { diff --git a/lldb/source/Host/openbsd/Host.cpp b/lldb/source/Host/openbsd/Host.cpp index ba6cf057ca171..2202bc809f711 100644 --- a/lldb/source/Host/openbsd/Host.cpp +++ b/lldb/source/Host/openbsd/Host.cpp @@ -140,8 +140,8 @@ static bool GetOpenBSDProcessUserAndGroup(ProcessInstanceInfo &process_info) { return false; } -uint32_t Host::FindProcesses(const ProcessInstanceInfoMatch &match_info, - ProcessInstanceInfoList &process_infos) { +uint32_t Host::FindProcessesImpl(const ProcessInstanceInfoMatch &match_info, + ProcessInstanceInfoList &process_infos) { std::vector kinfos; int mib[3] = {CTL_KERN, KERN_PROC, KERN_PROC_ALL}; @@ -193,11 +193,11 @@ uint32_t Host::FindProcesses(const ProcessInstanceInfoMatch &match_info, GetOpenBSDProcessArgs(&match_info, process_info)) { GetOpenBSDProcessCPUType(process_info); if (match_info.Matches(process_info)) - process_infos.Append(process_info); + process_infos.push_back(process_info); } } - return process_infos.GetSize(); + return process_infos.size(); } bool Host::GetProcessInfo(lldb::pid_t pid, ProcessInstanceInfo &process_info) { diff --git a/lldb/source/Host/windows/Host.cpp b/lldb/source/Host/windows/Host.cpp index 1282bbe8e5c55..9b625310f854c 100644 --- a/lldb/source/Host/windows/Host.cpp +++ b/lldb/source/Host/windows/Host.cpp @@ -131,9 +131,9 @@ FileSpec Host::GetModuleFileSpecForHostAddress(const void *host_addr) { return module_filespec; } -uint32_t Host::FindProcesses(const ProcessInstanceInfoMatch &match_info, - ProcessInstanceInfoList &process_infos) { - process_infos.Clear(); +uint32_t Host::FindProcessesImpl(const ProcessInstanceInfoMatch &match_info, + ProcessInstanceInfoList &process_infos) { + process_infos.clear(); AutoHandle snapshot(CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0)); if (!snapshot.IsValid()) @@ -156,10 +156,10 @@ uint32_t Host::FindProcesses(const ProcessInstanceInfoMatch &match_info, GetProcessExecutableAndTriple(handle, process); if (match_info.MatchAllProcesses() || match_info.Matches(process)) - process_infos.Append(process); + process_infos.push_back(process); } while (Process32NextW(snapshot.get(), &pe)); } - return process_infos.GetSize(); + return process_infos.size(); } bool Host::GetProcessInfo(lldb::pid_t pid, ProcessInstanceInfo &process_info) { diff --git a/lldb/source/Plugins/ABI/SysV-ppc64/ABISysV_ppc64.cpp b/lldb/source/Plugins/ABI/SysV-ppc64/ABISysV_ppc64.cpp index 91720a7094456..eb51cf26ced37 100644 --- a/lldb/source/Plugins/ABI/SysV-ppc64/ABISysV_ppc64.cpp +++ b/lldb/source/Plugins/ABI/SysV-ppc64/ABISysV_ppc64.cpp @@ -11,6 +11,7 @@ #include "llvm/ADT/STLExtras.h" #include "llvm/ADT/Triple.h" +#include "Plugins/TypeSystem/Clang/TypeSystemClang.h" #include "Utility/PPC64LE_DWARF_Registers.h" #include "Utility/PPC64_DWARF_Registers.h" #include "lldb/Core/Module.h" @@ -19,7 +20,6 @@ #include "lldb/Core/ValueObjectConstResult.h" #include "lldb/Core/ValueObjectMemory.h" #include "lldb/Core/ValueObjectRegister.h" -#include "lldb/Symbol/TypeSystemClang.h" #include "lldb/Symbol/UnwindPlan.h" #include "lldb/Target/Process.h" #include "lldb/Target/RegisterContext.h" diff --git a/lldb/source/Plugins/ABI/SysV-ppc64/CMakeLists.txt b/lldb/source/Plugins/ABI/SysV-ppc64/CMakeLists.txt index b31182dd0f78e..0a0bb7b8623d9 100644 --- a/lldb/source/Plugins/ABI/SysV-ppc64/CMakeLists.txt +++ b/lldb/source/Plugins/ABI/SysV-ppc64/CMakeLists.txt @@ -5,6 +5,7 @@ add_lldb_library(lldbPluginABISysV_ppc64 PLUGIN lldbCore lldbSymbol lldbTarget + lldbPluginTypeSystemClang LINK_COMPONENTS Support ) diff --git a/lldb/source/Plugins/CMakeLists.txt b/lldb/source/Plugins/CMakeLists.txt index 5092b210a12cf..08817baec14ca 100644 --- a/lldb/source/Plugins/CMakeLists.txt +++ b/lldb/source/Plugins/CMakeLists.txt @@ -19,4 +19,5 @@ add_subdirectory(StructuredData) add_subdirectory(SymbolFile) add_subdirectory(SystemRuntime) add_subdirectory(SymbolVendor) +add_subdirectory(TypeSystem) add_subdirectory(UnwindAssembly) diff --git a/lldb/source/Plugins/DynamicLoader/Darwin-Kernel/DynamicLoaderDarwinKernel.cpp b/lldb/source/Plugins/DynamicLoader/Darwin-Kernel/DynamicLoaderDarwinKernel.cpp index 6019a1cc76021..bda9dd06c9114 100644 --- a/lldb/source/Plugins/DynamicLoader/Darwin-Kernel/DynamicLoaderDarwinKernel.cpp +++ b/lldb/source/Plugins/DynamicLoader/Darwin-Kernel/DynamicLoaderDarwinKernel.cpp @@ -244,6 +244,7 @@ DynamicLoaderDarwinKernel::SearchForKernelWithDebugHints(Process *process) { Status read_err; addr_t kernel_addresses_64[] = { + 0xfffffff000002010ULL, 0xfffffff000004010ULL, // newest arm64 devices 0xffffff8000004010ULL, // 2014-2015-ish arm64 devices 0xffffff8000002010ULL, // oldest arm64 devices diff --git a/lldb/source/Plugins/DynamicLoader/MacOSX-DYLD/CMakeLists.txt b/lldb/source/Plugins/DynamicLoader/MacOSX-DYLD/CMakeLists.txt index 515c82dcaca97..c470bc6e8339f 100644 --- a/lldb/source/Plugins/DynamicLoader/MacOSX-DYLD/CMakeLists.txt +++ b/lldb/source/Plugins/DynamicLoader/MacOSX-DYLD/CMakeLists.txt @@ -11,6 +11,7 @@ add_lldb_library(lldbPluginDynamicLoaderMacOSXDYLD PLUGIN lldbSymbol lldbTarget lldbUtility + lldbPluginTypeSystemClang LINK_COMPONENTS Support ) diff --git a/lldb/source/Plugins/DynamicLoader/MacOSX-DYLD/DynamicLoaderDarwin.cpp b/lldb/source/Plugins/DynamicLoader/MacOSX-DYLD/DynamicLoaderDarwin.cpp index 73347241a7391..e9778ba43cae6 100644 --- a/lldb/source/Plugins/DynamicLoader/MacOSX-DYLD/DynamicLoaderDarwin.cpp +++ b/lldb/source/Plugins/DynamicLoader/MacOSX-DYLD/DynamicLoaderDarwin.cpp @@ -16,7 +16,6 @@ #include "lldb/Core/Section.h" #include "lldb/Expression/DiagnosticManager.h" #include "lldb/Host/FileSystem.h" -#include "lldb/Symbol/TypeSystemClang.h" #include "lldb/Symbol/Function.h" #include "lldb/Symbol/ObjectFile.h" #include "lldb/Target/ABI.h" @@ -32,6 +31,7 @@ #include "lldb/Utility/State.h" #include "Plugins/LanguageRuntime/ObjC/ObjCLanguageRuntime.h" +#include "Plugins/TypeSystem/Clang/TypeSystemClang.h" //#define ENABLE_DEBUG_PRINTF // COMMENT THIS LINE OUT PRIOR TO CHECKIN #ifdef ENABLE_DEBUG_PRINTF @@ -399,6 +399,15 @@ bool DynamicLoaderDarwin::JSONImageInformationIntoImageInfo( else if (os_name == "maccatalyst") { image_infos[i].os_type = llvm::Triple::IOS; image_infos[i].os_env = llvm::Triple::MacABI; + } else if (os_name == "iossimulator") { + image_infos[i].os_type = llvm::Triple::IOS; + image_infos[i].os_env = llvm::Triple::Simulator; + } else if (os_name == "tvossimulator") { + image_infos[i].os_type = llvm::Triple::TvOS; + image_infos[i].os_env = llvm::Triple::Simulator; + } else if (os_name == "watchossimulator") { + image_infos[i].os_type = llvm::Triple::WatchOS; + image_infos[i].os_env = llvm::Triple::Simulator; } } if (image->HasKey("min_version_os_sdk")) { diff --git a/lldb/source/Plugins/DynamicLoader/MacOSX-DYLD/DynamicLoaderMacOS.cpp b/lldb/source/Plugins/DynamicLoader/MacOSX-DYLD/DynamicLoaderMacOS.cpp index e57f5cee64232..b9ace1b666175 100644 --- a/lldb/source/Plugins/DynamicLoader/MacOSX-DYLD/DynamicLoaderMacOS.cpp +++ b/lldb/source/Plugins/DynamicLoader/MacOSX-DYLD/DynamicLoaderMacOS.cpp @@ -11,7 +11,6 @@ #include "lldb/Core/Module.h" #include "lldb/Core/PluginManager.h" #include "lldb/Core/Section.h" -#include "lldb/Symbol/TypeSystemClang.h" #include "lldb/Symbol/ObjectFile.h" #include "lldb/Symbol/SymbolVendor.h" #include "lldb/Target/ABI.h" @@ -24,6 +23,8 @@ #include "DynamicLoaderDarwin.h" #include "DynamicLoaderMacOS.h" +#include "Plugins/TypeSystem/Clang/TypeSystemClang.h" + using namespace lldb; using namespace lldb_private; diff --git a/lldb/source/Plugins/DynamicLoader/MacOSX-DYLD/DynamicLoaderMacOSXDYLD.cpp b/lldb/source/Plugins/DynamicLoader/MacOSX-DYLD/DynamicLoaderMacOSXDYLD.cpp index 0bc732a75896d..f3e052846443d 100644 --- a/lldb/source/Plugins/DynamicLoader/MacOSX-DYLD/DynamicLoaderMacOSXDYLD.cpp +++ b/lldb/source/Plugins/DynamicLoader/MacOSX-DYLD/DynamicLoaderMacOSXDYLD.cpp @@ -12,7 +12,6 @@ #include "lldb/Core/ModuleSpec.h" #include "lldb/Core/PluginManager.h" #include "lldb/Core/Section.h" -#include "lldb/Symbol/TypeSystemClang.h" #include "lldb/Symbol/Function.h" #include "lldb/Symbol/ObjectFile.h" #include "lldb/Target/ABI.h" @@ -30,6 +29,7 @@ #include "DynamicLoaderMacOSXDYLD.h" #include "Plugins/LanguageRuntime/ObjC/ObjCLanguageRuntime.h" +#include "Plugins/TypeSystem/Clang/TypeSystemClang.h" //#define ENABLE_DEBUG_PRINTF // COMMENT THIS LINE OUT PRIOR TO CHECKIN #ifdef ENABLE_DEBUG_PRINTF diff --git a/lldb/source/Plugins/ExpressionParser/Clang/ASTResultSynthesizer.cpp b/lldb/source/Plugins/ExpressionParser/Clang/ASTResultSynthesizer.cpp index e21bc738992e7..b3252cf0cc87c 100644 --- a/lldb/source/Plugins/ExpressionParser/Clang/ASTResultSynthesizer.cpp +++ b/lldb/source/Plugins/ExpressionParser/Clang/ASTResultSynthesizer.cpp @@ -8,10 +8,10 @@ #include "ASTResultSynthesizer.h" +#include "ClangASTImporter.h" #include "ClangPersistentVariables.h" -#include "lldb/Symbol/TypeSystemClang.h" -#include "lldb/Symbol/ClangASTImporter.h" +#include "Plugins/TypeSystem/Clang/TypeSystemClang.h" #include "lldb/Target/Target.h" #include "lldb/Utility/LLDBAssert.h" #include "lldb/Utility/Log.h" diff --git a/lldb/source/Plugins/ExpressionParser/Clang/CMakeLists.txt b/lldb/source/Plugins/ExpressionParser/Clang/CMakeLists.txt index e92d089cab108..3bb120a48e90b 100644 --- a/lldb/source/Plugins/ExpressionParser/Clang/CMakeLists.txt +++ b/lldb/source/Plugins/ExpressionParser/Clang/CMakeLists.txt @@ -6,19 +6,24 @@ add_lldb_library(lldbPluginExpressionParserClang PLUGIN ASTResultSynthesizer.cpp ASTStructExtractor.cpp ASTUtils.cpp + ClangASTImporter.cpp + ClangASTMetadata.cpp ClangASTSource.cpp ClangDeclVendor.cpp ClangExpressionDeclMap.cpp ClangExpressionParser.cpp ClangExpressionSourceCode.cpp ClangExpressionVariable.cpp + ClangExternalASTSourceCallbacks.cpp ClangFunctionCaller.cpp ClangHost.cpp ClangModulesDeclVendor.cpp ClangPersistentVariables.cpp ClangUserExpression.cpp + ClangUtil.cpp ClangUtilityFunction.cpp CppModuleConfiguration.cpp + CxxModuleHandler.cpp IRForTarget.cpp IRDynamicChecks.cpp @@ -35,6 +40,8 @@ add_lldb_library(lldbPluginExpressionParserClang PLUGIN lldbUtility lldbPluginCPlusPlusLanguage lldbPluginCPPRuntime + lldbPluginObjCRuntime + lldbPluginTypeSystemClang CLANG_LIBS clangAST clangCodeGen diff --git a/lldb/source/Symbol/ClangASTImporter.cpp b/lldb/source/Plugins/ExpressionParser/Clang/ClangASTImporter.cpp similarity index 93% rename from lldb/source/Symbol/ClangASTImporter.cpp rename to lldb/source/Plugins/ExpressionParser/Clang/ClangASTImporter.cpp index 8feef9d0f284b..7e7e5c8a216a7 100644 --- a/lldb/source/Symbol/ClangASTImporter.cpp +++ b/lldb/source/Plugins/ExpressionParser/Clang/ClangASTImporter.cpp @@ -6,11 +6,7 @@ // //===----------------------------------------------------------------------===// -#include "lldb/Symbol/ClangASTImporter.h" #include "lldb/Core/Module.h" -#include "lldb/Symbol/TypeSystemClang.h" -#include "lldb/Symbol/ClangASTMetadata.h" -#include "lldb/Symbol/ClangUtil.h" #include "lldb/Utility/LLDBAssert.h" #include "lldb/Utility/Log.h" #include "clang/AST/Decl.h" @@ -20,6 +16,11 @@ #include "clang/Sema/Sema.h" #include "llvm/Support/raw_ostream.h" +#include "Plugins/ExpressionParser/Clang/ClangASTImporter.h" +#include "Plugins/ExpressionParser/Clang/ClangASTMetadata.h" +#include "Plugins/ExpressionParser/Clang/ClangUtil.h" +#include "Plugins/TypeSystem/Clang/TypeSystemClang.h" + #include using namespace lldb_private; @@ -872,6 +873,39 @@ ClangASTImporter::ASTImporterDelegate::ImportImpl(Decl *From) { } } + // Check which ASTContext this declaration originally came from. + DeclOrigin origin = m_master.GetDeclOrigin(From); + // If it originally came from the target ASTContext then we can just + // pretend that the original is the one we imported. This can happen for + // example when inspecting a persistent declaration from the scratch + // ASTContext (which will provide the declaration when parsing the + // expression and then we later try to copy the declaration back to the + // scratch ASTContext to store the result). + // Without this check we would ask the ASTImporter to import a declaration + // into the same ASTContext where it came from (which doesn't make a lot of + // sense). + if (origin.Valid() && origin.ctx == &getToContext()) { + RegisterImportedDecl(From, origin.decl); + return origin.decl; + } + + // This declaration came originally from another ASTContext. Instead of + // copying our potentially incomplete 'From' Decl we instead go to the + // original ASTContext and copy the original to the target. This is not + // only faster than first completing our current decl and then copying it + // to the target, but it also prevents that indirectly copying the same + // declaration to the same target requires the ASTImporter to merge all + // the different decls that appear to come from different ASTContexts (even + // though all these different source ASTContexts just got a copy from + // one source AST). + if (origin.Valid()) { + auto R = m_master.CopyDecl(&getToContext(), origin.decl); + if (R) { + RegisterImportedDecl(From, R); + return R; + } + } + return ASTImporter::ImportImpl(From); } @@ -971,6 +1005,27 @@ void ClangASTImporter::ASTImporterDelegate::ImportDefinitionTo( } } +/// Takes a CXXMethodDecl and completes the return type if necessary. This +/// is currently only necessary for virtual functions with covariant return +/// types where Clang's CodeGen expects that the underlying records are already +/// completed. +static void MaybeCompleteReturnType(ClangASTImporter &importer, + CXXMethodDecl *to_method) { + if (!to_method->isVirtual()) + return; + QualType return_type = to_method->getReturnType(); + if (!return_type->isPointerType() && !return_type->isReferenceType()) + return; + + clang::RecordDecl *rd = return_type->getPointeeType()->getAsRecordDecl(); + if (!rd) + return; + if (rd->getDefinition()) + return; + + importer.CompleteTagDecl(rd); +} + void ClangASTImporter::ASTImporterDelegate::Imported(clang::Decl *from, clang::Decl *to) { Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_EXPRESSIONS)); @@ -1126,6 +1181,9 @@ void ClangASTImporter::ASTImporterDelegate::Imported(clang::Decl *from, } } } + + if (clang::CXXMethodDecl *to_method = dyn_cast(to)) + MaybeCompleteReturnType(m_master, to_method); } clang::Decl * diff --git a/lldb/include/lldb/Symbol/ClangASTImporter.h b/lldb/source/Plugins/ExpressionParser/Clang/ClangASTImporter.h similarity index 99% rename from lldb/include/lldb/Symbol/ClangASTImporter.h rename to lldb/source/Plugins/ExpressionParser/Clang/ClangASTImporter.h index a4e042425dc62..2bc0cd6f7ecb8 100644 --- a/lldb/include/lldb/Symbol/ClangASTImporter.h +++ b/lldb/source/Plugins/ExpressionParser/Clang/ClangASTImporter.h @@ -23,9 +23,10 @@ #include "lldb/Host/FileSystem.h" #include "lldb/Symbol/CompilerDeclContext.h" -#include "lldb/Symbol/CxxModuleHandler.h" #include "lldb/lldb-types.h" +#include "Plugins/ExpressionParser/Clang/CxxModuleHandler.h" + #include "llvm/ADT/DenseMap.h" namespace lldb_private { diff --git a/lldb/source/Symbol/ClangASTMetadata.cpp b/lldb/source/Plugins/ExpressionParser/Clang/ClangASTMetadata.cpp similarity index 93% rename from lldb/source/Symbol/ClangASTMetadata.cpp rename to lldb/source/Plugins/ExpressionParser/Clang/ClangASTMetadata.cpp index 31b012f553fab..6a24e4551797d 100644 --- a/lldb/source/Symbol/ClangASTMetadata.cpp +++ b/lldb/source/Plugins/ExpressionParser/Clang/ClangASTMetadata.cpp @@ -6,7 +6,7 @@ // //===----------------------------------------------------------------------===// -#include "lldb/Symbol/ClangASTMetadata.h" +#include "Plugins/ExpressionParser/Clang/ClangASTMetadata.h" #include "lldb/Utility/Stream.h" using namespace lldb_private; diff --git a/lldb/include/lldb/Symbol/ClangASTMetadata.h b/lldb/source/Plugins/ExpressionParser/Clang/ClangASTMetadata.h similarity index 100% rename from lldb/include/lldb/Symbol/ClangASTMetadata.h rename to lldb/source/Plugins/ExpressionParser/Clang/ClangASTMetadata.h diff --git a/lldb/source/Plugins/ExpressionParser/Clang/ClangASTSource.cpp b/lldb/source/Plugins/ExpressionParser/Clang/ClangASTSource.cpp index f6e119902e31d..f84ce63dc3532 100644 --- a/lldb/source/Plugins/ExpressionParser/Clang/ClangASTSource.cpp +++ b/lldb/source/Plugins/ExpressionParser/Clang/ClangASTSource.cpp @@ -13,8 +13,6 @@ #include "lldb/Core/Module.h" #include "lldb/Core/ModuleList.h" -#include "lldb/Symbol/TypeSystemClang.h" -#include "lldb/Symbol/ClangUtil.h" #include "lldb/Symbol/CompilerDeclContext.h" #include "lldb/Symbol/Function.h" #include "lldb/Symbol/SymbolFile.h" @@ -24,7 +22,9 @@ #include "clang/AST/ASTContext.h" #include "clang/AST/RecordLayout.h" +#include "Plugins/ExpressionParser/Clang/ClangUtil.h" #include "Plugins/LanguageRuntime/ObjC/ObjCLanguageRuntime.h" +#include "Plugins/TypeSystem/Clang/TypeSystemClang.h" #include #include @@ -530,20 +530,6 @@ void ClangASTSource::FindExternalLexicalDecls( m_ast_importer_sp->RequireCompleteType(copied_field_type); } - auto decl_context_non_const = const_cast(decl_context); - - // The decl ended up in the wrong DeclContext. Let's fix that so - // the decl we copied will actually be found. - // FIXME: This is a horrible hack that shouldn't be necessary. However - // it seems our current setup sometimes fails to copy decls to the right - // place. See rdar://55129537. - if (copied_decl->getDeclContext() != decl_context) { - assert(copied_decl->getDeclContext()->containsDecl(copied_decl)); - copied_decl->getDeclContext()->removeDecl(copied_decl); - copied_decl->setDeclContext(decl_context_non_const); - assert(!decl_context_non_const->containsDecl(copied_decl)); - decl_context_non_const->addDeclInternal(copied_decl); - } } else { SkippedDecls = true; } diff --git a/lldb/source/Plugins/ExpressionParser/Clang/ClangASTSource.h b/lldb/source/Plugins/ExpressionParser/Clang/ClangASTSource.h index 52fb0d1f4eae3..4f0c9ac386369 100644 --- a/lldb/source/Plugins/ExpressionParser/Clang/ClangASTSource.h +++ b/lldb/source/Plugins/ExpressionParser/Clang/ClangASTSource.h @@ -11,7 +11,7 @@ #include -#include "lldb/Symbol/ClangASTImporter.h" +#include "Plugins/ExpressionParser/Clang/ClangASTImporter.h" #include "lldb/Symbol/CompilerType.h" #include "lldb/Target/Target.h" #include "clang/AST/ExternalASTSource.h" diff --git a/lldb/source/Plugins/ExpressionParser/Clang/ClangDeclVendor.cpp b/lldb/source/Plugins/ExpressionParser/Clang/ClangDeclVendor.cpp index 4bdd37d513c78..4dd932adab328 100644 --- a/lldb/source/Plugins/ExpressionParser/Clang/ClangDeclVendor.cpp +++ b/lldb/source/Plugins/ExpressionParser/Clang/ClangDeclVendor.cpp @@ -7,8 +7,9 @@ //===----------------------------------------------------------------------===// #include "Plugins/ExpressionParser/Clang/ClangDeclVendor.h" +#include "Plugins/ExpressionParser/Clang/ClangUtil.h" +#include "Plugins/TypeSystem/Clang/TypeSystemClang.h" -#include "lldb/Symbol/TypeSystemClang.h" #include "lldb/Utility/ConstString.h" using namespace lldb_private; diff --git a/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionDeclMap.cpp b/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionDeclMap.cpp index 6bfd7382f8118..f9fbc737ef4d0 100644 --- a/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionDeclMap.cpp +++ b/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionDeclMap.cpp @@ -11,15 +11,15 @@ #include "ClangASTSource.h" #include "ClangModulesDeclVendor.h" #include "ClangPersistentVariables.h" +#include "ClangUtil.h" +#include "Plugins/TypeSystem/Clang/TypeSystemClang.h" #include "lldb/Core/Address.h" #include "lldb/Core/Module.h" #include "lldb/Core/ModuleSpec.h" #include "lldb/Core/ValueObjectConstResult.h" #include "lldb/Core/ValueObjectVariable.h" #include "lldb/Expression/Materializer.h" -#include "lldb/Symbol/TypeSystemClang.h" -#include "lldb/Symbol/ClangUtil.h" #include "lldb/Symbol/CompileUnit.h" #include "lldb/Symbol/CompilerDecl.h" #include "lldb/Symbol/CompilerDeclContext.h" diff --git a/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionParser.cpp b/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionParser.cpp index b26493c87fecb..95975e4230acd 100644 --- a/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionParser.cpp +++ b/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionParser.cpp @@ -67,6 +67,7 @@ #include "IRForTarget.h" #include "ModuleDependencyCollector.h" +#include "Plugins/TypeSystem/Clang/TypeSystemClang.h" #include "lldb/Core/Debugger.h" #include "lldb/Core/Disassembler.h" #include "lldb/Core/Module.h" @@ -75,7 +76,6 @@ #include "lldb/Expression/IRInterpreter.h" #include "lldb/Host/File.h" #include "lldb/Host/HostInfo.h" -#include "lldb/Symbol/TypeSystemClang.h" #include "lldb/Symbol/SymbolVendor.h" #include "lldb/Target/ExecutionContext.h" #include "lldb/Target/Language.h" diff --git a/lldb/source/Symbol/ClangExternalASTSourceCallbacks.cpp b/lldb/source/Plugins/ExpressionParser/Clang/ClangExternalASTSourceCallbacks.cpp similarity index 92% rename from lldb/source/Symbol/ClangExternalASTSourceCallbacks.cpp rename to lldb/source/Plugins/ExpressionParser/Clang/ClangExternalASTSourceCallbacks.cpp index a830194975d65..db9d265ba9a2c 100644 --- a/lldb/source/Symbol/ClangExternalASTSourceCallbacks.cpp +++ b/lldb/source/Plugins/ExpressionParser/Clang/ClangExternalASTSourceCallbacks.cpp @@ -6,8 +6,8 @@ // //===----------------------------------------------------------------------===// -#include "lldb/Symbol/ClangExternalASTSourceCallbacks.h" -#include "lldb/Symbol/TypeSystemClang.h" +#include "Plugins/ExpressionParser/Clang/ClangExternalASTSourceCallbacks.h" +#include "Plugins/TypeSystem/Clang/TypeSystemClang.h" #include "clang/AST/Decl.h" diff --git a/lldb/include/lldb/Symbol/ClangExternalASTSourceCallbacks.h b/lldb/source/Plugins/ExpressionParser/Clang/ClangExternalASTSourceCallbacks.h similarity index 96% rename from lldb/include/lldb/Symbol/ClangExternalASTSourceCallbacks.h rename to lldb/source/Plugins/ExpressionParser/Clang/ClangExternalASTSourceCallbacks.h index 49bc30c633c30..98e9f5adbdbf1 100644 --- a/lldb/include/lldb/Symbol/ClangExternalASTSourceCallbacks.h +++ b/lldb/source/Plugins/ExpressionParser/Clang/ClangExternalASTSourceCallbacks.h @@ -9,7 +9,7 @@ #ifndef liblldb_ClangExternalASTSourceCallbacks_h_ #define liblldb_ClangExternalASTSourceCallbacks_h_ -#include "lldb/Symbol/TypeSystemClang.h" +#include "Plugins/TypeSystem/Clang/TypeSystemClang.h" #include "clang/AST/ExternalASTSource.h" namespace lldb_private { diff --git a/lldb/source/Plugins/ExpressionParser/Clang/ClangFunctionCaller.cpp b/lldb/source/Plugins/ExpressionParser/Clang/ClangFunctionCaller.cpp index 364ee582f5382..4c986a55e7496 100644 --- a/lldb/source/Plugins/ExpressionParser/Clang/ClangFunctionCaller.cpp +++ b/lldb/source/Plugins/ExpressionParser/Clang/ClangFunctionCaller.cpp @@ -21,12 +21,12 @@ #include "llvm/ExecutionEngine/ExecutionEngine.h" #include "llvm/IR/Module.h" +#include "Plugins/TypeSystem/Clang/TypeSystemClang.h" #include "lldb/Core/Module.h" #include "lldb/Core/ValueObject.h" #include "lldb/Core/ValueObjectList.h" #include "lldb/Expression/IRExecutionUnit.h" #include "lldb/Interpreter/CommandReturnObject.h" -#include "lldb/Symbol/TypeSystemClang.h" #include "lldb/Symbol/Function.h" #include "lldb/Symbol/Type.h" #include "lldb/Target/ExecutionContext.h" diff --git a/lldb/source/Plugins/ExpressionParser/Clang/ClangModulesDeclVendor.cpp b/lldb/source/Plugins/ExpressionParser/Clang/ClangModulesDeclVendor.cpp index 0490888fea70d..4fd4b84cb39e7 100644 --- a/lldb/source/Plugins/ExpressionParser/Clang/ClangModulesDeclVendor.cpp +++ b/lldb/source/Plugins/ExpressionParser/Clang/ClangModulesDeclVendor.cpp @@ -24,10 +24,10 @@ #include "ClangModulesDeclVendor.h" #include "ModuleDependencyCollector.h" +#include "Plugins/TypeSystem/Clang/TypeSystemClang.h" #include "lldb/Core/ModuleList.h" #include "lldb/Host/Host.h" #include "lldb/Host/HostInfo.h" -#include "lldb/Symbol/TypeSystemClang.h" #include "lldb/Symbol/CompileUnit.h" #include "lldb/Symbol/SourceModule.h" #include "lldb/Target/Target.h" diff --git a/lldb/source/Plugins/ExpressionParser/Clang/ClangPersistentVariables.cpp b/lldb/source/Plugins/ExpressionParser/Clang/ClangPersistentVariables.cpp index b2c12636c2715..e2e31ca0e6ad1 100644 --- a/lldb/source/Plugins/ExpressionParser/Clang/ClangPersistentVariables.cpp +++ b/lldb/source/Plugins/ExpressionParser/Clang/ClangPersistentVariables.cpp @@ -7,10 +7,10 @@ //===----------------------------------------------------------------------===// #include "ClangPersistentVariables.h" -#include "lldb/Expression/IRExecutionUnit.h" +#include "ClangASTImporter.h" +#include "Plugins/TypeSystem/Clang/TypeSystemClang.h" #include "lldb/Core/Value.h" -#include "lldb/Symbol/TypeSystemClang.h" #include "lldb/Target/Target.h" #include "lldb/Utility/DataExtractor.h" #include "lldb/Utility/Log.h" diff --git a/lldb/source/Plugins/ExpressionParser/Clang/ClangUserExpression.cpp b/lldb/source/Plugins/ExpressionParser/Clang/ClangUserExpression.cpp index c5296009c6da8..0132ccf1c2b28 100644 --- a/lldb/source/Plugins/ExpressionParser/Clang/ClangUserExpression.cpp +++ b/lldb/source/Plugins/ExpressionParser/Clang/ClangUserExpression.cpp @@ -20,6 +20,7 @@ #include "ClangUserExpression.h" #include "ASTResultSynthesizer.h" +#include "ClangASTMetadata.h" #include "ClangDiagnostic.h" #include "ClangExpressionDeclMap.h" #include "ClangExpressionParser.h" @@ -27,6 +28,7 @@ #include "ClangPersistentVariables.h" #include "CppModuleConfiguration.h" +#include "Plugins/TypeSystem/Clang/TypeSystemClang.h" #include "lldb/Core/Debugger.h" #include "lldb/Core/Module.h" #include "lldb/Core/StreamFile.h" @@ -37,8 +39,6 @@ #include "lldb/Expression/Materializer.h" #include "lldb/Host/HostInfo.h" #include "lldb/Symbol/Block.h" -#include "lldb/Symbol/TypeSystemClang.h" -#include "lldb/Symbol/ClangASTMetadata.h" #include "lldb/Symbol/CompileUnit.h" #include "lldb/Symbol/Function.h" #include "lldb/Symbol/ObjectFile.h" diff --git a/lldb/source/Symbol/ClangUtil.cpp b/lldb/source/Plugins/ExpressionParser/Clang/ClangUtil.cpp similarity index 95% rename from lldb/source/Symbol/ClangUtil.cpp rename to lldb/source/Plugins/ExpressionParser/Clang/ClangUtil.cpp index e351a16d87279..4e27d3d9adc2d 100644 --- a/lldb/source/Symbol/ClangUtil.cpp +++ b/lldb/source/Plugins/ExpressionParser/Clang/ClangUtil.cpp @@ -8,8 +8,8 @@ // types and decls. //===----------------------------------------------------------------------===// -#include "lldb/Symbol/ClangUtil.h" -#include "lldb/Symbol/TypeSystemClang.h" +#include "Plugins/ExpressionParser/Clang/ClangUtil.h" +#include "Plugins/TypeSystem/Clang/TypeSystemClang.h" using namespace clang; using namespace lldb_private; diff --git a/lldb/include/lldb/Symbol/ClangUtil.h b/lldb/source/Plugins/ExpressionParser/Clang/ClangUtil.h similarity index 100% rename from lldb/include/lldb/Symbol/ClangUtil.h rename to lldb/source/Plugins/ExpressionParser/Clang/ClangUtil.h diff --git a/lldb/source/Symbol/CxxModuleHandler.cpp b/lldb/source/Plugins/ExpressionParser/Clang/CxxModuleHandler.cpp similarity index 98% rename from lldb/source/Symbol/CxxModuleHandler.cpp rename to lldb/source/Plugins/ExpressionParser/Clang/CxxModuleHandler.cpp index 6930f71d1eb57..4b74e9a0d13c2 100644 --- a/lldb/source/Symbol/CxxModuleHandler.cpp +++ b/lldb/source/Plugins/ExpressionParser/Clang/CxxModuleHandler.cpp @@ -6,9 +6,9 @@ // //===----------------------------------------------------------------------===// -#include "lldb/Symbol/CxxModuleHandler.h" +#include "Plugins/ExpressionParser/Clang/CxxModuleHandler.h" +#include "Plugins/TypeSystem/Clang/TypeSystemClang.h" -#include "lldb/Symbol/TypeSystemClang.h" #include "lldb/Utility/Log.h" #include "clang/Sema/Lookup.h" #include "llvm/Support/Error.h" diff --git a/lldb/include/lldb/Symbol/CxxModuleHandler.h b/lldb/source/Plugins/ExpressionParser/Clang/CxxModuleHandler.h similarity index 100% rename from lldb/include/lldb/Symbol/CxxModuleHandler.h rename to lldb/source/Plugins/ExpressionParser/Clang/CxxModuleHandler.h diff --git a/lldb/source/Plugins/ExpressionParser/Clang/IRForTarget.cpp b/lldb/source/Plugins/ExpressionParser/Clang/IRForTarget.cpp index d5860ec4fd5a5..63dc6c8859f90 100644 --- a/lldb/source/Plugins/ExpressionParser/Clang/IRForTarget.cpp +++ b/lldb/source/Plugins/ExpressionParser/Clang/IRForTarget.cpp @@ -9,7 +9,9 @@ #include "IRForTarget.h" #include "ClangExpressionDeclMap.h" +#include "ClangUtil.h" +#include "Plugins/TypeSystem/Clang/TypeSystemClang.h" #include "llvm/IR/Constants.h" #include "llvm/IR/DataLayout.h" #include "llvm/IR/InstrTypes.h" @@ -27,8 +29,6 @@ #include "lldb/Core/dwarf.h" #include "lldb/Expression/IRExecutionUnit.h" #include "lldb/Expression/IRInterpreter.h" -#include "lldb/Symbol/TypeSystemClang.h" -#include "lldb/Symbol/ClangUtil.h" #include "lldb/Symbol/CompilerType.h" #include "lldb/Utility/ConstString.h" #include "lldb/Utility/DataBufferHeap.h" diff --git a/lldb/source/Plugins/ExpressionParser/Swift/SwiftASTManipulator.cpp b/lldb/source/Plugins/ExpressionParser/Swift/SwiftASTManipulator.cpp index 67e397529c44e..fdf0d4ab8c4b5 100644 --- a/lldb/source/Plugins/ExpressionParser/Swift/SwiftASTManipulator.cpp +++ b/lldb/source/Plugins/ExpressionParser/Swift/SwiftASTManipulator.cpp @@ -283,8 +283,8 @@ void SwiftASTManipulatorBase::DoInitialization() { break; } } - } else if (FD->hasName() && - FD->getName().str().startswith(m_wrapper_func_prefix)) { + } else if (FD->hasName() && FD->getBaseIdentifier().str() + .startswith(m_wrapper_func_prefix)) { m_wrapper_decl = FD; } @@ -320,7 +320,7 @@ void SwiftASTManipulatorBase::DoInitialization() { if (do_stmt) { // There should only be one catch: assert(m_do_stmt->getCatches().size() == 1); - swift::CatchStmt *our_catch = m_do_stmt->getCatches().front(); + swift::CaseStmt *our_catch = m_do_stmt->getCatches().front(); if (our_catch) m_catch_stmt = our_catch; } diff --git a/lldb/source/Plugins/ExpressionParser/Swift/SwiftASTManipulator.h b/lldb/source/Plugins/ExpressionParser/Swift/SwiftASTManipulator.h index 9b670a020a52a..c66b4d6d34f73 100644 --- a/lldb/source/Plugins/ExpressionParser/Swift/SwiftASTManipulator.h +++ b/lldb/source/Plugins/ExpressionParser/Swift/SwiftASTManipulator.h @@ -23,7 +23,7 @@ #include "llvm/ADT/SmallVector.h" namespace swift { -class CatchStmt; +class CaseStmt; class DoCatchStmt; class ExtensionDecl; class FuncDecl; @@ -133,7 +133,7 @@ class SwiftASTManipulatorBase { swift::DoCatchStmt *m_do_stmt = nullptr; /// The body of the catch - we patch the assignment there to capture /// any error thrown. - swift::CatchStmt *m_catch_stmt = nullptr; + swift::CaseStmt *m_catch_stmt = nullptr; }; class SwiftASTManipulator : public SwiftASTManipulatorBase { diff --git a/lldb/source/Plugins/ExpressionParser/Swift/SwiftExpressionParser.cpp b/lldb/source/Plugins/ExpressionParser/Swift/SwiftExpressionParser.cpp index ce0d19594859b..88a1019160b31 100644 --- a/lldb/source/Plugins/ExpressionParser/Swift/SwiftExpressionParser.cpp +++ b/lldb/source/Plugins/ExpressionParser/Swift/SwiftExpressionParser.cpp @@ -58,6 +58,7 @@ #include "swift/AST/DiagnosticEngine.h" #include "swift/AST/DiagnosticConsumer.h" #include "swift/AST/IRGenOptions.h" +#include "swift/AST/IRGenRequests.h" #include "swift/AST/Module.h" #include "swift/AST/ModuleLoader.h" #include "swift/Demangling/Demangle.h" @@ -250,7 +251,7 @@ class LLDBExprNameLookup : public LLDBNameLookup { // must be moved to the source-file level to be legal. But we // don't want to register them with lldb unless they are of the // kind lldb explicitly wants to globalize. - if (shouldGlobalize(value_decl->getBaseName().getIdentifier(), + if (shouldGlobalize(value_decl->getBaseIdentifier(), value_decl->getKind())) m_staged_decls.AddDecl(value_decl, false, ConstString()); } @@ -1326,7 +1327,7 @@ static llvm::Expected ParseAndImport( stack_frame_sp.reset(); } - swift::performNameBinding(*source_file); + swift::performImportResolution(*source_file); if (swift_ast_context->HasErrors()) return make_error(); @@ -1659,11 +1660,15 @@ unsigned SwiftExpressionParser::Parse(DiagnosticManager &diagnostic_manager, std::lock_guard global_context_locker( IRExecutionUnit::GetLLVMGlobalContextMutex()); - m_module = swift::performIRGeneration( + auto GenModule = swift::performIRGeneration( swift_ast_ctx->GetIRGenOptions(), &parsed_expr->module, std::move(sil_module), "lldb_module", swift::PrimarySpecificPaths("", parsed_expr->main_filename), - SwiftASTContext::GetGlobalLLVMContext(), llvm::ArrayRef()); + llvm::ArrayRef()); + + auto ContextAndModule = std::move(GenModule).release(); + m_llvm_context.reset(ContextAndModule.first); + m_module.reset(ContextAndModule.second); } if (swift_ast_ctx->HasErrors()) { @@ -1813,10 +1818,9 @@ Status SwiftExpressionParser::PrepareForExecution( std::vector features; - std::unique_ptr llvm_context_up; // m_module is handed off here. m_execution_unit_sp.reset( - new IRExecutionUnit(llvm_context_up, m_module, function_name, + new IRExecutionUnit(m_llvm_context, m_module, function_name, exe_ctx.GetTargetSP(), sc, features)); // TODO: figure out some way to work ClangExpressionDeclMap into diff --git a/lldb/source/Plugins/ExpressionParser/Swift/SwiftExpressionSourceCode.cpp b/lldb/source/Plugins/ExpressionParser/Swift/SwiftExpressionSourceCode.cpp index 8e08cdf50b6f2..7aa65aaf88da0 100644 --- a/lldb/source/Plugins/ExpressionParser/Swift/SwiftExpressionSourceCode.cpp +++ b/lldb/source/Plugins/ExpressionParser/Swift/SwiftExpressionSourceCode.cpp @@ -9,6 +9,7 @@ #include "SwiftExpressionSourceCode.h" #include "Plugins/ExpressionParser/Swift/SwiftASTManipulator.h" +#include "lldb/Symbol/SwiftASTContext.h" #include "lldb/Target/Language.h" #include "lldb/Target/Platform.h" #include "lldb/Target/Target.h" diff --git a/lldb/source/Plugins/ExpressionParser/Swift/SwiftPersistentExpressionState.cpp b/lldb/source/Plugins/ExpressionParser/Swift/SwiftPersistentExpressionState.cpp index 0bbf1feabfb3b..c5635e582199f 100644 --- a/lldb/source/Plugins/ExpressionParser/Swift/SwiftPersistentExpressionState.cpp +++ b/lldb/source/Plugins/ExpressionParser/Swift/SwiftPersistentExpressionState.cpp @@ -136,7 +136,7 @@ void SwiftPersistentExpressionState::SwiftDeclMap::AddDecl( std::string name_str; if (alias.IsEmpty()) { - name_str = (value_decl->getBaseName().getIdentifier().str()); + name_str = (value_decl->getBaseIdentifier().str()); } else { name_str.assign(alias.GetCString()); } diff --git a/lldb/source/Plugins/ExpressionParser/Swift/SwiftUserExpression.cpp b/lldb/source/Plugins/ExpressionParser/Swift/SwiftUserExpression.cpp index 3b4d3b764389d..26b819836d601 100644 --- a/lldb/source/Plugins/ExpressionParser/Swift/SwiftUserExpression.cpp +++ b/lldb/source/Plugins/ExpressionParser/Swift/SwiftUserExpression.cpp @@ -244,7 +244,7 @@ void SwiftUserExpression::ScanContext(ExecutionContext &exe_ctx, Status &err) { self_type = ToCompilerType(object_type.getPointer()); // Handle weak self. - if (auto *ref_type = llvm::dyn_cast( + if (auto *ref_type = llvm::dyn_cast_or_null( GetSwiftType(self_type).getPointer())) { if (ref_type->getOwnership() == swift::ReferenceOwnership::Weak) { m_is_class = true; diff --git a/lldb/source/Plugins/InstrumentationRuntime/MainThreadChecker/MainThreadCheckerRuntime.cpp b/lldb/source/Plugins/InstrumentationRuntime/MainThreadChecker/MainThreadCheckerRuntime.cpp index 454d4a16d7640..52e04794919ff 100644 --- a/lldb/source/Plugins/InstrumentationRuntime/MainThreadChecker/MainThreadCheckerRuntime.cpp +++ b/lldb/source/Plugins/InstrumentationRuntime/MainThreadChecker/MainThreadCheckerRuntime.cpp @@ -11,6 +11,7 @@ #include "lldb/Breakpoint/StoppointCallbackContext.h" #include "lldb/Core/Module.h" #include "lldb/Core/PluginManager.h" +#include "lldb/Symbol/SwiftASTContext.h" #include "lldb/Symbol/Symbol.h" #include "lldb/Symbol/SymbolContext.h" #include "lldb/Symbol/Variable.h" diff --git a/lldb/source/Plugins/InstrumentationRuntime/SwiftRuntimeReporting/SwiftRuntimeReporting.cpp b/lldb/source/Plugins/InstrumentationRuntime/SwiftRuntimeReporting/SwiftRuntimeReporting.cpp index c57833db40ffa..9c1db384dfe5d 100644 --- a/lldb/source/Plugins/InstrumentationRuntime/SwiftRuntimeReporting/SwiftRuntimeReporting.cpp +++ b/lldb/source/Plugins/InstrumentationRuntime/SwiftRuntimeReporting/SwiftRuntimeReporting.cpp @@ -9,10 +9,11 @@ #include "SwiftRuntimeReporting.h" +#include "Plugins/Process/Utility/HistoryThread.h" +#include "Plugins/TypeSystem/Clang/TypeSystemClang.h" #include "lldb/Breakpoint/StoppointCallbackContext.h" #include "lldb/Core/Module.h" #include "lldb/Core/PluginManager.h" -#include "lldb/Symbol/TypeSystemClang.h" #include "lldb/Symbol/Symbol.h" #include "lldb/Symbol/SymbolContext.h" #include "lldb/Symbol/Variable.h" @@ -24,7 +25,6 @@ #include "lldb/Target/Target.h" #include "lldb/Target/Thread.h" #include "lldb/Utility/RegularExpression.h" -#include "Plugins/Process/Utility/HistoryThread.h" #include "swift/AST/ASTContext.h" #include "swift/AST/NameLookup.h" #include "swift/ClangImporter/ClangImporter.h" diff --git a/lldb/source/Plugins/Language/CPlusPlus/BlockPointer.cpp b/lldb/source/Plugins/Language/CPlusPlus/BlockPointer.cpp index c4cd025da0175..decbdbce7ea52 100644 --- a/lldb/source/Plugins/Language/CPlusPlus/BlockPointer.cpp +++ b/lldb/source/Plugins/Language/CPlusPlus/BlockPointer.cpp @@ -8,10 +8,11 @@ #include "BlockPointer.h" +#include "Plugins/ExpressionParser/Clang/ClangASTImporter.h" +#include "Plugins/ExpressionParser/Clang/ClangPersistentVariables.h" +#include "Plugins/TypeSystem/Clang/TypeSystemClang.h" #include "lldb/Core/ValueObject.h" #include "lldb/DataFormatters/FormattersHelpers.h" -#include "lldb/Symbol/TypeSystemClang.h" -#include "lldb/Symbol/ClangASTImporter.h" #include "lldb/Symbol/CompilerType.h" #include "lldb/Symbol/TypeSystem.h" #include "lldb/Target/Target.h" diff --git a/lldb/source/Plugins/Language/CPlusPlus/CMakeLists.txt b/lldb/source/Plugins/Language/CPlusPlus/CMakeLists.txt index ea36c7ec80dbe..2a541a9e528cd 100644 --- a/lldb/source/Plugins/Language/CPlusPlus/CMakeLists.txt +++ b/lldb/source/Plugins/Language/CPlusPlus/CMakeLists.txt @@ -29,6 +29,7 @@ add_lldb_library(lldbPluginCPlusPlusLanguage PLUGIN lldbUtility lldbPluginClangCommon lldbPluginCPPRuntime + lldbPluginTypeSystemClang LINK_COMPONENTS Support diff --git a/lldb/source/Plugins/Language/CPlusPlus/CPlusPlusLanguage.cpp b/lldb/source/Plugins/Language/CPlusPlus/CPlusPlusLanguage.cpp index 4385a60f58623..6f9cb1460e8eb 100644 --- a/lldb/source/Plugins/Language/CPlusPlus/CPlusPlusLanguage.cpp +++ b/lldb/source/Plugins/Language/CPlusPlus/CPlusPlusLanguage.cpp @@ -609,6 +609,15 @@ static void LoadLibCxxFormatters(lldb::TypeCategoryImplSP cpp_category_sp) { "shared_ptr synthetic children", ConstString("^(std::__[[:alnum:]]+::)shared_ptr<.+>(( )?&)?$"), stl_synth_flags, true); + + ConstString libcxx_std_unique_ptr_regex( + "^std::__[[:alnum:]]+::unique_ptr<.+>(( )?&)?$"); + AddCXXSynthetic( + cpp_category_sp, + lldb_private::formatters::LibcxxUniquePtrSyntheticFrontEndCreator, + "unique_ptr synthetic children", libcxx_std_unique_ptr_regex, + stl_synth_flags, true); + AddCXXSynthetic( cpp_category_sp, lldb_private::formatters::LibcxxSharedPtrSyntheticFrontEndCreator, @@ -713,6 +722,10 @@ static void LoadLibCxxFormatters(lldb::TypeCategoryImplSP cpp_category_sp) { "libc++ std::weak_ptr summary provider", ConstString("^std::__[[:alnum:]]+::weak_ptr<.+>(( )?&)?$"), stl_summary_flags, true); + AddCXXSummary(cpp_category_sp, + lldb_private::formatters::LibcxxUniquePointerSummaryProvider, + "libc++ std::unique_ptr summary provider", + libcxx_std_unique_ptr_regex, stl_summary_flags, true); AddCXXSynthetic( cpp_category_sp, diff --git a/lldb/source/Plugins/Language/CPlusPlus/CPlusPlusNameParser.cpp b/lldb/source/Plugins/Language/CPlusPlus/CPlusPlusNameParser.cpp index 932db17b964a5..48f734731a651 100644 --- a/lldb/source/Plugins/Language/CPlusPlus/CPlusPlusNameParser.cpp +++ b/lldb/source/Plugins/Language/CPlusPlus/CPlusPlusNameParser.cpp @@ -329,6 +329,37 @@ bool CPlusPlusNameParser::ConsumeOperator() { } const auto &token = Peek(); + + // When clang generates debug info it adds template parameters to names. + // Since clang doesn't add a space between the name and the template parameter + // in some cases we are not generating valid C++ names e.g.: + // + // operator< + // + // In some of these cases we will not parse them correctly. This fixes the + // issue by detecting this case and inserting tok::less in place of + // tok::lessless and returning successfully that we consumed the operator. + if (token.getKind() == tok::lessless) { + // Make sure we have more tokens before attempting to look ahead one more. + if (m_next_token_index + 1 < m_tokens.size()) { + // Look ahead two tokens. + clang::Token n_token = m_tokens[m_next_token_index + 1]; + // If we find ( or < then this is indeed operator<< no need for fix. + if (n_token.getKind() != tok::l_paren && n_token.getKind() != tok::less) { + clang::Token tmp_tok; + tmp_tok.startToken(); + tmp_tok.setLength(1); + tmp_tok.setLocation(token.getLocation().getLocWithOffset(1)); + tmp_tok.setKind(tok::less); + + m_tokens[m_next_token_index] = tmp_tok; + + start_position.Remove(); + return true; + } + } + } + switch (token.getKind()) { case tok::kw_new: case tok::kw_delete: diff --git a/lldb/source/Plugins/Language/CPlusPlus/CxxStringTypes.cpp b/lldb/source/Plugins/Language/CPlusPlus/CxxStringTypes.cpp index eab42ec285261..c4f3446e1c78e 100644 --- a/lldb/source/Plugins/Language/CPlusPlus/CxxStringTypes.cpp +++ b/lldb/source/Plugins/Language/CPlusPlus/CxxStringTypes.cpp @@ -10,13 +10,13 @@ #include "llvm/Support/ConvertUTF.h" +#include "Plugins/TypeSystem/Clang/TypeSystemClang.h" #include "lldb/Core/ValueObject.h" #include "lldb/Core/ValueObjectConstResult.h" #include "lldb/DataFormatters/FormattersHelpers.h" #include "lldb/DataFormatters/StringPrinter.h" #include "lldb/DataFormatters/TypeSummary.h" #include "lldb/Host/Time.h" -#include "lldb/Symbol/TypeSystemClang.h" #include "lldb/Target/ProcessStructReader.h" #include "lldb/Target/SectionLoadList.h" #include "lldb/Target/Target.h" diff --git a/lldb/source/Plugins/Language/CPlusPlus/LibCxx.cpp b/lldb/source/Plugins/Language/CPlusPlus/LibCxx.cpp index cdfdc16dc8e02..3cb4a28eefee3 100644 --- a/lldb/source/Plugins/Language/CPlusPlus/LibCxx.cpp +++ b/lldb/source/Plugins/Language/CPlusPlus/LibCxx.cpp @@ -16,7 +16,6 @@ #include "lldb/DataFormatters/StringPrinter.h" #include "lldb/DataFormatters/TypeSummary.h" #include "lldb/DataFormatters/VectorIterator.h" -#include "lldb/Symbol/TypeSystemClang.h" #include "lldb/Target/ProcessStructReader.h" #include "lldb/Target/SectionLoadList.h" #include "lldb/Target/Target.h" @@ -26,6 +25,7 @@ #include "lldb/Utility/Stream.h" #include "Plugins/LanguageRuntime/CPlusPlus/CPPLanguageRuntime.h" +#include "Plugins/TypeSystem/Clang/TypeSystemClang.h" using namespace lldb; using namespace lldb_private; @@ -144,6 +144,43 @@ bool lldb_private::formatters::LibcxxSmartPointerSummaryProvider( return true; } +bool lldb_private::formatters::LibcxxUniquePointerSummaryProvider( + ValueObject &valobj, Stream &stream, const TypeSummaryOptions &options) { + ValueObjectSP valobj_sp(valobj.GetNonSyntheticValue()); + if (!valobj_sp) + return false; + + ValueObjectSP ptr_sp( + valobj_sp->GetChildMemberWithName(ConstString("__ptr_"), true)); + if (!ptr_sp) + return false; + + ptr_sp = GetValueOfLibCXXCompressedPair(*ptr_sp); + if (!ptr_sp) + return false; + + if (ptr_sp->GetValueAsUnsigned(0) == 0) { + stream.Printf("nullptr"); + return true; + } else { + bool print_pointee = false; + Status error; + ValueObjectSP pointee_sp = ptr_sp->Dereference(error); + if (pointee_sp && error.Success()) { + if (pointee_sp->DumpPrintableRepresentation( + stream, ValueObject::eValueObjectRepresentationStyleSummary, + lldb::eFormatInvalid, + ValueObject::PrintableRepresentationSpecialCases::eDisable, + false)) + print_pointee = true; + } + if (!print_pointee) + stream.Printf("ptr = 0x%" PRIx64, ptr_sp->GetValueAsUnsigned(0)); + } + + return true; +} + /* (lldb) fr var ibeg --raw --ptr-depth 1 (std::__1::__map_iteratorGetChildMemberWithName(ConstString("__ptr_"), true)); + if (!ptr_sp) + return false; + + m_compressed_pair_sp = GetValueOfLibCXXCompressedPair(*ptr_sp); + + return false; +} + +bool lldb_private::formatters::LibcxxUniquePtrSyntheticFrontEnd:: + MightHaveChildren() { + return true; +} + +size_t lldb_private::formatters::LibcxxUniquePtrSyntheticFrontEnd:: + GetIndexOfChildWithName(ConstString name) { + if (name == "__value_") + return 0; + return UINT32_MAX; +} + bool lldb_private::formatters::LibcxxContainerSummaryProvider( ValueObject &valobj, Stream &stream, const TypeSummaryOptions &options) { if (valobj.IsPointerType()) { diff --git a/lldb/source/Plugins/Language/CPlusPlus/LibCxx.h b/lldb/source/Plugins/Language/CPlusPlus/LibCxx.h index 214f5512e4a50..a3e41a44432a3 100644 --- a/lldb/source/Plugins/Language/CPlusPlus/LibCxx.h +++ b/lldb/source/Plugins/Language/CPlusPlus/LibCxx.h @@ -43,6 +43,10 @@ bool LibcxxSmartPointerSummaryProvider( const TypeSummaryOptions &options); // libc++ std::shared_ptr<> and std::weak_ptr<> +// libc++ std::unique_ptr<> +bool LibcxxUniquePointerSummaryProvider(ValueObject &valobj, Stream &stream, + const TypeSummaryOptions &options); + bool LibcxxFunctionSummaryProvider( ValueObject &valobj, Stream &stream, const TypeSummaryOptions &options); // libc++ std::function<> @@ -107,6 +111,26 @@ class LibcxxSharedPtrSyntheticFrontEnd : public SyntheticChildrenFrontEnd { lldb::ByteOrder m_byte_order; }; +class LibcxxUniquePtrSyntheticFrontEnd : public SyntheticChildrenFrontEnd { +public: + LibcxxUniquePtrSyntheticFrontEnd(lldb::ValueObjectSP valobj_sp); + + size_t CalculateNumChildren() override; + + lldb::ValueObjectSP GetChildAtIndex(size_t idx) override; + + bool Update() override; + + bool MightHaveChildren() override; + + size_t GetIndexOfChildWithName(ConstString name) override; + + ~LibcxxUniquePtrSyntheticFrontEnd() override; + +private: + lldb::ValueObjectSP m_compressed_pair_sp; +}; + SyntheticChildrenFrontEnd * LibcxxBitsetSyntheticFrontEndCreator(CXXSyntheticChildren *, lldb::ValueObjectSP); @@ -115,6 +139,10 @@ SyntheticChildrenFrontEnd * LibcxxSharedPtrSyntheticFrontEndCreator(CXXSyntheticChildren *, lldb::ValueObjectSP); +SyntheticChildrenFrontEnd * +LibcxxUniquePtrSyntheticFrontEndCreator(CXXSyntheticChildren *, + lldb::ValueObjectSP); + SyntheticChildrenFrontEnd * LibcxxStdVectorSyntheticFrontEndCreator(CXXSyntheticChildren *, lldb::ValueObjectSP); diff --git a/lldb/source/Plugins/Language/CPlusPlus/LibCxxBitset.cpp b/lldb/source/Plugins/Language/CPlusPlus/LibCxxBitset.cpp index 6f18e3501ad97..381a13584fac6 100644 --- a/lldb/source/Plugins/Language/CPlusPlus/LibCxxBitset.cpp +++ b/lldb/source/Plugins/Language/CPlusPlus/LibCxxBitset.cpp @@ -7,8 +7,8 @@ //===----------------------------------------------------------------------===// #include "LibCxx.h" +#include "Plugins/TypeSystem/Clang/TypeSystemClang.h" #include "lldb/DataFormatters/FormattersHelpers.h" -#include "lldb/Symbol/TypeSystemClang.h" #include "lldb/Target/Target.h" using namespace lldb; diff --git a/lldb/source/Plugins/Language/CPlusPlus/LibCxxList.cpp b/lldb/source/Plugins/Language/CPlusPlus/LibCxxList.cpp index 97eb2a24a2f1d..746f842f5e417 100644 --- a/lldb/source/Plugins/Language/CPlusPlus/LibCxxList.cpp +++ b/lldb/source/Plugins/Language/CPlusPlus/LibCxxList.cpp @@ -8,10 +8,10 @@ #include "LibCxx.h" +#include "Plugins/TypeSystem/Clang/TypeSystemClang.h" #include "lldb/Core/ValueObject.h" #include "lldb/Core/ValueObjectConstResult.h" #include "lldb/DataFormatters/FormattersHelpers.h" -#include "lldb/Symbol/TypeSystemClang.h" #include "lldb/Target/Target.h" #include "lldb/Utility/DataBufferHeap.h" #include "lldb/Utility/Endian.h" @@ -290,15 +290,6 @@ ValueObjectSP ForwardListFrontEnd::GetChildAtIndex(size_t idx) { m_element_type); } -static ValueObjectSP GetValueOfCompressedPair(ValueObject &pair) { - ValueObjectSP value = pair.GetChildMemberWithName(ConstString("__value_"), true); - if (! value) { - // pre-r300140 member name - value = pair.GetChildMemberWithName(ConstString("__first_"), true); - } - return value; -} - bool ForwardListFrontEnd::Update() { AbstractListFrontEnd::Update(); @@ -311,7 +302,7 @@ bool ForwardListFrontEnd::Update() { m_backend.GetChildMemberWithName(ConstString("__before_begin_"), true)); if (!impl_sp) return false; - impl_sp = GetValueOfCompressedPair(*impl_sp); + impl_sp = GetValueOfLibCXXCompressedPair(*impl_sp); if (!impl_sp) return false; m_head = impl_sp->GetChildMemberWithName(ConstString("__next_"), true).get(); @@ -332,7 +323,7 @@ size_t ListFrontEnd::CalculateNumChildren() { ValueObjectSP size_alloc( m_backend.GetChildMemberWithName(ConstString("__size_alloc_"), true)); if (size_alloc) { - ValueObjectSP value = GetValueOfCompressedPair(*size_alloc); + ValueObjectSP value = GetValueOfLibCXXCompressedPair(*size_alloc); if (value) { m_count = value->GetValueAsUnsigned(UINT32_MAX); } diff --git a/lldb/source/Plugins/Language/CPlusPlus/LibCxxMap.cpp b/lldb/source/Plugins/Language/CPlusPlus/LibCxxMap.cpp index 9cfc70ebbcae0..ab3a9752ecee5 100644 --- a/lldb/source/Plugins/Language/CPlusPlus/LibCxxMap.cpp +++ b/lldb/source/Plugins/Language/CPlusPlus/LibCxxMap.cpp @@ -8,10 +8,10 @@ #include "LibCxx.h" +#include "Plugins/TypeSystem/Clang/TypeSystemClang.h" #include "lldb/Core/ValueObject.h" #include "lldb/Core/ValueObjectConstResult.h" #include "lldb/DataFormatters/FormattersHelpers.h" -#include "lldb/Symbol/TypeSystemClang.h" #include "lldb/Target/Target.h" #include "lldb/Utility/DataBufferHeap.h" #include "lldb/Utility/Endian.h" diff --git a/lldb/source/Plugins/Language/CPlusPlus/LibCxxUnorderedMap.cpp b/lldb/source/Plugins/Language/CPlusPlus/LibCxxUnorderedMap.cpp index 63214de7b5578..aa38591daf996 100644 --- a/lldb/source/Plugins/Language/CPlusPlus/LibCxxUnorderedMap.cpp +++ b/lldb/source/Plugins/Language/CPlusPlus/LibCxxUnorderedMap.cpp @@ -8,10 +8,10 @@ #include "LibCxx.h" +#include "Plugins/TypeSystem/Clang/TypeSystemClang.h" #include "lldb/Core/ValueObject.h" #include "lldb/Core/ValueObjectConstResult.h" #include "lldb/DataFormatters/FormattersHelpers.h" -#include "lldb/Symbol/TypeSystemClang.h" #include "lldb/Target/Target.h" #include "lldb/Utility/DataBufferHeap.h" #include "lldb/Utility/Endian.h" diff --git a/lldb/source/Plugins/Language/CPlusPlus/LibCxxVariant.cpp b/lldb/source/Plugins/Language/CPlusPlus/LibCxxVariant.cpp index 62945bd3ce80b..1b33ecf958b54 100644 --- a/lldb/source/Plugins/Language/CPlusPlus/LibCxxVariant.cpp +++ b/lldb/source/Plugins/Language/CPlusPlus/LibCxxVariant.cpp @@ -159,7 +159,7 @@ bool LibcxxVariantSummaryProvider(ValueObject &valobj, Stream &stream, if (!template_type) return false; - stream.Printf(" Active Type = %s ", template_type.GetTypeName().GetCString()); + stream << " Active Type = " << template_type.GetDisplayTypeName() << " "; return true; } diff --git a/lldb/source/Plugins/Language/CPlusPlus/LibStdcpp.cpp b/lldb/source/Plugins/Language/CPlusPlus/LibStdcpp.cpp index 7db201822c8bd..0900a7b7032e3 100644 --- a/lldb/source/Plugins/Language/CPlusPlus/LibStdcpp.cpp +++ b/lldb/source/Plugins/Language/CPlusPlus/LibStdcpp.cpp @@ -8,11 +8,11 @@ #include "LibStdcpp.h" +#include "Plugins/TypeSystem/Clang/TypeSystemClang.h" #include "lldb/Core/ValueObject.h" #include "lldb/Core/ValueObjectConstResult.h" #include "lldb/DataFormatters/StringPrinter.h" #include "lldb/DataFormatters/VectorIterator.h" -#include "lldb/Symbol/TypeSystemClang.h" #include "lldb/Target/Target.h" #include "lldb/Utility/DataBufferHeap.h" #include "lldb/Utility/Endian.h" @@ -259,6 +259,7 @@ bool lldb_private::formatters::LibStdcppStringSummaryProvider( if (error.Fail()) return false; options.SetSourceSize(size_of_data); + options.SetHasSourceSize(true); if (!StringPrinter::ReadStringAndDumpToStream< StringPrinter::StringElementType::UTF8>(options)) { @@ -319,6 +320,7 @@ bool lldb_private::formatters::LibStdcppWStringSummaryProvider( if (error.Fail()) return false; options.SetSourceSize(size_of_data); + options.SetHasSourceSize(true); options.SetPrefixToken("L"); switch (wchar_size) { diff --git a/lldb/source/Plugins/Language/ObjC/CF.cpp b/lldb/source/Plugins/Language/ObjC/CF.cpp index bfda06e376e2e..68ae0ece58f84 100644 --- a/lldb/source/Plugins/Language/ObjC/CF.cpp +++ b/lldb/source/Plugins/Language/ObjC/CF.cpp @@ -9,10 +9,10 @@ #include "CF.h" +#include "Plugins/TypeSystem/Clang/TypeSystemClang.h" #include "lldb/Core/ValueObject.h" #include "lldb/Core/ValueObjectConstResult.h" #include "lldb/DataFormatters/FormattersHelpers.h" -#include "lldb/Symbol/TypeSystemClang.h" #include "lldb/Target/Language.h" #include "lldb/Target/StackFrame.h" #include "lldb/Target/Target.h" diff --git a/lldb/source/Plugins/Language/ObjC/CMakeLists.txt b/lldb/source/Plugins/Language/ObjC/CMakeLists.txt index a9dad64e73c73..b1eb06fee0691 100644 --- a/lldb/source/Plugins/Language/ObjC/CMakeLists.txt +++ b/lldb/source/Plugins/Language/ObjC/CMakeLists.txt @@ -31,6 +31,7 @@ add_lldb_library(lldbPluginObjCLanguage PLUGIN lldbUtility lldbPluginAppleObjCRuntime lldbPluginClangCommon + lldbPluginTypeSystemClang lldbPluginSwiftLanguage CLANG_LIBS clangAST diff --git a/lldb/source/Plugins/Language/ObjC/Cocoa.cpp b/lldb/source/Plugins/Language/ObjC/Cocoa.cpp index 3b53372f2b883..00df3303e45af 100644 --- a/lldb/source/Plugins/Language/ObjC/Cocoa.cpp +++ b/lldb/source/Plugins/Language/ObjC/Cocoa.cpp @@ -8,6 +8,7 @@ #include "Cocoa.h" +#include "Plugins/TypeSystem/Clang/TypeSystemClang.h" #include "lldb/Core/Mangled.h" #include "lldb/Core/ValueObject.h" #include "lldb/Core/ValueObjectConstResult.h" @@ -15,7 +16,6 @@ #include "lldb/DataFormatters/StringPrinter.h" #include "lldb/DataFormatters/TypeSummary.h" #include "lldb/Host/Time.h" -#include "lldb/Symbol/TypeSystemClang.h" #include "lldb/Target/Language.h" #include "lldb/Target/Process.h" #include "lldb/Target/ProcessStructReader.h" diff --git a/lldb/source/Plugins/Language/ObjC/NSArray.cpp b/lldb/source/Plugins/Language/ObjC/NSArray.cpp index f1095b89b92d2..d0a9fed1a2d14 100644 --- a/lldb/source/Plugins/Language/ObjC/NSArray.cpp +++ b/lldb/source/Plugins/Language/ObjC/NSArray.cpp @@ -11,12 +11,12 @@ #include "Cocoa.h" #include "Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntime.h" +#include "Plugins/TypeSystem/Clang/TypeSystemClang.h" #include "lldb/Core/ValueObject.h" #include "lldb/Core/ValueObjectConstResult.h" #include "lldb/DataFormatters/FormattersHelpers.h" #include "lldb/Expression/FunctionCaller.h" -#include "lldb/Symbol/TypeSystemClang.h" #include "lldb/Target/Language.h" #include "lldb/Target/Target.h" #include "lldb/Utility/DataBufferHeap.h" diff --git a/lldb/source/Plugins/Language/ObjC/NSDictionary.cpp b/lldb/source/Plugins/Language/ObjC/NSDictionary.cpp index 77612dfb2c3e7..8c26ba2a9297d 100644 --- a/lldb/source/Plugins/Language/ObjC/NSDictionary.cpp +++ b/lldb/source/Plugins/Language/ObjC/NSDictionary.cpp @@ -13,11 +13,11 @@ #include "NSDictionary.h" #include "Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntime.h" +#include "Plugins/TypeSystem/Clang/TypeSystemClang.h" #include "lldb/Core/ValueObject.h" #include "lldb/Core/ValueObjectConstResult.h" #include "lldb/DataFormatters/FormattersHelpers.h" -#include "lldb/Symbol/TypeSystemClang.h" #include "lldb/Target/Language.h" #include "lldb/Target/StackFrame.h" #include "lldb/Target/Target.h" diff --git a/lldb/source/Plugins/Language/ObjC/NSError.cpp b/lldb/source/Plugins/Language/ObjC/NSError.cpp index 3cd784afcdc63..ad2f9bd80a2e3 100644 --- a/lldb/source/Plugins/Language/ObjC/NSError.cpp +++ b/lldb/source/Plugins/Language/ObjC/NSError.cpp @@ -10,10 +10,10 @@ #include "Cocoa.h" +#include "Plugins/TypeSystem/Clang/TypeSystemClang.h" #include "lldb/Core/ValueObject.h" #include "lldb/Core/ValueObjectConstResult.h" #include "lldb/DataFormatters/FormattersHelpers.h" -#include "lldb/Symbol/TypeSystemClang.h" #include "lldb/Target/ProcessStructReader.h" #include "lldb/Target/Target.h" #include "lldb/Utility/DataBufferHeap.h" diff --git a/lldb/source/Plugins/Language/ObjC/NSException.cpp b/lldb/source/Plugins/Language/ObjC/NSException.cpp index 31a17ddd10d98..a001ab8673339 100644 --- a/lldb/source/Plugins/Language/ObjC/NSException.cpp +++ b/lldb/source/Plugins/Language/ObjC/NSException.cpp @@ -13,7 +13,6 @@ #include "lldb/Core/ValueObject.h" #include "lldb/Core/ValueObjectConstResult.h" #include "lldb/DataFormatters/FormattersHelpers.h" -#include "lldb/Symbol/TypeSystemClang.h" #include "lldb/Target/ProcessStructReader.h" #include "lldb/Target/Target.h" #include "lldb/Utility/DataBufferHeap.h" @@ -23,6 +22,7 @@ #include "Plugins/Language/ObjC/NSString.h" #include "Plugins/LanguageRuntime/ObjC/ObjCLanguageRuntime.h" +#include "Plugins/TypeSystem/Clang/TypeSystemClang.h" using namespace lldb; using namespace lldb_private; diff --git a/lldb/source/Plugins/Language/ObjC/NSIndexPath.cpp b/lldb/source/Plugins/Language/ObjC/NSIndexPath.cpp index 81cfb9b0ddfd8..50d539fa2952e 100644 --- a/lldb/source/Plugins/Language/ObjC/NSIndexPath.cpp +++ b/lldb/source/Plugins/Language/ObjC/NSIndexPath.cpp @@ -8,11 +8,11 @@ #include "Cocoa.h" +#include "Plugins/TypeSystem/Clang/TypeSystemClang.h" #include "lldb/Core/ValueObject.h" #include "lldb/Core/ValueObjectConstResult.h" #include "lldb/DataFormatters/FormattersHelpers.h" #include "lldb/DataFormatters/TypeSynthetic.h" -#include "lldb/Symbol/TypeSystemClang.h" #include "lldb/Target/Process.h" #include "lldb/Target/Target.h" diff --git a/lldb/source/Plugins/Language/ObjC/NSSet.cpp b/lldb/source/Plugins/Language/ObjC/NSSet.cpp index 380a99d56d99b..cc0db24ab2df9 100644 --- a/lldb/source/Plugins/Language/ObjC/NSSet.cpp +++ b/lldb/source/Plugins/Language/ObjC/NSSet.cpp @@ -9,10 +9,10 @@ #include "NSSet.h" #include "Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntime.h" +#include "Plugins/TypeSystem/Clang/TypeSystemClang.h" #include "lldb/Core/ValueObject.h" #include "lldb/Core/ValueObjectConstResult.h" #include "lldb/DataFormatters/FormattersHelpers.h" -#include "lldb/Symbol/TypeSystemClang.h" #include "lldb/Target/Language.h" #include "lldb/Target/Target.h" #include "lldb/Utility/DataBufferHeap.h" diff --git a/lldb/source/Plugins/Language/ObjC/NSString.cpp b/lldb/source/Plugins/Language/ObjC/NSString.cpp index bfbc8cd847980..04088747a3afd 100644 --- a/lldb/source/Plugins/Language/ObjC/NSString.cpp +++ b/lldb/source/Plugins/Language/ObjC/NSString.cpp @@ -9,11 +9,11 @@ #include "NSString.h" +#include "Plugins/TypeSystem/Clang/TypeSystemClang.h" #include "lldb/Core/ValueObject.h" #include "lldb/Core/ValueObjectConstResult.h" #include "lldb/DataFormatters/FormattersHelpers.h" #include "lldb/DataFormatters/StringPrinter.h" -#include "lldb/Symbol/TypeSystemClang.h" #include "lldb/Target/Language.h" #include "lldb/Target/ProcessStructReader.h" #include "lldb/Target/Target.h" @@ -171,6 +171,7 @@ bool lldb_private::formatters::NSStringSummaryProvider( options.SetStream(&stream); options.SetQuote('"'); options.SetSourceSize(explicit_length); + options.SetHasSourceSize(has_explicit_length); options.SetNeedsZeroTermination(false); options.SetIgnoreMaxLength(summary_options.GetCapping() == TypeSummaryCapping::eTypeSummaryUncapped); @@ -183,6 +184,7 @@ bool lldb_private::formatters::NSStringSummaryProvider( options.SetProcessSP(process_sp); options.SetStream(&stream); options.SetSourceSize(explicit_length); + options.SetHasSourceSize(has_explicit_length); options.SetNeedsZeroTermination(false); options.SetIgnoreMaxLength(summary_options.GetCapping() == TypeSummaryCapping::eTypeSummaryUncapped); @@ -200,6 +202,7 @@ bool lldb_private::formatters::NSStringSummaryProvider( options.SetStream(&stream); options.SetQuote('"'); options.SetSourceSize(explicit_length); + options.SetHasSourceSize(has_explicit_length); options.SetIgnoreMaxLength(summary_options.GetCapping() == TypeSummaryCapping::eTypeSummaryUncapped); options.SetLanguage(summary_options.GetLanguage()); @@ -222,6 +225,7 @@ bool lldb_private::formatters::NSStringSummaryProvider( options.SetStream(&stream); options.SetQuote('"'); options.SetSourceSize(explicit_length); + options.SetHasSourceSize(has_explicit_length); options.SetNeedsZeroTermination(!has_explicit_length); options.SetIgnoreMaxLength(summary_options.GetCapping() == TypeSummaryCapping::eTypeSummaryUncapped); @@ -242,6 +246,7 @@ bool lldb_private::formatters::NSStringSummaryProvider( options.SetStream(&stream); options.SetQuote('"'); options.SetSourceSize(explicit_length); + options.SetHasSourceSize(has_explicit_length); options.SetNeedsZeroTermination(!has_explicit_length); options.SetIgnoreMaxLength(summary_options.GetCapping() == TypeSummaryCapping::eTypeSummaryUncapped); @@ -264,6 +269,7 @@ bool lldb_private::formatters::NSStringSummaryProvider( options.SetProcessSP(process_sp); options.SetStream(&stream); options.SetSourceSize(explicit_length); + options.SetHasSourceSize(has_explicit_length); options.SetNeedsZeroTermination(!has_explicit_length); options.SetIgnoreMaxLength(summary_options.GetCapping() == TypeSummaryCapping::eTypeSummaryUncapped); @@ -287,6 +293,7 @@ bool lldb_private::formatters::NSStringSummaryProvider( options.SetProcessSP(process_sp); options.SetStream(&stream); options.SetSourceSize(explicit_length); + options.SetHasSourceSize(has_explicit_length); options.SetIgnoreMaxLength(summary_options.GetCapping() == TypeSummaryCapping::eTypeSummaryUncapped); options.SetLanguage(summary_options.GetLanguage()); diff --git a/lldb/source/Plugins/Language/ObjC/ObjCLanguage.cpp b/lldb/source/Plugins/Language/ObjC/ObjCLanguage.cpp index df09376e1fba6..68c2d6d4b6431 100644 --- a/lldb/source/Plugins/Language/ObjC/ObjCLanguage.cpp +++ b/lldb/source/Plugins/Language/ObjC/ObjCLanguage.cpp @@ -10,12 +10,12 @@ #include "ObjCLanguage.h" +#include "Plugins/ExpressionParser/Clang/ClangUtil.h" +#include "Plugins/TypeSystem/Clang/TypeSystemClang.h" #include "lldb/Core/PluginManager.h" #include "lldb/Core/ValueObject.h" #include "lldb/DataFormatters/DataVisualization.h" #include "lldb/DataFormatters/FormattersHelpers.h" -#include "lldb/Symbol/TypeSystemClang.h" -#include "lldb/Symbol/ClangUtil.h" #include "lldb/Symbol/CompilerType.h" #include "lldb/Target/Target.h" #include "lldb/Utility/ConstString.h" diff --git a/lldb/source/Plugins/Language/Swift/FoundationValueTypes.cpp b/lldb/source/Plugins/Language/Swift/FoundationValueTypes.cpp index acb3b9c2aa4c7..177876ea28b72 100644 --- a/lldb/source/Plugins/Language/Swift/FoundationValueTypes.cpp +++ b/lldb/source/Plugins/Language/Swift/FoundationValueTypes.cpp @@ -16,9 +16,9 @@ #include "llvm/ADT/STLExtras.h" #include "Plugins/LanguageRuntime/ObjC/ObjCLanguageRuntime.h" +#include "Plugins/TypeSystem/Clang/TypeSystemClang.h" #include "lldb/Core/ValueObject.h" #include "lldb/DataFormatters/FormattersHelpers.h" -#include "lldb/Symbol/TypeSystemClang.h" #include "lldb/Target/Process.h" #include "lldb/Target/SwiftLanguageRuntime.h" #include "lldb/Target/Target.h" @@ -159,8 +159,11 @@ bool lldb_private::formatters::swift::Measurement_SummaryProvider( if (!process_sp) return false; - auto descriptor_sp( - ObjCLanguageRuntime::Get(*process_sp)->GetClassDescriptor(*unit_sp)); + ObjCLanguageRuntime *objc_runtime = ObjCLanguageRuntime::Get(*process_sp); + if (!objc_runtime) + return false; + + auto descriptor_sp(objc_runtime->GetClassDescriptor(*unit_sp)); if (!descriptor_sp) return false; diff --git a/lldb/source/Plugins/Language/Swift/ObjCRuntimeSyntheticProvider.cpp b/lldb/source/Plugins/Language/Swift/ObjCRuntimeSyntheticProvider.cpp index bbd6ef7a13069..9384db20ccd5c 100644 --- a/lldb/source/Plugins/Language/Swift/ObjCRuntimeSyntheticProvider.cpp +++ b/lldb/source/Plugins/Language/Swift/ObjCRuntimeSyntheticProvider.cpp @@ -11,7 +11,7 @@ //===----------------------------------------------------------------------===// #include "ObjCRuntimeSyntheticProvider.h" -#include "lldb/Symbol/TypeSystemClang.h" +#include "Plugins/TypeSystem/Clang/TypeSystemClang.h" #include "lldb/Symbol/DeclVendor.h" #include "lldb/lldb-public.h" diff --git a/lldb/source/Plugins/Language/Swift/SwiftArray.cpp b/lldb/source/Plugins/Language/Swift/SwiftArray.cpp index 6d68423fc80f4..f1932ef207fac 100644 --- a/lldb/source/Plugins/Language/Swift/SwiftArray.cpp +++ b/lldb/source/Plugins/Language/Swift/SwiftArray.cpp @@ -12,9 +12,9 @@ #include "SwiftArray.h" +#include "Plugins/TypeSystem/Clang/TypeSystemClang.h" #include "lldb/Core/ValueObjectConstResult.h" #include "lldb/DataFormatters/FormattersHelpers.h" -#include "lldb/Symbol/TypeSystemClang.h" #include "lldb/Symbol/SwiftASTContext.h" #include "lldb/Target/Process.h" #include "lldb/Target/SwiftLanguageRuntime.h" diff --git a/lldb/source/Plugins/Language/Swift/SwiftDictionary.cpp b/lldb/source/Plugins/Language/Swift/SwiftDictionary.cpp index c777cfb07e74a..4ba3e8f4713a9 100644 --- a/lldb/source/Plugins/Language/Swift/SwiftDictionary.cpp +++ b/lldb/source/Plugins/Language/Swift/SwiftDictionary.cpp @@ -13,7 +13,7 @@ #include "SwiftDictionary.h" #include "lldb/DataFormatters/FormattersHelpers.h" -#include "lldb/Symbol/TypeSystemClang.h" +#include "Plugins/TypeSystem/Clang/TypeSystemClang.h" #include "lldb/Symbol/SwiftASTContext.h" #include "lldb/Target/Process.h" #include "lldb/Target/SwiftLanguageRuntime.h" diff --git a/lldb/source/Plugins/Language/Swift/SwiftFormatters.cpp b/lldb/source/Plugins/Language/Swift/SwiftFormatters.cpp index 9457317e91348..96a35ea6cf935 100644 --- a/lldb/source/Plugins/Language/Swift/SwiftFormatters.cpp +++ b/lldb/source/Plugins/Language/Swift/SwiftFormatters.cpp @@ -11,9 +11,9 @@ //===----------------------------------------------------------------------===// #include "SwiftFormatters.h" +#include "Plugins/TypeSystem/Clang/TypeSystemClang.h" #include "lldb/DataFormatters/FormattersHelpers.h" #include "lldb/DataFormatters/StringPrinter.h" -#include "lldb/Symbol/TypeSystemClang.h" #include "lldb/Target/Process.h" #include "lldb/Target/SwiftLanguageRuntime.h" #include "lldb/Utility/DataBufferHeap.h" @@ -81,6 +81,7 @@ static bool readStringFromAddress( read_options.SetProcessSP(process); read_options.SetStream(&stream); read_options.SetSourceSize(length); + read_options.SetHasSourceSize(true); read_options.SetNeedsZeroTermination(false); read_options.SetIgnoreMaxLength(summary_options.GetCapping() == lldb::eTypeSummaryUncapped); @@ -176,7 +177,7 @@ bool lldb_private::formatters::swift::StringGuts_SummaryProvider( return false; payload_sp = anyobject_sp->GetChildAtIndex(0, true); // "instance" } else { - lldbassert(false && "Uknown variant"); + // Unknown variant. return false; } if (!payload_sp) @@ -194,7 +195,7 @@ bool lldb_private::formatters::swift::StringGuts_SummaryProvider( raw1 = pointerBits | (discriminator << 56); } } else { - lldbassert(false && "Unsupported arch?"); + lldbassert(false && "Unsupported pointer bit-width"); return false; } @@ -291,8 +292,9 @@ bool lldb_private::formatters::swift::StringGuts_SummaryProvider( uint16_t flags = raw0 >> 48; lldb::addr_t objectAddress = (raw1 & 0x0FFFFFFFFFFFFFFF); if ((flags & 0x1000) != 0) { // Tail-allocated / biased address - lldbassert((discriminator & 0x70) == 0 && - "tail-allocation is only for natively stored or literals"); + // Tail-allocation is only for natively stored or literals. + if ((discriminator & 0x70) != 0) + return false; uint64_t bias = (ptrSize == 8 ? 32 : 20); auto address = objectAddress + bias; return readStringFromAddress( @@ -301,7 +303,9 @@ bool lldb_private::formatters::swift::StringGuts_SummaryProvider( if ((discriminator & 0xF0) == 0x00) { // Shared string // FIXME: Verify that there is a __SharedStringStorage instance at `address`. - lldbassert((flags & 0x3000) == 0); + // Shared strings must not be tail-allocated or natively stored. + if ((flags & 0x3000) != 0) + return false; uint64_t startOffset = (ptrSize == 8 ? 24 : 12); auto address = objectAddress + startOffset; lldb::addr_t start = process->ReadPointerFromMemory(address, error); @@ -312,8 +316,9 @@ bool lldb_private::formatters::swift::StringGuts_SummaryProvider( start, count, process, stream, summary_options, read_options); } - lldbassert((discriminator & 0x70) != 0 && - "native/shared strings already handled"); + // Native/shared strings should already have been handled. + if ((discriminator & 0x70) == 0) + return false; if ((discriminator & 0xE0) == 0x40) { // 010xxxxx: Bridged TypeSystemClang *clang_ast_context = @@ -335,13 +340,12 @@ bool lldb_private::formatters::swift::StringGuts_SummaryProvider( } if ((discriminator & 0xF8) == 0x18) { // 0001xxxx: Foreign - // Not currently generated - lldbassert( - false && "Foreign non-bridged strings are not currently used in Swift"); + // Not currently generated: Foreign non-bridged strings are not currently + // used in Swift. return false; } - lldbassert(false && "Invalid discriminator"); + // Invalid discriminator. return false; } @@ -413,6 +417,7 @@ bool lldb_private::formatters::swift::StaticString_SummaryProvider( read_options.SetProcessSP(process_sp); read_options.SetLocation(start_ptr); read_options.SetSourceSize(size); + read_options.SetHasSourceSize(true); read_options.SetBinaryZeroIsTerminator(false); read_options.SetNeedsZeroTermination(false); read_options.SetStream(&stream); diff --git a/lldb/source/Plugins/Language/Swift/SwiftHashedContainer.cpp b/lldb/source/Plugins/Language/Swift/SwiftHashedContainer.cpp index e5ffb10fc5b0c..1b986941fbc96 100644 --- a/lldb/source/Plugins/Language/Swift/SwiftHashedContainer.cpp +++ b/lldb/source/Plugins/Language/Swift/SwiftHashedContainer.cpp @@ -13,9 +13,9 @@ #include "SwiftHashedContainer.h" #include "Plugins/LanguageRuntime/ObjC/ObjCLanguageRuntime.h" +#include "Plugins/TypeSystem/Clang/TypeSystemClang.h" #include "lldb/Core/ValueObjectConstResult.h" #include "lldb/DataFormatters/FormattersHelpers.h" -#include "lldb/Symbol/TypeSystemClang.h" #include "lldb/Symbol/SwiftASTContext.h" #include "lldb/Target/Process.h" #include "lldb/Target/SwiftLanguageRuntime.h" @@ -530,7 +530,7 @@ bool NativeHashedStorageHandler::IsValid() { && (m_keys_ptr != LLDB_INVALID_ADDRESS) && (m_value_stride == 0 || m_values_ptr != LLDB_INVALID_ADDRESS) // Check counts. - && (m_count <= GetBucketCount()) + && ((m_scale < (sizeof(size_t) * 8)) && (m_count <= GetBucketCount())) // Buffers are tail-allocated in this order: metadata, keys, values && (m_metadata_ptr < m_keys_ptr) && (m_value_stride == 0 || m_keys_ptr < m_values_ptr); @@ -569,13 +569,15 @@ NativeHashedStorageHandler::UpdateBuckets() { size_t wordCount = GetWordCount(); for (size_t wordIndex = 0; wordIndex < wordCount; wordIndex++) { Status error; - auto word = GetMetadataWord(wordIndex, error); + uint64_t word = GetMetadataWord(wordIndex, error); if (error.Fail()) { return FailBuckets(); } if (wordCount == 1) { // Mask off out-of-bounds bits from first partial word. - word &= (1ULL << bucketCount) - 1; + if (bucketCount > (sizeof(uint64_t) * 8)) + return FailBuckets(); + word &= llvm::maskTrailingOnes(bucketCount); } for (size_t bit = 0; bit < wordWidth; bit++) { if ((word & (1ULL << bit)) != 0) { diff --git a/lldb/source/Plugins/Language/Swift/SwiftLanguage.cpp b/lldb/source/Plugins/Language/Swift/SwiftLanguage.cpp index 5400f61fe26e7..369d2339b0e69 100644 --- a/lldb/source/Plugins/Language/Swift/SwiftLanguage.cpp +++ b/lldb/source/Plugins/Language/Swift/SwiftLanguage.cpp @@ -21,7 +21,7 @@ #include "lldb/DataFormatters/FormattersHelpers.h" #include "lldb/DataFormatters/StringPrinter.h" -#include "lldb/Symbol/TypeSystemClang.h" +#include "Plugins/TypeSystem/Clang/TypeSystemClang.h" #include "lldb/Symbol/CompileUnit.h" #include "lldb/Symbol/Function.h" #include "lldb/Symbol/Variable.h" diff --git a/lldb/source/Plugins/Language/Swift/SwiftMetatype.cpp b/lldb/source/Plugins/Language/Swift/SwiftMetatype.cpp index 6c8e68c61efcc..f1ade30a41ce3 100644 --- a/lldb/source/Plugins/Language/Swift/SwiftMetatype.cpp +++ b/lldb/source/Plugins/Language/Swift/SwiftMetatype.cpp @@ -43,6 +43,8 @@ bool lldb_private::formatters::swift::SwiftMetatype_SummaryProvider( return false; SwiftLanguageRuntime::MetadataPromiseSP metadata_promise_sp = swift_runtime->GetMetadataPromise(metadata_ptr, valobj); + if (!metadata_promise_sp) + return false; if (CompilerType resolved_type = metadata_promise_sp->FulfillTypePromise()) { stream.Printf("%s", resolved_type.GetDisplayTypeName().AsCString()); diff --git a/lldb/source/Plugins/Language/Swift/SwiftOptionSet.cpp b/lldb/source/Plugins/Language/Swift/SwiftOptionSet.cpp index 4d4ab69f1ba83..f9826d537c55f 100644 --- a/lldb/source/Plugins/Language/Swift/SwiftOptionSet.cpp +++ b/lldb/source/Plugins/Language/Swift/SwiftOptionSet.cpp @@ -12,11 +12,11 @@ #include "SwiftOptionSet.h" -#include "lldb/Utility/StreamString.h" +#include "Plugins/TypeSystem/Clang/TypeSystemClang.h" #include "lldb/Core/ValueObject.h" -#include "lldb/Symbol/TypeSystemClang.h" #include "lldb/Symbol/CompilerType.h" #include "lldb/Symbol/SwiftASTContext.h" +#include "lldb/Utility/StreamString.h" #include "swift/AST/Decl.h" #include "swift/ClangImporter/ClangImporter.h" diff --git a/lldb/source/Plugins/Language/Swift/SwiftSet.cpp b/lldb/source/Plugins/Language/Swift/SwiftSet.cpp index eced04bc35443..fdc4625808ec4 100644 --- a/lldb/source/Plugins/Language/Swift/SwiftSet.cpp +++ b/lldb/source/Plugins/Language/Swift/SwiftSet.cpp @@ -13,7 +13,7 @@ #include "SwiftSet.h" #include "lldb/DataFormatters/FormattersHelpers.h" -#include "lldb/Symbol/TypeSystemClang.h" +#include "Plugins/TypeSystem/Clang/TypeSystemClang.h" #include "lldb/Symbol/SwiftASTContext.h" #include "lldb/Target/Process.h" #include "lldb/Target/SwiftLanguageRuntime.h" diff --git a/lldb/source/Plugins/LanguageRuntime/CPlusPlus/CMakeLists.txt b/lldb/source/Plugins/LanguageRuntime/CPlusPlus/CMakeLists.txt index 508a361aa6ddf..0260212266fbd 100644 --- a/lldb/source/Plugins/LanguageRuntime/CPlusPlus/CMakeLists.txt +++ b/lldb/source/Plugins/LanguageRuntime/CPlusPlus/CMakeLists.txt @@ -5,6 +5,7 @@ add_lldb_library(lldbPluginCPPRuntime PLUGIN lldbCore lldbSymbol lldbTarget + lldbPluginTypeSystemClang ) add_subdirectory(ItaniumABI) diff --git a/lldb/source/Plugins/LanguageRuntime/CPlusPlus/CPPLanguageRuntime.cpp b/lldb/source/Plugins/LanguageRuntime/CPlusPlus/CPPLanguageRuntime.cpp index 1bd993313ea37..43c51e75e6a88 100644 --- a/lldb/source/Plugins/LanguageRuntime/CPlusPlus/CPPLanguageRuntime.cpp +++ b/lldb/source/Plugins/LanguageRuntime/CPlusPlus/CPPLanguageRuntime.cpp @@ -18,9 +18,9 @@ #include "lldb/Symbol/Variable.h" #include "lldb/Symbol/VariableList.h" +#include "Plugins/TypeSystem/Clang/TypeSystemClang.h" #include "lldb/Core/PluginManager.h" #include "lldb/Core/UniqueCStringMap.h" -#include "lldb/Symbol/TypeSystemClang.h" #include "lldb/Symbol/CompileUnit.h" #include "lldb/Target/ABI.h" #include "lldb/Target/ExecutionContext.h" diff --git a/lldb/source/Plugins/LanguageRuntime/CPlusPlus/ItaniumABI/CMakeLists.txt b/lldb/source/Plugins/LanguageRuntime/CPlusPlus/ItaniumABI/CMakeLists.txt index 52c297d944b9f..5ab494414ac5b 100644 --- a/lldb/source/Plugins/LanguageRuntime/CPlusPlus/ItaniumABI/CMakeLists.txt +++ b/lldb/source/Plugins/LanguageRuntime/CPlusPlus/ItaniumABI/CMakeLists.txt @@ -8,4 +8,5 @@ add_lldb_library(lldbPluginCXXItaniumABI PLUGIN lldbSymbol lldbTarget lldbPluginCPPRuntime + lldbPluginTypeSystemClang ) diff --git a/lldb/source/Plugins/LanguageRuntime/CPlusPlus/ItaniumABI/ItaniumABILanguageRuntime.cpp b/lldb/source/Plugins/LanguageRuntime/CPlusPlus/ItaniumABI/ItaniumABILanguageRuntime.cpp index 836989868b626..a9127d4bdfd82 100644 --- a/lldb/source/Plugins/LanguageRuntime/CPlusPlus/ItaniumABI/ItaniumABILanguageRuntime.cpp +++ b/lldb/source/Plugins/LanguageRuntime/CPlusPlus/ItaniumABI/ItaniumABILanguageRuntime.cpp @@ -9,6 +9,7 @@ #include "ItaniumABILanguageRuntime.h" +#include "Plugins/TypeSystem/Clang/TypeSystemClang.h" #include "lldb/Breakpoint/BreakpointLocation.h" #include "lldb/Core/Mangled.h" #include "lldb/Core/Module.h" @@ -21,7 +22,6 @@ #include "lldb/Interpreter/CommandObject.h" #include "lldb/Interpreter/CommandObjectMultiword.h" #include "lldb/Interpreter/CommandReturnObject.h" -#include "lldb/Symbol/TypeSystemClang.h" #include "lldb/Symbol/Symbol.h" #include "lldb/Symbol/SymbolFile.h" #include "lldb/Symbol/TypeList.h" diff --git a/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCDeclVendor.cpp b/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCDeclVendor.cpp index d33af7943761a..7219f61a9834d 100644 --- a/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCDeclVendor.cpp +++ b/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCDeclVendor.cpp @@ -8,10 +8,10 @@ #include "AppleObjCDeclVendor.h" +#include "Plugins/ExpressionParser/Clang/ClangASTMetadata.h" +#include "Plugins/ExpressionParser/Clang/ClangUtil.h" #include "Plugins/LanguageRuntime/ObjC/ObjCLanguageRuntime.h" #include "lldb/Core/Module.h" -#include "lldb/Symbol/ClangASTMetadata.h" -#include "lldb/Symbol/ClangUtil.h" #include "lldb/Target/Process.h" #include "lldb/Target/Target.h" #include "lldb/Utility/Log.h" diff --git a/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCDeclVendor.h b/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCDeclVendor.h index eee802766117c..0d66cc781320f 100644 --- a/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCDeclVendor.h +++ b/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCDeclVendor.h @@ -9,11 +9,11 @@ #ifndef liblldb_AppleObjCDeclVendor_h_ #define liblldb_AppleObjCDeclVendor_h_ -#include "lldb/Symbol/TypeSystemClang.h" #include "lldb/lldb-private.h" #include "Plugins/ExpressionParser/Clang/ClangDeclVendor.h" #include "Plugins/LanguageRuntime/ObjC/ObjCLanguageRuntime.h" +#include "Plugins/TypeSystem/Clang/TypeSystemClang.h" namespace lldb_private { diff --git a/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntime.cpp b/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntime.cpp index d620bc567296d..d84a7341e5a34 100644 --- a/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntime.cpp +++ b/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntime.cpp @@ -22,7 +22,6 @@ #include "lldb/DataFormatters/FormattersHelpers.h" #include "lldb/Expression/DiagnosticManager.h" #include "lldb/Expression/FunctionCaller.h" -#include "lldb/Symbol/TypeSystemClang.h" #include "lldb/Symbol/ObjectFile.h" #include "lldb/Target/ExecutionContext.h" #include "lldb/Target/Process.h" @@ -40,6 +39,8 @@ #include "Plugins/Language/ObjC/NSString.h" #include "Plugins/LanguageRuntime/CPlusPlus/CPPLanguageRuntime.h" +#include "Plugins/TypeSystem/Clang/TypeSystemClang.h" + #include using namespace lldb; diff --git a/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntimeV1.cpp b/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntimeV1.cpp index 69673443ce570..f7c1409682627 100644 --- a/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntimeV1.cpp +++ b/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntimeV1.cpp @@ -13,12 +13,12 @@ #include "clang/AST/Type.h" +#include "Plugins/TypeSystem/Clang/TypeSystemClang.h" #include "lldb/Breakpoint/BreakpointLocation.h" #include "lldb/Core/Module.h" #include "lldb/Core/PluginManager.h" #include "lldb/Expression/FunctionCaller.h" #include "lldb/Expression/UtilityFunction.h" -#include "lldb/Symbol/TypeSystemClang.h" #include "lldb/Symbol/Symbol.h" #include "lldb/Target/ExecutionContext.h" #include "lldb/Target/Process.h" diff --git a/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntimeV2.cpp b/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntimeV2.cpp index c1ee53b5d143d..2c43d30928156 100644 --- a/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntimeV2.cpp +++ b/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntimeV2.cpp @@ -20,6 +20,7 @@ #include "lldb/Symbol/CompilerType.h" #include "lldb/lldb-enumerations.h" +#include "Plugins/TypeSystem/Clang/TypeSystemClang.h" #include "lldb/Core/ClangForward.h" #include "lldb/Core/Debugger.h" #include "lldb/Core/Module.h" @@ -35,7 +36,6 @@ #include "lldb/Interpreter/CommandReturnObject.h" #include "lldb/Interpreter/OptionArgParser.h" #include "lldb/Interpreter/OptionValueBoolean.h" -#include "lldb/Symbol/TypeSystemClang.h" #include "lldb/Symbol/ObjectFile.h" #include "lldb/Symbol/Symbol.h" #include "lldb/Symbol/TypeList.h" @@ -1184,6 +1184,28 @@ AppleObjCRuntimeV2::GetClassDescriptorFromISA(ObjCISA isa) { return class_descriptor_sp; } +static std::pair ObjCGetClassNameRaw( + AppleObjCRuntime::ObjCISA isa, + Process *process) { + StreamString expr_string; + std::string input = std::to_string(isa); + expr_string.Printf("(const char *)objc_debug_class_getNameRaw(%s)", + input.c_str()); + + ValueObjectSP result_sp; + EvaluateExpressionOptions eval_options; + eval_options.SetLanguage(lldb::eLanguageTypeObjC); + eval_options.SetResultIsInternal(true); + eval_options.SetGenerateDebugInfo(true); + eval_options.SetTimeout(process->GetUtilityExpressionTimeout()); + auto eval_result = process->GetTarget().EvaluateExpression( + expr_string.GetData(), + process->GetThreadList().GetSelectedThread()->GetSelectedFrame().get(), + result_sp, eval_options); + ConstString type_name(result_sp->GetSummaryAsCString()); + return std::make_pair(eval_result == eExpressionCompleted, type_name); +} + ObjCLanguageRuntime::ClassDescriptorSP AppleObjCRuntimeV2::GetClassDescriptor(ValueObject &valobj) { ClassDescriptorSP objc_class_sp; @@ -1200,32 +1222,43 @@ AppleObjCRuntimeV2::GetClassDescriptor(ValueObject &valobj) { // if we get an invalid VO (which might still happen when playing around with // pointers returned by the expression parser, don't consider this a valid // ObjC object) - if (valobj.GetCompilerType().IsValid()) { - addr_t isa_pointer = valobj.GetPointerValue(); + if (!valobj.GetCompilerType().IsValid()) + return objc_class_sp; + addr_t isa_pointer = valobj.GetPointerValue(); - // tagged pointer - if (IsTaggedPointer(isa_pointer)) { - return m_tagged_pointer_vendor_up->GetClassDescriptor(isa_pointer); - } else { - ExecutionContext exe_ctx(valobj.GetExecutionContextRef()); + // tagged pointer + if (IsTaggedPointer(isa_pointer)) + return m_tagged_pointer_vendor_up->GetClassDescriptor(isa_pointer); + ExecutionContext exe_ctx(valobj.GetExecutionContextRef()); - Process *process = exe_ctx.GetProcessPtr(); - if (process) { - Status error; - ObjCISA isa = process->ReadPointerFromMemory(isa_pointer, error); - if (isa != LLDB_INVALID_ADDRESS) { - objc_class_sp = GetClassDescriptorFromISA(isa); - if (isa && !objc_class_sp) { - Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_PROCESS)); - LLDB_LOGF(log, - "0x%" PRIx64 - ": AppleObjCRuntimeV2::GetClassDescriptor() ISA was " - "not in class descriptor cache 0x%" PRIx64, - isa_pointer, isa); - } - } - } - } + Process *process = exe_ctx.GetProcessPtr(); + if (!process) + return objc_class_sp; + + Status error; + ObjCISA isa = process->ReadPointerFromMemory(isa_pointer, error); + if (isa == LLDB_INVALID_ADDRESS) + return objc_class_sp; + + objc_class_sp = GetClassDescriptorFromISA(isa); + + if (objc_class_sp) + return objc_class_sp; + else { + Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_PROCESS | + LIBLLDB_LOG_TYPES)); + LLDB_LOGF(log, + "0x%" PRIx64 + ": AppleObjCRuntimeV2::GetClassDescriptor() ISA was " + "not in class descriptor cache 0x%" PRIx64, + isa_pointer, isa); + } + + ClassDescriptorSP descriptor_sp(new ClassDescriptorV2(*this, isa, nullptr)); + auto resolved = ObjCGetClassNameRaw(isa, process); + if (resolved.first == true) { + AddClass(isa, descriptor_sp, resolved.second.AsCString()); + objc_class_sp = descriptor_sp; } return objc_class_sp; } @@ -2729,9 +2762,10 @@ static void RegisterObjCExceptionRecognizer() { FileSpec module; ConstString function; std::tie(module, function) = AppleObjCRuntime::GetExceptionThrowLocation(); + std::vector symbols = {function}; StackFrameRecognizerManager::AddRecognizer( StackFrameRecognizerSP(new ObjCExceptionThrowFrameRecognizer()), - module.GetFilename(), function, /*alternate_symbol*/ {}, + module.GetFilename(), symbols, /*first_instruction_only*/ true); }); } diff --git a/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCTrampolineHandler.cpp b/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCTrampolineHandler.cpp index 5b5e416b20d89..79c7ab1c5c733 100644 --- a/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCTrampolineHandler.cpp +++ b/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCTrampolineHandler.cpp @@ -10,6 +10,7 @@ #include "AppleObjCTrampolineHandler.h" #include "AppleThreadPlanStepThroughObjCTrampoline.h" +#include "Plugins/TypeSystem/Clang/TypeSystemClang.h" #include "lldb/Breakpoint/StoppointCallbackContext.h" #include "lldb/Core/Debugger.h" #include "lldb/Core/Module.h" @@ -19,7 +20,6 @@ #include "lldb/Expression/FunctionCaller.h" #include "lldb/Expression/UserExpression.h" #include "lldb/Expression/UtilityFunction.h" -#include "lldb/Symbol/TypeSystemClang.h" #include "lldb/Symbol/Symbol.h" #include "lldb/Target/ABI.h" #include "lldb/Target/ExecutionContext.h" diff --git a/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCTypeEncodingParser.cpp b/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCTypeEncodingParser.cpp index 55655bf69c863..2bc6cfd9a7fc9 100644 --- a/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCTypeEncodingParser.cpp +++ b/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCTypeEncodingParser.cpp @@ -8,8 +8,8 @@ #include "AppleObjCTypeEncodingParser.h" -#include "lldb/Symbol/TypeSystemClang.h" -#include "lldb/Symbol/ClangUtil.h" +#include "Plugins/ExpressionParser/Clang/ClangUtil.h" +#include "Plugins/TypeSystem/Clang/TypeSystemClang.h" #include "lldb/Symbol/CompilerType.h" #include "lldb/Target/Process.h" #include "lldb/Target/Target.h" diff --git a/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleThreadPlanStepThroughObjCTrampoline.cpp b/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleThreadPlanStepThroughObjCTrampoline.cpp index ba9fb7f2e6ae8..0d99dc9e7bb4c 100644 --- a/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleThreadPlanStepThroughObjCTrampoline.cpp +++ b/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleThreadPlanStepThroughObjCTrampoline.cpp @@ -48,15 +48,14 @@ void AppleThreadPlanStepThroughObjCTrampoline::DidPush() { // Setting up the memory space for the called function text might require // allocations, i.e. a nested function call. This needs to be done as a // PreResumeAction. - m_thread.GetProcess()->AddPreResumeAction(PreResumeInitializeFunctionCaller, - (void *)this); + m_process.AddPreResumeAction(PreResumeInitializeFunctionCaller, (void *)this); } bool AppleThreadPlanStepThroughObjCTrampoline::InitializeFunctionCaller() { if (!m_func_sp) { DiagnosticManager diagnostics; m_args_addr = - m_trampoline_handler.SetupDispatchFunction(m_thread, m_input_values); + m_trampoline_handler.SetupDispatchFunction(GetThread(), m_input_values); if (m_args_addr == LLDB_INVALID_ADDRESS) { return false; @@ -68,7 +67,7 @@ bool AppleThreadPlanStepThroughObjCTrampoline::InitializeFunctionCaller() { options.SetUnwindOnError(true); options.SetIgnoreBreakpoints(true); options.SetStopOthers(m_stop_others); - m_thread.CalculateExecutionContext(exc_ctx); + GetThread().CalculateExecutionContext(exc_ctx); m_func_sp = m_impl_function->GetThreadPlanToCallFunction( exc_ctx, m_args_addr, options, diagnostics); m_func_sp->SetOkayToDiscard(true); @@ -132,7 +131,7 @@ bool AppleThreadPlanStepThroughObjCTrampoline::ShouldStop(Event *event_ptr) { if (!m_run_to_sp) { Value target_addr_value; ExecutionContext exc_ctx; - m_thread.CalculateExecutionContext(exc_ctx); + GetThread().CalculateExecutionContext(exc_ctx); m_impl_function->FetchFunctionResults(exc_ctx, m_args_addr, target_addr_value); m_impl_function->DeallocateFunctionResults(exc_ctx, m_args_addr); @@ -151,13 +150,13 @@ bool AppleThreadPlanStepThroughObjCTrampoline::ShouldStop(Event *event_ptr) { ", stopping.", target_addr); - SymbolContext sc = m_thread.GetStackFrameAtIndex(0)->GetSymbolContext( + SymbolContext sc = GetThread().GetStackFrameAtIndex(0)->GetSymbolContext( eSymbolContextEverything); Status status; const bool abort_other_plans = false; const bool first_insn = true; const uint32_t frame_idx = 0; - m_run_to_sp = m_thread.QueueThreadPlanForStepOutNoShouldStop( + m_run_to_sp = GetThread().QueueThreadPlanForStepOutNoShouldStop( abort_other_plans, &sc, first_insn, m_stop_others, eVoteNoOpinion, eVoteNoOpinion, frame_idx, status); if (m_run_to_sp && status.Success()) @@ -180,10 +179,10 @@ bool AppleThreadPlanStepThroughObjCTrampoline::ShouldStop(Event *event_ptr) { // Extract the target address from the value: m_run_to_sp = std::make_shared( - m_thread, target_so_addr, m_stop_others); + GetThread(), target_so_addr, m_stop_others); PushPlan(m_run_to_sp); return false; - } else if (m_thread.IsThreadPlanDone(m_run_to_sp.get())) { + } else if (GetThread().IsThreadPlanDone(m_run_to_sp.get())) { // Third stage, work the run to target plan. SetPlanComplete(); return true; diff --git a/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/CMakeLists.txt b/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/CMakeLists.txt index bcf324023c221..3789f56325980 100644 --- a/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/CMakeLists.txt +++ b/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/CMakeLists.txt @@ -19,6 +19,7 @@ add_lldb_library(lldbPluginAppleObjCRuntime PLUGIN lldbUtility lldbPluginExpressionParserClang lldbPluginCPPRuntime + lldbPluginTypeSystemClang CLANG_LIBS clangAST LINK_COMPONENTS diff --git a/lldb/source/Plugins/LanguageRuntime/ObjC/ObjCLanguageRuntime.cpp b/lldb/source/Plugins/LanguageRuntime/ObjC/ObjCLanguageRuntime.cpp index 9447597d9263c..4c2230944537c 100644 --- a/lldb/source/Plugins/LanguageRuntime/ObjC/ObjCLanguageRuntime.cpp +++ b/lldb/source/Plugins/LanguageRuntime/ObjC/ObjCLanguageRuntime.cpp @@ -9,11 +9,11 @@ #include "ObjCLanguageRuntime.h" +#include "Plugins/TypeSystem/Clang/TypeSystemClang.h" #include "lldb/Core/MappedHash.h" #include "lldb/Core/Module.h" #include "lldb/Core/PluginManager.h" #include "lldb/Core/ValueObject.h" -#include "lldb/Symbol/TypeSystemClang.h" #include "lldb/Symbol/SymbolContext.h" #include "lldb/Symbol/SymbolFile.h" #include "lldb/Symbol/Type.h" @@ -129,7 +129,7 @@ ObjCLanguageRuntime::LookupInCompleteClassCache(ConstString &name) { if (TypeSystemClang::IsObjCObjectOrInterfaceType( type_sp->GetForwardCompilerType())) { - if (type_sp->IsCompleteObjCClass()) { + if (TypePayloadClang(type_sp->GetPayload()).IsCompleteObjCClass()) { m_complete_class_cache[name] = type_sp; return type_sp; } diff --git a/lldb/source/Plugins/MemoryHistory/asan/MemoryHistoryASan.cpp b/lldb/source/Plugins/MemoryHistory/asan/MemoryHistoryASan.cpp index e0d2c5d0eef8c..87431dd886bd7 100644 --- a/lldb/source/Plugins/MemoryHistory/asan/MemoryHistoryASan.cpp +++ b/lldb/source/Plugins/MemoryHistory/asan/MemoryHistoryASan.cpp @@ -136,7 +136,12 @@ static void CreateHistoryThreadFromValueObject(ProcessSP process_sp, pcs.push_back(pc); } - HistoryThread *history_thread = new HistoryThread(*process_sp, tid, pcs); + // The ASAN runtime already massages the return addresses into call + // addresses, we don't want LLDB's unwinder to try to locate the previous + // instruction again as this might lead to us reporting a different line. + bool pcs_are_call_addresses = true; + HistoryThread *history_thread = + new HistoryThread(*process_sp, tid, pcs, pcs_are_call_addresses); ThreadSP new_thread_sp(history_thread); std::ostringstream thread_name_with_number; thread_name_with_number << thread_name << " Thread " << tid; diff --git a/lldb/source/Plugins/Platform/Linux/PlatformLinux.cpp b/lldb/source/Plugins/Platform/Linux/PlatformLinux.cpp index 485ffbe04872f..967119e377917 100644 --- a/lldb/source/Plugins/Platform/Linux/PlatformLinux.cpp +++ b/lldb/source/Plugins/Platform/Linux/PlatformLinux.cpp @@ -367,7 +367,7 @@ PlatformLinux::DebugProcess(ProcessLaunchInfo &launch_info, Debugger &debugger, } else LLDB_LOG(log, "not using process STDIO pty"); } else { - LLDB_LOG(log, "process launch failed: {0}", error); + LLDB_LOG(log, "{0}", error); // FIXME figure out appropriate cleanup here. Do we delete the target? Do // we delete the process? Does our caller do that? } diff --git a/lldb/source/Plugins/Platform/MacOSX/PlatformAppleSimulator.cpp b/lldb/source/Plugins/Platform/MacOSX/PlatformAppleSimulator.cpp index 12a63f0aacb77..082890f8571b3 100644 --- a/lldb/source/Plugins/Platform/MacOSX/PlatformAppleSimulator.cpp +++ b/lldb/source/Plugins/Platform/MacOSX/PlatformAppleSimulator.cpp @@ -77,9 +77,10 @@ void PlatformAppleSimulator::GetStatus(Stream &strm) { // simulator PlatformAppleSimulator::LoadCoreSimulator(); + std::string developer_dir = GetXcodeDeveloperDirectory().GetPath(); CoreSimulatorSupport::DeviceSet devices = CoreSimulatorSupport::DeviceSet::GetAvailableDevices( - GetDeveloperDirectory()); + developer_dir.c_str()); const size_t num_devices = devices.GetNumDevices(); if (num_devices) { strm.Printf("Available devices:\n"); @@ -123,9 +124,10 @@ Status PlatformAppleSimulator::ConnectRemote(Args &args) { const char *arg_cstr = args.GetArgumentAtIndex(0); if (arg_cstr) { std::string arg_str(arg_cstr); + std::string developer_dir = GetXcodeDeveloperDirectory().GetPath(); CoreSimulatorSupport::DeviceSet devices = CoreSimulatorSupport::DeviceSet::GetAvailableDevices( - GetDeveloperDirectory()); + developer_dir.c_str()); devices.ForEach( [this, &arg_str](const CoreSimulatorSupport::Device &device) -> bool { if (arg_str == device.GetUDID() || arg_str == device.GetName()) { @@ -212,12 +214,12 @@ FileSpec PlatformAppleSimulator::GetCoreSimulatorPath() { #if defined(__APPLE__) std::lock_guard guard(m_core_sim_path_mutex); if (!m_core_simulator_framework_path.hasValue()) { - const char *developer_dir = GetDeveloperDirectory(); - if (developer_dir) { + if (FileSpec fspec = GetXcodeDeveloperDirectory()) { + std::string developer_dir = fspec.GetPath(); StreamString cs_path; cs_path.Printf( "%s/Library/PrivateFrameworks/CoreSimulator.framework/CoreSimulator", - developer_dir); + developer_dir.c_str()); m_core_simulator_framework_path = FileSpec(cs_path.GetData()); FileSystem::Instance().Resolve(*m_core_simulator_framework_path); } @@ -245,8 +247,9 @@ CoreSimulatorSupport::Device PlatformAppleSimulator::GetSimulatorDevice() { if (!m_device.hasValue()) { const CoreSimulatorSupport::DeviceType::ProductFamilyID dev_id = CoreSimulatorSupport::DeviceType::ProductFamilyID::iPhone; + std::string developer_dir = GetXcodeDeveloperDirectory().GetPath(); m_device = CoreSimulatorSupport::DeviceSet::GetAvailableDevices( - GetDeveloperDirectory()) + developer_dir.c_str()) .GetFanciest(dev_id); } diff --git a/lldb/source/Plugins/Platform/MacOSX/PlatformAppleTVSimulator.cpp b/lldb/source/Plugins/Platform/MacOSX/PlatformAppleTVSimulator.cpp index 40148e23a1b11..5869d39bb1f98 100644 --- a/lldb/source/Plugins/Platform/MacOSX/PlatformAppleTVSimulator.cpp +++ b/lldb/source/Plugins/Platform/MacOSX/PlatformAppleTVSimulator.cpp @@ -255,14 +255,14 @@ EnumerateDirectoryCallback(void *baton, llvm::sys::fs::file_type ft, const char *PlatformAppleTVSimulator::GetSDKDirectoryAsCString() { std::lock_guard guard(m_sdk_dir_mutex); if (m_sdk_directory.empty()) { - const char *developer_dir = GetDeveloperDirectory(); - if (developer_dir) { + if (FileSpec fspec = GetXcodeDeveloperDirectory()) { + std::string developer_dir = fspec.GetPath(); char sdks_directory[PATH_MAX]; char sdk_dirname[PATH_MAX]; sdk_dirname[0] = '\0'; snprintf(sdks_directory, sizeof(sdks_directory), "%s/Platforms/AppleTVSimulator.platform/Developer/SDKs", - developer_dir); + developer_dir.c_str()); FileSpec simulator_sdk_spec; bool find_directories = true; bool find_files = false; @@ -361,13 +361,12 @@ uint32_t PlatformAppleTVSimulator::FindProcesses( // Now we filter them down to only the TvOS triples for (uint32_t i = 0; i < n; ++i) { - const ProcessInstanceInfo &proc_info = - all_osx_process_infos.GetProcessInfoAtIndex(i); + const ProcessInstanceInfo &proc_info = all_osx_process_infos[i]; if (proc_info.GetArchitecture().GetTriple().getOS() == llvm::Triple::TvOS) { - process_infos.Append(proc_info); + process_infos.push_back(proc_info); } } - return process_infos.GetSize(); + return process_infos.size(); } bool PlatformAppleTVSimulator::GetSupportedArchitectureAtIndex(uint32_t idx, diff --git a/lldb/source/Plugins/Platform/MacOSX/PlatformAppleTVSimulator.h b/lldb/source/Plugins/Platform/MacOSX/PlatformAppleTVSimulator.h index 0005eab4e6710..fc377ef04a6d4 100644 --- a/lldb/source/Plugins/Platform/MacOSX/PlatformAppleTVSimulator.h +++ b/lldb/source/Plugins/Platform/MacOSX/PlatformAppleTVSimulator.h @@ -69,7 +69,7 @@ class PlatformAppleTVSimulator : public PlatformDarwin { AddClangModuleCompilationOptions(lldb_private::Target *target, std::vector &options) override { return PlatformDarwin::AddClangModuleCompilationOptionsForSDKType( - target, options, PlatformDarwin::SDKType::iPhoneSimulator); + target, options, lldb_private::XcodeSDK::Type::iPhoneSimulator); } protected: diff --git a/lldb/source/Plugins/Platform/MacOSX/PlatformAppleWatchSimulator.cpp b/lldb/source/Plugins/Platform/MacOSX/PlatformAppleWatchSimulator.cpp index 0e21f3b96d999..8fb279bcf1c99 100644 --- a/lldb/source/Plugins/Platform/MacOSX/PlatformAppleWatchSimulator.cpp +++ b/lldb/source/Plugins/Platform/MacOSX/PlatformAppleWatchSimulator.cpp @@ -255,14 +255,14 @@ EnumerateDirectoryCallback(void *baton, llvm::sys::fs::file_type ft, const char *PlatformAppleWatchSimulator::GetSDKDirectoryAsCString() { std::lock_guard guard(m_sdk_dir_mutex); if (m_sdk_directory.empty()) { - const char *developer_dir = GetDeveloperDirectory(); - if (developer_dir) { + if (FileSpec fspec = GetXcodeDeveloperDirectory()) { + std::string developer_dir = fspec.GetPath(); char sdks_directory[PATH_MAX]; char sdk_dirname[PATH_MAX]; sdk_dirname[0] = '\0'; snprintf(sdks_directory, sizeof(sdks_directory), "%s/Platforms/AppleWatchSimulator.platform/Developer/SDKs", - developer_dir); + developer_dir.c_str()); FileSpec simulator_sdk_spec; bool find_directories = true; bool find_files = false; @@ -361,14 +361,13 @@ uint32_t PlatformAppleWatchSimulator::FindProcesses( // Now we filter them down to only the WatchOS triples for (uint32_t i = 0; i < n; ++i) { - const ProcessInstanceInfo &proc_info = - all_osx_process_infos.GetProcessInfoAtIndex(i); + const ProcessInstanceInfo &proc_info = all_osx_process_infos[i]; if (proc_info.GetArchitecture().GetTriple().getOS() == llvm::Triple::WatchOS) { - process_infos.Append(proc_info); + process_infos.push_back(proc_info); } } - return process_infos.GetSize(); + return process_infos.size(); } bool PlatformAppleWatchSimulator::GetSupportedArchitectureAtIndex( diff --git a/lldb/source/Plugins/Platform/MacOSX/PlatformAppleWatchSimulator.h b/lldb/source/Plugins/Platform/MacOSX/PlatformAppleWatchSimulator.h index d8ffa05343a73..cf6b2436b2969 100644 --- a/lldb/source/Plugins/Platform/MacOSX/PlatformAppleWatchSimulator.h +++ b/lldb/source/Plugins/Platform/MacOSX/PlatformAppleWatchSimulator.h @@ -69,7 +69,7 @@ class PlatformAppleWatchSimulator : public PlatformDarwin { AddClangModuleCompilationOptions(lldb_private::Target *target, std::vector &options) override { return PlatformDarwin::AddClangModuleCompilationOptionsForSDKType( - target, options, PlatformDarwin::SDKType::iPhoneSimulator); + target, options, lldb_private::XcodeSDK::Type::iPhoneSimulator); } protected: diff --git a/lldb/source/Plugins/Platform/MacOSX/PlatformDarwin.cpp b/lldb/source/Plugins/Platform/MacOSX/PlatformDarwin.cpp index f1abbf2ca1e11..0c70bafdfdb51 100644 --- a/lldb/source/Plugins/Platform/MacOSX/PlatformDarwin.cpp +++ b/lldb/source/Plugins/Platform/MacOSX/PlatformDarwin.cpp @@ -48,9 +48,7 @@ using namespace lldb; using namespace lldb_private; /// Default Constructor -PlatformDarwin::PlatformDarwin(bool is_host) - : PlatformPOSIX(is_host), // This is the local host platform - m_developer_directory() {} +PlatformDarwin::PlatformDarwin(bool is_host) : PlatformPOSIX(is_host) {} /// Destructor. /// @@ -58,6 +56,17 @@ PlatformDarwin::PlatformDarwin(bool is_host) /// inherited from by the plug-in instance. PlatformDarwin::~PlatformDarwin() {} +lldb_private::Status +PlatformDarwin::PutFile(const lldb_private::FileSpec &source, + const lldb_private::FileSpec &destination, uint32_t uid, + uint32_t gid) { + // Unconditionally unlink the destination. If it is an executable, + // simply opening it and truncating its contents would invalidate + // its cached code signature. + Unlink(destination); + return PlatformPOSIX::PutFile(source, destination, uid, gid); +} + FileSpecList PlatformDarwin::LocateExecutableScriptingResources( Target *target, Module &module, Stream *feedback_stream) { FileSpecList file_list; @@ -1124,88 +1133,17 @@ static FileSpec GetXcodeSelectPath() { return g_xcode_select_filespec; } -// Return a directory path like /Applications/Xcode.app/Contents/Developer -const char *PlatformDarwin::GetDeveloperDirectory() { - std::lock_guard guard(m_mutex); - if (m_developer_directory.empty()) { - bool developer_dir_path_valid = false; - char developer_dir_path[PATH_MAX]; - - // Get the lldb framework's file path, and if it exists, truncate some - // components to only the developer directory path. - FileSpec temp_file_spec = HostInfo::GetShlibDir(); - if (temp_file_spec) { - if (temp_file_spec.GetPath(developer_dir_path, - sizeof(developer_dir_path))) { - // e.g. - // /Applications/Xcode.app/Contents/SharedFrameworks/LLDB.framework - char *shared_frameworks = - strstr(developer_dir_path, "/SharedFrameworks/LLDB.framework"); - if (shared_frameworks) { - shared_frameworks[0] = '\0'; // truncate developer_dir_path at this point - strncat (developer_dir_path, "/Developer", sizeof (developer_dir_path) - 1); // add /Developer on - developer_dir_path_valid = true; - } else { - // e.g. - // /Applications/Xcode.app/Contents/Developer/Toolchains/iOS11.2.xctoolchain/System/Library/PrivateFrameworks/LLDB.framework - char *developer_toolchains = - strstr(developer_dir_path, "/Contents/Developer/Toolchains/"); - if (developer_toolchains) { - developer_toolchains += sizeof ("/Contents/Developer") - 1; - developer_toolchains[0] = '\0'; // truncate developer_dir_path at this point - developer_dir_path_valid = true; - } - } - } - } - - if (!developer_dir_path_valid) { - std::string xcode_dir_path; - const char *xcode_select_prefix_dir = getenv("XCODE_SELECT_PREFIX_DIR"); - if (xcode_select_prefix_dir) - xcode_dir_path.append(xcode_select_prefix_dir); - xcode_dir_path.append("/usr/share/xcode-select/xcode_dir_path"); - temp_file_spec.SetFile(xcode_dir_path, FileSpec::Style::native); - auto dir_buffer = - FileSystem::Instance().CreateDataBuffer(temp_file_spec.GetPath()); - if (dir_buffer && dir_buffer->GetByteSize() > 0) { - llvm::StringRef path_ref(dir_buffer->GetChars()); - // Trim tailing newlines and make sure there is enough room for a null - // terminator. - path_ref = - path_ref.rtrim("\r\n").take_front(sizeof(developer_dir_path) - 1); - ::memcpy(developer_dir_path, path_ref.data(), path_ref.size()); - developer_dir_path[path_ref.size()] = '\0'; - developer_dir_path_valid = true; - } - } - - if (!developer_dir_path_valid) { - FileSpec devel_dir = GetXcodeSelectPath(); - if (FileSystem::Instance().IsDirectory(devel_dir)) { - devel_dir.GetPath(&developer_dir_path[0], sizeof(developer_dir_path)); - developer_dir_path_valid = true; - } - } - - if (developer_dir_path_valid) { - temp_file_spec.SetFile(developer_dir_path, FileSpec::Style::native); - if (FileSystem::Instance().Exists(temp_file_spec)) { - m_developer_directory.assign(developer_dir_path); - return m_developer_directory.c_str(); - } +lldb_private::FileSpec PlatformDarwin::GetXcodeDeveloperDirectory() { + static lldb_private::FileSpec g_developer_directory; + static llvm::once_flag g_once_flag; + llvm::call_once(g_once_flag, []() { + if (FileSpec fspec = GetXcodeContentsDirectory()) { + fspec.AppendPathComponent("Developer"); + if (FileSystem::Instance().Exists(fspec)) + g_developer_directory = fspec; } - // Assign a single NULL character so we know we tried to find the device - // support directory and we don't keep trying to find it over and over. - m_developer_directory.assign(1, '\0'); - } - - // We should have put a single NULL character into m_developer_directory or - // it should have a valid path if the code gets here - assert(m_developer_directory.empty() == false); - if (m_developer_directory[0]) - return m_developer_directory.c_str(); - return nullptr; + }); + return g_developer_directory; } BreakpointSP PlatformDarwin::SetThreadCreationBreakpoint(Target &target) { @@ -1268,76 +1206,6 @@ void PlatformDarwin::CalculateTrapHandlerSymbolNames() { m_trap_handlers.push_back(ConstString("_sigtramp")); } -static const char *const sdk_strings[] = { - "MacOSX", "iPhoneSimulator", "iPhoneOS", -}; - -static FileSpec CheckPathForXcode(const FileSpec &fspec) { - if (FileSystem::Instance().Exists(fspec)) { - const char substr[] = ".app/Contents"; - - std::string path_to_shlib = fspec.GetPath(); - size_t pos = path_to_shlib.rfind(substr); - if (pos != std::string::npos) { - path_to_shlib.erase(pos + strlen(substr)); - FileSpec ret(path_to_shlib); - - FileSpec xcode_binary_path = ret; - xcode_binary_path.AppendPathComponent("MacOS"); - xcode_binary_path.AppendPathComponent("Xcode"); - - if (FileSystem::Instance().Exists(xcode_binary_path)) { - return ret; - } - } - } - return FileSpec(); -} - -static FileSpec GetXcodeContentsPath() { - static FileSpec g_xcode_filespec; - static llvm::once_flag g_once_flag; - llvm::call_once(g_once_flag, []() { - - FileSpec fspec; - - // First get the program file spec. If lldb.so or LLDB.framework is running - // in a program and that program is Xcode, the path returned with be the - // path to Xcode.app/Contents/MacOS/Xcode, so this will be the correct - // Xcode to use. - fspec = HostInfo::GetProgramFileSpec(); - - if (fspec) { - // Ignore the current binary if it is python. - std::string basename_lower = fspec.GetFilename().GetCString(); - std::transform(basename_lower.begin(), basename_lower.end(), - basename_lower.begin(), tolower); - if (basename_lower != "python") { - g_xcode_filespec = CheckPathForXcode(fspec); - } - } - - // Next check DEVELOPER_DIR environment variable - if (!g_xcode_filespec) { - const char *developer_dir_env_var = getenv("DEVELOPER_DIR"); - if (developer_dir_env_var && developer_dir_env_var[0]) { - FileSpec developer_dir_spec = FileSpec(developer_dir_env_var); - FileSystem::Instance().Resolve(developer_dir_spec); - g_xcode_filespec = CheckPathForXcode(developer_dir_spec); - } - - // Fall back to using "xcode-select" to find the selected Xcode - if (!g_xcode_filespec) { - FileSpec xcode_select_path(GetXcodeSelectPath()); - xcode_select_path.RemoveLastPathComponent(); - g_xcode_filespec = CheckPathForXcode(xcode_select_path); - } - } - }); - - return g_xcode_filespec; -} - static FileSpec GetCommandLineToolsLibraryPath() { static FileSpec g_command_line_tools_filespec; @@ -1352,47 +1220,12 @@ static FileSpec GetCommandLineToolsLibraryPath() { return g_command_line_tools_filespec; } -bool PlatformDarwin::SDKSupportsModules(SDKType sdk_type, - llvm::VersionTuple version) { - switch (sdk_type) { - case SDKType::MacOSX: - return version >= llvm::VersionTuple(10, 10); - case SDKType::iPhoneOS: - case SDKType::iPhoneSimulator: - return version >= llvm::VersionTuple(8); - } - - return false; -} - -bool PlatformDarwin::SDKSupportsModules(SDKType desired_type, - const FileSpec &sdk_path) { - ConstString last_path_component = sdk_path.GetLastPathComponent(); - - if (last_path_component) { - const llvm::StringRef sdk_name = last_path_component.GetStringRef(); - - if (!sdk_name.startswith(sdk_strings[desired_type])) - return false; - auto version_part = - sdk_name.drop_front(strlen(sdk_strings[desired_type])); - version_part.consume_back(".sdk"); - - llvm::VersionTuple version; - if (version.tryParse(version_part)) - return false; - return SDKSupportsModules(desired_type, version); - } - - return false; -} - FileSystem::EnumerateDirectoryResult PlatformDarwin::DirectoryEnumerator( void *baton, llvm::sys::fs::file_type file_type, llvm::StringRef path) { SDKEnumeratorInfo *enumerator_info = static_cast(baton); FileSpec spec(path); - if (SDKSupportsModules(enumerator_info->sdk_type, spec)) { + if (XcodeSDK::SDKSupportsModules(enumerator_info->sdk_type, spec)) { enumerator_info->found_path = spec; return FileSystem::EnumerateDirectoryResult::eEnumerateDirectoryResultNext; } @@ -1400,7 +1233,7 @@ FileSystem::EnumerateDirectoryResult PlatformDarwin::DirectoryEnumerator( return FileSystem::EnumerateDirectoryResult::eEnumerateDirectoryResultNext; } -FileSpec PlatformDarwin::FindSDKInXcodeForModules(SDKType sdk_type, +FileSpec PlatformDarwin::FindSDKInXcodeForModules(XcodeSDK::Type sdk_type, const FileSpec &sdks_spec) { // Look inside Xcode for the required installed iOS SDK version @@ -1426,38 +1259,33 @@ FileSpec PlatformDarwin::FindSDKInXcodeForModules(SDKType sdk_type, return FileSpec(); } -FileSpec PlatformDarwin::GetSDKDirectoryForModules(SDKType sdk_type) { - switch (sdk_type) { - case SDKType::MacOSX: - case SDKType::iPhoneSimulator: - case SDKType::iPhoneOS: - break; - } - - FileSpec sdks_spec = GetXcodeContentsPath(); +FileSpec PlatformDarwin::GetSDKDirectoryForModules(XcodeSDK::Type sdk_type) { + FileSpec sdks_spec = GetXcodeContentsDirectory(); sdks_spec.AppendPathComponent("Developer"); sdks_spec.AppendPathComponent("Platforms"); switch (sdk_type) { - case SDKType::MacOSX: + case XcodeSDK::Type::MacOSX: sdks_spec.AppendPathComponent("MacOSX.platform"); break; - case SDKType::iPhoneSimulator: + case XcodeSDK::Type::iPhoneSimulator: sdks_spec.AppendPathComponent("iPhoneSimulator.platform"); break; - case SDKType::iPhoneOS: + case XcodeSDK::Type::iPhoneOS: sdks_spec.AppendPathComponent("iPhoneOS.platform"); break; + default: + llvm_unreachable("unsupported sdk"); } sdks_spec.AppendPathComponent("Developer"); sdks_spec.AppendPathComponent("SDKs"); - if (sdk_type == SDKType::MacOSX) { + if (sdk_type == XcodeSDK::Type::MacOSX) { llvm::VersionTuple version = HostInfo::GetOSVersion(); if (!version.empty()) { - if (SDKSupportsModules(SDKType::MacOSX, version)) { + if (XcodeSDK::SDKSupportsModules(XcodeSDK::Type::MacOSX, version)) { // If the Xcode SDKs are not available then try to use the // Command Line Tools one which is only for MacOSX. if (!FileSystem::Instance().Exists(sdks_spec)) { @@ -1626,7 +1454,7 @@ PlatformDarwin::ExtractCrashInfoAnnotations(Process &process) { } void PlatformDarwin::AddClangModuleCompilationOptionsForSDKType( - Target *target, std::vector &options, SDKType sdk_type) { + Target *target, std::vector &options, XcodeSDK::Type sdk_type) { const std::vector apple_arguments = { "-x", "objective-c++", "-fobjc-arc", "-fblocks", "-D_ISO646_H", "-D__ISO646_H", @@ -1637,7 +1465,7 @@ void PlatformDarwin::AddClangModuleCompilationOptionsForSDKType( StreamString minimum_version_option; bool use_current_os_version = false; switch (sdk_type) { - case SDKType::iPhoneOS: + case XcodeSDK::Type::iPhoneOS: #if defined(__arm__) || defined(__arm64__) || defined(__aarch64__) use_current_os_version = true; #else @@ -1645,17 +1473,19 @@ void PlatformDarwin::AddClangModuleCompilationOptionsForSDKType( #endif break; - case SDKType::iPhoneSimulator: + case XcodeSDK::Type::iPhoneSimulator: use_current_os_version = false; break; - case SDKType::MacOSX: + case XcodeSDK::Type::MacOSX: #if defined(__i386__) || defined(__x86_64__) use_current_os_version = true; #else use_current_os_version = false; #endif break; + default: + break; } llvm::VersionTuple version; @@ -1674,17 +1504,20 @@ void PlatformDarwin::AddClangModuleCompilationOptionsForSDKType( // Only add the version-min options if we got a version from somewhere if (!version.empty()) { switch (sdk_type) { - case SDKType::iPhoneOS: + case XcodeSDK::Type::iPhoneOS: minimum_version_option.PutCString("-mios-version-min="); minimum_version_option.PutCString(version.getAsString()); break; - case SDKType::iPhoneSimulator: + case XcodeSDK::Type::iPhoneSimulator: minimum_version_option.PutCString("-mios-simulator-version-min="); minimum_version_option.PutCString(version.getAsString()); break; - case SDKType::MacOSX: + case XcodeSDK::Type::MacOSX: minimum_version_option.PutCString("-mmacosx-version-min="); minimum_version_option.PutCString(version.getAsString()); + break; + default: + llvm_unreachable("unsupported sdk"); } options.push_back(minimum_version_option.GetString()); } @@ -1744,8 +1577,7 @@ llvm::VersionTuple PlatformDarwin::GetOSVersion(Process *process) { lldb_private::FileSpec PlatformDarwin::LocateExecutable(const char *basename) { // A collection of SBFileSpec whose SBFileSpec.m_directory members are filled - // in with - // any executable directories that should be searched. + // in with any executable directories that should be searched. static std::vector g_executable_dirs; // Find the global list of directories that we will search for executables @@ -1754,7 +1586,7 @@ lldb_private::FileSpec PlatformDarwin::LocateExecutable(const char *basename) { llvm::call_once(g_once_flag, []() { // When locating executables, trust the DEVELOPER_DIR first if it is set - FileSpec xcode_contents_dir = GetXcodeContentsPath(); + FileSpec xcode_contents_dir = GetXcodeContentsDirectory(); if (xcode_contents_dir) { FileSpec xcode_lldb_resources = xcode_contents_dir; xcode_lldb_resources.AppendPathComponent("SharedFrameworks"); @@ -1816,12 +1648,10 @@ PlatformDarwin::LaunchProcess(lldb_private::ProcessLaunchInfo &launch_info) { return PlatformPOSIX::LaunchProcess(launch_info); } -lldb_private::Status -PlatformDarwin::FindBundleBinaryInExecSearchPaths (const ModuleSpec &module_spec, Process *process, - ModuleSP &module_sp, - const FileSpecList *module_search_paths_ptr, - ModuleSP *old_module_sp_ptr, bool *did_create_ptr) -{ +lldb_private::Status PlatformDarwin::FindBundleBinaryInExecSearchPaths( + const ModuleSpec &module_spec, Process *process, ModuleSP &module_sp, + const FileSpecList *module_search_paths_ptr, ModuleSP *old_module_sp_ptr, + bool *did_create_ptr) { const FileSpec &platform_file = module_spec.GetFileSpec(); // See if the file is present in any of the module_search_paths_ptr // directories. @@ -1892,3 +1722,103 @@ PlatformDarwin::FindBundleBinaryInExecSearchPaths (const ModuleSpec &module_spec } return Status(); } + +std::string PlatformDarwin::FindComponentInPath(llvm::StringRef path, + llvm::StringRef component) { + auto begin = llvm::sys::path::begin(path); + auto end = llvm::sys::path::end(path); + for (auto it = begin; it != end; ++it) { + if (it->contains(component)) { + llvm::SmallString<128> buffer; + llvm::sys::path::append(buffer, begin, ++it, + llvm::sys::path::Style::posix); + return buffer.str().str(); + } + } + return {}; +} + +std::string +PlatformDarwin::FindXcodeContentsDirectoryInPath(llvm::StringRef path) { + auto begin = llvm::sys::path::begin(path); + auto end = llvm::sys::path::end(path); + + // Iterate over the path components until we find something that ends with + // .app. If the next component is Contents then we've found the Contents + // directory. + for (auto it = begin; it != end; ++it) { + if (it->endswith(".app")) { + auto next = it; + if (++next != end && *next == "Contents") { + llvm::SmallString<128> buffer; + llvm::sys::path::append(buffer, begin, ++next, + llvm::sys::path::Style::posix); + return buffer.str().str(); + } + } + } + + return {}; +} + +llvm::StringRef PlatformDarwin::GetSDKPath(XcodeSDK sdk) { + std::string &path = m_sdk_path[sdk.GetString()]; + if (path.empty()) + path = HostInfo::GetXcodeSDK(sdk); + return path; +} + +FileSpec PlatformDarwin::GetXcodeContentsDirectory() { + static FileSpec g_xcode_contents_path; + static std::once_flag g_once_flag; + std::call_once(g_once_flag, [&]() { + // Try the shlib dir first. + if (FileSpec fspec = HostInfo::GetShlibDir()) { + if (FileSystem::Instance().Exists(fspec)) { + std::string xcode_contents_dir = + FindXcodeContentsDirectoryInPath(fspec.GetPath()); + if (!xcode_contents_dir.empty()) { + g_xcode_contents_path = FileSpec(xcode_contents_dir); + return; + } + } + } + + if (const char *developer_dir_env_var = getenv("DEVELOPER_DIR")) { + FileSpec fspec(developer_dir_env_var); + if (FileSystem::Instance().Exists(fspec)) { + std::string xcode_contents_dir = + FindXcodeContentsDirectoryInPath(fspec.GetPath()); + if (!xcode_contents_dir.empty()) { + g_xcode_contents_path = FileSpec(xcode_contents_dir); + return; + } + } + } + + FileSpec fspec(HostInfo::GetXcodeSDK(XcodeSDK::GetAnyMacOS())); + if (fspec) { + if (FileSystem::Instance().Exists(fspec)) { + std::string xcode_contents_dir = + FindXcodeContentsDirectoryInPath(fspec.GetPath()); + if (!xcode_contents_dir.empty()) { + g_xcode_contents_path = FileSpec(xcode_contents_dir); + return; + } + } + } + }); + return g_xcode_contents_path; +} + +FileSpec PlatformDarwin::GetCurrentToolchainDirectory() { + if (FileSpec fspec = HostInfo::GetShlibDir()) + return FileSpec(FindComponentInPath(fspec.GetPath(), ".xctoolchain")); + return {}; +} + +FileSpec PlatformDarwin::GetCurrentCommandLineToolsDirectory() { + if (FileSpec fspec = HostInfo::GetShlibDir()) + return FileSpec(FindComponentInPath(fspec.GetPath(), "CommandLineTools")); + return {}; +} diff --git a/lldb/source/Plugins/Platform/MacOSX/PlatformDarwin.h b/lldb/source/Plugins/Platform/MacOSX/PlatformDarwin.h index d9a0762181bda..91301d40e567f 100644 --- a/lldb/source/Plugins/Platform/MacOSX/PlatformDarwin.h +++ b/lldb/source/Plugins/Platform/MacOSX/PlatformDarwin.h @@ -12,8 +12,10 @@ #include "Plugins/Platform/POSIX/PlatformPOSIX.h" #include "lldb/Host/FileSystem.h" +#include "lldb/Utility/ConstString.h" #include "lldb/Utility/FileSpec.h" #include "lldb/Utility/StructuredData.h" +#include "lldb/Utility/XcodeSDK.h" #include "llvm/ADT/StringRef.h" #include "llvm/Support/FileSystem.h" @@ -26,6 +28,11 @@ class PlatformDarwin : public PlatformPOSIX { ~PlatformDarwin() override; + lldb_private::Status PutFile(const lldb_private::FileSpec &source, + const lldb_private::FileSpec &destination, + uint32_t uid = UINT32_MAX, + uint32_t gid = UINT32_MAX) override; + // lldb_private::Platform functions lldb_private::Status ResolveSymbolFile(lldb_private::Target &target, @@ -80,15 +87,21 @@ class PlatformDarwin : public PlatformPOSIX { static std::tuple ParseVersionBuildDir(llvm::StringRef str); - enum SDKType : unsigned { - MacOSX = 0, - iPhoneSimulator, - iPhoneOS, - }; - llvm::Expected FetchExtendedCrashInformation(lldb_private::Process &process) override; + llvm::StringRef GetSDKPath(lldb_private::XcodeSDK sdk) override; + + static lldb_private::FileSpec GetXcodeContentsDirectory(); + static lldb_private::FileSpec GetXcodeDeveloperDirectory(); + + /// Return the toolchain directroy the current LLDB instance is located in. + static lldb_private::FileSpec GetCurrentToolchainDirectory(); + + /// Return the command line tools directory the current LLDB instance is + /// located in. + static lldb_private::FileSpec GetCurrentCommandLineToolsDirectory(); + protected: struct CrashInfoAnnotations { uint64_t version; // unsigned long @@ -127,14 +140,9 @@ class PlatformDarwin : public PlatformPOSIX { const lldb_private::FileSpecList *module_search_paths_ptr, lldb::ModuleSP *old_module_sp_ptr, bool *did_create_ptr); - static bool SDKSupportsModules(SDKType sdk_type, llvm::VersionTuple version); - - static bool SDKSupportsModules(SDKType desired_type, - const lldb_private::FileSpec &sdk_path); - struct SDKEnumeratorInfo { lldb_private::FileSpec found_path; - SDKType sdk_type; + lldb_private::XcodeSDK::Type sdk_type; }; static lldb_private::FileSystem::EnumerateDirectoryResult @@ -142,26 +150,28 @@ class PlatformDarwin : public PlatformPOSIX { llvm::StringRef path); static lldb_private::FileSpec - FindSDKInXcodeForModules(SDKType sdk_type, + FindSDKInXcodeForModules(lldb_private::XcodeSDK::Type sdk_type, const lldb_private::FileSpec &sdks_spec); static lldb_private::FileSpec - GetSDKDirectoryForModules(PlatformDarwin::SDKType sdk_type); + GetSDKDirectoryForModules(lldb_private::XcodeSDK::Type sdk_type); - void - AddClangModuleCompilationOptionsForSDKType(lldb_private::Target *target, - std::vector &options, - SDKType sdk_type); + void AddClangModuleCompilationOptionsForSDKType( + lldb_private::Target *target, std::vector &options, + lldb_private::XcodeSDK::Type sdk_type); - const char *GetDeveloperDirectory(); + lldb_private::Status FindBundleBinaryInExecSearchPaths( + const lldb_private::ModuleSpec &module_spec, + lldb_private::Process *process, lldb::ModuleSP &module_sp, + const lldb_private::FileSpecList *module_search_paths_ptr, + lldb::ModuleSP *old_module_sp_ptr, bool *did_create_ptr); - lldb_private::Status - FindBundleBinaryInExecSearchPaths (const lldb_private::ModuleSpec &module_spec, lldb_private::Process *process, - lldb::ModuleSP &module_sp, const lldb_private::FileSpecList *module_search_paths_ptr, - lldb::ModuleSP *old_module_sp_ptr, bool *did_create_ptr); + static std::string FindComponentInPath(llvm::StringRef path, + llvm::StringRef component); + static std::string FindXcodeContentsDirectoryInPath(llvm::StringRef path); std::string m_developer_directory; - + llvm::StringMap m_sdk_path; private: DISALLOW_COPY_AND_ASSIGN(PlatformDarwin); diff --git a/lldb/source/Plugins/Platform/MacOSX/PlatformDarwinKernel.cpp b/lldb/source/Plugins/Platform/MacOSX/PlatformDarwinKernel.cpp index 7ca5397595c9e..e12d8a96adda5 100644 --- a/lldb/source/Plugins/Platform/MacOSX/PlatformDarwinKernel.cpp +++ b/lldb/source/Plugins/Platform/MacOSX/PlatformDarwinKernel.cpp @@ -328,7 +328,7 @@ void PlatformDarwinKernel::CollectKextAndKernelDirectories() { // DeveloperDirectory is something like // "/Applications/Xcode.app/Contents/Developer" - std::string developer_dir = GetDeveloperDirectory(); + std::string developer_dir = GetXcodeDeveloperDirectory().GetPath(); if (developer_dir.empty()) developer_dir = "/Applications/Xcode.app/Contents/Developer"; diff --git a/lldb/source/Plugins/Platform/MacOSX/PlatformMacOSX.cpp b/lldb/source/Plugins/Platform/MacOSX/PlatformMacOSX.cpp index 134a4c7c80759..0de249eb0bb85 100644 --- a/lldb/source/Plugins/Platform/MacOSX/PlatformMacOSX.cpp +++ b/lldb/source/Plugins/Platform/MacOSX/PlatformMacOSX.cpp @@ -155,73 +155,36 @@ PlatformMacOSX::~PlatformMacOSX() {} ConstString PlatformMacOSX::GetSDKDirectory(lldb_private::Target &target) { ModuleSP exe_module_sp(target.GetExecutableModule()); - if (exe_module_sp) { - ObjectFile *objfile = exe_module_sp->GetObjectFile(); - if (objfile) { - std::string xcode_contents_path; - std::string default_xcode_sdk; - FileSpec fspec; - llvm::VersionTuple version = objfile->GetSDKVersion(); - if (!version.empty()) { - fspec = HostInfo::GetShlibDir(); - if (fspec) { - std::string path; - xcode_contents_path = fspec.GetPath(); - size_t pos = xcode_contents_path.find("/Xcode.app/Contents/"); - if (pos != std::string::npos) { - // LLDB.framework is inside an Xcode app bundle, we can locate the - // SDK from here - xcode_contents_path.erase(pos + strlen("/Xcode.app/Contents/")); - } else { - xcode_contents_path.clear(); - // Use the selected Xcode - int status = 0; - int signo = 0; - std::string output; - const char *command = "xcrun -sdk macosx --show-sdk-path"; - lldb_private::Status error = RunShellCommand( - command, // shell command to run - FileSpec(), // current working directory - &status, // Put the exit status of the process in here - &signo, // Put the signal that caused the process to exit in - // here - &output, // Get the output from the command and place it in this - // string - std::chrono::seconds(3)); - if (status == 0 && !output.empty()) { - size_t first_non_newline = output.find_last_not_of("\r\n"); - if (first_non_newline != std::string::npos) - output.erase(first_non_newline + 1); - default_xcode_sdk = output; - - pos = default_xcode_sdk.find("/Xcode.app/Contents/"); - if (pos != std::string::npos) - xcode_contents_path = default_xcode_sdk.substr( - 0, pos + strlen("/Xcode.app/Contents/")); - } - } - } - - if (!xcode_contents_path.empty()) { - StreamString sdk_path; - sdk_path.Printf("%sDeveloper/Platforms/MacOSX.platform/Developer/" - "SDKs/MacOSX%u.%u.sdk", - xcode_contents_path.c_str(), version.getMajor(), - version.getMinor().getValue()); - fspec.SetFile(sdk_path.GetString(), FileSpec::Style::native); - if (FileSystem::Instance().Exists(fspec)) - return ConstString(sdk_path.GetString()); - } + if (!exe_module_sp) + return {}; + + ObjectFile *objfile = exe_module_sp->GetObjectFile(); + if (!objfile) + return {}; + + llvm::VersionTuple version = objfile->GetSDKVersion(); + if (version.empty()) + return {}; + + // First try to find an SDK that matches the given SDK version. + if (FileSpec fspec = GetXcodeContentsDirectory()) { + StreamString sdk_path; + sdk_path.Printf("%s/Developer/Platforms/MacOSX.platform/Developer/" + "SDKs/MacOSX%u.%u.sdk", + fspec.GetPath().c_str(), version.getMajor(), + version.getMinor().getValue()); + if (FileSystem::Instance().Exists(fspec)) + return ConstString(sdk_path.GetString()); + } - if (!default_xcode_sdk.empty()) { - fspec.SetFile(default_xcode_sdk, FileSpec::Style::native); - if (FileSystem::Instance().Exists(fspec)) - return ConstString(default_xcode_sdk); - } - } - } + // Use the default SDK as a fallback. + FileSpec fspec(HostInfo::GetXcodeSDK(lldb_private::XcodeSDK::GetAnyMacOS())); + if (fspec) { + if (FileSystem::Instance().Exists(fspec)) + return ConstString(fspec.GetPath()); } - return ConstString(); + + return {}; } Status PlatformMacOSX::GetSymbolFile(const FileSpec &platform_file, diff --git a/lldb/source/Plugins/Platform/MacOSX/PlatformMacOSX.h b/lldb/source/Plugins/Platform/MacOSX/PlatformMacOSX.h index 5e942f090c943..a4baf9274a8e1 100644 --- a/lldb/source/Plugins/Platform/MacOSX/PlatformMacOSX.h +++ b/lldb/source/Plugins/Platform/MacOSX/PlatformMacOSX.h @@ -73,7 +73,7 @@ class PlatformMacOSX : public PlatformDarwin { AddClangModuleCompilationOptions(lldb_private::Target *target, std::vector &options) override { return PlatformDarwin::AddClangModuleCompilationOptionsForSDKType( - target, options, PlatformDarwin::SDKType::MacOSX); + target, options, lldb_private::XcodeSDK::Type::MacOSX); } private: diff --git a/lldb/source/Plugins/Platform/MacOSX/PlatformRemoteDarwinDevice.cpp b/lldb/source/Plugins/Platform/MacOSX/PlatformRemoteDarwinDevice.cpp index 0aa129c808d43..d13ed3a709fb1 100644 --- a/lldb/source/Plugins/Platform/MacOSX/PlatformRemoteDarwinDevice.cpp +++ b/lldb/source/Plugins/Platform/MacOSX/PlatformRemoteDarwinDevice.cpp @@ -342,9 +342,8 @@ PlatformRemoteDarwinDevice::GetSDKDirectoryForLatestOSVersion() { const char *PlatformRemoteDarwinDevice::GetDeviceSupportDirectory() { std::string platform_dir = "/Platforms/" + GetPlatformName() + "/DeviceSupport"; if (m_device_support_directory.empty()) { - const char *device_support_dir = GetDeveloperDirectory(); - if (device_support_dir) { - m_device_support_directory.assign(device_support_dir); + if (FileSpec fspec = GetXcodeDeveloperDirectory()) { + m_device_support_directory = fspec.GetPath(); m_device_support_directory.append(platform_dir.c_str()); } else { // Assign a single NULL character so we know we tried to find the device diff --git a/lldb/source/Plugins/Platform/MacOSX/PlatformRemoteDarwinDevice.h b/lldb/source/Plugins/Platform/MacOSX/PlatformRemoteDarwinDevice.h index 5e0b7d92bbd4d..5b2bb55b6585a 100644 --- a/lldb/source/Plugins/Platform/MacOSX/PlatformRemoteDarwinDevice.h +++ b/lldb/source/Plugins/Platform/MacOSX/PlatformRemoteDarwinDevice.h @@ -45,7 +45,7 @@ class PlatformRemoteDarwinDevice : public PlatformDarwin { AddClangModuleCompilationOptions(lldb_private::Target *target, std::vector &options) override { return PlatformDarwin::AddClangModuleCompilationOptionsForSDKType( - target, options, PlatformDarwin::SDKType::iPhoneOS); + target, options, lldb_private::XcodeSDK::Type::iPhoneOS); } protected: diff --git a/lldb/source/Plugins/Platform/MacOSX/PlatformiOSSimulator.cpp b/lldb/source/Plugins/Platform/MacOSX/PlatformiOSSimulator.cpp index 6230962c2e29d..fc8243ea26aa2 100644 --- a/lldb/source/Plugins/Platform/MacOSX/PlatformiOSSimulator.cpp +++ b/lldb/source/Plugins/Platform/MacOSX/PlatformiOSSimulator.cpp @@ -261,14 +261,14 @@ EnumerateDirectoryCallback(void *baton, llvm::sys::fs::file_type ft, const char *PlatformiOSSimulator::GetSDKDirectoryAsCString() { std::lock_guard guard(m_sdk_dir_mutex); if (m_sdk_directory.empty()) { - const char *developer_dir = GetDeveloperDirectory(); - if (developer_dir) { + if (FileSpec fspec = GetXcodeDeveloperDirectory()) { + std::string developer_dir = fspec.GetPath(); char sdks_directory[PATH_MAX]; char sdk_dirname[PATH_MAX]; sdk_dirname[0] = '\0'; snprintf(sdks_directory, sizeof(sdks_directory), "%s/Platforms/iPhoneSimulator.platform/Developer/SDKs", - developer_dir); + developer_dir.c_str()); FileSpec simulator_sdk_spec; bool find_directories = true; bool find_files = false; @@ -367,13 +367,12 @@ PlatformiOSSimulator::FindProcesses(const ProcessInstanceInfoMatch &match_info, // Now we filter them down to only the iOS triples for (uint32_t i = 0; i < n; ++i) { - const ProcessInstanceInfo &proc_info = - all_osx_process_infos.GetProcessInfoAtIndex(i); + const ProcessInstanceInfo &proc_info = all_osx_process_infos[i]; if (proc_info.GetArchitecture().GetTriple().getOS() == llvm::Triple::IOS) { - process_infos.Append(proc_info); + process_infos.push_back(proc_info); } } - return process_infos.GetSize(); + return process_infos.size(); } bool PlatformiOSSimulator::GetSupportedArchitectureAtIndex(uint32_t idx, diff --git a/lldb/source/Plugins/Platform/MacOSX/PlatformiOSSimulator.h b/lldb/source/Plugins/Platform/MacOSX/PlatformiOSSimulator.h index d766929b2b891..948488a2853cd 100644 --- a/lldb/source/Plugins/Platform/MacOSX/PlatformiOSSimulator.h +++ b/lldb/source/Plugins/Platform/MacOSX/PlatformiOSSimulator.h @@ -71,7 +71,7 @@ class PlatformiOSSimulator : public PlatformAppleSimulator { AddClangModuleCompilationOptions(lldb_private::Target *target, std::vector &options) override { return PlatformDarwin::AddClangModuleCompilationOptionsForSDKType( - target, options, PlatformDarwin::SDKType::iPhoneSimulator); + target, options, lldb_private::XcodeSDK::Type::iPhoneSimulator); } protected: diff --git a/lldb/source/Plugins/Platform/NetBSD/PlatformNetBSD.cpp b/lldb/source/Plugins/Platform/NetBSD/PlatformNetBSD.cpp index 53f819e6a272c..f3eaffdd3cb75 100644 --- a/lldb/source/Plugins/Platform/NetBSD/PlatformNetBSD.cpp +++ b/lldb/source/Plugins/Platform/NetBSD/PlatformNetBSD.cpp @@ -336,7 +336,7 @@ PlatformNetBSD::DebugProcess(ProcessLaunchInfo &launch_info, Debugger &debugger, } else LLDB_LOG(log, "not using process STDIO pty"); } else { - LLDB_LOG(log, "process launch failed: {0}", error); + LLDB_LOG(log, "{0}", error); // FIXME figure out appropriate cleanup here. Do we delete the target? Do // we delete the process? Does our caller do that? } diff --git a/lldb/source/Plugins/Platform/POSIX/CMakeLists.txt b/lldb/source/Plugins/Platform/POSIX/CMakeLists.txt index 749407d63d5c9..c4c62e46add3d 100644 --- a/lldb/source/Plugins/Platform/POSIX/CMakeLists.txt +++ b/lldb/source/Plugins/Platform/POSIX/CMakeLists.txt @@ -7,4 +7,5 @@ add_lldb_library(lldbPluginPlatformPOSIX PLUGIN lldbHost lldbInterpreter lldbTarget + lldbPluginTypeSystemClang ) diff --git a/lldb/source/Plugins/Platform/POSIX/PlatformPOSIX.cpp b/lldb/source/Plugins/Platform/POSIX/PlatformPOSIX.cpp index 71da7cccbce31..e719cdb2fb38d 100644 --- a/lldb/source/Plugins/Platform/POSIX/PlatformPOSIX.cpp +++ b/lldb/source/Plugins/Platform/POSIX/PlatformPOSIX.cpp @@ -8,6 +8,7 @@ #include "PlatformPOSIX.h" +#include "Plugins/TypeSystem/Clang/TypeSystemClang.h" #include "lldb/Core/Debugger.h" #include "lldb/Core/Module.h" #include "lldb/Core/ModuleSpec.h" @@ -22,7 +23,6 @@ #include "lldb/Host/Host.h" #include "lldb/Host/HostInfo.h" #include "lldb/Host/ProcessLaunchInfo.h" -#include "lldb/Symbol/TypeSystemClang.h" #include "lldb/Target/DynamicLoader.h" #include "lldb/Target/ExecutionContext.h" #include "lldb/Target/Process.h" diff --git a/lldb/source/Plugins/Platform/Windows/PlatformWindows.cpp b/lldb/source/Plugins/Platform/Windows/PlatformWindows.cpp index c18939faa8f77..3981e96989b95 100644 --- a/lldb/source/Plugins/Platform/Windows/PlatformWindows.cpp +++ b/lldb/source/Plugins/Platform/Windows/PlatformWindows.cpp @@ -20,7 +20,10 @@ #include "lldb/Core/Module.h" #include "lldb/Core/ModuleSpec.h" #include "lldb/Core/PluginManager.h" +#include "lldb/Core/ValueObject.h" +#include "lldb/Expression/UserExpression.h" #include "lldb/Host/HostInfo.h" +#include "lldb/Target/DynamicLoader.h" #include "lldb/Target/Process.h" #include "lldb/Utility/Status.h" @@ -306,6 +309,111 @@ Status PlatformWindows::DisconnectRemote() { return error; } +Status PlatformWindows::EvaluateLoaderExpression(Process *process, + const char *expression, + ValueObjectSP &value) { + // FIXME(compnerd) `-fdeclspec` is not passed to the clang instance? + static const char kLoaderDecls[] = + R"( + // libloaderapi.h + + // WINBASEAPI BOOL WINAPI FreeModule(HMODULE); + extern "C" /* __declspec(dllimport) */ BOOL __stdcall FreeModule(void *hLibModule); + + // WINBASEAPI HMODULE WINAPI LoadLibraryA(LPCSTR); + extern "C" /* __declspec(dllimport) */ void * __stdcall LoadLibraryA(const char *); + )"; + + if (DynamicLoader *loader = process->GetDynamicLoader()) { + Status result = loader->CanLoadImage(); + if (result.Fail()) + return result; + } + + ThreadSP thread = process->GetThreadList().GetExpressionExecutionThread(); + if (!thread) + return Status("selected thread is invalid"); + + StackFrameSP frame = thread->GetStackFrameAtIndex(0); + if (!frame) + return Status("frame 0 is invalid"); + + ExecutionContext context; + frame->CalculateExecutionContext(context); + + EvaluateExpressionOptions options; + options.SetUnwindOnError(true); + options.SetIgnoreBreakpoints(true); + options.SetExecutionPolicy(eExecutionPolicyAlways); + options.SetLanguage(eLanguageTypeC_plus_plus); + // LoadLibrary{A,W}/FreeLibrary cannot raise exceptions which we can handle. + // They may potentially throw SEH exceptions which we do not know how to + // handle currently. + options.SetTrapExceptions(false); + options.SetTimeout(process->GetUtilityExpressionTimeout()); + + Status error; + ExpressionResults result = UserExpression::Evaluate( + context, options, expression, kLoaderDecls, value, error); + if (result != eExpressionCompleted) + return error; + + if (value->GetError().Fail()) + return value->GetError(); + + return Status(); +} + +uint32_t PlatformWindows::DoLoadImage(Process *process, + const FileSpec &remote_file, + const std::vector *paths, + Status &error, FileSpec *loaded_path) { + if (loaded_path) + loaded_path->Clear(); + + StreamString expression; + expression.Printf("LoadLibraryA(\"%s\")", remote_file.GetPath().c_str()); + + ValueObjectSP value; + Status result = + EvaluateLoaderExpression(process, expression.GetData(), value); + if (result.Fail()) + return LLDB_INVALID_IMAGE_TOKEN; + + Scalar scalar; + if (value->ResolveValue(scalar)) { + lldb::addr_t address = scalar.ULongLong(); + if (address == 0) + return LLDB_INVALID_IMAGE_TOKEN; + return process->AddImageToken(address); + } + return LLDB_INVALID_IMAGE_TOKEN; +} + +Status PlatformWindows::UnloadImage(Process *process, uint32_t image_token) { + const addr_t address = process->GetImagePtrFromToken(image_token); + if (address == LLDB_INVALID_ADDRESS) + return Status("invalid image token"); + + StreamString expression; + expression.Printf("FreeLibrary((HMODULE)0x%" PRIx64 ")", address); + + ValueObjectSP value; + Status result = + EvaluateLoaderExpression(process, expression.GetData(), value); + if (result.Fail()) + return result; + + Scalar scalar; + if (value->ResolveValue(scalar)) { + if (scalar.UInt(1)) + return Status("expression failed: \"%s\"", expression.GetData()); + process->ResetImageToken(image_token); + } + + return Status(); +} + ProcessSP PlatformWindows::DebugProcess(ProcessLaunchInfo &launch_info, Debugger &debugger, Target *target, Status &error) { diff --git a/lldb/source/Plugins/Platform/Windows/PlatformWindows.h b/lldb/source/Plugins/Platform/Windows/PlatformWindows.h index 5740001f0e036..1ca747aa14ec4 100644 --- a/lldb/source/Plugins/Platform/Windows/PlatformWindows.h +++ b/lldb/source/Plugins/Platform/Windows/PlatformWindows.h @@ -49,6 +49,15 @@ class PlatformWindows : public RemoteAwarePlatform { lldb_private::Status DisconnectRemote() override; + uint32_t DoLoadImage(lldb_private::Process *process, + const lldb_private::FileSpec &remote_file, + const std::vector *paths, + lldb_private::Status &error, + lldb_private::FileSpec *loaded_path) override; + + lldb_private::Status UnloadImage(lldb_private::Process *process, + uint32_t image_token) override; + lldb::ProcessSP DebugProcess(lldb_private::ProcessLaunchInfo &launch_info, lldb_private::Debugger &debugger, lldb_private::Target *target, @@ -73,6 +82,10 @@ class PlatformWindows : public RemoteAwarePlatform { private: DISALLOW_COPY_AND_ASSIGN(PlatformWindows); + + lldb_private::Status EvaluateLoaderExpression(lldb_private::Process *process, + const char *expression, + lldb::ValueObjectSP &value); }; } // namespace lldb_private diff --git a/lldb/source/Plugins/Process/Utility/HistoryThread.cpp b/lldb/source/Plugins/Process/Utility/HistoryThread.cpp index 295c17e474fba..86d807305e4c3 100644 --- a/lldb/source/Plugins/Process/Utility/HistoryThread.cpp +++ b/lldb/source/Plugins/Process/Utility/HistoryThread.cpp @@ -25,12 +25,13 @@ using namespace lldb_private; // Constructor HistoryThread::HistoryThread(lldb_private::Process &process, lldb::tid_t tid, - std::vector pcs) + std::vector pcs, + bool pcs_are_call_addresses) : Thread(process, tid, true), m_framelist_mutex(), m_framelist(), m_pcs(pcs), m_extended_unwind_token(LLDB_INVALID_ADDRESS), m_queue_name(), m_thread_name(), m_originating_unique_thread_id(tid), m_queue_id(LLDB_INVALID_QUEUE_ID) { - m_unwinder_up.reset(new HistoryUnwind(*this, pcs)); + m_unwinder_up.reset(new HistoryUnwind(*this, pcs, pcs_are_call_addresses)); Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_OBJECT)); LLDB_LOGF(log, "%p HistoryThread::HistoryThread", static_cast(this)); } diff --git a/lldb/source/Plugins/Process/Utility/HistoryThread.h b/lldb/source/Plugins/Process/Utility/HistoryThread.h index 1e26586401724..2428e1209d0dc 100644 --- a/lldb/source/Plugins/Process/Utility/HistoryThread.h +++ b/lldb/source/Plugins/Process/Utility/HistoryThread.h @@ -33,7 +33,8 @@ namespace lldb_private { class HistoryThread : public lldb_private::Thread { public: HistoryThread(lldb_private::Process &process, lldb::tid_t tid, - std::vector pcs); + std::vector pcs, + bool pcs_are_call_addresses = false); ~HistoryThread() override; diff --git a/lldb/source/Plugins/Process/Utility/HistoryUnwind.cpp b/lldb/source/Plugins/Process/Utility/HistoryUnwind.cpp index 83fdb011f5a1a..5e07b7593d492 100644 --- a/lldb/source/Plugins/Process/Utility/HistoryUnwind.cpp +++ b/lldb/source/Plugins/Process/Utility/HistoryUnwind.cpp @@ -23,8 +23,10 @@ using namespace lldb_private; // Constructor -HistoryUnwind::HistoryUnwind(Thread &thread, std::vector pcs) - : Unwind(thread), m_pcs(pcs) {} +HistoryUnwind::HistoryUnwind(Thread &thread, std::vector pcs, + bool pcs_are_call_addresses) + : Unwind(thread), m_pcs(pcs), + m_pcs_are_call_addresses(pcs_are_call_addresses) {} // Destructor @@ -59,7 +61,10 @@ bool HistoryUnwind::DoGetFrameInfoAtIndex(uint32_t frame_idx, lldb::addr_t &cfa, if (frame_idx < m_pcs.size()) { cfa = frame_idx; pc = m_pcs[frame_idx]; - behaves_like_zeroth_frame = (frame_idx == 0); + if (m_pcs_are_call_addresses) + behaves_like_zeroth_frame = true; + else + behaves_like_zeroth_frame = (frame_idx == 0); return true; } return false; diff --git a/lldb/source/Plugins/Process/Utility/HistoryUnwind.h b/lldb/source/Plugins/Process/Utility/HistoryUnwind.h index 4d16608bd8c27..ddbee00fc7aa1 100644 --- a/lldb/source/Plugins/Process/Utility/HistoryUnwind.h +++ b/lldb/source/Plugins/Process/Utility/HistoryUnwind.h @@ -18,7 +18,8 @@ namespace lldb_private { class HistoryUnwind : public lldb_private::Unwind { public: - HistoryUnwind(Thread &thread, std::vector pcs); + HistoryUnwind(Thread &thread, std::vector pcs, + bool pcs_are_call_addresses = false); ~HistoryUnwind() override; @@ -35,6 +36,9 @@ class HistoryUnwind : public lldb_private::Unwind { private: std::vector m_pcs; + /// This boolean indicates that the PCs in the non-0 frames are call + /// addresses and not return addresses. + bool m_pcs_are_call_addresses; }; } // namespace lldb_private diff --git a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunication.cpp b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunication.cpp index 7cea013eea7fa..05a83ed83f7b7 100644 --- a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunication.cpp +++ b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunication.cpp @@ -810,31 +810,9 @@ GDBRemoteCommunication::CheckForPacket(const uint8_t *src, size_t src_len, GDBRemotePacket::ePacketTypeRecv, total_length); // Copy the packet from m_bytes to packet_str expanding the run-length - // encoding in the process. Reserve enough byte for the most common case - // (no RLE used) - std ::string packet_str; - packet_str.reserve(m_bytes.length()); - for (std::string::const_iterator c = m_bytes.begin() + content_start; - c != m_bytes.begin() + content_end; ++c) { - if (*c == '*') { - // '*' indicates RLE. Next character will give us the repeat count - // and previous character is what is to be repeated. - char char_to_repeat = packet_str.back(); - // Number of time the previous character is repeated - int repeat_count = *++c + 3 - ' '; - // We have the char_to_repeat and repeat_count. Now push it in the - // packet. - for (int i = 0; i < repeat_count; ++i) - packet_str.push_back(char_to_repeat); - } else if (*c == 0x7d) { - // 0x7d is the escape character. The next character is to be XOR'd - // with 0x20. - char escapee = *++c ^ 0x20; - packet_str.push_back(escapee); - } else { - packet_str.push_back(*c); - } - } + // encoding in the process. + std ::string packet_str = + ExpandRLE(m_bytes.substr(content_start, content_end - content_start)); packet = StringExtractorGDBRemote(packet_str); if (m_bytes[0] == '$' || m_bytes[0] == '%') { @@ -1382,3 +1360,30 @@ void llvm::format_provider::format( break; } } + +std::string GDBRemoteCommunication::ExpandRLE(std::string packet) { + // Reserve enough byte for the most common case (no RLE used). + std::string decoded; + decoded.reserve(packet.size()); + for (std::string::const_iterator c = packet.begin(); c != packet.end(); ++c) { + if (*c == '*') { + // '*' indicates RLE. Next character will give us the repeat count and + // previous character is what is to be repeated. + char char_to_repeat = decoded.back(); + // Number of time the previous character is repeated. + int repeat_count = *++c + 3 - ' '; + // We have the char_to_repeat and repeat_count. Now push it in the + // packet. + for (int i = 0; i < repeat_count; ++i) + decoded.push_back(char_to_repeat); + } else if (*c == 0x7d) { + // 0x7d is the escape character. The next character is to be XOR'd with + // 0x20. + char escapee = *++c ^ 0x20; + decoded.push_back(escapee); + } else { + decoded.push_back(*c); + } + } + return decoded; +} diff --git a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunication.h b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunication.h index 0b670018bd693..89a1a4aa342b4 100644 --- a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunication.h +++ b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunication.h @@ -142,6 +142,9 @@ class GDBRemoteCommunication : public Communication { static llvm::Error ConnectLocally(GDBRemoteCommunication &client, GDBRemoteCommunication &server); + /// Expand GDB run-length encoding. + static std::string ExpandRLE(std::string); + protected: std::chrono::seconds m_packet_timeout; uint32_t m_echo_number; diff --git a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp index c094d8f51c911..0169df8c882c0 100644 --- a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp +++ b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp @@ -1123,6 +1123,20 @@ bool GDBRemoteCommunicationClient::GetDefaultThreadId(lldb::tid_t &tid) { return true; } +static void ParseOSType(llvm::StringRef value, std::string &os_name, + std::string &environment) { + if (value.equals("iossimulator") || value.equals("tvossimulator") || + value.equals("watchossimulator")) { + environment = "simulator"; + os_name = value.drop_back(environment.size()).str(); + } else if (value.equals("maccatalyst")) { + os_name = "ios"; + environment = "macabi"; + } else { + os_name = value.str(); + } +} + bool GDBRemoteCommunicationClient::GetHostInfo(bool force) { Log *log(ProcessGDBRemoteLog::GetLogIfAnyCategoryIsSet(GDBR_LOG_PROCESS)); @@ -1181,11 +1195,7 @@ bool GDBRemoteCommunicationClient::GetHostInfo(bool force) { extractor.GetHexByteString(m_os_kernel); ++num_keys_decoded; } else if (name.equals("ostype")) { - if (value.equals("maccatalyst")) { - os_name = "ios"; - environment = "macabi"; - } else - os_name = value; + ParseOSType(value, os_name, environment); ++num_keys_decoded; } else if (name.equals("vendor")) { vendor_name = value; @@ -2045,11 +2055,7 @@ bool GDBRemoteCommunicationClient::GetCurrentProcessInfo(bool allow_lazy) { extractor.GetHexByteString(triple); ++num_keys_decoded; } else if (name.equals("ostype")) { - if (value.equals("maccatalyst")) { - os_name = "ios"; - environment = "macabi"; - } else - os_name = value; + ParseOSType(value, os_name, environment); ++num_keys_decoded; } else if (name.equals("vendor")) { vendor_name = value; @@ -2140,7 +2146,7 @@ bool GDBRemoteCommunicationClient::GetCurrentProcessInfo(bool allow_lazy) { uint32_t GDBRemoteCommunicationClient::FindProcesses( const ProcessInstanceInfoMatch &match_info, ProcessInstanceInfoList &process_infos) { - process_infos.Clear(); + process_infos.clear(); if (m_supports_qfProcessInfo) { StreamString packet; @@ -2220,7 +2226,7 @@ uint32_t GDBRemoteCommunicationClient::FindProcesses( ProcessInstanceInfo process_info; if (!DecodeProcessInfoResponse(response, process_info)) break; - process_infos.Append(process_info); + process_infos.push_back(process_info); response = StringExtractorGDBRemote(); } while (SendPacketAndWaitForResponse("qsProcessInfo", response, false) == PacketResult::Success); @@ -2229,7 +2235,7 @@ uint32_t GDBRemoteCommunicationClient::FindProcesses( return 0; } } - return process_infos.GetSize(); + return process_infos.size(); } bool GDBRemoteCommunicationClient::GetUserName(uint32_t uid, diff --git a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.h b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.h index 11fd40bce44f7..2edcb4d0421a7 100644 --- a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.h +++ b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.h @@ -20,6 +20,7 @@ #include "lldb/Host/File.h" #include "lldb/Utility/ArchSpec.h" #include "lldb/Utility/GDBRemote.h" +#include "lldb/Utility/ProcessInfo.h" #include "lldb/Utility/StructuredData.h" #if defined(_WIN32) #include "lldb/Host/windows/PosixApi.h" diff --git a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationReplayServer.cpp b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationReplayServer.cpp index 15c73e78bd444..1a2c55fc1eb1d 100644 --- a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationReplayServer.cpp +++ b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationReplayServer.cpp @@ -131,22 +131,26 @@ GDBRemoteCommunicationReplayServer::GetPacketAndSendResponse( GDBRemotePacket entry = m_packet_history.back(); m_packet_history.pop_back(); + // Decode run-length encoding. + const std::string expanded_data = + GDBRemoteCommunication::ExpandRLE(entry.packet.data); + // We've handled the handshake implicitly before. Skip the packet and move // on. if (entry.packet.data == "+") continue; if (entry.type == GDBRemotePacket::ePacketTypeSend) { - if (unexpected(entry.packet.data, packet.GetStringRef())) { + if (unexpected(expanded_data, packet.GetStringRef())) { LLDB_LOG(log, "GDBRemoteCommunicationReplayServer expected packet: '{0}'", - entry.packet.data); + expanded_data); LLDB_LOG(log, "GDBRemoteCommunicationReplayServer actual packet: '{0}'", packet.GetStringRef()); #ifndef NDEBUG // This behaves like a regular assert, but prints the expected and // received packet before aborting. - printf("Reproducer expected packet: '%s'\n", entry.packet.data.c_str()); + printf("Reproducer expected packet: '%s'\n", expanded_data.c_str()); printf("Reproducer received packet: '%s'\n", packet.GetStringRef().data()); llvm::report_fatal_error("Encountered unexpected packet during replay"); @@ -155,7 +159,7 @@ GDBRemoteCommunicationReplayServer::GetPacketAndSendResponse( } // Ignore QEnvironment packets as they're handled earlier. - if (entry.packet.data.find("QEnvironment") == 1) { + if (expanded_data.find("QEnvironment") == 1) { assert(m_packet_history.back().type == GDBRemotePacket::ePacketTypeRecv); m_packet_history.pop_back(); diff --git a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerCommon.cpp b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerCommon.cpp index 4b5fc0774a6d2..7326316623bc3 100644 --- a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerCommon.cpp +++ b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerCommon.cpp @@ -334,7 +334,7 @@ GDBRemoteCommunication::PacketResult GDBRemoteCommunicationServerCommon::Handle_qfProcessInfo( StringExtractorGDBRemote &packet) { m_proc_infos_index = 0; - m_proc_infos.Clear(); + m_proc_infos.clear(); ProcessInstanceInfoMatch match_info; packet.SetFilePos(::strlen("qfProcessInfo")); @@ -416,10 +416,9 @@ GDBRemoteCommunicationServerCommon::Handle_qfProcessInfo( GDBRemoteCommunication::PacketResult GDBRemoteCommunicationServerCommon::Handle_qsProcessInfo( StringExtractorGDBRemote &packet) { - if (m_proc_infos_index < m_proc_infos.GetSize()) { + if (m_proc_infos_index < m_proc_infos.size()) { StreamString response; - CreateProcessInfoResponse( - m_proc_infos.GetProcessInfoAtIndex(m_proc_infos_index), response); + CreateProcessInfoResponse(m_proc_infos[m_proc_infos_index], response); ++m_proc_infos_index; return SendPacketNoLock(response.GetString()); } diff --git a/lldb/source/Plugins/ScriptInterpreter/Python/ScriptInterpreterPython.cpp b/lldb/source/Plugins/ScriptInterpreter/Python/ScriptInterpreterPython.cpp index 1bb3cde7ab241..56cf9ee5caa46 100644 --- a/lldb/source/Plugins/ScriptInterpreter/Python/ScriptInterpreterPython.cpp +++ b/lldb/source/Plugins/ScriptInterpreter/Python/ScriptInterpreterPython.cpp @@ -2748,6 +2748,7 @@ bool ScriptInterpreterPythonImpl::LoadScriptingModule( { FileSpec target_file(pathname); FileSystem::Instance().Resolve(target_file); + FileSystem::Instance().Collect(target_file); std::string basename(target_file.GetFilename().GetCString()); StreamString command_stream; diff --git a/lldb/source/Plugins/SymbolFile/DWARF/CMakeLists.txt b/lldb/source/Plugins/SymbolFile/DWARF/CMakeLists.txt index 9731864e82b29..33b45ccce530b 100644 --- a/lldb/source/Plugins/SymbolFile/DWARF/CMakeLists.txt +++ b/lldb/source/Plugins/SymbolFile/DWARF/CMakeLists.txt @@ -54,6 +54,7 @@ add_lldb_library(lldbPluginSymbolFileDWARF PLUGIN lldbPluginObjCLanguage lldbPluginCPlusPlusLanguage lldbPluginExpressionParserClang + lldbPluginTypeSystemClang CLANG_LIBS clangAST clangBasic diff --git a/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.cpp b/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.cpp index c07ac9bc252ba..f3077c4cdfade 100644 --- a/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.cpp +++ b/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.cpp @@ -17,13 +17,13 @@ #include "SymbolFileDWARFDebugMap.h" #include "UniqueDWARFASTType.h" +#include "Plugins/ExpressionParser/Clang/ClangASTImporter.h" +#include "Plugins/ExpressionParser/Clang/ClangASTMetadata.h" +#include "Plugins/ExpressionParser/Clang/ClangUtil.h" #include "Plugins/Language/ObjC/ObjCLanguage.h" #include "lldb/Core/Module.h" #include "lldb/Core/Value.h" #include "lldb/Host/Host.h" -#include "lldb/Symbol/ClangASTImporter.h" -#include "lldb/Symbol/ClangASTMetadata.h" -#include "lldb/Symbol/ClangUtil.h" #include "lldb/Symbol/CompileUnit.h" #include "lldb/Symbol/Function.h" #include "lldb/Symbol/ObjectFile.h" @@ -35,6 +35,8 @@ #include "lldb/Utility/Log.h" #include "lldb/Utility/StreamString.h" +#include "llvm/Demangle/Demangle.h" + #include "clang/AST/CXXInheritance.h" #include "clang/AST/DeclCXX.h" #include "clang/AST/DeclObjC.h" @@ -1169,12 +1171,22 @@ TypeSP DWARFASTParserClang::ParseSubroutine(const DWARFDIE &die, } if (!function_decl) { + const char *name = attrs.name.GetCString(); + + // We currently generate function templates with template parameters in + // their name. In order to get closer to the AST that clang generates + // we want to strip these from the name when creating the AST. + if (attrs.mangled_name) { + llvm::ItaniumPartialDemangler D; + if (!D.partialDemangle(attrs.mangled_name)) + name = D.getFunctionBaseName(nullptr, nullptr); + } + // We just have a function that isn't part of a class function_decl = m_ast.CreateFunctionDeclaration( ignore_containing_context ? m_ast.GetTranslationUnitDecl() : containing_decl_ctx, - attrs.name.GetCString(), clang_type, attrs.storage, - attrs.is_inline); + name, clang_type, attrs.storage, attrs.is_inline); if (has_template_params) { TypeSystemClang::TemplateParameterInfos template_param_infos; @@ -1182,14 +1194,14 @@ TypeSP DWARFASTParserClang::ParseSubroutine(const DWARFDIE &die, template_function_decl = m_ast.CreateFunctionDeclaration( ignore_containing_context ? m_ast.GetTranslationUnitDecl() : containing_decl_ctx, - attrs.name.GetCString(), clang_type, attrs.storage, - attrs.is_inline); + name, clang_type, attrs.storage, attrs.is_inline); + clang::FunctionTemplateDecl *func_template_decl = - m_ast.CreateFunctionTemplateDecl( - containing_decl_ctx, template_function_decl, - attrs.name.GetCString(), template_param_infos); + m_ast.CreateFunctionTemplateDecl(containing_decl_ctx, + template_function_decl, name, + template_param_infos); m_ast.CreateFunctionTemplateSpecializationInfo( - function_decl, func_template_decl, template_param_infos); + template_function_decl, func_template_decl, template_param_infos); } lldbassert(function_decl); @@ -1625,12 +1637,11 @@ DWARFASTParserClang::ParseStructureLikeDIE(const SymbolContext &sc, // parameters in any class methods need it for the clang types for // function prototypes. LinkDeclContextToDIE(m_ast.GetDeclContextForType(clang_type), die); - type_sp = std::make_shared(die.GetID(), dwarf, attrs.name, - attrs.byte_size, nullptr, LLDB_INVALID_UID, - Type::eEncodingIsUID, &attrs.decl, - clang_type, Type::ResolveState::Forward); - - type_sp->SetIsCompleteObjCClass(attrs.is_complete_objc_class); + type_sp = std::make_shared( + die.GetID(), dwarf, attrs.name, attrs.byte_size, nullptr, + LLDB_INVALID_UID, Type::eEncodingIsUID, &attrs.decl, clang_type, + Type::ResolveState::Forward, + TypePayloadClang(attrs.is_complete_objc_class)); // Add our type to the unique type map so we don't end up creating many // copies of the same type over and over in the ASTContext for our @@ -2708,9 +2719,19 @@ void DWARFASTParserClang::ParseSingleMember( } // If we have a gap between the last_field_end and the current - // field we have an unnamed bit-field + // field we have an unnamed bit-field. + // If we have a base class, we assume there is no unnamed + // bit-field if this is the first field since the gap can be + // attributed to the members from the base class. This assumption + // is not correct if the first field of the derived class is + // indeed an unnamed bit-field. We currently do not have the + // machinary to track the offset of the last field of classes we + // have seen before, so we are not handling this case. if (this_field_info.bit_offset != last_field_end && - !(this_field_info.bit_offset < last_field_end)) { + this_field_info.bit_offset > last_field_end && + !(last_field_info.bit_offset == 0 && + last_field_info.bit_size == 0 && + layout_info.base_offsets.size() != 0)) { unnamed_field_info = FieldInfo{}; unnamed_field_info->bit_size = this_field_info.bit_offset - last_field_end; diff --git a/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.h b/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.h index 6cd2dc8bf5580..9282131301f5d 100644 --- a/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.h +++ b/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.h @@ -21,8 +21,9 @@ #include "LogChannelDWARF.h" #include "lldb/Core/ClangForward.h" #include "lldb/Core/PluginInterface.h" -#include "lldb/Symbol/TypeSystemClang.h" -#include "lldb/Symbol/ClangASTImporter.h" + +#include "Plugins/ExpressionParser/Clang/ClangASTImporter.h" +#include "Plugins/TypeSystem/Clang/TypeSystemClang.h" #include diff --git a/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserSwift.cpp b/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserSwift.cpp index a77519fcc38aa..5265fe0c0c57d 100644 --- a/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserSwift.cpp +++ b/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserSwift.cpp @@ -25,8 +25,8 @@ #include "clang/AST/DeclObjC.h" +#include "Plugins/TypeSystem/Clang/TypeSystemClang.h" #include "lldb/Core/Module.h" -#include "lldb/Symbol/TypeSystemClang.h" #include "lldb/Symbol/CompileUnit.h" #include "lldb/Symbol/Function.h" #include "lldb/Symbol/ObjectFile.h" @@ -130,7 +130,7 @@ lldb::TypeSP DWARFASTParserSwift::ParseTypeFromDWARF(const SymbolContext &sc, if (auto wrapped_type = get_type(die.GetFirstChild())) { // Create a unique pointer for the type + fixed buffer flag. type_sp.reset(new Type(*wrapped_type)); - type_sp->SetSwiftFixedValueBuffer(true); + type_sp->SetPayload(TypePayloadSwift(true)); return type_sp; } } diff --git a/lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugInfoEntry.cpp b/lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugInfoEntry.cpp index 5612c59059bed..9c8ea07ee73e8 100644 --- a/lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugInfoEntry.cpp +++ b/lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugInfoEntry.cpp @@ -1230,6 +1230,29 @@ DWARFDebugInfoEntry::GetAbbreviationDeclarationPtr(const DWARFUnit *cu) const { return nullptr; } +bool DWARFDebugInfoEntry::IsGlobalOrStaticVariable() const { + if (Tag() != DW_TAG_variable) + return false; + const DWARFDebugInfoEntry *parent_die = GetParent(); + while (parent_die != nullptr) { + switch (parent_die->Tag()) { + case DW_TAG_subprogram: + case DW_TAG_lexical_block: + case DW_TAG_inlined_subroutine: + return false; + + case DW_TAG_compile_unit: + case DW_TAG_partial_unit: + return true; + + default: + break; + } + parent_die = parent_die->GetParent(); + } + return false; +} + bool DWARFDebugInfoEntry::operator==(const DWARFDebugInfoEntry &rhs) const { return m_offset == rhs.m_offset && m_parent_idx == rhs.m_parent_idx && m_sibling_idx == rhs.m_sibling_idx && diff --git a/lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugInfoEntry.h b/lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugInfoEntry.h index f35af6e7d498a..666d7070f4fe9 100644 --- a/lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugInfoEntry.h +++ b/lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugInfoEntry.h @@ -172,6 +172,8 @@ class DWARFDebugInfoEntry { void SetSiblingIndex(uint32_t idx) { m_sibling_idx = idx; } void SetParentIndex(uint32_t idx) { m_parent_idx = idx; } + bool IsGlobalOrStaticVariable() const; + protected: dw_offset_t m_offset; // Offset within the .debug_info/.debug_types uint32_t m_parent_idx; // How many to subtract from "this" to get the parent. diff --git a/lldb/source/Plugins/SymbolFile/DWARF/DWARFUnit.h b/lldb/source/Plugins/SymbolFile/DWARF/DWARFUnit.h index d53ed756fe05d..1ac286a8a52d5 100644 --- a/lldb/source/Plugins/SymbolFile/DWARF/DWARFUnit.h +++ b/lldb/source/Plugins/SymbolFile/DWARF/DWARFUnit.h @@ -12,6 +12,7 @@ #include "DWARFDIE.h" #include "DWARFDebugInfoEntry.h" #include "lldb/lldb-enumerations.h" +#include "lldb/Utility/XcodeSDK.h" #include "llvm/Support/RWMutex.h" #include diff --git a/lldb/source/Plugins/SymbolFile/DWARF/ManualDWARFIndex.cpp b/lldb/source/Plugins/SymbolFile/DWARF/ManualDWARFIndex.cpp index e8a095cffb291..cd706b2f16b3b 100644 --- a/lldb/source/Plugins/SymbolFile/DWARF/ManualDWARFIndex.cpp +++ b/lldb/source/Plugins/SymbolFile/DWARF/ManualDWARFIndex.cpp @@ -170,12 +170,6 @@ void ManualDWARFIndex::IndexUnitImpl(DWARFUnit &unit, is_declaration = form_value.Unsigned() != 0; break; - // case DW_AT_artificial: - // if (attributes.ExtractFormValueAtIndex(i, - // form_value)) - // is_artificial = form_value.Unsigned() != 0; - // break; - case DW_AT_MIPS_linkage_name: case DW_AT_linkage_name: if (attributes.ExtractFormValueAtIndex(i, form_value)) @@ -195,49 +189,8 @@ void ManualDWARFIndex::IndexUnitImpl(DWARFUnit &unit, case DW_AT_location: case DW_AT_const_value: has_location_or_const_value = true; - if (tag == DW_TAG_variable) { - const DWARFDebugInfoEntry *parent_die = die.GetParent(); - while (parent_die != nullptr) { - switch (parent_die->Tag()) { - case DW_TAG_subprogram: - case DW_TAG_lexical_block: - case DW_TAG_inlined_subroutine: - // Even if this is a function level static, we don't add it. We - // could theoretically add these if we wanted to by - // introspecting into the DW_AT_location and seeing if the - // location describes a hard coded address, but we don't want - // the performance penalty of that right now. - is_global_or_static_variable = false; - // if (attributes.ExtractFormValueAtIndex(dwarf, i, - // form_value)) { - // // If we have valid block data, then we have location - // // expression bytesthat are fixed (not a location list). - // const uint8_t *block_data = form_value.BlockData(); - // if (block_data) { - // uint32_t block_length = form_value.Unsigned(); - // if (block_length == 1 + - // attributes.UnitAtIndex(i)->GetAddressByteSize()) { - // if (block_data[0] == DW_OP_addr) - // add_die = true; - // } - // } - // } - parent_die = nullptr; // Terminate the while loop. - break; - - case DW_TAG_compile_unit: - case DW_TAG_partial_unit: - is_global_or_static_variable = true; - parent_die = nullptr; // Terminate the while loop. - break; - - default: - parent_die = - parent_die->GetParent(); // Keep going in the while loop. - break; - } - } - } + is_global_or_static_variable = die.IsGlobalOrStaticVariable(); + break; case DW_AT_specification: diff --git a/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp b/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp index 702ce1ea45559..36ca1bdee6ac3 100644 --- a/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp +++ b/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp @@ -35,9 +35,9 @@ #include "lldb/Interpreter/OptionValueFileSpecList.h" #include "lldb/Interpreter/OptionValueProperties.h" +#include "Plugins/ExpressionParser/Clang/ClangUtil.h" +#include "Plugins/TypeSystem/Clang/TypeSystemClang.h" #include "lldb/Symbol/Block.h" -#include "lldb/Symbol/TypeSystemClang.h" -#include "lldb/Symbol/ClangUtil.h" #include "lldb/Symbol/CompileUnit.h" #include "lldb/Symbol/CompilerDecl.h" #include "lldb/Symbol/CompilerDeclContext.h" @@ -690,6 +690,22 @@ DWARFDebugRanges *SymbolFileDWARF::GetDebugRanges() { return m_ranges.get(); } +/// Make an absolute path out of \p file_spec and remap it using the +/// module's source remapping dictionary. +static void MakeAbsoluteAndRemap(FileSpec &file_spec, DWARFUnit &dwarf_cu, + const ModuleSP &module_sp) { + if (!file_spec) + return; + // If we have a full path to the compile unit, we don't need to + // resolve the file. This can be expensive e.g. when the source + // files are NFS mounted. + file_spec.MakeAbsolute(dwarf_cu.GetCompilationDirectory()); + + std::string remapped_file; + if (module_sp->RemapSourceFile(file_spec.GetPath(), remapped_file)) + file_spec.SetFile(remapped_file, FileSpec::Style::native); +} + lldb::CompUnitSP SymbolFileDWARF::ParseCompileUnit(DWARFCompileUnit &dwarf_cu) { CompUnitSP cu_sp; CompileUnit *comp_unit = (CompileUnit *)dwarf_cu.GetUserData(); @@ -708,18 +724,14 @@ lldb::CompUnitSP SymbolFileDWARF::ParseCompileUnit(DWARFCompileUnit &dwarf_cu) { if (module_sp) { const DWARFDIE cu_die = dwarf_cu.DIE(); if (cu_die) { - FileSpec cu_file_spec(cu_die.GetName(), dwarf_cu.GetPathStyle()); - if (cu_file_spec) { - // If we have a full path to the compile unit, we don't need to - // resolve the file. This can be expensive e.g. when the source - // files are NFS mounted. - cu_file_spec.MakeAbsolute(dwarf_cu.GetCompilationDirectory()); - - std::string remapped_file; - if (module_sp->RemapSourceFile(cu_file_spec.GetPath(), - remapped_file)) - cu_file_spec.SetFile(remapped_file, FileSpec::Style::native); + if (const char *sdk = + cu_die.GetAttributeValueAsString(DW_AT_APPLE_sdk, nullptr)) { + const char *sysroot = + cu_die.GetAttributeValueAsString(DW_AT_LLVM_sysroot, ""); + module_sp->RegisterXcodeSDK(sdk, sysroot); } + FileSpec cu_file_spec(cu_die.GetName(), dwarf_cu.GetPathStyle()); + MakeAbsoluteAndRemap(cu_file_spec, dwarf_cu, module_sp); LanguageType cu_language = DWARFUnit::LanguageTypeFromDWARF( cu_die.GetAttributeValueAsUnsigned(DW_AT_language, 0)); @@ -991,8 +1003,11 @@ bool SymbolFileDWARF::ParseImportedModules( } std::reverse(module.path.begin(), module.path.end()); if (const char *include_path = module_die.GetAttributeValueAsString( - DW_AT_LLVM_include_path, nullptr)) - module.search_path = ConstString(include_path); + DW_AT_LLVM_include_path, nullptr)) { + FileSpec include_spec(include_path, dwarf_cu->GetPathStyle()); + MakeAbsoluteAndRemap(include_spec, *dwarf_cu, m_objfile_sp->GetModule()); + module.search_path = ConstString(include_spec.GetPath()); + } if (const char *sysroot = dwarf_cu->DIE().GetAttributeValueAsString( DW_AT_LLVM_sysroot, nullptr)) module.sysroot = ConstString(sysroot); @@ -3620,8 +3635,7 @@ VariableSP SymbolFileDWARF::ParseVariableDIE(const SymbolContext &sc, } } } else { - if (location_is_const_value_data && - !IsSwiftLanguage(sc.comp_unit->GetLanguage())) + if (location_is_const_value_data && die.GetDIE()->IsGlobalOrStaticVariable()) scope = eValueTypeVariableStatic; else { scope = eValueTypeVariableLocal; @@ -3937,6 +3951,7 @@ SymbolFileDWARF::CollectCallEdges(ModuleSP module, DWARFDIE function_die) { llvm::Optional call_origin; llvm::Optional call_target; addr_t return_pc = LLDB_INVALID_ADDRESS; + addr_t call_inst_pc = LLDB_INVALID_ADDRESS; DWARFAttributes attributes; const size_t num_attributes = child.GetAttributes(attributes); @@ -3965,6 +3980,12 @@ SymbolFileDWARF::CollectCallEdges(ModuleSP module, DWARFDIE function_die) { if (attr == DW_AT_call_return_pc) return_pc = form_value.Address(); + // Extract DW_AT_call_pc (the PC at the call/branch instruction). It + // should only ever be unavailable for non-tail calls, in which case use + // LLDB_INVALID_ADDRESS. + if (attr == DW_AT_call_pc) + call_inst_pc = form_value.Address(); + // Extract DW_AT_call_target (the location of the address of the indirect // call). if (attr == DW_AT_call_target) { @@ -3987,10 +4008,11 @@ SymbolFileDWARF::CollectCallEdges(ModuleSP module, DWARFDIE function_die) { continue; } - // Adjust the return PC. It needs to be fixed up if the main executable + // Adjust any PC forms. It needs to be fixed up if the main executable // contains a debug map (i.e. pointers to object files), because we need a // file address relative to the executable's text section. return_pc = FixupAddress(return_pc); + call_inst_pc = FixupAddress(call_inst_pc); // Extract call site parameters. CallSiteParameterArray parameters = @@ -3998,10 +4020,13 @@ SymbolFileDWARF::CollectCallEdges(ModuleSP module, DWARFDIE function_die) { std::unique_ptr edge; if (call_origin) { - LLDB_LOG(log, "CollectCallEdges: Found call origin: {0} (retn-PC: {1:x})", - call_origin->GetPubname(), return_pc); + LLDB_LOG(log, + "CollectCallEdges: Found call origin: {0} (retn-PC: {1:x}) " + "(call-PC: {2:x})", + call_origin->GetPubname(), return_pc, call_inst_pc); edge = std::make_unique(call_origin->GetMangledName(), - return_pc, std::move(parameters)); + return_pc, call_inst_pc, + std::move(parameters)); } else { if (log) { StreamString call_target_desc; @@ -4010,8 +4035,8 @@ SymbolFileDWARF::CollectCallEdges(ModuleSP module, DWARFDIE function_die) { LLDB_LOG(log, "CollectCallEdges: Found indirect call target: {0}", call_target_desc.GetString()); } - edge = std::make_unique(*call_target, return_pc, - std::move(parameters)); + edge = std::make_unique( + *call_target, return_pc, call_inst_pc, std::move(parameters)); } if (log && parameters.size()) { diff --git a/lldb/source/Plugins/SymbolFile/NativePDB/CMakeLists.txt b/lldb/source/Plugins/SymbolFile/NativePDB/CMakeLists.txt index aaecec4765f57..4f19231c346ca 100644 --- a/lldb/source/Plugins/SymbolFile/NativePDB/CMakeLists.txt +++ b/lldb/source/Plugins/SymbolFile/NativePDB/CMakeLists.txt @@ -14,6 +14,7 @@ add_lldb_library(lldbPluginSymbolFileNativePDB PLUGIN lldbCore lldbSymbol lldbUtility + lldbPluginTypeSystemClang CLANG_LIBS clangAST clangLex diff --git a/lldb/source/Plugins/SymbolFile/NativePDB/PdbAstBuilder.cpp b/lldb/source/Plugins/SymbolFile/NativePDB/PdbAstBuilder.cpp index f80d45b8d3402..03cd8ffc53921 100644 --- a/lldb/source/Plugins/SymbolFile/NativePDB/PdbAstBuilder.cpp +++ b/lldb/source/Plugins/SymbolFile/NativePDB/PdbAstBuilder.cpp @@ -14,11 +14,11 @@ #include "llvm/DebugInfo/PDB/Native/TpiStream.h" #include "llvm/Demangle/MicrosoftDemangle.h" +#include "Plugins/ExpressionParser/Clang/ClangASTMetadata.h" +#include "Plugins/ExpressionParser/Clang/ClangUtil.h" #include "Plugins/Language/CPlusPlus/MSVCUndecoratedNameParser.h" +#include "Plugins/TypeSystem/Clang/TypeSystemClang.h" #include "lldb/Core/Module.h" -#include "lldb/Symbol/TypeSystemClang.h" -#include "lldb/Symbol/ClangASTMetadata.h" -#include "lldb/Symbol/ClangUtil.h" #include "lldb/Symbol/ObjectFile.h" #include "lldb/Utility/LLDBAssert.h" diff --git a/lldb/source/Plugins/SymbolFile/NativePDB/PdbAstBuilder.h b/lldb/source/Plugins/SymbolFile/NativePDB/PdbAstBuilder.h index 78f19b85c359c..f31eeb57cc5c0 100644 --- a/lldb/source/Plugins/SymbolFile/NativePDB/PdbAstBuilder.h +++ b/lldb/source/Plugins/SymbolFile/NativePDB/PdbAstBuilder.h @@ -12,7 +12,7 @@ #include "llvm/ADT/DenseMap.h" #include "llvm/ADT/StringRef.h" -#include "lldb/Symbol/ClangASTImporter.h" +#include "Plugins/ExpressionParser/Clang/ClangASTImporter.h" #include "PdbIndex.h" #include "PdbSymUid.h" diff --git a/lldb/source/Plugins/SymbolFile/NativePDB/SymbolFileNativePDB.cpp b/lldb/source/Plugins/SymbolFile/NativePDB/SymbolFileNativePDB.cpp index 2fe2518daf376..00d50aa081e44 100644 --- a/lldb/source/Plugins/SymbolFile/NativePDB/SymbolFileNativePDB.cpp +++ b/lldb/source/Plugins/SymbolFile/NativePDB/SymbolFileNativePDB.cpp @@ -14,13 +14,13 @@ #include "clang/AST/DeclCXX.h" #include "clang/AST/Type.h" +#include "Plugins/ExpressionParser/Clang/ClangUtil.h" #include "Plugins/Language/CPlusPlus/MSVCUndecoratedNameParser.h" +#include "Plugins/TypeSystem/Clang/TypeSystemClang.h" #include "lldb/Core/Module.h" #include "lldb/Core/PluginManager.h" #include "lldb/Core/StreamBuffer.h" #include "lldb/Core/StreamFile.h" -#include "lldb/Symbol/TypeSystemClang.h" -#include "lldb/Symbol/ClangUtil.h" #include "lldb/Symbol/CompileUnit.h" #include "lldb/Symbol/LineTable.h" #include "lldb/Symbol/ObjectFile.h" diff --git a/lldb/source/Plugins/SymbolFile/NativePDB/UdtRecordCompleter.cpp b/lldb/source/Plugins/SymbolFile/NativePDB/UdtRecordCompleter.cpp index 9ecd4e2e14402..308ba9e3dec0b 100644 --- a/lldb/source/Plugins/SymbolFile/NativePDB/UdtRecordCompleter.cpp +++ b/lldb/source/Plugins/SymbolFile/NativePDB/UdtRecordCompleter.cpp @@ -5,8 +5,8 @@ #include "PdbSymUid.h" #include "PdbUtil.h" -#include "lldb/Symbol/TypeSystemClang.h" -#include "lldb/Symbol/ClangASTImporter.h" +#include "Plugins/ExpressionParser/Clang/ClangASTImporter.h" +#include "Plugins/TypeSystem/Clang/TypeSystemClang.h" #include "lldb/Symbol/Type.h" #include "lldb/Utility/LLDBAssert.h" #include "lldb/lldb-enumerations.h" diff --git a/lldb/source/Plugins/SymbolFile/NativePDB/UdtRecordCompleter.h b/lldb/source/Plugins/SymbolFile/NativePDB/UdtRecordCompleter.h index 55397582209b8..1b082785764e2 100644 --- a/lldb/source/Plugins/SymbolFile/NativePDB/UdtRecordCompleter.h +++ b/lldb/source/Plugins/SymbolFile/NativePDB/UdtRecordCompleter.h @@ -9,7 +9,7 @@ #ifndef LLDB_PLUGINS_SYMBOLFILE_NATIVEPDB_UDTRECORDCOMPLETER_H #define LLDB_PLUGINS_SYMBOLFILE_NATIVEPDB_UDTRECORDCOMPLETER_H -#include "lldb/Symbol/ClangASTImporter.h" +#include "Plugins/ExpressionParser/Clang/ClangASTImporter.h" #include "llvm/DebugInfo/CodeView/CVRecord.h" #include "llvm/DebugInfo/CodeView/TypeRecord.h" #include "llvm/DebugInfo/CodeView/TypeVisitorCallbacks.h" diff --git a/lldb/source/Plugins/SymbolFile/PDB/CMakeLists.txt b/lldb/source/Plugins/SymbolFile/PDB/CMakeLists.txt index 79bdce4277c75..ceeb173a99e1d 100644 --- a/lldb/source/Plugins/SymbolFile/PDB/CMakeLists.txt +++ b/lldb/source/Plugins/SymbolFile/PDB/CMakeLists.txt @@ -8,6 +8,7 @@ add_lldb_library(lldbPluginSymbolFilePDB PLUGIN lldbPluginSymbolFileNativePDB lldbSymbol lldbUtility + lldbPluginTypeSystemClang CLANG_LIBS clangAST clangLex diff --git a/lldb/source/Plugins/SymbolFile/PDB/PDBASTParser.cpp b/lldb/source/Plugins/SymbolFile/PDB/PDBASTParser.cpp index eb382387df37c..8f1a40a82150e 100644 --- a/lldb/source/Plugins/SymbolFile/PDB/PDBASTParser.cpp +++ b/lldb/source/Plugins/SymbolFile/PDB/PDBASTParser.cpp @@ -14,10 +14,10 @@ #include "clang/AST/Decl.h" #include "clang/AST/DeclCXX.h" +#include "Plugins/ExpressionParser/Clang/ClangASTMetadata.h" +#include "Plugins/ExpressionParser/Clang/ClangUtil.h" +#include "Plugins/TypeSystem/Clang/TypeSystemClang.h" #include "lldb/Core/Module.h" -#include "lldb/Symbol/TypeSystemClang.h" -#include "lldb/Symbol/ClangASTMetadata.h" -#include "lldb/Symbol/ClangUtil.h" #include "lldb/Symbol/Declaration.h" #include "lldb/Symbol/SymbolFile.h" #include "lldb/Symbol/TypeMap.h" diff --git a/lldb/source/Plugins/SymbolFile/PDB/PDBASTParser.h b/lldb/source/Plugins/SymbolFile/PDB/PDBASTParser.h index 6ded624fa435f..06ae32c664c5e 100644 --- a/lldb/source/Plugins/SymbolFile/PDB/PDBASTParser.h +++ b/lldb/source/Plugins/SymbolFile/PDB/PDBASTParser.h @@ -11,7 +11,7 @@ #include "lldb/lldb-forward.h" -#include "lldb/Symbol/ClangASTImporter.h" +#include "Plugins/ExpressionParser/Clang/ClangASTImporter.h" class SymbolFilePDB; diff --git a/lldb/source/Plugins/SymbolFile/PDB/SymbolFilePDB.cpp b/lldb/source/Plugins/SymbolFile/PDB/SymbolFilePDB.cpp index 820cecd09b03f..ee63166dbd05f 100644 --- a/lldb/source/Plugins/SymbolFile/PDB/SymbolFilePDB.cpp +++ b/lldb/source/Plugins/SymbolFile/PDB/SymbolFilePDB.cpp @@ -13,9 +13,9 @@ #include "clang/Lex/Lexer.h" +#include "Plugins/TypeSystem/Clang/TypeSystemClang.h" #include "lldb/Core/Module.h" #include "lldb/Core/PluginManager.h" -#include "lldb/Symbol/TypeSystemClang.h" #include "lldb/Symbol/CompileUnit.h" #include "lldb/Symbol/LineTable.h" #include "lldb/Symbol/ObjectFile.h" diff --git a/lldb/source/Plugins/SystemRuntime/MacOSX/AppleGetItemInfoHandler.cpp b/lldb/source/Plugins/SystemRuntime/MacOSX/AppleGetItemInfoHandler.cpp index fb271a988cb8f..d822698e26e09 100644 --- a/lldb/source/Plugins/SystemRuntime/MacOSX/AppleGetItemInfoHandler.cpp +++ b/lldb/source/Plugins/SystemRuntime/MacOSX/AppleGetItemInfoHandler.cpp @@ -9,13 +9,12 @@ #include "AppleGetItemInfoHandler.h" - +#include "Plugins/TypeSystem/Clang/TypeSystemClang.h" #include "lldb/Core/Module.h" #include "lldb/Core/Value.h" #include "lldb/Expression/DiagnosticManager.h" #include "lldb/Expression/FunctionCaller.h" #include "lldb/Expression/UtilityFunction.h" -#include "lldb/Symbol/TypeSystemClang.h" #include "lldb/Symbol/Symbol.h" #include "lldb/Target/ExecutionContext.h" #include "lldb/Target/Process.h" diff --git a/lldb/source/Plugins/SystemRuntime/MacOSX/AppleGetPendingItemsHandler.cpp b/lldb/source/Plugins/SystemRuntime/MacOSX/AppleGetPendingItemsHandler.cpp index 3d7c31bd01164..99b403ffdc163 100644 --- a/lldb/source/Plugins/SystemRuntime/MacOSX/AppleGetPendingItemsHandler.cpp +++ b/lldb/source/Plugins/SystemRuntime/MacOSX/AppleGetPendingItemsHandler.cpp @@ -9,13 +9,12 @@ #include "AppleGetPendingItemsHandler.h" - +#include "Plugins/TypeSystem/Clang/TypeSystemClang.h" #include "lldb/Core/Module.h" #include "lldb/Core/Value.h" #include "lldb/Expression/DiagnosticManager.h" #include "lldb/Expression/FunctionCaller.h" #include "lldb/Expression/UtilityFunction.h" -#include "lldb/Symbol/TypeSystemClang.h" #include "lldb/Symbol/Symbol.h" #include "lldb/Target/ExecutionContext.h" #include "lldb/Target/Process.h" diff --git a/lldb/source/Plugins/SystemRuntime/MacOSX/AppleGetQueuesHandler.cpp b/lldb/source/Plugins/SystemRuntime/MacOSX/AppleGetQueuesHandler.cpp index 20fa540a1e3f0..5a69578462e04 100644 --- a/lldb/source/Plugins/SystemRuntime/MacOSX/AppleGetQueuesHandler.cpp +++ b/lldb/source/Plugins/SystemRuntime/MacOSX/AppleGetQueuesHandler.cpp @@ -8,12 +8,12 @@ #include "AppleGetQueuesHandler.h" +#include "Plugins/TypeSystem/Clang/TypeSystemClang.h" #include "lldb/Core/Module.h" #include "lldb/Core/Value.h" #include "lldb/Expression/DiagnosticManager.h" #include "lldb/Expression/FunctionCaller.h" #include "lldb/Expression/UtilityFunction.h" -#include "lldb/Symbol/TypeSystemClang.h" #include "lldb/Symbol/Symbol.h" #include "lldb/Target/ExecutionContext.h" #include "lldb/Target/Process.h" diff --git a/lldb/source/Plugins/SystemRuntime/MacOSX/AppleGetThreadItemInfoHandler.cpp b/lldb/source/Plugins/SystemRuntime/MacOSX/AppleGetThreadItemInfoHandler.cpp index d3ee8a852f40d..4b99b56eef8f3 100644 --- a/lldb/source/Plugins/SystemRuntime/MacOSX/AppleGetThreadItemInfoHandler.cpp +++ b/lldb/source/Plugins/SystemRuntime/MacOSX/AppleGetThreadItemInfoHandler.cpp @@ -9,14 +9,13 @@ #include "AppleGetThreadItemInfoHandler.h" - +#include "Plugins/TypeSystem/Clang/TypeSystemClang.h" #include "lldb/Core/Module.h" #include "lldb/Core/Value.h" #include "lldb/Expression/DiagnosticManager.h" #include "lldb/Expression/Expression.h" #include "lldb/Expression/FunctionCaller.h" #include "lldb/Expression/UtilityFunction.h" -#include "lldb/Symbol/TypeSystemClang.h" #include "lldb/Symbol/Symbol.h" #include "lldb/Target/ExecutionContext.h" #include "lldb/Target/Process.h" diff --git a/lldb/source/Plugins/SystemRuntime/MacOSX/CMakeLists.txt b/lldb/source/Plugins/SystemRuntime/MacOSX/CMakeLists.txt index ac5781b98b09c..04d30652ba4b4 100644 --- a/lldb/source/Plugins/SystemRuntime/MacOSX/CMakeLists.txt +++ b/lldb/source/Plugins/SystemRuntime/MacOSX/CMakeLists.txt @@ -14,4 +14,5 @@ add_lldb_library(lldbPluginSystemRuntimeMacOSX PLUGIN lldbTarget lldbUtility lldbPluginProcessUtility + lldbPluginTypeSystemClang ) diff --git a/lldb/source/Plugins/SystemRuntime/MacOSX/SystemRuntimeMacOSX.cpp b/lldb/source/Plugins/SystemRuntime/MacOSX/SystemRuntimeMacOSX.cpp index a42671331c8e6..41a7a525385b7 100644 --- a/lldb/source/Plugins/SystemRuntime/MacOSX/SystemRuntimeMacOSX.cpp +++ b/lldb/source/Plugins/SystemRuntime/MacOSX/SystemRuntimeMacOSX.cpp @@ -7,12 +7,12 @@ //===----------------------------------------------------------------------===// #include "Plugins/Process/Utility/HistoryThread.h" +#include "Plugins/TypeSystem/Clang/TypeSystemClang.h" #include "lldb/Breakpoint/StoppointCallbackContext.h" #include "lldb/Core/Module.h" #include "lldb/Core/ModuleSpec.h" #include "lldb/Core/PluginManager.h" #include "lldb/Core/Section.h" -#include "lldb/Symbol/TypeSystemClang.h" #include "lldb/Symbol/ObjectFile.h" #include "lldb/Symbol/SymbolContext.h" #include "lldb/Target/Process.h" diff --git a/lldb/source/Plugins/TypeSystem/CMakeLists.txt b/lldb/source/Plugins/TypeSystem/CMakeLists.txt new file mode 100644 index 0000000000000..17c40aee44cc2 --- /dev/null +++ b/lldb/source/Plugins/TypeSystem/CMakeLists.txt @@ -0,0 +1 @@ +add_subdirectory(Clang) diff --git a/lldb/source/Plugins/TypeSystem/Clang/CMakeLists.txt b/lldb/source/Plugins/TypeSystem/Clang/CMakeLists.txt new file mode 100644 index 0000000000000..37a3142da7274 --- /dev/null +++ b/lldb/source/Plugins/TypeSystem/Clang/CMakeLists.txt @@ -0,0 +1,20 @@ +add_lldb_library(lldbPluginTypeSystemClang PLUGIN + TypeSystemClang.cpp + + LINK_LIBS + lldbCore + lldbSymbol + lldbTarget + lldbUtility + lldbPluginExpressionParserClang + lldbPluginSymbolFileDWARF + lldbPluginSymbolFilePDB + lldbPluginObjCRuntime + CLANG_LIBS + clangAST + clangBasic + clangFrontend + clangSema + LINK_COMPONENTS + Support +) diff --git a/lldb/source/Symbol/TypeSystemClang.cpp b/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.cpp similarity index 96% rename from lldb/source/Symbol/TypeSystemClang.cpp rename to lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.cpp index ae601727d9b45..2fd9a2059b3d9 100644 --- a/lldb/source/Symbol/TypeSystemClang.cpp +++ b/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.cpp @@ -6,7 +6,7 @@ // //===----------------------------------------------------------------------===// -#include "lldb/Symbol/TypeSystemClang.h" +#include "TypeSystemClang.h" #include "llvm/Support/FormatAdapters.h" #include "llvm/Support/FormatVariadic.h" @@ -40,9 +40,13 @@ #include "llvm/Support/Signals.h" #include "llvm/Support/Threading.h" +#include "Plugins/ExpressionParser/Clang/ClangASTImporter.h" +#include "Plugins/ExpressionParser/Clang/ClangASTMetadata.h" +#include "Plugins/ExpressionParser/Clang/ClangExternalASTSourceCallbacks.h" #include "Plugins/ExpressionParser/Clang/ClangFunctionCaller.h" #include "Plugins/ExpressionParser/Clang/ClangPersistentVariables.h" #include "Plugins/ExpressionParser/Clang/ClangUserExpression.h" +#include "Plugins/ExpressionParser/Clang/ClangUtil.h" #include "Plugins/ExpressionParser/Clang/ClangUtilityFunction.h" #include "lldb/Utility/ArchSpec.h" #include "lldb/Utility/Flags.h" @@ -53,10 +57,6 @@ #include "lldb/Core/StreamFile.h" #include "lldb/Core/ThreadSafeDenseMap.h" #include "lldb/Core/UniqueCStringMap.h" -#include "lldb/Symbol/ClangASTImporter.h" -#include "lldb/Symbol/ClangASTMetadata.h" -#include "lldb/Symbol/ClangExternalASTSourceCallbacks.h" -#include "lldb/Symbol/ClangUtil.h" #include "lldb/Symbol/ObjectFile.h" #include "lldb/Symbol/SymbolFile.h" #include "lldb/Target/ExecutionContext.h" @@ -313,6 +313,10 @@ static ClangASTMap &GetASTMap() { return *g_map_ptr; } +TypePayloadClang::TypePayloadClang(bool is_complete_objc_class) { + SetIsCompleteObjCClass(is_complete_objc_class); +} + char TypeSystemClang::ID; bool TypeSystemClang::IsOperator(llvm::StringRef name, @@ -1201,10 +1205,11 @@ CompilerType TypeSystemClang::CreateRecordType(DeclContext *decl_ctx, // complete definition just in case. bool has_name = !name.empty(); - - CXXRecordDecl *decl = CXXRecordDecl::Create( - ast, (TagDecl::TagKind)kind, decl_ctx, SourceLocation(), SourceLocation(), - has_name ? &ast.Idents.get(name) : nullptr); + CXXRecordDecl *decl = CXXRecordDecl::CreateDeserialized(ast, 0); + decl->setTagKind(static_cast(kind)); + decl->setDeclContext(decl_ctx); + if (has_name) + decl->setDeclName(&ast.Idents.get(name)); if (!has_name) { // In C++ a lambda is also represented as an unnamed class. This is @@ -1322,9 +1327,12 @@ clang::FunctionTemplateDecl *TypeSystemClang::CreateFunctionTemplateDecl( TemplateParameterList *template_param_list = CreateTemplateParameterList( ast, template_param_infos, template_param_decls); - FunctionTemplateDecl *func_tmpl_decl = FunctionTemplateDecl::Create( - ast, decl_ctx, func_decl->getLocation(), func_decl->getDeclName(), - template_param_list, func_decl); + FunctionTemplateDecl *func_tmpl_decl = + FunctionTemplateDecl::CreateDeserialized(ast, 0); + func_tmpl_decl->setDeclContext(decl_ctx); + func_tmpl_decl->setLocation(func_decl->getLocation()); + func_tmpl_decl->setDeclName(func_decl->getDeclName()); + func_tmpl_decl->init(func_decl, template_param_list); for (size_t i = 0, template_param_decl_count = template_param_decls.size(); i < template_param_decl_count; ++i) { @@ -1375,11 +1383,11 @@ ClassTemplateDecl *TypeSystemClang::CreateClassTemplateDecl( TemplateParameterList *template_param_list = CreateTemplateParameterList( ast, template_param_infos, template_param_decls); - CXXRecordDecl *template_cxx_decl = CXXRecordDecl::Create( - ast, (TagDecl::TagKind)kind, - decl_ctx, // What decl context do we use here? TU? The actual decl - // context? - SourceLocation(), SourceLocation(), &identifier_info); + CXXRecordDecl *template_cxx_decl = CXXRecordDecl::CreateDeserialized(ast, 0); + template_cxx_decl->setTagKind(static_cast(kind)); + // What decl context do we use here? TU? The actual decl context? + template_cxx_decl->setDeclContext(decl_ctx); + template_cxx_decl->setDeclName(decl_name); for (size_t i = 0, template_param_decl_count = template_param_decls.size(); i < template_param_decl_count; ++i) { @@ -1391,11 +1399,11 @@ ClassTemplateDecl *TypeSystemClang::CreateClassTemplateDecl( // template_cxx_decl->startDefinition(); // template_cxx_decl->completeDefinition(); - class_template_decl = ClassTemplateDecl::Create( - ast, - decl_ctx, // What decl context do we use here? TU? The actual decl - // context? - SourceLocation(), decl_name, template_param_list, template_cxx_decl); + class_template_decl = ClassTemplateDecl::CreateDeserialized(ast, 0); + // What decl context do we use here? TU? The actual decl context? + class_template_decl->setDeclContext(decl_ctx); + class_template_decl->setDeclName(decl_name); + class_template_decl->init(template_cxx_decl, template_param_list); template_cxx_decl->setDescribedClassTemplate(class_template_decl); if (class_template_decl) { @@ -1454,9 +1462,16 @@ TypeSystemClang::CreateClassTemplateSpecializationDecl( ast, template_param_infos.packed_args->args); } ClassTemplateSpecializationDecl *class_template_specialization_decl = - ClassTemplateSpecializationDecl::Create( - ast, (TagDecl::TagKind)kind, decl_ctx, SourceLocation(), - SourceLocation(), class_template_decl, args, nullptr); + ClassTemplateSpecializationDecl::CreateDeserialized(ast, 0); + class_template_specialization_decl->setTagKind( + static_cast(kind)); + class_template_specialization_decl->setDeclContext(decl_ctx); + class_template_specialization_decl->setInstantiationOf(class_template_decl); + class_template_specialization_decl->setTemplateArgs( + TemplateArgumentList::CreateCopy(ast, args)); + ast.getTypeDeclType(class_template_specialization_decl, nullptr); + class_template_specialization_decl->setDeclName( + class_template_decl->getDeclName()); class_template_specialization_decl->setSpecializationKind( TSK_ExplicitSpecialization); @@ -1585,11 +1600,11 @@ CompilerType TypeSystemClang::CreateObjCClass(llvm::StringRef name, if (decl_ctx == nullptr) decl_ctx = ast.getTranslationUnitDecl(); - ObjCInterfaceDecl *decl = ObjCInterfaceDecl::Create( - ast, decl_ctx, SourceLocation(), &ast.Idents.get(name), nullptr, nullptr, - SourceLocation(), - /*isForwardDecl,*/ - isInternal); + ObjCInterfaceDecl *decl = ObjCInterfaceDecl::CreateDeserialized(ast, 0); + decl->setDeclContext(decl_ctx); + decl->setDeclName(&ast.Idents.get(name)); + /*isForwardDecl,*/ + decl->setImplicit(isInternal); if (decl && metadata) SetMetadata(decl, *metadata); @@ -1627,7 +1642,7 @@ TypeSystemClang::GetNumBaseClasses(const CXXRecordDecl *cxx_record_decl, #pragma mark Namespace Declarations NamespaceDecl *TypeSystemClang::GetUniqueNamespaceDeclaration( - const char *name, DeclContext *decl_ctx, bool is_inline) { + const char *name, clang::DeclContext *decl_ctx, bool is_inline) { NamespaceDecl *namespace_decl = nullptr; ASTContext &ast = getASTContext(); TranslationUnitDecl *translation_unit_decl = ast.getTranslationUnitDecl(); @@ -1688,9 +1703,10 @@ NamespaceDecl *TypeSystemClang::GetUniqueNamespaceDeclaration( clang::BlockDecl * TypeSystemClang::CreateBlockDeclaration(clang::DeclContext *ctx) { - if (ctx != nullptr) { + if (ctx) { clang::BlockDecl *decl = - clang::BlockDecl::Create(getASTContext(), ctx, clang::SourceLocation()); + clang::BlockDecl::CreateDeserialized(getASTContext(), 0); + decl->setDeclContext(ctx); ctx->addDecl(decl); return decl; } @@ -1716,15 +1732,16 @@ clang::DeclContext *FindLCABetweenDecls(clang::DeclContext *left, clang::UsingDirectiveDecl *TypeSystemClang::CreateUsingDirectiveDeclaration( clang::DeclContext *decl_ctx, clang::NamespaceDecl *ns_decl) { - if (decl_ctx != nullptr && ns_decl != nullptr) { + if (decl_ctx && ns_decl) { auto *translation_unit = getASTContext().getTranslationUnitDecl(); clang::UsingDirectiveDecl *using_decl = clang::UsingDirectiveDecl::Create( - getASTContext(), decl_ctx, clang::SourceLocation(), - clang::SourceLocation(), clang::NestedNameSpecifierLoc(), - clang::SourceLocation(), ns_decl, - FindLCABetweenDecls(decl_ctx, ns_decl, translation_unit)); - decl_ctx->addDecl(using_decl); - return using_decl; + getASTContext(), decl_ctx, clang::SourceLocation(), + clang::SourceLocation(), clang::NestedNameSpecifierLoc(), + clang::SourceLocation(), ns_decl, + FindLCABetweenDecls(decl_ctx, ns_decl, + translation_unit)); + decl_ctx->addDecl(using_decl); + return using_decl; } return nullptr; } @@ -1748,12 +1765,13 @@ TypeSystemClang::CreateUsingDeclaration(clang::DeclContext *current_decl_ctx, clang::VarDecl *TypeSystemClang::CreateVariableDeclaration( clang::DeclContext *decl_context, const char *name, clang::QualType type) { - if (decl_context != nullptr) { - clang::VarDecl *var_decl = clang::VarDecl::Create( - getASTContext(), decl_context, clang::SourceLocation(), - clang::SourceLocation(), - name && name[0] ? &getASTContext().Idents.getOwn(name) : nullptr, type, - nullptr, clang::SC_None); + if (decl_context) { + clang::VarDecl *var_decl = + clang::VarDecl::CreateDeserialized(getASTContext(), 0); + var_decl->setDeclContext(decl_context); + if (name && name[0]) + var_decl->setDeclName(&getASTContext().Idents.getOwn(name)); + var_decl->setType(type); var_decl->setAccess(clang::AS_public); decl_context->addDecl(var_decl); return var_decl; @@ -1877,11 +1895,15 @@ FunctionDecl *TypeSystemClang::CreateFunctionDeclaration( clang::DeclarationName declarationName = GetDeclarationName(name, function_clang_type); - func_decl = FunctionDecl::Create( - ast, decl_ctx, SourceLocation(), SourceLocation(), declarationName, - ClangUtil::GetQualType(function_clang_type), nullptr, - (clang::StorageClass)storage, is_inline, hasWrittenPrototype, - isConstexprSpecified ? CSK_constexpr : CSK_unspecified); + func_decl = FunctionDecl::CreateDeserialized(ast, 0); + func_decl->setDeclContext(decl_ctx); + func_decl->setDeclName(declarationName); + func_decl->setType(ClangUtil::GetQualType(function_clang_type)); + func_decl->setStorageClass(static_cast(storage)); + func_decl->setInlineSpecified(is_inline); + func_decl->setHasWrittenPrototype(hasWrittenPrototype); + func_decl->setConstexprKind(isConstexprSpecified ? CSK_constexpr + : CSK_unspecified); if (func_decl) decl_ctx->addDecl(func_decl); @@ -1935,11 +1957,12 @@ ParmVarDecl *TypeSystemClang::CreateParameterDeclaration( clang::DeclContext *decl_ctx, const char *name, const CompilerType ¶m_type, int storage, bool add_decl) { ASTContext &ast = getASTContext(); - auto *decl = - ParmVarDecl::Create(ast, decl_ctx, SourceLocation(), SourceLocation(), - name && name[0] ? &ast.Idents.get(name) : nullptr, - ClangUtil::GetQualType(param_type), nullptr, - (clang::StorageClass)storage, nullptr); + auto *decl = ParmVarDecl::CreateDeserialized(ast, 0); + decl->setDeclContext(decl_ctx); + if (name && name[0]) + decl->setDeclName(&ast.Idents.get(name)); + decl->setType(ClangUtil::GetQualType(param_type)); + decl->setStorageClass(static_cast(storage)); if (add_decl) decl_ctx->addDecl(decl); @@ -2038,7 +2061,6 @@ TypeSystemClang::CreateEnumerationType(const char *name, DeclContext *decl_ctx, // TODO: ask about these... // const bool IsFixed = false; - EnumDecl *enum_decl = EnumDecl::Create( ast, decl_ctx, SourceLocation(), SourceLocation(), name && name[0] ? &ast.Idents.get(name) : nullptr, nullptr, @@ -3497,21 +3519,34 @@ bool TypeSystemClang::GetCompleteType(lldb::opaque_compiler_type_t type) { } ConstString TypeSystemClang::GetTypeName(lldb::opaque_compiler_type_t type) { - std::string type_name; - if (type) { - clang::PrintingPolicy printing_policy(getASTContext().getPrintingPolicy()); - clang::QualType qual_type(GetQualType(type)); - printing_policy.SuppressTagKeyword = true; - const clang::TypedefType *typedef_type = - qual_type->getAs(); - if (typedef_type) { - const clang::TypedefNameDecl *typedef_decl = typedef_type->getDecl(); - type_name = typedef_decl->getQualifiedNameAsString(); - } else { - type_name = qual_type.getAsString(printing_policy); - } + if (!type) + return ConstString(); + + clang::QualType qual_type(GetQualType(type)); + + // For a typedef just return the qualified name. + if (const auto *typedef_type = qual_type->getAs()) { + const clang::TypedefNameDecl *typedef_decl = typedef_type->getDecl(); + return ConstString(typedef_decl->getQualifiedNameAsString()); } - return ConstString(type_name); + + clang::PrintingPolicy printing_policy(getASTContext().getPrintingPolicy()); + printing_policy.SuppressTagKeyword = true; + return ConstString(qual_type.getAsString(printing_policy)); +} + +ConstString +TypeSystemClang::GetDisplayTypeName(lldb::opaque_compiler_type_t type, + const SymbolContext *) { + if (!type) + return ConstString(); + + clang::QualType qual_type(GetQualType(type)); + clang::PrintingPolicy printing_policy(getASTContext().getPrintingPolicy()); + printing_policy.SuppressTagKeyword = true; + printing_policy.SuppressScope = false; + printing_policy.SuppressUnwrittenScope = true; + return ConstString(qual_type.getAsString(printing_policy)); } uint32_t @@ -4235,10 +4270,11 @@ CompilerType TypeSystemClang::CreateTypedefType( if (decl_ctx == nullptr) decl_ctx = ast->getASTContext().getTranslationUnitDecl(); - clang::TypedefDecl *decl = clang::TypedefDecl::Create( - clang_ast, decl_ctx, clang::SourceLocation(), clang::SourceLocation(), - &clang_ast.Idents.get(typedef_name), - clang_ast.getTrivialTypeSourceInfo(qual_type)); + clang::TypedefDecl *decl = + clang::TypedefDecl::CreateDeserialized(clang_ast, 0); + decl->setDeclContext(decl_ctx); + decl->setDeclName(&clang_ast.Idents.get(typedef_name)); + decl->setTypeSourceInfo(clang_ast.getTrivialTypeSourceInfo(qual_type)); decl->setAccess(clang::AS_public); // TODO respect proper access specifier @@ -4341,10 +4377,11 @@ TypeSystemClang::CreateTypedef(lldb::opaque_compiler_type_t type, if (decl_ctx == nullptr) decl_ctx = getASTContext().getTranslationUnitDecl(); - clang::TypedefDecl *decl = clang::TypedefDecl::Create( - clang_ast, decl_ctx, clang::SourceLocation(), clang::SourceLocation(), - &clang_ast.Idents.get(typedef_name), - clang_ast.getTrivialTypeSourceInfo(qual_type)); + clang::TypedefDecl *decl = + clang::TypedefDecl::CreateDeserialized(clang_ast, 0); + decl->setDeclContext(decl_ctx); + decl->setDeclName(&clang_ast.Idents.get(typedef_name)); + decl->setTypeSourceInfo(clang_ast.getTrivialTypeSourceInfo(qual_type)); clang::TagDecl *tdecl = nullptr; if (!qual_type.isNull()) { @@ -6902,15 +6939,12 @@ clang::FieldDecl *TypeSystemClang::AddFieldToRecordType( clang::RecordDecl *record_decl = ast->GetAsRecordDecl(type); if (record_decl) { - field = clang::FieldDecl::Create( - clang_ast, record_decl, clang::SourceLocation(), - clang::SourceLocation(), - ident, // Identifier - ClangUtil::GetQualType(field_clang_type), // Field type - nullptr, // TInfo * - bit_width, // BitWidth - false, // Mutable - clang::ICIS_NoInit); // HasInit + field = clang::FieldDecl::CreateDeserialized(clang_ast, 0); + field->setDeclContext(record_decl); + field->setDeclName(ident); + field->setType(ClangUtil::GetQualType(field_clang_type)); + if (bit_width) + field->setBitWidth(bit_width); if (name.empty()) { // Determine whether this field corresponds to an anonymous struct or @@ -6945,14 +6979,15 @@ clang::FieldDecl *TypeSystemClang::AddFieldToRecordType( field_clang_type.GetCompleteType(); - field = clang::ObjCIvarDecl::Create( - clang_ast, class_interface_decl, clang::SourceLocation(), - clang::SourceLocation(), - ident, // Identifier - ClangUtil::GetQualType(field_clang_type), // Field type - nullptr, // TypeSourceInfo * - ConvertAccessTypeToObjCIvarAccessControl(access), bit_width, - is_synthesized); + auto ivar = clang::ObjCIvarDecl::CreateDeserialized(clang_ast, 0); + ivar->setDeclContext(class_interface_decl); + ivar->setDeclName(ident); + ivar->setType(ClangUtil::GetQualType(field_clang_type)); + ivar->setAccessControl(ConvertAccessTypeToObjCIvarAccessControl(access)); + if (bit_width) + ivar->setBitWidth(bit_width); + ivar->setSynthesize(is_synthesized); + field = ivar; if (field) { class_interface_decl->addDecl(field); @@ -7107,15 +7142,11 @@ clang::VarDecl *TypeSystemClang::AddVariableToRecordType( if (!name.empty()) ident = &ast->getASTContext().Idents.get(name); - var_decl = clang::VarDecl::Create( - ast->getASTContext(), // ASTContext & - record_decl, // DeclContext * - clang::SourceLocation(), // clang::SourceLocation StartLoc - clang::SourceLocation(), // clang::SourceLocation IdLoc - ident, // clang::IdentifierInfo * - ClangUtil::GetQualType(var_type), // Variable clang::QualType - nullptr, // TypeSourceInfo * - clang::SC_Static); // StorageClass + var_decl = clang::VarDecl::CreateDeserialized(ast->getASTContext(), 0); + var_decl->setDeclContext(record_decl); + var_decl->setDeclName(ident); + var_decl->setType(ClangUtil::GetQualType(var_type)); + var_decl->setStorageClass(clang::SC_Static); if (!var_decl) return nullptr; @@ -7131,12 +7162,11 @@ clang::VarDecl *TypeSystemClang::AddVariableToRecordType( } clang::CXXMethodDecl *TypeSystemClang::AddMethodToCXXRecordType( - lldb::opaque_compiler_type_t type, const char *name, const char *mangled_name, - const CompilerType &method_clang_type, lldb::AccessType access, - bool is_virtual, bool is_static, bool is_inline, bool is_explicit, - bool is_attr_used, bool is_artificial) { - if (!type || !method_clang_type.IsValid() || name == nullptr || - name[0] == '\0') + lldb::opaque_compiler_type_t type, llvm::StringRef name, + const char *mangled_name, const CompilerType &method_clang_type, + lldb::AccessType access, bool is_virtual, bool is_static, bool is_inline, + bool is_explicit, bool is_attr_used, bool is_artificial) { + if (!type || !method_clang_type.IsValid() || name.empty()) return nullptr; clang::QualType record_qual_type(GetCanonicalQualType(type)); @@ -7174,29 +7204,34 @@ clang::CXXMethodDecl *TypeSystemClang::AddMethodToCXXRecordType( return nullptr; // skip everything artificial const clang::ExplicitSpecifier explicit_spec( - nullptr /*expr*/, is_explicit - ? clang::ExplicitSpecKind::ResolvedTrue - : clang::ExplicitSpecKind::ResolvedFalse); - if (name[0] == '~') { - cxx_dtor_decl = clang::CXXDestructorDecl::Create( - getASTContext(), cxx_record_decl, clang::SourceLocation(), - clang::DeclarationNameInfo( - getASTContext().DeclarationNames.getCXXDestructorName( - getASTContext().getCanonicalType(record_qual_type)), - clang::SourceLocation()), - method_qual_type, nullptr, is_inline, is_artificial, - ConstexprSpecKind::CSK_unspecified); + nullptr /*expr*/, is_explicit ? clang::ExplicitSpecKind::ResolvedTrue + : clang::ExplicitSpecKind::ResolvedFalse); + + if (name.startswith("~")) { + cxx_dtor_decl = + clang::CXXDestructorDecl::CreateDeserialized(getASTContext(), 0); + cxx_dtor_decl->setDeclContext(cxx_record_decl); + cxx_dtor_decl->setDeclName( + getASTContext().DeclarationNames.getCXXDestructorName( + getASTContext().getCanonicalType(record_qual_type))); + cxx_dtor_decl->setType(method_qual_type); + cxx_dtor_decl->setImplicit(is_artificial); + cxx_dtor_decl->setInlineSpecified(is_inline); + cxx_dtor_decl->setConstexprKind(CSK_unspecified); cxx_method_decl = cxx_dtor_decl; } else if (decl_name == cxx_record_decl->getDeclName()) { - cxx_ctor_decl = clang::CXXConstructorDecl::Create( - getASTContext(), cxx_record_decl, clang::SourceLocation(), - clang::DeclarationNameInfo( - getASTContext().DeclarationNames.getCXXConstructorName( - getASTContext().getCanonicalType(record_qual_type)), - clang::SourceLocation()), - method_qual_type, - nullptr, // TypeSourceInfo * - explicit_spec, is_inline, is_artificial, CSK_unspecified); + cxx_ctor_decl = clang::CXXConstructorDecl::CreateDeserialized( + getASTContext(), 0, 0); + cxx_ctor_decl->setDeclContext(cxx_record_decl); + cxx_ctor_decl->setDeclName( + getASTContext().DeclarationNames.getCXXConstructorName( + getASTContext().getCanonicalType(record_qual_type))); + cxx_ctor_decl->setType(method_qual_type); + cxx_ctor_decl->setImplicit(is_artificial); + cxx_ctor_decl->setInlineSpecified(is_inline); + cxx_ctor_decl->setConstexprKind(CSK_unspecified); + cxx_ctor_decl->setNumCtorInitializers(0); + cxx_ctor_decl->setExplicitSpecifier(explicit_spec); cxx_method_decl = cxx_ctor_decl; } else { clang::StorageClass SC = is_static ? clang::SC_Static : clang::SC_None; @@ -7212,36 +7247,41 @@ clang::CXXMethodDecl *TypeSystemClang::AddMethodToCXXRecordType( if (!TypeSystemClang::CheckOverloadedOperatorKindParameterCount( is_method, op_kind, num_params)) return nullptr; - cxx_method_decl = clang::CXXMethodDecl::Create( - getASTContext(), cxx_record_decl, clang::SourceLocation(), - clang::DeclarationNameInfo( - getASTContext().DeclarationNames.getCXXOperatorName(op_kind), - clang::SourceLocation()), - method_qual_type, - nullptr, // TypeSourceInfo * - SC, is_inline, CSK_unspecified, clang::SourceLocation()); + cxx_method_decl = + clang::CXXMethodDecl::CreateDeserialized(getASTContext(), 0); + cxx_method_decl->setDeclContext(cxx_record_decl); + cxx_method_decl->setDeclName( + getASTContext().DeclarationNames.getCXXOperatorName(op_kind)); + cxx_method_decl->setType(method_qual_type); + cxx_method_decl->setStorageClass(SC); + cxx_method_decl->setInlineSpecified(is_inline); + cxx_method_decl->setConstexprKind(CSK_unspecified); } else if (num_params == 0) { // Conversion operators don't take params... - cxx_method_decl = clang::CXXConversionDecl::Create( - getASTContext(), cxx_record_decl, clang::SourceLocation(), - clang::DeclarationNameInfo( - getASTContext().DeclarationNames.getCXXConversionFunctionName( - getASTContext().getCanonicalType( - function_type->getReturnType())), - clang::SourceLocation()), - method_qual_type, - nullptr, // TypeSourceInfo * - is_inline, explicit_spec, CSK_unspecified, clang::SourceLocation()); + auto *cxx_conversion_decl = + clang::CXXConversionDecl::CreateDeserialized(getASTContext(), 0); + cxx_conversion_decl->setDeclContext(cxx_record_decl); + cxx_conversion_decl->setDeclName( + getASTContext().DeclarationNames.getCXXConversionFunctionName( + getASTContext().getCanonicalType( + function_type->getReturnType()))); + cxx_conversion_decl->setType(method_qual_type); + cxx_conversion_decl->setInlineSpecified(is_inline); + cxx_conversion_decl->setExplicitSpecifier(explicit_spec); + cxx_conversion_decl->setConstexprKind(CSK_unspecified); + cxx_method_decl = cxx_conversion_decl; } } if (cxx_method_decl == nullptr) { - cxx_method_decl = clang::CXXMethodDecl::Create( - getASTContext(), cxx_record_decl, clang::SourceLocation(), - clang::DeclarationNameInfo(decl_name, clang::SourceLocation()), - method_qual_type, - nullptr, // TypeSourceInfo * - SC, is_inline, CSK_unspecified, clang::SourceLocation()); + cxx_method_decl = + clang::CXXMethodDecl::CreateDeserialized(getASTContext(), 0); + cxx_method_decl->setDeclContext(cxx_record_decl); + cxx_method_decl->setDeclName(decl_name); + cxx_method_decl->setType(method_qual_type); + cxx_method_decl->setInlineSpecified(is_inline); + cxx_method_decl->setStorageClass(SC); + cxx_method_decl->setConstexprKind(CSK_unspecified); } } @@ -7412,15 +7452,14 @@ bool TypeSystemClang::AddObjCClassProperty( prop_type_source = clang_ast.getTrivialTypeSourceInfo( ClangUtil::GetQualType(property_clang_type)); - clang::ObjCPropertyDecl *property_decl = clang::ObjCPropertyDecl::Create( - clang_ast, class_interface_decl, - clang::SourceLocation(), // Source Location - &clang_ast.Idents.get(property_name), - clang::SourceLocation(), // Source Location for AT - clang::SourceLocation(), // Source location for ( - ivar_decl ? ivar_decl->getType() - : ClangUtil::GetQualType(property_clang_type), - prop_type_source); + clang::ObjCPropertyDecl *property_decl = + clang::ObjCPropertyDecl::CreateDeserialized(clang_ast, 0); + property_decl->setDeclContext(class_interface_decl); + property_decl->setDeclName(&clang_ast.Idents.get(property_name)); + property_decl->setType(ivar_decl + ? ivar_decl->getType() + : ClangUtil::GetQualType(property_clang_type), + prop_type_source); if (!property_decl) return false; @@ -7500,12 +7539,18 @@ bool TypeSystemClang::AddObjCClassProperty( clang::ObjCMethodDecl::None; const bool HasRelatedResultType = false; - getter = clang::ObjCMethodDecl::Create( - clang_ast, clang::SourceLocation(), clang::SourceLocation(), getter_sel, - ClangUtil::GetQualType(property_clang_type_to_access), nullptr, - class_interface_decl, isInstance, isVariadic, isPropertyAccessor, - isSynthesizedAccessorStub, isImplicitlyDeclared, isDefined, impControl, - HasRelatedResultType); + getter = clang::ObjCMethodDecl::CreateDeserialized(clang_ast, 0); + getter->setDeclName(getter_sel); + getter->setReturnType(ClangUtil::GetQualType(property_clang_type_to_access)); + getter->setDeclContext(class_interface_decl); + getter->setInstanceMethod(isInstance); + getter->setVariadic(isVariadic); + getter->setPropertyAccessor(isPropertyAccessor); + getter->setSynthesizedAccessorStub(isSynthesizedAccessorStub); + getter->setImplicit(isImplicitlyDeclared); + getter->setDefined(isDefined); + getter->setDeclImplementation(impControl); + getter->setRelatedResultType(HasRelatedResultType); if (getter) { if (metadata) @@ -7535,11 +7580,18 @@ bool TypeSystemClang::AddObjCClassProperty( clang::ObjCMethodDecl::None; const bool HasRelatedResultType = false; - setter = clang::ObjCMethodDecl::Create( - clang_ast, clang::SourceLocation(), clang::SourceLocation(), setter_sel, - result_type, nullptr, class_interface_decl, isInstance, isVariadic, - isPropertyAccessor, isSynthesizedAccessorStub, isImplicitlyDeclared, - isDefined, impControl, HasRelatedResultType); + setter = clang::ObjCMethodDecl::CreateDeserialized(clang_ast, 0); + setter->setDeclName(setter_sel); + setter->setReturnType(result_type); + setter->setDeclContext(class_interface_decl); + setter->setInstanceMethod(isInstance); + setter->setVariadic(isVariadic); + setter->setPropertyAccessor(isPropertyAccessor); + setter->setSynthesizedAccessorStub(isSynthesizedAccessorStub); + setter->setImplicit(isImplicitlyDeclared); + setter->setDefined(isDefined); + setter->setDeclImplementation(impControl); + setter->setRelatedResultType(HasRelatedResultType); if (setter) { if (metadata) @@ -7656,15 +7708,19 @@ clang::ObjCMethodDecl *TypeSystemClang::AddMethodToObjCObjectType( return nullptr; // some debug information is corrupt. We are not going to // deal with it. - clang::ObjCMethodDecl *objc_method_decl = clang::ObjCMethodDecl::Create( - ast, - clang::SourceLocation(), // beginLoc, - clang::SourceLocation(), // endLoc, - method_selector, method_function_prototype->getReturnType(), - nullptr, // TypeSourceInfo *ResultTInfo, - lldb_ast->GetDeclContextForType(ClangUtil::GetQualType(type)), isInstance, - isVariadic, isPropertyAccessor, isSynthesizedAccessorStub, - isImplicitlyDeclared, isDefined, impControl, HasRelatedResultType); + auto *objc_method_decl = clang::ObjCMethodDecl::CreateDeserialized(ast, 0); + objc_method_decl->setDeclName(method_selector); + objc_method_decl->setReturnType(method_function_prototype->getReturnType()); + objc_method_decl->setDeclContext( + lldb_ast->GetDeclContextForType(ClangUtil::GetQualType(type))); + objc_method_decl->setInstanceMethod(isInstance); + objc_method_decl->setVariadic(isVariadic); + objc_method_decl->setPropertyAccessor(isPropertyAccessor); + objc_method_decl->setSynthesizedAccessorStub(isSynthesizedAccessorStub); + objc_method_decl->setImplicit(isImplicitlyDeclared); + objc_method_decl->setDefined(isDefined); + objc_method_decl->setDeclImplementation(impControl); + objc_method_decl->setRelatedResultType(HasRelatedResultType); if (objc_method_decl == nullptr) return nullptr; @@ -7896,10 +7952,13 @@ clang::EnumConstantDecl *TypeSystemClang::AddEnumerationValueToEnumerationType( if (!enutype) return nullptr; - clang::EnumConstantDecl *enumerator_decl = clang::EnumConstantDecl::Create( - getASTContext(), enutype->getDecl(), clang::SourceLocation(), - name ? &getASTContext().Idents.get(name) : nullptr, // Identifier - clang::QualType(enutype, 0), nullptr, value); + clang::EnumConstantDecl *enumerator_decl = + clang::EnumConstantDecl::CreateDeserialized(getASTContext(), 0); + enumerator_decl->setDeclContext(enutype->getDecl()); + if (name && name[0]) + enumerator_decl->setDeclName(&getASTContext().Idents.get(name)); + enumerator_decl->setType(clang::QualType(enutype, 0)); + enumerator_decl->setInitVal(value); if (!enumerator_decl) return nullptr; diff --git a/lldb/include/lldb/Symbol/TypeSystemClang.h b/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.h similarity index 95% rename from lldb/include/lldb/Symbol/TypeSystemClang.h rename to lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.h index cf7f8920b42e6..93941587a12e6 100644 --- a/lldb/include/lldb/Symbol/TypeSystemClang.h +++ b/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.h @@ -31,6 +31,7 @@ #include "lldb/Symbol/TypeSystem.h" #include "lldb/Target/Target.h" #include "lldb/Utility/ConstString.h" +#include "lldb/Utility/Flags.h" #include "lldb/Utility/Log.h" #include "lldb/Utility/Logging.h" #include "lldb/lldb-enumerations.h" @@ -38,10 +39,44 @@ class DWARFASTParserClang; class PDBASTParser; +namespace clang { +class FileManager; +class HeaderSearch; +class ModuleMap; +} // namespace clang + namespace lldb_private { class Declaration; +/// The implementation of lldb::Type's m_payload field for TypeSystemClang. +class TypePayloadClang { + /// Layout: bit 31 ... IsCompleteObjCClass. + Type::Payload m_payload = 0; +public: + TypePayloadClang() = default; + explicit TypePayloadClang(bool is_complete_objc_class); + explicit TypePayloadClang(uint32_t opaque_payload) : m_payload(opaque_payload) {} + operator Type::Payload() { return m_payload; } + + static constexpr unsigned ObjCClassBit = 1 << 31; + bool IsCompleteObjCClass() { return Flags(m_payload).Test(ObjCClassBit); } + void SetIsCompleteObjCClass(bool is_complete_objc_class) { + m_payload = is_complete_objc_class ? Flags(m_payload).Set(ObjCClassBit) + : Flags(m_payload).Clear(ObjCClassBit); + } +}; + +/// A TypeSystem implementation based on Clang. +/// +/// This class uses a single clang::ASTContext as the backend for storing +/// its types and declarations. Every clang::ASTContext should also just have +/// a single associated TypeSystemClang instance that manages it. +/// +/// The clang::ASTContext instance can either be created by TypeSystemClang +/// itself or it can adopt an existing clang::ASTContext (for example, when +/// it is necessary to provide a TypeSystem interface for an existing +/// clang::ASTContext that was created by clang::CompilerInstance). class TypeSystemClang : public TypeSystem { // LLVM RTTI support static char ID; @@ -571,6 +606,9 @@ class TypeSystemClang : public TypeSystem { ConstString GetTypeName(lldb::opaque_compiler_type_t type) override; + ConstString GetDisplayTypeName(lldb::opaque_compiler_type_t type, + const SymbolContext *sc) override; + uint32_t GetTypeInfo(lldb::opaque_compiler_type_t type, CompilerType *pointee_or_element_compiler_type) override; @@ -777,13 +815,11 @@ class TypeSystemClang : public TypeSystem { const CompilerType &var_type, lldb::AccessType access); - clang::CXXMethodDecl * - AddMethodToCXXRecordType(lldb::opaque_compiler_type_t type, const char *name, - const char *mangled_name, - const CompilerType &method_type, - lldb::AccessType access, bool is_virtual, - bool is_static, bool is_inline, bool is_explicit, - bool is_attr_used, bool is_artificial); + clang::CXXMethodDecl *AddMethodToCXXRecordType( + lldb::opaque_compiler_type_t type, llvm::StringRef name, + const char *mangled_name, const CompilerType &method_type, + lldb::AccessType access, bool is_virtual, bool is_static, bool is_inline, + bool is_explicit, bool is_attr_used, bool is_artificial); void AddMethodOverridesForCXXRecordType(lldb::opaque_compiler_type_t type); diff --git a/lldb/source/Plugins/UnwindAssembly/InstEmulation/UnwindAssemblyInstEmulation.cpp b/lldb/source/Plugins/UnwindAssembly/InstEmulation/UnwindAssemblyInstEmulation.cpp index 4aa9fb634b61a..04ce23908fd16 100644 --- a/lldb/source/Plugins/UnwindAssembly/InstEmulation/UnwindAssemblyInstEmulation.cpp +++ b/lldb/source/Plugins/UnwindAssembly/InstEmulation/UnwindAssemblyInstEmulation.cpp @@ -123,18 +123,12 @@ bool UnwindAssemblyInstEmulation::GetNonCallSiteUnwindPlanFromAssembly( // Add the initial state to the save list with offset 0. saved_unwind_states.insert({0, {last_row, m_register_values}}); - // cache the pc register number (in whatever register numbering this - // UnwindPlan uses) for quick reference during instruction parsing. - RegisterInfo pc_reg_info; - m_inst_emulator_up->GetRegisterInfo( - eRegisterKindGeneric, LLDB_REGNUM_GENERIC_PC, pc_reg_info); - - // cache the return address register number (in whatever register + // cache the stack pointer register number (in whatever register // numbering this UnwindPlan uses) for quick reference during // instruction parsing. - RegisterInfo ra_reg_info; + RegisterInfo sp_reg_info; m_inst_emulator_up->GetRegisterInfo( - eRegisterKindGeneric, LLDB_REGNUM_GENERIC_RA, ra_reg_info); + eRegisterKindGeneric, LLDB_REGNUM_GENERIC_SP, sp_reg_info); // The architecture dependent condition code of the last processed // instruction. @@ -165,6 +159,23 @@ bool UnwindAssemblyInstEmulation::GetNonCallSiteUnwindPlanFromAssembly( *newrow = *it->second.first; m_curr_row.reset(newrow); m_register_values = it->second.second; + // re-set the CFA register ivars to match the + // new m_curr_row. + if (sp_reg_info.name && + m_curr_row->GetCFAValue().IsRegisterPlusOffset()) { + uint32_t row_cfa_regnum = + m_curr_row->GetCFAValue().GetRegisterNumber(); + lldb::RegisterKind row_kind = + m_unwind_plan_ptr->GetRegisterKind(); + // set m_cfa_reg_info to the row's CFA reg. + m_inst_emulator_up->GetRegisterInfo(row_kind, row_cfa_regnum, + m_cfa_reg_info); + // set m_fp_is_cfa. + if (sp_reg_info.kinds[row_kind] == row_cfa_regnum) + m_fp_is_cfa = false; + else + m_fp_is_cfa = true; + } } m_inst_emulator_up->SetInstruction(inst->GetOpcode(), @@ -195,6 +206,23 @@ bool UnwindAssemblyInstEmulation::GetNonCallSiteUnwindPlanFromAssembly( std::make_shared(*saved_state.first); m_curr_row->SetOffset(current_offset); m_register_values = saved_state.second; + // re-set the CFA register ivars to match the + // new m_curr_row. + if (sp_reg_info.name && + m_curr_row->GetCFAValue().IsRegisterPlusOffset()) { + uint32_t row_cfa_regnum = + m_curr_row->GetCFAValue().GetRegisterNumber(); + lldb::RegisterKind row_kind = + m_unwind_plan_ptr->GetRegisterKind(); + // set m_cfa_reg_info to the row's CFA reg. + m_inst_emulator_up->GetRegisterInfo(row_kind, row_cfa_regnum, + m_cfa_reg_info); + // set m_fp_is_cfa. + if (sp_reg_info.kinds[row_kind] == row_cfa_regnum) + m_fp_is_cfa = false; + else + m_fp_is_cfa = true; + } bool replace_existing = true; // The last instruction might already // created a row for this offset and diff --git a/lldb/source/Symbol/CMakeLists.txt b/lldb/source/Symbol/CMakeLists.txt index 0abdefa860133..e0101858b10b7 100644 --- a/lldb/source/Symbol/CMakeLists.txt +++ b/lldb/source/Symbol/CMakeLists.txt @@ -7,17 +7,11 @@ endif() add_lldb_library(lldbSymbol ArmUnwindInfo.cpp Block.cpp - TypeSystemClang.cpp - ClangASTImporter.cpp - ClangASTMetadata.cpp - ClangExternalASTSourceCallbacks.cpp - ClangUtil.cpp CompactUnwindInfo.cpp CompileUnit.cpp CompilerDecl.cpp CompilerDeclContext.cpp CompilerType.cpp - CxxModuleHandler.cpp DWARFCallFrameInfo.cpp DebugMacros.cpp Declaration.cpp @@ -39,6 +33,7 @@ add_lldb_library(lldbSymbol TypeList.cpp TypeMap.cpp TypeSystem.cpp + TypeSystemSwiftTypeRef.cpp UnwindPlan.cpp UnwindTable.cpp Variable.cpp @@ -59,18 +54,8 @@ add_lldb_library(lldbSymbol lldbHost lldbTarget lldbUtility - lldbPluginExpressionParserClang - lldbPluginExpressionParserSwift - lldbPluginSymbolFileDWARF - lldbPluginSymbolFilePDB lldbPluginObjCLanguage lldbPluginPlatformMacOSX - lldbPluginObjCRuntime - - CLANG_LIBS - clangAST - clangBasic - clangFrontend LINK_COMPONENTS Support diff --git a/lldb/source/Symbol/CompilerType.cpp b/lldb/source/Symbol/CompilerType.cpp index 0f68d73413af1..286718c4faead 100644 --- a/lldb/source/Symbol/CompilerType.cpp +++ b/lldb/source/Symbol/CompilerType.cpp @@ -288,12 +288,10 @@ ConstString CompilerType::GetTypeName() const { return ConstString(""); } -ConstString -CompilerType::GetDisplayTypeName(const SymbolContext *sc) const { - if (IsValid()) { +ConstString CompilerType::GetDisplayTypeName(const SymbolContext *sc) const { + if (IsValid()) return m_type_system->GetDisplayTypeName(m_type, sc); - } - return ConstString(); + return ConstString(""); } ConstString CompilerType::GetMangledTypeName() const { diff --git a/lldb/source/Symbol/Function.cpp b/lldb/source/Symbol/Function.cpp index c8c16cf11b87d..0a002b23edb33 100644 --- a/lldb/source/Symbol/Function.cpp +++ b/lldb/source/Symbol/Function.cpp @@ -131,27 +131,36 @@ size_t InlineFunctionInfo::MemorySize() const { /// @name Call site related structures /// @{ -lldb::addr_t CallEdge::GetReturnPCAddress(Function &caller, - Target &target) const { +lldb::addr_t CallEdge::GetLoadAddress(lldb::addr_t unresolved_pc, + Function &caller, Target &target) { Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_STEP)); const Address &caller_start_addr = caller.GetAddressRange().GetBaseAddress(); ModuleSP caller_module_sp = caller_start_addr.GetModule(); if (!caller_module_sp) { - LLDB_LOG(log, "GetReturnPCAddress: cannot get Module for caller"); + LLDB_LOG(log, "GetLoadAddress: cannot get Module for caller"); return LLDB_INVALID_ADDRESS; } SectionList *section_list = caller_module_sp->GetSectionList(); if (!section_list) { - LLDB_LOG(log, "GetReturnPCAddress: cannot get SectionList for Module"); + LLDB_LOG(log, "GetLoadAddress: cannot get SectionList for Module"); return LLDB_INVALID_ADDRESS; } - Address return_pc_addr = Address(return_pc, section_list); - lldb::addr_t ret_addr = return_pc_addr.GetLoadAddress(&target); - return ret_addr; + Address the_addr = Address(unresolved_pc, section_list); + lldb::addr_t load_addr = the_addr.GetLoadAddress(&target); + return load_addr; +} + +lldb::addr_t CallEdge::GetReturnPCAddress(Function &caller, + Target &target) const { + return GetLoadAddress(return_pc, caller, target); +} + +lldb::addr_t CallEdge::GetCallInstPC(Function &caller, Target &target) const { + return GetLoadAddress(call_inst_pc, caller, target); } void DirectCallEdge::ParseSymbolFileAndResolve(ModuleList &images) { diff --git a/lldb/source/Symbol/SwiftASTContext.cpp b/lldb/source/Symbol/SwiftASTContext.cpp index 0bac8f3d3c157..eb79cd5414564 100644 --- a/lldb/source/Symbol/SwiftASTContext.cpp +++ b/lldb/source/Symbol/SwiftASTContext.cpp @@ -84,9 +84,11 @@ #include "swift/Strings.h" #include "Plugins/ExpressionParser/Clang/ClangHost.h" +#include "Plugins/ExpressionParser/Clang/ClangUtil.h" #include "Plugins/ExpressionParser/Swift/SwiftDiagnostic.h" #include "Plugins/ExpressionParser/Swift/SwiftHost.h" #include "Plugins/ExpressionParser/Swift/SwiftUserExpression.h" +#include "Plugins/TypeSystem/Clang/TypeSystemClang.h" #include "lldb/Core/Debugger.h" #include "lldb/Core/DumpDataExtractor.h" #include "lldb/Core/Module.h" @@ -101,13 +103,11 @@ #include "lldb/Host/HostInfo.h" #include "lldb/Host/StringConvert.h" #include "lldb/Host/XML.h" -#include "lldb/Symbol/ClangUtil.h" #include "lldb/Symbol/CompileUnit.h" #include "lldb/Symbol/ObjectFile.h" #include "lldb/Symbol/SourceModule.h" #include "lldb/Symbol/SymbolFile.h" #include "lldb/Symbol/TypeMap.h" -#include "lldb/Symbol/TypeSystemClang.h" #include "lldb/Symbol/VariableList.h" #include "lldb/Target/Platform.h" #include "lldb/Target/Process.h" @@ -118,6 +118,7 @@ #include "lldb/Utility/LLDBAssert.h" #include "lldb/Utility/Log.h" #include "lldb/Utility/Status.h" +#include "lldb/Utility/XcodeSDK.h" #include "llvm/ADT/ScopeExit.h" #include "Plugins/Platform/MacOSX/PlatformDarwin.h" @@ -168,8 +169,6 @@ std::recursive_mutex g_log_mutex; using namespace lldb; using namespace lldb_private; -char TypeSystemSwift::ID; -char TypeSystemSwiftTypeRef::ID; char SwiftASTContext::ID; char SwiftASTContextForExpressions::ID; @@ -179,8 +178,12 @@ CompilerType lldb_private::ToCompilerType(swift::Type qual_type) { qual_type.getPointer()); } +TypePayloadSwift::TypePayloadSwift(bool is_fixed_value_buffer) { + SetIsFixedValueBuffer(is_fixed_value_buffer); +} + CompilerType SwiftASTContext::GetCompilerType(ConstString mangled_name) { - return {&m_typeref_typesystem, (void *)mangled_name.AsCString()}; + return m_typeref_typesystem.GetTypeFromMangledTypename(mangled_name); } CompilerType SwiftASTContext::GetCompilerType(swift::TypeBase *swift_type) { @@ -193,11 +196,10 @@ swift::Type TypeSystemSwiftTypeRef::GetSwiftType(CompilerType compiler_type) { if (!ts) return {}; - Status error; // FIXME: Suboptimal performance, because the ConstString is looked up again. ConstString mangled_name( reinterpret_cast(compiler_type.GetOpaqueQualType())); - return ts->m_swift_ast_context->ReconstructType(mangled_name, error); + return ts->m_swift_ast_context->ReconstructType(mangled_name); } swift::Type SwiftASTContext::GetSwiftType(CompilerType compiler_type) { @@ -219,505 +221,10 @@ swift::CanType SwiftASTContext::GetCanonicalSwiftType(void *opaque_type) { return lldb_private::GetCanonicalSwiftType(CompilerType(this, opaque_type)); } -ConstString TypeSystemSwiftTypeRef::GetMangledTypeName(void *type) { - assert(type && *reinterpret_cast(type) == '$' && - "wrong type system"); - // FIXME: Suboptimal performance, because the ConstString is looked up again. - return ConstString(reinterpret_cast(type)); -} - ConstString SwiftASTContext::GetMangledTypeName(void *type) { return GetMangledTypeName(GetSwiftType({this, type}).getPointer()); } -TypeSystemSwift::TypeSystemSwift() : TypeSystem() {} - -CompilerType TypeSystemSwift::GetInstanceType(CompilerType compiler_type) { - auto *ts = compiler_type.GetTypeSystem(); - if (auto *tr = llvm::dyn_cast_or_null(ts)) - return tr->GetInstanceType(compiler_type.GetOpaqueQualType()); - if (auto *ast = llvm::dyn_cast_or_null(ts)) - return ast->GetInstanceType(compiler_type.GetOpaqueQualType()); - return {}; -} - -TypeSystemSwiftTypeRef::TypeSystemSwiftTypeRef( - SwiftASTContext *swift_ast_context) - : m_swift_ast_context(swift_ast_context) { - m_description = "TypeSystemSwiftTypeRef"; -} - -void *TypeSystemSwiftTypeRef::ReconstructType(void *type) { - Status error; - return m_swift_ast_context->ReconstructType(GetMangledTypeName(type), error); -} - -CompilerType TypeSystemSwiftTypeRef::ReconstructType(CompilerType type) { - return {m_swift_ast_context, ReconstructType(type.GetOpaqueQualType())}; -} - -lldb::TypeSP TypeSystemSwiftTypeRef::GetCachedType(ConstString mangled) { - return m_swift_ast_context->GetCachedType(mangled); -} - -void TypeSystemSwiftTypeRef::SetCachedType(ConstString mangled, - const lldb::TypeSP &type_sp) { - return m_swift_ast_context->SetCachedType(mangled, type_sp); -} - -Module *TypeSystemSwiftTypeRef::GetModule() const { - return m_swift_ast_context->GetModule(); -} - -ConstString TypeSystemSwiftTypeRef::GetPluginName() { - return ConstString("TypeSystemSwiftTypeRef"); -} -uint32_t TypeSystemSwiftTypeRef::GetPluginVersion() { return 1; } - -bool TypeSystemSwiftTypeRef::SupportsLanguage(lldb::LanguageType language) { - return language == eLanguageTypeSwift; -} - -Status TypeSystemSwiftTypeRef::IsCompatible() { - return m_swift_ast_context->IsCompatible(); -} - -void TypeSystemSwiftTypeRef::DiagnoseWarnings(Process &process, - Module &module) const { - m_swift_ast_context->DiagnoseWarnings(process, module); -} -DWARFASTParser *TypeSystemSwiftTypeRef::GetDWARFParser() { - return m_swift_ast_context->GetDWARFParser(); -} -ConstString TypeSystemSwiftTypeRef::DeclContextGetName(void *opaque_decl_ctx) { - return m_swift_ast_context->DeclContextGetName(opaque_decl_ctx); -} -ConstString TypeSystemSwiftTypeRef::DeclContextGetScopeQualifiedName( - void *opaque_decl_ctx) { - return m_swift_ast_context->DeclContextGetScopeQualifiedName(opaque_decl_ctx); -} -bool TypeSystemSwiftTypeRef::DeclContextIsClassMethod( - void *opaque_decl_ctx, lldb::LanguageType *language_ptr, - bool *is_instance_method_ptr, ConstString *language_object_name_ptr) { - return m_swift_ast_context->DeclContextIsClassMethod( - opaque_decl_ctx, language_ptr, is_instance_method_ptr, - language_object_name_ptr); -} - -// Tests - -#ifndef NDEBUG -bool TypeSystemSwiftTypeRef::Verify(lldb::opaque_compiler_type_t type) { - if (!type) - return true; - - const char *str = reinterpret_cast(type); - return SwiftLanguageRuntime::IsSwiftMangledName(str); -} -#endif - -bool TypeSystemSwiftTypeRef::IsArrayType(void *type, CompilerType *element_type, - uint64_t *size, bool *is_incomplete) { - return m_swift_ast_context->IsArrayType(ReconstructType(type), element_type, - size, is_incomplete); -} -bool TypeSystemSwiftTypeRef::IsAggregateType(void *type) { - return m_swift_ast_context->IsAggregateType(ReconstructType(type)); -} -bool TypeSystemSwiftTypeRef::IsCharType(void *type) { - return m_swift_ast_context->IsCharType(ReconstructType(type)); -} -bool TypeSystemSwiftTypeRef::IsCompleteType(void *type) { - return m_swift_ast_context->IsCompleteType(ReconstructType(type)); -} -bool TypeSystemSwiftTypeRef::IsDefined(void *type) { - return m_swift_ast_context->IsDefined(ReconstructType(type)); -} -bool TypeSystemSwiftTypeRef::IsFloatingPointType(void *type, uint32_t &count, - bool &is_complex) { - return m_swift_ast_context->IsFloatingPointType(ReconstructType(type), count, - is_complex); -} -bool TypeSystemSwiftTypeRef::IsFunctionType(void *type, bool *is_variadic_ptr) { - return m_swift_ast_context->IsFunctionType(ReconstructType(type), - is_variadic_ptr); -} -size_t TypeSystemSwiftTypeRef::GetNumberOfFunctionArguments(void *type) { - return m_swift_ast_context->GetNumberOfFunctionArguments( - ReconstructType(type)); -} -CompilerType -TypeSystemSwiftTypeRef::GetFunctionArgumentAtIndex(void *type, - const size_t index) { - return m_swift_ast_context->GetFunctionArgumentAtIndex(ReconstructType(type), - index); -} -bool TypeSystemSwiftTypeRef::IsFunctionPointerType(void *type) { - return m_swift_ast_context->IsFunctionPointerType(ReconstructType(type)); -} -bool TypeSystemSwiftTypeRef::IsBlockPointerType( - void *type, CompilerType *function_pointer_type_ptr) { - return m_swift_ast_context->IsBlockPointerType(ReconstructType(type), - function_pointer_type_ptr); -} -bool TypeSystemSwiftTypeRef::IsIntegerType(void *type, bool &is_signed) { - return m_swift_ast_context->IsIntegerType(ReconstructType(type), is_signed); -} -bool TypeSystemSwiftTypeRef::IsPossibleDynamicType(void *type, - CompilerType *target_type, - bool check_cplusplus, - bool check_objc) { - return m_swift_ast_context->IsPossibleDynamicType( - ReconstructType(type), target_type, check_cplusplus, check_objc); -} -bool TypeSystemSwiftTypeRef::IsPointerType(void *type, - CompilerType *pointee_type) { - return m_swift_ast_context->IsPointerType(ReconstructType(type), - pointee_type); -} -bool TypeSystemSwiftTypeRef::IsScalarType(void *type) { - return m_swift_ast_context->IsScalarType(ReconstructType(type)); -} -bool TypeSystemSwiftTypeRef::IsVoidType(void *type) { - return m_swift_ast_context->IsVoidType(ReconstructType(type)); -} -bool TypeSystemSwiftTypeRef::CanPassInRegisters(const CompilerType &type) { - return m_swift_ast_context->CanPassInRegisters( - {m_swift_ast_context, ReconstructType(type.GetOpaqueQualType())}); -} -// Type Completion -bool TypeSystemSwiftTypeRef::GetCompleteType(void *type) { - return m_swift_ast_context->GetCompleteType(ReconstructType(type)); -} -// AST related queries -uint32_t TypeSystemSwiftTypeRef::GetPointerByteSize() { - return m_swift_ast_context->GetPointerByteSize(); -} -// Accessors -ConstString TypeSystemSwiftTypeRef::GetTypeName(void *type) { - return m_swift_ast_context->GetTypeName(ReconstructType(type)); -} -ConstString -TypeSystemSwiftTypeRef::GetDisplayTypeName(void *type, - const SymbolContext *sc) { - return m_swift_ast_context->GetDisplayTypeName(ReconstructType(type), sc); -} -uint32_t TypeSystemSwiftTypeRef::GetTypeInfo( - void *type, CompilerType *pointee_or_element_clang_type) { - return m_swift_ast_context->GetTypeInfo(ReconstructType(type), - pointee_or_element_clang_type); -} -lldb::LanguageType TypeSystemSwiftTypeRef::GetMinimumLanguage(void *type) { - return m_swift_ast_context->GetMinimumLanguage(ReconstructType(type)); -} -lldb::TypeClass TypeSystemSwiftTypeRef::GetTypeClass(void *type) { - return m_swift_ast_context->GetTypeClass(ReconstructType(type)); -} - -// Creating related types -CompilerType TypeSystemSwiftTypeRef::GetArrayElementType(void *type, - uint64_t *stride) { - return m_swift_ast_context->GetArrayElementType(ReconstructType(type), - stride); -} -CompilerType TypeSystemSwiftTypeRef::GetCanonicalType(void *type) { - return m_swift_ast_context->GetCanonicalType(ReconstructType(type)); -} -int TypeSystemSwiftTypeRef::GetFunctionArgumentCount(void *type) { - return m_swift_ast_context->GetFunctionArgumentCount(ReconstructType(type)); -} -CompilerType -TypeSystemSwiftTypeRef::GetFunctionArgumentTypeAtIndex(void *type, size_t idx) { - return m_swift_ast_context->GetFunctionArgumentTypeAtIndex( - ReconstructType(type), idx); -} -CompilerType TypeSystemSwiftTypeRef::GetFunctionReturnType(void *type) { - return m_swift_ast_context->GetFunctionReturnType(ReconstructType(type)); -} -size_t TypeSystemSwiftTypeRef::GetNumMemberFunctions(void *type) { - return m_swift_ast_context->GetNumMemberFunctions(ReconstructType(type)); -} -TypeMemberFunctionImpl -TypeSystemSwiftTypeRef::GetMemberFunctionAtIndex(void *type, size_t idx) { - return m_swift_ast_context->GetMemberFunctionAtIndex(ReconstructType(type), - idx); -} -CompilerType TypeSystemSwiftTypeRef::GetPointeeType(void *type) { - return m_swift_ast_context->GetPointeeType(ReconstructType(type)); -} -CompilerType TypeSystemSwiftTypeRef::GetPointerType(void *type) { - return m_swift_ast_context->GetPointerType(ReconstructType(type)); -} - -// Exploring the type -const llvm::fltSemantics & -TypeSystemSwiftTypeRef::GetFloatTypeSemantics(size_t byte_size) { - return m_swift_ast_context->GetFloatTypeSemantics(byte_size); -} -llvm::Optional -TypeSystemSwiftTypeRef::GetBitSize(lldb::opaque_compiler_type_t type, - ExecutionContextScope *exe_scope) { - return m_swift_ast_context->GetBitSize(ReconstructType(type), exe_scope); -} -llvm::Optional -TypeSystemSwiftTypeRef::GetByteStride(lldb::opaque_compiler_type_t type, - ExecutionContextScope *exe_scope) { - return m_swift_ast_context->GetByteStride(ReconstructType(type), exe_scope); -} -lldb::Encoding TypeSystemSwiftTypeRef::GetEncoding(void *type, - uint64_t &count) { - return m_swift_ast_context->GetEncoding(ReconstructType(type), count); -} -lldb::Format TypeSystemSwiftTypeRef::GetFormat(void *type) { - return m_swift_ast_context->GetFormat(ReconstructType(type)); -} -uint32_t -TypeSystemSwiftTypeRef::GetNumChildren(void *type, bool omit_empty_base_classes, - const ExecutionContext *exe_ctx) { - return m_swift_ast_context->GetNumChildren(ReconstructType(type), - omit_empty_base_classes, exe_ctx); -} -lldb::BasicType TypeSystemSwiftTypeRef::GetBasicTypeEnumeration(void *type) { - return m_swift_ast_context->GetBasicTypeEnumeration(ReconstructType(type)); -} -uint32_t TypeSystemSwiftTypeRef::GetNumFields(void *type) { - return m_swift_ast_context->GetNumFields(ReconstructType(type)); -} -CompilerType TypeSystemSwiftTypeRef::GetFieldAtIndex( - void *type, size_t idx, std::string &name, uint64_t *bit_offset_ptr, - uint32_t *bitfield_bit_size_ptr, bool *is_bitfield_ptr) { - return m_swift_ast_context->GetFieldAtIndex( - ReconstructType(type), idx, name, bit_offset_ptr, bitfield_bit_size_ptr, - is_bitfield_ptr); -} -CompilerType TypeSystemSwiftTypeRef::GetChildCompilerTypeAtIndex( - void *type, ExecutionContext *exe_ctx, size_t idx, - bool transparent_pointers, bool omit_empty_base_classes, - bool ignore_array_bounds, std::string &child_name, - uint32_t &child_byte_size, int32_t &child_byte_offset, - uint32_t &child_bitfield_bit_size, uint32_t &child_bitfield_bit_offset, - bool &child_is_base_class, bool &child_is_deref_of_parent, - ValueObject *valobj, uint64_t &language_flags) { - return m_swift_ast_context->GetChildCompilerTypeAtIndex( - ReconstructType(type), exe_ctx, idx, transparent_pointers, - omit_empty_base_classes, ignore_array_bounds, child_name, child_byte_size, - child_byte_offset, child_bitfield_bit_size, child_bitfield_bit_offset, - child_is_base_class, child_is_deref_of_parent, valobj, language_flags); -} -uint32_t -TypeSystemSwiftTypeRef::GetIndexOfChildWithName(void *type, const char *name, - bool omit_empty_base_classes) { - return m_swift_ast_context->GetIndexOfChildWithName( - ReconstructType(type), name, omit_empty_base_classes); -} -size_t TypeSystemSwiftTypeRef::GetIndexOfChildMemberWithName( - void *type, const char *name, bool omit_empty_base_classes, - std::vector &child_indexes) { - return m_swift_ast_context->GetIndexOfChildMemberWithName( - ReconstructType(type), name, omit_empty_base_classes, child_indexes); -} -size_t TypeSystemSwiftTypeRef::GetNumTemplateArguments(void *type) { - return m_swift_ast_context->GetNumTemplateArguments(ReconstructType(type)); -} -CompilerType TypeSystemSwiftTypeRef::GetTypeForFormatters(void *type) { - return m_swift_ast_context->GetTypeForFormatters(ReconstructType(type)); -} -LazyBool TypeSystemSwiftTypeRef::ShouldPrintAsOneLiner(void *type, - ValueObject *valobj) { - return m_swift_ast_context->ShouldPrintAsOneLiner(ReconstructType(type), - valobj); -} -bool TypeSystemSwiftTypeRef::IsMeaninglessWithoutDynamicResolution(void *type) { - return m_swift_ast_context->IsMeaninglessWithoutDynamicResolution( - ReconstructType(type)); -} -bool TypeSystemSwiftTypeRef::IsImportedType(CompilerType type, - CompilerType *original_type) { - return m_swift_ast_context->IsImportedType( - {m_swift_ast_context, ReconstructType(type.GetOpaqueQualType())}, - original_type); -} -bool TypeSystemSwiftTypeRef::IsErrorType(CompilerType compiler_type) { - return m_swift_ast_context->IsErrorType( - {m_swift_ast_context, - ReconstructType(compiler_type.GetOpaqueQualType())}); -} -CompilerType TypeSystemSwiftTypeRef::GetErrorType() { - return m_swift_ast_context->GetErrorType(); -} - -CompilerType -TypeSystemSwiftTypeRef::GetReferentType(CompilerType compiler_type) { - return m_swift_ast_context->GetReferentType( - {m_swift_ast_context, - ReconstructType(compiler_type.GetOpaqueQualType())}); -} - -CompilerType TypeSystemSwiftTypeRef::GetInstanceType(void *type) { - return m_swift_ast_context->GetInstanceType(ReconstructType(type)); -} -TypeSystemSwift::TypeAllocationStrategy -TypeSystemSwiftTypeRef::GetAllocationStrategy(CompilerType type) { - return m_swift_ast_context->GetAllocationStrategy( - {m_swift_ast_context, ReconstructType(type.GetOpaqueQualType())}); -} -CompilerType TypeSystemSwiftTypeRef::CreateTupleType( - const std::vector &elements) { - return m_swift_ast_context->CreateTupleType(elements); -} -void TypeSystemSwiftTypeRef::DumpTypeDescription( - void *type, bool print_help_if_available, - bool print_extensions_if_available) { - return m_swift_ast_context->DumpTypeDescription( - ReconstructType(type), print_help_if_available, print_help_if_available); -} -void TypeSystemSwiftTypeRef::DumpTypeDescription( - void *type, Stream *s, bool print_help_if_available, - bool print_extensions_if_available) { - return m_swift_ast_context->DumpTypeDescription( - ReconstructType(type), s, print_help_if_available, - print_extensions_if_available); -} - -// Dumping types -#ifndef NDEBUG -/// Convenience LLVM-style dump method for use in the debugger only. -LLVM_DUMP_METHOD void -TypeSystemSwiftTypeRef::dump(lldb::opaque_compiler_type_t type) const { - llvm::dbgs() << reinterpret_cast(type) << "\n"; -} -#endif - -void TypeSystemSwiftTypeRef::DumpValue( - void *type, ExecutionContext *exe_ctx, Stream *s, lldb::Format format, - const DataExtractor &data, lldb::offset_t data_offset, - size_t data_byte_size, uint32_t bitfield_bit_size, - uint32_t bitfield_bit_offset, bool show_types, bool show_summary, - bool verbose, uint32_t depth) { - return m_swift_ast_context->DumpValue( - ReconstructType(type), exe_ctx, s, format, data, data_offset, - data_byte_size, bitfield_bit_size, bitfield_bit_offset, show_types, - show_summary, verbose, depth); -} - -bool TypeSystemSwiftTypeRef::DumpTypeValue( - void *type, Stream *s, lldb::Format format, const DataExtractor &data, - lldb::offset_t data_offset, size_t data_byte_size, - uint32_t bitfield_bit_size, uint32_t bitfield_bit_offset, - ExecutionContextScope *exe_scope, bool is_base_class) { - return m_swift_ast_context->DumpTypeValue( - ReconstructType(type), s, format, data, data_offset, data_byte_size, - bitfield_bit_size, bitfield_bit_offset, exe_scope, is_base_class); -} - -void TypeSystemSwiftTypeRef::DumpTypeDescription(void *type) { - return m_swift_ast_context->DumpTypeDescription(ReconstructType(type)); -} -void TypeSystemSwiftTypeRef::DumpTypeDescription(void *type, Stream *s) { - return m_swift_ast_context->DumpTypeDescription(ReconstructType(type), s); -} -bool TypeSystemSwiftTypeRef::IsRuntimeGeneratedType(void *type) { - return m_swift_ast_context->IsRuntimeGeneratedType(ReconstructType(type)); -} -void TypeSystemSwiftTypeRef::DumpSummary(void *type, ExecutionContext *exe_ctx, - Stream *s, const DataExtractor &data, - lldb::offset_t data_offset, - size_t data_byte_size) { - return m_swift_ast_context->DumpSummary(ReconstructType(type), exe_ctx, s, - data, data_offset, data_byte_size); -} -bool TypeSystemSwiftTypeRef::IsPointerOrReferenceType( - void *type, CompilerType *pointee_type) { - return m_swift_ast_context->IsPointerOrReferenceType(ReconstructType(type), - pointee_type); -} -unsigned TypeSystemSwiftTypeRef::GetTypeQualifiers(void *type) { - return m_swift_ast_context->GetTypeQualifiers(ReconstructType(type)); -} -bool TypeSystemSwiftTypeRef::IsCStringType(void *type, uint32_t &length) { - return m_swift_ast_context->IsCStringType(ReconstructType(type), length); -} -llvm::Optional -TypeSystemSwiftTypeRef::GetTypeBitAlign(void *type, - ExecutionContextScope *exe_scope) { - return m_swift_ast_context->GetTypeBitAlign(ReconstructType(type), exe_scope); -} -CompilerType -TypeSystemSwiftTypeRef::GetBasicTypeFromAST(lldb::BasicType basic_type) { - return m_swift_ast_context->GetBasicTypeFromAST(basic_type); -} -bool TypeSystemSwiftTypeRef::IsBeingDefined(void *type) { - return m_swift_ast_context->IsBeingDefined(ReconstructType(type)); -} -bool TypeSystemSwiftTypeRef::IsConst(void *type) { - return m_swift_ast_context->IsConst(ReconstructType(type)); -} -uint32_t -TypeSystemSwiftTypeRef::IsHomogeneousAggregate(void *type, - CompilerType *base_type_ptr) { - return m_swift_ast_context->IsHomogeneousAggregate(ReconstructType(type), - base_type_ptr); -} -bool TypeSystemSwiftTypeRef::IsPolymorphicClass(void *type) { - return m_swift_ast_context->IsPolymorphicClass(ReconstructType(type)); -} -bool TypeSystemSwiftTypeRef::IsTypedefType(void *type) { - return m_swift_ast_context->IsTypedefType(ReconstructType(type)); -} -CompilerType TypeSystemSwiftTypeRef::GetTypedefedType(void *type) { - return m_swift_ast_context->GetTypedefedType(ReconstructType(type)); -} -CompilerType TypeSystemSwiftTypeRef::GetTypeForDecl(void *opaque_decl) { - return m_swift_ast_context->GetTypeForDecl(opaque_decl); -} -bool TypeSystemSwiftTypeRef::IsVectorType(void *type, - CompilerType *element_type, - uint64_t *size) { - return m_swift_ast_context->IsVectorType(ReconstructType(type), element_type, - size); -} -CompilerType TypeSystemSwiftTypeRef::GetFullyUnqualifiedType(void *type) { - return m_swift_ast_context->GetFullyUnqualifiedType(ReconstructType(type)); -} -CompilerType TypeSystemSwiftTypeRef::GetNonReferenceType(void *type) { - return m_swift_ast_context->GetNonReferenceType(ReconstructType(type)); -} -CompilerType TypeSystemSwiftTypeRef::GetLValueReferenceType(void *type) { - return m_swift_ast_context->GetLValueReferenceType(ReconstructType(type)); -} -CompilerType TypeSystemSwiftTypeRef::GetRValueReferenceType(void *type) { - return m_swift_ast_context->GetRValueReferenceType(ReconstructType(type)); -} -uint32_t TypeSystemSwiftTypeRef::GetNumDirectBaseClasses(void *type) { - return m_swift_ast_context->GetNumDirectBaseClasses(ReconstructType(type)); -} -uint32_t TypeSystemSwiftTypeRef::GetNumVirtualBaseClasses(void *type) { - return m_swift_ast_context->GetNumVirtualBaseClasses(ReconstructType(type)); -} -CompilerType -TypeSystemSwiftTypeRef::GetDirectBaseClassAtIndex(void *type, size_t idx, - uint32_t *bit_offset_ptr) { - return m_swift_ast_context->GetDirectBaseClassAtIndex(ReconstructType(type), - idx, bit_offset_ptr); -} -CompilerType -TypeSystemSwiftTypeRef::GetVirtualBaseClassAtIndex(void *type, size_t idx, - uint32_t *bit_offset_ptr) { - return m_swift_ast_context->GetVirtualBaseClassAtIndex(ReconstructType(type), - idx, bit_offset_ptr); -} -bool TypeSystemSwiftTypeRef::IsReferenceType(void *type, - CompilerType *pointee_type, - bool *is_rvalue) { - return m_swift_ast_context->IsReferenceType(ReconstructType(type), - pointee_type, is_rvalue); -} -bool TypeSystemSwiftTypeRef::ShouldTreatScalarValueAsAddress( - lldb::opaque_compiler_type_t type) { - return m_swift_ast_context->ShouldTreatScalarValueAsAddress( - ReconstructType(type)); -} - typedef lldb_private::ThreadSafeDenseMap ThreadSafeSwiftASTMap; @@ -948,7 +455,7 @@ class SwiftCStyleEnumDescriptor : public SwiftEnumDescriptor { Dump(m_nopayload_elems_bitmask).c_str()); for (auto enum_case : elements_with_no_payload) { - ConstString case_name(enum_case.decl->getName().str()); + ConstString case_name(enum_case.decl->getBaseIdentifier().str()); swift::ClusteredBitVector case_value = enum_impl_strategy.getBitPatternForNoPayloadElement(enum_case.decl); @@ -1081,7 +588,7 @@ class SwiftAllPayloadEnumDescriptor : public SwiftEnumDescriptor { auto module_ctx = enum_decl->getModuleContext(); const bool has_payload = true; for (auto enum_case : elements_with_payload) { - ConstString case_name(enum_case.decl->getName().str()); + ConstString case_name(enum_case.decl->getBaseIdentifier().str()); swift::EnumElementDecl *case_decl = enum_case.decl; assert(case_decl); @@ -1442,25 +949,9 @@ ConstString SwiftASTContext::GetPluginName() { uint32_t SwiftASTContext::GetPluginVersion() { return 1; } namespace { -enum SDKType : int { - MacOSX = 0, - iPhoneSimulator, - iPhoneOS, - AppleTVSimulator, - AppleTVOS, - WatchSimulator, - watchOS, - Linux, - numSDKTypes, - unknown = -1 -}; - -const char *const sdk_strings[] = { - "macosx", "iphonesimulator", "iphoneos", "appletvsimulator", - "appletvos", "watchsimulator", "watchos", "linux"}; struct SDKTypeMinVersion { - SDKType sdk_type; + XcodeSDK::Type sdk_type; unsigned min_version_major; unsigned min_version_minor; }; @@ -1474,7 +965,7 @@ static SDKTypeMinVersion GetSDKType(const llvm::Triple &target, // Only Darwin platforms know the concept of an SDK. auto host_os = host.getOS(); if (host_os != llvm::Triple::OSType::MacOSX) - return {SDKType::unknown, 0, 0}; + return {XcodeSDK::Type::unknown, 0, 0}; auto is_simulator = [&]() -> bool { return target.getEnvironment() == llvm::Triple::Simulator || @@ -1484,106 +975,22 @@ static SDKTypeMinVersion GetSDKType(const llvm::Triple &target, switch (target.getOS()) { case llvm::Triple::OSType::MacOSX: case llvm::Triple::OSType::Darwin: - return {SDKType::MacOSX, 10, 10}; + return {XcodeSDK::Type::MacOSX, 10, 10}; case llvm::Triple::OSType::IOS: if (is_simulator()) - return {SDKType::iPhoneSimulator, 8, 0}; - return {SDKType::iPhoneOS, 8, 0}; + return {XcodeSDK::Type::iPhoneSimulator, 8, 0}; + return {XcodeSDK::Type::iPhoneOS, 8, 0}; case llvm::Triple::OSType::TvOS: if (is_simulator()) - return {SDKType::AppleTVSimulator, 9, 0}; - return {SDKType::AppleTVOS, 9, 0}; + return {XcodeSDK::Type::AppleTVSimulator, 9, 0}; + return {XcodeSDK::Type::AppleTVOS, 9, 0}; case llvm::Triple::OSType::WatchOS: if (is_simulator()) - return {SDKType::WatchSimulator, 2, 0}; - return {SDKType::watchOS, 2, 0}; + return {XcodeSDK::Type::WatchSimulator, 2, 0}; + return {XcodeSDK::Type::watchOS, 2, 0}; default: - return {SDKType::unknown, 0, 0}; - } -} - -static StringRef GetXcodeContentsPath() { - static std::once_flag g_once_flag; - static std::string g_xcode_contents_path; - std::call_once(g_once_flag, [&]() { - const char substr[] = ".app/Contents/"; - - // First, try based on the current shlib's location. - if (FileSpec fspec = HostInfo::GetShlibDir()) { - std::string path_to_shlib = fspec.GetPath(); - size_t pos = path_to_shlib.rfind(substr); - if (pos != std::string::npos) { - path_to_shlib.erase(pos + strlen(substr)); - g_xcode_contents_path = path_to_shlib; - return; - } - } - - // Fall back to using xcrun. - if (HostInfo::GetArchitecture().GetTriple().getOS() == - llvm::Triple::MacOSX) { - int status = 0; - int signo = 0; - std::string output; - const char *command = "xcrun -sdk macosx --show-sdk-path"; - lldb_private::Status error = Host::RunShellCommand( - command, // shell command to run - {}, // current working directory - &status, // Put the exit status of the process in here - &signo, // Put the signal that caused the process to exit in here - &output, // Get the output from the command and place it in this - // string - std::chrono::seconds( - 3)); // Timeout in seconds to wait for shell program to finish - if (status == 0 && !output.empty()) { - size_t first_non_newline = output.find_last_not_of("\r\n"); - if (first_non_newline != std::string::npos) { - output.erase(first_non_newline + 1); - } - - size_t pos = output.rfind(substr); - if (pos != std::string::npos) { - output.erase(pos + strlen(substr)); - g_xcode_contents_path = output; - } - } - } - }); - return g_xcode_contents_path; -} - -static std::string GetCurrentToolchainPath() { - const char substr[] = ".xctoolchain/"; - - { - if (FileSpec fspec = HostInfo::GetShlibDir()) { - std::string path_to_shlib = fspec.GetPath(); - size_t pos = path_to_shlib.rfind(substr); - if (pos != std::string::npos) { - path_to_shlib.erase(pos + strlen(substr)); - return path_to_shlib; - } - } + return {XcodeSDK::Type::unknown, 0, 0}; } - - return {}; -} - -static std::string GetCurrentCLToolsPath() { - const char substr[] = "/CommandLineTools/"; - - { - if (FileSpec fspec = HostInfo::GetShlibDir()) { - std::string path_to_shlib = fspec.GetPath(); - size_t pos = path_to_shlib.rfind(substr); - if (pos != std::string::npos) { - path_to_shlib.erase(pos + strlen(substr)); - return path_to_shlib; - } - } - } - - return {}; } /// Return the name of the OS-specific subdirectory containing the @@ -1591,8 +998,9 @@ static std::string GetCurrentCLToolsPath() { StringRef SwiftASTContext::GetSwiftStdlibOSDir(const llvm::Triple &target, const llvm::Triple &host) { auto sdk = GetSDKType(target, host); - if (sdk.sdk_type != SDKType::unknown) - return sdk_strings[sdk.sdk_type]; + llvm::StringRef sdk_name = XcodeSDK::GetSDKNameForType(sdk.sdk_type); + if (!sdk_name.empty()) + return sdk_name; return target.getOSName(); } @@ -1611,10 +1019,11 @@ StringRef SwiftASTContext::GetResourceDir(const llvm::Triple &triple) { if (it != g_resource_dir_cache.end()) return it->getValue(); - auto value = - GetResourceDir(platform_sdk_path, swift_stdlib_os_dir, - GetSwiftResourceDir().GetPath(), GetXcodeContentsPath(), - GetCurrentToolchainPath(), GetCurrentCLToolsPath()); + auto value = GetResourceDir( + platform_sdk_path, swift_stdlib_os_dir, GetSwiftResourceDir().GetPath(), + PlatformDarwin::GetXcodeContentsDirectory().GetPath(), + PlatformDarwin::GetCurrentToolchainDirectory().GetPath(), + PlatformDarwin::GetCurrentCommandLineToolsDirectory().GetPath()); g_resource_dir_cache.insert({key, value}); return g_resource_dir_cache[key]; } @@ -2934,91 +2343,54 @@ namespace { struct SDKEnumeratorInfo { FileSpec found_path; - SDKType sdk_type; + XcodeSDK::Type sdk_type; uint32_t least_major; uint32_t least_minor; }; } // anonymous namespace -static bool SDKSupportsSwift(const FileSpec &sdk_path, SDKType desired_type) { +static bool SDKSupportsSwift(const FileSpec &sdk_path, + XcodeSDK::Type desired_type) { ConstString last_path_component = sdk_path.GetLastPathComponent(); if (last_path_component) { const llvm::StringRef sdk_name_raw = last_path_component.GetStringRef(); - std::string sdk_name_lower = sdk_name_raw.lower(); - const llvm::StringRef sdk_name(sdk_name_lower); + XcodeSDK sdk(sdk_name_raw); + XcodeSDK::Type sdk_type = sdk.GetType(); - llvm::StringRef version_part; - - SDKType sdk_type = SDKType::unknown; - - if (desired_type == SDKType::unknown) { - for (int i = (int)SDKType::MacOSX; i < SDKType::numSDKTypes; ++i) { - if (sdk_name.startswith(sdk_strings[i])) { - version_part = sdk_name.drop_front(strlen(sdk_strings[i])); - sdk_type = (SDKType)i; - break; - } - } - - // For non-Darwin SDKs assume Swift is supported - if (sdk_type == SDKType::unknown) - return true; - } else { - if (sdk_name.startswith(sdk_strings[desired_type])) { - version_part = sdk_name.drop_front(strlen(sdk_strings[desired_type])); - sdk_type = desired_type; - } else { - return false; - } - } - - const size_t major_dot_offset = version_part.find('.'); - if (major_dot_offset == llvm::StringRef::npos) - return false; - - const llvm::StringRef major_version = - version_part.slice(0, major_dot_offset); - const llvm::StringRef minor_part = - version_part.drop_front(major_dot_offset + 1); - - const size_t minor_dot_offset = minor_part.find('.'); - if (minor_dot_offset == llvm::StringRef::npos) - return false; - - const llvm::StringRef minor_version = minor_part.slice(0, minor_dot_offset); - - unsigned int major = 0; - unsigned int minor = 0; - - if (major_version.getAsInteger(10, major)) - return false; + // For non-Darwin SDKs assume Swift is supported. + if (desired_type == XcodeSDK::Type::unknown && + sdk_type == XcodeSDK::Type::unknown) + return true; - if (minor_version.getAsInteger(10, minor)) + if (sdk_type != desired_type) return false; + llvm::VersionTuple sdk_version = sdk.GetVersion(); + unsigned major = sdk_version.getMajor(); + unsigned minor = sdk_version.getMinor().getValueOr(0); switch (sdk_type) { - case SDKType::MacOSX: + case XcodeSDK::Type::MacOSX: if (major > 10 || (major == 10 && minor >= 10)) return true; break; - case SDKType::iPhoneOS: - case SDKType::iPhoneSimulator: + case XcodeSDK::Type::iPhoneOS: + case XcodeSDK::Type::iPhoneSimulator: if (major >= 8) return true; break; - case SDKType::AppleTVSimulator: - case SDKType::AppleTVOS: + case XcodeSDK::Type::AppleTVSimulator: + case XcodeSDK::Type::AppleTVOS: if (major >= 9) return true; break; - case SDKType::WatchSimulator: - case SDKType::watchOS: + case XcodeSDK::Type::WatchSimulator: + case XcodeSDK::Type::watchOS: if (major >= 2) return true; break; - case SDKType::Linux: + case XcodeSDK::Type::Linux: return true; default: return false; @@ -3041,7 +2413,8 @@ DirectoryEnumerator(void *baton, llvm::sys::fs::file_type file_type, return FileSystem::EnumerateDirectoryResult::eEnumerateDirectoryResultNext; }; -static ConstString EnumerateSDKsForVersion(FileSpec sdks_spec, SDKType sdk_type, +static ConstString EnumerateSDKsForVersion(FileSpec sdks_spec, + XcodeSDK::Type sdk_type, uint32_t least_major, uint32_t least_minor) { if (!IsDirectory(sdks_spec)) @@ -3067,42 +2440,45 @@ static ConstString EnumerateSDKsForVersion(FileSpec sdks_spec, SDKType sdk_type, return ConstString(); } -static ConstString GetSDKDirectory(SDKType sdk_type, uint32_t least_major, - uint32_t least_minor) { - if (sdk_type != SDKType::MacOSX) { +static ConstString GetSDKDirectory(XcodeSDK::Type sdk_type, + uint32_t least_major, uint32_t least_minor) { + using namespace llvm::sys; + if (sdk_type != XcodeSDK::Type::MacOSX) { // Look inside Xcode for the required installed iOS SDK version. - std::string sdks_path = GetXcodeContentsPath(); - sdks_path.append("Developer/Platforms"); - - if (sdk_type == SDKType::iPhoneSimulator) { - sdks_path.append("/iPhoneSimulator.platform/"); - } else if (sdk_type == SDKType::AppleTVSimulator) { - sdks_path.append("/AppleTVSimulator.platform/"); - } else if (sdk_type == SDKType::AppleTVOS) { - sdks_path.append("/AppleTVOS.platform/"); - } else if (sdk_type == SDKType::WatchSimulator) { - sdks_path.append("/WatchSimulator.platform/"); - } else if (sdk_type == SDKType::watchOS) { - // For now, we need to be prepared to handle either capitalization of this - // path. - std::string WatchOS_candidate_path = sdks_path + "/WatchOS.platform/"; - if (IsDirectory(FileSpec(WatchOS_candidate_path.c_str()))) { - sdks_path = WatchOS_candidate_path; + llvm::SmallString<256> sdks_path( + PlatformDarwin::GetXcodeContentsDirectory().GetPath()); + path::append(sdks_path, "Developer", "Platforms"); + + if (sdk_type == XcodeSDK::Type::iPhoneSimulator) { + path::append(sdks_path, "iPhoneSimulator.platform"); + } else if (sdk_type == XcodeSDK::Type::AppleTVSimulator) { + path::append(sdks_path, "AppleTVSimulator.platform"); + } else if (sdk_type == XcodeSDK::Type::AppleTVOS) { + path::append(sdks_path, "AppleTVOS.platform"); + } else if (sdk_type == XcodeSDK::Type::WatchSimulator) { + path::append(sdks_path, "WatchSimulator.platform"); + } else if (sdk_type == XcodeSDK::Type::watchOS) { + // For now, we need to be prepared to handle either capitalization of + // this path. + llvm::SmallString<256> candidate_path = sdks_path; + path::append(candidate_path, "WatchOS.platform"); + if (FileSystem::Instance().Exists(candidate_path)) { + sdks_path = candidate_path; } else { - std::string watchOS_candidate_path = sdks_path + "/watchOS.platform/"; - if (IsDirectory(FileSpec(watchOS_candidate_path.c_str()))) { - sdks_path = watchOS_candidate_path; + // Reset the candidate path. + candidate_path = sdks_path; + path::append(candidate_path, "watchOS.platform"); + if (FileSystem::Instance().Exists(candidate_path)) { + sdks_path = candidate_path; } else { return ConstString(); } } } else { - sdks_path.append("/iPhoneOS.platform/"); + path::append(sdks_path, "iPhoneOS.platform"); } - - sdks_path.append("Developer/SDKs/"); - - FileSpec sdks_spec(sdks_path.c_str()); + path::append(sdks_path, "Developer", "SDKs"); + FileSpec sdks_spec(sdks_path.str()); return EnumerateSDKsForVersion(sdks_spec, sdk_type, least_major, least_major); @@ -3137,51 +2513,55 @@ static ConstString GetSDKDirectory(SDKType sdk_type, uint32_t least_major, return pos->second; FileSpec fspec; - std::string xcode_contents_path; - - if (xcode_contents_path.empty()) - xcode_contents_path = GetXcodeContentsPath(); + std::string xcode_contents_path = + PlatformDarwin::GetXcodeContentsDirectory().GetPath(); + ; if (!xcode_contents_path.empty()) { - StreamString sdk_path; - sdk_path.Printf( - "%sDeveloper/Platforms/MacOSX.platform/Developer/SDKs/MacOSX%u.%u.sdk", - xcode_contents_path.c_str(), major, minor); - fspec.SetFile(sdk_path.GetString(), FileSpec::Style::native); - if (FileSystem::Instance().Exists(fspec)) { - ConstString path(sdk_path.GetString()); - // Cache results. - g_sdk_cache[major_minor] = path; - return path; - } else if ((least_major != major) || (least_minor != minor)) { - // Try the required SDK. - sdk_path.Clear(); - sdk_path.Printf("%sDeveloper/Platforms/MacOSX.platform/Developer/SDKs/" - "MacOSX%u.%u.sdk", - xcode_contents_path.c_str(), least_major, least_minor); - fspec.SetFile(sdk_path.GetString(), FileSpec::Style::native); + llvm::SmallString<256> sdks_dir( + PlatformDarwin::GetXcodeContentsDirectory().GetPath()); + llvm::sys::path::append(sdks_dir, "Developer", "Platforms", + "MacOSX.platform"); + llvm::sys::path::append(sdks_dir, "Developer", "SDKs"); + + // Try an exact match first. + { + std::string sdk_name = llvm::formatv("MacOSX{0}.{1}.sdk", major, minor); + llvm::SmallString<256> sdk_path = sdks_dir; + llvm::sys::path::append(sdk_path, sdk_name); + fspec.SetFile(sdk_path.str(), FileSpec::Style::native); if (FileSystem::Instance().Exists(fspec)) { - ConstString path(sdk_path.GetString()); + ConstString path(sdk_path.str()); // Cache results. g_sdk_cache[major_minor] = path; return path; - } else { - // Okay, we're going to do an exhaustive search for *any* SDK - // that has an adequate version. - std::string sdks_path = xcode_contents_path; - sdks_path.append("Developer/Platforms/MacOSX.platform/Developer/SDKs"); - - FileSpec sdks_spec(sdks_path.c_str()); - - ConstString sdk_path = EnumerateSDKsForVersion( - sdks_spec, sdk_type, least_major, least_major); + } + } - if (sdk_path) { - g_sdk_cache[major_minor] = sdk_path; - return sdk_path; - } + // Try the minimum required SDK, if it's different from the actual version. + if ((least_major != major) || (least_minor != minor)) { + std::string sdk_name = + llvm::formatv("MacOSX{0}.{1}.sdk", least_major, least_minor); + llvm::SmallString<256> sdk_path = sdks_dir; + llvm::sys::path::append(sdk_path, sdk_name); + fspec.SetFile(sdk_path.str(), FileSpec::Style::native); + if (FileSystem::Instance().Exists(fspec)) { + ConstString path(sdk_path.str()); + // Cache results. + g_sdk_cache[major_minor] = path; + return path; } } + + // Okay, if we haven't found anything yet, we're going to do an exhaustive + // search for *any* SDK that has an adequate version. + ConstString sdk_path = EnumerateSDKsForVersion( + FileSpec(sdks_dir.str()), sdk_type, least_major, least_major); + if (sdk_path) { + // Cache results. + g_sdk_cache[major_minor] = sdk_path; + return sdk_path; + } } // Cache results. @@ -3260,6 +2640,9 @@ swift::ClangImporterOptions &SwiftASTContext::GetClangImporterOptions() { if (FileSystem::Instance().Exists(clang_dir_spec)) clang_importer_options.OverrideResourceDir = clang_dir_spec.GetPath(); clang_importer_options.DebuggerSupport = true; + + clang_importer_options.DisableSourceImport = + !props.GetUseSwiftClangImporter(); } return clang_importer_options; } @@ -3291,7 +2674,7 @@ void SwiftASTContext::InitializeSearchPathOptions( FileSpec platform_sdk(m_platform_sdk_path.c_str()); if (FileSystem::Instance().Exists(platform_sdk) && - SDKSupportsSwift(platform_sdk, SDKType::unknown)) { + SDKSupportsSwift(platform_sdk, XcodeSDK::Type::unknown)) { invocation.setSDKPath(m_platform_sdk_path.c_str()); set_sdk = true; } @@ -3310,7 +2693,7 @@ void SwiftASTContext::InitializeSearchPathOptions( if (!set_sdk) { auto sdk = GetSDKType(triple, HostInfo::GetArchitecture().GetTriple()); // Explicitly leave the SDKPath blank on other platforms. - if (sdk.sdk_type != SDKType::unknown) { + if (sdk.sdk_type != XcodeSDK::Type::unknown) { auto dir = GetSDKDirectory(sdk.sdk_type, sdk.min_version_major, sdk.min_version_minor); // Note that calling setSDKPath() also recomputes all paths that @@ -3429,8 +2812,8 @@ class ANSIColorStringStream : public llvm::raw_string_ostream { class StoringDiagnosticConsumer : public swift::DiagnosticConsumer { public: StoringDiagnosticConsumer(SwiftASTContext &ast_context) - : m_ast_context(ast_context), m_diagnostics(), m_num_errors(0), - m_colorize(false) { + : m_ast_context(ast_context), m_raw_diagnostics(), m_diagnostics(), + m_num_errors(0), m_colorize(false) { m_ast_context.GetDiagnosticEngine().resetHadAnyError(); m_ast_context.GetDiagnosticEngine().addConsumer(*this); } @@ -3502,19 +2885,19 @@ class StoringDiagnosticConsumer : public swift::DiagnosticConsumer { std::string &message_ref = os.str(); if (message_ref.empty()) - m_diagnostics.push_back(RawDiagnostic( + m_raw_diagnostics.push_back(RawDiagnostic( text.str(), info.Kind, bufferName, bufferID, line_col.first, line_col.second, use_fixits ? info.FixIts : llvm::ArrayRef())); else - m_diagnostics.push_back(RawDiagnostic( + m_raw_diagnostics.push_back(RawDiagnostic( message_ref, info.Kind, bufferName, bufferID, line_col.first, line_col.second, use_fixits ? info.FixIts : llvm::ArrayRef())); } else { - m_diagnostics.push_back(RawDiagnostic( + m_raw_diagnostics.push_back(RawDiagnostic( text.str(), info.Kind, bufferName, bufferID, line_col.first, line_col.second, llvm::ArrayRef())); } @@ -3525,6 +2908,7 @@ class StoringDiagnosticConsumer : public swift::DiagnosticConsumer { void Clear() { m_ast_context.GetDiagnosticEngine().resetHadAnyError(); + m_raw_diagnostics.clear(); m_diagnostics.clear(); m_num_errors = 0; } @@ -3556,8 +2940,13 @@ class StoringDiagnosticConsumer : public swift::DiagnosticConsumer { void PrintDiagnostics(DiagnosticManager &diagnostic_manager, uint32_t bufferID = UINT32_MAX, uint32_t first_line = 0, uint32_t last_line = UINT32_MAX) { - bool added_one_diagnostic = false; - for (const RawDiagnostic &diagnostic : m_diagnostics) { + bool added_one_diagnostic = !m_diagnostics.empty(); + + for (std::unique_ptr &diagnostic : m_diagnostics) { + diagnostic_manager.AddDiagnostic(std::move(diagnostic)); + } + + for (const RawDiagnostic &diagnostic : m_raw_diagnostics) { // We often make expressions and wrap them in some code. When // we see errors we want the line numbers to be correct so we // correct them below. LLVM stores in SourceLoc objects as @@ -3629,7 +3018,7 @@ class StoringDiagnosticConsumer : public swift::DiagnosticConsumer { // This will report diagnostic errors from outside the // expression's source range. Those are not interesting to // users, so we only emit them in debug builds. - for (const RawDiagnostic &diagnostic : m_diagnostics) { + for (const RawDiagnostic &diagnostic : m_raw_diagnostics) { const DiagnosticSeverity severity = SeverityForKind(diagnostic.kind); const DiagnosticOrigin origin = eDiagnosticOriginSwift; diagnostic_manager.AddDiagnostic(diagnostic.description.c_str(), @@ -3646,6 +3035,10 @@ class StoringDiagnosticConsumer : public swift::DiagnosticConsumer { return old; } + void AddDiagnostic(std::unique_ptr diagnostic) { + m_diagnostics.push_back(std::move(diagnostic)); + } + private: // We don't currently use lldb_private::Diagostic or any of the lldb // DiagnosticManager machinery to store diagnostics as they @@ -3671,9 +3064,12 @@ class StoringDiagnosticConsumer : public swift::DiagnosticConsumer { std::vector fixits; }; typedef std::vector RawDiagnosticBuffer; + typedef std::vector> DiagnosticList; SwiftASTContext &m_ast_context; - RawDiagnosticBuffer m_diagnostics; + RawDiagnosticBuffer m_raw_diagnostics; + DiagnosticList m_diagnostics; + unsigned m_num_errors = 0; bool m_colorize; }; @@ -3990,7 +3386,7 @@ swift::ASTContext *SwiftASTContext::GetASTContext() { if (!clang_importer_options.OverrideResourceDir.empty()) { // Create the DWARFImporterDelegate. auto props = ModuleList::GetGlobalModuleListProperties(); - if (props.GetUseDWARFImporter()) + if (props.GetUseSwiftDWARFImporter()) m_dwarf_importer_delegate_up = std::make_unique(*this); clang_importer_ap = swift::ClangImporter::create( @@ -4039,7 +3435,13 @@ swift::ASTContext *SwiftASTContext::GetASTContext() { llvm::Triple triple(GetTriple()); llvm::SmallString<128> prebuiltModuleCachePath = GetResourceDir(triple); StringRef platform; - platform = swift::getPlatformNameForTriple(triple); + if (swift::tripleIsMacCatalystEnvironment(triple)) { + // The prebuilt cache for macCatalyst is the same as the one for macOS, + // not iOS or a separate location of its own. + platform = "macosx"; + } else { + platform = swift::getPlatformNameForTriple(triple); + } llvm::sys::path::append(prebuiltModuleCachePath, platform, "prebuilt-modules"); LOG_PRINTF(LIBLLDB_LOG_TYPES, "Using prebuilt Swift module cache path: %s", @@ -4111,13 +3513,13 @@ swift::ASTContext *SwiftASTContext::GetASTContext() { } // Set up the required state for the evaluator in the TypeChecker. - (void)swift::createTypeChecker(*m_ast_context_ap); registerIDERequestFunctions(m_ast_context_ap->evaluator); registerParseRequestFunctions(m_ast_context_ap->evaluator); registerTypeCheckerRequestFunctions(m_ast_context_ap->evaluator); registerSILGenRequestFunctions(m_ast_context_ap->evaluator); registerSILOptimizerRequestFunctions(m_ast_context_ap->evaluator); registerTBDGenRequestFunctions(m_ast_context_ap->evaluator); + registerIRGenRequestFunctions(m_ast_context_ap->evaluator); registerIRGenSILTransforms(*m_ast_context_ap); @@ -4930,9 +4332,8 @@ swift::Type convertSILFunctionTypesToASTFunctionTypes(swift::Type t) { CompilerType SwiftASTContext::GetTypeFromMangledTypename(ConstString mangled_typename) { - Status error; if (llvm::isa(this)) - return GetCompilerType(ReconstructType(mangled_typename, error)); + return GetCompilerType(ReconstructType(mangled_typename)); return GetCompilerType(mangled_typename); } @@ -4980,6 +4381,17 @@ CompilerType SwiftASTContext::GetAsClangType(ConstString mangled_name) { return clang_type; } +swift::TypeBase *SwiftASTContext::ReconstructType(ConstString mangled_typename) { + Status error; + + auto reconstructed_type = + this->ReconstructType(mangled_typename, error); + if (!error.Success()) { + this->AddErrorStatusAsGenericDiagnostic(error); + } + return reconstructed_type; +} + swift::TypeBase *SwiftASTContext::ReconstructType(ConstString mangled_typename, Status &error) { VALID_OR_RETURN(nullptr); @@ -5333,7 +4745,7 @@ CompilerType SwiftASTContext::ImportType(CompilerType &type, Status &error) { auto *ts = type.GetTypeSystem(); SwiftASTContext *swift_ast_ctx = llvm::dyn_cast_or_null(ts); - if (swift_ast_ctx == nullptr && !llvm::isa(ts)) { + if (swift_ast_ctx == nullptr && (!ts || !llvm::isa(ts))) { error.SetErrorString("Can't import clang type into a Swift ASTContext."); return CompilerType(); } else if (swift_ast_ctx == this) { @@ -5473,7 +4885,7 @@ swift::irgen::IRGenModule &SwiftASTContext::GetIRGenModule() { IRExecutionUnit::GetLLVMGlobalContextMutex()); m_ir_gen_module_ap.reset(new swift::irgen::IRGenModule( ir_generator, ir_generator.createTargetMachine(), nullptr, - GetGlobalLLVMContext(), ir_gen_opts.ModuleName, PSPs.OutputFilename, + ir_gen_opts.ModuleName, PSPs.OutputFilename, PSPs.MainInputFilenameForDebugInfo, "")); llvm::Module *llvm_module = m_ir_gen_module_ap->getModule(); llvm_module->setDataLayout(data_layout.getStringRepresentation()); @@ -5571,6 +4983,17 @@ bool SwiftASTContext::SetColorizeDiagnostics(bool b) { return false; } +void SwiftASTContext::AddErrorStatusAsGenericDiagnostic(Status error) { + assert(!error.Success() && "status should be in an error state"); + + auto diagnostic = std::make_unique( + error.AsCString(), eDiagnosticSeverityError, eDiagnosticOriginLLDB, + LLDB_INVALID_COMPILER_ID); + if (m_diagnostic_consumer_ap.get()) + static_cast(m_diagnostic_consumer_ap.get()) + ->AddDiagnostic(std::move(diagnostic)); +} + void SwiftASTContext::PrintDiagnostics(DiagnosticManager &diagnostic_manager, uint32_t bufferID, uint32_t first_line, uint32_t last_line) { @@ -5733,25 +5156,6 @@ void SwiftASTContext::AddDebuggerClient( std::unique_ptr(debugger_client)); } -ConstString SwiftASTContext::DeclContextGetName(void *opaque_decl_ctx) { - return ConstString(); -} - -ConstString -SwiftASTContext::DeclContextGetScopeQualifiedName(void *opaque_decl_ctx) { - return ConstString(); -} - -bool SwiftASTContext::DeclContextIsClassMethod( - void *opaque_decl_ctx, lldb::LanguageType *language_ptr, - bool *is_instance_method_ptr, ConstString *language_object_name_ptr) { - return false; -} - -/////////// -//////////////////// -/////////// - #ifndef NDEBUG bool SwiftASTContext::Verify(lldb::opaque_compiler_type_t type) { // Manual casting to avoid construction a temporary CompilerType @@ -5802,23 +5206,6 @@ bool SwiftASTContext::IsAggregateType(void *type) { return false; } -bool SwiftASTContext::IsVectorType(void *type, CompilerType *element_type, - uint64_t *size) { - return false; -} - -bool SwiftASTContext::IsRuntimeGeneratedType(void *type) { return false; } - -bool SwiftASTContext::IsCharType(void *type) { return false; } - -bool SwiftASTContext::IsCompleteType(void *type) { return true; } - -bool SwiftASTContext::IsConst(void *type) { return false; } - -bool SwiftASTContext::IsCStringType(void *type, uint32_t &length) { - return false; -} - bool SwiftASTContext::IsFunctionType(void *type, bool *is_variadic_ptr) { if (type) { swift::CanType swift_can_type(GetCanonicalSwiftType(type)); @@ -5836,12 +5223,6 @@ bool SwiftASTContext::IsFunctionType(void *type, bool *is_variadic_ptr) { return false; } -/// Used to detect "Homogeneous Floating-point Aggregates" -uint32_t SwiftASTContext::IsHomogeneousAggregate(void *type, - CompilerType *base_type_ptr) { - return 0; -} - size_t SwiftASTContext::GetNumberOfFunctionArguments(void *type) { if (type) { swift::CanType swift_can_type(GetCanonicalSwiftType(type)); @@ -5875,11 +5256,6 @@ bool SwiftASTContext::IsFunctionPointerType(void *type) { return IsFunctionType(type, nullptr); // FIXME: think about this } -bool SwiftASTContext::IsBlockPointerType( - void *type, CompilerType *function_pointer_type_ptr) { - return false; -} - bool SwiftASTContext::IsIntegerType(void *type, bool &is_signed) { return (GetTypeInfo(type, nullptr) & eTypeIsInteger); } @@ -5953,8 +5329,6 @@ bool SwiftASTContext::IsDefined(void *type) { return true; } -bool SwiftASTContext::IsPolymorphicClass(void *type) { return false; } - bool SwiftASTContext::IsPossibleDynamicType(void *type, CompilerType *dynamic_pointee_type, bool check_cplusplus, @@ -6009,13 +5383,6 @@ bool SwiftASTContext::IsVoidType(void *type) { return type == GetASTContext()->TheEmptyTupleType.getPointer(); } -bool SwiftASTContext::CanPassInRegisters(const CompilerType &type) { - // FIXME: Implement this. There was an abort() here to figure out which tests - // where hitting this code. At least TestSwiftReturns and TestSwiftStepping - // were failing because of this Darwin. - return false; -} - bool SwiftASTContext::IsGenericType(const CompilerType &compiler_type) { if (swift::Type swift_type = ::GetSwiftType(compiler_type)) return swift_type->hasTypeParameter(); // is(); @@ -6142,8 +5509,6 @@ SwiftASTContext::GetAllocationStrategy(CompilerType type) { return TypeAllocationStrategy::eUnknown; } -bool SwiftASTContext::IsBeingDefined(void *type) { return false; } - //---------------------------------------------------------------------- // Type Completion //---------------------------------------------------------------------- @@ -6192,6 +5557,8 @@ GetArchetypeNames(swift::Type swift_type, swift::ASTContext &ast_ctx, if (!type->isTypeParameter() || dict.count(type->getCanonicalType())) return; auto *param = type->getAs(); + if (!param) + return; auto it = names.find({param->getDepth(), param->getIndex()}); if (it != names.end()) { swift::Identifier ident = ast_ctx.getIdentifier(it->second); @@ -6463,8 +5830,6 @@ lldb::TypeClass SwiftASTContext::GetTypeClass(void *type) { return lldb::eTypeClassOther; } -unsigned SwiftASTContext::GetTypeQualifiers(void *type) { return 0; } - //---------------------------------------------------------------------- // Creating related types //---------------------------------------------------------------------- @@ -6615,10 +5980,10 @@ TypeMemberFunctionImpl SwiftASTContext::GetMemberFunctionAtIndex(void *type, swift::FuncDecl *func_decl = llvm::dyn_cast(*iter); if (func_decl) { - if (func_decl->getName().empty()) + if (func_decl->getBaseIdentifier().empty()) name.clear(); else - name.assign(func_decl->getName().get()); + name.assign(func_decl->getBaseIdentifier().get()); if (func_decl->isStatic()) kind = lldb::eMemberFunctionKindStaticMethod; else @@ -6717,19 +6082,6 @@ SwiftASTContext::GetUnboundType(lldb::opaque_compiler_type_t type) { return ToCompilerType({GetSwiftType(type)}); } -CompilerType SwiftASTContext::GetTypeForDecl(void *opaque_decl) { - assert("not yet implemented"); - return {}; -} - -//---------------------------------------------------------------------- -// Create related types using the current type's AST -//---------------------------------------------------------------------- - -CompilerType SwiftASTContext::GetBasicTypeFromAST(lldb::BasicType basic_type) { - return {}; -} - //---------------------------------------------------------------------- // Exploring the type //---------------------------------------------------------------------- @@ -6767,13 +6119,6 @@ bool SwiftASTContext::IsFixedSize(CompilerType compiler_type) { return false; } -const llvm::fltSemantics & -SwiftASTContext::GetFloatTypeSemantics(size_t byte_size) { - // See: https://reviews.llvm.org/D67239. At this time of writing this API - // is only used by DumpDataExtractor for the C type system. - llvm_unreachable("SwiftASTContext::GetFloatTypeSemantics not implemented."); -} - llvm::Optional SwiftASTContext::GetBitSize(lldb::opaque_compiler_type_t type, ExecutionContextScope *exe_scope) { @@ -7172,10 +6517,6 @@ uint32_t SwiftASTContext::GetNumChildren(void *type, return num_children; } -lldb::BasicType SwiftASTContext::GetBasicTypeEnumeration(void *type) { - return eBasicTypeInvalid; -} - #pragma mark Aggregate Types uint32_t SwiftASTContext::GetNumDirectBaseClasses(void *opaque_type) { @@ -7192,10 +6533,6 @@ uint32_t SwiftASTContext::GetNumDirectBaseClasses(void *opaque_type) { return 0; } -uint32_t SwiftASTContext::GetNumVirtualBaseClasses(void *opaque_type) { - return 0; -} - uint32_t SwiftASTContext::GetNumFields(void *type) { VALID_OR_RETURN(0); @@ -7312,12 +6649,6 @@ SwiftASTContext::GetDirectBaseClassAtIndex(void *opaque_type, size_t idx, return {}; } -CompilerType -SwiftASTContext::GetVirtualBaseClassAtIndex(void *opaque_type, size_t idx, - uint32_t *bit_offset_ptr) { - return {}; -} - /// Retrieve the printable name of a tuple element. static std::string GetTupleElementName(const swift::TupleType *tuple_type, unsigned index, @@ -7447,22 +6778,8 @@ CompilerType SwiftASTContext::GetFieldAtIndex(void *type, size_t idx, break; case swift::TypeKind::Enum: - case swift::TypeKind::BoundGenericEnum: { - SwiftEnumDescriptor *cached_enum_info = GetCachedEnumInfo(type); - if (cached_enum_info && - idx < cached_enum_info->GetNumElementsWithPayload()) { - const SwiftEnumDescriptor::ElementInfo *enum_element_info = - cached_enum_info->GetElementWithPayloadAtIndex(idx); - name.assign(enum_element_info->name.GetCString()); - if (bit_offset_ptr) - *bit_offset_ptr = 0; - if (bitfield_bit_size_ptr) - *bitfield_bit_size_ptr = 0; - if (is_bitfield_ptr) - *is_bitfield_ptr = false; - return enum_element_info->payload_type; - } - } break; + case swift::TypeKind::BoundGenericEnum: + break; case swift::TypeKind::Tuple: { auto tuple_type = cast(swift_can_type); @@ -8992,6 +8309,9 @@ static void DescribeFileUnit(Stream &s, swift::FileUnit *file_unit) { case swift::FileUnitKind::Builtin: { s.PutCString("Builtin"); } break; + case swift::FileUnitKind::Synthesized: { + s.PutCString("Synthesized"); + } break; case swift::FileUnitKind::SerializedAST: case swift::FileUnitKind::ClangModule: { if (file_unit->getKind() == swift::FileUnitKind::SerializedAST) diff --git a/lldb/source/Symbol/Type.cpp b/lldb/source/Symbol/Type.cpp index 968ae1f7c2415..d440cc050b18c 100644 --- a/lldb/source/Symbol/Type.cpp +++ b/lldb/source/Symbol/Type.cpp @@ -143,15 +143,14 @@ Type::Type(lldb::user_id_t uid, SymbolFile *symbol_file, ConstString name, llvm::Optional byte_size, SymbolContextScope *context, user_id_t encoding_uid, EncodingDataType encoding_uid_type, const Declaration &decl, const CompilerType &compiler_type, - ResolveState compiler_type_resolve_state) + ResolveState compiler_type_resolve_state, uint32_t opaque_payload) : std::enable_shared_from_this(), UserID(uid), m_name(name), m_symbol_file(symbol_file), m_context(context), m_encoding_type(nullptr), m_encoding_uid(encoding_uid), m_encoding_uid_type(encoding_uid_type), m_decl(decl), m_compiler_type(compiler_type), - m_compiler_type_resolve_state( - compiler_type ? compiler_type_resolve_state - : ResolveState::Unresolved), - m_is_complete_objc_class(false) { + m_compiler_type_resolve_state(compiler_type ? compiler_type_resolve_state + : ResolveState::Unresolved), + m_payload(opaque_payload) { if (byte_size) { m_byte_size = *byte_size; m_byte_size_has_value = true; diff --git a/lldb/source/Symbol/TypeSystemSwiftTypeRef.cpp b/lldb/source/Symbol/TypeSystemSwiftTypeRef.cpp new file mode 100644 index 0000000000000..1949ade4138ed --- /dev/null +++ b/lldb/source/Symbol/TypeSystemSwiftTypeRef.cpp @@ -0,0 +1,875 @@ +//===-- TypeSystemSwiftTypeRef.cpp ----------------------------------------===// +// +// This source file is part of the Swift.org open source project +// +// Copyright (c) 2014 - 2020 Apple Inc. and the Swift project authors +// Licensed under Apache License v2.0 with Runtime Library Exception +// +// See https://swift.org/LICENSE.txt for license information +// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors +// +//===----------------------------------------------------------------------===// + +#include "lldb/Symbol/SwiftASTContext.h" +#include "lldb/Symbol/TypeList.h" +#include "lldb/Target/SwiftLanguageRuntime.h" +#include "lldb/Utility/Log.h" + +#include "swift/Demangling/Demangle.h" +#include "swift/Demangling/Demangler.h" +#include "swift/Strings.h" + +using namespace lldb; +using namespace lldb_private; + +char TypeSystemSwift::ID; +char TypeSystemSwiftTypeRef::ID; + +TypeSystemSwift::TypeSystemSwift() : TypeSystem() {} + +/// Create a mangled name for a type alias node. +static ConstString GetTypeAlias(swift::Demangle::Demangler &Dem, + swift::Demangle::NodePointer node) { + using namespace swift::Demangle; + auto global = Dem.createNode(Node::Kind::Global); + auto type_mangling = Dem.createNode(Node::Kind::TypeMangling); + global->addChild(type_mangling, Dem); + type_mangling->addChild(node, Dem); + return ConstString(mangleNode(global)); +} + +/// Iteratively resolve all type aliases in \p node by looking up their +/// desugared types in the debug info of module \p M. +static swift::Demangle::NodePointer +GetCanonicalNode(lldb_private::Module *M, swift::Demangle::Demangler &Dem, + swift::Demangle::NodePointer node) { + if (!node) + return node; + using namespace swift::Demangle; + auto getCanonicalNode = [&](NodePointer node) -> NodePointer { + return GetCanonicalNode(M, Dem, node); + }; + + NodePointer canonical = nullptr; + auto kind = node->getKind(); + switch (kind) { + case Node::Kind::SugaredOptional: + // FIXME: Factor these three cases out. + assert(node->getNumChildren() == 1); + if (node->getNumChildren() != 1) + return node; + + canonical = Dem.createNode(Node::Kind::BoundGenericEnum); + { + NodePointer type = Dem.createNode(Node::Kind::Type); + NodePointer e = Dem.createNode(Node::Kind::Enum); + NodePointer module = Dem.createNodeWithAllocatedText(Node::Kind::Module, + swift::STDLIB_NAME); + e->addChild(module, Dem); + NodePointer optional = + Dem.createNodeWithAllocatedText(Node::Kind::Module, "Optional"); + e->addChild(optional, Dem); + type->addChild(e, Dem); + canonical->addChild(type, Dem); + } + { + NodePointer typelist = Dem.createNode(Node::Kind::TypeList); + NodePointer type = Dem.createNode(Node::Kind::Type); + type->addChild(getCanonicalNode(node->getFirstChild()), Dem); + typelist->addChild(type, Dem); + canonical->addChild(typelist, Dem); + } + return canonical; + case Node::Kind::SugaredArray: { + assert(node->getNumChildren() == 1); + if (node->getNumChildren() != 1) + return node; + + canonical = Dem.createNode(Node::Kind::BoundGenericStructure); + { + NodePointer type = Dem.createNode(Node::Kind::Type); + NodePointer structure = Dem.createNode(Node::Kind::Structure); + NodePointer module = Dem.createNodeWithAllocatedText(Node::Kind::Module, + swift::STDLIB_NAME); + structure->addChild(module, Dem); + NodePointer array = + Dem.createNodeWithAllocatedText(Node::Kind::Module, "Array"); + structure->addChild(array, Dem); + type->addChild(structure, Dem); + canonical->addChild(type, Dem); + } + { + NodePointer typelist = Dem.createNode(Node::Kind::TypeList); + NodePointer type = Dem.createNode(Node::Kind::Type); + type->addChild(getCanonicalNode(node->getFirstChild()), Dem); + typelist->addChild(type, Dem); + canonical->addChild(typelist, Dem); + } + return canonical; + } + case Node::Kind::SugaredDictionary: + // FIXME: This isnt covered by any test. + assert(node->getNumChildren() == 2); + if (node->getNumChildren() != 2) + return node; + + canonical = Dem.createNode(Node::Kind::BoundGenericStructure); + { + NodePointer type = Dem.createNode(Node::Kind::Type); + NodePointer structure = Dem.createNode(Node::Kind::Structure); + NodePointer module = Dem.createNodeWithAllocatedText(Node::Kind::Module, + swift::STDLIB_NAME); + structure->addChild(module, Dem); + NodePointer dict = + Dem.createNodeWithAllocatedText(Node::Kind::Module, "Dictionary"); + structure->addChild(dict, Dem); + type->addChild(structure, Dem); + canonical->addChild(type, Dem); + } + { + NodePointer typelist = Dem.createNode(Node::Kind::TypeList); + { + NodePointer type = Dem.createNode(Node::Kind::Type); + type->addChild(getCanonicalNode(node->getChild(0)), Dem); + typelist->addChild(type, Dem); + } + { + NodePointer type = Dem.createNode(Node::Kind::Type); + type->addChild(getCanonicalNode(node->getChild(1)), Dem); + typelist->addChild(type, Dem); + } + canonical->addChild(typelist, Dem); + } + return canonical; + case Node::Kind::SugaredParen: + assert(node->getNumChildren() == 1); + if (node->getNumChildren() != 1) + return node; + return getCanonicalNode(node->getFirstChild()); + + case Node::Kind::BoundGenericTypeAlias: + case Node::Kind::TypeAlias: { + // Try to look this up as a Swift type alias. For each *Swift* + // type alias there is a debug info entry that has the mangled + // name as name and the aliased type as a type. + ConstString mangled = GetTypeAlias(Dem, node); + if (!M) { + LLDB_LOGF(GetLogIfAllCategoriesSet(LIBLLDB_LOG_TYPES), + "No module. Couldn't resolve type alias %s", + mangled.AsCString()); + return node; + } + llvm::DenseSet searched_symbol_files; + TypeList types; + M->FindTypes({mangled}, false, 1, searched_symbol_files, types); + if (types.Empty()) { + // TODO: No Swift type found -- this could be a Clang typdef. + LLDB_LOGF(GetLogIfAllCategoriesSet(LIBLLDB_LOG_TYPES), + "Couldn't resolve type alias %s", mangled.AsCString()); + return node; + } + auto type = types.GetTypeAtIndex(0); + if (!type) { + LLDB_LOGF(GetLogIfAllCategoriesSet(LIBLLDB_LOG_TYPES), + "Found empty type alias %s", mangled.AsCString()); + return node; + } + + // DWARFASTParserSwift stashes the desugared mangled name of a + // type alias into the Type's name field. + ConstString desugared_name = type->GetName(); + if (!isMangledName(desugared_name.GetStringRef())) { + LLDB_LOGF(GetLogIfAllCategoriesSet(LIBLLDB_LOG_TYPES), + "Found non-Swift type alias %s", mangled.AsCString()); + return node; + } + NodePointer n = Dem.demangleSymbol(desugared_name.GetStringRef()); + if (n && n->getKind() == Node::Kind::Global && n->hasChildren()) + n = n->getFirstChild(); + if (n && n->getKind() == Node::Kind::TypeMangling && n->hasChildren()) + n = n->getFirstChild(); + if (n && n->getKind() == Node::Kind::Type && n->hasChildren()) + n = n->getFirstChild(); + if (!n) { + LLDB_LOG(GetLogIfAllCategoriesSet(LIBLLDB_LOG_TYPES), + "Unrecognized demangling %s", desugared_name.AsCString()); + return node; + } + return getCanonicalNode(n); + } + default: + break; + } + + // Recurse through all children. + // FIXME: don't create new nodes if children don't change! + if (node->hasText()) + canonical = Dem.createNodeWithAllocatedText(kind, node->getText()); + else if (node->hasIndex()) + canonical = Dem.createNode(kind, node->getIndex()); + else + canonical = Dem.createNode(kind); + for (unsigned i = 0; i < node->getNumChildren(); ++i) + canonical->addChild(getCanonicalNode(node->getChild(i)), Dem); + return canonical; +} + +/// Return the demangle tree representation of this type's canonical +/// (type aliases resolved) type. +static swift::Demangle::NodePointer +GetCanonicalDemangleTree(lldb_private::Module *Module, + swift::Demangle::Demangler &Dem, + const char *mangled_name) { + NodePointer node = Dem.demangleSymbol(mangled_name); + NodePointer canonical = GetCanonicalNode(Module, Dem, node); + return canonical; +} + +CompilerType TypeSystemSwift::GetInstanceType(CompilerType compiler_type) { + auto *ts = compiler_type.GetTypeSystem(); + if (auto *tr = llvm::dyn_cast_or_null(ts)) + return tr->GetInstanceType(compiler_type.GetOpaqueQualType()); + if (auto *ast = llvm::dyn_cast_or_null(ts)) + return ast->GetInstanceType(compiler_type.GetOpaqueQualType()); + return {}; +} + +TypeSystemSwiftTypeRef::TypeSystemSwiftTypeRef( + SwiftASTContext *swift_ast_context) + : m_swift_ast_context(swift_ast_context) { + m_description = "TypeSystemSwiftTypeRef"; +} + +const char *TypeSystemSwiftTypeRef::AsMangledName(void *type) { + assert(type && *reinterpret_cast(type) == '$' && + "wrong type system"); + return reinterpret_cast(type); +} + +ConstString TypeSystemSwiftTypeRef::GetMangledTypeName(void *type) { + // FIXME: Suboptimal performance, because the ConstString is looked up again. + return ConstString(AsMangledName(type)); +} + +void *TypeSystemSwiftTypeRef::ReconstructType(void *type) { + Status error; + return m_swift_ast_context->ReconstructType(GetMangledTypeName(type), error); +} + +CompilerType TypeSystemSwiftTypeRef::ReconstructType(CompilerType type) { + return {m_swift_ast_context, ReconstructType(type.GetOpaqueQualType())}; +} + +CompilerType TypeSystemSwiftTypeRef::GetTypeFromMangledTypename( + ConstString mangled_typename) { + return {this, (void *)mangled_typename.AsCString()}; +} + +lldb::TypeSP TypeSystemSwiftTypeRef::GetCachedType(ConstString mangled) { + return m_swift_ast_context->GetCachedType(mangled); +} + +void TypeSystemSwiftTypeRef::SetCachedType(ConstString mangled, + const lldb::TypeSP &type_sp) { + return m_swift_ast_context->SetCachedType(mangled, type_sp); +} + +Module *TypeSystemSwiftTypeRef::GetModule() const { + return m_swift_ast_context ? m_swift_ast_context->GetModule() : nullptr; +} + +ConstString TypeSystemSwiftTypeRef::GetPluginName() { + return ConstString("TypeSystemSwiftTypeRef"); +} +uint32_t TypeSystemSwiftTypeRef::GetPluginVersion() { return 1; } + +bool TypeSystemSwiftTypeRef::SupportsLanguage(lldb::LanguageType language) { + return language == eLanguageTypeSwift; +} + +Status TypeSystemSwiftTypeRef::IsCompatible() { + return m_swift_ast_context->IsCompatible(); +} + +void TypeSystemSwiftTypeRef::DiagnoseWarnings(Process &process, + Module &module) const { + m_swift_ast_context->DiagnoseWarnings(process, module); +} +DWARFASTParser *TypeSystemSwiftTypeRef::GetDWARFParser() { + return m_swift_ast_context->GetDWARFParser(); +} + +// Tests + +#ifndef NDEBUG +bool TypeSystemSwiftTypeRef::Verify(lldb::opaque_compiler_type_t type) { + if (!type) + return true; + + const char *str = reinterpret_cast(type); + return SwiftLanguageRuntime::IsSwiftMangledName(str); +} +#endif + +// This can be removed once the transition is complete. +#define VALIDATE_AND_RETURN(IMPL, EXPECTED) \ + do { \ + auto result = IMPL(); \ + if (m_swift_ast_context) \ + assert(result == (EXPECTED) && \ + "TypeSystemSwiftTypeRef diverges from SwiftASTContext"); \ + return result; \ + } while (0) + +CompilerType +TypeSystemSwiftTypeRef::RemangleAsType(swift::Demangle::Demangler &Dem, + swift::Demangle::NodePointer node) { + if (!node) + return {}; + assert(node->getKind() == Node::Kind::Type && "expected type node"); + + using namespace swift::Demangle; + auto global = Dem.createNode(Node::Kind::Global); + auto type_mangling = Dem.createNode(Node::Kind::TypeMangling); + global->addChild(type_mangling, Dem); + type_mangling->addChild(node, Dem); + ConstString mangled_element(mangleNode(global)); + return GetTypeFromMangledTypename(mangled_element); +} + +swift::Demangle::NodePointer +TypeSystemSwiftTypeRef::DemangleCanonicalType(swift::Demangle::Demangler &Dem, + void *opaque_type) { + using namespace swift::Demangle; + NodePointer node = + GetCanonicalDemangleTree(GetModule(), Dem, AsMangledName(opaque_type)); + + if (!node || node->getNumChildren() != 1 || + node->getKind() != Node::Kind::Global) + return nullptr; + node = node->getFirstChild(); + if (node->getNumChildren() != 1 || + node->getKind() != Node::Kind::TypeMangling) + return nullptr; + node = node->getFirstChild(); + if (node->getNumChildren() != 1 || node->getKind() != Node::Kind::Type) + return nullptr; + node = node->getFirstChild(); + return node; +} + +bool TypeSystemSwiftTypeRef::IsArrayType(void *type, CompilerType *element_type, + uint64_t *size, bool *is_incomplete) { + auto impl = [&]() { + using namespace swift::Demangle; + Demangler Dem; + NodePointer node = DemangleCanonicalType(Dem, type); + if (!node || node->getNumChildren() != 2 || + node->getKind() != Node::Kind::BoundGenericStructure) + return false; + auto elem_node = node->getChild(1); + node = node->getFirstChild(); + if (node->getNumChildren() != 1 || node->getKind() != Node::Kind::Type) + return false; + node = node->getFirstChild(); + if (node->getNumChildren() != 2 || + node->getKind() != Node::Kind::Structure || + node->getChild(0)->getKind() != Node::Kind::Module || + !node->getChild(0)->hasText() || + node->getChild(0)->getText() != swift::STDLIB_NAME || + node->getChild(1)->getKind() != Node::Kind::Identifier || + !node->getChild(1)->hasText() || + node->getChild(1)->getText() != "Array") + return false; + + if (elem_node->getNumChildren() != 1 || + elem_node->getKind() != Node::Kind::TypeList) + return false; + elem_node = elem_node->getFirstChild(); + + if (element_type) + *element_type = RemangleAsType(Dem, elem_node); + + if (is_incomplete) + *is_incomplete = true; + if (size) + *size = 0; + + return true; + }; + VALIDATE_AND_RETURN( + impl, m_swift_ast_context->IsArrayType(ReconstructType(type), nullptr, + nullptr, nullptr)); +} +bool TypeSystemSwiftTypeRef::IsAggregateType(void *type) { + return m_swift_ast_context->IsAggregateType(ReconstructType(type)); +} +bool TypeSystemSwiftTypeRef::IsDefined(void *type) { + return m_swift_ast_context->IsDefined(ReconstructType(type)); +} +bool TypeSystemSwiftTypeRef::IsFloatingPointType(void *type, uint32_t &count, + bool &is_complex) { + return m_swift_ast_context->IsFloatingPointType(ReconstructType(type), count, + is_complex); +} + +bool TypeSystemSwiftTypeRef::IsFunctionType(void *type, bool *is_variadic_ptr) { + auto impl = [&]() -> bool { + using namespace swift::Demangle; + Demangler Dem; + NodePointer node = DemangleCanonicalType(Dem, type); + return node && (node->getKind() == Node::Kind::FunctionType || + node->getKind() == Node::Kind::ImplFunctionType); + }; + VALIDATE_AND_RETURN(impl, m_swift_ast_context->IsFunctionType( + ReconstructType(type), nullptr)); +} +size_t TypeSystemSwiftTypeRef::GetNumberOfFunctionArguments(void *type) { + auto impl = [&]() -> size_t { + using namespace swift::Demangle; + Demangler Dem; + NodePointer node = DemangleCanonicalType(Dem, type); + if (!node || (node->getKind() != Node::Kind::FunctionType && + node->getKind() != Node::Kind::ImplFunctionType)) + return 0; + unsigned num_args = 0; + for (NodePointer child : *node) { + if (child->getKind() == Node::Kind::ImplParameter) + ++num_args; + if (child->getKind() == Node::Kind::ArgumentTuple && + child->getNumChildren() == 1) { + NodePointer node = child->getFirstChild(); + if (node->getNumChildren() != 1 || + node->getKind() != Node::Kind::Type) + break; + node = node->getFirstChild(); + if (node->getKind() == Node::Kind::Tuple) + return node->getNumChildren(); + } + } + return num_args; + }; + VALIDATE_AND_RETURN(impl, m_swift_ast_context->GetNumberOfFunctionArguments( + ReconstructType(type))); +} +CompilerType +TypeSystemSwiftTypeRef::GetFunctionArgumentAtIndex(void *type, + const size_t index) { + auto impl = [&]() -> CompilerType { + using namespace swift::Demangle; + Demangler Dem; + NodePointer node = DemangleCanonicalType(Dem, type); + if (!node || (node->getKind() != Node::Kind::FunctionType && + node->getKind() != Node::Kind::ImplFunctionType)) + return {}; + unsigned num_args = 0; + for (NodePointer child : *node) { + if (child->getKind() == Node::Kind::ImplParameter) { + if (num_args == index) + for (NodePointer type : *child) + if (type->getKind() == Node::Kind::Type) + return RemangleAsType(Dem, type); + ++num_args; + } + if (child->getKind() == Node::Kind::ArgumentTuple && + child->getNumChildren() == 1) { + NodePointer node = child->getFirstChild(); + if (node->getNumChildren() != 1 || + node->getKind() != Node::Kind::Type) + break; + node = node->getFirstChild(); + if (node->getKind() == Node::Kind::Tuple) + for (NodePointer child : *node) { + if (child->getNumChildren() == 1 && + child->getKind() == Node::Kind::TupleElement) { + NodePointer type = child->getFirstChild(); + if (num_args == index && type->getKind() == Node::Kind::Type) + return RemangleAsType(Dem, type); + ++num_args; + } + } + } + } + return {}; + }; + VALIDATE_AND_RETURN(impl, m_swift_ast_context->GetFunctionArgumentAtIndex( + ReconstructType(type), index)); +} +bool TypeSystemSwiftTypeRef::IsFunctionPointerType(void *type) { + auto impl = [&]() -> bool { return IsFunctionType(type, nullptr); }; + VALIDATE_AND_RETURN( + impl, m_swift_ast_context->IsFunctionPointerType(ReconstructType(type))); +} +bool TypeSystemSwiftTypeRef::IsIntegerType(void *type, bool &is_signed) { + return m_swift_ast_context->IsIntegerType(ReconstructType(type), is_signed); +} +bool TypeSystemSwiftTypeRef::IsPossibleDynamicType(void *type, + CompilerType *target_type, + bool check_cplusplus, + bool check_objc) { + return m_swift_ast_context->IsPossibleDynamicType( + ReconstructType(type), target_type, check_cplusplus, check_objc); +} +bool TypeSystemSwiftTypeRef::IsPointerType(void *type, + CompilerType *pointee_type) { + auto impl = [&]() { + using namespace swift::Demangle; + Demangler Dem; + NodePointer node = DemangleCanonicalType(Dem, type); + if (!node || node->getKind() != Node::Kind::BuiltinTypeName || + !node->hasText()) + return false; + return ((node->getText() == swift::BUILTIN_TYPE_NAME_RAWPOINTER) || + (node->getText() == swift::BUILTIN_TYPE_NAME_UNSAFEVALUEBUFFER) || + (node->getText() == swift::BUILTIN_TYPE_NAME_NATIVEOBJECT) || + (node->getText() == swift::BUILTIN_TYPE_NAME_BRIDGEOBJECT)); + }; + VALIDATE_AND_RETURN(impl, m_swift_ast_context->IsPointerType(ReconstructType(type), + pointee_type)); +} +bool TypeSystemSwiftTypeRef::IsScalarType(void *type) { + return m_swift_ast_context->IsScalarType(ReconstructType(type)); +} +bool TypeSystemSwiftTypeRef::IsVoidType(void *type) { + auto impl = [&]() { + using namespace swift::Demangle; + Demangler Dem; + NodePointer node = DemangleCanonicalType(Dem, type); + return node && node->getNumChildren() == 0 && + node->getKind() == Node::Kind::Tuple; + }; + VALIDATE_AND_RETURN(impl, + m_swift_ast_context->IsVoidType(ReconstructType(type))); +} +// Type Completion +bool TypeSystemSwiftTypeRef::GetCompleteType(void *type) { + return m_swift_ast_context->GetCompleteType(ReconstructType(type)); +} +// AST related queries +uint32_t TypeSystemSwiftTypeRef::GetPointerByteSize() { + return m_swift_ast_context->GetPointerByteSize(); +} +// Accessors +ConstString TypeSystemSwiftTypeRef::GetTypeName(void *type) { + return m_swift_ast_context->GetTypeName(ReconstructType(type)); +} +ConstString +TypeSystemSwiftTypeRef::GetDisplayTypeName(void *type, + const SymbolContext *sc) { + return m_swift_ast_context->GetDisplayTypeName(ReconstructType(type), sc); +} +uint32_t TypeSystemSwiftTypeRef::GetTypeInfo( + void *type, CompilerType *pointee_or_element_clang_type) { + return m_swift_ast_context->GetTypeInfo(ReconstructType(type), + pointee_or_element_clang_type); +} +lldb::LanguageType TypeSystemSwiftTypeRef::GetMinimumLanguage(void *type) { + return m_swift_ast_context->GetMinimumLanguage(ReconstructType(type)); +} +lldb::TypeClass TypeSystemSwiftTypeRef::GetTypeClass(void *type) { + return m_swift_ast_context->GetTypeClass(ReconstructType(type)); +} + +// Creating related types +CompilerType TypeSystemSwiftTypeRef::GetArrayElementType(void *type, + uint64_t *stride) { + return m_swift_ast_context->GetArrayElementType(ReconstructType(type), + stride); +} +CompilerType TypeSystemSwiftTypeRef::GetCanonicalType(void *type) { + return m_swift_ast_context->GetCanonicalType(ReconstructType(type)); +} +int TypeSystemSwiftTypeRef::GetFunctionArgumentCount(void *type) { + auto impl = [&]() { return GetNumberOfFunctionArguments(type); }; + VALIDATE_AND_RETURN(impl, m_swift_ast_context->GetFunctionArgumentCount( + ReconstructType(type))); +} +CompilerType +TypeSystemSwiftTypeRef::GetFunctionArgumentTypeAtIndex(void *type, size_t idx) { + auto impl = [&] { return GetFunctionArgumentAtIndex(type, idx); }; + VALIDATE_AND_RETURN(impl, m_swift_ast_context->GetFunctionArgumentTypeAtIndex( + ReconstructType(type), idx)); +} +CompilerType TypeSystemSwiftTypeRef::GetFunctionReturnType(void *type) { + auto impl = [&]() -> CompilerType { + using namespace swift::Demangle; + Demangler Dem; + NodePointer node = DemangleCanonicalType(Dem, type); + if (!node || (node->getKind() != Node::Kind::FunctionType && + node->getKind() != Node::Kind::ImplFunctionType)) + return {}; + unsigned num_args = 0; + for (NodePointer child : *node) { + if (child->getKind() == Node::Kind::ImplResult) { + for (NodePointer type : *child) + if (type->getKind() == Node::Kind::Type) + return RemangleAsType(Dem, type); + } + if (child->getKind() == Node::Kind::ReturnType && + child->getNumChildren() == 1) { + NodePointer type = child->getFirstChild(); + if (type->getKind() == Node::Kind::Type) + return RemangleAsType(Dem, type); + } + } + // Else this is a void / "()" type. + NodePointer type = Dem.createNode(Node::Kind::Type); + NodePointer tuple = Dem.createNode(Node::Kind::Tuple); + type->addChild(tuple, Dem); + return RemangleAsType(Dem, type); + }; + VALIDATE_AND_RETURN( + impl, m_swift_ast_context->GetFunctionReturnType(ReconstructType(type))); +} +size_t TypeSystemSwiftTypeRef::GetNumMemberFunctions(void *type) { + return m_swift_ast_context->GetNumMemberFunctions(ReconstructType(type)); +} +TypeMemberFunctionImpl +TypeSystemSwiftTypeRef::GetMemberFunctionAtIndex(void *type, size_t idx) { + return m_swift_ast_context->GetMemberFunctionAtIndex(ReconstructType(type), + idx); +} +CompilerType TypeSystemSwiftTypeRef::GetPointeeType(void *type) { + return m_swift_ast_context->GetPointeeType(ReconstructType(type)); +} +CompilerType TypeSystemSwiftTypeRef::GetPointerType(void *type) { + return m_swift_ast_context->GetPointerType(ReconstructType(type)); +} + +// Exploring the type +llvm::Optional +TypeSystemSwiftTypeRef::GetBitSize(lldb::opaque_compiler_type_t type, + ExecutionContextScope *exe_scope) { + return m_swift_ast_context->GetBitSize(ReconstructType(type), exe_scope); +} +llvm::Optional +TypeSystemSwiftTypeRef::GetByteStride(lldb::opaque_compiler_type_t type, + ExecutionContextScope *exe_scope) { + return m_swift_ast_context->GetByteStride(ReconstructType(type), exe_scope); +} +lldb::Encoding TypeSystemSwiftTypeRef::GetEncoding(void *type, + uint64_t &count) { + return m_swift_ast_context->GetEncoding(ReconstructType(type), count); +} +lldb::Format TypeSystemSwiftTypeRef::GetFormat(void *type) { + return m_swift_ast_context->GetFormat(ReconstructType(type)); +} +uint32_t +TypeSystemSwiftTypeRef::GetNumChildren(void *type, bool omit_empty_base_classes, + const ExecutionContext *exe_ctx) { + return m_swift_ast_context->GetNumChildren(ReconstructType(type), + omit_empty_base_classes, exe_ctx); +} +uint32_t TypeSystemSwiftTypeRef::GetNumFields(void *type) { + return m_swift_ast_context->GetNumFields(ReconstructType(type)); +} +CompilerType TypeSystemSwiftTypeRef::GetFieldAtIndex( + void *type, size_t idx, std::string &name, uint64_t *bit_offset_ptr, + uint32_t *bitfield_bit_size_ptr, bool *is_bitfield_ptr) { + return m_swift_ast_context->GetFieldAtIndex( + ReconstructType(type), idx, name, bit_offset_ptr, bitfield_bit_size_ptr, + is_bitfield_ptr); +} +CompilerType TypeSystemSwiftTypeRef::GetChildCompilerTypeAtIndex( + void *type, ExecutionContext *exe_ctx, size_t idx, + bool transparent_pointers, bool omit_empty_base_classes, + bool ignore_array_bounds, std::string &child_name, + uint32_t &child_byte_size, int32_t &child_byte_offset, + uint32_t &child_bitfield_bit_size, uint32_t &child_bitfield_bit_offset, + bool &child_is_base_class, bool &child_is_deref_of_parent, + ValueObject *valobj, uint64_t &language_flags) { + return m_swift_ast_context->GetChildCompilerTypeAtIndex( + ReconstructType(type), exe_ctx, idx, transparent_pointers, + omit_empty_base_classes, ignore_array_bounds, child_name, child_byte_size, + child_byte_offset, child_bitfield_bit_size, child_bitfield_bit_offset, + child_is_base_class, child_is_deref_of_parent, valobj, language_flags); +} +uint32_t +TypeSystemSwiftTypeRef::GetIndexOfChildWithName(void *type, const char *name, + bool omit_empty_base_classes) { + return m_swift_ast_context->GetIndexOfChildWithName( + ReconstructType(type), name, omit_empty_base_classes); +} +size_t TypeSystemSwiftTypeRef::GetIndexOfChildMemberWithName( + void *type, const char *name, bool omit_empty_base_classes, + std::vector &child_indexes) { + return m_swift_ast_context->GetIndexOfChildMemberWithName( + ReconstructType(type), name, omit_empty_base_classes, child_indexes); +} +size_t TypeSystemSwiftTypeRef::GetNumTemplateArguments(void *type) { + return m_swift_ast_context->GetNumTemplateArguments(ReconstructType(type)); +} +CompilerType TypeSystemSwiftTypeRef::GetTypeForFormatters(void *type) { + return m_swift_ast_context->GetTypeForFormatters(ReconstructType(type)); +} +LazyBool TypeSystemSwiftTypeRef::ShouldPrintAsOneLiner(void *type, + ValueObject *valobj) { + return m_swift_ast_context->ShouldPrintAsOneLiner(ReconstructType(type), + valobj); +} +bool TypeSystemSwiftTypeRef::IsMeaninglessWithoutDynamicResolution(void *type) { + return m_swift_ast_context->IsMeaninglessWithoutDynamicResolution( + ReconstructType(type)); +} +bool TypeSystemSwiftTypeRef::IsImportedType(CompilerType type, + CompilerType *original_type) { + return m_swift_ast_context->IsImportedType( + {m_swift_ast_context, ReconstructType(type.GetOpaqueQualType())}, + original_type); +} +bool TypeSystemSwiftTypeRef::IsErrorType(CompilerType compiler_type) { + return m_swift_ast_context->IsErrorType( + {m_swift_ast_context, + ReconstructType(compiler_type.GetOpaqueQualType())}); +} +CompilerType TypeSystemSwiftTypeRef::GetErrorType() { + return m_swift_ast_context->GetErrorType(); +} + +CompilerType +TypeSystemSwiftTypeRef::GetReferentType(CompilerType compiler_type) { + return m_swift_ast_context->GetReferentType( + {m_swift_ast_context, + ReconstructType(compiler_type.GetOpaqueQualType())}); +} + +CompilerType TypeSystemSwiftTypeRef::GetInstanceType(void *type) { + return m_swift_ast_context->GetInstanceType(ReconstructType(type)); +} +TypeSystemSwift::TypeAllocationStrategy +TypeSystemSwiftTypeRef::GetAllocationStrategy(CompilerType type) { + return m_swift_ast_context->GetAllocationStrategy( + {m_swift_ast_context, ReconstructType(type.GetOpaqueQualType())}); +} +CompilerType TypeSystemSwiftTypeRef::CreateTupleType( + const std::vector &elements) { + return m_swift_ast_context->CreateTupleType(elements); +} +void TypeSystemSwiftTypeRef::DumpTypeDescription( + void *type, bool print_help_if_available, + bool print_extensions_if_available) { + return m_swift_ast_context->DumpTypeDescription( + ReconstructType(type), print_help_if_available, print_help_if_available); +} +void TypeSystemSwiftTypeRef::DumpTypeDescription( + void *type, Stream *s, bool print_help_if_available, + bool print_extensions_if_available) { + return m_swift_ast_context->DumpTypeDescription( + ReconstructType(type), s, print_help_if_available, + print_extensions_if_available); +} + +// Dumping types +#ifndef NDEBUG +/// Convenience LLVM-style dump method for use in the debugger only. +LLVM_DUMP_METHOD void +TypeSystemSwiftTypeRef::dump(lldb::opaque_compiler_type_t type) const { + llvm::dbgs() << reinterpret_cast(type) << "\n"; +} +#endif + +void TypeSystemSwiftTypeRef::DumpValue( + void *type, ExecutionContext *exe_ctx, Stream *s, lldb::Format format, + const DataExtractor &data, lldb::offset_t data_offset, + size_t data_byte_size, uint32_t bitfield_bit_size, + uint32_t bitfield_bit_offset, bool show_types, bool show_summary, + bool verbose, uint32_t depth) { + return m_swift_ast_context->DumpValue( + ReconstructType(type), exe_ctx, s, format, data, data_offset, + data_byte_size, bitfield_bit_size, bitfield_bit_offset, show_types, + show_summary, verbose, depth); +} + +bool TypeSystemSwiftTypeRef::DumpTypeValue( + void *type, Stream *s, lldb::Format format, const DataExtractor &data, + lldb::offset_t data_offset, size_t data_byte_size, + uint32_t bitfield_bit_size, uint32_t bitfield_bit_offset, + ExecutionContextScope *exe_scope, bool is_base_class) { + return m_swift_ast_context->DumpTypeValue( + ReconstructType(type), s, format, data, data_offset, data_byte_size, + bitfield_bit_size, bitfield_bit_offset, exe_scope, is_base_class); +} + +void TypeSystemSwiftTypeRef::DumpTypeDescription(void *type) { + return m_swift_ast_context->DumpTypeDescription(ReconstructType(type)); +} +void TypeSystemSwiftTypeRef::DumpTypeDescription(void *type, Stream *s) { + return m_swift_ast_context->DumpTypeDescription(ReconstructType(type), s); +} +void TypeSystemSwiftTypeRef::DumpSummary(void *type, ExecutionContext *exe_ctx, + Stream *s, const DataExtractor &data, + lldb::offset_t data_offset, + size_t data_byte_size) { + return m_swift_ast_context->DumpSummary(ReconstructType(type), exe_ctx, s, + data, data_offset, data_byte_size); +} +bool TypeSystemSwiftTypeRef::IsPointerOrReferenceType( + void *type, CompilerType *pointee_type) { + return m_swift_ast_context->IsPointerOrReferenceType(ReconstructType(type), + pointee_type); +} +llvm::Optional +TypeSystemSwiftTypeRef::GetTypeBitAlign(void *type, + ExecutionContextScope *exe_scope) { + return m_swift_ast_context->GetTypeBitAlign(ReconstructType(type), exe_scope); +} +bool TypeSystemSwiftTypeRef::IsTypedefType(void *type) { + return m_swift_ast_context->IsTypedefType(ReconstructType(type)); +} +CompilerType TypeSystemSwiftTypeRef::GetTypedefedType(void *type) { + return m_swift_ast_context->GetTypedefedType(ReconstructType(type)); +} +CompilerType TypeSystemSwiftTypeRef::GetFullyUnqualifiedType(void *type) { + return m_swift_ast_context->GetFullyUnqualifiedType(ReconstructType(type)); +} +CompilerType TypeSystemSwiftTypeRef::GetNonReferenceType(void *type) { + return m_swift_ast_context->GetNonReferenceType(ReconstructType(type)); +} +CompilerType TypeSystemSwiftTypeRef::GetLValueReferenceType(void *type) { + return m_swift_ast_context->GetLValueReferenceType(ReconstructType(type)); +} +CompilerType TypeSystemSwiftTypeRef::GetRValueReferenceType(void *type) { + return m_swift_ast_context->GetRValueReferenceType(ReconstructType(type)); +} +uint32_t TypeSystemSwiftTypeRef::GetNumDirectBaseClasses(void *type) { + return m_swift_ast_context->GetNumDirectBaseClasses(ReconstructType(type)); +} +CompilerType +TypeSystemSwiftTypeRef::GetDirectBaseClassAtIndex(void *type, size_t idx, + uint32_t *bit_offset_ptr) { + return m_swift_ast_context->GetDirectBaseClassAtIndex(ReconstructType(type), + idx, bit_offset_ptr); +} +bool TypeSystemSwiftTypeRef::IsReferenceType(void *type, + CompilerType *pointee_type, + bool *is_rvalue) { + auto impl = [&]() { + using namespace swift::Demangle; + Demangler Dem; + NodePointer node = DemangleCanonicalType(Dem, type); + if (!node || node->getNumChildren() != 1 || + node->getKind() != Node::Kind::InOut) + return false; + + if (pointee_type) { + NodePointer referenced = node->getFirstChild(); + auto type = Dem.createNode(Node::Kind::Type); + type->addChild(referenced, Dem); + *pointee_type = RemangleAsType(Dem, type); + } + + if (is_rvalue) + *is_rvalue = false; + + return true; + }; + + VALIDATE_AND_RETURN( + impl, m_swift_ast_context->IsReferenceType(ReconstructType(type), + pointee_type, is_rvalue)); +} +bool TypeSystemSwiftTypeRef::ShouldTreatScalarValueAsAddress( + lldb::opaque_compiler_type_t type) { + return m_swift_ast_context->ShouldTreatScalarValueAsAddress( + ReconstructType(type)); +} diff --git a/lldb/source/Target/ABI.cpp b/lldb/source/Target/ABI.cpp index 127d8f858460e..d7a1dfa67d215 100644 --- a/lldb/source/Target/ABI.cpp +++ b/lldb/source/Target/ABI.cpp @@ -13,6 +13,7 @@ #include "lldb/Expression/ExpressionVariable.h" #include "lldb/Symbol/CompilerType.h" #include "lldb/Symbol/TypeSystem.h" +#include "lldb/Symbol/SwiftASTContext.h" #include "lldb/Target/Target.h" #include "lldb/Target/Thread.h" #include "lldb/Utility/Log.h" diff --git a/lldb/source/Target/AssertFrameRecognizer.cpp b/lldb/source/Target/AssertFrameRecognizer.cpp index ebeff6c393919..d87459ac2fdd4 100644 --- a/lldb/source/Target/AssertFrameRecognizer.cpp +++ b/lldb/source/Target/AssertFrameRecognizer.cpp @@ -21,8 +21,7 @@ namespace lldb_private { /// name. struct SymbolLocation { FileSpec module_spec; - ConstString symbol_name; - ConstString alternate_symbol_name; + std::vector symbols; }; /// Fetches the abort frame location depending on the current platform. @@ -39,12 +38,13 @@ bool GetAbortLocation(llvm::Triple::OSType os, SymbolLocation &location) { case llvm::Triple::Darwin: case llvm::Triple::MacOSX: location.module_spec = FileSpec("libsystem_kernel.dylib"); - location.symbol_name.SetString("__pthread_kill"); + location.symbols.push_back(ConstString("__pthread_kill")); break; case llvm::Triple::Linux: location.module_spec = FileSpec("libc.so.6"); - location.symbol_name.SetString("raise"); - location.alternate_symbol_name.SetString("__GI_raise"); + location.symbols.push_back(ConstString("raise")); + location.symbols.push_back(ConstString("__GI_raise")); + location.symbols.push_back(ConstString("gsignal")); break; default: Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_UNWIND)); @@ -69,12 +69,12 @@ bool GetAssertLocation(llvm::Triple::OSType os, SymbolLocation &location) { case llvm::Triple::Darwin: case llvm::Triple::MacOSX: location.module_spec = FileSpec("libsystem_c.dylib"); - location.symbol_name.SetString("__assert_rtn"); + location.symbols.push_back(ConstString("__assert_rtn")); break; case llvm::Triple::Linux: location.module_spec = FileSpec("libc.so.6"); - location.symbol_name.SetString("__assert_fail"); - location.alternate_symbol_name.SetString("__GI___assert_fail"); + location.symbols.push_back(ConstString("__assert_fail")); + location.symbols.push_back(ConstString("__GI___assert_fail")); break; default: Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_UNWIND)); @@ -97,8 +97,7 @@ void RegisterAssertFrameRecognizer(Process *process) { StackFrameRecognizerManager::AddRecognizer( StackFrameRecognizerSP(new AssertFrameRecognizer()), - location.module_spec.GetFilename(), ConstString(location.symbol_name), - ConstString(location.alternate_symbol_name), + location.module_spec.GetFilename(), location.symbols, /*first_instruction_only*/ false); }); } @@ -139,10 +138,7 @@ AssertFrameRecognizer::RecognizeFrame(lldb::StackFrameSP frame_sp) { ConstString func_name = sym_ctx.GetFunctionName(); - if (func_name == location.symbol_name || - (!location.alternate_symbol_name.IsEmpty() && - func_name == location.alternate_symbol_name)) { - + if (llvm::is_contained(location.symbols, func_name)) { // We go a frame beyond the assert location because the most relevant // frame for the user is the one in which the assert function was called. // If the assert location is the last frame fetched, then it is set as diff --git a/lldb/source/Target/CMakeLists.txt b/lldb/source/Target/CMakeLists.txt index 7d0e53b1e342d..aa8254c76cbbc 100644 --- a/lldb/source/Target/CMakeLists.txt +++ b/lldb/source/Target/CMakeLists.txt @@ -65,6 +65,7 @@ add_lldb_library(lldbTarget ThreadPlanStepThrough.cpp ThreadPlanStepUntil.cpp ThreadPlanTracer.cpp + ThreadPlanStack.cpp ThreadSpec.cpp UnixSignals.cpp UnwindAssembly.cpp diff --git a/lldb/source/Target/Process.cpp b/lldb/source/Target/Process.cpp index 4165bb660be0e..89aa4b63462f4 100644 --- a/lldb/source/Target/Process.cpp +++ b/lldb/source/Target/Process.cpp @@ -60,6 +60,7 @@ #include "lldb/Target/ThreadPlan.h" #include "lldb/Target/ThreadPlanBase.h" #include "lldb/Target/ThreadPlanCallFunction.h" +#include "lldb/Target/ThreadPlanStack.h" #include "lldb/Target/UnixSignals.h" #include "lldb/Utility/Event.h" #include "lldb/Utility/Log.h" @@ -484,7 +485,7 @@ Process::Process(lldb::TargetSP target_sp, ListenerSP listener_sp, m_mod_id(), m_process_unique_id(0), m_thread_index_id(0), m_thread_id_to_index_id_map(), m_exit_status(-1), m_exit_string(), m_exit_status_mutex(), m_thread_mutex(), m_thread_list_real(this), - m_thread_list(this), m_extended_thread_list(this), + m_thread_list(this), m_thread_plans(*this), m_extended_thread_list(this), m_extended_thread_stop_id(0), m_queue_list(this), m_queue_list_stop_id(0), m_notifications(), m_image_tokens(), m_listener_sp(listener_sp), m_breakpoint_site_list(), m_dynamic_checkers_up(), @@ -608,6 +609,7 @@ void Process::Finalize() { m_system_runtime_up.reset(); m_dyld_up.reset(); m_jit_loaders_up.reset(); + m_thread_plans.Clear(); m_thread_list_real.Destroy(); m_thread_list.Destroy(); m_extended_thread_list.Destroy(); @@ -1290,9 +1292,12 @@ void Process::UpdateThreadListIfNeeded() { const uint32_t stop_id = GetStopID(); if (m_thread_list.GetSize(false) == 0 || stop_id != m_thread_list.GetStopID()) { + bool clear_unused_threads = true; const StateType state = GetPrivateState(); if (StateIsStoppedState(state, true)) { std::lock_guard guard(m_thread_list.GetMutex()); + m_thread_list.SetStopID(stop_id); + // m_thread_list does have its own mutex, but we need to hold onto the // mutex between the call to UpdateThreadList(...) and the // os->UpdateThreadList(...) so it doesn't change on us @@ -1313,6 +1318,10 @@ void Process::UpdateThreadListIfNeeded() { size_t num_old_threads = old_thread_list.GetSize(false); for (size_t i = 0; i < num_old_threads; ++i) old_thread_list.GetThreadAtIndex(i, false)->ClearBackingThread(); + // See if the OS plugin reports all threads. If it does, then + // it is safe to clear unseen thread's plans here. Otherwise we + // should preserve them in case they show up again: + clear_unused_threads = GetTarget().GetOSPluginReportsAllThreads(); // Turn off dynamic types to ensure we don't run any expressions. // Objective-C can run an expression to determine if a SBValue is a @@ -1339,7 +1348,7 @@ void Process::UpdateThreadListIfNeeded() { target.SetPreferDynamicValue(saved_prefer_dynamic); } else { // No OS plug-in, the new thread list is the same as the real thread - // list + // list. new_thread_list = real_thread_list; } @@ -1356,10 +1365,42 @@ void Process::UpdateThreadListIfNeeded() { m_queue_list_stop_id = GetLastNaturalStopID(); } } + // Now update the plan stack map. + // If we do have an OS plugin, any absent real threads in the + // m_thread_list have already been removed from the ThreadPlanStackMap. + // So any remaining threads are OS Plugin threads, and those we want to + // preserve in case they show up again. + m_thread_plans.Update(m_thread_list, clear_unused_threads); } } } +ThreadPlanStack *Process::FindThreadPlans(lldb::tid_t tid) { + return m_thread_plans.Find(tid); +} + +bool Process::PruneThreadPlansForTID(lldb::tid_t tid) { + return m_thread_plans.PrunePlansForTID(tid); +} + +void Process::PruneThreadPlans() { + m_thread_plans.Update(GetThreadList(), true, false); +} + +bool Process::DumpThreadPlansForTID(Stream &strm, lldb::tid_t tid, + lldb::DescriptionLevel desc_level, + bool internal, bool condense_trivial, + bool skip_unreported_plans) { + return m_thread_plans.DumpPlansForTID( + strm, tid, desc_level, internal, condense_trivial, skip_unreported_plans); +} +void Process::DumpThreadPlans(Stream &strm, lldb::DescriptionLevel desc_level, + bool internal, bool condense_trivial, + bool skip_unreported_plans) { + m_thread_plans.DumpPlans(strm, desc_level, internal, condense_trivial, + skip_unreported_plans); +} + void Process::UpdateQueueListIfNeeded() { if (m_system_runtime_up) { if (m_queue_list.GetSize() == 0 || @@ -2911,9 +2952,9 @@ Status Process::Attach(ProcessAttachInfo &attach_info) { match_info.GetProcessInfo() = attach_info; match_info.SetNameMatchType(NameMatch::Equals); platform_sp->FindProcesses(match_info, process_infos); - const uint32_t num_matches = process_infos.GetSize(); + const uint32_t num_matches = process_infos.size(); if (num_matches == 1) { - attach_pid = process_infos.GetProcessIDAtIndex(0); + attach_pid = process_infos[0].GetProcessID(); // Fall through and attach using the above process ID } else { match_info.GetProcessInfo().GetExecutableFile().GetPath( @@ -2922,7 +2963,7 @@ Status Process::Attach(ProcessAttachInfo &attach_info) { StreamString s; ProcessInstanceInfo::DumpTableHeader(s, true, false); for (size_t i = 0; i < num_matches; i++) { - process_infos.GetProcessInfoAtIndex(i).DumpAsTableRow( + process_infos[i].DumpAsTableRow( s, platform_sp->GetUserIDResolver(), true, false); } error.SetErrorStringWithFormat( @@ -3344,6 +3385,10 @@ Status Process::Detach(bool keep_stopped) { } Status Process::Destroy(bool force_kill) { + // If we've already called Process::Finalize then there's nothing useful to + // be done here. Finalize has actually called Destroy already. + if (m_finalize_called) + return {}; // Tell ourselves we are in the process of destroying the process, so that we // don't do any unnecessary work that might hinder the destruction. Remember diff --git a/lldb/source/Target/StackFrameList.cpp b/lldb/source/Target/StackFrameList.cpp index 527f2630374c2..e52b7c8b27f15 100644 --- a/lldb/source/Target/StackFrameList.cpp +++ b/lldb/source/Target/StackFrameList.cpp @@ -239,13 +239,17 @@ void StackFrameList::GetOnlyConcreteFramesUpTo(uint32_t end_idx, m_frames.resize(num_frames); } +/// A sequence of calls that comprise some portion of a backtrace. Each frame +/// is represented as a pair of a callee (Function *) and an address within the +/// callee. +using CallSequence = std::vector>; + /// Find the unique path through the call graph from \p begin (with return PC /// \p return_pc) to \p end. On success this path is stored into \p path, and /// on failure \p path is unchanged. static void FindInterveningFrames(Function &begin, Function &end, ExecutionContext &exe_ctx, Target &target, - addr_t return_pc, - std::vector &path, + addr_t return_pc, CallSequence &path, ModuleList &images, Log *log) { LLDB_LOG(log, "Finding frames between {0} and {1}, retn-pc={2:x}", begin.GetDisplayName(), end.GetDisplayName(), return_pc); @@ -278,24 +282,27 @@ static void FindInterveningFrames(Function &begin, Function &end, // Fully explore the set of functions reachable from the first edge via tail // calls in order to detect ambiguous executions. struct DFS { - std::vector active_path = {}; - std::vector solution_path = {}; + CallSequence active_path = {}; + CallSequence solution_path = {}; llvm::SmallPtrSet visited_nodes = {}; bool ambiguous = false; Function *end; ModuleList &images; + Target ⌖ ExecutionContext &context; - DFS(Function *end, ModuleList &images, ExecutionContext &context) - : end(end), images(images), context(context) {} + DFS(Function *end, ModuleList &images, Target &target, + ExecutionContext &context) + : end(end), images(images), target(target), context(context) {} - void search(Function &first_callee, std::vector &path) { - dfs(first_callee); + void search(CallEdge &first_edge, Function &first_callee, + CallSequence &path) { + dfs(first_edge, first_callee); if (!ambiguous) path = std::move(solution_path); } - void dfs(Function &callee) { + void dfs(CallEdge ¤t_edge, Function &callee) { // Found a path to the target function. if (&callee == end) { if (solution_path.empty()) @@ -315,13 +322,16 @@ static void FindInterveningFrames(Function &begin, Function &end, } // Search the calls made from this callee. - active_path.push_back(&callee); + active_path.emplace_back(&callee, LLDB_INVALID_ADDRESS); for (const auto &edge : callee.GetTailCallingEdges()) { Function *next_callee = edge->GetCallee(images, context); if (!next_callee) continue; - dfs(*next_callee); + addr_t tail_call_pc = edge->GetCallInstPC(callee, target); + active_path.back().second = tail_call_pc; + + dfs(*edge, *next_callee); if (ambiguous) return; } @@ -329,7 +339,7 @@ static void FindInterveningFrames(Function &begin, Function &end, } }; - DFS(&end, images, exe_ctx).search(*first_callee, path); + DFS(&end, images, target, exe_ctx).search(*first_edge, *first_callee, path); } /// Given that \p next_frame will be appended to the frame list, synthesize @@ -382,7 +392,7 @@ void StackFrameList::SynthesizeTailCallFrames(StackFrame &next_frame) { // Try to find the unique sequence of (tail) calls which led from next_frame // to prev_frame. - std::vector path; + CallSequence path; addr_t return_pc = next_reg_ctx_sp->GetPC(); Target &target = *target_sp.get(); ModuleList &images = next_frame.CalculateTarget()->GetImages(); @@ -392,14 +402,17 @@ void StackFrameList::SynthesizeTailCallFrames(StackFrame &next_frame) { path, images, log); // Push synthetic tail call frames. - for (Function *callee : llvm::reverse(path)) { + for (auto calleeInfo : llvm::reverse(path)) { + Function *callee = calleeInfo.first; uint32_t frame_idx = m_frames.size(); uint32_t concrete_frame_idx = next_frame.GetConcreteFrameIndex(); addr_t cfa = LLDB_INVALID_ADDRESS; bool cfa_is_valid = false; - addr_t pc = - callee->GetAddressRange().GetBaseAddress().GetLoadAddress(&target); - constexpr bool behaves_like_zeroth_frame = false; + addr_t pc = calleeInfo.second; + // We do not want to subtract 1 from this PC, as it's the actual address + // of the tail-calling branch instruction. This address is provided by the + // compiler via DW_AT_call_pc. + constexpr bool behaves_like_zeroth_frame = true; SymbolContext sc; callee->CalculateSymbolContext(&sc); auto synth_frame = std::make_shared( @@ -407,7 +420,7 @@ void StackFrameList::SynthesizeTailCallFrames(StackFrame &next_frame) { cfa_is_valid, pc, StackFrame::Kind::Artificial, behaves_like_zeroth_frame, &sc); m_frames.push_back(synth_frame); - LLDB_LOG(log, "Pushed frame {0}", callee->GetDisplayName()); + LLDB_LOG(log, "Pushed frame {0} at {1:x}", callee->GetDisplayName(), pc); } // If any frames were created, adjust next_frame's index. diff --git a/lldb/source/Target/StackFrameRecognizer.cpp b/lldb/source/Target/StackFrameRecognizer.cpp index dfc811da0a507..32b8c94d942c0 100644 --- a/lldb/source/Target/StackFrameRecognizer.cpp +++ b/lldb/source/Target/StackFrameRecognizer.cpp @@ -51,27 +51,25 @@ ScriptedStackFrameRecognizer::RecognizeFrame(lldb::StackFrameSP frame) { class StackFrameRecognizerManagerImpl { public: void AddRecognizer(StackFrameRecognizerSP recognizer, ConstString module, - ConstString symbol, ConstString alternate_symbol, + llvm::ArrayRef symbols, bool first_instruction_only) { m_recognizers.push_front({(uint32_t)m_recognizers.size(), false, recognizer, - false, module, RegularExpressionSP(), symbol, - alternate_symbol, RegularExpressionSP(), - first_instruction_only}); + false, module, RegularExpressionSP(), symbols, + RegularExpressionSP(), first_instruction_only}); } void AddRecognizer(StackFrameRecognizerSP recognizer, RegularExpressionSP module, RegularExpressionSP symbol, bool first_instruction_only) { - m_recognizers.push_front({(uint32_t)m_recognizers.size(), false, recognizer, - true, ConstString(), module, ConstString(), - ConstString(), symbol, first_instruction_only}); + m_recognizers.push_front( + {(uint32_t)m_recognizers.size(), false, recognizer, true, ConstString(), + module, std::vector(), symbol, first_instruction_only}); } - void ForEach( - std::function const - &callback) { + void ForEach(std::function< + void(uint32_t recognized_id, std::string recognizer_name, + std::string module, llvm::ArrayRef symbols, + bool regexp)> const &callback) { for (auto entry : m_recognizers) { if (entry.is_regexp) { std::string module_name; @@ -83,16 +81,11 @@ class StackFrameRecognizerManagerImpl { symbol_name = entry.symbol_regexp->GetText().str(); callback(entry.recognizer_id, entry.recognizer->GetName(), module_name, - symbol_name, {}, true); + llvm::makeArrayRef(ConstString(symbol_name)), true); } else { - std::string alternate_symbol; - if (!entry.alternate_symbol.IsEmpty()) - alternate_symbol.append(entry.alternate_symbol.GetCString()); - callback(entry.recognizer_id, entry.recognizer->GetName(), - entry.module.GetCString(), entry.symbol.GetCString(), - alternate_symbol, false); + entry.module.GetCString(), entry.symbols, false); } } } @@ -128,10 +121,8 @@ class StackFrameRecognizerManagerImpl { if (entry.module_regexp) if (!entry.module_regexp->Execute(module_name.GetStringRef())) continue; - if (entry.symbol) - if (entry.symbol != function_name && - (!entry.alternate_symbol || - entry.alternate_symbol != function_name)) + if (!entry.symbols.empty()) + if (!llvm::is_contained(entry.symbols, function_name)) continue; if (entry.symbol_regexp) @@ -160,8 +151,7 @@ class StackFrameRecognizerManagerImpl { bool is_regexp; ConstString module; RegularExpressionSP module_regexp; - ConstString symbol; - ConstString alternate_symbol; + std::vector symbols; RegularExpressionSP symbol_regexp; bool first_instruction_only; }; @@ -176,10 +166,10 @@ StackFrameRecognizerManagerImpl &GetStackFrameRecognizerManagerImpl() { } void StackFrameRecognizerManager::AddRecognizer( - StackFrameRecognizerSP recognizer, ConstString module, ConstString symbol, - ConstString alternate_symbol, bool first_instruction_only) { + StackFrameRecognizerSP recognizer, ConstString module, + llvm::ArrayRef symbols, bool first_instruction_only) { GetStackFrameRecognizerManagerImpl().AddRecognizer( - recognizer, module, symbol, alternate_symbol, first_instruction_only); + recognizer, module, symbols, first_instruction_only); } void StackFrameRecognizerManager::AddRecognizer( @@ -191,9 +181,8 @@ void StackFrameRecognizerManager::AddRecognizer( void StackFrameRecognizerManager::ForEach( std::function const - &callback) { + std::string module, llvm::ArrayRef symbols, + bool regexp)> const &callback) { GetStackFrameRecognizerManagerImpl().ForEach(callback); } diff --git a/lldb/source/Target/SwiftLanguageRuntime.cpp b/lldb/source/Target/SwiftLanguageRuntime.cpp index 56d0be4f827f0..a2f4cb4818379 100644 --- a/lldb/source/Target/SwiftLanguageRuntime.cpp +++ b/lldb/source/Target/SwiftLanguageRuntime.cpp @@ -19,12 +19,13 @@ #include "lldb/Core/Section.h" #include "lldb/Core/ValueObjectConstResult.h" #include "lldb/DataFormatters/StringPrinter.h" +#include "lldb/Expression/ExpressionVariable.h" #include "lldb/Host/OptionParser.h" #include "lldb/Interpreter/CommandInterpreter.h" #include "lldb/Interpreter/CommandObject.h" #include "lldb/Interpreter/CommandObjectMultiword.h" #include "lldb/Interpreter/CommandReturnObject.h" -#include "lldb/Symbol/TypeSystemClang.h" +#include "Plugins/TypeSystem/Clang/TypeSystemClang.h" #include "lldb/Symbol/Function.h" #include "lldb/Symbol/VariableList.h" #include "lldb/Target/RegisterContext.h" @@ -46,6 +47,7 @@ // FIXME: we should not need this #include "Plugins/Language/Swift/SwiftFormatters.h" #include "Plugins/Language/Swift/SwiftRuntimeFailureRecognizer.h" +#include "Plugins/ExpressionParser/Clang/ClangExpressionVariable.h" using namespace lldb; using namespace lldb_private; @@ -190,9 +192,10 @@ class SwiftLanguageRuntimeStub { #define STUB_LOG() \ do { \ - LLDB_LOG(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_EXPRESSIONS | \ - LIBLLDB_LOG_TYPES), \ - g_stub_log_message, GetStandardLibraryName(m_process)); \ + LLDB_LOGF(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_EXPRESSIONS | \ + LIBLLDB_LOG_TYPES), \ + g_stub_log_message, \ + GetStandardLibraryName(m_process).AsCString()); \ assert(false && "called into swift language runtime stub"); \ } while (0) diff --git a/lldb/source/Target/SwiftLanguageRuntimeDynamicTypeResolution.cpp b/lldb/source/Target/SwiftLanguageRuntimeDynamicTypeResolution.cpp index 79320ca309f42..faa5416cabbb6 100644 --- a/lldb/source/Target/SwiftLanguageRuntimeDynamicTypeResolution.cpp +++ b/lldb/source/Target/SwiftLanguageRuntimeDynamicTypeResolution.cpp @@ -13,7 +13,7 @@ #include "SwiftLanguageRuntimeImpl.h" #include "lldb/Target/SwiftLanguageRuntime.h" -#include "lldb/Symbol/TypeSystemClang.h" +#include "Plugins/TypeSystem/Clang/TypeSystemClang.h" #include "lldb/Symbol/Function.h" #include "lldb/Symbol/Variable.h" #include "lldb/Symbol/VariableList.h" @@ -1518,11 +1518,11 @@ bool SwiftLanguageRuntimeImpl::GetDynamicTypeAndAddress( class_type_or_name, address); else { // Perform archetype binding in the scratch context. - auto *frame = in_value.GetExecutionContextRef().GetFrameSP().get(); + StackFrameSP frame = in_value.GetExecutionContextRef().GetFrameSP(); if (!frame) return false; - CompilerType bound_type = DoArchetypeBindingForType(*frame, val_type); + CompilerType bound_type = DoArchetypeBindingForType(*frame.get(), val_type); if (!bound_type) return false; diff --git a/lldb/source/Target/Target.cpp b/lldb/source/Target/Target.cpp index 6669e5073a278..035f15b3a01f0 100644 --- a/lldb/source/Target/Target.cpp +++ b/lldb/source/Target/Target.cpp @@ -8,6 +8,8 @@ #include "lldb/Target/Target.h" #include "Plugins/ExpressionParser/Clang/ClangModulesDeclVendor.h" +#include "Plugins/ExpressionParser/Clang/ClangModulesDeclVendor.h" +#include "Plugins/ExpressionParser/Clang/ClangPersistentVariables.h" #include "lldb/Breakpoint/BreakpointIDList.h" #include "lldb/Breakpoint/BreakpointPrecondition.h" #include "lldb/Breakpoint/BreakpointResolver.h" @@ -37,10 +39,11 @@ #include "lldb/Interpreter/OptionGroupWatchpoint.h" #include "lldb/Interpreter/OptionValues.h" #include "lldb/Interpreter/Property.h" -#include "lldb/Symbol/TypeSystemClang.h" -#include "lldb/Symbol/ClangASTImporter.h" +#include "Plugins/TypeSystem/Clang/TypeSystemClang.h" +#include "Plugins/ExpressionParser/Clang/ClangASTImporter.h" #include "lldb/Symbol/Function.h" #include "lldb/Symbol/ObjectFile.h" +#include "lldb/Symbol/SwiftASTContext.h" #include "lldb/Symbol/Symbol.h" #include "lldb/Symbol/SymbolFile.h" #include "lldb/Symbol/SymbolVendor.h" @@ -117,6 +120,8 @@ Target::Target(Debugger &debugger, const ArchSpec &target_arch, target_arch.GetArchitectureName(), target_arch.GetTriple().getTriple().c_str()); } + + UpdateLaunchInfoFromProperties(); } Target::~Target() { @@ -264,6 +269,16 @@ void Target::SetREPL(lldb::LanguageType language, lldb::REPLSP repl_sp) { lldbassert(!m_repl_map.count(language)); m_repl_map[language] = repl_sp; + + if (language == eLanguageTypeSwift) { + // The DWARFImporter always claims to be able to load a module, even if it + // doesn't exist, because it doesn't "import" anything until the first type is + // requested. To make the REPL behave more like the compiler and diagnose when + // Clang modules can't be located up front, the DWARFImporter is disabled in + // the REPL. There are use-cases for loading Clang types from debug info, but + // this needs a better diagnostic mechanism before it can be enabled. + ModuleList::GetGlobalModuleListProperties().SetUseSwiftDWARFImporter(repl_sp == NULL); + } } void Target::Destroy() { @@ -3283,11 +3298,6 @@ Status Target::Launch(ProcessLaunchInfo &launch_info, Stream *stream) { } } m_process_sp->RestoreProcessEvents(); - } else { - Status error2; - error2.SetErrorStringWithFormat("process launch failed: %s", - error.AsCString()); - error = error2; } return error; } @@ -3673,16 +3683,13 @@ enum { class TargetOptionValueProperties : public OptionValueProperties { public: - TargetOptionValueProperties(ConstString name) - : OptionValueProperties(name), m_target(nullptr), m_got_host_env(false) {} + TargetOptionValueProperties(ConstString name) : OptionValueProperties(name) {} // This constructor is used when creating TargetOptionValueProperties when it // is part of a new lldb_private::Target instance. It will copy all current // global property values as needed - TargetOptionValueProperties(Target *target, - const TargetPropertiesSP &target_properties_sp) - : OptionValueProperties(*target_properties_sp->GetValueProperties()), - m_target(target), m_got_host_env(false) {} + TargetOptionValueProperties(const TargetPropertiesSP &target_properties_sp) + : OptionValueProperties(*target_properties_sp->GetValueProperties()) {} const Property *GetPropertyAtIndex(const ExecutionContext *exe_ctx, bool will_modify, @@ -3690,9 +3697,6 @@ class TargetOptionValueProperties : public OptionValueProperties { // When getting the value for a key from the target options, we will always // try and grab the setting from the current target if there is one. Else // we just use the one from this instance. - if (idx == ePropertyEnvVars) - GetHostEnvironmentIfNeeded(); - if (exe_ctx) { Target *target = exe_ctx->GetTargetPtr(); if (target) { @@ -3705,41 +3709,6 @@ class TargetOptionValueProperties : public OptionValueProperties { } return ProtectedGetPropertyAtIndex(idx); } - - lldb::TargetSP GetTargetSP() { return m_target->shared_from_this(); } - -protected: - void GetHostEnvironmentIfNeeded() const { - if (!m_got_host_env) { - if (m_target) { - m_got_host_env = true; - const uint32_t idx = ePropertyInheritEnv; - if (GetPropertyAtIndexAsBoolean( - nullptr, idx, g_target_properties[idx].default_uint_value != 0)) { - PlatformSP platform_sp(m_target->GetPlatform()); - if (platform_sp) { - Environment env = platform_sp->GetEnvironment(); - OptionValueDictionary *env_dict = - GetPropertyAtIndexAsOptionValueDictionary(nullptr, - ePropertyEnvVars); - if (env_dict) { - const bool can_replace = false; - for (const auto &KV : env) { - // Don't allow existing keys to be replaced with ones we get - // from the platform environment - env_dict->SetValueForKey( - ConstString(KV.first()), - OptionValueSP(new OptionValueString(KV.second.c_str())), - can_replace); - } - } - } - } - } - } - } - Target *m_target; - mutable bool m_got_host_env; }; // TargetProperties @@ -3766,10 +3735,10 @@ TargetExperimentalProperties::TargetExperimentalProperties() // TargetProperties TargetProperties::TargetProperties(Target *target) - : Properties(), m_launch_info() { + : Properties(), m_launch_info(), m_target(target) { if (target) { m_collection_sp = std::make_shared( - target, Target::GetGlobalProperties()); + Target::GetGlobalProperties()); // Set callbacks to update launch_info whenever "settins set" updated any // of these properties @@ -3779,6 +3748,12 @@ TargetProperties::TargetProperties(Target *target) ePropertyRunArgs, TargetProperties::RunArgsValueChangedCallback, this); m_collection_sp->SetValueChangedCallback( ePropertyEnvVars, TargetProperties::EnvVarsValueChangedCallback, this); + m_collection_sp->SetValueChangedCallback( + ePropertyUnsetEnvVars, TargetProperties::EnvVarsValueChangedCallback, + this); + m_collection_sp->SetValueChangedCallback( + ePropertyInheritEnv, TargetProperties::EnvVarsValueChangedCallback, + this); m_collection_sp->SetValueChangedCallback( ePropertyInputPath, TargetProperties::InputPathValueChangedCallback, this); @@ -3804,18 +3779,6 @@ TargetProperties::TargetProperties(Target *target) ConstString("Experimental settings - setting these won't produce " "errors if the setting is not present."), true, m_experimental_properties_up->GetValueProperties()); - - // Update m_launch_info once it was created - Arg0ValueChangedCallback(this, nullptr); - RunArgsValueChangedCallback(this, nullptr); - // EnvVarsValueChangedCallback(this, nullptr); // FIXME: cause segfault in - // Target::GetPlatform() - InputPathValueChangedCallback(this, nullptr); - OutputPathValueChangedCallback(this, nullptr); - ErrorPathValueChangedCallback(this, nullptr); - DetachOnErrorValueChangedCallback(this, nullptr); - DisableASLRValueChangedCallback(this, nullptr); - DisableSTDIOValueChangedCallback(this, nullptr); } else { m_collection_sp = std::make_shared(ConstString("target")); @@ -3834,6 +3797,18 @@ TargetProperties::TargetProperties(Target *target) TargetProperties::~TargetProperties() = default; +void TargetProperties::UpdateLaunchInfoFromProperties() { + Arg0ValueChangedCallback(this, nullptr); + RunArgsValueChangedCallback(this, nullptr); + EnvVarsValueChangedCallback(this, nullptr); + InputPathValueChangedCallback(this, nullptr); + OutputPathValueChangedCallback(this, nullptr); + ErrorPathValueChangedCallback(this, nullptr); + DetachOnErrorValueChangedCallback(this, nullptr); + DisableASLRValueChangedCallback(this, nullptr); + DisableSTDIOValueChangedCallback(this, nullptr); +} + bool TargetProperties::GetInjectLocalVariables( ExecutionContext *exe_ctx) const { const Property *exp_property = m_collection_sp->GetPropertyAtIndex( @@ -3870,6 +3845,32 @@ bool TargetProperties::GetSwiftCreateModuleContextsInParallel() const { return true; } +bool TargetProperties::GetOSPluginReportsAllThreads() const { + const bool fail_value = true; + const Property *exp_property = + m_collection_sp->GetPropertyAtIndex(nullptr, true, ePropertyExperimental); + OptionValueProperties *exp_values = + exp_property->GetValue()->GetAsProperties(); + if (!exp_values) + return fail_value; + + return + exp_values->GetPropertyAtIndexAsBoolean(nullptr, + ePropertyOSPluginReportsAllThreads, + fail_value); +} + +void TargetProperties::SetOSPluginReportsAllThreads(bool does_report) { + const Property *exp_property = + m_collection_sp->GetPropertyAtIndex(nullptr, true, ePropertyExperimental); + OptionValueProperties *exp_values = + exp_property->GetValue()->GetAsProperties(); + if (exp_values) + exp_values->SetPropertyAtIndexAsBoolean(nullptr, + ePropertyOSPluginReportsAllThreads, + does_report); +} + ArchSpec TargetProperties::GetDefaultArchitecture() const { OptionValueArch *value = m_collection_sp->GetPropertyAtIndexAsOptionValueArch( nullptr, ePropertyDefaultArch); @@ -3987,19 +3988,43 @@ void TargetProperties::SetRunArguments(const Args &args) { m_launch_info.GetArguments() = args; } +Environment TargetProperties::ComputeEnvironment() const { + Environment env; + + if (m_target && + m_collection_sp->GetPropertyAtIndexAsBoolean( + nullptr, ePropertyInheritEnv, + g_target_properties[ePropertyInheritEnv].default_uint_value != 0)) { + if (auto platform_sp = m_target->GetPlatform()) { + Environment platform_env = platform_sp->GetEnvironment(); + for (const auto &KV : platform_env) + env[KV.first()] = KV.second; + } + } + + Args property_unset_env; + m_collection_sp->GetPropertyAtIndexAsArgs(nullptr, ePropertyUnsetEnvVars, + property_unset_env); + for (const auto &var : property_unset_env) + env.erase(var.ref()); + + Args property_env; + m_collection_sp->GetPropertyAtIndexAsArgs(nullptr, ePropertyEnvVars, + property_env); + for (const auto &KV : Environment(property_env)) + env[KV.first()] = KV.second; + + return env; +} + Environment TargetProperties::GetEnvironment() const { - // TODO: Get rid of the Args intermediate step - Args env; - const uint32_t idx = ePropertyEnvVars; - m_collection_sp->GetPropertyAtIndexAsArgs(nullptr, idx, env); - return Environment(env); + return ComputeEnvironment(); } void TargetProperties::SetEnvironment(Environment env) { // TODO: Get rid of the Args intermediate step const uint32_t idx = ePropertyEnvVars; m_collection_sp->SetPropertyAtIndexFromArgs(nullptr, idx, Args(env)); - m_launch_info.GetEnvironment() = std::move(env); } bool TargetProperties::GetSkipPrologue() const { @@ -4359,7 +4384,7 @@ void TargetProperties::EnvVarsValueChangedCallback(void *target_property_ptr, OptionValue *) { TargetProperties *this_ = static_cast(target_property_ptr); - this_->m_launch_info.GetEnvironment() = this_->GetEnvironment(); + this_->m_launch_info.GetEnvironment() = this_->ComputeEnvironment(); } void TargetProperties::InputPathValueChangedCallback(void *target_property_ptr, diff --git a/lldb/source/Target/TargetProperties.td b/lldb/source/Target/TargetProperties.td index 1f20484363afe..3b2d1fac9a961 100644 --- a/lldb/source/Target/TargetProperties.td +++ b/lldb/source/Target/TargetProperties.td @@ -7,6 +7,10 @@ let Definition = "experimental" in { def SwiftCreateModuleContextsInParallel : Property<"swift-create-module-contexts-in-parallel", "Boolean">, DefaultTrue, Desc<"Create the per-module Swift AST contexts in parallel.">; + def OSPluginReportsAllThreads: Property<"os-plugin-reports-all-threads", "Boolean">, + Global, + DefaultTrue, + Desc<"Set to False if your OS Plugins doesn't report all threads on each stop.">; } let Definition = "target" in { @@ -83,7 +87,10 @@ let Definition = "target" in { Desc<"A list containing all the arguments to be passed to the executable when it is run. Note that this does NOT include the argv[0] which is in target.arg0.">; def EnvVars: Property<"env-vars", "Dictionary">, DefaultUnsignedValue<16>, - Desc<"A list of all the environment variables to be passed to the executable's environment, and their values.">; + Desc<"A list of user provided environment variables to be passed to the executable's environment, and their values.">; + def UnsetEnvVars: Property<"unset-env-vars", "Array">, + DefaultUnsignedValue<16>, + Desc<"A list of environment variable names to be unset in the inferior's environment. This is most useful to unset some host environment variables when target.inherit-env is true. target.env-vars takes precedence over target.unset-env-vars.">; def InheritEnv: Property<"inherit-env", "Boolean">, DefaultTrue, Desc<"Inherit the environment from the process that is running LLDB.">; diff --git a/lldb/source/Target/Thread.cpp b/lldb/source/Target/Thread.cpp index 8d2343c8d3bd2..9043f16c9b795 100644 --- a/lldb/source/Target/Thread.cpp +++ b/lldb/source/Target/Thread.cpp @@ -35,6 +35,7 @@ #include "lldb/Target/ThreadPlanCallFunction.h" #include "lldb/Target/ThreadPlanPython.h" #include "lldb/Target/ThreadPlanRunToAddress.h" +#include "lldb/Target/ThreadPlanStack.h" #include "lldb/Target/ThreadPlanStepInRange.h" #include "lldb/Target/ThreadPlanStepInstruction.h" #include "lldb/Target/ThreadPlanStepOut.h" @@ -230,8 +231,7 @@ Thread::Thread(Process &process, lldb::tid_t tid, bool use_invalid_index_id) m_index_id(use_invalid_index_id ? LLDB_INVALID_INDEX32 : process.GetNextThreadIndexID(tid)), m_reg_context_sp(), m_state(eStateUnloaded), m_state_mutex(), - m_plan_stack(), m_completed_plan_stack(), m_frame_mutex(), - m_curr_frames_sp(), m_prev_frames_sp(), + m_frame_mutex(), m_curr_frames_sp(), m_prev_frames_sp(), m_resume_signal(LLDB_INVALID_SIGNAL_NUMBER), m_resume_state(eStateRunning), m_temporary_resume_state(eStateRunning), m_unwinder_up(), m_destroy_called(false), @@ -242,8 +242,6 @@ Thread::Thread(Process &process, lldb::tid_t tid, bool use_invalid_index_id) static_cast(this), GetID()); CheckInWithManager(); - - QueueFundamentalPlan(true); } Thread::~Thread() { @@ -256,30 +254,7 @@ Thread::~Thread() { } void Thread::DestroyThread() { - // Tell any plans on the plan stacks that the thread is being destroyed since - // any plans that have a thread go away in the middle of might need to do - // cleanup, or in some cases NOT do cleanup... - for (auto plan : m_plan_stack) - plan->ThreadDestroyed(); - - for (auto plan : m_discarded_plan_stack) - plan->ThreadDestroyed(); - - for (auto plan : m_completed_plan_stack) - plan->ThreadDestroyed(); - m_destroy_called = true; - m_plan_stack.clear(); - m_discarded_plan_stack.clear(); - m_completed_plan_stack.clear(); - - // Push a ThreadPlanNull on the plan stack. That way we can continue - // assuming that the plan stack is never empty, but if somebody errantly asks - // questions of a destroyed thread without checking first whether it is - // destroyed, they won't crash. - ThreadPlanSP null_plan_sp(new ThreadPlanNull(*this)); - m_plan_stack.push_back(null_plan_sp); - m_stop_info_sp.reset(); m_reg_context_sp.reset(); m_unwinder_up.reset(); @@ -536,7 +511,8 @@ bool Thread::CheckpointThreadState(ThreadStateCheckpoint &saved_state) { if (process_sp) saved_state.orig_stop_id = process_sp->GetStopID(); saved_state.current_inlined_depth = GetCurrentInlinedDepth(); - saved_state.m_completed_plan_stack = m_completed_plan_stack; + saved_state.m_completed_plan_checkpoint = + GetPlans().CheckpointCompletedPlans(); return true; } @@ -570,7 +546,8 @@ bool Thread::RestoreThreadStateFromCheckpoint( SetStopInfo(saved_state.stop_info_sp); GetStackFrameList()->SetCurrentInlinedDepth( saved_state.current_inlined_depth); - m_completed_plan_stack = saved_state.m_completed_plan_stack; + GetPlans().RestoreCompletedPlanCheckpoint( + saved_state.m_completed_plan_checkpoint); return true; } @@ -699,8 +676,7 @@ void Thread::SetupForResume() { bool Thread::ShouldResume(StateType resume_state) { // At this point clear the completed plan stack. - m_completed_plan_stack.clear(); - m_discarded_plan_stack.clear(); + GetPlans().WillResume(); m_override_should_notify = eLazyBoolCalculate; StateType prev_resume_state = GetTemporaryResumeState(); @@ -811,7 +787,9 @@ bool Thread::ShouldStop(Event *event_ptr) { LLDB_LOGF(log, "^^^^^^^^ Thread::ShouldStop Begin ^^^^^^^^"); StreamString s; s.IndentMore(); - DumpThreadPlans(&s); + GetProcess()->DumpThreadPlansForTID( + s, GetID(), eDescriptionLevelVerbose, true /* internal */, + false /* condense_trivial */, true /* skip_unreported */); LLDB_LOGF(log, "Plan stack initial state:\n%s", s.GetData()); } @@ -894,7 +872,7 @@ bool Thread::ShouldStop(Event *event_ptr) { current_plan->GetName(), over_ride_stop); // We're starting from the base plan, so just let it decide; - if (PlanIsBasePlan(current_plan)) { + if (current_plan->IsBasePlan()) { should_stop = current_plan->ShouldStop(event_ptr); LLDB_LOGF(log, "Base plan says should stop: %i.", should_stop); } else { @@ -902,7 +880,7 @@ bool Thread::ShouldStop(Event *event_ptr) { // to do, since presumably if there were other plans they would know what // to do... while (true) { - if (PlanIsBasePlan(current_plan)) + if (current_plan->IsBasePlan()) break; should_stop = current_plan->ShouldStop(event_ptr); @@ -948,7 +926,7 @@ bool Thread::ShouldStop(Event *event_ptr) { // Discard the stale plans and all plans below them in the stack, plus move // the completed plans to the completed plan stack - while (!PlanIsBasePlan(plan_ptr)) { + while (!plan_ptr->IsBasePlan()) { bool stale = plan_ptr->IsPlanStale(); ThreadPlan *examined_plan = plan_ptr; plan_ptr = GetPreviousPlan(examined_plan); @@ -975,7 +953,9 @@ bool Thread::ShouldStop(Event *event_ptr) { if (log) { StreamString s; s.IndentMore(); - DumpThreadPlans(&s); + GetProcess()->DumpThreadPlansForTID( + s, GetID(), eDescriptionLevelVerbose, true /* internal */, + false /* condense_trivial */, true /* skip_unreported */); LLDB_LOGF(log, "Plan stack final state:\n%s", s.GetData()); LLDB_LOGF(log, "vvvvvvvv Thread::ShouldStop End (returning %i) vvvvvvvv", should_stop); @@ -1014,13 +994,14 @@ Vote Thread::ShouldReportStop(Event *event_ptr) { return eVoteNoOpinion; } - if (m_completed_plan_stack.size() > 0) { - // Don't use GetCompletedPlan here, since that suppresses private plans. + if (GetPlans().AnyCompletedPlans()) { + // Pass skip_private = false to GetCompletedPlan, since we want to ask + // the last plan, regardless of whether it is private or not. LLDB_LOGF(log, "Thread::ShouldReportStop() tid = 0x%4.4" PRIx64 ": returning vote for complete stack's back plan", GetID()); - return m_completed_plan_stack.back()->ShouldReportStop(event_ptr); + return GetPlans().GetCompletedPlan(false)->ShouldReportStop(event_ptr); } else { Vote thread_vote = eVoteNoOpinion; ThreadPlan *plan_ptr = GetCurrentPlan(); @@ -1029,7 +1010,7 @@ Vote Thread::ShouldReportStop(Event *event_ptr) { thread_vote = plan_ptr->ShouldReportStop(event_ptr); break; } - if (PlanIsBasePlan(plan_ptr)) + if (plan_ptr->IsBasePlan()) break; else plan_ptr = GetPreviousPlan(plan_ptr); @@ -1051,16 +1032,17 @@ Vote Thread::ShouldReportRun(Event *event_ptr) { } Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_STEP)); - if (m_completed_plan_stack.size() > 0) { - // Don't use GetCompletedPlan here, since that suppresses private plans. + if (GetPlans().AnyCompletedPlans()) { + // Pass skip_private = false to GetCompletedPlan, since we want to ask + // the last plan, regardless of whether it is private or not. LLDB_LOGF(log, "Current Plan for thread %d(%p) (0x%4.4" PRIx64 ", %s): %s being asked whether we should report run.", GetIndexID(), static_cast(this), GetID(), StateAsCString(GetTemporaryResumeState()), - m_completed_plan_stack.back()->GetName()); + GetCompletedPlan()->GetName()); - return m_completed_plan_stack.back()->ShouldReportRun(event_ptr); + return GetPlans().GetCompletedPlan(false)->ShouldReportRun(event_ptr); } else { LLDB_LOGF(log, "Current Plan for thread %d(%p) (0x%4.4" PRIx64 @@ -1077,155 +1059,94 @@ bool Thread::MatchesSpec(const ThreadSpec *spec) { return (spec == nullptr) ? true : spec->ThreadPassesBasicTests(*this); } -void Thread::PushPlan(ThreadPlanSP &thread_plan_sp) { - if (thread_plan_sp) { - // If the thread plan doesn't already have a tracer, give it its parent's - // tracer: - if (!thread_plan_sp->GetThreadPlanTracer()) { - assert(!m_plan_stack.empty()); - thread_plan_sp->SetThreadPlanTracer( - m_plan_stack.back()->GetThreadPlanTracer()); - } - m_plan_stack.push_back(thread_plan_sp); +ThreadPlanStack &Thread::GetPlans() const { + ThreadPlanStack *plans = GetProcess()->FindThreadPlans(GetID()); + if (plans) + return *plans; - thread_plan_sp->DidPush(); + // History threads don't have a thread plan, but they do ask get asked to + // describe themselves, which usually involves pulling out the stop reason. + // That in turn will check for a completed plan on the ThreadPlanStack. + // Instead of special-casing at that point, we return a Stack with a + // ThreadPlanNull as its base plan. That will give the right answers to the + // queries GetDescription makes, and only assert if you try to run the thread. + if (!m_null_plan_stack_up) + m_null_plan_stack_up.reset(new ThreadPlanStack(*this, true)); + return *(m_null_plan_stack_up.get()); +} - Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_STEP)); - if (log) { - StreamString s; - thread_plan_sp->GetDescription(&s, lldb::eDescriptionLevelFull); - LLDB_LOGF(log, "Thread::PushPlan(0x%p): \"%s\", tid = 0x%4.4" PRIx64 ".", - static_cast(this), s.GetData(), - thread_plan_sp->GetThread().GetID()); - } +void Thread::PushPlan(ThreadPlanSP thread_plan_sp) { + assert(thread_plan_sp && "Don't push an empty thread plan."); + + Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_STEP)); + if (log) { + StreamString s; + thread_plan_sp->GetDescription(&s, lldb::eDescriptionLevelFull); + LLDB_LOGF(log, "Thread::PushPlan(0x%p): \"%s\", tid = 0x%4.4" PRIx64 ".", + static_cast(this), s.GetData(), + thread_plan_sp->GetThread().GetID()); } + + GetPlans().PushPlan(std::move(thread_plan_sp)); } void Thread::PopPlan() { Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_STEP)); - - if (m_plan_stack.size() <= 1) - return; - else { - ThreadPlanSP &plan = m_plan_stack.back(); - if (log) { - LLDB_LOGF(log, "Popping plan: \"%s\", tid = 0x%4.4" PRIx64 ".", - plan->GetName(), plan->GetThread().GetID()); - } - m_completed_plan_stack.push_back(plan); - plan->WillPop(); - m_plan_stack.pop_back(); + ThreadPlanSP popped_plan_sp = GetPlans().PopPlan(); + if (log) { + LLDB_LOGF(log, "Popping plan: \"%s\", tid = 0x%4.4" PRIx64 ".", + popped_plan_sp->GetName(), popped_plan_sp->GetThread().GetID()); } } void Thread::DiscardPlan() { Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_STEP)); - if (m_plan_stack.size() > 1) { - ThreadPlanSP &plan = m_plan_stack.back(); - LLDB_LOGF(log, "Discarding plan: \"%s\", tid = 0x%4.4" PRIx64 ".", - plan->GetName(), plan->GetThread().GetID()); - - m_discarded_plan_stack.push_back(plan); - plan->WillPop(); - m_plan_stack.pop_back(); - } -} + ThreadPlanSP discarded_plan_sp = GetPlans().PopPlan(); -ThreadPlan *Thread::GetCurrentPlan() { - // There will always be at least the base plan. If somebody is mucking with - // a thread with an empty plan stack, we should assert right away. - return m_plan_stack.empty() ? nullptr : m_plan_stack.back().get(); + LLDB_LOGF(log, "Discarding plan: \"%s\", tid = 0x%4.4" PRIx64 ".", + discarded_plan_sp->GetName(), + discarded_plan_sp->GetThread().GetID()); } -ThreadPlanSP Thread::GetCompletedPlan() { - ThreadPlanSP empty_plan_sp; - if (!m_completed_plan_stack.empty()) { - for (int i = m_completed_plan_stack.size() - 1; i >= 0; i--) { - ThreadPlanSP completed_plan_sp; - completed_plan_sp = m_completed_plan_stack[i]; - if (!completed_plan_sp->GetPrivate()) - return completed_plan_sp; - } - } - return empty_plan_sp; +ThreadPlan *Thread::GetCurrentPlan() const { + return GetPlans().GetCurrentPlan().get(); } ValueObjectSP Thread::GetReturnValueObject(bool *is_swift_error_value) { if (is_swift_error_value) *is_swift_error_value = false; - - if (!m_completed_plan_stack.empty()) { - for (int i = m_completed_plan_stack.size() - 1; i >= 0; i--) { - ValueObjectSP return_valobj_sp; - return_valobj_sp = m_completed_plan_stack[i]->GetReturnValueObject(); - if (return_valobj_sp) { - if (is_swift_error_value) - *is_swift_error_value = - m_completed_plan_stack[i]->IsReturnValueSwiftErrorValue(); - return return_valobj_sp; - } - } + + bool is_error; + ValueObjectSP return_valobj_sp = GetPlans().GetReturnValueObject(is_error); + if (return_valobj_sp) { + if (is_swift_error_value) + *is_swift_error_value = is_error; + return return_valobj_sp; } return ValueObjectSP(); } - -ExpressionVariableSP Thread::GetExpressionVariable() { - if (!m_completed_plan_stack.empty()) { - for (int i = m_completed_plan_stack.size() - 1; i >= 0; i--) { - ExpressionVariableSP expression_variable_sp; - expression_variable_sp = - m_completed_plan_stack[i]->GetExpressionVariable(); - if (expression_variable_sp) - return expression_variable_sp; - } - } - return ExpressionVariableSP(); +ThreadPlanSP Thread::GetCompletedPlan() const { + return GetPlans().GetCompletedPlan(); } -bool Thread::IsThreadPlanDone(ThreadPlan *plan) { - if (!m_completed_plan_stack.empty()) { - for (int i = m_completed_plan_stack.size() - 1; i >= 0; i--) { - if (m_completed_plan_stack[i].get() == plan) - return true; - } - } - return false; +ExpressionVariableSP Thread::GetExpressionVariable() const { + return GetPlans().GetExpressionVariable(); } -bool Thread::WasThreadPlanDiscarded(ThreadPlan *plan) { - if (!m_discarded_plan_stack.empty()) { - for (int i = m_discarded_plan_stack.size() - 1; i >= 0; i--) { - if (m_discarded_plan_stack[i].get() == plan) - return true; - } - } - return false; +bool Thread::IsThreadPlanDone(ThreadPlan *plan) const { + return GetPlans().IsPlanDone(plan); } -bool Thread::CompletedPlanOverridesBreakpoint() { - return (!m_completed_plan_stack.empty()) ; +bool Thread::WasThreadPlanDiscarded(ThreadPlan *plan) const { + return GetPlans().WasPlanDiscarded(plan); } -ThreadPlan *Thread::GetPreviousPlan(ThreadPlan *current_plan) { - if (current_plan == nullptr) - return nullptr; - - int stack_size = m_completed_plan_stack.size(); - for (int i = stack_size - 1; i > 0; i--) { - if (current_plan == m_completed_plan_stack[i].get()) - return m_completed_plan_stack[i - 1].get(); - } - - if (stack_size > 0 && m_completed_plan_stack[0].get() == current_plan) { - return GetCurrentPlan(); - } +bool Thread::CompletedPlanOverridesBreakpoint() const { + return GetPlans().AnyCompletedPlans(); +} - stack_size = m_plan_stack.size(); - for (int i = stack_size - 1; i > 0; i--) { - if (current_plan == m_plan_stack[i].get()) - return m_plan_stack[i - 1].get(); - } - return nullptr; +ThreadPlan *Thread::GetPreviousPlan(ThreadPlan *current_plan) const{ + return GetPlans().GetPreviousPlan(current_plan); } Status Thread::QueueThreadPlan(ThreadPlanSP &thread_plan_sp, @@ -1259,38 +1180,18 @@ Status Thread::QueueThreadPlan(ThreadPlanSP &thread_plan_sp, } void Thread::EnableTracer(bool value, bool single_stepping) { - int stack_size = m_plan_stack.size(); - for (int i = 0; i < stack_size; i++) { - if (m_plan_stack[i]->GetThreadPlanTracer()) { - m_plan_stack[i]->GetThreadPlanTracer()->EnableTracing(value); - m_plan_stack[i]->GetThreadPlanTracer()->EnableSingleStep(single_stepping); - } - } + GetPlans().EnableTracer(value, single_stepping); } void Thread::SetTracer(lldb::ThreadPlanTracerSP &tracer_sp) { - int stack_size = m_plan_stack.size(); - for (int i = 0; i < stack_size; i++) - m_plan_stack[i]->SetThreadPlanTracer(tracer_sp); + GetPlans().SetTracer(tracer_sp); } -bool Thread::DiscardUserThreadPlansUpToIndex(uint32_t thread_index) { +bool Thread::DiscardUserThreadPlansUpToIndex(uint32_t plan_index) { // Count the user thread plans from the back end to get the number of the one // we want to discard: - uint32_t idx = 0; - ThreadPlan *up_to_plan_ptr = nullptr; - - for (ThreadPlanSP plan_sp : m_plan_stack) { - if (plan_sp->GetPrivate()) - continue; - if (idx == thread_index) { - up_to_plan_ptr = plan_sp.get(); - break; - } else - idx++; - } - + ThreadPlan *up_to_plan_ptr = GetPlans().GetPlanByIndex(plan_index).get(); if (up_to_plan_ptr == nullptr) return false; @@ -1308,30 +1209,7 @@ void Thread::DiscardThreadPlansUpToPlan(ThreadPlan *up_to_plan_ptr) { "Discarding thread plans for thread tid = 0x%4.4" PRIx64 ", up to %p", GetID(), static_cast(up_to_plan_ptr)); - - int stack_size = m_plan_stack.size(); - - // If the input plan is nullptr, discard all plans. Otherwise make sure this - // plan is in the stack, and if so discard up to and including it. - - if (up_to_plan_ptr == nullptr) { - for (int i = stack_size - 1; i > 0; i--) - DiscardPlan(); - } else { - bool found_it = false; - for (int i = stack_size - 1; i > 0; i--) { - if (m_plan_stack[i].get() == up_to_plan_ptr) - found_it = true; - } - if (found_it) { - bool last_one = false; - for (int i = stack_size - 1; i > 0 && !last_one; i--) { - if (GetCurrentPlan() == up_to_plan_ptr) - last_one = true; - DiscardPlan(); - } - } - } + GetPlans().DiscardPlansUpToPlan(up_to_plan_ptr); } void Thread::DiscardThreadPlans(bool force) { @@ -1344,73 +1222,20 @@ void Thread::DiscardThreadPlans(bool force) { } if (force) { - int stack_size = m_plan_stack.size(); - for (int i = stack_size - 1; i > 0; i--) { - DiscardPlan(); - } + GetPlans().DiscardAllPlans(); return; } - - while (true) { - int master_plan_idx; - bool discard = true; - - // Find the first master plan, see if it wants discarding, and if yes - // discard up to it. - for (master_plan_idx = m_plan_stack.size() - 1; master_plan_idx >= 0; - master_plan_idx--) { - if (m_plan_stack[master_plan_idx]->IsMasterPlan()) { - discard = m_plan_stack[master_plan_idx]->OkayToDiscard(); - break; - } - } - - if (discard) { - // First pop all the dependent plans: - for (int i = m_plan_stack.size() - 1; i > master_plan_idx; i--) { - // FIXME: Do we need a finalize here, or is the rule that - // "PrepareForStop" - // for the plan leaves it in a state that it is safe to pop the plan - // with no more notice? - DiscardPlan(); - } - - // Now discard the master plan itself. - // The bottom-most plan never gets discarded. "OkayToDiscard" for it - // means discard it's dependent plans, but not it... - if (master_plan_idx > 0) { - DiscardPlan(); - } - } else { - // If the master plan doesn't want to get discarded, then we're done. - break; - } - } -} - -bool Thread::PlanIsBasePlan(ThreadPlan *plan_ptr) { - if (plan_ptr->IsBasePlan()) - return true; - else if (m_plan_stack.size() == 0) - return false; - else - return m_plan_stack[0].get() == plan_ptr; + GetPlans().DiscardConsultingMasterPlans(); } Status Thread::UnwindInnermostExpression() { Status error; - int stack_size = m_plan_stack.size(); - - // If the input plan is nullptr, discard all plans. Otherwise make sure this - // plan is in the stack, and if so discard up to and including it. - - for (int i = stack_size - 1; i > 0; i--) { - if (m_plan_stack[i]->GetKind() == ThreadPlan::eKindCallFunction) { - DiscardThreadPlansUpToPlan(m_plan_stack[i].get()); - return error; - } - } - error.SetErrorString("No expressions currently active on this thread"); + ThreadPlan *innermost_expr_plan = GetPlans().GetInnermostExpression(); + if (!innermost_expr_plan) { + error.SetErrorString("No expressions currently active on this thread"); + return error; + } + DiscardThreadPlansUpToPlan(innermost_expr_plan); return error; } @@ -1598,73 +1423,6 @@ lldb::ThreadPlanSP Thread::QueueThreadPlanForStepScripted( uint32_t Thread::GetIndexID() const { return m_index_id; } -static void PrintPlanElement(Stream *s, const ThreadPlanSP &plan, - lldb::DescriptionLevel desc_level, - int32_t elem_idx) { - s->IndentMore(); - s->Indent(); - s->Printf("Element %d: ", elem_idx); - plan->GetDescription(s, desc_level); - s->EOL(); - s->IndentLess(); -} - -static void PrintPlanStack(Stream *s, - const std::vector &plan_stack, - lldb::DescriptionLevel desc_level, - bool include_internal) { - int32_t print_idx = 0; - for (ThreadPlanSP plan_sp : plan_stack) { - if (include_internal || !plan_sp->GetPrivate()) { - PrintPlanElement(s, plan_sp, desc_level, print_idx++); - } - } -} - -void Thread::DumpThreadPlans(Stream *s, lldb::DescriptionLevel desc_level, - bool include_internal, - bool ignore_boring_threads) const { - uint32_t stack_size; - - if (ignore_boring_threads) { - uint32_t stack_size = m_plan_stack.size(); - uint32_t completed_stack_size = m_completed_plan_stack.size(); - uint32_t discarded_stack_size = m_discarded_plan_stack.size(); - if (stack_size == 1 && completed_stack_size == 0 && - discarded_stack_size == 0) { - s->Printf("thread #%u: tid = 0x%4.4" PRIx64 "\n", GetIndexID(), GetID()); - s->IndentMore(); - s->Indent(); - s->Printf("No active thread plans\n"); - s->IndentLess(); - return; - } - } - - s->Indent(); - s->Printf("thread #%u: tid = 0x%4.4" PRIx64 ":\n", GetIndexID(), GetID()); - s->IndentMore(); - s->Indent(); - s->Printf("Active plan stack:\n"); - PrintPlanStack(s, m_plan_stack, desc_level, include_internal); - - stack_size = m_completed_plan_stack.size(); - if (stack_size > 0) { - s->Indent(); - s->Printf("Completed Plan Stack:\n"); - PrintPlanStack(s, m_completed_plan_stack, desc_level, include_internal); - } - - stack_size = m_discarded_plan_stack.size(); - if (stack_size > 0) { - s->Indent(); - s->Printf("Discarded Plan Stack:\n"); - PrintPlanStack(s, m_discarded_plan_stack, desc_level, include_internal); - } - - s->IndentLess(); -} - TargetSP Thread::CalculateTarget() { TargetSP target_sp; ProcessSP process_sp(GetProcess()); diff --git a/lldb/source/Target/ThreadList.cpp b/lldb/source/Target/ThreadList.cpp index 183b39c2cfa9b..efdea45f81444 100644 --- a/lldb/source/Target/ThreadList.cpp +++ b/lldb/source/Target/ThreadList.cpp @@ -715,6 +715,11 @@ void ThreadList::Update(ThreadList &rhs) { // to work around the issue collection::iterator rhs_pos, rhs_end = rhs.m_threads.end(); for (rhs_pos = rhs.m_threads.begin(); rhs_pos != rhs_end; ++rhs_pos) { + // If this thread has already been destroyed, we don't need to look for + // it to destroy it again. + if (!(*rhs_pos)->IsValid()) + continue; + const lldb::tid_t tid = (*rhs_pos)->GetID(); bool thread_is_alive = false; const uint32_t num_threads = m_threads.size(); @@ -726,8 +731,9 @@ void ThreadList::Update(ThreadList &rhs) { break; } } - if (!thread_is_alive) + if (!thread_is_alive) { (*rhs_pos)->DestroyThread(); + } } } } diff --git a/lldb/source/Target/ThreadPlan.cpp b/lldb/source/Target/ThreadPlan.cpp index ba56f8d15d8a9..76dcc63f65783 100644 --- a/lldb/source/Target/ThreadPlan.cpp +++ b/lldb/source/Target/ThreadPlan.cpp @@ -21,9 +21,10 @@ using namespace lldb_private; // ThreadPlan constructor ThreadPlan::ThreadPlan(ThreadPlanKind kind, const char *name, Thread &thread, Vote stop_vote, Vote run_vote) - : m_thread(thread), m_stop_vote(stop_vote), m_run_vote(run_vote), + : m_process(*thread.GetProcess().get()), m_tid(thread.GetID()), + m_stop_vote(stop_vote), m_run_vote(run_vote), m_takes_iteration_count(false), m_could_not_resolve_hw_bp(false), - m_kind(kind), m_name(name), m_plan_complete_mutex(), + m_thread(&thread), m_kind(kind), m_name(name), m_plan_complete_mutex(), m_cached_plan_explains_stop(eLazyBoolCalculate), m_plan_complete(false), m_plan_private(false), m_okay_to_discard(true), m_is_master_plan(false), m_plan_succeeded(true) { @@ -33,6 +34,19 @@ ThreadPlan::ThreadPlan(ThreadPlanKind kind, const char *name, Thread &thread, // Destructor ThreadPlan::~ThreadPlan() = default; +Target &ThreadPlan::GetTarget() { return m_process.GetTarget(); } + +const Target &ThreadPlan::GetTarget() const { return m_process.GetTarget(); } + +Thread &ThreadPlan::GetThread() { + if (m_thread) + return *m_thread; + + ThreadSP thread_sp = m_process.GetThreadList().FindThreadByID(m_tid); + m_thread = thread_sp.get(); + return *m_thread; +} + bool ThreadPlan::PlanExplainsStop(Event *event_ptr) { if (m_cached_plan_explains_stop == eLazyBoolCalculate) { bool actual_value = DoPlanExplainsStop(event_ptr); @@ -103,7 +117,7 @@ bool ThreadPlan::WillResume(StateType resume_state, bool current_plan) { Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_STEP)); if (log) { - RegisterContext *reg_ctx = m_thread.GetRegisterContext().get(); + RegisterContext *reg_ctx = GetThread().GetRegisterContext().get(); assert(reg_ctx); addr_t pc = reg_ctx->GetPC(); addr_t sp = reg_ctx->GetSP(); @@ -113,13 +127,17 @@ bool ThreadPlan::WillResume(StateType resume_state, bool current_plan) { "%s Thread #%u (0x%p): tid = 0x%4.4" PRIx64 ", pc = 0x%8.8" PRIx64 ", sp = 0x%8.8" PRIx64 ", fp = 0x%8.8" PRIx64 ", " "plan = '%s', state = %s, stop others = %d", - __FUNCTION__, m_thread.GetIndexID(), static_cast(&m_thread), - m_thread.GetID(), static_cast(pc), + __FUNCTION__, GetThread().GetIndexID(), + static_cast(&GetThread()), m_tid, static_cast(pc), static_cast(sp), static_cast(fp), m_name.c_str(), StateAsCString(resume_state), StopOthers()); } } - return DoWillResume(resume_state, current_plan); + bool success = DoWillResume(resume_state, current_plan); + m_thread = nullptr; // We don't cache the thread pointer over resumes. This + // Thread might go away, and another Thread represent + // the same underlying object on a later stop. + return success; } lldb::user_id_t ThreadPlan::GetNextID() { @@ -174,14 +192,13 @@ bool ThreadPlanNull::ValidatePlan(Stream *error) { fprintf(stderr, "error: %s called on thread that has been destroyed (tid = 0x%" PRIx64 ", ptid = 0x%" PRIx64 ")", - LLVM_PRETTY_FUNCTION, m_thread.GetID(), m_thread.GetProtocolID()); + LLVM_PRETTY_FUNCTION, m_tid, GetThread().GetProtocolID()); #else Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_THREAD)); if (log) log->Error("%s called on thread that has been destroyed (tid = 0x%" PRIx64 ", ptid = 0x%" PRIx64 ")", - LLVM_PRETTY_FUNCTION, m_thread.GetID(), - m_thread.GetProtocolID()); + LLVM_PRETTY_FUNCTION, m_tid, GetThread().GetProtocolID()); #endif return true; } @@ -191,14 +208,13 @@ bool ThreadPlanNull::ShouldStop(Event *event_ptr) { fprintf(stderr, "error: %s called on thread that has been destroyed (tid = 0x%" PRIx64 ", ptid = 0x%" PRIx64 ")", - LLVM_PRETTY_FUNCTION, m_thread.GetID(), m_thread.GetProtocolID()); + LLVM_PRETTY_FUNCTION, m_tid, GetThread().GetProtocolID()); #else Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_THREAD)); if (log) log->Error("%s called on thread that has been destroyed (tid = 0x%" PRIx64 ", ptid = 0x%" PRIx64 ")", - LLVM_PRETTY_FUNCTION, m_thread.GetID(), - m_thread.GetProtocolID()); + LLVM_PRETTY_FUNCTION, m_tid, GetThread().GetProtocolID()); #endif return true; } @@ -208,14 +224,13 @@ bool ThreadPlanNull::WillStop() { fprintf(stderr, "error: %s called on thread that has been destroyed (tid = 0x%" PRIx64 ", ptid = 0x%" PRIx64 ")", - LLVM_PRETTY_FUNCTION, m_thread.GetID(), m_thread.GetProtocolID()); + LLVM_PRETTY_FUNCTION, m_tid, GetThread().GetProtocolID()); #else Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_THREAD)); if (log) log->Error("%s called on thread that has been destroyed (tid = 0x%" PRIx64 ", ptid = 0x%" PRIx64 ")", - LLVM_PRETTY_FUNCTION, m_thread.GetID(), - m_thread.GetProtocolID()); + LLVM_PRETTY_FUNCTION, m_tid, GetThread().GetProtocolID()); #endif return true; } @@ -225,14 +240,13 @@ bool ThreadPlanNull::DoPlanExplainsStop(Event *event_ptr) { fprintf(stderr, "error: %s called on thread that has been destroyed (tid = 0x%" PRIx64 ", ptid = 0x%" PRIx64 ")", - LLVM_PRETTY_FUNCTION, m_thread.GetID(), m_thread.GetProtocolID()); + LLVM_PRETTY_FUNCTION, GetThread().GetID(), GetThread().GetProtocolID()); #else Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_THREAD)); if (log) log->Error("%s called on thread that has been destroyed (tid = 0x%" PRIx64 ", ptid = 0x%" PRIx64 ")", - LLVM_PRETTY_FUNCTION, m_thread.GetID(), - m_thread.GetProtocolID()); + LLVM_PRETTY_FUNCTION, m_tid, GetThread().GetProtocolID()); #endif return true; } @@ -244,14 +258,13 @@ bool ThreadPlanNull::MischiefManaged() { fprintf(stderr, "error: %s called on thread that has been destroyed (tid = 0x%" PRIx64 ", ptid = 0x%" PRIx64 ")", - LLVM_PRETTY_FUNCTION, m_thread.GetID(), m_thread.GetProtocolID()); + LLVM_PRETTY_FUNCTION, m_tid, GetThread().GetProtocolID()); #else Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_THREAD)); if (log) log->Error("%s called on thread that has been destroyed (tid = 0x%" PRIx64 ", ptid = 0x%" PRIx64 ")", - LLVM_PRETTY_FUNCTION, m_thread.GetID(), - m_thread.GetProtocolID()); + LLVM_PRETTY_FUNCTION, m_tid, GetThread().GetProtocolID()); #endif return false; } @@ -262,14 +275,13 @@ lldb::StateType ThreadPlanNull::GetPlanRunState() { fprintf(stderr, "error: %s called on thread that has been destroyed (tid = 0x%" PRIx64 ", ptid = 0x%" PRIx64 ")", - LLVM_PRETTY_FUNCTION, m_thread.GetID(), m_thread.GetProtocolID()); + LLVM_PRETTY_FUNCTION, m_tid, GetThread().GetProtocolID()); #else Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_THREAD)); if (log) log->Error("%s called on thread that has been destroyed (tid = 0x%" PRIx64 ", ptid = 0x%" PRIx64 ")", - LLVM_PRETTY_FUNCTION, m_thread.GetID(), - m_thread.GetProtocolID()); + LLVM_PRETTY_FUNCTION, m_tid, GetThread().GetProtocolID()); #endif return eStateRunning; } diff --git a/lldb/source/Target/ThreadPlanBase.cpp b/lldb/source/Target/ThreadPlanBase.cpp index 821643d4bce51..40b002e7262c2 100644 --- a/lldb/source/Target/ThreadPlanBase.cpp +++ b/lldb/source/Target/ThreadPlanBase.cpp @@ -34,11 +34,11 @@ ThreadPlanBase::ThreadPlanBase(Thread &thread) #define THREAD_PLAN_USE_ASSEMBLY_TRACER 1 #ifdef THREAD_PLAN_USE_ASSEMBLY_TRACER - ThreadPlanTracerSP new_tracer_sp(new ThreadPlanAssemblyTracer(m_thread)); + ThreadPlanTracerSP new_tracer_sp(new ThreadPlanAssemblyTracer(thread)); #else ThreadPlanTracerSP new_tracer_sp(new ThreadPlanTracer(m_thread)); #endif - new_tracer_sp->EnableTracing(m_thread.GetTraceEnabledState()); + new_tracer_sp->EnableTracing(thread.GetTraceEnabledState()); SetThreadPlanTracer(new_tracer_sp); SetIsMasterPlan(true); } @@ -58,7 +58,7 @@ bool ThreadPlanBase::DoPlanExplainsStop(Event *event_ptr) { } Vote ThreadPlanBase::ShouldReportStop(Event *event_ptr) { - StopInfoSP stop_info_sp = m_thread.GetStopInfo(); + StopInfoSP stop_info_sp = GetThread().GetStopInfo(); if (stop_info_sp) { bool should_notify = stop_info_sp->ShouldNotify(event_ptr); if (should_notify) @@ -96,8 +96,8 @@ bool ThreadPlanBase::ShouldStop(Event *event_ptr) { log, "Base plan discarding thread plans for thread tid = 0x%4.4" PRIx64 " (breakpoint hit.)", - m_thread.GetID()); - m_thread.DiscardThreadPlans(false); + m_tid); + GetThread().DiscardThreadPlans(false); return true; } // If we aren't going to stop at this breakpoint, and it is internal, @@ -125,9 +125,9 @@ bool ThreadPlanBase::ShouldStop(Event *event_ptr) { LLDB_LOGF( log, "Base plan discarding thread plans for thread tid = 0x%4.4" PRIx64 - " (exception: %s)", - m_thread.GetID(), stop_info_sp->GetDescription()); - m_thread.DiscardThreadPlans(false); + " (exception: %s)", + m_tid, stop_info_sp->GetDescription()); + GetThread().DiscardThreadPlans(false); return true; case eStopReasonExec: @@ -138,8 +138,8 @@ bool ThreadPlanBase::ShouldStop(Event *event_ptr) { log, "Base plan discarding thread plans for thread tid = 0x%4.4" PRIx64 " (exec.)", - m_thread.GetID()); - m_thread.DiscardThreadPlans(false); + m_tid); + GetThread().DiscardThreadPlans(false); return true; case eStopReasonThreadExiting: @@ -148,9 +148,9 @@ bool ThreadPlanBase::ShouldStop(Event *event_ptr) { LLDB_LOGF( log, "Base plan discarding thread plans for thread tid = 0x%4.4" PRIx64 - " (signal: %s)", - m_thread.GetID(), stop_info_sp->GetDescription()); - m_thread.DiscardThreadPlans(false); + " (signal: %s)", + m_tid, stop_info_sp->GetDescription()); + GetThread().DiscardThreadPlans(false); return true; } else { // We're not going to stop, but while we are here, let's figure out diff --git a/lldb/source/Target/ThreadPlanCallFunction.cpp b/lldb/source/Target/ThreadPlanCallFunction.cpp index bfe7f1ba6223b..49d4ed9ee9c70 100644 --- a/lldb/source/Target/ThreadPlanCallFunction.cpp +++ b/lldb/source/Target/ThreadPlanCallFunction.cpp @@ -13,6 +13,7 @@ #include "lldb/Core/DumpRegisterValue.h" #include "lldb/Core/Module.h" #include "lldb/Symbol/ObjectFile.h" +#include "lldb/Symbol/SwiftASTContext.h" #include "lldb/Target/ABI.h" #include "lldb/Target/LanguageRuntime.h" #include "lldb/Target/Process.h" @@ -149,7 +150,7 @@ void ThreadPlanCallFunction::ReportRegisterState(const char *message) { Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_STEP)); if (log && log->GetVerbose()) { StreamString strm; - RegisterContext *reg_ctx = m_thread.GetRegisterContext().get(); + RegisterContext *reg_ctx = GetThread().GetRegisterContext().get(); log->PutCString(message); @@ -181,19 +182,19 @@ void ThreadPlanCallFunction::DoTakedown(bool success) { } if (!m_takedown_done) { + Thread &thread = GetThread(); if (success) { SetReturnValue(); } LLDB_LOGF(log, "ThreadPlanCallFunction(%p): DoTakedown called for thread " "0x%4.4" PRIx64 ", m_valid: %d complete: %d.\n", - static_cast(this), m_thread.GetID(), m_valid, - IsPlanComplete()); + static_cast(this), m_tid, m_valid, IsPlanComplete()); m_takedown_done = true; m_stop_address = - m_thread.GetStackFrameAtIndex(0)->GetRegisterContext()->GetPC(); + thread.GetStackFrameAtIndex(0)->GetRegisterContext()->GetPC(); m_real_stop_info_sp = GetPrivateStopInfo(); - if (!m_thread.RestoreRegisterStateFromCheckpoint(m_stored_thread_state)) { + if (!thread.RestoreRegisterStateFromCheckpoint(m_stored_thread_state)) { LLDB_LOGF(log, "ThreadPlanCallFunction(%p): DoTakedown failed to restore " "register state", @@ -208,8 +209,7 @@ void ThreadPlanCallFunction::DoTakedown(bool success) { LLDB_LOGF(log, "ThreadPlanCallFunction(%p): DoTakedown called as no-op for " "thread 0x%4.4" PRIx64 ", m_valid: %d complete: %d.\n", - static_cast(this), m_thread.GetID(), m_valid, - IsPlanComplete()); + static_cast(this), m_tid, m_valid, IsPlanComplete()); } } @@ -219,9 +219,8 @@ void ThreadPlanCallFunction::GetDescription(Stream *s, DescriptionLevel level) { if (level == eDescriptionLevelBrief) { s->Printf("Function call thread plan"); } else { - TargetSP target_sp(m_thread.CalculateTarget()); s->Printf("Thread plan to call 0x%" PRIx64, - m_function_addr.GetLoadAddress(target_sp.get())); + m_function_addr.GetLoadAddress(&GetTarget())); } } @@ -286,11 +285,9 @@ bool ThreadPlanCallFunction::DoPlanExplainsStop(Event *event_ptr) { // m_ignore_breakpoints. if (stop_reason == eStopReasonBreakpoint) { - ProcessSP process_sp(m_thread.CalculateProcess()); uint64_t break_site_id = m_real_stop_info_sp->GetValue(); BreakpointSiteSP bp_site_sp; - if (process_sp) - bp_site_sp = process_sp->GetBreakpointSiteList().FindByID(break_site_id); + bp_site_sp = m_process.GetBreakpointSiteList().FindByID(break_site_id); if (bp_site_sp) { uint32_t num_owners = bp_site_sp->GetNumberOfOwners(); bool is_internal = true; @@ -378,10 +375,11 @@ void ThreadPlanCallFunction::DidPush() { GetThread().SetStopInfoToNothing(); #ifndef SINGLE_STEP_EXPRESSIONS - m_subplan_sp = std::make_shared( - m_thread, m_start_addr, m_stop_other_threads); + Thread &thread = GetThread(); + m_subplan_sp = std::make_shared(thread, m_start_addr, + m_stop_other_threads); - m_thread.QueueThreadPlan(m_subplan_sp, false); + thread.QueueThreadPlan(m_subplan_sp, false); m_subplan_sp->SetPrivate(true); #endif } @@ -403,41 +401,38 @@ bool ThreadPlanCallFunction::MischiefManaged() { } void ThreadPlanCallFunction::SetBreakpoints() { - ProcessSP process_sp(m_thread.CalculateProcess()); - if (process_sp) { - if (m_trap_exceptions) { - m_cxx_language_runtime = - process_sp->GetLanguageRuntime(eLanguageTypeC_plus_plus); - m_objc_language_runtime = - process_sp->GetLanguageRuntime(eLanguageTypeObjC); - - if (m_cxx_language_runtime) { - m_should_clear_cxx_exception_bp = - !m_cxx_language_runtime->ExceptionBreakpointsAreSet(); - m_cxx_language_runtime->SetExceptionBreakpoints(); - } - if (m_objc_language_runtime) { - m_should_clear_objc_exception_bp = - !m_objc_language_runtime->ExceptionBreakpointsAreSet(); - m_objc_language_runtime->SetExceptionBreakpoints(); - } + if (m_trap_exceptions) { + m_cxx_language_runtime = + m_process.GetLanguageRuntime(eLanguageTypeC_plus_plus); + m_objc_language_runtime = m_process.GetLanguageRuntime(eLanguageTypeObjC); + + if (m_cxx_language_runtime) { + m_should_clear_cxx_exception_bp = + !m_cxx_language_runtime->ExceptionBreakpointsAreSet(); + m_cxx_language_runtime->SetExceptionBreakpoints(); } - if (GetExpressionLanguage() == eLanguageTypeSwift) { - auto *swift_runtime = SwiftLanguageRuntime::Get(process_sp); - if (swift_runtime) { - llvm::StringRef backstop_name = swift_runtime->GetErrorBackstopName(); - if (!backstop_name.empty()) { - FileSpecList stdlib_module_list; - stdlib_module_list.Append( - FileSpec(swift_runtime->GetStandardLibraryName().GetStringRef())); - const LazyBool skip_prologue = eLazyBoolNo; - const bool is_internal = true; - const bool is_hardware = false; - m_error_backstop_bp_sp = process_sp->GetTarget().CreateBreakpoint( - &stdlib_module_list, NULL, backstop_name.str().c_str(), - eFunctionNameTypeFull, eLanguageTypeUnknown, 0, skip_prologue, - is_internal, is_hardware); - } + if (m_objc_language_runtime) { + m_should_clear_objc_exception_bp = + !m_objc_language_runtime->ExceptionBreakpointsAreSet(); + m_objc_language_runtime->SetExceptionBreakpoints(); + } + } + if (GetExpressionLanguage() == eLanguageTypeSwift) { + auto *swift_runtime + = SwiftLanguageRuntime::Get(m_process.shared_from_this()); + if (swift_runtime) { + llvm::StringRef backstop_name = swift_runtime->GetErrorBackstopName(); + if (!backstop_name.empty()) { + FileSpecList stdlib_module_list; + stdlib_module_list.Append( + FileSpec(swift_runtime->GetStandardLibraryName().GetStringRef())); + const LazyBool skip_prologue = eLazyBoolNo; + const bool is_internal = true; + const bool is_hardware = false; + m_error_backstop_bp_sp = m_process.GetTarget().CreateBreakpoint( + &stdlib_module_list, NULL, backstop_name.str().c_str(), + eFunctionNameTypeFull, eLanguageTypeUnknown, 0, skip_prologue, + is_internal, is_hardware); } } } @@ -482,45 +477,42 @@ bool ThreadPlanCallFunction::BreakpointsExplainStop() { } } if (m_error_backstop_bp_sp) { - ProcessSP process_sp(m_thread.CalculateProcess()); - if (process_sp) { - uint64_t break_site_id = stop_info_sp->GetValue(); - if (process_sp->GetBreakpointSiteList().BreakpointSiteContainsBreakpoint( - break_site_id, m_error_backstop_bp_sp->GetID())) { - // Our expression threw an uncaught exception. That will happen in REPL - // & Playground, though not in - // the regular expression parser. In that case, we should fetch the - // actual return value from the - // argument passed to this function, and set that as the return value. - SetPlanComplete(true); - StackFrameSP frame_sp = m_thread.GetStackFrameAtIndex(0); - PersistentExpressionState *persistent_state = - GetTarget().GetPersistentExpressionStateForLanguage( - eLanguageTypeSwift); - const bool is_error = true; - auto prefix = persistent_state->GetPersistentVariablePrefix(is_error); - ConstString persistent_variable_name( - persistent_state->GetNextPersistentVariableName(GetTarget(), - prefix)); - if (m_return_valobj_sp = SwiftLanguageRuntime::CalculateErrorValue( - frame_sp, persistent_variable_name)) { - - DataExtractor data; - Status data_error; - uint64_t data_size = - m_return_valobj_sp->GetStaticValue()->GetData(data, data_error); - - if (data_size == data.GetAddressByteSize()) { - lldb::offset_t offset = 0; - lldb::addr_t addr = data.GetAddress(&offset); - - SwiftLanguageRuntime::RegisterGlobalError( - GetTarget(), persistent_variable_name, addr); - } - - m_hit_error_backstop = true; - return true; + uint64_t break_site_id = stop_info_sp->GetValue(); + if (m_process.GetBreakpointSiteList().BreakpointSiteContainsBreakpoint( + break_site_id, m_error_backstop_bp_sp->GetID())) { + // Our expression threw an uncaught exception. That will happen in REPL + // & Playground, though not in + // the regular expression parser. In that case, we should fetch the + // actual return value from the + // argument passed to this function, and set that as the return value. + SetPlanComplete(true); + StackFrameSP frame_sp = GetThread().GetStackFrameAtIndex(0); + PersistentExpressionState *persistent_state = + GetTarget().GetPersistentExpressionStateForLanguage( + eLanguageTypeSwift); + const bool is_error = true; + auto prefix = persistent_state->GetPersistentVariablePrefix(is_error); + ConstString persistent_variable_name( + persistent_state->GetNextPersistentVariableName(GetTarget(), + prefix)); + if (m_return_valobj_sp = SwiftLanguageRuntime::CalculateErrorValue( + frame_sp, persistent_variable_name)) { + + DataExtractor data; + Status data_error; + uint64_t data_size = + m_return_valobj_sp->GetStaticValue()->GetData(data, data_error); + + if (data_size == data.GetAddressByteSize()) { + lldb::offset_t offset = 0; + lldb::addr_t addr = data.GetAddress(&offset); + + SwiftLanguageRuntime::RegisterGlobalError( + GetTarget(), persistent_variable_name, addr); } + + m_hit_error_backstop = true; + return true; } } } @@ -537,11 +529,10 @@ bool ThreadPlanCallFunction::RestoreThreadState() { } void ThreadPlanCallFunction::SetReturnValue() { - ProcessSP process_sp(m_thread.GetProcess()); - const ABI *abi = process_sp ? process_sp->GetABI().get() : nullptr; + const ABI *abi = m_process.GetABI().get(); if (abi && m_return_type.IsValid()) { const bool persistent = false; m_return_valobj_sp = - abi->GetReturnValueObject(m_thread, m_return_type, persistent); + abi->GetReturnValueObject(GetThread(), m_return_type, persistent); } } diff --git a/lldb/source/Target/ThreadPlanCallFunctionUsingABI.cpp b/lldb/source/Target/ThreadPlanCallFunctionUsingABI.cpp index 3155e6f7965f9..1eb409a590c26 100644 --- a/lldb/source/Target/ThreadPlanCallFunctionUsingABI.cpp +++ b/lldb/source/Target/ThreadPlanCallFunctionUsingABI.cpp @@ -49,20 +49,18 @@ void ThreadPlanCallFunctionUsingABI::GetDescription(Stream *s, if (level == eDescriptionLevelBrief) { s->Printf("Function call thread plan using ABI instead of JIT"); } else { - TargetSP target_sp(m_thread.CalculateTarget()); s->Printf("Thread plan to call 0x%" PRIx64 " using ABI instead of JIT", - m_function_addr.GetLoadAddress(target_sp.get())); + m_function_addr.GetLoadAddress(&GetTarget())); } } void ThreadPlanCallFunctionUsingABI::SetReturnValue() { - ProcessSP process_sp(m_thread.GetProcess()); - const ABI *abi = process_sp ? process_sp->GetABI().get() : nullptr; + const ABI *abi = m_process.GetABI().get(); // Ask the abi for the return value if (abi) { const bool persistent = false; m_return_valobj_sp = - abi->GetReturnValueObject(m_thread, m_return_type, persistent); + abi->GetReturnValueObject(GetThread(), m_return_type, persistent); } } diff --git a/lldb/source/Target/ThreadPlanCallUserExpression.cpp b/lldb/source/Target/ThreadPlanCallUserExpression.cpp index 436938c8f207c..fdb329920483a 100644 --- a/lldb/source/Target/ThreadPlanCallUserExpression.cpp +++ b/lldb/source/Target/ThreadPlanCallUserExpression.cpp @@ -101,8 +101,7 @@ StopInfoSP ThreadPlanCallUserExpression::GetRealStopInfo() { if (stop_info_sp) { lldb::addr_t addr = GetStopAddress(); - DynamicCheckerFunctions *checkers = - m_thread.GetProcess()->GetDynamicCheckers(); + DynamicCheckerFunctions *checkers = m_process.GetDynamicCheckers(); StreamString s; if (checkers && checkers->DoCheckersExplainStop(addr, s)) diff --git a/lldb/source/Target/ThreadPlanPython.cpp b/lldb/source/Target/ThreadPlanPython.cpp index df432a0af3dae..a432511bc7a2c 100644 --- a/lldb/source/Target/ThreadPlanPython.cpp +++ b/lldb/source/Target/ThreadPlanPython.cpp @@ -55,15 +55,16 @@ bool ThreadPlanPython::ValidatePlan(Stream *error) { return true; } +ScriptInterpreter *ThreadPlanPython::GetScriptInterpreter() { + return m_process.GetTarget().GetDebugger().GetScriptInterpreter(); +} + void ThreadPlanPython::DidPush() { // We set up the script side in DidPush, so that it can push other plans in // the constructor, and doesn't have to care about the details of DidPush. m_did_push = true; if (!m_class_name.empty()) { - ScriptInterpreter *script_interp = m_thread.GetProcess() - ->GetTarget() - .GetDebugger() - .GetScriptInterpreter(); + ScriptInterpreter *script_interp = GetScriptInterpreter(); if (script_interp) { m_implementation_sp = script_interp->CreateScriptedThreadPlan( m_class_name.c_str(), m_args_data, m_error_str, @@ -79,10 +80,7 @@ bool ThreadPlanPython::ShouldStop(Event *event_ptr) { bool should_stop = true; if (m_implementation_sp) { - ScriptInterpreter *script_interp = m_thread.GetProcess() - ->GetTarget() - .GetDebugger() - .GetScriptInterpreter(); + ScriptInterpreter *script_interp = GetScriptInterpreter(); if (script_interp) { bool script_error; should_stop = script_interp->ScriptedThreadPlanShouldStop( @@ -101,10 +99,7 @@ bool ThreadPlanPython::IsPlanStale() { bool is_stale = true; if (m_implementation_sp) { - ScriptInterpreter *script_interp = m_thread.GetProcess() - ->GetTarget() - .GetDebugger() - .GetScriptInterpreter(); + ScriptInterpreter *script_interp = GetScriptInterpreter(); if (script_interp) { bool script_error; is_stale = script_interp->ScriptedThreadPlanIsStale(m_implementation_sp, @@ -123,10 +118,7 @@ bool ThreadPlanPython::DoPlanExplainsStop(Event *event_ptr) { bool explains_stop = true; if (m_implementation_sp) { - ScriptInterpreter *script_interp = m_thread.GetProcess() - ->GetTarget() - .GetDebugger() - .GetScriptInterpreter(); + ScriptInterpreter *script_interp = GetScriptInterpreter(); if (script_interp) { bool script_error; explains_stop = script_interp->ScriptedThreadPlanExplainsStop( @@ -159,10 +151,7 @@ lldb::StateType ThreadPlanPython::GetPlanRunState() { m_class_name.c_str()); lldb::StateType run_state = eStateRunning; if (m_implementation_sp) { - ScriptInterpreter *script_interp = m_thread.GetProcess() - ->GetTarget() - .GetDebugger() - .GetScriptInterpreter(); + ScriptInterpreter *script_interp = GetScriptInterpreter(); if (script_interp) { bool script_error; run_state = script_interp->ScriptedThreadPlanGetRunState( diff --git a/lldb/source/Target/ThreadPlanRunToAddress.cpp b/lldb/source/Target/ThreadPlanRunToAddress.cpp index 32ea2e6752707..f8a543ad21cf9 100644 --- a/lldb/source/Target/ThreadPlanRunToAddress.cpp +++ b/lldb/source/Target/ThreadPlanRunToAddress.cpp @@ -25,7 +25,7 @@ ThreadPlanRunToAddress::ThreadPlanRunToAddress(Thread &thread, Address &address, eVoteNoOpinion, eVoteNoOpinion), m_stop_others(stop_others), m_addresses(), m_break_ids() { m_addresses.push_back( - address.GetOpcodeLoadAddress(m_thread.CalculateTarget().get())); + address.GetOpcodeLoadAddress(thread.CalculateTarget().get())); SetInitialBreakpoints(); } @@ -36,7 +36,7 @@ ThreadPlanRunToAddress::ThreadPlanRunToAddress(Thread &thread, eVoteNoOpinion, eVoteNoOpinion), m_stop_others(stop_others), m_addresses(), m_break_ids() { m_addresses.push_back( - m_thread.CalculateTarget()->GetOpcodeLoadAddress(address)); + thread.CalculateTarget()->GetOpcodeLoadAddress(address)); SetInitialBreakpoints(); } @@ -62,14 +62,13 @@ void ThreadPlanRunToAddress::SetInitialBreakpoints() { for (size_t i = 0; i < num_addresses; i++) { Breakpoint *breakpoint; - breakpoint = m_thread.CalculateTarget() - ->CreateBreakpoint(m_addresses[i], true, false) - .get(); + breakpoint = + GetTarget().CreateBreakpoint(m_addresses[i], true, false).get(); if (breakpoint != nullptr) { if (breakpoint->IsHardware() && !breakpoint->HasResolvedLocations()) m_could_not_resolve_hw_bp = true; m_break_ids[i] = breakpoint->GetID(); - breakpoint->SetThreadID(m_thread.GetID()); + breakpoint->SetThreadID(m_tid); breakpoint->SetBreakpointKind("run-to-address"); } } @@ -78,7 +77,7 @@ void ThreadPlanRunToAddress::SetInitialBreakpoints() { ThreadPlanRunToAddress::~ThreadPlanRunToAddress() { size_t num_break_ids = m_break_ids.size(); for (size_t i = 0; i < num_break_ids; i++) { - m_thread.CalculateTarget()->RemoveBreakpointByID(m_break_ids[i]); + GetTarget().RemoveBreakpointByID(m_break_ids[i]); } m_could_not_resolve_hw_bp = false; } @@ -119,7 +118,7 @@ void ThreadPlanRunToAddress::GetDescription(Stream *s, DumpAddress(s->AsRawOstream(), m_addresses[i], sizeof(addr_t)); s->Printf(" using breakpoint: %d - ", m_break_ids[i]); Breakpoint *breakpoint = - m_thread.CalculateTarget()->GetBreakpointByID(m_break_ids[i]).get(); + GetTarget().GetBreakpointByID(m_break_ids[i]).get(); if (breakpoint) breakpoint->Dump(s); else @@ -178,7 +177,7 @@ bool ThreadPlanRunToAddress::MischiefManaged() { for (size_t i = 0; i < num_break_ids; i++) { if (m_break_ids[i] != LLDB_INVALID_BREAK_ID) { - m_thread.CalculateTarget()->RemoveBreakpointByID(m_break_ids[i]); + GetTarget().RemoveBreakpointByID(m_break_ids[i]); m_break_ids[i] = LLDB_INVALID_BREAK_ID; } } @@ -190,7 +189,7 @@ bool ThreadPlanRunToAddress::MischiefManaged() { } bool ThreadPlanRunToAddress::AtOurAddress() { - lldb::addr_t current_address = m_thread.GetRegisterContext()->GetPC(); + lldb::addr_t current_address = GetThread().GetRegisterContext()->GetPC(); bool found_it = false; size_t num_addresses = m_addresses.size(); for (size_t i = 0; i < num_addresses; i++) { diff --git a/lldb/source/Target/ThreadPlanStack.cpp b/lldb/source/Target/ThreadPlanStack.cpp new file mode 100644 index 0000000000000..2472a2f488744 --- /dev/null +++ b/lldb/source/Target/ThreadPlanStack.cpp @@ -0,0 +1,511 @@ +//===-- ThreadPlanStack.cpp -------------------------------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "lldb/Target/ThreadPlanStack.h" +#include "lldb/Target/Process.h" +#include "lldb/Target/Target.h" +#include "lldb/Target/Thread.h" +#include "lldb/Target/ThreadPlan.h" +#include "lldb/Utility/Log.h" + +using namespace lldb; +using namespace lldb_private; + +static void PrintPlanElement(Stream &s, const ThreadPlanSP &plan, + lldb::DescriptionLevel desc_level, + int32_t elem_idx) { + s.IndentMore(); + s.Indent(); + s.Printf("Element %d: ", elem_idx); + plan->GetDescription(&s, desc_level); + s.EOL(); + s.IndentLess(); +} + +ThreadPlanStack::ThreadPlanStack(const Thread &thread, bool make_null) { + if (make_null) { + // The ThreadPlanNull doesn't do anything to the Thread, so this is actually + // still a const operation. + m_plans.push_back( + ThreadPlanSP(new ThreadPlanNull(const_cast(thread)))); + } +} + +void ThreadPlanStack::DumpThreadPlans(Stream &s, + lldb::DescriptionLevel desc_level, + bool include_internal) const { + s.IndentMore(); + PrintOneStack(s, "Active plan stack", m_plans, desc_level, include_internal); + PrintOneStack(s, "Completed plan stack", m_completed_plans, desc_level, + include_internal); + PrintOneStack(s, "Discarded plan stack", m_discarded_plans, desc_level, + include_internal); + s.IndentLess(); +} + +void ThreadPlanStack::PrintOneStack(Stream &s, llvm::StringRef stack_name, + const PlanStack &stack, + lldb::DescriptionLevel desc_level, + bool include_internal) const { + // If the stack is empty, just exit: + if (stack.empty()) + return; + + // Make sure there are public completed plans: + bool any_public = false; + if (!include_internal) { + for (auto plan : stack) { + if (!plan->GetPrivate()) { + any_public = true; + break; + } + } + } + + if (include_internal || any_public) { + int print_idx = 0; + s.Indent(); + s << stack_name << ":\n"; + for (auto plan : stack) { + if (!include_internal && plan->GetPrivate()) + continue; + PrintPlanElement(s, plan, desc_level, print_idx++); + } + } +} + +size_t ThreadPlanStack::CheckpointCompletedPlans() { + m_completed_plan_checkpoint++; + m_completed_plan_store.insert( + std::make_pair(m_completed_plan_checkpoint, m_completed_plans)); + return m_completed_plan_checkpoint; +} + +void ThreadPlanStack::RestoreCompletedPlanCheckpoint(size_t checkpoint) { + auto result = m_completed_plan_store.find(checkpoint); + assert(result != m_completed_plan_store.end() && + "Asked for a checkpoint that didn't exist"); + m_completed_plans.swap((*result).second); + m_completed_plan_store.erase(result); +} + +void ThreadPlanStack::DiscardCompletedPlanCheckpoint(size_t checkpoint) { + m_completed_plan_store.erase(checkpoint); +} + +void ThreadPlanStack::ThreadDestroyed(Thread *thread) { + // Tell the plan stacks that this thread is going away: + for (ThreadPlanSP plan : m_plans) + plan->ThreadDestroyed(); + + for (ThreadPlanSP plan : m_discarded_plans) + plan->ThreadDestroyed(); + + for (ThreadPlanSP plan : m_completed_plans) + plan->ThreadDestroyed(); + + // Now clear the current plan stacks: + m_plans.clear(); + m_discarded_plans.clear(); + m_completed_plans.clear(); + + // Push a ThreadPlanNull on the plan stack. That way we can continue + // assuming that the plan stack is never empty, but if somebody errantly asks + // questions of a destroyed thread without checking first whether it is + // destroyed, they won't crash. + if (thread != nullptr) { + lldb::ThreadPlanSP null_plan_sp(new ThreadPlanNull(*thread)); + m_plans.push_back(null_plan_sp); + } +} + +void ThreadPlanStack::EnableTracer(bool value, bool single_stepping) { + for (ThreadPlanSP plan : m_plans) { + if (plan->GetThreadPlanTracer()) { + plan->GetThreadPlanTracer()->EnableTracing(value); + plan->GetThreadPlanTracer()->EnableSingleStep(single_stepping); + } + } +} + +void ThreadPlanStack::SetTracer(lldb::ThreadPlanTracerSP &tracer_sp) { + for (ThreadPlanSP plan : m_plans) + plan->SetThreadPlanTracer(tracer_sp); +} + +void ThreadPlanStack::PushPlan(lldb::ThreadPlanSP new_plan_sp) { + // If the thread plan doesn't already have a tracer, give it its parent's + // tracer: + // The first plan has to be a base plan: + assert(m_plans.size() > 0 || + new_plan_sp->IsBasePlan() && "Zeroth plan must be a base plan"); + + if (!new_plan_sp->GetThreadPlanTracer()) { + assert(!m_plans.empty()); + new_plan_sp->SetThreadPlanTracer(m_plans.back()->GetThreadPlanTracer()); + } + m_plans.push_back(new_plan_sp); + new_plan_sp->DidPush(); +} + +lldb::ThreadPlanSP ThreadPlanStack::PopPlan() { + assert(m_plans.size() > 1 && "Can't pop the base thread plan"); + + lldb::ThreadPlanSP plan_sp = std::move(m_plans.back()); + m_completed_plans.push_back(plan_sp); + plan_sp->WillPop(); + m_plans.pop_back(); + return plan_sp; +} + +lldb::ThreadPlanSP ThreadPlanStack::DiscardPlan() { + assert(m_plans.size() > 1 && "Can't discard the base thread plan"); + + lldb::ThreadPlanSP plan_sp = std::move(m_plans.back()); + m_discarded_plans.push_back(plan_sp); + plan_sp->WillPop(); + m_plans.pop_back(); + return plan_sp; +} + +// If the input plan is nullptr, discard all plans. Otherwise make sure this +// plan is in the stack, and if so discard up to and including it. +void ThreadPlanStack::DiscardPlansUpToPlan(ThreadPlan *up_to_plan_ptr) { + int stack_size = m_plans.size(); + + if (up_to_plan_ptr == nullptr) { + for (int i = stack_size - 1; i > 0; i--) + DiscardPlan(); + return; + } + + bool found_it = false; + for (int i = stack_size - 1; i > 0; i--) { + if (m_plans[i].get() == up_to_plan_ptr) { + found_it = true; + break; + } + } + + if (found_it) { + bool last_one = false; + for (int i = stack_size - 1; i > 0 && !last_one; i--) { + if (GetCurrentPlan().get() == up_to_plan_ptr) + last_one = true; + DiscardPlan(); + } + } +} + +void ThreadPlanStack::DiscardAllPlans() { + int stack_size = m_plans.size(); + for (int i = stack_size - 1; i > 0; i--) { + DiscardPlan(); + } + return; +} + +void ThreadPlanStack::DiscardConsultingMasterPlans() { + while (true) { + int master_plan_idx; + bool discard = true; + + // Find the first master plan, see if it wants discarding, and if yes + // discard up to it. + for (master_plan_idx = m_plans.size() - 1; master_plan_idx >= 0; + master_plan_idx--) { + if (m_plans[master_plan_idx]->IsMasterPlan()) { + discard = m_plans[master_plan_idx]->OkayToDiscard(); + break; + } + } + + // If the master plan doesn't want to get discarded, then we're done. + if (!discard) + return; + + // First pop all the dependent plans: + for (int i = m_plans.size() - 1; i > master_plan_idx; i--) { + DiscardPlan(); + } + + // Now discard the master plan itself. + // The bottom-most plan never gets discarded. "OkayToDiscard" for it + // means discard it's dependent plans, but not it... + if (master_plan_idx > 0) { + DiscardPlan(); + } + } +} + +lldb::ThreadPlanSP ThreadPlanStack::GetCurrentPlan() const { + assert(m_plans.size() != 0 && "There will always be a base plan."); + return m_plans.back(); +} + +lldb::ThreadPlanSP ThreadPlanStack::GetCompletedPlan(bool skip_private) const { + if (m_completed_plans.empty()) + return {}; + + if (!skip_private) + return m_completed_plans.back(); + + for (int i = m_completed_plans.size() - 1; i >= 0; i--) { + lldb::ThreadPlanSP completed_plan_sp; + completed_plan_sp = m_completed_plans[i]; + if (!completed_plan_sp->GetPrivate()) + return completed_plan_sp; + } + return {}; +} + +lldb::ThreadPlanSP ThreadPlanStack::GetPlanByIndex(uint32_t plan_idx, + bool skip_private) const { + uint32_t idx = 0; + + for (lldb::ThreadPlanSP plan_sp : m_plans) { + if (skip_private && plan_sp->GetPrivate()) + continue; + if (idx == plan_idx) + return plan_sp; + idx++; + } + return {}; +} + +lldb::ValueObjectSP +ThreadPlanStack::GetReturnValueObject(bool &is_error) const { + if (m_completed_plans.empty()) + return {}; + + for (int i = m_completed_plans.size() - 1; i >= 0; i--) { + lldb::ValueObjectSP return_valobj_sp; + return_valobj_sp = m_completed_plans[i]->GetReturnValueObject(); + if (return_valobj_sp) { + is_error = m_completed_plans[i]->IsReturnValueSwiftErrorValue(); + return return_valobj_sp; + } + } + return {}; +} + +lldb::ExpressionVariableSP ThreadPlanStack::GetExpressionVariable() const { + if (m_completed_plans.empty()) + return {}; + + for (int i = m_completed_plans.size() - 1; i >= 0; i--) { + lldb::ExpressionVariableSP expression_variable_sp; + expression_variable_sp = m_completed_plans[i]->GetExpressionVariable(); + if (expression_variable_sp) + return expression_variable_sp; + } + return {}; +} +bool ThreadPlanStack::AnyPlans() const { + // There is always a base plan... + return m_plans.size() > 1; +} + +bool ThreadPlanStack::AnyCompletedPlans() const { + return !m_completed_plans.empty(); +} + +bool ThreadPlanStack::AnyDiscardedPlans() const { + return !m_discarded_plans.empty(); +} + +bool ThreadPlanStack::IsPlanDone(ThreadPlan *in_plan) const { + for (auto plan : m_completed_plans) { + if (plan.get() == in_plan) + return true; + } + return false; +} + +bool ThreadPlanStack::WasPlanDiscarded(ThreadPlan *in_plan) const { + for (auto plan : m_discarded_plans) { + if (plan.get() == in_plan) + return true; + } + return false; +} + +ThreadPlan *ThreadPlanStack::GetPreviousPlan(ThreadPlan *current_plan) const { + if (current_plan == nullptr) + return nullptr; + + // Look first in the completed plans, if the plan is here and there is + // a completed plan above it, return that. + int stack_size = m_completed_plans.size(); + for (int i = stack_size - 1; i > 0; i--) { + if (current_plan == m_completed_plans[i].get()) + return m_completed_plans[i - 1].get(); + } + + // If this is the first completed plan, the previous one is the + // bottom of the regular plan stack. + if (stack_size > 0 && m_completed_plans[0].get() == current_plan) { + return GetCurrentPlan().get(); + } + + // Otherwise look for it in the regular plans. + stack_size = m_plans.size(); + for (int i = stack_size - 1; i > 0; i--) { + if (current_plan == m_plans[i].get()) + return m_plans[i - 1].get(); + } + return nullptr; +} + +ThreadPlan *ThreadPlanStack::GetInnermostExpression() const { + int stack_size = m_plans.size(); + + for (int i = stack_size - 1; i > 0; i--) { + if (m_plans[i]->GetKind() == ThreadPlan::eKindCallFunction) + return m_plans[i].get(); + } + return nullptr; +} + +void ThreadPlanStack::WillResume() { + m_completed_plans.clear(); + m_discarded_plans.clear(); +} + +const ThreadPlanStack::PlanStack & +ThreadPlanStack::GetStackOfKind(ThreadPlanStack::StackKind kind) const { + switch (kind) { + case ePlans: + return m_plans; + case eCompletedPlans: + return m_completed_plans; + case eDiscardedPlans: + return m_discarded_plans; + } + llvm_unreachable("Invalid StackKind value"); +} + +void ThreadPlanStackMap::Update(ThreadList ¤t_threads, + bool delete_missing, + bool check_for_new) { + + // Now find all the new threads and add them to the map: + if (check_for_new) { + for (auto thread : current_threads.Threads()) { + lldb::tid_t cur_tid = thread->GetID(); + if (!Find(cur_tid)) { + AddThread(*thread.get()); + thread->QueueFundamentalPlan(true); + } + } + } + + // If we aren't reaping missing threads at this point, + // we are done. + if (!delete_missing) + return; + // Otherwise scan for absent TID's. + std::vector missing_threads; + // If we are going to delete plans from the plan stack, + // then scan for absent TID's: + for (auto thread_plans : m_plans_list) { + lldb::tid_t cur_tid = thread_plans.first; + ThreadSP thread_sp = current_threads.FindThreadByID(cur_tid); + if (!thread_sp) + missing_threads.push_back(cur_tid); + } + for (lldb::tid_t tid : missing_threads) { + RemoveTID(tid); + } +} + +void ThreadPlanStackMap::DumpPlans(Stream &strm, + lldb::DescriptionLevel desc_level, + bool internal, bool condense_if_trivial, + bool skip_unreported) { + for (auto elem : m_plans_list) { + lldb::tid_t tid = elem.first; + uint32_t index_id = 0; + ThreadSP thread_sp = m_process.GetThreadList().FindThreadByID(tid); + + if (skip_unreported) { + if (!thread_sp) + continue; + } + if (thread_sp) + index_id = thread_sp->GetIndexID(); + + if (condense_if_trivial) { + if (!elem.second.AnyPlans() && !elem.second.AnyCompletedPlans() && + !elem.second.AnyDiscardedPlans()) { + strm.Printf("thread #%u: tid = 0x%4.4" PRIx64 "\n", index_id, tid); + strm.IndentMore(); + strm.Indent(); + strm.Printf("No active thread plans\n"); + strm.IndentLess(); + return; + } + } + + strm.Indent(); + strm.Printf("thread #%u: tid = 0x%4.4" PRIx64 ":\n", index_id, tid); + + elem.second.DumpThreadPlans(strm, desc_level, internal); + } +} + +bool ThreadPlanStackMap::DumpPlansForTID(Stream &strm, lldb::tid_t tid, + lldb::DescriptionLevel desc_level, + bool internal, + bool condense_if_trivial, + bool skip_unreported) { + uint32_t index_id = 0; + ThreadSP thread_sp = m_process.GetThreadList().FindThreadByID(tid); + + if (skip_unreported) { + if (!thread_sp) { + strm.Format("Unknown TID: {0}", tid); + return false; + } + } + + if (thread_sp) + index_id = thread_sp->GetIndexID(); + ThreadPlanStack *stack = Find(tid); + if (!stack) { + strm.Format("Unknown TID: {0}\n", tid); + return false; + } + + if (condense_if_trivial) { + if (!stack->AnyPlans() && !stack->AnyCompletedPlans() && + !stack->AnyDiscardedPlans()) { + strm.Printf("thread #%u: tid = 0x%4.4" PRIx64 "\n", index_id, tid); + strm.IndentMore(); + strm.Indent(); + strm.Printf("No active thread plans\n"); + strm.IndentLess(); + return true; + } + } + + strm.Indent(); + strm.Printf("thread #%u: tid = 0x%4.4" PRIx64 ":\n", index_id, tid); + + stack->DumpThreadPlans(strm, desc_level, internal); + return true; +} + +bool ThreadPlanStackMap::PrunePlansForTID(lldb::tid_t tid) { + // We only remove the plans for unreported TID's. + ThreadSP thread_sp = m_process.GetThreadList().FindThreadByID(tid); + if (thread_sp) + return false; + + return RemoveTID(tid); +} diff --git a/lldb/source/Target/ThreadPlanStepInRange.cpp b/lldb/source/Target/ThreadPlanStepInRange.cpp index b01ce3939ce65..0e45faca57eb3 100644 --- a/lldb/source/Target/ThreadPlanStepInRange.cpp +++ b/lldb/source/Target/ThreadPlanStepInRange.cpp @@ -73,7 +73,7 @@ void ThreadPlanStepInRange::SetupAvoidNoDebug( LazyBool step_in_avoids_code_without_debug_info, LazyBool step_out_avoids_code_without_debug_info) { bool avoid_nodebug = true; - + Thread &thread = GetThread(); switch (step_in_avoids_code_without_debug_info) { case eLazyBoolYes: avoid_nodebug = true; @@ -82,7 +82,7 @@ void ThreadPlanStepInRange::SetupAvoidNoDebug( avoid_nodebug = false; break; case eLazyBoolCalculate: - avoid_nodebug = m_thread.GetStepInAvoidsNoDebug(); + avoid_nodebug = thread.GetStepInAvoidsNoDebug(); break; } if (avoid_nodebug) @@ -98,7 +98,7 @@ void ThreadPlanStepInRange::SetupAvoidNoDebug( avoid_nodebug = false; break; case eLazyBoolCalculate: - avoid_nodebug = m_thread.GetStepOutAvoidsNoDebug(); + avoid_nodebug = thread.GetStepOutAvoidsNoDebug(); break; } if (avoid_nodebug) @@ -149,9 +149,8 @@ bool ThreadPlanStepInRange::ShouldStop(Event *event_ptr) { if (log) { StreamString s; - DumpAddress( - s.AsRawOstream(), m_thread.GetRegisterContext()->GetPC(), - m_thread.CalculateTarget()->GetArchitecture().GetAddressByteSize()); + DumpAddress(s.AsRawOstream(), GetThread().GetRegisterContext()->GetPC(), + GetTarget().GetArchitecture().GetAddressByteSize()); LLDB_LOGF(log, "ThreadPlanStepInRange reached %s.", s.GetData()); } @@ -184,6 +183,7 @@ bool ThreadPlanStepInRange::ShouldStop(Event *event_ptr) { FrameComparison frame_order = CompareCurrentFrameToStartFrame(); + Thread &thread = GetThread(); if (frame_order == eFrameCompareOlder || frame_order == eFrameCompareSameParent) { // If we're in an older frame then we should stop. @@ -193,7 +193,7 @@ bool ThreadPlanStepInRange::ShouldStop(Event *event_ptr) { // I'm going to make the assumption that you wouldn't RETURN to a // trampoline. So if we are in a trampoline we think the frame is older // because the trampoline confused the backtracer. - m_sub_plan_sp = m_thread.QueueThreadPlanForStepThrough( + m_sub_plan_sp = thread.QueueThreadPlanForStepThrough( m_stack_id, false, stop_others, m_status); if (!m_sub_plan_sp) { // Otherwise check the ShouldStopHere for step out: @@ -237,7 +237,7 @@ bool ThreadPlanStepInRange::ShouldStop(Event *event_ptr) { // We may have set the plan up above in the FrameIsOlder section: if (!m_sub_plan_sp) - m_sub_plan_sp = m_thread.QueueThreadPlanForStepThrough( + m_sub_plan_sp = thread.QueueThreadPlanForStepThrough( m_stack_id, false, stop_others, m_status); if (log) { @@ -258,10 +258,10 @@ bool ThreadPlanStepInRange::ShouldStop(Event *event_ptr) { if (!m_sub_plan_sp && frame_order == eFrameCompareYounger && m_step_past_prologue) { - lldb::StackFrameSP curr_frame = m_thread.GetStackFrameAtIndex(0); + lldb::StackFrameSP curr_frame = thread.GetStackFrameAtIndex(0); if (curr_frame) { size_t bytes_to_skip = 0; - lldb::addr_t curr_addr = m_thread.GetRegisterContext()->GetPC(); + lldb::addr_t curr_addr = thread.GetRegisterContext()->GetPC(); Address func_start_address; SymbolContext sc = curr_frame->GetSymbolContext(eSymbolContextFunction | @@ -269,25 +269,20 @@ bool ThreadPlanStepInRange::ShouldStop(Event *event_ptr) { if (sc.function) { func_start_address = sc.function->GetAddressRange().GetBaseAddress(); - if (curr_addr == - func_start_address.GetLoadAddress( - m_thread.CalculateTarget().get())) + if (curr_addr == func_start_address.GetLoadAddress(&GetTarget())) bytes_to_skip = sc.function->GetPrologueByteSize(); } else if (sc.symbol) { func_start_address = sc.symbol->GetAddress(); - if (curr_addr == - func_start_address.GetLoadAddress( - m_thread.CalculateTarget().get())) + if (curr_addr == func_start_address.GetLoadAddress(&GetTarget())) bytes_to_skip = sc.symbol->GetPrologueByteSize(); } if (bytes_to_skip == 0 && sc.symbol) { - TargetSP target = m_thread.CalculateTarget(); - const Architecture *arch = target->GetArchitecturePlugin(); + const Architecture *arch = GetTarget().GetArchitecturePlugin(); if (arch) { Address curr_sec_addr; - target->GetSectionLoadList().ResolveLoadAddress(curr_addr, - curr_sec_addr); + GetTarget().GetSectionLoadList().ResolveLoadAddress(curr_addr, + curr_sec_addr); bytes_to_skip = arch->GetBytesToSkip(*sc.symbol, curr_sec_addr); } } @@ -297,7 +292,7 @@ bool ThreadPlanStepInRange::ShouldStop(Event *event_ptr) { log = lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_STEP); LLDB_LOGF(log, "Pushing past prologue "); - m_sub_plan_sp = m_thread.QueueThreadPlanForRunToAddress( + m_sub_plan_sp = thread.QueueThreadPlanForRunToAddress( false, func_start_address, true, m_status); } } @@ -344,7 +339,7 @@ bool ThreadPlanStepInRange::StepInDeepBreakpointExplainsStop( break_id_t bp_site_id = stop_info_sp->GetValue(); BreakpointSiteSP bp_site_sp = - m_thread.GetProcess()->GetBreakpointSiteList().FindByID(bp_site_id); + m_process.GetBreakpointSiteList().FindByID(bp_site_id); if (!bp_site_sp) return false; @@ -614,15 +609,16 @@ bool ThreadPlanStepInRange::DoWillResume(lldb::StateType resume_state, bool current_plan) { m_virtual_step = false; if (resume_state == eStateStepping && current_plan) { + Thread &thread = GetThread(); // See if we are about to step over a virtual inlined call. - bool step_without_resume = m_thread.DecrementCurrentInlinedDepth(); + bool step_without_resume = thread.DecrementCurrentInlinedDepth(); if (step_without_resume) { Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_STEP)); LLDB_LOGF(log, "ThreadPlanStepInRange::DoWillResume: returning false, " "inline_depth: %d", - m_thread.GetCurrentInlinedDepth()); - SetStopInfo(StopInfo::CreateStopReasonToTrace(m_thread)); + thread.GetCurrentInlinedDepth()); + SetStopInfo(StopInfo::CreateStopReasonToTrace(thread)); // FIXME: Maybe it would be better to create a InlineStep stop reason, but // then diff --git a/lldb/source/Target/ThreadPlanStepInstruction.cpp b/lldb/source/Target/ThreadPlanStepInstruction.cpp index afcc9d608b27c..0507df99bca08 100644 --- a/lldb/source/Target/ThreadPlanStepInstruction.cpp +++ b/lldb/source/Target/ThreadPlanStepInstruction.cpp @@ -36,14 +36,15 @@ ThreadPlanStepInstruction::ThreadPlanStepInstruction(Thread &thread, ThreadPlanStepInstruction::~ThreadPlanStepInstruction() = default; void ThreadPlanStepInstruction::SetUpState() { - m_instruction_addr = m_thread.GetRegisterContext()->GetPC(0); - StackFrameSP start_frame_sp(m_thread.GetStackFrameAtIndex(0)); + Thread &thread = GetThread(); + m_instruction_addr = thread.GetRegisterContext()->GetPC(0); + StackFrameSP start_frame_sp(thread.GetStackFrameAtIndex(0)); m_stack_id = start_frame_sp->GetStackID(); m_start_has_symbol = start_frame_sp->GetSymbolContext(eSymbolContextSymbol).symbol != nullptr; - StackFrameSP parent_frame_sp = m_thread.GetStackFrameAtIndex(1); + StackFrameSP parent_frame_sp = thread.GetStackFrameAtIndex(1); if (parent_frame_sp) m_parent_frame_id = parent_frame_sp->GetStackID(); } @@ -95,18 +96,19 @@ bool ThreadPlanStepInstruction::DoPlanExplainsStop(Event *event_ptr) { bool ThreadPlanStepInstruction::IsPlanStale() { Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_STEP)); - StackID cur_frame_id = m_thread.GetStackFrameAtIndex(0)->GetStackID(); + Thread &thread = GetThread(); + StackID cur_frame_id = thread.GetStackFrameAtIndex(0)->GetStackID(); if (cur_frame_id == m_stack_id) { // Set plan Complete when we reach next instruction - uint64_t pc = m_thread.GetRegisterContext()->GetPC(0); - uint32_t max_opcode_size = m_thread.CalculateTarget() - ->GetArchitecture().GetMaximumOpcodeByteSize(); + uint64_t pc = thread.GetRegisterContext()->GetPC(0); + uint32_t max_opcode_size = + GetTarget().GetArchitecture().GetMaximumOpcodeByteSize(); bool next_instruction_reached = (pc > m_instruction_addr) && (pc <= m_instruction_addr + max_opcode_size); if (next_instruction_reached) { SetPlanComplete(); } - return (m_thread.GetRegisterContext()->GetPC(0) != m_instruction_addr); + return (thread.GetRegisterContext()->GetPC(0) != m_instruction_addr); } else if (cur_frame_id < m_stack_id) { // If the current frame is younger than the start frame and we are stepping // over, then we need to continue, but if we are doing just one step, we're @@ -123,10 +125,10 @@ bool ThreadPlanStepInstruction::IsPlanStale() { } bool ThreadPlanStepInstruction::ShouldStop(Event *event_ptr) { + Thread &thread = GetThread(); if (m_step_over) { Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_STEP)); - - StackFrameSP cur_frame_sp = m_thread.GetStackFrameAtIndex(0); + StackFrameSP cur_frame_sp = thread.GetStackFrameAtIndex(0); if (!cur_frame_sp) { LLDB_LOGF( log, @@ -138,7 +140,7 @@ bool ThreadPlanStepInstruction::ShouldStop(Event *event_ptr) { StackID cur_frame_zero_id = cur_frame_sp->GetStackID(); if (cur_frame_zero_id == m_stack_id || m_stack_id < cur_frame_zero_id) { - if (m_thread.GetRegisterContext()->GetPC(0) != m_instruction_addr) { + if (thread.GetRegisterContext()->GetPC(0) != m_instruction_addr) { if (--m_iteration_count <= 0) { SetPlanComplete(); return true; @@ -152,7 +154,7 @@ bool ThreadPlanStepInstruction::ShouldStop(Event *event_ptr) { return false; } else { // We've stepped in, step back out again: - StackFrame *return_frame = m_thread.GetStackFrameAtIndex(1).get(); + StackFrame *return_frame = thread.GetStackFrameAtIndex(1).get(); if (return_frame) { if (return_frame->GetStackID() != m_parent_frame_id || m_start_has_symbol) { @@ -162,7 +164,7 @@ bool ThreadPlanStepInstruction::ShouldStop(Event *event_ptr) { if (cur_frame_sp->IsInlined()) { StackFrameSP parent_frame_sp = - m_thread.GetFrameWithStackID(m_stack_id); + thread.GetFrameWithStackID(m_stack_id); if (parent_frame_sp && parent_frame_sp->GetConcreteFrameIndex() == @@ -181,24 +183,20 @@ bool ThreadPlanStepInstruction::ShouldStop(Event *event_ptr) { StreamString s; s.PutCString("Stepped in to: "); addr_t stop_addr = - m_thread.GetStackFrameAtIndex(0)->GetRegisterContext()->GetPC(); + thread.GetStackFrameAtIndex(0)->GetRegisterContext()->GetPC(); DumpAddress(s.AsRawOstream(), stop_addr, - m_thread.CalculateTarget() - ->GetArchitecture() - .GetAddressByteSize()); + GetTarget().GetArchitecture().GetAddressByteSize()); s.PutCString(" stepping out to: "); addr_t return_addr = return_frame->GetRegisterContext()->GetPC(); DumpAddress(s.AsRawOstream(), return_addr, - m_thread.CalculateTarget() - ->GetArchitecture() - .GetAddressByteSize()); + GetTarget().GetArchitecture().GetAddressByteSize()); LLDB_LOGF(log, "%s.", s.GetData()); } // StepInstruction should probably have the tri-state RunMode, but // for now it is safer to run others. const bool stop_others = false; - m_thread.QueueThreadPlanForStepOutNoShouldStop( + thread.QueueThreadPlanForStepOutNoShouldStop( false, nullptr, true, stop_others, eVoteNo, eVoteNoOpinion, 0, m_status); return false; @@ -219,7 +217,7 @@ bool ThreadPlanStepInstruction::ShouldStop(Event *event_ptr) { } } } else { - lldb::addr_t pc_addr = m_thread.GetRegisterContext()->GetPC(0); + lldb::addr_t pc_addr = thread.GetRegisterContext()->GetPC(0); if (pc_addr != m_instruction_addr) { if (--m_iteration_count <= 0) { SetPlanComplete(); diff --git a/lldb/source/Target/ThreadPlanStepOut.cpp b/lldb/source/Target/ThreadPlanStepOut.cpp index 321da8840978a..9770715c32dbc 100644 --- a/lldb/source/Target/ThreadPlanStepOut.cpp +++ b/lldb/source/Target/ThreadPlanStepOut.cpp @@ -13,6 +13,7 @@ #include "lldb/Symbol/Block.h" #include "lldb/Symbol/CompileUnit.h" #include "lldb/Symbol/Function.h" +#include "lldb/Symbol/SwiftASTContext.h" #include "lldb/Symbol/Symbol.h" #include "lldb/Symbol/Type.h" #include "lldb/Symbol/VariableList.h" @@ -53,13 +54,11 @@ ThreadPlanStepOut::ThreadPlanStepOut( SetFlagsToDefault(); SetupAvoidNoDebug(step_out_avoids_code_without_debug_info); - m_step_from_insn = m_thread.GetRegisterContext()->GetPC(0); + m_step_from_insn = thread.GetRegisterContext()->GetPC(0); uint32_t return_frame_index = frame_idx + 1; - StackFrameSP return_frame_sp( - m_thread.GetStackFrameAtIndex(return_frame_index)); - StackFrameSP immediate_return_from_sp( - m_thread.GetStackFrameAtIndex(frame_idx)); + StackFrameSP return_frame_sp(thread.GetStackFrameAtIndex(return_frame_index)); + StackFrameSP immediate_return_from_sp(thread.GetStackFrameAtIndex(frame_idx)); if (!return_frame_sp || !immediate_return_from_sp) return; // we can't do anything here. ValidatePlan() will return false. @@ -69,7 +68,7 @@ ThreadPlanStepOut::ThreadPlanStepOut( m_stepped_past_frames.push_back(return_frame_sp); ++return_frame_index; - return_frame_sp = m_thread.GetStackFrameAtIndex(return_frame_index); + return_frame_sp = thread.GetStackFrameAtIndex(return_frame_index); // We never expect to see an artificial frame without a regular ancestor. // If this happens, log the issue and defensively refuse to step out. @@ -91,7 +90,7 @@ ThreadPlanStepOut::ThreadPlanStepOut( // First queue a plan that gets us to this inlined frame, and when we get // there we'll queue a second plan that walks us out of this frame. m_step_out_to_inline_plan_sp = std::make_shared( - m_thread, nullptr, false, stop_others, eVoteNoOpinion, eVoteNoOpinion, + thread, nullptr, false, stop_others, eVoteNoOpinion, eVoteNoOpinion, frame_idx - 1, eLazyBoolNo, continue_to_next_branch); static_cast(m_step_out_to_inline_plan_sp.get()) ->SetShouldStopHereCallbacks(nullptr, nullptr); @@ -120,28 +119,23 @@ ThreadPlanStepOut::ThreadPlanStepOut( range = return_address_sc.line_entry.GetSameLineContiguousAddressRange( include_inlined_functions); if (range.GetByteSize() > 0) { - return_address = - m_thread.GetProcess()->AdvanceAddressToNextBranchInstruction( - return_address, range); + return_address = m_process.AdvanceAddressToNextBranchInstruction( + return_address, range); } } } - m_return_addr = - return_address.GetLoadAddress(&m_thread.GetProcess()->GetTarget()); + m_return_addr = return_address.GetLoadAddress(&m_process.GetTarget()); if (m_return_addr == LLDB_INVALID_ADDRESS) return; // Perform some additional validation on the return address. uint32_t permissions = 0; - if (!m_thread.GetProcess()->GetLoadAddressPermissions(m_return_addr, - permissions)) { - m_constructor_errors.Printf("Return address (0x%" PRIx64 - ") permissions not found.", - m_return_addr); - LLDB_LOGF(log, "ThreadPlanStepOut(%p): %s", static_cast(this), - m_constructor_errors.GetData()); - return; + if (!m_process.GetLoadAddressPermissions(m_return_addr, + permissions)) { + LLDB_LOGF(log, "ThreadPlanStepOut(%p): Return address (0x%" PRIx64 + ") permissions not found.", static_cast(this), + m_return_addr); } else if (!(permissions & ePermissionsExecutable)) { m_constructor_errors.Printf("Return address (0x%" PRIx64 ") did not point to executable memory.", @@ -151,14 +145,13 @@ ThreadPlanStepOut::ThreadPlanStepOut( return; } - Breakpoint *return_bp = m_thread.CalculateTarget() - ->CreateBreakpoint(m_return_addr, true, false) - .get(); + Breakpoint *return_bp = + GetTarget().CreateBreakpoint(m_return_addr, true, false).get(); if (return_bp != nullptr) { if (return_bp->IsHardware() && !return_bp->HasResolvedLocations()) m_could_not_resolve_hw_bp = true; - return_bp->SetThreadID(m_thread.GetID()); + return_bp->SetThreadID(m_tid); m_return_bp_id = return_bp->GetID(); return_bp->SetBreakpointKind("step-out"); } @@ -182,9 +175,10 @@ ThreadPlanStepOut::ThreadPlanStepOut( // step out. That's more than I have time to do right now. if (frame_idx == 0) { - StackFrameSP frame_sp = m_thread.GetStackFrameAtIndex(0); + StackFrameSP frame_sp = GetThread().GetStackFrameAtIndex(0); if (frame_sp->GuessLanguage() == eLanguageTypeSwift) { - auto *swift_runtime = SwiftLanguageRuntime::Get(m_thread.GetProcess()); + auto *swift_runtime + = SwiftLanguageRuntime::Get(m_process.shared_from_this()); if (swift_runtime) { m_swift_error_return = swift_runtime->GetErrorReturnLocationBeforeReturn( @@ -205,7 +199,7 @@ void ThreadPlanStepOut::SetupAvoidNoDebug( avoid_nodebug = false; break; case eLazyBoolCalculate: - avoid_nodebug = m_thread.GetStepOutAvoidsNoDebug(); + avoid_nodebug = GetThread().GetStepOutAvoidsNoDebug(); break; } if (avoid_nodebug) @@ -215,15 +209,16 @@ void ThreadPlanStepOut::SetupAvoidNoDebug( } void ThreadPlanStepOut::DidPush() { + Thread &thread = GetThread(); if (m_step_out_to_inline_plan_sp) - m_thread.QueueThreadPlan(m_step_out_to_inline_plan_sp, false); + thread.QueueThreadPlan(m_step_out_to_inline_plan_sp, false); else if (m_step_through_inline_plan_sp) - m_thread.QueueThreadPlan(m_step_through_inline_plan_sp, false); + thread.QueueThreadPlan(m_step_through_inline_plan_sp, false); } ThreadPlanStepOut::~ThreadPlanStepOut() { if (m_return_bp_id != LLDB_INVALID_BREAK_ID) - m_thread.CalculateTarget()->RemoveBreakpointByID(m_return_bp_id); + GetTarget().RemoveBreakpointByID(m_return_bp_id); } void ThreadPlanStepOut::GetDescription(Stream *s, @@ -239,7 +234,7 @@ void ThreadPlanStepOut::GetDescription(Stream *s, s->Printf("Stepping out from "); Address tmp_address; if (tmp_address.SetLoadAddress(m_step_from_insn, &GetTarget())) { - tmp_address.Dump(s, &GetThread(), Address::DumpStyleResolvedDescription, + tmp_address.Dump(s, &m_process, Address::DumpStyleResolvedDescription, Address::DumpStyleLoadAddress); } else { s->Printf("address 0x%" PRIx64 "", (uint64_t)m_step_from_insn); @@ -251,7 +246,7 @@ void ThreadPlanStepOut::GetDescription(Stream *s, s->Printf(" returning to frame at "); if (tmp_address.SetLoadAddress(m_return_addr, &GetTarget())) { - tmp_address.Dump(s, &GetThread(), Address::DumpStyleResolvedDescription, + tmp_address.Dump(s, &m_process, Address::DumpStyleResolvedDescription, Address::DumpStyleLoadAddress); } else { s->Printf("address 0x%" PRIx64 "", (uint64_t)m_return_addr); @@ -262,6 +257,9 @@ void ThreadPlanStepOut::GetDescription(Stream *s, } } + if (m_stepped_past_frames.empty()) + return; + s->Printf("\n"); for (StackFrameSP frame_sp : m_stepped_past_frames) { s->Printf("Stepped out past: "); @@ -323,12 +321,12 @@ bool ThreadPlanStepOut::DoPlanExplainsStop(Event *event_ptr) { // If this is OUR breakpoint, we're fine, otherwise we don't know why // this happened... BreakpointSiteSP site_sp( - m_thread.GetProcess()->GetBreakpointSiteList().FindByID( - stop_info_sp->GetValue())); + m_process.GetBreakpointSiteList().FindByID(stop_info_sp->GetValue())); if (site_sp && site_sp->IsBreakpointAtThisSite(m_return_bp_id)) { bool done; - StackID frame_zero_id = m_thread.GetStackFrameAtIndex(0)->GetStackID(); + StackID frame_zero_id = + GetThread().GetStackFrameAtIndex(0)->GetStackID(); if (m_step_out_to_id == frame_zero_id) done = true; @@ -395,7 +393,7 @@ bool ThreadPlanStepOut::ShouldStop(Event *event_ptr) { } if (!done) { - StackID frame_zero_id = m_thread.GetStackFrameAtIndex(0)->GetStackID(); + StackID frame_zero_id = GetThread().GetStackFrameAtIndex(0)->GetStackID(); done = !(frame_zero_id < m_step_out_to_id); } @@ -409,6 +407,14 @@ bool ThreadPlanStepOut::ShouldStop(Event *event_ptr) { } else { m_step_out_further_plan_sp = QueueStepOutFromHerePlan(m_flags, eFrameCompareOlder, m_status); + // I have a few reports of getting here and not being able to + // actually generate a step out from here plan. That shouldn't happen + // because the ShouldStopHere callback shouldn't return true if it + // can't make a step out plan. So far I don't know how that can + // happen, but it's better to just stop here than to crash. + if (!m_step_out_further_plan_sp) + return true; + if (m_step_out_further_plan_sp->GetKind() == eKindStepOut) { // If we are planning to step out further, then the frame we are going @@ -438,8 +444,7 @@ bool ThreadPlanStepOut::DoWillResume(StateType resume_state, return false; if (current_plan) { - Breakpoint *return_bp = - m_thread.CalculateTarget()->GetBreakpointByID(m_return_bp_id).get(); + Breakpoint *return_bp = GetTarget().GetBreakpointByID(m_return_bp_id).get(); if (return_bp != nullptr) return_bp->SetEnabled(true); } @@ -448,8 +453,7 @@ bool ThreadPlanStepOut::DoWillResume(StateType resume_state, bool ThreadPlanStepOut::WillStop() { if (m_return_bp_id != LLDB_INVALID_BREAK_ID) { - Breakpoint *return_bp = - m_thread.CalculateTarget()->GetBreakpointByID(m_return_bp_id).get(); + Breakpoint *return_bp = GetTarget().GetBreakpointByID(m_return_bp_id).get(); if (return_bp != nullptr) return_bp->SetEnabled(false); } @@ -470,7 +474,7 @@ bool ThreadPlanStepOut::MischiefManaged() { if (log) LLDB_LOGF(log, "Completed step out plan."); if (m_return_bp_id != LLDB_INVALID_BREAK_ID) { - m_thread.CalculateTarget()->RemoveBreakpointByID(m_return_bp_id); + GetTarget().RemoveBreakpointByID(m_return_bp_id); m_return_bp_id = LLDB_INVALID_BREAK_ID; } @@ -485,7 +489,8 @@ bool ThreadPlanStepOut::QueueInlinedStepPlan(bool queue_now) { // Now figure out the range of this inlined block, and set up a "step through // range" plan for that. If we've been provided with a context, then use the // block in that context. - StackFrameSP immediate_return_from_sp(m_thread.GetStackFrameAtIndex(0)); + Thread &thread = GetThread(); + StackFrameSP immediate_return_from_sp(thread.GetStackFrameAtIndex(0)); if (!immediate_return_from_sp) return false; @@ -512,7 +517,7 @@ bool ThreadPlanStepOut::QueueInlinedStepPlan(bool queue_now) { m_step_through_inline_plan_sp = std::make_shared( - m_thread, inline_range, inlined_sc, run_mode, avoid_no_debug); + thread, inline_range, inlined_sc, run_mode, avoid_no_debug); ThreadPlanStepOverRange *step_through_inline_plan_ptr = static_cast( m_step_through_inline_plan_sp.get()); @@ -532,7 +537,7 @@ bool ThreadPlanStepOut::QueueInlinedStepPlan(bool queue_now) { } if (queue_now) - m_thread.QueueThreadPlan(m_step_through_inline_plan_sp, false); + thread.QueueThreadPlan(m_step_through_inline_plan_sp, false); return true; } } @@ -549,7 +554,7 @@ void ThreadPlanStepOut::CalculateReturnValue() { return; // First check if we have an error return address, and if that pointer // contains a valid error return, grab it. - auto *swift_runtime = SwiftLanguageRuntime::Get(m_thread.GetProcess()); + auto *swift_runtime = SwiftLanguageRuntime::Get(m_process.shared_from_this()); if (swift_runtime) { // In some ABI's the error is in a memory location in the caller's frame // and we need to fetch that location from the frame before we leave the @@ -557,7 +562,7 @@ void ThreadPlanStepOut::CalculateReturnValue() { // so we need to fetch the value of the address AFTER leaving the frame. if (m_swift_error_check_after_return) { - StackFrameSP frame_sp = m_thread.GetStackFrameAtIndex(0); + StackFrameSP frame_sp = GetThread().GetStackFrameAtIndex(0); if (!frame_sp) return; @@ -583,10 +588,10 @@ void ThreadPlanStepOut::CalculateReturnValue() { m_immediate_step_from_function->GetCompilerType() .GetFunctionReturnType(); if (return_compiler_type) { - lldb::ABISP abi_sp = m_thread.GetProcess()->GetABI(); + lldb::ABISP abi_sp = m_process.GetABI(); if (abi_sp) m_return_valobj_sp = - abi_sp->GetReturnValueObject(m_thread, return_compiler_type); + abi_sp->GetReturnValueObject(GetThread(), return_compiler_type); } } } @@ -595,6 +600,6 @@ bool ThreadPlanStepOut::IsPlanStale() { // If we are still lower on the stack than the frame we are returning to, // then there's something for us to do. Otherwise, we're stale. - StackID frame_zero_id = m_thread.GetStackFrameAtIndex(0)->GetStackID(); + StackID frame_zero_id = GetThread().GetStackFrameAtIndex(0)->GetStackID(); return !(frame_zero_id < m_step_out_to_id); } diff --git a/lldb/source/Target/ThreadPlanStepOverBreakpoint.cpp b/lldb/source/Target/ThreadPlanStepOverBreakpoint.cpp index 725669b1e9a8b..22498fd65f6f9 100644 --- a/lldb/source/Target/ThreadPlanStepOverBreakpoint.cpp +++ b/lldb/source/Target/ThreadPlanStepOverBreakpoint.cpp @@ -30,9 +30,9 @@ ThreadPlanStepOverBreakpoint::ThreadPlanStepOverBreakpoint(Thread &thread) m_auto_continue(false), m_reenabled_breakpoint_site(false) { - m_breakpoint_addr = m_thread.GetRegisterContext()->GetPC(); + m_breakpoint_addr = thread.GetRegisterContext()->GetPC(); m_breakpoint_site_id = - m_thread.GetProcess()->GetBreakpointSiteList().FindIDByAddress( + thread.GetProcess()->GetBreakpointSiteList().FindIDByAddress( m_breakpoint_addr); } @@ -86,7 +86,7 @@ bool ThreadPlanStepOverBreakpoint::DoPlanExplainsStop(Event *event_ptr) { // Be careful, however, as we may have "seen a breakpoint under the PC // because we stopped without changing the PC, in which case we do want // to re-claim this stop so we'll try again. - lldb::addr_t pc_addr = m_thread.GetRegisterContext()->GetPC(); + lldb::addr_t pc_addr = GetThread().GetRegisterContext()->GetPC(); if (pc_addr == m_breakpoint_addr) { LLDB_LOGF(log, @@ -120,10 +120,9 @@ bool ThreadPlanStepOverBreakpoint::DoWillResume(StateType resume_state, bool current_plan) { if (current_plan) { BreakpointSiteSP bp_site_sp( - m_thread.GetProcess()->GetBreakpointSiteList().FindByAddress( - m_breakpoint_addr)); + m_process.GetBreakpointSiteList().FindByAddress(m_breakpoint_addr)); if (bp_site_sp && bp_site_sp->IsEnabled()) { - m_thread.GetProcess()->DisableBreakpointSite(bp_site_sp.get()); + m_process.DisableBreakpointSite(bp_site_sp.get()); m_reenabled_breakpoint_site = false; } } @@ -140,7 +139,7 @@ void ThreadPlanStepOverBreakpoint::WillPop() { } bool ThreadPlanStepOverBreakpoint::MischiefManaged() { - lldb::addr_t pc_addr = m_thread.GetRegisterContext()->GetPC(); + lldb::addr_t pc_addr = GetThread().GetRegisterContext()->GetPC(); if (pc_addr == m_breakpoint_addr) { // If we are still at the PC of our breakpoint, then for some reason we @@ -161,10 +160,9 @@ void ThreadPlanStepOverBreakpoint::ReenableBreakpointSite() { if (!m_reenabled_breakpoint_site) { m_reenabled_breakpoint_site = true; BreakpointSiteSP bp_site_sp( - m_thread.GetProcess()->GetBreakpointSiteList().FindByAddress( - m_breakpoint_addr)); + m_process.GetBreakpointSiteList().FindByAddress(m_breakpoint_addr)); if (bp_site_sp) { - m_thread.GetProcess()->EnableBreakpointSite(bp_site_sp.get()); + m_process.EnableBreakpointSite(bp_site_sp.get()); } } } @@ -181,5 +179,5 @@ bool ThreadPlanStepOverBreakpoint::ShouldAutoContinue(Event *event_ptr) { } bool ThreadPlanStepOverBreakpoint::IsPlanStale() { - return m_thread.GetRegisterContext()->GetPC() != m_breakpoint_addr; + return GetThread().GetRegisterContext()->GetPC() != m_breakpoint_addr; } diff --git a/lldb/source/Target/ThreadPlanStepOverRange.cpp b/lldb/source/Target/ThreadPlanStepOverRange.cpp index 3dc1967e6d4e5..ab49a37bc8d55 100644 --- a/lldb/source/Target/ThreadPlanStepOverRange.cpp +++ b/lldb/source/Target/ThreadPlanStepOverRange.cpp @@ -85,7 +85,7 @@ void ThreadPlanStepOverRange::SetupAvoidNoDebug( avoid_nodebug = false; break; case eLazyBoolCalculate: - avoid_nodebug = m_thread.GetStepOutAvoidsNoDebug(); + avoid_nodebug = GetThread().GetStepOutAvoidsNoDebug(); break; } if (avoid_nodebug) @@ -125,12 +125,12 @@ bool ThreadPlanStepOverRange::IsEquivalentContext( bool ThreadPlanStepOverRange::ShouldStop(Event *event_ptr) { Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_STEP)); + Thread &thread = GetThread(); if (log) { StreamString s; - DumpAddress( - s.AsRawOstream(), m_thread.GetRegisterContext()->GetPC(), - m_thread.CalculateTarget()->GetArchitecture().GetAddressByteSize()); + DumpAddress(s.AsRawOstream(), thread.GetRegisterContext()->GetPC(), + GetTarget().GetArchitecture().GetAddressByteSize()); LLDB_LOGF(log, "ThreadPlanStepOverRange reached %s.", s.GetData()); } @@ -151,8 +151,8 @@ bool ThreadPlanStepOverRange::ShouldStop(Event *event_ptr) { // because the trampoline confused the backtracer. As below, we step // through first, and then try to figure out how to get back out again. - new_plan_sp = m_thread.QueueThreadPlanForStepThrough(m_stack_id, false, - stop_others, m_status); + new_plan_sp = thread.QueueThreadPlanForStepThrough(m_stack_id, false, + stop_others, m_status); if (new_plan_sp && log) LLDB_LOGF(log, @@ -161,7 +161,7 @@ bool ThreadPlanStepOverRange::ShouldStop(Event *event_ptr) { // Make sure we really are in a new frame. Do that by unwinding and seeing // if the start function really is our start function... for (uint32_t i = 1;; ++i) { - StackFrameSP older_frame_sp = m_thread.GetStackFrameAtIndex(i); + StackFrameSP older_frame_sp = thread.GetStackFrameAtIndex(i); if (!older_frame_sp) { // We can't unwind the next frame we should just get out of here & // stop... @@ -171,12 +171,12 @@ bool ThreadPlanStepOverRange::ShouldStop(Event *event_ptr) { const SymbolContext &older_context = older_frame_sp->GetSymbolContext(eSymbolContextEverything); if (IsEquivalentContext(older_context)) { - new_plan_sp = m_thread.QueueThreadPlanForStepOutNoShouldStop( + new_plan_sp = thread.QueueThreadPlanForStepOutNoShouldStop( false, nullptr, true, stop_others, eVoteNo, eVoteNoOpinion, 0, m_status, true); break; } else { - new_plan_sp = m_thread.QueueThreadPlanForStepThrough( + new_plan_sp = thread.QueueThreadPlanForStepThrough( m_stack_id, false, stop_others, m_status); // If we found a way through, then we should stop recursing. if (new_plan_sp) @@ -196,8 +196,8 @@ bool ThreadPlanStepOverRange::ShouldStop(Event *event_ptr) { // we are in a stub then it's likely going to be hard to get out from // here. It is probably easiest to step into the stub, and then it will // be straight-forward to step out. - new_plan_sp = m_thread.QueueThreadPlanForStepThrough( - m_stack_id, false, stop_others, m_status); + new_plan_sp = thread.QueueThreadPlanForStepThrough(m_stack_id, false, + stop_others, m_status); } else { // The current clang (at least through 424) doesn't always get the // address range for the DW_TAG_inlined_subroutines right, so that when @@ -212,7 +212,7 @@ bool ThreadPlanStepOverRange::ShouldStop(Event *event_ptr) { if (m_addr_context.line_entry.IsValid()) { SymbolContext sc; - StackFrameSP frame_sp = m_thread.GetStackFrameAtIndex(0); + StackFrameSP frame_sp = thread.GetStackFrameAtIndex(0); sc = frame_sp->GetSymbolContext(eSymbolContextEverything); if (sc.line_entry.IsValid()) { if (sc.line_entry.original_file != @@ -278,7 +278,7 @@ bool ThreadPlanStepOverRange::ShouldStop(Event *event_ptr) { m_addr_context.line_entry.original_file) { const bool abort_other_plans = false; const RunMode stop_other_threads = RunMode::eAllThreads; - lldb::addr_t cur_pc = m_thread.GetStackFrameAtIndex(0) + lldb::addr_t cur_pc = thread.GetStackFrameAtIndex(0) ->GetRegisterContext() ->GetPC(); AddressRange step_range( @@ -286,7 +286,7 @@ bool ThreadPlanStepOverRange::ShouldStop(Event *event_ptr) { next_line_address.GetLoadAddress(&GetTarget()) - cur_pc); - new_plan_sp = m_thread.QueueThreadPlanForStepOverRange( + new_plan_sp = thread.QueueThreadPlanForStepOverRange( abort_other_plans, step_range, sc, stop_other_threads, m_status); break; @@ -365,23 +365,24 @@ bool ThreadPlanStepOverRange::DoWillResume(lldb::StateType resume_state, if (resume_state != eStateSuspended && m_first_resume) { m_first_resume = false; if (resume_state == eStateStepping && current_plan) { + Thread &thread = GetThread(); // See if we are about to step over an inlined call in the middle of the // inlined stack, if so figure out its extents and reset our range to // step over that. - bool in_inlined_stack = m_thread.DecrementCurrentInlinedDepth(); + bool in_inlined_stack = thread.DecrementCurrentInlinedDepth(); if (in_inlined_stack) { Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_STEP)); LLDB_LOGF(log, "ThreadPlanStepInRange::DoWillResume: adjusting range to " "the frame at inlined depth %d.", - m_thread.GetCurrentInlinedDepth()); - StackFrameSP stack_sp = m_thread.GetStackFrameAtIndex(0); + thread.GetCurrentInlinedDepth()); + StackFrameSP stack_sp = thread.GetStackFrameAtIndex(0); if (stack_sp) { Block *frame_block = stack_sp->GetFrameBlock(); - lldb::addr_t curr_pc = m_thread.GetRegisterContext()->GetPC(); + lldb::addr_t curr_pc = thread.GetRegisterContext()->GetPC(); AddressRange my_range; if (frame_block->GetRangeContainingLoadAddress( - curr_pc, m_thread.GetProcess()->GetTarget(), my_range)) { + curr_pc, m_process.GetTarget(), my_range)) { m_address_ranges.clear(); m_address_ranges.push_back(my_range); if (log) { diff --git a/lldb/source/Target/ThreadPlanStepRange.cpp b/lldb/source/Target/ThreadPlanStepRange.cpp index f3040cecb1904..dd0ae95ea97aa 100644 --- a/lldb/source/Target/ThreadPlanStepRange.cpp +++ b/lldb/source/Target/ThreadPlanStepRange.cpp @@ -41,8 +41,8 @@ ThreadPlanStepRange::ThreadPlanStepRange(ThreadPlanKind kind, const char *name, m_given_ranges_only(given_ranges_only) { m_use_fast_step = GetTarget().GetUseFastStepping(); AddRange(range); - m_stack_id = m_thread.GetStackFrameAtIndex(0)->GetStackID(); - StackFrameSP parent_stack = m_thread.GetStackFrameAtIndex(1); + m_stack_id = thread.GetStackFrameAtIndex(0)->GetStackID(); + StackFrameSP parent_stack = thread.GetStackFrameAtIndex(1); if (parent_stack) m_parent_stack_id = parent_stack->GetStackID(); } @@ -88,13 +88,11 @@ void ThreadPlanStepRange::AddRange(const AddressRange &new_range) { void ThreadPlanStepRange::DumpRanges(Stream *s) { size_t num_ranges = m_address_ranges.size(); if (num_ranges == 1) { - m_address_ranges[0].Dump(s, m_thread.CalculateTarget().get(), - Address::DumpStyleLoadAddress); + m_address_ranges[0].Dump(s, &GetTarget(), Address::DumpStyleLoadAddress); } else { for (size_t i = 0; i < num_ranges; i++) { s->Printf(" %" PRIu64 ": ", uint64_t(i)); - m_address_ranges[i].Dump(s, m_thread.CalculateTarget().get(), - Address::DumpStyleLoadAddress); + m_address_ranges[i].Dump(s, &GetTarget(), Address::DumpStyleLoadAddress); } } } @@ -102,20 +100,20 @@ void ThreadPlanStepRange::DumpRanges(Stream *s) { bool ThreadPlanStepRange::InRange() { Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_STEP)); bool ret_value = false; - - lldb::addr_t pc_load_addr = m_thread.GetRegisterContext()->GetPC(); + Thread &thread = GetThread(); + lldb::addr_t pc_load_addr = thread.GetRegisterContext()->GetPC(); size_t num_ranges = m_address_ranges.size(); for (size_t i = 0; i < num_ranges; i++) { - ret_value = m_address_ranges[i].ContainsLoadAddress( - pc_load_addr, m_thread.CalculateTarget().get()); + ret_value = + m_address_ranges[i].ContainsLoadAddress(pc_load_addr, &GetTarget()); if (ret_value) break; } if (!ret_value && !m_given_ranges_only) { // See if we've just stepped to another part of the same line number... - StackFrame *frame = m_thread.GetStackFrameAtIndex(0).get(); + StackFrame *frame = thread.GetStackFrameAtIndex(0).get(); SymbolContext new_context( frame->GetSymbolContext(eSymbolContextEverything)); @@ -132,8 +130,8 @@ bool ThreadPlanStepRange::InRange() { ret_value = true; if (log) { StreamString s; - m_addr_context.line_entry.Dump(&s, m_thread.CalculateTarget().get(), - true, Address::DumpStyleLoadAddress, + m_addr_context.line_entry.Dump(&s, &GetTarget(), true, + Address::DumpStyleLoadAddress, Address::DumpStyleLoadAddress, true); LLDB_LOGF( @@ -151,8 +149,8 @@ bool ThreadPlanStepRange::InRange() { ret_value = true; if (log) { StreamString s; - m_addr_context.line_entry.Dump(&s, m_thread.CalculateTarget().get(), - true, Address::DumpStyleLoadAddress, + m_addr_context.line_entry.Dump(&s, &GetTarget(), true, + Address::DumpStyleLoadAddress, Address::DumpStyleLoadAddress, true); LLDB_LOGF(log, @@ -161,7 +159,7 @@ bool ThreadPlanStepRange::InRange() { s.GetData()); } } else if (new_context.line_entry.range.GetBaseAddress().GetLoadAddress( - m_thread.CalculateTarget().get()) != pc_load_addr) { + &GetTarget()) != pc_load_addr) { // Another thing that sometimes happens here is that we step out of // one line into the MIDDLE of another line. So far I mostly see // this due to bugs in the debug information. But we probably don't @@ -174,8 +172,8 @@ bool ThreadPlanStepRange::InRange() { ret_value = true; if (log) { StreamString s; - m_addr_context.line_entry.Dump(&s, m_thread.CalculateTarget().get(), - true, Address::DumpStyleLoadAddress, + m_addr_context.line_entry.Dump(&s, &GetTarget(), true, + Address::DumpStyleLoadAddress, Address::DumpStyleLoadAddress, true); LLDB_LOGF(log, @@ -195,14 +193,14 @@ bool ThreadPlanStepRange::InRange() { } bool ThreadPlanStepRange::InSymbol() { - lldb::addr_t cur_pc = m_thread.GetRegisterContext()->GetPC(); + lldb::addr_t cur_pc = GetThread().GetRegisterContext()->GetPC(); if (m_addr_context.function != nullptr) { return m_addr_context.function->GetAddressRange().ContainsLoadAddress( - cur_pc, m_thread.CalculateTarget().get()); + cur_pc, &GetTarget()); } else if (m_addr_context.symbol && m_addr_context.symbol->ValueIsAddress()) { AddressRange range(m_addr_context.symbol->GetAddressRef(), m_addr_context.symbol->GetByteSize()); - return range.ContainsLoadAddress(cur_pc, m_thread.CalculateTarget().get()); + return range.ContainsLoadAddress(cur_pc, &GetTarget()); } return false; } @@ -216,15 +214,15 @@ bool ThreadPlanStepRange::InSymbol() { lldb::FrameComparison ThreadPlanStepRange::CompareCurrentFrameToStartFrame() { FrameComparison frame_order; - - StackID cur_frame_id = m_thread.GetStackFrameAtIndex(0)->GetStackID(); + Thread &thread = GetThread(); + StackID cur_frame_id = thread.GetStackFrameAtIndex(0)->GetStackID(); if (cur_frame_id == m_stack_id) { frame_order = eFrameCompareEqual; } else if (cur_frame_id < m_stack_id) { frame_order = eFrameCompareYounger; } else { - StackFrameSP cur_parent_frame = m_thread.GetStackFrameAtIndex(1); + StackFrameSP cur_parent_frame = thread.GetStackFrameAtIndex(1); StackID cur_parent_id; if (cur_parent_frame) cur_parent_id = cur_parent_frame->GetStackID(); @@ -264,7 +262,7 @@ InstructionList *ThreadPlanStepRange::GetInstructionsForAddress( if (!m_instruction_ranges[i]) { // Disassemble the address range given: - ExecutionContext exe_ctx(m_thread.GetProcess()); + ExecutionContext exe_ctx(&m_process); const char *plugin_name = nullptr; const char *flavor = nullptr; const bool prefer_file_cache = true; @@ -378,11 +376,10 @@ bool ThreadPlanStepRange::SetNextBranchBreakpoint() { "ThreadPlanStepRange::SetNextBranchBreakpoint - Setting " "breakpoint %d (site %d) to run to address 0x%" PRIx64, m_next_branch_bp_sp->GetID(), bp_site_id, - run_to_address.GetLoadAddress( - &m_thread.GetProcess()->GetTarget())); + run_to_address.GetLoadAddress(&m_process.GetTarget())); } - m_next_branch_bp_sp->SetThreadID(m_thread.GetID()); + m_next_branch_bp_sp->SetThreadID(m_tid); m_next_branch_bp_sp->SetBreakpointKind("next-branch-location"); return true; @@ -401,7 +398,7 @@ bool ThreadPlanStepRange::NextRangeBreakpointExplainsStop( break_id_t bp_site_id = stop_info_sp->GetValue(); BreakpointSiteSP bp_site_sp = - m_thread.GetProcess()->GetBreakpointSiteList().FindByID(bp_site_id); + m_process.GetBreakpointSiteList().FindByID(bp_site_id); if (!bp_site_sp) return false; else if (!bp_site_sp->IsBreakpointAtThisSite(m_next_branch_bp_sp->GetID())) @@ -488,11 +485,11 @@ bool ThreadPlanStepRange::IsPlanStale() { // check that we are in the same symbol. if (!InRange()) { // Set plan Complete when we reach next instruction just after the range - lldb::addr_t addr = m_thread.GetRegisterContext()->GetPC() - 1; + lldb::addr_t addr = GetThread().GetRegisterContext()->GetPC() - 1; size_t num_ranges = m_address_ranges.size(); for (size_t i = 0; i < num_ranges; i++) { - bool in_range = m_address_ranges[i].ContainsLoadAddress( - addr, m_thread.CalculateTarget().get()); + bool in_range = + m_address_ranges[i].ContainsLoadAddress(addr, &GetTarget()); if (in_range) { SetPlanComplete(); } diff --git a/lldb/source/Target/ThreadPlanStepThrough.cpp b/lldb/source/Target/ThreadPlanStepThrough.cpp index 8c7b180fce2d3..8d5939741323a 100644 --- a/lldb/source/Target/ThreadPlanStepThrough.cpp +++ b/lldb/source/Target/ThreadPlanStepThrough.cpp @@ -44,21 +44,20 @@ ThreadPlanStepThrough::ThreadPlanStepThrough(Thread &thread, // some inlined code that we're in the middle of by doing this, but it's // easier than trying to figure out where the inlined code might return to. - StackFrameSP return_frame_sp = m_thread.GetFrameWithStackID(m_stack_id); + StackFrameSP return_frame_sp = thread.GetFrameWithStackID(m_stack_id); if (return_frame_sp) { m_backstop_addr = return_frame_sp->GetFrameCodeAddress().GetLoadAddress( - m_thread.CalculateTarget().get()); + thread.CalculateTarget().get()); Breakpoint *return_bp = - m_thread.GetProcess() - ->GetTarget() + m_process.GetTarget() .CreateBreakpoint(m_backstop_addr, true, false) .get(); if (return_bp != nullptr) { if (return_bp->IsHardware() && !return_bp->HasResolvedLocations()) m_could_not_resolve_hw_bp = true; - return_bp->SetThreadID(m_thread.GetID()); + return_bp->SetThreadID(m_tid); m_backstop_bkpt_id = return_bp->GetID(); return_bp->SetBreakpointKind("step-through-backstop"); } @@ -79,18 +78,17 @@ void ThreadPlanStepThrough::DidPush() { } void ThreadPlanStepThrough::LookForPlanToStepThroughFromCurrentPC() { - DynamicLoader *loader = m_thread.GetProcess()->GetDynamicLoader(); + Thread &thread = GetThread(); + DynamicLoader *loader = thread.GetProcess()->GetDynamicLoader(); if (loader) - m_sub_plan_sp = - loader->GetStepThroughTrampolinePlan(m_thread, m_stop_others); + m_sub_plan_sp = loader->GetStepThroughTrampolinePlan(thread, m_stop_others); // If the DynamicLoader was unable to provide us with a ThreadPlan, then we // try the LanguageRuntimes. if (!m_sub_plan_sp) { - for (LanguageRuntime *runtime : - m_thread.GetProcess()->GetLanguageRuntimes()) { + for (LanguageRuntime *runtime : m_process.GetLanguageRuntimes()) { m_sub_plan_sp = - runtime->GetStepThroughTrampolinePlan(m_thread, m_stop_others); + runtime->GetStepThroughTrampolinePlan(thread, m_stop_others); if (m_sub_plan_sp) break; @@ -223,7 +221,7 @@ bool ThreadPlanStepThrough::WillStop() { return true; } void ThreadPlanStepThrough::ClearBackstopBreakpoint() { if (m_backstop_bkpt_id != LLDB_INVALID_BREAK_ID) { - m_thread.GetProcess()->GetTarget().RemoveBreakpointByID(m_backstop_bkpt_id); + m_process.GetTarget().RemoveBreakpointByID(m_backstop_bkpt_id); m_backstop_bkpt_id = LLDB_INVALID_BREAK_ID; m_could_not_resolve_hw_bp = false; } @@ -244,15 +242,15 @@ bool ThreadPlanStepThrough::MischiefManaged() { } bool ThreadPlanStepThrough::HitOurBackstopBreakpoint() { - StopInfoSP stop_info_sp(m_thread.GetStopInfo()); + Thread &thread = GetThread(); + StopInfoSP stop_info_sp(thread.GetStopInfo()); if (stop_info_sp && stop_info_sp->GetStopReason() == eStopReasonBreakpoint) { break_id_t stop_value = (break_id_t)stop_info_sp->GetValue(); BreakpointSiteSP cur_site_sp = - m_thread.GetProcess()->GetBreakpointSiteList().FindByID(stop_value); + m_process.GetBreakpointSiteList().FindByID(stop_value); if (cur_site_sp && cur_site_sp->IsBreakpointAtThisSite(m_backstop_bkpt_id)) { - StackID cur_frame_zero_id = - m_thread.GetStackFrameAtIndex(0)->GetStackID(); + StackID cur_frame_zero_id = thread.GetStackFrameAtIndex(0)->GetStackID(); if (cur_frame_zero_id == m_return_stack_id) { Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_STEP)); diff --git a/lldb/source/Target/ThreadPlanStepUntil.cpp b/lldb/source/Target/ThreadPlanStepUntil.cpp index 54d276337488d..8de7505d86e2b 100644 --- a/lldb/source/Target/ThreadPlanStepUntil.cpp +++ b/lldb/source/Target/ThreadPlanStepUntil.cpp @@ -34,17 +34,16 @@ ThreadPlanStepUntil::ThreadPlanStepUntil(Thread &thread, m_should_stop(false), m_ran_analyze(false), m_explains_stop(false), m_until_points(), m_stop_others(stop_others) { // Stash away our "until" addresses: - TargetSP target_sp(m_thread.CalculateTarget()); + TargetSP target_sp(thread.CalculateTarget()); - StackFrameSP frame_sp(m_thread.GetStackFrameAtIndex(frame_idx)); + StackFrameSP frame_sp(thread.GetStackFrameAtIndex(frame_idx)); if (frame_sp) { m_step_from_insn = frame_sp->GetStackID().GetPC(); - lldb::user_id_t thread_id = m_thread.GetID(); // Find the return address and set a breakpoint there: // FIXME - can we do this more securely if we know first_insn? - StackFrameSP return_frame_sp(m_thread.GetStackFrameAtIndex(frame_idx + 1)); + StackFrameSP return_frame_sp(thread.GetStackFrameAtIndex(frame_idx + 1)); if (return_frame_sp) { // TODO: add inline functionality m_return_addr = return_frame_sp->GetStackID().GetPC(); @@ -54,7 +53,7 @@ ThreadPlanStepUntil::ThreadPlanStepUntil(Thread &thread, if (return_bp != nullptr) { if (return_bp->IsHardware() && !return_bp->HasResolvedLocations()) m_could_not_resolve_hw_bp = true; - return_bp->SetThreadID(thread_id); + return_bp->SetThreadID(m_tid); m_return_bp_id = return_bp->GetID(); return_bp->SetBreakpointKind("until-return-backstop"); } @@ -67,7 +66,7 @@ ThreadPlanStepUntil::ThreadPlanStepUntil(Thread &thread, Breakpoint *until_bp = target_sp->CreateBreakpoint(address_list[i], true, false).get(); if (until_bp != nullptr) { - until_bp->SetThreadID(thread_id); + until_bp->SetThreadID(m_tid); m_until_points[address_list[i]] = until_bp->GetID(); until_bp->SetBreakpointKind("until-target"); } else { @@ -80,17 +79,15 @@ ThreadPlanStepUntil::ThreadPlanStepUntil(Thread &thread, ThreadPlanStepUntil::~ThreadPlanStepUntil() { Clear(); } void ThreadPlanStepUntil::Clear() { - TargetSP target_sp(m_thread.CalculateTarget()); - if (target_sp) { - if (m_return_bp_id != LLDB_INVALID_BREAK_ID) { - target_sp->RemoveBreakpointByID(m_return_bp_id); - m_return_bp_id = LLDB_INVALID_BREAK_ID; - } + Target &target = GetTarget(); + if (m_return_bp_id != LLDB_INVALID_BREAK_ID) { + target.RemoveBreakpointByID(m_return_bp_id); + m_return_bp_id = LLDB_INVALID_BREAK_ID; + } - until_collection::iterator pos, end = m_until_points.end(); - for (pos = m_until_points.begin(); pos != end; pos++) { - target_sp->RemoveBreakpointByID((*pos).second); - } + until_collection::iterator pos, end = m_until_points.end(); + for (pos = m_until_points.begin(); pos != end; pos++) { + target.RemoveBreakpointByID((*pos).second); } m_until_points.clear(); m_could_not_resolve_hw_bp = false; @@ -158,8 +155,7 @@ void ThreadPlanStepUntil::AnalyzeStop() { // If this is OUR breakpoint, we're fine, otherwise we don't know why // this happened... BreakpointSiteSP this_site = - m_thread.GetProcess()->GetBreakpointSiteList().FindByID( - stop_info_sp->GetValue()); + m_process.GetBreakpointSiteList().FindByID(stop_info_sp->GetValue()); if (!this_site) { m_explains_stop = false; return; @@ -196,17 +192,17 @@ void ThreadPlanStepUntil::AnalyzeStop() { for (pos = m_until_points.begin(); pos != end; pos++) { if (this_site->IsBreakpointAtThisSite((*pos).second)) { // If we're at the right stack depth, then we're done. - + Thread &thread = GetThread(); bool done; StackID frame_zero_id = - m_thread.GetStackFrameAtIndex(0)->GetStackID(); + thread.GetStackFrameAtIndex(0)->GetStackID(); if (frame_zero_id == m_stack_id) done = true; else if (frame_zero_id < m_stack_id) done = false; else { - StackFrameSP older_frame_sp = m_thread.GetStackFrameAtIndex(1); + StackFrameSP older_frame_sp = thread.GetStackFrameAtIndex(1); // But if we can't even unwind one frame we should just get out // of here & stop... @@ -280,20 +276,16 @@ StateType ThreadPlanStepUntil::GetPlanRunState() { return eStateRunning; } bool ThreadPlanStepUntil::DoWillResume(StateType resume_state, bool current_plan) { if (current_plan) { - TargetSP target_sp(m_thread.CalculateTarget()); - if (target_sp) { - Breakpoint *return_bp = - target_sp->GetBreakpointByID(m_return_bp_id).get(); - if (return_bp != nullptr) - return_bp->SetEnabled(true); + Target &target = GetTarget(); + Breakpoint *return_bp = target.GetBreakpointByID(m_return_bp_id).get(); + if (return_bp != nullptr) + return_bp->SetEnabled(true); - until_collection::iterator pos, end = m_until_points.end(); - for (pos = m_until_points.begin(); pos != end; pos++) { - Breakpoint *until_bp = - target_sp->GetBreakpointByID((*pos).second).get(); - if (until_bp != nullptr) - until_bp->SetEnabled(true); - } + until_collection::iterator pos, end = m_until_points.end(); + for (pos = m_until_points.begin(); pos != end; pos++) { + Breakpoint *until_bp = target.GetBreakpointByID((*pos).second).get(); + if (until_bp != nullptr) + until_bp->SetEnabled(true); } } @@ -304,18 +296,16 @@ bool ThreadPlanStepUntil::DoWillResume(StateType resume_state, } bool ThreadPlanStepUntil::WillStop() { - TargetSP target_sp(m_thread.CalculateTarget()); - if (target_sp) { - Breakpoint *return_bp = target_sp->GetBreakpointByID(m_return_bp_id).get(); - if (return_bp != nullptr) - return_bp->SetEnabled(false); - - until_collection::iterator pos, end = m_until_points.end(); - for (pos = m_until_points.begin(); pos != end; pos++) { - Breakpoint *until_bp = target_sp->GetBreakpointByID((*pos).second).get(); - if (until_bp != nullptr) - until_bp->SetEnabled(false); - } + Target &target = GetTarget(); + Breakpoint *return_bp = target.GetBreakpointByID(m_return_bp_id).get(); + if (return_bp != nullptr) + return_bp->SetEnabled(false); + + until_collection::iterator pos, end = m_until_points.end(); + for (pos = m_until_points.begin(); pos != end; pos++) { + Breakpoint *until_bp = target.GetBreakpointByID((*pos).second).get(); + if (until_bp != nullptr) + until_bp->SetEnabled(false); } return true; } diff --git a/lldb/source/Target/ThreadPlanTracer.cpp b/lldb/source/Target/ThreadPlanTracer.cpp index b50c1636b7ff7..fb31eb9829d21 100644 --- a/lldb/source/Target/ThreadPlanTracer.cpp +++ b/lldb/source/Target/ThreadPlanTracer.cpp @@ -34,23 +34,32 @@ using namespace lldb_private; #pragma mark ThreadPlanTracer ThreadPlanTracer::ThreadPlanTracer(Thread &thread, lldb::StreamSP &stream_sp) - : m_thread(thread), m_single_step(true), m_enabled(false), - m_stream_sp(stream_sp) {} + : m_process(*thread.GetProcess().get()), m_tid(thread.GetID()), + m_single_step(true), m_enabled(false), m_stream_sp(stream_sp) {} ThreadPlanTracer::ThreadPlanTracer(Thread &thread) - : m_thread(thread), m_single_step(true), m_enabled(false), m_stream_sp() {} + : m_process(*thread.GetProcess().get()), m_tid(thread.GetID()), + m_single_step(true), m_enabled(false), m_stream_sp() {} Stream *ThreadPlanTracer::GetLogStream() { if (m_stream_sp) return m_stream_sp.get(); else { - TargetSP target_sp(m_thread.CalculateTarget()); + TargetSP target_sp(GetThread().CalculateTarget()); if (target_sp) return &(target_sp->GetDebugger().GetOutputStream()); } return nullptr; } +Thread &ThreadPlanTracer::GetThread() { + if (m_thread) + return *m_thread; + + ThreadSP thread_sp = m_process.GetThreadList().FindThreadByID(m_tid); + m_thread = thread_sp.get(); + return *m_thread; +} void ThreadPlanTracer::Log() { SymbolContext sc; bool show_frame_index = false; @@ -58,8 +67,8 @@ void ThreadPlanTracer::Log() { Stream *stream = GetLogStream(); if (stream) { - m_thread.GetStackFrameAtIndex(0)->Dump(stream, show_frame_index, - show_fullpaths); + GetThread().GetStackFrameAtIndex(0)->Dump(stream, show_frame_index, + show_fullpaths); stream->Printf("\n"); stream->Flush(); } @@ -67,7 +76,7 @@ void ThreadPlanTracer::Log() { bool ThreadPlanTracer::TracerExplainsStop() { if (m_enabled && m_single_step) { - lldb::StopInfoSP stop_info = m_thread.GetStopInfo(); + lldb::StopInfoSP stop_info = GetThread().GetStopInfo(); return (stop_info->GetStopReason() == eStopReasonTrace); } else return false; @@ -87,13 +96,13 @@ ThreadPlanAssemblyTracer::ThreadPlanAssemblyTracer(Thread &thread) Disassembler *ThreadPlanAssemblyTracer::GetDisassembler() { if (!m_disassembler_sp) m_disassembler_sp = Disassembler::FindPlugin( - m_thread.GetProcess()->GetTarget().GetArchitecture(), nullptr, nullptr); + m_process.GetTarget().GetArchitecture(), nullptr, nullptr); return m_disassembler_sp.get(); } TypeFromUser ThreadPlanAssemblyTracer::GetIntPointerType() { if (!m_intptr_type.IsValid()) { - if (auto target_sp = m_thread.CalculateTarget()) { + if (auto target_sp = m_process.CalculateTarget()) { auto type_system_or_err = target_sp->GetScratchTypeSystemForLanguage(eLanguageTypeC); if (auto err = type_system_or_err.takeError()) { @@ -125,29 +134,27 @@ void ThreadPlanAssemblyTracer::Log() { if (!stream) return; - RegisterContext *reg_ctx = m_thread.GetRegisterContext().get(); + RegisterContext *reg_ctx = GetThread().GetRegisterContext().get(); lldb::addr_t pc = reg_ctx->GetPC(); - ProcessSP process_sp(m_thread.GetProcess()); Address pc_addr; bool addr_valid = false; uint8_t buffer[16] = {0}; // Must be big enough for any single instruction - addr_valid = process_sp->GetTarget().GetSectionLoadList().ResolveLoadAddress( + addr_valid = m_process.GetTarget().GetSectionLoadList().ResolveLoadAddress( pc, pc_addr); - pc_addr.Dump(stream, &m_thread, Address::DumpStyleResolvedDescription, + pc_addr.Dump(stream, &GetThread(), Address::DumpStyleResolvedDescription, Address::DumpStyleModuleWithFileAddress); stream->PutCString(" "); Disassembler *disassembler = GetDisassembler(); if (disassembler) { Status err; - process_sp->ReadMemory(pc, buffer, sizeof(buffer), err); + m_process.ReadMemory(pc, buffer, sizeof(buffer), err); if (err.Success()) { - DataExtractor extractor(buffer, sizeof(buffer), - process_sp->GetByteOrder(), - process_sp->GetAddressByteSize()); + DataExtractor extractor(buffer, sizeof(buffer), m_process.GetByteOrder(), + m_process.GetAddressByteSize()); bool data_from_file = false; if (addr_valid) @@ -167,10 +174,7 @@ void ThreadPlanAssemblyTracer::Log() { Instruction *instruction = instruction_list.GetInstructionAtIndex(0).get(); const FormatEntity::Entry *disassemble_format = - m_thread.GetProcess() - ->GetTarget() - .GetDebugger() - .GetDisassemblyFormat(); + m_process.GetTarget().GetDebugger().GetDisassemblyFormat(); instruction->Dump(stream, max_opcode_byte_size, show_address, show_bytes, nullptr, nullptr, nullptr, disassemble_format, 0); @@ -178,7 +182,7 @@ void ThreadPlanAssemblyTracer::Log() { } } - const ABI *abi = process_sp->GetABI().get(); + const ABI *abi = m_process.GetABI().get(); TypeFromUser intptr_type = GetIntPointerType(); if (abi && intptr_type.IsValid()) { @@ -192,7 +196,7 @@ void ThreadPlanAssemblyTracer::Log() { value_list.PushValue(value); } - if (abi->GetArgumentValues(m_thread, value_list)) { + if (abi->GetArgumentValues(GetThread(), value_list)) { for (int arg_index = 0; arg_index < num_args; ++arg_index) { stream->Printf( "\n\targ[%d]=%llx", arg_index, @@ -205,7 +209,7 @@ void ThreadPlanAssemblyTracer::Log() { } if (m_register_values.empty()) { - RegisterContext *reg_ctx = m_thread.GetRegisterContext().get(); + RegisterContext *reg_ctx = GetThread().GetRegisterContext().get(); m_register_values.resize(reg_ctx->GetRegisterCount()); } diff --git a/lldb/source/Utility/ArchSpec.cpp b/lldb/source/Utility/ArchSpec.cpp index 3dae25ceacd6c..0507710204a7a 100644 --- a/lldb/source/Utility/ArchSpec.cpp +++ b/lldb/source/Utility/ArchSpec.cpp @@ -1460,3 +1460,15 @@ void ArchSpec::DumpTriple(llvm::raw_ostream &s) const { if (!environ_str.empty()) s << "-" << environ_str; } + +void llvm::yaml::ScalarTraits::output(const ArchSpec &Val, void *, + raw_ostream &Out) { + Val.DumpTriple(Out); +} + +llvm::StringRef +llvm::yaml::ScalarTraits::input(llvm::StringRef Scalar, void *, + ArchSpec &Val) { + Val = ArchSpec(Scalar); + return {}; +} diff --git a/lldb/source/Utility/CMakeLists.txt b/lldb/source/Utility/CMakeLists.txt index df486e2c0a4ca..0d82640019a27 100644 --- a/lldb/source/Utility/CMakeLists.txt +++ b/lldb/source/Utility/CMakeLists.txt @@ -58,6 +58,7 @@ add_lldb_library(lldbUtility UserIDResolver.cpp VASprintf.cpp VMRange.cpp + XcodeSDK.cpp LINK_LIBS ${LLDB_SYSTEM_LIBS} diff --git a/lldb/source/Utility/ConstString.cpp b/lldb/source/Utility/ConstString.cpp index e90bb929bb81f..6bcb10d971be2 100644 --- a/lldb/source/Utility/ConstString.cpp +++ b/lldb/source/Utility/ConstString.cpp @@ -309,3 +309,15 @@ void llvm::format_provider::format(const ConstString &CS, llvm::StringRef Options) { format_provider::format(CS.AsCString(), OS, Options); } + +void llvm::yaml::ScalarTraits::output(const ConstString &Val, + void *, raw_ostream &Out) { + Out << Val.GetStringRef(); +} + +llvm::StringRef +llvm::yaml::ScalarTraits::input(llvm::StringRef Scalar, void *, + ConstString &Val) { + Val = ConstString(Scalar); + return {}; +} diff --git a/lldb/source/Utility/FileSpec.cpp b/lldb/source/Utility/FileSpec.cpp index 5c216d947f75a..79ed6d3d2f602 100644 --- a/lldb/source/Utility/FileSpec.cpp +++ b/lldb/source/Utility/FileSpec.cpp @@ -537,3 +537,19 @@ void llvm::format_provider::format(const FileSpec &F, if (!file.empty()) Stream << file; } + +void llvm::yaml::ScalarEnumerationTraits::enumeration( + IO &io, FileSpecStyle &value) { + io.enumCase(value, "windows", FileSpecStyle(FileSpec::Style::windows)); + io.enumCase(value, "posix", FileSpecStyle(FileSpec::Style::posix)); + io.enumCase(value, "native", FileSpecStyle(FileSpec::Style::native)); +} + +void llvm::yaml::MappingTraits::mapping(IO &io, FileSpec &f) { + io.mapRequired("directory", f.m_directory); + io.mapRequired("file", f.m_filename); + io.mapRequired("resolved", f.m_is_resolved); + FileSpecStyle style = f.m_style; + io.mapRequired("style", style); + f.m_style = style; +} diff --git a/lldb/source/Utility/ProcessInfo.cpp b/lldb/source/Utility/ProcessInfo.cpp index b159e26419737..f03e698e99689 100644 --- a/lldb/source/Utility/ProcessInfo.cpp +++ b/lldb/source/Utility/ProcessInfo.cpp @@ -18,6 +18,7 @@ using namespace lldb; using namespace lldb_private; +using namespace lldb_private::repro; ProcessInfo::ProcessInfo() : m_executable(), m_arguments(), m_environment(), m_uid(UINT32_MAX), @@ -331,3 +332,99 @@ void ProcessInstanceInfoMatch::Clear() { m_name_match_type = NameMatch::Ignore; m_match_all_users = false; } + +void llvm::yaml::MappingTraits::mapping( + IO &io, ProcessInstanceInfo &Info) { + io.mapRequired("executable", Info.m_executable); + io.mapRequired("arg0", Info.m_arg0); + io.mapRequired("arch", Info.m_arch); + io.mapRequired("uid", Info.m_uid); + io.mapRequired("gid", Info.m_gid); + io.mapRequired("pid", Info.m_pid); + io.mapRequired("effective-uid", Info.m_euid); + io.mapRequired("effective-gid", Info.m_egid); + io.mapRequired("parent-pid", Info.m_parent_pid); +} + +llvm::Expected> +ProcessInfoRecorder::Create(const FileSpec &filename) { + std::error_code ec; + auto recorder = + std::make_unique(std::move(filename), ec); + if (ec) + return llvm::errorCodeToError(ec); + return std::move(recorder); +} + +void ProcessInfoProvider::Keep() { + std::vector files; + for (auto &recorder : m_process_info_recorders) { + recorder->Stop(); + files.push_back(recorder->GetFilename().GetPath()); + } + + FileSpec file = GetRoot().CopyByAppendingPathComponent(Info::file); + std::error_code ec; + llvm::raw_fd_ostream os(file.GetPath(), ec, llvm::sys::fs::OF_Text); + if (ec) + return; + llvm::yaml::Output yout(os); + yout << files; +} + +void ProcessInfoProvider::Discard() { m_process_info_recorders.clear(); } + +ProcessInfoRecorder *ProcessInfoProvider::GetNewProcessInfoRecorder() { + std::size_t i = m_process_info_recorders.size() + 1; + std::string filename = (llvm::Twine(Info::name) + llvm::Twine("-") + + llvm::Twine(i) + llvm::Twine(".yaml")) + .str(); + auto recorder_or_error = ProcessInfoRecorder::Create( + GetRoot().CopyByAppendingPathComponent(filename)); + if (!recorder_or_error) { + llvm::consumeError(recorder_or_error.takeError()); + return nullptr; + } + + m_process_info_recorders.push_back(std::move(*recorder_or_error)); + return m_process_info_recorders.back().get(); +} + +void ProcessInfoRecorder::Record(const ProcessInstanceInfoList &process_infos) { + if (!m_record) + return; + llvm::yaml::Output yout(m_os); + yout << const_cast(process_infos); + m_os.flush(); +} + +llvm::Optional +repro::GetReplayProcessInstanceInfoList() { + static std::unique_ptr> + loader = repro::MultiLoader::Create( + repro::Reproducer::Instance().GetLoader()); + + if (!loader) + return {}; + + llvm::Optional nextfile = loader->GetNextFile(); + if (!nextfile) + return {}; + + auto error_or_file = llvm::MemoryBuffer::getFile(*nextfile); + if (std::error_code err = error_or_file.getError()) + return {}; + + ProcessInstanceInfoList infos; + llvm::yaml::Input yin((*error_or_file)->getBuffer()); + yin >> infos; + + if (auto err = yin.error()) + return {}; + + return infos; +} + +char ProcessInfoProvider::ID = 0; +const char *ProcessInfoProvider::Info::file = "process-info.yaml"; +const char *ProcessInfoProvider::Info::name = "process-info"; diff --git a/lldb/source/Utility/XcodeSDK.cpp b/lldb/source/Utility/XcodeSDK.cpp new file mode 100644 index 0000000000000..7ad0090f85e2d --- /dev/null +++ b/lldb/source/Utility/XcodeSDK.cpp @@ -0,0 +1,164 @@ +//===-- XcodeSDK.cpp ------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "lldb/Utility/FileSpec.h" +#include "lldb/Utility/XcodeSDK.h" + +#include "lldb/lldb-types.h" + +using namespace lldb; +using namespace lldb_private; + +XcodeSDK &XcodeSDK::operator=(XcodeSDK other) { + m_name = other.m_name; + return *this; +} + +bool XcodeSDK::operator==(XcodeSDK other) { + return m_name == other.m_name; +} + +static XcodeSDK::Type ParseSDKName(llvm::StringRef &name) { + if (name.consume_front("MacOSX")) + return XcodeSDK::MacOSX; + if (name.consume_front("iPhoneSimulator")) + return XcodeSDK::iPhoneSimulator; + if (name.consume_front("iPhoneOS")) + return XcodeSDK::iPhoneOS; + if (name.consume_front("AppleTVSimulator")) + return XcodeSDK::AppleTVSimulator; + if (name.consume_front("AppleTVOS")) + return XcodeSDK::AppleTVOS; + if (name.consume_front("WatchSimulator")) + return XcodeSDK::WatchSimulator; + if (name.consume_front("WatchOS")) + return XcodeSDK::watchOS; + if (name.consume_front("bridgeOS")) + return XcodeSDK::bridgeOS; + if (name.consume_front("Linux")) + return XcodeSDK::Linux; + static_assert(XcodeSDK::Linux == XcodeSDK::numSDKTypes - 1, + "New SDK type was added, update this list!"); + return XcodeSDK::unknown; +} + +static llvm::VersionTuple ParseSDKVersion(llvm::StringRef &name) { + unsigned i = 0; + while (i < name.size() && name[i] >= '0' && name[i] <= '9') + ++i; + if (i == name.size() || name[i++] != '.') + return {}; + while (i < name.size() && name[i] >= '0' && name[i] <= '9') + ++i; + if (i == name.size() || name[i++] != '.') + return {}; + + llvm::VersionTuple version; + version.tryParse(name.slice(0, i - 1)); + name = name.drop_front(i); + return version; +} + + +std::tuple XcodeSDK::Parse() const { + llvm::StringRef input(m_name); + XcodeSDK::Type sdk = ParseSDKName(input); + llvm::VersionTuple version = ParseSDKVersion(input); + return std::make_tuple( + std::move(sdk), std::move(version)); +} + +llvm::VersionTuple XcodeSDK::GetVersion() const { + llvm::StringRef input(m_name); + ParseSDKName(input); + return ParseSDKVersion(input); +} + +XcodeSDK::Type XcodeSDK::GetType() const { + llvm::StringRef input(m_name); + return ParseSDKName(input); +} + +llvm::StringRef XcodeSDK::GetString() const { return m_name; } + +void XcodeSDK::Merge(XcodeSDK other) { + // The "bigger" SDK always wins. + if (Parse() < other.Parse()) + *this = other; +} + +llvm::StringRef XcodeSDK::GetSDKNameForType(XcodeSDK::Type type) { + switch (type) { + case MacOSX: + return "macosx"; + case iPhoneSimulator: + return "iphonesimulator"; + case iPhoneOS: + return "iphoneos"; + case AppleTVSimulator: + return "appletvsimulator"; + case AppleTVOS: + return "appletvos"; + case WatchSimulator: + return "watchsimulator"; + case watchOS: + return "watchos"; + case bridgeOS: + return "bridgeos"; + case Linux: + return "linux"; + case numSDKTypes: + case unknown: + return ""; + } + llvm_unreachable("unhandled switch case"); +} + +bool XcodeSDK::SDKSupportsModules(XcodeSDK::Type sdk_type, + llvm::VersionTuple version) { + switch (sdk_type) { + case Type::MacOSX: + return version >= llvm::VersionTuple(10, 10); + case Type::iPhoneOS: + case Type::iPhoneSimulator: + case Type::AppleTVOS: + case Type::AppleTVSimulator: + return version >= llvm::VersionTuple(8); + case Type::watchOS: + case Type::WatchSimulator: + return version >= llvm::VersionTuple(6); + default: + return false; + } + + return false; +} + +bool XcodeSDK::SDKSupportsModules(XcodeSDK::Type desired_type, + const FileSpec &sdk_path) { + ConstString last_path_component = sdk_path.GetLastPathComponent(); + + if (last_path_component) { + const llvm::StringRef sdk_name = last_path_component.GetStringRef(); + + const std::string sdk_name_lower = sdk_name.lower(); + const llvm::StringRef sdk_string = GetSDKNameForType(desired_type); + if (!llvm::StringRef(sdk_name_lower).startswith(sdk_string)) + return false; + + auto version_part = sdk_name.drop_front(sdk_string.size()); + version_part.consume_back(".sdk"); + + llvm::VersionTuple version; + if (version.tryParse(version_part)) + return false; + return SDKSupportsModules(desired_type, version); + } + + return false; +} diff --git a/lldb/test/API/CMakeLists.txt b/lldb/test/API/CMakeLists.txt index e4015f3a05159..44bd39c41c071 100644 --- a/lldb/test/API/CMakeLists.txt +++ b/lldb/test/API/CMakeLists.txt @@ -34,10 +34,9 @@ if(LLDB_TEST_SWIFT) set(LLDB_SWIFT_LIBS ${SWIFT_LIBRARY_DIR}/swift CACHE STRING "Path to swift libraries") set(SWIFT_TEST_ARGS --swift-compiler ${LLDB_SWIFTC} - --swift-library ${LLDB_SWIFT_LIBS} - --inferior-env "DYLD_LIBRARY_PATH=\\\"${LLDB_SWIFT_LIBS}\\\"" - --inferior-env "LD_LIBRARY_PATH=\\\"${LLDB_SWIFT_LIBS}\\\"" - --inferior-env "SIMCTL_CHILD_DYLD_LIBRARY_PATH=\\\"${LLDB_SWIFT_LIBS}\\\"" + --inferior-env "DYLD_LIBRARY_PATH=\\\"${LLDB_SWIFT_LIBS}/macosx\\\"" + --inferior-env "LD_LIBRARY_PATH=\\\"${LLDB_SWIFT_LIBS}/${CMAKE_SYSTEM_PROCESSOR}\\\"" + --inferior-env "SIMCTL_CHILD_DYLD_LIBRARY_PATH=\\\"${LLDB_SWIFT_LIBS}/macosx\\\"" ) endif() # END - Swift Mods diff --git a/lldb/test/API/commands/expression/import-std-module/basic/TestImportStdModule.py b/lldb/test/API/commands/expression/import-std-module/basic/TestImportStdModule.py index de0d796505e77..0cea2d372f4e2 100644 --- a/lldb/test/API/commands/expression/import-std-module/basic/TestImportStdModule.py +++ b/lldb/test/API/commands/expression/import-std-module/basic/TestImportStdModule.py @@ -25,7 +25,7 @@ def test(self): self.expect("expr std::abs(-42)", substrs=['(int) $0 = 42']) self.expect("expr std::div(2, 1).quot", substrs=['(int) $1 = 2']) # Using types from std. - self.expect("expr (std::size_t)33U", substrs=['(size_t) $2 = 33']) + self.expect_expr("(std::size_t)33U", result_type="std::size_t", result_value="33") # Calling templated functions that return non-template types. self.expect("expr char char_a = 'b'; char char_b = 'a'; std::swap(char_a, char_b); char_a", substrs=["(char) $3 = 'a'"]) diff --git a/lldb/test/API/commands/expression/import-std-module/conflicts/TestStdModuleWithConflicts.py b/lldb/test/API/commands/expression/import-std-module/conflicts/TestStdModuleWithConflicts.py index ad5322baab007..6b817c882ad87 100644 --- a/lldb/test/API/commands/expression/import-std-module/conflicts/TestStdModuleWithConflicts.py +++ b/lldb/test/API/commands/expression/import-std-module/conflicts/TestStdModuleWithConflicts.py @@ -25,8 +25,8 @@ def test(self): "// Set break point at this line.", lldb.SBFileSpec("main.cpp")) self.runCmd("settings set target.import-std-module true") - self.expect("expr std::abs(-42)", substrs=['(int) $0 = 42']) - self.expect("expr std::div(2, 1).quot", substrs=['(int) $1 = 2']) - self.expect("expr (std::size_t)33U", substrs=['(size_t) $2 = 33']) + self.expect_expr("std::abs(-42)", result_type="int", result_value="42") + self.expect_expr("std::div(2, 1).quot", result_type="int", result_value="2") + self.expect_expr("(std::size_t)33U", result_type="std::size_t", result_value="33") self.expect("expr char char_a = 'b'; char char_b = 'a'; std::swap(char_a, char_b); char_a", substrs=["(char) $3 = 'a'"]) diff --git a/lldb/test/API/commands/expression/import-std-module/empty-module/TestEmptyStdModule.py b/lldb/test/API/commands/expression/import-std-module/empty-module/TestEmptyStdModule.py index 76e79df5cd1c8..2b1cb100a3251 100644 --- a/lldb/test/API/commands/expression/import-std-module/empty-module/TestEmptyStdModule.py +++ b/lldb/test/API/commands/expression/import-std-module/empty-module/TestEmptyStdModule.py @@ -15,6 +15,7 @@ class ImportStdModule(TestBase): # but we still add the libc++ category so that this test is only run in # test configurations where libc++ is actually supposed to be tested. @add_test_categories(["libc++"]) + @skipIfRemote @skipIf(compiler=no_match("clang")) def test(self): self.build() diff --git a/lldb/test/API/commands/frame/recognizer/TestFrameRecognizer.py b/lldb/test/API/commands/frame/recognizer/TestFrameRecognizer.py index 3a2faa48e7679..04b940049496e 100644 --- a/lldb/test/API/commands/frame/recognizer/TestFrameRecognizer.py +++ b/lldb/test/API/commands/frame/recognizer/TestFrameRecognizer.py @@ -18,9 +18,7 @@ class FrameRecognizerTestCase(TestBase): @skipUnlessDarwin def test_frame_recognizer_1(self): self.build() - - target = self.dbg.CreateTarget(self.getBuildArtifact("a.out")) - self.assertTrue(target, VALID_TARGET) + exe = self.getBuildArtifact("a.out") # Clear internal & plugins recognizers that get initialized at launch self.runCmd("frame recognizer clear") @@ -33,19 +31,21 @@ def test_frame_recognizer_1(self): self.runCmd("frame recognizer add -l recognizer.MyFrameRecognizer -s a.out -n foo") self.expect("frame recognizer list", - substrs=['0: recognizer.MyFrameRecognizer, module a.out, function foo']) + substrs=['0: recognizer.MyFrameRecognizer, module a.out, symbol foo']) self.runCmd("frame recognizer add -l recognizer.MyOtherFrameRecognizer -s a.out -n bar -x") - self.expect("frame recognizer list", - substrs=['0: recognizer.MyFrameRecognizer, module a.out, function foo', - '1: recognizer.MyOtherFrameRecognizer, module a.out, function bar (regexp)' - ]) + self.expect( + "frame recognizer list", + substrs=[ + '1: recognizer.MyOtherFrameRecognizer, module a.out, symbol bar (regexp)', + '0: recognizer.MyFrameRecognizer, module a.out, symbol foo' + ]) self.runCmd("frame recognizer delete 0") self.expect("frame recognizer list", - substrs=['1: recognizer.MyOtherFrameRecognizer, module a.out, function bar (regexp)']) + substrs=['1: recognizer.MyOtherFrameRecognizer, module a.out, symbol bar (regexp)']) self.runCmd("frame recognizer clear") @@ -54,19 +54,10 @@ def test_frame_recognizer_1(self): self.runCmd("frame recognizer add -l recognizer.MyFrameRecognizer -s a.out -n foo") - lldbutil.run_break_set_by_symbol(self, "foo") - self.runCmd("r") - - self.expect("thread list", STOPPED_DUE_TO_BREAKPOINT, - substrs=['stopped', 'stop reason = breakpoint']) - - process = target.GetProcess() - thread = process.GetSelectedThread() + target, process, thread, _ = lldbutil.run_to_name_breakpoint(self, "foo", + exe_name = exe) frame = thread.GetSelectedFrame() - self.assertEqual(frame.GetSymbol().GetName(), "foo") - self.assertFalse(frame.GetLineEntry().IsValid()) - self.expect("frame variable", substrs=['(int) a = 42', '(int) b = 56']) @@ -108,8 +99,9 @@ def test_frame_recognizer_1(self): # FIXME: The following doesn't work yet, but should be fixed. """ - lldbutil.run_break_set_by_symbol(self, "bar") - self.runCmd("c") + target, process, thread, _ = lldbutil.run_to_name_breakpoint(self, "bar", + exe_name = exe) + frame = thread.GetSelectedFrame() self.expect("thread list", STOPPED_DUE_TO_BREAKPOINT, substrs=['stopped', 'stop reason = breakpoint']) @@ -120,3 +112,35 @@ def test_frame_recognizer_1(self): self.expect("frame variable -t *a", substrs=['*a = 78']) """ + + @skipUnlessDarwin + def test_frame_recognizer_multi_symbol(self): + self.build() + exe = self.getBuildArtifact("a.out") + + # Clear internal & plugins recognizers that get initialized at launch + self.runCmd("frame recognizer clear") + + self.runCmd("command script import " + os.path.join(self.getSourceDir(), "recognizer.py")) + + self.expect("frame recognizer list", + substrs=['no matching results found.']) + + self.runCmd("frame recognizer add -l recognizer.MyFrameRecognizer -s a.out -n foo -n bar") + + self.expect("frame recognizer list", + substrs=['recognizer.MyFrameRecognizer, module a.out, symbol foo, symbol bar']) + + target, process, thread, _ = lldbutil.run_to_name_breakpoint(self, "foo", + exe_name = exe) + frame = thread.GetSelectedFrame() + + self.expect("frame recognizer info 0", + substrs=['frame 0 is recognized by recognizer.MyFrameRecognizer']) + + target, process, thread, _ = lldbutil.run_to_name_breakpoint(self, "bar", + exe_name = exe) + frame = thread.GetSelectedFrame() + + self.expect("frame recognizer info 0", + substrs=['frame 0 is recognized by recognizer.MyFrameRecognizer']) diff --git a/lldb/test/API/commands/frame/recognizer/main.m b/lldb/test/API/commands/frame/recognizer/main.m index 9c6ce9d210233..a5ef73c43b445 100644 --- a/lldb/test/API/commands/frame/recognizer/main.m +++ b/lldb/test/API/commands/frame/recognizer/main.m @@ -13,10 +13,7 @@ void foo(int a, int b) printf("%d %d\n", a, b); } -void bar(int *ptr) -{ - printf("%d\n", *ptr); -} +void bar(int *ptr) { printf("%d\n", *ptr); } int main (int argc, const char * argv[]) { diff --git a/lldb/test/API/commands/settings/TestSettings.py b/lldb/test/API/commands/settings/TestSettings.py index 1130821bac0f4..23f4de05ea0cb 100644 --- a/lldb/test/API/commands/settings/TestSettings.py +++ b/lldb/test/API/commands/settings/TestSettings.py @@ -205,10 +205,15 @@ def test_disassembler_settings(self): @skipIfDarwinEmbedded # debugserver on ios etc can't write files def test_run_args_and_env_vars(self): + self.do_test_run_args_and_env_vars(use_launchsimple=False) + + @skipIfDarwinEmbedded # debugserver on ios etc can't write files + def test_launchsimple_args_and_env_vars(self): + self.do_test_run_args_and_env_vars(use_launchsimple=True) + + def do_test_run_args_and_env_vars(self, use_launchsimple): """Test that run-args and env-vars are passed to the launched process.""" self.build() - exe = self.getBuildArtifact("a.out") - self.runCmd("file " + exe, CURRENT_EXECUTABLE_SET) # Set the run-args and the env-vars. # And add hooks to restore the settings during tearDown(). @@ -219,7 +224,29 @@ def test_run_args_and_env_vars(self): self.addTearDownHook( lambda: self.runCmd("settings clear target.env-vars")) - self.runCmd("process launch --working-dir '{0}'".format(self.get_process_working_directory()), + exe = self.getBuildArtifact("a.out") + self.runCmd("file " + exe, CURRENT_EXECUTABLE_SET) + + target = self.dbg.GetTargetAtIndex(0) + launch_info = target.GetLaunchInfo() + found_env_var = False + for i in range(0, launch_info.GetNumEnvironmentEntries()): + if launch_info.GetEnvironmentEntryAtIndex(i) == "MY_ENV_VAR=YES": + found_env_var = True + break + self.assertTrue(found_env_var, + "MY_ENV_VAR was not set in LunchInfo object") + + self.expect( + 'target show-launch-environment', + substrs=["MY_ENV_VAR=YES"]) + + wd = self.get_process_working_directory() + if use_launchsimple: + process = target.LaunchSimple(None, None, wd) + self.assertTrue(process) + else: + self.runCmd("process launch --working-dir '{0}'".format(wd), RUN_SUCCEEDED) # Read the output file produced by running the program. @@ -234,11 +261,46 @@ def test_run_args_and_env_vars(self): "argv[3] matches", "Environment variable 'MY_ENV_VAR' successfully passed."]) + # Check that env-vars overrides unset-env-vars. + self.runCmd('settings set target.unset-env-vars MY_ENV_VAR') + + self.expect( + 'target show-launch-environment', + 'env-vars overrides unset-env-vars', + substrs=["MY_ENV_VAR=YES"]) + + wd = self.get_process_working_directory() + if use_launchsimple: + process = target.LaunchSimple(None, None, wd) + self.assertTrue(process) + else: + self.runCmd("process launch --working-dir '{0}'".format(wd), + RUN_SUCCEEDED) + + # Read the output file produced by running the program. + output = lldbutil.read_file_from_process_wd(self, "output2.txt") + + self.expect( + output, + exe=False, + substrs=[ + "Environment variable 'MY_ENV_VAR' successfully passed."]) + @skipIfRemote # it doesn't make sense to send host env to remote target def test_pass_host_env_vars(self): """Test that the host env vars are passed to the launched process.""" self.build() + # Set some host environment variables now. + os.environ["MY_HOST_ENV_VAR1"] = "VAR1" + os.environ["MY_HOST_ENV_VAR2"] = "VAR2" + + # This is the function to unset the two env variables set above. + def unset_env_variables(): + os.environ.pop("MY_HOST_ENV_VAR1") + os.environ.pop("MY_HOST_ENV_VAR2") + self.addTearDownHook(unset_env_variables) + exe = self.getBuildArtifact("a.out") self.runCmd("file " + exe, CURRENT_EXECUTABLE_SET) @@ -248,16 +310,33 @@ def test_pass_host_env_vars(self): "Default inherit-env is 'true'", startstr="target.inherit-env (boolean) = true") - # Set some host environment variables now. - os.environ["MY_HOST_ENV_VAR1"] = "VAR1" - os.environ["MY_HOST_ENV_VAR2"] = "VAR2" + self.expect( + 'target show-launch-environment', + 'Host environment is passed correctly', + substrs=['MY_HOST_ENV_VAR1=VAR1', 'MY_HOST_ENV_VAR2=VAR2']) + self.runCmd("process launch --working-dir '{0}'".format(self.get_process_working_directory()), + RUN_SUCCEEDED) - # This is the function to unset the two env variables set above. - def unset_env_variables(): - os.environ.pop("MY_HOST_ENV_VAR1") - os.environ.pop("MY_HOST_ENV_VAR2") + # Read the output file produced by running the program. + output = lldbutil.read_file_from_process_wd(self, "output1.txt") + + self.expect( + output, + exe=False, + substrs=[ + "The host environment variable 'MY_HOST_ENV_VAR1' successfully passed.", + "The host environment variable 'MY_HOST_ENV_VAR2' successfully passed."]) + + # Now test that we can prevent the inferior from inheriting the + # environment. + self.runCmd('settings set target.inherit-env false') + + self.expect( + 'target show-launch-environment', + 'target.inherit-env affects `target show-launch-environment`', + matching=False, + substrs = ['MY_HOST_ENV_VAR1=VAR1', 'MY_HOST_ENV_VAR2=VAR2']) - self.addTearDownHook(unset_env_variables) self.runCmd("process launch --working-dir '{0}'".format(self.get_process_working_directory()), RUN_SUCCEEDED) @@ -267,10 +346,42 @@ def unset_env_variables(): self.expect( output, exe=False, + matching=False, substrs=[ "The host environment variable 'MY_HOST_ENV_VAR1' successfully passed.", "The host environment variable 'MY_HOST_ENV_VAR2' successfully passed."]) + # Now test that we can unset variables from the inherited environment. + self.runCmd('settings set target.inherit-env true') + self.runCmd('settings set target.unset-env-vars MY_HOST_ENV_VAR1') + self.runCmd("process launch --working-dir '{0}'".format(self.get_process_working_directory()), + RUN_SUCCEEDED) + + # Read the output file produced by running the program. + output = lldbutil.read_file_from_process_wd(self, "output1.txt") + + self.expect( + 'target show-launch-environment', + 'MY_HOST_ENV_VAR1 is unset, it shouldn\'t be in `target show-launch-environment`', + matching=False, + substrs = ['MY_HOST_ENV_VAR1=VAR1']) + self.expect( + 'target show-launch-environment', + 'MY_HOST_ENV_VAR2 shouldn be in `target show-launch-environment`', + substrs = ['MY_HOST_ENV_VAR2=VAR2']) + + self.expect( + output, + exe=False, + matching=False, + substrs=[ + "The host environment variable 'MY_HOST_ENV_VAR1' successfully passed."]) + self.expect( + output, + exe=False, + substrs=[ + "The host environment variable 'MY_HOST_ENV_VAR2' successfully passed."]) + @skipIfDarwinEmbedded # debugserver on ios etc can't write files def test_set_error_output_path(self): """Test that setting target.error/output-path for the launched process works.""" diff --git a/lldb/test/API/commands/statistics/basic/Makefile b/lldb/test/API/commands/statistics/basic/Makefile new file mode 100644 index 0000000000000..c9319d6e6888a --- /dev/null +++ b/lldb/test/API/commands/statistics/basic/Makefile @@ -0,0 +1,2 @@ +C_SOURCES := main.c +include Makefile.rules diff --git a/lldb/test/API/commands/statistics/basic/TestStats.py b/lldb/test/API/commands/statistics/basic/TestStats.py index 9f5c7172a65b9..be028199fade1 100644 --- a/lldb/test/API/commands/statistics/basic/TestStats.py +++ b/lldb/test/API/commands/statistics/basic/TestStats.py @@ -1,5 +1,46 @@ -from lldbsuite.test import lldbinline -from lldbsuite.test import decorators +import lldb +from lldbsuite.test.decorators import * +from lldbsuite.test.lldbtest import * +from lldbsuite.test import lldbutil -lldbinline.MakeInlineTest( - __file__, globals(), [decorators.no_debug_info_test]) +class TestCase(TestBase): + + mydir = TestBase.compute_mydir(__file__) + + def test(self): + self.build() + lldbutil.run_to_source_breakpoint(self, "// break here", lldb.SBFileSpec("main.c")) + + self.expect("statistics disable", substrs=['need to enable statistics before disabling'], error=True) + + # 'expression' should change the statistics. + self.expect("statistics enable") + self.expect("statistics enable", substrs=['already enabled'], error=True) + self.expect("expr patatino", substrs=['27']) + self.expect("statistics disable") + self.expect("statistics dump", substrs=['expr evaluation successes : 1\n', + 'expr evaluation failures : 0\n']) + + self.expect("statistics enable") + # Doesn't parse. + self.expect("expr doesnt_exist", error=True, + substrs=["undeclared identifier 'doesnt_exist'"]) + # Doesn't successfully execute. + self.expect("expr int *i = nullptr; *i", error=True) + # Interpret an integer as an array with 3 elements is also a failure. + self.expect("expr -Z 3 -- 1", error=True, + substrs=["expression cannot be used with --element-count"]) + self.expect("statistics disable") + # We should have gotten 3 new failures and the previous success. + self.expect("statistics dump", substrs=['expr evaluation successes : 1\n', + 'expr evaluation failures : 3\n']) + + # 'frame var' with disabled statistics shouldn't change stats. + self.expect("frame var", substrs=['27']) + + self.expect("statistics enable") + # 'frame var' with enabled statistics will change stats. + self.expect("frame var", substrs=['27']) + self.expect("statistics disable") + self.expect("statistics dump", substrs=['frame var successes : 1\n', + 'frame var failures : 0\n']) diff --git a/lldb/test/API/commands/statistics/basic/main.c b/lldb/test/API/commands/statistics/basic/main.c index 9adb3a09a0806..2c5b4f5f098ee 100644 --- a/lldb/test/API/commands/statistics/basic/main.c +++ b/lldb/test/API/commands/statistics/basic/main.c @@ -2,17 +2,6 @@ int main(void) { int patatino = 27; - //%self.expect("statistics disable", substrs=['need to enable statistics before disabling'], error=True) - //%self.expect("statistics enable") - //%self.expect("statistics enable", substrs=['already enabled'], error=True) - //%self.expect("expr patatino", substrs=['27']) - //%self.expect("statistics disable") - //%self.expect("statistics dump", substrs=['expr evaluation successes : 1', 'expr evaluation failures : 0']) - //%self.expect("frame var", substrs=['27']) - //%self.expect("statistics enable") - //%self.expect("frame var", substrs=['27']) - //%self.expect("statistics disable") - //%self.expect("statistics dump", substrs=['frame var successes : 1', 'frame var failures : 0']) - return 0; + return 0; // break here } diff --git a/lldb/test/API/commands/watchpoints/watchpoint_count/Makefile b/lldb/test/API/commands/watchpoints/watchpoint_count/Makefile new file mode 100644 index 0000000000000..10495940055b6 --- /dev/null +++ b/lldb/test/API/commands/watchpoints/watchpoint_count/Makefile @@ -0,0 +1,3 @@ +C_SOURCES := main.c + +include Makefile.rules diff --git a/lldb/test/API/commands/watchpoints/watchpoint_count/TestWatchpointCount.py b/lldb/test/API/commands/watchpoints/watchpoint_count/TestWatchpointCount.py new file mode 100644 index 0000000000000..18667e913a944 --- /dev/null +++ b/lldb/test/API/commands/watchpoints/watchpoint_count/TestWatchpointCount.py @@ -0,0 +1,43 @@ +import lldb +from lldbsuite.test.decorators import * +from lldbsuite.test.lldbtest import * +from lldbsuite.test import lldbutil + +class TestWatchpointCount(TestBase): + mydir = TestBase.compute_mydir(__file__) + NO_DEBUG_INFO_TESTCASE = True + + def setUp(self): + TestBase.setUp(self) + + def test_watchpoint_count(self): + self.build() + (_, process, thread, _) = lldbutil.run_to_source_breakpoint(self, "patatino", lldb.SBFileSpec("main.c")) + frame = thread.GetFrameAtIndex(0) + first_var = frame.FindVariable("x1") + second_var = frame.FindVariable("x2") + + error = lldb.SBError() + first_watch = first_var.Watch(True, False, True, error) + if not error.Success(): + self.fail( + "Failed to make watchpoint for x1: %s" % + (error.GetCString())) + + second_watch = second_var.Watch(True, False, True, error) + if not error.Success(): + self.fail( + "Failed to make watchpoint for x2: %s" % + (error.GetCString())) + process.Continue() + + stop_reason = thread.GetStopReason() + self.assertEqual(stop_reason, lldb.eStopReasonWatchpoint, "watchpoint for x1 not hit") + stop_reason_descr = thread.GetStopDescription(256) + self.assertEqual(stop_reason_descr, "watchpoint 1") + + process.Continue() + stop_reason = thread.GetStopReason() + self.assertEqual(stop_reason, lldb.eStopReasonWatchpoint, "watchpoint for x2 not hit") + stop_reason_descr = thread.GetStopDescription(256) + self.assertEqual(stop_reason_descr, "watchpoint 2") diff --git a/lldb/test/API/commands/watchpoints/watchpoint_count/main.c b/lldb/test/API/commands/watchpoints/watchpoint_count/main.c new file mode 100644 index 0000000000000..fc9a370e41f31 --- /dev/null +++ b/lldb/test/API/commands/watchpoints/watchpoint_count/main.c @@ -0,0 +1,13 @@ +#include +#include + +int main() { + uint8_t x1 = 0; + uint16_t x2 = 0; + + printf("patatino\n"); + + x1 += 1; + x2 += 2; + return 0; +} diff --git a/lldb/test/API/functionalities/breakpoint/breakpoint_locations/main.c b/lldb/test/API/functionalities/breakpoint/breakpoint_locations/main.c index 7ec3ded67b74f..f6ccb031c7445 100644 --- a/lldb/test/API/functionalities/breakpoint/breakpoint_locations/main.c +++ b/lldb/test/API/functionalities/breakpoint/breakpoint_locations/main.c @@ -14,9 +14,9 @@ func_inlined (void) { static int func_inline_call_count = 0; printf ("Called func_inlined.\n"); - ++func_inline_call_count; + ++func_inline_call_count; // Set break point at this line. printf ("Returning func_inlined call count: %d.\n", func_inline_call_count); - return func_inline_call_count; // Set break point at this line. + return func_inline_call_count; } extern int func_inlined (void); diff --git a/lldb/test/API/functionalities/breakpoint/hardware_breakpoints/hardware_breakpoint_on_multiple_threads/TestHWBreakMultiThread.py b/lldb/test/API/functionalities/breakpoint/hardware_breakpoints/hardware_breakpoint_on_multiple_threads/TestHWBreakMultiThread.py index 90d182bfcc89f..5f3ecf564bc8b 100644 --- a/lldb/test/API/functionalities/breakpoint/hardware_breakpoints/hardware_breakpoint_on_multiple_threads/TestHWBreakMultiThread.py +++ b/lldb/test/API/functionalities/breakpoint/hardware_breakpoints/hardware_breakpoint_on_multiple_threads/TestHWBreakMultiThread.py @@ -32,19 +32,21 @@ def test_hw_break_set_disable_multi_thread_linux(self): self.setTearDownCleanup() self.break_multi_thread('disable', False) # llvm.org/PR44659 - # LLDB on darwin supports hardware breakpoints for arm, aarch64, x86_64 and - # i386 architectures. + # LLDB on darwin supports hardware breakpoints for x86_64 and i386 + # architectures. @skipUnlessDarwin @skipIfOutOfTreeDebugserver + @skipIfDarwinEmbedded def test_hw_break_set_delete_multi_thread_macos(self): self.build() self.setTearDownCleanup() self.break_multi_thread('delete') - # LLDB on darwin supports hardware breakpoints for arm, aarch64, x86_64 and - # i386 architectures. + # LLDB on darwin supports hardware breakpoints for x86_64 and i386 + # architectures. @skipUnlessDarwin @skipIfOutOfTreeDebugserver + @skipIfDarwinEmbedded def test_hw_break_set_disable_multi_thread_macos(self): self.build() self.setTearDownCleanup() diff --git a/lldb/test/API/functionalities/breakpoint/require_hw_breakpoints/TestRequireHWBreakpoints.py b/lldb/test/API/functionalities/breakpoint/require_hw_breakpoints/TestRequireHWBreakpoints.py index 74f2fbb0c1a01..61e4171131013 100644 --- a/lldb/test/API/functionalities/breakpoint/require_hw_breakpoints/TestRequireHWBreakpoints.py +++ b/lldb/test/API/functionalities/breakpoint/require_hw_breakpoints/TestRequireHWBreakpoints.py @@ -19,7 +19,6 @@ def supports_hw_breakpoints(self): CURRENT_EXECUTABLE_SET) self.runCmd("breakpoint set -b main --hardware") self.runCmd("run") - print(self.res.GetOutput()) if 'stopped' in self.res.GetOutput(): return 'Hardware breakpoints are supported' return None diff --git a/lldb/test/API/functionalities/data-formatter/data-formatter-objc/TestDataFormatterObjCNSError.py b/lldb/test/API/functionalities/data-formatter/data-formatter-objc/TestDataFormatterObjCNSError.py index ced7444c0ca5a..b5e1f149354fd 100644 --- a/lldb/test/API/functionalities/data-formatter/data-formatter-objc/TestDataFormatterObjCNSError.py +++ b/lldb/test/API/functionalities/data-formatter/data-formatter-objc/TestDataFormatterObjCNSError.py @@ -15,7 +15,7 @@ class ObjCDataFormatterNSError(ObjCDataFormatterTestCase): @skipUnlessDarwin - @expectedFailureAll(bugnumber="rdar://25587546") + @expectedFailureAll(debug_info=["dwarf", "dsym", "dwo"], bugnumber="rdar://25587546") def test_nserror_with_run_command(self): """Test formatters for NSError.""" self.appkit_tester_impl(self.nserror_data_formatter_commands) diff --git a/lldb/test/API/functionalities/data-formatter/data-formatter-objc/nsstring/TestDataFormatterNSString.py b/lldb/test/API/functionalities/data-formatter/data-formatter-objc/nsstring/TestDataFormatterNSString.py index 6480025e2e17d..5b323f5614b21 100644 --- a/lldb/test/API/functionalities/data-formatter/data-formatter-objc/nsstring/TestDataFormatterNSString.py +++ b/lldb/test/API/functionalities/data-formatter/data-formatter-objc/nsstring/TestDataFormatterNSString.py @@ -76,8 +76,8 @@ def rdar11106605_commands(self): self.expect('frame variable hebrew', substrs=['לילה טוב']) def nsstring_data_formatter_commands(self): - self.expect('frame variable str0 str1 str2 str3 str4 str5 str6 str8 str9 str10 str11 label1 label2 processName str12', - substrs=['(NSString *) str1 = ', ' @"A rather short ASCII NSString object is here"', + self.expect('frame variable empty str0 str1 str2 str3 str4 str5 str6 str8 str9 str10 str11 label1 label2 processName str12', + substrs=['(NSString *) empty = ', ' @""', # '(NSString *) str0 = ',' @"255"', '(NSString *) str1 = ', ' @"A rather short ASCII NSString object is here"', '(NSString *) str2 = ', ' @"A rather short UTF8 NSString object is here"', @@ -104,6 +104,8 @@ def nsstring_data_formatter_commands(self): self.expect('expr -d run-target -- path', substrs=['usr/blah/stuff']) self.expect('frame variable path', substrs=['usr/blah/stuff']) + self.expect('expr -d run-target -- empty_path', substrs=['@""']) + self.expect('frame variable empty_path', substrs=['@""']) def nsstring_withNULs_commands(self): """Check that the NSString formatter supports embedded NULs in the text""" diff --git a/lldb/test/API/functionalities/data-formatter/data-formatter-objc/nsstring/main.m b/lldb/test/API/functionalities/data-formatter/data-formatter-objc/nsstring/main.m index b0d926fd54ef6..e5a365605b231 100644 --- a/lldb/test/API/functionalities/data-formatter/data-formatter-objc/nsstring/main.m +++ b/lldb/test/API/functionalities/data-formatter/data-formatter-objc/nsstring/main.m @@ -25,6 +25,7 @@ int main (int argc, const char * argv[]) NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init]; + NSString *empty = @""; NSString *str0 = [[NSNumber numberWithUnsignedLongLong:0xFF] stringValue]; NSString *str1 = [NSString stringWithCString:"A rather short ASCII NSString object is here" encoding:NSASCIIStringEncoding]; NSString *str2 = [NSString stringWithUTF8String:"A rather short UTF8 NSString object is here"]; @@ -77,6 +78,7 @@ int main (int argc, const char * argv[]) NSArray *components = @[@"usr", @"blah", @"stuff"]; NSString *path = [NSString pathWithComponents: components]; + NSString *empty_path = [empty stringByDeletingPathExtension]; const unichar someOfTheseAreNUL[] = {'a',' ', 'v','e','r','y',' ', 'm','u','c','h',' ','b','o','r','i','n','g',' ','t','a','s','k', diff --git a/lldb/test/API/functionalities/data-formatter/data-formatter-python-synth/TestDataFormatterPythonSynth.py b/lldb/test/API/functionalities/data-formatter/data-formatter-python-synth/TestDataFormatterPythonSynth.py index 5f908f76b0abc..9d4759100ce2e 100644 --- a/lldb/test/API/functionalities/data-formatter/data-formatter-python-synth/TestDataFormatterPythonSynth.py +++ b/lldb/test/API/functionalities/data-formatter/data-formatter-python-synth/TestDataFormatterPythonSynth.py @@ -38,19 +38,9 @@ def setUp(self): def data_formatter_commands(self): """Test using Python synthetic children provider.""" - self.runCmd("file " + self.getBuildArtifact("a.out"), CURRENT_EXECUTABLE_SET) - - lldbutil.run_break_set_by_file_and_line( - self, "main.cpp", self.line, num_expected_locations=1, loc_exact=True) - - self.runCmd("run", RUN_SUCCEEDED) - - process = self.dbg.GetSelectedTarget().GetProcess() - # The stop reason of the thread should be breakpoint. - self.expect("thread list", STOPPED_DUE_TO_BREAKPOINT, - substrs=['stopped', - 'stop reason = breakpoint']) + _, process, thread, _ = lldbutil.run_to_line_breakpoint( + self, lldb.SBFileSpec("main.cpp"), self.line) # This is the function to remove the custom formats in order to have a # clean slate for the next test case. @@ -72,6 +62,7 @@ def cleanup(): # now set up the synth self.runCmd("script from fooSynthProvider import *") self.runCmd("type synth add -l fooSynthProvider foo") + self.runCmd("type synth add -l wrapfooSynthProvider wrapfoo") self.expect("type synthetic list foo", substrs=['fooSynthProvider']) # note that the value of fake_a depends on target byte order @@ -147,6 +138,10 @@ def cleanup(): substrs=['r = 45', 'fake_a = %d' % fake_a_val, 'a = 12']) + self.expect("frame variable --ptr-depth 1 wrapper", + substrs=['r = 45', + 'fake_a = %d' % fake_a_val, + 'a = 12']) # now add a filter.. it should fail self.expect("type filter add foo --child b --child j", error=True, @@ -160,9 +155,24 @@ def cleanup(): substrs=['r = 45', 'fake_a = %d' % fake_a_val, 'a = 12']) + self.expect("frame variable --ptr-depth 1 wrapper", + substrs=['r = 45', + 'fake_a = %d' % fake_a_val, + 'a = 12']) + + # Test that the custom dereference operator for `wrapfoo` works through + # the Python API. The synthetic children provider gets queried at + # slightly different times in this case. + wrapper_var = thread.GetSelectedFrame().FindVariable('wrapper') + foo_var = wrapper_var.Dereference() + self.assertEqual(foo_var.GetNumChildren(), 3) + self.assertEqual(foo_var.GetChildAtIndex(0).GetName(), 'a') + self.assertEqual(foo_var.GetChildAtIndex(1).GetName(), 'fake_a') + self.assertEqual(foo_var.GetChildAtIndex(2).GetName(), 'r') # now delete the synth and add the filter self.runCmd("type synth delete foo") + self.runCmd("type synth delete wrapfoo") self.runCmd("type filter add foo --child b --child j") self.expect('frame variable f00_1', @@ -172,6 +182,10 @@ def cleanup(): substrs=['r = 45', 'fake_a = %d' % fake_a_val, 'a = 12']) + self.expect("frame variable --ptr-depth 1 wrapper", matching=False, + substrs=['r = 45', + 'fake_a = %d' % fake_a_val, + 'a = 12']) # now add the synth and it should fail self.expect("type synth add -l fooSynthProvider foo", error=True, @@ -197,6 +211,10 @@ def cleanup(): substrs=['r = 45', 'fake_a = %d' % fake_a_val, 'a = 12']) + self.expect("frame variable --ptr-depth 1 wrapper", + substrs=['r = 45', + 'fake_a = %d' % fake_a_val, + 'a = 12']) # check the listing self.expect('type synth list', diff --git a/lldb/test/API/functionalities/data-formatter/data-formatter-python-synth/fooSynthProvider.py b/lldb/test/API/functionalities/data-formatter/data-formatter-python-synth/fooSynthProvider.py index 45fb00468e083..6ee749b720b2c 100644 --- a/lldb/test/API/functionalities/data-formatter/data-formatter-python-synth/fooSynthProvider.py +++ b/lldb/test/API/functionalities/data-formatter/data-formatter-python-synth/fooSynthProvider.py @@ -28,3 +28,29 @@ def get_child_index(self, name): def update(self): return True + + +class wrapfooSynthProvider: + + def __init__(self, valobj, dict): + self.valobj = valobj + + def num_children(self): + return 1 + + def get_child_at_index(self, index): + if index == 0: + return self.valobj.GetChildMemberWithName('ptr') + if index == 1: + return self.valobj.GetChildMemberWithName('ptr').Dereference() + return None + + def get_child_index(self, name): + if name == 'ptr': + return 0 + if name == '$$dereference$$': + return 1 + return -1 + + def update(self): + return True diff --git a/lldb/test/API/functionalities/data-formatter/data-formatter-python-synth/main.cpp b/lldb/test/API/functionalities/data-formatter/data-formatter-python-synth/main.cpp index f45a2abfb9f1e..5cf4b63459271 100644 --- a/lldb/test/API/functionalities/data-formatter/data-formatter-python-synth/main.cpp +++ b/lldb/test/API/functionalities/data-formatter/data-formatter-python-synth/main.cpp @@ -46,11 +46,17 @@ struct wrapint wrapint(int X) : x(X) {} }; +struct wrapfoo +{ + foo *ptr; +}; + int main() { foo f00_1(1); foo *f00_ptr = new foo(12); - + wrapfoo wrapper{f00_ptr}; + f00_1.a++; // Set break point at this line. wrapint test_cast('A' + diff --git a/lldb/test/API/functionalities/data-formatter/data-formatter-stl/libcxx/forward_list/TestDataFormatterLibcxxForwardList.py b/lldb/test/API/functionalities/data-formatter/data-formatter-stl/libcxx/forward_list/TestDataFormatterLibcxxForwardList.py index a9983dd045e99..efbc4c538798e 100644 --- a/lldb/test/API/functionalities/data-formatter/data-formatter-stl/libcxx/forward_list/TestDataFormatterLibcxxForwardList.py +++ b/lldb/test/API/functionalities/data-formatter/data-formatter-stl/libcxx/forward_list/TestDataFormatterLibcxxForwardList.py @@ -17,8 +17,7 @@ class TestDataFormatterLibcxxForwardList(TestBase): def setUp(self): TestBase.setUp(self) self.line = line_number('main.cpp', '// break here') - ns = 'ndk' if lldbplatformutil.target_is_android() else '' - self.namespace = 'std::__' + ns + '1' + self.namespace = 'std' @add_test_categories(["libc++"]) def test(self): diff --git a/lldb/test/API/functionalities/data-formatter/data-formatter-stl/libcxx/iterator/TestDataFormatterLibccIterator.py b/lldb/test/API/functionalities/data-formatter/data-formatter-stl/libcxx/iterator/TestDataFormatterLibccIterator.py index 2ff3d63d004d9..9081edc2bfc62 100644 --- a/lldb/test/API/functionalities/data-formatter/data-formatter-stl/libcxx/iterator/TestDataFormatterLibccIterator.py +++ b/lldb/test/API/functionalities/data-formatter/data-formatter-stl/libcxx/iterator/TestDataFormatterLibccIterator.py @@ -19,8 +19,7 @@ def setUp(self): TestBase.setUp(self) # Find the line number to break at. self.line = line_number('main.cpp', '// Set break point at this line.') - ns = 'ndk' if lldbplatformutil.target_is_android() else '' - self.namespace = 'std::__' + ns + '1' + self.namespace = 'std' @add_test_categories(["libc++"]) def test_with_run_command(self): diff --git a/lldb/test/API/functionalities/data-formatter/data-formatter-stl/libcxx/map/TestDataFormatterLibccMap.py b/lldb/test/API/functionalities/data-formatter/data-formatter-stl/libcxx/map/TestDataFormatterLibccMap.py index d9da0c3886e28..0644742c5fb11 100644 --- a/lldb/test/API/functionalities/data-formatter/data-formatter-stl/libcxx/map/TestDataFormatterLibccMap.py +++ b/lldb/test/API/functionalities/data-formatter/data-formatter-stl/libcxx/map/TestDataFormatterLibccMap.py @@ -17,7 +17,7 @@ class LibcxxMapDataFormatterTestCase(TestBase): def setUp(self): TestBase.setUp(self) ns = 'ndk' if lldbplatformutil.target_is_android() else '' - self.namespace = 'std::__' + ns + '1' + self.namespace = 'std' @add_test_categories(["libc++"]) def test_with_run_command(self): diff --git a/lldb/test/API/functionalities/data-formatter/data-formatter-stl/libcxx/multimap/TestDataFormatterLibccMultiMap.py b/lldb/test/API/functionalities/data-formatter/data-formatter-stl/libcxx/multimap/TestDataFormatterLibccMultiMap.py index 39adc04e49ae0..3f3a2ba0cb12a 100644 --- a/lldb/test/API/functionalities/data-formatter/data-formatter-stl/libcxx/multimap/TestDataFormatterLibccMultiMap.py +++ b/lldb/test/API/functionalities/data-formatter/data-formatter-stl/libcxx/multimap/TestDataFormatterLibccMultiMap.py @@ -17,8 +17,7 @@ class LibcxxMultiMapDataFormatterTestCase(TestBase): def setUp(self): TestBase.setUp(self) - ns = 'ndk' if lldbplatformutil.target_is_android() else '' - self.namespace = 'std::__' + ns + '1' + self.namespace = 'std' @add_test_categories(["libc++"]) def test_with_run_command(self): diff --git a/lldb/test/API/functionalities/data-formatter/data-formatter-stl/libcxx/multiset/TestDataFormatterLibcxxMultiSet.py b/lldb/test/API/functionalities/data-formatter/data-formatter-stl/libcxx/multiset/TestDataFormatterLibcxxMultiSet.py index 621b22a538c34..a21d537eaea28 100644 --- a/lldb/test/API/functionalities/data-formatter/data-formatter-stl/libcxx/multiset/TestDataFormatterLibcxxMultiSet.py +++ b/lldb/test/API/functionalities/data-formatter/data-formatter-stl/libcxx/multiset/TestDataFormatterLibcxxMultiSet.py @@ -16,13 +16,12 @@ class LibcxxMultiSetDataFormatterTestCase(TestBase): def setUp(self): TestBase.setUp(self) - ns = 'ndk' if lldbplatformutil.target_is_android() else '' - self.namespace = 'std::__' + ns + '1' + self.namespace = 'std' def getVariableType(self, name): var = self.frame().FindVariable(name) self.assertTrue(var.IsValid()) - return var.GetType().GetCanonicalType().GetName() + return var.GetType().GetDisplayTypeName() def check_ii(self, var_name): """ This checks the value of the bitset stored in ii at the call to by_ref_and_ptr. diff --git a/lldb/test/API/functionalities/data-formatter/data-formatter-stl/libcxx/multiset/main.cpp b/lldb/test/API/functionalities/data-formatter/data-formatter-stl/libcxx/multiset/main.cpp index dd3d8be4ae915..6813b6eca395b 100644 --- a/lldb/test/API/functionalities/data-formatter/data-formatter-stl/libcxx/multiset/main.cpp +++ b/lldb/test/API/functionalities/data-formatter/data-formatter-stl/libcxx/multiset/main.cpp @@ -1,9 +1,6 @@ #include #include -typedef std::multiset intset; -typedef std::multiset stringset; - int g_the_foo = 0; int thefoo_rw(int arg = 1) @@ -16,7 +13,7 @@ int thefoo_rw(int arg = 1) return g_the_foo; } -void by_ref_and_ptr(intset &ref, intset *ptr) +void by_ref_and_ptr(std::multiset &ref, std::multiset *ptr) { // Stop here to check by ref and ptr return; @@ -24,7 +21,7 @@ void by_ref_and_ptr(intset &ref, intset *ptr) int main() { - intset ii; + std::multiset ii; thefoo_rw(1); // Set break point at this line. ii.insert(0); @@ -43,7 +40,7 @@ int main() ii.clear(); thefoo_rw(1); // Set break point at this line. - stringset ss; + std::multiset ss; thefoo_rw(1); // Set break point at this line. ss.insert("a"); diff --git a/lldb/test/API/functionalities/data-formatter/data-formatter-stl/libcxx/queue/TestDataFormatterLibcxxQueue.py b/lldb/test/API/functionalities/data-formatter/data-formatter-stl/libcxx/queue/TestDataFormatterLibcxxQueue.py index b163fa56fae53..f2f9f670c7144 100644 --- a/lldb/test/API/functionalities/data-formatter/data-formatter-stl/libcxx/queue/TestDataFormatterLibcxxQueue.py +++ b/lldb/test/API/functionalities/data-formatter/data-formatter-stl/libcxx/queue/TestDataFormatterLibcxxQueue.py @@ -16,15 +16,14 @@ class TestDataFormatterLibcxxQueue(TestBase): def setUp(self): TestBase.setUp(self) - ns = 'ndk' if lldbplatformutil.target_is_android() else '' - self.namespace = 'std::__' + ns + '1' + self.namespace = 'std' def check_variable(self, name): var = self.frame().FindVariable(name) self.assertTrue(var.IsValid()) queue = self.namespace + '::queue' - self.assertTrue(queue in var.GetTypeName()) + self.assertTrue(queue in var.GetDisplayTypeName()) self.assertEqual(var.GetNumChildren(), 5) for i in range(5): ch = var.GetChildAtIndex(i) diff --git a/lldb/test/API/functionalities/data-formatter/data-formatter-stl/libcxx/set/TestDataFormatterLibcxxSet.py b/lldb/test/API/functionalities/data-formatter/data-formatter-stl/libcxx/set/TestDataFormatterLibcxxSet.py index 738df85d05193..82f4335245f1f 100644 --- a/lldb/test/API/functionalities/data-formatter/data-formatter-stl/libcxx/set/TestDataFormatterLibcxxSet.py +++ b/lldb/test/API/functionalities/data-formatter/data-formatter-stl/libcxx/set/TestDataFormatterLibcxxSet.py @@ -16,13 +16,12 @@ class LibcxxSetDataFormatterTestCase(TestBase): def setUp(self): TestBase.setUp(self) - ns = 'ndk' if lldbplatformutil.target_is_android() else '' - self.namespace = 'std::__' + ns + '1' + self.namespace = 'std' def getVariableType(self, name): var = self.frame().FindVariable(name) self.assertTrue(var.IsValid()) - return var.GetType().GetCanonicalType().GetName() + return var.GetType().GetDisplayTypeName() def check_ii(self, var_name): """ This checks the value of the bitset stored in ii at the call to by_ref_and_ptr. diff --git a/lldb/test/API/functionalities/data-formatter/data-formatter-stl/libcxx/set/main.cpp b/lldb/test/API/functionalities/data-formatter/data-formatter-stl/libcxx/set/main.cpp index df39e9746c03a..1d48f9b9ad1a5 100644 --- a/lldb/test/API/functionalities/data-formatter/data-formatter-stl/libcxx/set/main.cpp +++ b/lldb/test/API/functionalities/data-formatter/data-formatter-stl/libcxx/set/main.cpp @@ -1,9 +1,6 @@ #include #include -typedef std::set intset; -typedef std::set stringset; - int g_the_foo = 0; int thefoo_rw(int arg = 1) @@ -16,7 +13,7 @@ int thefoo_rw(int arg = 1) return g_the_foo; } -void by_ref_and_ptr(intset &ref, intset *ptr) +void by_ref_and_ptr(std::set &ref, std::set *ptr) { // Stop here to check by ref and ptr return; @@ -24,7 +21,7 @@ void by_ref_and_ptr(intset &ref, intset *ptr) int main() { - intset ii; + std::set ii; thefoo_rw(1); // Set break point at this line. ii.insert(0); @@ -43,7 +40,7 @@ int main() ii.clear(); thefoo_rw(1); // Set break point at this line. - stringset ss; + std::set ss; thefoo_rw(1); // Set break point at this line. ss.insert("a"); diff --git a/lldb/test/API/functionalities/data-formatter/data-formatter-stl/libcxx/string/TestDataFormatterLibcxxString.py b/lldb/test/API/functionalities/data-formatter/data-formatter-stl/libcxx/string/TestDataFormatterLibcxxString.py index f04ec6d402b34..3753067113b1a 100644 --- a/lldb/test/API/functionalities/data-formatter/data-formatter-stl/libcxx/string/TestDataFormatterLibcxxString.py +++ b/lldb/test/API/functionalities/data-formatter/data-formatter-stl/libcxx/string/TestDataFormatterLibcxxString.py @@ -20,8 +20,7 @@ def setUp(self): TestBase.setUp(self) # Find the line number to break at. self.line = line_number('main.cpp', '// Set break point at this line.') - ns = 'ndk' if lldbplatformutil.target_is_android() else '' - self.namespace = 'std::__' + ns + '1' + self.namespace = 'std' @add_test_categories(["libc++"]) @expectedFailureAll(bugnumber="llvm.org/pr36109", debug_info="gmodules", triple=".*-android") diff --git a/lldb/test/API/functionalities/data-formatter/data-formatter-stl/libcxx/tuple/TestDataFormatterLibcxxTuple.py b/lldb/test/API/functionalities/data-formatter/data-formatter-stl/libcxx/tuple/TestDataFormatterLibcxxTuple.py index 57b777837165e..171f9a8e5c078 100644 --- a/lldb/test/API/functionalities/data-formatter/data-formatter-stl/libcxx/tuple/TestDataFormatterLibcxxTuple.py +++ b/lldb/test/API/functionalities/data-formatter/data-formatter-stl/libcxx/tuple/TestDataFormatterLibcxxTuple.py @@ -17,8 +17,7 @@ class TestDataFormatterLibcxxTuple(TestBase): def setUp(self): TestBase.setUp(self) self.line = line_number('main.cpp', '// break here') - ns = 'ndk' if lldbplatformutil.target_is_android() else '' - self.namespace = 'std::__' + ns + '1' + self.namespace = 'std' @add_test_categories(["libc++"]) def test(self): diff --git a/lldb/test/API/functionalities/data-formatter/data-formatter-stl/libcxx/unique_ptr/Makefile b/lldb/test/API/functionalities/data-formatter/data-formatter-stl/libcxx/unique_ptr/Makefile new file mode 100644 index 0000000000000..7e57f13aea55a --- /dev/null +++ b/lldb/test/API/functionalities/data-formatter/data-formatter-stl/libcxx/unique_ptr/Makefile @@ -0,0 +1,6 @@ +CXX_SOURCES := main.cpp + +USE_LIBCPP := 1 + +CXXFLAGS_EXTRAS := -std=c++14 +include Makefile.rules diff --git a/lldb/test/API/functionalities/data-formatter/data-formatter-stl/libcxx/unique_ptr/TestDataFormatterLibcxxUniquePtr.py b/lldb/test/API/functionalities/data-formatter/data-formatter-stl/libcxx/unique_ptr/TestDataFormatterLibcxxUniquePtr.py new file mode 100644 index 0000000000000..b91e494258bf9 --- /dev/null +++ b/lldb/test/API/functionalities/data-formatter/data-formatter-stl/libcxx/unique_ptr/TestDataFormatterLibcxxUniquePtr.py @@ -0,0 +1,47 @@ +""" +Test lldb data formatter for libc++ std::unique_ptr. +""" + + + +import lldb +from lldbsuite.test.decorators import * +from lldbsuite.test.lldbtest import * +from lldbsuite.test import lldbutil + +class LibcxUniquePtrDataFormatterTestCase(TestBase): + + mydir = TestBase.compute_mydir(__file__) + + @add_test_categories(["libc++"]) + def test_with_run_command(self): + """Test that that file and class static variables display correctly.""" + self.build() + + (self.target, self.process, _, bkpt) = lldbutil.run_to_source_breakpoint(self, '// break here', + lldb.SBFileSpec("main.cpp", False)) + + self.expect("frame variable up_empty", + substrs=['(std::unique_ptr >) up_empty = nullptr {', + '__value_ = ', + '}']) + + self.expect("frame variable up_int", + substrs=['(std::unique_ptr >) up_int = 10 {', + '__value_ = ', + '}']) + + self.expect("frame variable up_int_ref", + substrs=['(std::unique_ptr > &) up_int_ref = 10: {', + '__value_ = ', + '}']) + + self.expect("frame variable up_int_ref_ref", + substrs=['(std::unique_ptr > &&) up_int_ref_ref = 10: {', + '__value_ = ', + '}']) + + self.expect("frame variable up_str", + substrs=['up_str = "hello" {', + '__value_ = ', + '}']) diff --git a/lldb/test/API/functionalities/data-formatter/data-formatter-stl/libcxx/unique_ptr/main.cpp b/lldb/test/API/functionalities/data-formatter/data-formatter-stl/libcxx/unique_ptr/main.cpp new file mode 100644 index 0000000000000..4ccffe2a006d3 --- /dev/null +++ b/lldb/test/API/functionalities/data-formatter/data-formatter-stl/libcxx/unique_ptr/main.cpp @@ -0,0 +1,13 @@ +#include +#include +#include + +int main() { + std::unique_ptr up_empty; + std::unique_ptr up_int = std::make_unique(10); + std::unique_ptr up_str = std::make_unique("hello"); + std::unique_ptr &up_int_ref = up_int; + std::unique_ptr &&up_int_ref_ref = std::make_unique(10); + + return 0; // break here +} diff --git a/lldb/test/API/functionalities/data-formatter/data-formatter-stl/libcxx/unordered/TestDataFormatterUnordered.py b/lldb/test/API/functionalities/data-formatter/data-formatter-stl/libcxx/unordered/TestDataFormatterUnordered.py index 9566af0313092..3519daec6ec41 100644 --- a/lldb/test/API/functionalities/data-formatter/data-formatter-stl/libcxx/unordered/TestDataFormatterUnordered.py +++ b/lldb/test/API/functionalities/data-formatter/data-formatter-stl/libcxx/unordered/TestDataFormatterUnordered.py @@ -16,8 +16,7 @@ class LibcxxUnorderedDataFormatterTestCase(TestBase): def setUp(self): TestBase.setUp(self) - ns = 'ndk' if lldbplatformutil.target_is_android() else '' - self.namespace = 'std::__' + ns + '1' + self.namespace = 'std' @add_test_categories(["libc++"]) def test_with_run_command(self): diff --git a/lldb/test/API/functionalities/data-formatter/data-formatter-stl/libcxx/variant/TestDataFormatterLibcxxVariant.py b/lldb/test/API/functionalities/data-formatter/data-formatter-stl/libcxx/variant/TestDataFormatterLibcxxVariant.py index a2a6b74faa41a..cea4fd6bf1c3f 100644 --- a/lldb/test/API/functionalities/data-formatter/data-formatter-stl/libcxx/variant/TestDataFormatterLibcxxVariant.py +++ b/lldb/test/API/functionalities/data-formatter/data-formatter-stl/libcxx/variant/TestDataFormatterLibcxxVariant.py @@ -51,7 +51,7 @@ def test_with_run_command(self): '}']) self.expect("frame variable v_v1", - substrs=['v_v1 = Active Type = std::__1::variant {', + substrs=['v_v1 = Active Type = std::variant {', 'Value = Active Type = int {', 'Value = 12', '}', diff --git a/lldb/test/API/functionalities/gdb_remote_client/TestGDBRemoteClient.py b/lldb/test/API/functionalities/gdb_remote_client/TestGDBRemoteClient.py index 8f0ed9a4933da..e5a9ef1da8091 100644 --- a/lldb/test/API/functionalities/gdb_remote_client/TestGDBRemoteClient.py +++ b/lldb/test/API/functionalities/gdb_remote_client/TestGDBRemoteClient.py @@ -50,6 +50,31 @@ def vAttach(self, pid): target.AttachToProcessWithID(lldb.SBListener(), 47, error) self.assertEquals(error_msg, error.GetCString()) + def test_launch_fail(self): + class MyResponder(MockGDBServerResponder): + # Pretend we don't have any process during the initial queries. + def qC(self): + return "E42" + + def qfThreadInfo(self): + return "OK" # No threads. + + # Then, when we are asked to attach, error out. + def A(self, packet): + return "E47" + + self.runCmd("log enable gdb-remote packets") + self.server.responder = MyResponder() + + target = self.createTarget("a.yaml") + process = self.connect(target) + lldbutil.expect_state_changes(self, self.dbg.GetListener(), process, [lldb.eStateConnected]) + + error = lldb.SBError() + target.Launch(lldb.SBListener(), None, None, None, None, None, + None, 0, True, error) + self.assertEquals("'A' packet returned an error: 71", error.GetCString()) + def test_read_registers_using_g_packets(self): """Test reading registers using 'g' packets (default behavior)""" self.dbg.HandleCommand( diff --git a/lldb/test/API/functionalities/gdb_remote_client/TestIOSSimulator.py b/lldb/test/API/functionalities/gdb_remote_client/TestIOSSimulator.py new file mode 100644 index 0000000000000..a096a1504fd67 --- /dev/null +++ b/lldb/test/API/functionalities/gdb_remote_client/TestIOSSimulator.py @@ -0,0 +1,63 @@ +import lldb +from lldbsuite.test.lldbtest import * +from lldbsuite.test.decorators import * +from gdbclientutils import * + +class TestIOSSimulator(GDBRemoteTestBase): + """ + Test that an ios simulator process is recognized as such. + """ + + class MyResponder(MockGDBServerResponder): + def __init__(self, host, process): + self.host_ostype = host + self.process_ostype = process + MockGDBServerResponder.__init__(self) + + def respond(self, packet): + if packet == "qProcessInfo": + return self.qProcessInfo() + return MockGDBServerResponder.respond(self, packet) + + def qHostInfo(self): + return "cputype:16777223;cpusubtype:8;ostype:%s;vendor:apple;os_version:10.15.4;maccatalyst_version:13.4;endian:little;ptrsize:8;"%self.host_ostype + def qProcessInfo(self): + return "pid:a860;parent-pid:d2a0;real-uid:1f5;real-gid:14;effective-uid:1f5;effective-gid:14;cputype:1000007;cpusubtype:8;ptrsize:8;ostype:%s;vendor:apple;endian:little;"%self.process_ostype + def vCont(self): + return "vCont;" + + def platform_test(self, host, process, expected_triple): + self.server.responder = self.MyResponder(host, process) + if self.TraceOn(): + self.runCmd("log enable gdb-remote packets") + self.addTearDownHook(lambda: self.runCmd("log disable gdb-remote packets")) + + target = self.dbg.CreateTargetWithFileAndArch(None, None) + process = self.connect(target) + triple = target.GetTriple() + self.assertEqual(triple, expected_triple) + + @skipIfRemote + def test_macos(self): + self.platform_test(host="macosx", process="macosx", + expected_triple="x86_64h-apple-macosx-") + + @skipIfRemote + def test_ios_sim(self): + self.platform_test(host="macosx", process="iossimulator", + expected_triple="x86_64h-apple-ios-simulator") + + @skipIfRemote + def test_catalyst(self): + self.platform_test(host="macosx", process="maccatalyst", + expected_triple="x86_64h-apple-ios-macabi") + + @skipIfRemote + def test_tvos_sim(self): + self.platform_test(host="macosx", process="tvossimulator", + expected_triple="x86_64h-apple-tvos-simulator") + + @skipIfRemote + def test_tvos_sim(self): + self.platform_test(host="macosx", process="watchossimulator", + expected_triple="x86_64h-apple-watchos-simulator") diff --git a/lldb/test/API/functionalities/gdb_remote_client/gdbclientutils.py b/lldb/test/API/functionalities/gdb_remote_client/gdbclientutils.py index 392aeba5bd688..486485c8e28db 100644 --- a/lldb/test/API/functionalities/gdb_remote_client/gdbclientutils.py +++ b/lldb/test/API/functionalities/gdb_remote_client/gdbclientutils.py @@ -106,6 +106,8 @@ def respond(self, packet): return self.cont() if packet.startswith("vCont;c"): return self.vCont(packet) + if packet[0] == "A": + return self.A(packet) if packet[0] == "g": return self.readRegisters() if packet[0] == "G": @@ -201,6 +203,9 @@ def cont(self): def vCont(self, packet): raise self.UnexpectedPacketException() + def A(self, packet): + return "" + def readRegisters(self): return "00000000" * self.registerCount diff --git a/lldb/test/API/functionalities/inline-stepping/calling.cpp b/lldb/test/API/functionalities/inline-stepping/calling.cpp index 9982fbf42734f..49179ce7c9788 100644 --- a/lldb/test/API/functionalities/inline-stepping/calling.cpp +++ b/lldb/test/API/functionalities/inline-stepping/calling.cpp @@ -75,7 +75,7 @@ caller_trivial_1 () void caller_trivial_2 () { - inline_trivial_1 (); // In caller_trivial_2. + asm volatile ("nop"); inline_trivial_1 (); // In caller_trivial_2. inline_value += 1; // At increment in caller_trivial_2. } @@ -88,7 +88,7 @@ called_by_inline_trivial () void inline_trivial_1 () { - inline_trivial_2(); // In inline_trivial_1. + asm volatile ("nop"); inline_trivial_2(); // In inline_trivial_1. inline_value += 1; // At increment in inline_trivial_1. } diff --git a/lldb/test/API/functionalities/mtc/swift-property/TestMTCSwiftProperty.py b/lldb/test/API/functionalities/mtc/swift-property/TestMTCSwiftProperty.py index 521d3d130a92c..fa26a727aa3df 100644 --- a/lldb/test/API/functionalities/mtc/swift-property/TestMTCSwiftProperty.py +++ b/lldb/test/API/functionalities/mtc/swift-property/TestMTCSwiftProperty.py @@ -16,6 +16,8 @@ class MTCSwiftPropertyTestCase(TestBase): mydir = TestBase.compute_mydir(__file__) + @expectedFailureAll(bugnumber="rdar://60396797", + setting=('symbols.use-swift-clangimporter', 'false')) @skipUnlessDarwin def test(self): self.mtc_dylib_path = findMainThreadCheckerDylib() diff --git a/lldb/test/API/functionalities/mtc/swift/TestMTCSwift.py b/lldb/test/API/functionalities/mtc/swift/TestMTCSwift.py index ba1bf3262b95c..5aa3d85f0047e 100644 --- a/lldb/test/API/functionalities/mtc/swift/TestMTCSwift.py +++ b/lldb/test/API/functionalities/mtc/swift/TestMTCSwift.py @@ -16,6 +16,8 @@ class MTCSwiftTestCase(TestBase): mydir = TestBase.compute_mydir(__file__) + @expectedFailureAll(bugnumber="rdar://60396797", + setting=('symbols.use-swift-clangimporter', 'false')) @skipUnlessDarwin def test(self): self.mtc_dylib_path = findMainThreadCheckerDylib() diff --git a/lldb/test/API/functionalities/plugins/python_os_plugin/stepping_plugin_threads/Makefile b/lldb/test/API/functionalities/plugins/python_os_plugin/stepping_plugin_threads/Makefile new file mode 100644 index 0000000000000..c46619c662348 --- /dev/null +++ b/lldb/test/API/functionalities/plugins/python_os_plugin/stepping_plugin_threads/Makefile @@ -0,0 +1,4 @@ +CXX_SOURCES := main.cpp +ENABLE_THREADS := YES + +include Makefile.rules diff --git a/lldb/test/API/functionalities/plugins/python_os_plugin/stepping_plugin_threads/TestOSPluginStepping.py b/lldb/test/API/functionalities/plugins/python_os_plugin/stepping_plugin_threads/TestOSPluginStepping.py new file mode 100644 index 0000000000000..5bba483647310 --- /dev/null +++ b/lldb/test/API/functionalities/plugins/python_os_plugin/stepping_plugin_threads/TestOSPluginStepping.py @@ -0,0 +1,113 @@ +""" +Test that stepping works even when the OS Plugin doesn't report +all threads at every stop. +""" + +from __future__ import print_function + + +import os +import lldb +from lldbsuite.test.lldbtest import * +import lldbsuite.test.lldbutil as lldbutil + + +class TestOSPluginStepping(TestBase): + + mydir = TestBase.compute_mydir(__file__) + NO_DEBUG_INFO_TESTCASE = True + + def test_python_os_plugin(self): + """Test that stepping works when the OS Plugin doesn't report all + threads at every stop""" + self.build() + self.main_file = lldb.SBFileSpec('main.cpp') + self.run_python_os_step_missing_thread(False) + + def test_python_os_plugin_prune(self): + """Test that pruning the unreported PlanStacks works""" + self.build() + self.main_file = lldb.SBFileSpec('main.cpp') + self.run_python_os_step_missing_thread(True) + + def get_os_thread(self): + return self.process.GetThreadByID(0x111111111) + + def is_os_thread(self, thread): + id = thread.GetID() + return id == 0x111111111 + + def run_python_os_step_missing_thread(self, do_prune): + """Test that the Python operating system plugin works correctly""" + + # Our OS plugin does NOT report all threads: + result = self.dbg.HandleCommand("settings set target.experimental.os-plugin-reports-all-threads false") + + python_os_plugin_path = os.path.join(self.getSourceDir(), + "operating_system.py") + (target, self.process, thread, thread_bkpt) = lldbutil.run_to_source_breakpoint( + self, "first stop in thread - do a step out", self.main_file) + + main_bkpt = target.BreakpointCreateBySourceRegex('Stop here and do not make a memory thread for thread_1', + self.main_file) + self.assertEqual(main_bkpt.GetNumLocations(), 1, "Main breakpoint has one location") + + # There should not be an os thread before we load the plugin: + self.assertFalse(self.get_os_thread().IsValid(), "No OS thread before loading plugin") + + # Now load the python OS plug-in which should update the thread list and we should have + # an OS plug-in thread overlaying thread_1 with id 0x111111111 + command = "settings set target.process.python-os-plugin-path '%s'" % python_os_plugin_path + self.dbg.HandleCommand(command) + + # Verify our OS plug-in threads showed up + os_thread = self.get_os_thread() + self.assertTrue( + os_thread.IsValid(), + "Make sure we added the thread 0x111111111 after we load the python OS plug-in") + + # Now we are going to step-out. This should get interrupted by main_bkpt. We've + # set up the OS plugin so at this stop, we have lost the OS thread 0x111111111. + # Make sure both of these are true: + os_thread.StepOut() + + stopped_threads = lldbutil.get_threads_stopped_at_breakpoint(self.process, main_bkpt) + self.assertEqual(len(stopped_threads), 1, "Stopped at main_bkpt") + thread = self.process.GetThreadByID(0x111111111) + self.assertFalse(thread.IsValid(), "No thread 0x111111111 on second stop.") + + # Make sure we still have the thread plans for this thread: + # First, don't show unreported threads, that should fail: + command = "thread plan list -t 0x111111111" + result = lldb.SBCommandReturnObject() + interp = self.dbg.GetCommandInterpreter() + interp.HandleCommand(command, result) + self.assertFalse(result.Succeeded(), "We found no plans for the unreported thread.") + # Now do it again but with the -u flag: + command = "thread plan list -u -t 0x111111111" + result = lldb.SBCommandReturnObject() + interp.HandleCommand(command, result) + self.assertTrue(result.Succeeded(), "We found plans for the unreported thread.") + + if do_prune: + # Prune the thread plan and continue, and we will run to exit. + interp.HandleCommand("thread plan prune 0x111111111", result) + self.assertTrue(result.Succeeded(), "Found the plan for 0x111111111 and pruned it") + + # List again, make sure it doesn't work: + command = "thread plan list -u -t 0x111111111" + interp.HandleCommand(command, result) + self.assertFalse(result.Succeeded(), "We still found plans for the unreported thread.") + + self.process.Continue() + self.assertEqual(self.process.GetState(), lldb.eStateExited, "We exited.") + else: + # Now we are going to continue, and when we hit the step-out breakpoint, we will + # put the OS plugin thread back, lldb will recover its ThreadPlanStack, and + # we will stop with a "step-out" reason. + self.process.Continue() + os_thread = self.get_os_thread() + self.assertTrue(os_thread.IsValid(), "The OS thread is back after continue") + self.assertTrue("step out" in os_thread.GetStopDescription(100), "Completed step out plan") + + diff --git a/lldb/test/API/functionalities/plugins/python_os_plugin/stepping_plugin_threads/main.cpp b/lldb/test/API/functionalities/plugins/python_os_plugin/stepping_plugin_threads/main.cpp new file mode 100644 index 0000000000000..6fd6b1c4332cf --- /dev/null +++ b/lldb/test/API/functionalities/plugins/python_os_plugin/stepping_plugin_threads/main.cpp @@ -0,0 +1,55 @@ +// This test will present lldb with two threads one of which the test will +// overlay with an OSPlugin thread. Then we'll do a step out on the thread_1, +// but arrange to hit a breakpoint in main before the step out completes. At +// that point we will not report an OS plugin thread for thread_1. Then we'll +// run again and hit the step out breakpoint. Make sure we haven't deleted +// that, and recognize it. + +#include +#include +#include +#include + +static int g_value = 0; // I don't have access to the real threads in the + // OS Plugin, and I don't want to have to count + // StopID's. So I'm using this value to tell me which + // stop point the program has reached. +std::mutex g_mutex; +std::condition_variable g_cv; +static int g_condition = 0; // Using this as the variable backing g_cv + // to prevent spurious wakeups. + +void step_out_of_here() { + std::unique_lock func_lock(g_mutex); + // Set a breakpoint:first stop in thread - do a step out. + g_condition = 1; + g_cv.notify_one(); + g_cv.wait(func_lock, [&] { return g_condition == 2; }); +} + +void *thread_func() { + // Do something + step_out_of_here(); + + // Return + return NULL; +} + +int main() { + // Lock the mutex so we can block the thread: + std::unique_lock main_lock(g_mutex); + // Create the thread + std::thread thread_1(thread_func); + g_cv.wait(main_lock, [&] { return g_condition == 1; }); + g_value = 1; + g_condition = 2; + // Stop here and do not make a memory thread for thread_1. + g_cv.notify_one(); + g_value = 2; + main_lock.unlock(); + + // Wait for the threads to finish + thread_1.join(); + + return 0; +} diff --git a/lldb/test/API/functionalities/plugins/python_os_plugin/stepping_plugin_threads/operating_system.py b/lldb/test/API/functionalities/plugins/python_os_plugin/stepping_plugin_threads/operating_system.py new file mode 100644 index 0000000000000..ff9a57367a2aa --- /dev/null +++ b/lldb/test/API/functionalities/plugins/python_os_plugin/stepping_plugin_threads/operating_system.py @@ -0,0 +1,62 @@ +#!/usr/bin/python + +import lldb +import struct + + +class OperatingSystemPlugIn(object): + """Class that provides a OS plugin that along with the particular code in main.cpp + emulates the following scenario: + a) We stop in an OS Plugin created thread - which should be thread index 1 + b) We step-out from that thread + c) We hit a breakpoint in another thread, and DON'T produce the OS Plugin thread. + d) We continue, and when we hit the step out breakpoint, we again produce the same + OS Plugin thread. + main.cpp sets values into the global variable g_value, which we use to tell the OS + plugin whether to produce the OS plugin thread or not. + Since we are always producing an OS plugin thread with a backing thread, we don't + need to implement get_register_info or get_register_data. + """ + + def __init__(self, process): + '''Initialization needs a valid.SBProcess object. + + This plug-in will get created after a live process is valid and has stopped for the + first time.''' + print("Plugin initialized.") + self.process = None + self.start_stop_id = 0 + self.g_value = lldb.SBValue() + + if isinstance(process, lldb.SBProcess) and process.IsValid(): + self.process = process + self.g_value = process.GetTarget().FindFirstGlobalVariable("g_value") + if not self.g_value.IsValid(): + print("Could not find g_value") + + def create_thread(self, tid, context): + print("Called create thread with tid: ", tid) + return None + + def get_thread_info(self): + g_value = self.g_value.GetValueAsUnsigned() + print("Called get_thread_info: g_value: %d"%(g_value)) + if g_value == 0 or g_value == 2: + return [{'tid': 0x111111111, + 'name': 'one', + 'queue': 'queue1', + 'state': 'stopped', + 'stop_reason': 'breakpoint', + 'core' : 1 }] + else: + return [] + + def get_register_info(self): + print ("called get_register_info") + return None + + + def get_register_data(self, tid): + print("Get register data called for tid: %d"%(tid)) + return None + diff --git a/lldb/test/API/functionalities/process_crash_info/TestProcessCrashInfo.py b/lldb/test/API/functionalities/process_crash_info/TestProcessCrashInfo.py index d0f47de83eea4..6ef5018204fd8 100644 --- a/lldb/test/API/functionalities/process_crash_info/TestProcessCrashInfo.py +++ b/lldb/test/API/functionalities/process_crash_info/TestProcessCrashInfo.py @@ -69,6 +69,8 @@ def test_api(self): self.assertIn("pointer being freed was not allocated", stream.GetData()) + # dyld leaves permanent crash_info records when testing on device. + @skipIfDarwinEmbedded def test_on_sane_process(self): """Test that lldb doesn't fetch the extended crash information dictionnary from a 'sane' stopped process.""" diff --git a/lldb/test/API/functionalities/reproducers/attach/Makefile b/lldb/test/API/functionalities/reproducers/attach/Makefile new file mode 100644 index 0000000000000..3d0b98f13f3d7 --- /dev/null +++ b/lldb/test/API/functionalities/reproducers/attach/Makefile @@ -0,0 +1,2 @@ +CXX_SOURCES := main.cpp +include Makefile.rules diff --git a/lldb/test/API/functionalities/reproducers/attach/TestReproducerAttach.py b/lldb/test/API/functionalities/reproducers/attach/TestReproducerAttach.py new file mode 100644 index 0000000000000..968268d6838bd --- /dev/null +++ b/lldb/test/API/functionalities/reproducers/attach/TestReproducerAttach.py @@ -0,0 +1,73 @@ +""" +Test reproducer attach. +""" + +import lldb +import tempfile +from lldbsuite.test import lldbtest_config +from lldbsuite.test.decorators import * +from lldbsuite.test.lldbtest import * +from lldbsuite.test import lldbutil + + +class ReproducerAttachTestCase(TestBase): + + mydir = TestBase.compute_mydir(__file__) + NO_DEBUG_INFO_TESTCASE = True + + @skipIfFreeBSD + @skipIfNetBSD + @skipIfWindows + @skipIfRemote + @skipIfiOSSimulator + def test_reproducer_attach(self): + """Test thread creation after process attach.""" + exe = '%s_%d' % (self.testMethodName, os.getpid()) + + token = self.getBuildArtifact(exe + '.token') + if os.path.exists(token): + os.remove(token) + + reproducer = self.getBuildArtifact(exe + '.reproducer') + if os.path.exists(reproducer): + try: + shutil.rmtree(reproducer) + except OSError: + pass + + self.build(dictionary={'EXE': exe}) + self.addTearDownHook(self.cleanupSubprocesses) + + inferior = self.spawnSubprocess(self.getBuildArtifact(exe), [token]) + pid = inferior.pid + + lldbutil.wait_for_file_on_target(self, token) + + # Use Popen because pexpect is overkill and spawnSubprocess is + # asynchronous. + capture = subprocess.Popen([ + lldbtest_config.lldbExec, '-b', '--capture', '--capture-path', + reproducer, '-o', 'proc att -n {}'.format(exe), '-o', + 'reproducer generate' + ], + stdin=subprocess.PIPE, + stdout=subprocess.PIPE, + stderr=subprocess.PIPE) + outs, _ = capture.communicate() + outs = outs.decode('utf-8') + self.assertIn('Process {} stopped'.format(pid), outs) + self.assertIn('Reproducer written', outs) + + # Check that replay works. + replay = subprocess.Popen( + [lldbtest_config.lldbExec, '-replay', reproducer], + stdin=subprocess.PIPE, + stdout=subprocess.PIPE, + stderr=subprocess.PIPE) + outs, _ = replay.communicate() + outs = outs.decode('utf-8') + self.assertIn('Process {} stopped'.format(pid), outs) + + # We can dump the reproducer in the current context. + self.expect('reproducer dump -f {} -p process'.format(reproducer), + substrs=['pid = {}'.format(pid), 'name = {}'.format(exe)]) diff --git a/lldb/test/API/functionalities/reproducers/attach/main.cpp b/lldb/test/API/functionalities/reproducers/attach/main.cpp new file mode 100644 index 0000000000000..781da12400af9 --- /dev/null +++ b/lldb/test/API/functionalities/reproducers/attach/main.cpp @@ -0,0 +1,24 @@ +#include +#include +#include + +using std::chrono::seconds; + +int main(int argc, char const *argv[]) { + lldb_enable_attach(); + + // Create the synchronization token. + FILE *f; + if (f = fopen(argv[1], "wx")) { + fputs("\n", f); + fflush(f); + fclose(f); + } else + return 1; + + while (true) { + std::this_thread::sleep_for(seconds(1)); + } + + return 0; +} diff --git a/lldb/test/API/functionalities/tail_call_frames/unambiguous_sequence/main.cpp b/lldb/test/API/functionalities/tail_call_frames/unambiguous_sequence/main.cpp index edfe59777c6cd..559f8a6d66aa9 100644 --- a/lldb/test/API/functionalities/tail_call_frames/unambiguous_sequence/main.cpp +++ b/lldb/test/API/functionalities/tail_call_frames/unambiguous_sequence/main.cpp @@ -1,29 +1,30 @@ -//===-- main.cpp ------------------------------------------------*- C++ -*-===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// - volatile int x; void __attribute__((noinline)) sink() { x++; //% self.filecheck("bt", "main.cpp", "-implicit-check-not=artificial") // CHECK: frame #0: 0x{{[0-9a-f]+}} a.out`sink() at main.cpp:[[@LINE-1]]:4 [opt] - // CHECK-NEXT: frame #1: 0x{{[0-9a-f]+}} a.out`func3{{.*}} [opt] [artificial] - // CHECK-NEXT: frame #2: 0x{{[0-9a-f]+}} a.out`func2{{.*}} [opt] - // CHECK-NEXT: frame #3: 0x{{[0-9a-f]+}} a.out`func1{{.*}} [opt] [artificial] + // CHECK-NEXT: frame #1: 0x{{[0-9a-f]+}} a.out`func3() at main.cpp:14:3 [opt] [artificial] + // CHECK-NEXT: frame #2: 0x{{[0-9a-f]+}} a.out`func2() {{.*}} [opt] + // CHECK-NEXT: frame #3: 0x{{[0-9a-f]+}} a.out`func1() at main.cpp:23:3 [opt] [artificial] // CHECK-NEXT: frame #4: 0x{{[0-9a-f]+}} a.out`main{{.*}} [opt] } -void __attribute__((noinline)) func3() { sink(); /* tail */ } +void __attribute__((noinline)) func3() { + x++; + sink(); /* tail */ +} -void __attribute__((disable_tail_calls, noinline)) func2() { func3(); /* regular */ } +void __attribute__((disable_tail_calls, noinline)) func2() { + func3(); /* regular */ +} -void __attribute__((noinline)) func1() { func2(); /* tail */ } +void __attribute__((noinline)) func1() { + x++; + func2(); /* tail */ +} int __attribute__((disable_tail_calls)) main() { + // DEBUG: self.runCmd("log enable lldb step -f /tmp/lldbstep.log") func1(); /* regular */ return 0; } diff --git a/lldb/test/API/functionalities/thread_plan/Makefile b/lldb/test/API/functionalities/thread_plan/Makefile new file mode 100644 index 0000000000000..695335e068c0c --- /dev/null +++ b/lldb/test/API/functionalities/thread_plan/Makefile @@ -0,0 +1,4 @@ +C_SOURCES := main.c +CFLAGS_EXTRAS := -std=c99 + +include Makefile.rules diff --git a/lldb/test/API/functionalities/thread_plan/TestThreadPlanCommands.py b/lldb/test/API/functionalities/thread_plan/TestThreadPlanCommands.py new file mode 100644 index 0000000000000..30fdb218fc2eb --- /dev/null +++ b/lldb/test/API/functionalities/thread_plan/TestThreadPlanCommands.py @@ -0,0 +1,164 @@ +""" +Test that thread plan listing, and deleting works. +""" + + + +import lldb +import lldbsuite.test.lldbutil as lldbutil +from lldbsuite.test.lldbtest import * + + +class TestThreadPlanCommands(TestBase): + + mydir = TestBase.compute_mydir(__file__) + + NO_DEBUG_INFO_TESTCASE = True + + def test_thread_plan_actions(self): + self.build() + self.main_source_file = lldb.SBFileSpec("main.c") + self.thread_plan_test() + + def check_list_output(self, command, active_plans = [], completed_plans = [], discarded_plans = []): + # Check the "thread plan list" output against a list of active & completed and discarded plans. + # If all three check arrays are empty, that means the command is expected to fail. + + interp = self.dbg.GetCommandInterpreter() + result = lldb.SBCommandReturnObject() + + num_active = len(active_plans) + num_completed = len(completed_plans) + num_discarded = len(discarded_plans) + + interp.HandleCommand(command, result) + if self.TraceOn(): + print("Command: %s"%(command)) + print(result.GetOutput()) + + if num_active == 0 and num_completed == 0 and num_discarded == 0: + self.assertFalse(result.Succeeded(), "command: '%s' succeeded when it should have failed: '%s'"% + (command, result.GetError())) + return + + self.assertTrue(result.Succeeded(), "command: '%s' failed: '%s'"%(command, result.GetError())) + result_arr = result.GetOutput().splitlines() + num_results = len(result_arr) + + # Match the expected number of elements. + # Adjust the count for the number of header lines we aren't matching: + fudge = 0 + + if num_completed == 0 and num_discarded == 0: + # The fudge is 3: Thread header, Active Plan header and base plan + fudge = 3 + elif num_completed == 0 or num_discarded == 0: + # The fudge is 4: The above plus either the Completed or Discarded Plan header: + fudge = 4 + else: + # The fudge is 5 since we have both headers: + fudge = 5 + + self.assertEqual(num_results, num_active + num_completed + num_discarded + fudge, + "Too many elements in match arrays") + + # Now iterate through the results array and pick out the results. + result_idx = 0 + self.assertIn("thread #", result_arr[result_idx], "Found thread header") ; result_idx += 1 + self.assertIn("Active plan stack", result_arr[result_idx], "Found active header") ; result_idx += 1 + self.assertIn("Element 0: Base thread plan", result_arr[result_idx], "Found base plan") ; result_idx += 1 + + for text in active_plans: + self.assertFalse("Completed plan stack" in result_arr[result_idx], "Found Completed header too early.") + self.assertIn(text, result_arr[result_idx], "Didn't find active plan: %s"%(text)) ; result_idx += 1 + + if len(completed_plans) > 0: + self.assertIn("Completed plan stack:", result_arr[result_idx], "Found completed plan stack header") ; result_idx += 1 + for text in completed_plans: + self.assertIn(text, result_arr[result_idx], "Didn't find completed plan: %s"%(text)) ; result_idx += 1 + + if len(discarded_plans) > 0: + self.assertIn("Discarded plan stack:", result_arr[result_idx], "Found discarded plan stack header") ; result_idx += 1 + for text in discarded_plans: + self.assertIn(text, result_arr[result_idx], "Didn't find completed plan: %s"%(text)) ; result_idx += 1 + + + def thread_plan_test(self): + (target, process, thread, bkpt) = lldbutil.run_to_source_breakpoint(self, + "Set a breakpoint here", self.main_source_file) + + # Now set a breakpoint in call_me and step over. We should have + # two public thread plans + call_me_bkpt = target.BreakpointCreateBySourceRegex("Set another here", self.main_source_file) + self.assertTrue(call_me_bkpt.GetNumLocations() > 0, "Set the breakpoint successfully") + thread.StepOver() + threads = lldbutil.get_threads_stopped_at_breakpoint(process, call_me_bkpt) + self.assertEqual(len(threads), 1, "Hit my breakpoint while stepping over") + + current_id = threads[0].GetIndexID() + current_tid = threads[0].GetThreadID() + # Run thread plan list without the -i flag: + command = "thread plan list %d"%(current_id) + self.check_list_output (command, ["Stepping over line main.c"], []) + + # Run thread plan list with the -i flag: + command = "thread plan list -i %d"%(current_id) + self.check_list_output(command, ["Stepping over line main.c", "Stepping out from"]) + + # Run thread plan list providing TID, output should be the same: + command = "thread plan list -t %d"%(current_tid) + self.check_list_output(command, ["Stepping over line main.c"]) + + # Provide both index & tid, and make sure we only print once: + command = "thread plan list -t %d %d"%(current_tid, current_id) + self.check_list_output(command, ["Stepping over line main.c"]) + + # Try a fake TID, and make sure that fails: + fake_tid = 0 + for i in range(100, 10000, 100): + fake_tid = current_tid + i + thread = process.GetThreadByID(fake_tid) + if not thread: + break + + command = "thread plan list -t %d"%(fake_tid) + self.check_list_output(command) + + # Now continue, and make sure we printed the completed plan: + process.Continue() + threads = lldbutil.get_stopped_threads(process, lldb.eStopReasonPlanComplete) + self.assertEqual(len(threads), 1, "One thread completed a step") + + # Run thread plan list - there aren't any private plans at this point: + command = "thread plan list %d"%(current_id) + self.check_list_output(command, [], ["Stepping over line main.c"]) + + # Set another breakpoint that we can run to, to try deleting thread plans. + second_step_bkpt = target.BreakpointCreateBySourceRegex("Run here to step over again", + self.main_source_file) + self.assertTrue(second_step_bkpt.GetNumLocations() > 0, "Set the breakpoint successfully") + final_bkpt = target.BreakpointCreateBySourceRegex("Make sure we get here on last continue", + self.main_source_file) + self.assertTrue(final_bkpt.GetNumLocations() > 0, "Set the breakpoint successfully") + + threads = lldbutil.continue_to_breakpoint(process, second_step_bkpt) + self.assertEqual(len(threads), 1, "Hit the second step breakpoint") + + threads[0].StepOver() + threads = lldbutil.get_threads_stopped_at_breakpoint(process, call_me_bkpt) + + result = lldb.SBCommandReturnObject() + interp = self.dbg.GetCommandInterpreter() + interp.HandleCommand("thread plan discard 1", result) + self.assertTrue(result.Succeeded(), "Deleted the step over plan: %s"%(result.GetOutput())) + + # Make sure the plan gets listed in the discarded plans: + command = "thread plan list %d"%(current_id) + self.check_list_output(command, [], [], ["Stepping over line main.c:"]) + + process.Continue() + threads = lldbutil.get_threads_stopped_at_breakpoint(process, final_bkpt) + self.assertEqual(len(threads), 1, "Ran to final breakpoint") + threads = lldbutil.get_stopped_threads(process, lldb.eStopReasonPlanComplete) + self.assertEqual(len(threads), 0, "Did NOT complete the step over plan") + diff --git a/lldb/test/API/functionalities/thread_plan/main.c b/lldb/test/API/functionalities/thread_plan/main.c new file mode 100644 index 0000000000000..74654cb976a88 --- /dev/null +++ b/lldb/test/API/functionalities/thread_plan/main.c @@ -0,0 +1,16 @@ +#include + +void +call_me(int value) { + printf("called with %d\n", value); // Set another here. +} + +int +main(int argc, char **argv) +{ + call_me(argc); // Set a breakpoint here. + printf("This just spaces the two calls\n"); + call_me(argc); // Run here to step over again. + printf("More spacing\n"); + return 0; // Make sure we get here on last continue +} diff --git a/lldb/test/API/lang/cpp/bitfields/TestCppBitfields.py b/lldb/test/API/lang/cpp/bitfields/TestCppBitfields.py index 1b362e6b04f93..7320ce2b816ec 100644 --- a/lldb/test/API/lang/cpp/bitfields/TestCppBitfields.py +++ b/lldb/test/API/lang/cpp/bitfields/TestCppBitfields.py @@ -103,3 +103,10 @@ def test_and_run_command(self): '(uint64_t:1) k = 1', ]) + self.expect( + "frame variable --show-types derived", + VARIABLES_DISPLAYED_CORRECTLY, + substrs=[ + '(uint32_t) b_a = 2', + '(uint32_t:1) d_a = 1', + ]) diff --git a/lldb/test/API/lang/cpp/bitfields/main.cpp b/lldb/test/API/lang/cpp/bitfields/main.cpp index e43bf8c138e9b..986b7cb947ed0 100644 --- a/lldb/test/API/lang/cpp/bitfields/main.cpp +++ b/lldb/test/API/lang/cpp/bitfields/main.cpp @@ -60,6 +60,16 @@ int main(int argc, char const *argv[]) { } } clang_example; + class B { + public: + uint32_t b_a; + }; + + class D : public B { + public: + uint32_t d_a : 1; + } derived; + lba.a = 2; lbb.a = 1; @@ -76,6 +86,8 @@ int main(int argc, char const *argv[]) { lbd.arr[2] = '\0'; lbd.a = 5; + derived.b_a = 2; + derived.d_a = 1; return 0; // Set break point at this line. } diff --git a/lldb/test/API/lang/cpp/incomplete-types/Makefile b/lldb/test/API/lang/cpp/incomplete-types/Makefile index 769920c28336c..c39743d999da3 100644 --- a/lldb/test/API/lang/cpp/incomplete-types/Makefile +++ b/lldb/test/API/lang/cpp/incomplete-types/Makefile @@ -1,33 +1,22 @@ -CXX_SOURCES = main.cpp length.cpp a.cpp - -CFLAGS_LIMIT = -c $(CXXFLAGS) -CFLAGS_NO_LIMIT = -c $(CXXFLAGS) - -ifneq (,$(findstring clang,$(CC))) - CFLAGS_LIMIT += -flimit-debug-info - CFLAGS_NO_LIMIT += -fno-limit-debug-info -endif +CXX_SOURCES := length.cpp a.o main.o +EXE := nolimit all: limit nolimit -limit: main.o length_limit.o a.o - $(CXX) main.o length_limit.o a.o -o limit $(LDFLAGS) - -nolimit: main.o length_nolimit.o a.o - $(CXX) main.o length_nolimit.o a.o -o nolimit $(LDFLAGS) - -main.o: main.cpp - $(CXX) $(CFLAGS_LIMIT) $(SRCDIR)/main.cpp -o main.o - -length_limit.o: length.cpp - $(CXX) $(CFLAGS_LIMIT) $(SRCDIR)/length.cpp -o length_limit.o +include Makefile.rules -length_nolimit.o: length.cpp - $(CXX) $(CFLAGS_NO_LIMIT) $(SRCDIR)/length.cpp -o length_nolimit.o +# Force a.cpp to be built with no debug inforamtion +a.o: CFLAGS = $(CFLAGS_NO_DEBUG) -a.o: a.cpp - $(CXX) $(CFLAGS_NO_DEBUG) -c $(SRCDIR)/a.cpp -o a.o +# The default testsuite setup forces -fno-limit-debug-info. Let's not rely on +# CFLAGS_EXTRAS being passed after the default arguments. This rule makes +# sure the variable used by Makefile.rules for this argument is cleared. +main.o: NO_LIMIT_DEBUG_INFO_FLAGS = "" +main.o: CFLAGS_EXTRAS = -flimit-debug-info -clean: OBJECTS += limit nolimit length_limit.o length_nolimit.o length_limit.dwo length_nolimit.dwo +limit: a.o main.o + mkdir -p build_limit + $(MAKE) -C $(BUILDDIR)/build_limit -f $(MAKEFILE_RULES) \ + EXE=../limit CXX_SOURCES="length.cpp ../a.o ../main.o" \ + CFLAGS_EXTRAS=-flimit-debug-info NO_LIMIT_DEBUG_INFO_FLAGS="" -include Makefile.rules diff --git a/lldb/test/API/lang/cpp/template-function/TestTemplateFunctions.py b/lldb/test/API/lang/cpp/template-function/TestTemplateFunctions.py index 6c9a0ac35f4fd..aa98b3c4d29de 100644 --- a/lldb/test/API/lang/cpp/template-function/TestTemplateFunctions.py +++ b/lldb/test/API/lang/cpp/template-function/TestTemplateFunctions.py @@ -13,14 +13,40 @@ class TemplateFunctionsTestCase(TestBase): def do_test_template_function(self, add_cast): self.build() - (_, _, thread, _) = lldbutil.run_to_name_breakpoint(self, "main") - frame = thread.GetSelectedFrame() - expr = "foo(42)" + lldbutil.run_to_source_breakpoint(self, '// break here', + lldb.SBFileSpec("main.cpp", False)) + if add_cast: - expr = "(int)" + expr - expr_result = frame.EvaluateExpression(expr) - self.assertTrue(expr_result.IsValid()) - self.assertEqual(expr_result.GetValue(), "42") + self.expect_expr("(int) foo(42)", result_type="int", result_value="42") + else: + self.expect("expr b1 <=> b2", error=True, substrs=["warning: :1:4: '<=>' is a single token in C++2a; add a space to avoid a change in behavior"]) + + self.expect_expr("foo(42)", result_type="int", result_value="42") + + # overload with template case + self.expect_expr("h(10)", result_type="int", result_value="10") + + # ADL lookup case + self.expect_expr("f(A::C{})", result_type="int", result_value="4") + + # ADL lookup but no overload + self.expect_expr("g(A::C{})", result_type="int", result_value="4") + + # variadic function cases + self.expect_expr("var(1)", result_type="int", result_value="10") + self.expect_expr("var(1, 2)", result_type="int", result_value="10") + + # Overloaded templated operator case + self.expect_expr("b1 > b2", result_type="bool", result_value="true") + self.expect_expr("b1 >> b2", result_type="bool", result_value="true") + self.expect_expr("b1 << b2", result_type="bool", result_value="true") + self.expect_expr("b1 == b2", result_type="bool", result_value="true") + + # Overloaded operator case + self.expect_expr("d1 > d2", result_type="bool", result_value="true") + self.expect_expr("d1 >> d2", result_type="bool", result_value="true") + self.expect_expr("d1 << d2", result_type="bool", result_value="true") + self.expect_expr("d1 == d2", result_type="bool", result_value="true") @skipIfWindows def test_template_function_with_cast(self): diff --git a/lldb/test/API/lang/cpp/template-function/main.cpp b/lldb/test/API/lang/cpp/template-function/main.cpp index 035e6450cd3e5..47b2c5c1f6e4b 100644 --- a/lldb/test/API/lang/cpp/template-function/main.cpp +++ b/lldb/test/API/lang/cpp/template-function/main.cpp @@ -11,6 +11,66 @@ int foo(T t1) { return int(t1); } +// Some cases to cover ADL, we have two cases: +// +// - f which will have a overload in the global namespace if unqualified lookup +// find f(int) and f(T) is found via ADL. +// +// - g which does not have an overload in the global namespace. +namespace A { +struct C {}; + +template int f(T) { return 4; } + +template int g(T) { return 4; } +} // namespace A + +// Meant to overload A::f(T) which may be found via ADL +int f(int) { return 1; } + +// Regular overloaded functions case h(T) and h(double). +template int h(T x) { return x; } +int h(double d) { return 5; } + +template int var(Us... pargs) { return 10; } + +// Having the templated overloaded operators in a namespace effects the +// mangled name generated in the IR e.g. _ZltRK1BS1_ Vs _ZN1AltERKNS_1BES2_ +// One will be in the symbol table but the other won't. This results in a +// different code path that will result in CPlusPlusNameParser being used. +// This allows us to cover that code as well. +namespace A { +template bool operator<(const T &, const T &) { return true; } + +template bool operator>(const T &, const T &) { return true; } + +template bool operator<<(const T &, const T &) { return true; } + +template bool operator>>(const T &, const T &) { return true; } + +template bool operator==(const T &, const T &) { return true; } + +struct B {}; +} // namespace A + +struct D {}; + +// Make sure we cover more straight forward cases as well. +bool operator<(const D &, const D &) { return true; } +bool operator>(const D &, const D &) { return true; } +bool operator>>(const D &, const D &) { return true; } +bool operator<<(const D &, const D &) { return true; } +bool operator==(const D &, const D &) { return true; } + int main() { - return foo(42); + A::B b1; + A::B b2; + D d1; + D d2; + + bool result_b = b1 < b2 && b1 << b2 && b1 == b2 && b1 > b2 && b1 >> b2; + bool result_c = d1 < d2 && d1 << d2 && d1 == d2 && d1 > d2 && d1 >> d2; + + return foo(42) + result_b + result_c + f(A::C{}) + g(A::C{}) + h(10) + h(1.) + + var(1) + var(1, 2); // break here } diff --git a/lldb/test/API/lang/cpp/thread_local/TestThreadLocal.py b/lldb/test/API/lang/cpp/thread_local/TestThreadLocal.py index 5152c0010d102..e7cfa1ca14f27 100644 --- a/lldb/test/API/lang/cpp/thread_local/TestThreadLocal.py +++ b/lldb/test/API/lang/cpp/thread_local/TestThreadLocal.py @@ -1,6 +1,49 @@ -from lldbsuite.test import lldbinline from lldbsuite.test import decorators -lldbinline.MakeInlineTest(__file__, globals(), - lldbinline.expectedFailureAll(oslist=[ - "windows", "linux", "netbsd"])) +import lldb +from lldbsuite.test.decorators import * +from lldbsuite.test.lldbtest import * +from lldbsuite.test import lldbutil +from lldbsuite.test import lldbtest + + +class PlatformProcessCrashInfoTestCase(TestBase): + + mydir = TestBase.compute_mydir(__file__) + + @expectedFailureAll(oslist=["windows", "linux", "netbsd"]) + def test_thread_local(self): + # Set a breakpoint on the first instruction of the main function, + # before the TLS initialization has run. + self.build() + exe = self.getBuildArtifact("a.out") + + (target, process, _, _) = \ + lldbutil.run_to_source_breakpoint(self, "Set breakpoint here", + lldb.SBFileSpec("main.cpp")) + self.expect_expr("tl_local_int + 1", + result_type="int", result_value="323") + self.expect_expr("*tl_local_ptr + 2", + result_type="int", result_value="324") + self.expect_expr("tl_global_int", + result_type="int", result_value="123") + self.expect_expr("*tl_global_ptr", + result_type="int", result_value="45") + + # Now see if we emit the correct error when the TLS is not yet + # initialized. Let's set a breakpoint on the first instruction + # of main. + main_module = target.FindModule(lldb.SBFileSpec(exe)) + main_address = main_module.FindSymbol("main").GetStartAddress() + main_bkpt = target.BreakpointCreateBySBAddress(main_address) + + process.Kill() + lldbutil.run_to_breakpoint_do_run(self, target, main_bkpt) + + self.expect("expr tl_local_int", error=True, + substrs=["couldn't get the value of variable tl_local_int", + "No TLS data currently exists for this thread"]) + self.expect("expr *tl_local_ptr", error=True, + substrs=["couldn't get the value of variable tl_local_ptr", + "No TLS data currently exists for this thread"]) + diff --git a/lldb/test/API/lang/cpp/thread_local/main.cpp b/lldb/test/API/lang/cpp/thread_local/main.cpp index 1855b7c5f3441..04c7fc0ed74de 100644 --- a/lldb/test/API/lang/cpp/thread_local/main.cpp +++ b/lldb/test/API/lang/cpp/thread_local/main.cpp @@ -3,15 +3,9 @@ thread_local int tl_global_int = 123; thread_local int *tl_global_ptr = &storage; int main(int argc, char **argv) { - //% self.expect("expr tl_local_int", error=True, substrs=["couldn't get the value of variable tl_local_int"]) - //% self.expect("expr *tl_local_ptr", error=True, substrs=["couldn't get the value of variable tl_local_ptr"]) thread_local int tl_local_int = 321; thread_local int *tl_local_ptr = nullptr; tl_local_ptr = &tl_local_int; tl_local_int++; - //% self.expect("expr tl_local_int + 1", substrs=["int", "= 323"]) - //% self.expect("expr *tl_local_ptr + 2", substrs=["int", "= 324"]) - //% self.expect("expr tl_global_int", substrs=["int", "= 123"]) - //% self.expect("expr *tl_global_ptr", substrs=["int", "= 45"]) - return 0; + return 0; // Set breakpoint here } diff --git a/lldb/test/API/lang/objc/hidden-ivars/Makefile b/lldb/test/API/lang/objc/hidden-ivars/Makefile index 0664769456eff..283e8a118fb16 100644 --- a/lldb/test/API/lang/objc/hidden-ivars/Makefile +++ b/lldb/test/API/lang/objc/hidden-ivars/Makefile @@ -4,4 +4,24 @@ OBJC_SOURCES := main.m LD_EXTRAS = -framework Foundation +all: a.out libInternalDefiner.dylib stripped + include Makefile.rules + +ifeq "$(MAKE_DSYM)" "YES" +stripped: a.out.dSYM +endif + +stripped: a.out libInternalDefiner.dylib + mkdir stripped + strip -Sx a.out -o stripped/a.out + strip -Sx libInternalDefiner.dylib -o stripped/libInternalDefiner.dylib +ifneq "$(CODESIGN)" "" + $(CODESIGN) -fs - stripped/a.out +endif +ifneq "$(CODESIGN)" "" + $(CODESIGN) -fs - stripped/libInternalDefiner.dylib +endif +ifeq "$(MAKE_DSYM)" "YES" + cp -r a.out.dSYM stripped/a.out.dSYM +endif diff --git a/lldb/test/API/lang/objc/hidden-ivars/TestHiddenIvars.py b/lldb/test/API/lang/objc/hidden-ivars/TestHiddenIvars.py index 03a325ac49c62..5930ffdc958aa 100644 --- a/lldb/test/API/lang/objc/hidden-ivars/TestHiddenIvars.py +++ b/lldb/test/API/lang/objc/hidden-ivars/TestHiddenIvars.py @@ -80,20 +80,11 @@ def test_frame_variable_across_modules(self): def common_setup(self, strip): if strip: - self.assertTrue(subprocess.call( - ['/usr/bin/strip', '-Sx', - self.getBuildArtifact('libInternalDefiner.dylib')]) == 0, - 'stripping dylib succeeded') - self.assertTrue(subprocess.call( - ['/bin/rm', '-rf', - self.getBuildArtifact('libInternalDefiner.dylib.dSYM')]) == 0, - 'remove dylib dSYM file succeeded') - self.assertTrue(subprocess.call(['/usr/bin/strip', '-Sx', - self.getBuildArtifact("a.out") - ]) == 0, - 'stripping a.out succeeded') + exe = self.getBuildArtifact("stripped/a.out") + else: + exe = self.getBuildArtifact("a.out") # Create a target by the debugger. - target = self.dbg.CreateTarget(self.getBuildArtifact("a.out")) + target = self.dbg.CreateTarget(exe) self.assertTrue(target, VALID_TARGET) # Create the breakpoint inside function 'main'. @@ -110,7 +101,6 @@ def common_setup(self, strip): None, environment, self.get_process_working_directory()) self.assertTrue(process, PROCESS_IS_VALID) - exe = self.getBuildArtifact("a.out") self.runCmd("file " + exe, CURRENT_EXECUTABLE_SET) # Break inside the foo function which takes a bar_ptr argument. diff --git a/lldb/test/API/lang/objc/ivar-IMP/Makefile b/lldb/test/API/lang/objc/ivar-IMP/Makefile index ba7e23acabab1..5d920f4421368 100644 --- a/lldb/test/API/lang/objc/ivar-IMP/Makefile +++ b/lldb/test/API/lang/objc/ivar-IMP/Makefile @@ -1,13 +1,8 @@ -CFLAGS := -g -O0 -CFLAGS_NO_DEBUG = +OBJC_SOURCES := myclass.m repro.m +LD_EXTRAS := -framework Foundation -all: aout - -aout: - $(CC) $(CFLAGS_NO_DEBUG) $(SRCDIR)/myclass.m -c -o myclass.o - $(CC) $(CFLAGS) myclass.o $(SRCDIR)/repro.m -framework Foundation +include Makefile.rules -clean:: - rm -f myclass.o +# Force myclass.m to be compiled without debug info +myclass.o: CFLAGS = $(CFLAGS_NO_DEBUG) -include Makefile.rules diff --git a/lldb/test/API/lang/objc/objc-ivar-stripped/Makefile b/lldb/test/API/lang/objc/objc-ivar-stripped/Makefile index a218ce37e61df..8b63215d6d9da 100644 --- a/lldb/test/API/lang/objc/objc-ivar-stripped/Makefile +++ b/lldb/test/API/lang/objc/objc-ivar-stripped/Makefile @@ -3,11 +3,10 @@ LD_EXTRAS := -lobjc -framework Foundation all: a.out.stripped +include Makefile.rules + a.out.stripped: a.out.dSYM strip -o a.out.stripped a.out - -clean:: - rm -f a.out.stripped - rm -rf a.out.stripped.dSYM - -include Makefile.rules +ifneq "$(CODESIGN)" "" + $(CODESIGN) -fs - a.out.stripped +endif diff --git a/lldb/test/API/lang/swift/array_tuple_resilient/TestSwiftArrayTupleResilient.py b/lldb/test/API/lang/swift/array_tuple_resilient/TestSwiftArrayTupleResilient.py index fce1c086555d4..96679bbaac78d 100644 --- a/lldb/test/API/lang/swift/array_tuple_resilient/TestSwiftArrayTupleResilient.py +++ b/lldb/test/API/lang/swift/array_tuple_resilient/TestSwiftArrayTupleResilient.py @@ -1,4 +1,7 @@ import lldbsuite.test.lldbinline as lldbinline from lldbsuite.test.decorators import * -lldbinline.MakeInlineTest(__file__, globals(), decorators=[swiftTest, skipUnlessDarwin]) +lldbinline.MakeInlineTest(__file__, globals(), decorators=[swiftTest, skipUnlessDarwin, +expectedFailureAll(bugnumber="rdar://60396797", + setting=('symbols.use-swift-clangimporter', 'false')) +]) diff --git a/lldb/test/API/lang/swift/bridged_metatype/TestSwiftBridgedMetatype.py b/lldb/test/API/lang/swift/bridged_metatype/TestSwiftBridgedMetatype.py index 51433ef657b4d..d9a801d7aaf2e 100644 --- a/lldb/test/API/lang/swift/bridged_metatype/TestSwiftBridgedMetatype.py +++ b/lldb/test/API/lang/swift/bridged_metatype/TestSwiftBridgedMetatype.py @@ -16,6 +16,9 @@ class TestSwiftBridgedMetatype(TestBase): def setUp(self): TestBase.setUp(self) + @expectedFailureAll(bugnumber="rdar://60396797", + oslist=lldbplatform.darwin_all, + setting=('symbols.use-swift-clangimporter', 'false')) @swiftTest def test_swift_bridged_metatype(self): """Test the formatting of bridged Swift metatypes""" diff --git a/lldb/test/API/lang/swift/clangimporter/bridging_header_headermap/TestSwiftBridgingHeaderHeadermap.py b/lldb/test/API/lang/swift/clangimporter/bridging_header_headermap/TestSwiftBridgingHeaderHeadermap.py index e5e5bbb05e77a..535e4787d5fb0 100644 --- a/lldb/test/API/lang/swift/clangimporter/bridging_header_headermap/TestSwiftBridgingHeaderHeadermap.py +++ b/lldb/test/API/lang/swift/clangimporter/bridging_header_headermap/TestSwiftBridgingHeaderHeadermap.py @@ -26,6 +26,8 @@ class TestSwiftBridgingHeaderHeadermap(TestBase): def setUp(self): TestBase.setUp(self) + # Don't run ClangImporter tests if Clangimporter is disabled. + @skipIf(setting=('symbols.use-swift-clangimporter', 'false')) @skipUnlessDarwin @swiftTest def test(self): diff --git a/lldb/test/API/lang/swift/clangimporter/config_macros/TestSwiftDedupMacros.py b/lldb/test/API/lang/swift/clangimporter/config_macros/TestSwiftDedupMacros.py index f782d6dd8ba19..a7f6c3157c2fa 100644 --- a/lldb/test/API/lang/swift/clangimporter/config_macros/TestSwiftDedupMacros.py +++ b/lldb/test/API/lang/swift/clangimporter/config_macros/TestSwiftDedupMacros.py @@ -24,6 +24,8 @@ class TestSwiftDedupMacros(TestBase): def setUp(self): TestBase.setUp(self) + # Don't run ClangImporter tests if Clangimporter is disabled. + @skipIf(setting=('symbols.use-swift-clangimporter', 'false')) # NOTE: rdar://44201206 - This test may sporadically segfault. It's likely # that the underlying memory corruption issue has been addressed, but due # to the difficulty of reproducing the crash, we are not sure. If a crash diff --git a/lldb/test/API/lang/swift/clangimporter/dynamic_type_resolution_import_conflict/TestSwiftDynamicTypeResolutionImportConflict.py b/lldb/test/API/lang/swift/clangimporter/dynamic_type_resolution_import_conflict/TestSwiftDynamicTypeResolutionImportConflict.py index cc9484aebd26f..36a9714cf802a 100644 --- a/lldb/test/API/lang/swift/clangimporter/dynamic_type_resolution_import_conflict/TestSwiftDynamicTypeResolutionImportConflict.py +++ b/lldb/test/API/lang/swift/clangimporter/dynamic_type_resolution_import_conflict/TestSwiftDynamicTypeResolutionImportConflict.py @@ -25,6 +25,8 @@ class TestSwiftDynamicTypeResolutionImportConflict(TestBase): def setUp(self): TestBase.setUp(self) + # Don't run ClangImporter tests if Clangimporter is disabled. + @skipIf(setting=('symbols.use-swift-clangimporter', 'false')) @skipUnlessDarwin @swiftTest def test(self): diff --git a/lldb/test/API/lang/swift/clangimporter/extra_clang_flags/TestSwiftExtraClangFlags.py b/lldb/test/API/lang/swift/clangimporter/extra_clang_flags/TestSwiftExtraClangFlags.py index d86e559badf65..a7965ae8d5165 100644 --- a/lldb/test/API/lang/swift/clangimporter/extra_clang_flags/TestSwiftExtraClangFlags.py +++ b/lldb/test/API/lang/swift/clangimporter/extra_clang_flags/TestSwiftExtraClangFlags.py @@ -11,6 +11,8 @@ class TestSwiftExtraClangFlags(TestBase): def setUp(self): TestBase.setUp(self) + # Don't run ClangImporter tests if Clangimporter is disabled. + @skipIf(setting=('symbols.use-swift-clangimporter', 'false')) @skipUnlessDarwin @swiftTest def test_sanity(self): @@ -20,6 +22,8 @@ def test_sanity(self): self.expect("frame var foo", "sanity check", substrs=['(Foo)']) self.expect("expr FromOverlay(i: 23)", error=True) + # Don't run ClangImporter tests if Clangimporter is disabled. + @skipIf(setting=('symbols.use-swift-clangimporter', 'false')) @skipUnlessDarwin @swiftTest def test_extra_clang_flags(self): diff --git a/lldb/test/API/lang/swift/clangimporter/headermap_conflict/TestSwiftHeadermapConflict.py b/lldb/test/API/lang/swift/clangimporter/headermap_conflict/TestSwiftHeadermapConflict.py index d0233276868ae..5e678bc565479 100644 --- a/lldb/test/API/lang/swift/clangimporter/headermap_conflict/TestSwiftHeadermapConflict.py +++ b/lldb/test/API/lang/swift/clangimporter/headermap_conflict/TestSwiftHeadermapConflict.py @@ -25,6 +25,8 @@ class TestSwiftHeadermapConflict(TestBase): def setUp(self): TestBase.setUp(self) + @skipIf(bugnumber="rdar://60396797", + setting=('symbols.use-swift-clangimporter', 'false')) @skipUnlessDarwin @swiftTest def test(self): diff --git a/lldb/test/API/lang/swift/clangimporter/include_conflict/TestSwiftIncludeConflict.py b/lldb/test/API/lang/swift/clangimporter/include_conflict/TestSwiftIncludeConflict.py index 12dc7a243a4e7..72b7e0014aeac 100644 --- a/lldb/test/API/lang/swift/clangimporter/include_conflict/TestSwiftIncludeConflict.py +++ b/lldb/test/API/lang/swift/clangimporter/include_conflict/TestSwiftIncludeConflict.py @@ -25,6 +25,8 @@ class TestSwiftIncludeConflict(TestBase): def setUp(self): TestBase.setUp(self) + # Don't run ClangImporter tests if Clangimporter is disabled. + @skipIf(setting=('symbols.use-swift-clangimporter', 'false')) @skipUnlessDarwin @swiftTest def test(self): diff --git a/lldb/test/API/lang/swift/clangimporter/macro_conflict/TestSwiftMacroConflict.py b/lldb/test/API/lang/swift/clangimporter/macro_conflict/TestSwiftMacroConflict.py index 4073bd220b8c5..c69874d39d30c 100644 --- a/lldb/test/API/lang/swift/clangimporter/macro_conflict/TestSwiftMacroConflict.py +++ b/lldb/test/API/lang/swift/clangimporter/macro_conflict/TestSwiftMacroConflict.py @@ -25,6 +25,8 @@ class TestSwiftMacroConflict(TestBase): def setUp(self): TestBase.setUp(self) + # Don't run ClangImporter tests if Clangimporter is disabled. + @skipIf(setting=('symbols.use-swift-clangimporter', 'false')) @skipUnlessDarwin @swiftTest def test(self): @@ -61,6 +63,8 @@ def test(self): self.assertTrue(os.path.isdir(mod_cache), "module cache exists") lldb.SBDebugger.MemoryPressureDetected() + # Don't run ClangImporter tests if Clangimporter is disabled. + @skipIf(setting=('symbols.use-swift-clangimporter', 'false')) @skipUnlessDarwin @swiftTest def test_with_dwarfimporter(self): diff --git a/lldb/test/API/lang/swift/clangimporter/objcmain_conflicting_dylibs/TestSwiftObjCMainConflictingDylibs.py b/lldb/test/API/lang/swift/clangimporter/objcmain_conflicting_dylibs/TestSwiftObjCMainConflictingDylibs.py index 9ba124a8454d2..32b045ba76196 100644 --- a/lldb/test/API/lang/swift/clangimporter/objcmain_conflicting_dylibs/TestSwiftObjCMainConflictingDylibs.py +++ b/lldb/test/API/lang/swift/clangimporter/objcmain_conflicting_dylibs/TestSwiftObjCMainConflictingDylibs.py @@ -25,6 +25,8 @@ class TestSwiftObjCMainConflictingDylibs(TestBase): def setUp(self): TestBase.setUp(self) + # Don't run ClangImporter tests if Clangimporter is disabled. + @skipIf(setting=('symbols.use-swift-clangimporter', 'false')) @skipUnlessDarwin @swiftTest def test(self): diff --git a/lldb/test/API/lang/swift/clangimporter/objcmain_conflicting_dylibs_bridging_headers/TestSwiftObjCMainConflictingDylibsBridgingHeader.py b/lldb/test/API/lang/swift/clangimporter/objcmain_conflicting_dylibs_bridging_headers/TestSwiftObjCMainConflictingDylibsBridgingHeader.py index 1d8feabea3322..89a66fd060a7d 100644 --- a/lldb/test/API/lang/swift/clangimporter/objcmain_conflicting_dylibs_bridging_headers/TestSwiftObjCMainConflictingDylibsBridgingHeader.py +++ b/lldb/test/API/lang/swift/clangimporter/objcmain_conflicting_dylibs_bridging_headers/TestSwiftObjCMainConflictingDylibsBridgingHeader.py @@ -25,6 +25,8 @@ class TestSwiftObjCMainConflictingDylibsBridgingHeader(TestBase): def setUp(self): TestBase.setUp(self) + # Don't run ClangImporter tests if Clangimporter is disabled. + @skipIf(setting=('symbols.use-swift-clangimporter', 'false')) @skipUnlessDarwin @swiftTest def test(self): diff --git a/lldb/test/API/lang/swift/clangimporter/objcmain_conflicting_dylibs_failing_import/TestSwiftObjCMainConflictingDylibsFailingImport.py b/lldb/test/API/lang/swift/clangimporter/objcmain_conflicting_dylibs_failing_import/TestSwiftObjCMainConflictingDylibsFailingImport.py index 3734f5592590a..60026f27394aa 100644 --- a/lldb/test/API/lang/swift/clangimporter/objcmain_conflicting_dylibs_failing_import/TestSwiftObjCMainConflictingDylibsFailingImport.py +++ b/lldb/test/API/lang/swift/clangimporter/objcmain_conflicting_dylibs_failing_import/TestSwiftObjCMainConflictingDylibsFailingImport.py @@ -25,6 +25,8 @@ class TestSwiftObjCMainConflictingDylibsFailingImport(TestBase): def setUp(self): TestBase.setUp(self) + # Don't run ClangImporter tests if Clangimporter is disabled. + @skipIf(setting=('symbols.use-swift-clangimporter', 'false')) @skipUnlessDarwin @swiftTest def test(self): diff --git a/lldb/test/API/lang/swift/clangimporter/remoteast_import/TestSwiftRemoteASTImport.py b/lldb/test/API/lang/swift/clangimporter/remoteast_import/TestSwiftRemoteASTImport.py index efbcab8ec6104..0928c9243bf6e 100644 --- a/lldb/test/API/lang/swift/clangimporter/remoteast_import/TestSwiftRemoteASTImport.py +++ b/lldb/test/API/lang/swift/clangimporter/remoteast_import/TestSwiftRemoteASTImport.py @@ -24,6 +24,8 @@ class TestSwiftRemoteASTImport(TestBase): def setUp(self): TestBase.setUp(self) + # Don't run ClangImporter tests if Clangimporter is disabled. + @skipIf(setting=('symbols.use-swift-clangimporter', 'false')) @skipUnlessDarwin @swiftTest def testSwiftRemoteASTImport(self): diff --git a/lldb/test/API/lang/swift/clangimporter/rewrite_clang_paths/TestSwiftRewriteClangPaths.py b/lldb/test/API/lang/swift/clangimporter/rewrite_clang_paths/TestSwiftRewriteClangPaths.py index 52ce620b3859e..f7e54b3885a9c 100644 --- a/lldb/test/API/lang/swift/clangimporter/rewrite_clang_paths/TestSwiftRewriteClangPaths.py +++ b/lldb/test/API/lang/swift/clangimporter/rewrite_clang_paths/TestSwiftRewriteClangPaths.py @@ -25,12 +25,16 @@ class TestSwiftRewriteClangPaths(TestBase): def setUp(self): TestBase.setUp(self) + # Don't run ClangImporter tests if Clangimporter is disabled. + @skipIf(setting=('symbols.use-swift-clangimporter', 'false')) @skipUnlessDarwin @swiftTest @skipIf(debug_info=no_match(["dsym"])) def testWithRemap(self): self.dotest(True) + # Don't run ClangImporter tests if Clangimporter is disabled. + @skipIf(setting=('symbols.use-swift-clangimporter', 'false')) @skipUnlessDarwin @swiftTest @skipIf(debug_info=no_match(["dsym"])) diff --git a/lldb/test/API/lang/swift/clangimporter/static_archive/TestSwiftStaticArchiveTwoSwiftmodules.py b/lldb/test/API/lang/swift/clangimporter/static_archive/TestSwiftStaticArchiveTwoSwiftmodules.py index 19d918d5196b9..8fef90151bda6 100644 --- a/lldb/test/API/lang/swift/clangimporter/static_archive/TestSwiftStaticArchiveTwoSwiftmodules.py +++ b/lldb/test/API/lang/swift/clangimporter/static_archive/TestSwiftStaticArchiveTwoSwiftmodules.py @@ -25,6 +25,8 @@ class TestSwiftStaticArchiveTwoSwiftmodules(TestBase): def setUp(self): TestBase.setUp(self) + # Don't run ClangImporter tests if Clangimporter is disabled. + @skipIf(setting=('symbols.use-swift-clangimporter', 'false')) @skipUnlessDarwin @swiftTest def test(self): diff --git a/lldb/test/API/lang/swift/completion/TestSwiftREPLCompletion.py b/lldb/test/API/lang/swift/completion/TestSwiftREPLCompletion.py index eb776440fbb6d..6a5eb84e6f3b3 100644 --- a/lldb/test/API/lang/swift/completion/TestSwiftREPLCompletion.py +++ b/lldb/test/API/lang/swift/completion/TestSwiftREPLCompletion.py @@ -23,9 +23,9 @@ def test_basic_completion(self): # pexpect is not recognized as a interactive terminal by pexpect it seems. self.child.send("\t\t\t") - # Try completing something that only has one result "Hasabl" -> "Hashable". - self.child.send("Hashabl\t") - self.child.expect_exact("Hashable") + # Try completing something that only has one result "fun" -> "func". + self.child.send("fun\t") + self.child.expect_exact("func") self.child.sendline("") # Try completing something that has multiple completions. diff --git a/lldb/test/API/lang/swift/conditional_breakpoints/TestSwiftConditionalBreakpoint.py b/lldb/test/API/lang/swift/conditional_breakpoints/TestSwiftConditionalBreakpoint.py index e6e1c74785362..f4ab631c8ec46 100644 --- a/lldb/test/API/lang/swift/conditional_breakpoints/TestSwiftConditionalBreakpoint.py +++ b/lldb/test/API/lang/swift/conditional_breakpoints/TestSwiftConditionalBreakpoint.py @@ -24,7 +24,6 @@ class TestSwiftConditionalBreakpoint(TestBase): mydir = TestBase.compute_mydir(__file__) @swiftTest - @skipIfLinux def test_swift_conditional_breakpoint(self): """Tests that we can set a conditional breakpoint in Swift code""" self.build() diff --git a/lldb/test/API/lang/swift/deployment_target/TestSwiftDeploymentTarget.py b/lldb/test/API/lang/swift/deployment_target/TestSwiftDeploymentTarget.py index 805407b49b429..62b13e5361aea 100644 --- a/lldb/test/API/lang/swift/deployment_target/TestSwiftDeploymentTarget.py +++ b/lldb/test/API/lang/swift/deployment_target/TestSwiftDeploymentTarget.py @@ -23,6 +23,8 @@ class TestSwiftDeploymentTarget(TestBase): mydir = TestBase.compute_mydir(__file__) + @skipIf(bugnumber="rdar://60396797", # should work but crashes. + setting=('symbols.use-swift-clangimporter', 'false')) @skipUnlessDarwin @skipIfDarwinEmbedded # This test uses macOS triples explicitly. @skipIf(macos_version=["<", "10.11"]) @@ -35,6 +37,8 @@ def test_swift_deployment_target(self): lldb.SBFileSpec('main.swift')) self.expect("p f", substrs=['i = 23']) + @skipIf(bugnumber="rdar://60396797", # should work but crashes. + setting=('symbols.use-swift-clangimporter', 'false')) @skipUnlessDarwin @skipIfDarwinEmbedded # This test uses macOS triples explicitely. @skipIf(macos_version=["<", "10.11"]) diff --git a/lldb/test/API/lang/swift/enum_objc/TestEnumObjC.py b/lldb/test/API/lang/swift/enum_objc/TestEnumObjC.py index e0768afb05784..3765776a47a6d 100644 --- a/lldb/test/API/lang/swift/enum_objc/TestEnumObjC.py +++ b/lldb/test/API/lang/swift/enum_objc/TestEnumObjC.py @@ -1,4 +1,7 @@ import lldbsuite.test.lldbinline as lldbinline from lldbsuite.test.decorators import * -lldbinline.MakeInlineTest(__file__, globals(), decorators=[swiftTest]) +lldbinline.MakeInlineTest(__file__, globals(), decorators=[ + skipIf(bugnumber="rdar://60396797", # should work but crashes. + setting=('symbols.use-swift-clangimporter', 'false')), + swiftTest]) diff --git a/lldb/test/API/lang/swift/expression/classes/fromobjc/TestSwiftExpressionsInMethodsFromObjc.py b/lldb/test/API/lang/swift/expression/classes/fromobjc/TestSwiftExpressionsInMethodsFromObjc.py index 530d848e5ceb7..ea7082247053e 100644 --- a/lldb/test/API/lang/swift/expression/classes/fromobjc/TestSwiftExpressionsInMethodsFromObjc.py +++ b/lldb/test/API/lang/swift/expression/classes/fromobjc/TestSwiftExpressionsInMethodsFromObjc.py @@ -39,6 +39,8 @@ def check_expression(self, expression, expected_result, use_summary=True): expression, expected_result, answer) self.assertTrue(answer == expected_result, report_str) + @skipIf(bugnumber="rdar://60396797", # should work but crashes. + setting=('symbols.use-swift-clangimporter', 'false')) @skipUnlessDarwin @swiftTest def test_swift_expressions_from_objc(self): diff --git a/lldb/test/API/lang/swift/first_expr_module_load/TestFirstExprModuleLoad.py b/lldb/test/API/lang/swift/first_expr_module_load/TestFirstExprModuleLoad.py index fce1c086555d4..4b0198aa71da0 100644 --- a/lldb/test/API/lang/swift/first_expr_module_load/TestFirstExprModuleLoad.py +++ b/lldb/test/API/lang/swift/first_expr_module_load/TestFirstExprModuleLoad.py @@ -1,4 +1,7 @@ import lldbsuite.test.lldbinline as lldbinline from lldbsuite.test.decorators import * -lldbinline.MakeInlineTest(__file__, globals(), decorators=[swiftTest, skipUnlessDarwin]) +lldbinline.MakeInlineTest(__file__, globals(), decorators=[swiftTest, skipUnlessDarwin, + skipIf(bugnumber="rdar://60396797", # should work but crashes. + setting=('symbols.use-swift-clangimporter', 'false')) +]) diff --git a/lldb/test/API/lang/swift/foundation_value_types/data/TestSwiftFoundationTypeData.py b/lldb/test/API/lang/swift/foundation_value_types/data/TestSwiftFoundationTypeData.py index ac0e40de886fb..a33c05bfa7621 100644 --- a/lldb/test/API/lang/swift/foundation_value_types/data/TestSwiftFoundationTypeData.py +++ b/lldb/test/API/lang/swift/foundation_value_types/data/TestSwiftFoundationTypeData.py @@ -13,4 +13,8 @@ from lldbsuite.test.decorators import * lldbinline.MakeInlineTest(__file__, globals(), - decorators=[swiftTest,skipUnlessDarwin]) + decorators=[ + swiftTest,skipUnlessDarwin, + skipIf(bugnumber="rdar://60396797", # should work but crashes. + setting=('symbols.use-swift-clangimporter', 'false')) +]) diff --git a/lldb/test/API/lang/swift/foundation_value_types/decimal/TestSwiftFoundationTypeDecimal.py b/lldb/test/API/lang/swift/foundation_value_types/decimal/TestSwiftFoundationTypeDecimal.py index 1048d65fc050a..f761b3c67c24f 100644 --- a/lldb/test/API/lang/swift/foundation_value_types/decimal/TestSwiftFoundationTypeDecimal.py +++ b/lldb/test/API/lang/swift/foundation_value_types/decimal/TestSwiftFoundationTypeDecimal.py @@ -2,4 +2,7 @@ from lldbsuite.test.decorators import * lldbinline.MakeInlineTest(__file__, globals(), - decorators=[swiftTest,skipUnlessDarwin]) + decorators=[swiftTest,skipUnlessDarwin, +expectedFailureAll(bugnumber="rdar://60396797", + setting=('symbols.use-swift-clangimporter', 'false')) +]) diff --git a/lldb/test/API/lang/swift/foundation_value_types/measurement/TestSwiftFoundationTypeMeasurement.py b/lldb/test/API/lang/swift/foundation_value_types/measurement/TestSwiftFoundationTypeMeasurement.py index e437f6658979b..e5a427a50c096 100644 --- a/lldb/test/API/lang/swift/foundation_value_types/measurement/TestSwiftFoundationTypeMeasurement.py +++ b/lldb/test/API/lang/swift/foundation_value_types/measurement/TestSwiftFoundationTypeMeasurement.py @@ -13,4 +13,7 @@ from lldbsuite.test.decorators import * lldbinline.MakeInlineTest(__file__, globals(), - decorators=[swiftTest,skipUnlessDarwin]) + decorators=[swiftTest,skipUnlessDarwin, + expectedFailureAll(bugnumber="rdar://60396797", + setting=('symbols.use-swift-clangimporter', 'false')) +]) diff --git a/lldb/test/API/lang/swift/foundation_value_types/notification/TestSwiftFoundationTypeNotification.py b/lldb/test/API/lang/swift/foundation_value_types/notification/TestSwiftFoundationTypeNotification.py index 12199fb21e44c..dff8c5c16c87f 100644 --- a/lldb/test/API/lang/swift/foundation_value_types/notification/TestSwiftFoundationTypeNotification.py +++ b/lldb/test/API/lang/swift/foundation_value_types/notification/TestSwiftFoundationTypeNotification.py @@ -14,4 +14,7 @@ lldbinline.MakeInlineTest( __file__, globals(), decorators= - [skipUnlessDarwin,swiftTest]) + [skipUnlessDarwin,swiftTest, + expectedFailureAll(bugnumber="rdar://60396797", + setting=('symbols.use-swift-clangimporter', 'false')) +]) diff --git a/lldb/test/API/lang/swift/foundation_value_types/url/TestSwiftFoundationTypeURL.py b/lldb/test/API/lang/swift/foundation_value_types/url/TestSwiftFoundationTypeURL.py index 958c8fac57091..54eb5c2ba5fb5 100644 --- a/lldb/test/API/lang/swift/foundation_value_types/url/TestSwiftFoundationTypeURL.py +++ b/lldb/test/API/lang/swift/foundation_value_types/url/TestSwiftFoundationTypeURL.py @@ -13,4 +13,7 @@ from lldbsuite.test.decorators import * lldbinline.MakeInlineTest(__file__, globals(), - decorators=[swiftTest,skipUnlessDarwin]) + decorators=[swiftTest,skipUnlessDarwin, + expectedFailureAll(bugnumber="rdar://60396797", + setting=('symbols.use-swift-clangimporter', 'false')) +]) diff --git a/lldb/test/API/lang/swift/implementation_only_imports/main_executable/TestMainExecutable.py b/lldb/test/API/lang/swift/implementation_only_imports/main_executable/TestMainExecutable.py index ec0dc06fa7e57..b270013704ce8 100644 --- a/lldb/test/API/lang/swift/implementation_only_imports/main_executable/TestMainExecutable.py +++ b/lldb/test/API/lang/swift/implementation_only_imports/main_executable/TestMainExecutable.py @@ -41,6 +41,8 @@ def launch_info(self): return info + @skipIf(bugnumber="rdar://problem/54322424", # This test is unreliable. + setting=('symbols.use-swift-clangimporter', 'false')) @swiftTest def test_implementation_only_import_main_executable(self): """Test `@_implementationOnly import` in the main executable @@ -64,6 +66,8 @@ def cleanup(): self.expect("e container", substrs=["(main.ContainsTwoInts)", "wrapped = (first = 2, second = 3)", "other = 10"]) self.expect("e TwoInts(4, 5)", substrs=["(SomeLibrary.TwoInts)", "= (first = 4, second = 5)"]) + @skipIf(bugnumber="rdar://problem/54322424", # This test is unreliable. + setting=('symbols.use-swift-clangimporter', 'false')) @swiftTest def test_implementation_only_import_main_executable_no_library_module(self): """Test `@_implementationOnly import` in the main executable, after removing the library's swiftmodule diff --git a/lldb/test/API/lang/swift/mix_any_object/TestSwiftMixAnyObjectType.py b/lldb/test/API/lang/swift/mix_any_object/TestSwiftMixAnyObjectType.py index fb92e3e3fd10b..22206dcb9785f 100644 --- a/lldb/test/API/lang/swift/mix_any_object/TestSwiftMixAnyObjectType.py +++ b/lldb/test/API/lang/swift/mix_any_object/TestSwiftMixAnyObjectType.py @@ -27,6 +27,8 @@ class TestSwiftMixAnyObjectType(TestBase): def setUp(self): TestBase.setUp(self) + @expectedFailureAll(bugnumber="rdar://60396797", + setting=('symbols.use-swift-clangimporter', 'false')) @skipUnlessDarwin @swiftTest def test_any_object_type(self): diff --git a/lldb/test/API/lang/swift/multilang_category/TestMultilangFormatterCategories.py b/lldb/test/API/lang/swift/multilang_category/TestMultilangFormatterCategories.py index e7943cdc81072..1083924d9149d 100644 --- a/lldb/test/API/lang/swift/multilang_category/TestMultilangFormatterCategories.py +++ b/lldb/test/API/lang/swift/multilang_category/TestMultilangFormatterCategories.py @@ -15,6 +15,8 @@ class TestMultilangFormatterCategories(TestBase): def setUp(self): TestBase.setUp(self) + @expectedFailureAll(bugnumber="rdar://60396797", + setting=('symbols.use-swift-clangimporter', 'false')) @swiftTest @skipUnlessDarwin def test_multilang_formatter_categories(self): diff --git a/lldb/test/API/lang/swift/nsarray_code_running_formatter/TestSwiftNSArrayCodeRunningFormatter.py b/lldb/test/API/lang/swift/nsarray_code_running_formatter/TestSwiftNSArrayCodeRunningFormatter.py index 1c98a0c0e26e0..3a2b20512cd22 100644 --- a/lldb/test/API/lang/swift/nsarray_code_running_formatter/TestSwiftNSArrayCodeRunningFormatter.py +++ b/lldb/test/API/lang/swift/nsarray_code_running_formatter/TestSwiftNSArrayCodeRunningFormatter.py @@ -13,4 +13,7 @@ from lldbsuite.test.decorators import * lldbinline.MakeInlineTest(__file__, globals(), - decorators=[swiftTest,skipUnlessDarwin]) + decorators=[swiftTest,skipUnlessDarwin, +expectedFailureAll(bugnumber="rdar://60396797", + setting=('symbols.use-swift-clangimporter', 'false')) +]) diff --git a/lldb/test/API/lang/swift/objc_inherited_ivars/TestSwiftAtObjCIvars.py b/lldb/test/API/lang/swift/objc_inherited_ivars/TestSwiftAtObjCIvars.py index 9d2bac2d36d02..d3b8b1bc13a79 100644 --- a/lldb/test/API/lang/swift/objc_inherited_ivars/TestSwiftAtObjCIvars.py +++ b/lldb/test/API/lang/swift/objc_inherited_ivars/TestSwiftAtObjCIvars.py @@ -33,6 +33,8 @@ def check_foo(self, theFoo): lldbutil.check_variable(self, x, False, value='12') lldbutil.check_variable(self, y, False, '"12"') + @expectedFailureAll(bugnumber="rdar://60396797", + setting=('symbols.use-swift-clangimporter', 'false')) @skipUnlessDarwin @swiftTest def test_swift_at_objc_ivars(self): diff --git a/lldb/test/API/lang/swift/objc_runtime_ivars/TestObjCIvarDiscovery.py b/lldb/test/API/lang/swift/objc_runtime_ivars/TestObjCIvarDiscovery.py index b9d7ea746ad57..12a868e830ef4 100644 --- a/lldb/test/API/lang/swift/objc_runtime_ivars/TestObjCIvarDiscovery.py +++ b/lldb/test/API/lang/swift/objc_runtime_ivars/TestObjCIvarDiscovery.py @@ -26,6 +26,8 @@ class TestObjCIVarDiscovery(TestBase): mydir = TestBase.compute_mydir(__file__) + @expectedFailureAll(bugnumber="rdar://60396797", + setting=('symbols.use-swift-clangimporter', 'false')) @skipUnlessDarwin @skipIf(debug_info=no_match("dsym")) def test_nodbg(self): @@ -33,6 +35,8 @@ def test_nodbg(self): shutil.rmtree(self.getBuildArtifact("aTestFramework.framework/Versions/A/aTestFramework.dSYM")) self.do_test(False) + @expectedFailureAll(bugnumber="rdar://60396797", + setting=('symbols.use-swift-clangimporter', 'false')) @skipUnlessDarwin @skipIf(debug_info=no_match("dsym")) def test_dbg(self): diff --git a/lldb/test/API/lang/swift/optionset/TestSwiftOptionSetType.py b/lldb/test/API/lang/swift/optionset/TestSwiftOptionSetType.py index dcdf2eebfc01d..e12d83951c722 100644 --- a/lldb/test/API/lang/swift/optionset/TestSwiftOptionSetType.py +++ b/lldb/test/API/lang/swift/optionset/TestSwiftOptionSetType.py @@ -13,4 +13,7 @@ from lldbsuite.test.decorators import * lldbinline.MakeInlineTest(__file__, globals(), - decorators=[swiftTest,skipUnlessDarwin]) + decorators=[swiftTest,skipUnlessDarwin, + expectedFailureAll(bugnumber="rdar://60396797", + setting=('symbols.use-swift-clangimporter', 'false')) +]) diff --git a/lldb/test/API/lang/swift/protocol_extension_computed_property/TestProtocolExtensionComputerProperty.py b/lldb/test/API/lang/swift/protocol_extension_computed_property/TestProtocolExtensionComputerProperty.py index dad5915422c91..37ed3f1358668 100644 --- a/lldb/test/API/lang/swift/protocol_extension_computed_property/TestProtocolExtensionComputerProperty.py +++ b/lldb/test/API/lang/swift/protocol_extension_computed_property/TestProtocolExtensionComputerProperty.py @@ -2,4 +2,9 @@ from lldbsuite.test.decorators import * lldbinline.MakeInlineTest( - __file__, globals(), decorators=[skipUnlessDarwin]) + __file__, globals(), + decorators=[ + swiftTest,skipUnlessDarwin, + skipIf(bugnumber="rdar://60396797", # should work but crashes. + setting=('symbols.use-swift-clangimporter', 'false')) + ]) diff --git a/lldb/test/API/lang/swift/protocols/class_protocol/TestClassConstrainedProtocolArgument.py b/lldb/test/API/lang/swift/protocols/class_protocol/TestClassConstrainedProtocolArgument.py index 6e52c7fabea8b..ba4271dfb6ba5 100644 --- a/lldb/test/API/lang/swift/protocols/class_protocol/TestClassConstrainedProtocolArgument.py +++ b/lldb/test/API/lang/swift/protocols/class_protocol/TestClassConstrainedProtocolArgument.py @@ -6,4 +6,9 @@ from lldbsuite.test.decorators import * lldbinline.MakeInlineTest( - __file__, globals(), decorators=[skipUnlessDarwin]) + __file__, globals(), + decorators=[ + swiftTest,skipUnlessDarwin, + skipIf(bugnumber="rdar://60396797", # should work but crashes. + setting=('symbols.use-swift-clangimporter', 'false')) + ]) diff --git a/lldb/test/API/lang/swift/runtime_failure_recognizer/TestSwiftRuntimeFailureRecognizer.py b/lldb/test/API/lang/swift/runtime_failure_recognizer/TestSwiftRuntimeFailureRecognizer.py index fd09d4d2e5f42..4bede566cbb9f 100644 --- a/lldb/test/API/lang/swift/runtime_failure_recognizer/TestSwiftRuntimeFailureRecognizer.py +++ b/lldb/test/API/lang/swift/runtime_failure_recognizer/TestSwiftRuntimeFailureRecognizer.py @@ -30,7 +30,7 @@ def test_swift_runtime_recognizer(self): self.runCmd("file " + self.getBuildArtifact("a.out")) self.expect("frame recognizer list", - substrs=['Swift Runtime Failure StackFrame Recognizer, function Swift runtime failure (regexp)']) + substrs=['Swift Runtime Failure StackFrame Recognizer, symbol Swift runtime failure (regexp)']) self.runCmd("process launch") diff --git a/lldb/test/API/lang/swift/stdlib/ContiguousArray/Makefile b/lldb/test/API/lang/swift/stdlib/ContiguousArray/Makefile new file mode 100644 index 0000000000000..2a69023633b34 --- /dev/null +++ b/lldb/test/API/lang/swift/stdlib/ContiguousArray/Makefile @@ -0,0 +1,3 @@ +SWIFT_SOURCES := main.swift + +include Makefile.rules diff --git a/lldb/test/API/lang/swift/stdlib/ContiguousArray/TestContiguousArray.py b/lldb/test/API/lang/swift/stdlib/ContiguousArray/TestContiguousArray.py new file mode 100644 index 0000000000000..a435dfbad1bff --- /dev/null +++ b/lldb/test/API/lang/swift/stdlib/ContiguousArray/TestContiguousArray.py @@ -0,0 +1,28 @@ +""" +Test that contiguous array prints correctly +""" +import lldb +from lldbsuite.test.decorators import * +import lldbsuite.test.lldbtest as lldbtest +import lldbsuite.test.lldbutil as lldbutil +import os +import unittest2 + + +class TestContiguousArray(lldbtest.TestBase): + + mydir = lldbtest.TestBase.compute_mydir(__file__) + + @swiftTest + def test_frame_contiguous_array(self): + """Test that contiguous array prints correctly""" + self.build() + lldbutil.run_to_source_breakpoint( + self, 'Set breakpoint here', lldb.SBFileSpec('main.swift')) + + self.expect("frame variable --dynamic-type run-target", + startstr="""(ContiguousArray) array = { + _buffer = { + _storage = 1 value { + [0] = 0x""") + diff --git a/lldb/test/API/lang/swift/stdlib/ContiguousArray/main b/lldb/test/API/lang/swift/stdlib/ContiguousArray/main new file mode 100755 index 0000000000000..078d60a125bde Binary files /dev/null and b/lldb/test/API/lang/swift/stdlib/ContiguousArray/main differ diff --git a/lldb/test/API/lang/swift/stdlib/ContiguousArray/main.swift b/lldb/test/API/lang/swift/stdlib/ContiguousArray/main.swift new file mode 100644 index 0000000000000..316cfa8a36d71 --- /dev/null +++ b/lldb/test/API/lang/swift/stdlib/ContiguousArray/main.swift @@ -0,0 +1,11 @@ +class Class {} + +func use(_ t: T) {} + +func main() { + let array = ContiguousArray([Class()]) + use(array)// Set breakpoint here +} + +main() + diff --git a/lldb/test/API/lang/swift/stepping/TestSwiftStepping.py b/lldb/test/API/lang/swift/stepping/TestSwiftStepping.py index 7b7eb58cf3874..766f01aaf4c4b 100644 --- a/lldb/test/API/lang/swift/stepping/TestSwiftStepping.py +++ b/lldb/test/API/lang/swift/stepping/TestSwiftStepping.py @@ -25,7 +25,6 @@ class TestSwiftStepping(lldbtest.TestBase): mydir = lldbtest.TestBase.compute_mydir(__file__) @swiftTest - @skipIfLinux def test_swift_stepping(self): """Tests that we can step reliably in swift code.""" self.build() diff --git a/lldb/test/API/lang/swift/swiftieformatting/TestSwiftieFormatting.py b/lldb/test/API/lang/swift/swiftieformatting/TestSwiftieFormatting.py index ae2518494dded..2a15f434f3dae 100644 --- a/lldb/test/API/lang/swift/swiftieformatting/TestSwiftieFormatting.py +++ b/lldb/test/API/lang/swift/swiftieformatting/TestSwiftieFormatting.py @@ -27,6 +27,8 @@ class TestSwiftieFormatting(TestBase): def setUp(self): TestBase.setUp(self) + @expectedFailureAll(bugnumber="rdar://60396797", + setting=('symbols.use-swift-clangimporter', 'false')) @skipUnlessDarwin @swiftTest def test_swiftie_formatting(self): diff --git a/lldb/test/API/lang/swift/tagged_pointer/TestSwiftTaggedPointer.py b/lldb/test/API/lang/swift/tagged_pointer/TestSwiftTaggedPointer.py index 5d776c004560e..3ab081c71d808 100644 --- a/lldb/test/API/lang/swift/tagged_pointer/TestSwiftTaggedPointer.py +++ b/lldb/test/API/lang/swift/tagged_pointer/TestSwiftTaggedPointer.py @@ -15,4 +15,7 @@ # This test depends on NSObject, so it is not available on non-Darwin # platforms. lldbinline.MakeInlineTest(__file__, globals(), - decorators=[swiftTest,skipUnlessDarwin]) + decorators=[swiftTest,skipUnlessDarwin, + expectedFailureAll(bugnumber="rdar://60396797", + setting=('symbols.use-swift-clangimporter', 'false')) +]) diff --git a/lldb/test/API/lang/swift/clangimporter/union/Makefile b/lldb/test/API/lang/swift/union/Makefile similarity index 100% rename from lldb/test/API/lang/swift/clangimporter/union/Makefile rename to lldb/test/API/lang/swift/union/Makefile diff --git a/lldb/test/API/lang/swift/clangimporter/union/TestSwiftCUnion.py b/lldb/test/API/lang/swift/union/TestSwiftCUnion.py similarity index 81% rename from lldb/test/API/lang/swift/clangimporter/union/TestSwiftCUnion.py rename to lldb/test/API/lang/swift/union/TestSwiftCUnion.py index cfc67659a64d2..f684c9299329f 100644 --- a/lldb/test/API/lang/swift/clangimporter/union/TestSwiftCUnion.py +++ b/lldb/test/API/lang/swift/union/TestSwiftCUnion.py @@ -10,6 +10,8 @@ class TestSwiftAnyType(lldbtest.TestBase): mydir = lldbtest.TestBase.compute_mydir(__file__) + @expectedFailureAll(bugnumber="rdar://60396797", + setting=('symbols.use-swift-clangimporter', 'false')) @swiftTest def test_c_unions(self): self.build() diff --git a/lldb/test/API/lang/swift/clangimporter/union/main.swift b/lldb/test/API/lang/swift/union/main.swift similarity index 100% rename from lldb/test/API/lang/swift/clangimporter/union/main.swift rename to lldb/test/API/lang/swift/union/main.swift diff --git a/lldb/test/API/lang/swift/clangimporter/union/module.modulemap b/lldb/test/API/lang/swift/union/module.modulemap similarity index 100% rename from lldb/test/API/lang/swift/clangimporter/union/module.modulemap rename to lldb/test/API/lang/swift/union/module.modulemap diff --git a/lldb/test/API/lang/swift/clangimporter/union/union.h b/lldb/test/API/lang/swift/union/union.h similarity index 100% rename from lldb/test/API/lang/swift/clangimporter/union/union.h rename to lldb/test/API/lang/swift/union/union.h diff --git a/lldb/test/API/lang/swift/unknown_reference/TestSwiftUnknownReference.py b/lldb/test/API/lang/swift/unknown_reference/TestSwiftUnknownReference.py index 41ef074771239..b53709d817a75 100644 --- a/lldb/test/API/lang/swift/unknown_reference/TestSwiftUnknownReference.py +++ b/lldb/test/API/lang/swift/unknown_reference/TestSwiftUnknownReference.py @@ -29,6 +29,9 @@ def check_class(self, var_self): lldbutil.check_variable(self, m_string, summary='"world"') + @expectedFailureAll(bugnumber="rdar://60396797", + oslist=lldbplatform.darwin_all, + setting=('symbols.use-swift-clangimporter', 'false')) @swiftTest def test_unknown_objc_ref(self): """Test unknown references to Objective-C objects.""" diff --git a/lldb/test/API/lang/swift/unknown_self/TestSwiftUnknownSelf.py b/lldb/test/API/lang/swift/unknown_self/TestSwiftUnknownSelf.py index fc350caf3b02f..6e484a7bac7ef 100644 --- a/lldb/test/API/lang/swift/unknown_self/TestSwiftUnknownSelf.py +++ b/lldb/test/API/lang/swift/unknown_self/TestSwiftUnknownSelf.py @@ -33,8 +33,10 @@ def check_class(self, var_self, broken): self.expect("fr v self", substrs=["hello", "world"]) - @skipIf(archs=['ppc64le']) - # SR-10216 + @expectedFailureAll(bugnumber="rdar://60396797", + oslist=lldbplatform.darwin_all, + setting=('symbols.use-swift-clangimporter', 'false')) + @skipIf(bugnumber="SR-10216", archs=['ppc64le']) @swiftTest def test_unknown_self_objc_ref(self): """Test unknown references to Objective-C objects.""" diff --git a/lldb/test/API/lang/swift/variables/dict_nsobj_anyobj/TestSwiftDictionaryNSObjectAnyObject.py b/lldb/test/API/lang/swift/variables/dict_nsobj_anyobj/TestSwiftDictionaryNSObjectAnyObject.py index bb6c7e3b289ba..17996bdee5c7e 100644 --- a/lldb/test/API/lang/swift/variables/dict_nsobj_anyobj/TestSwiftDictionaryNSObjectAnyObject.py +++ b/lldb/test/API/lang/swift/variables/dict_nsobj_anyobj/TestSwiftDictionaryNSObjectAnyObject.py @@ -27,6 +27,8 @@ class TestDictionaryNSObjectAnyObject(TestBase): def setUp(self): TestBase.setUp(self) + @expectedFailureAll(bugnumber="rdar://60396797", + setting=('symbols.use-swift-clangimporter', 'false')) @skipUnlessDarwin @swiftTest def test_dictionary_nsobject_any_object(self): diff --git a/lldb/test/API/lang/swift/variables/objc/TestObjCImportedTypes.py b/lldb/test/API/lang/swift/variables/objc/TestObjCImportedTypes.py index 0718684def5f7..1fbf3271a7996 100644 --- a/lldb/test/API/lang/swift/variables/objc/TestObjCImportedTypes.py +++ b/lldb/test/API/lang/swift/variables/objc/TestObjCImportedTypes.py @@ -27,6 +27,8 @@ class TestSwiftObjCImportedTypes(TestBase): def setUp(self): TestBase.setUp(self) + @expectedFailureAll(bugnumber="rdar://60396797", + setting=('symbols.use-swift-clangimporter', 'false')) @swiftTest @skipUnlessDarwin def test_swift_objc_imported_types(self): diff --git a/lldb/test/API/lang/swift/variables/objc_optionals/TestSwiftObjCOptionals.py b/lldb/test/API/lang/swift/variables/objc_optionals/TestSwiftObjCOptionals.py index eb7ba3549c59a..53e6e3f275f40 100644 --- a/lldb/test/API/lang/swift/variables/objc_optionals/TestSwiftObjCOptionals.py +++ b/lldb/test/API/lang/swift/variables/objc_optionals/TestSwiftObjCOptionals.py @@ -24,6 +24,8 @@ class TestSwiftObjCOptionalType(TestBase): mydir = TestBase.compute_mydir(__file__) + @expectedFailureAll(bugnumber="rdar://60396797", + setting=('symbols.use-swift-clangimporter', 'false')) @swiftTest @skipUnlessDarwin def test_swift_objc_optional_type(self): diff --git a/lldb/test/API/linux/builtin_trap/TestBuiltinTrap.py b/lldb/test/API/linux/builtin_trap/TestBuiltinTrap.py index 22de873e29fad..added4ef508a7 100644 --- a/lldb/test/API/linux/builtin_trap/TestBuiltinTrap.py +++ b/lldb/test/API/linux/builtin_trap/TestBuiltinTrap.py @@ -23,7 +23,7 @@ def setUp(self): # gcc generates incorrect linetable @expectedFailureAll(archs="arm", compiler="gcc", triple=".*-android") - @expectedFailureAll(oslist=['linux'], archs=['arm', 'aarch64']) + @expectedFailureAll(archs=['arm', 'aarch64']) @skipIfWindows def test_with_run_command(self): """Test that LLDB handles a function with __builtin_trap correctly.""" diff --git a/lldb/test/API/lldbtest.py b/lldb/test/API/lldbtest.py index 65aafab5c617d..94c0588fd9e63 100644 --- a/lldb/test/API/lldbtest.py +++ b/lldb/test/API/lldbtest.py @@ -114,14 +114,12 @@ def execute(self, test, litConfig): return lit.Test.TIMEOUT, output if exitCode: - # Match FAIL but not XFAIL. - for line in out.splitlines() + err.splitlines(): - if line.startswith('FAIL:'): - return lit.Test.FAIL, output - if 'XPASS:' in out or 'XPASS:' in err: return lit.Test.XPASS, output + # Otherwise this is just a failure. + return lit.Test.FAIL, output + has_unsupported_tests = 'UNSUPPORTED:' in out or 'UNSUPPORTED:' in err has_passing_tests = 'PASS:' in out or 'PASS:' in err if has_unsupported_tests and not has_passing_tests: diff --git a/lldb/test/API/sanity/TestSettingSkipping.py b/lldb/test/API/sanity/TestSettingSkipping.py new file mode 100644 index 0000000000000..206c7b4ecd730 --- /dev/null +++ b/lldb/test/API/sanity/TestSettingSkipping.py @@ -0,0 +1,37 @@ +""" +This is a sanity check that verifies that test can be sklipped based on settings. +""" + + +import lldb +from lldbsuite.test.lldbtest import * +from lldbsuite.test.decorators import * + + +class SettingSkipSanityTestCase(TestBase): + + mydir = TestBase.compute_mydir(__file__) + + NO_DEBUG_INFO_TESTCASE = True + + @skipIf(setting=('target.prefer-dynamic-value', 'no-dynamic-values')) + def testSkip(self): + """This setting is on by default""" + self.assertTrue(False, "This test should not run!") + + @skipIf(setting=('target.prefer-dynamic-value', 'run-target')) + def testNoMatch(self): + self.assertTrue(True, "This test should run!") + + @skipIf(setting=('target.i-made-this-one-up', 'true')) + def testNotExisting(self): + self.assertTrue(True, "This test should run!") + + @expectedFailureAll(setting=('target.prefer-dynamic-value', 'no-dynamic-values')) + def testXFAIL(self): + self.assertTrue(False, "This test should run and fail!") + + @expectedFailureAll(setting=('target.prefer-dynamic-value', 'run-target')) + def testNotXFAIL(self): + self.assertTrue(True, "This test should run and succeed!") + diff --git a/lldb/test/API/tools/lldb-server/TestAppleSimulatorOSType.py b/lldb/test/API/tools/lldb-server/TestAppleSimulatorOSType.py index a1aa9d0b1c117..156bafb32212b 100644 --- a/lldb/test/API/tools/lldb-server/TestAppleSimulatorOSType.py +++ b/lldb/test/API/tools/lldb-server/TestAppleSimulatorOSType.py @@ -83,7 +83,7 @@ def check_simulator_ostype(self, sdk, platform, arch='x86_64'): self.assertIsNotNone(process_info) # Check that ostype is correct - self.assertEquals(process_info['ostype'], platform) + self.assertEquals(process_info['ostype'], platform + 'simulator') # Now for dylibs dylib_info_raw = context.get("dylib_info_raw") @@ -98,7 +98,7 @@ def check_simulator_ostype(self, sdk, platform, arch='x86_64'): break self.assertIsNotNone(image_info) - self.assertEquals(image['min_version_os_name'], platform) + self.assertEquals(image['min_version_os_name'], platform + 'simulator') @apple_simulator_test('iphone') diff --git a/lldb/test/CMakeLists.txt b/lldb/test/CMakeLists.txt index 130c9a871e9c7..74369fd4aff14 100644 --- a/lldb/test/CMakeLists.txt +++ b/lldb/test/CMakeLists.txt @@ -1,6 +1,16 @@ # Test runner infrastructure for LLDB. This configures the LLDB test trees # for use by Lit, and delegates to LLVM's lit test handlers. +if(LLDB_BUILT_STANDALONE) + # In order to run check-lldb-* we need the correct map_config directives in + # llvm-lit. Because this is a standalone build, LLVM doesn't know about LLDB, + # and the lldb mappings are missing. We build our own llvm-lit, and tell LLVM + # to use the llvm-lit in the lldb build directory. + if (EXISTS ${LLVM_MAIN_SRC_DIR}/utils/llvm-lit) + set(LLVM_EXTERNAL_LIT ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/llvm-lit) + endif() +endif() + # Configure the build directory. set(LLDB_TEST_BUILD_DIRECTORY "${PROJECT_BINARY_DIR}/lldb-test-build.noindex" CACHE PATH "The build root for building tests.") @@ -195,3 +205,10 @@ add_lit_testsuite(check-lldb-swift ARGS "--filter=[sS]wift" DEPENDS lldb-test-deps) # END SWIFT MOD + +if(LLDB_BUILT_STANDALONE) + # This has to happen *AFTER* add_lit_testsuite. + if (EXISTS ${LLVM_MAIN_SRC_DIR}/utils/llvm-lit) + add_subdirectory(${LLVM_MAIN_SRC_DIR}/utils/llvm-lit ${CMAKE_CURRENT_BINARY_DIR}/llvm-lit) + endif() +endif() diff --git a/lldb/test/Shell/ExecControl/StopHook/stop-hook.test b/lldb/test/Shell/ExecControl/StopHook/stop-hook.test index a06de6634ea19..98a77cac99bac 100644 --- a/lldb/test/Shell/ExecControl/StopHook/stop-hook.test +++ b/lldb/test/Shell/ExecControl/StopHook/stop-hook.test @@ -46,12 +46,12 @@ target stop-hook list run # Stopping inside of the stop hook range # CHECK: (lldb) run -# CHECK-NEXT: (void *) $0 = 0x +# CHECK-NEXT: (void *) ${{.*}} = 0x thread step-over # Stepping inside of the stop hook range # CHECK: (lldb) thread step-over -# CHECK-NEXT: (void *) $1 = 0x +# CHECK-NEXT: (void *) ${{.*}} = 0x # CHECK: ->{{.*}} // We should stop here after stepping. process continue diff --git a/lldb/test/Shell/Process/Windows/launch_failure.yaml b/lldb/test/Shell/Process/Windows/launch_failure.yaml index be723ef7621d0..88cb0edd9f90e 100644 --- a/lldb/test/Shell/Process/Windows/launch_failure.yaml +++ b/lldb/test/Shell/Process/Windows/launch_failure.yaml @@ -7,7 +7,7 @@ # RUN: yaml2obj %s > %t.exe # RUN: %lldb %t.exe -o run 2>&1 | FileCheck %s -# CHECK: error: process launch failed: unknown error +# CHECK: error: unknown error --- !COFF OptionalHeader: diff --git a/lldb/test/Shell/Process/Windows/process_load.cpp b/lldb/test/Shell/Process/Windows/process_load.cpp new file mode 100644 index 0000000000000..43bf45865f9ba --- /dev/null +++ b/lldb/test/Shell/Process/Windows/process_load.cpp @@ -0,0 +1,12 @@ +// clang-format off + +// REQUIRES: system-windows +// RUN: %build --compiler=clang-cl -o %t.exe -- %s +// RUN: env LLDB_USE_NATIVE_PDB_READER=1 %lldb -f %t.exe -o "b main" -o "process launch" -o "process load kernel32.dll" | FileCheck %s + +int main(int argc, char *argv[]) { + return 0; +} + +// CHECK: "Loading "kernel32.dll"...ok{{.*}} +// CHECK: Image 0 loaded. diff --git a/lldb/test/Shell/Reproducer/Inputs/foo.lua b/lldb/test/Shell/Reproducer/Inputs/foo.lua new file mode 100644 index 0000000000000..8ed0c94cbba96 --- /dev/null +++ b/lldb/test/Shell/Reproducer/Inputs/foo.lua @@ -0,0 +1 @@ +print('95126') diff --git a/lldb/test/Shell/Reproducer/Inputs/foo.py b/lldb/test/Shell/Reproducer/Inputs/foo.py new file mode 100644 index 0000000000000..8ed0c94cbba96 --- /dev/null +++ b/lldb/test/Shell/Reproducer/Inputs/foo.py @@ -0,0 +1 @@ +print('95126') diff --git a/lldb/test/Shell/Reproducer/TestPythonImport.test b/lldb/test/Shell/Reproducer/TestPythonImport.test new file mode 100644 index 0000000000000..7bea97c91d986 --- /dev/null +++ b/lldb/test/Shell/Reproducer/TestPythonImport.test @@ -0,0 +1,11 @@ +# REQUIRES: python +# UNSUPPORTED: system-windows +# Ensure that the reproducers know about imported Python modules. + +# RUN: rm -rf %t.repro +# RUN: %lldb -x -b --capture --capture-path %t.repro -o 'command script import %S/Inputs/foo.py' -o 'reproducer generate' | FileCheck %s --check-prefix CAPTURE + +# CAPTURE: 95126 + +# RUN: %lldb -b -o 'reproducer dump -p files -f %t.repro' | FileCheck %s --check-prefix FILES +# FILES: foo.py diff --git a/lldb/test/Shell/Swift/Inputs/No.swiftmodule.swift b/lldb/test/Shell/Swift/Inputs/No.swiftmodule.swift index 91ba2de773687..5179473605b69 100644 --- a/lldb/test/Shell/Swift/Inputs/No.swiftmodule.swift +++ b/lldb/test/Shell/Swift/Inputs/No.swiftmodule.swift @@ -1,16 +1,24 @@ +import NoSwiftmoduleHelper + // The struct could not possibly be resolved with just the mangled type name. struct s { let i = 0 } +func useTypeFromOtherModule(x: S2) { + // break here +} + func f(_ t: T) { let number = 1 // CHECK-DAG: (Int) number = 1 let array = [1, 2, 3] // CHECK-DAG: ([Int]) array = 3 values let string = "hello" // CHECK-DAG: (String) string = "hello" let tuple = (0, 1) // CHECK-DAG: (Int, Int) tuple = (0 = 0, 1 = 1) let strct = s() // CHECK-DAG: strct ={{$}} + let strct2 = S2() // CHECK-DAG: strct2 = let generic = t // CHECK-DAG: (Int) generic = 23 let generic_tuple = (t, t) // CHECK-DAG: generic_tuple = // FIXME: CHECK-DAG: = [ // DICT-NEXT: } // DICT-NEXT: } +// Test formatters in Objective-C context. + +// Empty singleton +let d_objc1 = NSArray(object: [:] as [NSNumber: NSNumber] as NSDictionary) +// DICT-LABEL: d_objc1: NSArray = 1 element { +// DICT-NEXT: [0] = 0 key/value pairs +// DICT-NEXT: } + +// Verbatim bridging +let d_objc2 = NSArray(object: [1: 2] as [NSNumber: NSNumber] as NSDictionary) +// DICT-LABEL: d_objc2: NSArray = 1 element { +// DICT-NEXT: [0] = 1 key/value pair { +// DICT-NEXT: [0] = { +// DICT-NEXT: key = Int64(1) +// DICT-NEXT: value = Int64(2) +// DICT-NEXT: } +// DICT-NEXT: } +// DICT-NEXT: } + +// Non-verbatim bridging +let d_objc3 = NSArray(object: [1: 2] as [Int: Int] as NSDictionary) +// DICT-LABEL: d_objc3: NSArray = 1 element { +// DICT-NEXT: [0] = 1 key/value pair { +// DICT-NEXT: [0] = (key = 1, value = 2) +// DICT-NEXT: } +// DICT-NEXT: } + // Verbatim bridging from Swift to Objective-C let d2b = d2 as NSDictionary // DICT-LABEL: d2b: {{(_HashableTypedNativeDictionaryStorage|_DictionaryStorage)}} = 1 key/value pair { @@ -80,30 +107,3 @@ let d3b2 = d3 as! [Int: Int] // DICT-NEXT: value = 2 // DICT-NEXT: } // DICT-NEXT: } - -// Test formatters in Objective-C context. - -// Empty singleton -let d4 = NSArray(object: [:] as [NSNumber: NSNumber] as NSDictionary) -// DICT-LABEL: d4: NSArray = 1 element { -// DICT-NEXT: [0] = 0 key/value pairs -// DICT-NEXT: } - -// Verbatim bridging -let d5 = NSArray(object: [1: 2] as [NSNumber: NSNumber] as NSDictionary) -// DICT-LABEL: d5: NSArray = 1 element { -// DICT-NEXT: [0] = 1 key/value pair { -// DICT-NEXT: [0] = { -// DICT-NEXT: key = Int64(1) -// DICT-NEXT: value = Int64(2) -// DICT-NEXT: } -// DICT-NEXT: } -// DICT-NEXT: } - -// Non-verbatim bridging -let d6 = NSArray(object: [1: 2] as [Int: Int] as NSDictionary) -// DICT-LABEL: d6: NSArray = 1 element { -// DICT-NEXT: [0] = 1 key/value pair { -// DICT-NEXT: [0] = (key = 1, value = 2) -// DICT-NEXT: } -// DICT-NEXT: } diff --git a/lldb/test/Shell/SwiftREPL/ImportError.test b/lldb/test/Shell/SwiftREPL/ImportError.test new file mode 100644 index 0000000000000..44fe179103c57 --- /dev/null +++ b/lldb/test/Shell/SwiftREPL/ImportError.test @@ -0,0 +1,6 @@ +// Test that importing non-existing module fails. + +// RUN: %lldb --repl < %s 2>&1 | FileCheck %s + +import ModuleThatDoesNotExist +// CHECK: error: no such module 'ModuleThatDoesNotExist' diff --git a/lldb/test/Shell/SwiftREPL/SetBridging.test b/lldb/test/Shell/SwiftREPL/SetBridging.test index b11985b059c53..4c7aca292f144 100644 --- a/lldb/test/Shell/SwiftREPL/SetBridging.test +++ b/lldb/test/Shell/SwiftREPL/SetBridging.test @@ -31,6 +31,30 @@ let s2: Set = [NSNumber(value: 1)] // SET-NEXT: [0] = Int64(1) // SET-NEXT: } +// Test formatters in Objective-C context. + +// Empty singleton +let s_objc1 = NSArray(object: [] as Set as NSSet) +// SET-LABEL: s_objc1: NSArray = 1 element { +// SET-NEXT: [0] = 0 values +// SET-NEXT: } + +// Verbatim bridging +let s_objc2 = NSArray(object: [1] as Set as NSSet) +// SET-LABEL: s_objc2: NSArray = 1 element { +// SET-NEXT: [0] = 1 value { +// SET-NEXT: [0] = Int64(1) +// SET-NEXT: } +// SET-NEXT: } + +// Non-verbatim bridging +let s_objc3 = NSArray(object: [1] as Set as NSSet) +// SET-LABEL: s_objc3: NSArray = 1 element { +// SET-NEXT: [0] = 1 value { +// SET-NEXT: [0] = 1 +// SET-NEXT: } +// SET-NEXT: } + // Verbatim bridging from Swift to Objective-C let s2b = s2 as NSSet // SET-LABEL: s2b: {{(_HashableTypedNativeSetStorage|_SetStorage)}} = 1 value { @@ -58,27 +82,3 @@ let s3b2 = s3 as! Set // SET-NEXT: [0] = {{[12]}} // SET-NEXT: [1] = {{[12]}} // SET-NEXT: } - -// Test formatters in Objective-C context. - -// Empty singleton -let s4 = NSArray(object: [] as Set as NSSet) -// SET-LABEL: s4: NSArray = 1 element { -// SET-NEXT: [0] = 0 values -// SET-NEXT: } - -// Verbatim bridging -let s5 = NSArray(object: [1] as Set as NSSet) -// SET-LABEL: s5: NSArray = 1 element { -// SET-NEXT: [0] = 1 value { -// SET-NEXT: [0] = Int64(1) -// SET-NEXT: } -// SET-NEXT: } - -// Non-verbatim bridging -let s6 = NSArray(object: [1] as Set as NSSet) -// SET-LABEL: s6: NSArray = 1 element { -// SET-NEXT: [0] = 1 value { -// SET-NEXT: [0] = 1 -// SET-NEXT: } -// SET-NEXT: } diff --git a/lldb/test/Shell/SymbolFile/DWARF/static_scope.s b/lldb/test/Shell/SymbolFile/DWARF/static_scope.s new file mode 100644 index 0000000000000..17b2485798494 --- /dev/null +++ b/lldb/test/Shell/SymbolFile/DWARF/static_scope.s @@ -0,0 +1,312 @@ +# Test that the DWARF parser assigns the right scope to the +# variable `b`, which is `local` and not `static`. + +# REQUIRES: x86 +# UNSUPPORTED: lldb-repro + +# RUN: llvm-mc -triple=x86_64-apple-macosx10.15.0 -filetype=obj %s > %t.o +# RUN: lldb-test symbols %t.o | FileCheck %s + +# CHECK: Variable{{.*}}, name = "b", type = {{.*}} (int), scope = local + + .section __TEXT,__text,regular,pure_instructions + .macosx_version_min 10, 15 + .file 1 "/Users/davide/work/build/bin" "a.c" + .globl _main ## -- Begin function main + .p2align 4, 0x90 +_main: ## @main +Lfunc_begin0: + .loc 1 2 0 ## a.c:2:0 + .cfi_startproc +## %bb.0: + pushq %rbp + .cfi_def_cfa_offset 16 + .cfi_offset %rbp, -16 + movq %rsp, %rbp + .cfi_def_cfa_register %rbp +Ltmp0: + ##DEBUG_VALUE: b <- 3 + .loc 1 5 9 prologue_end ## a.c:5:9 + movl _a(%rip), %eax +Ltmp1: + .loc 1 7 5 ## a.c:7:5 + xorl %eax, %eax + popq %rbp + retq +Ltmp2: +Lfunc_end0: + .cfi_endproc + ## -- End function + .globl _a ## @a +.zerofill __DATA,__common,_a,4,2 + .section __DWARF,__debug_abbrev,regular,debug +Lsection_abbrev: + .byte 1 ## Abbreviation Code + .byte 17 ## DW_TAG_compile_unit + .byte 1 ## DW_CHILDREN_yes + .byte 37 ## DW_AT_producer + .byte 14 ## DW_FORM_strp + .byte 19 ## DW_AT_language + .byte 5 ## DW_FORM_data2 + .byte 3 ## DW_AT_name + .byte 14 ## DW_FORM_strp + .ascii "\202|" ## DW_AT_LLVM_sysroot + .byte 14 ## DW_FORM_strp + .byte 16 ## DW_AT_stmt_list + .byte 23 ## DW_FORM_sec_offset + .byte 27 ## DW_AT_comp_dir + .byte 14 ## DW_FORM_strp + .ascii "\341\177" ## DW_AT_APPLE_optimized + .byte 25 ## DW_FORM_flag_present + .byte 17 ## DW_AT_low_pc + .byte 1 ## DW_FORM_addr + .byte 18 ## DW_AT_high_pc + .byte 6 ## DW_FORM_data4 + .byte 0 ## EOM(1) + .byte 0 ## EOM(2) + .byte 2 ## Abbreviation Code + .byte 52 ## DW_TAG_variable + .byte 0 ## DW_CHILDREN_no + .byte 3 ## DW_AT_name + .byte 14 ## DW_FORM_strp + .byte 73 ## DW_AT_type + .byte 19 ## DW_FORM_ref4 + .byte 63 ## DW_AT_external + .byte 25 ## DW_FORM_flag_present + .byte 58 ## DW_AT_decl_file + .byte 11 ## DW_FORM_data1 + .byte 59 ## DW_AT_decl_line + .byte 11 ## DW_FORM_data1 + .byte 2 ## DW_AT_location + .byte 24 ## DW_FORM_exprloc + .byte 0 ## EOM(1) + .byte 0 ## EOM(2) + .byte 3 ## Abbreviation Code + .byte 53 ## DW_TAG_volatile_type + .byte 0 ## DW_CHILDREN_no + .byte 73 ## DW_AT_type + .byte 19 ## DW_FORM_ref4 + .byte 0 ## EOM(1) + .byte 0 ## EOM(2) + .byte 4 ## Abbreviation Code + .byte 36 ## DW_TAG_base_type + .byte 0 ## DW_CHILDREN_no + .byte 3 ## DW_AT_name + .byte 14 ## DW_FORM_strp + .byte 62 ## DW_AT_encoding + .byte 11 ## DW_FORM_data1 + .byte 11 ## DW_AT_byte_size + .byte 11 ## DW_FORM_data1 + .byte 0 ## EOM(1) + .byte 0 ## EOM(2) + .byte 5 ## Abbreviation Code + .byte 46 ## DW_TAG_subprogram + .byte 1 ## DW_CHILDREN_yes + .byte 17 ## DW_AT_low_pc + .byte 1 ## DW_FORM_addr + .byte 18 ## DW_AT_high_pc + .byte 6 ## DW_FORM_data4 + .byte 64 ## DW_AT_frame_base + .byte 24 ## DW_FORM_exprloc + .byte 122 ## DW_AT_call_all_calls + .byte 25 ## DW_FORM_flag_present + .byte 3 ## DW_AT_name + .byte 14 ## DW_FORM_strp + .byte 58 ## DW_AT_decl_file + .byte 11 ## DW_FORM_data1 + .byte 59 ## DW_AT_decl_line + .byte 11 ## DW_FORM_data1 + .byte 73 ## DW_AT_type + .byte 19 ## DW_FORM_ref4 + .byte 63 ## DW_AT_external + .byte 25 ## DW_FORM_flag_present + .ascii "\341\177" ## DW_AT_APPLE_optimized + .byte 25 ## DW_FORM_flag_present + .byte 0 ## EOM(1) + .byte 0 ## EOM(2) + .byte 6 ## Abbreviation Code + .byte 11 ## DW_TAG_lexical_block + .byte 1 ## DW_CHILDREN_yes + .byte 17 ## DW_AT_low_pc + .byte 1 ## DW_FORM_addr + .byte 18 ## DW_AT_high_pc + .byte 6 ## DW_FORM_data4 + .byte 0 ## EOM(1) + .byte 0 ## EOM(2) + .byte 7 ## Abbreviation Code + .byte 52 ## DW_TAG_variable + .byte 0 ## DW_CHILDREN_no + .byte 28 ## DW_AT_const_value + .byte 13 ## DW_FORM_sdata + .byte 3 ## DW_AT_name + .byte 14 ## DW_FORM_strp + .byte 58 ## DW_AT_decl_file + .byte 11 ## DW_FORM_data1 + .byte 59 ## DW_AT_decl_line + .byte 11 ## DW_FORM_data1 + .byte 73 ## DW_AT_type + .byte 19 ## DW_FORM_ref4 + .byte 0 ## EOM(1) + .byte 0 ## EOM(2) + .byte 0 ## EOM(3) + .section __DWARF,__debug_info,regular,debug +Lsection_info: +Lcu_begin0: +.set Lset0, Ldebug_info_end0-Ldebug_info_start0 ## Length of Unit + .long Lset0 +Ldebug_info_start0: + .short 4 ## DWARF version number +.set Lset1, Lsection_abbrev-Lsection_abbrev ## Offset Into Abbrev. Section + .long Lset1 + .byte 8 ## Address Size (in bytes) + .byte 1 ## Abbrev [1] 0xb:0x79 DW_TAG_compile_unit + .long 0 ## DW_AT_producer + .short 12 ## DW_AT_language + .long 101 ## DW_AT_name + .long 105 ## DW_AT_LLVM_sysroot +.set Lset2, Lline_table_start0-Lsection_line ## DW_AT_stmt_list + .long Lset2 + .long 107 ## DW_AT_comp_dir + ## DW_AT_APPLE_optimized + .quad Lfunc_begin0 ## DW_AT_low_pc +.set Lset3, Lfunc_end0-Lfunc_begin0 ## DW_AT_high_pc + .long Lset3 + .byte 2 ## Abbrev [2] 0x2e:0x15 DW_TAG_variable + .long 136 ## DW_AT_name + .long 67 ## DW_AT_type + ## DW_AT_external + .byte 1 ## DW_AT_decl_file + .byte 1 ## DW_AT_decl_line + .byte 9 ## DW_AT_location + .byte 3 + .quad _a + .byte 3 ## Abbrev [3] 0x43:0x5 DW_TAG_volatile_type + .long 72 ## DW_AT_type + .byte 4 ## Abbrev [4] 0x48:0x7 DW_TAG_base_type + .long 138 ## DW_AT_name + .byte 5 ## DW_AT_encoding + .byte 4 ## DW_AT_byte_size + .byte 5 ## Abbrev [5] 0x4f:0x34 DW_TAG_subprogram + .quad Lfunc_begin0 ## DW_AT_low_pc +.set Lset4, Lfunc_end0-Lfunc_begin0 ## DW_AT_high_pc + .long Lset4 + .byte 1 ## DW_AT_frame_base + .byte 86 + ## DW_AT_call_all_calls + .long 142 ## DW_AT_name + .byte 1 ## DW_AT_decl_file + .byte 2 ## DW_AT_decl_line + .long 72 ## DW_AT_type + ## DW_AT_external + ## DW_AT_APPLE_optimized + .byte 6 ## Abbrev [6] 0x68:0x1a DW_TAG_lexical_block + .quad Ltmp0 ## DW_AT_low_pc +.set Lset5, Ltmp1-Ltmp0 ## DW_AT_high_pc + .long Lset5 + .byte 7 ## Abbrev [7] 0x75:0xc DW_TAG_variable + .byte 3 ## DW_AT_const_value + .long 147 ## DW_AT_name + .byte 1 ## DW_AT_decl_file + .byte 4 ## DW_AT_decl_line + .long 72 ## DW_AT_type + .byte 0 ## End Of Children Mark + .byte 0 ## End Of Children Mark + .byte 0 ## End Of Children Mark +Ldebug_info_end0: + .section __DWARF,__debug_str,regular,debug +Linfo_string: + .asciz "clang version 11.0.0 (https://github.com/llvm/llvm-project f30ebf437851d3c68fd0eee82afbc0cef7373c00)" ## string offset=0 + .asciz "a.c" ## string offset=101 + .asciz "/" ## string offset=105 + .asciz "/Users/davide/work/build/bin" ## string offset=107 + .asciz "a" ## string offset=136 + .asciz "int" ## string offset=138 + .asciz "main" ## string offset=142 + .asciz "b" ## string offset=147 + .section __DWARF,__apple_names,regular,debug +Lnames_begin: + .long 1212240712 ## Header Magic + .short 1 ## Header Version + .short 0 ## Header Hash Function + .long 2 ## Header Bucket Count + .long 2 ## Header Hash Count + .long 12 ## Header Data Length + .long 0 ## HeaderData Die Offset Base + .long 1 ## HeaderData Atom Count + .short 1 ## DW_ATOM_die_offset + .short 6 ## DW_FORM_data4 + .long 0 ## Bucket 0 + .long -1 ## Bucket 1 + .long 177670 ## Hash in Bucket 0 + .long 2090499946 ## Hash in Bucket 0 +.set Lset6, LNames0-Lnames_begin ## Offset in Bucket 0 + .long Lset6 +.set Lset7, LNames1-Lnames_begin ## Offset in Bucket 0 + .long Lset7 +LNames0: + .long 136 ## a + .long 1 ## Num DIEs + .long 46 + .long 0 +LNames1: + .long 142 ## main + .long 1 ## Num DIEs + .long 79 + .long 0 + .section __DWARF,__apple_objc,regular,debug +Lobjc_begin: + .long 1212240712 ## Header Magic + .short 1 ## Header Version + .short 0 ## Header Hash Function + .long 1 ## Header Bucket Count + .long 0 ## Header Hash Count + .long 12 ## Header Data Length + .long 0 ## HeaderData Die Offset Base + .long 1 ## HeaderData Atom Count + .short 1 ## DW_ATOM_die_offset + .short 6 ## DW_FORM_data4 + .long -1 ## Bucket 0 + .section __DWARF,__apple_namespac,regular,debug +Lnamespac_begin: + .long 1212240712 ## Header Magic + .short 1 ## Header Version + .short 0 ## Header Hash Function + .long 1 ## Header Bucket Count + .long 0 ## Header Hash Count + .long 12 ## Header Data Length + .long 0 ## HeaderData Die Offset Base + .long 1 ## HeaderData Atom Count + .short 1 ## DW_ATOM_die_offset + .short 6 ## DW_FORM_data4 + .long -1 ## Bucket 0 + .section __DWARF,__apple_types,regular,debug +Ltypes_begin: + .long 1212240712 ## Header Magic + .short 1 ## Header Version + .short 0 ## Header Hash Function + .long 1 ## Header Bucket Count + .long 1 ## Header Hash Count + .long 20 ## Header Data Length + .long 0 ## HeaderData Die Offset Base + .long 3 ## HeaderData Atom Count + .short 1 ## DW_ATOM_die_offset + .short 6 ## DW_FORM_data4 + .short 3 ## DW_ATOM_die_tag + .short 5 ## DW_FORM_data2 + .short 4 ## DW_ATOM_type_flags + .short 11 ## DW_FORM_data1 + .long 0 ## Bucket 0 + .long 193495088 ## Hash in Bucket 0 +.set Lset8, Ltypes0-Ltypes_begin ## Offset in Bucket 0 + .long Lset8 +Ltypes0: + .long 138 ## int + .long 1 ## Num DIEs + .long 72 + .short 36 + .byte 0 + .long 0 +.subsections_via_symbols + .section __DWARF,__debug_line,regular,debug +Lsection_line: +Lline_table_start0: diff --git a/lldb/test/Shell/SymbolFile/NativePDB/ast-types.cpp b/lldb/test/Shell/SymbolFile/NativePDB/ast-types.cpp index 9d4ac139f5927..c4d50433a3b57 100644 --- a/lldb/test/Shell/SymbolFile/NativePDB/ast-types.cpp +++ b/lldb/test/Shell/SymbolFile/NativePDB/ast-types.cpp @@ -102,9 +102,9 @@ Anonymous>::D AnonABCVoidD; // CHECK: (A::C<-1>::D) ACNeg1D = (ACDMember = 0, CPtr = 0x{{0+}}) // CHECK: (A::D) AD = {} // CHECK: (A::D::E) ADE = (ADDMember = 0) -// CHECK: ((anonymous namespace)::Anonymous) AnonInt = (AnonymousMember = 0) -// CHECK: ((anonymous namespace)::Anonymous>) AnonABCVoid = (AnonymousMember = 0) -// CHECK: ((anonymous namespace)::Anonymous>::D) AnonABCVoidD = (AnonymousDMember = 0) +// CHECK: (Anonymous) AnonInt = (AnonymousMember = 0) +// CHECK: (Anonymous>) AnonABCVoid = (AnonymousMember = 0) +// CHECK: (Anonymous>::D) AnonABCVoidD = (AnonymousDMember = 0) // CHECK: Dumping clang ast for 1 modules. // CHECK: TranslationUnitDecl {{.*}} // CHECK: |-CXXRecordDecl {{.*}} class TrivialC definition diff --git a/lldb/test/Shell/lit-lldb-init.in b/lldb/test/Shell/lit-lldb-init.in index 77871a404b88e..c0c52b368f515 100644 --- a/lldb/test/Shell/lit-lldb-init.in +++ b/lldb/test/Shell/lit-lldb-init.in @@ -1,5 +1,5 @@ # LLDB init file for the LIT tests. -env DYLD_LIBRARY_PATH='@LLDB_SWIFT_LIBS@' LD_LIBRARY_PATH='@LLDB_SWIFT_LIBS@' SIMCTL_CHILD_DYLD_LIBRARY_PATH='@LLDB_SWIFT_LIBS@' +env DYLD_LIBRARY_PATH='@LLDB_SWIFT_LIBS@/macosx' LD_LIBRARY_PATH='@LLDB_SWIFT_LIBS@/@CMAKE_SYSTEM_PROCESSOR@' SIMCTL_CHILD_DYLD_LIBRARY_PATH='@LLDB_SWIFT_LIBS@/macosx' settings set symbols.enable-external-lookup false settings set plugin.process.gdb-remote.packet-timeout 60 settings set interpreter.echo-comment-commands false diff --git a/lldb/tools/debugserver/debugserver.xcodeproj/project.pbxproj b/lldb/tools/debugserver/debugserver.xcodeproj/project.pbxproj index 3056635eff34d..1c7a55f7108a0 100644 --- a/lldb/tools/debugserver/debugserver.xcodeproj/project.pbxproj +++ b/lldb/tools/debugserver/debugserver.xcodeproj/project.pbxproj @@ -7,131 +7,165 @@ objects = { /* Begin PBXBuildFile section */ - 23562ED61D342A5A00AB2BD4 /* ActivityStore.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 23562ED51D342A5A00AB2BD4 /* ActivityStore.cpp */; }; - 23562ED71D342A5A00AB2BD4 /* ActivityStore.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 23562ED51D342A5A00AB2BD4 /* ActivityStore.cpp */; }; - 26CE05C5115C36590022F371 /* CFBundle.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 2695DD910D3EBFF6007E4CA2 /* CFBundle.cpp */; }; - 456F67641AD46CE9002850C2 /* CFBundle.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 2695DD910D3EBFF6007E4CA2 /* CFBundle.cpp */; }; - 26CE05C3115C36580022F371 /* CFString.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 2695DD9B0D3EC160007E4CA2 /* CFString.cpp */; }; - 456F67621AD46CE9002850C2 /* CFString.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 2695DD9B0D3EC160007E4CA2 /* CFString.cpp */; }; - 26CE05CF115C36F70022F371 /* CoreFoundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 26ACA3340D3E956300A2120B /* CoreFoundation.framework */; settings = {ATTRIBUTES = (Required, ); }; }; - 456F676B1AD46CE9002850C2 /* CoreFoundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 26ACA3340D3E956300A2120B /* CoreFoundation.framework */; settings = {ATTRIBUTES = (Required, ); }; }; - 26CE05B7115C363B0022F371 /* DNB.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 26C637D60C71334A0024798E /* DNB.cpp */; }; - 456F67551AD46CE9002850C2 /* DNB.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 26C637D60C71334A0024798E /* DNB.cpp */; }; - 264D5D581293835600ED4C01 /* DNBArch.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 264D5D571293835600ED4C01 /* DNBArch.cpp */; }; - 456F67671AD46CE9002850C2 /* DNBArch.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 264D5D571293835600ED4C01 /* DNBArch.cpp */; }; - 26CE05C1115C36510022F371 /* DNBArchImpl.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 2675D4220CCEB705000F49AF /* DNBArchImpl.cpp */; }; - 26CE05C2115C36550022F371 /* DNBArchImpl.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 26C637FB0C71334A0024798E /* DNBArchImpl.cpp */; }; - 456F67601AD46CE9002850C2 /* DNBArchImpl.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 2675D4220CCEB705000F49AF /* DNBArchImpl.cpp */; }; - 456F67611AD46CE9002850C2 /* DNBArchImpl.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 26C637FB0C71334A0024798E /* DNBArchImpl.cpp */; }; - 266B5ED11460A68200E43F0A /* DNBArchImplARM64.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 266B5ECF1460A68200E43F0A /* DNBArchImplARM64.cpp */; }; - 456F67691AD46CE9002850C2 /* DNBArchImplARM64.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 266B5ECF1460A68200E43F0A /* DNBArchImplARM64.cpp */; }; - 26CE05C0115C364F0022F371 /* DNBArchImplI386.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 26C637EA0C71334A0024798E /* DNBArchImplI386.cpp */; }; - 456F675F1AD46CE9002850C2 /* DNBArchImplI386.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 26C637EA0C71334A0024798E /* DNBArchImplI386.cpp */; }; - 26CE05BF115C364D0022F371 /* DNBArchImplX86_64.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 26CF99A21142EB7400011AAB /* DNBArchImplX86_64.cpp */; }; - 456F675E1AD46CE9002850C2 /* DNBArchImplX86_64.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 26CF99A21142EB7400011AAB /* DNBArchImplX86_64.cpp */; }; - 26CE05B8115C363C0022F371 /* DNBBreakpoint.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 26C637D90C71334A0024798E /* DNBBreakpoint.cpp */; }; - 456F67571AD46CE9002850C2 /* DNBBreakpoint.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 26C637D90C71334A0024798E /* DNBBreakpoint.cpp */; }; - 26CE05B9115C363D0022F371 /* DNBDataRef.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 26C637DB0C71334A0024798E /* DNBDataRef.cpp */; }; - 456F67581AD46CE9002850C2 /* DNBDataRef.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 26C637DB0C71334A0024798E /* DNBDataRef.cpp */; }; - 26CE05A7115C360D0022F371 /* DNBError.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 26C637DE0C71334A0024798E /* DNBError.cpp */; }; - 456F67461AD46CE9002850C2 /* DNBError.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 26C637DE0C71334A0024798E /* DNBError.cpp */; }; - 26CE05BA115C363E0022F371 /* DNBLog.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 26C637E00C71334A0024798E /* DNBLog.cpp */; }; - 456F67591AD46CE9002850C2 /* DNBLog.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 26C637E00C71334A0024798E /* DNBLog.cpp */; }; - 26CE05BB115C363F0022F371 /* DNBRegisterInfo.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 26C637E20C71334A0024798E /* DNBRegisterInfo.cpp */; }; - 456F675A1AD46CE9002850C2 /* DNBRegisterInfo.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 26C637E20C71334A0024798E /* DNBRegisterInfo.cpp */; }; - 26CE05A8115C36170022F371 /* DNBThreadResumeActions.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 260E7331114BFFE600D1DFB3 /* DNBThreadResumeActions.cpp */; }; - 456F67471AD46CE9002850C2 /* DNBThreadResumeActions.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 260E7331114BFFE600D1DFB3 /* DNBThreadResumeActions.cpp */; }; - 23AE72E41D25DECF00945BCE /* DarwinLogCollector.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 23AE72E21D25DECF00945BCE /* DarwinLogCollector.cpp */; }; - 23AE72E51D25DEE100945BCE /* DarwinLogCollector.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 23AE72E21D25DECF00945BCE /* DarwinLogCollector.cpp */; }; - 49D404621E39260F00570CDC /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 49D404611E39260F00570CDC /* Foundation.framework */; }; - AFA3FCA11E39984900218D5E /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 49D404611E39260F00570CDC /* Foundation.framework */; }; - 456F67561AD46CE9002850C2 /* Genealogy.cpp in Sources */ = {isa = PBXBuildFile; fileRef = AFEC3363194A8B0B00FF05C6 /* Genealogy.cpp */; }; - AFEC3364194A8B0B00FF05C6 /* Genealogy.cpp in Sources */ = {isa = PBXBuildFile; fileRef = AFEC3363194A8B0B00FF05C6 /* Genealogy.cpp */; }; 23043C9D1D35DBEC00FC25CA /* JSON.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 233B4EA51D2DB54300E98261 /* JSON.cpp */; }; + 23043C9E1D35DBFA00FC25CA /* StringConvert.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 233B4EA81D2DB96A00E98261 /* StringConvert.cpp */; }; + 2307CCCB1D4A5D630016ABC0 /* LogFilterExactMatch.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 237821AE1D4917D20028B7A1 /* LogFilterExactMatch.cpp */; }; 233B4EA71D2DB54300E98261 /* JSON.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 233B4EA51D2DB54300E98261 /* JSON.cpp */; }; + 233B4EA91D2DB96A00E98261 /* StringConvert.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 233B4EA81D2DB96A00E98261 /* StringConvert.cpp */; }; + 23562ED21D3424DF00AB2BD4 /* LogMessageOsLog.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 23562ED01D3424DF00AB2BD4 /* LogMessageOsLog.cpp */; }; + 23562ED31D3424DF00AB2BD4 /* LogMessageOsLog.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 23562ED01D3424DF00AB2BD4 /* LogMessageOsLog.cpp */; }; + 23562ED61D342A5A00AB2BD4 /* ActivityStore.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 23562ED51D342A5A00AB2BD4 /* ActivityStore.cpp */; }; + 23562ED71D342A5A00AB2BD4 /* ActivityStore.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 23562ED51D342A5A00AB2BD4 /* ActivityStore.cpp */; }; + 23562ED91D342B0000AB2BD4 /* LogMessage.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 23562ED81D342B0000AB2BD4 /* LogMessage.cpp */; }; + 23562EDA1D342B0000AB2BD4 /* LogMessage.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 23562ED81D342B0000AB2BD4 /* LogMessage.cpp */; }; + 237821B01D4917D20028B7A1 /* LogFilterExactMatch.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 237821AE1D4917D20028B7A1 /* LogFilterExactMatch.cpp */; }; 23AC04C61D2F41A00072351D /* LogFilter.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 23AC04C41D2F41A00072351D /* LogFilter.cpp */; }; 23AC04C71D2F41A00072351D /* LogFilter.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 23AC04C41D2F41A00072351D /* LogFilter.cpp */; }; 23AC04CA1D2F42250072351D /* LogFilterChain.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 23AC04C81D2F42250072351D /* LogFilterChain.cpp */; }; 23AC04CB1D2F42250072351D /* LogFilterChain.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 23AC04C81D2F42250072351D /* LogFilterChain.cpp */; }; - 2307CCCB1D4A5D630016ABC0 /* LogFilterExactMatch.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 237821AE1D4917D20028B7A1 /* LogFilterExactMatch.cpp */; }; - 237821B01D4917D20028B7A1 /* LogFilterExactMatch.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 237821AE1D4917D20028B7A1 /* LogFilterExactMatch.cpp */; }; 23AC04CF1D2F58AF0072351D /* LogFilterRegex.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 23AC04CD1D2F58AF0072351D /* LogFilterRegex.cpp */; }; 23AC04D01D2F58AF0072351D /* LogFilterRegex.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 23AC04CD1D2F58AF0072351D /* LogFilterRegex.cpp */; }; - 23562ED91D342B0000AB2BD4 /* LogMessage.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 23562ED81D342B0000AB2BD4 /* LogMessage.cpp */; }; - 23562EDA1D342B0000AB2BD4 /* LogMessage.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 23562ED81D342B0000AB2BD4 /* LogMessage.cpp */; }; - 23562ED21D3424DF00AB2BD4 /* LogMessageOsLog.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 23562ED01D3424DF00AB2BD4 /* LogMessageOsLog.cpp */; }; - 23562ED31D3424DF00AB2BD4 /* LogMessageOsLog.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 23562ED01D3424DF00AB2BD4 /* LogMessageOsLog.cpp */; }; + 23AE72E41D25DECF00945BCE /* DarwinLogCollector.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 23AE72E21D25DECF00945BCE /* DarwinLogCollector.cpp */; }; + 23AE72E51D25DEE100945BCE /* DarwinLogCollector.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 23AE72E21D25DECF00945BCE /* DarwinLogCollector.cpp */; }; + 23D1B0291D497E8B00FF831B /* OsLogger.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 23D1B0271D497E8B00FF831B /* OsLogger.cpp */; }; + 23D1B02A1D497E8B00FF831B /* OsLogger.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 23D1B0271D497E8B00FF831B /* OsLogger.cpp */; }; + 264D5D581293835600ED4C01 /* DNBArch.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 264D5D571293835600ED4C01 /* DNBArch.cpp */; }; + 266B5ED11460A68200E43F0A /* DNBArchImplARM64.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 266B5ECF1460A68200E43F0A /* DNBArchImplARM64.cpp */; }; + 26CE05A7115C360D0022F371 /* DNBError.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 26C637DE0C71334A0024798E /* DNBError.cpp */; }; + 26CE05A8115C36170022F371 /* DNBThreadResumeActions.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 260E7331114BFFE600D1DFB3 /* DNBThreadResumeActions.cpp */; }; + 26CE05A9115C36250022F371 /* debugserver.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 26A02918114AB9240029C479 /* debugserver.cpp */; }; + 26CE05AA115C36260022F371 /* RNBContext.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 26A68F7E0D104EC800665A9E /* RNBContext.cpp */; }; + 26CE05AB115C36270022F371 /* RNBServices.cpp in Sources */ = {isa = PBXBuildFile; fileRef = EF8878A00D9C797C001831DA /* RNBServices.cpp */; }; + 26CE05AC115C36280022F371 /* RNBSocket.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 26A68FB00D1054DA00665A9E /* RNBSocket.cpp */; }; + 26CE05AD115C36280022F371 /* RNBRemote.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 26A68FD60D10574500665A9E /* RNBRemote.cpp */; }; + 26CE05AE115C36320022F371 /* dbgnub-mig.defs in Sources */ = {isa = PBXBuildFile; fileRef = 26C637E80C71334A0024798E /* dbgnub-mig.defs */; settings = {ATTRIBUTES = (Client, Server, ); }; }; 26CE05B0115C36340022F371 /* MachException.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 26C637EE0C71334A0024798E /* MachException.cpp */; }; - 456F674E1AD46CE9002850C2 /* MachException.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 26C637EE0C71334A0024798E /* MachException.cpp */; }; 26CE05B1115C36350022F371 /* MachProcess.mm in Sources */ = {isa = PBXBuildFile; fileRef = 26C637F00C71334A0024798E /* MachProcess.mm */; }; - 456F674F1AD46CE9002850C2 /* MachProcess.mm in Sources */ = {isa = PBXBuildFile; fileRef = 26C637F00C71334A0024798E /* MachProcess.mm */; }; - 26CE05B6115C36390022F371 /* MachTask.mm in Sources */ = {isa = PBXBuildFile; fileRef = 26B67DE10EE9BC30006C8BC0 /* MachTask.mm */; }; - 456F67541AD46CE9002850C2 /* MachTask.mm in Sources */ = {isa = PBXBuildFile; fileRef = 26B67DE10EE9BC30006C8BC0 /* MachTask.mm */; }; 26CE05B2115C36360022F371 /* MachThread.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 26C637F20C71334A0024798E /* MachThread.cpp */; }; - 456F67501AD46CE9002850C2 /* MachThread.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 26C637F20C71334A0024798E /* MachThread.cpp */; }; 26CE05B3115C36370022F371 /* MachThreadList.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 26C637F40C71334A0024798E /* MachThreadList.cpp */; }; - 456F67511AD46CE9002850C2 /* MachThreadList.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 26C637F40C71334A0024798E /* MachThreadList.cpp */; }; 26CE05B4115C36380022F371 /* MachVMMemory.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 26C637F60C71334A0024798E /* MachVMMemory.cpp */; }; - 456F67521AD46CE9002850C2 /* MachVMMemory.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 26C637F60C71334A0024798E /* MachVMMemory.cpp */; }; 26CE05B5115C36380022F371 /* MachVMRegion.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 26C637F80C71334A0024798E /* MachVMRegion.cpp */; }; - 456F67531AD46CE9002850C2 /* MachVMRegion.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 26C637F80C71334A0024798E /* MachVMRegion.cpp */; }; - 23D1B0291D497E8B00FF831B /* OsLogger.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 23D1B0271D497E8B00FF831B /* OsLogger.cpp */; }; - 23D1B02A1D497E8B00FF831B /* OsLogger.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 23D1B0271D497E8B00FF831B /* OsLogger.cpp */; }; + 26CE05B6115C36390022F371 /* MachTask.mm in Sources */ = {isa = PBXBuildFile; fileRef = 26B67DE10EE9BC30006C8BC0 /* MachTask.mm */; }; + 26CE05B7115C363B0022F371 /* DNB.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 26C637D60C71334A0024798E /* DNB.cpp */; }; + 26CE05B8115C363C0022F371 /* DNBBreakpoint.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 26C637D90C71334A0024798E /* DNBBreakpoint.cpp */; }; + 26CE05B9115C363D0022F371 /* DNBDataRef.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 26C637DB0C71334A0024798E /* DNBDataRef.cpp */; }; + 26CE05BA115C363E0022F371 /* DNBLog.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 26C637E00C71334A0024798E /* DNBLog.cpp */; }; + 26CE05BB115C363F0022F371 /* DNBRegisterInfo.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 26C637E20C71334A0024798E /* DNBRegisterInfo.cpp */; }; 26CE05BC115C36420022F371 /* PThreadEvent.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 26C637FE0C71334A0024798E /* PThreadEvent.cpp */; }; - 456F675B1AD46CE9002850C2 /* PThreadEvent.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 26C637FE0C71334A0024798E /* PThreadEvent.cpp */; }; 26CE05BD115C36430022F371 /* PThreadMutex.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 2672DBEE0EEF446700E92059 /* PThreadMutex.cpp */; }; - 456F675C1AD46CE9002850C2 /* PThreadMutex.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 2672DBEE0EEF446700E92059 /* PThreadMutex.cpp */; }; + 26CE05BE115C36440022F371 /* SysSignal.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 26C638010C71334A0024798E /* SysSignal.cpp */; }; + 26CE05BF115C364D0022F371 /* DNBArchImplX86_64.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 26CF99A21142EB7400011AAB /* DNBArchImplX86_64.cpp */; }; + 26CE05C0115C364F0022F371 /* DNBArchImplI386.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 26C637EA0C71334A0024798E /* DNBArchImplI386.cpp */; }; + 26CE05C1115C36510022F371 /* DNBArchImpl.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 2675D4220CCEB705000F49AF /* DNBArchImpl.cpp */; }; + 26CE05C3115C36580022F371 /* CFString.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 2695DD9B0D3EC160007E4CA2 /* CFString.cpp */; }; + 26CE05C5115C36590022F371 /* CFBundle.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 2695DD910D3EBFF6007E4CA2 /* CFBundle.cpp */; }; + 26CE05CF115C36F70022F371 /* CoreFoundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 26ACA3340D3E956300A2120B /* CoreFoundation.framework */; settings = {ATTRIBUTES = (Required, ); }; }; 26CE05F1115C387C0022F371 /* PseudoTerminal.cpp in Sources */ = {isa = PBXBuildFile; fileRef = AF67ABFF0D34604D0022D128 /* PseudoTerminal.cpp */; }; - 456F67651AD46CE9002850C2 /* PseudoTerminal.cpp in Sources */ = {isa = PBXBuildFile; fileRef = AF67ABFF0D34604D0022D128 /* PseudoTerminal.cpp */; }; - 26CE05AA115C36260022F371 /* RNBContext.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 26A68F7E0D104EC800665A9E /* RNBContext.cpp */; }; + 456F67461AD46CE9002850C2 /* DNBError.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 26C637DE0C71334A0024798E /* DNBError.cpp */; }; + 456F67471AD46CE9002850C2 /* DNBThreadResumeActions.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 260E7331114BFFE600D1DFB3 /* DNBThreadResumeActions.cpp */; }; + 456F67481AD46CE9002850C2 /* debugserver.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 26A02918114AB9240029C479 /* debugserver.cpp */; }; 456F67491AD46CE9002850C2 /* RNBContext.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 26A68F7E0D104EC800665A9E /* RNBContext.cpp */; }; - 26CE05AD115C36280022F371 /* RNBRemote.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 26A68FD60D10574500665A9E /* RNBRemote.cpp */; }; - 456F674C1AD46CE9002850C2 /* RNBRemote.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 26A68FD60D10574500665A9E /* RNBRemote.cpp */; }; - 26CE05AB115C36270022F371 /* RNBServices.cpp in Sources */ = {isa = PBXBuildFile; fileRef = EF8878A00D9C797C001831DA /* RNBServices.cpp */; }; 456F674A1AD46CE9002850C2 /* RNBServices.cpp in Sources */ = {isa = PBXBuildFile; fileRef = EF8878A00D9C797C001831DA /* RNBServices.cpp */; }; - 26CE05AC115C36280022F371 /* RNBSocket.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 26A68FB00D1054DA00665A9E /* RNBSocket.cpp */; }; 456F674B1AD46CE9002850C2 /* RNBSocket.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 26A68FB00D1054DA00665A9E /* RNBSocket.cpp */; }; - AF588449206077BD00A0CB5A /* SocketAddress.cpp in Sources */ = {isa = PBXBuildFile; fileRef = D6631CA81E848FE9006A7B11 /* SocketAddress.cpp */; }; - D6631CA91E848FE9006A7B11 /* SocketAddress.cpp in Sources */ = {isa = PBXBuildFile; fileRef = D6631CA81E848FE9006A7B11 /* SocketAddress.cpp */; }; + 456F674C1AD46CE9002850C2 /* RNBRemote.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 26A68FD60D10574500665A9E /* RNBRemote.cpp */; }; + 456F674D1AD46CE9002850C2 /* dbgnub-mig.defs in Sources */ = {isa = PBXBuildFile; fileRef = 26C637E80C71334A0024798E /* dbgnub-mig.defs */; settings = {ATTRIBUTES = (Client, Server, ); }; }; + 456F674E1AD46CE9002850C2 /* MachException.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 26C637EE0C71334A0024798E /* MachException.cpp */; }; + 456F674F1AD46CE9002850C2 /* MachProcess.mm in Sources */ = {isa = PBXBuildFile; fileRef = 26C637F00C71334A0024798E /* MachProcess.mm */; }; + 456F67501AD46CE9002850C2 /* MachThread.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 26C637F20C71334A0024798E /* MachThread.cpp */; }; + 456F67511AD46CE9002850C2 /* MachThreadList.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 26C637F40C71334A0024798E /* MachThreadList.cpp */; }; + 456F67521AD46CE9002850C2 /* MachVMMemory.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 26C637F60C71334A0024798E /* MachVMMemory.cpp */; }; + 456F67531AD46CE9002850C2 /* MachVMRegion.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 26C637F80C71334A0024798E /* MachVMRegion.cpp */; }; + 456F67541AD46CE9002850C2 /* MachTask.mm in Sources */ = {isa = PBXBuildFile; fileRef = 26B67DE10EE9BC30006C8BC0 /* MachTask.mm */; }; + 456F67551AD46CE9002850C2 /* DNB.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 26C637D60C71334A0024798E /* DNB.cpp */; }; + 456F67561AD46CE9002850C2 /* Genealogy.cpp in Sources */ = {isa = PBXBuildFile; fileRef = AFEC3363194A8B0B00FF05C6 /* Genealogy.cpp */; }; + 456F67571AD46CE9002850C2 /* DNBBreakpoint.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 26C637D90C71334A0024798E /* DNBBreakpoint.cpp */; }; + 456F67581AD46CE9002850C2 /* DNBDataRef.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 26C637DB0C71334A0024798E /* DNBDataRef.cpp */; }; + 456F67591AD46CE9002850C2 /* DNBLog.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 26C637E00C71334A0024798E /* DNBLog.cpp */; }; + 456F675A1AD46CE9002850C2 /* DNBRegisterInfo.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 26C637E20C71334A0024798E /* DNBRegisterInfo.cpp */; }; + 456F675B1AD46CE9002850C2 /* PThreadEvent.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 26C637FE0C71334A0024798E /* PThreadEvent.cpp */; }; + 456F675C1AD46CE9002850C2 /* PThreadMutex.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 2672DBEE0EEF446700E92059 /* PThreadMutex.cpp */; }; + 456F675D1AD46CE9002850C2 /* SysSignal.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 26C638010C71334A0024798E /* SysSignal.cpp */; }; + 456F675E1AD46CE9002850C2 /* DNBArchImplX86_64.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 26CF99A21142EB7400011AAB /* DNBArchImplX86_64.cpp */; }; + 456F675F1AD46CE9002850C2 /* DNBArchImplI386.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 26C637EA0C71334A0024798E /* DNBArchImplI386.cpp */; }; + 456F67601AD46CE9002850C2 /* DNBArchImpl.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 2675D4220CCEB705000F49AF /* DNBArchImpl.cpp */; }; + 456F67621AD46CE9002850C2 /* CFString.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 2695DD9B0D3EC160007E4CA2 /* CFString.cpp */; }; + 456F67641AD46CE9002850C2 /* CFBundle.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 2695DD910D3EBFF6007E4CA2 /* CFBundle.cpp */; }; + 456F67651AD46CE9002850C2 /* PseudoTerminal.cpp in Sources */ = {isa = PBXBuildFile; fileRef = AF67ABFF0D34604D0022D128 /* PseudoTerminal.cpp */; }; + 456F67671AD46CE9002850C2 /* DNBArch.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 264D5D571293835600ED4C01 /* DNBArch.cpp */; }; + 456F67691AD46CE9002850C2 /* DNBArchImplARM64.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 266B5ECF1460A68200E43F0A /* DNBArchImplARM64.cpp */; }; + 456F676B1AD46CE9002850C2 /* CoreFoundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 26ACA3340D3E956300A2120B /* CoreFoundation.framework */; settings = {ATTRIBUTES = (Required, ); }; }; + 49D404621E39260F00570CDC /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 49D404611E39260F00570CDC /* Foundation.framework */; }; AF48558C1D75126800D19C07 /* StdStringExtractor.cpp in Sources */ = {isa = PBXBuildFile; fileRef = AF48558B1D75126800D19C07 /* StdStringExtractor.cpp */; }; AF48558D1D75127500D19C07 /* StdStringExtractor.cpp in Sources */ = {isa = PBXBuildFile; fileRef = AF48558B1D75126800D19C07 /* StdStringExtractor.cpp */; }; - 23043C9E1D35DBFA00FC25CA /* StringConvert.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 233B4EA81D2DB96A00E98261 /* StringConvert.cpp */; }; - 233B4EA91D2DB96A00E98261 /* StringConvert.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 233B4EA81D2DB96A00E98261 /* StringConvert.cpp */; }; - 26CE05BE115C36440022F371 /* SysSignal.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 26C638010C71334A0024798E /* SysSignal.cpp */; }; - 456F675D1AD46CE9002850C2 /* SysSignal.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 26C638010C71334A0024798E /* SysSignal.cpp */; }; - 26CE05AE115C36320022F371 /* dbgnub-mig.defs in Sources */ = {isa = PBXBuildFile; fileRef = 26C637E80C71334A0024798E /* dbgnub-mig.defs */; settings = {ATTRIBUTES = (Client, Server, ); }; }; - 456F674D1AD46CE9002850C2 /* dbgnub-mig.defs in Sources */ = {isa = PBXBuildFile; fileRef = 26C637E80C71334A0024798E /* dbgnub-mig.defs */; settings = {ATTRIBUTES = (Client, Server, ); }; }; - 26CE05A9115C36250022F371 /* debugserver.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 26A02918114AB9240029C479 /* debugserver.cpp */; }; - 456F67481AD46CE9002850C2 /* debugserver.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 26A02918114AB9240029C479 /* debugserver.cpp */; }; + AF588449206077BD00A0CB5A /* SocketAddress.cpp in Sources */ = {isa = PBXBuildFile; fileRef = D6631CA81E848FE9006A7B11 /* SocketAddress.cpp */; }; + AFA3FCA11E39984900218D5E /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 49D404611E39260F00570CDC /* Foundation.framework */; }; + AFEC3364194A8B0B00FF05C6 /* Genealogy.cpp in Sources */ = {isa = PBXBuildFile; fileRef = AFEC3363194A8B0B00FF05C6 /* Genealogy.cpp */; }; + D6631CA91E848FE9006A7B11 /* SocketAddress.cpp in Sources */ = {isa = PBXBuildFile; fileRef = D6631CA81E848FE9006A7B11 /* SocketAddress.cpp */; }; /* End PBXBuildFile section */ /* Begin PBXFileReference section */ - 23562ED51D342A5A00AB2BD4 /* ActivityStore.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = ActivityStore.cpp; sourceTree = ""; }; + 2307CCCC1D4A5DAE0016ABC0 /* CMakeLists.txt */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = CMakeLists.txt; sourceTree = ""; }; + 233B4EA51D2DB54300E98261 /* JSON.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = JSON.cpp; sourceTree = ""; }; + 233B4EA61D2DB54300E98261 /* JSON.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JSON.h; sourceTree = ""; }; + 233B4EA81D2DB96A00E98261 /* StringConvert.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = StringConvert.cpp; path = ../../../source/Host/common/StringConvert.cpp; sourceTree = ""; }; + 23562ECF1D34110D00AB2BD4 /* DarwinLogTypes.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = DarwinLogTypes.h; sourceTree = ""; }; + 23562ED01D3424DF00AB2BD4 /* LogMessageOsLog.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = LogMessageOsLog.cpp; sourceTree = ""; }; + 23562ED11D3424DF00AB2BD4 /* LogMessageOsLog.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = LogMessageOsLog.h; sourceTree = ""; }; 23562ED41D3426DD00AB2BD4 /* ActivityStore.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = ActivityStore.h; sourceTree = ""; }; + 23562ED51D342A5A00AB2BD4 /* ActivityStore.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = ActivityStore.cpp; sourceTree = ""; }; + 23562ED81D342B0000AB2BD4 /* LogMessage.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = LogMessage.cpp; sourceTree = ""; }; + 237821AD1D4917D20028B7A1 /* CMakeLists.txt */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = CMakeLists.txt; sourceTree = ""; }; + 237821AE1D4917D20028B7A1 /* LogFilterExactMatch.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = LogFilterExactMatch.cpp; sourceTree = ""; }; + 237821AF1D4917D20028B7A1 /* LogFilterExactMatch.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = LogFilterExactMatch.h; sourceTree = ""; }; + 23AC04C41D2F41A00072351D /* LogFilter.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = LogFilter.cpp; sourceTree = ""; }; + 23AC04C51D2F41A00072351D /* LogFilter.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = LogFilter.h; sourceTree = ""; }; + 23AC04C81D2F42250072351D /* LogFilterChain.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = LogFilterChain.cpp; sourceTree = ""; }; + 23AC04C91D2F42250072351D /* LogFilterChain.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = LogFilterChain.h; sourceTree = ""; }; + 23AC04CC1D2F42F10072351D /* DarwinLogInterfaces.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = DarwinLogInterfaces.h; sourceTree = ""; }; + 23AC04CD1D2F58AF0072351D /* LogFilterRegex.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = LogFilterRegex.cpp; sourceTree = ""; }; + 23AC04CE1D2F58AF0072351D /* LogFilterRegex.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = LogFilterRegex.h; sourceTree = ""; }; + 23AC04D11D2F60130072351D /* LogMessage.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = LogMessage.h; sourceTree = ""; }; + 23AE72E21D25DECF00945BCE /* DarwinLogCollector.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = DarwinLogCollector.cpp; sourceTree = ""; }; + 23AE72E31D25DECF00945BCE /* DarwinLogCollector.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DarwinLogCollector.h; sourceTree = ""; }; 23AE72E61D25DEFB00945BCE /* ActivityStreamSPI.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = ActivityStreamSPI.h; sourceTree = ""; }; + 23CF6F5E1D28A3760088ADC9 /* DarwinLogEvent.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = DarwinLogEvent.h; sourceTree = ""; }; + 23D1B0271D497E8B00FF831B /* OsLogger.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = OsLogger.cpp; sourceTree = ""; }; + 23D1B0281D497E8B00FF831B /* OsLogger.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OsLogger.h; sourceTree = ""; }; + 260828DE0CBAF7F400F95054 /* DNBRuntimeAction.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DNBRuntimeAction.h; sourceTree = ""; }; + 260E7331114BFFE600D1DFB3 /* DNBThreadResumeActions.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = DNBThreadResumeActions.cpp; sourceTree = ""; }; + 260E7332114BFFE600D1DFB3 /* DNBThreadResumeActions.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DNBThreadResumeActions.h; sourceTree = ""; }; + 260FC7320E5B290400043FC9 /* debugnub-exports */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = "debugnub-exports"; sourceTree = SOURCE_ROOT; }; + 26203D1C1641EFB200A662F7 /* com.apple.debugserver.applist.internal.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = com.apple.debugserver.applist.internal.plist; sourceTree = ""; }; + 26203D1D1641EFB200A662F7 /* com.apple.debugserver.internal.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = com.apple.debugserver.internal.plist; sourceTree = ""; }; + 26242C390DDBD33C0054A4CC /* debugserver-entitlements.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = "debugserver-entitlements.plist"; sourceTree = ""; }; + 264D5D571293835600ED4C01 /* DNBArch.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = DNBArch.cpp; sourceTree = ""; }; + 264F679A1B2F9EB200140093 /* JSONGenerator.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = JSONGenerator.h; sourceTree = ""; }; + 26593A060D4931CC001C9FE3 /* ChangeLog */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = ChangeLog; sourceTree = ""; }; + 266B5ECF1460A68200E43F0A /* DNBArchImplARM64.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = DNBArchImplARM64.cpp; sourceTree = ""; }; + 266B5ED01460A68200E43F0A /* DNBArchImplARM64.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DNBArchImplARM64.h; sourceTree = ""; }; + 2672DBEE0EEF446700E92059 /* PThreadMutex.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = PThreadMutex.cpp; sourceTree = ""; }; + 2675D4220CCEB705000F49AF /* DNBArchImpl.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = DNBArchImpl.cpp; path = arm/DNBArchImpl.cpp; sourceTree = ""; }; + 2675D4230CCEB705000F49AF /* DNBArchImpl.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; name = DNBArchImpl.h; path = arm/DNBArchImpl.h; sourceTree = ""; }; 2695DD910D3EBFF6007E4CA2 /* CFBundle.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = CFBundle.cpp; sourceTree = ""; }; 2695DD920D3EBFF6007E4CA2 /* CFBundle.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CFBundle.h; sourceTree = ""; }; - 2695DD9B0D3EC160007E4CA2 /* CFString.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = CFString.cpp; sourceTree = ""; }; 2695DD9A0D3EC160007E4CA2 /* CFString.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CFString.h; sourceTree = ""; }; - 26C637E70C71334A0024798E /* CFUtils.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = CFUtils.h; sourceTree = ""; }; - 2307CCCC1D4A5DAE0016ABC0 /* CMakeLists.txt */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = CMakeLists.txt; sourceTree = ""; }; - 237821AD1D4917D20028B7A1 /* CMakeLists.txt */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = CMakeLists.txt; sourceTree = ""; }; - 26593A060D4931CC001C9FE3 /* ChangeLog */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = ChangeLog; sourceTree = ""; }; + 2695DD9B0D3EC160007E4CA2 /* CFString.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = CFString.cpp; sourceTree = ""; }; + 269E8DF8164B2ED200AD65F6 /* com.apple.debugserver.posix.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = com.apple.debugserver.posix.plist; sourceTree = ""; }; + 26A02918114AB9240029C479 /* debugserver.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = debugserver.cpp; sourceTree = ""; }; + 26A4BAED0D498B7D00A9BEAB /* com.apple.debugserver.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = com.apple.debugserver.plist; sourceTree = ""; }; + 26A68F7D0D104EC800665A9E /* RNBContext.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RNBContext.h; sourceTree = ""; }; + 26A68F7E0D104EC800665A9E /* RNBContext.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = RNBContext.cpp; sourceTree = ""; }; + 26A68FAF0D1054DA00665A9E /* RNBSocket.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RNBSocket.h; sourceTree = ""; }; + 26A68FB00D1054DA00665A9E /* RNBSocket.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = RNBSocket.cpp; sourceTree = ""; }; + 26A68FD50D10574500665A9E /* RNBRemote.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RNBRemote.h; sourceTree = ""; }; + 26A68FD60D10574500665A9E /* RNBRemote.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = RNBRemote.cpp; sourceTree = ""; }; + 26A8FE1E0D11A77B00203048 /* DNBTimer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DNBTimer.h; sourceTree = ""; }; 26ACA3340D3E956300A2120B /* CoreFoundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreFoundation.framework; path = System/Library/Frameworks/CoreFoundation.framework; sourceTree = SDKROOT; }; + 26B67DE00EE9BC30006C8BC0 /* MachTask.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MachTask.h; sourceTree = ""; }; + 26B67DE10EE9BC30006C8BC0 /* MachTask.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = MachTask.mm; sourceTree = ""; }; 26C637D60C71334A0024798E /* DNB.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = DNB.cpp; sourceTree = ""; }; 26C637D70C71334A0024798E /* DNB.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = DNB.h; sourceTree = ""; }; - 264D5D571293835600ED4C01 /* DNBArch.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = DNBArch.cpp; sourceTree = ""; }; 26C637D80C71334A0024798E /* DNBArch.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = DNBArch.h; sourceTree = ""; }; - 2675D4220CCEB705000F49AF /* DNBArchImpl.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = DNBArchImpl.cpp; path = arm/DNBArchImpl.cpp; sourceTree = ""; }; - 26C637FB0C71334A0024798E /* DNBArchImpl.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = DNBArchImpl.cpp; sourceTree = ""; }; - 2675D4230CCEB705000F49AF /* DNBArchImpl.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; name = DNBArchImpl.h; path = arm/DNBArchImpl.h; sourceTree = ""; }; - 26C637FC0C71334A0024798E /* DNBArchImpl.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = DNBArchImpl.h; sourceTree = ""; }; - 266B5ECF1460A68200E43F0A /* DNBArchImplARM64.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = DNBArchImplARM64.cpp; sourceTree = ""; }; - 266B5ED01460A68200E43F0A /* DNBArchImplARM64.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DNBArchImplARM64.h; sourceTree = ""; }; - 26C637EA0C71334A0024798E /* DNBArchImplI386.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = DNBArchImplI386.cpp; sourceTree = ""; }; - 26C637EB0C71334A0024798E /* DNBArchImplI386.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = DNBArchImplI386.h; sourceTree = ""; }; - 26CF99A21142EB7400011AAB /* DNBArchImplX86_64.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = DNBArchImplX86_64.cpp; sourceTree = ""; }; - 26CF99A31142EB7400011AAB /* DNBArchImplX86_64.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DNBArchImplX86_64.h; sourceTree = ""; }; 26C637D90C71334A0024798E /* DNBBreakpoint.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = DNBBreakpoint.cpp; sourceTree = ""; }; 26C637DA0C71334A0024798E /* DNBBreakpoint.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = DNBBreakpoint.h; sourceTree = ""; }; 26C637DB0C71334A0024798E /* DNBDataRef.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = DNBDataRef.cpp; sourceTree = ""; }; @@ -143,42 +177,14 @@ 26C637E10C71334A0024798E /* DNBLog.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = DNBLog.h; sourceTree = ""; }; 26C637E20C71334A0024798E /* DNBRegisterInfo.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = DNBRegisterInfo.cpp; sourceTree = ""; }; 26C637E30C71334A0024798E /* DNBRegisterInfo.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = DNBRegisterInfo.h; sourceTree = ""; }; - 260828DE0CBAF7F400F95054 /* DNBRuntimeAction.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DNBRuntimeAction.h; sourceTree = ""; }; - 260E7331114BFFE600D1DFB3 /* DNBThreadResumeActions.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = DNBThreadResumeActions.cpp; sourceTree = ""; }; - 260E7332114BFFE600D1DFB3 /* DNBThreadResumeActions.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DNBThreadResumeActions.h; sourceTree = ""; }; - 26A8FE1E0D11A77B00203048 /* DNBTimer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DNBTimer.h; sourceTree = ""; }; - 23AE72E21D25DECF00945BCE /* DarwinLogCollector.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = DarwinLogCollector.cpp; sourceTree = ""; }; - 23AE72E31D25DECF00945BCE /* DarwinLogCollector.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DarwinLogCollector.h; sourceTree = ""; }; - 23CF6F5E1D28A3760088ADC9 /* DarwinLogEvent.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = DarwinLogEvent.h; sourceTree = ""; }; - 23AC04CC1D2F42F10072351D /* DarwinLogInterfaces.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = DarwinLogInterfaces.h; sourceTree = ""; }; - 23562ECF1D34110D00AB2BD4 /* DarwinLogTypes.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = DarwinLogTypes.h; sourceTree = ""; }; - 49D404611E39260F00570CDC /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = System/Library/Frameworks/Foundation.framework; sourceTree = SDKROOT; }; - AFEC3363194A8B0B00FF05C6 /* Genealogy.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = Genealogy.cpp; sourceTree = ""; }; - AF0934BA18E12B92005A11FD /* Genealogy.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Genealogy.h; sourceTree = ""; }; - AF0934BB18E12B92005A11FD /* GenealogySPI.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = GenealogySPI.h; sourceTree = ""; }; - 233B4EA51D2DB54300E98261 /* JSON.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = JSON.cpp; sourceTree = ""; }; - 233B4EA61D2DB54300E98261 /* JSON.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JSON.h; sourceTree = ""; }; - 264F679A1B2F9EB200140093 /* JSONGenerator.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = JSONGenerator.h; sourceTree = ""; }; - 23AC04C41D2F41A00072351D /* LogFilter.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = LogFilter.cpp; sourceTree = ""; }; - 23AC04C51D2F41A00072351D /* LogFilter.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = LogFilter.h; sourceTree = ""; }; - 23AC04C81D2F42250072351D /* LogFilterChain.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = LogFilterChain.cpp; sourceTree = ""; }; - 23AC04C91D2F42250072351D /* LogFilterChain.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = LogFilterChain.h; sourceTree = ""; }; - 237821AE1D4917D20028B7A1 /* LogFilterExactMatch.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = LogFilterExactMatch.cpp; sourceTree = ""; }; - 237821AF1D4917D20028B7A1 /* LogFilterExactMatch.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = LogFilterExactMatch.h; sourceTree = ""; }; - 23AC04CD1D2F58AF0072351D /* LogFilterRegex.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = LogFilterRegex.cpp; sourceTree = ""; }; - 23AC04CE1D2F58AF0072351D /* LogFilterRegex.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = LogFilterRegex.h; sourceTree = ""; }; - 23562ED81D342B0000AB2BD4 /* LogMessage.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = LogMessage.cpp; sourceTree = ""; }; - 23AC04D11D2F60130072351D /* LogMessage.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = LogMessage.h; sourceTree = ""; }; - 23562ED01D3424DF00AB2BD4 /* LogMessageOsLog.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = LogMessageOsLog.cpp; sourceTree = ""; }; - 23562ED11D3424DF00AB2BD4 /* LogMessageOsLog.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = LogMessageOsLog.h; sourceTree = ""; }; + 26C637E70C71334A0024798E /* CFUtils.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = CFUtils.h; sourceTree = ""; }; + 26C637E80C71334A0024798E /* dbgnub-mig.defs */ = {isa = PBXFileReference; explicitFileType = sourcecode.mig; fileEncoding = 30; path = "dbgnub-mig.defs"; sourceTree = ""; }; + 26C637EA0C71334A0024798E /* DNBArchImplI386.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = DNBArchImplI386.cpp; sourceTree = ""; }; + 26C637EB0C71334A0024798E /* DNBArchImplI386.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = DNBArchImplI386.h; sourceTree = ""; }; 26C637EE0C71334A0024798E /* MachException.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = MachException.cpp; sourceTree = ""; }; 26C637EF0C71334A0024798E /* MachException.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = MachException.h; sourceTree = ""; }; - 26C637F10C71334A0024798E /* MachProcess.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = MachProcess.h; sourceTree = ""; }; 26C637F00C71334A0024798E /* MachProcess.mm */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.objcpp; path = MachProcess.mm; sourceTree = ""; }; - 49F530111331519C008956F6 /* MachRegisterStatesI386.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MachRegisterStatesI386.h; sourceTree = ""; }; - 49F5301213316D7F008956F6 /* MachRegisterStatesX86_64.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MachRegisterStatesX86_64.h; sourceTree = ""; }; - 26B67DE00EE9BC30006C8BC0 /* MachTask.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MachTask.h; sourceTree = ""; }; - 26B67DE10EE9BC30006C8BC0 /* MachTask.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = MachTask.mm; sourceTree = ""; }; + 26C637F10C71334A0024798E /* MachProcess.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = MachProcess.h; sourceTree = ""; }; 26C637F20C71334A0024798E /* MachThread.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = MachThread.cpp; sourceTree = ""; }; 26C637F30C71334A0024798E /* MachThread.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = MachThread.h; sourceTree = ""; }; 26C637F40C71334A0024798E /* MachThreadList.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = MachThreadList.cpp; sourceTree = ""; }; @@ -187,45 +193,35 @@ 26C637F70C71334A0024798E /* MachVMMemory.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = MachVMMemory.h; sourceTree = ""; }; 26C637F80C71334A0024798E /* MachVMRegion.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = MachVMRegion.cpp; sourceTree = ""; }; 26C637F90C71334A0024798E /* MachVMRegion.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = MachVMRegion.h; sourceTree = ""; }; - 23D1B0271D497E8B00FF831B /* OsLogger.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = OsLogger.cpp; sourceTree = ""; }; - 23D1B0281D497E8B00FF831B /* OsLogger.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OsLogger.h; sourceTree = ""; }; 26C637FD0C71334A0024798E /* PThreadCondition.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = PThreadCondition.h; sourceTree = ""; }; 26C637FE0C71334A0024798E /* PThreadEvent.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = PThreadEvent.cpp; sourceTree = ""; }; 26C637FF0C71334A0024798E /* PThreadEvent.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = PThreadEvent.h; sourceTree = ""; }; - 2672DBEE0EEF446700E92059 /* PThreadMutex.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = PThreadMutex.cpp; sourceTree = ""; }; 26C638000C71334A0024798E /* PThreadMutex.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = PThreadMutex.h; sourceTree = ""; }; - AF67ABFF0D34604D0022D128 /* PseudoTerminal.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = PseudoTerminal.cpp; sourceTree = ""; }; - AF67AC000D34604D0022D128 /* PseudoTerminal.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PseudoTerminal.h; sourceTree = ""; }; - 26A68F7E0D104EC800665A9E /* RNBContext.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = RNBContext.cpp; sourceTree = ""; }; - 26A68F7D0D104EC800665A9E /* RNBContext.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RNBContext.h; sourceTree = ""; }; - 26E6B9DA0D1329010037ECDD /* RNBDefs.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RNBDefs.h; sourceTree = ""; }; - 26A68FD60D10574500665A9E /* RNBRemote.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = RNBRemote.cpp; sourceTree = ""; }; - 26A68FD50D10574500665A9E /* RNBRemote.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RNBRemote.h; sourceTree = ""; }; - EF8878A00D9C797C001831DA /* RNBServices.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = RNBServices.cpp; sourceTree = ""; }; - EF88789F0D9C797C001831DA /* RNBServices.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RNBServices.h; sourceTree = ""; }; - 26A68FB00D1054DA00665A9E /* RNBSocket.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = RNBSocket.cpp; sourceTree = ""; }; - 26A68FAF0D1054DA00665A9E /* RNBSocket.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RNBSocket.h; sourceTree = ""; }; - D6631CA81E848FE9006A7B11 /* SocketAddress.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = SocketAddress.cpp; path = ../../source/Host/common/SocketAddress.cpp; sourceTree = ""; }; - AF48558B1D75126800D19C07 /* StdStringExtractor.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = StdStringExtractor.cpp; sourceTree = ""; }; - 233B4EA81D2DB96A00E98261 /* StringConvert.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = StringConvert.cpp; path = ../../../source/Host/common/StringConvert.cpp; sourceTree = ""; }; 26C638010C71334A0024798E /* SysSignal.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = SysSignal.cpp; sourceTree = ""; }; 26C638020C71334A0024798E /* SysSignal.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = SysSignal.h; sourceTree = ""; }; 26C638050C71334A0024798E /* TTYState.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = TTYState.cpp; sourceTree = ""; }; 26C638060C71334A0024798E /* TTYState.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = TTYState.h; sourceTree = ""; }; - 26203D1C1641EFB200A662F7 /* com.apple.debugserver.applist.internal.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = com.apple.debugserver.applist.internal.plist; sourceTree = ""; }; - EF88788B0D9C7558001831DA /* com.apple.debugserver.applist.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = com.apple.debugserver.applist.plist; sourceTree = ""; }; - 26203D1D1641EFB200A662F7 /* com.apple.debugserver.internal.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = com.apple.debugserver.internal.plist; sourceTree = ""; }; - 26A4BAED0D498B7D00A9BEAB /* com.apple.debugserver.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = com.apple.debugserver.plist; sourceTree = ""; }; - 269E8DF8164B2ED200AD65F6 /* com.apple.debugserver.posix.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = com.apple.debugserver.posix.plist; sourceTree = ""; }; - AF949ED620605DC2002A91F9 /* com.apple.internal.xpc.remote.debugserver.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = com.apple.internal.xpc.remote.debugserver.plist; sourceTree = ""; }; - 26C637E80C71334A0024798E /* dbgnub-mig.defs */ = {isa = PBXFileReference; explicitFileType = sourcecode.mig; fileEncoding = 30; path = "dbgnub-mig.defs"; sourceTree = ""; }; - 260FC7320E5B290400043FC9 /* debugnub-exports */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = "debugnub-exports"; sourceTree = SOURCE_ROOT; }; 26CE0594115C31C20022F371 /* debugserver */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = debugserver; sourceTree = BUILT_PRODUCTS_DIR; }; - 26242C390DDBD33C0054A4CC /* debugserver-entitlements.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = "debugserver-entitlements.plist"; sourceTree = ""; }; - AF61C60418F75ABC00B48D9D /* debugserver-macosx-entitlements.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = "debugserver-macosx-entitlements.plist"; sourceTree = ""; }; + 26CF99A21142EB7400011AAB /* DNBArchImplX86_64.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = DNBArchImplX86_64.cpp; sourceTree = ""; }; + 26CF99A31142EB7400011AAB /* DNBArchImplX86_64.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DNBArchImplX86_64.h; sourceTree = ""; }; + 26E6B9DA0D1329010037ECDD /* RNBDefs.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RNBDefs.h; sourceTree = ""; }; 456F67721AD46CE9002850C2 /* debugserver-nonui */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = "debugserver-nonui"; sourceTree = BUILT_PRODUCTS_DIR; }; - 26A02918114AB9240029C479 /* debugserver.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = debugserver.cpp; sourceTree = ""; }; + 49D404611E39260F00570CDC /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = System/Library/Frameworks/Foundation.framework; sourceTree = SDKROOT; }; + 49F530111331519C008956F6 /* MachRegisterStatesI386.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MachRegisterStatesI386.h; sourceTree = ""; }; + 49F5301213316D7F008956F6 /* MachRegisterStatesX86_64.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MachRegisterStatesX86_64.h; sourceTree = ""; }; 9457ECF61419864100DFE7D8 /* stack_logging.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = stack_logging.h; sourceTree = ""; }; + AF0934BA18E12B92005A11FD /* Genealogy.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Genealogy.h; sourceTree = ""; }; + AF0934BB18E12B92005A11FD /* GenealogySPI.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = GenealogySPI.h; sourceTree = ""; }; + AF48558B1D75126800D19C07 /* StdStringExtractor.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = StdStringExtractor.cpp; sourceTree = ""; }; + AF61C60418F75ABC00B48D9D /* debugserver-macosx-entitlements.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = "debugserver-macosx-entitlements.plist"; sourceTree = ""; }; + AF67ABFF0D34604D0022D128 /* PseudoTerminal.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = PseudoTerminal.cpp; sourceTree = ""; }; + AF67AC000D34604D0022D128 /* PseudoTerminal.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PseudoTerminal.h; sourceTree = ""; }; + AF949ED620605DC2002A91F9 /* com.apple.internal.xpc.remote.debugserver.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = com.apple.internal.xpc.remote.debugserver.plist; sourceTree = ""; }; + AFEC3363194A8B0B00FF05C6 /* Genealogy.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = Genealogy.cpp; sourceTree = ""; }; + D6631CA81E848FE9006A7B11 /* SocketAddress.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = SocketAddress.cpp; path = ../../source/Host/common/SocketAddress.cpp; sourceTree = ""; }; + EF88788B0D9C7558001831DA /* com.apple.debugserver.applist.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = com.apple.debugserver.applist.plist; sourceTree = ""; }; + EF88789F0D9C797C001831DA /* RNBServices.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RNBServices.h; sourceTree = ""; }; + EF8878A00D9C797C001831DA /* RNBServices.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = RNBServices.cpp; sourceTree = ""; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ @@ -409,7 +405,6 @@ 2675D41C0CCEB6CF000F49AF /* arm */, 266B5ECE1460A68200E43F0A /* arm64 */, 26C637E90C71334A0024798E /* i386 */, - 26C637FA0C71334A0024798E /* ppc */, 26CF99A11142EB7400011AAB /* x86_64 */, 26C637E80C71334A0024798E /* dbgnub-mig.defs */, AFEC3363194A8B0B00FF05C6 /* Genealogy.cpp */, @@ -446,15 +441,6 @@ path = i386; sourceTree = ""; }; - 26C637FA0C71334A0024798E /* ppc */ = { - isa = PBXGroup; - children = ( - 26C637FB0C71334A0024798E /* DNBArchImpl.cpp */, - 26C637FC0C71334A0024798E /* DNBArchImpl.h */, - ); - path = ppc; - sourceTree = ""; - }; 26CF99A11142EB7400011AAB /* x86_64 */ = { isa = PBXGroup; children = ( @@ -535,7 +521,6 @@ 08FB7793FE84155DC02AAC07 /* Project object */ = { isa = PBXProject; attributes = { - DefaultBuildSystemTypeForWorkspace = Latest; LastSwiftUpdateCheck = 0700; LastUpgradeCheck = 0720; }; @@ -618,7 +603,6 @@ 26CE05BF115C364D0022F371 /* DNBArchImplX86_64.cpp in Sources */, 26CE05C0115C364F0022F371 /* DNBArchImplI386.cpp in Sources */, 26CE05C1115C36510022F371 /* DNBArchImpl.cpp in Sources */, - 26CE05C2115C36550022F371 /* DNBArchImpl.cpp in Sources */, 26CE05C5115C36590022F371 /* CFBundle.cpp in Sources */, 26CE05C3115C36580022F371 /* CFString.cpp in Sources */, 23562ED91D342B0000AB2BD4 /* LogMessage.cpp in Sources */, @@ -669,7 +653,6 @@ 456F67601AD46CE9002850C2 /* DNBArchImpl.cpp in Sources */, 23AC04C71D2F41A00072351D /* LogFilter.cpp in Sources */, 23043C9E1D35DBFA00FC25CA /* StringConvert.cpp in Sources */, - 456F67611AD46CE9002850C2 /* DNBArchImpl.cpp in Sources */, AF588449206077BD00A0CB5A /* SocketAddress.cpp in Sources */, 456F67621AD46CE9002850C2 /* CFString.cpp in Sources */, 23AC04CB1D2F42250072351D /* LogFilterChain.cpp in Sources */, @@ -701,7 +684,7 @@ CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; CODE_SIGN_IDENTITY = ""; COPY_PHASE_STRIP = NO; - CURRENT_PROJECT_VERSION = 360.0.0; + CURRENT_PROJECT_VERSION = 360.99.0; ENABLE_STRICT_OBJC_MSGSEND = YES; GCC_NO_COMMON_BLOCKS = YES; GCC_VERSION = com.apple.compilers.llvm.clang.1_0; @@ -736,7 +719,7 @@ CLANG_WARN_INT_CONVERSION = YES; CLANG_WARN_UNREACHABLE_CODE = YES; CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; - CURRENT_PROJECT_VERSION = 360.0.0; + CURRENT_PROJECT_VERSION = 360.99.0; DEAD_CODE_STRIPPING = YES; ENABLE_STRICT_OBJC_MSGSEND = YES; GCC_NO_COMMON_BLOCKS = YES; @@ -760,202 +743,6 @@ }; name = Release; }; - 237965FC1C124395008D490F /* CustomSwift-RelWithDebInfo */ = { - isa = XCBuildConfiguration; - buildSettings = { - "ARCHS[sdk=iphoneos*]" = ( - armv7, - armv7s, - ); - "ARCHS[sdk=macosx*]" = "$(ARCHS_STANDARD_64_BIT)"; - CLANG_WARN_BOOL_CONVERSION = YES; - CLANG_WARN_CONSTANT_CONVERSION = YES; - CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES; - CLANG_WARN_EMPTY_BODY = YES; - CLANG_WARN_ENUM_CONVERSION = YES; - CLANG_WARN_INT_CONVERSION = YES; - CLANG_WARN_UNREACHABLE_CODE = YES; - CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; - COPY_PHASE_STRIP = NO; - CURRENT_PROJECT_VERSION = 360.0.0; - DEAD_CODE_STRIPPING = YES; - ENABLE_STRICT_OBJC_MSGSEND = YES; - GCC_NO_COMMON_BLOCKS = YES; - GCC_VERSION = com.apple.compilers.llvm.clang.1_0; - GCC_WARN_64_TO_32_BIT_CONVERSION = YES; - GCC_WARN_ABOUT_RETURN_TYPE = YES; - GCC_WARN_UNDECLARED_SELECTOR = YES; - GCC_WARN_UNINITIALIZED_AUTOS = YES; - GCC_WARN_UNUSED_FUNCTION = YES; - GCC_WARN_UNUSED_VARIABLE = YES; - LLDB_COMPRESSION_CFLAGS = "-DHAVE_LIBCOMPRESSION=1"; - LLDB_COMPRESSION_LDFLAGS = "-lcompression"; - LLDB_ZLIB_CFLAGS = "-DHAVE_LIBZ=1"; - LLDB_ZLIB_LDFLAGS = "-lz"; - MACOSX_DEPLOYMENT_TARGET = 10.11; - ONLY_ACTIVE_ARCH = YES; - OTHER_CFLAGS = ""; - STRIPFLAGS = ""; - STRIP_INSTALLED_PRODUCT = NO; - STRIP_STYLE = debugging; - VERSIONING_SYSTEM = "apple-generic"; - VERSION_INFO_BUILDER = "$(USER)"; - }; - name = "CustomSwift-RelWithDebInfo"; - }; - 237965FD1C124395008D490F /* CustomSwift-RelWithDebInfo */ = { - isa = XCBuildConfiguration; - buildSettings = { - CLANG_CXX_LANGUAGE_STANDARD = "c++0x"; - CLANG_CXX_LIBRARY = "libc++"; - "CODE_SIGN_ENTITLEMENTS[sdk=*]" = "source/debugserver-entitlements.plist"; - "CODE_SIGN_ENTITLEMENTS[sdk=macosx*]" = "source/debugserver-macosx-entitlements.plist"; - "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = ""; - "CODE_SIGN_IDENTITY[sdk=macosx*]" = ""; - COPY_PHASE_STRIP = YES; - CURRENT_PROJECT_VERSION = 360.0.0; - DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; - FRAMEWORK_SEARCH_PATHS = $SDKROOT/System/Library/PrivateFrameworks; - "FRAMEWORK_SEARCH_PATHS[sdk=iphoneos*][arch=*]" = ( - "$(SDKROOT)/System/Library/PrivateFrameworks", - "$(SDKROOT)/Developer/Library/PrivateFrameworks", - ); - "FRAMEWORK_SEARCH_PATHS[sdk=macosx*][arch=*]" = "$(SDKROOT)/System/Library/PrivateFrameworks"; - GCC_C_LANGUAGE_STANDARD = c99; - GCC_PREPROCESSOR_DEFINITIONS = LLDB_DEBUGSERVER_RELEASE; - GCC_VERSION = com.apple.compilers.llvm.clang.1_0; - HEADER_SEARCH_PATHS = /System/Library/Frameworks/System.framework/PrivateHeaders; - INSTALL_PATH = /usr/bin; - LLDB_COMPRESSION_CFLAGS = "-DHAVE_LIBCOMPRESSION=1"; - LLDB_COMPRESSION_LDFLAGS = "-lcompression"; - LLDB_DEBUGSERVER = 1; - LLDB_ENERGY_CFLAGS = ""; - "LLDB_ENERGY_CFLAGS[sdk=macosx.internal]" = "-DLLDB_ENERGY"; - LLDB_ENERGY_LFLAGS = "-lpmenergy -lpmsample"; - LLDB_ZLIB_CFLAGS = "-DHAVE_LIBZ=1"; - LLDB_ZLIB_LDFLAGS = "-lz"; - MACOSX_DEPLOYMENT_TARGET = 10.9; - OTHER_CFLAGS = ( - "-Wparentheses", - "$(LLDB_ENERGY_CFLAGS)", - "-DDT_VARIANT_$(DT_VARIANT)", - "$(LLDB_COMPRESSION_CFLAGS)", - "$(LLDB_ZLIB_CFLAGS)", - ); - "OTHER_CFLAGS[sdk=iphoneos*][arch=*]" = ( - "-Wparentheses", - "-DWITH_LOCKDOWN", - "-DWITH_FBS", - "-DWITH_BKS", - "-DOS_OBJECT_USE_OBJC=0", - "$(LLDB_COMPRESSION_CFLAGS)", - "$(LLDB_ZLIB_CFLAGS)", - ); - "OTHER_CPLUSPLUSFLAGS[sdk=iphoneos*][arch=*]" = "$(OTHER_CFLAGS)"; - OTHER_LDFLAGS = ""; - "OTHER_LDFLAGS[sdk=iphoneos*][arch=*]" = ( - "-framework", - SpringBoardServices, - "-framework", - BackBoardServices, - "-llockdown", - "-framework", - FrontBoardServices, - "-framework", - MobileCoreServices, - "$(LLDB_COMPRESSION_LDFLAGS)", - "$(LLDB_ZLIB_LDFLAGS)", - ); - "OTHER_LDFLAGS[sdk=macosx*]" = ( - "-sectcreate", - __TEXT, - __info_plist, - "$(PROJECT_DIR)/resources/lldb-debugserver-Info.plist", - "$(LLDB_ENERGY_LFLAGS)", - "$(LLDB_COMPRESSION_LDFLAGS)", - "$(LLDB_ZLIB_LDFLAGS)", - ); - OTHER_MIGFLAGS = "-I$(DERIVED_FILE_DIR)"; - PRODUCT_NAME = debugserver; - "PROVISIONING_PROFILE[sdk=iphoneos*]" = ""; - "PROVISIONING_PROFILE[sdk=macosx*]" = ""; - SDKROOT = macosx; - "SDKROOT[arch=i386]" = macosx; - "SDKROOT[arch=x86_64]" = macosx; - "SDKROOT[arch=x86_64h]" = macosx; - SKIP_INSTALL = YES; - USER_HEADER_SEARCH_PATHS = "./source ../../source $(DERIVED_SOURCES_DIR) ../../include"; - ZERO_LINK = NO; - }; - name = "CustomSwift-RelWithDebInfo"; - }; - 237965FE1C124395008D490F /* CustomSwift-RelWithDebInfo */ = { - isa = XCBuildConfiguration; - buildSettings = { - CLANG_CXX_LANGUAGE_STANDARD = "c++0x"; - CLANG_CXX_LIBRARY = "libc++"; - "CODE_SIGN_ENTITLEMENTS[sdk=*]" = "source/debugserver-entitlements.plist"; - "CODE_SIGN_ENTITLEMENTS[sdk=macosx*]" = "source/debugserver-macosx-entitlements.plist"; - "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = ""; - "CODE_SIGN_IDENTITY[sdk=macosx*]" = ""; - COPY_PHASE_STRIP = YES; - CURRENT_PROJECT_VERSION = 360.0.0; - DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; - FRAMEWORK_SEARCH_PATHS = $SDKROOT/System/Library/PrivateFrameworks; - "FRAMEWORK_SEARCH_PATHS[sdk=iphoneos*][arch=*]" = ( - "$(SDKROOT)/System/Library/PrivateFrameworks", - "$(SDKROOT)/Developer/Library/PrivateFrameworks", - ); - "FRAMEWORK_SEARCH_PATHS[sdk=macosx*][arch=*]" = "$(SDKROOT)/System/Library/PrivateFrameworks"; - GCC_C_LANGUAGE_STANDARD = c99; - GCC_PREPROCESSOR_DEFINITIONS = LLDB_DEBUGSERVER_RELEASE; - GCC_VERSION = com.apple.compilers.llvm.clang.1_0; - HEADER_SEARCH_PATHS = /System/Library/Frameworks/System.framework/PrivateHeaders; - INSTALL_PATH = /usr/bin; - LLDB_DEBUGSERVER = 1; - LLDB_ENERGY_CFLAGS = ""; - "LLDB_ENERGY_CFLAGS[sdk=macosx.internal]" = "-DLLDB_ENERGY"; - LLDB_ENERGY_LFLAGS = "-lpmenergy -lpmsample"; - MACOSX_DEPLOYMENT_TARGET = 10.9; - OTHER_CFLAGS = ( - "$(LLDB_COMPRESSION_CFLAGS)", - "$(LLDB_ZLIB_CFLAGS)", - ); - "OTHER_CFLAGS[sdk=iphoneos*][arch=*]" = ( - "-Wparentheses", - "-DOS_OBJECT_USE_OBJC=0", - ); - "OTHER_CPLUSPLUSFLAGS[sdk=iphoneos*][arch=*]" = "$(OTHER_CFLAGS)"; - OTHER_LDFLAGS = ""; - "OTHER_LDFLAGS[sdk=iphoneos*][arch=*]" = ( - "-framework", - Foundation, - "$(LLDB_COMPRESSION_LDFLAGS)", - "$(LLDB_ZLIB_LDFLAGS)", - ); - "OTHER_LDFLAGS[sdk=macosx*]" = ( - "-sectcreate", - __TEXT, - __info_plist, - "$(PROJECT_DIR)/resources/lldb-debugserver-Info.plist", - "$(LLDB_ENERGY_LFLAGS)", - "$(LLDB_COMPRESSION_LDFLAGS)", - "$(LLDB_ZLIB_LDFLAGS)", - ); - OTHER_MIGFLAGS = "-I$(DERIVED_FILE_DIR)"; - PRODUCT_NAME = debugserver; - "PROVISIONING_PROFILE[sdk=iphoneos*]" = ""; - "PROVISIONING_PROFILE[sdk=macosx*]" = ""; - SDKROOT = macosx; - "SDKROOT[arch=i386]" = macosx; - "SDKROOT[arch=x86_64]" = macosx; - "SDKROOT[arch=x86_64h]" = macosx; - SKIP_INSTALL = YES; - USER_HEADER_SEARCH_PATHS = "./source ../../source $(DERIVED_SOURCES_DIR) ../../include"; - ZERO_LINK = NO; - }; - name = "CustomSwift-RelWithDebInfo"; - }; 262419A11198A93E00067686 /* BuildAndIntegration */ = { isa = XCBuildConfiguration; buildSettings = { @@ -970,7 +757,7 @@ CLANG_WARN_INT_CONVERSION = YES; CLANG_WARN_UNREACHABLE_CODE = YES; CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; - CURRENT_PROJECT_VERSION = 360.0.0; + CURRENT_PROJECT_VERSION = 360.99.0; DEAD_CODE_STRIPPING = YES; ENABLE_STRICT_OBJC_MSGSEND = YES; GCC_NO_COMMON_BLOCKS = YES; @@ -1002,7 +789,7 @@ "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "-"; "CODE_SIGN_IDENTITY[sdk=macosx*]" = "-"; COPY_PHASE_STRIP = YES; - CURRENT_PROJECT_VERSION = 360.0.0; + CURRENT_PROJECT_VERSION = 360.99.0; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; FRAMEWORK_SEARCH_PATHS = $SDKROOT/System/Library/PrivateFrameworks; "FRAMEWORK_SEARCH_PATHS[sdk=iphoneos*][arch=*]" = ( @@ -1060,6 +847,8 @@ "$(PROJECT_DIR)/resources/lldb-debugserver-Info.plist", "$(LLDB_ENERGY_LDFLAGS)", "$(LLDB_COMPRESSION_LDFLAGS)", + "-framework", + Security, ); OTHER_MIGFLAGS = "-I$(DERIVED_FILE_DIR)"; PRODUCT_NAME = debugserver; @@ -1082,7 +871,7 @@ "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = ""; "CODE_SIGN_IDENTITY[sdk=macosx*]" = ""; COPY_PHASE_STRIP = YES; - CURRENT_PROJECT_VERSION = 360.0.0; + CURRENT_PROJECT_VERSION = 360.99.0; FRAMEWORK_SEARCH_PATHS = $SDKROOT/System/Library/PrivateFrameworks; "FRAMEWORK_SEARCH_PATHS[sdk=iphoneos*][arch=*]" = ( "$(SDKROOT)/System/Library/PrivateFrameworks", @@ -1139,6 +928,8 @@ "$(PROJECT_DIR)/resources/lldb-debugserver-Info.plist", "$(LLDB_ENERGY_LDFLAGS)", "$(LLDB_COMPRESSION_LDFLAGS)", + "-framework", + Security, ); OTHER_MIGFLAGS = "-I$(DERIVED_FILE_DIR)"; PRODUCT_NAME = debugserver; @@ -1161,7 +952,7 @@ "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = ""; "CODE_SIGN_IDENTITY[sdk=macosx*]" = ""; COPY_PHASE_STRIP = YES; - CURRENT_PROJECT_VERSION = 360.0.0; + CURRENT_PROJECT_VERSION = 360.99.0; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; FRAMEWORK_SEARCH_PATHS = $SDKROOT/System/Library/PrivateFrameworks; "FRAMEWORK_SEARCH_PATHS[sdk=iphoneos*][arch=*]" = ( @@ -1217,6 +1008,8 @@ "$(PROJECT_DIR)/resources/lldb-debugserver-Info.plist", "$(LLDB_ENERGY_LDFLAGS)", "$(LLDB_COMPRESSION_LDFLAGS)", + "-framework", + Security, ); OTHER_MIGFLAGS = "-I$(DERIVED_FILE_DIR)"; PRODUCT_NAME = debugserver; @@ -1248,7 +1041,7 @@ "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = ""; "CODE_SIGN_IDENTITY[sdk=macosx*]" = ""; COPY_PHASE_STRIP = NO; - CURRENT_PROJECT_VERSION = 360.0.0; + CURRENT_PROJECT_VERSION = 360.99.0; ENABLE_STRICT_OBJC_MSGSEND = YES; FRAMEWORK_SEARCH_PATHS = $SDKROOT/System/Library/PrivateFrameworks; "FRAMEWORK_SEARCH_PATHS[sdk=iphoneos*][arch=*]" = ( @@ -1327,7 +1120,7 @@ "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = ""; "CODE_SIGN_IDENTITY[sdk=macosx*]" = ""; COPY_PHASE_STRIP = YES; - CURRENT_PROJECT_VERSION = 360.0.0; + CURRENT_PROJECT_VERSION = 360.99.0; FRAMEWORK_SEARCH_PATHS = $SDKROOT/System/Library/PrivateFrameworks; "FRAMEWORK_SEARCH_PATHS[sdk=iphoneos*][arch=*]" = ( "$(SDKROOT)/System/Library/PrivateFrameworks", @@ -1344,9 +1137,7 @@ LLDB_ENERGY_CFLAGS = ""; "LLDB_ENERGY_CFLAGS[sdk=*.internal]" = "-DLLDB_ENERGY"; LLDB_ENERGY_LDFLAGS = "-lpmenergy -lpmsample"; - OTHER_CFLAGS = ( - "$(LLDB_ENERGY_CFLAGS)", - ); + OTHER_CFLAGS = "$(LLDB_ENERGY_CFLAGS)"; "OTHER_CFLAGS[sdk=iphoneos*][arch=*]" = ( "-Wparentheses", "-DOS_OBJECT_USE_OBJC=0", @@ -1390,7 +1181,7 @@ "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = ""; "CODE_SIGN_IDENTITY[sdk=macosx*]" = ""; COPY_PHASE_STRIP = YES; - CURRENT_PROJECT_VERSION = 360.0.0; + CURRENT_PROJECT_VERSION = 360.99.0; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; FRAMEWORK_SEARCH_PATHS = $SDKROOT/System/Library/PrivateFrameworks; "FRAMEWORK_SEARCH_PATHS[sdk=iphoneos*][arch=*]" = ( @@ -1457,7 +1248,7 @@ "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "-"; "CODE_SIGN_IDENTITY[sdk=macosx*]" = "-"; COPY_PHASE_STRIP = YES; - CURRENT_PROJECT_VERSION = 360.0.0; + CURRENT_PROJECT_VERSION = 360.99.0; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; FRAMEWORK_SEARCH_PATHS = $SDKROOT/System/Library/PrivateFrameworks; "FRAMEWORK_SEARCH_PATHS[sdk=iphoneos*][arch=*]" = ( @@ -1527,7 +1318,7 @@ CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; CODE_SIGN_IDENTITY = ""; COPY_PHASE_STRIP = NO; - CURRENT_PROJECT_VERSION = 360.0.0; + CURRENT_PROJECT_VERSION = 360.99.0; ENABLE_STRICT_OBJC_MSGSEND = YES; GCC_NO_COMMON_BLOCKS = YES; GCC_VERSION = com.apple.compilers.llvm.clang.1_0; @@ -1558,7 +1349,7 @@ "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = ""; "CODE_SIGN_IDENTITY[sdk=macosx*]" = ""; COPY_PHASE_STRIP = YES; - CURRENT_PROJECT_VERSION = 360.0.0; + CURRENT_PROJECT_VERSION = 360.99.0; FRAMEWORK_SEARCH_PATHS = $SDKROOT/System/Library/PrivateFrameworks; "FRAMEWORK_SEARCH_PATHS[sdk=iphoneos*][arch=*]" = ( "$(SDKROOT)/System/Library/PrivateFrameworks", @@ -1642,7 +1433,7 @@ CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; CODE_SIGN_IDENTITY = ""; COPY_PHASE_STRIP = NO; - CURRENT_PROJECT_VERSION = 360.0.0; + CURRENT_PROJECT_VERSION = 360.99.0; ENABLE_STRICT_OBJC_MSGSEND = YES; GCC_NO_COMMON_BLOCKS = YES; GCC_VERSION = com.apple.compilers.llvm.clang.1_0; @@ -1673,7 +1464,7 @@ "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = ""; "CODE_SIGN_IDENTITY[sdk=macosx*]" = ""; COPY_PHASE_STRIP = YES; - CURRENT_PROJECT_VERSION = 360.0.0; + CURRENT_PROJECT_VERSION = 360.99.0; FRAMEWORK_SEARCH_PATHS = $SDKROOT/System/Library/PrivateFrameworks; "FRAMEWORK_SEARCH_PATHS[sdk=iphoneos*][arch=*]" = ( "$(SDKROOT)/System/Library/PrivateFrameworks", @@ -1750,7 +1541,7 @@ "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = ""; "CODE_SIGN_IDENTITY[sdk=macosx*]" = ""; COPY_PHASE_STRIP = YES; - CURRENT_PROJECT_VERSION = 360.0.0; + CURRENT_PROJECT_VERSION = 360.99.0; FRAMEWORK_SEARCH_PATHS = $SDKROOT/System/Library/PrivateFrameworks; "FRAMEWORK_SEARCH_PATHS[sdk=iphoneos*][arch=*]" = ( "$(SDKROOT)/System/Library/PrivateFrameworks", @@ -1832,7 +1623,7 @@ CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; CODE_SIGN_IDENTITY = ""; COPY_PHASE_STRIP = NO; - CURRENT_PROJECT_VERSION = 360.0.0; + CURRENT_PROJECT_VERSION = 360.99.0; ENABLE_STRICT_OBJC_MSGSEND = YES; GCC_NO_COMMON_BLOCKS = YES; GCC_VERSION = com.apple.compilers.llvm.clang.1_0; @@ -1863,7 +1654,7 @@ "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = ""; "CODE_SIGN_IDENTITY[sdk=macosx*]" = ""; COPY_PHASE_STRIP = YES; - CURRENT_PROJECT_VERSION = 360.0.0; + CURRENT_PROJECT_VERSION = 360.99.0; FRAMEWORK_SEARCH_PATHS = $SDKROOT/System/Library/PrivateFrameworks; "FRAMEWORK_SEARCH_PATHS[sdk=iphoneos*][arch=*]" = ( "$(SDKROOT)/System/Library/PrivateFrameworks", @@ -1946,7 +1737,7 @@ CLANG_WARN_INT_CONVERSION = YES; CLANG_WARN_UNREACHABLE_CODE = YES; CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; - CURRENT_PROJECT_VERSION = 360.0.0; + CURRENT_PROJECT_VERSION = 360.99.0; DEAD_CODE_STRIPPING = YES; ENABLE_STRICT_OBJC_MSGSEND = YES; GCC_NO_COMMON_BLOCKS = YES; @@ -1963,7 +1754,6 @@ ONLY_ACTIVE_ARCH = YES; SDKROOT = macosx; STRIPFLAGS = "-x"; - STRIP_INSTALLED_PRODUCT = YES; STRIP_STYLE = debugging; VERSIONING_SYSTEM = "apple-generic"; VERSION_INFO_BUILDER = "$(USER)"; @@ -1980,7 +1770,7 @@ "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = ""; "CODE_SIGN_IDENTITY[sdk=macosx*]" = ""; COPY_PHASE_STRIP = YES; - CURRENT_PROJECT_VERSION = 360.0.0; + CURRENT_PROJECT_VERSION = 360.99.0; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; FRAMEWORK_SEARCH_PATHS = $SDKROOT/System/Library/PrivateFrameworks; "FRAMEWORK_SEARCH_PATHS[sdk=iphoneos*][arch=*]" = ( @@ -2059,7 +1849,6 @@ 4968B7A916657FAE00741ABB /* DebugClang */, 940AD5251B1FE3B10051E88F /* DebugPresubmission */, 1DEB915008733D8E0010E9CD /* Release */, - 237965FC1C124395008D490F /* CustomSwift-RelWithDebInfo */, 94D72C891ADF10B000A3F718 /* CustomSwift-Release */, 262419A11198A93E00067686 /* BuildAndIntegration */, ); @@ -2074,7 +1863,6 @@ 4968B7AA16657FAE00741ABB /* DebugClang */, 940AD5261B1FE3B10051E88F /* DebugPresubmission */, 26CE0597115C31C30022F371 /* Release */, - 237965FD1C124395008D490F /* CustomSwift-RelWithDebInfo */, 94D72C8A1ADF10B000A3F718 /* CustomSwift-Release */, 262419A21198A93E00067686 /* BuildAndIntegration */, ); @@ -2088,7 +1876,6 @@ 456F676F1AD46CE9002850C2 /* DebugClang */, 940AD5271B1FE3B10051E88F /* DebugPresubmission */, 456F67701AD46CE9002850C2 /* Release */, - 237965FE1C124395008D490F /* CustomSwift-RelWithDebInfo */, 456F67711AD46CE9002850C2 /* BuildAndIntegration */, 94BA9B361B1A7C5700035A23 /* CustomSwift-Debug */, 94BA9B371B1A7C5700035A23 /* CustomSwift-Release */, diff --git a/lldb/tools/debugserver/resources/lldb-debugserver-Info.plist b/lldb/tools/debugserver/resources/lldb-debugserver-Info.plist index 343325c2765cb..ddaf0644f2cf2 100644 --- a/lldb/tools/debugserver/resources/lldb-debugserver-Info.plist +++ b/lldb/tools/debugserver/resources/lldb-debugserver-Info.plist @@ -12,10 +12,5 @@ debugserver CFBundleVersion 2 - SecTaskAccess - - allowed - debug - diff --git a/lldb/tools/debugserver/source/MacOSX/MachProcess.mm b/lldb/tools/debugserver/source/MacOSX/MachProcess.mm index e4ec6129f70c5..664c5083f8756 100644 --- a/lldb/tools/debugserver/source/MacOSX/MachProcess.mm +++ b/lldb/tools/debugserver/source/MacOSX/MachProcess.mm @@ -595,6 +595,16 @@ static bool FBSAddEventDataToOptions(NSMutableDictionary *options, plo_pthread_tsd_entry_size); } +/// Determine whether this is running on macOS. +/// Since debugserver runs on the same machine as the process, we can +/// just look at the compilation target. +static bool IsMacOSHost() { +#if TARGET_OS_OSX == 1 + return true; +#else + return false; +#endif +} const char *MachProcess::GetDeploymentInfo(const struct load_command& lc, uint64_t load_command_address, @@ -616,15 +626,17 @@ static bool FBSAddEventDataToOptions(NSMutableDictionary *options, minor_version = (vers_cmd.sdk >> 8) & 0xffu; patch_version = vers_cmd.sdk & 0xffu; + // Handle the older LC_VERSION load commands, which don't + // distinguish between simulator and real hardware. switch (cmd) { case LC_VERSION_MIN_IPHONEOS: - return "ios"; + return IsMacOSHost() ? "iossimulator": "ios"; case LC_VERSION_MIN_MACOSX: return "macosx"; case LC_VERSION_MIN_TVOS: - return "tvos"; + return IsMacOSHost() ? "tvossimulator": "tvos"; case LC_VERSION_MIN_WATCHOS: - return "watchos"; + return IsMacOSHost() ? "watchossimulator" : "watchos"; default: return nullptr; } @@ -646,14 +658,17 @@ static bool FBSAddEventDataToOptions(NSMutableDictionary *options, case PLATFORM_MACCATALYST: return "maccatalyst"; case PLATFORM_IOS: - case PLATFORM_IOSSIMULATOR: return "ios"; + case PLATFORM_IOSSIMULATOR: + return "iossimulator"; case PLATFORM_TVOS: - case PLATFORM_TVOSSIMULATOR: return "tvos"; + case PLATFORM_TVOSSIMULATOR: + return "tvossimulator"; case PLATFORM_WATCHOS: - case PLATFORM_WATCHOSSIMULATOR: return "watchos"; + case PLATFORM_WATCHOSSIMULATOR: + return "watchossimulator"; case PLATFORM_BRIDGEOS: return "bridgeos"; case PLATFORM_DRIVERKIT: diff --git a/lldb/tools/debugserver/source/MacOSX/arm64/DNBArchImplARM64.cpp b/lldb/tools/debugserver/source/MacOSX/arm64/DNBArchImplARM64.cpp index f99dbc48b128e..3e7bda88e6af3 100644 --- a/lldb/tools/debugserver/source/MacOSX/arm64/DNBArchImplARM64.cpp +++ b/lldb/tools/debugserver/source/MacOSX/arm64/DNBArchImplARM64.cpp @@ -666,6 +666,112 @@ uint32_t DNBArchMachARM64::NumSupportedHardwareWatchpoints() { return g_num_supported_hw_watchpoints; } +uint32_t DNBArchMachARM64::NumSupportedHardwareBreakpoints() { + // Set the init value to something that will let us know that we need to + // autodetect how many breakpoints are supported dynamically... + static uint32_t g_num_supported_hw_breakpoints = UINT_MAX; + if (g_num_supported_hw_breakpoints == UINT_MAX) { + // Set this to zero in case we can't tell if there are any HW breakpoints + g_num_supported_hw_breakpoints = 0; + + size_t len; + uint32_t n = 0; + len = sizeof(n); + if (::sysctlbyname("hw.optional.breakpoint", &n, &len, NULL, 0) == 0) { + g_num_supported_hw_breakpoints = n; + DNBLogThreadedIf(LOG_THREAD, "hw.optional.breakpoint=%u", n); + } else { +// For AArch64 we would need to look at ID_AA64DFR0_EL1 but debugserver runs in +// EL0 so it can't access that reg. The kernel should have filled in the +// sysctls based on it though. +#if defined(__arm__) + uint32_t register_DBGDIDR; + + asm("mrc p14, 0, %0, c0, c0, 0" : "=r"(register_DBGDIDR)); + uint32_t numWRPs = bits(register_DBGDIDR, 31, 28); + // Zero is reserved for the WRP count, so don't increment it if it is zero + if (numWRPs > 0) + numWRPs++; + g_num_supported_hw_breakpoints = numWRPs; + DNBLogThreadedIf(LOG_THREAD, + "Number of supported hw breakpoint via asm(): %d", + g_num_supported_hw_breakpoints); +#endif + } + } + return g_num_supported_hw_breakpoints; +} + +uint32_t DNBArchMachARM64::EnableHardwareBreakpoint(nub_addr_t addr, + nub_size_t size, + bool also_set_on_task) { + DNBLogThreadedIf(LOG_WATCHPOINTS, + "DNBArchMachARM64::EnableHardwareBreakpoint(addr = " + "0x%8.8llx, size = %zu)", + (uint64_t)addr, size); + + const uint32_t num_hw_breakpoints = NumSupportedHardwareBreakpoints(); + + nub_addr_t aligned_bp_address = addr; + uint32_t control_value = 0; + + switch (size) { + case 2: + control_value = (0x3 << 5) | 7; + aligned_bp_address &= ~1; + break; + case 4: + control_value = (0xfu << 5) | 7; + aligned_bp_address &= ~3; + break; + }; + + // Read the debug state + kern_return_t kret = GetDBGState(false); + if (kret == KERN_SUCCESS) { + // Check to make sure we have the needed hardware support + uint32_t i = 0; + + for (i = 0; i < num_hw_breakpoints; ++i) { + if ((m_state.dbg.__bcr[i] & BCR_ENABLE) == 0) + break; // We found an available hw breakpoint slot (in i) + } + + // See if we found an available hw breakpoint slot above + if (i < num_hw_breakpoints) { + m_state.dbg.__bvr[i] = aligned_bp_address; + m_state.dbg.__bcr[i] = control_value; + + DNBLogThreadedIf(LOG_WATCHPOINTS, + "DNBArchMachARM64::EnableHardwareBreakpoint() " + "adding breakpoint on address 0x%llx with control " + "register value 0x%x", + (uint64_t)m_state.dbg.__bvr[i], + (uint32_t)m_state.dbg.__bcr[i]); + + // The kernel will set the MDE_ENABLE bit in the MDSCR_EL1 for us + // automatically, don't need to do it here. + kret = SetDBGState(also_set_on_task); + + DNBLogThreadedIf(LOG_WATCHPOINTS, + "DNBArchMachARM64::" + "EnableHardwareBreakpoint() " + "SetDBGState() => 0x%8.8x.", + kret); + + if (kret == KERN_SUCCESS) + return i; + } else { + DNBLogThreadedIf(LOG_WATCHPOINTS, + "DNBArchMachARM64::" + "EnableHardwareBreakpoint(): All " + "hardware resources (%u) are in use.", + num_hw_breakpoints); + } + } + return INVALID_NUB_HW_INDEX; +} + uint32_t DNBArchMachARM64::EnableHardwareWatchpoint(nub_addr_t addr, nub_size_t size, bool read, bool write, @@ -905,6 +1011,32 @@ bool DNBArchMachARM64::DisableHardwareWatchpoint_helper(uint32_t hw_index, return (kret == KERN_SUCCESS); } +bool DNBArchMachARM64::DisableHardwareBreakpoint(uint32_t hw_index, + bool also_set_on_task) { + kern_return_t kret = GetDBGState(false); + if (kret != KERN_SUCCESS) + return false; + + const uint32_t num_hw_points = NumSupportedHardwareBreakpoints(); + if (hw_index >= num_hw_points) + return false; + + m_disabled_breakpoints[hw_index].addr = m_state.dbg.__bvr[hw_index]; + m_disabled_breakpoints[hw_index].control = m_state.dbg.__bcr[hw_index]; + + m_state.dbg.__bcr[hw_index] = 0; + DNBLogThreadedIf(LOG_WATCHPOINTS, + "DNBArchMachARM64::" + "DisableHardwareBreakpoint( %u ) - WVR%u = " + "0x%8.8llx BCR%u = 0x%8.8llx", + hw_index, hw_index, (uint64_t)m_state.dbg.__bvr[hw_index], + hw_index, (uint64_t)m_state.dbg.__bcr[hw_index]); + + kret = SetDBGState(also_set_on_task); + + return (kret == KERN_SUCCESS); +} + // This is for checking the Byte Address Select bits in the DBRWCRn_EL1 control // register. // Returns -1 if the trailing bit patterns are not one of: @@ -935,31 +1067,34 @@ uint32_t DNBArchMachARM64::GetHardwareWatchpointHit(nub_addr_t &addr) { "DNBArchMachARM64::GetHardwareWatchpointHit() addr = 0x%llx", (uint64_t)addr); - // This is the watchpoint value to match against, i.e., word address. - nub_addr_t wp_val = addr & ~((nub_addr_t)3); if (kret == KERN_SUCCESS) { DBG &debug_state = m_state.dbg; uint32_t i, num = NumSupportedHardwareWatchpoints(); for (i = 0; i < num; ++i) { nub_addr_t wp_addr = GetWatchAddress(debug_state, i); - DNBLogThreadedIf(LOG_WATCHPOINTS, "DNBArchMachARM64::" - "GetHardwareWatchpointHit() slot: %u " - "(addr = 0x%llx).", - i, (uint64_t)wp_addr); - if (wp_val == wp_addr) { - uint32_t byte_mask = bits(debug_state.__wcr[i], 12, 5); - - // Sanity check the byte_mask, first. - if (LowestBitSet(byte_mask) < 0) - continue; - - // Check that the watchpoint is enabled. - if (!IsWatchpointEnabled(debug_state, i)) - continue; - - // Compute the starting address (from the point of view of the - // debugger). - addr = wp_addr + LowestBitSet(byte_mask); + uint32_t byte_mask = bits(debug_state.__wcr[i], 12, 5); + + DNBLogThreadedIf(LOG_WATCHPOINTS, "DNBArchImplX86_64::" + "GetHardwareWatchpointHit() slot: %u " + "(addr = 0x%llx; byte_mask = 0x%x)", + i, static_cast(wp_addr), + byte_mask); + + if (!IsWatchpointEnabled(debug_state, i)) + continue; + + if (bits(wp_addr, 48, 3) != bits(addr, 48, 3)) + continue; + + // Sanity check the byte_mask + uint32_t lsb = LowestBitSet(byte_mask); + if (lsb < 0) + continue; + + uint64_t byte_to_match = bits(addr, 2, 0); + + if (byte_mask & (1 << byte_to_match)) { + addr = wp_addr + lsb; return i; } } diff --git a/lldb/tools/debugserver/source/MacOSX/arm64/DNBArchImplARM64.h b/lldb/tools/debugserver/source/MacOSX/arm64/DNBArchImplARM64.h index 2c59a0ceb5d98..87228a15ae614 100644 --- a/lldb/tools/debugserver/source/MacOSX/arm64/DNBArchImplARM64.h +++ b/lldb/tools/debugserver/source/MacOSX/arm64/DNBArchImplARM64.h @@ -26,10 +26,12 @@ class DNBArchMachARM64 : public DNBArchProtocol { DNBArchMachARM64(MachThread *thread) : m_thread(thread), m_state(), m_disabled_watchpoints(), - m_watchpoint_hw_index(-1), m_watchpoint_did_occur(false), + m_disabled_breakpoints(), m_watchpoint_hw_index(-1), + m_watchpoint_did_occur(false), m_watchpoint_resume_single_step_enabled(false), m_saved_register_states() { m_disabled_watchpoints.resize(16); + m_disabled_breakpoints.resize(16); memset(&m_dbg_save, 0, sizeof(m_dbg_save)); } @@ -62,7 +64,13 @@ class DNBArchMachARM64 : public DNBArchProtocol { static const uint8_t *SoftwareBreakpointOpcode(nub_size_t byte_size); static uint32_t GetCPUType(); + virtual uint32_t NumSupportedHardwareBreakpoints(); virtual uint32_t NumSupportedHardwareWatchpoints(); + + virtual uint32_t EnableHardwareBreakpoint(nub_addr_t addr, nub_size_t size, + bool also_set_on_task); + virtual bool DisableHardwareBreakpoint(uint32_t hw_break_index, + bool also_set_on_task); virtual uint32_t EnableHardwareWatchpoint(nub_addr_t addr, nub_size_t size, bool read, bool write, bool also_set_on_task); @@ -229,10 +237,11 @@ class DNBArchMachARM64 : public DNBArchProtocol { State m_state; arm_debug_state64_t m_dbg_save; - // arm64 doesn't keep the disabled watchpoint values in the debug register - // context like armv7; + // arm64 doesn't keep the disabled watchpoint and breakpoint values in the + // debug register context like armv7; // we need to save them aside when we disable them temporarily. std::vector m_disabled_watchpoints; + std::vector m_disabled_breakpoints; // The following member variables should be updated atomically. int32_t m_watchpoint_hw_index; diff --git a/lldb/tools/debugserver/source/RNBRemote.cpp b/lldb/tools/debugserver/source/RNBRemote.cpp index 8eed06381d3a0..df358065f8775 100644 --- a/lldb/tools/debugserver/source/RNBRemote.cpp +++ b/lldb/tools/debugserver/source/RNBRemote.cpp @@ -3663,30 +3663,6 @@ static bool process_does_not_exist (nub_process_t pid) { return true; // process does not exist } -static bool attach_failed_due_to_sip (nub_process_t pid) { - bool retval = false; -#if defined(__APPLE__) && \ - (__ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__ >= 101000) - - // csr_check(CSR_ALLOW_TASK_FOR_PID) will be nonzero if System Integrity - // Protection is in effect. - if (csr_check(CSR_ALLOW_TASK_FOR_PID) == 0) - return false; - - if (rootless_allows_task_for_pid(pid) == 0) - retval = true; - - int csops_flags = 0; - int csops_ret = ::csops(pid, CS_OPS_STATUS, &csops_flags, - sizeof(csops_flags)); - if (csops_ret != -1 && (csops_flags & CS_RESTRICT)) { - retval = true; - } -#endif - - return retval; -} - // my_uid and process_uid are only initialized if this function // returns true -- that there was a uid mismatch -- and those // id's may want to be used in the error message. @@ -4065,13 +4041,6 @@ rnb_err_t RNBRemote::HandlePacket_v(const char *p) { "processes."); return SendPacket(return_message.c_str()); } - if (attach_failed_due_to_sip (pid_attaching_to)) { - DNBLogError("Attach failed because of SIP protection."); - std::string return_message = "E96;"; - return_message += cstring_to_asciihex_string("cannot attach " - "to process due to System Integrity Protection"); - return SendPacket(return_message.c_str()); - } } std::string error_explainer = "attach failed"; diff --git a/lldb/tools/lldb-test/SystemInitializerTest.cpp b/lldb/tools/lldb-test/SystemInitializerTest.cpp index 0d637f8dfd06a..8385653bc4197 100644 --- a/lldb/tools/lldb-test/SystemInitializerTest.cpp +++ b/lldb/tools/lldb-test/SystemInitializerTest.cpp @@ -12,7 +12,6 @@ #include "lldb/Host/Host.h" #include "lldb/Initialization/SystemInitializerCommon.h" #include "lldb/Interpreter/CommandInterpreter.h" -#include "lldb/Symbol/TypeSystemClang.h" #include "lldb/Utility/Timer.h" #include "Plugins/ABI/MacOSX-arm/ABIMacOSX_arm.h" @@ -76,6 +75,7 @@ #include "Plugins/SymbolFile/Symtab/SymbolFileSymtab.h" #include "Plugins/SymbolVendor/ELF/SymbolVendorELF.h" #include "Plugins/SystemRuntime/MacOSX/SystemRuntimeMacOSX.h" +#include "Plugins/TypeSystem/Clang/TypeSystemClang.h" #include "Plugins/UnwindAssembly/InstEmulation/UnwindAssemblyInstEmulation.h" #include "Plugins/UnwindAssembly/x86/UnwindAssembly-x86.h" diff --git a/lldb/tools/lldb-test/lldb-test.cpp b/lldb/tools/lldb-test/lldb-test.cpp index 696f64cdeff9e..0bd532fa2945a 100644 --- a/lldb/tools/lldb-test/lldb-test.cpp +++ b/lldb/tools/lldb-test/lldb-test.cpp @@ -10,6 +10,7 @@ #include "SystemInitializerTest.h" #include "Plugins/SymbolFile/DWARF/SymbolFileDWARF.h" +#include "Plugins/TypeSystem/Clang/TypeSystemClang.h" #include "lldb/Breakpoint/BreakpointLocation.h" #include "lldb/Core/Debugger.h" #include "lldb/Core/Module.h" @@ -18,7 +19,6 @@ #include "lldb/Initialization/SystemLifetimeManager.h" #include "lldb/Interpreter/CommandInterpreter.h" #include "lldb/Interpreter/CommandReturnObject.h" -#include "lldb/Symbol/TypeSystemClang.h" #include "lldb/Symbol/CompileUnit.h" #include "lldb/Symbol/LineTable.h" #include "lldb/Symbol/SymbolFile.h" diff --git a/lldb/unittests/Core/CMakeLists.txt b/lldb/unittests/Core/CMakeLists.txt index 688a39d9a10ff..688837dff3907 100644 --- a/lldb/unittests/Core/CMakeLists.txt +++ b/lldb/unittests/Core/CMakeLists.txt @@ -12,6 +12,7 @@ add_lldb_unittest(LLDBCoreTests lldbPluginSymbolFileSymtab lldbUtilityHelpers LLVMTestingSupport + lldbPluginPlatformMacOSX LINK_COMPONENTS Support ) diff --git a/lldb/unittests/DataFormatter/CMakeLists.txt b/lldb/unittests/DataFormatter/CMakeLists.txt index fc60bff058798..a2a2f7f40571b 100644 --- a/lldb/unittests/DataFormatter/CMakeLists.txt +++ b/lldb/unittests/DataFormatter/CMakeLists.txt @@ -7,6 +7,7 @@ add_lldb_unittest(LLDBFormatterTests lldbSymbol lldbTarget lldbUtility + lldbPluginPlatformMacOSX LINK_COMPONENTS Support diff --git a/lldb/unittests/Disassembler/CMakeLists.txt b/lldb/unittests/Disassembler/CMakeLists.txt index de78d12fa2faf..a178c1860658f 100644 --- a/lldb/unittests/Disassembler/CMakeLists.txt +++ b/lldb/unittests/Disassembler/CMakeLists.txt @@ -8,6 +8,7 @@ if("ARM" IN_LIST LLVM_TARGETS_TO_BUILD) lldbTarget lldbPluginDisassemblerLLVM lldbPluginProcessUtility + lldbPluginPlatformMacOSX LINK_COMPONENTS Support ${LLVM_TARGETS_TO_BUILD}) diff --git a/lldb/unittests/Expression/CMakeLists.txt b/lldb/unittests/Expression/CMakeLists.txt index 8478af1fff577..25cfd30c464e1 100644 --- a/lldb/unittests/Expression/CMakeLists.txt +++ b/lldb/unittests/Expression/CMakeLists.txt @@ -9,7 +9,9 @@ add_lldb_unittest(ExpressionTests LINK_LIBS lldbCore lldbPluginExpressionParserClang + lldbPluginTypeSystemClang lldbUtility lldbUtilityHelpers LLVMTestingSupport + lldbPluginPlatformMacOSX ) diff --git a/lldb/unittests/Expression/ClangExpressionDeclMapTest.cpp b/lldb/unittests/Expression/ClangExpressionDeclMapTest.cpp index 41a4868fa8211..7d1e0ed3b3657 100644 --- a/lldb/unittests/Expression/ClangExpressionDeclMapTest.cpp +++ b/lldb/unittests/Expression/ClangExpressionDeclMapTest.cpp @@ -7,12 +7,12 @@ //===----------------------------------------------------------------------===// #include "Plugins/ExpressionParser/Clang/ClangExpressionDeclMap.h" +#include "Plugins/ExpressionParser/Clang/ClangUtil.h" +#include "Plugins/TypeSystem/Clang/TypeSystemClang.h" #include "TestingSupport/SubsystemRAII.h" #include "TestingSupport/Symbol/ClangTestUtils.h" #include "lldb/Host/FileSystem.h" #include "lldb/Host/HostInfo.h" -#include "lldb/Symbol/TypeSystemClang.h" -#include "lldb/Symbol/ClangUtil.h" #include "lldb/lldb-defines.h" #include "gtest/gtest.h" diff --git a/lldb/unittests/Expression/DWARFExpressionTest.cpp b/lldb/unittests/Expression/DWARFExpressionTest.cpp index 8fad88a93e114..0340db2d026f8 100644 --- a/lldb/unittests/Expression/DWARFExpressionTest.cpp +++ b/lldb/unittests/Expression/DWARFExpressionTest.cpp @@ -335,3 +335,7 @@ TEST(DWARFExpression, DW_OP_convert) { t.Eval({DW_OP_const1s, 'X', DW_OP_convert, 0x1d}).takeError(), llvm::Failed()); } + +TEST(DWARFExpression, DW_OP_stack_value) { + EXPECT_THAT_EXPECTED(Evaluate({DW_OP_stack_value}), llvm::Failed()); +} diff --git a/lldb/unittests/Host/HostInfoTest.cpp b/lldb/unittests/Host/HostInfoTest.cpp index c332606a4dad2..450cb9edc5cd6 100644 --- a/lldb/unittests/Host/HostInfoTest.cpp +++ b/lldb/unittests/Host/HostInfoTest.cpp @@ -11,6 +11,7 @@ #include "TestingSupport/TestUtilities.h" #include "lldb/Host/FileSystem.h" #include "lldb/lldb-defines.h" +#include "llvm/Support/Host.h" #include "gtest/gtest.h" using namespace lldb_private; diff --git a/lldb/unittests/Interpreter/CMakeLists.txt b/lldb/unittests/Interpreter/CMakeLists.txt index 0de5b0b72488e..aef8c617676ae 100644 --- a/lldb/unittests/Interpreter/CMakeLists.txt +++ b/lldb/unittests/Interpreter/CMakeLists.txt @@ -5,4 +5,5 @@ add_lldb_unittest(InterpreterTests LINK_LIBS lldbInterpreter lldbUtilityHelpers + lldbPluginPlatformMacOSX ) diff --git a/lldb/unittests/Language/CPlusPlus/CMakeLists.txt b/lldb/unittests/Language/CPlusPlus/CMakeLists.txt index 4882eafc8d854..e65b0eeee1ea8 100644 --- a/lldb/unittests/Language/CPlusPlus/CMakeLists.txt +++ b/lldb/unittests/Language/CPlusPlus/CMakeLists.txt @@ -3,4 +3,5 @@ add_lldb_unittest(LanguageCPlusPlusTests LINK_LIBS lldbPluginCPlusPlusLanguage + lldbPluginPlatformMacOSX ) diff --git a/lldb/unittests/Language/CPlusPlus/CPlusPlusLanguageTest.cpp b/lldb/unittests/Language/CPlusPlus/CPlusPlusLanguageTest.cpp index deb6c7d54ea9f..acac55b7f3bfa 100644 --- a/lldb/unittests/Language/CPlusPlus/CPlusPlusLanguageTest.cpp +++ b/lldb/unittests/Language/CPlusPlus/CPlusPlusLanguageTest.cpp @@ -140,12 +140,20 @@ TEST(CPlusPlusLanguage, ExtractContextAndIdentifier) { "std::vector>", "_M_emplace_back_aux"}, {"`anonymous namespace'::foo", "`anonymous namespace'", "foo"}, - {"`operator<'::`2'::B<0>::operator>", - "`operator<'::`2'::B<0>", + {"`operator<'::`2'::B<0>::operator>", "`operator<'::`2'::B<0>", "operator>"}, {"`anonymous namespace'::S::<<::__l2::Foo", - "`anonymous namespace'::S::<<::__l2", - "Foo"}}; + "`anonymous namespace'::S::<<::__l2", "Foo"}, + // These cases are idiosyncratic in how clang generates debug info for + // names when we have template parameters. They are not valid C++ names + // but if we fix this we need to support them for older compilers. + {"A::operator>", "A", "operator>"}, + {"operator>", "", "operator>"}, + {"A::operator<", "A", "operator<"}, + {"operator<", "", "operator<"}, + {"A::operator<<", "A", "operator<<"}, + {"operator<<", "", "operator<<"}, + }; llvm::StringRef context, basename; for (const auto &test : test_cases) { @@ -169,6 +177,12 @@ TEST(CPlusPlusLanguage, ExtractContextAndIdentifier) { "abc::", context, basename)); EXPECT_FALSE(CPlusPlusLanguage::ExtractContextAndIdentifier( "f>", context, basename)); + + // We expect these cases to fail until we turn on C++2a + EXPECT_FALSE(CPlusPlusLanguage::ExtractContextAndIdentifier( + "A::operator<=>", context, basename)); + EXPECT_FALSE(CPlusPlusLanguage::ExtractContextAndIdentifier( + "operator<=>", context, basename)); } static std::set FindAlternate(llvm::StringRef Name) { diff --git a/lldb/unittests/Language/Highlighting/CMakeLists.txt b/lldb/unittests/Language/Highlighting/CMakeLists.txt index 576f8dff10f03..58221360b467e 100644 --- a/lldb/unittests/Language/Highlighting/CMakeLists.txt +++ b/lldb/unittests/Language/Highlighting/CMakeLists.txt @@ -5,4 +5,5 @@ add_lldb_unittest(HighlighterTests lldbPluginCPlusPlusLanguage lldbPluginObjCLanguage lldbPluginObjCPlusPlusLanguage + lldbPluginPlatformMacOSX ) diff --git a/lldb/unittests/ObjectFile/ELF/CMakeLists.txt b/lldb/unittests/ObjectFile/ELF/CMakeLists.txt index 4c59ca109a57e..cd6b55012c662 100644 --- a/lldb/unittests/ObjectFile/ELF/CMakeLists.txt +++ b/lldb/unittests/ObjectFile/ELF/CMakeLists.txt @@ -7,6 +7,7 @@ add_lldb_unittest(ObjectFileELFTests lldbCore lldbUtilityHelpers LLVMTestingSupport + lldbPluginPlatformMacOSX ) set(test_inputs diff --git a/lldb/unittests/ObjectFile/PECOFF/CMakeLists.txt b/lldb/unittests/ObjectFile/PECOFF/CMakeLists.txt index 3ce5a7b9739cc..da9456e811977 100644 --- a/lldb/unittests/ObjectFile/PECOFF/CMakeLists.txt +++ b/lldb/unittests/ObjectFile/PECOFF/CMakeLists.txt @@ -5,4 +5,5 @@ add_lldb_unittest(ObjectFilePECOFFTests lldbUtilityHelpers lldbPluginObjectFilePECOFF LLVMTestingSupport + lldbPluginPlatformMacOSX ) diff --git a/lldb/unittests/Platform/PlatformDarwinTest.cpp b/lldb/unittests/Platform/PlatformDarwinTest.cpp index 476848d6881f8..74ad2318ecffd 100644 --- a/lldb/unittests/Platform/PlatformDarwinTest.cpp +++ b/lldb/unittests/Platform/PlatformDarwinTest.cpp @@ -18,10 +18,9 @@ using namespace lldb; using namespace lldb_private; struct PlatformDarwinTester : public PlatformDarwin { - static bool SDKSupportsModules(SDKType desired_type, - const lldb_private::FileSpec &sdk_path) { - return PlatformDarwin::SDKSupportsModules(desired_type, sdk_path); - } +public: + using PlatformDarwin::FindComponentInPath; + using PlatformDarwin::FindXcodeContentsDirectoryInPath; }; TEST(PlatformDarwinTest, TestParseVersionBuildDir) { @@ -50,22 +49,59 @@ TEST(PlatformDarwinTest, TestParseVersionBuildDir) { std::tie(V, D) = PlatformDarwin::ParseVersionBuildDir("3.4.5"); EXPECT_EQ(llvm::VersionTuple(3, 4, 5), V); +} + +TEST(PlatformDarwinTest, FindXcodeContentsDirectoryInPath) { + std::string standard = + "/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/" + "Developer/SDKs/MacOSX.sdk"; + EXPECT_EQ("/Applications/Xcode.app/Contents", + PlatformDarwinTester::FindXcodeContentsDirectoryInPath(standard)); + + std::string standard_version = + "/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/" + "Developer/SDKs/MacOSX10.15.sdk"; + EXPECT_EQ( + "/Applications/Xcode.app/Contents", + PlatformDarwinTester::FindXcodeContentsDirectoryInPath(standard_version)); + + std::string beta = "/Applications/Xcode-beta.app/Contents/Developer/" + "Platforms/MacOSX.platform/" + "Developer/SDKs/MacOSX10.15.sdk"; + EXPECT_EQ("/Applications/Xcode-beta.app/Contents", + PlatformDarwinTester::FindXcodeContentsDirectoryInPath(beta)); + + std::string no_app = + "/Applications/Xcode/Contents/Developer/Platforms/MacOSX.platform/" + "Developer/SDKs/MacOSX10.15.sdk"; + EXPECT_EQ("", PlatformDarwinTester::FindXcodeContentsDirectoryInPath(no_app)); + + std::string no_contents = + "/Applications/Xcode.app/Developer/Platforms/MacOSX.platform/" + "Developer/SDKs/MacOSX10.15.sdk"; + EXPECT_EQ( + "", PlatformDarwinTester::FindXcodeContentsDirectoryInPath(no_contents)); + + std::string no_capitalization = + "/Applications/Xcode.app/contents/Developer/Platforms/MacOSX.platform/" + "Developer/SDKs/MacOSX10.15.sdk"; + EXPECT_EQ("", PlatformDarwinTester::FindXcodeContentsDirectoryInPath( + no_capitalization)); +} + +TEST(PlatformDarwinTest, FindComponentInPath) { + EXPECT_EQ("/path/to/foo", + PlatformDarwinTester::FindComponentInPath("/path/to/foo/", "foo")); + + EXPECT_EQ("/path/to/foo", + PlatformDarwinTester::FindComponentInPath("/path/to/foo", "foo")); + + EXPECT_EQ("/path/to/foobar", PlatformDarwinTester::FindComponentInPath( + "/path/to/foobar", "foo")); + + EXPECT_EQ("/path/to/foobar", PlatformDarwinTester::FindComponentInPath( + "/path/to/foobar", "bar")); - std::string base = "/Applications/Xcode.app/Contents/Developer/Platforms/"; - EXPECT_TRUE(PlatformDarwinTester::SDKSupportsModules( - PlatformDarwin::SDKType::iPhoneSimulator, - FileSpec( - base + - "iPhoneSimulator.platform/Developer/SDKs/iPhoneSimulator12.0.sdk"))); - EXPECT_FALSE(PlatformDarwinTester::SDKSupportsModules( - PlatformDarwin::SDKType::iPhoneSimulator, - FileSpec( - base + - "iPhoneSimulator.platform/Developer/SDKs/iPhoneSimulator7.2.sdk"))); - EXPECT_TRUE(PlatformDarwinTester::SDKSupportsModules( - PlatformDarwin::SDKType::MacOSX, - FileSpec(base + "MacOSX.platform/Developer/SDKs/MacOSX10.10.sdk"))); - EXPECT_FALSE(PlatformDarwinTester::SDKSupportsModules( - PlatformDarwin::SDKType::MacOSX, - FileSpec(base + "MacOSX.platform/Developer/SDKs/MacOSX10.9.sdk"))); + EXPECT_EQ("", + PlatformDarwinTester::FindComponentInPath("/path/to/foo", "bar")); } diff --git a/lldb/unittests/Process/minidump/CMakeLists.txt b/lldb/unittests/Process/minidump/CMakeLists.txt index ad5f188314715..949be923e6f5b 100644 --- a/lldb/unittests/Process/minidump/CMakeLists.txt +++ b/lldb/unittests/Process/minidump/CMakeLists.txt @@ -10,6 +10,7 @@ add_lldb_unittest(LLDBMinidumpTests lldbPluginProcessMinidump lldbUtilityHelpers LLVMTestingSupport + lldbPluginPlatformMacOSX LINK_COMPONENTS ObjectYAML Support diff --git a/lldb/unittests/ScriptInterpreter/Python/CMakeLists.txt b/lldb/unittests/ScriptInterpreter/Python/CMakeLists.txt index 471f4c6dbc354..f024e2043a73d 100644 --- a/lldb/unittests/ScriptInterpreter/Python/CMakeLists.txt +++ b/lldb/unittests/ScriptInterpreter/Python/CMakeLists.txt @@ -6,6 +6,7 @@ add_lldb_unittest(ScriptInterpreterPythonTests lldbHost lldbPluginScriptInterpreterPython LLVMTestingSupport + lldbPluginPlatformMacOSX LINK_COMPONENTS Support - ) \ No newline at end of file + ) diff --git a/lldb/unittests/Symbol/CMakeLists.txt b/lldb/unittests/Symbol/CMakeLists.txt index 18d44f6005116..06489df0d3300 100644 --- a/lldb/unittests/Symbol/CMakeLists.txt +++ b/lldb/unittests/Symbol/CMakeLists.txt @@ -5,6 +5,7 @@ add_lldb_unittest(SymbolTests TestClangASTImporter.cpp TestDWARFCallFrameInfo.cpp TestType.cpp + TestTypeSystemSwiftTypeRef.cpp TestSwiftASTContext.cpp TestLineEntry.cpp @@ -16,6 +17,8 @@ add_lldb_unittest(SymbolTests lldbPluginObjectFileMachO lldbPluginSymbolFileDWARF lldbPluginSymbolFileSymtab + lldbPluginTypeSystemClang + lldbPluginPlatformMacOSX LLVMTestingSupport ) diff --git a/lldb/unittests/Symbol/TestClangASTImporter.cpp b/lldb/unittests/Symbol/TestClangASTImporter.cpp index e3bf13eb068e7..bf9a25c91cb6a 100644 --- a/lldb/unittests/Symbol/TestClangASTImporter.cpp +++ b/lldb/unittests/Symbol/TestClangASTImporter.cpp @@ -8,14 +8,14 @@ #include "gtest/gtest.h" +#include "Plugins/ExpressionParser/Clang/ClangASTImporter.h" +#include "Plugins/ExpressionParser/Clang/ClangASTMetadata.h" +#include "Plugins/ExpressionParser/Clang/ClangUtil.h" +#include "Plugins/TypeSystem/Clang/TypeSystemClang.h" #include "TestingSupport/SubsystemRAII.h" #include "TestingSupport/Symbol/ClangTestUtils.h" #include "lldb/Host/FileSystem.h" #include "lldb/Host/HostInfo.h" -#include "lldb/Symbol/TypeSystemClang.h" -#include "lldb/Symbol/ClangASTImporter.h" -#include "lldb/Symbol/ClangASTMetadata.h" -#include "lldb/Symbol/ClangUtil.h" #include "lldb/Symbol/Declaration.h" #include "clang/AST/DeclCXX.h" diff --git a/lldb/unittests/Symbol/TestLineEntry.cpp b/lldb/unittests/Symbol/TestLineEntry.cpp index 0dbfb65815151..d058b4f3d0430 100644 --- a/lldb/unittests/Symbol/TestLineEntry.cpp +++ b/lldb/unittests/Symbol/TestLineEntry.cpp @@ -14,9 +14,9 @@ #include "Plugins/ObjectFile/Mach-O/ObjectFileMachO.h" #include "Plugins/SymbolFile/DWARF/DWARFASTParserClang.h" #include "Plugins/SymbolFile/DWARF/SymbolFileDWARF.h" +#include "Plugins/TypeSystem/Clang/TypeSystemClang.h" #include "TestingSupport/SubsystemRAII.h" #include "TestingSupport/TestUtilities.h" -#include "lldb/Symbol/TypeSystemClang.h" #include "lldb/Core/Module.h" #include "lldb/Host/FileSystem.h" diff --git a/lldb/unittests/Symbol/TestTypeSystemClang.cpp b/lldb/unittests/Symbol/TestTypeSystemClang.cpp index a9580e43c243d..8b716be955e80 100644 --- a/lldb/unittests/Symbol/TestTypeSystemClang.cpp +++ b/lldb/unittests/Symbol/TestTypeSystemClang.cpp @@ -6,12 +6,12 @@ // //===----------------------------------------------------------------------===// +#include "Plugins/ExpressionParser/Clang/ClangUtil.h" +#include "Plugins/TypeSystem/Clang/TypeSystemClang.h" #include "TestingSupport/SubsystemRAII.h" #include "TestingSupport/Symbol/ClangTestUtils.h" #include "lldb/Host/FileSystem.h" #include "lldb/Host/HostInfo.h" -#include "lldb/Symbol/TypeSystemClang.h" -#include "lldb/Symbol/ClangUtil.h" #include "lldb/Symbol/Declaration.h" #include "clang/AST/DeclCXX.h" #include "clang/AST/ExprCXX.h" diff --git a/lldb/unittests/Symbol/TestTypeSystemSwiftTypeRef.cpp b/lldb/unittests/Symbol/TestTypeSystemSwiftTypeRef.cpp new file mode 100644 index 0000000000000..6b81b9f110c97 --- /dev/null +++ b/lldb/unittests/Symbol/TestTypeSystemSwiftTypeRef.cpp @@ -0,0 +1,243 @@ +//===-- TestTypeSystemSwiftTypeRef.cpp ------------------------------------===// +// +// This source file is part of the Swift.org open source project +// +// Copyright (c) 2014 - 2020 Apple Inc. and the Swift project authors +// Licensed under Apache License v2.0 with Runtime Library Exception +// +// See https://swift.org/LICENSE.txt for license information +// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors +// +//===----------------------------------------------------------------------===// + +#include "gtest/gtest.h" + +#include "lldb/Symbol/SwiftASTContext.h" +#include "swift/Demangling/Demangle.h" +#include "swift/Demangling/Demangler.h" +#include "swift/Strings.h" + +using namespace lldb; +using namespace lldb_private; +using namespace llvm; + +struct TestTypeSystemSwiftTypeRef : public testing::Test { + TypeSystemSwiftTypeRef m_swift_ts = TypeSystemSwiftTypeRef(nullptr); + + CompilerType GetCompilerType(std::string mangled_name) { + ConstString internalized(mangled_name); + return m_swift_ts.GetTypeFromMangledTypename(internalized); + } +}; + +/// Helper class to conveniently construct demangle tree hierarchies. +class NodeBuilder { + using NodePointer = swift::Demangle::NodePointer; + using Kind = swift::Demangle::Node::Kind; + + swift::Demangle::Demangler &m_dem; + +public: + NodeBuilder(swift::Demangle::Demangler &dem) : m_dem(dem) {} + NodePointer Node(Kind kind, StringRef text) { + return m_dem.createNode(kind, text); + } + NodePointer Node(Kind kind, NodePointer child0 = nullptr, + NodePointer child1 = nullptr, + NodePointer child2 = nullptr, + NodePointer child3 = nullptr) { + NodePointer node = m_dem.createNode(kind); + + if (child0) + node->addChild(child0, m_dem); + if (child1) + node->addChild(child1, m_dem); + if (child2) + node->addChild(child2, m_dem); + if (child3) + node->addChild(child3, m_dem); + return node; + } + NodePointer IntType() { + return Node( + Node::Kind::Type, + Node(Node::Kind::Structure, + Node(Node::Kind::Module, swift::STDLIB_NAME), + Node(Node::Kind::Identifier, swift::BUILTIN_TYPE_NAME_INT))); + } + NodePointer GlobalTypeMangling(NodePointer type) { + assert(type && type->getKind() == Node::Kind::Type); + return Node(Node::Kind::Global, Node(Node::Kind::TypeMangling, type)); + } + NodePointer GlobalType(NodePointer type) { + assert(type && type->getKind() != Node::Kind::Type && + type->getKind() != Node::Kind::TypeMangling && + type->getKind() != Node::Kind::Global); + return GlobalTypeMangling(Node(Node::Kind::Type, type)); + } + + std::string Mangle(NodePointer node) { return mangleNode(node); } +}; + +TEST_F(TestTypeSystemSwiftTypeRef, Array) { + using namespace swift::Demangle; + Demangler dem; + NodeBuilder b(dem); + NodePointer n = b.GlobalType( + b.Node(Node::Kind::BoundGenericStructure, + b.Node(Node::Kind::Type, + b.Node(Node::Kind::Structure, + b.Node(Node::Kind::Module, swift::STDLIB_NAME), + b.Node(Node::Kind::Identifier, "Array"))), + b.Node(Node::Kind::TypeList, b.IntType()))); + CompilerType int_array = GetCompilerType(b.Mangle(n)); + ASSERT_TRUE(int_array.IsArrayType(nullptr, nullptr, nullptr)); +} + +TEST_F(TestTypeSystemSwiftTypeRef, Function) { + using namespace swift::Demangle; + Demangler dem; + NodeBuilder b(dem); + NodePointer int_node = b.GlobalTypeMangling(b.IntType()); + CompilerType int_type = GetCompilerType(b.Mangle(int_node)); + NodePointer void_node = b.GlobalType(b.Node(Node::Kind::Tuple)); + CompilerType void_type = GetCompilerType(b.Mangle(void_node)); + { + NodePointer n = b.GlobalType( + b.Node(Node::Kind::FunctionType, + b.Node(Node::Kind::ArgumentTuple, + b.Node(Node::Kind::Type, b.Node(Node::Kind::Tuple))), + b.Node(Node::Kind::ReturnType, + b.Node(Node::Kind::Type, b.Node(Node::Kind::Tuple))))); + CompilerType void_void = GetCompilerType(b.Mangle(n)); + ASSERT_TRUE(void_void.IsFunctionType(nullptr)); + ASSERT_TRUE(void_void.IsFunctionPointerType()); + ASSERT_EQ(void_void.GetNumberOfFunctionArguments(), 0); + } + { + NodePointer n = b.GlobalType( + b.Node(Node::Kind::ImplFunctionType, b.Node(Node::Kind::ImplEscaping), + b.Node(Node::Kind::ImplConvention, "@callee_guaranteed"))); + CompilerType impl_void_void = GetCompilerType(b.Mangle(n)); + ASSERT_TRUE(impl_void_void.IsFunctionType(nullptr)); + ASSERT_EQ(impl_void_void.GetNumberOfFunctionArguments(), 0); + } + { + NodePointer n = b.GlobalType(b.Node( + Node::Kind::ImplFunctionType, b.Node(Node::Kind::ImplEscaping), + b.Node(Node::Kind::ImplConvention, "@callee_guaranteed"), + b.Node(Node::Kind::ImplParameter, + b.Node(Node::Kind::ImplConvention, "@unowned"), b.IntType()), + b.Node(Node::Kind::ImplParameter, + b.Node(Node::Kind::ImplConvention, "@unowned"), + b.Node(Node::Kind::Tuple)))); + CompilerType impl_two_args = GetCompilerType(b.Mangle(n)); + ASSERT_TRUE(impl_two_args.IsFunctionType(nullptr)); + ASSERT_EQ(impl_two_args.GetNumberOfFunctionArguments(), 2); + ASSERT_EQ(impl_two_args.GetFunctionArgumentAtIndex(0), int_type); + ASSERT_EQ(impl_two_args.GetFunctionArgumentAtIndex(1), void_type); + ASSERT_EQ(impl_two_args.GetFunctionArgumentTypeAtIndex(0), int_type); + ASSERT_EQ(impl_two_args.GetFunctionArgumentTypeAtIndex(1), void_type); + ASSERT_EQ(impl_two_args.GetFunctionReturnType(), void_type); + } + { + NodePointer n = b.GlobalType(b.Node( + Node::Kind::FunctionType, + b.Node(Node::Kind::ArgumentTuple, + b.Node(Node::Kind::Type, + b.Node(Node::Kind::Tuple, + b.Node(Node::Kind::TupleElement, b.IntType()), + b.Node(Node::Kind::TupleElement, + b.Node(Node::Kind::Tuple))))), + b.Node(Node::Kind::ReturnType, + b.Node(Node::Kind::Type, b.Node(Node::Kind::Tuple))))); + CompilerType two_args = GetCompilerType(b.Mangle(n)); + ASSERT_TRUE(two_args.IsFunctionType(nullptr)); + ASSERT_EQ(two_args.GetNumberOfFunctionArguments(), 2); + ASSERT_EQ(two_args.GetFunctionArgumentAtIndex(0), int_type); + ASSERT_EQ(two_args.GetFunctionArgumentAtIndex(1), void_type); + ASSERT_EQ(two_args.GetFunctionArgumentTypeAtIndex(0), int_type); + ASSERT_EQ(two_args.GetFunctionArgumentTypeAtIndex(1), void_type); + ASSERT_EQ(two_args.GetFunctionReturnType(), void_type); + } + { + NodePointer n = b.GlobalType(b.Node( + Node::Kind::FunctionType, + b.Node(Node::Kind::ArgumentTuple, + b.Node(Node::Kind::Type, b.Node(Node::Kind::Tuple))), + b.Node(Node::Kind::ReturnType, b.Node(Node::Kind::Type, b.IntType())))); + CompilerType void_int = GetCompilerType(b.Mangle(n)); + ASSERT_TRUE(void_int.IsFunctionType(nullptr)); + ASSERT_EQ(void_int.GetFunctionReturnType(), int_type); + } + { + NodePointer n = b.GlobalType(b.Node( + Node::Kind::ImplFunctionType, b.Node(Node::Kind::ImplEscaping), + b.Node(Node::Kind::ImplConvention, "@callee_guaranteed"), + b.Node(Node::Kind::ImplResult, + b.Node(Node::Kind::ImplConvention, "@unowned"), b.IntType()))); + CompilerType impl_void_int = GetCompilerType(b.Mangle(n)); + ASSERT_TRUE(impl_void_int.IsFunctionType(nullptr)); + ASSERT_EQ(impl_void_int.GetFunctionReturnType(), int_type); + } +} + +TEST_F(TestTypeSystemSwiftTypeRef, Pointer) { + using namespace swift::Demangle; + Demangler dem; + NodeBuilder b(dem); + { + NodePointer n = b.GlobalType(b.Node(Node::Kind::BuiltinTypeName, + swift::BUILTIN_TYPE_NAME_RAWPOINTER)); + CompilerType p = GetCompilerType(b.Mangle(n)); + ASSERT_TRUE(p.IsPointerType(nullptr)); + } + { + NodePointer n = + b.GlobalType(b.Node(Node::Kind::BuiltinTypeName, + swift::BUILTIN_TYPE_NAME_UNSAFEVALUEBUFFER)); + CompilerType p = GetCompilerType(b.Mangle(n)); + ASSERT_TRUE(p.IsPointerType(nullptr)); + } + { + NodePointer n = b.GlobalType(b.Node(Node::Kind::BuiltinTypeName, + swift::BUILTIN_TYPE_NAME_NATIVEOBJECT)); + CompilerType p = GetCompilerType(b.Mangle(n)); + ASSERT_TRUE(p.IsPointerType(nullptr)); + } + { + NodePointer n = b.GlobalType(b.Node(Node::Kind::BuiltinTypeName, + swift::BUILTIN_TYPE_NAME_BRIDGEOBJECT)); + CompilerType p = GetCompilerType(b.Mangle(n)); + ASSERT_TRUE(p.IsPointerType(nullptr)); + } +} + +TEST_F(TestTypeSystemSwiftTypeRef, Void) { + using namespace swift::Demangle; + Demangler dem; + NodeBuilder b(dem); + { + NodePointer n = b.GlobalType(b.Node(Node::Kind::Tuple)); + CompilerType v = GetCompilerType(b.Mangle(n)); + ASSERT_TRUE(v.IsVoidType()); + } +} + +TEST_F(TestTypeSystemSwiftTypeRef, Reference) { + using namespace swift::Demangle; + Demangler dem; + NodeBuilder b(dem); + { + NodePointer n = b.GlobalType(b.Node(Node::Kind::InOut, b.IntType())); + CompilerType ref = GetCompilerType(b.Mangle(n)); + ASSERT_TRUE(ref.IsReferenceType(nullptr, nullptr)); + CompilerType pointee; + bool is_rvalue = true; + ASSERT_TRUE(ref.IsReferenceType(&pointee, &is_rvalue)); + NodePointer int_node = b.GlobalTypeMangling(b.IntType()); + CompilerType int_type = GetCompilerType(b.Mangle(int_node)); + ASSERT_EQ(int_type, pointee); + ASSERT_FALSE(is_rvalue); + } +} diff --git a/lldb/unittests/SymbolFile/DWARF/CMakeLists.txt b/lldb/unittests/SymbolFile/DWARF/CMakeLists.txt index 57ee46316e03f..cbbf17042109d 100644 --- a/lldb/unittests/SymbolFile/DWARF/CMakeLists.txt +++ b/lldb/unittests/SymbolFile/DWARF/CMakeLists.txt @@ -9,7 +9,9 @@ add_lldb_unittest(SymbolFileDWARFTests lldbPluginObjectFilePECOFF lldbPluginSymbolFileDWARF lldbPluginSymbolFilePDB + lldbPluginTypeSystemClang lldbUtilityHelpers + lldbPluginPlatformMacOSX LINK_COMPONENTS Support DebugInfoPDB diff --git a/lldb/unittests/SymbolFile/DWARF/SymbolFileDWARFTests.cpp b/lldb/unittests/SymbolFile/DWARF/SymbolFileDWARFTests.cpp index 2ee89519b19ff..065efedc70226 100644 --- a/lldb/unittests/SymbolFile/DWARF/SymbolFileDWARFTests.cpp +++ b/lldb/unittests/SymbolFile/DWARF/SymbolFileDWARFTests.cpp @@ -20,6 +20,7 @@ #include "Plugins/SymbolFile/DWARF/DWARFDebugAbbrev.h" #include "Plugins/SymbolFile/DWARF/SymbolFileDWARF.h" #include "Plugins/SymbolFile/PDB/SymbolFilePDB.h" +#include "Plugins/TypeSystem/Clang/TypeSystemClang.h" #include "TestingSupport/SubsystemRAII.h" #include "TestingSupport/TestUtilities.h" #include "lldb/Core/Address.h" @@ -27,7 +28,6 @@ #include "lldb/Core/ModuleSpec.h" #include "lldb/Host/FileSystem.h" #include "lldb/Host/HostInfo.h" -#include "lldb/Symbol/TypeSystemClang.h" #include "lldb/Symbol/CompileUnit.h" #include "lldb/Symbol/LineTable.h" #include "lldb/Utility/ArchSpec.h" @@ -35,8 +35,6 @@ #include "lldb/Utility/FileSpec.h" #include "lldb/Utility/StreamString.h" - - using namespace lldb; using namespace lldb_private; diff --git a/lldb/unittests/SymbolFile/NativePDB/CMakeLists.txt b/lldb/unittests/SymbolFile/NativePDB/CMakeLists.txt index b82199f21dde6..9f477914fa612 100644 --- a/lldb/unittests/SymbolFile/NativePDB/CMakeLists.txt +++ b/lldb/unittests/SymbolFile/NativePDB/CMakeLists.txt @@ -7,6 +7,7 @@ add_lldb_unittest(SymbolFileNativePDBTests lldbSymbol lldbPluginSymbolFileNativePDB lldbUtilityHelpers + lldbPluginPlatformMacOSX LINK_COMPONENTS Support DebugInfoPDB diff --git a/lldb/unittests/SymbolFile/PDB/CMakeLists.txt b/lldb/unittests/SymbolFile/PDB/CMakeLists.txt index 75e4b50424966..8fc2167ee6ba2 100644 --- a/lldb/unittests/SymbolFile/PDB/CMakeLists.txt +++ b/lldb/unittests/SymbolFile/PDB/CMakeLists.txt @@ -8,6 +8,7 @@ add_lldb_unittest(SymbolFilePDBTests lldbPluginObjectFilePECOFF lldbPluginSymbolFileDWARF lldbPluginSymbolFilePDB + lldbPluginTypeSystemClang lldbUtilityHelpers LLVMTestingSupport LINK_COMPONENTS diff --git a/lldb/unittests/SymbolFile/PDB/SymbolFilePDBTests.cpp b/lldb/unittests/SymbolFile/PDB/SymbolFilePDBTests.cpp index 73eef664c2b89..be3781b37f6bf 100644 --- a/lldb/unittests/SymbolFile/PDB/SymbolFilePDBTests.cpp +++ b/lldb/unittests/SymbolFile/PDB/SymbolFilePDBTests.cpp @@ -18,13 +18,13 @@ #include "Plugins/ObjectFile/PECOFF/ObjectFilePECOFF.h" #include "Plugins/SymbolFile/DWARF/SymbolFileDWARF.h" #include "Plugins/SymbolFile/PDB/SymbolFilePDB.h" +#include "Plugins/TypeSystem/Clang/TypeSystemClang.h" #include "TestingSupport/TestUtilities.h" #include "lldb/Core/Address.h" #include "lldb/Core/Module.h" #include "lldb/Core/ModuleSpec.h" #include "lldb/Host/FileSystem.h" #include "lldb/Host/HostInfo.h" -#include "lldb/Symbol/TypeSystemClang.h" #include "lldb/Symbol/CompileUnit.h" #include "lldb/Symbol/LineTable.h" #include "lldb/Symbol/TypeMap.h" diff --git a/lldb/unittests/Target/CMakeLists.txt b/lldb/unittests/Target/CMakeLists.txt index 4694139369d31..cc0537bb46227 100644 --- a/lldb/unittests/Target/CMakeLists.txt +++ b/lldb/unittests/Target/CMakeLists.txt @@ -15,6 +15,7 @@ add_lldb_unittest(TargetTests lldbSymbol lldbUtility lldbUtilityHelpers + lldbPluginPlatformMacOSX LINK_COMPONENTS Support ) diff --git a/lldb/unittests/Target/StackFrameRecognizerTest.cpp b/lldb/unittests/Target/StackFrameRecognizerTest.cpp index f7b7829e2bb8d..067a56a19902b 100644 --- a/lldb/unittests/Target/StackFrameRecognizerTest.cpp +++ b/lldb/unittests/Target/StackFrameRecognizerTest.cpp @@ -76,8 +76,7 @@ TEST_F(StackFrameRecognizerTest, NullModuleRegex) { bool any_printed = false; StackFrameRecognizerManager::ForEach( [&any_printed](uint32_t recognizer_id, std::string name, - std::string function, std::string symbol, - std::string alternate_symbol, + std::string function, llvm::ArrayRef symbols, bool regexp) { any_printed = true; }); EXPECT_TRUE(any_printed); diff --git a/lldb/unittests/TestingSupport/Symbol/ClangTestUtils.h b/lldb/unittests/TestingSupport/Symbol/ClangTestUtils.h index 9ee657d3a5338..896996512fcf7 100644 --- a/lldb/unittests/TestingSupport/Symbol/ClangTestUtils.h +++ b/lldb/unittests/TestingSupport/Symbol/ClangTestUtils.h @@ -9,9 +9,9 @@ #ifndef LLDB_UNITTESTS_TESTINGSUPPORT_SYMBOL_CLANGTESTUTILS_H #define LLDB_UNITTESTS_TESTINGSUPPORT_SYMBOL_CLANGTESTUTILS_H +#include "Plugins/ExpressionParser/Clang/ClangUtil.h" +#include "Plugins/TypeSystem/Clang/TypeSystemClang.h" #include "lldb/Host/HostInfo.h" -#include "lldb/Symbol/TypeSystemClang.h" -#include "lldb/Symbol/ClangUtil.h" namespace lldb_private { namespace clang_utils { diff --git a/lldb/unittests/UnwindAssembly/ARM64/CMakeLists.txt b/lldb/unittests/UnwindAssembly/ARM64/CMakeLists.txt index 77924792fe5c3..76b4b004c0b4e 100644 --- a/lldb/unittests/UnwindAssembly/ARM64/CMakeLists.txt +++ b/lldb/unittests/UnwindAssembly/ARM64/CMakeLists.txt @@ -8,6 +8,7 @@ add_lldb_unittest(Arm64InstEmulationTests lldbPluginDisassemblerLLVM lldbPluginInstructionARM64 lldbPluginProcessUtility + lldbPluginPlatformMacOSX LINK_COMPONENTS Support ${LLVM_TARGETS_TO_BUILD}) diff --git a/lldb/unittests/UnwindAssembly/ARM64/TestArm64InstEmulation.cpp b/lldb/unittests/UnwindAssembly/ARM64/TestArm64InstEmulation.cpp index d853e6fb43c0d..6920bacc741f6 100644 --- a/lldb/unittests/UnwindAssembly/ARM64/TestArm64InstEmulation.cpp +++ b/lldb/unittests/UnwindAssembly/ARM64/TestArm64InstEmulation.cpp @@ -679,3 +679,103 @@ TEST_F(TestArm64InstEmulation, TestRegisterDoubleSpills) { EXPECT_TRUE(regloc.IsSame()); } } + +TEST_F(TestArm64InstEmulation, TestCFARegisterTrackedAcrossJumps) { + ArchSpec arch("arm64-apple-ios10"); + std::unique_ptr engine( + static_cast( + UnwindAssemblyInstEmulation::CreateInstance(arch))); + ASSERT_NE(nullptr, engine); + + UnwindPlan::RowSP row_sp; + AddressRange sample_range; + UnwindPlan unwind_plan(eRegisterKindLLDB); + UnwindPlan::Row::RegisterLocation regloc; + + uint8_t data[] = { + // prologue + 0xf4, 0x4f, 0xbe, 0xa9, // 0: 0xa9be4ff4 stp x20, x19, [sp, #-0x20]! + 0xfd, 0x7b, 0x01, 0xa9, // 4: 0xa9017bfd stp x29, x30, [sp, #0x10] + 0xfd, 0x43, 0x00, 0x91, // 8: 0x910043fd add x29, sp, #0x10 + 0xff, 0x43, 0x00, 0xd1, // 12: 0xd10043ff sub sp, sp, #0x10 + // conditional branch over a mid-function epilogue + 0xeb, 0x00, 0x00, 0x54, // 16: 0x540000eb b.lt <+44> + // mid-function epilogue + 0x1f, 0x20, 0x03, 0xd5, // 20: 0xd503201f nop + 0xe0, 0x03, 0x13, 0xaa, // 24: 0xaa1303e0 mov x0, x19 + 0xbf, 0x43, 0x00, 0xd1, // 28: 0xd10043bf sub sp, x29, #0x10 + 0xfd, 0x7b, 0x41, 0xa9, // 32: 0xa9417bfd ldp x29, x30, [sp, #0x10] + 0xf4, 0x4f, 0xc2, 0xa8, // 36: 0xa8c24ff4 ldp x20, x19, [sp], #0x20 + 0xc0, 0x03, 0x5f, 0xd6, // 40: 0xd65f03c0 ret + // unwind state restored, we're using a frame pointer, let's change the + // stack pointer and see no change in how the CFA is computed + 0x1f, 0x20, 0x03, 0xd5, // 44: 0xd503201f nop + 0xff, 0x43, 0x00, 0xd1, // 48: 0xd10043ff sub sp, sp, #0x10 + 0x1f, 0x20, 0x03, 0xd5, // 52: 0xd503201f nop + // final epilogue + 0xe0, 0x03, 0x13, 0xaa, // 56: 0xaa1303e0 mov x0, x19 + 0xbf, 0x43, 0x00, 0xd1, // 60: 0xd10043bf sub sp, x29, #0x10 + 0xfd, 0x7b, 0x41, 0xa9, // 64: 0xa9417bfd ldp x29, x30, [sp, #0x10] + 0xf4, 0x4f, 0xc2, 0xa8, // 68: 0xa8c24ff4 ldp x20, x19, [sp], #0x20 + 0xc0, 0x03, 0x5f, 0xd6, // 72: 0xd65f03c0 ret + + 0x1f, 0x20, 0x03, 0xd5, // 52: 0xd503201f nop + }; + + // UnwindPlan we expect: + // row[0]: 0: CFA=sp +0 => + // row[1]: 4: CFA=sp+32 => x19=[CFA-24] x20=[CFA-32] + // row[2]: 8: CFA=sp+32 => x19=[CFA-24] x20=[CFA-32] fp=[CFA-16] lr=[CFA-8] + // row[3]: 12: CFA=fp+16 => x19=[CFA-24] x20=[CFA-32] fp=[CFA-16] lr=[CFA-8] + // row[4]: 32: CFA=sp+32 => x19=[CFA-24] x20=[CFA-32] fp=[CFA-16] lr=[CFA-8] + // row[5]: 36: CFA=sp+32 => x19=[CFA-24] x20=[CFA-32] fp= lr= + // row[6]: 40: CFA=sp +0 => x19= x20= fp= lr= + // row[7]: 44: CFA=fp+16 => x19=[CFA-24] x20=[CFA-32] fp=[CFA-16] lr=[CFA-8] + // row[8]: 64: CFA=sp+32 => x19=[CFA-24] x20=[CFA-32] fp=[CFA-16] lr=[CFA-8] + // row[9]: 68: CFA=sp+32 => x19=[CFA-24] x20=[CFA-32] fp= lr= + // row[10]: 72: CFA=sp +0 => x19= x20= fp= lr= + + // The specific bug we're looking for is this incorrect CFA definition, + // where the InstEmulation is using the $sp value mixed in with $fp, + // it looks like this: + // + // row[7]: 44: CFA=fp+16 => x19=[CFA-24] x20=[CFA-32] fp=[CFA-16] lr=[CFA-8] + // row[8]: 52: CFA=fp+64 => x19=[CFA-24] x20=[CFA-32] fp=[CFA-16] lr=[CFA-8] + // row[9]: 68: CFA=fp+64 => x19=[CFA-24] x20=[CFA-32] fp= lr= + + sample_range = AddressRange(0x1000, sizeof(data)); + + EXPECT_TRUE(engine->GetNonCallSiteUnwindPlanFromAssembly( + sample_range, data, sizeof(data), unwind_plan)); + + // Confirm CFA at mid-func epilogue 'ret' is $sp+0 + row_sp = unwind_plan.GetRowForFunctionOffset(40); + EXPECT_EQ(40ull, row_sp->GetOffset()); + EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == gpr_sp_arm64); + EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true); + EXPECT_EQ(0, row_sp->GetCFAValue().GetOffset()); + + // After the 'ret', confirm we're back to the correct CFA of $fp+16 + row_sp = unwind_plan.GetRowForFunctionOffset(44); + EXPECT_EQ(44ull, row_sp->GetOffset()); + EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == gpr_fp_arm64); + EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true); + EXPECT_EQ(16, row_sp->GetCFAValue().GetOffset()); + + // Confirm that we have no additional UnwindPlan rows before the + // real epilogue -- we still get the Row at offset 44. + row_sp = unwind_plan.GetRowForFunctionOffset(60); + EXPECT_EQ(44ull, row_sp->GetOffset()); + EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == gpr_fp_arm64); + EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true); + EXPECT_EQ(16, row_sp->GetCFAValue().GetOffset()); + + // And in the epilogue, confirm that we start by switching back to + // defining the CFA in terms of $sp. + row_sp = unwind_plan.GetRowForFunctionOffset(64); + EXPECT_EQ(64ull, row_sp->GetOffset()); + EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == gpr_sp_arm64); + EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true); + EXPECT_EQ(32, row_sp->GetCFAValue().GetOffset()); +} + diff --git a/lldb/unittests/UnwindAssembly/PPC64/CMakeLists.txt b/lldb/unittests/UnwindAssembly/PPC64/CMakeLists.txt index d803f45936365..41cf7b756758b 100644 --- a/lldb/unittests/UnwindAssembly/PPC64/CMakeLists.txt +++ b/lldb/unittests/UnwindAssembly/PPC64/CMakeLists.txt @@ -8,6 +8,7 @@ add_lldb_unittest(PPC64InstEmulationTests lldbPluginDisassemblerLLVM lldbPluginInstructionPPC64 lldbPluginProcessUtility + lldbPluginPlatformMacOSX LINK_COMPONENTS Support ${LLVM_TARGETS_TO_BUILD}) diff --git a/lldb/unittests/UnwindAssembly/x86/CMakeLists.txt b/lldb/unittests/UnwindAssembly/x86/CMakeLists.txt index 2b5b31f79063d..2fdba137f8d9f 100644 --- a/lldb/unittests/UnwindAssembly/x86/CMakeLists.txt +++ b/lldb/unittests/UnwindAssembly/x86/CMakeLists.txt @@ -4,6 +4,7 @@ add_lldb_unittest(UnwindAssemblyx86Tests lldbCore lldbSymbol lldbPluginUnwindAssemblyX86 + lldbPluginPlatformMacOSX LINK_COMPONENTS Support ${LLVM_TARGETS_TO_BUILD} diff --git a/lldb/unittests/Utility/ArchSpecTest.cpp b/lldb/unittests/Utility/ArchSpecTest.cpp index 9115808c12587..19186667da9e9 100644 --- a/lldb/unittests/Utility/ArchSpecTest.cpp +++ b/lldb/unittests/Utility/ArchSpecTest.cpp @@ -9,8 +9,9 @@ #include "gtest/gtest.h" #include "lldb/Utility/ArchSpec.h" -#include "llvm/BinaryFormat/MachO.h" #include "llvm/BinaryFormat/ELF.h" +#include "llvm/BinaryFormat/MachO.h" +#include "llvm/Support/YAMLParser.h" using namespace lldb; using namespace lldb_private; @@ -200,14 +201,14 @@ TEST(ArchSpecTest, MergeFrom) { EXPECT_TRUE(A.IsValid()); EXPECT_TRUE(B.IsValid()); - + EXPECT_EQ(llvm::Triple::ArchType::arm, B.GetTriple().getArch()); EXPECT_EQ(llvm::Triple::VendorType::UnknownVendor, B.GetTriple().getVendor()); EXPECT_EQ(llvm::Triple::OSType::Linux, B.GetTriple().getOS()); EXPECT_EQ(llvm::Triple::EnvironmentType::UnknownEnvironment, B.GetTriple().getEnvironment()); - + A.MergeFrom(B); EXPECT_EQ(llvm::Triple::ArchType::arm, A.GetTriple().getArch()); EXPECT_EQ(llvm::Triple::VendorType::UnknownVendor, @@ -406,3 +407,23 @@ TEST(ArchSpecTest, TripleComponentsWereSpecified) { ASSERT_TRUE(D.TripleEnvironmentWasSpecified()); } } + +TEST(ArchSpecTest, YAML) { + std::string buffer; + llvm::raw_string_ostream os(buffer); + + // Serialize. + llvm::yaml::Output yout(os); + std::vector archs = {ArchSpec("x86_64-pc-linux"), + ArchSpec("x86_64-apple-macosx10.12"), + ArchSpec("i686-pc-windows")}; + yout << archs; + os.flush(); + + // Deserialize. + std::vector deserialized; + llvm::yaml::Input yin(buffer); + yin >> deserialized; + + EXPECT_EQ(archs, deserialized); +} diff --git a/lldb/unittests/Utility/CMakeLists.txt b/lldb/unittests/Utility/CMakeLists.txt index 8dc13327b9b0e..876fb9268c3e4 100644 --- a/lldb/unittests/Utility/CMakeLists.txt +++ b/lldb/unittests/Utility/CMakeLists.txt @@ -41,6 +41,7 @@ add_lldb_unittest(UtilityTests UUIDTest.cpp VASprintfTest.cpp VMRangeTest.cpp + XcodeSDKTest.cpp LINK_LIBS lldbUtility diff --git a/lldb/unittests/Utility/ConstStringTest.cpp b/lldb/unittests/Utility/ConstStringTest.cpp index 74753b903171d..1aefa25380455 100644 --- a/lldb/unittests/Utility/ConstStringTest.cpp +++ b/lldb/unittests/Utility/ConstStringTest.cpp @@ -8,6 +8,7 @@ #include "lldb/Utility/ConstString.h" #include "llvm/Support/FormatVariadic.h" +#include "llvm/Support/YAMLParser.h" #include "gtest/gtest.h" using namespace lldb_private; @@ -137,3 +138,22 @@ TEST(ConstStringTest, CompareStringRef) { EXPECT_TRUE(null == static_cast(nullptr)); EXPECT_TRUE(null != "bar"); } + +TEST(ConstStringTest, YAML) { + std::string buffer; + llvm::raw_string_ostream os(buffer); + + // Serialize. + std::vector strings = {ConstString("foo"), ConstString("bar"), + ConstString("")}; + llvm::yaml::Output yout(os); + yout << strings; + os.flush(); + + // Deserialize. + std::vector deserialized; + llvm::yaml::Input yin(buffer); + yin >> deserialized; + + EXPECT_EQ(strings, deserialized); +} diff --git a/lldb/unittests/Utility/FileSpecTest.cpp b/lldb/unittests/Utility/FileSpecTest.cpp index d5f1091d5d469..b5ccb5373df98 100644 --- a/lldb/unittests/Utility/FileSpecTest.cpp +++ b/lldb/unittests/Utility/FileSpecTest.cpp @@ -420,3 +420,24 @@ TEST(FileSpecTest, Match) { EXPECT_TRUE(Match("", "")); } + +TEST(FileSpecTest, Yaml) { + std::string buffer; + llvm::raw_string_ostream os(buffer); + + // Serialize. + FileSpec fs_windows("F:\\bar", FileSpec::Style::windows); + llvm::yaml::Output yout(os); + yout << fs_windows; + os.flush(); + + // Deserialize. + FileSpec deserialized; + llvm::yaml::Input yin(buffer); + yin >> deserialized; + + EXPECT_EQ(deserialized.GetPathStyle(), fs_windows.GetPathStyle()); + EXPECT_EQ(deserialized.GetFilename(), fs_windows.GetFilename()); + EXPECT_EQ(deserialized.GetDirectory(), fs_windows.GetDirectory()); + EXPECT_EQ(deserialized, fs_windows); +} diff --git a/lldb/unittests/Utility/ProcessInstanceInfoTest.cpp b/lldb/unittests/Utility/ProcessInstanceInfoTest.cpp index 1d363ac80a365..d433b04e4f258 100644 --- a/lldb/unittests/Utility/ProcessInstanceInfoTest.cpp +++ b/lldb/unittests/Utility/ProcessInstanceInfoTest.cpp @@ -108,3 +108,60 @@ TEST(ProcessInstanceInfoMatch, Name) { EXPECT_TRUE(match.Matches(info_bar)); EXPECT_TRUE(match.Matches(info_empty)); } + +TEST(ProcessInstanceInfo, Yaml) { + std::string buffer; + llvm::raw_string_ostream os(buffer); + + // Serialize. + ProcessInstanceInfo info("a.out", ArchSpec("x86_64-pc-linux"), 47); + info.SetUserID(1); + info.SetEffectiveUserID(2); + info.SetGroupID(3); + info.SetEffectiveGroupID(4); + llvm::yaml::Output yout(os); + yout << info; + os.flush(); + + // Deserialize. + ProcessInstanceInfo deserialized; + llvm::yaml::Input yin(buffer); + yin >> deserialized; + + EXPECT_EQ(deserialized.GetNameAsStringRef(), info.GetNameAsStringRef()); + EXPECT_EQ(deserialized.GetArchitecture(), info.GetArchitecture()); + EXPECT_EQ(deserialized.GetUserID(), info.GetUserID()); + EXPECT_EQ(deserialized.GetGroupID(), info.GetGroupID()); + EXPECT_EQ(deserialized.GetEffectiveUserID(), info.GetEffectiveUserID()); + EXPECT_EQ(deserialized.GetEffectiveGroupID(), info.GetEffectiveGroupID()); +} + +TEST(ProcessInstanceInfoList, Yaml) { + std::string buffer; + llvm::raw_string_ostream os(buffer); + + // Serialize. + ProcessInstanceInfo info("a.out", ArchSpec("x86_64-pc-linux"), 47); + info.SetUserID(1); + info.SetEffectiveUserID(2); + info.SetGroupID(3); + info.SetEffectiveGroupID(4); + ProcessInstanceInfoList list; + list.push_back(info); + llvm::yaml::Output yout(os); + yout << list; + os.flush(); + + // Deserialize. + ProcessInstanceInfoList deserialized; + llvm::yaml::Input yin(buffer); + yin >> deserialized; + + ASSERT_EQ(deserialized.size(), static_cast(1)); + EXPECT_EQ(deserialized[0].GetNameAsStringRef(), info.GetNameAsStringRef()); + EXPECT_EQ(deserialized[0].GetArchitecture(), info.GetArchitecture()); + EXPECT_EQ(deserialized[0].GetUserID(), info.GetUserID()); + EXPECT_EQ(deserialized[0].GetGroupID(), info.GetGroupID()); + EXPECT_EQ(deserialized[0].GetEffectiveUserID(), info.GetEffectiveUserID()); + EXPECT_EQ(deserialized[0].GetEffectiveGroupID(), info.GetEffectiveGroupID()); +} diff --git a/lldb/unittests/Utility/XcodeSDKTest.cpp b/lldb/unittests/Utility/XcodeSDKTest.cpp new file mode 100644 index 0000000000000..a316516a16758 --- /dev/null +++ b/lldb/unittests/Utility/XcodeSDKTest.cpp @@ -0,0 +1,86 @@ +//===-- XcodeSDKTest.cpp --------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "gtest/gtest.h" + +#include "lldb/Utility/FileSpec.h" +#include "lldb/Utility/XcodeSDK.h" + +#include "llvm/ADT/StringRef.h" + +#include + +using namespace lldb_private; + +TEST(XcodeSDKTest, ParseTest) { + EXPECT_EQ(XcodeSDK::GetAnyMacOS().GetType(), XcodeSDK::MacOSX); + EXPECT_EQ(XcodeSDK("MacOSX.sdk").GetType(), XcodeSDK::MacOSX); + EXPECT_EQ(XcodeSDK("iPhoneSimulator.sdk").GetType(), XcodeSDK::iPhoneSimulator); + EXPECT_EQ(XcodeSDK("iPhoneOS.sdk").GetType(), XcodeSDK::iPhoneOS); + EXPECT_EQ(XcodeSDK("AppleTVSimulator.sdk").GetType(), XcodeSDK::AppleTVSimulator); + EXPECT_EQ(XcodeSDK("AppleTVOS.sdk").GetType(), XcodeSDK::AppleTVOS); + EXPECT_EQ(XcodeSDK("WatchSimulator.sdk").GetType(), XcodeSDK::WatchSimulator); + EXPECT_EQ(XcodeSDK("WatchOS.sdk").GetType(), XcodeSDK::watchOS); + EXPECT_EQ(XcodeSDK("Linux.sdk").GetType(), XcodeSDK::Linux); + EXPECT_EQ(XcodeSDK("MacOSX.sdk").GetVersion(), llvm::VersionTuple()); + EXPECT_EQ(XcodeSDK("MacOSX10.9.sdk").GetVersion(), llvm::VersionTuple(10, 9)); + EXPECT_EQ(XcodeSDK("MacOSX10.15.4.sdk").GetVersion(), llvm::VersionTuple(10, 15)); + EXPECT_EQ(XcodeSDK().GetType(), XcodeSDK::unknown); + EXPECT_EQ(XcodeSDK().GetVersion(), llvm::VersionTuple()); +} + +TEST(XcodeSDKTest, MergeTest) { + XcodeSDK sdk("MacOSX.sdk"); + sdk.Merge(XcodeSDK("WatchOS.sdk")); + // This doesn't make any particular sense and shouldn't happen in practice, we + // just want to guarantee a well-defined behavior when choosing one + // SDK to fit all CUs in an lldb::Module. + // -> The higher number wins. + EXPECT_EQ(sdk.GetType(), XcodeSDK::watchOS); + sdk.Merge(XcodeSDK("WatchOS1.1.sdk")); + EXPECT_EQ(sdk.GetVersion(), llvm::VersionTuple(1, 1)); + sdk.Merge(XcodeSDK("WatchOS2.0.sdk")); + EXPECT_EQ(sdk.GetVersion(), llvm::VersionTuple(2, 0)); +} + +TEST(XcodeSDKTest, SDKSupportsModules) { + std::string base = "/Applications/Xcode.app/Contents/Developer/Platforms/"; + EXPECT_TRUE(XcodeSDK::SDKSupportsModules( + XcodeSDK::Type::iPhoneSimulator, + FileSpec( + base + + "iPhoneSimulator.platform/Developer/SDKs/iPhoneSimulator12.0.sdk"))); + EXPECT_FALSE(XcodeSDK::SDKSupportsModules( + XcodeSDK::Type::iPhoneSimulator, + FileSpec( + base + + "iPhoneSimulator.platform/Developer/SDKs/iPhoneSimulator7.2.sdk"))); + EXPECT_TRUE(XcodeSDK::SDKSupportsModules( + XcodeSDK::Type::MacOSX, + FileSpec(base + "MacOSX.platform/Developer/SDKs/MacOSX10.10.sdk"))); + EXPECT_FALSE(XcodeSDK::SDKSupportsModules( + XcodeSDK::Type::MacOSX, + FileSpec(base + "MacOSX.platform/Developer/SDKs/MacOSX10.9.sdk"))); +} + +TEST(XcodeSDKTest, GetSDKNameForType) { + EXPECT_EQ("macosx", XcodeSDK::GetSDKNameForType(XcodeSDK::Type::MacOSX)); + EXPECT_EQ("iphonesimulator", + XcodeSDK::GetSDKNameForType(XcodeSDK::Type::iPhoneSimulator)); + EXPECT_EQ("iphoneos", XcodeSDK::GetSDKNameForType(XcodeSDK::Type::iPhoneOS)); + EXPECT_EQ("appletvsimulator", + XcodeSDK::GetSDKNameForType(XcodeSDK::Type::AppleTVSimulator)); + EXPECT_EQ("appletvos", + XcodeSDK::GetSDKNameForType(XcodeSDK::Type::AppleTVOS)); + EXPECT_EQ("watchsimulator", + XcodeSDK::GetSDKNameForType(XcodeSDK::Type::WatchSimulator)); + EXPECT_EQ("watchos", XcodeSDK::GetSDKNameForType(XcodeSDK::Type::watchOS)); + EXPECT_EQ("linux", XcodeSDK::GetSDKNameForType(XcodeSDK::Type::Linux)); + EXPECT_EQ("", XcodeSDK::GetSDKNameForType(XcodeSDK::Type::numSDKTypes)); + EXPECT_EQ("", XcodeSDK::GetSDKNameForType(XcodeSDK::Type::unknown)); +} diff --git a/lldb/utils/lldb-dotest/lldb-dotest.in b/lldb/utils/lldb-dotest/lldb-dotest.in index e4647594e2b44..02a770809e9df 100755 --- a/lldb/utils/lldb-dotest/lldb-dotest.in +++ b/lldb/utils/lldb-dotest/lldb-dotest.in @@ -1,4 +1,4 @@ -#!/usr/bin/env python +#!@PYTHON_EXECUTABLE@ import os import subprocess import sys diff --git a/llvm/docs/CommandGuide/dsymutil.rst b/llvm/docs/CommandGuide/dsymutil.rst index 4aa9c1c7c49dd..2f638daf2ae3f 100644 --- a/llvm/docs/CommandGuide/dsymutil.rst +++ b/llvm/docs/CommandGuide/dsymutil.rst @@ -71,6 +71,12 @@ OPTIONS Specifies a ``path`` to prepend to all debug symbol object file paths. +.. option:: --object-prefix-map= + + Remap object file paths (but no source paths) before processing. Use + this for Clang objects where the module cache location was remapped using + ``-fdebug-prefix-map``; to help dsymutil find the Clang module cache. + .. option:: --papertrail When running dsymutil as part of your build system, it can be desirable for diff --git a/llvm/include/llvm-c/DebugInfo.h b/llvm/include/llvm-c/DebugInfo.h index 61702253f69b8..cdf5f5a0cca86 100644 --- a/llvm/include/llvm-c/DebugInfo.h +++ b/llvm/include/llvm-c/DebugInfo.h @@ -296,7 +296,7 @@ LLVMDIBuilderCreateModule(LLVMDIBuilderRef Builder, LLVMMetadataRef ParentScope, const char *Name, size_t NameLen, const char *ConfigMacros, size_t ConfigMacrosLen, const char *IncludePath, size_t IncludePathLen, - const char *APINotestFile, size_t APINotestFileLen); + const char *APINotesFile, size_t APINotesFileLen); /** * Creates a new descriptor for a namespace with the specified parent scope. diff --git a/llvm/include/llvm/ADT/CoalescingBitVector.h b/llvm/include/llvm/ADT/CoalescingBitVector.h index 21b3bbbe2ff27..8ef6f4fac0a1b 100644 --- a/llvm/include/llvm/ADT/CoalescingBitVector.h +++ b/llvm/include/llvm/ADT/CoalescingBitVector.h @@ -21,7 +21,6 @@ #include #include -#include namespace llvm { @@ -33,9 +32,8 @@ namespace llvm { /// Compared to SparseBitVector, CoalescingBitVector offers more predictable /// performance for non-sequential find() operations. /// -/// \param IndexT - The type of the index into the bitvector. -/// \param N - The first N coalesced intervals of set bits are stored in-place -/// (in the initial heap allocation). +/// \tparam IndexT - The type of the index into the bitvector. +/// \tparam N - The first N coalesced intervals of set bits are stored in-place. template class CoalescingBitVector { static_assert(std::is_unsigned::value, "Index must be an unsigned integer."); @@ -55,13 +53,13 @@ template class CoalescingBitVector { /// Construct by passing in a CoalescingBitVector::Allocator /// reference. CoalescingBitVector(Allocator &Alloc) - : Alloc(&Alloc), Intervals(std::make_unique(Alloc)) {} + : Alloc(&Alloc), Intervals(Alloc) {} /// \name Copy/move constructors and assignment operators. /// @{ CoalescingBitVector(const ThisT &Other) - : Alloc(Other.Alloc), Intervals(std::make_unique(*Other.Alloc)) { + : Alloc(Other.Alloc), Intervals(*Other.Alloc) { set(Other); } @@ -71,27 +69,21 @@ template class CoalescingBitVector { return *this; } - CoalescingBitVector(ThisT &&Other) - : Alloc(Other.Alloc), Intervals(std::move(Other.Intervals)) {} - - ThisT &operator=(ThisT &&Other) { - Alloc = Other.Alloc; - Intervals = std::move(Other.Intervals); - return *this; - } + CoalescingBitVector(ThisT &&Other) = delete; + ThisT &operator=(ThisT &&Other) = delete; /// @} /// Clear all the bits. - void clear() { Intervals->clear(); } + void clear() { Intervals.clear(); } /// Check whether no bits are set. - bool empty() const { return Intervals->empty(); } + bool empty() const { return Intervals.empty(); } /// Count the number of set bits. unsigned count() const { unsigned Bits = 0; - for (auto It = Intervals->begin(), End = Intervals->end(); It != End; ++It) + for (auto It = Intervals.begin(), End = Intervals.end(); It != End; ++It) Bits += 1 + It.stop() - It.start(); return Bits; } @@ -112,7 +104,7 @@ template class CoalescingBitVector { /// This method does /not/ support setting already-set bits, see \ref set /// for the rationale. For a safe set union operation, use \ref operator|=. void set(const ThisT &Other) { - for (auto It = Other.Intervals->begin(), End = Other.Intervals->end(); + for (auto It = Other.Intervals.begin(), End = Other.Intervals.end(); It != End; ++It) insert(It.start(), It.stop()); } @@ -125,8 +117,8 @@ template class CoalescingBitVector { /// Check whether the bit at \p Index is set. bool test(IndexT Index) const { - const auto It = Intervals->find(Index); - if (It == Intervals->end()) + const auto It = Intervals.find(Index); + if (It == Intervals.end()) return false; assert(It.stop() >= Index && "Interval must end after Index"); return It.start() <= Index; @@ -140,8 +132,8 @@ template class CoalescingBitVector { /// Reset the bit at \p Index. Supports resetting an already-unset bit. void reset(IndexT Index) { - auto It = Intervals->find(Index); - if (It == Intervals->end()) + auto It = Intervals.find(Index); + if (It == Intervals.end()) return; // Split the interval containing Index into up to two parts: one from @@ -169,7 +161,7 @@ template class CoalescingBitVector { getOverlaps(RHS, Overlaps); // Insert the non-overlapping parts of all the intervals from RHS. - for (auto It = RHS.Intervals->begin(), End = RHS.Intervals->end(); + for (auto It = RHS.Intervals.begin(), End = RHS.Intervals.end(); It != End; ++It) { IndexT Start = It.start(); IndexT Stop = It.stop(); @@ -205,7 +197,7 @@ template class CoalescingBitVector { IndexT OlapStart, OlapStop; std::tie(OlapStart, OlapStop) = Overlap; - auto It = Intervals->find(OlapStart); + auto It = Intervals.find(OlapStart); IndexT CurrStart = It.start(); IndexT CurrStop = It.stop(); assert(CurrStart <= OlapStart && OlapStop <= CurrStop && @@ -227,14 +219,14 @@ template class CoalescingBitVector { // We cannot just use std::equal because it checks the dereferenced values // of an iterator pair for equality, not the iterators themselves. In our // case that results in comparison of the (unused) IntervalMap values. - auto ItL = Intervals->begin(); - auto ItR = RHS.Intervals->begin(); - while (ItL != Intervals->end() && ItR != RHS.Intervals->end() && + auto ItL = Intervals.begin(); + auto ItR = RHS.Intervals.begin(); + while (ItL != Intervals.end() && ItR != RHS.Intervals.end() && ItL.start() == ItR.start() && ItL.stop() == ItR.stop()) { ++ItL; ++ItR; } - return ItL == Intervals->end() && ItR == RHS.Intervals->end(); + return ItL == Intervals.end() && ItR == RHS.Intervals.end(); } bool operator!=(const ThisT &RHS) const { return !operator==(RHS); } @@ -274,9 +266,9 @@ template class CoalescingBitVector { } /// Advance the iterator to \p Index, if it is contained within the current - /// interval. + /// interval. The public-facing method which supports advancing past the + /// current interval is \ref advanceToLowerBound. void advanceTo(IndexT Index) { - assert(OffsetIntoMapIterator == 0 && "Not implemented"); assert(Index <= CachedStop && "Cannot advance to OOB index"); if (Index < CachedStart) // We're already past this index. @@ -322,17 +314,38 @@ template class CoalescingBitVector { operator++(); return tmp; } + + /// Advance the iterator to the first set bit AT, OR AFTER, \p Index. If + /// no such set bit exists, advance to end(). This is like std::lower_bound. + /// This is useful if \p Index is close to the current iterator position. + /// However, unlike \ref find(), this has worst-case O(n) performance. + void advanceToLowerBound(IndexT Index) { + if (OffsetIntoMapIterator == kIteratorAtTheEndOffset) + return; + + // Advance to the first interval containing (or past) Index, or to end(). + while (Index > CachedStop) { + ++MapIterator; + resetCache(); + if (OffsetIntoMapIterator == kIteratorAtTheEndOffset) + return; + } + + advanceTo(Index); + } }; - const_iterator begin() const { return const_iterator(Intervals->begin()); } + const_iterator begin() const { return const_iterator(Intervals.begin()); } const_iterator end() const { return const_iterator(); } /// Return an iterator pointing to the first set bit AT, OR AFTER, \p Index. /// If no such set bit exists, return end(). This is like std::lower_bound. + /// This has worst-case logarithmic performance (roughly O(log(gaps between + /// contiguous ranges))). const_iterator find(IndexT Index) const { - auto UnderlyingIt = Intervals->find(Index); - if (UnderlyingIt == Intervals->end()) + auto UnderlyingIt = Intervals.find(Index); + if (UnderlyingIt == Intervals.end()) return end(); auto It = const_iterator(UnderlyingIt); It.advanceTo(Index); @@ -341,7 +354,7 @@ template class CoalescingBitVector { void print(raw_ostream &OS) const { OS << "{"; - for (auto It = Intervals->begin(), End = Intervals->end(); It != End; + for (auto It = Intervals.begin(), End = Intervals.end(); It != End; ++It) { OS << "[" << It.start(); if (It.start() != It.stop()) @@ -362,13 +375,13 @@ template class CoalescingBitVector { #endif private: - void insert(IndexT Start, IndexT End) { Intervals->insert(Start, End, 0); } + void insert(IndexT Start, IndexT End) { Intervals.insert(Start, End, 0); } /// Record the overlaps between \p this and \p Other in \p Overlaps. Return /// true if there is any overlap. bool getOverlaps(const ThisT &Other, SmallVectorImpl &Overlaps) const { - for (IntervalMapOverlaps I(*Intervals, *Other.Intervals); + for (IntervalMapOverlaps I(Intervals, Other.Intervals); I.valid(); ++I) Overlaps.emplace_back(I.start(), I.stop()); assert(std::is_sorted(Overlaps.begin(), Overlaps.end(), @@ -409,7 +422,7 @@ template class CoalescingBitVector { } Allocator *Alloc; - std::unique_ptr Intervals; + MapT Intervals; }; } // namespace llvm diff --git a/llvm/include/llvm/Analysis/AliasAnalysis.h b/llvm/include/llvm/Analysis/AliasAnalysis.h index 7c42a261ebb68..4ae2cb24040cc 100644 --- a/llvm/include/llvm/Analysis/AliasAnalysis.h +++ b/llvm/include/llvm/Analysis/AliasAnalysis.h @@ -59,7 +59,6 @@ class AnalysisUsage; class BasicAAResult; class BasicBlock; class DominatorTree; -class OrderedBasicBlock; class Value; /// The possible results of an alias query. @@ -643,19 +642,16 @@ class AAResults { /// Return information about whether a particular call site modifies /// or reads the specified memory location \p MemLoc before instruction \p I - /// in a BasicBlock. An ordered basic block \p OBB can be used to speed up - /// instruction ordering queries inside the BasicBlock containing \p I. + /// in a BasicBlock. /// Early exits in callCapturesBefore may lead to ModRefInfo::Must not being /// set. ModRefInfo callCapturesBefore(const Instruction *I, - const MemoryLocation &MemLoc, DominatorTree *DT, - OrderedBasicBlock *OBB = nullptr); + const MemoryLocation &MemLoc, DominatorTree *DT); /// A convenience wrapper to synthesize a memory location. ModRefInfo callCapturesBefore(const Instruction *I, const Value *P, - LocationSize Size, DominatorTree *DT, - OrderedBasicBlock *OBB = nullptr) { - return callCapturesBefore(I, MemoryLocation(P, Size), DT, OBB); + LocationSize Size, DominatorTree *DT) { + return callCapturesBefore(I, MemoryLocation(P, Size), DT); } /// @} diff --git a/llvm/include/llvm/Analysis/CaptureTracking.h b/llvm/include/llvm/Analysis/CaptureTracking.h index 29921a51d5be0..5f72f82f95663 100644 --- a/llvm/include/llvm/Analysis/CaptureTracking.h +++ b/llvm/include/llvm/Analysis/CaptureTracking.h @@ -20,7 +20,6 @@ namespace llvm { class DataLayout; class Instruction; class DominatorTree; - class OrderedBasicBlock; /// The default value for MaxUsesToExplore argument. It's relatively small to /// keep the cost of analysis reasonable for clients like BasicAliasAnalysis, @@ -53,14 +52,12 @@ namespace llvm { /// it or not. The boolean StoreCaptures specified whether storing the value /// (or part of it) into memory anywhere automatically counts as capturing it /// or not. Captures by the provided instruction are considered if the - /// final parameter is true. An ordered basic block in \p OBB could be used - /// to speed up capture-tracker queries. + /// final parameter is true. /// MaxUsesToExplore specifies how many uses should the analysis explore for /// one value before giving up due too "too many uses". bool PointerMayBeCapturedBefore(const Value *V, bool ReturnCaptures, bool StoreCaptures, const Instruction *I, const DominatorTree *DT, bool IncludeI = false, - OrderedBasicBlock *OBB = nullptr, unsigned MaxUsesToExplore = DefaultMaxUsesToExplore); /// This callback is used in conjunction with PointerMayBeCaptured. In diff --git a/llvm/include/llvm/Analysis/MemoryDependenceAnalysis.h b/llvm/include/llvm/Analysis/MemoryDependenceAnalysis.h index e89e5690fad03..e48f2b23a1cb9 100644 --- a/llvm/include/llvm/Analysis/MemoryDependenceAnalysis.h +++ b/llvm/include/llvm/Analysis/MemoryDependenceAnalysis.h @@ -384,8 +384,7 @@ class MemoryDependenceResults { /// /// See the class comment for more details. It is illegal to call this on /// non-memory instructions. - MemDepResult getDependency(Instruction *QueryInst, - OrderedBasicBlock *OBB = nullptr); + MemDepResult getDependency(Instruction *QueryInst); /// Perform a full dependency query for the specified call, returning the set /// of blocks that the value is potentially live across. @@ -451,14 +450,12 @@ class MemoryDependenceResults { BasicBlock::iterator ScanIt, BasicBlock *BB, Instruction *QueryInst = nullptr, - unsigned *Limit = nullptr, - OrderedBasicBlock *OBB = nullptr); + unsigned *Limit = nullptr); MemDepResult getSimplePointerDependencyFrom(const MemoryLocation &MemLoc, bool isLoad, BasicBlock::iterator ScanIt, BasicBlock *BB, - Instruction *QueryInst, unsigned *Limit, - OrderedBasicBlock *OBB); + Instruction *QueryInst, unsigned *Limit); /// This analysis looks for other loads and stores with invariant.group /// metadata and the same pointer operand. Returns Unknown if it does not diff --git a/llvm/include/llvm/Analysis/OrderedBasicBlock.h b/llvm/include/llvm/Analysis/OrderedBasicBlock.h deleted file mode 100644 index ae64c0189f5ec..0000000000000 --- a/llvm/include/llvm/Analysis/OrderedBasicBlock.h +++ /dev/null @@ -1,74 +0,0 @@ -//===- llvm/Analysis/OrderedBasicBlock.h --------------------- -*- C++ -*-===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// -// -// This file defines the OrderedBasicBlock class. OrderedBasicBlock maintains -// an interface where clients can query if one instruction comes before another -// in a BasicBlock. Since BasicBlock currently lacks a reliable way to query -// relative position between instructions one can use OrderedBasicBlock to do -// such queries. OrderedBasicBlock is lazily built on a source BasicBlock and -// maintains an internal Instruction -> Position map. A OrderedBasicBlock -// instance should be discarded whenever the source BasicBlock changes. -// -// It's currently used by the CaptureTracker in order to find relative -// positions of a pair of instructions inside a BasicBlock. -// -//===----------------------------------------------------------------------===// - -#ifndef LLVM_ANALYSIS_ORDEREDBASICBLOCK_H -#define LLVM_ANALYSIS_ORDEREDBASICBLOCK_H - -#include "llvm/ADT/DenseMap.h" -#include "llvm/IR/BasicBlock.h" - -namespace llvm { - -class Instruction; -class BasicBlock; - -class OrderedBasicBlock { -private: - /// Map a instruction to its position in a BasicBlock. - SmallDenseMap NumberedInsts; - - /// Keep track of last instruction inserted into \p NumberedInsts. - /// It speeds up queries for uncached instructions by providing a start point - /// for new queries in OrderedBasicBlock::comesBefore. - BasicBlock::const_iterator LastInstFound; - - /// The position/number to tag the next instruction to be found. - unsigned NextInstPos; - - /// The source BasicBlock to map. - const BasicBlock *BB; - - /// Given no cached results, find if \p A comes before \p B in \p BB. - /// Cache and number out instruction while walking \p BB. - bool comesBefore(const Instruction *A, const Instruction *B); - -public: - OrderedBasicBlock(const BasicBlock *BasicB); - - /// Find out whether \p A dominates \p B, meaning whether \p A - /// comes before \p B in \p BB. This is a simplification that considers - /// cached instruction positions and ignores other basic blocks, being - /// only relevant to compare relative instructions positions inside \p BB. - /// Returns false for A == B. - bool dominates(const Instruction *A, const Instruction *B); - - /// Remove \p from the ordering, if it is present. - void eraseInstruction(const Instruction *I); - - /// Replace \p Old with \p New in the ordering. \p New is assigned the - /// numbering of \p Old, so it must be inserted at the same position in the - /// IR. - void replaceInstruction(const Instruction *Old, const Instruction *New); -}; - -} // End llvm namespace - -#endif diff --git a/llvm/include/llvm/Analysis/OrderedInstructions.h b/llvm/include/llvm/Analysis/OrderedInstructions.h index 967b146b52deb..302509380a03a 100644 --- a/llvm/include/llvm/Analysis/OrderedInstructions.h +++ b/llvm/include/llvm/Analysis/OrderedInstructions.h @@ -9,10 +9,9 @@ // This file defines an efficient way to check for dominance relation between 2 // instructions. // -// This interface dispatches to appropriate dominance check given 2 -// instructions, i.e. in case the instructions are in the same basic block, -// OrderedBasicBlock (with instruction numbering and caching) are used. -// Otherwise, dominator tree is used. +// FIXME: This is really just a convenience wrapper to check dominance between +// two arbitrary instructions in different basic blocks. We should fold it into +// DominatorTree, which is the more widely used interface. // //===----------------------------------------------------------------------===// @@ -20,17 +19,12 @@ #define LLVM_ANALYSIS_ORDEREDINSTRUCTIONS_H #include "llvm/ADT/DenseMap.h" -#include "llvm/Analysis/OrderedBasicBlock.h" #include "llvm/IR/Dominators.h" #include "llvm/IR/Operator.h" namespace llvm { class OrderedInstructions { - /// Used to check dominance for instructions in same basic block. - mutable DenseMap> - OBBMap; - /// The dominator tree of the parent function. DominatorTree *DT; @@ -51,12 +45,6 @@ class OrderedInstructions { /// or if the first instruction comes before the second in the same basic /// block. bool dfsBefore(const Instruction *, const Instruction *) const; - - /// Invalidate the OrderedBasicBlock cache when its basic block changes. - /// i.e. If an instruction is deleted or added to the basic block, the user - /// should call this function to invalidate the OrderedBasicBlock cache for - /// this basic block. - void invalidateBlock(const BasicBlock *BB) { OBBMap.erase(BB); } }; } // end namespace llvm diff --git a/llvm/include/llvm/BinaryFormat/Dwarf.def b/llvm/include/llvm/BinaryFormat/Dwarf.def index e50ae58ddca9a..c31c5a750db87 100644 --- a/llvm/include/llvm/BinaryFormat/Dwarf.def +++ b/llvm/include/llvm/BinaryFormat/Dwarf.def @@ -420,6 +420,7 @@ HANDLE_DW_AT(0x3e06, APPLE_ptrauth_extra_discriminator, 0, LLVM) HANDLE_DW_AT(0x3e07, LLVM_apinotes, 0, APPLE) // Apple extensions. + HANDLE_DW_AT(0x3fe1, APPLE_optimized, 0, APPLE) HANDLE_DW_AT(0x3fe2, APPLE_flags, 0, APPLE) HANDLE_DW_AT(0x3fe3, APPLE_isa, 0, APPLE) diff --git a/llvm/include/llvm/CodeGen/DIE.h b/llvm/include/llvm/CodeGen/DIE.h index 40f6b041e9b30..150c30df9dd72 100644 --- a/llvm/include/llvm/CodeGen/DIE.h +++ b/llvm/include/llvm/CodeGen/DIE.h @@ -551,10 +551,21 @@ template class IntrusiveBackList : IntrusiveBackListBase { } void takeNodes(IntrusiveBackList &Other) { - for (auto &N : Other) { - N.Next.setPointerAndInt(&N, true); - push_back(N); - } + if (Other.empty()) + return; + + T *FirstNode = static_cast(Other.Last->Next.getPointer()); + T *IterNode = FirstNode; + do { + // Keep a pointer to the node and increment the iterator. + T *TmpNode = IterNode; + IterNode = static_cast(IterNode->Next.getPointer()); + + // Unlink the node and push it back to this list. + TmpNode->Next.setPointerAndInt(TmpNode, true); + push_back(*TmpNode); + } while (IterNode != FirstNode); + Other.Last = nullptr; } diff --git a/llvm/include/llvm/CodeGen/MachineFunction.h b/llvm/include/llvm/CodeGen/MachineFunction.h index c396bf9cea573..972e9eddc5160 100644 --- a/llvm/include/llvm/CodeGen/MachineFunction.h +++ b/llvm/include/llvm/CodeGen/MachineFunction.h @@ -221,7 +221,7 @@ struct LandingPadInfo { }; class MachineFunction { - const Function &F; + Function &F; const LLVMTargetMachine &Target; const TargetSubtargetInfo *STI; MCContext &Ctx; @@ -414,7 +414,7 @@ class MachineFunction { using VariableDbgInfoMapTy = SmallVector; VariableDbgInfoMapTy VariableDbgInfos; - MachineFunction(const Function &F, const LLVMTargetMachine &Target, + MachineFunction(Function &F, const LLVMTargetMachine &Target, const TargetSubtargetInfo &STI, unsigned FunctionNum, MachineModuleInfo &MMI); MachineFunction(const MachineFunction &) = delete; @@ -452,6 +452,9 @@ class MachineFunction { /// Return the DataLayout attached to the Module associated to this MF. const DataLayout &getDataLayout() const; + /// Return the LLVM function that this machine code represents + Function &getFunction() { return F; } + /// Return the LLVM function that this machine code represents const Function &getFunction() const { return F; } diff --git a/llvm/include/llvm/CodeGen/MachineModuleInfo.h b/llvm/include/llvm/CodeGen/MachineModuleInfo.h index 6902dada2423a..4aa5f03960ce1 100644 --- a/llvm/include/llvm/CodeGen/MachineModuleInfo.h +++ b/llvm/include/llvm/CodeGen/MachineModuleInfo.h @@ -165,9 +165,9 @@ class MachineModuleInfo { /// Returns the MachineFunction constructed for the IR function \p F. /// Creates a new MachineFunction if none exists yet. - MachineFunction &getOrCreateMachineFunction(const Function &F); + MachineFunction &getOrCreateMachineFunction(Function &F); - /// \bried Returns the MachineFunction associated to IR function \p F if there + /// \brief Returns the MachineFunction associated to IR function \p F if there /// is one, otherwise nullptr. MachineFunction *getMachineFunction(const Function &F) const; diff --git a/llvm/include/llvm/CodeGen/Passes.h b/llvm/include/llvm/CodeGen/Passes.h index 4e3451d80572b..9819543ec0d19 100644 --- a/llvm/include/llvm/CodeGen/Passes.h +++ b/llvm/include/llvm/CodeGen/Passes.h @@ -466,6 +466,14 @@ namespace llvm { /// Create IR Type Promotion pass. \see TypePromotion.cpp FunctionPass *createTypePromotionPass(); + /// Creates MIR Debugify pass. \see MachineDebugify.cpp + ModulePass *createDebugifyMachineModulePass(); + + /// Creates MIR Strip Debug pass. \see MachineStripDebug.cpp + /// If OnlyDebugified is true then it will only strip debug info if it was + /// added by a Debugify pass. The module will be left unchanged if the debug + /// info was generated by another source such as clang. + ModulePass *createStripDebugMachineModulePass(bool OnlyDebugified); } // End llvm namespace #endif diff --git a/llvm/include/llvm/CodeGen/TargetPassConfig.h b/llvm/include/llvm/CodeGen/TargetPassConfig.h index d48fc664c1c3d..3a4c09163f325 100644 --- a/llvm/include/llvm/CodeGen/TargetPassConfig.h +++ b/llvm/include/llvm/CodeGen/TargetPassConfig.h @@ -103,6 +103,7 @@ class TargetPassConfig : public ImmutablePass { bool Started = true; bool Stopped = false; bool AddingMachinePasses = false; + bool DebugifyIsSafe = true; /// Set the StartAfter, StartBefore and StopAfter passes to allow running only /// a portion of the normal code-gen pass sequence. @@ -306,6 +307,21 @@ class TargetPassConfig : public ImmutablePass { /// verification is enabled. void addVerifyPass(const std::string &Banner); + /// Add a pass to add synthesized debug info to the MIR. + void addDebugifyPass(); + + /// Add a pass to remove debug info from the MIR. + void addStripDebugPass(); + + /// Add standard passes before a pass that's about to be added. For example, + /// the DebugifyMachineModulePass if it is enabled. + void addMachinePrePasses(bool AllowDebugify = true); + + /// Add standard passes after a pass that has just been added. For example, + /// the MachineVerifier if it is enabled. + void addMachinePostPasses(const std::string &Banner, bool AllowPrint = true, + bool AllowVerify = true, bool AllowStrip = true); + /// Check whether or not GlobalISel should abort on error. /// When this is disabled, GlobalISel will fall back on SDISel instead of /// erroring out. diff --git a/llvm/include/llvm/IR/BasicBlock.h b/llvm/include/llvm/IR/BasicBlock.h index d594145f8636c..24bc740d32204 100644 --- a/llvm/include/llvm/IR/BasicBlock.h +++ b/llvm/include/llvm/IR/BasicBlock.h @@ -393,7 +393,9 @@ class BasicBlock final : public Value, // Basic blocks are data objects also /// Returns true if there are any uses of this basic block other than /// direct branches, switches, etc. to it. - bool hasAddressTaken() const { return getSubclassDataFromValue() != 0; } + bool hasAddressTaken() const { + return getBasicBlockBits().BlockAddressRefCount != 0; + } /// Update all phi nodes in this basic block to refer to basic block \p New /// instead of basic block \p Old. @@ -428,16 +430,61 @@ class BasicBlock final : public Value, // Basic blocks are data objects also Optional getIrrLoopHeaderWeight() const; + /// Returns true if the Order field of child Instructions is valid. + bool isInstrOrderValid() const { + return getBasicBlockBits().InstrOrderValid; + } + + /// Mark instruction ordering invalid. Done on every instruction insert. + void invalidateOrders() { + validateInstrOrdering(); + BasicBlockBits Bits = getBasicBlockBits(); + Bits.InstrOrderValid = false; + setBasicBlockBits(Bits); + } + + /// Renumber instructions and mark the ordering as valid. + void renumberInstructions(); + + /// Returns false if the instruction ordering is incorrect in an debug build. + /// Always returns true when assertions are disabled. The method does not + /// assert internally so that we get better location info. + void validateInstrOrdering() const; + private: + /// Bitfield to help interpret the bits in Value::SubclassData. + struct BasicBlockBits { + unsigned short BlockAddressRefCount : 15; + unsigned short InstrOrderValid : 1; + }; + + /// Safely reinterpret the subclass data bits to a more useful form. + BasicBlockBits getBasicBlockBits() const { + static_assert(sizeof(BasicBlockBits) == sizeof(unsigned short), + "too many bits for Value::SubclassData"); + unsigned short ValueData = getSubclassDataFromValue(); + BasicBlockBits AsBits; + memcpy(&AsBits, &ValueData, sizeof(AsBits)); + return AsBits; + } + + /// Reinterpret our subclass bits and store them back into Value. + void setBasicBlockBits(BasicBlockBits AsBits) { + unsigned short D; + memcpy(&D, &AsBits, sizeof(D)); + Value::setValueSubclassData(D); + } + /// Increment the internal refcount of the number of BlockAddresses /// referencing this BasicBlock by \p Amt. /// /// This is almost always 0, sometimes one possibly, but almost never 2, and /// inconceivably 3 or more. void AdjustBlockAddressRefCount(int Amt) { - setValueSubclassData(getSubclassDataFromValue()+Amt); - assert((int)(signed char)getSubclassDataFromValue() >= 0 && - "Refcount wrap-around"); + BasicBlockBits Bits = getBasicBlockBits(); + Bits.BlockAddressRefCount += Amt; + setBasicBlockBits(Bits); + assert(Bits.BlockAddressRefCount < 255 && "Refcount wrap-around"); } /// Shadow Value::setValueSubclassData with a private forwarding method so @@ -454,6 +501,12 @@ DEFINE_SIMPLE_CONVERSION_FUNCTIONS(BasicBlock, LLVMBasicBlockRef) /// This assumes that \p It is not at the end of a block. BasicBlock::iterator skipDebugIntrinsics(BasicBlock::iterator It); +#ifdef NDEBUG +/// In release builds, this is a no-op. For !NDEBUG builds, the checks are +/// implemented in the .cpp file to avoid circular header deps. +inline void BasicBlock::validateInstrOrdering() const {} +#endif + } // end namespace llvm #endif // LLVM_IR_BASICBLOCK_H diff --git a/llvm/include/llvm/IR/DebugInfoMetadata.h b/llvm/include/llvm/IR/DebugInfoMetadata.h index d20b618be50ea..a70c98b2a7946 100644 --- a/llvm/include/llvm/IR/DebugInfoMetadata.h +++ b/llvm/include/llvm/IR/DebugInfoMetadata.h @@ -1601,6 +1601,13 @@ class DILocation : public MDNode { static const DILocation *getMergedLocation(const DILocation *LocA, const DILocation *LocB); + /// Try to combine the vector of locations passed as input in a single one. + /// This function applies getMergedLocation() repeatedly left-to-right. + /// + /// \p Locs: The locations to be merged. + static + const DILocation *getMergedLocations(ArrayRef Locs); + /// Returns the base discriminator for a given encoded discriminator \p D. static unsigned getBaseDiscriminatorFromDiscriminator(unsigned D) { return getUnsignedFromPrefixEncoding(D); diff --git a/llvm/include/llvm/IR/Instruction.h b/llvm/include/llvm/IR/Instruction.h index 3bfa0e4afc398..b15ececc677cc 100644 --- a/llvm/include/llvm/IR/Instruction.h +++ b/llvm/include/llvm/IR/Instruction.h @@ -45,6 +45,10 @@ class Instruction : public User, BasicBlock *Parent; DebugLoc DbgLoc; // 'dbg' Metadata cache. + /// Relative order of this instruction in its parent basic block. Used for + /// O(1) local dominance checks between instructions. + mutable unsigned Order = 0; + enum { /// This is a bit stored in the SubClassData field which indicates whether /// this instruction has metadata attached to it or not. @@ -117,6 +121,13 @@ class Instruction : public User, /// the basic block that MovePos lives in, right after MovePos. void moveAfter(Instruction *MovePos); + /// Given an instruction Other in the same basic block as this instruction, + /// return true if this instruction comes before Other. In this worst case, + /// this takes linear time in the number of instructions in the block. The + /// results are cached, so in common cases when the block remains unmodified, + /// it takes constant time. + bool comesBefore(const Instruction *Other) const; + //===--------------------------------------------------------------------===// // Subclass classification. //===--------------------------------------------------------------------===// @@ -738,6 +749,7 @@ class Instruction : public User, private: friend class SymbolTableListTraits; + friend class BasicBlock; // For renumbering. // Shadow Value::setValueSubclassData with a private forwarding method so that // subclasses cannot accidentally use it. diff --git a/llvm/include/llvm/IR/IntrinsicInst.h b/llvm/include/llvm/IR/IntrinsicInst.h index 42a5564a44880..90c3fbfc3655b 100644 --- a/llvm/include/llvm/IR/IntrinsicInst.h +++ b/llvm/include/llvm/IR/IntrinsicInst.h @@ -63,20 +63,26 @@ namespace llvm { } }; + /// Check if \p ID corresponds to a debug info intrinsic. + static inline bool isDbgInfoIntrinsic(Intrinsic::ID ID) { + switch (ID) { + case Intrinsic::dbg_declare: + case Intrinsic::dbg_value: + case Intrinsic::dbg_addr: + case Intrinsic::dbg_label: + return true; + default: + return false; + } + } + /// This is the common base class for debug info intrinsics. class DbgInfoIntrinsic : public IntrinsicInst { public: /// \name Casting methods /// @{ static bool classof(const IntrinsicInst *I) { - switch (I->getIntrinsicID()) { - case Intrinsic::dbg_declare: - case Intrinsic::dbg_value: - case Intrinsic::dbg_addr: - case Intrinsic::dbg_label: - return true; - default: return false; - } + return isDbgInfoIntrinsic(I->getIntrinsicID()); } static bool classof(const Value *V) { return isa(V) && classof(cast(V)); diff --git a/llvm/include/llvm/InitializePasses.h b/llvm/include/llvm/InitializePasses.h index b3c6abab97a0d..79459bdff959b 100644 --- a/llvm/include/llvm/InitializePasses.h +++ b/llvm/include/llvm/InitializePasses.h @@ -118,6 +118,7 @@ void initializeDSELegacyPassPass(PassRegistry&); void initializeDataFlowSanitizerPass(PassRegistry&); void initializeDeadInstEliminationPass(PassRegistry&); void initializeDeadMachineInstructionElimPass(PassRegistry&); +void initializeDebugifyMachineModulePass(PassRegistry &); void initializeDelinearizationPass(PassRegistry&); void initializeDemandedBitsWrapperPassPass(PassRegistry&); void initializeDependenceAnalysisPass(PassRegistry&); @@ -398,6 +399,7 @@ void initializeStraightLineStrengthReducePass(PassRegistry&); void initializeStripDeadDebugInfoPass(PassRegistry&); void initializeStripDeadPrototypesLegacyPassPass(PassRegistry&); void initializeStripDebugDeclarePass(PassRegistry&); +void initializeStripDebugMachineModulePass(PassRegistry &); void initializeStripGCRelocatesPass(PassRegistry&); void initializeStripNonDebugSymbolsPass(PassRegistry&); void initializeStripNonLineTableDebugInfoPass(PassRegistry&); diff --git a/llvm/include/llvm/Support/OptimalLayout.h b/llvm/include/llvm/Support/OptimalLayout.h new file mode 100644 index 0000000000000..870dc78791bb3 --- /dev/null +++ b/llvm/include/llvm/Support/OptimalLayout.h @@ -0,0 +1,130 @@ +//===-- OptimalLayout.h - Optimal data layout algorithm -----------*- C++ -*-=// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +/// +/// This file provides an interface for laying out a sequence of fields +/// as a struct in a way that attempts to minimizes the total space +/// requirements of the struct. +/// +/// The word "optimal" is a misnomer in several ways. First, minimizing +/// space usage doesn't necessarily yield optimal performance because it +/// may decrease locality. Second, there is no known efficient algorithm +/// that guarantees a minimal layout for arbitrary inputs. Nonetheless, +/// this algorithm is likely to produce much more compact layouts than +/// would be produced by just allocating space in a buffer. +/// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_SUPPORT_OPTIMALLAYOUT_H +#define LLVM_SUPPORT_OPTIMALLAYOUT_H + +#include "llvm/Support/Alignment.h" +#include "llvm/ADT/ArrayRef.h" +#include + +namespace llvm { + +/// A field in a structure. +struct OptimalLayoutField { + /// A special value for Offset indicating that the field can be moved + /// anywhere. + static constexpr uint64_t FlexibleOffset = ~(uint64_t)0; + + OptimalLayoutField(const void *Id, uint64_t Size, Align Alignment, + uint64_t FixedOffset = FlexibleOffset) + : Offset(FixedOffset), Size(Size), Id(Id), Alignment(Alignment) { + assert(Size > 0 && "adding an empty field to the layout"); + } + + /// The offset of this field in the final layout. If this is + /// initialized to FlexibleOffset, layout will overwrite it with + /// the assigned offset of the field. + uint64_t Offset; + + /// The required size of this field in bytes. Does not have to be + /// a multiple of Alignment. Must be non-zero. + uint64_t Size; + + /// A opaque value which uniquely identifies this field. + const void *Id; + + /// Private scratch space for the algorithm. The implementation + /// must treat this as uninitialized memory on entry. + void *Scratch; + + /// The required alignment of this field. + Align Alignment; + + /// Return true if this field has been assigned a fixed offset. + /// After layout, this will be true of all the fields. + bool hasFixedOffset() const { + return (Offset != FlexibleOffset); + } + + /// Given that this field has a fixed offset, return the offset + /// of the first byte following it. + uint64_t getEndOffset() const { + assert(hasFixedOffset()); + return Offset + Size; + } +}; + +/// Compute a layout for a struct containing the given fields, making a +/// best-effort attempt to minimize the amount of space required. +/// +/// Two features are supported which require a more careful solution +/// than the well-known "sort by decreasing alignment" solution: +/// +/// - Fields may be assigned a fixed offset in the layout. If there are +/// gaps among the fixed-offset fields, the algorithm may attempt +/// to allocate flexible-offset fields into those gaps. If that's +/// undesirable, the caller should "block out" those gaps by e.g. +/// just creating a single fixed-offset field that represents the +/// entire "header". +/// +/// - The size of a field is not required to be a multiple of, or even +/// greater than, the field's required alignment. The only constraint +/// on fields is that they must not be zero-sized. +/// +/// To simplify the implementation, any fixed-offset fields in the +/// layout must appear at the start of the field array, and they must +/// be ordered by increasing offset. +/// +/// The algorithm will produce a guaranteed-minimal layout with no +/// interior padding in the following "C-style" case: +/// +/// - every field's size is a multiple of its required alignment and +/// - either no fields have initially fixed offsets, or the fixed-offset +/// fields have no interior padding and end at an offset that is at +/// least as aligned as all the flexible-offset fields. +/// +/// Otherwise, while the algorithm will make a best-effort attempt to +/// avoid padding, it cannot guarantee a minimal layout, as there is +/// no known efficient algorithm for doing so. +/// +/// The layout produced by this algorithm may not be stable across LLVM +/// releases. Do not use this anywhere where ABI stability is required. +/// +/// Flexible-offset fields with the same size and alignment will be ordered +/// the same way they were in the initial array. Otherwise the current +/// algorithm makes no effort to preserve the initial order of +/// flexible-offset fields. +/// +/// On return, all fields will have been assigned a fixed offset, and the +/// array will be sorted in order of ascending offsets. Note that this +/// means that the fixed-offset fields may no longer form a strict prefix +/// if there's any padding before they end. +/// +/// The return value is the total size of the struct and its required +/// alignment. Note that the total size is not rounded up to a multiple +/// of the required alignment; clients which require this can do so easily. +std::pair +performOptimalLayout(MutableArrayRef Fields); + +} // namespace llvm + +#endif diff --git a/llvm/include/llvm/Transforms/Utils/Debugify.h b/llvm/include/llvm/Transforms/Utils/Debugify.h index 0b5ec738750db..6f11d0a7d0624 100644 --- a/llvm/include/llvm/Transforms/Utils/Debugify.h +++ b/llvm/include/llvm/Transforms/Utils/Debugify.h @@ -17,6 +17,28 @@ #include "llvm/ADT/MapVector.h" #include "llvm/IR/PassManager.h" +namespace llvm { +class DIBuilder; + +/// Add synthesized debug information to a module. +/// +/// \param M The module to add debug information to. +/// \param Functions A range of functions to add debug information to. +/// \param Banner A prefix string to add to debug/error messages. +/// \param ApplyToMF A call back that will add debug information to the +/// MachineFunction for a Function. If nullptr, then the +/// MachineFunction (if any) will not be modified. +bool applyDebugifyMetadata( + Module &M, iterator_range Functions, StringRef Banner, + std::function ApplyToMF); + +/// Strip out all of the metadata and debug info inserted by debugify. If no +/// llvm.debugify module-level named metadata is present, this is a no-op. +/// Returns true if any change was made. +bool stripDebugifyMetadata(Module &M); + +} // namespace llvm + llvm::ModulePass *createDebugifyModulePass(); llvm::FunctionPass *createDebugifyFunctionPass(); diff --git a/llvm/lib/Analysis/AliasAnalysis.cpp b/llvm/lib/Analysis/AliasAnalysis.cpp index 1c7678a602d81..3f05b6146feff 100644 --- a/llvm/lib/Analysis/AliasAnalysis.cpp +++ b/llvm/lib/Analysis/AliasAnalysis.cpp @@ -631,16 +631,14 @@ ModRefInfo AAResults::getModRefInfo(const AtomicRMWInst *RMW, /// Return information about whether a particular call site modifies /// or reads the specified memory location \p MemLoc before instruction \p I -/// in a BasicBlock. An ordered basic block \p OBB can be used to speed up -/// instruction-ordering queries inside the BasicBlock containing \p I. +/// in a BasicBlock. /// FIXME: this is really just shoring-up a deficiency in alias analysis. /// BasicAA isn't willing to spend linear time determining whether an alloca /// was captured before or after this particular call, while we are. However, /// with a smarter AA in place, this test is just wasting compile time. ModRefInfo AAResults::callCapturesBefore(const Instruction *I, const MemoryLocation &MemLoc, - DominatorTree *DT, - OrderedBasicBlock *OBB) { + DominatorTree *DT) { if (!DT) return ModRefInfo::ModRef; @@ -656,8 +654,7 @@ ModRefInfo AAResults::callCapturesBefore(const Instruction *I, if (PointerMayBeCapturedBefore(Object, /* ReturnCaptures */ true, /* StoreCaptures */ true, I, DT, - /* include Object */ true, - /* OrderedBasicBlock */ OBB)) + /* include Object */ true)) return ModRefInfo::ModRef; unsigned ArgNo = 0; diff --git a/llvm/lib/Analysis/CMakeLists.txt b/llvm/lib/Analysis/CMakeLists.txt index cc9ff0bc1f570..34140e18677d2 100644 --- a/llvm/lib/Analysis/CMakeLists.txt +++ b/llvm/lib/Analysis/CMakeLists.txt @@ -70,7 +70,6 @@ add_llvm_component_library(LLVMAnalysis ObjCARCAnalysisUtils.cpp ObjCARCInstKind.cpp OptimizationRemarkEmitter.cpp - OrderedBasicBlock.cpp OrderedInstructions.cpp PHITransAddr.cpp PhiValues.cpp diff --git a/llvm/lib/Analysis/CallGraph.cpp b/llvm/lib/Analysis/CallGraph.cpp index 8e8a50178518d..3d4c9930920c6 100644 --- a/llvm/lib/Analysis/CallGraph.cpp +++ b/llvm/lib/Analysis/CallGraph.cpp @@ -11,6 +11,7 @@ #include "llvm/ADT/SmallVector.h" #include "llvm/Config/llvm-config.h" #include "llvm/IR/Function.h" +#include "llvm/IR/IntrinsicInst.h" #include "llvm/IR/Intrinsics.h" #include "llvm/IR/Module.h" #include "llvm/IR/PassManager.h" @@ -31,9 +32,10 @@ using namespace llvm; CallGraph::CallGraph(Module &M) : M(M), ExternalCallingNode(getOrInsertFunction(nullptr)), CallsExternalNode(std::make_unique(nullptr)) { - // Add every function to the call graph. + // Add every interesting function to the call graph. for (Function &F : M) - addToCallGraph(&F); + if (!isDbgInfoIntrinsic(F.getIntrinsicID())) + addToCallGraph(&F); } CallGraph::CallGraph(CallGraph &&Arg) diff --git a/llvm/lib/Analysis/CaptureTracking.cpp b/llvm/lib/Analysis/CaptureTracking.cpp index 20e2f06540a38..3d1f266a2e578 100644 --- a/llvm/lib/Analysis/CaptureTracking.cpp +++ b/llvm/lib/Analysis/CaptureTracking.cpp @@ -20,7 +20,6 @@ #include "llvm/ADT/SmallVector.h" #include "llvm/Analysis/AliasAnalysis.h" #include "llvm/Analysis/CFG.h" -#include "llvm/Analysis/OrderedBasicBlock.h" #include "llvm/Analysis/ValueTracking.h" #include "llvm/IR/Constants.h" #include "llvm/IR/Dominators.h" @@ -76,8 +75,8 @@ namespace { struct CapturesBefore : public CaptureTracker { CapturesBefore(bool ReturnCaptures, const Instruction *I, const DominatorTree *DT, - bool IncludeI, OrderedBasicBlock *IC) - : OrderedBB(IC), BeforeHere(I), DT(DT), + bool IncludeI) + : BeforeHere(I), DT(DT), ReturnCaptures(ReturnCaptures), IncludeI(IncludeI), Captured(false) {} void tooManyUses() override { Captured = true; } @@ -90,9 +89,7 @@ namespace { return true; // Compute the case where both instructions are inside the same basic - // block. Since instructions in the same BB as BeforeHere are numbered in - // 'OrderedBB', avoid using 'dominates' and 'isPotentiallyReachable' - // which are very expensive for large basic blocks. + // block. if (BB == BeforeHere->getParent()) { // 'I' dominates 'BeforeHere' => not safe to prune. // @@ -102,7 +99,7 @@ namespace { // UseBB == BB, avoid pruning. if (isa(BeforeHere) || isa(I) || I == BeforeHere) return false; - if (!OrderedBB->dominates(BeforeHere, I)) + if (!BeforeHere->comesBefore(I)) return false; // 'BeforeHere' comes before 'I', it's safe to prune if we also @@ -153,7 +150,6 @@ namespace { return true; } - OrderedBasicBlock *OrderedBB; const Instruction *BeforeHere; const DominatorTree *DT; @@ -196,31 +192,23 @@ bool llvm::PointerMayBeCaptured(const Value *V, /// returning the value (or part of it) from the function counts as capturing /// it or not. The boolean StoreCaptures specified whether storing the value /// (or part of it) into memory anywhere automatically counts as capturing it -/// or not. A ordered basic block \p OBB can be used in order to speed up -/// queries about relative order among instructions in the same basic block. +/// or not. bool llvm::PointerMayBeCapturedBefore(const Value *V, bool ReturnCaptures, bool StoreCaptures, const Instruction *I, const DominatorTree *DT, bool IncludeI, - OrderedBasicBlock *OBB, unsigned MaxUsesToExplore) { assert(!isa(V) && "It doesn't make sense to ask whether a global is captured."); - bool UseNewOBB = OBB == nullptr; if (!DT) return PointerMayBeCaptured(V, ReturnCaptures, StoreCaptures, MaxUsesToExplore); - if (UseNewOBB) - OBB = new OrderedBasicBlock(I->getParent()); // TODO: See comment in PointerMayBeCaptured regarding what could be done // with StoreCaptures. - CapturesBefore CB(ReturnCaptures, I, DT, IncludeI, OBB); + CapturesBefore CB(ReturnCaptures, I, DT, IncludeI); PointerMayBeCaptured(V, &CB, MaxUsesToExplore); - - if (UseNewOBB) - delete OBB; return CB.Captured; } diff --git a/llvm/lib/Analysis/InstructionPrecedenceTracking.cpp b/llvm/lib/Analysis/InstructionPrecedenceTracking.cpp index 415797d6a3783..3f5a161c8659f 100644 --- a/llvm/lib/Analysis/InstructionPrecedenceTracking.cpp +++ b/llvm/lib/Analysis/InstructionPrecedenceTracking.cpp @@ -104,18 +104,14 @@ void InstructionPrecedenceTracking::insertInstructionTo(const Instruction *Inst, const BasicBlock *BB) { if (isSpecialInstruction(Inst)) FirstSpecialInsts.erase(BB); - OI.invalidateBlock(BB); } void InstructionPrecedenceTracking::removeInstruction(const Instruction *Inst) { if (isSpecialInstruction(Inst)) FirstSpecialInsts.erase(Inst->getParent()); - OI.invalidateBlock(Inst->getParent()); } void InstructionPrecedenceTracking::clear() { - for (auto It : FirstSpecialInsts) - OI.invalidateBlock(It.first); FirstSpecialInsts.clear(); #ifndef NDEBUG // The map should be valid after clearing (at least empty). diff --git a/llvm/lib/Analysis/MemoryDependenceAnalysis.cpp b/llvm/lib/Analysis/MemoryDependenceAnalysis.cpp index a97a56e258050..8a08bdc4949b8 100644 --- a/llvm/lib/Analysis/MemoryDependenceAnalysis.cpp +++ b/llvm/lib/Analysis/MemoryDependenceAnalysis.cpp @@ -23,7 +23,6 @@ #include "llvm/Analysis/AssumptionCache.h" #include "llvm/Analysis/MemoryBuiltins.h" #include "llvm/Analysis/MemoryLocation.h" -#include "llvm/Analysis/OrderedBasicBlock.h" #include "llvm/Analysis/PHITransAddr.h" #include "llvm/Analysis/PhiValues.h" #include "llvm/Analysis/TargetLibraryInfo.h" @@ -327,8 +326,7 @@ static bool isVolatile(Instruction *Inst) { MemDepResult MemoryDependenceResults::getPointerDependencyFrom( const MemoryLocation &MemLoc, bool isLoad, BasicBlock::iterator ScanIt, - BasicBlock *BB, Instruction *QueryInst, unsigned *Limit, - OrderedBasicBlock *OBB) { + BasicBlock *BB, Instruction *QueryInst, unsigned *Limit) { MemDepResult InvariantGroupDependency = MemDepResult::getUnknown(); if (QueryInst != nullptr) { if (auto *LI = dyn_cast(QueryInst)) { @@ -339,7 +337,7 @@ MemDepResult MemoryDependenceResults::getPointerDependencyFrom( } } MemDepResult SimpleDep = getSimplePointerDependencyFrom( - MemLoc, isLoad, ScanIt, BB, QueryInst, Limit, OBB); + MemLoc, isLoad, ScanIt, BB, QueryInst, Limit); if (SimpleDep.isDef()) return SimpleDep; // Non-local invariant group dependency indicates there is non local Def @@ -440,8 +438,7 @@ MemoryDependenceResults::getInvariantGroupPointerDependency(LoadInst *LI, MemDepResult MemoryDependenceResults::getSimplePointerDependencyFrom( const MemoryLocation &MemLoc, bool isLoad, BasicBlock::iterator ScanIt, - BasicBlock *BB, Instruction *QueryInst, unsigned *Limit, - OrderedBasicBlock *OBB) { + BasicBlock *BB, Instruction *QueryInst, unsigned *Limit) { bool isInvariantLoad = false; unsigned DefaultLimit = getDefaultBlockScanLimit(); @@ -488,15 +485,6 @@ MemDepResult MemoryDependenceResults::getSimplePointerDependencyFrom( const DataLayout &DL = BB->getModule()->getDataLayout(); - // If the caller did not provide an ordered basic block, - // create one to lazily compute and cache instruction - // positions inside a BB. This is used to provide fast queries for relative - // position between two instructions in a BB and can be used by - // AliasAnalysis::callCapturesBefore. - OrderedBasicBlock OBBTmp(BB); - if (!OBB) - OBB = &OBBTmp; - // Return "true" if and only if the instruction I is either a non-simple // load or a non-simple store. auto isNonSimpleLoadOrStore = [](Instruction *I) -> bool { @@ -686,7 +674,7 @@ MemDepResult MemoryDependenceResults::getSimplePointerDependencyFrom( ModRefInfo MR = AA.getModRefInfo(Inst, MemLoc); // If necessary, perform additional analysis. if (isModAndRefSet(MR)) - MR = AA.callCapturesBefore(Inst, MemLoc, &DT, OBB); + MR = AA.callCapturesBefore(Inst, MemLoc, &DT); switch (clearMust(MR)) { case ModRefInfo::NoModRef: // If the call has no effect on the queried pointer, just ignore it. @@ -712,8 +700,7 @@ MemDepResult MemoryDependenceResults::getSimplePointerDependencyFrom( return MemDepResult::getNonFuncLocal(); } -MemDepResult MemoryDependenceResults::getDependency(Instruction *QueryInst, - OrderedBasicBlock *OBB) { +MemDepResult MemoryDependenceResults::getDependency(Instruction *QueryInst) { Instruction *ScanPos = QueryInst; // Check for a cached result @@ -753,7 +740,7 @@ MemDepResult MemoryDependenceResults::getDependency(Instruction *QueryInst, LocalCache = getPointerDependencyFrom(MemLoc, isLoad, ScanPos->getIterator(), - QueryParent, QueryInst, nullptr, OBB); + QueryParent, QueryInst, nullptr); } else if (auto *QueryCall = dyn_cast(QueryInst)) { bool isReadOnly = AA.onlyReadsMemory(QueryCall); LocalCache = getCallDependencyFrom(QueryCall, isReadOnly, diff --git a/llvm/lib/Analysis/OrderedBasicBlock.cpp b/llvm/lib/Analysis/OrderedBasicBlock.cpp deleted file mode 100644 index 48f2a4020c666..0000000000000 --- a/llvm/lib/Analysis/OrderedBasicBlock.cpp +++ /dev/null @@ -1,111 +0,0 @@ -//===- OrderedBasicBlock.cpp --------------------------------- -*- C++ -*-===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// -// -// This file implements the OrderedBasicBlock class. OrderedBasicBlock -// maintains an interface where clients can query if one instruction comes -// before another in a BasicBlock. Since BasicBlock currently lacks a reliable -// way to query relative position between instructions one can use -// OrderedBasicBlock to do such queries. OrderedBasicBlock is lazily built on a -// source BasicBlock and maintains an internal Instruction -> Position map. A -// OrderedBasicBlock instance should be discarded whenever the source -// BasicBlock changes. -// -// It's currently used by the CaptureTracker in order to find relative -// positions of a pair of instructions inside a BasicBlock. -// -//===----------------------------------------------------------------------===// - -#include "llvm/Analysis/OrderedBasicBlock.h" -#include "llvm/IR/Instruction.h" -using namespace llvm; - -OrderedBasicBlock::OrderedBasicBlock(const BasicBlock *BasicB) - : NextInstPos(0), BB(BasicB) { - LastInstFound = BB->end(); -} - -/// Given no cached results, find if \p A comes before \p B in \p BB. -/// Cache and number out instruction while walking \p BB. -bool OrderedBasicBlock::comesBefore(const Instruction *A, - const Instruction *B) { - const Instruction *Inst = nullptr; - assert(!(LastInstFound == BB->end() && NextInstPos != 0) && - "Instruction supposed to be in NumberedInsts"); - assert(A->getParent() == BB && "Instruction supposed to be in the block!"); - assert(B->getParent() == BB && "Instruction supposed to be in the block!"); - - // Start the search with the instruction found in the last lookup round. - auto II = BB->begin(); - auto IE = BB->end(); - if (LastInstFound != IE) - II = std::next(LastInstFound); - - // Number all instructions up to the point where we find 'A' or 'B'. - for (; II != IE; ++II) { - Inst = cast(II); - NumberedInsts[Inst] = NextInstPos++; - if (Inst == A || Inst == B) - break; - } - - assert(II != IE && "Instruction not found?"); - assert((Inst == A || Inst == B) && "Should find A or B"); - LastInstFound = II; - return Inst != B; -} - -/// Find out whether \p A dominates \p B, meaning whether \p A -/// comes before \p B in \p BB. This is a simplification that considers -/// cached instruction positions and ignores other basic blocks, being -/// only relevant to compare relative instructions positions inside \p BB. -bool OrderedBasicBlock::dominates(const Instruction *A, const Instruction *B) { - assert(A->getParent() == B->getParent() && - "Instructions must be in the same basic block!"); - assert(A->getParent() == BB && "Instructions must be in the tracked block!"); - - // First we lookup the instructions. If they don't exist, lookup will give us - // back ::end(). If they both exist, we compare the numbers. Otherwise, if NA - // exists and NB doesn't, it means NA must come before NB because we would - // have numbered NB as well if it didn't. The same is true for NB. If it - // exists, but NA does not, NA must come after it. If neither exist, we need - // to number the block and cache the results (by calling comesBefore). - auto NAI = NumberedInsts.find(A); - auto NBI = NumberedInsts.find(B); - if (NAI != NumberedInsts.end() && NBI != NumberedInsts.end()) - return NAI->second < NBI->second; - if (NAI != NumberedInsts.end()) - return true; - if (NBI != NumberedInsts.end()) - return false; - - return comesBefore(A, B); -} - -void OrderedBasicBlock::eraseInstruction(const Instruction *I) { - if (LastInstFound != BB->end() && I == &*LastInstFound) { - if (LastInstFound == BB->begin()) { - LastInstFound = BB->end(); - NextInstPos = 0; - } else - LastInstFound--; - } - - NumberedInsts.erase(I); -} - -void OrderedBasicBlock::replaceInstruction(const Instruction *Old, - const Instruction *New) { - auto OI = NumberedInsts.find(Old); - if (OI == NumberedInsts.end()) - return; - - NumberedInsts.insert({New, OI->second}); - if (LastInstFound != BB->end() && Old == &*LastInstFound) - LastInstFound = New->getIterator(); - NumberedInsts.erase(Old); -} diff --git a/llvm/lib/Analysis/OrderedInstructions.cpp b/llvm/lib/Analysis/OrderedInstructions.cpp index e947e5e388a83..11ab3e0927d2e 100644 --- a/llvm/lib/Analysis/OrderedInstructions.cpp +++ b/llvm/lib/Analysis/OrderedInstructions.cpp @@ -18,16 +18,11 @@ bool OrderedInstructions::localDominates(const Instruction *InstA, assert(InstA->getParent() == InstB->getParent() && "Instructions must be in the same basic block"); - const BasicBlock *IBB = InstA->getParent(); - auto OBB = OBBMap.find(IBB); - if (OBB == OBBMap.end()) - OBB = OBBMap.insert({IBB, std::make_unique(IBB)}).first; - return OBB->second->dominates(InstA, InstB); + return InstA->comesBefore(InstB); } -/// Given 2 instructions, use OrderedBasicBlock to check for dominance relation -/// if the instructions are in the same basic block, Otherwise, use dominator -/// tree. +/// Given 2 instructions, check for dominance relation if the instructions are +/// in the same basic block. Otherwise, use dominator tree. bool OrderedInstructions::dominates(const Instruction *InstA, const Instruction *InstB) const { // Use ordered basic block to do dominance check in case the 2 instructions diff --git a/llvm/lib/CodeGen/AsmPrinter/DwarfCompileUnit.cpp b/llvm/lib/CodeGen/AsmPrinter/DwarfCompileUnit.cpp index 075b75effa709..f97bf71e06607 100644 --- a/llvm/lib/CodeGen/AsmPrinter/DwarfCompileUnit.cpp +++ b/llvm/lib/CodeGen/AsmPrinter/DwarfCompileUnit.cpp @@ -904,13 +904,12 @@ void DwarfCompileUnit::constructAbstractSubprogramScopeDIE( ContextCU->addDIEEntry(*AbsDef, dwarf::DW_AT_object_pointer, *ObjectPointer); } -/// Whether to use the GNU analog for a DWARF5 tag, attribute, or location atom. -static bool useGNUAnalogForDwarf5Feature(DwarfDebug *DD) { +bool DwarfCompileUnit::useGNUAnalogForDwarf5Feature() const { return DD->getDwarfVersion() == 4 && DD->tuneForGDB(); } dwarf::Tag DwarfCompileUnit::getDwarf5OrGNUTag(dwarf::Tag Tag) const { - if (!useGNUAnalogForDwarf5Feature(DD)) + if (!useGNUAnalogForDwarf5Feature()) return Tag; switch (Tag) { case dwarf::DW_TAG_call_site: @@ -924,7 +923,7 @@ dwarf::Tag DwarfCompileUnit::getDwarf5OrGNUTag(dwarf::Tag Tag) const { dwarf::Attribute DwarfCompileUnit::getDwarf5OrGNUAttr(dwarf::Attribute Attr) const { - if (!useGNUAnalogForDwarf5Feature(DD)) + if (!useGNUAnalogForDwarf5Feature()) return Attr; switch (Attr) { case dwarf::DW_AT_call_all_calls: @@ -946,7 +945,7 @@ DwarfCompileUnit::getDwarf5OrGNUAttr(dwarf::Attribute Attr) const { dwarf::LocationAtom DwarfCompileUnit::getDwarf5OrGNULocationAtom(dwarf::LocationAtom Loc) const { - if (!useGNUAnalogForDwarf5Feature(DD)) + if (!useGNUAnalogForDwarf5Feature()) return Loc; switch (Loc) { case dwarf::DW_OP_entry_value: @@ -960,6 +959,7 @@ DIE &DwarfCompileUnit::constructCallSiteEntryDIE(DIE &ScopeDIE, DIE *CalleeDIE, bool IsTail, const MCSymbol *PCAddr, + const MCSymbol *CallAddr, unsigned CallReg) { // Insert a call site entry DIE within ScopeDIE. DIE &CallSiteDIE = createAndAddDIE(getDwarf5OrGNUTag(dwarf::DW_TAG_call_site), @@ -975,16 +975,33 @@ DIE &DwarfCompileUnit::constructCallSiteEntryDIE(DIE &ScopeDIE, *CalleeDIE); } - if (IsTail) + if (IsTail) { // Attach DW_AT_call_tail_call to tail calls for standards compliance. addFlag(CallSiteDIE, getDwarf5OrGNUAttr(dwarf::DW_AT_call_tail_call)); + // Attach the address of the branch instruction to allow the debugger to + // show where the tail call occurred. This attribute has no GNU analog. + // + // GDB works backwards from non-standard usage of DW_AT_low_pc (in DWARF4 + // mode -- equivalently, in DWARF5 mode, DW_AT_call_return_pc) at tail-call + // site entries to figure out the PC of tail-calling branch instructions. + // This means it doesn't need the compiler to emit DW_AT_call_pc, so we + // don't emit it here. + // + // There's no need to tie non-GDB debuggers to this non-standardness, as it + // adds unnecessary complexity to the debugger. For non-GDB debuggers, emit + // the standard DW_AT_call_pc info. + if (!useGNUAnalogForDwarf5Feature()) + addLabelAddress(CallSiteDIE, dwarf::DW_AT_call_pc, CallAddr); + } + // Attach the return PC to allow the debugger to disambiguate call paths // from one function to another. // // The return PC is only really needed when the call /isn't/ a tail call, but - // for some reason GDB always expects it. - if (!IsTail || DD->tuneForGDB()) { + // GDB expects it in DWARF4 mode, even for tail calls (see the comment above + // the DW_AT_call_pc emission logic for an explanation). + if (!IsTail || useGNUAnalogForDwarf5Feature()) { assert(PCAddr && "Missing return PC information for a call"); addLabelAddress(CallSiteDIE, getDwarf5OrGNUAttr(dwarf::DW_AT_call_return_pc), PCAddr); diff --git a/llvm/lib/CodeGen/AsmPrinter/DwarfCompileUnit.h b/llvm/lib/CodeGen/AsmPrinter/DwarfCompileUnit.h index 52e1c71a8e653..5d0afee4c3df0 100644 --- a/llvm/lib/CodeGen/AsmPrinter/DwarfCompileUnit.h +++ b/llvm/lib/CodeGen/AsmPrinter/DwarfCompileUnit.h @@ -230,6 +230,10 @@ class DwarfCompileUnit final : public DwarfUnit { void constructAbstractSubprogramScopeDIE(LexicalScope *Scope); + /// Whether to use the GNU analog for a DWARF5 tag, attribute, or location + /// atom. Only applicable when emitting otherwise DWARF4-compliant debug info. + bool useGNUAnalogForDwarf5Feature() const; + /// This takes a DWARF 5 tag and returns it or a GNU analog. dwarf::Tag getDwarf5OrGNUTag(dwarf::Tag Tag) const; @@ -245,10 +249,12 @@ class DwarfCompileUnit final : public DwarfUnit { /// For indirect calls \p CalleeDIE is set to nullptr. /// \p IsTail specifies whether the call is a tail call. /// \p PCAddr points to the PC value after the call instruction. + /// \p CallAddr points to the PC value at the call instruction (or is null). /// \p CallReg is a register location for an indirect call. For direct calls /// the \p CallReg is set to 0. DIE &constructCallSiteEntryDIE(DIE &ScopeDIE, DIE *CalleeDIE, bool IsTail, - const MCSymbol *PCAddr, unsigned CallReg); + const MCSymbol *PCAddr, + const MCSymbol *CallAddr, unsigned CallReg); /// Construct call site parameter DIEs for the \p CallSiteDIE. The \p Params /// were collected by the \ref collectCallSiteParameters. /// Note: The order of parameters does not matter, since debuggers recognize diff --git a/llvm/lib/CodeGen/AsmPrinter/DwarfDebug.cpp b/llvm/lib/CodeGen/AsmPrinter/DwarfDebug.cpp index bb718fd33647b..a5589d78c21d3 100644 --- a/llvm/lib/CodeGen/AsmPrinter/DwarfDebug.cpp +++ b/llvm/lib/CodeGen/AsmPrinter/DwarfDebug.cpp @@ -572,6 +572,18 @@ struct FwdRegParamInfo { /// Register worklist for finding call site values. using FwdRegWorklist = MapVector>; +/// Append the expression \p Addition to \p Original and return the result. +static const DIExpression *combineDIExpressions(const DIExpression *Original, + const DIExpression *Addition) { + std::vector Elts = Addition->getElements().vec(); + // Avoid multiple DW_OP_stack_values. + if (Original->isImplicit() && Addition->isImplicit()) + erase_if(Elts, [](uint64_t Op) { return Op == dwarf::DW_OP_stack_value; }); + const DIExpression *CombinedExpr = + (Elts.size() > 0) ? DIExpression::append(Original, Elts) : Original; + return CombinedExpr; +} + /// Emit call site parameter entries that are described by the given value and /// debug expression. template @@ -591,9 +603,8 @@ static void finishCallSiteParams(ValT Val, const DIExpression *Expr, // parameter when walking through the instructions. Append that to the // base expression. const DIExpression *CombinedExpr = - ShouldCombineExpressions - ? DIExpression::append(Expr, Param.Expr->getElements()) - : Expr; + ShouldCombineExpressions ? combineDIExpressions(Expr, Param.Expr) + : Expr; assert((!CombinedExpr || CombinedExpr->isValid()) && "Combined debug expression is invalid"); @@ -623,12 +634,7 @@ static void addToFwdRegWorklist(FwdRegWorklist &Worklist, unsigned Reg, // instructions we may have already created an expression for the // parameter when walking through the instructions. Append that to the // new expression. - const DIExpression *CombinedExpr = - (Param.Expr->getNumElements() > 0) - ? DIExpression::append(Expr, Param.Expr->getElements()) - : Expr; - assert(CombinedExpr->isValid() && "Combined debug expression is invalid"); - + const DIExpression *CombinedExpr = combineDIExpressions(Expr, Param.Expr); ParamsForFwdReg.push_back({Param.ParamReg, CombinedExpr}); } } @@ -872,16 +878,21 @@ void DwarfDebug::constructCallSiteEntryDIEs(const DISubprogram &SP, const MachineInstr *TopLevelCallMI = MI.isInsideBundle() ? &*getBundleStart(MI.getIterator()) : &MI; - // For tail calls, no return PC information is needed. - // For regular calls (and tail calls in GDB tuning), the return PC - // is needed to disambiguate paths in the call graph which could lead to - // some target function. + // For non-tail calls, the return PC is needed to disambiguate paths in + // the call graph which could lead to some target function. For tail + // calls, no return PC information is needed, unless tuning for GDB in + // DWARF4 mode in which case we fake a return PC for compatibility. const MCSymbol *PCAddr = - (IsTail && !tuneForGDB()) - ? nullptr - : const_cast(getLabelAfterInsn(TopLevelCallMI)); + (!IsTail || CU.useGNUAnalogForDwarf5Feature()) + ? const_cast(getLabelAfterInsn(TopLevelCallMI)) + : nullptr; + + // For tail calls, it's necessary to record the address of the branch + // instruction so that the debugger can show where the tail call occurred. + const MCSymbol *CallAddr = + IsTail ? getLabelBeforeInsn(TopLevelCallMI) : nullptr; - assert((IsTail || PCAddr) && "Call without return PC information"); + assert((IsTail || PCAddr) && "Non-tail call without return PC"); LLVM_DEBUG(dbgs() << "CallSiteEntry: " << MF.getName() << " -> " << (CalleeDecl ? CalleeDecl->getName() @@ -890,8 +901,8 @@ void DwarfDebug::constructCallSiteEntryDIEs(const DISubprogram &SP, ->getName(CallReg))) << (IsTail ? " [IsTail]" : "") << "\n"); - DIE &CallSiteDIE = CU.constructCallSiteEntryDIE(ScopeDIE, CalleeDIE, - IsTail, PCAddr, CallReg); + DIE &CallSiteDIE = CU.constructCallSiteEntryDIE( + ScopeDIE, CalleeDIE, IsTail, PCAddr, CallAddr, CallReg); // Optionally emit call-site-param debug info. if (emitDebugEntryValues()) { @@ -1458,11 +1469,24 @@ static bool validThroughout(LexicalScopes &LScopes, if (LSRange.size() == 0) return false; + // If this range is neither open ended nor a constant, then it is not a + // candidate for being validThroughout. + if (RangeEnd && !DbgValue->getOperand(0).isImm()) + return false; + // Determine if the DBG_VALUE is valid at the beginning of its lexical block. const MachineInstr *LScopeBegin = LSRange.front().first; // Early exit if the lexical scope begins outside of the current block. if (LScopeBegin->getParent() != MBB) return false; + + // If there are instructions belonging to our scope in another block, and + // we're not a constant (see DWARF2 comment below), then we can't be + // validThroughout. + const MachineInstr *LScopeEnd = LSRange.back().second; + if (RangeEnd && LScopeEnd->getParent() != MBB) + return false; + MachineBasicBlock::const_reverse_iterator Pred(DbgValue); for (++Pred; Pred != MBB->rend(); ++Pred) { if (Pred->getFlag(MachineInstr::FrameSetup)) @@ -1483,11 +1507,6 @@ static bool validThroughout(LexicalScopes &LScopes, if (!RangeEnd) return true; - // Fail if there are instructions belonging to our scope in another block. - const MachineInstr *LScopeEnd = LSRange.back().second; - if (LScopeEnd->getParent() != MBB) - return false; - // Single, constant DBG_VALUEs in the prologue are promoted to be live // throughout the function. This is a hack, presumably for DWARF v2 and not // necessarily correct. It would be much better to use a dbg.declare instead @@ -1780,11 +1799,32 @@ void DwarfDebug::collectEntityInfo(DwarfCompileUnit &TheCU, // Process beginning of an instruction. void DwarfDebug::beginInstruction(const MachineInstr *MI) { + const MachineFunction &MF = *MI->getMF(); + const auto *SP = MF.getFunction().getSubprogram(); + bool NoDebug = + !SP || SP->getUnit()->getEmissionKind() == DICompileUnit::NoDebug; + + // When describing calls, we need a label for the call instruction. + // TODO: Add support for targets with delay slots. + if (!NoDebug && SP->areAllCallsDescribed() && + MI->isCandidateForCallSiteEntry(MachineInstr::AnyInBundle) && + !MI->hasDelaySlot()) { + const TargetInstrInfo *TII = MF.getSubtarget().getInstrInfo(); + bool IsTail = TII->isTailCall(*MI); + // For tail calls, we need the address of the branch instruction for + // DW_AT_call_pc. + if (IsTail) + requestLabelBeforeInsn(MI); + // For non-tail calls, we need the return address for the call for + // DW_AT_call_return_pc. Under GDB tuning, this information is needed for + // tail calls as well. + requestLabelAfterInsn(MI); + } + DebugHandlerBase::beginInstruction(MI); assert(CurMI); - const auto *SP = MI->getMF()->getFunction().getSubprogram(); - if (!SP || SP->getUnit()->getEmissionKind() == DICompileUnit::NoDebug) + if (NoDebug) return; // Check if source location changes, but ignore DBG_VALUE and CFI locations. @@ -1798,11 +1838,6 @@ void DwarfDebug::beginInstruction(const MachineInstr *MI) { unsigned LastAsmLine = Asm->OutStreamer->getContext().getCurrentDwarfLoc().getLine(); - // Request a label after the call in order to emit AT_return_pc information - // in call site entries. TODO: Add support for targets with delay slots. - if (SP->areAllCallsDescribed() && MI->isCall() && !MI->hasDelaySlot()) - requestLabelAfterInsn(MI); - if (DL == PrevInstLoc) { // If we have an ongoing unspecified location, nothing to do here. if (!DL) diff --git a/llvm/lib/CodeGen/CMakeLists.txt b/llvm/lib/CodeGen/CMakeLists.txt index 470b027e38c81..da2fa1b520af7 100644 --- a/llvm/lib/CodeGen/CMakeLists.txt +++ b/llvm/lib/CodeGen/CMakeLists.txt @@ -71,6 +71,7 @@ add_llvm_component_library(LLVMCodeGen MachineCombiner.cpp MachineCopyPropagation.cpp MachineCSE.cpp + MachineDebugify.cpp MachineDominanceFrontier.cpp MachineDominators.cpp MachineFrameInfo.cpp @@ -95,6 +96,7 @@ add_llvm_component_library(LLVMCodeGen MachineSink.cpp MachineSizeOpts.cpp MachineSSAUpdater.cpp + MachineStripDebug.cpp MachineTraceMetrics.cpp MachineVerifier.cpp ModuloSchedule.cpp diff --git a/llvm/lib/CodeGen/CodeGen.cpp b/llvm/lib/CodeGen/CodeGen.cpp index 20fc67cc66ae7..838142c062159 100644 --- a/llvm/lib/CodeGen/CodeGen.cpp +++ b/llvm/lib/CodeGen/CodeGen.cpp @@ -26,6 +26,7 @@ void llvm::initializeCodeGen(PassRegistry &Registry) { initializeCFIInstrInserterPass(Registry); initializeCodeGenPreparePass(Registry); initializeDeadMachineInstructionElimPass(Registry); + initializeDebugifyMachineModulePass(Registry); initializeDetectDeadLanesPass(Registry); initializeDwarfEHPreparePass(Registry); initializeEarlyIfConverterPass(Registry); @@ -102,6 +103,7 @@ void llvm::initializeCodeGen(PassRegistry &Registry) { initializeStackMapLivenessPass(Registry); initializeStackProtectorPass(Registry); initializeStackSlotColoringPass(Registry); + initializeStripDebugMachineModulePass(Registry); initializeTailDuplicatePass(Registry); initializeTargetPassConfigPass(Registry); initializeTwoAddressInstructionPassPass(Registry); diff --git a/llvm/lib/CodeGen/GlobalISel/LegalizerHelper.cpp b/llvm/lib/CodeGen/GlobalISel/LegalizerHelper.cpp index 53bda81d6a5e1..7f6b0d87d72f1 100644 --- a/llvm/lib/CodeGen/GlobalISel/LegalizerHelper.cpp +++ b/llvm/lib/CodeGen/GlobalISel/LegalizerHelper.cpp @@ -493,6 +493,7 @@ LegalizerHelper::libcall(MachineInstr &MI) { auto &Ctx = MIRBuilder.getMF().getFunction().getContext(); MIRBuilder.setInstr(MI); + MIRBuilder.setDebugLoc(MI.getDebugLoc()); switch (MI.getOpcode()) { default: @@ -598,6 +599,7 @@ LegalizerHelper::LegalizeResult LegalizerHelper::narrowScalar(MachineInstr &MI, unsigned TypeIdx, LLT NarrowTy) { MIRBuilder.setInstr(MI); + MIRBuilder.setDebugLoc(MI.getDebugLoc()); uint64_t SizeOp0 = MRI.getType(MI.getOperand(0).getReg()).getSizeInBits(); uint64_t NarrowSize = NarrowTy.getSizeInBits(); @@ -1428,6 +1430,7 @@ LegalizerHelper::widenScalarInsert(MachineInstr &MI, unsigned TypeIdx, LegalizerHelper::LegalizeResult LegalizerHelper::widenScalar(MachineInstr &MI, unsigned TypeIdx, LLT WideTy) { MIRBuilder.setInstr(MI); + MIRBuilder.setDebugLoc(MI.getDebugLoc()); switch (MI.getOpcode()) { default: @@ -1939,6 +1942,7 @@ LegalizerHelper::LegalizeResult LegalizerHelper::lower(MachineInstr &MI, unsigned TypeIdx, LLT Ty) { using namespace TargetOpcode; MIRBuilder.setInstr(MI); + MIRBuilder.setDebugLoc(MI.getDebugLoc()); switch(MI.getOpcode()) { default: @@ -2984,6 +2988,7 @@ LegalizerHelper::fewerElementsVector(MachineInstr &MI, unsigned TypeIdx, using namespace TargetOpcode; MIRBuilder.setInstr(MI); + MIRBuilder.setDebugLoc(MI.getDebugLoc()); switch (MI.getOpcode()) { case G_IMPLICIT_DEF: return fewerElementsVectorImplicitDef(MI, TypeIdx, NarrowTy); diff --git a/llvm/lib/CodeGen/LiveDebugValues.cpp b/llvm/lib/CodeGen/LiveDebugValues.cpp index a013c419b7c79..9816bd8f97ec5 100644 --- a/llvm/lib/CodeGen/LiveDebugValues.cpp +++ b/llvm/lib/CodeGen/LiveDebugValues.cpp @@ -110,7 +110,10 @@ static bool isRegOtherThanSPAndFP(const MachineOperand &Op, namespace { +// Max out the number of statically allocated elements in DefinedRegsSet, as +// this prevents fallback to std::set::count() operations. using DefinedRegsSet = SmallSet; + using VarLocSet = CoalescingBitVector; /// A type-checked pair of {Register Location (or 0), Index}, used to index @@ -482,7 +485,8 @@ class LiveDebugValues : public MachineFunctionPass { } }; - using VarLocInMBB = SmallDenseMap; + using VarLocInMBB = + SmallDenseMap>; struct TransferDebugPair { MachineInstr *TransferInst; ///< Instruction where this transfer occurs. LocIndex LocationID; ///< Location number for the transfer dest. @@ -562,10 +566,11 @@ class LiveDebugValues : public MachineFunctionPass { } }; - /// Collect all VarLoc IDs from \p CollectFrom for VarLocs which are located - /// in \p Reg, of kind RegisterKind. Insert collected IDs in \p Collected. - void collectIDsForReg(VarLocSet &Collected, uint32_t Reg, - const VarLocSet &CollectFrom) const; + /// Collect all VarLoc IDs from \p CollectFrom for VarLocs of kind + /// RegisterKind which are located in any reg in \p Regs. Insert collected IDs + /// into \p Collected. + void collectIDsForRegs(VarLocSet &Collected, const DefinedRegsSet &Regs, + const VarLocSet &CollectFrom) const; /// Get the registers which are used by VarLocs of kind RegisterKind tracked /// by \p CollectFrom. @@ -573,15 +578,17 @@ class LiveDebugValues : public MachineFunctionPass { SmallVectorImpl &UsedRegs) const; VarLocSet &getVarLocsInMBB(const MachineBasicBlock *MBB, VarLocInMBB &Locs) { - auto Result = Locs.try_emplace(MBB, Alloc); - return Result.first->second; + std::unique_ptr &VLS = Locs[MBB]; + if (!VLS) + VLS = std::make_unique(Alloc); + return *VLS.get(); } const VarLocSet &getVarLocsInMBB(const MachineBasicBlock *MBB, const VarLocInMBB &Locs) const { auto It = Locs.find(MBB); assert(It != Locs.end() && "MBB not in map"); - return It->second; + return *It->second.get(); } /// Tests whether this instruction is a spill to a stack location. @@ -770,16 +777,30 @@ LiveDebugValues::OpenRangesSet::getEntryValueBackup(DebugVariable Var) { return llvm::None; } -void LiveDebugValues::collectIDsForReg(VarLocSet &Collected, uint32_t Reg, - const VarLocSet &CollectFrom) const { - // The half-open interval [FirstIndexForReg, FirstInvalidIndex) contains all - // possible VarLoc IDs for VarLocs of kind RegisterKind which live in Reg. - uint64_t FirstIndexForReg = LocIndex::rawIndexForReg(Reg); - uint64_t FirstInvalidIndex = LocIndex::rawIndexForReg(Reg + 1); - // Iterate through that half-open interval and collect all the set IDs. - for (auto It = CollectFrom.find(FirstIndexForReg), End = CollectFrom.end(); - It != End && *It < FirstInvalidIndex; ++It) - Collected.set(*It); +void LiveDebugValues::collectIDsForRegs(VarLocSet &Collected, + const DefinedRegsSet &Regs, + const VarLocSet &CollectFrom) const { + assert(!Regs.empty() && "Nothing to collect"); + SmallVector SortedRegs; + for (Register Reg : Regs) + SortedRegs.push_back(Reg); + array_pod_sort(SortedRegs.begin(), SortedRegs.end()); + auto It = CollectFrom.find(LocIndex::rawIndexForReg(SortedRegs.front())); + auto End = CollectFrom.end(); + for (uint32_t Reg : SortedRegs) { + // The half-open interval [FirstIndexForReg, FirstInvalidIndex) contains all + // possible VarLoc IDs for VarLocs of kind RegisterKind which live in Reg. + uint64_t FirstIndexForReg = LocIndex::rawIndexForReg(Reg); + uint64_t FirstInvalidIndex = LocIndex::rawIndexForReg(Reg + 1); + It.advanceToLowerBound(FirstIndexForReg); + + // Iterate through that half-open interval and collect all the set IDs. + for (; It != End && *It < FirstInvalidIndex; ++It) + Collected.set(*It); + + if (It == End) + return; + } } void LiveDebugValues::getUsedRegs(const VarLocSet &CollectFrom, @@ -800,7 +821,7 @@ void LiveDebugValues::getUsedRegs(const VarLocSet &CollectFrom, // even if there aren't any VarLocs living in `FoundReg+1`, we're still // guaranteed to move on to the next register (or to end()). uint64_t NextRegIndex = LocIndex::rawIndexForReg(FoundReg + 1); - It = CollectFrom.find(NextRegIndex); + It.advanceToLowerBound(NextRegIndex); } } @@ -1073,9 +1094,7 @@ void LiveDebugValues::transferRegisterDef( unsigned SP = TLI->getStackPointerRegisterToSaveRestore(); // Find the regs killed by MI, and find regmasks of preserved regs. - // Max out the number of statically allocated elements in `DeadRegs`, as this - // prevents fallback to std::set::count() operations. - SmallSet DeadRegs; + DefinedRegsSet DeadRegs; SmallVector RegMasks; for (const MachineOperand &MO : MI.operands()) { // Determine whether the operand is a register def. @@ -1094,9 +1113,6 @@ void LiveDebugValues::transferRegisterDef( // Erase VarLocs which reside in one of the dead registers. For performance // reasons, it's critical to not iterate over the full set of open VarLocs. // Iterate over the set of dying/used regs instead. - VarLocSet KillSet(Alloc); - for (uint32_t DeadReg : DeadRegs) - collectIDsForReg(KillSet, DeadReg, OpenRanges.getVarLocs()); if (!RegMasks.empty()) { SmallVector UsedRegs; getUsedRegs(OpenRanges.getVarLocs(), UsedRegs); @@ -1118,9 +1134,15 @@ void LiveDebugValues::transferRegisterDef( return MachineOperand::clobbersPhysReg(RegMask, Reg); }); if (AnyRegMaskKillsReg) - collectIDsForReg(KillSet, Reg, OpenRanges.getVarLocs()); + DeadRegs.insert(Reg); } } + + if (DeadRegs.empty()) + return; + + VarLocSet KillSet(Alloc); + collectIDsForRegs(KillSet, DeadRegs, OpenRanges.getVarLocs()); OpenRanges.erase(KillSet, VarLocIDs); if (auto *TPC = getAnalysisIfAvailable()) { @@ -1479,10 +1501,11 @@ bool LiveDebugValues::join( // Just copy over the Out locs to incoming locs for the first visited // predecessor, and for all other predecessors join the Out locs. + VarLocSet &OutLocVLS = *OL->second.get(); if (!NumVisited) - InLocsT = OL->second; + InLocsT = OutLocVLS; else - InLocsT &= OL->second; + InLocsT &= OutLocVLS; LLVM_DEBUG({ if (!InLocsT.empty()) { @@ -1554,7 +1577,7 @@ void LiveDebugValues::flushPendingLocs(VarLocInMBB &PendingInLocs, for (auto &Iter : PendingInLocs) { // Map is keyed on a constant pointer, unwrap it so we can insert insts. auto &MBB = const_cast(*Iter.first); - VarLocSet &Pending = Iter.second; + VarLocSet &Pending = *Iter.second.get(); for (uint64_t ID : Pending) { // The ID location is live-in to MBB -- work out what kind of machine @@ -1703,7 +1726,7 @@ bool LiveDebugValues::ExtendRanges(MachineFunction &MF) { // Initialize per-block structures and scan for fragment overlaps. for (auto &MBB : MF) { - PendingInLocs.try_emplace(&MBB, Alloc); + PendingInLocs[&MBB] = std::make_unique(Alloc); for (auto &MI : MBB) { if (MI.isDebugValue()) diff --git a/llvm/lib/CodeGen/LiveDebugVariables.cpp b/llvm/lib/CodeGen/LiveDebugVariables.cpp index 2b3e98f933284..a686d12c45a9b 100644 --- a/llvm/lib/CodeGen/LiveDebugVariables.cpp +++ b/llvm/lib/CodeGen/LiveDebugVariables.cpp @@ -154,9 +154,8 @@ class LDVImpl; /// holds part of a user variable. The part is identified by a byte offset. /// /// UserValues are grouped into equivalence classes for easier searching. Two -/// user values are related if they refer to the same variable, or if they are -/// held by the same virtual register. The equivalence class is the transitive -/// closure of that relation. +/// user values are related if they are held by the same virtual register. The +/// equivalence class is the transitive closure of that relation. class UserValue { const DILocalVariable *Variable; ///< The debug info variable we are part of. /// The part of the variable we describe. @@ -207,24 +206,6 @@ class UserValue { /// Return the next UserValue in the equivalence class. UserValue *getNext() const { return next; } - /// Does this UserValue match the parameters? - bool matches(const DILocalVariable *Var, - Optional OtherFragment, - const DILocation *IA) const { - // FIXME: Handle partially overlapping fragments. - // A DBG_VALUE with a fragment which overlaps a previous DBG_VALUE fragment - // for the same variable terminates the interval opened by the first. - // getUserValue() uses matches() to filter DBG_VALUEs into interval maps to - // represent these intervals. - // Given two _partially_ overlapping fragments matches() will always return - // false. The DBG_VALUEs will be filtered into separate interval maps and - // therefore we do not faithfully represent the original intervals. - // See D70121#1849741 for a more detailed explanation and further - // discussion. - return Var == Variable && OtherFragment == Fragment && - dl->getInlinedAt() == IA; - } - /// Merge equivalence classes. static UserValue *merge(UserValue *L1, UserValue *L2) { L2 = L2->getLeader(); @@ -429,8 +410,8 @@ class LDVImpl { using VRMap = DenseMap; VRMap virtRegToEqClass; - /// Map user variable to eq class leader. - using UVMap = DenseMap; + /// Map to find existing UserValue instances. + using UVMap = DenseMap; UVMap userVarMap; /// Find or create a UserValue. @@ -600,19 +581,15 @@ void UserValue::mapVirtRegs(LDVImpl *LDV) { UserValue *LDVImpl::getUserValue(const DILocalVariable *Var, Optional Fragment, const DebugLoc &DL) { - UserValue *&Leader = userVarMap[Var]; - if (Leader) { - UserValue *UV = Leader->getLeader(); - Leader = UV; - for (; UV; UV = UV->getNext()) - if (UV->matches(Var, Fragment, DL->getInlinedAt())) - return UV; + // FIXME: Handle partially overlapping fragments. See + // https://reviews.llvm.org/D70121#1849741. + DebugVariable ID(Var, Fragment, DL->getInlinedAt()); + UserValue *&UV = userVarMap[ID]; + if (!UV) { + userValues.push_back( + std::make_unique(Var, Fragment, DL, allocator)); + UV = userValues.back().get(); } - - userValues.push_back( - std::make_unique(Var, Fragment, DL, allocator)); - UserValue *UV = userValues.back().get(); - Leader = UserValue::merge(Leader, UV); return UV; } diff --git a/llvm/lib/CodeGen/MIRPrinter.cpp b/llvm/lib/CodeGen/MIRPrinter.cpp index b06e34a809fca..2b81126e527d8 100644 --- a/llvm/lib/CodeGen/MIRPrinter.cpp +++ b/llvm/lib/CodeGen/MIRPrinter.cpp @@ -79,6 +79,9 @@ static cl::opt SimplifyMIR( "simplify-mir", cl::Hidden, cl::desc("Leave out unnecessary information when printing MIR")); +static cl::opt PrintLocations("mir-debug-loc", cl::Hidden, cl::init(true), + cl::desc("Print MIR debug-locations")); + namespace { /// This structure describes how to print out stack object references. @@ -792,11 +795,13 @@ void MIPrinter::print(const MachineInstr &MI) { NeedComma = true; } - if (const DebugLoc &DL = MI.getDebugLoc()) { - if (NeedComma) - OS << ','; - OS << " debug-location "; - DL->printAsOperand(OS, MST); + if (PrintLocations) { + if (const DebugLoc &DL = MI.getDebugLoc()) { + if (NeedComma) + OS << ','; + OS << " debug-location "; + DL->printAsOperand(OS, MST); + } } if (!MI.memoperands_empty()) { diff --git a/llvm/lib/CodeGen/MachineCSE.cpp b/llvm/lib/CodeGen/MachineCSE.cpp index 9561a06ce8dfd..8c195adb444d5 100644 --- a/llvm/lib/CodeGen/MachineCSE.cpp +++ b/llvm/lib/CodeGen/MachineCSE.cpp @@ -831,6 +831,13 @@ bool MachineCSE::ProcessBlockPRE(MachineDominatorTree *DT, continue; MachineInstr &NewMI = TII->duplicate(*CMBB, CMBB->getFirstTerminator(), *MI); + + // When hoisting, make sure we don't carry the debug location of + // the original instruction, as that's not correct and can cause + // unexpected jumps when debugging optimized code. + auto EmptyDL = DebugLoc(); + NewMI.setDebugLoc(EmptyDL); + NewMI.getOperand(0).setReg(NewReg); PREMap[MI] = CMBB; diff --git a/llvm/lib/CodeGen/MachineDebugify.cpp b/llvm/lib/CodeGen/MachineDebugify.cpp new file mode 100644 index 0000000000000..bee9b63467571 --- /dev/null +++ b/llvm/lib/CodeGen/MachineDebugify.cpp @@ -0,0 +1,85 @@ +//===- MachineDebugify.cpp - Attach synthetic debug info to everything ----===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +/// +/// \file This pass attaches synthetic debug info to everything. It can be used +/// to create targeted tests for debug info preservation. +/// +/// This isn't intended to have feature parity with Debugify. +//===----------------------------------------------------------------------===// + +#include "llvm/CodeGen/MachineFunctionPass.h" +#include "llvm/CodeGen/MachineModuleInfo.h" +#include "llvm/CodeGen/Passes.h" +#include "llvm/IR/DIBuilder.h" +#include "llvm/IR/DebugInfo.h" +#include "llvm/InitializePasses.h" +#include "llvm/Transforms/Utils/Debugify.h" + +#define DEBUG_TYPE "mir-debugify" + +using namespace llvm; + +namespace { +bool applyDebugifyMetadataToMachineFunction(MachineModuleInfo &MMI, + DIBuilder &DIB, Function &F) { + MachineFunction &MF = MMI.getOrCreateMachineFunction(F); + + DISubprogram *SP = F.getSubprogram(); + assert(SP && "IR Debugify just created it?"); + + LLVMContext &Ctx = F.getParent()->getContext(); + unsigned NextLine = SP->getLine(); + + for (MachineBasicBlock &MBB : MF) { + for (MachineInstr &MI : MBB) { + // This will likely emit line numbers beyond the end of the imagined + // source function and into subsequent ones. We don't do anything about + // that as it doesn't really matter to the compiler where the line is in + // the imaginary source code. + MI.setDebugLoc(DILocation::get(Ctx, NextLine++, 1, SP)); + } + } + + return true; +} + +/// ModulePass for attaching synthetic debug info to everything, used with the +/// legacy module pass manager. +struct DebugifyMachineModule : public ModulePass { + bool runOnModule(Module &M) override { + MachineModuleInfo &MMI = + getAnalysis().getMMI(); + return applyDebugifyMetadata( + M, M.functions(), + "ModuleDebugify: ", [&](DIBuilder &DIB, Function &F) -> bool { + return applyDebugifyMetadataToMachineFunction(MMI, DIB, F); + }); + } + + DebugifyMachineModule() : ModulePass(ID) {} + + void getAnalysisUsage(AnalysisUsage &AU) const override { + AU.addRequired(); + AU.addPreserved(); + AU.setPreservesCFG(); + } + + static char ID; // Pass identification. +}; +char DebugifyMachineModule::ID = 0; + +} // end anonymous namespace + +INITIALIZE_PASS_BEGIN(DebugifyMachineModule, DEBUG_TYPE, + "Machine Debugify Module", false, false) +INITIALIZE_PASS_END(DebugifyMachineModule, DEBUG_TYPE, + "Machine Debugify Module", false, false) + +ModulePass *llvm::createDebugifyMachineModulePass() { + return new DebugifyMachineModule(); +} diff --git a/llvm/lib/CodeGen/MachineFunction.cpp b/llvm/lib/CodeGen/MachineFunction.cpp index 1ef1939f9ba38..f6e2089f1c1c9 100644 --- a/llvm/lib/CodeGen/MachineFunction.cpp +++ b/llvm/lib/CodeGen/MachineFunction.cpp @@ -131,8 +131,7 @@ static inline unsigned getFnStackAlignment(const TargetSubtargetInfo *STI, return STI->getFrameLowering()->getStackAlignment(); } -MachineFunction::MachineFunction(const Function &F, - const LLVMTargetMachine &Target, +MachineFunction::MachineFunction(Function &F, const LLVMTargetMachine &Target, const TargetSubtargetInfo &STI, unsigned FunctionNum, MachineModuleInfo &mmi) : F(F), Target(Target), STI(&STI), Ctx(mmi.getContext()), MMI(mmi) { @@ -370,6 +369,11 @@ MachineInstr &MachineFunction::CloneMachineInstrBundle(MachineBasicBlock &MBB, break; ++I; } + // Copy over call site info to the cloned instruction if needed. If Orig is in + // a bundle, copyCallSiteInfo takes care of finding the call instruction in + // the bundle. + if (Orig.shouldUpdateCallSiteInfo()) + copyCallSiteInfo(&Orig, FirstClone); return *FirstClone; } diff --git a/llvm/lib/CodeGen/MachineModuleInfo.cpp b/llvm/lib/CodeGen/MachineModuleInfo.cpp index 0094a923e0390..0fc9f2498a54c 100644 --- a/llvm/lib/CodeGen/MachineModuleInfo.cpp +++ b/llvm/lib/CodeGen/MachineModuleInfo.cpp @@ -279,8 +279,7 @@ MachineModuleInfo::getMachineFunction(const Function &F) const { return I != MachineFunctions.end() ? I->second.get() : nullptr; } -MachineFunction & -MachineModuleInfo::getOrCreateMachineFunction(const Function &F) { +MachineFunction &MachineModuleInfo::getOrCreateMachineFunction(Function &F) { // Shortcut for the common case where a sequence of MachineFunctionPasses // all query for the same Function. if (LastRequest == &F) diff --git a/llvm/lib/CodeGen/MachineStripDebug.cpp b/llvm/lib/CodeGen/MachineStripDebug.cpp new file mode 100644 index 0000000000000..48b50ceb092a5 --- /dev/null +++ b/llvm/lib/CodeGen/MachineStripDebug.cpp @@ -0,0 +1,108 @@ +//===- MachineStripDebug.cpp - Strip debug info ---------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +/// +/// \file This removes debug info from everything. It can be used to ensure +/// tests can be debugified without affecting the output MIR. +//===----------------------------------------------------------------------===// + +#include "llvm/CodeGen/MachineFunctionPass.h" +#include "llvm/CodeGen/MachineModuleInfo.h" +#include "llvm/CodeGen/Passes.h" +#include "llvm/IR/DebugInfo.h" +#include "llvm/InitializePasses.h" +#include "llvm/Support/CommandLine.h" +#include "llvm/Transforms/Utils/Debugify.h" + +#define DEBUG_TYPE "mir-strip-debug" + +using namespace llvm; + +namespace { +cl::opt + OnlyDebugifiedDefault("mir-strip-debugify-only", + cl::desc("Should mir-strip-debug only strip debug " + "info from debugified modules by default"), + cl::init(true)); + +struct StripDebugMachineModule : public ModulePass { + bool runOnModule(Module &M) override { + if (OnlyDebugified) { + NamedMDNode *DebugifyMD = M.getNamedMetadata("llvm.debugify"); + if (!DebugifyMD) { + LLVM_DEBUG(dbgs() << "Not stripping debug info" + " (debugify metadata not found)?\n"); + return false; + } + } + + MachineModuleInfo &MMI = + getAnalysis().getMMI(); + + bool Changed = false; + for (Function &F : M.functions()) { + MachineFunction &MF = MMI.getOrCreateMachineFunction(F); + for (MachineBasicBlock &MBB : MF) { + for (MachineBasicBlock::iterator I = MBB.begin(), E = MBB.end(); + I != E;) { + if (I->isDebugInstr()) { + // FIXME: We should remove all of them. However, AArch64 emits an + // invalid `DBG_VALUE $lr` with only one operand instead of + // the usual three and has a test that depends on it's + // preservation. Preserve it for now. + if (I->getNumOperands() > 1) { + LLVM_DEBUG(dbgs() << "Removing debug instruction " << *I); + I = MBB.erase(I); + Changed |= true; + continue; + } + } + if (I->getDebugLoc()) { + LLVM_DEBUG(dbgs() << "Removing location " << *I); + I->setDebugLoc(DebugLoc()); + Changed |= true; + ++I; + continue; + } + LLVM_DEBUG(dbgs() << "Keeping " << *I); + ++I; + } + } + } + + Changed |= stripDebugifyMetadata(M); + + return Changed; + } + + StripDebugMachineModule() : StripDebugMachineModule(OnlyDebugifiedDefault) {} + StripDebugMachineModule(bool OnlyDebugified) + : ModulePass(ID), OnlyDebugified(OnlyDebugified) {} + + void getAnalysisUsage(AnalysisUsage &AU) const override { + AU.addRequired(); + AU.addPreserved(); + AU.setPreservesCFG(); + } + + static char ID; // Pass identification. + +protected: + bool OnlyDebugified; +}; +char StripDebugMachineModule::ID = 0; + +} // end anonymous namespace + +INITIALIZE_PASS_BEGIN(StripDebugMachineModule, DEBUG_TYPE, + "Machine Strip Debug Module", false, false) +INITIALIZE_PASS_END(StripDebugMachineModule, DEBUG_TYPE, + "Machine Strip Debug Module", false, false) + +ModulePass *llvm::createStripDebugMachineModulePass(bool OnlyDebugified) { + return new StripDebugMachineModule(OnlyDebugified); +} diff --git a/llvm/lib/CodeGen/TargetPassConfig.cpp b/llvm/lib/CodeGen/TargetPassConfig.cpp index 41cb511ad9b47..984d858be7d1f 100644 --- a/llvm/lib/CodeGen/TargetPassConfig.cpp +++ b/llvm/lib/CodeGen/TargetPassConfig.cpp @@ -114,6 +114,12 @@ static cl::opt VerifyMachineCode("verify-machineinstrs", cl::Hidden, cl::desc("Verify generated machine code"), cl::ZeroOrMore); +static cl::opt DebugifyAndStripAll( + "debugify-and-strip-all-safe", cl::Hidden, + cl::desc( + "Debugify MIR before and Strip debug after " + "each pass except those known to be unsafe when debug info is present"), + cl::ZeroOrMore); enum RunOutliner { AlwaysOutline, NeverOutline, TargetDefault }; // Enable or disable the MachineOutliner. static cl::opt EnableMachineOutliner( @@ -530,17 +536,16 @@ void TargetPassConfig::addPass(Pass *P, bool verifyAfter, bool printAfter) { if (StopBefore == PassID && StopBeforeCount++ == StopBeforeInstanceNum) Stopped = true; if (Started && !Stopped) { + if (AddingMachinePasses) + addMachinePrePasses(); std::string Banner; // Construct banner message before PM->add() as that may delete the pass. if (AddingMachinePasses && (printAfter || verifyAfter)) Banner = std::string("After ") + std::string(P->getPassName()); PM->add(P); - if (AddingMachinePasses) { - if (printAfter) - addPrintPass(Banner); - if (verifyAfter) - addVerifyPass(Banner); - } + if (AddingMachinePasses) + addMachinePostPasses(Banner, /*AllowPrint*/ printAfter, + /*AllowVerify*/ verifyAfter); // Add the passes after the pass P if there is any. for (auto IP : Impl->InsertedPasses) { @@ -606,6 +611,30 @@ void TargetPassConfig::addVerifyPass(const std::string &Banner) { PM->add(createMachineVerifierPass(Banner)); } +void TargetPassConfig::addDebugifyPass() { + PM->add(createDebugifyMachineModulePass()); +} + +void TargetPassConfig::addStripDebugPass() { + PM->add(createStripDebugMachineModulePass(/*OnlyDebugified=*/true)); +} + +void TargetPassConfig::addMachinePrePasses(bool AllowDebugify) { + if (AllowDebugify && DebugifyAndStripAll == cl::BOU_TRUE && DebugifyIsSafe) + addDebugifyPass(); +} + +void TargetPassConfig::addMachinePostPasses(const std::string &Banner, + bool AllowPrint, bool AllowVerify, + bool AllowStrip) { + if (DebugifyAndStripAll == cl::BOU_TRUE && DebugifyIsSafe) + addStripDebugPass(); + if (AllowPrint) + addPrintPass(Banner); + if (AllowVerify) + addVerifyPass(Banner); +} + /// Add common target configurable passes that perform LLVM IR to IR transforms /// following machine independent optimization. void TargetPassConfig::addIRPasses() { @@ -785,6 +814,19 @@ bool TargetPassConfig::addCoreISelPasses() { TM->setGlobalISel(true); } + // FIXME: Injecting into the DAGISel pipeline seems to cause issues with + // analyses needing to be re-run. This can result in being unable to + // schedule passes (particularly with 'Function Alias Analysis + // Results'). It's not entirely clear why but AFAICT this seems to be + // due to one FunctionPassManager not being able to use analyses from a + // previous one. As we're injecting a ModulePass we break the usual + // pass manager into two. GlobalISel with the fallback path disabled + // and -run-pass seem to be unaffected. The majority of GlobalISel + // testing uses -run-pass so this probably isn't too bad. + SaveAndRestore SavedDebugifyIsSafe(DebugifyIsSafe); + if (Selector != SelectorType::GlobalISel || !isGlobalISelAbortEnabled()) + DebugifyIsSafe = false; + // Add instruction selector passes. if (Selector == SelectorType::GlobalISel) { SaveAndRestore SavedAddingMachinePasses(AddingMachinePasses, true); @@ -901,6 +943,11 @@ void TargetPassConfig::addMachinePasses() { // Run pre-ra passes. addPreRegAlloc(); + // Debugifying the register allocator passes seems to provoke some + // non-determinism that affects CodeGen and there doesn't seem to be a point + // where it becomes safe again so stop debugifying here. + DebugifyIsSafe = false; + // Run register allocation and passes that are tightly coupled with it, // including phi elimination and scheduling. if (getOptimizeRegAlloc()) @@ -1110,6 +1157,7 @@ bool TargetPassConfig::addRegAssignmentOptimized() { // Finally rewrite virtual registers. addPass(&VirtRegRewriterID); + // Perform stack slot coloring and post-ra machine LICM. // // FIXME: Re-enable coloring with register when it's capable of adding diff --git a/llvm/lib/IR/BasicBlock.cpp b/llvm/lib/IR/BasicBlock.cpp index bdee6990f9324..7c6395e4dccb5 100644 --- a/llvm/lib/IR/BasicBlock.cpp +++ b/llvm/lib/IR/BasicBlock.cpp @@ -33,6 +33,10 @@ LLVMContext &BasicBlock::getContext() const { return getType()->getContext(); } +template <> void llvm::invalidateParentIListOrdering(BasicBlock *BB) { + BB->invalidateOrders(); +} + // Explicit instantiation of SymbolTableListTraits since some of the methods // are not in the public header file... template class llvm::SymbolTableListTraits; @@ -61,6 +65,8 @@ void BasicBlock::insertInto(Function *NewParent, BasicBlock *InsertBefore) { } BasicBlock::~BasicBlock() { + validateInstrOrdering(); + // If the address of the block is taken and it is being deleted (e.g. because // it is dead), this means that there is either a dangling constant expr // hanging off the block, or an undefined use of the block (source code @@ -494,3 +500,29 @@ BasicBlock::iterator llvm::skipDebugIntrinsics(BasicBlock::iterator It) { ++It; return It; } + +void BasicBlock::renumberInstructions() { + unsigned Order = 0; + for (Instruction &I : *this) + I.Order = Order++; + + // Set the bit to indicate that the instruction order valid and cached. + BasicBlockBits Bits = getBasicBlockBits(); + Bits.InstrOrderValid = true; + setBasicBlockBits(Bits); +} + +#ifndef NDEBUG +/// In asserts builds, this checks the numbering. In non-asserts builds, it +/// is defined as an inline function returning true in BasicBlock.h. +void BasicBlock::validateInstrOrdering() const { + if (!isInstrOrderValid()) + return; + const Instruction *Prev = nullptr; + for (const Instruction &I : *this) { + assert((!Prev || Prev->comesBefore(&I)) && + "cached instruction ordering is incorrect"); + Prev = &I; + } +} +#endif diff --git a/llvm/lib/IR/DebugInfo.cpp b/llvm/lib/IR/DebugInfo.cpp index 7ac26986c662a..2175ffe77cfd8 100644 --- a/llvm/lib/IR/DebugInfo.cpp +++ b/llvm/lib/IR/DebugInfo.cpp @@ -623,7 +623,9 @@ bool llvm::stripNonLineTableDebugInfo(Module &M) { Changed = true; } }; + RemoveUses("llvm.dbg.addr"); RemoveUses("llvm.dbg.declare"); + RemoveUses("llvm.dbg.label"); RemoveUses("llvm.dbg.value"); // Delete non-CU debug info named metadata nodes. diff --git a/llvm/lib/IR/DebugInfoMetadata.cpp b/llvm/lib/IR/DebugInfoMetadata.cpp index 18bfeff8afa15..da266d2845f06 100644 --- a/llvm/lib/IR/DebugInfoMetadata.cpp +++ b/llvm/lib/IR/DebugInfoMetadata.cpp @@ -75,6 +75,21 @@ DILocation *DILocation::getImpl(LLVMContext &Context, unsigned Line, Storage, Context.pImpl->DILocations); } +const +DILocation *DILocation::getMergedLocations(ArrayRef Locs) { + if (Locs.empty()) + return nullptr; + if (Locs.size() == 1) + return Locs[0]; + auto *Merged = Locs[0]; + for (auto I = std::next(Locs.begin()), E = Locs.end(); I != E; ++I) { + Merged = getMergedLocation(Merged, *I); + if (Merged == nullptr) + break; + } + return Merged; +} + const DILocation *DILocation::getMergedLocation(const DILocation *LocA, const DILocation *LocB) { if (!LocA || !LocB) @@ -1117,7 +1132,9 @@ DIExpression *DIExpression::append(const DIExpression *Expr, } NewOps.append(Ops.begin(), Ops.end()); - return DIExpression::get(Expr->getContext(), NewOps); + auto *result = DIExpression::get(Expr->getContext(), NewOps); + assert(result->isValid() && "concatenated expression is not valid"); + return result; } DIExpression *DIExpression::appendToStack(const DIExpression *Expr, diff --git a/llvm/lib/IR/Instruction.cpp b/llvm/lib/IR/Instruction.cpp index 7da1697128965..2ef109067dd69 100644 --- a/llvm/lib/IR/Instruction.cpp +++ b/llvm/lib/IR/Instruction.cpp @@ -97,6 +97,15 @@ void Instruction::moveBefore(BasicBlock &BB, BB.getInstList().splice(I, getParent()->getInstList(), getIterator()); } +bool Instruction::comesBefore(const Instruction *Other) const { + assert(Parent && Other->Parent && + "instructions without BB parents have no order"); + assert(Parent == Other->Parent && "cross-BB instruction order comparison"); + if (!Parent->isInstrOrderValid()) + Parent->renumberInstructions(); + return Order < Other->Order; +} + void Instruction::setHasNoUnsignedWrap(bool b) { cast(this)->setHasNoUnsignedWrap(b); } diff --git a/llvm/lib/IR/SymbolTableListTraitsImpl.h b/llvm/lib/IR/SymbolTableListTraitsImpl.h index f399c823d6fb0..4283744bd058d 100644 --- a/llvm/lib/IR/SymbolTableListTraitsImpl.h +++ b/llvm/lib/IR/SymbolTableListTraitsImpl.h @@ -20,6 +20,11 @@ namespace llvm { +/// Notify basic blocks when an instruction is inserted. +template +inline void invalidateParentIListOrdering(ParentClass *Parent) {} +template <> void invalidateParentIListOrdering(BasicBlock *BB); + /// setSymTabObject - This is called when (f.e.) the parent of a basic block /// changes. This requires us to remove all the instruction symtab entries from /// the current function and reinsert them into the new function. @@ -64,6 +69,7 @@ void SymbolTableListTraits::addNodeToList(ValueSubClass *V) { assert(!V->getParent() && "Value already in a container!!"); ItemParentClass *Owner = getListOwner(); V->setParent(Owner); + invalidateParentIListOrdering(Owner); if (V->hasName()) if (ValueSymbolTable *ST = getSymTab(Owner)) ST->reinsertValue(V); @@ -81,8 +87,13 @@ void SymbolTableListTraits::removeNodeFromList( template void SymbolTableListTraits::transferNodesFromList( SymbolTableListTraits &L2, iterator first, iterator last) { - // We only have to do work here if transferring instructions between BBs - ItemParentClass *NewIP = getListOwner(), *OldIP = L2.getListOwner(); + // Transfering nodes, even within the same BB, invalidates the ordering. The + // list that we removed the nodes from still has a valid ordering. + ItemParentClass *NewIP = getListOwner(); + invalidateParentIListOrdering(NewIP); + + // Nothing else needs to be done if we're reording nodes within the same list. + ItemParentClass *OldIP = L2.getListOwner(); if (NewIP == OldIP) return; diff --git a/llvm/lib/IR/Verifier.cpp b/llvm/lib/IR/Verifier.cpp index 547ad0f115b2e..c2fa55b9880c7 100644 --- a/llvm/lib/IR/Verifier.cpp +++ b/llvm/lib/IR/Verifier.cpp @@ -3073,7 +3073,9 @@ static AttrBuilder getParameterABIAttributes(int I, AttributeList Attrs) { if (Attrs.hasParamAttribute(I, AK)) Copy.addAttribute(AK); } - if (Attrs.hasParamAttribute(I, Attribute::Alignment)) + // `align` is ABI-affecting only in combination with `byval`. + if (Attrs.hasParamAttribute(I, Attribute::Alignment) && + Attrs.hasParamAttribute(I, Attribute::ByVal)) Copy.addAlignmentAttr(Attrs.getParamAlignment(I)); return Copy; } diff --git a/llvm/lib/Support/CMakeLists.txt b/llvm/lib/Support/CMakeLists.txt index 26332d4f539c5..11606ce82adc8 100644 --- a/llvm/lib/Support/CMakeLists.txt +++ b/llvm/lib/Support/CMakeLists.txt @@ -115,6 +115,7 @@ add_llvm_component_library(LLVMSupport MemoryBuffer.cpp MD5.cpp NativeFormatting.cpp + OptimalLayout.cpp Optional.cpp Parallel.cpp PluginLoader.cpp diff --git a/llvm/lib/Support/OptimalLayout.cpp b/llvm/lib/Support/OptimalLayout.cpp new file mode 100644 index 0000000000000..b0c7720e71c60 --- /dev/null +++ b/llvm/lib/Support/OptimalLayout.cpp @@ -0,0 +1,452 @@ +//===--- OptimalLayout.cpp - Optimal data layout algorithm ----------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// This file implements the performOptimalLayout interface. +// +//===----------------------------------------------------------------------===// + +#include "llvm/Support/OptimalLayout.h" + +using namespace llvm; + +#ifndef NDEBUG +void checkValidLayout(ArrayRef Fields, + uint64_t Size, Align MaxAlign) { + uint64_t LastEnd = 0; + Align ComputedMaxAlign; + for (auto &Field : Fields) { + assert(Field.hasFixedOffset() && + "didn't assign a fixed offset to field"); + assert(isAligned(Field.Alignment, Field.Offset) && + "didn't assign a correctly-aligned offset to field"); + assert(Field.Offset >= LastEnd && + "didn't assign offsets in ascending order"); + LastEnd = Field.getEndOffset(); + assert(Field.Alignment <= MaxAlign && + "didn't compute MaxAlign correctly"); + ComputedMaxAlign = std::max(Field.Alignment, MaxAlign); + } + assert(LastEnd == Size && "didn't compute LastEnd correctly"); + assert(ComputedMaxAlign == MaxAlign && "didn't compute MaxAlign correctly"); +} +#endif + +std::pair +llvm::performOptimalLayout(MutableArrayRef Fields) { +#ifndef NDEBUG + // Do some simple precondition checks. + { + bool InFixedPrefix = true; + size_t LastEnd = 0; + for (auto &Field : Fields) { + assert(Field.Size > 0 && "field of zero size"); + if (Field.hasFixedOffset()) { + assert(InFixedPrefix && + "fixed-offset fields are not a strict prefix of array"); + assert(LastEnd <= Field.Offset && + "fixed-offset fields overlap or are not in order"); + LastEnd = Field.getEndOffset(); + assert(LastEnd > Field.Offset && + "overflow in fixed-offset end offset"); + } else { + InFixedPrefix = false; + } + } + } +#endif + + // Do an initial pass over the fields. + Align MaxAlign; + + // Find the first flexible-offset field, tracking MaxAlign. + auto FirstFlexible = Fields.begin(), E = Fields.end(); + while (FirstFlexible != E && FirstFlexible->hasFixedOffset()) { + MaxAlign = std::max(MaxAlign, FirstFlexible->Alignment); + ++FirstFlexible; + } + + // If there are no flexible fields, we're done. + if (FirstFlexible == E) { + uint64_t Size = 0; + if (!Fields.empty()) + Size = Fields.back().getEndOffset(); + +#ifndef NDEBUG + checkValidLayout(Fields, Size, MaxAlign); +#endif + return std::make_pair(Size, MaxAlign); + } + + // Walk over the flexible-offset fields, tracking MaxAlign and + // assigning them a unique number in order of their appearance. + // We'll use this unique number in the comparison below so that + // we can use array_pod_sort, which isn't stable. We won't use it + // past that point. + { + uintptr_t UniqueNumber = 0; + for (auto I = FirstFlexible; I != E; ++I) { + I->Scratch = reinterpret_cast(UniqueNumber++); + MaxAlign = std::max(MaxAlign, I->Alignment); + } + } + + // Sort the flexible elements in order of decreasing alignment, + // then decreasing size, and then the original order as recorded + // in Scratch. The decreasing-size aspect of this is only really + // important if we get into the gap-filling stage below, but it + // doesn't hurt here. + array_pod_sort(FirstFlexible, E, + [](const OptimalLayoutField *lhs, + const OptimalLayoutField *rhs) -> int { + // Decreasing alignment. + if (lhs->Alignment != rhs->Alignment) + return (lhs->Alignment < rhs->Alignment ? 1 : -1); + + // Decreasing size. + if (lhs->Size != rhs->Size) + return (lhs->Size < rhs->Size ? 1 : -1); + + // Original order. + auto lhsNumber = reinterpret_cast(lhs->Scratch); + auto rhsNumber = reinterpret_cast(rhs->Scratch); + if (lhsNumber != rhsNumber) + return (lhsNumber < rhsNumber ? -1 : 1); + + return 0; + }); + + // Do a quick check for whether that sort alone has given us a perfect + // layout with no interior padding. This is very common: if the + // fixed-layout fields have no interior padding, and they end at a + // sufficiently-aligned offset for all the flexible-layout fields, + // and the flexible-layout fields all have sizes that are multiples + // of their alignment, then this will reliably trigger. + { + bool HasPadding = false; + uint64_t LastEnd = 0; + + // Walk the fixed-offset fields. + for (auto I = Fields.begin(); I != FirstFlexible; ++I) { + assert(I->hasFixedOffset()); + if (LastEnd != I->Offset) { + HasPadding = true; + break; + } + LastEnd = I->getEndOffset(); + } + + // Walk the flexible-offset fields, optimistically assigning fixed + // offsets. Note that we maintain a strict division between the + // fixed-offset and flexible-offset fields, so if we end up + // discovering padding later in this loop, we can just abandon this + // work and we'll ignore the offsets we already assigned. + if (!HasPadding) { + for (auto I = FirstFlexible; I != E; ++I) { + auto Offset = alignTo(LastEnd, I->Alignment); + if (LastEnd != Offset) { + HasPadding = true; + break; + } + I->Offset = Offset; + LastEnd = I->getEndOffset(); + } + } + + // If we already have a perfect layout, we're done. + if (!HasPadding) { +#ifndef NDEBUG + checkValidLayout(Fields, LastEnd, MaxAlign); +#endif + return std::make_pair(LastEnd, MaxAlign); + } + } + + // The algorithm sketch at this point is as follows. + // + // Consider the padding gaps between fixed-offset fields in ascending + // order. Let LastEnd be the offset of the first byte following the + // field before the gap, or 0 if the gap is at the beginning of the + // structure. Find the "best" flexible-offset field according to the + // criteria below. If no such field exists, proceed to the next gap. + // Otherwise, add the field at the first properly-aligned offset for + // that field that is >= LastEnd, then update LastEnd and repeat in + // order to fill any remaining gap following that field. + // + // Next, let LastEnd to be the offset of the first byte following the + // last fixed-offset field, or 0 if there are no fixed-offset fields. + // While there are flexible-offset fields remaining, find the "best" + // flexible-offset field according to the criteria below, add it at + // the first properly-aligned offset for that field that is >= LastEnd, + // and update LastEnd to the first byte following the field. + // + // The "best" field is chosen by the following criteria, considered + // strictly in order: + // + // - When filling a gap betweeen fields, the field must fit. + // - A field is preferred if it requires less padding following LastEnd. + // - A field is preferred if it is more aligned. + // - A field is preferred if it is larger. + // - A field is preferred if it appeared earlier in the initial order. + // + // Minimizing leading padding is a greedy attempt to avoid padding + // entirely. Preferring more-aligned fields is an attempt to eliminate + // stricter constraints earlier, with the idea that weaker alignment + // constraints may be resolvable with less padding elsewhere. These + // These two rules are sufficient to ensure that we get the optimal + // layout in the "C-style" case. Preferring larger fields tends to take + // better advantage of large gaps and may be more likely to have a size + // that's a multiple of a useful alignment. Preferring the initial + // order may help somewhat with locality but is mostly just a way of + // ensuring deterministic output. + // + // Note that this algorithm does not guarantee a minimal layout. Picking + // a larger object greedily may leave a gap that cannot be filled as + // efficiently. Unfortunately, solving this perfectly is an NP-complete + // problem (by reduction from bin-packing: let B_i be the bin sizes and + // O_j be the object sizes; add fixed-offset fields such that the gaps + // between them have size B_i, and add flexible-offset fields with + // alignment 1 and size O_j; if the layout size is equal to the end of + // the last fixed-layout field, the objects fit in the bins; note that + // this doesn't even require the complexity of alignment). + + // The implementation below is essentially just an optimized version of + // scanning the list of remaining fields looking for the best, which + // would be O(n^2). In the worst case, it doesn't improve on that. + // However, in practice it'll just scan the array of alignment bins + // and consider the first few elements from one or two bins. The + // number of bins is bounded by a small constant: alignments are powers + // of two that are vanishingly unlikely to be over 64 and fairly unlikely + // to be over 8. And multiple elements only need to be considered when + // filling a gap between fixed-offset fields, which doesn't happen very + // often. We could use a data structure within bins that optimizes for + // finding the best-sized match, but it would require allocating memory + // and copying data, so it's unlikely to be worthwhile. + + + // Start by organizing the flexible-offset fields into bins according to + // their alignment. We expect a small enough number of bins that we + // don't care about the asymptotic costs of walking this. + struct AlignmentQueue { + /// The minimum size of anything currently in this queue. + uint64_t MinSize; + + /// The head of the queue. A singly-linked list. The order here should + /// be consistent with the earlier sort, i.e. the elements should be + /// monotonically descending in size and otherwise in the original order. + /// + /// We remove the queue from the array as soon as this is empty. + OptimalLayoutField *Head; + + /// The alignment requirement of the queue. + Align Alignment; + + static OptimalLayoutField *getNext(OptimalLayoutField *Cur) { + return static_cast(Cur->Scratch); + } + }; + SmallVector FlexibleFieldsByAlignment; + for (auto I = FirstFlexible; I != E; ) { + auto Head = I; + auto Alignment = I->Alignment; + + uint64_t MinSize = I->Size; + auto LastInQueue = I; + for (++I; I != E && I->Alignment == Alignment; ++I) { + LastInQueue->Scratch = I; + LastInQueue = I; + MinSize = std::min(MinSize, I->Size); + } + LastInQueue->Scratch = nullptr; + + FlexibleFieldsByAlignment.push_back({MinSize, Head, Alignment}); + } + +#ifndef NDEBUG + // Verify that we set the queues up correctly. + auto checkQueues = [&]{ + bool FirstQueue = true; + Align LastQueueAlignment; + for (auto &Queue : FlexibleFieldsByAlignment) { + assert((FirstQueue || Queue.Alignment < LastQueueAlignment) && + "bins not in order of descending alignment"); + LastQueueAlignment = Queue.Alignment; + FirstQueue = false; + + assert(Queue.Head && "queue was empty"); + uint64_t LastSize = ~(uint64_t)0; + for (auto I = Queue.Head; I; I = Queue.getNext(I)) { + assert(I->Alignment == Queue.Alignment && "bad field in queue"); + assert(I->Size <= LastSize && "queue not in descending size order"); + LastSize = I->Size; + } + } + }; + checkQueues(); +#endif + + /// Helper function to remove a field from a queue. + auto spliceFromQueue = [&](AlignmentQueue *Queue, + OptimalLayoutField *Last, + OptimalLayoutField *Cur) { + assert(Last ? Queue->getNext(Last) == Cur : Queue->Head == Cur); + + // If we're removing Cur from a non-initial position, splice it out + // of the linked list. + if (Last) { + Last->Scratch = Cur->Scratch; + + // If Cur was the last field in the list, we need to update MinSize. + // We can just use the last field's size because the list is in + // descending order of size. + if (!Cur->Scratch) + Queue->MinSize = Last->Size; + + // Otherwise, replace the head. + } else { + if (auto NewHead = Queue->getNext(Cur)) + Queue->Head = NewHead; + + // If we just emptied the queue, destroy its bin. + else + FlexibleFieldsByAlignment.erase(Queue); + } + }; + + // Do layout into a local array. Doing this in-place on Fields is + // not really feasible. + SmallVector Layout; + Layout.reserve(Fields.size()); + + // The offset that we're currently looking to insert at (or after). + uint64_t LastEnd = 0; + + // Helper function to splice Cur out of the given queue and add it + // to the layout at the given offset. + auto addToLayout = [&](AlignmentQueue *Queue, + OptimalLayoutField *Last, + OptimalLayoutField *Cur, + uint64_t Offset) -> bool { + assert(Offset == alignTo(LastEnd, Cur->Alignment)); + + // Splice out. This potentially invalidates Queue. + spliceFromQueue(Queue, Last, Cur); + + // Add Cur to the layout. + Layout.push_back(*Cur); + Layout.back().Offset = Offset; + LastEnd = Layout.back().getEndOffset(); + + // Always return true so that we can be tail-called. + return true; + }; + + // Helper function to try to find a field in the given queue that'll + // fit starting at StartOffset but before EndOffset (if present). + // Note that this never fails if EndOffset is not provided. + auto tryAddFillerFromQueue = [&](AlignmentQueue *Queue, + uint64_t StartOffset, + Optional EndOffset) -> bool { + assert(Queue->Head); + assert(StartOffset == alignTo(LastEnd, Queue->Alignment)); + + // Figure out the maximum size that a field can be, and ignore this + // queue if there's nothing in it that small. + auto MaxViableSize = + (EndOffset ? *EndOffset - StartOffset : ~(uint64_t)0); + if (Queue->MinSize > MaxViableSize) return false; + + // Find the matching field. Note that this should always find + // something because of the MinSize check above. + for (OptimalLayoutField *Cur = Queue->Head, *Last = nullptr; + true; Last = Cur, Cur = Queue->getNext(Cur)) { + assert(Cur && "didn't find a match in queue despite its MinSize"); + if (Cur->Size <= MaxViableSize) + return addToLayout(Queue, Last, Cur, StartOffset); + } + + llvm_unreachable("didn't find a match in queue despite its MinSize"); + }; + + // Helper function to find the "best" flexible-offset field according + // to the criteria described above. + auto tryAddBestField = [&](Optional BeforeOffset) -> bool { + auto QueueB = FlexibleFieldsByAlignment.begin(); + auto QueueE = FlexibleFieldsByAlignment.end(); + + // Start by looking for the most-aligned queue that doesn't need any + // leading padding after LastEnd. + auto FirstQueueToSearch = QueueB; + for (; FirstQueueToSearch != QueueE; ++FirstQueueToSearch) { + if (isAligned(FirstQueueToSearch->Alignment, LastEnd)) + break; + } + + uint64_t Offset = LastEnd; + while (true) { + // Invariant: all of the queues in [FirstQueueToSearch, QueueE) + // require the same initial padding offset. + + // Search those queues in descending order of alignment for a + // satisfactory field. + for (auto Queue = FirstQueueToSearch; Queue != QueueE; ++Queue) { + if (tryAddFillerFromQueue(Queue, Offset, BeforeOffset)) + return true; + } + + // Okay, we don't need to scan those again. + QueueE = FirstQueueToSearch; + + // If we started from the first queue, we're done. + if (FirstQueueToSearch == QueueB) + return false; + + // Otherwise, scan backwards to find the most-aligned queue that + // still has minimal leading padding after LastEnd. + --FirstQueueToSearch; + Offset = alignTo(LastEnd, FirstQueueToSearch->Alignment); + while (FirstQueueToSearch != QueueB && + Offset == alignTo(LastEnd, FirstQueueToSearch[-1].Alignment)) + --FirstQueueToSearch; + } + }; + + // Phase 1: fill the gaps between fixed-offset fields with the best + // flexible-offset field that fits. + for (auto I = Fields.begin(); I != FirstFlexible; ++I) { + while (LastEnd != I->Offset) { + if (!tryAddBestField(I->Offset)) + break; + } + Layout.push_back(*I); + LastEnd = I->getEndOffset(); + } + +#ifndef NDEBUG + checkQueues(); +#endif + + // Phase 2: repeatedly add the best flexible-offset field until + // they're all gone. + while (!FlexibleFieldsByAlignment.empty()) { + bool Success = tryAddBestField(None); + assert(Success && "didn't find a field with no fixed limit?"); + (void) Success; + } + + // Copy the layout back into place. + assert(Layout.size() == Fields.size()); + memcpy(Fields.data(), Layout.data(), + Fields.size() * sizeof(OptimalLayoutField)); + +#ifndef NDEBUG + // Make a final check that the layout is valid. + checkValidLayout(Fields, LastEnd, MaxAlign); +#endif + + return std::make_pair(LastEnd, MaxAlign); +} diff --git a/llvm/lib/Target/ARM/ARMParallelDSP.cpp b/llvm/lib/Target/ARM/ARMParallelDSP.cpp index e2c9335db4190..0d619e76e9bb0 100644 --- a/llvm/lib/Target/ARM/ARMParallelDSP.cpp +++ b/llvm/lib/Target/ARM/ARMParallelDSP.cpp @@ -20,7 +20,6 @@ #include "llvm/ADT/Statistic.h" #include "llvm/Analysis/AliasAnalysis.h" #include "llvm/Analysis/LoopAccessAnalysis.h" -#include "llvm/Analysis/OrderedBasicBlock.h" #include "llvm/CodeGen/TargetPassConfig.h" #include "llvm/IR/Instructions.h" #include "llvm/IR/IntrinsicsARM.h" @@ -352,7 +351,6 @@ bool ARMParallelDSP::RecordMemoryOps(BasicBlock *BB) { SmallVector Writes; LoadPairs.clear(); WideLoads.clear(); - OrderedBasicBlock OrderedBB(BB); // Collect loads and instruction that may write to memory. For now we only // record loads which are simple, sign-extended and have a single user. @@ -384,7 +382,7 @@ bool ARMParallelDSP::RecordMemoryOps(BasicBlock *BB) { if (!isModOrRefSet(intersectModRef(AA->getModRefInfo(Write, ReadLoc), ModRefInfo::ModRef))) continue; - if (OrderedBB.dominates(Write, Read)) + if (Write->comesBefore(Read)) RAWDeps[Read].insert(Write); } } @@ -392,8 +390,9 @@ bool ARMParallelDSP::RecordMemoryOps(BasicBlock *BB) { // Check whether there's not a write between the two loads which would // prevent them from being safely merged. auto SafeToPair = [&](LoadInst *Base, LoadInst *Offset) { - LoadInst *Dominator = OrderedBB.dominates(Base, Offset) ? Base : Offset; - LoadInst *Dominated = OrderedBB.dominates(Base, Offset) ? Offset : Base; + bool BaseFirst = Base->comesBefore(Offset); + LoadInst *Dominator = BaseFirst ? Base : Offset; + LoadInst *Dominated = BaseFirst ? Offset : Base; if (RAWDeps.count(Dominated)) { InstSet &WritesBefore = RAWDeps[Dominated]; @@ -401,7 +400,7 @@ bool ARMParallelDSP::RecordMemoryOps(BasicBlock *BB) { for (auto Before : WritesBefore) { // We can't move the second load backward, past a write, to merge // with the first load. - if (OrderedBB.dominates(Dominator, Before)) + if (Dominator->comesBefore(Before)) return false; } } @@ -705,12 +704,11 @@ void ARMParallelDSP::InsertParallelMACs(Reduction &R) { } // Roughly sort the mul pairs in their program order. - OrderedBasicBlock OrderedBB(R.getRoot()->getParent()); - llvm::sort(R.getMulPairs(), [&OrderedBB](auto &PairA, auto &PairB) { - const Instruction *A = PairA.first->Root; - const Instruction *B = PairB.first->Root; - return OrderedBB.dominates(A, B); - }); + llvm::sort(R.getMulPairs(), [](auto &PairA, auto &PairB) { + const Instruction *A = PairA.first->Root; + const Instruction *B = PairB.first->Root; + return A->comesBefore(B); + }); IntegerType *Ty = IntegerType::get(M->getContext(), 32); for (auto &Pair : R.getMulPairs()) { diff --git a/llvm/lib/TextAPI/MachO/TextStub.cpp b/llvm/lib/TextAPI/MachO/TextStub.cpp index 0584e43d5893f..f4e370aa822b4 100644 --- a/llvm/lib/TextAPI/MachO/TextStub.cpp +++ b/llvm/lib/TextAPI/MachO/TextStub.cpp @@ -959,7 +959,8 @@ template <> struct MappingTraits { for (auto &sym : CurrentSection.WeakSymbols) File->addSymbol(SymbolKind::GlobalSymbol, sym, - CurrentSection.Targets); + CurrentSection.Targets, SymbolFlags::WeakDefined); + for (auto &sym : CurrentSection.TlvSymbols) File->addSymbol(SymbolKind::GlobalSymbol, sym, CurrentSection.Targets, diff --git a/llvm/lib/Transforms/Coroutines/CoroEarly.cpp b/llvm/lib/Transforms/Coroutines/CoroEarly.cpp index e73fb9eeb1e9d..02f7a420e8cd0 100644 --- a/llvm/lib/Transforms/Coroutines/CoroEarly.cpp +++ b/llvm/lib/Transforms/Coroutines/CoroEarly.cpp @@ -64,14 +64,14 @@ void Lowerer::lowerResumeOrDestroy(CallSite CS, // TODO: Handle the case when coroutine promise alloca has align override. void Lowerer::lowerCoroPromise(CoroPromiseInst *Intrin) { Value *Operand = Intrin->getArgOperand(0); - unsigned Alignement = Intrin->getAlignment(); + Align Alignment = Intrin->getAlignment(); Type *Int8Ty = Builder.getInt8Ty(); auto *SampleStruct = StructType::get(Context, {AnyResumeFnPtrTy, AnyResumeFnPtrTy, Int8Ty}); const DataLayout &DL = TheModule.getDataLayout(); int64_t Offset = alignTo( - DL.getStructLayout(SampleStruct)->getElementOffset(2), Alignement); + DL.getStructLayout(SampleStruct)->getElementOffset(2), Alignment); if (Intrin->isFromPromise()) Offset = -Offset; diff --git a/llvm/lib/Transforms/Coroutines/CoroElide.cpp b/llvm/lib/Transforms/Coroutines/CoroElide.cpp index 23d22e23861a5..889fcff889842 100644 --- a/llvm/lib/Transforms/Coroutines/CoroElide.cpp +++ b/llvm/lib/Transforms/Coroutines/CoroElide.cpp @@ -35,7 +35,8 @@ struct Lowerer : coro::LowererBase { Lowerer(Module &M) : LowererBase(M) {} - void elideHeapAllocations(Function *F, Type *FrameTy, AAResults &AA); + void elideHeapAllocations(Function *F, uint64_t FrameSize, + MaybeAlign FrameAlign, AAResults &AA); bool shouldElide(Function *F, DominatorTree &DT) const; bool processCoroId(CoroIdInst *, AAResults &AA, DominatorTree &DT); }; @@ -90,10 +91,23 @@ static void removeTailCallAttribute(AllocaInst *Frame, AAResults &AA) { } } -// Given a resume function @f.resume(%f.frame* %frame), returns %f.frame type. -static Type *getFrameType(Function *Resume) { - auto *ArgType = Resume->arg_begin()->getType(); - return cast(ArgType)->getElementType(); +// Given a resume function @f.resume(%f.frame* %frame), returns the size +// and expected alignment of %f.frame type. +static std::pair getFrameLayout(Function *Resume) { + // Prefer to pull information from the function attributes. + auto Size = Resume->getParamDereferenceableBytes(0); + auto Align = Resume->getParamAlign(0); + + // If those aren't given, extract them from the type. + if (Size == 0 || !Align) { + auto *FrameTy = Resume->arg_begin()->getType()->getPointerElementType(); + + const DataLayout &DL = Resume->getParent()->getDataLayout(); + if (!Size) Size = DL.getTypeAllocSize(FrameTy); + if (!Align) Align = llvm::Align(DL.getABITypeAlignment(FrameTy)); + } + + return std::make_pair(Size, Align); } // Finds first non alloca instruction in the entry block of a function. @@ -106,8 +120,9 @@ static Instruction *getFirstNonAllocaInTheEntryBlock(Function *F) { // To elide heap allocations we need to suppress code blocks guarded by // llvm.coro.alloc and llvm.coro.free instructions. -void Lowerer::elideHeapAllocations(Function *F, Type *FrameTy, AAResults &AA) { - LLVMContext &C = FrameTy->getContext(); +void Lowerer::elideHeapAllocations(Function *F, uint64_t FrameSize, + MaybeAlign FrameAlign, AAResults &AA) { + LLVMContext &C = F->getContext(); auto *InsertPt = getFirstNonAllocaInTheEntryBlock(CoroIds.front()->getFunction()); @@ -128,7 +143,9 @@ void Lowerer::elideHeapAllocations(Function *F, Type *FrameTy, AAResults &AA) { // here. Possibly we will need to do a mini SROA here and break the coroutine // frame into individual AllocaInst recreating the original alignment. const DataLayout &DL = F->getParent()->getDataLayout(); + auto FrameTy = ArrayType::get(Type::getInt8Ty(C), FrameSize); auto *Frame = new AllocaInst(FrameTy, DL.getAllocaAddrSpace(), "", InsertPt); + Frame->setAlignment(FrameAlign); auto *FrameVoidPtr = new BitCastInst(Frame, Type::getInt8PtrTy(C), "vFrame", InsertPt); @@ -244,8 +261,9 @@ bool Lowerer::processCoroId(CoroIdInst *CoroId, AAResults &AA, replaceWithConstant(DestroyAddrConstant, DestroyAddr); if (ShouldElide) { - auto *FrameTy = getFrameType(cast(ResumeAddrConstant)); - elideHeapAllocations(CoroId->getFunction(), FrameTy, AA); + auto FrameSizeAndAlign = getFrameLayout(cast(ResumeAddrConstant)); + elideHeapAllocations(CoroId->getFunction(), FrameSizeAndAlign.first, + FrameSizeAndAlign.second, AA); coro::replaceCoroFree(CoroId, /*Elide=*/true); } diff --git a/llvm/lib/Transforms/Coroutines/CoroFrame.cpp b/llvm/lib/Transforms/Coroutines/CoroFrame.cpp index 2c42cf8a6d259..e6cbfa3198e73 100644 --- a/llvm/lib/Transforms/Coroutines/CoroFrame.cpp +++ b/llvm/lib/Transforms/Coroutines/CoroFrame.cpp @@ -28,6 +28,7 @@ #include "llvm/Support/Debug.h" #include "llvm/Support/MathExtras.h" #include "llvm/Support/circular_raw_ostream.h" +#include "llvm/Support/OptimalLayout.h" #include "llvm/Transforms/Utils/BasicBlockUtils.h" #include "llvm/Transforms/Utils/PromoteMemToReg.h" @@ -338,52 +339,182 @@ namespace { // coroutine frame and if the alignment specified on the Alloca instruction // differs from the natural alignment of the alloca type we will need to insert // padding. -struct PaddingCalculator { +class FrameTypeBuilder { + struct Field { + uint64_t Size; + uint64_t Offset; + Spill *ForSpill; + Type *Ty; + unsigned FieldIndex; + Align Alignment; + Align TyAlignment; + }; + const DataLayout &DL; LLVMContext &Context; - unsigned StructSize = 0; + uint64_t StructSize = 0; + Align StructAlign; + bool IsFinished = false; - PaddingCalculator(LLVMContext &Context, DataLayout const &DL) - : DL(DL), Context(Context) {} + SmallVector Fields; + DenseMap FieldIndexByKey; - // Replicate the logic from IR/DataLayout.cpp to match field offset - // computation for LLVM structs. - void addType(Type *Ty) { - unsigned TyAlign = DL.getABITypeAlignment(Ty); - if ((StructSize & (TyAlign - 1)) != 0) - StructSize = alignTo(StructSize, TyAlign); +public: + FrameTypeBuilder(LLVMContext &Context, DataLayout const &DL) + : DL(DL), Context(Context) {} - StructSize += DL.getTypeAllocSize(Ty); // Consume space for this data item. - } + class FieldId { + size_t Value; + explicit FieldId(size_t Value) : Value(Value) {} - void addTypes(SmallVectorImpl const &Types) { - for (auto *Ty : Types) - addType(Ty); + friend class FrameTypeBuilder; + }; + + /// Add a field to this structure for the storage of an `alloca` + /// instruction. + FieldId addFieldForAlloca(AllocaInst *AI, Spill *ForSpill = nullptr, + bool IsHeader = false) { + Type *Ty = AI->getAllocatedType(); + + // Make an array type if this is a static array allocation. + if (AI->isArrayAllocation()) { + if (auto *CI = dyn_cast(AI->getArraySize())) + Ty = ArrayType::get(Ty, CI->getValue().getZExtValue()); + else + report_fatal_error("Coroutines cannot handle non static allocas yet"); + } + + return addField(Ty, MaybeAlign(AI->getAlignment()), ForSpill, IsHeader); } - unsigned computePadding(Type *Ty, unsigned ForcedAlignment) { - unsigned TyAlign = DL.getABITypeAlignment(Ty); - auto Natural = alignTo(StructSize, TyAlign); - auto Forced = alignTo(StructSize, ForcedAlignment); + /// Add a field to this structure. + FieldId addField(Type *Ty, MaybeAlign FieldAlignment, + Spill *ForSpill = nullptr, + bool IsHeader = false) { + assert(!IsFinished && "adding fields to a finished builder"); + assert(Ty && "must provide a type for a field"); - // Return how many bytes of padding we need to insert. - if (Natural != Forced) - return std::max(Natural, Forced) - StructSize; + // The field size is always the alloc size of the type. + uint64_t FieldSize = DL.getTypeAllocSize(Ty); - // Rely on natural alignment. - return 0; + // The field alignment might not be the type alignment, but we need + // to remember the type alignment anyway to build the type. + Align TyAlignment = Align(DL.getABITypeAlignment(Ty)); + if (!FieldAlignment) FieldAlignment = TyAlignment; + + // Lay out header fields immediately. + uint64_t Offset; + if (IsHeader) { + Offset = alignTo(StructSize, FieldAlignment); + StructSize = Offset + FieldSize; + + // Everything else has a flexible offset. + } else { + Offset = OptimalLayoutField::FlexibleOffset; + } + + Fields.push_back({FieldSize, Offset, ForSpill, Ty, 0, + *FieldAlignment, TyAlignment}); + return FieldId(Fields.size() - 1); } - // If padding required, return the padding field type to insert. - ArrayType *getPaddingType(Type *Ty, unsigned ForcedAlignment) { - if (auto Padding = computePadding(Ty, ForcedAlignment)) - return ArrayType::get(Type::getInt8Ty(Context), Padding); + /// Finish the layout and set the body on the given type. + void finish(StructType *Ty); + + uint64_t getStructSize() const { + assert(IsFinished && "not yet finished!"); + return StructSize; + } - return nullptr; + Align getStructAlign() const { + assert(IsFinished && "not yet finished!"); + return StructAlign; + } + + unsigned getFieldIndex(FieldId Id) const { + assert(IsFinished && "not yet finished!"); + return Fields[Id.Value].FieldIndex; } }; } // namespace +void FrameTypeBuilder::finish(StructType *Ty) { + assert(!IsFinished && "already finished!"); + + // Prepare the optimal-layout field array. + // The Id in the layout field is a pointer to our Field for it. + SmallVector LayoutFields; + LayoutFields.reserve(Fields.size()); + for (auto &Field : Fields) { + LayoutFields.emplace_back(&Field, Field.Size, Field.Alignment, + Field.Offset); + } + + // Perform layout. + auto SizeAndAlign = performOptimalLayout(LayoutFields); + StructSize = SizeAndAlign.first; + StructAlign = SizeAndAlign.second; + + auto getField = [](const OptimalLayoutField &LayoutField) -> Field & { + return *static_cast(const_cast(LayoutField.Id)); + }; + + // We need to produce a packed struct type if there's a field whose + // assigned offset isn't a multiple of its natural type alignment. + bool Packed = [&] { + for (auto &LayoutField : LayoutFields) { + auto &F = getField(LayoutField); + if (!isAligned(F.TyAlignment, LayoutField.Offset)) + return true; + } + return false; + }(); + + // Build the struct body. + SmallVector FieldTypes; + FieldTypes.reserve(LayoutFields.size() * 3 / 2); + uint64_t LastOffset = 0; + for (auto &LayoutField : LayoutFields) { + auto &F = getField(LayoutField); + + auto Offset = LayoutField.Offset; + + // Add a padding field if there's a padding gap and we're either + // building a packed struct or the padding gap is more than we'd + // get from aligning to the field type's natural alignment. + assert(Offset >= LastOffset); + if (Offset != LastOffset) { + if (Packed || alignTo(LastOffset, F.TyAlignment) != Offset) + FieldTypes.push_back(ArrayType::get(Type::getInt8Ty(Context), + Offset - LastOffset)); + } + + // Record the layout information into both the Field and the + // original Spill, if there is one. + F.Offset = Offset; + F.FieldIndex = FieldTypes.size(); + if (F.ForSpill) { + F.ForSpill->setFieldIndex(F.FieldIndex); + } + + FieldTypes.push_back(F.Ty); + LastOffset = Offset + F.Size; + } + + Ty->setBody(FieldTypes, Packed); + +#ifndef NDEBUG + // Check that the IR layout matches the offsets we expect. + auto Layout = DL.getStructLayout(Ty); + for (auto &F : Fields) { + assert(Ty->getElementType(F.FieldIndex) == F.Ty); + assert(Layout->getElementOffset(F.FieldIndex) == F.Offset); + } +#endif + + IsFinished = true; +} + // Build a struct that will keep state for an active coroutine. // struct f.frame { // ResumeFnTy ResumeFnAddr; @@ -396,13 +527,17 @@ static StructType *buildFrameType(Function &F, coro::Shape &Shape, SpillInfo &Spills) { LLVMContext &C = F.getContext(); const DataLayout &DL = F.getParent()->getDataLayout(); - PaddingCalculator Padder(C, DL); - SmallString<32> Name(F.getName()); - Name.append(".Frame"); - StructType *FrameTy = StructType::create(C, Name); - SmallVector Types; + StructType *FrameTy = [&] { + SmallString<32> Name(F.getName()); + Name.append(".Frame"); + return StructType::create(C, Name); + }(); + + FrameTypeBuilder B(C, DL); AllocaInst *PromiseAlloca = Shape.getPromiseAlloca(); + Optional PromiseFieldId; + Optional SwitchIndexFieldId; if (Shape.ABI == coro::ABI::Switch) { auto *FramePtrTy = FrameTy->getPointerTo(); @@ -410,74 +545,74 @@ static StructType *buildFrameType(Function &F, coro::Shape &Shape, /*IsVarArg=*/false); auto *FnPtrTy = FnTy->getPointerTo(); - // Figure out how wide should be an integer type storing the suspend index. + // Add header fields for the resume and destroy functions. + // We can rely on these being perfectly packed. + B.addField(FnPtrTy, None, nullptr, /*header*/ true); + B.addField(FnPtrTy, None, nullptr, /*header*/ true); + + // Add a header field for the promise if there is one. + if (PromiseAlloca) { + PromiseFieldId = + B.addFieldForAlloca(PromiseAlloca, nullptr, /*header*/ true); + } + + // Add a field to store the suspend index. This doesn't need to + // be in the header. unsigned IndexBits = std::max(1U, Log2_64_Ceil(Shape.CoroSuspends.size())); - Type *PromiseType = PromiseAlloca - ? PromiseAlloca->getType()->getElementType() - : Type::getInt1Ty(C); Type *IndexType = Type::getIntNTy(C, IndexBits); - Types.push_back(FnPtrTy); - Types.push_back(FnPtrTy); - Types.push_back(PromiseType); - Types.push_back(IndexType); + + SwitchIndexFieldId = B.addField(IndexType, None); } else { assert(PromiseAlloca == nullptr && "lowering doesn't support promises"); } Value *CurrentDef = nullptr; - Padder.addTypes(Types); - // Create an entry for every spilled value. for (auto &S : Spills) { + // We can have multiple entries in Spills for a single value, but + // they should form a contiguous run. Ignore all but the first. if (CurrentDef == S.def()) continue; CurrentDef = S.def(); - // PromiseAlloca was already added to Types array earlier. - if (CurrentDef == PromiseAlloca) - continue; - uint64_t Count = 1; - Type *Ty = nullptr; + assert(CurrentDef != PromiseAlloca && + "recorded spill use of promise alloca?"); + if (auto *AI = dyn_cast(CurrentDef)) { - Ty = AI->getAllocatedType(); - if (unsigned AllocaAlignment = AI->getAlignment()) { - // If alignment is specified in alloca, see if we need to insert extra - // padding. - if (auto PaddingTy = Padder.getPaddingType(Ty, AllocaAlignment)) { - Types.push_back(PaddingTy); - Padder.addType(PaddingTy); - } - } - if (auto *CI = dyn_cast(AI->getArraySize())) - Count = CI->getValue().getZExtValue(); - else - report_fatal_error("Coroutines cannot handle non static allocas yet"); + B.addFieldForAlloca(AI, &S); } else { - Ty = CurrentDef->getType(); + Type *Ty = CurrentDef->getType(); + B.addField(Ty, None, &S); } - S.setFieldIndex(Types.size()); - if (Count == 1) - Types.push_back(Ty); - else - Types.push_back(ArrayType::get(Ty, Count)); - Padder.addType(Ty); } - FrameTy->setBody(Types); + + B.finish(FrameTy); + Shape.FrameAlign = B.getStructAlign(); + Shape.FrameSize = B.getStructSize(); switch (Shape.ABI) { + // In the switch ABI, remember the field indices for the promise and + // switch-index fields. case coro::ABI::Switch: + Shape.SwitchLowering.IndexField = + B.getFieldIndex(*SwitchIndexFieldId); + Shape.SwitchLowering.PromiseField = + (PromiseAlloca ? B.getFieldIndex(*PromiseFieldId) : 0); + + // Also round the frame size up to a multiple of its alignment, as is + // generally expected in C/C++. + Shape.FrameSize = alignTo(Shape.FrameSize, Shape.FrameAlign); break; - // Remember whether the frame is inline in the storage. + // In the retcon ABI, remember whether the frame is inline in the storage. case coro::ABI::Retcon: case coro::ABI::RetconOnce: { - auto &Layout = F.getParent()->getDataLayout(); auto Id = Shape.getRetconCoroId(); Shape.RetconLowering.IsFrameInlineInStorage - = (Layout.getTypeAllocSize(FrameTy) <= Id->getStorageSize() && - Layout.getABITypeAlignment(FrameTy) <= Id->getStorageAlignment()); + = (B.getStructSize() <= Id->getStorageSize() && + B.getStructAlign() <= Id->getStorageAlignment()); break; } } @@ -606,10 +741,12 @@ static Instruction *insertSpills(const SpillInfo &Spills, coro::Shape &Shape) { // we remember allocas and their indices to be handled once we processed // all the spills. SmallVector, 4> Allocas; - // Promise alloca (if present) has a fixed field number. + + // Promise alloca (if present) doesn't show in the spills and has a + // special field number. if (auto *PromiseAlloca = Shape.getPromiseAlloca()) { assert(Shape.ABI == coro::ABI::Switch); - Allocas.emplace_back(PromiseAlloca, coro::Shape::SwitchFieldIndex::Promise); + Allocas.emplace_back(PromiseAlloca, Shape.getPromiseField()); } // Create a GEP with the given index into the coroutine frame for the original diff --git a/llvm/lib/Transforms/Coroutines/CoroInstr.h b/llvm/lib/Transforms/Coroutines/CoroInstr.h index de2d2920cb15a..384e20cd0a9b2 100644 --- a/llvm/lib/Transforms/Coroutines/CoroInstr.h +++ b/llvm/lib/Transforms/Coroutines/CoroInstr.h @@ -211,8 +211,8 @@ class LLVM_LIBRARY_VISIBILITY AnyCoroIdRetconInst : public AnyCoroIdInst { return cast(getArgOperand(SizeArg))->getZExtValue(); } - uint64_t getStorageAlignment() const { - return cast(getArgOperand(AlignArg))->getZExtValue(); + Align getStorageAlignment() const { + return Align(cast(getArgOperand(AlignArg))->getZExtValue()); } Value *getStorage() const { @@ -338,11 +338,16 @@ class LLVM_LIBRARY_VISIBILITY CoroPromiseInst : public IntrinsicInst { enum { FrameArg, AlignArg, FromArg }; public: + /// Are we translating from the frame to the promise (false) or from + /// the promise to the frame (true)? bool isFromPromise() const { return cast(getArgOperand(FromArg))->isOneValue(); } - unsigned getAlignment() const { - return cast(getArgOperand(AlignArg))->getZExtValue(); + + /// The required alignment of the promise. This must match the + /// alignment of the promise alloca in the coroutine. + Align getAlignment() const { + return Align(cast(getArgOperand(AlignArg))->getZExtValue()); } // Methods to support type inquiry through isa, cast, and dyn_cast: diff --git a/llvm/lib/Transforms/Coroutines/CoroInternal.h b/llvm/lib/Transforms/Coroutines/CoroInternal.h index 7eb35400c0d51..bd76e93c91241 100644 --- a/llvm/lib/Transforms/Coroutines/CoroInternal.h +++ b/llvm/lib/Transforms/Coroutines/CoroInternal.h @@ -96,17 +96,22 @@ struct LLVM_LIBRARY_VISIBILITY Shape { struct SwitchFieldIndex { enum { Resume, - Destroy, - Promise, - Index, - /// The index of the first spill field. - FirstSpill + Destroy + + // The promise field is always at a fixed offset from the start of + // frame given its type, but the index isn't a constant for all + // possible frames. + + // The switch-index field isn't at a fixed offset or index, either; + // we just work it in where it fits best. }; }; coro::ABI ABI; StructType *FrameTy; + Align FrameAlign; + uint64_t FrameSize; Instruction *FramePtr; BasicBlock *AllocaSpillBlock; @@ -114,6 +119,8 @@ struct LLVM_LIBRARY_VISIBILITY Shape { SwitchInst *ResumeSwitch; AllocaInst *PromiseAlloca; BasicBlock *ResumeEntryBlock; + unsigned IndexField; + unsigned PromiseField; bool HasFinalSuspend; }; @@ -141,10 +148,15 @@ struct LLVM_LIBRARY_VISIBILITY Shape { return cast(CoroBegin->getId()); } + unsigned getSwitchIndexField() const { + assert(ABI == coro::ABI::Switch); + assert(FrameTy && "frame type not assigned"); + return SwitchLowering.IndexField; + } IntegerType *getIndexType() const { assert(ABI == coro::ABI::Switch); assert(FrameTy && "frame type not assigned"); - return cast(FrameTy->getElementType(SwitchFieldIndex::Index)); + return cast(FrameTy->getElementType(getSwitchIndexField())); } ConstantInt *getIndex(uint64_t Value) const { return ConstantInt::get(getIndexType(), Value); @@ -203,23 +215,17 @@ struct LLVM_LIBRARY_VISIBILITY Shape { llvm_unreachable("Unknown coro::ABI enum"); } - unsigned getFirstSpillFieldIndex() const { - switch (ABI) { - case coro::ABI::Switch: - return SwitchFieldIndex::FirstSpill; - - case coro::ABI::Retcon: - case coro::ABI::RetconOnce: - return 0; - } - llvm_unreachable("Unknown coro::ABI enum"); - } - AllocaInst *getPromiseAlloca() const { if (ABI == coro::ABI::Switch) return SwitchLowering.PromiseAlloca; return nullptr; } + unsigned getPromiseField() const { + assert(ABI == coro::ABI::Switch); + assert(FrameTy && "frame type not assigned"); + assert(SwitchLowering.PromiseAlloca && "no promise alloca"); + return SwitchLowering.PromiseField; + } /// Allocate memory according to the rules of the active lowering. /// diff --git a/llvm/lib/Transforms/Coroutines/CoroSplit.cpp b/llvm/lib/Transforms/Coroutines/CoroSplit.cpp index 66cb3e74e53e6..c83a7f2e0ed52 100644 --- a/llvm/lib/Transforms/Coroutines/CoroSplit.cpp +++ b/llvm/lib/Transforms/Coroutines/CoroSplit.cpp @@ -283,7 +283,7 @@ static void createResumeEntryBlock(Function &F, coro::Shape &Shape) { auto *FramePtr = Shape.FramePtr; auto *FrameTy = Shape.FrameTy; auto *GepIndex = Builder.CreateStructGEP( - FrameTy, FramePtr, coro::Shape::SwitchFieldIndex::Index, "index.addr"); + FrameTy, FramePtr, Shape.getSwitchIndexField(), "index.addr"); auto *Index = Builder.CreateLoad(Shape.getIndexType(), GepIndex, "index"); auto *Switch = Builder.CreateSwitch(Index, UnreachBB, Shape.CoroSuspends.size()); @@ -309,7 +309,7 @@ static void createResumeEntryBlock(Function &F, coro::Shape &Shape) { Builder.CreateStore(NullPtr, GepIndex); } else { auto *GepIndex = Builder.CreateStructGEP( - FrameTy, FramePtr, coro::Shape::SwitchFieldIndex::Index, "index.addr"); + FrameTy, FramePtr, Shape.getSwitchIndexField(), "index.addr"); Builder.CreateStore(IndexVal, GepIndex); } Save->replaceAllUsesWith(ConstantTokenNone::get(C)); @@ -636,6 +636,17 @@ Value *CoroCloner::deriveNewFramePointer() { llvm_unreachable("bad ABI"); } +static void addFramePointerAttrs(AttributeList &Attrs, LLVMContext &Context, + unsigned ParamIndex, + uint64_t Size, Align Alignment) { + AttrBuilder ParamAttrs; + ParamAttrs.addAttribute(Attribute::NonNull); + ParamAttrs.addAttribute(Attribute::NoAlias); + ParamAttrs.addAlignmentAttr(Alignment); + ParamAttrs.addDereferenceableAttr(Size); + Attrs = Attrs.addParamAttributes(Context, ParamIndex, ParamAttrs); +} + /// Clone the body of the original function into a resume function of /// some sort. void CoroCloner::create() { @@ -684,6 +695,9 @@ void CoroCloner::create() { // original function. This should include optimization settings and so on. NewAttrs = NewAttrs.addAttributes(Context, AttributeList::FunctionIndex, OrigAttrs.getFnAttributes()); + + addFramePointerAttrs(NewAttrs, Context, 0, + Shape.FrameSize, Shape.FrameAlign); break; case coro::ABI::Retcon: @@ -691,13 +705,13 @@ void CoroCloner::create() { // If we have a continuation prototype, just use its attributes, // full-stop. NewAttrs = Shape.RetconLowering.ResumePrototype->getAttributes(); + + addFramePointerAttrs(NewAttrs, Context, 0, + Shape.getRetconCoroId()->getStorageSize(), + Shape.getRetconCoroId()->getStorageAlignment()); break; } - // Make the frame parameter nonnull and noalias. - NewAttrs = NewAttrs.addParamAttribute(Context, 0, Attribute::NonNull); - NewAttrs = NewAttrs.addParamAttribute(Context, 0, Attribute::NoAlias); - switch (Shape.ABI) { // In these ABIs, the cloned functions always return 'void', and the // existing return sites are meaningless. Note that for unique @@ -993,8 +1007,8 @@ static void handleNoSuspendCoroutine(coro::Shape &Shape) { coro::replaceCoroFree(SwitchId, /*Elide=*/AllocInst != nullptr); if (AllocInst) { IRBuilder<> Builder(AllocInst); - // FIXME: Need to handle overaligned members. auto *Frame = Builder.CreateAlloca(Shape.FrameTy); + Frame->setAlignment(Shape.FrameAlign); auto *VFrame = Builder.CreateBitCast(Frame, Builder.getInt8PtrTy()); AllocInst->replaceAllUsesWith(Builder.getFalse()); AllocInst->eraseFromParent(); @@ -1225,6 +1239,7 @@ static void splitRetconCoroutine(Function &F, coro::Shape &Shape, // Allocate. We don't need to update the call graph node because we're // going to recompute it from scratch after splitting. + // FIXME: pass the required alignment RawFramePtr = Shape.emitAlloc(Builder, Builder.getInt64(Size), nullptr); RawFramePtr = Builder.CreateBitCast(RawFramePtr, Shape.CoroBegin->getType()); diff --git a/llvm/lib/Transforms/IPO/GlobalOpt.cpp b/llvm/lib/Transforms/IPO/GlobalOpt.cpp index beb3785eda31f..06659760e7cdc 100644 --- a/llvm/lib/Transforms/IPO/GlobalOpt.cpp +++ b/llvm/lib/Transforms/IPO/GlobalOpt.cpp @@ -659,9 +659,6 @@ static bool AllUsesOfValueWillTrapIfNull(const Value *V, // checked. if (PHIs.insert(PN).second && !AllUsesOfValueWillTrapIfNull(PN, PHIs)) return false; - } else if (isa(U) && - isa(U->getOperand(1))) { - // Ignore icmp X, null } else { //cerr << "NONTRAPPING USE: " << *U; return false; diff --git a/llvm/lib/Transforms/InstCombine/InstructionCombining.cpp b/llvm/lib/Transforms/InstCombine/InstructionCombining.cpp index e31023607e807..8901f3f2f5645 100644 --- a/llvm/lib/Transforms/InstCombine/InstructionCombining.cpp +++ b/llvm/lib/Transforms/InstCombine/InstructionCombining.cpp @@ -2517,7 +2517,7 @@ static Instruction *tryToMoveFreeBeforeNullTest(CallInst &FI, // If there are more than 2 instructions, check that they are noops // i.e., they won't hurt the performance of the generated code. if (FreeInstrBB->size() != 2) { - for (const Instruction &Inst : *FreeInstrBB) { + for (const Instruction &Inst : FreeInstrBB->instructionsWithoutDebug()) { if (&Inst == &FI || &Inst == FreeInstrBBTerminator) continue; auto *Cast = dyn_cast(&Inst); diff --git a/llvm/lib/Transforms/Instrumentation/AddressSanitizer.cpp b/llvm/lib/Transforms/Instrumentation/AddressSanitizer.cpp index 0688ef628e90c..d77fbd73af1ff 100644 --- a/llvm/lib/Transforms/Instrumentation/AddressSanitizer.cpp +++ b/llvm/lib/Transforms/Instrumentation/AddressSanitizer.cpp @@ -2984,6 +2984,59 @@ void FunctionStackPoisoner::processDynamicAllocas() { unpoisonDynamicAllocas(); } +/// Collect instructions in the entry block after \p InsBefore which initialize +/// permanent storage for a function argument. These instructions must remain in +/// the entry block so that uninitialized values do not appear in backtraces. An +/// added benefit is that this conserves spill slots. This does not move stores +/// before instrumented / "interesting" allocas. +static void findStoresToUninstrumentedArgAllocas( + AddressSanitizer &ASan, Instruction &InsBefore, + SmallVectorImpl &InitInsts) { + Instruction *Start = InsBefore.getNextNonDebugInstruction(); + for (Instruction *It = Start; It; It = It->getNextNonDebugInstruction()) { + // Argument initialization looks like: + // 1) store , OR + // 2) = cast to ... + // store to + // Do not consider any other kind of instruction. + // + // Note: This covers all known cases, but may not be exhaustive. An + // alternative to pattern-matching stores is to DFS over all Argument uses: + // this might be more general, but is probably much more complicated. + if (isa(It) || isa(It)) + continue; + if (auto *Store = dyn_cast(It)) { + // The store destination must be an alloca that isn't interesting for + // ASan to instrument. These are moved up before InsBefore, and they're + // not interesting because allocas for arguments can be mem2reg'd. + auto *Alloca = dyn_cast(Store->getPointerOperand()); + if (!Alloca || ASan.isInterestingAlloca(*Alloca)) + continue; + + Value *Val = Store->getValueOperand(); + bool IsDirectArgInit = isa(Val); + bool IsArgInitViaCast = + isa(Val) && + isa(cast(Val)->getOperand(0)) && + // Check that the cast appears directly before the store. Otherwise + // moving the cast before InsBefore may break the IR. + Val == It->getPrevNonDebugInstruction(); + bool IsArgInit = IsDirectArgInit || IsArgInitViaCast; + if (!IsArgInit) + continue; + + if (IsArgInitViaCast) + InitInsts.push_back(cast(Val)); + InitInsts.push_back(Store); + continue; + } + + // Do not reorder past unknown instructions: argument initialization should + // only involve casts and stores. + return; + } +} + void FunctionStackPoisoner::processStaticAllocas() { if (AllocaVec.empty()) { assert(StaticAllocaPoisonCallVec.empty()); @@ -3007,6 +3060,15 @@ void FunctionStackPoisoner::processStaticAllocas() { if (AI->getParent() == InsBeforeB) AI->moveBefore(InsBefore); + // Move stores of arguments into entry-block allocas as well. This prevents + // extra stack slots from being generated (to house the argument values until + // they can be stored into the allocas). This also prevents uninitialized + // values from being shown in backtraces. + SmallVector ArgInitInsts; + findStoresToUninstrumentedArgAllocas(ASan, *InsBefore, ArgInitInsts); + for (Instruction *ArgInitInst : ArgInitInsts) + ArgInitInst->moveBefore(InsBefore); + // If we have a call to llvm.localescape, keep it in the entry block. if (LocalEscapeCall) LocalEscapeCall->moveBefore(InsBefore); diff --git a/llvm/lib/Transforms/ObjCARC/ObjCARCOpts.cpp b/llvm/lib/Transforms/ObjCARC/ObjCARCOpts.cpp index 577a744f30626..9da202eba95e6 100644 --- a/llvm/lib/Transforms/ObjCARC/ObjCARCOpts.cpp +++ b/llvm/lib/Transforms/ObjCARC/ObjCARCOpts.cpp @@ -2344,6 +2344,14 @@ void ObjCARCOpt::OptimizeReturns(Function &F) { bool HasSafePathToCall = HasSafePathToPredecessorCall(Arg, Retain, DependingInstructions, Visited, PA); + + // Don't remove retainRV/autoreleaseRV pairs if the call isn't a tail call. + if (HasSafePathToCall && + GetBasicARCInstKind(Retain) == ARCInstKind::RetainRV && + GetBasicARCInstKind(Autorelease) == ARCInstKind::AutoreleaseRV && + !cast(*DependingInstructions.begin())->isTailCall()) + continue; + DependingInstructions.clear(); Visited.clear(); diff --git a/llvm/lib/Transforms/Scalar/DeadStoreElimination.cpp b/llvm/lib/Transforms/Scalar/DeadStoreElimination.cpp index 8da1f560f7b97..77ad46edf3264 100644 --- a/llvm/lib/Transforms/Scalar/DeadStoreElimination.cpp +++ b/llvm/lib/Transforms/Scalar/DeadStoreElimination.cpp @@ -31,7 +31,6 @@ #include "llvm/Analysis/MemoryLocation.h" #include "llvm/Analysis/MemorySSA.h" #include "llvm/Analysis/MemorySSAUpdater.h" -#include "llvm/Analysis/OrderedBasicBlock.h" #include "llvm/Analysis/PostDominators.h" #include "llvm/Analysis/TargetLibraryInfo.h" #include "llvm/Analysis/ValueTracking.h" @@ -122,7 +121,7 @@ using InstOverlapIntervalsTy = DenseMap; static void deleteDeadInstruction(Instruction *I, BasicBlock::iterator *BBI, MemoryDependenceResults &MD, const TargetLibraryInfo &TLI, - InstOverlapIntervalsTy &IOL, OrderedBasicBlock &OBB, + InstOverlapIntervalsTy &IOL, MapVector &ThrowableInst, SmallSetVector *ValueSet = nullptr) { SmallVector NowDeadInsts; @@ -144,7 +143,7 @@ deleteDeadInstruction(Instruction *I, BasicBlock::iterator *BBI, ++NumFastOther; // Try to preserve debug information attached to the dead instruction. - salvageDebugInfo(*DeadInst); + salvageDebugInfoOrMarkUndef(*DeadInst); // This instruction is dead, zap it, in stages. Start by removing it from // MemDep, which needs to know the operands and needs it to be in the @@ -165,7 +164,6 @@ deleteDeadInstruction(Instruction *I, BasicBlock::iterator *BBI, if (ValueSet) ValueSet->remove(DeadInst); IOL.erase(DeadInst); - OBB.eraseInstruction(DeadInst); if (NewIter == DeadInst->getIterator()) NewIter = DeadInst->eraseFromParent(); @@ -688,7 +686,7 @@ static void findUnconditionalPreds(SmallVectorImpl &Blocks, static bool handleFree(CallInst *F, AliasAnalysis *AA, MemoryDependenceResults *MD, DominatorTree *DT, const TargetLibraryInfo *TLI, - InstOverlapIntervalsTy &IOL, OrderedBasicBlock &OBB, + InstOverlapIntervalsTy &IOL, MapVector &ThrowableInst) { bool MadeChange = false; @@ -723,7 +721,7 @@ static bool handleFree(CallInst *F, AliasAnalysis *AA, // DCE instructions only used to calculate that store. BasicBlock::iterator BBI(Dependency); - deleteDeadInstruction(Dependency, &BBI, *MD, *TLI, IOL, OBB, + deleteDeadInstruction(Dependency, &BBI, *MD, *TLI, IOL, ThrowableInst); ++NumFastStores; MadeChange = true; @@ -781,7 +779,7 @@ static void removeAccessedObjects(const MemoryLocation &LoadedLoc, static bool handleEndBlock(BasicBlock &BB, AliasAnalysis *AA, MemoryDependenceResults *MD, const TargetLibraryInfo *TLI, - InstOverlapIntervalsTy &IOL, OrderedBasicBlock &OBB, + InstOverlapIntervalsTy &IOL, MapVector &ThrowableInst) { bool MadeChange = false; @@ -843,7 +841,7 @@ static bool handleEndBlock(BasicBlock &BB, AliasAnalysis *AA, << '\n'); // DCE instructions only used to calculate that store. - deleteDeadInstruction(Dead, &BBI, *MD, *TLI, IOL, OBB, ThrowableInst, + deleteDeadInstruction(Dead, &BBI, *MD, *TLI, IOL, ThrowableInst, &DeadStackObjects); ++NumFastStores; MadeChange = true; @@ -855,7 +853,7 @@ static bool handleEndBlock(BasicBlock &BB, AliasAnalysis *AA, if (isInstructionTriviallyDead(&*BBI, TLI)) { LLVM_DEBUG(dbgs() << "DSE: Removing trivially dead instruction:\n DEAD: " << *&*BBI << '\n'); - deleteDeadInstruction(&*BBI, &BBI, *MD, *TLI, IOL, OBB, ThrowableInst, + deleteDeadInstruction(&*BBI, &BBI, *MD, *TLI, IOL, ThrowableInst, &DeadStackObjects); ++NumFastOther; MadeChange = true; @@ -1062,7 +1060,6 @@ static bool eliminateNoopStore(Instruction *Inst, BasicBlock::iterator &BBI, const DataLayout &DL, const TargetLibraryInfo *TLI, InstOverlapIntervalsTy &IOL, - OrderedBasicBlock &OBB, MapVector &ThrowableInst) { // Must be a store instruction. StoreInst *SI = dyn_cast(Inst); @@ -1079,7 +1076,7 @@ static bool eliminateNoopStore(Instruction *Inst, BasicBlock::iterator &BBI, dbgs() << "DSE: Remove Store Of Load from same pointer:\n LOAD: " << *DepLoad << "\n STORE: " << *SI << '\n'); - deleteDeadInstruction(SI, &BBI, *MD, *TLI, IOL, OBB, ThrowableInst); + deleteDeadInstruction(SI, &BBI, *MD, *TLI, IOL, ThrowableInst); ++NumRedundantStores; return true; } @@ -1097,7 +1094,7 @@ static bool eliminateNoopStore(Instruction *Inst, BasicBlock::iterator &BBI, dbgs() << "DSE: Remove null store to the calloc'ed object:\n DEAD: " << *Inst << "\n OBJECT: " << *UnderlyingPointer << '\n'); - deleteDeadInstruction(SI, &BBI, *MD, *TLI, IOL, OBB, ThrowableInst); + deleteDeadInstruction(SI, &BBI, *MD, *TLI, IOL, ThrowableInst); ++NumRedundantStores; return true; } @@ -1111,7 +1108,6 @@ static bool eliminateDeadStores(BasicBlock &BB, AliasAnalysis *AA, const DataLayout &DL = BB.getModule()->getDataLayout(); bool MadeChange = false; - OrderedBasicBlock OBB(&BB); MapVector ThrowableInst; // A map of interval maps representing partially-overwritten value parts. @@ -1121,7 +1117,7 @@ static bool eliminateDeadStores(BasicBlock &BB, AliasAnalysis *AA, for (BasicBlock::iterator BBI = BB.begin(), BBE = BB.end(); BBI != BBE; ) { // Handle 'free' calls specially. if (CallInst *F = isFreeCall(&*BBI, TLI)) { - MadeChange |= handleFree(F, AA, MD, DT, TLI, IOL, OBB, ThrowableInst); + MadeChange |= handleFree(F, AA, MD, DT, TLI, IOL, ThrowableInst); // Increment BBI after handleFree has potentially deleted instructions. // This ensures we maintain a valid iterator. ++BBI; @@ -1140,14 +1136,14 @@ static bool eliminateDeadStores(BasicBlock &BB, AliasAnalysis *AA, continue; // eliminateNoopStore will update in iterator, if necessary. - if (eliminateNoopStore(Inst, BBI, AA, MD, DL, TLI, IOL, OBB, + if (eliminateNoopStore(Inst, BBI, AA, MD, DL, TLI, IOL, ThrowableInst)) { MadeChange = true; continue; } // If we find something that writes memory, get its memory dependence. - MemDepResult InstDep = MD->getDependency(Inst, &OBB); + MemDepResult InstDep = MD->getDependency(Inst); // Ignore any store where we can't find a local dependence. // FIXME: cross-block DSE would be fun. :) @@ -1198,7 +1194,7 @@ static bool eliminateDeadStores(BasicBlock &BB, AliasAnalysis *AA, // If the underlying object is a non-escaping memory allocation, any store // to it is dead along the unwind edge. Otherwise, we need to preserve // the store. - if (LastThrowing && OBB.dominates(DepWrite, LastThrowing)) { + if (LastThrowing && DepWrite->comesBefore(LastThrowing)) { const Value* Underlying = GetUnderlyingObject(DepLoc.Ptr, DL); bool IsStoreDeadOnUnwind = isa(Underlying); if (!IsStoreDeadOnUnwind) { @@ -1229,13 +1225,13 @@ static bool eliminateDeadStores(BasicBlock &BB, AliasAnalysis *AA, << "\n KILLER: " << *Inst << '\n'); // Delete the store and now-dead instructions that feed it. - deleteDeadInstruction(DepWrite, &BBI, *MD, *TLI, IOL, OBB, + deleteDeadInstruction(DepWrite, &BBI, *MD, *TLI, IOL, ThrowableInst); ++NumFastStores; MadeChange = true; // We erased DepWrite; start over. - InstDep = MD->getDependency(Inst, &OBB); + InstDep = MD->getDependency(Inst); continue; } else if ((OR == OW_End && isShortenableAtTheEnd(DepWrite)) || ((OR == OW_Begin && @@ -1308,13 +1304,10 @@ static bool eliminateDeadStores(BasicBlock &BB, AliasAnalysis *AA, SI->copyMetadata(*DepWrite, MDToKeep); ++NumModifiedStores; - // Remove earlier, wider, store - OBB.replaceInstruction(DepWrite, SI); - // Delete the old stores and now-dead instructions that feed them. - deleteDeadInstruction(Inst, &BBI, *MD, *TLI, IOL, OBB, + deleteDeadInstruction(Inst, &BBI, *MD, *TLI, IOL, ThrowableInst); - deleteDeadInstruction(DepWrite, &BBI, *MD, *TLI, IOL, OBB, + deleteDeadInstruction(DepWrite, &BBI, *MD, *TLI, IOL, ThrowableInst); MadeChange = true; @@ -1350,7 +1343,7 @@ static bool eliminateDeadStores(BasicBlock &BB, AliasAnalysis *AA, // If this block ends in a return, unwind, or unreachable, all allocas are // dead at its end, which means stores to them are also dead. if (BB.getTerminator()->getNumSuccessors() == 0) - MadeChange |= handleEndBlock(BB, AA, MD, TLI, IOL, OBB, ThrowableInst); + MadeChange |= handleEndBlock(BB, AA, MD, TLI, IOL, ThrowableInst); return MadeChange; } diff --git a/llvm/lib/Transforms/Scalar/LICM.cpp b/llvm/lib/Transforms/Scalar/LICM.cpp index 8c33045c23802..5c5325a71da6d 100644 --- a/llvm/lib/Transforms/Scalar/LICM.cpp +++ b/llvm/lib/Transforms/Scalar/LICM.cpp @@ -549,6 +549,7 @@ bool llvm::sinkRegion(DomTreeNode *N, AliasAnalysis *AA, LoopInfo *LI, if (sink(I, LI, DT, CurLoop, SafetyInfo, MSSAU, ORE)) { if (!FreeInLoop) { ++II; + salvageDebugInfoOrMarkUndef(I); eraseInstruction(I, *SafetyInfo, CurAST, MSSAU); } Changed = true; @@ -2156,11 +2157,11 @@ bool llvm::promoteLoopAccessesToScalars( }); ++NumPromoted; - // Grab a debug location for the inserted loads/stores; given that the - // inserted loads/stores have little relation to the original loads/stores, - // this code just arbitrarily picks a location from one, since any debug - // location is better than none. - DebugLoc DL = LoopUses[0]->getDebugLoc(); + // Look at all the loop uses, and try to merge their locations. + std::vector LoopUsesLocs; + for (auto U : LoopUses) + LoopUsesLocs.push_back(U->getDebugLoc().get()); + auto DL = DebugLoc(DILocation::getMergedLocations(LoopUsesLocs)); // We use the SSAUpdater interface to insert phi nodes as required. SmallVector NewPHIs; diff --git a/llvm/lib/Transforms/Utils/Debugify.cpp b/llvm/lib/Transforms/Utils/Debugify.cpp index b1274d948e882..57f1740bc21b3 100644 --- a/llvm/lib/Transforms/Utils/Debugify.cpp +++ b/llvm/lib/Transforms/Utils/Debugify.cpp @@ -30,6 +30,17 @@ namespace { cl::opt Quiet("debugify-quiet", cl::desc("Suppress verbose debugify output")); +enum class Level { + Locations, + LocationsAndVariables +}; +cl::opt DebugifyLevel( + "debugify-level", cl::desc("Kind of debug info to add"), + cl::values(clEnumValN(Level::Locations, "locations", "Locations only"), + clEnumValN(Level::LocationsAndVariables, "location+variables", + "Locations and Variables")), + cl::init(Level::LocationsAndVariables)); + raw_ostream &dbg() { return Quiet ? nulls() : errs(); } uint64_t getAllocSizeInBits(Module &M, Type *Ty) { @@ -51,10 +62,11 @@ Instruction *findTerminatingInstruction(BasicBlock &BB) { return I; return BB.getTerminator(); } +} // end anonymous namespace -bool applyDebugifyMetadata(Module &M, - iterator_range Functions, - StringRef Banner) { +bool llvm::applyDebugifyMetadata( + Module &M, iterator_range Functions, StringRef Banner, + std::function ApplyToMF) { // Skip modules with debug info. if (M.getNamedMetadata("llvm.dbg.cu")) { dbg() << Banner << "Skipping module with debug info\n"; @@ -100,6 +112,9 @@ bool applyDebugifyMetadata(Module &M, for (Instruction &I : BB) I.setDebugLoc(DILocation::get(Ctx, NextLine++, 1, SP)); + if (DebugifyLevel < Level::LocationsAndVariables) + continue; + // Inserting debug values into EH pads can break IR invariants. if (BB.isEHPad()) continue; @@ -135,6 +150,8 @@ bool applyDebugifyMetadata(Module &M, InsertBefore); } } + if (ApplyToMF) + ApplyToMF(DIB, F); DIB.finalizeSubprogram(SP); } DIB.finalize(); @@ -159,6 +176,53 @@ bool applyDebugifyMetadata(Module &M, return true; } +bool llvm::stripDebugifyMetadata(Module &M) { + bool Changed = false; + + // Remove the llvm.debugify module-level named metadata. + NamedMDNode *DebugifyMD = M.getNamedMetadata("llvm.debugify"); + if (DebugifyMD) { + M.eraseNamedMetadata(DebugifyMD); + Changed = true; + } + + // Strip out all debug intrinsics and supporting metadata (subprograms, types, + // variables, etc). + Changed |= StripDebugInfo(M); + + // Strip out the dead dbg.value prototype. + Function *DbgValF = M.getFunction("llvm.dbg.value"); + if (DbgValF) { + assert(DbgValF->isDeclaration() && DbgValF->use_empty() && + "Not all debug info stripped?"); + DbgValF->eraseFromParent(); + Changed = true; + } + + // Strip out the module-level Debug Info Version metadata. + // FIXME: There must be an easier way to remove an operand from a NamedMDNode. + NamedMDNode *NMD = M.getModuleFlagsMetadata(); + assert(NMD && "debugify metadata present without Debug Info Version set?"); + SmallVector Flags; + for (MDNode *Flag : NMD->operands()) + Flags.push_back(Flag); + NMD->clearOperands(); + for (MDNode *Flag : Flags) { + MDString *Key = dyn_cast_or_null(Flag->getOperand(1)); + if (Key->getString() == "Debug Info Version") { + Changed = true; + continue; + } + NMD->addOperand(Flag); + } + // If we left it empty we might as well remove it. + if (NMD->getNumOperands() == 0) + NMD->eraseFromParent(); + + return Changed; +} + +namespace { /// Return true if a mis-sized diagnostic is issued for \p DVI. bool diagnoseMisSizedDbgValue(Module &M, DbgValueInst *DVI) { // The size of a dbg.value's value operand should match the size of the @@ -287,12 +351,9 @@ bool checkDebugifyMetadata(Module &M, dbg() << " [" << NameOfWrappedPass << "]"; dbg() << ": " << (HasErrors ? "FAIL" : "PASS") << '\n'; - // Strip the Debugify Metadata if required. - if (Strip) { - StripDebugInfo(M); - M.eraseNamedMetadata(NMD); - return true; - } + // Strip debugify metadata if required. + if (Strip) + return stripDebugifyMetadata(M); return false; } @@ -301,7 +362,8 @@ bool checkDebugifyMetadata(Module &M, /// legacy module pass manager. struct DebugifyModulePass : public ModulePass { bool runOnModule(Module &M) override { - return applyDebugifyMetadata(M, M.functions(), "ModuleDebugify: "); + return applyDebugifyMetadata(M, M.functions(), + "ModuleDebugify: ", /*ApplyToMF*/ nullptr); } DebugifyModulePass() : ModulePass(ID) {} @@ -320,7 +382,7 @@ struct DebugifyFunctionPass : public FunctionPass { Module &M = *F.getParent(); auto FuncIt = F.getIterator(); return applyDebugifyMetadata(M, make_range(FuncIt, std::next(FuncIt)), - "FunctionDebugify: "); + "FunctionDebugify: ", /*ApplyToMF*/ nullptr); } DebugifyFunctionPass() : FunctionPass(ID) {} @@ -395,7 +457,8 @@ FunctionPass *createDebugifyFunctionPass() { } PreservedAnalyses NewPMDebugifyPass::run(Module &M, ModuleAnalysisManager &) { - applyDebugifyMetadata(M, M.functions(), "ModuleDebugify: "); + applyDebugifyMetadata(M, M.functions(), + "ModuleDebugify: ", /*ApplyToMF*/ nullptr); return PreservedAnalyses::all(); } diff --git a/llvm/lib/Transforms/Vectorize/LoadStoreVectorizer.cpp b/llvm/lib/Transforms/Vectorize/LoadStoreVectorizer.cpp index 7478daa2a0a52..4c3df04c7e788 100644 --- a/llvm/lib/Transforms/Vectorize/LoadStoreVectorizer.cpp +++ b/llvm/lib/Transforms/Vectorize/LoadStoreVectorizer.cpp @@ -50,7 +50,6 @@ #include "llvm/ADT/iterator_range.h" #include "llvm/Analysis/AliasAnalysis.h" #include "llvm/Analysis/MemoryLocation.h" -#include "llvm/Analysis/OrderedBasicBlock.h" #include "llvm/Analysis/ScalarEvolution.h" #include "llvm/Analysis/TargetTransformInfo.h" #include "llvm/Analysis/ValueTracking.h" @@ -503,7 +502,6 @@ bool Vectorizer::lookThroughSelects(Value *PtrA, Value *PtrB, } void Vectorizer::reorder(Instruction *I) { - OrderedBasicBlock OBB(I->getParent()); SmallPtrSet InstructionsToMove; SmallVector Worklist; @@ -521,7 +519,7 @@ void Vectorizer::reorder(Instruction *I) { if (IM->getParent() != I->getParent()) continue; - if (!OBB.dominates(IM, I)) { + if (!IM->comesBefore(I)) { InstructionsToMove.insert(IM); Worklist.push_back(IM); } @@ -637,8 +635,6 @@ Vectorizer::getVectorizablePrefix(ArrayRef Chain) { } } - OrderedBasicBlock OBB(Chain[0]->getParent()); - // Loop until we find an instruction in ChainInstrs that we can't vectorize. unsigned ChainInstrIdx = 0; Instruction *BarrierMemoryInstr = nullptr; @@ -648,14 +644,14 @@ Vectorizer::getVectorizablePrefix(ArrayRef Chain) { // If a barrier memory instruction was found, chain instructions that follow // will not be added to the valid prefix. - if (BarrierMemoryInstr && OBB.dominates(BarrierMemoryInstr, ChainInstr)) + if (BarrierMemoryInstr && BarrierMemoryInstr->comesBefore(ChainInstr)) break; // Check (in BB order) if any instruction prevents ChainInstr from being // vectorized. Find and store the first such "conflicting" instruction. for (Instruction *MemInstr : MemoryInstrs) { // If a barrier memory instruction was found, do not check past it. - if (BarrierMemoryInstr && OBB.dominates(BarrierMemoryInstr, MemInstr)) + if (BarrierMemoryInstr && BarrierMemoryInstr->comesBefore(MemInstr)) break; auto *MemLoad = dyn_cast(MemInstr); @@ -674,12 +670,12 @@ Vectorizer::getVectorizablePrefix(ArrayRef Chain) { // vectorize it (the vectorized load is inserted at the location of the // first load in the chain). if (isa(MemInstr) && ChainLoad && - (IsInvariantLoad(ChainLoad) || OBB.dominates(ChainLoad, MemInstr))) + (IsInvariantLoad(ChainLoad) || ChainLoad->comesBefore(MemInstr))) continue; // Same case, but in reverse. if (MemLoad && isa(ChainInstr) && - (IsInvariantLoad(MemLoad) || OBB.dominates(MemLoad, ChainInstr))) + (IsInvariantLoad(MemLoad) || MemLoad->comesBefore(ChainInstr))) continue; if (!AA.isNoAlias(MemoryLocation::get(MemInstr), @@ -705,7 +701,7 @@ Vectorizer::getVectorizablePrefix(ArrayRef Chain) { // the basic block. if (IsLoadChain && BarrierMemoryInstr) { // The BarrierMemoryInstr is a store that precedes ChainInstr. - assert(OBB.dominates(BarrierMemoryInstr, ChainInstr)); + assert(BarrierMemoryInstr->comesBefore(ChainInstr)); break; } } diff --git a/llvm/lib/Transforms/Vectorize/LoopVectorize.cpp b/llvm/lib/Transforms/Vectorize/LoopVectorize.cpp index dba4aa42b3781..e7c79e55e82a2 100644 --- a/llvm/lib/Transforms/Vectorize/LoopVectorize.cpp +++ b/llvm/lib/Transforms/Vectorize/LoopVectorize.cpp @@ -2579,7 +2579,7 @@ Value *InnerLoopVectorizer::getOrCreateTripCount(Loop *L) { // compare. The only way that we get a backedge taken count is that the // induction variable was signed and as such will not overflow. In such a case // truncation is legal. - if (BackedgeTakenCount->getType()->getPrimitiveSizeInBits() > + if (SE->getTypeSizeInBits(BackedgeTakenCount->getType()) > IdxTy->getPrimitiveSizeInBits()) BackedgeTakenCount = SE->getTruncateOrNoop(BackedgeTakenCount, IdxTy); BackedgeTakenCount = SE->getNoopOrZeroExtend(BackedgeTakenCount, IdxTy); diff --git a/llvm/test/CodeGen/AArch64/GlobalISel/gisel-commandline-option.ll b/llvm/test/CodeGen/AArch64/GlobalISel/gisel-commandline-option.ll index f7cc409ea9d73..fba596d4e056c 100644 --- a/llvm/test/CodeGen/AArch64/GlobalISel/gisel-commandline-option.ll +++ b/llvm/test/CodeGen/AArch64/GlobalISel/gisel-commandline-option.ll @@ -1,43 +1,54 @@ ; RUN: llc -mtriple=aarch64-- -debug-pass=Structure %s -o /dev/null 2>&1 \ +; RUN: --debugify-and-strip-all-safe=0 \ ; RUN: -verify-machineinstrs=0 -O0 \ ; RUN: | FileCheck %s --check-prefixes=ENABLED,ENABLED-O0,FALLBACK ; RUN: llc -mtriple=aarch64-- -debug-pass=Structure %s -o /dev/null 2>&1 \ +; RUN: --debugify-and-strip-all-safe=0 \ ; RUN: -verify-machineinstrs -O0 \ ; RUN: | FileCheck %s --check-prefixes=ENABLED,ENABLED-O0,FALLBACK,VERIFY,VERIFY-O0 ; RUN: llc -mtriple=aarch64-- -debug-pass=Structure %s -o /dev/null 2>&1 \ +; RUN: --debugify-and-strip-all-safe=0 \ ; RUN: -verify-machineinstrs=0 -O0 -aarch64-enable-global-isel-at-O=0 -global-isel-abort=1 \ ; RUN: | FileCheck %s --check-prefix ENABLED --check-prefix ENABLED-O0 --check-prefix NOFALLBACK ; RUN: llc -mtriple=aarch64-- -debug-pass=Structure %s -o /dev/null 2>&1 \ +; RUN: --debugify-and-strip-all-safe=0 \ ; RUN: -verify-machineinstrs=0 -O0 -aarch64-enable-global-isel-at-O=0 -global-isel-abort=2 \ ; RUN: | FileCheck %s --check-prefix ENABLED --check-prefix ENABLED-O0 --check-prefix FALLBACK ; RUN: llc -mtriple=aarch64-- -debug-pass=Structure %s -o /dev/null 2>&1 \ +; RUN: --debugify-and-strip-all-safe=0 \ ; RUN: -verify-machineinstrs=0 -global-isel \ ; RUN: | FileCheck %s --check-prefix ENABLED --check-prefix NOFALLBACK --check-prefix ENABLED-O1 ; RUN: llc -mtriple=aarch64-- -debug-pass=Structure %s -o /dev/null 2>&1 \ +; RUN: --debugify-and-strip-all-safe=0 \ ; RUN: -verify-machineinstrs=0 -global-isel -global-isel-abort=2 \ ; RUN: | FileCheck %s --check-prefix ENABLED --check-prefix FALLBACK --check-prefix ENABLED-O1 ; RUN: llc -mtriple=aarch64-- -debug-pass=Structure %s -o /dev/null 2>&1 \ +; RUN: --debugify-and-strip-all-safe=0 \ ; RUN: -verify-machineinstrs=0 -O1 -aarch64-enable-global-isel-at-O=3 \ ; RUN: | FileCheck %s --check-prefix ENABLED --check-prefix ENABLED-O1 ; RUN: llc -mtriple=aarch64-- -debug-pass=Structure %s -o /dev/null 2>&1 \ +; RUN: --debugify-and-strip-all-safe=0 \ ; RUN: -verify-machineinstrs=0 -O1 -aarch64-enable-global-isel-at-O=0 \ ; RUN: | FileCheck %s --check-prefix DISABLED ; RUN: llc -mtriple=aarch64-- -debug-pass=Structure %s -o /dev/null 2>&1 \ +; RUN: --debugify-and-strip-all-safe=0 \ ; RUN: -verify-machineinstrs=0 -aarch64-enable-global-isel-at-O=-1 \ ; RUN: | FileCheck %s --check-prefix DISABLED ; RUN: llc -mtriple=aarch64-- -debug-pass=Structure %s -o /dev/null 2>&1 \ +; RUN: --debugify-and-strip-all-safe=0 \ ; RUN: -verify-machineinstrs=0 | FileCheck %s --check-prefix DISABLED ; RUN: llc -mtriple=aarch64-- -fast-isel=0 -global-isel=false \ +; RUN: --debugify-and-strip-all-safe=0 \ ; RUN: -debug-pass=Structure %s -o /dev/null 2>&1 -verify-machineinstrs=0 \ ; RUN: | FileCheck %s --check-prefix DISABLED diff --git a/llvm/test/CodeGen/AArch64/GlobalISel/prelegalizercombiner-extending-loads-cornercases.mir b/llvm/test/CodeGen/AArch64/GlobalISel/prelegalizercombiner-extending-loads-cornercases.mir index 9128cb88c6b6e..63e80af680d6d 100644 --- a/llvm/test/CodeGen/AArch64/GlobalISel/prelegalizercombiner-extending-loads-cornercases.mir +++ b/llvm/test/CodeGen/AArch64/GlobalISel/prelegalizercombiner-extending-loads-cornercases.mir @@ -112,15 +112,15 @@ body: | # a test of the debug output and a test. # # CHECK-WORKLIST-LABEL: Generic MI Combiner for: multiple_copies -# CHECK-WORKLIST: Try combining [[IN0:%[0-9]+]]:_(s8) = G_LOAD [[IN1:%[0-9]+]]:_(p0) :: (load 1 from %ir.addr) +# CHECK-WORKLIST: Try combining [[IN0:%[0-9]+]]:_(s8) = G_LOAD [[IN1:%[0-9]+]]:_(p0){{.*}} :: (load 1 from %ir.addr) # CHECK-WORKLIST: Preferred use is: [[IN2:%[0-9]+]]:_(s32) = G_SEXT [[IN0]]:_(s8) -# CHECK-WORKLIST-DAG: Changing: [[IN0]]:_(s8) = G_LOAD [[IN1]]:_(p0) :: (load 1 from %ir.addr) +# CHECK-WORKLIST-DAG: Changing: [[IN0]]:_(s8) = G_LOAD [[IN1]]:_(p0){{.*}} :: (load 1 from %ir.addr) # CHECK-WORKLIST-DAG: Changing: [[IN3:%[0-9]+]]:_(s8) = G_ADD [[IN0]]:_, [[IN4:%[0-9]+]]:_ # CHECK-WORKLIST-DAG: Changed: [[IN3]]:_(s8) = G_ADD [[NEW1:%[0-9]+]]:_, [[IN4]]:_ # CHECK-WORKLIST-DAG: Changing: [[IN5:%[0-9]+]]:_(s8) = G_SUB [[IN0]]:_, [[IN6:%[0-9]+]]:_ # CHECK-WORKLIST-DAG: Changed: [[IN5]]:_(s8) = G_SUB [[NEW2:%[0-9]+]]:_, [[IN6]]:_ # CHECK-WORKLIST-DAG: Erasing: [[IN2]]:_(s32) = G_SEXT [[IN0]]:_(s8) -# CHECK-WORKLIST-DAG: Changed: [[IN2]]:_(s32) = G_SEXTLOAD [[IN1]]:_(p0) :: (load 1 from %ir.addr) +# CHECK-WORKLIST-DAG: Changed: [[IN2]]:_(s32) = G_SEXTLOAD [[IN1]]:_(p0){{.*}} :: (load 1 from %ir.addr) # CHECK-WORKLIST-DAG: Created: [[NEW1]]:_(s8) = G_TRUNC [[IN2]]:_(s32) # CHECK-WORKLIST-DAG: Created: [[NEW2]]:_(s8) = G_TRUNC [[IN2]]:_(s32) # CHECK-WORKLIST: Try combining @@ -211,9 +211,9 @@ body: | $w0 = COPY %10 $w1 = COPY %11 # CHECK-WORKLIST-LABEL: Generic MI Combiner for: sink_to_phi_nondominating -# CHECK-WORKLIST: Try combining [[IN0:%[0-9]+]]:_(s8) = G_LOAD [[IN1:%[0-9]+]]:_(p0) :: (load 1 from %ir.addr) +# CHECK-WORKLIST: Try combining [[IN0:%[0-9]+]]:_(s8) = G_LOAD [[IN1:%[0-9]+]]:_(p0){{.*}} :: (load 1 from %ir.addr) # CHECK-WORKLIST: Preferred use is: [[IN2:%[0-9]+]]:_(s32) = G_SEXT [[IN0]]:_(s8) -# CHECK-WORKLIST-DAG: Changing: [[IN0]]:_(s8) = G_LOAD [[IN1]]:_(p0) :: (load 1 from %ir.addr) +# CHECK-WORKLIST-DAG: Changing: [[IN0]]:_(s8) = G_LOAD [[IN1]]:_(p0){{.*}} :: (load 1 from %ir.addr) # CHECK-WORKLIST-DAG: Creating: G_TRUNC # CHECK-WORKLIST-DAG: Changing: [[IN3:%[0-9]+]]:_(s8) = G_ADD [[IN0]]:_, [[IN4:%[0-9]+]]:_ # CHECK-WORKLIST-DAG: Changed: [[IN3]]:_(s8) = G_ADD [[OUT1:%[0-9]+]]:_, [[IN4]]:_ @@ -221,7 +221,7 @@ body: | # CHECK-WORKLIST-DAG: Changing: [[IN5:%[0-9]+]]:_(s8) = G_SUB [[IN0]]:_, [[IN6:%[0-9]+]]:_ # CHECK-WORKLIST-DAG: Changed: [[IN5]]:_(s8) = G_SUB [[OUT2:%[0-9]+]]:_, [[IN6]]:_ # CHECK-WORKLIST-DAG: Erasing: [[IN2]]:_(s32) = G_SEXT [[IN0]]:_(s8) -# CHECK-WORKLIST-DAG: Changed: [[IN2]]:_(s32) = G_SEXTLOAD [[IN1]]:_(p0) :: (load 1 from %ir.addr) +# CHECK-WORKLIST-DAG: Changed: [[IN2]]:_(s32) = G_SEXTLOAD [[IN1]]:_(p0){{.*}} :: (load 1 from %ir.addr) # CHECK-WORKLIST-DAG: Created: [[OUT1]]:_(s8) = G_TRUNC [[IN2]]:_(s32) # CHECK-WORKLIST-DAG: Created: [[OUT2]]:_(s8) = G_TRUNC [[IN2]]:_(s32) # CHECK-WORKLIST: Try combining diff --git a/llvm/test/CodeGen/AArch64/O0-pipeline.ll b/llvm/test/CodeGen/AArch64/O0-pipeline.ll index 489cc4316891d..383723389a2fb 100644 --- a/llvm/test/CodeGen/AArch64/O0-pipeline.ll +++ b/llvm/test/CodeGen/AArch64/O0-pipeline.ll @@ -1,4 +1,5 @@ -; RUN: llc -mtriple=arm64-- -O0 -debug-pass=Structure < %s -o /dev/null 2>&1 | grep -v "Verify generated machine code" | FileCheck %s +; RUN: llc --debugify-and-strip-all-safe=0 -mtriple=arm64-- -O0 -debug-pass=Structure < %s -o /dev/null 2>&1 | \ +; RUN: grep -v "Verify generated machine code" | FileCheck %s ; REQUIRES: asserts diff --git a/llvm/test/CodeGen/AArch64/O3-pipeline.ll b/llvm/test/CodeGen/AArch64/O3-pipeline.ll index 9aa5cb54bedf6..85e08cfd3e3d2 100644 --- a/llvm/test/CodeGen/AArch64/O3-pipeline.ll +++ b/llvm/test/CodeGen/AArch64/O3-pipeline.ll @@ -1,4 +1,5 @@ -; RUN: llc -mtriple=arm64-- -O3 -debug-pass=Structure < %s -o /dev/null 2>&1 | grep -v "Verify generated machine code" | FileCheck %s +; RUN: llc --debugify-and-strip-all-safe=0 -mtriple=arm64-- -O3 -debug-pass=Structure < %s -o /dev/null 2>&1 | \ +; RUN: grep -v "Verify generated machine code" | FileCheck %s ; REQUIRES: asserts diff --git a/llvm/test/CodeGen/AArch64/arm64-opt-remarks-lazy-bfi.ll b/llvm/test/CodeGen/AArch64/arm64-opt-remarks-lazy-bfi.ll index 79cf990084336..e12fb7478d647 100644 --- a/llvm/test/CodeGen/AArch64/arm64-opt-remarks-lazy-bfi.ll +++ b/llvm/test/CodeGen/AArch64/arm64-opt-remarks-lazy-bfi.ll @@ -1,10 +1,12 @@ ; RUN: llc < %s -mtriple=arm64-apple-ios7.0 -pass-remarks-analysis=asm-printer \ +; RUN: --debugify-and-strip-all-safe=0 \ ; RUN: -verify-machineinstrs \ ; RUN: -pass-remarks-with-hotness=1 -asm-verbose=0 \ ; RUN: -debug-only=lazy-machine-block-freq,block-freq \ ; RUN: -debug-pass=Executions 2>&1 | FileCheck %s -check-prefix=HOTNESS ; RUN: llc < %s -mtriple=arm64-apple-ios7.0 -pass-remarks-analysis=asm-printer \ +; RUN: --debugify-and-strip-all-safe=0 \ ; RUN: -verify-machineinstrs \ ; RUN: -pass-remarks-with-hotness=0 -asm-verbose=0 \ ; RUN: -debug-only=lazy-machine-block-freq,block-freq \ diff --git a/llvm/test/CodeGen/AArch64/fastisel-debugvalue-undef.ll b/llvm/test/CodeGen/AArch64/fastisel-debugvalue-undef.ll index 86aa7d15edbba..aceb85f4dd7f0 100644 --- a/llvm/test/CodeGen/AArch64/fastisel-debugvalue-undef.ll +++ b/llvm/test/CodeGen/AArch64/fastisel-debugvalue-undef.ll @@ -12,14 +12,11 @@ define void @foo() !dbg !6 { declare void @llvm.dbg.value(metadata, metadata, metadata) !llvm.dbg.cu = !{!0} -!llvm.debugify = !{!3, !4} !llvm.module.flags = !{!5} !0 = distinct !DICompileUnit(language: DW_LANG_C, file: !1, producer: "debugify", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, enums: !2) !1 = !DIFile(filename: "t.ll", directory: "/") !2 = !{} -!3 = !{i32 2} -!4 = !{i32 1} !5 = !{i32 2, !"Debug Info Version", i32 3} !6 = distinct !DISubprogram(name: "foo", linkageName: "foo", scope: null, file: !1, line: 1, type: !7, scopeLine: 1, spFlags: DISPFlagDefinition | DISPFlagOptimized, unit: !0, retainedNodes: !8) !7 = !DISubroutineType(types: !2) diff --git a/llvm/test/CodeGen/AArch64/prologue-epilogue-remarks.mir b/llvm/test/CodeGen/AArch64/prologue-epilogue-remarks.mir index ed139875d26ac..4bc1b968d1708 100644 --- a/llvm/test/CodeGen/AArch64/prologue-epilogue-remarks.mir +++ b/llvm/test/CodeGen/AArch64/prologue-epilogue-remarks.mir @@ -5,10 +5,10 @@ name: fun0 stack: - { id: 0, type: default, offset: 0, size: 8, alignment: 4 } -# CHECK: --- !Analysis +# CHECK-LABEL: --- !Analysis # CHECK-NEXT: Pass: prologepilog # CHECK-NEXT: Name: StackSize -# CHECK-NEXT: Function: fun0 +# CHECK: Function: fun0 # CHECK-NEXT: Args: # CHECK-NEXT: - NumStackBytes: '16' # CHECK-NEXT: - String: ' stack bytes in function' @@ -23,10 +23,10 @@ body: | name: fun1 stack: - { id: 0, type: default, offset: 0, size: 19, alignment: 4 } -# CHECK: --- !Analysis +# CHECK-LABEL: --- !Analysis # CHECK-NEXT: Pass: prologepilog # CHECK-NEXT: Name: StackSize -# CHECK-NEXT: Function: fun1 +# CHECK: Function: fun1 # CHECK-NEXT: Args: # CHECK-NEXT: - NumStackBytes: '32' # CHECK-NEXT: - String: ' stack bytes in function' @@ -41,10 +41,10 @@ body: | name: fun2 stack: - { id: 0, type: default, offset: 0, size: 1024, alignment: 4 } -# --- !Analysis +# CHECK-LABEL: --- !Analysis # CHECK: Pass: prologepilog # CHECK-NEXT: Name: StackSize -# CHECK-NEXT: Function: fun2 +# CHECK: Function: fun2 # CHECK-NEXT: Args: # CHECK-NEXT: - NumStackBytes: '1040' # CHECK-NEXT: - String: ' stack bytes in function' diff --git a/llvm/test/CodeGen/AArch64/seqpairspill.mir b/llvm/test/CodeGen/AArch64/seqpairspill.mir index 225e10ecfdb5a..fdcb3dc611817 100644 --- a/llvm/test/CodeGen/AArch64/seqpairspill.mir +++ b/llvm/test/CodeGen/AArch64/seqpairspill.mir @@ -1,4 +1,4 @@ -# RUN: llc -o - %s -mtriple=aarch64-- -mattr=+v8.1a -run-pass=greedy,virtregrewriter | FileCheck %s +# RUN: llc --debugify-and-strip-all-safe=0 -o - %s -mtriple=aarch64-- -mattr=+v8.1a -run-pass=greedy,virtregrewriter | FileCheck %s # Make sure spills/reloads from xseqpairs and wseqpairs work correctly. --- # CHECK-LABEL: name: spill_reload_xseqpairs diff --git a/llvm/test/CodeGen/AArch64/stp-opt-with-renaming-debug.mir b/llvm/test/CodeGen/AArch64/stp-opt-with-renaming-debug.mir index 17a9c47a588a2..e89c778c53669 100644 --- a/llvm/test/CodeGen/AArch64/stp-opt-with-renaming-debug.mir +++ b/llvm/test/CodeGen/AArch64/stp-opt-with-renaming-debug.mir @@ -11,6 +11,9 @@ !7 = !DILocalVariable(name: "x", arg: 1, scope: !5, file: !1, line: 1, type: !8) !8 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed) !9 = !DILocation(line: 1, column: 1, scope: !5) + !10 = !{i32 2, !"Debug Info Version", i32 3} + !llvm.dbg.cu = !{!0} + !llvm.module.flags = !{!10} --- # Check we do not crash when checking $noreg debug operands. # diff --git a/llvm/test/CodeGen/Generic/MIRDebugify/locations.mir b/llvm/test/CodeGen/Generic/MIRDebugify/locations.mir new file mode 100644 index 0000000000000..cd51432ad96bf --- /dev/null +++ b/llvm/test/CodeGen/Generic/MIRDebugify/locations.mir @@ -0,0 +1,44 @@ +# RUN: llc -run-pass=mir-debugify -o - %s | FileCheck --check-prefixes=ALL,VALUE %s +# RUN: llc -run-pass=mir-debugify -debugify-level=locations -o - %s | FileCheck --check-prefixes=ALL --implicit-check-not=dbg.value %s +# RUN: llc -run-pass=mir-debugify,mir-strip-debug,mir-debugify -o - %s | FileCheck --check-prefixes=ALL,VALUE %s +--- | + ; ModuleID = 'loc-only.ll' + source_filename = "loc-only.ll" + + ; ALL-LABEL: @test + define i32 @test(i32 %a, i32 %b) { + %add = add i32 %a, 2 + ; ALL-NEXT: %add = add i32 %a, 2, !dbg [[L1:![0-9]+]] + ; VALUE-NEXT: call void @llvm.dbg.value(metadata i32 %add, metadata [[add:![0-9]+]], metadata !DIExpression()), !dbg [[L1]] + %sub = sub i32 %add, %b + ; ALL-NEXT: %sub = sub i32 %add, %b, !dbg [[L2:![0-9]+]] + ; VALUE-NEXT: call void @llvm.dbg.value(metadata i32 %sub, metadata [[sub:![0-9]+]], metadata !DIExpression()), !dbg [[L2]] + ; ALL-NEXT: ret i32 %sub, !dbg [[L3:![0-9]+]] + ret i32 %sub + } + + ; CHECK: !llvm.dbg.cu = !{!0} + ; CHECK: !llvm.debugify = + ; CHECK: !llvm.module.flags = !{![[VERSION:[0-9]+]]} + ; CHECK: !0 = distinct !DICompileUnit( + ; CHECK: ![[VERSION]] = !{i32 2, !"Debug Info Version", i32 3} + +... +--- +name: test +body: | + bb.1 (%ir-block.0): + %0:_(s32) = IMPLICIT_DEF + %1:_(s32) = IMPLICIT_DEF + %2:_(s32) = G_CONSTANT i32 2 + %3:_(s32) = G_ADD %0, %2 + %4:_(s32) = G_SUB %3, %1 + ; There's no attempt to have the locations make sense as it's an imaginary + ; source file anyway. These first three coincide with IR-level information + ; and therefore use metadata references. + ; ALL: %0:_(s32) = IMPLICIT_DEF debug-location [[L1]] + ; ALL: %1:_(s32) = IMPLICIT_DEF debug-location [[L2]] + ; ALL: %2:_(s32) = G_CONSTANT i32 2, debug-location [[L3]] + ; ALL: %3:_(s32) = G_ADD %0, %2, debug-location !DILocation(line: 4, column: 1, scope: !6) + ; ALL: %4:_(s32) = G_SUB %3, %1, debug-location !DILocation(line: 5, column: 1, scope: !6) +... diff --git a/llvm/test/CodeGen/Generic/MIRStripDebug/all.mir b/llvm/test/CodeGen/Generic/MIRStripDebug/all.mir new file mode 100644 index 0000000000000..7eaf609537956 --- /dev/null +++ b/llvm/test/CodeGen/Generic/MIRStripDebug/all.mir @@ -0,0 +1,73 @@ +# RUN: llc -run-pass=mir-strip-debug -o - %s | FileCheck %s +# RUN: llc -run-pass=mir-strip-debug,mir-debugify,mir-strip-debug -o - %s | FileCheck %s +--- | + ; ModuleID = 'loc-only.ll' + source_filename = "loc-only.ll" + + define i32 @test(i32 %a, i32 %b) !dbg !6 { + %add = add i32 %a, 2, !dbg !12 + call void @llvm.dbg.value(metadata i32 %add, metadata !9, metadata !DIExpression()), !dbg !12 + %sub = sub i32 %add, %b, !dbg !13 + call void @llvm.dbg.value(metadata i32 %sub, metadata !11, metadata !DIExpression()), !dbg !13 + ret i32 %sub, !dbg !14 + } + ; CHECK-LABEL: define i32 @test(i32 %a, i32 %b) { + ; CHECK-NEXT: %add = add i32 %a, 2 + ; CHECK-NEXT: %sub = sub i32 %add, %b + ; CHECK-NEXT: ret i32 %sub + ; CHECK-NEXT: } + + ; Function Attrs: nounwind readnone speculatable willreturn + declare void @llvm.dbg.value(metadata, metadata, metadata) #0 + + ; Function Attrs: nounwind + declare void @llvm.stackprotector(i8*, i8**) #1 + + attributes #0 = { nounwind readnone speculatable willreturn } + attributes #1 = { nounwind } + + !llvm.dbg.cu = !{!0} + ; CHECK-NOT: !llvm.dbg.cu + !llvm.debugify = !{!3, !4} + ; CHECK-NOT: !llvm.debugify + !llvm.module.flags = !{!5} + ; CHECK-NOT: !llvm.module.flags + + ; CHECK-NOT: !DI + !0 = distinct !DICompileUnit(language: DW_LANG_C, file: !1, producer: "debugify", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, enums: !2) + !1 = !DIFile(filename: "", directory: "/") + !2 = !{} + !3 = !{i32 3} + !4 = !{i32 2} + !5 = !{i32 2, !"Debug Info Version", i32 3} + !6 = distinct !DISubprogram(name: "test", linkageName: "test", scope: null, file: !1, line: 1, type: !7, scopeLine: 1, spFlags: DISPFlagDefinition | DISPFlagOptimized, unit: !0, retainedNodes: !8) + !7 = !DISubroutineType(types: !2) + !8 = !{!9, !11} + !9 = !DILocalVariable(name: "1", scope: !6, file: !1, line: 1, type: !10) + !10 = !DIBasicType(name: "ty32", size: 32, encoding: DW_ATE_unsigned) + !11 = !DILocalVariable(name: "2", scope: !6, file: !1, line: 2, type: !10) + !12 = !DILocation(line: 1, column: 1, scope: !6) + !13 = !DILocation(line: 2, column: 1, scope: !6) + !14 = !DILocation(line: 3, column: 1, scope: !6) + +... +--- +name: test +body: | + bb.1 (%ir-block.0): + %0:_(s32) = G_IMPLICIT_DEF + %1:_(s32) = G_IMPLICIT_DEF + %2:_(s32) = G_CONSTANT i32 2, debug-location !DILocation(line: 0, scope: !6) + %3:_(s32) = G_ADD %0, %2, debug-location !12 + DBG_VALUE %3(s32), $noreg, !9, !DIExpression(), debug-location !12 + %4:_(s32) = G_SUB %3, %1, debug-location !13 + DBG_VALUE %4(s32), $noreg, !11, !DIExpression(), debug-location !13 + + ; CHECK-LABEL: body: + ; CHECK-NEXT: bb + ; CHECK-NEXT: %0:_(s32) = G_IMPLICIT_DEF{{$}} + ; CHECK-NEXT: %1:_(s32) = G_IMPLICIT_DEF{{$}} + ; CHECK-NEXT: %2:_(s32) = G_CONSTANT i32 2{{$}} + ; CHECK-NEXT: %3:_(s32) = G_ADD %0, %2{{$}} + ; CHECK-NEXT: %4:_(s32) = G_SUB %3, %1{{$}} +... diff --git a/llvm/test/CodeGen/Generic/MIRStripDebug/dont-strip-real-debug-info.mir b/llvm/test/CodeGen/Generic/MIRStripDebug/dont-strip-real-debug-info.mir new file mode 100644 index 0000000000000..860cb9731ae80 --- /dev/null +++ b/llvm/test/CodeGen/Generic/MIRStripDebug/dont-strip-real-debug-info.mir @@ -0,0 +1,86 @@ +# RUN: llc -run-pass=mir-strip-debug -o - %s | FileCheck %s +# RUN: llc -run-pass=mir-strip-debug,mir-debugify,mir-strip-debug -o - %s | FileCheck %s +--- | + ; ModuleID = 'loc-only.ll' + source_filename = "loc-only.ll" + + define i32 @test(i32 %a, i32 %b) !dbg !4 { + %add = add i32 %a, 2, !dbg !10 + call void @llvm.dbg.value(metadata i32 %add, metadata !7, metadata !DIExpression()), !dbg !10 + %sub = sub i32 %add, %b, !dbg !11 + call void @llvm.dbg.value(metadata i32 %sub, metadata !9, metadata !DIExpression()), !dbg !11 + ret i32 %sub, !dbg !12 + } + ; CHECK-LABEL: define i32 @test(i32 %a, i32 %b) !dbg !4 { + ; CHECK-NEXT: %add = add i32 %a, 2, !dbg !10 + ; CHECK-NEXT: call void @llvm.dbg.value(metadata i32 %add, metadata !7, metadata !DIExpression()), !dbg !10 + ; CHECK-NEXT: %sub = sub i32 %add, %b, !dbg !11 + ; CHECK-NEXT: call void @llvm.dbg.value(metadata i32 %sub, metadata !9, metadata !DIExpression()), !dbg !11 + ; CHECK-NEXT: ret i32 %sub, !dbg !12 + ; CHECK-NEXT: } + + ; Function Attrs: nounwind readnone speculatable willreturn + declare void @llvm.dbg.value(metadata, metadata, metadata) #0 + + ; Function Attrs: nounwind + declare void @llvm.stackprotector(i8*, i8**) #1 + + attributes #0 = { nounwind readnone speculatable willreturn } + attributes #1 = { nounwind } + + !llvm.dbg.cu = !{!0} + ; CHECK: !llvm.dbg.cu = !{!0} + !llvm.module.flags = !{!3} + ; CHECK: !llvm.module.flags = !{!3} + + !0 = distinct !DICompileUnit(language: DW_LANG_C, file: !1, producer: "debugify", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, enums: !2) + !1 = !DIFile(filename: "", directory: "/") + !2 = !{} + !3 = !{i32 2, !"Debug Info Version", i32 3} + !4 = distinct !DISubprogram(name: "test", linkageName: "test", scope: null, file: !1, line: 1, type: !5, scopeLine: 1, spFlags: DISPFlagDefinition | DISPFlagOptimized, unit: !0, retainedNodes: !6) + !5 = !DISubroutineType(types: !2) + !6 = !{!7, !9} + !7 = !DILocalVariable(name: "1", scope: !4, file: !1, line: 1, type: !8) + !8 = !DIBasicType(name: "ty32", size: 32, encoding: DW_ATE_unsigned) + !9 = !DILocalVariable(name: "2", scope: !4, file: !1, line: 2, type: !8) + !10 = !DILocation(line: 1, column: 1, scope: !4) + !11 = !DILocation(line: 2, column: 1, scope: !4) + !12 = !DILocation(line: 3, column: 1, scope: !4) + + ; CHECK: !0 = distinct !DICompileUnit(language: DW_LANG_C, file: !1, producer: "debugify", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, enums: !2) + ; CHECK: !1 = !DIFile(filename: "", directory: "/") + ; CHECK: !2 = !{} + ; CHECK: !3 = !{i32 2, !"Debug Info Version", i32 3} + ; CHECK: !4 = distinct !DISubprogram(name: "test", linkageName: "test", scope: null, file: !1, line: 1, type: !5, scopeLine: 1, spFlags: DISPFlagDefinition | DISPFlagOptimized, unit: !0, retainedNodes: !6) + ; CHECK: !5 = !DISubroutineType(types: !2) + ; CHECK: !6 = !{!7, !9} + ; CHECK: !7 = !DILocalVariable(name: "1", scope: !4, file: !1, line: 1, type: !8) + ; CHECK: !8 = !DIBasicType(name: "ty32", size: 32, encoding: DW_ATE_unsigned) + ; CHECK: !9 = !DILocalVariable(name: "2", scope: !4, file: !1, line: 2, type: !8) + ; CHECK: !10 = !DILocation(line: 1, column: 1, scope: !4) + ; CHECK: !11 = !DILocation(line: 2, column: 1, scope: !4) + ; CHECK: !12 = !DILocation(line: 3, column: 1, scope: !4) + +... +--- +name: test +body: | + bb.1 (%ir-block.0): + %0:_(s32) = G_IMPLICIT_DEF + %1:_(s32) = G_IMPLICIT_DEF + %2:_(s32) = G_CONSTANT i32 2, debug-location !DILocation(line: 0, scope: !4) + %3:_(s32) = G_ADD %0, %2, debug-location !10 + DBG_VALUE %3(s32), $noreg, !7, !DIExpression(), debug-location !10 + %4:_(s32) = G_SUB %3, %1, debug-location !11 + DBG_VALUE %4(s32), $noreg, !9, !DIExpression(), debug-location !11 + + ; CHECK-LABEL: body: + ; CHECK-NEXT: bb + ; CHECK-NEXT: %0:_(s32) = G_IMPLICIT_DEF{{$}} + ; CHECK-NEXT: %1:_(s32) = G_IMPLICIT_DEF{{$}} + ; CHECK-NEXT: %2:_(s32) = G_CONSTANT i32 2, debug-location !DILocation(line: 0, scope: !4) + ; CHECK-NEXT: %3:_(s32) = G_ADD %0, %2, debug-location !10 + ; CHECK-NEXT: DBG_VALUE %3(s32), $noreg, !7, !DIExpression(), debug-location !10 + ; CHECK-NEXT: %4:_(s32) = G_SUB %3, %1, debug-location !11 + ; CHECK-NEXT: DBG_VALUE %4(s32), $noreg, !9, !DIExpression(), debug-location !11 +... diff --git a/llvm/test/CodeGen/Generic/MIRStripDebug/multiple-moduleflags.mir b/llvm/test/CodeGen/Generic/MIRStripDebug/multiple-moduleflags.mir new file mode 100644 index 0000000000000..2a62cd4bb8770 --- /dev/null +++ b/llvm/test/CodeGen/Generic/MIRStripDebug/multiple-moduleflags.mir @@ -0,0 +1,75 @@ +# RUN: llc -run-pass=mir-strip-debug -o - %s | FileCheck %s +# RUN: llc -run-pass=mir-strip-debug,mir-debugify,mir-strip-debug -o - %s | FileCheck %s +--- | + ; ModuleID = 'loc-only.ll' + source_filename = "loc-only.ll" + + define i32 @test(i32 %a, i32 %b) !dbg !6 { + %add = add i32 %a, 2, !dbg !12 + call void @llvm.dbg.value(metadata i32 %add, metadata !9, metadata !DIExpression()), !dbg !12 + %sub = sub i32 %add, %b, !dbg !13 + call void @llvm.dbg.value(metadata i32 %sub, metadata !11, metadata !DIExpression()), !dbg !13 + ret i32 %sub, !dbg !14 + } + ; CHECK-LABEL: define i32 @test(i32 %a, i32 %b) { + ; CHECK-NEXT: %add = add i32 %a, 2 + ; CHECK-NEXT: %sub = sub i32 %add, %b + ; CHECK-NEXT: ret i32 %sub + ; CHECK-NEXT: } + + ; Function Attrs: nounwind readnone speculatable willreturn + declare void @llvm.dbg.value(metadata, metadata, metadata) #0 + + ; Function Attrs: nounwind + declare void @llvm.stackprotector(i8*, i8**) #1 + + attributes #0 = { nounwind readnone speculatable willreturn } + attributes #1 = { nounwind } + + !llvm.dbg.cu = !{!0} + ; CHECK-NOT: !llvm.dbg.cu + !llvm.debugify = !{!3, !4} + ; CHECK-NOT: !llvm.debugify + !llvm.module.flags = !{!5, !15} + ; CHECK: !llvm.module.flags = !{!0} + ; CHECK: !0 = !{i32 2, !"Another Flag", i32 3} + + ; CHECK-NOT: !DI + !0 = distinct !DICompileUnit(language: DW_LANG_C, file: !1, producer: "debugify", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, enums: !2) + !1 = !DIFile(filename: "", directory: "/") + !2 = !{} + !3 = !{i32 3} + !4 = !{i32 2} + !5 = !{i32 2, !"Debug Info Version", i32 3} + !6 = distinct !DISubprogram(name: "test", linkageName: "test", scope: null, file: !1, line: 1, type: !7, scopeLine: 1, spFlags: DISPFlagDefinition | DISPFlagOptimized, unit: !0, retainedNodes: !8) + !7 = !DISubroutineType(types: !2) + !8 = !{!9, !11} + !9 = !DILocalVariable(name: "1", scope: !6, file: !1, line: 1, type: !10) + !10 = !DIBasicType(name: "ty32", size: 32, encoding: DW_ATE_unsigned) + !11 = !DILocalVariable(name: "2", scope: !6, file: !1, line: 2, type: !10) + !12 = !DILocation(line: 1, column: 1, scope: !6) + !13 = !DILocation(line: 2, column: 1, scope: !6) + !14 = !DILocation(line: 3, column: 1, scope: !6) + !15 = !{i32 2, !"Another Flag", i32 3} + +... +--- +name: test +body: | + bb.1 (%ir-block.0): + %0:_(s32) = G_IMPLICIT_DEF + %1:_(s32) = G_IMPLICIT_DEF + %2:_(s32) = G_CONSTANT i32 2, debug-location !DILocation(line: 0, scope: !6) + %3:_(s32) = G_ADD %0, %2, debug-location !12 + DBG_VALUE %3(s32), $noreg, !9, !DIExpression(), debug-location !12 + %4:_(s32) = G_SUB %3, %1, debug-location !13 + DBG_VALUE %4(s32), $noreg, !11, !DIExpression(), debug-location !13 + + ; CHECK-LABEL: body: + ; CHECK-NEXT: bb + ; CHECK-NEXT: %0:_(s32) = G_IMPLICIT_DEF{{$}} + ; CHECK-NEXT: %1:_(s32) = G_IMPLICIT_DEF{{$}} + ; CHECK-NEXT: %2:_(s32) = G_CONSTANT i32 2{{$}} + ; CHECK-NEXT: %3:_(s32) = G_ADD %0, %2{{$}} + ; CHECK-NEXT: %4:_(s32) = G_SUB %3, %1{{$}} +... diff --git a/llvm/test/CodeGen/X86/taildup-callsiteinfo.mir b/llvm/test/CodeGen/X86/taildup-callsiteinfo.mir new file mode 100644 index 0000000000000..cecc58a419c4e --- /dev/null +++ b/llvm/test/CodeGen/X86/taildup-callsiteinfo.mir @@ -0,0 +1,75 @@ +# RUN: llc %s -run-pass=block-placement -tail-dup-placement-threshold=4 -o - | FileCheck %s +# +# Test case adapted from test/CodeGen/X86/taildup-heapallocsite.ll. + +# CHECK-LABEL: callSites: +# CHECK-NEXT: - { bb: 1, offset: 1, fwdArgRegs: +# CHECK-NEXT: - { arg: 0, reg: '$rcx' } } +# CHECK-NEXT: - { bb: 2, offset: 1, fwdArgRegs: +# CHECK-NEXT: - { arg: 0, reg: '$rcx' } } + +--- | + target datalayout = "e-m:w-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128" + target triple = "x86_64-pc-windows-msvc19.22.27905" + + define dso_local void @taildupit(i32* readonly %size_ptr) { + entry: + %tobool = icmp eq i32* %size_ptr, null + br i1 %tobool, label %cond.end, label %cond.true + + cond.true: ; preds = %entry + %0 = load i32, i32* %size_ptr, align 4 + br label %cond.end + + cond.end: ; preds = %cond.true, %entry + %cond = phi i32 [ %0, %cond.true ], [ 1, %entry ] + %call = tail call i8* @alloc(i32 %cond) + tail call void @f2() + ret void + } + + declare dso_local i8* @alloc(i32) + + declare dso_local void @f2() + +... +--- +name: taildupit +tracksRegLiveness: true +liveins: + - { reg: '$rcx', virtual-reg: '' } +callSites: + - { bb: 3, offset: 0, fwdArgRegs: + - { arg: 0, reg: '$rcx' } } +body: | + bb.0.entry: + successors: %bb.1(0x30000000), %bb.2(0x50000000) + liveins: $rcx + + $rsp = frame-setup SUB64ri8 $rsp, 40, implicit-def dead $eflags + frame-setup SEH_StackAlloc 40 + frame-setup SEH_EndPrologue + TEST64rr renamable $rcx, renamable $rcx, implicit-def $eflags + JCC_1 %bb.2, 5, implicit killed $eflags + + bb.1: + successors: %bb.3(0x80000000) + + renamable $ecx = MOV32ri 1 + JMP_1 %bb.3 + + bb.2.cond.true: + successors: %bb.3(0x80000000) + liveins: $rcx + + renamable $ecx = MOV32rm killed renamable $rcx, 1, $noreg, 0, $noreg :: (load 4 from %ir.size_ptr) + + bb.3.cond.end: + liveins: $ecx + + CALL64pcrel32 @alloc, csr_win64, implicit $rsp, implicit $ssp, implicit $ecx, implicit-def $rsp, implicit-def $ssp, implicit-def dead $rax + SEH_Epilogue + $rsp = frame-destroy ADD64ri8 $rsp, 40, implicit-def dead $eflags + TAILJMPd64 @f2, csr_win64, implicit $rsp, implicit $ssp, implicit $rsp, implicit $ssp + +... diff --git a/llvm/test/DebugInfo/AArch64/dbgcall-site-float-entry-value.ll b/llvm/test/DebugInfo/AArch64/dbgcall-site-float-entry-value.ll new file mode 100644 index 0000000000000..27c6fb3f8ff0c --- /dev/null +++ b/llvm/test/DebugInfo/AArch64/dbgcall-site-float-entry-value.ll @@ -0,0 +1,49 @@ +; RUN: llc -mtriple aarch64-linux-gnu -debug-entry-values -filetype=obj -o - %s | llvm-dwarfdump - | FileCheck %s + +; Based on the following C reproducer: +; +; extern void callee(float); +; +; void foo(float param) { +; callee(param); +; } + +; Verify that a call site value using DW_OP_GNU_entry_value(DW_OP_regx B0) is +; emitted for the float parameter. Previously the entry value's multi-byte +; DW_OP_regx expression would be truncated. + +; CHECK: DW_TAG_GNU_call_site_parameter +; CHECK-NEXT: DW_AT_location (DW_OP_regx B0) +; CHECK-NEXT: DW_AT_GNU_call_site_value (DW_OP_GNU_entry_value(DW_OP_regx B0) + +target datalayout = "e-m:e-i8:8:32-i16:16:32-i64:64-i128:128-n32:64-S128" +target triple = "aarch64" + +; Function Attrs: nounwind +define dso_local void @foo(float %param) local_unnamed_addr !dbg !12 { +entry: + tail call void @callee(float %param), !dbg !13 + ret void, !dbg !14 +} + +declare !dbg !4 dso_local void @callee(float) local_unnamed_addr + +!llvm.dbg.cu = !{!0} +!llvm.module.flags = !{!8, !9, !10} +!llvm.ident = !{!11} + +!0 = distinct !DICompileUnit(language: DW_LANG_C99, file: !1, producer: "clang version 11.0.0 ", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, enums: !2, retainedTypes: !3, splitDebugInlining: false, nameTableKind: None) +!1 = !DIFile(filename: "float.c", directory: "/") +!2 = !{} +!3 = !{!4} +!4 = !DISubprogram(name: "callee", scope: !1, file: !1, line: 1, type: !5, flags: DIFlagPrototyped, spFlags: DISPFlagOptimized, retainedNodes: !2) +!5 = !DISubroutineType(types: !6) +!6 = !{null, !7} +!7 = !DIBasicType(name: "float", size: 32, encoding: DW_ATE_float) +!8 = !{i32 7, !"Dwarf Version", i32 4} +!9 = !{i32 2, !"Debug Info Version", i32 3} +!10 = !{i32 1, !"wchar_size", i32 4} +!11 = !{!"clang version 11.0.0 "} +!12 = distinct !DISubprogram(name: "foo", scope: !1, file: !1, line: 3, type: !5, scopeLine: 3, flags: DIFlagPrototyped | DIFlagAllCallsDescribed, spFlags: DISPFlagDefinition | DISPFlagOptimized, unit: !0, retainedNodes: !2) +!13 = !DILocation(line: 4, scope: !12) +!14 = !DILocation(line: 5, scope: !12) diff --git a/llvm/test/DebugInfo/MIR/X86/call-site-gnu-vs-dwarf5-attrs.mir b/llvm/test/DebugInfo/MIR/X86/call-site-gnu-vs-dwarf5-attrs.mir index 0718878e0faa4..53bb954b4ef2b 100644 --- a/llvm/test/DebugInfo/MIR/X86/call-site-gnu-vs-dwarf5-attrs.mir +++ b/llvm/test/DebugInfo/MIR/X86/call-site-gnu-vs-dwarf5-attrs.mir @@ -1,20 +1,24 @@ # Test the call site encoding in DWARF5 vs GNU extensions. # +# === DWARF4, tune for gdb === # RUN: llc -dwarf-version 4 -debugger-tune=gdb -filetype=obj \ # RUN: -mtriple=x86_64-unknown-unknown -start-after=machineverifier -o - %s \ -# RUN: | llvm-dwarfdump - | FileCheck %s -check-prefixes=CHECK-GNU +# RUN: | llvm-dwarfdump - | FileCheck %s -check-prefixes=CHECK-GNU -implicit-check-not=DW_AT_call # -# RUN: llc -dwarf-version 5 -debugger-tune=lldb -filetype=obj \ -# RUN: -mtriple=x86_64-unknown-unknown -start-after=machineverifier -o - %s \ -# RUN: | llvm-dwarfdump - | FileCheck %s -check-prefixes=CHECK-DWARF5 +# === DWARF5, tune for gdb === +# RUN: llc -dwarf-version 5 -debugger-tune=gdb -filetype=obj \ +# RUN: -mtriple=x86_64-unknown-unknown -start-after=machineverifier -o - %s \ +# RUN: | llvm-dwarfdump - | FileCheck %s -check-prefixes=CHECK-DWARF5 -implicit-check-not=DW_AT_call # -# RUN: llc -dwarf-version 5 -filetype=obj \ +# === DWARF4, tune for lldb === +# RUN: llc -dwarf-version 4 -debugger-tune=lldb -filetype=obj \ # RUN: -mtriple=x86_64-unknown-unknown -start-after=machineverifier -o - %s \ -# RUN: | llvm-dwarfdump - | FileCheck %s -check-prefixes=CHECK-DWARF5 +# RUN: | llvm-dwarfdump - | FileCheck %s -check-prefixes=CHECK-DWARF5 -implicit-check-not=DW_AT_call # -# RUN: llc -dwarf-version 5 -filetype=obj -debugger-tune=sce -emit-debug-entry-values \ +# === DWARF5, tune for lldb === +# RUN: llc -dwarf-version 5 -debugger-tune=lldb -filetype=obj \ # RUN: -mtriple=x86_64-unknown-unknown -start-after=machineverifier -o - %s \ -# RUN: | llvm-dwarfdump - | FileCheck %s -check-prefixes=CHECK-DWARF5 +# RUN: | llvm-dwarfdump - | FileCheck %s -check-prefixes=CHECK-DWARF5 -implicit-check-not=DW_AT_call # # This is based on the following reproducer: # @@ -49,6 +53,7 @@ # CHECK-GNU: DW_TAG_GNU_call_site # CHECK-GNU-NEXT: DW_AT_abstract_origin # CHECK-GNU-NEXT: DW_AT_GNU_tail_call +# CHECK-GNU-NEXT: DW_AT_low_pc # # # Check DWARF 5: @@ -58,6 +63,9 @@ # CHECK-DWARF5: DW_TAG_call_site # CHECK-DWARF5-NEXT: DW_AT_call_origin # CHECK-DWARF5-NEXT: DW_AT_call_return_pc +# CHECK-DWARF5: DW_TAG_call_site +# CHECK-DWARF5-NEXT: DW_AT_call_origin +# CHECK-DWARF5-NEXT: DW_AT_call_return_pc # CHECK-DWARF5: DW_TAG_call_site_parameter # CHECK-DWARF5-NEXT: DW_AT_location # CHECK-DWARF5-NEXT: DW_AT_call_value @@ -67,6 +75,7 @@ # CHECK-DWARF5: DW_TAG_call_site # CHECK-DWARF5-NEXT: DW_AT_call_origin # CHECK-DWARF5-NEXT: DW_AT_call_tail_call +# CHECK-DWARF5-NEXT: DW_AT_call_pc # --- | ; ModuleID = 'call-site-attrs.c' diff --git a/llvm/test/DebugInfo/MIR/X86/callsite-stack-value.mir b/llvm/test/DebugInfo/MIR/X86/callsite-stack-value.mir new file mode 100644 index 0000000000000..5a24bd54cef9b --- /dev/null +++ b/llvm/test/DebugInfo/MIR/X86/callsite-stack-value.mir @@ -0,0 +1,68 @@ +# RUN: llc -start-after=livedebugvalues -mtriple=x86_64-apple-darwin -o - %s -filetype=obj \ +# RUN: | llvm-dwarfdump - | FileCheck %s -implicit-check-not=call_site_parameter + +# CHECK: DW_TAG_formal_parameter +# CHECK-NEXT: DW_AT_location +# CHECK-NEXT: DW_OP_reg17 + +# struct S { +# float w; +# }; +# void f(long w, long b); +# void g(struct S s) { +# int w = s.w; +# f(w, w*4); +# } + +--- | + define void @g(float %s.coerce) local_unnamed_addr !dbg !20 { + entry: + ret void, !dbg !31 + } + declare !dbg !14 void @f(i64, i64) local_unnamed_addr + !llvm.module.flags = !{!6, !7, !8, !9} + !llvm.dbg.cu = !{!10} + !6 = !{i32 7, !"Dwarf Version", i32 4} + !7 = !{i32 2, !"Debug Info Version", i32 3} + !8 = !{i32 1, !"wchar_size", i32 4} + !9 = !{i32 7, !"PIC Level", i32 2} + !10 = distinct !DICompileUnit(language: DW_LANG_ObjC, file: !15, producer: "", isOptimized: true, runtimeVersion: 2, emissionKind: FullDebug, enums: !12, retainedTypes: !13, nameTableKind: None, sysroot: "/") + !12 = !{} + !13 = !{!14} + !14 = !DISubprogram(name: "f", scope: !15, file: !15, line: 4, type: !16, flags: DIFlagPrototyped, spFlags: DISPFlagOptimized, retainedNodes: !12) + !15 = !DIFile(filename: "test.m", directory: "/") + !16 = !DISubroutineType(types: !17) + !17 = !{null, !18, !18} + !18 = !DIBasicType(name: "long int", size: 64, encoding: DW_ATE_signed) + !20 = distinct !DISubprogram(name: "g", scope: !15, file: !15, line: 5, type: !21, scopeLine: 5, flags: DIFlagPrototyped | DIFlagAllCallsDescribed, spFlags: DISPFlagDefinition | DISPFlagOptimized, unit: !10, retainedNodes: !27) + !21 = !DISubroutineType(types: !22) + !22 = !{null, !23} + !23 = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "S", file: !15, line: 1, size: 32, elements: !24) + !24 = !{!25} + !25 = !DIDerivedType(tag: DW_TAG_member, name: "w", scope: !23, file: !15, line: 2, baseType: !26, size: 32) + !26 = !DIBasicType(name: "float", size: 32, encoding: DW_ATE_float) + !27 = !{!28, !29} + !28 = !DILocalVariable(name: "s", arg: 1, scope: !20, file: !15, line: 5, type: !23) + !29 = !DILocalVariable(name: "w", scope: !20, file: !15, line: 6, type: !30) + !30 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed) + !31 = !DILocation(line: 0, scope: !20) +name: g +callSites: + - { bb: 0, offset: 13, fwdArgRegs: + - { arg: 1, reg: '$rsi' } } +body: | + bb.0.entry: + DBG_VALUE $xmm0, $noreg, !28, !DIExpression(), debug-location !31 + DBG_VALUE $xmm0, $noreg, !28, !DIExpression(), debug-location !31 + frame-setup PUSH64r killed $rbp, implicit-def $rsp, implicit $rsp + CFI_INSTRUCTION def_cfa_offset 16 + CFI_INSTRUCTION offset $rbp, -16 + $rbp = frame-setup MOV64rr $rsp + CFI_INSTRUCTION def_cfa_register $rbp + renamable $eax = CVTTSS2SIrr killed renamable $xmm0, implicit $mxcsr, debug-location !31 + DBG_VALUE $eax, $noreg, !29, !DIExpression(), debug-location !31 + renamable $rdi = MOVSX64rr32 killed renamable $eax, debug-location !31 + renamable $eax = LEA64_32r $noreg, 4, renamable $rdi, 0, $noreg, debug-location !31 + renamable $rsi = MOVSX64rr32 killed renamable $eax, debug-location !31 + $rbp = frame-destroy POP64r implicit-def $rsp, implicit $rsp, debug-location !31 + TAILJMPd64 @f, csr_64, implicit $rsp, implicit $ssp, implicit $rsp, implicit $ssp, implicit $rdi, implicit $rsi, debug-location !31 diff --git a/llvm/test/DebugInfo/X86/dead-store-elimination-marks-undef.ll b/llvm/test/DebugInfo/X86/dead-store-elimination-marks-undef.ll new file mode 100644 index 0000000000000..5f9e67653d966 --- /dev/null +++ b/llvm/test/DebugInfo/X86/dead-store-elimination-marks-undef.ll @@ -0,0 +1,36 @@ +; RUN: opt -mtriple=x86_64-- -S --dse %s -o - | FileCheck %s +; Ensure that we can mark a value as undefined when performing dead +; store elimination. +; Bugzilla #45080 + +@b = common dso_local local_unnamed_addr global i32 0, align 1 + +define dso_local i32 @main() local_unnamed_addr !dbg !7 { + %1 = alloca i32, align 4 + %2 = load i32, i32* @b, align 1, !dbg !13 + ; CHECK: call void @llvm.dbg.value(metadata i32 undef + call void @llvm.dbg.value(metadata i32 %2, metadata !12, metadata !DIExpression()), !dbg !13 + store i32 %2, i32* %1, align 4, !dbg !13 + ret i32 0, !dbg !13 +} + +declare void @llvm.dbg.value(metadata, metadata, metadata) + +!llvm.dbg.cu = !{!0} +!llvm.module.flags = !{!3, !4} +!llvm.ident = !{!6} + +!0 = distinct !DICompileUnit(language: DW_LANG_C99, file: !1, producer: "clang version 10.0.0", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, enums: !2, globals: !2, nameTableKind: None) +!1 = !DIFile(filename: "dead-store-elimination-marks-undef.ll", directory: "/temp/bz45080") +!2 = !{} +!3 = !{i32 2, !"Dwarf Version", i32 4} +!4 = !{i32 2, !"Debug Info Version", i32 3} +!6 = !{!"clang version 10.0.0"} +!7 = distinct !DISubprogram(name: "main", scope: !1, file: !1, line: 3, type: !8, scopeLine: 3, spFlags: DISPFlagDefinition | DISPFlagOptimized, unit: !0, retainedNodes: !11) +!8 = !DISubroutineType(types: !9) +!9 = !{!10} +!10 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed) +!11 = !{!12} +!12 = !DILocalVariable(name: "l_2864", scope: !7, file: !1, line: 4, type: !10) +!13 = !DILocation(line: 5, column: 12, scope: !7) + diff --git a/llvm/test/DebugInfo/X86/dwarf-callsite-related-attrs.ll b/llvm/test/DebugInfo/X86/dwarf-callsite-related-attrs.ll index 33e06faba57bc..51738f2122425 100644 --- a/llvm/test/DebugInfo/X86/dwarf-callsite-related-attrs.ll +++ b/llvm/test/DebugInfo/X86/dwarf-callsite-related-attrs.ll @@ -15,7 +15,7 @@ ; REQUIRES: object-emission ; RUN: %llc_dwarf -mtriple=x86_64-- < %s -o - | FileCheck %s -check-prefix=ASM ; RUN: %llc_dwarf -debugger-tune=lldb -mtriple=x86_64-- < %s -filetype=obj -o %t.o -; RUN: llvm-dwarfdump %t.o -o - | FileCheck %s -check-prefix=OBJ -implicit-check-not=DW_TAG_call_site +; RUN: llvm-dwarfdump %t.o -o - | FileCheck %s -check-prefix=OBJ -implicit-check-not=DW_TAG_call -implicit-check-not=DW_AT_call ; RUN: llvm-dwarfdump -verify %t.o 2>&1 | FileCheck %s -check-prefix=VERIFY ; RUN: llvm-dwarfdump -statistics %t.o | FileCheck %s -check-prefix=STATS ; RUN: llvm-as < %s | llvm-dis | llvm-as | llvm-dis -o /dev/null @@ -76,6 +76,7 @@ entry: ; OBJ: DW_TAG_call_site ; OBJ: DW_AT_call_origin ([[bat_sp]]) ; OBJ: DW_AT_call_tail_call +; OBJ: DW_AT_call_pc define void @_Z3foov() !dbg !25 { entry: tail call void @__has_no_subprogram() diff --git a/llvm/test/DebugInfo/X86/licm-undef-dbg-value.ll b/llvm/test/DebugInfo/X86/licm-undef-dbg-value.ll new file mode 100644 index 0000000000000..09a18f937b3bb --- /dev/null +++ b/llvm/test/DebugInfo/X86/licm-undef-dbg-value.ll @@ -0,0 +1,86 @@ +; RUN: opt -licm %s -S | FileCheck %s + +; CHECK: for.body: +; CHECK-NEXT: llvm.dbg.value(metadata i8 undef + +; The load is loop invariant. Check that we leave an undef dbg.value behind +; when licm sinks the instruction. + +; clang reduce.cpp -g -O2 -Xclang -disable-llvm-passes -emit-llvm -o reduce.ll +; opt -simplifycfg -sroa -loop-rotate -o - -S reduce.ll +; cat reduce.cpp +; extern char a; +; extern char b; +; void use(char); +; void fun() { +; char local = 0; +; for (;b;) +; local = a; +; use(local); +; } + +@b = external dso_local global i8, align 1 +@a = external dso_local global i8, align 1 + +define dso_local void @_Z3funv() !dbg !12 { +entry: + call void @llvm.dbg.value(metadata i8 0, metadata !16, metadata !DIExpression()), !dbg !17 + %0 = load i8, i8* @b, align 1, !dbg !18 + %tobool1 = icmp ne i8 %0, 0, !dbg !18 + br i1 %tobool1, label %for.body.lr.ph, label %for.end, !dbg !24 + +for.body.lr.ph: ; preds = %entry + br label %for.body, !dbg !24 + +for.body: ; preds = %for.body.lr.ph, %for.body + %1 = load i8, i8* @a, align 1, !dbg !25 + call void @llvm.dbg.value(metadata i8 %1, metadata !16, metadata !DIExpression()), !dbg !17 + %2 = load i8, i8* @b, align 1, !dbg !18 + %tobool = icmp ne i8 %2, 0, !dbg !18 + br i1 %tobool, label %for.body, label %for.cond.for.end_crit_edge, !dbg !24, !llvm.loop !26 + +for.cond.for.end_crit_edge: ; preds = %for.body + %split = phi i8 [ %1, %for.body ] + br label %for.end, !dbg !24 + +for.end: ; preds = %for.cond.for.end_crit_edge, %entry + %local.0.lcssa = phi i8 [ %split, %for.cond.for.end_crit_edge ], [ 0, %entry ], !dbg !17 + call void @llvm.dbg.value(metadata i8 %local.0.lcssa, metadata !16, metadata !DIExpression()), !dbg !17 + call void @_Z3usec(i8 signext %local.0.lcssa), !dbg !28 + ret void, !dbg !29 +} + +declare !dbg !4 dso_local void @_Z3usec(i8 signext) +declare void @llvm.dbg.value(metadata, metadata, metadata) + +!llvm.dbg.cu = !{!0} +!llvm.module.flags = !{!8, !9, !10} +!llvm.ident = !{!11} + +!0 = distinct !DICompileUnit(language: DW_LANG_C_plus_plus_14, file: !1, producer: "clang version 11.0.0", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, enums: !2, retainedTypes: !3, splitDebugInlining: false, nameTableKind: None) +!1 = !DIFile(filename: "reduce.cpp", directory: "/") +!2 = !{} +!3 = !{!4} +!4 = !DISubprogram(name: "use", linkageName: "_Z3usec", scope: !1, file: !1, line: 3, type: !5, flags: DIFlagPrototyped, spFlags: DISPFlagOptimized, retainedNodes: !2) +!5 = !DISubroutineType(types: !6) +!6 = !{null, !7} +!7 = !DIBasicType(name: "char", size: 8, encoding: DW_ATE_signed_char) +!8 = !{i32 7, !"Dwarf Version", i32 4} +!9 = !{i32 2, !"Debug Info Version", i32 3} +!10 = !{i32 1, !"wchar_size", i32 4} +!11 = !{!"clang version 11.0.0"} +!12 = distinct !DISubprogram(name: "fun", linkageName: "_Z3funv", scope: !1, file: !1, line: 4, type: !13, scopeLine: 4, flags: DIFlagPrototyped | DIFlagAllCallsDescribed, spFlags: DISPFlagDefinition | DISPFlagOptimized, unit: !0, retainedNodes: !15) +!13 = !DISubroutineType(types: !14) +!14 = !{null} +!15 = !{!16} +!16 = !DILocalVariable(name: "local", scope: !12, file: !1, line: 5, type: !7) +!17 = !DILocation(line: 0, scope: !12) +!18 = !DILocation(line: 6, column: 9, scope: !19) +!19 = distinct !DILexicalBlock(scope: !20, file: !1, line: 6, column: 3) +!20 = distinct !DILexicalBlock(scope: !12, file: !1, line: 6, column: 3) +!24 = !DILocation(line: 6, column: 3, scope: !20) +!25 = !DILocation(line: 7, column: 13, scope: !19) +!26 = distinct !{!26, !24, !27} +!27 = !DILocation(line: 7, column: 13, scope: !20) +!28 = !DILocation(line: 8, column: 3, scope: !12) +!29 = !DILocation(line: 9, column: 1, scope: !12) diff --git a/llvm/test/DebugInfo/X86/machinecse-wrongdebug-hoist.ll b/llvm/test/DebugInfo/X86/machinecse-wrongdebug-hoist.ll new file mode 100644 index 0000000000000..8f3b08a91eb57 --- /dev/null +++ b/llvm/test/DebugInfo/X86/machinecse-wrongdebug-hoist.ll @@ -0,0 +1,80 @@ +; RUN: llc %s -o - -print-after=machine-cse -mtriple=x86_64-- 2>&1 | FileCheck %s --match-full-lines + +; CHECK: %5:gr32 = SUB32ri8 %0:gr32(tied-def 0), 1, implicit-def $eflags, debug-location !24; a.c:3:13 +; CHECK-NEXT: %10:gr32 = MOVSX32rr8 %4:gr8 +; CHECK-NEXT: JCC_1 %bb.2, 15, implicit $eflags, debug-location !25; a.c:3:18 + +target datalayout = "e-m:o-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128" +target triple = "x86_64-apple-macosx10.15.0" + +@a = local_unnamed_addr global i32 0, align 4, !dbg !0 + +; Function Attrs: norecurse nounwind readonly ssp uwtable +define i32 @b(i8 signext %0) local_unnamed_addr #0 !dbg !12 { + call void @llvm.dbg.value(metadata i8 %0, metadata !17, metadata !DIExpression()), !dbg !18 + %2 = load i32, i32* @a, align 4, !dbg !19, !tbaa !20 + %3 = icmp sgt i32 %2, 1, !dbg !24 + br i1 %3, label %8, label %4, !dbg !25 + +4: ; preds = %1 + %5 = sext i8 %0 to i32, !dbg !26 + %6 = ashr i32 %5, %2, !dbg !27 + %7 = icmp eq i32 %6, 0, !dbg !27 + br i1 %7, label %10, label %8, !dbg !28 + +8: ; preds = %4, %1 + %9 = sext i8 %0 to i32, !dbg !29 + br label %10, !dbg !28 + +10: ; preds = %4, %8 + %11 = phi i32 [ %9, %8 ], [ 0, %4 ], !dbg !28 + ret i32 %11, !dbg !30 +} + +define i32 @main() local_unnamed_addr #0 !dbg !31 { + %1 = call i32 @b(i8 signext 0), !dbg !34 + ret i32 %1, !dbg !35 +} + +declare void @llvm.dbg.value(metadata, metadata, metadata) #1 + +!llvm.dbg.cu = !{!2} +!llvm.module.flags = !{!7, !8, !9, !10} +!llvm.ident = !{!11} + +!0 = !DIGlobalVariableExpression(var: !1, expr: !DIExpression()) +!1 = distinct !DIGlobalVariable(name: "a", scope: !2, file: !3, line: 1, type: !6, isLocal: false, isDefinition: true) +!2 = distinct !DICompileUnit(language: DW_LANG_C99, file: !3, producer: "clang version 11.0.0 (https://github.com/llvm/llvm-project 75cfd382201978615cca1c91c2d9f14f8b7af56d)", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, enums: !4, globals: !5, nameTableKind: None, sysroot: "/") +!3 = !DIFile(filename: "a.c", directory: "/Users/davide/work/build/bin") +!4 = !{} +!5 = !{!0} +!6 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed) +!7 = !{i32 7, !"Dwarf Version", i32 4} +!8 = !{i32 2, !"Debug Info Version", i32 3} +!9 = !{i32 1, !"wchar_size", i32 4} +!10 = !{i32 7, !"PIC Level", i32 2} +!11 = !{!"clang version 11.0.0 (https://github.com/llvm/llvm-project 75cfd382201978615cca1c91c2d9f14f8b7af56d)"} +!12 = distinct !DISubprogram(name: "b", scope: !3, file: !3, line: 2, type: !13, scopeLine: 2, flags: DIFlagPrototyped | DIFlagAllCallsDescribed, spFlags: DISPFlagDefinition | DISPFlagOptimized, unit: !2, retainedNodes: !16) +!13 = !DISubroutineType(types: !14) +!14 = !{!6, !15} +!15 = !DIBasicType(name: "char", size: 8, encoding: DW_ATE_signed_char) +!16 = !{!17} +!17 = !DILocalVariable(name: "c", arg: 1, scope: !12, file: !3, line: 2, type: !15) +!18 = !DILocation(line: 0, scope: !12) +!19 = !DILocation(line: 3, column: 11, scope: !12) +!20 = !{!21, !21, i64 0} +!21 = !{!"int", !22, i64 0} +!22 = !{!"omnipotent char", !23, i64 0} +!23 = !{!"Simple C/C++ TBAA"} +!24 = !DILocation(line: 3, column: 13, scope: !12) +!25 = !DILocation(line: 3, column: 18, scope: !12) +!26 = !DILocation(line: 3, column: 21, scope: !12) +!27 = !DILocation(line: 3, column: 23, scope: !12) +!28 = !DILocation(line: 3, column: 10, scope: !12) +!29 = !DILocation(line: 4, column: 16, scope: !12) +!30 = !DILocation(line: 3, column: 3, scope: !12) +!31 = distinct !DISubprogram(name: "main", scope: !3, file: !3, line: 8, type: !32, scopeLine: 9, flags: DIFlagAllCallsDescribed, spFlags: DISPFlagDefinition | DISPFlagOptimized, unit: !2, retainedNodes: !4) +!32 = !DISubroutineType(types: !33) +!33 = !{!6} +!34 = !DILocation(line: 10, column: 10, scope: !31) +!35 = !DILocation(line: 10, column: 3, scope: !31) diff --git a/llvm/test/DebugInfo/X86/pr45181.ll b/llvm/test/DebugInfo/X86/pr45181.ll new file mode 100644 index 0000000000000..ececeabdfd89d --- /dev/null +++ b/llvm/test/DebugInfo/X86/pr45181.ll @@ -0,0 +1,306 @@ +; RUN: llc -O1 -filetype=obj -debug-entry-values -o - < %s | llvm-dwarfdump -verify - -o /dev/null + +; TODO: This test should be made more targeted by converting to MIR and reducing, +; however at the moment conversion to MIR fails with: +; Assertion failed: (!NameRef.empty() && "Normal symbols cannot be unnamed!") + +target datalayout = "e-m:o-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128" +target triple = "x86_64-apple-macosx10.14.0" + +%struct.e = type opaque +%"class.aa::aq" = type { i8 } +%"class.aa::ah" = type { i8 } +%"class.aa::y" = type { i8 } +%"class.aa::y.0" = type { i8 } +%struct.j = type opaque +%struct.h = type opaque +%struct.r = type opaque + +@o = local_unnamed_addr global i32 0, align 4, !dbg !0 +@p = local_unnamed_addr global %struct.e* null, align 8, !dbg !42 + +; Function Attrs: optsize ssp uwtable +define void @_ZN2aa2aq2arEv(%"class.aa::aq"* %this) local_unnamed_addr #0 align 2 !dbg !50 { +entry: + call void @llvm.dbg.value(metadata %"class.aa::aq"* %this, metadata !71, metadata !DIExpression()), !dbg !75 + %0 = bitcast %"class.aa::aq"* %this to %"class.aa::ah"*, !dbg !76 + tail call void @_ZN2aa2ah2aiEiib(%"class.aa::ah"* %0, i32 undef, i32 undef, i1 zeroext true) #5, !dbg !76 + ret void, !dbg !77 +} + +; Function Attrs: nounwind readnone speculatable willreturn +declare void @llvm.dbg.declare(metadata, metadata, metadata) #1 + +; Function Attrs: argmemonly nounwind willreturn +declare void @llvm.lifetime.start.p0i8(i64 immarg, i8* nocapture) #2 + +; Function Attrs: optsize ssp uwtable +define linkonce_odr void @_ZN2aa2ah2aiEiib(%"class.aa::ah"* %this, i32 %aj, i32 %0, i1 zeroext %1) local_unnamed_addr #0 align 2 personality i8* bitcast (i32 (...)* @__gxx_personality_v0 to i8*) !dbg !78 { +entry: + %ao = alloca %"class.aa::y", align 1 + %ap = alloca %"class.aa::y.0", align 1 + call void @llvm.dbg.value(metadata %"class.aa::ah"* %this, metadata !80, metadata !DIExpression()), !dbg !126 + call void @llvm.dbg.value(metadata i32 %aj, metadata !82, metadata !DIExpression()), !dbg !126 + call void @llvm.dbg.value(metadata i32 %0, metadata !83, metadata !DIExpression()), !dbg !126 + call void @llvm.dbg.value(metadata i1 %1, metadata !84, metadata !DIExpression()), !dbg !126 + call void @llvm.dbg.value(metadata i32 %aj, metadata !85, metadata !DIExpression()), !dbg !126 + %2 = getelementptr inbounds %"class.aa::y", %"class.aa::y"* %ao, i64 0, i32 0, !dbg !127 + call void @llvm.lifetime.start.p0i8(i64 1, i8* nonnull %2) #6, !dbg !127 + call void @llvm.dbg.declare(metadata %"class.aa::y"* %ao, metadata !91, metadata !DIExpression()), !dbg !128 + %call = tail call %struct.j* @_Z1mPvS_lPFvS_PKvlE(i8* undef, i8* undef, i64 0, void (i8*, i8*, i64)* nonnull @_ZN2aa12_GLOBAL__N_12agEPvPKvl) #5, !dbg !129 + call void @_ZN2aa1yIP1jNS_2ac1zI1eEEEC1ES2_(%"class.aa::y"* nonnull %ao, %struct.j* %call) #5, !dbg !128 + %3 = getelementptr inbounds %"class.aa::y.0", %"class.aa::y.0"* %ap, i64 0, i32 0, !dbg !130 + call void @llvm.lifetime.start.p0i8(i64 1, i8* nonnull %3) #6, !dbg !130 + call void @llvm.dbg.declare(metadata %"class.aa::y.0"* %ap, metadata !110, metadata !DIExpression()), !dbg !131 + %4 = load %struct.e*, %struct.e** @p, align 8, !dbg !132, !tbaa !133 + %call3 = invoke %struct.h* @_Z1qP1e(%struct.e* %4) #5 + to label %invoke.cont unwind label %lpad, !dbg !137 + +invoke.cont: ; preds = %entry + invoke void @_ZN2aa1yIP1hNS_2ac1zI1eEEEC1ES2_(%"class.aa::y.0"* nonnull %ap, %struct.h* %call3) #5 + to label %invoke.cont4 unwind label %lpad, !dbg !131 + +invoke.cont4: ; preds = %invoke.cont + %conv = sext i32 %aj to i64, !dbg !138 + %mul = shl nsw i32 %aj, 2, !dbg !139 + %conv6 = sext i32 %mul to i64, !dbg !140 + %call9 = invoke %struct.h* @_ZN2aa1yIP1hNS_2ac1zI1eEEE2abEv(%"class.aa::y.0"* nonnull %ap) #5 + to label %invoke.cont8 unwind label %lpad7, !dbg !141 + +invoke.cont8: ; preds = %invoke.cont4 + %call11 = invoke %struct.j* @_ZN2aa1yIP1jNS_2ac1zI1eEEE2abEv(%"class.aa::y"* nonnull %ao) #5 + to label %invoke.cont10 unwind label %lpad7, !dbg !142 + +invoke.cont10: ; preds = %invoke.cont8 + %5 = load i32, i32* @o, align 4, !dbg !143, !tbaa !144 + %call13 = invoke %struct.r* @_Z1vlllllP1hiP1jPdb1n(i64 %conv, i64 0, i64 8, i64 2, i64 %conv6, %struct.h* %call9, i32 0, %struct.j* %call11, double* null, i1 zeroext false, i32 %5) #5 + to label %invoke.cont12 unwind label %lpad7, !dbg !146 + +invoke.cont12: ; preds = %invoke.cont10 + unreachable, !dbg !146 + +lpad: ; preds = %invoke.cont, %entry + %6 = landingpad { i8*, i32 } + cleanup, !dbg !147 + %7 = extractvalue { i8*, i32 } %6, 0, !dbg !147 + %8 = extractvalue { i8*, i32 } %6, 1, !dbg !147 + br label %ehcleanup, !dbg !147 + +lpad7: ; preds = %invoke.cont10, %invoke.cont8, %invoke.cont4 + %9 = landingpad { i8*, i32 } + cleanup, !dbg !147 + %10 = extractvalue { i8*, i32 } %9, 0, !dbg !147 + %11 = extractvalue { i8*, i32 } %9, 1, !dbg !147 + call void @_ZN2aa1yIP1hNS_2ac1zI1eEEED1Ev(%"class.aa::y.0"* nonnull %ap) #7, !dbg !147 + br label %ehcleanup, !dbg !147 + +ehcleanup: ; preds = %lpad7, %lpad + %exn.slot.0 = phi i8* [ %10, %lpad7 ], [ %7, %lpad ], !dbg !147 + %ehselector.slot.0 = phi i32 [ %11, %lpad7 ], [ %8, %lpad ], !dbg !147 + call void @llvm.lifetime.end.p0i8(i64 1, i8* nonnull %3) #6, !dbg !147 + call void @_ZN2aa1yIP1jNS_2ac1zI1eEEED1Ev(%"class.aa::y"* nonnull %ao) #7, !dbg !147 + call void @llvm.lifetime.end.p0i8(i64 1, i8* nonnull %2) #6, !dbg !147 + %lpad.val = insertvalue { i8*, i32 } undef, i8* %exn.slot.0, 0, !dbg !147 + %lpad.val19 = insertvalue { i8*, i32 } %lpad.val, i32 %ehselector.slot.0, 1, !dbg !147 + resume { i8*, i32 } %lpad.val19, !dbg !147 +} + +; Function Attrs: argmemonly nounwind willreturn +declare void @llvm.lifetime.end.p0i8(i64 immarg, i8* nocapture) #2 + +; Function Attrs: optsize +declare !dbg !11 %struct.j* @_Z1mPvS_lPFvS_PKvlE(i8*, i8*, i64, void (i8*, i8*, i64)*) local_unnamed_addr #3 + +; Function Attrs: optsize +declare void @_ZN2aa12_GLOBAL__N_12agEPvPKvl(i8*, i8*, i64) #3 + +; Function Attrs: optsize +declare void @_ZN2aa1yIP1jNS_2ac1zI1eEEEC1ES2_(%"class.aa::y"*, %struct.j*) unnamed_addr #3 + +; Function Attrs: optsize +declare !dbg !24 %struct.h* @_Z1qP1e(%struct.e*) local_unnamed_addr #3 + +declare i32 @__gxx_personality_v0(...) + +; Function Attrs: optsize +declare void @_ZN2aa1yIP1hNS_2ac1zI1eEEEC1ES2_(%"class.aa::y.0"*, %struct.h*) unnamed_addr #3 + +; Function Attrs: optsize +declare !dbg !31 %struct.r* @_Z1vlllllP1hiP1jPdb1n(i64, i64, i64, i64, i64, %struct.h*, i32, %struct.j*, double*, i1 zeroext, i32) local_unnamed_addr #3 + +; Function Attrs: optsize +declare %struct.h* @_ZN2aa1yIP1hNS_2ac1zI1eEEE2abEv(%"class.aa::y.0"*) local_unnamed_addr #3 + +; Function Attrs: optsize +declare %struct.j* @_ZN2aa1yIP1jNS_2ac1zI1eEEE2abEv(%"class.aa::y"*) local_unnamed_addr #3 + +; Function Attrs: nounwind optsize +declare void @_ZN2aa1yIP1hNS_2ac1zI1eEEED1Ev(%"class.aa::y.0"*) unnamed_addr #4 + +; Function Attrs: nounwind optsize +declare void @_ZN2aa1yIP1jNS_2ac1zI1eEEED1Ev(%"class.aa::y"*) unnamed_addr #4 + +; Function Attrs: nounwind readnone speculatable willreturn +declare void @llvm.dbg.value(metadata, metadata, metadata) #1 + +attributes #0 = { optsize ssp uwtable "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "frame-pointer"="all" "less-precise-fpmad"="false" "min-legal-vector-width"="0" "no-infs-fp-math"="false" "no-jump-tables"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "target-cpu"="penryn" "target-features"="+cx16,+cx8,+fxsr,+mmx,+sahf,+sse,+sse2,+sse3,+sse4.1,+ssse3,+x87" "unsafe-fp-math"="false" "use-soft-float"="false" } +attributes #1 = { nounwind readnone speculatable willreturn } +attributes #2 = { argmemonly nounwind willreturn } +attributes #3 = { optsize "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "frame-pointer"="all" "less-precise-fpmad"="false" "no-infs-fp-math"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "target-cpu"="penryn" "target-features"="+cx16,+cx8,+fxsr,+mmx,+sahf,+sse,+sse2,+sse3,+sse4.1,+ssse3,+x87" "unsafe-fp-math"="false" "use-soft-float"="false" } +attributes #4 = { nounwind optsize "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "frame-pointer"="all" "less-precise-fpmad"="false" "no-infs-fp-math"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "target-cpu"="penryn" "target-features"="+cx16,+cx8,+fxsr,+mmx,+sahf,+sse,+sse2,+sse3,+sse4.1,+ssse3,+x87" "unsafe-fp-math"="false" "use-soft-float"="false" } +attributes #5 = { optsize } +attributes #6 = { nounwind } +attributes #7 = { nounwind optsize } + +!llvm.dbg.cu = !{!2} +!llvm.module.flags = !{!45, !46, !47, !48} +!llvm.ident = !{!49} + +!0 = !DIGlobalVariableExpression(var: !1, expr: !DIExpression()) +!1 = distinct !DIGlobalVariable(name: "o", scope: !2, file: !6, line: 11, type: !40, isLocal: false, isDefinition: true) +!2 = distinct !DICompileUnit(language: DW_LANG_C_plus_plus_14, file: !3, producer: "clang version 11.0.0 (git@github.com:llvm/llvm-project.git 0fecdcd1628999a1900d9cf84cd33dacf1319fa6)", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, enums: !4, retainedTypes: !10, globals: !41, nameTableKind: None, sysroot: "/") +!3 = !DIFile(filename: "/Users/vsk/tmp/x.cc", directory: "/Users/vsk/src/llvm-backup-master") +!4 = !{!5} +!5 = !DICompositeType(tag: DW_TAG_enumeration_type, file: !6, line: 16, baseType: !7, size: 32, elements: !8) +!6 = !DIFile(filename: "tmp/x.cc", directory: "/Users/vsk") +!7 = !DIBasicType(name: "unsigned int", size: 32, encoding: DW_ATE_unsigned) +!8 = !{!9} +!9 = !DIEnumerator(name: "u", value: 0, isUnsigned: true) +!10 = !{!11, !24, !31} +!11 = !DISubprogram(name: "m", linkageName: "_Z1mPvS_lPFvS_PKvlE", scope: !6, file: !6, line: 10, type: !12, flags: DIFlagPrototyped, spFlags: DISPFlagOptimized, retainedNodes: !23) +!12 = !DISubroutineType(types: !13) +!13 = !{!14, !16, !16, !17, !18} +!14 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !15, size: 64) +!15 = !DICompositeType(tag: DW_TAG_structure_type, name: "j", file: !6, line: 8, flags: DIFlagFwdDecl, identifier: "_ZTS1j") +!16 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: null, size: 64) +!17 = !DIBasicType(name: "long int", size: 64, encoding: DW_ATE_signed) +!18 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !19, size: 64) +!19 = !DISubroutineType(types: !20) +!20 = !{null, !16, !21, !17} +!21 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !22, size: 64) +!22 = !DIDerivedType(tag: DW_TAG_const_type, baseType: null) +!23 = !{} +!24 = !DISubprogram(name: "q", linkageName: "_Z1qP1e", scope: !6, file: !6, line: 13, type: !25, flags: DIFlagPrototyped, spFlags: DISPFlagOptimized, retainedNodes: !23) +!25 = !DISubroutineType(types: !26) +!26 = !{!27, !29} +!27 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !28, size: 64) +!28 = !DICompositeType(tag: DW_TAG_structure_type, name: "h", file: !6, line: 7, flags: DIFlagFwdDecl, identifier: "_ZTS1h") +!29 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !30, size: 64) +!30 = !DICompositeType(tag: DW_TAG_structure_type, name: "e", file: !6, line: 5, flags: DIFlagFwdDecl, identifier: "_ZTS1e") +!31 = !DISubprogram(name: "v", linkageName: "_Z1vlllllP1hiP1jPdb1n", scope: !6, file: !6, line: 17, type: !32, flags: DIFlagPrototyped, spFlags: DISPFlagOptimized, retainedNodes: !23) +!32 = !DISubroutineType(types: !33) +!33 = !{!34, !17, !17, !17, !17, !17, !27, !36, !14, !37, !39, !40} +!34 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !35, size: 64) +!35 = !DICompositeType(tag: DW_TAG_structure_type, name: "r", file: !6, line: 14, flags: DIFlagFwdDecl, identifier: "_ZTS1r") +!36 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed) +!37 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !38, size: 64) +!38 = !DIBasicType(name: "double", size: 64, encoding: DW_ATE_float) +!39 = !DIBasicType(name: "bool", size: 8, encoding: DW_ATE_boolean) +!40 = !DICompositeType(tag: DW_TAG_enumeration_type, name: "n", file: !6, line: 11, size: 32, flags: DIFlagFwdDecl, identifier: "_ZTS1n") +!41 = !{!0, !42} +!42 = !DIGlobalVariableExpression(var: !43, expr: !DIExpression()) +!43 = distinct !DIGlobalVariable(name: "p", scope: !2, file: !6, line: 12, type: !44, isLocal: false, isDefinition: true) +!44 = !DIDerivedType(tag: DW_TAG_typedef, name: "f", file: !6, line: 5, baseType: !29) +!45 = !{i32 7, !"Dwarf Version", i32 4} +!46 = !{i32 2, !"Debug Info Version", i32 3} +!47 = !{i32 1, !"wchar_size", i32 4} +!48 = !{i32 7, !"PIC Level", i32 2} +!49 = !{!"clang version 11.0.0 (git@github.com:llvm/llvm-project.git 0fecdcd1628999a1900d9cf84cd33dacf1319fa6)"} +!50 = distinct !DISubprogram(name: "ar", linkageName: "_ZN2aa2aq2arEv", scope: !51, file: !6, line: 48, type: !67, scopeLine: 48, flags: DIFlagPrototyped | DIFlagAllCallsDescribed, spFlags: DISPFlagDefinition | DISPFlagOptimized, unit: !2, declaration: !66, retainedNodes: !70) +!51 = distinct !DICompositeType(tag: DW_TAG_class_type, name: "aq", scope: !52, file: !6, line: 45, size: 8, flags: DIFlagTypePassByValue, elements: !53, identifier: "_ZTSN2aa2aqE") +!52 = !DINamespace(name: "aa", scope: null) +!53 = !{!54, !66} +!54 = !DIDerivedType(tag: DW_TAG_inheritance, scope: !51, baseType: !55, extraData: i32 0) +!55 = distinct !DICompositeType(tag: DW_TAG_class_type, name: "ah", scope: !52, file: !6, line: 34, size: 8, flags: DIFlagTypePassByValue, elements: !56, identifier: "_ZTSN2aa2ahE") +!56 = !{!57} +!57 = !DISubprogram(name: "ai", linkageName: "_ZN2aa2ah2aiEiib", scope: !55, file: !6, line: 36, type: !58, scopeLine: 36, flags: DIFlagPublic | DIFlagPrototyped, spFlags: DISPFlagOptimized) +!58 = !DISubroutineType(types: !59) +!59 = !{!60, !64, !65, !65, !39} +!60 = distinct !DICompositeType(tag: DW_TAG_class_type, name: "af", scope: !52, file: !6, line: 30, size: 8, flags: DIFlagTypePassByValue, elements: !23, templateParams: !61, identifier: "_ZTSN2aa2afI1wEE") +!61 = !{!62} +!62 = !DITemplateTypeParameter(type: !63) +!63 = !DICompositeType(tag: DW_TAG_class_type, name: "w", file: !6, line: 18, flags: DIFlagFwdDecl, identifier: "_ZTS1w") +!64 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !55, size: 64, flags: DIFlagArtificial | DIFlagObjectPointer) +!65 = !DIDerivedType(tag: DW_TAG_typedef, name: "b", file: !6, line: 2, baseType: !36) +!66 = !DISubprogram(name: "ar", linkageName: "_ZN2aa2aq2arEv", scope: !51, file: !6, line: 46, type: !67, scopeLine: 46, flags: DIFlagPrototyped, spFlags: DISPFlagOptimized) +!67 = !DISubroutineType(types: !68) +!68 = !{null, !69} +!69 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !51, size: 64, flags: DIFlagArtificial | DIFlagObjectPointer) +!70 = !{!71, !73, !74} +!71 = !DILocalVariable(name: "this", arg: 1, scope: !50, type: !72, flags: DIFlagArtificial | DIFlagObjectPointer) +!72 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !51, size: 64) +!73 = !DILocalVariable(name: "aj", scope: !50, file: !6, line: 49, type: !65) +!74 = !DILocalVariable(name: "am", scope: !50, file: !6, line: 50, type: !65) +!75 = !DILocation(line: 0, scope: !50) +!76 = !DILocation(line: 51, column: 3, scope: !50) +!77 = !DILocation(line: 52, column: 1, scope: !50) +!78 = distinct !DISubprogram(name: "ai", linkageName: "_ZN2aa2ah2aiEiib", scope: !55, file: !6, line: 36, type: !58, scopeLine: 36, flags: DIFlagPrototyped | DIFlagAllCallsDescribed, spFlags: DISPFlagDefinition | DISPFlagOptimized, unit: !2, declaration: !57, retainedNodes: !79) +!79 = !{!80, !82, !83, !84, !85, !86, !87, !91, !110} +!80 = !DILocalVariable(name: "this", arg: 1, scope: !78, type: !81, flags: DIFlagArtificial | DIFlagObjectPointer) +!81 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !55, size: 64) +!82 = !DILocalVariable(name: "aj", arg: 2, scope: !78, file: !6, line: 36, type: !65) +!83 = !DILocalVariable(arg: 3, scope: !78, file: !6, line: 36, type: !65) +!84 = !DILocalVariable(arg: 4, scope: !78, file: !6, line: 36, type: !39) +!85 = !DILocalVariable(name: "ak", scope: !78, file: !6, line: 37, type: !65) +!86 = !DILocalVariable(name: "al", scope: !78, file: !6, line: 38, type: !65) +!87 = !DILocalVariable(name: "an", scope: !78, file: !6, line: 39, type: !88) +!88 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !89, size: 64) +!89 = !DIDerivedType(tag: DW_TAG_typedef, name: "c", file: !6, line: 3, baseType: !90) +!90 = !DIBasicType(name: "char", size: 8, encoding: DW_ATE_signed_char) +!91 = !DILocalVariable(name: "ao", scope: !78, file: !6, line: 40, type: !92) +!92 = !DIDerivedType(tag: DW_TAG_typedef, name: "ae", scope: !52, file: !6, line: 29, baseType: !93) +!93 = distinct !DICompositeType(tag: DW_TAG_class_type, name: "y >", scope: !52, file: !6, line: 20, size: 8, flags: DIFlagTypePassByReference | DIFlagNonTrivial, elements: !94, templateParams: !105, identifier: "_ZTSN2aa1yIP1jNS_2ac1zI1eEEEE") +!94 = !{!95, !99, !102} +!95 = !DISubprogram(name: "y", scope: !93, file: !6, line: 22, type: !96, scopeLine: 22, flags: DIFlagPublic | DIFlagPrototyped, spFlags: DISPFlagOptimized) +!96 = !DISubroutineType(types: !97) +!97 = !{null, !98, !14} +!98 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !93, size: 64, flags: DIFlagArtificial | DIFlagObjectPointer) +!99 = !DISubprogram(name: "~y", scope: !93, file: !6, line: 23, type: !100, scopeLine: 23, flags: DIFlagPublic | DIFlagPrototyped, spFlags: DISPFlagOptimized) +!100 = !DISubroutineType(types: !101) +!101 = !{null, !98} +!102 = !DISubprogram(name: "ab", linkageName: "_ZN2aa1yIP1jNS_2ac1zI1eEEE2abEv", scope: !93, file: !6, line: 24, type: !103, scopeLine: 24, flags: DIFlagPublic | DIFlagPrototyped, spFlags: DISPFlagOptimized) +!103 = !DISubroutineType(types: !104) +!104 = !{!14, !98} +!105 = !{!106, !107} +!106 = !DITemplateTypeParameter(name: "x", type: !14) +!107 = !DITemplateTypeParameter(type: !108) +!108 = !DICompositeType(tag: DW_TAG_structure_type, name: "z", scope: !109, file: !6, line: 27, flags: DIFlagFwdDecl, identifier: "_ZTSN2aa2ac1zI1eEE") +!109 = !DINamespace(name: "ac", scope: !52) +!110 = !DILocalVariable(name: "ap", scope: !78, file: !6, line: 41, type: !111) +!111 = !DIDerivedType(tag: DW_TAG_typedef, name: "ae", scope: !52, file: !6, line: 29, baseType: !112) +!112 = distinct !DICompositeType(tag: DW_TAG_class_type, name: "y >", scope: !52, file: !6, line: 20, size: 8, flags: DIFlagTypePassByReference | DIFlagNonTrivial, elements: !113, templateParams: !124, identifier: "_ZTSN2aa1yIP1hNS_2ac1zI1eEEEE") +!113 = !{!114, !118, !121} +!114 = !DISubprogram(name: "y", scope: !112, file: !6, line: 22, type: !115, scopeLine: 22, flags: DIFlagPublic | DIFlagPrototyped, spFlags: DISPFlagOptimized) +!115 = !DISubroutineType(types: !116) +!116 = !{null, !117, !27} +!117 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !112, size: 64, flags: DIFlagArtificial | DIFlagObjectPointer) +!118 = !DISubprogram(name: "~y", scope: !112, file: !6, line: 23, type: !119, scopeLine: 23, flags: DIFlagPublic | DIFlagPrototyped, spFlags: DISPFlagOptimized) +!119 = !DISubroutineType(types: !120) +!120 = !{null, !117} +!121 = !DISubprogram(name: "ab", linkageName: "_ZN2aa1yIP1hNS_2ac1zI1eEEE2abEv", scope: !112, file: !6, line: 24, type: !122, scopeLine: 24, flags: DIFlagPublic | DIFlagPrototyped, spFlags: DISPFlagOptimized) +!122 = !DISubroutineType(types: !123) +!123 = !{!27, !117} +!124 = !{!125, !107} +!125 = !DITemplateTypeParameter(name: "x", type: !27) +!126 = !DILocation(line: 0, scope: !78) +!127 = !DILocation(line: 40, column: 5, scope: !78) +!128 = !DILocation(line: 40, column: 11, scope: !78) +!129 = !DILocation(line: 40, column: 14, scope: !78) +!130 = !DILocation(line: 41, column: 5, scope: !78) +!131 = !DILocation(line: 41, column: 11, scope: !78) +!132 = !DILocation(line: 41, column: 16, scope: !78) +!133 = !{!134, !134, i64 0} +!134 = !{!"any pointer", !135, i64 0} +!135 = !{!"omnipotent char", !136, i64 0} +!136 = !{!"Simple C++ TBAA"} +!137 = !DILocation(line: 41, column: 14, scope: !78) +!138 = !DILocation(line: 42, column: 7, scope: !78) +!139 = !DILocation(line: 42, column: 23, scope: !78) +!140 = !DILocation(line: 42, column: 21, scope: !78) +!141 = !DILocation(line: 42, column: 32, scope: !78) +!142 = !DILocation(line: 42, column: 44, scope: !78) +!143 = !DILocation(line: 42, column: 70, scope: !78) +!144 = !{!145, !145, i64 0} +!145 = !{!"_ZTS1n", !135, i64 0} +!146 = !DILocation(line: 42, column: 5, scope: !78) +!147 = !DILocation(line: 43, column: 3, scope: !78) diff --git a/llvm/test/DebugInfo/debugify-each.ll b/llvm/test/DebugInfo/debugify-each.ll index e290b948cc76d..3fbb66d7d517b 100644 --- a/llvm/test/DebugInfo/debugify-each.ll +++ b/llvm/test/DebugInfo/debugify-each.ll @@ -18,19 +18,13 @@ ; Check that stripped textual IR compares equal before and after applying ; debugify. -; RUN: opt -O1 < %s -S -o - | \ -; RUN: opt -strip -strip-dead-prototypes -strip-named-metadata -S -o %t.before -; RUN: opt -O1 -debugify-each < %s -S -o - | \ -; RUN: opt -strip -strip-dead-prototypes -strip-named-metadata -S -o %t.after +; RUN: opt -O1 < %s -S -o %t.before +; RUN: opt -O1 -debugify-each < %s -S -o %t.after ; RUN: diff %t.before %t.after ; Check that stripped IR compares equal before and after applying debugify. -; RUN: opt -O1 < %s | \ -; RUN: opt -strip -strip-dead-prototypes -strip-named-metadata | \ -; RUN: llvm-dis -o %t.before -; RUN: opt -O1 -debugify-each < %s | \ -; RUN: opt -strip -strip-dead-prototypes -strip-named-metadata | \ -; RUN: llvm-dis -o %t.after +; RUN: opt -O1 < %s | llvm-dis -o %t.before +; RUN: opt -O1 -debugify-each < %s | llvm-dis -o %t.after ; RUN: diff %t.before %t.after define void @foo(i32 %arg) { diff --git a/llvm/test/Instrumentation/AddressSanitizer/hoist-argument-init-insts.ll b/llvm/test/Instrumentation/AddressSanitizer/hoist-argument-init-insts.ll new file mode 100644 index 0000000000000..1414b2122d983 --- /dev/null +++ b/llvm/test/Instrumentation/AddressSanitizer/hoist-argument-init-insts.ll @@ -0,0 +1,173 @@ +; RUN: opt < %s -asan -asan-module -asan-use-after-return -S | FileCheck %s + +; Source (-O0 -fsanitize=address -fsanitize-address-use-after-scope): +;; struct S { int x, y; }; +;; void swap(S *a, S *b, bool doit) { +;; if (!doit) +;; return; +;; auto tmp = *a; +;; *a = *b; +;; *b = tmp; +;; } + +target datalayout = "e-m:o-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128" +target triple = "x86_64-apple-macosx10.14.0" + +%struct.S = type { i32, i32 } + +; CHECK-LABEL: define {{.*}} @_Z4swapP1SS0_b( + +; First come the argument allocas. +; CHECK: [[argA:%.*]] = alloca %struct.S*, +; CHECK-NEXT: [[argB:%.*]] = alloca %struct.S*, +; CHECK-NEXT: [[argDoit:%.*]] = alloca i8, + +; Next, the stores into the argument allocas. +; CHECK-NEXT: store %struct.S* {{.*}}, %struct.S** [[argA]] +; CHECK-NEXT: store %struct.S* {{.*}}, %struct.S** [[argB]] +; CHECK-NEXT: [[frombool:%.*]] = zext i1 {{.*}} to i8 +; CHECK-NEXT: store i8 [[frombool]], i8* [[argDoit]] + +define void @_Z4swapP1SS0_b(%struct.S* %a, %struct.S* %b, i1 zeroext %doit) sanitize_address { +entry: + %a.addr = alloca %struct.S*, align 8 + %b.addr = alloca %struct.S*, align 8 + %doit.addr = alloca i8, align 1 + %tmp = alloca %struct.S, align 4 + store %struct.S* %a, %struct.S** %a.addr, align 8 + store %struct.S* %b, %struct.S** %b.addr, align 8 + %frombool = zext i1 %doit to i8 + store i8 %frombool, i8* %doit.addr, align 1 + %0 = load i8, i8* %doit.addr, align 1 + %tobool = trunc i8 %0 to i1 + br i1 %tobool, label %if.end, label %if.then + +if.then: ; preds = %entry + br label %return + +if.end: ; preds = %entry + %1 = load %struct.S*, %struct.S** %a.addr, align 8 + %2 = bitcast %struct.S* %tmp to i8* + %3 = bitcast %struct.S* %1 to i8* + call void @llvm.memcpy.p0i8.p0i8.i64(i8* align 4 %2, i8* align 4 %3, i64 8, i1 false) + %4 = load %struct.S*, %struct.S** %b.addr, align 8 + %5 = load %struct.S*, %struct.S** %a.addr, align 8 + %6 = bitcast %struct.S* %5 to i8* + %7 = bitcast %struct.S* %4 to i8* + call void @llvm.memcpy.p0i8.p0i8.i64(i8* align 4 %6, i8* align 4 %7, i64 8, i1 false) + %8 = load %struct.S*, %struct.S** %b.addr, align 8 + %9 = bitcast %struct.S* %8 to i8* + %10 = bitcast %struct.S* %tmp to i8* + call void @llvm.memcpy.p0i8.p0i8.i64(i8* align 4 %9, i8* align 4 %10, i64 8, i1 false) + br label %return + +return: ; preds = %if.end, %if.then + ret void +} + +; Synthetic test case, meant to check that we do not reorder instructions past +; a load when attempting to hoist argument init insts. +; CHECK-LABEL: define {{.*}} @func_with_load_in_arginit_sequence +; CHECK: [[argA:%.*]] = alloca %struct.S*, +; CHECK-NEXT: [[argB:%.*]] = alloca %struct.S*, +; CHECK-NEXT: [[argDoit:%.*]] = alloca i8, +; CHECK-NEXT: store %struct.S* {{.*}}, %struct.S** [[argA]] +; CHECK-NEXT: store %struct.S* {{.*}}, %struct.S** [[argB]] +; CHECK-NEXT: [[stack_base:%.*]] = alloca i64 +define void @func_with_load_in_arginit_sequence(%struct.S* %a, %struct.S* %b, i1 zeroext %doit) sanitize_address { +entry: + %a.addr = alloca %struct.S*, align 8 + %b.addr = alloca %struct.S*, align 8 + %doit.addr = alloca i8, align 1 + %tmp = alloca %struct.S, align 4 + store %struct.S* %a, %struct.S** %a.addr, align 8 + store %struct.S* %b, %struct.S** %b.addr, align 8 + + ; This load prevents the next argument init sequence from being moved. + %0 = load i8, i8* %doit.addr, align 1 + + %frombool = zext i1 %doit to i8 + store i8 %frombool, i8* %doit.addr, align 1 + %tobool = trunc i8 %0 to i1 + br i1 %tobool, label %if.end, label %if.then + +if.then: ; preds = %entry + br label %return + +if.end: ; preds = %entry + %1 = load %struct.S*, %struct.S** %a.addr, align 8 + %2 = bitcast %struct.S* %tmp to i8* + %3 = bitcast %struct.S* %1 to i8* + call void @llvm.memcpy.p0i8.p0i8.i64(i8* align 4 %2, i8* align 4 %3, i64 8, i1 false) + %4 = load %struct.S*, %struct.S** %b.addr, align 8 + %5 = load %struct.S*, %struct.S** %a.addr, align 8 + %6 = bitcast %struct.S* %5 to i8* + %7 = bitcast %struct.S* %4 to i8* + call void @llvm.memcpy.p0i8.p0i8.i64(i8* align 4 %6, i8* align 4 %7, i64 8, i1 false) + %8 = load %struct.S*, %struct.S** %b.addr, align 8 + %9 = bitcast %struct.S* %8 to i8* + %10 = bitcast %struct.S* %tmp to i8* + call void @llvm.memcpy.p0i8.p0i8.i64(i8* align 4 %9, i8* align 4 %10, i64 8, i1 false) + br label %return + +return: ; preds = %if.end, %if.then + ret void +} + +; Synthetic test case, meant to check that we can handle functions with more +; than one interesting alloca. +; CHECK-LABEL: define {{.*}} @func_with_multiple_interesting_allocas +; CHECK: [[argA:%.*]] = alloca %struct.S*, +; CHECK-NEXT: [[argB:%.*]] = alloca %struct.S*, +; CHECK-NEXT: [[argDoit:%.*]] = alloca i8, +; CHECK-NEXT: store %struct.S* {{.*}}, %struct.S** [[argA]] +; CHECK-NEXT: store %struct.S* {{.*}}, %struct.S** [[argB]] +; CHECK-NEXT: [[frombool:%.*]] = zext i1 {{.*}} to i8 +; CHECK-NEXT: store i8 [[frombool]], i8* [[argDoit]] +define void @func_with_multiple_interesting_allocas(%struct.S* %a, %struct.S* %b, i1 zeroext %doit) sanitize_address { +entry: + %a.addr = alloca %struct.S*, align 8 + %b.addr = alloca %struct.S*, align 8 + %doit.addr = alloca i8, align 1 + %tmp = alloca %struct.S, align 4 + %tmp2 = alloca %struct.S, align 4 + store %struct.S* %a, %struct.S** %a.addr, align 8 + store %struct.S* %b, %struct.S** %b.addr, align 8 + %frombool = zext i1 %doit to i8 + store i8 %frombool, i8* %doit.addr, align 1 + %0 = load i8, i8* %doit.addr, align 1 + %tobool = trunc i8 %0 to i1 + br i1 %tobool, label %if.end, label %if.then + +if.then: ; preds = %entry + br label %return + +if.end: ; preds = %entry + %1 = load %struct.S*, %struct.S** %a.addr, align 8 + %2 = bitcast %struct.S* %tmp to i8* + %3 = bitcast %struct.S* %1 to i8* + call void @llvm.memcpy.p0i8.p0i8.i64(i8* align 4 %2, i8* align 4 %3, i64 8, i1 false) + %4 = load %struct.S*, %struct.S** %b.addr, align 8 + %5 = bitcast %struct.S* %tmp2 to i8* + %6 = bitcast %struct.S* %4 to i8* + call void @llvm.memcpy.p0i8.p0i8.i64(i8* align 4 %5, i8* align 4 %6, i64 8, i1 false) + %7 = load %struct.S*, %struct.S** %b.addr, align 8 + %8 = load %struct.S*, %struct.S** %a.addr, align 8 + %9 = bitcast %struct.S* %8 to i8* + %10 = bitcast %struct.S* %7 to i8* + call void @llvm.memcpy.p0i8.p0i8.i64(i8* align 4 %9, i8* align 4 %10, i64 8, i1 false) + %11 = load %struct.S*, %struct.S** %b.addr, align 8 + %12 = bitcast %struct.S* %11 to i8* + %13 = bitcast %struct.S* %tmp to i8* + call void @llvm.memcpy.p0i8.p0i8.i64(i8* align 4 %12, i8* align 4 %13, i64 8, i1 false) + %14 = load %struct.S*, %struct.S** %a.addr, align 8 + %15 = bitcast %struct.S* %14 to i8* + %16 = bitcast %struct.S* %tmp2 to i8* + call void @llvm.memcpy.p0i8.p0i8.i64(i8* align 4 %15, i8* align 4 %16, i64 8, i1 false) + br label %return + +return: ; preds = %if.end, %if.then + ret void +} + +declare void @llvm.memcpy.p0i8.p0i8.i64(i8* noalias nocapture writeonly, i8* noalias nocapture readonly, i64, i1 immarg) diff --git a/llvm/test/Transforms/Coroutines/ArgAddr.ll b/llvm/test/Transforms/Coroutines/ArgAddr.ll index 5d0fbd781be96..83523763d9d94 100644 --- a/llvm/test/Transforms/Coroutines/ArgAddr.ll +++ b/llvm/test/Transforms/Coroutines/ArgAddr.ll @@ -1,6 +1,6 @@ ; Need to move users of allocas that were moved into the coroutine frame after ; coro.begin. -; RUN: opt < %s -O2 -enable-coroutines -S | FileCheck %s +; RUN: opt < %s -preserve-alignment-assumptions-during-inlining=false -O2 -enable-coroutines -S | FileCheck %s define nonnull i8* @f(i32 %n) { entry: diff --git a/llvm/test/Transforms/Coroutines/coro-alloc-with-param.ll b/llvm/test/Transforms/Coroutines/coro-alloc-with-param.ll index ce0975f108d8a..803c138d0bf59 100644 --- a/llvm/test/Transforms/Coroutines/coro-alloc-with-param.ll +++ b/llvm/test/Transforms/Coroutines/coro-alloc-with-param.ll @@ -52,18 +52,18 @@ suspend: } ; See if %this was added to the frame -; CHECK: %f_direct.Frame = type { void (%f_direct.Frame*)*, void (%f_direct.Frame*)*, i1, i1, i64 } -; CHECK: %f_copy.Frame = type { void (%f_copy.Frame*)*, void (%f_copy.Frame*)*, i1, i1, i64 } +; CHECK: %f_direct.Frame = type { void (%f_direct.Frame*)*, void (%f_direct.Frame*)*, i64, i1 } +; CHECK: %f_copy.Frame = type { void (%f_copy.Frame*)*, void (%f_copy.Frame*)*, i64, i1 } ; See that %this is spilled into the frame ; CHECK-LABEL: define i8* @f_direct(i64 %this) -; CHECK: %this.spill.addr = getelementptr inbounds %f_direct.Frame, %f_direct.Frame* %FramePtr, i32 0, i32 4 +; CHECK: %this.spill.addr = getelementptr inbounds %f_direct.Frame, %f_direct.Frame* %FramePtr, i32 0, i32 2 ; CHECK: store i64 %this, i64* %this.spill.addr ; CHECK: ret i8* %hdl ; See that %this is spilled into the frame ; CHECK-LABEL: define i8* @f_copy(i64 %this_arg) -; CHECK: %this.spill.addr = getelementptr inbounds %f_copy.Frame, %f_copy.Frame* %FramePtr, i32 0, i32 4 +; CHECK: %this.spill.addr = getelementptr inbounds %f_copy.Frame, %f_copy.Frame* %FramePtr, i32 0, i32 2 ; CHECK: store i64 %this_arg, i64* %this.spill.addr ; CHECK: ret i8* %hdl diff --git a/llvm/test/Transforms/Coroutines/coro-catchswitch.ll b/llvm/test/Transforms/Coroutines/coro-catchswitch.ll index dd06f1280caed..24ceb421cfe9a 100644 --- a/llvm/test/Transforms/Coroutines/coro-catchswitch.ll +++ b/llvm/test/Transforms/Coroutines/coro-catchswitch.ll @@ -31,7 +31,7 @@ catch.dispatch: ; preds = %if.else, %if.then ; CHECK: catch.dispatch: ; CHECK: %val = phi i32 [ 2, %if.else ], [ 1, %if.then ] ; CHECK: %[[Pad:.+]] = cleanuppad within none [] -; CHECK: %val.spill.addr = getelementptr inbounds %f.Frame, %f.Frame* %FramePtr, i32 0, i32 4 +; CHECK: %val.spill.addr = getelementptr inbounds %f.Frame, %f.Frame* %FramePtr, i32 0, i32 2 ; CHECK: store i32 %val, i32* %val.spill.addr ; CHECK: cleanupret from %[[Pad]] unwind label %[[Switch:.+]] diff --git a/llvm/test/Transforms/Coroutines/coro-debug.ll b/llvm/test/Transforms/Coroutines/coro-debug.ll index 1d40ddd671738..6f5e3ff887d11 100644 --- a/llvm/test/Transforms/Coroutines/coro-debug.ll +++ b/llvm/test/Transforms/Coroutines/coro-debug.ll @@ -127,9 +127,9 @@ attributes #7 = { noduplicate } !24 = !DILocation(line: 62, column: 3, scope: !6) ; CHECK: define i8* @f(i32 %x) #0 !dbg ![[ORIG:[0-9]+]] -; CHECK: define internal fastcc void @f.resume(%f.Frame* noalias nonnull %FramePtr) #0 !dbg ![[RESUME:[0-9]+]] -; CHECK: define internal fastcc void @f.destroy(%f.Frame* noalias nonnull %FramePtr) #0 !dbg ![[DESTROY:[0-9]+]] -; CHECK: define internal fastcc void @f.cleanup(%f.Frame* noalias nonnull %FramePtr) #0 !dbg ![[CLEANUP:[0-9]+]] +; CHECK: define internal fastcc void @f.resume(%f.Frame* noalias nonnull align 8 dereferenceable(32) %FramePtr) #0 !dbg ![[RESUME:[0-9]+]] +; CHECK: define internal fastcc void @f.destroy(%f.Frame* noalias nonnull align 8 dereferenceable(32) %FramePtr) #0 !dbg ![[DESTROY:[0-9]+]] +; CHECK: define internal fastcc void @f.cleanup(%f.Frame* noalias nonnull align 8 dereferenceable(32) %FramePtr) #0 !dbg ![[CLEANUP:[0-9]+]] ; CHECK: ![[ORIG]] = distinct !DISubprogram(name: "f", linkageName: "flink" ; CHECK: !DILocalVariable(name: "x", arg: 1, scope: ![[ORIG]] diff --git a/llvm/test/Transforms/Coroutines/coro-eh-aware-edge-split.ll b/llvm/test/Transforms/Coroutines/coro-eh-aware-edge-split.ll index 5da0e3c199db5..763025c1ac058 100644 --- a/llvm/test/Transforms/Coroutines/coro-eh-aware-edge-split.ll +++ b/llvm/test/Transforms/Coroutines/coro-eh-aware-edge-split.ll @@ -99,13 +99,13 @@ invoke2: ; CHECK: pad.with.phi.from.invoke2: ; CHECK: %0 = cleanuppad within none [] -; CHECK: %y.reload.addr = getelementptr inbounds %g.Frame, %g.Frame* %FramePtr, i32 0, i32 6 +; CHECK: %y.reload.addr = getelementptr inbounds %g.Frame, %g.Frame* %FramePtr, i32 0, i32 3 ; CHECK: %y.reload = load i32, i32* %y.reload.addr ; CHECK: cleanupret from %0 unwind label %pad.with.phi ; CHECK: pad.with.phi.from.invoke1: ; CHECK: %1 = cleanuppad within none [] -; CHECK: %x.reload.addr = getelementptr inbounds %g.Frame, %g.Frame* %FramePtr, i32 0, i32 5 +; CHECK: %x.reload.addr = getelementptr inbounds %g.Frame, %g.Frame* %FramePtr, i32 0, i32 2 ; CHECK: %x.reload = load i32, i32* %x.reload.addr ; CHECK: cleanupret from %1 unwind label %pad.with.phi @@ -161,13 +161,13 @@ invoke2: ; CHECK: pad.with.phi.from.invoke2: ; CHECK: %0 = cleanuppad within none [] -; CHECK: %y.reload.addr = getelementptr inbounds %h.Frame, %h.Frame* %FramePtr, i32 0, i32 6 +; CHECK: %y.reload.addr = getelementptr inbounds %h.Frame, %h.Frame* %FramePtr, i32 0, i32 3 ; CHECK: %y.reload = load i32, i32* %y.reload.addr ; CHECK: cleanupret from %0 unwind label %pad.with.phi ; CHECK: pad.with.phi.from.invoke1: ; CHECK: %1 = cleanuppad within none [] -; CHECK: %x.reload.addr = getelementptr inbounds %h.Frame, %h.Frame* %FramePtr, i32 0, i32 5 +; CHECK: %x.reload.addr = getelementptr inbounds %h.Frame, %h.Frame* %FramePtr, i32 0, i32 2 ; CHECK: %x.reload = load i32, i32* %x.reload.addr ; CHECK: cleanupret from %1 unwind label %pad.with.phi diff --git a/llvm/test/Transforms/Coroutines/coro-frame-arrayalloca.ll b/llvm/test/Transforms/Coroutines/coro-frame-arrayalloca.ll index d01120e379cec..e682b4e6726a3 100644 --- a/llvm/test/Transforms/Coroutines/coro-frame-arrayalloca.ll +++ b/llvm/test/Transforms/Coroutines/coro-frame-arrayalloca.ll @@ -35,13 +35,13 @@ suspend: } ; See if the array alloca was stored as an array field. -; CHECK-LABEL: %f.Frame = type { void (%f.Frame*)*, void (%f.Frame*)*, i1, i1, double, [4 x i32], double } +; CHECK-LABEL: %f.Frame = type { void (%f.Frame*)*, void (%f.Frame*)*, double, double, [4 x i32], i1 } ; See if we used correct index to access prefix, data, suffix (@f) ; CHECK-LABEL: @f( -; CHECK: %prefix = getelementptr inbounds %f.Frame, %f.Frame* %FramePtr, i32 0, i32 4 -; CHECK-NEXT: %data = getelementptr inbounds %f.Frame, %f.Frame* %FramePtr, i32 0, i32 5 -; CHECK-NEXT: %suffix = getelementptr inbounds %f.Frame, %f.Frame* %FramePtr, i32 0, i32 6 +; CHECK: %prefix = getelementptr inbounds %f.Frame, %f.Frame* %FramePtr, i32 0, i32 2 +; CHECK-NEXT: %data = getelementptr inbounds %f.Frame, %f.Frame* %FramePtr, i32 0, i32 4 +; CHECK-NEXT: %suffix = getelementptr inbounds %f.Frame, %f.Frame* %FramePtr, i32 0, i32 3 ; CHECK-NEXT: call void @consume.double.ptr(double* %prefix) ; CHECK-NEXT: call void @consume.i32.ptr(i32* %data) ; CHECK-NEXT: call void @consume.double.ptr(double* %suffix) @@ -49,9 +49,9 @@ suspend: ; See if we used correct index to access prefix, data, suffix (@f.resume) ; CHECK-LABEL: @f.resume( -; CHECK: %[[SUFFIX:.+]] = getelementptr inbounds %f.Frame, %f.Frame* %FramePtr, i32 0, i32 6 -; CHECK: %[[DATA:.+]] = getelementptr inbounds %f.Frame, %f.Frame* %FramePtr, i32 0, i32 5 -; CHECK: %[[PREFIX:.+]] = getelementptr inbounds %f.Frame, %f.Frame* %FramePtr, i32 0, i32 4 +; CHECK: %[[SUFFIX:.+]] = getelementptr inbounds %f.Frame, %f.Frame* %FramePtr, i32 0, i32 3 +; CHECK: %[[DATA:.+]] = getelementptr inbounds %f.Frame, %f.Frame* %FramePtr, i32 0, i32 4 +; CHECK: %[[PREFIX:.+]] = getelementptr inbounds %f.Frame, %f.Frame* %FramePtr, i32 0, i32 2 ; CHECK: call void @consume.double.ptr(double* %[[PREFIX]]) ; CHECK-NEXT: call void @consume.i32.ptr(i32* %[[DATA]]) ; CHECK-NEXT: call void @consume.double.ptr(double* %[[SUFFIX]]) diff --git a/llvm/test/Transforms/Coroutines/coro-frame.ll b/llvm/test/Transforms/Coroutines/coro-frame.ll index 826d3a04fa1e1..9d1ee9ab30fe0 100644 --- a/llvm/test/Transforms/Coroutines/coro-frame.ll +++ b/llvm/test/Transforms/Coroutines/coro-frame.ll @@ -34,17 +34,17 @@ pad: } ; See if the float was added to the frame -; CHECK-LABEL: %f.Frame = type { void (%f.Frame*)*, void (%f.Frame*)*, i1, i1, i64, double } +; CHECK-LABEL: %f.Frame = type { void (%f.Frame*)*, void (%f.Frame*)*, double, i64, i1 } ; See if the float was spilled into the frame ; CHECK-LABEL: @f( ; CHECK: %r = call double @print( -; CHECK: %r.spill.addr = getelementptr inbounds %f.Frame, %f.Frame* %FramePtr, i32 0, i32 5 +; CHECK: %r.spill.addr = getelementptr inbounds %f.Frame, %f.Frame* %FramePtr, i32 0, i32 2 ; CHECK: store double %r, double* %r.spill.addr ; CHECK: ret i8* %hdl -; See of the float was loaded from the frame -; CHECK-LABEL: @f.resume( +; See if the float was loaded from the frame +; CHECK-LABEL: @f.resume(%f.Frame* noalias nonnull align 8 ; CHECK: %r.reload = load double, double* %r.reload.addr ; CHECK: call double @print(double %r.reload) ; CHECK: ret void diff --git a/llvm/test/Transforms/Coroutines/coro-heap-elide.ll b/llvm/test/Transforms/Coroutines/coro-heap-elide.ll index 5ce2b693bc5e5..5696a4f387d0e 100644 --- a/llvm/test/Transforms/Coroutines/coro-heap-elide.ll +++ b/llvm/test/Transforms/Coroutines/coro-heap-elide.ll @@ -54,7 +54,7 @@ if.end: ; CHECK-LABEL: @callResume( define void @callResume() { entry: -; CHECK: alloca %f.frame +; CHECK: alloca [4 x i8], align 4 ; CHECK-NOT: coro.begin ; CHECK-NOT: CustomAlloc ; CHECK: call void @may_throw() diff --git a/llvm/test/Transforms/Coroutines/coro-materialize.ll b/llvm/test/Transforms/Coroutines/coro-materialize.ll index 95e8a049ad2f6..c17c525272721 100644 --- a/llvm/test/Transforms/Coroutines/coro-materialize.ll +++ b/llvm/test/Transforms/Coroutines/coro-materialize.ll @@ -33,7 +33,7 @@ suspend: } ; See that we only spilled one value -; CHECK: %f.Frame = type { void (%f.Frame*)*, void (%f.Frame*)*, i1, i1, i32 } +; CHECK: %f.Frame = type { void (%f.Frame*)*, void (%f.Frame*)*, i32, i1 } ; CHECK-LABEL: @f( declare i8* @llvm.coro.free(token, i8*) diff --git a/llvm/test/Transforms/Coroutines/coro-padding.ll b/llvm/test/Transforms/Coroutines/coro-padding.ll index 87b5bf732d9df..b912a28afa923 100644 --- a/llvm/test/Transforms/Coroutines/coro-padding.ll +++ b/llvm/test/Transforms/Coroutines/coro-padding.ll @@ -8,7 +8,7 @@ declare void @consume(%PackedStruct*) define i8* @f() "coroutine.presplit"="1" { entry: - %data = alloca %PackedStruct, align 8 + %data = alloca %PackedStruct, align 32 %id = call token @llvm.coro.id(i32 0, i8* null, i8* null, i8* null) %size = call i32 @llvm.coro.size.i32() %alloc = call i8* @malloc(i32 %size) @@ -31,17 +31,17 @@ suspend: } ; See if the padding was inserted before PackedStruct -; CHECK-LABEL: %f.Frame = type { void (%f.Frame*)*, void (%f.Frame*)*, i1, i1, [6 x i8], %PackedStruct } +; CHECK-LABEL: %f.Frame = type { void (%f.Frame*)*, void (%f.Frame*)*, i1, [15 x i8], %PackedStruct } -; See if we used correct index to access packed struct (padding is field 4) +; See if we used correct index to access packed struct (padding is field 3) ; CHECK-LABEL: @f( -; CHECK: %[[DATA:.+]] = getelementptr inbounds %f.Frame, %f.Frame* %FramePtr, i32 0, i32 5 +; CHECK: %[[DATA:.+]] = getelementptr inbounds %f.Frame, %f.Frame* %FramePtr, i32 0, i32 4 ; CHECK-NEXT: call void @consume(%PackedStruct* %[[DATA]]) ; CHECK: ret i8* -; See if we used correct index to access packed struct (padding is field 4) +; See if we used correct index to access packed struct (padding is field 3) ; CHECK-LABEL: @f.resume( -; CHECK: %[[DATA:.+]] = getelementptr inbounds %f.Frame, %f.Frame* %FramePtr, i32 0, i32 5 +; CHECK: %[[DATA:.+]] = getelementptr inbounds %f.Frame, %f.Frame* %FramePtr, i32 0, i32 4 ; CHECK-NEXT: call void @consume(%PackedStruct* %[[DATA]]) ; CHECK: ret void diff --git a/llvm/test/Transforms/Coroutines/coro-param-copy.ll b/llvm/test/Transforms/Coroutines/coro-param-copy.ll index 6f4d0f3b22484..d075e8a964ce9 100644 --- a/llvm/test/Transforms/Coroutines/coro-param-copy.ll +++ b/llvm/test/Transforms/Coroutines/coro-param-copy.ll @@ -32,7 +32,7 @@ suspend: } ; See that we added both x and y to the frame. -; CHECK: %f.Frame = type { void (%f.Frame*)*, void (%f.Frame*)*, i1, i1, i64, i64 } +; CHECK: %f.Frame = type { void (%f.Frame*)*, void (%f.Frame*)*, i64, i64, i1 } ; See that all of the uses prior to coro-begin stays put. ; CHECK-LABEL: define i8* @f() { @@ -45,10 +45,10 @@ suspend: ; See that we only copy the x as y was not modified prior to coro.begin. ; CHECK: store void (%f.Frame*)* @f.destroy, void (%f.Frame*)** %destroy.addr -; CHECK-NEXT: %0 = getelementptr inbounds %f.Frame, %f.Frame* %FramePtr, i32 0, i32 4 +; CHECK-NEXT: %0 = getelementptr inbounds %f.Frame, %f.Frame* %FramePtr, i32 0, i32 2 ; CHECK-NEXT: %1 = load i64, i64* %x.addr ; CHECK-NEXT: store i64 %1, i64* %0 -; CHECK-NEXT: %index.addr1 = getelementptr inbounds %f.Frame, %f.Frame* %FramePtr, i32 0, i32 3 +; CHECK-NEXT: %index.addr1 = getelementptr inbounds %f.Frame, %f.Frame* %FramePtr, i32 0, i32 4 ; CHECK-NEXT: store i1 false, i1* %index.addr1 ; CHECK-NEXT: ret i8* %hdl diff --git a/llvm/test/Transforms/Coroutines/coro-retcon-alloca.ll b/llvm/test/Transforms/Coroutines/coro-retcon-alloca.ll index 17aec4eed1b23..61c21324d94a2 100644 --- a/llvm/test/Transforms/Coroutines/coro-retcon-alloca.ll +++ b/llvm/test/Transforms/Coroutines/coro-retcon-alloca.ll @@ -28,21 +28,20 @@ cleanup: ; CHECK-LABEL: define { i8*, i8*, i32 } @f(i8* %buffer, i32 %n) ; CHECK-NEXT: entry: -; CHECK-NEXT: [[T0:%.*]] = bitcast i8* %buffer to i32* -; CHECK-NEXT: store i32 %n, i32* [[T0]], align 4 -; CHECK-NEXT: [[ALLOC:%.*]] = tail call i8* @allocate(i32 %n) ; CHECK-NEXT: [[T0:%.*]] = getelementptr inbounds i8, i8* %buffer, i64 8 -; CHECK-NEXT: [[T1:%.*]] = bitcast i8* [[T0]] to i8** +; CHECK-NEXT: [[T1:%.*]] = bitcast i8* [[T0]] to i32* +; CHECK-NEXT: store i32 %n, i32* [[T1]], align 4 +; CHECK-NEXT: [[ALLOC:%.*]] = tail call i8* @allocate(i32 %n) +; CHECK-NEXT: [[T1:%.*]] = bitcast i8* %buffer to i8** ; CHECK-NEXT: store i8* [[ALLOC]], i8** [[T1]], align 8 ; CHECK-NEXT: [[T0:%.*]] = insertvalue { i8*, i8*, i32 } { i8* bitcast ({ i8*, i8*, i32 } (i8*, i1)* @f.resume.0 to i8*), i8* undef, i32 undef }, i8* [[ALLOC]], 1 ; CHECK-NEXT: [[RET:%.*]] = insertvalue { i8*, i8*, i32 } [[T0]], i32 %n, 2 ; CHECK-NEXT: ret { i8*, i8*, i32 } [[RET]] ; CHECK-NEXT: } -; CHECK-LABEL: define internal { i8*, i8*, i32 } @f.resume.0(i8* noalias nonnull %0, i1 %1) +; CHECK-LABEL: define internal { i8*, i8*, i32 } @f.resume.0(i8* noalias nonnull align 8 dereferenceable(1024) %0, i1 %1) ; CHECK-NEXT: : -; CHECK-NEXT: [[T0:%.*]] = getelementptr inbounds i8, i8* %0, i64 8 -; CHECK-NEXT: [[T1:%.*]] = bitcast i8* [[T0]] to i8** +; CHECK-NEXT: [[T1:%.*]] = bitcast i8* %0 to i8** ; CHECK-NEXT: [[ALLOC:%.*]] = load i8*, i8** [[T1]], align 8 ; CHECK-NEXT: tail call void @deallocate(i8* [[ALLOC]]) ; CHECK-NEXT: br i1 %1, @@ -83,14 +82,14 @@ cleanup: ; CHECK-NEXT: ret { i8*, i32 } [[RET]] ; CHECK-NEXT: } -; CHECK-LABEL: define internal { i8*, i32 } @g.resume.0(i8* noalias nonnull %0, i1 %1) +; CHECK-LABEL: define internal { i8*, i32 } @g.resume.0(i8* noalias nonnull align 8 dereferenceable(1024) %0, i1 %1) ; CHECK-NEXT: : ; CHECK-NEXT: br i1 %1, ; CHECK: : ; CHECK-NEXT: [[T0:%.*]] = bitcast i8* %0 to i32* -; CHECK-NEXT: [[T1:%.*]] = load i32, i32* [[T0]], align 4 +; CHECK-NEXT: [[T1:%.*]] = load i32, i32* [[T0]], align 8 ; CHECK-NEXT: %inc = add i32 [[T1]], 1 -; CHECK-NEXT: store i32 %inc, i32* [[T0]], align 4 +; CHECK-NEXT: store i32 %inc, i32* [[T0]], align 8 ; CHECK-NEXT: [[T0:%.*]] = zext i32 %inc to i64 ; CHECK-NEXT: [[ALLOC:%.*]] = alloca i8, i64 [[T0]], align 8 ; CHECK-NEXT: call void @use(i8* nonnull [[ALLOC]]) @@ -132,17 +131,17 @@ cleanup: ; CHECK-NEXT: ret { i8*, i32 } [[RET]] ; CHECK-NEXT: } -; CHECK-LABEL: define internal { i8*, i32 } @h.resume.0(i8* noalias nonnull %0, i1 %1) +; CHECK-LABEL: define internal { i8*, i32 } @h.resume.0(i8* noalias nonnull align 8 dereferenceable(1024) %0, i1 %1) ; CHECK-NEXT: : ; CHECK-NEXT: br i1 %1, ; CHECK: : ; CHECK-NEXT: [[NSLOT:%.*]] = bitcast i8* %0 to i32* -; CHECK-NEXT: [[T1:%.*]] = load i32, i32* [[NSLOT]], align 4 +; CHECK-NEXT: [[T1:%.*]] = load i32, i32* [[NSLOT]], align 8 ; CHECK-NEXT: %inc = add i32 [[T1]], 1 ; CHECK-NEXT: [[T0:%.*]] = zext i32 %inc to i64 ; CHECK-NEXT: [[ALLOC:%.*]] = alloca i8, i64 [[T0]], align 8 ; CHECK-NEXT: call void @use(i8* nonnull [[ALLOC]]) -; CHECK-NEXT: store i32 %inc, i32* [[NSLOT]], align 4 +; CHECK-NEXT: store i32 %inc, i32* [[NSLOT]], align 8 ; CHECK-NEXT: [[RET:%.*]] = insertvalue { i8*, i32 } { i8* bitcast ({ i8*, i32 } (i8*, i1)* @h.resume.0 to i8*), i32 undef }, i32 %inc, 1 ; CHECK-NEXT: ret { i8*, i32 } [[RET]] ; CHECK: : @@ -180,14 +179,14 @@ loop2: ; CHECK-NEXT: ret { i8*, i32 } [[RET]] ; CHECK-NEXT: } -; CHECK-LABEL: define internal { i8*, i32 } @i.resume.0(i8* noalias nonnull %0) +; CHECK-LABEL: define internal { i8*, i32 } @i.resume.0(i8* noalias nonnull align 8 dereferenceable(1024) %0) ; CHECK-NEXT: : ; CHECK-NEXT: [[NSLOT:%.*]] = bitcast i8* %0 to i32* -; CHECK-NEXT: [[T1:%.*]] = load i32, i32* [[NSLOT]], align 4 +; CHECK-NEXT: [[T1:%.*]] = load i32, i32* [[NSLOT]], align 8 ; CHECK-NEXT: %inc = add i32 [[T1]], 1 ; CHECK-NEXT: br label %loop2 ; CHECK: : -; CHECK-NEXT: store i32 %k, i32* [[NSLOT]], align 4 +; CHECK-NEXT: store i32 %k, i32* [[NSLOT]], align 8 ; CHECK-NEXT: [[RET:%.*]] = insertvalue { i8*, i32 } { i8* bitcast ({ i8*, i32 } (i8*)* @i.resume.0 to i8*), i32 undef }, i32 %k, 1 ; CHECK-NEXT: ret { i8*, i32 } [[RET]] ; CHECK: loop2: diff --git a/llvm/test/Transforms/Coroutines/coro-retcon-once-value.ll b/llvm/test/Transforms/Coroutines/coro-retcon-once-value.ll index ac49b22ee6bb9..6e80da87bc09f 100644 --- a/llvm/test/Transforms/Coroutines/coro-retcon-once-value.ll +++ b/llvm/test/Transforms/Coroutines/coro-retcon-once-value.ll @@ -45,7 +45,7 @@ cleanup: ; CHECK-NEXT: ret { i8*, i32 } [[T1]] ; CHECK-NEXT: } -; CHECK-LABEL: define internal void @f.resume.0(i8* noalias nonnull %0, i1 zeroext %1) +; CHECK-LABEL: define internal void @f.resume.0(i8* noalias nonnull align 8 dereferenceable(8) %0, i1 zeroext %1) ; CHECK-NEXT: : ; CHECK-NEXT: br i1 %1, ; CHECK: : @@ -57,7 +57,7 @@ cleanup: ; CHECK-NEXT: ret void ; CHECK-NEXT: } -; CHECK-LABEL: define internal void @f.resume.1(i8* noalias nonnull %0, i1 zeroext %1) +; CHECK-LABEL: define internal void @f.resume.1(i8* noalias nonnull align 8 dereferenceable(8) %0, i1 zeroext %1) ; CHECK-NEXT: : ; CHECK-NEXT: br i1 %1, ; CHECK: : diff --git a/llvm/test/Transforms/Coroutines/coro-retcon-once-value2.ll b/llvm/test/Transforms/Coroutines/coro-retcon-once-value2.ll index ad49f24dc547a..4f43da03550c8 100644 --- a/llvm/test/Transforms/Coroutines/coro-retcon-once-value2.ll +++ b/llvm/test/Transforms/Coroutines/coro-retcon-once-value2.ll @@ -37,7 +37,7 @@ cleanup: ; CHECK-NEXT: ret { i8*, i32* } [[T0]] ; CHECK-NEXT: } -; CHECK-LABEL: define internal void @f.resume.0(i8* noalias nonnull %0, i1 zeroext %1) +; CHECK-LABEL: define internal void @f.resume.0(i8* noalias nonnull align 8 dereferenceable(8) %0, i1 zeroext %1) ; CHECK-NEXT: : ; CHECK-NEXT: [[T0:%.*]] = bitcast i8* %0 to [[FRAME_T:%.*]]** ; CHECK-NEXT: [[FRAME:%.*]] = load [[FRAME_T]]*, [[FRAME_T]]** [[T0]] diff --git a/llvm/test/Transforms/Coroutines/coro-retcon-resume-values.ll b/llvm/test/Transforms/Coroutines/coro-retcon-resume-values.ll index ac99dd15b9882..80e8170d7ba1e 100644 --- a/llvm/test/Transforms/Coroutines/coro-retcon-resume-values.ll +++ b/llvm/test/Transforms/Coroutines/coro-retcon-resume-values.ll @@ -30,7 +30,7 @@ cleanup: ; CHECK-NEXT: ret i8* bitcast (i8* (i8*, i32, i1)* @f.resume.0 to i8*) ; CHECK-NEXT: } -; CHECK-LABEL: define internal i8* @f.resume.0(i8* noalias nonnull %0, i32 %1, i1 zeroext %2) +; CHECK-LABEL: define internal i8* @f.resume.0(i8* noalias nonnull align 4 dereferenceable(8) %0, i32 %1, i1 zeroext %2) ; CHECK-NEXT: : ; CHECK-NEXT: [[T0:%.*]] = bitcast i8* %0 to i32* ; CHECK-NEXT: [[T1:%.*]] = load i32, i32* [[T0]], align 4 diff --git a/llvm/test/Transforms/Coroutines/coro-retcon-resume-values2.ll b/llvm/test/Transforms/Coroutines/coro-retcon-resume-values2.ll index 43f98e958aab3..e2412b6b8a5a3 100644 --- a/llvm/test/Transforms/Coroutines/coro-retcon-resume-values2.ll +++ b/llvm/test/Transforms/Coroutines/coro-retcon-resume-values2.ll @@ -29,7 +29,7 @@ entry: ; CHECK-NEXT: ret i8* bitcast (i8* (i8*, i32)* @f.resume.0 to i8*) ; CHECK-NEXT: } -; CHECK-LABEL: define internal i8* @f.resume.0(i8* noalias nonnull %0, i32 %1) +; CHECK-LABEL: define internal i8* @f.resume.0(i8* noalias nonnull align 4 dereferenceable(8) %0, i32 %1) ; CHECK-NEXT: : ; CHECK-NEXT: [[T0:%.*]] = bitcast i8* %0 to [[FRAME_T:%.*]]** ; CHECK-NEXT: [[FRAME:%.*]] = load [[FRAME_T]]*, [[FRAME_T]]** [[T0]] @@ -45,7 +45,7 @@ entry: ; CHECK-NEXT: ret i8* [[CONT]] ; CHECK-NEXT: } -; CHECK-LABEL: define internal i8* @f.resume.1(i8* noalias nonnull %0, i32 %1) +; CHECK-LABEL: define internal i8* @f.resume.1(i8* noalias nonnull align 4 dereferenceable(8) %0, i32 %1) ; CHECK-NEXT: : ; CHECK-NEXT: [[T0:%.*]] = bitcast i8* %0 to [[FRAME_T:%.*]]** ; CHECK-NEXT: [[FRAME:%.*]] = load [[FRAME_T]]*, [[FRAME_T]]** [[T0]] @@ -64,7 +64,7 @@ entry: ; CHECK-NEXT: ret i8* [[CONT]] ; CHECK-NEXT: } -; CHECK-LABEL: define internal i8* @f.resume.2(i8* noalias nonnull %0, i32 %1) +; CHECK-LABEL: define internal i8* @f.resume.2(i8* noalias nonnull align 4 dereferenceable(8) %0, i32 %1) ; CHECK-NEXT: : ; CHECK-NEXT: [[T0:%.*]] = bitcast i8* %0 to [[FRAME_T:%.*]]** ; CHECK-NEXT: [[FRAME:%.*]] = load [[FRAME_T]]*, [[FRAME_T]]** [[T0]] diff --git a/llvm/test/Transforms/Coroutines/coro-retcon-value.ll b/llvm/test/Transforms/Coroutines/coro-retcon-value.ll index cfda73bbe754a..29ec7cda170f2 100644 --- a/llvm/test/Transforms/Coroutines/coro-retcon-value.ll +++ b/llvm/test/Transforms/Coroutines/coro-retcon-value.ll @@ -30,7 +30,7 @@ cleanup: ; CHECK-NEXT: ret { i8*, i32 } [[RET]] ; CHECK-NEXT: } -; CHECK-LABEL: define internal { i8*, i32 } @f.resume.0(i8* noalias nonnull %0, i8 zeroext %1) +; CHECK-LABEL: define internal { i8*, i32 } @f.resume.0(i8* noalias nonnull align 4 dereferenceable(8) %0, i8 zeroext %1) ; CHECK-NEXT: : ; CHECK-NEXT: [[T0:%.*]] = icmp eq i8 %1, 0 ; CHECK-NEXT: br i1 [[T0]], diff --git a/llvm/test/Transforms/Coroutines/coro-retcon.ll b/llvm/test/Transforms/Coroutines/coro-retcon.ll index 5cd4cb61d94cc..13283f05b2661 100644 --- a/llvm/test/Transforms/Coroutines/coro-retcon.ll +++ b/llvm/test/Transforms/Coroutines/coro-retcon.ll @@ -30,7 +30,7 @@ cleanup: ; CHECK-NEXT: ret i8* bitcast (i8* (i8*, i1)* @f.resume.0 to i8*) ; CHECK-NEXT: } -; CHECK-LABEL: define internal i8* @f.resume.0(i8* noalias nonnull %0, i1 zeroext %1) +; CHECK-LABEL: define internal i8* @f.resume.0(i8* noalias nonnull align 4 dereferenceable(8) %0, i1 zeroext %1) ; CHECK-NEXT: : ; CHECK-NEXT: br i1 %1, ; CHECK: : diff --git a/llvm/test/Transforms/Coroutines/coro-spill-after-phi.ll b/llvm/test/Transforms/Coroutines/coro-spill-after-phi.ll index 3c7e050c09e95..463705f3b3f3b 100644 --- a/llvm/test/Transforms/Coroutines/coro-spill-after-phi.ll +++ b/llvm/test/Transforms/Coroutines/coro-spill-after-phi.ll @@ -33,14 +33,14 @@ suspend: } ; Verifies that the both phis are stored correctly in the coroutine frame -; CHECK: %f.Frame = type { void (%f.Frame*)*, void (%f.Frame*)*, i1, i1, i32, i32 } +; CHECK: %f.Frame = type { void (%f.Frame*)*, void (%f.Frame*)*, i32, i32, i1 } ; CHECK-LABEL: @f( ; CHECK: store void (%f.Frame*)* @f.destroy, void (%f.Frame*)** %destroy.addr ; CHECK: %phi1 = select i1 %n, i32 0, i32 2 ; CHECK: %phi2 = select i1 %n, i32 1, i32 3 -; CHECK: %phi2.spill.addr = getelementptr inbounds %f.Frame, %f.Frame* %FramePtr, i32 0, i32 5 +; CHECK: %phi2.spill.addr = getelementptr inbounds %f.Frame, %f.Frame* %FramePtr, i32 0, i32 3 ; CHECK: store i32 %phi2, i32* %phi2.spill.addr -; CHECK: %phi1.spill.addr = getelementptr inbounds %f.Frame, %f.Frame* %FramePtr, i32 0, i32 4 +; CHECK: %phi1.spill.addr = getelementptr inbounds %f.Frame, %f.Frame* %FramePtr, i32 0, i32 2 ; CHECK: store i32 %phi1, i32* %phi1.spill.addr ; CHECK: ret i8* %hdl diff --git a/llvm/test/Transforms/Coroutines/coro-spill-corobegin.ll b/llvm/test/Transforms/Coroutines/coro-spill-corobegin.ll index e57e2f28ed3c2..299de76c5c427 100644 --- a/llvm/test/Transforms/Coroutines/coro-spill-corobegin.ll +++ b/llvm/test/Transforms/Coroutines/coro-spill-corobegin.ll @@ -37,18 +37,18 @@ suspend: } ; See if the i8* for coro.begin was added to f.Frame -; CHECK-LABEL: %f.Frame = type { void (%f.Frame*)*, void (%f.Frame*)*, i1, i1, i8* } +; CHECK-LABEL: %f.Frame = type { void (%f.Frame*)*, void (%f.Frame*)*, i8*, i1 } ; See if the g's coro.begin was spilled into the frame ; CHECK-LABEL: @f( ; CHECK: %innerid = call token @llvm.coro.id(i32 0, i8* null, i8* null, i8* bitcast ([3 x void (%g.Frame*)*]* @g.resumers to i8*)) ; CHECK: %innerhdl = call noalias nonnull i8* @llvm.coro.begin(token %innerid, i8* null) -; CHECK: %[[spilladdr:.+]] = getelementptr inbounds %f.Frame, %f.Frame* %FramePtr, i32 0, i32 4 +; CHECK: %[[spilladdr:.+]] = getelementptr inbounds %f.Frame, %f.Frame* %FramePtr, i32 0, i32 2 ; CHECK: store i8* %innerhdl, i8** %[[spilladdr]] ; See if the coro.begin was loaded from the frame ; CHECK-LABEL: @f.resume( -; CHECK: %[[innerhdlAddr:.+]] = getelementptr inbounds %f.Frame, %f.Frame* %{{.+}}, i32 0, i32 4 +; CHECK: %[[innerhdlAddr:.+]] = getelementptr inbounds %f.Frame, %f.Frame* %{{.+}}, i32 0, i32 2 ; CHECK: %[[innerhdl:.+]] = load i8*, i8** %[[innerhdlAddr]] ; CHECK: %[[gframe:.+]] = bitcast i8* %[[innerhdl]] to %g.Frame* ; CHECK: %[[gvarAddr:.+]] = getelementptr inbounds %g.Frame, %g.Frame* %[[gframe]], i32 0, i32 4 diff --git a/llvm/test/Transforms/Coroutines/coro-swifterror.ll b/llvm/test/Transforms/Coroutines/coro-swifterror.ll index 932e448a57193..7390bb77ca9b6 100644 --- a/llvm/test/Transforms/Coroutines/coro-swifterror.ll +++ b/llvm/test/Transforms/Coroutines/coro-swifterror.ll @@ -40,7 +40,7 @@ cleanup: ; CHECK-NEXT: ret i8* bitcast (i8* (i8*, i1, i8**)* @f.resume.0 to i8*) ; CHECK-NEXT: } -; CHECK-LABEL: define internal i8* @f.resume.0(i8* noalias nonnull %0, i1 zeroext %1, i8** swifterror %2) +; CHECK-LABEL: define internal i8* @f.resume.0(i8* noalias nonnull align 4 dereferenceable(8) %0, i1 zeroext %1, i8** swifterror %2) ; CHECK-NEXT: : ; CHECK-NEXT: br i1 %1, ; CHECK: : @@ -102,7 +102,7 @@ cleanup: ; CHECK-NEXT: ret i8* bitcast (i8* (i8*, i1)* @g.resume.0 to i8*) ; CHECK-NEXT: } -; CHECK-LABEL: define internal i8* @g.resume.0(i8* noalias nonnull %0, i1 zeroext %1) +; CHECK-LABEL: define internal i8* @g.resume.0(i8* noalias nonnull align 4 dereferenceable(8) %0, i1 zeroext %1) ; CHECK-NEXT: : ; CHECK-NEXT: [[ERRORSLOT:%.*]] = alloca swifterror i8*, align 4 ; CHECK-NEXT: br i1 %1, diff --git a/llvm/test/Transforms/Coroutines/ex0.ll b/llvm/test/Transforms/Coroutines/ex0.ll index 59bebc5466490..64f87065cc816 100644 --- a/llvm/test/Transforms/Coroutines/ex0.ll +++ b/llvm/test/Transforms/Coroutines/ex0.ll @@ -1,5 +1,5 @@ ; First example from Doc/Coroutines.rst (two block loop) -; RUN: opt < %s -enable-coroutines -O2 -S | FileCheck %s +; RUN: opt < %s -enable-coroutines -O2 -preserve-alignment-assumptions-during-inlining=false -S | FileCheck %s define i8* @f(i32 %n) { entry: diff --git a/llvm/test/Transforms/Coroutines/ex1.ll b/llvm/test/Transforms/Coroutines/ex1.ll index c2a5586fde584..f51da69ee3fcd 100644 --- a/llvm/test/Transforms/Coroutines/ex1.ll +++ b/llvm/test/Transforms/Coroutines/ex1.ll @@ -1,5 +1,5 @@ ; First example from Doc/Coroutines.rst (one block loop) -; RUN: opt < %s -O2 -enable-coroutines -S | FileCheck %s +; RUN: opt < %s -O2 -enable-coroutines -preserve-alignment-assumptions-during-inlining=false -S | FileCheck %s define i8* @f(i32 %n) { entry: diff --git a/llvm/test/Transforms/Coroutines/ex3.ll b/llvm/test/Transforms/Coroutines/ex3.ll index 8ff4d718230f5..d30afbf2e3e00 100644 --- a/llvm/test/Transforms/Coroutines/ex3.ll +++ b/llvm/test/Transforms/Coroutines/ex3.ll @@ -1,5 +1,5 @@ ; Third example from Doc/Coroutines.rst (two suspend points) -; RUN: opt < %s -O2 -enable-coroutines -S | FileCheck %s +; RUN: opt < %s -O2 -enable-coroutines -preserve-alignment-assumptions-during-inlining=false -S | FileCheck %s define i8* @f(i32 %n) { entry: diff --git a/llvm/test/Transforms/Coroutines/ex5.ll b/llvm/test/Transforms/Coroutines/ex5.ll index 34767584c8116..2c3ace2d5cf40 100644 --- a/llvm/test/Transforms/Coroutines/ex5.ll +++ b/llvm/test/Transforms/Coroutines/ex5.ll @@ -1,5 +1,5 @@ ; Fifth example from Doc/Coroutines.rst (final suspend) -; RUN: opt < %s -O2 -enable-coroutines -S | FileCheck %s +; RUN: opt < %s -O2 -enable-coroutines -preserve-alignment-assumptions-during-inlining=false -S | FileCheck %s define i8* @f(i32 %n) { entry: diff --git a/llvm/test/Transforms/GlobalOpt/null-check-is-use-pr35760.ll b/llvm/test/Transforms/GlobalOpt/null-check-is-use-pr35760.ll new file mode 100644 index 0000000000000..32516b6db7ca2 --- /dev/null +++ b/llvm/test/Transforms/GlobalOpt/null-check-is-use-pr35760.ll @@ -0,0 +1,41 @@ +; RUN: opt -S -globalopt -o - < %s | FileCheck %s + +target datalayout = "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128" +target triple = "x86_64-unknown-linux-gnu" + +@_ZL3g_i = internal global i32* null, align 8 +@.str = private unnamed_addr constant [2 x i8] c"0\00", align 1 +@.str.1 = private unnamed_addr constant [2 x i8] c"1\00", align 1 + +define dso_local i32 @main() { + store i32* null, i32** @_ZL3g_i, align 8 + call void @_ZL13PutsSomethingv() + ret i32 0 +} + +; CHECK-LABEL: define {{.*}} @_ZL13PutsSomethingv() +; CHECK: [[gvLoad:%.*]] = load i32*, i32** @_ZL3g_i +; CHECK-NEXT: icmp eq i32* [[gvLoad]], null +define internal void @_ZL13PutsSomethingv() { + %1 = load i32*, i32** @_ZL3g_i, align 8 + %2 = icmp eq i32* %1, null + br i1 %2, label %3, label %7 + +3: ; preds = %0 + %4 = call noalias i8* @malloc(i64 4) #3 + %5 = bitcast i8* %4 to i32* + store i32* %5, i32** @_ZL3g_i, align 8 + %6 = call i32 @puts(i8* getelementptr inbounds ([2 x i8], [2 x i8]* @.str, i64 0, i64 0)) + br label %9 + +7: ; preds = %0 + %8 = call i32 @puts(i8* getelementptr inbounds ([2 x i8], [2 x i8]* @.str.1, i64 0, i64 0)) + br label %9 + +9: ; preds = %7, %3 + ret void +} + +declare dso_local noalias i8* @malloc(i64) + +declare dso_local i32 @puts(i8* nocapture readonly) diff --git a/llvm/test/Transforms/InstCombine/malloc-free-delete-dbginvar.ll b/llvm/test/Transforms/InstCombine/malloc-free-delete-dbginvar.ll new file mode 100644 index 0000000000000..a3c4f47fd45e7 --- /dev/null +++ b/llvm/test/Transforms/InstCombine/malloc-free-delete-dbginvar.ll @@ -0,0 +1,22 @@ +; Check that the instcombine result is the same with/without debug info. +; This is a regression test for a function taken from malloc-free-delete.ll. + +; RUN: opt < %s -instcombine -S > %t.no_dbg.ll +; RUN: opt < %s -debugify-each -instcombine -S > %t.ll +; RUN: diff %t.no_dbg.ll %t.ll + +declare void @free(i8*) + +define void @test12(i32* %foo) minsize { +entry: + %tobool = icmp eq i32* %foo, null + br i1 %tobool, label %if.end, label %if.then + +if.then: ; preds = %entry + %bitcast = bitcast i32* %foo to i8* + tail call void @free(i8* %bitcast) + br label %if.end + +if.end: ; preds = %entry, %if.then + ret void +} diff --git a/llvm/test/Transforms/LICM/sink-debuginfo-preserve.ll b/llvm/test/Transforms/LICM/sink-debuginfo-preserve.ll new file mode 100644 index 0000000000000..9bb7edccf243e --- /dev/null +++ b/llvm/test/Transforms/LICM/sink-debuginfo-preserve.ll @@ -0,0 +1,147 @@ +; RUN: opt -S -licm < %s | FileCheck %s + +; LICM is trying to merge the two `store` in block %14 and %17, but given their +; locations disagree, it sets a line zero location instead instead of picking a +; random one (the DILocation picked the nearest enclosing scope of the two stores). + +; Original C testcase. +; volatile int a; +; extern int g; +; int g; +; void f1() { +; while (a) { +; g = 0; +; if (a) +; g = 0; +; } +; } + +; CHECK: %.lcssa = phi i32 +; CHECK-NEXT: store i32 %.lcssa, i32* getelementptr inbounds ([2 x i32], [2 x i32]* @g_390, i64 0, i64 1), align 4, !dbg [[storeLocation:![0-9]+]] +; CHECK: [[storeLocation]] = !DILocation(line: 0 + +target datalayout = "e-m:o-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128" +target triple = "x86_64-apple-macosx10.15.0" + +@b = global i32 0, align 4, !dbg !0 +@c = global i32 0, align 4, !dbg !10 +@g_390 = local_unnamed_addr global [2 x i32] zeroinitializer, align 4, !dbg !12 +@a = local_unnamed_addr global i32 0, align 4, !dbg !6 + +define i32 @main() local_unnamed_addr !dbg !22 { + %1 = load volatile i32, i32* @b, align 4, !dbg !37, !tbaa !40 + %2 = icmp sgt i32 %1, -9, !dbg !44 + br i1 %2, label %3, label %5, !dbg !45 + +3: ; preds = %0 + br label %9, !dbg !45 + +4: ; preds = %9 + br label %5, !dbg !45 + +5: ; preds = %4, %0 + %6 = load volatile i32, i32* @c, align 4, !dbg !46, !tbaa !40 + %7 = icmp slt i32 %6, 6, !dbg !47 + br i1 %7, label %8, label %24, !dbg !48 + +8: ; preds = %5 + br label %14, !dbg !48 + +9: ; preds = %3, %9 + %10 = load volatile i32, i32* @b, align 4, !dbg !49, !tbaa !40 + %11 = add nsw i32 %10, -1, !dbg !49 + store volatile i32 %11, i32* @b, align 4, !dbg !49, !tbaa !40 + %12 = load volatile i32, i32* @b, align 4, !dbg !37, !tbaa !40 + %13 = icmp sgt i32 %12, -9, !dbg !44 + br i1 %13, label %9, label %4, !dbg !45, !llvm.loop !50 + +14: ; preds = %8, %18 + store i32 0, i32* getelementptr inbounds ([2 x i32], [2 x i32]* @g_390, i64 0, i64 1), align 4, !dbg !53, !tbaa !40 + %15 = load volatile i32, i32* @b, align 4, !dbg !54, !tbaa !40 + %16 = icmp eq i32 %15, 0, !dbg !54 + br i1 %16, label %17, label %18, !dbg !55 + +17: ; preds = %14 + store i32 0, i32* getelementptr inbounds ([2 x i32], [2 x i32]* @g_390, i64 0, i64 1), align 4, !dbg !56, !tbaa !40 + br label %18 + +18: ; preds = %14, %17 + %19 = load volatile i32, i32* @c, align 4, !dbg !57, !tbaa !40 + %20 = add nsw i32 %19, 1, !dbg !57 + store volatile i32 %20, i32* @c, align 4, !dbg !57, !tbaa !40 + %21 = load volatile i32, i32* @c, align 4, !dbg !46, !tbaa !40 + %22 = icmp slt i32 %21, 6, !dbg !47 + br i1 %22, label %14, label %23, !dbg !48, !llvm.loop !58 + +23: ; preds = %18 + br label %24, !dbg !48 + +24: ; preds = %23, %5 + ret i32 0, !dbg !60 +} + +!llvm.dbg.cu = !{!2} +!llvm.module.flags = !{!17, !18, !19, !20} +!llvm.ident = !{!21} + +!0 = !DIGlobalVariableExpression(var: !1, expr: !DIExpression()) +!1 = distinct !DIGlobalVariable(name: "b", scope: !2, file: !3, line: 1, type: !8, isLocal: false, isDefinition: true) +!2 = distinct !DICompileUnit(language: DW_LANG_C99, file: !3, producer: "clang version 11.0.0 (https://github.com/llvm/llvm-project d3588d0814c4cbc7fca677b4d9634f6e1428a331)", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, enums: !4, globals: !5, nameTableKind: None, sysroot: "/") +!3 = !DIFile(filename: "a.c", directory: "/Users/davide/work/build/bin") +!4 = !{} +!5 = !{!6, !0, !10, !12} +!6 = !DIGlobalVariableExpression(var: !7, expr: !DIExpression()) +!7 = distinct !DIGlobalVariable(name: "a", scope: !2, file: !3, line: 1, type: !8, isLocal: false, isDefinition: true) +!8 = !DIDerivedType(tag: DW_TAG_volatile_type, baseType: !9) +!9 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed) +!10 = !DIGlobalVariableExpression(var: !11, expr: !DIExpression()) +!11 = distinct !DIGlobalVariable(name: "c", scope: !2, file: !3, line: 1, type: !8, isLocal: false, isDefinition: true) +!12 = !DIGlobalVariableExpression(var: !13, expr: !DIExpression()) +!13 = distinct !DIGlobalVariable(name: "g_390", scope: !2, file: !3, line: 2, type: !14, isLocal: false, isDefinition: true) +!14 = !DICompositeType(tag: DW_TAG_array_type, baseType: !9, size: 64, elements: !15) +!15 = !{!16} +!16 = !DISubrange(count: 2) +!17 = !{i32 7, !"Dwarf Version", i32 4} +!18 = !{i32 2, !"Debug Info Version", i32 3} +!19 = !{i32 1, !"wchar_size", i32 4} +!20 = !{i32 7, !"PIC Level", i32 2} +!21 = !{!"clang version 11.0.0 (https://github.com/llvm/llvm-project d3588d0814c4cbc7fca677b4d9634f6e1428a331)"} +!22 = distinct !DISubprogram(name: "main", scope: !3, file: !3, line: 3, type: !23, scopeLine: 3, flags: DIFlagAllCallsDescribed, spFlags: DISPFlagDefinition | DISPFlagOptimized, unit: !2, retainedNodes: !25) +!23 = !DISubroutineType(types: !24) +!24 = !{!9} +!25 = !{!26} +!26 = !DILocalVariable(name: "l_1546", scope: !27, file: !3, line: 11, type: !32) +!27 = distinct !DILexicalBlock(scope: !28, file: !3, line: 10, column: 10) +!28 = distinct !DILexicalBlock(scope: !29, file: !3, line: 8, column: 9) +!29 = distinct !DILexicalBlock(scope: !30, file: !3, line: 6, column: 23) +!30 = distinct !DILexicalBlock(scope: !31, file: !3, line: 6, column: 3) +!31 = distinct !DILexicalBlock(scope: !22, file: !3, line: 6, column: 3) +!32 = !DICompositeType(tag: DW_TAG_array_type, baseType: !33, size: 288, elements: !34) +!33 = !DIBasicType(name: "char", size: 8, encoding: DW_ATE_signed_char) +!34 = !{!35, !36, !35} +!35 = !DISubrange(count: 3) +!36 = !DISubrange(count: 4) +!37 = !DILocation(line: 4, column: 10, scope: !38) +!38 = distinct !DILexicalBlock(scope: !39, file: !3, line: 4, column: 3) +!39 = distinct !DILexicalBlock(scope: !22, file: !3, line: 4, column: 3) +!40 = !{!41, !41, i64 0} +!41 = !{!"int", !42, i64 0} +!42 = !{!"omnipotent char", !43, i64 0} +!43 = !{!"Simple C/C++ TBAA"} +!44 = !DILocation(line: 4, column: 12, scope: !38) +!45 = !DILocation(line: 4, column: 3, scope: !39) +!46 = !DILocation(line: 6, column: 10, scope: !30) +!47 = !DILocation(line: 6, column: 12, scope: !30) +!48 = !DILocation(line: 6, column: 3, scope: !31) +!49 = !DILocation(line: 4, column: 19, scope: !38) +!50 = distinct !{!50, !45, !51, !52} +!51 = !DILocation(line: 5, column: 5, scope: !39) +!52 = !{!"llvm.loop.unroll.disable"} +!53 = !DILocation(line: 7, column: 14, scope: !29) +!54 = !DILocation(line: 8, column: 9, scope: !28) +!55 = !DILocation(line: 8, column: 9, scope: !29) +!56 = !DILocation(line: 12, column: 16, scope: !27) +!57 = !DILocation(line: 6, column: 19, scope: !30) +!58 = distinct !{!58, !48, !59, !52} +!59 = !DILocation(line: 14, column: 3, scope: !31) +!60 = !DILocation(line: 15, column: 1, scope: !22) diff --git a/llvm/test/Transforms/LoopVectorize/pr45259.ll b/llvm/test/Transforms/LoopVectorize/pr45259.ll new file mode 100644 index 0000000000000..3d1370b14a0f4 --- /dev/null +++ b/llvm/test/Transforms/LoopVectorize/pr45259.ll @@ -0,0 +1,36 @@ +; RUN: opt < %s -S -loop-vectorize -force-vector-width=4 -force-vector-interleave=1 | FileCheck %s + +; Check that we can vectorize this loop without crashing. + +; CHECK-LABEL: define {{.*}} @widget( +; CHECK: [[vecInd:%.*]] = phi <4 x i8> [ +; CHECK-NEXT: add <4 x i8> [[vecInd]], + +define i8 @widget(i8* %arr, i8 %t9) { +bb: + br label %bb6 + +bb6: + %t1.0 = phi i8* [ %arr, %bb ], [ null, %bb6 ] + %c = call i1 @cond() + br i1 %c, label %for.preheader, label %bb6 + +for.preheader: + br label %for.body + +for.body: + %iv = phi i8 [ %iv.next, %for.body ], [ 0, %for.preheader ] + %iv.next = add i8 %iv, 1 + %ptr = getelementptr inbounds i8, i8* %arr, i8 %iv.next + %t3.i = icmp slt i8 %iv.next, %t9 + %t3.i8 = zext i1 %t3.i to i8 + store i8 %t3.i8, i8* %ptr + %ec = icmp eq i8* %t1.0, %ptr + br i1 %ec, label %for.exit, label %for.body + +for.exit: + %iv.next.lcssa = phi i8 [ %iv.next, %for.body ] + ret i8 %iv.next.lcssa +} + +declare i1 @cond() diff --git a/llvm/test/Transforms/ObjCARC/rv.ll b/llvm/test/Transforms/ObjCARC/rv.ll index 3d0d56ca0e536..0a1f4665afc6b 100644 --- a/llvm/test/Transforms/ObjCARC/rv.ll +++ b/llvm/test/Transforms/ObjCARC/rv.ll @@ -21,6 +21,8 @@ declare void @callee() declare void @callee_fnptr(void ()*) declare void @invokee() declare i8* @returner() +declare i8* @returner1(i8*) +declare i32 @__gxx_personality_v0(...) ; Test that retain+release elimination is suppressed when the ; retain is an objc_retainAutoreleasedReturnValue, since it's @@ -77,7 +79,7 @@ define void @test2() { ; CHECK-NEXT: ret i8* %call define i8* @test3() { entry: - %call = call i8* @returner() + %call = tail call i8* @returner() %0 = call i8* @llvm.objc.retainAutoreleasedReturnValue(i8* %call) nounwind %1 = call i8* @llvm.objc.autoreleaseReturnValue(i8* %0) nounwind ret i8* %1 @@ -387,6 +389,44 @@ bb3: ret i32* %retval } +; Don't eliminate the retainRV/autoreleaseRV pair if the call isn't a tail call. + +; CHECK-LABEL: define i8* @test28( +; CHECK: call i8* @returner() +; CHECK: call i8* @llvm.objc.retainAutoreleasedReturnValue( +; CHECK: call i8* @llvm.objc.autoreleaseReturnValue( +define i8* @test28() { +entry: + %call = call i8* @returner() + %0 = call i8* @llvm.objc.retainAutoreleasedReturnValue(i8* %call) nounwind + %1 = call i8* @llvm.objc.autoreleaseReturnValue(i8* %0) nounwind + ret i8* %1 +} + +; CHECK-LABEL: define i8* @test29( +; CHECK: call i8* @llvm.objc.retainAutoreleasedReturnValue( +; CHECK: call i8* @llvm.objc.autoreleaseReturnValue( + +define i8* @test29(i8* %k) local_unnamed_addr personality i8* bitcast (i32 (...)* @__gxx_personality_v0 to i8*) { +entry: + %0 = tail call i8* @llvm.objc.retain(i8* %k) + %call = invoke i8* @returner1(i8* %k) + to label %invoke.cont unwind label %lpad + +invoke.cont: + %1 = bitcast i8* %call to i8* + %2 = notail call i8* @llvm.objc.retainAutoreleasedReturnValue(i8* %1) + tail call void @llvm.objc.release(i8* %k), !clang.imprecise_release !0 + %3 = tail call i8* @llvm.objc.autoreleaseReturnValue(i8* %1) + ret i8* %call + +lpad: + %4 = landingpad { i8*, i32 } + cleanup + tail call void @llvm.objc.release(i8* %k) #1, !clang.imprecise_release !0 + resume { i8*, i32 } %4 +} + !0 = !{} ; CHECK: attributes [[NUW]] = { nounwind } diff --git a/llvm/test/Transforms/Util/Debugify/loc-only.ll b/llvm/test/Transforms/Util/Debugify/loc-only.ll new file mode 100644 index 0000000000000..250e72d28eb9f --- /dev/null +++ b/llvm/test/Transforms/Util/Debugify/loc-only.ll @@ -0,0 +1,21 @@ +; RUN: opt -debugify -S < %s | FileCheck --check-prefixes=ALL,VALUE %s +; RUN: opt -debugify -debugify-level=locations -S < %s | FileCheck --check-prefixes=ALL --implicit-check-not=dbg.value %s + +; ALL-LABEL: @test +define void @test() { + %add = add i32 1, 2 +; ALL-NEXT: %add = add i32 1, 2, !dbg [[L1:![0-9]+]] +; VALUE-NEXT: call void @llvm.dbg.value(metadata i32 %add, metadata [[add:![0-9]+]], metadata !DIExpression()), !dbg [[L1]] + %sub = sub i32 %add, 1 +; ALL-NEXT: %sub = sub i32 %add, 1, !dbg [[L2:![0-9]+]] +; VALUE-NEXT: call void @llvm.dbg.value(metadata i32 %sub, metadata [[sub:![0-9]+]], metadata !DIExpression()), !dbg [[L2]] +; ALL-NEXT: ret void, !dbg [[L3:![0-9]+]] + ret void +} + +; VALUE: [[add]] = !DILocalVariable +; VALUE: [[sub]] = !DILocalVariable + +; ALL: [[L1]] = !DILocation(line: 1, column: 1, scope: +; ALL: [[L2]] = !DILocation(line: 2, column: 1, scope: +; ALL: [[L3]] = !DILocation(line: 3, column: 1, scope: diff --git a/llvm/test/Transforms/Util/strip-nonlinetable-debuginfo-labels.ll b/llvm/test/Transforms/Util/strip-nonlinetable-debuginfo-labels.ll new file mode 100644 index 0000000000000..ed48add3b115a --- /dev/null +++ b/llvm/test/Transforms/Util/strip-nonlinetable-debuginfo-labels.ll @@ -0,0 +1,28 @@ +; RUN: opt -S -strip-nonlinetable-debuginfo %s -o - | FileCheck %s +; CHECK: define void @f() +define void @f() !dbg !4 { +entry: +; CHECK-NOT: llvm.dbg.label + call void @llvm.dbg.label(metadata !12), !dbg !11 + ret void, !dbg !11 +} + +declare void @llvm.dbg.label(metadata) + +!llvm.dbg.cu = !{!0} +!llvm.module.flags = !{!7, !8, !9} +!llvm.ident = !{!10} + +!0 = distinct !DICompileUnit(language: DW_LANG_C99, file: !1, producer: "LLVM", isOptimized: false, runtimeVersion: 0, emissionKind: 1, enums: !2) +!1 = !DIFile(filename: "f.c", directory: "/") +!2 = !{} +!4 = distinct !DISubprogram(name: "f", scope: !1, file: !1, line: 1, type: !5, isLocal: false, isDefinition: true, scopeLine: 1, isOptimized: false, unit: !0, retainedNodes: !2) +!5 = !DISubroutineType(types: !6) +!6 = !{null} +!7 = !{i32 2, !"Dwarf Version", i32 2} +!8 = !{i32 2, !"Debug Info Version", i32 3} +!9 = !{i32 1, !"PIC Level", i32 2} +!10 = !{!"LLVM"} +!11 = !DILocation(line: 1, column: 24, scope: !4) +; CHECK-NOT: DILabel +!12 = !DILabel(scope: !4, name: "entry", file: !1, line: 1) diff --git a/llvm/test/Transforms/Util/strip-nonlinetable-debuginfo-localvars.ll b/llvm/test/Transforms/Util/strip-nonlinetable-debuginfo-localvars.ll index c2cb87acb2a0b..c2642c312ccdc 100644 --- a/llvm/test/Transforms/Util/strip-nonlinetable-debuginfo-localvars.ll +++ b/llvm/test/Transforms/Util/strip-nonlinetable-debuginfo-localvars.ll @@ -3,14 +3,18 @@ define void @f() !dbg !4 { entry: %i = alloca i32, align 4 - ; CHECK-NOT: llvm.dbg.declare + ; CHECK-NOT: llvm.dbg.{{addr|declare|value}} call void @llvm.dbg.declare(metadata i32* %i, metadata !11, metadata !13), !dbg !14 + call void @llvm.dbg.addr(metadata i32* %i, metadata !16, metadata !13), !dbg !14 store i32 42, i32* %i, align 4, !dbg !14 + call void @llvm.dbg.value(metadata i32 0, metadata !16, metadata !13), !dbg !15 ret void, !dbg !15 } ; Function Attrs: nounwind readnone +declare void @llvm.dbg.addr(metadata, metadata, metadata) declare void @llvm.dbg.declare(metadata, metadata, metadata) +declare void @llvm.dbg.value(metadata, metadata, metadata) !llvm.dbg.cu = !{!0} !llvm.module.flags = !{!7, !8, !9} @@ -22,6 +26,7 @@ declare void @llvm.dbg.declare(metadata, metadata, metadata) ; CHECK: ![[F]] = distinct !DISubprogram(name: "f" ; CHECK-NOT: retainedNodes: ; CHECK-NOT: distinct !DISubprogram(name: "f" +; CHECK-NOT: DILocalVariable !4 = distinct !DISubprogram(name: "f", scope: !1, file: !1, line: 1, type: !5, isLocal: false, isDefinition: true, scopeLine: 1, isOptimized: false, unit: !0, retainedNodes: !2) !5 = !DISubroutineType(types: !6) !6 = !{null} @@ -34,3 +39,4 @@ declare void @llvm.dbg.declare(metadata, metadata, metadata) !13 = !DIExpression() !14 = !DILocation(line: 1, column: 16, scope: !4) !15 = !DILocation(line: 1, column: 24, scope: !4) +!16 = !DILocalVariable(name: "j", scope: !4, file: !1, line: 1, type: !12) diff --git a/llvm/test/tools/dsymutil/X86/Inputs/tail-call.cpp b/llvm/test/tools/dsymutil/X86/Inputs/tail-call.cpp new file mode 100644 index 0000000000000..57e512e7009d9 --- /dev/null +++ b/llvm/test/tools/dsymutil/X86/Inputs/tail-call.cpp @@ -0,0 +1,28 @@ +/* + * This file is used to test dsymutil support for call site entries with tail + * calls (DW_AT_call_pc). + * + * Instructions for regenerating binaries (on Darwin/x86_64): + * + * 1. Copy the source to a top-level directory to work around having absolute + * paths in the symtab's OSO entries. + * + * mkdir -p /Inputs/ && cp tail-call.c /Inputs && cd /Inputs + * + * 2. Compile with call site info enabled. -O2 is used to get tail call + * promotion. + * + * clang -g -O2 tail-call.c -c -o tail-call.macho.x86_64.o + * clang tail-call.macho.x86_64.o -o tail-call.macho.x86_64 + * + * 3. Copy the binaries back into the repo's Inputs directory. You'll need + * -oso-prepend-path=%p to link. + */ + +volatile int x; + +__attribute__((disable_tail_calls, noinline)) void func2() { x++; } + +__attribute__((noinline)) void func1() { func2(); /* tail */ } + +__attribute__((disable_tail_calls)) int main() { func1(); /* regular */ } diff --git a/llvm/test/tools/dsymutil/X86/Inputs/tail-call.macho.x86_64 b/llvm/test/tools/dsymutil/X86/Inputs/tail-call.macho.x86_64 new file mode 100755 index 0000000000000..d6098d0de5e4b Binary files /dev/null and b/llvm/test/tools/dsymutil/X86/Inputs/tail-call.macho.x86_64 differ diff --git a/llvm/test/tools/dsymutil/X86/Inputs/tail-call.macho.x86_64.o b/llvm/test/tools/dsymutil/X86/Inputs/tail-call.macho.x86_64.o new file mode 100644 index 0000000000000..1d5726d12e34c Binary files /dev/null and b/llvm/test/tools/dsymutil/X86/Inputs/tail-call.macho.x86_64.o differ diff --git a/llvm/test/tools/dsymutil/X86/object-prefix-path.test b/llvm/test/tools/dsymutil/X86/object-prefix-path.test new file mode 100644 index 0000000000000..16956e0f94521 --- /dev/null +++ b/llvm/test/tools/dsymutil/X86/object-prefix-path.test @@ -0,0 +1,11 @@ +RUN: rm -rf %t.dir && mkdir %t.dir && mkdir %t.dir/ModuleCacheRenamed +RUN: cp %p/../Inputs/module-warnings/1.o %t.dir +RUN: cp %p/../Inputs/module-warnings/Foo.pcm %t.dir/ModuleCacheRenamed + +RUN: dsymutil -verify -f -oso-prepend-path=%t.dir -y \ +RUN: %p/dummy-debug-map.map -o %t \ +RUN: -object-prefix-map=/ModuleCache=/ModuleCacheRenamed \ +RUN: 2>&1 | FileCheck %s + +CHECK: warning: {{.*}}Bar.pcm: +CHECK-NOT: warning: {{.*}}Foo.pcm: diff --git a/llvm/test/tools/dsymutil/X86/tail-call-linking.test b/llvm/test/tools/dsymutil/X86/tail-call-linking.test new file mode 100644 index 0000000000000..29ae2cc544cf6 --- /dev/null +++ b/llvm/test/tools/dsymutil/X86/tail-call-linking.test @@ -0,0 +1,4 @@ +RUN: dsymutil -oso-prepend-path=%p %p/Inputs/tail-call.macho.x86_64 -o %t.dSYM +RUN: llvm-dwarfdump %t.dSYM | FileCheck %s -implicit-check-not=DW_AT_call_pc + +CHECK: DW_AT_call_pc (0x0000000100000f95) diff --git a/llvm/test/tools/dsymutil/cmdline.test b/llvm/test/tools/dsymutil/cmdline.test index fc3f00b369fde..701de29637dd8 100644 --- a/llvm/test/tools/dsymutil/cmdline.test +++ b/llvm/test/tools/dsymutil/cmdline.test @@ -12,6 +12,7 @@ HELP: -no-odr HELP: -no-output HELP: -no-swiftmodule-timestamp HELP: -num-threads +HELP: -object-prefix-map HELP: -oso-prepend-path HELP: -o HELP: -papertrail diff --git a/llvm/tools/dsymutil/DwarfLinker.cpp b/llvm/tools/dsymutil/DwarfLinker.cpp index 16863fa5f197b..14bff4f706953 100644 --- a/llvm/tools/dsymutil/DwarfLinker.cpp +++ b/llvm/tools/dsymutil/DwarfLinker.cpp @@ -1428,6 +1428,10 @@ unsigned DwarfLinker::DIECloner::cloneAddressAttribute( if (Die.getTag() == dwarf::DW_TAG_call_site) Addr = (Info.OrigCallReturnPc ? Info.OrigCallReturnPc : Addr) + Info.PCOffset; + } else if (AttrSpec.Attr == dwarf::DW_AT_call_pc) { + // Relocate the address of a branch instruction within a call site entry. + if (Die.getTag() == dwarf::DW_TAG_call_site) + Addr = (Info.OrigCallPc ? Info.OrigCallPc : Addr) + Info.PCOffset; } Die.addValue(DIEAlloc, static_cast(AttrSpec.Attr), @@ -2324,6 +2328,14 @@ static uint64_t getDwoId(const DWARFDie &CUDie, const DWARFUnit &Unit) { return 0; } +static std::string remapPath(StringRef Path, + const objectPrefixMap &ObjectPrefixMap) { + for (const auto &Entry : ObjectPrefixMap) + if (Path.startswith(Entry.first)) + return (Twine(Entry.second) + Path.substr(Entry.first.size())).str(); + return Path.str(); +} + bool DwarfLinker::registerModuleReference( DWARFDie CUDie, const DWARFUnit &Unit, DebugMap &ModuleMap, const DebugMapObject &DMO, RangesTy &Ranges, OffsetsStringPool &StringPool, @@ -2334,6 +2346,8 @@ bool DwarfLinker::registerModuleReference( CUDie.find({dwarf::DW_AT_dwo_name, dwarf::DW_AT_GNU_dwo_name}), ""); if (PCMfile.empty()) return false; + if (ObjectPrefixMap) + PCMfile = remapPath(PCMfile, *ObjectPrefixMap); // Clang module DWARF skeleton CUs abuse this for the path to the module. uint64_t DwoId = getDwoId(CUDie, Unit); @@ -2748,6 +2762,8 @@ bool DwarfLinker::link(const DebugMap &Map) { if (!createStreamer(Map.getTriple(), OutFile)) return false; + setObjectPrefixMap(&Options.ObjectPrefixMap); + // Size of the DIEs (and headers) generated for the linked output. OutputDebugInfoSize = 0; // A unique ID that identifies each compile unit. @@ -2773,7 +2789,11 @@ bool DwarfLinker::link(const DebugMap &Map) { // This Dwarf string pool which is used for emission. It must be used // serially as the order of calling getStringOffset matters for // reproducibility. - OffsetsStringPool OffsetsStringPool(Options.Translator, true); + std::function TranslationLambda = + Options.Translator + ? [&](StringRef Input) { return Options.Translator(Input); } + : static_cast>(nullptr); + OffsetsStringPool OffsetsStringPool(TranslationLambda, true); // ODR Contexts for the link. DeclContextTree ODRContexts; diff --git a/llvm/tools/dsymutil/DwarfLinker.h b/llvm/tools/dsymutil/DwarfLinker.h index f0057f88f5992..ba7ed721b1540 100644 --- a/llvm/tools/dsymutil/DwarfLinker.h +++ b/llvm/tools/dsymutil/DwarfLinker.h @@ -38,6 +38,7 @@ struct DebugMapObjectRange { /// Map LowPC to DebugMapObjectRange. using RangesTy = std::map; using UnitListTy = std::vector>; +typedef std::map objectPrefixMap; /// The core of the Dwarf linking logic. /// @@ -184,6 +185,11 @@ class DwarfLinker { /// Called at the end of a debug object link. void endDebugObject(LinkContext &Context); + /// Set prefix map for objects. + void setObjectPrefixMap(objectPrefixMap *Map) { + ObjectPrefixMap = Map; + } + /// \defgroup FindRootDIEs Find DIEs corresponding to debug map entries. /// /// @{ @@ -321,6 +327,9 @@ class DwarfLinker { /// Value of DW_AT_call_return_pc in the input DIE uint64_t OrigCallReturnPc = 0; + /// Value of DW_AT_call_pc in the input DIE + uint64_t OrigCallPc = 0; + /// Offset to apply to PC addresses inside a function. int64_t PCOffset = 0; @@ -502,6 +511,8 @@ class DwarfLinker { /// be uniqued and sorted and there are only few entries expected /// per compile unit, which is why this is a std::map. std::map ParseableSwiftInterfaces; + /// A list of remappings to apply to file paths. + objectPrefixMap *ObjectPrefixMap = nullptr; bool ModuleCacheHintDisplayed = false; bool ArchiveHintDisplayed = false; diff --git a/llvm/tools/dsymutil/LinkUtils.h b/llvm/tools/dsymutil/LinkUtils.h index 0f31334cd317a..0d99fa73f74d6 100644 --- a/llvm/tools/dsymutil/LinkUtils.h +++ b/llvm/tools/dsymutil/LinkUtils.h @@ -63,6 +63,9 @@ struct LinkOptions { /// -oso-prepend-path std::string PrependPath; + /// The -object-prefix-map. + std::map ObjectPrefixMap; + /// The Resources directory in the .dSYM bundle. Optional ResourceDir; diff --git a/llvm/tools/dsymutil/Options.td b/llvm/tools/dsymutil/Options.td index eb86c2f3ae1b3..5360bf09ac751 100644 --- a/llvm/tools/dsymutil/Options.td +++ b/llvm/tools/dsymutil/Options.td @@ -110,6 +110,15 @@ def oso_prepend_path: Separate<["--", "-"], "oso-prepend-path">, Group; def: Joined<["--", "-"], "oso-prepend-path=">, Alias; +def object_prefix_map: Separate<["--", "-"], "object-prefix-map">, + MetaVarName<"">, + HelpText<"Remap object file paths (but no source paths) before processing." + "Use this for Clang objects where the module cache location was" + "remapped using -fdebug-prefix-map; to help dsymutil" + "find the Clang module cache.">, + Group; +def: Joined<["--", "-"], "object-prefix-map=">, Alias; + def symbolmap: Separate<["--", "-"], "symbol-map">, MetaVarName<"">, HelpText<"Updates the existing dSYMs inplace using symbol map specified.">, diff --git a/llvm/tools/dsymutil/dsymutil.cpp b/llvm/tools/dsymutil/dsymutil.cpp index 2801178c605f2..15f34e509c7a8 100644 --- a/llvm/tools/dsymutil/dsymutil.cpp +++ b/llvm/tools/dsymutil/dsymutil.cpp @@ -246,6 +246,12 @@ static Expected getOptions(opt::InputArgList &Args) { if (opt::Arg *OsoPrependPath = Args.getLastArg(OPT_oso_prepend_path)) Options.LinkOpts.PrependPath = OsoPrependPath->getValue(); + for (const auto &Arg : Args.getAllArgValues(OPT_object_prefix_map)) { + auto Split = StringRef(Arg).split('='); + Options.LinkOpts.ObjectPrefixMap.insert( + {std::string(Split.first), std::string(Split.second)}); + } + if (opt::Arg *OutputFile = Args.getLastArg(OPT_output)) Options.OutputFile = OutputFile->getValue(); diff --git a/llvm/tools/llc/llc.cpp b/llvm/tools/llc/llc.cpp index 9e5da83250728..4a1b2de388986 100644 --- a/llvm/tools/llc/llc.cpp +++ b/llvm/tools/llc/llc.cpp @@ -383,8 +383,9 @@ static bool addPass(PassManagerBase &PM, const char *argv0, return true; } std::string Banner = std::string("After ") + std::string(P->getPassName()); + TPC.addMachinePrePasses(); PM.add(P); - TPC.printAndVerify(Banner); + TPC.addMachinePostPasses(Banner); return false; } diff --git a/llvm/unittests/ADT/CoalescingBitVectorTest.cpp b/llvm/unittests/ADT/CoalescingBitVectorTest.cpp index 02a5bde2bfacd..4f87bf415bebb 100644 --- a/llvm/unittests/ADT/CoalescingBitVectorTest.cpp +++ b/llvm/unittests/ADT/CoalescingBitVectorTest.cpp @@ -77,17 +77,6 @@ TEST(CoalescingBitVector, Copy) { EXPECT_TRUE(elementsMatch(BV2, {0})); } -TEST(CoalescingBitVector, Move) { - UBitVec::Allocator Alloc; - UBitVec BV1(Alloc); - BV1.set(0); - UBitVec BV2 = std::move(BV1); - EXPECT_TRUE(elementsMatch(BV2, {0})); - BV2.set(5); - BV1 = std::move(BV2); - EXPECT_TRUE(elementsMatch(BV1, {0, 5})); -} - TEST(CoalescingBitVectorTest, Iterators) { UBitVec::Allocator Alloc; UBitVec BV(Alloc); @@ -194,14 +183,12 @@ TEST(CoalescingBitVectorTest, Comparison) { // A simple implementation of set union, used to double-check the human // "expected" answer. -UBitVec simpleUnion(UBitVec::Allocator &Alloc, const UBitVec &LHS, +void simpleUnion(UBitVec &Union, const UBitVec &LHS, const UBitVec &RHS) { - UBitVec Union(Alloc); for (unsigned Bit : LHS) Union.test_and_set(Bit); for (unsigned Bit : RHS) Union.test_and_set(Bit); - return Union; } TEST(CoalescingBitVectorTest, Union) { @@ -215,7 +202,8 @@ TEST(CoalescingBitVectorTest, Union) { BV1.set(LHS); UBitVec BV2(Alloc); BV2.set(RHS); - const UBitVec &DoubleCheckedExpected = simpleUnion(Alloc, BV1, BV2); + UBitVec DoubleCheckedExpected(Alloc); + simpleUnion(DoubleCheckedExpected, BV1, BV2); ASSERT_TRUE(elementsMatch(DoubleCheckedExpected, Expected)); BV1 |= BV2; ASSERT_TRUE(elementsMatch(BV1, Expected)); @@ -288,13 +276,11 @@ TEST(CoalescingBitVectorTest, Union) { // A simple implementation of set intersection, used to double-check the // human "expected" answer. -UBitVec simpleIntersection(UBitVec::Allocator &Alloc, const UBitVec &LHS, - const UBitVec &RHS) { - UBitVec Intersection(Alloc); +void simpleIntersection(UBitVec &Intersection, const UBitVec &LHS, + const UBitVec &RHS) { for (unsigned Bit : LHS) if (RHS.test(Bit)) Intersection.set(Bit); - return Intersection; } TEST(CoalescingBitVectorTest, Intersection) { @@ -308,7 +294,8 @@ TEST(CoalescingBitVectorTest, Intersection) { BV1.set(LHS); UBitVec BV2(Alloc); BV2.set(RHS); - const UBitVec &DoubleCheckedExpected = simpleIntersection(Alloc, BV1, BV2); + UBitVec DoubleCheckedExpected(Alloc); + simpleIntersection(DoubleCheckedExpected, BV1, BV2); ASSERT_TRUE(elementsMatch(DoubleCheckedExpected, Expected)); BV1 &= BV2; ASSERT_TRUE(elementsMatch(BV1, Expected)); @@ -367,14 +354,11 @@ TEST(CoalescingBitVectorTest, Intersection) { // A simple implementation of set intersection-with-complement, used to // double-check the human "expected" answer. -UBitVec simpleIntersectionWithComplement(UBitVec::Allocator &Alloc, - const UBitVec &LHS, - const UBitVec &RHS) { - UBitVec Intersection(Alloc); +void simpleIntersectionWithComplement(UBitVec &Intersection, const UBitVec &LHS, + const UBitVec &RHS) { for (unsigned Bit : LHS) if (!RHS.test(Bit)) Intersection.set(Bit); - return Intersection; } TEST(CoalescingBitVectorTest, IntersectWithComplement) { @@ -389,8 +373,8 @@ TEST(CoalescingBitVectorTest, IntersectWithComplement) { BV1.set(LHS); UBitVec BV2(Alloc); BV2.set(RHS); - const UBitVec &DoubleCheckedExpected = - simpleIntersectionWithComplement(Alloc, BV1, BV2); + UBitVec DoubleCheckedExpected(Alloc); + simpleIntersectionWithComplement(DoubleCheckedExpected, BV1, BV2); ASSERT_TRUE(elementsMatch(DoubleCheckedExpected, Expected)); BV1.intersectWithComplement(BV2); ASSERT_TRUE(elementsMatch(BV1, Expected)); @@ -464,6 +448,44 @@ TEST(CoalescingBitVectorTest, FindLowerBound) { EXPECT_EQ(*BV.find(3), 3u); } +TEST(CoalescingBitVectorTest, AdvanceToLowerBound) { + U64BitVec::Allocator Alloc; + U64BitVec BV(Alloc); + uint64_t BigNum1 = uint64_t(1) << 32; + uint64_t BigNum2 = (uint64_t(1) << 33) + 1; + + auto advFromBegin = [&](uint64_t To) -> U64BitVec::const_iterator { + auto It = BV.begin(); + It.advanceToLowerBound(To); + return It; + }; + + EXPECT_TRUE(advFromBegin(BigNum1) == BV.end()); + BV.set(BigNum1); + auto Find1 = advFromBegin(BigNum1); + EXPECT_EQ(*Find1, BigNum1); + BV.set(BigNum2); + auto Find2 = advFromBegin(BigNum1); + EXPECT_EQ(*Find2, BigNum1); + auto Find3 = advFromBegin(BigNum2); + EXPECT_EQ(*Find3, BigNum2); + BV.reset(BigNum1); + auto Find4 = advFromBegin(BigNum1); + EXPECT_EQ(*Find4, BigNum2); + + BV.clear(); + BV.set({1, 2, 3}); + EXPECT_EQ(*advFromBegin(2), 2u); + EXPECT_EQ(*advFromBegin(3), 3u); + auto It = BV.begin(); + It.advanceToLowerBound(0); + EXPECT_EQ(*It, 1u); + It.advanceToLowerBound(100); + EXPECT_TRUE(It == BV.end()); + It.advanceToLowerBound(100); + EXPECT_TRUE(It == BV.end()); +} + TEST(CoalescingBitVectorTest, Print) { std::string S; { diff --git a/llvm/unittests/Analysis/CMakeLists.txt b/llvm/unittests/Analysis/CMakeLists.txt index 4b4ea416ed8dd..91f583dfd7239 100644 --- a/llvm/unittests/Analysis/CMakeLists.txt +++ b/llvm/unittests/Analysis/CMakeLists.txt @@ -23,7 +23,6 @@ add_llvm_unittest(AnalysisTests LoopInfoTest.cpp MemoryBuiltinsTest.cpp MemorySSATest.cpp - OrderedBasicBlockTest.cpp OrderedInstructionsTest.cpp PhiValuesTest.cpp ProfileSummaryInfoTest.cpp diff --git a/llvm/unittests/Analysis/CaptureTrackingTest.cpp b/llvm/unittests/Analysis/CaptureTrackingTest.cpp index 86a0aa16a066a..e4c8a9ff0f744 100644 --- a/llvm/unittests/Analysis/CaptureTrackingTest.cpp +++ b/llvm/unittests/Analysis/CaptureTrackingTest.cpp @@ -7,7 +7,6 @@ //===----------------------------------------------------------------------===// #include "llvm/Analysis/CaptureTracking.h" -#include "llvm/Analysis/OrderedBasicBlock.h" #include "llvm/AsmParser/Parser.h" #include "llvm/IR/Dominators.h" #include "llvm/IR/Instructions.h" @@ -62,14 +61,13 @@ TEST(CaptureTracking, MaxUsesToExplore) { BasicBlock *EntryBB = &F->getEntryBlock(); DominatorTree DT(*F); - OrderedBasicBlock OBB(EntryBB); Instruction *Ret = EntryBB->getTerminator(); ASSERT_TRUE(isa(Ret)); - ASSERT_FALSE(PointerMayBeCapturedBefore(Arg, true, true, Ret, &DT, false, - &OBB, FalseMaxUsesLimit)); + ASSERT_FALSE(PointerMayBeCapturedBefore(Arg, true, true, Ret, &DT, false, + FalseMaxUsesLimit)); ASSERT_TRUE(PointerMayBeCapturedBefore(Arg, true, true, Ret, &DT, false, - &OBB, TrueMaxUsesLimit)); + TrueMaxUsesLimit)); }; Test("test_few_uses", 6, 4); diff --git a/llvm/unittests/Analysis/OrderedBasicBlockTest.cpp b/llvm/unittests/Analysis/OrderedBasicBlockTest.cpp deleted file mode 100644 index 4cccb38daff35..0000000000000 --- a/llvm/unittests/Analysis/OrderedBasicBlockTest.cpp +++ /dev/null @@ -1,57 +0,0 @@ -//===- OrderedBasicBlockTest.cpp - OrderedBasicBlock unit tests -----------===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// - -#include "llvm/Analysis/OrderedBasicBlock.h" -#include "llvm/AsmParser/Parser.h" -#include "llvm/IR/BasicBlock.h" -#include "llvm/IR/Function.h" -#include "llvm/IR/LLVMContext.h" -#include "llvm/IR/Module.h" -#include "llvm/Support/DataTypes.h" -#include "llvm/Support/SourceMgr.h" -#include "gtest/gtest.h" - -namespace llvm { -namespace { - -class OrderedBasicBlockTest : public testing::Test { -protected: - LLVMContext C; - - std::unique_ptr makeLLVMModule() { - const char *ModuleString = R"(define i32 @f(i32 %x) { - %add = add i32 %x, 42 - ret i32 %add - })"; - SMDiagnostic Err; - auto foo = parseAssemblyString(ModuleString, Err, C); - return foo; - } -}; - -TEST_F(OrderedBasicBlockTest, Basic) { - auto M = makeLLVMModule(); - Function *F = M->getFunction("f"); - BasicBlock::iterator I = F->front().begin(); - Instruction *Add = &*I++; - Instruction *Ret = &*I++; - - OrderedBasicBlock OBB(&F->front()); - // Intentionally duplicated to verify cached and uncached are the same. - EXPECT_FALSE(OBB.dominates(Add, Add)); - EXPECT_FALSE(OBB.dominates(Add, Add)); - EXPECT_TRUE(OBB.dominates(Add, Ret)); - EXPECT_TRUE(OBB.dominates(Add, Ret)); - EXPECT_FALSE(OBB.dominates(Ret, Add)); - EXPECT_FALSE(OBB.dominates(Ret, Add)); - EXPECT_FALSE(OBB.dominates(Ret, Ret)); - EXPECT_FALSE(OBB.dominates(Ret, Ret)); -} - -} // end anonymous namespace -} // end namespace llvm diff --git a/llvm/unittests/IR/BasicBlockTest.cpp b/llvm/unittests/IR/BasicBlockTest.cpp index ad446ee6ebab2..fcdc9c2c07fba 100644 --- a/llvm/unittests/IR/BasicBlockTest.cpp +++ b/llvm/unittests/IR/BasicBlockTest.cpp @@ -8,11 +8,13 @@ #include "llvm/IR/BasicBlock.h" #include "llvm/ADT/STLExtras.h" +#include "llvm/AsmParser/Parser.h" #include "llvm/IR/Function.h" #include "llvm/IR/IRBuilder.h" #include "llvm/IR/LLVMContext.h" #include "llvm/IR/Module.h" #include "llvm/IR/NoFolder.h" +#include "llvm/Support/SourceMgr.h" #include "gmock/gmock-matchers.h" #include "gtest/gtest.h" #include @@ -129,5 +131,130 @@ TEST(BasicBlockTest, TestInstructionsWithoutDebug) { delete V; } +TEST(BasicBlockTest, ComesBefore) { + const char *ModuleString = R"(define i32 @f(i32 %x) { + %add = add i32 %x, 42 + ret i32 %add + })"; + LLVMContext Ctx; + SMDiagnostic Err; + auto M = parseAssemblyString(ModuleString, Err, Ctx); + ASSERT_TRUE(M.get()); + + Function *F = M->getFunction("f"); + BasicBlock &BB = F->front(); + BasicBlock::iterator I = BB.begin(); + Instruction *Add = &*I++; + Instruction *Ret = &*I++; + + // Intentionally duplicated to verify cached and uncached are the same. + EXPECT_FALSE(BB.isInstrOrderValid()); + EXPECT_FALSE(Add->comesBefore(Add)); + EXPECT_TRUE(BB.isInstrOrderValid()); + EXPECT_FALSE(Add->comesBefore(Add)); + BB.invalidateOrders(); + EXPECT_FALSE(BB.isInstrOrderValid()); + EXPECT_TRUE(Add->comesBefore(Ret)); + EXPECT_TRUE(BB.isInstrOrderValid()); + EXPECT_TRUE(Add->comesBefore(Ret)); + BB.invalidateOrders(); + EXPECT_FALSE(Ret->comesBefore(Add)); + EXPECT_FALSE(Ret->comesBefore(Add)); + BB.invalidateOrders(); + EXPECT_FALSE(Ret->comesBefore(Ret)); + EXPECT_FALSE(Ret->comesBefore(Ret)); +} + +class InstrOrderInvalidationTest : public ::testing::Test { +protected: + void SetUp() override { + M.reset(new Module("MyModule", Ctx)); + Nop = Intrinsic::getDeclaration(M.get(), Intrinsic::donothing); + FunctionType *FT = FunctionType::get(Type::getVoidTy(Ctx), {}, false); + Function *F = Function::Create(FT, Function::ExternalLinkage, "foo", *M); + BB = BasicBlock::Create(Ctx, "entry", F); + + IRBuilder<> Builder(BB); + I1 = Builder.CreateCall(Nop); + I2 = Builder.CreateCall(Nop); + I3 = Builder.CreateCall(Nop); + Ret = Builder.CreateRetVoid(); + } + + LLVMContext Ctx; + std::unique_ptr M; + Function *Nop = nullptr; + BasicBlock *BB = nullptr; + Instruction *I1 = nullptr; + Instruction *I2 = nullptr; + Instruction *I3 = nullptr; + Instruction *Ret = nullptr; +}; + +TEST_F(InstrOrderInvalidationTest, InsertInvalidation) { + EXPECT_FALSE(BB->isInstrOrderValid()); + EXPECT_TRUE(I1->comesBefore(I2)); + EXPECT_TRUE(BB->isInstrOrderValid()); + EXPECT_TRUE(I2->comesBefore(I3)); + EXPECT_TRUE(I3->comesBefore(Ret)); + EXPECT_TRUE(BB->isInstrOrderValid()); + + // Invalidate orders. + IRBuilder<> Builder(BB, I2->getIterator()); + Instruction *I1a = Builder.CreateCall(Nop); + EXPECT_FALSE(BB->isInstrOrderValid()); + EXPECT_TRUE(I1->comesBefore(I1a)); + EXPECT_TRUE(BB->isInstrOrderValid()); + EXPECT_TRUE(I1a->comesBefore(I2)); + EXPECT_TRUE(I2->comesBefore(I3)); + EXPECT_TRUE(I3->comesBefore(Ret)); + EXPECT_TRUE(BB->isInstrOrderValid()); +} + +TEST_F(InstrOrderInvalidationTest, SpliceInvalidation) { + EXPECT_TRUE(I1->comesBefore(I2)); + EXPECT_TRUE(I2->comesBefore(I3)); + EXPECT_TRUE(I3->comesBefore(Ret)); + EXPECT_TRUE(BB->isInstrOrderValid()); + + // Use Instruction::moveBefore, which uses splice. + I2->moveBefore(I1); + EXPECT_FALSE(BB->isInstrOrderValid()); + + EXPECT_TRUE(I2->comesBefore(I1)); + EXPECT_TRUE(I1->comesBefore(I3)); + EXPECT_TRUE(I3->comesBefore(Ret)); + EXPECT_TRUE(BB->isInstrOrderValid()); +} + +TEST_F(InstrOrderInvalidationTest, RemoveNoInvalidation) { + // Cache the instruction order. + EXPECT_FALSE(BB->isInstrOrderValid()); + EXPECT_TRUE(I1->comesBefore(I2)); + EXPECT_TRUE(BB->isInstrOrderValid()); + + // Removing does not invalidate instruction order. + I2->removeFromParent(); + I2->deleteValue(); + I2 = nullptr; + EXPECT_TRUE(BB->isInstrOrderValid()); + EXPECT_TRUE(I1->comesBefore(I3)); + EXPECT_EQ(std::next(I1->getIterator()), I3->getIterator()); +} + +TEST_F(InstrOrderInvalidationTest, EraseNoInvalidation) { + // Cache the instruction order. + EXPECT_FALSE(BB->isInstrOrderValid()); + EXPECT_TRUE(I1->comesBefore(I2)); + EXPECT_TRUE(BB->isInstrOrderValid()); + + // Removing does not invalidate instruction order. + I2->eraseFromParent(); + I2 = nullptr; + EXPECT_TRUE(BB->isInstrOrderValid()); + EXPECT_TRUE(I1->comesBefore(I3)); + EXPECT_EQ(std::next(I1->getIterator()), I3->getIterator()); +} + } // End anonymous namespace. } // End llvm namespace. diff --git a/llvm/unittests/Support/CMakeLists.txt b/llvm/unittests/Support/CMakeLists.txt index 161891517cf37..0b46040e10e57 100644 --- a/llvm/unittests/Support/CMakeLists.txt +++ b/llvm/unittests/Support/CMakeLists.txt @@ -50,6 +50,7 @@ add_llvm_unittest(SupportTests MemoryBufferTest.cpp MemoryTest.cpp NativeFormatTests.cpp + OptimalLayoutTest.cpp ParallelTest.cpp Path.cpp ProcessTest.cpp diff --git a/llvm/unittests/Support/OptimalLayoutTest.cpp b/llvm/unittests/Support/OptimalLayoutTest.cpp new file mode 100644 index 0000000000000..a31fbaf3f2e68 --- /dev/null +++ b/llvm/unittests/Support/OptimalLayoutTest.cpp @@ -0,0 +1,132 @@ +//=== - llvm/unittest/Support/OptimalLayoutTest.cpp - Layout tests --------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "llvm/Support/OptimalLayout.h" +#include "gtest/gtest.h" + +using namespace llvm; + +namespace { + +class LayoutTest { + struct Field { + uint64_t Size; + Align Alignment; + uint64_t ForcedOffset; + uint64_t ExpectedOffset; + }; + + SmallVector Fields; + bool Verified = false; + +public: + LayoutTest() {} + LayoutTest(const LayoutTest &) = delete; + LayoutTest &operator=(const LayoutTest &) = delete; + ~LayoutTest() { assert(Verified); } + + LayoutTest &flexible(uint64_t Size, uint64_t Alignment, + uint64_t ExpectedOffset) { + Fields.push_back({Size, Align(Alignment), + OptimalLayoutField::FlexibleOffset, ExpectedOffset}); + return *this; + } + + LayoutTest &fixed(uint64_t Size, uint64_t Alignment, uint64_t Offset) { + Fields.push_back({Size, Align(Alignment), Offset, Offset}); + return *this; + } + + void verify(uint64_t ExpectedSize, uint64_t ExpectedAlignment) { + SmallVector LayoutFields; + LayoutFields.reserve(Fields.size()); + for (auto &F : Fields) + LayoutFields.emplace_back(&F, F.Size, F.Alignment, F.ForcedOffset); + + auto SizeAndAlign = performOptimalLayout(LayoutFields); + + EXPECT_EQ(SizeAndAlign.first, ExpectedSize); + EXPECT_EQ(SizeAndAlign.second, Align(ExpectedAlignment)); + + for (auto &LF : LayoutFields) { + auto &F = *static_cast(LF.Id); + EXPECT_EQ(LF.Offset, F.ExpectedOffset); + } + + Verified = true; + } +}; + +} + +TEST(OptimalLayoutTest, Basic) { + LayoutTest() + .flexible(12, 4, 8) + .flexible(8, 8, 0) + .flexible(4, 4, 20) + .verify(24, 8); +} + +TEST(OptimalLayoutTest, OddSize) { + LayoutTest() + .flexible(8, 8, 16) + .flexible(4, 4, 12) + .flexible(1, 1, 10) + .flexible(10, 8, 0) + .verify(24, 8); +} + +TEST(OptimalLayoutTest, Gaps) { + LayoutTest() + .fixed(4, 4, 8) + .fixed(4, 4, 16) + .flexible(4, 4, 0) + .flexible(4, 4, 4) + .flexible(4, 4, 12) + .flexible(4, 4, 20) + .verify(24, 4); +} + +TEST(OptimalLayoutTest, Greed) { + // The greedy algorithm doesn't find the optimal layout here, which + // would be to put the 5-byte field at the end. + LayoutTest() + .fixed(4, 4, 8) + .flexible(5, 4, 0) + .flexible(4, 4, 12) + .flexible(4, 4, 16) + .flexible(4, 4, 20) + .verify(24, 4); +} + +TEST(OptimalLayoutTest, Jagged) { + LayoutTest() + .flexible(1, 2, 18) + .flexible(13, 8, 0) + .flexible(3, 2, 14) + .verify(19, 8); +} + +TEST(OptimalLayoutTest, GardenPath) { + // The 4-byte-aligned field is our highest priority, but the less-aligned + // fields keep leaving the end offset mis-aligned. + LayoutTest() + .fixed(7, 4, 0) + .flexible(4, 4, 44) + .flexible(6, 1, 7) + .flexible(5, 1, 13) + .flexible(7, 2, 18) + .flexible(4, 1, 25) + .flexible(4, 1, 29) + .flexible(1, 1, 33) + .flexible(4, 2, 34) + .flexible(4, 2, 38) + .flexible(2, 2, 42) + .flexible(2, 2, 48) + .verify(50, 4); +} \ No newline at end of file diff --git a/llvm/utils/clang-parse-diagnostics-file b/llvm/utils/clang-parse-diagnostics-file index 59b13f306505a..1f720c34544a7 100755 --- a/llvm/utils/clang-parse-diagnostics-file +++ b/llvm/utils/clang-parse-diagnostics-file @@ -66,6 +66,10 @@ Utility for dumping Clang-style logged diagnostics.\ for file_diags in diags: file = file_diags.get('main-file') + # Diagnostics from modules don't have a main-file listed. + if not file: + file = '' + # Ignore diagnostics for 'conftest.c', which is the file autoconf uses # for its tests (which frequently will have warnings). if os.path.basename(file) == 'conftest.c': diff --git a/llvm/utils/gn/secondary/llvm/lib/Analysis/BUILD.gn b/llvm/utils/gn/secondary/llvm/lib/Analysis/BUILD.gn index cbbe1499a560b..328d819fd1f05 100644 --- a/llvm/utils/gn/secondary/llvm/lib/Analysis/BUILD.gn +++ b/llvm/utils/gn/secondary/llvm/lib/Analysis/BUILD.gn @@ -84,7 +84,6 @@ static_library("Analysis") { "ObjCARCAnalysisUtils.cpp", "ObjCARCInstKind.cpp", "OptimizationRemarkEmitter.cpp", - "OrderedBasicBlock.cpp", "OrderedInstructions.cpp", "PHITransAddr.cpp", "PhiValues.cpp", diff --git a/llvm/utils/gn/secondary/llvm/unittests/Analysis/BUILD.gn b/llvm/utils/gn/secondary/llvm/unittests/Analysis/BUILD.gn index 1e4b1581722fa..76a055e989fc5 100644 --- a/llvm/utils/gn/secondary/llvm/unittests/Analysis/BUILD.gn +++ b/llvm/utils/gn/secondary/llvm/unittests/Analysis/BUILD.gn @@ -25,7 +25,6 @@ unittest("AnalysisTests") { "LoopInfoTest.cpp", "MemoryBuiltinsTest.cpp", "MemorySSATest.cpp", - "OrderedBasicBlockTest.cpp", "OrderedInstructionsTest.cpp", "PhiValuesTest.cpp", "ProfileSummaryInfoTest.cpp", diff --git a/llvm/utils/llvm-locstats/llvm-locstats.py b/llvm/utils/llvm-locstats/llvm-locstats.py index 7b2f706fca943..dec87f9caf7d3 100755 --- a/llvm/utils/llvm-locstats/llvm-locstats.py +++ b/llvm/utils/llvm-locstats/llvm-locstats.py @@ -121,14 +121,16 @@ def draw_location_diff(self, locstats_to_compare): ax = fig.add_subplot(111) init_plot(plt) + comparison_keys = list(coverage_buckets()) ax.bar(buckets, self.variables_coverage_map.values(), align='edge', - tick_label=self.variables_coverage_map.keys(), width=0.4, + width=0.4, label='variables of {}'.format(self.file_name)) ax.bar(buckets_to_compare, locstats_to_compare.variables_coverage_map.values(), color='r', align='edge', width=-0.4, - tick_label=locstats_to_compare.variables_coverage_map.keys(), label='variables of {}'.format(locstats_to_compare.file_name)) + ax.set_xticks(range(len(comparison_keys))) + ax.set_xticklabels(comparison_keys) props = dict(boxstyle='round', facecolor='wheat', alpha=0.5) plt.text(0.02, 0.88,