From c7923e7705d0dad0bf2babd619ae211bebc2c5fa Mon Sep 17 00:00:00 2001 From: Simon Atanasyan Date: Thu, 21 May 2020 16:14:24 +0300 Subject: [PATCH 01/14] [mips] Reorganize check directives in the test. NFC --- llvm/test/DebugInfo/Mips/eh_frame.ll | 41 ++++++++++++++++++---------- 1 file changed, 27 insertions(+), 14 deletions(-) diff --git a/llvm/test/DebugInfo/Mips/eh_frame.ll b/llvm/test/DebugInfo/Mips/eh_frame.ll index 67d59837aa220d..a71ae61f3e6320 100644 --- a/llvm/test/DebugInfo/Mips/eh_frame.ll +++ b/llvm/test/DebugInfo/Mips/eh_frame.ll @@ -1,22 +1,35 @@ -; RUN: llc -mtriple mips-unknown-linux-gnu -mattr=+micromips -relocation-model=static -O3 -filetype=obj -o - %s | \ -; RUN: llvm-readelf -r | FileCheck %s --check-prefixes=CHECK-READELF,CHECK-READELF-STATIC -; RUN: llc -mtriple mips-unknown-linux-gnu -mattr=+micromips -relocation-model=pic -O3 -filetype=obj -o - %s | \ -; RUN: llvm-readelf -r | FileCheck %s --check-prefixes=CHECK-READELF,CHECK-READELF-PIC -; RUN: llc -mtriple mips-unknown-linux-gnu -mattr=+micromips -relocation-model=static -O3 -filetype=obj -o - %s | \ -; RUN: llvm-objdump -s -j .gcc_except_table - | FileCheck %s --check-prefix=CHECK-EXCEPT-TABLE-STATIC -; RUN: llc -mtriple mips-unknown-linux-gnu -mattr=+micromips -relocation-model=pic -O3 -filetype=obj -o - %s | \ -; RUN: llvm-objdump -s -j .gcc_except_table - | FileCheck %s --check-prefix=CHECK-EXCEPT-TABLE-PIC - -; CHECK-READELF: .rel.eh_frame +; RUN: llc -mtriple mips-unknown-linux-gnu -mattr=+micromips \ +; RUN: -relocation-model=static -O3 -filetype=obj -o - %s | \ +; RUN: llvm-readelf -r | FileCheck %s --check-prefixes=STATIC +; RUN: llc -mtriple mips-unknown-linux-gnu -mattr=+micromips \ +; RUN: -relocation-model=pic -O3 -filetype=obj -o - %s | \ +; RUN: llvm-readelf -r | FileCheck %s --check-prefixes=PIC +; RUN: llc -mtriple mips-unknown-linux-gnu -mattr=+micromips \ +; RUN: -relocation-model=static -O3 -filetype=obj -o - %s | \ +; RUN: llvm-objdump -s -j .gcc_except_table - | FileCheck %s --check-prefix=EXCEPT-TABLE-STATIC +; RUN: llc -mtriple mips-unknown-linux-gnu -mattr=+micromips \ +; RUN: -relocation-model=pic -O3 -filetype=obj -o - %s | \ +; RUN: llvm-objdump -s -j .gcc_except_table - | FileCheck %s --check-prefix=EXCEPT-TABLE-PIC + +; STATIC-LABEL: Relocation section '.rel.eh_frame' +; STATIC-DAG: R_MIPS_32 00000000 DW.ref.__gxx_personality_v0 +; STATIC-DAG: R_MIPS_32 00000000 .text +; STATIC-DAG: R_MIPS_32 00000000 .gcc_except_table + +; PIC-LABEL: Relocation section '.rel.eh_frame' +; PIC-DAG: R_MIPS_32 00000000 DW.ref.__gxx_personality_v0 +; PIC-DAG: R_MIPS_PC32 +; PIC-DAG: R_MIPS_32 00000000 .gcc_except_table + ; CHECK-READELF: DW.ref.__gxx_personality_v0 ; CHECK-READELF-STATIC-NEXT: R_MIPS_32 00000000 .text ; CHECK-READELF-PIC-NEXT: R_MIPS_PC32 ; CHECK-READELF-NEXT: .gcc_except_table -; CHECK-EXCEPT-TABLE-STATIC: 0000 ff9b1501 0c011500 00150e23 01231e00 ...........#.#.. -; CHECK-EXCEPT-TABLE-STATIC: 0010 00010000 00000000 -; CHECK-EXCEPT-TABLE-PIC: 0000 ff9b1501 0c012d00 002d133f 013f2a00 ......-..-.?.?*. -; CHECK-EXCEPT-TABLE-PIC: 0010 00010000 00000000 ........ +; EXCEPT-TABLE-STATIC: 0000 ff9b1501 0c011500 00150e23 01231e00 ...........#.#.. +; EXCEPT-TABLE-STATIC: 0010 00010000 00000000 +; EXCEPT-TABLE-PIC: 0000 ff9b1501 0c012d00 002d133f 013f2a00 ......-..-.?.?*. +; EXCEPT-TABLE-PIC: 0010 00010000 00000000 ........ @_ZTIi = external constant i8* From 92fd3971e0db1d9faf2dbbcceb2b79b3192fd79d Mon Sep 17 00:00:00 2001 From: Jonas Devlieghere Date: Thu, 21 May 2020 10:57:53 -0700 Subject: [PATCH 02/14] [dsymutil] Add reproducers to dsymutil Add support for generating a dsymutil reproducer. The result is a folder containing all the object files for linking. When --gen-reproducer is passed, dsymutil uses a FileCollectorFileSystem which keeps track of all the files used by dsymutil. These files are copied into a temporary directory when dsymutil exists. When this path is passed to --use-reproducer, dsymutil uses a RedirectingFileSystem that will use the files from the reproducer directory instead of the actual paths. This means you don't need to mess with the OSO path prefix. Differential revision: https://reviews.llvm.org/D79398 --- llvm/docs/CommandGuide/dsymutil.rst | 8 ++ llvm/test/tools/dsymutil/X86/reproducer.test | 76 ++++++++++++++++++ llvm/test/tools/dsymutil/cmdline.test | 2 + llvm/tools/dsymutil/CMakeLists.txt | 1 + llvm/tools/dsymutil/Options.td | 10 +++ llvm/tools/dsymutil/Reproducer.cpp | 82 ++++++++++++++++++++ llvm/tools/dsymutil/Reproducer.h | 77 ++++++++++++++++++ llvm/tools/dsymutil/dsymutil.cpp | 27 +++++++ 8 files changed, 283 insertions(+) create mode 100644 llvm/test/tools/dsymutil/X86/reproducer.test create mode 100644 llvm/tools/dsymutil/Reproducer.cpp create mode 100644 llvm/tools/dsymutil/Reproducer.h diff --git a/llvm/docs/CommandGuide/dsymutil.rst b/llvm/docs/CommandGuide/dsymutil.rst index 5b7016ced2f564..78954fcc8d8766 100644 --- a/llvm/docs/CommandGuide/dsymutil.rst +++ b/llvm/docs/CommandGuide/dsymutil.rst @@ -42,6 +42,10 @@ OPTIONS Produce a flat dSYM file. A ``.dwarf`` extension will be appended to the executable name unless the output file is specified using the ``-o`` option. +.. option:: --gen-reproducer + + Generate a reproducer consisting of the input object files. + .. option:: --help, -h Print this help output. @@ -131,6 +135,10 @@ OPTIONS other DWARF optimizations. This option will rebuild the '.apple_names' and '.apple_types' hashed accelerator tables. +.. option:: --use-reproducer + + Use the object files from the given reproducer path. + .. option:: --verbose Display verbose information when linking. diff --git a/llvm/test/tools/dsymutil/X86/reproducer.test b/llvm/test/tools/dsymutil/X86/reproducer.test new file mode 100644 index 00000000000000..02d73b91e399f9 --- /dev/null +++ b/llvm/test/tools/dsymutil/X86/reproducer.test @@ -0,0 +1,76 @@ +# Recreate the folder structure in a temp directory we can remove later. +RUN: rm -rf %t +RUN: mkdir -p %t/Inputs +RUN: cp %p/../Inputs/basic.macho.x86_64 %t/Inputs +RUN: cp %p/../Inputs/basic1.macho.x86_64.o %t/Inputs +RUN: cp %p/../Inputs/basic2.macho.x86_64.o %t/Inputs +RUN: cp %p/../Inputs/basic3.macho.x86_64.o %t/Inputs + +# Sanity check all the files are present. +RUN: dsymutil -f -o - -oso-prepend-path=%t %t/Inputs/basic.macho.x86_64 | llvm-dwarfdump -a - | FileCheck %s + +# Create a reproducer. +RUN: env DSYMUTIL_REPRODUCER_PATH=%t.repro dsymutil -gen-reproducer -f -o %t.generate -oso-prepend-path=%t %t/Inputs/basic.macho.x86_64 | FileCheck %s --check-prefixes=REPRODUCER +RUN: llvm-dwarfdump -a %t.generate | FileCheck %s + +# Remove the input files and sanity check that was successful. +RUN: rm -rf %t +RUN: not dsymutil -f -o %t.error -oso-prepend-path=%t %t/Inputs/basic.macho.x86_64 2>&1 | FileCheck %s --check-prefix=ERROR + +# Use the reproducer. +RUN: dsymutil -use-reproducer %t.repro -f -o - -oso-prepend-path=%t %t/Inputs/basic.macho.x86_64 | llvm-dwarfdump -a - | FileCheck %s + +# Conflicting options. +RUN: not dsymutil -gen-reproducer -use-reproducer %t.repro -f -o %t.error -oso-prepend-path=%t %t/Inputs/basic.macho.x86_64 2>&1 | FileCheck %s --check-prefix=CONFLICT + +CHECK: .debug_info +CHECK: DW_TAG_compile_unit +CHECK-NEXT: DW_AT_producer ("Apple LLVM version 6.0 (clang-600.0.39) (based on LLVM 3.5svn)") +CHECK-NEXT: DW_AT_language (DW_LANG_C99) +CHECK-NEXT: DW_AT_name ("basic1.c") +CHECK-NEXT: DW_AT_stmt_list (0x00000000) +CHECK-NEXT: DW_AT_comp_dir ("/Inputs") +CHECK-NEXT: DW_AT_low_pc (0x0000000100000ea0) +CHECK: DW_TAG_subprogram +CHECK-NEXT: DW_AT_name ("main") +CHECK-NEXT: DW_AT_decl_file ("/Inputs{{[/\\]}}basic1.c") +CHECK-NEXT: DW_AT_decl_line (23) +CHECK-NEXT: DW_AT_prototyped (0x01) +CHECK-NEXT: DW_AT_type (0x00000063 +CHECK-NEXT: DW_AT_external (0x01) +CHECK-NEXT: DW_AT_accessibility (DW_ACCESS_public) +CHECK-NEXT: DW_AT_low_pc (0x0000000100000ea0) +CHECK-NEXT: DW_AT_high_pc (0x0000000100000ec4) +CHECK-NEXT: DW_AT_frame_base (DW_OP_reg6 RBP) +CHECK: DW_TAG_formal_parameter +CHECK-NEXT: DW_AT_name ("argc") +CHECK-NEXT: DW_AT_decl_file ("/Inputs{{[/\\]}}basic1.c") +CHECK-NEXT: DW_AT_decl_line (23) +CHECK-NEXT: DW_AT_type (0x00000063 +CHECK-NEXT: DW_AT_location (DW_OP_fbreg -8) +CHECK: DW_TAG_formal_parameter +CHECK-NEXT: DW_AT_name ("argv") +CHECK-NEXT: DW_AT_decl_file ("/Inputs{{[/\\]}}basic1.c") +CHECK-NEXT: DW_AT_decl_line (23) +CHECK-NEXT: DW_AT_type (0x0000006a +CHECK-NEXT: DW_AT_location (DW_OP_fbreg -16) +CHECK: NULL +CHECK: DW_TAG_base_type +CHECK-NEXT: DW_AT_name ("int") +CHECK-NEXT: DW_AT_encoding (DW_ATE_signed) +CHECK-NEXT: DW_AT_byte_size (0x04) +CHECK: DW_TAG_pointer_type +CHECK-NEXT: DW_AT_type (0x0000006f +CHECK: DW_TAG_pointer_type +CHECK-NEXT: DW_AT_type (0x00000074 +CHECK: DW_TAG_const_type +CHECK-NEXT: DW_AT_type (0x00000079 +CHECK: DW_TAG_base_type +CHECK-NEXT: DW_AT_name ("char") +CHECK-NEXT: DW_AT_encoding (DW_ATE_signed_char) +CHECK-NEXT: DW_AT_byte_size (0x01) +CHECK: NULL + +REPRODUCER: reproducer written +ERROR: error: cannot parse the debug map +CONFLICT: cannot combine --gen-reproducer and --use-reproducer diff --git a/llvm/test/tools/dsymutil/cmdline.test b/llvm/test/tools/dsymutil/cmdline.test index 29f6e70f01306d..e3f8bbdf7503a6 100644 --- a/llvm/test/tools/dsymutil/cmdline.test +++ b/llvm/test/tools/dsymutil/cmdline.test @@ -9,6 +9,7 @@ CHECK: -accelerator CHECK: -arch CHECK: -dump-debug-map CHECK: -flat +CHECK: -gen-reproducer CHECK: -help CHECK: -minimize CHECK: -no-odr @@ -28,6 +29,7 @@ CHECK: -symtab CHECK: {{-S}} CHECK: -toolchain CHECK: -update +CHECK: -use-reproducer CHECK: -verbose CHECK: -verify CHECK: {{-y}} diff --git a/llvm/tools/dsymutil/CMakeLists.txt b/llvm/tools/dsymutil/CMakeLists.txt index a42e1a98080a26..1efc58d19e92c2 100644 --- a/llvm/tools/dsymutil/CMakeLists.txt +++ b/llvm/tools/dsymutil/CMakeLists.txt @@ -26,6 +26,7 @@ add_llvm_tool(dsymutil DwarfLinkerForBinary.cpp MachODebugMapParser.cpp MachOUtils.cpp + Reproducer.cpp SymbolMap.cpp DEPENDS diff --git a/llvm/tools/dsymutil/Options.td b/llvm/tools/dsymutil/Options.td index bdd11b5c4c1e24..7bd21b0d434624 100644 --- a/llvm/tools/dsymutil/Options.td +++ b/llvm/tools/dsymutil/Options.td @@ -164,6 +164,16 @@ def: Separate<["-"], "j">, HelpText<"Alias for --num-threads">, Group; +def gen_reproducer: F<"gen-reproducer">, + HelpText<"Generate a reproducer consisting of the input object files.">, + Group; + +def use_reproducer: Separate<["--", "-"], "use-reproducer">, + MetaVarName<"">, + HelpText<"Use the object files from the given reproducer path.">, + Group; +def: Joined<["--", "-"], "use-reproducer=">, Alias; + def remarks_prepend_path: Separate<["--", "-"], "remarks-prepend-path">, MetaVarName<"">, HelpText<"Specify a directory to prepend to the paths of the external remark files.">, diff --git a/llvm/tools/dsymutil/Reproducer.cpp b/llvm/tools/dsymutil/Reproducer.cpp new file mode 100644 index 00000000000000..baa6bc6f11e0f4 --- /dev/null +++ b/llvm/tools/dsymutil/Reproducer.cpp @@ -0,0 +1,82 @@ +//===- Reproducer.cpp -----------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "llvm/Support/Path.h" +#include + +using namespace llvm; +using namespace llvm::dsymutil; + +static std::string createReproducerDir(std::error_code &EC) { + SmallString<128> Root; + if (const char *Path = getenv("DSYMUTIL_REPRODUCER_PATH")) { + Root.assign(Path); + EC = sys::fs::create_directory(Root); + } else { + EC = sys::fs::createUniqueDirectory("dsymutil", Root); + } + return EC ? "" : std::string(Root); +} + +Reproducer::Reproducer() : VFS(vfs::getRealFileSystem()) {} +Reproducer::~Reproducer() = default; + +ReproducerGenerate::ReproducerGenerate(std::error_code &EC) + : Root(createReproducerDir(EC)), FC() { + if (!Root.empty()) + FC = std::make_shared(Root, Root); + VFS = FileCollector::createCollectorVFS(vfs::getRealFileSystem(), FC); +} + +ReproducerGenerate::~ReproducerGenerate() { + if (!FC) + return; + FC->copyFiles(false); + SmallString<128> Mapping(Root); + sys::path::append(Mapping, "mapping.yaml"); + FC->writeMapping(Mapping.str()); + outs() << "reproducer written to " << Root << '\n'; +} + +ReproducerUse::~ReproducerUse() = default; + +ReproducerUse::ReproducerUse(StringRef Root, std::error_code &EC) { + SmallString<128> Mapping(Root); + sys::path::append(Mapping, "mapping.yaml"); + ErrorOr> Buffer = + vfs::getRealFileSystem()->getBufferForFile(Mapping.str()); + + if (!Buffer) { + EC = Buffer.getError(); + return; + } + + VFS = llvm::vfs::getVFSFromYAML(std::move(Buffer.get()), nullptr, Mapping); +} + +llvm::Expected> +Reproducer::createReproducer(ReproducerMode Mode, StringRef Root) { + switch (Mode) { + case ReproducerMode::Generate: { + std::error_code EC; + auto Repro = std::make_unique(EC); + if (EC) + return errorCodeToError(EC); + return Repro; + } + case ReproducerMode::Use: { + std::error_code EC; + auto Repro = std::make_unique(Root, EC); + if (EC) + return errorCodeToError(EC); + return Repro; + } + case ReproducerMode::Off: + return std::make_unique(); + } +} diff --git a/llvm/tools/dsymutil/Reproducer.h b/llvm/tools/dsymutil/Reproducer.h new file mode 100644 index 00000000000000..e965e1ceda249f --- /dev/null +++ b/llvm/tools/dsymutil/Reproducer.h @@ -0,0 +1,77 @@ +//===- tools/dsymutil/Reproducer.h ------------------------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_TOOLS_DSYMUTIL_REPRODUCER_H +#define LLVM_TOOLS_DSYMUTIL_REPRODUCER_H + +#include "llvm/Support/Error.h" +#include "llvm/Support/FileCollector.h" +#include "llvm/Support/VirtualFileSystem.h" + +namespace llvm { +namespace dsymutil { + +/// The reproducer mode. +enum class ReproducerMode { + Generate, + Use, + Off, +}; + +/// The reproducer class manages the sate related to reproducers in dsymutil. +/// Instances should be created with Reproducer::createReproducer. An instance +/// of this class is returned when reproducers are off. The VFS returned by +/// this instance is the real file system. +class Reproducer { +public: + Reproducer(); + virtual ~Reproducer(); + + IntrusiveRefCntPtr getVFS() const { return VFS; } + + /// Create a Reproducer instance based on the given mode. + static llvm::Expected> + createReproducer(ReproducerMode Mode, StringRef Root); + +protected: + IntrusiveRefCntPtr VFS; +}; + +/// Reproducer instance used to generate a new reproducer. The VFS returned by +/// this instance is a FileCollectorFileSystem that tracks every file used by +/// dsymutil. +class ReproducerGenerate : public Reproducer { +public: + ReproducerGenerate(std::error_code &EC); + ~ReproducerGenerate() override; + +private: + /// The path to the reproducer. + std::string Root; + + /// The FileCollector used by the FileCollectorFileSystem. + std::shared_ptr FC; +}; + +/// Reproducer instance used to use an existing reproducer. The VFS returned by +/// this instance is a RedirectingFileSystem that remaps paths to their +/// counterpart in the reproducer. +class ReproducerUse : public Reproducer { +public: + ReproducerUse(StringRef Root, std::error_code &EC); + ~ReproducerUse() override; + +private: + /// The path to the reproducer. + std::string Root; +}; + +} // end namespace dsymutil +} // end namespace llvm + +#endif // LLVM_TOOLS_DSYMUTIL_REPRODUCER_H diff --git a/llvm/tools/dsymutil/dsymutil.cpp b/llvm/tools/dsymutil/dsymutil.cpp index 8ea89933e362a9..32df55611f070d 100644 --- a/llvm/tools/dsymutil/dsymutil.cpp +++ b/llvm/tools/dsymutil/dsymutil.cpp @@ -16,6 +16,7 @@ #include "DebugMap.h" #include "LinkUtils.h" #include "MachOUtils.h" +#include "Reproducer.h" #include "llvm/ADT/SmallString.h" #include "llvm/ADT/SmallVector.h" #include "llvm/ADT/StringExtras.h" @@ -31,6 +32,7 @@ #include "llvm/Option/ArgList.h" #include "llvm/Option/Option.h" #include "llvm/Support/CommandLine.h" +#include "llvm/Support/FileCollector.h" #include "llvm/Support/FileSystem.h" #include "llvm/Support/InitLLVM.h" #include "llvm/Support/ManagedStatic.h" @@ -92,9 +94,11 @@ struct DsymutilOptions { std::string SymbolMap; std::string OutputFile; std::string Toolchain; + std::string ReproducerPath; std::vector Archs; std::vector InputFiles; unsigned NumThreads; + ReproducerMode ReproMode = ReproducerMode::Off; dsymutil::LinkOptions LinkOpts; }; @@ -182,6 +186,12 @@ static Error verifyOptions(const DsymutilOptions &Options) { "paper trail warnings are not supported for YAML input.", errc::invalid_argument); + if (!Options.ReproducerPath.empty() && + Options.ReproMode != ReproducerMode::Use) + return make_error( + "cannot combine --gen-reproducer and --use-reproducer.", + errc::invalid_argument); + return Error::success(); } @@ -222,6 +232,14 @@ static Expected getOptions(opt::InputArgList &Args) { Options.LinkOpts.Verbose = Args.hasArg(OPT_verbose); Options.LinkOpts.Statistics = Args.hasArg(OPT_statistics); + if (opt::Arg *ReproducerPath = Args.getLastArg(OPT_use_reproducer)) { + Options.ReproMode = ReproducerMode::Use; + Options.ReproducerPath = ReproducerPath->getValue(); + } + + if (Args.hasArg(OPT_gen_reproducer)) + Options.ReproMode = ReproducerMode::Generate; + if (Expected AccelKind = getAccelTableKind(Args)) { Options.LinkOpts.TheAccelTableKind = *AccelKind; } else { @@ -499,6 +517,15 @@ int main(int argc, char **argv) { InitializeAllTargets(); InitializeAllAsmPrinters(); + auto Repro = + Reproducer::createReproducer(Options.ReproMode, Options.ReproducerPath); + if (!Repro) { + WithColor::error() << toString(Repro.takeError()); + return 1; + } + + Options.LinkOpts.VFS = (*Repro)->getVFS(); + for (const auto &Arch : Options.Archs) if (Arch != "*" && Arch != "all" && !object::MachOObjectFile::isValidArch(Arch)) { From d395eacca579858972fd4f79f4c9637db7666392 Mon Sep 17 00:00:00 2001 From: Jonas Devlieghere Date: Thu, 21 May 2020 11:19:57 -0700 Subject: [PATCH 03/14] [dsymutil] Fix include-style --- llvm/tools/dsymutil/Reproducer.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/llvm/tools/dsymutil/Reproducer.cpp b/llvm/tools/dsymutil/Reproducer.cpp index baa6bc6f11e0f4..53e4bda375df0b 100644 --- a/llvm/tools/dsymutil/Reproducer.cpp +++ b/llvm/tools/dsymutil/Reproducer.cpp @@ -7,7 +7,7 @@ //===----------------------------------------------------------------------===// #include "llvm/Support/Path.h" -#include +#include "Reproducer.h" using namespace llvm; using namespace llvm::dsymutil; From abf4957204f55f435a5655260be13982a224fc3b Mon Sep 17 00:00:00 2001 From: LLVM GN Syncbot Date: Thu, 21 May 2020 18:20:26 +0000 Subject: [PATCH 04/14] [gn build] Port 92fd3971e0d --- llvm/utils/gn/secondary/llvm/tools/dsymutil/BUILD.gn | 1 + 1 file changed, 1 insertion(+) diff --git a/llvm/utils/gn/secondary/llvm/tools/dsymutil/BUILD.gn b/llvm/utils/gn/secondary/llvm/tools/dsymutil/BUILD.gn index c988aeb394f350..19d24e5092045a 100644 --- a/llvm/utils/gn/secondary/llvm/tools/dsymutil/BUILD.gn +++ b/llvm/utils/gn/secondary/llvm/tools/dsymutil/BUILD.gn @@ -25,6 +25,7 @@ executable("dsymutil") { "DwarfLinkerForBinary.cpp", "MachODebugMapParser.cpp", "MachOUtils.cpp", + "Reproducer.cpp", "SymbolMap.cpp", "dsymutil.cpp", ] From d851fce4cb238d5fe85ce71002721dfc2330fa46 Mon Sep 17 00:00:00 2001 From: Thomas Lively Date: Thu, 21 May 2020 11:33:25 -0700 Subject: [PATCH 05/14] [lld][WebAssembly] Do not emit initialization for .bss segments Summary: This patch fixes a bug where initialization code for .bss segments was emitted in the memory initialization function even though the .bss segments were discounted in the datacount section and omitted in the data section. This was producing invalid binaries due to out-of-bounds segment indices on the memory.init and data.drop instructions that were trying to operate on the nonexistent .bss segments. Reviewers: sbc100 Subscribers: dschuff, jgravelle-google, aheejin, sunfish, llvm-commits Tags: #llvm Differential Revision: https://reviews.llvm.org/D80354 --- lld/test/wasm/data-segments.ll | 5 ++++- lld/wasm/SyntheticSections.cpp | 2 +- lld/wasm/SyntheticSections.h | 8 ++++---- lld/wasm/Writer.cpp | 23 +++++++++++++++++++---- 4 files changed, 28 insertions(+), 10 deletions(-) diff --git a/lld/test/wasm/data-segments.ll b/lld/test/wasm/data-segments.ll index 7c5af8f743058f..eb419ba07f30a5 100644 --- a/lld/test/wasm/data-segments.ll +++ b/lld/test/wasm/data-segments.ll @@ -52,6 +52,8 @@ target triple = "wasm32-unknown-unknown" ; PASSIVE-LABEL: - Type: START ; PASSIVE-NEXT: StartFunction: 1 +; PASSIVE-LABEL: - Type: DATACOUNT +; PASSIVE-NEXT: Count: 2 ; PASSIVE-LABEL: - Type: CODE ; PASSIVE-NEXT: Functions: ; PASSIVE-NEXT: - Index: 0 @@ -59,7 +61,8 @@ target triple = "wasm32-unknown-unknown" ; PASSIVE-NEXT: Body: 0B ; PASSIVE-NEXT: - Index: 1 ; PASSIVE-NEXT: Locals: [] -; PASSIVE-NEXT: Body: 41B4D60041004101FE480200044041B4D6004101427FFE0102001A054180084100410DFC08000041900841004114FC08010041A40841004190CE00FC08020041B4D6004102FE17020041B4D600417FFE0002001A0BFC0900FC0901FC09020B +; PASSIVE-NEXT: Body: 41B4D60041004101FE480200044041B4D6004101427FFE0102001A054180084100410DFC08000041900841004114FC08010041B4D6004102FE17020041B4D600417FFE0002001A0BFC0900FC09010B + ; PASSIVE-NEXT: - Index: 2 ; PASSIVE-NEXT: Locals: [] ; PASSIVE-NEXT: Body: 0B diff --git a/lld/wasm/SyntheticSections.cpp b/lld/wasm/SyntheticSections.cpp index 87e4251bffd4a7..4e974c8e4c9d94 100644 --- a/lld/wasm/SyntheticSections.cpp +++ b/lld/wasm/SyntheticSections.cpp @@ -326,7 +326,7 @@ void ExportSection::writeBody() { } bool StartSection::isNeeded() const { - return !config->relocatable && numSegments && config->sharedMemory; + return !config->relocatable && hasInitializedSegments && config->sharedMemory; } void StartSection::writeBody() { diff --git a/lld/wasm/SyntheticSections.h b/lld/wasm/SyntheticSections.h index ceb6d604da8770..6cf593cf016cea 100644 --- a/lld/wasm/SyntheticSections.h +++ b/lld/wasm/SyntheticSections.h @@ -225,14 +225,14 @@ class ExportSection : public SyntheticSection { class StartSection : public SyntheticSection { public: - StartSection(uint32_t numSegments) - : SyntheticSection(llvm::wasm::WASM_SEC_START), numSegments(numSegments) { - } + StartSection(bool hasInitializedSegments) + : SyntheticSection(llvm::wasm::WASM_SEC_START), + hasInitializedSegments(hasInitializedSegments) {} bool isNeeded() const override; void writeBody() override; protected: - uint32_t numSegments; + bool hasInitializedSegments; }; class ElemSection : public SyntheticSection { diff --git a/lld/wasm/Writer.cpp b/lld/wasm/Writer.cpp index a1b5a463a530de..4947c358146765 100644 --- a/lld/wasm/Writer.cpp +++ b/lld/wasm/Writer.cpp @@ -54,6 +54,9 @@ class Writer { private: void openFile(); + bool needsPassiveInitialization(const OutputSegment *segment); + bool hasPassiveInitializedSegments(); + void createInitMemoryFunction(); void createApplyRelocationsFunction(); void createCallCtorsFunction(); @@ -729,6 +732,18 @@ static void createFunction(DefinedFunction *func, StringRef bodyContent) { cast(func->function)->setBody(body); } +bool Writer::needsPassiveInitialization(const OutputSegment *segment) { + return segment->initFlags & WASM_SEGMENT_IS_PASSIVE && + segment->name != ".tdata" && !segment->isBss; +} + +bool Writer::hasPassiveInitializedSegments() { + return std::find_if(segments.begin(), segments.end(), + [this](const OutputSegment *s) { + return this->needsPassiveInitialization(s); + }) != segments.end(); +} + void Writer::createInitMemoryFunction() { LLVM_DEBUG(dbgs() << "createInitMemoryFunction\n"); assert(WasmSym::initMemoryFlag); @@ -738,7 +753,7 @@ void Writer::createInitMemoryFunction() { raw_string_ostream os(bodyContent); writeUleb128(os, 0, "num locals"); - if (segments.size()) { + if (hasPassiveInitializedSegments()) { // Initialize memory in a thread-safe manner. The thread that successfully // increments the flag from 0 to 1 is is responsible for performing the // memory initialization. Other threads go sleep on the flag until the @@ -804,7 +819,7 @@ void Writer::createInitMemoryFunction() { // Did increment 0, so conditionally initialize passive data segments for (const OutputSegment *s : segments) { - if (s->initFlags & WASM_SEGMENT_IS_PASSIVE && s->name != ".tdata") { + if (needsPassiveInitialization(s)) { // destination address writeI32Const(os, s->startVA, "destination address"); // source segment offset @@ -838,7 +853,7 @@ void Writer::createInitMemoryFunction() { // Unconditionally drop passive data segments for (const OutputSegment *s : segments) { - if (s->initFlags & WASM_SEGMENT_IS_PASSIVE && s->name != ".tdata") { + if (needsPassiveInitialization(s)) { // data.drop instruction writeU8(os, WASM_OPCODE_MISC_PREFIX, "bulk-memory prefix"); writeUleb128(os, WASM_OPCODE_DATA_DROP, "data.drop"); @@ -983,7 +998,7 @@ void Writer::createSyntheticSections() { out.eventSec = make(); out.globalSec = make(); out.exportSec = make(); - out.startSec = make(segments.size()); + out.startSec = make(hasPassiveInitializedSegments()); out.elemSec = make(); out.dataCountSec = make(segments); out.linkingSec = make(initFunctions, segments); From 01909b4e850846bb4cf5226072ccc608c68c9466 Mon Sep 17 00:00:00 2001 From: Hiroshi Yamauchi Date: Wed, 13 May 2020 12:14:33 -0700 Subject: [PATCH 06/14] [IR] Make Module::setProfileSummary to replace an existing ProfileSummary flag. Summary: Module::setProfileSummary currently calls addModuelFlag. This prevents from updating the ProfileSummary metadata in the module and results in a second ProfileSummary added instead of replacing an existing one. I don't think this is the expected behavior. It prevents updating the ProfileSummary and it does not make sense to have more than one. To address this, add Module::setModuleFlag and use it from setProfileSummary. Reviewers: davidxl Subscribers: hiraditya, llvm-commits Tags: #llvm Differential Revision: https://reviews.llvm.org/D79902 --- llvm/include/llvm/IR/Module.h | 13 +++++++-- llvm/lib/IR/Module.cpp | 43 +++++++++++++++++++++++----- llvm/unittests/IR/ModuleTest.cpp | 49 ++++++++++++++++++++++++++++++++ 3 files changed, 95 insertions(+), 10 deletions(-) diff --git a/llvm/include/llvm/IR/Module.h b/llvm/include/llvm/IR/Module.h index 3895e99c10d232..3052651a372267 100644 --- a/llvm/include/llvm/IR/Module.h +++ b/llvm/include/llvm/IR/Module.h @@ -156,6 +156,11 @@ class Module { /// converted result in MFB. static bool isValidModFlagBehavior(Metadata *MD, ModFlagBehavior &MFB); + /// Check if the given module flag metadata represents a valid module flag, + /// and store the flag behavior, the key string and the value metadata. + static bool isValidModuleFlag(const MDNode &ModFlag, ModFlagBehavior &MFB, + MDString *&Key, Metadata *&Val); + struct ModuleFlagEntry { ModFlagBehavior Behavior; MDString *Key; @@ -493,10 +498,12 @@ class Module { void addModuleFlag(ModFlagBehavior Behavior, StringRef Key, Constant *Val); void addModuleFlag(ModFlagBehavior Behavior, StringRef Key, uint32_t Val); void addModuleFlag(MDNode *Node); + /// Like addModuleFlag but replaces the old module flag if it already exists. + void setModuleFlag(ModFlagBehavior Behavior, StringRef Key, Metadata *Val); -/// @} -/// @name Materialization -/// @{ + /// @} + /// @name Materialization + /// @{ /// Sets the GVMaterializer to GVM. This module must not yet have a /// Materializer. To reset the materializer for a module that already has one, diff --git a/llvm/lib/IR/Module.cpp b/llvm/lib/IR/Module.cpp index f1acf4653de66e..9ac1edb2519d37 100644 --- a/llvm/lib/IR/Module.cpp +++ b/llvm/lib/IR/Module.cpp @@ -283,6 +283,20 @@ bool Module::isValidModFlagBehavior(Metadata *MD, ModFlagBehavior &MFB) { return false; } +bool Module::isValidModuleFlag(const MDNode &ModFlag, ModFlagBehavior &MFB, + MDString *&Key, Metadata *&Val) { + if (ModFlag.getNumOperands() < 3) + return false; + if (!isValidModFlagBehavior(ModFlag.getOperand(0), MFB)) + return false; + MDString *K = dyn_cast_or_null(ModFlag.getOperand(1)); + if (!K) + return false; + Key = K; + Val = ModFlag.getOperand(2); + return true; +} + /// getModuleFlagsMetadata - Returns the module flags in the provided vector. void Module:: getModuleFlagsMetadata(SmallVectorImpl &Flags) const { @@ -291,13 +305,11 @@ getModuleFlagsMetadata(SmallVectorImpl &Flags) const { for (const MDNode *Flag : ModFlags->operands()) { ModFlagBehavior MFB; - if (Flag->getNumOperands() >= 3 && - isValidModFlagBehavior(Flag->getOperand(0), MFB) && - dyn_cast_or_null(Flag->getOperand(1))) { + MDString *Key = nullptr; + Metadata *Val = nullptr; + if (isValidModuleFlag(*Flag, MFB, Key, Val)) { // Check the operands of the MDNode before accessing the operands. // The verifier will actually catch these failures. - MDString *Key = cast(Flag->getOperand(1)); - Metadata *Val = Flag->getOperand(2); Flags.push_back(ModuleFlagEntry(MFB, Key, Val)); } } @@ -358,6 +370,23 @@ void Module::addModuleFlag(MDNode *Node) { getOrInsertModuleFlagsMetadata()->addOperand(Node); } +void Module::setModuleFlag(ModFlagBehavior Behavior, StringRef Key, + Metadata *Val) { + NamedMDNode *ModFlags = getOrInsertModuleFlagsMetadata(); + // Replace the flag if it already exists. + for (unsigned I = 0, E = ModFlags->getNumOperands(); I != E; ++I) { + MDNode *Flag = ModFlags->getOperand(I); + ModFlagBehavior MFB; + MDString *K = nullptr; + Metadata *V = nullptr; + if (isValidModuleFlag(*Flag, MFB, K, V) && K->getString() == Key) { + Flag->replaceOperandWith(2, Val); + return; + } + } + addModuleFlag(Behavior, Key, Val); +} + void Module::setDataLayout(StringRef Desc) { DL.reset(Desc); } @@ -547,9 +576,9 @@ void Module::setCodeModel(CodeModel::Model CL) { void Module::setProfileSummary(Metadata *M, ProfileSummary::Kind Kind) { if (Kind == ProfileSummary::PSK_CSInstr) - addModuleFlag(ModFlagBehavior::Error, "CSProfileSummary", M); + setModuleFlag(ModFlagBehavior::Error, "CSProfileSummary", M); else - addModuleFlag(ModFlagBehavior::Error, "ProfileSummary", M); + setModuleFlag(ModFlagBehavior::Error, "ProfileSummary", M); } Metadata *Module::getProfileSummary(bool IsCS) { diff --git a/llvm/unittests/IR/ModuleTest.cpp b/llvm/unittests/IR/ModuleTest.cpp index f642b002a5eb1e..7b34d5d0ee5546 100644 --- a/llvm/unittests/IR/ModuleTest.cpp +++ b/llvm/unittests/IR/ModuleTest.cpp @@ -7,6 +7,7 @@ //===----------------------------------------------------------------------===// #include "llvm/IR/Module.h" +#include "llvm/AsmParser/Parser.h" #include "llvm/IR/GlobalVariable.h" #include "llvm/Pass.h" #include "llvm/Support/RandomNumberGenerator.h" @@ -72,4 +73,52 @@ TEST(ModuleTest, randomNumberGenerator) { RandomStreams[1].begin())); } +TEST(ModuleTest, setModuleFlag) { + LLVMContext Context; + Module M("M", Context); + StringRef Key = "Key"; + Metadata *Val1 = MDString::get(Context, "Val1"); + Metadata *Val2 = MDString::get(Context, "Val2"); + EXPECT_EQ(nullptr, M.getModuleFlag(Key)); + M.setModuleFlag(Module::ModFlagBehavior::Error, Key, Val1); + EXPECT_EQ(Val1, M.getModuleFlag(Key)); + M.setModuleFlag(Module::ModFlagBehavior::Error, Key, Val2); + EXPECT_EQ(Val2, M.getModuleFlag(Key)); +} + +const char *IRString = R"IR( + !llvm.module.flags = !{!0} + + !0 = !{i32 1, !"ProfileSummary", !1} + !1 = !{!2, !3, !4, !5, !6, !7, !8, !9} + !2 = !{!"ProfileFormat", !"SampleProfile"} + !3 = !{!"TotalCount", i64 10000} + !4 = !{!"MaxCount", i64 10} + !5 = !{!"MaxInternalCount", i64 1} + !6 = !{!"MaxFunctionCount", i64 1000} + !7 = !{!"NumCounts", i64 200} + !8 = !{!"NumFunctions", i64 3} + !9 = !{!"DetailedSummary", !10} + !10 = !{!11, !12, !13} + !11 = !{i32 10000, i64 1000, i32 1} + !12 = !{i32 990000, i64 300, i32 10} + !13 = !{i32 999999, i64 5, i32 100} +)IR"; + +TEST(ModuleTest, setProfileSummary) { + SMDiagnostic Err; + LLVMContext Context; + std::unique_ptr M = parseAssemblyString(IRString, Err, Context); + auto *PS = ProfileSummary::getFromMD(M->getProfileSummary(/*IsCS*/ false)); + EXPECT_NE(nullptr, PS); + EXPECT_EQ(false, PS->isPartialProfile()); + PS->setPartialProfile(true); + M->setProfileSummary(PS->getMD(Context), ProfileSummary::PSK_Sample); + delete PS; + PS = ProfileSummary::getFromMD(M->getProfileSummary(/*IsCS*/ false)); + EXPECT_NE(nullptr, PS); + EXPECT_EQ(true, PS->isPartialProfile()); + delete PS; +} + } // end namespace From 07ffcef469cb7f6a97bc0227fb0966264ca902ce Mon Sep 17 00:00:00 2001 From: Jonas Devlieghere Date: Thu, 21 May 2020 11:41:20 -0700 Subject: [PATCH 07/14] [dsymutil] Fix conversion between unique_ptr and Expected MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Reproducer.cpp:70:12: error: could not convert ‘Repro’ from ‘std::unique_ptr >’ to ‘llvm::Expected >’ --- llvm/tools/dsymutil/Reproducer.cpp | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/llvm/tools/dsymutil/Reproducer.cpp b/llvm/tools/dsymutil/Reproducer.cpp index 53e4bda375df0b..448736d702e479 100644 --- a/llvm/tools/dsymutil/Reproducer.cpp +++ b/llvm/tools/dsymutil/Reproducer.cpp @@ -6,8 +6,8 @@ // //===----------------------------------------------------------------------===// -#include "llvm/Support/Path.h" #include "Reproducer.h" +#include "llvm/Support/Path.h" using namespace llvm; using namespace llvm::dsymutil; @@ -64,17 +64,19 @@ Reproducer::createReproducer(ReproducerMode Mode, StringRef Root) { switch (Mode) { case ReproducerMode::Generate: { std::error_code EC; - auto Repro = std::make_unique(EC); + std::unique_ptr Repro = + std::make_unique(EC); if (EC) return errorCodeToError(EC); - return Repro; + return std::move(Repro); } case ReproducerMode::Use: { std::error_code EC; - auto Repro = std::make_unique(Root, EC); + std::unique_ptr Repro = + std::make_unique(Root, EC); if (EC) return errorCodeToError(EC); - return Repro; + return std::move(Repro); } case ReproducerMode::Off: return std::make_unique(); From 8f555780ef3502021a0237a6ace100f728fd0f5b Mon Sep 17 00:00:00 2001 From: Louis Dionne Date: Thu, 21 May 2020 14:33:32 -0400 Subject: [PATCH 08/14] [libc++] Link back-deployment tests against the latest libc++ and libc++abi Instead of linking the tests against a library in some version of the SDK, always link against the latest library, but still run against the specified back-deployment target dylib. This makes more sense since what we're really trying to test is that the current library can be used to produce binaries that run on some deployment target -- not that linking against the library in some previous SDK makes that possible. This solves an additional issue that when linking against a system dylib, the -rpath argument given to the tests is ignored because the install_name of the system library we link against is absolute. rdar://63241847 --- libcxx/utils/ci/macos-backdeployment.sh | 32 +++++-------------------- 1 file changed, 6 insertions(+), 26 deletions(-) diff --git a/libcxx/utils/ci/macos-backdeployment.sh b/libcxx/utils/ci/macos-backdeployment.sh index 71687c2f521eaa..4ed3bda2e3af27 100755 --- a/libcxx/utils/ci/macos-backdeployment.sh +++ b/libcxx/utils/ci/macos-backdeployment.sh @@ -4,14 +4,15 @@ set -ue function usage() { cat < --std --deployment-target --sdk-version [--libcxx-roots ] [--lit-args ] [--no-cleanup] +$(basename ${0}) [-h|--help] --monorepo-root --std --deployment-target [--libcxx-roots ] [--lit-args ] [--no-cleanup] This script is used to continually test the back-deployment use case of libc++ and libc++abi on MacOS. +Specifically, this script runs the libc++ test suite against the just-built headers and linking against the just-built dylib, but it runs the tests against the dylibs for the given deployment target. + --monorepo-root Full path to the root of the LLVM monorepo. Both libc++ and libc++abi headers from the monorepo are used. --std Version of the C++ Standard to run the tests under (c++03, c++11, etc..). --deployment-target The deployment target to run the tests for. This should be a version number of MacOS (e.g. 10.12). All MacOS versions until and including 10.9 are supported. - --sdk-version The version of the SDK to test with. This should be a version number of MacOS (e.g. 10.12). We'll link against the libc++ dylib in that SDK, but we'll run against the one on the given deployment target. The SDK version must be no older than the deployment target. [--libcxx-roots] The path to previous libc++/libc++abi dylibs to use for back-deployment testing. Those are normally downloaded automatically, but if specified, this option will override the directory used. The directory should have the same layout as the roots downloaded automatically. [--lit-args] Additional arguments to pass to lit (optional). If there are multiple arguments, quote them to pass them as a single argument to this script. [--no-cleanup] Do not cleanup the temporary directory that was used for testing at the end. This can be useful to debug failures. Make sure to clean up manually after. @@ -19,14 +20,6 @@ This script is used to continually test the back-deployment use case of libc++ a EOM } -function version-less-equal() { - [ "$1" = "$(echo -e "$1\n$2" | sort -V | head -n1)" ] -} - -function version-less() { - [ "$1" = "$2" ] && return 1 || version-less-equal $1 $2 -} - while [[ $# -gt 0 ]]; do case "$1" in --monorepo-root) @@ -46,10 +39,6 @@ while [[ $# -gt 0 ]]; do DEPLOYMENT_TARGET="${2}" shift; shift ;; - --sdk-version) - MACOS_SDK_VERSION="${2}" - shift; shift - ;; --lit-args) ADDITIONAL_LIT_ARGS="${2}" shift; shift @@ -77,16 +66,9 @@ done if [[ -z ${MONOREPO_ROOT+x} ]]; then echo "--monorepo-root is a required parameter"; usage; exit 1; fi if [[ -z ${STD+x} ]]; then echo "--std is a required parameter"; usage; exit 1; fi if [[ -z ${DEPLOYMENT_TARGET+x} ]]; then echo "--deployment-target is a required parameter"; usage; exit 1; fi -if [[ -z ${MACOS_SDK_VERSION+x} ]]; then echo "--sdk-version is a required parameter"; usage; exit 1; fi if [[ -z ${ADDITIONAL_LIT_ARGS+x} ]]; then ADDITIONAL_LIT_ARGS=""; fi if [[ -z ${PREVIOUS_DYLIBS_DIR+x} ]]; then PREVIOUS_DYLIBS_DIR=""; fi -if version-less "${MACOS_SDK_VERSION}" "${DEPLOYMENT_TARGET}"; then - echo "SDK version ${MACOS_SDK_VERSION} shouldn't be older than the deployment target (${DEPLOYMENT_TARGET})" - usage - exit 1 -fi - TEMP_DIR="$(mktemp -d)" echo "Created temporary directory ${TEMP_DIR}" function cleanup { @@ -121,12 +103,11 @@ mkdir -p "${LLVM_BUILD_DIR}" echo "@@@@@@" -echo "@@@ Installing the latest libc++ headers @@@" -ninja -C "${LLVM_BUILD_DIR}" install-cxx-headers +echo "@@@ Building and installing libc++ and libc++abi @@@" +ninja -C "${LLVM_BUILD_DIR}" install-cxx install-cxxabi echo "@@@@@@" -# TODO: We should also link against the libc++abi.dylib that was shipped in the SDK if [[ ${PREVIOUS_DYLIBS_DIR} == "" ]]; then echo "@@@ Downloading dylibs for older deployment targets @@@" PREVIOUS_DYLIBS_DIR="${TEMP_DIR}/libcxx-dylibs" @@ -137,7 +118,6 @@ fi LIBCXX_ROOT_ON_DEPLOYMENT_TARGET="${PREVIOUS_DYLIBS_DIR}/macOS/libc++/${DEPLOYMENT_TARGET}" LIBCXXABI_ROOT_ON_DEPLOYMENT_TARGET="${PREVIOUS_DYLIBS_DIR}/macOS/libc++abi/${DEPLOYMENT_TARGET}" -LIBCXX_ROOT_IN_SDK="${PREVIOUS_DYLIBS_DIR}/macOS/libc++/${MACOS_SDK_VERSION}" # TODO: We need to also run the tests for libc++abi. echo "@@@ Running tests for libc++ @@@" @@ -146,7 +126,7 @@ echo "@@@ Running tests for libc++ @@@" --param=cxx_headers="${LLVM_INSTALL_DIR}/include/c++/v1" \ --param=std="${STD}" \ --param=platform="macosx${DEPLOYMENT_TARGET}" \ - --param=cxx_library_root="${LIBCXX_ROOT_IN_SDK}" \ + --param=cxx_library_root="${LLVM_INSTALL_DIR}/lib" \ --param=cxx_runtime_root="${LIBCXX_ROOT_ON_DEPLOYMENT_TARGET}" \ --param=abi_library_path="${LIBCXXABI_ROOT_ON_DEPLOYMENT_TARGET}" \ --param=use_system_cxx_lib="True" \ From f7c7e8a523f56b0ed1b14c0756ba4e5d1ccb48d2 Mon Sep 17 00:00:00 2001 From: Jan Korous Date: Thu, 21 May 2020 11:52:12 -0700 Subject: [PATCH 09/14] [Analyzer][WebKit] RefCntblBaseVirtualDtorChecker Differential Revision: https://reviews.llvm.org/D77177 --- clang/docs/analyzer/checkers.rst | 27 +++ .../clang/StaticAnalyzer/Checkers/Checkers.td | 13 ++ .../StaticAnalyzer/Checkers/CMakeLists.txt | 2 + .../StaticAnalyzer/Checkers/WebKit/ASTUtils.h | 70 +++++++ .../Checkers/WebKit/DiagOutputUtils.h | 28 +++ .../Checkers/WebKit/PtrTypesSemantics.cpp | 172 ++++++++++++++++++ .../Checkers/WebKit/PtrTypesSemantics.h | 59 ++++++ .../WebKit/RefCntblBaseVirtualDtorChecker.cpp | 167 +++++++++++++++++ .../Analysis/Checkers/WebKit/mock-types.h | 48 +++++ .../ref-cntbl-base-virtual-dtor-templates.cpp | 30 +++ .../WebKit/ref-cntbl-base-virtual-dtor.cpp | 53 ++++++ 11 files changed, 669 insertions(+) create mode 100644 clang/lib/StaticAnalyzer/Checkers/WebKit/ASTUtils.h create mode 100644 clang/lib/StaticAnalyzer/Checkers/WebKit/DiagOutputUtils.h create mode 100644 clang/lib/StaticAnalyzer/Checkers/WebKit/PtrTypesSemantics.cpp create mode 100644 clang/lib/StaticAnalyzer/Checkers/WebKit/PtrTypesSemantics.h create mode 100644 clang/lib/StaticAnalyzer/Checkers/WebKit/RefCntblBaseVirtualDtorChecker.cpp create mode 100644 clang/test/Analysis/Checkers/WebKit/mock-types.h create mode 100644 clang/test/Analysis/Checkers/WebKit/ref-cntbl-base-virtual-dtor-templates.cpp create mode 100644 clang/test/Analysis/Checkers/WebKit/ref-cntbl-base-virtual-dtor.cpp diff --git a/clang/docs/analyzer/checkers.rst b/clang/docs/analyzer/checkers.rst index 0bfb6456dc820b..79ba8fb18ba86d 100644 --- a/clang/docs/analyzer/checkers.rst +++ b/clang/docs/analyzer/checkers.rst @@ -1374,6 +1374,33 @@ double freed, or use after freed. This check attempts to find such problems. zx_handle_close(sb); } +WebKit +^^^^^^ + +WebKit is an open-source web browser engine available for macOS, iOS and Linux. +This section describes checkers that can find issues in WebKit codebase. + +Most of the checkers focus on memory management for which WebKit uses custom implementation of reference counted smartpointers. +Checker are formulated in terms related to ref-counting: +* *Ref-counted type* is either ``Ref`` or ``RefPtr``. +* *Ref-countable type* is any type that implements ``ref()`` and ``deref()`` methods as ``RefPtr<>`` is a template (i. e. relies on duck typing). +* *Uncounted type* is ref-countable but not ref-counted type. + +.. _webkit-WebKitRefCntblBaseVirtualDtor: + +webkit.WebKitRefCntblBaseVirtualDtor +"""""""""""""""""""""""""""""""""""" +All uncounted types used as base classes must have a virtual destructor. + +Ref-counted types hold their ref-countable data by a raw pointer and allow implicit upcasting from ref-counted pointer to derived type to ref-counted pointer to base type. This might lead to an object of (dynamic) derived type being deleted via pointer to the base class type which C++ standard defines as UB in case the base class doesn't have virtual destructor ``[expr.delete]``. + +.. code-block:: cpp + struct RefCntblBase { + void ref() {} + void deref() {} + }; + + struct Derived : RefCntblBase { }; // warn .. _alpha-checkers: diff --git a/clang/include/clang/StaticAnalyzer/Checkers/Checkers.td b/clang/include/clang/StaticAnalyzer/Checkers/Checkers.td index 93c4d964d77240..ec65afb30dd028 100644 --- a/clang/include/clang/StaticAnalyzer/Checkers/Checkers.td +++ b/clang/include/clang/StaticAnalyzer/Checkers/Checkers.td @@ -116,6 +116,9 @@ def NonDeterminismAlpha : Package<"nondeterminism">, ParentPackage; def Fuchsia : Package<"fuchsia">; def FuchsiaAlpha : Package<"fuchsia">, ParentPackage; +def WebKit : Package<"webkit">; +def WebKitAlpha : Package<"webkit">, ParentPackage; + //===----------------------------------------------------------------------===// // Core Checkers. //===----------------------------------------------------------------------===// @@ -1620,3 +1623,13 @@ def FuchsiaLockChecker : Checker<"Lock">, } // end fuchsia +//===----------------------------------------------------------------------===// +// WebKit checkers. +//===----------------------------------------------------------------------===// + +let ParentPackage = WebKit in { + +def WebKitRefCntblBaseVirtualDtorChecker : Checker<"WebKitRefCntblBaseVirtualDtor">, + HelpText<"Check for any ref-countable base class having virtual destructor.">, + Documentation; +} // end webkit diff --git a/clang/lib/StaticAnalyzer/Checkers/CMakeLists.txt b/clang/lib/StaticAnalyzer/Checkers/CMakeLists.txt index bcf2dfdb832661..4f885fadf4158d 100644 --- a/clang/lib/StaticAnalyzer/Checkers/CMakeLists.txt +++ b/clang/lib/StaticAnalyzer/Checkers/CMakeLists.txt @@ -121,6 +121,8 @@ add_clang_library(clangStaticAnalyzerCheckers VLASizeChecker.cpp ValistChecker.cpp VirtualCallChecker.cpp + WebKit/PtrTypesSemantics.cpp + WebKit/RefCntblBaseVirtualDtorChecker.cpp LINK_LIBS clangAST diff --git a/clang/lib/StaticAnalyzer/Checkers/WebKit/ASTUtils.h b/clang/lib/StaticAnalyzer/Checkers/WebKit/ASTUtils.h new file mode 100644 index 00000000000000..26d79cfcd9b519 --- /dev/null +++ b/clang/lib/StaticAnalyzer/Checkers/WebKit/ASTUtils.h @@ -0,0 +1,70 @@ +//=======- ASTUtis.h ---------------------------------------------*- C++ -*-==// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_ANALYZER_WEBKIT_ASTUTILS_H +#define LLVM_CLANG_ANALYZER_WEBKIT_ASTUTILS_H + +#include "clang/AST/Decl.h" +#include "llvm/ADT/APInt.h" +#include "llvm/Support/Casting.h" + +#include +#include + +namespace clang { +class CXXRecordDecl; +class CXXBaseSpecifier; +class FunctionDecl; +class CXXMethodDecl; +class Expr; + +/// If passed expression is of type uncounted pointer/reference we try to find +/// the origin of this pointer. Example: Origin can be a local variable, nullptr +/// constant or this-pointer. +/// +/// Certain subexpression nodes represent transformations that don't affect +/// where the memory address originates from. We try to traverse such +/// subexpressions to get to the relevant child nodes. Whenever we encounter a +/// subexpression that either can't be ignored, we don't model its semantics or +/// that has multiple children we stop. +/// +/// \p E is an expression of uncounted pointer/reference type. +/// If \p StopAtFirstRefCountedObj is true and we encounter a subexpression that +/// represents ref-counted object during the traversal we return relevant +/// sub-expression and true. +/// +/// \returns subexpression that we traversed to and if \p +/// StopAtFirstRefCountedObj is true we also return whether we stopped early. +std::pair +tryToFindPtrOrigin(const clang::Expr *E, bool StopAtFirstRefCountedObj); + +/// For \p E referring to a ref-countable/-counted pointer/reference we return +/// whether it's a safe call argument. Examples: function parameter or +/// this-pointer. The logic relies on the set of recursive rules we enforce for +/// WebKit codebase. +/// +/// \returns Whether \p E is a safe call arugment. +bool isASafeCallArg(const clang::Expr *E); + +/// \returns name of AST node or empty string. +template std::string safeGetName(const T *ASTNode) { + const auto *const ND = llvm::dyn_cast_or_null(ASTNode); + if (!ND) + return ""; + + // In case F is for example "operator|" the getName() method below would + // assert. + if (!ND->getDeclName().isIdentifier()) + return ""; + + return ND->getName().str(); +} + +} // namespace clang + +#endif diff --git a/clang/lib/StaticAnalyzer/Checkers/WebKit/DiagOutputUtils.h b/clang/lib/StaticAnalyzer/Checkers/WebKit/DiagOutputUtils.h new file mode 100644 index 00000000000000..4979b8ffc2b20c --- /dev/null +++ b/clang/lib/StaticAnalyzer/Checkers/WebKit/DiagOutputUtils.h @@ -0,0 +1,28 @@ +//=======- DiagOutputUtils.h -------------------------------------*- C++ -*-==// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_ANALYZER_WEBKIT_DIAGPRINTUTILS_H +#define LLVM_CLANG_ANALYZER_WEBKIT_DIAGPRINTUTILS_H + +#include "clang/AST/Decl.h" +#include "llvm/Support/raw_ostream.h" + +namespace clang { + +template +void printQuotedQualifiedName(llvm::raw_ostream &Os, + const NamedDeclDerivedT &D) { + Os << "'"; + D->getNameForDiagnostic(Os, D->getASTContext().getPrintingPolicy(), + /*Qualified=*/true); + Os << "'"; +} + +} // namespace clang + +#endif diff --git a/clang/lib/StaticAnalyzer/Checkers/WebKit/PtrTypesSemantics.cpp b/clang/lib/StaticAnalyzer/Checkers/WebKit/PtrTypesSemantics.cpp new file mode 100644 index 00000000000000..adb6253df96526 --- /dev/null +++ b/clang/lib/StaticAnalyzer/Checkers/WebKit/PtrTypesSemantics.cpp @@ -0,0 +1,172 @@ +//=======- PtrTypesSemantics.cpp ---------------------------------*- C++ -*-==// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "PtrTypesSemantics.h" +#include "ASTUtils.h" +#include "clang/AST/CXXInheritance.h" +#include "clang/AST/Decl.h" +#include "clang/AST/DeclCXX.h" +#include "clang/AST/ExprCXX.h" + +using llvm::Optional; +using namespace clang; + +namespace { + +bool hasPublicRefAndDeref(const CXXRecordDecl *R) { + assert(R); + + bool hasRef = false; + bool hasDeref = false; + for (const CXXMethodDecl *MD : R->methods()) { + const auto MethodName = safeGetName(MD); + + if (MethodName == "ref" && MD->getAccess() == AS_public) { + if (hasDeref) + return true; + hasRef = true; + } else if (MethodName == "deref" && MD->getAccess() == AS_public) { + if (hasRef) + return true; + hasDeref = true; + } + } + return false; +} + +} // namespace + +namespace clang { + +const CXXRecordDecl *isRefCountable(const CXXBaseSpecifier *Base) { + assert(Base); + + const Type *T = Base->getType().getTypePtrOrNull(); + if (!T) + return nullptr; + + const CXXRecordDecl *R = T->getAsCXXRecordDecl(); + if (!R) + return nullptr; + + return hasPublicRefAndDeref(R) ? R : nullptr; +}; + +bool isRefCountable(const CXXRecordDecl *R) { + assert(R); + + R = R->getDefinition(); + assert(R); + + if (hasPublicRefAndDeref(R)) + return true; + + CXXBasePaths Paths; + Paths.setOrigin(const_cast(R)); + + const auto isRefCountableBase = [](const CXXBaseSpecifier *Base, + CXXBasePath &) { + return clang::isRefCountable(Base); + }; + + return R->lookupInBases(isRefCountableBase, Paths, + /*LookupInDependent =*/true); +} + +bool isCtorOfRefCounted(const clang::FunctionDecl *F) { + assert(F); + const auto &FunctionName = safeGetName(F); + + return FunctionName == "Ref" || FunctionName == "makeRef" + + || FunctionName == "RefPtr" || FunctionName == "makeRefPtr" + + || FunctionName == "UniqueRef" || FunctionName == "makeUniqueRef" || + FunctionName == "makeUniqueRefWithoutFastMallocCheck" + + || FunctionName == "String" || FunctionName == "AtomString" || + FunctionName == "UniqueString" + // FIXME: Implement as attribute. + || FunctionName == "Identifier"; +} + +bool isUncounted(const CXXRecordDecl *Class) { + // Keep isRefCounted first as it's cheaper. + return !isRefCounted(Class) && isRefCountable(Class); +} + +bool isUncountedPtr(const Type *T) { + assert(T); + + if (T->isPointerType() || T->isReferenceType()) { + if (auto *CXXRD = T->getPointeeCXXRecordDecl()) { + return isUncounted(CXXRD); + } + } + return false; +} + +bool isGetterOfRefCounted(const CXXMethodDecl *M) { + assert(M); + + if (auto *calleeMethodDecl = dyn_cast(M)) { + const CXXRecordDecl *calleeMethodsClass = M->getParent(); + auto className = safeGetName(calleeMethodsClass); + auto methodName = safeGetName(M); + + if (((className == "Ref" || className == "RefPtr") && + methodName == "get") || + ((className == "String" || className == "AtomString" || + className == "AtomStringImpl" || className == "UniqueString" || + className == "UniqueStringImpl" || className == "Identifier") && + methodName == "impl")) + return true; + + // Ref -> T conversion + // FIXME: Currently allowing any Ref -> whatever cast. + if (className == "Ref" || className == "RefPtr") { + if (auto *maybeRefToRawOperator = dyn_cast(M)) { + if (auto *targetConversionType = + maybeRefToRawOperator->getConversionType().getTypePtrOrNull()) { + if (isUncountedPtr(targetConversionType)) { + return true; + } + } + } + } + } + return false; +} + +bool isRefCounted(const CXXRecordDecl *R) { + assert(R); + if (auto *TmplR = R->getTemplateInstantiationPattern()) { + // FIXME: String/AtomString/UniqueString + const auto &ClassName = safeGetName(TmplR); + return ClassName == "RefPtr" || ClassName == "Ref"; + } + return false; +} + +bool isPtrConversion(const FunctionDecl *F) { + assert(F); + if (isCtorOfRefCounted(F)) + return true; + + // FIXME: check # of params == 1 + const auto FunctionName = safeGetName(F); + if (FunctionName == "getPtr" || FunctionName == "WeakPtr" || + FunctionName == "makeWeakPtr" + + || FunctionName == "downcast" || FunctionName == "bitwise_cast") + return true; + + return false; +} + +} // namespace clang diff --git a/clang/lib/StaticAnalyzer/Checkers/WebKit/PtrTypesSemantics.h b/clang/lib/StaticAnalyzer/Checkers/WebKit/PtrTypesSemantics.h new file mode 100644 index 00000000000000..83d9c0bcc13b38 --- /dev/null +++ b/clang/lib/StaticAnalyzer/Checkers/WebKit/PtrTypesSemantics.h @@ -0,0 +1,59 @@ +//=======- PtrTypesSemantics.cpp ---------------------------------*- C++ -*-==// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_ANALYZER_WEBKIT_PTRTYPESEMANTICS_H +#define LLVM_CLANG_ANALYZER_WEBKIT_PTRTYPESEMANTICS_H + +namespace clang { +class CXXBaseSpecifier; +class CXXMethodDecl; +class CXXRecordDecl; +class Expr; +class FunctionDecl; +class Type; + +// Ref-countability of a type is implicitly defined by Ref and RefPtr +// implementation. It can be modeled as: type T having public methods ref() and +// deref() + +// In WebKit there are two ref-counted templated smart pointers: RefPtr and +// Ref. + +/// \returns CXXRecordDecl of the base if the type is ref-countable, nullptr if +/// not. +const clang::CXXRecordDecl *isRefCountable(const clang::CXXBaseSpecifier *Base); + +/// \returns true if \p Class is ref-countable, false if not. +/// Asserts that \p Class IS a definition. +bool isRefCountable(const clang::CXXRecordDecl *Class); + +/// \returns true if \p Class is ref-counted, false if not. +bool isRefCounted(const clang::CXXRecordDecl *Class); + +/// \returns true if \p Class is ref-countable AND not ref-counted, false if +/// not. Asserts that \p Class IS a definition. +bool isUncounted(const clang::CXXRecordDecl *Class); + +/// \returns true if \p T is either a raw pointer or reference to an uncounted +/// class, false if not. +bool isUncountedPtr(const clang::Type *T); + +/// \returns true if \p F creates ref-countable object from uncounted parameter, +/// false if not. +bool isCtorOfRefCounted(const clang::FunctionDecl *F); + +/// \returns true if \p M is getter of a ref-counted class, false if not. +bool isGetterOfRefCounted(const clang::CXXMethodDecl *Method); + +/// \returns true if \p F is a conversion between ref-countable or ref-counted +/// pointer types. +bool isPtrConversion(const FunctionDecl *F); + +} // namespace clang + +#endif diff --git a/clang/lib/StaticAnalyzer/Checkers/WebKit/RefCntblBaseVirtualDtorChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/WebKit/RefCntblBaseVirtualDtorChecker.cpp new file mode 100644 index 00000000000000..4343d427351b09 --- /dev/null +++ b/clang/lib/StaticAnalyzer/Checkers/WebKit/RefCntblBaseVirtualDtorChecker.cpp @@ -0,0 +1,167 @@ +//=======- RefCntblBaseVirtualDtor.cpp ---------------------------*- C++ -*-==// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "DiagOutputUtils.h" +#include "PtrTypesSemantics.h" +#include "clang/AST/CXXInheritance.h" +#include "clang/AST/RecursiveASTVisitor.h" +#include "clang/StaticAnalyzer/Checkers/BuiltinCheckerRegistration.h" +#include "clang/StaticAnalyzer/Core/BugReporter/BugReporter.h" +#include "clang/StaticAnalyzer/Core/BugReporter/BugType.h" +#include "clang/StaticAnalyzer/Core/Checker.h" + +using namespace clang; +using namespace ento; + +namespace { +class RefCntblBaseVirtualDtorChecker + : public Checker> { +private: + BugType Bug; + mutable BugReporter *BR; + +public: + RefCntblBaseVirtualDtorChecker() + : Bug(this, + "Reference-countable base class doesn't have virtual destructor", + "WebKit coding guidelines") {} + + void checkASTDecl(const TranslationUnitDecl *TUD, AnalysisManager &MGR, + BugReporter &BRArg) const { + BR = &BRArg; + + // The calls to checkAST* from AnalysisConsumer don't + // visit template instantiations or lambda classes. We + // want to visit those, so we make our own RecursiveASTVisitor. + struct LocalVisitor : public RecursiveASTVisitor { + const RefCntblBaseVirtualDtorChecker *Checker; + explicit LocalVisitor(const RefCntblBaseVirtualDtorChecker *Checker) + : Checker(Checker) { + assert(Checker); + } + + bool shouldVisitTemplateInstantiations() const { return true; } + bool shouldVisitImplicitCode() const { return false; } + + bool VisitCXXRecordDecl(const CXXRecordDecl *RD) { + Checker->visitCXXRecordDecl(RD); + return true; + } + }; + + LocalVisitor visitor(this); + visitor.TraverseDecl(const_cast(TUD)); + } + + void visitCXXRecordDecl(const CXXRecordDecl *RD) const { + if (shouldSkipDecl(RD)) + return; + + CXXBasePaths Paths; + Paths.setOrigin(RD); + + const CXXBaseSpecifier *ProblematicBaseSpecifier = nullptr; + const CXXRecordDecl *ProblematicBaseClass = nullptr; + + const auto IsPublicBaseRefCntblWOVirtualDtor = + [RD, &ProblematicBaseSpecifier, + &ProblematicBaseClass](const CXXBaseSpecifier *Base, CXXBasePath &) { + const auto AccSpec = Base->getAccessSpecifier(); + if (AccSpec == AS_protected || AccSpec == AS_private || + (AccSpec == AS_none && RD->isClass())) + return false; + + llvm::Optional MaybeRefCntblBaseRD = + isRefCountable(Base); + if (!MaybeRefCntblBaseRD.hasValue()) + return false; + + const CXXRecordDecl *RefCntblBaseRD = MaybeRefCntblBaseRD.getValue(); + if (!RefCntblBaseRD) + return false; + + const auto *Dtor = RefCntblBaseRD->getDestructor(); + if (!Dtor || !Dtor->isVirtual()) { + ProblematicBaseSpecifier = Base; + ProblematicBaseClass = RefCntblBaseRD; + return true; + } + + return false; + }; + + if (RD->lookupInBases(IsPublicBaseRefCntblWOVirtualDtor, Paths, + /*LookupInDependent =*/true)) { + reportBug(RD, ProblematicBaseSpecifier, ProblematicBaseClass); + } + } + + bool shouldSkipDecl(const CXXRecordDecl *RD) const { + if (!RD->isThisDeclarationADefinition()) + return true; + + if (RD->isImplicit()) + return true; + + if (RD->isLambda()) + return true; + + // If the construct doesn't have a source file, then it's not something + // we want to diagnose. + const auto RDLocation = RD->getLocation(); + if (!RDLocation.isValid()) + return true; + + const auto Kind = RD->getTagKind(); + if (Kind != TTK_Struct && Kind != TTK_Class) + return true; + + // Ignore CXXRecords that come from system headers. + if (BR->getSourceManager().getFileCharacteristic(RDLocation) != + SrcMgr::C_User) + return true; + + return false; + } + + void reportBug(const CXXRecordDecl *DerivedClass, + const CXXBaseSpecifier *BaseSpec, + const CXXRecordDecl *ProblematicBaseClass) const { + assert(DerivedClass); + assert(BaseSpec); + assert(ProblematicBaseClass); + + SmallString<100> Buf; + llvm::raw_svector_ostream Os(Buf); + + Os << (ProblematicBaseClass->isClass() ? "Class" : "Struct") << " "; + printQuotedQualifiedName(Os, ProblematicBaseClass); + + Os << " is used as a base of " + << (DerivedClass->isClass() ? "class" : "struct") << " "; + printQuotedQualifiedName(Os, DerivedClass); + + Os << " but doesn't have virtual destructor"; + + PathDiagnosticLocation BSLoc(BaseSpec->getSourceRange().getBegin(), + BR->getSourceManager()); + auto Report = std::make_unique(Bug, Os.str(), BSLoc); + Report->addRange(BaseSpec->getSourceRange()); + BR->emitReport(std::move(Report)); + } +}; +} // namespace + +void ento::registerWebKitRefCntblBaseVirtualDtorChecker(CheckerManager &Mgr) { + Mgr.registerChecker(); +} + +bool ento::shouldRegisterWebKitRefCntblBaseVirtualDtorChecker( + const LangOptions &LO) { + return true; +} diff --git a/clang/test/Analysis/Checkers/WebKit/mock-types.h b/clang/test/Analysis/Checkers/WebKit/mock-types.h new file mode 100644 index 00000000000000..5f570b8bee8cb8 --- /dev/null +++ b/clang/test/Analysis/Checkers/WebKit/mock-types.h @@ -0,0 +1,48 @@ +#ifndef mock_types_1103988513531 +#define mock_types_1103988513531 + +template struct Ref { + T t; + + Ref() : t{} {}; + Ref(T *) {} + T *get() { return nullptr; } + operator const T &() const { return t; } + operator T &() { return t; } +}; + +template struct RefPtr { + T *t; + + RefPtr() : t(new T) {} + RefPtr(T *t) : t(t) {} + T *get() { return t; } + T *operator->() { return t; } + T &operator*() { return *t; } + RefPtr &operator=(T *) { return *this; } +}; + +template bool operator==(const RefPtr &, const RefPtr &) { + return false; +} + +template bool operator==(const RefPtr &, T *) { return false; } + +template bool operator==(const RefPtr &, T &) { return false; } + +template bool operator!=(const RefPtr &, const RefPtr &) { + return false; +} + +template bool operator!=(const RefPtr &, T *) { return false; } + +template bool operator!=(const RefPtr &, T &) { return false; } + +struct RefCountable { + void ref() {} + void deref() {} +}; + +template T *downcast(T *t) { return t; } + +#endif diff --git a/clang/test/Analysis/Checkers/WebKit/ref-cntbl-base-virtual-dtor-templates.cpp b/clang/test/Analysis/Checkers/WebKit/ref-cntbl-base-virtual-dtor-templates.cpp new file mode 100644 index 00000000000000..f73655258b4783 --- /dev/null +++ b/clang/test/Analysis/Checkers/WebKit/ref-cntbl-base-virtual-dtor-templates.cpp @@ -0,0 +1,30 @@ +// RUN: %clang_analyze_cc1 -analyzer-checker=webkit.WebKitRefCntblBaseVirtualDtor -verify %s + +struct RefCntblBase { + void ref() {} + void deref() {} +}; + +template +struct DerivedClassTmpl1 : T { }; +// expected-warning@-1{{Struct 'RefCntblBase' is used as a base of struct 'DerivedClassTmpl1' but doesn't have virtual destructor}} + +DerivedClassTmpl1 a; + + + +template +struct DerivedClassTmpl2 : T { }; +// expected-warning@-1{{Struct 'RefCntblBase' is used as a base of struct 'DerivedClassTmpl2' but doesn't have virtual destructor}} + +template int foo(T) { DerivedClassTmpl2 f; return 42; } +int b = foo(RefCntblBase{}); + + + +template +struct DerivedClassTmpl3 : T { }; +// expected-warning@-1{{Struct 'RefCntblBase' is used as a base of struct 'DerivedClassTmpl3' but doesn't have virtual destructor}} + +typedef DerivedClassTmpl3 Foo; +Foo c; diff --git a/clang/test/Analysis/Checkers/WebKit/ref-cntbl-base-virtual-dtor.cpp b/clang/test/Analysis/Checkers/WebKit/ref-cntbl-base-virtual-dtor.cpp new file mode 100644 index 00000000000000..a0eb4d6169b666 --- /dev/null +++ b/clang/test/Analysis/Checkers/WebKit/ref-cntbl-base-virtual-dtor.cpp @@ -0,0 +1,53 @@ +// RUN: %clang_analyze_cc1 -analyzer-checker=webkit.WebKitRefCntblBaseVirtualDtor -verify %s + +struct RefCntblBase { + void ref() {} + void deref() {} +}; + +struct Derived : RefCntblBase { }; +// expected-warning@-1{{Struct 'RefCntblBase' is used as a base of struct 'Derived' but doesn't have virtual destructor}} + +struct DerivedWithVirtualDtor : RefCntblBase { +// expected-warning@-1{{Struct 'RefCntblBase' is used as a base of struct 'DerivedWithVirtualDtor' but doesn't have virtual destructor}} + virtual ~DerivedWithVirtualDtor() {} +}; + + + +template +struct DerivedClassTmpl : T { }; +typedef DerivedClassTmpl Foo; + + + +struct RandomBase {}; +struct RandomDerivedClass : RandomBase { }; + + + +struct FakeRefCntblBase1 { + private: + void ref() {} + void deref() {} +}; +struct Quiet1 : FakeRefCntblBase1 {}; + +struct FakeRefCntblBase2 { + protected: + void ref() {} + void deref() {} +}; +struct Quiet2 : FakeRefCntblBase2 {}; + +class FakeRefCntblBase3 { + void ref() {} + void deref() {} +}; +struct Quiet3 : FakeRefCntblBase3 {}; +struct Quiet4 : private RefCntblBase {}; +class Quiet5 : RefCntblBase {}; + +void foo () { + Derived d; +} From 15389cdc5b721fc1e10dc5818390fa3fa939a92e Mon Sep 17 00:00:00 2001 From: Thomas Raoux Date: Thu, 21 May 2020 11:35:32 -0700 Subject: [PATCH 10/14] [mlir][spirv] Add remaining cooperative matrix instructions Adds support for cooperative matrix support for arithmetic and cast instructions. It also adds cooperative matrix store, muladd and matrixlength instructions which are part of the extension. Differential Revision: https://reviews.llvm.org/D80181 --- .../mlir/Dialect/SPIRV/SPIRVArithmeticOps.td | 13 +- mlir/include/mlir/Dialect/SPIRV/SPIRVBase.td | 17 +- .../mlir/Dialect/SPIRV/SPIRVCastOps.td | 4 +- .../SPIRV/SPIRVCooperativeMatrixOps.td | 192 +++++++++++++++++- mlir/lib/Dialect/SPIRV/SPIRVOps.cpp | 139 +++++++++++++ .../Serialization/cooperative-matrix.mlir | 77 +++++++ .../Dialect/SPIRV/cooperative-matrix.mlir | 110 ++++++++++ mlir/test/Dialect/SPIRV/ops.mlir | 16 ++ mlir/tools/mlir-tblgen/SPIRVUtilsGen.cpp | 10 + 9 files changed, 570 insertions(+), 8 deletions(-) diff --git a/mlir/include/mlir/Dialect/SPIRV/SPIRVArithmeticOps.td b/mlir/include/mlir/Dialect/SPIRV/SPIRVArithmeticOps.td index 11d0cdf23d79f9..350e3659a28d75 100644 --- a/mlir/include/mlir/Dialect/SPIRV/SPIRVArithmeticOps.td +++ b/mlir/include/mlir/Dialect/SPIRV/SPIRVArithmeticOps.td @@ -22,7 +22,18 @@ class SPV_ArithmeticBinaryOp; + [NoSideEffect, SameOperandsAndResultType])> { + // In addition to normal types arithmetic instructions can support cooperative + // matrix. + let arguments = (ins + SPV_ScalarOrVectorOrCoopMatrixOf:$operand1, + SPV_ScalarOrVectorOrCoopMatrixOf:$operand2 + ); + + let results = (outs + SPV_ScalarOrVectorOrCoopMatrixOf:$result + ); +} class SPV_ArithmeticUnaryOp traits = []> : diff --git a/mlir/include/mlir/Dialect/SPIRV/SPIRVBase.td b/mlir/include/mlir/Dialect/SPIRV/SPIRVBase.td index b958a10c59521b..a3a2c2bec43bc5 100644 --- a/mlir/include/mlir/Dialect/SPIRV/SPIRVBase.td +++ b/mlir/include/mlir/Dialect/SPIRV/SPIRVBase.td @@ -3004,6 +3004,7 @@ def SPV_IsStructType : CPred<"$_self.isa<::mlir::spirv::StructType>()">; def SPV_Void : TypeAlias; def SPV_Bool : TypeAlias; def SPV_Integer : AnyIntOfWidths<[8, 16, 32, 64]>; +def SPV_Int32 : TypeAlias; def SPV_Float : FloatOfWidths<[16, 32, 64]>; def SPV_Float16or32 : FloatOfWidths<[16, 32]>; def SPV_Vector : VectorOfLengthAndType<[2, 3, 4], @@ -3034,9 +3035,18 @@ def SPV_Type : AnyTypeOf<[ def SPV_SignlessOrUnsignedInt : SignlessOrUnsignedIntOfWidths<[8, 16, 32, 64]>; +class SPV_CoopMatrixOfType allowedTypes> : + ContainerType, SPV_IsCooperativeMatrixType, + "$_self.cast<::mlir::spirv::CooperativeMatrixNVType>().getElementType()", + "Cooperative Matrix">; + class SPV_ScalarOrVectorOf : AnyTypeOf<[type, VectorOfLengthAndType<[2, 3, 4], [type]>]>; +class SPV_ScalarOrVectorOrCoopMatrixOf : + AnyTypeOf<[type, VectorOfLengthAndType<[2, 3, 4], [type]>, + SPV_CoopMatrixOfType<[type]>]>; + def SPV_ScalarOrVector : AnyTypeOf<[SPV_Scalar, SPV_Vector]>; def SPV_ScalarOrVectorOrPtr : AnyTypeOf<[SPV_ScalarOrVector, SPV_AnyPtr]>; @@ -3227,6 +3237,9 @@ def SPV_OC_OpGroupNonUniformFMax : I32EnumAttrCase<"OpGroupNonUniformFMax" def SPV_OC_OpSubgroupBallotKHR : I32EnumAttrCase<"OpSubgroupBallotKHR", 4421>; def SPV_OC_OpTypeCooperativeMatrixNV : I32EnumAttrCase<"OpTypeCooperativeMatrixNV", 5358>; def SPV_OC_OpCooperativeMatrixLoadNV : I32EnumAttrCase<"OpCooperativeMatrixLoadNV", 5359>; +def SPV_OC_OpCooperativeMatrixStoreNV : I32EnumAttrCase<"OpCooperativeMatrixStoreNV", 5360>; +def SPV_OC_OpCooperativeMatrixMulAddNV : I32EnumAttrCase<"OpCooperativeMatrixMulAddNV", 5361>; +def SPV_OC_OpCooperativeMatrixLengthNV : I32EnumAttrCase<"OpCooperativeMatrixLengthNV", 5362>; def SPV_OpcodeAttr : SPV_I32EnumAttr<"Opcode", "valid SPIR-V instructions", [ @@ -3279,7 +3292,9 @@ def SPV_OpcodeAttr : SPV_OC_OpGroupNonUniformUMin, SPV_OC_OpGroupNonUniformFMin, SPV_OC_OpGroupNonUniformSMax, SPV_OC_OpGroupNonUniformUMax, SPV_OC_OpGroupNonUniformFMax, SPV_OC_OpSubgroupBallotKHR, - SPV_OC_OpTypeCooperativeMatrixNV, SPV_OC_OpCooperativeMatrixLoadNV + SPV_OC_OpTypeCooperativeMatrixNV, SPV_OC_OpCooperativeMatrixLoadNV, + SPV_OC_OpCooperativeMatrixStoreNV, SPV_OC_OpCooperativeMatrixMulAddNV, + SPV_OC_OpCooperativeMatrixLengthNV ]>; // End opcode section. Generated from SPIR-V spec; DO NOT MODIFY! diff --git a/mlir/include/mlir/Dialect/SPIRV/SPIRVCastOps.td b/mlir/include/mlir/Dialect/SPIRV/SPIRVCastOps.td index 8a64e48d56c0f3..c67c8d5e45423b 100644 --- a/mlir/include/mlir/Dialect/SPIRV/SPIRVCastOps.td +++ b/mlir/include/mlir/Dialect/SPIRV/SPIRVCastOps.td @@ -23,11 +23,11 @@ class SPV_CastOp { let arguments = (ins - SPV_ScalarOrVectorOf:$operand + SPV_ScalarOrVectorOrCoopMatrixOf:$operand ); let results = (outs - SPV_ScalarOrVectorOf:$result + SPV_ScalarOrVectorOrCoopMatrixOf:$result ); let parser = [{ return mlir::impl::parseCastOp(parser, result); }]; diff --git a/mlir/include/mlir/Dialect/SPIRV/SPIRVCooperativeMatrixOps.td b/mlir/include/mlir/Dialect/SPIRV/SPIRVCooperativeMatrixOps.td index 931f56f587553e..4645765b66babf 100644 --- a/mlir/include/mlir/Dialect/SPIRV/SPIRVCooperativeMatrixOps.td +++ b/mlir/include/mlir/Dialect/SPIRV/SPIRVCooperativeMatrixOps.td @@ -15,6 +15,49 @@ // ----- +def SPV_CooperativeMatrixLengthNVOp : SPV_Op<"CooperativeMatrixLengthNV", + [NoSideEffect]> { + let summary = "See extension SPV_NV_cooperative_matrix"; + + let description = [{ + Number of components of a cooperative matrix type accessible to each + invocation when treated as a composite. + + Result Type must be an OpTypeInt with 32-bit Width and 0 Signedness. + + Type is a cooperative matrix type. + + ``` {.ebnf} + cooperative-matrix-length-op ::= ssa-id `=` `spv.CooperativeMatrixLengthNV + ` : ` cooperative-matrix-type + ``` + + For example: + + ``` + %0 = spv.CooperativeMatrixLengthNV : !spv.coopmatrix + ``` + }]; + + let availability = [ + MinVersion, + MaxVersion, + Extension<[SPV_NV_cooperative_matrix]>, + Capability<[SPV_C_CooperativeMatrixNV]> + ]; + + let arguments = (ins + TypeAttr:$type + ); + + let results = (outs + SPV_Int32:$result + ); + let verifier = [{ return success(); }]; +} + +// ----- + def SPV_CooperativeMatrixLoadNVOp : SPV_Op<"CooperativeMatrixLoadNV", []> { let summary = "See extension SPV_NV_cooperative_matrix"; @@ -55,9 +98,10 @@ def SPV_CooperativeMatrixLoadNVOp : SPV_Op<"CooperativeMatrixLoadNV", []> { ### Custom assembly form ``` {.ebnf} - cooperative-matrix-op ::= ssa-id `=` `spv.CooperativeMatrixLoadNV` - storage-class ssa-use (`[` memory-access `]`)? ` - : ` cooperative-matrix-type + cooperative-matrixload-op ::= ssa-id `=` `spv.CooperativeMatrixLoadNV` + storage-class ssa-use `,` ssa-use `,` ssa-use + (`[` memory-access `]`)? ` : ` + cooperative-matrix-type ``` For example: @@ -86,7 +130,147 @@ def SPV_CooperativeMatrixLoadNVOp : SPV_Op<"CooperativeMatrixLoadNV", []> { SPV_AnyCooperativeMatrix:$result ); - let verifier = [{ return success(); }]; + let verifier = [{ + return verifyPointerAndCoopMatrixType(*this, pointer().getType(), + result().getType()); + }]; +} + +// ----- + +def SPV_CooperativeMatrixMulAddNVOp : SPV_Op<"CooperativeMatrixMulAddNV", + [NoSideEffect]> { + let summary = "See extension SPV_NV_cooperative_matrix"; + + let description = [{ + Linear-algebraic matrix multiply of A by B and then component-wise add C. + The order of the operations is implementation-dependent. The internal + precision of floating-point operations is defined by the client API. + Integer operations are performed at the precision of the Result Type and are + exact unless there is overflow or underflow, in which case the result is + undefined. + + Result Type must be a cooperative matrix type with M rows and N columns. + + A is a cooperative matrix with M rows and K columns. + + B is a cooperative matrix with K rows and N columns. + + C is a cooperative matrix with M rows and N columns. + + The values of M, N, and K must be consistent across the result and operands. + This is referred to as an MxNxK matrix multiply. + + A, B, C, and Result Type must have the same scope, and this defines the + scope of the operation. A, B, C, and Result Type need not necessarily have + the same component type, this is defined by the client API. + + If the Component Type of any matrix operand is an integer type, then its + components are treated as signed if its Component Type has Signedness of 1 + and are treated as unsigned otherwise. + + For a given dynamic instance of this instruction, all invocations in a given + scope instance must be active or all must be inactive (where the scope is + the scope of the operation). + + ``` {.ebnf} + cooperative-matrixmuladd-op ::= ssa-id `=` `spv.CooperativeMatrixMulAddNV` + ssa-use `,` ssa-use `,` ssa-use ` : ` + a-cooperative-matrix-type, + b-cooperative-matrix-type -> + result-cooperative-matrix-type + ``` + For example: + + ``` + %0 = spv.CooperativeMatrixMulAddNV %arg0, %arg1, %arg2, : + !spv.coopmatrix + ``` + }]; + + let availability = [ + MinVersion, + MaxVersion, + Extension<[SPV_NV_cooperative_matrix]>, + Capability<[SPV_C_CooperativeMatrixNV]> + ]; + + let arguments = (ins + SPV_AnyCooperativeMatrix:$a, + SPV_AnyCooperativeMatrix:$b, + SPV_AnyCooperativeMatrix:$c + ); + + let results = (outs + SPV_AnyCooperativeMatrix:$result + ); + + let verifier = [{ return verifyCoopMatrixMulAdd(*this); }]; +} + +// ----- + +def SPV_CooperativeMatrixStoreNVOp : SPV_Op<"CooperativeMatrixStoreNV", []> { + let summary = "See extension SPV_NV_cooperative_matrix"; + + let description = [{ + Store a cooperative matrix through a pointer. + + Pointer is a pointer into an array. Its type must be an OpTypePointer whose + Type operand is a scalar or vector type. The storage class of Pointer must + be Workgroup, StorageBuffer, or (if SPV_EXT_physical_storage_buffer is + supported) PhysicalStorageBufferEXT. + + Object is the object to store. Its type must be an + OpTypeCooperativeMatrixNV. + + Stride is the number of elements in the array in memory between the first + component of consecutive rows (or columns) in the result. It must be a + scalar integer type. + + ColumnMajor indicates whether the values stored to memory are arranged in + column-major or row-major order. It must be a boolean constant instruction, + with false indicating row major and true indicating column major. + + Memory Access must be a Memory Access literal. If not present, it is the + same as specifying None. + + ``` {.ebnf} + coop-matrix-store-op ::= `spv.CooperativeMatrixStoreNV ` + storage-class ssa-use `, ` ssa-use `, ` + ssa-use `, ` ssa-use `, ` + (`[` memory-access `]`)? `:` spirv-element-type + ``` + + For example: + + ``` + spv.CooperativeMatrixStoreNV "StorageBuffer" %arg0, %arg2, %arg1, %arg3 : + !spv.coopmatrix + ``` + }]; + + let availability = [ + MinVersion, + MaxVersion, + Extension<[SPV_NV_cooperative_matrix]>, + Capability<[SPV_C_CooperativeMatrixNV]> + ]; + + let arguments = (ins + SPV_AnyPtr:$pointer, + SPV_AnyCooperativeMatrix:$object, + SPV_Integer:$stride, + SPV_Bool:$columnmajor, + OptionalAttr:$memory_access + ); + + let results = (outs); + + let verifier = [{ + return verifyPointerAndCoopMatrixType(*this, pointer().getType(), + object().getType()); + }]; } // ----- diff --git a/mlir/lib/Dialect/SPIRV/SPIRVOps.cpp b/mlir/lib/Dialect/SPIRV/SPIRVOps.cpp index eed597b1d21c2d..630f09842ccdf6 100644 --- a/mlir/lib/Dialect/SPIRV/SPIRVOps.cpp +++ b/mlir/lib/Dialect/SPIRV/SPIRVOps.cpp @@ -213,6 +213,13 @@ static LogicalResult verifyCastOp(Operation *op, resultType = resultType.cast().getElementType(); } + if (auto coopMatrixType = + operandType.dyn_cast()) { + operandType = coopMatrixType.getElementType(); + resultType = + resultType.cast().getElementType(); + } + auto operandTypeBitWidth = operandType.getIntOrFloatBitWidth(); auto resultTypeBitWidth = resultType.getIntOrFloatBitWidth(); auto isSameBitWidth = operandTypeBitWidth == resultTypeBitWidth; @@ -2662,6 +2669,138 @@ static void print(spirv::CooperativeMatrixLoadNVOp M, OpAsmPrinter &printer) { printer << " : " << M.getType(); } +static LogicalResult verifyPointerAndCoopMatrixType(Operation *op, Type pointer, + Type coopMatrix) { + if (pointer.cast().getPointeeType() != + coopMatrix.cast().getElementType()) + return op->emitError( + "expected the same type for pointer and the cooperative matrix" + "element, bu provided ") + << pointer << " and " << coopMatrix; + return success(); +} + +//===----------------------------------------------------------------------===// +// spv.CooperativeMatrixStoreNV +//===----------------------------------------------------------------------===// + +static ParseResult parseCooperativeMatrixStoreNVOp(OpAsmParser &parser, + OperationState &state) { + spirv::StorageClass storageClass; + SmallVector operandInfo; + Type strideType = parser.getBuilder().getIntegerType(32); + Type columnMajorType = parser.getBuilder().getIntegerType(1); + Type elementType; + if (parseEnumStrAttr(storageClass, parser) || + parser.parseOperandList(operandInfo, 4) || + parseMemoryAccessAttributes(parser, state) || parser.parseColon() || + parser.parseType(elementType)) { + return failure(); + } + + auto ptrType = spirv::PointerType::get( + elementType.cast().getElementType(), + storageClass); + SmallVector OperandType = {ptrType, elementType, strideType, + columnMajorType}; + if (parser.resolveOperands(operandInfo, OperandType, parser.getNameLoc(), + state.operands)) { + return failure(); + } + + return success(); +} + +static void print(spirv::CooperativeMatrixStoreNVOp coopMatrix, + OpAsmPrinter &printer) { + StringRef sc = stringifyStorageClass(coopMatrix.pointer() + .getType() + .cast() + .getStorageClass()); + printer << spirv::CooperativeMatrixStoreNVOp::getOperationName() << " \"" + << sc << "\" " << coopMatrix.pointer() << ", " << coopMatrix.object() + << ", " << coopMatrix.stride() << ", " << coopMatrix.columnmajor(); + // Print optional memory access attribute. + if (auto memAccess = coopMatrix.memory_access()) + printer << " [\"" << stringifyMemoryAccess(*memAccess) << "\"]"; + printer << " : " << coopMatrix.getOperand(1).getType(); +} + +//===----------------------------------------------------------------------===// +// spv.CooperativeMatrixLengthNV +//===----------------------------------------------------------------------===// + +static ParseResult parseCooperativeMatrixLengthNVOp(OpAsmParser &parser, + OperationState &state) { + OpAsmParser::OperandType operandInfo; + Type dstType = parser.getBuilder().getIntegerType(32); + Type type; + if (parser.parseColonType(type)) { + return failure(); + } + state.addAttribute(kTypeAttrName, TypeAttr::get(type)); + state.addTypes(dstType); + return success(); +} + +static void print(spirv::CooperativeMatrixLengthNVOp coopMatrix, + OpAsmPrinter &printer) { + printer << coopMatrix.getOperationName() << " : " << coopMatrix.type(); +} + +//===----------------------------------------------------------------------===// +// spv.CooperativeMatrixMulAddNV +//===----------------------------------------------------------------------===// + +static ParseResult parseCooperativeMatrixMulAddNVOp(OpAsmParser &parser, + OperationState &state) { + SmallVector ops; + SmallVector types(3); + if (parser.parseOperandList(ops, 3) || parser.parseColon() || + parser.parseType(types[0]) || parser.parseComma() || + parser.parseType(types[1]) || parser.parseArrow() || + parser.parseType(types[2]) || + parser.resolveOperands(ops, types, parser.getNameLoc(), state.operands)) { + return failure(); + } + state.addTypes(types[2]); + return success(); +} + +static void print(spirv::CooperativeMatrixMulAddNVOp coopMatrix, + OpAsmPrinter &printer) { + printer << coopMatrix.getOperationName() << ' ' << coopMatrix.getOperand(0) + << ", " << coopMatrix.getOperand(1) << ", " + << coopMatrix.getOperand(2) << ", " + << " : " << coopMatrix.getOperand(0).getType() << ", " + << coopMatrix.getOperand(1).getType() << " -> " + << coopMatrix.getOperand(2).getType(); +} + +static LogicalResult +verifyCoopMatrixMulAdd(spirv::CooperativeMatrixMulAddNVOp op) { + if (op.c().getType() != op.result().getType()) + return op.emitOpError( + "result and third operand must have the same type"); + auto typeA = op.a().getType().cast(); + auto typeB = op.b().getType().cast(); + auto typeC = op.c().getType().cast(); + auto typeR = op.result().getType().cast(); + if (typeA.getRows() != typeR.getRows() || + typeA.getColumns() != typeB.getRows() || + typeB.getColumns() != typeR.getColumns()) + return op.emitOpError("matrix size must match"); + if (typeR.getScope() != typeA.getScope() || + typeR.getScope() != typeB.getScope() || + typeR.getScope() != typeC.getScope()) + return op.emitOpError("matrix scope must match"); + if (typeR.getElementType() != typeA.getElementType() || + typeR.getElementType() != typeB.getElementType() || + typeR.getElementType() != typeC.getElementType()) + return op.emitOpError("matrix element type must match"); + return success(); +} + namespace mlir { namespace spirv { diff --git a/mlir/test/Dialect/SPIRV/Serialization/cooperative-matrix.mlir b/mlir/test/Dialect/SPIRV/Serialization/cooperative-matrix.mlir index e90996ee24b79e..6fb58d859d1f56 100644 --- a/mlir/test/Dialect/SPIRV/Serialization/cooperative-matrix.mlir +++ b/mlir/test/Dialect/SPIRV/Serialization/cooperative-matrix.mlir @@ -14,4 +14,81 @@ spv.module Logical GLSL450 requires #spv.vce spv.Return } + + // CHECK-LABEL: @cooperative_matrix_store + spv.func @cooperative_matrix_store(%ptr : !spv.ptr, %stride : i32, %m : !spv.coopmatrix<16x8xi32, Workgroup>, %b : i1) "None" { + // CHECK: spv.CooperativeMatrixStoreNV "StorageBuffer" {{%.*}}, {{%.*}}, {{%.*}} : !spv.coopmatrix<16x8xi32, Workgroup> + spv.CooperativeMatrixStoreNV "StorageBuffer" %ptr, %m, %stride, %b : !spv.coopmatrix<16x8xi32, Workgroup> + spv.Return + } + + // CHECK-LABEL: @cooperative_matrix_store_memaccess + spv.func @cooperative_matrix_store_memaccess(%ptr : !spv.ptr, %m : !spv.coopmatrix<8x16xi32, Subgroup>, %stride : i32, %b : i1) "None" { + // CHECK: spv.CooperativeMatrixStoreNV "StorageBuffer" {{%.*}}, {{%.*}}, {{%.*}} ["Volatile"] : !spv.coopmatrix<8x16xi32, Subgroup> + spv.CooperativeMatrixStoreNV "StorageBuffer" %ptr, %m, %stride, %b ["Volatile"] : !spv.coopmatrix<8x16xi32, Subgroup> + spv.Return + } + + // CHECK-LABEL: @cooperative_matrix_length + spv.func @cooperative_matrix_length() -> i32 "None" { + // CHECK: {{%.*}} = spv.CooperativeMatrixLengthNV : !spv.coopmatrix<8x16xi32, Subgroup> + %0 = spv.CooperativeMatrixLengthNV : !spv.coopmatrix<8x16xi32, Subgroup> + spv.ReturnValue %0 : i32 + } + + // CHECK-LABEL: @cooperative_matrix_muladd + spv.func @cooperative_matrix_muladd(%a : !spv.coopmatrix<8x16xi32, Subgroup>, %b : !spv.coopmatrix<16x8xi32, Subgroup>, %c : !spv.coopmatrix<8x8xi32, Subgroup>) "None" { + // CHECK: {{%.*}} = spv.CooperativeMatrixMulAddNV {{%.*}}, {{%.*}}, {{%.*}}, : !spv.coopmatrix<8x16xi32, Subgroup>, !spv.coopmatrix<16x8xi32, Subgroup> -> !spv.coopmatrix<8x8xi32, Subgroup> + %r = spv.CooperativeMatrixMulAddNV %a, %b, %c : !spv.coopmatrix<8x16xi32, Subgroup>, !spv.coopmatrix<16x8xi32, Subgroup> -> !spv.coopmatrix<8x8xi32, Subgroup> + spv.Return + } + + // CHECK-LABEL: @cooperative_matrix_add + spv.func @cooperative_matrix_add(%a : !spv.coopmatrix<8x16xi32, Subgroup>, %b : !spv.coopmatrix<8x16xi32, Subgroup>) "None" { + // CHECK: {{%.*}} = spv.IAdd {{%.*}}, {{%.*}} : !spv.coopmatrix<8x16xi32, Subgroup> + %r = spv.IAdd %a, %b : !spv.coopmatrix<8x16xi32, Subgroup> + spv.Return + } + + // CHECK-LABEL: @cooperative_matrix_sub + spv.func @cooperative_matrix_sub(%a : !spv.coopmatrix<8x16xi32, Subgroup>, %b : !spv.coopmatrix<8x16xi32, Subgroup>) "None" { + // CHECK: {{%.*}} = spv.ISub {{%.*}}, {{%.*}} : !spv.coopmatrix<8x16xi32, Subgroup> + %r = spv.ISub %a, %b : !spv.coopmatrix<8x16xi32, Subgroup> + spv.Return + } + + // CHECK-LABEL: @cooperative_matrix_sdiv + spv.func @cooperative_matrix_sdiv(%a : !spv.coopmatrix<8x16xi32, Subgroup>, %b : !spv.coopmatrix<8x16xi32, Subgroup>) "None" { + // CHECK: {{%.*}} = spv.SDiv {{%.*}}, {{%.*}} : !spv.coopmatrix<8x16xi32, Subgroup> + %r = spv.SDiv %a, %b : !spv.coopmatrix<8x16xi32, Subgroup> + spv.Return + } + + // CHECK-LABEL: @cooperative_matrix_udiv + spv.func @cooperative_matrix_udiv(%a : !spv.coopmatrix<8x16xi32, Subgroup>, %b : !spv.coopmatrix<8x16xi32, Subgroup>) "None" { + // CHECK: {{%.*}} = spv.UDiv {{%.*}}, {{%.*}} : !spv.coopmatrix<8x16xi32, Subgroup> + %r = spv.UDiv %a, %b : !spv.coopmatrix<8x16xi32, Subgroup> + spv.Return + } + + // CHECK-LABEL: @cooperative_matrix_fadd + spv.func @cooperative_matrix_fadd(%a : !spv.coopmatrix<8x16xf32, Subgroup>, %b : !spv.coopmatrix<8x16xf32, Subgroup>) "None" { + // CHECK: {{%.*}} = spv.FAdd {{%.*}}, {{%.*}} : !spv.coopmatrix<8x16xf32, Subgroup> + %r = spv.FAdd %a, %b : !spv.coopmatrix<8x16xf32, Subgroup> + spv.Return + } + + // CHECK-LABEL: @cooperative_matrix_fsub + spv.func @cooperative_matrix_fsub(%a : !spv.coopmatrix<8x16xf32, Subgroup>, %b : !spv.coopmatrix<8x16xf32, Subgroup>) "None" { + // CHECK: {{%.*}} = spv.FSub {{%.*}}, {{%.*}} : !spv.coopmatrix<8x16xf32, Subgroup> + %r = spv.FSub %a, %b : !spv.coopmatrix<8x16xf32, Subgroup> + spv.Return + } + + // CHECK-LABEL: @cooperative_matrix_fdiv + spv.func @cooperative_matrix_fdiv(%a : !spv.coopmatrix<8x16xf32, Subgroup>, %b : !spv.coopmatrix<8x16xf32, Subgroup>) "None" { + // CHECK: {{%.*}} = spv.FDiv {{%.*}}, {{%.*}} : !spv.coopmatrix<8x16xf32, Subgroup> + %r = spv.FDiv %a, %b : !spv.coopmatrix<8x16xf32, Subgroup> + spv.Return + } } diff --git a/mlir/test/Dialect/SPIRV/cooperative-matrix.mlir b/mlir/test/Dialect/SPIRV/cooperative-matrix.mlir index c121943acf8279..0b05d8a587e522 100644 --- a/mlir/test/Dialect/SPIRV/cooperative-matrix.mlir +++ b/mlir/test/Dialect/SPIRV/cooperative-matrix.mlir @@ -14,3 +14,113 @@ spv.func @cooperative_matrix_load_memaccess(%ptr : !spv.ptr, %0 = spv.CooperativeMatrixLoadNV "StorageBuffer" %ptr, %stride, %b ["Volatile"] : !spv.coopmatrix<8x16xi32, Subgroup> spv.Return } + +// CHECK-LABEL: @cooperative_matrix_store +spv.func @cooperative_matrix_store(%ptr : !spv.ptr, %stride : i32, %m : !spv.coopmatrix<8x16xi32, Workgroup>, %b : i1) "None" { + // CHECK: spv.CooperativeMatrixStoreNV "StorageBuffer" {{%.*}}, {{%.*}}, {{%.*}} : !spv.coopmatrix<8x16xi32, Workgroup> + spv.CooperativeMatrixStoreNV "StorageBuffer" %ptr, %m, %stride, %b : !spv.coopmatrix<8x16xi32, Workgroup> + spv.Return +} + +// CHECK-LABEL: @cooperative_matrix_store_memaccess +spv.func @cooperative_matrix_store_memaccess(%ptr : !spv.ptr, %m : !spv.coopmatrix<8x16xi32, Subgroup>, %stride : i32, %b : i1) "None" { + // CHECK: spv.CooperativeMatrixStoreNV "StorageBuffer" {{%.*}}, {{%.*}}, {{%.*}} ["Volatile"] : !spv.coopmatrix<8x16xi32, Subgroup> + spv.CooperativeMatrixStoreNV "StorageBuffer" %ptr, %m, %stride, %b ["Volatile"] : !spv.coopmatrix<8x16xi32, Subgroup> + spv.Return +} + +// CHECK-LABEL: @cooperative_matrix_length +spv.func @cooperative_matrix_length() -> i32 "None" { + // CHECK: {{%.*}} = spv.CooperativeMatrixLengthNV : !spv.coopmatrix<8x16xi32, Subgroup> + %0 = spv.CooperativeMatrixLengthNV : !spv.coopmatrix<8x16xi32, Subgroup> + spv.ReturnValue %0 : i32 +} + +// CHECK-LABEL: @cooperative_matrix_muladd +spv.func @cooperative_matrix_muladd(%a : !spv.coopmatrix<8x16xi32, Subgroup>, %b : !spv.coopmatrix<16x8xi32, Subgroup>, %c : !spv.coopmatrix<8x8xi32, Subgroup>) "None" { + // CHECK: {{%.*}} = spv.CooperativeMatrixMulAddNV {{%.*}}, {{%.*}}, {{%.*}}, : !spv.coopmatrix<8x16xi32, Subgroup>, !spv.coopmatrix<16x8xi32, Subgroup> -> !spv.coopmatrix<8x8xi32, Subgroup> + %r = spv.CooperativeMatrixMulAddNV %a, %b, %c : !spv.coopmatrix<8x16xi32, Subgroup>, !spv.coopmatrix<16x8xi32, Subgroup> -> !spv.coopmatrix<8x8xi32, Subgroup> + spv.Return +} + +// CHECK-LABEL: @cooperative_matrix_add +spv.func @cooperative_matrix_add(%a : !spv.coopmatrix<8x16xi32, Subgroup>, %b : !spv.coopmatrix<8x16xi32, Subgroup>) "None" { + // CHECK: {{%.*}} = spv.IAdd {{%.*}}, {{%.*}} : !spv.coopmatrix<8x16xi32, Subgroup> + %r = spv.IAdd %a, %b : !spv.coopmatrix<8x16xi32, Subgroup> + spv.Return +} + +// CHECK-LABEL: @cooperative_matrix_sub +spv.func @cooperative_matrix_sub(%a : !spv.coopmatrix<8x16xi32, Subgroup>, %b : !spv.coopmatrix<8x16xi32, Subgroup>) "None" { + // CHECK: {{%.*}} = spv.ISub {{%.*}}, {{%.*}} : !spv.coopmatrix<8x16xi32, Subgroup> + %r = spv.ISub %a, %b : !spv.coopmatrix<8x16xi32, Subgroup> + spv.Return +} + +// CHECK-LABEL: @cooperative_matrix_sdiv +spv.func @cooperative_matrix_sdiv(%a : !spv.coopmatrix<8x16xi32, Subgroup>, %b : !spv.coopmatrix<8x16xi32, Subgroup>) "None" { + // CHECK: {{%.*}} = spv.SDiv {{%.*}}, {{%.*}} : !spv.coopmatrix<8x16xi32, Subgroup> + %r = spv.SDiv %a, %b : !spv.coopmatrix<8x16xi32, Subgroup> + spv.Return +} + +// CHECK-LABEL: @cooperative_matrix_udiv +spv.func @cooperative_matrix_udiv(%a : !spv.coopmatrix<8x16xi32, Subgroup>, %b : !spv.coopmatrix<8x16xi32, Subgroup>) "None" { + // CHECK: {{%.*}} = spv.UDiv {{%.*}}, {{%.*}} : !spv.coopmatrix<8x16xi32, Subgroup> + %r = spv.UDiv %a, %b : !spv.coopmatrix<8x16xi32, Subgroup> + spv.Return +} + +// CHECK-LABEL: @cooperative_matrix_fadd +spv.func @cooperative_matrix_fadd(%a : !spv.coopmatrix<8x16xf32, Subgroup>, %b : !spv.coopmatrix<8x16xf32, Subgroup>) "None" { + // CHECK: {{%.*}} = spv.FAdd {{%.*}}, {{%.*}} : !spv.coopmatrix<8x16xf32, Subgroup> + %r = spv.FAdd %a, %b : !spv.coopmatrix<8x16xf32, Subgroup> + spv.Return +} + +// CHECK-LABEL: @cooperative_matrix_fsub +spv.func @cooperative_matrix_fsub(%a : !spv.coopmatrix<8x16xf32, Subgroup>, %b : !spv.coopmatrix<8x16xf32, Subgroup>) "None" { + // CHECK: {{%.*}} = spv.FSub {{%.*}}, {{%.*}} : !spv.coopmatrix<8x16xf32, Subgroup> + %r = spv.FSub %a, %b : !spv.coopmatrix<8x16xf32, Subgroup> + spv.Return +} + +// CHECK-LABEL: @cooperative_matrix_fdiv +spv.func @cooperative_matrix_fdiv(%a : !spv.coopmatrix<8x16xf32, Subgroup>, %b : !spv.coopmatrix<8x16xf32, Subgroup>) "None" { + // CHECK: {{%.*}} = spv.FDiv {{%.*}}, {{%.*}} : !spv.coopmatrix<8x16xf32, Subgroup> + %r = spv.FDiv %a, %b : !spv.coopmatrix<8x16xf32, Subgroup> + spv.Return +} + +// ----- + +spv.func @cooperative_matrix_muladd(%a : !spv.coopmatrix<16x16xi32, Subgroup>, %b : !spv.coopmatrix<16x8xi32, Subgroup>, %c : !spv.coopmatrix<8x8xi32, Subgroup>) "None" { + // expected-error @+1 {{'spv.CooperativeMatrixMulAddNV' op matrix size must match}} + %r = spv.CooperativeMatrixMulAddNV %a, %b, %c : !spv.coopmatrix<16x16xi32, Subgroup>, !spv.coopmatrix<16x8xi32, Subgroup> -> !spv.coopmatrix<8x8xi32, Subgroup> + spv.Return +} + +// ----- + +spv.func @cooperative_matrix_muladd(%a : !spv.coopmatrix<8x16xi32, Subgroup>, %b : !spv.coopmatrix<8x8xi32, Subgroup>, %c : !spv.coopmatrix<8x8xi32, Subgroup>) "None" { + // expected-error @+1 {{'spv.CooperativeMatrixMulAddNV' op matrix size must match}} + %r = spv.CooperativeMatrixMulAddNV %a, %b, %c : !spv.coopmatrix<8x16xi32, Subgroup>, !spv.coopmatrix<8x8xi32, Subgroup> -> !spv.coopmatrix<8x8xi32, Subgroup> + spv.Return +} + +// ----- + +spv.func @cooperative_matrix_muladd(%a : !spv.coopmatrix<8x16xi32, Subgroup>, %b : !spv.coopmatrix<16x8xi32, Workgroup>, %c : !spv.coopmatrix<8x8xi32, Subgroup>) "None" { + // expected-error @+1 {{'spv.CooperativeMatrixMulAddNV' op matrix scope must match}} + %r = spv.CooperativeMatrixMulAddNV %a, %b, %c : !spv.coopmatrix<8x16xi32, Subgroup>, !spv.coopmatrix<16x8xi32, Workgroup> -> !spv.coopmatrix<8x8xi32, Subgroup> + spv.Return +} + +// ----- + +spv.func @cooperative_matrix_muladd(%a : !spv.coopmatrix<8x16xf32, Subgroup>, %b : !spv.coopmatrix<16x8xi32, Subgroup>, %c : !spv.coopmatrix<8x8xi32, Subgroup>) "None" { + // expected-error @+1 {{matrix element type must match}} + %r = spv.CooperativeMatrixMulAddNV %a, %b, %c : !spv.coopmatrix<8x16xf32, Subgroup>, !spv.coopmatrix<16x8xi32, Subgroup> -> !spv.coopmatrix<8x8xi32, Subgroup> + spv.Return +} + diff --git a/mlir/test/Dialect/SPIRV/ops.mlir b/mlir/test/Dialect/SPIRV/ops.mlir index 5cf91c0b09b964..14e1fa10735eb5 100644 --- a/mlir/test/Dialect/SPIRV/ops.mlir +++ b/mlir/test/Dialect/SPIRV/ops.mlir @@ -328,6 +328,14 @@ func @convert_f_to_u_vector(%arg0 : vector<3xf32>) -> vector<3xi32> { // ----- +func @convert_f_to_u_coopmatrix(%arg0 : !spv.coopmatrix<8x16xf32, Subgroup>) { + // CHECK: {{%.*}} = spv.ConvertFToU {{%.*}} : !spv.coopmatrix<8x16xf32, Subgroup> to !spv.coopmatrix<8x16xi32, Subgroup> + %0 = spv.ConvertFToU %arg0 : !spv.coopmatrix<8x16xf32, Subgroup> to !spv.coopmatrix<8x16xi32, Subgroup> + spv.Return +} + +// ----- + func @convert_f_to_u_scalar_invalid(%arg0 : f16) -> i32 { // expected-error @+1 {{expected the same bit widths for operand type and result type, but provided 'f16' and 'i32'}} %0 = spv.ConvertFToU %arg0 : f16 to i32 @@ -380,6 +388,14 @@ func @f_convert_vector(%arg0 : vector<3xf32>) -> vector<3xf64> { // ----- +func @f_convert_coop_matrix(%arg0 : !spv.coopmatrix<8x16xf32, Subgroup>) { + // CHECK: {{%.*}} = spv.FConvert {{%.*}} : !spv.coopmatrix<8x16xf32, Subgroup> to !spv.coopmatrix<8x16xf64, Subgroup> + %0 = spv.FConvert %arg0 : !spv.coopmatrix<8x16xf32, Subgroup> to !spv.coopmatrix<8x16xf64, Subgroup> + spv.Return +} + +// ----- + func @f_convert_vector(%arg0 : f32) -> f32 { // expected-error @+1 {{expected the different bit widths for operand type and result type, but provided 'f32' and 'f32'}} %0 = spv.FConvert %arg0 : f32 to f32 diff --git a/mlir/tools/mlir-tblgen/SPIRVUtilsGen.cpp b/mlir/tools/mlir-tblgen/SPIRVUtilsGen.cpp index 73418b83172199..e860dbc3fb5857 100644 --- a/mlir/tools/mlir-tblgen/SPIRVUtilsGen.cpp +++ b/mlir/tools/mlir-tblgen/SPIRVUtilsGen.cpp @@ -508,6 +508,11 @@ static void emitAttributeSerialization(const Attribute &attr, << formatv(" {0}.push_back(static_cast(" "attr.cast().getValue().getZExtValue()));\n", operandList); + } else if (attr.isEnumAttr() || attr.getAttrDefName() == "TypeAttr") { + os << tabs + << formatv(" {0}.push_back(static_cast(" + "getTypeID(attr.cast().getValue())));\n", + operandList); } else { PrintFatalError( loc, @@ -766,6 +771,11 @@ static void emitAttributeDeserialization(const Attribute &attr, << formatv("{0}.push_back(opBuilder.getNamedAttr(\"{1}\", " "opBuilder.getI32IntegerAttr({2}[{3}++])));\n", attrList, attrName, words, wordIndex); + } else if (attr.isEnumAttr() || attr.getAttrDefName() == "TypeAttr") { + os << tabs + << formatv("{0}.push_back(opBuilder.getNamedAttr(\"{1}\", " + "TypeAttr::get(getType({2}[{3}++]))));\n", + attrList, attrName, words, wordIndex); } else { PrintFatalError( loc, llvm::Twine( From 71bbe5d7999ac3506a18c0ba1f5bffe6d788cd6c Mon Sep 17 00:00:00 2001 From: Stanislav Mekhanoshin Date: Thu, 21 May 2020 11:58:35 -0700 Subject: [PATCH 11/14] [AMDGPU] Added opt pipeline test. NFC. --- llvm/test/CodeGen/AMDGPU/opt-pipeline.ll | 1028 ++++++++++++++++++++++ 1 file changed, 1028 insertions(+) create mode 100644 llvm/test/CodeGen/AMDGPU/opt-pipeline.ll diff --git a/llvm/test/CodeGen/AMDGPU/opt-pipeline.ll b/llvm/test/CodeGen/AMDGPU/opt-pipeline.ll new file mode 100644 index 00000000000000..0c8b0a7990657c --- /dev/null +++ b/llvm/test/CodeGen/AMDGPU/opt-pipeline.ll @@ -0,0 +1,1028 @@ +; RUN: opt -O0 -mtriple=amdgcn--amdhsa -disable-output -disable-verify -debug-pass=Structure %s 2>&1 | FileCheck -check-prefix=GCN-O0 %s +; RUN: opt -O1 -mtriple=amdgcn--amdhsa -disable-output -disable-verify -debug-pass=Structure %s 2>&1 | FileCheck -check-prefix=GCN-O1 %s +; RUN: opt -O2 -mtriple=amdgcn--amdhsa -disable-output -disable-verify -debug-pass=Structure %s 2>&1 | FileCheck -check-prefix=GCN-O2 %s +; RUN: opt -O3 -mtriple=amdgcn--amdhsa -disable-output -disable-verify -debug-pass=Structure %s 2>&1 | FileCheck -check-prefix=GCN-O3 %s + +; REQUIRES: asserts + +; GCN-O0: Pass Arguments: +; GCN-O0-NEXT: Target Transform Information +; GCN-O0-NEXT: FunctionPass Manager +; GCN-O0-NEXT: Early propagate attributes from kernels to functions +; GCN-O0-NEXT: Replace builtin math calls with that native versions. +; GCN-O0-NEXT: Instrument function entry/exit with calls to e.g. mcount() (pre inlining) + +; GCN-O0-NEXT: Pass Arguments: +; GCN-O0-NEXT: Target Library Information +; GCN-O0-NEXT: Target Transform Information +; GCN-O0-NEXT: Target Pass Configuration +; GCN-O0-NEXT: Assumption Cache Tracker +; GCN-O0-NEXT: Profile summary info +; GCN-O0-NEXT: ModulePass Manager +; GCN-O0-NEXT: Force set function attributes +; GCN-O0-NEXT: CallGraph Construction +; GCN-O0-NEXT: Call Graph SCC Pass Manager +; GCN-O0-NEXT: AMDGPU Function Integration/Inlining +; GCN-O0-NEXT: A No-Op Barrier Pass + + +; GCN-O1: Pass Arguments: +; GCN-O1-NEXT: Target Transform Information +; GCN-O1-NEXT: AMDGPU Address space based Alias Analysis +; GCN-O1-NEXT: External Alias Analysis +; GCN-O1-NEXT: Assumption Cache Tracker +; GCN-O1-NEXT: Target Library Information +; GCN-O1-NEXT: Type-Based Alias Analysis +; GCN-O1-NEXT: Scoped NoAlias Alias Analysis +; GCN-O1-NEXT: FunctionPass Manager +; GCN-O1-NEXT: Early propagate attributes from kernels to functions +; GCN-O1-NEXT: Replace builtin math calls with that native versions. +; GCN-O1-NEXT: Dominator Tree Construction +; GCN-O1-NEXT: Basic Alias Analysis (stateless AA impl) +; GCN-O1-NEXT: Function Alias Analysis Results +; GCN-O1-NEXT: Simplify well-known AMD library calls +; GCN-O1-NEXT: Instrument function entry/exit with calls to e.g. mcount() (pre inlining) +; GCN-O1-NEXT: Simplify the CFG +; GCN-O1-NEXT: Dominator Tree Construction +; GCN-O1-NEXT: SROA +; GCN-O1-NEXT: Early CSE +; GCN-O1-NEXT: Lower 'expect' Intrinsics + +; GCN-O1-NEXT: Pass Arguments: +; GCN-O1-NEXT: Target Library Information +; GCN-O1-NEXT: Target Transform Information +; GCN-O1-NEXT: Target Pass Configuration +; GCN-O1-NEXT: Type-Based Alias Analysis +; GCN-O1-NEXT: Scoped NoAlias Alias Analysis +; GCN-O1-NEXT: AMDGPU Address space based Alias Analysis +; GCN-O1-NEXT: External Alias Analysis +; GCN-O1-NEXT: Assumption Cache Tracker +; GCN-O1-NEXT: Profile summary info +; GCN-O1-NEXT: ModulePass Manager +; GCN-O1-NEXT: Force set function attributes +; GCN-O1-NEXT: Infer set function attributes +; GCN-O1-NEXT: Unify multiple OpenCL metadata due to linking +; GCN-O1-NEXT: AMDGPU Printf lowering +; GCN-O1-NEXT: FunctionPass Manager +; GCN-O1-NEXT: Dominator Tree Construction +; GCN-O1-NEXT: Late propagate attributes from kernels to functions +; GCN-O1-NEXT: Interprocedural Sparse Conditional Constant Propagation +; GCN-O1-NEXT: FunctionPass Manager +; GCN-O1-NEXT: Dominator Tree Construction +; GCN-O1-NEXT: Called Value Propagation +; GCN-O1-NEXT: Global Variable Optimizer +; GCN-O1-NEXT: FunctionPass Manager +; GCN-O1-NEXT: Dominator Tree Construction +; GCN-O1-NEXT: Natural Loop Information +; GCN-O1-NEXT: Post-Dominator Tree Construction +; GCN-O1-NEXT: Branch Probability Analysis +; GCN-O1-NEXT: Block Frequency Analysis +; GCN-O1-NEXT: FunctionPass Manager +; GCN-O1-NEXT: Dominator Tree Construction +; GCN-O1-NEXT: Promote Memory to Register +; GCN-O1-NEXT: Dead Argument Elimination +; GCN-O1-NEXT: FunctionPass Manager +; GCN-O1-NEXT: Dominator Tree Construction +; GCN-O1-NEXT: Basic Alias Analysis (stateless AA impl) +; GCN-O1-NEXT: Function Alias Analysis Results +; GCN-O1-NEXT: Natural Loop Information +; GCN-O1-NEXT: Lazy Branch Probability Analysis +; GCN-O1-NEXT: Lazy Block Frequency Analysis +; GCN-O1-NEXT: Optimization Remark Emitter +; GCN-O1-NEXT: Combine redundant instructions +; GCN-O1-NEXT: Simplify the CFG +; GCN-O1-NEXT: CallGraph Construction +; GCN-O1-NEXT: Globals Alias Analysis +; GCN-O1-NEXT: Call Graph SCC Pass Manager +; GCN-O1-NEXT: Remove unused exception handling info +; GCN-O1-NEXT: AMDGPU Function Integration/Inlining +; GCN-O1-NEXT: Deduce function attributes +; GCN-O1-NEXT: FunctionPass Manager +; GCN-O1-NEXT: Infer address spaces +; GCN-O1-NEXT: AMDGPU Kernel Attributes +; GCN-O1-NEXT: FunctionPass Manager +; GCN-O1-NEXT: Dominator Tree Construction +; GCN-O1-NEXT: SROA +; GCN-O1-NEXT: Basic Alias Analysis (stateless AA impl) +; GCN-O1-NEXT: Function Alias Analysis Results +; GCN-O1-NEXT: Memory SSA +; GCN-O1-NEXT: Early CSE w/ MemorySSA +; GCN-O1-NEXT: Simplify the CFG +; GCN-O1-NEXT: Dominator Tree Construction +; GCN-O1-NEXT: Basic Alias Analysis (stateless AA impl) +; GCN-O1-NEXT: Function Alias Analysis Results +; GCN-O1-NEXT: Natural Loop Information +; GCN-O1-NEXT: Lazy Branch Probability Analysis +; GCN-O1-NEXT: Lazy Block Frequency Analysis +; GCN-O1-NEXT: Optimization Remark Emitter +; GCN-O1-NEXT: Combine redundant instructions +; GCN-O1-NEXT: Conditionally eliminate dead library calls +; GCN-O1-NEXT: Natural Loop Information +; GCN-O1-NEXT: Post-Dominator Tree Construction +; GCN-O1-NEXT: Branch Probability Analysis +; GCN-O1-NEXT: Block Frequency Analysis +; GCN-O1-NEXT: Lazy Branch Probability Analysis +; GCN-O1-NEXT: Lazy Block Frequency Analysis +; GCN-O1-NEXT: Optimization Remark Emitter +; GCN-O1-NEXT: PGOMemOPSize +; GCN-O1-NEXT: Simplify the CFG +; GCN-O1-NEXT: Reassociate expressions +; GCN-O1-NEXT: Dominator Tree Construction +; GCN-O1-NEXT: Natural Loop Information +; GCN-O1-NEXT: Canonicalize natural loops +; GCN-O1-NEXT: LCSSA Verifier +; GCN-O1-NEXT: Loop-Closed SSA Form Pass +; GCN-O1-NEXT: Basic Alias Analysis (stateless AA impl) +; GCN-O1-NEXT: Function Alias Analysis Results +; GCN-O1-NEXT: Scalar Evolution Analysis +; GCN-O1-NEXT: Loop Pass Manager +; GCN-O1-NEXT: Rotate Loops +; GCN-O1-NEXT: Memory SSA +; GCN-O1-NEXT: Loop Pass Manager +; GCN-O1-NEXT: Loop Invariant Code Motion +; GCN-O1-NEXT: Post-Dominator Tree Construction +; GCN-O1-NEXT: Legacy Divergence Analysis +; GCN-O1-NEXT: Loop Pass Manager +; GCN-O1-NEXT: Unswitch loops +; GCN-O1-NEXT: Simplify the CFG +; GCN-O1-NEXT: Dominator Tree Construction +; GCN-O1-NEXT: Basic Alias Analysis (stateless AA impl) +; GCN-O1-NEXT: Function Alias Analysis Results +; GCN-O1-NEXT: Natural Loop Information +; GCN-O1-NEXT: Lazy Branch Probability Analysis +; GCN-O1-NEXT: Lazy Block Frequency Analysis +; GCN-O1-NEXT: Optimization Remark Emitter +; GCN-O1-NEXT: Combine redundant instructions +; GCN-O1-NEXT: Canonicalize natural loops +; GCN-O1-NEXT: LCSSA Verifier +; GCN-O1-NEXT: Loop-Closed SSA Form Pass +; GCN-O1-NEXT: Scalar Evolution Analysis +; GCN-O1-NEXT: Loop Pass Manager +; GCN-O1-NEXT: Induction Variable Simplification +; GCN-O1-NEXT: Recognize loop idioms +; GCN-O1-NEXT: Delete dead loops +; GCN-O1-NEXT: Unroll loops +; GCN-O1-NEXT: Phi Values Analysis +; GCN-O1-NEXT: Memory Dependence Analysis +; GCN-O1-NEXT: MemCpy Optimization +; GCN-O1-NEXT: Sparse Conditional Constant Propagation +; GCN-O1-NEXT: Demanded bits analysis +; GCN-O1-NEXT: Bit-Tracking Dead Code Elimination +; GCN-O1-NEXT: Function Alias Analysis Results +; GCN-O1-NEXT: Lazy Branch Probability Analysis +; GCN-O1-NEXT: Lazy Block Frequency Analysis +; GCN-O1-NEXT: Optimization Remark Emitter +; GCN-O1-NEXT: Combine redundant instructions +; GCN-O1-NEXT: Post-Dominator Tree Construction +; GCN-O1-NEXT: Aggressive Dead Code Elimination +; GCN-O1-NEXT: Simplify the CFG +; GCN-O1-NEXT: Dominator Tree Construction +; GCN-O1-NEXT: Basic Alias Analysis (stateless AA impl) +; GCN-O1-NEXT: Function Alias Analysis Results +; GCN-O1-NEXT: Natural Loop Information +; GCN-O1-NEXT: Lazy Branch Probability Analysis +; GCN-O1-NEXT: Lazy Block Frequency Analysis +; GCN-O1-NEXT: Optimization Remark Emitter +; GCN-O1-NEXT: Combine redundant instructions +; GCN-O1-NEXT: A No-Op Barrier Pass +; GCN-O1-NEXT: CallGraph Construction +; GCN-O1-NEXT: Deduce function attributes in RPO +; GCN-O1-NEXT: Global Variable Optimizer +; GCN-O1-NEXT: FunctionPass Manager +; GCN-O1-NEXT: Dominator Tree Construction +; GCN-O1-NEXT: Natural Loop Information +; GCN-O1-NEXT: Post-Dominator Tree Construction +; GCN-O1-NEXT: Branch Probability Analysis +; GCN-O1-NEXT: Block Frequency Analysis +; GCN-O1-NEXT: Dead Global Elimination +; GCN-O1-NEXT: CallGraph Construction +; GCN-O1-NEXT: Globals Alias Analysis +; GCN-O1-NEXT: FunctionPass Manager +; GCN-O1-NEXT: Dominator Tree Construction +; GCN-O1-NEXT: Float to int +; GCN-O1-NEXT: Lower constant intrinsics +; GCN-O1-NEXT: Dominator Tree Construction +; GCN-O1-NEXT: Natural Loop Information +; GCN-O1-NEXT: Canonicalize natural loops +; GCN-O1-NEXT: LCSSA Verifier +; GCN-O1-NEXT: Loop-Closed SSA Form Pass +; GCN-O1-NEXT: Basic Alias Analysis (stateless AA impl) +; GCN-O1-NEXT: Function Alias Analysis Results +; GCN-O1-NEXT: Scalar Evolution Analysis +; GCN-O1-NEXT: Loop Pass Manager +; GCN-O1-NEXT: Rotate Loops +; GCN-O1-NEXT: Loop Access Analysis +; GCN-O1-NEXT: Lazy Branch Probability Analysis +; GCN-O1-NEXT: Lazy Block Frequency Analysis +; GCN-O1-NEXT: Optimization Remark Emitter +; GCN-O1-NEXT: Loop Distribution +; GCN-O1-NEXT: Post-Dominator Tree Construction +; GCN-O1-NEXT: Branch Probability Analysis +; GCN-O1-NEXT: Block Frequency Analysis +; GCN-O1-NEXT: Scalar Evolution Analysis +; GCN-O1-NEXT: Basic Alias Analysis (stateless AA impl) +; GCN-O1-NEXT: Function Alias Analysis Results +; GCN-O1-NEXT: Loop Access Analysis +; GCN-O1-NEXT: Demanded bits analysis +; GCN-O1-NEXT: Lazy Branch Probability Analysis +; GCN-O1-NEXT: Lazy Block Frequency Analysis +; GCN-O1-NEXT: Optimization Remark Emitter +; GCN-O1-NEXT: Inject TLI Mappings +; GCN-O1-NEXT: Loop Vectorization +; GCN-O1-NEXT: Optimize scalar/vector ops +; GCN-O1-NEXT: Early CSE +; GCN-O1-NEXT: Canonicalize natural loops +; GCN-O1-NEXT: Scalar Evolution Analysis +; GCN-O1-NEXT: Function Alias Analysis Results +; GCN-O1-NEXT: Loop Access Analysis +; GCN-O1-NEXT: Lazy Branch Probability Analysis +; GCN-O1-NEXT: Lazy Block Frequency Analysis +; GCN-O1-NEXT: Loop Load Elimination +; GCN-O1-NEXT: Basic Alias Analysis (stateless AA impl) +; GCN-O1-NEXT: Function Alias Analysis Results +; GCN-O1-NEXT: Lazy Branch Probability Analysis +; GCN-O1-NEXT: Lazy Block Frequency Analysis +; GCN-O1-NEXT: Optimization Remark Emitter +; GCN-O1-NEXT: Combine redundant instructions +; GCN-O1-NEXT: Simplify the CFG +; GCN-O1-NEXT: Dominator Tree Construction +; GCN-O1-NEXT: Basic Alias Analysis (stateless AA impl) +; GCN-O1-NEXT: Function Alias Analysis Results +; GCN-O1-NEXT: Natural Loop Information +; GCN-O1-NEXT: Lazy Branch Probability Analysis +; GCN-O1-NEXT: Lazy Block Frequency Analysis +; GCN-O1-NEXT: Optimization Remark Emitter +; GCN-O1-NEXT: Combine redundant instructions +; GCN-O1-NEXT: Canonicalize natural loops +; GCN-O1-NEXT: LCSSA Verifier +; GCN-O1-NEXT: Loop-Closed SSA Form Pass +; GCN-O1-NEXT: Scalar Evolution Analysis +; GCN-O1-NEXT: Loop Pass Manager +; GCN-O1-NEXT: Unroll loops +; GCN-O1-NEXT: Lazy Branch Probability Analysis +; GCN-O1-NEXT: Lazy Block Frequency Analysis +; GCN-O1-NEXT: Optimization Remark Emitter +; GCN-O1-NEXT: Combine redundant instructions +; GCN-O1-NEXT: Memory SSA +; GCN-O1-NEXT: Canonicalize natural loops +; GCN-O1-NEXT: LCSSA Verifier +; GCN-O1-NEXT: Loop-Closed SSA Form Pass +; GCN-O1-NEXT: Scalar Evolution Analysis +; GCN-O1-NEXT: Loop Pass Manager +; GCN-O1-NEXT: Loop Invariant Code Motion +; GCN-O1-NEXT: Lazy Branch Probability Analysis +; GCN-O1-NEXT: Lazy Block Frequency Analysis +; GCN-O1-NEXT: Optimization Remark Emitter +; GCN-O1-NEXT: Warn about non-applied transformations +; GCN-O1-NEXT: Alignment from assumptions +; GCN-O1-NEXT: Strip Unused Function Prototypes +; GCN-O1-NEXT: FunctionPass Manager +; GCN-O1-NEXT: Dominator Tree Construction +; GCN-O1-NEXT: Natural Loop Information +; GCN-O1-NEXT: Post-Dominator Tree Construction +; GCN-O1-NEXT: Branch Probability Analysis +; GCN-O1-NEXT: Block Frequency Analysis +; GCN-O1-NEXT: Canonicalize natural loops +; GCN-O1-NEXT: LCSSA Verifier +; GCN-O1-NEXT: Loop-Closed SSA Form Pass +; GCN-O1-NEXT: Basic Alias Analysis (stateless AA impl) +; GCN-O1-NEXT: Function Alias Analysis Results +; GCN-O1-NEXT: Scalar Evolution Analysis +; GCN-O1-NEXT: Block Frequency Analysis +; GCN-O1-NEXT: Loop Pass Manager +; GCN-O1-NEXT: Loop Sink +; GCN-O1-NEXT: Lazy Branch Probability Analysis +; GCN-O1-NEXT: Lazy Block Frequency Analysis +; GCN-O1-NEXT: Optimization Remark Emitter +; GCN-O1-NEXT: Remove redundant instructions +; GCN-O1-NEXT: Hoist/decompose integer division and remainder +; GCN-O1-NEXT: Simplify the CFG + +; GCN-O1-NEXT: Pass Arguments: +; GCN-O1-NEXT: FunctionPass Manager +; GCN-O1-NEXT: Dominator Tree Construction + +; GCN-O1-NEXT: Pass Arguments: +; GCN-O1-NEXT: FunctionPass Manager +; GCN-O1-NEXT: Dominator Tree Construction + +; GCN-O1-NEXT: Pass Arguments: +; GCN-O1-NEXT: Target Library Information +; GCN-O1-NEXT: FunctionPass Manager +; GCN-O1-NEXT: Dominator Tree Construction +; GCN-O1-NEXT: Natural Loop Information +; GCN-O1-NEXT: Post-Dominator Tree Construction +; GCN-O1-NEXT: Branch Probability Analysis +; GCN-O1-NEXT: Block Frequency Analysis + +; GCN-O1-NEXT: Pass Arguments: +; GCN-O1-NEXT: Target Library Information +; GCN-O1-NEXT: FunctionPass Manager +; GCN-O1-NEXT: Dominator Tree Construction +; GCN-O1-NEXT: Natural Loop Information +; GCN-O1-NEXT: Post-Dominator Tree Construction +; GCN-O1-NEXT: Branch Probability Analysis +; GCN-O1-NEXT: Block Frequency Analysis + + +; GCN-O2: Pass Arguments: +; GCN-O2-NEXT: Target Transform Information +; GCN-O2-NEXT: AMDGPU Address space based Alias Analysis +; GCN-O2-NEXT: External Alias Analysis +; GCN-O2-NEXT: Assumption Cache Tracker +; GCN-O2-NEXT: Target Library Information +; GCN-O2-NEXT: Type-Based Alias Analysis +; GCN-O2-NEXT: Scoped NoAlias Alias Analysis +; GCN-O2-NEXT: FunctionPass Manager +; GCN-O2-NEXT: Early propagate attributes from kernels to functions +; GCN-O2-NEXT: Replace builtin math calls with that native versions. +; GCN-O2-NEXT: Dominator Tree Construction +; GCN-O2-NEXT: Basic Alias Analysis (stateless AA impl) +; GCN-O2-NEXT: Function Alias Analysis Results +; GCN-O2-NEXT: Simplify well-known AMD library calls +; GCN-O2-NEXT: Instrument function entry/exit with calls to e.g. mcount() (pre inlining) +; GCN-O2-NEXT: Simplify the CFG +; GCN-O2-NEXT: Dominator Tree Construction +; GCN-O2-NEXT: SROA +; GCN-O2-NEXT: Early CSE +; GCN-O2-NEXT: Lower 'expect' Intrinsics + +; GCN-O2-NEXT: Pass Arguments: +; GCN-O2-NEXT: Target Library Information +; GCN-O2-NEXT: Target Transform Information +; GCN-O2-NEXT: Target Pass Configuration +; GCN-O2-NEXT: Type-Based Alias Analysis +; GCN-O2-NEXT: Scoped NoAlias Alias Analysis +; GCN-O2-NEXT: AMDGPU Address space based Alias Analysis +; GCN-O2-NEXT: External Alias Analysis +; GCN-O2-NEXT: Assumption Cache Tracker +; GCN-O2-NEXT: Profile summary info +; GCN-O2-NEXT: ModulePass Manager +; GCN-O2-NEXT: Force set function attributes +; GCN-O2-NEXT: Infer set function attributes +; GCN-O2-NEXT: Unify multiple OpenCL metadata due to linking +; GCN-O2-NEXT: AMDGPU Printf lowering +; GCN-O2-NEXT: FunctionPass Manager +; GCN-O2-NEXT: Dominator Tree Construction +; GCN-O2-NEXT: Late propagate attributes from kernels to functions +; GCN-O2-NEXT: Interprocedural Sparse Conditional Constant Propagation +; GCN-O2-NEXT: FunctionPass Manager +; GCN-O2-NEXT: Dominator Tree Construction +; GCN-O2-NEXT: Called Value Propagation +; GCN-O2-NEXT: Global Variable Optimizer +; GCN-O2-NEXT: FunctionPass Manager +; GCN-O2-NEXT: Dominator Tree Construction +; GCN-O2-NEXT: Natural Loop Information +; GCN-O2-NEXT: Post-Dominator Tree Construction +; GCN-O2-NEXT: Branch Probability Analysis +; GCN-O2-NEXT: Block Frequency Analysis +; GCN-O2-NEXT: FunctionPass Manager +; GCN-O2-NEXT: Dominator Tree Construction +; GCN-O2-NEXT: Promote Memory to Register +; GCN-O2-NEXT: Dead Argument Elimination +; GCN-O2-NEXT: FunctionPass Manager +; GCN-O2-NEXT: Dominator Tree Construction +; GCN-O2-NEXT: Basic Alias Analysis (stateless AA impl) +; GCN-O2-NEXT: Function Alias Analysis Results +; GCN-O2-NEXT: Natural Loop Information +; GCN-O2-NEXT: Lazy Branch Probability Analysis +; GCN-O2-NEXT: Lazy Block Frequency Analysis +; GCN-O2-NEXT: Optimization Remark Emitter +; GCN-O2-NEXT: Combine redundant instructions +; GCN-O2-NEXT: Simplify the CFG +; GCN-O2-NEXT: CallGraph Construction +; GCN-O2-NEXT: Globals Alias Analysis +; GCN-O2-NEXT: Call Graph SCC Pass Manager +; GCN-O2-NEXT: Remove unused exception handling info +; GCN-O2-NEXT: AMDGPU Function Integration/Inlining +; GCN-O2-NEXT: OpenMP specific optimizations +; GCN-O2-NEXT: Deduce function attributes +; GCN-O2-NEXT: FunctionPass Manager +; GCN-O2-NEXT: Infer address spaces +; GCN-O2-NEXT: AMDGPU Kernel Attributes +; GCN-O2-NEXT: FunctionPass Manager +; GCN-O2-NEXT: Dominator Tree Construction +; GCN-O2-NEXT: SROA +; GCN-O2-NEXT: Basic Alias Analysis (stateless AA impl) +; GCN-O2-NEXT: Function Alias Analysis Results +; GCN-O2-NEXT: Memory SSA +; GCN-O2-NEXT: Early CSE w/ MemorySSA +; GCN-O2-NEXT: Speculatively execute instructions if target has divergent branches +; GCN-O2-NEXT: Function Alias Analysis Results +; GCN-O2-NEXT: Lazy Value Information Analysis +; GCN-O2-NEXT: Jump Threading +; GCN-O2-NEXT: Value Propagation +; GCN-O2-NEXT: Simplify the CFG +; GCN-O2-NEXT: Dominator Tree Construction +; GCN-O2-NEXT: Basic Alias Analysis (stateless AA impl) +; GCN-O2-NEXT: Function Alias Analysis Results +; GCN-O2-NEXT: Natural Loop Information +; GCN-O2-NEXT: Lazy Branch Probability Analysis +; GCN-O2-NEXT: Lazy Block Frequency Analysis +; GCN-O2-NEXT: Optimization Remark Emitter +; GCN-O2-NEXT: Combine redundant instructions +; GCN-O2-NEXT: Conditionally eliminate dead library calls +; GCN-O2-NEXT: Natural Loop Information +; GCN-O2-NEXT: Post-Dominator Tree Construction +; GCN-O2-NEXT: Branch Probability Analysis +; GCN-O2-NEXT: Block Frequency Analysis +; GCN-O2-NEXT: Lazy Branch Probability Analysis +; GCN-O2-NEXT: Lazy Block Frequency Analysis +; GCN-O2-NEXT: Optimization Remark Emitter +; GCN-O2-NEXT: PGOMemOPSize +; GCN-O2-NEXT: Basic Alias Analysis (stateless AA impl) +; GCN-O2-NEXT: Function Alias Analysis Results +; GCN-O2-NEXT: Natural Loop Information +; GCN-O2-NEXT: Lazy Branch Probability Analysis +; GCN-O2-NEXT: Lazy Block Frequency Analysis +; GCN-O2-NEXT: Optimization Remark Emitter +; GCN-O2-NEXT: Tail Call Elimination +; GCN-O2-NEXT: Simplify the CFG +; GCN-O2-NEXT: Reassociate expressions +; GCN-O2-NEXT: Dominator Tree Construction +; GCN-O2-NEXT: Natural Loop Information +; GCN-O2-NEXT: Canonicalize natural loops +; GCN-O2-NEXT: LCSSA Verifier +; GCN-O2-NEXT: Loop-Closed SSA Form Pass +; GCN-O2-NEXT: Basic Alias Analysis (stateless AA impl) +; GCN-O2-NEXT: Function Alias Analysis Results +; GCN-O2-NEXT: Scalar Evolution Analysis +; GCN-O2-NEXT: Loop Pass Manager +; GCN-O2-NEXT: Rotate Loops +; GCN-O2-NEXT: Memory SSA +; GCN-O2-NEXT: Loop Pass Manager +; GCN-O2-NEXT: Loop Invariant Code Motion +; GCN-O2-NEXT: Post-Dominator Tree Construction +; GCN-O2-NEXT: Legacy Divergence Analysis +; GCN-O2-NEXT: Loop Pass Manager +; GCN-O2-NEXT: Unswitch loops +; GCN-O2-NEXT: Simplify the CFG +; GCN-O2-NEXT: Dominator Tree Construction +; GCN-O2-NEXT: Basic Alias Analysis (stateless AA impl) +; GCN-O2-NEXT: Function Alias Analysis Results +; GCN-O2-NEXT: Natural Loop Information +; GCN-O2-NEXT: Lazy Branch Probability Analysis +; GCN-O2-NEXT: Lazy Block Frequency Analysis +; GCN-O2-NEXT: Optimization Remark Emitter +; GCN-O2-NEXT: Combine redundant instructions +; GCN-O2-NEXT: Canonicalize natural loops +; GCN-O2-NEXT: LCSSA Verifier +; GCN-O2-NEXT: Loop-Closed SSA Form Pass +; GCN-O2-NEXT: Scalar Evolution Analysis +; GCN-O2-NEXT: Loop Pass Manager +; GCN-O2-NEXT: Induction Variable Simplification +; GCN-O2-NEXT: Recognize loop idioms +; GCN-O2-NEXT: Delete dead loops +; GCN-O2-NEXT: Unroll loops +; GCN-O2-NEXT: MergedLoadStoreMotion +; GCN-O2-NEXT: Phi Values Analysis +; GCN-O2-NEXT: Function Alias Analysis Results +; GCN-O2-NEXT: Memory Dependence Analysis +; GCN-O2-NEXT: Lazy Branch Probability Analysis +; GCN-O2-NEXT: Lazy Block Frequency Analysis +; GCN-O2-NEXT: Optimization Remark Emitter +; GCN-O2-NEXT: Global Value Numbering +; GCN-O2-NEXT: Phi Values Analysis +; GCN-O2-NEXT: Basic Alias Analysis (stateless AA impl) +; GCN-O2-NEXT: Function Alias Analysis Results +; GCN-O2-NEXT: Memory Dependence Analysis +; GCN-O2-NEXT: MemCpy Optimization +; GCN-O2-NEXT: Sparse Conditional Constant Propagation +; GCN-O2-NEXT: Demanded bits analysis +; GCN-O2-NEXT: Bit-Tracking Dead Code Elimination +; GCN-O2-NEXT: Function Alias Analysis Results +; GCN-O2-NEXT: Lazy Branch Probability Analysis +; GCN-O2-NEXT: Lazy Block Frequency Analysis +; GCN-O2-NEXT: Optimization Remark Emitter +; GCN-O2-NEXT: Combine redundant instructions +; GCN-O2-NEXT: Lazy Value Information Analysis +; GCN-O2-NEXT: Jump Threading +; GCN-O2-NEXT: Value Propagation +; GCN-O2-NEXT: Basic Alias Analysis (stateless AA impl) +; GCN-O2-NEXT: Function Alias Analysis Results +; GCN-O2-NEXT: Phi Values Analysis +; GCN-O2-NEXT: Memory Dependence Analysis +; GCN-O2-NEXT: Dead Store Elimination +; GCN-O2-NEXT: Function Alias Analysis Results +; GCN-O2-NEXT: Memory SSA +; GCN-O2-NEXT: Natural Loop Information +; GCN-O2-NEXT: Canonicalize natural loops +; GCN-O2-NEXT: LCSSA Verifier +; GCN-O2-NEXT: Loop-Closed SSA Form Pass +; GCN-O2-NEXT: Scalar Evolution Analysis +; GCN-O2-NEXT: Loop Pass Manager +; GCN-O2-NEXT: Loop Invariant Code Motion +; GCN-O2-NEXT: Post-Dominator Tree Construction +; GCN-O2-NEXT: Aggressive Dead Code Elimination +; GCN-O2-NEXT: Simplify the CFG +; GCN-O2-NEXT: Dominator Tree Construction +; GCN-O2-NEXT: Basic Alias Analysis (stateless AA impl) +; GCN-O2-NEXT: Function Alias Analysis Results +; GCN-O2-NEXT: Natural Loop Information +; GCN-O2-NEXT: Lazy Branch Probability Analysis +; GCN-O2-NEXT: Lazy Block Frequency Analysis +; GCN-O2-NEXT: Optimization Remark Emitter +; GCN-O2-NEXT: Combine redundant instructions +; GCN-O2-NEXT: A No-Op Barrier Pass +; GCN-O2-NEXT: Eliminate Available Externally Globals +; GCN-O2-NEXT: CallGraph Construction +; GCN-O2-NEXT: Deduce function attributes in RPO +; GCN-O2-NEXT: Global Variable Optimizer +; GCN-O2-NEXT: FunctionPass Manager +; GCN-O2-NEXT: Dominator Tree Construction +; GCN-O2-NEXT: Natural Loop Information +; GCN-O2-NEXT: Post-Dominator Tree Construction +; GCN-O2-NEXT: Branch Probability Analysis +; GCN-O2-NEXT: Block Frequency Analysis +; GCN-O2-NEXT: Dead Global Elimination +; GCN-O2-NEXT: CallGraph Construction +; GCN-O2-NEXT: Globals Alias Analysis +; GCN-O2-NEXT: FunctionPass Manager +; GCN-O2-NEXT: Dominator Tree Construction +; GCN-O2-NEXT: Float to int +; GCN-O2-NEXT: Lower constant intrinsics +; GCN-O2-NEXT: Dominator Tree Construction +; GCN-O2-NEXT: Natural Loop Information +; GCN-O2-NEXT: Canonicalize natural loops +; GCN-O2-NEXT: LCSSA Verifier +; GCN-O2-NEXT: Loop-Closed SSA Form Pass +; GCN-O2-NEXT: Basic Alias Analysis (stateless AA impl) +; GCN-O2-NEXT: Function Alias Analysis Results +; GCN-O2-NEXT: Scalar Evolution Analysis +; GCN-O2-NEXT: Loop Pass Manager +; GCN-O2-NEXT: Rotate Loops +; GCN-O2-NEXT: Loop Access Analysis +; GCN-O2-NEXT: Lazy Branch Probability Analysis +; GCN-O2-NEXT: Lazy Block Frequency Analysis +; GCN-O2-NEXT: Optimization Remark Emitter +; GCN-O2-NEXT: Loop Distribution +; GCN-O2-NEXT: Post-Dominator Tree Construction +; GCN-O2-NEXT: Branch Probability Analysis +; GCN-O2-NEXT: Block Frequency Analysis +; GCN-O2-NEXT: Scalar Evolution Analysis +; GCN-O2-NEXT: Basic Alias Analysis (stateless AA impl) +; GCN-O2-NEXT: Function Alias Analysis Results +; GCN-O2-NEXT: Loop Access Analysis +; GCN-O2-NEXT: Demanded bits analysis +; GCN-O2-NEXT: Lazy Branch Probability Analysis +; GCN-O2-NEXT: Lazy Block Frequency Analysis +; GCN-O2-NEXT: Optimization Remark Emitter +; GCN-O2-NEXT: Inject TLI Mappings +; GCN-O2-NEXT: Loop Vectorization +; GCN-O2-NEXT: Optimize scalar/vector ops +; GCN-O2-NEXT: Early CSE +; GCN-O2-NEXT: Canonicalize natural loops +; GCN-O2-NEXT: Scalar Evolution Analysis +; GCN-O2-NEXT: Function Alias Analysis Results +; GCN-O2-NEXT: Loop Access Analysis +; GCN-O2-NEXT: Lazy Branch Probability Analysis +; GCN-O2-NEXT: Lazy Block Frequency Analysis +; GCN-O2-NEXT: Loop Load Elimination +; GCN-O2-NEXT: Basic Alias Analysis (stateless AA impl) +; GCN-O2-NEXT: Function Alias Analysis Results +; GCN-O2-NEXT: Lazy Branch Probability Analysis +; GCN-O2-NEXT: Lazy Block Frequency Analysis +; GCN-O2-NEXT: Optimization Remark Emitter +; GCN-O2-NEXT: Combine redundant instructions +; GCN-O2-NEXT: Simplify the CFG +; GCN-O2-NEXT: Dominator Tree Construction +; GCN-O2-NEXT: Natural Loop Information +; GCN-O2-NEXT: Scalar Evolution Analysis +; GCN-O2-NEXT: Basic Alias Analysis (stateless AA impl) +; GCN-O2-NEXT: Function Alias Analysis Results +; GCN-O2-NEXT: Demanded bits analysis +; GCN-O2-NEXT: Lazy Branch Probability Analysis +; GCN-O2-NEXT: Lazy Block Frequency Analysis +; GCN-O2-NEXT: Optimization Remark Emitter +; GCN-O2-NEXT: Inject TLI Mappings +; GCN-O2-NEXT: SLP Vectorizer +; GCN-O2-NEXT: Optimization Remark Emitter +; GCN-O2-NEXT: Combine redundant instructions +; GCN-O2-NEXT: Canonicalize natural loops +; GCN-O2-NEXT: LCSSA Verifier +; GCN-O2-NEXT: Loop-Closed SSA Form Pass +; GCN-O2-NEXT: Scalar Evolution Analysis +; GCN-O2-NEXT: Loop Pass Manager +; GCN-O2-NEXT: Unroll loops +; GCN-O2-NEXT: Lazy Branch Probability Analysis +; GCN-O2-NEXT: Lazy Block Frequency Analysis +; GCN-O2-NEXT: Optimization Remark Emitter +; GCN-O2-NEXT: Combine redundant instructions +; GCN-O2-NEXT: Memory SSA +; GCN-O2-NEXT: Canonicalize natural loops +; GCN-O2-NEXT: LCSSA Verifier +; GCN-O2-NEXT: Loop-Closed SSA Form Pass +; GCN-O2-NEXT: Scalar Evolution Analysis +; GCN-O2-NEXT: Loop Pass Manager +; GCN-O2-NEXT: Loop Invariant Code Motion +; GCN-O2-NEXT: Lazy Branch Probability Analysis +; GCN-O2-NEXT: Lazy Block Frequency Analysis +; GCN-O2-NEXT: Optimization Remark Emitter +; GCN-O2-NEXT: Warn about non-applied transformations +; GCN-O2-NEXT: Alignment from assumptions +; GCN-O2-NEXT: Strip Unused Function Prototypes +; GCN-O2-NEXT: Dead Global Elimination +; GCN-O2-NEXT: Merge Duplicate Global Constants +; GCN-O2-NEXT: FunctionPass Manager +; GCN-O2-NEXT: Dominator Tree Construction +; GCN-O2-NEXT: Natural Loop Information +; GCN-O2-NEXT: Post-Dominator Tree Construction +; GCN-O2-NEXT: Branch Probability Analysis +; GCN-O2-NEXT: Block Frequency Analysis +; GCN-O2-NEXT: Canonicalize natural loops +; GCN-O2-NEXT: LCSSA Verifier +; GCN-O2-NEXT: Loop-Closed SSA Form Pass +; GCN-O2-NEXT: Basic Alias Analysis (stateless AA impl) +; GCN-O2-NEXT: Function Alias Analysis Results +; GCN-O2-NEXT: Scalar Evolution Analysis +; GCN-O2-NEXT: Block Frequency Analysis +; GCN-O2-NEXT: Loop Pass Manager +; GCN-O2-NEXT: Loop Sink +; GCN-O2-NEXT: Lazy Branch Probability Analysis +; GCN-O2-NEXT: Lazy Block Frequency Analysis +; GCN-O2-NEXT: Optimization Remark Emitter +; GCN-O2-NEXT: Remove redundant instructions +; GCN-O2-NEXT: Hoist/decompose integer division and remainder +; GCN-O2-NEXT: Simplify the CFG + +; GCN-O2-NEXT: Pass Arguments: +; GCN-O2-NEXT: FunctionPass Manager +; GCN-O2-NEXT: Dominator Tree Construction + +; GCN-O2-NEXT: Pass Arguments: +; GCN-O2-NEXT: FunctionPass Manager +; GCN-O2-NEXT: Dominator Tree Construction + +; GCN-O2-NEXT: Pass Arguments: +; GCN-O2-NEXT: Target Library Information +; GCN-O2-NEXT: FunctionPass Manager +; GCN-O2-NEXT: Dominator Tree Construction +; GCN-O2-NEXT: Natural Loop Information +; GCN-O2-NEXT: Post-Dominator Tree Construction +; GCN-O2-NEXT: Branch Probability Analysis +; GCN-O2-NEXT: Block Frequency Analysis + +; GCN-O2-NEXT: Pass Arguments: +; GCN-O2-NEXT: Target Library Information +; GCN-O2-NEXT: FunctionPass Manager +; GCN-O2-NEXT: Dominator Tree Construction +; GCN-O2-NEXT: Natural Loop Information +; GCN-O2-NEXT: Post-Dominator Tree Construction +; GCN-O2-NEXT: Branch Probability Analysis +; GCN-O2-NEXT: Block Frequency Analysis + + +; GCN-O3: Pass Arguments: +; GCN-O3-NEXT: Target Transform Information +; GCN-O3-NEXT: AMDGPU Address space based Alias Analysis +; GCN-O3-NEXT: External Alias Analysis +; GCN-O3-NEXT: Assumption Cache Tracker +; GCN-O3-NEXT: Target Library Information +; GCN-O3-NEXT: Type-Based Alias Analysis +; GCN-O3-NEXT: Scoped NoAlias Alias Analysis +; GCN-O3-NEXT: FunctionPass Manager +; GCN-O3-NEXT: Early propagate attributes from kernels to functions +; GCN-O3-NEXT: Replace builtin math calls with that native versions. +; GCN-O3-NEXT: Dominator Tree Construction +; GCN-O3-NEXT: Basic Alias Analysis (stateless AA impl) +; GCN-O3-NEXT: Function Alias Analysis Results +; GCN-O3-NEXT: Simplify well-known AMD library calls +; GCN-O3-NEXT: Instrument function entry/exit with calls to e.g. mcount() (pre inlining) +; GCN-O3-NEXT: Simplify the CFG +; GCN-O3-NEXT: Dominator Tree Construction +; GCN-O3-NEXT: SROA +; GCN-O3-NEXT: Early CSE +; GCN-O3-NEXT: Lower 'expect' Intrinsics + +; GCN-O3-NEXT: Pass Arguments: +; GCN-O3-NEXT: Target Library Information +; GCN-O3-NEXT: Target Transform Information +; GCN-O3-NEXT: Target Pass Configuration +; GCN-O3-NEXT: Type-Based Alias Analysis +; GCN-O3-NEXT: Scoped NoAlias Alias Analysis +; GCN-O3-NEXT: AMDGPU Address space based Alias Analysis +; GCN-O3-NEXT: External Alias Analysis +; GCN-O3-NEXT: Assumption Cache Tracker +; GCN-O3-NEXT: Profile summary info +; GCN-O3-NEXT: ModulePass Manager +; GCN-O3-NEXT: Force set function attributes +; GCN-O3-NEXT: Infer set function attributes +; GCN-O3-NEXT: Unify multiple OpenCL metadata due to linking +; GCN-O3-NEXT: AMDGPU Printf lowering +; GCN-O3-NEXT: FunctionPass Manager +; GCN-O3-NEXT: Dominator Tree Construction +; GCN-O3-NEXT: Late propagate attributes from kernels to functions +; GCN-O3-NEXT: FunctionPass Manager +; GCN-O3-NEXT: Dominator Tree Construction +; GCN-O3-NEXT: Call-site splitting +; GCN-O3-NEXT: Interprocedural Sparse Conditional Constant Propagation +; GCN-O3-NEXT: FunctionPass Manager +; GCN-O3-NEXT: Dominator Tree Construction +; GCN-O3-NEXT: Called Value Propagation +; GCN-O3-NEXT: Global Variable Optimizer +; GCN-O3-NEXT: FunctionPass Manager +; GCN-O3-NEXT: Dominator Tree Construction +; GCN-O3-NEXT: Natural Loop Information +; GCN-O3-NEXT: Post-Dominator Tree Construction +; GCN-O3-NEXT: Branch Probability Analysis +; GCN-O3-NEXT: Block Frequency Analysis +; GCN-O3-NEXT: FunctionPass Manager +; GCN-O3-NEXT: Dominator Tree Construction +; GCN-O3-NEXT: Promote Memory to Register +; GCN-O3-NEXT: Dead Argument Elimination +; GCN-O3-NEXT: FunctionPass Manager +; GCN-O3-NEXT: Dominator Tree Construction +; GCN-O3-NEXT: Basic Alias Analysis (stateless AA impl) +; GCN-O3-NEXT: Function Alias Analysis Results +; GCN-O3-NEXT: Natural Loop Information +; GCN-O3-NEXT: Lazy Branch Probability Analysis +; GCN-O3-NEXT: Lazy Block Frequency Analysis +; GCN-O3-NEXT: Optimization Remark Emitter +; GCN-O3-NEXT: Combine redundant instructions +; GCN-O3-NEXT: Simplify the CFG +; GCN-O3-NEXT: CallGraph Construction +; GCN-O3-NEXT: Globals Alias Analysis +; GCN-O3-NEXT: Call Graph SCC Pass Manager +; GCN-O3-NEXT: Remove unused exception handling info +; GCN-O3-NEXT: AMDGPU Function Integration/Inlining +; GCN-O3-NEXT: OpenMP specific optimizations +; GCN-O3-NEXT: Deduce function attributes +; GCN-O3-NEXT: Promote 'by reference' arguments to scalars +; GCN-O3-NEXT: FunctionPass Manager +; GCN-O3-NEXT: Infer address spaces +; GCN-O3-NEXT: AMDGPU Kernel Attributes +; GCN-O3-NEXT: FunctionPass Manager +; GCN-O3-NEXT: Dominator Tree Construction +; GCN-O3-NEXT: SROA +; GCN-O3-NEXT: Basic Alias Analysis (stateless AA impl) +; GCN-O3-NEXT: Function Alias Analysis Results +; GCN-O3-NEXT: Memory SSA +; GCN-O3-NEXT: Early CSE w/ MemorySSA +; GCN-O3-NEXT: Speculatively execute instructions if target has divergent branches +; GCN-O3-NEXT: Function Alias Analysis Results +; GCN-O3-NEXT: Lazy Value Information Analysis +; GCN-O3-NEXT: Jump Threading +; GCN-O3-NEXT: Value Propagation +; GCN-O3-NEXT: Simplify the CFG +; GCN-O3-NEXT: Dominator Tree Construction +; GCN-O3-NEXT: Combine pattern based expressions +; GCN-O3-NEXT: Basic Alias Analysis (stateless AA impl) +; GCN-O3-NEXT: Function Alias Analysis Results +; GCN-O3-NEXT: Natural Loop Information +; GCN-O3-NEXT: Lazy Branch Probability Analysis +; GCN-O3-NEXT: Lazy Block Frequency Analysis +; GCN-O3-NEXT: Optimization Remark Emitter +; GCN-O3-NEXT: Combine redundant instructions +; GCN-O3-NEXT: Conditionally eliminate dead library calls +; GCN-O3-NEXT: Natural Loop Information +; GCN-O3-NEXT: Post-Dominator Tree Construction +; GCN-O3-NEXT: Branch Probability Analysis +; GCN-O3-NEXT: Block Frequency Analysis +; GCN-O3-NEXT: Lazy Branch Probability Analysis +; GCN-O3-NEXT: Lazy Block Frequency Analysis +; GCN-O3-NEXT: Optimization Remark Emitter +; GCN-O3-NEXT: PGOMemOPSize +; GCN-O3-NEXT: Basic Alias Analysis (stateless AA impl) +; GCN-O3-NEXT: Function Alias Analysis Results +; GCN-O3-NEXT: Natural Loop Information +; GCN-O3-NEXT: Lazy Branch Probability Analysis +; GCN-O3-NEXT: Lazy Block Frequency Analysis +; GCN-O3-NEXT: Optimization Remark Emitter +; GCN-O3-NEXT: Tail Call Elimination +; GCN-O3-NEXT: Simplify the CFG +; GCN-O3-NEXT: Reassociate expressions +; GCN-O3-NEXT: Dominator Tree Construction +; GCN-O3-NEXT: Natural Loop Information +; GCN-O3-NEXT: Canonicalize natural loops +; GCN-O3-NEXT: LCSSA Verifier +; GCN-O3-NEXT: Loop-Closed SSA Form Pass +; GCN-O3-NEXT: Basic Alias Analysis (stateless AA impl) +; GCN-O3-NEXT: Function Alias Analysis Results +; GCN-O3-NEXT: Scalar Evolution Analysis +; GCN-O3-NEXT: Loop Pass Manager +; GCN-O3-NEXT: Rotate Loops +; GCN-O3-NEXT: Memory SSA +; GCN-O3-NEXT: Loop Pass Manager +; GCN-O3-NEXT: Loop Invariant Code Motion +; GCN-O3-NEXT: Post-Dominator Tree Construction +; GCN-O3-NEXT: Legacy Divergence Analysis +; GCN-O3-NEXT: Loop Pass Manager +; GCN-O3-NEXT: Unswitch loops +; GCN-O3-NEXT: Simplify the CFG +; GCN-O3-NEXT: Dominator Tree Construction +; GCN-O3-NEXT: Basic Alias Analysis (stateless AA impl) +; GCN-O3-NEXT: Function Alias Analysis Results +; GCN-O3-NEXT: Natural Loop Information +; GCN-O3-NEXT: Lazy Branch Probability Analysis +; GCN-O3-NEXT: Lazy Block Frequency Analysis +; GCN-O3-NEXT: Optimization Remark Emitter +; GCN-O3-NEXT: Combine redundant instructions +; GCN-O3-NEXT: Canonicalize natural loops +; GCN-O3-NEXT: LCSSA Verifier +; GCN-O3-NEXT: Loop-Closed SSA Form Pass +; GCN-O3-NEXT: Scalar Evolution Analysis +; GCN-O3-NEXT: Loop Pass Manager +; GCN-O3-NEXT: Induction Variable Simplification +; GCN-O3-NEXT: Recognize loop idioms +; GCN-O3-NEXT: Delete dead loops +; GCN-O3-NEXT: Unroll loops +; GCN-O3-NEXT: MergedLoadStoreMotion +; GCN-O3-NEXT: Phi Values Analysis +; GCN-O3-NEXT: Function Alias Analysis Results +; GCN-O3-NEXT: Memory Dependence Analysis +; GCN-O3-NEXT: Lazy Branch Probability Analysis +; GCN-O3-NEXT: Lazy Block Frequency Analysis +; GCN-O3-NEXT: Optimization Remark Emitter +; GCN-O3-NEXT: Global Value Numbering +; GCN-O3-NEXT: Phi Values Analysis +; GCN-O3-NEXT: Basic Alias Analysis (stateless AA impl) +; GCN-O3-NEXT: Function Alias Analysis Results +; GCN-O3-NEXT: Memory Dependence Analysis +; GCN-O3-NEXT: MemCpy Optimization +; GCN-O3-NEXT: Sparse Conditional Constant Propagation +; GCN-O3-NEXT: Demanded bits analysis +; GCN-O3-NEXT: Bit-Tracking Dead Code Elimination +; GCN-O3-NEXT: Function Alias Analysis Results +; GCN-O3-NEXT: Lazy Branch Probability Analysis +; GCN-O3-NEXT: Lazy Block Frequency Analysis +; GCN-O3-NEXT: Optimization Remark Emitter +; GCN-O3-NEXT: Combine redundant instructions +; GCN-O3-NEXT: Lazy Value Information Analysis +; GCN-O3-NEXT: Jump Threading +; GCN-O3-NEXT: Value Propagation +; GCN-O3-NEXT: Basic Alias Analysis (stateless AA impl) +; GCN-O3-NEXT: Function Alias Analysis Results +; GCN-O3-NEXT: Phi Values Analysis +; GCN-O3-NEXT: Memory Dependence Analysis +; GCN-O3-NEXT: Dead Store Elimination +; GCN-O3-NEXT: Function Alias Analysis Results +; GCN-O3-NEXT: Memory SSA +; GCN-O3-NEXT: Natural Loop Information +; GCN-O3-NEXT: Canonicalize natural loops +; GCN-O3-NEXT: LCSSA Verifier +; GCN-O3-NEXT: Loop-Closed SSA Form Pass +; GCN-O3-NEXT: Scalar Evolution Analysis +; GCN-O3-NEXT: Loop Pass Manager +; GCN-O3-NEXT: Loop Invariant Code Motion +; GCN-O3-NEXT: Post-Dominator Tree Construction +; GCN-O3-NEXT: Aggressive Dead Code Elimination +; GCN-O3-NEXT: Simplify the CFG +; GCN-O3-NEXT: Dominator Tree Construction +; GCN-O3-NEXT: Basic Alias Analysis (stateless AA impl) +; GCN-O3-NEXT: Function Alias Analysis Results +; GCN-O3-NEXT: Natural Loop Information +; GCN-O3-NEXT: Lazy Branch Probability Analysis +; GCN-O3-NEXT: Lazy Block Frequency Analysis +; GCN-O3-NEXT: Optimization Remark Emitter +; GCN-O3-NEXT: Combine redundant instructions +; GCN-O3-NEXT: A No-Op Barrier Pass +; GCN-O3-NEXT: Eliminate Available Externally Globals +; GCN-O3-NEXT: CallGraph Construction +; GCN-O3-NEXT: Deduce function attributes in RPO +; GCN-O3-NEXT: Global Variable Optimizer +; GCN-O3-NEXT: FunctionPass Manager +; GCN-O3-NEXT: Dominator Tree Construction +; GCN-O3-NEXT: Natural Loop Information +; GCN-O3-NEXT: Post-Dominator Tree Construction +; GCN-O3-NEXT: Branch Probability Analysis +; GCN-O3-NEXT: Block Frequency Analysis +; GCN-O3-NEXT: Dead Global Elimination +; GCN-O3-NEXT: CallGraph Construction +; GCN-O3-NEXT: Globals Alias Analysis +; GCN-O3-NEXT: FunctionPass Manager +; GCN-O3-NEXT: Dominator Tree Construction +; GCN-O3-NEXT: Float to int +; GCN-O3-NEXT: Lower constant intrinsics +; GCN-O3-NEXT: Dominator Tree Construction +; GCN-O3-NEXT: Natural Loop Information +; GCN-O3-NEXT: Canonicalize natural loops +; GCN-O3-NEXT: LCSSA Verifier +; GCN-O3-NEXT: Loop-Closed SSA Form Pass +; GCN-O3-NEXT: Basic Alias Analysis (stateless AA impl) +; GCN-O3-NEXT: Function Alias Analysis Results +; GCN-O3-NEXT: Scalar Evolution Analysis +; GCN-O3-NEXT: Loop Pass Manager +; GCN-O3-NEXT: Rotate Loops +; GCN-O3-NEXT: Loop Access Analysis +; GCN-O3-NEXT: Lazy Branch Probability Analysis +; GCN-O3-NEXT: Lazy Block Frequency Analysis +; GCN-O3-NEXT: Optimization Remark Emitter +; GCN-O3-NEXT: Loop Distribution +; GCN-O3-NEXT: Post-Dominator Tree Construction +; GCN-O3-NEXT: Branch Probability Analysis +; GCN-O3-NEXT: Block Frequency Analysis +; GCN-O3-NEXT: Scalar Evolution Analysis +; GCN-O3-NEXT: Basic Alias Analysis (stateless AA impl) +; GCN-O3-NEXT: Function Alias Analysis Results +; GCN-O3-NEXT: Loop Access Analysis +; GCN-O3-NEXT: Demanded bits analysis +; GCN-O3-NEXT: Lazy Branch Probability Analysis +; GCN-O3-NEXT: Lazy Block Frequency Analysis +; GCN-O3-NEXT: Optimization Remark Emitter +; GCN-O3-NEXT: Inject TLI Mappings +; GCN-O3-NEXT: Loop Vectorization +; GCN-O3-NEXT: Optimize scalar/vector ops +; GCN-O3-NEXT: Early CSE +; GCN-O3-NEXT: Canonicalize natural loops +; GCN-O3-NEXT: Scalar Evolution Analysis +; GCN-O3-NEXT: Function Alias Analysis Results +; GCN-O3-NEXT: Loop Access Analysis +; GCN-O3-NEXT: Lazy Branch Probability Analysis +; GCN-O3-NEXT: Lazy Block Frequency Analysis +; GCN-O3-NEXT: Loop Load Elimination +; GCN-O3-NEXT: Basic Alias Analysis (stateless AA impl) +; GCN-O3-NEXT: Function Alias Analysis Results +; GCN-O3-NEXT: Lazy Branch Probability Analysis +; GCN-O3-NEXT: Lazy Block Frequency Analysis +; GCN-O3-NEXT: Optimization Remark Emitter +; GCN-O3-NEXT: Combine redundant instructions +; GCN-O3-NEXT: Simplify the CFG +; GCN-O3-NEXT: Dominator Tree Construction +; GCN-O3-NEXT: Natural Loop Information +; GCN-O3-NEXT: Scalar Evolution Analysis +; GCN-O3-NEXT: Basic Alias Analysis (stateless AA impl) +; GCN-O3-NEXT: Function Alias Analysis Results +; GCN-O3-NEXT: Demanded bits analysis +; GCN-O3-NEXT: Lazy Branch Probability Analysis +; GCN-O3-NEXT: Lazy Block Frequency Analysis +; GCN-O3-NEXT: Optimization Remark Emitter +; GCN-O3-NEXT: Inject TLI Mappings +; GCN-O3-NEXT: SLP Vectorizer +; GCN-O3-NEXT: Optimization Remark Emitter +; GCN-O3-NEXT: Combine redundant instructions +; GCN-O3-NEXT: Canonicalize natural loops +; GCN-O3-NEXT: LCSSA Verifier +; GCN-O3-NEXT: Loop-Closed SSA Form Pass +; GCN-O3-NEXT: Scalar Evolution Analysis +; GCN-O3-NEXT: Loop Pass Manager +; GCN-O3-NEXT: Unroll loops +; GCN-O3-NEXT: Lazy Branch Probability Analysis +; GCN-O3-NEXT: Lazy Block Frequency Analysis +; GCN-O3-NEXT: Optimization Remark Emitter +; GCN-O3-NEXT: Combine redundant instructions +; GCN-O3-NEXT: Memory SSA +; GCN-O3-NEXT: Canonicalize natural loops +; GCN-O3-NEXT: LCSSA Verifier +; GCN-O3-NEXT: Loop-Closed SSA Form Pass +; GCN-O3-NEXT: Scalar Evolution Analysis +; GCN-O3-NEXT: Loop Pass Manager +; GCN-O3-NEXT: Loop Invariant Code Motion +; GCN-O3-NEXT: Lazy Branch Probability Analysis +; GCN-O3-NEXT: Lazy Block Frequency Analysis +; GCN-O3-NEXT: Optimization Remark Emitter +; GCN-O3-NEXT: Warn about non-applied transformations +; GCN-O3-NEXT: Alignment from assumptions +; GCN-O3-NEXT: Strip Unused Function Prototypes +; GCN-O3-NEXT: Dead Global Elimination +; GCN-O3-NEXT: Merge Duplicate Global Constants +; GCN-O3-NEXT: FunctionPass Manager +; GCN-O3-NEXT: Dominator Tree Construction +; GCN-O3-NEXT: Natural Loop Information +; GCN-O3-NEXT: Post-Dominator Tree Construction +; GCN-O3-NEXT: Branch Probability Analysis +; GCN-O3-NEXT: Block Frequency Analysis +; GCN-O3-NEXT: Canonicalize natural loops +; GCN-O3-NEXT: LCSSA Verifier +; GCN-O3-NEXT: Loop-Closed SSA Form Pass +; GCN-O3-NEXT: Basic Alias Analysis (stateless AA impl) +; GCN-O3-NEXT: Function Alias Analysis Results +; GCN-O3-NEXT: Scalar Evolution Analysis +; GCN-O3-NEXT: Block Frequency Analysis +; GCN-O3-NEXT: Loop Pass Manager +; GCN-O3-NEXT: Loop Sink +; GCN-O3-NEXT: Lazy Branch Probability Analysis +; GCN-O3-NEXT: Lazy Block Frequency Analysis +; GCN-O3-NEXT: Optimization Remark Emitter +; GCN-O3-NEXT: Remove redundant instructions +; GCN-O3-NEXT: Hoist/decompose integer division and remainder +; GCN-O3-NEXT: Simplify the CFG + +; GCN-O3-NEXT: Pass Arguments: +; GCN-O3-NEXT: FunctionPass Manager +; GCN-O3-NEXT: Dominator Tree Construction + +; GCN-O3-NEXT: Pass Arguments: +; GCN-O3-NEXT: FunctionPass Manager +; GCN-O3-NEXT: Dominator Tree Construction + +; GCN-O3-NEXT: Pass Arguments: +; GCN-O3-NEXT: Target Library Information +; GCN-O3-NEXT: FunctionPass Manager +; GCN-O3-NEXT: Dominator Tree Construction +; GCN-O3-NEXT: Natural Loop Information +; GCN-O3-NEXT: Post-Dominator Tree Construction +; GCN-O3-NEXT: Branch Probability Analysis +; GCN-O3-NEXT: Block Frequency Analysis + +; GCN-O3-NEXT: Pass Arguments: +; GCN-O3-NEXT: Target Library Information +; GCN-O3-NEXT: FunctionPass Manager +; GCN-O3-NEXT: Dominator Tree Construction +; GCN-O3-NEXT: Natural Loop Information +; GCN-O3-NEXT: Post-Dominator Tree Construction +; GCN-O3-NEXT: Branch Probability Analysis +; GCN-O3-NEXT: Block Frequency Analysis + +define void @empty() { + ret void +} From 0712eac76616a088f1f1183399049560e69c3506 Mon Sep 17 00:00:00 2001 From: Thomas Raoux Date: Thu, 21 May 2020 11:59:31 -0700 Subject: [PATCH 12/14] [mlir][spirv] Enable composite instructions for cooperative matrix type. Enable inset/extract/construct composite ops as well as access chain for cooperative matrix. ConstantComposite requires more change and will be done in a separate patch. Also fix the getNumElements function for coopMatrix per feedback from Jeff Bolz. The number of element is implementation dependent so it cannot be known at compile time. Differential Revision: https://reviews.llvm.org/D80321 --- mlir/include/mlir/Dialect/SPIRV/SPIRVBase.td | 6 ++-- mlir/include/mlir/Dialect/SPIRV/SPIRVTypes.h | 8 ++++- mlir/lib/Dialect/SPIRV/SPIRVOps.cpp | 29 +++++++++++------ mlir/lib/Dialect/SPIRV/SPIRVTypes.cpp | 14 ++++++-- .../Serialization/cooperative-matrix.mlir | 8 +++++ mlir/test/Dialect/SPIRV/composite-ops.mlir | 32 +++++++++++++++++++ .../Dialect/SPIRV/cooperative-matrix.mlir | 10 ++++++ 7 files changed, 92 insertions(+), 15 deletions(-) diff --git a/mlir/include/mlir/Dialect/SPIRV/SPIRVBase.td b/mlir/include/mlir/Dialect/SPIRV/SPIRVBase.td index a3a2c2bec43bc5..ead6c0341cd69d 100644 --- a/mlir/include/mlir/Dialect/SPIRV/SPIRVBase.td +++ b/mlir/include/mlir/Dialect/SPIRV/SPIRVBase.td @@ -3027,10 +3027,12 @@ def SPV_Numerical : AnyTypeOf<[SPV_Integer, SPV_Float]>; def SPV_Scalar : AnyTypeOf<[SPV_Numerical, SPV_Bool]>; def SPV_Aggregate : AnyTypeOf<[SPV_AnyArray, SPV_AnyRTArray, SPV_AnyStruct]>; def SPV_Composite : - AnyTypeOf<[SPV_Vector, SPV_AnyArray, SPV_AnyRTArray, SPV_AnyStruct]>; + AnyTypeOf<[SPV_Vector, SPV_AnyArray, SPV_AnyRTArray, SPV_AnyStruct, + SPV_AnyCooperativeMatrix]>; def SPV_Type : AnyTypeOf<[ SPV_Void, SPV_Bool, SPV_Integer, SPV_Float, SPV_Vector, - SPV_AnyPtr, SPV_AnyArray, SPV_AnyRTArray, SPV_AnyStruct + SPV_AnyPtr, SPV_AnyArray, SPV_AnyRTArray, SPV_AnyStruct, + SPV_AnyCooperativeMatrix ]>; def SPV_SignlessOrUnsignedInt : SignlessOrUnsignedIntOfWidths<[8, 16, 32, 64]>; diff --git a/mlir/include/mlir/Dialect/SPIRV/SPIRVTypes.h b/mlir/include/mlir/Dialect/SPIRV/SPIRVTypes.h index 078fb5a672257a..71eba72e5e84d0 100644 --- a/mlir/include/mlir/Dialect/SPIRV/SPIRVTypes.h +++ b/mlir/include/mlir/Dialect/SPIRV/SPIRVTypes.h @@ -134,10 +134,16 @@ class CompositeType : public SPIRVType { /// Returns true if the given vector type is valid for the SPIR-V dialect. static bool isValid(VectorType); + /// Return the number of elements of the type. This should only be called if + /// hasCompileTimeKnownNumElements is true. unsigned getNumElements() const; Type getElementType(unsigned) const; + /// Return true if the number of elements is known at compile time and is not + /// implementation dependent. + bool hasCompileTimeKnownNumElements() const; + void getExtensions(SPIRVType::ExtensionArrayRefVector &extensions, Optional storage = llvm::None); void getCapabilities(SPIRVType::CapabilityArrayRefVector &capabilities, @@ -334,7 +340,7 @@ class StructType : public Type::TypeBase { public: using Base::Base; diff --git a/mlir/lib/Dialect/SPIRV/SPIRVOps.cpp b/mlir/lib/Dialect/SPIRV/SPIRVOps.cpp index 630f09842ccdf6..4f48ef9d7d7cfb 100644 --- a/mlir/lib/Dialect/SPIRV/SPIRVOps.cpp +++ b/mlir/lib/Dialect/SPIRV/SPIRVOps.cpp @@ -418,7 +418,9 @@ getElementType(Type type, ArrayRef indices, for (auto index : indices) { if (auto cType = type.dyn_cast()) { - if (index < 0 || static_cast(index) >= cType.getNumElements()) { + if (cType.hasCompileTimeKnownNumElements() && + (index < 0 || + static_cast(index) >= cType.getNumElements())) { emitErrorFn("index ") << index << " out of bounds for " << type; return nullptr; } @@ -1098,7 +1100,8 @@ static ParseResult parseCompositeConstructOp(OpAsmParser &parser, << type; } - if (operands.size() != cType.getNumElements()) { + if (cType.hasCompileTimeKnownNumElements() && + operands.size() != cType.getNumElements()) { return parser.emitError(loc, "has incorrect number of operands: expected ") << cType.getNumElements() << ", but provided " << operands.size(); } @@ -1107,8 +1110,8 @@ static ParseResult parseCompositeConstructOp(OpAsmParser &parser, // also be vectors with the same component type as the Result Type component // type". SmallVector elementTypes; - elementTypes.reserve(cType.getNumElements()); - for (auto index : llvm::seq(0, cType.getNumElements())) { + elementTypes.reserve(operands.size()); + for (auto index : llvm::seq(0, operands.size())) { elementTypes.push_back(cType.getElementType(index)); } state.addTypes(type); @@ -1124,13 +1127,19 @@ static void print(spirv::CompositeConstructOp compositeConstructOp, static LogicalResult verify(spirv::CompositeConstructOp compositeConstructOp) { auto cType = compositeConstructOp.getType().cast(); - SmallVector constituents(compositeConstructOp.constituents()); - if (constituents.size() != cType.getNumElements()) { - return compositeConstructOp.emitError( - "has incorrect number of operands: expected ") - << cType.getNumElements() << ", but provided " - << constituents.size(); + + if (cType.isa()) { + if (constituents.size() != 1) + return compositeConstructOp.emitError( + "has incorrect number of operands: expected ") + << "1, but provided " << constituents.size(); + } else { + if (constituents.size() != cType.getNumElements()) + return compositeConstructOp.emitError( + "has incorrect number of operands: expected ") + << cType.getNumElements() << ", but provided " + << constituents.size(); } for (auto index : llvm::seq(0, constituents.size())) { diff --git a/mlir/lib/Dialect/SPIRV/SPIRVTypes.cpp b/mlir/lib/Dialect/SPIRV/SPIRVTypes.cpp index ce5a6c0c4fd9eb..49b39ec7843530 100644 --- a/mlir/lib/Dialect/SPIRV/SPIRVTypes.cpp +++ b/mlir/lib/Dialect/SPIRV/SPIRVTypes.cpp @@ -196,8 +196,8 @@ unsigned CompositeType::getNumElements() const { case spirv::TypeKind::Array: return cast().getNumElements(); case spirv::TypeKind::CooperativeMatrix: - return cast().getRows() * - cast().getColumns(); + llvm_unreachable( + "invalid to query number of elements of spirv::CooperativeMatrix type"); case spirv::TypeKind::RuntimeArray: llvm_unreachable( "invalid to query number of elements of spirv::RuntimeArray type"); @@ -210,6 +210,16 @@ unsigned CompositeType::getNumElements() const { } } +bool CompositeType::hasCompileTimeKnownNumElements() const { + switch (getKind()) { + case TypeKind::CooperativeMatrix: + case TypeKind::RuntimeArray: + return false; + default: + return true; + } +} + void CompositeType::getExtensions( SPIRVType::ExtensionArrayRefVector &extensions, Optional storage) { diff --git a/mlir/test/Dialect/SPIRV/Serialization/cooperative-matrix.mlir b/mlir/test/Dialect/SPIRV/Serialization/cooperative-matrix.mlir index 6fb58d859d1f56..12f710ea1b465b 100644 --- a/mlir/test/Dialect/SPIRV/Serialization/cooperative-matrix.mlir +++ b/mlir/test/Dialect/SPIRV/Serialization/cooperative-matrix.mlir @@ -91,4 +91,12 @@ spv.module Logical GLSL450 requires #spv.vce spv.Return } + + // CHECK-LABEL: @cooperative_matrix_access_chain + spv.func @cooperative_matrix_access_chain(%a : !spv.ptr, Function>) -> !spv.ptr "None" { + %0 = spv.constant 0: i32 + // CHECK: {{%.*}} = spv.AccessChain {{%.*}}[{{%.*}}] : !spv.ptr, Function> + %1 = spv.AccessChain %a[%0] : !spv.ptr, Function> + spv.ReturnValue %1 : !spv.ptr + } } diff --git a/mlir/test/Dialect/SPIRV/composite-ops.mlir b/mlir/test/Dialect/SPIRV/composite-ops.mlir index 556bed823155a3..ca3f603115767d 100644 --- a/mlir/test/Dialect/SPIRV/composite-ops.mlir +++ b/mlir/test/Dialect/SPIRV/composite-ops.mlir @@ -20,6 +20,14 @@ func @composite_construct_struct(%arg0: vector<3xf32>, %arg1: !spv.array<4xf32>, // ----- +func @composite_construct_coopmatrix(%arg0 : f32) -> !spv.coopmatrix<8x16xf32, Subgroup> { + // CHECK: spv.CompositeConstruct {{%.*}} : !spv.coopmatrix<8x16xf32, Subgroup> + %0 = spv.CompositeConstruct %arg0 : !spv.coopmatrix<8x16xf32, Subgroup> + return %0: !spv.coopmatrix<8x16xf32, Subgroup> +} + +// ----- + func @composite_construct_empty_struct() -> !spv.struct<> { // CHECK: spv.CompositeConstruct : !spv.struct<> %0 = spv.CompositeConstruct : !spv.struct<> @@ -52,6 +60,14 @@ func @composite_construct_invalid_operand_type(%arg0: f32, %arg1: f32, %arg2 : f // ----- +func @composite_construct_coopmatrix(%arg0 : f32, %arg1 : f32) -> !spv.coopmatrix<8x16xf32, Subgroup> { + // expected-error @+1 {{has incorrect number of operands: expected 1, but provided 2}} + %0 = spv.CompositeConstruct %arg0, %arg1 : !spv.coopmatrix<8x16xf32, Subgroup> + return %0: !spv.coopmatrix<8x16xf32, Subgroup> +} + +// ----- + //===----------------------------------------------------------------------===// // spv.CompositeExtractOp //===----------------------------------------------------------------------===// @@ -80,6 +96,14 @@ func @composite_extract_vector(%arg0 : vector<4xf32>) -> f32 { // ----- +func @composite_extract_coopmatrix(%arg0 : !spv.coopmatrix<8x16xf32, Subgroup>) -> f32 { + // CHECK: {{%.*}} = spv.CompositeExtract {{%.*}}[2 : i32] : !spv.coopmatrix<8x16xf32, Subgroup> + %0 = spv.CompositeExtract %arg0[2 : i32] : !spv.coopmatrix<8x16xf32, Subgroup> + return %0 : f32 +} + +// ----- + func @composite_extract_no_ssa_operand() -> () { // expected-error @+1 {{expected SSA operand}} %0 = spv.CompositeExtract [4 : i32, 1 : i32] : !spv.array<4x!spv.array<4xf32>> @@ -200,6 +224,14 @@ func @composite_insert_struct(%arg0: !spv.struct, f32>, %arg1: // ----- +func @composite_insert_coopmatrix(%arg0: !spv.coopmatrix<8x16xi32, Subgroup>, %arg1: i32) -> !spv.coopmatrix<8x16xi32, Subgroup> { + // CHECK: {{%.*}} = spv.CompositeInsert {{%.*}}, {{%.*}}[5 : i32] : i32 into !spv.coopmatrix<8x16xi32, Subgroup> + %0 = spv.CompositeInsert %arg1, %arg0[5 : i32] : i32 into !spv.coopmatrix<8x16xi32, Subgroup> + return %0: !spv.coopmatrix<8x16xi32, Subgroup> +} + +// ----- + func @composite_insert_no_indices(%arg0: !spv.array<4xf32>, %arg1: f32) -> !spv.array<4xf32> { // expected-error @+1 {{expected at least one index}} %0 = spv.CompositeInsert %arg1, %arg0[] : f32 into !spv.array<4xf32> diff --git a/mlir/test/Dialect/SPIRV/cooperative-matrix.mlir b/mlir/test/Dialect/SPIRV/cooperative-matrix.mlir index 0b05d8a587e522..e30352625da67d 100644 --- a/mlir/test/Dialect/SPIRV/cooperative-matrix.mlir +++ b/mlir/test/Dialect/SPIRV/cooperative-matrix.mlir @@ -94,6 +94,16 @@ spv.func @cooperative_matrix_fdiv(%a : !spv.coopmatrix<8x16xf32, Subgroup>, %b : // ----- +// CHECK-LABEL: @cooperative_matrix_access_chain +spv.func @cooperative_matrix_access_chain(%a : !spv.ptr, Function>) -> !spv.ptr "None" { + %0 = spv.constant 0: i32 + // CHECK: {{%.*}} = spv.AccessChain {{%.*}}[{{%.*}}] : !spv.ptr, Function> + %1 = spv.AccessChain %a[%0] : !spv.ptr, Function> + spv.ReturnValue %1 : !spv.ptr +} + +// ----- + spv.func @cooperative_matrix_muladd(%a : !spv.coopmatrix<16x16xi32, Subgroup>, %b : !spv.coopmatrix<16x8xi32, Subgroup>, %c : !spv.coopmatrix<8x8xi32, Subgroup>) "None" { // expected-error @+1 {{'spv.CooperativeMatrixMulAddNV' op matrix size must match}} %r = spv.CooperativeMatrixMulAddNV %a, %b, %c : !spv.coopmatrix<16x16xi32, Subgroup>, !spv.coopmatrix<16x8xi32, Subgroup> -> !spv.coopmatrix<8x8xi32, Subgroup> From f8b4412b997b5f92d01d80eabbe587d51c8ed2c3 Mon Sep 17 00:00:00 2001 From: Jonas Devlieghere Date: Thu, 21 May 2020 12:27:39 -0700 Subject: [PATCH 13/14] [dsymutil] Add llvm_unreachable to silence warning Fixes warning: control reaches end of non-void function [-Wreturn-type] --- llvm/tools/dsymutil/Reproducer.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/llvm/tools/dsymutil/Reproducer.cpp b/llvm/tools/dsymutil/Reproducer.cpp index 448736d702e479..5c60758c6f80e5 100644 --- a/llvm/tools/dsymutil/Reproducer.cpp +++ b/llvm/tools/dsymutil/Reproducer.cpp @@ -81,4 +81,5 @@ Reproducer::createReproducer(ReproducerMode Mode, StringRef Root) { case ReproducerMode::Off: return std::make_unique(); } + llvm_unreachable("All cases handled above."); } From 1108f5c737dbdab0277874a7e5b237491839c43a Mon Sep 17 00:00:00 2001 From: Nico Weber Date: Thu, 21 May 2020 15:49:46 -0400 Subject: [PATCH 14/14] Revert "[Analyzer][WebKit] RefCntblBaseVirtualDtorChecker" This reverts commit f7c7e8a523f56b0ed1b14c0756ba4e5d1ccb48d2. Breaks build everywhere. --- clang/docs/analyzer/checkers.rst | 27 --- .../clang/StaticAnalyzer/Checkers/Checkers.td | 13 -- .../StaticAnalyzer/Checkers/CMakeLists.txt | 2 - .../StaticAnalyzer/Checkers/WebKit/ASTUtils.h | 70 ------- .../Checkers/WebKit/DiagOutputUtils.h | 28 --- .../Checkers/WebKit/PtrTypesSemantics.cpp | 172 ------------------ .../Checkers/WebKit/PtrTypesSemantics.h | 59 ------ .../WebKit/RefCntblBaseVirtualDtorChecker.cpp | 167 ----------------- .../Analysis/Checkers/WebKit/mock-types.h | 48 ----- .../ref-cntbl-base-virtual-dtor-templates.cpp | 30 --- .../WebKit/ref-cntbl-base-virtual-dtor.cpp | 53 ------ 11 files changed, 669 deletions(-) delete mode 100644 clang/lib/StaticAnalyzer/Checkers/WebKit/ASTUtils.h delete mode 100644 clang/lib/StaticAnalyzer/Checkers/WebKit/DiagOutputUtils.h delete mode 100644 clang/lib/StaticAnalyzer/Checkers/WebKit/PtrTypesSemantics.cpp delete mode 100644 clang/lib/StaticAnalyzer/Checkers/WebKit/PtrTypesSemantics.h delete mode 100644 clang/lib/StaticAnalyzer/Checkers/WebKit/RefCntblBaseVirtualDtorChecker.cpp delete mode 100644 clang/test/Analysis/Checkers/WebKit/mock-types.h delete mode 100644 clang/test/Analysis/Checkers/WebKit/ref-cntbl-base-virtual-dtor-templates.cpp delete mode 100644 clang/test/Analysis/Checkers/WebKit/ref-cntbl-base-virtual-dtor.cpp diff --git a/clang/docs/analyzer/checkers.rst b/clang/docs/analyzer/checkers.rst index 79ba8fb18ba86d..0bfb6456dc820b 100644 --- a/clang/docs/analyzer/checkers.rst +++ b/clang/docs/analyzer/checkers.rst @@ -1374,33 +1374,6 @@ double freed, or use after freed. This check attempts to find such problems. zx_handle_close(sb); } -WebKit -^^^^^^ - -WebKit is an open-source web browser engine available for macOS, iOS and Linux. -This section describes checkers that can find issues in WebKit codebase. - -Most of the checkers focus on memory management for which WebKit uses custom implementation of reference counted smartpointers. -Checker are formulated in terms related to ref-counting: -* *Ref-counted type* is either ``Ref`` or ``RefPtr``. -* *Ref-countable type* is any type that implements ``ref()`` and ``deref()`` methods as ``RefPtr<>`` is a template (i. e. relies on duck typing). -* *Uncounted type* is ref-countable but not ref-counted type. - -.. _webkit-WebKitRefCntblBaseVirtualDtor: - -webkit.WebKitRefCntblBaseVirtualDtor -"""""""""""""""""""""""""""""""""""" -All uncounted types used as base classes must have a virtual destructor. - -Ref-counted types hold their ref-countable data by a raw pointer and allow implicit upcasting from ref-counted pointer to derived type to ref-counted pointer to base type. This might lead to an object of (dynamic) derived type being deleted via pointer to the base class type which C++ standard defines as UB in case the base class doesn't have virtual destructor ``[expr.delete]``. - -.. code-block:: cpp - struct RefCntblBase { - void ref() {} - void deref() {} - }; - - struct Derived : RefCntblBase { }; // warn .. _alpha-checkers: diff --git a/clang/include/clang/StaticAnalyzer/Checkers/Checkers.td b/clang/include/clang/StaticAnalyzer/Checkers/Checkers.td index ec65afb30dd028..93c4d964d77240 100644 --- a/clang/include/clang/StaticAnalyzer/Checkers/Checkers.td +++ b/clang/include/clang/StaticAnalyzer/Checkers/Checkers.td @@ -116,9 +116,6 @@ def NonDeterminismAlpha : Package<"nondeterminism">, ParentPackage; def Fuchsia : Package<"fuchsia">; def FuchsiaAlpha : Package<"fuchsia">, ParentPackage; -def WebKit : Package<"webkit">; -def WebKitAlpha : Package<"webkit">, ParentPackage; - //===----------------------------------------------------------------------===// // Core Checkers. //===----------------------------------------------------------------------===// @@ -1623,13 +1620,3 @@ def FuchsiaLockChecker : Checker<"Lock">, } // end fuchsia -//===----------------------------------------------------------------------===// -// WebKit checkers. -//===----------------------------------------------------------------------===// - -let ParentPackage = WebKit in { - -def WebKitRefCntblBaseVirtualDtorChecker : Checker<"WebKitRefCntblBaseVirtualDtor">, - HelpText<"Check for any ref-countable base class having virtual destructor.">, - Documentation; -} // end webkit diff --git a/clang/lib/StaticAnalyzer/Checkers/CMakeLists.txt b/clang/lib/StaticAnalyzer/Checkers/CMakeLists.txt index 4f885fadf4158d..bcf2dfdb832661 100644 --- a/clang/lib/StaticAnalyzer/Checkers/CMakeLists.txt +++ b/clang/lib/StaticAnalyzer/Checkers/CMakeLists.txt @@ -121,8 +121,6 @@ add_clang_library(clangStaticAnalyzerCheckers VLASizeChecker.cpp ValistChecker.cpp VirtualCallChecker.cpp - WebKit/PtrTypesSemantics.cpp - WebKit/RefCntblBaseVirtualDtorChecker.cpp LINK_LIBS clangAST diff --git a/clang/lib/StaticAnalyzer/Checkers/WebKit/ASTUtils.h b/clang/lib/StaticAnalyzer/Checkers/WebKit/ASTUtils.h deleted file mode 100644 index 26d79cfcd9b519..00000000000000 --- a/clang/lib/StaticAnalyzer/Checkers/WebKit/ASTUtils.h +++ /dev/null @@ -1,70 +0,0 @@ -//=======- ASTUtis.h ---------------------------------------------*- C++ -*-==// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// - -#ifndef LLVM_CLANG_ANALYZER_WEBKIT_ASTUTILS_H -#define LLVM_CLANG_ANALYZER_WEBKIT_ASTUTILS_H - -#include "clang/AST/Decl.h" -#include "llvm/ADT/APInt.h" -#include "llvm/Support/Casting.h" - -#include -#include - -namespace clang { -class CXXRecordDecl; -class CXXBaseSpecifier; -class FunctionDecl; -class CXXMethodDecl; -class Expr; - -/// If passed expression is of type uncounted pointer/reference we try to find -/// the origin of this pointer. Example: Origin can be a local variable, nullptr -/// constant or this-pointer. -/// -/// Certain subexpression nodes represent transformations that don't affect -/// where the memory address originates from. We try to traverse such -/// subexpressions to get to the relevant child nodes. Whenever we encounter a -/// subexpression that either can't be ignored, we don't model its semantics or -/// that has multiple children we stop. -/// -/// \p E is an expression of uncounted pointer/reference type. -/// If \p StopAtFirstRefCountedObj is true and we encounter a subexpression that -/// represents ref-counted object during the traversal we return relevant -/// sub-expression and true. -/// -/// \returns subexpression that we traversed to and if \p -/// StopAtFirstRefCountedObj is true we also return whether we stopped early. -std::pair -tryToFindPtrOrigin(const clang::Expr *E, bool StopAtFirstRefCountedObj); - -/// For \p E referring to a ref-countable/-counted pointer/reference we return -/// whether it's a safe call argument. Examples: function parameter or -/// this-pointer. The logic relies on the set of recursive rules we enforce for -/// WebKit codebase. -/// -/// \returns Whether \p E is a safe call arugment. -bool isASafeCallArg(const clang::Expr *E); - -/// \returns name of AST node or empty string. -template std::string safeGetName(const T *ASTNode) { - const auto *const ND = llvm::dyn_cast_or_null(ASTNode); - if (!ND) - return ""; - - // In case F is for example "operator|" the getName() method below would - // assert. - if (!ND->getDeclName().isIdentifier()) - return ""; - - return ND->getName().str(); -} - -} // namespace clang - -#endif diff --git a/clang/lib/StaticAnalyzer/Checkers/WebKit/DiagOutputUtils.h b/clang/lib/StaticAnalyzer/Checkers/WebKit/DiagOutputUtils.h deleted file mode 100644 index 4979b8ffc2b20c..00000000000000 --- a/clang/lib/StaticAnalyzer/Checkers/WebKit/DiagOutputUtils.h +++ /dev/null @@ -1,28 +0,0 @@ -//=======- DiagOutputUtils.h -------------------------------------*- C++ -*-==// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// - -#ifndef LLVM_CLANG_ANALYZER_WEBKIT_DIAGPRINTUTILS_H -#define LLVM_CLANG_ANALYZER_WEBKIT_DIAGPRINTUTILS_H - -#include "clang/AST/Decl.h" -#include "llvm/Support/raw_ostream.h" - -namespace clang { - -template -void printQuotedQualifiedName(llvm::raw_ostream &Os, - const NamedDeclDerivedT &D) { - Os << "'"; - D->getNameForDiagnostic(Os, D->getASTContext().getPrintingPolicy(), - /*Qualified=*/true); - Os << "'"; -} - -} // namespace clang - -#endif diff --git a/clang/lib/StaticAnalyzer/Checkers/WebKit/PtrTypesSemantics.cpp b/clang/lib/StaticAnalyzer/Checkers/WebKit/PtrTypesSemantics.cpp deleted file mode 100644 index adb6253df96526..00000000000000 --- a/clang/lib/StaticAnalyzer/Checkers/WebKit/PtrTypesSemantics.cpp +++ /dev/null @@ -1,172 +0,0 @@ -//=======- PtrTypesSemantics.cpp ---------------------------------*- C++ -*-==// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// - -#include "PtrTypesSemantics.h" -#include "ASTUtils.h" -#include "clang/AST/CXXInheritance.h" -#include "clang/AST/Decl.h" -#include "clang/AST/DeclCXX.h" -#include "clang/AST/ExprCXX.h" - -using llvm::Optional; -using namespace clang; - -namespace { - -bool hasPublicRefAndDeref(const CXXRecordDecl *R) { - assert(R); - - bool hasRef = false; - bool hasDeref = false; - for (const CXXMethodDecl *MD : R->methods()) { - const auto MethodName = safeGetName(MD); - - if (MethodName == "ref" && MD->getAccess() == AS_public) { - if (hasDeref) - return true; - hasRef = true; - } else if (MethodName == "deref" && MD->getAccess() == AS_public) { - if (hasRef) - return true; - hasDeref = true; - } - } - return false; -} - -} // namespace - -namespace clang { - -const CXXRecordDecl *isRefCountable(const CXXBaseSpecifier *Base) { - assert(Base); - - const Type *T = Base->getType().getTypePtrOrNull(); - if (!T) - return nullptr; - - const CXXRecordDecl *R = T->getAsCXXRecordDecl(); - if (!R) - return nullptr; - - return hasPublicRefAndDeref(R) ? R : nullptr; -}; - -bool isRefCountable(const CXXRecordDecl *R) { - assert(R); - - R = R->getDefinition(); - assert(R); - - if (hasPublicRefAndDeref(R)) - return true; - - CXXBasePaths Paths; - Paths.setOrigin(const_cast(R)); - - const auto isRefCountableBase = [](const CXXBaseSpecifier *Base, - CXXBasePath &) { - return clang::isRefCountable(Base); - }; - - return R->lookupInBases(isRefCountableBase, Paths, - /*LookupInDependent =*/true); -} - -bool isCtorOfRefCounted(const clang::FunctionDecl *F) { - assert(F); - const auto &FunctionName = safeGetName(F); - - return FunctionName == "Ref" || FunctionName == "makeRef" - - || FunctionName == "RefPtr" || FunctionName == "makeRefPtr" - - || FunctionName == "UniqueRef" || FunctionName == "makeUniqueRef" || - FunctionName == "makeUniqueRefWithoutFastMallocCheck" - - || FunctionName == "String" || FunctionName == "AtomString" || - FunctionName == "UniqueString" - // FIXME: Implement as attribute. - || FunctionName == "Identifier"; -} - -bool isUncounted(const CXXRecordDecl *Class) { - // Keep isRefCounted first as it's cheaper. - return !isRefCounted(Class) && isRefCountable(Class); -} - -bool isUncountedPtr(const Type *T) { - assert(T); - - if (T->isPointerType() || T->isReferenceType()) { - if (auto *CXXRD = T->getPointeeCXXRecordDecl()) { - return isUncounted(CXXRD); - } - } - return false; -} - -bool isGetterOfRefCounted(const CXXMethodDecl *M) { - assert(M); - - if (auto *calleeMethodDecl = dyn_cast(M)) { - const CXXRecordDecl *calleeMethodsClass = M->getParent(); - auto className = safeGetName(calleeMethodsClass); - auto methodName = safeGetName(M); - - if (((className == "Ref" || className == "RefPtr") && - methodName == "get") || - ((className == "String" || className == "AtomString" || - className == "AtomStringImpl" || className == "UniqueString" || - className == "UniqueStringImpl" || className == "Identifier") && - methodName == "impl")) - return true; - - // Ref -> T conversion - // FIXME: Currently allowing any Ref -> whatever cast. - if (className == "Ref" || className == "RefPtr") { - if (auto *maybeRefToRawOperator = dyn_cast(M)) { - if (auto *targetConversionType = - maybeRefToRawOperator->getConversionType().getTypePtrOrNull()) { - if (isUncountedPtr(targetConversionType)) { - return true; - } - } - } - } - } - return false; -} - -bool isRefCounted(const CXXRecordDecl *R) { - assert(R); - if (auto *TmplR = R->getTemplateInstantiationPattern()) { - // FIXME: String/AtomString/UniqueString - const auto &ClassName = safeGetName(TmplR); - return ClassName == "RefPtr" || ClassName == "Ref"; - } - return false; -} - -bool isPtrConversion(const FunctionDecl *F) { - assert(F); - if (isCtorOfRefCounted(F)) - return true; - - // FIXME: check # of params == 1 - const auto FunctionName = safeGetName(F); - if (FunctionName == "getPtr" || FunctionName == "WeakPtr" || - FunctionName == "makeWeakPtr" - - || FunctionName == "downcast" || FunctionName == "bitwise_cast") - return true; - - return false; -} - -} // namespace clang diff --git a/clang/lib/StaticAnalyzer/Checkers/WebKit/PtrTypesSemantics.h b/clang/lib/StaticAnalyzer/Checkers/WebKit/PtrTypesSemantics.h deleted file mode 100644 index 83d9c0bcc13b38..00000000000000 --- a/clang/lib/StaticAnalyzer/Checkers/WebKit/PtrTypesSemantics.h +++ /dev/null @@ -1,59 +0,0 @@ -//=======- PtrTypesSemantics.cpp ---------------------------------*- C++ -*-==// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// - -#ifndef LLVM_CLANG_ANALYZER_WEBKIT_PTRTYPESEMANTICS_H -#define LLVM_CLANG_ANALYZER_WEBKIT_PTRTYPESEMANTICS_H - -namespace clang { -class CXXBaseSpecifier; -class CXXMethodDecl; -class CXXRecordDecl; -class Expr; -class FunctionDecl; -class Type; - -// Ref-countability of a type is implicitly defined by Ref and RefPtr -// implementation. It can be modeled as: type T having public methods ref() and -// deref() - -// In WebKit there are two ref-counted templated smart pointers: RefPtr and -// Ref. - -/// \returns CXXRecordDecl of the base if the type is ref-countable, nullptr if -/// not. -const clang::CXXRecordDecl *isRefCountable(const clang::CXXBaseSpecifier *Base); - -/// \returns true if \p Class is ref-countable, false if not. -/// Asserts that \p Class IS a definition. -bool isRefCountable(const clang::CXXRecordDecl *Class); - -/// \returns true if \p Class is ref-counted, false if not. -bool isRefCounted(const clang::CXXRecordDecl *Class); - -/// \returns true if \p Class is ref-countable AND not ref-counted, false if -/// not. Asserts that \p Class IS a definition. -bool isUncounted(const clang::CXXRecordDecl *Class); - -/// \returns true if \p T is either a raw pointer or reference to an uncounted -/// class, false if not. -bool isUncountedPtr(const clang::Type *T); - -/// \returns true if \p F creates ref-countable object from uncounted parameter, -/// false if not. -bool isCtorOfRefCounted(const clang::FunctionDecl *F); - -/// \returns true if \p M is getter of a ref-counted class, false if not. -bool isGetterOfRefCounted(const clang::CXXMethodDecl *Method); - -/// \returns true if \p F is a conversion between ref-countable or ref-counted -/// pointer types. -bool isPtrConversion(const FunctionDecl *F); - -} // namespace clang - -#endif diff --git a/clang/lib/StaticAnalyzer/Checkers/WebKit/RefCntblBaseVirtualDtorChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/WebKit/RefCntblBaseVirtualDtorChecker.cpp deleted file mode 100644 index 4343d427351b09..00000000000000 --- a/clang/lib/StaticAnalyzer/Checkers/WebKit/RefCntblBaseVirtualDtorChecker.cpp +++ /dev/null @@ -1,167 +0,0 @@ -//=======- RefCntblBaseVirtualDtor.cpp ---------------------------*- C++ -*-==// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// - -#include "DiagOutputUtils.h" -#include "PtrTypesSemantics.h" -#include "clang/AST/CXXInheritance.h" -#include "clang/AST/RecursiveASTVisitor.h" -#include "clang/StaticAnalyzer/Checkers/BuiltinCheckerRegistration.h" -#include "clang/StaticAnalyzer/Core/BugReporter/BugReporter.h" -#include "clang/StaticAnalyzer/Core/BugReporter/BugType.h" -#include "clang/StaticAnalyzer/Core/Checker.h" - -using namespace clang; -using namespace ento; - -namespace { -class RefCntblBaseVirtualDtorChecker - : public Checker> { -private: - BugType Bug; - mutable BugReporter *BR; - -public: - RefCntblBaseVirtualDtorChecker() - : Bug(this, - "Reference-countable base class doesn't have virtual destructor", - "WebKit coding guidelines") {} - - void checkASTDecl(const TranslationUnitDecl *TUD, AnalysisManager &MGR, - BugReporter &BRArg) const { - BR = &BRArg; - - // The calls to checkAST* from AnalysisConsumer don't - // visit template instantiations or lambda classes. We - // want to visit those, so we make our own RecursiveASTVisitor. - struct LocalVisitor : public RecursiveASTVisitor { - const RefCntblBaseVirtualDtorChecker *Checker; - explicit LocalVisitor(const RefCntblBaseVirtualDtorChecker *Checker) - : Checker(Checker) { - assert(Checker); - } - - bool shouldVisitTemplateInstantiations() const { return true; } - bool shouldVisitImplicitCode() const { return false; } - - bool VisitCXXRecordDecl(const CXXRecordDecl *RD) { - Checker->visitCXXRecordDecl(RD); - return true; - } - }; - - LocalVisitor visitor(this); - visitor.TraverseDecl(const_cast(TUD)); - } - - void visitCXXRecordDecl(const CXXRecordDecl *RD) const { - if (shouldSkipDecl(RD)) - return; - - CXXBasePaths Paths; - Paths.setOrigin(RD); - - const CXXBaseSpecifier *ProblematicBaseSpecifier = nullptr; - const CXXRecordDecl *ProblematicBaseClass = nullptr; - - const auto IsPublicBaseRefCntblWOVirtualDtor = - [RD, &ProblematicBaseSpecifier, - &ProblematicBaseClass](const CXXBaseSpecifier *Base, CXXBasePath &) { - const auto AccSpec = Base->getAccessSpecifier(); - if (AccSpec == AS_protected || AccSpec == AS_private || - (AccSpec == AS_none && RD->isClass())) - return false; - - llvm::Optional MaybeRefCntblBaseRD = - isRefCountable(Base); - if (!MaybeRefCntblBaseRD.hasValue()) - return false; - - const CXXRecordDecl *RefCntblBaseRD = MaybeRefCntblBaseRD.getValue(); - if (!RefCntblBaseRD) - return false; - - const auto *Dtor = RefCntblBaseRD->getDestructor(); - if (!Dtor || !Dtor->isVirtual()) { - ProblematicBaseSpecifier = Base; - ProblematicBaseClass = RefCntblBaseRD; - return true; - } - - return false; - }; - - if (RD->lookupInBases(IsPublicBaseRefCntblWOVirtualDtor, Paths, - /*LookupInDependent =*/true)) { - reportBug(RD, ProblematicBaseSpecifier, ProblematicBaseClass); - } - } - - bool shouldSkipDecl(const CXXRecordDecl *RD) const { - if (!RD->isThisDeclarationADefinition()) - return true; - - if (RD->isImplicit()) - return true; - - if (RD->isLambda()) - return true; - - // If the construct doesn't have a source file, then it's not something - // we want to diagnose. - const auto RDLocation = RD->getLocation(); - if (!RDLocation.isValid()) - return true; - - const auto Kind = RD->getTagKind(); - if (Kind != TTK_Struct && Kind != TTK_Class) - return true; - - // Ignore CXXRecords that come from system headers. - if (BR->getSourceManager().getFileCharacteristic(RDLocation) != - SrcMgr::C_User) - return true; - - return false; - } - - void reportBug(const CXXRecordDecl *DerivedClass, - const CXXBaseSpecifier *BaseSpec, - const CXXRecordDecl *ProblematicBaseClass) const { - assert(DerivedClass); - assert(BaseSpec); - assert(ProblematicBaseClass); - - SmallString<100> Buf; - llvm::raw_svector_ostream Os(Buf); - - Os << (ProblematicBaseClass->isClass() ? "Class" : "Struct") << " "; - printQuotedQualifiedName(Os, ProblematicBaseClass); - - Os << " is used as a base of " - << (DerivedClass->isClass() ? "class" : "struct") << " "; - printQuotedQualifiedName(Os, DerivedClass); - - Os << " but doesn't have virtual destructor"; - - PathDiagnosticLocation BSLoc(BaseSpec->getSourceRange().getBegin(), - BR->getSourceManager()); - auto Report = std::make_unique(Bug, Os.str(), BSLoc); - Report->addRange(BaseSpec->getSourceRange()); - BR->emitReport(std::move(Report)); - } -}; -} // namespace - -void ento::registerWebKitRefCntblBaseVirtualDtorChecker(CheckerManager &Mgr) { - Mgr.registerChecker(); -} - -bool ento::shouldRegisterWebKitRefCntblBaseVirtualDtorChecker( - const LangOptions &LO) { - return true; -} diff --git a/clang/test/Analysis/Checkers/WebKit/mock-types.h b/clang/test/Analysis/Checkers/WebKit/mock-types.h deleted file mode 100644 index 5f570b8bee8cb8..00000000000000 --- a/clang/test/Analysis/Checkers/WebKit/mock-types.h +++ /dev/null @@ -1,48 +0,0 @@ -#ifndef mock_types_1103988513531 -#define mock_types_1103988513531 - -template struct Ref { - T t; - - Ref() : t{} {}; - Ref(T *) {} - T *get() { return nullptr; } - operator const T &() const { return t; } - operator T &() { return t; } -}; - -template struct RefPtr { - T *t; - - RefPtr() : t(new T) {} - RefPtr(T *t) : t(t) {} - T *get() { return t; } - T *operator->() { return t; } - T &operator*() { return *t; } - RefPtr &operator=(T *) { return *this; } -}; - -template bool operator==(const RefPtr &, const RefPtr &) { - return false; -} - -template bool operator==(const RefPtr &, T *) { return false; } - -template bool operator==(const RefPtr &, T &) { return false; } - -template bool operator!=(const RefPtr &, const RefPtr &) { - return false; -} - -template bool operator!=(const RefPtr &, T *) { return false; } - -template bool operator!=(const RefPtr &, T &) { return false; } - -struct RefCountable { - void ref() {} - void deref() {} -}; - -template T *downcast(T *t) { return t; } - -#endif diff --git a/clang/test/Analysis/Checkers/WebKit/ref-cntbl-base-virtual-dtor-templates.cpp b/clang/test/Analysis/Checkers/WebKit/ref-cntbl-base-virtual-dtor-templates.cpp deleted file mode 100644 index f73655258b4783..00000000000000 --- a/clang/test/Analysis/Checkers/WebKit/ref-cntbl-base-virtual-dtor-templates.cpp +++ /dev/null @@ -1,30 +0,0 @@ -// RUN: %clang_analyze_cc1 -analyzer-checker=webkit.WebKitRefCntblBaseVirtualDtor -verify %s - -struct RefCntblBase { - void ref() {} - void deref() {} -}; - -template -struct DerivedClassTmpl1 : T { }; -// expected-warning@-1{{Struct 'RefCntblBase' is used as a base of struct 'DerivedClassTmpl1' but doesn't have virtual destructor}} - -DerivedClassTmpl1 a; - - - -template -struct DerivedClassTmpl2 : T { }; -// expected-warning@-1{{Struct 'RefCntblBase' is used as a base of struct 'DerivedClassTmpl2' but doesn't have virtual destructor}} - -template int foo(T) { DerivedClassTmpl2 f; return 42; } -int b = foo(RefCntblBase{}); - - - -template -struct DerivedClassTmpl3 : T { }; -// expected-warning@-1{{Struct 'RefCntblBase' is used as a base of struct 'DerivedClassTmpl3' but doesn't have virtual destructor}} - -typedef DerivedClassTmpl3 Foo; -Foo c; diff --git a/clang/test/Analysis/Checkers/WebKit/ref-cntbl-base-virtual-dtor.cpp b/clang/test/Analysis/Checkers/WebKit/ref-cntbl-base-virtual-dtor.cpp deleted file mode 100644 index a0eb4d6169b666..00000000000000 --- a/clang/test/Analysis/Checkers/WebKit/ref-cntbl-base-virtual-dtor.cpp +++ /dev/null @@ -1,53 +0,0 @@ -// RUN: %clang_analyze_cc1 -analyzer-checker=webkit.WebKitRefCntblBaseVirtualDtor -verify %s - -struct RefCntblBase { - void ref() {} - void deref() {} -}; - -struct Derived : RefCntblBase { }; -// expected-warning@-1{{Struct 'RefCntblBase' is used as a base of struct 'Derived' but doesn't have virtual destructor}} - -struct DerivedWithVirtualDtor : RefCntblBase { -// expected-warning@-1{{Struct 'RefCntblBase' is used as a base of struct 'DerivedWithVirtualDtor' but doesn't have virtual destructor}} - virtual ~DerivedWithVirtualDtor() {} -}; - - - -template -struct DerivedClassTmpl : T { }; -typedef DerivedClassTmpl Foo; - - - -struct RandomBase {}; -struct RandomDerivedClass : RandomBase { }; - - - -struct FakeRefCntblBase1 { - private: - void ref() {} - void deref() {} -}; -struct Quiet1 : FakeRefCntblBase1 {}; - -struct FakeRefCntblBase2 { - protected: - void ref() {} - void deref() {} -}; -struct Quiet2 : FakeRefCntblBase2 {}; - -class FakeRefCntblBase3 { - void ref() {} - void deref() {} -}; -struct Quiet3 : FakeRefCntblBase3 {}; -struct Quiet4 : private RefCntblBase {}; -class Quiet5 : RefCntblBase {}; - -void foo () { - Derived d; -}