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(Oracle & O)59 explicit AttributeRemapper(Oracle &O) : O(O) {}
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 : AL.indexes()) {
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__anon28f14e740111::AttributeCounter111 void visitModule(Module &M) {
112 for (GlobalVariable &GV : M.getGlobalList())
113 visitGlobalVariable(GV);
114 }
115
visitGlobalVariable__anon28f14e740111::AttributeCounter116 void visitGlobalVariable(GlobalVariable &GV) {
117 // Global variables only have one attribute set.
118 visitAttributeSet(GV.getAttributes());
119 }
120
visitFunction__anon28f14e740111::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__anon28f14e740111::AttributeCounter127 void visitCallBase(CallBase &I) { visitAttributeList(I.getAttributes()); }
128
visitAttributeList__anon28f14e740111::AttributeCounter129 void visitAttributeList(const AttributeList &AL) {
130 for (const AttributeSet &AS : AL)
131 visitAttributeSet(AS);
132 }
133
visitAttributeSet__anon28f14e740111::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(C);
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 llvm::sort(SetVec, llvm::less_first()); // All values are unique.
162
163 return AttributeList::get(C, SetVec);
164 }
165
166 /// Removes out-of-chunk attributes from module.
extractAttributesFromModule(Oracle & O,Module & Program)167 static void extractAttributesFromModule(Oracle &O, Module &Program) {
168 AttributeRemapper R(O);
169 R.visit(Program);
170
171 LLVMContext &C = Program.getContext();
172 for (const auto &I : R.GlobalVariablesToRefine)
173 I.first->setAttributes(convertAttributeRefToAttributeSet(C, I.second));
174 for (const auto &I : R.FunctionsToRefine)
175 I.first->setAttributes(convertAttributeRefVecToAttributeList(C, I.second));
176 for (const auto &I : R.CallsToRefine)
177 I.first->setAttributes(convertAttributeRefVecToAttributeList(C, I.second));
178 }
179
reduceAttributesDeltaPass(TestRunner & Test)180 void llvm::reduceAttributesDeltaPass(TestRunner &Test) {
181 outs() << "*** Reducing Attributes...\n";
182 runDeltaPass(Test, extractAttributesFromModule);
183 }
184