File: cse.cpp

package info (click to toggle)
halide 21.0.0-4
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 55,752 kB
  • sloc: cpp: 289,334; ansic: 22,751; python: 7,486; makefile: 4,299; sh: 2,508; java: 1,549; javascript: 282; pascal: 207; xml: 127; asm: 9
file content (98 lines) | stat: -rw-r--r-- 3,419 bytes parent folder | download | duplicates (2)
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
#include "Halide.h"

#include "fuzz_helpers.h"
#include <functional>
#include <fuzzer/FuzzedDataProvider.h>
#include <time.h>

using namespace Halide;
using namespace Halide::ConciseCasts;
using namespace Halide::Internal;
using std::pair;
using std::vector;

// Note that this deliberately uses int16 values everywhere --
// *not* int32 -- because we want to test CSE, not the simplifier's
// overflow behavior, and using int32 can end up with results
// containing signed_integer_overflow(), which is not helpful here.
Expr random_expr(FuzzedDataProvider &fdp, int depth, vector<pair<Expr, int>> &exprs) {
    if (depth <= 0) {
        return i16(fdp.ConsumeIntegralInRange<int>(-5, 4));
    }
    if (!exprs.empty() && fdp.ConsumeBool()) {
        // Reuse an existing expression that was generated under conditions at
        // least as strict as our current depth limit.
        auto p = pick_value_in_vector(fdp, exprs);
        if (p.second <= depth) {
            return p.first;
        }
    }
    std::function<Expr()> build_next_expr[] = {
        [&]() {
            // Can't use Var() here because that would require i32 values,
            // which we are avoiding here because we don't want to end
            // up with signed_integer_overflow()
            return Variable::make(Int(16), "x");
        },
        [&]() {
            return Variable::make(Int(16), "y");
        },
        [&]() {
            return Variable::make(Int(16), "z");
        },
        [&]() {
            Expr next = random_expr(fdp, depth - 1, exprs);
            next += random_expr(fdp, depth - 1, exprs);
            return next;
        },
        [&]() {
            Expr a = random_expr(fdp, depth - 2, exprs);
            Expr b = random_expr(fdp, depth - 2, exprs);
            Expr c = random_expr(fdp, depth - 2, exprs);
            Expr d = random_expr(fdp, depth - 2, exprs);
            return select(a > b, c, d);
        },
        [&]() {
            Expr a = random_expr(fdp, depth - 1, exprs);
            Expr b = random_expr(fdp, depth - 1, exprs);
            return i16(Let::make("x", a, b));
        },
        [&]() {
            Expr a = random_expr(fdp, depth - 1, exprs);
            Expr b = random_expr(fdp, depth - 1, exprs);
            return i16(Let::make("y", a, b));
        },
        [&]() {
            Expr a = random_expr(fdp, depth - 1, exprs);
            Expr b = random_expr(fdp, depth - 1, exprs);
            return i16(Let::make("z", a, b));
        },
        [&]() {
            return i16(fdp.ConsumeIntegralInRange<int>(-5, 4));
        },
    };
    Expr next = fdp.PickValueInArray(build_next_expr)();
    exprs.emplace_back(next, depth);
    return next;
}

extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
    FuzzedDataProvider fdp(data, size);
    vector<pair<Expr, int>> exprs;
    Expr orig = random_expr(fdp, 5, exprs);

    Expr csed = common_subexpression_elimination(orig);

    Expr check = (orig == csed);
    check = Let::make("x", i16(1), check);
    check = Let::make("y", i16(2), check);
    check = Let::make("z", i16(3), check);
    Stmt check_stmt = uniquify_variable_names(Evaluate::make(check));
    check = check_stmt.as<Evaluate>()->value;

    // Don't use can_prove, because it recursively calls cse, which just confuses matters.
    Expr result = simplify(check);
    assert(is_const_one(result));

    return 0;
}