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

ArkScript-lang / Ark / 20377988123

19 Dec 2025 05:45PM UTC coverage: 92.242% (+1.6%) from 90.661%
20377988123

push

github

SuperFola
chore: addressing cppcheck recommandations

1 of 1 new or added line in 1 file covered. (100.0%)

137 existing lines in 6 files now uncovered.

8430 of 9139 relevant lines covered (92.24%)

245122.08 hits per line

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

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

3
#include <cassert>
4
#include <utility>
5
#include <ranges>
6
#include <algorithm>
7

8
#include <Ark/Builtins/Builtins.hpp>
9

10
namespace Ark::internal
11
{
12
    IR::Entity fuseMathOps3(const std::span<const IR::Entity> e)
92✔
13
    {
92✔
14
        return IR::Entity(FUSED_MATH, e[0].inst(), e[1].inst(), e[2].inst());
92✔
15
    }
16

17
    IR::Entity fuseMathOps2(const std::span<const IR::Entity> e)
274✔
18
    {
274✔
19
        return IR::Entity(FUSED_MATH, e[0].inst(), e[1].inst(), NOP);
274✔
20
    }
21

22
    IROptimizer::IROptimizer(const unsigned debug) :
712✔
23
        m_logger("IROptimizer", debug)
356✔
24
    {
356✔
25
        m_ruleset = {
21,716✔
26
            Rule { { LOAD_CONST, LOAD_CONST }, LOAD_CONST_LOAD_CONST },
356✔
27
            Rule { { LOAD_CONST, STORE }, LOAD_CONST_STORE },
356✔
28
            Rule { { LOAD_CONST, SET_VAL }, LOAD_CONST_SET_VAL },
356✔
29
            Rule { { LOAD_SYMBOL, STORE }, STORE_FROM },
356✔
30
            Rule { { LOAD_SYMBOL_BY_INDEX, STORE }, STORE_FROM_INDEX },
356✔
31
            Rule { { LOAD_SYMBOL, SET_VAL }, SET_VAL_FROM },
356✔
32
            Rule { { LOAD_SYMBOL_BY_INDEX, SET_VAL }, SET_VAL_FROM_INDEX },
356✔
33
            Rule { { STORE, PUSH_RETURN_ADDRESS, LOAD_SYMBOL_BY_INDEX, BUILTIN, CALL },
356✔
34
                   [](const Entities entities, const std::size_t start_idx) {
965✔
35
                       return Builtins::builtins[entities[3].primaryArg()].second.isFunction() && start_idx == 0;
609✔
36
                   },
37
                   [](const Entities e) {
965✔
38
                       return IR::Entity(CALL_BUILTIN_WITHOUT_RETURN_ADDRESS, e[3].primaryArg(), 1);
609✔
39
                   } },
40
            Rule { { STORE, STORE, PUSH_RETURN_ADDRESS, LOAD_SYMBOL_BY_INDEX, LOAD_SYMBOL_BY_INDEX, BUILTIN, CALL },
356✔
41
                   [](const Entities entities, const std::size_t start_idx) {
439✔
42
                       return Builtins::builtins[entities[5].primaryArg()].second.isFunction() && start_idx == 0;
83✔
43
                   },
44
                   [](const Entities e) {
439✔
45
                       return IR::Entity(CALL_BUILTIN_WITHOUT_RETURN_ADDRESS, e[5].primaryArg(), 2);
83✔
46
                   } },
47
            Rule { { STORE, STORE, STORE, PUSH_RETURN_ADDRESS, LOAD_SYMBOL_BY_INDEX, LOAD_SYMBOL_BY_INDEX, LOAD_SYMBOL_BY_INDEX, BUILTIN, CALL },
356✔
48
                   [](const Entities entities, const std::size_t start_idx) {
408✔
49
                       return Builtins::builtins[entities[7].primaryArg()].second.isFunction() && start_idx == 0;
52✔
50
                   },
51
                   [](const Entities e) {
408✔
52
                       return IR::Entity(CALL_BUILTIN_WITHOUT_RETURN_ADDRESS, e[7].primaryArg(), 3);
52✔
53
                   } },
54
            Rule { { BUILTIN, CALL }, CALL_BUILTIN, [](const Entities entities, const std::size_t) {
844✔
55
                      return Builtins::builtins[entities[0].primaryArg()].second.isFunction();
488✔
56
                  } },
57
            Rule { { LOAD_SYMBOL, CALL }, CALL_SYMBOL },
356✔
58
            Rule { { GET_CURRENT_PAGE_ADDR, CALL }, CALL_CURRENT_PAGE },
356✔
59
            Rule { { LOAD_SYMBOL, GET_FIELD }, GET_FIELD_FROM_SYMBOL },
356✔
60
            Rule { { LOAD_SYMBOL_BY_INDEX, GET_FIELD }, GET_FIELD_FROM_SYMBOL_INDEX },
356✔
61
            Rule { { LIST, STORE }, STORE_LIST },
356✔
62
            Rule { { LOAD_SYMBOL, APPEND_IN_PLACE }, APPEND_IN_PLACE_SYM },
356✔
63
            Rule { { LOAD_SYMBOL_BY_INDEX, APPEND_IN_PLACE }, APPEND_IN_PLACE_SYM_INDEX },
356✔
64
            // LOAD_CONST, LOAD_SYMBOL a, MUL, SET_VAL / LOAD_SYMBOL a, LOAD_CONST, MUL, SET_VAL
65
            // ---> MUL_SET_VAL a value
66
            Rule { { LOAD_CONST, LOAD_SYMBOL, MUL, SET_VAL }, [this](const Entities e, const std::size_t) {
358✔
67
                      return isSmallerNumberInlinable(e[0].primaryArg()) && e[1].primaryArg() == e[3].primaryArg();
2✔
68
                  },
69
                   [this](const Entities e) {
358✔
70
                       return IR::Entity(MUL_SET_VAL, e[1].primaryArg(), smallerNumberAsArg(e[0].primaryArg()));
2✔
71
                   } },
72
            Rule { { LOAD_SYMBOL, LOAD_CONST, MUL, SET_VAL }, [this](const Entities e, const std::size_t) {
357✔
73
                      return isSmallerNumberInlinable(e[1].primaryArg()) && e[0].primaryArg() == e[3].primaryArg();
1✔
74
                  },
75
                   [this](const Entities e) {
357✔
76
                       return IR::Entity(MUL_SET_VAL, e[0].primaryArg(), smallerNumberAsArg(e[1].primaryArg()));
1✔
77
                   } },
78
            // LOAD_CONST, LOAD_SYMBOL a, MUL / LOAD_SYMBOL a, LOAD_CONST, MUL
79
            // ---> MUL_(BY|BY_INDEX) a value
80
            Rule { { LOAD_CONST, LOAD_SYMBOL, MUL }, [this](const Entities e, const std::size_t) {
358✔
81
                      return isSmallerNumberInlinable(e[0].primaryArg());
2✔
82
                  },
83
                   [this](const Entities e) {
358✔
84
                       return IR::Entity(MUL_BY, e[1].primaryArg(), smallerNumberAsArg(e[0].primaryArg()));
2✔
85
                   } },
86
            Rule { { LOAD_SYMBOL, LOAD_CONST, MUL }, [this](const Entities e, const std::size_t) {
358✔
87
                      return isSmallerNumberInlinable(e[1].primaryArg());
2✔
88
                  },
89
                   [this](const Entities e) {
358✔
90
                       return IR::Entity(MUL_BY, e[0].primaryArg(), smallerNumberAsArg(e[1].primaryArg()));
2✔
91
                   } },
92
            Rule { { LOAD_CONST, LOAD_SYMBOL_BY_INDEX, MUL }, [this](const Entities e, const std::size_t) {
436✔
93
                      return isSmallerNumberInlinable(e[0].primaryArg());
80✔
94
                  },
95
                   [this](const Entities e) {
436✔
96
                       return IR::Entity(MUL_BY_INDEX, e[1].primaryArg(), smallerNumberAsArg(e[0].primaryArg()));
80✔
97
                   } },
98
            Rule { { LOAD_SYMBOL_BY_INDEX, LOAD_CONST, MUL }, [this](const Entities e, const std::size_t) {
359✔
99
                      return isSmallerNumberInlinable(e[1].primaryArg());
3✔
100
                  },
101
                   [this](const Entities e) {
359✔
102
                       return IR::Entity(MUL_BY_INDEX, e[0].primaryArg(), smallerNumberAsArg(e[1].primaryArg()));
3✔
103
                   } },
104
            // (LOAD_SYMBOL a | LOAD_SYMBOL_BY_INDEX index), LOAD_CONST n (=1), (ADD | SUB), STORE
105
            // ---> INCREMENT_STORE / DECREMENT_STORE a value
106
            Rule { { LOAD_CONST, LOAD_SYMBOL, ADD, SET_VAL }, [this](const Entities e, const std::size_t) {
1,249✔
107
                      return isPositiveNumberInlinable(e[0].primaryArg()) && e[1].primaryArg() == e[3].primaryArg();
893✔
108
                  },
109
                   [this](const Entities e) {
1,248✔
110
                       return IR::Entity(INCREMENT_STORE, e[1].primaryArg(), numberAsArg(e[0].primaryArg()));
892✔
111
                   } },
112
            Rule { { LOAD_SYMBOL, LOAD_CONST, ADD, SET_VAL }, [this](const Entities e, const std::size_t) {
497✔
113
                      return isPositiveNumberInlinable(e[1].primaryArg()) && e[0].primaryArg() == e[3].primaryArg();
141✔
114
                  },
115
                   [this](const Entities e) {
484✔
116
                       return IR::Entity(INCREMENT_STORE, e[0].primaryArg(), numberAsArg(e[1].primaryArg()));
128✔
117
                   } },
118
            Rule { { LOAD_SYMBOL, LOAD_CONST, SUB, SET_VAL }, [this](const Entities e, const std::size_t) {
405✔
119
                      return isPositiveNumberInlinable(e[1].primaryArg()) && e[0].primaryArg() == e[3].primaryArg();
49✔
120
                  },
121
                   [this](const Entities e) {
405✔
122
                       return IR::Entity(DECREMENT_STORE, e[0].primaryArg(), numberAsArg(e[1].primaryArg()));
49✔
123
                   } },
124
            // without the final store, just increment/decrement
125
            Rule { { LOAD_CONST, LOAD_SYMBOL, ADD }, [this](const Entities e, const std::size_t) {
358✔
126
                      return isPositiveNumberInlinable(e[0].primaryArg());
2✔
127
                  },
128
                   [this](const Entities e) {
358✔
129
                       return IR::Entity(INCREMENT, e[1].primaryArg(), numberAsArg(e[0].primaryArg()));
2✔
130
                   } },
131
            Rule { { LOAD_SYMBOL, LOAD_CONST, ADD }, [this](const Entities e, const std::size_t) {
372✔
132
                      return isPositiveNumberInlinable(e[1].primaryArg());
16✔
133
                  },
134
                   [this](const Entities e) {
359✔
135
                       return IR::Entity(INCREMENT, e[0].primaryArg(), numberAsArg(e[1].primaryArg()));
3✔
136
                   } },
137
            Rule { { LOAD_SYMBOL, LOAD_CONST, SUB }, [this](const Entities e, const std::size_t) {
367✔
138
                      return isPositiveNumberInlinable(e[1].primaryArg());
11✔
139
                  },
140
                   [this](const Entities e) {
367✔
141
                       return IR::Entity(DECREMENT, e[0].primaryArg(), numberAsArg(e[1].primaryArg()));
11✔
142
                   } },
143
            Rule { { LOAD_CONST, LOAD_SYMBOL_BY_INDEX, ADD }, [this](const Entities e, const std::size_t) {
478✔
144
                      return isPositiveNumberInlinable(e[0].primaryArg());
122✔
145
                  },
146
                   [this](const Entities e) {
478✔
147
                       return IR::Entity(INCREMENT_BY_INDEX, e[1].primaryArg(), numberAsArg(e[0].primaryArg()));
122✔
148
                   } },
149
            Rule { { LOAD_SYMBOL_BY_INDEX, LOAD_CONST, ADD }, [this](const Entities e, const std::size_t) {
387✔
150
                      return isPositiveNumberInlinable(e[1].primaryArg());
31✔
151
                  },
152
                   [this](const Entities e) {
375✔
153
                       return IR::Entity(INCREMENT_BY_INDEX, e[0].primaryArg(), numberAsArg(e[1].primaryArg()));
19✔
154
                   } },
155
            Rule { { LOAD_SYMBOL_BY_INDEX, LOAD_CONST, SUB }, [this](const Entities e, const std::size_t) {
468✔
156
                      return isPositiveNumberInlinable(e[1].primaryArg());
112✔
157
                  },
158
                   [this](const Entities e) {
467✔
159
                       return IR::Entity(DECREMENT_BY_INDEX, e[0].primaryArg(), numberAsArg(e[1].primaryArg()));
111✔
160
                   } },
161
            // LOAD_SYMBOL list, (TAIL | HEAD), (STORE | SET_VAL a)
162
            // ---> STORE_TAIL list a ; STORE_HEAD ; SET_VAL_TAIL ; SET_VAL_HEAD
163
            Rule { { LOAD_SYMBOL, TAIL, STORE }, [](const Entities e) {
358✔
164
                      return IR::Entity(STORE_TAIL, e[0].primaryArg(), e[2].primaryArg());
2✔
165
                  } },
166
            Rule { { LOAD_SYMBOL, TAIL, SET_VAL }, [](const Entities e) {
361✔
167
                      return IR::Entity(SET_VAL_TAIL, e[0].primaryArg(), e[2].primaryArg());
5✔
168
                  } },
169
            Rule { { LOAD_SYMBOL, HEAD, STORE }, [](const Entities e) {
359✔
170
                      return IR::Entity(STORE_HEAD, e[0].primaryArg(), e[2].primaryArg());
3✔
171
                  } },
172
            Rule { { LOAD_SYMBOL, HEAD, SET_VAL }, [](const Entities e) {
358✔
173
                      return IR::Entity(SET_VAL_HEAD, e[0].primaryArg(), e[2].primaryArg());
2✔
174
                  } },
175
            Rule { { LOAD_SYMBOL_BY_INDEX, TAIL, STORE }, [](const Entities e) {
381✔
176
                      return IR::Entity(STORE_TAIL_BY_INDEX, e[0].primaryArg(), e[2].primaryArg());
25✔
177
                  } },
178
            Rule { { LOAD_SYMBOL_BY_INDEX, TAIL, SET_VAL }, [](const Entities e) {
358✔
179
                      return IR::Entity(SET_VAL_TAIL_BY_INDEX, e[0].primaryArg(), e[2].primaryArg());
2✔
180
                  } },
181
            Rule { { LOAD_SYMBOL_BY_INDEX, HEAD, STORE }, [](const Entities e) {
382✔
182
                      return IR::Entity(STORE_HEAD_BY_INDEX, e[0].primaryArg(), e[2].primaryArg());
26✔
183
                  } },
184
            Rule { { LOAD_SYMBOL_BY_INDEX, HEAD, SET_VAL }, [](const Entities e) {
358✔
185
                      return IR::Entity(SET_VAL_HEAD_BY_INDEX, e[0].primaryArg(), e[2].primaryArg());
2✔
186
                  } },
187
            // (LOAD_CONST id | LOAD_SYMBOL id), <comparison operator>, POP_JUMP_IF_(FALSE|TRUE)
188
            // ---> <OP>_(CONST|SYM)_JUMP_IF_(FALSE|TRUE)
189
            Rule { { LOAD_CONST, LT, POP_JUMP_IF_FALSE }, [](const Entities e) {
366✔
190
                      return IR::Entity::GotoWithArg(e[2], LT_CONST_JUMP_IF_FALSE, e[0].primaryArg());
10✔
191
                  } },
192
            Rule { { LOAD_CONST, LT, POP_JUMP_IF_TRUE }, [](const Entities e) {
436✔
193
                      return IR::Entity::GotoWithArg(e[2], LT_CONST_JUMP_IF_TRUE, e[0].primaryArg());
80✔
194
                  } },
195
            Rule { { LOAD_SYMBOL, LT, POP_JUMP_IF_FALSE }, [](const Entities e) {
667✔
196
                      return IR::Entity::GotoWithArg(e[2], LT_SYM_JUMP_IF_FALSE, e[0].primaryArg());
311✔
197
                  } },
198
            Rule { { LOAD_CONST, GT, POP_JUMP_IF_TRUE }, [](const Entities e) {
393✔
199
                      return IR::Entity::GotoWithArg(e[2], GT_CONST_JUMP_IF_TRUE, e[0].primaryArg());
37✔
200
                  } },
201
            Rule { { LOAD_CONST, GT, POP_JUMP_IF_FALSE }, [](const Entities e) {
398✔
202
                      return IR::Entity::GotoWithArg(e[2], GT_CONST_JUMP_IF_FALSE, e[0].primaryArg());
42✔
203
                  } },
204
            Rule { { LOAD_SYMBOL, GT, POP_JUMP_IF_FALSE }, [](const Entities e) {
358✔
205
                      return IR::Entity::GotoWithArg(e[2], GT_SYM_JUMP_IF_FALSE, e[0].primaryArg());
2✔
206
                  } },
207
            Rule { { LOAD_CONST, EQ, POP_JUMP_IF_TRUE }, [](const Entities e) {
435✔
208
                      return IR::Entity::GotoWithArg(e[2], EQ_CONST_JUMP_IF_TRUE, e[0].primaryArg());
79✔
209
                  } },
210
            Rule { { LOAD_SYMBOL_BY_INDEX, EQ, POP_JUMP_IF_TRUE }, [](const Entities e) {
560✔
211
                      return IR::Entity::GotoWithArg(e[2], EQ_SYM_INDEX_JUMP_IF_TRUE, e[0].primaryArg());
204✔
212
                  } },
213
            Rule { { LOAD_CONST, NEQ, POP_JUMP_IF_TRUE }, [](const Entities e) {
359✔
214
                      return IR::Entity::GotoWithArg(e[2], NEQ_CONST_JUMP_IF_TRUE, e[0].primaryArg());
3✔
215
                  } },
216
            Rule { { LOAD_SYMBOL, NEQ, POP_JUMP_IF_FALSE }, [](const Entities e) {
385✔
217
                      return IR::Entity::GotoWithArg(e[2], NEQ_SYM_JUMP_IF_FALSE, e[0].primaryArg());
29✔
218
                  } },
219
            // LOAD_SYMBOL id, LOAD_SYMBOL id2, AT
220
            // ---> AT_SYM_SYM id id2
221
            Rule { { LOAD_SYMBOL, LOAD_SYMBOL, AT }, AT_SYM_SYM },
356✔
222
            Rule { { LOAD_SYMBOL_BY_INDEX, LOAD_SYMBOL_BY_INDEX, AT }, AT_SYM_INDEX_SYM_INDEX },
356✔
223
            Rule { { LOAD_SYMBOL_BY_INDEX, LOAD_CONST, AT }, AT_SYM_INDEX_CONST },
356✔
224
            // LOAD_SYMBOL sym, TYPE, LOAD_CONST cst, EQ
225
            // ---> CHECK_TYPE_OF sym, cst
226
            // also works with LOAD_CONST cst, LOAD_SYMBOL sym, TYPE, EQ, but args will be flipped
227
            Rule { { LOAD_SYMBOL, TYPE, LOAD_CONST, EQ }, [](const Entities e) {
359✔
228
                      return IR::Entity(CHECK_TYPE_OF, e[0].primaryArg(), e[2].primaryArg());
3✔
229
                  } },
230
            Rule { { LOAD_CONST, LOAD_SYMBOL, TYPE, EQ }, [](const Entities e) {
357✔
231
                      return IR::Entity(CHECK_TYPE_OF, e[1].primaryArg(), e[0].primaryArg());
1✔
232
                  } },
233
            Rule { { LOAD_SYMBOL_BY_INDEX, TYPE, LOAD_CONST, EQ }, [](const Entities e) {
359✔
234
                      return IR::Entity(CHECK_TYPE_OF_BY_INDEX, e[0].primaryArg(), e[2].primaryArg());
3✔
235
                  } },
236
            Rule { { LOAD_CONST, LOAD_SYMBOL_BY_INDEX, TYPE, EQ }, [](const Entities e) {
410✔
237
                      return IR::Entity(CHECK_TYPE_OF_BY_INDEX, e[1].primaryArg(), e[0].primaryArg());
54✔
238
                  } },
239
            // ---
240
            Rule { { LOAD_SYMBOL_BY_INDEX, LEN, STORE }, [](const Entities e) {
567✔
241
                      return IR::Entity(STORE_LEN, e[0].primaryArg(), e[2].primaryArg());
211✔
242
                  } },
243
            Rule { { LOAD_SYMBOL, LEN, LT, POP_JUMP_IF_FALSE }, [](const Entities e) {
883✔
244
                      return IR::Entity::GotoWithArg(e[3], LT_LEN_SYM_JUMP_IF_FALSE, e[0].primaryArg());
527✔
245
                  } },
246
        };
247

248
        const auto math_ops = { ADD, SUB, MUL, DIV };
356✔
249
        for (const auto& one : math_ops)
1,780✔
250
        {
251
            for (const auto& two : math_ops)
7,120✔
252
            {
253
                for (const auto& three : math_ops)
28,480✔
254
                    m_ruleset.emplace_back(Rule { { one, two, three }, fuseMathOps3 });
22,784✔
255
            }
5,696✔
256
        }
1,424✔
257

258
        for (const auto& one : math_ops)
1,780✔
259
        {
260
            for (const auto& two : math_ops)
7,120✔
261
                m_ruleset.emplace_back(Rule { { one, two }, fuseMathOps2 });
5,696✔
262
        }
1,424✔
263

264
        m_logger.debug("Loaded {} rules", m_ruleset.size());
356✔
265
    }
356✔
266

267
    void IROptimizer::process(const std::vector<IR::Block>& pages, const std::vector<std::string>& symbols, const std::vector<ValTableElem>& values)
224✔
268
    {
224✔
269
        m_logger.traceStart("process");
224✔
270
        m_symbols = symbols;
224✔
271
        m_values = values;
224✔
272

273
        for (const auto& block : pages)
4,048✔
274
        {
275
            m_ir.emplace_back();
3,824✔
276
            IR::Block& current_block = m_ir.back();
3,824✔
277

278
            std::size_t i = 0;
3,824✔
279
            const std::size_t end = block.size();
3,824✔
280

281
            while (i < end)
101,764✔
282
            {
283
                std::optional<EntityWithOffset> maybe_compacted = replaceWithRules(
195,880✔
284
                    std::span(
97,940✔
285
                        block.begin() + static_cast<IR::Block::difference_type>(i),
97,940✔
286
                        block.size() - i),
97,940✔
287
                    i);
97,940✔
288

289
                if (maybe_compacted.has_value())
97,940✔
290
                {
291
                    auto [entity, offset] = maybe_compacted.value();
46,144✔
292
                    current_block.emplace_back(entity);
23,072✔
293
                    i += offset;
23,072✔
294
                }
23,072✔
295
                else
296
                {
297
                    current_block.emplace_back(block[i]);
74,868✔
298
                    ++i;
74,868✔
299
                }
300
            }
97,940✔
301
        }
3,824✔
302

303
        m_logger.traceEnd();
224✔
304
    }
224✔
305

306
    const std::vector<IR::Block>& IROptimizer::intermediateRepresentation() const noexcept
224✔
307
    {
224✔
308
        return m_ir;
224✔
309
    }
310

311
    bool IROptimizer::match(const std::vector<Instruction>& expected_insts, const std::span<const IR::Entity> entities) const
10,843,217✔
312
    {
10,843,217✔
313
        if (expected_insts.size() > entities.size())
10,843,217✔
314
            return false;
958,814✔
315

316
        for (std::size_t i = 0; i < expected_insts.size(); ++i)
20,298,439✔
317
        {
318
            if (expected_insts[i] != entities[i].inst())
10,414,036✔
319
                return false;
9,861,288✔
320
        }
552,748✔
321

322
        return true;
23,115✔
323
    }
10,843,217✔
324

325
    bool IROptimizer::canBeOptimizedSafely(std::span<const IR::Entity> entities, std::size_t window_size) const
23,072✔
326
    {
23,072✔
327
        // check that we can actually safely apply the optimization on the given instructions
328
        return std::ranges::none_of(
23,072✔
329
            entities | std::ranges::views::take(window_size),
23,072✔
330
            [](const IR::Entity& entity) {
54,783✔
331
                return entity.primaryArg() > IR::MaxValueForDualArg;
54,783✔
332
            });
333
    }
334

335
    std::optional<EntityWithOffset> IROptimizer::replaceWithRules(const std::span<const IR::Entity> entities, const std::size_t position_in_block)
97,940✔
336
    {
97,940✔
337
        for (const auto& [expected, condition, createReplacement] : m_ruleset)
11,010,416✔
338
        {
339
            if (match(expected, entities) && condition(entities, position_in_block))
10,843,217✔
340
            {
341
                const std::size_t window_size = expected.size();
46,144✔
342
                if (!canBeOptimizedSafely(entities, window_size))
23,072✔
UNCOV
343
                    return std::nullopt;  // no need to try other optimizations, they won't be applied either
×
344

345
                auto output = createReplacement(entities);
46,144✔
346

347
                if (const auto it = std::ranges::find_if(entities, [](const auto& entity) {
4,260,673✔
348
                        return entity.hasValidSourceLocation();
4,237,601✔
349
                    });
350
                    it != entities.end())
46,144✔
351
                    output.setSourceLocation(it->filename(), it->sourceLine());
23,072✔
352

353
                return EntityWithOffset { output, window_size };
23,072✔
354
            }
23,072✔
355
        }
10,843,217✔
356

357
        return std::nullopt;
74,868✔
358
    }
97,940✔
359

360
    bool IROptimizer::isPositiveNumberInlinable(const uint16_t id) const
1,377✔
361
    {
1,377✔
362
        if (std::cmp_less(id, m_values.size()) && m_values[id].type == ValTableElemType::Number)
1,377✔
363
        {
364
            const double val = std::get<double>(m_values[id].value);
1,341✔
365
            return val >= 0.0 &&
2,682✔
366
                val < IR::MaxValueForDualArg &&
1,341✔
367
                static_cast<double>(static_cast<long>(val)) == val;
1,340✔
368
        }
1,341✔
369
        return false;
36✔
370
    }
1,377✔
371

372
    bool IROptimizer::isSmallerNumberInlinable(const uint16_t id) const
90✔
373
    {
90✔
374
        if (std::cmp_less(id, m_values.size()) && m_values[id].type == ValTableElemType::Number)
90✔
375
        {
376
            const double val = std::get<double>(m_values[id].value) + IR::MaxValueForSmallNumber;
90✔
377
            return val >= 0.0 &&
180✔
378
                val < IR::MaxValueForDualArg &&
90✔
379
                static_cast<double>(static_cast<long>(val)) == val;
90✔
380
        }
90✔
UNCOV
381
        return false;
×
382
    }
90✔
383

UNCOV
384
    bool IROptimizer::isNumberEqualTo(const uint16_t id, const int number) const
×
UNCOV
385
    {
×
UNCOV
386
        if (std::cmp_less(id, m_values.size()) && m_values[id].type == ValTableElemType::Number)
×
387
        {
UNCOV
388
            const double val = std::get<double>(m_values[id].value);
×
UNCOV
389
            return static_cast<double>(static_cast<long>(val)) == val &&
×
UNCOV
390
                static_cast<int>(val) == number;
×
UNCOV
391
        }
×
UNCOV
392
        return false;
×
UNCOV
393
    }
×
394

395
    uint16_t IROptimizer::numberAsArg(const uint16_t id) const
1,337✔
396
    {
1,337✔
397
        return static_cast<uint16_t>(std::get<double>(m_values[id].value));
1,337✔
398
    }
399

400
    uint16_t IROptimizer::smallerNumberAsArg(const uint16_t id) const
90✔
401
    {
90✔
402
        return static_cast<uint16_t>(std::get<double>(m_values[id].value) + IR::MaxValueForSmallNumber);
90✔
403
    }
404
}
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