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 : 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 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; 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(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. 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 196 void llvm::reduceAttributesDeltaPass(TestRunner &Test) { 197 outs() << "*** Reducing Attributes...\n"; 198 int AttributeCount = countAttributes(Test.getProgram()); 199 runDeltaPass(Test, AttributeCount, extractAttributesFromModule); 200 } 201