reference, declarationdefinition
definition → references, declarations, derived classes, virtual overrides
reference to multiple definitions → definitions
unreferenced
    1
    2
    3
    4
    5
    6
    7
    8
    9
   10
   11
   12
   13
   14
   15
   16
   17
   18
   19
   20
   21
   22
   23
   24
   25
   26
   27
   28
   29
   30
   31
   32
   33
   34
   35
   36
   37
   38
   39
   40
   41
   42
   43
   44
   45
   46
   47
   48
   49
   50
   51
   52
   53
   54
   55
   56
   57
   58
   59
   60
   61
   62
   63
   64
   65
   66
   67
   68
   69
   70
   71
   72
   73
   74
   75
   76
   77
   78
   79
   80
   81
   82
   83
   84
   85
   86
   87
   88
   89
   90
   91
   92
   93
   94
   95
   96
   97
   98
   99
  100
  101
  102
  103
  104
  105
  106
  107
  108
  109
  110
  111
  112
  113
  114
  115
  116
  117
  118
  119
  120
  121
  122
  123
  124
  125
  126
  127
  128
  129
  130
  131
  132
  133
  134
  135
  136
  137
  138
//===- ReduceMetadata.cpp - Specialized Delta Pass ------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
//
// This file implements two functions used by the Generic Delta Debugging
// Algorithm, which are used to reduce Metadata nodes.
//
//===----------------------------------------------------------------------===//

#include "ReduceMetadata.h"
#include "Delta.h"
#include "llvm/ADT/SmallVector.h"
#include <set>
#include <vector>

using namespace llvm;

/// Adds all Unnamed Metadata Nodes that are inside desired Chunks to set
template <class T>
static void getChunkMetadataNodes(T &MDUser, int &I,
                                  const std::vector<Chunk> &ChunksToKeep,
                                  std::set<MDNode *> &SeenNodes,
                                  std::set<MDNode *> &NodesToKeep) {
  SmallVector<std::pair<unsigned, MDNode *>, 4> MDs;
  MDUser.getAllMetadata(MDs);
  for (auto &MD : MDs) {
    SeenNodes.insert(MD.second);
    if (I < (int)ChunksToKeep.size()) {
      if (ChunksToKeep[I].contains(SeenNodes.size()))
        NodesToKeep.insert(MD.second);
      if (ChunksToKeep[I].end == (int)SeenNodes.size())
        ++I;
    }
  }
}

/// Erases out-of-chunk unnamed metadata nodes from its user
template <class T>
static void eraseMetadataIfOutsideChunk(T &MDUser,
                                        const std::set<MDNode *> &NodesToKeep) {
  SmallVector<std::pair<unsigned, MDNode *>, 4> MDs;
  MDUser.getAllMetadata(MDs);
  for (int I = 0, E = MDs.size(); I != E; ++I)
    if (!NodesToKeep.count(MDs[I].second))
      MDUser.setMetadata(I, NULL);
}

/// Removes all the Named and Unnamed Metadata Nodes, as well as any debug
/// functions that aren't inside the desired Chunks.
static void extractMetadataFromModule(const std::vector<Chunk> &ChunksToKeep,
                                      Module *Program) {
  std::set<MDNode *> SeenNodes;
  std::set<MDNode *> NodesToKeep;
  int I = 0;

  // Add chunk MDNodes used by GVs, Functions, and Instructions to set
  for (auto &GV : Program->globals())
    getChunkMetadataNodes(GV, I, ChunksToKeep, SeenNodes, NodesToKeep);

  for (auto &F : *Program) {
    getChunkMetadataNodes(F, I, ChunksToKeep, SeenNodes, NodesToKeep);
    for (auto &BB : F)
      for (auto &Inst : BB)
        getChunkMetadataNodes(Inst, I, ChunksToKeep, SeenNodes, NodesToKeep);
  }

  // Once more, go over metadata nodes, but deleting the ones outside chunks
  for (auto &GV : Program->globals())
    eraseMetadataIfOutsideChunk(GV, NodesToKeep);

  for (auto &F : *Program) {
    eraseMetadataIfOutsideChunk(F, NodesToKeep);
    for (auto &BB : F)
      for (auto &Inst : BB)
        eraseMetadataIfOutsideChunk(Inst, NodesToKeep);
  }


  // Get out-of-chunk Named metadata nodes
  unsigned MetadataCount = SeenNodes.size();
  std::vector<NamedMDNode *> NamedNodesToDelete;
  for (auto &MD : Program->named_metadata()) {
    if (I < (int)ChunksToKeep.size()) {
      if (!ChunksToKeep[I].contains(++MetadataCount))
        NamedNodesToDelete.push_back(&MD);
      if (ChunksToKeep[I].end == (int)SeenNodes.size())
        ++I;
    } else
      NamedNodesToDelete.push_back(&MD);
  }

  for (auto *NN : NamedNodesToDelete) {
    for (int I = 0, E = NN->getNumOperands(); I != E; ++I)
      NN->setOperand(I, NULL);
    NN->eraseFromParent();
  }
}

// Gets unnamed metadata nodes used by a given instruction/GV/function and adds
// them to the set of seen nodes
template <class T>
static void addMetadataToSet(T &MDUser, std::set<MDNode *> &UnnamedNodes) {
  SmallVector<std::pair<unsigned, MDNode *>, 4> MDs;
  MDUser.getAllMetadata(MDs);
  for (auto &MD : MDs)
    UnnamedNodes.insert(MD.second);
}

/// Returns the amount of Named and Unnamed Metadata Nodes
static int countMetadataTargets(Module *Program) {
  std::set<MDNode *> UnnamedNodes;
  int NamedMetadataNodes = Program->named_metadata_size();

  // Get metadata nodes used by globals
  for (auto &GV : Program->globals())
    addMetadataToSet(GV, UnnamedNodes);

  // Do the same for nodes used by functions & instructions
  for (auto &F : *Program) {
    addMetadataToSet(F, UnnamedNodes);
    for (auto &BB : F)
      for (auto &I : BB)
        addMetadataToSet(I, UnnamedNodes);
  }

  return UnnamedNodes.size() + NamedMetadataNodes;
}

void llvm::reduceMetadataDeltaPass(TestRunner &Test) {
  outs() << "*** Reducing Metadata...\n";
  int MDCount = countMetadataTargets(Test.getProgram());
  runDeltaPass(Test, MDCount, extractMetadataFromModule);
  outs() << "----------------------------\n";
}