xref: /openbsd-src/gnu/llvm/llvm/tools/llvm-reduce/deltas/ReduceAttributes.cpp (revision d415bd752c734aee168c4ee86ff32e8cc249eb16)
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 /// Given ChunksToKeep, produce a map of global variables/functions/calls
46 /// and indexes of attributes to be preserved for each of them.
47 class AttributeRemapper : public InstVisitor<AttributeRemapper> {
48   Oracle &O;
49   LLVMContext &Context;
50 
51 public:
AttributeRemapper(Oracle & O,LLVMContext & C)52   AttributeRemapper(Oracle &O, LLVMContext &C) : O(O), Context(C) {}
53 
visitModule(Module & M)54   void visitModule(Module &M) {
55     for (GlobalVariable &GV : M.globals())
56       visitGlobalVariable(GV);
57   }
58 
visitGlobalVariable(GlobalVariable & GV)59   void visitGlobalVariable(GlobalVariable &GV) {
60     // Global variables only have one attribute set.
61     AttributeSet AS = GV.getAttributes();
62     if (AS.hasAttributes()) {
63       AttrBuilder AttrsToPreserve(Context);
64       visitAttributeSet(AS, AttrsToPreserve);
65       GV.setAttributes(AttributeSet::get(Context, AttrsToPreserve));
66     }
67   }
68 
visitFunction(Function & F)69   void visitFunction(Function &F) {
70     // We can neither add nor remove attributes from intrinsics.
71     if (F.getIntrinsicID() == Intrinsic::not_intrinsic)
72       F.setAttributes(visitAttributeList(F.getAttributes()));
73   }
74 
visitCallBase(CallBase & CB)75   void visitCallBase(CallBase &CB) {
76     CB.setAttributes(visitAttributeList(CB.getAttributes()));
77   }
78 
visitAttributeIndex(AttributeList AL,unsigned Index)79   AttributeSet visitAttributeIndex(AttributeList AL, unsigned Index) {
80     AttrBuilder AttributesToPreserve(Context);
81     visitAttributeSet(AL.getAttributes(Index), AttributesToPreserve);
82 
83     if (AttributesToPreserve.attrs().empty())
84       return {};
85     return AttributeSet::get(Context, AttributesToPreserve);
86   }
87 
visitAttributeList(AttributeList AL)88   AttributeList visitAttributeList(AttributeList AL) {
89     SmallVector<std::pair<unsigned, AttributeSet>> NewAttrList;
90     NewAttrList.reserve(AL.getNumAttrSets());
91 
92     for (unsigned SetIdx : AL.indexes()) {
93       if (SetIdx == AttributeList::FunctionIndex)
94         continue;
95 
96       AttributeSet AttrSet = visitAttributeIndex(AL, SetIdx);
97       if (AttrSet.hasAttributes())
98         NewAttrList.emplace_back(SetIdx, AttrSet);
99     }
100 
101     // FIXME: It's ridiculous that indexes() doesn't give us the correct order
102     // for contructing a new AttributeList. Special case the function index so
103     // we don't have to sort.
104     AttributeSet FnAttrSet =
105         visitAttributeIndex(AL, AttributeList::FunctionIndex);
106     if (FnAttrSet.hasAttributes())
107       NewAttrList.emplace_back(AttributeList::FunctionIndex, FnAttrSet);
108 
109     return AttributeList::get(Context, NewAttrList);
110   }
111 
visitAttributeSet(const AttributeSet & AS,AttrBuilder & AttrsToPreserve)112   void visitAttributeSet(const AttributeSet &AS, AttrBuilder &AttrsToPreserve) {
113     // Optnone requires noinline, so removing noinline requires removing the
114     // pair.
115     Attribute NoInline = AS.getAttribute(Attribute::NoInline);
116     bool RemoveNoInline = false;
117     if (NoInline.isValid()) {
118       RemoveNoInline = !O.shouldKeep();
119       if (!RemoveNoInline)
120         AttrsToPreserve.addAttribute(NoInline);
121     }
122 
123     for (Attribute A : AS) {
124       if (A.isEnumAttribute()) {
125         Attribute::AttrKind Kind = A.getKindAsEnum();
126         if (Kind == Attribute::NoInline)
127           continue;
128 
129         if (RemoveNoInline && Kind == Attribute::OptimizeNone)
130           continue;
131 
132         // TODO: Could only remove this if there are no constrained calls in the
133         // function.
134         if (Kind == Attribute::StrictFP) {
135           AttrsToPreserve.addAttribute(A);
136           continue;
137         }
138       }
139 
140       if (O.shouldKeep())
141         AttrsToPreserve.addAttribute(A);
142     }
143   }
144 };
145 
146 } // namespace
147 
148 /// Removes out-of-chunk attributes from module.
extractAttributesFromModule(Oracle & O,ReducerWorkItem & WorkItem)149 static void extractAttributesFromModule(Oracle &O, ReducerWorkItem &WorkItem) {
150   AttributeRemapper R(O, WorkItem.getContext());
151   R.visit(WorkItem.getModule());
152 }
153 
reduceAttributesDeltaPass(TestRunner & Test)154 void llvm::reduceAttributesDeltaPass(TestRunner &Test) {
155   runDeltaPass(Test, extractAttributesFromModule, "Reducing Attributes");
156 }
157