修正了一些错误
This commit is contained in:
@@ -126,19 +126,34 @@ class ArgumentParser:
|
||||
|
||||
def __new__(self, prog: str = "", description: str = "",
|
||||
pool: memhub.MemBuddy | t.CPtr = None) -> t.CPtr:
|
||||
stdio.printf("[DBG-argparse] __new__ enter pool=%p\n", pool)
|
||||
stdio.fflush(0)
|
||||
mb: memhub.MemBuddy | t.CPtr = pool
|
||||
if mb is None: mb = _mbuddy
|
||||
return mb.alloc(40)
|
||||
stdio.printf("[DBG-argparse] __new__ mb=%p\n", mb)
|
||||
stdio.fflush(0)
|
||||
ret: t.CPtr = mb.alloc(40)
|
||||
stdio.printf("[DBG-argparse] __new__ ret=%p\n", ret)
|
||||
stdio.fflush(0)
|
||||
return ret
|
||||
|
||||
def __init__(self, prog: str = "", description: str = "",
|
||||
pool: memhub.MemBuddy | t.CPtr = None):
|
||||
stdio.printf("[DBG-argparse] __init__ enter self=%p pool=%p\n", self, pool)
|
||||
stdio.fflush(0)
|
||||
mb: memhub.MemBuddy | t.CPtr = pool
|
||||
if mb is None: mb = _mbuddy
|
||||
stdio.printf("[DBG-argparse] __init__ mb=%p\n", mb)
|
||||
stdio.fflush(0)
|
||||
self.__mbuddy__ = mb
|
||||
self._prog = prog
|
||||
self._description = description
|
||||
self._arg_count = 0
|
||||
stdio.printf("[DBG-argparse] __init__ before alloc\n")
|
||||
stdio.fflush(0)
|
||||
self._args = mb.alloc(MAX_ARGS * Argument.__sizeof__())
|
||||
stdio.printf("[DBG-argparse] __init__ after alloc _args=%p\n", self._args)
|
||||
stdio.fflush(0)
|
||||
|
||||
def add_argument(self, name: str = "", short: str = None,
|
||||
arg_type: INT = 0, default: INT = 0,
|
||||
@@ -156,10 +171,18 @@ class ArgumentParser:
|
||||
action: 动作(STORE/STORE_TRUE/STORE_FALSE/COUNT)
|
||||
help: 帮助文本
|
||||
"""
|
||||
stdio.printf("[DBG-argparse] enter add_argument name=%s args_ptr=%p\n", name, self._args)
|
||||
stdio.fflush(0)
|
||||
if self._arg_count >= MAX_ARGS: return
|
||||
idx: INT = self._arg_count
|
||||
stdio.printf("[DBG-argparse] idx=%d sizeof(Argument)=%d\n", idx, Argument.__sizeof__())
|
||||
stdio.fflush(0)
|
||||
arg: Argument | t.CPtr = t.CPtr(t.CUInt64T(self._args) + idx * Argument.__sizeof__())
|
||||
stdio.printf("[DBG-argparse] arg ptr=%p\n", arg)
|
||||
stdio.fflush(0)
|
||||
arg.name = name
|
||||
stdio.printf("[DBG-argparse] after arg.name=%s\n", arg.name)
|
||||
stdio.fflush(0)
|
||||
arg.short_name = short
|
||||
arg.help_text = help
|
||||
arg.arg_type = arg_type
|
||||
@@ -167,6 +190,8 @@ class ArgumentParser:
|
||||
arg.default_int = default
|
||||
arg.default_str = default_str
|
||||
arg.required = required
|
||||
stdio.printf("[DBG-argparse] before dest logic\n")
|
||||
stdio.fflush(0)
|
||||
# 判断是否位置参数
|
||||
if name is not None and name[0] != '-':
|
||||
arg.is_positional = True
|
||||
@@ -177,7 +202,11 @@ class ArgumentParser:
|
||||
arg.dest = name + 2
|
||||
else:
|
||||
arg.dest = name + 1
|
||||
stdio.printf("[DBG-argparse] after dest logic\n")
|
||||
stdio.fflush(0)
|
||||
self._arg_count = idx + 1
|
||||
stdio.printf("[DBG-argparse] exit add_argument\n")
|
||||
stdio.fflush(0)
|
||||
|
||||
def _get_arg(self, idx: INT) -> Argument | t.CPtr:
|
||||
return t.CPtr(t.CUInt64T(self._args) + idx * Argument.__sizeof__())
|
||||
|
||||
@@ -439,6 +439,7 @@ def _parse_bitor(ps: Parser | t.CPtr) -> AST | t.CPtr:
|
||||
if left is None: return None
|
||||
while _match_op(ps, TokOp.VBar):
|
||||
_advance(ps)
|
||||
_skip_nl(ps)
|
||||
right: AST | t.CPtr = _parse_bitxor(ps)
|
||||
node: AST | t.CPtr = BinOp(ps.pool, left, OpKind.BitOr, right)
|
||||
_set_pos(node, left.lineno, left.col_offset, 0, 0)
|
||||
@@ -451,6 +452,7 @@ def _parse_bitxor(ps: Parser | t.CPtr) -> AST | t.CPtr:
|
||||
if left is None: return None
|
||||
while _match_op(ps, TokOp.Caret):
|
||||
_advance(ps)
|
||||
_skip_nl(ps)
|
||||
right: AST | t.CPtr = _parse_bitand(ps)
|
||||
node: AST | t.CPtr = BinOp(ps.pool, left, OpKind.BitXor, right)
|
||||
_set_pos(node, left.lineno, left.col_offset, 0, 0)
|
||||
@@ -463,6 +465,7 @@ def _parse_bitand(ps: Parser | t.CPtr) -> AST | t.CPtr:
|
||||
if left is None: return None
|
||||
while _match_op(ps, TokOp.Amp):
|
||||
_advance(ps)
|
||||
_skip_nl(ps)
|
||||
right: AST | t.CPtr = _parse_shift(ps)
|
||||
node: AST | t.CPtr = BinOp(ps.pool, left, OpKind.BitAnd, right)
|
||||
_set_pos(node, left.lineno, left.col_offset, 0, 0)
|
||||
@@ -476,6 +479,7 @@ def _parse_shift(ps: Parser | t.CPtr) -> AST | t.CPtr:
|
||||
while _match_op(ps, TokOp.LtLt) or _match_op(ps, TokOp.GtGt):
|
||||
op_token: t.CInt = _cur_op(ps)
|
||||
_advance(ps)
|
||||
_skip_nl(ps)
|
||||
right: AST | t.CPtr = _parse_arith(ps)
|
||||
ast_op: t.CInt = OpKind.LShift
|
||||
if op_token == TokOp.GtGt:
|
||||
@@ -492,6 +496,7 @@ def _parse_arith(ps: Parser | t.CPtr) -> AST | t.CPtr:
|
||||
while _match_op(ps, TokOp.Plus) or _match_op(ps, TokOp.Minus):
|
||||
op_token: t.CInt = _cur_op(ps)
|
||||
_advance(ps)
|
||||
_skip_nl(ps)
|
||||
right: AST | t.CPtr = _parse_term(ps)
|
||||
ast_op: t.CInt = OpKind.Add
|
||||
if op_token == TokOp.Minus:
|
||||
@@ -514,6 +519,7 @@ def _parse_term(ps: Parser | t.CPtr) -> AST | t.CPtr:
|
||||
elif _match_op(ps, TokOp.At): op_token = TokOp.At
|
||||
if op_token == 0: break
|
||||
_advance(ps)
|
||||
_skip_nl(ps)
|
||||
right: AST | t.CPtr = _parse_factor(ps)
|
||||
ast_op: t.CInt = _binop_from_op(op_token)
|
||||
node: AST | t.CPtr = BinOp(ps.pool, left, ast_op, right)
|
||||
@@ -1624,6 +1630,7 @@ def _parse_alias_list(ps: Parser | t.CPtr) -> list[AST | t.CPtr] | t.CPtr:
|
||||
names.append(a)
|
||||
if not _accept_op(ps, TokOp.Comma):
|
||||
break
|
||||
_skip_nl(ps)
|
||||
return names
|
||||
|
||||
|
||||
|
||||
@@ -3,6 +3,7 @@ from stdint import *
|
||||
import string
|
||||
import viperlib
|
||||
import memhub
|
||||
import stdio
|
||||
from linkedlist import GSListNode, GSList
|
||||
from .__types import LLVMType, TypePrint
|
||||
from .__values import Value, new_value, SSAValue
|
||||
@@ -145,6 +146,36 @@ def build_alloca(builder: IRBuilder | t.CPtr, ty: LLVMType | t.CPtr) -> Value |
|
||||
return SSAValue(pool, result_ty_ptr, name)
|
||||
|
||||
|
||||
def build_alloca_at_entry(builder: IRBuilder | t.CPtr, ty: LLVMType | t.CPtr) -> Value | t.CPtr:
|
||||
"""%N = alloca <ty>(在函数入口块生成,确保支配性)
|
||||
|
||||
在入口块的终止指令之前插入 alloca,避免在条件分支内生成 alloca
|
||||
导致的支配性违规(Instruction does not dominate all uses)。
|
||||
"""
|
||||
if builder is None: return None
|
||||
pool: memhub.MemBuddy | t.CPtr = builder.Pool
|
||||
func: Function | t.CPtr = builder.Func
|
||||
if func is None or func.Blocks is None:
|
||||
return build_alloca(builder, ty)
|
||||
entry_blk: BasicBlock | t.CPtr = func.Blocks.Head
|
||||
if entry_blk is None:
|
||||
return build_alloca(builder, ty)
|
||||
name: t.CChar | t.CPtr = _alloc_ssa_name(builder)
|
||||
ty_s: t.CChar | t.CPtr = _type_str(builder, ty)
|
||||
line_text: t.CChar | t.CPtr = pool.alloc(128)
|
||||
if line_text is None: return None
|
||||
viperlib.snprintf(line_text, 128, "%s = alloca %s", name, ty_s)
|
||||
# 在入口块终止指令之前插入
|
||||
block_insert_text_before_terminator(pool, entry_blk, line_text)
|
||||
# 结果类型是 ty*
|
||||
result_ty: LLVMType | t.CPtr = LLVMType.Ptr(ty)
|
||||
result_ty_ptr: LLVMType | t.CPtr = pool.alloc(LLVMType.__sizeof__())
|
||||
if result_ty_ptr is not None:
|
||||
string.memset(result_ty_ptr, 0, LLVMType.__sizeof__())
|
||||
c.DerefAs(result_ty_ptr, result_ty)
|
||||
return SSAValue(pool, result_ty_ptr, name)
|
||||
|
||||
|
||||
def build_load(builder: IRBuilder | t.CPtr, ty: LLVMType | t.CPtr,
|
||||
ptr: Value | t.CPtr) -> Value | t.CPtr:
|
||||
"""%N = load <ty>, <ptr_ty> <ptr>"""
|
||||
@@ -510,30 +541,30 @@ def build_call(builder: IRBuilder | t.CPtr, callee: t.CChar | t.CPtr,
|
||||
ret_ty_s: t.CChar | t.CPtr = _type_str(builder, ret_ty)
|
||||
|
||||
# 构建参数列表文本 + 变参函数类型签名
|
||||
args_buf: t.CChar | t.CPtr = pool.alloc(256)
|
||||
args_buf: t.CChar | t.CPtr = pool.alloc(1024)
|
||||
if args_buf is None: return None
|
||||
args_buf[0] = '\0'
|
||||
func_ty_buf: t.CChar | t.CPtr = pool.alloc(256)
|
||||
func_ty_buf: t.CChar | t.CPtr = pool.alloc(1024)
|
||||
if func_ty_buf is None: return None
|
||||
func_ty_buf[0] = '\0'
|
||||
cur: Value | t.CPtr = args
|
||||
first: t.CInt = 1
|
||||
while cur is not None:
|
||||
if first == 0:
|
||||
_append_cstr(args_buf, 256, ", ")
|
||||
_append_cstr(func_ty_buf, 256, ", ")
|
||||
_append_cstr(args_buf, 1024, ", ")
|
||||
_append_cstr(func_ty_buf, 1024, ", ")
|
||||
arg_ty_s: t.CChar | t.CPtr = _type_str(builder, cur.Ty)
|
||||
_append_cstr(args_buf, 256, arg_ty_s)
|
||||
_append_cstr(args_buf, 256, " ")
|
||||
_append_cstr(args_buf, 1024, arg_ty_s)
|
||||
_append_cstr(args_buf, 1024, " ")
|
||||
if cur.Name is not None:
|
||||
_append_cstr(args_buf, 256, cur.Name)
|
||||
_append_cstr(func_ty_buf, 256, arg_ty_s)
|
||||
_append_cstr(args_buf, 1024, cur.Name)
|
||||
_append_cstr(func_ty_buf, 1024, arg_ty_s)
|
||||
cur = cur.Next
|
||||
first = 0
|
||||
if is_variadic == 1:
|
||||
if first == 0:
|
||||
_append_cstr(func_ty_buf, 256, ", ")
|
||||
_append_cstr(func_ty_buf, 256, "...")
|
||||
_append_cstr(func_ty_buf, 1024, ", ")
|
||||
_append_cstr(func_ty_buf, 1024, "...")
|
||||
|
||||
# 构造带引号的 callee 名字(SHA1 前缀名含 '.' 或以数字开头需要加引号)
|
||||
callee_buf: t.CChar | t.CPtr = pool.alloc(128)
|
||||
@@ -546,18 +577,18 @@ def build_call(builder: IRBuilder | t.CPtr, callee: t.CChar | t.CPtr,
|
||||
else:
|
||||
_append_cstr(callee_buf, 128, callee)
|
||||
|
||||
line: t.CChar | t.CPtr = pool.alloc(512)
|
||||
line: t.CChar | t.CPtr = pool.alloc(2048)
|
||||
if line is None: return None
|
||||
if is_variadic == 1:
|
||||
if is_void == 1:
|
||||
viperlib.snprintf(line, 512, "call %s (%s) @%s(%s)", ret_ty_s, func_ty_buf, callee_buf, args_buf)
|
||||
viperlib.snprintf(line, 2048, "call %s (%s) @%s(%s)", ret_ty_s, func_ty_buf, callee_buf, args_buf)
|
||||
else:
|
||||
viperlib.snprintf(line, 512, "%s = call %s (%s) @%s(%s)", name, ret_ty_s, func_ty_buf, callee_buf, args_buf)
|
||||
viperlib.snprintf(line, 2048, "%s = call %s (%s) @%s(%s)", name, ret_ty_s, func_ty_buf, callee_buf, args_buf)
|
||||
else:
|
||||
if is_void == 1:
|
||||
viperlib.snprintf(line, 512, "call %s @%s(%s)", ret_ty_s, callee_buf, args_buf)
|
||||
viperlib.snprintf(line, 2048, "call %s @%s(%s)", ret_ty_s, callee_buf, args_buf)
|
||||
else:
|
||||
viperlib.snprintf(line, 512, "%s = call %s @%s(%s)", name, ret_ty_s, callee_buf, args_buf)
|
||||
viperlib.snprintf(line, 2048, "%s = call %s @%s(%s)", name, ret_ty_s, callee_buf, args_buf)
|
||||
_emit(builder, line)
|
||||
|
||||
if is_void == 1:
|
||||
@@ -594,28 +625,28 @@ def build_call_indirect(builder: IRBuilder | t.CPtr, callee_val: Value | t.CPtr,
|
||||
ret_ty_s: t.CChar | t.CPtr = _type_str(builder, ret_ty)
|
||||
|
||||
# 构建参数列表文本
|
||||
args_buf: t.CChar | t.CPtr = pool.alloc(256)
|
||||
args_buf: t.CChar | t.CPtr = pool.alloc(1024)
|
||||
if args_buf is None: return None
|
||||
args_buf[0] = '\0'
|
||||
cur: Value | t.CPtr = args
|
||||
first: t.CInt = 1
|
||||
while cur is not None:
|
||||
if first == 0:
|
||||
_append_cstr(args_buf, 256, ", ")
|
||||
_append_cstr(args_buf, 1024, ", ")
|
||||
arg_ty_s: t.CChar | t.CPtr = _type_str(builder, cur.Ty)
|
||||
_append_cstr(args_buf, 256, arg_ty_s)
|
||||
_append_cstr(args_buf, 256, " ")
|
||||
_append_cstr(args_buf, 1024, arg_ty_s)
|
||||
_append_cstr(args_buf, 1024, " ")
|
||||
if cur.Name is not None:
|
||||
_append_cstr(args_buf, 256, cur.Name)
|
||||
_append_cstr(args_buf, 1024, cur.Name)
|
||||
cur = cur.Next
|
||||
first = 0
|
||||
|
||||
line: t.CChar | t.CPtr = pool.alloc(512)
|
||||
line: t.CChar | t.CPtr = pool.alloc(2048)
|
||||
if line is None: return None
|
||||
if is_void == 1:
|
||||
viperlib.snprintf(line, 512, "call %s %s(%s)", ret_ty_s, callee_val.Name, args_buf)
|
||||
viperlib.snprintf(line, 2048, "call %s %s(%s)", ret_ty_s, callee_val.Name, args_buf)
|
||||
else:
|
||||
viperlib.snprintf(line, 512, "%s = call %s %s(%s)", name, ret_ty_s, callee_val.Name, args_buf)
|
||||
viperlib.snprintf(line, 2048, "%s = call %s %s(%s)", name, ret_ty_s, callee_val.Name, args_buf)
|
||||
_emit(builder, line)
|
||||
|
||||
if is_void == 1:
|
||||
@@ -885,17 +916,27 @@ def build_gep_struct(builder: IRBuilder | t.CPtr, struct_ty: LLVMType | t.CPtr,
|
||||
struct_ty_s: t.CChar | t.CPtr = _type_str(builder, struct_ty)
|
||||
ptr_ty_s: t.CChar | t.CPtr = _type_str(builder, ptr.Ty)
|
||||
line: t.CChar | t.CPtr = pool.alloc(2048)
|
||||
if line is None: return None
|
||||
if line is None:
|
||||
stdio.printf("[BGS] line alloc None\n")
|
||||
stdio.fflush(0)
|
||||
return None
|
||||
viperlib.snprintf(line, 2048, "%s = getelementptr %s, %s %s, i32 0, i32 %d",
|
||||
name, struct_ty_s, ptr_ty_s, ptr.Name, field_idx)
|
||||
_emit(builder, line)
|
||||
|
||||
# GEP 结果类型是 field_ty*
|
||||
result_ty: LLVMType | t.CPtr = pool.alloc(LLVMType.__sizeof__())
|
||||
if result_ty is not None:
|
||||
if result_ty is None:
|
||||
stdio.printf("[BGS] result_ty alloc None\n")
|
||||
stdio.fflush(0)
|
||||
else:
|
||||
string.memset(result_ty, 0, LLVMType.__sizeof__())
|
||||
c.DerefAs(result_ty, LLVMType.Ptr(field_ty))
|
||||
return SSAValue(pool, result_ty, name)
|
||||
rv: Value | t.CPtr = SSAValue(pool, result_ty, name)
|
||||
if rv is None:
|
||||
stdio.printf("[BGS] SSAValue None\n")
|
||||
stdio.fflush(0)
|
||||
return rv
|
||||
|
||||
|
||||
# ============================================================
|
||||
@@ -938,34 +979,35 @@ def build_phi(builder: IRBuilder | t.CPtr, ty: LLVMType | t.CPtr,
|
||||
ty_s: t.CChar | t.CPtr = _type_str(builder, ty)
|
||||
|
||||
# 构建入边列表文本: [val, %blk], [val, %blk], ...
|
||||
parts: t.CChar | t.CPtr = pool.alloc(512)
|
||||
# 入边可能很多(如 30+ 个 or 链的 bool.merge),需要大缓冲区
|
||||
parts: t.CChar | t.CPtr = pool.alloc(4096)
|
||||
if parts is None: return None
|
||||
parts[0] = '\0'
|
||||
cur: PhiIncoming | t.CPtr = incoming_head
|
||||
first: t.CInt = 1
|
||||
while cur is not None:
|
||||
if first == 0:
|
||||
_append_cstr(parts, 512, ", ")
|
||||
_append_cstr(parts, 512, "[")
|
||||
_append_cstr(parts, 4096, ", ")
|
||||
_append_cstr(parts, 4096, "[")
|
||||
# 使用中间变量避免链式结构体成员访问被编译器丢弃
|
||||
inc_val: Value | t.CPtr = cur.Val
|
||||
if inc_val is not None:
|
||||
inc_val_name: t.CChar | t.CPtr = inc_val.Name
|
||||
if inc_val_name is not None:
|
||||
_append_cstr(parts, 512, inc_val_name)
|
||||
_append_cstr(parts, 512, ", %")
|
||||
_append_cstr(parts, 4096, inc_val_name)
|
||||
_append_cstr(parts, 4096, ", %")
|
||||
inc_blk: BasicBlock | t.CPtr = cur.Block
|
||||
if inc_blk is not None:
|
||||
inc_blk_name: t.CChar | t.CPtr = inc_blk.Name
|
||||
if inc_blk_name is not None:
|
||||
_append_cstr(parts, 512, inc_blk_name)
|
||||
_append_cstr(parts, 512, "]")
|
||||
_append_cstr(parts, 4096, inc_blk_name)
|
||||
_append_cstr(parts, 4096, "]")
|
||||
cur = cur.Next
|
||||
first = 0
|
||||
|
||||
line: t.CChar | t.CPtr = pool.alloc(640)
|
||||
line: t.CChar | t.CPtr = pool.alloc(8192)
|
||||
if line is None: return None
|
||||
viperlib.snprintf(line, 640, "%s = phi %s %s", name, ty_s, parts)
|
||||
viperlib.snprintf(line, 8192, "%s = phi %s %s", name, ty_s, parts)
|
||||
_emit(builder, line)
|
||||
return SSAValue(pool, ty, name)
|
||||
|
||||
|
||||
@@ -227,6 +227,48 @@ def block_append_text(pool: memhub.MemBuddy | t.CPtr, block: BasicBlock | t.CPtr
|
||||
block_append_line(block, line)
|
||||
|
||||
|
||||
def block_insert_text_before_terminator(pool: memhub.MemBuddy | t.CPtr,
|
||||
block: BasicBlock | t.CPtr,
|
||||
text: t.CChar | t.CPtr):
|
||||
"""创建指令行并插入到基本块终止指令之前
|
||||
|
||||
如果块未终止,追加到末尾。
|
||||
如果块已终止(有 br/ret),在终止指令之前插入,确保 alloca 等指令
|
||||
不出现在终止指令之后。
|
||||
"""
|
||||
if block is None or text is None: return
|
||||
if block.Lines is None: return
|
||||
line: Line | t.CPtr = new_line(pool, text)
|
||||
if line is None: return
|
||||
# 块未终止:直接追加
|
||||
if block.IsTerminated == 0:
|
||||
block_append_line(block, line)
|
||||
return
|
||||
# 块已终止:在 Tail(终止指令)之前插入
|
||||
lines: GSList[Line] | t.CPtr = block.Lines
|
||||
if lines.Head is None:
|
||||
block_append_line(block, line)
|
||||
return
|
||||
# 只有一个节点:在 Head 之前插入
|
||||
if lines.Head is lines.Tail:
|
||||
line.Next = lines.Head
|
||||
lines.Head = line
|
||||
lines.Count += 1
|
||||
return
|
||||
# 找到 Tail 的前驱节点
|
||||
prev: Line | t.CPtr = lines.Head
|
||||
while prev is not None and prev.Next is not lines.Tail:
|
||||
prev = prev.Next
|
||||
if prev is None:
|
||||
# 找不到前驱,回退到追加
|
||||
block_append_line(block, line)
|
||||
return
|
||||
# 在 prev 和 Tail 之间插入 line
|
||||
line.Next = lines.Tail
|
||||
prev.Next = line
|
||||
lines.Count += 1
|
||||
|
||||
|
||||
# ============================================================
|
||||
# 属性设置
|
||||
# ============================================================
|
||||
@@ -276,6 +318,259 @@ def _ll_name_needs_quote(name: str) -> t.CInt:
|
||||
return 0
|
||||
|
||||
|
||||
# ============================================================
|
||||
# RenumberSSA: 重编号函数内数字 SSA 名
|
||||
#
|
||||
# 解决 build_alloca_at_entry 在入口块终止指令前插入 alloca 导致
|
||||
# SSA 名在文本输出中非单调递增的问题(llc 报错:
|
||||
# "instruction expected to be numbered '%N' or greater")。
|
||||
#
|
||||
# 现象: entry 块原指令 %0-%6 + br,alloca_at_entry 插入 %28/%41 到 br 之前,
|
||||
# 文本输出顺序为 entry(%0..%6, %28, %41) → if.then(%7..%27),
|
||||
# 导致 %28 出现在 %7 之前,llc 拒绝编译。
|
||||
#
|
||||
# 算法:
|
||||
# 1. 扫描所有 BB 指令行,按文本输出顺序收集数字 SSA 名 %N
|
||||
# 2. 按首次出现顺序建立 old→new 映射(从 0 递增)
|
||||
# 3. 替换所有指令行文本中的 %N 为新编号
|
||||
#
|
||||
# 注意:
|
||||
# - 仅重编号纯数字 SSA 名(%0, %1, ...)
|
||||
# - 命名 SSA 名(%entry, %.tmp, %self)、块标签、全局符号 @N 不重编号
|
||||
# - 仅对 define(有函数体)调用,declare 无函数体无需处理
|
||||
# - 当前 TransPyV 参数多为命名(%self/%env/%n),非数字,无需重编号参数
|
||||
# ============================================================
|
||||
|
||||
# 判定字符是否为十进制数字
|
||||
def _is_digit_ch(ch: t.CChar) -> t.CInt:
|
||||
"""判断字符是否是 '0'-'9'
|
||||
|
||||
ch 是值类型 (t.CChar = i8),TPC 已修复值类型 is None 处理:
|
||||
值类型 is None 恒为 false(生成 i1 0 常量),不会解引用空指针。
|
||||
"""
|
||||
if ch is None:
|
||||
return 0
|
||||
if ch >= '0' and ch <= '9':
|
||||
return 1
|
||||
return 0
|
||||
|
||||
|
||||
# ============================================================
|
||||
# i32 数组的安全访问(显式字节偏移)
|
||||
#
|
||||
# TransPyC 的 ptr[i] 指针索引可能被当作字节索引(i8*)而非 i32* 索引,
|
||||
# 导致内存损坏。必须显式计算字节偏移:addr = base + idx * 4,再转型为 i32*。
|
||||
# 参见 HandlesTranslator.py:358 的 t.CUInt64T(ptr) + offset * sizeof 用法。
|
||||
# ============================================================
|
||||
def _map_get_i32(map_arr: t.CChar | t.CPtr, idx: t.CInt) -> t.CInt:
|
||||
"""读取 i32 数组 map_arr[idx](显式字节偏移 idx*4)
|
||||
|
||||
使用 (t.CInt | t.CPtr)(uint64) 强转将字节偏移转为 i32*,再用 c.Deref 解引用。
|
||||
TPC 已修复类型联合强转(_HandleTypeUnionCastLlvm 添加 fallback),此写法可用。
|
||||
"""
|
||||
if map_arr is None:
|
||||
return -1
|
||||
byte_off: t.CUInt64T = t.CUInt64T(map_arr) + idx * 4
|
||||
elem_ptr: t.CInt | t.CPtr = (t.CInt | t.CPtr)(byte_off)
|
||||
return c.Deref(elem_ptr)
|
||||
|
||||
|
||||
def _map_set_i32(map_arr: t.CChar | t.CPtr, idx: t.CInt, val: t.CInt):
|
||||
"""写入 map_arr[idx] = val(i32 数组,显式字节偏移 idx*4)
|
||||
|
||||
使用 (t.CInt | t.CPtr)(uint64) 强转 + c.DerefAs 解引用赋值。
|
||||
TPC 已修复类型联合强转,此写法可用。
|
||||
"""
|
||||
if map_arr is None:
|
||||
return
|
||||
byte_off: t.CUInt64T = t.CUInt64T(map_arr) + idx * 4
|
||||
elem_ptr: t.CInt | t.CPtr = (t.CInt | t.CPtr)(byte_off)
|
||||
c.DerefAs(elem_ptr, val)
|
||||
|
||||
|
||||
def _scan_max_ssa_in_text(text: t.CChar | t.CPtr, cur_max: t.CInt) -> t.CInt:
|
||||
"""扫描文本,找出 %N(N 为数字)中最大的 N,与 cur_max 比较返回更大值
|
||||
|
||||
仅匹配 '%' 后紧跟数字的情况,跳过命名 SSA 名(%entry 等)。
|
||||
"""
|
||||
result: t.CInt = cur_max
|
||||
p: t.CChar | t.CPtr = text
|
||||
while p is not None and p[0] != '\0':
|
||||
if p[0] == '%':
|
||||
nxt: t.CChar | t.CPtr = p + 1
|
||||
if nxt is not None and _is_digit_ch(nxt[0]) != 0:
|
||||
num: t.CInt = string.atoi(nxt)
|
||||
if num > result:
|
||||
result = num
|
||||
p = p + 1
|
||||
return result
|
||||
|
||||
|
||||
def _find_max_ssa_number(func: Function | t.CPtr) -> t.CInt:
|
||||
"""遍历所有 BB 指令行,找出最大的 %N 数字;无数字 SSA 名返回 -1"""
|
||||
max_n: t.CInt = -1
|
||||
if func is None or func.Blocks is None:
|
||||
return max_n
|
||||
blk: BasicBlock | t.CPtr = func.Blocks.Head
|
||||
while blk is not None:
|
||||
if blk.Lines is not None:
|
||||
line: Line | t.CPtr = blk.Lines.Head
|
||||
while line is not None:
|
||||
if line.Buf is not None:
|
||||
max_n = _scan_max_ssa_in_text(line.Buf, max_n)
|
||||
line = line.Next
|
||||
blk = blk.Next
|
||||
return max_n
|
||||
|
||||
|
||||
def _assign_new_numbers(text: t.CChar | t.CPtr,
|
||||
map_arr: t.CChar | t.CPtr,
|
||||
max_n: t.CInt, next_new: t.CInt) -> t.CInt:
|
||||
"""扫描文本,对每个 %N(数字),若 map_arr[N]==-1 则分配 next_new
|
||||
|
||||
返回更新后的 next_new。按文本首次出现顺序建立映射。
|
||||
"""
|
||||
result: t.CInt = next_new
|
||||
p: t.CChar | t.CPtr = text
|
||||
while p is not None and p[0] != '\0':
|
||||
if p[0] == '%':
|
||||
nxt: t.CChar | t.CPtr = p + 1
|
||||
if nxt is not None and _is_digit_ch(nxt[0]) != 0:
|
||||
num: t.CInt = string.atoi(nxt)
|
||||
if num >= 0 and num <= max_n:
|
||||
if _map_get_i32(map_arr, num) == -1:
|
||||
_map_set_i32(map_arr, num, result)
|
||||
result += 1
|
||||
p = p + 1
|
||||
return result
|
||||
|
||||
|
||||
def _replace_ssa_numbers(text: t.CChar | t.CPtr,
|
||||
pool: memhub.MemBuddy | t.CPtr,
|
||||
map_arr: t.CChar | t.CPtr,
|
||||
max_n: t.CInt) -> t.CChar | t.CPtr:
|
||||
"""构建新文本,将 %N 替换为映射后的新编号
|
||||
|
||||
逐字符扫描:遇到 %N(数字)查映射表替换,其他字符原样复制。
|
||||
返回新分配的缓冲区(调用方无需释放旧 Buf,pool 统一管理)。
|
||||
"""
|
||||
src_len: t.CSizeT = string.strlen(text)
|
||||
# 新缓冲区:最坏情况每个数字变长(位数增加),分配 src_len*2 + 64
|
||||
new_size: t.CSizeT = src_len * 2 + 64
|
||||
new_buf: t.CChar | t.CPtr = pool.alloc(new_size)
|
||||
if new_buf is None:
|
||||
return None
|
||||
# 一次性分配数字缓冲区(循环中复用)
|
||||
num_buf: t.CChar | t.CPtr = pool.alloc(16)
|
||||
if num_buf is None:
|
||||
new_buf[0] = '\0'
|
||||
return new_buf
|
||||
|
||||
dst_idx: t.CSizeT = 0
|
||||
src_p: t.CChar | t.CPtr = text
|
||||
while src_p is not None and src_p[0] != '\0':
|
||||
if dst_idx + 16 >= new_size:
|
||||
# 缓冲区不足,截断
|
||||
break
|
||||
if src_p[0] == '%':
|
||||
nxt: t.CChar | t.CPtr = src_p + 1
|
||||
if nxt is not None and _is_digit_ch(nxt[0]) != 0:
|
||||
num: t.CInt = string.atoi(nxt)
|
||||
new_num: t.CInt = _map_get_i32(map_arr, num)
|
||||
if num >= 0 and num <= max_n and new_num != -1:
|
||||
# 写入 '%'
|
||||
new_buf[dst_idx] = '%'
|
||||
dst_idx += 1
|
||||
# 写入新编号
|
||||
num_buf[0] = '\0'
|
||||
viperlib.snprintf(num_buf, 16, "%d", new_num)
|
||||
k: t.CSizeT = 0
|
||||
while num_buf[k] != '\0' and dst_idx + 1 < new_size:
|
||||
new_buf[dst_idx] = num_buf[k]
|
||||
dst_idx += 1
|
||||
k += 1
|
||||
# 跳过旧数字字符
|
||||
src_p = src_p + 1
|
||||
while src_p is not None and _is_digit_ch(src_p[0]) != 0:
|
||||
src_p = src_p + 1
|
||||
continue
|
||||
# 普通字符:直接复制
|
||||
new_buf[dst_idx] = src_p[0]
|
||||
dst_idx += 1
|
||||
src_p = src_p + 1
|
||||
|
||||
new_buf[dst_idx] = '\0'
|
||||
return new_buf
|
||||
|
||||
|
||||
def RenumberSSA(func: Function | t.CPtr, pool: memhub.MemBuddy | t.CPtr):
|
||||
"""重编号函数内所有数字 SSA 名,确保按文本输出顺序单调递增
|
||||
|
||||
在 FunctionPrint 序列化函数体之前调用。
|
||||
仅对 define(IsDeclared==0)且 Blocks 非空 的函数生效。
|
||||
"""
|
||||
if func is None or pool is None:
|
||||
return
|
||||
if func.IsDeclared == 1:
|
||||
return # declare 无函数体
|
||||
if func.Blocks is None:
|
||||
return
|
||||
|
||||
# 1. 第一遍扫描:找出最大 SSA 编号
|
||||
max_n: t.CInt = _find_max_ssa_number(func)
|
||||
if max_n < 0:
|
||||
return # 无数字 SSA 名
|
||||
|
||||
# 2. 分配并初始化映射数组 map_arr[0..max_n] = -1
|
||||
# 用 i8* 存储(pool.alloc 返回 i8*),通过 _map_get_i32/_map_set_i32 访问。
|
||||
# 初始化为 -1:每个 i32 元素 4 字节,0xFFFFFFFF = -1(有符号 i32)。
|
||||
# 用 memset 一次性填充,避免循环内 ptr[i] 指针索引问题。
|
||||
map_bytes: t.CSizeT = (max_n + 1) * 4 # t.CInt = 4 字节
|
||||
map_arr: t.CChar | t.CPtr = pool.alloc(map_bytes)
|
||||
if map_arr is None:
|
||||
return
|
||||
string.memset(map_arr, 0xFF, map_bytes) # 0xFF * 4 = 0xFFFFFFFF = -1
|
||||
|
||||
# 3. 第二遍扫描:按文本顺序分配新编号
|
||||
next_new: t.CInt = 0
|
||||
blk: BasicBlock | t.CPtr = func.Blocks.Head
|
||||
while blk is not None:
|
||||
if blk.Lines is not None:
|
||||
line: Line | t.CPtr = blk.Lines.Head
|
||||
while line is not None:
|
||||
if line.Buf is not None:
|
||||
next_new = _assign_new_numbers(line.Buf, map_arr, max_n, next_new)
|
||||
line = line.Next
|
||||
blk = blk.Next
|
||||
|
||||
# 4. 检查是否有需要重编号的(old != new)
|
||||
need_renumber: t.CInt = 0
|
||||
i: t.CInt = 0
|
||||
while i <= max_n:
|
||||
v: t.CInt = _map_get_i32(map_arr, i)
|
||||
if v != -1 and v != i:
|
||||
need_renumber = 1
|
||||
break
|
||||
i += 1
|
||||
if need_renumber == 0:
|
||||
return # 编号已单调,无需替换
|
||||
|
||||
# 5. 第三遍扫描:替换所有指令行文本
|
||||
blk = func.Blocks.Head
|
||||
while blk is not None:
|
||||
if blk.Lines is not None:
|
||||
line: Line | t.CPtr = blk.Lines.Head
|
||||
while line is not None:
|
||||
if line.Buf is not None:
|
||||
new_buf: t.CChar | t.CPtr = _replace_ssa_numbers(
|
||||
line.Buf, pool, map_arr, max_n)
|
||||
if new_buf is not None:
|
||||
line.Buf = new_buf
|
||||
line.Len = string.strlen(new_buf)
|
||||
line = line.Next
|
||||
blk = blk.Next
|
||||
|
||||
|
||||
# ============================================================
|
||||
# FunctionPrint: 将函数序列化为 IR 文本
|
||||
#
|
||||
@@ -293,6 +588,12 @@ def FunctionPrint(buf: t.CChar | t.CPtr, size: t.CSizeT,
|
||||
"""将函数 func 序列化为 IR 文本写入 buf"""
|
||||
if func is None or buf is None or size == 0: return
|
||||
|
||||
# 在序列化前重编号数字 SSA 名,确保按文本输出顺序单调递增。
|
||||
# 解决 build_alloca_at_entry 在入口块终止指令前插入 alloca 导致
|
||||
# SSA 名非单调(llc 报错 "instruction expected to be numbered '%N' or greater")。
|
||||
# RenumberSSA 内部会跳过 declare 函数(IsDeclared==1),无需在此判断。
|
||||
RenumberSSA(func, pool)
|
||||
|
||||
ty_buf: t.CChar | t.CPtr = pool.alloc(128)
|
||||
if ty_buf is None: return
|
||||
ty_buf[0] = '\0'
|
||||
@@ -371,12 +672,22 @@ def FunctionPrint(buf: t.CChar | t.CPtr, size: t.CSizeT,
|
||||
line: Line | t.CPtr = None
|
||||
if blk.Lines is not None:
|
||||
line = blk.Lines.Head
|
||||
has_lines: t.CInt = 0
|
||||
while line is not None:
|
||||
if line.Buf is not None:
|
||||
_append_cstr(buf, size, " ")
|
||||
_append_cstr(buf, size, line.Buf)
|
||||
_append_cstr(buf, size, "\n")
|
||||
has_lines = 1
|
||||
line = line.Next
|
||||
# 块未终止兜底:LLVM IR 要求每个基本块以终止指令(br/ret/unreachable)结尾。
|
||||
# 两种情况需要补 unreachable:
|
||||
# 1. 空块(has_lines==0):标签后无任何指令
|
||||
# 2. 有指令但未终止(IsTerminated==0):如 break/continue 后的 dead.N 块
|
||||
# 被后续语句填入指令但缺少终止符,导致下一个标签处报
|
||||
# "expected instruction opcode"
|
||||
if has_lines == 0 or blk.IsTerminated == 0:
|
||||
_append_cstr(buf, size, " unreachable\n")
|
||||
blk = blk.Next
|
||||
|
||||
_append_cstr(buf, size, "}\n")
|
||||
|
||||
@@ -39,7 +39,8 @@ from .__module import (
|
||||
)
|
||||
from .__builder import (
|
||||
IRBuilder, new_builder, position_at_end,
|
||||
build_alloca, build_load, build_store,
|
||||
builder_cur_block_is_terminated,
|
||||
build_alloca, build_alloca_at_entry, build_load, build_store,
|
||||
build_add, build_sub, build_mul, build_sdiv, build_udiv, build_srem, build_urem,
|
||||
build_and, build_or, build_xor, build_shl, build_lshr, build_ashr,
|
||||
build_fadd, build_fsub, build_fmul, build_fdiv, build_frem, build_fneg,
|
||||
|
||||
@@ -5,7 +5,7 @@ import stdio
|
||||
import viperlib
|
||||
import memhub
|
||||
from linkedlist import GSList, GSListNode
|
||||
from .__types import LLVMType, TypePrint, Array, PrintStructDefinition, get_struct_name, Struct
|
||||
from .__types import LLVMType, TypePrint, Array, PrintStructDefinition, get_struct_name, Struct, ParamNode
|
||||
from .__function import Function, FunctionPrint, _ll_name_needs_quote, Param
|
||||
|
||||
|
||||
@@ -150,39 +150,82 @@ def module_set_datalayout(mod: LLVMModule | t.CPtr, layout: t.CChar | t.CPtr):
|
||||
# ============================================================
|
||||
# 命名结构体类型管理
|
||||
# ============================================================
|
||||
|
||||
# ============================================================
|
||||
# _is_opaque_struct - 检查类型是否是 opaque 结构体
|
||||
#
|
||||
# opaque 结构体特征: Struct 类型,字段数为 0 且字段列表为 None。
|
||||
# 通过 Struct(pool, None, 0, name) 创建,IR 输出为 %"name" = type opaque。
|
||||
# 用于在 module_add_named_type 中区分 opaque 声明和完整定义,
|
||||
# 确保 opaque 声明插入链表头部(在使用之前声明)。
|
||||
#
|
||||
# Returns: 1=是 opaque / 0=否
|
||||
# ============================================================
|
||||
def _is_opaque_struct(ty: LLVMType | t.CPtr) -> int:
|
||||
"""检查类型是否是 opaque 结构体(无字段的命名结构体)"""
|
||||
if ty is None:
|
||||
return 0
|
||||
match ty:
|
||||
case LLVMType.Struct(fields, fcount, name):
|
||||
# opaque: 字段数为 0 且字段列表为 None
|
||||
if fcount == 0 and fields is None:
|
||||
return 1
|
||||
return 0
|
||||
case _:
|
||||
return 0
|
||||
|
||||
|
||||
def module_add_named_type(mod: LLVMModule | t.CPtr, pool: memhub.MemBuddy | t.CPtr,
|
||||
ty: LLVMType | t.CPtr):
|
||||
"""将命名结构体类型添加到模块(用于输出 %"name" = type { ... } 定义行)
|
||||
|
||||
非命名结构体(Name 为 None 或非 Struct 类型)会被忽略。
|
||||
按 Name 去重,相同名称的类型只保留第一个。
|
||||
按 Name 去重;同名时 opaque 声明可被完整定义替换(供跨模块值类型 alloca)。
|
||||
"""
|
||||
if mod is None or pool is None or ty is None:
|
||||
return
|
||||
name: t.CChar | t.CPtr = get_struct_name(ty)
|
||||
if name is None:
|
||||
return
|
||||
# 去重检查
|
||||
# 去重检查(opaque 声明可被完整定义替换)
|
||||
cur: NamedTypeNode | t.CPtr = mod.NamedTypeHead
|
||||
while cur is not None:
|
||||
if cur.Ty is not None:
|
||||
existing_name: t.CChar | t.CPtr = get_struct_name(cur.Ty)
|
||||
if existing_name is not None:
|
||||
if string.strcmp(existing_name, name) == 0:
|
||||
# 已有完整定义则无需替换
|
||||
if _is_opaque_struct(cur.Ty) == 0:
|
||||
return
|
||||
# 已有 opaque,新类型也是 opaque 则不重复
|
||||
if _is_opaque_struct(ty) != 0:
|
||||
return
|
||||
# 用完整定义替换 opaque 声明(原地替换 Ty 指针)
|
||||
cur.Ty = ty
|
||||
return
|
||||
cur = cur.Next
|
||||
# 创建新节点并追加到链表尾部
|
||||
# 创建新节点
|
||||
node: NamedTypeNode | t.CPtr = pool.alloc(NAMED_TYPE_NODE_SIZE)
|
||||
if node is None:
|
||||
return
|
||||
string.memset(node, 0, NAMED_TYPE_NODE_SIZE)
|
||||
node.Ty = ty
|
||||
node.Next = None
|
||||
if mod.NamedTypeHead is None:
|
||||
# opaque 类型插入链表头部,确保在引用它的完整定义之前声明。
|
||||
# 例如 TypeRegistry{HashTable*, ...} 中,HashTable 的 opaque 声明
|
||||
# 必须在 TypeRegistry 定义之前,否则 llc 报 "use of undefined type"。
|
||||
# 完整定义追加到链表尾部,保持原有顺序。
|
||||
if _is_opaque_struct(ty) != 0:
|
||||
node.Next = mod.NamedTypeHead
|
||||
if mod.NamedTypeHead is None:
|
||||
mod.NamedTypeTail = node
|
||||
mod.NamedTypeHead = node
|
||||
else:
|
||||
mod.NamedTypeTail.Next = node
|
||||
mod.NamedTypeTail = node
|
||||
node.Next = None
|
||||
if mod.NamedTypeHead is None:
|
||||
mod.NamedTypeHead = node
|
||||
else:
|
||||
mod.NamedTypeTail.Next = node
|
||||
mod.NamedTypeTail = node
|
||||
mod.NamedTypeCount += 1
|
||||
|
||||
|
||||
@@ -228,8 +271,24 @@ def _scan_type_for_cross_module_refs(pool: memhub.MemBuddy | t.CPtr,
|
||||
opaque_ty: LLVMType | t.CPtr = Struct(pool, None, 0, sname)
|
||||
if opaque_ty is not None:
|
||||
module_add_named_type(mod, pool, opaque_ty)
|
||||
# 递归扫描结构体字段中的跨模块引用
|
||||
# 例如 TypeRegistry{HashTable*, MemManager*} 中的 HashTable 引用
|
||||
if sfields is not None:
|
||||
fld: ParamNode | t.CPtr = sfields
|
||||
while fld is not None:
|
||||
if fld.Ty is not None:
|
||||
_scan_type_for_cross_module_refs(pool, mod, fld.Ty)
|
||||
fld = fld.Next
|
||||
case _:
|
||||
_scan_type_for_cross_module_refs(pool, mod, pointee)
|
||||
case LLVMType.Struct(sfields2, sfcount2, sname2):
|
||||
# 顶层结构体(非指针):递归扫描字段
|
||||
if sfields2 is not None:
|
||||
fld2: ParamNode | t.CPtr = sfields2
|
||||
while fld2 is not None:
|
||||
if fld2.Ty is not None:
|
||||
_scan_type_for_cross_module_refs(pool, mod, fld2.Ty)
|
||||
fld2 = fld2.Next
|
||||
case LLVMType.Array(elem_ty, acount):
|
||||
if elem_ty is not None:
|
||||
_scan_type_for_cross_module_refs(pool, mod, elem_ty)
|
||||
@@ -333,12 +392,14 @@ def LLVMModulePrint(buf: t.CChar | t.CPtr, size: t.CSizeT,
|
||||
param_scan = param_scan.Next
|
||||
func_scan = func_scan.Next
|
||||
nt: NamedTypeNode | t.CPtr = mod.NamedTypeHead
|
||||
# 结构体定义缓冲区:48 字段 × ~50 字节/字段类型名 ≈ 2400 字节,4096 足够
|
||||
# 在循环外分配一次并复用,减少 pool 碎片
|
||||
ty_buf: t.CChar | t.CPtr = pool.alloc(4096)
|
||||
while nt is not None:
|
||||
if nt.Ty is not None:
|
||||
ty_buf: t.CChar | t.CPtr = pool.alloc(256)
|
||||
if ty_buf is not None:
|
||||
ty_buf[0] = '\0'
|
||||
PrintStructDefinition(ty_buf, 256, nt.Ty, pool)
|
||||
PrintStructDefinition(ty_buf, 4096, nt.Ty, pool)
|
||||
_append_cstr(buf, size, ty_buf)
|
||||
_append_cstr(buf, size, "\n")
|
||||
nt = nt.Next
|
||||
|
||||
@@ -3,6 +3,7 @@ from stdint import *
|
||||
import viperlib
|
||||
import string
|
||||
import memhub
|
||||
import stdio
|
||||
from linkedlist import GSListNode
|
||||
|
||||
|
||||
@@ -371,7 +372,15 @@ def TypePrint(buf: t.CChar | t.CPtr, size: t.CSizeT,
|
||||
case LLVMType.Int(bits):
|
||||
viperlib.snprintf(buf, size, "i%d", bits)
|
||||
case LLVMType.Ptr(pointee):
|
||||
# 先打印 pointee,再追加 '*'
|
||||
# 快速路径: Ptr(Struct(name)) → %"name"*
|
||||
# 使用 snprintf 一次性格式化,避免递归 TypePrint + _strappend 导致的截断
|
||||
if pointee is not None:
|
||||
match pointee:
|
||||
case LLVMType.Struct(sfields, sfcount, sname):
|
||||
if sname is not None:
|
||||
viperlib.snprintf(buf, size, "%%\"%s\"*", sname)
|
||||
return
|
||||
# 通用路径: 递归打印 pointee 后追加 '*'
|
||||
TypePrint(buf, size, pointee, pool)
|
||||
pos: t.CSizeT = string.strlen(buf)
|
||||
if pos + 1 < size:
|
||||
@@ -380,19 +389,17 @@ def TypePrint(buf: t.CChar | t.CPtr, size: t.CSizeT,
|
||||
case LLVMType.Array(elem_ty, count):
|
||||
# [N x elem_ty]
|
||||
viperlib.snprintf(buf, size, "[%d x ", count)
|
||||
tmp: t.CChar | t.CPtr = pool.alloc(128)
|
||||
# SHA1 限定类型名(如 %"21a7fcfc665f75ef.NamedTypeNode")可达 ~50 字节,
|
||||
# 嵌套指针/数组更易超过 128,使用 512 字节避免截断
|
||||
tmp: t.CChar | t.CPtr = pool.alloc(512)
|
||||
if tmp is not None:
|
||||
TypePrint(tmp, 128, elem_ty, pool)
|
||||
TypePrint(tmp, 512, elem_ty, pool)
|
||||
_strappend(buf, size, tmp)
|
||||
_strappend(buf, size, "]")
|
||||
case LLVMType.Struct(fields, fcount, name):
|
||||
if name is not None:
|
||||
# 命名结构体: %"name"
|
||||
buf[0] = '%'
|
||||
buf[1] = '"'
|
||||
buf[2] = '\0'
|
||||
_strappend(buf, size, name)
|
||||
_strappend(buf, size, "\"")
|
||||
viperlib.snprintf(buf, size, "%%\"%s\"", name)
|
||||
else:
|
||||
# 匿名结构体: {ty1, ty2, ...}
|
||||
_print_struct_body(buf, size, fields, pool)
|
||||
@@ -402,12 +409,13 @@ def TypePrint(buf: t.CChar | t.CPtr, size: t.CSizeT,
|
||||
_strappend(buf, size, " (")
|
||||
cur2: ParamNode | t.CPtr = params
|
||||
first2: t.CInt = 1
|
||||
tmp3: t.CChar | t.CPtr = pool.alloc(128)
|
||||
# 函数参数类型可能为 SHA1 限定命名结构体指针,512 字节避免截断
|
||||
tmp3: t.CChar | t.CPtr = pool.alloc(512)
|
||||
while cur2 is not None:
|
||||
if first2 == 0:
|
||||
_strappend(buf, size, ", ")
|
||||
if tmp3 is not None:
|
||||
TypePrint(tmp3, 128, cur2.Ty, pool)
|
||||
TypePrint(tmp3, 512, cur2.Ty, pool)
|
||||
_strappend(buf, size, tmp3)
|
||||
cur2 = cur2.Next
|
||||
first2 = 0
|
||||
@@ -457,21 +465,28 @@ def _strappend(dst: t.CChar | t.CPtr, dst_size: t.CSizeT, src: t.CChar | t.CPtr)
|
||||
# ============================================================
|
||||
def _print_struct_body(buf: t.CChar | t.CPtr, size: t.CSizeT,
|
||||
fields: ParamNode | t.CPtr, pool: memhub.MemBuddy | t.CPtr):
|
||||
"""打印 {ty1, ty2, ...} 到 buf(追加模式,不覆盖已有内容)"""
|
||||
"""打印 {ty1, ty2, ...} 到 buf(追加模式,不覆盖已有内容)
|
||||
|
||||
直接在 buf 当前末尾写入字段类型,避免 pool.alloc 返回与 buf 重叠的内存
|
||||
导致 TypePrint 写入 tmp 时覆盖 buf 已有内容。
|
||||
"""
|
||||
if buf is None or size == 0:
|
||||
return
|
||||
_strappend(buf, size, "{")
|
||||
cur: ParamNode | t.CPtr = fields
|
||||
first: t.CInt = 1
|
||||
tmp: t.CChar | t.CPtr = pool.alloc(128)
|
||||
fidx: t.CInt = 0
|
||||
while cur is not None:
|
||||
if first == 0:
|
||||
_strappend(buf, size, ", ")
|
||||
if tmp is not None:
|
||||
TypePrint(tmp, 128, cur.Ty, pool)
|
||||
_strappend(buf, size, tmp)
|
||||
# 直接在 buf 当前末尾位置写入字段类型
|
||||
# TypePrint 首字节置 '\0' 是无害的(pos 处本来就是 '\0')
|
||||
pos: t.CSizeT = string.strlen(buf)
|
||||
if pos + 2 < size:
|
||||
TypePrint(buf + pos, size - pos, cur.Ty, pool)
|
||||
cur = cur.Next
|
||||
first = 0
|
||||
fidx += 1
|
||||
_strappend(buf, size, "}")
|
||||
|
||||
|
||||
@@ -493,15 +508,12 @@ def PrintStructDefinition(buf: t.CChar | t.CPtr, size: t.CSizeT,
|
||||
case LLVMType.Struct(fields, fcount, name):
|
||||
if name is None:
|
||||
return
|
||||
buf[0] = '%'
|
||||
buf[1] = '"'
|
||||
buf[2] = '\0'
|
||||
_strappend(buf, size, name)
|
||||
# 使用 snprintf 构建 "%%"name" = type" 前缀,避免 _strappend 截断
|
||||
# opaque 类型: fcount==0 且 fields is None(跨模块前向声明)
|
||||
if fcount == 0 and fields is None:
|
||||
_strappend(buf, size, "\" = type opaque")
|
||||
viperlib.snprintf(buf, size, "%%\"%s\" = type opaque", name)
|
||||
else:
|
||||
_strappend(buf, size, "\" = type ")
|
||||
viperlib.snprintf(buf, size, "%%\"%s\" = type ", name)
|
||||
_print_struct_body(buf, size, fields, pool)
|
||||
case _:
|
||||
return
|
||||
|
||||
@@ -429,6 +429,13 @@ class MemBuddy(MemManager):
|
||||
if block is not None:
|
||||
c.DerefAs(block, t.CVoid(t.CUInt64T((order << 1) | 1), t.CPtr))
|
||||
result = t.CVoid(t.CUInt64T(block) + MEMBUDDY_HEADER_SIZE, t.CPtr)
|
||||
if result is None:
|
||||
# 分配失败: 打印内存使用情况
|
||||
fb: t.CSizeT = self.free_bytes()
|
||||
ub: t.CSizeT = self.usable_size - fb
|
||||
stdio.printf("[MEM-FAIL] alloc(%zu) failed: total=%zu used=%zu free=%zu free_blocks=%zu\n",
|
||||
size, self.usable_size, ub, fb, self.free_count())
|
||||
stdio.fflush(0)
|
||||
self._unlock()
|
||||
return result
|
||||
|
||||
@@ -503,6 +510,32 @@ class MemBuddy(MemManager):
|
||||
cur = t.CVoid(c.Deref(t.CUInt64T(cur, t.CPtr)), t.CPtr)
|
||||
return count
|
||||
|
||||
def free_bytes(self) -> t.CSizeT:
|
||||
# 统计所有空闲块的总字节数
|
||||
total: t.CSizeT = 0
|
||||
i: t.CInt
|
||||
for i in range(MEMBUDDY_MAX_ORDERS + 1):
|
||||
head_val: t.CUInt64T = self.free_lists[i]
|
||||
cur: t.CVoid | t.CPtr = t.CVoid(head_val, t.CPtr)
|
||||
while t.CUInt64T(cur) != 0:
|
||||
total += _block_size_at_order(i)
|
||||
cur = t.CVoid(c.Deref(t.CUInt64T(cur, t.CPtr)), t.CPtr)
|
||||
return total
|
||||
|
||||
def used_bytes(self) -> t.CSizeT:
|
||||
# 已使用字节数 = 可用区总大小 - 空闲字节数
|
||||
return self.usable_size - self.free_bytes()
|
||||
|
||||
def dump_stats(self, label: t.CChar | t.CPtr):
|
||||
# 打印内存使用统计
|
||||
fb: t.CSizeT = self.free_bytes()
|
||||
ub: t.CSizeT = self.usable_size - fb
|
||||
stdio.printf("[MEM] %s: total=%zu used=%zu (%zu%%) free=%zu free_blocks=%zu\n",
|
||||
label, self.usable_size, ub,
|
||||
(ub * 100) / self.usable_size if self.usable_size > 0 else 0,
|
||||
fb, self.free_count())
|
||||
stdio.fflush(0)
|
||||
|
||||
def self_check(self) -> t.CInt:
|
||||
# 验证伙伴分配器内部一致性,返回 0=OK,非 0=损坏
|
||||
if self.usable is None:
|
||||
|
||||
@@ -51,6 +51,9 @@ class File:
|
||||
self.is_append = False
|
||||
self._share_mode = share
|
||||
|
||||
stdio.printf("[FILE] __init__ filename=%s mode=%d share=%d\n", filename, mode, share)
|
||||
stdio.fflush(0)
|
||||
|
||||
access: ULONG = 0
|
||||
disposition: ULONG = w32.win32file.OPEN_EXISTING
|
||||
|
||||
@@ -97,12 +100,18 @@ class File:
|
||||
disposition = w32.win32file.OPEN_EXISTING
|
||||
self.can_read = True
|
||||
|
||||
stdio.printf("[FILE] before CreateFileA access=%d disp=%d share=%d\n", access, disposition, self._share_mode)
|
||||
stdio.fflush(0)
|
||||
self.handle = w32.win32file.CreateFileA(
|
||||
filename, access, self._share_mode,
|
||||
None, disposition, w32.win32file.FILE_ATTRIBUTE_NORMAL, None
|
||||
)
|
||||
stdio.printf("[FILE] after CreateFileA handle=%p\n", self.handle)
|
||||
stdio.fflush(0)
|
||||
|
||||
if self.handle == w32.win32base.INVALID_HANDLE_VALUE:
|
||||
stdio.printf("[FILE] FAIL: handle == INVALID_HANDLE_VALUE\n")
|
||||
stdio.fflush(0)
|
||||
self.closed = True
|
||||
return
|
||||
|
||||
|
||||
@@ -5,7 +5,7 @@ HANDLE: t.CTypedef = VOIDPTR
|
||||
LPCSTR: t.CTypedef = t.CConst | t.CChar | t.CPtr
|
||||
LPCWSTR: t.CTypedef = t.CConst | t.CUnsignedShort | t.CPtr
|
||||
|
||||
INVALID_HANDLE_VALUE: t.CDefine = t.CVoid(-1)
|
||||
INVALID_HANDLE_VALUE: t.CDefine = 0xFFFFFFFF
|
||||
NULL: t.CDefine = 0
|
||||
TRUE: t.CDefine = 1
|
||||
FALSE: t.CDefine = 0
|
||||
|
||||
Reference in New Issue
Block a user