Files
Viper_VRTE/mlirlite/__values.vp
T
TermiNexus c0d56b127d chore(comments): includes 头注释英文化(R11 收尾)
把 includes 下 64 个 .vp 的文件头注释(含 traceback.vp 第 13-427 行的整块文件级说明)以及 2 处漏网的正文中文注释(ast/lexer.vp、json/__writer.vp)与 1 处中文 docstring(memhub.vp)逐行译为英文;同步把 fltk/gen_ffi.py 的生成模板与其自身注释英文化,使重新生成仍为英文。

只改注释/文档串文字:行数与代码逐字节不变(骨架比对 140 文件漂移 0),运行时中文字符串字面量 305 处保持原样。验证:三重重编 SUCCESS(170.21s)+ 全量 77/77 顺序回归通过 + VET 编译 SUCCESS / --search-paths 7 条 exit 0。
2026-10-06 09:42:25 +08:00

241 lines
8.2 KiB
Plaintext

import t, c
from stdint import *
import string
import viperlib
import stdio
import memhub
from linkedlist import GSListNode
from .__types import LLVMType, TypePrint
# ============================================================
# Value: SSA value representation
#
# Represents an LLVM IR value: an SSA temporary (%0/%result) or a constant literal (42/0).
# Each value has a type pointer, a name, and an is-constant flag.
# Inherits GSListNode[Value] to get a strongly-typed Next: Value|CPtr (the value pool list)
#
# Note: @t.NoVTable must be added (see the Line comment in __function.py for the reason).
# ============================================================
@t.NoVTable
class Value(GSListNode[Value]):
Ty: LLVMType* # value type
Name: str # SSA name ("%0"/"%result") or constant text ("42"/"1.5e+00")
IsConst: int # 1 = constant literal, 0 = SSA temporary
IntVal: int64 # integer constant value (used when IsConst=1)
FloatVal: double # float constant value (used when IsConst=1 and Ty is Float)
# ============================================================
# Factory functions
# ============================================================
# Value hardcoded size: Next(8) + Ty(8) + Name(8) + IsConst(4) + IntVal(8) + FloatVal(8) = 48 bytes
define VALUE_SIZE = 48
def new_value(pool: memhub.MemBuddy*) -> Value*:
"""Allocate a zero-initialized Value from mpool."""
ptr: Value* = pool.alloc(VALUE_SIZE)
if ptr:
string.memset(ptr, 0, VALUE_SIZE)
return ptr
def ConstInt(pool: memhub.MemBuddy*, ty: LLVMType*,
val: int64, name: str) -> Value*:
"""Create an integer constant value.
ty: integer type (Int1/Int8/Int32/Int64); val: integer value; name: caller-provided constant text (e.g. "42").
"""
v: Value* = new_value(pool)
if v is None: return None
v.Ty = ty
v.Name = name
v.IsConst = 1
v.IntVal = val
return v
def ConstNull(pool: memhub.MemBuddy*, ty: LLVMType*,
name: str) -> Value*:
"""Create a null pointer constant."""
v: Value* = new_value(pool)
if v is None: return None
v.Ty = ty
v.Name = name
v.IsConst = 1
v.IntVal = 0
return v
def ConstZero(pool: memhub.MemBuddy*, ty: LLVMType*) -> Value*:
"""Create a zeroinitializer constant (zero-initialized aggregate: struct/array)."""
v: Value* = new_value(pool)
if v is None: return None
v.Ty = ty
v.Name = "zeroinitializer"
v.IsConst = 1
v.IntVal = 0
return v
def ConstFloat(pool: memhub.MemBuddy*, ty: LLVMType*,
val: double) -> Value*:
"""Create a float constant value.
ty: float type; val: float value. Name is the raw bit pattern (f16 0x%04x, f32 0x%08x,
f64 0x%016llx, f128 0x%032x hi+lo) so MLIR FloatAttr is lossless; use CRT stdio.snprintf (%g in viperlib is buggy).
"""
v: Value* = new_value(pool)
if v is None: return None
v.Ty = ty
v.IsConst = 1
v.FloatVal = val
v.IntVal = 0
f_bits: int = 64
match ty:
case LLVMType.Float(ftb):
f_bits = ftb
name_buf: str = pool.alloc(64)
if name_buf is not None:
if f_bits == 16:
# half: round to half first (double -> half is fptrunc), then take its 2-byte bit pattern
h16: t.CFloat16T = t.CFloat16T(val)
b16: uint16 = 0
*&b16 = *&h16
stdio.snprintf(name_buf, 64, "0x%04x", b16)
elif f_bits == 32:
# f32 bit pattern must be the float 32-bit encoding, not the low 32 bits of the double
# (3.14 double=0x40091EB851EB851F, low 0x51EB851F != f32 0x4048F5C3): round to f32 first.
f32v: float = float(val)
b32: uint32 = 0
*&b32 = *&f32v
stdio.snprintf(name_buf, 64, "0x%08x", b32)
elif f_bits == 128:
# quad: double -> fp128 is lossless (fpext); little-endian low 64 first, print big-endian
# (hi first). c.Load width follows the source pointee, so cast the source to u64* to avoid overflow.
q128: t.CFloat128T = t.CFloat128T(val)
q8: uint8* = (uint8*)(&q128)
q_lo: uint64 = 0
q_hi: uint64 = 0
*&q_lo = *(uint64*)(q8)
*&q_hi = *(uint64*)(q8 + 8)
stdio.snprintf(name_buf, 64, "0x%016llx%016llx", q_hi, q_lo)
else:
fv_bits: uint64 = 0
*&fv_bits = *&val
stdio.snprintf(name_buf, 64, "0x%016llx", fv_bits)
v.Name = name_buf
return v
def SSAValue(pool: memhub.MemBuddy*, ty: LLVMType*,
name: str) -> Value*:
"""Create an SSA temporary value.
ty: value type; name: caller-provided SSA name (e.g. "%0"/"%result").
"""
v: Value* = new_value(pool)
if v is None: return None
v.Ty = ty
v.Name = name
v.IsConst = 0
v.IntVal = 0
return v
# ============================================================
# ValuePrint: serialize a value to MLIR text (diagnostics only)
#
# SSA value -> "%0" (operands are bare SSA names); constant -> "42 : i32" (MLIR attribute form).
# Instruction rendering MUST NOT depend on this; op rendering goes through __function.vp (constants
# must first be materialized as llvm.mlir.constant/zero/addressof ops).
# ============================================================
def ValuePrint(buf: str, size: sizet,
val: Value*, pool: memhub.MemBuddy*):
"""Serialize val into buf as MLIR text; pool is used to allocate scratch buffers for
recursive complex types (Array/Struct/Func).
"""
if val is None or buf is None or size == 0:
return
buf[0] = '\0'
if val.Name is None:
return
if val.IsConst == 0:
# SSA value: emit only the SSA name
_append_str(buf, size, val.Name)
return
# constant: "<constant text> : <MLIR type>"
_append_str(buf, size, val.Name)
_append_str(buf, size, " : ")
tp: str = pool.alloc(4096)
if tp is not None:
TypePrint(tp, 4096, val.Ty, pool)
_append_str(buf, size, tp)
# ============================================================
# Value field accessors (let other modules bypass stub-type limits)
#
# Cross-module callers only see a stub Value (missing/wrong fields), so TransPyC silently skips
# field access; these accessors run inside this module with the full type definition.
# ============================================================
def value_get_ty(val: Value*) -> LLVMType*:
"""Get the value's type."""
if val is None:
return None
return val.Ty
def value_get_next(val: Value*) -> Value*:
"""Get the next value in the list."""
if val is None:
return None
return val.Next
def value_set_ty(val: Value*, ty: LLVMType*):
"""Set the value's type."""
if val is None:
return
val.Ty = ty
def value_set_next(val: Value*, nxt: Value*):
"""Set the next value in the list."""
if val is None:
return
val.Next = nxt
def value_set_name(val: Value*, name: str):
"""Set the value's name."""
if val is None:
return
val.Name = name
def value_set_isconst(val: Value*, is_const: int):
"""Set whether the value is a constant."""
if val is None:
return
val.IsConst = is_const
# ============================================================
# Internal helpers
# ============================================================
def _append_str(dst: str, dst_size: sizet, src: str):
"""Append src to the end of dst."""
if dst is None or src is None: return
dlen: sizet = string.strlen(dst)
# Unsigned-underflow guard: if dlen >= buffer size (buffer corrupt/dangling) return early,
# else remain = dst_size - dlen underflows and dst[dlen+i] would write past the buffer.
if dlen >= dst_size:
return
slen: sizet = string.strlen(src)
remain: sizet = dst_size - dlen
if remain <= 0: return
i: sizet = 0
while i < slen and i + 1 < remain:
dst[dlen + i] = src[i]
i += 1
dst[dlen + i] = '\0'