From 29e8b8ce6697414759f9314255d0165edbb3e454 Mon Sep 17 00:00:00 2001 From: Florian Hahn Date: Wed, 30 Oct 2019 14:30:42 +0000 Subject: [PATCH] [bugpoint] Reduce metadata that does not contribute to crash. Add a new reducer that drops metadata that does not contribute to the crash from instructions. It adjusts the metadata.ll test case, as now also the instruction level metadata will get dropped. Reviewers: davide, reames, modocache Reviewed By: reames Differential Revision: https://reviews.llvm.org/D69234 --- llvm/test/BugPoint/metadata.ll | 16 ++--- llvm/test/BugPoint/retain-crashing-metadata.ll | 22 +++++++ llvm/tools/bugpoint-passes/TestPasses.cpp | 34 ++++++++++ llvm/tools/bugpoint/CrashDebugger.cpp | 90 +++++++++++++++++++++++++- 4 files changed, 151 insertions(+), 11 deletions(-) create mode 100644 llvm/test/BugPoint/retain-crashing-metadata.ll diff --git a/llvm/test/BugPoint/metadata.ll b/llvm/test/BugPoint/metadata.ll index a090bbd..9cc4659 100644 --- a/llvm/test/BugPoint/metadata.ll +++ b/llvm/test/BugPoint/metadata.ll @@ -8,22 +8,18 @@ ; RUN: bugpoint -load %llvmshlibdir/BugpointPasses%shlibext %s -output-prefix %t-notype -bugpoint-crashcalls -silence-passes -disable-namedmd-remove -disable-strip-debuginfo > /dev/null ; RUN: llvm-dis %t-notype-reduced-simplified.bc -o - | FileCheck %s --check-prefix=NOTYPE ; -; Bugpoint should keep the call's metadata attached to the call. +; Bugpoint can drop the metadata on the call, as it does not contrinute to the crash. -; CHECK: call void @foo(), !dbg ![[LOC:[0-9]+]], !attach ![[CALL:[0-9]+]] -; NODEBUG: call void @foo(), !attach ![[CALL:[0-9]+]] -; NOTYPE: call void @foo(), !dbg ![[LOC:[0-9]+]], !attach ![[CALL:[0-9]+]] -; NODEBUG-NOT: call void @foo(), !attach ![[CALL:[0-9]+]] +; CHECK: call void @foo() +; NODEBUG: call void @foo() +; NOTYPE: call void @foo() +; NODEBUG-NOT: call void @foo() ; NOTYPE-NOT: !DIBasicType ; NOTYPE: !DICompileUnit ; NOTYPE-NOT: !DIBasicType -; CHECK-DAG: ![[LOC]] = !DILocation(line: 104, column: 105, scope: ![[SCOPE:[0-9]+]]) -; CHECK-DAG: ![[SCOPE]] = distinct !DISubprogram(name: "test",{{.*}}file: ![[FILE:[0-9]+]] -; CHECK-DAG: ![[FILE]] = !DIFile(filename: "source.c", directory: "/dir") -; CHECK-DAG: ![[CALL]] = !{!"the call to foo"} %rust_task = type {} -define void @test(i32* %a, i8* %b) { +define void @test(i32* %a, i8* %b) !dbg !9 { %s = mul i8 22, 9, !attach !0, !dbg !10 store i8 %s, i8* %b, !attach !1, !dbg !11 call void @foo(), !attach !2, !dbg !12 diff --git a/llvm/test/BugPoint/retain-crashing-metadata.ll b/llvm/test/BugPoint/retain-crashing-metadata.ll new file mode 100644 index 0000000..ddceb80 --- /dev/null +++ b/llvm/test/BugPoint/retain-crashing-metadata.ll @@ -0,0 +1,22 @@ +; REQUIRES: plugins +; RUN: bugpoint -load %llvmshlibdir/BugpointPasses%shlibext %s -output-prefix %t-notype -bugpoint-crashmetadata -silence-passes > /dev/null +; RUN: llvm-dis %t-notype-reduced-simplified.bc -o - | FileCheck %s +; +; Make sure BugPoint retains metadata contributing to a crash. + +; CHECK-LABEL: define void @test2(float %f) { +; CHECK-NEXT: %arg = fadd float %f, 1.000000e+01 +; CHECK-NOT: !fpmath +; CHECK-NEXT: %x = call float @llvm.fabs.f32(float %arg), !fpmath [[FPMATH:![0-9]+]] +; CHECK-NEXT: ret void + +; CHECK: [[FPMATH]] = !{float 2.500000e+00} +define void @test2(float %f) { + %arg = fadd float %f, 1.000000e+01, !fpmath !0 + %x = call float @llvm.fabs.f32(float %arg), !fpmath !0 + ret void +} + +declare float @llvm.fabs.f32(float) + +!0 = !{float 2.500000e+00} diff --git a/llvm/tools/bugpoint-passes/TestPasses.cpp b/llvm/tools/bugpoint-passes/TestPasses.cpp index 6340a3e..d11a605 100644 --- a/llvm/tools/bugpoint-passes/TestPasses.cpp +++ b/llvm/tools/bugpoint-passes/TestPasses.cpp @@ -1,5 +1,6 @@ //===- TestPasses.cpp - "buggy" passes used to test bugpoint --------------===// // +// // 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 @@ -13,11 +14,14 @@ #include "llvm/IR/BasicBlock.h" #include "llvm/IR/Constant.h" +#include "llvm/IR/InstIterator.h" #include "llvm/IR/InstVisitor.h" #include "llvm/IR/Instructions.h" #include "llvm/IR/Type.h" #include "llvm/Pass.h" +#include "llvm/IR/PatternMatch.h" +using namespace llvm::PatternMatch; using namespace llvm; namespace { @@ -147,3 +151,33 @@ char CrashOnFunctionAttribute::ID = 0; static RegisterPass B("bugpoint-crashfuncattr", "BugPoint Test Pass - Intentionally crash on " "function attribute 'bugpoint-crash'"); + +namespace { +class CrashOnMetadata : public FunctionPass { +public: + static char ID; // Pass ID, replacement for typeid + CrashOnMetadata() : FunctionPass(ID) {} + +private: + void getAnalysisUsage(AnalysisUsage &AU) const override { + AU.setPreservesAll(); + } + + // Crash on fabs calls with fpmath metdata and an fadd as argument. This + // ensures the fadd instruction sticks around and we can check that the + // metadata there is dropped correctly. + bool runOnFunction(Function &F) override { + for (Instruction &I : instructions(F)) + if (match(&I, m_FAbs(m_FAdd(m_Value(), m_Value()))) && + I.hasMetadata("fpmath")) + abort(); + return false; + } +}; +} // namespace + +char CrashOnMetadata::ID = 0; +static RegisterPass + C("bugpoint-crashmetadata", + "BugPoint Test Pass - Intentionally crash on " + "fabs calls with fpmath metadata and an fadd as argument"); diff --git a/llvm/tools/bugpoint/CrashDebugger.cpp b/llvm/tools/bugpoint/CrashDebugger.cpp index de86fc2..6e95630 100644 --- a/llvm/tools/bugpoint/CrashDebugger.cpp +++ b/llvm/tools/bugpoint/CrashDebugger.cpp @@ -16,11 +16,11 @@ #include "llvm/ADT/SmallPtrSet.h" #include "llvm/ADT/StringSet.h" #include "llvm/Analysis/TargetTransformInfo.h" -#include "llvm/Transforms/Utils/Local.h" #include "llvm/IR/CFG.h" #include "llvm/IR/Constants.h" #include "llvm/IR/DebugInfo.h" #include "llvm/IR/DerivedTypes.h" +#include "llvm/IR/InstIterator.h" #include "llvm/IR/Instructions.h" #include "llvm/IR/LegacyPassManager.h" #include "llvm/IR/Module.h" @@ -32,6 +32,7 @@ #include "llvm/Transforms/Scalar.h" #include "llvm/Transforms/Utils/BasicBlockUtils.h" #include "llvm/Transforms/Utils/Cloning.h" +#include "llvm/Transforms/Utils/Local.h" #include using namespace llvm; @@ -806,6 +807,78 @@ bool ReduceCrashingInstructions::TestInsts( } namespace { +/// ReduceCrashingMetadata reducer - This works by removing all metadata from +/// the specified instructions. +/// +class ReduceCrashingMetadata : public ListReducer { + BugDriver &BD; + BugTester TestFn; + +public: + ReduceCrashingMetadata(BugDriver &bd, BugTester testFn) + : BD(bd), TestFn(testFn) {} + + Expected doTest(std::vector &Prefix, + std::vector &Kept) override { + if (!Kept.empty() && TestInsts(Kept)) + return KeepSuffix; + if (!Prefix.empty() && TestInsts(Prefix)) + return KeepPrefix; + return NoFailure; + } + + bool TestInsts(std::vector &Prefix); +}; +} // namespace + +bool ReduceCrashingMetadata::TestInsts(std::vector &Insts) { + // Clone the program to try hacking it apart... + ValueToValueMapTy VMap; + std::unique_ptr M = CloneModule(BD.getProgram(), VMap); + + // Convert list to set for fast lookup... + SmallPtrSet Instructions; + for (Instruction *I : Insts) + Instructions.insert(cast(VMap[I])); + + outs() << "Checking for crash with metadata retained from " + << Instructions.size(); + if (Instructions.size() == 1) + outs() << " instruction: "; + else + outs() << " instructions: "; + + // Try to drop instruction metadata from all instructions, except the ones + // selected in Instructions. + for (Function &F : *M) + for (Instruction &Inst : instructions(F)) { + if (Instructions.find(&Inst) == Instructions.end()) { + Inst.dropUnknownNonDebugMetadata(); + Inst.setDebugLoc({}); + } + } + + // Verify that this is still valid. + legacy::PassManager Passes; + Passes.add(createVerifierPass(/*FatalErrors=*/false)); + Passes.run(*M); + + // Try running on the hacked up program... + if (TestFn(BD, M.get())) { + BD.setNewProgram(std::move(M)); // It crashed, keep the trimmed version... + + // Make sure to use instruction pointers that point into the now-current + // module, and that they don't include any deleted blocks. + Insts.clear(); + for (Instruction *I : Instructions) + Insts.push_back(I); + return true; + } + // It didn't crash, try something else. + return false; +} + +namespace { // Reduce the list of Named Metadata nodes. We keep this as a list of // names to avoid having to convert back and forth every time. class ReduceCrashingNamedMD : public ListReducer { @@ -1081,6 +1154,21 @@ static Error ReduceInsts(BugDriver &BD, BugTester TestFn) { } } while (Simplification); + + // Attempt to drop metadata from instructions that does not contribute to the + // crash. + if (!BugpointIsInterrupted) { + std::vector Insts; + for (Function &F : BD.getProgram()) + for (Instruction &I : instructions(F)) + Insts.push_back(&I); + + Expected Result = + ReduceCrashingMetadata(BD, TestFn).reduceList(Insts); + if (Error E = Result.takeError()) + return E; + } + BD.EmitProgressBitcode(BD.getProgram(), "reduced-instructions"); return Error::success(); } -- 2.7.4