步骤C:FB 函数化——共享体(r1 实例指针 + LOAD_PTR/STORE_PTR 基址寻址 + CALL),退役内联/fb_temp,嵌套 r1 保护

This commit is contained in:
2026-08-27 09:19:58 +08:00
parent f32a8c6aa6
commit c19e306512
3 changed files with 129 additions and 83 deletions
+4
View File
@@ -338,6 +338,10 @@ void disasm(const MachineConfig& cfg, const uint8_t* code, size_t len,
snprintf(out, cap, "%s%s r%u, s%u, %d", op->name.c_str(), suffix.c_str(), snprintf(out, cap, "%s%s r%u, s%u, %d", op->name.c_str(), suffix.c_str(),
static_cast<unsigned>(rd_of(code)), static_cast<unsigned>(slot32_of(code)), static_cast<unsigned>(rd_of(code)), static_cast<unsigned>(slot32_of(code)),
static_cast<int>(off32_hi_of(code))); static_cast<int>(off32_hi_of(code)));
} else if (f == "RS+off") {
snprintf(out, cap, "%s%s r%u, r%u, %d", op->name.c_str(), suffix.c_str(),
static_cast<unsigned>(rd_of(code)), static_cast<unsigned>(rs1_of(code)),
static_cast<int>(off32_hi_of(code)));
} else { // NONE / 预留 } else { // NONE / 预留
snprintf(out, cap, "%s", op->name.c_str()); snprintf(out, cap, "%s", op->name.c_str());
} }
+116 -80
View File
@@ -120,8 +120,9 @@ namespace {
std::vector<uint8_t> code; ///< 字节码(变长指令,字节流) std::vector<uint8_t> code; ///< 字节码(变长指令,字节流)
std::map<std::string, uint8_t> regs; ///< 变量名 → 帧寄存器 std::map<std::string, uint8_t> regs; ///< 变量名 → 帧寄存器
std::map<std::string, uint8_t> reg_func; ///< 变量名 → func(类型) std::map<std::string, uint8_t> reg_func; ///< 变量名 → func(类型)
std::map<std::string, uint8_t> fb_temp; ///< FB 内联 VAR_TEMP → 帧寄存器(当前内联层 bool is_fb = false; ///< 本函数是 FUNCTION_BLOCK(共享体,r1=实例指针
std::map<std::string, uint8_t> fb_temp_func; ///< FB 内联 VAR_TEMP → func std::map<std::string, int32_t> fb_field_off; ///< FB 类型字段名 → 偏移
std::map<std::string, uint8_t> fb_field_func; ///< 本 FB 类型字段名 → func
uint8_t nlocals = 0; ///< 变量区终点 = 临时寄存器起始 uint8_t nlocals = 0; ///< 变量区终点 = 临时寄存器起始
uint8_t nregs = 0; ///< 寄存器峰值 uint8_t nregs = 0; ///< 寄存器峰值
uint8_t temp_used = 0; ///< 本语句已用临时数 uint8_t temp_used = 0; ///< 本语句已用临时数
@@ -206,6 +207,15 @@ namespace {
set_off32_hi(f.code.data() + s, off); set_off32_hi(f.code.data() + s, off);
return s; return s;
} }
/// 基址寻址字段访问(rd, 基址寄存器rs, 偏移;16B RS+off)。
size_t E_rs_off(FuncCtx& f, const char* name, uint8_t rd, uint8_t rs,
int32_t off) {
const size_t s = emit(f, opc(name));
set_rd(f.code.data() + s, rd);
set_rs1(f.code.data() + s, rs);
set_off32_hi(f.code.data() + s, off);
return s;
}
/// 内建 FB 调用(fb_id16 + 实例槽32)。 /// 内建 FB 调用(fb_id16 + 实例槽32)。
size_t E_cal(FuncCtx& f, uint16_t fb_id, uint32_t slot) { size_t E_cal(FuncCtx& f, uint16_t fb_id, uint32_t slot) {
const size_t s = emit(f, opc("CAL")); const size_t s = emit(f, opc("CAL"));
@@ -242,6 +252,7 @@ namespace {
std::map<std::string, int32_t> field_off; ///< 字段名 → 值区内偏移 std::map<std::string, int32_t> field_off; ///< 字段名 → 值区内偏移
std::map<std::string, uint8_t> field_func; ///< 字段名 → func(类型) std::map<std::string, uint8_t> field_func; ///< 字段名 → func(类型)
uint32_t slot = 0; ///< 实例槽号(槽表条目) uint32_t slot = 0; ///< 实例槽号(槽表条目)
uint32_t addr = 0; ///< 实例基址(值区偏移,LOADK r1 用)
std::string type_name; ///< 实例的 FB 类型名 std::string type_name; ///< 实例的 FB 类型名
}; };
@@ -295,10 +306,68 @@ namespace {
} }
} }
/// FB 类型字段偏移(类型级,对齐规则与 layout_slots_values 一致)。
void fb_type_field_off(const FbLayout& lay,
std::map<std::string, int32_t>* off,
std::map<std::string, uint8_t>* func) {
int32_t cur = 0;
for (const FbField& fd : lay.fields) {
const TypeMeta tm = type_meta(cfg_, fd.type_name);
cur = static_cast<int32_t>(align_up(static_cast<uint32_t>(cur), tm.width()));
(*off)[fd.name] = cur;
(*func)[fd.name] = static_cast<uint8_t>(tm.func());
cur += static_cast<int32_t>(tm.width());
}
}
bool build_function(const POU& pou, FuncCtx* f) { bool build_function(const POU& pou, FuncCtx* f) {
if (pou.kind == PouKind::FunctionBlock) { if (pou.kind == PouKind::FunctionBlock) {
// FB 共享体:编译为独立函数,r1 = 实例指针(值区地址,约定)
// 字段(输入/输出/内部 VAR)在实例存储 → LOAD_PTR/STORE_PTR r1+off
// 局部寄存器 = VAR_TEMP + 表达式临时(r8 起),帧每周期重建 → 天然重置
f->is_fb = true;
f->nlocals = 8; f->nlocals = 8;
f->nregs = 8; f->nregs = 8;
const auto fl = link_.fb_types.find(pou.name);
if (fl == link_.fb_types.end()) {
return fail("no FB type layout for '" + pou.name + "'");
}
fb_type_field_off(fl->second, &f->fb_field_off, &f->fb_field_func);
uint8_t r = 8;
for (const VarBlock& b : pou.blocks) {
if (b.section != VarSection::Temp) {
continue;
}
for (const VarDecl& d : b.vars) {
if (d.type.kind != TypeKind::Scalar) {
continue;
}
f->regs[d.name] = r;
f->reg_func[d.name] = func_of_name(type_name_of_var(pou, d.name));
++r;
}
}
f->nlocals = r;
f->nregs = r;
if (map_ != nullptr) {
std::map<std::string, std::string> vars;
for (const auto& kv : f->regs) {
std::string tn = "int";
const auto tf = f->reg_func.find(kv.first);
if (tf != f->reg_func.end()) {
tn = std::to_string(tf->second);
}
vars[kv.first] = "r" + std::to_string(kv.second) + " (func " + tn + ")";
}
map_->funcs.emplace_back(f->name, vars);
}
emit_temp_init(*f, pou, f->regs, f->reg_func);
for (const Stmt& st : pou.body) {
begin_stmt(*f);
if (!compile_stmt(*f, st)) {
return false;
}
}
E_ret(*f); E_ret(*f);
return true; return true;
} }
@@ -373,38 +442,24 @@ namespace {
if (st.kind != StmtKind::Assign) { if (st.kind != StmtKind::Assign) {
return fail("statement not supported"); return fail("statement not supported");
} }
if (inline_fields_) { if (f.is_fb) {
const auto fit = inline_fields_->field_off.find(st.target); // FB 共享体:本实例字段(裸名)→ STORE_PTR r1+off
if (fit != inline_fields_->field_off.end()) { const auto fit = f.fb_field_off.find(st.target);
if (fit != f.fb_field_off.end()) {
const uint8_t t = alloc_temp(f); const uint8_t t = alloc_temp(f);
const auto ff_ = inline_fields_->field_func.find(st.target); const auto ff_ = f.fb_field_func.find(st.target);
if (!compile_expr(f, *st.value, t, if (!compile_expr(f, *st.value, t,
ff_ != inline_fields_->field_func.end() ff_ != f.fb_field_func.end() ? ff_->second : 0)) {
? ff_->second
: 0)) {
return false; return false;
} }
const size_t so = E_slot_off(f, "STORE_OFF", t, inline_fields_->slot, const size_t so = E_rs_off(f, "STORE_PTR", t, 1, fit->second);
fit->second); const auto ff = f.fb_field_func.find(st.target);
const auto ff = inline_fields_->field_func.find(st.target); if (ff != f.fb_field_func.end()) {
if (ff != inline_fields_->field_func.end()) {
set_func(f.code.data() + so, ff->second); set_func(f.code.data() + so, ff->second);
} }
return true; return true;
} }
} }
const auto tit = f.fb_temp.find(st.target);
if (tit != f.fb_temp.end()) {
const uint8_t t = alloc_temp(f);
const uint8_t tf_ = f.fb_temp_func.count(st.target)
? f.fb_temp_func.at(st.target)
: func_of_name("INT");
if (!compile_expr(f, *st.value, t, tf_)) {
return false;
}
E_rr(f, "MOVE", tit->second, t);
return true;
}
const auto it = f.regs.find(st.target); const auto it = f.regs.find(st.target);
if (it == f.regs.end()) { if (it == f.regs.end()) {
return store_target(f, st.target, *st.value); return store_target(f, st.target, *st.value);
@@ -449,7 +504,25 @@ namespace {
if (user_fb == nullptr) { if (user_fb == nullptr) {
return fail("no FB type '" + inst->type_name + "'"); return fail("no FB type '" + inst->type_name + "'");
} }
return compile_fb_inline(f, *user_fb, *inst); // 用户 FB → CALL 共享体:r1 = 实例指针(值区地址)→ CALL
const int fb_fn = find_fn_id(user_fb->name);
if (fb_fn < 0) {
return fail("no fn_id for '" + user_fb->name + "'");
}
f.calls.push_back(static_cast<uint32_t>(fb_fn));
uint8_t save_r = 0;
if (f.is_fb) {
// 嵌套(FB 函数体内再调 FB):保存本层 r1,调用后恢复
save_r = alloc_temp(f);
E_rr(f, "MOVE", save_r, 1);
}
const size_t lk = E_imm(f, "LOADK", 1, const_id(inst->addr));
set_func(f.code.data() + lk, func_of_name("UDINT"));
E_call(f, static_cast<uint32_t>(fb_fn));
if (f.is_fb) {
E_rr(f, "MOVE", 1, save_r);
}
return true;
} }
static std::string uppercase_of(const std::string& s) { static std::string uppercase_of(const std::string& s) {
@@ -460,43 +533,6 @@ namespace {
return out; return out;
} }
bool compile_fb_inline(FuncCtx& f, const POU& fb, const InstFields& inst) {
const InstFields* saved = inline_fields_;
inline_fields_ = &inst;
// VAR_TEMP:本调用点分配独立固定寄存器(MAIN 帧,nregs 之后),
// 内联体开头装载初值 → 每次调用重新初始化;嵌套内联 save/restore
const std::map<std::string, uint8_t> saved_temp = f.fb_temp;
const std::map<std::string, uint8_t> saved_temp_func = f.fb_temp_func;
f.fb_temp.clear();
f.fb_temp_func.clear();
for (const VarBlock& b : fb.blocks) {
if (b.section != VarSection::Temp) {
continue;
}
for (const VarDecl& d : b.vars) {
if (d.type.kind != TypeKind::Scalar) {
continue;
}
const uint8_t r = f.nregs++;
f.fb_temp[d.name] = r;
f.fb_temp_func[d.name] = func_of_name(type_name_of_var(fb, d.name));
}
}
// 临时寄存器起点提到 Temp 区之上,避免语句内 alloc_temp 撞上 Temp 寄存器
f.nlocals = f.nregs;
emit_temp_init(f, fb, f.fb_temp, f.fb_temp_func);
for (const Stmt& s : fb.body) {
begin_stmt(f);
if (!compile_stmt(f, s)) {
return false;
}
}
f.fb_temp = saved_temp;
f.fb_temp_func = saved_temp_func;
inline_fields_ = saved;
return true;
}
bool compile_while(FuncCtx& f, const Stmt& st) { bool compile_while(FuncCtx& f, const Stmt& st) {
const size_t loop = f.code.size(); const size_t loop = f.code.size();
const uint8_t t = alloc_temp(f); const uint8_t t = alloc_temp(f);
@@ -609,27 +645,18 @@ namespace {
return true; return true;
} }
if (e.kind == ExprKind::VarRef) { if (e.kind == ExprKind::VarRef) {
if (inline_fields_) { if (f.is_fb) {
const auto fit = inline_fields_->field_off.find(e.name); // FB 共享体:本实例字段(裸名)→ LOAD_PTR r1+off
if (fit != inline_fields_->field_off.end()) { const auto fit = f.fb_field_off.find(e.name);
const size_t lo = E_slot_off(f, "LOAD_OFF", rd, if (fit != f.fb_field_off.end()) {
inline_fields_->slot, fit->second); const size_t lo = E_rs_off(f, "LOAD_PTR", rd, 1, fit->second);
const auto ff = inline_fields_->field_func.find(e.name); const auto ff = f.fb_field_func.find(e.name);
if (ff != inline_fields_->field_func.end()) { if (ff != f.fb_field_func.end()) {
set_func(f.code.data() + lo, ff->second); set_func(f.code.data() + lo, ff->second);
} }
return true; return true;
} }
} }
const auto tit = f.fb_temp.find(e.name);
if (tit != f.fb_temp.end()) {
const size_t s = E_rr(f, "MOVE", rd, tit->second);
const auto tf = f.fb_temp_func.find(e.name);
set_func(f.code.data() + s,
tf != f.fb_temp_func.end() ? tf->second
: func_of_name("INT"));
return true;
}
const auto sit = f.regs.find(e.name); const auto sit = f.regs.find(e.name);
if (sit != f.regs.end()) { if (sit != f.regs.end()) {
const size_t s = E_rr(f, "MOVE", rd, sit->second); const size_t s = E_rr(f, "MOVE", rd, sit->second);
@@ -736,11 +763,20 @@ namespace {
if (fn_id < 0) { if (fn_id < 0) {
return fail("no fn_id for '" + e.name + "'"); return fail("no fn_id for '" + e.name + "'");
} }
uint8_t save_r = 0;
if (f.is_fb) {
// FB 函数内调 FUNCTION:实参区 r1..r7 会覆盖 r1(实例指针)→ 保存恢复
save_r = alloc_temp(f);
E_rr(f, "MOVE", save_r, 1);
}
for (size_t i = 0; i < args.size(); ++i) { for (size_t i = 0; i < args.size(); ++i) {
E_rr(f, "MOVE", static_cast<uint8_t>(1 + i), args[i]); E_rr(f, "MOVE", static_cast<uint8_t>(1 + i), args[i]);
} }
f.calls.push_back(static_cast<uint32_t>(fn_id)); f.calls.push_back(static_cast<uint32_t>(fn_id));
E_call(f, static_cast<uint32_t>(fn_id)); E_call(f, static_cast<uint32_t>(fn_id));
if (f.is_fb) {
E_rr(f, "MOVE", 1, save_r);
}
E_rr(f, "MOVE", rd, 0); E_rr(f, "MOVE", rd, 0);
return true; return true;
} }
@@ -896,6 +932,7 @@ namespace {
max_align = max_align > tm.width() ? max_align : tm.width(); max_align = max_align > tm.width() ? max_align : tm.width();
} }
cur_addr = align_up(cur_addr, max_align); cur_addr = align_up(cur_addr, max_align);
inst.addr = cur_addr;
slots_.push_back(cur_addr); slots_.push_back(cur_addr);
values_.resize(cur_addr + static_cast<uint32_t>(off), 0); values_.resize(cur_addr + static_cast<uint32_t>(off), 0);
instances_[sc.name + "/" + s.name] = inst; instances_[sc.name + "/" + s.name] = inst;
@@ -1153,7 +1190,6 @@ namespace {
std::vector<uint8_t> values_; ///< 值段字节 std::vector<uint8_t> values_; ///< 值段字节
std::map<std::string, uint32_t> global_slot_; ///< 全局名 → 槽号 std::map<std::string, uint32_t> global_slot_; ///< 全局名 → 槽号
std::map<std::string, InstFields> instances_; ///< "POU名/实例名" → 实例布局 std::map<std::string, InstFields> instances_; ///< "POU名/实例名" → 实例布局
const InstFields* inline_fields_ = nullptr; ///< 内联 FB 字段表
uint32_t max_stack_ = 0; ///< 栈区字节数 uint32_t max_stack_ = 0; ///< 栈区字节数
CodegenMap* map_ = nullptr; ///< 变量/槽映射输出(可空) CodegenMap* map_ = nullptr; ///< 变量/槽映射输出(可空)
}; };
+9 -3
View File
@@ -237,14 +237,20 @@ static bool test_line1() {
CHECK(v.n_globals() == 4); // EmergencyStop/I0_0/I0_1/Q0_0 CHECK(v.n_globals() == 4); // EmergencyStop/I0_0/I0_1/Q0_0
CHECK(v.n_slots() == 5); // 4 全局 + 1 实例(字段走偏移,实例占 1 条) CHECK(v.n_slots() == 5); // 4 全局 + 1 实例(字段走偏移,实例占 1 条)
CHECK(v.values_size() == 7); // 全局 4×1B + starter 3×1B CHECK(v.values_size() == 7); // 全局 4×1B + starter 3×1B
CHECK(v.max_stack() >= 12 + 13 * 8); CHECK(v.max_stack() >= (12 + 13 * 8) + (12 + 10 * 8)); // fn0 共享体 13 + MAIN 10
// 指令序列LOADI 读)、STORE_OFFFB 输入写)、LOAD_OFFFB 输出读)、STOREQ 写) // MAINfn 1LOADI 读)、STORE_OFF实参写)、LOADK r1 + CALL(共享体)、LOAD_OFF(输出读)、STOREQ 写)
const std::vector<std::string> lines = disasm_lines(cfg_global(), v, 1); const std::vector<std::string> lines = disasm_lines(cfg_global(), v, 1);
CHECK(has_line(lines, "LOAD.U8")); CHECK(has_line(lines, "LOAD.U8"));
CHECK(has_line(lines, "STORE_OFF.U8")); CHECK(has_line(lines, "STORE_OFF.U8"));
CHECK(has_line(lines, "LOAD_OFF.U8")); CHECK(has_line(lines, "LOAD_OFF.U8"));
CHECK(has_line(lines, "STORE.U8")); CHECK(has_line(lines, "STORE.U8"));
CHECK(has_line(lines, "JF r")); CHECK(has_line(lines, "LOADK.U32 r1"));
CHECK(has_line(lines, "CALL 0"));
// MotorStarter 共享体(fn 0):LOAD_PTR/STORE_PTR + 短路 JF
const std::vector<std::string> fb = disasm_lines(cfg_global(), v, 0);
CHECK(has_line(fb, "LOAD_PTR.U8"));
CHECK(has_line(fb, "STORE_PTR.U8"));
CHECK(has_line(fb, "JF r"));
return true; return true;
} }