- c.Addr(Call) 分支:求值存临时槽(entry alloca)返回槽地址,
供 coerce 指针→结构体 load 就地解读(Coroutine={__ptr__} 8 字节)
- 协程登记扩展:c.Addr(async_call) 也登记 _coro_var_async
- 新增 _coro_frame_ptr_from_arg 统一提取帧指针:pointee 是 Struct
(Coroutine 变量,translate_value 返回 alloca 地址)GEP __ptr__ load,
普通指针 bitcast 直通;5 处拦截函数(run/destroy/exception/msg/gather)替换
1423 lines
73 KiB
Plaintext
1423 lines
73 KiB
Plaintext
import lib.core.Gen.GenTypes as GenTypes
|
||
import t, c
|
||
from stdint import *
|
||
import ast
|
||
import llvmlite
|
||
import memhub
|
||
import string
|
||
import stdio
|
||
import stdlib
|
||
import sys
|
||
import viperlib
|
||
import w32.fileio as fileio
|
||
import lib.core.VLogger as VLogger
|
||
import lib.core.Handles.HandlesBase as HandlesBase
|
||
import lib.core.Handles.HandlesTranslator as HT
|
||
import lib.core.Handles.HandlesExpr as HandlesExpr
|
||
import lib.core.StubMerger as StubMerger
|
||
import lib.core.Handles.HandlesExprCall as HandlesExprCall
|
||
import lib.core.CompilerFactory as CompilerFactory
|
||
|
||
|
||
import lib.core.Gen.CallGenBase as CallGenBase
|
||
|
||
|
||
# ============================================================
|
||
# CallGenCBuiltin - CallGenMixin 拆分 2/9:c.* 内建 + asm + llvmir
|
||
#
|
||
# 按功能域从 CallGenMixin.vp 拆出(500~1500 行/文件架构重构):
|
||
# translate_c_deref/derefas/set/addr/load + c.Asm 全套 + c.LLVMIR。
|
||
# 继承 CallGenBase。
|
||
#
|
||
# @t.NoVTable:静态绑定(方法沿 MRO 直接调用 + this 调整)。
|
||
# ============================================================
|
||
|
||
|
||
# ============================================================
|
||
# _IsTypeExpr / _IsCastWrappingDeref - c.Deref 加载宽度推断的转换包裹判定
|
||
# (镜像 TPC HandlesSpecialCall:转换链包裹 Deref 时允许从赋值注解推断
|
||
# 加载宽度;ifexp/binop 包裹不放行,避免 i8* 错 bitcast 成其他位宽读)
|
||
# ============================================================
|
||
def _IsTypeExpr(node: ast.AST | t.CPtr) -> int:
|
||
"""节点是否为类型表达式(Name/Attribute/Subscript/BinOp|)"""
|
||
if node is None:
|
||
return 0
|
||
k: int = node.kind()
|
||
if k == ast.ASTKind.Name or k == ast.ASTKind.Attribute or k == ast.ASTKind.Subscript:
|
||
return 1
|
||
if k == ast.ASTKind.BinOp:
|
||
bop: ast.BinOp | t.CPtr = (ast.BinOp | t.CPtr)(node)
|
||
if bop.op == ast.OpKind.BitOr:
|
||
return 1
|
||
return 0
|
||
|
||
|
||
def _IsCastWrappingDeref(rhs: ast.AST | t.CPtr, deref_node: ast.AST | t.CPtr) -> int:
|
||
"""rhs 是否为"类型转换链包裹 c.Deref"(如 (T | t.CPtr)(t.CPtr(c.Deref(p))))"""
|
||
if rhs is None:
|
||
return 0
|
||
if t.CUInt64T(rhs) == t.CUInt64T(deref_node):
|
||
return 1
|
||
if rhs.kind() == ast.ASTKind.Call:
|
||
cl: ast.Call | t.CPtr = (ast.Call | t.CPtr)(rhs)
|
||
if cl.args is not None and len(cl.args) == 1 and _IsTypeExpr(cl.func) != 0:
|
||
return _IsCastWrappingDeref(cl.args.get(0), deref_node)
|
||
return 0
|
||
|
||
|
||
# ============================================================
|
||
# 常量(与 HandlesExprCall 保持一致,本地副本避免跨模块 CDefine 查找 bug)
|
||
# ============================================================
|
||
GLOBAL_FUNC_MAX: t.CDefine = 8192
|
||
GLOBAL_DEFAULTS_MAX: t.CDefine = 4096
|
||
_CEXPORT_MAX: t.CDefine = 256
|
||
ASM_MAX_OPERANDS: t.CDefine = 16
|
||
ASM_TEXT_BUF_SIZE: t.CDefine = 2048
|
||
ASM_CONST_BUF_SIZE: t.CDefine = 512
|
||
ASM_ARGS_BUF_SIZE: t.CDefine = 512
|
||
ASM_LINE_BUF_SIZE: t.CDefine = 4096
|
||
LLVMIR_MAX_OPS: t.CDefine = 16
|
||
LLVMIR_TEMPLATE_BUF: t.CDefine = 512
|
||
# 闭包名表大小(原 HandlesExprCall 模块级常量)
|
||
MAX_CLOSURE_NAMES: t.CDefine = 128
|
||
# 函数指针签名表大小(原 HandlesExprCall 模块级常量)
|
||
MAX_FUNC_PTR_SIGS: t.CDefine = 64
|
||
# isinstance 子类收集上限(防数组越界;t.CDefine 注解由 TPC 解析为 i32)
|
||
ISINSTANCE_CLASS_MAX: t.CDefine = 64
|
||
|
||
|
||
# ============================================================
|
||
# CallGenCBuiltin - c.*/asm/llvmir 内建
|
||
# ============================================================
|
||
@t.NoVTable
|
||
class CallGenCBuiltin(CallGenBase.CallGenBase):
|
||
"""c.* 内建 + 内联汇编 + LLVMIR 翻译(继承 Base)"""
|
||
|
||
|
||
def translate_c_deref(self, pool: memhub.MemBuddy | t.CPtr,
|
||
builder: llvmlite.IRBuilder | t.CPtr,
|
||
mod: llvmlite.LLVMModule | t.CPtr,
|
||
cl: ast.Call | t.CPtr,
|
||
trans: HT.Translator | t.CPtr = None) -> llvmlite.Value | t.CPtr:
|
||
"""c.Deref(ptr) → load 按 ptr 的 pointee 类型"""
|
||
if cl is None:
|
||
return None
|
||
cargs: list[ast.AST | t.CPtr] | t.CPtr = cl.args
|
||
if cargs is None or len(cargs) < 1:
|
||
return None
|
||
|
||
ptr_val: llvmlite.Value | t.CPtr = self.Gen.ExprGen.translate_value(
|
||
builder, pool, mod, cargs.get(0), None, 0, trans)
|
||
if ptr_val is None:
|
||
return None
|
||
|
||
# 按 pointee 类型读取;非指针参数默认按 i8(保持向后兼容)
|
||
if self.Gen.ExprGenBase.is_ptr_type(ptr_val.Ty) != 0:
|
||
pointee: llvmlite.LLVMType | t.CPtr = ptr_val.Ty.Pointee
|
||
if pointee is not None:
|
||
# i8*(void*)时按赋值目标类型推断读取宽度(对齐 TPC
|
||
# HandlesSpecialCall._infer_deref_target_type):
|
||
# v: int = c.Deref(p) → bitcast i32* 后 load 4 字节。
|
||
# 背景:DictTest d3[key5]=500 读出 -12——固定按 i8 读 1 字节 +
|
||
# sext 截断(0xF4 → 0xFFFFFFF4);Test 1 的小值(10)恰好正确
|
||
# 掩盖了缺陷。
|
||
match pointee:
|
||
case llvmlite.LLVMType.Int(pointee_width):
|
||
# 允许推断:c.Deref 是赋值语句直接 RHS(v: int = c.Deref(p))
|
||
# 或处于类型转换链包裹中(如 vt: t.CVoid | t.CPtr =
|
||
# t.CVoid(c.Deref(p)))。嵌套在 while 条件/比较/binop/
|
||
# 其他调用中(如 while c.Deref(p) != 0、total +=
|
||
# t.CInt(c.Deref(p)))不推断,否则 i8* 会被残留
|
||
# CurAssignAnnot 误判为 i32* 读 4 字节 → StringIterTest
|
||
# ASCII sum/manual strcmp 失败。
|
||
allow_infer: int = 0
|
||
if trans is not None and trans.CurAssignNode is not None:
|
||
if t.CUInt64T(cl) == t.CUInt64T(trans.CurAssignNode):
|
||
allow_infer = 1
|
||
elif _IsCastWrappingDeref(trans.CurAssignNode, cl) != 0:
|
||
allow_infer = 1
|
||
if pointee_width == 8 and allow_infer != 0 \
|
||
and trans is not None and trans.CurAssignAnnot is not None:
|
||
dref_ty: llvmlite.LLVMType | t.CPtr = self.Gen.TypeGenResolve.resolve_annotation_type(
|
||
trans.Pool, trans.CurAssignAnnot,
|
||
trans._imported_modules, trans._from_imports, trans)
|
||
if dref_ty is not None:
|
||
dref_bits: int = self.Gen.ExprGenBase.get_llvm_type_bits(dref_ty)
|
||
dref_fbits: int = self.Gen.ExprGenBase.get_llvm_float_bits(dref_ty)
|
||
dref_is_ptr: int = self.Gen.ExprGenBase.is_ptr_type(dref_ty)
|
||
# 整数/浮点/指针目标均推断(指针 → bitcast 后
|
||
# load 8 字节;struct 值目标不推断,保持 i8 读)
|
||
dref_ptr: llvmlite.Value | t.CPtr = None
|
||
if (dref_bits != 0 or dref_fbits != 0 or dref_is_ptr != 0) \
|
||
and dref_bits != 8:
|
||
dref_ptr_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, dref_ty)
|
||
dref_ptr = llvmlite.build_bitcast(
|
||
builder, ptr_val, dref_ptr_ty)
|
||
if dref_ptr is not None:
|
||
return llvmlite.build_load(builder, dref_ty, dref_ptr)
|
||
case _:
|
||
pass
|
||
return llvmlite.build_load(builder, pointee, ptr_val)
|
||
# 非指针参数即类型推断退化:fail-fast,绝不按 i8 兜底读取(会读到垃圾宽度)
|
||
self.Gen.TypeGenErr.fatal_error(cl, "c.Deref 参数不是指针类型(类型推断退化)", "TypeError")
|
||
return None
|
||
|
||
|
||
def translate_c_derefas(self, pool: memhub.MemBuddy | t.CPtr,
|
||
builder: llvmlite.IRBuilder | t.CPtr,
|
||
mod: llvmlite.LLVMModule | t.CPtr,
|
||
cl: ast.Call | t.CPtr,
|
||
trans: HT.Translator | t.CPtr = None) -> llvmlite.Value | t.CPtr:
|
||
"""c.DerefAs(ptr, val) → store val to ptr(bitcast 后 store)"""
|
||
if cl is None:
|
||
return None
|
||
cargs: list[ast.AST | t.CPtr] | t.CPtr = cl.args
|
||
if cargs is None or len(cargs) < 2:
|
||
return None
|
||
|
||
ptr_val: llvmlite.Value | t.CPtr = self.Gen.ExprGen.translate_value(
|
||
builder, pool, mod, cargs.get(0), None, 0, trans)
|
||
val: llvmlite.Value | t.CPtr = self.Gen.ExprGen.translate_value(
|
||
builder, pool, mod, cargs.get(1), None, 0, trans)
|
||
if ptr_val is None or val is None:
|
||
return None
|
||
|
||
# 两端均为指向同一结构体类型的指针时执行结构体拷贝(*ptr = *val),
|
||
# 而非存储指针值。这对 REnum 变体构造(c.DerefAs(ptr, LLVMType.Int(32)))至关重要:
|
||
# LLVMType.Int(32) 构造返回 alloca 指针(Ptr(LLVMType)),若直接 store 指针值,
|
||
# 只写入 8 字节指针(tag 字段仍是 0x0),导致运行时读 tag 错乱。
|
||
# 对应 TPC HandlesExprCall.py:3696-3701 的 struct 拷贝逻辑。
|
||
if self.Gen.ExprGenBase.is_ptr_type(ptr_val.Ty) != 0 and self.Gen.ExprGenBase.is_ptr_type(val.Ty) != 0:
|
||
ptr_pointee: llvmlite.LLVMType | t.CPtr = ptr_val.Ty.Pointee
|
||
val_pointee: llvmlite.LLVMType | t.CPtr = val.Ty.Pointee
|
||
if ptr_pointee is not None and val_pointee is not None:
|
||
# ptr_pointee 是已注册结构体类型(用 find_struct_by_type 判断)
|
||
if self.Gen.StructGen.find_struct_by_type(ptr_pointee) is not None:
|
||
if ptr_pointee is val_pointee:
|
||
# 同一结构体类型:load 值再 store(结构体拷贝)
|
||
loaded: llvmlite.Value | t.CPtr = llvmlite.build_load(
|
||
builder, val_pointee, val)
|
||
if loaded is not None:
|
||
# bitcast ptr 到结构体指针再 store
|
||
struct_ptr_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(
|
||
pool, ptr_pointee)
|
||
casted_ptr: llvmlite.Value | t.CPtr = llvmlite.build_bitcast(
|
||
builder, ptr_val, struct_ptr_ty)
|
||
if casted_ptr is not None:
|
||
llvmlite.build_store(builder, loaded, casted_ptr)
|
||
return val
|
||
|
||
# bitcast ptr 到 val.Ty* 再 store
|
||
val_ptr_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, val.Ty)
|
||
casted_ptr: llvmlite.Value | t.CPtr = llvmlite.build_bitcast(builder, ptr_val, val_ptr_ty)
|
||
if casted_ptr is None:
|
||
return None
|
||
llvmlite.build_store(builder, val, casted_ptr)
|
||
return val
|
||
|
||
|
||
def translate_c_set(self, pool: memhub.MemBuddy | t.CPtr,
|
||
builder: llvmlite.IRBuilder | t.CPtr,
|
||
mod: llvmlite.LLVMModule | t.CPtr,
|
||
cl: ast.Call | t.CPtr,
|
||
trans: HT.Translator | t.CPtr = None) -> llvmlite.Value | t.CPtr:
|
||
"""c.Set(a, b) → a = b(赋值语义,a 为左值)"""
|
||
if cl is None:
|
||
return None
|
||
cargs: list[ast.AST | t.CPtr] | t.CPtr = cl.args
|
||
if cargs is None or len(cargs) < 2:
|
||
return None
|
||
a_node: ast.AST | t.CPtr = cargs.get(0)
|
||
b_val: llvmlite.Value | t.CPtr = self.Gen.ExprGen.translate_value(
|
||
builder, pool, mod, cargs.get(1), None, 0, trans)
|
||
if b_val is None:
|
||
return None
|
||
|
||
# 形态 1: c.Set(c.Deref(ptr), b) → *ptr = b
|
||
if a_node is not None and a_node.kind() == ast.ASTKind.Call:
|
||
d_call: ast.Call | t.CPtr = (ast.Call | t.CPtr)(a_node)
|
||
if d_call.func is not None and d_call.func.kind() == ast.ASTKind.Attribute:
|
||
d_at: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(d_call.func)
|
||
if d_at.attr is not None and string.strcmp(d_at.attr, "Deref") == 0:
|
||
d_args: list[ast.AST | t.CPtr] | t.CPtr = d_call.args
|
||
if d_args is not None and len(d_args) >= 1:
|
||
ptr_val: llvmlite.Value | t.CPtr = self.Gen.ExprGen.translate_value(
|
||
builder, pool, mod, d_args.get(0), None, 0, trans)
|
||
if ptr_val is not None:
|
||
val_ptr_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, b_val.Ty)
|
||
casted_ptr: llvmlite.Value | t.CPtr = llvmlite.build_bitcast(
|
||
builder, ptr_val, val_ptr_ty)
|
||
if casted_ptr is not None:
|
||
llvmlite.build_store(builder, b_val, casted_ptr)
|
||
return b_val
|
||
# 其他 Call 形态不可作左值
|
||
return b_val
|
||
|
||
# 形态 2: Name 变量赋值
|
||
if a_node is not None and a_node.kind() == ast.ASTKind.Name and trans is not None:
|
||
nm_set: ast.Name | t.CPtr = (ast.Name | t.CPtr)(a_node)
|
||
if nm_set.id is not None:
|
||
if HT.is_global_name(trans, nm_set.id) != 0:
|
||
mod_alloca: llvmlite.Value | t.CPtr = self.Gen.VarGen.lookup_module_var(
|
||
trans.SymTab, nm_set.id)
|
||
if mod_alloca is not None:
|
||
tg_ty: llvmlite.LLVMType | t.CPtr = None
|
||
if mod_alloca.Ty is not None:
|
||
tg_ty = mod_alloca.Ty.Pointee
|
||
sv: llvmlite.Value | t.CPtr = b_val
|
||
if tg_ty is not None:
|
||
sv = self.Gen.ExprGenBase.coerce_to_type(builder, b_val, tg_ty, a_node)
|
||
llvmlite.build_store(builder, sv, mod_alloca)
|
||
return b_val
|
||
if HT.is_nonlocal_name(trans, nm_set.id) != 0:
|
||
nl_ptr: llvmlite.Value | t.CPtr = self.Gen.StmtGenDecl.get_nonlocal_var_ptr(
|
||
trans, nm_set.id)
|
||
if nl_ptr is not None:
|
||
nl_ty: llvmlite.LLVMType | t.CPtr = None
|
||
if nl_ptr.Ty is not None:
|
||
nl_ty = nl_ptr.Ty.Pointee
|
||
sv2: llvmlite.Value | t.CPtr = b_val
|
||
if nl_ty is not None:
|
||
sv2 = self.Gen.ExprGenBase.coerce_to_type(builder, b_val, nl_ty, a_node)
|
||
llvmlite.build_store(builder, sv2, nl_ptr)
|
||
return b_val
|
||
alloca: llvmlite.Value | t.CPtr = self.Gen.VarGen.get_or_create_sym(
|
||
trans.SymTab, pool, builder, nm_set.id, b_val.Ty)
|
||
if alloca is not None:
|
||
ac_ty: llvmlite.LLVMType | t.CPtr = None
|
||
if alloca.Ty is not None:
|
||
ac_ty = alloca.Ty.Pointee
|
||
sv3: llvmlite.Value | t.CPtr = b_val
|
||
if ac_ty is not None:
|
||
sv3 = self.Gen.ExprGenBase.coerce_to_type(builder, b_val, ac_ty, a_node)
|
||
llvmlite.build_store(builder, sv3, alloca)
|
||
return b_val
|
||
return b_val
|
||
|
||
# 形态 3: Attribute 字段赋值
|
||
if a_node is not None and a_node.kind() == ast.ASTKind.Attribute:
|
||
field_ptr: llvmlite.Value | t.CPtr = self.Gen.ExprGenAttr.get_attribute_ptr(
|
||
builder, pool, mod, a_node, trans)
|
||
if field_ptr is not None:
|
||
fd_ty: llvmlite.LLVMType | t.CPtr = None
|
||
if field_ptr.Ty is not None:
|
||
fd_ty = field_ptr.Ty.Pointee
|
||
sv4: llvmlite.Value | t.CPtr = b_val
|
||
if fd_ty is not None:
|
||
sv4 = self.Gen.ExprGenBase.coerce_to_type(builder, b_val, fd_ty, a_node)
|
||
llvmlite.build_store(builder, sv4, field_ptr)
|
||
return b_val
|
||
|
||
return b_val
|
||
|
||
|
||
def translate_c_addr(self, pool: memhub.MemBuddy | t.CPtr,
|
||
builder: llvmlite.IRBuilder | t.CPtr,
|
||
mod: llvmlite.LLVMModule | t.CPtr,
|
||
cl: ast.Call | t.CPtr,
|
||
trans: HT.Translator | t.CPtr = None) -> llvmlite.Value | t.CPtr:
|
||
"""c.Addr(var) → 返回变量的 alloca 指针(不 load)"""
|
||
if cl is None:
|
||
return None
|
||
cargs: list[ast.AST | t.CPtr] | t.CPtr = cl.args
|
||
if cargs is None or len(cargs) < 1:
|
||
return None
|
||
|
||
arg0: ast.AST | t.CPtr = cargs.get(0)
|
||
if arg0 is None:
|
||
return None
|
||
|
||
# Name 形式: c.Addr(var) → 返回变量的 alloca 指针(不 load)
|
||
if arg0.kind() == ast.ASTKind.Name:
|
||
nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(arg0)
|
||
if nm.id is None:
|
||
return None
|
||
if trans is not None:
|
||
# self/cls 对象引用:c.Addr(self) 返回对象指针本身(Ptr(Struct)),
|
||
# 而非指针变量的地址(Ptr(Ptr(Struct)))。方法与 Attribute 分支
|
||
# (c.Addr(self.field) 先 load self)语义一致,供
|
||
# return t.CVoid(c.Addr(self), CPtr) 返回 this 使用。
|
||
if string.strcmp(nm.id, "self") == 0 or string.strcmp(nm.id, "cls") == 0:
|
||
self_entry: GenTypes.VarEntry | t.CPtr = self.Gen.VarGen.lookup_var_entry(
|
||
trans.SymTab, nm.id)
|
||
if self_entry is not None and self_entry.Alloca is not None and self_entry.Alloca.Ty is not None:
|
||
match self_entry.Alloca.Ty:
|
||
case llvmlite.LLVMType.Ptr(inner1):
|
||
match inner1:
|
||
case llvmlite.LLVMType.Ptr(inner2):
|
||
obj_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, inner2)
|
||
return llvmlite.build_load(builder, obj_ty, self_entry.Alloca)
|
||
case _:
|
||
pass
|
||
case _:
|
||
pass
|
||
return_var: llvmlite.Value | t.CPtr = self.Gen.VarGen.lookup_var(trans.SymTab, nm.id)
|
||
if return_var is not None and return_var.Ty is not None:
|
||
# 对象指针变量(如 lit_tree = zhuff.zhuff_tree(),alloca 是
|
||
# Ptr(Ptr(Struct)),存对象指针):c.Addr(对象变量) 应返回对象
|
||
# 指针本身(load 一次),对齐 self/cls 分支与 c.Addr(self.field)
|
||
# (GEP 后对象地址)。此前直接返回 &变量(Ptr(Ptr(Struct)))→
|
||
# 调用端 bitcast 成 Ptr(Struct) 后 ht 指向指针变量存储 → 字段
|
||
# 读到指针值/垃圾 → build_decode_tree 越界崩溃
|
||
# (zinflate inflate_block_fixed 的 c.Addr(lit_tree) 根因)。
|
||
match return_var.Ty:
|
||
case llvmlite.LLVMType.Ptr(addr_inner1):
|
||
match addr_inner1:
|
||
case llvmlite.LLVMType.Ptr(addr_inner2):
|
||
match addr_inner2:
|
||
case llvmlite.LLVMType.Struct(_, _, _):
|
||
addr_obj_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, addr_inner2)
|
||
return llvmlite.build_load(builder, addr_obj_ty, return_var)
|
||
case _:
|
||
pass
|
||
case _:
|
||
pass
|
||
case _:
|
||
pass
|
||
return return_var
|
||
|
||
# Attribute 形式: c.Addr(self.field) → 取字段地址(GEP 到字段,不 load)
|
||
# 用于 atom.__atomic_test_and_set(c.Addr(self.lock_val), ...) 等锁操作
|
||
if arg0.kind() == ast.ASTKind.Attribute:
|
||
if trans is None:
|
||
return None
|
||
at_addr: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(arg0)
|
||
if at_addr is None or at_addr.attr is None or at_addr.value is None:
|
||
return None
|
||
# 解析 self(Name)→ 查找 alloca
|
||
if at_addr.value.kind() != ast.ASTKind.Name:
|
||
return None
|
||
self_nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(at_addr.value)
|
||
if self_nm.id is None:
|
||
return None
|
||
self_alloca: llvmlite.Value | t.CPtr = self.Gen.VarGen.lookup_var(
|
||
trans.SymTab, self_nm.id)
|
||
if self_alloca is None or self_alloca.Ty is None:
|
||
return None
|
||
# 从 self 类型提取结构体类型(Ptr(Struct) 或 Ptr(Ptr(Struct)))
|
||
struct_ty: llvmlite.LLVMType | t.CPtr = None
|
||
self_is_ptr_ptr: int = 0
|
||
match self_alloca.Ty:
|
||
case llvmlite.LLVMType.Ptr(inner1):
|
||
match inner1:
|
||
case llvmlite.LLVMType.Ptr(inner2):
|
||
struct_ty = inner2
|
||
self_is_ptr_ptr = 1
|
||
case _:
|
||
struct_ty = inner1
|
||
case _:
|
||
return None
|
||
# 查找字段
|
||
fe_addr: GenTypes.FieldEntry | t.CPtr = self.Gen.StructGen.lookup_field(
|
||
struct_ty, at_addr.attr)
|
||
if fe_addr is None:
|
||
return None
|
||
# self_alloca 是 Ptr(Ptr(Struct)) 时先 load 成 Ptr(Struct) 对象指针
|
||
obj_ptr: llvmlite.Value | t.CPtr = self_alloca
|
||
if self_is_ptr_ptr == 1:
|
||
self_obj_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, struct_ty)
|
||
obj_ptr = llvmlite.build_load(builder, self_obj_ty, self_alloca)
|
||
if obj_ptr is None:
|
||
return None
|
||
# GEP 到字段地址
|
||
return llvmlite.build_gep_struct(
|
||
builder, struct_ty, fe_addr.Ty, obj_ptr, fe_addr.Index)
|
||
|
||
# Subscript 形式: c.Addr(arr[i]) → 数组元素地址(GEP 数组,不 load)
|
||
# 用于 self.root_directory = c.Addr(directories[directory_count]) 等。
|
||
# 此前只支持 Name/Attribute,Subscript 落到函数末尾返回 None →
|
||
# 赋值右侧为 None(devfs.vp:159 根因)。
|
||
if arg0.kind() == ast.ASTKind.Subscript:
|
||
if trans is None:
|
||
return None
|
||
sub_addr: ast.Subscript | t.CPtr = (ast.Subscript | t.CPtr)(arg0)
|
||
if sub_addr is None or sub_addr.value is None or sub_addr.slice is None:
|
||
return None
|
||
arr_val: llvmlite.Value | t.CPtr = self.Gen.ExprGen.translate_value(
|
||
builder, pool, mod, sub_addr.value, None, 0, trans)
|
||
if arr_val is None or arr_val.Ty is None:
|
||
return None
|
||
idx_val: llvmlite.Value | t.CPtr = self.Gen.ExprGen.translate_value(
|
||
builder, pool, mod, sub_addr.slice, None, 0, trans)
|
||
if idx_val is None:
|
||
return None
|
||
# 数组基址 pointee 是 Array(elem_ty, N) → GEP 得元素指针
|
||
arr_pointee_ca: llvmlite.LLVMType | t.CPtr = None
|
||
if self.Gen.ExprGenBase.is_ptr_type(arr_val.Ty) != 0:
|
||
arr_pointee_ca = arr_val.Ty.Pointee
|
||
if arr_pointee_ca is not None:
|
||
match arr_pointee_ca:
|
||
case llvmlite.LLVMType.Array(arr_et_ca, _):
|
||
return llvmlite.build_gep_array(
|
||
builder, arr_pointee_ca, arr_et_ca, arr_val, idx_val)
|
||
case _:
|
||
pass
|
||
return None
|
||
|
||
# Call 形式: c.Addr(expr) → 求值 expr 存临时槽(entry alloca),返回槽地址
|
||
# 供就地解读使用:tt: Coroutine = c.Addr(task()) —— coerce 指针→结构体时
|
||
# 从槽地址 load(target 是 NoVTable 结构体,如 Coroutine={__ptr__} 8 字节)。
|
||
if arg0.kind() == ast.ASTKind.Call:
|
||
call_val: llvmlite.Value | t.CPtr = self.Gen.ExprGen.translate_value(
|
||
builder, pool, mod, arg0, None, 0, trans)
|
||
if call_val is None or call_val.Ty is None:
|
||
return None
|
||
tmp_slot: llvmlite.Value | t.CPtr = llvmlite.build_alloca_at_entry(
|
||
builder, call_val.Ty)
|
||
if tmp_slot is None:
|
||
return None
|
||
llvmlite.build_store(builder, call_val, tmp_slot)
|
||
return tmp_slot
|
||
|
||
# 其他 arg0 形式(非 Name/Attribute/Subscript/Call):真实掉出函数末尾,
|
||
# 补显式 return None(fail-fast 不允许流程掉出末尾)
|
||
return None
|
||
|
||
|
||
def translate_c_load(self, pool: memhub.MemBuddy | t.CPtr,
|
||
builder: llvmlite.IRBuilder | t.CPtr,
|
||
mod: llvmlite.LLVMModule | t.CPtr,
|
||
cl: ast.Call | t.CPtr,
|
||
trans: HT.Translator | t.CPtr = None) -> llvmlite.Value | t.CPtr:
|
||
"""c.Load(a, b) → *a = *b(加载 b 的值,存储到 a)"""
|
||
if cl is None:
|
||
return None
|
||
cargs: list[ast.AST | t.CPtr] | t.CPtr = cl.args
|
||
if cargs is None or len(cargs) < 2:
|
||
return None
|
||
|
||
dst_ptr: llvmlite.Value | t.CPtr = self.Gen.ExprGen.translate_value(
|
||
builder, pool, mod, cargs.get(0), None, 0, trans)
|
||
src_ptr: llvmlite.Value | t.CPtr = self.Gen.ExprGen.translate_value(
|
||
builder, pool, mod, cargs.get(1), None, 0, trans)
|
||
if dst_ptr is None or src_ptr is None:
|
||
return None
|
||
|
||
# 确定 pointee 类型(优先用 src 的 pointee,回退到 dst 的 pointee)
|
||
pointee: llvmlite.LLVMType | t.CPtr = None
|
||
if src_ptr.Ty is not None:
|
||
pointee = src_ptr.Ty.Pointee
|
||
if pointee is None and dst_ptr.Ty is not None:
|
||
pointee = dst_ptr.Ty.Pointee
|
||
if pointee is None:
|
||
return None
|
||
|
||
# bitcast src 到 pointee* 并 load
|
||
target_ptr_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, pointee)
|
||
src_cast: llvmlite.Value | t.CPtr = llvmlite.build_bitcast(builder, src_ptr, target_ptr_ty)
|
||
if src_cast is None:
|
||
return None
|
||
loaded: llvmlite.Value | t.CPtr = llvmlite.build_load(builder, pointee, src_cast)
|
||
if loaded is None:
|
||
return None
|
||
|
||
# bitcast dst 到 pointee* 并 store
|
||
dst_cast: llvmlite.Value | t.CPtr = llvmlite.build_bitcast(builder, dst_ptr, target_ptr_ty)
|
||
if dst_cast is None:
|
||
return None
|
||
llvmlite.build_store(builder, loaded, dst_cast)
|
||
return loaded
|
||
|
||
|
||
def _asm_append_cstr(self, dst: str, dst_size: t.CSizeT,
|
||
src: str):
|
||
"""将 C 字符串 src 追加到 dst 末尾"""
|
||
if dst is None or src is None:
|
||
return
|
||
dlen: t.CSizeT = string.strlen(dst)
|
||
slen: t.CSizeT = string.strlen(src)
|
||
remain: t.CSizeT = dst_size - dlen
|
||
if remain <= 0:
|
||
return
|
||
i: t.CSizeT = 0
|
||
while i < slen and i + 1 < remain:
|
||
dst[dlen + i] = src[i]
|
||
i += 1
|
||
dst[dlen + i] = '\0'
|
||
|
||
|
||
def _asm_escape_for_ir(self, pool: memhub.MemBuddy | t.CPtr,
|
||
src: str) -> str:
|
||
"""转义汇编文本用于 LLVM IR 字符串字面量"""
|
||
if src is None:
|
||
return None
|
||
slen: t.CSizeT = string.strlen(src)
|
||
buf: str = pool.alloc(slen * 4 + 8)
|
||
if buf is None:
|
||
return None
|
||
pos: t.CSizeT = 0
|
||
for ch in src:
|
||
if ch == '\n':
|
||
buf[pos] = '\\'
|
||
pos += 1
|
||
buf[pos] = '0'
|
||
pos += 1
|
||
buf[pos] = 'A'
|
||
pos += 1
|
||
elif ch == '"':
|
||
buf[pos] = '\\'
|
||
pos += 1
|
||
buf[pos] = '2'
|
||
pos += 1
|
||
buf[pos] = '2'
|
||
pos += 1
|
||
elif ch == '\\':
|
||
buf[pos] = '\\'
|
||
pos += 1
|
||
buf[pos] = '5'
|
||
pos += 1
|
||
buf[pos] = 'C'
|
||
pos += 1
|
||
else:
|
||
buf[pos] = ch
|
||
pos += 1
|
||
buf[pos] = '\0'
|
||
return buf
|
||
|
||
|
||
def _resolve_register(self, attr_name: str) -> str:
|
||
"""将 t.ASM_DESCR.XXX 的属性名映射到约束字符串值"""
|
||
if attr_name is None:
|
||
return ""
|
||
|
||
# Clobber 破坏描述符
|
||
if string.strcmp(attr_name, "CLOBBER_MEMORY") == 0: return "memory"
|
||
if string.strcmp(attr_name, "CLOBBER_CC") == 0: return "cc"
|
||
if string.strcmp(attr_name, "CLOBBER_RAX") == 0: return "rax"
|
||
if string.strcmp(attr_name, "CLOBBER_RBX") == 0: return "rbx"
|
||
if string.strcmp(attr_name, "CLOBBER_RCX") == 0: return "rcx"
|
||
if string.strcmp(attr_name, "CLOBBER_RDX") == 0: return "rdx"
|
||
if string.strcmp(attr_name, "CLOBBER_RSI") == 0: return "rsi"
|
||
if string.strcmp(attr_name, "CLOBBER_RDI") == 0: return "rdi"
|
||
if string.strcmp(attr_name, "CLOBBER_RBP") == 0: return "rbp"
|
||
if string.strcmp(attr_name, "CLOBBER_RSP") == 0: return "rsp"
|
||
if string.strcmp(attr_name, "CLOBBER_R8") == 0: return "r8"
|
||
if string.strcmp(attr_name, "CLOBBER_R9") == 0: return "r9"
|
||
if string.strcmp(attr_name, "CLOBBER_R10") == 0: return "r10"
|
||
if string.strcmp(attr_name, "CLOBBER_R11") == 0: return "r11"
|
||
if string.strcmp(attr_name, "CLOBBER_R12") == 0: return "r12"
|
||
if string.strcmp(attr_name, "CLOBBER_R13") == 0: return "r13"
|
||
if string.strcmp(attr_name, "CLOBBER_R14") == 0: return "r14"
|
||
if string.strcmp(attr_name, "CLOBBER_R15") == 0: return "r15"
|
||
if string.strcmp(attr_name, "CLOBBER_EAX") == 0: return "eax"
|
||
if string.strcmp(attr_name, "CLOBBER_EBX") == 0: return "ebx"
|
||
if string.strcmp(attr_name, "CLOBBER_ECX") == 0: return "ecx"
|
||
if string.strcmp(attr_name, "CLOBBER_EDX") == 0: return "edx"
|
||
if string.strcmp(attr_name, "CLOBBER_ESI") == 0: return "esi"
|
||
if string.strcmp(attr_name, "CLOBBER_EDI") == 0: return "edi"
|
||
if string.strcmp(attr_name, "CLOBBER_DX") == 0: return "dx"
|
||
if string.strcmp(attr_name, "CLOBBER_AX") == 0: return "ax"
|
||
if string.strcmp(attr_name, "CLOBBER_CX") == 0: return "cx"
|
||
if string.strcmp(attr_name, "CLOBBER_SI") == 0: return "si"
|
||
if string.strcmp(attr_name, "CLOBBER_DI") == 0: return "di"
|
||
|
||
# Output 输出约束
|
||
if string.strcmp(attr_name, "OUTPUT_REG") == 0: return "=r"
|
||
if string.strcmp(attr_name, "OUTPUT_MEM") == 0: return "=m"
|
||
if string.strcmp(attr_name, "OUTPUT_EAX") == 0: return "=a"
|
||
if string.strcmp(attr_name, "OUTPUT_EBX") == 0: return "=b"
|
||
if string.strcmp(attr_name, "OUTPUT_ECX") == 0: return "=c"
|
||
if string.strcmp(attr_name, "OUTPUT_EDX") == 0: return "=d"
|
||
if string.strcmp(attr_name, "OUTPUT_ESI") == 0: return "=S"
|
||
if string.strcmp(attr_name, "OUTPUT_EDI") == 0: return "=D"
|
||
if string.strcmp(attr_name, "OUTPUT_RAX") == 0: return "=a"
|
||
if string.strcmp(attr_name, "OUTPUT_RBX") == 0: return "=b"
|
||
if string.strcmp(attr_name, "OUTPUT_RCX") == 0: return "=c"
|
||
if string.strcmp(attr_name, "OUTPUT_RDX") == 0: return "=d"
|
||
if string.strcmp(attr_name, "OUTPUT_RSI") == 0: return "=S"
|
||
if string.strcmp(attr_name, "OUTPUT_RDI") == 0: return "=D"
|
||
|
||
# Input/Register 输入约束
|
||
if string.strcmp(attr_name, "REG_ANY") == 0: return "r"
|
||
if string.strcmp(attr_name, "REG_EAX") == 0: return "a"
|
||
if string.strcmp(attr_name, "REG_EBX") == 0: return "b"
|
||
if string.strcmp(attr_name, "REG_ECX") == 0: return "c"
|
||
if string.strcmp(attr_name, "REG_EDX") == 0: return "d"
|
||
if string.strcmp(attr_name, "REG_ESI") == 0: return "S"
|
||
if string.strcmp(attr_name, "REG_EDI") == 0: return "D"
|
||
if string.strcmp(attr_name, "REG_RAX") == 0: return "a"
|
||
if string.strcmp(attr_name, "REG_RBX") == 0: return "b"
|
||
if string.strcmp(attr_name, "REG_RCX") == 0: return "c"
|
||
if string.strcmp(attr_name, "REG_RDX") == 0: return "d"
|
||
if string.strcmp(attr_name, "REG_RSI") == 0: return "S"
|
||
if string.strcmp(attr_name, "REG_RDI") == 0: return "D"
|
||
|
||
if string.strcmp(attr_name, "INPUT_REG") == 0: return "r"
|
||
if string.strcmp(attr_name, "INPUT_MEM") == 0: return "m"
|
||
if string.strcmp(attr_name, "INPUT_EAX") == 0: return "a"
|
||
if string.strcmp(attr_name, "INPUT_EBX") == 0: return "b"
|
||
if string.strcmp(attr_name, "INPUT_ECX") == 0: return "c"
|
||
if string.strcmp(attr_name, "INPUT_EDX") == 0: return "d"
|
||
if string.strcmp(attr_name, "INPUT_ESI") == 0: return "S"
|
||
if string.strcmp(attr_name, "INPUT_EDI") == 0: return "D"
|
||
if string.strcmp(attr_name, "INPUT_RAX") == 0: return "a"
|
||
if string.strcmp(attr_name, "INPUT_RBX") == 0: return "b"
|
||
if string.strcmp(attr_name, "INPUT_RCX") == 0: return "c"
|
||
if string.strcmp(attr_name, "INPUT_RDX") == 0: return "d"
|
||
if string.strcmp(attr_name, "INPUT_RSI") == 0: return "S"
|
||
if string.strcmp(attr_name, "INPUT_RDI") == 0: return "D"
|
||
|
||
return ""
|
||
|
||
|
||
def _resolve_asm_descr(self, pool: memhub.MemBuddy | t.CPtr,
|
||
node: ast.AST | t.CPtr) -> str:
|
||
"""递归解析约束表达式,返回约束字符串"""
|
||
if node is None:
|
||
return ""
|
||
|
||
k: int = node.kind()
|
||
|
||
# BinOp with BitOr: 拼接左右
|
||
if k == ast.ASTKind.BinOp:
|
||
bop: ast.BinOp | t.CPtr = (ast.BinOp | t.CPtr)(node)
|
||
if bop.op == ast.OpKind.BitOr:
|
||
left_str: str = self._resolve_asm_descr(pool, bop.left)
|
||
right_str: str = self._resolve_asm_descr(pool, bop.right)
|
||
llen: t.CSizeT = string.strlen(left_str)
|
||
rlen: t.CSizeT = string.strlen(right_str)
|
||
buf: str = pool.alloc(llen + rlen + 1)
|
||
if buf is None:
|
||
return ""
|
||
string.strcpy(buf, left_str)
|
||
for i in range(rlen):
|
||
buf[llen + i] = right_str[i]
|
||
buf[llen + rlen] = '\0'
|
||
return buf
|
||
return ""
|
||
|
||
# Attribute: t.ASM_DESCR.XXX 或 t.XXX
|
||
if k == ast.ASTKind.Attribute:
|
||
at: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(node)
|
||
# t.ASM_DESCR.XXX
|
||
if at.value is not None and at.value.kind() == ast.ASTKind.Attribute:
|
||
inner: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(at.value)
|
||
if inner.value is not None and inner.value.kind() == ast.ASTKind.Name:
|
||
mod_nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(inner.value)
|
||
if mod_nm.id is not None and string.strcmp(mod_nm.id, "t") == 0:
|
||
if inner.attr is not None and string.strcmp(inner.attr, "ASM_DESCR") == 0:
|
||
return self._resolve_register(at.attr)
|
||
# t.XXX 简化形式
|
||
if at.value is not None and at.value.kind() == ast.ASTKind.Name:
|
||
mod_nm2: ast.Name | t.CPtr = (ast.Name | t.CPtr)(at.value)
|
||
if mod_nm2.id is not None and string.strcmp(mod_nm2.id, "t") == 0:
|
||
return self._resolve_register(at.attr)
|
||
return ""
|
||
|
||
# Constant: 字符串常量
|
||
if k == ast.ASTKind.Constant:
|
||
cn: ast.Constant | t.CPtr = (ast.Constant | t.CPtr)(node)
|
||
if cn.const_kind == ast.CONST_STR:
|
||
return cn.str_val
|
||
return ""
|
||
|
||
return ""
|
||
|
||
|
||
def _asm_get_operand(self, base: GenTypes.AsmOperand | t.CPtr,
|
||
idx: int) -> GenTypes.AsmOperand | t.CPtr:
|
||
"""获取操作数数组中第 idx 个元素的指针"""
|
||
entry_size: t.CSizeT = GenTypes.AsmOperand.__sizeof__()
|
||
entry_addr: t.CUInt64T = t.CUInt64T(base) + idx * entry_size
|
||
return (GenTypes.AsmOperand | t.CPtr)(t.CVoid(entry_addr, t.CPtr))
|
||
|
||
|
||
def _asm_is_c_call(self, node: ast.Call | t.CPtr) -> str:
|
||
"""检查 Call 节点是否是 c.XXX 调用,返回属性名或 None"""
|
||
if node is None or node.func is None:
|
||
return None
|
||
if node.func.kind() != ast.ASTKind.Attribute:
|
||
return None
|
||
at: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(node.func)
|
||
if at.value is None or at.value.kind() != ast.ASTKind.Name:
|
||
return None
|
||
mod_nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(at.value)
|
||
if mod_nm.id is None or string.strcmp(mod_nm.id, "c") != 0:
|
||
return None
|
||
return at.attr
|
||
|
||
|
||
def _asm_add_operand(self, operands: GenTypes.AsmOperand | t.CPtr,
|
||
count: int,
|
||
val: llvmlite.Value | t.CPtr,
|
||
constraint: str,
|
||
is_output: int) -> int:
|
||
"""添加操作数到数组,返回新计数(失败返回原计数)
|
||
|
||
去重:f-string 模板内嵌的 AsmOut/AsmInp 与 out=/inp= 声明指向
|
||
同一变量时会重复收集(如 vrandom.vp 的 c.Asm(f"...{AsmOut(v)}",
|
||
out=[AsmOut(v)])),同一 (Value, IsOutput) 只保留第一个,
|
||
避免约束数多于 asm 返回元素数(llc: output constraints mismatch)。
|
||
"""
|
||
if count >= ASM_MAX_OPERANDS:
|
||
return count
|
||
if val is not None:
|
||
for ei in range(count):
|
||
eop: GenTypes.AsmOperand | t.CPtr = self._asm_get_operand(operands, ei)
|
||
if eop is not None and eop.Value == val and eop.IsOutput == is_output:
|
||
return count
|
||
op: GenTypes.AsmOperand | t.CPtr = self._asm_get_operand(operands, count)
|
||
op.Value = val
|
||
op.Constraint = constraint
|
||
op.IsOutput = is_output
|
||
return count + 1
|
||
|
||
|
||
def translate_c_asm(self, pool: memhub.MemBuddy | t.CPtr,
|
||
builder: llvmlite.IRBuilder | t.CPtr,
|
||
mod: llvmlite.LLVMModule | t.CPtr,
|
||
cl: ast.Call | t.CPtr,
|
||
trans: HT.Translator | t.CPtr = None) -> llvmlite.Value | t.CPtr:
|
||
"""翻译 c.Asm 内联汇编,返回结果 Value(无输出时返回 None)"""
|
||
if cl is None:
|
||
return None
|
||
|
||
cargs: list[ast.AST | t.CPtr] | t.CPtr = cl.args
|
||
if cargs is None or len(cargs) < 1:
|
||
return None
|
||
|
||
# 分配操作数数组
|
||
operand_size: t.CSizeT = GenTypes.AsmOperand.__sizeof__()
|
||
operands: GenTypes.AsmOperand | t.CPtr = pool.alloc(operand_size * ASM_MAX_OPERANDS)
|
||
if operands is None:
|
||
return None
|
||
string.memset(operands, 0, operand_size * ASM_MAX_OPERANDS)
|
||
|
||
# 分配 clobber 名数组
|
||
clobbers: str | t.CPtr = pool.alloc(8 * ASM_MAX_OPERANDS)
|
||
if clobbers is None:
|
||
return None
|
||
string.memset(clobbers, 0, 8 * ASM_MAX_OPERANDS)
|
||
|
||
# 分配 asm 文本缓冲区
|
||
asm_text: str = pool.alloc(ASM_TEXT_BUF_SIZE)
|
||
if asm_text is None:
|
||
return None
|
||
asm_text[0] = '\0'
|
||
|
||
operand_count: int = 0
|
||
clobber_count: int = 0
|
||
fv_count: int = 0
|
||
|
||
# 分配 fv 索引数组(记录每个 FormattedValue 对应的操作数原始索引)
|
||
fv_orig_indices: int | t.CPtr = pool.alloc(4 * ASM_MAX_OPERANDS)
|
||
if fv_orig_indices is None:
|
||
return None
|
||
string.memset(fv_orig_indices, 0, 4 * ASM_MAX_OPERANDS)
|
||
|
||
# ============================================================
|
||
# 1. 解析汇编模板(JoinedStr 或 Constant)— 第一遍:收集操作数
|
||
# 不生成 asm 文本(占位符 $N 需在重排后才能确定编号)
|
||
# ============================================================
|
||
tmpl_node: ast.AST | t.CPtr = cargs.get(0)
|
||
if tmpl_node is not None:
|
||
tk: int = tmpl_node.kind()
|
||
|
||
if tk == ast.ASTKind.JoinedStr:
|
||
js: ast.JoinedStr | t.CPtr = (ast.JoinedStr | t.CPtr)(tmpl_node)
|
||
jvalues: list[ast.AST | t.CPtr] | t.CPtr = js.values
|
||
if jvalues is not None:
|
||
jvlen: t.CSizeT = len(jvalues)
|
||
for vi in range(jvlen):
|
||
part: ast.AST | t.CPtr = jvalues.get(vi)
|
||
if part is None:
|
||
continue
|
||
pk: int = part.kind()
|
||
|
||
if pk == ast.ASTKind.FormattedValue:
|
||
fv: ast.FormattedValue | t.CPtr = (ast.FormattedValue | t.CPtr)(part)
|
||
fexpr: ast.AST | t.CPtr = fv.value
|
||
if fexpr is None or fexpr.kind() != ast.ASTKind.Call:
|
||
continue
|
||
fcall: ast.Call | t.CPtr = (ast.Call | t.CPtr)(fexpr)
|
||
attr_nm: str = self._asm_is_c_call(fcall)
|
||
if attr_nm is None:
|
||
continue
|
||
|
||
is_out: int = 0
|
||
if string.strcmp(attr_nm, "AsmOut") == 0:
|
||
is_out = 1
|
||
elif string.strcmp(attr_nm, "AsmInp") == 0:
|
||
is_out = 0
|
||
else:
|
||
continue
|
||
|
||
fargs: list[ast.AST | t.CPtr] | t.CPtr = fcall.args
|
||
if fargs is None or len(fargs) < 1:
|
||
continue
|
||
|
||
val_node: ast.AST | t.CPtr = fargs.get(0)
|
||
cons_str: str = ""
|
||
if len(fargs) >= 2:
|
||
cons_str = self._resolve_asm_descr(pool, fargs.get(1))
|
||
|
||
if is_out != 0:
|
||
# 输出:获取变量 alloca
|
||
if val_node is None or val_node.kind() != ast.ASTKind.Name:
|
||
continue
|
||
nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(val_node)
|
||
if nm.id is None:
|
||
continue
|
||
alloca: llvmlite.Value | t.CPtr = self.Gen.VarGen.lookup_var(trans.SymTab, nm.id)
|
||
if alloca is None:
|
||
continue
|
||
operand_count = self._asm_add_operand(
|
||
operands, operand_count, alloca, cons_str, 1)
|
||
else:
|
||
# 输入:翻译值
|
||
ival: llvmlite.Value | t.CPtr = self.Gen.ExprGen.translate_value(
|
||
builder, pool, mod, val_node, None, 0, trans)
|
||
if ival is None:
|
||
continue
|
||
operand_count = self._asm_add_operand(
|
||
operands, operand_count, ival, cons_str, 0)
|
||
|
||
# 记录 fv 的原始操作数索引
|
||
if fv_count < ASM_MAX_OPERANDS:
|
||
fv_orig_indices[fv_count] = operand_count - 1
|
||
fv_count += 1
|
||
|
||
# ============================================================
|
||
# 2. 解析关键字参数 out=/inp=/op=/clobber=
|
||
# ============================================================
|
||
keywords: list[ast.AST | t.CPtr] | t.CPtr = cl.keywords
|
||
if keywords is not None:
|
||
kwlen: t.CSizeT = len(keywords)
|
||
for ki in range(kwlen):
|
||
kw: ast.Keyword | t.CPtr = (ast.Keyword | t.CPtr)(keywords.get(ki))
|
||
if kw is None or kw.arg is None or kw.value is None:
|
||
continue
|
||
kwk: int = kw.value.kind()
|
||
|
||
if string.strcmp(kw.arg, "out") == 0:
|
||
# 输出操作数列表
|
||
if kwk != ast.ASTKind.List:
|
||
continue
|
||
out_lst: ast.List | t.CPtr = (ast.List | t.CPtr)(kw.value)
|
||
out_elts: list[ast.AST | t.CPtr] | t.CPtr = out_lst.elts
|
||
if out_elts is None:
|
||
continue
|
||
oelen: t.CSizeT = len(out_elts)
|
||
for oi in range(oelen):
|
||
oelt: ast.AST | t.CPtr = out_elts.get(oi)
|
||
if oelt is None or oelt.kind() != ast.ASTKind.Call:
|
||
continue
|
||
ocall: ast.Call | t.CPtr = (ast.Call | t.CPtr)(oelt)
|
||
oattr: str = self._asm_is_c_call(ocall)
|
||
if oattr is None or string.strcmp(oattr, "AsmOut") != 0:
|
||
continue
|
||
oargs: list[ast.AST | t.CPtr] | t.CPtr = ocall.args
|
||
if oargs is None or len(oargs) < 1:
|
||
continue
|
||
oval_node: ast.AST | t.CPtr = oargs.get(0)
|
||
ocons: str = ""
|
||
if len(oargs) >= 2:
|
||
ocons = self._resolve_asm_descr(pool, oargs.get(1))
|
||
if oval_node is None or oval_node.kind() != ast.ASTKind.Name:
|
||
continue
|
||
onm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(oval_node)
|
||
if onm.id is None:
|
||
continue
|
||
oalloca: llvmlite.Value | t.CPtr = self.Gen.VarGen.lookup_var(trans.SymTab, onm.id)
|
||
if oalloca is None:
|
||
continue
|
||
operand_count = self._asm_add_operand(
|
||
operands, operand_count, oalloca, ocons, 1)
|
||
|
||
elif string.strcmp(kw.arg, "inp") == 0 or string.strcmp(kw.arg, "inputs") == 0:
|
||
# 输入操作数列表
|
||
if kwk != ast.ASTKind.List:
|
||
continue
|
||
in_lst: ast.List | t.CPtr = (ast.List | t.CPtr)(kw.value)
|
||
in_elts: list[ast.AST | t.CPtr] | t.CPtr = in_lst.elts
|
||
if in_elts is None:
|
||
continue
|
||
ielen: t.CSizeT = len(in_elts)
|
||
for ii in range(ielen):
|
||
ielt: ast.AST | t.CPtr = in_elts.get(ii)
|
||
if ielt is None or ielt.kind() != ast.ASTKind.Call:
|
||
continue
|
||
icall: ast.Call | t.CPtr = (ast.Call | t.CPtr)(ielt)
|
||
iattr: str = self._asm_is_c_call(icall)
|
||
if iattr is None or string.strcmp(iattr, "AsmInp") != 0:
|
||
continue
|
||
iargs: list[ast.AST | t.CPtr] | t.CPtr = icall.args
|
||
if iargs is None or len(iargs) < 1:
|
||
continue
|
||
ival_node: ast.AST | t.CPtr = iargs.get(0)
|
||
icons: str = ""
|
||
if len(iargs) >= 2:
|
||
icons = self._resolve_asm_descr(pool, iargs.get(1))
|
||
ival2: llvmlite.Value | t.CPtr = self.Gen.ExprGen.translate_value(
|
||
builder, pool, mod, ival_node, None, 0, trans)
|
||
if ival2 is None:
|
||
continue
|
||
operand_count = self._asm_add_operand(
|
||
operands, operand_count, ival2, icons, 0)
|
||
|
||
elif string.strcmp(kw.arg, "op") == 0 or string.strcmp(kw.arg, "clobber") == 0:
|
||
# 破坏列表
|
||
if kwk != ast.ASTKind.List:
|
||
continue
|
||
cl_lst: ast.List | t.CPtr = (ast.List | t.CPtr)(kw.value)
|
||
cl_elts: list[ast.AST | t.CPtr] | t.CPtr = cl_lst.elts
|
||
if cl_elts is None:
|
||
continue
|
||
clen: t.CSizeT = len(cl_elts)
|
||
for ci in range(clen):
|
||
celt: ast.AST | t.CPtr = cl_elts.get(ci)
|
||
if celt is None:
|
||
continue
|
||
cstr: str = self._resolve_asm_descr(pool, celt)
|
||
if cstr is None or cstr[0] == '\0':
|
||
continue
|
||
if clobber_count < ASM_MAX_OPERANDS:
|
||
cl_addr: t.CUInt64T = t.CUInt64T(clobbers) + clobber_count * 8
|
||
cl_ptr: str | t.CPtr = (str | t.CPtr)(t.CVoid(cl_addr, t.CPtr))
|
||
cl_ptr[0] = cstr
|
||
clobber_count += 1
|
||
|
||
# ============================================================
|
||
# 3. 解析第二个位置参数作为破坏列表
|
||
# ============================================================
|
||
if len(cargs) >= 2:
|
||
pos_node: ast.AST | t.CPtr = cargs.get(1)
|
||
if pos_node is not None and pos_node.kind() == ast.ASTKind.List:
|
||
pos_lst: ast.List | t.CPtr = (ast.List | t.CPtr)(pos_node)
|
||
pos_elts: list[ast.AST | t.CPtr] | t.CPtr = pos_lst.elts
|
||
if pos_elts is not None:
|
||
plen: t.CSizeT = len(pos_elts)
|
||
for pi in range(plen):
|
||
pelt: ast.AST | t.CPtr = pos_elts.get(pi)
|
||
if pelt is None:
|
||
continue
|
||
pstr: str = self._resolve_asm_descr(pool, pelt)
|
||
if pstr is None or pstr[0] == '\0':
|
||
continue
|
||
if clobber_count < ASM_MAX_OPERANDS:
|
||
pcl_addr: t.CUInt64T = t.CUInt64T(clobbers) + clobber_count * 8
|
||
pcl_ptr: str | t.CPtr = (str | t.CPtr)(t.CVoid(pcl_addr, t.CPtr))
|
||
pcl_ptr[0] = pstr
|
||
clobber_count += 1
|
||
|
||
# ============================================================
|
||
# 4. 统计输出/输入数量,确定返回类型
|
||
# ============================================================
|
||
output_count: int = 0
|
||
input_count: int = 0
|
||
first_output_idx: int = -1
|
||
for oi2 in range(operand_count):
|
||
op2: GenTypes.AsmOperand | t.CPtr = self._asm_get_operand(operands, oi2)
|
||
if op2.IsOutput != 0:
|
||
if first_output_idx < 0:
|
||
first_output_idx = oi2
|
||
output_count += 1
|
||
else:
|
||
input_count += 1
|
||
|
||
# 确定返回类型
|
||
# 多输出(如 vrandom rdrand*_step 的 val+ok 两个 AsmOut)返回
|
||
# 匿名 struct {ty1, ty2, ...},元素数 = 输出操作数(LLVM asm
|
||
# 要求输出约束数 = 返回 struct 元素数)。
|
||
ret_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Void(pool)
|
||
if output_count > 0 and first_output_idx >= 0:
|
||
if output_count > 1:
|
||
out_pn_head: llvmlite.ParamNode | t.CPtr = None
|
||
out_pn_last: llvmlite.ParamNode | t.CPtr = None
|
||
out_pn_n: int = 0
|
||
for oi5 in range(operand_count):
|
||
op5: GenTypes.AsmOperand | t.CPtr = self._asm_get_operand(operands, oi5)
|
||
if op5 is None or op5.IsOutput == 0:
|
||
continue
|
||
if op5.Value is not None and op5.Value.Ty is not None \
|
||
and op5.Value.Ty.Pointee is not None:
|
||
pn5: llvmlite.ParamNode | t.CPtr = llvmlite.new_param_node(
|
||
pool, op5.Value.Ty.Pointee)
|
||
if pn5 is not None:
|
||
if out_pn_head is None:
|
||
out_pn_head = pn5
|
||
else:
|
||
out_pn_last.Next = pn5
|
||
out_pn_last = pn5
|
||
out_pn_n += 1
|
||
if out_pn_head is not None and out_pn_n > 0:
|
||
ret_ty = llvmlite.Struct(pool, out_pn_head, out_pn_n, None)
|
||
else:
|
||
self.Gen.TypeGenErr.fatal_error(
|
||
cl, "c.Asm 输出操作数类型缺失(变量 alloca 类型退化)", "TypeError")
|
||
ret_ty = llvmlite.Int32(pool)
|
||
else:
|
||
out_op: GenTypes.AsmOperand | t.CPtr = self._asm_get_operand(operands, first_output_idx)
|
||
if out_op.Value is not None and out_op.Value.Ty is not None:
|
||
# alloca 的类型是指针,Pointee 是目标类型
|
||
if out_op.Value.Ty.Pointee is not None:
|
||
ret_ty = out_op.Value.Ty.Pointee
|
||
else:
|
||
self.Gen.TypeGenErr.fatal_error(
|
||
cl, "c.Asm 输出操作数类型缺失(变量 alloca 类型退化)", "TypeError")
|
||
ret_ty = llvmlite.Int32(pool)
|
||
|
||
# 判断 void — 直接基于 output_count 判断,避免 match 类型匹配问题
|
||
is_void: int = 1
|
||
if output_count > 0:
|
||
is_void = 0
|
||
|
||
# ============================================================
|
||
# 4.5 重排操作数:输出在前,输入在后(LLVM IR 要求)
|
||
#
|
||
# new_order[new_idx] = orig_idx — 新位置对应原索引
|
||
# orig_to_new[orig_idx] = new_idx — 原索引映射到新位置(用于占位符编号)
|
||
# ============================================================
|
||
new_order: int | t.CPtr = pool.alloc(4 * (operand_count + 1))
|
||
orig_to_new: int | t.CPtr = pool.alloc(4 * (operand_count + 1))
|
||
if new_order is None or orig_to_new is None:
|
||
return None
|
||
|
||
new_idx: int = 0
|
||
# 先放输出
|
||
for oi3 in range(operand_count):
|
||
op3: GenTypes.AsmOperand | t.CPtr = self._asm_get_operand(operands, oi3)
|
||
if op3.IsOutput != 0:
|
||
new_order[new_idx] = oi3
|
||
new_idx += 1
|
||
# 再放输入
|
||
for oi4 in range(operand_count):
|
||
op4: GenTypes.AsmOperand | t.CPtr = self._asm_get_operand(operands, oi4)
|
||
if op4.IsOutput == 0:
|
||
new_order[new_idx] = oi4
|
||
new_idx += 1
|
||
# 建立映射 orig -> new
|
||
for ni2 in range(operand_count):
|
||
orig_to_new[new_order[ni2]] = ni2
|
||
|
||
# ============================================================
|
||
# 4.6 生成汇编文本(第二遍遍历 f-string,用重排后的索引生成占位符)
|
||
# 项目约定使用 Intel 语法,通过 IR 的 inteldialect 关键字启用
|
||
# ============================================================
|
||
if tmpl_node is not None:
|
||
tk2: int = tmpl_node.kind()
|
||
if tk2 == ast.ASTKind.JoinedStr:
|
||
js2: ast.JoinedStr | t.CPtr = (ast.JoinedStr | t.CPtr)(tmpl_node)
|
||
jvalues2: list[ast.AST | t.CPtr] | t.CPtr = js2.values
|
||
if jvalues2 is not None:
|
||
jvlen2: t.CSizeT = len(jvalues2)
|
||
fv_fi: int = 0
|
||
for vi2 in range(jvlen2):
|
||
part2: ast.AST | t.CPtr = jvalues2.get(vi2)
|
||
if part2 is None:
|
||
continue
|
||
pk2: int = part2.kind()
|
||
if pk2 == ast.ASTKind.Constant:
|
||
cn3: ast.Constant | t.CPtr = (ast.Constant | t.CPtr)(part2)
|
||
if cn3.const_kind == ast.CONST_STR and cn3.str_val is not None:
|
||
self._asm_append_cstr(asm_text, ASM_TEXT_BUF_SIZE, cn3.str_val)
|
||
elif pk2 == ast.ASTKind.FormattedValue:
|
||
if fv_fi < fv_count:
|
||
orig_idx2: int = fv_orig_indices[fv_fi]
|
||
new_idx2: int = orig_to_new[orig_idx2]
|
||
ph_buf2: str = pool.alloc(16)
|
||
if ph_buf2 is not None:
|
||
viperlib.snprintf(ph_buf2, 16, "$%d", new_idx2)
|
||
self._asm_append_cstr(asm_text, ASM_TEXT_BUF_SIZE, ph_buf2)
|
||
fv_fi += 1
|
||
elif tk2 == ast.ASTKind.Constant:
|
||
cn4: ast.Constant | t.CPtr = (ast.Constant | t.CPtr)(tmpl_node)
|
||
if cn4.const_kind == ast.CONST_STR and cn4.str_val is not None:
|
||
self._asm_append_cstr(asm_text, ASM_TEXT_BUF_SIZE, cn4.str_val)
|
||
|
||
# ============================================================
|
||
# 5. 构建约束字符串(按重排后的顺序:输出在前,输入在后)
|
||
# ============================================================
|
||
const_buf: str = pool.alloc(ASM_CONST_BUF_SIZE)
|
||
if const_buf is None:
|
||
return None
|
||
const_buf[0] = '\0'
|
||
|
||
first_const: int = 1
|
||
for ci2 in range(operand_count):
|
||
orig_i: int = new_order[ci2]
|
||
cop: GenTypes.AsmOperand | t.CPtr = self._asm_get_operand(operands, orig_i)
|
||
cons_val: str = cop.Constraint
|
||
if cons_val is None:
|
||
cons_val = "r"
|
||
|
||
if first_const == 0:
|
||
self._asm_append_cstr(const_buf, ASM_CONST_BUF_SIZE, ",")
|
||
first_const = 0
|
||
|
||
if cop.IsOutput != 0:
|
||
# 输出约束:确保以 = 开头
|
||
if cons_val[0] != '=':
|
||
self._asm_append_cstr(const_buf, ASM_CONST_BUF_SIZE, "=")
|
||
self._asm_append_cstr(const_buf, ASM_CONST_BUF_SIZE, cons_val)
|
||
else:
|
||
self._asm_append_cstr(const_buf, ASM_CONST_BUF_SIZE, cons_val)
|
||
|
||
# 追加 clobber 约束 ~{name}
|
||
for cidx in range(clobber_count):
|
||
cl_addr2: t.CUInt64T = t.CUInt64T(clobbers) + cidx * 8
|
||
cname: str = (str | t.CPtr)(t.CVoid(cl_addr2, t.CPtr))[0]
|
||
if cname is None or cname[0] == '\0':
|
||
continue
|
||
if first_const == 0:
|
||
self._asm_append_cstr(const_buf, ASM_CONST_BUF_SIZE, ",")
|
||
first_const = 0
|
||
self._asm_append_cstr(const_buf, ASM_CONST_BUF_SIZE, "~{")
|
||
self._asm_append_cstr(const_buf, ASM_CONST_BUF_SIZE, cname)
|
||
self._asm_append_cstr(const_buf, ASM_CONST_BUF_SIZE, "}")
|
||
|
||
# ============================================================
|
||
# 6. 构建参数列表文本(仅输入操作数)
|
||
# ============================================================
|
||
args_buf: str = pool.alloc(ASM_ARGS_BUF_SIZE)
|
||
if args_buf is None:
|
||
return None
|
||
args_buf[0] = '\0'
|
||
|
||
first_arg: int = 1
|
||
for ai3 in range(operand_count):
|
||
orig_i2: int = new_order[ai3]
|
||
aop: GenTypes.AsmOperand | t.CPtr = self._asm_get_operand(operands, orig_i2)
|
||
if aop.IsOutput != 0:
|
||
continue
|
||
aval: llvmlite.Value | t.CPtr = aop.Value
|
||
if aval is None or aval.Ty is None or aval.Name is None:
|
||
continue
|
||
|
||
if first_arg == 0:
|
||
self._asm_append_cstr(args_buf, ASM_ARGS_BUF_SIZE, ", ")
|
||
first_arg = 0
|
||
|
||
# 类型文本
|
||
ty_buf: str = pool.alloc(64)
|
||
if ty_buf is not None:
|
||
ty_buf[0] = '\0'
|
||
llvmlite.TypePrint(ty_buf, 64, aval.Ty, pool)
|
||
self._asm_append_cstr(args_buf, ASM_ARGS_BUF_SIZE, ty_buf)
|
||
self._asm_append_cstr(args_buf, ASM_ARGS_BUF_SIZE, " ")
|
||
self._asm_append_cstr(args_buf, ASM_ARGS_BUF_SIZE, aval.Name)
|
||
|
||
# ============================================================
|
||
# 7. 转义汇编文本
|
||
# ============================================================
|
||
escaped_asm: str = self._asm_escape_for_ir(pool, asm_text)
|
||
if escaped_asm is None:
|
||
return None
|
||
|
||
# ============================================================
|
||
# 8. 生成 IR 行并发射
|
||
# ============================================================
|
||
line: str = pool.alloc(ASM_LINE_BUF_SIZE)
|
||
if line is None:
|
||
return None
|
||
line[0] = '\0'
|
||
|
||
ssa_name: str = None
|
||
if is_void == 0:
|
||
ssa_name = pool.alloc(16)
|
||
if ssa_name is not None:
|
||
viperlib.snprintf(ssa_name, 16, "%%%d", builder.Counter)
|
||
builder.Counter += 1
|
||
|
||
# 获取返回类型文本
|
||
ret_ty_buf: str = pool.alloc(64)
|
||
if ret_ty_buf is not None:
|
||
ret_ty_buf[0] = '\0'
|
||
llvmlite.TypePrint(ret_ty_buf, 64, ret_ty, pool)
|
||
|
||
if is_void == 1:
|
||
viperlib.snprintf(line, ASM_LINE_BUF_SIZE,
|
||
"call %s asm sideeffect inteldialect \"%s\", \"%s\"(%s)",
|
||
ret_ty_buf, escaped_asm, const_buf, args_buf)
|
||
else:
|
||
viperlib.snprintf(line, ASM_LINE_BUF_SIZE,
|
||
"%s = call %s asm sideeffect inteldialect \"%s\", \"%s\"(%s)",
|
||
ssa_name, ret_ty_buf, escaped_asm, const_buf, args_buf)
|
||
|
||
# 发射 IR 到当前块
|
||
llvmlite.block_append_text(pool, builder.CurBlock, line)
|
||
|
||
# ============================================================
|
||
# 9. 处理输出:存储结果到输出变量
|
||
# ============================================================
|
||
if is_void == 0 and first_output_idx >= 0:
|
||
result_val: llvmlite.Value | t.CPtr = llvmlite.SSAValue(pool, ret_ty, ssa_name)
|
||
out_emit_idx: int = 0
|
||
for oi_out in range(operand_count):
|
||
orig_o: int = new_order[oi_out]
|
||
oo: GenTypes.AsmOperand | t.CPtr = self._asm_get_operand(operands, orig_o)
|
||
if oo is None or oo.IsOutput == 0:
|
||
continue
|
||
if output_count > 1:
|
||
# 多输出:extractvalue 取第 out_emit_idx 个元素后 store
|
||
if oo.Value is not None and oo.Value.Ty is not None \
|
||
and oo.Value.Ty.Pointee is not None:
|
||
ev_name: str = pool.alloc(32)
|
||
ev_line: str = pool.alloc(ASM_LINE_BUF_SIZE)
|
||
if ev_name is not None and ev_line is not None:
|
||
# ssa_name 形如 "%N"(纯数字 ID),构造唯一名
|
||
# "%asm.N.e{i}"(字母开头,避免 %N.e{i} 被解析为
|
||
# 数字 ID + 非法后缀导致 "expected '=' after id")
|
||
viperlib.snprintf(ev_name, 32, "%%asm.%s.e%d", ssa_name + 1, out_emit_idx)
|
||
viperlib.snprintf(ev_line, ASM_LINE_BUF_SIZE,
|
||
"%s = extractvalue %s %s, %d",
|
||
ev_name, ret_ty_buf, ssa_name, out_emit_idx)
|
||
llvmlite.block_append_text(pool, builder.CurBlock, ev_line)
|
||
ev_val: llvmlite.Value | t.CPtr = llvmlite.SSAValue(
|
||
pool, oo.Value.Ty.Pointee, ev_name)
|
||
llvmlite.build_store(builder, ev_val, oo.Value)
|
||
else:
|
||
if oo.Value is not None:
|
||
llvmlite.build_store(builder, result_val, oo.Value)
|
||
out_emit_idx += 1
|
||
return result_val
|
||
|
||
return None
|
||
|
||
|
||
def translate_c_llvmir(self, pool: memhub.MemBuddy | t.CPtr,
|
||
builder: llvmlite.IRBuilder | t.CPtr,
|
||
mod: llvmlite.LLVMModule | t.CPtr,
|
||
cl: ast.Call | t.CPtr,
|
||
trans: HT.Translator | t.CPtr = None) -> llvmlite.Value | t.CPtr:
|
||
"""c.LLVMIR 内联 LLVM IR:无返回值,直接嵌入原始 IR 文本
|
||
|
||
不做指令解析,模板文本(c.LInp/c.LOut 替换后)用 block_append_text
|
||
嵌入当前基本块。c.LOut 变量由唯一 SSA 寄存器 %llvmirN 接收结果,
|
||
嵌入后自动追加 store 写回变量 alloca。返回 None(无返回值)。
|
||
"""
|
||
if cl is None or builder is None or pool is None or trans is None:
|
||
return None
|
||
|
||
cargs: list[ast.AST | t.CPtr] | t.CPtr = cl.args
|
||
if cargs is None or len(cargs) < 1:
|
||
self.Gen.TypeGenErr.fatal_error(cl, "c.LLVMIR 缺少模板参数", "TypeError")
|
||
|
||
# LOut 写回记录(alloca 指针 + 寄存器名),最多 LLVMIR_MAX_OPS 个
|
||
out_alloca: t.CSizeT | t.CPtr = pool.alloc(8 * LLVMIR_MAX_OPS)
|
||
out_regname: t.CSizeT | t.CPtr = pool.alloc(8 * LLVMIR_MAX_OPS)
|
||
if out_alloca is None or out_regname is None:
|
||
return None
|
||
string.memset(out_alloca, 0, 8 * LLVMIR_MAX_OPS)
|
||
string.memset(out_regname, 0, 8 * LLVMIR_MAX_OPS)
|
||
out_count: int = 0
|
||
|
||
# 模板文本缓冲区
|
||
text: str = pool.alloc(LLVMIR_TEMPLATE_BUF)
|
||
if text is None:
|
||
return None
|
||
text[0] = '\0'
|
||
|
||
# ============================================================
|
||
# 1. 解析 IR 模板(JoinedStr 或 Constant)— 替换 LInp/LOut/表达式为值文本
|
||
# ============================================================
|
||
first_arg: ast.AST | t.CPtr = cargs.get(0)
|
||
if first_arg is None:
|
||
return None
|
||
|
||
tk: int = first_arg.kind()
|
||
|
||
if tk == ast.ASTKind.JoinedStr:
|
||
js: ast.JoinedStr | t.CPtr = (ast.JoinedStr | t.CPtr)(first_arg)
|
||
jvalues: list[ast.AST | t.CPtr] | t.CPtr = js.values
|
||
if jvalues is not None:
|
||
jvlen: t.CSizeT = len(jvalues)
|
||
for vi in range(jvlen):
|
||
part: ast.AST | t.CPtr = jvalues.get(vi)
|
||
if part is None:
|
||
continue
|
||
pk: int = part.kind()
|
||
|
||
if pk == ast.ASTKind.Constant:
|
||
# 字符串字面量片段
|
||
cn: ast.Constant | t.CPtr = (ast.Constant | t.CPtr)(part)
|
||
if cn.str_val is not None:
|
||
self._asm_append_cstr(text, LLVMIR_TEMPLATE_BUF, cn.str_val)
|
||
|
||
elif pk == ast.ASTKind.FormattedValue:
|
||
fv: ast.FormattedValue | t.CPtr = (ast.FormattedValue | t.CPtr)(part)
|
||
fexpr: ast.AST | t.CPtr = fv.value
|
||
if fexpr is None:
|
||
continue
|
||
# 检测 c.LInp / c.LOut
|
||
if fexpr.kind() == ast.ASTKind.Call:
|
||
fcall: ast.Call | t.CPtr = (ast.Call | t.CPtr)(fexpr)
|
||
attr_nm: str = self._asm_is_c_call(fcall)
|
||
if attr_nm is not None:
|
||
fargs: list[ast.AST | t.CPtr] | t.CPtr = fcall.args
|
||
if fargs is None or len(fargs) < 1:
|
||
continue
|
||
val_node: ast.AST | t.CPtr = fargs.get(0)
|
||
|
||
if string.strcmp(attr_nm, "LInp") == 0:
|
||
# 输入操作数:翻译值,替换为 LLVM 值引用文本(%x 或常量文本)
|
||
inp_val: llvmlite.Value | t.CPtr = self.Gen.ExprGen.translate_value(
|
||
builder, pool, mod, val_node, None, 0, trans)
|
||
if inp_val is not None and inp_val.Name is not None:
|
||
self._asm_append_cstr(text, LLVMIR_TEMPLATE_BUF, inp_val.Name)
|
||
|
||
elif string.strcmp(attr_nm, "LOut") == 0:
|
||
# 输出操作数:为变量分配唯一 SSA 寄存器 %llvmirN,
|
||
# 记录写回(模板嵌入后 store 到变量 alloca)
|
||
if val_node is not None and val_node.kind() == ast.ASTKind.Name:
|
||
nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(val_node)
|
||
if nm.id is not None:
|
||
alloca: llvmlite.Value | t.CPtr = self.Gen.VarGen.lookup_var(
|
||
trans.SymTab, nm.id)
|
||
if alloca is None or out_count >= LLVMIR_MAX_OPS:
|
||
self.Gen.TypeGenErr.fatal_error(
|
||
fcall,
|
||
f"c.LOut 变量 '{nm.id}' 未定义或输出数超过 {LLVMIR_MAX_OPS}",
|
||
"TypeError")
|
||
self.Gen.CallGenBase.LLVMIRRegSeq += 1
|
||
reg_buf: str = pool.alloc(32)
|
||
if reg_buf is not None:
|
||
viperlib.snprintf(reg_buf, 32, "%%llvmir_%d", self.Gen.CallGenBase.LLVMIRRegSeq)
|
||
self._asm_append_cstr(text, LLVMIR_TEMPLATE_BUF, reg_buf)
|
||
out_alloca[out_count] = t.CSizeT(alloca)
|
||
out_regname[out_count] = t.CSizeT(reg_buf)
|
||
out_count += 1
|
||
continue
|
||
# 非 c.LInp/c.LOut 的 f-string 表达式:翻译值并嵌入值文本
|
||
ival: llvmlite.Value | t.CPtr = self.Gen.ExprGen.translate_value(
|
||
builder, pool, mod, fexpr, None, 0, trans)
|
||
if ival is not None and ival.Name is not None:
|
||
self._asm_append_cstr(text, LLVMIR_TEMPLATE_BUF, ival.Name)
|
||
|
||
elif tk == ast.ASTKind.Constant:
|
||
cn2: ast.Constant | t.CPtr = (ast.Constant | t.CPtr)(first_arg)
|
||
if cn2.str_val is not None:
|
||
# 裸 strcpy 无界:模板常量串 ≥ LLVMIR_TEMPLATE_BUF 会越界写 pool 块,
|
||
# 改用与 JoinedStr 分支一致的有界追加
|
||
self._asm_append_cstr(text, LLVMIR_TEMPLATE_BUF, cn2.str_val)
|
||
|
||
# ============================================================
|
||
# 2. 直接嵌入模板文本(不做指令解析)+ LOut 写回
|
||
# ============================================================
|
||
llvmlite.block_append_text(pool, builder.CurBlock, text)
|
||
|
||
# LOut 写回: store <ty> %llvmirN, <ty>* %var
|
||
oi: int
|
||
for oi in range(out_count):
|
||
oa: llvmlite.Value | t.CPtr = (llvmlite.Value | t.CPtr)(t.CVoid(out_alloca[oi], t.CPtr))
|
||
rn: str = (str)(t.CVoid(out_regname[oi], t.CPtr))
|
||
if oa is None or oa.Ty is None or oa.Ty.Pointee is None or rn is None:
|
||
continue
|
||
reg_val: llvmlite.Value | t.CPtr = llvmlite.new_value(pool)
|
||
if reg_val is None:
|
||
continue
|
||
reg_val.Ty = oa.Ty.Pointee
|
||
reg_val.Name = rn
|
||
reg_val.IsConst = 0
|
||
llvmlite.build_store(builder, reg_val, oa)
|
||
|
||
return None
|
||
|
||
# ============================================================
|
||
# _apply_struct_defaults — 应用结构体字段的默认值
|
||
#
|
||
# 在 zeroinitializer 之后、显式参数之前调用
|
||
# 遍历所有字段,对有默认值的字段翻译并 store
|
||
# 显式参数(位置/关键字)后续会覆盖默认值
|
||
# ============================================================
|