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