R14:rawptr[X] -> X*(41 文件 / 2037 行改动),X 含模块限定名与嵌套下标(rawptr[GSList[NameEntry]] -> GSList[NameEntry]*)。保留 6 处 rawptr[t.CPtr](规范例外:存纯裸指针);# 注释与字符串里的 rawptr[...] 属元语法描述,未动。 R16(保守子集):t.CConst | str/bytes -> const str/bytes,t.CConst | char | t.CPtr -> const str;typedef 右值位置豁免(const str 在该处无法注册,与 R1 同源)。 验证:TPC 自举三重重编 SUCCESS;TransPyV.exe 全量 77/77 顺序回归通过。
241 lines
8.1 KiB
Plaintext
241 lines
8.1 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 值表示
|
|
#
|
|
# 表示一个 LLVM IR 值:SSA 临时值(%0/%result)或常量字面量(42/0)。
|
|
# 每个值有类型指针、名字、是否常量标志。
|
|
# 继承 GSListNode[Value] 获取强类型 Next: Value|CPtr(值池链表)
|
|
#
|
|
# 注意: 必须加 @t.NoVTable(理由见 __function.py 的 Line 注释)。
|
|
# ============================================================
|
|
@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'
|