OSDN Git Service

[llvm-reduce] Reducing call operand bundles
authorRoman Lebedev <lebedev.ri@gmail.com>
Mon, 6 Jul 2020 22:16:37 +0000 (01:16 +0300)
committerRoman Lebedev <lebedev.ri@gmail.com>
Mon, 6 Jul 2020 22:16:37 +0000 (01:16 +0300)
Summary:
This would have been marginally useful to me during/for rG7ea46aee3670981827c04df89b2c3a1cbdc7561b.

With ongoing migration to representing assumes via operand bundles on the assume, this will be gradually more useful.

Reviewers: nickdesaulniers, diegotf, dblaikie, george.burgess.iv, jdoerfert, Tyker

Reviewed By: nickdesaulniers

Subscribers: hiraditya, mgorny, llvm-commits

Tags: #llvm

Differential Revision: https://reviews.llvm.org/D83177

llvm/test/Reduce/remove-operand-bundles.ll [new file with mode: 0644]
llvm/tools/llvm-reduce/CMakeLists.txt
llvm/tools/llvm-reduce/DeltaManager.h
llvm/tools/llvm-reduce/deltas/ReduceOperandBundles.cpp [new file with mode: 0644]
llvm/tools/llvm-reduce/deltas/ReduceOperandBundles.h [new file with mode: 0644]
llvm/utils/gn/secondary/llvm/tools/llvm-reduce/BUILD.gn

