5 个新 Mixin(92 方法)承接 HandlesBody/If/While/For/Return/Nonlocal/Match/Enum/AnnAssign/AugAssign/Var/Imports/Translator/Main 的无状态函数与 _g_ 全局;15 个 Handles 模块改为一行委托(调用方零改动);Generator 组合扩展至 12 Mixin,__init__ 初始化 8 个新字段;BuildPipeline/main 注入 14 个模块 set_global_gen;修复 ImportsGenMixin 与 TypeGenMixin 的 CurrentFile 重复字段冲突(改 HandlesType 委托,延迟 import 规避循环依赖)。
519 lines
24 KiB
Plaintext
519 lines
24 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.VLogger as VLogger
|
||
import lib.core.Handles.HandlesTranslator as HT
|
||
import lib.core.Handles.HandlesType as HandlesType
|
||
import lib.core.Handles.HandlesExpr as HandlesExpr
|
||
|
||
|
||
# ============================================================
|
||
# AssignGenMixin - 赋值翻译 Mixin(P6 方法化)
|
||
#
|
||
# 从 HandlesAssign/HandlesAnnAssign/HandlesAugAssign 迁移:
|
||
# 模块级无状态函数(trans/pool 首参)→ 类方法;全局状态
|
||
# (HandlesAnnAssign._g_recover_found)→ 本类字段 RecoverFound。
|
||
#
|
||
# 迁移原则(与 P1-P5 一致,行为零变化):
|
||
# 1. 方法保留原函数签名(含 trans/pool 首参),仅函数体内的
|
||
# 本模块函数调用改为 self.xxx(...)
|
||
# 2. 外部模块调用(HandlesType.xxx/HandlesExpr.xxx 等)保留模块前缀
|
||
# 3. 原 Handles 模块函数保留为"委托":本地模块级单例 _g_gen
|
||
# (BuildPipeline/main 注入)cast 成 Generator 类型
|
||
#
|
||
# @t.NoVTable:静态绑定(方法沿 MRO 直接调用 + this 调整)。
|
||
# ============================================================
|
||
|
||
|
||
@t.NoVTable
|
||
class AssignGenMixin:
|
||
"""赋值翻译 Mixin(P6 方法化)"""
|
||
|
||
# --- 原 HandlesAnnAssign._g_recover_found 模块级全局(迁移为实例字段) ---
|
||
RecoverFound: int
|
||
|
||
# ============================================================
|
||
# is_cdefine_annotation - 检测注解是否为 t.CDefine(模块级函数)
|
||
#
|
||
# 支持两种形式:
|
||
# 1. Attribute(Name('t'), 'CDefine')
|
||
# 2. BinOp(... | Attribute(Name('t'), 'CDefine'))(联合注解)
|
||
# ============================================================
|
||
def is_cdefine_annotation(self, annot: ast.AST | t.CPtr) -> int:
|
||
"""检测注解是否为 t.CDefine,返回 1 表示是,0 表示否"""
|
||
if annot is None:
|
||
return 0
|
||
k: int = annot.kind()
|
||
if k == ast.ASTKind.Attribute:
|
||
at: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(annot)
|
||
if at.attr is not None and string.strcmp(at.attr, "CDefine") == 0:
|
||
return 1
|
||
return 0
|
||
if k == ast.ASTKind.BinOp:
|
||
bop: ast.BinOp | t.CPtr = (ast.BinOp | t.CPtr)(annot)
|
||
if self.is_cdefine_annotation(bop.left) != 0:
|
||
return 1
|
||
if self.is_cdefine_annotation(bop.right) != 0:
|
||
return 1
|
||
return 0
|
||
|
||
# ============================================================
|
||
# extract_cdefine_int_value - 从 AnnAssign.value 提取整数常量(模块级函数)
|
||
#
|
||
# 支持的表达式形式:
|
||
# 1. Constant(INT) — 如 0x0002, 42
|
||
# 2. BinOp(BitOr/BitAnd) — 如 FOREGROUND_RED | FOREGROUND_GREEN
|
||
# 3. Name — 引用已注册的 CDefine 常量
|
||
# 4. Call — 如 t.CUnsignedLong(-11) → 取第一个参数
|
||
# 5. UnaryOp(USub/UAdd/Invert) — 如 -11
|
||
# ============================================================
|
||
def extract_cdefine_int_value(self, val_node: ast.AST | t.CPtr) -> int:
|
||
"""从值节点提取整数常量(支持 Constant/BinOp/Name/Call/UnaryOp)"""
|
||
if val_node is None:
|
||
return 0
|
||
k: int = val_node.kind()
|
||
|
||
# Case 1: Constant(INT) — 如 0x0002
|
||
if k == ast.ASTKind.Constant:
|
||
cn: ast.Constant | t.CPtr = (ast.Constant | t.CPtr)(val_node)
|
||
if cn.const_kind != ast.CONST_INT:
|
||
return 0
|
||
return cn.int_val
|
||
|
||
# Case 2: BinOp — 如 FOREGROUND_RED | FOREGROUND_GREEN
|
||
if k == ast.ASTKind.BinOp:
|
||
bop: ast.BinOp | t.CPtr = (ast.BinOp | t.CPtr)(val_node)
|
||
left_val: int = self.extract_cdefine_int_value(bop.left)
|
||
right_val: int = self.extract_cdefine_int_value(bop.right)
|
||
if bop.op == ast.OpKind.BitOr:
|
||
return left_val | right_val
|
||
if bop.op == ast.OpKind.BitAnd:
|
||
return left_val & right_val
|
||
if bop.op == ast.OpKind.Add:
|
||
return left_val + right_val
|
||
if bop.op == ast.OpKind.Sub:
|
||
return left_val - right_val
|
||
return 0
|
||
|
||
# Case 3: Name — 引用已注册的 CDefine 常量
|
||
if k == ast.ASTKind.Name:
|
||
nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(val_node)
|
||
if nm.id is not None:
|
||
looked_up: int = HandlesType.lookup_cdefine_constant(nm.id)
|
||
if HandlesType.is_cdefine_found() != 0:
|
||
return looked_up
|
||
return 0
|
||
|
||
# Case 4: Call — 如 t.CUnsignedLong(-11)
|
||
if k == ast.ASTKind.Call:
|
||
cl: ast.Call | t.CPtr = (ast.Call | t.CPtr)(val_node)
|
||
# 必须先把属性赋给显式类型为 list[...] | t.CPtr 的局部变量再调用 __len__(),
|
||
# 否则编译器无法识别属性返回的 list 类型,GEP base 会变成 i32 0 导致 llc 报错
|
||
cl_args_list: list[ast.AST | t.CPtr] | t.CPtr = cl.args
|
||
if cl_args_list is not None and cl_args_list.__len__() > 0:
|
||
first_arg: ast.AST | t.CPtr = cl_args_list.get(0)
|
||
arg_val: int = self.extract_cdefine_int_value(first_arg)
|
||
return arg_val
|
||
return 0
|
||
|
||
# Case 5: UnaryOp — 如 -11
|
||
if k == ast.ASTKind.UnaryOp:
|
||
uop: ast.UnaryOp | t.CPtr = (ast.UnaryOp | t.CPtr)(val_node)
|
||
operand_val: int = self.extract_cdefine_int_value(uop.operand)
|
||
if uop.op == ast.OpKind.USub:
|
||
return -operand_val
|
||
if uop.op == ast.OpKind.UAdd:
|
||
return operand_val
|
||
if uop.op == ast.OpKind.Invert:
|
||
return ~operand_val
|
||
return 0
|
||
|
||
return 0
|
||
|
||
# ============================================================
|
||
# _register_cdefine_from_value - 注册 CDefine 常量(浮点/整数自动识别)
|
||
#
|
||
# 浮点字面量(如 vipermath 的 U_M_PI: t.CDefine = 3.14159...)走
|
||
# register_cdefine_double,否则 translate_value 查表得 0 生成
|
||
# ret i32 0(llc 报错 "value doesn't match function result type")。
|
||
# ============================================================
|
||
def _register_cdefine_from_value(self, pool: memhub.MemBuddy | t.CPtr,
|
||
name: str, val_node: ast.AST | t.CPtr) -> None:
|
||
"""注册 CDefine 常量(浮点字面量 → register_cdefine_double,否则整数)"""
|
||
if pool is None or name is None:
|
||
return
|
||
if val_node is not None and val_node.kind() == ast.ASTKind.Constant:
|
||
cn_fp: ast.Constant | t.CPtr = (ast.Constant | t.CPtr)(val_node)
|
||
if cn_fp.const_kind == ast.CONST_FLOAT:
|
||
# 源文件重读恢复(最可靠:AST 节点 float_val 可能被 pool 操作覆写,
|
||
# 源文件文本不受影响;用输出参数绕开跨模块 double 返回值传递 bug)
|
||
use_val: double = cn_fp.float_val
|
||
rec_d: t.CDouble = 0.0
|
||
if self._recover_cdefine_float(name, t.CPtr(c.Addr(rec_d))) != 0:
|
||
use_val = rec_d
|
||
# CDEF-DBG: 打印 float_val 读取(定位浮点 CDefine 值错误)
|
||
fb_cd: t.CChar | t.CPtr = VLogger.fmt_buf()
|
||
if fb_cd is not None:
|
||
# 位模式拆解:把 float_val / rec_d 的 8 字节拷贝到 u64,再拆高低 32 位
|
||
# 用于确认"哪一半被覆写 + 被谁覆写"(若与 int_val/const_kind 位模式重叠即锁布局 bug)
|
||
fv_bits: t.CUInt64T = 0
|
||
string.memcpy(t.CVoid(t.CUInt64T(c.Addr(fv_bits)), t.CPtr),
|
||
t.CVoid(t.CUInt64T(c.Addr(cn_fp.float_val)), t.CPtr), 8)
|
||
rec_bits: t.CUInt64T = 0
|
||
string.memcpy(t.CVoid(t.CUInt64T(c.Addr(rec_bits)), t.CPtr),
|
||
t.CVoid(t.CUInt64T(c.Addr(rec_d)), t.CPtr), 8)
|
||
stdio.snprintf(fb_cd, 1024,
|
||
"REG-SRC: %s kind=%d const_kind=%d ptr=%p\n"
|
||
" fv=%.17g %a hi=%08llx lo=%08llx\n"
|
||
" int_val=%lld bits=%016llx const_kind_hex=%x str_val=%p\n"
|
||
" rec=%.17g %a hi=%08llx lo=%08llx use=%.17g",
|
||
name, val_node.kind(), cn_fp.const_kind, t.CSizeT(cn_fp),
|
||
cn_fp.float_val, cn_fp.float_val,
|
||
t.CUInt64T(fv_bits >> 32), t.CUInt64T(fv_bits & 0xFFFFFFFF),
|
||
cn_fp.int_val, t.CUInt64T(cn_fp.int_val), cn_fp.const_kind,
|
||
t.CSizeT(cn_fp.str_val),
|
||
rec_d, rec_d,
|
||
t.CUInt64T(rec_bits >> 32), t.CUInt64T(rec_bits & 0xFFFFFFFF),
|
||
use_val)
|
||
VLogger.info(fb_cd, "CDEF-DBG")
|
||
HandlesType.register_cdefine_double(pool, name, use_val)
|
||
return
|
||
val_fp: int = self.extract_cdefine_int_value(val_node)
|
||
HandlesType.register_cdefine_constant(pool, name, val_fp)
|
||
|
||
# ============================================================
|
||
# 源文件重读恢复 CDefine 浮点值
|
||
#
|
||
# 背景:AST 节点的 float_val/str_val 字段可能被 pool 分配操作覆写
|
||
# (MemBuddy 内存冲突),导致注册的浮点 CDefine 值错误(llc ret i32 0)。
|
||
# 本函数直接读源文件找 "NAME: t.CDefine = value" 行,atof 解析 value——
|
||
# 源文件文本不受 pool 影响,是最可靠的恢复路径。
|
||
#
|
||
# 原模块级 _g_recover_found 全局已迁移为实例字段 self.RecoverFound。
|
||
# ============================================================
|
||
|
||
def _recover_found(self) -> int:
|
||
"""检查最近一次 _recover_cdefine_float 是否成功"""
|
||
return self.RecoverFound
|
||
|
||
def _recover_cdefine_float(self, name: str, out: t.CDouble | t.CPtr) -> int:
|
||
"""从当前模块源文件恢复浮点 CDefine 值,写入 out[0],成功返回 1
|
||
|
||
用输出参数传递 double,避免 TPV 跨模块 double 返回值传递 bug。
|
||
"""
|
||
self.RecoverFound = 0
|
||
fp: str = HandlesType.get_current_file()
|
||
if fp is None or name is None or out is None:
|
||
return 0
|
||
f: fileio.File | t.CPtr = fileio.File(fp, fileio.MODE.R)
|
||
if f.closed:
|
||
return 0
|
||
BUF_SZ: t.CSizeT = 1048576
|
||
buf: bytes = stdlib.malloc(BUF_SZ)
|
||
if buf is None:
|
||
f.close()
|
||
return 0
|
||
nrd: LONG = f.read_all(buf, BUF_SZ)
|
||
f.close()
|
||
if nrd <= 0:
|
||
stdlib.free(buf)
|
||
return 0
|
||
if nrd < BUF_SZ:
|
||
buf[nrd] = 0
|
||
else:
|
||
buf[BUF_SZ - 1] = 0
|
||
|
||
name_len: t.CSizeT = string.strlen(name)
|
||
total_len: t.CSizeT = string.strlen(buf)
|
||
pos: t.CSizeT = 0
|
||
while pos < total_len:
|
||
line_start: t.CSizeT = pos
|
||
while pos < total_len and buf[pos] != '\n':
|
||
pos += 1
|
||
line_len: t.CSizeT = pos - line_start
|
||
if pos < total_len:
|
||
pos += 1
|
||
|
||
# 匹配 "name:"
|
||
if line_len < name_len + 1:
|
||
continue
|
||
match_ok: int = 1
|
||
ki: t.CSizeT
|
||
for ki in range(name_len):
|
||
if buf[line_start + ki] != name[ki]:
|
||
match_ok = 0
|
||
break
|
||
if match_ok == 0:
|
||
continue
|
||
if buf[line_start + name_len] != ':':
|
||
continue
|
||
|
||
# 行内包含 "t.CDefine"
|
||
has_cd: int = 0
|
||
ci: t.CSizeT = line_start + name_len + 1
|
||
while ci + 8 <= line_start + line_len:
|
||
if (buf[ci] == 't' and buf[ci + 1] == '.' and buf[ci + 2] == 'C' and
|
||
buf[ci + 3] == 'D' and buf[ci + 4] == 'e' and buf[ci + 5] == 'f' and
|
||
buf[ci + 6] == 'i' and buf[ci + 7] == 'n' and buf[ci + 8] == 'e'):
|
||
has_cd = 1
|
||
break
|
||
ci += 1
|
||
if has_cd == 0:
|
||
continue
|
||
|
||
# 找 '='
|
||
eq: t.CSizeT = line_start
|
||
while eq < line_start + line_len and buf[eq] != '=':
|
||
eq += 1
|
||
if eq >= line_start + line_len:
|
||
continue
|
||
eq += 1
|
||
while eq < line_start + line_len and buf[eq] == ' ':
|
||
eq += 1
|
||
val_start: t.CSizeT = eq
|
||
while eq < line_start + line_len and buf[eq] != ' ' and buf[eq] != '\t' \
|
||
and buf[eq] != '#' and buf[eq] != '\r' and buf[eq] != '\n':
|
||
eq += 1
|
||
if eq == val_start:
|
||
continue
|
||
|
||
val_txt: str = stdlib.malloc(eq - val_start + 1)
|
||
if val_txt is None:
|
||
stdlib.free(buf)
|
||
return 0
|
||
vi: t.CSizeT
|
||
for vi in range(eq - val_start):
|
||
val_txt[vi] = buf[val_start + vi]
|
||
val_txt[eq - val_start] = 0
|
||
stdlib.free(buf)
|
||
# 用 atof_out(输出参数)绕开跨模块 double 返回值传递 bug
|
||
if string.atof_out(val_txt, out) != 0:
|
||
self.RecoverFound = 1
|
||
return 1
|
||
return 0
|
||
|
||
stdlib.free(buf)
|
||
return 0
|
||
|
||
# ============================================================
|
||
# _annotation_contains_name - 递归检查注解中是否包含指定名称
|
||
#
|
||
# 支持 BinOp(BitOr) 递归,同时检查 Attribute.attr 和 Name.id。
|
||
# ============================================================
|
||
def _annotation_contains_name(self, annot: ast.AST | t.CPtr, name: str) -> int:
|
||
"""递归检查注解中是否包含指定名称,返回 1=包含 / 0=不包含"""
|
||
if annot is None or name is None:
|
||
return 0
|
||
k: int = annot.kind()
|
||
if k == ast.ASTKind.Attribute:
|
||
at: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(annot)
|
||
if at.attr is not None and string.strcmp(at.attr, name) == 0:
|
||
return 1
|
||
return 0
|
||
if k == ast.ASTKind.Name:
|
||
nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(annot)
|
||
if nm.id is not None and string.strcmp(nm.id, name) == 0:
|
||
return 1
|
||
return 0
|
||
if k == ast.ASTKind.BinOp:
|
||
bop: ast.BinOp | t.CPtr = (ast.BinOp | t.CPtr)(annot)
|
||
if self._annotation_contains_name(bop.left, name) != 0:
|
||
return 1
|
||
if self._annotation_contains_name(bop.right, name) != 0:
|
||
return 1
|
||
return 0
|
||
|
||
# ============================================================
|
||
# _is_ptr_element_annotation - 检查注解是否为 bytes|t.CPtr 或 str|t.CPtr
|
||
#
|
||
# 返回 1=是(下标按 8 字节步长, i8** 语义), 0=否(下标按 1 字节步长, i8* 语义)
|
||
#
|
||
# 规则:
|
||
# bytes|t.CPtr / str|t.CPtr → i8**(8 字节步长)→ 返回 1
|
||
# t.CChar|t.CPtr / t.CInt8T|t.CPtr → i8*(1 字节步长)→ 返回 0
|
||
# 纯 bytes / str → i8*(1 字节步长)→ 返回 0
|
||
#
|
||
# 注: 注解中的 "|" 是"和"的意思(组合类型),非右值中的位或运算
|
||
# ============================================================
|
||
def _is_ptr_element_annotation(self, annot: ast.AST | t.CPtr) -> int:
|
||
"""检查注解是否为 bytes|t.CPtr 或 str|t.CPtr 形式"""
|
||
if annot is None:
|
||
return 0
|
||
k: int = annot.kind()
|
||
if k != ast.ASTKind.BinOp:
|
||
return 0
|
||
bop: ast.BinOp | t.CPtr = (ast.BinOp | t.CPtr)(annot)
|
||
if bop.op != ast.OpKind.BitOr:
|
||
return 0
|
||
if self._annotation_contains_name(annot, "str") != 0:
|
||
return 1
|
||
if self._annotation_contains_name(annot, "bytes") != 0:
|
||
return 1
|
||
return 0
|
||
|
||
# ============================================================
|
||
# _init_global_array_from_list — 从列表字面量初始化全局数组
|
||
#
|
||
# 为每个元素生成 GEP + store 指令,将值存入全局数组的对应位置。
|
||
# 适用于模块级 t.CArray[elem_ty, count] = [v0, v1, ...] 的初始化。
|
||
#
|
||
# Args:
|
||
# builder: IRBuilder
|
||
# pool: 编译器内存池
|
||
# mod: LLVMModule
|
||
# array_alloca: 全局数组变量的 Value 引用(类型为 [N x elem_ty]*)
|
||
# list_node: ast.List 节点
|
||
# trans: Translator 对象
|
||
#
|
||
# Returns:
|
||
# 0 成功,1 失败
|
||
# ============================================================
|
||
def _init_global_array_from_list(self, builder: llvmlite.IRBuilder | t.CPtr,
|
||
pool: memhub.MemBuddy | t.CPtr,
|
||
mod: llvmlite.LLVMModule | t.CPtr,
|
||
array_alloca: llvmlite.Value | t.CPtr,
|
||
list_node: ast.AST | t.CPtr,
|
||
trans: HT.Translator | t.CPtr) -> int:
|
||
"""从列表字面量初始化全局数组,为每个元素生成 GEP + store"""
|
||
if builder is None or array_alloca is None or list_node is None:
|
||
return 1
|
||
|
||
# 获取数组类型(Pointee of [N x elem_ty]*)
|
||
arr_ty: llvmlite.LLVMType | t.CPtr = None
|
||
if array_alloca.Ty is not None:
|
||
arr_ty = array_alloca.Ty.Pointee
|
||
if arr_ty is None:
|
||
return 1
|
||
|
||
# 匹配数组类型获取元素类型
|
||
elem_ty: llvmlite.LLVMType | t.CPtr = None
|
||
match arr_ty:
|
||
case llvmlite.LLVMType.Array(et, _):
|
||
elem_ty = et
|
||
if elem_ty is None:
|
||
return 1
|
||
|
||
# 获取列表元素
|
||
lst: ast.List | t.CPtr = (ast.List | t.CPtr)(list_node)
|
||
if lst is None or lst.elts is None:
|
||
return 1
|
||
elts: list[ast.AST | t.CPtr] | t.CPtr = lst.elts
|
||
elts_count: t.CSizeT = elts.__len__()
|
||
|
||
# 为每个元素生成 GEP + store
|
||
i: t.CSizeT = 0
|
||
while i < elts_count:
|
||
elem_node: ast.AST | t.CPtr = elts.get(i)
|
||
elem_val: llvmlite.Value | t.CPtr = HandlesExpr.translate_value(
|
||
builder, pool, mod, elem_node, None, 0, trans)
|
||
if elem_val is not None:
|
||
idx_val: llvmlite.Value | t.CPtr = llvmlite.const_int32(pool, i)
|
||
elem_ptr: llvmlite.Value | t.CPtr = llvmlite.build_gep_array(
|
||
builder, arr_ty, elem_ty, array_alloca, idx_val)
|
||
if elem_ptr is not None:
|
||
# 类型转换(如 i32 → i8 截断)
|
||
store_val: llvmlite.Value | t.CPtr = elem_val
|
||
if elem_ptr.Ty is not None and elem_ptr.Ty.Pointee is not None:
|
||
store_val = HandlesExpr.coerce_to_type(
|
||
builder, elem_val, elem_ptr.Ty.Pointee, elem_node)
|
||
llvmlite.build_store(builder, store_val, elem_ptr)
|
||
i += 1
|
||
|
||
return 0
|
||
|
||
# ============================================================
|
||
# _apply_aug_op - 应用增强赋值的二元运算
|
||
#
|
||
# 支持浮点运算、指针算术: ptr += int / ptr -= int
|
||
# 整数运算自动类型提升
|
||
# ============================================================
|
||
def _apply_aug_op(self, pool: memhub.MemBuddy | t.CPtr,
|
||
builder: llvmlite.IRBuilder | t.CPtr,
|
||
op: int,
|
||
lhs: llvmlite.Value | t.CPtr,
|
||
rhs: llvmlite.Value | t.CPtr,
|
||
node: ast.AST | t.CPtr = None,
|
||
trans: HT.Translator | t.CPtr = None,
|
||
lhs_node: ast.AST | t.CPtr = None) -> llvmlite.Value | t.CPtr:
|
||
"""应用增强赋值的二元运算(浮点 + 指针算术 + 整数运算)"""
|
||
lhs_bits: int = HandlesExpr.get_llvm_type_bits(lhs.Ty)
|
||
rhs_bits: int = HandlesExpr.get_llvm_type_bits(rhs.Ty)
|
||
lhs_fbits: int = HandlesExpr.get_llvm_float_bits(lhs.Ty)
|
||
rhs_fbits: int = HandlesExpr.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 = HandlesExpr.coerce_to_type(builder, lhs, target_float_ty, node)
|
||
rhs = HandlesExpr.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 → getelementptr(按元素大小缩放)
|
||
# 对齐 TPC HandlesAugAssign.py L140-149 / L170-180
|
||
if lhs_bits == 0 and rhs_bits != 0:
|
||
if op == ast.OpKind.Add or op == ast.OpKind.Sub:
|
||
return HandlesExpr.translate_ptr_arith(pool, builder, lhs, rhs, op)
|
||
return None
|
||
|
||
# 整数运算:类型提升
|
||
if lhs_bits > rhs_bits and rhs_bits > 0:
|
||
rhs = HandlesExpr.coerce_to_type(builder, rhs, lhs.Ty, node)
|
||
elif rhs_bits > lhs_bits and lhs_bits > 0:
|
||
lhs = HandlesExpr.coerce_to_type(builder, lhs, rhs.Ty, node)
|
||
|
||
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 lhs_node is not None and trans is not None:
|
||
if HandlesExpr._node_type_unsigned(pool, lhs_node, trans) != 0:
|
||
return llvmlite.build_lshr(builder, lhs, rhs)
|
||
return llvmlite.build_ashr(builder, lhs, rhs)
|
||
return None
|