12.8 切片 6:FUNCTION 与 CALL,冻结调用约定。

- 调用约定(冻结进 isa 规格与 12.8 文档):结果 r0、参数 r1..r7(最多 7 输入、函数内只读)、
  变量与临时全部从 r8 起;CALL/RET 时 VM 复制 r0..r7(12.9 实现)
- 调用点:实参求值到 r8+ 临时 → MOVE r(1+i) → CALL fn_id → MOVE rd, r0
- 函数名赋值 = 写 r0(结果);写函数输入 → codegen error
- codegen_test:134 断言(用例 13 两函数 CALL 序列;既有用例帧基址迁移 r8 起),ctest 9/9
This commit is contained in:
2026-08-21 11:48:33 +08:00
parent 31ba557627
commit 0a36e36b16
4 changed files with 213 additions and 72 deletions
+105 -54
View File
@@ -121,7 +121,7 @@ static bool test_case01() {
CHECK(v.header().project_hash != isa::kFnvBasis);
const isa::FuncRow r = v.func_row(0);
CHECK(r.nregs == 0);
CHECK(r.nregs == 8); // 帧基址(调用约定区)
CHECK(r.code_len == 1);
char buf[32];
@@ -143,16 +143,16 @@ static bool test_case02() {
CHECK(v.header().n_consts == 2); // TRUE 与 FALSE
const isa::FuncRow r = v.func_row(0);
CHECK(r.nregs == 2); // a, b
CHECK(r.nregs == 10); // a, br8 起)
CHECK(r.code_len == 3);
// 从字节码段取指令(按函数行 code_offset 定位)
const uint8_t* base = v.code_bytes();
char buf[64];
isa::disasm(reinterpret_cast<const uint32_t*>(base)[0], buf, sizeof buf);
CHECK(std::strcmp(buf, "LOADK r0, 0") == 0); // a := TRUE(常量 0
CHECK(std::strcmp(buf, "LOADK r8, 0") == 0); // a := TRUE(常量 0
isa::disasm(reinterpret_cast<const uint32_t*>(base)[1], buf, sizeof buf);
CHECK(std::strcmp(buf, "LOADK r1, 1") == 0); // b := FALSE(常量 1
CHECK(std::strcmp(buf, "LOADK r9, 1") == 0); // b := FALSE(常量 1
isa::disasm(reinterpret_cast<const uint32_t*>(base)[2], buf, sizeof buf);
CHECK(std::strcmp(buf, "RET") == 0);
@@ -179,13 +179,13 @@ static bool test_case09() {
CHECK(v.data_bytes()[1] == 0);
const isa::FuncRow r = v.func_row(0);
CHECK(r.nregs == 1); // 仅局部 x
CHECK(r.nregs == 9); // r8 起:仅局部 x
CHECK(r.code_len == 2);
char buf[64];
const uint8_t* base = v.code_bytes();
isa::disasm(reinterpret_cast<const uint32_t*>(base)[0], buf, sizeof buf);
CHECK(std::strcmp(buf, "LOAD_GLOBAL r0, 0") == 0); // x := G1(槽 0 偏移 0
CHECK(std::strcmp(buf, "LOAD_GLOBAL r8, 0") == 0); // x := G1(槽 0 偏移 0
isa::disasm(reinterpret_cast<const uint32_t*>(base)[1], buf, sizeof buf);
CHECK(std::strcmp(buf, "RET") == 0);
return true;
@@ -213,16 +213,16 @@ static bool test_io_ops() {
CHECK(v.header().n_globals == 2);
const isa::FuncRow r = v.func_row(0);
CHECK(r.nregs == 2); // q + 1 临时
CHECK(r.nregs == 10); // r8 起:q + 1 临时
char buf[64];
const uint8_t* base = v.code_bytes();
isa::disasm(reinterpret_cast<const uint32_t*>(base)[0], buf, sizeof buf);
CHECK(std::strcmp(buf, "LOAD_I r0, 0") == 0); // q := I0_0io.input → LOAD_I
CHECK(std::strcmp(buf, "LOAD_I r8, 0") == 0); // q := I0_0io.input → LOAD_I
isa::disasm(reinterpret_cast<const uint32_t*>(base)[1], buf, sizeof buf);
CHECK(std::strcmp(buf, "MOVE r1, r0") == 0); // 临时 ← q
CHECK(std::strcmp(buf, "MOVE r9, r8") == 0); // 临时 ← q
isa::disasm(reinterpret_cast<const uint32_t*>(base)[2], buf, sizeof buf);
CHECK(std::strcmp(buf, "STORE_Q r1, 1") == 0); // Q0_0 := 临时(io.output → STORE_Q
CHECK(std::strcmp(buf, "STORE_Q r9, 1") == 0); // Q0_0 := 临时(io.output → STORE_Q
isa::disasm(reinterpret_cast<const uint32_t*>(base)[3], buf, sizeof buf);
CHECK(std::strcmp(buf, "RET") == 0);
return true;
@@ -255,7 +255,7 @@ static bool test_layout() {
char buf[64];
isa::disasm(reinterpret_cast<const uint32_t*>(v.code_bytes())[0], buf, sizeof buf);
CHECK(std::strcmp(buf, "LOAD_GLOBAL r0, 2") == 0); // x := IINT 偏移 2
CHECK(std::strcmp(buf, "LOAD_GLOBAL r8, 2") == 0); // x := IINT 偏移 2
return true;
}
@@ -289,7 +289,7 @@ static bool test_case03() {
const isa::ImageView v = isa::ImageView::from(img);
CHECK(v.ok());
const isa::FuncRow r = v.func_row(0);
CHECK(r.nregs == 4); // a b x + 1 临时
CHECK(r.nregs == 12); // r8 起:a b x + 1 临时
CHECK(r.code_len == 9);
char buf[64];
@@ -297,22 +297,22 @@ static bool test_case03() {
const uint32_t* ins = reinterpret_cast<const uint32_t*>(base);
// x := a AND bMOVE r2,r0 / JF r2,+2 / MOVE r3,r1 / MOVE r2,r3
isa::disasm(ins[0], buf, sizeof buf);
CHECK(std::strcmp(buf, "MOVE r2, r0") == 0);
CHECK(std::strcmp(buf, "MOVE r10, r8") == 0);
isa::disasm(ins[1], buf, sizeof buf);
CHECK(std::strcmp(buf, "JF r2, +2") == 0);
CHECK(std::strcmp(buf, "JF r10, +2") == 0);
isa::disasm(ins[2], buf, sizeof buf);
CHECK(std::strcmp(buf, "MOVE r3, r1") == 0);
CHECK(std::strcmp(buf, "MOVE r11, r9") == 0);
isa::disasm(ins[3], buf, sizeof buf);
CHECK(std::strcmp(buf, "MOVE r2, r3") == 0);
CHECK(std::strcmp(buf, "MOVE r10, r11") == 0);
// x := a OR bMOVE r2,r0 / JT r2,+2 / MOVE r3,r1 / MOVE r2,r3
isa::disasm(ins[4], buf, sizeof buf);
CHECK(std::strcmp(buf, "MOVE r2, r0") == 0);
CHECK(std::strcmp(buf, "MOVE r10, r8") == 0);
isa::disasm(ins[5], buf, sizeof buf);
CHECK(std::strcmp(buf, "JT r2, +2") == 0);
CHECK(std::strcmp(buf, "JT r10, +2") == 0);
isa::disasm(ins[6], buf, sizeof buf);
CHECK(std::strcmp(buf, "MOVE r3, r1") == 0);
CHECK(std::strcmp(buf, "MOVE r11, r9") == 0);
isa::disasm(ins[7], buf, sizeof buf);
CHECK(std::strcmp(buf, "MOVE r2, r3") == 0);
CHECK(std::strcmp(buf, "MOVE r10, r11") == 0);
isa::disasm(ins[8], buf, sizeof buf);
CHECK(std::strcmp(buf, "RET") == 0);
return true;
@@ -332,16 +332,16 @@ static bool test_not() {
const isa::ImageView v = isa::ImageView::from(img);
CHECK(v.ok());
const isa::FuncRow r = v.func_row(0);
CHECK(r.nregs == 3); // a x + 1 临时
CHECK(r.nregs == 11); // r8 起:a x + 1 临时
CHECK(r.code_len == 3);
char buf[64];
const uint8_t* base = v.code_bytes();
const uint32_t* ins = reinterpret_cast<const uint32_t*>(base);
isa::disasm(ins[0], buf, sizeof buf);
CHECK(std::strcmp(buf, "MOVE r2, r0") == 0); // 临时 ← a
CHECK(std::strcmp(buf, "MOVE r10, r8") == 0); // 临时 ← a
isa::disasm(ins[1], buf, sizeof buf);
CHECK(std::strcmp(buf, "NOT r1, r2") == 0); // x := NOT 临时
CHECK(std::strcmp(buf, "NOT r9, r10") == 0); // x := NOT 临时
isa::disasm(ins[2], buf, sizeof buf);
CHECK(std::strcmp(buf, "RET") == 0);
return true;
@@ -357,7 +357,7 @@ static bool test_case04() {
const isa::ImageView v = isa::ImageView::from(img);
CHECK(v.ok());
const isa::FuncRow r = v.func_row(0);
CHECK(r.nregs == 5); // sel out + 3 临时CMP 目的 + 两操作数)
CHECK(r.nregs == 13); // r8 起:sel out + 3 临时
CHECK(r.code_len == 14);
char buf[64];
@@ -365,33 +365,33 @@ static bool test_case04() {
const uint32_t* ins = reinterpret_cast<const uint32_t*>(base);
// IF sel = 0 THENsel→r3、0→r4、CMP_EQ r2(常量序:0、10、1、20、30
isa::disasm(ins[0], buf, sizeof buf);
CHECK(std::strcmp(buf, "MOVE r3, r0") == 0);
CHECK(std::strcmp(buf, "MOVE r11, r8") == 0);
isa::disasm(ins[1], buf, sizeof buf);
CHECK(std::strcmp(buf, "LOADK r4, 0") == 0);
CHECK(std::strcmp(buf, "LOADK r12, 0") == 0);
isa::disasm(ins[2], buf, sizeof buf);
CHECK(std::strcmp(buf, "CMP_EQ r2, r3, r4") == 0);
CHECK(std::strcmp(buf, "CMP_EQ r10, r11, r12") == 0);
isa::disasm(ins[3], buf, sizeof buf);
CHECK(std::strcmp(buf, "JF r2, +2") == 0); // 假 → elsif[6]
CHECK(std::strcmp(buf, "JF r10, +2") == 0); // 假 → elsif[6]
isa::disasm(ins[4], buf, sizeof buf);
CHECK(std::strcmp(buf, "LOADK r1, 1") == 0); // out := 10(常量 1
CHECK(std::strcmp(buf, "LOADK r9, 1") == 0); // out := 10(常量 1
isa::disasm(ins[5], buf, sizeof buf);
CHECK(std::strcmp(buf, "JMP +7") == 0); // → end[13]
// ELSIF sel = 1
isa::disasm(ins[6], buf, sizeof buf);
CHECK(std::strcmp(buf, "MOVE r3, r0") == 0);
CHECK(std::strcmp(buf, "MOVE r11, r8") == 0);
isa::disasm(ins[7], buf, sizeof buf);
CHECK(std::strcmp(buf, "LOADK r4, 2") == 0);
CHECK(std::strcmp(buf, "LOADK r12, 2") == 0);
isa::disasm(ins[8], buf, sizeof buf);
CHECK(std::strcmp(buf, "CMP_EQ r2, r3, r4") == 0);
CHECK(std::strcmp(buf, "CMP_EQ r10, r11, r12") == 0);
isa::disasm(ins[9], buf, sizeof buf);
CHECK(std::strcmp(buf, "JF r2, +2") == 0); // 假 → else[12]
CHECK(std::strcmp(buf, "JF r10, +2") == 0); // 假 → else[12]
isa::disasm(ins[10], buf, sizeof buf);
CHECK(std::strcmp(buf, "LOADK r1, 3") == 0);
CHECK(std::strcmp(buf, "LOADK r9, 3") == 0);
isa::disasm(ins[11], buf, sizeof buf);
CHECK(std::strcmp(buf, "JMP +1") == 0); // → end[13]
// ELSE
isa::disasm(ins[12], buf, sizeof buf);
CHECK(std::strcmp(buf, "LOADK r1, 4") == 0);
CHECK(std::strcmp(buf, "LOADK r9, 4") == 0);
isa::disasm(ins[13], buf, sizeof buf);
CHECK(std::strcmp(buf, "RET") == 0);
return true;
@@ -407,30 +407,30 @@ static bool test_case05() {
const isa::ImageView v = isa::ImageView::from(img);
CHECK(v.ok());
const isa::FuncRow r = v.func_row(0);
CHECK(r.nregs == 4); // n + 3 临时(CMP 目的 + 两操作数)
CHECK(r.nregs == 12); // r8 起:n + 3 临时(条件结果 r9 + 两操作数)
CHECK(r.code_len == 10);
char buf[64];
const uint8_t* base = v.code_bytes();
const uint32_t* ins = reinterpret_cast<const uint32_t*>(base);
isa::disasm(ins[0], buf, sizeof buf);
CHECK(std::strcmp(buf, "LOADK r0, 0") == 0); // n := 0
// L_loop [1]n < 10 → r1
CHECK(std::strcmp(buf, "LOADK r8, 0") == 0); // n := 0
// L_loop [1]n < 10 → r9
isa::disasm(ins[1], buf, sizeof buf);
CHECK(std::strcmp(buf, "MOVE r2, r0") == 0);
CHECK(std::strcmp(buf, "MOVE r10, r8") == 0);
isa::disasm(ins[2], buf, sizeof buf);
CHECK(std::strcmp(buf, "LOADK r3, 1") == 0); // 常量 1 = 10
CHECK(std::strcmp(buf, "LOADK r11, 1") == 0); // 常量 1 = 10
isa::disasm(ins[3], buf, sizeof buf);
CHECK(std::strcmp(buf, "CMP_LT r1, r2, r3") == 0);
CHECK(std::strcmp(buf, "CMP_LT r9, r10, r11") == 0);
isa::disasm(ins[4], buf, sizeof buf);
CHECK(std::strcmp(buf, "JF r1, +4") == 0); // 假 → RET[9]
// n := n + 1(体语句临时复用 r1/r2
CHECK(std::strcmp(buf, "JF r9, +4") == 0); // 假 → RET[9]
// n := n + 1(体语句临时复用 r9/r10
isa::disasm(ins[5], buf, sizeof buf);
CHECK(std::strcmp(buf, "MOVE r1, r0") == 0);
CHECK(std::strcmp(buf, "MOVE r9, r8") == 0);
isa::disasm(ins[6], buf, sizeof buf);
CHECK(std::strcmp(buf, "LOADK r2, 2") == 0); // 常量 2 = 1
CHECK(std::strcmp(buf, "LOADK r10, 2") == 0); // 常量 2 = 1
isa::disasm(ins[7], buf, sizeof buf);
CHECK(std::strcmp(buf, "ADD r0, r1, r2") == 0);
CHECK(std::strcmp(buf, "ADD r8, r9, r10") == 0);
isa::disasm(ins[8], buf, sizeof buf);
CHECK(std::strcmp(buf, "JMP -8") == 0); // 回 L_loop[1]
isa::disasm(ins[9], buf, sizeof buf);
@@ -448,7 +448,7 @@ static bool test_case07() {
const isa::ImageView v = isa::ImageView::from(img);
CHECK(v.ok());
const isa::FuncRow r = v.func_row(0);
CHECK(r.nregs == 6); // a b c eq + 2 临时(语句间复用)
CHECK(r.nregs == 14); // r8 起:a b c eq + 2 临时
char buf[64];
const uint8_t* base = v.code_bytes();
@@ -456,10 +456,10 @@ static bool test_case07() {
bool saw_mul = false, saw_div = false, saw_sub = false, saw_gt = false;
for (uint32_t i = 0; i < r.code_len; ++i) {
isa::disasm(ins[i], buf, sizeof buf);
if (std::strstr(buf, "MUL r0, ")) saw_mul = true;
if (std::strstr(buf, "DIV r1, ")) saw_div = true;
if (std::strstr(buf, "SUB r2, ")) saw_sub = true;
if (std::strstr(buf, "CMP_GT r3, ")) saw_gt = true;
if (std::strstr(buf, "MUL r8, ")) saw_mul = true;
if (std::strstr(buf, "DIV r9, ")) saw_div = true;
if (std::strstr(buf, "SUB r10, ")) saw_sub = true;
if (std::strstr(buf, "CMP_GT r11, ")) saw_gt = true;
}
CHECK(saw_mul && saw_div && saw_sub && saw_gt);
return true;
@@ -481,13 +481,63 @@ static bool test_case08() {
CHECK(c1.tag == isa::types::Time && c1.value == 1250); // T#1s250ms
const isa::FuncRow r = v.func_row(0);
CHECK(r.nregs == 2);
CHECK(r.nregs == 10); // r8 起
char buf[64];
const uint32_t* ins = reinterpret_cast<const uint32_t*>(v.code_bytes());
isa::disasm(ins[0], buf, sizeof buf);
CHECK(std::strcmp(buf, "LOADK r0, 0") == 0);
CHECK(std::strcmp(buf, "LOADK r8, 0") == 0);
isa::disasm(ins[1], buf, sizeof buf);
CHECK(std::strcmp(buf, "LOADK r1, 1") == 0);
CHECK(std::strcmp(buf, "LOADK r9, 1") == 0);
return true;
}
// ---- 13. 用例 13FUNCTION + CALL(调用约定 r0 结果 / r1.. 参数)----
static bool test_case13() {
std::vector<uint8_t> img;
std::string err;
CHECK(compile_case("13_function_call", &img, &err));
const isa::ImageView v = isa::ImageView::from(img);
CHECK(v.ok());
CHECK(v.header().n_funcs == 2);
CHECK(v.header().entry_fn_id == 1); // MAIN 是第二个 POU
char buf[64];
const uint8_t* base = v.code_bytes();
// Addfn_id 0):结果 r0、输入 r1(a) r2(b)、临时 r8/r9
const isa::FuncRow fa = v.func_row(0);
CHECK(fa.nregs == 10);
CHECK(fa.code_len == 4);
const uint32_t* ia = reinterpret_cast<const uint32_t*>(base);
isa::disasm(ia[0], buf, sizeof buf);
CHECK(std::strcmp(buf, "MOVE r8, r1") == 0); // t ← a
isa::disasm(ia[1], buf, sizeof buf);
CHECK(std::strcmp(buf, "MOVE r9, r2") == 0); // t ← b
isa::disasm(ia[2], buf, sizeof buf);
CHECK(std::strcmp(buf, "ADD r0, r8, r9") == 0); // 结果 r0
isa::disasm(ia[3], buf, sizeof buf);
CHECK(std::strcmp(buf, "RET") == 0);
// MAINfn_id 1):x 在 r8,实参临时 r9/r10
const isa::FuncRow fm = v.func_row(1);
CHECK(fm.nregs == 11);
CHECK(fm.code_len == 7);
const uint32_t* im = reinterpret_cast<const uint32_t*>(base) + fm.code_offset / 4;
isa::disasm(im[0], buf, sizeof buf);
CHECK(std::strcmp(buf, "LOADK r9, 0") == 0); // 3
isa::disasm(im[1], buf, sizeof buf);
CHECK(std::strcmp(buf, "LOADK r10, 1") == 0); // 4
isa::disasm(im[2], buf, sizeof buf);
CHECK(std::strcmp(buf, "MOVE r1, r9") == 0); // 参数 1 ← 3
isa::disasm(im[3], buf, sizeof buf);
CHECK(std::strcmp(buf, "MOVE r2, r10") == 0); // 参数 2 ← 4
isa::disasm(im[4], buf, sizeof buf);
CHECK(std::strcmp(buf, "CALL 0") == 0);
isa::disasm(im[5], buf, sizeof buf);
CHECK(std::strcmp(buf, "MOVE r8, r0") == 0); // x ← 结果
isa::disasm(im[6], buf, sizeof buf);
CHECK(std::strcmp(buf, "RET") == 0);
return true;
}
@@ -504,6 +554,7 @@ int main() {
if (!test_case05()) return 1;
if (!test_case07()) return 1;
if (!test_case08()) return 1;
if (!test_case13()) return 1;
std::printf("codegen_test: %d checks passed\n", g_checks);
return 0;
}