6#include <unordered_map>
8#include <fmt/ostream.h>
18 using namespace literals;
21 m_logger(
"IRCompiler", debug)
24 void IRCompiler::process(
const std::vector<IR::Block>& pages,
const std::vector<std::string>& symbols,
const std::vector<ValTableElem>& values)
32 for (
const auto& page : pages)
34 for (
const auto& inst : page)
61 std::vector<unsigned char> hash_out(picosha2::k_digest_size);
70 std::size_t index = 0;
71 for (
const auto& block :
m_ir)
73 fmt::println(stream,
"page_{}", index);
74 for (
const auto& entity : block)
76 switch (entity.kind())
79 fmt::println(stream,
".L{}:", entity.label());
83 fmt::println(stream,
"\tGOTO L{}", entity.label());
87 fmt::println(stream,
"\tGOTO_IF_TRUE L{}", entity.label());
91 fmt::println(stream,
"\tGOTO_IF_FALSE L{}", entity.label());
95 fmt::println(stream,
"\t{} {}",
InstructionNames[entity.inst()], entity.primaryArg());
99 fmt::println(stream,
"\t{} {}, {}",
InstructionNames[entity.inst()], entity.primaryArg(), entity.secondaryArg());
104 fmt::println(stream,
"");
117 for (std::size_t i = 0, end =
m_ir.size(); i < end; ++i)
122 page.emplace_back(
HALT);
125 const auto page_size = std::ranges::count_if(page, [](
const auto& a) {
128 if (std::cmp_greater(page_size, std::numeric_limits<uint16_t>::max()))
129 throw std::overflow_error(fmt::format(
"Size of page {} exceeds the maximum size of 2^16 - 1", i));
136 std::unordered_map<IR::label_t, uint16_t> label_to_position;
137 for (
auto& inst : page)
142 label_to_position[inst.label()] = pos;
150 for (
auto& inst : page)
207 const long long timestamp = std::chrono::duration_cast<std::chrono::seconds>(
208 std::chrono::system_clock::now().time_since_epoch())
210 for (
long i = 0; i < 8; ++i)
212 const long shift = 8 * (7 - i);
213 const auto ts_byte =
static_cast<uint8_t
>((timestamp & (0xffLL << shift)) >> shift);
220 const std::size_t symbol_size = symbols.size();
221 if (symbol_size > std::numeric_limits<uint16_t>::max())
222 throw std::overflow_error(fmt::format(
"Too many symbols: {}, exceeds the maximum size of 2^16 - 1", symbol_size));
227 for (
const auto& sym : symbols)
230 std::ranges::transform(sym, std::back_inserter(
m_bytecode), [](
const char i) {
231 return static_cast<uint8_t
>(i);
239 const std::size_t value_size = values.size();
240 if (value_size > std::numeric_limits<uint16_t>::max())
241 throw std::overflow_error(fmt::format(
"Too many values: {}, exceeds the maximum size of 2^16 - 1", value_size));
253 const auto n = std::get<double>(val.value);
263 auto t = std::get<std::string>(val.value);
264 std::ranges::transform(t, std::back_inserter(
m_bytecode), [](
const char i) {
265 return static_cast<uint8_t
>(i);
273 const std::size_t addr = std::get<std::size_t>(val.value);
285 if (
m_filenames.size() > std::numeric_limits<uint16_t>::max())
286 throw std::overflow_error(fmt::format(
"Too many filenames: {}, exceeds the maximum size of 2^16 - 1",
m_filenames.size()));
294 std::ranges::transform(name, std::back_inserter(
m_bytecode), [](
const char i) {
295 return static_cast<uint8_t
>(i);
303 std::vector<internal::InstLoc> locations;
304 for (std::size_t i = 0, end = pages.size(); i < end; ++i)
306 const auto& page = pages[i];
309 for (
const auto& inst : page)
311 if (inst.hasValidSourceLocation())
315 auto file_id =
static_cast<uint16_t
>(std::distance(
m_filenames.begin(), std::ranges::find(
m_filenames, inst.filename())));
317 std::optional<internal::InstLoc> prev = std::nullopt;
318 if (!locations.empty())
319 prev = locations.back();
322 if (!(prev.has_value() && prev->filename_id == file_id && prev->line == inst.sourceLine() && prev->page_pointer == i))
324 { .page_pointer =
static_cast<uint16_t
>(i),
326 .filename_id = file_id,
327 .line =
static_cast<uint32_t
>(inst.sourceLine()) });
338 std::optional<internal::InstLoc> prev = std::nullopt;
340 for (
const auto& loc : locations)
Constants used by ArkScript.
constexpr int ARK_VERSION_MAJOR
constexpr int ARK_VERSION_PATCH
constexpr int ARK_VERSION_MINOR
Compile the intermediate representation to bytecode.
User defined literals for Ark internals.
void pushInstLocTable(const std::vector< IR::Block > &pages)
IRCompiler(unsigned debug)
Create a new IRCompiler.
void dumpToStream(std::ostream &stream) const
Dump the IR given to process to an output stream.
const bytecode_t & bytecode() const noexcept
Return the constructed bytecode object.
std::vector< std::string > m_filenames
void pushWord(const Word &word)
Push a word (4 bytes) to the m_bytecode.
std::vector< IR::Block > m_ir
void pushFileHeader() noexcept
Push the file headers (magic, version used, timestamp)
void process(const std::vector< IR::Block > &pages, const std::vector< std::string > &symbols, const std::vector< ValTableElem > &values)
Turn a given IR into bytecode.
void pushValueTable(const std::vector< ValTableElem > &values)
void pushSymbolTable(const std::vector< std::string > &symbols)
void traceStart(std::string &&trace_name)
std::vector< Entity > Block
constexpr std::size_t HeaderSize
DecomposedDouble serialize(const double n)
void serializeToVecBE(std::integral auto number, std::vector< uint8_t > &out)
void serializeToVecLE(std::integral auto number, std::vector< uint8_t > &out)
void serializeOn2BytesToVecBE(std::integral auto number, std::vector< uint8_t > &out)
constexpr std::array InstructionNames
std::vector< uint8_t > bytecode_t
A Compiler Value class helper to handle multiple types.
uint8_t opcode
Instruction opcode.