Files
ViperC/App/lib/core/Gen/Expr/ExprGenMixin.vp
T
TermiNexus 3e52baa209 fix(viperc): 回退一元负号字面量的 f32 直出,保留正号字面量与 CDefine 的 f32 直出
- 现场二分定位:float(-10.0) / -float(10.0) 走「按目标类型直出 f32 常量」后,
  MLIR 渲染阶段报 float 位模式位宽不匹配(VKernel 整个编不过);同一份 gfx.vp
  只把负号字面量换成正号就渲染通过,故该路径回退为改动前行为(按操作数自身类型
  出常量,f64 常量 + 使用处 fptrunc)。
- 保留两条已验证有效的修复:
  1) 正号浮点字面量在 f32 目标下直接物化 f32 常量(translate_constant);
  2) CDefine 记宽度种类(1=f64 / 2=f32),define PI: float = ... 的使用处直出 f32
     常量(含 -PI —— 折叠按操作数类型出常量,操作数已是 f32,故仍是 f32)。
- define 常量补 ': int' 注解:无注解 define 按值的最小可存宽度物化(1/2 -> i8),
  直接当实参传给 list[int].append(x: int) 会落成 i8 != i32 被 mlir-opt 拦下
  (自举编译 TypeGenCDef 时必现)。
2026-10-15 19:25:49 +08:00

83 lines
5.8 KiB
Plaintext

