1 //===- ReduceOperandBundes.cpp - Specialized Delta Pass -------------------===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8 //
9 // This file implements a function which calls the Generic Delta pass in order
10 // to reduce uninteresting operand bundes from calls.
11 //
12 //===----------------------------------------------------------------------===//
13 
14 #include "ReduceOperandBundles.h"
15 #include "Delta.h"
16 #include "TestRunner.h"
17 #include "llvm/ADT/ArrayRef.h"
18 #include "llvm/ADT/DenseMap.h"
19 #include "llvm/ADT/STLExtras.h"
20 #include "llvm/ADT/Sequence.h"
21 #include "llvm/ADT/iterator_range.h"
22 #include "llvm/IR/InstVisitor.h"
23 #include "llvm/IR/InstrTypes.h"
24 #include "llvm/Support/raw_ostream.h"
25 #include <algorithm>
26 #include <iterator>
27 #include <vector>
28 
29 namespace llvm {
30 class Module;
31 } // namespace llvm
32 
33 using namespace llvm;
34 
35 namespace {
36 
37 /// Given ChunksToKeep, produce a map of calls and indexes of operand bundles
38 /// to be preserved for each call.
39 class OperandBundleRemapper : public InstVisitor<OperandBundleRemapper> {
40   Oracle O;
41 
42 public:
43   DenseMap<CallBase *, std::vector<unsigned>> CallsToRefine;
44 
OperandBundleRemapper(ArrayRef<Chunk> ChunksToKeep)45   explicit OperandBundleRemapper(ArrayRef<Chunk> ChunksToKeep)
46       : O(ChunksToKeep) {}
47 
48   /// So far only CallBase sub-classes can have operand bundles.
49   /// Let's see which of the operand bundles of this call are to be kept.
visitCallBase(CallBase & Call)50   void visitCallBase(CallBase &Call) {
51     if (!Call.hasOperandBundles())
52       return; // No bundles to begin with.
53 
54     // Insert this call into map, we will likely want to rebuild it.
55     auto &OperandBundlesToKeepIndexes = CallsToRefine[&Call];
56     OperandBundlesToKeepIndexes.reserve(Call.getNumOperandBundles());
57 
58     // Enumerate every operand bundle on this call.
59     for (unsigned BundleIndex : seq(0U, Call.getNumOperandBundles()))
60       if (O.shouldKeep()) // Should we keep this one?
61         OperandBundlesToKeepIndexes.emplace_back(BundleIndex);
62   }
63 };
64 
65 struct OperandBundleCounter : public InstVisitor<OperandBundleCounter> {
66   /// How many features (in this case, operand bundles) did we count, total?
67   int OperandBundeCount = 0;
68 
69   /// So far only CallBase sub-classes can have operand bundles.
visitCallBase__anon8cc4d7cd0111::OperandBundleCounter70   void visitCallBase(CallBase &Call) {
71     // Just accumulate the total number of operand bundles.
72     OperandBundeCount += Call.getNumOperandBundles();
73   }
74 };
75 
76 } // namespace
77 
maybeRewriteCallWithDifferentBundles(CallBase * OrigCall,ArrayRef<unsigned> OperandBundlesToKeepIndexes)78 static void maybeRewriteCallWithDifferentBundles(
79     CallBase *OrigCall, ArrayRef<unsigned> OperandBundlesToKeepIndexes) {
80   if (OperandBundlesToKeepIndexes.size() == OrigCall->getNumOperandBundles())
81     return; // Not modifying operand bundles of this call after all.
82 
83   std::vector<OperandBundleDef> NewBundles;
84   NewBundles.reserve(OperandBundlesToKeepIndexes.size());
85 
86   // Actually copy over the bundles that we want to keep.
87   transform(OperandBundlesToKeepIndexes, std::back_inserter(NewBundles),
88             [OrigCall](unsigned Index) {
89               return OperandBundleDef(OrigCall->getOperandBundleAt(Index));
90             });
91 
92   // Finally actually replace the bundles on the call.
93   CallBase *NewCall = CallBase::Create(OrigCall, NewBundles, OrigCall);
94   OrigCall->replaceAllUsesWith(NewCall);
95   OrigCall->eraseFromParent();
96 }
97 
98 /// Removes out-of-chunk operand bundles from calls.
extractOperandBundesFromModule(std::vector<Chunk> ChunksToKeep,Module * Program)99 static void extractOperandBundesFromModule(std::vector<Chunk> ChunksToKeep,
100                                            Module *Program) {
101   OperandBundleRemapper R(ChunksToKeep);
102   R.visit(Program);
103 
104   for (const auto &I : R.CallsToRefine)
105     maybeRewriteCallWithDifferentBundles(I.first, I.second);
106 }
107 
108 /// Counts the amount of operand bundles.
countOperandBundes(Module * Program)109 static int countOperandBundes(Module *Program) {
110   OperandBundleCounter C;
111 
112   // TODO: Silence index with --quiet flag
113   outs() << "----------------------------\n";
114   C.visit(Program);
115   outs() << "Number of operand bundles: " << C.OperandBundeCount << "\n";
116 
117   return C.OperandBundeCount;
118 }
119 
reduceOperandBundesDeltaPass(TestRunner & Test)120 void llvm::reduceOperandBundesDeltaPass(TestRunner &Test) {
121   outs() << "*** Reducing OperandBundes...\n";
122   int OperandBundeCount = countOperandBundes(Test.getProgram());
123   runDeltaPass(Test, OperandBundeCount, extractOperandBundesFromModule);
124 }
125