Skip to content

Commit

Permalink
refactor(ir optimizer): shorter and more functional code when trying …
Browse files Browse the repository at this point in the history
…to compact instructions
  • Loading branch information
SuperFola committed Oct 14, 2024
1 parent 6bc5e0c commit 7c9f978
Show file tree
Hide file tree
Showing 3 changed files with 116 additions and 99 deletions.
3 changes: 3 additions & 0 deletions include/Ark/Compiler/IntermediateRepresentation/Entity.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,9 @@ namespace Ark::internal::IR

using label_t = std::size_t;

/// The maximum value an argument can have when an IR entity has two arguments
constexpr uint16_t MaxValueForDualArg = 0x0fff;

class Entity
{
public:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
* @file IROptimizer.hpp
* @author Alexandre Plateau ([email protected])
* @brief Optimize IR based on IR entity grouped by 2 (or more)
* @version 0.1
* @version 0.2
* @date 2024-10-11
*
* @copyright Copyright (c) 2024
Expand All @@ -16,6 +16,8 @@
#include <Ark/Compiler/ValTableElem.hpp>
#include <Ark/Compiler/IntermediateRepresentation/Entity.hpp>

#include <optional>

namespace Ark::internal
{
class ARK_API IROptimizer final
Expand Down Expand Up @@ -49,6 +51,11 @@ namespace Ark::internal
std::vector<IR::Block> m_ir;
std::vector<std::string> m_symbols;
std::vector<ValTableElem> m_values;

[[nodiscard]] std::optional<IR::Entity> compactEntities(const IR::Entity& first, const IR::Entity& second);
[[nodiscard]] std::optional<IR::Entity> compactEntities(const IR::Entity& first, const IR::Entity& second, const IR::Entity& third);

[[nodiscard]] bool isNumber(uint16_t id, double expected_number) const;
};
}

Expand Down
203 changes: 105 additions & 98 deletions src/arkreactor/Compiler/IntermediateRepresentation/IROptimizer.cpp
Original file line number Diff line number Diff line change
@@ -1,7 +1,15 @@
#include <Ark/Compiler/IntermediateRepresentation/IROptimizer.hpp>

#include <utility>

