128 lines
5.2 KiB
Python
128 lines
5.2 KiB
Python
import t, c
|
||
from stdint import *
|
||
import ast
|
||
import llvmlite
|
||
import memhub
|
||
import string
|
||
import stdio
|
||
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 或全局变量)
|
||
#
|
||
# 在提升的嵌套函数中:
|
||
# 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 i32*
|
||
# f. read: %val = load i32, i32* %var_ptr
|
||
# write: store i32 %new, i32* %var_ptr
|
||
# ============================================================
|
||
|
||
|
||
# ============================================================
|
||
# 获取或创建 _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
|
||
|
||
|
||
# ============================================================
|
||
# 加载 nonlocal 变量值 → 返回 i32 Value
|
||
#
|
||
# env 直接存储 i32 值(不是指针),每个 nonlocal 变量占 4 字节
|
||
# ============================================================
|
||
def load_nonlocal_var(trans: HT.Translator | t.CPtr,
|
||
name: str) -> llvmlite.Value | t.CPtr:
|
||
"""从闭包 env 加载 nonlocal 变量值(env 直接存储 i32 值)"""
|
||
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)
|
||
i32_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int32(pool)
|
||
i32_ptr_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, i32_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 * 4) — env 直接存储 i32 值
|
||
offset_val: llvmlite.Value | t.CPtr = llvmlite.const_int32(pool, idx * 4)
|
||
addr: llvmlite.Value | t.CPtr = llvmlite.build_gep(builder, i8_ty, env_ptr, offset_val)
|
||
if addr is None:
|
||
return None
|
||
|
||
# 3. Bitcast to i32* and load
|
||
var_ptr: llvmlite.Value | t.CPtr = llvmlite.build_bitcast(builder, addr, i32_ptr_ty)
|
||
if var_ptr is None:
|
||
return None
|
||
return llvmlite.build_load(builder, i32_ty, var_ptr)
|
||
|
||
|
||
# ============================================================
|
||
# 获取 nonlocal 变量指针(用于 store)
|
||
#
|
||
# 返回 env 中 i32 槽位的地址(i32*),用于直接 store
|
||
# ============================================================
|
||
def get_nonlocal_var_ptr(trans: HT.Translator | t.CPtr,
|
||
name: str) -> llvmlite.Value | t.CPtr:
|
||
"""获取 nonlocal 变量在 env 中的地址(i32*),用于 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)
|
||
i32_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int32(pool)
|
||
i32_ptr_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, i32_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 * 4) — env 直接存储 i32 值
|
||
offset_val: llvmlite.Value | t.CPtr = llvmlite.const_int32(pool, idx * 4)
|
||
addr: llvmlite.Value | t.CPtr = llvmlite.build_gep(builder, i8_ty, env_ptr, offset_val)
|
||
if addr is None:
|
||
return None
|
||
|
||
# 3. Bitcast to i32* and return (直接指向 env 中的 i32 槽位)
|
||
return llvmlite.build_bitcast(builder, addr, i32_ptr_ty)
|