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