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
28namespace llvm {
29class Module;
30} // namespace llvm
31
32using namespace llvm;
33
34namespace {
35
36/// Given ChunksToKeep, produce a map of calls and indexes of operand bundles
37/// to be preserved for each call.
38class OperandBundleRemapper : public InstVisitor<OperandBundleRemapper> {
39 Oracle &O;
40
41public:
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(n: Call.getNumOperandBundles());
55
56 // Enumerate every operand bundle on this call.
57 for (unsigned BundleIndex : seq(Size: Call.getNumOperandBundles()))
58 if (O.shouldKeep()) // Should we keep this one?
59 OperandBundlesToKeepIndexes.emplace_back(args&: BundleIndex);
60 }
61};
62
63struct 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
76static 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(n: OperandBundlesToKeepIndexes.size());
83
84 // Actually copy over the bundles that we want to keep.
85 transform(Range&: OperandBundlesToKeepIndexes, d_first: std::back_inserter(x&: NewBundles),
86 F: [OrigCall](unsigned Index) {
87 return OperandBundleDef(OrigCall->getOperandBundleAt(Index));
88 });
89
90 // Finally actually replace the bundles on the call.
91 CallBase *NewCall = CallBase::Create(CB: OrigCall, Bundles: NewBundles, InsertPt: OrigCall);
92 OrigCall->replaceAllUsesWith(V: NewCall);
93 OrigCall->eraseFromParent();
94}
95
96/// Removes out-of-chunk operand bundles from calls.
97static void extractOperandBundesFromModule(Oracle &O,
98 ReducerWorkItem &WorkItem) {
99 Module &Program = WorkItem.getModule();
100 OperandBundleRemapper R(O);
101 R.visit(M&: Program);
102
103 for (const auto &I : R.CallsToRefine)
104 maybeRewriteCallWithDifferentBundles(OrigCall: I.first, OperandBundlesToKeepIndexes: I.second);
105}
106
107void llvm::reduceOperandBundesDeltaPass(TestRunner &Test) {
108 runDeltaPass(Test, ExtractChunksFromModule: extractOperandBundesFromModule,
109 Message: "Reducing Operand Bundles");
110}
111