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,
"\t{} L{}",
InstructionNames[entity.inst()], entity.label());
87 fmt::println(stream,
"\t{} L{}, {}",
InstructionNames[entity.inst()], entity.label(), entity.primaryArg());
91 fmt::println(stream,
"\t{} {}",
InstructionNames[entity.inst()], entity.primaryArg());
95 fmt::println(stream,
"\t{} {}, {}",
InstructionNames[entity.inst()], entity.primaryArg(), entity.secondaryArg());
100 fmt::println(stream,
"");
113 for (std::size_t i = 0, end =
m_ir.size(); i < end; ++i)
118 page.emplace_back(
HALT);
121 const auto page_size = std::ranges::count_if(page, [](
const auto& a) {
124 if (std::cmp_greater(page_size, std::numeric_limits<uint16_t>::max()))
125 throw std::overflow_error(fmt::format(
"Size of page {} exceeds the maximum size of 2^16 - 1", i));
132 std::unordered_map<IR::label_t, uint16_t> label_to_position;
133 for (
auto& inst : page)
138 label_to_position[inst.label()] = pos;
146 for (
auto& inst : page)
151 pushWord(
Word(inst.inst(), label_to_position[inst.label()]));
155 pushWord(
Word(inst.inst(), inst.primaryArg(), label_to_position[inst.label()]));
199 const long long timestamp = std::chrono::duration_cast<std::chrono::seconds>(
200 std::chrono::system_clock::now().time_since_epoch())
202 for (
long i = 0; i < 8; ++i)
204 const long shift = 8 * (7 - i);
205 const auto ts_byte =
static_cast<uint8_t
>((timestamp & (0xffLL << shift)) >> shift);
212 const std::size_t symbol_size = symbols.size();
213 if (symbol_size > std::numeric_limits<uint16_t>::max())
214 throw std::overflow_error(fmt::format(
"Too many symbols: {}, exceeds the maximum size of 2^16 - 1", symbol_size));
219 for (
const auto& sym : symbols)
222 std::ranges::transform(sym, std::back_inserter(
m_bytecode), [](
const char i) {
223 return static_cast<uint8_t
>(i);
231 const std::size_t value_size = values.size();
232 if (value_size > std::numeric_limits<uint16_t>::max())
233 throw std::overflow_error(fmt::format(
"Too many values: {}, exceeds the maximum size of 2^16 - 1", value_size));
245 const auto n = std::get<double>(val.value);
255 auto t = std::get<std::string>(val.value);
256 std::ranges::transform(t, std::back_inserter(
m_bytecode), [](
const char i) {
257 return static_cast<uint8_t
>(i);
265 const std::size_t addr = std::get<std::size_t>(val.value);
277 if (
m_filenames.size() > std::numeric_limits<uint16_t>::max())
278 throw std::overflow_error(fmt::format(
"Too many filenames: {}, exceeds the maximum size of 2^16 - 1",
m_filenames.size()));
286 std::ranges::transform(name, std::back_inserter(
m_bytecode), [](
const char i) {
287 return static_cast<uint8_t
>(i);
295 std::vector<internal::InstLoc> locations;
296 for (std::size_t i = 0, end = pages.size(); i < end; ++i)
298 const auto& page = pages[i];
301 for (
const auto& inst : page)
303 if (inst.hasValidSourceLocation())
307 auto file_id =
static_cast<uint16_t
>(std::distance(
m_filenames.begin(), std::ranges::find(
m_filenames, inst.filename())));
309 std::optional<internal::InstLoc> prev = std::nullopt;
310 if (!locations.empty())
311 prev = locations.back();
314 if (!(prev.has_value() && prev->filename_id == file_id && prev->line == inst.sourceLine() && prev->page_pointer == i))
316 { .page_pointer =
static_cast<uint16_t
>(i),
318 .filename_id = file_id,
319 .line =
static_cast<uint32_t
>(inst.sourceLine()) });
330 std::optional<internal::InstLoc> prev = std::nullopt;
332 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.