diff --git a/llvm/test/Reduce/remove-operand-bundles.ll b/llvm/test/Reduce/remove-operand-bundles.ll
new file mode 100644 (file)
index 0000000..39c0af6
--- /dev/null
@@ -0,0 +1,41 @@
+; Test that llvm-reduce can remove uninteresting operand bundles from calls.
+;
+; RUN: rm -rf %t
+; RUN: llvm-reduce --test FileCheck --test-arg --check-prefixes=CHECK-ALL,CHECK-INTERESTINGNESS --test-arg %s --test-arg --input-file %s -o %t
+; RUN: cat %t | FileCheck --check-prefixes=CHECK-ALL,CHECK-FINAL %s
+
+; CHECK-ALL: declare void @f1()
+; CHECK-ALL: declare void @f2()
+; CHECK-ALL: declare void @f3()
+declare void @f1()
+declare void @f2()
+declare void @f3()
+
+; CHECK-FINAL-LABEL: define void @interesting(i32 %arg0, i32 %arg1, i32 %arg2) {
+; CHECK-FINAL-NEXT:  entry:
+; CHECK-FINAL-NEXT:    call void @f1() [ "bundle0"(), "align"(i32 %arg0), "whatever0"() ]
+; CHECK-FINAL-NEXT:    call void @f2()
+; CHECK-FINAL-NEXT:    call void @f3() [ "align"(i32 %arg2) ]
+; CHECK-FINAL-NEXT:    ret void
+; CHECK-FINAL-NEXT:  }
+define void @interesting(i32 %arg0, i32 %arg1, i32 %arg2) {
+entry:
+; CHECK-INTERESTINGNESS-LABEL: @interesting(
+
+; CHECK-INTERESTINGNESS: call void @f1()
+; CHECK-INTERESTINGNESS: "bundle0"()
+; CHECK-INTERESTINGNESS: "align"(i32 %arg0)
+; CHECK-INTERESTINGNESS: "whatever0"()
+
+; CHECK-INTERESTINGNESS: call void @f2()
+
+; CHECK-INTERESTINGNESS: call void @f3()
+; CHECK-INTERESTINGNESS: "align"(i32 %arg2)
+
+; CHECK-INTERESTINGNESS: ret
+
+  call void @f1() [ "bundle0"(),        "align"(i32 %arg0), "whatever0"() ]
+  call void @f2() [ "align"(i32 %arg1), "whatever1"(),      "bundle1"() ]
+  call void @f3() [ "whatever2"(),      "bundle2"(),        "align"(i32 %arg2) ]
+  ret void
+}
index 48de0ff..24eedac 100644 (file)
@@ -11,15 +11,16 @@ set(LLVM_LINK_COMPONENTS
   )
 
 add_llvm_tool(llvm-reduce
-  llvm-reduce.cpp
   TestRunner.cpp
   deltas/Delta.cpp
-  deltas/ReduceFunctions.cpp
-  deltas/ReduceGlobalVars.cpp
-  deltas/ReduceMetadata.cpp
   deltas/ReduceArguments.cpp
   deltas/ReduceBasicBlocks.cpp
+  deltas/ReduceFunctions.cpp
+  deltas/ReduceGlobalVars.cpp
   deltas/ReduceInstructions.cpp
+  deltas/ReduceMetadata.cpp
+  deltas/ReduceOperandBundles.cpp
+  llvm-reduce.cpp
 
   DEPENDS
   intrinsics_gen
index 2309c3a..5635352 100644 (file)
@@ -17,8 +17,9 @@
 #include "deltas/ReduceBasicBlocks.h"
 #include "deltas/ReduceFunctions.h"
 #include "deltas/ReduceGlobalVars.h"
-#include "deltas/ReduceMetadata.h"
 #include "deltas/ReduceInstructions.h"
+#include "deltas/ReduceMetadata.h"
+#include "deltas/ReduceOperandBundles.h"
 
 namespace llvm {
 
@@ -30,6 +31,7 @@ inline void runDeltaPasses(TestRunner &Tester) {
   reduceMetadataDeltaPass(Tester);
   reduceArgumentsDeltaPass(Tester);
   reduceInstructionsDeltaPass(Tester);
+  reduceOperandBundesDeltaPass(Tester);
   // TODO: Implement the remaining Delta Passes
 }
 
diff --git a/llvm/tools/llvm-reduce/deltas/ReduceOperandBundles.cpp b/llvm/tools/llvm-reduce/deltas/ReduceOperandBundles.cpp
new file mode 100644 (file)
index 0000000..c6de6e9
--- /dev/null
@@ -0,0 +1,161 @@
+//===- ReduceOperandBundes.cpp - Specialized Delta Pass -------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This file implements a function which calls the Generic Delta pass in order
+// to reduce uninteresting operand bundes from calls.
+//
+//===----------------------------------------------------------------------===//
+
+#include "ReduceOperandBundles.h"
+#include "Delta.h"
+#include "TestRunner.h"
+#include "llvm/ADT/ArrayRef.h"
+#include "llvm/ADT/DenseMap.h"
+#include "llvm/ADT/STLExtras.h"
+#include "llvm/ADT/ScopeExit.h"
+#include "llvm/ADT/Sequence.h"
+#include "llvm/ADT/iterator_range.h"
+#include "llvm/IR/InstVisitor.h"
+#include "llvm/IR/InstrTypes.h"
+#include "llvm/Support/raw_ostream.h"
+#include <algorithm>
+#include <iterator>
+#include <vector>
+
+namespace {
+class Module;
+} // namespace
+
+using namespace llvm;
+
+namespace {
+
+/// Provides opaque interface for querying into ChunksToKeep without having to
+/// actually understand what is going on.
+struct Oracle {
+  /// Out of all the features that we promised to be,
+  /// how many have we already processed? 1-based!
+  int Index = 1;
+
+  /// The actual workhorse, contains the knowledge whether or not
+  /// some particular feature should be preserved this time.
+  ArrayRef<Chunk> ChunksToKeep;
+
+public:
+  Oracle(ArrayRef<Chunk> ChunksToKeep_) : ChunksToKeep(ChunksToKeep_) {}
+
+  /// Should be called for each feature on which we are operating.
+  /// Name is self-explanatory - if returns true, then it should be preserved.
+  bool shouldKeep() {
+    if (ChunksToKeep.empty())
+      return false; // All further features are to be discarded.
+
+    // Does the current (front) chunk contain such a feature?
+    bool ShouldKeep = ChunksToKeep.front().contains(Index);
+    auto _ = make_scope_exit([&]() { ++Index; }); // Next time - next feature.
+
+    // Is this the last feature in the chunk?
+    if (ChunksToKeep.front().end == Index)
+      ChunksToKeep = ChunksToKeep.drop_front(); // Onto next chunk.
+
+    return ShouldKeep;
+  }
+};
+
+/// Given ChunksToKeep, produce a map of calls and indexes of operand bundles
+/// to be preserved for each call.
+class OperandBundleRemapper : public InstVisitor<OperandBundleRemapper> {
+  Oracle O;
+
+public:
+  DenseMap<CallBase *, std::vector<unsigned>> CallsToRefine;
+
+  explicit OperandBundleRemapper(ArrayRef<Chunk> ChunksToKeep)
+      : O(ChunksToKeep) {}
+
+  /// So far only CallBase sub-classes can have operand bundles.
+  /// Let's see which of the operand bundles of this call are to be kept.
+  void visitCallBase(CallBase &Call) {
+    if (!Call.hasOperandBundles())
+      return; // No bundles to begin with.
+
+    // Insert this call into map, we will likely want to rebuild it.
+    auto &OperandBundlesToKeepIndexes = CallsToRefine[&Call];
+    OperandBundlesToKeepIndexes.reserve(Call.getNumOperandBundles());
+
+    // Enumerate every operand bundle on this call.
+    for_each(seq(0U, Call.getNumOperandBundles()), [&](unsigned BundleIndex) {
+      if (O.shouldKeep()) // Should we keep this one?
+        OperandBundlesToKeepIndexes.emplace_back(BundleIndex);
+    });
+  }
+};
+
+struct OperandBundleCounter : public InstVisitor<OperandBundleCounter> {
+  /// How many features (in this case, operand bundles) did we count, total?
+  int OperandBundeCount = 0;
+
+  OperandBundleCounter() {}
+
+  /// So far only CallBase sub-classes can have operand bundles.
+  void visitCallBase(CallBase &Call) {
+    // Just accumulate the total number of operand bundles.
+    OperandBundeCount += Call.getNumOperandBundles();
+  }
+};
+
+} // namespace
+
+static void maybeRewriteCallWithDifferentBundles(
+    CallBase *OrigCall, ArrayRef<unsigned> OperandBundlesToKeepIndexes) {
+  if (OperandBundlesToKeepIndexes.size() == OrigCall->getNumOperandBundles())
+    return; // Not modifying operand bundles of this call after all.
+
+  std::vector<OperandBundleDef> NewBundles;
+  NewBundles.reserve(OperandBundlesToKeepIndexes.size());
+
+  // Actually copy over the bundles that we want to keep.
+  transform(OperandBundlesToKeepIndexes, std::back_inserter(NewBundles),
+            [OrigCall](unsigned Index) {
+              return OperandBundleDef(OrigCall->getOperandBundleAt(Index));
+            });
+
+  // Finally actually replace the bundles on the call.
+  CallBase *NewCall = CallBase::Create(OrigCall, NewBundles, OrigCall);
+  OrigCall->replaceAllUsesWith(NewCall);
+  OrigCall->eraseFromParent();
+}
+
+/// Removes out-of-chunk operand bundles from calls.
+static void extractOperandBundesFromModule(std::vector<Chunk> ChunksToKeep,
+                                           Module *Program) {
+  OperandBundleRemapper R(ChunksToKeep);
+  R.visit(Program);
+
+  for_each(R.CallsToRefine, [](const auto &P) {
+    return maybeRewriteCallWithDifferentBundles(P.first, P.second);
+  });
+}
+
+/// Counts the amount of operand bundles.
+static int countOperandBundes(Module *Program) {
+  OperandBundleCounter C;
+
+  // TODO: Silence index with --quiet flag
+  outs() << "----------------------------\n";
+  C.visit(Program);
+  outs() << "Number of operand bundles: " << C.OperandBundeCount << "\n";
+
+  return C.OperandBundeCount;
+}
+
+void llvm::reduceOperandBundesDeltaPass(TestRunner &Test) {
+  outs() << "*** Reducing OperandBundes...\n";
+  int OperandBundeCount = countOperandBundes(Test.getProgram());
+  runDeltaPass(Test, OperandBundeCount, extractOperandBundesFromModule);
+}
diff --git a/llvm/tools/llvm-reduce/deltas/ReduceOperandBundles.h b/llvm/tools/llvm-reduce/deltas/ReduceOperandBundles.h
new file mode 100644 (file)
index 0000000..382c5cb
--- /dev/null
@@ -0,0 +1,20 @@
+//===- ReduceOperandBundes.h - Specialized Delta Pass ---------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This file implements a function which calls the Generic Delta pass in order
+// to reduce uninteresting operand bundes from calls.
+//
+//===----------------------------------------------------------------------===//
+
+namespace llvm {
+
+class TestRunner;
+
+void reduceOperandBundesDeltaPass(TestRunner &Test);
+
+} // namespace llvm
index efa80c1..34e99f4 100644 (file)
@@ -17,6 +17,7 @@ executable("llvm-reduce") {
     "deltas/ReduceGlobalVars.cpp",
     "deltas/ReduceInstructions.cpp",
     "deltas/ReduceMetadata.cpp",
+    "deltas/ReduceOperandBundes.cpp",
     "llvm-reduce.cpp",
   ]
 }