import t, c
from stdint import *
import ast
import memhub
import mlirlite
import lib.core.Gen.Translator as HT
import lib.core.Gen.Expr.ExprGenBase as ExprGenBase
# docstring registry capacities (__doc__ magic attribute support).
# DOC_MAX: max entries; DOC_KEY_SZ: key "{module_sha1}.{symbol}" width; DOC_VAL_SZ: content width.
define DOC_MAX = 512
define DOC_KEY_SZ = 192
define DOC_VAL_SZ = 4096
# f-string translation constants (aligned with TPC HandlesExprFormat).
# FSTR_BUF_SIZE: runtime stack buffer; FSTR_SPEC_MAX: format_spec parse width; FSTR_FMT_MAX: printf format width.
define FSTR_BUF_SIZE = 1024
define FSTR_SPEC_MAX = 64
define FSTR_FMT_MAX = 64
# ExprGenMixin - expression handling mixin (objectified P3).
# ExprGenMixin - expressions / constants / subscripts / attributes / operators.
novirtual class ExprGenMixin(ExprGenBase.ExprGenBase):
"""Expression-handling mixin (pure methods, no state fields)."""
# Translate a value expression (RHS dispatch) - module-level version.
def translate_value(self, builder: mlirlite.IRBuilder*, pool: memhub.MemBuddy*, mod: mlirlite.LLVMModule*, node: ast.AST*, funcs_ptr: t.CPtr = None, func_count: int = 0, trans: HT.Translator* = None, target_ty: mlirlite.LLVMType* = None, use_ctx: str = None) -> mlirlite.Value*:
"""Translate a value expression to an LLVM Value (depth-guard wrapper; see _translate_value_impl).
target_ty = assignment/parameter type context; use_ctx = real call site for CDefine width checks."""
if trans is not None:
if trans.TranslateDepth >= HT.TRANSLATE_MAX_DEPTH: self.Gen.TypeGenErr.fatal_error(node, "expression translation nested too deep (suspected AST self-reference cycle or translation bug)", "RecursionError")
trans.TranslateDepth += 1
rv: mlirlite.Value* = self._translate_value_impl(builder, pool, mod, node, funcs_ptr, func_count, trans, target_ty, use_ctx)
if trans is not None: trans.TranslateDepth -= 1
return rv
def _translate_value_impl(self, builder: mlirlite.IRBuilder*, pool: memhub.MemBuddy*, mod: mlirlite.LLVMModule*, node: ast.AST*, funcs_ptr: t.CPtr = None, func_count: int = 0, trans: HT.Translator* = None, target_ty: mlirlite.LLVMType* = None, use_ctx: str = None) -> mlirlite.Value*:
"""Translate a value expression to an LLVM Value."""
if node is None: return None
k: int = node.kind()
if k == ast.ASTKind.Constant:
rv: mlirlite.Value* = self.Gen.ExprGenConst.translate_constant(builder, pool, mod, node, trans, target_ty)
return rv
elif k == ast.ASTKind.Name: return self.Gen.ExprGenName.translate_name_value(builder, pool, node, trans, target_ty, use_ctx)
elif k == ast.ASTKind.BinOp: return self.Gen.ExprGenOps.translate_binop(pool, builder, mod, node, trans, target_ty)
elif k == ast.ASTKind.Call: return self.Gen.CallGen.translate_call(pool, builder, mod, node, funcs_ptr, func_count, trans)
# M2.4 `new stack|heap|memgr(x) [slife|hlife] T(args)`:只换"取存储",其余复用构造序列
elif k == ast.ASTKind.New: return self.Gen.CallGenCtor._translate_new_expr(pool, builder, mod, ast.New*(node), trans)
elif k == ast.ASTKind.Compare: return self.Gen.ExprGenOps.translate_compare(builder, pool, mod, node, trans)
elif k == ast.ASTKind.UnaryOp: return self.Gen.ExprGenOps.translate_unaryop(builder, pool, mod, node, trans)
elif k == ast.ASTKind.BoolOp: return self.Gen.ExprGenOps.translate_boolop(builder, pool, mod, node, funcs_ptr, func_count, trans)
elif k == ast.ASTKind.Subscript: return self.Gen.ExprGenName.translate_subscript(builder, pool, mod, node, trans)
elif k == ast.ASTKind.Attribute: return self.Gen.ExprGenAttr.translate_attribute(builder, pool, mod, node, trans)
elif k == ast.ASTKind.List: return self.Gen.ExprGenConst.translate_list_literal(builder, pool, mod, node, None, trans)
elif k == ast.ASTKind.IfExp: return self.Gen.ExprGenOps.translate_ifexp(builder, pool, mod, node, trans)
elif k == ast.ASTKind.Lambda: return self.Gen.FuncGen.translate_lambda(builder, pool, mod, node, trans)
elif k == ast.ASTKind.JoinedStr: return self.Gen.ExprGenFstr.translate_joined_str(builder, pool, mod, node, trans)
elif k == ast.ASTKind.FormattedValue: return self.Gen.ExprGenFstr.translate_formatted_value(builder, pool, mod, node, trans)
elif k == ast.ASTKind.Await:
# Coroutine await (VPC-M1): inline-translate when the await target is an async call.
# Returns the child coroutine's i32 ret; top-level await is handled by AsyncGen.
aw: ast.Await* = ast.Await*(node)
if aw is not None and aw.value is not None and aw.value.kind() == ast.ASTKind.Call:
aw_cl: ast.Call* = ast.Call*(aw.value)
if aw_cl.func is not None and aw_cl.func.kind() == ast.ASTKind.Name:
aw_nm: ast.Name* = ast.Name*(aw_cl.func)
if aw_nm.id is not None and trans is not None:
if self.Gen.AsyncGen.is_async_func(trans, aw_nm.id) != 0: return self.Gen.AsyncGen._emit_await(builder, pool, mod, trans, aw, aw_nm.id)
return None
elif k == ast.ASTKind.Starred:
# *x in a value context: the parser tags '*' as Starred, but Viper has no unpacking.
# Treat it as C unary deref (*ptr -> load pointee) by building a Deref UnaryOp.
st: ast.Starred* = ast.Starred*(node)
if st is None or st.value is None: return None
deref_node: ast.AST* = ast.UnaryOp(pool, ast.OpKind.Deref, st.value)
if deref_node is None: return None
return self.Gen.ExprGenOps.translate_unaryop(builder, pool, mod, deref_node, trans)
return None