阶段2-6:V2 生成侧 bug 修复与验证收尾

- Codec:set_byte0 的 11/10 前缀位修正(0xC0/0x80);新增 JC 形态偏移
  专用读写(off@55..24,字节 3..6)——修复 JF rd 被 off 覆盖
- Stb:offset_meta=0(空段)时值段大小校验按 SHA 尾计算(修复
  values segment size mismatch)
- Codegen:实例字段带 func(field_func),LOAD_OFF/STORE_OFF 按字段
  类型设 func(pt=TIME → I64)
- main.cpp:--disasm 按 instr_len 迭代变长字节码
- 验证:13 个正例全部编译出 V2 产物 + disasm 自读通过(RET/CAL.TON/
  STORE_OFF.I64/JF 偏移等抽查正确);ctest 11/13(vm/cases 待阶段 4)
This commit is contained in:
2026-08-25 20:23:32 +08:00
parent 924c0c1923
commit 4785cf3e3b
5 changed files with 79 additions and 31 deletions
+6 -2
View File
@@ -60,8 +60,10 @@ namespace compiler {
uint32_t imm32_of(const uint8_t* code);
/// @brief 取 slot3255..24SLOT 形态)。
uint32_t slot32_of(const uint8_t* code);
/// @brief 取 off3247..16JMP/JC 形态,有符号字节偏移)。
/// @brief 取 off3247..16JMP 形态,有符号字节偏移)。
int32_t off32_of(const uint8_t* code);
/// @brief 取 off3255..24JC 形态,有符号字节偏移)。
int32_t off32_jc_of(const uint8_t* code);
/// @brief 取 fn_id3247..16CALL 形态)。
uint32_t fn_id32_of(const uint8_t* code);
/// @brief 取 fb_id1631..16CAL 形态)。
@@ -93,8 +95,10 @@ namespace compiler {
void set_imm32(uint8_t* out, uint32_t v);
/// @brief 写 slot3255..24)。
void set_slot32(uint8_t* out, uint32_t v);
/// @brief 写 off3247..16)。
/// @brief 写 off3247..16JMP 形态)。
void set_off32(uint8_t* out, int32_t v);
/// @brief 写 off3255..24JC 形态)。
void set_off32_jc(uint8_t* out, int32_t v);
/// @brief 写 fn_id3247..16)。
void set_fn_id32(uint8_t* out, uint32_t v);
/// @brief 写 fb_id1631..16)。
+24 -4
View File
@@ -121,7 +121,7 @@ uint32_t imm32_of(const uint8_t* code) {
uint32_t slot32_of(const uint8_t* code) { return imm32_of(code); }
/**
* @brief 取 off3247..16,小端 4 字节,有符号)。
* @brief 取 off3247..16JMP 形态,小端 4 字节,有符号)。
* @param code 指令字节
* @return 字节偏移(相对下一条)
*/
@@ -132,6 +132,18 @@ int32_t off32_of(const uint8_t* code) {
| (static_cast<uint32_t>(code[5]) << 24));
}
/**
* @brief 取 off3255..24JC 形态,小端 4 字节,有符号)。
* @param code 指令字节
* @return 字节偏移(相对下一条)
*/
int32_t off32_jc_of(const uint8_t* code) {
return static_cast<int32_t>(static_cast<uint32_t>(code[3])
| (static_cast<uint32_t>(code[4]) << 8)
| (static_cast<uint32_t>(code[5]) << 16)
| (static_cast<uint32_t>(code[6]) << 24));
}
uint32_t fn_id32_of(const uint8_t* code) {
return static_cast<uint32_t>(code[2])
| (static_cast<uint32_t>(code[3]) << 8)
@@ -193,9 +205,9 @@ uint64_t imm64_of(const uint8_t* code) {
*/
void set_byte0(uint8_t* out, const std::string& prefix, uint32_t op) {
if (prefix == "11") {
out[0] = static_cast<uint8_t>(0x80 | (op & 0x3F));
out[0] = static_cast<uint8_t>(0xC0 | (op & 0x3F)); // bit7..6 = 11
} else if (prefix == "10") {
out[0] = static_cast<uint8_t>(0x80 | 0x40 | (op & 0x3F));
out[0] = static_cast<uint8_t>(0x80 | (op & 0x3F)); // bit7..6 = 10
} else if (prefix == "011") {
out[0] = static_cast<uint8_t>(0x40 | (op & 0x1F));
} else if (prefix.size() == 6 && prefix.compare(0, 3, "010") == 0) {
@@ -232,6 +244,14 @@ void set_off32(uint8_t* out, int32_t v) {
out[4] = static_cast<uint8_t>((u >> 16) & 0xFF);
out[5] = static_cast<uint8_t>((u >> 24) & 0xFF);
}
void set_off32_jc(uint8_t* out, int32_t v) {
const uint32_t u = static_cast<uint32_t>(v);
out[3] = static_cast<uint8_t>(u & 0xFF);
out[4] = static_cast<uint8_t>((u >> 8) & 0xFF);
out[5] = static_cast<uint8_t>((u >> 16) & 0xFF);
out[6] = static_cast<uint8_t>((u >> 24) & 0xFF);
}
void set_fn_id32(uint8_t* out, uint32_t v) { set_off32(out, static_cast<int32_t>(v)); }
void set_fb_id16(uint8_t* out, uint16_t v) {
out[2] = static_cast<uint8_t>(v & 0xFF);
@@ -302,7 +322,7 @@ void disasm(const MachineConfig& cfg, const uint8_t* code, size_t len,
snprintf(out, cap, "%s %+d", op->name.c_str(), static_cast<int>(off32_of(code)));
} else if (f == "JC") {
snprintf(out, cap, "%s r%u, %+d", op->name.c_str(),
static_cast<unsigned>(rd_of(code)), static_cast<int>(off32_of(code)));
static_cast<unsigned>(rd_of(code)), static_cast<int>(off32_jc_of(code)));
} else if (f == "CALL") {
snprintf(out, cap, "%s %u", op->name.c_str(), static_cast<unsigned>(fn_id32_of(code)));
} else if (f == "CAL") {
+33 -16
View File
@@ -175,11 +175,11 @@ namespace {
set_off32(f.code.data() + s, off);
return s;
}
/// 条件跳转(r 为真则跳;off 字节相对下一条)。
/// 条件跳转(r 为真则跳;off 字节相对下一条JC 形态 off@55..24)。
size_t E_jc(FuncCtx& f, const char* name, uint8_t r, int32_t off) {
const size_t s = emit(f, opc(name));
set_rd(f.code.data() + s, r);
set_off32(f.code.data() + s, off);
set_off32_jc(f.code.data() + s, off);
return s;
}
/// CALL 指令(fn_id32)。
@@ -241,9 +241,10 @@ namespace {
* @brief FB 实例布局(V2:槽表条目 + 值区偏移 + 字段偏移)。
*/
struct InstFields {
std::map<std::string, int32_t> field_off; ///< 字段名 → 值区内偏移
uint32_t slot = 0; ///< 实例槽号(槽表条目
std::string type_name; ///< 实例的 FB 类型名
std::map<std::string, int32_t> field_off; ///< 字段名 → 值区内偏移
std::map<std::string, uint8_t> field_func; ///< 字段名 → func(类型
uint32_t slot = 0; ///< 实例槽号(槽表条目)
std::string type_name; ///< 实例的 FB 类型名
};
void begin_stmt(FuncCtx& f) { f.temp_used = 0; }
@@ -344,7 +345,12 @@ namespace {
if (!compile_expr(f, *st.value, t)) {
return false;
}
E_slot_off(f, "STORE_OFF", t, inline_fields_->slot, fit->second);
const size_t so = E_slot_off(f, "STORE_OFF", t, inline_fields_->slot,
fit->second);
const auto ff = inline_fields_->field_func.find(st.target);
if (ff != inline_fields_->field_func.end()) {
set_func(f.code.data() + so, ff->second);
}
return true;
}
}
@@ -372,7 +378,11 @@ namespace {
if (!compile_expr(f, *a.value, t)) {
return false;
}
E_slot_off(f, "STORE_OFF", t, inst->slot, it->second);
const size_t so = E_slot_off(f, "STORE_OFF", t, inst->slot, it->second);
const auto ff = inst->field_func.find(a.name);
if (ff != inst->field_func.end()) {
set_func(f.code.data() + so, ff->second);
}
}
// 内建 FBfb 表查 id
const ConfigFb* fb = cfg_.find_fb(uppercase_of(inst->type_name));
@@ -498,7 +508,12 @@ namespace {
if (inline_fields_) {
const auto fit = inline_fields_->field_off.find(e.name);
if (fit != inline_fields_->field_off.end()) {
E_slot_off(f, "LOAD_OFF", rd, inline_fields_->slot, fit->second);
const size_t lo = E_slot_off(f, "LOAD_OFF", rd,
inline_fields_->slot, fit->second);
const auto ff = inline_fields_->field_func.find(e.name);
if (ff != inline_fields_->field_func.end()) {
set_func(f.code.data() + lo, ff->second);
}
return true;
}
}
@@ -527,7 +542,11 @@ namespace {
if (fit == inst->field_off.end()) {
return fail("unknown field '" + e.field + "' for '" + e.name + "'");
}
E_slot_off(f, "LOAD_OFF", rd, inst->slot, fit->second);
const size_t lo = E_slot_off(f, "LOAD_OFF", rd, inst->slot, fit->second);
const auto ff = inst->field_func.find(e.field);
if (ff != inst->field_func.end()) {
set_func(f.code.data() + lo, ff->second);
}
return true;
}
if (e.kind == ExprKind::Add || e.kind == ExprKind::Sub ||
@@ -636,16 +655,13 @@ namespace {
const int32_t off = static_cast<int32_t>(
static_cast<int64_t>(target_off) -
(static_cast<int64_t>(idx) + static_cast<int64_t>(instr_len(f.code.data() + idx))));
const ConfigOp* j = nullptr;
// 按字节 0 前缀推导跳转指令:JMP/JT/JF010010/010011 区)
// 按前缀选偏移字段:JMP010010off@47..16JT/JF010011off@55..24
const std::string prefix = prefix_of(f.code.data() + idx);
if (prefix == "010010") {
j = cfg_.find_op("JMP");
} else if (prefix == "010011") {
j = cfg_.find_op("JF"); // 占位:JF/JT 按 rd 区分不必要(偏移相同)
set_off32(f.code.data() + idx, off);
} else {
set_off32_jc(f.code.data() + idx, off);
}
(void)j;
set_off32(f.code.data() + idx, off);
}
static const char* arith_name(ExprKind k) {
@@ -717,6 +733,7 @@ namespace {
}
off = static_cast<int32_t>(align_up(off, tm.width()));
inst.field_off[fd.name] = off;
inst.field_func[fd.name] = static_cast<uint8_t>(tm.func());
off += static_cast<int32_t>(tm.width());
}
// 实例块对齐到 max(字段对齐)
+10 -5
View File
@@ -271,10 +271,9 @@ StbView StbView::from(const uint8_t* buf, size_t len) {
v.err_ = "missing sha256 tail";
return v;
}
const uint64_t offs[6] = {get_le32(buf + kOffConst), get_le32(buf + kOffFuncs), v.offset_code_,
v.offset_slots_, v.offset_values_,
(v.offset_meta_ != 0) ? v.offset_meta_ : v.offset_values_};
for (int i = 0; i < 6; ++i) {
const uint64_t offs[5] = {get_le32(buf + kOffConst), get_le32(buf + kOffFuncs), v.offset_code_,
v.offset_slots_, v.offset_values_};
for (int i = 0; i < 5; ++i) {
if (offs[i] < kHeaderSize || offs[i] > len - kSha256Size) {
v.err_ = "segment offset out of range";
return v;
@@ -296,7 +295,13 @@ StbView StbView::from(const uint8_t* buf, size_t len) {
v.err_ = "slot table size mismatch";
return v;
}
if (offs[5] - offs[4] != v.values_size_) {
// 值段大小:meta 段为 0(空段)时值段到 SHA 尾;否则到 meta 起点
if (v.offset_meta_ != 0) {
if (static_cast<uint64_t>(v.offset_meta_) - offs[4] != v.values_size_) {
v.err_ = "values segment size mismatch";
return v;
}
} else if (static_cast<uint64_t>(len - kSha256Size) - offs[4] != v.values_size_) {
v.err_ = "values segment size mismatch";
return v;
}
+6 -4
View File
@@ -81,12 +81,14 @@ namespace {
std::printf(" fn %u: nregs=%u, offset=%u, len=%u\n", i, r.nregs,
r.code_offset, r.code_len);
const uint8_t* base = v.code_bytes() + r.code_offset;
for (uint32_t j = 0; j < r.code_len; ++j) {
uint32_t pc = 0;
while (pc < r.code_len) {
char buf[64];
// TODO(V2): Stb 重写(阶段2-4)后 code_len 为字节、instr_len 定长
compiler::disasm(cfg, base + j * 4, 4, buf, sizeof buf);
const size_t ilen = compiler::instr_len(base + pc);
compiler::disasm(cfg, base + pc, ilen, buf, sizeof buf);
std::printf(" 0x%04x %s\n",
v.offset_code() + r.code_offset + j * 4, buf);
v.offset_code() + r.code_offset + pc, buf);
pc += static_cast<uint32_t>(ilen);
}
}