#include "emit.h" #include "accumulation.h" #include #include #include #include #include #include #include namespace { struct TARGET_REC { uint32_t size; uint32_t fieldcnt; uint32_t fieldoff; }; struct TARGET_FIELD_REC { uint32_t offset; uint32_t size; uint32_t alignment; uint32_t flags; }; struct IPIN_REC { std::string addr_sym; uint32_t size; uint32_t program; }; struct IPIN_OP_REC { uint32_t code; uint32_t op0; uint32_t op1; }; struct DPIN_REC { std::string addr_sym; uint32_t target; }; struct PROGRAM_KEY { uint32_t target; uint32_t field; bool operator==(const PROGRAM_KEY& other) const { return target == other.target && field == other.field; } }; struct PROGRAM_KEY_HASH { std::size_t operator()(const PROGRAM_KEY& k) const { return (static_cast(k.target) << 32) ^ k.field; } }; static bool emit_header(std::ostream& out); static bool emit_u32_object(std::ostream& out, const char* name, uint32_t value); static bool emit_targets(std::ostream& out, const std::vector& targets); static bool emit_target_fields(std::ostream& out, const std::vector& fields); static bool emit_ipins(std::ostream& out, const std::vector& ipins); static bool emit_ipin_ops(std::ostream& out, const std::vector& ops); static bool emit_dpins(std::ostream& out, const std::vector& dpins); static uint32_t intern_simple_ipin_program( std::vector& ops, std::unordered_map& memo, uint32_t target, uint32_t field) { PROGRAM_KEY key{target, field}; auto it = memo.find(key); if (it != memo.end()) return it->second; const uint32_t start = static_cast(ops.size()); ops.push_back(IPIN_OP_REC{ .code = SPSLR_IPIN_OP_ADD_OFFSET, .op0 = target, .op1 = field, }); ops.push_back(IPIN_OP_REC{ .code = SPSLR_IPIN_OP_PATCH, .op0 = 0, .op1 = 0, }); memo.emplace(key, start); return start; } static bool emit_header(std::ostream& out) { out << ".section .spslr,\"a\",@progbits\n"; out << ".balign 8\n"; return !!out; } static bool emit_u32_object(std::ostream& out, const char* name, uint32_t value) { out << ".globl " << name << "\n"; out << ".type " << name << ", @object\n"; out << ".balign 4\n"; out << name << ":\n"; out << "\t.long " << value << "\n"; out << ".size " << name << ", 4\n"; return !!out; } static bool emit_targets(std::ostream& out, const std::vector& targets) { out << ".globl spslr_targets\n"; out << ".type spslr_targets, @object\n"; out << ".balign 4\n"; out << "spslr_targets:\n"; for (const TARGET_REC& t : targets) { out << "\t.long " << t.size << "\n"; out << "\t.long " << t.fieldcnt << "\n"; out << "\t.long " << t.fieldoff << "\n"; } out << ".size spslr_targets, .-spslr_targets\n"; return !!out; } static bool emit_target_fields(std::ostream& out, const std::vector& fields) { out << ".globl spslr_target_fields\n"; out << ".type spslr_target_fields, @object\n"; out << ".balign 4\n"; out << "spslr_target_fields:\n"; for (const TARGET_FIELD_REC& f : fields) { out << "\t.long " << f.offset << "\n"; out << "\t.long " << f.size << "\n"; out << "\t.long " << f.alignment << "\n"; out << "\t.long " << f.flags << "\n"; } out << ".size spslr_target_fields, .-spslr_target_fields\n"; return !!out; } static bool emit_ipins(std::ostream& out, const std::vector& ipins) { out << ".globl spslr_ipins\n"; out << ".type spslr_ipins, @object\n"; out << ".balign 8\n"; out << "spslr_ipins:\n"; for (const IPIN_REC& ip : ipins) { out << "\t.quad " << ip.addr_sym << "\n"; out << "\t.long " << ip.size << "\n"; out << "\t.long " << ip.program << "\n"; } out << ".size spslr_ipins, .-spslr_ipins\n"; return !!out; } static bool emit_ipin_ops(std::ostream& out, const std::vector& ops) { out << ".globl spslr_ipin_ops\n"; out << ".type spslr_ipin_ops, @object\n"; out << ".balign 4\n"; out << "spslr_ipin_ops:\n"; for (const IPIN_OP_REC& op : ops) { out << "\t.long " << op.code << "\n"; out << "\t.long " << op.op0 << "\n"; out << "\t.long " << op.op1 << "\n"; } out << ".size spslr_ipin_ops, .-spslr_ipin_ops\n"; return !!out; } static bool emit_dpins(std::ostream& out, const std::vector& dpins) { out << ".globl spslr_dpins\n"; out << ".type spslr_dpins, @object\n"; out << ".balign 8\n"; out << "spslr_dpins:\n"; for (const DPIN_REC& dp : dpins) { out << "\t.quad " << dp.addr_sym << "\n"; out << "\t.long " << dp.target << "\n"; } out << ".size spslr_dpins, .-spslr_dpins\n"; return !!out; } } bool emit_patcher_program_asm(std::ostream& out) { if (!emit_header(out)) return false; // Important: target UID == index in spslr_targets[] for the new interface. std::vector target_recs(targets.size()); std::vector field_recs; field_recs.reserve(64); for (uint32_t uid = 0; uid < static_cast(targets.size()); ++uid) { if (!targets.contains(uid)) return false; const TARGET& target = targets.at(uid); TARGET_REC trec{}; trec.size = static_cast(target.size); trec.fieldoff = static_cast(field_recs.size()); trec.fieldcnt = static_cast(target.fields.size()); for (const auto& [off, field] : target.fields) { (void)off; field_recs.push_back(TARGET_FIELD_REC{ .offset = static_cast(field.offset), .size = static_cast(field.size), .alignment = static_cast(field.alignment), .flags = static_cast(field.flags), }); } target_recs[uid] = trec; } std::vector ipin_recs; std::vector ipin_ops; std::unordered_map program_memo; std::vector dpin_recs; for (const auto& [cu_uid, cu] : units) { (void)cu_uid; for (const auto& [sym, ipin] : cu.ipins) { const uint32_t global_target = static_cast(cu.local_targets.at(ipin.local_target)); if (!targets.contains(global_target)) return false; const TARGET& target = targets.at(global_target); if (!target.fields.contains(ipin.field_offset)) return false; const FIELD& field = target.fields.at(ipin.field_offset); const uint32_t program = intern_simple_ipin_program( ipin_ops, program_memo, global_target, static_cast(field.idx) ); ipin_recs.push_back(IPIN_REC{ .addr_sym = ipin.symbol, .size = static_cast(ipin.imm_size), .program = program, }); } for (const auto& [sym, dpin] : cu.dpins) { std::vector sorted_components(dpin.components.begin(), dpin.components.end()); std::sort( sorted_components.begin(), sorted_components.end(), [](const DPIN::COMPONENT& a, const DPIN::COMPONENT& b) { return a.level > b.level; } ); for (const DPIN::COMPONENT& component : sorted_components) { const uint32_t global_target = static_cast(cu.local_targets.at(component.target)); std::string addr = dpin.symbol; if (component.offset != 0) addr += " + " + std::to_string(component.offset); dpin_recs.push_back(DPIN_REC{ .addr_sym = std::move(addr), .target = global_target, }); } } } if (!emit_u32_object(out, "spslr_target_cnt", static_cast(target_recs.size()))) return false; if (!emit_targets(out, target_recs)) return false; if (!emit_u32_object(out, "spslr_target_field_cnt", static_cast(field_recs.size()))) return false; if (!emit_target_fields(out, field_recs)) return false; if (!emit_u32_object(out, "spslr_ipin_cnt", static_cast(ipin_recs.size()))) return false; if (!emit_ipins(out, ipin_recs)) return false; if (!emit_u32_object(out, "spslr_ipin_op_cnt", static_cast(ipin_ops.size()))) return false; if (!emit_ipin_ops(out, ipin_ops)) return false; if (!emit_u32_object(out, "spslr_dpin_cnt", static_cast(dpin_recs.size()))) return false; if (!emit_dpins(out, dpin_recs)) return false; return !!out; }