1 //===- ReductionNode.cpp - Reduction Node Implementation -----------------===//
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
7 //===----------------------------------------------------------------------===//
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.
15 //===----------------------------------------------------------------------===//
17 #include "mlir/Reducer/ReductionNode.h"
21 /// Sets up the metadata and links the node to its parent.
22 ReductionNode::ReductionNode(ModuleOp module, ReductionNode *parent)
23 : module(module), evaluated(false) {
25 if (parent != nullptr)
26 parent->linkVariant(this);
29 /// Calculates and updates the size and interesting values of the module.
30 void ReductionNode::measureAndTest(const Tester *test) {
31 SmallString<128> filepath;
34 // Print module to temprary file.
36 llvm::sys::fs::createTemporaryFile("mlir-reduce", "mlir", fd, filepath);
39 llvm::report_fatal_error("Error making unique filename: " + ec.message());
41 llvm::ToolOutputFile out(filepath, fd);
42 module.print(out.os());
45 if (out.os().has_error())
46 llvm::report_fatal_error("Error emitting bitcode to file '" + filepath);
48 size = out.os().tell();
49 interesting = test->isInteresting(filepath);
53 /// Returns true if the size and interestingness have been calculated.
54 bool ReductionNode::isEvaluated() const { return evaluated; }
56 /// Returns the size in bytes of the module.
57 int ReductionNode::getSize() const { return size; }
59 /// Returns true if the module exhibits the interesting behavior.
60 bool ReductionNode::isInteresting() const { return interesting; }
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();
70 /// Returns true if the child variants vector is empty.
71 bool ReductionNode::variantsEmpty() const { return variants.empty(); }
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));
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);
86 // Sort variants by interestingness and size.
88 variants.begin(), variants.end(), [](const auto *lhs, const auto *rhs) {
89 if (lhs->get()->isInteresting() && !rhs->get()->isInteresting())
92 if (!lhs->get()->isInteresting() && rhs->get()->isInteresting())
95 return (lhs->get()->getSize(), rhs->get()->getSize());
98 int interestingCount = 0;
99 for (auto &var : variants) {
100 if (var->isInteresting()) {
107 // Remove uninteresting variants.
108 variants.resize(interestingCount);