From e5d17c511fa603b557f86257b5b6f39b429f4e35 Mon Sep 17 00:00:00 2001 From: Yaxun Liu Date: Fri, 20 Sep 2019 14:28:09 +0000 Subject: [PATCH 01/71] [CUDA][HIP] Fix hostness of defaulted constructor Clang does not respect the explicit device host attributes of defaulted special members. Also clang does not respect the hostness of special members determined by their first declarations. Clang also adds duplicate implicit device or host attributes in certain cases. This patch fixes that. Differential Revision: https://reviews.llvm.org/D67509 llvm-svn: 372394 --- clang/lib/Sema/SemaCUDA.cpp | 39 ++++++++++++++++++-------- clang/test/SemaCUDA/default-ctor.cu | 43 +++++++++++++++++++++++++++++ 2 files changed, 70 insertions(+), 12 deletions(-) create mode 100644 clang/test/SemaCUDA/default-ctor.cu diff --git a/clang/lib/Sema/SemaCUDA.cpp b/clang/lib/Sema/SemaCUDA.cpp index 203c09c57112b..e009dcb6f166f 100644 --- a/clang/lib/Sema/SemaCUDA.cpp +++ b/clang/lib/Sema/SemaCUDA.cpp @@ -267,6 +267,18 @@ bool Sema::inferCUDATargetForImplicitSpecialMember(CXXRecordDecl *ClassDecl, CXXMethodDecl *MemberDecl, bool ConstRHS, bool Diagnose) { + // If the defaulted special member is defined lexically outside of its + // owning class, or the special member already has explicit device or host + // attributes, do not infer. + bool InClass = MemberDecl->getLexicalParent() == MemberDecl->getParent(); + bool HasH = MemberDecl->hasAttr(); + bool HasD = MemberDecl->hasAttr(); + bool HasExplicitAttr = + (HasD && !MemberDecl->getAttr()->isImplicit()) || + (HasH && !MemberDecl->getAttr()->isImplicit()); + if (!InClass || HasExplicitAttr) + return false; + llvm::Optional InferredTarget; // We're going to invoke special member lookup; mark that these special @@ -371,21 +383,24 @@ bool Sema::inferCUDATargetForImplicitSpecialMember(CXXRecordDecl *ClassDecl, } } + + // If no target was inferred, mark this member as __host__ __device__; + // it's the least restrictive option that can be invoked from any target. + bool NeedsH = true, NeedsD = true; if (InferredTarget.hasValue()) { - if (InferredTarget.getValue() == CFT_Device) { - MemberDecl->addAttr(CUDADeviceAttr::CreateImplicit(Context)); - } else if (InferredTarget.getValue() == CFT_Host) { - MemberDecl->addAttr(CUDAHostAttr::CreateImplicit(Context)); - } else { - MemberDecl->addAttr(CUDADeviceAttr::CreateImplicit(Context)); - MemberDecl->addAttr(CUDAHostAttr::CreateImplicit(Context)); - } - } else { - // If no target was inferred, mark this member as __host__ __device__; - // it's the least restrictive option that can be invoked from any target. + if (InferredTarget.getValue() == CFT_Device) + NeedsH = false; + else if (InferredTarget.getValue() == CFT_Host) + NeedsD = false; + } + + // We either setting attributes first time, or the inferred ones must match + // previously set ones. + assert(!(HasD || HasH) || (NeedsD == HasD && NeedsH == HasH)); + if (NeedsD && !HasD) MemberDecl->addAttr(CUDADeviceAttr::CreateImplicit(Context)); + if (NeedsH && !HasH) MemberDecl->addAttr(CUDAHostAttr::CreateImplicit(Context)); - } return false; } diff --git a/clang/test/SemaCUDA/default-ctor.cu b/clang/test/SemaCUDA/default-ctor.cu new file mode 100644 index 0000000000000..cbad7a1774c15 --- /dev/null +++ b/clang/test/SemaCUDA/default-ctor.cu @@ -0,0 +1,43 @@ +// RUN: %clang_cc1 -std=c++11 -triple nvptx64-nvidia-cuda -fsyntax-only \ +// RUN: -fcuda-is-device -verify -verify-ignore-unexpected=note %s +// RUN: %clang_cc1 -std=c++11 -triple x86_64-unknown-linux-gnu -fsyntax-only \ +// RUN: -verify -verify-ignore-unexpected=note %s + +#include "Inputs/cuda.h" + +struct In { In() = default; }; +struct InD { __device__ InD() = default; }; +struct InH { __host__ InH() = default; }; +struct InHD { __host__ __device__ InHD() = default; }; + +struct Out { Out(); }; +struct OutD { __device__ OutD(); }; +struct OutH { __host__ OutH(); }; +struct OutHD { __host__ __device__ OutHD(); }; + +Out::Out() = default; +__device__ OutD::OutD() = default; +__host__ OutH::OutH() = default; +__host__ __device__ OutHD::OutHD() = default; + +__device__ void fd() { + In in; + InD ind; + InH inh; // expected-error{{no matching constructor for initialization of 'InH'}} + InHD inhd; + Out out; // expected-error{{no matching constructor for initialization of 'Out'}} + OutD outd; + OutH outh; // expected-error{{no matching constructor for initialization of 'OutH'}} + OutHD outhd; +} + +__host__ void fh() { + In in; + InD ind; // expected-error{{no matching constructor for initialization of 'InD'}} + InH inh; + InHD inhd; + Out out; + OutD outd; // expected-error{{no matching constructor for initialization of 'OutD'}} + OutH outh; + OutHD outhd; +} From 084801bdc1a798f30d3ecc183009c74809e051c5 Mon Sep 17 00:00:00 2001 From: Fangrui Song Date: Fri, 20 Sep 2019 14:31:42 +0000 Subject: [PATCH 02/71] Use llvm::StringLiteral instead of StringRef in few places llvm-svn: 372395 --- .../AMDGPU/AMDGPUAnnotateKernelFeatures.cpp | 18 ++++++------------ .../AMDGPU/AsmParser/AMDGPUAsmParser.cpp | 8 +------- llvm/lib/Target/X86/X86InsertPrefetch.cpp | 2 +- 3 files changed, 8 insertions(+), 20 deletions(-) diff --git a/llvm/lib/Target/AMDGPU/AMDGPUAnnotateKernelFeatures.cpp b/llvm/lib/Target/AMDGPU/AMDGPUAnnotateKernelFeatures.cpp index d8d2b6b899a42..e72b3f4fde633 100644 --- a/llvm/lib/Target/AMDGPU/AMDGPUAnnotateKernelFeatures.cpp +++ b/llvm/lib/Target/AMDGPU/AMDGPUAnnotateKernelFeatures.cpp @@ -197,18 +197,12 @@ static bool handleAttr(Function &Parent, const Function &Callee, static void copyFeaturesToFunction(Function &Parent, const Function &Callee, bool &NeedQueuePtr) { // X ids unnecessarily propagated to kernels. - static const StringRef AttrNames[] = { - { "amdgpu-work-item-id-x" }, - { "amdgpu-work-item-id-y" }, - { "amdgpu-work-item-id-z" }, - { "amdgpu-work-group-id-x" }, - { "amdgpu-work-group-id-y" }, - { "amdgpu-work-group-id-z" }, - { "amdgpu-dispatch-ptr" }, - { "amdgpu-dispatch-id" }, - { "amdgpu-kernarg-segment-ptr" }, - { "amdgpu-implicitarg-ptr" } - }; + static constexpr StringLiteral AttrNames[] = { + "amdgpu-work-item-id-x", "amdgpu-work-item-id-y", + "amdgpu-work-item-id-z", "amdgpu-work-group-id-x", + "amdgpu-work-group-id-y", "amdgpu-work-group-id-z", + "amdgpu-dispatch-ptr", "amdgpu-dispatch-id", + "amdgpu-kernarg-segment-ptr", "amdgpu-implicitarg-ptr"}; if (handleAttr(Parent, Callee, "amdgpu-queue-ptr")) NeedQueuePtr = true; diff --git a/llvm/lib/Target/AMDGPU/AsmParser/AMDGPUAsmParser.cpp b/llvm/lib/Target/AMDGPU/AsmParser/AMDGPUAsmParser.cpp index b8e91d3f3642a..462e0e8da1466 100644 --- a/llvm/lib/Target/AMDGPU/AsmParser/AMDGPUAsmParser.cpp +++ b/llvm/lib/Target/AMDGPU/AsmParser/AMDGPUAsmParser.cpp @@ -2017,13 +2017,7 @@ bool AMDGPUAsmParser::AddNextRegisterToList(unsigned &Reg, unsigned &RegWidth, } } -static const StringRef Registers[] = { - { "v" }, - { "s" }, - { "ttmp" }, - { "acc" }, - { "a" }, -}; +static constexpr StringLiteral Registers[] = {"v", "s", "ttmp", "acc", "a"}; bool AMDGPUAsmParser::isRegister(const AsmToken &Token, diff --git a/llvm/lib/Target/X86/X86InsertPrefetch.cpp b/llvm/lib/Target/X86/X86InsertPrefetch.cpp index 70225f0f4b27b..e0ce18a2f372a 100644 --- a/llvm/lib/Target/X86/X86InsertPrefetch.cpp +++ b/llvm/lib/Target/X86/X86InsertPrefetch.cpp @@ -108,7 +108,7 @@ bool X86InsertPrefetch::findPrefetchInfo(const FunctionSamples *TopSamples, Prefetches &Prefetches) const { assert(Prefetches.empty() && "Expected caller passed empty PrefetchInfo vector."); - static const std::pair HintTypes[] = { + static constexpr std::pair HintTypes[] = { {"_nta_", X86::PREFETCHNTA}, {"_t0_", X86::PREFETCHT0}, {"_t1_", X86::PREFETCHT1}, From 81669d5ead6fa555f13308771a6d4cd97f9a73c5 Mon Sep 17 00:00:00 2001 From: Cyndy Ishida Date: Fri, 20 Sep 2019 14:32:34 +0000 Subject: [PATCH 03/71] [TextAPI] Arch&Platform to Target Summary: This is a patch for updating TextAPI/Macho to read in targets as opposed to arch/platform. This is because in previous versions tbd files only supported a single platform but that is no longer the case, so, now its tracked by unique triples. This precedes a seperate patch that will add the TBD-v4 format Reviewers: ributzka, steven_wu, plotfi, compnerd, smeenai Reviewed By: ributzka Subscribers: mgorny, hiraditya, dexonsmith, llvm-commits Tags: #llvm Differential Revision: https://reviews.llvm.org/D67527 llvm-svn: 372396 --- .../include/llvm/TextAPI/MachO/Architecture.h | 4 + .../llvm/TextAPI/MachO/ArchitectureSet.h | 4 + .../llvm/TextAPI/MachO/InterfaceFile.h | 142 +++++++++++------- llvm/include/llvm/TextAPI/MachO/Platform.h | 40 +++++ llvm/include/llvm/TextAPI/MachO/Symbol.h | 26 +++- llvm/include/llvm/TextAPI/MachO/Target.h | 66 ++++++++ llvm/lib/Object/TapiFile.cpp | 4 +- llvm/lib/TextAPI/CMakeLists.txt | 2 + llvm/lib/TextAPI/MachO/Architecture.cpp | 4 + llvm/lib/TextAPI/MachO/InterfaceFile.cpp | 80 +++++++--- llvm/lib/TextAPI/MachO/Platform.cpp | 61 ++++++++ llvm/lib/TextAPI/MachO/Symbol.cpp | 9 ++ llvm/lib/TextAPI/MachO/Target.cpp | 45 ++++++ llvm/lib/TextAPI/MachO/TextStub.cpp | 86 ++++++----- llvm/lib/TextAPI/MachO/TextStubCommon.cpp | 39 +++-- llvm/lib/TextAPI/MachO/TextStubCommon.h | 8 +- llvm/tools/llvm-ifs/llvm-ifs.cpp | 27 +--- llvm/unittests/TextAPI/TextStubV1Tests.cpp | 64 +++++--- llvm/unittests/TextAPI/TextStubV2Tests.cpp | 67 ++++++--- llvm/unittests/TextAPI/TextStubV3Tests.cpp | 63 +++++--- 20 files changed, 615 insertions(+), 226 deletions(-) create mode 100644 llvm/include/llvm/TextAPI/MachO/Platform.h create mode 100644 llvm/include/llvm/TextAPI/MachO/Target.h create mode 100644 llvm/lib/TextAPI/MachO/Platform.cpp create mode 100644 llvm/lib/TextAPI/MachO/Target.cpp diff --git a/llvm/include/llvm/TextAPI/MachO/Architecture.h b/llvm/include/llvm/TextAPI/MachO/Architecture.h index 055baeb0c0f0c..3898cbada68f7 100644 --- a/llvm/include/llvm/TextAPI/MachO/Architecture.h +++ b/llvm/include/llvm/TextAPI/MachO/Architecture.h @@ -14,6 +14,7 @@ #define LLVM_TEXTAPI_MACHO_ARCHITECTURE_H #include "llvm/ADT/StringRef.h" +#include "llvm/ADT/Triple.h" #include "llvm/Support/raw_ostream.h" namespace llvm { @@ -39,6 +40,9 @@ StringRef getArchitectureName(Architecture Arch); /// Convert an architecture slice to a CPU Type and Subtype pair. std::pair getCPUTypeFromArchitecture(Architecture Arch); +/// Convert a target to an architecture slice. +Architecture mapToArchitecture(const llvm::Triple &Target); + raw_ostream &operator<<(raw_ostream &OS, Architecture Arch); } // end namespace MachO. diff --git a/llvm/include/llvm/TextAPI/MachO/ArchitectureSet.h b/llvm/include/llvm/TextAPI/MachO/ArchitectureSet.h index d8dfc7f1af214..6e4ede6275b4f 100644 --- a/llvm/include/llvm/TextAPI/MachO/ArchitectureSet.h +++ b/llvm/include/llvm/TextAPI/MachO/ArchitectureSet.h @@ -59,6 +59,10 @@ class ArchitectureSet { ArchSetType rawValue() const { return ArchSet; } + bool hasX86() const { + return has(AK_i386) || has(AK_x86_64) || has(AK_x86_64h); + } + template class arch_iterator : public std::iterator { diff --git a/llvm/include/llvm/TextAPI/MachO/InterfaceFile.h b/llvm/include/llvm/TextAPI/MachO/InterfaceFile.h index 323b05095856a..c85708f29b011 100644 --- a/llvm/include/llvm/TextAPI/MachO/InterfaceFile.h +++ b/llvm/include/llvm/TextAPI/MachO/InterfaceFile.h @@ -26,21 +26,13 @@ #include "llvm/TextAPI/MachO/Architecture.h" #include "llvm/TextAPI/MachO/ArchitectureSet.h" #include "llvm/TextAPI/MachO/PackedVersion.h" +#include "llvm/TextAPI/MachO/Platform.h" #include "llvm/TextAPI/MachO/Symbol.h" +#include "llvm/TextAPI/MachO/Target.h" namespace llvm { namespace MachO { -/// Defines the list of MachO platforms. -enum class PlatformKind : unsigned { - unknown, - macOS = MachO::PLATFORM_MACOS, - iOS = MachO::PLATFORM_IOS, - tvOS = MachO::PLATFORM_TVOS, - watchOS = MachO::PLATFORM_WATCHOS, - bridgeOS = MachO::PLATFORM_BRIDGEOS, -}; - /// Defines a list of Objective-C constraints. enum class ObjCConstraintType : unsigned { /// No constraint. @@ -89,29 +81,42 @@ class InterfaceFileRef { InterfaceFileRef(StringRef InstallName) : InstallName(InstallName) {} - InterfaceFileRef(StringRef InstallName, ArchitectureSet Archs) - : InstallName(InstallName), Architectures(Archs) {} + InterfaceFileRef(StringRef InstallName, const TargetList Targets) + : InstallName(InstallName), Targets(std::move(Targets)) {} StringRef getInstallName() const { return InstallName; }; - void addArchitectures(ArchitectureSet Archs) { Architectures |= Archs; } - ArchitectureSet getArchitectures() const { return Architectures; } - bool hasArchitecture(Architecture Arch) const { - return Architectures.has(Arch); + + void addTarget(const Target &Target); + template void addTargets(RangeT &&Targets) { + for (const auto &Target : Targets) + addTarget(Target(Target)); } + using const_target_iterator = TargetList::const_iterator; + using const_target_range = llvm::iterator_range; + const_target_range targets() const { return {Targets}; } + + ArchitectureSet getArchitectures() const { + return mapToArchitectureSet(Targets); + } + + PlatformSet getPlatforms() const { return mapToPlatformSet(Targets); } + bool operator==(const InterfaceFileRef &O) const { - return std::tie(InstallName, Architectures) == - std::tie(O.InstallName, O.Architectures); + return std::tie(InstallName, Targets) == std::tie(O.InstallName, O.Targets); + } + + bool operator!=(const InterfaceFileRef &O) const { + return std::tie(InstallName, Targets) != std::tie(O.InstallName, O.Targets); } bool operator<(const InterfaceFileRef &O) const { - return std::tie(InstallName, Architectures) < - std::tie(O.InstallName, O.Architectures); + return std::tie(InstallName, Targets) < std::tie(O.InstallName, O.Targets); } private: std::string InstallName; - ArchitectureSet Architectures; + TargetList Targets; }; } // end namespace MachO. @@ -170,27 +175,43 @@ class InterfaceFile { /// \return The file type. FileType getFileType() const { return FileKind; } - /// Set the platform. - void setPlatform(PlatformKind Platform_) { Platform = Platform_; } + /// Get the architectures. + /// + /// \return The applicable architectures. + ArchitectureSet getArchitectures() const { + return mapToArchitectureSet(Targets); + } - /// Get the platform. - PlatformKind getPlatform() const { return Platform; } + /// Get the platforms. + /// + /// \return The applicable platforms. + PlatformSet getPlatforms() const { return mapToPlatformSet(Targets); } - /// Specify the set of supported architectures by this file. - void setArchitectures(ArchitectureSet Architectures_) { - Architectures = Architectures_; - } + /// Set and add target. + /// + /// \param Target the target to add into. + void addTarget(const Target &Target); - /// Add the set of supported architectures by this file. - void addArchitectures(ArchitectureSet Architectures_) { - Architectures |= Architectures_; + /// Set and add targets. + /// + /// Add the subset of llvm::triples that is supported by Tapi + /// + /// \param Targets the collection of targets. + template void addTargets(RangeT &&Targets) { + for (const auto &Target_ : Targets) + addTarget(Target(Target_)); } - /// Add supported architecture by this file.. - void addArch(Architecture Arch) { Architectures.set(Arch); } + using const_target_iterator = TargetList::const_iterator; + using const_target_range = llvm::iterator_range; + const_target_range targets() const { return {Targets}; } - /// Get the set of supported architectures. - ArchitectureSet getArchitectures() const { return Architectures; } + using const_filtered_target_iterator = + llvm::filter_iterator>; + using const_filtered_target_range = + llvm::iterator_range; + const_filtered_target_range targets(ArchitectureSet Archs) const; /// Set the install name of the library. void setInstallName(StringRef InstallName_) { InstallName = InstallName_; } @@ -244,11 +265,18 @@ class InterfaceFile { /// Check if this file was generated during InstallAPI. bool isInstallAPI() const { return IsInstallAPI; } - /// Set the parent umbrella framework. - void setParentUmbrella(StringRef Parent) { ParentUmbrella = Parent; } + /// Set the parent umbrella frameworks. + /// \param Target_ The target applicable to Parent + /// \param Parent The name of Parent + void addParentUmbrella(const Target &Target_, StringRef Parent); + const std::vector> &umbrellas() const { + return ParentUmbrellas; + } /// Get the parent umbrella framework. - StringRef getParentUmbrella() const { return ParentUmbrella; } + const std::vector> getParentUmbrellas() const { + return ParentUmbrellas; + } /// Add an allowable client. /// @@ -258,8 +286,8 @@ class InterfaceFile { /// linker refuses to link this library. /// /// \param Name The name of the client that is allowed to link this library. - /// \param Architectures The set of architecture for which this applies. - void addAllowableClient(StringRef Name, ArchitectureSet Architectures); + /// \param Target The target triple for which this applies. + void addAllowableClient(StringRef InstallName, const Target &Target); /// Get the list of allowable clients. /// @@ -271,9 +299,8 @@ class InterfaceFile { /// Add a re-exported library. /// /// \param InstallName The name of the library to re-export. - /// \param Architectures The set of architecture for which this applies. - void addReexportedLibrary(StringRef InstallName, - ArchitectureSet Architectures); + /// \param Target The target triple for which this applies. + void addReexportedLibrary(StringRef InstallName, const Target &Target); /// Get the list of re-exported libraries. /// @@ -282,27 +309,27 @@ class InterfaceFile { return ReexportedLibraries; } - /// Add an architecture/UUID pair. + /// Add an Target/UUID pair. /// - /// \param Arch The architecture for which this applies. + /// \param Target The target triple for which this applies. /// \param UUID The UUID of the library for the specified architecture. - void addUUID(Architecture Arch, StringRef UUID); + void addUUID(const Target &Target, StringRef UUID); - /// Add an architecture/UUID pair. + /// Add an Target/UUID pair. /// - /// \param Arch The architecture for which this applies. + /// \param Target The target triple for which this applies. /// \param UUID The UUID of the library for the specified architecture. - void addUUID(Architecture Arch, uint8_t UUID[16]); + void addUUID(const Target &Target, uint8_t UUID[16]); - /// Get the list of architecture/UUID pairs. + /// Get the list of Target/UUID pairs. /// - /// \return Returns a list of architecture/UUID pairs. - const std::vector> &uuids() const { + /// \return Returns a list of Target/UUID pairs. + const std::vector> &uuids() const { return UUIDs; } /// Add a symbol to the symbols list or extend an existing one. - void addSymbol(SymbolKind Kind, StringRef Name, ArchitectureSet Architectures, + void addSymbol(SymbolKind Kind, StringRef Name, const TargetList &Targets, SymbolFlags Flags = SymbolFlags::None); using SymbolMapType = DenseMap; @@ -362,10 +389,9 @@ class InterfaceFile { return StringRef(reinterpret_cast(Ptr), String.size()); } + TargetList Targets; std::string Path; FileType FileKind; - PlatformKind Platform; - ArchitectureSet Architectures; std::string InstallName; PackedVersion CurrentVersion; PackedVersion CompatibilityVersion; @@ -374,10 +400,10 @@ class InterfaceFile { bool IsAppExtensionSafe{false}; bool IsInstallAPI{false}; ObjCConstraintType ObjcConstraint = ObjCConstraintType::None; - std::string ParentUmbrella; + std::vector> ParentUmbrellas; std::vector AllowableClients; std::vector ReexportedLibraries; - std::vector> UUIDs; + std::vector> UUIDs; SymbolMapType Symbols; }; diff --git a/llvm/include/llvm/TextAPI/MachO/Platform.h b/llvm/include/llvm/TextAPI/MachO/Platform.h new file mode 100644 index 0000000000000..2928cffe678ad --- /dev/null +++ b/llvm/include/llvm/TextAPI/MachO/Platform.h @@ -0,0 +1,40 @@ +//===- llvm/TextAPI/MachO/Platform.h - Platform -----------------*- 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 +// +//===----------------------------------------------------------------------===// +// +// Defines the Platforms supported by Tapi and helpers. +// +//===----------------------------------------------------------------------===// +#ifndef LLVM_TEXTAPI_MACHO_PLATFORM_H +#define LLVM_TEXTAPI_MACHO_PLATFORM_H + +#include "llvm/ADT/SmallSet.h" +#include "llvm/BinaryFormat/MachO.h" + +namespace llvm { +namespace MachO { + +/// Defines the list of MachO platforms. +enum class PlatformKind : unsigned { + unknown, + macOS = MachO::PLATFORM_MACOS, + iOS = MachO::PLATFORM_IOS, + tvOS = MachO::PLATFORM_TVOS, + watchOS = MachO::PLATFORM_WATCHOS, + bridgeOS = MachO::PLATFORM_BRIDGEOS +}; + +using PlatformSet = SmallSet; + +PlatformKind mapToPlatformKind(const Triple &Target); +PlatformSet mapToPlatformSet(ArrayRef Targets); +StringRef getPlatformName(PlatformKind Platform); + +} // end namespace MachO. +} // end namespace llvm. + +#endif // LLVM_TEXTAPI_MACHO_PLATFORM_H \ No newline at end of file diff --git a/llvm/include/llvm/TextAPI/MachO/Symbol.h b/llvm/include/llvm/TextAPI/MachO/Symbol.h index 3c7ff5e0f4ea3..b6444fbd78ff7 100644 --- a/llvm/include/llvm/TextAPI/MachO/Symbol.h +++ b/llvm/include/llvm/TextAPI/MachO/Symbol.h @@ -14,6 +14,7 @@ #include "llvm/Support/Error.h" #include "llvm/Support/raw_ostream.h" #include "llvm/TextAPI/MachO/ArchitectureSet.h" +#include "llvm/TextAPI/MachO/Target.h" namespace llvm { namespace MachO { @@ -49,16 +50,18 @@ enum class SymbolKind : uint8_t { ObjectiveCInstanceVariable, }; +using TargetList = SmallVector; class Symbol { public: - constexpr Symbol(SymbolKind Kind, StringRef Name, - ArchitectureSet Architectures, SymbolFlags Flags) - : Name(Name), Architectures(Architectures), Kind(Kind), Flags(Flags) {} + Symbol(SymbolKind Kind, StringRef Name, TargetList Targets, SymbolFlags Flags) + : Name(Name), Targets(std::move(Targets)), Kind(Kind), Flags(Flags) {} + void addTarget(Target target) { Targets.emplace_back(target); } SymbolKind getKind() const { return Kind; } StringRef getName() const { return Name; } - ArchitectureSet getArchitectures() const { return Architectures; } - void addArchitectures(ArchitectureSet Archs) { Architectures |= Archs; } + ArchitectureSet getArchitectures() const { + return mapToArchitectureSet(Targets); + } SymbolFlags getFlags() const { return Flags; } bool isWeakDefined() const { @@ -78,6 +81,17 @@ class Symbol { return (Flags & SymbolFlags::Undefined) == SymbolFlags::Undefined; } + using const_target_iterator = TargetList::const_iterator; + using const_target_range = llvm::iterator_range; + const_target_range targets() const { return {Targets}; } + + using const_filtered_target_iterator = + llvm::filter_iterator>; + using const_filtered_target_range = + llvm::iterator_range; + const_filtered_target_range targets(ArchitectureSet architectures) const; + #if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP) void dump(raw_ostream &OS) const; void dump() const { dump(llvm::errs()); } @@ -85,7 +99,7 @@ class Symbol { private: StringRef Name; - ArchitectureSet Architectures; + TargetList Targets; SymbolKind Kind; SymbolFlags Flags; }; diff --git a/llvm/include/llvm/TextAPI/MachO/Target.h b/llvm/include/llvm/TextAPI/MachO/Target.h new file mode 100644 index 0000000000000..74e900d812f52 --- /dev/null +++ b/llvm/include/llvm/TextAPI/MachO/Target.h @@ -0,0 +1,66 @@ +//===- llvm/TextAPI/Target.h - TAPI Target ----------------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_TEXTAPI_MACHO_TARGET_H +#define LLVM_TEXTAPI_MACHO_TARGET_H + +#include "llvm/ADT/Triple.h" +#include "llvm/Support/Error.h" +#include "llvm/TextAPI/MachO/Architecture.h" +#include "llvm/TextAPI/MachO/ArchitectureSet.h" +#include "llvm/TextAPI/MachO/Platform.h" + +namespace llvm { +namespace MachO { + +// This is similar to a llvm Triple, but the triple doesn't have all the +// information we need. For example there is no enum value for x86_64h. The +// only way to get that information is to parse the triple string. +class Target { +public: + Target() = default; + Target(Architecture Arch, PlatformKind Platform) + : Arch(Arch), Platform(Platform) {} + explicit Target(const llvm::Triple &Triple) + : Arch(mapToArchitecture(Triple)), Platform(mapToPlatformKind(Triple)) {} + + operator std::string() const; + + Architecture Arch; + PlatformKind Platform; +}; + +inline bool operator==(const Target &LHS, const Target &RHS) { + return std::tie(LHS.Arch, LHS.Platform) == std::tie(RHS.Arch, RHS.Platform); +} + +inline bool operator!=(const Target &LHS, const Target &RHS) { + return std::tie(LHS.Arch, LHS.Platform) != std::tie(RHS.Arch, RHS.Platform); +} + +inline bool operator<(const Target &LHS, const Target &RHS) { + return std::tie(LHS.Arch, LHS.Platform) < std::tie(RHS.Arch, RHS.Platform); +} + +inline bool operator==(const Target &LHS, const Architecture &RHS) { + return LHS.Arch == RHS; +} + +inline bool operator!=(const Target &LHS, const Architecture &RHS) { + return LHS.Arch != RHS; +} + +PlatformSet mapToPlatformSet(ArrayRef Targets); +ArchitectureSet mapToArchitectureSet(ArrayRef Targets); + +raw_ostream &operator<<(raw_ostream &OS, const Target &Target); + +} // namespace MachO +} // namespace llvm + +#endif // LLVM_TEXTAPI_MACHO_TARGET_H diff --git a/llvm/lib/Object/TapiFile.cpp b/llvm/lib/Object/TapiFile.cpp index 4d9fe7d9e8ac1..c409bd8e59951 100644 --- a/llvm/lib/Object/TapiFile.cpp +++ b/llvm/lib/Object/TapiFile.cpp @@ -45,13 +45,13 @@ TapiFile::TapiFile(MemoryBufferRef Source, const InterfaceFile &interface, if (!Symbol->getArchitectures().has(Arch)) continue; - auto Platform = interface.getPlatform(); switch (Symbol->getKind()) { case SymbolKind::GlobalSymbol: Symbols.emplace_back(StringRef(), Symbol->getName(), getFlags(Symbol)); break; case SymbolKind::ObjectiveCClass: - if (Platform == PlatformKind::macOS && Arch == AK_i386) { + if (interface.getPlatforms().count(PlatformKind::macOS) && + Arch == AK_i386) { Symbols.emplace_back(ObjC1ClassNamePrefix, Symbol->getName(), getFlags(Symbol)); } else { diff --git a/llvm/lib/TextAPI/CMakeLists.txt b/llvm/lib/TextAPI/CMakeLists.txt index 91b776b2caa6f..d959fb972a802 100644 --- a/llvm/lib/TextAPI/CMakeLists.txt +++ b/llvm/lib/TextAPI/CMakeLists.txt @@ -5,7 +5,9 @@ add_llvm_library(LLVMTextAPI MachO/ArchitectureSet.cpp MachO/InterfaceFile.cpp MachO/PackedVersion.cpp + MachO/Platform.cpp MachO/Symbol.cpp + MachO/Target.cpp MachO/TextStub.cpp MachO/TextStubCommon.cpp diff --git a/llvm/lib/TextAPI/MachO/Architecture.cpp b/llvm/lib/TextAPI/MachO/Architecture.cpp index a66a982fa1532..699fb5f4587ad 100644 --- a/llvm/lib/TextAPI/MachO/Architecture.cpp +++ b/llvm/lib/TextAPI/MachO/Architecture.cpp @@ -68,6 +68,10 @@ std::pair getCPUTypeFromArchitecture(Architecture Arch) { return std::make_pair(0, 0); } +Architecture mapToArchitecture(const Triple &Target) { + return getArchitectureFromName(Target.getArchName()); +} + raw_ostream &operator<<(raw_ostream &OS, Architecture Arch) { OS << getArchitectureName(Arch); return OS; diff --git a/llvm/lib/TextAPI/MachO/InterfaceFile.cpp b/llvm/lib/TextAPI/MachO/InterfaceFile.cpp index 54ba8cc312673..c40a952a6a8bd 100644 --- a/llvm/lib/TextAPI/MachO/InterfaceFile.cpp +++ b/llvm/lib/TextAPI/MachO/InterfaceFile.cpp @@ -27,36 +27,65 @@ typename C::iterator addEntry(C &Container, StringRef InstallName) { return Container.emplace(I, InstallName); } + +template +typename C::iterator addEntry(C &Container, const Target &Target_) { + auto Iter = + lower_bound(Container, Target_, [](const Target &LHS, const Target &RHS) { + return LHS < RHS; + }); + if ((Iter != std::end(Container)) && !(Target_ < *Iter)) + return Iter; + + return Container.insert(Iter, Target_); +} } // end namespace detail. -void InterfaceFile::addAllowableClient(StringRef Name, - ArchitectureSet Architectures) { - auto Client = detail::addEntry(AllowableClients, Name); - Client->addArchitectures(Architectures); +void InterfaceFileRef::addTarget(const Target &Target) { + detail::addEntry(Targets, Target); +} + +void InterfaceFile::addAllowableClient(StringRef InstallName, + const Target &Target) { + auto Client = detail::addEntry(AllowableClients, InstallName); + Client->addTarget(Target); } void InterfaceFile::addReexportedLibrary(StringRef InstallName, - ArchitectureSet Architectures) { + const Target &Target) { auto Lib = detail::addEntry(ReexportedLibraries, InstallName); - Lib->addArchitectures(Architectures); + Lib->addTarget(Target); } -void InterfaceFile::addUUID(Architecture Arch, StringRef UUID) { - auto I = partition_point(UUIDs, - [=](const std::pair &O) { - return O.first < Arch; - }); +void InterfaceFile::addParentUmbrella(const Target &Target_, StringRef Parent) { + auto Iter = lower_bound(ParentUmbrellas, Target_, + [](const std::pair &LHS, + Target RHS) { return LHS.first < RHS; }); - if (I != UUIDs.end() && Arch == I->first) { - I->second = UUID; + if ((Iter != ParentUmbrellas.end()) && !(Target_ < Iter->first)) { + Iter->second = Parent; return; } - UUIDs.emplace(I, Arch, UUID); + ParentUmbrellas.emplace(Iter, Target_, Parent); return; } -void InterfaceFile::addUUID(Architecture Arch, uint8_t UUID[16]) { +void InterfaceFile::addUUID(const Target &Target_, StringRef UUID) { + auto Iter = lower_bound(UUIDs, Target_, + [](const std::pair &LHS, + Target RHS) { return LHS.first < RHS; }); + + if ((Iter != UUIDs.end()) && !(Target_ < Iter->first)) { + Iter->second = UUID; + return; + } + + UUIDs.emplace(Iter, Target_, UUID); + return; +} + +void InterfaceFile::addUUID(const Target &Target, uint8_t UUID[16]) { std::stringstream Stream; for (unsigned i = 0; i < 16; ++i) { if (i == 4 || i == 6 || i == 8 || i == 10) @@ -64,17 +93,30 @@ void InterfaceFile::addUUID(Architecture Arch, uint8_t UUID[16]) { Stream << std::setfill('0') << std::setw(2) << std::uppercase << std::hex << static_cast(UUID[i]); } - addUUID(Arch, Stream.str()); + addUUID(Target, Stream.str()); +} + +void InterfaceFile::addTarget(const Target &Target) { + detail::addEntry(Targets, Target); +} + +InterfaceFile::const_filtered_target_range +InterfaceFile::targets(ArchitectureSet Archs) const { + std::function fn = [Archs](const Target &Target_) { + return Archs.has(Target_.Arch); + }; + return make_filter_range(Targets, fn); } void InterfaceFile::addSymbol(SymbolKind Kind, StringRef Name, - ArchitectureSet Archs, SymbolFlags Flags) { + const TargetList &Targets, SymbolFlags Flags) { Name = copyString(Name); auto result = Symbols.try_emplace(SymbolsMapKey{Kind, Name}, nullptr); if (result.second) - result.first->second = new (Allocator) Symbol{Kind, Name, Archs, Flags}; + result.first->second = new (Allocator) Symbol{Kind, Name, Targets, Flags}; else - result.first->second->addArchitectures(Archs); + for (const auto &Target : Targets) + result.first->second->addTarget(Target); } } // end namespace MachO. diff --git a/llvm/lib/TextAPI/MachO/Platform.cpp b/llvm/lib/TextAPI/MachO/Platform.cpp new file mode 100644 index 0000000000000..ec62a9b3edba6 --- /dev/null +++ b/llvm/lib/TextAPI/MachO/Platform.cpp @@ -0,0 +1,61 @@ +//===- llvm/TextAPI/MachO/Platform.cpp - Platform ---------------*- 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 +// +//===----------------------------------------------------------------------===// +// +// Implementations of Platform Helper functions. +// +//===----------------------------------------------------------------------===// + +#include "llvm/ADT/ArrayRef.h" +#include "llvm/ADT/Triple.h" +#include "llvm/TextAPI/MachO/Platform.h" + +namespace llvm { +namespace MachO { + +PlatformKind mapToPlatformKind(const Triple &Target) { + switch (Target.getOS()) { + default: + return PlatformKind::unknown; + case Triple::MacOSX: + return PlatformKind::macOS; + case Triple::IOS: + return PlatformKind::iOS; + case Triple::TvOS: + return PlatformKind::tvOS; + case Triple::WatchOS: + return PlatformKind::watchOS; + // TODO: add bridgeOS once in llvm::Triple + } +} + +PlatformSet mapToPlatformSet(ArrayRef Targets) { + PlatformSet Result; + for (const auto &Target : Targets) + Result.insert(mapToPlatformKind(Target)); + return Result; +} + +StringRef getPlatformName(PlatformKind Platform) { + switch (Platform) { + case PlatformKind::unknown: + return "unknown"; + case PlatformKind::macOS: + return "macOS"; + case PlatformKind::iOS: + return "iOS"; + case PlatformKind::tvOS: + return "tvOS"; + case PlatformKind::watchOS: + return "watchOS"; + case PlatformKind::bridgeOS: + return "bridgeOS"; + } +} + +} // end namespace MachO. +} // end namespace llvm. \ No newline at end of file diff --git a/llvm/lib/TextAPI/MachO/Symbol.cpp b/llvm/lib/TextAPI/MachO/Symbol.cpp index 731b264f6082d..9f2d8172beed4 100644 --- a/llvm/lib/TextAPI/MachO/Symbol.cpp +++ b/llvm/lib/TextAPI/MachO/Symbol.cpp @@ -45,5 +45,14 @@ LLVM_DUMP_METHOD void Symbol::dump(raw_ostream &OS) const { } #endif +Symbol::const_filtered_target_range +Symbol::targets(ArchitectureSet Architectures) const { + std::function FN = + [Architectures](const Target &Target) { + return Architectures.has(Target.Arch); + }; + return make_filter_range(Targets, FN); +} + } // end namespace MachO. } // end namespace llvm. diff --git a/llvm/lib/TextAPI/MachO/Target.cpp b/llvm/lib/TextAPI/MachO/Target.cpp new file mode 100644 index 0000000000000..3052aa53ac233 --- /dev/null +++ b/llvm/lib/TextAPI/MachO/Target.cpp @@ -0,0 +1,45 @@ +//===- tapi/Core/Target.cpp - Target ----------------------------*- 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 "llvm/ADT/SmallString.h" +#include "llvm/ADT/SmallVector.h" +#include "llvm/ADT/StringExtras.h" +#include "llvm/ADT/StringSwitch.h" +#include "llvm/Support/Format.h" +#include "llvm/Support/raw_ostream.h" +#include "llvm/TextAPI/MachO/Target.h" + +namespace llvm { +namespace MachO { + +Target::operator std::string() const { + return (getArchitectureName(Arch) + " (" + getPlatformName(Platform) + ")") + .str(); +} + +raw_ostream &operator<<(raw_ostream &OS, const Target &Target) { + OS << std::string(Target); + return OS; +} + +PlatformSet mapToPlatformSet(ArrayRef Targets) { + PlatformSet Result; + for (const auto &Target : Targets) + Result.insert(Target.Platform); + return Result; +} + +ArchitectureSet mapToArchitectureSet(ArrayRef Targets) { + ArchitectureSet Result; + for (const auto &Target : Targets) + Result.set(Target.Arch); + return Result; +} + +} // end namespace MachO. +} // end namespace llvm. \ No newline at end of file diff --git a/llvm/lib/TextAPI/MachO/TextStub.cpp b/llvm/lib/TextAPI/MachO/TextStub.cpp index 371866736c024..1f1d39ee0187d 100644 --- a/llvm/lib/TextAPI/MachO/TextStub.cpp +++ b/llvm/lib/TextAPI/MachO/TextStub.cpp @@ -246,7 +246,7 @@ template <> struct MappingTraits { NormalizedTBD(IO &IO, const InterfaceFile *&File) { Architectures = File->getArchitectures(); UUIDs = File->uuids(); - Platform = File->getPlatform(); + Platforms = File->getPlatforms(); InstallName = File->getInstallName(); CurrentVersion = PackedVersion(File->getCurrentVersion()); CompatibilityVersion = PackedVersion(File->getCompatibilityVersion()); @@ -263,7 +263,10 @@ template <> struct MappingTraits { if (File->isInstallAPI()) Flags |= TBDFlags::InstallAPI; - ParentUmbrella = File->getParentUmbrella(); + for (const auto &Iter : File->umbrellas()) { + ParentUmbrella = Iter.second; + break; + } std::set ArchSet; for (const auto &Library : File->allowableClients()) @@ -396,6 +399,17 @@ template <> struct MappingTraits { } } + TargetList synthesizeTargets(ArchitectureSet Architectures, + const PlatformSet &Platforms) { + TargetList Targets; + + for (auto Platform : Platforms) { + for (const auto &&Architecture : Architectures) + Targets.emplace_back(Architecture, Platform); + } + return Targets; + } + const InterfaceFile *denormalize(IO &IO) { auto Ctx = reinterpret_cast(IO.getContext()); assert(Ctx); @@ -403,16 +417,16 @@ template <> struct MappingTraits { auto *File = new InterfaceFile; File->setPath(Ctx->Path); File->setFileType(Ctx->FileKind); + File->addTargets(synthesizeTargets(Architectures, Platforms)); for (auto &ID : UUIDs) File->addUUID(ID.first, ID.second); - File->setPlatform(Platform); - File->setArchitectures(Architectures); File->setInstallName(InstallName); File->setCurrentVersion(CurrentVersion); File->setCompatibilityVersion(CompatibilityVersion); File->setSwiftABIVersion(SwiftABIVersion); File->setObjCConstraint(ObjCConstraint); - File->setParentUmbrella(ParentUmbrella); + for (const auto &Target : File->targets()) + File->addParentUmbrella(Target, ParentUmbrella); if (Ctx->FileKind == FileType::TBD_V1) { File->setTwoLevelNamespace(); @@ -425,76 +439,80 @@ template <> struct MappingTraits { } for (const auto &Section : Exports) { - for (const auto &Library : Section.AllowableClients) - File->addAllowableClient(Library, Section.Architectures); - for (const auto &Library : Section.ReexportedLibraries) - File->addReexportedLibrary(Library, Section.Architectures); + const auto Targets = + synthesizeTargets(Section.Architectures, Platforms); + + for (const auto &Lib : Section.AllowableClients) + for (const auto &Target : Targets) + File->addAllowableClient(Lib, Target); + + for (const auto &Lib : Section.ReexportedLibraries) + for (const auto &Target : Targets) + File->addReexportedLibrary(Lib, Target); for (const auto &Symbol : Section.Symbols) { if (Ctx->FileKind != FileType::TBD_V3 && Symbol.value.startswith("_OBJC_EHTYPE_$_")) File->addSymbol(SymbolKind::ObjectiveCClassEHType, - Symbol.value.drop_front(15), Section.Architectures); + Symbol.value.drop_front(15), Targets); else - File->addSymbol(SymbolKind::GlobalSymbol, Symbol, - Section.Architectures); + File->addSymbol(SymbolKind::GlobalSymbol, Symbol, Targets); } for (auto &Symbol : Section.Classes) { auto Name = Symbol.value; if (Ctx->FileKind != FileType::TBD_V3) Name = Name.drop_front(); - File->addSymbol(SymbolKind::ObjectiveCClass, Name, - Section.Architectures); + File->addSymbol(SymbolKind::ObjectiveCClass, Name, Targets); } for (auto &Symbol : Section.ClassEHs) - File->addSymbol(SymbolKind::ObjectiveCClassEHType, Symbol, - Section.Architectures); + File->addSymbol(SymbolKind::ObjectiveCClassEHType, Symbol, Targets); for (auto &Symbol : Section.IVars) { auto Name = Symbol.value; if (Ctx->FileKind != FileType::TBD_V3) Name = Name.drop_front(); File->addSymbol(SymbolKind::ObjectiveCInstanceVariable, Name, - Section.Architectures); + Targets); } for (auto &Symbol : Section.WeakDefSymbols) - File->addSymbol(SymbolKind::GlobalSymbol, Symbol, - Section.Architectures, SymbolFlags::WeakDefined); + File->addSymbol(SymbolKind::GlobalSymbol, Symbol, Targets, + SymbolFlags::WeakDefined); for (auto &Symbol : Section.TLVSymbols) - File->addSymbol(SymbolKind::GlobalSymbol, Symbol, - Section.Architectures, SymbolFlags::ThreadLocalValue); + File->addSymbol(SymbolKind::GlobalSymbol, Symbol, Targets, + SymbolFlags::ThreadLocalValue); } for (const auto &Section : Undefineds) { + const auto Targets = + synthesizeTargets(Section.Architectures, Platforms); for (auto &Symbol : Section.Symbols) { if (Ctx->FileKind != FileType::TBD_V3 && Symbol.value.startswith("_OBJC_EHTYPE_$_")) File->addSymbol(SymbolKind::ObjectiveCClassEHType, - Symbol.value.drop_front(15), Section.Architectures, + Symbol.value.drop_front(15), Targets, SymbolFlags::Undefined); else - File->addSymbol(SymbolKind::GlobalSymbol, Symbol, - Section.Architectures, SymbolFlags::Undefined); + File->addSymbol(SymbolKind::GlobalSymbol, Symbol, Targets, + SymbolFlags::Undefined); } for (auto &Symbol : Section.Classes) { auto Name = Symbol.value; if (Ctx->FileKind != FileType::TBD_V3) Name = Name.drop_front(); - File->addSymbol(SymbolKind::ObjectiveCClass, Name, - Section.Architectures, SymbolFlags::Undefined); + File->addSymbol(SymbolKind::ObjectiveCClass, Name, Targets, + SymbolFlags::Undefined); } for (auto &Symbol : Section.ClassEHs) - File->addSymbol(SymbolKind::ObjectiveCClassEHType, Symbol, - Section.Architectures, SymbolFlags::Undefined); + File->addSymbol(SymbolKind::ObjectiveCClassEHType, Symbol, Targets, + SymbolFlags::Undefined); for (auto &Symbol : Section.IVars) { auto Name = Symbol.value; if (Ctx->FileKind != FileType::TBD_V3) Name = Name.drop_front(); - File->addSymbol(SymbolKind::ObjectiveCInstanceVariable, Name, - Section.Architectures, SymbolFlags::Undefined); + File->addSymbol(SymbolKind::ObjectiveCInstanceVariable, Name, Targets, + SymbolFlags::Undefined); } for (auto &Symbol : Section.WeakRefSymbols) - File->addSymbol(SymbolKind::GlobalSymbol, Symbol, - Section.Architectures, + File->addSymbol(SymbolKind::GlobalSymbol, Symbol, Targets, SymbolFlags::Undefined | SymbolFlags::WeakReferenced); } @@ -513,7 +531,7 @@ template <> struct MappingTraits { std::vector Architectures; std::vector UUIDs; - PlatformKind Platform{PlatformKind::unknown}; + PlatformSet Platforms; StringRef InstallName; PackedVersion CurrentVersion; PackedVersion CompatibilityVersion; @@ -567,7 +585,7 @@ template <> struct MappingTraits { IO.mapRequired("archs", Keys->Architectures); if (Ctx->FileKind != FileType::TBD_V1) IO.mapOptional("uuids", Keys->UUIDs); - IO.mapRequired("platform", Keys->Platform); + IO.mapRequired("platform", Keys->Platforms); if (Ctx->FileKind != FileType::TBD_V1) IO.mapOptional("flags", Keys->Flags, TBDFlags::None); IO.mapRequired("install-name", Keys->InstallName); diff --git a/llvm/lib/TextAPI/MachO/TextStubCommon.cpp b/llvm/lib/TextAPI/MachO/TextStubCommon.cpp index 00382cd24573a..313b040557bd8 100644 --- a/llvm/lib/TextAPI/MachO/TextStubCommon.cpp +++ b/llvm/lib/TextAPI/MachO/TextStubCommon.cpp @@ -41,9 +41,10 @@ void ScalarEnumerationTraits::enumeration( IO.enumCase(Constraint, "gc", ObjCConstraintType::GC); } -void ScalarTraits::output(const PlatformKind &Value, void *, - raw_ostream &OS) { - switch (Value) { +void ScalarTraits::output(const PlatformSet &Values, void *IO, + raw_ostream &OS) { + assert(Values.size() == 1U); + switch (*Values.begin()) { default: llvm_unreachable("unexpected platform"); break; @@ -64,21 +65,26 @@ void ScalarTraits::output(const PlatformKind &Value, void *, break; } } -StringRef ScalarTraits::input(StringRef Scalar, void *, - PlatformKind &Value) { - Value = StringSwitch(Scalar) - .Case("macosx", PlatformKind::macOS) - .Case("ios", PlatformKind::iOS) - .Case("watchos", PlatformKind::watchOS) - .Case("tvos", PlatformKind::tvOS) - .Case("bridgeos", PlatformKind::bridgeOS) - .Default(PlatformKind::unknown); - - if (Value == PlatformKind::unknown) + +StringRef ScalarTraits::input(StringRef Scalar, void *IO, + PlatformSet &Values) { + auto Platform = StringSwitch(Scalar) + .Case("unknown", PlatformKind::unknown) + .Case("macosx", PlatformKind::macOS) + .Case("ios", PlatformKind::iOS) + .Case("watchos", PlatformKind::watchOS) + .Case("tvos", PlatformKind::tvOS) + .Case("bridgeos", PlatformKind::bridgeOS) + .Default(PlatformKind::unknown); + + if (Platform == PlatformKind::unknown) return "unknown platform"; + + Values.insert(Platform); return {}; } -QuotingType ScalarTraits::mustQuote(StringRef) { + +QuotingType ScalarTraits::mustQuote(StringRef) { return QuotingType::None; } @@ -166,10 +172,11 @@ StringRef ScalarTraits::input(StringRef Scalar, void *, UUID &Value) { auto UUID = Split.second.trim(); if (UUID.empty()) return "invalid uuid string pair"; - Value.first = getArchitectureFromName(Arch); Value.second = UUID; + Value.first = Target{getArchitectureFromName(Arch), PlatformKind::unknown}; return {}; } + QuotingType ScalarTraits::mustQuote(StringRef) { return QuotingType::Single; } diff --git a/llvm/lib/TextAPI/MachO/TextStubCommon.h b/llvm/lib/TextAPI/MachO/TextStubCommon.h index c4dd1075b1c83..a558cbcec9fb6 100644 --- a/llvm/lib/TextAPI/MachO/TextStubCommon.h +++ b/llvm/lib/TextAPI/MachO/TextStubCommon.h @@ -21,7 +21,7 @@ #include "llvm/TextAPI/MachO/InterfaceFile.h" #include "llvm/TextAPI/MachO/PackedVersion.h" -using UUID = std::pair; +using UUID = std::pair; LLVM_YAML_STRONG_TYPEDEF(llvm::StringRef, FlowStringRef) LLVM_YAML_STRONG_TYPEDEF(uint8_t, SwiftVersion) @@ -41,9 +41,9 @@ template <> struct ScalarEnumerationTraits { static void enumeration(IO &, MachO::ObjCConstraintType &); }; -template <> struct ScalarTraits { - static void output(const MachO::PlatformKind &, void *, raw_ostream &); - static StringRef input(StringRef, void *, MachO::PlatformKind &); +template <> struct ScalarTraits { + static void output(const MachO::PlatformSet &, void *, raw_ostream &); + static StringRef input(StringRef, void *, MachO::PlatformSet &); static QuotingType mustQuote(StringRef); }; diff --git a/llvm/tools/llvm-ifs/llvm-ifs.cpp b/llvm/tools/llvm-ifs/llvm-ifs.cpp index 9d6d8d9ec4c04..f329b46336321 100644 --- a/llvm/tools/llvm-ifs/llvm-ifs.cpp +++ b/llvm/tools/llvm-ifs/llvm-ifs.cpp @@ -220,21 +220,6 @@ static Expected> readInputFile(StringRef FilePath) { int writeTbdStub(const llvm::Triple &T, const std::set &Symbols, const StringRef Format, raw_ostream &Out) { - auto ArchOrError = - [](const llvm::Triple &T) -> llvm::Expected { - switch (T.getArch()) { - default: - return createStringError(errc::not_supported, "Invalid Architecture.\n"); - case llvm::Triple::ArchType::x86: - return AK_i386; - case llvm::Triple::ArchType::x86_64: - return AK_x86_64; - case llvm::Triple::ArchType::arm: - return AK_armv7; - case llvm::Triple::ArchType::aarch64: - return AK_arm64; - } - }(T); auto PlatformKindOrError = [](const llvm::Triple &T) -> llvm::Expected { @@ -256,19 +241,15 @@ int writeTbdStub(const llvm::Triple &T, const std::set &Symbols, return createStringError(errc::not_supported, "Invalid Platform.\n"); }(T); - if (!ArchOrError) - return -1; - if (!PlatformKindOrError) return -1; - Architecture Arch = ArchOrError.get(); PlatformKind Plat = PlatformKindOrError.get(); + TargetList Targets({Target(llvm::MachO::mapToArchitecture(T), Plat)}); InterfaceFile File; File.setFileType(FileType::TBD_V3); // Only supporting v3 for now. - File.setArchitectures(Arch); - File.setPlatform(Plat); + File.addTargets(Targets); for (const auto &Symbol : Symbols) { auto Name = Symbol.Name; @@ -286,9 +267,9 @@ int writeTbdStub(const llvm::Triple &T, const std::set &Symbols, break; } if (Symbol.Weak) - File.addSymbol(Kind, Name, Arch, SymbolFlags::WeakDefined); + File.addSymbol(Kind, Name, Targets, SymbolFlags::WeakDefined); else - File.addSymbol(Kind, Name, Arch); + File.addSymbol(Kind, Name, Targets); } SmallString<4096> Buffer; diff --git a/llvm/unittests/TextAPI/TextStubV1Tests.cpp b/llvm/unittests/TextAPI/TextStubV1Tests.cpp index 383bc41d4f104..4472b1c599350 100644 --- a/llvm/unittests/TextAPI/TextStubV1Tests.cpp +++ b/llvm/unittests/TextAPI/TextStubV1Tests.cpp @@ -87,8 +87,13 @@ TEST(TBDv1, ReadFile) { auto File = std::move(Result.get()); EXPECT_EQ(FileType::TBD_V1, File->getFileType()); auto Archs = AK_armv7 | AK_armv7s | AK_armv7k | AK_arm64; + auto Platform = PlatformKind::iOS; + TargetList Targets; + for (auto &&arch : Archs) + Targets.emplace_back(Target(arch, Platform)); EXPECT_EQ(Archs, File->getArchitectures()); - EXPECT_EQ(PlatformKind::iOS, File->getPlatform()); + EXPECT_EQ(File->getPlatforms().size(), 1U); + EXPECT_EQ(Platform, *File->getPlatforms().begin()); EXPECT_EQ(std::string("Test.dylib"), File->getInstallName()); EXPECT_EQ(PackedVersion(2, 3, 4), File->getCurrentVersion()); EXPECT_EQ(PackedVersion(1, 0, 0), File->getCompatibilityVersion()); @@ -97,8 +102,8 @@ TEST(TBDv1, ReadFile) { EXPECT_TRUE(File->isTwoLevelNamespace()); EXPECT_TRUE(File->isApplicationExtensionSafe()); EXPECT_FALSE(File->isInstallAPI()); - InterfaceFileRef client("clientA", Archs); - InterfaceFileRef reexport("/usr/lib/libfoo.dylib", Archs); + InterfaceFileRef client("clientA", Targets); + InterfaceFileRef reexport("/usr/lib/libfoo.dylib", Targets); EXPECT_EQ(1U, File->allowableClients().size()); EXPECT_EQ(client, File->allowableClients().front()); EXPECT_EQ(1U, File->reexportedLibraries().size()); @@ -117,6 +122,10 @@ TEST(TBDv1, ReadFile) { EXPECT_EQ(sizeof(TBDv1Symbols) / sizeof(ExportedSymbol), Exports.size()); EXPECT_TRUE( std::equal(Exports.begin(), Exports.end(), std::begin(TBDv1Symbols))); + + File->addSymbol(SymbolKind::ObjectiveCClassEHType, "Class1", {Targets[1]}); + File->addSymbol(SymbolKind::ObjectiveCInstanceVariable, "Class1._ivar1", + {Targets[1]}); } TEST(TBDv1, ReadFile2) { @@ -131,8 +140,13 @@ TEST(TBDv1, ReadFile2) { auto File = std::move(Result.get()); EXPECT_EQ(FileType::TBD_V1, File->getFileType()); auto Archs = AK_armv7 | AK_armv7s | AK_armv7k | AK_arm64; + auto Platform = PlatformKind::iOS; + TargetList Targets; + for (auto &&arch : Archs) + Targets.emplace_back(Target(arch, Platform)); EXPECT_EQ(Archs, File->getArchitectures()); - EXPECT_EQ(PlatformKind::iOS, File->getPlatform()); + EXPECT_EQ(File->getPlatforms().size(), 1U); + EXPECT_EQ(Platform, *File->getPlatforms().begin()); EXPECT_EQ(std::string("Test.dylib"), File->getInstallName()); EXPECT_EQ(PackedVersion(1, 0, 0), File->getCurrentVersion()); EXPECT_EQ(PackedVersion(1, 0, 0), File->getCompatibilityVersion()); @@ -169,25 +183,27 @@ TEST(TBDv1, WriteFile) { "...\n"; InterfaceFile File; + TargetList Targets; + for (auto &&arch : AK_i386 | AK_x86_64) + Targets.emplace_back(Target(arch, PlatformKind::macOS)); File.setPath("libfoo.dylib"); File.setInstallName("/usr/lib/libfoo.dylib"); File.setFileType(FileType::TBD_V1); - File.setArchitectures(AK_i386 | AK_x86_64); - File.setPlatform(PlatformKind::macOS); + File.addTargets(Targets); File.setCurrentVersion(PackedVersion(1, 2, 3)); File.setSwiftABIVersion(5); File.setObjCConstraint(ObjCConstraintType::Retain_Release); - File.addAllowableClient("clientA", AK_x86_64); - File.addReexportedLibrary("/usr/lib/libfoo.dylib", AK_x86_64); - File.addSymbol(SymbolKind::GlobalSymbol, "_sym1", AK_i386); - File.addSymbol(SymbolKind::GlobalSymbol, "_sym2", AK_i386, + File.addAllowableClient("clientA", Targets[1]); + File.addReexportedLibrary("/usr/lib/libfoo.dylib", Targets[1]); + File.addSymbol(SymbolKind::GlobalSymbol, "_sym1", {Targets[0]}); + File.addSymbol(SymbolKind::GlobalSymbol, "_sym2", {Targets[0]}, SymbolFlags::WeakDefined); - File.addSymbol(SymbolKind::GlobalSymbol, "_sym3", AK_i386, + File.addSymbol(SymbolKind::GlobalSymbol, "_sym3", {Targets[0]}, SymbolFlags::ThreadLocalValue); - File.addSymbol(SymbolKind::ObjectiveCClass, "Class1", AK_x86_64); - File.addSymbol(SymbolKind::ObjectiveCClassEHType, "Class1", AK_x86_64); + File.addSymbol(SymbolKind::ObjectiveCClass, "Class1", {Targets[1]}); + File.addSymbol(SymbolKind::ObjectiveCClassEHType, "Class1", {Targets[1]}); File.addSymbol(SymbolKind::ObjectiveCInstanceVariable, "Class1._ivar1", - AK_x86_64); + {Targets[1]}); SmallString<4096> Buffer; raw_svector_ostream OS(Buffer); @@ -206,9 +222,11 @@ TEST(TBDv1, Platform_macOS) { auto Result = TextAPIReader::get(MemoryBufferRef(tbd_v1_platform_macos, "Test.tbd")); EXPECT_TRUE(!!Result); + auto Platform = PlatformKind::macOS; auto File = std::move(Result.get()); EXPECT_EQ(FileType::TBD_V1, File->getFileType()); - EXPECT_EQ(PlatformKind::macOS, File->getPlatform()); + EXPECT_EQ(File->getPlatforms().size(), 1U); + EXPECT_EQ(Platform, *File->getPlatforms().begin()); } TEST(TBDv1, Platform_iOS) { @@ -221,9 +239,11 @@ TEST(TBDv1, Platform_iOS) { auto Result = TextAPIReader::get(MemoryBufferRef(tbd_v1_platform_ios, "Test.tbd")); EXPECT_TRUE(!!Result); + auto Platform = PlatformKind::iOS; auto File = std::move(Result.get()); EXPECT_EQ(FileType::TBD_V1, File->getFileType()); - EXPECT_EQ(PlatformKind::iOS, File->getPlatform()); + EXPECT_EQ(File->getPlatforms().size(), 1U); + EXPECT_EQ(Platform, *File->getPlatforms().begin()); } TEST(TBDv1, Platform_watchOS) { @@ -236,9 +256,11 @@ TEST(TBDv1, Platform_watchOS) { auto Result = TextAPIReader::get(MemoryBufferRef(tbd_v1_platform_watchos, "Test.tbd")); EXPECT_TRUE(!!Result); + auto Platform = PlatformKind::watchOS; auto File = std::move(Result.get()); EXPECT_EQ(FileType::TBD_V1, File->getFileType()); - EXPECT_EQ(PlatformKind::watchOS, File->getPlatform()); + EXPECT_EQ(File->getPlatforms().size(), 1U); + EXPECT_EQ(Platform, *File->getPlatforms().begin()); } TEST(TBDv1, Platform_tvOS) { @@ -251,9 +273,11 @@ TEST(TBDv1, Platform_tvOS) { auto Result = TextAPIReader::get(MemoryBufferRef(tbd_v1_platform_tvos, "Test.tbd")); EXPECT_TRUE(!!Result); + auto Platform = PlatformKind::tvOS; auto File = std::move(Result.get()); EXPECT_EQ(FileType::TBD_V1, File->getFileType()); - EXPECT_EQ(PlatformKind::tvOS, File->getPlatform()); + EXPECT_EQ(File->getPlatforms().size(), 1U); + EXPECT_EQ(Platform, *File->getPlatforms().begin()); } TEST(TBDv1, Platform_bridgeOS) { @@ -266,9 +290,11 @@ TEST(TBDv1, Platform_bridgeOS) { auto Result = TextAPIReader::get(MemoryBufferRef(tbd_v1_platform_bridgeos, "Test.tbd")); EXPECT_TRUE(!!Result); + auto Platform = PlatformKind::bridgeOS; auto File = std::move(Result.get()); EXPECT_EQ(FileType::TBD_V1, File->getFileType()); - EXPECT_EQ(PlatformKind::bridgeOS, File->getPlatform()); + EXPECT_EQ(File->getPlatforms().size(), 1U); + EXPECT_EQ(Platform, *File->getPlatforms().begin()); } TEST(TBDv1, Swift_1_0) { diff --git a/llvm/unittests/TextAPI/TextStubV2Tests.cpp b/llvm/unittests/TextAPI/TextStubV2Tests.cpp index 6350b61db5d75..0a75fb2fce213 100644 --- a/llvm/unittests/TextAPI/TextStubV2Tests.cpp +++ b/llvm/unittests/TextAPI/TextStubV2Tests.cpp @@ -89,8 +89,13 @@ TEST(TBDv2, ReadFile) { auto File = std::move(Result.get()); EXPECT_EQ(FileType::TBD_V2, File->getFileType()); auto Archs = AK_armv7 | AK_armv7s | AK_armv7k | AK_arm64; + auto Platform = PlatformKind::iOS; + TargetList Targets; + for (auto &&arch : Archs) + Targets.emplace_back(Target(arch, Platform)); EXPECT_EQ(Archs, File->getArchitectures()); - EXPECT_EQ(PlatformKind::iOS, File->getPlatform()); + EXPECT_EQ(File->getPlatforms().size(), 1U); + EXPECT_EQ(Platform, *File->getPlatforms().begin()); EXPECT_EQ(std::string("Test.dylib"), File->getInstallName()); EXPECT_EQ(PackedVersion(2, 3, 4), File->getCurrentVersion()); EXPECT_EQ(PackedVersion(1, 0, 0), File->getCompatibilityVersion()); @@ -99,8 +104,8 @@ TEST(TBDv2, ReadFile) { EXPECT_TRUE(File->isTwoLevelNamespace()); EXPECT_TRUE(File->isApplicationExtensionSafe()); EXPECT_TRUE(File->isInstallAPI()); - InterfaceFileRef client("clientA", Archs); - InterfaceFileRef reexport("/usr/lib/libfoo.dylib", Archs); + InterfaceFileRef client("clientA", Targets); + InterfaceFileRef reexport("/usr/lib/libfoo.dylib", Targets); EXPECT_EQ(1U, File->allowableClients().size()); EXPECT_EQ(client, File->allowableClients().front()); EXPECT_EQ(1U, File->reexportedLibraries().size()); @@ -155,8 +160,13 @@ TEST(TBDv2, ReadFile2) { auto File = std::move(Result.get()); EXPECT_EQ(FileType::TBD_V2, File->getFileType()); auto Archs = AK_armv7 | AK_armv7s | AK_armv7k | AK_arm64; + auto Platform = PlatformKind::iOS; + TargetList Targets; + for (auto &&arch : Archs) + Targets.emplace_back(Target(arch, Platform)); EXPECT_EQ(Archs, File->getArchitectures()); - EXPECT_EQ(PlatformKind::iOS, File->getPlatform()); + EXPECT_EQ(File->getPlatforms().size(), 1U); + EXPECT_EQ(Platform, *File->getPlatforms().begin()); EXPECT_EQ(std::string("Test.dylib"), File->getInstallName()); EXPECT_EQ(PackedVersion(1, 0, 0), File->getCurrentVersion()); EXPECT_EQ(PackedVersion(1, 0, 0), File->getCompatibilityVersion()); @@ -192,27 +202,29 @@ TEST(TBDv2, WriteFile) { "...\n"; InterfaceFile File; + TargetList Targets; + for (auto &&arch : AK_i386 | AK_x86_64) + Targets.emplace_back(Target(arch, PlatformKind::macOS)); File.setPath("libfoo.dylib"); File.setInstallName("/usr/lib/libfoo.dylib"); File.setFileType(FileType::TBD_V2); - File.setArchitectures(AK_i386 | AK_x86_64); - File.setPlatform(PlatformKind::macOS); + File.addTargets(Targets); File.setCurrentVersion(PackedVersion(1, 2, 3)); File.setTwoLevelNamespace(); File.setApplicationExtensionSafe(); File.setSwiftABIVersion(5); File.setObjCConstraint(ObjCConstraintType::Retain_Release); - File.addAllowableClient("clientA", AK_x86_64); - File.addReexportedLibrary("/usr/lib/libfoo.dylib", AK_x86_64); - File.addSymbol(SymbolKind::GlobalSymbol, "_sym1", AK_i386); - File.addSymbol(SymbolKind::GlobalSymbol, "_sym2", AK_i386, + File.addAllowableClient("clientA", Targets[1]); + File.addReexportedLibrary("/usr/lib/libfoo.dylib", Targets[1]); + File.addSymbol(SymbolKind::GlobalSymbol, "_sym1", {Targets[0]}); + File.addSymbol(SymbolKind::GlobalSymbol, "_sym2", {Targets[0]}, SymbolFlags::WeakDefined); - File.addSymbol(SymbolKind::GlobalSymbol, "_sym3", AK_i386, + File.addSymbol(SymbolKind::GlobalSymbol, "_sym3", {Targets[0]}, SymbolFlags::ThreadLocalValue); - File.addSymbol(SymbolKind::ObjectiveCClass, "Class1", AK_x86_64); - File.addSymbol(SymbolKind::ObjectiveCClassEHType, "Class1", AK_x86_64); + File.addSymbol(SymbolKind::ObjectiveCClass, "Class1", {Targets[1]}); + File.addSymbol(SymbolKind::ObjectiveCClassEHType, "Class1", {Targets[1]}); File.addSymbol(SymbolKind::ObjectiveCInstanceVariable, "Class1._ivar1", - AK_x86_64); + {Targets[1]}); SmallString<4096> Buffer; raw_svector_ostream OS(Buffer); @@ -232,8 +244,10 @@ TEST(TBDv2, Platform_macOS) { TextAPIReader::get(MemoryBufferRef(tbd_v1_platform_macos, "Test.tbd")); EXPECT_TRUE(!!Result); auto File = std::move(Result.get()); + auto Platform = PlatformKind::macOS; EXPECT_EQ(FileType::TBD_V2, File->getFileType()); - EXPECT_EQ(PlatformKind::macOS, File->getPlatform()); + EXPECT_EQ(File->getPlatforms().size(), 1U); + EXPECT_EQ(Platform, *File->getPlatforms().begin()); } TEST(TBDv2, Platform_iOS) { @@ -246,9 +260,11 @@ TEST(TBDv2, Platform_iOS) { auto Result = TextAPIReader::get(MemoryBufferRef(tbd_v1_platform_ios, "Test.tbd")); EXPECT_TRUE(!!Result); + auto Platform = PlatformKind::iOS; auto File = std::move(Result.get()); EXPECT_EQ(FileType::TBD_V2, File->getFileType()); - EXPECT_EQ(PlatformKind::iOS, File->getPlatform()); + EXPECT_EQ(File->getPlatforms().size(), 1U); + EXPECT_EQ(Platform, *File->getPlatforms().begin()); } TEST(TBDv2, Platform_watchOS) { @@ -261,9 +277,11 @@ TEST(TBDv2, Platform_watchOS) { auto Result = TextAPIReader::get(MemoryBufferRef(tbd_v1_platform_watchos, "Test.tbd")); EXPECT_TRUE(!!Result); + auto Platform = PlatformKind::watchOS; auto File = std::move(Result.get()); EXPECT_EQ(FileType::TBD_V2, File->getFileType()); - EXPECT_EQ(PlatformKind::watchOS, File->getPlatform()); + EXPECT_EQ(File->getPlatforms().size(), 1U); + EXPECT_EQ(Platform, *File->getPlatforms().begin()); } TEST(TBDv2, Platform_tvOS) { @@ -276,9 +294,11 @@ TEST(TBDv2, Platform_tvOS) { auto Result = TextAPIReader::get(MemoryBufferRef(tbd_v1_platform_tvos, "Test.tbd")); EXPECT_TRUE(!!Result); + auto Platform = PlatformKind::tvOS; auto File = std::move(Result.get()); EXPECT_EQ(FileType::TBD_V2, File->getFileType()); - EXPECT_EQ(PlatformKind::tvOS, File->getPlatform()); + EXPECT_EQ(File->getPlatforms().size(), 1U); + EXPECT_EQ(Platform, *File->getPlatforms().begin()); } TEST(TBDv2, Platform_bridgeOS) { @@ -291,9 +311,11 @@ TEST(TBDv2, Platform_bridgeOS) { auto Result = TextAPIReader::get(MemoryBufferRef(tbd_v1_platform_bridgeos, "Test.tbd")); EXPECT_TRUE(!!Result); + auto Platform = PlatformKind::bridgeOS; auto File = std::move(Result.get()); EXPECT_EQ(FileType::TBD_V2, File->getFileType()); - EXPECT_EQ(PlatformKind::bridgeOS, File->getPlatform()); + EXPECT_EQ(File->getPlatforms().size(), 1U); + EXPECT_EQ(Platform, *File->getPlatforms().begin()); } TEST(TBDv2, Swift_1_0) { @@ -415,7 +437,6 @@ TEST(TBDv2, UnknownArchitecture) { "platform: macosx\n" "install-name: Test.dylib\n" "...\n"; - auto Result = TextAPIReader::get( MemoryBufferRef(tbd_v2_file_unknown_architecture, "Test.tbd")); EXPECT_TRUE(!!Result); @@ -423,9 +444,9 @@ TEST(TBDv2, UnknownArchitecture) { TEST(TBDv2, UnknownPlatform) { static const char tbd_v2_file_unknown_platform[] = "--- !tapi-tbd-v2\n" - "archs: [ i386 ]\n" - "platform: newOS\n" - "...\n"; + "archs: [ i386 ]\n" + "platform: newOS\n" + "...\n"; auto Result = TextAPIReader::get( MemoryBufferRef(tbd_v2_file_unknown_platform, "Test.tbd")); diff --git a/llvm/unittests/TextAPI/TextStubV3Tests.cpp b/llvm/unittests/TextAPI/TextStubV3Tests.cpp index 9904e7bc7358d..10d76b5b8fec5 100644 --- a/llvm/unittests/TextAPI/TextStubV3Tests.cpp +++ b/llvm/unittests/TextAPI/TextStubV3Tests.cpp @@ -23,7 +23,7 @@ struct ExportedSymbol { bool ThreadLocalValue; }; using ExportedSymbolSeq = std::vector; -using UUIDs = std::vector>; +using UUIDs = std::vector>; inline bool operator<(const ExportedSymbol &lhs, const ExportedSymbol &rhs) { return std::tie(lhs.Kind, lhs.Name) < std::tie(rhs.Kind, rhs.Name); @@ -93,11 +93,18 @@ TEST(TBDv3, ReadFile) { auto File = std::move(Result.get()); EXPECT_EQ(FileType::TBD_V3, File->getFileType()); auto Archs = AK_armv7 | AK_arm64; + auto Platform = PlatformKind::iOS; + TargetList Targets; + for (auto &&arch : Archs) + Targets.emplace_back(Target(arch, Platform)); EXPECT_EQ(Archs, File->getArchitectures()); - UUIDs uuids = {{AK_armv7, "00000000-0000-0000-0000-000000000000"}, - {AK_arm64, "11111111-1111-1111-1111-111111111111"}}; - EXPECT_EQ(uuids, File->uuids()); - EXPECT_EQ(PlatformKind::iOS, File->getPlatform()); + UUIDs Uuids = {{Target(AK_armv7, PlatformKind::unknown), + "00000000-0000-0000-0000-000000000000"}, + {Target(AK_arm64, PlatformKind::unknown), + "11111111-1111-1111-1111-111111111111"}}; + EXPECT_EQ(Uuids, File->uuids()); + EXPECT_EQ(File->getPlatforms().size(), 1U); + EXPECT_EQ(Platform, *File->getPlatforms().begin()); EXPECT_EQ(std::string("Test.dylib"), File->getInstallName()); EXPECT_EQ(PackedVersion(2, 3, 4), File->getCurrentVersion()); EXPECT_EQ(PackedVersion(1, 0, 0), File->getCompatibilityVersion()); @@ -106,8 +113,8 @@ TEST(TBDv3, ReadFile) { EXPECT_TRUE(File->isTwoLevelNamespace()); EXPECT_TRUE(File->isApplicationExtensionSafe()); EXPECT_TRUE(File->isInstallAPI()); - InterfaceFileRef client("clientA", Archs); - InterfaceFileRef reexport("/usr/lib/libfoo.dylib", Archs); + InterfaceFileRef client("clientA", Targets); + InterfaceFileRef reexport("/usr/lib/libfoo.dylib", Targets); EXPECT_EQ(1U, File->allowableClients().size()); EXPECT_EQ(client, File->allowableClients().front()); EXPECT_EQ(1U, File->reexportedLibraries().size()); @@ -151,27 +158,29 @@ TEST(TBDv3, WriteFile) { "...\n"; InterfaceFile File; + TargetList Targets; + for (auto &&arch : AK_i386 | AK_x86_64) + Targets.emplace_back(Target(arch, PlatformKind::macOS)); File.setPath("libfoo.dylib"); File.setInstallName("/usr/lib/libfoo.dylib"); File.setFileType(FileType::TBD_V3); - File.setArchitectures(AK_i386 | AK_x86_64); - File.setPlatform(PlatformKind::macOS); + File.addTargets(Targets); File.setCurrentVersion(PackedVersion(1, 2, 3)); File.setTwoLevelNamespace(); File.setApplicationExtensionSafe(); File.setSwiftABIVersion(5); File.setObjCConstraint(ObjCConstraintType::Retain_Release); - File.addAllowableClient("clientA", AK_x86_64); - File.addReexportedLibrary("/usr/lib/libfoo.dylib", AK_x86_64); - File.addSymbol(SymbolKind::GlobalSymbol, "_sym1", AK_i386); - File.addSymbol(SymbolKind::GlobalSymbol, "_sym2", AK_i386, + File.addAllowableClient("clientA", Targets[1]); + File.addReexportedLibrary("/usr/lib/libfoo.dylib", Targets[1]); + File.addSymbol(SymbolKind::GlobalSymbol, "_sym1", {Targets[0]}); + File.addSymbol(SymbolKind::GlobalSymbol, "_sym2", {Targets[0]}, SymbolFlags::WeakDefined); - File.addSymbol(SymbolKind::GlobalSymbol, "_sym3", AK_i386, + File.addSymbol(SymbolKind::GlobalSymbol, "_sym3", {Targets[0]}, SymbolFlags::ThreadLocalValue); - File.addSymbol(SymbolKind::ObjectiveCClass, "Class1", AK_x86_64); - File.addSymbol(SymbolKind::ObjectiveCClassEHType, "Class1", AK_x86_64); + File.addSymbol(SymbolKind::ObjectiveCClass, "Class1", {Targets[1]}); + File.addSymbol(SymbolKind::ObjectiveCClassEHType, "Class1", {Targets[1]}); File.addSymbol(SymbolKind::ObjectiveCInstanceVariable, "Class1._ivar1", - AK_x86_64); + {Targets[1]}); SmallString<4096> Buffer; raw_svector_ostream OS(Buffer); @@ -190,9 +199,11 @@ TEST(TBDv3, Platform_macOS) { auto Result = TextAPIReader::get(MemoryBufferRef(tbd_v1_platform_macos, "Test.tbd")); EXPECT_TRUE(!!Result); + auto Platform = PlatformKind::macOS; auto File = std::move(Result.get()); EXPECT_EQ(FileType::TBD_V3, File->getFileType()); - EXPECT_EQ(PlatformKind::macOS, File->getPlatform()); + EXPECT_EQ(File->getPlatforms().size(), 1U); + EXPECT_EQ(Platform, *File->getPlatforms().begin()); } TEST(TBDv3, Platform_iOS) { @@ -205,9 +216,11 @@ TEST(TBDv3, Platform_iOS) { auto Result = TextAPIReader::get(MemoryBufferRef(tbd_v1_platform_ios, "Test.tbd")); EXPECT_TRUE(!!Result); + auto Platform = PlatformKind::iOS; auto File = std::move(Result.get()); EXPECT_EQ(FileType::TBD_V3, File->getFileType()); - EXPECT_EQ(PlatformKind::iOS, File->getPlatform()); + EXPECT_EQ(File->getPlatforms().size(), 1U); + EXPECT_EQ(Platform, *File->getPlatforms().begin()); } TEST(TBDv3, Platform_watchOS) { @@ -220,9 +233,11 @@ TEST(TBDv3, Platform_watchOS) { auto Result = TextAPIReader::get(MemoryBufferRef(tbd_v1_platform_watchos, "Test.tbd")); EXPECT_TRUE(!!Result); + auto Platform = PlatformKind::watchOS; auto File = std::move(Result.get()); EXPECT_EQ(FileType::TBD_V3, File->getFileType()); - EXPECT_EQ(PlatformKind::watchOS, File->getPlatform()); + EXPECT_EQ(File->getPlatforms().size(), 1U); + EXPECT_EQ(Platform, *File->getPlatforms().begin()); } TEST(TBDv3, Platform_tvOS) { @@ -236,8 +251,10 @@ TEST(TBDv3, Platform_tvOS) { TextAPIReader::get(MemoryBufferRef(tbd_v1_platform_tvos, "Test.tbd")); EXPECT_TRUE(!!Result); auto File = std::move(Result.get()); + auto Platform = PlatformKind::tvOS; EXPECT_EQ(FileType::TBD_V3, File->getFileType()); - EXPECT_EQ(PlatformKind::tvOS, File->getPlatform()); + EXPECT_EQ(File->getPlatforms().size(), 1U); + EXPECT_EQ(Platform, *File->getPlatforms().begin()); } TEST(TBDv3, Platform_bridgeOS) { @@ -250,9 +267,11 @@ TEST(TBDv3, Platform_bridgeOS) { auto Result = TextAPIReader::get(MemoryBufferRef(tbd_v1_platform_bridgeos, "Test.tbd")); EXPECT_TRUE(!!Result); + auto Platform = PlatformKind::bridgeOS; auto File = std::move(Result.get()); EXPECT_EQ(FileType::TBD_V3, File->getFileType()); - EXPECT_EQ(PlatformKind::bridgeOS, File->getPlatform()); + EXPECT_EQ(File->getPlatforms().size(), 1U); + EXPECT_EQ(Platform, *File->getPlatforms().begin()); } TEST(TBDv3, Swift_1_0) { From 927699490aec66edab97bf05b993f01a56b74c64 Mon Sep 17 00:00:00 2001 From: GN Sync Bot Date: Fri, 20 Sep 2019 14:39:52 +0000 Subject: [PATCH 04/71] gn build: Merge r372396 llvm-svn: 372397 --- llvm/utils/gn/secondary/llvm/lib/TextAPI/BUILD.gn | 2 ++ 1 file changed, 2 insertions(+) diff --git a/llvm/utils/gn/secondary/llvm/lib/TextAPI/BUILD.gn b/llvm/utils/gn/secondary/llvm/lib/TextAPI/BUILD.gn index 509d589086698..aa695da4bf30d 100644 --- a/llvm/utils/gn/secondary/llvm/lib/TextAPI/BUILD.gn +++ b/llvm/utils/gn/secondary/llvm/lib/TextAPI/BUILD.gn @@ -12,7 +12,9 @@ static_library("TextAPI") { "MachO/ArchitectureSet.cpp", "MachO/InterfaceFile.cpp", "MachO/PackedVersion.cpp", + "MachO/Platform.cpp", "MachO/Symbol.cpp", + "MachO/Target.cpp", "MachO/TextStub.cpp", "MachO/TextStubCommon.cpp", ] From b71d8d465aa992870a22bd17e684fa6a5e9b2759 Mon Sep 17 00:00:00 2001 From: David Stenberg Date: Fri, 20 Sep 2019 14:41:41 +0000 Subject: [PATCH 05/71] Add a missing space in a MIR parser error message llvm-svn: 372398 --- llvm/lib/CodeGen/MIRParser/MIRParser.cpp | 2 +- llvm/test/CodeGen/MIR/X86/call-site-info-error2.mir | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/llvm/lib/CodeGen/MIRParser/MIRParser.cpp b/llvm/lib/CodeGen/MIRParser/MIRParser.cpp index 72d3d1d14e935..5f5b6eb82bc73 100644 --- a/llvm/lib/CodeGen/MIRParser/MIRParser.cpp +++ b/llvm/lib/CodeGen/MIRParser/MIRParser.cpp @@ -355,7 +355,7 @@ bool MIRParserImpl::initializeCallSiteInfo( if (MILoc.Offset >= CallB->size()) return error(Twine(MF.getName()) + Twine(" call instruction offset out of range.") + - "Unable to reference instruction at bb: " + + " Unable to reference instruction at bb: " + Twine(MILoc.BlockNum) + " at offset:" + Twine(MILoc.Offset)); auto CallI = std::next(CallB->instr_begin(), MILoc.Offset); if (!CallI->isCall(MachineInstr::IgnoreBundle)) diff --git a/llvm/test/CodeGen/MIR/X86/call-site-info-error2.mir b/llvm/test/CodeGen/MIR/X86/call-site-info-error2.mir index 1d65b3eb5dbf7..bd5b2451a8d76 100644 --- a/llvm/test/CodeGen/MIR/X86/call-site-info-error2.mir +++ b/llvm/test/CodeGen/MIR/X86/call-site-info-error2.mir @@ -1,5 +1,5 @@ # RUN: not llc -mtriple=x86_64-- -run-pass none -debug-entry-values %s -o - 2>&1 | FileCheck %s -# CHECK: baa call instruction offset out of range.Unable to reference instruction at bb: 0 at offset:1 +# CHECK: baa call instruction offset out of range. Unable to reference instruction at bb: 0 at offset:1 --- | define dso_local i32 @baa(i32 %a) local_unnamed_addr { entry: From be428513cb05893e74a7276a21b12b709db53bb9 Mon Sep 17 00:00:00 2001 From: Francesco Petrogalli Date: Fri, 20 Sep 2019 15:02:32 +0000 Subject: [PATCH 06/71] [docs] Remove training whitespaces. NFC Subscribers: jfb, llvm-commits Tags: #llvm Differential Revision: https://reviews.llvm.org/D67835 llvm-svn: 372399 --- llvm/docs/Frontend/PerformanceTips.rst | 254 ++++++++++++------------- 1 file changed, 127 insertions(+), 127 deletions(-) diff --git a/llvm/docs/Frontend/PerformanceTips.rst b/llvm/docs/Frontend/PerformanceTips.rst index 2c356de14cdbd..749fbd8085879 100644 --- a/llvm/docs/Frontend/PerformanceTips.rst +++ b/llvm/docs/Frontend/PerformanceTips.rst @@ -9,220 +9,220 @@ Performance Tips for Frontend Authors Abstract ======== -The intended audience of this document is developers of language frontends -targeting LLVM IR. This document is home to a collection of tips on how to -generate IR that optimizes well. +The intended audience of this document is developers of language frontends +targeting LLVM IR. This document is home to a collection of tips on how to +generate IR that optimizes well. IR Best Practices ================= -As with any optimizer, LLVM has its strengths and weaknesses. In some cases, -surprisingly small changes in the source IR can have a large effect on the -generated code. +As with any optimizer, LLVM has its strengths and weaknesses. In some cases, +surprisingly small changes in the source IR can have a large effect on the +generated code. -Beyond the specific items on the list below, it's worth noting that the most +Beyond the specific items on the list below, it's worth noting that the most mature frontend for LLVM is Clang. As a result, the further your IR gets from what Clang might emit, the less likely it is to be effectively optimized. It can often be useful to write a quick C program with the semantics you're trying -to model and see what decisions Clang's IRGen makes about what IR to emit. -Studying Clang's CodeGen directory can also be a good source of ideas. Note -that Clang and LLVM are explicitly version locked so you'll need to make sure -you're using a Clang built from the same svn revision or release as the LLVM -library you're using. As always, it's *strongly* recommended that you track +to model and see what decisions Clang's IRGen makes about what IR to emit. +Studying Clang's CodeGen directory can also be a good source of ideas. Note +that Clang and LLVM are explicitly version locked so you'll need to make sure +you're using a Clang built from the same svn revision or release as the LLVM +library you're using. As always, it's *strongly* recommended that you track tip of tree development, particularly during bring up of a new project. The Basics ^^^^^^^^^^^ -#. Make sure that your Modules contain both a data layout specification and +#. Make sure that your Modules contain both a data layout specification and target triple. Without these pieces, non of the target specific optimization will be enabled. This can have a major effect on the generated code quality. #. For each function or global emitted, use the most private linkage type - possible (private, internal or linkonce_odr preferably). Doing so will + possible (private, internal or linkonce_odr preferably). Doing so will make LLVM's inter-procedural optimizations much more effective. #. Avoid high in-degree basic blocks (e.g. basic blocks with dozens or hundreds - of predecessors). Among other issues, the register allocator is known to - perform badly with confronted with such structures. The only exception to + of predecessors). Among other issues, the register allocator is known to + perform badly with confronted with such structures. The only exception to this guidance is that a unified return block with high in-degree is fine. Use of allocas ^^^^^^^^^^^^^^ -An alloca instruction can be used to represent a function scoped stack slot, -but can also represent dynamic frame expansion. When representing function -scoped variables or locations, placing alloca instructions at the beginning of -the entry block should be preferred. In particular, place them before any -call instructions. Call instructions might get inlined and replaced with -multiple basic blocks. The end result is that a following alloca instruction +An alloca instruction can be used to represent a function scoped stack slot, +but can also represent dynamic frame expansion. When representing function +scoped variables or locations, placing alloca instructions at the beginning of +the entry block should be preferred. In particular, place them before any +call instructions. Call instructions might get inlined and replaced with +multiple basic blocks. The end result is that a following alloca instruction would no longer be in the entry basic block afterward. The SROA (Scalar Replacement Of Aggregates) and Mem2Reg passes only attempt -to eliminate alloca instructions that are in the entry basic block. Given -SSA is the canonical form expected by much of the optimizer; if allocas can -not be eliminated by Mem2Reg or SROA, the optimizer is likely to be less +to eliminate alloca instructions that are in the entry basic block. Given +SSA is the canonical form expected by much of the optimizer; if allocas can +not be eliminated by Mem2Reg or SROA, the optimizer is likely to be less effective than it could be. Avoid loads and stores of large aggregate type ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ LLVM currently does not optimize well loads and stores of large :ref:`aggregate -types ` (i.e. structs and arrays). As an alternative, consider +types ` (i.e. structs and arrays). As an alternative, consider loading individual fields from memory. -Aggregates that are smaller than the largest (performant) load or store -instruction supported by the targeted hardware are well supported. These can -be an effective way to represent collections of small packed fields. +Aggregates that are smaller than the largest (performant) load or store +instruction supported by the targeted hardware are well supported. These can +be an effective way to represent collections of small packed fields. Prefer zext over sext when legal ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -On some architectures (X86_64 is one), sign extension can involve an extra +On some architectures (X86_64 is one), sign extension can involve an extra instruction whereas zero extension can be folded into a load. LLVM will try to -replace a sext with a zext when it can be proven safe, but if you have -information in your source language about the range of a integer value, it can -be profitable to use a zext rather than a sext. +replace a sext with a zext when it can be proven safe, but if you have +information in your source language about the range of a integer value, it can +be profitable to use a zext rather than a sext. -Alternatively, you can :ref:`specify the range of the value using metadata +Alternatively, you can :ref:`specify the range of the value using metadata ` and LLVM can do the sext to zext conversion for you. Zext GEP indices to machine register width ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Internally, LLVM often promotes the width of GEP indices to machine register -width. When it does so, it will default to using sign extension (sext) -operations for safety. If your source language provides information about -the range of the index, you may wish to manually extend indices to machine +width. When it does so, it will default to using sign extension (sext) +operations for safety. If your source language provides information about +the range of the index, you may wish to manually extend indices to machine register width using a zext instruction. When to specify alignment ^^^^^^^^^^^^^^^^^^^^^^^^^^ LLVM will always generate correct code if you don’t specify alignment, but may -generate inefficient code. For example, if you are targeting MIPS (or older -ARM ISAs) then the hardware does not handle unaligned loads and stores, and -so you will enter a trap-and-emulate path if you do a load or store with -lower-than-natural alignment. To avoid this, LLVM will emit a slower -sequence of loads, shifts and masks (or load-right + load-left on MIPS) for -all cases where the load / store does not have a sufficiently high alignment +generate inefficient code. For example, if you are targeting MIPS (or older +ARM ISAs) then the hardware does not handle unaligned loads and stores, and +so you will enter a trap-and-emulate path if you do a load or store with +lower-than-natural alignment. To avoid this, LLVM will emit a slower +sequence of loads, shifts and masks (or load-right + load-left on MIPS) for +all cases where the load / store does not have a sufficiently high alignment in the IR. -The alignment is used to guarantee the alignment on allocas and globals, -though in most cases this is unnecessary (most targets have a sufficiently -high default alignment that they’ll be fine). It is also used to provide a +The alignment is used to guarantee the alignment on allocas and globals, +though in most cases this is unnecessary (most targets have a sufficiently +high default alignment that they’ll be fine). It is also used to provide a contract to the back end saying ‘either this load/store has this alignment, or -it is undefined behavior’. This means that the back end is free to emit -instructions that rely on that alignment (and mid-level optimizers are free to -perform transforms that require that alignment). For x86, it doesn’t make -much difference, as almost all instructions are alignment-independent. For +it is undefined behavior’. This means that the back end is free to emit +instructions that rely on that alignment (and mid-level optimizers are free to +perform transforms that require that alignment). For x86, it doesn’t make +much difference, as almost all instructions are alignment-independent. For MIPS, it can make a big difference. -Note that if your loads and stores are atomic, the backend will be unable to -lower an under aligned access into a sequence of natively aligned accesses. +Note that if your loads and stores are atomic, the backend will be unable to +lower an under aligned access into a sequence of natively aligned accesses. As a result, alignment is mandatory for atomic loads and stores. Other Things to Consider ^^^^^^^^^^^^^^^^^^^^^^^^ -#. Use ptrtoint/inttoptr sparingly (they interfere with pointer aliasing +#. Use ptrtoint/inttoptr sparingly (they interfere with pointer aliasing analysis), prefer GEPs -#. Prefer globals over inttoptr of a constant address - this gives you - dereferencability information. In MCJIT, use getSymbolAddress to provide +#. Prefer globals over inttoptr of a constant address - this gives you + dereferencability information. In MCJIT, use getSymbolAddress to provide actual address. -#. Be wary of ordered and atomic memory operations. They are hard to optimize +#. Be wary of ordered and atomic memory operations. They are hard to optimize and may not be well optimized by the current optimizer. Depending on your source language, you may consider using fences instead. -#. If calling a function which is known to throw an exception (unwind), use - an invoke with a normal destination which contains an unreachable - instruction. This form conveys to the optimizer that the call returns +#. If calling a function which is known to throw an exception (unwind), use + an invoke with a normal destination which contains an unreachable + instruction. This form conveys to the optimizer that the call returns abnormally. For an invoke which neither returns normally or requires unwind - code in the current function, you can use a noreturn call instruction if + code in the current function, you can use a noreturn call instruction if desired. This is generally not required because the optimizer will convert an invoke with an unreachable unwind destination to a call instruction. -#. Use profile metadata to indicate statically known cold paths, even if - dynamic profiling information is not available. This can make a large +#. Use profile metadata to indicate statically known cold paths, even if + dynamic profiling information is not available. This can make a large difference in code placement and thus the performance of tight loops. #. When generating code for loops, try to avoid terminating the header block of - the loop earlier than necessary. If the terminator of the loop header + the loop earlier than necessary. If the terminator of the loop header block is a loop exiting conditional branch, the effectiveness of LICM will - be limited for loads not in the header. (This is due to the fact that LLVM - may not know such a load is safe to speculatively execute and thus can't - lift an otherwise loop invariant load unless it can prove the exiting - condition is not taken.) It can be profitable, in some cases, to emit such - instructions into the header even if they are not used along a rarely - executed path that exits the loop. This guidance specifically does not + be limited for loads not in the header. (This is due to the fact that LLVM + may not know such a load is safe to speculatively execute and thus can't + lift an otherwise loop invariant load unless it can prove the exiting + condition is not taken.) It can be profitable, in some cases, to emit such + instructions into the header even if they are not used along a rarely + executed path that exits the loop. This guidance specifically does not apply if the condition which terminates the loop header is itself invariant, or can be easily discharged by inspecting the loop index variables. -#. In hot loops, consider duplicating instructions from small basic blocks - which end in highly predictable terminators into their successor blocks. - If a hot successor block contains instructions which can be vectorized +#. In hot loops, consider duplicating instructions from small basic blocks + which end in highly predictable terminators into their successor blocks. + If a hot successor block contains instructions which can be vectorized with the duplicated ones, this can provide a noticeable throughput - improvement. Note that this is not always profitable and does involve a + improvement. Note that this is not always profitable and does involve a potentially large increase in code size. #. When checking a value against a constant, emit the check using a consistent comparison type. The GVN pass *will* optimize redundant equalities even if the type of comparison is inverted, but GVN only runs late in the pipeline. - As a result, you may miss the opportunity to run other important - optimizations. Improvements to EarlyCSE to remove this issue are tracked in + As a result, you may miss the opportunity to run other important + optimizations. Improvements to EarlyCSE to remove this issue are tracked in Bug 23333. -#. Avoid using arithmetic intrinsics unless you are *required* by your source - language specification to emit a particular code sequence. The optimizer +#. Avoid using arithmetic intrinsics unless you are *required* by your source + language specification to emit a particular code sequence. The optimizer is quite good at reasoning about general control flow and arithmetic, it is - not anywhere near as strong at reasoning about the various intrinsics. If - profitable for code generation purposes, the optimizer will likely form the - intrinsics itself late in the optimization pipeline. It is *very* rarely + not anywhere near as strong at reasoning about the various intrinsics. If + profitable for code generation purposes, the optimizer will likely form the + intrinsics itself late in the optimization pipeline. It is *very* rarely profitable to emit these directly in the language frontend. This item explicitly includes the use of the :ref:`overflow intrinsics `. -#. Avoid using the :ref:`assume intrinsic ` until you've - established that a) there's no other way to express the given fact and b) - that fact is critical for optimization purposes. Assumes are a great - prototyping mechanism, but they can have negative effects on both compile - time and optimization effectiveness. The former is fixable with enough +#. Avoid using the :ref:`assume intrinsic ` until you've + established that a) there's no other way to express the given fact and b) + that fact is critical for optimization purposes. Assumes are a great + prototyping mechanism, but they can have negative effects on both compile + time and optimization effectiveness. The former is fixable with enough effort, but the later is fairly fundamental to their designed purpose. Describing Language Specific Properties ======================================= -When translating a source language to LLVM, finding ways to express concepts -and guarantees available in your source language which are not natively -provided by LLVM IR will greatly improve LLVM's ability to optimize your code. +When translating a source language to LLVM, finding ways to express concepts +and guarantees available in your source language which are not natively +provided by LLVM IR will greatly improve LLVM's ability to optimize your code. As an example, C/C++'s ability to mark every add as "no signed wrap (nsw)" goes -a long way to assisting the optimizer in reasoning about loop induction -variables and thus generating more optimal code for loops. +a long way to assisting the optimizer in reasoning about loop induction +variables and thus generating more optimal code for loops. -The LLVM LangRef includes a number of mechanisms for annotating the IR with -additional semantic information. It is *strongly* recommended that you become -highly familiar with this document. The list below is intended to highlight a +The LLVM LangRef includes a number of mechanisms for annotating the IR with +additional semantic information. It is *strongly* recommended that you become +highly familiar with this document. The list below is intended to highlight a couple of items of particular interest, but is by no means exhaustive. Restricted Operation Semantics ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -#. Add nsw/nuw flags as appropriate. Reasoning about overflow is - generally hard for an optimizer so providing these facts from the frontend - can be very impactful. +#. Add nsw/nuw flags as appropriate. Reasoning about overflow is + generally hard for an optimizer so providing these facts from the frontend + can be very impactful. -#. Use fast-math flags on floating point operations if legal. If you don't - need strict IEEE floating point semantics, there are a number of additional - optimizations that can be performed. This can be highly impactful for +#. Use fast-math flags on floating point operations if legal. If you don't + need strict IEEE floating point semantics, there are a number of additional + optimizations that can be performed. This can be highly impactful for floating point intensive computations. Describing Aliasing Properties ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -#. Add noalias/align/dereferenceable/nonnull to function arguments and return +#. Add noalias/align/dereferenceable/nonnull to function arguments and return values as appropriate -#. Use pointer aliasing metadata, especially tbaa metadata, to communicate +#. Use pointer aliasing metadata, especially tbaa metadata, to communicate otherwise-non-deducible pointer aliasing facts #. Use inbounds on geps. This can help to disambiguate some aliasing queries. @@ -233,37 +233,37 @@ Modeling Memory Effects #. Mark functions as readnone/readonly/argmemonly or noreturn/nounwind when known. The optimizer will try to infer these flags, but may not always be - able to. Manual annotations are particularly important for external + able to. Manual annotations are particularly important for external functions that the optimizer can not analyze. -#. Use the lifetime.start/lifetime.end and invariant.start/invariant.end - intrinsics where possible. Common profitable uses are for stack like data - structures (thus allowing dead store elimination) and for describing - life times of allocas (thus allowing smaller stack sizes). +#. Use the lifetime.start/lifetime.end and invariant.start/invariant.end + intrinsics where possible. Common profitable uses are for stack like data + structures (thus allowing dead store elimination) and for describing + life times of allocas (thus allowing smaller stack sizes). #. Mark invariant locations using !invariant.load and TBAA's constant flags Pass Ordering ^^^^^^^^^^^^^ -One of the most common mistakes made by new language frontend projects is to +One of the most common mistakes made by new language frontend projects is to use the existing -O2 or -O3 pass pipelines as is. These pass pipelines make a -good starting point for an optimizing compiler for any language, but they have -been carefully tuned for C and C++, not your target language. You will almost -certainly need to use a custom pass order to achieve optimal performance. A +good starting point for an optimizing compiler for any language, but they have +been carefully tuned for C and C++, not your target language. You will almost +certainly need to use a custom pass order to achieve optimal performance. A couple specific suggestions: -#. For languages with numerous rarely executed guard conditions (e.g. null - checks, type checks, range checks) consider adding an extra execution or - two of LoopUnswith and LICM to your pass order. The standard pass order, - which is tuned for C and C++ applications, may not be sufficient to remove +#. For languages with numerous rarely executed guard conditions (e.g. null + checks, type checks, range checks) consider adding an extra execution or + two of LoopUnswith and LICM to your pass order. The standard pass order, + which is tuned for C and C++ applications, may not be sufficient to remove all dischargeable checks from loops. -#. If you language uses range checks, consider using the IRCE pass. It is not +#. If you language uses range checks, consider using the IRCE pass. It is not currently part of the standard pass order. -#. A useful sanity check to run is to run your optimized IR back through the - -O2 pipeline again. If you see noticeable improvement in the resulting IR, +#. A useful sanity check to run is to run your optimized IR back through the + -O2 pipeline again. If you see noticeable improvement in the resulting IR, you likely need to adjust your pass order. @@ -272,16 +272,16 @@ I Still Can't Find What I'm Looking For If you didn't find what you were looking for above, consider proposing an piece of metadata which provides the optimization hint you need. Such extensions are -relatively common and are generally well received by the community. You will -need to ensure that your proposal is sufficiently general so that it benefits +relatively common and are generally well received by the community. You will +need to ensure that your proposal is sufficiently general so that it benefits others if you wish to contribute it upstream. -You should also consider describing the problem you're facing on `llvm-dev -`_ and asking for advice. -It's entirely possible someone has encountered your problem before and can -give good advice. If there are multiple interested parties, that also +You should also consider describing the problem you're facing on `llvm-dev +`_ and asking for advice. +It's entirely possible someone has encountered your problem before and can +give good advice. If there are multiple interested parties, that also increases the chances that a metadata extension would be well received by the -community as a whole. +community as a whole. Adding to this document ======================= @@ -290,8 +290,8 @@ If you run across a case that you feel deserves to be covered here, please send a patch to `llvm-commits `_ for review. -If you have questions on these items, please direct them to `llvm-dev -`_. The more relevant -context you are able to give to your question, the more likely it is to be +If you have questions on these items, please direct them to `llvm-dev +`_. The more relevant +context you are able to give to your question, the more likely it is to be answered. From 267205149587595e956db25a12252835a51cd372 Mon Sep 17 00:00:00 2001 From: Fangrui Song Date: Fri, 20 Sep 2019 15:03:21 +0000 Subject: [PATCH 07/71] [ELF] Error if the linked-to section of a SHF_LINK_ORDER section is discarded Summary: If st_link(A)=B, and A has the SHF_LINK_ORDER flag, we may dereference a null pointer if B is garbage collected (PR43147): 1. In Wrter.cpp:compareByFilePosition, `aOut->sectionIndex` or `bOut->sectionIndex` 2. In OutputSections::finalize, `d->getParent()->sectionIndex` Simply error and bail out to avoid null pointer dereferences. ld.bfd has a similar error: sh_link of section `.bar' points to discarded section `.foo0' of `a.o' ld.bfd is more permissive in that it just checks whether the linked-to section of the first input section is discarded. This is likely because it sets sh_link of the output section according to the first input section. Reviewed By: grimar Differential Revision: https://reviews.llvm.org/D67761 llvm-svn: 372400 --- lld/ELF/Writer.cpp | 18 +++++++++--- lld/test/ELF/gc-sections-metadata-err.s | 37 +++++++++++++++++++++++++ 2 files changed, 51 insertions(+), 4 deletions(-) create mode 100644 lld/test/ELF/gc-sections-metadata-err.s diff --git a/lld/ELF/Writer.cpp b/lld/ELF/Writer.cpp index 9a618830cbfd8..f0334470e5e96 100644 --- a/lld/ELF/Writer.cpp +++ b/lld/ELF/Writer.cpp @@ -1500,6 +1500,12 @@ template void Writer::resolveShfLinkOrder() { if (!(sec->flags & SHF_LINK_ORDER)) continue; + // The ARM.exidx section use SHF_LINK_ORDER, but we have consolidated + // this processing inside the ARMExidxsyntheticsection::finalizeContents(). + if (!config->relocatable && config->emachine == EM_ARM && + sec->type == SHT_ARM_EXIDX) + continue; + // Link order may be distributed across several InputSectionDescriptions // but sort must consider them all at once. std::vector scriptSections; @@ -1509,14 +1515,16 @@ template void Writer::resolveShfLinkOrder() { for (InputSection *&isec : isd->sections) { scriptSections.push_back(&isec); sections.push_back(isec); + + InputSection *link = isec->getLinkOrderDep(); + if (!link->getParent()) + error(toString(isec) + ": sh_link points to discarded section " + + toString(link)); } } } - // The ARM.exidx section use SHF_LINK_ORDER, but we have consolidated - // this processing inside the ARMExidxsyntheticsection::finalizeContents(). - if (!config->relocatable && config->emachine == EM_ARM && - sec->type == SHT_ARM_EXIDX) + if (errorCount()) continue; llvm::stable_sort(sections, compareByFilePosition); @@ -1894,6 +1902,8 @@ template void Writer::finalizeSections() { // SHFLinkOrder processing must be processed after relative section placements are // known but before addresses are allocated. resolveShfLinkOrder(); + if (errorCount()) + return; // This is used to: // 1) Create "thunks": diff --git a/lld/test/ELF/gc-sections-metadata-err.s b/lld/test/ELF/gc-sections-metadata-err.s new file mode 100644 index 0000000000000..0f96e4157dfc2 --- /dev/null +++ b/lld/test/ELF/gc-sections-metadata-err.s @@ -0,0 +1,37 @@ +# REQUIRES: x86 + +## Error if the linked-to section of an input section is discarded. + +# RUN: llvm-mc -filetype=obj -triple=x86_64 %s -o %t.o +# RUN: not ld.lld --gc-sections --print-gc-sections %t.o -o /dev/null 2>&1 | FileCheck %s + +# CHECK: removing unused section {{.*}}.o:(.foo0) +# CHECK-NEXT: error: {{.*}}.o:(.bar): sh_link points to discarded section {{.*}}.o:(.foo0) +# CHECK-NEXT: error: {{.*}}.o:(.baz): sh_link points to discarded section {{.*}}.o:(.foo0) + +.globl _start +_start: + call .foo1 + call bar0 + call bar1 + call baz0 + call baz1 + +.section .foo0,"a" +.section .foo1,"a" + +## The linked-to section of the first input section is discarded. +.section .bar,"ao",@progbits,.foo0,unique,0 +bar0: +.byte 0 +.section .bar,"ao",@progbits,.foo1,unique,1 +bar1: +.byte 1 + +## Another case: the linked-to section of the second input section is discarded. +.section .baz,"ao",@progbits,.foo1,unique,0 +baz0: +.byte 0 +.section .baz,"ao",@progbits,.foo0,unique,1 +baz1: +.byte 1 From c84722ff277a6848dfa17d137dcf21d64cdfb972 Mon Sep 17 00:00:00 2001 From: Oliver Cruickshank Date: Fri, 20 Sep 2019 15:03:44 +0000 Subject: [PATCH 08/71] [ARM] Fix CTTZ not generating correct instructions MVE CTTZ intrinsic should have been set to Custom, not Expand llvm-svn: 372401 --- llvm/lib/Target/ARM/ARMISelLowering.cpp | 2 +- llvm/test/CodeGen/Thumb2/mve-cttz.ll | 42 +++++++------------------ 2 files changed, 13 insertions(+), 31 deletions(-) diff --git a/llvm/lib/Target/ARM/ARMISelLowering.cpp b/llvm/lib/Target/ARM/ARMISelLowering.cpp index e30b878d84e42..fbcdbbc2d0a29 100644 --- a/llvm/lib/Target/ARM/ARMISelLowering.cpp +++ b/llvm/lib/Target/ARM/ARMISelLowering.cpp @@ -262,7 +262,7 @@ void ARMTargetLowering::addMVEVectorTypes(bool HasMVEFP) { setOperationAction(ISD::MLOAD, VT, Custom); setOperationAction(ISD::MSTORE, VT, Legal); setOperationAction(ISD::CTLZ, VT, Legal); - setOperationAction(ISD::CTTZ, VT, Expand); + setOperationAction(ISD::CTTZ, VT, Custom); setOperationAction(ISD::BITREVERSE, VT, Legal); setOperationAction(ISD::BSWAP, VT, Legal); diff --git a/llvm/test/CodeGen/Thumb2/mve-cttz.ll b/llvm/test/CodeGen/Thumb2/mve-cttz.ll index c30906fdbb146..d1034fb2aac9a 100644 --- a/llvm/test/CodeGen/Thumb2/mve-cttz.ll +++ b/llvm/test/CodeGen/Thumb2/mve-cttz.ll @@ -44,12 +44,9 @@ entry: define arm_aapcs_vfpcc <4 x i32> @cttz_4i32_0_t(<4 x i32> %src){ ; CHECK-LABEL: cttz_4i32_0_t: ; CHECK: @ %bb.0: @ %entry -; CHECK-NEXT: vmov.i32 q1, #0x1 -; CHECK-NEXT: vsub.i32 q1, q0, q1 -; CHECK-NEXT: vbic q0, q1, q0 -; CHECK-NEXT: vmov.i32 q1, #0x20 +; CHECK-NEXT: movs r0, #32 +; CHECK-NEXT: vbrsr.32 q0, q0, r0 ; CHECK-NEXT: vclz.i32 q0, q0 -; CHECK-NEXT: vsub.i32 q0, q1, q0 ; CHECK-NEXT: bx lr entry: %0 = call <4 x i32> @llvm.cttz.v4i32(<4 x i32> %src, i1 0) @@ -59,12 +56,9 @@ entry: define arm_aapcs_vfpcc <8 x i16> @cttz_8i16_0_t(<8 x i16> %src){ ; CHECK-LABEL: cttz_8i16_0_t: ; CHECK: @ %bb.0: @ %entry -; CHECK-NEXT: vmov.i16 q1, #0x1 -; CHECK-NEXT: vsub.i16 q1, q0, q1 -; CHECK-NEXT: vbic q0, q1, q0 -; CHECK-NEXT: vmov.i16 q1, #0x10 +; CHECK-NEXT: movs r0, #16 +; CHECK-NEXT: vbrsr.16 q0, q0, r0 ; CHECK-NEXT: vclz.i16 q0, q0 -; CHECK-NEXT: vsub.i16 q0, q1, q0 ; CHECK-NEXT: bx lr entry: %0 = call <8 x i16> @llvm.cttz.v8i16(<8 x i16> %src, i1 0) @@ -74,12 +68,9 @@ entry: define arm_aapcs_vfpcc <16 x i8> @cttz_16i8_0_t(<16 x i8> %src) { ; CHECK-LABEL: cttz_16i8_0_t: ; CHECK: @ %bb.0: @ %entry -; CHECK-NEXT: vmov.i8 q1, #0x1 -; CHECK-NEXT: vsub.i8 q1, q0, q1 -; CHECK-NEXT: vbic q0, q1, q0 -; CHECK-NEXT: vmov.i8 q1, #0x8 +; CHECK-NEXT: movs r0, #8 +; CHECK-NEXT: vbrsr.8 q0, q0, r0 ; CHECK-NEXT: vclz.i8 q0, q0 -; CHECK-NEXT: vsub.i8 q0, q1, q0 ; CHECK-NEXT: bx lr entry: %0 = call <16 x i8> @llvm.cttz.v16i8(<16 x i8> %src, i1 0) @@ -129,12 +120,9 @@ entry: define arm_aapcs_vfpcc <4 x i32> @cttz_4i32_1_t(<4 x i32> %src){ ; CHECK-LABEL: cttz_4i32_1_t: ; CHECK: @ %bb.0: @ %entry -; CHECK-NEXT: vmov.i32 q1, #0x1 -; CHECK-NEXT: vsub.i32 q1, q0, q1 -; CHECK-NEXT: vbic q0, q1, q0 -; CHECK-NEXT: vmov.i32 q1, #0x20 +; CHECK-NEXT: movs r0, #32 +; CHECK-NEXT: vbrsr.32 q0, q0, r0 ; CHECK-NEXT: vclz.i32 q0, q0 -; CHECK-NEXT: vsub.i32 q0, q1, q0 ; CHECK-NEXT: bx lr entry: %0 = call <4 x i32> @llvm.cttz.v4i32(<4 x i32> %src, i1 1) @@ -144,12 +132,9 @@ entry: define arm_aapcs_vfpcc <8 x i16> @cttz_8i16_1_t(<8 x i16> %src){ ; CHECK-LABEL: cttz_8i16_1_t: ; CHECK: @ %bb.0: @ %entry -; CHECK-NEXT: vmov.i16 q1, #0x1 -; CHECK-NEXT: vsub.i16 q1, q0, q1 -; CHECK-NEXT: vbic q0, q1, q0 -; CHECK-NEXT: vmov.i16 q1, #0x10 +; CHECK-NEXT: movs r0, #16 +; CHECK-NEXT: vbrsr.16 q0, q0, r0 ; CHECK-NEXT: vclz.i16 q0, q0 -; CHECK-NEXT: vsub.i16 q0, q1, q0 ; CHECK-NEXT: bx lr entry: %0 = call <8 x i16> @llvm.cttz.v8i16(<8 x i16> %src, i1 1) @@ -159,12 +144,9 @@ entry: define arm_aapcs_vfpcc <16 x i8> @cttz_16i8_1_t(<16 x i8> %src) { ; CHECK-LABEL: cttz_16i8_1_t: ; CHECK: @ %bb.0: @ %entry -; CHECK-NEXT: vmov.i8 q1, #0x1 -; CHECK-NEXT: vsub.i8 q1, q0, q1 -; CHECK-NEXT: vbic q0, q1, q0 -; CHECK-NEXT: vmov.i8 q1, #0x8 +; CHECK-NEXT: movs r0, #8 +; CHECK-NEXT: vbrsr.8 q0, q0, r0 ; CHECK-NEXT: vclz.i8 q0, q0 -; CHECK-NEXT: vsub.i8 q0, q1, q0 ; CHECK-NEXT: bx lr entry: %0 = call <16 x i8> @llvm.cttz.v16i8(<16 x i8> %src, i1 1) From d21087af958656e3eab173fc69bf7a83a3956e90 Mon Sep 17 00:00:00 2001 From: Roman Lebedev Date: Fri, 20 Sep 2019 15:06:47 +0000 Subject: [PATCH 09/71] [InstCombine] Tests for (a+b)<=a && (a+b)!=0 fold (PR43259) https://rise4fun.com/Alive/knp https://rise4fun.com/Alive/ALap llvm-svn: 372402 --- ...f-negative-is-non-zero-and-no-underflow.ll | 27 ++- ...ve-or-zero-is-non-zero-and-no-underflow.ll | 166 ++++++++++++++++++ 2 files changed, 189 insertions(+), 4 deletions(-) create mode 100644 llvm/test/Transforms/InstCombine/result-of-add-of-negative-or-zero-is-non-zero-and-no-underflow.ll diff --git a/llvm/test/Transforms/InstCombine/result-of-add-of-negative-is-non-zero-and-no-underflow.ll b/llvm/test/Transforms/InstCombine/result-of-add-of-negative-is-non-zero-and-no-underflow.ll index 1a376c42648e0..1253988f97533 100644 --- a/llvm/test/Transforms/InstCombine/result-of-add-of-negative-is-non-zero-and-no-underflow.ll +++ b/llvm/test/Transforms/InstCombine/result-of-add-of-negative-is-non-zero-and-no-underflow.ll @@ -1,10 +1,6 @@ ; NOTE: Assertions have been autogenerated by utils/update_test_checks.py ; RUN: opt %s -instcombine -S | FileCheck %s -; Here we add unsigned two values, check that addition did not underflow AND -; that the result is non-zero. This can be simplified just to a comparison -; between the base and negated offset. - declare void @use8(i8) declare void @use1(i1) @@ -233,3 +229,26 @@ define i1 @t8(i8 %base, i8 %offset) { %r = or i1 %not_null, %no_underflow ret i1 %r } + +; The comparison can be with any of the values being added. +define i1 @t9(i8 %base, i8 %offset) { +; CHECK-LABEL: @t9( +; CHECK-NEXT: [[CMP:%.*]] = icmp slt i8 [[BASE:%.*]], 0 +; CHECK-NEXT: call void @llvm.assume(i1 [[CMP]]) +; CHECK-NEXT: [[ADJUSTED:%.*]] = add i8 [[BASE]], [[OFFSET:%.*]] +; CHECK-NEXT: call void @use8(i8 [[ADJUSTED]]) +; CHECK-NEXT: [[NOT_NULL:%.*]] = icmp ne i8 [[ADJUSTED]], 0 +; CHECK-NEXT: [[NO_UNDERFLOW:%.*]] = icmp ult i8 [[ADJUSTED]], [[OFFSET]] +; CHECK-NEXT: [[R:%.*]] = and i1 [[NOT_NULL]], [[NO_UNDERFLOW]] +; CHECK-NEXT: ret i1 [[R]] +; + %cmp = icmp slt i8 %base, 0 + call void @llvm.assume(i1 %cmp) + + %adjusted = add i8 %base, %offset + call void @use8(i8 %adjusted) + %not_null = icmp ne i8 %adjusted, 0 + %no_underflow = icmp ult i8 %adjusted, %offset + %r = and i1 %not_null, %no_underflow + ret i1 %r +} diff --git a/llvm/test/Transforms/InstCombine/result-of-add-of-negative-or-zero-is-non-zero-and-no-underflow.ll b/llvm/test/Transforms/InstCombine/result-of-add-of-negative-or-zero-is-non-zero-and-no-underflow.ll new file mode 100644 index 0000000000000..abf8f9b862725 --- /dev/null +++ b/llvm/test/Transforms/InstCombine/result-of-add-of-negative-or-zero-is-non-zero-and-no-underflow.ll @@ -0,0 +1,166 @@ +; NOTE: Assertions have been autogenerated by utils/update_test_checks.py +; RUN: opt %s -instcombine -S | FileCheck %s + +declare void @use8(i8) + +declare void @use1(i1) +declare void @llvm.assume(i1) + +define i1 @t0(i8 %base, i8 %offset) { +; CHECK-LABEL: @t0( +; CHECK-NEXT: [[ADJUSTED:%.*]] = add i8 [[BASE:%.*]], [[OFFSET:%.*]] +; CHECK-NEXT: call void @use8(i8 [[ADJUSTED]]) +; CHECK-NEXT: [[NOT_NULL:%.*]] = icmp ne i8 [[ADJUSTED]], 0 +; CHECK-NEXT: [[NO_UNDERFLOW:%.*]] = icmp ule i8 [[ADJUSTED]], [[BASE]] +; CHECK-NEXT: [[R:%.*]] = and i1 [[NOT_NULL]], [[NO_UNDERFLOW]] +; CHECK-NEXT: ret i1 [[R]] +; + %adjusted = add i8 %base, %offset + call void @use8(i8 %adjusted) + %not_null = icmp ne i8 %adjusted, 0 + %no_underflow = icmp ule i8 %adjusted, %base + %r = and i1 %not_null, %no_underflow + ret i1 %r +} + +; We need to produce extra instruction, so one of icmp's must go away. +define i1 @t1_oneuse0(i8 %base, i8 %offset) { +; CHECK-LABEL: @t1_oneuse0( +; CHECK-NEXT: [[ADJUSTED:%.*]] = add i8 [[BASE:%.*]], [[OFFSET:%.*]] +; CHECK-NEXT: call void @use8(i8 [[ADJUSTED]]) +; CHECK-NEXT: [[NOT_NULL:%.*]] = icmp ne i8 [[ADJUSTED]], 0 +; CHECK-NEXT: call void @use1(i1 [[NOT_NULL]]) +; CHECK-NEXT: [[NO_UNDERFLOW:%.*]] = icmp ule i8 [[ADJUSTED]], [[BASE]] +; CHECK-NEXT: [[R:%.*]] = and i1 [[NOT_NULL]], [[NO_UNDERFLOW]] +; CHECK-NEXT: ret i1 [[R]] +; + %adjusted = add i8 %base, %offset + call void @use8(i8 %adjusted) + %not_null = icmp ne i8 %adjusted, 0 + call void @use1(i1 %not_null) + %no_underflow = icmp ule i8 %adjusted, %base + %r = and i1 %not_null, %no_underflow + ret i1 %r +} +define i1 @t2_oneuse1(i8 %base, i8 %offset) { +; CHECK-LABEL: @t2_oneuse1( +; CHECK-NEXT: [[ADJUSTED:%.*]] = add i8 [[BASE:%.*]], [[OFFSET:%.*]] +; CHECK-NEXT: call void @use8(i8 [[ADJUSTED]]) +; CHECK-NEXT: [[NOT_NULL:%.*]] = icmp ne i8 [[ADJUSTED]], 0 +; CHECK-NEXT: [[NO_UNDERFLOW:%.*]] = icmp ule i8 [[ADJUSTED]], [[BASE]] +; CHECK-NEXT: call void @use1(i1 [[NO_UNDERFLOW]]) +; CHECK-NEXT: [[R:%.*]] = and i1 [[NOT_NULL]], [[NO_UNDERFLOW]] +; CHECK-NEXT: ret i1 [[R]] +; + %adjusted = add i8 %base, %offset + call void @use8(i8 %adjusted) + %not_null = icmp ne i8 %adjusted, 0 + %no_underflow = icmp ule i8 %adjusted, %base + call void @use1(i1 %no_underflow) + %r = and i1 %not_null, %no_underflow + ret i1 %r +} +define i1 @n3_oneuse2_bad(i8 %base, i8 %offset) { +; CHECK-LABEL: @n3_oneuse2_bad( +; CHECK-NEXT: [[ADJUSTED:%.*]] = add i8 [[BASE:%.*]], [[OFFSET:%.*]] +; CHECK-NEXT: call void @use8(i8 [[ADJUSTED]]) +; CHECK-NEXT: [[NOT_NULL:%.*]] = icmp ne i8 [[ADJUSTED]], 0 +; CHECK-NEXT: call void @use1(i1 [[NOT_NULL]]) +; CHECK-NEXT: [[NO_UNDERFLOW:%.*]] = icmp ule i8 [[ADJUSTED]], [[BASE]] +; CHECK-NEXT: call void @use1(i1 [[NO_UNDERFLOW]]) +; CHECK-NEXT: [[R:%.*]] = and i1 [[NOT_NULL]], [[NO_UNDERFLOW]] +; CHECK-NEXT: ret i1 [[R]] +; + %adjusted = add i8 %base, %offset + call void @use8(i8 %adjusted) + %not_null = icmp ne i8 %adjusted, 0 + call void @use1(i1 %not_null) + %no_underflow = icmp ule i8 %adjusted, %base + call void @use1(i1 %no_underflow) + %r = and i1 %not_null, %no_underflow + ret i1 %r +} + +define i1 @t4_commutativity0(i8 %base, i8 %offset) { +; CHECK-LABEL: @t4_commutativity0( +; CHECK-NEXT: [[ADJUSTED:%.*]] = add i8 [[BASE:%.*]], [[OFFSET:%.*]] +; CHECK-NEXT: call void @use8(i8 [[ADJUSTED]]) +; CHECK-NEXT: [[NOT_NULL:%.*]] = icmp ne i8 [[ADJUSTED]], 0 +; CHECK-NEXT: [[NO_UNDERFLOW:%.*]] = icmp ule i8 [[ADJUSTED]], [[BASE]] +; CHECK-NEXT: [[R:%.*]] = and i1 [[NO_UNDERFLOW]], [[NOT_NULL]] +; CHECK-NEXT: ret i1 [[R]] +; + %adjusted = add i8 %base, %offset + call void @use8(i8 %adjusted) + %not_null = icmp ne i8 %adjusted, 0 + %no_underflow = icmp ule i8 %adjusted, %base + %r = and i1 %no_underflow, %not_null ; swapped + ret i1 %r +} +define i1 @t5_commutativity1(i8 %base, i8 %offset) { +; CHECK-LABEL: @t5_commutativity1( +; CHECK-NEXT: [[ADJUSTED:%.*]] = add i8 [[BASE:%.*]], [[OFFSET:%.*]] +; CHECK-NEXT: call void @use8(i8 [[ADJUSTED]]) +; CHECK-NEXT: [[NOT_NULL:%.*]] = icmp ne i8 [[ADJUSTED]], 0 +; CHECK-NEXT: [[NO_UNDERFLOW:%.*]] = icmp ult i8 [[ADJUSTED]], [[BASE]] +; CHECK-NEXT: [[R:%.*]] = and i1 [[NOT_NULL]], [[NO_UNDERFLOW]] +; CHECK-NEXT: ret i1 [[R]] +; + %adjusted = add i8 %base, %offset + call void @use8(i8 %adjusted) + %not_null = icmp ne i8 %adjusted, 0 + %no_underflow = icmp ugt i8 %base, %adjusted ; swapped + %r = and i1 %not_null, %no_underflow + ret i1 %r +} +define i1 @t6_commutativity3(i8 %base, i8 %offset) { +; CHECK-LABEL: @t6_commutativity3( +; CHECK-NEXT: [[ADJUSTED:%.*]] = add i8 [[BASE:%.*]], [[OFFSET:%.*]] +; CHECK-NEXT: call void @use8(i8 [[ADJUSTED]]) +; CHECK-NEXT: [[NOT_NULL:%.*]] = icmp ne i8 [[ADJUSTED]], 0 +; CHECK-NEXT: [[NO_UNDERFLOW:%.*]] = icmp ult i8 [[ADJUSTED]], [[BASE]] +; CHECK-NEXT: [[R:%.*]] = and i1 [[NO_UNDERFLOW]], [[NOT_NULL]] +; CHECK-NEXT: ret i1 [[R]] +; + %adjusted = add i8 %base, %offset + call void @use8(i8 %adjusted) + %not_null = icmp ne i8 %adjusted, 0 + %no_underflow = icmp ugt i8 %base, %adjusted ; swapped + %r = and i1 %no_underflow, %not_null ; swapped + ret i1 %r +} + +; We could have the opposite question, did we get null or overflow happened? +define i1 @t7(i8 %base, i8 %offset) { +; CHECK-LABEL: @t7( +; CHECK-NEXT: [[ADJUSTED:%.*]] = add i8 [[BASE:%.*]], [[OFFSET:%.*]] +; CHECK-NEXT: call void @use8(i8 [[ADJUSTED]]) +; CHECK-NEXT: [[TMP1:%.*]] = add i8 [[ADJUSTED]], -1 +; CHECK-NEXT: [[TMP2:%.*]] = icmp uge i8 [[TMP1]], [[BASE]] +; CHECK-NEXT: ret i1 [[TMP2]] +; + %adjusted = add i8 %base, %offset + call void @use8(i8 %adjusted) + %not_null = icmp eq i8 %adjusted, 0 + %no_underflow = icmp ugt i8 %adjusted, %base + %r = or i1 %not_null, %no_underflow + ret i1 %r +} + +; The comparison can be with any of the values being added. +define i1 @t8(i8 %base, i8 %offset) { +; CHECK-LABEL: @t8( +; CHECK-NEXT: [[ADJUSTED:%.*]] = add i8 [[BASE:%.*]], [[OFFSET:%.*]] +; CHECK-NEXT: call void @use8(i8 [[ADJUSTED]]) +; CHECK-NEXT: [[NOT_NULL:%.*]] = icmp ne i8 [[ADJUSTED]], 0 +; CHECK-NEXT: [[NO_UNDERFLOW:%.*]] = icmp ule i8 [[ADJUSTED]], [[OFFSET]] +; CHECK-NEXT: [[R:%.*]] = and i1 [[NOT_NULL]], [[NO_UNDERFLOW]] +; CHECK-NEXT: ret i1 [[R]] +; + %adjusted = add i8 %base, %offset + call void @use8(i8 %adjusted) + %not_null = icmp ne i8 %adjusted, 0 + %no_underflow = icmp ule i8 %adjusted, %offset + %r = and i1 %not_null, %no_underflow + ret i1 %r +} From 2b5d7e93dd18c13d5358f602d361273ec0960b37 Mon Sep 17 00:00:00 2001 From: Krzysztof Parzyszek Date: Fri, 20 Sep 2019 15:19:20 +0000 Subject: [PATCH 10/71] [MVT] Add v256i1 to MachineValueType This type can show up when lowering some HVX vector code on Hexagon. llvm-svn: 372403 --- llvm/include/llvm/CodeGen/ValueTypes.td | 251 +++++++++--------- llvm/include/llvm/Support/MachineValueType.h | 251 +++++++++--------- llvm/lib/CodeGen/ValueTypes.cpp | 2 + .../Target/Hexagon/HexagonISelLowering.cpp | 21 +- .../Hexagon/autohvx/isel-setcc-v256i1.ll | 15 ++ 5 files changed, 285 insertions(+), 255 deletions(-) create mode 100644 llvm/test/CodeGen/Hexagon/autohvx/isel-setcc-v256i1.ll diff --git a/llvm/include/llvm/CodeGen/ValueTypes.td b/llvm/include/llvm/CodeGen/ValueTypes.td index 1d80e25c35a88..16df565bc8b8d 100644 --- a/llvm/include/llvm/CodeGen/ValueTypes.td +++ b/llvm/include/llvm/CodeGen/ValueTypes.td @@ -40,131 +40,132 @@ def v16i1 : ValueType<16, 18>; // 16 x i1 vector value def v32i1 : ValueType<32 , 19>; // 32 x i1 vector value def v64i1 : ValueType<64 , 20>; // 64 x i1 vector value def v128i1 : ValueType<128, 21>; // 128 x i1 vector value -def v512i1 : ValueType<512, 22>; // 512 x i1 vector value -def v1024i1: ValueType<1024,23>; //1024 x i1 vector value - -def v1i8 : ValueType<8, 24>; // 1 x i8 vector value -def v2i8 : ValueType<16 , 25>; // 2 x i8 vector value -def v4i8 : ValueType<32 , 26>; // 4 x i8 vector value -def v8i8 : ValueType<64 , 27>; // 8 x i8 vector value -def v16i8 : ValueType<128, 28>; // 16 x i8 vector value -def v32i8 : ValueType<256, 29>; // 32 x i8 vector value -def v64i8 : ValueType<512, 30>; // 64 x i8 vector value -def v128i8 : ValueType<1024,31>; //128 x i8 vector value -def v256i8 : ValueType<2048,32>; //256 x i8 vector value - -def v1i16 : ValueType<16 , 33>; // 1 x i16 vector value -def v2i16 : ValueType<32 , 34>; // 2 x i16 vector value -def v3i16 : ValueType<48 , 35>; // 3 x i16 vector value -def v4i16 : ValueType<64 , 36>; // 4 x i16 vector value -def v8i16 : ValueType<128, 37>; // 8 x i16 vector value -def v16i16 : ValueType<256, 38>; // 16 x i16 vector value -def v32i16 : ValueType<512, 39>; // 32 x i16 vector value -def v64i16 : ValueType<1024,40>; // 64 x i16 vector value -def v128i16: ValueType<2048,41>; //128 x i16 vector value - -def v1i32 : ValueType<32 , 42>; // 1 x i32 vector value -def v2i32 : ValueType<64 , 43>; // 2 x i32 vector value -def v3i32 : ValueType<96 , 44>; // 3 x i32 vector value -def v4i32 : ValueType<128, 45>; // 4 x i32 vector value -def v5i32 : ValueType<160, 46>; // 5 x i32 vector value -def v8i32 : ValueType<256, 47>; // 8 x i32 vector value -def v16i32 : ValueType<512, 48>; // 16 x i32 vector value -def v32i32 : ValueType<1024,49>; // 32 x i32 vector value -def v64i32 : ValueType<2048,50>; // 64 x i32 vector value -def v128i32 : ValueType<4096,51>; // 128 x i32 vector value -def v256i32 : ValueType<8182,52>; // 256 x i32 vector value -def v512i32 : ValueType<16384,53>; // 512 x i32 vector value -def v1024i32 : ValueType<32768,54>; // 1024 x i32 vector value -def v2048i32 : ValueType<65536,55>; // 2048 x i32 vector value - -def v1i64 : ValueType<64 , 56>; // 1 x i64 vector value -def v2i64 : ValueType<128, 57>; // 2 x i64 vector value -def v4i64 : ValueType<256, 58>; // 4 x i64 vector value -def v8i64 : ValueType<512, 59>; // 8 x i64 vector value -def v16i64 : ValueType<1024,60>; // 16 x i64 vector value -def v32i64 : ValueType<2048,61>; // 32 x i64 vector value - -def v1i128 : ValueType<128, 62>; // 1 x i128 vector value - -def v2f16 : ValueType<32 , 63>; // 2 x f16 vector value -def v3f16 : ValueType<48 , 64>; // 3 x f16 vector value -def v4f16 : ValueType<64 , 65>; // 4 x f16 vector value -def v8f16 : ValueType<128, 66>; // 8 x f16 vector value -def v16f16 : ValueType<256, 67>; // 8 x f16 vector value -def v32f16 : ValueType<512, 68>; // 8 x f16 vector value -def v1f32 : ValueType<32 , 69>; // 1 x f32 vector value -def v2f32 : ValueType<64 , 70>; // 2 x f32 vector value -def v3f32 : ValueType<96 , 71>; // 3 x f32 vector value -def v4f32 : ValueType<128, 72>; // 4 x f32 vector value -def v5f32 : ValueType<160, 73>; // 5 x f32 vector value -def v8f32 : ValueType<256, 74>; // 8 x f32 vector value -def v16f32 : ValueType<512, 75>; // 16 x f32 vector value -def v32f32 : ValueType<1024, 76>; // 32 x f32 vector value -def v64f32 : ValueType<2048, 77>; // 64 x f32 vector value -def v128f32 : ValueType<4096, 78>; // 128 x f32 vector value -def v256f32 : ValueType<8182, 79>; // 256 x f32 vector value -def v512f32 : ValueType<16384, 80>; // 512 x f32 vector value -def v1024f32 : ValueType<32768, 81>; // 1024 x f32 vector value -def v2048f32 : ValueType<65536, 82>; // 2048 x f32 vector value -def v1f64 : ValueType<64, 83>; // 1 x f64 vector value -def v2f64 : ValueType<128, 84>; // 2 x f64 vector value -def v4f64 : ValueType<256, 85>; // 4 x f64 vector value -def v8f64 : ValueType<512, 86>; // 8 x f64 vector value - -def nxv1i1 : ValueType<1, 87>; // n x 1 x i1 vector value -def nxv2i1 : ValueType<2, 88>; // n x 2 x i1 vector value -def nxv4i1 : ValueType<4, 89>; // n x 4 x i1 vector value -def nxv8i1 : ValueType<8, 90>; // n x 8 x i1 vector value -def nxv16i1 : ValueType<16, 91>; // n x 16 x i1 vector value -def nxv32i1 : ValueType<32, 92>; // n x 32 x i1 vector value - -def nxv1i8 : ValueType<8, 93>; // n x 1 x i8 vector value -def nxv2i8 : ValueType<16, 94>; // n x 2 x i8 vector value -def nxv4i8 : ValueType<32, 95>; // n x 4 x i8 vector value -def nxv8i8 : ValueType<64, 96>; // n x 8 x i8 vector value -def nxv16i8 : ValueType<128, 97>; // n x 16 x i8 vector value -def nxv32i8 : ValueType<256, 98>; // n x 32 x i8 vector value - -def nxv1i16 : ValueType<16, 99>; // n x 1 x i16 vector value -def nxv2i16 : ValueType<32, 100>; // n x 2 x i16 vector value -def nxv4i16 : ValueType<64, 101>; // n x 4 x i16 vector value -def nxv8i16 : ValueType<128, 102>; // n x 8 x i16 vector value -def nxv16i16: ValueType<256, 103>; // n x 16 x i16 vector value -def nxv32i16: ValueType<512, 104>; // n x 32 x i16 vector value - -def nxv1i32 : ValueType<32, 105>; // n x 1 x i32 vector value -def nxv2i32 : ValueType<64, 106>; // n x 2 x i32 vector value -def nxv4i32 : ValueType<128, 107>; // n x 4 x i32 vector value -def nxv8i32 : ValueType<256, 108>; // n x 8 x i32 vector value -def nxv16i32: ValueType<512, 109>; // n x 16 x i32 vector value -def nxv32i32: ValueType<1024,110>; // n x 32 x i32 vector value - -def nxv1i64 : ValueType<64, 111>; // n x 1 x i64 vector value -def nxv2i64 : ValueType<128, 112>; // n x 2 x i64 vector value -def nxv4i64 : ValueType<256, 113>; // n x 4 x i64 vector value -def nxv8i64 : ValueType<512, 114>; // n x 8 x i64 vector value -def nxv16i64: ValueType<1024,115>; // n x 16 x i64 vector value -def nxv32i64: ValueType<2048,116>; // n x 32 x i64 vector value - -def nxv2f16 : ValueType<32 , 117>; // n x 2 x f16 vector value -def nxv4f16 : ValueType<64 , 118>; // n x 4 x f16 vector value -def nxv8f16 : ValueType<128, 119>; // n x 8 x f16 vector value -def nxv1f32 : ValueType<32 , 120>; // n x 1 x f32 vector value -def nxv2f32 : ValueType<64 , 121>; // n x 2 x f32 vector value -def nxv4f32 : ValueType<128, 122>; // n x 4 x f32 vector value -def nxv8f32 : ValueType<256, 123>; // n x 8 x f32 vector value -def nxv16f32 : ValueType<512, 124>; // n x 16 x f32 vector value -def nxv1f64 : ValueType<64, 125>; // n x 1 x f64 vector value -def nxv2f64 : ValueType<128, 126>; // n x 2 x f64 vector value -def nxv4f64 : ValueType<256, 127>; // n x 4 x f64 vector value -def nxv8f64 : ValueType<512, 128>; // n x 8 x f64 vector value - -def x86mmx : ValueType<64 , 129>; // X86 MMX value -def FlagVT : ValueType<0 , 130>; // Pre-RA sched glue -def isVoid : ValueType<0 , 131>; // Produces no value -def untyped: ValueType<8 , 132>; // Produces an untyped value -def exnref: ValueType<0, 133>; // WebAssembly's exnref type +def v256i1 : ValueType<256, 22>; // 256 x i1 vector value +def v512i1 : ValueType<512, 23>; // 512 x i1 vector value +def v1024i1: ValueType<1024,24>; //1024 x i1 vector value + +def v1i8 : ValueType<8, 25>; // 1 x i8 vector value +def v2i8 : ValueType<16 , 26>; // 2 x i8 vector value +def v4i8 : ValueType<32 , 27>; // 4 x i8 vector value +def v8i8 : ValueType<64 , 28>; // 8 x i8 vector value +def v16i8 : ValueType<128, 29>; // 16 x i8 vector value +def v32i8 : ValueType<256, 30>; // 32 x i8 vector value +def v64i8 : ValueType<512, 31>; // 64 x i8 vector value +def v128i8 : ValueType<1024,32>; //128 x i8 vector value +def v256i8 : ValueType<2048,33>; //256 x i8 vector value + +def v1i16 : ValueType<16 , 34>; // 1 x i16 vector value +def v2i16 : ValueType<32 , 35>; // 2 x i16 vector value +def v3i16 : ValueType<48 , 36>; // 3 x i16 vector value +def v4i16 : ValueType<64 , 37>; // 4 x i16 vector value +def v8i16 : ValueType<128, 38>; // 8 x i16 vector value +def v16i16 : ValueType<256, 39>; // 16 x i16 vector value +def v32i16 : ValueType<512, 40>; // 32 x i16 vector value +def v64i16 : ValueType<1024,41>; // 64 x i16 vector value +def v128i16: ValueType<2048,42>; //128 x i16 vector value + +def v1i32 : ValueType<32 , 43>; // 1 x i32 vector value +def v2i32 : ValueType<64 , 44>; // 2 x i32 vector value +def v3i32 : ValueType<96 , 45>; // 3 x i32 vector value +def v4i32 : ValueType<128, 46>; // 4 x i32 vector value +def v5i32 : ValueType<160, 47>; // 5 x i32 vector value +def v8i32 : ValueType<256, 48>; // 8 x i32 vector value +def v16i32 : ValueType<512, 49>; // 16 x i32 vector value +def v32i32 : ValueType<1024,50>; // 32 x i32 vector value +def v64i32 : ValueType<2048,51>; // 64 x i32 vector value +def v128i32 : ValueType<4096,52>; // 128 x i32 vector value +def v256i32 : ValueType<8182,53>; // 256 x i32 vector value +def v512i32 : ValueType<16384,54>; // 512 x i32 vector value +def v1024i32 : ValueType<32768,55>; // 1024 x i32 vector value +def v2048i32 : ValueType<65536,56>; // 2048 x i32 vector value + +def v1i64 : ValueType<64 , 57>; // 1 x i64 vector value +def v2i64 : ValueType<128, 58>; // 2 x i64 vector value +def v4i64 : ValueType<256, 59>; // 4 x i64 vector value +def v8i64 : ValueType<512, 60>; // 8 x i64 vector value +def v16i64 : ValueType<1024,61>; // 16 x i64 vector value +def v32i64 : ValueType<2048,62>; // 32 x i64 vector value + +def v1i128 : ValueType<128, 63>; // 1 x i128 vector value + +def v2f16 : ValueType<32 , 64>; // 2 x f16 vector value +def v3f16 : ValueType<48 , 65>; // 3 x f16 vector value +def v4f16 : ValueType<64 , 66>; // 4 x f16 vector value +def v8f16 : ValueType<128, 67>; // 8 x f16 vector value +def v16f16 : ValueType<256, 68>; // 8 x f16 vector value +def v32f16 : ValueType<512, 69>; // 8 x f16 vector value +def v1f32 : ValueType<32 , 70>; // 1 x f32 vector value +def v2f32 : ValueType<64 , 71>; // 2 x f32 vector value +def v3f32 : ValueType<96 , 72>; // 3 x f32 vector value +def v4f32 : ValueType<128, 73>; // 4 x f32 vector value +def v5f32 : ValueType<160, 74>; // 5 x f32 vector value +def v8f32 : ValueType<256, 75>; // 8 x f32 vector value +def v16f32 : ValueType<512, 76>; // 16 x f32 vector value +def v32f32 : ValueType<1024, 77>; // 32 x f32 vector value +def v64f32 : ValueType<2048, 78>; // 64 x f32 vector value +def v128f32 : ValueType<4096, 79>; // 128 x f32 vector value +def v256f32 : ValueType<8182, 80>; // 256 x f32 vector value +def v512f32 : ValueType<16384, 81>; // 512 x f32 vector value +def v1024f32 : ValueType<32768, 82>; // 1024 x f32 vector value +def v2048f32 : ValueType<65536, 83>; // 2048 x f32 vector value +def v1f64 : ValueType<64, 84>; // 1 x f64 vector value +def v2f64 : ValueType<128, 85>; // 2 x f64 vector value +def v4f64 : ValueType<256, 86>; // 4 x f64 vector value +def v8f64 : ValueType<512, 87>; // 8 x f64 vector value + +def nxv1i1 : ValueType<1, 88>; // n x 1 x i1 vector value +def nxv2i1 : ValueType<2, 89>; // n x 2 x i1 vector value +def nxv4i1 : ValueType<4, 90>; // n x 4 x i1 vector value +def nxv8i1 : ValueType<8, 91>; // n x 8 x i1 vector value +def nxv16i1 : ValueType<16, 92>; // n x 16 x i1 vector value +def nxv32i1 : ValueType<32, 93>; // n x 32 x i1 vector value + +def nxv1i8 : ValueType<8, 94>; // n x 1 x i8 vector value +def nxv2i8 : ValueType<16, 95>; // n x 2 x i8 vector value +def nxv4i8 : ValueType<32, 96>; // n x 4 x i8 vector value +def nxv8i8 : ValueType<64, 97>; // n x 8 x i8 vector value +def nxv16i8 : ValueType<128, 98>; // n x 16 x i8 vector value +def nxv32i8 : ValueType<256, 99>; // n x 32 x i8 vector value + +def nxv1i16 : ValueType<16, 100>; // n x 1 x i16 vector value +def nxv2i16 : ValueType<32, 101>; // n x 2 x i16 vector value +def nxv4i16 : ValueType<64, 102>; // n x 4 x i16 vector value +def nxv8i16 : ValueType<128, 103>; // n x 8 x i16 vector value +def nxv16i16: ValueType<256, 104>; // n x 16 x i16 vector value +def nxv32i16: ValueType<512, 105>; // n x 32 x i16 vector value + +def nxv1i32 : ValueType<32, 106>; // n x 1 x i32 vector value +def nxv2i32 : ValueType<64, 107>; // n x 2 x i32 vector value +def nxv4i32 : ValueType<128, 108>; // n x 4 x i32 vector value +def nxv8i32 : ValueType<256, 109>; // n x 8 x i32 vector value +def nxv16i32: ValueType<512, 110>; // n x 16 x i32 vector value +def nxv32i32: ValueType<1024,111>; // n x 32 x i32 vector value + +def nxv1i64 : ValueType<64, 112>; // n x 1 x i64 vector value +def nxv2i64 : ValueType<128, 113>; // n x 2 x i64 vector value +def nxv4i64 : ValueType<256, 114>; // n x 4 x i64 vector value +def nxv8i64 : ValueType<512, 115>; // n x 8 x i64 vector value +def nxv16i64: ValueType<1024,116>; // n x 16 x i64 vector value +def nxv32i64: ValueType<2048,117>; // n x 32 x i64 vector value + +def nxv2f16 : ValueType<32 , 118>; // n x 2 x f16 vector value +def nxv4f16 : ValueType<64 , 119>; // n x 4 x f16 vector value +def nxv8f16 : ValueType<128, 120>; // n x 8 x f16 vector value +def nxv1f32 : ValueType<32 , 121>; // n x 1 x f32 vector value +def nxv2f32 : ValueType<64 , 122>; // n x 2 x f32 vector value +def nxv4f32 : ValueType<128, 123>; // n x 4 x f32 vector value +def nxv8f32 : ValueType<256, 124>; // n x 8 x f32 vector value +def nxv16f32 : ValueType<512, 125>; // n x 16 x f32 vector value +def nxv1f64 : ValueType<64, 126>; // n x 1 x f64 vector value +def nxv2f64 : ValueType<128, 127>; // n x 2 x f64 vector value +def nxv4f64 : ValueType<256, 128>; // n x 4 x f64 vector value +def nxv8f64 : ValueType<512, 129>; // n x 8 x f64 vector value + +def x86mmx : ValueType<64 , 130>; // X86 MMX value +def FlagVT : ValueType<0 , 131>; // Pre-RA sched glue +def isVoid : ValueType<0 , 132>; // Produces no value +def untyped: ValueType<8 , 133>; // Produces an untyped value +def exnref: ValueType<0, 134>; // WebAssembly's exnref type def token : ValueType<0 , 248>; // TokenTy def MetadataVT: ValueType<0, 249>; // Metadata diff --git a/llvm/include/llvm/Support/MachineValueType.h b/llvm/include/llvm/Support/MachineValueType.h index ae3079ceb84fe..bc617e3b90e6f 100644 --- a/llvm/include/llvm/Support/MachineValueType.h +++ b/llvm/include/llvm/Support/MachineValueType.h @@ -65,80 +65,81 @@ namespace llvm { v32i1 = 19, // 32 x i1 v64i1 = 20, // 64 x i1 v128i1 = 21, // 128 x i1 - v512i1 = 22, // 512 x i1 - v1024i1 = 23, // 1024 x i1 - - v1i8 = 24, // 1 x i8 - v2i8 = 25, // 2 x i8 - v4i8 = 26, // 4 x i8 - v8i8 = 27, // 8 x i8 - v16i8 = 28, // 16 x i8 - v32i8 = 29, // 32 x i8 - v64i8 = 30, // 64 x i8 - v128i8 = 31, //128 x i8 - v256i8 = 32, //256 x i8 - - v1i16 = 33, // 1 x i16 - v2i16 = 34, // 2 x i16 - v3i16 = 35, // 3 x i16 - v4i16 = 36, // 4 x i16 - v8i16 = 37, // 8 x i16 - v16i16 = 38, // 16 x i16 - v32i16 = 39, // 32 x i16 - v64i16 = 40, // 64 x i16 - v128i16 = 41, //128 x i16 - - v1i32 = 42, // 1 x i32 - v2i32 = 43, // 2 x i32 - v3i32 = 44, // 3 x i32 - v4i32 = 45, // 4 x i32 - v5i32 = 46, // 5 x i32 - v8i32 = 47, // 8 x i32 - v16i32 = 48, // 16 x i32 - v32i32 = 49, // 32 x i32 - v64i32 = 50, // 64 x i32 - v128i32 = 51, // 128 x i32 - v256i32 = 52, // 256 x i32 - v512i32 = 53, // 512 x i32 - v1024i32 = 54, // 1024 x i32 - v2048i32 = 55, // 2048 x i32 - - v1i64 = 56, // 1 x i64 - v2i64 = 57, // 2 x i64 - v4i64 = 58, // 4 x i64 - v8i64 = 59, // 8 x i64 - v16i64 = 60, // 16 x i64 - v32i64 = 61, // 32 x i64 - - v1i128 = 62, // 1 x i128 + v256i1 = 22, // 256 x i1 + v512i1 = 23, // 512 x i1 + v1024i1 = 24, // 1024 x i1 + + v1i8 = 25, // 1 x i8 + v2i8 = 26, // 2 x i8 + v4i8 = 27, // 4 x i8 + v8i8 = 28, // 8 x i8 + v16i8 = 29, // 16 x i8 + v32i8 = 30, // 32 x i8 + v64i8 = 31, // 64 x i8 + v128i8 = 32, //128 x i8 + v256i8 = 33, //256 x i8 + + v1i16 = 34, // 1 x i16 + v2i16 = 35, // 2 x i16 + v3i16 = 36, // 3 x i16 + v4i16 = 37, // 4 x i16 + v8i16 = 38, // 8 x i16 + v16i16 = 39, // 16 x i16 + v32i16 = 40, // 32 x i16 + v64i16 = 41, // 64 x i16 + v128i16 = 42, //128 x i16 + + v1i32 = 43, // 1 x i32 + v2i32 = 44, // 2 x i32 + v3i32 = 45, // 3 x i32 + v4i32 = 46, // 4 x i32 + v5i32 = 47, // 5 x i32 + v8i32 = 48, // 8 x i32 + v16i32 = 49, // 16 x i32 + v32i32 = 50, // 32 x i32 + v64i32 = 51, // 64 x i32 + v128i32 = 52, // 128 x i32 + v256i32 = 53, // 256 x i32 + v512i32 = 54, // 512 x i32 + v1024i32 = 55, // 1024 x i32 + v2048i32 = 56, // 2048 x i32 + + v1i64 = 57, // 1 x i64 + v2i64 = 58, // 2 x i64 + v4i64 = 59, // 4 x i64 + v8i64 = 60, // 8 x i64 + v16i64 = 61, // 16 x i64 + v32i64 = 62, // 32 x i64 + + v1i128 = 63, // 1 x i128 FIRST_INTEGER_FIXEDLEN_VECTOR_VALUETYPE = v1i1, LAST_INTEGER_FIXEDLEN_VECTOR_VALUETYPE = v1i128, - v2f16 = 63, // 2 x f16 - v3f16 = 64, // 3 x f16 - v4f16 = 65, // 4 x f16 - v8f16 = 66, // 8 x f16 - v16f16 = 67, // 16 x f16 - v32f16 = 68, // 32 x f16 - v1f32 = 69, // 1 x f32 - v2f32 = 70, // 2 x f32 - v3f32 = 71, // 3 x f32 - v4f32 = 72, // 4 x f32 - v5f32 = 73, // 5 x f32 - v8f32 = 74, // 8 x f32 - v16f32 = 75, // 16 x f32 - v32f32 = 76, // 32 x f32 - v64f32 = 77, // 64 x f32 - v128f32 = 78, // 128 x f32 - v256f32 = 79, // 256 x f32 - v512f32 = 80, // 512 x f32 - v1024f32 = 81, // 1024 x f32 - v2048f32 = 82, // 2048 x f32 - v1f64 = 83, // 1 x f64 - v2f64 = 84, // 2 x f64 - v4f64 = 85, // 4 x f64 - v8f64 = 86, // 8 x f64 + v2f16 = 64, // 2 x f16 + v3f16 = 65, // 3 x f16 + v4f16 = 66, // 4 x f16 + v8f16 = 67, // 8 x f16 + v16f16 = 68, // 16 x f16 + v32f16 = 69, // 32 x f16 + v1f32 = 70, // 1 x f32 + v2f32 = 71, // 2 x f32 + v3f32 = 72, // 3 x f32 + v4f32 = 73, // 4 x f32 + v5f32 = 74, // 5 x f32 + v8f32 = 75, // 8 x f32 + v16f32 = 76, // 16 x f32 + v32f32 = 77, // 32 x f32 + v64f32 = 78, // 64 x f32 + v128f32 = 79, // 128 x f32 + v256f32 = 80, // 256 x f32 + v512f32 = 81, // 512 x f32 + v1024f32 = 82, // 1024 x f32 + v2048f32 = 83, // 2048 x f32 + v1f64 = 84, // 1 x f64 + v2f64 = 85, // 2 x f64 + v4f64 = 86, // 4 x f64 + v8f64 = 87, // 8 x f64 FIRST_FP_FIXEDLEN_VECTOR_VALUETYPE = v2f16, LAST_FP_FIXEDLEN_VECTOR_VALUETYPE = v8f64, @@ -146,56 +147,56 @@ namespace llvm { FIRST_FIXEDLEN_VECTOR_VALUETYPE = v1i1, LAST_FIXEDLEN_VECTOR_VALUETYPE = v8f64, - nxv1i1 = 87, // n x 1 x i1 - nxv2i1 = 88, // n x 2 x i1 - nxv4i1 = 89, // n x 4 x i1 - nxv8i1 = 90, // n x 8 x i1 - nxv16i1 = 91, // n x 16 x i1 - nxv32i1 = 92, // n x 32 x i1 - - nxv1i8 = 93, // n x 1 x i8 - nxv2i8 = 94, // n x 2 x i8 - nxv4i8 = 95, // n x 4 x i8 - nxv8i8 = 96, // n x 8 x i8 - nxv16i8 = 97, // n x 16 x i8 - nxv32i8 = 98, // n x 32 x i8 - - nxv1i16 = 99, // n x 1 x i16 - nxv2i16 = 100, // n x 2 x i16 - nxv4i16 = 101, // n x 4 x i16 - nxv8i16 = 102, // n x 8 x i16 - nxv16i16 = 103, // n x 16 x i16 - nxv32i16 = 104, // n x 32 x i16 - - nxv1i32 = 105, // n x 1 x i32 - nxv2i32 = 106, // n x 2 x i32 - nxv4i32 = 107, // n x 4 x i32 - nxv8i32 = 108, // n x 8 x i32 - nxv16i32 = 109, // n x 16 x i32 - nxv32i32 = 110, // n x 32 x i32 - - nxv1i64 = 111, // n x 1 x i64 - nxv2i64 = 112, // n x 2 x i64 - nxv4i64 = 113, // n x 4 x i64 - nxv8i64 = 114, // n x 8 x i64 - nxv16i64 = 115, // n x 16 x i64 - nxv32i64 = 116, // n x 32 x i64 + nxv1i1 = 88, // n x 1 x i1 + nxv2i1 = 89, // n x 2 x i1 + nxv4i1 = 90, // n x 4 x i1 + nxv8i1 = 91, // n x 8 x i1 + nxv16i1 = 92, // n x 16 x i1 + nxv32i1 = 93, // n x 32 x i1 + + nxv1i8 = 94, // n x 1 x i8 + nxv2i8 = 95, // n x 2 x i8 + nxv4i8 = 96, // n x 4 x i8 + nxv8i8 = 97, // n x 8 x i8 + nxv16i8 = 98, // n x 16 x i8 + nxv32i8 = 99, // n x 32 x i8 + + nxv1i16 = 100, // n x 1 x i16 + nxv2i16 = 101, // n x 2 x i16 + nxv4i16 = 102, // n x 4 x i16 + nxv8i16 = 103, // n x 8 x i16 + nxv16i16 = 104, // n x 16 x i16 + nxv32i16 = 105, // n x 32 x i16 + + nxv1i32 = 106, // n x 1 x i32 + nxv2i32 = 107, // n x 2 x i32 + nxv4i32 = 108, // n x 4 x i32 + nxv8i32 = 109, // n x 8 x i32 + nxv16i32 = 110, // n x 16 x i32 + nxv32i32 = 111, // n x 32 x i32 + + nxv1i64 = 112, // n x 1 x i64 + nxv2i64 = 113, // n x 2 x i64 + nxv4i64 = 114, // n x 4 x i64 + nxv8i64 = 115, // n x 8 x i64 + nxv16i64 = 116, // n x 16 x i64 + nxv32i64 = 117, // n x 32 x i64 FIRST_INTEGER_SCALABLE_VECTOR_VALUETYPE = nxv1i1, LAST_INTEGER_SCALABLE_VECTOR_VALUETYPE = nxv32i64, - nxv2f16 = 117, // n x 2 x f16 - nxv4f16 = 118, // n x 4 x f16 - nxv8f16 = 119, // n x 8 x f16 - nxv1f32 = 120, // n x 1 x f32 - nxv2f32 = 121, // n x 2 x f32 - nxv4f32 = 122, // n x 4 x f32 - nxv8f32 = 123, // n x 8 x f32 - nxv16f32 = 124, // n x 16 x f32 - nxv1f64 = 125, // n x 1 x f64 - nxv2f64 = 126, // n x 2 x f64 - nxv4f64 = 127, // n x 4 x f64 - nxv8f64 = 128, // n x 8 x f64 + nxv2f16 = 118, // n x 2 x f16 + nxv4f16 = 119, // n x 4 x f16 + nxv8f16 = 120, // n x 8 x f16 + nxv1f32 = 121, // n x 1 x f32 + nxv2f32 = 122, // n x 2 x f32 + nxv4f32 = 123, // n x 4 x f32 + nxv8f32 = 124, // n x 8 x f32 + nxv16f32 = 125, // n x 16 x f32 + nxv1f64 = 126, // n x 1 x f64 + nxv2f64 = 127, // n x 2 x f64 + nxv4f64 = 128, // n x 4 x f64 + nxv8f64 = 129, // n x 8 x f64 FIRST_FP_SCALABLE_VECTOR_VALUETYPE = nxv2f16, LAST_FP_SCALABLE_VECTOR_VALUETYPE = nxv8f64, @@ -206,20 +207,20 @@ namespace llvm { FIRST_VECTOR_VALUETYPE = v1i1, LAST_VECTOR_VALUETYPE = nxv8f64, - x86mmx = 129, // This is an X86 MMX value + x86mmx = 130, // This is an X86 MMX value - Glue = 130, // This glues nodes together during pre-RA sched + Glue = 131, // This glues nodes together during pre-RA sched - isVoid = 131, // This has no value + isVoid = 132, // This has no value - Untyped = 132, // This value takes a register, but has + Untyped = 133, // This value takes a register, but has // unspecified type. The register class // will be determined by the opcode. - exnref = 133, // WebAssembly's exnref type + exnref = 134, // WebAssembly's exnref type FIRST_VALUETYPE = 1, // This is always the beginning of the list. - LAST_VALUETYPE = 134, // This always remains at the end of the list. + LAST_VALUETYPE = 135, // This always remains at the end of the list. // This is the current maximum for LAST_VALUETYPE. // MVT::MAX_ALLOWED_VALUETYPE is used for asserts and to size bit vectors @@ -358,7 +359,7 @@ namespace llvm { return (SimpleTy == MVT::v16f16 || SimpleTy == MVT::v8f32 || SimpleTy == MVT::v4f64 || SimpleTy == MVT::v32i8 || SimpleTy == MVT::v16i16 || SimpleTy == MVT::v8i32 || - SimpleTy == MVT::v4i64); + SimpleTy == MVT::v4i64 || SimpleTy == MVT::v256i1); } /// Return true if this is a 512-bit vector type. @@ -432,6 +433,7 @@ namespace llvm { case v32i1: case v64i1: case v128i1: + case v256i1: case v512i1: case v1024i1: case nxv1i1: @@ -554,6 +556,7 @@ namespace llvm { case v512i1: case v512i32: case v512f32: return 512; + case v256i1: case v256i8: case v256i32: case v256f32: return 256; @@ -765,6 +768,7 @@ namespace llvm { case nxv2f64: return 128; case v5i32: case v5f32: return 160; + case v256i1: case v32i8: case v16i16: case v8i32: @@ -904,6 +908,7 @@ namespace llvm { if (NumElements == 32) return MVT::v32i1; if (NumElements == 64) return MVT::v64i1; if (NumElements == 128) return MVT::v128i1; + if (NumElements == 256) return MVT::v256i1; if (NumElements == 512) return MVT::v512i1; if (NumElements == 1024) return MVT::v1024i1; break; diff --git a/llvm/lib/CodeGen/ValueTypes.cpp b/llvm/lib/CodeGen/ValueTypes.cpp index f56aa84bad096..73b862d51c0f7 100644 --- a/llvm/lib/CodeGen/ValueTypes.cpp +++ b/llvm/lib/CodeGen/ValueTypes.cpp @@ -144,6 +144,7 @@ std::string EVT::getEVTString() const { case MVT::v32i1: return "v32i1"; case MVT::v64i1: return "v64i1"; case MVT::v128i1: return "v128i1"; + case MVT::v256i1: return "v256i1"; case MVT::v512i1: return "v512i1"; case MVT::v1024i1: return "v1024i1"; case MVT::v1i8: return "v1i8"; @@ -287,6 +288,7 @@ Type *EVT::getTypeForEVT(LLVMContext &Context) const { case MVT::v32i1: return VectorType::get(Type::getInt1Ty(Context), 32); case MVT::v64i1: return VectorType::get(Type::getInt1Ty(Context), 64); case MVT::v128i1: return VectorType::get(Type::getInt1Ty(Context), 128); + case MVT::v256i1: return VectorType::get(Type::getInt1Ty(Context), 256); case MVT::v512i1: return VectorType::get(Type::getInt1Ty(Context), 512); case MVT::v1024i1: return VectorType::get(Type::getInt1Ty(Context), 1024); case MVT::v1i8: return VectorType::get(Type::getInt8Ty(Context), 1); diff --git a/llvm/lib/Target/Hexagon/HexagonISelLowering.cpp b/llvm/lib/Target/Hexagon/HexagonISelLowering.cpp index ac70b4db86eac..66b6e11bb07be 100644 --- a/llvm/lib/Target/Hexagon/HexagonISelLowering.cpp +++ b/llvm/lib/Target/Hexagon/HexagonISelLowering.cpp @@ -1864,26 +1864,33 @@ bool HexagonTargetLowering::isShuffleMaskLegal(ArrayRef Mask, TargetLoweringBase::LegalizeTypeAction HexagonTargetLowering::getPreferredVectorAction(MVT VT) const { - if (VT.getVectorNumElements() == 1 || VT.isScalableVector()) - return TargetLoweringBase::TypeScalarizeVector; - - // Always widen vectors of i1. + unsigned VecLen = VT.getVectorNumElements(); MVT ElemTy = VT.getVectorElementType(); - if (ElemTy == MVT::i1) - return TargetLoweringBase::TypeWidenVector; + + if (VecLen == 1 || VT.isScalableVector()) + return TargetLoweringBase::TypeScalarizeVector; if (Subtarget.useHVXOps()) { + unsigned HwLen = Subtarget.getVectorLength(); // If the size of VT is at least half of the vector length, // widen the vector. Note: the threshold was not selected in // any scientific way. ArrayRef Tys = Subtarget.getHVXElementTypes(); if (llvm::find(Tys, ElemTy) != Tys.end()) { - unsigned HwWidth = 8*Subtarget.getVectorLength(); + unsigned HwWidth = 8*HwLen; unsigned VecWidth = VT.getSizeInBits(); if (VecWidth >= HwWidth/2 && VecWidth < HwWidth) return TargetLoweringBase::TypeWidenVector; } + // Split vectors of i1 that correspond to (byte) vector pairs. + if (ElemTy == MVT::i1 && VecLen == 2*HwLen) + return TargetLoweringBase::TypeSplitVector; } + + // Always widen (remaining) vectors of i1. + if (ElemTy == MVT::i1) + return TargetLoweringBase::TypeWidenVector; + return TargetLoweringBase::TypeSplitVector; } diff --git a/llvm/test/CodeGen/Hexagon/autohvx/isel-setcc-v256i1.ll b/llvm/test/CodeGen/Hexagon/autohvx/isel-setcc-v256i1.ll new file mode 100644 index 0000000000000..b0fbb1ceaf0f0 --- /dev/null +++ b/llvm/test/CodeGen/Hexagon/autohvx/isel-setcc-v256i1.ll @@ -0,0 +1,15 @@ +; RUN: llc -march=hexagon < %s | FileCheck %s + +; Check that this doesn't crash. The select should be broken up into two +; vmux instructions. + +; CHECK-LABEL: foo: +; CHECK: vmux +; CHECK: vmux +define <256 x i8> @foo(<256 x i8> %a0, <256 x i8> %a1) #0 { + %v0 = icmp slt <256 x i8> %a0, zeroinitializer + %v1 = select <256 x i1> %v0, <256 x i8> %a1, <256 x i8> %a0 + ret <256 x i8> %v1 +} + +attributes #0 = { "target-cpu"="hexagonv62" "target-features"="+hvx,+hvx-length128b" } From af77ca7e6e738b7963a622e4c35807ecc52f854b Mon Sep 17 00:00:00 2001 From: Stanislav Mekhanoshin Date: Fri, 20 Sep 2019 15:26:10 +0000 Subject: [PATCH 11/71] Remove assert from MachineLoop::getLoopPredecessor() According to the documentation method returns predecessor if the given loop's header has exactly one unique predecessor outside the loop. Otherwise return null. In reality it asserts if there is no predecessor outside of the loop. The testcase has the loop where predecessors outside of the loop were not identified as analyzeBranch() was unable to process the mask branch and returned true. That is also not correct to assert for the truly dead loops. Differential Revision: https://reviews.llvm.org/D67634 llvm-svn: 372405 --- llvm/include/llvm/Analysis/LoopInfoImpl.h | 2 - .../CodeGen/AMDGPU/loop_header_nopred.mir | 92 +++++++++++++++++++ 2 files changed, 92 insertions(+), 2 deletions(-) create mode 100644 llvm/test/CodeGen/AMDGPU/loop_header_nopred.mir diff --git a/llvm/include/llvm/Analysis/LoopInfoImpl.h b/llvm/include/llvm/Analysis/LoopInfoImpl.h index 4c33dac9e21e1..2f38dde7b3af3 100644 --- a/llvm/include/llvm/Analysis/LoopInfoImpl.h +++ b/llvm/include/llvm/Analysis/LoopInfoImpl.h @@ -200,8 +200,6 @@ BlockT *LoopBase::getLoopPredecessor() const { } } - // Make sure there is only one exit out of the preheader. - assert(Out && "Header of loop has no predecessors from outside loop?"); return Out; } diff --git a/llvm/test/CodeGen/AMDGPU/loop_header_nopred.mir b/llvm/test/CodeGen/AMDGPU/loop_header_nopred.mir new file mode 100644 index 0000000000000..a1f23777e30e7 --- /dev/null +++ b/llvm/test/CodeGen/AMDGPU/loop_header_nopred.mir @@ -0,0 +1,92 @@ +# NOTE: Assertions have been autogenerated by utils/update_mir_test_checks.py +# RUN: llc -march=amdgcn -o - -run-pass=block-placement -mcpu=gfx1010 -mattr=-inst-fwd-prefetch-bug -verify-machineinstrs %s | FileCheck -check-prefix=GCN %s + +# Used to fail with +# Assertion `Out && "Header of loop has no predecessors from outside loop?" + +--- +name: loop_header_nopred +body: | + ; GCN-LABEL: name: loop_header_nopred + ; GCN: bb.0: + ; GCN: successors: %bb.2(0x40000000), %bb.3(0x40000000) + ; GCN: S_CBRANCH_VCCZ %bb.3, implicit $vcc + ; GCN: S_BRANCH %bb.2 + ; GCN: bb.6 (align 64): + ; GCN: successors: %bb.7(0x04000000), %bb.1(0x7c000000) + ; GCN: S_CBRANCH_VCCNZ %bb.7, implicit $vcc + ; GCN: bb.1: + ; GCN: successors: %bb.2(0x40000000), %bb.3(0x40000000) + ; GCN: S_CBRANCH_VCCNZ %bb.2, implicit $vcc + ; GCN: bb.3: + ; GCN: successors: %bb.4(0x40000000), %bb.6(0x40000000) + ; GCN: SI_MASK_BRANCH %bb.6, implicit $exec + ; GCN: S_BRANCH %bb.4 + ; GCN: bb.2 (align 64): + ; GCN: successors: %bb.4(0x40000000), %bb.6(0x40000000) + ; GCN: SI_MASK_BRANCH %bb.6, implicit $exec + ; GCN: S_BRANCH %bb.4 + ; GCN: bb.4: + ; GCN: successors: %bb.5(0x04000000), %bb.4(0x7c000000) + ; GCN: S_NOP 0 + ; GCN: S_NOP 0 + ; GCN: S_NOP 0 + ; GCN: S_NOP 0 + ; GCN: S_NOP 0 + ; GCN: S_NOP 0 + ; GCN: S_NOP 0 + ; GCN: S_NOP 0 + ; GCN: S_NOP 0 + ; GCN: S_NOP 0 + ; GCN: S_NOP 0 + ; GCN: S_CBRANCH_EXECZ %bb.4, implicit $exec + ; GCN: bb.5: + ; GCN: successors: %bb.6(0x80000000) + ; GCN: S_BRANCH %bb.6 + ; GCN: bb.7: + ; GCN: S_ENDPGM 0 + bb.0: + successors: %bb.1(0x80000000) + + bb.1: + successors: %bb.2(0x40000000), %bb.3(0x40000000) + + S_CBRANCH_VCCZ %bb.3, implicit $vcc + S_BRANCH %bb.2 + + bb.2: + successors: %bb.3(0x80000000) + + bb.3: + successors: %bb.4(0x40000000), %bb.6(0x40000000) + + SI_MASK_BRANCH %bb.6, implicit $exec + S_BRANCH %bb.4 + + bb.4: + successors: %bb.5(0x04000000), %bb.4(0x7c000000) + + S_NOP 0 + S_NOP 0 + S_NOP 0 + S_NOP 0 + S_NOP 0 + S_NOP 0 + S_NOP 0 + S_NOP 0 + S_NOP 0 + S_NOP 0 + S_NOP 0 + S_CBRANCH_EXECZ %bb.4, implicit $exec + + bb.5: + successors: %bb.6(0x80000000) + + bb.6: + successors: %bb.7(0x04000000), %bb.1(0x7c000000) + + S_CBRANCH_VCCZ %bb.1, implicit $vcc + + bb.7: + S_ENDPGM 0 +... From ae685e7aab7f278cf197b8b1b1ccf76a6e884682 Mon Sep 17 00:00:00 2001 From: Saleem Abdulrasool Date: Fri, 20 Sep 2019 15:53:42 +0000 Subject: [PATCH 12/71] Unwind: prevent unw_get_proc_info from returning stale data If unwind info is not available at the current IP, unw_get_proc_info should return a zero-filled structure rather than the info of the previous IP. This change also makes unw_get_proc_info return UNW_ENOINFO instead of UNW_ESUCCESS. Patch by Amanieu d'Antras! llvm-svn: 372407 --- libunwind/src/UnwindCursor.hpp | 5 ++++- libunwind/test/libunwind_01.pass.cpp | 21 +++++++++++++++++++++ 2 files changed, 25 insertions(+), 1 deletion(-) diff --git a/libunwind/src/UnwindCursor.hpp b/libunwind/src/UnwindCursor.hpp index a96c9f39958d6..488c3173dd7e3 100644 --- a/libunwind/src/UnwindCursor.hpp +++ b/libunwind/src/UnwindCursor.hpp @@ -1991,7 +1991,10 @@ int UnwindCursor::step() { template void UnwindCursor::getInfo(unw_proc_info_t *info) { - *info = _info; + if (_unwindInfoMissing) + memset(info, 0, sizeof(*info)); + else + *info = _info; } template diff --git a/libunwind/test/libunwind_01.pass.cpp b/libunwind/test/libunwind_01.pass.cpp index 6957d98f956d7..830dcdd44f21a 100644 --- a/libunwind/test/libunwind_01.pass.cpp +++ b/libunwind/test/libunwind_01.pass.cpp @@ -35,8 +35,29 @@ void test3(int i, int j, int k) { test2(j, k); } +void test_no_info() { + unw_context_t context; + unw_getcontext(&context); + + unw_cursor_t cursor; + unw_init_local(&cursor, &context); + + unw_proc_info_t info; + int ret = unw_get_proc_info(&cursor, &info); + if (ret != UNW_ESUCCESS) + abort(); + + // Set the IP to an address clearly outside any function. + unw_set_reg(&cursor, UNW_REG_IP, (unw_word_t)&context); + + ret = unw_get_proc_info(&cursor, &info); + if (ret != UNW_ENOINFO) + abort(); +} + int main() { test1(1); test2(1, 2); test3(1, 2, 3); + test_no_info(); } From f6398fb72c9e2d224ecc837d0e5713e008afbcb2 Mon Sep 17 00:00:00 2001 From: Sebastian Pop Date: Fri, 20 Sep 2019 16:33:33 +0000 Subject: [PATCH 13/71] [aarch64] add def-pats for dot product This patch adds the patterns to select the dot product instructions. Tested on aarch64-linux with make check-all. Differential Revision: https://reviews.llvm.org/D67645 llvm-svn: 372408 --- llvm/lib/Target/AArch64/AArch64InstrInfo.td | 109 ++++++++++++++ llvm/test/CodeGen/AArch64/neon-dot-product.ll | 142 ++++++++++++++++++ 2 files changed, 251 insertions(+) diff --git a/llvm/lib/Target/AArch64/AArch64InstrInfo.td b/llvm/lib/Target/AArch64/AArch64InstrInfo.td index d89229865e4f6..ce6d032481c08 100644 --- a/llvm/lib/Target/AArch64/AArch64InstrInfo.td +++ b/llvm/lib/Target/AArch64/AArch64InstrInfo.td @@ -7000,5 +7000,114 @@ let AddedComplexity = 10 in { def : Pat<(i32 (extractelt (v2i32 V64:$V), (i64 0))), (EXTRACT_SUBREG V64:$V, ssub)>; } +// dot_v4i8 +class mul_v4i8 : + PatFrag<(ops node:$Rn, node:$Rm, node:$offset), + (mul (ldop (add node:$Rn, node:$offset)), + (ldop (add node:$Rm, node:$offset)))>; +class mulz_v4i8 : + PatFrag<(ops node:$Rn, node:$Rm), + (mul (ldop node:$Rn), (ldop node:$Rm))>; + +def load_v4i8 : + OutPatFrag<(ops node:$R), + (INSERT_SUBREG + (v2i32 (IMPLICIT_DEF)), + (i32 (COPY_TO_REGCLASS (LDRWui node:$R, (i64 0)), FPR32)), + ssub)>; + +class dot_v4i8 : + Pat<(i32 (add (mul_v4i8 GPR64sp:$Rn, GPR64sp:$Rm, (i64 3)), + (add (mul_v4i8 GPR64sp:$Rn, GPR64sp:$Rm, (i64 2)), + (add (mul_v4i8 GPR64sp:$Rn, GPR64sp:$Rm, (i64 1)), + (mulz_v4i8 GPR64sp:$Rn, GPR64sp:$Rm))))), + (EXTRACT_SUBREG (i64 (DOT (DUPv2i32gpr WZR), + (load_v4i8 GPR64sp:$Rn), + (load_v4i8 GPR64sp:$Rm))), + sub_32)>, Requires<[HasDotProd]>; + +// dot_v8i8 +class ee_v8i8 : + PatFrag<(ops node:$V, node:$K), + (v4i16 (extract_subvector (v8i16 (extend node:$V)), node:$K))>; + +class mul_v8i8 : + PatFrag<(ops node:$M, node:$N, node:$K), + (mulop (v4i16 (ee_v8i8 node:$M, node:$K)), + (v4i16 (ee_v8i8 node:$N, node:$K)))>; + +class idot_v8i8 : + PatFrag<(ops node:$M, node:$N), + (i32 (extractelt + (v4i32 (AArch64uaddv + (add (mul_v8i8 node:$M, node:$N, (i64 0)), + (mul_v8i8 node:$M, node:$N, (i64 4))))), + (i64 0)))>; + +// vaddv_[su]32 is special; -> ADDP Vd.2S,Vn.2S,Vm.2S; return Vd.s[0];Vn==Vm +def VADDV_32 : OutPatFrag<(ops node:$R), (ADDPv2i32 node:$R, node:$R)>; + +class odot_v8i8 : + OutPatFrag<(ops node:$Vm, node:$Vn), + (EXTRACT_SUBREG + (VADDV_32 + (i64 (DOT (DUPv2i32gpr WZR), + (v8i8 node:$Vm), + (v8i8 node:$Vn)))), + sub_32)>; + +class dot_v8i8 : + Pat<(idot_v8i8 V64:$Vm, V64:$Vn), + (odot_v8i8 V64:$Vm, V64:$Vn)>, + Requires<[HasDotProd]>; + +// dot_v16i8 +class ee_v16i8 : + PatFrag<(ops node:$V, node:$K1, node:$K2), + (v4i16 (extract_subvector + (v8i16 (extend + (v8i8 (extract_subvector node:$V, node:$K1)))), node:$K2))>; + +class mul_v16i8 : + PatFrag<(ops node:$M, node:$N, node:$K1, node:$K2), + (v4i32 + (mulop (v4i16 (ee_v16i8 node:$M, node:$K1, node:$K2)), + (v4i16 (ee_v16i8 node:$N, node:$K1, node:$K2))))>; + +class idot_v16i8 : + PatFrag<(ops node:$M, node:$N), + (i32 (extractelt + (v4i32 (AArch64uaddv + (add + (add (mul_v16i8 node:$M, node:$N, (i64 0), (i64 0)), + (mul_v16i8 node:$M, node:$N, (i64 8), (i64 0))), + (add (mul_v16i8 node:$M, node:$N, (i64 0), (i64 4)), + (mul_v16i8 node:$M, node:$N, (i64 8), (i64 4)))))), + (i64 0)))>; + +class odot_v16i8 : + OutPatFrag<(ops node:$Vm, node:$Vn), + (i32 (ADDVv4i32v + (DOT (DUPv4i32gpr WZR), node:$Vm, node:$Vn)))>; + +class dot_v16i8 : + Pat<(idot_v16i8 V128:$Vm, V128:$Vn), + (odot_v16i8 V128:$Vm, V128:$Vn)>, + Requires<[HasDotProd]>; + +let AddedComplexity = 10 in { + def : dot_v4i8; + def : dot_v4i8; + def : dot_v8i8; + def : dot_v8i8; + def : dot_v16i8; + def : dot_v16i8; + + // FIXME: add patterns to generate vector by element dot product. + // FIXME: add SVE dot-product patterns. +} + include "AArch64InstrAtomics.td" include "AArch64SVEInstrInfo.td" diff --git a/llvm/test/CodeGen/AArch64/neon-dot-product.ll b/llvm/test/CodeGen/AArch64/neon-dot-product.ll index 4b3c7cf4a6574..b6131e1d045ed 100644 --- a/llvm/test/CodeGen/AArch64/neon-dot-product.ll +++ b/llvm/test/CodeGen/AArch64/neon-dot-product.ll @@ -128,3 +128,145 @@ entry: %vdot1.i = call <4 x i32> @llvm.aarch64.neon.sdot.v4i32.v16i8(<4 x i32> %a, <16 x i8> %b, <16 x i8> %.cast3) #2 ret <4 x i32> %vdot1.i } + +define fastcc void @test_sdot_v4i8(i8* noalias nocapture %0, i8* noalias nocapture readonly %1, i8* noalias nocapture readonly %2) { +entry: +; CHECK-LABEL: test_sdot_v4i8: +; CHECK: sdot {{v[0-9]+}}.2s, {{v[0-9]+}}.8b, {{v[0-9]+}}.8b + %3 = bitcast i8* %0 to i32* + %4 = load i8, i8* %1, align 1 + %5 = sext i8 %4 to i32 + %6 = load i8, i8* %2, align 1 + %7 = sext i8 %6 to i32 + %8 = mul nsw i32 %7, %5 + %9 = getelementptr inbounds i8, i8* %1, i64 1 + %10 = load i8, i8* %9, align 1 + %11 = sext i8 %10 to i32 + %12 = getelementptr inbounds i8, i8* %2, i64 1 + %13 = load i8, i8* %12, align 1 + %14 = sext i8 %13 to i32 + %15 = mul nsw i32 %14, %11 + %16 = add nsw i32 %15, %8 + %17 = getelementptr inbounds i8, i8* %1, i64 2 + %18 = load i8, i8* %17, align 1 + %19 = sext i8 %18 to i32 + %20 = getelementptr inbounds i8, i8* %2, i64 2 + %21 = load i8, i8* %20, align 1 + %22 = sext i8 %21 to i32 + %23 = mul nsw i32 %22, %19 + %24 = add nsw i32 %23, %16 + %25 = getelementptr inbounds i8, i8* %1, i64 3 + %26 = load i8, i8* %25, align 1 + %27 = sext i8 %26 to i32 + %28 = getelementptr inbounds i8, i8* %2, i64 3 + %29 = load i8, i8* %28, align 1 + %30 = sext i8 %29 to i32 + %31 = mul nsw i32 %30, %27 + %32 = add nsw i32 %31, %24 + store i32 %32, i32* %3, align 64 + ret void +} + +define fastcc void @test_udot_v4i8(i8* noalias nocapture %0, i8* noalias nocapture readonly %1, i8* noalias nocapture readonly %2) { +entry: +; CHECK-LABEL: test_udot_v4i8: +; CHECK: udot {{v[0-9]+}}.2s, {{v[0-9]+}}.8b, {{v[0-9]+}}.8b + %3 = bitcast i8* %0 to i32* + %4 = load i8, i8* %1, align 1 + %5 = zext i8 %4 to i32 + %6 = load i8, i8* %2, align 1 + %7 = zext i8 %6 to i32 + %8 = mul nsw i32 %7, %5 + %9 = getelementptr inbounds i8, i8* %1, i64 1 + %10 = load i8, i8* %9, align 1 + %11 = zext i8 %10 to i32 + %12 = getelementptr inbounds i8, i8* %2, i64 1 + %13 = load i8, i8* %12, align 1 + %14 = zext i8 %13 to i32 + %15 = mul nsw i32 %14, %11 + %16 = add nsw i32 %15, %8 + %17 = getelementptr inbounds i8, i8* %1, i64 2 + %18 = load i8, i8* %17, align 1 + %19 = zext i8 %18 to i32 + %20 = getelementptr inbounds i8, i8* %2, i64 2 + %21 = load i8, i8* %20, align 1 + %22 = zext i8 %21 to i32 + %23 = mul nsw i32 %22, %19 + %24 = add nsw i32 %23, %16 + %25 = getelementptr inbounds i8, i8* %1, i64 3 + %26 = load i8, i8* %25, align 1 + %27 = zext i8 %26 to i32 + %28 = getelementptr inbounds i8, i8* %2, i64 3 + %29 = load i8, i8* %28, align 1 + %30 = zext i8 %29 to i32 + %31 = mul nsw i32 %30, %27 + %32 = add nsw i32 %31, %24 + store i32 %32, i32* %3, align 64 + ret void +} + +declare i32 @llvm.experimental.vector.reduce.add.v8i32(<8 x i32>) + +define i32 @test_udot_v8i8(i8* nocapture readonly %a, i8* nocapture readonly %b) { +entry: +; CHECK-LABEL: test_udot_v8i8: +; CHECK: udot {{v[0-9]+}}.2s, {{v[0-9]+}}.8b, {{v[0-9]+}}.8b + %0 = bitcast i8* %a to <8 x i8>* + %1 = load <8 x i8>, <8 x i8>* %0 + %2 = zext <8 x i8> %1 to <8 x i32> + %3 = bitcast i8* %b to <8 x i8>* + %4 = load <8 x i8>, <8 x i8>* %3 + %5 = zext <8 x i8> %4 to <8 x i32> + %6 = mul nuw nsw <8 x i32> %5, %2 + %7 = call i32 @llvm.experimental.vector.reduce.add.v8i32(<8 x i32> %6) + ret i32 %7 +} + +define i32 @test_sdot_v8i8(i8* nocapture readonly %a, i8* nocapture readonly %b) { +entry: +; CHECK-LABEL: test_sdot_v8i8: +; CHECK: sdot {{v[0-9]+}}.2s, {{v[0-9]+}}.8b, {{v[0-9]+}}.8b + %0 = bitcast i8* %a to <8 x i8>* + %1 = load <8 x i8>, <8 x i8>* %0 + %2 = sext <8 x i8> %1 to <8 x i32> + %3 = bitcast i8* %b to <8 x i8>* + %4 = load <8 x i8>, <8 x i8>* %3 + %5 = sext <8 x i8> %4 to <8 x i32> + %6 = mul nsw <8 x i32> %5, %2 + %7 = call i32 @llvm.experimental.vector.reduce.add.v8i32(<8 x i32> %6) + ret i32 %7 +} + +declare i32 @llvm.experimental.vector.reduce.add.v16i32(<16 x i32>) + +define i32 @test_udot_v16i8(i8* nocapture readonly %a, i8* nocapture readonly %b, i32 %sum) { +entry: +; CHECK-LABEL: test_udot_v16i8: +; CHECK: udot {{v[0-9]+}}.4s, {{v[0-9]+}}.16b, {{v[0-9]+}}.16b + %0 = bitcast i8* %a to <16 x i8>* + %1 = load <16 x i8>, <16 x i8>* %0 + %2 = zext <16 x i8> %1 to <16 x i32> + %3 = bitcast i8* %b to <16 x i8>* + %4 = load <16 x i8>, <16 x i8>* %3 + %5 = zext <16 x i8> %4 to <16 x i32> + %6 = mul nuw nsw <16 x i32> %5, %2 + %7 = call i32 @llvm.experimental.vector.reduce.add.v16i32(<16 x i32> %6) + %op.extra = add i32 %7, %sum + ret i32 %op.extra +} + +define i32 @test_sdot_v16i8(i8* nocapture readonly %a, i8* nocapture readonly %b, i32 %sum) { +entry: +; CHECK-LABEL: test_sdot_v16i8: +; CHECK: sdot {{v[0-9]+}}.4s, {{v[0-9]+}}.16b, {{v[0-9]+}}.16b + %0 = bitcast i8* %a to <16 x i8>* + %1 = load <16 x i8>, <16 x i8>* %0 + %2 = sext <16 x i8> %1 to <16 x i32> + %3 = bitcast i8* %b to <16 x i8>* + %4 = load <16 x i8>, <16 x i8>* %3 + %5 = sext <16 x i8> %4 to <16 x i32> + %6 = mul nsw <16 x i32> %5, %2 + %7 = call i32 @llvm.experimental.vector.reduce.add.v16i32(<16 x i32> %6) + %op.extra = add nsw i32 %7, %sum + ret i32 %op.extra +} From 1b7b4b467f03322f37b20ccee5cdef0c9ecec5d4 Mon Sep 17 00:00:00 2001 From: Craig Topper Date: Fri, 20 Sep 2019 16:49:51 +0000 Subject: [PATCH 14/71] [SelectionDAG][Mips][Sparc] Don't allow SimplifyDemandedBits to constant fold TargetConstant nodes to a Constant. Summary: After the switch in SimplifyDemandedBits, it tries to create a constant when possible. If the original node is a TargetConstant the default in the switch will call computeKnownBits on the TargetConstant which will succeed. This results in the TargetConstant becoming a Constant. But TargetConstant exists to avoid being changed. I've fixed the two cases that relied on this in tree by explicitly making the nodes constant instead of target constant. The Sparc case is an old bug. The Mips case was recently introduced now that ImmArg on intrinsics gets turned into a TargetConstant when the SelectionDAG is created. I've removed the ImmArg since it lowers to generic code. Reviewers: arsenm, RKSimon, spatel Subscribers: jyknight, sdardis, wdng, arichardson, hiraditya, fedor.sergeev, jrtc27, atanasyan, llvm-commits Tags: #llvm Differential Revision: https://reviews.llvm.org/D67802 llvm-svn: 372409 --- llvm/include/llvm/IR/IntrinsicsMips.td | 16 ++++++++-------- llvm/lib/CodeGen/SelectionDAG/TargetLowering.cpp | 2 ++ llvm/lib/Target/Sparc/SparcISelLowering.cpp | 6 +++--- 3 files changed, 13 insertions(+), 11 deletions(-) diff --git a/llvm/include/llvm/IR/IntrinsicsMips.td b/llvm/include/llvm/IR/IntrinsicsMips.td index 6393a9ca35d55..bfcdd80a52d57 100644 --- a/llvm/include/llvm/IR/IntrinsicsMips.td +++ b/llvm/include/llvm/IR/IntrinsicsMips.td @@ -1260,16 +1260,16 @@ def int_mips_insve_d : GCCBuiltin<"__builtin_msa_insve_d">, def int_mips_ld_b : GCCBuiltin<"__builtin_msa_ld_b">, Intrinsic<[llvm_v16i8_ty], [llvm_ptr_ty, llvm_i32_ty], - [IntrReadMem, IntrArgMemOnly, ImmArg<1>]>; + [IntrReadMem, IntrArgMemOnly]>; def int_mips_ld_h : GCCBuiltin<"__builtin_msa_ld_h">, Intrinsic<[llvm_v8i16_ty], [llvm_ptr_ty, llvm_i32_ty], - [IntrReadMem, IntrArgMemOnly, ImmArg<1>]>; + [IntrReadMem, IntrArgMemOnly]>; def int_mips_ld_w : GCCBuiltin<"__builtin_msa_ld_w">, Intrinsic<[llvm_v4i32_ty], [llvm_ptr_ty, llvm_i32_ty], - [IntrReadMem, IntrArgMemOnly, ImmArg<1>]>; + [IntrReadMem, IntrArgMemOnly]>; def int_mips_ld_d : GCCBuiltin<"__builtin_msa_ld_d">, Intrinsic<[llvm_v2i64_ty], [llvm_ptr_ty, llvm_i32_ty], - [IntrReadMem, IntrArgMemOnly, ImmArg<1>]>; + [IntrReadMem, IntrArgMemOnly]>; def int_mips_ldi_b : GCCBuiltin<"__builtin_msa_ldi_b">, Intrinsic<[llvm_v16i8_ty], [llvm_i32_ty], [IntrNoMem, ImmArg<0>]>; @@ -1684,16 +1684,16 @@ def int_mips_srlri_d : GCCBuiltin<"__builtin_msa_srlri_d">, def int_mips_st_b : GCCBuiltin<"__builtin_msa_st_b">, Intrinsic<[], [llvm_v16i8_ty, llvm_ptr_ty, llvm_i32_ty], - [IntrArgMemOnly, ImmArg<2>]>; + [IntrArgMemOnly]>; def int_mips_st_h : GCCBuiltin<"__builtin_msa_st_h">, Intrinsic<[], [llvm_v8i16_ty, llvm_ptr_ty, llvm_i32_ty], - [IntrArgMemOnly, ImmArg<2>]>; + [IntrArgMemOnly]>; def int_mips_st_w : GCCBuiltin<"__builtin_msa_st_w">, Intrinsic<[], [llvm_v4i32_ty, llvm_ptr_ty, llvm_i32_ty], - [IntrArgMemOnly, ImmArg<2>]>; + [IntrArgMemOnly]>; def int_mips_st_d : GCCBuiltin<"__builtin_msa_st_d">, Intrinsic<[], [llvm_v2i64_ty, llvm_ptr_ty, llvm_i32_ty], - [IntrArgMemOnly, ImmArg<2>]>; + [IntrArgMemOnly]>; def int_mips_subs_s_b : GCCBuiltin<"__builtin_msa_subs_s_b">, Intrinsic<[llvm_v16i8_ty], [llvm_v16i8_ty, llvm_v16i8_ty], [IntrNoMem]>; diff --git a/llvm/lib/CodeGen/SelectionDAG/TargetLowering.cpp b/llvm/lib/CodeGen/SelectionDAG/TargetLowering.cpp index 0b6f8ba4257ca..0ab2f5a292a40 100644 --- a/llvm/lib/CodeGen/SelectionDAG/TargetLowering.cpp +++ b/llvm/lib/CodeGen/SelectionDAG/TargetLowering.cpp @@ -805,6 +805,8 @@ bool TargetLowering::SimplifyDemandedBits( KnownBits Known2, KnownOut; switch (Op.getOpcode()) { + case ISD::TargetConstant: + llvm_unreachable("Can't simplify this node"); case ISD::SCALAR_TO_VECTOR: { if (!DemandedElts[0]) return TLO.CombineTo(Op, TLO.DAG.getUNDEF(VT)); diff --git a/llvm/lib/Target/Sparc/SparcISelLowering.cpp b/llvm/lib/Target/Sparc/SparcISelLowering.cpp index 09dd8395f7676..e8b33f8a70e26 100644 --- a/llvm/lib/Target/Sparc/SparcISelLowering.cpp +++ b/llvm/lib/Target/Sparc/SparcISelLowering.cpp @@ -2244,7 +2244,7 @@ SDValue SparcTargetLowering::LowerF128Compare(SDValue LHS, SDValue RHS, return DAG.getNode(SPISD::CMPICC, DL, MVT::Glue, Result, RHS); } case SPCC::FCC_UL : { - SDValue Mask = DAG.getTargetConstant(1, DL, Result.getValueType()); + SDValue Mask = DAG.getConstant(1, DL, Result.getValueType()); Result = DAG.getNode(ISD::AND, DL, Result.getValueType(), Result, Mask); SDValue RHS = DAG.getTargetConstant(0, DL, Result.getValueType()); SPCC = SPCC::ICC_NE; @@ -2277,14 +2277,14 @@ SDValue SparcTargetLowering::LowerF128Compare(SDValue LHS, SDValue RHS, return DAG.getNode(SPISD::CMPICC, DL, MVT::Glue, Result, RHS); } case SPCC::FCC_LG : { - SDValue Mask = DAG.getTargetConstant(3, DL, Result.getValueType()); + SDValue Mask = DAG.getConstant(3, DL, Result.getValueType()); Result = DAG.getNode(ISD::AND, DL, Result.getValueType(), Result, Mask); SDValue RHS = DAG.getTargetConstant(0, DL, Result.getValueType()); SPCC = SPCC::ICC_NE; return DAG.getNode(SPISD::CMPICC, DL, MVT::Glue, Result, RHS); } case SPCC::FCC_UE : { - SDValue Mask = DAG.getTargetConstant(3, DL, Result.getValueType()); + SDValue Mask = DAG.getConstant(3, DL, Result.getValueType()); Result = DAG.getNode(ISD::AND, DL, Result.getValueType(), Result, Mask); SDValue RHS = DAG.getTargetConstant(0, DL, Result.getValueType()); SPCC = SPCC::ICC_E; From eff88e42f7860ac38cccafd175f5feca4d89c7c3 Mon Sep 17 00:00:00 2001 From: Yitzhak Mandelbaum Date: Fri, 20 Sep 2019 17:11:03 +0000 Subject: [PATCH 15/71] [libTooling] Add `ifBound`, `elseBranch` RangeSelector combinators. Summary: Adds two new combinators and corresponding tests to the RangeSelector library. * `ifBound` -- conditional evaluation of range-selectors, based on whether a given node id is bound in the match. * `elseBranch` -- selects the source range of the else and its statement. Reviewers: gribozavr Subscribers: cfe-commits Tags: #clang Differential Revision: https://reviews.llvm.org/D67621 llvm-svn: 372410 --- .../clang/Tooling/Refactoring/RangeSelector.h | 9 ++++ .../lib/Tooling/Refactoring/RangeSelector.cpp | 24 +++++++++ clang/unittests/Tooling/RangeSelectorTest.cpp | 54 +++++++++++++++++++ 3 files changed, 87 insertions(+) diff --git a/clang/include/clang/Tooling/Refactoring/RangeSelector.h b/clang/include/clang/Tooling/Refactoring/RangeSelector.h index b117e4d82ad46..e5fe051413424 100644 --- a/clang/include/clang/Tooling/Refactoring/RangeSelector.h +++ b/clang/include/clang/Tooling/Refactoring/RangeSelector.h @@ -79,10 +79,19 @@ RangeSelector statements(std::string ID); // (all source between the braces). RangeSelector initListElements(std::string ID); +/// Given an \IfStmt (bound to \p ID), selects the range of the else branch, +/// starting from the \c else keyword. +RangeSelector elseBranch(std::string ID); + /// Selects the range from which `S` was expanded (possibly along with other /// source), if `S` is an expansion, and `S` itself, otherwise. Corresponds to /// `SourceManager::getExpansionRange`. RangeSelector expansion(RangeSelector S); + +/// Chooses between the two selectors, based on whether \p ID is bound in the +/// match. +RangeSelector ifBound(std::string ID, RangeSelector TrueSelector, + RangeSelector FalseSelector); } // namespace tooling } // namespace clang diff --git a/clang/lib/Tooling/Refactoring/RangeSelector.cpp b/clang/lib/Tooling/Refactoring/RangeSelector.cpp index 768c02e2277b3..ae55698189cfd 100644 --- a/clang/lib/Tooling/Refactoring/RangeSelector.cpp +++ b/clang/lib/Tooling/Refactoring/RangeSelector.cpp @@ -219,6 +219,9 @@ RangeSelector tooling::name(std::string ID) { } namespace { +// FIXME: make this available in the public API for users to easily create their +// own selectors. + // Creates a selector from a range-selection function \p Func, which selects a // range that is relative to a bound node id. \c T is the node type expected by // \p Func. @@ -286,6 +289,19 @@ RangeSelector tooling::initListElements(std::string ID) { return RelativeSelector(std::move(ID)); } +namespace { +// Returns the range of the else branch, including the `else` keyword. +CharSourceRange getElseRange(const MatchResult &Result, const IfStmt &S) { + return maybeExtendRange( + CharSourceRange::getTokenRange(S.getElseLoc(), S.getEndLoc()), + tok::TokenKind::semi, *Result.Context); +} +} // namespace + +RangeSelector tooling::elseBranch(std::string ID) { + return RelativeSelector(std::move(ID)); +} + RangeSelector tooling::expansion(RangeSelector S) { return [S](const MatchResult &Result) -> Expected { Expected SRange = S(Result); @@ -294,3 +310,11 @@ RangeSelector tooling::expansion(RangeSelector S) { return Result.SourceManager->getExpansionRange(*SRange); }; } + +RangeSelector tooling::ifBound(std::string ID, RangeSelector TrueSelector, + RangeSelector FalseSelector) { + return [=](const MatchResult &Result) { + auto &Map = Result.Nodes.getMap(); + return (Map.find(ID) != Map.end() ? TrueSelector : FalseSelector)(Result); + }; +} diff --git a/clang/unittests/Tooling/RangeSelectorTest.cpp b/clang/unittests/Tooling/RangeSelectorTest.cpp index 38c15be00cd06..58ce63cbd750f 100644 --- a/clang/unittests/Tooling/RangeSelectorTest.cpp +++ b/clang/unittests/Tooling/RangeSelectorTest.cpp @@ -520,6 +520,35 @@ TEST(RangeSelectorTest, ElementsOpErrors) { Failed(withTypeErrorMessage("stmt"))); } +TEST(RangeSelectorTest, ElseBranchOpSingleStatement) { + StringRef Code = R"cc( + int f() { + int x = 0; + if (true) x = 3; + else x = 4; + return x + 5; + } + )cc"; + StringRef ID = "id"; + TestMatch Match = matchCode(Code, ifStmt().bind(ID)); + EXPECT_THAT_EXPECTED(select(elseBranch(ID), Match), HasValue("else x = 4;")); +} + +TEST(RangeSelectorTest, ElseBranchOpCompoundStatement) { + StringRef Code = R"cc( + int f() { + int x = 0; + if (true) x = 3; + else { x = 4; } + return x + 5; + } + )cc"; + StringRef ID = "id"; + TestMatch Match = matchCode(Code, ifStmt().bind(ID)); + EXPECT_THAT_EXPECTED(select(elseBranch(ID), Match), + HasValue("else { x = 4; }")); +} + // Tests case where the matched node is the complete expanded text. TEST(RangeSelectorTest, ExpansionOp) { StringRef Code = R"cc( @@ -546,4 +575,29 @@ TEST(RangeSelectorTest, ExpansionOpPartial) { HasValue("BADDECL(x * x)")); } +TEST(RangeSelectorTest, IfBoundOpBound) { + StringRef Code = R"cc( + int f() { + return 3 + 5; + } + )cc"; + StringRef ID = "id", Op = "op"; + TestMatch Match = + matchCode(Code, binaryOperator(hasLHS(expr().bind(ID))).bind(Op)); + EXPECT_THAT_EXPECTED(select(ifBound(ID, node(ID), node(Op)), Match), + HasValue("3")); +} + +TEST(RangeSelectorTest, IfBoundOpUnbound) { + StringRef Code = R"cc( + int f() { + return 3 + 5; + } + )cc"; + StringRef ID = "id", Op = "op"; + TestMatch Match = matchCode(Code, binaryOperator().bind(Op)); + EXPECT_THAT_EXPECTED(select(ifBound(ID, node(ID), node(Op)), Match), + HasValue("3 + 5")); +} + } // namespace From 330014843ceccdcb32463875b3fcd36654e75ad4 Mon Sep 17 00:00:00 2001 From: Adrian Prantl Date: Fri, 20 Sep 2019 17:15:57 +0000 Subject: [PATCH 16/71] Doxygenify comments. llvm-svn: 372411 --- lldb/include/lldb/Symbol/Variable.h | 75 ++++++++++++++++------------- lldb/source/Symbol/Variable.cpp | 15 +++--- 2 files changed, 47 insertions(+), 43 deletions(-) diff --git a/lldb/include/lldb/Symbol/Variable.h b/lldb/include/lldb/Symbol/Variable.h index 03a20985462bf..30f57f1f91104 100644 --- a/lldb/include/lldb/Symbol/Variable.h +++ b/lldb/include/lldb/Symbol/Variable.h @@ -26,15 +26,14 @@ class Variable : public UserID, public std::enable_shared_from_this { public: typedef RangeVector RangeList; - // Constructors and Destructors - Variable(lldb::user_id_t uid, const char *name, - const char - *mangled, // The mangled or fully qualified name of the variable. - const lldb::SymbolFileTypeSP &symfile_type_sp, - lldb::ValueType scope, SymbolContextScope *owner_scope, - const RangeList &scope_range, Declaration *decl, - const DWARFExpression &location, bool external, bool artificial, - bool static_member = false); + /// Constructors and Destructors. + /// + /// \param mangled The mangled or fully qualified name of the variable. + Variable(lldb::user_id_t uid, const char *name, const char *mangled, + const lldb::SymbolFileTypeSP &symfile_type_sp, lldb::ValueType scope, + SymbolContextScope *owner_scope, const RangeList &scope_range, + Declaration *decl, const DWARFExpression &location, bool external, + bool artificial, bool static_member = false); virtual ~Variable(); @@ -50,11 +49,11 @@ class Variable : public UserID, public std::enable_shared_from_this { SymbolContextScope *GetSymbolContextScope() const { return m_owner_scope; } - // Since a variable can have a basename "i" and also a mangled named - // "_ZN12_GLOBAL__N_11iE" and a demangled mangled name "(anonymous - // namespace)::i", this function will allow a generic match function that can - // be called by commands and expression parsers to make sure we match - // anything we come across. + /// Since a variable can have a basename "i" and also a mangled named + /// "_ZN12_GLOBAL__N_11iE" and a demangled mangled name "(anonymous + /// namespace)::i", this function will allow a generic match function that can + /// be called by commands and expression parsers to make sure we match + /// anything we come across. bool NameMatches(ConstString name) const; bool NameMatches(const RegularExpression ®ex) const; @@ -107,26 +106,34 @@ class Variable : public UserID, public std::enable_shared_from_this { CompilerDecl GetDecl(); protected: - ConstString m_name; // The basename of the variable (no namespaces) - Mangled m_mangled; // The mangled name of the variable - lldb::SymbolFileTypeSP m_symfile_type_sp; // The type pointer of the variable - // (int, struct, class, etc) - lldb::ValueType m_scope; // global, parameter, local - SymbolContextScope - *m_owner_scope; // The symbol file scope that this variable was defined in - RangeList m_scope_range; // The list of ranges inside the owner's scope where - // this variable is valid - Declaration m_declaration; // Declaration location for this item. - DWARFExpression m_location; // The location of this variable that can be fed - // to DWARFExpression::Evaluate() - uint8_t m_external : 1, // Visible outside the containing compile unit? - m_artificial : 1, // Non-zero if the variable is not explicitly declared - // in source - m_loc_is_const_data : 1, // The m_location expression contains the - // constant variable value data, not a DWARF - // location - m_static_member : 1; // Non-zero if variable is static member of a class - // or struct. + /// The basename of the variable (no namespaces). + ConstString m_name; + /// The mangled name of the variable. + Mangled m_mangled; + /// The type pointer of the variable (int, struct, class, etc) + /// global, parameter, local. + lldb::SymbolFileTypeSP m_symfile_type_sp; + lldb::ValueType m_scope; + /// The symbol file scope that this variable was defined in + SymbolContextScope *m_owner_scope; + /// The list of ranges inside the owner's scope where this variable + /// is valid. + RangeList m_scope_range; + /// Declaration location for this item. + Declaration m_declaration; + /// The location of this variable that can be fed to + /// DWARFExpression::Evaluate(). + DWARFExpression m_location; + /// Visible outside the containing compile unit? + unsigned m_external : 1; + /// Non-zero if the variable is not explicitly declared in source. + unsigned m_artificial : 1; + /// The m_location expression contains the constant variable value + /// data, not a DWARF location. + unsigned m_loc_is_const_data : 1; + /// Non-zero if variable is static member of a class or struct. + unsigned m_static_member : 1; + private: Variable(const Variable &rhs) = delete; Variable &operator=(const Variable &rhs) = delete; diff --git a/lldb/source/Symbol/Variable.cpp b/lldb/source/Symbol/Variable.cpp index 3ec97b1fce7f1..3f3d7c198f15b 100644 --- a/lldb/source/Symbol/Variable.cpp +++ b/lldb/source/Symbol/Variable.cpp @@ -35,14 +35,12 @@ using namespace lldb; using namespace lldb_private; -// Variable constructor -Variable::Variable( - lldb::user_id_t uid, const char *name, - const char *mangled, // The mangled or fully qualified name of the variable. - const lldb::SymbolFileTypeSP &symfile_type_sp, ValueType scope, - SymbolContextScope *context, const RangeList &scope_range, - Declaration *decl_ptr, const DWARFExpression &location, bool external, - bool artificial, bool static_member) +Variable::Variable(lldb::user_id_t uid, const char *name, const char *mangled, + const lldb::SymbolFileTypeSP &symfile_type_sp, + ValueType scope, SymbolContextScope *context, + const RangeList &scope_range, Declaration *decl_ptr, + const DWARFExpression &location, bool external, + bool artificial, bool static_member) : UserID(uid), m_name(name), m_mangled(ConstString(mangled)), m_symfile_type_sp(symfile_type_sp), m_scope(scope), m_owner_scope(context), m_scope_range(scope_range), @@ -50,7 +48,6 @@ Variable::Variable( m_artificial(artificial), m_loc_is_const_data(false), m_static_member(static_member) {} -// Destructor Variable::~Variable() {} lldb::LanguageType Variable::GetLanguage() const { From c2bda3e422a9d00c49f4f3faf3adfb0ac9767097 Mon Sep 17 00:00:00 2001 From: Evgeniy Stepanov Date: Fri, 20 Sep 2019 17:36:27 +0000 Subject: [PATCH 17/71] [MTE] Handle MTE instructions in AArch64LoadStoreOptimizer. Summary: Generate pre- and post-indexed forms of ST*G and STGP when possible. Reviewers: ostannard, vitalybuka Subscribers: kristof.beyls, hiraditya, llvm-commits Tags: #llvm Differential Revision: https://reviews.llvm.org/D67741 llvm-svn: 372412 --- .../AArch64/AArch64LoadStoreOptimizer.cpp | 130 ++++++-- llvm/test/CodeGen/AArch64/ldst-opt-mte.mir | 285 ++++++++++++++++++ llvm/test/CodeGen/AArch64/stgp.ll | 2 +- 3 files changed, 384 insertions(+), 33 deletions(-) create mode 100644 llvm/test/CodeGen/AArch64/ldst-opt-mte.mir diff --git a/llvm/lib/Target/AArch64/AArch64LoadStoreOptimizer.cpp b/llvm/lib/Target/AArch64/AArch64LoadStoreOptimizer.cpp index 5242e87f0eb2b..a0c4a25bb5b96 100644 --- a/llvm/lib/Target/AArch64/AArch64LoadStoreOptimizer.cpp +++ b/llvm/lib/Target/AArch64/AArch64LoadStoreOptimizer.cpp @@ -201,8 +201,22 @@ static bool isNarrowStore(unsigned Opc) { } } +// These instruction set memory tag and either keep memory contents unchanged or +// set it to zero, ignoring the address part of the source register. +static bool isTagStore(const MachineInstr &MI) { + switch (MI.getOpcode()) { + default: + return false; + case AArch64::STGOffset: + case AArch64::STZGOffset: + case AArch64::ST2GOffset: + case AArch64::STZ2GOffset: + return true; + } +} + // Scaling factor for unscaled load or store. -static int getMemScale(MachineInstr &MI) { +static int getMemScale(const MachineInstr &MI) { switch (MI.getOpcode()) { default: llvm_unreachable("Opcode has unknown scale!"); @@ -255,6 +269,11 @@ static int getMemScale(MachineInstr &MI) { case AArch64::STURQi: case AArch64::LDPQi: case AArch64::STPQi: + case AArch64::STGOffset: + case AArch64::STZGOffset: + case AArch64::ST2GOffset: + case AArch64::STZ2GOffset: + case AArch64::STGPi: return 16; } } @@ -449,6 +468,16 @@ static unsigned getPreIndexedOpcode(unsigned Opc) { return AArch64::STPWpre; case AArch64::STPXi: return AArch64::STPXpre; + case AArch64::STGOffset: + return AArch64::STGPreIndex; + case AArch64::STZGOffset: + return AArch64::STZGPreIndex; + case AArch64::ST2GOffset: + return AArch64::ST2GPreIndex; + case AArch64::STZ2GOffset: + return AArch64::STZ2GPreIndex; + case AArch64::STGPi: + return AArch64::STGPpre; } } @@ -518,6 +547,16 @@ static unsigned getPostIndexedOpcode(unsigned Opc) { return AArch64::STPWpost; case AArch64::STPXi: return AArch64::STPXpost; + case AArch64::STGOffset: + return AArch64::STGPostIndex; + case AArch64::STZGOffset: + return AArch64::STZGPostIndex; + case AArch64::ST2GOffset: + return AArch64::ST2GPostIndex; + case AArch64::STZ2GOffset: + return AArch64::STZ2GPostIndex; + case AArch64::STGPi: + return AArch64::STGPpost; } } @@ -536,10 +575,30 @@ static bool isPairedLdSt(const MachineInstr &MI) { case AArch64::STPQi: case AArch64::STPWi: case AArch64::STPXi: + case AArch64::STGPi: return true; } } +// Returns the scale and offset range of pre/post indexed variants of MI. +static void getPrePostIndexedMemOpInfo(const MachineInstr &MI, int &Scale, + int &MinOffset, int &MaxOffset) { + bool IsPaired = isPairedLdSt(MI); + bool IsTagStore = isTagStore(MI); + // ST*G and all paired ldst have the same scale in pre/post-indexed variants + // as in the "unsigned offset" variant. + // All other pre/post indexed ldst instructions are unscaled. + Scale = (IsTagStore || IsPaired) ? getMemScale(MI) : 1; + + if (IsPaired) { + MinOffset = -64; + MaxOffset = 63; + } else { + MinOffset = -256; + MaxOffset = 255; + } +} + static const MachineOperand &getLdStRegOp(const MachineInstr &MI, unsigned PairedRegOp = 0) { assert(PairedRegOp < 2 && "Unexpected register operand idx."); @@ -618,6 +677,11 @@ static bool isMergeableLdStUpdate(MachineInstr &MI) { case AArch64::LDRWui: case AArch64::LDRHHui: case AArch64::LDRBBui: + case AArch64::STGOffset: + case AArch64::STZGOffset: + case AArch64::ST2GOffset: + case AArch64::STZ2GOffset: + case AArch64::STGPi: // Unscaled instructions. case AArch64::STURSi: case AArch64::STURDi: @@ -1328,18 +1392,19 @@ AArch64LoadStoreOpt::mergeUpdateInsn(MachineBasicBlock::iterator I, unsigned NewOpc = IsPreIdx ? getPreIndexedOpcode(I->getOpcode()) : getPostIndexedOpcode(I->getOpcode()); MachineInstrBuilder MIB; + int Scale, MinOffset, MaxOffset; + getPrePostIndexedMemOpInfo(*I, Scale, MinOffset, MaxOffset); if (!isPairedLdSt(*I)) { // Non-paired instruction. MIB = BuildMI(*I->getParent(), I, I->getDebugLoc(), TII->get(NewOpc)) .add(getLdStRegOp(*Update)) .add(getLdStRegOp(*I)) .add(getLdStBaseOp(*I)) - .addImm(Value) + .addImm(Value / Scale) .setMemRefs(I->memoperands()) .setMIFlags(I->mergeFlagsWith(*Update)); } else { // Paired instruction. - int Scale = getMemScale(*I); MIB = BuildMI(*I->getParent(), I, I->getDebugLoc(), TII->get(NewOpc)) .add(getLdStRegOp(*Update)) .add(getLdStRegOp(*I, 0)) @@ -1395,28 +1460,21 @@ bool AArch64LoadStoreOpt::isMatchingUpdateInsn(MachineInstr &MemMI, MI.getOperand(1).getReg() != BaseReg) break; - bool IsPairedInsn = isPairedLdSt(MemMI); int UpdateOffset = MI.getOperand(2).getImm(); if (MI.getOpcode() == AArch64::SUBXri) UpdateOffset = -UpdateOffset; - // For non-paired load/store instructions, the immediate must fit in a - // signed 9-bit integer. - if (!IsPairedInsn && (UpdateOffset > 255 || UpdateOffset < -256)) + // The immediate must be a multiple of the scaling factor of the pre/post + // indexed instruction. + int Scale, MinOffset, MaxOffset; + getPrePostIndexedMemOpInfo(MemMI, Scale, MinOffset, MaxOffset); + if (UpdateOffset % Scale != 0) break; - // For paired load/store instructions, the immediate must be a multiple of - // the scaling factor. The scaled offset must also fit into a signed 7-bit - // integer. - if (IsPairedInsn) { - int Scale = getMemScale(MemMI); - if (UpdateOffset % Scale != 0) - break; - - int ScaledOffset = UpdateOffset / Scale; - if (ScaledOffset > 63 || ScaledOffset < -64) - break; - } + // Scaled offset must fit in the instruction immediate. + int ScaledOffset = UpdateOffset / Scale; + if (ScaledOffset > MaxOffset || ScaledOffset < MinOffset) + break; // If we have a non-zero Offset, we check that it matches the amount // we're adding to the register. @@ -1442,13 +1500,19 @@ MachineBasicBlock::iterator AArch64LoadStoreOpt::findMatchingUpdateInsnForward( if (MIUnscaledOffset != UnscaledOffset) return E; - // If the base register overlaps a destination register, we can't - // merge the update. - bool IsPairedInsn = isPairedLdSt(MemMI); - for (unsigned i = 0, e = IsPairedInsn ? 2 : 1; i != e; ++i) { - Register DestReg = getLdStRegOp(MemMI, i).getReg(); - if (DestReg == BaseReg || TRI->isSubRegister(BaseReg, DestReg)) - return E; + // If the base register overlaps a source/destination register, we can't + // merge the update. This does not apply to tag store instructions which + // ignore the address part of the source register. + // This does not apply to STGPi as well, which does not have unpredictable + // behavior in this case unlike normal stores, and always performs writeback + // after reading the source register value. + if (!isTagStore(MemMI) && MemMI.getOpcode() != AArch64::STGPi) { + bool IsPairedInsn = isPairedLdSt(MemMI); + for (unsigned i = 0, e = IsPairedInsn ? 2 : 1; i != e; ++i) { + Register DestReg = getLdStRegOp(MemMI, i).getReg(); + if (DestReg == BaseReg || TRI->isSubRegister(BaseReg, DestReg)) + return E; + } } // Track which register units have been modified and used between the first @@ -1496,11 +1560,13 @@ MachineBasicBlock::iterator AArch64LoadStoreOpt::findMatchingUpdateInsnBackward( return E; // If the base register overlaps a destination register, we can't // merge the update. - bool IsPairedInsn = isPairedLdSt(MemMI); - for (unsigned i = 0, e = IsPairedInsn ? 2 : 1; i != e; ++i) { - Register DestReg = getLdStRegOp(MemMI, i).getReg(); - if (DestReg == BaseReg || TRI->isSubRegister(BaseReg, DestReg)) - return E; + if (!isTagStore(MemMI)) { + bool IsPairedInsn = isPairedLdSt(MemMI); + for (unsigned i = 0, e = IsPairedInsn ? 2 : 1; i != e; ++i) { + Register DestReg = getLdStRegOp(MemMI, i).getReg(); + if (DestReg == BaseReg || TRI->isSubRegister(BaseReg, DestReg)) + return E; + } } // Track which register units have been modified and used between the first @@ -1659,7 +1725,7 @@ bool AArch64LoadStoreOpt::tryToMergeLdStUpdate // however, is not, so adjust here. int UnscaledOffset = getLdStOffsetOp(MI).getImm() * getMemScale(MI); - // Look forward to try to find a post-index instruction. For example, + // Look forward to try to find a pre-index instruction. For example, // ldr x1, [x0, #64] // add x0, x0, #64 // merged into: diff --git a/llvm/test/CodeGen/AArch64/ldst-opt-mte.mir b/llvm/test/CodeGen/AArch64/ldst-opt-mte.mir new file mode 100644 index 0000000000000..b44258abd8871 --- /dev/null +++ b/llvm/test/CodeGen/AArch64/ldst-opt-mte.mir @@ -0,0 +1,285 @@ +# RUN: llc -mtriple=aarch64-none-linux-gnu -run-pass aarch64-ldst-opt -verify-machineinstrs -o - %s | FileCheck %s +--- + +### STG and its offset limits + +# CHECK-LABEL: name: test_STG_post +# CHECK: STGPostIndex $x0, $x0, 7 +name: test_STG_post +body: | + bb.0.entry: + liveins: $x0 + + STGOffset $x0, $x0, 0 + $x0 = ADDXri $x0, 112, 0 + RET_ReallyLR implicit $x0 +... + +# CHECK-LABEL: name: test_STG_post_same_reg +# CHECK: STGPostIndex $x1, $x0, 7 +name: test_STG_post_same_reg +body: | + bb.0.entry: + liveins: $x0, $x1 + + STGOffset $x1, $x0, 0 + $x0 = ADDXri $x0, 112, 0 + RET_ReallyLR implicit $x0 +... + +# CHECK-LABEL: name: test_STG_post_unaligned +# CHECK: STGOffset $x0, $x0, 0 +# CHECK-NEXT: ADDXri $x0, 8, 0 +name: test_STG_post_unaligned +body: | + bb.0.entry: + liveins: $x0 + + STGOffset $x0, $x0, 0 + $x0 = ADDXri $x0, 8, 0 + RET_ReallyLR implicit $x0 +... + +# CHECK-LABEL: name: test_STG_post2 +# CHECK: STGPostIndex $x0, $x0, -256 +name: test_STG_post2 +body: | + bb.0.entry: + liveins: $x0 + + STGOffset $x0, $x0, 0 + $x0 = SUBXri $x0, 4096, 0 + RET_ReallyLR implicit $x0 +... + +# CHECK-LABEL: name: test_STG_post3 +# CHECK: STGOffset $x0, $x0, 0 +# CHECK-NEXT: SUBXri $x0, 4112, 0 +name: test_STG_post3 +body: | + bb.0.entry: + liveins: $x0 + + STGOffset $x0, $x0, 0 + $x0 = SUBXri $x0, 4112, 0 + RET_ReallyLR implicit $x0 +... + +# CHECK-LABEL: name: test_STG_post4 +# CHECK: STGPostIndex $x0, $x0, 255 +name: test_STG_post4 +body: | + bb.0.entry: + liveins: $x0 + + STGOffset $x0, $x0, 0 + $x0 = ADDXri $x0, 4080, 0 + RET_ReallyLR implicit $x0 +... + +# CHECK-LABEL: name: test_STG_post5 +# CHECK: STGOffset $x0, $x0, 0 +# CHECK-NEXT: ADDXri $x0, 4096, 0 +name: test_STG_post5 +body: | + bb.0.entry: + liveins: $x0 + + STGOffset $x0, $x0, 0 + $x0 = ADDXri $x0, 4096, 0 + RET_ReallyLR implicit $x0 +... + +### The rest of ST*G variants. + +# CHECK-LABEL: name: test_STZG_post +# CHECK: STZGPostIndex $x0, $x0, 7 +name: test_STZG_post +body: | + bb.0.entry: + liveins: $x0 + + STZGOffset $x0, $x0, 0 + $x0 = ADDXri $x0, 112, 0 + RET_ReallyLR implicit $x0 +... + +# CHECK-LABEL: name: test_ST2G_post +# CHECK: ST2GPostIndex $x0, $x0, 7 +name: test_ST2G_post +body: | + bb.0.entry: + liveins: $x0 + + ST2GOffset $x0, $x0, 0 + $x0 = ADDXri $x0, 112, 0 + RET_ReallyLR implicit $x0 +... + +# CHECK-LABEL: name: test_STZ2G_post +# CHECK: STZ2GPostIndex $x0, $x0, 7 +name: test_STZ2G_post +body: | + bb.0.entry: + liveins: $x0 + + STZ2GOffset $x0, $x0, 0 + $x0 = ADDXri $x0, 112, 0 + RET_ReallyLR implicit $x0 +... + +### STGP and its offset limits + +# CHECK-LABEL: name: test_STGP_post +# CHECK: STGPpost $x1, $x2, $x0, 7 +name: test_STGP_post +body: | + bb.0.entry: + liveins: $x0, $x1, $x2 + + STGPi $x1, $x2, $x0, 0 + $x0 = ADDXri $x0, 112, 0 + RET_ReallyLR implicit $x0 +... + +# CHECK-LABEL: name: test_STGP_post2 +# CHECK: STGPpost $x1, $x2, $x0, -64 +name: test_STGP_post2 +body: | + bb.0.entry: + liveins: $x0, $x1, $x2 + + STGPi $x1, $x2, $x0, 0 + $x0 = SUBXri $x0, 1024, 0 + RET_ReallyLR implicit $x0 +... + +# CHECK-LABEL: name: test_STGP_post3 +# CHECK: STGPi $x1, $x2, $x0, 0 +# CHECK-NEXT: SUBXri $x0, 1040, 0 +name: test_STGP_post3 +body: | + bb.0.entry: + liveins: $x0, $x1, $x2 + + STGPi $x1, $x2, $x0, 0 + $x0 = SUBXri $x0, 1040, 0 + RET_ReallyLR implicit $x0 +... + +# CHECK-LABEL: name: test_STGP_post4 +# CHECK: STGPpost $x1, $x2, $x0, 63 +name: test_STGP_post4 +body: | + bb.0.entry: + liveins: $x0, $x1, $x2 + + STGPi $x1, $x2, $x0, 0 + $x0 = ADDXri $x0, 1008, 0 + RET_ReallyLR implicit $x0 +... + +# CHECK-LABEL: name: test_STGP_post5 +# CHECK: STGPi $x1, $x2, $x0, 0 +# CHECK-NEXT: ADDXri $x0, 1024, 0 +name: test_STGP_post5 +body: | + bb.0.entry: + liveins: $x0, $x1, $x2 + + STGPi $x1, $x2, $x0, 0 + $x0 = ADDXri $x0, 1024, 0 + RET_ReallyLR implicit $x0 +... + +### Pre-indexed forms + +# CHECK-LABEL: name: test_STG_pre +# CHECK: STGPreIndex $x0, $x0, 10 +name: test_STG_pre +body: | + bb.0.entry: + liveins: $x0 + + STGOffset $x0, $x0, 10 + $x0 = ADDXri $x0, 160, 0 + RET_ReallyLR implicit $x0 +... + +# CHECK-LABEL: name: test_STGP_pre +# CHECK: STGPpre $x1, $x2, $x0, 10 +name: test_STGP_pre +body: | + bb.0.entry: + liveins: $x0, $x1, $x2 + + STGPi $x1, $x2, $x0, 10 + $x0 = ADDXri $x0, 160, 0 + RET_ReallyLR implicit $x0 +... + +### Pre-indexed forms with add/sub coming before the store. + +# CHECK-LABEL: name: test_STG_pre_back +# CHECK: STGPreIndex $x0, $x0, 2 +name: test_STG_pre_back +body: | + bb.0.entry: + liveins: $x0 + + $x0 = ADDXri $x0, 32, 0 + STGOffset $x0, $x0, 0 + RET_ReallyLR implicit $x0 +... + +# CHECK-LABEL: name: test_STGP_pre_back +# CHECK: STGPpre $x1, $x2, $x0, -3 +name: test_STGP_pre_back +body: | + bb.0.entry: + liveins: $x0, $x1, $x2 + + $x0 = SUBXri $x0, 48, 0 + STGPi $x1, $x2, $x0, 0 + RET_ReallyLR implicit $x0 +... + +### STGP with source register == address register + +# CHECK-LABEL: name: test_STGP_post_same_reg +# CHECK: STGPpost $x0, $x0, $x0, 7 +name: test_STGP_post_same_reg +body: | + bb.0.entry: + liveins: $x0 + + STGPi $x0, $x0, $x0, 0 + $x0 = ADDXri $x0, 112, 0 + RET_ReallyLR implicit $x0 +... + +# CHECK-LABEL: name: test_STGP_pre_same_reg +# CHECK: STGPpre $x0, $x0, $x0, 7 +name: test_STGP_pre_same_reg +body: | + bb.0.entry: + liveins: $x0 + + STGPi $x0, $x0, $x0, 7 + $x0 = ADDXri $x0, 112, 0 + RET_ReallyLR implicit $x0 +... + +# This case can not be merged because the source register is always read before writeback. +# CHECK-LABEL: name: test_STGP_pre_back_same_reg +# CHECK: SUBXri $x0, 48, 0 +# CHECK-NEXT: STGPi $x0, $x0, $x0, 0 +name: test_STGP_pre_back_same_reg +body: | + bb.0.entry: + liveins: $x0 + + $x0 = SUBXri $x0, 48, 0 + STGPi $x0, $x0, $x0, 0 + RET_ReallyLR implicit $x0 +... diff --git a/llvm/test/CodeGen/AArch64/stgp.ll b/llvm/test/CodeGen/AArch64/stgp.ll index b4af16fd9ff79..d82b45134f552 100644 --- a/llvm/test/CodeGen/AArch64/stgp.ll +++ b/llvm/test/CodeGen/AArch64/stgp.ll @@ -65,7 +65,7 @@ entry: define void @stgp_alloca(i64 %a, i64 %b) { entry: ; CHECK-LABEL: stgp_alloca: -; CHECK: stgp x0, x1, [sp] +; CHECK: stgp x0, x1, [sp, #-32]! ; CHECK: stgp x1, x0, [sp, #16] ; CHECK: ret %x = alloca i8, i32 32, align 16 From 081eebc58fcc9baa7517b20eb1243e0bf056a683 Mon Sep 17 00:00:00 2001 From: Roman Lebedev Date: Fri, 20 Sep 2019 17:43:46 +0000 Subject: [PATCH 18/71] [NFC][InstCombine] Fixup newly-added tests llvm-svn: 372413 --- ...ult-of-add-of-negative-is-non-zero-and-no-underflow.ll | 8 ++++---- ...dd-of-negative-or-zero-is-non-zero-and-no-underflow.ll | 8 ++++---- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/llvm/test/Transforms/InstCombine/result-of-add-of-negative-is-non-zero-and-no-underflow.ll b/llvm/test/Transforms/InstCombine/result-of-add-of-negative-is-non-zero-and-no-underflow.ll index 1253988f97533..00a37a5822d16 100644 --- a/llvm/test/Transforms/InstCombine/result-of-add-of-negative-is-non-zero-and-no-underflow.ll +++ b/llvm/test/Transforms/InstCombine/result-of-add-of-negative-is-non-zero-and-no-underflow.ll @@ -171,7 +171,7 @@ define i1 @t7_commutativity1(i8 %base, i8 %offset) { ; CHECK-NEXT: [[ADJUSTED:%.*]] = add i8 [[BASE]], [[OFFSET:%.*]] ; CHECK-NEXT: call void @use8(i8 [[ADJUSTED]]) ; CHECK-NEXT: [[NOT_NULL:%.*]] = icmp ne i8 [[ADJUSTED]], 0 -; CHECK-NEXT: [[NO_UNDERFLOW:%.*]] = icmp ule i8 [[ADJUSTED]], [[BASE]] +; CHECK-NEXT: [[NO_UNDERFLOW:%.*]] = icmp ult i8 [[ADJUSTED]], [[BASE]] ; CHECK-NEXT: [[R:%.*]] = and i1 [[NOT_NULL]], [[NO_UNDERFLOW]] ; CHECK-NEXT: ret i1 [[R]] ; @@ -181,7 +181,7 @@ define i1 @t7_commutativity1(i8 %base, i8 %offset) { %adjusted = add i8 %base, %offset call void @use8(i8 %adjusted) %not_null = icmp ne i8 %adjusted, 0 - %no_underflow = icmp uge i8 %base, %adjusted ; swapped + %no_underflow = icmp ugt i8 %base, %adjusted ; swapped %r = and i1 %not_null, %no_underflow ret i1 %r } @@ -192,7 +192,7 @@ define i1 @t7_commutativity3(i8 %base, i8 %offset) { ; CHECK-NEXT: [[ADJUSTED:%.*]] = add i8 [[BASE]], [[OFFSET:%.*]] ; CHECK-NEXT: call void @use8(i8 [[ADJUSTED]]) ; CHECK-NEXT: [[NOT_NULL:%.*]] = icmp ne i8 [[ADJUSTED]], 0 -; CHECK-NEXT: [[NO_UNDERFLOW:%.*]] = icmp ule i8 [[ADJUSTED]], [[BASE]] +; CHECK-NEXT: [[NO_UNDERFLOW:%.*]] = icmp ult i8 [[ADJUSTED]], [[BASE]] ; CHECK-NEXT: [[R:%.*]] = and i1 [[NO_UNDERFLOW]], [[NOT_NULL]] ; CHECK-NEXT: ret i1 [[R]] ; @@ -202,7 +202,7 @@ define i1 @t7_commutativity3(i8 %base, i8 %offset) { %adjusted = add i8 %base, %offset call void @use8(i8 %adjusted) %not_null = icmp ne i8 %adjusted, 0 - %no_underflow = icmp uge i8 %base, %adjusted ; swapped + %no_underflow = icmp ugt i8 %base, %adjusted ; swapped %r = and i1 %no_underflow, %not_null ; swapped ret i1 %r } diff --git a/llvm/test/Transforms/InstCombine/result-of-add-of-negative-or-zero-is-non-zero-and-no-underflow.ll b/llvm/test/Transforms/InstCombine/result-of-add-of-negative-or-zero-is-non-zero-and-no-underflow.ll index abf8f9b862725..de4fd42b5bfe0 100644 --- a/llvm/test/Transforms/InstCombine/result-of-add-of-negative-or-zero-is-non-zero-and-no-underflow.ll +++ b/llvm/test/Transforms/InstCombine/result-of-add-of-negative-or-zero-is-non-zero-and-no-underflow.ll @@ -102,14 +102,14 @@ define i1 @t5_commutativity1(i8 %base, i8 %offset) { ; CHECK-NEXT: [[ADJUSTED:%.*]] = add i8 [[BASE:%.*]], [[OFFSET:%.*]] ; CHECK-NEXT: call void @use8(i8 [[ADJUSTED]]) ; CHECK-NEXT: [[NOT_NULL:%.*]] = icmp ne i8 [[ADJUSTED]], 0 -; CHECK-NEXT: [[NO_UNDERFLOW:%.*]] = icmp ult i8 [[ADJUSTED]], [[BASE]] +; CHECK-NEXT: [[NO_UNDERFLOW:%.*]] = icmp ule i8 [[ADJUSTED]], [[BASE]] ; CHECK-NEXT: [[R:%.*]] = and i1 [[NOT_NULL]], [[NO_UNDERFLOW]] ; CHECK-NEXT: ret i1 [[R]] ; %adjusted = add i8 %base, %offset call void @use8(i8 %adjusted) %not_null = icmp ne i8 %adjusted, 0 - %no_underflow = icmp ugt i8 %base, %adjusted ; swapped + %no_underflow = icmp uge i8 %base, %adjusted ; swapped %r = and i1 %not_null, %no_underflow ret i1 %r } @@ -118,14 +118,14 @@ define i1 @t6_commutativity3(i8 %base, i8 %offset) { ; CHECK-NEXT: [[ADJUSTED:%.*]] = add i8 [[BASE:%.*]], [[OFFSET:%.*]] ; CHECK-NEXT: call void @use8(i8 [[ADJUSTED]]) ; CHECK-NEXT: [[NOT_NULL:%.*]] = icmp ne i8 [[ADJUSTED]], 0 -; CHECK-NEXT: [[NO_UNDERFLOW:%.*]] = icmp ult i8 [[ADJUSTED]], [[BASE]] +; CHECK-NEXT: [[NO_UNDERFLOW:%.*]] = icmp ule i8 [[ADJUSTED]], [[BASE]] ; CHECK-NEXT: [[R:%.*]] = and i1 [[NO_UNDERFLOW]], [[NOT_NULL]] ; CHECK-NEXT: ret i1 [[R]] ; %adjusted = add i8 %base, %offset call void @use8(i8 %adjusted) %not_null = icmp ne i8 %adjusted, 0 - %no_underflow = icmp ugt i8 %base, %adjusted ; swapped + %no_underflow = icmp uge i8 %base, %adjusted ; swapped %r = and i1 %no_underflow, %not_null ; swapped ret i1 %r } From 951cd32f4ba8e2cc08814a609853c11c69efc394 Mon Sep 17 00:00:00 2001 From: Kristof Umann Date: Fri, 20 Sep 2019 17:59:20 +0000 Subject: [PATCH 19/71] Reland '[analyzer][MallocChecker][NFC] Document and reorganize some functions' Differential Revision: https://reviews.llvm.org/D54823 llvm-svn: 372414 --- .../StaticAnalyzer/Checkers/MallocChecker.cpp | 1183 ++++++++++------- 1 file changed, 720 insertions(+), 463 deletions(-) diff --git a/clang/lib/StaticAnalyzer/Checkers/MallocChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/MallocChecker.cpp index 699b5c6b9fa8e..144096f8087f7 100644 --- a/clang/lib/StaticAnalyzer/Checkers/MallocChecker.cpp +++ b/clang/lib/StaticAnalyzer/Checkers/MallocChecker.cpp @@ -6,8 +6,41 @@ // //===----------------------------------------------------------------------===// // -// This file defines malloc/free checker, which checks for potential memory -// leaks, double free, and use-after-free problems. +// This file defines a variety of memory management related checkers, such as +// leak, double free, and use-after-free. +// +// The following checkers are defined here: +// +// * MallocChecker +// Despite its name, it models all sorts of memory allocations and +// de- or reallocation, including but not limited to malloc, free, +// relloc, new, delete. It also reports on a variety of memory misuse +// errors. +// Many other checkers interact very closely with this checker, in fact, +// most are merely options to this one. Other checkers may register +// MallocChecker, but do not enable MallocChecker's reports (more details +// to follow around its field, ChecksEnabled). +// It also has a boolean "Optimistic" checker option, which if set to true +// will cause the checker to model user defined memory management related +// functions annotated via the attribute ownership_takes, ownership_holds +// and ownership_returns. +// +// * NewDeleteChecker +// Enables the modeling of new, new[], delete, delete[] in MallocChecker, +// and checks for related double-free and use-after-free errors. +// +// * NewDeleteLeaksChecker +// Checks for leaks related to new, new[], delete, delete[]. +// Depends on NewDeleteChecker. +// +// * MismatchedDeallocatorChecker +// Enables checking whether memory is deallocated with the correspending +// allocation function in MallocChecker, such as malloc() allocated +// regions are only freed by free(), new by delete, new[] by delete[]. +// +// InnerPointerChecker interacts very closely with MallocChecker, but unlike +// the above checkers, it has it's own file, hence the many InnerPointerChecker +// related headers and non-static functions. // //===----------------------------------------------------------------------===// @@ -37,6 +70,10 @@ using namespace clang; using namespace ento; +//===----------------------------------------------------------------------===// +// The types of allocation we're modeling. +//===----------------------------------------------------------------------===// + namespace { // Used to check correspondence between allocators and deallocators. @@ -50,57 +87,88 @@ enum AllocationFamily { AF_InnerBuffer }; +struct MemFunctionInfoTy; + +} // end of anonymous namespace + +/// Determine family of a deallocation expression. +static AllocationFamily +getAllocationFamily(const MemFunctionInfoTy &MemFunctionInfo, CheckerContext &C, + const Stmt *S); + +/// Print names of allocators and deallocators. +/// +/// \returns true on success. +static bool printAllocDeallocName(raw_ostream &os, CheckerContext &C, + const Expr *E); + +/// Print expected name of an allocator based on the deallocator's +/// family derived from the DeallocExpr. +static void printExpectedAllocName(raw_ostream &os, + const MemFunctionInfoTy &MemFunctionInfo, + CheckerContext &C, const Expr *E); + +/// Print expected name of a deallocator based on the allocator's +/// family. +static void printExpectedDeallocName(raw_ostream &os, AllocationFamily Family); + +//===----------------------------------------------------------------------===// +// The state of a symbol, in terms of memory management. +//===----------------------------------------------------------------------===// + +namespace { + class RefState { - enum Kind { // Reference to allocated memory. - Allocated, - // Reference to zero-allocated memory. - AllocatedOfSizeZero, - // Reference to released/freed memory. - Released, - // The responsibility for freeing resources has transferred from - // this reference. A relinquished symbol should not be freed. - Relinquished, - // We are no longer guaranteed to have observed all manipulations - // of this pointer/memory. For example, it could have been - // passed as a parameter to an opaque function. - Escaped + enum Kind { + // Reference to allocated memory. + Allocated, + // Reference to zero-allocated memory. + AllocatedOfSizeZero, + // Reference to released/freed memory. + Released, + // The responsibility for freeing resources has transferred from + // this reference. A relinquished symbol should not be freed. + Relinquished, + // We are no longer guaranteed to have observed all manipulations + // of this pointer/memory. For example, it could have been + // passed as a parameter to an opaque function. + Escaped }; const Stmt *S; - unsigned K : 3; // Kind enum, but stored as a bitfield. - unsigned Family : 29; // Rest of 32-bit word, currently just an allocation - // family. - RefState(Kind k, const Stmt *s, unsigned family) - : S(s), K(k), Family(family) { + Kind K : 3; + AllocationFamily Family : 3; + + RefState(Kind k, const Stmt *s, AllocationFamily family) + : S(s), K(k), Family(family) { assert(family != AF_None); } + public: bool isAllocated() const { return K == Allocated; } bool isAllocatedOfSizeZero() const { return K == AllocatedOfSizeZero; } bool isReleased() const { return K == Released; } bool isRelinquished() const { return K == Relinquished; } bool isEscaped() const { return K == Escaped; } - AllocationFamily getAllocationFamily() const { - return (AllocationFamily)Family; - } + AllocationFamily getAllocationFamily() const { return Family; } const Stmt *getStmt() const { return S; } bool operator==(const RefState &X) const { return K == X.K && S == X.S && Family == X.Family; } - static RefState getAllocated(unsigned family, const Stmt *s) { + static RefState getAllocated(AllocationFamily family, const Stmt *s) { return RefState(Allocated, s, family); } static RefState getAllocatedOfSizeZero(const RefState *RS) { return RefState(AllocatedOfSizeZero, RS->getStmt(), RS->getAllocationFamily()); } - static RefState getReleased(unsigned family, const Stmt *s) { + static RefState getReleased(AllocationFamily family, const Stmt *s) { return RefState(Released, s, family); } - static RefState getRelinquished(unsigned family, const Stmt *s) { + static RefState getRelinquished(AllocationFamily family, const Stmt *s) { return RefState(Relinquished, s, family); } static RefState getEscaped(const RefState *RS) { @@ -113,8 +181,8 @@ class RefState { ID.AddInteger(Family); } - void dump(raw_ostream &OS) const { - switch (static_cast(K)) { + LLVM_DUMP_METHOD void dump(raw_ostream &OS) const { + switch (K) { #define CASE(ID) case ID: OS << #ID; break; CASE(Allocated) CASE(AllocatedOfSizeZero) @@ -127,24 +195,62 @@ class RefState { LLVM_DUMP_METHOD void dump() const { dump(llvm::errs()); } }; -enum ReallocPairKind { - RPToBeFreedAfterFailure, - // The symbol has been freed when reallocation failed. - RPIsFreeOnFailure, - // The symbol does not need to be freed after reallocation fails. - RPDoNotTrackAfterFailure +} // end of anonymous namespace + +REGISTER_MAP_WITH_PROGRAMSTATE(RegionState, SymbolRef, RefState) + +/// Check if the memory associated with this symbol was released. +static bool isReleased(SymbolRef Sym, CheckerContext &C); + +/// Update the RefState to reflect the new memory allocation. +/// The optional \p RetVal parameter specifies the newly allocated pointer +/// value; if unspecified, the value of expression \p E is used. +static ProgramStateRef MallocUpdateRefState(CheckerContext &C, const Expr *E, + ProgramStateRef State, + AllocationFamily Family = AF_Malloc, + Optional RetVal = None); + +//===----------------------------------------------------------------------===// +// The modeling of memory reallocation. +// +// The terminology 'toPtr' and 'fromPtr' will be used: +// toPtr = realloc(fromPtr, 20); +//===----------------------------------------------------------------------===// + +REGISTER_SET_WITH_PROGRAMSTATE(ReallocSizeZeroSymbols, SymbolRef) + +namespace { + +/// The state of 'fromPtr' after reallocation is known to have failed. +enum OwnershipAfterReallocKind { + // The symbol needs to be freed (e.g.: realloc) + OAR_ToBeFreedAfterFailure, + // The symbol has been freed (e.g.: reallocf) + OAR_FreeOnFailure, + // The symbol doesn't have to freed (e.g.: we aren't sure if, how and where + // 'fromPtr' was allocated: + // void Haha(int *ptr) { + // ptr = realloc(ptr, 67); + // // ... + // } + // ). + OAR_DoNotTrackAfterFailure }; -/// \class ReallocPair -/// Stores information about the symbol being reallocated by a call to -/// 'realloc' to allow modeling failed reallocation later in the path. +/// Stores information about the 'fromPtr' symbol after reallocation. +/// +/// This is important because realloc may fail, and that needs special modeling. +/// Whether reallocation failed or not will not be known until later, so we'll +/// store whether upon failure 'fromPtr' will be freed, or needs to be freed +/// later, etc. struct ReallocPair { - // The symbol which realloc reallocated. + + // The 'fromPtr'. SymbolRef ReallocatedSym; - ReallocPairKind Kind; + OwnershipAfterReallocKind Kind; - ReallocPair(SymbolRef S, ReallocPairKind K) : - ReallocatedSym(S), Kind(K) {} + ReallocPair(SymbolRef S, OwnershipAfterReallocKind K) + : ReallocatedSym(S), Kind(K) {} void Profile(llvm::FoldingSetNodeID &ID) const { ID.AddInteger(Kind); ID.AddPointer(ReallocatedSym); @@ -155,42 +261,88 @@ struct ReallocPair { } }; -typedef std::pair LeakInfo; - -class MallocChecker : public Checker, - check::EndFunction, - check::PreCall, - check::PostStmt, - check::PostStmt, - check::NewAllocator, - check::PreStmt, - check::PostStmt, - check::PostObjCMessage, - check::Location, - eval::Assume> -{ -public: - MallocChecker() - : II_alloca(nullptr), II_win_alloca(nullptr), II_malloc(nullptr), - II_free(nullptr), II_realloc(nullptr), II_calloc(nullptr), - II_valloc(nullptr), II_reallocf(nullptr), II_strndup(nullptr), - II_strdup(nullptr), II_win_strdup(nullptr), II_kmalloc(nullptr), - II_kfree(nullptr), II_if_nameindex(nullptr), - II_if_freenameindex(nullptr), II_wcsdup(nullptr), - II_win_wcsdup(nullptr), II_g_malloc(nullptr), II_g_malloc0(nullptr), - II_g_realloc(nullptr), II_g_try_malloc(nullptr), - II_g_try_malloc0(nullptr), II_g_try_realloc(nullptr), - II_g_free(nullptr), II_g_memdup(nullptr), II_g_malloc_n(nullptr), - II_g_malloc0_n(nullptr), II_g_realloc_n(nullptr), - II_g_try_malloc_n(nullptr), II_g_try_malloc0_n(nullptr), - II_g_try_realloc_n(nullptr) {} +} // end of anonymous namespace + +REGISTER_MAP_WITH_PROGRAMSTATE(ReallocPairs, SymbolRef, ReallocPair) + +//===----------------------------------------------------------------------===// +// Kinds of memory operations, information about resource managing functions. +//===----------------------------------------------------------------------===// + +namespace { + +enum class MemoryOperationKind { MOK_Allocate, MOK_Free, MOK_Any }; +struct MemFunctionInfoTy { + /// The value of the MallocChecker:Optimistic is stored in this variable. + /// /// In pessimistic mode, the checker assumes that it does not know which /// functions might free the memory. + /// In optimistic mode, the checker assumes that all user-defined functions + /// which might free a pointer are annotated. + DefaultBool ShouldIncludeOwnershipAnnotatedFunctions; + + // TODO: Change these to CallDescription, and get rid of lazy initialization. + mutable IdentifierInfo *II_alloca = nullptr, *II_win_alloca = nullptr, + *II_malloc = nullptr, *II_free = nullptr, + *II_realloc = nullptr, *II_calloc = nullptr, + *II_valloc = nullptr, *II_reallocf = nullptr, + *II_strndup = nullptr, *II_strdup = nullptr, + *II_win_strdup = nullptr, *II_kmalloc = nullptr, + *II_if_nameindex = nullptr, + *II_if_freenameindex = nullptr, *II_wcsdup = nullptr, + *II_win_wcsdup = nullptr, *II_g_malloc = nullptr, + *II_g_malloc0 = nullptr, *II_g_realloc = nullptr, + *II_g_try_malloc = nullptr, + *II_g_try_malloc0 = nullptr, + *II_g_try_realloc = nullptr, *II_g_free = nullptr, + *II_g_memdup = nullptr, *II_g_malloc_n = nullptr, + *II_g_malloc0_n = nullptr, *II_g_realloc_n = nullptr, + *II_g_try_malloc_n = nullptr, + *II_g_try_malloc0_n = nullptr, *II_kfree = nullptr, + *II_g_try_realloc_n = nullptr; + + void initIdentifierInfo(ASTContext &C) const; + + ///@{ + /// Check if this is one of the functions which can allocate/reallocate + /// memory pointed to by one of its arguments. + bool isMemFunction(const FunctionDecl *FD, ASTContext &C) const; + bool isCMemFunction(const FunctionDecl *FD, ASTContext &C, + AllocationFamily Family, + MemoryOperationKind MemKind) const; + + /// Tells if the callee is one of the builtin new/delete operators, including + /// placement operators and other standard overloads. + bool isStandardNewDelete(const FunctionDecl *FD, ASTContext &C) const; + ///@} +}; + +} // end of anonymous namespace + +//===----------------------------------------------------------------------===// +// Definition of the MallocChecker class. +//===----------------------------------------------------------------------===// + +namespace { + +class MallocChecker + : public Checker, + check::EndFunction, check::PreCall, + check::PostStmt, check::PostStmt, + check::NewAllocator, check::PreStmt, + check::PostStmt, check::PostObjCMessage, + check::Location, eval::Assume> { +public: + MemFunctionInfoTy MemFunctionInfo; + + /// Many checkers are essentially built into this one, so enabling them will + /// make MallocChecker perform additional modeling and reporting. enum CheckKind { + /// When a subchecker is enabled but MallocChecker isn't, model memory + /// management but do not emit warnings emitted with MallocChecker only + /// enabled. CK_MallocChecker, CK_NewDeleteChecker, CK_NewDeleteLeaksChecker, @@ -199,13 +351,7 @@ class MallocChecker : public Checker; DefaultBool ChecksEnabled[CK_NumCheckKinds]; CheckerNameRef CheckNames[CK_NumCheckKinds]; @@ -248,47 +394,9 @@ class MallocChecker : public Checker BT_MismatchedDealloc; mutable std::unique_ptr BT_OffsetFree[CK_NumCheckKinds]; mutable std::unique_ptr BT_UseZerroAllocated[CK_NumCheckKinds]; - mutable IdentifierInfo *II_alloca, *II_win_alloca, *II_malloc, *II_free, - *II_realloc, *II_calloc, *II_valloc, *II_reallocf, - *II_strndup, *II_strdup, *II_win_strdup, *II_kmalloc, - *II_kfree, *II_if_nameindex, *II_if_freenameindex, - *II_wcsdup, *II_win_wcsdup, *II_g_malloc, - *II_g_malloc0, *II_g_realloc, *II_g_try_malloc, - *II_g_try_malloc0, *II_g_try_realloc, *II_g_free, - *II_g_memdup, *II_g_malloc_n, *II_g_malloc0_n, - *II_g_realloc_n, *II_g_try_malloc_n, - *II_g_try_malloc0_n, *II_g_try_realloc_n; - mutable Optional KernelZeroFlagVal; - void initIdentifierInfo(ASTContext &C) const; - - /// Determine family of a deallocation expression. - AllocationFamily getAllocationFamily(CheckerContext &C, const Stmt *S) const; - - /// Print names of allocators and deallocators. - /// - /// \returns true on success. - bool printAllocDeallocName(raw_ostream &os, CheckerContext &C, - const Expr *E) const; - - /// Print expected name of an allocator based on the deallocator's - /// family derived from the DeallocExpr. - void printExpectedAllocName(raw_ostream &os, CheckerContext &C, - const Expr *DeallocExpr) const; - /// Print expected name of a deallocator based on the allocator's - /// family. - void printExpectedDeallocName(raw_ostream &os, AllocationFamily Family) const; - - ///@{ - /// Check if this is one of the functions which can allocate/reallocate memory - /// pointed to by one of its arguments. - bool isMemFunction(const FunctionDecl *FD, ASTContext &C) const; - bool isCMemFunction(const FunctionDecl *FD, - ASTContext &C, - AllocationFamily Family, - MemoryOperationKind MemKind) const; - bool isStandardNewDelete(const FunctionDecl *FD, ASTContext &C) const; - ///@} + // TODO: Remove mutable by moving the initializtaion to the registry function. + mutable Optional KernelZeroFlagVal; /// Process C++ operator new()'s allocation, which is the part of C++ /// new-expression that goes before the constructor. @@ -296,23 +404,64 @@ class MallocChecker : public Checker RetVal = None) const; - + /// + /// \param [in] E The expression that allocates memory. + /// \param [in] IndexOfSizeArg Index of the argument that specifies the size + /// of the memory that needs to be allocated. E.g. for malloc, this would be + /// 0. + /// \param [in] RetVal Specifies the newly allocated pointer value; + /// if unspecified, the value of expression \p E is used. + static ProgramStateRef ProcessZeroAllocCheck(CheckerContext &C, const Expr *E, + const unsigned IndexOfSizeArg, + ProgramStateRef State, + Optional RetVal = None); + + /// Model functions with the ownership_returns attribute. + /// + /// User-defined function may have the ownership_returns attribute, which + /// annotates that the function returns with an object that was allocated on + /// the heap, and passes the ownertship to the callee. + /// + /// void __attribute((ownership_returns(malloc, 1))) *my_malloc(size_t); + /// + /// It has two parameters: + /// - first: name of the resource (e.g. 'malloc') + /// - (OPTIONAL) second: size of the allocated region + /// + /// \param [in] CE The expression that allocates memory. + /// \param [in] Att The ownership_returns attribute. + /// \param [in] State The \c ProgramState right before allocation. + /// \returns The ProgramState right after allocation. ProgramStateRef MallocMemReturnsAttr(CheckerContext &C, const CallExpr *CE, const OwnershipAttr* Att, ProgramStateRef State) const; + + /// Models memory allocation. + /// + /// \param [in] CE The expression that allocates memory. + /// \param [in] SizeEx Size of the memory that needs to be allocated. + /// \param [in] Init The value the allocated memory needs to be initialized. + /// with. For example, \c calloc initializes the allocated memory to 0, + /// malloc leaves it undefined. + /// \param [in] State The \c ProgramState right before allocation. + /// \returns The ProgramState right after allocation. static ProgramStateRef MallocMemAux(CheckerContext &C, const CallExpr *CE, const Expr *SizeEx, SVal Init, ProgramStateRef State, AllocationFamily Family = AF_Malloc); + + /// Models memory allocation. + /// + /// \param [in] CE The expression that allocates memory. + /// \param [in] Size Size of the memory that needs to be allocated. + /// \param [in] Init The value the allocated memory needs to be initialized. + /// with. For example, \c calloc initializes the allocated memory to 0, + /// malloc leaves it undefined. + /// \param [in] State The \c ProgramState right before allocation. + /// \returns The ProgramState right after allocation. static ProgramStateRef MallocMemAux(CheckerContext &C, const CallExpr *CE, - SVal SizeEx, SVal Init, + SVal Size, SVal Init, ProgramStateRef State, AllocationFamily Family = AF_Malloc); @@ -325,54 +474,125 @@ class MallocChecker : public Checker RetVal = None); - + /// Model functions with the ownership_takes and ownership_holds attributes. + /// + /// User-defined function may have the ownership_takes and/or ownership_holds + /// attributes, which annotates that the function frees the memory passed as a + /// parameter. + /// + /// void __attribute((ownership_takes(malloc, 1))) my_free(void *); + /// void __attribute((ownership_holds(malloc, 1))) my_hold(void *); + /// + /// They have two parameters: + /// - first: name of the resource (e.g. 'malloc') + /// - second: index of the parameter the attribute applies to + /// + /// \param [in] CE The expression that frees memory. + /// \param [in] Att The ownership_takes or ownership_holds attribute. + /// \param [in] State The \c ProgramState right before allocation. + /// \returns The ProgramState right after deallocation. ProgramStateRef FreeMemAttr(CheckerContext &C, const CallExpr *CE, const OwnershipAttr* Att, ProgramStateRef State) const; + + /// Models memory deallocation. + /// + /// \param [in] CE The expression that frees memory. + /// \param [in] State The \c ProgramState right before allocation. + /// \param [in] Num Index of the argument that needs to be freed. This is + /// normally 0, but for custom free functions it may be different. + /// \param [in] Hold Whether the parameter at \p Index has the ownership_holds + /// attribute. + /// \param [out] IsKnownToBeAllocated Whether the memory to be freed is known + /// to have been allocated, or in other words, the symbol to be freed was + /// registered as allocated by this checker. In the following case, \c ptr + /// isn't known to be allocated. + /// void Haha(int *ptr) { + /// ptr = realloc(ptr, 67); + /// // ... + /// } + /// \param [in] ReturnsNullOnFailure Whether the memory deallocation function + /// we're modeling returns with Null on failure. + /// \returns The ProgramState right after deallocation. ProgramStateRef FreeMemAux(CheckerContext &C, const CallExpr *CE, - ProgramStateRef state, unsigned Num, - bool Hold, - bool &ReleasedAllocated, + ProgramStateRef State, unsigned Num, bool Hold, + bool &IsKnownToBeAllocated, bool ReturnsNullOnFailure = false) const; - ProgramStateRef FreeMemAux(CheckerContext &C, const Expr *Arg, - const Expr *ParentExpr, - ProgramStateRef State, - bool Hold, - bool &ReleasedAllocated, + + /// Models memory deallocation. + /// + /// \param [in] ArgExpr The variable who's pointee needs to be freed. + /// \param [in] ParentExpr The expression that frees the memory. + /// \param [in] State The \c ProgramState right before allocation. + /// normally 0, but for custom free functions it may be different. + /// \param [in] Hold Whether the parameter at \p Index has the ownership_holds + /// attribute. + /// \param [out] IsKnownToBeAllocated Whether the memory to be freed is known + /// to have been allocated, or in other words, the symbol to be freed was + /// registered as allocated by this checker. In the following case, \c ptr + /// isn't known to be allocated. + /// void Haha(int *ptr) { + /// ptr = realloc(ptr, 67); + /// // ... + /// } + /// \param [in] ReturnsNullOnFailure Whether the memory deallocation function + /// we're modeling returns with Null on failure. + /// \returns The ProgramState right after deallocation. + ProgramStateRef FreeMemAux(CheckerContext &C, const Expr *ArgExpr, + const Expr *ParentExpr, ProgramStateRef State, + bool Hold, bool &IsKnownToBeAllocated, bool ReturnsNullOnFailure = false) const; + // TODO: Needs some refactoring, as all other deallocation modeling + // functions are suffering from out parameters and messy code due to how + // realloc is handled. + // + /// Models memory reallocation. + /// + /// \param [in] CE The expression that reallocated memory + /// \param [in] FreesMemOnFailure Whether if reallocation fails, the supplied + /// memory should be freed. + /// \param [in] State The \c ProgramState right before reallocation. + /// \param [in] SuffixWithN Whether the reallocation function we're modeling + /// has an '_n' suffix, such as g_realloc_n. + /// \returns The ProgramState right after reallocation. ProgramStateRef ReallocMemAux(CheckerContext &C, const CallExpr *CE, - bool FreesMemOnFailure, - ProgramStateRef State, + bool ShouldFreeOnFail, ProgramStateRef State, bool SuffixWithN = false) const; + + /// Evaluates the buffer size that needs to be allocated. + /// + /// \param [in] Blocks The amount of blocks that needs to be allocated. + /// \param [in] BlockBytes The size of a block. + /// \returns The symbolic value of \p Blocks * \p BlockBytes. static SVal evalMulForBufferSize(CheckerContext &C, const Expr *Blocks, const Expr *BlockBytes); + + /// Models zero initialized array allocation. + /// + /// \param [in] CE The expression that reallocated memory + /// \param [in] State The \c ProgramState right before reallocation. + /// \returns The ProgramState right after allocation. static ProgramStateRef CallocMem(CheckerContext &C, const CallExpr *CE, ProgramStateRef State); - /// Check if the memory associated with this symbol was released. - bool isReleased(SymbolRef Sym, CheckerContext &C) const; - /// See if deallocation happens in a suspicious context. If so, escape the /// pointers that otherwise would have been deallocated and return true. bool suppressDeallocationsInSuspiciousContexts(const CallExpr *CE, CheckerContext &C) const; + /// If in \p S \p Sym is used, check whether \p Sym was already freed. bool checkUseAfterFree(SymbolRef Sym, CheckerContext &C, const Stmt *S) const; + /// If in \p S \p Sym is used, check whether \p Sym was allocated as a zero + /// sized memory region. void checkUseZeroAllocated(SymbolRef Sym, CheckerContext &C, const Stmt *S) const; + /// If in \p S \p Sym is being freed, check whether \p Sym was already freed. bool checkDoubleDelete(SymbolRef Sym, CheckerContext &C) const; - /// Check if the function is known free memory, or if it is + /// Check if the function is known to free memory, or if it is /// "interesting" and should be modeled explicitly. /// /// \param [out] EscapingSymbol A function might not free memory in general, @@ -386,12 +606,12 @@ class MallocChecker : public Checker allocated. Other state (released) -> allocated. - return (Stmt && (isa(Stmt) || isa(Stmt)) && - (S && (S->isAllocated() || S->isAllocatedOfSizeZero())) && - (!SPrev || !(SPrev->isAllocated() || - SPrev->isAllocatedOfSizeZero()))); - } + // The allocated region symbol tracked by the main analysis. + SymbolRef Sym; - inline bool isReleased(const RefState *S, const RefState *SPrev, - const Stmt *Stmt) { - // Did not track -> released. Other state (allocated) -> released. - // The statement associated with the release might be missing. - bool IsReleased = (S && S->isReleased()) && - (!SPrev || !SPrev->isReleased()); - assert(!IsReleased || - (Stmt && (isa(Stmt) || isa(Stmt))) || - (!Stmt && S->getAllocationFamily() == AF_InnerBuffer)); - return IsReleased; - } + // The mode we are in, i.e. what kind of diagnostics will be emitted. + NotificationMode Mode; - inline bool isRelinquished(const RefState *S, const RefState *SPrev, - const Stmt *Stmt) { - // Did not track -> relinquished. Other state (allocated) -> relinquished. - return (Stmt && (isa(Stmt) || isa(Stmt) || - isa(Stmt)) && - (S && S->isRelinquished()) && - (!SPrev || !SPrev->isRelinquished())); - } + // A symbol from when the primary region should have been reallocated. + SymbolRef FailedReallocSymbol; - inline bool isReallocFailedCheck(const RefState *S, const RefState *SPrev, - const Stmt *Stmt) { - // If the expression is not a call, and the state change is - // released -> allocated, it must be the realloc return value - // check. If we have to handle more cases here, it might be cleaner just - // to track this extra bit in the state itself. - return ( - (!Stmt || !isa(Stmt)) && - (S && (S->isAllocated() || S->isAllocatedOfSizeZero())) && - (SPrev && !(SPrev->isAllocated() || SPrev->isAllocatedOfSizeZero()))); - } + // A C++ destructor stack frame in which memory was released. Used for + // miscellaneous false positive suppression. + const StackFrameContext *ReleaseDestructorLC; - PathDiagnosticPieceRef VisitNode(const ExplodedNode *N, - BugReporterContext &BRC, - PathSensitiveBugReport &BR) override; + bool IsLeak; - PathDiagnosticPieceRef getEndPath(BugReporterContext &BRC, - const ExplodedNode *EndPathNode, - PathSensitiveBugReport &BR) override { - if (!IsLeak) - return nullptr; +public: + MallocBugVisitor(SymbolRef S, bool isLeak = false) + : Sym(S), Mode(Normal), FailedReallocSymbol(nullptr), + ReleaseDestructorLC(nullptr), IsLeak(isLeak) {} + + static void *getTag() { + static int Tag = 0; + return &Tag; + } + + void Profile(llvm::FoldingSetNodeID &ID) const override { + ID.AddPointer(getTag()); + ID.AddPointer(Sym); + } + + /// Did not track -> allocated. Other state (released) -> allocated. + static inline bool isAllocated(const RefState *RSCurr, const RefState *RSPrev, + const Stmt *Stmt) { + return (Stmt && (isa(Stmt) || isa(Stmt)) && + (RSCurr && + (RSCurr->isAllocated() || RSCurr->isAllocatedOfSizeZero())) && + (!RSPrev || + !(RSPrev->isAllocated() || RSPrev->isAllocatedOfSizeZero()))); + } + + /// Did not track -> released. Other state (allocated) -> released. + /// The statement associated with the release might be missing. + static inline bool isReleased(const RefState *RSCurr, const RefState *RSPrev, + const Stmt *Stmt) { + bool IsReleased = + (RSCurr && RSCurr->isReleased()) && (!RSPrev || !RSPrev->isReleased()); + assert(!IsReleased || + (Stmt && (isa(Stmt) || isa(Stmt))) || + (!Stmt && RSCurr->getAllocationFamily() == AF_InnerBuffer)); + return IsReleased; + } + + /// Did not track -> relinquished. Other state (allocated) -> relinquished. + static inline bool isRelinquished(const RefState *RSCurr, + const RefState *RSPrev, const Stmt *Stmt) { + return (Stmt && + (isa(Stmt) || isa(Stmt) || + isa(Stmt)) && + (RSCurr && RSCurr->isRelinquished()) && + (!RSPrev || !RSPrev->isRelinquished())); + } + + /// If the expression is not a call, and the state change is + /// released -> allocated, it must be the realloc return value + /// check. If we have to handle more cases here, it might be cleaner just + /// to track this extra bit in the state itself. + static inline bool hasReallocFailed(const RefState *RSCurr, + const RefState *RSPrev, + const Stmt *Stmt) { + return ((!Stmt || !isa(Stmt)) && + (RSCurr && + (RSCurr->isAllocated() || RSCurr->isAllocatedOfSizeZero())) && + (RSPrev && + !(RSPrev->isAllocated() || RSPrev->isAllocatedOfSizeZero()))); + } + + PathDiagnosticPieceRef VisitNode(const ExplodedNode *N, + BugReporterContext &BRC, + PathSensitiveBugReport &BR) override; + + PathDiagnosticPieceRef getEndPath(BugReporterContext &BRC, + const ExplodedNode *EndPathNode, + PathSensitiveBugReport &BR) override { + if (!IsLeak) + return nullptr; - PathDiagnosticLocation L = BR.getLocation(); - // Do not add the statement itself as a range in case of leak. - return std::make_shared(L, BR.getDescription(), - false); - } + PathDiagnosticLocation L = BR.getLocation(); + // Do not add the statement itself as a range in case of leak. + return std::make_shared(L, BR.getDescription(), + false); + } - private: - class StackHintGeneratorForReallocationFailed - : public StackHintGeneratorForSymbol { - public: - StackHintGeneratorForReallocationFailed(SymbolRef S, StringRef M) +private: + class StackHintGeneratorForReallocationFailed + : public StackHintGeneratorForSymbol { + public: + StackHintGeneratorForReallocationFailed(SymbolRef S, StringRef M) : StackHintGeneratorForSymbol(S, M) {} - std::string getMessageForArg(const Expr *ArgE, - unsigned ArgIndex) override { - // Printed parameters start at 1, not 0. - ++ArgIndex; + std::string getMessageForArg(const Expr *ArgE, unsigned ArgIndex) override { + // Printed parameters start at 1, not 0. + ++ArgIndex; - SmallString<200> buf; - llvm::raw_svector_ostream os(buf); + SmallString<200> buf; + llvm::raw_svector_ostream os(buf); - os << "Reallocation of " << ArgIndex << llvm::getOrdinalSuffix(ArgIndex) - << " parameter failed"; + os << "Reallocation of " << ArgIndex << llvm::getOrdinalSuffix(ArgIndex) + << " parameter failed"; - return os.str(); - } + return os.str(); + } - std::string getMessageForReturn(const CallExpr *CallExpr) override { - return "Reallocation of returned value failed"; - } - }; + std::string getMessageForReturn(const CallExpr *CallExpr) override { + return "Reallocation of returned value failed"; + } }; }; -} // end anonymous namespace - -REGISTER_MAP_WITH_PROGRAMSTATE(RegionState, SymbolRef, RefState) -REGISTER_MAP_WITH_PROGRAMSTATE(ReallocPairs, SymbolRef, ReallocPair) -REGISTER_SET_WITH_PROGRAMSTATE(ReallocSizeZeroSymbols, SymbolRef) // A map from the freed symbol to the symbol representing the return value of // the free function. @@ -589,7 +811,11 @@ class StopTrackingCallback final : public SymbolVisitor { }; } // end anonymous namespace -void MallocChecker::initIdentifierInfo(ASTContext &Ctx) const { +//===----------------------------------------------------------------------===// +// Methods of MemFunctionInfoTy. +//===----------------------------------------------------------------------===// + +void MemFunctionInfoTy::initIdentifierInfo(ASTContext &Ctx) const { if (II_malloc) return; II_alloca = &Ctx.Idents.get("alloca"); @@ -629,7 +855,8 @@ void MallocChecker::initIdentifierInfo(ASTContext &Ctx) const { II_g_try_realloc_n = &Ctx.Idents.get("g_try_realloc_n"); } -bool MallocChecker::isMemFunction(const FunctionDecl *FD, ASTContext &C) const { +bool MemFunctionInfoTy::isMemFunction(const FunctionDecl *FD, + ASTContext &C) const { if (isCMemFunction(FD, C, AF_Malloc, MemoryOperationKind::MOK_Any)) return true; @@ -645,10 +872,9 @@ bool MallocChecker::isMemFunction(const FunctionDecl *FD, ASTContext &C) const { return false; } -bool MallocChecker::isCMemFunction(const FunctionDecl *FD, - ASTContext &C, - AllocationFamily Family, - MemoryOperationKind MemKind) const { +bool MemFunctionInfoTy::isCMemFunction(const FunctionDecl *FD, ASTContext &C, + AllocationFamily Family, + MemoryOperationKind MemKind) const { if (!FD) return false; @@ -701,7 +927,7 @@ bool MallocChecker::isCMemFunction(const FunctionDecl *FD, if (Family != AF_Malloc) return false; - if (IsOptimistic && FD->hasAttrs()) { + if (ShouldIncludeOwnershipAnnotatedFunctions && FD->hasAttrs()) { for (const auto *I : FD->specific_attrs()) { OwnershipAttr::OwnershipKind OwnKind = I->getOwnKind(); if(OwnKind == OwnershipAttr::Takes || OwnKind == OwnershipAttr::Holds) { @@ -716,11 +942,8 @@ bool MallocChecker::isCMemFunction(const FunctionDecl *FD, return false; } - -// Tells if the callee is one of the builtin new/delete operators, including -// placement operators and other standard overloads. -bool MallocChecker::isStandardNewDelete(const FunctionDecl *FD, - ASTContext &C) const { +bool MemFunctionInfoTy::isStandardNewDelete(const FunctionDecl *FD, + ASTContext &C) const { if (!FD) return false; @@ -736,6 +959,10 @@ bool MallocChecker::isStandardNewDelete(const FunctionDecl *FD, return !L.isValid() || C.getSourceManager().isInSystemHeader(L); } +//===----------------------------------------------------------------------===// +// Methods of MallocChecker and MallocBugVisitor. +//===----------------------------------------------------------------------===// + llvm::Optional MallocChecker::performKernelMalloc( const CallExpr *CE, CheckerContext &C, const ProgramStateRef &State) const { // 3-argument malloc(), as commonly used in {Free,Net,Open}BSD Kernels: @@ -834,28 +1061,35 @@ void MallocChecker::checkPostStmt(const CallExpr *CE, CheckerContext &C) const { return; ProgramStateRef State = C.getState(); - bool ReleasedAllocatedMemory = false; + bool IsKnownToBeAllocatedMemory = false; if (FD->getKind() == Decl::Function) { - initIdentifierInfo(C.getASTContext()); + MemFunctionInfo.initIdentifierInfo(C.getASTContext()); IdentifierInfo *FunI = FD->getIdentifier(); - if (FunI == II_malloc || FunI == II_g_malloc || FunI == II_g_try_malloc) { - if (CE->getNumArgs() < 1) + if (FunI == MemFunctionInfo.II_malloc || + FunI == MemFunctionInfo.II_g_malloc || + FunI == MemFunctionInfo.II_g_try_malloc) { + switch (CE->getNumArgs()) { + default: return; - if (CE->getNumArgs() < 3) { + case 1: + State = MallocMemAux(C, CE, CE->getArg(0), UndefinedVal(), State); + State = ProcessZeroAllocCheck(C, CE, 0, State); + break; + case 2: State = MallocMemAux(C, CE, CE->getArg(0), UndefinedVal(), State); - if (CE->getNumArgs() == 1) - State = ProcessZeroAllocation(C, CE, 0, State); - } else if (CE->getNumArgs() == 3) { + break; + case 3: llvm::Optional MaybeState = performKernelMalloc(CE, C, State); if (MaybeState.hasValue()) State = MaybeState.getValue(); else State = MallocMemAux(C, CE, CE->getArg(0), UndefinedVal(), State); + break; } - } else if (FunI == II_kmalloc) { + } else if (FunI == MemFunctionInfo.II_kmalloc) { if (CE->getNumArgs() < 1) return; llvm::Optional MaybeState = @@ -864,100 +1098,116 @@ void MallocChecker::checkPostStmt(const CallExpr *CE, CheckerContext &C) const { State = MaybeState.getValue(); else State = MallocMemAux(C, CE, CE->getArg(0), UndefinedVal(), State); - } else if (FunI == II_valloc) { + } else if (FunI == MemFunctionInfo.II_valloc) { if (CE->getNumArgs() < 1) return; State = MallocMemAux(C, CE, CE->getArg(0), UndefinedVal(), State); - State = ProcessZeroAllocation(C, CE, 0, State); - } else if (FunI == II_realloc || FunI == II_g_realloc || - FunI == II_g_try_realloc) { - State = ReallocMemAux(C, CE, false, State); - State = ProcessZeroAllocation(C, CE, 1, State); - } else if (FunI == II_reallocf) { - State = ReallocMemAux(C, CE, true, State); - State = ProcessZeroAllocation(C, CE, 1, State); - } else if (FunI == II_calloc) { + State = ProcessZeroAllocCheck(C, CE, 0, State); + } else if (FunI == MemFunctionInfo.II_realloc || + FunI == MemFunctionInfo.II_g_realloc || + FunI == MemFunctionInfo.II_g_try_realloc) { + State = ReallocMemAux(C, CE, /*ShouldFreeOnFail*/ false, State); + State = ProcessZeroAllocCheck(C, CE, 1, State); + } else if (FunI == MemFunctionInfo.II_reallocf) { + State = ReallocMemAux(C, CE, /*ShouldFreeOnFail*/ true, State); + State = ProcessZeroAllocCheck(C, CE, 1, State); + } else if (FunI == MemFunctionInfo.II_calloc) { State = CallocMem(C, CE, State); - State = ProcessZeroAllocation(C, CE, 0, State); - State = ProcessZeroAllocation(C, CE, 1, State); - } else if (FunI == II_free || FunI == II_g_free || FunI == II_kfree) { + State = ProcessZeroAllocCheck(C, CE, 0, State); + State = ProcessZeroAllocCheck(C, CE, 1, State); + } else if (FunI == MemFunctionInfo.II_free || + FunI == MemFunctionInfo.II_g_free || + FunI == MemFunctionInfo.II_kfree) { if (suppressDeallocationsInSuspiciousContexts(CE, C)) return; - State = FreeMemAux(C, CE, State, 0, false, ReleasedAllocatedMemory); - } else if (FunI == II_strdup || FunI == II_win_strdup || - FunI == II_wcsdup || FunI == II_win_wcsdup) { + State = FreeMemAux(C, CE, State, 0, false, IsKnownToBeAllocatedMemory); + } else if (FunI == MemFunctionInfo.II_strdup || + FunI == MemFunctionInfo.II_win_strdup || + FunI == MemFunctionInfo.II_wcsdup || + FunI == MemFunctionInfo.II_win_wcsdup) { State = MallocUpdateRefState(C, CE, State); - } else if (FunI == II_strndup) { + } else if (FunI == MemFunctionInfo.II_strndup) { State = MallocUpdateRefState(C, CE, State); - } else if (FunI == II_alloca || FunI == II_win_alloca) { + } else if (FunI == MemFunctionInfo.II_alloca || + FunI == MemFunctionInfo.II_win_alloca) { if (CE->getNumArgs() < 1) return; State = MallocMemAux(C, CE, CE->getArg(0), UndefinedVal(), State, AF_Alloca); - State = ProcessZeroAllocation(C, CE, 0, State); - } else if (isStandardNewDelete(FD, C.getASTContext())) { + State = ProcessZeroAllocCheck(C, CE, 0, State); + } else if (MemFunctionInfo.isStandardNewDelete(FD, C.getASTContext())) { // Process direct calls to operator new/new[]/delete/delete[] functions // as distinct from new/new[]/delete/delete[] expressions that are // processed by the checkPostStmt callbacks for CXXNewExpr and // CXXDeleteExpr. - OverloadedOperatorKind K = FD->getOverloadedOperator(); - if (K == OO_New) { + switch (FD->getOverloadedOperator()) { + case OO_New: State = MallocMemAux(C, CE, CE->getArg(0), UndefinedVal(), State, AF_CXXNew); - State = ProcessZeroAllocation(C, CE, 0, State); - } - else if (K == OO_Array_New) { + State = ProcessZeroAllocCheck(C, CE, 0, State); + break; + case OO_Array_New: State = MallocMemAux(C, CE, CE->getArg(0), UndefinedVal(), State, AF_CXXNewArray); - State = ProcessZeroAllocation(C, CE, 0, State); - } - else if (K == OO_Delete || K == OO_Array_Delete) - State = FreeMemAux(C, CE, State, 0, false, ReleasedAllocatedMemory); - else + State = ProcessZeroAllocCheck(C, CE, 0, State); + break; + case OO_Delete: + case OO_Array_Delete: + State = FreeMemAux(C, CE, State, 0, false, IsKnownToBeAllocatedMemory); + break; + default: llvm_unreachable("not a new/delete operator"); - } else if (FunI == II_if_nameindex) { + } + } else if (FunI == MemFunctionInfo.II_if_nameindex) { // Should we model this differently? We can allocate a fixed number of // elements with zeros in the last one. State = MallocMemAux(C, CE, UnknownVal(), UnknownVal(), State, AF_IfNameIndex); - } else if (FunI == II_if_freenameindex) { - State = FreeMemAux(C, CE, State, 0, false, ReleasedAllocatedMemory); - } else if (FunI == II_g_malloc0 || FunI == II_g_try_malloc0) { + } else if (FunI == MemFunctionInfo.II_if_freenameindex) { + State = FreeMemAux(C, CE, State, 0, false, IsKnownToBeAllocatedMemory); + } else if (FunI == MemFunctionInfo.II_g_malloc0 || + FunI == MemFunctionInfo.II_g_try_malloc0) { if (CE->getNumArgs() < 1) return; SValBuilder &svalBuilder = C.getSValBuilder(); SVal zeroVal = svalBuilder.makeZeroVal(svalBuilder.getContext().CharTy); State = MallocMemAux(C, CE, CE->getArg(0), zeroVal, State); - State = ProcessZeroAllocation(C, CE, 0, State); - } else if (FunI == II_g_memdup) { + State = ProcessZeroAllocCheck(C, CE, 0, State); + } else if (FunI == MemFunctionInfo.II_g_memdup) { if (CE->getNumArgs() < 2) return; State = MallocMemAux(C, CE, CE->getArg(1), UndefinedVal(), State); - State = ProcessZeroAllocation(C, CE, 1, State); - } else if (FunI == II_g_malloc_n || FunI == II_g_try_malloc_n || - FunI == II_g_malloc0_n || FunI == II_g_try_malloc0_n) { + State = ProcessZeroAllocCheck(C, CE, 1, State); + } else if (FunI == MemFunctionInfo.II_g_malloc_n || + FunI == MemFunctionInfo.II_g_try_malloc_n || + FunI == MemFunctionInfo.II_g_malloc0_n || + FunI == MemFunctionInfo.II_g_try_malloc0_n) { if (CE->getNumArgs() < 2) return; SVal Init = UndefinedVal(); - if (FunI == II_g_malloc0_n || FunI == II_g_try_malloc0_n) { + if (FunI == MemFunctionInfo.II_g_malloc0_n || + FunI == MemFunctionInfo.II_g_try_malloc0_n) { SValBuilder &SB = C.getSValBuilder(); Init = SB.makeZeroVal(SB.getContext().CharTy); } SVal TotalSize = evalMulForBufferSize(C, CE->getArg(0), CE->getArg(1)); State = MallocMemAux(C, CE, TotalSize, Init, State); - State = ProcessZeroAllocation(C, CE, 0, State); - State = ProcessZeroAllocation(C, CE, 1, State); - } else if (FunI == II_g_realloc_n || FunI == II_g_try_realloc_n) { + State = ProcessZeroAllocCheck(C, CE, 0, State); + State = ProcessZeroAllocCheck(C, CE, 1, State); + } else if (FunI == MemFunctionInfo.II_g_realloc_n || + FunI == MemFunctionInfo.II_g_try_realloc_n) { if (CE->getNumArgs() < 3) return; - State = ReallocMemAux(C, CE, false, State, true); - State = ProcessZeroAllocation(C, CE, 1, State); - State = ProcessZeroAllocation(C, CE, 2, State); + State = ReallocMemAux(C, CE, /*ShouldFreeOnFail*/ false, State, + /*SuffixWithN*/ true); + State = ProcessZeroAllocCheck(C, CE, 1, State); + State = ProcessZeroAllocCheck(C, CE, 2, State); } } - if (IsOptimistic || ChecksEnabled[CK_MismatchedDeallocatorChecker]) { + if (MemFunctionInfo.ShouldIncludeOwnershipAnnotatedFunctions || + ChecksEnabled[CK_MismatchedDeallocatorChecker]) { // Check all the attributes, if there are any. // There can be multiple of these attributes. if (FD->hasAttrs()) @@ -977,9 +1227,9 @@ void MallocChecker::checkPostStmt(const CallExpr *CE, CheckerContext &C) const { } // Performs a 0-sized allocations check. -ProgramStateRef MallocChecker::ProcessZeroAllocation( - CheckerContext &C, const Expr *E, const unsigned AllocationSizeArg, - ProgramStateRef State, Optional RetVal) const { +ProgramStateRef MallocChecker::ProcessZeroAllocCheck( + CheckerContext &C, const Expr *E, const unsigned IndexOfSizeArg, + ProgramStateRef State, Optional RetVal) { if (!State) return nullptr; @@ -989,7 +1239,7 @@ ProgramStateRef MallocChecker::ProcessZeroAllocation( const Expr *Arg = nullptr; if (const CallExpr *CE = dyn_cast(E)) { - Arg = CE->getArg(AllocationSizeArg); + Arg = CE->getArg(IndexOfSizeArg); } else if (const CXXNewExpr *NE = dyn_cast(E)) { if (NE->isArray()) @@ -1051,7 +1301,9 @@ static QualType getDeepPointeeType(QualType T) { return Result; } -static bool treatUnusedNewEscaped(const CXXNewExpr *NE) { +/// \returns true if the constructor invoked by \p NE has an argument of a +/// pointer/reference to a record type. +static bool hasNonTrivialConstructorCall(const CXXNewExpr *NE) { const CXXConstructExpr *ConstructE = NE->getConstructExpr(); if (!ConstructE) @@ -1081,11 +1333,17 @@ static bool treatUnusedNewEscaped(const CXXNewExpr *NE) { void MallocChecker::processNewAllocation(const CXXNewExpr *NE, CheckerContext &C, SVal Target) const { - if (!isStandardNewDelete(NE->getOperatorNew(), C.getASTContext())) + if (!MemFunctionInfo.isStandardNewDelete(NE->getOperatorNew(), + C.getASTContext())) return; const ParentMap &PM = C.getLocationContext()->getParentMap(); - if (!PM.isConsumedExpr(NE) && treatUnusedNewEscaped(NE)) + + // Non-trivial constructors have a chance to escape 'this', but marking all + // invocations of trivial constructors as escaped would cause too great of + // reduction of true positives, so let's just do that for constructors that + // have an argument of a pointer-to-record type. + if (!PM.isConsumedExpr(NE) && hasNonTrivialConstructorCall(NE)) return; ProgramStateRef State = C.getState(); @@ -1096,7 +1354,7 @@ void MallocChecker::processNewAllocation(const CXXNewExpr *NE, State = MallocUpdateRefState(C, NE, State, NE->isArray() ? AF_CXXNewArray : AF_CXXNew, Target); State = addExtentSize(C, NE, State, Target); - State = ProcessZeroAllocation(C, NE, 0, State, Target); + State = ProcessZeroAllocCheck(C, NE, 0, State, Target); C.addTransition(State); } @@ -1164,13 +1422,14 @@ void MallocChecker::checkPreStmt(const CXXDeleteExpr *DE, if (SymbolRef Sym = C.getSVal(DE->getArgument()).getAsSymbol()) checkUseAfterFree(Sym, C, DE->getArgument()); - if (!isStandardNewDelete(DE->getOperatorDelete(), C.getASTContext())) + if (!MemFunctionInfo.isStandardNewDelete(DE->getOperatorDelete(), + C.getASTContext())) return; ProgramStateRef State = C.getState(); - bool ReleasedAllocated; + bool IsKnownToBeAllocated; State = FreeMemAux(C, DE->getArgument(), DE, State, - /*Hold*/false, ReleasedAllocated); + /*Hold*/ false, IsKnownToBeAllocated); C.addTransition(State); } @@ -1210,11 +1469,11 @@ void MallocChecker::checkPostObjCMessage(const ObjCMethodCall &Call, if (!*FreeWhenDone) return; - bool ReleasedAllocatedMemory; - ProgramStateRef State = FreeMemAux(C, Call.getArgExpr(0), - Call.getOriginExpr(), C.getState(), - /*Hold=*/true, ReleasedAllocatedMemory, - /*ReturnsNullOnFailure=*/true); + bool IsKnownToBeAllocatedMemory; + ProgramStateRef State = + FreeMemAux(C, Call.getArgExpr(0), Call.getOriginExpr(), C.getState(), + /*Hold=*/true, IsKnownToBeAllocatedMemory, + /*RetNullOnFailure=*/true); C.addTransition(State); } @@ -1226,7 +1485,7 @@ MallocChecker::MallocMemReturnsAttr(CheckerContext &C, const CallExpr *CE, if (!State) return nullptr; - if (Att->getModule() != II_malloc) + if (Att->getModule() != MemFunctionInfo.II_malloc) return nullptr; OwnershipAttr::args_iterator I = Att->args_begin(), E = Att->args_end(); @@ -1292,11 +1551,10 @@ ProgramStateRef MallocChecker::MallocMemAux(CheckerContext &C, return MallocUpdateRefState(C, CE, State, Family); } -ProgramStateRef MallocChecker::MallocUpdateRefState(CheckerContext &C, - const Expr *E, - ProgramStateRef State, - AllocationFamily Family, - Optional RetVal) { +static ProgramStateRef MallocUpdateRefState(CheckerContext &C, const Expr *E, + ProgramStateRef State, + AllocationFamily Family, + Optional RetVal) { if (!State) return nullptr; @@ -1324,27 +1582,24 @@ ProgramStateRef MallocChecker::FreeMemAttr(CheckerContext &C, if (!State) return nullptr; - if (Att->getModule() != II_malloc) + if (Att->getModule() != MemFunctionInfo.II_malloc) return nullptr; - bool ReleasedAllocated = false; + bool IsKnownToBeAllocated = false; for (const auto &Arg : Att->args()) { ProgramStateRef StateI = FreeMemAux( C, CE, State, Arg.getASTIndex(), - Att->getOwnKind() == OwnershipAttr::Holds, ReleasedAllocated); + Att->getOwnKind() == OwnershipAttr::Holds, IsKnownToBeAllocated); if (StateI) State = StateI; } return State; } -ProgramStateRef MallocChecker::FreeMemAux(CheckerContext &C, - const CallExpr *CE, - ProgramStateRef State, - unsigned Num, - bool Hold, - bool &ReleasedAllocated, +ProgramStateRef MallocChecker::FreeMemAux(CheckerContext &C, const CallExpr *CE, + ProgramStateRef State, unsigned Num, + bool Hold, bool &IsKnownToBeAllocated, bool ReturnsNullOnFailure) const { if (!State) return nullptr; @@ -1352,8 +1607,8 @@ ProgramStateRef MallocChecker::FreeMemAux(CheckerContext &C, if (CE->getNumArgs() < (Num + 1)) return nullptr; - return FreeMemAux(C, CE->getArg(Num), CE, State, Hold, - ReleasedAllocated, ReturnsNullOnFailure); + return FreeMemAux(C, CE->getArg(Num), CE, State, Hold, IsKnownToBeAllocated, + ReturnsNullOnFailure); } /// Checks if the previous call to free on the given symbol failed - if free @@ -1371,8 +1626,10 @@ static bool didPreviousFreeFail(ProgramStateRef State, return false; } -AllocationFamily MallocChecker::getAllocationFamily(CheckerContext &C, - const Stmt *S) const { +static AllocationFamily +getAllocationFamily(const MemFunctionInfoTy &MemFunctionInfo, CheckerContext &C, + const Stmt *S) { + if (!S) return AF_None; @@ -1384,10 +1641,11 @@ AllocationFamily MallocChecker::getAllocationFamily(CheckerContext &C, ASTContext &Ctx = C.getASTContext(); - if (isCMemFunction(FD, Ctx, AF_Malloc, MemoryOperationKind::MOK_Any)) + if (MemFunctionInfo.isCMemFunction(FD, Ctx, AF_Malloc, + MemoryOperationKind::MOK_Any)) return AF_Malloc; - if (isStandardNewDelete(FD, Ctx)) { + if (MemFunctionInfo.isStandardNewDelete(FD, Ctx)) { OverloadedOperatorKind Kind = FD->getOverloadedOperator(); if (Kind == OO_New || Kind == OO_Delete) return AF_CXXNew; @@ -1395,10 +1653,12 @@ AllocationFamily MallocChecker::getAllocationFamily(CheckerContext &C, return AF_CXXNewArray; } - if (isCMemFunction(FD, Ctx, AF_IfNameIndex, MemoryOperationKind::MOK_Any)) + if (MemFunctionInfo.isCMemFunction(FD, Ctx, AF_IfNameIndex, + MemoryOperationKind::MOK_Any)) return AF_IfNameIndex; - if (isCMemFunction(FD, Ctx, AF_Alloca, MemoryOperationKind::MOK_Any)) + if (MemFunctionInfo.isCMemFunction(FD, Ctx, AF_Alloca, + MemoryOperationKind::MOK_Any)) return AF_Alloca; return AF_None; @@ -1416,8 +1676,8 @@ AllocationFamily MallocChecker::getAllocationFamily(CheckerContext &C, return AF_None; } -bool MallocChecker::printAllocDeallocName(raw_ostream &os, CheckerContext &C, - const Expr *E) const { +static bool printAllocDeallocName(raw_ostream &os, CheckerContext &C, + const Expr *E) { if (const CallExpr *CE = dyn_cast(E)) { // FIXME: This doesn't handle indirect calls. const FunctionDecl *FD = CE->getDirectCallee(); @@ -1456,9 +1716,10 @@ bool MallocChecker::printAllocDeallocName(raw_ostream &os, CheckerContext &C, return false; } -void MallocChecker::printExpectedAllocName(raw_ostream &os, CheckerContext &C, - const Expr *E) const { - AllocationFamily Family = getAllocationFamily(C, E); +static void printExpectedAllocName(raw_ostream &os, + const MemFunctionInfoTy &MemFunctionInfo, + CheckerContext &C, const Expr *E) { + AllocationFamily Family = getAllocationFamily(MemFunctionInfo, C, E); switch(Family) { case AF_Malloc: os << "malloc()"; return; @@ -1471,8 +1732,7 @@ void MallocChecker::printExpectedAllocName(raw_ostream &os, CheckerContext &C, } } -void MallocChecker::printExpectedDeallocName(raw_ostream &os, - AllocationFamily Family) const { +static void printExpectedDeallocName(raw_ostream &os, AllocationFamily Family) { switch(Family) { case AF_Malloc: os << "free()"; return; case AF_CXXNew: os << "'delete'"; return; @@ -1487,9 +1747,8 @@ void MallocChecker::printExpectedDeallocName(raw_ostream &os, ProgramStateRef MallocChecker::FreeMemAux(CheckerContext &C, const Expr *ArgExpr, const Expr *ParentExpr, - ProgramStateRef State, - bool Hold, - bool &ReleasedAllocated, + ProgramStateRef State, bool Hold, + bool &IsKnownToBeAllocated, bool ReturnsNullOnFailure) const { if (!State) @@ -1563,6 +1822,9 @@ ProgramStateRef MallocChecker::FreeMemAux(CheckerContext &C, const RefState *RsBase = State->get(SymBase); SymbolRef PreviousRetStatusSymbol = nullptr; + IsKnownToBeAllocated = + RsBase && (RsBase->isAllocated() || RsBase->isAllocatedOfSizeZero()); + if (RsBase) { // Memory returned by alloca() shouldn't be freed. @@ -1585,7 +1847,8 @@ ProgramStateRef MallocChecker::FreeMemAux(CheckerContext &C, // Check if an expected deallocation function matches the real one. bool DeallocMatchesAlloc = - RsBase->getAllocationFamily() == getAllocationFamily(C, ParentExpr); + RsBase->getAllocationFamily() == + getAllocationFamily(MemFunctionInfo, C, ParentExpr); if (!DeallocMatchesAlloc) { ReportMismatchedDealloc(C, ArgExpr->getSourceRange(), ParentExpr, RsBase, SymBase, Hold); @@ -1611,9 +1874,6 @@ ProgramStateRef MallocChecker::FreeMemAux(CheckerContext &C, return nullptr; } - ReleasedAllocated = (RsBase != nullptr) && (RsBase->isAllocated() || - RsBase->isAllocatedOfSizeZero()); - // Clean out the info on previous call to free return info. State = State->remove(SymBase); @@ -1628,8 +1888,9 @@ ProgramStateRef MallocChecker::FreeMemAux(CheckerContext &C, } } - AllocationFamily Family = RsBase ? RsBase->getAllocationFamily() - : getAllocationFamily(C, ParentExpr); + AllocationFamily Family = + RsBase ? RsBase->getAllocationFamily() + : getAllocationFamily(MemFunctionInfo, C, ParentExpr); // Normal free. if (Hold) return State->set(SymBase, @@ -1679,8 +1940,8 @@ Optional MallocChecker::getCheckIfTracked(CheckerContext &C, const Stmt *AllocDeallocStmt, bool IsALeakCheck) const { - return getCheckIfTracked(getAllocationFamily(C, AllocDeallocStmt), - IsALeakCheck); + return getCheckIfTracked( + getAllocationFamily(MemFunctionInfo, C, AllocDeallocStmt), IsALeakCheck); } Optional @@ -1818,7 +2079,7 @@ void MallocChecker::ReportBadFree(CheckerContext &C, SVal ArgVal, else os << "not memory allocated by "; - printExpectedAllocName(os, C, DeallocExpr); + printExpectedAllocName(os, MemFunctionInfo, C, DeallocExpr); auto R = std::make_unique(*BT_BadFree[*CheckKind], os.str(), N); @@ -2130,7 +2391,7 @@ void MallocChecker::ReportFunctionPointerFree(CheckerContext &C, SVal ArgVal, ProgramStateRef MallocChecker::ReallocMemAux(CheckerContext &C, const CallExpr *CE, - bool FreesOnFail, + bool ShouldFreeOnFail, ProgramStateRef State, bool SuffixWithN) const { if (!State) @@ -2195,33 +2456,32 @@ ProgramStateRef MallocChecker::ReallocMemAux(CheckerContext &C, if (!FromPtr || !ToPtr) return nullptr; - bool ReleasedAllocated = false; + bool IsKnownToBeAllocated = false; // If the size is 0, free the memory. if (SizeIsZero) - if (ProgramStateRef stateFree = FreeMemAux(C, CE, StateSizeIsZero, 0, - false, ReleasedAllocated)){ - // The semantics of the return value are: - // If size was equal to 0, either NULL or a pointer suitable to be passed - // to free() is returned. We just free the input pointer and do not add - // any constrains on the output pointer. + // The semantics of the return value are: + // If size was equal to 0, either NULL or a pointer suitable to be passed + // to free() is returned. We just free the input pointer and do not add + // any constrains on the output pointer. + if (ProgramStateRef stateFree = + FreeMemAux(C, CE, StateSizeIsZero, 0, false, IsKnownToBeAllocated)) return stateFree; - } // Default behavior. if (ProgramStateRef stateFree = - FreeMemAux(C, CE, State, 0, false, ReleasedAllocated)) { + FreeMemAux(C, CE, State, 0, false, IsKnownToBeAllocated)) { ProgramStateRef stateRealloc = MallocMemAux(C, CE, TotalSize, UnknownVal(), stateFree); if (!stateRealloc) return nullptr; - ReallocPairKind Kind = RPToBeFreedAfterFailure; - if (FreesOnFail) - Kind = RPIsFreeOnFailure; - else if (!ReleasedAllocated) - Kind = RPDoNotTrackAfterFailure; + OwnershipAfterReallocKind Kind = OAR_ToBeFreedAfterFailure; + if (ShouldFreeOnFail) + Kind = OAR_FreeOnFailure; + else if (!IsKnownToBeAllocated) + Kind = OAR_DoNotTrackAfterFailure; // Record the info about the reallocated symbol so that we could properly // process failed reallocation. @@ -2249,9 +2509,9 @@ ProgramStateRef MallocChecker::CallocMem(CheckerContext &C, const CallExpr *CE, return MallocMemAux(C, CE, TotalSize, zeroVal, State); } -LeakInfo -MallocChecker::getAllocationSite(const ExplodedNode *N, SymbolRef Sym, - CheckerContext &C) const { +MallocChecker::LeakInfo MallocChecker::getAllocationSite(const ExplodedNode *N, + SymbolRef Sym, + CheckerContext &C) { const LocationContext *LeakContext = N->getLocationContext(); // Walk the ExplodedGraph backwards and find the first node that referred to // the tracked symbol. @@ -2432,9 +2692,10 @@ void MallocChecker::checkPreCall(const CallEvent &Call, ASTContext &Ctx = C.getASTContext(); if (ChecksEnabled[CK_MallocChecker] && - (isCMemFunction(FD, Ctx, AF_Malloc, MemoryOperationKind::MOK_Free) || - isCMemFunction(FD, Ctx, AF_IfNameIndex, - MemoryOperationKind::MOK_Free))) + (MemFunctionInfo.isCMemFunction(FD, Ctx, AF_Malloc, + MemoryOperationKind::MOK_Free) || + MemFunctionInfo.isCMemFunction(FD, Ctx, AF_IfNameIndex, + MemoryOperationKind::MOK_Free))) return; } @@ -2537,7 +2798,7 @@ void MallocChecker::checkPostStmt(const BlockExpr *BE, C.addTransition(state); } -bool MallocChecker::isReleased(SymbolRef Sym, CheckerContext &C) const { +static bool isReleased(SymbolRef Sym, CheckerContext &C) { assert(Sym); const RefState *RS = C.getState()->get(Sym); return (RS && RS->isReleased()); @@ -2642,13 +2903,17 @@ ProgramStateRef MallocChecker::evalAssume(ProgramStateRef state, SymbolRef ReallocSym = I.getData().ReallocatedSym; if (const RefState *RS = state->get(ReallocSym)) { if (RS->isReleased()) { - if (I.getData().Kind == RPToBeFreedAfterFailure) + switch (I.getData().Kind) { + case OAR_ToBeFreedAfterFailure: state = state->set(ReallocSym, RefState::getAllocated(RS->getAllocationFamily(), RS->getStmt())); - else if (I.getData().Kind == RPDoNotTrackAfterFailure) + break; + case OAR_DoNotTrackAfterFailure: state = state->remove(ReallocSym); - else - assert(I.getData().Kind == RPIsFreeOnFailure); + break; + default: + assert(I.getData().Kind == OAR_FreeOnFailure); + } } } state = state->remove(I.getKey()); @@ -2731,7 +2996,7 @@ bool MallocChecker::mayFreeAnyEscapedMemoryOrIsModeledExplicitly( // If it's one of the allocation functions we can reason about, we model // its behavior explicitly. - if (isMemFunction(FD, ASTC)) + if (MemFunctionInfo.isMemFunction(FD, ASTC)) return false; // If it's not a system call, assume it frees memory. @@ -2823,35 +3088,32 @@ bool MallocChecker::mayFreeAnyEscapedMemoryOrIsModeledExplicitly( return false; } -static bool retTrue(const RefState *RS) { - return true; -} - -static bool checkIfNewOrNewArrayFamily(const RefState *RS) { - return (RS->getAllocationFamily() == AF_CXXNewArray || - RS->getAllocationFamily() == AF_CXXNew); -} - ProgramStateRef MallocChecker::checkPointerEscape(ProgramStateRef State, const InvalidatedSymbols &Escaped, const CallEvent *Call, PointerEscapeKind Kind) const { - return checkPointerEscapeAux(State, Escaped, Call, Kind, &retTrue); + return checkPointerEscapeAux(State, Escaped, Call, Kind, + /*IsConstPointerEscape*/ false); } ProgramStateRef MallocChecker::checkConstPointerEscape(ProgramStateRef State, const InvalidatedSymbols &Escaped, const CallEvent *Call, PointerEscapeKind Kind) const { + // If a const pointer escapes, it may not be freed(), but it could be deleted. return checkPointerEscapeAux(State, Escaped, Call, Kind, - &checkIfNewOrNewArrayFamily); + /*IsConstPointerEscape*/ true); } -ProgramStateRef MallocChecker::checkPointerEscapeAux(ProgramStateRef State, - const InvalidatedSymbols &Escaped, - const CallEvent *Call, - PointerEscapeKind Kind, - bool(*CheckRefState)(const RefState*)) const { +static bool checkIfNewOrNewArrayFamily(const RefState *RS) { + return (RS->getAllocationFamily() == AF_CXXNewArray || + RS->getAllocationFamily() == AF_CXXNew); +} + +ProgramStateRef MallocChecker::checkPointerEscapeAux( + ProgramStateRef State, const InvalidatedSymbols &Escaped, + const CallEvent *Call, PointerEscapeKind Kind, + bool IsConstPointerEscape) const { // If we know that the call does not free memory, or we want to process the // call later, keep tracking the top level arguments. SymbolRef EscapingSymbol = nullptr; @@ -2870,12 +3132,10 @@ ProgramStateRef MallocChecker::checkPointerEscapeAux(ProgramStateRef State, if (EscapingSymbol && EscapingSymbol != sym) continue; - if (const RefState *RS = State->get(sym)) { - if ((RS->isAllocated() || RS->isAllocatedOfSizeZero()) && - CheckRefState(RS)) { - State = State->set(sym, RefState::getEscaped(RS)); - } - } + if (const RefState *RS = State->get(sym)) + if (RS->isAllocated() || RS->isAllocatedOfSizeZero()) + if (!IsConstPointerEscape || checkIfNewOrNewArrayFamily(RS)) + State = State->set(sym, RefState::getEscaped(RS)); } return State; } @@ -2885,9 +3145,8 @@ static SymbolRef findFailedReallocSymbol(ProgramStateRef currState, ReallocPairsTy currMap = currState->get(); ReallocPairsTy prevMap = prevState->get(); - for (ReallocPairsTy::iterator I = prevMap.begin(), E = prevMap.end(); - I != E; ++I) { - SymbolRef sym = I.getKey(); + for (const ReallocPairsTy::value_type &Pair : prevMap) { + SymbolRef sym = Pair.first; if (!currMap.lookup(sym)) return sym; } @@ -2908,21 +3167,19 @@ static bool isReferenceCountingPointerDestructor(const CXXDestructorDecl *DD) { return false; } -PathDiagnosticPieceRef -MallocChecker::MallocBugVisitor::VisitNode(const ExplodedNode *N, - BugReporterContext &BRC, - PathSensitiveBugReport &BR) { - +PathDiagnosticPieceRef MallocBugVisitor::VisitNode(const ExplodedNode *N, + BugReporterContext &BRC, + PathSensitiveBugReport &BR) { ProgramStateRef state = N->getState(); ProgramStateRef statePrev = N->getFirstPred()->getState(); - const RefState *RS = state->get(Sym); + const RefState *RSCurr = state->get(Sym); const RefState *RSPrev = statePrev->get(Sym); const Stmt *S = N->getStmtForDiagnostics(); // When dealing with containers, we sometimes want to give a note // even if the statement is missing. - if (!S && (!RS || RS->getAllocationFamily() != AF_InnerBuffer)) + if (!S && (!RSCurr || RSCurr->getAllocationFamily() != AF_InnerBuffer)) return nullptr; const LocationContext *CurrentLC = N->getLocationContext(); @@ -2957,12 +3214,12 @@ MallocChecker::MallocBugVisitor::VisitNode(const ExplodedNode *N, llvm::raw_svector_ostream OS(Buf); if (Mode == Normal) { - if (isAllocated(RS, RSPrev, S)) { + if (isAllocated(RSCurr, RSPrev, S)) { Msg = "Memory is allocated"; StackHint = std::make_unique( Sym, "Returned allocated memory"); - } else if (isReleased(RS, RSPrev, S)) { - const auto Family = RS->getAllocationFamily(); + } else if (isReleased(RSCurr, RSPrev, S)) { + const auto Family = RSCurr->getAllocationFamily(); switch (Family) { case AF_Alloca: case AF_Malloc: @@ -2986,7 +3243,7 @@ MallocChecker::MallocBugVisitor::VisitNode(const ExplodedNode *N, Sym, "Returning; inner buffer was deallocated"); } else { OS << "reallocated by call to '"; - const Stmt *S = RS->getStmt(); + const Stmt *S = RSCurr->getStmt(); if (const auto *MemCallE = dyn_cast(S)) { OS << MemCallE->getMethodDecl()->getNameAsString(); } else if (const auto *OpCallE = dyn_cast(S)) { @@ -3037,10 +3294,10 @@ MallocChecker::MallocBugVisitor::VisitNode(const ExplodedNode *N, } } } - } else if (isRelinquished(RS, RSPrev, S)) { + } else if (isRelinquished(RSCurr, RSPrev, S)) { Msg = "Memory ownership is transferred"; StackHint = std::make_unique(Sym, ""); - } else if (isReallocFailedCheck(RS, RSPrev, S)) { + } else if (hasReallocFailed(RSCurr, RSPrev, S)) { Mode = ReallocationFailed; Msg = "Reallocation failed"; StackHint = std::make_unique( @@ -3080,7 +3337,7 @@ MallocChecker::MallocBugVisitor::VisitNode(const ExplodedNode *N, // Generate the extra diagnostic. PathDiagnosticLocation Pos; if (!S) { - assert(RS->getAllocationFamily() == AF_InnerBuffer); + assert(RSCurr->getAllocationFamily() == AF_InnerBuffer); auto PostImplCall = N->getLocation().getAs(); if (!PostImplCall) return nullptr; @@ -3145,8 +3402,8 @@ void ento::registerInnerPointerCheckerAux(CheckerManager &mgr) { void ento::registerDynamicMemoryModeling(CheckerManager &mgr) { auto *checker = mgr.registerChecker(); - checker->IsOptimistic = mgr.getAnalyzerOptions().getCheckerBooleanOption( - checker, "Optimistic"); + checker->MemFunctionInfo.ShouldIncludeOwnershipAnnotatedFunctions = + mgr.getAnalyzerOptions().getCheckerBooleanOption(checker, "Optimistic"); } bool ento::shouldRegisterDynamicMemoryModeling(const LangOptions &LO) { From 2d2850ff09b7b1ca5fbc249b46c05ff94931831a Mon Sep 17 00:00:00 2001 From: Richard Smith Date: Fri, 20 Sep 2019 18:09:05 +0000 Subject: [PATCH 20/71] [www] Turn 'Clang 9' boxes green in C++ status pages now Clang 9 is released. llvm-svn: 372415 --- clang/www/cxx_dr_status.html | 24 ++++++++++++------------ clang/www/cxx_status.html | 30 +++++++++++++++--------------- clang/www/make_cxx_dr_status | 3 --- 3 files changed, 27 insertions(+), 30 deletions(-) diff --git a/clang/www/cxx_dr_status.html b/clang/www/cxx_dr_status.html index 487d6fb2d93e5..40af4732ef600 100755 --- a/clang/www/cxx_dr_status.html +++ b/clang/www/cxx_dr_status.html @@ -9955,19 +9955,19 @@

C++ defect report implementation status

1690 C++14 Associated namespace for local type - Clang 9 + Clang 9 1691 C++14 Argument-dependent lookup and opaque enumerations - Clang 9 + Clang 9 1692 C++14 Associated namespaces of doubly-nested classes - Clang 9 + Clang 9 1693 @@ -10147,7 +10147,7 @@

C++ defect report implementation status

1722 CD4 Should lambda to function pointer conversion function be noexcept? - Clang 9 + Clang 9 1723 @@ -10483,7 +10483,7 @@

C++ defect report implementation status

1778 C++14 exception-specification in explicitly-defaulted functions - Clang 9 + Clang 9 1779 @@ -11047,7 +11047,7 @@

C++ defect report implementation status

1872 CD4 Instantiations of constexpr templates that cannot appear in constant expressions - Clang 9 + Clang 9 1873 @@ -12655,7 +12655,7 @@

C++ defect report implementation status

2140 CD4 Lvalue-to-rvalue conversion of std::nullptr_t - Clang 9 + Clang 9 2141 @@ -12835,7 +12835,7 @@

C++ defect report implementation status

2170 DR Unclear definition of odr-use for arrays - Clang 9 + Clang 9 2171 @@ -13567,7 +13567,7 @@

C++ defect report implementation status

2292 DRWP simple-template-id is ambiguous between class-name and type-name - Clang 9 + Clang 9 2293 @@ -13933,7 +13933,7 @@

C++ defect report implementation status

2353 DR Potential results of a member access expression for a static data member - Clang 9 + Clang 9 2354 @@ -14131,13 +14131,13 @@

C++ defect report implementation status

2386 DR tuple_size requirements for structured binding - Clang 9 + Clang 9 2387 DR Linkage of const-qualified variable template - Clang 9 + Clang 9 2388 diff --git a/clang/www/cxx_status.html b/clang/www/cxx_status.html index 7b2c79326efe9..611c8427af1b6 100755 --- a/clang/www/cxx_status.html +++ b/clang/www/cxx_status.html @@ -114,7 +114,7 @@

C++11 implementation status

P1009R2 (DR) - Clang 9 + Clang 9 Static assertions @@ -289,7 +289,7 @@

C++11 implementation status

P1286R2 (DR) - Clang 9 + Clang 9 Deleted functions @@ -664,7 +664,7 @@

C++17 implementation status

P1771R1 (DR) - Clang 9 + Clang 9 [[maybe_unused]] attribute @@ -866,7 +866,7 @@

C++2a implementation status

P1042R1 - Clang 9 + Clang 9 Designated initializers @@ -876,7 +876,7 @@

C++2a implementation status

template-parameter-list for generic lambdas P0428R2 - Clang 9 + Clang 9 Concepts @@ -910,7 +910,7 @@

C++2a implementation status

ADL and function templates that are not visible P0846R0 - Clang 9 + Clang 9 const mismatch with defaulted copy constructor @@ -957,7 +957,7 @@

C++2a implementation status

[[no_unique_address]] attribute P0840R2 - Clang 9 + Clang 9 [[likely]] and [[unlikely]] attributes @@ -972,7 +972,7 @@

C++2a implementation status

Pack expansion in lambda init-capture P0780R2 - Clang 9 + Clang 9 @@ -988,7 +988,7 @@

C++2a implementation status

Relaxations of constexpr restrictions P1064R0 - Clang 9 + Clang 9 P1002R1 @@ -996,7 +996,7 @@

C++2a implementation status

P1327R1 - Clang 9 + Clang 9 P1330R0 @@ -1025,13 +1025,13 @@

C++2a implementation status

explicit(bool) P0892R2 - Clang 9 + Clang 9 Signed integers are two's complement P1236R1 - Clang 9 + Clang 9 char8_t @@ -1046,7 +1046,7 @@

C++2a implementation status

std::is_constant_evaluated P0595R2 - Clang 9 + Clang 9 Nested inline namespaces @@ -1099,7 +1099,7 @@

C++2a implementation status

Deprecate a[b,c] P1161R3 - Clang 9 + Clang 9 Deprecate some problematic uses of volatile @@ -1109,7 +1109,7 @@

C++2a implementation status

[[nodiscard("with reason")]] P1301R4 - Clang 9 + Clang 9 using enum diff --git a/clang/www/make_cxx_dr_status b/clang/www/make_cxx_dr_status index ff4a3f5c1b471..4351d659e41ae 100755 --- a/clang/www/make_cxx_dr_status +++ b/clang/www/make_cxx_dr_status @@ -111,9 +111,6 @@ def availability(issue): elif status == '10': avail = 'SVN' avail_style = ' class="svn"' - elif status == '9': - avail = 'Clang 9' - avail_style = ' class="svn"' elif re.match('^[0-9]+\.?[0-9]*', status): avail = 'Clang %s' % status avail_style = ' class="full"' From 7dab840fd4f26fc814b323e017f549f9fb43fcd5 Mon Sep 17 00:00:00 2001 From: Simon Pilgrim Date: Fri, 20 Sep 2019 18:10:17 +0000 Subject: [PATCH 21/71] Fix MSVC "not all control paths return a value" warning. NFCI. llvm-svn: 372416 --- llvm/lib/TextAPI/MachO/Platform.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/llvm/lib/TextAPI/MachO/Platform.cpp b/llvm/lib/TextAPI/MachO/Platform.cpp index ec62a9b3edba6..66bb7df9aa5ce 100644 --- a/llvm/lib/TextAPI/MachO/Platform.cpp +++ b/llvm/lib/TextAPI/MachO/Platform.cpp @@ -55,7 +55,8 @@ StringRef getPlatformName(PlatformKind Platform) { case PlatformKind::bridgeOS: return "bridgeOS"; } + llvm_unreachable("Unknown llvm.MachO.PlatformKind enum"); } } // end namespace MachO. -} // end namespace llvm. \ No newline at end of file +} // end namespace llvm. From e065e5f12a7de2074355e1fc3d2d1fcb4a4fcf66 Mon Sep 17 00:00:00 2001 From: Jinsong Ji Date: Fri, 20 Sep 2019 18:21:07 +0000 Subject: [PATCH 22/71] [NFC][PowerPC] Refactor classifyGlobalReference We always(and only) check the NLP flag after calling classifyGlobalReference to see whether it is accessed indirectly. Refactor to code to use isGVIndirectSym instead. llvm-svn: 372417 --- llvm/lib/Target/PowerPC/PPCAsmPrinter.cpp | 9 +++------ llvm/lib/Target/PowerPC/PPCFastISel.cpp | 3 +-- llvm/lib/Target/PowerPC/PPCISelLowering.cpp | 10 ++-------- llvm/lib/Target/PowerPC/PPCSubtarget.cpp | 13 ++++--------- llvm/lib/Target/PowerPC/PPCSubtarget.h | 5 ++--- 5 files changed, 12 insertions(+), 28 deletions(-) diff --git a/llvm/lib/Target/PowerPC/PPCAsmPrinter.cpp b/llvm/lib/Target/PowerPC/PPCAsmPrinter.cpp index 2b64bcf3cf88a..c835df3cabc65 100644 --- a/llvm/lib/Target/PowerPC/PPCAsmPrinter.cpp +++ b/llvm/lib/Target/PowerPC/PPCAsmPrinter.cpp @@ -742,8 +742,7 @@ void PPCAsmPrinter::EmitInstruction(const MachineInstr *MI) { if (MO.isGlobal()) { const GlobalValue *GV = MO.getGlobal(); MOSymbol = getSymbol(GV); - unsigned char GVFlags = Subtarget->classifyGlobalReference(GV); - GlobalToc = (GVFlags & PPCII::MO_NLP_FLAG); + GlobalToc = Subtarget->isGVIndirectSymbol(GV); } else if (MO.isCPI()) { MOSymbol = GetCPISymbol(MO.getIndex()); } else if (MO.isJTI()) { @@ -799,8 +798,7 @@ void PPCAsmPrinter::EmitInstruction(const MachineInstr *MI) { const GlobalValue *GV = MO.getGlobal(); MOSymbol = getSymbol(GV); LLVM_DEBUG( - unsigned char GVFlags = Subtarget->classifyGlobalReference(GV); - assert((GVFlags & PPCII::MO_NLP_FLAG) && + assert((Subtarget->isGVIndirectSymbol(GV)) && "LDtocL used on symbol that could be accessed directly is " "invalid. Must match ADDIStocHA8.")); MOSymbol = lookUpOrCreateTOCEntry(MOSymbol); @@ -827,8 +825,7 @@ void PPCAsmPrinter::EmitInstruction(const MachineInstr *MI) { if (MO.isGlobal()) { const GlobalValue *GV = MO.getGlobal(); - LLVM_DEBUG(unsigned char GVFlags = Subtarget->classifyGlobalReference(GV); - assert(!(GVFlags & PPCII::MO_NLP_FLAG) && + LLVM_DEBUG(assert(!(Subtarget->isGVIndirectSymbol(GV)) && "Interposable definitions must use indirect access.")); MOSymbol = getSymbol(GV); } else if (MO.isCPI()) { diff --git a/llvm/lib/Target/PowerPC/PPCFastISel.cpp b/llvm/lib/Target/PowerPC/PPCFastISel.cpp index 1b545bccb4d0d..d8425d89da92e 100644 --- a/llvm/lib/Target/PowerPC/PPCFastISel.cpp +++ b/llvm/lib/Target/PowerPC/PPCFastISel.cpp @@ -2093,8 +2093,7 @@ unsigned PPCFastISel::PPCMaterializeGV(const GlobalValue *GV, MVT VT) { BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc, TII.get(PPC::ADDIStocHA8), HighPartReg).addReg(PPC::X2).addGlobalAddress(GV); - unsigned char GVFlags = PPCSubTarget->classifyGlobalReference(GV); - if (GVFlags & PPCII::MO_NLP_FLAG) { + if (PPCSubTarget->isGVIndirectSymbol(GV)) { BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc, TII.get(PPC::LDtocL), DestReg).addGlobalAddress(GV).addReg(HighPartReg); } else { diff --git a/llvm/lib/Target/PowerPC/PPCISelLowering.cpp b/llvm/lib/Target/PowerPC/PPCISelLowering.cpp index 4c846e6e75386..ed9aae8f2e768 100644 --- a/llvm/lib/Target/PowerPC/PPCISelLowering.cpp +++ b/llvm/lib/Target/PowerPC/PPCISelLowering.cpp @@ -14555,14 +14555,8 @@ bool PPCTargetLowering::isAccessedAsGotIndirect(SDValue GA) const { if (isa(GA) || isa(GA)) return true; - if (GlobalAddressSDNode *G = dyn_cast(GA)) { - const GlobalValue *GV = G->getGlobal(); - unsigned char GVFlags = Subtarget.classifyGlobalReference(GV); - // The NLP flag indicates that a global access has to use an - // extra indirection. - if (GVFlags & PPCII::MO_NLP_FLAG) - return true; - } + if (GlobalAddressSDNode *G = dyn_cast(GA)) + return Subtarget.isGVIndirectSymbol(G->getGlobal()); return false; } diff --git a/llvm/lib/Target/PowerPC/PPCSubtarget.cpp b/llvm/lib/Target/PowerPC/PPCSubtarget.cpp index 6239decf15392..b63f008ce866d 100644 --- a/llvm/lib/Target/PowerPC/PPCSubtarget.cpp +++ b/llvm/lib/Target/PowerPC/PPCSubtarget.cpp @@ -229,18 +229,13 @@ bool PPCSubtarget::enableSubRegLiveness() const { return UseSubRegLiveness; } -unsigned char -PPCSubtarget::classifyGlobalReference(const GlobalValue *GV) const { - // Note that currently we don't generate non-pic references. - // If a caller wants that, this will have to be updated. - +bool PPCSubtarget::isGVIndirectSymbol(const GlobalValue *GV) const { // Large code model always uses the TOC even for local symbols. if (TM.getCodeModel() == CodeModel::Large) - return PPCII::MO_PIC_FLAG | PPCII::MO_NLP_FLAG; - + return true; if (TM.shouldAssumeDSOLocal(*GV->getParent(), GV)) - return PPCII::MO_PIC_FLAG; - return PPCII::MO_PIC_FLAG | PPCII::MO_NLP_FLAG; + return false; + return true; } bool PPCSubtarget::isELFv2ABI() const { return TM.isELFv2ABI(); } diff --git a/llvm/lib/Target/PowerPC/PPCSubtarget.h b/llvm/lib/Target/PowerPC/PPCSubtarget.h index 35bb90c6203f7..0ac0bbe2edec9 100644 --- a/llvm/lib/Target/PowerPC/PPCSubtarget.h +++ b/llvm/lib/Target/PowerPC/PPCSubtarget.h @@ -344,9 +344,8 @@ class PPCSubtarget : public PPCGenSubtargetInfo { bool enableSubRegLiveness() const override; - /// classifyGlobalReference - Classify a global variable reference for the - /// current subtarget accourding to how we should reference it. - unsigned char classifyGlobalReference(const GlobalValue *GV) const; + /// True if the GV will be accessed via an indirect symbol. + bool isGVIndirectSymbol(const GlobalValue *GV) const; bool isXRaySupported() const override { return IsPPC64 && IsLittleEndian; } }; From 60a6f31dde488e28afab0dc39697e645d0653e2e Mon Sep 17 00:00:00 2001 From: Simon Pilgrim Date: Fri, 20 Sep 2019 18:21:31 +0000 Subject: [PATCH 23/71] Fix -Wdocumentation warning. NFCI. llvm-svn: 372418 --- llvm/include/llvm/TextAPI/MachO/InterfaceFile.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/llvm/include/llvm/TextAPI/MachO/InterfaceFile.h b/llvm/include/llvm/TextAPI/MachO/InterfaceFile.h index c85708f29b011..8bb6b5ff06665 100644 --- a/llvm/include/llvm/TextAPI/MachO/InterfaceFile.h +++ b/llvm/include/llvm/TextAPI/MachO/InterfaceFile.h @@ -285,7 +285,7 @@ class InterfaceFile { /// that is being generated needs to match one of the allowable clients or the /// linker refuses to link this library. /// - /// \param Name The name of the client that is allowed to link this library. + /// \param InstallName The name of the client that is allowed to link this library. /// \param Target The target triple for which this applies. void addAllowableClient(StringRef InstallName, const Target &Target); From 96be6f485c733c990d01c60f0dc6ae11b3974eea Mon Sep 17 00:00:00 2001 From: Kristof Umann Date: Fri, 20 Sep 2019 18:28:04 +0000 Subject: [PATCH 24/71] Fix a documentation error llvm-svn: 372419 --- clang/lib/StaticAnalyzer/Checkers/MallocChecker.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/clang/lib/StaticAnalyzer/Checkers/MallocChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/MallocChecker.cpp index 144096f8087f7..27a40e35d642b 100644 --- a/clang/lib/StaticAnalyzer/Checkers/MallocChecker.cpp +++ b/clang/lib/StaticAnalyzer/Checkers/MallocChecker.cpp @@ -550,7 +550,7 @@ class MallocChecker /// Models memory reallocation. /// /// \param [in] CE The expression that reallocated memory - /// \param [in] FreesMemOnFailure Whether if reallocation fails, the supplied + /// \param [in] ShouldFreeOnFail Whether if reallocation fails, the supplied /// memory should be freed. /// \param [in] State The \c ProgramState right before reallocation. /// \param [in] SuffixWithN Whether the reallocation function we're modeling From c139d1e28109450085a11e3b2ec7d53c6a00c37b Mon Sep 17 00:00:00 2001 From: Craig Topper Date: Fri, 20 Sep 2019 18:52:49 +0000 Subject: [PATCH 25/71] [Mips] Remove immarg test for intrinsics that no longer have an immarg after r372409. llvm-svn: 372420 --- llvm/test/Verifier/Mips/intrinsic-immarg.ll | 82 --------------------- 1 file changed, 82 deletions(-) delete mode 100644 llvm/test/Verifier/Mips/intrinsic-immarg.ll diff --git a/llvm/test/Verifier/Mips/intrinsic-immarg.ll b/llvm/test/Verifier/Mips/intrinsic-immarg.ll deleted file mode 100644 index dfe5aa94ab97f..0000000000000 --- a/llvm/test/Verifier/Mips/intrinsic-immarg.ll +++ /dev/null @@ -1,82 +0,0 @@ -; RUN: not llvm-as %s -o /dev/null 2>&1 | FileCheck %s - -define void @ld_b(<16 x i8> * %ptr, i8 * %ldptr, i32 %offset) { - ; CHECK: immarg operand has non-immediate parameter - ; CHECK-NEXT: i32 %offset - ; CHECK-NEXT: %a = call <16 x i8> @llvm.mips.ld.b(i8* %ldptr, i32 %offset) - %a = call <16 x i8> @llvm.mips.ld.b(i8* %ldptr, i32 %offset) - store <16 x i8> %a, <16 x i8> * %ptr, align 16 - ret void -} - -define void @st_b(<16 x i8> * %ptr, i8 * %ldptr, i32 %offset, i8 * %stptr) { - ; CHECK: immarg operand has non-immediate parameter - ; CHECK-NEXT: i32 %offset - ; CHECK-NEXT: call void @llvm.mips.st.b(<16 x i8> %a, i8* %stptr, i32 %offset) - %a = call <16 x i8> @llvm.mips.ld.b(i8* %ldptr, i32 0) - call void @llvm.mips.st.b(<16 x i8> %a, i8* %stptr, i32 %offset) - ret void -} - -define void @ld_w(<4 x i32> * %ptr, i8 * %ldptr, i32 %offset) { - ; CHECK: immarg operand has non-immediate parameter - ; CHECK-NEXT: i32 %offset - ; CHECK-NEXT: %a = call <4 x i32> @llvm.mips.ld.w(i8* %ldptr, i32 %offset) - %a = call <4 x i32> @llvm.mips.ld.w(i8* %ldptr, i32 %offset) - store <4 x i32> %a, <4 x i32> * %ptr, align 16 - ret void -} - -define void @st_w(<8 x i16> * %ptr, i8 * %ldptr, i32 %offset, i8 * %stptr) { - ; CHECK: immarg operand has non-immediate parameter - ; CHECK-NEXT: i32 %offset - ; CHECK-NEXT: call void @llvm.mips.st.w(<4 x i32> %a, i8* %stptr, i32 %offset) - %a = call <4 x i32> @llvm.mips.ld.w(i8* %ldptr, i32 0) - call void @llvm.mips.st.w(<4 x i32> %a, i8* %stptr, i32 %offset) - ret void -} - -define void @ld_h(<8 x i16> * %ptr, i8 * %ldptr, i32 %offset) { - ; CHECK: immarg operand has non-immediate parameter - ; CHECK-NEXT: i32 %offset - ; CHECK-NEXT: %a = call <8 x i16> @llvm.mips.ld.h(i8* %ldptr, i32 %offset) - %a = call <8 x i16> @llvm.mips.ld.h(i8* %ldptr, i32 %offset) - store <8 x i16> %a, <8 x i16> * %ptr, align 16 - ret void -} - -define void @st_h(<8 x i16> * %ptr, i8 * %ldptr, i32 %offset, i8 * %stptr) { - ; CHECK: immarg operand has non-immediate parameter - ; CHECK-NEXT: i32 %offset - ; CHECK-NEXT: call void @llvm.mips.st.h(<8 x i16> %a, i8* %stptr, i32 %offset) - %a = call <8 x i16> @llvm.mips.ld.h(i8* %ldptr, i32 0) - call void @llvm.mips.st.h(<8 x i16> %a, i8* %stptr, i32 %offset) - ret void -} - -define void @ld_d(<2 x i64> * %ptr, i8 * %ldptr, i32 %offset) { - ; CHECK: immarg operand has non-immediate parameter - ; CHECK-NEXT: i32 %offset - ; CHECK-NEXT: %a = call <2 x i64> @llvm.mips.ld.d(i8* %ldptr, i32 %offset) - %a = call <2 x i64> @llvm.mips.ld.d(i8* %ldptr, i32 %offset) - store <2 x i64> %a, <2 x i64> * %ptr, align 16 - ret void -} - -define void @st_d(<2 x i64> * %ptr, i8 * %ldptr, i32 %offset, i8 * %stptr) { - ; CHECK: immarg operand has non-immediate parameter - ; CHECK-NEXT: i32 %offset - ; CHECK-NEXT: call void @llvm.mips.st.d(<2 x i64> %a, i8* %stptr, i32 %offset) - %a = call <2 x i64> @llvm.mips.ld.d(i8* %ldptr, i32 0) - call void @llvm.mips.st.d(<2 x i64> %a, i8* %stptr, i32 %offset) - ret void -} - -declare <16 x i8> @llvm.mips.ld.b(i8*, i32) -declare <8 x i16> @llvm.mips.ld.h(i8*, i32) -declare <4 x i32> @llvm.mips.ld.w(i8*, i32) -declare <2 x i64> @llvm.mips.ld.d(i8*, i32) -declare void @llvm.mips.st.b(<16 x i8>, i8*, i32) -declare void @llvm.mips.st.h(<8 x i16>, i8*, i32) -declare void @llvm.mips.st.w(<4 x i32>, i8*, i32) -declare void @llvm.mips.st.d(<2 x i64>, i8*, i32) From 6a234677f4916fc647e463f058feeff73b131879 Mon Sep 17 00:00:00 2001 From: Michael Trent Date: Fri, 20 Sep 2019 19:13:24 +0000 Subject: [PATCH 26/71] Can't pass .dSYM directory to llvm-objdump -dsym= (and error message is wrong) Summary: Allow users to pass the path to a .dSYM directory to llvm-objdump's -dsym flag rather than requiring users to find the DWARF DSYM Mach-O within the bundle structure by hand. rdar://46873333 Reviewers: pete, lhames, friss, aprantl Reviewed By: pete, aprantl Subscribers: MaskRay, aprantl, rupprecht, seiya, llvm-commits Tags: #llvm Differential Revision: https://reviews.llvm.org/D67780 llvm-svn: 372421 --- llvm/tools/llvm-objdump/MachODump.cpp | 31 +++++++++++++++++++-------- 1 file changed, 22 insertions(+), 9 deletions(-) diff --git a/llvm/tools/llvm-objdump/MachODump.cpp b/llvm/tools/llvm-objdump/MachODump.cpp index 25b721ae5586e..284f9b2a7af73 100644 --- a/llvm/tools/llvm-objdump/MachODump.cpp +++ b/llvm/tools/llvm-objdump/MachODump.cpp @@ -7340,10 +7340,24 @@ static void DisassembleMachO(StringRef Filename, MachOObjectFile *MachOOF, // A separate DSym file path was specified, parse it as a macho file, // get the sections and supply it to the section name parsing machinery. if (!DSYMFile.empty()) { + std::string DSYMPath(DSYMFile); + + // If DSYMPath is a .dSYM directory, append the Mach-O file. + if (llvm::sys::fs::is_directory(DSYMPath) && + llvm::sys::path::extension(DSYMPath) == ".dSYM") { + SmallString<128> ShortName(llvm::sys::path::filename(DSYMPath)); + llvm::sys::path::replace_extension(ShortName, ""); + SmallString<1024> FullPath(DSYMPath); + llvm::sys::path::append(FullPath, "Contents", "Resources", "DWARF", + ShortName); + DSYMPath = FullPath.str(); + } + + // Load the file. ErrorOr> BufOrErr = - MemoryBuffer::getFileOrSTDIN(DSYMFile); + MemoryBuffer::getFileOrSTDIN(DSYMPath); if (std::error_code EC = BufOrErr.getError()) { - reportError(errorCodeToError(EC), DSYMFile); + reportError(errorCodeToError(EC), DSYMPath); return; } @@ -7353,13 +7367,12 @@ static void DisassembleMachO(StringRef Filename, MachOObjectFile *MachOOF, Expected> BinaryOrErr = createBinary(DSYMBuf.get()->getMemBufferRef()); if (!BinaryOrErr) { - reportError(BinaryOrErr.takeError(), DSYMFile); + reportError(BinaryOrErr.takeError(), DSYMPath); return; } - // We need to keep the Binary elive with the buffer + // We need to keep the Binary alive with the buffer DSYMBinary = std::move(BinaryOrErr.get()); - if (ObjectFile *O = dyn_cast(DSYMBinary.get())) { // this is a Mach-O object file, use it if (MachOObjectFile *MachDSYM = dyn_cast(&*O)) { @@ -7367,7 +7380,7 @@ static void DisassembleMachO(StringRef Filename, MachOObjectFile *MachOOF, } else { WithColor::error(errs(), "llvm-objdump") - << DSYMFile << " is not a Mach-O file type.\n"; + << DSYMPath << " is not a Mach-O file type.\n"; return; } } @@ -7389,17 +7402,17 @@ static void DisassembleMachO(StringRef Filename, MachOObjectFile *MachOOF, Expected> MachDSYM = UB->getMachOObjectForArch(ArchFlag); if (!MachDSYM) { - reportError(MachDSYM.takeError(), DSYMFile); + reportError(MachDSYM.takeError(), DSYMPath); return; } - // We need to keep the Binary elive with the buffer + // We need to keep the Binary alive with the buffer DbgObj = &*MachDSYM.get(); DSYMBinary = std::move(*MachDSYM); } else { WithColor::error(errs(), "llvm-objdump") - << DSYMFile << " is not a Mach-O or Universal file type.\n"; + << DSYMPath << " is not a Mach-O or Universal file type.\n"; return; } } From 830909b97a9a63959758f0b5e049ac172815d0db Mon Sep 17 00:00:00 2001 From: Erich Keane Date: Fri, 20 Sep 2019 19:17:31 +0000 Subject: [PATCH 27/71] Ensure AtomicExpr goes through SEMA checking after TreeTransform RebuildAtomicExpr was skipping doing semantic analysis which broke in the cases where the expressions were not dependent. This resulted in the ImplicitCastExpr from an array to a pointer being lost, causing a crash in IR CodeGen. Differential Revision: https://reviews.llvm.org/D67854 llvm-svn: 372422 --- clang/include/clang/Sema/Sema.h | 3 + clang/lib/Sema/SemaChecking.cpp | 101 +++++++++++++++++--------------- clang/lib/Sema/TreeTransform.h | 13 ++-- clang/test/AST/atomic-expr.cpp | 19 ++++++ 4 files changed, 81 insertions(+), 55 deletions(-) create mode 100644 clang/test/AST/atomic-expr.cpp diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h index 7faea280b7310..9c2226f83c2f8 100644 --- a/clang/include/clang/Sema/Sema.h +++ b/clang/include/clang/Sema/Sema.h @@ -4637,6 +4637,9 @@ class Sema { MultiExprArg ArgExprs, SourceLocation RParenLoc, Expr *ExecConfig = nullptr, bool IsExecConfig = false); + ExprResult BuildAtomicExpr(SourceRange CallRange, SourceRange ExprRange, + SourceLocation RParenLoc, MultiExprArg Args, + AtomicExpr::AtomicOp Op); ExprResult BuildResolvedCallExpr(Expr *Fn, NamedDecl *NDecl, SourceLocation LParenLoc, ArrayRef Arg, SourceLocation RParenLoc, diff --git a/clang/lib/Sema/SemaChecking.cpp b/clang/lib/Sema/SemaChecking.cpp index 4a3d26a5abe1b..fb66bc7db34b0 100644 --- a/clang/lib/Sema/SemaChecking.cpp +++ b/clang/lib/Sema/SemaChecking.cpp @@ -4475,7 +4475,15 @@ ExprResult Sema::SemaAtomicOpsOverloaded(ExprResult TheCallResult, AtomicExpr::AtomicOp Op) { CallExpr *TheCall = cast(TheCallResult.get()); DeclRefExpr *DRE =cast(TheCall->getCallee()->IgnoreParenCasts()); + MultiExprArg Args{TheCall->getArgs(), TheCall->getNumArgs()}; + return BuildAtomicExpr({TheCall->getBeginLoc(), TheCall->getEndLoc()}, + DRE->getSourceRange(), TheCall->getRParenLoc(), Args, + Op); +} +ExprResult Sema::BuildAtomicExpr(SourceRange CallRange, SourceRange ExprRange, + SourceLocation RParenLoc, MultiExprArg Args, + AtomicExpr::AtomicOp Op) { // All the non-OpenCL operations take one of the following forms. // The OpenCL operations take the __c11 forms with one extra argument for // synchronization scope. @@ -4622,21 +4630,21 @@ ExprResult Sema::SemaAtomicOpsOverloaded(ExprResult TheCallResult, if (IsOpenCL && Op != AtomicExpr::AO__opencl_atomic_init) ++AdjustedNumArgs; // Check we have the right number of arguments. - if (TheCall->getNumArgs() < AdjustedNumArgs) { - Diag(TheCall->getEndLoc(), diag::err_typecheck_call_too_few_args) - << 0 << AdjustedNumArgs << TheCall->getNumArgs() - << TheCall->getCallee()->getSourceRange(); + if (Args.size() < AdjustedNumArgs) { + Diag(CallRange.getEnd(), diag::err_typecheck_call_too_few_args) + << 0 << AdjustedNumArgs << static_cast(Args.size()) + << ExprRange; return ExprError(); - } else if (TheCall->getNumArgs() > AdjustedNumArgs) { - Diag(TheCall->getArg(AdjustedNumArgs)->getBeginLoc(), + } else if (Args.size() > AdjustedNumArgs) { + Diag(Args[AdjustedNumArgs]->getBeginLoc(), diag::err_typecheck_call_too_many_args) - << 0 << AdjustedNumArgs << TheCall->getNumArgs() - << TheCall->getCallee()->getSourceRange(); + << 0 << AdjustedNumArgs << static_cast(Args.size()) + << ExprRange; return ExprError(); } // Inspect the first argument of the atomic operation. - Expr *Ptr = TheCall->getArg(0); + Expr *Ptr = Args[0]; ExprResult ConvertedPtr = DefaultFunctionArrayLvalueConversion(Ptr); if (ConvertedPtr.isInvalid()) return ExprError(); @@ -4644,7 +4652,7 @@ ExprResult Sema::SemaAtomicOpsOverloaded(ExprResult TheCallResult, Ptr = ConvertedPtr.get(); const PointerType *pointerType = Ptr->getType()->getAs(); if (!pointerType) { - Diag(DRE->getBeginLoc(), diag::err_atomic_builtin_must_be_pointer) + Diag(ExprRange.getBegin(), diag::err_atomic_builtin_must_be_pointer) << Ptr->getType() << Ptr->getSourceRange(); return ExprError(); } @@ -4654,13 +4662,13 @@ ExprResult Sema::SemaAtomicOpsOverloaded(ExprResult TheCallResult, QualType ValType = AtomTy; // 'C' if (IsC11) { if (!AtomTy->isAtomicType()) { - Diag(DRE->getBeginLoc(), diag::err_atomic_op_needs_atomic) + Diag(ExprRange.getBegin(), diag::err_atomic_op_needs_atomic) << Ptr->getType() << Ptr->getSourceRange(); return ExprError(); } if ((Form != Load && Form != LoadCopy && AtomTy.isConstQualified()) || AtomTy.getAddressSpace() == LangAS::opencl_constant) { - Diag(DRE->getBeginLoc(), diag::err_atomic_op_needs_non_const_atomic) + Diag(ExprRange.getBegin(), diag::err_atomic_op_needs_non_const_atomic) << (AtomTy.isConstQualified() ? 0 : 1) << Ptr->getType() << Ptr->getSourceRange(); return ExprError(); @@ -4668,7 +4676,7 @@ ExprResult Sema::SemaAtomicOpsOverloaded(ExprResult TheCallResult, ValType = AtomTy->getAs()->getValueType(); } else if (Form != Load && Form != LoadCopy) { if (ValType.isConstQualified()) { - Diag(DRE->getBeginLoc(), diag::err_atomic_op_needs_non_const_pointer) + Diag(ExprRange.getBegin(), diag::err_atomic_op_needs_non_const_pointer) << Ptr->getType() << Ptr->getSourceRange(); return ExprError(); } @@ -4679,7 +4687,7 @@ ExprResult Sema::SemaAtomicOpsOverloaded(ExprResult TheCallResult, // gcc does not enforce these rules for GNU atomics, but we do so for sanity. if (IsAddSub && !ValType->isIntegerType() && !ValType->isPointerType()) { - Diag(DRE->getBeginLoc(), diag::err_atomic_op_needs_atomic_int_or_ptr) + Diag(ExprRange.getBegin(), diag::err_atomic_op_needs_atomic_int_or_ptr) << IsC11 << Ptr->getType() << Ptr->getSourceRange(); return ExprError(); } @@ -4687,12 +4695,12 @@ ExprResult Sema::SemaAtomicOpsOverloaded(ExprResult TheCallResult, const BuiltinType *BT = ValType->getAs(); if (!BT || (BT->getKind() != BuiltinType::Int && BT->getKind() != BuiltinType::UInt)) { - Diag(DRE->getBeginLoc(), diag::err_atomic_op_needs_int32_or_ptr); + Diag(ExprRange.getBegin(), diag::err_atomic_op_needs_int32_or_ptr); return ExprError(); } } if (!IsAddSub && !IsMinMax && !ValType->isIntegerType()) { - Diag(DRE->getBeginLoc(), diag::err_atomic_op_bitwise_needs_atomic_int) + Diag(ExprRange.getBegin(), diag::err_atomic_op_bitwise_needs_atomic_int) << IsC11 << Ptr->getType() << Ptr->getSourceRange(); return ExprError(); } @@ -4704,7 +4712,7 @@ ExprResult Sema::SemaAtomicOpsOverloaded(ExprResult TheCallResult, } else if (IsN && !ValType->isIntegerType() && !ValType->isPointerType()) { // For __atomic_*_n operations, the value type must be a scalar integral or // pointer type which is 1, 2, 4, 8 or 16 bytes in length. - Diag(DRE->getBeginLoc(), diag::err_atomic_op_needs_atomic_int_or_ptr) + Diag(ExprRange.getBegin(), diag::err_atomic_op_needs_atomic_int_or_ptr) << IsC11 << Ptr->getType() << Ptr->getSourceRange(); return ExprError(); } @@ -4713,7 +4721,7 @@ ExprResult Sema::SemaAtomicOpsOverloaded(ExprResult TheCallResult, !AtomTy->isScalarType()) { // For GNU atomics, require a trivially-copyable type. This is not part of // the GNU atomics specification, but we enforce it for sanity. - Diag(DRE->getBeginLoc(), diag::err_atomic_op_needs_trivial_copy) + Diag(ExprRange.getBegin(), diag::err_atomic_op_needs_trivial_copy) << Ptr->getType() << Ptr->getSourceRange(); return ExprError(); } @@ -4729,7 +4737,7 @@ ExprResult Sema::SemaAtomicOpsOverloaded(ExprResult TheCallResult, case Qualifiers::OCL_Autoreleasing: // FIXME: Can this happen? By this point, ValType should be known // to be trivially copyable. - Diag(DRE->getBeginLoc(), diag::err_arc_atomic_ownership) + Diag(ExprRange.getBegin(), diag::err_arc_atomic_ownership) << ValType << Ptr->getSourceRange(); return ExprError(); } @@ -4761,14 +4769,14 @@ ExprResult Sema::SemaAtomicOpsOverloaded(ExprResult TheCallResult, // - weak flag (always converted to bool) // - memory order (always converted to int) // - scope (always converted to int) - for (unsigned i = 0; i != TheCall->getNumArgs(); ++i) { + for (unsigned i = 0; i != Args.size(); ++i) { QualType Ty; if (i < NumVals[Form] + 1) { switch (i) { case 0: // The first argument is always a pointer. It has a fixed type. // It is always dereferenced, a nullptr is undefined. - CheckNonNullArgument(*this, TheCall->getArg(i), DRE->getBeginLoc()); + CheckNonNullArgument(*this, Args[i], ExprRange.getBegin()); // Nothing else to do: we already know all we want about this pointer. continue; case 1: @@ -4782,14 +4790,14 @@ ExprResult Sema::SemaAtomicOpsOverloaded(ExprResult TheCallResult, else if (Form == Copy || Form == Xchg) { if (IsPassedByAddress) // The value pointer is always dereferenced, a nullptr is undefined. - CheckNonNullArgument(*this, TheCall->getArg(i), DRE->getBeginLoc()); + CheckNonNullArgument(*this, Args[i], ExprRange.getBegin()); Ty = ByValType; } else if (Form == Arithmetic) Ty = Context.getPointerDiffType(); else { - Expr *ValArg = TheCall->getArg(i); + Expr *ValArg = Args[i]; // The value pointer is always dereferenced, a nullptr is undefined. - CheckNonNullArgument(*this, ValArg, DRE->getBeginLoc()); + CheckNonNullArgument(*this, ValArg, ExprRange.getBegin()); LangAS AS = LangAS::Default; // Keep address space of non-atomic pointer type. if (const PointerType *PtrTy = @@ -4804,7 +4812,7 @@ ExprResult Sema::SemaAtomicOpsOverloaded(ExprResult TheCallResult, // The third argument to compare_exchange / GNU exchange is the desired // value, either by-value (for the C11 and *_n variant) or as a pointer. if (IsPassedByAddress) - CheckNonNullArgument(*this, TheCall->getArg(i), DRE->getBeginLoc()); + CheckNonNullArgument(*this, Args[i], ExprRange.getBegin()); Ty = ByValType; break; case 3: @@ -4819,11 +4827,11 @@ ExprResult Sema::SemaAtomicOpsOverloaded(ExprResult TheCallResult, InitializedEntity Entity = InitializedEntity::InitializeParameter(Context, Ty, false); - ExprResult Arg = TheCall->getArg(i); + ExprResult Arg = Args[i]; Arg = PerformCopyInitialization(Entity, SourceLocation(), Arg); if (Arg.isInvalid()) return true; - TheCall->setArg(i, Arg.get()); + Args[i] = Arg.get(); } // Permute the arguments into a 'consistent' order. @@ -4832,36 +4840,36 @@ ExprResult Sema::SemaAtomicOpsOverloaded(ExprResult TheCallResult, switch (Form) { case Init: // Note, AtomicExpr::getVal1() has a special case for this atomic. - SubExprs.push_back(TheCall->getArg(1)); // Val1 + SubExprs.push_back(Args[1]); // Val1 break; case Load: - SubExprs.push_back(TheCall->getArg(1)); // Order + SubExprs.push_back(Args[1]); // Order break; case LoadCopy: case Copy: case Arithmetic: case Xchg: - SubExprs.push_back(TheCall->getArg(2)); // Order - SubExprs.push_back(TheCall->getArg(1)); // Val1 + SubExprs.push_back(Args[2]); // Order + SubExprs.push_back(Args[1]); // Val1 break; case GNUXchg: // Note, AtomicExpr::getVal2() has a special case for this atomic. - SubExprs.push_back(TheCall->getArg(3)); // Order - SubExprs.push_back(TheCall->getArg(1)); // Val1 - SubExprs.push_back(TheCall->getArg(2)); // Val2 + SubExprs.push_back(Args[3]); // Order + SubExprs.push_back(Args[1]); // Val1 + SubExprs.push_back(Args[2]); // Val2 break; case C11CmpXchg: - SubExprs.push_back(TheCall->getArg(3)); // Order - SubExprs.push_back(TheCall->getArg(1)); // Val1 - SubExprs.push_back(TheCall->getArg(4)); // OrderFail - SubExprs.push_back(TheCall->getArg(2)); // Val2 + SubExprs.push_back(Args[3]); // Order + SubExprs.push_back(Args[1]); // Val1 + SubExprs.push_back(Args[4]); // OrderFail + SubExprs.push_back(Args[2]); // Val2 break; case GNUCmpXchg: - SubExprs.push_back(TheCall->getArg(4)); // Order - SubExprs.push_back(TheCall->getArg(1)); // Val1 - SubExprs.push_back(TheCall->getArg(5)); // OrderFail - SubExprs.push_back(TheCall->getArg(2)); // Val2 - SubExprs.push_back(TheCall->getArg(3)); // Weak + SubExprs.push_back(Args[4]); // Order + SubExprs.push_back(Args[1]); // Val1 + SubExprs.push_back(Args[5]); // OrderFail + SubExprs.push_back(Args[2]); // Val2 + SubExprs.push_back(Args[3]); // Weak break; } @@ -4875,7 +4883,7 @@ ExprResult Sema::SemaAtomicOpsOverloaded(ExprResult TheCallResult, } if (auto ScopeModel = AtomicExpr::getScopeModel(Op)) { - auto *Scope = TheCall->getArg(TheCall->getNumArgs() - 1); + auto *Scope = Args[Args.size() - 1]; llvm::APSInt Result(32); if (Scope->isIntegerConstantExpr(Result, Context) && !ScopeModel->isValid(Result.getZExtValue())) { @@ -4885,9 +4893,8 @@ ExprResult Sema::SemaAtomicOpsOverloaded(ExprResult TheCallResult, SubExprs.push_back(Scope); } - AtomicExpr *AE = - new (Context) AtomicExpr(TheCall->getCallee()->getBeginLoc(), SubExprs, - ResultType, Op, TheCall->getRParenLoc()); + AtomicExpr *AE = new (Context) + AtomicExpr(ExprRange.getBegin(), SubExprs, ResultType, Op, RParenLoc); if ((Op == AtomicExpr::AO__c11_atomic_load || Op == AtomicExpr::AO__c11_atomic_store || diff --git a/clang/lib/Sema/TreeTransform.h b/clang/lib/Sema/TreeTransform.h index beef7ca840d79..9a436e81ec5c5 100644 --- a/clang/lib/Sema/TreeTransform.h +++ b/clang/lib/Sema/TreeTransform.h @@ -3310,14 +3310,12 @@ class TreeTransform { /// Subclasses may override this routine to provide different behavior. ExprResult RebuildAtomicExpr(SourceLocation BuiltinLoc, MultiExprArg SubExprs, - QualType RetTy, AtomicExpr::AtomicOp Op, SourceLocation RParenLoc) { - // Just create the expression; there is not any interesting semantic - // analysis here because we can't actually build an AtomicExpr until - // we are sure it is semantically sound. - return new (SemaRef.Context) AtomicExpr(BuiltinLoc, SubExprs, RetTy, Op, - RParenLoc); + // Use this for all of the locations, since we don't know the difference + // between the call and the expr at this point. + SourceRange Range{BuiltinLoc, RParenLoc}; + return getSema().BuildAtomicExpr(Range, Range, RParenLoc, SubExprs, Op); } private: @@ -12673,7 +12671,6 @@ TreeTransform::TransformAsTypeExpr(AsTypeExpr *E) { template ExprResult TreeTransform::TransformAtomicExpr(AtomicExpr *E) { - QualType RetTy = getDerived().TransformType(E->getType()); bool ArgumentChanged = false; SmallVector SubExprs; SubExprs.reserve(E->getNumSubExprs()); @@ -12686,7 +12683,7 @@ TreeTransform::TransformAtomicExpr(AtomicExpr *E) { return E; return getDerived().RebuildAtomicExpr(E->getBuiltinLoc(), SubExprs, - RetTy, E->getOp(), E->getRParenLoc()); + E->getOp(), E->getRParenLoc()); } //===----------------------------------------------------------------------===// diff --git a/clang/test/AST/atomic-expr.cpp b/clang/test/AST/atomic-expr.cpp new file mode 100644 index 0000000000000..34b51fabc81b0 --- /dev/null +++ b/clang/test/AST/atomic-expr.cpp @@ -0,0 +1,19 @@ +// RUN: %clang_cc1 -ast-dump %s | FileCheck %s + +template +void pr43370() { + int arr[2]; + __atomic_store_n(arr, 0, 0); +} +void useage(){ + pr43370(); +} + +// CHECK:FunctionTemplateDecl 0x{{[0-9a-f]+}} <{{[^:]+}}:3:1, line:7:1> line:4:6 pr43370 +// CHECK: AtomicExpr +// CHECK-NEXT: ImplicitCastExpr +// CHECK-SAME: +// CHECK:FunctionDecl 0x{{[0-9a-f]+}} line:4:6 used pr43370 +// CHECK: AtomicExpr +// CHECK-NEXT: ImplicitCastExpr +// CHECK-SAME: From 949a126438b9d4949208fec549e2772e3270d7d5 Mon Sep 17 00:00:00 2001 From: Matt Morehouse Date: Fri, 20 Sep 2019 19:39:50 +0000 Subject: [PATCH 28/71] [docs] Update structure-aware-fuzzing link. The document has been moved to the google/fuzzing GitHub repo. llvm-svn: 372423 --- llvm/docs/LibFuzzer.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/llvm/docs/LibFuzzer.rst b/llvm/docs/LibFuzzer.rst index 49f72f63ee3eb..e38489014e69e 100644 --- a/llvm/docs/LibFuzzer.rst +++ b/llvm/docs/LibFuzzer.rst @@ -590,7 +590,7 @@ User-supplied mutators ---------------------- LibFuzzer allows to use custom (user-supplied) mutators, see -`Structure-Aware Fuzzing `_ +`Structure-Aware Fuzzing `_ for more details. Startup initialization From ce7cfbccc63ba318bed00aef65dab49adc6f43c8 Mon Sep 17 00:00:00 2001 From: Jan Kratochvil Date: Fri, 20 Sep 2019 20:19:18 +0000 Subject: [PATCH 29/71] [lldb] Process formatters in reverse-chronological order If one reverts D66398 then the TestDataFormatterStdList does fail - as the C++ formatters are initialized in the opposite order. But the current state of trunk does not mind the order for C++ formatters. It is using now a single std::vector as suggested by Pavel Labath. Differential Revision: https://reviews.llvm.org/D66654 llvm-svn: 372424 --- .../lldb/DataFormatters/FormattersContainer.h | 62 ++++++++----------- lldb/include/lldb/Utility/RegularExpression.h | 4 -- .../TestDataFormatterAdv.py | 7 +++ 3 files changed, 34 insertions(+), 39 deletions(-) diff --git a/lldb/include/lldb/DataFormatters/FormattersContainer.h b/lldb/include/lldb/DataFormatters/FormattersContainer.h index 079102810025d..de2edb103151a 100644 --- a/lldb/include/lldb/DataFormatters/FormattersContainer.h +++ b/lldb/include/lldb/DataFormatters/FormattersContainer.h @@ -65,7 +65,7 @@ template class FormattersContainer; template class FormatMap { public: typedef typename ValueType::SharedPointer ValueSP; - typedef std::map MapType; + typedef std::vector> MapType; typedef typename MapType::iterator MapIterator; typedef std::function ForEachCallback; @@ -79,20 +79,22 @@ template class FormatMap { entry->GetRevision() = 0; std::lock_guard guard(m_map_mutex); - m_map[std::move(name)] = entry; + Delete(name); + m_map.emplace_back(std::move(name), std::move(entry)); if (listener) listener->Changed(); } bool Delete(const KeyType &name) { std::lock_guard guard(m_map_mutex); - MapIterator iter = m_map.find(name); - if (iter == m_map.end()) - return false; - m_map.erase(iter); - if (listener) - listener->Changed(); - return true; + for (MapIterator iter = m_map.begin(); iter != m_map.end(); ++iter) + if (iter->first == name) { + m_map.erase(iter); + if (listener) + listener->Changed(); + return true; + } + return false; } void Clear() { @@ -104,11 +106,12 @@ template class FormatMap { bool Get(const KeyType &name, ValueSP &entry) { std::lock_guard guard(m_map_mutex); - MapIterator iter = m_map.find(name); - if (iter == m_map.end()) - return false; - entry = iter->second; - return true; + for (const auto &pos : m_map) + if (pos.first == name) { + entry = pos.second; + return true; + } + return false; } void ForEach(ForEachCallback callback) { @@ -126,29 +129,17 @@ template class FormatMap { ValueSP GetValueAtIndex(size_t index) { std::lock_guard guard(m_map_mutex); - MapIterator iter = m_map.begin(); - MapIterator end = m_map.end(); - while (index > 0) { - iter++; - index--; - if (end == iter) - return ValueSP(); - } - return iter->second; + if (index >= m_map.size()) + return ValueSP(); + return m_map[index].second; } // If caller holds the mutex we could return a reference without copy ctor. KeyType GetKeyAtIndex(size_t index) { std::lock_guard guard(m_map_mutex); - MapIterator iter = m_map.begin(); - MapIterator end = m_map.end(); - while (index > 0) { - iter++; - index--; - if (end == iter) - return KeyType(); - } - return iter->first; + if (index >= m_map.size()) + return {}; + return m_map[index].first; } protected: @@ -171,8 +162,8 @@ template class FormattersContainer { public: typedef typename BackEndType::MapType MapType; typedef typename MapType::iterator MapIterator; - typedef typename MapType::key_type MapKeyType; - typedef typename MapType::mapped_type MapValueType; + typedef KeyType MapKeyType; + typedef std::shared_ptr MapValueType; typedef typename BackEndType::ForEachCallback ForEachCallback; typedef typename std::shared_ptr> SharedPointer; @@ -294,7 +285,8 @@ template class FormattersContainer { RegularExpression *dummy) { llvm::StringRef key_str = key.GetStringRef(); std::lock_guard guard(m_format_map.mutex()); - for (const auto &pos : m_format_map.map()) { + // Patterns are matched in reverse-chronological order. + for (const auto &pos : llvm::reverse(m_format_map.map())) { const RegularExpression ®ex = pos.first; if (regex.Execute(key_str)) { value = pos.second; diff --git a/lldb/include/lldb/Utility/RegularExpression.h b/lldb/include/lldb/Utility/RegularExpression.h index ee2e2f5dbc398..6acc203d8e7c0 100644 --- a/lldb/include/lldb/Utility/RegularExpression.h +++ b/lldb/include/lldb/Utility/RegularExpression.h @@ -78,10 +78,6 @@ class RegularExpression { /// otherwise. llvm::Error GetError() const; - bool operator<(const RegularExpression &rhs) const { - return GetText() < rhs.GetText(); - } - bool operator==(const RegularExpression &rhs) const { return GetText() == rhs.GetText(); } diff --git a/lldb/packages/Python/lldbsuite/test/functionalities/data-formatter/data-formatter-advanced/TestDataFormatterAdv.py b/lldb/packages/Python/lldbsuite/test/functionalities/data-formatter/data-formatter-advanced/TestDataFormatterAdv.py index 8615fe65dd577..3390da4bf3fd9 100644 --- a/lldb/packages/Python/lldbsuite/test/functionalities/data-formatter/data-formatter-advanced/TestDataFormatterAdv.py +++ b/lldb/packages/Python/lldbsuite/test/functionalities/data-formatter/data-formatter-advanced/TestDataFormatterAdv.py @@ -136,6 +136,13 @@ def cleanup(): self.expect("frame variable int_array", substrs=['1,2']) + # Test the patterns are matched in reverse-chronological order. + self.runCmd( + 'type summary add --summary-string \"${var[2-3]}\" "int []"') + + self.expect("frame variable int_array", + substrs=['3,4']) + self.runCmd("type summary clear") self.runCmd("type summary add -c -x \"i_am_cool \[[0-9]\]\"") From 72a3d8597da5cb50f3a21ba8a2f822117459af34 Mon Sep 17 00:00:00 2001 From: Mitch Phillips Date: Fri, 20 Sep 2019 20:25:16 +0000 Subject: [PATCH 30/71] Revert "[MachinePipeliner] Improve the TargetInstrInfo API analyzeLoop/reduceLoopCount" This commit broke the ASan buildbot. See comments in rL372376 for more information. This reverts commit 15e27b0b6d9d51362fad85dbe95ac5b3fadf0a06. llvm-svn: 372425 --- llvm/include/llvm/CodeGen/ModuloSchedule.h | 2 - llvm/include/llvm/CodeGen/TargetInstrInfo.h | 44 ------ llvm/lib/CodeGen/MachinePipeliner.cpp | 2 +- llvm/lib/CodeGen/ModuloSchedule.cpp | 40 ++--- llvm/lib/CodeGen/TargetInstrInfo.cpp | 2 - llvm/lib/Target/Hexagon/HexagonInstrInfo.cpp | 152 ++++++++++--------- llvm/lib/Target/Hexagon/HexagonInstrInfo.h | 19 ++- llvm/lib/Target/PowerPC/PPCInstrInfo.cpp | 139 +++++++---------- llvm/lib/Target/PowerPC/PPCInstrInfo.h | 28 +++- llvm/test/CodeGen/Hexagon/swp-epilog-phi7.ll | 4 +- 10 files changed, 194 insertions(+), 238 deletions(-) diff --git a/llvm/include/llvm/CodeGen/ModuloSchedule.h b/llvm/include/llvm/CodeGen/ModuloSchedule.h index 36cc843c8849e..530cefd1c81a7 100644 --- a/llvm/include/llvm/CodeGen/ModuloSchedule.h +++ b/llvm/include/llvm/CodeGen/ModuloSchedule.h @@ -62,7 +62,6 @@ #include "llvm/CodeGen/MachineFunction.h" #include "llvm/CodeGen/MachineLoopInfo.h" -#include "llvm/CodeGen/TargetInstrInfo.h" #include "llvm/CodeGen/TargetSubtargetInfo.h" #include @@ -169,7 +168,6 @@ class ModuloScheduleExpander { MachineBasicBlock *BB; MachineBasicBlock *Preheader; MachineBasicBlock *NewKernel = nullptr; - std::unique_ptr LoopInfo; /// Map for each register and the max difference between its uses and def. /// The first element in the pair is the max difference in stages. The diff --git a/llvm/include/llvm/CodeGen/TargetInstrInfo.h b/llvm/include/llvm/CodeGen/TargetInstrInfo.h index f16ec7a0837d9..a01d851f5104f 100644 --- a/llvm/include/llvm/CodeGen/TargetInstrInfo.h +++ b/llvm/include/llvm/CodeGen/TargetInstrInfo.h @@ -662,50 +662,6 @@ class TargetInstrInfo : public MCInstrInfo { BytesAdded); } - /// Object returned by analyzeLoopForPipelining. Allows software pipelining - /// implementations to query attributes of the loop being pipelined and to - /// apply target-specific updates to the loop once pipelining is complete. - class PipelinerLoopInfo { - public: - virtual ~PipelinerLoopInfo(); - /// Return true if the given instruction should not be pipelined and should - /// be ignored. An example could be a loop comparison, or induction variable - /// update with no users being pipelined. - virtual bool shouldIgnoreForPipelining(const MachineInstr *MI) const = 0; - - /// Create a condition to determine if the trip count of the loop is greater - /// than TC. - /// - /// If the trip count is statically known to be greater than TC, return - /// true. If the trip count is statically known to be not greater than TC, - /// return false. Otherwise return nullopt and fill out Cond with the test - /// condition. - virtual Optional - createTripCountGreaterCondition(int TC, MachineBasicBlock &MBB, - SmallVectorImpl &Cond) = 0; - - /// Modify the loop such that the trip count is - /// OriginalTC + TripCountAdjust. - virtual void adjustTripCount(int TripCountAdjust) = 0; - - /// Called when the loop's preheader has been modified to NewPreheader. - virtual void setPreheader(MachineBasicBlock *NewPreheader) = 0; - - /// Called when the loop is being removed. Any instructions in the preheader - /// should be removed. - /// - /// Once this function is called, no other functions on this object are - /// valid; the loop has been removed. - virtual void disposed() = 0; - }; - - /// Analyze loop L, which must be a single-basic-block loop, and if the - /// conditions can be understood enough produce a PipelinerLoopInfo object. - virtual std::unique_ptr - analyzeLoopForPipelining(MachineBasicBlock *LoopBB) const { - return nullptr; - } - /// Analyze the loop code, return true if it cannot be understoo. Upon /// success, this function returns false and returns information about the /// induction variable and compare instruction used at the end. diff --git a/llvm/lib/CodeGen/MachinePipeliner.cpp b/llvm/lib/CodeGen/MachinePipeliner.cpp index b3d97c61fdaf6..fc16ebf66f5d9 100644 --- a/llvm/lib/CodeGen/MachinePipeliner.cpp +++ b/llvm/lib/CodeGen/MachinePipeliner.cpp @@ -326,7 +326,7 @@ bool MachinePipeliner::canPipelineLoop(MachineLoop &L) { LI.LoopInductionVar = nullptr; LI.LoopCompare = nullptr; - if (!TII->analyzeLoopForPipelining(L.getTopBlock())) { + if (TII->analyzeLoop(L, LI.LoopInductionVar, LI.LoopCompare)) { LLVM_DEBUG( dbgs() << "Unable to analyzeLoop, can NOT pipeline current Loop\n"); NumFailLoop++; diff --git a/llvm/lib/CodeGen/ModuloSchedule.cpp b/llvm/lib/CodeGen/ModuloSchedule.cpp index aa5e86e97d1aa..8bea4037f544f 100644 --- a/llvm/lib/CodeGen/ModuloSchedule.cpp +++ b/llvm/lib/CodeGen/ModuloSchedule.cpp @@ -105,9 +105,6 @@ void ModuloScheduleExpander::expand() { } void ModuloScheduleExpander::generatePipelinedLoop() { - LoopInfo = TII->analyzeLoopForPipelining(BB); - assert(LoopInfo && "Must be able to analyze loop!"); - // Create a new basic block for the kernel and add it to the CFG. MachineBasicBlock *KernelBB = MF.CreateMachineBasicBlock(BB->getBasicBlock()); @@ -850,6 +847,10 @@ void ModuloScheduleExpander::addBranches(MachineBasicBlock &PreheaderBB, MBBVectorTy &EpilogBBs, ValueMapTy *VRMap) { assert(PrologBBs.size() == EpilogBBs.size() && "Prolog/Epilog mismatch"); + MachineInstr *IndVar; + MachineInstr *Cmp; + if (TII->analyzeLoop(*Schedule.getLoop(), IndVar, Cmp)) + llvm_unreachable("Must be able to analyze loop!"); MachineBasicBlock *LastPro = KernelBB; MachineBasicBlock *LastEpi = KernelBB; @@ -857,20 +858,32 @@ void ModuloScheduleExpander::addBranches(MachineBasicBlock &PreheaderBB, // to the first prolog and the last epilog blocks. SmallVector PrevInsts; unsigned MaxIter = PrologBBs.size() - 1; + unsigned LC = UINT_MAX; + unsigned LCMin = UINT_MAX; for (unsigned i = 0, j = MaxIter; i <= MaxIter; ++i, --j) { // Add branches to the prolog that go to the corresponding // epilog, and the fall-thru prolog/kernel block. MachineBasicBlock *Prolog = PrologBBs[j]; MachineBasicBlock *Epilog = EpilogBBs[i]; - + // We've executed one iteration, so decrement the loop count and check for + // the loop end. SmallVector Cond; - Optional StaticallyGreater = - LoopInfo->createTripCountGreaterCondition(j + 1, *Prolog, Cond); + // Check if the LOOP0 has already been removed. If so, then there is no need + // to reduce the trip count. + if (LC != 0) + LC = TII->reduceLoopCount(*Prolog, PreheaderBB, IndVar, *Cmp, Cond, + PrevInsts, j, MaxIter); + + // Record the value of the first trip count, which is used to determine if + // branches and blocks can be removed for constant trip counts. + if (LCMin == UINT_MAX) + LCMin = LC; + unsigned numAdded = 0; - if (!StaticallyGreater.hasValue()) { + if (Register::isVirtualRegister(LC)) { Prolog->addSuccessor(Epilog); numAdded = TII->insertBranch(*Prolog, Epilog, LastPro, Cond, DebugLoc()); - } else if (*StaticallyGreater == false) { + } else if (j >= LCMin) { Prolog->addSuccessor(Epilog); Prolog->removeSuccessor(LastPro); LastEpi->removeSuccessor(Epilog); @@ -881,12 +894,10 @@ void ModuloScheduleExpander::addBranches(MachineBasicBlock &PreheaderBB, LastEpi->clear(); LastEpi->eraseFromParent(); } - if (LastPro == KernelBB) { - LoopInfo->disposed(); - NewKernel = nullptr; - } LastPro->clear(); LastPro->eraseFromParent(); + if (LastPro == KernelBB) + NewKernel = nullptr; } else { numAdded = TII->insertBranch(*Prolog, LastPro, nullptr, Cond, DebugLoc()); removePhis(Epilog, Prolog); @@ -898,11 +909,6 @@ void ModuloScheduleExpander::addBranches(MachineBasicBlock &PreheaderBB, I != E && numAdded > 0; ++I, --numAdded) updateInstruction(&*I, false, j, 0, VRMap); } - - if (NewKernel) { - LoopInfo->setPreheader(PrologBBs[MaxIter]); - LoopInfo->adjustTripCount(-(MaxIter + 1)); - } } /// Return true if we can compute the amount the instruction changes diff --git a/llvm/lib/CodeGen/TargetInstrInfo.cpp b/llvm/lib/CodeGen/TargetInstrInfo.cpp index 11872e13e4f7d..0406649345b36 100644 --- a/llvm/lib/CodeGen/TargetInstrInfo.cpp +++ b/llvm/lib/CodeGen/TargetInstrInfo.cpp @@ -1257,5 +1257,3 @@ bool TargetInstrInfo::getInsertSubregInputs( InsertedReg.SubIdx = (unsigned)MOSubIdx.getImm(); return true; } - -TargetInstrInfo::PipelinerLoopInfo::~PipelinerLoopInfo() {} diff --git a/llvm/lib/Target/Hexagon/HexagonInstrInfo.cpp b/llvm/lib/Target/Hexagon/HexagonInstrInfo.cpp index f9d464b0797b8..97318a8057bdd 100644 --- a/llvm/lib/Target/Hexagon/HexagonInstrInfo.cpp +++ b/llvm/lib/Target/Hexagon/HexagonInstrInfo.cpp @@ -674,84 +674,86 @@ unsigned HexagonInstrInfo::insertBranch(MachineBasicBlock &MBB, return 2; } -class HexagonPipelinerLoopInfo : public TargetInstrInfo::PipelinerLoopInfo { - MachineInstr *Loop, *EndLoop; - MachineFunction *MF; - const HexagonInstrInfo *TII; - -public: - HexagonPipelinerLoopInfo(MachineInstr *Loop, MachineInstr *EndLoop) - : Loop(Loop), EndLoop(EndLoop), MF(Loop->getParent()->getParent()), - TII(MF->getSubtarget().getInstrInfo()) {} - - bool shouldIgnoreForPipelining(const MachineInstr *MI) const override { - // Only ignore the terminator. - return MI == EndLoop; - } - - Optional - createTripCountGreaterCondition(int TC, MachineBasicBlock &MBB, - SmallVectorImpl &Cond) override { - if (Loop->getOpcode() == Hexagon::J2_loop0r) { - Register LoopCount = Loop->getOperand(1).getReg(); - // Check if we're done with the loop. - unsigned Done = TII->createVR(MF, MVT::i1); - MachineInstr *NewCmp = BuildMI(&MBB, Loop->getDebugLoc(), - TII->get(Hexagon::C2_cmpgtui), Done) - .addReg(LoopCount) - .addImm(TC); - Cond.push_back(MachineOperand::CreateImm(Hexagon::J2_jumpf)); - Cond.push_back(NewCmp->getOperand(0)); - return {}; - } - - int64_t TripCount = Loop->getOperand(1).getImm(); - return TripCount > TC; - } - - void setPreheader(MachineBasicBlock *NewPreheader) override { - NewPreheader->splice(NewPreheader->getFirstTerminator(), Loop->getParent(), - Loop); - } - - void adjustTripCount(int TripCountAdjust) override { - // If the loop trip count is a compile-time value, then just change the - // value. - if (Loop->getOpcode() == Hexagon::J2_loop0i || - Loop->getOpcode() == Hexagon::J2_loop1i) { - int64_t TripCount = Loop->getOperand(1).getImm() + TripCountAdjust; - assert(TripCount > 0 && "Can't create an empty or negative loop!"); - Loop->getOperand(1).setImm(TripCount); - return; - } - - // The loop trip count is a run-time value. We generate code to subtract - // one from the trip count, and update the loop instruction. - Register LoopCount = Loop->getOperand(1).getReg(); - Register NewLoopCount = TII->createVR(MF, MVT::i32); - BuildMI(*Loop->getParent(), Loop, Loop->getDebugLoc(), - TII->get(Hexagon::A2_addi), NewLoopCount) - .addReg(LoopCount) - .addImm(TripCountAdjust); - Loop->getOperand(1).setReg(NewLoopCount); - } - - void disposed() override { Loop->eraseFromParent(); } -}; - -std::unique_ptr -HexagonInstrInfo::analyzeLoopForPipelining(MachineBasicBlock *LoopBB) const { +/// Analyze the loop code to find the loop induction variable and compare used +/// to compute the number of iterations. Currently, we analyze loop that are +/// controlled using hardware loops. In this case, the induction variable +/// instruction is null. For all other cases, this function returns true, which +/// means we're unable to analyze it. +bool HexagonInstrInfo::analyzeLoop(MachineLoop &L, + MachineInstr *&IndVarInst, + MachineInstr *&CmpInst) const { + + MachineBasicBlock *LoopEnd = L.getBottomBlock(); + MachineBasicBlock::iterator I = LoopEnd->getFirstTerminator(); // We really "analyze" only hardware loops right now. - MachineBasicBlock::iterator I = LoopBB->getFirstTerminator(); + if (I != LoopEnd->end() && isEndLoopN(I->getOpcode())) { + IndVarInst = nullptr; + CmpInst = &*I; + return false; + } + return true; +} - if (I != LoopBB->end() && isEndLoopN(I->getOpcode())) { - SmallPtrSet VisitedBBs; - MachineInstr *LoopInst = findLoopInstr( - LoopBB, I->getOpcode(), I->getOperand(0).getMBB(), VisitedBBs); - if (LoopInst) - return std::make_unique(LoopInst, &*I); +/// Generate code to reduce the loop iteration by one and check if the loop is +/// finished. Return the value/register of the new loop count. this function +/// assumes the nth iteration is peeled first. +unsigned HexagonInstrInfo::reduceLoopCount( + MachineBasicBlock &MBB, MachineBasicBlock &PreHeader, MachineInstr *IndVar, + MachineInstr &Cmp, SmallVectorImpl &Cond, + SmallVectorImpl &PrevInsts, unsigned Iter, + unsigned MaxIter) const { + // We expect a hardware loop currently. This means that IndVar is set + // to null, and the compare is the ENDLOOP instruction. + assert((!IndVar) && isEndLoopN(Cmp.getOpcode()) + && "Expecting a hardware loop"); + MachineFunction *MF = MBB.getParent(); + DebugLoc DL = Cmp.getDebugLoc(); + SmallPtrSet VisitedBBs; + MachineInstr *Loop = findLoopInstr(&MBB, Cmp.getOpcode(), + Cmp.getOperand(0).getMBB(), VisitedBBs); + if (!Loop) + return 0; + // If the loop trip count is a compile-time value, then just change the + // value. + if (Loop->getOpcode() == Hexagon::J2_loop0i || + Loop->getOpcode() == Hexagon::J2_loop1i) { + int64_t Offset = Loop->getOperand(1).getImm(); + if (Offset <= 1) + Loop->eraseFromParent(); + else + Loop->getOperand(1).setImm(Offset - 1); + return Offset - 1; } - return nullptr; + // The loop trip count is a run-time value. We generate code to subtract + // one from the trip count, and update the loop instruction. + assert(Loop->getOpcode() == Hexagon::J2_loop0r && "Unexpected instruction"); + Register LoopCount = Loop->getOperand(1).getReg(); + // Check if we're done with the loop. + unsigned LoopEnd = createVR(MF, MVT::i1); + MachineInstr *NewCmp = BuildMI(&MBB, DL, get(Hexagon::C2_cmpgtui), LoopEnd). + addReg(LoopCount).addImm(1); + unsigned NewLoopCount = createVR(MF, MVT::i32); + MachineInstr *NewAdd = BuildMI(&MBB, DL, get(Hexagon::A2_addi), NewLoopCount). + addReg(LoopCount).addImm(-1); + const HexagonRegisterInfo &HRI = *Subtarget.getRegisterInfo(); + // Update the previously generated instructions with the new loop counter. + for (SmallVectorImpl::iterator I = PrevInsts.begin(), + E = PrevInsts.end(); I != E; ++I) + (*I)->substituteRegister(LoopCount, NewLoopCount, 0, HRI); + PrevInsts.clear(); + PrevInsts.push_back(NewCmp); + PrevInsts.push_back(NewAdd); + // Insert the new loop instruction if this is the last time the loop is + // decremented. + if (Iter == MaxIter) + BuildMI(&MBB, DL, get(Hexagon::J2_loop0r)). + addMBB(Loop->getOperand(0).getMBB()).addReg(NewLoopCount); + // Delete the old loop instruction. + if (Iter == 0) + Loop->eraseFromParent(); + Cond.push_back(MachineOperand::CreateImm(Hexagon::J2_jumpf)); + Cond.push_back(NewCmp->getOperand(0)); + return NewLoopCount; } bool HexagonInstrInfo::isProfitableToIfCvt(MachineBasicBlock &MBB, diff --git a/llvm/lib/Target/Hexagon/HexagonInstrInfo.h b/llvm/lib/Target/Hexagon/HexagonInstrInfo.h index e863400480b62..e0a999d0f4c43 100644 --- a/llvm/lib/Target/Hexagon/HexagonInstrInfo.h +++ b/llvm/lib/Target/Hexagon/HexagonInstrInfo.h @@ -129,10 +129,21 @@ class HexagonInstrInfo : public HexagonGenInstrInfo { const DebugLoc &DL, int *BytesAdded = nullptr) const override; - /// Analyze loop L, which must be a single-basic-block loop, and if the - /// conditions can be understood enough produce a PipelinerLoopInfo object. - std::unique_ptr - analyzeLoopForPipelining(MachineBasicBlock *LoopBB) const override; + /// Analyze the loop code, return true if it cannot be understood. Upon + /// success, this function returns false and returns information about the + /// induction variable and compare instruction used at the end. + bool analyzeLoop(MachineLoop &L, MachineInstr *&IndVarInst, + MachineInstr *&CmpInst) const override; + + /// Generate code to reduce the loop iteration by one and check if the loop + /// is finished. Return the value/register of the new loop count. We need + /// this function when peeling off one or more iterations of a loop. This + /// function assumes the nth iteration is peeled first. + unsigned reduceLoopCount(MachineBasicBlock &MBB, MachineBasicBlock &PreHeader, + MachineInstr *IndVar, MachineInstr &Cmp, + SmallVectorImpl &Cond, + SmallVectorImpl &PrevInsts, + unsigned Iter, unsigned MaxIter) const override; /// Return true if it's profitable to predicate /// instructions with accumulated instruction latency of "NumCycles" diff --git a/llvm/lib/Target/PowerPC/PPCInstrInfo.cpp b/llvm/lib/Target/PowerPC/PPCInstrInfo.cpp index 455fbdfea28f7..e4540d6520efd 100644 --- a/llvm/lib/Target/PowerPC/PPCInstrInfo.cpp +++ b/llvm/lib/Target/PowerPC/PPCInstrInfo.cpp @@ -3930,92 +3930,21 @@ bool PPCInstrInfo::isBDNZ(unsigned Opcode) const { return (Opcode == (Subtarget.isPPC64() ? PPC::BDNZ8 : PPC::BDNZ)); } -class PPCPipelinerLoopInfo : public TargetInstrInfo::PipelinerLoopInfo { - MachineInstr *Loop, *EndLoop, *LoopCount; - MachineFunction *MF; - const TargetInstrInfo *TII; - -public: - PPCPipelinerLoopInfo(MachineInstr *Loop, MachineInstr *EndLoop, - MachineInstr *LoopCount) - : Loop(Loop), EndLoop(EndLoop), LoopCount(LoopCount), - MF(Loop->getParent()->getParent()), - TII(MF->getSubtarget().getInstrInfo()) {} - - bool shouldIgnoreForPipelining(const MachineInstr *MI) const override { - // Only ignore the terminator. - return MI == EndLoop; - } - - Optional - createTripCountGreaterCondition(int TC, MachineBasicBlock &MBB, - SmallVectorImpl &Cond) override { - bool IsConstantTripCount = - LoopCount->getOpcode() == PPC::LI8 || LoopCount->getOpcode() == PPC::LI; - if (!IsConstantTripCount) { - // Since BDZ/BDZ8 that we will insert will also decrease the ctr by 1, - // so we don't need to generate any thing here. - Cond.push_back(MachineOperand::CreateImm(0)); - Cond.push_back(MachineOperand::CreateReg( - MF->getSubtarget().isPPC64() ? PPC::CTR8 : PPC::CTR, - true)); - return {}; - } - - int64_t TripCount = LoopCount->getOperand(1).getImm(); - return TripCount > TC; - } - - void setPreheader(MachineBasicBlock *NewPreheader) override { - // Do nothing. We want the LOOP setup instruction to stay in the *old* - // preheader, so we can use BDZ in the prologs to adapt the loop trip count. - } - - void adjustTripCount(int TripCountAdjust) override { - // If the loop trip count is a compile-time value, then just change the - // value. - if (LoopCount->getOpcode() == PPC::LI8 || - LoopCount->getOpcode() == PPC::LI) { - int64_t TripCount = LoopCount->getOperand(1).getImm() + TripCountAdjust; - LoopCount->getOperand(1).setImm(TripCount); - return; - } - - // Since BDZ/BDZ8 that we will insert will also decrease the ctr by 1, - // so we don't need to generate any thing here. - } - - void disposed() override { - Loop->eraseFromParent(); - // Ensure the loop setup instruction is deleted too. - LoopCount->eraseFromParent(); - } -}; - -std::unique_ptr -PPCInstrInfo::analyzeLoopForPipelining(MachineBasicBlock *LoopBB) const { - // We really "analyze" only hardware loops right now. - MachineBasicBlock::iterator I = LoopBB->getFirstTerminator(); - MachineBasicBlock *Preheader = *LoopBB->pred_begin(); - if (Preheader == LoopBB) - Preheader = *std::next(LoopBB->pred_begin()); - MachineFunction *MF = Preheader->getParent(); - - if (I != LoopBB->end() && isBDNZ(I->getOpcode())) { - SmallPtrSet Visited; - if (MachineInstr *LoopInst = findLoopInstr(*Preheader, Visited)) { - Register LoopCountReg = LoopInst->getOperand(0).getReg(); - MachineRegisterInfo &MRI = MF->getRegInfo(); - MachineInstr *LoopCount = MRI.getUniqueVRegDef(LoopCountReg); - return std::make_unique(LoopInst, &*I, LoopCount); - } +bool PPCInstrInfo::analyzeLoop(MachineLoop &L, MachineInstr *&IndVarInst, + MachineInstr *&CmpInst) const { + MachineBasicBlock *LoopEnd = L.getBottomBlock(); + MachineBasicBlock::iterator I = LoopEnd->getFirstTerminator(); + // We really "analyze" only CTR loops right now. + if (I != LoopEnd->end() && isBDNZ(I->getOpcode())) { + IndVarInst = nullptr; + CmpInst = &*I; + return false; } - return nullptr; + return true; } -MachineInstr *PPCInstrInfo::findLoopInstr( - MachineBasicBlock &PreHeader, - SmallPtrSet &Visited) const { +MachineInstr * +PPCInstrInfo::findLoopInstr(MachineBasicBlock &PreHeader) const { unsigned LOOPi = (Subtarget.isPPC64() ? PPC::MTCTR8loop : PPC::MTCTRloop); @@ -4026,6 +3955,50 @@ MachineInstr *PPCInstrInfo::findLoopInstr( return nullptr; } +unsigned PPCInstrInfo::reduceLoopCount( + MachineBasicBlock &MBB, MachineBasicBlock &PreHeader, MachineInstr *IndVar, + MachineInstr &Cmp, SmallVectorImpl &Cond, + SmallVectorImpl &PrevInsts, unsigned Iter, + unsigned MaxIter) const { + // We expect a hardware loop currently. This means that IndVar is set + // to null, and the compare is the ENDLOOP instruction. + assert((!IndVar) && isBDNZ(Cmp.getOpcode()) && "Expecting a CTR loop"); + MachineFunction *MF = MBB.getParent(); + DebugLoc DL = Cmp.getDebugLoc(); + MachineInstr *Loop = findLoopInstr(PreHeader); + if (!Loop) + return 0; + Register LoopCountReg = Loop->getOperand(0).getReg(); + MachineRegisterInfo &MRI = MF->getRegInfo(); + MachineInstr *LoopCount = MRI.getUniqueVRegDef(LoopCountReg); + + if (!LoopCount) + return 0; + // If the loop trip count is a compile-time value, then just change the + // value. + if (LoopCount->getOpcode() == PPC::LI8 || LoopCount->getOpcode() == PPC::LI) { + int64_t Offset = LoopCount->getOperand(1).getImm(); + if (Offset <= 1) { + LoopCount->eraseFromParent(); + Loop->eraseFromParent(); + return 0; + } + LoopCount->getOperand(1).setImm(Offset - 1); + return Offset - 1; + } + + // The loop trip count is a run-time value. + // We need to subtract one from the trip count, + // and insert branch later to check if we're done with the loop. + + // Since BDZ/BDZ8 that we will insert will also decrease the ctr by 1, + // so we don't need to generate any thing here. + Cond.push_back(MachineOperand::CreateImm(0)); + Cond.push_back(MachineOperand::CreateReg( + Subtarget.isPPC64() ? PPC::CTR8 : PPC::CTR, true)); + return LoopCountReg; +} + // Return true if get the base operand, byte offset of an instruction and the // memory width. Width is the size of memory that is being loaded/stored. bool PPCInstrInfo::getMemOperandWithOffsetWidth( diff --git a/llvm/lib/Target/PowerPC/PPCInstrInfo.h b/llvm/lib/Target/PowerPC/PPCInstrInfo.h index 13eecdff55842..5150650439bc6 100644 --- a/llvm/lib/Target/PowerPC/PPCInstrInfo.h +++ b/llvm/lib/Target/PowerPC/PPCInstrInfo.h @@ -486,14 +486,26 @@ class PPCInstrInfo : public PPCGenInstrInfo { /// On PPC, we have two instructions used to set-up the hardware loop /// (MTCTRloop, MTCTR8loop) with corresponding endloop (BDNZ, BDNZ8) /// instructions to indicate the end of a loop. - MachineInstr * - findLoopInstr(MachineBasicBlock &PreHeader, - SmallPtrSet &Visited) const; - - /// Analyze loop L, which must be a single-basic-block loop, and if the - /// conditions can be understood enough produce a PipelinerLoopInfo object. - std::unique_ptr - analyzeLoopForPipelining(MachineBasicBlock *LoopBB) const override; + MachineInstr *findLoopInstr(MachineBasicBlock &PreHeader) const; + + /// Analyze the loop code to find the loop induction variable and compare used + /// to compute the number of iterations. Currently, we analyze loop that are + /// controlled using hardware loops. In this case, the induction variable + /// instruction is null. For all other cases, this function returns true, + /// which means we're unable to analyze it. \p IndVarInst and \p CmpInst will + /// return new values when we can analyze the readonly loop \p L, otherwise, + /// nothing got changed + bool analyzeLoop(MachineLoop &L, MachineInstr *&IndVarInst, + MachineInstr *&CmpInst) const override; + /// Generate code to reduce the loop iteration by one and check if the loop + /// is finished. Return the value/register of the new loop count. We need + /// this function when peeling off one or more iterations of a loop. This + /// function assumes the last iteration is peeled first. + unsigned reduceLoopCount(MachineBasicBlock &MBB, MachineBasicBlock &PreHeader, + MachineInstr *IndVar, MachineInstr &Cmp, + SmallVectorImpl &Cond, + SmallVectorImpl &PrevInsts, + unsigned Iter, unsigned MaxIter) const override; }; } diff --git a/llvm/test/CodeGen/Hexagon/swp-epilog-phi7.ll b/llvm/test/CodeGen/Hexagon/swp-epilog-phi7.ll index 89a04d9f76ff5..8cad174937df8 100644 --- a/llvm/test/CodeGen/Hexagon/swp-epilog-phi7.ll +++ b/llvm/test/CodeGen/Hexagon/swp-epilog-phi7.ll @@ -7,8 +7,8 @@ ; CHECK: if ({{.*}}) jump ; CHECK: [[VREG:v([0-9]+)]]{{.*}} = {{.*}}vmem(r{{[0-9]+}}++#1) -; CHECK: if ({{.*}}) {{jump|jump:nt|jump:t}} [[EPLOG1:(.*)]] -; CHECK: if ({{.*}}) {{jump|jump:nt|jump:t}} [[EPLOG:(.*)]] +; CHECK: if ({{.*}}) {{jump|jump:nt}} [[EPLOG1:(.*)]] +; CHECK: if ({{.*}}) {{jump|jump:nt}} [[EPLOG:(.*)]] ; CHECK: [[EPLOG]]: ; CHECK: [[VREG1:v([0-9]+)]] = [[VREG]] ; CHECK: [[VREG]] = v{{[0-9]+}} From 216be996d68ec325f1d4341d3af78f078d430d4b Mon Sep 17 00:00:00 2001 From: Jinsong Ji Date: Fri, 20 Sep 2019 20:31:37 +0000 Subject: [PATCH 31/71] [NFC][PowerPC] Consolidate testing of common linkage symbols Add a new file to test the code gen for common linkage symbol. Remove common linkage in some other testcases to avoid distraction. llvm-svn: 372426 --- .../PowerPC/CompareEliminationSpillIssue.ll | 2 +- llvm/test/CodeGen/PowerPC/csr-split.ll | 2 +- .../CodeGen/PowerPC/ctrloop-shortLoops.ll | 14 +++--- llvm/test/CodeGen/PowerPC/elf-common.ll | 45 +++++++++++++++++++ llvm/test/CodeGen/PowerPC/expand-isel.ll | 4 +- llvm/test/CodeGen/PowerPC/f128-aggregates.ll | 2 +- llvm/test/CodeGen/PowerPC/ppc64-P9-mod.ll | 16 +++---- .../PowerPC/ppc64-pre-inc-no-extra-phi.ll | 2 +- llvm/test/CodeGen/PowerPC/pr32140.ll | 8 ++-- llvm/test/CodeGen/PowerPC/pr36068.ll | 2 +- llvm/test/CodeGen/PowerPC/pr39815.ll | 4 +- llvm/test/CodeGen/PowerPC/sms-simple.ll | 2 +- .../test/CodeGen/PowerPC/testComparesieqsc.ll | 2 +- .../test/CodeGen/PowerPC/testComparesieqsi.ll | 2 +- .../CodeGen/PowerPC/testComparesieqsll.ll | 2 +- .../test/CodeGen/PowerPC/testComparesieqss.ll | 2 +- .../test/CodeGen/PowerPC/testComparesiequc.ll | 2 +- .../test/CodeGen/PowerPC/testComparesiequi.ll | 2 +- .../CodeGen/PowerPC/testComparesiequll.ll | 2 +- .../test/CodeGen/PowerPC/testComparesiequs.ll | 2 +- .../test/CodeGen/PowerPC/testComparesigesc.ll | 2 +- .../test/CodeGen/PowerPC/testComparesigesi.ll | 2 +- .../CodeGen/PowerPC/testComparesigesll.ll | 2 +- .../test/CodeGen/PowerPC/testComparesigess.ll | 2 +- .../test/CodeGen/PowerPC/testComparesigeuc.ll | 2 +- .../test/CodeGen/PowerPC/testComparesigeui.ll | 2 +- .../CodeGen/PowerPC/testComparesigeull.ll | 2 +- .../test/CodeGen/PowerPC/testComparesigeus.ll | 2 +- .../test/CodeGen/PowerPC/testComparesigtsc.ll | 2 +- .../test/CodeGen/PowerPC/testComparesigtsi.ll | 2 +- .../CodeGen/PowerPC/testComparesigtsll.ll | 2 +- .../test/CodeGen/PowerPC/testComparesigtss.ll | 2 +- .../test/CodeGen/PowerPC/testComparesigtuc.ll | 2 +- .../test/CodeGen/PowerPC/testComparesigtui.ll | 2 +- .../test/CodeGen/PowerPC/testComparesigtus.ll | 2 +- .../test/CodeGen/PowerPC/testComparesilesc.ll | 2 +- .../test/CodeGen/PowerPC/testComparesilesi.ll | 2 +- .../CodeGen/PowerPC/testComparesilesll.ll | 2 +- .../test/CodeGen/PowerPC/testComparesiless.ll | 2 +- .../test/CodeGen/PowerPC/testComparesileuc.ll | 2 +- .../test/CodeGen/PowerPC/testComparesileui.ll | 2 +- .../CodeGen/PowerPC/testComparesileull.ll | 2 +- .../test/CodeGen/PowerPC/testComparesileus.ll | 2 +- .../test/CodeGen/PowerPC/testComparesiltsc.ll | 2 +- .../test/CodeGen/PowerPC/testComparesiltsi.ll | 2 +- .../CodeGen/PowerPC/testComparesiltsll.ll | 2 +- .../test/CodeGen/PowerPC/testComparesiltss.ll | 2 +- .../test/CodeGen/PowerPC/testComparesiltuc.ll | 2 +- .../test/CodeGen/PowerPC/testComparesiltui.ll | 2 +- .../test/CodeGen/PowerPC/testComparesiltus.ll | 2 +- .../test/CodeGen/PowerPC/testComparesinesc.ll | 2 +- .../test/CodeGen/PowerPC/testComparesinesi.ll | 2 +- .../CodeGen/PowerPC/testComparesinesll.ll | 2 +- .../test/CodeGen/PowerPC/testComparesiness.ll | 2 +- .../test/CodeGen/PowerPC/testComparesineuc.ll | 2 +- .../test/CodeGen/PowerPC/testComparesineui.ll | 2 +- .../CodeGen/PowerPC/testComparesineull.ll | 2 +- .../test/CodeGen/PowerPC/testComparesineus.ll | 2 +- .../CodeGen/PowerPC/testCompareslleqsc.ll | 2 +- .../CodeGen/PowerPC/testCompareslleqsi.ll | 2 +- .../CodeGen/PowerPC/testCompareslleqsll.ll | 2 +- .../CodeGen/PowerPC/testCompareslleqss.ll | 2 +- .../CodeGen/PowerPC/testComparesllequc.ll | 2 +- .../CodeGen/PowerPC/testComparesllequi.ll | 2 +- .../CodeGen/PowerPC/testComparesllequll.ll | 2 +- .../CodeGen/PowerPC/testComparesllequs.ll | 2 +- .../CodeGen/PowerPC/testComparesllgesc.ll | 2 +- .../CodeGen/PowerPC/testComparesllgesi.ll | 2 +- .../CodeGen/PowerPC/testComparesllgesll.ll | 2 +- .../CodeGen/PowerPC/testComparesllgess.ll | 2 +- .../CodeGen/PowerPC/testComparesllgeuc.ll | 2 +- .../CodeGen/PowerPC/testComparesllgeui.ll | 2 +- .../CodeGen/PowerPC/testComparesllgeull.ll | 2 +- .../CodeGen/PowerPC/testComparesllgeus.ll | 2 +- .../CodeGen/PowerPC/testComparesllgtsll.ll | 2 +- .../CodeGen/PowerPC/testComparesllgtuc.ll | 2 +- .../CodeGen/PowerPC/testComparesllgtui.ll | 2 +- .../CodeGen/PowerPC/testComparesllgtus.ll | 2 +- .../CodeGen/PowerPC/testCompareslllesc.ll | 2 +- .../CodeGen/PowerPC/testCompareslllesi.ll | 2 +- .../CodeGen/PowerPC/testCompareslllesll.ll | 2 +- .../CodeGen/PowerPC/testComparesllless.ll | 2 +- .../CodeGen/PowerPC/testComparesllleuc.ll | 2 +- .../CodeGen/PowerPC/testComparesllleui.ll | 2 +- .../CodeGen/PowerPC/testComparesllleull.ll | 2 +- .../CodeGen/PowerPC/testComparesllleus.ll | 2 +- .../CodeGen/PowerPC/testComparesllltsll.ll | 2 +- .../CodeGen/PowerPC/testComparesllltuc.ll | 2 +- .../CodeGen/PowerPC/testComparesllltui.ll | 2 +- .../CodeGen/PowerPC/testComparesllltus.ll | 2 +- .../CodeGen/PowerPC/testComparesllnesll.ll | 2 +- .../CodeGen/PowerPC/testComparesllneull.ll | 2 +- llvm/test/CodeGen/PowerPC/zext-and-cmp.ll | 2 +- 93 files changed, 155 insertions(+), 110 deletions(-) create mode 100644 llvm/test/CodeGen/PowerPC/elf-common.ll diff --git a/llvm/test/CodeGen/PowerPC/CompareEliminationSpillIssue.ll b/llvm/test/CodeGen/PowerPC/CompareEliminationSpillIssue.ll index 75cac9030ef89..10a5e0d4371c8 100644 --- a/llvm/test/CodeGen/PowerPC/CompareEliminationSpillIssue.ll +++ b/llvm/test/CodeGen/PowerPC/CompareEliminationSpillIssue.ll @@ -9,7 +9,7 @@ ; RUN: llc -verify-machineinstrs -mtriple=powerpc64le-unknown-linux-gnu -O2 \ ; RUN: -ppc-gpr-icmps=all -ppc-asm-full-reg-names -mcpu=pwr8 < %s | FileCheck %s \ ; RUN: --implicit-check-not cmpw --implicit-check-not cmpd --implicit-check-not cmpl -@glob = common local_unnamed_addr global i64 0, align 8 +@glob = local_unnamed_addr global i64 0, align 8 @.str = private unnamed_addr constant [12 x i8] c"Value = %d\0A\00", align 1 ; Function Attrs: noinline nounwind diff --git a/llvm/test/CodeGen/PowerPC/csr-split.ll b/llvm/test/CodeGen/PowerPC/csr-split.ll index 4e7db535089ec..cd981a27d2edb 100644 --- a/llvm/test/CodeGen/PowerPC/csr-split.ll +++ b/llvm/test/CodeGen/PowerPC/csr-split.ll @@ -6,7 +6,7 @@ ; Check CSR split can work properly for tests below. -@a = common dso_local local_unnamed_addr global i32 0, align 4 +@a = dso_local local_unnamed_addr global i32 0, align 4 define dso_local signext i32 @test1(i32* %b) local_unnamed_addr { ; CHECK-PWR9-LABEL: test1: diff --git a/llvm/test/CodeGen/PowerPC/ctrloop-shortLoops.ll b/llvm/test/CodeGen/PowerPC/ctrloop-shortLoops.ll index 4f904d6fe09f6..44acfcdd6e66a 100644 --- a/llvm/test/CodeGen/PowerPC/ctrloop-shortLoops.ll +++ b/llvm/test/CodeGen/PowerPC/ctrloop-shortLoops.ll @@ -4,13 +4,13 @@ ; Verify that we do NOT generate the mtctr instruction for loop trip counts < 4 ; The latency of the mtctr is only justified if there are more than 4 comparisons that are removed as a result. -@a = common local_unnamed_addr global i32 0, align 4 -@b = common local_unnamed_addr global i32 0, align 4 -@c = common local_unnamed_addr global i32 0, align 4 -@d = common local_unnamed_addr global i32 0, align 4 -@e = common local_unnamed_addr global i32 0, align 4 -@f = common local_unnamed_addr global i32 0, align 4 -@arr = common local_unnamed_addr global [5 x i32] zeroinitializer, align 4 +@a = local_unnamed_addr global i32 0, align 4 +@b = local_unnamed_addr global i32 0, align 4 +@c = local_unnamed_addr global i32 0, align 4 +@d = local_unnamed_addr global i32 0, align 4 +@e = local_unnamed_addr global i32 0, align 4 +@f = local_unnamed_addr global i32 0, align 4 +@arr = local_unnamed_addr global [5 x i32] zeroinitializer, align 4 ; Function Attrs: norecurse nounwind readonly define signext i32 @testTripCount2(i32 signext %a) { diff --git a/llvm/test/CodeGen/PowerPC/elf-common.ll b/llvm/test/CodeGen/PowerPC/elf-common.ll new file mode 100644 index 0000000000000..cc73d9b58b54a --- /dev/null +++ b/llvm/test/CodeGen/PowerPC/elf-common.ll @@ -0,0 +1,45 @@ +; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py +; RUN: llc -verify-machineinstrs -mtriple=powerpc64le-unknown-linux-gnu -mcpu=pwr8 -O0 < %s \ +; RUN: | FileCheck -check-prefix=NOOPT %s +; RUN: llc -relocation-model=static -verify-machineinstrs -mtriple=powerpc64le-unknown-linux-gnu \ +; RUN: -mcpu=pwr8 < %s | FileCheck -check-prefix=STATIC %s +; RUN: llc -relocation-model=pic -verify-machineinstrs -mtriple=powerpc64le-unknown-linux-gnu \ +; RUN: -mcpu=pwr8 < %s | FileCheck -check-prefix=PIC %s + +; Test correct code generation for static and pic for loading and storing a common symbol + +@comm_glob = common global i32 0, align 4 + +define signext i32 @test_comm() nounwind { +; NOOPT-LABEL: test_comm: +; NOOPT: # %bb.0: # %entry +; NOOPT-NEXT: addis 3, 2, comm_glob@toc@ha +; NOOPT-NEXT: addi 3, 3, comm_glob@toc@l +; NOOPT-NEXT: lwz 4, 0(3) +; NOOPT-NEXT: addi 5, 4, 1 +; NOOPT-NEXT: stw 5, 0(3) +; NOOPT-NEXT: extsw 3, 4 +; NOOPT-NEXT: blr +; +; STATIC-LABEL: test_comm: +; STATIC: # %bb.0: # %entry +; STATIC-NEXT: addis 4, 2, comm_glob@toc@ha +; STATIC-NEXT: lwa 3, comm_glob@toc@l(4) +; STATIC-NEXT: addi 5, 3, 1 +; STATIC-NEXT: stw 5, comm_glob@toc@l(4) +; STATIC-NEXT: blr +; +; PIC-LABEL: test_comm: +; PIC: # %bb.0: # %entry +; PIC-NEXT: addis 3, 2, .LC0@toc@ha +; PIC-NEXT: ld 4, .LC0@toc@l(3) +; PIC-NEXT: lwa 3, 0(4) +; PIC-NEXT: addi 5, 3, 1 +; PIC-NEXT: stw 5, 0(4) +; PIC-NEXT: blr +entry: + %0 = load i32, i32* @comm_glob, align 4 + %inc = add nsw i32 %0, 1 + store i32 %inc, i32* @comm_glob, align 4 + ret i32 %0 +} diff --git a/llvm/test/CodeGen/PowerPC/expand-isel.ll b/llvm/test/CodeGen/PowerPC/expand-isel.ll index d9b571eda47aa..1d1c00e5f5a5a 100644 --- a/llvm/test/CodeGen/PowerPC/expand-isel.ll +++ b/llvm/test/CodeGen/PowerPC/expand-isel.ll @@ -169,8 +169,8 @@ entry: } -@b = common local_unnamed_addr global i32 0, align 4 -@a = common local_unnamed_addr global i32 0, align 4 +@b = local_unnamed_addr global i32 0, align 4 +@a = local_unnamed_addr global i32 0, align 4 ; Function Attrs: norecurse nounwind readonly define signext i32 @testComplexISEL() #0 { entry: diff --git a/llvm/test/CodeGen/PowerPC/f128-aggregates.ll b/llvm/test/CodeGen/PowerPC/f128-aggregates.ll index 30476508dd14c..8c21b85d0ce0a 100644 --- a/llvm/test/CodeGen/PowerPC/f128-aggregates.ll +++ b/llvm/test/CodeGen/PowerPC/f128-aggregates.ll @@ -11,7 +11,7 @@ %struct.With9fp128params = type { fp128, fp128, fp128, fp128, fp128, fp128, fp128, fp128, fp128 } -@a1 = common local_unnamed_addr global [3 x fp128] zeroinitializer, align 16 +@a1 = local_unnamed_addr global [3 x fp128] zeroinitializer, align 16 ; Function Attrs: norecurse nounwind readonly define fp128 @testArray_01(fp128* nocapture readonly %sa) { diff --git a/llvm/test/CodeGen/PowerPC/ppc64-P9-mod.ll b/llvm/test/CodeGen/PowerPC/ppc64-P9-mod.ll index 46e347becbb67..547f9273f5a4f 100644 --- a/llvm/test/CodeGen/PowerPC/ppc64-P9-mod.ll +++ b/llvm/test/CodeGen/PowerPC/ppc64-P9-mod.ll @@ -2,14 +2,14 @@ ; RUN: llc < %s -mtriple=powerpc64-unknown-linux-gnu -mcpu=pwr9 -verify-machineinstrs | FileCheck %s ; RUN: llc < %s -mtriple=powerpc64le-unknown-linux-gnu -mcpu=pwr8 | FileCheck %s -check-prefix=CHECK-PWR8 -implicit-check-not mod[us][wd] -@mod_resultsw = common local_unnamed_addr global i32 0, align 4 -@mod_resultud = common local_unnamed_addr global i64 0, align 8 -@div_resultsw = common local_unnamed_addr global i32 0, align 4 -@mod_resultuw = common local_unnamed_addr global i32 0, align 4 -@div_resultuw = common local_unnamed_addr global i32 0, align 4 -@div_resultsd = common local_unnamed_addr global i64 0, align 8 -@mod_resultsd = common local_unnamed_addr global i64 0, align 8 -@div_resultud = common local_unnamed_addr global i64 0, align 8 +@mod_resultsw = local_unnamed_addr global i32 0, align 4 +@mod_resultud = local_unnamed_addr global i64 0, align 8 +@div_resultsw = local_unnamed_addr global i32 0, align 4 +@mod_resultuw = local_unnamed_addr global i32 0, align 4 +@div_resultuw = local_unnamed_addr global i32 0, align 4 +@div_resultsd = local_unnamed_addr global i64 0, align 8 +@mod_resultsd = local_unnamed_addr global i64 0, align 8 +@div_resultud = local_unnamed_addr global i64 0, align 8 ; Function Attrs: norecurse nounwind define void @modulo_sw(i32 signext %a, i32 signext %b) local_unnamed_addr { diff --git a/llvm/test/CodeGen/PowerPC/ppc64-pre-inc-no-extra-phi.ll b/llvm/test/CodeGen/PowerPC/ppc64-pre-inc-no-extra-phi.ll index 032bad6f63d67..ab84707ce46ef 100644 --- a/llvm/test/CodeGen/PowerPC/ppc64-pre-inc-no-extra-phi.ll +++ b/llvm/test/CodeGen/PowerPC/ppc64-pre-inc-no-extra-phi.ll @@ -3,7 +3,7 @@ ; RUN: llc < %s -mtriple=powerpc64le-unknown-linux-gnu -mcpu=pwr8 -verify-machineinstrs | FileCheck %s ; RUN: llc < %s -mtriple=powerpc64-unknown-linux-gnu -mcpu=pwr8 -verify-machineinstrs | FileCheck %s -@perm = common local_unnamed_addr global [100 x i64] zeroinitializer, align 8 +@perm = local_unnamed_addr global [100 x i64] zeroinitializer, align 8 define void @sort_basket() local_unnamed_addr { entry: diff --git a/llvm/test/CodeGen/PowerPC/pr32140.ll b/llvm/test/CodeGen/PowerPC/pr32140.ll index ddcf27232398e..1a0054b0fd778 100644 --- a/llvm/test/CodeGen/PowerPC/pr32140.ll +++ b/llvm/test/CodeGen/PowerPC/pr32140.ll @@ -2,10 +2,10 @@ ; RUN: llc -mtriple=powerpc64le-linux-gnu -mcpu=pwr8 < %s | FileCheck %s --check-prefix CHECK-LE ; RUN: llc -mtriple=powerpc64-linux-gnu -mcpu=pwr8 < %s | FileCheck %s --check-prefix CHECK-BE -@as = common local_unnamed_addr global i16 0, align 2 -@bs = common local_unnamed_addr global i16 0, align 2 -@ai = common local_unnamed_addr global i32 0, align 4 -@bi = common local_unnamed_addr global i32 0, align 4 +@as = local_unnamed_addr global i16 0, align 2 +@bs = local_unnamed_addr global i16 0, align 2 +@ai = local_unnamed_addr global i32 0, align 4 +@bi = local_unnamed_addr global i32 0, align 4 define void @bswapStorei64Toi32() { ; CHECK-LABEL: bswapStorei64Toi32: diff --git a/llvm/test/CodeGen/PowerPC/pr36068.ll b/llvm/test/CodeGen/PowerPC/pr36068.ll index aac659bfb7093..ee56d020e3cc4 100644 --- a/llvm/test/CodeGen/PowerPC/pr36068.ll +++ b/llvm/test/CodeGen/PowerPC/pr36068.ll @@ -1,7 +1,7 @@ ; RUN: llc -verify-machineinstrs -mtriple=powerpc64le-unknown-unknown < %s | \ ; RUN: FileCheck %s -@glob = common local_unnamed_addr global <4 x float> zeroinitializer, align 4 +@glob = local_unnamed_addr global <4 x float> zeroinitializer, align 4 ; Function Attrs: norecurse nounwind define void @test(float %a, <4 x float>* nocapture readonly %b) { diff --git a/llvm/test/CodeGen/PowerPC/pr39815.ll b/llvm/test/CodeGen/PowerPC/pr39815.ll index 062e055167c42..badba31319544 100644 --- a/llvm/test/CodeGen/PowerPC/pr39815.ll +++ b/llvm/test/CodeGen/PowerPC/pr39815.ll @@ -1,8 +1,8 @@ ; RUN: llc -mcpu=pwr9 -mtriple=powerpc64le-unknown-linux-gnu < %s \ ; RUN: -verify-machineinstrs | FileCheck %s -@b = common dso_local local_unnamed_addr global i64* null, align 8 -@a = common dso_local local_unnamed_addr global i8 0, align 1 +@b = dso_local local_unnamed_addr global i64* null, align 8 +@a = dso_local local_unnamed_addr global i8 0, align 1 define void @testADDEPromoteResult() { entry: diff --git a/llvm/test/CodeGen/PowerPC/sms-simple.ll b/llvm/test/CodeGen/PowerPC/sms-simple.ll index 6b1f0e453e8f2..c4d6270ba99a2 100644 --- a/llvm/test/CodeGen/PowerPC/sms-simple.ll +++ b/llvm/test/CodeGen/PowerPC/sms-simple.ll @@ -4,7 +4,7 @@ ; RUN: | FileCheck %s @x = dso_local local_unnamed_addr global <{ i32, i32, i32, i32, [1020 x i32] }> <{ i32 1, i32 2, i32 3, i32 4, [1020 x i32] zeroinitializer }>, align 4 -@y = common dso_local global [1024 x i32] zeroinitializer, align 4 +@y = dso_local global [1024 x i32] zeroinitializer, align 4 ; Function Attrs: norecurse nounwind define dso_local i32* @foo() local_unnamed_addr #0 { diff --git a/llvm/test/CodeGen/PowerPC/testComparesieqsc.ll b/llvm/test/CodeGen/PowerPC/testComparesieqsc.ll index 893b374d8521e..8b5cade8f8ca0 100644 --- a/llvm/test/CodeGen/PowerPC/testComparesieqsc.ll +++ b/llvm/test/CodeGen/PowerPC/testComparesieqsc.ll @@ -7,7 +7,7 @@ ; RUN: --implicit-check-not cmpw --implicit-check-not cmpd --implicit-check-not cmpl ; ModuleID = 'ComparisonTestCases/testComparesieqsc.c' -@glob = common local_unnamed_addr global i8 0, align 1 +@glob = local_unnamed_addr global i8 0, align 1 ; Function Attrs: norecurse nounwind readnone define signext i32 @test_ieqsc(i8 signext %a, i8 signext %b) { diff --git a/llvm/test/CodeGen/PowerPC/testComparesieqsi.ll b/llvm/test/CodeGen/PowerPC/testComparesieqsi.ll index d75485fcb6ff9..d405741726b20 100644 --- a/llvm/test/CodeGen/PowerPC/testComparesieqsi.ll +++ b/llvm/test/CodeGen/PowerPC/testComparesieqsi.ll @@ -7,7 +7,7 @@ ; RUN: --implicit-check-not cmpw --implicit-check-not cmpd --implicit-check-not cmpl ; ModuleID = 'ComparisonTestCases/testComparesieqsi.c' -@glob = common local_unnamed_addr global i32 0, align 4 +@glob = local_unnamed_addr global i32 0, align 4 ; Function Attrs: norecurse nounwind readnone define signext i32 @test_ieqsi(i32 signext %a, i32 signext %b) { diff --git a/llvm/test/CodeGen/PowerPC/testComparesieqsll.ll b/llvm/test/CodeGen/PowerPC/testComparesieqsll.ll index f5627ff766dcc..9d6e0b6784d05 100644 --- a/llvm/test/CodeGen/PowerPC/testComparesieqsll.ll +++ b/llvm/test/CodeGen/PowerPC/testComparesieqsll.ll @@ -7,7 +7,7 @@ ; RUN: --implicit-check-not cmpw --implicit-check-not cmpd --implicit-check-not cmpl ; ModuleID = 'ComparisonTestCases/testComparesieqsll.c' -@glob = common local_unnamed_addr global i64 0, align 8 +@glob = local_unnamed_addr global i64 0, align 8 ; Function Attrs: norecurse nounwind readnone define signext i32 @test_ieqsll(i64 %a, i64 %b) { diff --git a/llvm/test/CodeGen/PowerPC/testComparesieqss.ll b/llvm/test/CodeGen/PowerPC/testComparesieqss.ll index 2a5ee0c0f9d28..9acfcc4405a70 100644 --- a/llvm/test/CodeGen/PowerPC/testComparesieqss.ll +++ b/llvm/test/CodeGen/PowerPC/testComparesieqss.ll @@ -7,7 +7,7 @@ ; RUN: --implicit-check-not cmpw --implicit-check-not cmpd --implicit-check-not cmpl ; ModuleID = 'ComparisonTestCases/testComparesieqss.c' -@glob = common local_unnamed_addr global i16 0, align 2 +@glob = local_unnamed_addr global i16 0, align 2 ; Function Attrs: norecurse nounwind readnone define signext i32 @test_ieqss(i16 signext %a, i16 signext %b) { diff --git a/llvm/test/CodeGen/PowerPC/testComparesiequc.ll b/llvm/test/CodeGen/PowerPC/testComparesiequc.ll index 18243d36619ef..7f938dff8612b 100644 --- a/llvm/test/CodeGen/PowerPC/testComparesiequc.ll +++ b/llvm/test/CodeGen/PowerPC/testComparesiequc.ll @@ -7,7 +7,7 @@ ; RUN: --implicit-check-not cmpw --implicit-check-not cmpd --implicit-check-not cmpl ; ModuleID = 'ComparisonTestCases/testComparesiequc.c' -@glob = common local_unnamed_addr global i8 0, align 1 +@glob = local_unnamed_addr global i8 0, align 1 ; Function Attrs: norecurse nounwind readnone define signext i32 @test_iequc(i8 zeroext %a, i8 zeroext %b) { diff --git a/llvm/test/CodeGen/PowerPC/testComparesiequi.ll b/llvm/test/CodeGen/PowerPC/testComparesiequi.ll index afa447525efb3..b40e3af36caf5 100644 --- a/llvm/test/CodeGen/PowerPC/testComparesiequi.ll +++ b/llvm/test/CodeGen/PowerPC/testComparesiequi.ll @@ -7,7 +7,7 @@ ; RUN: --implicit-check-not cmpw --implicit-check-not cmpd --implicit-check-not cmpl ; ModuleID = 'ComparisonTestCases/testComparesiequi.c' -@glob = common local_unnamed_addr global i32 0, align 4 +@glob = local_unnamed_addr global i32 0, align 4 ; Function Attrs: norecurse nounwind readnone define signext i32 @test_iequi(i32 zeroext %a, i32 zeroext %b) { diff --git a/llvm/test/CodeGen/PowerPC/testComparesiequll.ll b/llvm/test/CodeGen/PowerPC/testComparesiequll.ll index 16399715386c9..6ef9db9bdc886 100644 --- a/llvm/test/CodeGen/PowerPC/testComparesiequll.ll +++ b/llvm/test/CodeGen/PowerPC/testComparesiequll.ll @@ -7,7 +7,7 @@ ; RUN: --implicit-check-not cmpw --implicit-check-not cmpd --implicit-check-not cmpl ; ModuleID = 'ComparisonTestCases/testComparesiequll.c' -@glob = common local_unnamed_addr global i64 0, align 8 +@glob = local_unnamed_addr global i64 0, align 8 ; Function Attrs: norecurse nounwind readnone define signext i32 @test_iequll(i64 %a, i64 %b) { diff --git a/llvm/test/CodeGen/PowerPC/testComparesiequs.ll b/llvm/test/CodeGen/PowerPC/testComparesiequs.ll index 99b388313e121..90bcee8d70c44 100644 --- a/llvm/test/CodeGen/PowerPC/testComparesiequs.ll +++ b/llvm/test/CodeGen/PowerPC/testComparesiequs.ll @@ -7,7 +7,7 @@ ; RUN: --implicit-check-not cmpw --implicit-check-not cmpd --implicit-check-not cmpl ; ModuleID = 'ComparisonTestCases/testComparesiequs.c' -@glob = common local_unnamed_addr global i16 0, align 2 +@glob = local_unnamed_addr global i16 0, align 2 ; Function Attrs: norecurse nounwind readnone define signext i32 @test_iequs(i16 zeroext %a, i16 zeroext %b) { diff --git a/llvm/test/CodeGen/PowerPC/testComparesigesc.ll b/llvm/test/CodeGen/PowerPC/testComparesigesc.ll index eb457951fb784..d9a397cf023bb 100644 --- a/llvm/test/CodeGen/PowerPC/testComparesigesc.ll +++ b/llvm/test/CodeGen/PowerPC/testComparesigesc.ll @@ -5,7 +5,7 @@ ; RUN: llc -verify-machineinstrs -mtriple=powerpc64le-unknown-linux-gnu -O2 \ ; RUN: -ppc-gpr-icmps=all -ppc-asm-full-reg-names -mcpu=pwr8 < %s | FileCheck %s --check-prefix=CHECK-LE \ ; RUN: --implicit-check-not cmpw --implicit-check-not cmpd --implicit-check-not cmpl -@glob = common local_unnamed_addr global i8 0, align 1 +@glob = local_unnamed_addr global i8 0, align 1 define signext i32 @test_igesc(i8 signext %a, i8 signext %b) { ; CHECK-LABEL: test_igesc: diff --git a/llvm/test/CodeGen/PowerPC/testComparesigesi.ll b/llvm/test/CodeGen/PowerPC/testComparesigesi.ll index 93e6c1e1f9cf6..bff6cb2435115 100644 --- a/llvm/test/CodeGen/PowerPC/testComparesigesi.ll +++ b/llvm/test/CodeGen/PowerPC/testComparesigesi.ll @@ -5,7 +5,7 @@ ; RUN: llc -verify-machineinstrs -mtriple=powerpc64le-unknown-linux-gnu -O2 \ ; RUN: -ppc-gpr-icmps=all -ppc-asm-full-reg-names -mcpu=pwr8 < %s | FileCheck %s --check-prefix=CHECK-LE \ ; RUN: --implicit-check-not cmpw --implicit-check-not cmpd --implicit-check-not cmpl -@glob = common local_unnamed_addr global i32 0, align 4 +@glob = local_unnamed_addr global i32 0, align 4 define signext i32 @test_igesi(i32 signext %a, i32 signext %b) { ; CHECK-LABEL: test_igesi: diff --git a/llvm/test/CodeGen/PowerPC/testComparesigesll.ll b/llvm/test/CodeGen/PowerPC/testComparesigesll.ll index 0f0d792edcf4a..541ee87da1ff7 100644 --- a/llvm/test/CodeGen/PowerPC/testComparesigesll.ll +++ b/llvm/test/CodeGen/PowerPC/testComparesigesll.ll @@ -5,7 +5,7 @@ ; RUN: llc -verify-machineinstrs -mtriple=powerpc64le-unknown-linux-gnu -O2 \ ; RUN: -ppc-gpr-icmps=all -ppc-asm-full-reg-names -mcpu=pwr8 < %s | FileCheck %s --check-prefix=CHECK-LE \ ; RUN: --implicit-check-not cmpw --implicit-check-not cmpd --implicit-check-not cmpl -@glob = common local_unnamed_addr global i64 0, align 8 +@glob = local_unnamed_addr global i64 0, align 8 define signext i32 @test_igesll(i64 %a, i64 %b) { ; CHECK-LABEL: test_igesll: diff --git a/llvm/test/CodeGen/PowerPC/testComparesigess.ll b/llvm/test/CodeGen/PowerPC/testComparesigess.ll index ac04e9e86a2e4..c0e1ab8ec214a 100644 --- a/llvm/test/CodeGen/PowerPC/testComparesigess.ll +++ b/llvm/test/CodeGen/PowerPC/testComparesigess.ll @@ -5,7 +5,7 @@ ; RUN: llc -verify-machineinstrs -mtriple=powerpc64le-unknown-linux-gnu -O2 \ ; RUN: -ppc-gpr-icmps=all -ppc-asm-full-reg-names -mcpu=pwr8 < %s | FileCheck %s --check-prefix=CHECK-LE \ ; RUN: --implicit-check-not cmpw --implicit-check-not cmpd --implicit-check-not cmpl -@glob = common local_unnamed_addr global i16 0, align 2 +@glob = local_unnamed_addr global i16 0, align 2 define signext i32 @test_igess(i16 signext %a, i16 signext %b) { ; CHECK-LABEL: test_igess: diff --git a/llvm/test/CodeGen/PowerPC/testComparesigeuc.ll b/llvm/test/CodeGen/PowerPC/testComparesigeuc.ll index 5047f0fbee159..3b9314bf6fdf1 100644 --- a/llvm/test/CodeGen/PowerPC/testComparesigeuc.ll +++ b/llvm/test/CodeGen/PowerPC/testComparesigeuc.ll @@ -8,7 +8,7 @@ ; RUN: --implicit-check-not cmpw --implicit-check-not cmpd --implicit-check-not cmpl \ ; RUN: --check-prefixes=CHECK,LE -@glob = common local_unnamed_addr global i8 0, align 1 +@glob = local_unnamed_addr global i8 0, align 1 ; Function Attrs: norecurse nounwind readnone define signext i32 @test_igeuc(i8 zeroext %a, i8 zeroext %b) { diff --git a/llvm/test/CodeGen/PowerPC/testComparesigeui.ll b/llvm/test/CodeGen/PowerPC/testComparesigeui.ll index 48a0677a44a8c..13d99c4355bbd 100644 --- a/llvm/test/CodeGen/PowerPC/testComparesigeui.ll +++ b/llvm/test/CodeGen/PowerPC/testComparesigeui.ll @@ -8,7 +8,7 @@ ; RUN: --implicit-check-not cmpw --implicit-check-not cmpd --implicit-check-not cmpl \ ; RUN: --check-prefixes=CHECK,LE -@glob = common local_unnamed_addr global i32 0, align 4 +@glob = local_unnamed_addr global i32 0, align 4 ; Function Attrs: norecurse nounwind readnone define signext i32 @test_igeui(i32 zeroext %a, i32 zeroext %b) { diff --git a/llvm/test/CodeGen/PowerPC/testComparesigeull.ll b/llvm/test/CodeGen/PowerPC/testComparesigeull.ll index 53f0e2ac47d1b..4d430db0b68b6 100644 --- a/llvm/test/CodeGen/PowerPC/testComparesigeull.ll +++ b/llvm/test/CodeGen/PowerPC/testComparesigeull.ll @@ -8,7 +8,7 @@ ; RUN: --implicit-check-not cmpw --implicit-check-not cmpd --implicit-check-not cmpl \ ; RUN: --check-prefixes=CHECK,LE -@glob = common local_unnamed_addr global i64 0, align 8 +@glob = local_unnamed_addr global i64 0, align 8 ; Function Attrs: norecurse nounwind readnone define signext i32 @test_igeull(i64 %a, i64 %b) { diff --git a/llvm/test/CodeGen/PowerPC/testComparesigeus.ll b/llvm/test/CodeGen/PowerPC/testComparesigeus.ll index ede0e42bcbf38..3e5063dc3fc3b 100644 --- a/llvm/test/CodeGen/PowerPC/testComparesigeus.ll +++ b/llvm/test/CodeGen/PowerPC/testComparesigeus.ll @@ -8,7 +8,7 @@ ; RUN: --implicit-check-not cmpw --implicit-check-not cmpd --implicit-check-not cmpl \ ; RUN: --check-prefixes=CHECK,LE -@glob = common local_unnamed_addr global i16 0, align 2 +@glob = local_unnamed_addr global i16 0, align 2 ; Function Attrs: norecurse nounwind readnone define signext i32 @test_igeus(i16 zeroext %a, i16 zeroext %b) { diff --git a/llvm/test/CodeGen/PowerPC/testComparesigtsc.ll b/llvm/test/CodeGen/PowerPC/testComparesigtsc.ll index 9ae7e5d0a9096..19a0a1d96d0b2 100644 --- a/llvm/test/CodeGen/PowerPC/testComparesigtsc.ll +++ b/llvm/test/CodeGen/PowerPC/testComparesigtsc.ll @@ -6,7 +6,7 @@ ; RUN: -ppc-gpr-icmps=all -ppc-asm-full-reg-names -mcpu=pwr8 < %s | FileCheck %s \ ; RUN: --implicit-check-not cmpw --implicit-check-not cmpd --implicit-check-not cmpl -@glob = common local_unnamed_addr global i8 0, align 1 +@glob = local_unnamed_addr global i8 0, align 1 ; Function Attrs: norecurse nounwind readnone define signext i32 @test_igtsc(i8 signext %a, i8 signext %b) { diff --git a/llvm/test/CodeGen/PowerPC/testComparesigtsi.ll b/llvm/test/CodeGen/PowerPC/testComparesigtsi.ll index ecdc2f7b4746d..21a773f1fd804 100644 --- a/llvm/test/CodeGen/PowerPC/testComparesigtsi.ll +++ b/llvm/test/CodeGen/PowerPC/testComparesigtsi.ll @@ -6,7 +6,7 @@ ; RUN: -ppc-gpr-icmps=all -ppc-asm-full-reg-names -mcpu=pwr8 < %s | FileCheck %s \ ; RUN: --implicit-check-not cmpw --implicit-check-not cmpd --implicit-check-not cmpl -@glob = common local_unnamed_addr global i32 0, align 4 +@glob = local_unnamed_addr global i32 0, align 4 ; Function Attrs: norecurse nounwind readnone define signext i32 @test_igtsi(i32 signext %a, i32 signext %b) { diff --git a/llvm/test/CodeGen/PowerPC/testComparesigtsll.ll b/llvm/test/CodeGen/PowerPC/testComparesigtsll.ll index d1f89d9aef1aa..f96a285142a33 100644 --- a/llvm/test/CodeGen/PowerPC/testComparesigtsll.ll +++ b/llvm/test/CodeGen/PowerPC/testComparesigtsll.ll @@ -6,7 +6,7 @@ ; RUN: -ppc-gpr-icmps=all -ppc-asm-full-reg-names -mcpu=pwr8 < %s | FileCheck %s \ ; RUN: --implicit-check-not cmpw --implicit-check-not cmpd --implicit-check-not cmpl -@glob = common local_unnamed_addr global i64 0, align 8 +@glob = local_unnamed_addr global i64 0, align 8 ; Function Attrs: norecurse nounwind readnone define signext i32 @test_igtsll(i64 %a, i64 %b) { diff --git a/llvm/test/CodeGen/PowerPC/testComparesigtss.ll b/llvm/test/CodeGen/PowerPC/testComparesigtss.ll index f6fa43a530498..fe951271986b1 100644 --- a/llvm/test/CodeGen/PowerPC/testComparesigtss.ll +++ b/llvm/test/CodeGen/PowerPC/testComparesigtss.ll @@ -6,7 +6,7 @@ ; RUN: -ppc-gpr-icmps=all -ppc-asm-full-reg-names -mcpu=pwr8 < %s | FileCheck %s \ ; RUN: --implicit-check-not cmpw --implicit-check-not cmpd --implicit-check-not cmpl -@glob = common local_unnamed_addr global i16 0, align 2 +@glob = local_unnamed_addr global i16 0, align 2 ; Function Attrs: norecurse nounwind readnone define signext i32 @test_igtss(i16 signext %a, i16 signext %b) { diff --git a/llvm/test/CodeGen/PowerPC/testComparesigtuc.ll b/llvm/test/CodeGen/PowerPC/testComparesigtuc.ll index 51a29746c0f5d..2aca2dd2b0dff 100644 --- a/llvm/test/CodeGen/PowerPC/testComparesigtuc.ll +++ b/llvm/test/CodeGen/PowerPC/testComparesigtuc.ll @@ -6,7 +6,7 @@ ; RUN: -ppc-gpr-icmps=all -ppc-asm-full-reg-names -mcpu=pwr8 < %s | FileCheck %s \ ; RUN: --implicit-check-not cmpw --implicit-check-not cmpd --implicit-check-not cmpl -@glob = common local_unnamed_addr global i8 0, align 1 +@glob = local_unnamed_addr global i8 0, align 1 ; Function Attrs: norecurse nounwind readnone define signext i32 @test_igtuc(i8 zeroext %a, i8 zeroext %b) { diff --git a/llvm/test/CodeGen/PowerPC/testComparesigtui.ll b/llvm/test/CodeGen/PowerPC/testComparesigtui.ll index db80bef1569ba..aa1c2edc5754b 100644 --- a/llvm/test/CodeGen/PowerPC/testComparesigtui.ll +++ b/llvm/test/CodeGen/PowerPC/testComparesigtui.ll @@ -6,7 +6,7 @@ ; RUN: -ppc-gpr-icmps=all -ppc-asm-full-reg-names -mcpu=pwr8 < %s | FileCheck %s \ ; RUN: --implicit-check-not cmpw --implicit-check-not cmpd --implicit-check-not cmpl -@glob = common local_unnamed_addr global i32 0, align 4 +@glob = local_unnamed_addr global i32 0, align 4 ; Function Attrs: norecurse nounwind readnone define signext i32 @test_igtui(i32 zeroext %a, i32 zeroext %b) { diff --git a/llvm/test/CodeGen/PowerPC/testComparesigtus.ll b/llvm/test/CodeGen/PowerPC/testComparesigtus.ll index ffcd468ab0d42..877753c1a477e 100644 --- a/llvm/test/CodeGen/PowerPC/testComparesigtus.ll +++ b/llvm/test/CodeGen/PowerPC/testComparesigtus.ll @@ -6,7 +6,7 @@ ; RUN: -ppc-gpr-icmps=all -ppc-asm-full-reg-names -mcpu=pwr8 < %s | FileCheck %s \ ; RUN: --implicit-check-not cmpw --implicit-check-not cmpd --implicit-check-not cmpl -@glob = common local_unnamed_addr global i16 0, align 2 +@glob = local_unnamed_addr global i16 0, align 2 ; Function Attrs: norecurse nounwind readnone define signext i32 @test_igtus(i16 zeroext %a, i16 zeroext %b) { diff --git a/llvm/test/CodeGen/PowerPC/testComparesilesc.ll b/llvm/test/CodeGen/PowerPC/testComparesilesc.ll index 94118d642eda7..bd5a16fb5a807 100644 --- a/llvm/test/CodeGen/PowerPC/testComparesilesc.ll +++ b/llvm/test/CodeGen/PowerPC/testComparesilesc.ll @@ -5,7 +5,7 @@ ; RUN: llc -verify-machineinstrs -mtriple=powerpc64le-unknown-linux-gnu -O2 \ ; RUN: -ppc-gpr-icmps=all -ppc-asm-full-reg-names -mcpu=pwr8 < %s | FileCheck %s --check-prefix=CHECK-LE \ ; RUN: --implicit-check-not cmpw --implicit-check-not cmpd --implicit-check-not cmpl -@glob = common local_unnamed_addr global i8 0, align 1 +@glob = local_unnamed_addr global i8 0, align 1 define signext i32 @test_ilesc(i8 signext %a, i8 signext %b) { ; CHECK-LABEL: test_ilesc: diff --git a/llvm/test/CodeGen/PowerPC/testComparesilesi.ll b/llvm/test/CodeGen/PowerPC/testComparesilesi.ll index a5f2f84a5a695..8717e237eb0a0 100644 --- a/llvm/test/CodeGen/PowerPC/testComparesilesi.ll +++ b/llvm/test/CodeGen/PowerPC/testComparesilesi.ll @@ -5,7 +5,7 @@ ; RUN: llc -verify-machineinstrs -mtriple=powerpc64le-unknown-linux-gnu -O2 \ ; RUN: -ppc-gpr-icmps=all -ppc-asm-full-reg-names -mcpu=pwr8 < %s | FileCheck %s --check-prefix=CHECK-LE \ ; RUN: --implicit-check-not cmpw --implicit-check-not cmpd --implicit-check-not cmpl -@glob = common local_unnamed_addr global i32 0, align 4 +@glob = local_unnamed_addr global i32 0, align 4 define signext i32 @test_ilesi(i32 signext %a, i32 signext %b) { ; CHECK-LABEL: test_ilesi: diff --git a/llvm/test/CodeGen/PowerPC/testComparesilesll.ll b/llvm/test/CodeGen/PowerPC/testComparesilesll.ll index 532df4c3cdbc3..b1827661a935f 100644 --- a/llvm/test/CodeGen/PowerPC/testComparesilesll.ll +++ b/llvm/test/CodeGen/PowerPC/testComparesilesll.ll @@ -5,7 +5,7 @@ ; RUN: llc -verify-machineinstrs -mtriple=powerpc64le-unknown-linux-gnu -O2 \ ; RUN: -ppc-gpr-icmps=all -ppc-asm-full-reg-names -mcpu=pwr8 < %s | FileCheck %s --check-prefix=CHECK-LE \ ; RUN: --implicit-check-not cmpw --implicit-check-not cmpd --implicit-check-not cmpl -@glob = common local_unnamed_addr global i64 0, align 8 +@glob = local_unnamed_addr global i64 0, align 8 define signext i32 @test_ilesll(i64 %a, i64 %b) { ; CHECK-LABEL: test_ilesll: diff --git a/llvm/test/CodeGen/PowerPC/testComparesiless.ll b/llvm/test/CodeGen/PowerPC/testComparesiless.ll index 45c887d21adca..b9b029496f921 100644 --- a/llvm/test/CodeGen/PowerPC/testComparesiless.ll +++ b/llvm/test/CodeGen/PowerPC/testComparesiless.ll @@ -5,7 +5,7 @@ ; RUN: llc -verify-machineinstrs -mtriple=powerpc64le-unknown-linux-gnu -O2 \ ; RUN: -ppc-gpr-icmps=all -ppc-asm-full-reg-names -mcpu=pwr8 < %s | FileCheck %s --check-prefix=CHECK-LE \ ; RUN: --implicit-check-not cmpw --implicit-check-not cmpd --implicit-check-not cmpl -@glob = common local_unnamed_addr global i16 0, align 2 +@glob = local_unnamed_addr global i16 0, align 2 define signext i32 @test_iless(i16 signext %a, i16 signext %b) { ; CHECK-LABEL: test_iless: diff --git a/llvm/test/CodeGen/PowerPC/testComparesileuc.ll b/llvm/test/CodeGen/PowerPC/testComparesileuc.ll index 9976dada86b3d..4461fb66cef31 100644 --- a/llvm/test/CodeGen/PowerPC/testComparesileuc.ll +++ b/llvm/test/CodeGen/PowerPC/testComparesileuc.ll @@ -8,7 +8,7 @@ ; RUN: --implicit-check-not cmpw --implicit-check-not cmpd --implicit-check-not cmpl \ ; RUN: --check-prefixes=CHECK,LE -@glob = common local_unnamed_addr global i8 0, align 1 +@glob = local_unnamed_addr global i8 0, align 1 ; Function Attrs: norecurse nounwind readnone define signext i32 @test_ileuc(i8 zeroext %a, i8 zeroext %b) { diff --git a/llvm/test/CodeGen/PowerPC/testComparesileui.ll b/llvm/test/CodeGen/PowerPC/testComparesileui.ll index dc69277111c9c..ad6418c103c8c 100644 --- a/llvm/test/CodeGen/PowerPC/testComparesileui.ll +++ b/llvm/test/CodeGen/PowerPC/testComparesileui.ll @@ -8,7 +8,7 @@ ; RUN: --implicit-check-not cmpw --implicit-check-not cmpd --implicit-check-not cmpl \ ; RUN: --check-prefixes=CHECK,LE -@glob = common local_unnamed_addr global i32 0, align 4 +@glob = local_unnamed_addr global i32 0, align 4 ; Function Attrs: norecurse nounwind readnone define signext i32 @test_ileui(i32 zeroext %a, i32 zeroext %b) { diff --git a/llvm/test/CodeGen/PowerPC/testComparesileull.ll b/llvm/test/CodeGen/PowerPC/testComparesileull.ll index 4b18754d79668..54ee2561acbd7 100644 --- a/llvm/test/CodeGen/PowerPC/testComparesileull.ll +++ b/llvm/test/CodeGen/PowerPC/testComparesileull.ll @@ -8,7 +8,7 @@ ; RUN: --implicit-check-not cmpw --implicit-check-not cmpd --implicit-check-not cmpl \ ; RUN: --check-prefixes=CHECK,LE -@glob = common local_unnamed_addr global i64 0, align 8 +@glob = local_unnamed_addr global i64 0, align 8 ; Function Attrs: norecurse nounwind readnone define signext i32 @test_ileull(i64 %a, i64 %b) { diff --git a/llvm/test/CodeGen/PowerPC/testComparesileus.ll b/llvm/test/CodeGen/PowerPC/testComparesileus.ll index 0cb21e0b28e10..e4b68bb0328f8 100644 --- a/llvm/test/CodeGen/PowerPC/testComparesileus.ll +++ b/llvm/test/CodeGen/PowerPC/testComparesileus.ll @@ -8,7 +8,7 @@ ; RUN: --implicit-check-not cmpw --implicit-check-not cmpd --implicit-check-not cmpl \ ; RUN: --check-prefixes=CHECK,LE -@glob = common local_unnamed_addr global i16 0, align 2 +@glob = local_unnamed_addr global i16 0, align 2 ; Function Attrs: norecurse nounwind readnone define signext i32 @test_ileus(i16 zeroext %a, i16 zeroext %b) { diff --git a/llvm/test/CodeGen/PowerPC/testComparesiltsc.ll b/llvm/test/CodeGen/PowerPC/testComparesiltsc.ll index 7702598c5ffb1..b1a1b96e66df2 100644 --- a/llvm/test/CodeGen/PowerPC/testComparesiltsc.ll +++ b/llvm/test/CodeGen/PowerPC/testComparesiltsc.ll @@ -8,7 +8,7 @@ ; RUN: --implicit-check-not cmpw --implicit-check-not cmpd --implicit-check-not cmpl \ ; RUN: --check-prefixes=CHECK,LE -@glob = common local_unnamed_addr global i8 0, align 1 +@glob = local_unnamed_addr global i8 0, align 1 ; Function Attrs: norecurse nounwind readnone define signext i32 @test_iltsc(i8 signext %a, i8 signext %b) { diff --git a/llvm/test/CodeGen/PowerPC/testComparesiltsi.ll b/llvm/test/CodeGen/PowerPC/testComparesiltsi.ll index a97b734a8e41f..252e9c3238a22 100644 --- a/llvm/test/CodeGen/PowerPC/testComparesiltsi.ll +++ b/llvm/test/CodeGen/PowerPC/testComparesiltsi.ll @@ -8,7 +8,7 @@ ; RUN: --implicit-check-not cmpw --implicit-check-not cmpd --implicit-check-not cmpl \ ; RUN: --check-prefixes=CHECK,LE -@glob = common local_unnamed_addr global i32 0, align 4 +@glob = local_unnamed_addr global i32 0, align 4 ; Function Attrs: norecurse nounwind readnone define signext i32 @test_iltsi(i32 signext %a, i32 signext %b) { diff --git a/llvm/test/CodeGen/PowerPC/testComparesiltsll.ll b/llvm/test/CodeGen/PowerPC/testComparesiltsll.ll index 0341c158fe2b2..0a31d051e0e58 100644 --- a/llvm/test/CodeGen/PowerPC/testComparesiltsll.ll +++ b/llvm/test/CodeGen/PowerPC/testComparesiltsll.ll @@ -8,7 +8,7 @@ ; RUN: --implicit-check-not cmpw --implicit-check-not cmpd --implicit-check-not cmpl \ ; RUN: --check-prefixes=CHECK,LE -@glob = common local_unnamed_addr global i64 0, align 8 +@glob = local_unnamed_addr global i64 0, align 8 ; Function Attrs: norecurse nounwind readnone define signext i32 @test_iltsll(i64 %a, i64 %b) { diff --git a/llvm/test/CodeGen/PowerPC/testComparesiltss.ll b/llvm/test/CodeGen/PowerPC/testComparesiltss.ll index 195a5cf58a819..f6a91251363a1 100644 --- a/llvm/test/CodeGen/PowerPC/testComparesiltss.ll +++ b/llvm/test/CodeGen/PowerPC/testComparesiltss.ll @@ -8,7 +8,7 @@ ; RUN: --implicit-check-not cmpw --implicit-check-not cmpd --implicit-check-not cmpl \ ; RUN: --check-prefixes=CHECK,LE -@glob = common local_unnamed_addr global i16 0, align 2 +@glob = local_unnamed_addr global i16 0, align 2 ; Function Attrs: norecurse nounwind readnone define signext i32 @test_iltss(i16 signext %a, i16 signext %b) { diff --git a/llvm/test/CodeGen/PowerPC/testComparesiltuc.ll b/llvm/test/CodeGen/PowerPC/testComparesiltuc.ll index 64b4fa948a17a..de2dc1cbe19fb 100644 --- a/llvm/test/CodeGen/PowerPC/testComparesiltuc.ll +++ b/llvm/test/CodeGen/PowerPC/testComparesiltuc.ll @@ -8,7 +8,7 @@ ; RUN: --implicit-check-not cmpw --implicit-check-not cmpd --implicit-check-not cmpl \ ; RUN: --check-prefixes=CHECK,LE -@glob = common local_unnamed_addr global i8 0, align 1 +@glob = local_unnamed_addr global i8 0, align 1 ; Function Attrs: norecurse nounwind readnone define signext i32 @test_iltuc(i8 zeroext %a, i8 zeroext %b) { diff --git a/llvm/test/CodeGen/PowerPC/testComparesiltui.ll b/llvm/test/CodeGen/PowerPC/testComparesiltui.ll index 005f3b8352929..a0d40b62aa0f4 100644 --- a/llvm/test/CodeGen/PowerPC/testComparesiltui.ll +++ b/llvm/test/CodeGen/PowerPC/testComparesiltui.ll @@ -8,7 +8,7 @@ ; RUN: --implicit-check-not cmpw --implicit-check-not cmpd --implicit-check-not cmpl \ ; RUN: --check-prefixes=CHECK,LE -@glob = common local_unnamed_addr global i32 0, align 4 +@glob = local_unnamed_addr global i32 0, align 4 ; Function Attrs: norecurse nounwind readnone define signext i32 @test_iltui(i32 zeroext %a, i32 zeroext %b) { diff --git a/llvm/test/CodeGen/PowerPC/testComparesiltus.ll b/llvm/test/CodeGen/PowerPC/testComparesiltus.ll index 20cb9e141a288..98b8f35535324 100644 --- a/llvm/test/CodeGen/PowerPC/testComparesiltus.ll +++ b/llvm/test/CodeGen/PowerPC/testComparesiltus.ll @@ -8,7 +8,7 @@ ; RUN: --implicit-check-not cmpw --implicit-check-not cmpd --implicit-check-not cmpl \ ; RUN: --check-prefixes=CHECK,LE -@glob = common local_unnamed_addr global i16 0, align 2 +@glob = local_unnamed_addr global i16 0, align 2 ; Function Attrs: norecurse nounwind readnone define signext i32 @test_iltus(i16 zeroext %a, i16 zeroext %b) { diff --git a/llvm/test/CodeGen/PowerPC/testComparesinesc.ll b/llvm/test/CodeGen/PowerPC/testComparesinesc.ll index f5ad934409e5f..8c81eadc10a89 100644 --- a/llvm/test/CodeGen/PowerPC/testComparesinesc.ll +++ b/llvm/test/CodeGen/PowerPC/testComparesinesc.ll @@ -6,7 +6,7 @@ ; RUN: -ppc-gpr-icmps=all -ppc-asm-full-reg-names -mcpu=pwr8 < %s | FileCheck %s --check-prefix=CHECK-LE \ ; RUN: --implicit-check-not cmpw --implicit-check-not cmpd --implicit-check-not cmpl -@glob = common local_unnamed_addr global i8 0, align 1 +@glob = local_unnamed_addr global i8 0, align 1 define signext i32 @test_inesc(i8 signext %a, i8 signext %b) { ; CHECK-LABEL: test_inesc: diff --git a/llvm/test/CodeGen/PowerPC/testComparesinesi.ll b/llvm/test/CodeGen/PowerPC/testComparesinesi.ll index 3b0fe78e99c84..ae8d981cde22f 100644 --- a/llvm/test/CodeGen/PowerPC/testComparesinesi.ll +++ b/llvm/test/CodeGen/PowerPC/testComparesinesi.ll @@ -6,7 +6,7 @@ ; RUN: -ppc-gpr-icmps=all -ppc-asm-full-reg-names -mcpu=pwr8 < %s | FileCheck %s --check-prefix=CHECK-LE \ ; RUN: --implicit-check-not cmpw --implicit-check-not cmpd --implicit-check-not cmpl -@glob = common local_unnamed_addr global i32 0, align 4 +@glob = local_unnamed_addr global i32 0, align 4 define signext i32 @test_inesi(i32 signext %a, i32 signext %b) { ; CHECK-LABEL: test_inesi: diff --git a/llvm/test/CodeGen/PowerPC/testComparesinesll.ll b/llvm/test/CodeGen/PowerPC/testComparesinesll.ll index bfc0b9d3fbb47..c360fb99106ae 100644 --- a/llvm/test/CodeGen/PowerPC/testComparesinesll.ll +++ b/llvm/test/CodeGen/PowerPC/testComparesinesll.ll @@ -6,7 +6,7 @@ ; RUN: -ppc-gpr-icmps=all -ppc-asm-full-reg-names -mcpu=pwr8 < %s | FileCheck %s --check-prefix=CHECK-LE \ ; RUN: --implicit-check-not cmpw --implicit-check-not cmpd --implicit-check-not cmpl -@glob = common local_unnamed_addr global i64 0, align 8 +@glob = local_unnamed_addr global i64 0, align 8 define signext i32 @test_inesll(i64 %a, i64 %b) { ; CHECK-LABEL: test_inesll: diff --git a/llvm/test/CodeGen/PowerPC/testComparesiness.ll b/llvm/test/CodeGen/PowerPC/testComparesiness.ll index 9e570949e1273..cdfeaa9d77e05 100644 --- a/llvm/test/CodeGen/PowerPC/testComparesiness.ll +++ b/llvm/test/CodeGen/PowerPC/testComparesiness.ll @@ -6,7 +6,7 @@ ; RUN: -ppc-gpr-icmps=all -ppc-asm-full-reg-names -mcpu=pwr8 < %s | FileCheck %s --check-prefix=CHECK-LE \ ; RUN: --implicit-check-not cmpw --implicit-check-not cmpd --implicit-check-not cmpl -@glob = common local_unnamed_addr global i16 0, align 2 +@glob = local_unnamed_addr global i16 0, align 2 define signext i32 @test_iness(i16 signext %a, i16 signext %b) { ; CHECK-LABEL: test_iness: diff --git a/llvm/test/CodeGen/PowerPC/testComparesineuc.ll b/llvm/test/CodeGen/PowerPC/testComparesineuc.ll index 4e7f5c05cf6de..e63ea46b05551 100644 --- a/llvm/test/CodeGen/PowerPC/testComparesineuc.ll +++ b/llvm/test/CodeGen/PowerPC/testComparesineuc.ll @@ -5,7 +5,7 @@ ; RUN: llc -verify-machineinstrs -mtriple=powerpc64le-unknown-linux-gnu -O2 \ ; RUN: -ppc-gpr-icmps=all -ppc-asm-full-reg-names -mcpu=pwr8 < %s | FileCheck %s --check-prefix=CHECK-LE \ ; RUN: --implicit-check-not cmpw --implicit-check-not cmpd --implicit-check-not cmpl -@glob = common local_unnamed_addr global i8 0, align 1 +@glob = local_unnamed_addr global i8 0, align 1 define signext i32 @test_ineuc(i8 zeroext %a, i8 zeroext %b) { ; CHECK-LABEL: test_ineuc: diff --git a/llvm/test/CodeGen/PowerPC/testComparesineui.ll b/llvm/test/CodeGen/PowerPC/testComparesineui.ll index e8fb3dd85be77..86e6fb9c7d263 100644 --- a/llvm/test/CodeGen/PowerPC/testComparesineui.ll +++ b/llvm/test/CodeGen/PowerPC/testComparesineui.ll @@ -6,7 +6,7 @@ ; RUN: -ppc-gpr-icmps=all -ppc-asm-full-reg-names -mcpu=pwr8 < %s | FileCheck %s --check-prefix=CHECK-LE \ ; RUN: --implicit-check-not cmpw --implicit-check-not cmpd --implicit-check-not cmpl -@glob = common local_unnamed_addr global i32 0, align 4 +@glob = local_unnamed_addr global i32 0, align 4 define signext i32 @test_ineui(i32 zeroext %a, i32 zeroext %b) { ; CHECK-LABEL: test_ineui: diff --git a/llvm/test/CodeGen/PowerPC/testComparesineull.ll b/llvm/test/CodeGen/PowerPC/testComparesineull.ll index e288988bdcde6..c0b04c2737c43 100644 --- a/llvm/test/CodeGen/PowerPC/testComparesineull.ll +++ b/llvm/test/CodeGen/PowerPC/testComparesineull.ll @@ -6,7 +6,7 @@ ; RUN: -ppc-gpr-icmps=all -ppc-asm-full-reg-names -mcpu=pwr8 < %s | FileCheck %s --check-prefix=CHECK-LE \ ; RUN: --implicit-check-not cmpw --implicit-check-not cmpd --implicit-check-not cmpl -@glob = common local_unnamed_addr global i64 0, align 8 +@glob = local_unnamed_addr global i64 0, align 8 define signext i32 @test_ineull(i64 %a, i64 %b) { ; CHECK-LABEL: test_ineull: diff --git a/llvm/test/CodeGen/PowerPC/testComparesineus.ll b/llvm/test/CodeGen/PowerPC/testComparesineus.ll index 4a2f851fa647c..df208eebf44a7 100644 --- a/llvm/test/CodeGen/PowerPC/testComparesineus.ll +++ b/llvm/test/CodeGen/PowerPC/testComparesineus.ll @@ -6,7 +6,7 @@ ; RUN: -ppc-gpr-icmps=all -ppc-asm-full-reg-names -mcpu=pwr8 < %s | FileCheck %s --check-prefix=CHECK-LE \ ; RUN: --implicit-check-not cmpw --implicit-check-not cmpd --implicit-check-not cmpl -@glob = common local_unnamed_addr global i16 0, align 2 +@glob = local_unnamed_addr global i16 0, align 2 define signext i32 @test_ineus(i16 zeroext %a, i16 zeroext %b) { ; CHECK-LABEL: test_ineus: diff --git a/llvm/test/CodeGen/PowerPC/testCompareslleqsc.ll b/llvm/test/CodeGen/PowerPC/testCompareslleqsc.ll index 3e519edcd0cd3..7759f0ad9f3c1 100644 --- a/llvm/test/CodeGen/PowerPC/testCompareslleqsc.ll +++ b/llvm/test/CodeGen/PowerPC/testCompareslleqsc.ll @@ -7,7 +7,7 @@ ; RUN: --implicit-check-not cmpw --implicit-check-not cmpd --implicit-check-not cmpl ; ModuleID = 'ComparisonTestCases/testCompareslleqsc.c' -@glob = common local_unnamed_addr global i8 0, align 1 +@glob = local_unnamed_addr global i8 0, align 1 ; Function Attrs: norecurse nounwind readnone define i64 @test_lleqsc(i8 signext %a, i8 signext %b) { diff --git a/llvm/test/CodeGen/PowerPC/testCompareslleqsi.ll b/llvm/test/CodeGen/PowerPC/testCompareslleqsi.ll index 4de1d588238cf..63612aec1672f 100644 --- a/llvm/test/CodeGen/PowerPC/testCompareslleqsi.ll +++ b/llvm/test/CodeGen/PowerPC/testCompareslleqsi.ll @@ -6,7 +6,7 @@ ; RUN: -ppc-gpr-icmps=all -ppc-asm-full-reg-names -mcpu=pwr8 < %s | FileCheck %s --check-prefix=CHECK-LE \ ; RUN: --implicit-check-not cmpw --implicit-check-not cmpd --implicit-check-not cmpl -@glob = common local_unnamed_addr global i32 0, align 4 +@glob = local_unnamed_addr global i32 0, align 4 ; Function Attrs: norecurse nounwind readnone define i64 @test_lleqsi(i32 signext %a, i32 signext %b) { diff --git a/llvm/test/CodeGen/PowerPC/testCompareslleqsll.ll b/llvm/test/CodeGen/PowerPC/testCompareslleqsll.ll index ac92d171a68bb..18b8d0b24fde1 100644 --- a/llvm/test/CodeGen/PowerPC/testCompareslleqsll.ll +++ b/llvm/test/CodeGen/PowerPC/testCompareslleqsll.ll @@ -6,7 +6,7 @@ ; RUN: -ppc-gpr-icmps=all -ppc-asm-full-reg-names -mcpu=pwr8 < %s | FileCheck %s --check-prefix=CHECK-LE \ ; RUN: --implicit-check-not cmpw --implicit-check-not cmpd --implicit-check-not cmpl -@glob = common local_unnamed_addr global i64 0, align 8 +@glob = local_unnamed_addr global i64 0, align 8 ; Function Attrs: norecurse nounwind readnone define i64 @test_lleqsll(i64 %a, i64 %b) { diff --git a/llvm/test/CodeGen/PowerPC/testCompareslleqss.ll b/llvm/test/CodeGen/PowerPC/testCompareslleqss.ll index d65990f9dc936..13e0759e83ea4 100644 --- a/llvm/test/CodeGen/PowerPC/testCompareslleqss.ll +++ b/llvm/test/CodeGen/PowerPC/testCompareslleqss.ll @@ -6,7 +6,7 @@ ; RUN: -ppc-gpr-icmps=all -ppc-asm-full-reg-names -mcpu=pwr8 < %s | FileCheck %s --check-prefix=CHECK-LE \ ; RUN: --implicit-check-not cmpw --implicit-check-not cmpd --implicit-check-not cmpl -@glob = common local_unnamed_addr global i16 0, align 2 +@glob = local_unnamed_addr global i16 0, align 2 ; Function Attrs: norecurse nounwind readnone define i64 @test_lleqss(i16 signext %a, i16 signext %b) { diff --git a/llvm/test/CodeGen/PowerPC/testComparesllequc.ll b/llvm/test/CodeGen/PowerPC/testComparesllequc.ll index 1672d19a4a3da..4c3c1d6115c2c 100644 --- a/llvm/test/CodeGen/PowerPC/testComparesllequc.ll +++ b/llvm/test/CodeGen/PowerPC/testComparesllequc.ll @@ -6,7 +6,7 @@ ; RUN: -ppc-gpr-icmps=all -ppc-asm-full-reg-names -mcpu=pwr8 < %s | FileCheck %s --check-prefix=CHECK-LE \ ; RUN: --implicit-check-not cmpw --implicit-check-not cmpd --implicit-check-not cmpl -@glob = common local_unnamed_addr global i8 0, align 1 +@glob = local_unnamed_addr global i8 0, align 1 ; Function Attrs: norecurse nounwind readnone define i64 @test_llequc(i8 zeroext %a, i8 zeroext %b) { diff --git a/llvm/test/CodeGen/PowerPC/testComparesllequi.ll b/llvm/test/CodeGen/PowerPC/testComparesllequi.ll index fd1d13bae7f6b..16741ea0251ae 100644 --- a/llvm/test/CodeGen/PowerPC/testComparesllequi.ll +++ b/llvm/test/CodeGen/PowerPC/testComparesllequi.ll @@ -6,7 +6,7 @@ ; RUN: -ppc-gpr-icmps=all -ppc-asm-full-reg-names -mcpu=pwr8 < %s | FileCheck %s --check-prefix=CHECK-LE \ ; RUN: --implicit-check-not cmpw --implicit-check-not cmpd --implicit-check-not cmpl -@glob = common local_unnamed_addr global i32 0, align 4 +@glob = local_unnamed_addr global i32 0, align 4 ; Function Attrs: norecurse nounwind readnone define i64 @test_llequi(i32 zeroext %a, i32 zeroext %b) { diff --git a/llvm/test/CodeGen/PowerPC/testComparesllequll.ll b/llvm/test/CodeGen/PowerPC/testComparesllequll.ll index a42b5e4c7b7b1..16bd2d1a4c0c4 100644 --- a/llvm/test/CodeGen/PowerPC/testComparesllequll.ll +++ b/llvm/test/CodeGen/PowerPC/testComparesllequll.ll @@ -6,7 +6,7 @@ ; RUN: -ppc-gpr-icmps=all -ppc-asm-full-reg-names -mcpu=pwr8 < %s | FileCheck %s --check-prefix=CHECK-LE \ ; RUN: --implicit-check-not cmpw --implicit-check-not cmpd --implicit-check-not cmpl -@glob = common local_unnamed_addr global i64 0, align 8 +@glob = local_unnamed_addr global i64 0, align 8 ; Function Attrs: norecurse nounwind readnone define i64 @test_llequll(i64 %a, i64 %b) { diff --git a/llvm/test/CodeGen/PowerPC/testComparesllequs.ll b/llvm/test/CodeGen/PowerPC/testComparesllequs.ll index e3dde77aba7e6..4470b4f959a79 100644 --- a/llvm/test/CodeGen/PowerPC/testComparesllequs.ll +++ b/llvm/test/CodeGen/PowerPC/testComparesllequs.ll @@ -6,7 +6,7 @@ ; RUN: -ppc-gpr-icmps=all -ppc-asm-full-reg-names -mcpu=pwr8 < %s | FileCheck %s --check-prefix=CHECK-LE \ ; RUN: --implicit-check-not cmpw --implicit-check-not cmpd --implicit-check-not cmpl -@glob = common local_unnamed_addr global i16 0, align 2 +@glob = local_unnamed_addr global i16 0, align 2 ; Function Attrs: norecurse nounwind readnone define i64 @test_llequs(i16 zeroext %a, i16 zeroext %b) { diff --git a/llvm/test/CodeGen/PowerPC/testComparesllgesc.ll b/llvm/test/CodeGen/PowerPC/testComparesllgesc.ll index b97da250323bc..f7c79859666e0 100644 --- a/llvm/test/CodeGen/PowerPC/testComparesllgesc.ll +++ b/llvm/test/CodeGen/PowerPC/testComparesllgesc.ll @@ -5,7 +5,7 @@ ; RUN: llc -verify-machineinstrs -mtriple=powerpc64le-unknown-linux-gnu -O2 \ ; RUN: -ppc-gpr-icmps=all -ppc-asm-full-reg-names -mcpu=pwr8 < %s | FileCheck %s --check-prefix=CHECK-LE \ ; RUN: --implicit-check-not cmpw --implicit-check-not cmpd --implicit-check-not cmpl -@glob = common local_unnamed_addr global i8 0, align 1 +@glob = local_unnamed_addr global i8 0, align 1 define i64 @test_llgesc(i8 signext %a, i8 signext %b) { ; CHECK-LABEL: test_llgesc: diff --git a/llvm/test/CodeGen/PowerPC/testComparesllgesi.ll b/llvm/test/CodeGen/PowerPC/testComparesllgesi.ll index cc23babc00055..046c037bb7940 100644 --- a/llvm/test/CodeGen/PowerPC/testComparesllgesi.ll +++ b/llvm/test/CodeGen/PowerPC/testComparesllgesi.ll @@ -5,7 +5,7 @@ ; RUN: llc -verify-machineinstrs -mtriple=powerpc64le-unknown-linux-gnu -O2 \ ; RUN: -ppc-gpr-icmps=all -ppc-asm-full-reg-names -mcpu=pwr8 < %s | FileCheck %s --check-prefix=CHECK-LE \ ; RUN: --implicit-check-not cmpw --implicit-check-not cmpd --implicit-check-not cmpl -@glob = common local_unnamed_addr global i32 0, align 4 +@glob = local_unnamed_addr global i32 0, align 4 define i64 @test_llgesi(i32 signext %a, i32 signext %b) { ; CHECK-LABEL: test_llgesi: diff --git a/llvm/test/CodeGen/PowerPC/testComparesllgesll.ll b/llvm/test/CodeGen/PowerPC/testComparesllgesll.ll index 1c119b950a35a..2b1dc4a689c96 100644 --- a/llvm/test/CodeGen/PowerPC/testComparesllgesll.ll +++ b/llvm/test/CodeGen/PowerPC/testComparesllgesll.ll @@ -5,7 +5,7 @@ ; RUN: llc -verify-machineinstrs -mtriple=powerpc64le-unknown-linux-gnu -O2 \ ; RUN: -ppc-gpr-icmps=all -ppc-asm-full-reg-names -mcpu=pwr8 < %s | FileCheck %s --check-prefix=CHECK-LE \ ; RUN: --implicit-check-not cmpw --implicit-check-not cmpd --implicit-check-not cmpl -@glob = common local_unnamed_addr global i64 0, align 8 +@glob = local_unnamed_addr global i64 0, align 8 define i64 @test_llgesll(i64 %a, i64 %b) { ; CHECK-LABEL: test_llgesll: diff --git a/llvm/test/CodeGen/PowerPC/testComparesllgess.ll b/llvm/test/CodeGen/PowerPC/testComparesllgess.ll index 400c11bef4b61..50583cd7fa94b 100644 --- a/llvm/test/CodeGen/PowerPC/testComparesllgess.ll +++ b/llvm/test/CodeGen/PowerPC/testComparesllgess.ll @@ -5,7 +5,7 @@ ; RUN: llc -verify-machineinstrs -mtriple=powerpc64le-unknown-linux-gnu -O2 \ ; RUN: -ppc-gpr-icmps=all -ppc-asm-full-reg-names -mcpu=pwr8 < %s | FileCheck %s --check-prefix=CHECK-LE \ ; RUN: --implicit-check-not cmpw --implicit-check-not cmpd --implicit-check-not cmpl -@glob = common local_unnamed_addr global i16 0, align 2 +@glob = local_unnamed_addr global i16 0, align 2 define i64 @test_llgess(i16 signext %a, i16 signext %b) { ; CHECK-LABEL: test_llgess: diff --git a/llvm/test/CodeGen/PowerPC/testComparesllgeuc.ll b/llvm/test/CodeGen/PowerPC/testComparesllgeuc.ll index 4c01f87952bf8..85a9df5c21883 100644 --- a/llvm/test/CodeGen/PowerPC/testComparesllgeuc.ll +++ b/llvm/test/CodeGen/PowerPC/testComparesllgeuc.ll @@ -8,7 +8,7 @@ ; RUN: --implicit-check-not cmpw --implicit-check-not cmpd --implicit-check-not cmpl \ ; RUN: --check-prefixes=CHECK,LE -@glob = common local_unnamed_addr global i8 0, align 1 +@glob = local_unnamed_addr global i8 0, align 1 ; Function Attrs: norecurse nounwind readnone define i64 @test_llgeuc(i8 zeroext %a, i8 zeroext %b) { diff --git a/llvm/test/CodeGen/PowerPC/testComparesllgeui.ll b/llvm/test/CodeGen/PowerPC/testComparesllgeui.ll index 5fc0323d8041f..19da9da01fa40 100644 --- a/llvm/test/CodeGen/PowerPC/testComparesllgeui.ll +++ b/llvm/test/CodeGen/PowerPC/testComparesllgeui.ll @@ -8,7 +8,7 @@ ; RUN: --implicit-check-not cmpw --implicit-check-not cmpd --implicit-check-not cmpl \ ; RUN: --check-prefixes=CHECK,LE -@glob = common local_unnamed_addr global i32 0, align 4 +@glob = local_unnamed_addr global i32 0, align 4 ; Function Attrs: norecurse nounwind readnone define i64 @test_llgeui(i32 zeroext %a, i32 zeroext %b) { diff --git a/llvm/test/CodeGen/PowerPC/testComparesllgeull.ll b/llvm/test/CodeGen/PowerPC/testComparesllgeull.ll index 32849572ebb10..68d908a4e805f 100644 --- a/llvm/test/CodeGen/PowerPC/testComparesllgeull.ll +++ b/llvm/test/CodeGen/PowerPC/testComparesllgeull.ll @@ -8,7 +8,7 @@ ; RUN: --implicit-check-not cmpw --implicit-check-not cmpd --implicit-check-not cmpl \ ; RUN: --check-prefixes=CHECK,LE -@glob = common local_unnamed_addr global i64 0, align 8 +@glob = local_unnamed_addr global i64 0, align 8 ; Function Attrs: norecurse nounwind readnone define i64 @test_llgeull(i64 %a, i64 %b) { diff --git a/llvm/test/CodeGen/PowerPC/testComparesllgeus.ll b/llvm/test/CodeGen/PowerPC/testComparesllgeus.ll index 552bdd46a1614..56099c63d5373 100644 --- a/llvm/test/CodeGen/PowerPC/testComparesllgeus.ll +++ b/llvm/test/CodeGen/PowerPC/testComparesllgeus.ll @@ -8,7 +8,7 @@ ; RUN: --implicit-check-not cmpw --implicit-check-not cmpd --implicit-check-not cmpl \ ; RUN: --check-prefixes=CHECK,LE -@glob = common local_unnamed_addr global i16 0, align 2 +@glob = local_unnamed_addr global i16 0, align 2 ; Function Attrs: norecurse nounwind readnone define i64 @test_llgeus(i16 zeroext %a, i16 zeroext %b) { diff --git a/llvm/test/CodeGen/PowerPC/testComparesllgtsll.ll b/llvm/test/CodeGen/PowerPC/testComparesllgtsll.ll index 8948503c3b633..6f4c9b00b83f2 100644 --- a/llvm/test/CodeGen/PowerPC/testComparesllgtsll.ll +++ b/llvm/test/CodeGen/PowerPC/testComparesllgtsll.ll @@ -6,7 +6,7 @@ ; RUN: -ppc-gpr-icmps=all -ppc-asm-full-reg-names -mcpu=pwr8 < %s | FileCheck %s \ ; RUN: --implicit-check-not cmpw --implicit-check-not cmpd --implicit-check-not cmpl -@glob = common local_unnamed_addr global i64 0, align 8 +@glob = local_unnamed_addr global i64 0, align 8 ; Function Attrs: norecurse nounwind readnone define i64 @test_llgtsll(i64 %a, i64 %b) { diff --git a/llvm/test/CodeGen/PowerPC/testComparesllgtuc.ll b/llvm/test/CodeGen/PowerPC/testComparesllgtuc.ll index b885082190dfd..e535d30d2ebaa 100644 --- a/llvm/test/CodeGen/PowerPC/testComparesllgtuc.ll +++ b/llvm/test/CodeGen/PowerPC/testComparesllgtuc.ll @@ -6,7 +6,7 @@ ; RUN: -ppc-gpr-icmps=all -ppc-asm-full-reg-names -mcpu=pwr8 < %s | FileCheck %s \ ; RUN: --implicit-check-not cmpw --implicit-check-not cmpd --implicit-check-not cmpl -@glob = common local_unnamed_addr global i8 0, align 1 +@glob = local_unnamed_addr global i8 0, align 1 ; Function Attrs: norecurse nounwind readnone define i64 @test_llgtuc(i8 zeroext %a, i8 zeroext %b) { diff --git a/llvm/test/CodeGen/PowerPC/testComparesllgtui.ll b/llvm/test/CodeGen/PowerPC/testComparesllgtui.ll index 4a093db0b9cd7..3c6b2f1c27599 100644 --- a/llvm/test/CodeGen/PowerPC/testComparesllgtui.ll +++ b/llvm/test/CodeGen/PowerPC/testComparesllgtui.ll @@ -6,7 +6,7 @@ ; RUN: -ppc-gpr-icmps=all -ppc-asm-full-reg-names -mcpu=pwr8 < %s | FileCheck %s \ ; RUN: --implicit-check-not cmpw --implicit-check-not cmpd --implicit-check-not cmpl -@glob = common local_unnamed_addr global i32 0, align 4 +@glob = local_unnamed_addr global i32 0, align 4 ; Function Attrs: norecurse nounwind readnone define i64 @test_llgtui(i32 zeroext %a, i32 zeroext %b) { diff --git a/llvm/test/CodeGen/PowerPC/testComparesllgtus.ll b/llvm/test/CodeGen/PowerPC/testComparesllgtus.ll index b148c6861440e..1dbd9ca80bec2 100644 --- a/llvm/test/CodeGen/PowerPC/testComparesllgtus.ll +++ b/llvm/test/CodeGen/PowerPC/testComparesllgtus.ll @@ -6,7 +6,7 @@ ; RUN: -ppc-gpr-icmps=all -ppc-asm-full-reg-names -mcpu=pwr8 < %s | FileCheck %s \ ; RUN: --implicit-check-not cmpw --implicit-check-not cmpd --implicit-check-not cmpl -@glob = common local_unnamed_addr global i16 0, align 2 +@glob = local_unnamed_addr global i16 0, align 2 ; Function Attrs: norecurse nounwind readnone define i64 @test_llgtus(i16 zeroext %a, i16 zeroext %b) { diff --git a/llvm/test/CodeGen/PowerPC/testCompareslllesc.ll b/llvm/test/CodeGen/PowerPC/testCompareslllesc.ll index 1a5ad44ee080b..1ec226a86420c 100644 --- a/llvm/test/CodeGen/PowerPC/testCompareslllesc.ll +++ b/llvm/test/CodeGen/PowerPC/testCompareslllesc.ll @@ -6,7 +6,7 @@ ; RUN: -ppc-gpr-icmps=all -ppc-asm-full-reg-names -mcpu=pwr8 < %s | FileCheck %s --check-prefix=CHECK-LE \ ; RUN: --implicit-check-not cmpw --implicit-check-not cmpd --implicit-check-not cmpl -@glob = common local_unnamed_addr global i8 0, align 1 +@glob = local_unnamed_addr global i8 0, align 1 define i64 @test_lllesc(i8 signext %a, i8 signext %b) { ; CHECK-LABEL: test_lllesc: diff --git a/llvm/test/CodeGen/PowerPC/testCompareslllesi.ll b/llvm/test/CodeGen/PowerPC/testCompareslllesi.ll index 9b79c1739a5c4..3ff4907741078 100644 --- a/llvm/test/CodeGen/PowerPC/testCompareslllesi.ll +++ b/llvm/test/CodeGen/PowerPC/testCompareslllesi.ll @@ -6,7 +6,7 @@ ; RUN: -ppc-gpr-icmps=all -ppc-asm-full-reg-names -mcpu=pwr8 < %s | FileCheck %s --check-prefix=CHECK-LE \ ; RUN: --implicit-check-not cmpw --implicit-check-not cmpd --implicit-check-not cmpl -@glob = common local_unnamed_addr global i32 0, align 4 +@glob = local_unnamed_addr global i32 0, align 4 define i64 @test_lllesi(i32 signext %a, i32 signext %b) { ; CHECK-LABEL: test_lllesi: diff --git a/llvm/test/CodeGen/PowerPC/testCompareslllesll.ll b/llvm/test/CodeGen/PowerPC/testCompareslllesll.ll index 83ce2f812ae14..ca7ce5e56e3b2 100644 --- a/llvm/test/CodeGen/PowerPC/testCompareslllesll.ll +++ b/llvm/test/CodeGen/PowerPC/testCompareslllesll.ll @@ -5,7 +5,7 @@ ; RUN: llc -verify-machineinstrs -mtriple=powerpc64le-unknown-linux-gnu -O2 \ ; RUN: -ppc-gpr-icmps=all -ppc-asm-full-reg-names -mcpu=pwr8 < %s | FileCheck %s --check-prefix=CHECK-LE \ ; RUN: --implicit-check-not cmpw --implicit-check-not cmpd --implicit-check-not cmpl -@glob = common local_unnamed_addr global i64 0, align 8 +@glob = local_unnamed_addr global i64 0, align 8 ; Function Attrs: norecurse nounwind readnone define i64 @test_lllesll(i64 %a, i64 %b) { diff --git a/llvm/test/CodeGen/PowerPC/testComparesllless.ll b/llvm/test/CodeGen/PowerPC/testComparesllless.ll index 6f8657dac4b1d..c67ef49e86617 100644 --- a/llvm/test/CodeGen/PowerPC/testComparesllless.ll +++ b/llvm/test/CodeGen/PowerPC/testComparesllless.ll @@ -6,7 +6,7 @@ ; RUN: -ppc-gpr-icmps=all -ppc-asm-full-reg-names -mcpu=pwr8 < %s | FileCheck %s --check-prefix=CHECK-LE \ ; RUN: --implicit-check-not cmpw --implicit-check-not cmpd --implicit-check-not cmpl -@glob = common local_unnamed_addr global i16 0, align 2 +@glob = local_unnamed_addr global i16 0, align 2 define i64 @test_llless(i16 signext %a, i16 signext %b) { ; CHECK-LABEL: test_llless: diff --git a/llvm/test/CodeGen/PowerPC/testComparesllleuc.ll b/llvm/test/CodeGen/PowerPC/testComparesllleuc.ll index f54027714da3b..9f0bf574e55cd 100644 --- a/llvm/test/CodeGen/PowerPC/testComparesllleuc.ll +++ b/llvm/test/CodeGen/PowerPC/testComparesllleuc.ll @@ -8,7 +8,7 @@ ; RUN: --implicit-check-not cmpw --implicit-check-not cmpd --implicit-check-not cmpl \ ; RUN: --check-prefixes=CHECK,LE -@glob = common local_unnamed_addr global i8 0, align 1 +@glob = local_unnamed_addr global i8 0, align 1 ; Function Attrs: norecurse nounwind readnone define i64 @test_llleuc(i8 zeroext %a, i8 zeroext %b) { diff --git a/llvm/test/CodeGen/PowerPC/testComparesllleui.ll b/llvm/test/CodeGen/PowerPC/testComparesllleui.ll index d6bf2e26e1e9f..b6c43e4a346e4 100644 --- a/llvm/test/CodeGen/PowerPC/testComparesllleui.ll +++ b/llvm/test/CodeGen/PowerPC/testComparesllleui.ll @@ -8,7 +8,7 @@ ; RUN: --implicit-check-not cmpw --implicit-check-not cmpd --implicit-check-not cmpl \ ; RUN: --check-prefixes=CHECK,LE -@glob = common local_unnamed_addr global i32 0, align 4 +@glob = local_unnamed_addr global i32 0, align 4 ; Function Attrs: norecurse nounwind readnone define i64 @test_llleui(i32 zeroext %a, i32 zeroext %b) { diff --git a/llvm/test/CodeGen/PowerPC/testComparesllleull.ll b/llvm/test/CodeGen/PowerPC/testComparesllleull.ll index 2eca70ed014c7..412d264974442 100644 --- a/llvm/test/CodeGen/PowerPC/testComparesllleull.ll +++ b/llvm/test/CodeGen/PowerPC/testComparesllleull.ll @@ -8,7 +8,7 @@ ; RUN: --implicit-check-not cmpw --implicit-check-not cmpd --implicit-check-not cmpl \ ; RUN: --check-prefixes=CHECK,LE -@glob = common local_unnamed_addr global i64 0, align 8 +@glob = local_unnamed_addr global i64 0, align 8 ; Function Attrs: norecurse nounwind readnone define i64 @test_llleull(i64 %a, i64 %b) { diff --git a/llvm/test/CodeGen/PowerPC/testComparesllleus.ll b/llvm/test/CodeGen/PowerPC/testComparesllleus.ll index 1cdb66d6cff81..8c852f16da10d 100644 --- a/llvm/test/CodeGen/PowerPC/testComparesllleus.ll +++ b/llvm/test/CodeGen/PowerPC/testComparesllleus.ll @@ -8,7 +8,7 @@ ; RUN: --implicit-check-not cmpw --implicit-check-not cmpd --implicit-check-not cmpl \ ; RUN: --check-prefixes=CHECK,LE -@glob = common local_unnamed_addr global i16 0, align 2 +@glob = local_unnamed_addr global i16 0, align 2 ; Function Attrs: norecurse nounwind readnone define i64 @test_llleus(i16 zeroext %a, i16 zeroext %b) { diff --git a/llvm/test/CodeGen/PowerPC/testComparesllltsll.ll b/llvm/test/CodeGen/PowerPC/testComparesllltsll.ll index 5bf437c920642..aeb1891122e34 100644 --- a/llvm/test/CodeGen/PowerPC/testComparesllltsll.ll +++ b/llvm/test/CodeGen/PowerPC/testComparesllltsll.ll @@ -8,7 +8,7 @@ ; RUN: --implicit-check-not cmpw --implicit-check-not cmpd --implicit-check-not cmpl \ ; RUN: --check-prefixes=CHECK,LE -@glob = common local_unnamed_addr global i64 0, align 8 +@glob = local_unnamed_addr global i64 0, align 8 ; Function Attrs: norecurse nounwind readnone define i64 @test_llltsll(i64 %a, i64 %b) { diff --git a/llvm/test/CodeGen/PowerPC/testComparesllltuc.ll b/llvm/test/CodeGen/PowerPC/testComparesllltuc.ll index 47d196720c62d..dafbbc1f4d051 100644 --- a/llvm/test/CodeGen/PowerPC/testComparesllltuc.ll +++ b/llvm/test/CodeGen/PowerPC/testComparesllltuc.ll @@ -8,7 +8,7 @@ ; RUN: --implicit-check-not cmpw --implicit-check-not cmpd --implicit-check-not cmpl \ ; RUN: --check-prefixes=CHECK,LE -@glob = common local_unnamed_addr global i8 0, align 1 +@glob = local_unnamed_addr global i8 0, align 1 ; Function Attrs: norecurse nounwind readnone define i64 @test_llltuc(i8 zeroext %a, i8 zeroext %b) { diff --git a/llvm/test/CodeGen/PowerPC/testComparesllltui.ll b/llvm/test/CodeGen/PowerPC/testComparesllltui.ll index 3f5dfba99e883..50a0ff11961da 100644 --- a/llvm/test/CodeGen/PowerPC/testComparesllltui.ll +++ b/llvm/test/CodeGen/PowerPC/testComparesllltui.ll @@ -6,7 +6,7 @@ ; RUN: -ppc-gpr-icmps=all -ppc-asm-full-reg-names -mcpu=pwr8 < %s | FileCheck %s \ ; RUN: --implicit-check-not cmpw --implicit-check-not cmpd --implicit-check-not cmpl -@glob = common local_unnamed_addr global i32 0, align 4 +@glob = local_unnamed_addr global i32 0, align 4 ; Function Attrs: norecurse nounwind readnone define i64 @test_llltui(i32 zeroext %a, i32 zeroext %b) { diff --git a/llvm/test/CodeGen/PowerPC/testComparesllltus.ll b/llvm/test/CodeGen/PowerPC/testComparesllltus.ll index 2cbc1b16c84bd..217821b661f9b 100644 --- a/llvm/test/CodeGen/PowerPC/testComparesllltus.ll +++ b/llvm/test/CodeGen/PowerPC/testComparesllltus.ll @@ -8,7 +8,7 @@ ; RUN: --implicit-check-not cmpw --implicit-check-not cmpd --implicit-check-not cmpl \ ; RUN: --check-prefixes=CHECK,LE -@glob = common local_unnamed_addr global i16 0, align 2 +@glob = local_unnamed_addr global i16 0, align 2 ; Function Attrs: norecurse nounwind readnone define i64 @test_llltus(i16 zeroext %a, i16 zeroext %b) { diff --git a/llvm/test/CodeGen/PowerPC/testComparesllnesll.ll b/llvm/test/CodeGen/PowerPC/testComparesllnesll.ll index 10bff2f7d94e4..76ea6262ddadb 100644 --- a/llvm/test/CodeGen/PowerPC/testComparesllnesll.ll +++ b/llvm/test/CodeGen/PowerPC/testComparesllnesll.ll @@ -6,7 +6,7 @@ ; RUN: -ppc-gpr-icmps=all -ppc-asm-full-reg-names -mcpu=pwr8 < %s | FileCheck %s --check-prefix=CHECK-LE \ ; RUN: --implicit-check-not cmpw --implicit-check-not cmpd --implicit-check-not cmpl -@glob = common local_unnamed_addr global i64 0, align 8 +@glob = local_unnamed_addr global i64 0, align 8 define i64 @test_llnesll(i64 %a, i64 %b) { ; CHECK-LABEL: test_llnesll: diff --git a/llvm/test/CodeGen/PowerPC/testComparesllneull.ll b/llvm/test/CodeGen/PowerPC/testComparesllneull.ll index 9e6be97e8c176..e809a0b91a589 100644 --- a/llvm/test/CodeGen/PowerPC/testComparesllneull.ll +++ b/llvm/test/CodeGen/PowerPC/testComparesllneull.ll @@ -6,7 +6,7 @@ ; RUN: -ppc-gpr-icmps=all -ppc-asm-full-reg-names -mcpu=pwr8 < %s | FileCheck %s --check-prefix=CHECK-LE \ ; RUN: --implicit-check-not cmpw --implicit-check-not cmpd --implicit-check-not cmpl -@glob = common local_unnamed_addr global i64 0, align 8 +@glob = local_unnamed_addr global i64 0, align 8 define i64 @test_llneull(i64 %a, i64 %b) { ; CHECK-LABEL: test_llneull: diff --git a/llvm/test/CodeGen/PowerPC/zext-and-cmp.ll b/llvm/test/CodeGen/PowerPC/zext-and-cmp.ll index b06a384d73b30..69474bd0805ad 100644 --- a/llvm/test/CodeGen/PowerPC/zext-and-cmp.ll +++ b/llvm/test/CodeGen/PowerPC/zext-and-cmp.ll @@ -4,7 +4,7 @@ ; to zero can be simplifed by using the record form when one of its operands ; is known to be zero extended. -@k = common local_unnamed_addr global i32 0, align 4 +@k = local_unnamed_addr global i32 0, align 4 ; Function Attrs: norecurse nounwind define signext i32 @cmplwi(i32* nocapture readonly %p, i32* nocapture readonly %q, i32 signext %j, i32 signext %r10) { From 0ae02fd71a3828209df37239910568ecde68912a Mon Sep 17 00:00:00 2001 From: Saleem Abdulrasool Date: Fri, 20 Sep 2019 20:46:33 +0000 Subject: [PATCH 32/71] Unwind: avoid warning about unused typedef Move the definition of Elf_Addr typedef to the only place it is used, to avoid: ``` llvm-project/libunwind/src/AddressSpace.hpp:501:28: warning: unused typedef 'Elf_Addr' [-Wunused-local-typedef] ``` when compiling for Android with _LIBUNWIND_ARM_EHABI defined and _LIBUNWIND_SUPPORT_DWARF_UNWIND not defined. Patch by Joel Klinghed! llvm-svn: 372427 --- libunwind/src/AddressSpace.hpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/libunwind/src/AddressSpace.hpp b/libunwind/src/AddressSpace.hpp index 2c9a083be2ace..bf57fdacbe6a7 100644 --- a/libunwind/src/AddressSpace.hpp +++ b/libunwind/src/AddressSpace.hpp @@ -497,9 +497,6 @@ inline bool LocalAddressSpace::findUnwindSections(pint_t targetAddr, #if !defined(Elf_Phdr) typedef ElfW(Phdr) Elf_Phdr; #endif -#if !defined(Elf_Addr) && defined(__ANDROID__) - typedef ElfW(Addr) Elf_Addr; -#endif #if defined(_LIBUNWIND_SUPPORT_DWARF_UNWIND) #if !defined(_LIBUNWIND_SUPPORT_DWARF_INDEX) @@ -507,6 +504,9 @@ inline bool LocalAddressSpace::findUnwindSections(pint_t targetAddr, #endif size_t object_length; #if defined(__ANDROID__) +#if !defined(Elf_Addr) + typedef ElfW(Addr) Elf_Addr; +#endif Elf_Addr image_base = pinfo->dlpi_phnum ? reinterpret_cast(pinfo->dlpi_phdr) - From 01a3080960eec85ca85467a3930e30ac3e93ca0c Mon Sep 17 00:00:00 2001 From: DeForest Richards Date: Fri, 20 Sep 2019 20:51:33 +0000 Subject: [PATCH 33/71] [Docs] Move topics to new categories This commit moves several topics to new categories. llvm-svn: 372428 --- llvm/docs/ProgrammingDocumentation.rst | 9 --------- llvm/docs/SubsystemDocumentation.rst | 5 ----- llvm/docs/UserGuides.rst | 9 --------- llvm/docs/index.rst | 28 ++++++++++++++++++++++---- 4 files changed, 24 insertions(+), 27 deletions(-) diff --git a/llvm/docs/ProgrammingDocumentation.rst b/llvm/docs/ProgrammingDocumentation.rst index 85bf39241dfa3..fa8f114b22a30 100644 --- a/llvm/docs/ProgrammingDocumentation.rst +++ b/llvm/docs/ProgrammingDocumentation.rst @@ -7,9 +7,7 @@ For developers of applications which use LLVM as a library. :hidden: Atomics - CodingStandards CommandLine - CompilerWriterInfo ExtendingLLVM HowToSetUpLLVMStyleRTTI ProgrammersManual @@ -33,10 +31,6 @@ For developers of applications which use LLVM as a library. :doc:`CommandLine` Provides information on using the command line parsing library. -:doc:`CodingStandards` - Details the LLVM coding standards and provides useful information on writing - efficient C++ code. - :doc:`HowToSetUpLLVMStyleRTTI` How to make ``isa<>``, ``dyn_cast<>``, etc. available for clients of your class hierarchy. @@ -44,9 +38,6 @@ For developers of applications which use LLVM as a library. :doc:`ExtendingLLVM` Look here to see how to add instructions and intrinsics to LLVM. -:doc:`CompilerWriterInfo` - A list of helpful links for compiler writers. - :doc:`LibFuzzer` A library for writing in-process guided fuzzers. diff --git a/llvm/docs/SubsystemDocumentation.rst b/llvm/docs/SubsystemDocumentation.rst index 2d3882a6b6f35..cac0ce85b1f5d 100644 --- a/llvm/docs/SubsystemDocumentation.rst +++ b/llvm/docs/SubsystemDocumentation.rst @@ -43,7 +43,6 @@ For API clients and LLVM developers. TypeMetadata TransformMetadata FaultMaps - MIRLangRef Coroutines GlobalISel XRay @@ -67,10 +66,6 @@ For API clients and LLVM developers. working on retargetting LLVM to a new architecture, designing a new codegen pass, or enhancing existing components. -:doc:`Machine IR (MIR) Format Reference Manual ` - A reference manual for the MIR serialization format, which is used to test - LLVM's code generation passes. - :doc:`TableGen ` Describes the TableGen tool, which is used heavily by the LLVM code generator. diff --git a/llvm/docs/UserGuides.rst b/llvm/docs/UserGuides.rst index 962fd14974319..9dfab67f42eb3 100644 --- a/llvm/docs/UserGuides.rst +++ b/llvm/docs/UserGuides.rst @@ -18,8 +18,6 @@ intermediate LLVM representation. HowToBuildWithPGO HowToCrossCompileBuiltinsOnArm HowToCrossCompileLLVM - GettingStartedVS - FAQ yaml2obj MarkdownQuickstartTemplate Phabricator @@ -53,16 +51,9 @@ intermediate LLVM representation. :doc:`HowToCrossCompileLLVM` Notes on cross-building and testing LLVM/Clang. -:doc:`GettingStartedVS` - An addendum to the main Getting Started guide for those using Visual Studio - on Windows. - :doc:`Passes` A list of optimizations and analyses implemented in LLVM. -:doc:`FAQ` - A list of common questions and problems and their solutions. - :doc:`TestSuiteGuide` Describes how to compile and run the test-suite benchmarks. diff --git a/llvm/docs/index.rst b/llvm/docs/index.rst index ef7ae86baab87..a9abd97c373b8 100644 --- a/llvm/docs/index.rst +++ b/llvm/docs/index.rst @@ -21,11 +21,8 @@ Several introductory papers and presentations. .. toctree:: :hidden: - LangRef Lexicon - -:doc:`LangRef` - Defines the LLVM intermediate representation. + FAQ `Introduction to the LLVM Compiler`__ Presentation providing a users introduction to LLVM. @@ -54,6 +51,9 @@ Several introductory papers and presentations. :doc:`Lexicon` Definition of acronyms, terms and concepts used in LLVM. +:doc:`FAQ` + A list of common questions and problems and their solutions. + Documentation ============= @@ -83,6 +83,7 @@ Getting Started/Tutorials GettingStarted tutorial/index + GettingStartedVS :doc:`GettingStarted` Discusses how to get up and running quickly with the LLVM infrastructure. @@ -93,6 +94,10 @@ Getting Started/Tutorials Tutorials about using LLVM. Includes a tutorial about making a custom language with LLVM. +:doc:`GettingStartedVS` + An addendum to the main Getting Started guide for those using Visual Studio + on Windows. + Reference --------- @@ -104,8 +109,11 @@ LLVM and API reference documentation. .. toctree:: :hidden: + LangRef CommandGuide/index TestingGuide + CompilerWriterInfo + MIRLangRef :doc:`LLVM Language Reference Manual ` Defines the LLVM intermediate representation and the assembly form of the @@ -118,6 +126,13 @@ LLVM and API reference documentation. :doc:`LLVM Testing Infrastructure Guide ` A reference manual for using the LLVM testing infrastructure. +:doc:`CompilerWriterInfo` + A list of helpful links for compiler writers. + +:doc:`Machine IR (MIR) Format Reference Manual ` + A reference manual for the MIR serialization format, which is used to test + LLVM's code generation passes. + `Doxygen generated documentation `_ (`classes `_) @@ -147,6 +162,7 @@ LLVM welcomes contributions of all kinds. To get started, please review the foll Phabricator HowToSubmitABug BugLifeCycle + CodingStandards :doc:`Contributing` An overview on how to contribute to LLVM. @@ -169,6 +185,10 @@ LLVM welcomes contributions of all kinds. To get started, please review the foll :doc:`BugLifeCycle` Describes how bugs are reported, triaged and closed. +:doc:`CodingStandards` + Details the LLVM coding standards and provides useful information on writing + efficient C++ code. + Development Process ------------------- From 2e0c95edfe0fbbded0835c3e5ec341c9a28b30e6 Mon Sep 17 00:00:00 2001 From: Simon Pilgrim Date: Fri, 20 Sep 2019 20:52:21 +0000 Subject: [PATCH 34/71] [AddressSanitizer] Don't dereference dyn_cast results. NFCI. The static analyzer is warning about potential null dereference, but we can use cast directly and if not assert will fire for us. llvm-svn: 372429 --- llvm/lib/Transforms/Instrumentation/AddressSanitizer.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/llvm/lib/Transforms/Instrumentation/AddressSanitizer.cpp b/llvm/lib/Transforms/Instrumentation/AddressSanitizer.cpp index 21280f2d6970f..b58a9436a200e 100644 --- a/llvm/lib/Transforms/Instrumentation/AddressSanitizer.cpp +++ b/llvm/lib/Transforms/Instrumentation/AddressSanitizer.cpp @@ -1048,7 +1048,7 @@ struct FunctionStackPoisoner : public InstVisitor { if (!II.isLifetimeStartOrEnd()) return; // Found lifetime intrinsic, add ASan instrumentation if necessary. - ConstantInt *Size = dyn_cast(II.getArgOperand(0)); + auto *Size = cast(II.getArgOperand(0)); // If size argument is undefined, don't do anything. if (Size->isMinusOne()) return; // Check that size doesn't saturate uint64_t and can @@ -1790,7 +1790,7 @@ void ModuleAddressSanitizer::createInitializerPoisonCalls( // Must have a function or null ptr. if (Function *F = dyn_cast(CS->getOperand(1))) { if (F->getName() == kAsanModuleCtorName) continue; - ConstantInt *Priority = dyn_cast(CS->getOperand(0)); + auto *Priority = cast(CS->getOperand(0)); // Don't instrument CTORs that will run before asan.module_ctor. if (Priority->getLimitedValue() <= GetCtorAndDtorPriority(TargetTriple)) continue; From 63ddbc2fbc31f2ef32f61d7c603d42bb92a7dcbd Mon Sep 17 00:00:00 2001 From: Simon Pilgrim Date: Fri, 20 Sep 2019 21:27:49 +0000 Subject: [PATCH 35/71] [PPC] PPCLoopPreIncPrep - silence static analyzer null dereference warning. llvm-svn: 372430 --- llvm/lib/Target/PowerPC/PPCLoopPreIncPrep.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/llvm/lib/Target/PowerPC/PPCLoopPreIncPrep.cpp b/llvm/lib/Target/PowerPC/PPCLoopPreIncPrep.cpp index 4d45d96d4479f..a3c52a8d64794 100644 --- a/llvm/lib/Target/PowerPC/PPCLoopPreIncPrep.cpp +++ b/llvm/lib/Target/PowerPC/PPCLoopPreIncPrep.cpp @@ -481,7 +481,7 @@ bool PPCLoopPreIncPrep::runOnLoop(Loop *L) { if (PtrIP && isa(NewBasePtr) && cast(NewBasePtr)->getParent() == PtrIP->getParent()) PtrIP = nullptr; - else if (isa(PtrIP)) + else if (PtrIP && isa(PtrIP)) PtrIP = &*PtrIP->getParent()->getFirstInsertionPt(); else if (!PtrIP) PtrIP = I->Instr; From eacbe1cccc40ddd8874fcdbbee2cb9f8a842f4b5 Mon Sep 17 00:00:00 2001 From: DeForest Richards Date: Fri, 20 Sep 2019 22:16:39 +0000 Subject: [PATCH 36/71] [Docs] Add a custom sidebar to doc pages Adds a custom sidebar to LLVM docs. Sidebar includes links to How to submit a bug and FAQ topics, as well as a Show Source link and search box. llvm-svn: 372432 --- llvm/docs/_templates/indexsidebar.html | 9 +++++++-- llvm/docs/conf.py | 11 +++++++++-- 2 files changed, 16 insertions(+), 4 deletions(-) diff --git a/llvm/docs/_templates/indexsidebar.html b/llvm/docs/_templates/indexsidebar.html index 416174279ce48..dbd85f06a048f 100644 --- a/llvm/docs/_templates/indexsidebar.html +++ b/llvm/docs/_templates/indexsidebar.html @@ -3,5 +3,10 @@

Bugs

-

LLVM bugs should be reported to - Bugzilla.

+

Information on submitting bugs can be found + here.

+ +

FAQ

+ +

A list of + frequently asked questions about LLVM.

\ No newline at end of file diff --git a/llvm/docs/conf.py b/llvm/docs/conf.py index a0357cf3cb8ac..c92ede3ea44b6 100644 --- a/llvm/docs/conf.py +++ b/llvm/docs/conf.py @@ -99,7 +99,7 @@ # Theme options are theme-specific and customize the look and feel of a theme # further. For a list of options available for each theme, see the # documentation. -html_theme_options = { "nosidebar": True } +html_theme_options = { "nosidebar": False } # Add any paths that contain custom themes here, relative to this directory. html_theme_path = ["_themes"] @@ -134,7 +134,14 @@ #html_use_smartypants = True # Custom sidebar templates, maps document names to template names. -html_sidebars = {'index': 'indexsidebar.html'} + +html_sidebars = { + '**': [ + 'indexsidebar.html', + 'sourcelink.html', + 'searchbox.html', + ] +} # Additional templates that should be rendered to pages, maps page names to # template names. From 4a58936716e5733662ca1f46734594db0a0e67b9 Mon Sep 17 00:00:00 2001 From: Sterling Augustine Date: Fri, 20 Sep 2019 22:26:55 +0000 Subject: [PATCH 37/71] Fix missed case of switching getConstant to getTargetConstant. Try 2. Summary: This fixes a crasher introduced by r372338. Reviewers: echristo, arsenm Subscribers: wdng, hiraditya, llvm-commits Tags: #llvm Differential Revision: https://reviews.llvm.org/D67850 llvm-svn: 372434 --- llvm/lib/Target/X86/X86ISelLowering.cpp | 2 +- .../X86/isel-blendi-gettargetconstant.ll | 19 +++++++++++++++++++ 2 files changed, 20 insertions(+), 1 deletion(-) create mode 100644 llvm/test/CodeGen/X86/isel-blendi-gettargetconstant.ll diff --git a/llvm/lib/Target/X86/X86ISelLowering.cpp b/llvm/lib/Target/X86/X86ISelLowering.cpp index 58af2b37e5374..dec3773e1ddee 100644 --- a/llvm/lib/Target/X86/X86ISelLowering.cpp +++ b/llvm/lib/Target/X86/X86ISelLowering.cpp @@ -17608,7 +17608,7 @@ SDValue X86TargetLowering::LowerINSERT_VECTOR_ELT(SDValue Op, // operand form. N1 = DAG.getNode(ISD::SCALAR_TO_VECTOR, dl, MVT::v4f32, N1); return DAG.getNode(X86ISD::BLENDI, dl, VT, N0, N1, - DAG.getConstant(1, dl, MVT::i8)); + DAG.getTargetConstant(1, dl, MVT::i8)); } // Create this as a scalar to vector.. N1 = DAG.getNode(ISD::SCALAR_TO_VECTOR, dl, MVT::v4f32, N1); diff --git a/llvm/test/CodeGen/X86/isel-blendi-gettargetconstant.ll b/llvm/test/CodeGen/X86/isel-blendi-gettargetconstant.ll new file mode 100644 index 0000000000000..b43e2e5a5fbd1 --- /dev/null +++ b/llvm/test/CodeGen/X86/isel-blendi-gettargetconstant.ll @@ -0,0 +1,19 @@ +; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py +; RUN: llc < %s -mtriple=x86_64-linux-gnu -mattr=sse4.2 | FileCheck %s + +define void @csrot_(float* %0) { +; CHECK-LABEL: csrot_: +; CHECK: # %bb.0: +; CHECK-NEXT: movss {{.*#+}} xmm0 = mem[0],zero,zero,zero +; CHECK-NEXT: movss {{.*#+}} xmm1 = mem[0],zero,zero,zero +; CHECK-NEXT: xorps %xmm0, %xmm1 +; CHECK-NEXT: blendps {{.*#+}} xmm1 = xmm1[0],mem[1,2,3] +; CHECK-NEXT: movlps %xmm1, (%rax) +; CHECK-NEXT: retq +1: + %2 = load float, float* %0, align 4 + %3 = fsub float -0.000000e+00, %2 + %4 = insertelement <2 x float> , float %3, i32 0 + store <2 x float> %4, <2 x float>* undef, align 8 + ret void +} From 819c1651f723b51490eb98b3fc11cbd7dafc7831 Mon Sep 17 00:00:00 2001 From: Ulrich Weigand Date: Fri, 20 Sep 2019 23:04:45 +0000 Subject: [PATCH 38/71] [SystemZ] Support z15 processor name The recently announced IBM z15 processor implements the architecture already supported as "arch13" in LLVM. This patch adds support for "z15" as an alternate architecture name for arch13. The patch also uses z15 in a number of places where we used arch13 as long as the official name was not yet announced. llvm-svn: 372435 --- llvm/lib/Support/Host.cpp | 2 +- .../Target/SystemZ/SystemZISelLowering.cpp | 2 +- llvm/lib/Target/SystemZ/SystemZProcessors.td | 3 +- llvm/lib/Target/SystemZ/SystemZSchedule.td | 2 +- ...cheduleArch13.td => SystemZScheduleZ15.td} | 64 +++++++++---------- .../SystemZ/SystemZTargetTransformInfo.cpp | 2 +- .../Analysis/CostModel/SystemZ/fp-cast.ll | 36 +++++------ .../Analysis/CostModel/SystemZ/intrinsics.ll | 22 +++---- .../CostModel/SystemZ/logic-miscext3.ll | 24 +++---- llvm/test/CodeGen/SystemZ/cond-move-01.ll | 2 +- llvm/test/CodeGen/SystemZ/cond-move-02.ll | 2 +- llvm/test/CodeGen/SystemZ/cond-move-03.ll | 2 +- llvm/test/CodeGen/SystemZ/cond-move-06.ll | 2 +- llvm/test/CodeGen/SystemZ/cond-move-07.ll | 2 +- llvm/test/CodeGen/SystemZ/cond-move-08.mir | 4 +- llvm/test/CodeGen/SystemZ/ctpop-02.ll | 4 +- llvm/test/CodeGen/SystemZ/not-01.ll | 4 +- llvm/test/CodeGen/SystemZ/vec-bswap-01.ll | 2 +- llvm/test/CodeGen/SystemZ/vec-bswap-02.ll | 2 +- llvm/test/CodeGen/SystemZ/vec-bswap-03.ll | 2 +- llvm/test/CodeGen/SystemZ/vec-bswap-04.ll | 2 +- llvm/test/CodeGen/SystemZ/vec-bswap-05.ll | 2 +- llvm/test/CodeGen/SystemZ/vec-bswap-06.ll | 2 +- llvm/test/CodeGen/SystemZ/vec-bswap-07.ll | 2 +- llvm/test/CodeGen/SystemZ/vec-conv-03.ll | 4 +- llvm/test/CodeGen/SystemZ/vec-eswap-01.ll | 2 +- llvm/test/CodeGen/SystemZ/vec-eswap-02.ll | 2 +- .../test/CodeGen/SystemZ/vec-intrinsics-03.ll | 4 +- .../CodeGen/SystemZ/vec-strict-conv-03.ll | 4 +- .../{insns-arch13.txt => insns-z15.txt} | 4 +- .../{insn-bad-arch13.s => insn-bad-z15.s} | 4 +- .../{insn-good-arch13.s => insn-good-z15.s} | 4 +- 32 files changed, 113 insertions(+), 108 deletions(-) rename llvm/lib/Target/SystemZ/{SystemZScheduleArch13.td => SystemZScheduleZ15.td} (97%) rename llvm/test/MC/Disassembler/SystemZ/{insns-arch13.txt => insns-z15.txt} (99%) rename llvm/test/MC/SystemZ/{insn-bad-arch13.s => insn-bad-z15.s} (99%) rename llvm/test/MC/SystemZ/{insn-good-arch13.s => insn-good-z15.s} (99%) diff --git a/llvm/lib/Support/Host.cpp b/llvm/lib/Support/Host.cpp index 0d6fab50424c4..5509ec0088627 100644 --- a/llvm/lib/Support/Host.cpp +++ b/llvm/lib/Support/Host.cpp @@ -316,7 +316,7 @@ StringRef sys::detail::getHostCPUNameForS390x(StringRef ProcCpuinfoContent) { unsigned int Id; if (!Lines[I].drop_front(Pos).getAsInteger(10, Id)) { if (Id >= 8561 && HaveVectorSupport) - return "arch13"; + return "z15"; if (Id >= 3906 && HaveVectorSupport) return "z14"; if (Id >= 2964 && HaveVectorSupport) diff --git a/llvm/lib/Target/SystemZ/SystemZISelLowering.cpp b/llvm/lib/Target/SystemZ/SystemZISelLowering.cpp index aaf7c580ea5ca..6a0f59ef56a42 100644 --- a/llvm/lib/Target/SystemZ/SystemZISelLowering.cpp +++ b/llvm/lib/Target/SystemZ/SystemZISelLowering.cpp @@ -258,7 +258,7 @@ SystemZTargetLowering::SystemZTargetLowering(const TargetMachine &TM, setOperationAction(ISD::CTLZ_ZERO_UNDEF, MVT::i32, Promote); setOperationAction(ISD::CTLZ, MVT::i64, Legal); - // On arch13 we have native support for a 64-bit CTPOP. + // On z15 we have native support for a 64-bit CTPOP. if (Subtarget.hasMiscellaneousExtensions3()) { setOperationAction(ISD::CTPOP, MVT::i32, Promote); setOperationAction(ISD::CTPOP, MVT::i64, Legal); diff --git a/llvm/lib/Target/SystemZ/SystemZProcessors.td b/llvm/lib/Target/SystemZ/SystemZProcessors.td index b27c25beb58ca..af33a03005524 100644 --- a/llvm/lib/Target/SystemZ/SystemZProcessors.td +++ b/llvm/lib/Target/SystemZ/SystemZProcessors.td @@ -35,5 +35,6 @@ def : ProcessorModel<"z13", Z13Model, Arch11SupportedFeatures.List>; def : ProcessorModel<"arch12", Z14Model, Arch12SupportedFeatures.List>; def : ProcessorModel<"z14", Z14Model, Arch12SupportedFeatures.List>; -def : ProcessorModel<"arch13", Arch13Model, Arch13SupportedFeatures.List>; +def : ProcessorModel<"arch13", Z15Model, Arch13SupportedFeatures.List>; +def : ProcessorModel<"z15", Z15Model, Arch13SupportedFeatures.List>; diff --git a/llvm/lib/Target/SystemZ/SystemZSchedule.td b/llvm/lib/Target/SystemZ/SystemZSchedule.td index 98eca28022423..119e3ee7c22c6 100644 --- a/llvm/lib/Target/SystemZ/SystemZSchedule.td +++ b/llvm/lib/Target/SystemZ/SystemZSchedule.td @@ -59,7 +59,7 @@ def VBU : SchedWrite; // Virtual branching unit def MCD : SchedWrite; // Millicode -include "SystemZScheduleArch13.td" +include "SystemZScheduleZ15.td" include "SystemZScheduleZ14.td" include "SystemZScheduleZ13.td" include "SystemZScheduleZEC12.td" diff --git a/llvm/lib/Target/SystemZ/SystemZScheduleArch13.td b/llvm/lib/Target/SystemZ/SystemZScheduleZ15.td similarity index 97% rename from llvm/lib/Target/SystemZ/SystemZScheduleArch13.td rename to llvm/lib/Target/SystemZ/SystemZScheduleZ15.td index 9f82f24d0e8f3..56ceb88f35d4f 100644 --- a/llvm/lib/Target/SystemZ/SystemZScheduleArch13.td +++ b/llvm/lib/Target/SystemZ/SystemZScheduleZ15.td @@ -1,4 +1,4 @@ -//-- SystemZScheduleArch13.td - SystemZ Scheduling Definitions ----*- tblgen -*-=// +//-- SystemZScheduleZ15.td - SystemZ Scheduling Definitions ----*- tblgen -*-=// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. @@ -6,14 +6,14 @@ // //===----------------------------------------------------------------------===// // -// This file defines the machine model for Arch13 to support instruction +// This file defines the machine model for Z15 to support instruction // scheduling and other instruction cost heuristics. // // Pseudos expanded right after isel do not need to be modelled here. // //===----------------------------------------------------------------------===// -def Arch13Model : SchedMachineModel { +def Z15Model : SchedMachineModel { let UnsupportedFeatures = Arch13UnsupportedFeatures.List; @@ -27,7 +27,7 @@ def Arch13Model : SchedMachineModel { let MispredictPenalty = 20; } -let SchedModel = Arch13Model in { +let SchedModel = Z15Model in { // These definitions need the SchedModel value. They could be put in a // subtarget common include file, but it seems the include system in Tablegen // currently (2016) rejects multiple includes of same file. @@ -73,43 +73,43 @@ let NumMicroOps = 0 in { } // Execution units. -def Arch13_FXaUnit : ProcResource<2>; -def Arch13_FXbUnit : ProcResource<2>; -def Arch13_LSUnit : ProcResource<2>; -def Arch13_VecUnit : ProcResource<2>; -def Arch13_VecFPdUnit : ProcResource<2> { let BufferSize = 1; /* blocking */ } -def Arch13_VBUnit : ProcResource<2>; -def Arch13_MCD : ProcResource<1>; +def Z15_FXaUnit : ProcResource<2>; +def Z15_FXbUnit : ProcResource<2>; +def Z15_LSUnit : ProcResource<2>; +def Z15_VecUnit : ProcResource<2>; +def Z15_VecFPdUnit : ProcResource<2> { let BufferSize = 1; /* blocking */ } +def Z15_VBUnit : ProcResource<2>; +def Z15_MCD : ProcResource<1>; // Subtarget specific definitions of scheduling resources. let NumMicroOps = 0 in { - def : WriteRes; - def : WriteRes; - def : WriteRes; - def : WriteRes; - def : WriteRes; - def : WriteRes; - def : WriteRes; - def : WriteRes; - def : WriteRes; + def : WriteRes; + def : WriteRes; + def : WriteRes; + def : WriteRes; + def : WriteRes; + def : WriteRes; + def : WriteRes; + def : WriteRes; + def : WriteRes; foreach Num = 2-5 in { let ResourceCycles = [Num] in { - def : WriteRes("FXa"#Num), [Arch13_FXaUnit]>; - def : WriteRes("FXb"#Num), [Arch13_FXbUnit]>; - def : WriteRes("LSU"#Num), [Arch13_LSUnit]>; - def : WriteRes("VecBF"#Num), [Arch13_VecUnit]>; - def : WriteRes("VecDF"#Num), [Arch13_VecUnit]>; - def : WriteRes("VecDFX"#Num), [Arch13_VecUnit]>; - def : WriteRes("VecMul"#Num), [Arch13_VecUnit]>; - def : WriteRes("VecStr"#Num), [Arch13_VecUnit]>; - def : WriteRes("VecXsPm"#Num), [Arch13_VecUnit]>; + def : WriteRes("FXa"#Num), [Z15_FXaUnit]>; + def : WriteRes("FXb"#Num), [Z15_FXbUnit]>; + def : WriteRes("LSU"#Num), [Z15_LSUnit]>; + def : WriteRes("VecBF"#Num), [Z15_VecUnit]>; + def : WriteRes("VecDF"#Num), [Z15_VecUnit]>; + def : WriteRes("VecDFX"#Num), [Z15_VecUnit]>; + def : WriteRes("VecMul"#Num), [Z15_VecUnit]>; + def : WriteRes("VecStr"#Num), [Z15_VecUnit]>; + def : WriteRes("VecXsPm"#Num), [Z15_VecUnit]>; }} - def : WriteRes { let ResourceCycles = [30]; } + def : WriteRes { let ResourceCycles = [30]; } - def : WriteRes; // Virtual Branching Unit + def : WriteRes; // Virtual Branching Unit } -def : WriteRes { let NumMicroOps = 3; +def : WriteRes { let NumMicroOps = 3; let BeginGroup = 1; let EndGroup = 1; } diff --git a/llvm/lib/Target/SystemZ/SystemZTargetTransformInfo.cpp b/llvm/lib/Target/SystemZ/SystemZTargetTransformInfo.cpp index 145cf87ef9f59..8d45e67d73c26 100644 --- a/llvm/lib/Target/SystemZ/SystemZTargetTransformInfo.cpp +++ b/llvm/lib/Target/SystemZ/SystemZTargetTransformInfo.cpp @@ -707,7 +707,7 @@ int SystemZTTIImpl::getCastInstrCost(unsigned Opcode, Type *Dst, Type *Src, // TODO: Fix base implementation which could simplify things a bit here // (seems to miss on differentiating on scalar/vector types). - // Only 64 bit vector conversions are natively supported before arch13. + // Only 64 bit vector conversions are natively supported before z15. if (DstScalarBits == 64 || ST->hasVectorEnhancements2()) { if (SrcScalarBits == DstScalarBits) return NumDstVectors; diff --git a/llvm/test/Analysis/CostModel/SystemZ/fp-cast.ll b/llvm/test/Analysis/CostModel/SystemZ/fp-cast.ll index 9a43ca318384b..0c95b537340ce 100644 --- a/llvm/test/Analysis/CostModel/SystemZ/fp-cast.ll +++ b/llvm/test/Analysis/CostModel/SystemZ/fp-cast.ll @@ -1,7 +1,7 @@ ; RUN: opt < %s -cost-model -analyze -mtriple=systemz-unknown -mcpu=z13 \ ; RUN: | FileCheck %s -check-prefixes=CHECK,Z13 -; RUN: opt < %s -cost-model -analyze -mtriple=systemz-unknown -mcpu=arch13 \ -; RUN: | FileCheck %s -check-prefixes=CHECK,AR13 +; RUN: opt < %s -cost-model -analyze -mtriple=systemz-unknown -mcpu=z15 \ +; RUN: | FileCheck %s -check-prefixes=CHECK,Z15 ; ; Note: The scalarized vector instructions costs are not including any ; extracts, due to the undef operands. @@ -118,7 +118,7 @@ define void @fptosi() { ; CHECK: Cost Model: Found an estimated cost of 6 for instruction: %v19 = fptosi <2 x double> undef to <2 x i8> ; CHECK: Cost Model: Found an estimated cost of 5 for instruction: %v20 = fptosi <2 x float> undef to <2 x i64> ; Z13: Cost Model: Found an estimated cost of 12 for instruction: %v21 = fptosi <2 x float> undef to <2 x i32> -; AR13: Cost Model: Found an estimated cost of 1 for instruction: %v21 = fptosi <2 x float> undef to <2 x i32> +; Z15: Cost Model: Found an estimated cost of 1 for instruction: %v21 = fptosi <2 x float> undef to <2 x i32> ; CHECK: Cost Model: Found an estimated cost of 6 for instruction: %v22 = fptosi <2 x float> undef to <2 x i16> ; CHECK: Cost Model: Found an estimated cost of 6 for instruction: %v23 = fptosi <2 x float> undef to <2 x i8> ; CHECK: Cost Model: Found an estimated cost of 6 for instruction: %v24 = fptosi <4 x fp128> undef to <4 x i64> @@ -131,7 +131,7 @@ define void @fptosi() { ; CHECK: Cost Model: Found an estimated cost of 12 for instruction: %v31 = fptosi <4 x double> undef to <4 x i8> ; CHECK: Cost Model: Found an estimated cost of 10 for instruction: %v32 = fptosi <4 x float> undef to <4 x i64> ; Z13: Cost Model: Found an estimated cost of 12 for instruction: %v33 = fptosi <4 x float> undef to <4 x i32> -; AR13: Cost Model: Found an estimated cost of 1 for instruction: %v33 = fptosi <4 x float> undef to <4 x i32> +; Z15: Cost Model: Found an estimated cost of 1 for instruction: %v33 = fptosi <4 x float> undef to <4 x i32> ; CHECK: Cost Model: Found an estimated cost of 12 for instruction: %v34 = fptosi <4 x float> undef to <4 x i16> ; CHECK: Cost Model: Found an estimated cost of 12 for instruction: %v35 = fptosi <4 x float> undef to <4 x i8> ; CHECK: Cost Model: Found an estimated cost of 12 for instruction: %v36 = fptosi <8 x fp128> undef to <8 x i64> @@ -144,7 +144,7 @@ define void @fptosi() { ; CHECK: Cost Model: Found an estimated cost of 24 for instruction: %v43 = fptosi <8 x double> undef to <8 x i8> ; CHECK: Cost Model: Found an estimated cost of 20 for instruction: %v44 = fptosi <8 x float> undef to <8 x i64> ; Z13: Cost Model: Found an estimated cost of 24 for instruction: %v45 = fptosi <8 x float> undef to <8 x i32> -; AR13: Cost Model: Found an estimated cost of 2 for instruction: %v45 = fptosi <8 x float> undef to <8 x i32> +; Z15: Cost Model: Found an estimated cost of 2 for instruction: %v45 = fptosi <8 x float> undef to <8 x i32> ; CHECK: Cost Model: Found an estimated cost of 24 for instruction: %v46 = fptosi <8 x float> undef to <8 x i16> ; CHECK: Cost Model: Found an estimated cost of 24 for instruction: %v47 = fptosi <8 x float> undef to <8 x i8> ; CHECK: Cost Model: Found an estimated cost of 8 for instruction: %v48 = fptosi <16 x double> undef to <16 x i64> @@ -153,7 +153,7 @@ define void @fptosi() { ; CHECK: Cost Model: Found an estimated cost of 48 for instruction: %v51 = fptosi <16 x double> undef to <16 x i8> ; CHECK: Cost Model: Found an estimated cost of 40 for instruction: %v52 = fptosi <16 x float> undef to <16 x i64> ; Z13: Cost Model: Found an estimated cost of 48 for instruction: %v53 = fptosi <16 x float> undef to <16 x i32> -; AR13: Cost Model: Found an estimated cost of 4 for instruction: %v53 = fptosi <16 x float> undef to <16 x i32> +; Z15: Cost Model: Found an estimated cost of 4 for instruction: %v53 = fptosi <16 x float> undef to <16 x i32> ; CHECK: Cost Model: Found an estimated cost of 48 for instruction: %v54 = fptosi <16 x float> undef to <16 x i16> ; CHECK: Cost Model: Found an estimated cost of 48 for instruction: %v55 = fptosi <16 x float> undef to <16 x i8> @@ -241,7 +241,7 @@ define void @fptoui() { ; CHECK: Cost Model: Found an estimated cost of 6 for instruction: %v19 = fptoui <2 x double> undef to <2 x i8> ; CHECK: Cost Model: Found an estimated cost of 5 for instruction: %v20 = fptoui <2 x float> undef to <2 x i64> ; Z13: Cost Model: Found an estimated cost of 12 for instruction: %v21 = fptoui <2 x float> undef to <2 x i32> -; AR13: Cost Model: Found an estimated cost of 1 for instruction: %v21 = fptoui <2 x float> undef to <2 x i32> +; Z15: Cost Model: Found an estimated cost of 1 for instruction: %v21 = fptoui <2 x float> undef to <2 x i32> ; CHECK: Cost Model: Found an estimated cost of 6 for instruction: %v22 = fptoui <2 x float> undef to <2 x i16> ; CHECK: Cost Model: Found an estimated cost of 6 for instruction: %v23 = fptoui <2 x float> undef to <2 x i8> ; CHECK: Cost Model: Found an estimated cost of 6 for instruction: %v24 = fptoui <4 x fp128> undef to <4 x i64> @@ -254,7 +254,7 @@ define void @fptoui() { ; CHECK: Cost Model: Found an estimated cost of 12 for instruction: %v31 = fptoui <4 x double> undef to <4 x i8> ; CHECK: Cost Model: Found an estimated cost of 10 for instruction: %v32 = fptoui <4 x float> undef to <4 x i64> ; Z13: Cost Model: Found an estimated cost of 12 for instruction: %v33 = fptoui <4 x float> undef to <4 x i32> -; AR13: Cost Model: Found an estimated cost of 1 for instruction: %v33 = fptoui <4 x float> undef to <4 x i32> +; Z15: Cost Model: Found an estimated cost of 1 for instruction: %v33 = fptoui <4 x float> undef to <4 x i32> ; CHECK: Cost Model: Found an estimated cost of 12 for instruction: %v34 = fptoui <4 x float> undef to <4 x i16> ; CHECK: Cost Model: Found an estimated cost of 12 for instruction: %v35 = fptoui <4 x float> undef to <4 x i8> ; CHECK: Cost Model: Found an estimated cost of 12 for instruction: %v36 = fptoui <8 x fp128> undef to <8 x i64> @@ -267,7 +267,7 @@ define void @fptoui() { ; CHECK: Cost Model: Found an estimated cost of 24 for instruction: %v43 = fptoui <8 x double> undef to <8 x i8> ; CHECK: Cost Model: Found an estimated cost of 20 for instruction: %v44 = fptoui <8 x float> undef to <8 x i64> ; Z13: Cost Model: Found an estimated cost of 24 for instruction: %v45 = fptoui <8 x float> undef to <8 x i32> -; AR13: Cost Model: Found an estimated cost of 2 for instruction: %v45 = fptoui <8 x float> undef to <8 x i32> +; Z15: Cost Model: Found an estimated cost of 2 for instruction: %v45 = fptoui <8 x float> undef to <8 x i32> ; CHECK: Cost Model: Found an estimated cost of 24 for instruction: %v46 = fptoui <8 x float> undef to <8 x i16> ; CHECK: Cost Model: Found an estimated cost of 24 for instruction: %v47 = fptoui <8 x float> undef to <8 x i8> ; CHECK: Cost Model: Found an estimated cost of 8 for instruction: %v48 = fptoui <16 x double> undef to <16 x i64> @@ -276,7 +276,7 @@ define void @fptoui() { ; CHECK: Cost Model: Found an estimated cost of 48 for instruction: %v51 = fptoui <16 x double> undef to <16 x i8> ; CHECK: Cost Model: Found an estimated cost of 40 for instruction: %v52 = fptoui <16 x float> undef to <16 x i64> ; Z13: Cost Model: Found an estimated cost of 48 for instruction: %v53 = fptoui <16 x float> undef to <16 x i32> -; AR13: Cost Model: Found an estimated cost of 4 for instruction: %v53 = fptoui <16 x float> undef to <16 x i32> +; Z15: Cost Model: Found an estimated cost of 4 for instruction: %v53 = fptoui <16 x float> undef to <16 x i32> ; CHECK: Cost Model: Found an estimated cost of 48 for instruction: %v54 = fptoui <16 x float> undef to <16 x i16> ; CHECK: Cost Model: Found an estimated cost of 48 for instruction: %v55 = fptoui <16 x float> undef to <16 x i8> @@ -391,7 +391,7 @@ define void @sitofp() { ; CHECK: Cost Model: Found an estimated cost of 5 for instruction: %v15 = sitofp <2 x i32> undef to <2 x fp128> ; CHECK: Cost Model: Found an estimated cost of 7 for instruction: %v16 = sitofp <2 x i32> undef to <2 x double> ; Z13: Cost Model: Found an estimated cost of 14 for instruction: %v17 = sitofp <2 x i32> undef to <2 x float> -; AR13: Cost Model: Found an estimated cost of 1 for instruction: %v17 = sitofp <2 x i32> undef to <2 x float> +; Z15: Cost Model: Found an estimated cost of 1 for instruction: %v17 = sitofp <2 x i32> undef to <2 x float> ; CHECK: Cost Model: Found an estimated cost of 7 for instruction: %v18 = sitofp <2 x i16> undef to <2 x fp128> ; CHECK: Cost Model: Found an estimated cost of 9 for instruction: %v19 = sitofp <2 x i16> undef to <2 x double> ; CHECK: Cost Model: Found an estimated cost of 9 for instruction: %v20 = sitofp <2 x i16> undef to <2 x float> @@ -404,7 +404,7 @@ define void @sitofp() { ; CHECK: Cost Model: Found an estimated cost of 9 for instruction: %v27 = sitofp <4 x i32> undef to <4 x fp128> ; CHECK: Cost Model: Found an estimated cost of 13 for instruction: %v28 = sitofp <4 x i32> undef to <4 x double> ; Z13: Cost Model: Found an estimated cost of 13 for instruction: %v29 = sitofp <4 x i32> undef to <4 x float> -; AR13: Cost Model: Found an estimated cost of 1 for instruction: %v29 = sitofp <4 x i32> undef to <4 x float> +; Z15: Cost Model: Found an estimated cost of 1 for instruction: %v29 = sitofp <4 x i32> undef to <4 x float> ; CHECK: Cost Model: Found an estimated cost of 13 for instruction: %v30 = sitofp <4 x i16> undef to <4 x fp128> ; CHECK: Cost Model: Found an estimated cost of 17 for instruction: %v31 = sitofp <4 x i16> undef to <4 x double> ; CHECK: Cost Model: Found an estimated cost of 17 for instruction: %v32 = sitofp <4 x i16> undef to <4 x float> @@ -417,7 +417,7 @@ define void @sitofp() { ; CHECK: Cost Model: Found an estimated cost of 17 for instruction: %v39 = sitofp <8 x i32> undef to <8 x fp128> ; CHECK: Cost Model: Found an estimated cost of 25 for instruction: %v40 = sitofp <8 x i32> undef to <8 x double> ; Z13: Cost Model: Found an estimated cost of 25 for instruction: %v41 = sitofp <8 x i32> undef to <8 x float> -; AR13: Cost Model: Found an estimated cost of 2 for instruction: %v41 = sitofp <8 x i32> undef to <8 x float> +; Z15: Cost Model: Found an estimated cost of 2 for instruction: %v41 = sitofp <8 x i32> undef to <8 x float> ; CHECK: Cost Model: Found an estimated cost of 25 for instruction: %v42 = sitofp <8 x i16> undef to <8 x fp128> ; CHECK: Cost Model: Found an estimated cost of 33 for instruction: %v43 = sitofp <8 x i16> undef to <8 x double> ; CHECK: Cost Model: Found an estimated cost of 33 for instruction: %v44 = sitofp <8 x i16> undef to <8 x float> @@ -428,7 +428,7 @@ define void @sitofp() { ; CHECK: Cost Model: Found an estimated cost of 49 for instruction: %v49 = sitofp <16 x i64> undef to <16 x float> ; CHECK: Cost Model: Found an estimated cost of 49 for instruction: %v50 = sitofp <16 x i32> undef to <16 x double> ; Z13: Cost Model: Found an estimated cost of 49 for instruction: %v51 = sitofp <16 x i32> undef to <16 x float> -; AR13: Cost Model: Found an estimated cost of 4 for instruction: %v51 = sitofp <16 x i32> undef to <16 x float> +; Z15: Cost Model: Found an estimated cost of 4 for instruction: %v51 = sitofp <16 x i32> undef to <16 x float> ; CHECK: Cost Model: Found an estimated cost of 65 for instruction: %v52 = sitofp <16 x i16> undef to <16 x double> ; CHECK: Cost Model: Found an estimated cost of 65 for instruction: %v53 = sitofp <16 x i16> undef to <16 x float> ; CHECK: Cost Model: Found an estimated cost of 65 for instruction: %v54 = sitofp <16 x i8> undef to <16 x double> @@ -513,7 +513,7 @@ define void @uitofp() { ; CHECK: Cost Model: Found an estimated cost of 5 for instruction: %v15 = uitofp <2 x i32> undef to <2 x fp128> ; CHECK: Cost Model: Found an estimated cost of 7 for instruction: %v16 = uitofp <2 x i32> undef to <2 x double> ; Z13: Cost Model: Found an estimated cost of 14 for instruction: %v17 = uitofp <2 x i32> undef to <2 x float> -; AR13: Cost Model: Found an estimated cost of 1 for instruction: %v17 = uitofp <2 x i32> undef to <2 x float> +; Z15: Cost Model: Found an estimated cost of 1 for instruction: %v17 = uitofp <2 x i32> undef to <2 x float> ; CHECK: Cost Model: Found an estimated cost of 7 for instruction: %v18 = uitofp <2 x i16> undef to <2 x fp128> ; CHECK: Cost Model: Found an estimated cost of 9 for instruction: %v19 = uitofp <2 x i16> undef to <2 x double> ; CHECK: Cost Model: Found an estimated cost of 9 for instruction: %v20 = uitofp <2 x i16> undef to <2 x float> @@ -526,7 +526,7 @@ define void @uitofp() { ; CHECK: Cost Model: Found an estimated cost of 9 for instruction: %v27 = uitofp <4 x i32> undef to <4 x fp128> ; CHECK: Cost Model: Found an estimated cost of 13 for instruction: %v28 = uitofp <4 x i32> undef to <4 x double> ; Z13: Cost Model: Found an estimated cost of 13 for instruction: %v29 = uitofp <4 x i32> undef to <4 x float> -; AR13: Cost Model: Found an estimated cost of 1 for instruction: %v29 = uitofp <4 x i32> undef to <4 x float> +; Z15: Cost Model: Found an estimated cost of 1 for instruction: %v29 = uitofp <4 x i32> undef to <4 x float> ; CHECK: Cost Model: Found an estimated cost of 13 for instruction: %v30 = uitofp <4 x i16> undef to <4 x fp128> ; CHECK: Cost Model: Found an estimated cost of 17 for instruction: %v31 = uitofp <4 x i16> undef to <4 x double> ; CHECK: Cost Model: Found an estimated cost of 17 for instruction: %v32 = uitofp <4 x i16> undef to <4 x float> @@ -539,7 +539,7 @@ define void @uitofp() { ; CHECK: Cost Model: Found an estimated cost of 17 for instruction: %v39 = uitofp <8 x i32> undef to <8 x fp128> ; CHECK: Cost Model: Found an estimated cost of 25 for instruction: %v40 = uitofp <8 x i32> undef to <8 x double> ; Z13: Cost Model: Found an estimated cost of 25 for instruction: %v41 = uitofp <8 x i32> undef to <8 x float> -; AR13: Cost Model: Found an estimated cost of 2 for instruction: %v41 = uitofp <8 x i32> undef to <8 x float> +; Z15: Cost Model: Found an estimated cost of 2 for instruction: %v41 = uitofp <8 x i32> undef to <8 x float> ; CHECK: Cost Model: Found an estimated cost of 25 for instruction: %v42 = uitofp <8 x i16> undef to <8 x fp128> ; CHECK: Cost Model: Found an estimated cost of 33 for instruction: %v43 = uitofp <8 x i16> undef to <8 x double> ; CHECK: Cost Model: Found an estimated cost of 33 for instruction: %v44 = uitofp <8 x i16> undef to <8 x float> @@ -550,7 +550,7 @@ define void @uitofp() { ; CHECK: Cost Model: Found an estimated cost of 49 for instruction: %v49 = uitofp <16 x i64> undef to <16 x float> ; CHECK: Cost Model: Found an estimated cost of 49 for instruction: %v50 = uitofp <16 x i32> undef to <16 x double> ; Z13: Cost Model: Found an estimated cost of 49 for instruction: %v51 = uitofp <16 x i32> undef to <16 x float> -; AR13: Cost Model: Found an estimated cost of 4 for instruction: %v51 = uitofp <16 x i32> undef to <16 x float> +; Z15: Cost Model: Found an estimated cost of 4 for instruction: %v51 = uitofp <16 x i32> undef to <16 x float> ; CHECK: Cost Model: Found an estimated cost of 65 for instruction: %v52 = uitofp <16 x i16> undef to <16 x double> ; CHECK: Cost Model: Found an estimated cost of 65 for instruction: %v53 = uitofp <16 x i16> undef to <16 x float> ; CHECK: Cost Model: Found an estimated cost of 65 for instruction: %v54 = uitofp <16 x i8> undef to <16 x double> diff --git a/llvm/test/Analysis/CostModel/SystemZ/intrinsics.ll b/llvm/test/Analysis/CostModel/SystemZ/intrinsics.ll index bbde627838bc4..4bc0508304f9f 100644 --- a/llvm/test/Analysis/CostModel/SystemZ/intrinsics.ll +++ b/llvm/test/Analysis/CostModel/SystemZ/intrinsics.ll @@ -1,7 +1,7 @@ ; RUN: opt < %s -cost-model -analyze -mtriple=systemz-unknown -mcpu=z13 \ ; RUN: | FileCheck %s -check-prefixes=CHECK,Z13 -; RUN: opt < %s -cost-model -analyze -mtriple=systemz-unknown -mcpu=arch13 \ -; RUN: | FileCheck %s -check-prefixes=CHECK,AR13 +; RUN: opt < %s -cost-model -analyze -mtriple=systemz-unknown -mcpu=z15 \ +; RUN: | FileCheck %s -check-prefixes=CHECK,Z15 define void @bswap_i64(i64 %arg, <2 x i64> %arg2) { ; CHECK: Printing analysis 'Cost Model Analysis' for function 'bswap_i64': @@ -69,15 +69,15 @@ define void @bswap_i64_mem(i64* %src, i64 %arg, i64* %dst) { define void @bswap_v2i64_mem(<2 x i64>* %src, <2 x i64> %arg, <2 x i64>* %dst) { ; CHECK:Printing analysis 'Cost Model Analysis' for function 'bswap_v2i64_mem': ; Z13: Cost Model: Found an estimated cost of 1 for instruction: %Ld1 = load <2 x i64>, <2 x i64>* %src -; AR13: Cost Model: Found an estimated cost of 0 for instruction: %Ld1 = load <2 x i64>, <2 x i64>* %src +; Z15: Cost Model: Found an estimated cost of 0 for instruction: %Ld1 = load <2 x i64>, <2 x i64>* %src ; CHECK: Cost Model: Found an estimated cost of 1 for instruction: %swp1 = tail call <2 x i64> @llvm.bswap.v2i64(<2 x i64> %Ld1) ; CHECK: Cost Model: Found an estimated cost of 1 for instruction: %swp2 = tail call <2 x i64> @llvm.bswap.v2i64(<2 x i64> %arg) ; Z13: Cost Model: Found an estimated cost of 1 for instruction: store <2 x i64> %swp2, <2 x i64>* %dst -; AR13: Cost Model: Found an estimated cost of 0 for instruction: store <2 x i64> %swp2, <2 x i64>* %dst +; Z15: Cost Model: Found an estimated cost of 0 for instruction: store <2 x i64> %swp2, <2 x i64>* %dst ; CHECK: Cost Model: Found an estimated cost of 1 for instruction: %Ld2 = load <2 x i64>, <2 x i64>* %src ; CHECK: Cost Model: Found an estimated cost of 1 for instruction: %swp3 = tail call <2 x i64> @llvm.bswap.v2i64(<2 x i64> %Ld2) ; Z13: Cost Model: Found an estimated cost of 1 for instruction: store <2 x i64> %swp3, <2 x i64>* %dst -; AR13: Cost Model: Found an estimated cost of 0 for instruction: store <2 x i64> %swp3, <2 x i64>* %dst +; Z15: Cost Model: Found an estimated cost of 0 for instruction: store <2 x i64> %swp3, <2 x i64>* %dst %Ld1 = load <2 x i64>, <2 x i64>* %src %swp1 = tail call <2 x i64> @llvm.bswap.v2i64(<2 x i64> %Ld1) @@ -117,15 +117,15 @@ define void @bswap_i32_mem(i32* %src, i32 %arg, i32* %dst) { define void @bswap_v4i32_mem(<4 x i32>* %src, <4 x i32> %arg, <4 x i32>* %dst) { ; CHECK: Printing analysis 'Cost Model Analysis' for function 'bswap_v4i32_mem': ; Z13: Cost Model: Found an estimated cost of 1 for instruction: %Ld1 = load <4 x i32>, <4 x i32>* %src -; AR13: Cost Model: Found an estimated cost of 0 for instruction: %Ld1 = load <4 x i32>, <4 x i32>* %src +; Z15: Cost Model: Found an estimated cost of 0 for instruction: %Ld1 = load <4 x i32>, <4 x i32>* %src ; CHECK: Cost Model: Found an estimated cost of 1 for instruction: %swp1 = tail call <4 x i32> @llvm.bswap.v4i32(<4 x i32> %Ld1) ; CHECK: Cost Model: Found an estimated cost of 1 for instruction: %swp2 = tail call <4 x i32> @llvm.bswap.v4i32(<4 x i32> %arg) ; Z13: Cost Model: Found an estimated cost of 1 for instruction: store <4 x i32> %swp2, <4 x i32>* %dst -; AR13: Cost Model: Found an estimated cost of 0 for instruction: store <4 x i32> %swp2, <4 x i32>* %dst +; Z15: Cost Model: Found an estimated cost of 0 for instruction: store <4 x i32> %swp2, <4 x i32>* %dst ; CHECK: Cost Model: Found an estimated cost of 1 for instruction: %Ld2 = load <4 x i32>, <4 x i32>* %src ; CHECK: Cost Model: Found an estimated cost of 1 for instruction: %swp3 = tail call <4 x i32> @llvm.bswap.v4i32(<4 x i32> %Ld2) ; Z13: Cost Model: Found an estimated cost of 1 for instruction: store <4 x i32> %swp3, <4 x i32>* %dst -; AR13: Cost Model: Found an estimated cost of 0 for instruction: store <4 x i32> %swp3, <4 x i32>* %dst +; Z15: Cost Model: Found an estimated cost of 0 for instruction: store <4 x i32> %swp3, <4 x i32>* %dst %Ld1 = load <4 x i32>, <4 x i32>* %src %swp1 = tail call <4 x i32> @llvm.bswap.v4i32(<4 x i32> %Ld1) @@ -164,15 +164,15 @@ define void @bswap_i16_mem(i16* %src, i16 %arg, i16* %dst) { define void @bswap_v8i16_mem(<8 x i16>* %src, <8 x i16> %arg, <8 x i16>* %dst) { ; CHECK: Printing analysis 'Cost Model Analysis' for function 'bswap_v8i16_mem': ; Z13: Cost Model: Found an estimated cost of 1 for instruction: %Ld1 = load <8 x i16>, <8 x i16>* %src -; AR13: Cost Model: Found an estimated cost of 0 for instruction: %Ld1 = load <8 x i16>, <8 x i16>* %src +; Z15: Cost Model: Found an estimated cost of 0 for instruction: %Ld1 = load <8 x i16>, <8 x i16>* %src ; CHECK: Cost Model: Found an estimated cost of 1 for instruction: %swp1 = tail call <8 x i16> @llvm.bswap.v8i16(<8 x i16> %Ld1) ; CHECK: Cost Model: Found an estimated cost of 1 for instruction: %swp2 = tail call <8 x i16> @llvm.bswap.v8i16(<8 x i16> %arg) ; Z13: Cost Model: Found an estimated cost of 1 for instruction: store <8 x i16> %swp2, <8 x i16>* %dst -; AR13: Cost Model: Found an estimated cost of 0 for instruction: store <8 x i16> %swp2, <8 x i16>* %dst +; Z15: Cost Model: Found an estimated cost of 0 for instruction: store <8 x i16> %swp2, <8 x i16>* %dst ; CHECK: Cost Model: Found an estimated cost of 1 for instruction: %Ld2 = load <8 x i16>, <8 x i16>* %src ; CHECK: Cost Model: Found an estimated cost of 1 for instruction: %swp3 = tail call <8 x i16> @llvm.bswap.v8i16(<8 x i16> %Ld2) ; Z13: Cost Model: Found an estimated cost of 1 for instruction: store <8 x i16> %swp3, <8 x i16>* %dst -; AR13: Cost Model: Found an estimated cost of 0 for instruction: store <8 x i16> %swp3, <8 x i16>* %dst +; Z15: Cost Model: Found an estimated cost of 0 for instruction: store <8 x i16> %swp3, <8 x i16>* %dst %Ld1 = load <8 x i16>, <8 x i16>* %src %swp1 = tail call <8 x i16> @llvm.bswap.v8i16(<8 x i16> %Ld1) diff --git a/llvm/test/Analysis/CostModel/SystemZ/logic-miscext3.ll b/llvm/test/Analysis/CostModel/SystemZ/logic-miscext3.ll index 86706309e6d14..f3b915d0a64d4 100644 --- a/llvm/test/Analysis/CostModel/SystemZ/logic-miscext3.ll +++ b/llvm/test/Analysis/CostModel/SystemZ/logic-miscext3.ll @@ -1,25 +1,25 @@ ; RUN: opt < %s -cost-model -analyze -mtriple=systemz-unknown -mcpu=z13 \ ; RUN: | FileCheck %s -check-prefixes=CHECK,Z13 -; RUN: opt < %s -cost-model -analyze -mtriple=systemz-unknown -mcpu=arch13 \ -; RUN: | FileCheck %s -check-prefixes=CHECK,AR13 +; RUN: opt < %s -cost-model -analyze -mtriple=systemz-unknown -mcpu=z15 \ +; RUN: | FileCheck %s -check-prefixes=CHECK,Z15 define void @fun0(i32 %a) { ; CHECK-LABEL: Printing analysis 'Cost Model Analysis' for function 'fun0': ; CHECK: Cost Model: Found an estimated cost of 1 for instruction: %c0 = xor i32 %l0, -1 ; Z13: Cost Model: Found an estimated cost of 1 for instruction: %res0 = or i32 %a, %c0 -; AR13: Cost Model: Found an estimated cost of 0 for instruction: %res0 = or i32 %a, %c0 +; Z15: Cost Model: Found an estimated cost of 0 for instruction: %res0 = or i32 %a, %c0 ; CHECK: Cost Model: Found an estimated cost of 1 for instruction: %c1 = xor i32 %l1, -1 ; Z13: Cost Model: Found an estimated cost of 1 for instruction: %res1 = and i32 %a, %c1 -; AR13: Cost Model: Found an estimated cost of 0 for instruction: %res1 = and i32 %a, %c1 +; Z15: Cost Model: Found an estimated cost of 0 for instruction: %res1 = and i32 %a, %c1 ; CHECK: Cost Model: Found an estimated cost of 1 for instruction: %c2 = and i32 %l2, %a ; Z13: Cost Model: Found an estimated cost of 1 for instruction: %res2 = xor i32 %c2, -1 -; AR13: Cost Model: Found an estimated cost of 0 for instruction: %res2 = xor i32 %c2, -1 +; Z15: Cost Model: Found an estimated cost of 0 for instruction: %res2 = xor i32 %c2, -1 ; CHECK: Cost Model: Found an estimated cost of 1 for instruction: %c3 = or i32 %l3, %a ; Z13: Cost Model: Found an estimated cost of 1 for instruction: %res3 = xor i32 %c3, -1 -; AR13: Cost Model: Found an estimated cost of 0 for instruction: %res3 = xor i32 %c3, -1 +; Z15: Cost Model: Found an estimated cost of 0 for instruction: %res3 = xor i32 %c3, -1 ; CHECK: Cost Model: Found an estimated cost of 1 for instruction: %c4 = xor i32 %l4, %a ; Z13: Cost Model: Found an estimated cost of 1 for instruction: %res4 = xor i32 %c4, -1 -; AR13: Cost Model: Found an estimated cost of 0 for instruction: %res4 = xor i32 %c4, -1 +; Z15: Cost Model: Found an estimated cost of 0 for instruction: %res4 = xor i32 %c4, -1 entry: %l0 = load i32, i32* undef @@ -54,19 +54,19 @@ define void @fun1(i64 %a) { ; CHECK-LABEL: Printing analysis 'Cost Model Analysis' for function 'fun1': ; CHECK: Cost Model: Found an estimated cost of 1 for instruction: %c0 = xor i64 %l0, -1 ; Z13: Cost Model: Found an estimated cost of 1 for instruction: %res0 = or i64 %a, %c0 -; AR13: Cost Model: Found an estimated cost of 0 for instruction: %res0 = or i64 %a, %c0 +; Z15: Cost Model: Found an estimated cost of 0 for instruction: %res0 = or i64 %a, %c0 ; CHECK: Cost Model: Found an estimated cost of 1 for instruction: %c1 = xor i64 %l1, -1 ; Z13: Cost Model: Found an estimated cost of 1 for instruction: %res1 = and i64 %a, %c1 -; AR13: Cost Model: Found an estimated cost of 0 for instruction: %res1 = and i64 %a, %c1 +; Z15: Cost Model: Found an estimated cost of 0 for instruction: %res1 = and i64 %a, %c1 ; CHECK: Cost Model: Found an estimated cost of 1 for instruction: %c2 = and i64 %l2, %a ; Z13: Cost Model: Found an estimated cost of 1 for instruction: %res2 = xor i64 %c2, -1 -; AR13: Cost Model: Found an estimated cost of 0 for instruction: %res2 = xor i64 %c2, -1 +; Z15: Cost Model: Found an estimated cost of 0 for instruction: %res2 = xor i64 %c2, -1 ; CHECK: Cost Model: Found an estimated cost of 1 for instruction: %c3 = or i64 %l3, %a ; Z13: Cost Model: Found an estimated cost of 1 for instruction: %res3 = xor i64 %c3, -1 -; AR13: Cost Model: Found an estimated cost of 0 for instruction: %res3 = xor i64 %c3, -1 +; Z15: Cost Model: Found an estimated cost of 0 for instruction: %res3 = xor i64 %c3, -1 ; CHECK: Cost Model: Found an estimated cost of 1 for instruction: %c4 = xor i64 %l4, %a ; Z13: Cost Model: Found an estimated cost of 1 for instruction: %res4 = xor i64 %c4, -1 -; AR13: Cost Model: Found an estimated cost of 0 for instruction: %res4 = xor i64 %c4, -1 +; Z15: Cost Model: Found an estimated cost of 0 for instruction: %res4 = xor i64 %c4, -1 entry: %l0 = load i64, i64* undef %c0 = xor i64 %l0, -1 diff --git a/llvm/test/CodeGen/SystemZ/cond-move-01.ll b/llvm/test/CodeGen/SystemZ/cond-move-01.ll index fad5012be10e9..c6b0cd5393afc 100644 --- a/llvm/test/CodeGen/SystemZ/cond-move-01.ll +++ b/llvm/test/CodeGen/SystemZ/cond-move-01.ll @@ -7,7 +7,7 @@ ; RUN: llc < %s -mtriple=s390x-linux-gnu -mcpu=z13 -verify-machineinstrs | FileCheck %s ; ; And again in the presence of the select instructions. -; RUN: llc < %s -mtriple=s390x-linux-gnu -mcpu=arch13 -verify-machineinstrs | FileCheck %s +; RUN: llc < %s -mtriple=s390x-linux-gnu -mcpu=z15 -verify-machineinstrs | FileCheck %s ; Test LOCR. define i32 @f1(i32 %a, i32 %b, i32 %limit) { diff --git a/llvm/test/CodeGen/SystemZ/cond-move-02.ll b/llvm/test/CodeGen/SystemZ/cond-move-02.ll index c8ab5331216b0..362d7cc3865b6 100644 --- a/llvm/test/CodeGen/SystemZ/cond-move-02.ll +++ b/llvm/test/CodeGen/SystemZ/cond-move-02.ll @@ -4,7 +4,7 @@ ; ; Run the test again to make sure it still works the same even ; in the presence of the select instructions. -; RUN: llc < %s -mtriple=s390x-linux-gnu -mcpu=arch13 -verify-machineinstrs | FileCheck %s +; RUN: llc < %s -mtriple=s390x-linux-gnu -mcpu=z15 -verify-machineinstrs | FileCheck %s define i32 @f1(i32 %x) { diff --git a/llvm/test/CodeGen/SystemZ/cond-move-03.ll b/llvm/test/CodeGen/SystemZ/cond-move-03.ll index 0f4d080d6bcb2..f668f1ac40718 100644 --- a/llvm/test/CodeGen/SystemZ/cond-move-03.ll +++ b/llvm/test/CodeGen/SystemZ/cond-move-03.ll @@ -6,7 +6,7 @@ ; ; Run the test again to make sure it still works the same even ; in the presence of the select instructions. -; RUN: llc < %s -verify-machineinstrs -mtriple=s390x-linux-gnu -mcpu=arch13 \ +; RUN: llc < %s -verify-machineinstrs -mtriple=s390x-linux-gnu -mcpu=z15 \ ; RUN: -no-integrated-as | FileCheck %s define void @f1(i32 %limit) { diff --git a/llvm/test/CodeGen/SystemZ/cond-move-06.ll b/llvm/test/CodeGen/SystemZ/cond-move-06.ll index 3c133d9167185..bcedb3ae8e8d8 100644 --- a/llvm/test/CodeGen/SystemZ/cond-move-06.ll +++ b/llvm/test/CodeGen/SystemZ/cond-move-06.ll @@ -1,6 +1,6 @@ ; Test SELR and SELGR. ; -; RUN: llc < %s -mtriple=s390x-linux-gnu -mcpu=arch13 -verify-machineinstrs | FileCheck %s +; RUN: llc < %s -mtriple=s390x-linux-gnu -mcpu=z15 -verify-machineinstrs | FileCheck %s ; Test SELR. define i32 @f1(i32 %limit, i32 %a, i32 %b) { diff --git a/llvm/test/CodeGen/SystemZ/cond-move-07.ll b/llvm/test/CodeGen/SystemZ/cond-move-07.ll index 87123b5337928..2bee8919b5198 100644 --- a/llvm/test/CodeGen/SystemZ/cond-move-07.ll +++ b/llvm/test/CodeGen/SystemZ/cond-move-07.ll @@ -1,7 +1,7 @@ ; Test SELFHR. ; See comments in asm-18.ll about testing high-word operations. ; -; RUN: llc < %s -verify-machineinstrs -mtriple=s390x-linux-gnu -mcpu=arch13 \ +; RUN: llc < %s -verify-machineinstrs -mtriple=s390x-linux-gnu -mcpu=z15 \ ; RUN: -no-integrated-as | FileCheck %s define void @f1(i32 %limit) { diff --git a/llvm/test/CodeGen/SystemZ/cond-move-08.mir b/llvm/test/CodeGen/SystemZ/cond-move-08.mir index 5808fc643bcae..aed6110360152 100644 --- a/llvm/test/CodeGen/SystemZ/cond-move-08.mir +++ b/llvm/test/CodeGen/SystemZ/cond-move-08.mir @@ -1,4 +1,4 @@ -# RUN: llc -mtriple=s390x-linux-gnu -mcpu=arch13 -start-before=greedy %s -o - \ +# RUN: llc -mtriple=s390x-linux-gnu -mcpu=z15 -start-before=greedy %s -o - \ # RUN: | FileCheck %s # # Test that regalloc manages (via regalloc hints) to avoid a LOCRMux jump @@ -73,7 +73,7 @@ ; Function Attrs: nounwind declare void @llvm.stackprotector(i8*, i8**) #1 - attributes #0 = { "target-cpu"="arch13" } + attributes #0 = { "target-cpu"="z15" } attributes #1 = { nounwind } ... diff --git a/llvm/test/CodeGen/SystemZ/ctpop-02.ll b/llvm/test/CodeGen/SystemZ/ctpop-02.ll index 5b9d41f9af2e9..a2bddac8c5a42 100644 --- a/llvm/test/CodeGen/SystemZ/ctpop-02.ll +++ b/llvm/test/CodeGen/SystemZ/ctpop-02.ll @@ -1,6 +1,6 @@ -; Test population-count instruction on arch13 +; Test population-count instruction on z15 ; -; RUN: llc < %s -mtriple=s390x-linux-gnu -mcpu=arch13 | FileCheck %s +; RUN: llc < %s -mtriple=s390x-linux-gnu -mcpu=z15 | FileCheck %s declare i32 @llvm.ctpop.i32(i32 %a) declare i64 @llvm.ctpop.i64(i64 %a) diff --git a/llvm/test/CodeGen/SystemZ/not-01.ll b/llvm/test/CodeGen/SystemZ/not-01.ll index 3b9dbd1311f64..be2a5a88d73f0 100644 --- a/llvm/test/CodeGen/SystemZ/not-01.ll +++ b/llvm/test/CodeGen/SystemZ/not-01.ll @@ -1,6 +1,6 @@ -; Combined logical operations involving complement on arch13 +; Combined logical operations involving complement on z15 ; -; RUN: llc -mcpu=arch13 < %s -mtriple=s390x-linux-gnu | FileCheck %s +; RUN: llc -mcpu=z15 < %s -mtriple=s390x-linux-gnu | FileCheck %s ; And-with-complement 32-bit. define i32 @f1(i32 %dummy, i32 %a, i32 %b) { diff --git a/llvm/test/CodeGen/SystemZ/vec-bswap-01.ll b/llvm/test/CodeGen/SystemZ/vec-bswap-01.ll index 8132108953a90..4d5e574033f34 100644 --- a/llvm/test/CodeGen/SystemZ/vec-bswap-01.ll +++ b/llvm/test/CodeGen/SystemZ/vec-bswap-01.ll @@ -1,6 +1,6 @@ ; Test loads of byte-swapped vector elements. ; -; RUN: llc < %s -mtriple=s390x-linux-gnu -mcpu=arch13 | FileCheck %s +; RUN: llc < %s -mtriple=s390x-linux-gnu -mcpu=z15 | FileCheck %s declare <8 x i16> @llvm.bswap.v8i16(<8 x i16>) declare <4 x i32> @llvm.bswap.v4i32(<4 x i32>) diff --git a/llvm/test/CodeGen/SystemZ/vec-bswap-02.ll b/llvm/test/CodeGen/SystemZ/vec-bswap-02.ll index ff7facc0910a7..b7e8a1c1711df 100644 --- a/llvm/test/CodeGen/SystemZ/vec-bswap-02.ll +++ b/llvm/test/CodeGen/SystemZ/vec-bswap-02.ll @@ -1,6 +1,6 @@ ; Test stores of byte-swapped vector elements. ; -; RUN: llc < %s -mtriple=s390x-linux-gnu -mcpu=arch13 | FileCheck %s +; RUN: llc < %s -mtriple=s390x-linux-gnu -mcpu=z15 | FileCheck %s declare <8 x i16> @llvm.bswap.v8i16(<8 x i16>) declare <4 x i32> @llvm.bswap.v4i32(<4 x i32>) diff --git a/llvm/test/CodeGen/SystemZ/vec-bswap-03.ll b/llvm/test/CodeGen/SystemZ/vec-bswap-03.ll index 9102c739b1248..b812308fc6d16 100644 --- a/llvm/test/CodeGen/SystemZ/vec-bswap-03.ll +++ b/llvm/test/CodeGen/SystemZ/vec-bswap-03.ll @@ -1,6 +1,6 @@ ; Test vector insertion of byte-swapped memory values. ; -; RUN: llc < %s -mtriple=s390x-linux-gnu -mcpu=arch13 | FileCheck %s +; RUN: llc < %s -mtriple=s390x-linux-gnu -mcpu=z15 | FileCheck %s declare i16 @llvm.bswap.i16(i16) declare i32 @llvm.bswap.i32(i32) diff --git a/llvm/test/CodeGen/SystemZ/vec-bswap-04.ll b/llvm/test/CodeGen/SystemZ/vec-bswap-04.ll index 43787a48b2efd..0ab521dbb9cf5 100644 --- a/llvm/test/CodeGen/SystemZ/vec-bswap-04.ll +++ b/llvm/test/CodeGen/SystemZ/vec-bswap-04.ll @@ -1,6 +1,6 @@ ; Test vector extraction of byte-swapped value to memory. ; -; RUN: llc < %s -mtriple=s390x-linux-gnu -mcpu=arch13 | FileCheck %s +; RUN: llc < %s -mtriple=s390x-linux-gnu -mcpu=z15 | FileCheck %s declare i16 @llvm.bswap.i16(i16) declare i32 @llvm.bswap.i32(i32) diff --git a/llvm/test/CodeGen/SystemZ/vec-bswap-05.ll b/llvm/test/CodeGen/SystemZ/vec-bswap-05.ll index 038a3f4f4f57e..4718aadbdd5dc 100644 --- a/llvm/test/CodeGen/SystemZ/vec-bswap-05.ll +++ b/llvm/test/CodeGen/SystemZ/vec-bswap-05.ll @@ -1,6 +1,6 @@ ; Test vector insertions of byte-swapped memory values into 0. ; -; RUN: llc < %s -mtriple=s390x-linux-gnu -mcpu=arch13 | FileCheck %s +; RUN: llc < %s -mtriple=s390x-linux-gnu -mcpu=z15 | FileCheck %s declare i16 @llvm.bswap.i16(i16) declare i32 @llvm.bswap.i32(i32) diff --git a/llvm/test/CodeGen/SystemZ/vec-bswap-06.ll b/llvm/test/CodeGen/SystemZ/vec-bswap-06.ll index 0c78633ee7d11..a67b5756c4d52 100644 --- a/llvm/test/CodeGen/SystemZ/vec-bswap-06.ll +++ b/llvm/test/CodeGen/SystemZ/vec-bswap-06.ll @@ -1,6 +1,6 @@ ; Test insertions of byte-swapped memory values into a nonzero index of an undef. ; -; RUN: llc < %s -mtriple=s390x-linux-gnu -mcpu=arch13 | FileCheck %s +; RUN: llc < %s -mtriple=s390x-linux-gnu -mcpu=z15 | FileCheck %s declare i16 @llvm.bswap.i16(i16) declare i32 @llvm.bswap.i32(i32) diff --git a/llvm/test/CodeGen/SystemZ/vec-bswap-07.ll b/llvm/test/CodeGen/SystemZ/vec-bswap-07.ll index 0190184c1e2f3..d3f38a0a6851a 100644 --- a/llvm/test/CodeGen/SystemZ/vec-bswap-07.ll +++ b/llvm/test/CodeGen/SystemZ/vec-bswap-07.ll @@ -1,6 +1,6 @@ ; Test replications of a byte-swapped scalar memory value. ; -; RUN: llc < %s -mtriple=s390x-linux-gnu -mcpu=arch13 | FileCheck %s +; RUN: llc < %s -mtriple=s390x-linux-gnu -mcpu=z15 | FileCheck %s declare i16 @llvm.bswap.i16(i16) declare i32 @llvm.bswap.i32(i32) diff --git a/llvm/test/CodeGen/SystemZ/vec-conv-03.ll b/llvm/test/CodeGen/SystemZ/vec-conv-03.ll index 8398876821c19..df1e3a4e0dc33 100644 --- a/llvm/test/CodeGen/SystemZ/vec-conv-03.ll +++ b/llvm/test/CodeGen/SystemZ/vec-conv-03.ll @@ -1,6 +1,6 @@ -; Test conversions between integer and float elements on arch13. +; Test conversions between integer and float elements on z15. ; -; RUN: llc < %s -mtriple=s390x-linux-gnu -mcpu=arch13 | FileCheck %s +; RUN: llc < %s -mtriple=s390x-linux-gnu -mcpu=z15 | FileCheck %s ; Test conversion of f32s to signed i32s. define <4 x i32> @f1(<4 x float> %floats) { diff --git a/llvm/test/CodeGen/SystemZ/vec-eswap-01.ll b/llvm/test/CodeGen/SystemZ/vec-eswap-01.ll index 89b65392440a5..0e93f609eac1c 100644 --- a/llvm/test/CodeGen/SystemZ/vec-eswap-01.ll +++ b/llvm/test/CodeGen/SystemZ/vec-eswap-01.ll @@ -1,6 +1,6 @@ ; Test loads of byte-swapped vector elements. ; -; RUN: llc < %s -mtriple=s390x-linux-gnu -mcpu=arch13 | FileCheck %s +; RUN: llc < %s -mtriple=s390x-linux-gnu -mcpu=z15 | FileCheck %s ; Test v16i8 loads. define <16 x i8> @f1(<16 x i8> *%ptr) { diff --git a/llvm/test/CodeGen/SystemZ/vec-eswap-02.ll b/llvm/test/CodeGen/SystemZ/vec-eswap-02.ll index 1eab5a06ff213..07e07258204e7 100644 --- a/llvm/test/CodeGen/SystemZ/vec-eswap-02.ll +++ b/llvm/test/CodeGen/SystemZ/vec-eswap-02.ll @@ -1,6 +1,6 @@ ; Test stores of element-swapped vector elements. ; -; RUN: llc < %s -mtriple=s390x-linux-gnu -mcpu=arch13 | FileCheck %s +; RUN: llc < %s -mtriple=s390x-linux-gnu -mcpu=z15 | FileCheck %s ; Test v16i8 stores. define void @f1(<16 x i8> %val, <16 x i8> *%ptr) { diff --git a/llvm/test/CodeGen/SystemZ/vec-intrinsics-03.ll b/llvm/test/CodeGen/SystemZ/vec-intrinsics-03.ll index d192ad8948805..fa144cc93d350 100644 --- a/llvm/test/CodeGen/SystemZ/vec-intrinsics-03.ll +++ b/llvm/test/CodeGen/SystemZ/vec-intrinsics-03.ll @@ -1,6 +1,6 @@ -; Test vector intrinsics added with arch13. +; Test vector intrinsics added with z15. ; -; RUN: llc < %s -mtriple=s390x-linux-gnu -mcpu=arch13 | FileCheck %s +; RUN: llc < %s -mtriple=s390x-linux-gnu -mcpu=z15 | FileCheck %s declare <16 x i8> @llvm.s390.vsld(<16 x i8>, <16 x i8>, i32) declare <16 x i8> @llvm.s390.vsrd(<16 x i8>, <16 x i8>, i32) diff --git a/llvm/test/CodeGen/SystemZ/vec-strict-conv-03.ll b/llvm/test/CodeGen/SystemZ/vec-strict-conv-03.ll index f42a2b4120279..6b9bc80cbdeb5 100644 --- a/llvm/test/CodeGen/SystemZ/vec-strict-conv-03.ll +++ b/llvm/test/CodeGen/SystemZ/vec-strict-conv-03.ll @@ -1,6 +1,6 @@ -; Test strict conversions between integer and float elements on arch13. +; Test strict conversions between integer and float elements on z15. ; -; RUN: llc < %s -mtriple=s390x-linux-gnu -mcpu=arch13 | FileCheck %s +; RUN: llc < %s -mtriple=s390x-linux-gnu -mcpu=z15 | FileCheck %s ; FIXME: llvm.experimental.constrained.[su]itofp does not yet exist diff --git a/llvm/test/MC/Disassembler/SystemZ/insns-arch13.txt b/llvm/test/MC/Disassembler/SystemZ/insns-z15.txt similarity index 99% rename from llvm/test/MC/Disassembler/SystemZ/insns-arch13.txt rename to llvm/test/MC/Disassembler/SystemZ/insns-z15.txt index 3ed0435510e0c..1742a9208b6ed 100644 --- a/llvm/test/MC/Disassembler/SystemZ/insns-arch13.txt +++ b/llvm/test/MC/Disassembler/SystemZ/insns-z15.txt @@ -1,5 +1,5 @@ -# Test arch13 instructions that don't have PC-relative operands. -# RUN: llvm-mc --disassemble %s -triple=s390x-linux-gnu -mcpu=arch13 \ +# Test z15 instructions that don't have PC-relative operands. +# RUN: llvm-mc --disassemble %s -triple=s390x-linux-gnu -mcpu=z15 \ # RUN: | FileCheck %s # CHECK: dfltcc %r2, %r2, %r2 diff --git a/llvm/test/MC/SystemZ/insn-bad-arch13.s b/llvm/test/MC/SystemZ/insn-bad-z15.s similarity index 99% rename from llvm/test/MC/SystemZ/insn-bad-arch13.s rename to llvm/test/MC/SystemZ/insn-bad-z15.s index ad84e55b69f89..484dfd342dab0 100644 --- a/llvm/test/MC/SystemZ/insn-bad-arch13.s +++ b/llvm/test/MC/SystemZ/insn-bad-z15.s @@ -1,4 +1,6 @@ -# For arch13 only. +# For z15 only. +# RUN: not llvm-mc -triple s390x-linux-gnu -mcpu=z15 < %s 2> %t +# RUN: FileCheck < %t %s # RUN: not llvm-mc -triple s390x-linux-gnu -mcpu=arch13 < %s 2> %t # RUN: FileCheck < %t %s diff --git a/llvm/test/MC/SystemZ/insn-good-arch13.s b/llvm/test/MC/SystemZ/insn-good-z15.s similarity index 99% rename from llvm/test/MC/SystemZ/insn-good-arch13.s rename to llvm/test/MC/SystemZ/insn-good-z15.s index 0bbb8a546387e..1eb3b743cc61d 100644 --- a/llvm/test/MC/SystemZ/insn-good-arch13.s +++ b/llvm/test/MC/SystemZ/insn-good-z15.s @@ -1,4 +1,6 @@ -# For arch13 and above. +# For z15 and above. +# RUN: llvm-mc -triple s390x-linux-gnu -mcpu=z15 -show-encoding %s \ +# RUN: | FileCheck %s # RUN: llvm-mc -triple s390x-linux-gnu -mcpu=arch13 -show-encoding %s \ # RUN: | FileCheck %s From 48b40834dc59ec1d02f59b1c36360b12c58b3c7b Mon Sep 17 00:00:00 2001 From: Ulrich Weigand Date: Fri, 20 Sep 2019 23:06:03 +0000 Subject: [PATCH 39/71] [SystemZ] Support z15 processor name The recently announced IBM z15 processor implements the architecture already supported as "arch13" in LLVM. This patch adds support for "z15" as an alternate architecture name for arch13. Corrsponding LLVM support was committed as rev. 372435. llvm-svn: 372436 --- clang/lib/Basic/Targets/SystemZ.cpp | 2 +- clang/test/CodeGen/builtins-systemz-vector3-error.c | 2 +- clang/test/CodeGen/builtins-systemz-vector3.c | 2 +- clang/test/CodeGen/builtins-systemz-zvector3-error.c | 2 +- clang/test/CodeGen/builtins-systemz-zvector3.c | 4 ++-- clang/test/CodeGen/systemz-abi-vector.c | 2 ++ clang/test/CodeGen/systemz-abi.c | 2 ++ clang/test/CodeGen/target-data.c | 2 ++ clang/test/Driver/systemz-march.c | 2 ++ clang/test/Misc/target-invalid-cpu-note.c | 2 +- clang/test/Preprocessor/predefined-arch-macros.c | 3 +++ 11 files changed, 18 insertions(+), 7 deletions(-) diff --git a/clang/lib/Basic/Targets/SystemZ.cpp b/clang/lib/Basic/Targets/SystemZ.cpp index d86928a6333b0..ad3915e4d5dd0 100644 --- a/clang/lib/Basic/Targets/SystemZ.cpp +++ b/clang/lib/Basic/Targets/SystemZ.cpp @@ -92,7 +92,7 @@ static constexpr ISANameRevision ISARevisions[] = { {{"arch10"}, 10}, {{"zEC12"}, 10}, {{"arch11"}, 11}, {{"z13"}, 11}, {{"arch12"}, 12}, {{"z14"}, 12}, - {{"arch13"}, 13}, + {{"arch13"}, 13}, {{"z15"}, 13} }; int SystemZTargetInfo::getISARevision(StringRef Name) const { diff --git a/clang/test/CodeGen/builtins-systemz-vector3-error.c b/clang/test/CodeGen/builtins-systemz-vector3-error.c index 6583857c3c178..99b171c55bb55 100644 --- a/clang/test/CodeGen/builtins-systemz-vector3-error.c +++ b/clang/test/CodeGen/builtins-systemz-vector3-error.c @@ -1,5 +1,5 @@ // REQUIRES: systemz-registered-target -// RUN: %clang_cc1 -target-cpu arch13 -triple s390x-unknown-unknown \ +// RUN: %clang_cc1 -target-cpu z15 -triple s390x-unknown-unknown \ // RUN: -Wall -Wno-unused -Werror -fsyntax-only -verify %s typedef __attribute__((vector_size(16))) signed char vec_schar; diff --git a/clang/test/CodeGen/builtins-systemz-vector3.c b/clang/test/CodeGen/builtins-systemz-vector3.c index e8194b642cd63..e4af1c1e54b86 100644 --- a/clang/test/CodeGen/builtins-systemz-vector3.c +++ b/clang/test/CodeGen/builtins-systemz-vector3.c @@ -1,5 +1,5 @@ // REQUIRES: systemz-registered-target -// RUN: %clang_cc1 -target-cpu arch13 -triple s390x-ibm-linux -flax-vector-conversions=none \ +// RUN: %clang_cc1 -target-cpu z15 -triple s390x-ibm-linux -flax-vector-conversions=none \ // RUN: -Wall -Wno-unused -Werror -emit-llvm %s -o - | FileCheck %s typedef __attribute__((vector_size(16))) signed char vec_schar; diff --git a/clang/test/CodeGen/builtins-systemz-zvector3-error.c b/clang/test/CodeGen/builtins-systemz-zvector3-error.c index 657508b261867..557b9a3a7ec1b 100644 --- a/clang/test/CodeGen/builtins-systemz-zvector3-error.c +++ b/clang/test/CodeGen/builtins-systemz-zvector3-error.c @@ -1,5 +1,5 @@ // REQUIRES: systemz-registered-target -// RUN: %clang_cc1 -target-cpu arch13 -triple s390x-linux-gnu \ +// RUN: %clang_cc1 -target-cpu z15 -triple s390x-linux-gnu \ // RUN: -fzvector -flax-vector-conversions=none \ // RUN: -Wall -Wno-unused -Werror -fsyntax-only -verify %s diff --git a/clang/test/CodeGen/builtins-systemz-zvector3.c b/clang/test/CodeGen/builtins-systemz-zvector3.c index db30f41933263..a987c6113e36b 100644 --- a/clang/test/CodeGen/builtins-systemz-zvector3.c +++ b/clang/test/CodeGen/builtins-systemz-zvector3.c @@ -1,8 +1,8 @@ // REQUIRES: systemz-registered-target -// RUN: %clang_cc1 -target-cpu arch13 -triple s390x-linux-gnu \ +// RUN: %clang_cc1 -target-cpu z15 -triple s390x-linux-gnu \ // RUN: -O -fzvector -flax-vector-conversions=none \ // RUN: -Wall -Wno-unused -Werror -emit-llvm %s -o - | FileCheck %s -// RUN: %clang_cc1 -target-cpu arch13 -triple s390x-linux-gnu \ +// RUN: %clang_cc1 -target-cpu z15 -triple s390x-linux-gnu \ // RUN: -O -fzvector -flax-vector-conversions=none \ // RUN: -Wall -Wno-unused -Werror -S %s -o - | FileCheck %s --check-prefix=CHECK-ASM diff --git a/clang/test/CodeGen/systemz-abi-vector.c b/clang/test/CodeGen/systemz-abi-vector.c index 46c008a8d9f8e..f2e6c13c718f5 100644 --- a/clang/test/CodeGen/systemz-abi-vector.c +++ b/clang/test/CodeGen/systemz-abi-vector.c @@ -10,6 +10,8 @@ // RUN: -emit-llvm -o - %s | FileCheck --check-prefix=CHECK-VECTOR %s // RUN: %clang_cc1 -triple s390x-linux-gnu -target-cpu arch12 \ // RUN: -emit-llvm -o - %s | FileCheck --check-prefix=CHECK-VECTOR %s +// RUN: %clang_cc1 -triple s390x-linux-gnu -target-cpu z15 \ +// RUN: -emit-llvm -o - %s | FileCheck --check-prefix=CHECK-VECTOR %s // RUN: %clang_cc1 -triple s390x-linux-gnu -target-cpu arch13 \ // RUN: -emit-llvm -o - %s | FileCheck --check-prefix=CHECK-VECTOR %s diff --git a/clang/test/CodeGen/systemz-abi.c b/clang/test/CodeGen/systemz-abi.c index c04a51ff6ef44..3511983e32d76 100644 --- a/clang/test/CodeGen/systemz-abi.c +++ b/clang/test/CodeGen/systemz-abi.c @@ -10,6 +10,8 @@ // RUN: -emit-llvm -o - %s | FileCheck %s // RUN: %clang_cc1 -triple s390x-linux-gnu -target-cpu arch12 \ // RUN: -emit-llvm -o - %s | FileCheck %s +// RUN: %clang_cc1 -triple s390x-linux-gnu -target-cpu z15 \ +// RUN: -emit-llvm -o - %s | FileCheck %s // RUN: %clang_cc1 -triple s390x-linux-gnu -target-cpu arch13 \ // RUN: -emit-llvm -o - %s | FileCheck %s diff --git a/clang/test/CodeGen/target-data.c b/clang/test/CodeGen/target-data.c index 3e4d05436327d..21a8b415dc217 100644 --- a/clang/test/CodeGen/target-data.c +++ b/clang/test/CodeGen/target-data.c @@ -199,6 +199,8 @@ // RUN: FileCheck %s -check-prefix=SYSTEMZ-VECTOR // RUN: %clang_cc1 -triple s390x-unknown -target-cpu arch12 -o - -emit-llvm %s | \ // RUN: FileCheck %s -check-prefix=SYSTEMZ-VECTOR +// RUN: %clang_cc1 -triple s390x-unknown -target-cpu z15 -o - -emit-llvm %s | \ +// RUN: FileCheck %s -check-prefix=SYSTEMZ-VECTOR // RUN: %clang_cc1 -triple s390x-unknown -target-cpu arch13 -o - -emit-llvm %s | \ // RUN: FileCheck %s -check-prefix=SYSTEMZ-VECTOR // SYSTEMZ-VECTOR: target datalayout = "E-m:e-i1:8:16-i8:8:16-i64:64-f128:64-v128:64-a:8:16-n32:64" diff --git a/clang/test/Driver/systemz-march.c b/clang/test/Driver/systemz-march.c index 6b751523c34f9..f07a2c50131ad 100644 --- a/clang/test/Driver/systemz-march.c +++ b/clang/test/Driver/systemz-march.c @@ -11,6 +11,7 @@ // RUN: %clang -target s390x -### -S -emit-llvm -march=arch11 %s 2>&1 | FileCheck --check-prefix=CHECK-ARCH11 %s // RUN: %clang -target s390x -### -S -emit-llvm -march=z14 %s 2>&1 | FileCheck --check-prefix=CHECK-Z14 %s // RUN: %clang -target s390x -### -S -emit-llvm -march=arch12 %s 2>&1 | FileCheck --check-prefix=CHECK-ARCH12 %s +// RUN: %clang -target s390x -### -S -emit-llvm -march=z15 %s 2>&1 | FileCheck --check-prefix=CHECK-Z15 %s // RUN: %clang -target s390x -### -S -emit-llvm -march=arch13 %s 2>&1 | FileCheck --check-prefix=CHECK-ARCH13 %s // CHECK-Z9: error: unknown target CPU 'z9' @@ -24,6 +25,7 @@ // CHECK-ARCH11: "-target-cpu" "arch11" // CHECK-Z14: "-target-cpu" "z14" // CHECK-ARCH12: "-target-cpu" "arch12" +// CHECK-Z15: "-target-cpu" "z15" // CHECK-ARCH13: "-target-cpu" "arch13" int x; diff --git a/clang/test/Misc/target-invalid-cpu-note.c b/clang/test/Misc/target-invalid-cpu-note.c index e7dc6ed478b6d..4f8158e50229e 100644 --- a/clang/test/Misc/target-invalid-cpu-note.c +++ b/clang/test/Misc/target-invalid-cpu-note.c @@ -60,7 +60,7 @@ // RUN: not %clang_cc1 -triple systemz--- -target-cpu not-a-cpu -fsyntax-only %s 2>&1 | FileCheck %s --check-prefix SYSTEMZ // SYSTEMZ: error: unknown target CPU 'not-a-cpu' // SYSTEMZ: note: valid target CPU values are: arch8, z10, arch9, z196, arch10, -// SYSTEMZ-SAME: zEC12, arch11, z13, arch12, z14, arch13 +// SYSTEMZ-SAME: zEC12, arch11, z13, arch12, z14, arch13, z15 // RUN: not %clang_cc1 -triple sparc--- -target-cpu not-a-cpu -fsyntax-only %s 2>&1 | FileCheck %s --check-prefix SPARC // SPARC: error: unknown target CPU 'not-a-cpu' diff --git a/clang/test/Preprocessor/predefined-arch-macros.c b/clang/test/Preprocessor/predefined-arch-macros.c index 5981c80ae3a1a..95bea654fe220 100644 --- a/clang/test/Preprocessor/predefined-arch-macros.c +++ b/clang/test/Preprocessor/predefined-arch-macros.c @@ -3242,6 +3242,9 @@ // RUN: %clang -march=arch13 -E -dM %s -o - 2>&1 \ // RUN: -target s390x-unknown-linux \ // RUN: | FileCheck -match-full-lines %s -check-prefix=CHECK_SYSTEMZ_ARCH13 +// RUN: %clang -march=z15 -E -dM %s -o - 2>&1 \ +// RUN: -target s390x-unknown-linux \ +// RUN: | FileCheck -match-full-lines %s -check-prefix=CHECK_SYSTEMZ_ARCH13 // CHECK_SYSTEMZ_ARCH13: #define __ARCH__ 13 // CHECK_SYSTEMZ_ARCH13: #define __GCC_HAVE_SYNC_COMPARE_AND_SWAP_1 1 // CHECK_SYSTEMZ_ARCH13: #define __GCC_HAVE_SYNC_COMPARE_AND_SWAP_2 1 From 397a686762e229c32857efc4e66b4e6cf72bee93 Mon Sep 17 00:00:00 2001 From: Richard Smith Date: Fri, 20 Sep 2019 23:08:59 +0000 Subject: [PATCH 40/71] Fix assertion failure when constant evaluation of a switch jumps over an uninitialized variable in an init-statement of a 'for' or 'if'. llvm-svn: 372437 --- clang/lib/AST/ExprConstant.cpp | 27 +++++++++++++++++++ .../SemaCXX/constant-expression-cxx2a.cpp | 13 +++++++++ 2 files changed, 40 insertions(+) diff --git a/clang/lib/AST/ExprConstant.cpp b/clang/lib/AST/ExprConstant.cpp index 2d538eda8128e..39d0943b45ec1 100644 --- a/clang/lib/AST/ExprConstant.cpp +++ b/clang/lib/AST/ExprConstant.cpp @@ -4131,6 +4131,21 @@ static EvalStmtResult EvaluateStmt(StmtResult &Result, EvalInfo &Info, // preceded by our switch label. BlockScopeRAII Scope(Info); + // Step into the init statement in case it brings an (uninitialized) + // variable into scope. + if (const Stmt *Init = IS->getInit()) { + EvalStmtResult ESR = EvaluateStmt(Result, Info, Init, Case); + if (ESR != ESR_CaseNotFound) { + assert(ESR != ESR_Succeeded); + return ESR; + } + } + + // Condition variable must be initialized if it exists. + // FIXME: We can skip evaluating the body if there's a condition + // variable, as there can't be any case labels within it. + // (The same is true for 'for' statements.) + EvalStmtResult ESR = EvaluateStmt(Result, Info, IS->getThen(), Case); if (ESR != ESR_CaseNotFound || !IS->getElse()) return ESR; @@ -4147,6 +4162,18 @@ static EvalStmtResult EvaluateStmt(StmtResult &Result, EvalInfo &Info, case Stmt::ForStmtClass: { const ForStmt *FS = cast(S); + BlockScopeRAII Scope(Info); + + // Step into the init statement in case it brings an (uninitialized) + // variable into scope. + if (const Stmt *Init = FS->getInit()) { + EvalStmtResult ESR = EvaluateStmt(Result, Info, Init, Case); + if (ESR != ESR_CaseNotFound) { + assert(ESR != ESR_Succeeded); + return ESR; + } + } + EvalStmtResult ESR = EvaluateLoopBody(Result, Info, FS->getBody(), Case); if (ESR != ESR_Continue) diff --git a/clang/test/SemaCXX/constant-expression-cxx2a.cpp b/clang/test/SemaCXX/constant-expression-cxx2a.cpp index ec4263e3ee427..a1ab6e8e12627 100644 --- a/clang/test/SemaCXX/constant-expression-cxx2a.cpp +++ b/clang/test/SemaCXX/constant-expression-cxx2a.cpp @@ -620,4 +620,17 @@ namespace Uninit { constexpr int s1 = switch_var(1); constexpr int s2 = switch_var(2); static_assert(s1 == 1 && s2 == 2); + + constexpr bool switch_into_init_stmt() { + switch (1) { + if (int n; false) { + for (int m; false;) { + case 1: + n = m = 1; + return n == 1 && m == 1; + } + } + } + } + static_assert(switch_into_init_stmt()); } From 6c0894b58ac8cbf12383f18789ac5a161a18f141 Mon Sep 17 00:00:00 2001 From: Richard Smith Date: Fri, 20 Sep 2019 23:12:51 +0000 Subject: [PATCH 41/71] Remove outdated FIXME. llvm-svn: 372438 --- clang/lib/AST/ExprConstant.cpp | 4 ---- 1 file changed, 4 deletions(-) diff --git a/clang/lib/AST/ExprConstant.cpp b/clang/lib/AST/ExprConstant.cpp index 39d0943b45ec1..4e371d7ca9510 100644 --- a/clang/lib/AST/ExprConstant.cpp +++ b/clang/lib/AST/ExprConstant.cpp @@ -4102,10 +4102,6 @@ static EvalStmtResult EvaluateStmt(StmtResult &Result, EvalInfo &Info, // If we're hunting down a 'case' or 'default' label, recurse through // substatements until we hit the label. if (Case) { - // FIXME: We don't start the lifetime of objects whose initialization we - // jump over. However, such objects must be of class type with a trivial - // default constructor that initialize all subobjects, so must be empty, - // so this almost never matters. switch (S->getStmtClass()) { case Stmt::CompoundStmtClass: // FIXME: Precompute which substatement of a compound statement we From f118852046a1d255ed8c65c6b5db320e8cea53a0 Mon Sep 17 00:00:00 2001 From: Wei Mi Date: Fri, 20 Sep 2019 23:24:50 +0000 Subject: [PATCH 42/71] [SampleFDO] Expose an interface to return the size of a section or the size of the profile for profile in ExtBinary format. Sometimes we want to limit the size of the profile by stripping some functions with low sample count or by stripping some function names with small text size from profile symbol list. That requires the profile reader to have the interfaces returning the size of a section or the size of total profile. The patch add those interfaces. At the same time, add some dump facility to show the size of each section. llvm-svn: 372439 --- llvm/include/llvm/ProfileData/SampleProf.h | 16 ++++++++++ .../llvm/ProfileData/SampleProfReader.h | 7 +++++ llvm/lib/ProfileData/SampleProfReader.cpp | 30 +++++++++++++++++++ .../tools/llvm-profdata/show-prof-size.test | 7 +++++ llvm/tools/llvm-profdata/llvm-profdata.cpp | 27 +++++++++++++++-- 5 files changed, 85 insertions(+), 2 deletions(-) create mode 100644 llvm/test/tools/llvm-profdata/show-prof-size.test diff --git a/llvm/include/llvm/ProfileData/SampleProf.h b/llvm/include/llvm/ProfileData/SampleProf.h index 157c79f6772fc..9ad740ed804eb 100644 --- a/llvm/include/llvm/ProfileData/SampleProf.h +++ b/llvm/include/llvm/ProfileData/SampleProf.h @@ -125,6 +125,22 @@ enum SecType { SecLBRProfile = SecFuncProfileFirst }; +static inline std::string getSecName(SecType Type) { + switch (Type) { + case SecInValid: + return "InvalidSection"; + case SecProfSummary: + return "ProfileSummarySection"; + case SecNameTable: + return "NameTableSection"; + case SecProfileSymbolList: + return "ProfileSymbolListSection"; + case SecLBRProfile: + return "LBRProfileSection"; + } + llvm_unreachable("A SecType has no name for output"); +} + // Entry type of section header table used by SampleProfileExtBinaryBaseReader // and SampleProfileExtBinaryBaseWriter. struct SecHdrTableEntry { diff --git a/llvm/include/llvm/ProfileData/SampleProfReader.h b/llvm/include/llvm/ProfileData/SampleProfReader.h index 3d5134d77490d..761dbde059569 100644 --- a/llvm/include/llvm/ProfileData/SampleProfReader.h +++ b/llvm/include/llvm/ProfileData/SampleProfReader.h @@ -333,6 +333,7 @@ class SampleProfileReader { /// It includes all the names that have samples either in outline instance /// or inline instance. virtual std::vector *getNameTable() { return nullptr; } + virtual bool dumpSectionInfo(raw_ostream &OS = dbgs()) { return false; }; protected: /// Map every function to its associated profile. @@ -504,6 +505,12 @@ class SampleProfileReaderExtBinaryBase : public SampleProfileReaderBinary { /// Read sample profiles in extensible format from the associated file. std::error_code read() override; + + /// Get the total size of all \p Type sections. + uint64_t getSectionSize(SecType Type); + /// Get the total size of header and all sections. + uint64_t getFileSize(); + virtual bool dumpSectionInfo(raw_ostream &OS = dbgs()) override; }; class SampleProfileReaderExtBinary : public SampleProfileReaderExtBinaryBase { diff --git a/llvm/lib/ProfileData/SampleProfReader.cpp b/llvm/lib/ProfileData/SampleProfReader.cpp index f6b33d962616c..07272ebac0a9e 100644 --- a/llvm/lib/ProfileData/SampleProfReader.cpp +++ b/llvm/lib/ProfileData/SampleProfReader.cpp @@ -667,6 +667,36 @@ std::error_code SampleProfileReaderExtBinaryBase::readHeader() { return sampleprof_error::success; } +uint64_t SampleProfileReaderExtBinaryBase::getSectionSize(SecType Type) { + for (auto &Entry : SecHdrTable) { + if (Entry.Type == Type) + return Entry.Size; + } + return 0; +} + +uint64_t SampleProfileReaderExtBinaryBase::getFileSize() { + auto &LastEntry = SecHdrTable.back(); + return LastEntry.Offset + LastEntry.Size; +} + +bool SampleProfileReaderExtBinaryBase::dumpSectionInfo(raw_ostream &OS) { + uint64_t TotalSecsSize = 0; + for (auto &Entry : SecHdrTable) { + OS << getSecName(Entry.Type) << " - Offset: " << Entry.Offset + << ", Size: " << Entry.Size << "\n"; + TotalSecsSize += getSectionSize(Entry.Type); + } + uint64_t HeaderSize = SecHdrTable.front().Offset; + assert(HeaderSize + TotalSecsSize == getFileSize() && + "Size of 'header + sections' doesn't match the total size of profile"); + + OS << "Header Size: " << HeaderSize << "\n"; + OS << "Total Sections Size: " << TotalSecsSize << "\n"; + OS << "File Size: " << getFileSize() << "\n"; + return true; +} + std::error_code SampleProfileReaderBinary::readMagicIdent() { // Read and check the magic identifier. auto Magic = readNumber(); diff --git a/llvm/test/tools/llvm-profdata/show-prof-size.test b/llvm/test/tools/llvm-profdata/show-prof-size.test new file mode 100644 index 0000000000000..0d1ecdcfd672f --- /dev/null +++ b/llvm/test/tools/llvm-profdata/show-prof-size.test @@ -0,0 +1,7 @@ +; RUN: llvm-profdata merge -sample -extbinary -prof-sym-list=%S/Inputs/profile-symbol-list-1.text %S/Inputs/sample-profile.proftext -o %t.1.output +; RUN: ls -l %t.1.output |cut -f5 -d ' ' > %t.txt +; RUN: llvm-profdata show -sample -show-sec-info-only %t.1.output >> %t.txt +; RUN: FileCheck %s --input-file=%t.txt +; Check llvm-profdata shows the correct file size. +; CHECK: [[FILESIZE:.*]] +; CHECK: [[FILESIZE]] diff --git a/llvm/tools/llvm-profdata/llvm-profdata.cpp b/llvm/tools/llvm-profdata/llvm-profdata.cpp index 4f825dfb5b87f..2b1205b950fd4 100644 --- a/llvm/tools/llvm-profdata/llvm-profdata.cpp +++ b/llvm/tools/llvm-profdata/llvm-profdata.cpp @@ -982,10 +982,21 @@ static int showInstrProfile(const std::string &Filename, bool ShowCounts, return 0; } +static void showSectionInfo(sampleprof::SampleProfileReader *Reader, + raw_fd_ostream &OS) { + if (!Reader->dumpSectionInfo(OS)) { + WithColor::warning() << "-show-sec-info-only is only supported for " + << "sample profile in extbinary format and is " + << "ignored for other formats.\n"; + return; + } +} + static int showSampleProfile(const std::string &Filename, bool ShowCounts, bool ShowAllFunctions, const std::string &ShowFunction, - bool ShowProfileSymbolList, raw_fd_ostream &OS) { + bool ShowProfileSymbolList, + bool ShowSectionInfoOnly, raw_fd_ostream &OS) { using namespace sampleprof; LLVMContext Context; auto ReaderOrErr = SampleProfileReader::create(Filename, Context); @@ -993,6 +1004,12 @@ static int showSampleProfile(const std::string &Filename, bool ShowCounts, exitWithErrorCode(EC, Filename); auto Reader = std::move(ReaderOrErr.get()); + + if (ShowSectionInfoOnly) { + showSectionInfo(Reader.get(), OS); + return 0; + } + if (std::error_code EC = Reader->read()) exitWithErrorCode(EC, Filename); @@ -1062,6 +1079,11 @@ static int show_main(int argc, const char *argv[]) { cl::opt ShowProfileSymbolList( "show-prof-sym-list", cl::init(false), cl::desc("Show profile symbol list if it exists in the profile. ")); + cl::opt ShowSectionInfoOnly( + "show-sec-info-only", cl::init(false), + cl::desc("Show the information of each section in the sample profile. " + "The flag is only usable when the sample profile is in " + "extbinary format")); cl::ParseCommandLineOptions(argc, argv, "LLVM profile data summary\n"); @@ -1090,7 +1112,8 @@ static int show_main(int argc, const char *argv[]) { OnlyListBelow, ShowFunction, TextFormat, OS); else return showSampleProfile(Filename, ShowCounts, ShowAllFunctions, - ShowFunction, ShowProfileSymbolList, OS); + ShowFunction, ShowProfileSymbolList, + ShowSectionInfoOnly, OS); } int main(int argc, const char *argv[]) { From 2f32e5d84d3483a0d6170fc61d2cceb49fc930a3 Mon Sep 17 00:00:00 2001 From: Teresa Johnson Date: Fri, 20 Sep 2019 23:29:17 +0000 Subject: [PATCH 43/71] [Inliner] Remove incorrect early exit during switch cost computation Summary: The CallAnalyzer::visitSwitchInst has an early exit when the estimated lower bound of the switch cost will put the overall cost of the inline above the threshold. However, this code is not correctly estimating the lower bound for switches that can be transformed into bit tests, leading to unnecessary lost inlines, and also differing behavior with optimization remarks enabled. First, the early exit is controlled by whether ComputeFullInlineCost is enabled or not, and that in turn is disabled by default but enabled when enabling -pass-remarks=missed. This by itself wouldn't lead to a problem, except that as described below, the lower bound can be above the real lower bound, so we can sometimes get different inline decisions with inline remarks enabled, which is problematic. The early exit was added in along with a new switch cost model in D31085. The reason why this early exit was added is due to a concern one reviewer raised about compile time for large switches: https://reviews.llvm.org/D31085?id=94559#inline-276200 However, the code just below there calls getEstimatedNumberOfCaseClusters, which in turn immediately calls BasicTTIImpl getEstimatedNumberOfCaseClusters, which in the worst case does a linear scan of the cases to get the high and low values. The bit test handling in particular is guarded by whether the number of cases fits into the max bit width. There is no suggestion that anyone measured a compile time issue, it appears to be theoretical. The problem is that the reviewer's comment about the lower bound calculation is incorrect, specifically in the case of a switch that can be lowered to a bit test. This isn't followed up on the comment thread, but the author does add a FIXME to that effect above the early exit added when they subsequently revised the patch. As a result, we were incorrectly early exiting and not inlining functions with switch statements that would be lowered to bit tests in cases where we were nearing the threshold. Combined with the fact that this early exit was skipped with opt remarks enabled, this caused different inlining decisions to be made when -pass-remarks=missed is enabled to debug the missing inline. Remove the early exit for the above reasons. I also copied over an existing AArch64 inlining test to X86, and adjusted the threshold so that the bit test inline only occurs with the fix in this patch. Reviewers: davidxl Subscribers: eraman, kristof.beyls, haicheng, llvm-commits Tags: #llvm Differential Revision: https://reviews.llvm.org/D67716 llvm-svn: 372440 --- llvm/lib/Analysis/InlineCost.cpp | 13 -- llvm/test/Transforms/Inline/X86/switch.ll | 160 ++++++++++++++++++++++ 2 files changed, 160 insertions(+), 13 deletions(-) create mode 100644 llvm/test/Transforms/Inline/X86/switch.ll diff --git a/llvm/lib/Analysis/InlineCost.cpp b/llvm/lib/Analysis/InlineCost.cpp index c6e5c1c1ace93..57dee459fc2cb 100644 --- a/llvm/lib/Analysis/InlineCost.cpp +++ b/llvm/lib/Analysis/InlineCost.cpp @@ -1453,19 +1453,6 @@ bool CallAnalyzer::visitSwitchInst(SwitchInst &SI) { // Maximum valid cost increased in this function. int CostUpperBound = INT_MAX - InlineConstants::InstrCost - 1; - // Exit early for a large switch, assuming one case needs at least one - // instruction. - // FIXME: This is not true for a bit test, but ignore such case for now to - // save compile-time. - int64_t CostLowerBound = - std::min((int64_t)CostUpperBound, - (int64_t)SI.getNumCases() * InlineConstants::InstrCost + Cost); - - if (CostLowerBound > Threshold && !ComputeFullInlineCost) { - addCost((int64_t)SI.getNumCases() * InlineConstants::InstrCost); - return false; - } - unsigned JumpTableSize = 0; unsigned NumCaseCluster = TTI.getEstimatedNumberOfCaseClusters(SI, JumpTableSize); diff --git a/llvm/test/Transforms/Inline/X86/switch.ll b/llvm/test/Transforms/Inline/X86/switch.ll new file mode 100644 index 0000000000000..5565c7aba5036 --- /dev/null +++ b/llvm/test/Transforms/Inline/X86/switch.ll @@ -0,0 +1,160 @@ +; RUN: opt < %s -inline -inline-threshold=1 -S -mtriple=x86_64-unknown-linux-gnu | FileCheck %s +; RUN: opt < %s -passes='cgscc(inline)' -inline-threshold=1 -S -mtriple=x86_64-unknown-linux-gnu | FileCheck %s + +define i32 @callee_range(i32 %a, i32* %P) { + switch i32 %a, label %sw.default [ + i32 0, label %sw.bb0 + i32 1000, label %sw.bb1 + i32 2000, label %sw.bb1 + i32 3000, label %sw.bb1 + i32 4000, label %sw.bb1 + i32 5000, label %sw.bb1 + i32 6000, label %sw.bb1 + i32 7000, label %sw.bb1 + i32 8000, label %sw.bb1 + i32 9000, label %sw.bb1 + ] + +sw.default: + store volatile i32 %a, i32* %P + br label %return +sw.bb0: + store volatile i32 %a, i32* %P + br label %return +sw.bb1: + store volatile i32 %a, i32* %P + br label %return +return: + ret i32 42 +} + +define i32 @caller_range(i32 %a, i32* %P) { +; CHECK-LABEL: @caller_range( +; CHECK: call i32 @callee_range + %r = call i32 @callee_range(i32 %a, i32* %P) + ret i32 %r +} + +define i32 @callee_bittest(i32 %a, i32* %P) { + switch i32 %a, label %sw.default [ + i32 0, label %sw.bb0 + i32 1, label %sw.bb1 + i32 2, label %sw.bb2 + i32 3, label %sw.bb0 + i32 4, label %sw.bb1 + i32 5, label %sw.bb2 + i32 6, label %sw.bb0 + i32 7, label %sw.bb1 + i32 8, label %sw.bb2 + ] + +sw.default: + store volatile i32 %a, i32* %P + br label %return + +sw.bb0: + store volatile i32 %a, i32* %P + br label %return + +sw.bb1: + store volatile i32 %a, i32* %P + br label %return + +sw.bb2: + br label %return + +return: + ret i32 42 +} + + +define i32 @caller_bittest(i32 %a, i32* %P) { +; CHECK-LABEL: @caller_bittest( +; CHECK-NOT: call i32 @callee_bittest + %r= call i32 @callee_bittest(i32 %a, i32* %P) + ret i32 %r +} + +define i32 @callee_jumptable(i32 %a, i32* %P) { + switch i32 %a, label %sw.default [ + i32 1001, label %sw.bb101 + i32 1002, label %sw.bb102 + i32 1003, label %sw.bb103 + i32 1004, label %sw.bb104 + i32 1005, label %sw.bb101 + i32 1006, label %sw.bb102 + i32 1007, label %sw.bb103 + i32 1008, label %sw.bb104 + i32 1009, label %sw.bb101 + i32 1010, label %sw.bb102 + i32 1011, label %sw.bb103 + i32 1012, label %sw.bb104 + ] + +sw.default: + br label %return + +sw.bb101: + store volatile i32 %a, i32* %P + br label %return + +sw.bb102: + store volatile i32 %a, i32* %P + br label %return + +sw.bb103: + store volatile i32 %a, i32* %P + br label %return + +sw.bb104: + store volatile i32 %a, i32* %P + br label %return + +return: + ret i32 42 +} + +define i32 @caller_jumptable(i32 %a, i32 %b, i32* %P) { +; CHECK-LABEL: @caller_jumptable( +; CHECK: call i32 @callee_jumptable + %r = call i32 @callee_jumptable(i32 %b, i32* %P) + ret i32 %r +} + + +define internal i32 @callee_negativeCost(i32 %t) { +entry: + switch i32 %t, label %sw.default [ + i32 1, label %sw.bb + i32 0, label %sw.bb1 + i32 42, label %sw.bb2 + i32 43, label %sw.bb3 + ] + +sw.bb: ; preds = %entry + br label %cleanup + +sw.bb1: ; preds = %entry + br label %cleanup + +sw.bb2: ; preds = %entry + br label %cleanup + +sw.bb3: ; preds = %entry + br label %cleanup + +sw.default: ; preds = %entry + br label %cleanup + +cleanup: ; preds = %sw.default, %sw.bb3, %sw.bb2, %sw.bb1, %sw.bb + %retval.0 = phi i32 [ 1, %sw.default ], [ 3, %sw.bb3 ], [ 2, %sw.bb2 ], [ 0, %sw.bb1 ], [ 0, %sw.bb ] + ret i32 %retval.0 +} + +define i32 @caller_negativeCost(i32 %t) { +; CHECK-LABEL: @caller_negativeCost( +; CHECK-NOT: call i32 @callee_negativeCost +entry: + %call = call i32 @callee_negativeCost(i32 %t) + ret i32 %call +} From e021d6909436c6baac2dc7c9065340862a9b9aa2 Mon Sep 17 00:00:00 2001 From: Jonas Devlieghere Date: Fri, 20 Sep 2019 23:41:29 +0000 Subject: [PATCH 44/71] dotest.py: bugfix: test filters with -f do not work on Python3 dotest -f does not work on Python3. The name types.UnboundMethodType was an alias for types.MethodType in 2.7, but it does not exist in python3. MethodType works in both. Also the actual type returned from SomeClass.some_method in python3 will be types.Function, not MethodType. Patch by: Lawrence D'Anna Differential revision: https://reviews.llvm.org/D67791 llvm-svn: 372441 --- lldb/third_party/Python/module/unittest2/unittest2/loader.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lldb/third_party/Python/module/unittest2/unittest2/loader.py b/lldb/third_party/Python/module/unittest2/unittest2/loader.py index 996dd76647579..87edddca40281 100644 --- a/lldb/third_party/Python/module/unittest2/unittest2/loader.py +++ b/lldb/third_party/Python/module/unittest2/unittest2/loader.py @@ -117,7 +117,7 @@ def loadTestsFromName(self, name, module=None): return self.loadTestsFromModule(obj) elif isinstance(obj, type) and issubclass(obj, unittest.TestCase): return self.loadTestsFromTestCase(obj) - elif (isinstance(obj, types.UnboundMethodType) and + elif (isinstance(obj, (types.MethodType, types.FunctionType)) and isinstance(parent, type) and issubclass(parent, case.TestCase)): return self.suiteClass([parent(obj.__name__)]) From 7d6a95cf83fcca92e64302194995601474bc161a Mon Sep 17 00:00:00 2001 From: Jonas Devlieghere Date: Fri, 20 Sep 2019 23:41:32 +0000 Subject: [PATCH 45/71] prepare_binding_Python: print readable errors if SWIG fails When swig fails, all the errors are squished onto one line with \n quoting. It's very hard to read. This will print them out in a more reasonable format. Patch by: Lawrence D'Anna Differential revision: https://reviews.llvm.org/D67790 llvm-svn: 372442 --- lldb/scripts/Python/prepare_binding_Python.py | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/lldb/scripts/Python/prepare_binding_Python.py b/lldb/scripts/Python/prepare_binding_Python.py index 7d13d6ebb17f7..fc409b09eb3f4 100644 --- a/lldb/scripts/Python/prepare_binding_Python.py +++ b/lldb/scripts/Python/prepare_binding_Python.py @@ -231,11 +231,13 @@ def do_swig_rebuild(options, dependency_file, config_build_dir, settings): swig_stdout, swig_stderr = process.communicate() return_code = process.returncode if return_code != 0: + swig_stdout = swig_stdout.decode('utf8', errors='replace').rstrip() + swig_stderr = swig_stderr.decode('utf8', errors='replace').rstrip() + swig_stdout = re.sub(r'^(?=.)', 'stdout: ', swig_stdout, flags=re.MULTILINE) + swig_stderr = re.sub(r'^(?=.)', 'stderr: ', swig_stderr, flags=re.MULTILINE) logging.error( - "swig failed with error code %d: stdout=%s, stderr=%s", - return_code, - swig_stdout, - swig_stderr) + "swig failed with error code %d\n%s%s", + return_code, swig_stdout, swig_stderr) logging.error( "command line:\n%s", ' '.join(command)) sys.exit(return_code) From 7ac1039957f9aebcdf3ccf36cdd11067eb42b832 Mon Sep 17 00:00:00 2001 From: Amara Emerson Date: Fri, 20 Sep 2019 23:52:07 +0000 Subject: [PATCH 46/71] [GlobalISel] Defer setting HasCalls on MachineFrameInfo to selection time. We currently always set the HasCalls on MFI during translation and legalization if we're handling a call or legalizing to a libcall. However, if that call is later optimized to a tail call then we don't need the flag. The flag being set to true causes frame lowering to always save and restore FP/LR, which adds unnecessary code. This change does the same thing as SelectionDAG and ports over some code that scans instructions after selection, using TargetInstrInfo to determine if target opcodes are known calls. Code size geomean improvements on CTMark: -O0 : 0.1% -Os : 0.3% Differential Revision: https://reviews.llvm.org/D67868 llvm-svn: 372443 --- llvm/lib/CodeGen/GlobalISel/IRTranslator.cpp | 4 +++- .../CodeGen/GlobalISel/InstructionSelect.cpp | 18 +++++++++++++++++ .../CodeGen/GlobalISel/LegalizerHelper.cpp | 3 --- .../AArch64/GlobalISel/call-translator.ll | 1 - .../GlobalISel/tail-call-no-save-fp-lr.ll | 20 +++++++++++++++++++ 5 files changed, 41 insertions(+), 5 deletions(-) create mode 100644 llvm/test/CodeGen/AArch64/GlobalISel/tail-call-no-save-fp-lr.ll diff --git a/llvm/lib/CodeGen/GlobalISel/IRTranslator.cpp b/llvm/lib/CodeGen/GlobalISel/IRTranslator.cpp index c44532e240f8b..74365af7a2b73 100644 --- a/llvm/lib/CodeGen/GlobalISel/IRTranslator.cpp +++ b/llvm/lib/CodeGen/GlobalISel/IRTranslator.cpp @@ -1564,7 +1564,9 @@ bool IRTranslator::translateCallSite(const ImmutableCallSite &CS, Args.push_back(getOrCreateVRegs(*Arg)); } - MF->getFrameInfo().setHasCalls(true); + // We don't set HasCalls on MFI here yet because call lowering may decide to + // optimize into tail calls. Instead, we defer that to selection where a final + // scan is done to check if any instructions are calls. bool Success = CLI->lowerCall(MIRBuilder, CS, Res, Args, SwiftErrorVReg, [&]() { return getOrCreateVReg(*CS.getCalledValue()); }); diff --git a/llvm/lib/CodeGen/GlobalISel/InstructionSelect.cpp b/llvm/lib/CodeGen/GlobalISel/InstructionSelect.cpp index bf441afc9dc80..7c4fd2d140d36 100644 --- a/llvm/lib/CodeGen/GlobalISel/InstructionSelect.cpp +++ b/llvm/lib/CodeGen/GlobalISel/InstructionSelect.cpp @@ -17,7 +17,9 @@ #include "llvm/CodeGen/GlobalISel/LegalizerInfo.h" #include "llvm/CodeGen/GlobalISel/Utils.h" #include "llvm/CodeGen/MachineOptimizationRemarkEmitter.h" +#include "llvm/CodeGen/MachineFrameInfo.h" #include "llvm/CodeGen/MachineRegisterInfo.h" +#include "llvm/CodeGen/TargetInstrInfo.h" #include "llvm/CodeGen/TargetLowering.h" #include "llvm/CodeGen/TargetPassConfig.h" #include "llvm/CodeGen/TargetSubtargetInfo.h" @@ -223,6 +225,22 @@ bool InstructionSelect::runOnMachineFunction(MachineFunction &MF) { auto &TLI = *MF.getSubtarget().getTargetLowering(); TLI.finalizeLowering(MF); + // Determine if there are any calls in this machine function. Ported from + // SelectionDAG. + MachineFrameInfo &MFI = MF.getFrameInfo(); + for (const auto &MBB : MF) { + if (MFI.hasCalls() && MF.hasInlineAsm()) + break; + + for (const auto &MI : MBB) { + if ((MI.isCall() && !MI.isReturn()) || MI.isStackAligningInlineAsm()) + MFI.setHasCalls(true); + if (MI.isInlineAsm()) + MF.setHasInlineAsm(true); + } + } + + LLVM_DEBUG({ dbgs() << "Rules covered by selecting function: " << MF.getName() << ":"; for (auto RuleID : CoverageInfo.covered()) diff --git a/llvm/lib/CodeGen/GlobalISel/LegalizerHelper.cpp b/llvm/lib/CodeGen/GlobalISel/LegalizerHelper.cpp index d4ae3b52a465c..f2b37eada2e0e 100644 --- a/llvm/lib/CodeGen/GlobalISel/LegalizerHelper.cpp +++ b/llvm/lib/CodeGen/GlobalISel/LegalizerHelper.cpp @@ -364,8 +364,6 @@ llvm::createLibcall(MachineIRBuilder &MIRBuilder, RTLIB::Libcall Libcall, auto &TLI = *MIRBuilder.getMF().getSubtarget().getTargetLowering(); const char *Name = TLI.getLibcallName(Libcall); - MIRBuilder.getMF().getFrameInfo().setHasCalls(true); - CallLowering::CallLoweringInfo Info; Info.CallConv = TLI.getLibcallCallingConv(Libcall); Info.Callee = MachineOperand::CreateES(Name); @@ -430,7 +428,6 @@ llvm::createMemLibcall(MachineIRBuilder &MIRBuilder, MachineRegisterInfo &MRI, const char *Name = TLI.getLibcallName(RTLibcall); MIRBuilder.setInstr(MI); - MIRBuilder.getMF().getFrameInfo().setHasCalls(true); CallLowering::CallLoweringInfo Info; Info.CallConv = TLI.getLibcallCallingConv(RTLibcall); diff --git a/llvm/test/CodeGen/AArch64/GlobalISel/call-translator.ll b/llvm/test/CodeGen/AArch64/GlobalISel/call-translator.ll index b5e66d69ca07b..d6d39281f9bea 100644 --- a/llvm/test/CodeGen/AArch64/GlobalISel/call-translator.ll +++ b/llvm/test/CodeGen/AArch64/GlobalISel/call-translator.ll @@ -100,7 +100,6 @@ define {double, i64, i32} @test_struct_return({double, i64, i32}* %addr) { } ; CHECK-LABEL: name: test_arr_call -; CHECK: hasCalls: true ; CHECK: %0:_(p0) = COPY $x0 ; CHECK: [[LD1:%[0-9]+]]:_(s64) = G_LOAD %0(p0) :: (load 8 from %ir.addr) ; CHECK: [[CST1:%[0-9]+]]:_(s64) = G_CONSTANT i64 8 diff --git a/llvm/test/CodeGen/AArch64/GlobalISel/tail-call-no-save-fp-lr.ll b/llvm/test/CodeGen/AArch64/GlobalISel/tail-call-no-save-fp-lr.ll new file mode 100644 index 0000000000000..533e126292ae1 --- /dev/null +++ b/llvm/test/CodeGen/AArch64/GlobalISel/tail-call-no-save-fp-lr.ll @@ -0,0 +1,20 @@ +; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py +; RUN: llc %s -verify-machineinstrs -mtriple aarch64-apple-darwin -global-isel -global-isel-abort=1 -o - 2>&1 | FileCheck %s + +; Check that we get a tail call to foo without saving fp/lr. +define void @bar(i32 %a) #1 { +; CHECK-LABEL: bar: +; CHECK: ; %bb.0: ; %entry +; CHECK-NEXT: b _zoo +entry: + tail call void @zoo(i32 undef) + ret void +} + +define void @zoo(i32 %a) { +entry: + ret void +} + +attributes #1 = { "frame-pointer"="all" } + From 172e8a7a5de1c5aa110272da5483138e9aabc204 Mon Sep 17 00:00:00 2001 From: Alex Lorenz Date: Sat, 21 Sep 2019 00:17:26 +0000 Subject: [PATCH 47/71] [clang-scan-deps] strip the --serialize-diagnostics argument This ensures that clang-scan-deps won't write out diagnostics when scanning dependencies. llvm-svn: 372444 --- clang/include/clang/Tooling/ArgumentsAdjusters.h | 4 ++++ clang/lib/Tooling/ArgumentsAdjusters.cpp | 16 ++++++++++++++++ .../Inputs/strip_diag_serialize.json | 7 +++++++ .../test/ClangScanDeps/strip_diag_serialize.cpp | 11 +++++++++++ clang/tools/clang-scan-deps/ClangScanDeps.cpp | 2 ++ 5 files changed, 40 insertions(+) create mode 100644 clang/test/ClangScanDeps/Inputs/strip_diag_serialize.json create mode 100644 clang/test/ClangScanDeps/strip_diag_serialize.cpp diff --git a/clang/include/clang/Tooling/ArgumentsAdjusters.h b/clang/include/clang/Tooling/ArgumentsAdjusters.h index bf0886034324a..c48a8725aae90 100644 --- a/clang/include/clang/Tooling/ArgumentsAdjusters.h +++ b/clang/include/clang/Tooling/ArgumentsAdjusters.h @@ -43,6 +43,10 @@ ArgumentsAdjuster getClangSyntaxOnlyAdjuster(); /// arguments. ArgumentsAdjuster getClangStripOutputAdjuster(); +/// Gets an argument adjuster which removes command line arguments related to +/// diagnostic serialization. +ArgumentsAdjuster getClangStripSerializeDiagnosticAdjuster(); + /// Gets an argument adjuster which removes dependency-file /// related command line arguments. ArgumentsAdjuster getClangStripDependencyFileAdjuster(); diff --git a/clang/lib/Tooling/ArgumentsAdjusters.cpp b/clang/lib/Tooling/ArgumentsAdjusters.cpp index 942b35df453e9..f56d08c47b9a4 100644 --- a/clang/lib/Tooling/ArgumentsAdjusters.cpp +++ b/clang/lib/Tooling/ArgumentsAdjusters.cpp @@ -57,6 +57,22 @@ ArgumentsAdjuster getClangStripOutputAdjuster() { }; } +ArgumentsAdjuster getClangStripSerializeDiagnosticAdjuster() { + return [](const CommandLineArguments &Args, StringRef /*unused*/) { + CommandLineArguments AdjustedArgs; + for (size_t i = 0, e = Args.size(); i < e; ++i) { + StringRef Arg = Args[i]; + if (Arg == "--serialize-diagnostics") { + // Skip the diagnostic output argument. + ++i; + continue; + } + AdjustedArgs.push_back(Args[i]); + } + return AdjustedArgs; + }; +} + ArgumentsAdjuster getClangStripDependencyFileAdjuster() { return [](const CommandLineArguments &Args, StringRef /*unused*/) { CommandLineArguments AdjustedArgs; diff --git a/clang/test/ClangScanDeps/Inputs/strip_diag_serialize.json b/clang/test/ClangScanDeps/Inputs/strip_diag_serialize.json new file mode 100644 index 0000000000000..a774d95a3b023 --- /dev/null +++ b/clang/test/ClangScanDeps/Inputs/strip_diag_serialize.json @@ -0,0 +1,7 @@ +[ +{ + "directory": "DIR", + "command": "clang -E -fsyntax-only DIR/strip_diag_serialize_input.cpp --serialize-diagnostics /does/not/exist", + "file": "DIR/strip_diag_serialize_input.cpp" +} +] diff --git a/clang/test/ClangScanDeps/strip_diag_serialize.cpp b/clang/test/ClangScanDeps/strip_diag_serialize.cpp new file mode 100644 index 0000000000000..ec62e75134814 --- /dev/null +++ b/clang/test/ClangScanDeps/strip_diag_serialize.cpp @@ -0,0 +1,11 @@ +// RUN: rm -rf %t.dir +// RUN: rm -rf %t.cdb +// RUN: mkdir -p %t.dir +// RUN: cp %s %t.dir/strip_diag_serialize_input.cpp +// RUN: sed -e "s|DIR|%/t.dir|g" %S/Inputs/strip_diag_serialize.json > %t.cdb +// +// RUN: clang-scan-deps -compilation-database %t.cdb 2>&1 | FileCheck %s +// CHECK-NOT: unable to open file +// CHECK: strip_diag_serialize_input.cpp + +#warning "diagnostic" diff --git a/clang/tools/clang-scan-deps/ClangScanDeps.cpp b/clang/tools/clang-scan-deps/ClangScanDeps.cpp index ebb42c034633e..d44e3b9ff3558 100644 --- a/clang/tools/clang-scan-deps/ClangScanDeps.cpp +++ b/clang/tools/clang-scan-deps/ClangScanDeps.cpp @@ -266,6 +266,8 @@ int main(int argc, const char **argv) { AdjustedArgs.push_back("-Wno-error"); return AdjustedArgs; }); + AdjustingCompilations->appendArgumentsAdjuster( + tooling::getClangStripSerializeDiagnosticAdjuster()); SharedStream Errs(llvm::errs()); // Print out the dependency results to STDOUT by default. From 2f6a52816fc33cf24373ce2aaf7df08b95403f44 Mon Sep 17 00:00:00 2001 From: Stephane Moore Date: Sat, 21 Sep 2019 01:22:22 +0000 Subject: [PATCH 48/71] =?UTF-8?q?[clang-tidy]=20Add=20check=20for=20classe?= =?UTF-8?q?s=20missing=20-hash=20=E2=9A=A0=EF=B8=8F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Summary: Apple documentation states that: "If two objects are equal, they must have the same hash value. This last point is particularly important if you define isEqual: in a subclass and intend to put instances of that subclass into a collection. Make sure you also define hash in your subclass." https://developer.apple.com/documentation/objectivec/1418956-nsobject/1418795-isequal?language=objc In many or all versions of libobjc, -[NSObject isEqual:] is a pointer equality check and -[NSObject hash] returns the messaged object's pointer. A relatively common form of developer error is for a developer to override -isEqual: in a subclass without overriding -hash to ensure that hashes are equal for objects that are equal. It is assumed that an override of -isEqual: is a strong signal for changing the object's equality operator to something other than pointer equality which implies that a missing override of -hash could result in distinct objects being equal but having distinct hashes because they are independent instances. This added check flags classes that override -isEqual: but inherit NSObject's implementation of -hash to warn of the potential for unexpected behavior. The proper implementation of -hash is the responsibility of the developer and the check will only verify that the developer made an effort to properly implement -hash. Developers can set up unit tests to verify that their implementation of -hash is appropriate. Test Notes: Ran check-clang-tools. Reviewers: aaron.ballman, benhamilton Reviewed By: aaron.ballman Subscribers: Eugene.Zelenko, mgorny, xazax.hun, cfe-commits Tags: #clang Differential Revision: https://reviews.llvm.org/D67737 llvm-svn: 372445 --- .../clang-tidy/objc/CMakeLists.txt | 1 + .../clang-tidy/objc/MissingHashCheck.cpp | 62 +++++++++++++++++ .../clang-tidy/objc/MissingHashCheck.h | 35 ++++++++++ .../clang-tidy/objc/ObjCTidyModule.cpp | 3 + clang-tools-extra/docs/ReleaseNotes.rst | 6 ++ .../docs/clang-tidy/checks/list.rst | 1 + .../clang-tidy/checks/objc-missing-hash.rst | 16 +++++ .../test/clang-tidy/objc-missing-hash.m | 68 +++++++++++++++++++ 8 files changed, 192 insertions(+) create mode 100644 clang-tools-extra/clang-tidy/objc/MissingHashCheck.cpp create mode 100644 clang-tools-extra/clang-tidy/objc/MissingHashCheck.h create mode 100644 clang-tools-extra/docs/clang-tidy/checks/objc-missing-hash.rst create mode 100644 clang-tools-extra/test/clang-tidy/objc-missing-hash.m diff --git a/clang-tools-extra/clang-tidy/objc/CMakeLists.txt b/clang-tools-extra/clang-tidy/objc/CMakeLists.txt index 4eeb14844a58d..0a12e4a850d50 100644 --- a/clang-tools-extra/clang-tidy/objc/CMakeLists.txt +++ b/clang-tools-extra/clang-tidy/objc/CMakeLists.txt @@ -4,6 +4,7 @@ add_clang_library(clangTidyObjCModule AvoidNSErrorInitCheck.cpp AvoidSpinlockCheck.cpp ForbiddenSubclassingCheck.cpp + MissingHashCheck.cpp ObjCTidyModule.cpp PropertyDeclarationCheck.cpp SuperSelfCheck.cpp diff --git a/clang-tools-extra/clang-tidy/objc/MissingHashCheck.cpp b/clang-tools-extra/clang-tidy/objc/MissingHashCheck.cpp new file mode 100644 index 0000000000000..0da5571b2f26c --- /dev/null +++ b/clang-tools-extra/clang-tidy/objc/MissingHashCheck.cpp @@ -0,0 +1,62 @@ +//===--- MissingHashCheck.cpp - clang-tidy --------------------------------===// +// +// 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 "MissingHashCheck.h" +#include "clang/AST/ASTContext.h" +#include "clang/ASTMatchers/ASTMatchFinder.h" + +using namespace clang::ast_matchers; + +namespace clang { +namespace tidy { +namespace objc { + +namespace { + +AST_MATCHER_P(ObjCImplementationDecl, hasInterface, + ast_matchers::internal::Matcher, Base) { + const ObjCInterfaceDecl *InterfaceDecl = Node.getClassInterface(); + return Base.matches(*InterfaceDecl, Finder, Builder); +} + +AST_MATCHER_P(ObjCContainerDecl, hasInstanceMethod, + ast_matchers::internal::Matcher, Base) { + // Check each instance method against the provided matcher. + for (const auto *I : Node.instance_methods()) { + if (Base.matches(*I, Finder, Builder)) + return true; + } + return false; +} + +} // namespace + +void MissingHashCheck::registerMatchers(MatchFinder *Finder) { + // This check should only be applied to Objective-C sources. + if (!getLangOpts().ObjC) + return; + + Finder->addMatcher( + objcMethodDecl( + hasName("isEqual:"), isInstanceMethod(), + hasDeclContext(objcImplementationDecl( + hasInterface(isDirectlyDerivedFrom("NSObject")), + unless(hasInstanceMethod(hasName("hash")))) + .bind("impl"))), + this); +} + +void MissingHashCheck::check(const MatchFinder::MatchResult &Result) { + const auto *ID = Result.Nodes.getNodeAs("impl"); + diag(ID->getLocation(), "%0 implements -isEqual: without implementing -hash") + << ID; +} + +} // namespace objc +} // namespace tidy +} // namespace clang diff --git a/clang-tools-extra/clang-tidy/objc/MissingHashCheck.h b/clang-tools-extra/clang-tidy/objc/MissingHashCheck.h new file mode 100644 index 0000000000000..4ac74d5865218 --- /dev/null +++ b/clang-tools-extra/clang-tidy/objc/MissingHashCheck.h @@ -0,0 +1,35 @@ +//===--- MissingHashCheck.h - clang-tidy ------------------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_OBJC_MISSINGHASHCHECK_H +#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_OBJC_MISSINGHASHCHECK_H + +#include "../ClangTidyCheck.h" + +namespace clang { +namespace tidy { +namespace objc { + +/// Finds Objective-C implementations that implement -isEqual: without also +/// appropriately implementing -hash. +/// +/// For the user-facing documentation see: +/// http://clang.llvm.org/extra/clang-tidy/checks/objc-missing-hash.html +class MissingHashCheck : public ClangTidyCheck { +public: + MissingHashCheck(StringRef Name, ClangTidyContext *Context) + : ClangTidyCheck(Name, Context) {} + void registerMatchers(ast_matchers::MatchFinder *Finder) override; + void check(const ast_matchers::MatchFinder::MatchResult &Result) override; +}; + +} // namespace objc +} // namespace tidy +} // namespace clang + +#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_OBJC_MISSINGHASHCHECK_H diff --git a/clang-tools-extra/clang-tidy/objc/ObjCTidyModule.cpp b/clang-tools-extra/clang-tidy/objc/ObjCTidyModule.cpp index 636e2c02af649..c9b57d5e2c819 100644 --- a/clang-tools-extra/clang-tidy/objc/ObjCTidyModule.cpp +++ b/clang-tools-extra/clang-tidy/objc/ObjCTidyModule.cpp @@ -12,6 +12,7 @@ #include "AvoidNSErrorInitCheck.h" #include "AvoidSpinlockCheck.h" #include "ForbiddenSubclassingCheck.h" +#include "MissingHashCheck.h" #include "PropertyDeclarationCheck.h" #include "SuperSelfCheck.h" @@ -30,6 +31,8 @@ class ObjCModule : public ClangTidyModule { "objc-avoid-spinlock"); CheckFactories.registerCheck( "objc-forbidden-subclassing"); + CheckFactories.registerCheck( + "objc-missing-hash"); CheckFactories.registerCheck( "objc-property-declaration"); CheckFactories.registerCheck( diff --git a/clang-tools-extra/docs/ReleaseNotes.rst b/clang-tools-extra/docs/ReleaseNotes.rst index fc72a332d25f8..d16d8c1b0f0aa 100644 --- a/clang-tools-extra/docs/ReleaseNotes.rst +++ b/clang-tools-extra/docs/ReleaseNotes.rst @@ -91,6 +91,12 @@ Improvements to clang-tidy Finds historical use of ``unsigned`` to hold vregs and physregs and rewrites them to use ``Register`` +- New :doc:`objc-missing-hash + ` check. + + Finds Objective-C implementations that implement ``-isEqual:`` without also + appropriately implementing ``-hash``. + - Improved :doc:`bugprone-posix-return ` check. diff --git a/clang-tools-extra/docs/clang-tidy/checks/list.rst b/clang-tools-extra/docs/clang-tidy/checks/list.rst index a906a5b291178..e81b62d5d45c7 100644 --- a/clang-tools-extra/docs/clang-tidy/checks/list.rst +++ b/clang-tools-extra/docs/clang-tidy/checks/list.rst @@ -325,6 +325,7 @@ Clang-Tidy Checks objc-avoid-nserror-init objc-avoid-spinlock objc-forbidden-subclassing + objc-missing-hash objc-property-declaration objc-super-self openmp-exception-escape diff --git a/clang-tools-extra/docs/clang-tidy/checks/objc-missing-hash.rst b/clang-tools-extra/docs/clang-tidy/checks/objc-missing-hash.rst new file mode 100644 index 0000000000000..ea8f775897c21 --- /dev/null +++ b/clang-tools-extra/docs/clang-tidy/checks/objc-missing-hash.rst @@ -0,0 +1,16 @@ +.. title:: clang-tidy - objc-missing-hash + +objc-missing-hash +================= + +Finds Objective-C implementations that implement ``-isEqual:`` without also +appropriately implementing ``-hash``. + +Apple documentation highlights that objects that are equal must have the same +hash value: +https://developer.apple.com/documentation/objectivec/1418956-nsobject/1418795-isequal?language=objc + +Note that the check only verifies the presence of ``-hash`` in scenarios where +its omission could result in unexpected behavior. The verification of the +implementation of ``-hash`` is the responsibility of the developer, e.g., +through the addition of unit tests to verify the implementation. diff --git a/clang-tools-extra/test/clang-tidy/objc-missing-hash.m b/clang-tools-extra/test/clang-tidy/objc-missing-hash.m new file mode 100644 index 0000000000000..b9cc9d023ad13 --- /dev/null +++ b/clang-tools-extra/test/clang-tidy/objc-missing-hash.m @@ -0,0 +1,68 @@ +// RUN: %check_clang_tidy %s objc-missing-hash %t + +typedef _Bool BOOL; +#define YES 1 +#define NO 0 +typedef unsigned int NSUInteger; +typedef void *id; + +@interface NSObject +- (NSUInteger)hash; +- (BOOL)isEqual:(id)object; +@end + +@interface MissingHash : NSObject +@end + +@implementation MissingHash +// CHECK-MESSAGES: :[[@LINE-1]]:17: warning: 'MissingHash' implements -isEqual: without implementing -hash [objc-missing-hash] + +- (BOOL)isEqual:(id)object { + return YES; +} + +@end + +@interface HasHash : NSObject +@end + +@implementation HasHash + +- (NSUInteger)hash { + return 0; +} + +- (BOOL)isEqual:(id)object { + return YES; +} + +@end + +@interface NSArray : NSObject +@end + +@interface MayHaveInheritedHash : NSArray +@end + +@implementation MayHaveInheritedHash + +- (BOOL)isEqual:(id)object { + return YES; +} + +@end + +@interface AnotherRootClass +@end + +@interface NotDerivedFromNSObject : AnotherRootClass +@end + +@implementation NotDerivedFromNSObject + +- (BOOL)isEqual:(id)object { + return NO; +} + +@end + From c96d5545f0c97b3ad88672a09a4feeb7256ce2cb Mon Sep 17 00:00:00 2001 From: GN Sync Bot Date: Sat, 21 Sep 2019 01:27:09 +0000 Subject: [PATCH 49/71] gn build: Merge r372445 llvm-svn: 372446 --- .../gn/secondary/clang-tools-extra/clang-tidy/objc/BUILD.gn | 1 + 1 file changed, 1 insertion(+) diff --git a/llvm/utils/gn/secondary/clang-tools-extra/clang-tidy/objc/BUILD.gn b/llvm/utils/gn/secondary/clang-tools-extra/clang-tidy/objc/BUILD.gn index 714a4a1fab021..47cd0c8c6cda8 100644 --- a/llvm/utils/gn/secondary/clang-tools-extra/clang-tidy/objc/BUILD.gn +++ b/llvm/utils/gn/secondary/clang-tools-extra/clang-tidy/objc/BUILD.gn @@ -14,6 +14,7 @@ static_library("objc") { "AvoidNSErrorInitCheck.cpp", "AvoidSpinlockCheck.cpp", "ForbiddenSubclassingCheck.cpp", + "MissingHashCheck.cpp", "ObjCTidyModule.cpp", "PropertyDeclarationCheck.cpp", "SuperSelfCheck.cpp", From 3e6590c45177958030513e6be199fc2d54f13ac7 Mon Sep 17 00:00:00 2001 From: Artur Pilipenko Date: Sat, 21 Sep 2019 01:37:14 +0000 Subject: [PATCH 50/71] Support for 64-bit PC-relative relocations for X86_64 ELF files generated for X86_64 targets may contain 64-bit PC-relative relocations. For instance, an exception handler table entry contains the start of exception-throwing frame relative to the start of exception handler. As these two labels belong to different sections, their difference and so the relocation is 64-bit. An attempt to parse such file, i.e. in DWARFContext::create, results in "failed to compute relocation" error. This fix adds support for such relocations to RelocationResolver.cpp. Reviewed By: MaskRay Differential Revision: https://reviews.llvm.org/D67779 Patch by Oleg Pliss (Oleg.Pliss@azul.com) llvm-svn: 372447 --- llvm/lib/Object/RelocationResolver.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/llvm/lib/Object/RelocationResolver.cpp b/llvm/lib/Object/RelocationResolver.cpp index 90ae4fa4a54ec..ca89f5671b8a7 100644 --- a/llvm/lib/Object/RelocationResolver.cpp +++ b/llvm/lib/Object/RelocationResolver.cpp @@ -30,6 +30,7 @@ static bool supportsX86_64(uint64_t Type) { case ELF::R_X86_64_DTPOFF32: case ELF::R_X86_64_DTPOFF64: case ELF::R_X86_64_PC32: + case ELF::R_X86_64_PC64: case ELF::R_X86_64_32: case ELF::R_X86_64_32S: return true; @@ -47,6 +48,7 @@ static uint64_t resolveX86_64(RelocationRef R, uint64_t S, uint64_t A) { case ELF::R_X86_64_DTPOFF64: return S + getELFAddend(R); case ELF::R_X86_64_PC32: + case ELF::R_X86_64_PC64: return S + getELFAddend(R) - R.getOffset(); case ELF::R_X86_64_32: case ELF::R_X86_64_32S: From 6541c7988b83b30b2590ca6b3e23585ae04a02a2 Mon Sep 17 00:00:00 2001 From: Richard Trieu Date: Sat, 21 Sep 2019 02:37:10 +0000 Subject: [PATCH 51/71] Improve -Wtautological-overlap-compare Allow this warning to detect a larger number of constant values, including negative numbers, and handle non-int types better. Differential Revision: https://reviews.llvm.org/D66044 llvm-svn: 372448 --- clang/docs/ReleaseNotes.rst | 3 +- clang/lib/Analysis/CFG.cpp | 44 ++++++++++++++++++++++--- clang/lib/Analysis/ReachableCode.cpp | 2 +- clang/test/Analysis/cfg.cpp | 21 ++++++++++++ clang/test/Sema/warn-overlap.c | 17 ++++++++++ clang/test/Sema/warn-unreachable.c | 2 +- clang/test/SemaCXX/warn-unreachable.cpp | 5 +-- 7 files changed, 84 insertions(+), 10 deletions(-) diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst index 9716360a78d13..e04e568ddb0a9 100644 --- a/clang/docs/ReleaseNotes.rst +++ b/clang/docs/ReleaseNotes.rst @@ -51,7 +51,8 @@ Major New Features Improvements to Clang's diagnostics ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -- ... +- -Wtautological-overlap-compare will warn on negative numbers and non-int + types. Non-comprehensive list of changes in this release ------------------------------------------------- diff --git a/clang/lib/Analysis/CFG.cpp b/clang/lib/Analysis/CFG.cpp index 1a45c9f532d92..86816997f0719 100644 --- a/clang/lib/Analysis/CFG.cpp +++ b/clang/lib/Analysis/CFG.cpp @@ -70,11 +70,35 @@ static SourceLocation GetEndLoc(Decl *D) { return D->getLocation(); } +/// Returns true on constant values based around a single IntegerLiteral. +/// Allow for use of parentheses, integer casts, and negative signs. +static bool IsIntegerLiteralConstantExpr(const Expr *E) { + // Allow parentheses + E = E->IgnoreParens(); + + // Allow conversions to different integer kind. + if (const auto *CE = dyn_cast(E)) { + if (CE->getCastKind() != CK_IntegralCast) + return false; + E = CE->getSubExpr(); + } + + // Allow negative numbers. + if (const auto *UO = dyn_cast(E)) { + if (UO->getOpcode() != UO_Minus) + return false; + E = UO->getSubExpr(); + } + + return isa(E); +} + /// Helper for tryNormalizeBinaryOperator. Attempts to extract an IntegerLiteral -/// or EnumConstantDecl from the given Expr. If it fails, returns nullptr. +/// constant expression or EnumConstantDecl from the given Expr. If it fails, +/// returns nullptr. static const Expr *tryTransformToIntOrEnumConstant(const Expr *E) { E = E->IgnoreParens(); - if (isa(E)) + if (IsIntegerLiteralConstantExpr(E)) return E; if (auto *DR = dyn_cast(E->IgnoreParenImpCasts())) return isa(DR->getDecl()) ? DR : nullptr; @@ -121,11 +145,11 @@ tryNormalizeBinaryOperator(const BinaryOperator *B) { static bool areExprTypesCompatible(const Expr *E1, const Expr *E2) { // User intent isn't clear if they're mixing int literals with enum // constants. - if (isa(E1) != isa(E2)) + if (isa(E1) != isa(E2)) return false; // Integer literal comparisons, regardless of literal type, are acceptable. - if (isa(E1)) + if (!isa(E1)) return true; // IntegerLiterals are handled above and only EnumConstantDecls are expected @@ -1081,6 +1105,10 @@ class CFGBuilder { // * Variable x is equal to the largest literal. // * Variable x is greater than largest literal. bool AlwaysTrue = true, AlwaysFalse = true; + // Track value of both subexpressions. If either side is always + // true/false, another warning should have already been emitted. + bool LHSAlwaysTrue = true, LHSAlwaysFalse = true; + bool RHSAlwaysTrue = true, RHSAlwaysFalse = true; for (const llvm::APSInt &Value : Values) { TryResult Res1, Res2; Res1 = analyzeLogicOperatorCondition(BO1, Value, L1); @@ -1096,10 +1124,16 @@ class CFGBuilder { AlwaysTrue &= (Res1.isTrue() || Res2.isTrue()); AlwaysFalse &= !(Res1.isTrue() || Res2.isTrue()); } + + LHSAlwaysTrue &= Res1.isTrue(); + LHSAlwaysFalse &= Res1.isFalse(); + RHSAlwaysTrue &= Res2.isTrue(); + RHSAlwaysFalse &= Res2.isFalse(); } if (AlwaysTrue || AlwaysFalse) { - if (BuildOpts.Observer) + if (!LHSAlwaysTrue && !LHSAlwaysFalse && !RHSAlwaysTrue && + !RHSAlwaysFalse && BuildOpts.Observer) BuildOpts.Observer->compareAlwaysTrue(B, AlwaysTrue); return TryResult(AlwaysTrue); } diff --git a/clang/lib/Analysis/ReachableCode.cpp b/clang/lib/Analysis/ReachableCode.cpp index 2fea88ea2eff4..1dab8e309f599 100644 --- a/clang/lib/Analysis/ReachableCode.cpp +++ b/clang/lib/Analysis/ReachableCode.cpp @@ -247,7 +247,7 @@ static bool isConfigurationValue(const Stmt *S, } case Stmt::UnaryOperatorClass: { const UnaryOperator *UO = cast(S); - if (UO->getOpcode() != UO_LNot) + if (UO->getOpcode() != UO_LNot && UO->getOpcode() != UO_Minus) return false; bool SilenceableCondValNotSet = SilenceableCondVal && SilenceableCondVal->getBegin().isInvalid(); diff --git a/clang/test/Analysis/cfg.cpp b/clang/test/Analysis/cfg.cpp index 9b0203e99efe9..a7d707ee20d1a 100644 --- a/clang/test/Analysis/cfg.cpp +++ b/clang/test/Analysis/cfg.cpp @@ -547,6 +547,27 @@ int foo() { } } // namespace statement_expression_in_return +// CHECK-LABEL: int overlap_compare(int x) +// CHECK: [B2] +// CHECK-NEXT: 1: 1 +// CHECK-NEXT: 2: return [B2.1]; +// CHECK-NEXT: Preds (1): B3(Unreachable) +// CHECK-NEXT: Succs (1): B0 +// CHECK: [B3] +// CHECK-NEXT: 1: x +// CHECK-NEXT: 2: [B3.1] (ImplicitCastExpr, LValueToRValue, int) +// CHECK-NEXT: 3: 5 +// CHECK-NEXT: 4: [B3.2] > [B3.3] +// CHECK-NEXT: T: if [B4.5] && [B3.4] +// CHECK-NEXT: Preds (1): B4 +// CHECK-NEXT: Succs (2): B2(Unreachable) B1 +int overlap_compare(int x) { + if (x == -1 && x > 5) + return 1; + + return 2; +} + // CHECK-LABEL: template<> int *PR18472() // CHECK: [B2 (ENTRY)] // CHECK-NEXT: Succs (1): B1 diff --git a/clang/test/Sema/warn-overlap.c b/clang/test/Sema/warn-overlap.c index 6299c511fe230..d72e60755db76 100644 --- a/clang/test/Sema/warn-overlap.c +++ b/clang/test/Sema/warn-overlap.c @@ -141,3 +141,20 @@ int returns(int x) { return x < 1 || x != 0; // expected-warning@-1{{overlapping comparisons always evaluate to true}} } + +int integer_conversion(unsigned x, int y) { + return x > 4 || x < 10; + // expected-warning@-1{{overlapping comparisons always evaluate to true}} + return y > 4u || y < 10u; + // expected-warning@-1{{overlapping comparisons always evaluate to true}} +} + +int negative_compare(int x) { + return x > -1 || x < 1; + // expected-warning@-1{{overlapping comparisons always evaluate to true}} +} + +int no_warning(unsigned x) { + return x >= 0 || x == 1; + // no warning since "x >= 0" is caught by a different tautological warning. +} diff --git a/clang/test/Sema/warn-unreachable.c b/clang/test/Sema/warn-unreachable.c index aec3b070213c7..cfac36a131869 100644 --- a/clang/test/Sema/warn-unreachable.c +++ b/clang/test/Sema/warn-unreachable.c @@ -433,7 +433,7 @@ void wrapOneInFixit(struct StructWithPointer *s) { } void unaryOpNoFixit() { - if (- 1) + if (~ 1) return; // CHECK-NOT: fix-it:"{{.*}}":{[[@LINE-1]] unaryOpNoFixit(); // expected-warning {{code will never be executed}} } diff --git a/clang/test/SemaCXX/warn-unreachable.cpp b/clang/test/SemaCXX/warn-unreachable.cpp index a14e4226861c1..c664c1912899d 100644 --- a/clang/test/SemaCXX/warn-unreachable.cpp +++ b/clang/test/SemaCXX/warn-unreachable.cpp @@ -393,6 +393,9 @@ void tautological_compare(bool x, int y) { else calledFun(); // expected-warning {{will never be executed}} + if (y == -1 && y != -1) // expected-note {{silence}} + calledFun(); // expected-warning {{will never be executed}} + // TODO: Extend warning to the following code: if (x < -1) calledFun(); @@ -408,6 +411,4 @@ void tautological_compare(bool x, int y) { else calledFun(); - if (y == -1 && y != -1) - calledFun(); } From bd7f2354ccbaa50923b134b223349ae532443aba Mon Sep 17 00:00:00 2001 From: Matt Arsenault Date: Sat, 21 Sep 2019 02:37:28 +0000 Subject: [PATCH 52/71] LiveIntervals: Add missing operator!= for segments llvm-svn: 372449 --- llvm/include/llvm/CodeGen/LiveInterval.h | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/llvm/include/llvm/CodeGen/LiveInterval.h b/llvm/include/llvm/CodeGen/LiveInterval.h index c3b472e6555c2..290a2381d9c96 100644 --- a/llvm/include/llvm/CodeGen/LiveInterval.h +++ b/llvm/include/llvm/CodeGen/LiveInterval.h @@ -189,6 +189,10 @@ namespace llvm { return start == Other.start && end == Other.end; } + bool operator!=(const Segment &Other) const { + return !(*this == Other); + } + void dump() const; }; From eb6eb694e42d85541a1abc79f6025425540f8a7c Mon Sep 17 00:00:00 2001 From: Matt Arsenault Date: Sat, 21 Sep 2019 02:37:33 +0000 Subject: [PATCH 53/71] AMDGPU/GlobalISel: Allow selection of scalar min/max I believe all of the uniform/divergent pattern predicates are redundant and can be removed. The uniformity bit already influences the register class, and nothhing has broken when I've removed this and others. llvm-svn: 372450 --- llvm/lib/Target/AMDGPU/SOPInstructions.td | 8 ++++---- .../AMDGPU/GlobalISel/inst-select-smax.mir | 15 +++++---------- .../AMDGPU/GlobalISel/inst-select-smin.mir | 15 +++++---------- .../AMDGPU/GlobalISel/inst-select-umax.mir | 15 +++++---------- .../AMDGPU/GlobalISel/inst-select-umin.mir | 15 +++++---------- 5 files changed, 24 insertions(+), 44 deletions(-) diff --git a/llvm/lib/Target/AMDGPU/SOPInstructions.td b/llvm/lib/Target/AMDGPU/SOPInstructions.td index 2cd4e1cbc077d..d31a49f428ee7 100644 --- a/llvm/lib/Target/AMDGPU/SOPInstructions.td +++ b/llvm/lib/Target/AMDGPU/SOPInstructions.td @@ -419,16 +419,16 @@ def S_SUBB_U32 : SOP2_32 <"s_subb_u32", let isCommutable = 1 in { def S_MIN_I32 : SOP2_32 <"s_min_i32", - [(set i32:$sdst, (UniformBinFrag i32:$src0, i32:$src1))] + [(set i32:$sdst, (smin i32:$src0, i32:$src1))] >; def S_MIN_U32 : SOP2_32 <"s_min_u32", - [(set i32:$sdst, (UniformBinFrag i32:$src0, i32:$src1))] + [(set i32:$sdst, (umin i32:$src0, i32:$src1))] >; def S_MAX_I32 : SOP2_32 <"s_max_i32", - [(set i32:$sdst, (UniformBinFrag i32:$src0, i32:$src1))] + [(set i32:$sdst, (smax i32:$src0, i32:$src1))] >; def S_MAX_U32 : SOP2_32 <"s_max_u32", - [(set i32:$sdst, (UniformBinFrag i32:$src0, i32:$src1))] + [(set i32:$sdst, (umax i32:$src0, i32:$src1))] >; } // End isCommutable = 1 } // End Defs = [SCC] diff --git a/llvm/test/CodeGen/AMDGPU/GlobalISel/inst-select-smax.mir b/llvm/test/CodeGen/AMDGPU/GlobalISel/inst-select-smax.mir index 50811a47cd2c5..1ffe7d3d679d6 100644 --- a/llvm/test/CodeGen/AMDGPU/GlobalISel/inst-select-smax.mir +++ b/llvm/test/CodeGen/AMDGPU/GlobalISel/inst-select-smax.mir @@ -1,10 +1,5 @@ # NOTE: Assertions have been autogenerated by utils/update_mir_test_checks.py -# RUN: llc -march=amdgcn -mcpu=gfx900 -run-pass=instruction-select -global-isel-abort=2 -pass-remarks-missed='gisel*' -verify-machineinstrs %s -o - 2>%t | FileCheck -check-prefix=GCN %s -# RUN: FileCheck -check-prefix=ERR %s < %t - -# ERR-NOT: remark: -# ERR: remark: :0:0: cannot select: %2:sgpr(s32) = G_SMAX %0:sgpr, %1:sgpr (in function: smax_s32_ss) -# ERR-NOT: remark: +# RUN: llc -march=amdgcn -mcpu=gfx900 -run-pass=instruction-select -verify-machineinstrs %s -o - | FileCheck -check-prefix=GCN %s --- name: smax_s32_ss @@ -15,10 +10,10 @@ body: | bb.0: liveins: $sgpr0, $sgpr1 ; GCN-LABEL: name: smax_s32_ss - ; GCN: [[COPY:%[0-9]+]]:sgpr(s32) = COPY $sgpr0 - ; GCN: [[COPY1:%[0-9]+]]:sgpr(s32) = COPY $sgpr1 - ; GCN: [[SMAX:%[0-9]+]]:sgpr(s32) = G_SMAX [[COPY]], [[COPY1]] - ; GCN: S_ENDPGM 0, implicit [[SMAX]](s32) + ; GCN: [[COPY:%[0-9]+]]:sreg_32 = COPY $sgpr0 + ; GCN: [[COPY1:%[0-9]+]]:sreg_32 = COPY $sgpr1 + ; GCN: [[S_MAX_I32_:%[0-9]+]]:sreg_32 = S_MAX_I32 [[COPY]], [[COPY1]], implicit-def $scc + ; GCN: S_ENDPGM 0, implicit [[S_MAX_I32_]] %0:sgpr(s32) = COPY $sgpr0 %1:sgpr(s32) = COPY $sgpr1 %2:sgpr(s32) = G_SMAX %0, %1 diff --git a/llvm/test/CodeGen/AMDGPU/GlobalISel/inst-select-smin.mir b/llvm/test/CodeGen/AMDGPU/GlobalISel/inst-select-smin.mir index 39fd79660f76d..3c37a9425d47a 100644 --- a/llvm/test/CodeGen/AMDGPU/GlobalISel/inst-select-smin.mir +++ b/llvm/test/CodeGen/AMDGPU/GlobalISel/inst-select-smin.mir @@ -1,10 +1,5 @@ # NOTE: Assertions have been autogenerated by utils/update_mir_test_checks.py -# RUN: llc -march=amdgcn -mcpu=gfx900 -run-pass=instruction-select -global-isel-abort=2 -pass-remarks-missed='gisel*' -verify-machineinstrs %s -o - 2>%t | FileCheck -check-prefix=GCN %s -# RUN: FileCheck -check-prefix=ERR %s < %t - -# ERR-NOT: remark: -# ERR: remark: :0:0: cannot select: %2:sgpr(s32) = G_SMIN %0:sgpr, %1:sgpr (in function: smin_s32_ss) -# ERR-NOT: remark: +# RUN: llc -march=amdgcn -mcpu=gfx900 -run-pass=instruction-select -verify-machineinstrs %s -o - | FileCheck -check-prefix=GCN %s --- name: smin_s32_ss @@ -15,10 +10,10 @@ body: | bb.0: liveins: $sgpr0, $sgpr1 ; GCN-LABEL: name: smin_s32_ss - ; GCN: [[COPY:%[0-9]+]]:sgpr(s32) = COPY $sgpr0 - ; GCN: [[COPY1:%[0-9]+]]:sgpr(s32) = COPY $sgpr1 - ; GCN: [[SMIN:%[0-9]+]]:sgpr(s32) = G_SMIN [[COPY]], [[COPY1]] - ; GCN: S_ENDPGM 0, implicit [[SMIN]](s32) + ; GCN: [[COPY:%[0-9]+]]:sreg_32 = COPY $sgpr0 + ; GCN: [[COPY1:%[0-9]+]]:sreg_32 = COPY $sgpr1 + ; GCN: [[S_MIN_I32_:%[0-9]+]]:sreg_32 = S_MIN_I32 [[COPY]], [[COPY1]], implicit-def $scc + ; GCN: S_ENDPGM 0, implicit [[S_MIN_I32_]] %0:sgpr(s32) = COPY $sgpr0 %1:sgpr(s32) = COPY $sgpr1 %2:sgpr(s32) = G_SMIN %0, %1 diff --git a/llvm/test/CodeGen/AMDGPU/GlobalISel/inst-select-umax.mir b/llvm/test/CodeGen/AMDGPU/GlobalISel/inst-select-umax.mir index d4537a07c4dad..a5ae6ab6ca8d8 100644 --- a/llvm/test/CodeGen/AMDGPU/GlobalISel/inst-select-umax.mir +++ b/llvm/test/CodeGen/AMDGPU/GlobalISel/inst-select-umax.mir @@ -1,10 +1,5 @@ # NOTE: Assertions have been autogenerated by utils/update_mir_test_checks.py -# RUN: llc -march=amdgcn -mcpu=gfx900 -run-pass=instruction-select -global-isel-abort=2 -pass-remarks-missed='gisel*' -verify-machineinstrs %s -o - 2>%t | FileCheck -check-prefix=GCN %s -# RUN: FileCheck -check-prefix=ERR %s < %t - -# ERR-NOT: remark: -# ERR: remark: :0:0: cannot select: %2:sgpr(s32) = G_UMAX %0:sgpr, %1:sgpr (in function: umax_s32_ss) -# ERR-NOT: remark: +# RUN: llc -march=amdgcn -mcpu=gfx900 -run-pass=instruction-select -verify-machineinstrs %s -o - | FileCheck -check-prefix=GCN %s --- name: umax_s32_ss @@ -15,10 +10,10 @@ body: | bb.0: liveins: $sgpr0, $sgpr1 ; GCN-LABEL: name: umax_s32_ss - ; GCN: [[COPY:%[0-9]+]]:sgpr(s32) = COPY $sgpr0 - ; GCN: [[COPY1:%[0-9]+]]:sgpr(s32) = COPY $sgpr1 - ; GCN: [[UMAX:%[0-9]+]]:sgpr(s32) = G_UMAX [[COPY]], [[COPY1]] - ; GCN: S_ENDPGM 0, implicit [[UMAX]](s32) + ; GCN: [[COPY:%[0-9]+]]:sreg_32 = COPY $sgpr0 + ; GCN: [[COPY1:%[0-9]+]]:sreg_32 = COPY $sgpr1 + ; GCN: [[S_MAX_U32_:%[0-9]+]]:sreg_32 = S_MAX_U32 [[COPY]], [[COPY1]], implicit-def $scc + ; GCN: S_ENDPGM 0, implicit [[S_MAX_U32_]] %0:sgpr(s32) = COPY $sgpr0 %1:sgpr(s32) = COPY $sgpr1 %2:sgpr(s32) = G_UMAX %0, %1 diff --git a/llvm/test/CodeGen/AMDGPU/GlobalISel/inst-select-umin.mir b/llvm/test/CodeGen/AMDGPU/GlobalISel/inst-select-umin.mir index cfa573c9fca99..be097fc126d1f 100644 --- a/llvm/test/CodeGen/AMDGPU/GlobalISel/inst-select-umin.mir +++ b/llvm/test/CodeGen/AMDGPU/GlobalISel/inst-select-umin.mir @@ -1,10 +1,5 @@ # NOTE: Assertions have been autogenerated by utils/update_mir_test_checks.py -# RUN: llc -march=amdgcn -mcpu=gfx900 -run-pass=instruction-select -global-isel-abort=2 -pass-remarks-missed='gisel*' -verify-machineinstrs %s -o - 2>%t | FileCheck -check-prefix=GCN %s -# RUN: FileCheck -check-prefix=ERR %s < %t - -# ERR-NOT: remark: -# ERR: remark: :0:0: cannot select: %2:sgpr(s32) = G_UMIN %0:sgpr, %1:sgpr (in function: umin_s32_ss) -# ERR-NOT: remark: +# RUN: llc -march=amdgcn -mcpu=gfx900 -run-pass=instruction-select -verify-machineinstrs %s -o - 2>%t | FileCheck -check-prefix=GCN %s --- name: umin_s32_ss @@ -15,10 +10,10 @@ body: | bb.0: liveins: $sgpr0, $sgpr1 ; GCN-LABEL: name: umin_s32_ss - ; GCN: [[COPY:%[0-9]+]]:sgpr(s32) = COPY $sgpr0 - ; GCN: [[COPY1:%[0-9]+]]:sgpr(s32) = COPY $sgpr1 - ; GCN: [[UMIN:%[0-9]+]]:sgpr(s32) = G_UMIN [[COPY]], [[COPY1]] - ; GCN: S_ENDPGM 0, implicit [[UMIN]](s32) + ; GCN: [[COPY:%[0-9]+]]:sreg_32 = COPY $sgpr0 + ; GCN: [[COPY1:%[0-9]+]]:sreg_32 = COPY $sgpr1 + ; GCN: [[S_MIN_U32_:%[0-9]+]]:sreg_32 = S_MIN_U32 [[COPY]], [[COPY1]], implicit-def $scc + ; GCN: S_ENDPGM 0, implicit [[S_MIN_U32_]] %0:sgpr(s32) = COPY $sgpr0 %1:sgpr(s32) = COPY $sgpr1 %2:sgpr(s32) = G_UMIN %0, %1 From d98d3ea9fe382c2fd0beeaf170532bf8e3521d47 Mon Sep 17 00:00:00 2001 From: Nico Weber Date: Sat, 21 Sep 2019 02:43:32 +0000 Subject: [PATCH 54/71] avr targetinfo: remove unneeded dep on MC llvm-svn: 372451 --- llvm/lib/Target/AVR/TargetInfo/LLVMBuild.txt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/llvm/lib/Target/AVR/TargetInfo/LLVMBuild.txt b/llvm/lib/Target/AVR/TargetInfo/LLVMBuild.txt index 6446977632855..7b112a2f00c6a 100644 --- a/llvm/lib/Target/AVR/TargetInfo/LLVMBuild.txt +++ b/llvm/lib/Target/AVR/TargetInfo/LLVMBuild.txt @@ -18,5 +18,5 @@ type = Library name = AVRInfo parent = AVR -required_libraries = MC Support -add_to_library_groups = AVR \ No newline at end of file +required_libraries = Support +add_to_library_groups = AVR From 27a8039171817a38f76adf51793f0d22f84dd78e Mon Sep 17 00:00:00 2001 From: Yaxun Liu Date: Sat, 21 Sep 2019 02:51:44 +0000 Subject: [PATCH 55/71] Revert assertion added by r372394 The assertion added by r372394 causes CUDA test in test-suite to assert. The assertion was not there originally, so revert it. llvm-svn: 372452 --- clang/lib/Sema/SemaCUDA.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/clang/lib/Sema/SemaCUDA.cpp b/clang/lib/Sema/SemaCUDA.cpp index e009dcb6f166f..cf8910cd84f75 100644 --- a/clang/lib/Sema/SemaCUDA.cpp +++ b/clang/lib/Sema/SemaCUDA.cpp @@ -396,7 +396,6 @@ bool Sema::inferCUDATargetForImplicitSpecialMember(CXXRecordDecl *ClassDecl, // We either setting attributes first time, or the inferred ones must match // previously set ones. - assert(!(HasD || HasH) || (NeedsD == HasD && NeedsH == HasH)); if (NeedsD && !HasD) MemberDecl->addAttr(CUDADeviceAttr::CreateImplicit(Context)); if (NeedsH && !HasH) From 4c05de8c1d157f4b5e0091a52dbbcce7242ee485 Mon Sep 17 00:00:00 2001 From: Richard Trieu Date: Sat, 21 Sep 2019 03:02:26 +0000 Subject: [PATCH 56/71] Merge and improve code that detects same value in comparisons. -Wtautological-overlap-compare and self-comparison from -Wtautological-compare relay on detecting the same operand in different locations. Previously, each warning had it's own operand checker. Now, both are merged together into one function that each can call. The function also now looks through member access and array accesses. Differential Revision: https://reviews.llvm.org/D66045 llvm-svn: 372453 --- clang/docs/ReleaseNotes.rst | 3 + clang/include/clang/AST/Expr.h | 5 + clang/lib/AST/Expr.cpp | 105 ++++++++++++++++++++ clang/lib/Analysis/CFG.cpp | 33 +++--- clang/lib/Sema/SemaExpr.cpp | 31 +++--- clang/test/Analysis/array-struct-region.cpp | 6 ++ clang/test/Sema/warn-overlap.c | 14 +++ clang/test/SemaCXX/compare-cxx2a.cpp | 6 ++ clang/test/SemaCXX/self-comparison.cpp | 81 +++++++++++++++ 9 files changed, 249 insertions(+), 35 deletions(-) diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst index e04e568ddb0a9..bb93fb547770c 100644 --- a/clang/docs/ReleaseNotes.rst +++ b/clang/docs/ReleaseNotes.rst @@ -53,6 +53,9 @@ Improvements to Clang's diagnostics - -Wtautological-overlap-compare will warn on negative numbers and non-int types. +- -Wtautological-compare for self comparisons and + -Wtautological-overlap-compare will now look through member and array + access to determine if two operand expressions are the same. Non-comprehensive list of changes in this release ------------------------------------------------- diff --git a/clang/include/clang/AST/Expr.h b/clang/include/clang/AST/Expr.h index 30fa84315ff53..ffa7d4db96a47 100644 --- a/clang/include/clang/AST/Expr.h +++ b/clang/include/clang/AST/Expr.h @@ -906,6 +906,11 @@ class Expr : public ValueStmt { return skipRValueSubobjectAdjustments(CommaLHSs, Adjustments); } + /// Checks that the two Expr's will refer to the same value as a comparison + /// operand. The caller must ensure that the values referenced by the Expr's + /// are not modified between E1 and E2 or the result my be invalid. + static bool isSameComparisonOperand(const Expr* E1, const Expr* E2); + static bool classof(const Stmt *T) { return T->getStmtClass() >= firstExprConstant && T->getStmtClass() <= lastExprConstant; diff --git a/clang/lib/AST/Expr.cpp b/clang/lib/AST/Expr.cpp index 00c6a8170406f..b5fb7fafb00a2 100644 --- a/clang/lib/AST/Expr.cpp +++ b/clang/lib/AST/Expr.cpp @@ -3921,6 +3921,111 @@ bool Expr::refersToGlobalRegisterVar() const { return false; } +bool Expr::isSameComparisonOperand(const Expr* E1, const Expr* E2) { + E1 = E1->IgnoreParens(); + E2 = E2->IgnoreParens(); + + if (E1->getStmtClass() != E2->getStmtClass()) + return false; + + switch (E1->getStmtClass()) { + default: + return false; + case CXXThisExprClass: + return true; + case DeclRefExprClass: { + // DeclRefExpr without an ImplicitCastExpr can happen for integral + // template parameters. + const auto *DRE1 = cast(E1); + const auto *DRE2 = cast(E2); + return DRE1->isRValue() && DRE2->isRValue() && + DRE1->getDecl() == DRE2->getDecl(); + } + case ImplicitCastExprClass: { + // Peel off implicit casts. + while (true) { + const auto *ICE1 = dyn_cast(E1); + const auto *ICE2 = dyn_cast(E2); + if (!ICE1 || !ICE2) + return false; + if (ICE1->getCastKind() != ICE2->getCastKind()) + return false; + E1 = ICE1->getSubExpr()->IgnoreParens(); + E2 = ICE2->getSubExpr()->IgnoreParens(); + // The final cast must be one of these types. + if (ICE1->getCastKind() == CK_LValueToRValue || + ICE1->getCastKind() == CK_ArrayToPointerDecay || + ICE1->getCastKind() == CK_FunctionToPointerDecay) { + break; + } + } + + const auto *DRE1 = dyn_cast(E1); + const auto *DRE2 = dyn_cast(E2); + if (DRE1 && DRE2) + return declaresSameEntity(DRE1->getDecl(), DRE2->getDecl()); + + const auto *Ivar1 = dyn_cast(E1); + const auto *Ivar2 = dyn_cast(E2); + if (Ivar1 && Ivar2) { + return Ivar1->isFreeIvar() && Ivar2->isFreeIvar() && + declaresSameEntity(Ivar1->getDecl(), Ivar2->getDecl()); + } + + const auto *Array1 = dyn_cast(E1); + const auto *Array2 = dyn_cast(E2); + if (Array1 && Array2) { + if (!isSameComparisonOperand(Array1->getBase(), Array2->getBase())) + return false; + + auto Idx1 = Array1->getIdx(); + auto Idx2 = Array2->getIdx(); + const auto Integer1 = dyn_cast(Idx1); + const auto Integer2 = dyn_cast(Idx2); + if (Integer1 && Integer2) { + if (Integer1->getValue() != Integer2->getValue()) + return false; + } else { + if (!isSameComparisonOperand(Idx1, Idx2)) + return false; + } + + return true; + } + + // Walk the MemberExpr chain. + while (isa(E1) && isa(E2)) { + const auto *ME1 = cast(E1); + const auto *ME2 = cast(E2); + if (!declaresSameEntity(ME1->getMemberDecl(), ME2->getMemberDecl())) + return false; + if (const auto *D = dyn_cast(ME1->getMemberDecl())) + if (D->isStaticDataMember()) + return true; + E1 = ME1->getBase()->IgnoreParenImpCasts(); + E2 = ME2->getBase()->IgnoreParenImpCasts(); + } + + if (isa(E1) && isa(E2)) + return true; + + // A static member variable can end the MemberExpr chain with either + // a MemberExpr or a DeclRefExpr. + auto getAnyDecl = [](const Expr *E) -> const ValueDecl * { + if (const auto *DRE = dyn_cast(E)) + return DRE->getDecl(); + if (const auto *ME = dyn_cast(E)) + return ME->getMemberDecl(); + return nullptr; + }; + + const ValueDecl *VD1 = getAnyDecl(E1); + const ValueDecl *VD2 = getAnyDecl(E2); + return declaresSameEntity(VD1, VD2); + } + } +} + /// isArrow - Return true if the base expression is a pointer to vector, /// return false if the base expression is a vector. bool ExtVectorElementExpr::isArrow() const { diff --git a/clang/lib/Analysis/CFG.cpp b/clang/lib/Analysis/CFG.cpp index 86816997f0719..687cf57059138 100644 --- a/clang/lib/Analysis/CFG.cpp +++ b/clang/lib/Analysis/CFG.cpp @@ -105,12 +105,12 @@ static const Expr *tryTransformToIntOrEnumConstant(const Expr *E) { return nullptr; } -/// Tries to interpret a binary operator into `Decl Op Expr` form, if Expr is -/// an integer literal or an enum constant. +/// Tries to interpret a binary operator into `Expr Op NumExpr` form, if +/// NumExpr is an integer literal or an enum constant. /// /// If this fails, at least one of the returned DeclRefExpr or Expr will be /// null. -static std::tuple +static std::tuple tryNormalizeBinaryOperator(const BinaryOperator *B) { BinaryOperatorKind Op = B->getOpcode(); @@ -132,8 +132,7 @@ tryNormalizeBinaryOperator(const BinaryOperator *B) { Constant = tryTransformToIntOrEnumConstant(B->getLHS()); } - auto *D = dyn_cast(MaybeDecl->IgnoreParenImpCasts()); - return std::make_tuple(D, Op, Constant); + return std::make_tuple(MaybeDecl, Op, Constant); } /// For an expression `x == Foo && x == Bar`, this determines whether the @@ -1045,34 +1044,34 @@ class CFGBuilder { if (!LHS->isComparisonOp() || !RHS->isComparisonOp()) return {}; - const DeclRefExpr *Decl1; - const Expr *Expr1; + const Expr *DeclExpr1; + const Expr *NumExpr1; BinaryOperatorKind BO1; - std::tie(Decl1, BO1, Expr1) = tryNormalizeBinaryOperator(LHS); + std::tie(DeclExpr1, BO1, NumExpr1) = tryNormalizeBinaryOperator(LHS); - if (!Decl1 || !Expr1) + if (!DeclExpr1 || !NumExpr1) return {}; - const DeclRefExpr *Decl2; - const Expr *Expr2; + const Expr *DeclExpr2; + const Expr *NumExpr2; BinaryOperatorKind BO2; - std::tie(Decl2, BO2, Expr2) = tryNormalizeBinaryOperator(RHS); + std::tie(DeclExpr2, BO2, NumExpr2) = tryNormalizeBinaryOperator(RHS); - if (!Decl2 || !Expr2) + if (!DeclExpr2 || !NumExpr2) return {}; // Check that it is the same variable on both sides. - if (Decl1->getDecl() != Decl2->getDecl()) + if (!Expr::isSameComparisonOperand(DeclExpr1, DeclExpr2)) return {}; // Make sure the user's intent is clear (e.g. they're comparing against two // int literals, or two things from the same enum) - if (!areExprTypesCompatible(Expr1, Expr2)) + if (!areExprTypesCompatible(NumExpr1, NumExpr2)) return {}; Expr::EvalResult L1Result, L2Result; - if (!Expr1->EvaluateAsInt(L1Result, *Context) || - !Expr2->EvaluateAsInt(L2Result, *Context)) + if (!NumExpr1->EvaluateAsInt(L1Result, *Context) || + !NumExpr2->EvaluateAsInt(L2Result, *Context)) return {}; llvm::APSInt L1 = L1Result.Val.getInt(); diff --git a/clang/lib/Sema/SemaExpr.cpp b/clang/lib/Sema/SemaExpr.cpp index 808c0e450a558..6dfbc4cda598b 100644 --- a/clang/lib/Sema/SemaExpr.cpp +++ b/clang/lib/Sema/SemaExpr.cpp @@ -10245,20 +10245,18 @@ static void diagnoseLogicalNotOnLHSofCheck(Sema &S, ExprResult &LHS, << FixItHint::CreateInsertion(SecondClose, ")"); } -// Get the decl for a simple expression: a reference to a variable, -// an implicit C++ field reference, or an implicit ObjC ivar reference. -static ValueDecl *getCompareDecl(Expr *E) { - if (DeclRefExpr *DR = dyn_cast(E)) - return DR->getDecl(); - if (ObjCIvarRefExpr *Ivar = dyn_cast(E)) { - if (Ivar->isFreeIvar()) - return Ivar->getDecl(); - } - if (MemberExpr *Mem = dyn_cast(E)) { +// Returns true if E refers to a non-weak array. +static bool checkForArray(const Expr *E) { + const ValueDecl *D = nullptr; + if (const DeclRefExpr *DR = dyn_cast(E)) { + D = DR->getDecl(); + } else if (const MemberExpr *Mem = dyn_cast(E)) { if (Mem->isImplicitAccess()) - return Mem->getMemberDecl(); + D = Mem->getMemberDecl(); } - return nullptr; + if (!D) + return false; + return D->getType()->isArrayType() && !D->isWeak(); } /// Diagnose some forms of syntactically-obvious tautological comparison. @@ -10291,8 +10289,6 @@ static void diagnoseTautologicalComparison(Sema &S, SourceLocation Loc, // obvious cases in the definition of the template anyways. The idea is to // warn when the typed comparison operator will always evaluate to the same // result. - ValueDecl *DL = getCompareDecl(LHSStripped); - ValueDecl *DR = getCompareDecl(RHSStripped); // Used for indexing into %select in warn_comparison_always enum { @@ -10301,7 +10297,8 @@ static void diagnoseTautologicalComparison(Sema &S, SourceLocation Loc, AlwaysFalse, AlwaysEqual, // std::strong_ordering::equal from operator<=> }; - if (DL && DR && declaresSameEntity(DL, DR)) { + + if (Expr::isSameComparisonOperand(LHS, RHS)) { unsigned Result; switch (Opc) { case BO_EQ: case BO_LE: case BO_GE: @@ -10321,9 +10318,7 @@ static void diagnoseTautologicalComparison(Sema &S, SourceLocation Loc, S.PDiag(diag::warn_comparison_always) << 0 /*self-comparison*/ << Result); - } else if (DL && DR && - DL->getType()->isArrayType() && DR->getType()->isArrayType() && - !DL->isWeak() && !DR->isWeak()) { + } else if (checkForArray(LHSStripped) && checkForArray(RHSStripped)) { // What is it always going to evaluate to? unsigned Result; switch(Opc) { diff --git a/clang/test/Analysis/array-struct-region.cpp b/clang/test/Analysis/array-struct-region.cpp index cfb57d39242db..1b9fa3e8db55c 100644 --- a/clang/test/Analysis/array-struct-region.cpp +++ b/clang/test/Analysis/array-struct-region.cpp @@ -1,20 +1,26 @@ // RUN: %clang_analyze_cc1 -analyzer-checker=core,alpha.core\ // RUN: -analyzer-checker=debug.ExprInspection -verify\ +// RUN: -Wno-tautological-compare\ // RUN: -x c %s // RUN: %clang_analyze_cc1 -analyzer-checker=core,alpha.core\ // RUN: -analyzer-checker=debug.ExprInspection -verify\ +// RUN: -Wno-tautological-compare\ // RUN: -x c++ -std=c++14 %s // RUN: %clang_analyze_cc1 -analyzer-checker=core,alpha.core\ // RUN: -analyzer-checker=debug.ExprInspection -verify\ +// RUN: -Wno-tautological-compare\ // RUN: -x c++ -std=c++17 %s // RUN: %clang_analyze_cc1 -analyzer-checker=core,alpha.core\ // RUN: -analyzer-checker=debug.ExprInspection -verify\ +// RUN: -Wno-tautological-compare\ // RUN: -DINLINE -x c %s // RUN: %clang_analyze_cc1 -analyzer-checker=core,alpha.core\ // RUN: -analyzer-checker=debug.ExprInspection -verify\ +// RUN: -Wno-tautological-compare\ // RUN: -DINLINE -x c++ -std=c++14 %s // RUN: %clang_analyze_cc1 -analyzer-checker=core,alpha.core\ // RUN: -analyzer-checker=debug.ExprInspection -verify\ +// RUN: -Wno-tautological-compare\ // RUN: -DINLINE -x c++ -std=c++17 %s void clang_analyzer_eval(int); diff --git a/clang/test/Sema/warn-overlap.c b/clang/test/Sema/warn-overlap.c index d72e60755db76..066312591c1eb 100644 --- a/clang/test/Sema/warn-overlap.c +++ b/clang/test/Sema/warn-overlap.c @@ -158,3 +158,17 @@ int no_warning(unsigned x) { return x >= 0 || x == 1; // no warning since "x >= 0" is caught by a different tautological warning. } + +struct A { + int x; + int y; +}; + +int struct_test(struct A a) { + return a.x > 5 && a.y < 1; // no warning, different variables + + return a.x > 5 && a.x < 1; + // expected-warning@-1{{overlapping comparisons always evaluate to false}} + return a.y == 1 || a.y != 1; + // expected-warning@-1{{overlapping comparisons always evaluate to true}} +} diff --git a/clang/test/SemaCXX/compare-cxx2a.cpp b/clang/test/SemaCXX/compare-cxx2a.cpp index c68a0ae9133f3..b6e7fc806114b 100644 --- a/clang/test/SemaCXX/compare-cxx2a.cpp +++ b/clang/test/SemaCXX/compare-cxx2a.cpp @@ -8,12 +8,18 @@ #define ASSERT_TYPE(...) static_assert(__is_same(__VA_ARGS__)) #define ASSERT_EXPR_TYPE(Expr, Expect) static_assert(__is_same(decltype(Expr), Expect)); +struct S { + static int x[5]; +}; + void self_compare() { int a; int *b = nullptr; + S s; (void)(a <=> a); // expected-warning {{self-comparison always evaluates to 'std::strong_ordering::equal'}} (void)(b <=> b); // expected-warning {{self-comparison always evaluates to 'std::strong_ordering::equal'}} + (void)(s.x[a] <=> S::x[a]); // expected-warning {{self-comparison always evaluates to 'std::strong_ordering::equal'}} } void test0(long a, unsigned long b) { diff --git a/clang/test/SemaCXX/self-comparison.cpp b/clang/test/SemaCXX/self-comparison.cpp index ac129b68a67a9..4ea16665f1985 100644 --- a/clang/test/SemaCXX/self-comparison.cpp +++ b/clang/test/SemaCXX/self-comparison.cpp @@ -40,3 +40,84 @@ bool g() { Y::n == Y::n; } template bool g(); // should not produce any warnings + +namespace member_tests { +struct B { + int field; + static int static_field; + int test(B b) { + return field == field; // expected-warning {{self-comparison always evaluates to true}} + return static_field == static_field; // expected-warning {{self-comparison always evaluates to true}} + return static_field == b.static_field; // expected-warning {{self-comparison always evaluates to true}} + return B::static_field == this->static_field; // expected-warning {{self-comparison always evaluates to true}} + return this == this; // expected-warning {{self-comparison always evaluates to true}} + + return field == b.field; + return this->field == b.field; + } +}; + +enum { + I0, + I1, + I2, +}; + +struct S { + int field; + static int static_field; + int array[4]; +}; + +struct T { + int field; + static int static_field; + int array[4]; + S s; +}; + +int struct_test(S s1, S s2, S *s3, T t) { + return s1.field == s1.field; // expected-warning {{self-comparison always evaluates to true}} + return s2.field == s2.field; // expected-warning {{self-comparison always evaluates to true}} + return s1.static_field == s2.static_field; // expected-warning {{self-comparison always evaluates to true}} + return S::static_field == s1.static_field; // expected-warning {{self-comparison always evaluates to true}} + return s1.array == s1.array; // expected-warning {{self-comparison always evaluates to true}} + return t.s.static_field == S::static_field; // expected-warning {{self-comparison always evaluates to true}} + return s3->field == s3->field; // expected-warning {{self-comparison always evaluates to true}} + return s3->static_field == S::static_field; // expected-warning {{self-comparison always evaluates to true}} + return s1.array[0] == s1.array[0]; // expected-warning {{self-comparison always evaluates to true}} + return s1.array[I1] == s1.array[I1]; // expected-warning {{self-comparison always evaluates to true}} + return s1.array[s2.array[0]] == s1.array[s2.array[0]]; // expected-warning {{self-comparison always evaluates to true}} + return s3->array[t.field] == s3->array[t.field]; // expected-warning {{self-comparison always evaluates to true}} + + // Try all operators + return t.field == t.field; // expected-warning {{self-comparison always evaluates to true}} + return t.field <= t.field; // expected-warning {{self-comparison always evaluates to true}} + return t.field >= t.field; // expected-warning {{self-comparison always evaluates to true}} + + return t.field != t.field; // expected-warning {{self-comparison always evaluates to false}} + return t.field < t.field; // expected-warning {{self-comparison always evaluates to false}} + return t.field > t.field; // expected-warning {{self-comparison always evaluates to false}} + + // no warning + return s1.field == s2.field; + return s2.array == s1.array; + return s2.array[0] == s1.array[0]; + return s1.array[I1] == s1.array[I2]; + + return s1.static_field == t.static_field; +}; + +struct U { + bool operator!=(const U&); +}; + +bool operator==(const U&, const U&); + +// May want to warn on this in the future. +int user_defined(U u) { + return u == u; + return u != u; +} + +} // namespace member_tests From 77297f0761d2009e25d5d709cdcb041229f3493c Mon Sep 17 00:00:00 2001 From: Richard Trieu Date: Sat, 21 Sep 2019 04:18:54 +0000 Subject: [PATCH 57/71] Fix bad APInt compare. APInt comparison require both to have the same bitwidth. Since only the value is needed, use the compare function APInt::isSameValue instead. llvm-svn: 372454 --- clang/lib/AST/Expr.cpp | 3 ++- clang/test/SemaCXX/self-comparison.cpp | 1 + 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/clang/lib/AST/Expr.cpp b/clang/lib/AST/Expr.cpp index b5fb7fafb00a2..c9394bba2dd55 100644 --- a/clang/lib/AST/Expr.cpp +++ b/clang/lib/AST/Expr.cpp @@ -3983,7 +3983,8 @@ bool Expr::isSameComparisonOperand(const Expr* E1, const Expr* E2) { const auto Integer1 = dyn_cast(Idx1); const auto Integer2 = dyn_cast(Idx2); if (Integer1 && Integer2) { - if (Integer1->getValue() != Integer2->getValue()) + if (!llvm::APInt::isSameValue(Integer1->getValue(), + Integer2->getValue())) return false; } else { if (!isSameComparisonOperand(Idx1, Idx2)) diff --git a/clang/test/SemaCXX/self-comparison.cpp b/clang/test/SemaCXX/self-comparison.cpp index 4ea16665f1985..e20706a8b6cc9 100644 --- a/clang/test/SemaCXX/self-comparison.cpp +++ b/clang/test/SemaCXX/self-comparison.cpp @@ -86,6 +86,7 @@ int struct_test(S s1, S s2, S *s3, T t) { return s3->field == s3->field; // expected-warning {{self-comparison always evaluates to true}} return s3->static_field == S::static_field; // expected-warning {{self-comparison always evaluates to true}} return s1.array[0] == s1.array[0]; // expected-warning {{self-comparison always evaluates to true}} + return s1.array[0] == s1.array[0ull]; // expected-warning {{self-comparison always evaluates to true}} return s1.array[I1] == s1.array[I1]; // expected-warning {{self-comparison always evaluates to true}} return s1.array[s2.array[0]] == s1.array[s2.array[0]]; // expected-warning {{self-comparison always evaluates to true}} return s3->array[t.field] == s3->array[t.field]; // expected-warning {{self-comparison always evaluates to true}} From 10793e791f5b149cbdc4a836cace1552b04fb332 Mon Sep 17 00:00:00 2001 From: Nandor Licker Date: Sat, 21 Sep 2019 05:29:18 +0000 Subject: [PATCH 58/71] [Clang Interpreter] Fixed Bug 43362, build failure on GCC free() was not directly included in InterpStack.cpp, added include now. llvm-svn: 372455 --- clang/lib/AST/Interp/InterpStack.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/clang/lib/AST/Interp/InterpStack.cpp b/clang/lib/AST/Interp/InterpStack.cpp index f159fe1955f81..5c803f3d94244 100644 --- a/clang/lib/AST/Interp/InterpStack.cpp +++ b/clang/lib/AST/Interp/InterpStack.cpp @@ -7,6 +7,7 @@ //===----------------------------------------------------------------------===// #include +#include #include "InterpStack.h" using namespace clang; From 4fa12ac92ced6dafdaf1e7c7e7a4b86d774e0b83 Mon Sep 17 00:00:00 2001 From: Craig Topper Date: Sat, 21 Sep 2019 06:44:24 +0000 Subject: [PATCH 59/71] [X86] Add test case to show failure to fold load with getmantss due to isel pattern looking for Constant instead of TargetConstant The intrinsic has an immarg so its gets created with a TargetConstant instead of a Constant after r372338. The isel pattern was only updated for the register form, but not the memory form. llvm-svn: 372457 --- llvm/test/CodeGen/X86/avx512-intrinsics.ll | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/llvm/test/CodeGen/X86/avx512-intrinsics.ll b/llvm/test/CodeGen/X86/avx512-intrinsics.ll index b2d6ce4dfc9de..90b211ff65014 100644 --- a/llvm/test/CodeGen/X86/avx512-intrinsics.ll +++ b/llvm/test/CodeGen/X86/avx512-intrinsics.ll @@ -4798,6 +4798,24 @@ define <4 x float>@test_int_x86_avx512_mask_getmant_ss(<4 x float> %x0, <4 x flo ret <4 x float> %res13 } +define <4 x float> @test_int_x86_avx512_mask_getmant_ss_load(<4 x float> %x0, <4 x float>* %x1p) { +; X64-LABEL: test_int_x86_avx512_mask_getmant_ss_load: +; X64: # %bb.0: +; X64-NEXT: vmovaps (%rdi), %xmm1 +; X64-NEXT: vgetmantss $11, %xmm1, %xmm0, %xmm0 +; X64-NEXT: retq +; +; X86-LABEL: test_int_x86_avx512_mask_getmant_ss_load: +; X86: # %bb.0: +; X86-NEXT: movl {{[0-9]+}}(%esp), %eax +; X86-NEXT: vmovaps (%eax), %xmm1 +; X86-NEXT: vgetmantss $11, %xmm1, %xmm0, %xmm0 +; X86-NEXT: retl + %x1 = load <4 x float>, <4 x float>* %x1p + %res = call <4 x float> @llvm.x86.avx512.mask.getmant.ss(<4 x float> %x0, <4 x float> %x1, i32 11, <4 x float> undef, i8 -1, i32 4) + ret <4 x float> %res +} + declare <8 x double> @llvm.x86.avx512.vpermilvar.pd.512(<8 x double>, <8 x i64>) define <8 x double>@test_int_x86_avx512_vpermilvar_pd_512(<8 x double> %x0, <8 x i64> %x1) { From 04682939eb7e5ff06ec7e50cbe205b5c0069285f Mon Sep 17 00:00:00 2001 From: Craig Topper Date: Sat, 21 Sep 2019 06:44:29 +0000 Subject: [PATCH 60/71] [X86] Use sse_load_f32/f64 and timm in patterns for memory form of vgetmantss/sd. Previously we only matched scalar_to_vector and scalar load, but we should be able to narrow a vector load or match vzload. Also need to match TargetConstant instead of Constant. The register patterns were previously updated, but not the memory patterns. llvm-svn: 372458 --- llvm/lib/Target/X86/X86InstrAVX512.td | 7 +++---- llvm/test/CodeGen/X86/avx512-intrinsics.ll | 6 ++---- 2 files changed, 5 insertions(+), 8 deletions(-) diff --git a/llvm/lib/Target/X86/X86InstrAVX512.td b/llvm/lib/Target/X86/X86InstrAVX512.td index cd833b7d21e57..cb0d009234b7f 100644 --- a/llvm/lib/Target/X86/X86InstrAVX512.td +++ b/llvm/lib/Target/X86/X86InstrAVX512.td @@ -10280,12 +10280,11 @@ multiclass avx512_fp_scalar_imm opc, string OpcodeStr, SDNode OpNode, (i32 timm:$src3))>, Sched<[sched]>; defm rmi : AVX512_maskable_scalar, + (_.VT _.ScalarIntMemCPat:$src2), + (i32 timm:$src3))>, Sched<[sched.Folded, sched.ReadAfterFold]>; } } diff --git a/llvm/test/CodeGen/X86/avx512-intrinsics.ll b/llvm/test/CodeGen/X86/avx512-intrinsics.ll index 90b211ff65014..e94f16a562994 100644 --- a/llvm/test/CodeGen/X86/avx512-intrinsics.ll +++ b/llvm/test/CodeGen/X86/avx512-intrinsics.ll @@ -4801,15 +4801,13 @@ define <4 x float>@test_int_x86_avx512_mask_getmant_ss(<4 x float> %x0, <4 x flo define <4 x float> @test_int_x86_avx512_mask_getmant_ss_load(<4 x float> %x0, <4 x float>* %x1p) { ; X64-LABEL: test_int_x86_avx512_mask_getmant_ss_load: ; X64: # %bb.0: -; X64-NEXT: vmovaps (%rdi), %xmm1 -; X64-NEXT: vgetmantss $11, %xmm1, %xmm0, %xmm0 +; X64-NEXT: vgetmantss $11, (%rdi), %xmm0, %xmm0 ; X64-NEXT: retq ; ; X86-LABEL: test_int_x86_avx512_mask_getmant_ss_load: ; X86: # %bb.0: ; X86-NEXT: movl {{[0-9]+}}(%esp), %eax -; X86-NEXT: vmovaps (%eax), %xmm1 -; X86-NEXT: vgetmantss $11, %xmm1, %xmm0, %xmm0 +; X86-NEXT: vgetmantss $11, (%eax), %xmm0, %xmm0 ; X86-NEXT: retl %x1 = load <4 x float>, <4 x float>* %x1p %res = call <4 x float> @llvm.x86.avx512.mask.getmant.ss(<4 x float> %x0, <4 x float> %x1, i32 11, <4 x float> undef, i8 -1, i32 4) From 8827047551570b7ed7088765c3de2a8cce6823b8 Mon Sep 17 00:00:00 2001 From: Kamil Rytarowski Date: Sat, 21 Sep 2019 07:30:42 +0000 Subject: [PATCH 61/71] Stop tracking atexit/__cxa_atexit/pthread_atfork allocations in LSan/NetBSD Summary: The atexit(3) and __cxa_atexit() calls allocate internally memory and free on exit, after executing all callback. This causes false positives as DoLeakCheck() is called from the atexit handler. In the LSan/ASan tests there are strict checks triggering false positives here. Intercept all atexit(3) and __cxa_atexit() calls and disable LSan when calling the real functions. Stop tracing allocations in pthread_atfork(3) funtions, as there are performed internal allocations that are not freed for the time of running StopTheWorld() code. This avoids false-positives. The same changes have to be replicated in the ASan and LSan runtime. Non-NetBSD OSs are not tested and this code is restricted to NetBSD only. Reviewers: dvyukov, joerg, mgorny, vitalybuka, eugenis Reviewed By: vitalybuka Subscribers: jfb, llvm-commits, #sanitizers Tags: #sanitizers, #llvm Differential Revision: https://reviews.llvm.org/D67331 llvm-svn: 372459 --- compiler-rt/lib/asan/asan_interceptors.cpp | 44 ++++++++++++++++++- compiler-rt/lib/asan/asan_interceptors.h | 12 +++++ compiler-rt/lib/lsan/lsan_interceptors.cpp | 42 ++++++++++++++++++ .../sanitizer_platform_interceptors.h | 4 ++ 4 files changed, 101 insertions(+), 1 deletion(-) diff --git a/compiler-rt/lib/asan/asan_interceptors.cpp b/compiler-rt/lib/asan/asan_interceptors.cpp index cea4d63e64d55..ec958933875af 100644 --- a/compiler-rt/lib/asan/asan_interceptors.cpp +++ b/compiler-rt/lib/asan/asan_interceptors.cpp @@ -560,24 +560,58 @@ INTERCEPTOR(long long, atoll, const char *nptr) { } #endif // ASAN_INTERCEPT_ATOLL_AND_STRTOLL -#if ASAN_INTERCEPT___CXA_ATEXIT +#if ASAN_INTERCEPT___CXA_ATEXIT || ASAN_INTERCEPT_ATEXIT static void AtCxaAtexit(void *unused) { (void)unused; StopInitOrderChecking(); } +#endif +#if ASAN_INTERCEPT___CXA_ATEXIT INTERCEPTOR(int, __cxa_atexit, void (*func)(void *), void *arg, void *dso_handle) { #if SANITIZER_MAC if (UNLIKELY(!asan_inited)) return REAL(__cxa_atexit)(func, arg, dso_handle); #endif ENSURE_ASAN_INITED(); +#if CAN_SANITIZE_LEAKS + __lsan::ScopedInterceptorDisabler disabler; +#endif int res = REAL(__cxa_atexit)(func, arg, dso_handle); REAL(__cxa_atexit)(AtCxaAtexit, nullptr, nullptr); return res; } #endif // ASAN_INTERCEPT___CXA_ATEXIT +#if ASAN_INTERCEPT_ATEXIT +INTERCEPTOR(int, atexit, void (*func)()) { + ENSURE_ASAN_INITED(); +#if CAN_SANITIZE_LEAKS + __lsan::ScopedInterceptorDisabler disabler; +#endif + // Avoid calling real atexit as it is unrechable on at least on Linux. + int res = REAL(__cxa_atexit)((void (*)(void *a))func, nullptr, nullptr); + REAL(__cxa_atexit)(AtCxaAtexit, nullptr, nullptr); + return res; +} +#endif + +#if ASAN_INTERCEPT_PTHREAD_ATFORK +extern "C" { +extern int _pthread_atfork(void (*prepare)(), void (*parent)(), + void (*child)()); +}; + +INTERCEPTOR(int, pthread_atfork, void (*prepare)(), void (*parent)(), + void (*child)()) { +#if CAN_SANITIZE_LEAKS + __lsan::ScopedInterceptorDisabler disabler; +#endif + // REAL(pthread_atfork) cannot be called due to symbol indirections at least on NetBSD + return _pthread_atfork(prepare, parent, child); +} +#endif + #if ASAN_INTERCEPT_VFORK DEFINE_REAL(int, vfork) DECLARE_EXTERN_INTERCEPTOR_AND_WRAPPER(int, vfork) @@ -660,6 +694,14 @@ void InitializeAsanInterceptors() { ASAN_INTERCEPT_FUNC(__cxa_atexit); #endif +#if ASAN_INTERCEPT_ATEXIT + ASAN_INTERCEPT_FUNC(atexit); +#endif + +#if ASAN_INTERCEPT_PTHREAD_ATFORK + ASAN_INTERCEPT_FUNC(pthread_atfork); +#endif + #if ASAN_INTERCEPT_VFORK ASAN_INTERCEPT_FUNC(vfork); #endif diff --git a/compiler-rt/lib/asan/asan_interceptors.h b/compiler-rt/lib/asan/asan_interceptors.h index 155ea4156abbe..344a64bd83d33 100644 --- a/compiler-rt/lib/asan/asan_interceptors.h +++ b/compiler-rt/lib/asan/asan_interceptors.h @@ -99,6 +99,12 @@ void InitializePlatformInterceptors(); # define ASAN_INTERCEPT___CXA_ATEXIT 0 #endif +#if SANITIZER_NETBSD +# define ASAN_INTERCEPT_ATEXIT 1 +#else +# define ASAN_INTERCEPT_ATEXIT 0 +#endif + #if SANITIZER_LINUX && !SANITIZER_ANDROID # define ASAN_INTERCEPT___STRDUP 1 #else @@ -112,6 +118,12 @@ void InitializePlatformInterceptors(); # define ASAN_INTERCEPT_VFORK 0 #endif +#if SANITIZER_NETBSD +# define ASAN_INTERCEPT_PTHREAD_ATFORK 1 +#else +# define ASAN_INTERCEPT_PTHREAD_ATFORK 0 +#endif + DECLARE_REAL(int, memcmp, const void *a1, const void *a2, uptr size) DECLARE_REAL(char*, strchr, const char *str, int c) DECLARE_REAL(SIZE_T, strlen, const char *s) diff --git a/compiler-rt/lib/lsan/lsan_interceptors.cpp b/compiler-rt/lib/lsan/lsan_interceptors.cpp index f06d5fff70635..84a6acda464bf 100644 --- a/compiler-rt/lib/lsan/lsan_interceptors.cpp +++ b/compiler-rt/lib/lsan/lsan_interceptors.cpp @@ -345,6 +345,44 @@ INTERCEPTOR(void, thr_exit, tid_t *state) { #define LSAN_MAYBE_INTERCEPT_THR_EXIT #endif +#if SANITIZER_INTERCEPT___CXA_ATEXIT +INTERCEPTOR(int, __cxa_atexit, void (*func)(void *), void *arg, + void *dso_handle) { + __lsan::ScopedInterceptorDisabler disabler; + return REAL(__cxa_atexit)(func, arg, dso_handle); +} +#define LSAN_MAYBE_INTERCEPT___CXA_ATEXIT INTERCEPT_FUNCTION(__cxa_atexit) +#else +#define LSAN_MAYBE_INTERCEPT___CXA_ATEXIT +#endif + +#if SANITIZER_INTERCEPT_ATEXIT +INTERCEPTOR(int, atexit, void (*f)()) { + __lsan::ScopedInterceptorDisabler disabler; + return REAL(__cxa_atexit)((void (*)(void *a))f, 0, 0); +} +#define LSAN_MAYBE_INTERCEPT_ATEXIT INTERCEPT_FUNCTION(atexit) +#else +#define LSAN_MAYBE_INTERCEPT_ATEXIT +#endif + +#if SANITIZER_INTERCEPT_PTHREAD_ATFORK +extern "C" { +extern int _pthread_atfork(void (*prepare)(), void (*parent)(), + void (*child)()); +}; + +INTERCEPTOR(int, pthread_atfork, void (*prepare)(), void (*parent)(), + void (*child)()) { + __lsan::ScopedInterceptorDisabler disabler; + // REAL(pthread_atfork) cannot be called due to symbol indirections at least on NetBSD + return _pthread_atfork(prepare, parent, child); +} +#define LSAN_MAYBE_INTERCEPT_PTHREAD_ATFORK INTERCEPT_FUNCTION(pthread_atfork) +#else +#define LSAN_MAYBE_INTERCEPT_PTHREAD_ATFORK +#endif + struct ThreadParam { void *(*callback)(void *arg); void *param; @@ -454,6 +492,10 @@ void InitializeInterceptors() { LSAN_MAYBE_INTERCEPT__LWP_EXIT; LSAN_MAYBE_INTERCEPT_THR_EXIT; + LSAN_MAYBE_INTERCEPT___CXA_ATEXIT; + LSAN_MAYBE_INTERCEPT_ATEXIT; + LSAN_MAYBE_INTERCEPT_PTHREAD_ATFORK; + #if !SANITIZER_NETBSD && !SANITIZER_FREEBSD if (pthread_key_create(&g_thread_finalize_key, &thread_finalize)) { Report("LeakSanitizer: failed to create thread key.\n"); diff --git a/compiler-rt/lib/sanitizer_common/sanitizer_platform_interceptors.h b/compiler-rt/lib/sanitizer_common/sanitizer_platform_interceptors.h index cf079c4355455..c3b6f285569a8 100644 --- a/compiler-rt/lib/sanitizer_common/sanitizer_platform_interceptors.h +++ b/compiler-rt/lib/sanitizer_common/sanitizer_platform_interceptors.h @@ -567,5 +567,9 @@ #define SANITIZER_INTERCEPT_SL_INIT (SI_FREEBSD || SI_NETBSD) #define SANITIZER_INTERCEPT_GETRANDOM SI_LINUX +#define SANITIZER_INTERCEPT___CXA_ATEXIT SI_NETBSD +#define SANITIZER_INTERCEPT_ATEXIT SI_NETBSD +#define SANITIZER_INTERCEPT_PTHREAD_ATFORK SI_NETBSD + #endif // #ifndef SANITIZER_PLATFORM_INTERCEPTORS_H From 5fe1e55d35413b1904cfcf16ec15495398921fe5 Mon Sep 17 00:00:00 2001 From: Kamil Rytarowski Date: Sat, 21 Sep 2019 07:43:55 +0000 Subject: [PATCH 62/71] Avoid memory leak in ASan test Summary: Add missing free(3) for the malloc(3) call. Detected on NetBSD with LSan. Reviewers: joerg, mgorny, vitalybuka, dvyukov Reviewed By: vitalybuka Subscribers: llvm-commits, #sanitizers Tags: #sanitizers, #llvm Differential Revision: https://reviews.llvm.org/D67330 llvm-svn: 372460 --- compiler-rt/test/asan/TestCases/inline.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/compiler-rt/test/asan/TestCases/inline.cpp b/compiler-rt/test/asan/TestCases/inline.cpp index daeb7b49eb22a..12bd27e675844 100644 --- a/compiler-rt/test/asan/TestCases/inline.cpp +++ b/compiler-rt/test/asan/TestCases/inline.cpp @@ -13,6 +13,7 @@ int f(int *p) { int main(int argc, char **argv) { int * volatile x = (int*)malloc(2*sizeof(int) + 2); int res = f(x + 2); + free(x); if (res) exit(0); return 0; From 1b58389428ed07a7322ba9c2bcaeec99807f9457 Mon Sep 17 00:00:00 2001 From: Kamil Rytarowski Date: Sat, 21 Sep 2019 07:45:02 +0000 Subject: [PATCH 63/71] Add __lsan::ScopedInterceptorDisabler for strerror(3) Summary: strerror(3) on NetBSD uses internally TSD with a destructor that is never fired for exit(3). It's correctly called for pthread_exit(3) scenarios. This is a case when a leak on exit(3) is expected, unavoidable and harmless. Reviewers: joerg, vitalybuka, dvyukov, mgorny Reviewed By: vitalybuka Subscribers: dmgreen, kristof.beyls, jfb, llvm-commits, #sanitizers Tags: #sanitizers, #llvm Differential Revision: https://reviews.llvm.org/D67337 llvm-svn: 372461 --- compiler-rt/lib/asan/asan_interceptors.cpp | 5 +++++ compiler-rt/lib/lsan/lsan_interceptors.cpp | 12 ++++++++++++ .../sanitizer_common_interceptors.inc | 6 ++++++ 3 files changed, 23 insertions(+) diff --git a/compiler-rt/lib/asan/asan_interceptors.cpp b/compiler-rt/lib/asan/asan_interceptors.cpp index ec958933875af..e43a42736122c 100644 --- a/compiler-rt/lib/asan/asan_interceptors.cpp +++ b/compiler-rt/lib/asan/asan_interceptors.cpp @@ -164,6 +164,11 @@ DECLARE_REAL_AND_INTERCEPTOR(void, free, void *) ASAN_MEMSET_IMPL(ctx, block, c, size); \ } while (false) +#if CAN_SANITIZE_LEAKS +#define COMMON_INTERCEPTOR_STRERROR() \ + __lsan::ScopedInterceptorDisabler disabler +#endif + #include "sanitizer_common/sanitizer_common_interceptors.inc" #include "sanitizer_common/sanitizer_signal_interceptors.inc" diff --git a/compiler-rt/lib/lsan/lsan_interceptors.cpp b/compiler-rt/lib/lsan/lsan_interceptors.cpp index 84a6acda464bf..601a5efe9bd31 100644 --- a/compiler-rt/lib/lsan/lsan_interceptors.cpp +++ b/compiler-rt/lib/lsan/lsan_interceptors.cpp @@ -383,6 +383,16 @@ INTERCEPTOR(int, pthread_atfork, void (*prepare)(), void (*parent)(), #define LSAN_MAYBE_INTERCEPT_PTHREAD_ATFORK #endif +#if SANITIZER_INTERCEPT_STRERROR +INTERCEPTOR(char *, strerror, int errnum) { + __lsan::ScopedInterceptorDisabler disabler; + return REAL(strerror)(errnum); +} +#define LSAN_MAYBE_INTERCEPT_STRERROR INTERCEPT_FUNCTION(strerror) +#else +#define LSAN_MAYBE_INTERCEPT_STRERROR +#endif + struct ThreadParam { void *(*callback)(void *arg); void *param; @@ -496,6 +506,8 @@ void InitializeInterceptors() { LSAN_MAYBE_INTERCEPT_ATEXIT; LSAN_MAYBE_INTERCEPT_PTHREAD_ATFORK; + LSAN_MAYBE_INTERCEPT_STRERROR; + #if !SANITIZER_NETBSD && !SANITIZER_FREEBSD if (pthread_key_create(&g_thread_finalize_key, &thread_finalize)) { Report("LeakSanitizer: failed to create thread key.\n"); diff --git a/compiler-rt/lib/sanitizer_common/sanitizer_common_interceptors.inc b/compiler-rt/lib/sanitizer_common/sanitizer_common_interceptors.inc index 7ea896ef2d441..587b1ea227226 100644 --- a/compiler-rt/lib/sanitizer_common/sanitizer_common_interceptors.inc +++ b/compiler-rt/lib/sanitizer_common/sanitizer_common_interceptors.inc @@ -36,6 +36,7 @@ // COMMON_INTERCEPTOR_MMAP_IMPL // COMMON_INTERCEPTOR_COPY_STRING // COMMON_INTERCEPTOR_STRNDUP_IMPL +// COMMON_INTERCEPTOR_STRERROR //===----------------------------------------------------------------------===// #include "interception/interception.h" @@ -301,6 +302,10 @@ bool PlatformHasDifferentMemcpyAndMemmove(); return new_mem; #endif +#ifndef COMMON_INTERCEPTOR_STRERROR +#define COMMON_INTERCEPTOR_STRERROR() {} +#endif + struct FileMetadata { // For open_memstream(). char **addr; @@ -3677,6 +3682,7 @@ INTERCEPTOR(int, sched_getparam, int pid, void *param) { INTERCEPTOR(char *, strerror, int errnum) { void *ctx; COMMON_INTERCEPTOR_ENTER(ctx, strerror, errnum); + COMMON_INTERCEPTOR_STRERROR(); char *res = REAL(strerror)(errnum); if (res) COMMON_INTERCEPTOR_INITIALIZE_RANGE(res, REAL(strlen)(res) + 1); return res; From c90fda6abe84127a99a8fe4341b6ed7c8abee47e Mon Sep 17 00:00:00 2001 From: Kristof Umann Date: Sat, 21 Sep 2019 07:56:40 +0000 Subject: [PATCH 64/71] Attempt to fix a windows buildbot failure llvm-svn: 372462 --- clang/lib/StaticAnalyzer/Checkers/MallocChecker.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/clang/lib/StaticAnalyzer/Checkers/MallocChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/MallocChecker.cpp index 27a40e35d642b..52d21a54a12fd 100644 --- a/clang/lib/StaticAnalyzer/Checkers/MallocChecker.cpp +++ b/clang/lib/StaticAnalyzer/Checkers/MallocChecker.cpp @@ -137,8 +137,8 @@ class RefState { const Stmt *S; - Kind K : 3; - AllocationFamily Family : 3; + Kind K; + AllocationFamily Family; RefState(Kind k, const Stmt *s, AllocationFamily family) : S(s), K(k), Family(family) { From 8a74eca398a012a9b3b18b10c2b5aedef203d04b Mon Sep 17 00:00:00 2001 From: James Molloy Date: Sat, 21 Sep 2019 08:19:41 +0000 Subject: [PATCH 65/71] [MachinePipeliner] Improve the TargetInstrInfo API analyzeLoop/reduceLoopCount Recommit: fix asan errors. The way MachinePipeliner uses these target hooks is stateful - we reduce trip count by one per call to reduceLoopCount. It's a little overfit for hardware loops, where we don't have to worry about stitching a loop induction variable across prologs and epilogs (the induction variable is implicit). This patch introduces a new API: /// Analyze loop L, which must be a single-basic-block loop, and if the /// conditions can be understood enough produce a PipelinerLoopInfo object. virtual std::unique_ptr analyzeLoopForPipelining(MachineBasicBlock *LoopBB) const; The return value is expected to be an implementation of the abstract class: /// Object returned by analyzeLoopForPipelining. Allows software pipelining /// implementations to query attributes of the loop being pipelined. class PipelinerLoopInfo { public: virtual ~PipelinerLoopInfo(); /// Return true if the given instruction should not be pipelined and should /// be ignored. An example could be a loop comparison, or induction variable /// update with no users being pipelined. virtual bool shouldIgnoreForPipelining(const MachineInstr *MI) const = 0; /// Create a condition to determine if the trip count of the loop is greater /// than TC. /// /// If the trip count is statically known to be greater than TC, return /// true. If the trip count is statically known to be not greater than TC, /// return false. Otherwise return nullopt and fill out Cond with the test /// condition. virtual Optional createTripCountGreaterCondition(int TC, MachineBasicBlock &MBB, SmallVectorImpl &Cond) = 0; /// Modify the loop such that the trip count is /// OriginalTC + TripCountAdjust. virtual void adjustTripCount(int TripCountAdjust) = 0; /// Called when the loop's preheader has been modified to NewPreheader. virtual void setPreheader(MachineBasicBlock *NewPreheader) = 0; /// Called when the loop is being removed. virtual void disposed() = 0; }; The Pipeliner (ModuloSchedule.cpp) can use this object to modify the loop while allowing the target to hold its own state across all calls. This API, in particular the disjunction of creating a trip count check condition and adjusting the loop, improves the code quality in ModuloSchedule.cpp. llvm-svn: 372463 --- llvm/include/llvm/CodeGen/ModuloSchedule.h | 2 + llvm/include/llvm/CodeGen/TargetInstrInfo.h | 44 +++++ llvm/lib/CodeGen/MachinePipeliner.cpp | 2 +- llvm/lib/CodeGen/ModuloSchedule.cpp | 40 ++--- llvm/lib/CodeGen/TargetInstrInfo.cpp | 2 + llvm/lib/Target/Hexagon/HexagonInstrInfo.cpp | 162 ++++++++++--------- llvm/lib/Target/Hexagon/HexagonInstrInfo.h | 19 +-- llvm/lib/Target/PowerPC/PPCInstrInfo.cpp | 144 ++++++++++------- llvm/lib/Target/PowerPC/PPCInstrInfo.h | 28 +--- llvm/test/CodeGen/Hexagon/swp-epilog-phi7.ll | 4 +- 10 files changed, 253 insertions(+), 194 deletions(-) diff --git a/llvm/include/llvm/CodeGen/ModuloSchedule.h b/llvm/include/llvm/CodeGen/ModuloSchedule.h index 530cefd1c81a7..36cc843c8849e 100644 --- a/llvm/include/llvm/CodeGen/ModuloSchedule.h +++ b/llvm/include/llvm/CodeGen/ModuloSchedule.h @@ -62,6 +62,7 @@ #include "llvm/CodeGen/MachineFunction.h" #include "llvm/CodeGen/MachineLoopInfo.h" +#include "llvm/CodeGen/TargetInstrInfo.h" #include "llvm/CodeGen/TargetSubtargetInfo.h" #include @@ -168,6 +169,7 @@ class ModuloScheduleExpander { MachineBasicBlock *BB; MachineBasicBlock *Preheader; MachineBasicBlock *NewKernel = nullptr; + std::unique_ptr LoopInfo; /// Map for each register and the max difference between its uses and def. /// The first element in the pair is the max difference in stages. The diff --git a/llvm/include/llvm/CodeGen/TargetInstrInfo.h b/llvm/include/llvm/CodeGen/TargetInstrInfo.h index a01d851f5104f..f16ec7a0837d9 100644 --- a/llvm/include/llvm/CodeGen/TargetInstrInfo.h +++ b/llvm/include/llvm/CodeGen/TargetInstrInfo.h @@ -662,6 +662,50 @@ class TargetInstrInfo : public MCInstrInfo { BytesAdded); } + /// Object returned by analyzeLoopForPipelining. Allows software pipelining + /// implementations to query attributes of the loop being pipelined and to + /// apply target-specific updates to the loop once pipelining is complete. + class PipelinerLoopInfo { + public: + virtual ~PipelinerLoopInfo(); + /// Return true if the given instruction should not be pipelined and should + /// be ignored. An example could be a loop comparison, or induction variable + /// update with no users being pipelined. + virtual bool shouldIgnoreForPipelining(const MachineInstr *MI) const = 0; + + /// Create a condition to determine if the trip count of the loop is greater + /// than TC. + /// + /// If the trip count is statically known to be greater than TC, return + /// true. If the trip count is statically known to be not greater than TC, + /// return false. Otherwise return nullopt and fill out Cond with the test + /// condition. + virtual Optional + createTripCountGreaterCondition(int TC, MachineBasicBlock &MBB, + SmallVectorImpl &Cond) = 0; + + /// Modify the loop such that the trip count is + /// OriginalTC + TripCountAdjust. + virtual void adjustTripCount(int TripCountAdjust) = 0; + + /// Called when the loop's preheader has been modified to NewPreheader. + virtual void setPreheader(MachineBasicBlock *NewPreheader) = 0; + + /// Called when the loop is being removed. Any instructions in the preheader + /// should be removed. + /// + /// Once this function is called, no other functions on this object are + /// valid; the loop has been removed. + virtual void disposed() = 0; + }; + + /// Analyze loop L, which must be a single-basic-block loop, and if the + /// conditions can be understood enough produce a PipelinerLoopInfo object. + virtual std::unique_ptr + analyzeLoopForPipelining(MachineBasicBlock *LoopBB) const { + return nullptr; + } + /// Analyze the loop code, return true if it cannot be understoo. Upon /// success, this function returns false and returns information about the /// induction variable and compare instruction used at the end. diff --git a/llvm/lib/CodeGen/MachinePipeliner.cpp b/llvm/lib/CodeGen/MachinePipeliner.cpp index fc16ebf66f5d9..b3d97c61fdaf6 100644 --- a/llvm/lib/CodeGen/MachinePipeliner.cpp +++ b/llvm/lib/CodeGen/MachinePipeliner.cpp @@ -326,7 +326,7 @@ bool MachinePipeliner::canPipelineLoop(MachineLoop &L) { LI.LoopInductionVar = nullptr; LI.LoopCompare = nullptr; - if (TII->analyzeLoop(L, LI.LoopInductionVar, LI.LoopCompare)) { + if (!TII->analyzeLoopForPipelining(L.getTopBlock())) { LLVM_DEBUG( dbgs() << "Unable to analyzeLoop, can NOT pipeline current Loop\n"); NumFailLoop++; diff --git a/llvm/lib/CodeGen/ModuloSchedule.cpp b/llvm/lib/CodeGen/ModuloSchedule.cpp index 8bea4037f544f..aa5e86e97d1aa 100644 --- a/llvm/lib/CodeGen/ModuloSchedule.cpp +++ b/llvm/lib/CodeGen/ModuloSchedule.cpp @@ -105,6 +105,9 @@ void ModuloScheduleExpander::expand() { } void ModuloScheduleExpander::generatePipelinedLoop() { + LoopInfo = TII->analyzeLoopForPipelining(BB); + assert(LoopInfo && "Must be able to analyze loop!"); + // Create a new basic block for the kernel and add it to the CFG. MachineBasicBlock *KernelBB = MF.CreateMachineBasicBlock(BB->getBasicBlock()); @@ -847,10 +850,6 @@ void ModuloScheduleExpander::addBranches(MachineBasicBlock &PreheaderBB, MBBVectorTy &EpilogBBs, ValueMapTy *VRMap) { assert(PrologBBs.size() == EpilogBBs.size() && "Prolog/Epilog mismatch"); - MachineInstr *IndVar; - MachineInstr *Cmp; - if (TII->analyzeLoop(*Schedule.getLoop(), IndVar, Cmp)) - llvm_unreachable("Must be able to analyze loop!"); MachineBasicBlock *LastPro = KernelBB; MachineBasicBlock *LastEpi = KernelBB; @@ -858,32 +857,20 @@ void ModuloScheduleExpander::addBranches(MachineBasicBlock &PreheaderBB, // to the first prolog and the last epilog blocks. SmallVector PrevInsts; unsigned MaxIter = PrologBBs.size() - 1; - unsigned LC = UINT_MAX; - unsigned LCMin = UINT_MAX; for (unsigned i = 0, j = MaxIter; i <= MaxIter; ++i, --j) { // Add branches to the prolog that go to the corresponding // epilog, and the fall-thru prolog/kernel block. MachineBasicBlock *Prolog = PrologBBs[j]; MachineBasicBlock *Epilog = EpilogBBs[i]; - // We've executed one iteration, so decrement the loop count and check for - // the loop end. - SmallVector Cond; - // Check if the LOOP0 has already been removed. If so, then there is no need - // to reduce the trip count. - if (LC != 0) - LC = TII->reduceLoopCount(*Prolog, PreheaderBB, IndVar, *Cmp, Cond, - PrevInsts, j, MaxIter); - - // Record the value of the first trip count, which is used to determine if - // branches and blocks can be removed for constant trip counts. - if (LCMin == UINT_MAX) - LCMin = LC; + SmallVector Cond; + Optional StaticallyGreater = + LoopInfo->createTripCountGreaterCondition(j + 1, *Prolog, Cond); unsigned numAdded = 0; - if (Register::isVirtualRegister(LC)) { + if (!StaticallyGreater.hasValue()) { Prolog->addSuccessor(Epilog); numAdded = TII->insertBranch(*Prolog, Epilog, LastPro, Cond, DebugLoc()); - } else if (j >= LCMin) { + } else if (*StaticallyGreater == false) { Prolog->addSuccessor(Epilog); Prolog->removeSuccessor(LastPro); LastEpi->removeSuccessor(Epilog); @@ -894,10 +881,12 @@ void ModuloScheduleExpander::addBranches(MachineBasicBlock &PreheaderBB, LastEpi->clear(); LastEpi->eraseFromParent(); } + if (LastPro == KernelBB) { + LoopInfo->disposed(); + NewKernel = nullptr; + } LastPro->clear(); LastPro->eraseFromParent(); - if (LastPro == KernelBB) - NewKernel = nullptr; } else { numAdded = TII->insertBranch(*Prolog, LastPro, nullptr, Cond, DebugLoc()); removePhis(Epilog, Prolog); @@ -909,6 +898,11 @@ void ModuloScheduleExpander::addBranches(MachineBasicBlock &PreheaderBB, I != E && numAdded > 0; ++I, --numAdded) updateInstruction(&*I, false, j, 0, VRMap); } + + if (NewKernel) { + LoopInfo->setPreheader(PrologBBs[MaxIter]); + LoopInfo->adjustTripCount(-(MaxIter + 1)); + } } /// Return true if we can compute the amount the instruction changes diff --git a/llvm/lib/CodeGen/TargetInstrInfo.cpp b/llvm/lib/CodeGen/TargetInstrInfo.cpp index 0406649345b36..11872e13e4f7d 100644 --- a/llvm/lib/CodeGen/TargetInstrInfo.cpp +++ b/llvm/lib/CodeGen/TargetInstrInfo.cpp @@ -1257,3 +1257,5 @@ bool TargetInstrInfo::getInsertSubregInputs( InsertedReg.SubIdx = (unsigned)MOSubIdx.getImm(); return true; } + +TargetInstrInfo::PipelinerLoopInfo::~PipelinerLoopInfo() {} diff --git a/llvm/lib/Target/Hexagon/HexagonInstrInfo.cpp b/llvm/lib/Target/Hexagon/HexagonInstrInfo.cpp index 97318a8057bdd..ea43db0f4138d 100644 --- a/llvm/lib/Target/Hexagon/HexagonInstrInfo.cpp +++ b/llvm/lib/Target/Hexagon/HexagonInstrInfo.cpp @@ -674,86 +674,94 @@ unsigned HexagonInstrInfo::insertBranch(MachineBasicBlock &MBB, return 2; } -/// Analyze the loop code to find the loop induction variable and compare used -/// to compute the number of iterations. Currently, we analyze loop that are -/// controlled using hardware loops. In this case, the induction variable -/// instruction is null. For all other cases, this function returns true, which -/// means we're unable to analyze it. -bool HexagonInstrInfo::analyzeLoop(MachineLoop &L, - MachineInstr *&IndVarInst, - MachineInstr *&CmpInst) const { - - MachineBasicBlock *LoopEnd = L.getBottomBlock(); - MachineBasicBlock::iterator I = LoopEnd->getFirstTerminator(); - // We really "analyze" only hardware loops right now. - if (I != LoopEnd->end() && isEndLoopN(I->getOpcode())) { - IndVarInst = nullptr; - CmpInst = &*I; - return false; +class HexagonPipelinerLoopInfo : public TargetInstrInfo::PipelinerLoopInfo { + MachineInstr *Loop, *EndLoop; + MachineFunction *MF; + const HexagonInstrInfo *TII; + int64_t TripCount; + Register LoopCount; + DebugLoc DL; + +public: + HexagonPipelinerLoopInfo(MachineInstr *Loop, MachineInstr *EndLoop) + : Loop(Loop), EndLoop(EndLoop), MF(Loop->getParent()->getParent()), + TII(MF->getSubtarget().getInstrInfo()), + DL(Loop->getDebugLoc()) { + // Inspect the Loop instruction up-front, as it may be deleted when we call + // createTripCountGreaterCondition. + TripCount = Loop->getOpcode() == Hexagon::J2_loop0r + ? -1 + : Loop->getOperand(1).getImm(); + if (TripCount == -1) + LoopCount = Loop->getOperand(1).getReg(); } - return true; -} -/// Generate code to reduce the loop iteration by one and check if the loop is -/// finished. Return the value/register of the new loop count. this function -/// assumes the nth iteration is peeled first. -unsigned HexagonInstrInfo::reduceLoopCount( - MachineBasicBlock &MBB, MachineBasicBlock &PreHeader, MachineInstr *IndVar, - MachineInstr &Cmp, SmallVectorImpl &Cond, - SmallVectorImpl &PrevInsts, unsigned Iter, - unsigned MaxIter) const { - // We expect a hardware loop currently. This means that IndVar is set - // to null, and the compare is the ENDLOOP instruction. - assert((!IndVar) && isEndLoopN(Cmp.getOpcode()) - && "Expecting a hardware loop"); - MachineFunction *MF = MBB.getParent(); - DebugLoc DL = Cmp.getDebugLoc(); - SmallPtrSet VisitedBBs; - MachineInstr *Loop = findLoopInstr(&MBB, Cmp.getOpcode(), - Cmp.getOperand(0).getMBB(), VisitedBBs); - if (!Loop) - return 0; - // If the loop trip count is a compile-time value, then just change the - // value. - if (Loop->getOpcode() == Hexagon::J2_loop0i || - Loop->getOpcode() == Hexagon::J2_loop1i) { - int64_t Offset = Loop->getOperand(1).getImm(); - if (Offset <= 1) - Loop->eraseFromParent(); - else - Loop->getOperand(1).setImm(Offset - 1); - return Offset - 1; + bool shouldIgnoreForPipelining(const MachineInstr *MI) const override { + // Only ignore the terminator. + return MI == EndLoop; } - // The loop trip count is a run-time value. We generate code to subtract - // one from the trip count, and update the loop instruction. - assert(Loop->getOpcode() == Hexagon::J2_loop0r && "Unexpected instruction"); - Register LoopCount = Loop->getOperand(1).getReg(); - // Check if we're done with the loop. - unsigned LoopEnd = createVR(MF, MVT::i1); - MachineInstr *NewCmp = BuildMI(&MBB, DL, get(Hexagon::C2_cmpgtui), LoopEnd). - addReg(LoopCount).addImm(1); - unsigned NewLoopCount = createVR(MF, MVT::i32); - MachineInstr *NewAdd = BuildMI(&MBB, DL, get(Hexagon::A2_addi), NewLoopCount). - addReg(LoopCount).addImm(-1); - const HexagonRegisterInfo &HRI = *Subtarget.getRegisterInfo(); - // Update the previously generated instructions with the new loop counter. - for (SmallVectorImpl::iterator I = PrevInsts.begin(), - E = PrevInsts.end(); I != E; ++I) - (*I)->substituteRegister(LoopCount, NewLoopCount, 0, HRI); - PrevInsts.clear(); - PrevInsts.push_back(NewCmp); - PrevInsts.push_back(NewAdd); - // Insert the new loop instruction if this is the last time the loop is - // decremented. - if (Iter == MaxIter) - BuildMI(&MBB, DL, get(Hexagon::J2_loop0r)). - addMBB(Loop->getOperand(0).getMBB()).addReg(NewLoopCount); - // Delete the old loop instruction. - if (Iter == 0) - Loop->eraseFromParent(); - Cond.push_back(MachineOperand::CreateImm(Hexagon::J2_jumpf)); - Cond.push_back(NewCmp->getOperand(0)); - return NewLoopCount; + + Optional + createTripCountGreaterCondition(int TC, MachineBasicBlock &MBB, + SmallVectorImpl &Cond) override { + if (TripCount == -1) { + // Check if we're done with the loop. + unsigned Done = TII->createVR(MF, MVT::i1); + MachineInstr *NewCmp = BuildMI(&MBB, DL, + TII->get(Hexagon::C2_cmpgtui), Done) + .addReg(LoopCount) + .addImm(TC); + Cond.push_back(MachineOperand::CreateImm(Hexagon::J2_jumpf)); + Cond.push_back(NewCmp->getOperand(0)); + return {}; + } + + return TripCount > TC; + } + + void setPreheader(MachineBasicBlock *NewPreheader) override { + NewPreheader->splice(NewPreheader->getFirstTerminator(), Loop->getParent(), + Loop); + } + + void adjustTripCount(int TripCountAdjust) override { + // If the loop trip count is a compile-time value, then just change the + // value. + if (Loop->getOpcode() == Hexagon::J2_loop0i || + Loop->getOpcode() == Hexagon::J2_loop1i) { + int64_t TripCount = Loop->getOperand(1).getImm() + TripCountAdjust; + assert(TripCount > 0 && "Can't create an empty or negative loop!"); + Loop->getOperand(1).setImm(TripCount); + return; + } + + // The loop trip count is a run-time value. We generate code to subtract + // one from the trip count, and update the loop instruction. + Register LoopCount = Loop->getOperand(1).getReg(); + Register NewLoopCount = TII->createVR(MF, MVT::i32); + BuildMI(*Loop->getParent(), Loop, Loop->getDebugLoc(), + TII->get(Hexagon::A2_addi), NewLoopCount) + .addReg(LoopCount) + .addImm(TripCountAdjust); + Loop->getOperand(1).setReg(NewLoopCount); + } + + void disposed() override { Loop->eraseFromParent(); } +}; + +std::unique_ptr +HexagonInstrInfo::analyzeLoopForPipelining(MachineBasicBlock *LoopBB) const { + // We really "analyze" only hardware loops right now. + MachineBasicBlock::iterator I = LoopBB->getFirstTerminator(); + + if (I != LoopBB->end() && isEndLoopN(I->getOpcode())) { + SmallPtrSet VisitedBBs; + MachineInstr *LoopInst = findLoopInstr( + LoopBB, I->getOpcode(), I->getOperand(0).getMBB(), VisitedBBs); + if (LoopInst) + return std::make_unique(LoopInst, &*I); + } + return nullptr; } bool HexagonInstrInfo::isProfitableToIfCvt(MachineBasicBlock &MBB, diff --git a/llvm/lib/Target/Hexagon/HexagonInstrInfo.h b/llvm/lib/Target/Hexagon/HexagonInstrInfo.h index e0a999d0f4c43..e863400480b62 100644 --- a/llvm/lib/Target/Hexagon/HexagonInstrInfo.h +++ b/llvm/lib/Target/Hexagon/HexagonInstrInfo.h @@ -129,21 +129,10 @@ class HexagonInstrInfo : public HexagonGenInstrInfo { const DebugLoc &DL, int *BytesAdded = nullptr) const override; - /// Analyze the loop code, return true if it cannot be understood. Upon - /// success, this function returns false and returns information about the - /// induction variable and compare instruction used at the end. - bool analyzeLoop(MachineLoop &L, MachineInstr *&IndVarInst, - MachineInstr *&CmpInst) const override; - - /// Generate code to reduce the loop iteration by one and check if the loop - /// is finished. Return the value/register of the new loop count. We need - /// this function when peeling off one or more iterations of a loop. This - /// function assumes the nth iteration is peeled first. - unsigned reduceLoopCount(MachineBasicBlock &MBB, MachineBasicBlock &PreHeader, - MachineInstr *IndVar, MachineInstr &Cmp, - SmallVectorImpl &Cond, - SmallVectorImpl &PrevInsts, - unsigned Iter, unsigned MaxIter) const override; + /// Analyze loop L, which must be a single-basic-block loop, and if the + /// conditions can be understood enough produce a PipelinerLoopInfo object. + std::unique_ptr + analyzeLoopForPipelining(MachineBasicBlock *LoopBB) const override; /// Return true if it's profitable to predicate /// instructions with accumulated instruction latency of "NumCycles" diff --git a/llvm/lib/Target/PowerPC/PPCInstrInfo.cpp b/llvm/lib/Target/PowerPC/PPCInstrInfo.cpp index e4540d6520efd..c33f0b368670a 100644 --- a/llvm/lib/Target/PowerPC/PPCInstrInfo.cpp +++ b/llvm/lib/Target/PowerPC/PPCInstrInfo.cpp @@ -3930,21 +3930,97 @@ bool PPCInstrInfo::isBDNZ(unsigned Opcode) const { return (Opcode == (Subtarget.isPPC64() ? PPC::BDNZ8 : PPC::BDNZ)); } -bool PPCInstrInfo::analyzeLoop(MachineLoop &L, MachineInstr *&IndVarInst, - MachineInstr *&CmpInst) const { - MachineBasicBlock *LoopEnd = L.getBottomBlock(); - MachineBasicBlock::iterator I = LoopEnd->getFirstTerminator(); - // We really "analyze" only CTR loops right now. - if (I != LoopEnd->end() && isBDNZ(I->getOpcode())) { - IndVarInst = nullptr; - CmpInst = &*I; - return false; +class PPCPipelinerLoopInfo : public TargetInstrInfo::PipelinerLoopInfo { + MachineInstr *Loop, *EndLoop, *LoopCount; + MachineFunction *MF; + const TargetInstrInfo *TII; + int64_t TripCount; + +public: + PPCPipelinerLoopInfo(MachineInstr *Loop, MachineInstr *EndLoop, + MachineInstr *LoopCount) + : Loop(Loop), EndLoop(EndLoop), LoopCount(LoopCount), + MF(Loop->getParent()->getParent()), + TII(MF->getSubtarget().getInstrInfo()) { + // Inspect the Loop instruction up-front, as it may be deleted when we call + // createTripCountGreaterCondition. + if (LoopCount->getOpcode() == PPC::LI8 || LoopCount->getOpcode() == PPC::LI) + TripCount = LoopCount->getOperand(1).getImm(); + else + TripCount = -1; } - return true; + + bool shouldIgnoreForPipelining(const MachineInstr *MI) const override { + // Only ignore the terminator. + return MI == EndLoop; + } + + Optional + createTripCountGreaterCondition(int TC, MachineBasicBlock &MBB, + SmallVectorImpl &Cond) override { + if (TripCount == -1) { + // Since BDZ/BDZ8 that we will insert will also decrease the ctr by 1, + // so we don't need to generate any thing here. + Cond.push_back(MachineOperand::CreateImm(0)); + Cond.push_back(MachineOperand::CreateReg( + MF->getSubtarget().isPPC64() ? PPC::CTR8 : PPC::CTR, + true)); + return {}; + } + + return TripCount > TC; + } + + void setPreheader(MachineBasicBlock *NewPreheader) override { + // Do nothing. We want the LOOP setup instruction to stay in the *old* + // preheader, so we can use BDZ in the prologs to adapt the loop trip count. + } + + void adjustTripCount(int TripCountAdjust) override { + // If the loop trip count is a compile-time value, then just change the + // value. + if (LoopCount->getOpcode() == PPC::LI8 || + LoopCount->getOpcode() == PPC::LI) { + int64_t TripCount = LoopCount->getOperand(1).getImm() + TripCountAdjust; + LoopCount->getOperand(1).setImm(TripCount); + return; + } + + // Since BDZ/BDZ8 that we will insert will also decrease the ctr by 1, + // so we don't need to generate any thing here. + } + + void disposed() override { + Loop->eraseFromParent(); + // Ensure the loop setup instruction is deleted too. + LoopCount->eraseFromParent(); + } +}; + +std::unique_ptr +PPCInstrInfo::analyzeLoopForPipelining(MachineBasicBlock *LoopBB) const { + // We really "analyze" only hardware loops right now. + MachineBasicBlock::iterator I = LoopBB->getFirstTerminator(); + MachineBasicBlock *Preheader = *LoopBB->pred_begin(); + if (Preheader == LoopBB) + Preheader = *std::next(LoopBB->pred_begin()); + MachineFunction *MF = Preheader->getParent(); + + if (I != LoopBB->end() && isBDNZ(I->getOpcode())) { + SmallPtrSet Visited; + if (MachineInstr *LoopInst = findLoopInstr(*Preheader, Visited)) { + Register LoopCountReg = LoopInst->getOperand(0).getReg(); + MachineRegisterInfo &MRI = MF->getRegInfo(); + MachineInstr *LoopCount = MRI.getUniqueVRegDef(LoopCountReg); + return std::make_unique(LoopInst, &*I, LoopCount); + } + } + return nullptr; } -MachineInstr * -PPCInstrInfo::findLoopInstr(MachineBasicBlock &PreHeader) const { +MachineInstr *PPCInstrInfo::findLoopInstr( + MachineBasicBlock &PreHeader, + SmallPtrSet &Visited) const { unsigned LOOPi = (Subtarget.isPPC64() ? PPC::MTCTR8loop : PPC::MTCTRloop); @@ -3955,50 +4031,6 @@ PPCInstrInfo::findLoopInstr(MachineBasicBlock &PreHeader) const { return nullptr; } -unsigned PPCInstrInfo::reduceLoopCount( - MachineBasicBlock &MBB, MachineBasicBlock &PreHeader, MachineInstr *IndVar, - MachineInstr &Cmp, SmallVectorImpl &Cond, - SmallVectorImpl &PrevInsts, unsigned Iter, - unsigned MaxIter) const { - // We expect a hardware loop currently. This means that IndVar is set - // to null, and the compare is the ENDLOOP instruction. - assert((!IndVar) && isBDNZ(Cmp.getOpcode()) && "Expecting a CTR loop"); - MachineFunction *MF = MBB.getParent(); - DebugLoc DL = Cmp.getDebugLoc(); - MachineInstr *Loop = findLoopInstr(PreHeader); - if (!Loop) - return 0; - Register LoopCountReg = Loop->getOperand(0).getReg(); - MachineRegisterInfo &MRI = MF->getRegInfo(); - MachineInstr *LoopCount = MRI.getUniqueVRegDef(LoopCountReg); - - if (!LoopCount) - return 0; - // If the loop trip count is a compile-time value, then just change the - // value. - if (LoopCount->getOpcode() == PPC::LI8 || LoopCount->getOpcode() == PPC::LI) { - int64_t Offset = LoopCount->getOperand(1).getImm(); - if (Offset <= 1) { - LoopCount->eraseFromParent(); - Loop->eraseFromParent(); - return 0; - } - LoopCount->getOperand(1).setImm(Offset - 1); - return Offset - 1; - } - - // The loop trip count is a run-time value. - // We need to subtract one from the trip count, - // and insert branch later to check if we're done with the loop. - - // Since BDZ/BDZ8 that we will insert will also decrease the ctr by 1, - // so we don't need to generate any thing here. - Cond.push_back(MachineOperand::CreateImm(0)); - Cond.push_back(MachineOperand::CreateReg( - Subtarget.isPPC64() ? PPC::CTR8 : PPC::CTR, true)); - return LoopCountReg; -} - // Return true if get the base operand, byte offset of an instruction and the // memory width. Width is the size of memory that is being loaded/stored. bool PPCInstrInfo::getMemOperandWithOffsetWidth( diff --git a/llvm/lib/Target/PowerPC/PPCInstrInfo.h b/llvm/lib/Target/PowerPC/PPCInstrInfo.h index 5150650439bc6..13eecdff55842 100644 --- a/llvm/lib/Target/PowerPC/PPCInstrInfo.h +++ b/llvm/lib/Target/PowerPC/PPCInstrInfo.h @@ -486,26 +486,14 @@ class PPCInstrInfo : public PPCGenInstrInfo { /// On PPC, we have two instructions used to set-up the hardware loop /// (MTCTRloop, MTCTR8loop) with corresponding endloop (BDNZ, BDNZ8) /// instructions to indicate the end of a loop. - MachineInstr *findLoopInstr(MachineBasicBlock &PreHeader) const; - - /// Analyze the loop code to find the loop induction variable and compare used - /// to compute the number of iterations. Currently, we analyze loop that are - /// controlled using hardware loops. In this case, the induction variable - /// instruction is null. For all other cases, this function returns true, - /// which means we're unable to analyze it. \p IndVarInst and \p CmpInst will - /// return new values when we can analyze the readonly loop \p L, otherwise, - /// nothing got changed - bool analyzeLoop(MachineLoop &L, MachineInstr *&IndVarInst, - MachineInstr *&CmpInst) const override; - /// Generate code to reduce the loop iteration by one and check if the loop - /// is finished. Return the value/register of the new loop count. We need - /// this function when peeling off one or more iterations of a loop. This - /// function assumes the last iteration is peeled first. - unsigned reduceLoopCount(MachineBasicBlock &MBB, MachineBasicBlock &PreHeader, - MachineInstr *IndVar, MachineInstr &Cmp, - SmallVectorImpl &Cond, - SmallVectorImpl &PrevInsts, - unsigned Iter, unsigned MaxIter) const override; + MachineInstr * + findLoopInstr(MachineBasicBlock &PreHeader, + SmallPtrSet &Visited) const; + + /// Analyze loop L, which must be a single-basic-block loop, and if the + /// conditions can be understood enough produce a PipelinerLoopInfo object. + std::unique_ptr + analyzeLoopForPipelining(MachineBasicBlock *LoopBB) const override; }; } diff --git a/llvm/test/CodeGen/Hexagon/swp-epilog-phi7.ll b/llvm/test/CodeGen/Hexagon/swp-epilog-phi7.ll index 8cad174937df8..89a04d9f76ff5 100644 --- a/llvm/test/CodeGen/Hexagon/swp-epilog-phi7.ll +++ b/llvm/test/CodeGen/Hexagon/swp-epilog-phi7.ll @@ -7,8 +7,8 @@ ; CHECK: if ({{.*}}) jump ; CHECK: [[VREG:v([0-9]+)]]{{.*}} = {{.*}}vmem(r{{[0-9]+}}++#1) -; CHECK: if ({{.*}}) {{jump|jump:nt}} [[EPLOG1:(.*)]] -; CHECK: if ({{.*}}) {{jump|jump:nt}} [[EPLOG:(.*)]] +; CHECK: if ({{.*}}) {{jump|jump:nt|jump:t}} [[EPLOG1:(.*)]] +; CHECK: if ({{.*}}) {{jump|jump:nt|jump:t}} [[EPLOG:(.*)]] ; CHECK: [[EPLOG]]: ; CHECK: [[VREG1:v([0-9]+)]] = [[VREG]] ; CHECK: [[VREG]] = v{{[0-9]+}} From 3bb56fa4789095631074d42dc61e1c1536342f8c Mon Sep 17 00:00:00 2001 From: Amara Emerson Date: Sat, 21 Sep 2019 09:11:51 +0000 Subject: [PATCH 66/71] Revert "[SampleFDO] Expose an interface to return the size of a section or the size" This reverts commit f118852046a1d255ed8c65c6b5db320e8cea53a0. Broke the macOS build/greendragon bots. llvm-svn: 372464 --- llvm/include/llvm/ProfileData/SampleProf.h | 16 ---------- .../llvm/ProfileData/SampleProfReader.h | 7 ----- llvm/lib/ProfileData/SampleProfReader.cpp | 30 ------------------- .../tools/llvm-profdata/show-prof-size.test | 7 ----- llvm/tools/llvm-profdata/llvm-profdata.cpp | 27 ++--------------- 5 files changed, 2 insertions(+), 85 deletions(-) delete mode 100644 llvm/test/tools/llvm-profdata/show-prof-size.test diff --git a/llvm/include/llvm/ProfileData/SampleProf.h b/llvm/include/llvm/ProfileData/SampleProf.h index 9ad740ed804eb..157c79f6772fc 100644 --- a/llvm/include/llvm/ProfileData/SampleProf.h +++ b/llvm/include/llvm/ProfileData/SampleProf.h @@ -125,22 +125,6 @@ enum SecType { SecLBRProfile = SecFuncProfileFirst }; -static inline std::string getSecName(SecType Type) { - switch (Type) { - case SecInValid: - return "InvalidSection"; - case SecProfSummary: - return "ProfileSummarySection"; - case SecNameTable: - return "NameTableSection"; - case SecProfileSymbolList: - return "ProfileSymbolListSection"; - case SecLBRProfile: - return "LBRProfileSection"; - } - llvm_unreachable("A SecType has no name for output"); -} - // Entry type of section header table used by SampleProfileExtBinaryBaseReader // and SampleProfileExtBinaryBaseWriter. struct SecHdrTableEntry { diff --git a/llvm/include/llvm/ProfileData/SampleProfReader.h b/llvm/include/llvm/ProfileData/SampleProfReader.h index 761dbde059569..3d5134d77490d 100644 --- a/llvm/include/llvm/ProfileData/SampleProfReader.h +++ b/llvm/include/llvm/ProfileData/SampleProfReader.h @@ -333,7 +333,6 @@ class SampleProfileReader { /// It includes all the names that have samples either in outline instance /// or inline instance. virtual std::vector *getNameTable() { return nullptr; } - virtual bool dumpSectionInfo(raw_ostream &OS = dbgs()) { return false; }; protected: /// Map every function to its associated profile. @@ -505,12 +504,6 @@ class SampleProfileReaderExtBinaryBase : public SampleProfileReaderBinary { /// Read sample profiles in extensible format from the associated file. std::error_code read() override; - - /// Get the total size of all \p Type sections. - uint64_t getSectionSize(SecType Type); - /// Get the total size of header and all sections. - uint64_t getFileSize(); - virtual bool dumpSectionInfo(raw_ostream &OS = dbgs()) override; }; class SampleProfileReaderExtBinary : public SampleProfileReaderExtBinaryBase { diff --git a/llvm/lib/ProfileData/SampleProfReader.cpp b/llvm/lib/ProfileData/SampleProfReader.cpp index 07272ebac0a9e..f6b33d962616c 100644 --- a/llvm/lib/ProfileData/SampleProfReader.cpp +++ b/llvm/lib/ProfileData/SampleProfReader.cpp @@ -667,36 +667,6 @@ std::error_code SampleProfileReaderExtBinaryBase::readHeader() { return sampleprof_error::success; } -uint64_t SampleProfileReaderExtBinaryBase::getSectionSize(SecType Type) { - for (auto &Entry : SecHdrTable) { - if (Entry.Type == Type) - return Entry.Size; - } - return 0; -} - -uint64_t SampleProfileReaderExtBinaryBase::getFileSize() { - auto &LastEntry = SecHdrTable.back(); - return LastEntry.Offset + LastEntry.Size; -} - -bool SampleProfileReaderExtBinaryBase::dumpSectionInfo(raw_ostream &OS) { - uint64_t TotalSecsSize = 0; - for (auto &Entry : SecHdrTable) { - OS << getSecName(Entry.Type) << " - Offset: " << Entry.Offset - << ", Size: " << Entry.Size << "\n"; - TotalSecsSize += getSectionSize(Entry.Type); - } - uint64_t HeaderSize = SecHdrTable.front().Offset; - assert(HeaderSize + TotalSecsSize == getFileSize() && - "Size of 'header + sections' doesn't match the total size of profile"); - - OS << "Header Size: " << HeaderSize << "\n"; - OS << "Total Sections Size: " << TotalSecsSize << "\n"; - OS << "File Size: " << getFileSize() << "\n"; - return true; -} - std::error_code SampleProfileReaderBinary::readMagicIdent() { // Read and check the magic identifier. auto Magic = readNumber(); diff --git a/llvm/test/tools/llvm-profdata/show-prof-size.test b/llvm/test/tools/llvm-profdata/show-prof-size.test deleted file mode 100644 index 0d1ecdcfd672f..0000000000000 --- a/llvm/test/tools/llvm-profdata/show-prof-size.test +++ /dev/null @@ -1,7 +0,0 @@ -; RUN: llvm-profdata merge -sample -extbinary -prof-sym-list=%S/Inputs/profile-symbol-list-1.text %S/Inputs/sample-profile.proftext -o %t.1.output -; RUN: ls -l %t.1.output |cut -f5 -d ' ' > %t.txt -; RUN: llvm-profdata show -sample -show-sec-info-only %t.1.output >> %t.txt -; RUN: FileCheck %s --input-file=%t.txt -; Check llvm-profdata shows the correct file size. -; CHECK: [[FILESIZE:.*]] -; CHECK: [[FILESIZE]] diff --git a/llvm/tools/llvm-profdata/llvm-profdata.cpp b/llvm/tools/llvm-profdata/llvm-profdata.cpp index 2b1205b950fd4..4f825dfb5b87f 100644 --- a/llvm/tools/llvm-profdata/llvm-profdata.cpp +++ b/llvm/tools/llvm-profdata/llvm-profdata.cpp @@ -982,21 +982,10 @@ static int showInstrProfile(const std::string &Filename, bool ShowCounts, return 0; } -static void showSectionInfo(sampleprof::SampleProfileReader *Reader, - raw_fd_ostream &OS) { - if (!Reader->dumpSectionInfo(OS)) { - WithColor::warning() << "-show-sec-info-only is only supported for " - << "sample profile in extbinary format and is " - << "ignored for other formats.\n"; - return; - } -} - static int showSampleProfile(const std::string &Filename, bool ShowCounts, bool ShowAllFunctions, const std::string &ShowFunction, - bool ShowProfileSymbolList, - bool ShowSectionInfoOnly, raw_fd_ostream &OS) { + bool ShowProfileSymbolList, raw_fd_ostream &OS) { using namespace sampleprof; LLVMContext Context; auto ReaderOrErr = SampleProfileReader::create(Filename, Context); @@ -1004,12 +993,6 @@ static int showSampleProfile(const std::string &Filename, bool ShowCounts, exitWithErrorCode(EC, Filename); auto Reader = std::move(ReaderOrErr.get()); - - if (ShowSectionInfoOnly) { - showSectionInfo(Reader.get(), OS); - return 0; - } - if (std::error_code EC = Reader->read()) exitWithErrorCode(EC, Filename); @@ -1079,11 +1062,6 @@ static int show_main(int argc, const char *argv[]) { cl::opt ShowProfileSymbolList( "show-prof-sym-list", cl::init(false), cl::desc("Show profile symbol list if it exists in the profile. ")); - cl::opt ShowSectionInfoOnly( - "show-sec-info-only", cl::init(false), - cl::desc("Show the information of each section in the sample profile. " - "The flag is only usable when the sample profile is in " - "extbinary format")); cl::ParseCommandLineOptions(argc, argv, "LLVM profile data summary\n"); @@ -1112,8 +1090,7 @@ static int show_main(int argc, const char *argv[]) { OnlyListBelow, ShowFunction, TextFormat, OS); else return showSampleProfile(Filename, ShowCounts, ShowAllFunctions, - ShowFunction, ShowProfileSymbolList, - ShowSectionInfoOnly, OS); + ShowFunction, ShowProfileSymbolList, OS); } int main(int argc, const char *argv[]) { From fae979bc682bdb21a9bdf2e4170ee54afabee5c7 Mon Sep 17 00:00:00 2001 From: Amara Emerson Date: Sat, 21 Sep 2019 09:21:10 +0000 Subject: [PATCH 67/71] [AArch64][GlobalISel] Make <4 x s32> G_ASHR and G_LSHR legal. llvm-svn: 372465 --- .../Target/AArch64/AArch64LegalizerInfo.cpp | 8 +- .../GlobalISel/legalize-vector-shift.mir | 78 +++++++++++++++++++ 2 files changed, 84 insertions(+), 2 deletions(-) create mode 100644 llvm/test/CodeGen/AArch64/GlobalISel/legalize-vector-shift.mir diff --git a/llvm/lib/Target/AArch64/AArch64LegalizerInfo.cpp b/llvm/lib/Target/AArch64/AArch64LegalizerInfo.cpp index 2fd5e0d70a68e..7ff7902f1e020 100644 --- a/llvm/lib/Target/AArch64/AArch64LegalizerInfo.cpp +++ b/llvm/lib/Target/AArch64/AArch64LegalizerInfo.cpp @@ -124,8 +124,12 @@ AArch64LegalizerInfo::AArch64LegalizerInfo(const AArch64Subtarget &ST) { return !SrcTy.isVector() && SrcTy.getSizeInBits() == 32 && AmtTy.getSizeInBits() == 32; }) - .legalFor( - {{s32, s32}, {s32, s64}, {s64, s64}, {v2s32, v2s32}, {v4s32, v4s32}}) + .legalFor({{s32, s32}, + {s32, s64}, + {s64, s64}, + {v2s32, v2s32}, + {v4s32, v4s32}, + {v2s64, v2s64}}) .clampScalar(1, s32, s64) .clampScalar(0, s32, s64) .minScalarSameAs(1, 0); diff --git a/llvm/test/CodeGen/AArch64/GlobalISel/legalize-vector-shift.mir b/llvm/test/CodeGen/AArch64/GlobalISel/legalize-vector-shift.mir new file mode 100644 index 0000000000000..24c551c80fe5e --- /dev/null +++ b/llvm/test/CodeGen/AArch64/GlobalISel/legalize-vector-shift.mir @@ -0,0 +1,78 @@ +# NOTE: Assertions have been autogenerated by utils/update_mir_test_checks.py +# RUN: llc -O0 -march=aarch64 -run-pass=legalizer -global-isel-abort=1 %s -o - | FileCheck %s +--- +name: lshr_v4s32 +body: | + bb.1: + liveins: $q0, $q1 + + ; CHECK-LABEL: name: lshr_v4s32 + ; CHECK: [[COPY:%[0-9]+]]:_(<4 x s32>) = COPY $q0 + ; CHECK: [[COPY1:%[0-9]+]]:_(<4 x s32>) = COPY $q1 + ; CHECK: [[LSHR:%[0-9]+]]:_(<4 x s32>) = G_LSHR [[COPY]], [[COPY1]](<4 x s32>) + ; CHECK: $q0 = COPY [[LSHR]](<4 x s32>) + ; CHECK: RET_ReallyLR implicit $q0 + %0:_(<4 x s32>) = COPY $q0 + %1:_(<4 x s32>) = COPY $q1 + %2:_(<4 x s32>) = G_LSHR %0, %1(<4 x s32>) + $q0 = COPY %2(<4 x s32>) + RET_ReallyLR implicit $q0 + +... +--- +name: lshr_v2s64 +body: | + bb.1: + liveins: $q0, $q1 + + ; CHECK-LABEL: name: lshr_v2s64 + ; CHECK: [[COPY:%[0-9]+]]:_(<2 x s64>) = COPY $q0 + ; CHECK: [[COPY1:%[0-9]+]]:_(<2 x s64>) = COPY $q1 + ; CHECK: [[LSHR:%[0-9]+]]:_(<2 x s64>) = G_LSHR [[COPY]], [[COPY1]](<2 x s64>) + ; CHECK: $q0 = COPY [[LSHR]](<2 x s64>) + ; CHECK: RET_ReallyLR implicit $q0 + %0:_(<2 x s64>) = COPY $q0 + %1:_(<2 x s64>) = COPY $q1 + %2:_(<2 x s64>) = G_LSHR %0, %1(<2 x s64>) + $q0 = COPY %2(<2 x s64>) + RET_ReallyLR implicit $q0 + +... +--- +name: ashr_v4s32 +body: | + bb.1: + liveins: $q0, $q1 + + ; CHECK-LABEL: name: ashr_v4s32 + ; CHECK: [[COPY:%[0-9]+]]:_(<4 x s32>) = COPY $q0 + ; CHECK: [[COPY1:%[0-9]+]]:_(<4 x s32>) = COPY $q1 + ; CHECK: [[ASHR:%[0-9]+]]:_(<4 x s32>) = G_ASHR [[COPY]], [[COPY1]](<4 x s32>) + ; CHECK: $q0 = COPY [[ASHR]](<4 x s32>) + ; CHECK: RET_ReallyLR implicit $q0 + %0:_(<4 x s32>) = COPY $q0 + %1:_(<4 x s32>) = COPY $q1 + %2:_(<4 x s32>) = G_ASHR %0, %1(<4 x s32>) + $q0 = COPY %2(<4 x s32>) + RET_ReallyLR implicit $q0 + +... +--- +name: ashr_v2s64 +body: | + bb.1: + liveins: $q0, $q1 + + ; CHECK-LABEL: name: ashr_v2s64 + ; CHECK: [[COPY:%[0-9]+]]:_(<2 x s64>) = COPY $q0 + ; CHECK: [[COPY1:%[0-9]+]]:_(<2 x s64>) = COPY $q1 + ; CHECK: [[ASHR:%[0-9]+]]:_(<2 x s64>) = G_ASHR [[COPY]], [[COPY1]](<2 x s64>) + ; CHECK: $q0 = COPY [[ASHR]](<2 x s64>) + ; CHECK: RET_ReallyLR implicit $q0 + %0:_(<2 x s64>) = COPY $q0 + %1:_(<2 x s64>) = COPY $q1 + %2:_(<2 x s64>) = G_ASHR %0, %1(<2 x s64>) + $q0 = COPY %2(<2 x s64>) + RET_ReallyLR implicit $q0 + +... From a59a886832bd223127f5c7edf2cf729ba6857fe7 Mon Sep 17 00:00:00 2001 From: Amara Emerson Date: Sat, 21 Sep 2019 09:21:13 +0000 Subject: [PATCH 68/71] [AArch64][GlobalISel] Selection support for G_ASHR of <2 x s64> Just add an extra case to the existing selection logic. llvm-svn: 372466 --- .../AArch64/AArch64InstructionSelector.cpp | 6 +++- .../GlobalISel/select-vector-shift.mir | 30 +++++++++++++++++++ 2 files changed, 35 insertions(+), 1 deletion(-) diff --git a/llvm/lib/Target/AArch64/AArch64InstructionSelector.cpp b/llvm/lib/Target/AArch64/AArch64InstructionSelector.cpp index 8503a0dbb062a..223aa370e976b 100644 --- a/llvm/lib/Target/AArch64/AArch64InstructionSelector.cpp +++ b/llvm/lib/Target/AArch64/AArch64InstructionSelector.cpp @@ -1052,7 +1052,11 @@ bool AArch64InstructionSelector::selectVectorASHR( unsigned Opc = 0; unsigned NegOpc = 0; const TargetRegisterClass *RC = nullptr; - if (Ty == LLT::vector(4, 32)) { + if (Ty == LLT::vector(2, 64)) { + Opc = AArch64::SSHLv2i64; + NegOpc = AArch64::NEGv2i64; + RC = &AArch64::FPR128RegClass; + } else if (Ty == LLT::vector(4, 32)) { Opc = AArch64::SSHLv4i32; NegOpc = AArch64::NEGv4i32; RC = &AArch64::FPR128RegClass; diff --git a/llvm/test/CodeGen/AArch64/GlobalISel/select-vector-shift.mir b/llvm/test/CodeGen/AArch64/GlobalISel/select-vector-shift.mir index 95da841e71d23..b13c4b5ec0d88 100644 --- a/llvm/test/CodeGen/AArch64/GlobalISel/select-vector-shift.mir +++ b/llvm/test/CodeGen/AArch64/GlobalISel/select-vector-shift.mir @@ -118,3 +118,33 @@ body: | RET_ReallyLR implicit $q0 ... +--- +name: ashr_v4i64 +alignment: 4 +legalized: true +regBankSelected: true +tracksRegLiveness: true +registers: + - { id: 0, class: fpr } + - { id: 1, class: fpr } + - { id: 2, class: fpr } +machineFunctionInfo: {} +body: | + bb.1: + liveins: $q0, $q1 + + ; CHECK-LABEL: name: ashr_v4i64 + ; CHECK: liveins: $q0, $q1 + ; CHECK: [[COPY:%[0-9]+]]:fpr128 = COPY $q0 + ; CHECK: [[COPY1:%[0-9]+]]:fpr128 = COPY $q1 + ; CHECK: [[NEGv2i64_:%[0-9]+]]:fpr128 = NEGv2i64 [[COPY1]] + ; CHECK: [[SSHLv2i64_:%[0-9]+]]:fpr128 = SSHLv2i64 [[COPY]], [[NEGv2i64_]] + ; CHECK: $q0 = COPY [[SSHLv2i64_]] + ; CHECK: RET_ReallyLR implicit $q0 + %0:fpr(<2 x s64>) = COPY $q0 + %1:fpr(<2 x s64>) = COPY $q1 + %2:fpr(<2 x s64>) = G_ASHR %0, %1(<2 x s64>) + $q0 = COPY %2(<2 x s64>) + RET_ReallyLR implicit $q0 + +... From 9c7d599dec9c9b028dc56ac65e8154452fc2c77a Mon Sep 17 00:00:00 2001 From: Amara Emerson Date: Sat, 21 Sep 2019 09:21:16 +0000 Subject: [PATCH 69/71] [AArch64][GlobalISel] Implement selection for G_SHL of <2 x i64> Simple continuation of existing selection support. llvm-svn: 372467 --- .../AArch64/AArch64InstructionSelector.cpp | 4 ++- .../GlobalISel/select-vector-shift.mir | 29 +++++++++++++++++++ 2 files changed, 32 insertions(+), 1 deletion(-) diff --git a/llvm/lib/Target/AArch64/AArch64InstructionSelector.cpp b/llvm/lib/Target/AArch64/AArch64InstructionSelector.cpp index 223aa370e976b..961f38cad1e4a 100644 --- a/llvm/lib/Target/AArch64/AArch64InstructionSelector.cpp +++ b/llvm/lib/Target/AArch64/AArch64InstructionSelector.cpp @@ -1018,7 +1018,9 @@ bool AArch64InstructionSelector::selectVectorSHL( return false; unsigned Opc = 0; - if (Ty == LLT::vector(4, 32)) { + if (Ty == LLT::vector(2, 64)) { + Opc = AArch64::USHLv2i64; + } else if (Ty == LLT::vector(4, 32)) { Opc = AArch64::USHLv4i32; } else if (Ty == LLT::vector(2, 32)) { Opc = AArch64::USHLv2i32; diff --git a/llvm/test/CodeGen/AArch64/GlobalISel/select-vector-shift.mir b/llvm/test/CodeGen/AArch64/GlobalISel/select-vector-shift.mir index b13c4b5ec0d88..cf9925a9a8a51 100644 --- a/llvm/test/CodeGen/AArch64/GlobalISel/select-vector-shift.mir +++ b/llvm/test/CodeGen/AArch64/GlobalISel/select-vector-shift.mir @@ -57,6 +57,35 @@ body: | $q0 = COPY %2(<4 x s32>) RET_ReallyLR implicit $q0 +... +--- +name: shl_v2i64 +alignment: 4 +legalized: true +regBankSelected: true +tracksRegLiveness: true +registers: + - { id: 0, class: fpr } + - { id: 1, class: fpr } + - { id: 2, class: fpr } +machineFunctionInfo: {} +body: | + bb.1: + liveins: $q0, $q1 + + ; CHECK-LABEL: name: shl_v2i64 + ; CHECK: liveins: $q0, $q1 + ; CHECK: [[COPY:%[0-9]+]]:fpr128 = COPY $q0 + ; CHECK: [[COPY1:%[0-9]+]]:fpr128 = COPY $q1 + ; CHECK: [[USHLv2i64_:%[0-9]+]]:fpr128 = USHLv2i64 [[COPY]], [[COPY1]] + ; CHECK: $q0 = COPY [[USHLv2i64_]] + ; CHECK: RET_ReallyLR implicit $q0 + %0:fpr(<2 x s64>) = COPY $q0 + %1:fpr(<2 x s64>) = COPY $q1 + %2:fpr(<2 x s64>) = G_SHL %0, %1(<2 x s64>) + $q0 = COPY %2(<2 x s64>) + RET_ReallyLR implicit $q0 + ... --- name: ashr_v2i32 From 854b0f0f0030718af4257bb0a3c7620cf10a035c Mon Sep 17 00:00:00 2001 From: Roman Lebedev Date: Sat, 21 Sep 2019 11:12:55 +0000 Subject: [PATCH 70/71] [NFC][X86] Adjust check prefixes in bmi.ll (PR43381) llvm-svn: 372468 --- llvm/test/CodeGen/X86/bmi.ll | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/llvm/test/CodeGen/X86/bmi.ll b/llvm/test/CodeGen/X86/bmi.ll index d5603431e756c..9c3a74fccbe63 100644 --- a/llvm/test/CodeGen/X86/bmi.ll +++ b/llvm/test/CodeGen/X86/bmi.ll @@ -1,8 +1,8 @@ ; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py ; RUN: llc < %s -mtriple=i686-unknown-unknown -mattr=+cmov,+bmi | FileCheck %s --check-prefixes=CHECK,X86,X86-SLOW-BEXTR -; RUN: llc < %s -mtriple=i686-unknown-unknown -mattr=+cmov,+bmi,+bmi2 | FileCheck %s --check-prefixes=CHECK,X86,X86-SLOW-BEXTR +; RUN: llc < %s -mtriple=i686-unknown-unknown -mattr=+cmov,+bmi,+bmi2 | FileCheck %s --check-prefixes=CHECK,X86,X86-SLOW-BEXTR,X86-SLOW-BEXTR-BMI2 ; RUN: llc < %s -mtriple=x86_64-unknown-unknown -mattr=+bmi | FileCheck %s --check-prefixes=CHECK,X64,X64-SLOW-BEXTR -; RUN: llc < %s -mtriple=x86_64-unknown-unknown -mattr=+bmi,+bmi2 | FileCheck %s --check-prefixes=CHECK,X64,X64-SLOW-BEXTR +; RUN: llc < %s -mtriple=x86_64-unknown-unknown -mattr=+bmi,+bmi2 | FileCheck %s --check-prefixes=CHECK,X64,X64-SLOW-BEXTR,X64-SLOW-BEXTR-BMI2 ; RUN: llc < %s -mtriple=i686-unknown-unknown -mattr=+cmov,+bmi,+fast-bextr | FileCheck %s --check-prefixes=CHECK,X86,X86-FAST-BEXTR ; RUN: llc < %s -mtriple=x86_64-unknown-unknown -mattr=+bmi,+fast-bextr | FileCheck %s --check-prefixes=CHECK,X64,X64-FAST-BEXTR From fa1a34c83a8125e4b7b6675b97b4e2a5bdd92461 Mon Sep 17 00:00:00 2001 From: xyb Date: Sat, 21 Sep 2019 20:59:21 -0700 Subject: [PATCH 71/71] Update README.md. Add changes made in XYB port. --- README.md | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/README.md b/README.md index de0891a7044a9..809b44f2cb468 100644 --- a/README.md +++ b/README.md @@ -3,3 +3,17 @@ This directory and its subdirectories contain source code for LLVM, a toolkit for the construction of highly optimized compilers, optimizers, and runtime environments. + +## XYB Port + +I made the following changes based on the latest LLVM master: + +- [Add option "--driver-mode" to config driver mode used by clang-tidy.](https://github.com/xieyubo/llvm-project/commit/a7533c8c292c8e8c311310e5254735dbc1ae469e) +- [Add an option "IgnoreStdFunctionArguments" to bugprone-argument-comment.](https://github.com/xieyubo/llvm-project/commit/0ef5db32846661cf7fab284582f7342ebacbc82f) + +Some changes have been merged back to LLVM master already: + +- [Fix bugprone-argument-comment bug if there are marcos.](https://github.com/xieyubo/llvm-project/commit/b882946b522ee3b1f3fb0be5554d04385505226f). +- [Fix bugprone-argument-comment bug: negative literal number is not checked.](https://github.com/xieyubo/llvm-project/commit/b458819012215a9a33f67631f51f19fba1170130). +- [Add bugprone-argument-comment option: IgnoreSingleArgument.](https://github.com/xieyubo/llvm-project/commit/1aa31a81d30f918b27ecd1198c658337f812bc1f). +- [Fix relative path in header-filter of clang-tidy.](https://github.com/xieyubo/llvm-project/commit/814910e71adf2e6e28ef6222c1b38fc916d6ba44) \ No newline at end of file