6#include <unordered_map>
8#include <fmt/ostream.h>
18 using namespace literals;
21 Pass(
"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.data)
61 std::vector<unsigned char> hash_out(picosha2::k_digest_size);
70 std::size_t index = 0;
71 for (
const auto& block :
m_ir)
75 fmt::println(stream,
"global");
80 "page_{} ({} ({} argument{}) {}, {} instructions)",
83 block.metadata.argument_count,
84 block.metadata.argument_count == 1 ?
"" :
"s",
89 for (
const auto& entity : block.data)
91 switch (entity.kind())
94 fmt::println(stream,
".L{}:", entity.label());
98 fmt::println(stream,
"\t{} L{}",
InstructionNames[entity.inst()], entity.label());
102 fmt::println(stream,
"\t{} L{}, {}",
InstructionNames[entity.inst()], entity.label(), entity.primaryArg());
106 fmt::println(stream,
"\t{} {}",
InstructionNames[entity.inst()], entity.primaryArg());
110 fmt::println(stream,
"\t{} {}, {}",
InstructionNames[entity.inst()], entity.primaryArg(), entity.secondaryArg());
114 fmt::println(stream,
"\t{} {}, {}, {}",
InstructionNames[entity.inst()], entity.primaryArg(), entity.secondaryArg(), entity.tertiaryArg());
119 fmt::println(stream,
"");
132 for (std::size_t i = 0, end =
m_ir.size(); i < end; ++i)
137 page.
data.emplace_back(HALT);
145 message = fmt::format(
"Global scope exceeds the maximum number of instructions ({})",
MaxValue16Bits);
147 message = fmt::format(
"Function {} exceeds the maximum number of instructions ({})", page.
metadata.
name.value(),
MaxValue16Bits);
149 message = fmt::format(
"Anonymous function at page {} exceeds the maximum number of instructions ({})", i,
MaxValue16Bits);
151 throw std::overflow_error(message);
159 std::unordered_map<IR::label_t, uint16_t> label_to_position;
160 for (
const auto& inst : page.
data)
165 label_to_position[inst.label()] = pos;
173 for (
const auto& inst : page.
data)
178 pushWord(
Word(inst.inst(), label_to_position[inst.label()]));
182 pushWord(
Word(inst.inst(), inst.primaryArg(), label_to_position[inst.label()]));
228 const long long timestamp = std::chrono::duration_cast<std::chrono::seconds>(
229 std::chrono::system_clock::now().time_since_epoch())
231 for (
long i = 0; i < 8; ++i)
233 const long shift = 8 * (7 - i);
234 const auto ts_byte =
static_cast<uint8_t
>((timestamp & (0xffLL << shift)) >> shift);
241 const std::size_t symbol_size = symbols.size();
243 throw std::overflow_error(fmt::format(
"Too many symbols: {}, exceeds the maximum size of {}", symbol_size,
MaxValue16Bits));
248 for (
const auto& sym : symbols)
251 std::ranges::transform(sym, std::back_inserter(
m_bytecode), [](
const char i) {
252 return static_cast<uint8_t
>(i);
260 const std::size_t value_size = values.size();
262 throw std::overflow_error(fmt::format(
"Too many values: {}, exceeds the maximum size of {}", value_size,
MaxValue16Bits));
274 const auto n = std::get<double>(val.value);
284 auto t = std::get<std::string>(val.value);
285 std::ranges::transform(t, std::back_inserter(
m_bytecode), [](
const char i) {
286 return static_cast<uint8_t
>(i);
294 const std::size_t addr = std::get<std::size_t>(val.value);
307 throw std::overflow_error(fmt::format(
"Too many filenames: {}, exceeds the maximum size of {}",
m_filenames.size(),
MaxValue16Bits));
315 std::ranges::transform(name, std::back_inserter(
m_bytecode), [](
const char i) {
316 return static_cast<uint8_t
>(i);
324 std::vector<internal::InstLoc> locations;
325 for (std::size_t i = 0, end = pages.size(); i < end; ++i)
327 const auto& page = pages[i];
330 for (
const auto& inst : page.data)
332 if (inst.hasValidSourceLocation())
336 auto file_id =
static_cast<uint16_t
>(std::distance(
m_filenames.begin(), std::ranges::find(
m_filenames, inst.filename())));
338 std::optional<internal::InstLoc> prev = std::nullopt;
339 if (!locations.empty())
340 prev = locations.back();
343 if (!(prev.has_value() && prev->filename_id == file_id && prev->line == inst.sourceLine() && prev->page_pointer == i))
345 { .page_pointer =
static_cast<uint16_t
>(i),
347 .filename_id = file_id,
348 .line =
static_cast<uint32_t
>(inst.sourceLine()) });
359 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)
An interface to describe compiler passes.
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
constexpr uint16_t MaxValue16Bits
std::vector< uint8_t > bytecode_t
Block of IR entities, with attached metadata.
std::size_t instructionCount() const
struct Ark::internal::IR::Block::Metadata metadata
A Compiler Value class helper to handle multiple types.
uint8_t opcode
Instruction opcode.