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(Oracle &O) : O(O) {}
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.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 
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 
111   void visitModule(Module &M) {
112     for (GlobalVariable &GV : M.getGlobalList())
113       visitGlobalVariable(GV);
114   }
115 
116   void visitGlobalVariable(GlobalVariable &GV) {
117     // Global variables only have one attribute set.
118     visitAttributeSet(GV.getAttributes());
119   }
120 
121   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 
127   void visitCallBase(CallBase &I) { visitAttributeList(I.getAttributes()); }
128 
129   void visitAttributeList(const AttributeList &AL) {
130     for (const AttributeSet &AS : AL)
131       visitAttributeSet(AS);
132   }
133 
134   void visitAttributeSet(const AttributeSet &AS) {
135     AttributeCount += AS.getNumAttributes();
136   }
137 };
138 
139 } // namespace
140 
141 AttributeSet
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 
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.
170 static void extractAttributesFromModule(Oracle &O, Module &Program) {
171   AttributeRemapper R(O);
172   R.visit(Program);
173 
174   LLVMContext &C = Program.getContext();
175   for (const auto &I : R.GlobalVariablesToRefine)
176     I.first->setAttributes(convertAttributeRefToAttributeSet(C, I.second));
177   for (const auto &I : R.FunctionsToRefine)
178     I.first->setAttributes(convertAttributeRefVecToAttributeList(C, I.second));
179   for (const auto &I : R.CallsToRefine)
180     I.first->setAttributes(convertAttributeRefVecToAttributeList(C, I.second));
181 }
182 
183 void llvm::reduceAttributesDeltaPass(TestRunner &Test) {
184   outs() << "*** Reducing Attributes...\n";
185   runDeltaPass(Test, extractAttributesFromModule);
186 }
187