namespace Ark::internal
{
struct EntityWithOffset
{
IR::Entity entity;
std::size_t offset;
};

IROptimizer::IROptimizer(const unsigned debug) :
m_logger("IROptimizer", debug)
{}
Expand All @@ -11,6 +19,18 @@ namespace Ark::internal
m_symbols = symbols;
m_values = values;

auto map = []<typename T>(const std::optional<T>& opt, auto&& lambda) -> decltype(std::optional(lambda(opt.value()))) {
if (opt.has_value())
return lambda(opt.value());
return std::nullopt;
};

auto or_else = []<typename T>(const std::optional<T>& opt, auto&& lambda) -> std::optional<T> {
if (!opt.has_value())
return lambda();
return opt;
};

for (const auto& block : pages)
{
m_ir.emplace_back();
Expand All @@ -21,107 +41,30 @@ namespace Ark::internal

while (i < end)
{
const Instruction first = block[i].inst();
const uint16_t arg_1 = block[i].primaryArg();
std::optional<EntityWithOffset> maybe_compacted = std::nullopt;

if (i + 1 < end)
maybe_compacted = map(
compactEntities(block[i], block[i + 1]),
[](const auto& entity) {
return std::make_optional<EntityWithOffset>(entity, 2);
});
if (i + 2 < end)
maybe_compacted = or_else(
maybe_compacted,
[&, this]() {
return map(
compactEntities(block[i], block[i + 1], block[i + 2]),
[](const auto& entity) {
return std::make_optional<EntityWithOffset>(entity, 3);
});
});

if (maybe_compacted.has_value())
{
const Instruction second = block[i + 1].inst();
const uint16_t arg_2 = block[i + 1].primaryArg();

// LOAD_CONST x
// LOAD_CONST y
// ---> LOAD_CONST_LOAD_CONST x y
if (first == LOAD_CONST && second == LOAD_CONST)
{
current_block.emplace_back(LOAD_CONST_LOAD_CONST, arg_1, arg_2);
i += 2;
}
// LOAD_CONST x
// STORE / SET_VAL a
// ---> LOAD_CONST_STORE x a ; LOAD_CONST_SET_VAL x a
else if (first == LOAD_CONST && second == STORE)
{
current_block.emplace_back(LOAD_CONST_STORE, arg_1, arg_2);
i += 2;
}
else if (first == LOAD_CONST && second == SET_VAL)
{
current_block.emplace_back(LOAD_CONST_SET_VAL, arg_1, arg_2);
i += 2;
}
// LOAD_SYMBOL a
// STORE / SET_VAL b
// ---> STORE_FROM a b ; SET_VAL_FROM a b
else if (first == LOAD_SYMBOL && second == STORE)
{
current_block.emplace_back(STORE_FROM, arg_1, arg_2);
i += 2;
}
else if (first == LOAD_SYMBOL && second == SET_VAL)
{
current_block.emplace_back(SET_VAL_FROM, arg_1, arg_2);
i += 2;
}
else if (i + 2 < end)
{
const Instruction third = block[i + 2].inst();
const uint16_t arg_3 = block[i + 2].primaryArg();

// LOAD_SYMBOL a
// LOAD_CONST n (1)
// ADD / SUB
// ---> INCREMENT / DECREMENT a
if (third == ADD && first == LOAD_CONST && second == LOAD_SYMBOL && m_values[arg_1].type == ValTableElemType::Number && std::get<double>(m_values[arg_1].value) == 1)
{
current_block.emplace_back(INCREMENT, arg_2);
i += 3;
}
else if (third == ADD && first == LOAD_SYMBOL && second == LOAD_CONST && m_values[arg_2].type == ValTableElemType::Number && std::get<double>(m_values[arg_2].value) == 1)
{
current_block.emplace_back(INCREMENT, arg_1);
i += 3;
}
else if (third == SUB && first == LOAD_SYMBOL && second == LOAD_CONST && m_values[arg_2].type == ValTableElemType::Number && std::get<double>(m_values[arg_2].value) == 1)
{
current_block.emplace_back(DECREMENT, arg_1);
i += 3;
}
// LOAD_SYMBOL list
// TAIL / HEAD
// STORE / SET_VAL a
// ---> STORE_TAIL list a ; STORE_HEAD ; SET_VAL_TAIL ; SET_VAL_HEAD
else if (first == LOAD_SYMBOL && second == TAIL && third == STORE)
{
current_block.emplace_back(STORE_TAIL, arg_1, arg_3);
i += 3;
}
else if (first == LOAD_SYMBOL && second == TAIL && third == SET_VAL)
{
current_block.emplace_back(SET_VAL_TAIL, arg_1, arg_3);
i += 3;
}
else if (first == LOAD_SYMBOL && second == HEAD && third == STORE)
{
current_block.emplace_back(STORE_HEAD, arg_1, arg_3);
i += 3;
}
else if (first == LOAD_SYMBOL && second == HEAD && third == SET_VAL)
{
current_block.emplace_back(SET_VAL_HEAD, arg_1, arg_3);
i += 3;
}
else
{
current_block.emplace_back(block[i]);
++i;
}
}
else
{
current_block.emplace_back(block[i]);
++i;
}
auto [entity, offset] = maybe_compacted.value();
current_block.emplace_back(entity);
i += offset;
}
else
{
Expand All @@ -136,4 +79,68 @@ namespace Ark::internal
{
return m_ir;
}

std::optional<IR::Entity> IROptimizer::compactEntities(const IR::Entity& first, const IR::Entity& second)
{
if (first.primaryArg() > IR::MaxValueForDualArg || second.primaryArg() > IR::MaxValueForDualArg)
return std::nullopt;

// LOAD_CONST x
// LOAD_CONST y
// ---> LOAD_CONST_LOAD_CONST x y
if (first.inst() == LOAD_CONST && second.inst() == LOAD_CONST)
return IR::Entity(LOAD_CONST_LOAD_CONST, first.primaryArg(), second.primaryArg());
// LOAD_CONST x
// STORE / SET_VAL a
// ---> LOAD_CONST_STORE x a ; LOAD_CONST_SET_VAL x a
if (first.inst() == LOAD_CONST && second.inst() == STORE)
return IR::Entity(LOAD_CONST_STORE, first.primaryArg(), second.primaryArg());
if (first.inst() == LOAD_CONST && second.inst() == SET_VAL)
return IR::Entity(LOAD_CONST_SET_VAL, first.primaryArg(), second.primaryArg());
// LOAD_SYMBOL a
// STORE / SET_VAL b
// ---> STORE_FROM a b ; SET_VAL_FROM a b
if (first.inst() == LOAD_SYMBOL && second.inst() == STORE)
return IR::Entity(STORE_FROM, first.primaryArg(), second.primaryArg());
if (first.inst() == LOAD_SYMBOL && second.inst() == SET_VAL)
return IR::Entity(SET_VAL_FROM, first.primaryArg(), second.primaryArg());

return std::nullopt;
}

std::optional<IR::Entity> IROptimizer::compactEntities(const IR::Entity& first, const IR::Entity& second, const IR::Entity& third)
{
if (first.primaryArg() > IR::MaxValueForDualArg || second.primaryArg() > IR::MaxValueForDualArg || third.primaryArg() > IR::MaxValueForDualArg)
return std::nullopt;

// LOAD_SYMBOL a
// LOAD_CONST n (1)
// ADD / SUB
// ---> INCREMENT / DECREMENT a
if (third.inst() == ADD && first.inst() == LOAD_CONST && second.inst() == LOAD_SYMBOL && isNumber(first.primaryArg(), 1))
return IR::Entity(INCREMENT, second.primaryArg());
if (third.inst() == ADD && first.inst() == LOAD_SYMBOL && second.inst() == LOAD_CONST && isNumber(second.primaryArg(), 1))
return IR::Entity(INCREMENT, first.primaryArg());
if (third.inst() == SUB && first.inst() == LOAD_SYMBOL && second.inst() == LOAD_CONST && isNumber(second.primaryArg(), 1))
return IR::Entity(DECREMENT, first.primaryArg());
// LOAD_SYMBOL list
// TAIL / HEAD
// STORE / SET_VAL a
// ---> STORE_TAIL list a ; STORE_HEAD ; SET_VAL_TAIL ; SET_VAL_HEAD
if (first.inst() == LOAD_SYMBOL && second.inst() == TAIL && third.inst() == STORE)
return IR::Entity(STORE_TAIL, first.primaryArg(), third.primaryArg());
if (first.inst() == LOAD_SYMBOL && second.inst() == TAIL && third.inst() == SET_VAL)
return IR::Entity(SET_VAL_TAIL, first.primaryArg(), third.primaryArg());
if (first.inst() == LOAD_SYMBOL && second.inst() == HEAD && third.inst() == STORE)
return IR::Entity(STORE_HEAD, first.primaryArg(), third.primaryArg());
if (first.inst() == LOAD_SYMBOL && second.inst() == HEAD && third.inst() == SET_VAL)
return IR::Entity(SET_VAL_HEAD, first.primaryArg(), third.primaryArg());

return std::nullopt;
}

bool IROptimizer::isNumber(const uint16_t id, const double expected_number) const
{
return std::cmp_less(id, m_values.size()) && m_values[id].type == ValTableElemType::Number && std::get<double>(m_values[id].value) == expected_number;
}
}

0 comments on commit 7c9f978

Please sign in to comment.