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