ReduceAttributes.cpp 4.8 KB

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