[bugpoint] Reduce metadata that does not contribute to crash.
authorFlorian Hahn <flo@fhahn.com>
Wed, 30 Oct 2019 14:30:42 +0000 (14:30 +0000)
committerFlorian Hahn <flo@fhahn.com>
Wed, 30 Oct 2019 15:11:56 +0000 (15:11 +0000)
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
llvm/test/BugPoint/retain-crashing-metadata.ll [new file with mode: 0644]
llvm/tools/bugpoint-passes/TestPasses.cpp
llvm/tools/bugpoint/CrashDebugger.cpp

index a090bbd..9cc4659 100644 (file)
@@ -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 (file)
index 0000000..ddceb80
--- /dev/null
@@ -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}
index 6340a3e..d11a605 100644 (file)
@@ -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
 
 #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<CrashOnFunctionAttribute>
     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<CrashOnMetadata>
+    C("bugpoint-crashmetadata",
+      "BugPoint Test Pass - Intentionally crash on "
+      "fabs calls with fpmath metadata and an fadd as argument");
index de86fc2..6e95630 100644 (file)
 #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 <set>
 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<Instruction *> {
+  BugDriver &BD;
+  BugTester TestFn;
+
+public:
+  ReduceCrashingMetadata(BugDriver &bd, BugTester testFn)
+      : BD(bd), TestFn(testFn) {}
+
+  Expected<TestResult> doTest(std::vector<Instruction *> &Prefix,
+                              std::vector<Instruction *> &Kept) override {
+    if (!Kept.empty() && TestInsts(Kept))
+      return KeepSuffix;
+    if (!Prefix.empty() && TestInsts(Prefix))
+      return KeepPrefix;
+    return NoFailure;
+  }
+
+  bool TestInsts(std::vector<Instruction *> &Prefix);
+};
+} // namespace
+
+bool ReduceCrashingMetadata::TestInsts(std::vector<Instruction *> &Insts) {
+  // Clone the program to try hacking it apart...
+  ValueToValueMapTy VMap;
+  std::unique_ptr<Module> M = CloneModule(BD.getProgram(), VMap);
+
+  // Convert list to set for fast lookup...
+  SmallPtrSet<Instruction *, 32> Instructions;
+  for (Instruction *I : Insts)
+    Instructions.insert(cast<Instruction>(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<std::string> {
@@ -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<Instruction *> Insts;
+    for (Function &F : BD.getProgram())
+      for (Instruction &I : instructions(F))
+        Insts.push_back(&I);
+
+    Expected<bool> Result =
+        ReduceCrashingMetadata(BD, TestFn).reduceList(Insts);
+    if (Error E = Result.takeError())
+      return E;
+  }
+
   BD.EmitProgressBitcode(BD.getProgram(), "reduced-instructions");
   return Error::success();
 }