直接移动+改调用方:~100 个委托函数按功能移至 6 个子模块,主文件 保留 _g_gen/set_global_gen/顶层常量/4 个类(AsmOperand、FuncEntry、 FuncDefaultsEntry、ExprCallHandle——CallGenLeafKit/HandlesTranslator 仍以 HandlesExprCall.类名 引用)。 - 子模块函数体内 _g_gen/常量/类裸引用 → HandlesExprCall.xxx 跨模块访问 - 28 个调用方 HandlesExprCall.func( → 子模块前缀并补 import - 全 App 语法/引用/import 验证通过
1232 lines
65 KiB
Plaintext
1232 lines
65 KiB
Plaintext
import t, c
|
||
from stdint import *
|
||
import ast
|
||
import llvmlite
|
||
import memhub
|
||
import string
|
||
import stdio
|
||
import stdlib
|
||
import viperlib
|
||
import w32.fileio as fileio
|
||
import lib.core.CompilerFactory as CompilerFactory
|
||
import lib.core.Handles.HandlesBase as HandlesBase
|
||
import lib.core.Handles.HandlesTranslator as HT
|
||
import lib.core.Handles.HandlesVar as HandlesVar
|
||
import lib.core.Handles.HandlesExpr as HandlesExpr
|
||
import lib.core.Handles.HandlesExprOps as HandlesExprOps
|
||
import lib.core.Handles.HandlesExprCall as HandlesExprCall
|
||
import lib.core.Handles.HandlesNonlocal as HandlesNonlocal
|
||
import lib.core.Handles.HandlesType as HandlesType
|
||
import lib.core.Handles.HandlesStruct as HandlesStruct
|
||
import lib.core.Handles.HandlesEnum as HandlesEnum
|
||
import lib.core.Handles.HandlesClassDef as HandlesClassDef
|
||
import lib.core.Handles.HandlesImports as HandlesImports
|
||
import lib.core.StubMerger as StubMerger
|
||
import lib.core.VLogger as VLogger
|
||
import lib.Projectrans.Config as Config
|
||
import lib.Projectrans.Utils as Utils
|
||
|
||
|
||
import lib.core.Gen.ExprGenBase as ExprGenBase
|
||
import lib.core.Handles.ExprCallBase as ExprCallBase
|
||
import lib.core.Handles.ExprCallCtor as ExprCallCtor
|
||
|
||
# ============================================================
|
||
# ExprGenOps - ExprGenMixin 拆分(阶段 D):比较/一元/布尔/binop 运算
|
||
#
|
||
# 继承 ExprGenBase(1 级,TPV self 调用仅支持 1 级父类)。
|
||
# 跨 Mixin 调用统一走 HandlesExpr 委托(经 _g_gen)。
|
||
# @t.NoVTable:静态绑定。
|
||
# ============================================================
|
||
@t.NoVTable
|
||
class ExprGenOps(ExprGenBase.ExprGenBase):
|
||
"""比较/一元/布尔/binop 运算"""
|
||
|
||
# ============================================================
|
||
# 翻译三元表达式 IfExp(test, body, orelse)
|
||
#
|
||
# 生成: cond ? body : orelse
|
||
# then_blk: 翻译 body → br merge
|
||
# else_blk: 翻译 orelse → br merge
|
||
# merge_blk: phi [body_val, then_blk], [orelse_val, else_blk]
|
||
# ============================================================
|
||
def translate_ifexp(self, builder: llvmlite.IRBuilder | t.CPtr,
|
||
pool: memhub.MemBuddy | t.CPtr,
|
||
mod: llvmlite.LLVMModule | t.CPtr,
|
||
node: ast.AST | t.CPtr,
|
||
trans: HT.Translator | t.CPtr = None) -> llvmlite.Value | t.CPtr:
|
||
"""翻译三元表达式 (body if test else orelse),返回 phi 结果 Value"""
|
||
if node is None or builder is None or trans is None:
|
||
return None
|
||
ie: ast.IfExp | t.CPtr = (ast.IfExp | t.CPtr)(node)
|
||
if ie is None:
|
||
return None
|
||
|
||
func: llvmlite.Function | t.CPtr = trans._cur_func
|
||
if func is None:
|
||
return None
|
||
|
||
# 1. 求值条件
|
||
cond_val: llvmlite.Value | t.CPtr = HandlesExpr.translate_value(
|
||
builder, pool, mod, ie.test, None, 0, trans)
|
||
if cond_val is None:
|
||
return None
|
||
# 转换为 i1
|
||
cond_bits: int = self.get_llvm_type_bits(cond_val.Ty)
|
||
if cond_bits == 1:
|
||
cond_i1: llvmlite.Value | t.CPtr = cond_val
|
||
else:
|
||
if self.is_ptr_type(cond_val.Ty) != 0:
|
||
# 指针类型:与 null 比较
|
||
null_cond: llvmlite.Value | t.CPtr = llvmlite.ConstNull(pool, cond_val.Ty, "null")
|
||
cond_i1 = llvmlite.build_icmp(builder, llvmlite.ICMP_NE, cond_val, null_cond)
|
||
else:
|
||
zero: llvmlite.Value | t.CPtr = llvmlite.const_int32(pool, 0)
|
||
cond_i1 = llvmlite.build_icmp(builder, llvmlite.ICMP_NE, cond_val, zero)
|
||
|
||
# 2. 创建三个基本块
|
||
cnt: int = trans._label_counter
|
||
trans._label_counter = cnt + 1
|
||
name_buf: str = pool.alloc(32)
|
||
if name_buf is None:
|
||
return None
|
||
viperlib.snprintf(name_buf, 32, "ifexp.then.%d", cnt)
|
||
then_bb: llvmlite.BasicBlock | t.CPtr = llvmlite.create_block(pool, func, name_buf)
|
||
viperlib.snprintf(name_buf, 32, "ifexp.else.%d", cnt)
|
||
else_bb: llvmlite.BasicBlock | t.CPtr = llvmlite.create_block(pool, func, name_buf)
|
||
viperlib.snprintf(name_buf, 32, "ifexp.merge.%d", cnt)
|
||
merge_bb: llvmlite.BasicBlock | t.CPtr = llvmlite.create_block(pool, func, name_buf)
|
||
|
||
if then_bb is None or else_bb is None or merge_bb is None:
|
||
return None
|
||
|
||
# 3. 条件跳转
|
||
llvmlite.build_cond_br(builder, cond_i1, then_bb, else_bb)
|
||
|
||
# 4. then 分支
|
||
llvmlite.position_at_end(builder, then_bb)
|
||
body_val: llvmlite.Value | t.CPtr = HandlesExpr.translate_value(
|
||
builder, pool, mod, ie.body, None, 0, trans)
|
||
then_blk_for_phi: llvmlite.BasicBlock | t.CPtr = trans._cur_builder.CurBlock
|
||
if body_val is None:
|
||
# fail-fast:三元表达式 then 分支翻译失败,立即终止编译(暴露上游根因)
|
||
HandlesType.fatal_error(ie.body, "三元表达式分支翻译失败", "TypeError")
|
||
# 暂不 br,等类型对齐后再 br
|
||
|
||
# 5. else 分支
|
||
llvmlite.position_at_end(builder, else_bb)
|
||
orelse_val: llvmlite.Value | t.CPtr = HandlesExpr.translate_value(
|
||
builder, pool, mod, ie.orelse, None, 0, trans)
|
||
else_blk_for_phi: llvmlite.BasicBlock | t.CPtr = trans._cur_builder.CurBlock
|
||
if orelse_val is None:
|
||
# fail-fast:三元表达式 else 分支翻译失败,立即终止编译(暴露上游根因)
|
||
HandlesType.fatal_error(ie.orelse, "三元表达式分支翻译失败", "TypeError")
|
||
# 暂不 br,等类型对齐后再 br
|
||
|
||
# 类型对齐 (两分支类型可能不同)
|
||
# 必须在各自分支中执行 coerce_to_type,确保 merge 块中 PHI 是第一条指令
|
||
# (否则 coerce_to_type 生成的 sext/zext/ptrtoint/inttoptr 指令在 PHI 之前,违反 LLVM 规则)
|
||
body_bits: int = self.get_llvm_type_bits(body_val.Ty)
|
||
orelse_bits: int = self.get_llvm_type_bits(orelse_val.Ty)
|
||
body_is_ptr: int = self.is_ptr_type(body_val.Ty)
|
||
orelse_is_ptr: int = self.is_ptr_type(orelse_val.Ty)
|
||
# 情况0: 一侧是指针,另一侧是整数(如 i64 vs i8* null)
|
||
# 必须优先处理,因为 Ptr 的 bits=0 会导致下面三个分支全部跳过
|
||
# 选择 body_val.Ty 作为 phi_ty(then 分支优先),orelse_val 对齐到它
|
||
# coerce_to_type 内部会调用 ptrtoint(指针→整数)或 inttoptr(整数→指针)
|
||
if body_is_ptr != orelse_is_ptr:
|
||
llvmlite.position_at_end(builder, else_blk_for_phi)
|
||
orelse_val = self.coerce_to_type(builder, orelse_val, body_val.Ty, node)
|
||
elif body_bits > orelse_bits and orelse_bits > 0:
|
||
# 在 else 块中转换 orelse_val
|
||
llvmlite.position_at_end(builder, else_blk_for_phi)
|
||
orelse_val = self.coerce_to_type(builder, orelse_val, body_val.Ty, node)
|
||
elif orelse_bits > body_bits and body_bits > 0:
|
||
# 回到 then 块转换 body_val
|
||
llvmlite.position_at_end(builder, then_blk_for_phi)
|
||
body_val = self.coerce_to_type(builder, body_val, orelse_val.Ty, node)
|
||
elif body_bits == orelse_bits and body_bits > 0:
|
||
# bits 相同但类型不同(如 i64 vs Ptr):null 不能用于 i64 PHI
|
||
# 此分支理论上不会触发(已被情况0覆盖),保留作为防御
|
||
if self.is_ptr_type(body_val.Ty) != self.is_ptr_type(orelse_val.Ty):
|
||
llvmlite.position_at_end(builder, else_blk_for_phi)
|
||
orelse_val = self.coerce_to_type(builder, orelse_val, body_val.Ty, node)
|
||
|
||
# 现在分别在 then/else 块中 br 到 merge(在类型转换之后)
|
||
llvmlite.position_at_end(builder, then_blk_for_phi)
|
||
llvmlite.build_br(builder, merge_bb)
|
||
llvmlite.position_at_end(builder, else_blk_for_phi)
|
||
llvmlite.build_br(builder, merge_bb)
|
||
|
||
# 6. merge 块: phi(PHI 是 merge 块的第一条指令)
|
||
llvmlite.position_at_end(builder, merge_bb)
|
||
|
||
phi_ty: llvmlite.LLVMType | t.CPtr = body_val.Ty
|
||
if phi_ty is None:
|
||
# fail-fast:三元表达式分支类型缺失,立即终止编译(暴露上游根因)
|
||
HandlesType.fatal_error(node, "三元表达式分支类型缺失", "TypeError")
|
||
|
||
inc1: llvmlite.PhiIncoming | t.CPtr = llvmlite.new_phi_incoming(
|
||
pool, body_val, then_blk_for_phi)
|
||
inc2: llvmlite.PhiIncoming | t.CPtr = llvmlite.new_phi_incoming(
|
||
pool, orelse_val, else_blk_for_phi)
|
||
if inc1 is None or inc2 is None:
|
||
return None
|
||
# 链表顺序: inc1 (head) -> inc2 (tail)
|
||
# 之前错误写成 inc2.Next = inc1,导致 build_phi 从 inc1 遍历时
|
||
# inc1.Next 为 None,只输出一个 phi 条目,引发 LLVM 验证错误:
|
||
# "PHINode should have one entry for each predecessor"
|
||
inc1.Next = inc2
|
||
return llvmlite.build_phi(builder, phi_ty, inc1, 2)
|
||
# ============================================================
|
||
# 翻译比较表达式 Compare(left, ops, comparators)
|
||
# ============================================================
|
||
def should_zext_widen(self, pool: memhub.MemBuddy | t.CPtr,
|
||
narrow_val: llvmlite.Value | t.CPtr,
|
||
wide_val: llvmlite.Value | t.CPtr,
|
||
narrow_node: ast.AST | t.CPtr = None) -> int:
|
||
"""判断整数拓宽方向:1=zext(无符号语义),0=sext
|
||
|
||
对齐 TPC 的 _check_node_unsigned / HandlesExprOps 拓宽规则:
|
||
1. i1 (bool) → zext(1 保持 1,而非 sext 的 0xFF...)
|
||
2. i8 → zext(系统编程中 i8 几乎总是无符号字节)
|
||
3. 宽侧是常量且其值超出窄侧位宽的有符号范围 → zext
|
||
(常量"想要"无符号解释,如 0xAABBCCDD > INT32_MAX 与
|
||
t.CUInt32T 值比较,sext 会把 0xAABBCCDD 变成
|
||
0xFFFFFFFFAABBCCDD 导致恒不等)
|
||
"""
|
||
if narrow_val is None or narrow_val.Ty is None:
|
||
return 0
|
||
narrow_bits: int = self.get_llvm_type_bits(narrow_val.Ty)
|
||
if narrow_bits == 1:
|
||
return 1
|
||
if narrow_bits == 8:
|
||
return 1
|
||
# 宽侧常量启发式
|
||
if wide_val is not None and wide_val.IsConst == 1:
|
||
wide_bits: int = self.get_llvm_type_bits(wide_val.Ty)
|
||
if wide_bits > narrow_bits and narrow_bits < 64:
|
||
signed_max: t.CInt64T = (t.CInt64T(1) << (narrow_bits - 1)) - 1
|
||
if wide_val.IntVal > signed_max:
|
||
return 1
|
||
# 窄侧 AST 节点解析为无符号类型(如 t.CUIntXXT 字面量/强转)
|
||
if narrow_node is not None:
|
||
if self._node_type_unsigned(pool, narrow_node) != 0:
|
||
return 1
|
||
return 0
|
||
def _node_type_unsigned(self, pool: memhub.MemBuddy | t.CPtr,
|
||
node: ast.AST | t.CPtr,
|
||
trans: HT.Translator | t.CPtr = None) -> int:
|
||
"""轻量判断 AST 节点是否解析为无符号整数类型(1=是,0=否/未知)
|
||
|
||
覆盖常见形态(对齐 TPC _check_node_unsigned 的 Call/Subscript 分支):
|
||
- t.CUInt8T/CUInt16T/CUInt32T/CUInt64T/CUnsigned* 等显式无符号类型强转调用
|
||
- 无符号类型名的 Name 引用(如 UInt32T 别名)
|
||
- 变量名(trans 可用时):查询 SymTab 中变量的 AnnotClassName(如 v: t.CUInt32T)
|
||
"""
|
||
if node is None:
|
||
return 0
|
||
k: int = node.kind()
|
||
if k == ast.ASTKind.Call:
|
||
cl: ast.Call | t.CPtr = (ast.Call | t.CPtr)(node)
|
||
if cl.func is not None and cl.func.kind() == ast.ASTKind.Attribute:
|
||
at: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(cl.func)
|
||
if at.value is not None and at.value.kind() == ast.ASTKind.Name:
|
||
mod_nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(at.value)
|
||
if mod_nm.id is not None and string.strcmp(mod_nm.id, "t") == 0 \
|
||
and at.attr is not None:
|
||
if self._type_name_unsigned(at.attr) != 0:
|
||
return 1
|
||
return 0
|
||
if k == ast.ASTKind.Name:
|
||
nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(node)
|
||
if nm.id is not None:
|
||
# 1) 名字本身是无符号类型名(如 UInt32T 别名)
|
||
if self._type_name_unsigned(nm.id) != 0:
|
||
return 1
|
||
# 2) 变量注解类型为无符号类型(trans 可用时查 SymTab)
|
||
if trans is not None:
|
||
ve: HandlesVar.VarEntry | t.CPtr = HandlesVar.lookup_var_entry(
|
||
trans.SymTab, nm.id)
|
||
if ve is not None and ve.AnnotClassName is not None:
|
||
if self._type_name_unsigned(ve.AnnotClassName) != 0:
|
||
return 1
|
||
return 0
|
||
if k == ast.ASTKind.BinOp:
|
||
bop: ast.BinOp | t.CPtr = (ast.BinOp | t.CPtr)(node)
|
||
if self._node_type_unsigned(pool, bop.left, trans) != 0:
|
||
return 1
|
||
if self._node_type_unsigned(pool, bop.right, trans) != 0:
|
||
return 1
|
||
return 0
|
||
if k == ast.ASTKind.UnaryOp:
|
||
uop: ast.UnaryOp | t.CPtr = (ast.UnaryOp | t.CPtr)(node)
|
||
if self._node_type_unsigned(pool, uop.operand, trans) != 0:
|
||
return 1
|
||
return 0
|
||
if k == ast.ASTKind.Subscript:
|
||
# 数组/指针下标: md5_buf[i](t.CArray[t.CUInt8T, N])或 buf[i]
|
||
# (形参 t.CUInt8T | t.CPtr)元素是无符号整型 → printf("%02x", ...) zext。
|
||
sub_su: ast.Subscript | t.CPtr = (ast.Subscript | t.CPtr)(node)
|
||
if sub_su.value is not None and sub_su.value.kind() == ast.ASTKind.Name:
|
||
snm_su: ast.Name | t.CPtr = (ast.Name | t.CPtr)(sub_su.value)
|
||
if snm_su.id is not None and trans is not None:
|
||
ve_su: HandlesVar.VarEntry | t.CPtr = HandlesVar.lookup_var_entry(
|
||
trans.SymTab, snm_su.id)
|
||
if ve_su is not None and ve_su.AnnotClassName is not None:
|
||
if self._annot_str_unsigned(ve_su.AnnotClassName) != 0:
|
||
return 1
|
||
return 0
|
||
return 0
|
||
def _type_name_unsigned(self, type_name: str) -> int:
|
||
"""类型名是否为无符号整数类型(精确匹配,避免子串误伤如 nUIntCount)"""
|
||
if type_name is None:
|
||
return 0
|
||
# t.CUIntXXT 形式
|
||
if string.strcmp(type_name, "CUInt8T") == 0: return 1
|
||
if string.strcmp(type_name, "CUInt16T") == 0: return 1
|
||
if string.strcmp(type_name, "CUInt32T") == 0: return 1
|
||
if string.strcmp(type_name, "CUInt64T") == 0: return 1
|
||
# stdint 裸别名(from stdint import *)
|
||
if string.strcmp(type_name, "UInt8T") == 0: return 1
|
||
if string.strcmp(type_name, "UInt16T") == 0: return 1
|
||
if string.strcmp(type_name, "UInt32T") == 0: return 1
|
||
if string.strcmp(type_name, "UInt64T") == 0: return 1
|
||
# CUnsigned* 形式
|
||
if string.strcmp(type_name, "CUnsignedChar") == 0: return 1
|
||
if string.strcmp(type_name, "CUnsignedShort") == 0: return 1
|
||
if string.strcmp(type_name, "CUnsignedInt") == 0: return 1
|
||
if string.strcmp(type_name, "CUnsignedLong") == 0: return 1
|
||
if string.strcmp(type_name, "CUnsignedLongLong") == 0: return 1
|
||
# 常见无符号别名
|
||
if string.strcmp(type_name, "BYTE") == 0: return 1
|
||
if string.strcmp(type_name, "UCHAR") == 0: return 1
|
||
if string.strcmp(type_name, "USHORT") == 0: return 1
|
||
if string.strcmp(type_name, "UINT") == 0: return 1
|
||
if string.strcmp(type_name, "ULONG") == 0: return 1
|
||
return 0
|
||
def _annot_str_unsigned(self, annot: str) -> int:
|
||
"""检查类型注解字符串是否引用无符号整型(子串扫描)
|
||
|
||
用于复合注解(t.CArray[t.CUInt8T, 16] / t.CUInt8T | t.CPtr),
|
||
_type_name_unsigned 的精确匹配对这类串不适用。
|
||
"""
|
||
if annot is None:
|
||
return 0
|
||
if string.strstr(annot, "CUInt8T") is not None: return 1
|
||
if string.strstr(annot, "CUInt16T") is not None: return 1
|
||
if string.strstr(annot, "CUInt32T") is not None: return 1
|
||
if string.strstr(annot, "CUInt64T") is not None: return 1
|
||
if string.strstr(annot, "CUnsigned") is not None: return 1
|
||
if string.strstr(annot, "BYTE") is not None: return 1
|
||
if string.strstr(annot, "UCHAR") is not None: return 1
|
||
if string.strstr(annot, "USHORT") is not None: return 1
|
||
if string.strstr(annot, "UINT") is not None: return 1
|
||
if string.strstr(annot, "ULONG") is not None: return 1
|
||
return 0
|
||
def translate_compare(self, builder: llvmlite.IRBuilder | t.CPtr,
|
||
pool: memhub.MemBuddy | t.CPtr,
|
||
mod: llvmlite.LLVMModule | t.CPtr,
|
||
node: ast.AST | t.CPtr,
|
||
trans: HT.Translator | t.CPtr = None) -> llvmlite.Value | t.CPtr:
|
||
"""翻译比较表达式,返回 i1 结果"""
|
||
cmp: ast.Compare | t.CPtr = (ast.Compare | t.CPtr)(node)
|
||
if cmp is None:
|
||
return None
|
||
|
||
ops_list: list[t.CInt] | t.CPtr = (list[t.CInt] | t.CPtr)(cmp.ops)
|
||
if ops_list is None or len(ops_list) == 0:
|
||
return None
|
||
op: int = ops_list.get(0)
|
||
|
||
comparators: list[ast.AST | t.CPtr] | t.CPtr = cmp.comparators
|
||
if comparators is None or len(comparators) == 0:
|
||
return None
|
||
rhs_node: ast.AST | t.CPtr = comparators.get(0)
|
||
rhs: llvmlite.Value | t.CPtr = HandlesExpr.translate_value(
|
||
builder, pool, mod, rhs_node, None, 0, trans)
|
||
if rhs is None:
|
||
return None
|
||
|
||
# === None 比较优化: x == None / x != None 走身份比较(icmp eq/ne null)===
|
||
# 避免对结构体指针生成无效的 __eq__/__ne__ 调用(方法未定义但类有 SHA1 时
|
||
# try_operator_overload 会误生成 call void @...__eq__(...) 导致链接错误)
|
||
# 语义依据: Python 中 == None / != None 默认走身份比较,不调用 __eq__/__ne__
|
||
lhs_node: ast.AST | t.CPtr = cmp.left
|
||
cmp_with_none: int = 0
|
||
if op == ast.OpKind.Eq or op == ast.OpKind.Ne or op == ast.OpKind.Is or op == ast.OpKind.IsNot:
|
||
if rhs_node is not None and rhs_node.kind() == ast.ASTKind.Constant:
|
||
rhs_cn: ast.Constant | t.CPtr = (ast.Constant | t.CPtr)(rhs_node)
|
||
if rhs_cn is not None and rhs_cn.const_kind == ast.CONST_NONE:
|
||
cmp_with_none = 1
|
||
if cmp_with_none == 0 and lhs_node is not None and lhs_node.kind() == ast.ASTKind.Constant:
|
||
lhs_cn: ast.Constant | t.CPtr = (ast.Constant | t.CPtr)(lhs_node)
|
||
if lhs_cn is not None and lhs_cn.const_kind == ast.CONST_NONE:
|
||
cmp_with_none = 1
|
||
|
||
# === 指针判空模式: ptr != 0 / ptr == 0 ===
|
||
# 跳过运算符重载走身份比较(icmp null)。跨模块类(如 cpython.PyObject)
|
||
# 未定义 __eq__/__ne__ 时,try_operator_overload 无法判定方法不存在
|
||
# (类在依赖模块,cls_sha1 != trans.ModuleSha1),会误发幽灵
|
||
# `call void @...__ne__` → 链接 undefined reference(CPythonTest main.vp
|
||
# `py_num != 0` 根因)。C 语义:指针与字面量 0 比较 = 判空。
|
||
cmp_zero: int = 0
|
||
if op == ast.OpKind.Eq or op == ast.OpKind.Ne:
|
||
if rhs_node is not None and self._is_zero_int_literal(rhs_node) != 0:
|
||
cmp_zero = 1
|
||
if cmp_zero == 0 and lhs_node is not None and self._is_zero_int_literal(lhs_node) != 0:
|
||
cmp_zero = 1
|
||
|
||
# === 比较运算符重载路径 1: lhs 是 Name 且对应结构体变量 ===
|
||
# 对于值类型变量(如 cnt: Counter),用 alloca 指针尝试重载
|
||
# None 比较跳过重载(走身份比较)
|
||
if cmp_with_none == 0 and lhs_node is not None and lhs_node.kind() == ast.ASTKind.Name and trans is not None:
|
||
nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(lhs_node)
|
||
if nm is not None and nm.id is not None:
|
||
lhs_alloca: llvmlite.Value | t.CPtr = HandlesVar.lookup_var(
|
||
trans.SymTab, nm.id)
|
||
if lhs_alloca is not None:
|
||
if cmp_zero == 0 or self.get_ptr_level(lhs_alloca.Ty) == 0:
|
||
ovl_self1: llvmlite.Value | t.CPtr = lhs_alloca
|
||
# Ptr(Ptr(Struct)) 对象存储槽:load 出对象指针作 self
|
||
# (与 translate_binop 路径 1 一致,避免槽地址当对象地址)
|
||
if lhs_alloca.Ty is not None and lhs_alloca.Ty.Pointee is not None \
|
||
and HandlesExpr.is_ptr_type(lhs_alloca.Ty.Pointee) != 0:
|
||
load_self1: llvmlite.Value | t.CPtr = llvmlite.build_load(
|
||
builder, lhs_alloca.Ty.Pointee, lhs_alloca)
|
||
if load_self1 is not None:
|
||
ovl_self1 = load_self1
|
||
ovl_result: llvmlite.Value | t.CPtr = self.try_operator_overload(
|
||
pool, builder, mod, ovl_self1, rhs, op, trans, 1)
|
||
if ovl_result is not None:
|
||
return ovl_result
|
||
|
||
# 正常翻译 lhs
|
||
lhs: llvmlite.Value | t.CPtr = HandlesExpr.translate_value(
|
||
builder, pool, mod, cmp.left, None, 0, trans)
|
||
if lhs is None:
|
||
return None
|
||
|
||
# === in / not in:容器右操作数调用 __contains__(对齐 TPC
|
||
# HandlesExprOps.py L261-281)。x in y → y.__contains__(x);
|
||
# x not in y → !y.__contains__(x)。容器无 __contains__ →
|
||
# 返回 i1 0(TPC 同:恒 False)。
|
||
if op == ast.OpKind.In or op == ast.OpKind.NotIn:
|
||
cn_st: llvmlite.LLVMType | t.CPtr = HandlesStruct.get_struct_type_from_value(rhs)
|
||
if cn_st is not None:
|
||
cn_cls: str = HandlesStruct.get_class_name_by_type(pool, cn_st)
|
||
if cn_cls is not None:
|
||
cn_lookup: str = pool.alloc(128)
|
||
if cn_lookup is not None:
|
||
viperlib.snprintf(cn_lookup, 128, "%s.__contains__", cn_cls)
|
||
cn_fn: llvmlite.Function | t.CPtr = ExprCallBase.find_func_in_module(
|
||
mod, cn_lookup)
|
||
if cn_fn is not None:
|
||
cn_ret: llvmlite.LLVMType | t.CPtr = llvmlite.function_get_ret_ty(cn_fn)
|
||
cn_fn_name: str = llvmlite.function_get_name(cn_fn)
|
||
if cn_ret is not None and cn_fn_name is not None:
|
||
# self 参数(容器)按 __contains__ 首参类型对齐
|
||
cn_self: llvmlite.Value | t.CPtr = rhs
|
||
cn_first: llvmlite.Param | t.CPtr = llvmlite.function_get_param_head(cn_fn)
|
||
if cn_first is not None:
|
||
cn_self_ty: llvmlite.LLVMType | t.CPtr = llvmlite.param_get_ty(cn_first)
|
||
if cn_self_ty is not None:
|
||
cn_self = llvmlite.build_bitcast(builder, rhs, cn_self_ty)
|
||
if cn_self is not None:
|
||
# 参数链表: self → key(独立 null 结尾)
|
||
cn_self.Next = lhs
|
||
lhs.Next = None
|
||
cn_res: llvmlite.Value | t.CPtr = llvmlite.build_call(
|
||
builder, cn_fn_name, cn_self, 2, cn_ret, 0)
|
||
if cn_res is not None:
|
||
# 归一化到 i1(__contains__ 返回 t.CInt/i32 等)
|
||
cn_i1: llvmlite.Value | t.CPtr = cn_res
|
||
match cn_ret:
|
||
case llvmlite.LLVMType.Int(cn_bits):
|
||
if cn_bits > 1:
|
||
cn_zero: llvmlite.Value | t.CPtr = llvmlite.ConstInt(
|
||
pool, cn_ret, 0, "0")
|
||
if cn_zero is not None:
|
||
cn_i1 = llvmlite.build_icmp(
|
||
builder, llvmlite.ICMP_NE, cn_res, cn_zero)
|
||
case _:
|
||
pass
|
||
if op == ast.OpKind.NotIn:
|
||
i1_ty_ni: llvmlite.LLVMType | t.CPtr = llvmlite.Int1(pool)
|
||
if i1_ty_ni is not None and cn_i1 is not None:
|
||
one_i1_ni: llvmlite.Value | t.CPtr = llvmlite.ConstInt(
|
||
pool, i1_ty_ni, 1, "1")
|
||
if one_i1_ni is not None:
|
||
cn_i1 = llvmlite.build_xor(builder, cn_i1, one_i1_ni)
|
||
if cn_i1 is not None:
|
||
return cn_i1
|
||
# 容器无 __contains__:TPC 语义恒 False(i1 0)
|
||
i1_ty_in: llvmlite.LLVMType | t.CPtr = llvmlite.Int1(pool)
|
||
if i1_ty_in is not None:
|
||
return llvmlite.ConstInt(pool, i1_ty_in, 0, "0")
|
||
return None
|
||
|
||
# === 比较运算符重载路径 2: lhs 是 Ptr(Struct) ===
|
||
# Is/IsNot 不在 _cmpop_to_dunder 映射中,会自动返回 None 回退原生比较
|
||
# None 比较跳过重载(走身份比较);指针判空(cmp_zero + 指针)同样跳过
|
||
if cmp_with_none == 0 and (cmp_zero == 0 or self.get_ptr_level(lhs.Ty) == 0):
|
||
ovl_result2: llvmlite.Value | t.CPtr = self.try_operator_overload(
|
||
pool, builder, mod, lhs, rhs, op, trans, 1)
|
||
if ovl_result2 is not None:
|
||
return ovl_result2
|
||
|
||
predicate: int = llvmlite.ICMP_SLT
|
||
if op == ast.OpKind.Lt:
|
||
predicate = llvmlite.ICMP_SLT
|
||
elif op == ast.OpKind.Le:
|
||
predicate = llvmlite.ICMP_SLE
|
||
elif op == ast.OpKind.Gt:
|
||
predicate = llvmlite.ICMP_SGT
|
||
elif op == ast.OpKind.Ge:
|
||
predicate = llvmlite.ICMP_SGE
|
||
elif op == ast.OpKind.Eq:
|
||
predicate = llvmlite.ICMP_EQ
|
||
elif op == ast.OpKind.Ne:
|
||
predicate = llvmlite.ICMP_NE
|
||
elif op == ast.OpKind.Is:
|
||
# `x is y` → 指针/值相等比较
|
||
predicate = llvmlite.ICMP_EQ
|
||
elif op == ast.OpKind.IsNot:
|
||
# `x is not y` → 指针/值不等比较
|
||
predicate = llvmlite.ICMP_NE
|
||
|
||
# === 类型安全检查(BUG2 修复)===
|
||
# 规则:
|
||
# - 数值(0) vs 数值(0) → 允许(无关类型,按位宽 sext 对齐)
|
||
# - 一级指针(1) vs 一级指针(1) → 允许(无关 pointee 类型,地址比较)
|
||
# - 数值(0) vs 指针(1+) → 禁止(fast-fail,除 None 比较外)
|
||
# - 不同级指针(1 vs 2 等) → 禁止(fast-fail)
|
||
#
|
||
# None 比较跳过此检查(None 被翻译为 null 指针或 0,与任意指针/数值比较合法)
|
||
if cmp_with_none == 0:
|
||
lhs_ptr_level: int = self.get_ptr_level(lhs.Ty)
|
||
rhs_ptr_level: int = self.get_ptr_level(rhs.Ty)
|
||
if lhs_ptr_level != rhs_ptr_level:
|
||
# 指针 vs 整数字面量 0(判空模式 ptr != 0 / ptr == 0):
|
||
# 0 视为 NULL,转成与指针侧同类型的 null 指针(icmp 需要同类型),
|
||
# 不报类型不匹配(ClassArrayTest 的 if ptr != 0 等常见模式)。
|
||
zero_is_rhs: int = 0
|
||
zero_is_lhs: int = 0
|
||
if rhs_ptr_level == 0 and self._is_zero_int_literal(rhs_node) != 0:
|
||
zero_is_rhs = 1
|
||
if lhs_ptr_level == 0 and self._is_zero_int_literal(lhs_node) != 0:
|
||
zero_is_lhs = 1
|
||
if zero_is_rhs != 0 or zero_is_lhs != 0:
|
||
if zero_is_rhs != 0:
|
||
rhs = llvmlite.ConstNull(pool, lhs.Ty, "null")
|
||
else:
|
||
lhs = llvmlite.ConstNull(pool, rhs.Ty, "null")
|
||
else:
|
||
# 指针 vs 非零整数(C 哨兵值模式,如 w32.win32base.INVALID_HANDLE_VALUE = -1):
|
||
# 对齐 TPC HandlesExprOps.py L388-398 —— 指针 ptrtoint 成整数做地址值比较。
|
||
# (指针 vs 整数字面量 0 已在上方转 null 处理;此处处理非零整数哨兵)
|
||
if lhs_ptr_level != 0 and rhs_ptr_level == 0:
|
||
lhs = llvmlite.build_ptrtoint(builder, lhs, rhs.Ty)
|
||
elif rhs_ptr_level != 0 and lhs_ptr_level == 0:
|
||
rhs = llvmlite.build_ptrtoint(builder, rhs, lhs.Ty)
|
||
else:
|
||
# 不同级指针(1 vs 2 等)→ 禁止(fast-fail)
|
||
HandlesType.fatal_error(
|
||
cmp,
|
||
f"比较类型不匹配: 不同级指针比较 (lhs 层级={lhs_ptr_level}, rhs 层级={rhs_ptr_level})",
|
||
"TypeError")
|
||
else:
|
||
# None 比较: None 被翻译为 i8* null(一级指针)
|
||
# 如果 lhs 是指针,将 rhs (i8* null) bitcast 为 lhs 的指针类型
|
||
# 如果 lhs 是数值,将 rhs 转为数值 0(走正常整数比较)
|
||
# 如果 lhs 是结构体值类型,结构体永远不等于 None,返回常量 i1
|
||
lhs_ptr_level_none: int = self.get_ptr_level(lhs.Ty)
|
||
rhs_ptr_level_none: int = self.get_ptr_level(rhs.Ty)
|
||
if lhs_ptr_level_none != 0 and rhs_ptr_level_none != 0:
|
||
# 两边都是指针,类型可能不同(如 lhs=Struct*, rhs=i8* null)
|
||
# 由下方 bitcast 对齐处理,此处不处理
|
||
pass
|
||
elif lhs_ptr_level_none != 0 and rhs_ptr_level_none == 0:
|
||
# lhs 是指针, rhs 是数值 → 将 rhs 转为同层级 null 指针
|
||
rhs = llvmlite.ConstNull(pool, lhs.Ty, "null")
|
||
elif rhs_ptr_level_none != 0 and lhs_ptr_level_none == 0:
|
||
# 检查 lhs 是否是结构体值类型(非指针的 Struct)
|
||
lhs_is_struct_none: int = 0
|
||
match lhs.Ty:
|
||
case llvmlite.LLVMType.Struct(_, _, _):
|
||
lhs_is_struct_none = 1
|
||
case _:
|
||
lhs_is_struct_none = 0
|
||
if lhs_is_struct_none != 0:
|
||
# 结构体值永远不等于 None:==/is 返回 false,!=/is not 返回 true
|
||
if op == ast.OpKind.Eq or op == ast.OpKind.Is:
|
||
return llvmlite.const_int(pool, 1, 0)
|
||
else: # Ne, IsNot
|
||
return llvmlite.const_int(pool, 1, 1)
|
||
# lhs 是数值, rhs 是 i8* null → 将 rhs 转为数值 0(保持 lhs 不变)
|
||
rhs = llvmlite.const_int32(pool, 0)
|
||
|
||
# 类型对齐:icmp 要求两边类型相同
|
||
# 仅对数值类型做对齐(指针类型无需对齐,LLVM 允许同层级指针直接 icmp)
|
||
# i1 (bool) 侧用 zext 对齐(1 保持 1,而非 sext 的 0xFF...)
|
||
lhs_bits: int = self.get_llvm_type_bits(lhs.Ty)
|
||
rhs_bits: int = self.get_llvm_type_bits(rhs.Ty)
|
||
if lhs_bits != 0 and rhs_bits != 0 and lhs_bits != rhs_bits:
|
||
if lhs_bits < rhs_bits:
|
||
if self.should_zext_widen(pool, lhs, rhs, cmp.left) != 0:
|
||
lhs = llvmlite.build_zext(builder, lhs, rhs.Ty)
|
||
else:
|
||
lhs = llvmlite.build_sext(builder, lhs, rhs.Ty)
|
||
else:
|
||
if self.should_zext_widen(pool, rhs, lhs, rhs_node) != 0:
|
||
rhs = llvmlite.build_zext(builder, rhs, lhs.Ty)
|
||
else:
|
||
rhs = llvmlite.build_sext(builder, rhs, lhs.Ty)
|
||
|
||
# 指针类型对齐:同层级但不同 pointee 类型的指针需要 bitcast 统一类型
|
||
# 例如 i8* vs Struct* → 将 rhs bitcast 为 lhs 的类型
|
||
if lhs_bits == 0 and rhs_bits == 0:
|
||
lhs_is_ptr_now: int = self.is_ptr_type(lhs.Ty)
|
||
rhs_is_ptr_now: int = self.is_ptr_type(rhs.Ty)
|
||
if lhs_is_ptr_now != 0 and rhs_is_ptr_now != 0:
|
||
# 两边都是指针,用 TypePrint 比较类型字符串
|
||
lhs_ty_buf: str = pool.alloc(128)
|
||
rhs_ty_buf: str = pool.alloc(128)
|
||
if lhs_ty_buf is not None and rhs_ty_buf is not None:
|
||
llvmlite.TypePrint(lhs_ty_buf, 128, lhs.Ty, pool)
|
||
llvmlite.TypePrint(rhs_ty_buf, 128, rhs.Ty, pool)
|
||
if string.strcmp(lhs_ty_buf, rhs_ty_buf) != 0:
|
||
rhs = llvmlite.build_bitcast(builder, rhs, lhs.Ty)
|
||
|
||
# 浮点比较:任一操作数为浮点类型时使用 fcmp 而非 icmp
|
||
lhs_fbits: int = self.get_llvm_float_bits(lhs.Ty)
|
||
rhs_fbits: int = self.get_llvm_float_bits(rhs.Ty)
|
||
if lhs_fbits != 0 or rhs_fbits != 0:
|
||
# 浮点类型对齐(fpext/fptrunc)
|
||
if lhs_fbits != 0 and rhs_fbits != 0 and lhs_fbits != rhs_fbits:
|
||
if lhs_fbits < rhs_fbits:
|
||
lhs = llvmlite.build_fpext(builder, lhs, rhs.Ty)
|
||
else:
|
||
rhs = llvmlite.build_fptrunc(builder, rhs, lhs.Ty)
|
||
elif lhs_fbits != 0 and rhs_fbits == 0:
|
||
# int → float
|
||
rhs = llvmlite.build_si2fp(builder, rhs, lhs.Ty)
|
||
elif rhs_fbits != 0 and lhs_fbits == 0:
|
||
lhs = llvmlite.build_si2fp(builder, lhs, rhs.Ty)
|
||
# 映射比较谓词到 fcmp
|
||
fpredicate: int = llvmlite.FCMP_OEQ
|
||
if op == ast.OpKind.Eq or op == ast.OpKind.Is:
|
||
fpredicate = llvmlite.FCMP_OEQ
|
||
elif op == ast.OpKind.Ne or op == ast.OpKind.IsNot:
|
||
fpredicate = llvmlite.FCMP_ONE
|
||
elif op == ast.OpKind.Lt:
|
||
fpredicate = llvmlite.FCMP_OLT
|
||
elif op == ast.OpKind.Le:
|
||
fpredicate = llvmlite.FCMP_OLE
|
||
elif op == ast.OpKind.Gt:
|
||
fpredicate = llvmlite.FCMP_OGT
|
||
elif op == ast.OpKind.Ge:
|
||
fpredicate = llvmlite.FCMP_OGE
|
||
return llvmlite.build_fcmp(builder, fpredicate, lhs, rhs)
|
||
|
||
return llvmlite.build_icmp(builder, predicate, lhs, rhs)
|
||
# ============================================================
|
||
# 翻译一元运算表达式 UnaryOp(op, operand)
|
||
# ============================================================
|
||
def translate_unaryop(self, builder: llvmlite.IRBuilder | t.CPtr,
|
||
pool: memhub.MemBuddy | t.CPtr,
|
||
mod: llvmlite.LLVMModule | t.CPtr,
|
||
node: ast.AST | t.CPtr,
|
||
trans: HT.Translator | t.CPtr = None) -> llvmlite.Value | t.CPtr:
|
||
"""翻译一元运算(-x, +x, not x, ~x)"""
|
||
uo: ast.UnaryOp | t.CPtr = (ast.UnaryOp | t.CPtr)(node)
|
||
if uo is None:
|
||
return None
|
||
|
||
operand: llvmlite.Value | t.CPtr = HandlesExpr.translate_value(
|
||
builder, pool, mod, uo.operand, None, 0, trans)
|
||
if operand is None:
|
||
return None
|
||
|
||
# === 一元运算符重载: -obj/+obj/~obj 调用 __neg__/__pos__/__invert__ ===
|
||
# 仅 USub/UAdd/Invert 有重载语义(not 无 dunder 方法)
|
||
if uo.op == ast.OpKind.USub or uo.op == ast.OpKind.UAdd or uo.op == ast.OpKind.Invert:
|
||
ovl_u: llvmlite.Value | t.CPtr = self.try_unary_operator_overload(
|
||
pool, builder, mod, operand, uo.op, trans)
|
||
if ovl_u is not None:
|
||
return ovl_u
|
||
|
||
if uo.op == ast.OpKind.USub:
|
||
# -x
|
||
# 浮点类型用 fneg(直接生成 fneg 指令,避免 0.0 - x 的类型不匹配)
|
||
operand_fbits: int = self.get_llvm_float_bits(operand.Ty)
|
||
if operand_fbits > 0:
|
||
return llvmlite.build_fneg(builder, operand)
|
||
# 整数类型:-x = 0 - x,根据位宽选择零值常量(避免 i32 与 i64 类型不匹配)
|
||
operand_bits: int = self.get_llvm_type_bits(operand.Ty)
|
||
zero: llvmlite.Value | t.CPtr = llvmlite.const_int32(pool, 0)
|
||
if operand_bits == 64:
|
||
zero = llvmlite.const_int64(pool, 0)
|
||
elif operand_bits > 0 and operand_bits != 32:
|
||
# 其他位宽(i8/i16 等):用 i32 零值,operand 会被 coerce
|
||
zero = llvmlite.const_int32(pool, 0)
|
||
return llvmlite.build_sub(builder, zero, operand)
|
||
elif uo.op == ast.OpKind.UAdd:
|
||
# +x = x
|
||
return operand
|
||
elif uo.op == ast.OpKind.Not:
|
||
# not x = (x == 0/null),返回 i1
|
||
if self.is_ptr_type(operand.Ty) != 0:
|
||
# 指针类型:与 null 比较
|
||
null_op: llvmlite.Value | t.CPtr = llvmlite.ConstNull(pool, operand.Ty, "null")
|
||
return llvmlite.build_icmp(builder, llvmlite.ICMP_EQ, operand, null_op)
|
||
# 结构体值类型:永远为真(非空),not 返回 false
|
||
operand_is_struct_not: int = 0
|
||
match operand.Ty:
|
||
case llvmlite.LLVMType.Struct(_, _, _):
|
||
operand_is_struct_not = 1
|
||
case _:
|
||
operand_is_struct_not = 0
|
||
if operand_is_struct_not != 0:
|
||
return llvmlite.const_int(pool, 1, 0)
|
||
operand_bits_not: int = self.get_llvm_type_bits(operand.Ty)
|
||
zero = llvmlite.const_int32(pool, 0)
|
||
if operand_bits_not == 64:
|
||
zero = llvmlite.const_int64(pool, 0)
|
||
return llvmlite.build_icmp(builder, llvmlite.ICMP_EQ, operand, zero)
|
||
elif uo.op == ast.OpKind.Invert:
|
||
# ~x = x ^ -1
|
||
operand_bits_inv: int = self.get_llvm_type_bits(operand.Ty)
|
||
neg1: llvmlite.Value | t.CPtr = llvmlite.const_int32(pool, -1)
|
||
if operand_bits_inv == 64:
|
||
neg1 = llvmlite.const_int64(pool, -1)
|
||
return llvmlite.build_xor(builder, operand, neg1)
|
||
return operand
|
||
# ============================================================
|
||
# 翻译布尔运算 BoolOp(op, values) — 短路求值,返回 i1
|
||
#
|
||
# and: a and b and c → 若 a 为假短路到 merge(返回 a 的 i1),否则求 b,
|
||
# 最后一个值直接求值并跳 merge
|
||
# or: a or b or c → 若 a 为真短路到 merge(返回 a 的 i1),否则求 b,
|
||
# 最后一个值直接求值并跳 merge
|
||
# merge 块用 phi 合并所有入边的 i1
|
||
# ============================================================
|
||
def translate_boolop(self, builder: llvmlite.IRBuilder | t.CPtr,
|
||
pool: memhub.MemBuddy | t.CPtr,
|
||
mod: llvmlite.LLVMModule | t.CPtr,
|
||
node: ast.AST | t.CPtr,
|
||
funcs_ptr: t.CPtr = None,
|
||
func_count: int = 0,
|
||
trans: HT.Translator | t.CPtr = None) -> llvmlite.Value | t.CPtr:
|
||
"""翻译布尔运算(and/or)的短路求值,返回 i1"""
|
||
bo: ast.BoolOp | t.CPtr = (ast.BoolOp | t.CPtr)(node)
|
||
if bo is None:
|
||
return None
|
||
|
||
op: int = bo.op
|
||
values: list[ast.AST | t.CPtr] | t.CPtr = bo.values
|
||
if values is None:
|
||
return None
|
||
count: t.CSizeT = len(values)
|
||
if count == 0:
|
||
return None
|
||
if count == 1:
|
||
return HandlesExpr.translate_value(builder, pool, mod, values.get(0),
|
||
funcs_ptr, func_count, trans)
|
||
|
||
func: llvmlite.Function | t.CPtr = builder.Func
|
||
if func is None:
|
||
return None
|
||
|
||
# 创建 merge BB(用 builder.Counter 生成唯一标签名,position_at_end 的
|
||
# move_to_end 保证 BB 文本顺序与控制流顺序一致,标签名用 counter 安全)
|
||
cnt: int = builder.Counter
|
||
builder.Counter = cnt + 1
|
||
name_buf: str = pool.alloc(32)
|
||
if name_buf is None:
|
||
return None
|
||
viperlib.snprintf(name_buf, 32, "bool.merge.%d", cnt)
|
||
merge_bb: llvmlite.BasicBlock | t.CPtr = llvmlite.create_block(pool, func, name_buf)
|
||
|
||
# phi 入边链表头/尾
|
||
phi_head: llvmlite.PhiIncoming | t.CPtr = None
|
||
phi_tail: llvmlite.PhiIncoming | t.CPtr = None
|
||
phi_count: int = count - 1 # 循环次数
|
||
|
||
# 对每个值(除最后一个)求值并短路
|
||
for i in range(count - 1):
|
||
val_node: ast.AST | t.CPtr = values.get(i)
|
||
val: llvmlite.Value | t.CPtr = HandlesExpr.translate_value(
|
||
builder, pool, mod, val_node,
|
||
funcs_ptr, func_count, trans)
|
||
if val is None:
|
||
return None
|
||
|
||
# 转为 i1(已经是 i1 的直接用,否则与 0/null 比较)
|
||
val_bits: int = self.get_llvm_type_bits(val.Ty)
|
||
val_i1: llvmlite.Value | t.CPtr = val
|
||
if val_bits != 1:
|
||
if self.is_ptr_type(val.Ty) != 0:
|
||
# 指针类型:与 null 比较(避免 i8* 与 i32 类型不匹配)
|
||
null_val: llvmlite.Value | t.CPtr = llvmlite.ConstNull(pool, val.Ty, "null")
|
||
val_i1 = llvmlite.build_icmp(builder, llvmlite.ICMP_NE, val, null_val)
|
||
else:
|
||
zero: llvmlite.Value | t.CPtr = llvmlite.const_int32(pool, 0)
|
||
val_i1 = llvmlite.build_icmp(builder, llvmlite.ICMP_NE, val, zero)
|
||
|
||
# 创建 next BB(求值下一个值)
|
||
cnt = builder.Counter
|
||
builder.Counter = cnt + 1
|
||
viperlib.snprintf(name_buf, 32, "bool.next.%d", cnt)
|
||
next_bb: llvmlite.BasicBlock | t.CPtr = llvmlite.create_block(pool, func, name_buf)
|
||
|
||
# and: 短路假→merge,真→next;or: 短路真→merge,假→next
|
||
if op == ast.OpKind.And:
|
||
llvmlite.build_cond_br(builder, val_i1, next_bb, merge_bb)
|
||
else:
|
||
llvmlite.build_cond_br(builder, val_i1, merge_bb, next_bb)
|
||
|
||
# 添加 phi 入边:(val_i1, cond_br 所在 BB)
|
||
cur_bb: llvmlite.BasicBlock | t.CPtr = builder.CurBlock
|
||
inc: llvmlite.PhiIncoming | t.CPtr = llvmlite.new_phi_incoming(pool, val_i1, cur_bb)
|
||
if phi_head is None:
|
||
phi_head = inc
|
||
phi_tail = inc
|
||
else:
|
||
phi_tail.Next = inc
|
||
phi_tail = inc
|
||
|
||
# 定位到 next BB,求值下一个值
|
||
llvmlite.position_at_end(builder, next_bb)
|
||
|
||
# 最后一个值:求值后直接跳 merge
|
||
last_node: ast.AST | t.CPtr = values.get(count - 1)
|
||
last_val: llvmlite.Value | t.CPtr = HandlesExpr.translate_value(
|
||
builder, pool, mod, last_node,
|
||
funcs_ptr, func_count, trans)
|
||
if last_val is None:
|
||
return None
|
||
last_bits: int = self.get_llvm_type_bits(last_val.Ty)
|
||
last_i1: llvmlite.Value | t.CPtr = last_val
|
||
if last_bits != 1:
|
||
if self.is_ptr_type(last_val.Ty) != 0:
|
||
# 指针类型:与 null 比较(避免 i8* 与 i32 类型不匹配)
|
||
null_val2: llvmlite.Value | t.CPtr = llvmlite.ConstNull(pool, last_val.Ty, "null")
|
||
last_i1 = llvmlite.build_icmp(builder, llvmlite.ICMP_NE, last_val, null_val2)
|
||
else:
|
||
zero = llvmlite.const_int32(pool, 0)
|
||
last_i1 = llvmlite.build_icmp(builder, llvmlite.ICMP_NE, last_val, zero)
|
||
|
||
llvmlite.build_br(builder, merge_bb)
|
||
|
||
cur_bb = builder.CurBlock
|
||
inc = llvmlite.new_phi_incoming(pool, last_i1, cur_bb)
|
||
if phi_head is None:
|
||
phi_head = inc
|
||
else:
|
||
phi_tail.Next = inc
|
||
phi_count += 1
|
||
|
||
# 定位到 merge,创建 phi 合并所有入边
|
||
llvmlite.position_at_end(builder, merge_bb)
|
||
i1_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int1(pool)
|
||
return llvmlite.build_phi(builder, i1_ty, phi_head, phi_count)
|
||
# ============================================================
|
||
# BinOp 运算符 → dunder 方法名
|
||
# ============================================================
|
||
def _binop_to_dunder(self, op: int) -> str:
|
||
"""将 BinOp 运算符映射到 dunder 方法名,无映射时返回 None
|
||
|
||
Python 3 语义:/ 映射 __truediv__(Python 2 的 __div__ 已废弃)。
|
||
"""
|
||
if op == ast.OpKind.Add: return "__add__"
|
||
if op == ast.OpKind.Sub: return "__sub__"
|
||
if op == ast.OpKind.Mult: return "__mul__"
|
||
if op == ast.OpKind.Div: return "__truediv__"
|
||
if op == ast.OpKind.Mod: return "__mod__"
|
||
if op == ast.OpKind.BitAnd: return "__and__"
|
||
if op == ast.OpKind.BitOr: return "__or__"
|
||
if op == ast.OpKind.BitXor: return "__xor__"
|
||
if op == ast.OpKind.LShift: return "__lshift__"
|
||
if op == ast.OpKind.RShift: return "__rshift__"
|
||
if op == ast.OpKind.FloorDiv: return "__floordiv__"
|
||
return None
|
||
# ============================================================
|
||
# Compare 运算符 → dunder 方法名
|
||
# ============================================================
|
||
def _cmpop_to_dunder(self, op: int) -> str:
|
||
"""将 Compare 运算符映射到 dunder 方法名,无映射时返回 None"""
|
||
if op == ast.OpKind.Eq: return "__eq__"
|
||
if op == ast.OpKind.Ne: return "__ne__"
|
||
if op == ast.OpKind.Lt: return "__lt__"
|
||
if op == ast.OpKind.Le: return "__le__"
|
||
if op == ast.OpKind.Gt: return "__gt__"
|
||
if op == ast.OpKind.Ge: return "__ge__"
|
||
return None
|
||
# ============================================================
|
||
# UnaryOp 运算符 → dunder 方法名
|
||
# ============================================================
|
||
def _unaryop_to_dunder(self, op: int) -> str:
|
||
"""将 UnaryOp 运算符映射到 dunder 方法名,无映射时返回 None"""
|
||
if op == ast.OpKind.USub: return "__neg__"
|
||
if op == ast.OpKind.UAdd: return "__pos__"
|
||
if op == ast.OpKind.Invert: return "__invert__"
|
||
return None
|
||
# ============================================================
|
||
# try_operator_overload - 尝试运算符重载
|
||
#
|
||
# 检查 lhs 是否为结构体指针,并在该类(含继承链)中查找对应的
|
||
# dunder 方法。找到则生成方法调用 lhs.__dunder__(rhs),返回
|
||
# 调用结果;未找到返回 None,调用方回退到原生运算。
|
||
# ============================================================
|
||
def try_operator_overload(self, pool: memhub.MemBuddy | t.CPtr,
|
||
builder: llvmlite.IRBuilder | t.CPtr,
|
||
mod: llvmlite.LLVMModule | t.CPtr,
|
||
lhs: llvmlite.Value | t.CPtr,
|
||
rhs: llvmlite.Value | t.CPtr,
|
||
op: int,
|
||
trans: HT.Translator | t.CPtr,
|
||
is_compare: int) -> llvmlite.Value | t.CPtr:
|
||
"""尝试运算符重载:lhs 是结构体指针时调用 dunder 方法,否则返回 None"""
|
||
if lhs is None or rhs is None:
|
||
return None
|
||
|
||
# 延迟导入避免循环依赖
|
||
import lib.core.Handles.HandlesStruct as HandlesStruct
|
||
import lib.core.Handles.HandlesExprCall as HandlesExprCall
|
||
|
||
# 映射运算符到 dunder 方法名
|
||
dunder: str = None
|
||
if is_compare != 0:
|
||
dunder = self._cmpop_to_dunder(op)
|
||
else:
|
||
dunder = self._binop_to_dunder(op)
|
||
if dunder is None:
|
||
return None
|
||
|
||
# 检查 lhs 是否为结构体指针
|
||
struct_ty: llvmlite.LLVMType | t.CPtr = HandlesStruct.get_struct_type_from_value(lhs)
|
||
if struct_ty is None:
|
||
return None
|
||
|
||
# 获取类名
|
||
class_name: str = HandlesStruct.get_class_name_by_type(pool, struct_ty)
|
||
if class_name is None:
|
||
return None
|
||
|
||
# 在继承链中查找 dunder 方法
|
||
lookup_name: str = pool.alloc(128)
|
||
if lookup_name is None:
|
||
return None
|
||
viperlib.snprintf(lookup_name, 128, "%s.%s", class_name, dunder)
|
||
found_func: llvmlite.Function | t.CPtr = ExprCallBase.find_func_in_module(mod, lookup_name)
|
||
|
||
search_class: str = class_name
|
||
if found_func is None:
|
||
# 多继承:沿 MRO 祖先链查找(先声明父类优先)
|
||
mro_ptr: t.CSizeT | t.CPtr = HandlesStruct.get_mro_chain(pool, class_name)
|
||
mi: int = 1
|
||
while mro_ptr is not None and mro_ptr[mi] != 0:
|
||
anc: str = (str | t.CPtr)(t.CVoid(mro_ptr[mi], t.CPtr))
|
||
if anc is not None:
|
||
parent_lookup: str = pool.alloc(128)
|
||
if parent_lookup is not None:
|
||
viperlib.snprintf(parent_lookup, 128, "%s.%s", anc, dunder)
|
||
parent_func: llvmlite.Function | t.CPtr = ExprCallBase.find_func_in_module(mod, parent_lookup)
|
||
if parent_func is not None:
|
||
found_func = parent_func
|
||
search_class = anc
|
||
break
|
||
mi += 1
|
||
|
||
# 方法不在当前模块中时,检查类(含父类)是否有 SHA1(stub 可能未注入)
|
||
# 优先用类型指针定位 entry 获取 SHA1(规避跨模块同名 find_struct 找错)
|
||
cls_sha1: str = None
|
||
op_entry: HandlesStruct.StructEntry | t.CPtr = HandlesStruct.find_struct_by_type(struct_ty)
|
||
if op_entry is not None:
|
||
cls_sha1 = op_entry.ModuleSha1
|
||
if cls_sha1 is None:
|
||
cls_sha1 = HandlesStruct.get_struct_sha1(search_class)
|
||
if cls_sha1 is None:
|
||
mro_p: t.CSizeT | t.CPtr = HandlesStruct.get_mro_chain(pool, search_class)
|
||
mj: int = 1
|
||
while mro_p is not None and mro_p[mj] != 0 and cls_sha1 is None:
|
||
anc_p: str = (str | t.CPtr)(t.CVoid(mro_p[mj], t.CPtr))
|
||
if anc_p is not None:
|
||
cls_sha1 = HandlesStruct.get_struct_sha1(anc_p)
|
||
mj += 1
|
||
|
||
# 既无函数定义也无 SHA1 → 该类没有此 dunder 方法,返回 None 回退原生运算
|
||
if found_func is None and cls_sha1 is None:
|
||
return None
|
||
|
||
# 方法在"定义它的模块"中确实不存在(同模块类但模块内无此 dunder):
|
||
# 返回 None 回退原生运算,绝不发出幽灵 call——否则 IR 残留
|
||
# `call void @...__div__`(副作用)且调用方回退原生 sdiv 双重发射,
|
||
# llc 报 invalid operand type for instruction(CPythonTest PyFloatObj 根因)
|
||
if found_func is None and trans is not None and trans.ModuleSha1 is not None:
|
||
if cls_sha1 is not None and string.strcmp(cls_sha1, trans.ModuleSha1) == 0:
|
||
return None
|
||
# 跨模块类:stub 可能未注入,方法存在性以依赖模块 vpi stub 为准。
|
||
# vpi 未命中(依赖模块确实无此 dunder)→ 回退原生比较(icmp),
|
||
# 绝不发幽灵 call——`call @{cls_sha1}.{Class}.{dunder}` 链接 undefined
|
||
# (MemBuddy 无 __eq__ 时 os._mbuddy == sys._mbuddy,SysLibTest 根因)。
|
||
vpi_dup: llvmlite.LLVMType | t.CPtr = ExprCallCtor._lookup_method_ret_ty_via_vpi(
|
||
pool, cls_sha1, search_class, dunder)
|
||
if vpi_dup is None:
|
||
return None
|
||
|
||
# 构建 extra_args 数组(仅含 rhs 一个参数)
|
||
extra_args: t.CSizeT | t.CPtr = pool.alloc(8)
|
||
if extra_args is None:
|
||
return None
|
||
extra_args[0] = t.CSizeT(rhs)
|
||
|
||
# 调用方法: lhs.__dunder__(rhs)
|
||
return ExprCallCtor._call_method_on_ptr(
|
||
pool, builder, mod, search_class, dunder,
|
||
lhs, extra_args, 1, trans)
|
||
# ============================================================
|
||
# try_unary_operator_overload - 尝试一元运算符重载
|
||
#
|
||
# 检查 operand 是否为结构体指针,并在该类(含继承链)中查找对应的
|
||
# dunder 方法(__neg__/__pos__/__invert__)。找到则生成方法调用
|
||
# operand.__dunder__(),返回调用结果;未找到返回 None,调用方回退到原生运算。
|
||
# ============================================================
|
||
def try_unary_operator_overload(self, pool: memhub.MemBuddy | t.CPtr,
|
||
builder: llvmlite.IRBuilder | t.CPtr,
|
||
mod: llvmlite.LLVMModule | t.CPtr,
|
||
operand: llvmlite.Value | t.CPtr,
|
||
op: int,
|
||
trans: HT.Translator | t.CPtr) -> llvmlite.Value | t.CPtr:
|
||
"""尝试一元运算符重载:operand 是结构体指针时调用 dunder 方法,否则返回 None"""
|
||
if operand is None:
|
||
return None
|
||
|
||
# 延迟导入避免循环依赖
|
||
import lib.core.Handles.HandlesStruct as HandlesStruct
|
||
import lib.core.Handles.HandlesExprCall as HandlesExprCall
|
||
|
||
dunder: str = self._unaryop_to_dunder(op)
|
||
if dunder is None:
|
||
return None
|
||
|
||
# 检查 operand 是否为结构体指针
|
||
struct_ty: llvmlite.LLVMType | t.CPtr = HandlesStruct.get_struct_type_from_value(operand)
|
||
if struct_ty is None:
|
||
return None
|
||
|
||
# 获取类名
|
||
class_name: str = HandlesStruct.get_class_name_by_type(pool, struct_ty)
|
||
if class_name is None:
|
||
return None
|
||
|
||
# 在继承链中查找 dunder 方法
|
||
lookup_name: str = pool.alloc(128)
|
||
if lookup_name is None:
|
||
return None
|
||
viperlib.snprintf(lookup_name, 128, "%s.%s", class_name, dunder)
|
||
found_func: llvmlite.Function | t.CPtr = ExprCallBase.find_func_in_module(mod, lookup_name)
|
||
|
||
search_class: str = class_name
|
||
if found_func is None:
|
||
# 多继承:沿 MRO 祖先链查找(先声明父类优先)
|
||
mro_ptr: t.CSizeT | t.CPtr = HandlesStruct.get_mro_chain(pool, class_name)
|
||
mi: int = 1
|
||
while mro_ptr is not None and mro_ptr[mi] != 0:
|
||
anc: str = (str | t.CPtr)(t.CVoid(mro_ptr[mi], t.CPtr))
|
||
if anc is not None:
|
||
parent_lookup: str = pool.alloc(128)
|
||
if parent_lookup is not None:
|
||
viperlib.snprintf(parent_lookup, 128, "%s.%s", anc, dunder)
|
||
parent_func: llvmlite.Function | t.CPtr = ExprCallBase.find_func_in_module(mod, parent_lookup)
|
||
if parent_func is not None:
|
||
found_func = parent_func
|
||
search_class = anc
|
||
break
|
||
mi += 1
|
||
|
||
# 方法不在当前模块中时,检查类(含父类)是否有 SHA1(stub 可能未注入)
|
||
cls_sha1: str = None
|
||
uop_entry: HandlesStruct.StructEntry | t.CPtr = HandlesStruct.find_struct_by_type(struct_ty)
|
||
if uop_entry is not None:
|
||
cls_sha1 = uop_entry.ModuleSha1
|
||
if cls_sha1 is None:
|
||
cls_sha1 = HandlesStruct.get_struct_sha1(search_class)
|
||
if cls_sha1 is None:
|
||
mro_p: t.CSizeT | t.CPtr = HandlesStruct.get_mro_chain(pool, search_class)
|
||
mj: int = 1
|
||
while mro_p is not None and mro_p[mj] != 0 and cls_sha1 is None:
|
||
anc_p: str = (str | t.CPtr)(t.CVoid(mro_p[mj], t.CPtr))
|
||
if anc_p is not None:
|
||
cls_sha1 = HandlesStruct.get_struct_sha1(anc_p)
|
||
mj += 1
|
||
|
||
# 既无函数定义也无 SHA1 → 该类没有此 dunder 方法,返回 None 回退原生运算
|
||
if found_func is None and cls_sha1 is None:
|
||
return None
|
||
|
||
# 同模块类但模块内无此 dunder → 返回 None 回退原生运算,不发幽灵 call
|
||
# (与 try_operator_overload 一致,防 IR 残留 call void @...__neg__)
|
||
if found_func is None and trans is not None and trans.ModuleSha1 is not None:
|
||
if cls_sha1 is not None and string.strcmp(cls_sha1, trans.ModuleSha1) == 0:
|
||
return None
|
||
|
||
# 一元方法无额外参数(extra_args 为空)
|
||
return ExprCallCtor._call_method_on_ptr(
|
||
pool, builder, mod, search_class, dunder,
|
||
operand, None, 0, trans)
|
||
# ============================================================
|
||
# 翻译二元运算(自动类型提升)
|
||
# ============================================================
|
||
def translate_binop(self, pool: memhub.MemBuddy | t.CPtr,
|
||
builder: llvmlite.IRBuilder | t.CPtr,
|
||
mod: llvmlite.LLVMModule | t.CPtr,
|
||
node: ast.AST | t.CPtr,
|
||
trans: HT.Translator | t.CPtr = None) -> llvmlite.Value | t.CPtr:
|
||
"""翻译二元运算(自动类型提升)"""
|
||
binop: ast.BinOp | t.CPtr = (ast.BinOp | t.CPtr)(node)
|
||
if binop is None:
|
||
return None
|
||
|
||
lhs_node: ast.AST | t.CPtr = binop.left
|
||
rhs_node: ast.AST | t.CPtr = binop.right
|
||
op: int = binop.op
|
||
|
||
# 先翻译 rhs(只翻译一次,避免副作用重复)
|
||
rhs: llvmlite.Value | t.CPtr = HandlesExpr.translate_value(
|
||
builder, pool, mod, rhs_node, None, 0, trans)
|
||
if rhs is None:
|
||
return None
|
||
|
||
# === 运算符重载路径 1: lhs 是 Name 且对应结构体变量 ===
|
||
# 对于值类型变量(如 cnt: Counter),translate_value 会 load 返回 Struct 值,
|
||
# 但 dunder 方法需要 Ptr(Struct) 作为 self。直接用 alloca 指针尝试重载。
|
||
if lhs_node is not None and lhs_node.kind() == ast.ASTKind.Name and trans is not None:
|
||
nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(lhs_node)
|
||
if nm is not None and nm.id is not None:
|
||
lhs_alloca: llvmlite.Value | t.CPtr = HandlesVar.lookup_var(
|
||
trans.SymTab, nm.id)
|
||
if lhs_alloca is not None:
|
||
ovl_self1: llvmlite.Value | t.CPtr = lhs_alloca
|
||
# alloca 是 Ptr(Ptr(Struct))(X|t.CPtr 对象存储槽)时,
|
||
# load 出对象指针作为 self——若把槽地址当 self,dunder 内
|
||
# load 槽内容(对象指针值)当字段读 → 垃圾(MultiInheritTest
|
||
# Vec2Both __add__ 输出 (1.0,2.0) 根因;get_struct_type_from_value
|
||
# 递归解指针后路径 1 能识别 alloca,需同步修正 self 语义)
|
||
if lhs_alloca.Ty is not None and lhs_alloca.Ty.Pointee is not None \
|
||
and HandlesExpr.is_ptr_type(lhs_alloca.Ty.Pointee) != 0:
|
||
load_self1: llvmlite.Value | t.CPtr = llvmlite.build_load(
|
||
builder, lhs_alloca.Ty.Pointee, lhs_alloca)
|
||
if load_self1 is not None:
|
||
ovl_self1 = load_self1
|
||
ovl_result: llvmlite.Value | t.CPtr = self.try_operator_overload(
|
||
pool, builder, mod, ovl_self1, rhs, op, trans, 0)
|
||
if ovl_result is not None:
|
||
return ovl_result
|
||
|
||
# 正常翻译 lhs
|
||
lhs: llvmlite.Value | t.CPtr = HandlesExpr.translate_value(
|
||
builder, pool, mod, lhs_node, None, 0, trans)
|
||
if lhs is None:
|
||
return None
|
||
|
||
# === 运算符重载路径 2: lhs 是 Ptr(Struct)(如 Counter|t.CPtr 变量 load 后)===
|
||
ovl_result2: llvmlite.Value | t.CPtr = self.try_operator_overload(
|
||
pool, builder, mod, lhs, rhs, op, trans, 0)
|
||
if ovl_result2 is not None:
|
||
return ovl_result2
|
||
|
||
# 获取操作数类型信息
|
||
lhs_bits: int = self.get_llvm_type_bits(lhs.Ty)
|
||
rhs_bits: int = self.get_llvm_type_bits(rhs.Ty)
|
||
lhs_fbits: int = self.get_llvm_float_bits(lhs.Ty)
|
||
rhs_fbits: int = self.get_llvm_float_bits(rhs.Ty)
|
||
|
||
# 浮点运算: 任一操作数为浮点时,使用浮点指令(必须在指针算术之前检查,
|
||
# 因为 float 的 int bits 为 0,会被误认为指针)
|
||
if lhs_fbits != 0 or rhs_fbits != 0:
|
||
# 确定目标浮点类型(使用较大的位宽)
|
||
target_fbits: int = lhs_fbits
|
||
if rhs_fbits > target_fbits:
|
||
target_fbits = rhs_fbits
|
||
target_float_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Double(pool)
|
||
if target_fbits == 32:
|
||
target_float_ty = llvmlite.Float(pool)
|
||
# 将两个操作数转换为目标浮点类型(int→float via si2fp, float→float via fpext/fptrunc)
|
||
lhs = self.coerce_to_type(builder, lhs, target_float_ty, node)
|
||
rhs = self.coerce_to_type(builder, rhs, target_float_ty, node)
|
||
if op == ast.OpKind.Add:
|
||
return llvmlite.build_fadd(builder, lhs, rhs)
|
||
if op == ast.OpKind.Sub:
|
||
return llvmlite.build_fsub(builder, lhs, rhs)
|
||
if op == ast.OpKind.Mult:
|
||
return llvmlite.build_fmul(builder, lhs, rhs)
|
||
if op == ast.OpKind.Div:
|
||
return llvmlite.build_fdiv(builder, lhs, rhs)
|
||
if op == ast.OpKind.Mod:
|
||
return llvmlite.build_frem(builder, lhs, rhs)
|
||
return None
|
||
|
||
# 指针算术: ptr + int / ptr - int / int + ptr → getelementptr(按元素大小缩放)
|
||
# 对齐 TPC ExprGen.emit_binary_op L50-67;int - ptr 无 GEP 形式(C 语义非法)
|
||
if (lhs_bits == 0 and rhs_bits != 0) or (lhs_bits != 0 and rhs_bits == 0):
|
||
if op == ast.OpKind.Add:
|
||
if lhs_bits == 0:
|
||
return self.translate_ptr_arith(pool, builder, lhs, rhs, op)
|
||
# int + ptr(交换)
|
||
return self.translate_ptr_arith(pool, builder, rhs, lhs, op)
|
||
if op == ast.OpKind.Sub and lhs_bits == 0:
|
||
return self.translate_ptr_arith(pool, builder, lhs, rhs, op)
|
||
|
||
if lhs_bits > rhs_bits:
|
||
if self.should_zext_widen(pool, rhs, lhs, rhs_node) != 0:
|
||
rhs = llvmlite.build_zext(builder, rhs, lhs.Ty)
|
||
else:
|
||
rhs = self.coerce_to_type(builder, rhs, lhs.Ty, node)
|
||
elif rhs_bits > lhs_bits:
|
||
if self.should_zext_widen(pool, lhs, rhs, lhs_node) != 0:
|
||
lhs = llvmlite.build_zext(builder, lhs, rhs.Ty)
|
||
else:
|
||
lhs = self.coerce_to_type(builder, lhs, rhs.Ty, node)
|
||
|
||
# 位运算类型安全检查:两边都是指针(lhs_bits==0 and rhs_bits==0)时,
|
||
# 位运算(BitOr/BitAnd/BitXor/LShift/RShift)非法,LLVM 要求整数操作数。
|
||
# 常见触发场景:CDefine 常量查找失败返回指针 null,与另一指针做 `|`。
|
||
if lhs_bits == 0 and rhs_bits == 0:
|
||
if op == ast.OpKind.BitOr or op == ast.OpKind.BitAnd or op == ast.OpKind.BitXor or op == ast.OpKind.LShift or op == ast.OpKind.RShift:
|
||
# fail-fast:位运算操作数类型非法,立即终止编译(暴露上游根因)
|
||
HandlesType.fatal_error(
|
||
node,
|
||
"位运算操作数类型非法: lhs/rhs 均为非整数类型(指针或结构体),无法执行位运算",
|
||
"TypeError")
|
||
|
||
if op == ast.OpKind.Add:
|
||
return llvmlite.build_add(builder, lhs, rhs)
|
||
elif op == ast.OpKind.Sub:
|
||
return llvmlite.build_sub(builder, lhs, rhs)
|
||
elif op == ast.OpKind.Mult:
|
||
return llvmlite.build_mul(builder, lhs, rhs)
|
||
elif op == ast.OpKind.Div:
|
||
return llvmlite.build_sdiv(builder, lhs, rhs)
|
||
elif op == ast.OpKind.FloorDiv:
|
||
return llvmlite.build_sdiv(builder, lhs, rhs)
|
||
elif op == ast.OpKind.Mod:
|
||
return llvmlite.build_srem(builder, lhs, rhs)
|
||
elif op == ast.OpKind.BitAnd:
|
||
return llvmlite.build_and(builder, lhs, rhs)
|
||
elif op == ast.OpKind.BitOr:
|
||
return llvmlite.build_or(builder, lhs, rhs)
|
||
elif op == ast.OpKind.BitXor:
|
||
return llvmlite.build_xor(builder, lhs, rhs)
|
||
elif op == ast.OpKind.LShift:
|
||
return llvmlite.build_shl(builder, lhs, rhs)
|
||
elif op == ast.OpKind.RShift:
|
||
# 无符号 >> → lshr(逻辑右移),有符号 >> → ashr(算术右移)
|
||
# 对齐 TPC ExprGen.emit_binary_op:i8/i16 默认无符号;其余查操作数无符号性
|
||
if lhs_bits == 8 or lhs_bits == 16:
|
||
return llvmlite.build_lshr(builder, lhs, rhs)
|
||
if self._node_type_unsigned(pool, lhs_node, trans) != 0:
|
||
return llvmlite.build_lshr(builder, lhs, rhs)
|
||
return llvmlite.build_ashr(builder, lhs, rhs)
|
||
return None |