• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

ArkScript-lang / Ark / 13997050351

21 Mar 2025 05:05PM UTC coverage: 78.902% (+0.05%) from 78.852%
13997050351

Pull #519

github

web-flow
Merge bb26978e1 into 4aa4303da
Pull Request #519: Feat/better locals

266 of 293 new or added lines in 10 files covered. (90.78%)

25 existing lines in 2 files now uncovered.

6021 of 7631 relevant lines covered (78.9%)

77817.42 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

98.67
/src/arkreactor/Compiler/IntermediateRepresentation/IROptimizer.cpp
1
#include <Ark/Compiler/IntermediateRepresentation/IROptimizer.hpp>
2

3
#include <utility>
4
#include <Ark/Builtins/Builtins.hpp>
5

6
namespace Ark::internal
7
{
8
    struct EntityWithOffset
9
    {
10
        IR::Entity entity;
11
        std::size_t offset;
12
    };
13

14
    IROptimizer::IROptimizer(const unsigned debug) :
394✔
15
        m_logger("IROptimizer", debug)
197✔
16
    {
197✔
17
        m_ruleset_two = {
1,773✔
18
            Rule {
197✔
19
                { LOAD_CONST, LOAD_CONST }, LOAD_CONST_LOAD_CONST },
197✔
20
            Rule {
394✔
21
                { LOAD_CONST, STORE }, LOAD_CONST_STORE },
197✔
22
            Rule {
394✔
23
                { LOAD_CONST, SET_VAL }, LOAD_CONST_SET_VAL },
197✔
24
            Rule {
394✔
25
                { LOAD_SYMBOL, STORE }, STORE_FROM },
197✔
26
            Rule {
394✔
27
                { LOAD_SYMBOL_BY_INDEX, STORE }, STORE_FROM_INDEX },
197✔
28
            Rule {
394✔
29
                { LOAD_SYMBOL, SET_VAL }, SET_VAL_FROM },
197✔
30
            Rule {
394✔
31
                { LOAD_SYMBOL_BY_INDEX, SET_VAL }, SET_VAL_FROM_INDEX },
197✔
32
            Rule {
394✔
33
                { BUILTIN, CALL }, CALL_BUILTIN, [](const Entities& entities) {
698✔
34
                    return Builtins::builtins[entities[0].primaryArg()].second.isFunction();
501✔
35
                } }
36
        };
37

38
        m_ruleset_three = {
2,955✔
39
            // LOAD_SYMBOL a / LOAD_SYMBOL_BY_INDEX index
40
            // LOAD_CONST n (1)
41
            // ADD / SUB
42
            // ---> INCREMENT / DECREMENT a value
43
            Rule {
197✔
44
                { LOAD_CONST, LOAD_SYMBOL, ADD }, INCREMENT, [this](const Entities& e) {
592✔
45
                    return isPositiveNumberInlinable(e[0].primaryArg());
395✔
46
                },
47
                [this](const Entities& e) {
592✔
48
                    return std::make_pair(e[1].primaryArg(), numberAsArg(e[0].primaryArg()));
395✔
49
                } },
50
            Rule { { LOAD_SYMBOL, LOAD_CONST, ADD }, INCREMENT, [this](const Entities& e) {
240✔
51
                      return isPositiveNumberInlinable(e[1].primaryArg());
43✔
52
                  },
53
                   [this](const Entities& e) {
240✔
54
                       return std::make_pair(e[0].primaryArg(), numberAsArg(e[1].primaryArg()));
43✔
55
                   } },
56
            Rule { { LOAD_SYMBOL, LOAD_CONST, SUB }, DECREMENT, [this](const Entities& e) {
212✔
57
                      return isPositiveNumberInlinable(e[1].primaryArg());
15✔
58
                  },
2,955✔
59
                   [this](const Entities& e) {
212✔
60
                       return std::make_pair(e[0].primaryArg(), numberAsArg(e[1].primaryArg()));
15✔
61
                   } },
62
            Rule { { LOAD_CONST, LOAD_SYMBOL_BY_INDEX, ADD }, INCREMENT_BY_INDEX, [this](const Entities& e) {
1,819✔
63
                      return isPositiveNumberInlinable(e[0].primaryArg());
46✔
64
                  },
65
                   [this](const Entities& e) {
243✔
66
                       return std::make_pair(e[1].primaryArg(), numberAsArg(e[0].primaryArg()));
46✔
67
                   } },
68
            Rule { { LOAD_SYMBOL_BY_INDEX, LOAD_CONST, ADD }, INCREMENT_BY_INDEX, [this](const Entities& e) {
215✔
69
                      return isPositiveNumberInlinable(e[1].primaryArg());
18✔
70
                  },
71
                   [this](const Entities& e) {
202✔
72
                       return std::make_pair(e[0].primaryArg(), numberAsArg(e[1].primaryArg()));
5✔
73
                   } },
74
            Rule { { LOAD_SYMBOL_BY_INDEX, LOAD_CONST, SUB }, DECREMENT_BY_INDEX, [this](const Entities& e) {
253✔
75
                      return isPositiveNumberInlinable(e[1].primaryArg());
56✔
76
                  },
77
                   [this](const Entities& e) {
252✔
78
                       return std::make_pair(e[0].primaryArg(), numberAsArg(e[1].primaryArg()));
55✔
79
                   } },
80
            // LOAD_SYMBOL list
81
            // TAIL / HEAD
82
            // STORE / SET_VAL a
83
            // ---> STORE_TAIL list a ; STORE_HEAD ; SET_VAL_TAIL ; SET_VAL_HEAD
84
            Rule { .expected = { LOAD_SYMBOL, TAIL, STORE }, .replacement = STORE_TAIL, .createReplacement = [](const Entities& e) {
198✔
85
                      return std::make_pair(e[0].primaryArg(), e[2].primaryArg());
1✔
86
                  } },
87
            Rule { .expected = { LOAD_SYMBOL, TAIL, SET_VAL }, .replacement = SET_VAL_TAIL, .createReplacement = [](const Entities& e) {
198✔
88
                      return std::make_pair(e[0].primaryArg(), e[2].primaryArg());
1✔
89
                  } },
90
            Rule { .expected = { LOAD_SYMBOL, HEAD, STORE }, .replacement = STORE_HEAD, .createReplacement = [](const Entities& e) {
198✔
91
                      return std::make_pair(e[0].primaryArg(), e[2].primaryArg());
1✔
92
                  } },
93
            Rule { .expected = { LOAD_SYMBOL, HEAD, SET_VAL }, .replacement = SET_VAL_HEAD, .createReplacement = [](const Entities& e) {
198✔
94
                      return std::make_pair(e[0].primaryArg(), e[2].primaryArg());
1✔
95
                  } },
96
            Rule { .expected = { LOAD_SYMBOL_BY_INDEX, TAIL, STORE }, .replacement = STORE_TAIL_BY_INDEX, .createReplacement = [](const Entities& e) {
199✔
97
                      return std::make_pair(e[0].primaryArg(), e[2].primaryArg());
2✔
98
                  } },
99
            Rule { .expected = { LOAD_SYMBOL_BY_INDEX, TAIL, SET_VAL }, .replacement = SET_VAL_TAIL_BY_INDEX, .createReplacement = [](const Entities& e) {
199✔
100
                      return std::make_pair(e[0].primaryArg(), e[2].primaryArg());
2✔
101
                  } },
102
            Rule { .expected = { LOAD_SYMBOL_BY_INDEX, HEAD, STORE }, .replacement = STORE_HEAD_BY_INDEX, .createReplacement = [](const Entities& e) {
200✔
103
                      return std::make_pair(e[0].primaryArg(), e[2].primaryArg());
3✔
104
                  } },
105
            Rule { .expected = { LOAD_SYMBOL_BY_INDEX, HEAD, SET_VAL }, .replacement = SET_VAL_HEAD_BY_INDEX, .createReplacement = [](const Entities& e) {
199✔
106
                      return std::make_pair(e[0].primaryArg(), e[2].primaryArg());
2✔
107
                  } }
108
        };
109
    }
197✔
110

111
    void IROptimizer::process(const std::vector<IR::Block>& pages, const std::vector<std::string>& symbols, const std::vector<ValTableElem>& values)
89✔
112
    {
89✔
113
        m_logger.traceStart("process");
89✔
114
        m_symbols = symbols;
89✔
115
        m_values = values;
89✔
116

117
        auto map = []<typename T>(const std::optional<T>& opt, auto&& lambda) -> decltype(std::optional(lambda(opt.value()))) {
69,476✔
118
            if (opt.has_value())
69,387✔
119
                return lambda(opt.value());
4,173✔
120
            return std::nullopt;
65,214✔
121
        };
69,387✔
122

123
        auto or_else = []<typename T>(const std::optional<T>& opt, auto&& lambda) -> std::optional<T> {
35,976✔
124
            if (!opt.has_value())
35,887✔
125
                return lambda();
32,313✔
126
            return opt;
3,574✔
127
        };
35,887✔
128

129
        for (const auto& block : pages)
1,397✔
130
        {
131
            m_ir.emplace_back();
1,308✔
132
            IR::Block& current_block = m_ir.back();
1,308✔
133

134
            std::size_t i = 0;
1,308✔
135
            const std::size_t end = block.size();
1,308✔
136

137
            while (i < end)
39,662✔
138
            {
139
                std::optional<EntityWithOffset> maybe_compacted = std::nullopt;
38,354✔
140

141
                if (i + 1 < end)
38,354✔
142
                    maybe_compacted = map(
74,148✔
143
                        replaceWithRules(m_ruleset_two, { block[i], block[i + 1] }),
37,074✔
144
                        [](const auto& entity) {
40,675✔
145
                            return std::make_optional<EntityWithOffset>(entity, 2);
3,601✔
146
                        });
147
                if (i + 2 < end)
38,354✔
148
                    maybe_compacted = or_else(
35,887✔
149
                        maybe_compacted,
150
                        [&, this]() {
68,200✔
151
                            return map(
64,626✔
152
                                replaceWithRules(m_ruleset_three, { block[i], block[i + 1], block[i + 2] }),
32,313✔
153
                                [](const auto& entity) {
32,885✔
154
                                    return std::make_optional<EntityWithOffset>(entity, 3);
572✔
155
                                });
UNCOV
156
                        });
×
157

158
                if (maybe_compacted.has_value())
38,354✔
159
                {
160
                    auto [entity, offset] = maybe_compacted.value();
4,173✔
161
                    current_block.emplace_back(entity);
4,173✔
162
                    i += offset;
4,173✔
163
                }
4,173✔
164
                else
165
                {
166
                    current_block.emplace_back(block[i]);
34,181✔
167
                    ++i;
34,181✔
168
                }
169
            }
38,354✔
170
        }
1,308✔
171

172
        m_logger.traceEnd();
89✔
173
    }
89✔
174

175
    const std::vector<IR::Block>& IROptimizer::intermediateRepresentation() const noexcept
89✔
176
    {
89✔
177
        return m_ir;
89✔
178
    }
179

180
    bool IROptimizer::match(const std::vector<Instruction>& expected_insts, const Entities& entities) const
722,402✔
181
    {
722,402✔
182
        assert(expected_insts.size() == entities.size() && "Mismatching size between expected instructions and given entities");
722,402✔
183

184
        for (std::size_t i = 0; i < expected_insts.size(); ++i)
1,534,363✔
185
        {
186
            if (expected_insts[i] != entities[i].inst())
811,961✔
187
                return false;
718,213✔
188
        }
93,748✔
189

190
        return true;
4,189✔
191
    }
722,402✔
192

193
    std::optional<IR::Entity> IROptimizer::replaceWithRules(const std::vector<Rule>& rules, const Entities& entities)
69,387✔
194
    {
69,387✔
195
        for (auto&& entity : entities)
240,474✔
196
        {
197
            if (entity.primaryArg() > IR::MaxValueForDualArg)
171,087✔
NEW
198
                return std::nullopt;
×
199
        }
171,087✔
200

201
        for (const auto& [expected, replacement, condition, createReplacement] : rules)
804,324✔
202
        {
203
            if (match(expected, entities) && condition(entities))
722,402✔
204
            {
205
                auto [first, second] = createReplacement(entities);
8,346✔
206
                return IR::Entity(replacement, first, second);
16,692✔
207
            }
4,173✔
208
        }
722,402✔
209

210
        return std::nullopt;
65,214✔
211
    }
69,387✔
212

213
    bool IROptimizer::isPositiveNumberInlinable(const uint16_t id) const
573✔
214
    {
573✔
215
        if (std::cmp_less(id, m_values.size()) && m_values[id].type == ValTableElemType::Number)
573✔
216
        {
217
            const double val = std::get<double>(m_values[id].value);
562✔
218
            return val >= 0.0 &&
1,124✔
219
                val < IR::MaxValueForDualArg &&
562✔
220
                static_cast<double>(static_cast<long>(val)) == val;
561✔
221
        }
562✔
222
        return false;
11✔
223
    }
573✔
224

225
    uint16_t IROptimizer::numberAsArg(const uint16_t id) const
559✔
226
    {
559✔
227
        return static_cast<uint16_t>(std::get<double>(m_values[id].value));
559✔
228
    }
229
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc