dolphin/Source/Core/Common/Assembler/GekkoIRGen.cpp
Martino Fontana a14c88ba67 Remove unused imports
Yellow squiggly lines begone!
Done automatically on .cpp files through `run-clang-tidy`, with manual corrections to the mistakes.
If an import is directly used, but is technically unnecessary since it's recursively imported by something else, it is *not* removed.
The tool doesn't touch .h files, so I did some of them by hand while fixing errors due to old recursive imports.
Not everything is removed, but the cleanup should be substantial enough.
Because this done on Linux, code that isn't used on it is mostly untouched.
(Hopefully no open PR is depending on these imports...)
2026-01-25 16:12:15 +01:00

920 lines
23 KiB
C++

// Copyright 2023 Dolphin Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#include "Common/Assembler/GekkoIRGen.h"
#include <bit>
#include <functional>
#include <map>
#include <numeric>
#include <set>
#include <stack>
#include <variant>
#include <vector>
#include <fmt/format.h>
#include "Common/Assembler/AssemblerShared.h"
#include "Common/Assembler/GekkoParser.h"
#include "Common/Assert.h"
namespace Common::GekkoAssembler::detail
{
namespace
{
class GekkoIRPlugin : public ParsePlugin
{
public:
GekkoIRPlugin(GekkoIR& result, u32 base_addr)
: m_output_result(result), m_active_var(nullptr), m_operand_scan_begin(0)
{
m_active_block = &m_output_result.blocks.emplace_back(base_addr);
}
~GekkoIRPlugin() override = default;
void OnDirectivePre(GekkoDirective directive) override;
void OnDirectivePost(GekkoDirective directive) override;
void OnInstructionPre(const ParseInfo& mnemonic_info, bool extended) override;
void OnInstructionPost(const ParseInfo& mnemonic_info, bool extended) override;
void OnOperandPre() override;
void OnOperandPost() override;
void OnResolvedExprPost() override;
void OnOperator(AsmOp operation) override;
void OnTerminal(Terminal type, const AssemblerToken& val) override;
void OnHiaddr(std::string_view id) override;
void OnLoaddr(std::string_view id) override;
void OnCloseParen(ParenType type) override;
void OnLabelDecl(std::string_view name) override;
void OnNumericLabelDecl(std::string_view name, u32 num) override;
void OnVarDecl(std::string_view name) override;
void PostParseAction() override;
u32 CurrentAddress() const;
std::optional<u64> LookupVar(std::string_view lab);
std::optional<u32> LookupLabel(std::string_view lab);
template <typename T>
T& GetChunk();
template <typename T>
void AddBytes(T val);
void AddStringBytes(std::string_view str, bool null_term);
void PadAlign(u32 bits);
void PadSpace(size_t space);
void StartBlock(u32 address);
void StartBlockAlign(u32 bits);
void StartInstruction(size_t mnemonic_index, bool extended);
void FinishInstruction();
void SaveOperandFixup(size_t str_left, size_t str_right);
void AddBinaryEvaluator(u32 (*evaluator)(u32, u32));
void AddUnaryEvaluator(u32 (*evaluator)(u32));
void AddAbsoluteAddressConv();
void AddLiteral(u32 lit);
void AddSymbolResolve(std::string_view sym, bool absolute);
void AddNumLabelSymResolve(std::string_view sym, u32 num);
void RunFixups();
void EvalOperatorRel(AsmOp operation);
void EvalOperatorAbs(AsmOp operation);
void EvalTerminalRel(Terminal type, const AssemblerToken& tok);
void EvalTerminalAbs(Terminal type, const AssemblerToken& tok);
private:
enum class EvalMode
{
RelAddrDoublePass,
AbsAddrSinglePass,
};
GekkoIR& m_output_result;
IRBlock* m_active_block;
GekkoInstruction m_build_inst;
u64* m_active_var;
size_t m_operand_scan_begin;
// Ordered top-to-bottom, stores (label number, address)
std::vector<std::pair<u32, u32>> m_numlabs;
std::map<std::string, u32, std::less<>> m_labels;
std::map<std::string, u64, std::less<>> m_constants;
std::set<std::string> m_symset;
EvalMode m_evaluation_mode;
// For operand parsing
std::stack<std::function<u32()>> m_fixup_stack;
std::vector<std::function<u32()>> m_operand_fixups;
size_t m_operand_str_start;
// For directive parsing
std::vector<u64> m_eval_stack;
std::variant<std::vector<float>, std::vector<double>> m_floats_list;
std::string_view m_string_lit;
GekkoDirective m_active_directive;
};
///////////////
// OVERRIDES //
///////////////
void GekkoIRPlugin::OnDirectivePre(GekkoDirective directive)
{
m_evaluation_mode = EvalMode::AbsAddrSinglePass;
m_active_directive = directive;
m_eval_stack = std::vector<u64>{};
switch (directive)
{
case GekkoDirective::Float:
m_floats_list = std::vector<float>{};
break;
case GekkoDirective::Double:
m_floats_list = std::vector<double>{};
break;
default:
break;
}
}
void GekkoIRPlugin::OnDirectivePost(GekkoDirective directive)
{
switch (directive)
{
// .nbyte directives are handled by OnResolvedExprPost
default:
break;
case GekkoDirective::Float:
case GekkoDirective::Double:
std::visit(
[this](auto&& vec) {
for (auto&& val : vec)
{
AddBytes(val);
}
},
m_floats_list);
break;
case GekkoDirective::DefVar:
ASSERT(m_active_var != nullptr);
*m_active_var = m_eval_stack.back();
m_active_var = nullptr;
break;
case GekkoDirective::Locate:
StartBlock(static_cast<u32>(m_eval_stack.back()));
break;
case GekkoDirective::Zeros:
PadSpace(static_cast<u32>(m_eval_stack.back()));
break;
case GekkoDirective::Skip:
{
const u32 skip_len = static_cast<u32>(m_eval_stack.back());
if (skip_len > 0)
{
StartBlock(CurrentAddress() + skip_len);
}
break;
}
case GekkoDirective::PadAlign:
PadAlign(static_cast<u32>(m_eval_stack.back()));
break;
case GekkoDirective::Align:
StartBlockAlign(static_cast<u32>(m_eval_stack.back()));
break;
case GekkoDirective::Ascii:
AddStringBytes(m_string_lit, false);
break;
case GekkoDirective::Asciz:
AddStringBytes(m_string_lit, true);
break;
}
m_eval_stack = {};
}
void GekkoIRPlugin::OnInstructionPre(const ParseInfo& mnemonic_info, bool extended)
{
m_evaluation_mode = EvalMode::RelAddrDoublePass;
StartInstruction(mnemonic_info.mnemonic_index, extended);
}
void GekkoIRPlugin::OnInstructionPost(const ParseInfo&, bool)
{
FinishInstruction();
}
void GekkoIRPlugin::OnOperandPre()
{
m_operand_str_start = m_owner->lexer.ColNumber();
}
void GekkoIRPlugin::OnOperandPost()
{
SaveOperandFixup(m_operand_str_start, m_owner->lexer.ColNumber());
}
void GekkoIRPlugin::OnResolvedExprPost()
{
switch (m_active_directive)
{
case GekkoDirective::Byte:
AddBytes<u8>(static_cast<u8>(m_eval_stack.back()));
break;
case GekkoDirective::_2byte:
AddBytes<u16>(static_cast<u16>(m_eval_stack.back()));
break;
case GekkoDirective::_4byte:
AddBytes<u32>(static_cast<u32>(m_eval_stack.back()));
break;
case GekkoDirective::_8byte:
AddBytes<u64>(static_cast<u64>(m_eval_stack.back()));
break;
default:
return;
}
m_eval_stack.clear();
}
void GekkoIRPlugin::OnOperator(AsmOp operation)
{
if (m_evaluation_mode == EvalMode::RelAddrDoublePass)
{
EvalOperatorRel(operation);
}
else
{
EvalOperatorAbs(operation);
}
}
void GekkoIRPlugin::OnTerminal(Terminal type, const AssemblerToken& val)
{
if (type == Terminal::Str)
{
m_string_lit = val.token_val;
}
else if (m_evaluation_mode == EvalMode::RelAddrDoublePass)
{
EvalTerminalRel(type, val);
}
else
{
EvalTerminalAbs(type, val);
}
}
void GekkoIRPlugin::OnHiaddr(std::string_view id)
{
if (m_evaluation_mode == EvalMode::RelAddrDoublePass)
{
AddSymbolResolve(id, true);
AddLiteral(16);
AddBinaryEvaluator([](u32 lhs, u32 rhs) { return lhs >> rhs; });
AddLiteral(0xffff);
AddBinaryEvaluator([](u32 lhs, u32 rhs) { return lhs & rhs; });
}
else
{
u32 base;
if (auto lbl = LookupLabel(id); lbl)
{
base = *lbl;
}
else if (auto var = LookupVar(id); var)
{
base = *var;
}
else
{
m_owner->EmitErrorHere(fmt::format("Undefined reference to Label/Constant '{}'", id));
return;
}
m_eval_stack.push_back((base >> 16) & 0xffff);
}
}
void GekkoIRPlugin::OnLoaddr(std::string_view id)
{
if (m_evaluation_mode == EvalMode::RelAddrDoublePass)
{
AddSymbolResolve(id, true);
AddLiteral(0xffff);
AddBinaryEvaluator([](u32 lhs, u32 rhs) { return lhs & rhs; });
}
else
{
u32 base;
if (auto lbl = LookupLabel(id); lbl)
{
base = *lbl;
}
else if (auto var = LookupVar(id); var)
{
base = *var;
}
else
{
m_owner->EmitErrorHere(fmt::format("Undefined reference to Label/Constant '{}'", id));
return;
}
m_eval_stack.push_back(base & 0xffff);
}
}
void GekkoIRPlugin::OnCloseParen(ParenType type)
{
if (type != ParenType::RelConv)
{
return;
}
if (m_evaluation_mode == EvalMode::RelAddrDoublePass)
{
AddAbsoluteAddressConv();
}
else
{
m_eval_stack.push_back(CurrentAddress());
EvalOperatorAbs(AsmOp::Sub);
}
}
void GekkoIRPlugin::OnLabelDecl(std::string_view name)
{
const std::string name_str(name);
if (const bool inserted = m_symset.insert(name_str).second; !inserted)
{
m_owner->EmitErrorHere(fmt::format("Label/Constant {} is already defined", name));
return;
}
m_labels[name_str] = m_active_block->BlockEndAddress();
}
void GekkoIRPlugin::OnNumericLabelDecl(std::string_view, u32 num)
{
m_numlabs.emplace_back(num, m_active_block->BlockEndAddress());
}
void GekkoIRPlugin::OnVarDecl(std::string_view name)
{
const std::string name_str(name);
if (const bool inserted = m_symset.insert(name_str).second; !inserted)
{
m_owner->EmitErrorHere(fmt::format("Label/Constant {} is already defined", name));
return;
}
m_active_var = &m_constants[name_str];
}
void GekkoIRPlugin::PostParseAction()
{
RunFixups();
}
//////////////////////
// HELPER FUNCTIONS //
//////////////////////
u32 GekkoIRPlugin::CurrentAddress() const
{
return m_active_block->BlockEndAddress();
}
std::optional<u64> GekkoIRPlugin::LookupVar(std::string_view var)
{
auto var_it = m_constants.find(var);
return var_it == m_constants.end() ? std::nullopt : std::optional(var_it->second);
}
std::optional<u32> GekkoIRPlugin::LookupLabel(std::string_view lab)
{
auto label_it = m_labels.find(lab);
return label_it == m_labels.end() ? std::nullopt : std::optional(label_it->second);
}
void GekkoIRPlugin::AddStringBytes(std::string_view str, bool null_term)
{
ByteChunk& bytes = GetChunk<ByteChunk>();
ConvertStringLiteral(str, &bytes);
if (null_term)
{
bytes.push_back('\0');
}
}
template <typename T>
T& GekkoIRPlugin::GetChunk()
{
if (!m_active_block->chunks.empty() && std::holds_alternative<T>(m_active_block->chunks.back()))
{
return std::get<T>(m_active_block->chunks.back());
}
return std::get<T>(m_active_block->chunks.emplace_back(T{}));
}
template <typename T>
void GekkoIRPlugin::AddBytes(T val)
{
if constexpr (std::is_integral_v<T>)
{
ByteChunk& bytes = GetChunk<ByteChunk>();
for (size_t i = sizeof(T) - 1; i > 0; i--)
{
bytes.push_back((val >> (8 * i)) & 0xff);
}
bytes.push_back(val & 0xff);
}
else if constexpr (std::is_same_v<T, float>)
{
static_assert(sizeof(double) == sizeof(u64));
AddBytes(std::bit_cast<u32>(val));
}
else
{
// std::is_same_v<T, double>
static_assert(sizeof(double) == sizeof(u64));
AddBytes(std::bit_cast<u64>(val));
}
}
void GekkoIRPlugin::PadAlign(u32 bits)
{
const u32 align_mask = (1 << bits) - 1;
const u32 current_addr = m_active_block->BlockEndAddress();
if (current_addr & align_mask)
{
PadChunk& current_pad = GetChunk<PadChunk>();
current_pad += (1 << bits) - (current_addr & align_mask);
}
}
void GekkoIRPlugin::PadSpace(size_t space)
{
GetChunk<PadChunk>() += space;
}
void GekkoIRPlugin::StartBlock(u32 address)
{
m_active_block = &m_output_result.blocks.emplace_back(address);
}
void GekkoIRPlugin::StartBlockAlign(u32 bits)
{
const u32 align_mask = (1 << bits) - 1;
const u32 current_addr = m_active_block->BlockEndAddress();
if (current_addr & align_mask)
{
StartBlock((1 << bits) + (current_addr & ~align_mask));
}
}
void GekkoIRPlugin::StartInstruction(size_t mnemonic_index, bool extended)
{
m_build_inst = GekkoInstruction{
.mnemonic_index = mnemonic_index,
.raw_text = m_owner->lexer.CurrentLine(),
.line_number = m_owner->lexer.LineNumber(),
.is_extended = extended,
};
m_operand_scan_begin = m_output_result.operand_pool.size();
}
void GekkoIRPlugin::AddBinaryEvaluator(u32 (*evaluator)(u32, u32))
{
std::function<u32()> rhs = std::move(m_fixup_stack.top());
m_fixup_stack.pop();
std::function<u32()> lhs = std::move(m_fixup_stack.top());
m_fixup_stack.pop();
m_fixup_stack.emplace(
[evaluator, lhs = std::move(lhs), rhs = std::move(rhs)] { return evaluator(lhs(), rhs()); });
}
void GekkoIRPlugin::AddUnaryEvaluator(u32 (*evaluator)(u32))
{
std::function<u32()> sub = std::move(m_fixup_stack.top());
m_fixup_stack.pop();
m_fixup_stack.emplace([evaluator, sub = std::move(sub)] { return evaluator(sub()); });
}
void GekkoIRPlugin::AddAbsoluteAddressConv()
{
const u32 inst_address = m_active_block->BlockEndAddress();
std::function<u32()> sub = std::move(m_fixup_stack.top());
m_fixup_stack.pop();
m_fixup_stack.emplace([inst_address, sub = std::move(sub)] { return sub() - inst_address; });
}
void GekkoIRPlugin::AddLiteral(u32 lit)
{
m_fixup_stack.emplace([lit] { return lit; });
}
void GekkoIRPlugin::AddSymbolResolve(std::string_view sym, bool absolute)
{
const u32 source_address = m_active_block->BlockEndAddress();
AssemblerError err_on_fail = AssemblerError{
fmt::format("Unresolved symbol '{}'", sym),
m_owner->lexer.CurrentLine(),
m_owner->lexer.LineNumber(),
// Lexer should currently point to the label, as it hasn't been eaten yet
m_owner->lexer.ColNumber(),
sym.size(),
};
m_fixup_stack.emplace(
[this, sym, absolute, source_address, err_on_fail = std::move(err_on_fail)] {
auto label_it = m_labels.find(sym);
if (label_it != m_labels.end())
{
if (absolute)
{
return label_it->second;
}
return label_it->second - source_address;
}
auto var_it = m_constants.find(sym);
if (var_it != m_constants.end())
{
return static_cast<u32>(var_it->second);
}
m_owner->error = std::move(err_on_fail);
return u32{0};
});
}
void GekkoIRPlugin::AddNumLabelSymResolve(std::string_view sym, u32 num)
{
const u32 source_address = m_active_block->BlockEndAddress();
AssemblerError err_on_fail = AssemblerError{
fmt::format("No numeric label '{}' found below here", num),
m_owner->lexer.CurrentLine(),
m_owner->lexer.LineNumber(),
// Lexer should currently point to the label, as it hasn't been eaten yet
m_owner->lexer.ColNumber(),
sym.size(),
};
// Searching forward only
size_t search_start_idx = static_cast<size_t>(m_numlabs.size());
m_fixup_stack.emplace(
[this, num, source_address, search_start_idx, err_on_fail = std::move(err_on_fail)] {
for (size_t i = search_start_idx; i < m_numlabs.size(); i++)
{
if (num == m_numlabs[i].first)
{
return m_numlabs[i].second - source_address;
}
}
m_owner->error = std::move(err_on_fail);
return u32{0};
});
}
void GekkoIRPlugin::SaveOperandFixup(size_t str_left, size_t str_right)
{
m_operand_fixups.emplace_back(std::move(m_fixup_stack.top()));
m_fixup_stack.pop();
m_output_result.operand_pool.emplace_back(Interval{str_left, str_right - str_left}, 0);
}
void GekkoIRPlugin::RunFixups()
{
for (size_t i = 0; i < m_operand_fixups.size(); i++)
{
ValueOf(m_output_result.operand_pool[i]) = m_operand_fixups[i]();
if (m_owner->error)
{
return;
}
}
}
void GekkoIRPlugin::FinishInstruction()
{
m_build_inst.op_interval.begin = m_operand_scan_begin;
m_build_inst.op_interval.len = m_output_result.operand_pool.size() - m_operand_scan_begin;
GetChunk<InstChunk>().emplace_back(m_build_inst);
m_operand_scan_begin = 0;
}
void GekkoIRPlugin::EvalOperatorAbs(AsmOp operation)
{
#define EVAL_BINARY_OP(OPERATOR) \
{ \
u64 rhs = m_eval_stack.back(); \
m_eval_stack.pop_back(); \
m_eval_stack.back() = m_eval_stack.back() OPERATOR rhs; \
}
switch (operation)
{
case AsmOp::Or:
EVAL_BINARY_OP(|);
break;
case AsmOp::Xor:
EVAL_BINARY_OP(^);
break;
case AsmOp::And:
EVAL_BINARY_OP(&);
break;
case AsmOp::Lsh:
EVAL_BINARY_OP(<<);
break;
case AsmOp::Rsh:
EVAL_BINARY_OP(>>);
break;
case AsmOp::Add:
EVAL_BINARY_OP(+);
break;
case AsmOp::Sub:
EVAL_BINARY_OP(-);
break;
case AsmOp::Mul:
EVAL_BINARY_OP(*);
break;
case AsmOp::Div:
EVAL_BINARY_OP(/);
break;
case AsmOp::Neg:
m_eval_stack.back() = static_cast<u32>(-static_cast<s32>(m_eval_stack.back()));
break;
case AsmOp::Not:
m_eval_stack.back() = ~m_eval_stack.back();
break;
}
#undef EVAL_BINARY_OP
#undef EVAL_UNARY_OP
}
void GekkoIRPlugin::EvalOperatorRel(AsmOp operation)
{
switch (operation)
{
case AsmOp::Or:
AddBinaryEvaluator([](u32 lhs, u32 rhs) { return lhs | rhs; });
break;
case AsmOp::Xor:
AddBinaryEvaluator([](u32 lhs, u32 rhs) { return lhs ^ rhs; });
break;
case AsmOp::And:
AddBinaryEvaluator([](u32 lhs, u32 rhs) { return lhs & rhs; });
break;
case AsmOp::Lsh:
AddBinaryEvaluator([](u32 lhs, u32 rhs) { return lhs << rhs; });
break;
case AsmOp::Rsh:
AddBinaryEvaluator([](u32 lhs, u32 rhs) { return lhs >> rhs; });
break;
case AsmOp::Add:
AddBinaryEvaluator([](u32 lhs, u32 rhs) { return lhs + rhs; });
break;
case AsmOp::Sub:
AddBinaryEvaluator([](u32 lhs, u32 rhs) { return lhs - rhs; });
break;
case AsmOp::Mul:
AddBinaryEvaluator([](u32 lhs, u32 rhs) { return lhs * rhs; });
break;
case AsmOp::Div:
AddBinaryEvaluator([](u32 lhs, u32 rhs) { return lhs / rhs; });
break;
case AsmOp::Neg:
AddUnaryEvaluator([](u32 val) { return static_cast<u32>(-static_cast<s32>(val)); });
break;
case AsmOp::Not:
AddUnaryEvaluator([](u32 val) { return ~val; });
break;
}
}
void GekkoIRPlugin::EvalTerminalRel(Terminal type, const AssemblerToken& tok)
{
switch (type)
{
case Terminal::Hex:
case Terminal::Dec:
case Terminal::Oct:
case Terminal::Bin:
case Terminal::GPR:
case Terminal::FPR:
case Terminal::SPR:
case Terminal::CRField:
case Terminal::Lt:
case Terminal::Gt:
case Terminal::Eq:
case Terminal::So:
{
std::optional<u32> val = tok.EvalToken<u32>();
ASSERT(val.has_value());
AddLiteral(*val);
break;
}
case Terminal::Dot:
AddLiteral(CurrentAddress());
break;
case Terminal::Id:
{
if (auto label_it = m_labels.find(tok.token_val); label_it != m_labels.end())
{
AddLiteral(label_it->second - CurrentAddress());
}
else if (auto var_it = m_constants.find(tok.token_val); var_it != m_constants.end())
{
AddLiteral(var_it->second);
}
else
{
AddSymbolResolve(tok.token_val, false);
}
break;
}
case Terminal::NumLabFwd:
{
std::optional<u32> val = tok.EvalToken<u32>();
ASSERT(val.has_value());
AddNumLabelSymResolve(tok.token_val, *val);
break;
}
case Terminal::NumLabBwd:
{
std::optional<u32> mval = tok.EvalToken<u32>();
ASSERT(mval.has_value());
u32 val = *mval;
if (auto label_it = std::find_if(m_numlabs.rbegin(), m_numlabs.rend(),
[val](std::pair<u32, u32> p) { return p.first == val; });
label_it != m_numlabs.rend())
{
AddLiteral(label_it->second - CurrentAddress());
}
else
{
m_owner->EmitErrorHere(fmt::format("No numeric label '{}' found above here", val));
return;
}
break;
}
// Parser should disallow this from happening
default:
ASSERT(false);
break;
}
}
void GekkoIRPlugin::EvalTerminalAbs(Terminal type, const AssemblerToken& tok)
{
switch (type)
{
case Terminal::Hex:
case Terminal::Dec:
case Terminal::Oct:
case Terminal::Bin:
case Terminal::GPR:
case Terminal::FPR:
case Terminal::SPR:
case Terminal::CRField:
case Terminal::Lt:
case Terminal::Gt:
case Terminal::Eq:
case Terminal::So:
{
std::optional<u64> val = tok.EvalToken<u64>();
ASSERT(val.has_value());
m_eval_stack.push_back(*val);
break;
}
case Terminal::Flt:
{
std::visit(
[&tok](auto&& vec) {
auto opt = tok.EvalToken<typename std::decay_t<decltype(vec)>::value_type>();
ASSERT(opt.has_value());
vec.push_back(*opt);
},
m_floats_list);
break;
}
case Terminal::Dot:
m_eval_stack.push_back(static_cast<u64>(CurrentAddress()));
break;
case Terminal::Id:
{
if (auto label_it = m_labels.find(tok.token_val); label_it != m_labels.end())
{
m_eval_stack.push_back(label_it->second);
}
else if (auto var_it = m_constants.find(tok.token_val); var_it != m_constants.end())
{
m_eval_stack.push_back(var_it->second);
}
else
{
m_owner->EmitErrorHere(
fmt::format("Undefined reference to Label/Constant '{}'", tok.ValStr()));
return;
}
break;
}
case Terminal::NumLabFwd:
m_owner->EmitErrorHere(
fmt::format("Forward label references not supported in fully resolved expressions"));
break;
case Terminal::NumLabBwd:
{
std::optional<u32> mval = tok.EvalToken<u32>();
ASSERT(mval.has_value());
u32 val = *mval;
if (auto label_it = std::find_if(m_numlabs.rbegin(), m_numlabs.rend(),
[val](std::pair<u32, u32> p) { return p.first == val; });
label_it != m_numlabs.rend())
{
m_eval_stack.push_back(label_it->second);
}
else
{
m_owner->EmitErrorHere(fmt::format("No numeric label '{}' found above here", val));
return;
}
break;
}
// Parser should disallow this from happening
default:
ASSERT(false);
break;
}
}
} // namespace
u32 IRBlock::BlockEndAddress() const
{
return std::accumulate(chunks.begin(), chunks.end(), block_address,
[](u32 acc, const ChunkVariant& chunk) {
size_t size;
if (std::holds_alternative<InstChunk>(chunk))
{
size = std::get<InstChunk>(chunk).size() * 4;
}
else if (std::holds_alternative<ByteChunk>(chunk))
{
size = std::get<ByteChunk>(chunk).size();
}
else if (std::holds_alternative<PadChunk>(chunk))
{
size = std::get<PadChunk>(chunk);
}
else
{
ASSERT(false);
size = 0;
}
return acc + static_cast<u32>(size);
});
}
FailureOr<GekkoIR> ParseToIR(std::string_view assembly, u32 base_virtual_address)
{
GekkoIR ret;
GekkoIRPlugin plugin(ret, base_virtual_address);
ParseWithPlugin(&plugin, assembly);
if (plugin.Error())
{
return FailureOr<GekkoIR>(std::move(*plugin.Error()));
}
return std::move(ret);
}
} // namespace Common::GekkoAssembler::detail