@@ -13,7 +13,88 @@ namespace Ark::internal
1313
1414 IROptimizer::IROptimizer (const unsigned debug) :
1515 m_logger (" IROptimizer" , debug)
16- {}
16+ {
17+ m_ruleset_two = {
18+ Rule {
19+ { LOAD_CONST, LOAD_CONST }, LOAD_CONST_LOAD_CONST },
20+ Rule {
21+ { LOAD_CONST, STORE }, LOAD_CONST_STORE },
22+ Rule {
23+ { LOAD_CONST, SET_VAL }, LOAD_CONST_SET_VAL },
24+ Rule {
25+ { LOAD_SYMBOL, STORE }, STORE_FROM },
26+ Rule {
27+ { LOAD_SYMBOL_BY_INDEX, STORE }, STORE_FROM_INDEX },
28+ Rule {
29+ { LOAD_SYMBOL, SET_VAL }, SET_VAL_FROM },
30+ Rule {
31+ { LOAD_SYMBOL_BY_INDEX, SET_VAL }, SET_VAL_FROM_INDEX },
32+ Rule {
33+ { BUILTIN, CALL }, CALL_BUILTIN, [](const Entities& entities) {
34+ return Builtins::builtins[entities[0 ].primaryArg ()].second .isFunction ();
35+ } }
36+ };
37+
38+ m_ruleset_three = {
39+ // LOAD_SYMBOL a / LOAD_SYMBOL_BY_INDEX index
40+ // LOAD_CONST n (1)
41+ // ADD / SUB
42+ // ---> INCREMENT / DECREMENT a value
43+ Rule {
44+ { LOAD_CONST, LOAD_SYMBOL, ADD }, INCREMENT, [this ](const Entities& e) {
45+ return isPositiveNumberInlinable (e[0 ].primaryArg ());
46+ },
47+ [this ](const Entities& e) {
48+ return std::make_pair (e[1 ].primaryArg (), numberAsArg (e[0 ].primaryArg ()));
49+ } },
50+ Rule { { LOAD_SYMBOL, LOAD_CONST, ADD }, INCREMENT, [this ](const Entities& e) {
51+ return isPositiveNumberInlinable (e[1 ].primaryArg ());
52+ },
53+ [this ](const Entities& e) {
54+ return std::make_pair (e[0 ].primaryArg (), numberAsArg (e[1 ].primaryArg ()));
55+ } },
56+ Rule { { LOAD_SYMBOL, LOAD_CONST, SUB }, DECREMENT, [this ](const Entities& e) {
57+ return isPositiveNumberInlinable (e[1 ].primaryArg ());
58+ },
59+ [this ](const Entities& e) {
60+ return std::make_pair (e[0 ].primaryArg (), numberAsArg (e[1 ].primaryArg ()));
61+ } },
62+ Rule { { LOAD_CONST, LOAD_SYMBOL_BY_INDEX, ADD }, INCREMENT_BY_INDEX, [this ](const Entities& e) {
63+ return isPositiveNumberInlinable (e[0 ].primaryArg ());
64+ },
65+ [this ](const Entities& e) {
66+ return std::make_pair (e[1 ].primaryArg (), numberAsArg (e[0 ].primaryArg ()));
67+ } },
68+ Rule { { LOAD_SYMBOL_BY_INDEX, LOAD_CONST, ADD }, INCREMENT_BY_INDEX, [this ](const Entities& e) {
69+ return isPositiveNumberInlinable (e[1 ].primaryArg ());
70+ },
71+ [this ](const Entities& e) {
72+ return std::make_pair (e[0 ].primaryArg (), numberAsArg (e[1 ].primaryArg ()));
73+ } },
74+ Rule { { LOAD_SYMBOL_BY_INDEX, LOAD_CONST, SUB }, DECREMENT_BY_INDEX, [this ](const Entities& e) {
75+ return isPositiveNumberInlinable (e[1 ].primaryArg ());
76+ },
77+ [this ](const Entities& e) {
78+ return std::make_pair (e[0 ].primaryArg (), numberAsArg (e[1 ].primaryArg ()));
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 { { LOAD_SYMBOL, TAIL, STORE }, STORE_TAIL, .createReplacement = [](const Entities& e) {
85+ return std::make_pair (e[0 ].primaryArg (), e[1 ].primaryArg ());
86+ } },
87+ Rule { { LOAD_SYMBOL, TAIL, SET_VAL }, SET_VAL_TAIL, .createReplacement = [](const Entities& e) {
88+ return std::make_pair (e[0 ].primaryArg (), e[1 ].primaryArg ());
89+ } },
90+ Rule { { LOAD_SYMBOL, HEAD, STORE }, STORE_HEAD, .createReplacement = [](const Entities& e) {
91+ return std::make_pair (e[0 ].primaryArg (), e[1 ].primaryArg ());
92+ } },
93+ Rule { { LOAD_SYMBOL, HEAD, SET_VAL }, SET_VAL_HEAD, .createReplacement = [](const Entities& e) {
94+ return std::make_pair (e[0 ].primaryArg (), e[1 ].primaryArg ());
95+ } }
96+ };
97+ }
1798
1899 void IROptimizer::process (const std::vector<IR::Block>& pages, const std::vector<std::string>& symbols, const std::vector<ValTableElem>& values)
19100 {
@@ -47,7 +128,7 @@ namespace Ark::internal
47128
48129 if (i + 1 < end)
49130 maybe_compacted = map (
50- compactEntities ( block[i], block[i + 1 ]),
131+ replaceWithRules (m_ruleset_two, { block[i], block[i + 1 ] } ),
51132 [](const auto & entity) {
52133 return std::make_optional<EntityWithOffset>(entity, 2 );
53134 });
@@ -56,7 +137,7 @@ namespace Ark::internal
56137 maybe_compacted,
57138 [&, this ]() {
58139 return map (
59- compactEntities ( block[i], block[i + 1 ], block[i + 2 ]),
140+ replaceWithRules (m_ruleset_three, { block[i], block[i + 1 ], block[i + 2 ] } ),
60141 [](const auto & entity) {
61142 return std::make_optional<EntityWithOffset>(entity, 3 );
62143 });
@@ -84,79 +165,35 @@ namespace Ark::internal
84165 return m_ir;
85166 }
86167
87- std::optional<IR::Entity> IROptimizer::compactEntities (const IR::Entity& first , const IR::Entity& second)
168+ bool IROptimizer::match (const std::vector<Instruction>& expected_insts , const Entities& entities) const
88169 {
89- if (first.primaryArg () > IR::MaxValueForDualArg || second.primaryArg () > IR::MaxValueForDualArg)
90- return std::nullopt ;
170+ assert (expected_insts.size () == entities.size () && " Mismatching size between expected instructions and given entities" );
91171
92- // LOAD_CONST x
93- // LOAD_CONST y
94- // ---> LOAD_CONST_LOAD_CONST x y
95- if (first.inst () == LOAD_CONST && second.inst () == LOAD_CONST)
96- return IR::Entity (LOAD_CONST_LOAD_CONST, first.primaryArg (), second.primaryArg ());
97- // LOAD_CONST x
98- // STORE / SET_VAL a
99- // ---> LOAD_CONST_STORE x a ; LOAD_CONST_SET_VAL x a
100- if (first.inst () == LOAD_CONST && second.inst () == STORE)
101- return IR::Entity (LOAD_CONST_STORE, first.primaryArg (), second.primaryArg ());
102- if (first.inst () == LOAD_CONST && second.inst () == SET_VAL)
103- return IR::Entity (LOAD_CONST_SET_VAL, first.primaryArg (), second.primaryArg ());
104- // LOAD_SYMBOL / LOAD_SYMBOL_BY_INDEX a
105- // STORE / SET_VAL b
106- // ---> STORE_FROM a b ; SET_VAL_FROM a b
107- if (first.inst () == LOAD_SYMBOL && second.inst () == STORE)
108- return IR::Entity (STORE_FROM, first.primaryArg (), second.primaryArg ());
109- if (first.inst () == LOAD_SYMBOL_BY_INDEX && second.inst () == STORE)
110- return IR::Entity (STORE_FROM_INDEX, first.primaryArg (), second.primaryArg ());
111- if (first.inst () == LOAD_SYMBOL && second.inst () == SET_VAL)
112- return IR::Entity (SET_VAL_FROM, first.primaryArg (), second.primaryArg ());
113- if (first.inst () == LOAD_SYMBOL_BY_INDEX && second.inst () == SET_VAL)
114- return IR::Entity (SET_VAL_FROM_INDEX, first.primaryArg (), second.primaryArg ());
115- // BUILTIN i
116- // CALL n
117- // ---> CALL_BUILTIN i n
118- if (first.inst () == BUILTIN && second.inst () == CALL && Builtins::builtins[first.primaryArg ()].second .isFunction ())
119- return IR::Entity (CALL_BUILTIN, first.primaryArg (), second.primaryArg ());
172+ for (std::size_t i = 0 ; i < expected_insts.size (); ++i)
173+ {
174+ if (expected_insts[i] != entities[i].inst ())
175+ return false ;
176+ }
120177
121- return std:: nullopt ;
178+ return true ;
122179 }
123180
124- std::optional<IR::Entity> IROptimizer::compactEntities (const IR::Entity& first , const IR::Entity& second, const IR::Entity& third )
181+ std::optional<IR::Entity> IROptimizer::replaceWithRules (const std::vector<Rule>& rules , const Entities& entities )
125182 {
126- if (first.primaryArg () > IR::MaxValueForDualArg || second.primaryArg () > IR::MaxValueForDualArg || third.primaryArg () > IR::MaxValueForDualArg)
127- return std::nullopt ;
183+ for (auto && entity : entities)
184+ {
185+ if (entity.primaryArg () > IR::MaxValueForDualArg)
186+ return std::nullopt ;
187+ }
128188
129- // LOAD_SYMBOL a
130- // LOAD_CONST n (1)
131- // ADD / SUB
132- // ---> INCREMENT / DECREMENT a value
133- if (third.inst () == ADD && first.inst () == LOAD_CONST && second.inst () == LOAD_SYMBOL && isPositiveNumberInlinable (first.primaryArg ()))
134- return IR::Entity (INCREMENT, second.primaryArg (), static_cast <uint16_t >(std::get<double >(m_values[first.primaryArg ()].value )));
135- if (third.inst () == ADD && first.inst () == LOAD_SYMBOL && second.inst () == LOAD_CONST && isPositiveNumberInlinable (second.primaryArg ()))
136- return IR::Entity (INCREMENT, first.primaryArg (), static_cast <uint16_t >(std::get<double >(m_values[second.primaryArg ()].value )));
137- if (third.inst () == SUB && first.inst () == LOAD_SYMBOL && second.inst () == LOAD_CONST && isPositiveNumberInlinable (second.primaryArg ()))
138- return IR::Entity (DECREMENT, first.primaryArg (), static_cast <uint16_t >(std::get<double >(m_values[second.primaryArg ()].value )));
139-
140- // todo: refactor
141- if (third.inst () == ADD && first.inst () == LOAD_CONST && second.inst () == LOAD_SYMBOL_BY_INDEX && isPositiveNumberInlinable (first.primaryArg ()))
142- return IR::Entity (INCREMENT_BY_INDEX, second.primaryArg (), static_cast <uint16_t >(std::get<double >(m_values[first.primaryArg ()].value )));
143- if (third.inst () == ADD && first.inst () == LOAD_SYMBOL_BY_INDEX && second.inst () == LOAD_CONST && isPositiveNumberInlinable (second.primaryArg ()))
144- return IR::Entity (INCREMENT_BY_INDEX, first.primaryArg (), static_cast <uint16_t >(std::get<double >(m_values[second.primaryArg ()].value )));
145- if (third.inst () == SUB && first.inst () == LOAD_SYMBOL_BY_INDEX && second.inst () == LOAD_CONST && isPositiveNumberInlinable (second.primaryArg ()))
146- return IR::Entity (DECREMENT_BY_INDEX, first.primaryArg (), static_cast <uint16_t >(std::get<double >(m_values[second.primaryArg ()].value )));
147-
148- // LOAD_SYMBOL list
149- // TAIL / HEAD
150- // STORE / SET_VAL a
151- // ---> STORE_TAIL list a ; STORE_HEAD ; SET_VAL_TAIL ; SET_VAL_HEAD
152- if (first.inst () == LOAD_SYMBOL && second.inst () == TAIL && third.inst () == STORE)
153- return IR::Entity (STORE_TAIL, first.primaryArg (), third.primaryArg ());
154- if (first.inst () == LOAD_SYMBOL && second.inst () == TAIL && third.inst () == SET_VAL)
155- return IR::Entity (SET_VAL_TAIL, first.primaryArg (), third.primaryArg ());
156- if (first.inst () == LOAD_SYMBOL && second.inst () == HEAD && third.inst () == STORE)
157- return IR::Entity (STORE_HEAD, first.primaryArg (), third.primaryArg ());
158- if (first.inst () == LOAD_SYMBOL && second.inst () == HEAD && third.inst () == SET_VAL)
159- return IR::Entity (SET_VAL_HEAD, first.primaryArg (), third.primaryArg ());
189+ for (const auto & [expected, replacement, condition, createReplacement] : rules)
190+ {
191+ if (match (expected, entities) && condition (entities))
192+ {
193+ auto [first, second] = createReplacement (entities);
194+ return IR::Entity (replacement, first, second);
195+ }
196+ }
160197
161198 return std::nullopt ;
162199 }
@@ -172,4 +209,9 @@ namespace Ark::internal
172209 }
173210 return false ;
174211 }
212+
213+ uint16_t IROptimizer::numberAsArg (const uint16_t id) const
214+ {
215+ return static_cast <uint16_t >(std::get<double >(m_values[id].value ));
216+ }
175217}
0 commit comments