把 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。
241 lines
8.2 KiB
Plaintext
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'
|