ed1ff8534f7c0de92aa159767b18bd04a1508c4f
[lldb.git] / mlir / tools / mlir-reduce / ReductionNode.cpp
1 //===- ReductionNode.cpp - Reduction Node Implementation -----------------===//
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 defines the reduction nodes which are used to track of the
10 // metadata for a specific generated variant within a reduction pass and are the
11 // building blocks of the reduction tree structure. A reduction tree is used to
12 // keep track of the different generated variants throughout a reduction pass in
13 // the MLIR Reduce tool.
14 //
15 //===----------------------------------------------------------------------===//
16
17 #include "mlir/Reducer/ReductionNode.h"
18
19 using namespace mlir;
20
21 /// Sets up the metadata and links the node to its parent.
22 ReductionNode::ReductionNode(ModuleOp module, ReductionNode *parent)
23     : module(module), evaluated(false) {
24
25   if (parent != nullptr)
26     parent->linkVariant(this);
27 }
28
29 /// Calculates and updates the size and interesting values of the module.
30 void ReductionNode::measureAndTest(const Tester *test) {
31   SmallString<128> filepath;
32   int fd;
33
34   // Print module to temprary file.
35   std::error_code ec =
36       llvm::sys::fs::createTemporaryFile("mlir-reduce", "mlir", fd, filepath);
37
38   if (ec)
39     llvm::report_fatal_error("Error making unique filename: " + ec.message());
40
41   llvm::ToolOutputFile out(filepath, fd);
42   module.print(out.os());
43   out.os().close();
44
45   if (out.os().has_error())
46     llvm::report_fatal_error("Error emitting bitcode to file '" + filepath);
47
48   size = out.os().tell();
49   interesting = test->isInteresting(filepath);
50   evaluated = true;
51 }
52
53 /// Returns true if the size and interestingness have been calculated.
54 bool ReductionNode::isEvaluated() const { return evaluated; }
55
56 /// Returns the size in bytes of the module.
57 int ReductionNode::getSize() const { return size; }
58
59 /// Returns true if the module exhibits the interesting behavior.
60 bool ReductionNode::isInteresting() const { return interesting; }
61
62 /// Returns the pointers to the child variants.
63 ReductionNode *ReductionNode::getVariant(unsigned long index) const {
64   if (index < variants.size())
65     return variants[index].get();
66
67   return nullptr;
68 }
69
70 /// Returns true if the child variants vector is empty.
71 bool ReductionNode::variantsEmpty() const { return variants.empty(); }
72
73 /// Link a child variant node.
74 void ReductionNode::linkVariant(ReductionNode *newVariant) {
75   std::unique_ptr<ReductionNode> ptrVariant(newVariant);
76   variants.push_back(std::move(ptrVariant));
77 }
78
79 /// Sort the child variants and remove the uninteresting ones.
80 void ReductionNode::organizeVariants(const Tester *test) {
81   // Ensure all variants are evaluated.
82   for (auto &var : variants)
83     if (!var->isEvaluated())
84       var->measureAndTest(test);
85
86   // Sort variants by interestingness and size.
87   llvm::array_pod_sort(
88       variants.begin(), variants.end(), [](const auto *lhs, const auto *rhs) {
89         if (lhs->get()->isInteresting() && !rhs->get()->isInteresting())
90           return 0;
91
92         if (!lhs->get()->isInteresting() && rhs->get()->isInteresting())
93           return 1;
94
95         return (lhs->get()->getSize(), rhs->get()->getSize());
96       });
97
98   int interestingCount = 0;
99   for (auto &var : variants) {
100     if (var->isInteresting()) {
101       ++interestingCount;
102     } else {
103       break;
104     }
105   }
106
107   // Remove uninteresting variants.
108   variants.resize(interestingCount);
109 }