176 lines
7.3 KiB
Plaintext
176 lines
7.3 KiB
Plaintext
import t, c
|
||
from stdint import *
|
||
import ast
|
||
import llvmlite
|
||
import memhub
|
||
import string
|
||
import stdio
|
||
import lib.core.VLogger as VLogger
|
||
import lib.core.Handles.HandlesTranslator as HT
|
||
import lib.core.Handles.HandlesVar as HandlesVar
|
||
|
||
|
||
# ============================================================
|
||
# HandlesNonlocal - nonlocal 变量访问(通过闭包 env)
|
||
#
|
||
# 闭包 env 结构: {i8* ptr0, i8* ptr1, ...} (每个 nonlocal 变量一个 i8* 指针)
|
||
# 指针指向父函数中变量的 alloca(原始存储位置),父与子共享同一存储,
|
||
# 子函数修改对父函数可见(符合 Python nonlocal 语义)。
|
||
#
|
||
# 在提升的嵌套函数中:
|
||
# 1. 函数签名: define i32 @__closure_{name}(i8* %env)
|
||
# 2. 入口处: %env_alloca = alloca i8*; store i8* %env, i8** %env_alloca
|
||
# 3. 访问 nonlocal var:
|
||
# a. %env_ptr = load i8*, i8** %env_alloca
|
||
# b. %addr = gep i8, i8* %env_ptr, i32 (index * 8)
|
||
# c. %ptr_addr = bitcast i8* %addr to i8**
|
||
# d. %var_ptr_raw = load i8*, i8** %ptr_addr
|
||
# e. %var_ptr = bitcast i8* %var_ptr_raw to <var_ty>*
|
||
# f. read: %val = load <var_ty>, <var_ty>* %var_ptr
|
||
# write: store <var_ty> %new, <var_ty>* %var_ptr
|
||
#
|
||
# 变量类型通过 HT.get_nonlocal_type() 获取(注册 nonlocal 时记录)。
|
||
# ============================================================
|
||
|
||
|
||
# ============================================================
|
||
# _is_void_type — 判断是否为 Void 类型(非法用作变量类型)
|
||
#
|
||
# 由于某些路径(如 c.DerefAs 设置的 Pointee 字段访问异常)可能导致
|
||
# 类型被设为 Void 而非 None,这里显式检测 Void 类型并视为无效,
|
||
# 回退为 i32,避免生成 "bitcast ... to void*" / "load void, void*" 的非法 IR。
|
||
# ============================================================
|
||
def _is_void_type(ty: llvmlite.LLVMType | t.CPtr) -> int:
|
||
"""判断是否为 Void 类型,是则返回 1,否则 0"""
|
||
if ty is None:
|
||
return 0
|
||
match ty:
|
||
case llvmlite.LLVMType.Void():
|
||
return 1
|
||
case _:
|
||
return 0
|
||
|
||
|
||
# ============================================================
|
||
# 获取或创建 _env_ptr 变量(存储 env 参数的 alloca)
|
||
# ============================================================
|
||
def get_env_ptr_var(trans: HT.Translator | t.CPtr) -> llvmlite.Value | t.CPtr:
|
||
"""获取或创建 _env_ptr 变量(存储闭包 env 指针)"""
|
||
env_var: llvmlite.Value | t.CPtr = HandlesVar.lookup_var(
|
||
trans.SymTab, "_env_ptr")
|
||
if env_var is not None:
|
||
return env_var
|
||
# 创建 alloca 存储 env
|
||
pool: memhub.MemBuddy | t.CPtr = trans.Pool
|
||
builder: llvmlite.IRBuilder | t.CPtr = trans._cur_builder
|
||
i8_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int8(pool)
|
||
i8_ptr_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, i8_ty)
|
||
alloca: llvmlite.Value | t.CPtr = llvmlite.build_alloca(builder, i8_ptr_ty)
|
||
if alloca is None:
|
||
return None
|
||
HandlesVar.define_var(trans.SymTab, "_env_ptr", alloca)
|
||
return alloca
|
||
|
||
|
||
# ============================================================
|
||
# 从 env 加载原始变量指针(i8*)→ 调用方 bitcast 为具体类型
|
||
#
|
||
# env 存储指针数组(8 字节/槽),每个指针指向父函数的 alloca。
|
||
# ============================================================
|
||
def _load_raw_var_ptr(trans: HT.Translator | t.CPtr,
|
||
name: str) -> llvmlite.Value | t.CPtr:
|
||
"""从闭包 env 加载 nonlocal 变量的原始指针(i8*)
|
||
|
||
返回 i8* 类型的 Value,调用方需 bitcast 为具体类型指针后 load/store。
|
||
"""
|
||
idx: int = HT.get_nonlocal_index(trans, name)
|
||
if idx < 0:
|
||
return None
|
||
|
||
pool: memhub.MemBuddy | t.CPtr = trans.Pool
|
||
builder: llvmlite.IRBuilder | t.CPtr = trans._cur_builder
|
||
i8_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int8(pool)
|
||
i8_ptr_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, i8_ty)
|
||
i8_ptr_ptr_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, i8_ptr_ty)
|
||
|
||
# 1. 加载 env_ptr
|
||
env_alloca: llvmlite.Value | t.CPtr = get_env_ptr_var(trans)
|
||
if env_alloca is None:
|
||
return None
|
||
env_ptr: llvmlite.Value | t.CPtr = llvmlite.build_load(builder, i8_ptr_ty, env_alloca)
|
||
if env_ptr is None:
|
||
return None
|
||
|
||
# 2. GEP to offset (idx * 8) — env 存储指针数组,每槽 8 字节
|
||
offset_val: llvmlite.Value | t.CPtr = llvmlite.const_int32(pool, idx * 8)
|
||
addr: llvmlite.Value | t.CPtr = llvmlite.build_gep(builder, i8_ty, env_ptr, offset_val)
|
||
if addr is None:
|
||
return None
|
||
|
||
# 3. Bitcast to i8** and load the raw pointer
|
||
ptr_addr: llvmlite.Value | t.CPtr = llvmlite.build_bitcast(builder, addr, i8_ptr_ptr_ty)
|
||
if ptr_addr is None:
|
||
return None
|
||
return llvmlite.build_load(builder, i8_ptr_ty, ptr_addr)
|
||
|
||
|
||
# ============================================================
|
||
# 加载 nonlocal 变量值 → 返回具体类型的 Value
|
||
#
|
||
# env 存储指向父函数 alloca 的指针,通过类型恢复 load 正确类型的值。
|
||
# ============================================================
|
||
def load_nonlocal_var(trans: HT.Translator | t.CPtr,
|
||
name: str) -> llvmlite.Value | t.CPtr:
|
||
"""从闭包 env 加载 nonlocal 变量值
|
||
|
||
通过 HT.get_nonlocal_type 获取变量类型,bitcast 原始指针后 load。
|
||
"""
|
||
raw_ptr: llvmlite.Value | t.CPtr = _load_raw_var_ptr(trans, name)
|
||
if raw_ptr is None:
|
||
return None
|
||
|
||
pool: memhub.MemBuddy | t.CPtr = trans.Pool
|
||
builder: llvmlite.IRBuilder | t.CPtr = trans._cur_builder
|
||
|
||
# 获取变量类型(从注册时存储的类型信息)
|
||
var_ty: llvmlite.LLVMType | t.CPtr = HT.get_nonlocal_type(trans, name)
|
||
if var_ty is None or _is_void_type(var_ty) != 0:
|
||
# Void 类型视为无效(会导致 "load void, void*" 非法 IR),回退为 i32
|
||
var_ty = llvmlite.Int32(pool)
|
||
|
||
# bitcast raw i8* to var_ty*
|
||
var_ptr_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, var_ty)
|
||
var_ptr: llvmlite.Value | t.CPtr = llvmlite.build_bitcast(builder, raw_ptr, var_ptr_ty)
|
||
if var_ptr is None:
|
||
return None
|
||
return llvmlite.build_load(builder, var_ty, var_ptr)
|
||
|
||
|
||
# ============================================================
|
||
# 获取 nonlocal 变量指针(用于 store)
|
||
#
|
||
# 返回具体类型指针(var_ty*),用于直接 store。
|
||
# ============================================================
|
||
def get_nonlocal_var_ptr(trans: HT.Translator | t.CPtr,
|
||
name: str) -> llvmlite.Value | t.CPtr:
|
||
"""获取 nonlocal 变量的存储指针(var_ty*),用于 store 操作
|
||
|
||
返回的指针指向父函数的 alloca,store 操作对父函数可见。
|
||
"""
|
||
raw_ptr: llvmlite.Value | t.CPtr = _load_raw_var_ptr(trans, name)
|
||
if raw_ptr is None:
|
||
return None
|
||
|
||
pool: memhub.MemBuddy | t.CPtr = trans.Pool
|
||
builder: llvmlite.IRBuilder | t.CPtr = trans._cur_builder
|
||
|
||
# 获取变量类型
|
||
var_ty: llvmlite.LLVMType | t.CPtr = HT.get_nonlocal_type(trans, name)
|
||
if var_ty is None or _is_void_type(var_ty) != 0:
|
||
# Void 类型视为无效(会导致 "bitcast ... to void*" 非法 IR),回退为 i32
|
||
var_ty = llvmlite.Int32(pool)
|
||
|
||
# bitcast raw i8* to var_ty*
|
||
var_ptr_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, var_ty)
|
||
return llvmlite.build_bitcast(builder, raw_ptr, var_ptr_ty)
|