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/IR/InstVisitor.h" 22 #include "llvm/IR/InstrTypes.h" 23 #include "llvm/Support/raw_ostream.h" 24 #include <algorithm> 25 #include <iterator> 26 #include <vector> 27 28 namespace llvm { 29 class Module; 30 } // namespace llvm 31 32 using namespace llvm; 33 34 namespace { 35 36 /// Given ChunksToKeep, produce a map of calls and indexes of operand bundles 37 /// to be preserved for each call. 38 class OperandBundleRemapper : public InstVisitor<OperandBundleRemapper> { 39 Oracle &O; 40 41 public: 42 DenseMap<CallBase *, std::vector<unsigned>> CallsToRefine; 43 44 explicit OperandBundleRemapper(Oracle &O) : O(O) {} 45 46 /// So far only CallBase sub-classes can have operand bundles. 47 /// Let's see which of the operand bundles of this call are to be kept. 48 void visitCallBase(CallBase &Call) { 49 if (!Call.hasOperandBundles()) 50 return; // No bundles to begin with. 51 52 // Insert this call into map, we will likely want to rebuild it. 53 auto &OperandBundlesToKeepIndexes = CallsToRefine[&Call]; 54 OperandBundlesToKeepIndexes.reserve(Call.getNumOperandBundles()); 55 56 // Enumerate every operand bundle on this call. 57 for (unsigned BundleIndex : seq(Call.getNumOperandBundles())) 58 if (O.shouldKeep()) // Should we keep this one? 59 OperandBundlesToKeepIndexes.emplace_back(BundleIndex); 60 } 61 }; 62 63 struct OperandBundleCounter : public InstVisitor<OperandBundleCounter> { 64 /// How many features (in this case, operand bundles) did we count, total? 65 int OperandBundeCount = 0; 66 67 /// So far only CallBase sub-classes can have operand bundles. 68 void visitCallBase(CallBase &Call) { 69 // Just accumulate the total number of operand bundles. 70 OperandBundeCount += Call.getNumOperandBundles(); 71 } 72 }; 73 74 } // namespace 75 76 static void maybeRewriteCallWithDifferentBundles( 77 CallBase *OrigCall, ArrayRef<unsigned> OperandBundlesToKeepIndexes) { 78 if (OperandBundlesToKeepIndexes.size() == OrigCall->getNumOperandBundles()) 79 return; // Not modifying operand bundles of this call after all. 80 81 std::vector<OperandBundleDef> NewBundles; 82 NewBundles.reserve(OperandBundlesToKeepIndexes.size()); 83 84 // Actually copy over the bundles that we want to keep. 85 transform(OperandBundlesToKeepIndexes, std::back_inserter(NewBundles), 86 [OrigCall](unsigned Index) { 87 return OperandBundleDef(OrigCall->getOperandBundleAt(Index)); 88 }); 89 90 // Finally actually replace the bundles on the call. 91 CallBase *NewCall = 92 CallBase::Create(OrigCall, NewBundles, OrigCall->getIterator()); 93 OrigCall->replaceAllUsesWith(NewCall); 94 OrigCall->eraseFromParent(); 95 } 96 97 /// Removes out-of-chunk operand bundles from calls. 98 static void extractOperandBundesFromModule(Oracle &O, 99 ReducerWorkItem &WorkItem) { 100 Module &Program = WorkItem.getModule(); 101 OperandBundleRemapper R(O); 102 R.visit(Program); 103 104 for (const auto &I : R.CallsToRefine) 105 maybeRewriteCallWithDifferentBundles(I.first, I.second); 106 } 107 108 void llvm::reduceOperandBundesDeltaPass(TestRunner &Test) { 109 runDeltaPass(Test, extractOperandBundesFromModule, 110 "Reducing Operand Bundles"); 111 } 112