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