analysis.cpp 4.8 KB
Newer Older
1
#include <memory>
2
#include <unordered_map>
3 4 5 6 7
#include <vector>
#include <unordered_set>

#include "gtest/gtest.h"

8 9
#include "analysis/function_analysis.h"
#include "analysis/scoping_analysis.h"
10
#include "codegen/osrentry.h"
11 12 13
#include "codegen/parser.h"
#include "core/ast.h"
#include "core/cfg.h"
14
#include "unittests.h"
15 16 17

using namespace pyston;

18 19
class AnalysisTest : public ::testing::Test {
protected:
20
    static void SetUpTestCase() {
21 22 23 24 25
        initCodegen();
    }
};

TEST_F(AnalysisTest, augassign) {
26
    const std::string fn("test/unittests/analysis_listcomp.py");
Travis Hance's avatar
Travis Hance committed
27
    AST_Module* module = caching_parse_file(fn.c_str());
28 29
    assert(module);

30
    ScopingAnalysis *scoping = new ScopingAnalysis(module, true);
31 32 33 34 35

    assert(module->body[0]->type == AST_TYPE::FunctionDef);
    AST_FunctionDef* func = static_cast<AST_FunctionDef*>(module->body[0]);

    ScopeInfo* scope_info = scoping->getScopeInfoForNode(func);
Travis Hance's avatar
exec  
Travis Hance committed
36 37
    ASSERT_FALSE(scope_info->getScopeTypeOfName(module->interned_strings->get("a")) == ScopeInfo::VarScopeType::GLOBAL);
    ASSERT_FALSE(scope_info->getScopeTypeOfName(module->interned_strings->get("b")) == ScopeInfo::VarScopeType::GLOBAL);
38

39
    SourceInfo* si = new SourceInfo(createModule("augassign", fn), scoping, func, func->body, fn);
40 41

    CFG* cfg = computeCFG(si, func->body);
42
    std::unique_ptr<LivenessAnalysis> liveness = computeLivenessInfo(cfg);
43 44 45 46 47 48

    //cfg->print();

    for (CFGBlock* block : cfg->blocks) {
        //printf("%d\n", block->idx);
        if (block->body.back()->type != AST_TYPE::Return)
49
            ASSERT_TRUE(liveness->isLiveAtEnd(module->interned_strings->get("a"), block));
50 51
    }

52
    std::unique_ptr<PhiAnalysis> phis = computeRequiredPhis(ParamNames(func), cfg, liveness.get(), scope_info);
53 54
}

55 56 57 58 59
void doOsrTest(bool is_osr, bool i_maybe_undefined) {
    const std::string fn("test/unittests/analysis_osr.py");
    AST_Module* module = caching_parse_file(fn.c_str());
    assert(module);

60
    ScopingAnalysis *scoping = new ScopingAnalysis(module, true);
61 62 63 64 65 66

    assert(module->body[0]->type == AST_TYPE::FunctionDef);
    AST_FunctionDef* func = static_cast<AST_FunctionDef*>(module->body[0]);

    ScopeInfo* scope_info = scoping->getScopeInfoForNode(func);
    SourceInfo* si = new SourceInfo(createModule("osr" + std::to_string((is_osr << 1) + i_maybe_undefined), fn),
67
            scoping, func, func->body, fn);
68 69

    CFG* cfg = computeCFG(si, func->body);
70
    std::unique_ptr<LivenessAnalysis> liveness = computeLivenessInfo(cfg);
71 72 73 74 75 76 77 78 79 80 81 82 83 84 85

    // cfg->print();

    InternedString i_str = module->interned_strings->get("i");
    InternedString idi_str = module->interned_strings->get("!is_defined_i");
    InternedString iter_str = module->interned_strings->get("#iter_3");

    CFGBlock* loop_backedge = cfg->blocks[5];
    ASSERT_EQ(6, loop_backedge->idx);
    ASSERT_EQ(1, loop_backedge->body.size());

    ASSERT_EQ(AST_TYPE::Jump, loop_backedge->body[0]->type);
    AST_Jump* backedge = ast_cast<AST_Jump>(loop_backedge->body[0]);
    ASSERT_LE(backedge->target->idx, loop_backedge->idx);

86
    std::unique_ptr<PhiAnalysis> phis;
87 88 89 90 91 92 93

    if (is_osr) {
        OSREntryDescriptor* entry_descriptor = OSREntryDescriptor::create(NULL, backedge);
        entry_descriptor->args[i_str] = NULL;
        if (i_maybe_undefined)
            entry_descriptor->args[idi_str] = NULL;
        entry_descriptor->args[iter_str] = NULL;
94
        phis = computeRequiredPhis(entry_descriptor, liveness.get(), scope_info);
95
    } else {
96
        phis = computeRequiredPhis(ParamNames(func), cfg, liveness.get(), scope_info);
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
    }

    // First, verify that we require phi nodes for the block we enter into.
    // This is somewhat tricky since the osr entry represents an extra entry
    // into the BB which the analysis might not otherwise track.

    auto required_phis = phis->getAllRequiredFor(backedge->target);
    EXPECT_EQ(1, required_phis.count(i_str));
    EXPECT_EQ(0, required_phis.count(idi_str));
    EXPECT_EQ(1, required_phis.count(iter_str));
    EXPECT_EQ(2, required_phis.size());

    EXPECT_EQ(!is_osr || i_maybe_undefined, phis->isPotentiallyUndefinedAt(i_str, backedge->target));
    EXPECT_FALSE(phis->isPotentiallyUndefinedAt(iter_str, backedge->target));
    EXPECT_EQ(!is_osr || i_maybe_undefined, phis->isPotentiallyUndefinedAfter(i_str, loop_backedge));
    EXPECT_FALSE(phis->isPotentiallyUndefinedAfter(iter_str, loop_backedge));

    // Now, let's verify that we don't need a phi after the loop

    CFGBlock* if_join = cfg->blocks[7];
    ASSERT_EQ(8, if_join->idx);
    ASSERT_EQ(2, if_join->predecessors.size());

    if (is_osr)
        EXPECT_EQ(0, phis->getAllRequiredFor(if_join).size());
    else
        EXPECT_EQ(1, phis->getAllRequiredFor(if_join).size());
}

TEST_F(AnalysisTest, osr_initial) {
    doOsrTest(false, false);
}
TEST_F(AnalysisTest, osr1) {
    doOsrTest(true, false);
}
TEST_F(AnalysisTest, osr2) {
    doOsrTest(true, true);
}