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 
59   explicit AttributeRemapper(ArrayRef<Chunk> ChunksToKeep) : O(ChunksToKeep) {}
60 
61   void visitModule(Module &M) {
62     for (GlobalVariable &GV : M.getGlobalList())
63       visitGlobalVariable(GV);
64   }
65 
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 
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 
79   void visitCallBase(CallBase &I) {
80     visitAttributeList(I.getAttributes(), CallsToRefine[&I]);
81   }
82 
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.index_begin(), SetEndIdx = AL.index_end();
88          SetIdx != SetEndIdx; ++SetIdx) {
89       AttrPtrIdxVecVecTy AttributesToPreserve;
90       AttributesToPreserve.first = SetIdx;
91       visitAttributeSet(AL.getAttributes(AttributesToPreserve.first),
92                         AttributesToPreserve.second);
93       if (!AttributesToPreserve.second.empty())
94         AttributeSetsToPreserve.emplace_back(std::move(AttributesToPreserve));
95     }
96   }
97 
98   void visitAttributeSet(const AttributeSet &AS,
99                          AttrPtrVecTy &AttrsToPreserve) {
100     assert(AttrsToPreserve.empty() && "Should not be sharing vectors.");
101     AttrsToPreserve.reserve(AS.getNumAttributes());
102     for (const Attribute &A : AS)
103       if (O.shouldKeep())
104         AttrsToPreserve.emplace_back(&A);
105   }
106 };
107 
108 struct AttributeCounter : public InstVisitor<AttributeCounter> {
109   /// How many features (in this case, attributes) did we count, total?
110   int AttributeCount = 0;
111 
112   void visitModule(Module &M) {
113     for (GlobalVariable &GV : M.getGlobalList())
114       visitGlobalVariable(GV);
115   }
116 
117   void visitGlobalVariable(GlobalVariable &GV) {
118     // Global variables only have one attribute set.
119     visitAttributeSet(GV.getAttributes());
120   }
121 
122   void visitFunction(Function &F) {
123     if (F.getIntrinsicID() != Intrinsic::not_intrinsic)
124       return; // We can neither add nor remove attributes from intrinsics.
125     visitAttributeList(F.getAttributes());
126   }
127 
128   void visitCallBase(CallBase &I) { visitAttributeList(I.getAttributes()); }
129 
130   void visitAttributeList(const AttributeList &AL) {
131     for (const AttributeSet &AS : AL)
132       visitAttributeSet(AS);
133   }
134 
135   void visitAttributeSet(const AttributeSet &AS) {
136     AttributeCount += AS.getNumAttributes();
137   }
138 };
139 
140 } // namespace
141 
142 AttributeSet
143 convertAttributeRefToAttributeSet(LLVMContext &C,
144                                   ArrayRef<const Attribute *> Attributes) {
145   AttrBuilder B;
146   for (const Attribute *A : Attributes)
147     B.addAttribute(*A);
148   return AttributeSet::get(C, B);
149 }
150 
151 AttributeList convertAttributeRefVecToAttributeList(
152     LLVMContext &C, ArrayRef<AttrPtrIdxVecVecTy> AttributeSets) {
153   std::vector<std::pair<unsigned, AttributeSet>> SetVec;
154   SetVec.reserve(AttributeSets.size());
155 
156   transform(AttributeSets, std::back_inserter(SetVec),
157             [&C](const AttrPtrIdxVecVecTy &V) {
158               return std::make_pair(
159                   V.first, convertAttributeRefToAttributeSet(C, V.second));
160             });
161 
162   sort(SetVec, [](const std::pair<unsigned, AttributeSet> &LHS,
163                   const std::pair<unsigned, AttributeSet> &RHS) {
164     return LHS.first < RHS.first; // All values are unique.
165   });
166 
167   return AttributeList::get(C, SetVec);
168 }
169 
170 /// Removes out-of-chunk attributes from module.
171 static void extractAttributesFromModule(std::vector<Chunk> ChunksToKeep,
172                                         Module *Program) {
173   AttributeRemapper R(ChunksToKeep);
174   R.visit(Program);
175 
176   LLVMContext &C = Program->getContext();
177   for (const auto &I : R.GlobalVariablesToRefine)
178     I.first->setAttributes(convertAttributeRefToAttributeSet(C, I.second));
179   for (const auto &I : R.FunctionsToRefine)
180     I.first->setAttributes(convertAttributeRefVecToAttributeList(C, I.second));
181   for (const auto &I : R.CallsToRefine)
182     I.first->setAttributes(convertAttributeRefVecToAttributeList(C, I.second));
183 }
184 
185 /// Counts the amount of attributes.
186 static int countAttributes(Module *Program) {
187   AttributeCounter C;
188 
189   // TODO: Silence index with --quiet flag
190   outs() << "----------------------------\n";
191   C.visit(Program);
192   outs() << "Number of attributes: " << C.AttributeCount << "\n";
193 
194   return C.AttributeCount;
195 }
196 
197 void llvm::reduceAttributesDeltaPass(TestRunner &Test) {
198   outs() << "*** Reducing Attributes...\n";
199   int AttributeCount = countAttributes(Test.getProgram());
200   runDeltaPass(Test, AttributeCount, extractAttributesFromModule);
201 }
202