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