Files
Viper_RegressionTesting/MLIRLiteTest/App/main.vp
T
TermiNexus ee6461be46 chore(comments): Test 仓注释英文化(R11)
把 81 个 .vp 文件的中文 # 注释与三引号文档串改写为简洁英文,每个连续注释块 <=2 行;运行时中文字符串字面量(testcheck.begin/print 等用户可见消息)保持原样。骨架比对 HEAD 与工作区 112 文件漂移 0,全量 77/77 顺序回归通过。
2026-10-05 22:43:38 +08:00

1388 lines
67 KiB
Plaintext
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
from stdint import *
import stdio
import string
import stdlib
import w32.fileio as fileio
import memhub
import testcheck
import viperlib
import mlirlite
define POOL_SIZE = 83886080
define SUB_POOL_SIZE = 2097136
_DUMP_SEQ: int = 0
def _dump_is_module(text: str) -> int:
if text is None: return 0
p: str = text
while p[0] != '\0':
ch: char = p[0]
if ch == ' ' or ch == '\t' or ch == '\n' or ch == '\r':
p = p + 1
continue
if ch == '/' and p[1] == '/':
while p[0] != '\0' and p[0] != '\n':
p = p + 1
continue
break
if p[0] == '\0': return 0
if string.strncmp(p, "module", 6) == 0: return 1
return 0
def dump_mlir(pool: memhub.MemBuddy*, name: str, buf: str):
global _DUMP_SEQ
_DUMP_SEQ += 1
path: str = pool.alloc(256)
if path is None:
stdio.printf("[mlir] WARN: alloc path failed\n")
return
if name is None:
viperlib.snprintf(path, 256, "Test/MLIRLiteTest/output/auto_%02d.mlir", _DUMP_SEQ)
else:
viperlib.snprintf(path, 256, "Test/MLIRLiteTest/output/%s", name)
if _dump_is_module(buf) == 0:
cut: sizet = string.strlen(path)
d2: sizet = cut
while d2 > 0:
d2 -= 1
if path[d2] == '.':
path[d2] = '\0'
break
ext_txt: str = pool.alloc(8)
if ext_txt is not None:
string.strcpy(ext_txt, ".txt")
tmp_path: str = pool.alloc(256)
if tmp_path is not None:
viperlib.snprintf(tmp_path, 256, "%s%s", path, ext_txt)
string.strcpy(path, tmp_path)
f: fileio.File = fileio.File(path, fileio.MODE.W)
if f.closed:
stdio.printf("[mlir] WARN: open failed: %s\n", path)
return
hdr: str = pool.alloc(128)
if hdr is not None:
viperlib.snprintf(hdr, 128, "// dumped by MLIRLiteTest #%d\n", _DUMP_SEQ)
f.write(hdr, string.strlen(hdr))
f.write(buf, string.strlen(buf))
f.close()
stdio.printf(" [mlir] wrote %s (%d bytes)\n", path, int(string.strlen(buf)))
# Test 1: TypePrint - MLIR LLVM dialect type printing
def test_type_print(pool: memhub.MemBuddy*):
testcheck.section("Test 1: TypePrint (MLIR types)")
core: mlirlite.LLVMTypeCore* = mlirlite.LLVMTypeCore(pool)
buf: str = pool.alloc(256)
# i32
ty_i32: mlirlite.LLVMType* = core.Int32()
buf[0] = 0
core.PrintType(buf, 256, ty_i32)
testcheck.check(string.strcmp(buf, "i32") == 0,
"Int32 -> i32",
"Int32 fail")
# Opaque pointer: Ptr(Int32) -> !llvm.ptr
ty_ptr: mlirlite.LLVMType* = core.Ptr(ty_i32)
buf[0] = 0
core.PrintType(buf, 256, ty_ptr)
testcheck.check(string.strcmp(buf, "!llvm.ptr") == 0,
"Ptr(Int32) -> !llvm.ptr",
"Ptr fail")
# Void -> none
ty_void: mlirlite.LLVMType* = core.Void()
buf[0] = 0
core.PrintType(buf, 256, ty_void)
testcheck.check(string.strcmp(buf, "none") == 0,
"Void -> none",
"Void fail")
# [4 x i32] -> !llvm.array<4 x i32>
ty_arr: mlirlite.LLVMType* = core.Array(ty_i32, 4)
buf[0] = 0
core.PrintType(buf, 256, ty_arr)
testcheck.check(string.strcmp(buf, "!llvm.array<4 x i32>") == 0,
"Array(i32,4) -> !llvm.array<4 x i32>",
"Array fail")
# [2 x [3 x i8]] -> !llvm.array<2 x !llvm.array<3 x i8>>
ty_i8: mlirlite.LLVMType* = core.Int8()
ty_inner: mlirlite.LLVMType* = core.Array(ty_i8, 3)
ty_nested: mlirlite.LLVMType* = core.Array(ty_inner, 2)
buf[0] = 0
core.PrintType(buf, 256, ty_nested)
testcheck.check(string.strcmp(buf, "!llvm.array<2 x !llvm.array<3 x i8>>") == 0,
"nested array -> !llvm.array<2 x !llvm.array<3 x i8>>",
"nested array fail")
# {i32, i8*} -> !llvm.struct<(i32, !llvm.ptr)>
ty_i8ptr: mlirlite.LLVMType* = core.Ptr(ty_i8)
n1: mlirlite.ParamNode* = core.NewParamNode(ty_i32)
n2: mlirlite.ParamNode* = core.NewParamNode(ty_i8ptr)
head: mlirlite.ParamNode* = core.ParamListAppend(None, None, n1)
core.ParamListAppend(head, n1, n2)
ty_struct: mlirlite.LLVMType* = core.Struct(head, 2)
buf[0] = 0
core.PrintType(buf, 256, ty_struct)
testcheck.check(string.strcmp(buf, "!llvm.struct<(i32, !llvm.ptr)>") == 0,
"struct {i32, i8*} -> !llvm.struct<(i32, !llvm.ptr)>",
"struct fail")
# Empty struct -> !llvm.struct<()>
ty_empty: mlirlite.LLVMType* = core.Struct(None, 0)
buf[0] = 0
core.PrintType(buf, 256, ty_empty)
testcheck.check(string.strcmp(buf, "!llvm.struct<()>") == 0,
"empty struct -> !llvm.struct<()>",
"empty struct fail")
# Function type -> !llvm.func<i32 (i32, !llvm.ptr)>
fn1: mlirlite.ParamNode* = core.NewParamNode(ty_i32)
fn2: mlirlite.ParamNode* = core.NewParamNode(ty_i8ptr)
fhead: mlirlite.ParamNode* = core.ParamListAppend(None, None, fn1)
core.ParamListAppend(fhead, fn1, fn2)
ty_func: mlirlite.LLVMType* = core.Func(ty_i32, fhead, 2)
buf[0] = 0
core.PrintType(buf, 256, ty_func)
dump_mlir(pool, "T01_types.mlir", buf)
# Embed the actual value in the failure message so the FAIL line shows the
# real form directly, avoiding guesswork from a bare "fail"
ft_msg: str = pool.alloc(512)
if ft_msg is not None:
viperlib.snprintf(ft_msg, 512,
"func type fail: actual='%s' expected='!llvm.func<i32 (i32, !llvm.ptr)>'",
buf)
testcheck.check(string.strcmp(buf, "!llvm.func<i32 (i32, !llvm.ptr)>") == 0,
"func type -> !llvm.func<i32 (i32, !llvm.ptr)>",
ft_msg)
# Test 2: ValuePrint - value printing (diagnostics only)
def test_value_print(pool: memhub.MemBuddy*):
testcheck.section("Test 2: ValuePrint (MLIR)")
core: mlirlite.LLVMTypeCore* = mlirlite.LLVMTypeCore(pool)
mcore: mlirlite.LLVMModuleCore* = mlirlite.LLVMModuleCore(pool)
buf: str = pool.alloc(128)
ty_i32: mlirlite.LLVMType* = core.Int32()
# Constant 42 -> "42 : i32"
val42: mlirlite.Value* = mcore.ConstInt32(42)
buf[0] = 0
mcore.PrintValue(buf, 128, val42)
testcheck.check(string.strcmp(buf, "42 : i32") == 0,
"ConstInt(42) -> '42 : i32'",
"ConstInt fail")
# SSA value -> "%0" (MLIR operands carry no type)
val_ssa: mlirlite.Value* = mcore.SSAValue(ty_i32, "%0")
buf[0] = 0
mcore.PrintValue(buf, 128, val_ssa)
dump_mlir(pool, "T02_value.mlir", buf)
testcheck.check(string.strcmp(buf, "%0") == 0,
"SSAValue(%0) -> '%0'",
"SSAValue fail")
# Test 3: build add function (llvm.func @add + llvm.add + llvm.return)
def test_build_add(pool: memhub.MemBuddy*):
testcheck.section("Test 3: build_add function")
core: mlirlite.LLVMTypeCore* = mlirlite.LLVMTypeCore(pool)
mcore: mlirlite.LLVMModuleCore* = mlirlite.LLVMModuleCore(pool)
ty_i32: mlirlite.LLVMType* = core.Int32()
mod: mlirlite.LLVMModule* = mcore.NewModule("test_add")
func: mlirlite.Function* = mcore.CreateFunction(mod, "add", ty_i32)
mcore.AddParam(func, ty_i32, "%a")
mcore.AddParam(func, ty_i32, "%b")
entry: mlirlite.BasicBlock* = mcore.CreateBlock(func, "entry")
builder: mlirlite.IRBuilder* = mcore.NewBuilder(func)
mlirlite.position_at_end(builder, entry)
v_a: mlirlite.Value* = mcore.SSAValue(ty_i32, "%a")
v_b: mlirlite.Value* = mcore.SSAValue(ty_i32, "%b")
v_c: mlirlite.Value* = mlirlite.build_add(builder, v_a, v_b)
mlirlite.build_ret(builder, v_c)
buf: str = pool.alloc(4096)
buf[0] = 0
mcore.PrintFunction(buf, 4096, func)
dump_mlir(pool, None, buf)
testcheck.info(buf)
dump_mlir(pool, "T03_add.mlir", buf)
testcheck.check(string.strstr(buf, "llvm.func @add(%a: i32, %b: i32) -> i32") is not None,
"contains 'llvm.func @add(%a: i32, %b: i32) -> i32'",
"missing MLIR function signature")
testcheck.check(string.strstr(buf, "llvm.add %a, %b : i32") is not None,
"contains 'llvm.add %a, %b : i32'",
"missing 'llvm.add'")
testcheck.check(string.strstr(buf, "llvm.return") is not None,
"contains 'llvm.return'",
"missing 'llvm.return'")
testcheck.check(string.strstr(buf, "entry:") is None,
"entry 块不带标签",
"entry block should not be labelled")
# Test 4: build if-then-else (max)
def test_build_if_else(pool: memhub.MemBuddy*):
testcheck.section("Test 4: build if-then-else (max)")
core: mlirlite.LLVMTypeCore* = mlirlite.LLVMTypeCore(pool)
mcore: mlirlite.LLVMModuleCore* = mlirlite.LLVMModuleCore(pool)
ty_i32: mlirlite.LLVMType* = core.Int32()
mod: mlirlite.LLVMModule* = mcore.NewModule("test_max")
func: mlirlite.Function* = mcore.CreateFunction(mod, "max", ty_i32)
mcore.AddParam(func, ty_i32, "%a")
mcore.AddParam(func, ty_i32, "%b")
entry: mlirlite.BasicBlock* = mcore.CreateBlock(func, "entry")
then_blk: mlirlite.BasicBlock* = mcore.CreateBlock(func, "then")
else_blk: mlirlite.BasicBlock* = mcore.CreateBlock(func, "else")
builder: mlirlite.IRBuilder* = mcore.NewBuilder(func)
mlirlite.position_at_end(builder, entry)
v_a: mlirlite.Value* = mcore.SSAValue(ty_i32, "%a")
v_b: mlirlite.Value* = mcore.SSAValue(ty_i32, "%b")
v_cond: mlirlite.Value* = mlirlite.build_icmp(builder, mlirlite.ICMP_SGT, v_a, v_b)
mlirlite.build_cond_br(builder, v_cond, then_blk, else_blk)
mlirlite.position_at_end(builder, then_blk)
mlirlite.build_ret(builder, v_a)
mlirlite.position_at_end(builder, else_blk)
mlirlite.build_ret(builder, v_b)
buf: str = pool.alloc(4096)
buf[0] = 0
mcore.PrintFunction(buf, 4096, func)
dump_mlir(pool, None, buf)
testcheck.info(buf)
dump_mlir(pool, "T04_ifelse.mlir", buf)
testcheck.check(string.strstr(buf, "llvm.icmp \"sgt\"") is not None,
"contains 'llvm.icmp \"sgt\"'",
"missing 'llvm.icmp \"sgt\"'")
testcheck.check(string.strstr(buf, "llvm.cond_br") is not None,
"contains 'llvm.cond_br'",
"missing 'llvm.cond_br'")
testcheck.check(string.strstr(buf, "^then:") is not None,
"contains '^then:'",
"missing block label '^then:'")
testcheck.check(string.strstr(buf, "^else:") is not None,
"contains '^else:'",
"missing block label '^else:'")
# Test 5: void function
def test_build_void(pool: memhub.MemBuddy*):
testcheck.section("Test 5: void function")
core: mlirlite.LLVMTypeCore* = mlirlite.LLVMTypeCore(pool)
mcore: mlirlite.LLVMModuleCore* = mlirlite.LLVMModuleCore(pool)
ty_void: mlirlite.LLVMType* = core.Void()
mod: mlirlite.LLVMModule* = mcore.NewModule("test_void")
func: mlirlite.Function* = mcore.CreateFunction(mod, "noop", ty_void)
entry: mlirlite.BasicBlock* = mcore.CreateBlock(func, "entry")
builder: mlirlite.IRBuilder* = mcore.NewBuilder(func)
mlirlite.position_at_end(builder, entry)
mlirlite.build_ret_void(builder)
buf: str = pool.alloc(4096)
buf[0] = 0
mcore.PrintFunction(buf, 4096, func)
dump_mlir(pool, None, buf)
testcheck.info(buf)
dump_mlir(pool, "T05_void.mlir", buf)
testcheck.check(string.strstr(buf, "llvm.func @noop() {") is not None,
"contains 'llvm.func @noop() {'(void 返回省略 -> ty)",
"missing void function signature")
testcheck.check(string.strstr(buf, "llvm.return") is not None,
"contains 'llvm.return'",
"missing 'llvm.return'")
# Test 6: module printing (module / declare vs define)
def test_module_print(pool: memhub.MemBuddy*):
testcheck.section("Test 6: ModulePrint")
core: mlirlite.LLVMTypeCore* = mlirlite.LLVMTypeCore(pool)
mcore: mlirlite.LLVMModuleCore* = mlirlite.LLVMModuleCore(pool)
ty_i32: mlirlite.LLVMType* = core.Int32()
mod: mlirlite.LLVMModule* = mcore.NewModule("test_module")
mlirlite.module_set_target(mod, "x86_64-pc-windows-gnu")
mlirlite.module_set_datalayout(mod, "e-m:w-p270:32:32")
# declare: llvm.func @extern_func(%x: i32) -> i32 (no body)
func_decl: mlirlite.Function* = mcore.CreateDeclare(mod, "extern_func", ty_i32)
mcore.AddParam(func_decl, ty_i32, "%x")
# define: llvm.func @add(%a: i32, %b: i32) -> i32 { … }
func_add: mlirlite.Function* = mcore.CreateFunction(mod, "add", ty_i32)
mcore.AddParam(func_add, ty_i32, "%a")
mcore.AddParam(func_add, ty_i32, "%b")
entry1: mlirlite.BasicBlock* = mcore.CreateBlock(func_add, "entry")
builder1: mlirlite.IRBuilder* = mcore.NewBuilder(func_add)
mlirlite.position_at_end(builder1, entry1)
v_a1: mlirlite.Value* = mcore.SSAValue(ty_i32, "%a")
v_b1: mlirlite.Value* = mcore.SSAValue(ty_i32, "%b")
v_sum: mlirlite.Value* = mlirlite.build_add(builder1, v_a1, v_b1)
mlirlite.build_ret(builder1, v_sum)
buf: str = pool.alloc(65536)
buf[0] = 0
mcore.PrintModule(buf, 65536, mod)
dump_mlir(pool, None, buf)
testcheck.info(buf)
dump_mlir(pool, "T06_module.mlir", buf)
testcheck.check(string.strstr(buf, "module {") is not None,
"contains 'module {'",
"missing 'module {'")
testcheck.check(string.strstr(buf, "llvm.func @add") is not None,
"contains 'llvm.func @add'",
"missing add function")
testcheck.check(string.strstr(buf, "llvm.func @extern_func(%x: i32) -> i32") is not None,
"declare 形态 'llvm.func @extern_func(%x: i32) -> i32'",
"missing declare")
testcheck.check(string.strstr(buf, "llvm.func @extern_func(%x: i32) -> i32 {") is None,
"declare 无函数体(不出现 '{')",
"declare should not have a body")
testcheck.check(string.strstr(buf, "llvm.func @add(%a: i32, %b: i32) -> i32 {") is not None,
"define 形态带函数体",
"missing define body")
# Test 7: constant materialization (operand 42 -> llvm.mlir.constant)
def test_const_materialize(pool: memhub.MemBuddy*):
testcheck.section("Test 7: constant materialization")
core: mlirlite.LLVMTypeCore* = mlirlite.LLVMTypeCore(pool)
mcore: mlirlite.LLVMModuleCore* = mlirlite.LLVMModuleCore(pool)
ty_i32: mlirlite.LLVMType* = core.Int32()
mod: mlirlite.LLVMModule* = mcore.NewModule("test_const")
func: mlirlite.Function* = mcore.CreateFunction(mod, "const_test", ty_i32)
mcore.AddParam(func, ty_i32, "%a")
entry: mlirlite.BasicBlock* = mcore.CreateBlock(func, "entry")
builder: mlirlite.IRBuilder* = mcore.NewBuilder(func)
mlirlite.position_at_end(builder, entry)
v_a: mlirlite.Value* = mcore.SSAValue(ty_i32, "%a")
v_42: mlirlite.Value* = mcore.ConstInt32(42)
v_sum: mlirlite.Value* = mlirlite.build_add(builder, v_a, v_42)
mlirlite.build_ret(builder, v_sum)
buf: str = pool.alloc(4096)
buf[0] = 0
mcore.PrintFunction(buf, 4096, func)
dump_mlir(pool, None, buf)
testcheck.info(buf)
dump_mlir(pool, "T07_consts.mlir", buf)
testcheck.check(string.strstr(buf, "llvm.mlir.constant(42 : i32) : i32") is not None,
"contains 'llvm.mlir.constant(42 : i32) : i32'",
"constant not materialized")
testcheck.check(string.strstr(buf, "llvm.add %a, %c0 : i32") is not None,
"add 行引用物化后的 SSA 名 '%c0'",
"add line does not reference materialized constant")
# Same (type, text) constant materializes once: both add operands are 42
func2: mlirlite.Function* = mcore.CreateFunction(mod, "const_twice", ty_i32)
entry2: mlirlite.BasicBlock* = mcore.CreateBlock(func2, "entry")
builder2: mlirlite.IRBuilder* = mcore.NewBuilder(func2)
mlirlite.position_at_end(builder2, entry2)
v_42b: mlirlite.Value* = mcore.ConstInt32(42)
v_42c: mlirlite.Value* = mcore.ConstInt32(42)
v_sum2: mlirlite.Value* = mlirlite.build_add(builder2, v_42b, v_42c)
mlirlite.build_ret(builder2, v_sum2)
buf[0] = 0
mcore.PrintFunction(buf, 4096, func2)
testcheck.check(string.strstr(buf, "llvm.add %c0, %c0 : i32") is not None,
"相同 (类型,文本) 常量只物化一次(llvm.add %c0, %c0)",
"constant dedup failed")
# Test 8: phi -> block arguments
def test_phi_block_args(pool: memhub.MemBuddy*):
testcheck.section("Test 8: phi -> block arguments")
core: mlirlite.LLVMTypeCore* = mlirlite.LLVMTypeCore(pool)
mcore: mlirlite.LLVMModuleCore* = mlirlite.LLVMModuleCore(pool)
ty_i32: mlirlite.LLVMType* = core.Int32()
mod: mlirlite.LLVMModule* = mcore.NewModule("test_merge")
func: mlirlite.Function* = mcore.CreateFunction(mod, "merge_test", ty_i32)
entry: mlirlite.BasicBlock* = mcore.CreateBlock(func, "entry")
then_blk: mlirlite.BasicBlock* = mcore.CreateBlock(func, "then")
else_blk: mlirlite.BasicBlock* = mcore.CreateBlock(func, "else")
merge: mlirlite.BasicBlock* = mcore.CreateBlock(func, "merge")
builder: mlirlite.IRBuilder* = mcore.NewBuilder(func)
# entry: br label %then
mlirlite.position_at_end(builder, entry)
mlirlite.build_br(builder, then_blk)
# then: br label %merge
mlirlite.position_at_end(builder, then_blk)
v_1: mlirlite.Value* = mcore.ConstInt32(1)
mlirlite.build_br(builder, merge)
# else: br label %merge
mlirlite.position_at_end(builder, else_blk)
v_2: mlirlite.Value* = mcore.ConstInt32(2)
mlirlite.build_br(builder, merge)
# merge: %r = phi i32 [1, %then], [2, %else]; ret i32 %r
mlirlite.position_at_end(builder, merge)
inc1: mlirlite.PhiIncoming* = mlirlite.new_phi_incoming(pool, v_1, then_blk)
inc2: mlirlite.PhiIncoming* = mlirlite.new_phi_incoming(pool, v_2, else_blk)
inc1.Next = inc2
v_r: mlirlite.Value* = mlirlite.build_phi(builder, ty_i32, inc1, 2)
mlirlite.build_ret(builder, v_r)
buf: str = pool.alloc(4096)
buf[0] = 0
mcore.PrintFunction(buf, 4096, func)
dump_mlir(pool, None, buf)
testcheck.info(buf)
dump_mlir(pool, "T08_phi.mlir", buf)
testcheck.check(string.strstr(buf, "^merge(%") is not None,
"块参数形态 '^merge(%'",
"missing block arguments")
testcheck.check(string.strstr(buf, "llvm.br ^merge(%") is not None,
"跳转实参形态 'llvm.br ^merge(%'",
"missing branch block operands")
testcheck.check(string.strstr(buf, " = phi ") is None,
"phi 行不再输出",
"phi line should not be emitted")
# Test 9: memory / call / cast
def test_mem_call_cast(pool: memhub.MemBuddy*):
testcheck.section("Test 9: memory / call / cast")
core: mlirlite.LLVMTypeCore* = mlirlite.LLVMTypeCore(pool)
mcore: mlirlite.LLVMModuleCore* = mlirlite.LLVMModuleCore(pool)
ty_i32: mlirlite.LLVMType* = core.Int32()
ty_i64: mlirlite.LLVMType* = core.Int64()
ty_i8: mlirlite.LLVMType* = core.Int8()
ty_i8ptr: mlirlite.LLVMType* = core.Ptr(ty_i8)
mod: mlirlite.LLVMModule* = mcore.NewModule("test_mem")
func: mlirlite.Function* = mcore.CreateFunction(mod, "mem_test", ty_i32)
mcore.AddParam(func, ty_i8ptr, "%s")
mcore.AddParam(func, ty_i32, "%n")
entry: mlirlite.BasicBlock* = mcore.CreateBlock(func, "entry")
builder: mlirlite.IRBuilder* = mcore.NewBuilder(func)
mlirlite.position_at_end(builder, entry)
v_s: mlirlite.Value* = mcore.SSAValue(ty_i8ptr, "%s")
v_n: mlirlite.Value* = mcore.SSAValue(ty_i32, "%n")
# %0 = alloca i32 ; store i32 %n, !llvm.ptr %0 ; %1 = load i32, !llvm.ptr %0
v_slot: mlirlite.Value* = mlirlite.build_alloca(builder, ty_i32)
mlirlite.build_store(builder, v_n, v_slot, 0)
v_loaded: mlirlite.Value* = mlirlite.build_load(builder, ty_i32, v_slot, 0)
# %2 = getelementptr i8, !llvm.ptr %s, i32 %1
v_gep: mlirlite.Value* = mlirlite.build_gep(builder, ty_i8, v_s, v_loaded)
# %3 = zext i32 %1 to i64 ; %4 = ptrtoint !llvm.ptr %s to i64
v_zext: mlirlite.Value* = mlirlite.build_zext(builder, v_loaded, ty_i64)
v_p2i: mlirlite.Value* = mlirlite.build_ptrtoint(builder, v_s, ty_i64)
# %5 = call i32 @callee(i32 %1)
v_call: mlirlite.Value* = mlirlite.build_call(builder, "callee", v_loaded, 1, ty_i32, 0)
mlirlite.build_ret(builder, v_call)
buf: str = pool.alloc(4096)
buf[0] = 0
mcore.PrintFunction(buf, 4096, func)
dump_mlir(pool, None, buf)
testcheck.info(buf)
dump_mlir(pool, "T09_mem_call_cast.mlir", buf)
# Save the whole module: mlir-opt requires callees declared at module scope,
# otherwise single-function text without declare fails symbol resolution
decl: mlirlite.Function* = mcore.CreateDeclare(mod, "callee", ty_i32)
mcore.AddParam(decl, ty_i32, "%x")
mbuf: str = pool.alloc(65536)
if mbuf is not None:
mbuf[0] = 0
mcore.PrintModule(mbuf, 65536, mod)
dump_mlir(pool, "T09_mem_module.mlir", mbuf)
testcheck.check(string.strstr(buf, "llvm.alloca") is not None,
"contains 'llvm.alloca'", "missing 'llvm.alloca'")
testcheck.check(string.strstr(buf, "llvm.store %n, %") is not None,
"contains 'llvm.store'", "missing 'llvm.store'")
testcheck.check(string.strstr(buf, "llvm.load %") is not None,
"contains 'llvm.load'", "missing 'llvm.load'")
testcheck.check(string.strstr(buf, "llvm.getelementptr") is not None,
"contains 'llvm.getelementptr'", "missing 'llvm.getelementptr'")
testcheck.check(string.strstr(buf, "llvm.call @callee(") is not None,
"contains 'llvm.call @callee('", "missing 'llvm.call'")
testcheck.check(string.strstr(buf, "llvm.zext") is not None,
"contains 'llvm.zext'", "missing 'llvm.zext'")
testcheck.check(string.strstr(buf, "llvm.ptrtoint") is not None,
"contains 'llvm.ptrtoint'", "missing 'llvm.ptrtoint'")
# Test 10: global variables (string constant / int / int array)
def test_globals(pool: memhub.MemBuddy*):
testcheck.section("Test 10: Global Variables")
core: mlirlite.LLVMTypeCore* = mlirlite.LLVMTypeCore(pool)
mcore: mlirlite.LLVMModuleCore* = mlirlite.LLVMModuleCore(pool)
ty_void: mlirlite.LLVMType* = core.Void()
ty_i8: mlirlite.LLVMType* = core.Int8()
mod: mlirlite.LLVMModule* = mcore.NewModule("test_globals")
mlirlite.module_set_target(mod, "x86_64-pc-windows-gnu")
# @.str = private unnamed_addr constant [6 x i8] c"hello\00"
mcore.CreateGlobalString(mod, ".str", "hello")
# @counter = global i32 0
mcore.CreateGlobalInt(mod, "counter", 32, 0)
# @arr = [i8 1, i8 2] -> [1 : i8, 2 : i8] (elements carry type annotations);
# dense<...> is illegal for !llvm.array (it only accepts builtin shaped types)
ty_arr2: mlirlite.LLVMType* = core.Array(ty_i8, 2)
gv_arr: mlirlite.GlobalVariable* = mcore.NewGlobal(mod, "arr", ty_arr2)
init_arr: str = pool.alloc(32)
string.strcpy(init_arr, "[i8 1, i8 2]")
gv_arr.Initializer = init_arr
func: mlirlite.Function* = mcore.CreateFunction(mod, "use_global", ty_void)
entry: mlirlite.BasicBlock* = mcore.CreateBlock(func, "entry")
builder: mlirlite.IRBuilder* = mcore.NewBuilder(func)
mlirlite.position_at_end(builder, entry)
mlirlite.build_ret_void(builder)
buf: str = pool.alloc(65536)
buf[0] = 0
mcore.PrintModule(buf, 65536, mod)
dump_mlir(pool, None, buf)
testcheck.info(buf)
dump_mlir(pool, "T10_globals.mlir", buf)
testcheck.check(string.strstr(buf, "llvm.mlir.global") is not None,
"contains 'llvm.mlir.global'", "missing 'llvm.mlir.global'")
# A '.'-prefixed symbol name must be quoted (MLIR bare names start with a letter or _)
# Actual form: llvm.mlir.global ... constant @".str"("hello\00") : !llvm.array<6 x i8>
testcheck.check(string.strstr(buf, "@\".str\"(") is not None,
"字符串全局名引号形态 '@\".str\"('", "missing quoted string global name")
# The string attribute length must equal the i8 array length, so the trailing
# NUL must stay: mlir-opt rejects stripping \00, and dropping it breaks the ABI
testcheck.check(string.strstr(buf, "hello\\00") is not None,
"字符串初值保留 NUL 'hello\\00'", "missing string initializer")
testcheck.check(string.strstr(buf, "!llvm.array<6 x i8>") is not None,
"contains '!llvm.array<6 x i8>'", "missing string global type")
testcheck.check(string.strstr(buf, "@counter(0 : i32) : i32") is not None,
"整数全局 '@counter(0 : i32) : i32'", "missing integer global")
# Array attribute: elements carry type annotations (dense<...> invalid for !llvm.array)
testcheck.check(string.strstr(buf, "[1 : i8, 2 : i8]") is not None,
"整型数组初值 '[1 : i8, 2 : i8]'", "missing array initializer")
# Test 11: SSA verification (valid function, 0 errors)
def test_verify_valid(pool: memhub.MemBuddy*):
testcheck.section("Test 11: Verify valid function")
core: mlirlite.LLVMTypeCore* = mlirlite.LLVMTypeCore(pool)
mcore: mlirlite.LLVMModuleCore* = mlirlite.LLVMModuleCore(pool)
ty_i32: mlirlite.LLVMType* = core.Int32()
mod: mlirlite.LLVMModule* = mcore.NewModule("verify_valid")
func: mlirlite.Function* = mcore.CreateFunction(mod, "add", ty_i32)
mcore.AddParam(func, ty_i32, "%a")
mcore.AddParam(func, ty_i32, "%b")
entry: mlirlite.BasicBlock* = mcore.CreateBlock(func, "entry")
builder: mlirlite.IRBuilder* = mcore.NewBuilder(func)
mlirlite.position_at_end(builder, entry)
v_a: mlirlite.Value* = mcore.SSAValue(ty_i32, "%a")
v_b: mlirlite.Value* = mcore.SSAValue(ty_i32, "%b")
v_c: mlirlite.Value* = mlirlite.build_add(builder, v_a, v_b)
mlirlite.build_ret(builder, v_c)
result: mlirlite.VerifyResult* = mcore.NewVerifyResult(4096)
err_count: int = mcore.VerifyFunction(func, result)
# Render once via PrintFunction for on-disk acceptance (no assertion involved)
buf: str = pool.alloc(4096)
buf[0] = 0
mcore.PrintFunction(buf, 4096, func)
dump_mlir(pool, "T11_verify.mlir", buf)
testcheck.check(err_count == 0,
"valid add function: 0 errors",
"valid function should pass verification")
testcheck.check(result.ErrorCode == mlirlite.VERIFY_OK,
"error code = VERIFY_OK",
"wrong error code for valid function")
# Test 12: struct/vtable globals lower to initializer regions
# Covers vtable bitcast refs, GEP addressof, quoted names, bare null/zeroinitializer
def test_struct_global(pool: memhub.MemBuddy*):
testcheck.section("Test 12: struct/vtable global initializer (region)")
core: mlirlite.LLVMTypeCore* = mlirlite.LLVMTypeCore(pool)
mcore: mlirlite.LLVMModuleCore* = mlirlite.LLVMModuleCore(pool)
ty_i8: mlirlite.LLVMType* = core.Int8()
ty_i8ptr: mlirlite.LLVMType* = core.Ptr(ty_i8)
mod: mlirlite.LLVMModule* = mcore.NewModule("test_struct_global")
# ---- (1) vtable struct { i8*, i8*, i8* } ----
# Initializer is a TPV-generated LLVM syntax aggregate: null + bitcast symbol refs
vt1: mlirlite.ParamNode* = core.NewParamNode(ty_i8ptr)
vt2: mlirlite.ParamNode* = core.NewParamNode(ty_i8ptr)
vt3: mlirlite.ParamNode* = core.NewParamNode(ty_i8ptr)
vt_head: mlirlite.ParamNode* = core.ParamListAppend(None, None, vt1)
core.ParamListAppend(vt_head, vt1, vt2)
core.ParamListAppend(vt_head, vt2, vt3)
ty_vt: mlirlite.LLVMType* = core.Struct(vt_head, 3)
gv_vt: mlirlite.GlobalVariable* = mcore.NewGlobal(mod, "vt", ty_vt)
init_vt: str = pool.alloc(256)
string.strcpy(init_vt,
"{ i8* null, i8* bitcast (i8* (i8*)* @\"m0\" to i8*), i8* bitcast (i8* (i8*)* @m1 to i8*) }")
gv_vt.Initializer = init_vt
# IsConstant=1 with default external linkage: a non-empty initializer omits the keyword
mcore.GlobalSetConstant(gv_vt, 1)
# Declare referenced method symbols so the module is self-consistent for mlir-opt
d_m0: mlirlite.Function* = mcore.CreateDeclare(mod, "m0", ty_i8ptr)
mcore.AddParam(d_m0, ty_i8ptr, "%self")
d_m1: mlirlite.Function* = mcore.CreateDeclare(mod, "m1", ty_i8ptr)
mcore.AddParam(d_m1, ty_i8ptr, "%self")
# ---- (3) re-quoting branch: LLVM bare name @9m (digit start) -> MLIR @"9m" ----
vq1: mlirlite.ParamNode* = core.NewParamNode(ty_i8ptr)
ty_vtq: mlirlite.LLVMType* = core.Struct(vq1, 1)
gv_vtq: mlirlite.GlobalVariable* = mcore.NewGlobal(mod, "vtq", ty_vtq)
init_vtq: str = pool.alloc(128)
string.strcpy(init_vtq, "{ i8* bitcast (i8* (i8*)* @9m to i8*) }")
gv_vtq.Initializer = init_vtq
mcore.GlobalSetConstant(gv_vtq, 1)
mcore.GlobalSetLinkage(gv_vtq, "internal")
d_9m: mlirlite.Function* = mcore.CreateDeclare(mod, "9m", ty_i8ptr)
mcore.AddParam(d_9m, ty_i8ptr, "%self")
# ---- (2) pointer array + GEP constant expression ----
# @s0 = [3 x i8], the target of the GEP constant expression
mcore.CreateGlobalString(mod, "s0", "ab")
ty_arr2: mlirlite.LLVMType* = core.Array(ty_i8ptr, 2)
gv_arr: mlirlite.GlobalVariable* = mcore.NewGlobal(mod, "arr", ty_arr2)
init_arr: str = pool.alloc(256)
string.strcpy(init_arr,
"[i8* getelementptr inbounds ([3 x i8], [3 x i8]* @s0, i32 0, i32 0), i8* null]")
gv_arr.Initializer = init_arr
mcore.GlobalSetLinkage(gv_arr, "internal")
# ---- (2') root bare GEP (TPV pointer-global form) ----
# Initializer has no type prefix; it is a bare getelementptr constant expression
gv_sp: mlirlite.GlobalVariable* = mcore.NewGlobal(mod, "sp", ty_i8ptr)
init_sp: str = pool.alloc(192)
string.strcpy(init_sp,
"getelementptr inbounds ([3 x i8], [3 x i8]* @s0, i32 0, i32 0)")
gv_sp.Initializer = init_sp
# ---- (4) root bare null / zeroinitializer globals ----
# Lowered to a region with llvm.mlir.zero (mlir-opt rejects the (zeroinitializer) attr form)
gv_pn: mlirlite.GlobalVariable* = mcore.NewGlobal(mod, "pnull", ty_i8ptr)
init_pn: str = pool.alloc(16)
string.strcpy(init_pn, "null")
gv_pn.Initializer = init_pn
# Int array + bare zeroinitializer: top-level type comes from gv.Ty (!llvm.array<2 x i32>)
ty_i32: mlirlite.LLVMType* = core.Int32()
ty_arr_i32: mlirlite.LLVMType* = core.Array(ty_i32, 2)
gv_za: mlirlite.GlobalVariable* = mcore.NewGlobal(mod, "zarr", ty_arr_i32)
init_za: str = pool.alloc(24)
string.strcpy(init_za, "zeroinitializer")
gv_za.Initializer = init_za
buf: str = pool.alloc(65536)
buf[0] = 0
mcore.PrintModule(buf, 65536, mod)
testcheck.info(buf)
dump_mlir(pool, "T12_struct_global.mlir", buf)
# (1) vtable: region form + top-level aggregate type; element annotations from type tree
testcheck.check(string.strstr(buf, "@vt() : !llvm.struct<(!llvm.ptr, !llvm.ptr, !llvm.ptr)>") is not None,
"vtable 全局 region 形态 '@vt() : !llvm.struct<(…, …, …)>'",
"missing vtable global region header")
testcheck.check(string.strstr(buf, "llvm.mlir.undef : !llvm.struct<(!llvm.ptr, !llvm.ptr, !llvm.ptr)>") is not None,
"含 'llvm.mlir.undef'(insertvalue 链起点)",
"missing llvm.mlir.undef")
# LLVM @"m0" is unquoted to bare @m0 (a valid MLIR bare name)
testcheck.check(string.strstr(buf, "llvm.mlir.addressof @m0 : !llvm.ptr") is not None,
"bitcast 中的 @\"m0\" → 'llvm.mlir.addressof @m0 : !llvm.ptr'",
"missing addressof for m0")
testcheck.check(string.strstr(buf, "llvm.mlir.addressof @m1 : !llvm.ptr") is not None,
"bitcast 中的 @m1 → 'llvm.mlir.addressof @m1 : !llvm.ptr'",
"missing addressof for m1")
testcheck.check(string.strstr(buf, "i8* null") is None,
"LLVM 语法初值串不再出现(i8* null 已转 llvm.mlir.zero)",
"raw LLVM initializer text leaked")
testcheck.check(string.strstr(buf, "llvm.insertvalue") is not None,
"含 'llvm.insertvalue'",
"missing llvm.insertvalue")
testcheck.check(string.strstr(buf, "llvm.return") is not None,
"含 'llvm.return'",
"missing llvm.return")
testcheck.check(string.strstr(buf, "external") is None,
"external + 有初值 ⇒ 不输出 linkage 关键字",
"unexpected 'external' keyword")
# (3) digit-leading symbol names need quotes (per _ll_name_needs_quote)
testcheck.check(string.strstr(buf, "llvm.mlir.addressof @\"9m\" : !llvm.ptr") is not None,
"数字开头符号名重加引号 'llvm.mlir.addressof @\"9m\" : !llvm.ptr'",
"missing quoted addressof for 9m")
# (2) pointer array + GEP: GEP constant -> addressof; array global type + index path
testcheck.check(string.strstr(buf, "@arr() : !llvm.array<2 x !llvm.ptr>") is not None,
"数组全局 region 形态 '@arr() : !llvm.array<2 x !llvm.ptr>'",
"missing array global region header")
testcheck.check(string.strstr(buf, "llvm.mlir.addressof @s0 : !llvm.ptr") is not None,
"GEP 常量表达式 → 'llvm.mlir.addressof @s0 : !llvm.ptr'",
"missing addressof for s0")
testcheck.check(string.strstr(buf, "%undef[0] : !llvm.array<2 x !llvm.ptr>") is not None,
"下标 0 形态 '%undef[0] : !llvm.array<2 x !llvm.ptr>'",
"missing index [0] insertvalue")
testcheck.check(string.strstr(buf, "[1] : !llvm.array<2 x !llvm.ptr>") is not None,
"下标 1 形态 '[1] : !llvm.array<2 x !llvm.ptr>'",
"missing index [1] insertvalue")
# (2') root bare GEP: top-level leaf region, no undef/insertvalue
testcheck.check(string.strstr(buf, "@sp() : !llvm.ptr") is not None,
"根级裸 GEP → '@sp() : !llvm.ptr'(顶层叶子 region)",
"missing root bare-GEP global")
# (4) root bare null pointer global: region form, empty parens, type from gv.Ty
testcheck.check(string.strstr(buf, "@pnull() : !llvm.ptr") is not None,
"根级裸 null → '@pnull() : !llvm.ptr'(region 形态)",
"missing bare-null pointer global region header")
testcheck.check(string.strstr(buf, "llvm.mlir.zero : !llvm.ptr") is not None,
"根级裸 null → 'llvm.mlir.zero : !llvm.ptr'",
"missing llvm.mlir.zero for bare-null global")
testcheck.check(string.strstr(buf, "llvm.return") is not None,
"region 内含 'llvm.return'",
"missing llvm.return in region")
# (4') bare zeroinitializer int array: region form, zero type is the top-level type
testcheck.check(string.strstr(buf, "@zarr() : !llvm.array<2 x i32>") is not None,
"裸 zeroinitializer → '@zarr() : !llvm.array<2 x i32>'(region 形态)",
"missing zeroinitializer array global region header")
testcheck.check(string.strstr(buf, "llvm.mlir.zero : !llvm.array<2 x i32>") is not None,
"裸 zeroinitializer → 'llvm.mlir.zero : !llvm.array<2 x i32>'",
"missing llvm.mlir.zero for zeroinitializer array global")
# Both must never fall back to the attribute form (mlir-opt rejects it)
testcheck.check(string.strstr(buf, "(zeroinitializer)") is None,
"属性形态 '(zeroinitializer)' 不再出现",
"rejected attribute form '(zeroinitializer)' leaked")
# Test 13: alloca alignment / switch / inline_asm MLIR forms
# Forms verified against mlir-opt 22.1.8; switch phi targets carry block operands
def test_alloca_align_switch_asm(pool: memhub.MemBuddy*):
testcheck.section("Test 13: alloca align / switch / inline_asm")
core: mlirlite.LLVMTypeCore* = mlirlite.LLVMTypeCore(pool)
mcore: mlirlite.LLVMModuleCore* = mlirlite.LLVMModuleCore(pool)
ty_i32: mlirlite.LLVMType* = core.Int32()
ty_void: mlirlite.LLVMType* = core.Void()
mod: mlirlite.LLVMModule* = mcore.NewModule("test_align_switch_asm")
# ---- (1) alloca alignment + (3) inline_asm (builder + TPV-injected forms) ----
f1: mlirlite.Function* = mcore.CreateFunction(mod, "align_asm", ty_i32)
mcore.AddParam(f1, ty_i32, "%x")
e1: mlirlite.BasicBlock* = mcore.CreateBlock(f1, "entry")
b1: mlirlite.IRBuilder* = mcore.NewBuilder(f1)
mlirlite.position_at_end(b1, e1)
# %0 = alloca i32, align 16
v_slot: mlirlite.Value* = mlirlite.build_alloca_aligned(b1, ty_i32, 16)
# call none asm sideeffect "nop", ""() (void form)
mlirlite.build_inline_asm(b1, ty_void, "nop", "", 1)
# %1 = call i32 asm sideeffect "mov $0, $1", "=r,r"() (returning form)
v_asm: mlirlite.Value* = mlirlite.build_inline_asm(b1, ty_i32, "mov $0, $1", "=r,r", 1)
v_x: mlirlite.Value* = mcore.SSAValue(ty_i32, "%x")
mlirlite.build_store(b1, v_x, v_slot, 0)
# TPV CallGenCBuiltin injected form (inteldialect + typed input operands)
mlirlite.block_append_text(pool, e1,
"%7 = call i32 asm sideeffect inteldialect \"mov $0, $1\", \"=r,r\"(i32 %x)")
mlirlite.build_ret(b1, v_asm)
# ---- (2) switch: 3 cases + default (no phi) ----
f2: mlirlite.Function* = mcore.CreateFunction(mod, "sw", ty_i32)
mcore.AddParam(f2, ty_i32, "%v")
e2: mlirlite.BasicBlock* = mcore.CreateBlock(f2, "entry")
c0: mlirlite.BasicBlock* = mcore.CreateBlock(f2, "case0")
c1: mlirlite.BasicBlock* = mcore.CreateBlock(f2, "case1")
c2: mlirlite.BasicBlock* = mcore.CreateBlock(f2, "case2")
dflt: mlirlite.BasicBlock* = mcore.CreateBlock(f2, "default")
b2: mlirlite.IRBuilder* = mcore.NewBuilder(f2)
mlirlite.position_at_end(b2, e2)
v_v: mlirlite.Value* = mcore.SSAValue(ty_i32, "%v")
sc0: mlirlite.SwitchCase* = mlirlite.new_switch_case(pool, mcore.ConstInt32(0), c0)
sc1: mlirlite.SwitchCase* = mlirlite.new_switch_case(pool, mcore.ConstInt32(1), c1)
sc2: mlirlite.SwitchCase* = mlirlite.new_switch_case(pool, mcore.ConstInt32(2), c2)
sc0.Next = sc1
sc1.Next = sc2
mlirlite.build_switch(b2, v_v, dflt, sc0, 3)
mlirlite.position_at_end(b2, c0)
mlirlite.build_ret(b2, v_v)
mlirlite.position_at_end(b2, c1)
mlirlite.build_ret(b2, v_v)
mlirlite.position_at_end(b2, c2)
mlirlite.build_ret(b2, v_v)
mlirlite.position_at_end(b2, dflt)
mlirlite.build_ret(b2, v_v)
# ---- (2') switch: case and default targets carry phi -> block operands ----
f3: mlirlite.Function* = mcore.CreateFunction(mod, "sw_phi", ty_i32)
mcore.AddParam(f3, ty_i32, "%v")
e3: mlirlite.BasicBlock* = mcore.CreateBlock(f3, "entry")
sk: mlirlite.BasicBlock* = mcore.CreateBlock(f3, "scase")
sd: mlirlite.BasicBlock* = mcore.CreateBlock(f3, "sdef")
b3: mlirlite.IRBuilder* = mcore.NewBuilder(f3)
mlirlite.position_at_end(b3, e3)
v_v3: mlirlite.Value* = mcore.SSAValue(ty_i32, "%v")
skc: mlirlite.SwitchCase* = mlirlite.new_switch_case(pool, mcore.ConstInt32(0), sk)
mlirlite.build_switch(b3, v_v3, sd, skc, 1)
# scase: %p0 = phi i32 [1, %entry]; ret i32 %p0
mlirlite.position_at_end(b3, sk)
in1: mlirlite.PhiIncoming* = mlirlite.new_phi_incoming(pool, mcore.ConstInt32(1), e3)
v_p0: mlirlite.Value* = mlirlite.build_phi(b3, ty_i32, in1, 1)
mlirlite.build_ret(b3, v_p0)
# sdef: %p1 = phi i32 [2, %entry]; ret i32 %p1
mlirlite.position_at_end(b3, sd)
in2: mlirlite.PhiIncoming* = mlirlite.new_phi_incoming(pool, mcore.ConstInt32(2), e3)
v_p1: mlirlite.Value* = mlirlite.build_phi(b3, ty_i32, in2, 1)
mlirlite.build_ret(b3, v_p1)
buf: str = pool.alloc(65536)
buf[0] = 0
mcore.PrintModule(buf, 65536, mod)
testcheck.info(buf)
dump_mlir(pool, "T13_align_switch_asm.mlir", buf)
# (1) alloca alignment: form is {alignment = 16 : i64} (LLVM ', align 16' is gone)
testcheck.check(string.strstr(buf, "llvm.alloca %c0 x i32 {alignment = 16 : i64} : (i32) -> !llvm.ptr") is not None,
"alloca 对齐 'llvm.alloca %c0 x i32 {alignment = 16 : i64} : (i32) -> !llvm.ptr'",
"missing alloca alignment attribute")
testcheck.check(string.strstr(buf, ", align 16") is None,
"LLVM 词法 ', align 16' 不再出现(已转写为属性)",
"raw LLVM alloca align leaked")
# (2) switch: value type follows the value (%v : i32,) plus case/default labels
testcheck.check(string.strstr(buf, "llvm.switch %v : i32, ^default [0: ^case0, 1: ^case1, 2: ^case2]") is not None,
"switch 实测形态 'llvm.switch %v : i32, ^default [0: ^case0, 1: ^case1, 2: ^case2]'",
"missing llvm.switch")
testcheck.check(string.strstr(buf, "^case0") is not None,
"contains '^case0'", "missing '^case0'")
testcheck.check(string.strstr(buf, "^case1") is not None,
"contains '^case1'", "missing '^case1'")
testcheck.check(string.strstr(buf, "^case2") is not None,
"contains '^case2'", "missing '^case2'")
# (2') switch phi targets -> block operands (carried by default and case)
testcheck.check(string.strstr(buf, "llvm.switch %v : i32, ^sdef(%c1 : i32) [0: ^scase(%c0 : i32)]") is not None,
"switch 块实参 'llvm.switch %v : i32, ^sdef(%c1 : i32) [0: ^scase(%c0 : i32)]'",
"missing switch block operands")
# Block-argument SSA names depend on renumbering, so assert only the shape
# "target label carries arguments", not specific names, avoiding brittle asserts
testcheck.check(string.strstr(buf, "^scase(%") is not None,
"case 目标块带参数 '^scase(%…: i32):'",
"missing block argument for switch case target")
testcheck.check(string.strstr(buf, "^sdef(%") is not None,
"default 目标块带参数 '^sdef(%…: i32):'",
"missing block argument for switch default target")
# (3) inline_asm: void / returning / inteldialect -> asm_dialect = intel
testcheck.check(string.strstr(buf, "llvm.inline_asm has_side_effects \"nop\", \"\" : () -> ()") is not None,
"无返回值形态 'llvm.inline_asm has_side_effects \"nop\", \"\" : () -> ()'",
"missing void inline_asm")
testcheck.check(string.strstr(buf, "llvm.inline_asm has_side_effects \"mov $0, $1\", \"=r,r\" : () -> i32") is not None,
"有返回值形态 '… \"=r,r\" : () -> i32'",
"missing returning inline_asm")
testcheck.check(string.strstr(buf, "asm_dialect = intel") is not None,
"LLVM 的 inteldialect → 'asm_dialect = intel'",
"missing asm_dialect for inteldialect")
testcheck.check(string.strstr(buf, "asm_dialect = intel \"mov $0, $1\", \"=r,r\" %x : (i32) -> i32") is not None,
"注入形态操作数不带括号 'asm_dialect = intel \"…\", \"…\" %x : (i32) -> i32'",
"missing operand form of inline_asm")
testcheck.check(string.strstr(buf, "inteldialect") is None,
"LLVM 词法关键字 'inteldialect' 不再出现",
"raw LLVM inteldialect keyword leaked")
# Test 14: vararg function/call, va_arg, cmpxchg, global attribute dict
# Five MLIR forms verified with mlir-opt 22.1.8; the attr dict precedes the type
def test_vararg_vaarg_cmpxchg(pool: memhub.MemBuddy*):
testcheck.section("Test 14: vararg / va_arg / cmpxchg / global attrs")
core: mlirlite.LLVMTypeCore* = mlirlite.LLVMTypeCore(pool)
mcore: mlirlite.LLVMModuleCore* = mlirlite.LLVMModuleCore(pool)
ty_i32: mlirlite.LLVMType* = core.Int32()
ty_i8: mlirlite.LLVMType* = core.Int8()
ty_i32ptr: mlirlite.LLVMType* = core.Ptr(ty_i32)
mod: mlirlite.LLVMModule* = mcore.NewModule("test_vararg_vaarg_cmpxchg")
# ---- (1) vararg declaration: llvm.func @printf(%p: !llvm.ptr, ...) -> i32 ----
f_printf: mlirlite.Function* = mcore.CreateDeclare(mod, "printf", ty_i32)
mcore.AddParam(f_printf, ty_i32ptr, "%p")
f_printf.IsVarArg = 1
# ---- ③ va_arg: %0 = "llvm.va_arg"(%ap) : (!llvm.ptr) -> i32 ----
f_va: mlirlite.Function* = mcore.CreateFunction(mod, "va_reader", ty_i32)
mcore.AddParam(f_va, ty_i32ptr, "%ap")
e_va: mlirlite.BasicBlock* = mcore.CreateBlock(f_va, "entry")
b_va: mlirlite.IRBuilder* = mcore.NewBuilder(f_va)
mlirlite.position_at_end(b_va, e_va)
v_ap: mlirlite.Value* = mcore.SSAValue(ty_i32ptr, "%ap")
v_arg: mlirlite.Value* = mlirlite.build_va_arg(b_va, v_ap, ty_i32)
mlirlite.build_ret(b_va, v_arg)
# ---- (2) vararg call + (4) cmpxchg (builder single-result form) ----
f_cc: mlirlite.Function* = mcore.CreateFunction(mod, "vcall_cmpx", ty_i32)
mcore.AddParam(f_cc, ty_i32ptr, "%p")
mcore.AddParam(f_cc, ty_i32, "%n")
e_cc: mlirlite.BasicBlock* = mcore.CreateBlock(f_cc, "entry")
b_cc: mlirlite.IRBuilder* = mcore.NewBuilder(f_cc)
mlirlite.position_at_end(b_cc, e_cc)
v_p: mlirlite.Value* = mcore.SSAValue(ty_i32ptr, "%p")
v_n: mlirlite.Value* = mcore.SSAValue(ty_i32, "%n")
# %0 = cmpxchg !llvm.ptr %p, i32 %n, i32 %n acq_rel monotonic
# -> llvm.cmpxchg + two extractvalue; %0 binds to [0] (old value)
v_old: mlirlite.Value* = mlirlite.build_cmpxchg(b_cc, v_p, v_n, v_n,
mlirlite.ATOMIC_ORDER_ACQ_REL,
mlirlite.ATOMIC_ORDER_MONOTONIC)
# %1 = call i32 (i8*, i32, ...) @printf(i8* %p, i32 %n)
# -> %1 = llvm.call @printf(%p, %n) vararg(!llvm.func<i32 (!llvm.ptr, i32, ...)>)
mlirlite.value_set_next(v_p, v_n)
v_call: mlirlite.Value* = mlirlite.build_call(b_cc, "printf", v_p, 2, ty_i32, 1)
# ret uses the cmpxchg result to assert alias binding (text: %_0_v = extractvalue[0])
mlirlite.build_ret(b_cc, v_old)
# ---- (4') cmpxchg dual-result prefix (both names bind one extractvalue each) ----
f_cc2: mlirlite.Function* = mcore.CreateFunction(mod, "cmpx2", ty_i32)
mcore.AddParam(f_cc2, ty_i32ptr, "%p")
mcore.AddParam(f_cc2, ty_i32, "%n")
e_cc2: mlirlite.BasicBlock* = mcore.CreateBlock(f_cc2, "entry")
mlirlite.block_append_text(pool, e_cc2,
"%a, %b = cmpxchg !llvm.ptr %p, i32 %n, i32 %n acq_rel monotonic")
# %b = success bit [1]; %a = old value [0]
mlirlite.block_append_text(pool, e_cc2, "%r = zext i1 %b to i32")
mlirlite.block_append_text(pool, e_cc2, "ret i32 %a")
# ---- (5) global attr dict: section/alignment precede the type; unnamed_addr is a keyword ----
ty_arr3: mlirlite.LLVMType* = core.Array(ty_i8, 3)
init_s: str = pool.alloc(32)
string.strcpy(init_s, "c\"ab\\00\"")
gv_s: mlirlite.GlobalVariable* = mcore.NewGlobal(mod, "s", ty_arr3)
gv_s.Initializer = init_s
mlirlite.global_set_linkage(gv_s, "internal")
mlirlite.global_set_constant(gv_s, 1)
mlirlite.global_set_section(gv_s, "data")
gv_s.Align = 16
gv_t: mlirlite.GlobalVariable* = mcore.NewGlobal(mod, "t", ty_arr3)
gv_t.Initializer = init_s
mlirlite.global_set_linkage(gv_t, "internal")
mlirlite.global_set_constant(gv_t, 1)
mlirlite.global_set_unnamed_addr(gv_t, 1)
buf: str = pool.alloc(65536)
buf[0] = 0
mcore.PrintModule(buf, 65536, mod)
testcheck.info(buf)
dump_mlir(pool, "T14_vararg_vaarg_cmpxchg.mlir", buf)
# (1) vararg declaration: parameter list ends with ...
testcheck.check(string.strstr(buf, "llvm.func @printf(%p: !llvm.ptr, ...) -> i32") is not None,
"变参声明 'llvm.func @printf(%p: !llvm.ptr, ...) -> i32'",
"missing vararg function declaration")
testcheck.check(string.strstr(buf, ", ...) -> i32") is not None,
"参数表尾 '..., ...)' 形态(', ...)')",
"missing vararg ellipsis in declaration")
# (2) vararg call: vararg(full MLIR function type)
testcheck.check(string.strstr(buf, "vararg(!llvm.func<") is not None,
"变参调用 'vararg(!llvm.func<'", "missing vararg(...) attribute")
testcheck.check(string.strstr(buf,
"vararg(!llvm.func<i32 (!llvm.ptr, i32, ...)>) : (!llvm.ptr, i32) -> i32") is not None,
"vararg 完整函数类型 'vararg(!llvm.func<i32 (!llvm.ptr, i32, ...)>) : (!llvm.ptr, i32) -> i32'",
"missing vararg function type")
# (3) va_arg: generic form (deliberate; custom asm cannot express opaque pointers)
testcheck.check(string.strstr(buf, "\"llvm.va_arg\"(") is not None,
"va_arg generic 形态 '\"llvm.va_arg\"('", "missing generic llvm.va_arg")
testcheck.check(string.strstr(buf, ") : (!llvm.ptr) -> i32") is not None,
"va_arg 类型串 ') : (!llvm.ptr) -> i32'", "missing va_arg type list")
# (4) cmpxchg: single result + two extractvalue ([0]=old value, [1]=i1 success bit)
testcheck.check(string.strstr(buf, "llvm.cmpxchg") is not None,
"contains 'llvm.cmpxchg'", "missing llvm.cmpxchg")
testcheck.check(string.strstr(buf, "llvm.extractvalue ") is not None,
"contains 'llvm.extractvalue '", "missing llvm.extractvalue")
testcheck.check(string.strstr(buf, "[0] : !llvm.struct<(i32, i1)>") is not None,
"旧值抽取 '[0] : !llvm.struct<(i32, i1)>'", "missing extractvalue [0]")
testcheck.check(string.strstr(buf, "[1] : !llvm.struct<(i32, i1)>") is not None,
"成功位抽取 '[1] : !llvm.struct<(i32, i1)>'", "missing extractvalue [1]")
# extractvalue result names derive deterministically from the struct result name
# (%0 -> %_0_v/%_0_ok, %a -> %_a_v/%_a_ok; MLIR requires the _ name prefix)
testcheck.check(string.strstr(buf, "%_0_v = llvm.extractvalue %0[0] : !llvm.struct<(i32, i1)>") is not None,
"旧值定义 '%_0_v = llvm.extractvalue %0[0] …'",
"cmpxchg single result not deterministically named")
testcheck.check(string.strstr(buf, "%_0_ok = llvm.extractvalue %0[1] : !llvm.struct<(i32, i1)>") is not None,
"成功位定义 '%_0_ok = llvm.extractvalue %0[1] …'",
"cmpxchg ok bit not deterministically named")
testcheck.check(string.strstr(buf, "%_a_v = llvm.extractvalue %a[0] : !llvm.struct<(i32, i1)>") is not None,
"双结果首名定义 '%_a_v = llvm.extractvalue %a[0] …'",
"cmpxchg double-result old value not deterministically named")
testcheck.check(string.strstr(buf, "%_a_ok = llvm.extractvalue %a[1] : !llvm.struct<(i32, i1)>") is not None,
"双结果次名定义 '%_a_ok = llvm.extractvalue %a[1] …'",
"cmpxchg double-result ok bit not deterministically named")
# Reference side: aliases rewrite %0/%a/%b to those names (def and use match)
testcheck.check(string.strstr(buf, "llvm.return %_0_v : i32") is not None,
"单结果引用改写 'llvm.return %_0_v : i32'",
"cmpxchg result not bound to old value")
testcheck.check(string.strstr(buf, "llvm.zext %_a_ok : i1 to i32") is not None,
"双结果次名引用改写 'llvm.zext %_a_ok : i1 to i32'",
"cmpxchg second name not bound to success bit")
testcheck.check(string.strstr(buf, "llvm.return %_a_v : i32") is not None,
"双结果首名引用改写 'llvm.return %_a_v : i32'",
"cmpxchg first name not bound to old value")
# (5) attr dict precedes the type (whole-string assert); unnamed_addr is not in the dict
testcheck.check(string.strstr(buf,
"(\"ab\\00\") {section = \"data\", alignment = 16 : i64} : !llvm.array<3 x i8>") is not None,
"属性字典在类型之前 '(\"ab\\00\") {section = \"data\", alignment = 16 : i64} : !llvm.array<3 x i8>'",
"global attribute dict not before type")
testcheck.check(string.strstr(buf, "!llvm.array<3 x i8> {section") is None,
"字典不在类型之后('!llvm.array<3 x i8> {section' 不出现)",
"global attribute dict leaked after type")
testcheck.check(string.strstr(buf, "unnamed_addr constant @t(") is not None,
"unnamed_addr 作关键字 'unnamed_addr constant @t('",
"missing unnamed_addr keyword")
testcheck.check(string.strstr(buf, "{unnamed_addr") is None,
"unnamed_addr 不进属性字典('{unnamed_addr' 不出现)",
"unnamed_addr leaked into attribute dict")
# Test 15: named struct types (LLVM %"name" = type) in MLIR
# MLIR has no type defs: drop def lines, inline by value, keep pointers opaque !llvm.ptr
def test_named_struct(pool: memhub.MemBuddy*):
testcheck.section("Test 15: named struct type")
core: mlirlite.LLVMTypeCore* = mlirlite.LLVMTypeCore(pool)
mcore: mlirlite.LLVMModuleCore* = mlirlite.LLVMModuleCore(pool)
ty_i32: mlirlite.LLVMType* = core.Int32()
ty_i8: mlirlite.LLVMType* = core.Int8()
ty_i8ptr: mlirlite.LLVMType* = core.Ptr(ty_i8)
# Named struct %"aa11bb22cc33dd44.Cls" = type { i32, i8* } (sha1-style prefix with '.')
ns1: mlirlite.ParamNode* = core.NewParamNode(ty_i32)
ns2: mlirlite.ParamNode* = core.NewParamNode(ty_i8ptr)
ns_head: mlirlite.ParamNode* = core.ParamListAppend(None, None, ns1)
core.ParamListAppend(ns_head, ns1, ns2)
ty_named: mlirlite.LLVMType* = core.Struct(ns_head, 2, "aa11bb22cc33dd44.Cls")
ty_named_ptr: mlirlite.LLVMType* = core.Ptr(ty_named)
# Packed named struct %"aa11bb22cc33dd44.Packed" = type <{ i32, i8 }>
# MLIR: !llvm.struct<"aa11bb22cc33dd44.Packed", packed (i32, i8)>
pk1: mlirlite.ParamNode* = core.NewParamNode(ty_i32)
pk2: mlirlite.ParamNode* = core.NewParamNode(ty_i8)
pk_head: mlirlite.ParamNode* = core.ParamListAppend(None, None, pk1)
core.ParamListAppend(pk_head, pk1, pk2)
ty_packed: mlirlite.LLVMType* = core.Struct(pk_head, 2, "aa11bb22cc33dd44.Packed")
# ---- type text: by value = inline named form; pointer = opaque !llvm.ptr ----
tbuf: str = pool.alloc(256)
tbuf[0] = 0
core.PrintType(tbuf, 256, ty_named)
testcheck.check(string.strstr(tbuf, "!llvm.struct<\"aa11bb22cc33dd44.Cls\", (i32, !llvm.ptr)>") is not None,
"具名结构体按值形态 '!llvm.struct<\"aa11bb22cc33dd44.Cls\", (i32, !llvm.ptr)>'",
"named struct by-value form missing")
# A '.' / digit-leading name needs no extra escaping or quotes (verified)
testcheck.check(string.strstr(tbuf, "<\"aa11bb22cc33dd44.Cls\",") is not None,
"名字直接作字符串字面量(不额外转义)",
"named struct name literal form missing")
tbuf[0] = 0
core.PrintType(tbuf, 256, ty_named_ptr)
testcheck.check(string.strcmp(tbuf, "!llvm.ptr") == 0,
"Ptr(具名结构体) -> '!llvm.ptr'(不透明指针,不回退为指针类型)",
"named struct pointer must stay opaque !llvm.ptr")
mod: mlirlite.LLVMModule* = mcore.NewModule("test_named_struct")
# Real flow: register named structs via module_add_named_type for the print-time table
mlirlite.module_add_named_type(mod, pool, ty_named)
# Only place the packed flag is set (after add_named_type; carried by the table)
mlirlite.module_add_named_type(mod, pool, ty_packed)
mlirlite.module_set_named_type_packed(mod, pool, ty_packed, 1)
# ---- (1) by-value global (inlines the named body) + (2) pointer global to it ----
gv_v: mlirlite.GlobalVariable* = mcore.NewGlobal(mod, "g_cls", ty_named)
gv_p: mlirlite.GlobalVariable* = mcore.NewGlobal(mod, "g_cls_p", ty_named_ptr)
# (3) packed by-value global
gv_pk: mlirlite.GlobalVariable* = mcore.NewGlobal(mod, "g_packed", ty_packed)
# ---- (1) by-value parameter + (2) pointer parameter ----
fn: mlirlite.Function* = mcore.CreateFunction(mod, "use_named", ty_i32)
mcore.AddParam(fn, ty_named, "%v")
mcore.AddParam(fn, ty_named_ptr, "%p")
entry: mlirlite.BasicBlock* = mcore.CreateBlock(fn, "entry")
b: mlirlite.IRBuilder* = mcore.NewBuilder(fn)
mlirlite.position_at_end(b, entry)
# ---- (4) bare-name form in mid text (hand-written / TPV-injected) ----
# Print time expands it via the table; pointer form %"name"* stays !llvm.ptr
mlirlite.block_append_text(pool, entry, "%0 = alloca %\"aa11bb22cc33dd44.Cls\"")
mlirlite.block_append_text(pool, entry, "%1 = load i32, %\"aa11bb22cc33dd44.Cls\"* %0")
# (5) packed named struct text form (same table slot carries the packed flag)
mlirlite.block_append_text(pool, entry, "%2 = alloca %\"aa11bb22cc33dd44.Packed\"")
v_1: mlirlite.Value* = mcore.SSAValue(ty_i32, "%1")
mlirlite.build_ret(b, v_1)
# ---- (6) by-value packed parameter: separate declare, keeping use_named asserts ----
fn_pk: mlirlite.Function* = mcore.CreateDeclare(mod, "use_packed", ty_i32)
mcore.AddParam(fn_pk, ty_packed, "%pk")
buf: str = pool.alloc(65536)
buf[0] = 0
mcore.PrintModule(buf, 65536, mod)
testcheck.info(buf)
dump_mlir(pool, "T15_named_struct.mlir", buf)
# (1) by-value parameter / global: inline the named body at the use site
testcheck.check(string.strstr(buf, "llvm.func @use_named(%v: !llvm.struct<\"aa11bb22cc33dd44.Cls\", (i32, !llvm.ptr)>, %p: !llvm.ptr) -> i32") is not None,
"按值形参 'llvm.func @use_named(%v: !llvm.struct<\"aa11bb22cc33dd44.Cls\", (i32, !llvm.ptr)>, %p: !llvm.ptr) -> i32'",
"missing inline named struct parameter")
testcheck.check(string.strstr(buf, "@g_cls() : !llvm.struct<\"aa11bb22cc33dd44.Cls\", (i32, !llvm.ptr)>") is not None,
"按值全局 '@g_cls() : !llvm.struct<\"aa11bb22cc33dd44.Cls\", (i32, !llvm.ptr)>'",
"missing inline named struct global")
# (2) pointer: remains opaque !llvm.ptr
testcheck.check(string.strstr(buf, "@g_cls_p() : !llvm.ptr") is not None,
"指针全局 '@g_cls_p() : !llvm.ptr'",
"named struct pointer global must be !llvm.ptr")
testcheck.check(string.strstr(buf, "!llvm.struct<\"aa11bb22cc33dd44.Cls\", (i32, !llvm.ptr)>*") is None,
"不得出现指向具名结构体的指针类型(MLIR 不透明指针)",
"pointer-to-named-struct type leaked")
# (4) %"name" text expands (alloca element / load pointer type); no def line emitted
testcheck.check(string.strstr(buf, "%0 = llvm.alloca %c0 x !llvm.struct<\"aa11bb22cc33dd44.Cls\", (i32, !llvm.ptr)> : (i32) -> !llvm.ptr") is not None,
"文本 %\"name\" 展开为内联具名体(alloca 元素类型)",
"named struct type text not expanded in alloca")
testcheck.check(string.strstr(buf, "%1 = llvm.load %0 : !llvm.ptr -> i32") is not None,
"文本 %\"name\"* 仍为不透明指针('%1 = llvm.load %0 : !llvm.ptr -> i32')",
"named struct pointer text not collapsed to !llvm.ptr")
testcheck.check(string.strstr(buf, "%\"aa11bb22cc33dd44.Cls\"") is None,
"LLVM 口径的 %\"name\" 形态不再出现(已全部转写)",
"raw LLVM named type text leaked")
# (3) def lines dropped: MLIR has no type-def syntax (mlir-translate emits at use)
testcheck.check(string.strstr(buf, "\"aa11bb22cc33dd44.Cls\" = type") is None,
"模块不输出 '\"name\" = type {…}' 定义行",
"named type definition line should be dropped")
# (7) packed named struct: the table carries IsPacked and adds the 'packed ' keyword
testcheck.check(string.strstr(buf, "@g_packed() : !llvm.struct<\"aa11bb22cc33dd44.Packed\", packed (i32, i8)>") is not None,
"packed 按值全局 '@g_packed() : !llvm.struct<\"aa11bb22cc33dd44.Packed\", packed (i32, i8)>'",
"missing packed inline named struct global")
testcheck.check(string.strstr(buf, "llvm.func @use_packed(%pk: !llvm.struct<\"aa11bb22cc33dd44.Packed\", packed (i32, i8)>) -> i32") is not None,
"packed 按值形参 'llvm.func @use_packed(%pk: !llvm.struct<\"aa11bb22cc33dd44.Packed\", packed (i32, i8)>) -> i32'",
"missing packed inline named struct parameter")
testcheck.check(string.strstr(buf, "x !llvm.struct<\"aa11bb22cc33dd44.Packed\", packed (i32, i8)> : (i32) -> !llvm.ptr") is not None,
"文本 %\"name\" 展开为 packed 内联具名体(alloca 元素类型)",
"packed named struct type text not expanded with packed")
# Negative: a non-packed named struct type string must not contain 'packed'
testcheck.check(string.strstr(buf, "!llvm.struct<\"aa11bb22cc33dd44.Cls\", packed") is None,
"非 packed 具名结构体类型串不含 'packed'",
"packed keyword leaked into non-packed named struct")
# Negative: a packed named struct must not render without the packed keyword
testcheck.check(string.strstr(buf, "!llvm.struct<\"aa11bb22cc33dd44.Packed\", (i32, i8)>") is None,
"packed 具名结构体不得渲染为无 packed 的形态",
"packed named struct rendered without packed keyword")
# Test 16: extractvalue for multi-result inline asm
# MLIR uses a single struct-typed result plus extractvalue with [idx] index lists
def test_extractvalue_multi_asm(pool: memhub.MemBuddy*):
testcheck.section("Test 16: extractvalue (multi-result inline asm)")
core: mlirlite.LLVMTypeCore* = mlirlite.LLVMTypeCore(pool)
mcore: mlirlite.LLVMModuleCore* = mlirlite.LLVMModuleCore(pool)
ty_i32: mlirlite.LLVMType* = core.Int32()
mod: mlirlite.LLVMModule* = mcore.NewModule("test_extractvalue_multi_asm")
func: mlirlite.Function* = mcore.CreateFunction(mod, "multi_asm", ty_i32)
entry: mlirlite.BasicBlock* = mcore.CreateBlock(func, "entry")
# (1) TPV real form: multi-result inline asm + two extractvalue (single index)
mlirlite.block_append_text(pool, entry,
"%2 = call {i32, i32} asm sideeffect \"mov $0, $1; mov $1, $1\", \"=r,r\"()")
mlirlite.block_append_text(pool, entry,
"%a = extractvalue {i32, i32} %2, 0")
mlirlite.block_append_text(pool, entry,
"%b = extractvalue {i32, i32} %2, 1")
# (2) multi-level index [1, 0] into a nested struct result (verified legal)
mlirlite.block_append_text(pool, entry,
"%3 = call {i32, {i32, i32}} asm sideeffect \"mov $0, $1\", \"=r,r\"()")
mlirlite.block_append_text(pool, entry,
"%d = extractvalue {i32, {i32, i32}} %3, 1, 0")
# Reference %a so the extractvalue result is actually used
mlirlite.block_append_text(pool, entry, "ret i32 %a")
buf: str = pool.alloc(65536)
buf[0] = 0
mcore.PrintModule(buf, 65536, mod)
testcheck.info(buf)
dump_mlir(pool, "T16_extractvalue.mlir", buf)
# (1) multi-result inline asm -> single struct-typed result
testcheck.check(string.strstr(buf, ": () -> !llvm.struct<(i32, i32)>") is not None,
"多结果内联汇编 '… : () -> !llvm.struct<(i32, i32)>'",
"multi-result inline_asm struct result missing")
testcheck.check(string.strstr(buf, "llvm.inline_asm has_side_effects") is not None,
"contains 'llvm.inline_asm has_side_effects'",
"missing llvm.inline_asm")
# (2) extractvalue: index inside [], aggregate type in MLIR form
testcheck.check(string.strstr(buf, "llvm.extractvalue ") is not None,
"contains 'llvm.extractvalue '", "missing llvm.extractvalue")
testcheck.check(string.strstr(buf, "[0] : !llvm.struct<(i32, i32)>") is not None,
"字段 0 抽取 '[0] : !llvm.struct<(i32, i32)>'",
"missing extractvalue [0]")
testcheck.check(string.strstr(buf, "[1] : !llvm.struct<(i32, i32)>") is not None,
"字段 1 抽取 '[1] : !llvm.struct<(i32, i32)>'",
"missing extractvalue [1]")
testcheck.check(string.strstr(buf, ": !llvm.struct<(i32, i32)>") is not None,
"聚合类型为 MLIR 结构体 ': !llvm.struct<(i32, i32)>'",
"aggregate type not rendered as MLIR struct")
# (3) multi-level index [1, 0] (comma-separated in MLIR, verified legal)
testcheck.check(string.strstr(buf, "[1, 0] : !llvm.struct<(i32, !llvm.struct<(i32, i32)>)>") is not None,
"多级索引 '[1, 0] : !llvm.struct<(i32, !llvm.struct<(i32, i32)>)>'",
"multi-level extractvalue index missing")
# Negative: LLVM <agg type> <value>, <index> must not appear (type text rewritten)
testcheck.check(string.strstr(buf, "{i32, i32} %") is None,
"LLVM 词法聚合类型文本不再出现('{i32, i32} %' 不出现)",
"raw LLVM aggregate type text leaked")
# Reference side: the extractvalue result name is returned as-is
testcheck.check(string.strstr(buf, "llvm.return %a : i32") is not None,
"extractvalue 结果被引用 'llvm.return %a : i32'",
"extractvalue result not referenced")
def _sub_arena(main_pool: memhub.MemBuddy*) -> rawptr:
"""Carve a sub-pool arena from the main pool and return its raw pointer.
MemBuddy is a stack value here, so returning one would dangle; fail fast if alloc fails.
"""
mem: rawptr = main_pool.alloc(SUB_POOL_SIZE)
if mem is None:
stdio.printf("FAIL: sub pool arena alloc failed (raise POOL_SIZE)\n")
stdlib.exit(1)
return mem
def main() -> int:
testcheck.begin("MLIRLiteTest: mlirlite 库(MLIR llvm 方言文本生成)")
# Init main pool: used only to carve a sub-pool per test (allocs use their sub-pool)
pool_mem: bytes = stdlib.malloc(POOL_SIZE)
if pool_mem is None:
stdio.printf("FAIL: malloc for pool failed\n")
return 1
pool: memhub.MemBuddy* = memhub.MemBuddy(pool_mem, POOL_SIZE)
if pool is None:
stdio.printf("FAIL: memhub.MemBuddy init failed\n")
return 1
# Sub-pools must be built in main's frame (see _sub_arena): MemBuddy is a stack
# value, so its pointer cannot cross functions. One per test, not overlapping.
sub: memhub.MemBuddy* = memhub.MemBuddy(_sub_arena(pool), SUB_POOL_SIZE)
test_type_print(sub)
sub = memhub.MemBuddy(_sub_arena(pool), SUB_POOL_SIZE)
test_value_print(sub)
sub = memhub.MemBuddy(_sub_arena(pool), SUB_POOL_SIZE)
test_build_add(sub)
sub = memhub.MemBuddy(_sub_arena(pool), SUB_POOL_SIZE)
test_build_if_else(sub)
sub = memhub.MemBuddy(_sub_arena(pool), SUB_POOL_SIZE)
test_build_void(sub)
sub = memhub.MemBuddy(_sub_arena(pool), SUB_POOL_SIZE)
test_module_print(sub)
sub = memhub.MemBuddy(_sub_arena(pool), SUB_POOL_SIZE)
test_const_materialize(sub)
sub = memhub.MemBuddy(_sub_arena(pool), SUB_POOL_SIZE)
test_phi_block_args(sub)
sub = memhub.MemBuddy(_sub_arena(pool), SUB_POOL_SIZE)
test_mem_call_cast(sub)
sub = memhub.MemBuddy(_sub_arena(pool), SUB_POOL_SIZE)
test_globals(sub)
sub = memhub.MemBuddy(_sub_arena(pool), SUB_POOL_SIZE)
test_verify_valid(sub)
sub = memhub.MemBuddy(_sub_arena(pool), SUB_POOL_SIZE)
test_struct_global(sub)
sub = memhub.MemBuddy(_sub_arena(pool), SUB_POOL_SIZE)
test_alloca_align_switch_asm(sub)
sub = memhub.MemBuddy(_sub_arena(pool), SUB_POOL_SIZE)
test_vararg_vaarg_cmpxchg(sub)
sub = memhub.MemBuddy(_sub_arena(pool), SUB_POOL_SIZE)
test_named_struct(sub)
sub = memhub.MemBuddy(_sub_arena(pool), SUB_POOL_SIZE)
test_extractvalue_multi_asm(sub)
return testcheck.end()