1 //===- ReduceAttributes.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 attributes.
11 //
12 //===----------------------------------------------------------------------===//
13
14 #include "ReduceAttributes.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/SmallVector.h"
22 #include "llvm/ADT/iterator_range.h"
23 #include "llvm/IR/Attributes.h"
24 #include "llvm/IR/Function.h"
25 #include "llvm/IR/GlobalVariable.h"
26 #include "llvm/IR/InstVisitor.h"
27 #include "llvm/IR/InstrTypes.h"
28 #include "llvm/IR/Intrinsics.h"
29 #include "llvm/IR/Module.h"
30 #include "llvm/Support/raw_ostream.h"
31 #include <algorithm>
32 #include <cassert>
33 #include <iterator>
34 #include <utility>
35 #include <vector>
36
37 namespace llvm {
38 class LLVMContext;
39 } // namespace llvm
40
41 using namespace llvm;
42
43 namespace {
44
45 using AttrPtrVecTy = std::vector<const Attribute *>;
46 using AttrPtrIdxVecVecTy = std::pair<unsigned, AttrPtrVecTy>;
47 using AttrPtrVecVecTy = SmallVector<AttrPtrIdxVecVecTy, 3>;
48
49 /// Given ChunksToKeep, produce a map of global variables/functions/calls
50 /// and indexes of attributes to be preserved for each of them.
51 class AttributeRemapper : public InstVisitor<AttributeRemapper> {
52 Oracle O;
53
54 public:
55 DenseMap<GlobalVariable *, AttrPtrVecTy> GlobalVariablesToRefine;
56 DenseMap<Function *, AttrPtrVecVecTy> FunctionsToRefine;
57 DenseMap<CallBase *, AttrPtrVecVecTy> CallsToRefine;
58
AttributeRemapper(ArrayRef<Chunk> ChunksToKeep)59 explicit AttributeRemapper(ArrayRef<Chunk> ChunksToKeep) : O(ChunksToKeep) {}
60
visitModule(Module & M)61 void visitModule(Module &M) {
62 for (GlobalVariable &GV : M.getGlobalList())
63 visitGlobalVariable(GV);
64 }
65
visitGlobalVariable(GlobalVariable & GV)66 void visitGlobalVariable(GlobalVariable &GV) {
67 // Global variables only have one attribute set.
68 const AttributeSet &AS = GV.getAttributes();
69 if (AS.hasAttributes())
70 visitAttributeSet(AS, GlobalVariablesToRefine[&GV]);
71 }
72
visitFunction(Function & F)73 void visitFunction(Function &F) {
74 if (F.getIntrinsicID() != Intrinsic::not_intrinsic)
75 return; // We can neither add nor remove attributes from intrinsics.
76 visitAttributeList(F.getAttributes(), FunctionsToRefine[&F]);
77 }
78
visitCallBase(CallBase & I)79 void visitCallBase(CallBase &I) {
80 visitAttributeList(I.getAttributes(), CallsToRefine[&I]);
81 }
82
visitAttributeList(const AttributeList & AL,AttrPtrVecVecTy & AttributeSetsToPreserve)83 void visitAttributeList(const AttributeList &AL,
84 AttrPtrVecVecTy &AttributeSetsToPreserve) {
85 assert(AttributeSetsToPreserve.empty() && "Should not be sharing vectors.");
86 AttributeSetsToPreserve.reserve(AL.getNumAttrSets());
87 for (unsigned SetIdx : seq(AL.index_begin(), AL.index_end())) {
88 AttrPtrIdxVecVecTy AttributesToPreserve;
89 AttributesToPreserve.first = SetIdx;
90 visitAttributeSet(AL.getAttributes(AttributesToPreserve.first),
91 AttributesToPreserve.second);
92 if (!AttributesToPreserve.second.empty())
93 AttributeSetsToPreserve.emplace_back(std::move(AttributesToPreserve));
94 }
95 }
96
visitAttributeSet(const AttributeSet & AS,AttrPtrVecTy & AttrsToPreserve)97 void visitAttributeSet(const AttributeSet &AS,
98 AttrPtrVecTy &AttrsToPreserve) {
99 assert(AttrsToPreserve.empty() && "Should not be sharing vectors.");
100 AttrsToPreserve.reserve(AS.getNumAttributes());
101 for (const Attribute &A : AS)
102 if (O.shouldKeep())
103 AttrsToPreserve.emplace_back(&A);
104 }
105 };
106
107 struct AttributeCounter : public InstVisitor<AttributeCounter> {
108 /// How many features (in this case, attributes) did we count, total?
109 int AttributeCount = 0;
110
visitModule__anoncf437a340111::AttributeCounter111 void visitModule(Module &M) {
112 for (GlobalVariable &GV : M.getGlobalList())
113 visitGlobalVariable(GV);
114 }
115
visitGlobalVariable__anoncf437a340111::AttributeCounter116 void visitGlobalVariable(GlobalVariable &GV) {
117 // Global variables only have one attribute set.
118 visitAttributeSet(GV.getAttributes());
119 }
120
visitFunction__anoncf437a340111::AttributeCounter121 void visitFunction(Function &F) {
122 if (F.getIntrinsicID() != Intrinsic::not_intrinsic)
123 return; // We can neither add nor remove attributes from intrinsics.
124 visitAttributeList(F.getAttributes());
125 }
126
visitCallBase__anoncf437a340111::AttributeCounter127 void visitCallBase(CallBase &I) { visitAttributeList(I.getAttributes()); }
128
visitAttributeList__anoncf437a340111::AttributeCounter129 void visitAttributeList(const AttributeList &AL) {
130 for (const AttributeSet &AS : AL)
131 visitAttributeSet(AS);
132 }
133
visitAttributeSet__anoncf437a340111::AttributeCounter134 void visitAttributeSet(const AttributeSet &AS) {
135 AttributeCount += AS.getNumAttributes();
136 }
137 };
138
139 } // namespace
140
141 AttributeSet
convertAttributeRefToAttributeSet(LLVMContext & C,ArrayRef<const Attribute * > Attributes)142 convertAttributeRefToAttributeSet(LLVMContext &C,
143 ArrayRef<const Attribute *> Attributes) {
144 AttrBuilder B;
145 for (const Attribute *A : Attributes)
146 B.addAttribute(*A);
147 return AttributeSet::get(C, B);
148 }
149
convertAttributeRefVecToAttributeList(LLVMContext & C,ArrayRef<AttrPtrIdxVecVecTy> AttributeSets)150 AttributeList convertAttributeRefVecToAttributeList(
151 LLVMContext &C, ArrayRef<AttrPtrIdxVecVecTy> AttributeSets) {
152 std::vector<std::pair<unsigned, AttributeSet>> SetVec;
153 SetVec.reserve(AttributeSets.size());
154
155 transform(AttributeSets, std::back_inserter(SetVec),
156 [&C](const AttrPtrIdxVecVecTy &V) {
157 return std::make_pair(
158 V.first, convertAttributeRefToAttributeSet(C, V.second));
159 });
160
161 sort(SetVec, [](const std::pair<unsigned, AttributeSet> &LHS,
162 const std::pair<unsigned, AttributeSet> &RHS) {
163 return LHS.first < RHS.first; // All values are unique.
164 });
165
166 return AttributeList::get(C, SetVec);
167 }
168
169 /// Removes out-of-chunk attributes from module.
extractAttributesFromModule(std::vector<Chunk> ChunksToKeep,Module * Program)170 static void extractAttributesFromModule(std::vector<Chunk> ChunksToKeep,
171 Module *Program) {
172 AttributeRemapper R(ChunksToKeep);
173 R.visit(Program);
174
175 LLVMContext &C = Program->getContext();
176 for (const auto &I : R.GlobalVariablesToRefine)
177 I.first->setAttributes(convertAttributeRefToAttributeSet(C, I.second));
178 for (const auto &I : R.FunctionsToRefine)
179 I.first->setAttributes(convertAttributeRefVecToAttributeList(C, I.second));
180 for (const auto &I : R.CallsToRefine)
181 I.first->setAttributes(convertAttributeRefVecToAttributeList(C, I.second));
182 }
183
184 /// Counts the amount of attributes.
countAttributes(Module * Program)185 static int countAttributes(Module *Program) {
186 AttributeCounter C;
187
188 // TODO: Silence index with --quiet flag
189 outs() << "----------------------------\n";
190 C.visit(Program);
191 outs() << "Number of attributes: " << C.AttributeCount << "\n";
192
193 return C.AttributeCount;
194 }
195
reduceAttributesDeltaPass(TestRunner & Test)196 void llvm::reduceAttributesDeltaPass(TestRunner &Test) {
197 outs() << "*** Reducing Attributes...\n";
198 int AttributeCount = countAttributes(Test.getProgram());
199 runDeltaPass(Test, AttributeCount, extractAttributesFromModule);
200 }
201