1273 lines
50 KiB
Python
1273 lines
50 KiB
Python
import t, c
|
||
from stdint import *
|
||
import string
|
||
import viperlib
|
||
import memhub
|
||
import stdio
|
||
from linkedlist import GSListNode, GSList
|
||
from .__types import LLVMType, TypePrint
|
||
from .__values import Value, new_value, SSAValue
|
||
from .__function import Function, BasicBlock, block_append_text, function_move_block_to_end, _ll_name_needs_quote
|
||
|
||
# ============================================================
|
||
# IRBuilder: 游标式 IR 指令发射器
|
||
#
|
||
# 跟踪当前 BasicBlock,将指令文本追加到块的指令链表。
|
||
# 维护递增的 SSA 名计数器(%0, %1, %2, ...)。
|
||
#
|
||
# 用法:
|
||
# builder = new_builder(pool, func)
|
||
# builder.PositionAtEnd(entry_block)
|
||
# a = builder.build_alloca(i32_ty)
|
||
# b = builder.build_alloca(i32_ty)
|
||
# builder.build_store(ConstInt(42), a)
|
||
# r = builder.build_load(i32_ty, a)
|
||
# builder.build_ret(r)
|
||
#
|
||
# 注意: 加 @t.NoVTable 以与硬编码 BUILDER_SIZE=32 保持一致
|
||
# (所有方法均为顶层函数,无需 vtable)。
|
||
# ============================================================
|
||
@t.NoVTable
|
||
class IRBuilder:
|
||
Pool: memhub.MemBuddy | t.CPtr # 内存池
|
||
Func: Function | t.CPtr # 所属函数
|
||
CurBlock: BasicBlock | t.CPtr # 当前插入点
|
||
Counter: t.CInt # SSA 名计数器
|
||
|
||
|
||
# ============================================================
|
||
# 工厂函数
|
||
# ============================================================
|
||
# IRBuilder 硬编码大小: Pool(8) + Func(8) + CurBlock(8) + Counter(4) = 32 字节
|
||
BUILDER_SIZE: t.CDefine = 32
|
||
|
||
def new_builder(pool: memhub.MemBuddy | t.CPtr, func: Function | t.CPtr) -> IRBuilder | t.CPtr:
|
||
"""创建 IRBuilder,关联到函数 func"""
|
||
ptr: IRBuilder | t.CPtr = pool.alloc(BUILDER_SIZE)
|
||
if ptr is None: return None
|
||
string.memset(ptr, 0, BUILDER_SIZE)
|
||
ptr.Pool = pool
|
||
ptr.Func = func
|
||
ptr.CurBlock = None
|
||
ptr.Counter = 0
|
||
return ptr
|
||
|
||
|
||
# ============================================================
|
||
# 块定位
|
||
# ============================================================
|
||
def position_at_end(builder: IRBuilder | t.CPtr, block: BasicBlock | t.CPtr):
|
||
"""将插入点设为 block 的末尾,并把 block 移到函数块链表末尾。
|
||
|
||
移动 block 是为了保证 BB 文本输出顺序与控制流(position)顺序一致,
|
||
避免 SSA 名在文本中非单调递增导致 llc 编译失败。
|
||
"""
|
||
if builder is None: return
|
||
builder.CurBlock = block
|
||
if builder.Func is not None:
|
||
function_move_block_to_end(builder.Func, block)
|
||
|
||
|
||
# ============================================================
|
||
# 内部辅助
|
||
# ============================================================
|
||
def _alloc_ssa_name(builder: IRBuilder | t.CPtr) -> t.CChar | t.CPtr:
|
||
"""分配一个 SSA 名字符串 "%N" 并递增计数器"""
|
||
pool: memhub.MemBuddy | t.CPtr = builder.Pool
|
||
buf: t.CChar | t.CPtr = pool.alloc(16)
|
||
if buf is None: return None
|
||
viperlib.snprintf(buf, 16, "%%%d", builder.Counter)
|
||
builder.Counter += 1
|
||
return buf
|
||
|
||
|
||
def _type_str(builder: IRBuilder | t.CPtr, ty: LLVMType | t.CPtr) -> t.CChar | t.CPtr:
|
||
"""获取类型的 IR 文本(从 pool 分配 512 字节缓冲区)
|
||
|
||
注意:复杂结构体类型(如 13 方法的虚表 {i8*,i8*,...})可能超过 64 字节,
|
||
必须使用足够大的缓冲区,否则 '}' 会被截断导致 IR 语法错误。
|
||
"""
|
||
pool: memhub.MemBuddy | t.CPtr = builder.Pool
|
||
buf: t.CChar | t.CPtr = pool.alloc(512)
|
||
if buf is None: return None
|
||
buf[0] = '\0'
|
||
TypePrint(buf, 512, ty, pool)
|
||
return buf
|
||
|
||
|
||
def _emit(builder: IRBuilder | t.CPtr, text: t.CChar | t.CPtr):
|
||
"""将指令文本追加到当前块"""
|
||
if builder is None or builder.CurBlock is None: return
|
||
block_append_text(builder.Pool, builder.CurBlock, text)
|
||
|
||
|
||
def _mark_terminated(builder: IRBuilder | t.CPtr):
|
||
"""标记当前块已终止"""
|
||
if builder is None or builder.CurBlock is None: return
|
||
builder.CurBlock.IsTerminated = 1
|
||
|
||
|
||
def builder_cur_block_is_terminated(builder: IRBuilder | t.CPtr) -> t.CInt:
|
||
"""检查当前块的 IsTerminated 标志
|
||
|
||
供其他模块绕过 stub 类型限制使用:
|
||
builder.CurBlock.IsTerminated 在 stub 类型中 BasicBlock 为 opaque,
|
||
直接访问会被 TransPyC 静默跳过(不生成 GEP,不报错),
|
||
导致返回寄存器残留值,br 回边指令被错误跳过。
|
||
"""
|
||
if builder is None or builder.CurBlock is None:
|
||
return 1
|
||
return builder.CurBlock.IsTerminated
|
||
|
||
|
||
# ============================================================
|
||
# 内存指令
|
||
# ============================================================
|
||
def build_alloca(builder: IRBuilder | t.CPtr, ty: LLVMType | t.CPtr) -> Value | t.CPtr:
|
||
"""%N = alloca <ty>
|
||
|
||
返回类型为 ty* 的 SSA 值
|
||
"""
|
||
if builder is None: return None
|
||
pool: memhub.MemBuddy | t.CPtr = builder.Pool
|
||
name: t.CChar | t.CPtr = _alloc_ssa_name(builder)
|
||
ty_s: t.CChar | t.CPtr = _type_str(builder, ty)
|
||
line: t.CChar | t.CPtr = pool.alloc(128)
|
||
if line is None: return None
|
||
viperlib.snprintf(line, 128, "%s = alloca %s", name, ty_s)
|
||
_emit(builder, line)
|
||
|
||
# 结果类型是 ty*
|
||
result_ty: LLVMType | t.CPtr = LLVMType.Ptr(ty)
|
||
result_ty_ptr: LLVMType | t.CPtr = pool.alloc(LLVMType.__sizeof__())
|
||
if result_ty_ptr is not None:
|
||
string.memset(result_ty_ptr, 0, LLVMType.__sizeof__())
|
||
c.DerefAs(result_ty_ptr, result_ty)
|
||
return SSAValue(pool, result_ty_ptr, name)
|
||
|
||
|
||
def build_alloca_at_entry(builder: IRBuilder | t.CPtr, ty: LLVMType | t.CPtr) -> Value | t.CPtr:
|
||
"""%N = alloca <ty>(在函数入口块生成,确保支配性)
|
||
|
||
在入口块的终止指令之前插入 alloca,避免在条件分支内生成 alloca
|
||
导致的支配性违规(Instruction does not dominate all uses)。
|
||
"""
|
||
if builder is None: return None
|
||
pool: memhub.MemBuddy | t.CPtr = builder.Pool
|
||
func: Function | t.CPtr = builder.Func
|
||
if func is None or func.Blocks is None:
|
||
return build_alloca(builder, ty)
|
||
entry_blk: BasicBlock | t.CPtr = func.Blocks.Head
|
||
if entry_blk is None:
|
||
return build_alloca(builder, ty)
|
||
name: t.CChar | t.CPtr = _alloc_ssa_name(builder)
|
||
ty_s: t.CChar | t.CPtr = _type_str(builder, ty)
|
||
line_text: t.CChar | t.CPtr = pool.alloc(128)
|
||
if line_text is None: return None
|
||
viperlib.snprintf(line_text, 128, "%s = alloca %s", name, ty_s)
|
||
# 在入口块终止指令之前插入
|
||
block_insert_text_before_terminator(pool, entry_blk, line_text)
|
||
# 结果类型是 ty*
|
||
result_ty: LLVMType | t.CPtr = LLVMType.Ptr(ty)
|
||
result_ty_ptr: LLVMType | t.CPtr = pool.alloc(LLVMType.__sizeof__())
|
||
if result_ty_ptr is not None:
|
||
string.memset(result_ty_ptr, 0, LLVMType.__sizeof__())
|
||
c.DerefAs(result_ty_ptr, result_ty)
|
||
return SSAValue(pool, result_ty_ptr, name)
|
||
|
||
|
||
def build_load(builder: IRBuilder | t.CPtr, ty: LLVMType | t.CPtr,
|
||
ptr: Value | t.CPtr) -> Value | t.CPtr:
|
||
"""%N = load <ty>, <ptr_ty> <ptr>"""
|
||
if builder is None or ptr is None: return None
|
||
pool: memhub.MemBuddy | t.CPtr = builder.Pool
|
||
name: t.CChar | t.CPtr = _alloc_ssa_name(builder)
|
||
ty_s: t.CChar | t.CPtr = _type_str(builder, ty)
|
||
ptr_ty_s: t.CChar | t.CPtr = _type_str(builder, ptr.Ty)
|
||
line: t.CChar | t.CPtr = pool.alloc(256)
|
||
if line is None: return None
|
||
viperlib.snprintf(line, 256, "%s = load %s, %s %s", name, ty_s, ptr_ty_s, ptr.Name)
|
||
_emit(builder, line)
|
||
return SSAValue(pool, ty, name)
|
||
|
||
|
||
def build_store(builder: IRBuilder | t.CPtr, val: Value | t.CPtr, ptr: Value | t.CPtr):
|
||
"""store <val_ty> <val>, <ptr_ty> <ptr>"""
|
||
if builder is None or val is None or ptr is None: return
|
||
pool: memhub.MemBuddy | t.CPtr = builder.Pool
|
||
val_ty_s: t.CChar | t.CPtr = _type_str(builder, val.Ty)
|
||
ptr_ty_s: t.CChar | t.CPtr = _type_str(builder, ptr.Ty)
|
||
line: t.CChar | t.CPtr = pool.alloc(256)
|
||
if line is None: return
|
||
viperlib.snprintf(line, 256, "store %s %s, %s %s", val_ty_s, val.Name, ptr_ty_s, ptr.Name)
|
||
_emit(builder, line)
|
||
|
||
|
||
# ============================================================
|
||
# 二元运算指令
|
||
# ============================================================
|
||
def build_add(builder: IRBuilder | t.CPtr, lhs: Value | t.CPtr,
|
||
rhs: Value | t.CPtr) -> Value | t.CPtr:
|
||
"""%N = add <ty> <lhs>, <rhs>"""
|
||
return _build_binop(builder, "add", lhs, rhs)
|
||
|
||
|
||
def build_sub(builder: IRBuilder | t.CPtr, lhs: Value | t.CPtr,
|
||
rhs: Value | t.CPtr) -> Value | t.CPtr:
|
||
"""%N = sub <ty> <lhs>, <rhs>"""
|
||
return _build_binop(builder, "sub", lhs, rhs)
|
||
|
||
|
||
def build_mul(builder: IRBuilder | t.CPtr, lhs: Value | t.CPtr,
|
||
rhs: Value | t.CPtr) -> Value | t.CPtr:
|
||
"""%N = mul <ty> <lhs>, <rhs>"""
|
||
return _build_binop(builder, "mul", lhs, rhs)
|
||
|
||
|
||
def build_sdiv(builder: IRBuilder | t.CPtr, lhs: Value | t.CPtr,
|
||
rhs: Value | t.CPtr) -> Value | t.CPtr:
|
||
"""%N = sdiv <ty> <lhs>, <rhs>"""
|
||
return _build_binop(builder, "sdiv", lhs, rhs)
|
||
|
||
|
||
def build_udiv(builder: IRBuilder | t.CPtr, lhs: Value | t.CPtr,
|
||
rhs: Value | t.CPtr) -> Value | t.CPtr:
|
||
"""%N = udiv <ty> <lhs>, <rhs>"""
|
||
return _build_binop(builder, "udiv", lhs, rhs)
|
||
|
||
|
||
def build_srem(builder: IRBuilder | t.CPtr, lhs: Value | t.CPtr,
|
||
rhs: Value | t.CPtr) -> Value | t.CPtr:
|
||
"""%N = srem <ty> <lhs>, <rhs>"""
|
||
return _build_binop(builder, "srem", lhs, rhs)
|
||
|
||
|
||
def build_urem(builder: IRBuilder | t.CPtr, lhs: Value | t.CPtr,
|
||
rhs: Value | t.CPtr) -> Value | t.CPtr:
|
||
"""%N = urem <ty> <lhs>, <rhs>"""
|
||
return _build_binop(builder, "urem", lhs, rhs)
|
||
|
||
|
||
def build_and(builder: IRBuilder | t.CPtr, lhs: Value | t.CPtr,
|
||
rhs: Value | t.CPtr) -> Value | t.CPtr:
|
||
"""%N = and <ty> <lhs>, <rhs>"""
|
||
return _build_binop(builder, "and", lhs, rhs)
|
||
|
||
|
||
def build_or(builder: IRBuilder | t.CPtr, lhs: Value | t.CPtr,
|
||
rhs: Value | t.CPtr) -> Value | t.CPtr:
|
||
"""%N = or <ty> <lhs>, <rhs>"""
|
||
return _build_binop(builder, "or", lhs, rhs)
|
||
|
||
|
||
def build_xor(builder: IRBuilder | t.CPtr, lhs: Value | t.CPtr,
|
||
rhs: Value | t.CPtr) -> Value | t.CPtr:
|
||
"""%N = xor <ty> <lhs>, <rhs>"""
|
||
return _build_binop(builder, "xor", lhs, rhs)
|
||
|
||
|
||
def build_shl(builder: IRBuilder | t.CPtr, lhs: Value | t.CPtr,
|
||
rhs: Value | t.CPtr) -> Value | t.CPtr:
|
||
"""%N = shl <ty> <lhs>, <rhs>"""
|
||
return _build_binop(builder, "shl", lhs, rhs)
|
||
|
||
|
||
def build_lshr(builder: IRBuilder | t.CPtr, lhs: Value | t.CPtr,
|
||
rhs: Value | t.CPtr) -> Value | t.CPtr:
|
||
"""%N = lshr <ty> <lhs>, <rhs>"""
|
||
return _build_binop(builder, "lshr", lhs, rhs)
|
||
|
||
|
||
def build_ashr(builder: IRBuilder | t.CPtr, lhs: Value | t.CPtr,
|
||
rhs: Value | t.CPtr) -> Value | t.CPtr:
|
||
"""%N = ashr <ty> <lhs>, <rhs>"""
|
||
return _build_binop(builder, "ashr", lhs, rhs)
|
||
|
||
|
||
# ============================================================
|
||
# 浮点二元运算指令
|
||
# ============================================================
|
||
def build_fadd(builder: IRBuilder | t.CPtr, lhs: Value | t.CPtr,
|
||
rhs: Value | t.CPtr) -> Value | t.CPtr:
|
||
"""%N = fadd <ty> <lhs>, <rhs>"""
|
||
return _build_binop(builder, "fadd", lhs, rhs)
|
||
|
||
|
||
def build_fsub(builder: IRBuilder | t.CPtr, lhs: Value | t.CPtr,
|
||
rhs: Value | t.CPtr) -> Value | t.CPtr:
|
||
"""%N = fsub <ty> <lhs>, <rhs>"""
|
||
return _build_binop(builder, "fsub", lhs, rhs)
|
||
|
||
|
||
def build_fmul(builder: IRBuilder | t.CPtr, lhs: Value | t.CPtr,
|
||
rhs: Value | t.CPtr) -> Value | t.CPtr:
|
||
"""%N = fmul <ty> <lhs>, <rhs>"""
|
||
return _build_binop(builder, "fmul", lhs, rhs)
|
||
|
||
|
||
def build_fdiv(builder: IRBuilder | t.CPtr, lhs: Value | t.CPtr,
|
||
rhs: Value | t.CPtr) -> Value | t.CPtr:
|
||
"""%N = fdiv <ty> <lhs>, <rhs>"""
|
||
return _build_binop(builder, "fdiv", lhs, rhs)
|
||
|
||
|
||
def build_frem(builder: IRBuilder | t.CPtr, lhs: Value | t.CPtr,
|
||
rhs: Value | t.CPtr) -> Value | t.CPtr:
|
||
"""%N = frem <ty> <lhs>, <rhs>"""
|
||
return _build_binop(builder, "frem", lhs, rhs)
|
||
|
||
|
||
def build_fneg(builder: IRBuilder | t.CPtr, val: Value | t.CPtr) -> Value | t.CPtr:
|
||
"""%N = fneg <ty> <val>"""
|
||
if builder is None or val is None: return None
|
||
pool: memhub.MemBuddy | t.CPtr = builder.Pool
|
||
name: t.CChar | t.CPtr = _alloc_ssa_name(builder)
|
||
ty_s: t.CChar | t.CPtr = _type_str(builder, val.Ty)
|
||
line: t.CChar | t.CPtr = pool.alloc(128)
|
||
if line is None: return None
|
||
viperlib.snprintf(line, 128, "%s = fneg %s %s", name, ty_s, val.Name)
|
||
_emit(builder, line)
|
||
return SSAValue(pool, val.Ty, name)
|
||
|
||
|
||
def _build_binop(builder: IRBuilder | t.CPtr, op: t.CChar | t.CPtr,
|
||
lhs: Value | t.CPtr, rhs: Value | t.CPtr) -> Value | t.CPtr:
|
||
"""二元运算通用实现"""
|
||
if builder is None or lhs is None or rhs is None: return None
|
||
pool: memhub.MemBuddy | t.CPtr = builder.Pool
|
||
name: t.CChar | t.CPtr = _alloc_ssa_name(builder)
|
||
ty_s: t.CChar | t.CPtr = _type_str(builder, lhs.Ty)
|
||
line: t.CChar | t.CPtr = pool.alloc(256)
|
||
if line is None: return None
|
||
viperlib.snprintf(line, 256, "%s = %s %s %s, %s", name, op, ty_s, lhs.Name, rhs.Name)
|
||
_emit(builder, line)
|
||
return SSAValue(pool, lhs.Ty, name)
|
||
|
||
|
||
# ============================================================
|
||
# 比较指令
|
||
# ============================================================
|
||
# ICMP 谓词常量
|
||
ICMP_EQ: t.CDefine = 0
|
||
ICMP_NE: t.CDefine = 1
|
||
ICMP_SGT: t.CDefine = 2
|
||
ICMP_SGE: t.CDefine = 3
|
||
ICMP_SLT: t.CDefine = 4
|
||
ICMP_SLE: t.CDefine = 5
|
||
ICMP_UGT: t.CDefine = 6
|
||
ICMP_UGE: t.CDefine = 7
|
||
ICMP_ULT: t.CDefine = 8
|
||
ICMP_ULE: t.CDefine = 9
|
||
|
||
# FCMP 谓词常量
|
||
FCMP_FALSE: t.CDefine = 0
|
||
FCMP_OEQ: t.CDefine = 1
|
||
FCMP_OGT: t.CDefine = 2
|
||
FCMP_OGE: t.CDefine = 3
|
||
FCMP_OLT: t.CDefine = 4
|
||
FCMP_OLE: t.CDefine = 5
|
||
FCMP_ONE: t.CDefine = 6
|
||
FCMP_ORD: t.CDefine = 7
|
||
FCMP_UNO: t.CDefine = 8
|
||
FCMP_UEQ: t.CDefine = 9
|
||
FCMP_UGT: t.CDefine = 10
|
||
FCMP_UGE: t.CDefine = 11
|
||
FCMP_ULT: t.CDefine = 12
|
||
FCMP_ULE: t.CDefine = 13
|
||
FCMP_UNE: t.CDefine = 14
|
||
FCMP_TRUE: t.CDefine = 15
|
||
|
||
|
||
def _icmp_pred_str(pred: t.CInt) -> t.CChar | t.CPtr:
|
||
if pred == ICMP_EQ: return "eq"
|
||
if pred == ICMP_NE: return "ne"
|
||
if pred == ICMP_SGT: return "sgt"
|
||
if pred == ICMP_SGE: return "sge"
|
||
if pred == ICMP_SLT: return "slt"
|
||
if pred == ICMP_SLE: return "sle"
|
||
if pred == ICMP_UGT: return "ugt"
|
||
if pred == ICMP_UGE: return "uge"
|
||
if pred == ICMP_ULT: return "ult"
|
||
if pred == ICMP_ULE: return "ule"
|
||
return "eq"
|
||
|
||
|
||
def _fcmp_pred_str(pred: t.CInt) -> t.CChar | t.CPtr:
|
||
if pred == FCMP_FALSE: return "false"
|
||
if pred == FCMP_OEQ: return "oeq"
|
||
if pred == FCMP_OGT: return "ogt"
|
||
if pred == FCMP_OGE: return "oge"
|
||
if pred == FCMP_OLT: return "olt"
|
||
if pred == FCMP_OLE: return "ole"
|
||
if pred == FCMP_ONE: return "one"
|
||
if pred == FCMP_ORD: return "ord"
|
||
if pred == FCMP_UNO: return "uno"
|
||
if pred == FCMP_UEQ: return "ueq"
|
||
if pred == FCMP_UGT: return "ugt"
|
||
if pred == FCMP_UGE: return "uge"
|
||
if pred == FCMP_ULT: return "ult"
|
||
if pred == FCMP_ULE: return "ule"
|
||
if pred == FCMP_UNE: return "une"
|
||
if pred == FCMP_TRUE: return "true"
|
||
return "oeq"
|
||
|
||
|
||
def build_icmp(builder: IRBuilder | t.CPtr, pred: t.CInt,
|
||
lhs: Value | t.CPtr, rhs: Value | t.CPtr) -> Value | t.CPtr:
|
||
"""%N = icmp <pred> <ty> <lhs>, <rhs>
|
||
|
||
返回类型为 i1 的 SSA 值
|
||
"""
|
||
if builder is None or lhs is None or rhs is None: return None
|
||
pool: memhub.MemBuddy | t.CPtr = builder.Pool
|
||
name: t.CChar | t.CPtr = _alloc_ssa_name(builder)
|
||
ty_s: t.CChar | t.CPtr = _type_str(builder, lhs.Ty)
|
||
pred_s: t.CChar | t.CPtr = _icmp_pred_str(pred)
|
||
line: t.CChar | t.CPtr = pool.alloc(256)
|
||
if line is None: return None
|
||
viperlib.snprintf(line, 256, "%s = icmp %s %s %s, %s", name, pred_s, ty_s, lhs.Name, rhs.Name)
|
||
_emit(builder, line)
|
||
|
||
# 结果类型是 i1
|
||
i1_ty: LLVMType | t.CPtr = pool.alloc(LLVMType.__sizeof__())
|
||
if i1_ty is not None:
|
||
string.memset(i1_ty, 0, LLVMType.__sizeof__())
|
||
c.DerefAs(i1_ty, LLVMType.Int(1))
|
||
return SSAValue(pool, i1_ty, name)
|
||
|
||
|
||
def build_fcmp(builder: IRBuilder | t.CPtr, pred: t.CInt,
|
||
lhs: Value | t.CPtr, rhs: Value | t.CPtr) -> Value | t.CPtr:
|
||
"""%N = fcmp <pred> <ty> <lhs>, <rhs>
|
||
|
||
返回类型为 i1 的 SSA 值
|
||
"""
|
||
if builder is None or lhs is None or rhs is None: return None
|
||
pool: memhub.MemBuddy | t.CPtr = builder.Pool
|
||
name: t.CChar | t.CPtr = _alloc_ssa_name(builder)
|
||
ty_s: t.CChar | t.CPtr = _type_str(builder, lhs.Ty)
|
||
pred_s: t.CChar | t.CPtr = _fcmp_pred_str(pred)
|
||
line: t.CChar | t.CPtr = pool.alloc(256)
|
||
if line is None: return None
|
||
viperlib.snprintf(line, 256, "%s = fcmp %s %s %s, %s", name, pred_s, ty_s, lhs.Name, rhs.Name)
|
||
_emit(builder, line)
|
||
|
||
# 结果类型是 i1
|
||
i1_ty: LLVMType | t.CPtr = pool.alloc(LLVMType.__sizeof__())
|
||
if i1_ty is not None:
|
||
string.memset(i1_ty, 0, LLVMType.__sizeof__())
|
||
c.DerefAs(i1_ty, LLVMType.Int(1))
|
||
return SSAValue(pool, i1_ty, name)
|
||
|
||
|
||
# ============================================================
|
||
# 终止指令
|
||
# ============================================================
|
||
def build_br(builder: IRBuilder | t.CPtr, target: BasicBlock | t.CPtr):
|
||
"""br label %<target>"""
|
||
if builder is None or target is None: return
|
||
pool: memhub.MemBuddy | t.CPtr = builder.Pool
|
||
line: t.CChar | t.CPtr = pool.alloc(64)
|
||
if line is None: return
|
||
viperlib.snprintf(line, 64, "br label %%%s", target.Name)
|
||
_emit(builder, line)
|
||
_mark_terminated(builder)
|
||
|
||
|
||
def build_cond_br(builder: IRBuilder | t.CPtr, cond: Value | t.CPtr,
|
||
then_blk: BasicBlock | t.CPtr, else_blk: BasicBlock | t.CPtr):
|
||
"""br i1 <cond>, label %<then>, label %<else_>"""
|
||
if builder is None or cond is None or then_blk is None or else_blk is None: return
|
||
pool: memhub.MemBuddy | t.CPtr = builder.Pool
|
||
line: t.CChar | t.CPtr = pool.alloc(128)
|
||
if line is None: return
|
||
viperlib.snprintf(line, 128, "br i1 %s, label %%%s, label %%%s",
|
||
cond.Name, then_blk.Name, else_blk.Name)
|
||
_emit(builder, line)
|
||
_mark_terminated(builder)
|
||
|
||
|
||
def build_ret(builder: IRBuilder | t.CPtr, val: Value | t.CPtr):
|
||
"""ret <ty> <val>"""
|
||
if builder is None or val is None: return
|
||
pool: memhub.MemBuddy | t.CPtr = builder.Pool
|
||
ty_s: t.CChar | t.CPtr = _type_str(builder, val.Ty)
|
||
line: t.CChar | t.CPtr = pool.alloc(128)
|
||
if line is None: return
|
||
viperlib.snprintf(line, 128, "ret %s %s", ty_s, val.Name)
|
||
_emit(builder, line)
|
||
_mark_terminated(builder)
|
||
|
||
|
||
def build_ret_void(builder: IRBuilder | t.CPtr):
|
||
"""ret void"""
|
||
if builder is None: return
|
||
pool: memhub.MemBuddy | t.CPtr = builder.Pool
|
||
line: t.CChar | t.CPtr = pool.alloc(16)
|
||
if line is None: return
|
||
string.strcpy(line, "ret void")
|
||
_emit(builder, line)
|
||
_mark_terminated(builder)
|
||
|
||
|
||
# ============================================================
|
||
# 调用指令
|
||
# ============================================================
|
||
def build_call(builder: IRBuilder | t.CPtr, callee: t.CChar | t.CPtr,
|
||
args: Value | t.CPtr, arg_count: t.CInt,
|
||
ret_ty: LLVMType | t.CPtr,
|
||
is_variadic: t.CInt = 0) -> Value | t.CPtr:
|
||
"""%N = call <ret_ty> @<callee>(<args>)
|
||
|
||
args 是 Value 链表头,arg_count 是参数数量。
|
||
若 ret_ty 是 void,不分配 SSA 名(使用 call 而非 %N = call)。
|
||
is_variadic=1 时发射函数类型签名(如 i32 (i8*, ...) @printf)。
|
||
"""
|
||
if builder is None: return None
|
||
pool: memhub.MemBuddy | t.CPtr = builder.Pool
|
||
|
||
# 判断返回类型是否为 void
|
||
is_void: t.CInt = 0
|
||
match ret_ty:
|
||
case LLVMType.Void():
|
||
is_void = 1
|
||
case _:
|
||
is_void = 0
|
||
|
||
name: t.CChar | t.CPtr = None
|
||
if is_void == 0:
|
||
name = _alloc_ssa_name(builder)
|
||
|
||
ret_ty_s: t.CChar | t.CPtr = _type_str(builder, ret_ty)
|
||
|
||
# 构建参数列表文本 + 变参函数类型签名
|
||
args_buf: t.CChar | t.CPtr = pool.alloc(1024)
|
||
if args_buf is None: return None
|
||
args_buf[0] = '\0'
|
||
func_ty_buf: t.CChar | t.CPtr = pool.alloc(1024)
|
||
if func_ty_buf is None: return None
|
||
func_ty_buf[0] = '\0'
|
||
cur: Value | t.CPtr = args
|
||
first: t.CInt = 1
|
||
while cur is not None:
|
||
if first == 0:
|
||
_append_cstr(args_buf, 1024, ", ")
|
||
_append_cstr(func_ty_buf, 1024, ", ")
|
||
arg_ty_s: t.CChar | t.CPtr = _type_str(builder, cur.Ty)
|
||
_append_cstr(args_buf, 1024, arg_ty_s)
|
||
_append_cstr(args_buf, 1024, " ")
|
||
if cur.Name is not None:
|
||
_append_cstr(args_buf, 1024, cur.Name)
|
||
_append_cstr(func_ty_buf, 1024, arg_ty_s)
|
||
cur = cur.Next
|
||
first = 0
|
||
if is_variadic == 1:
|
||
if first == 0:
|
||
_append_cstr(func_ty_buf, 1024, ", ")
|
||
_append_cstr(func_ty_buf, 1024, "...")
|
||
|
||
# 构造带引号的 callee 名字(SHA1 前缀名含 '.' 或以数字开头需要加引号)
|
||
callee_buf: t.CChar | t.CPtr = pool.alloc(128)
|
||
if callee_buf is None: return None
|
||
callee_buf[0] = '\0'
|
||
if _ll_name_needs_quote(callee) != 0:
|
||
_append_cstr(callee_buf, 128, "\"")
|
||
_append_cstr(callee_buf, 128, callee)
|
||
_append_cstr(callee_buf, 128, "\"")
|
||
else:
|
||
_append_cstr(callee_buf, 128, callee)
|
||
|
||
line: t.CChar | t.CPtr = pool.alloc(2048)
|
||
if line is None: return None
|
||
if is_variadic == 1:
|
||
if is_void == 1:
|
||
viperlib.snprintf(line, 2048, "call %s (%s) @%s(%s)", ret_ty_s, func_ty_buf, callee_buf, args_buf)
|
||
else:
|
||
viperlib.snprintf(line, 2048, "%s = call %s (%s) @%s(%s)", name, ret_ty_s, func_ty_buf, callee_buf, args_buf)
|
||
else:
|
||
if is_void == 1:
|
||
viperlib.snprintf(line, 2048, "call %s @%s(%s)", ret_ty_s, callee_buf, args_buf)
|
||
else:
|
||
viperlib.snprintf(line, 2048, "%s = call %s @%s(%s)", name, ret_ty_s, callee_buf, args_buf)
|
||
_emit(builder, line)
|
||
|
||
if is_void == 1:
|
||
return None
|
||
return SSAValue(pool, ret_ty, name)
|
||
|
||
|
||
# ============================================================
|
||
# 间接调用指令: call <ret_ty> %callee(<args>)
|
||
#
|
||
# callee_val 是函数指针 SSA 值(必须已是函数指针类型,如 i32(i8*)*)
|
||
# ============================================================
|
||
def build_call_indirect(builder: IRBuilder | t.CPtr, callee_val: Value | t.CPtr,
|
||
args: Value | t.CPtr, arg_count: t.CInt,
|
||
ret_ty: LLVMType | t.CPtr) -> Value | t.CPtr:
|
||
"""%N = call <ret_ty> %callee(<args>)
|
||
|
||
间接调用:callee_val 是函数指针 SSA 值。
|
||
"""
|
||
if builder is None or callee_val is None: return None
|
||
pool: memhub.MemBuddy | t.CPtr = builder.Pool
|
||
|
||
is_void: t.CInt = 0
|
||
match ret_ty:
|
||
case LLVMType.Void():
|
||
is_void = 1
|
||
case _:
|
||
is_void = 0
|
||
|
||
name: t.CChar | t.CPtr = None
|
||
if is_void == 0:
|
||
name = _alloc_ssa_name(builder)
|
||
|
||
ret_ty_s: t.CChar | t.CPtr = _type_str(builder, ret_ty)
|
||
|
||
# 构建参数列表文本
|
||
args_buf: t.CChar | t.CPtr = pool.alloc(1024)
|
||
if args_buf is None: return None
|
||
args_buf[0] = '\0'
|
||
cur: Value | t.CPtr = args
|
||
first: t.CInt = 1
|
||
while cur is not None:
|
||
if first == 0:
|
||
_append_cstr(args_buf, 1024, ", ")
|
||
arg_ty_s: t.CChar | t.CPtr = _type_str(builder, cur.Ty)
|
||
_append_cstr(args_buf, 1024, arg_ty_s)
|
||
_append_cstr(args_buf, 1024, " ")
|
||
if cur.Name is not None:
|
||
_append_cstr(args_buf, 1024, cur.Name)
|
||
cur = cur.Next
|
||
first = 0
|
||
|
||
line: t.CChar | t.CPtr = pool.alloc(2048)
|
||
if line is None: return None
|
||
if is_void == 1:
|
||
viperlib.snprintf(line, 2048, "call %s %s(%s)", ret_ty_s, callee_val.Name, args_buf)
|
||
else:
|
||
viperlib.snprintf(line, 2048, "%s = call %s %s(%s)", name, ret_ty_s, callee_val.Name, args_buf)
|
||
_emit(builder, line)
|
||
|
||
if is_void == 1:
|
||
return None
|
||
return SSAValue(pool, ret_ty, name)
|
||
|
||
|
||
# ============================================================
|
||
# 类型转换指令
|
||
# ============================================================
|
||
def build_bitcast(builder: IRBuilder | t.CPtr, val: Value | t.CPtr,
|
||
to_ty: LLVMType | t.CPtr) -> Value | t.CPtr:
|
||
"""%N = bitcast <from_ty> <val> to <to_ty>"""
|
||
if builder is None or val is None:
|
||
return None
|
||
pool: memhub.MemBuddy | t.CPtr = builder.Pool
|
||
name: t.CChar | t.CPtr = _alloc_ssa_name(builder)
|
||
from_ty_s: t.CChar | t.CPtr = _type_str(builder, val.Ty)
|
||
to_ty_s: t.CChar | t.CPtr = _type_str(builder, to_ty)
|
||
line: t.CChar | t.CPtr = pool.alloc(256)
|
||
if line is None: return None
|
||
if val.Name is None:
|
||
return None
|
||
viperlib.snprintf(line, 256, "%s = bitcast %s %s to %s", name, from_ty_s, val.Name, to_ty_s)
|
||
_emit(builder, line)
|
||
ret: Value | t.CPtr = SSAValue(pool, to_ty, name)
|
||
return ret
|
||
|
||
|
||
def build_sext(builder: IRBuilder | t.CPtr, val: Value | t.CPtr,
|
||
to_ty: LLVMType | t.CPtr) -> Value | t.CPtr:
|
||
"""%N = sext <from_ty> <val> to <to_ty>"""
|
||
if builder is None or val is None: return None
|
||
pool: memhub.MemBuddy | t.CPtr = builder.Pool
|
||
name: t.CChar | t.CPtr = _alloc_ssa_name(builder)
|
||
from_ty_s: t.CChar | t.CPtr = _type_str(builder, val.Ty)
|
||
to_ty_s: t.CChar | t.CPtr = _type_str(builder, to_ty)
|
||
line: t.CChar | t.CPtr = pool.alloc(256)
|
||
if line is None: return None
|
||
viperlib.snprintf(line, 256, "%s = sext %s %s to %s", name, from_ty_s, val.Name, to_ty_s)
|
||
_emit(builder, line)
|
||
return SSAValue(pool, to_ty, name)
|
||
|
||
|
||
def build_trunc(builder: IRBuilder | t.CPtr, val: Value | t.CPtr,
|
||
to_ty: LLVMType | t.CPtr) -> Value | t.CPtr:
|
||
"""%N = trunc <from_ty> <val> to <to_ty>"""
|
||
if builder is None or val is None: return None
|
||
pool: memhub.MemBuddy | t.CPtr = builder.Pool
|
||
name: t.CChar | t.CPtr = _alloc_ssa_name(builder)
|
||
from_ty_s: t.CChar | t.CPtr = _type_str(builder, val.Ty)
|
||
to_ty_s: t.CChar | t.CPtr = _type_str(builder, to_ty)
|
||
line: t.CChar | t.CPtr = pool.alloc(256)
|
||
if line is None: return None
|
||
viperlib.snprintf(line, 256, "%s = trunc %s %s to %s", name, from_ty_s, val.Name, to_ty_s)
|
||
_emit(builder, line)
|
||
return SSAValue(pool, to_ty, name)
|
||
|
||
|
||
def build_zext(builder: IRBuilder | t.CPtr, val: Value | t.CPtr,
|
||
to_ty: LLVMType | t.CPtr) -> Value | t.CPtr:
|
||
"""%N = zext <from_ty> <val> to <to_ty>"""
|
||
if builder is None or val is None: return None
|
||
pool: memhub.MemBuddy | t.CPtr = builder.Pool
|
||
name: t.CChar | t.CPtr = _alloc_ssa_name(builder)
|
||
from_ty_s: t.CChar | t.CPtr = _type_str(builder, val.Ty)
|
||
to_ty_s: t.CChar | t.CPtr = _type_str(builder, to_ty)
|
||
line: t.CChar | t.CPtr = pool.alloc(256)
|
||
if line is None: return None
|
||
viperlib.snprintf(line, 256, "%s = zext %s %s to %s", name, from_ty_s, val.Name, to_ty_s)
|
||
_emit(builder, line)
|
||
return SSAValue(pool, to_ty, name)
|
||
|
||
|
||
def build_ptrtoint(builder: IRBuilder | t.CPtr, val: Value | t.CPtr,
|
||
to_ty: LLVMType | t.CPtr) -> Value | t.CPtr:
|
||
"""%N = ptrtoint <from_ty> <val> to <to_ty>"""
|
||
if builder is None or val is None: return None
|
||
pool: memhub.MemBuddy | t.CPtr = builder.Pool
|
||
name: t.CChar | t.CPtr = _alloc_ssa_name(builder)
|
||
from_ty_s: t.CChar | t.CPtr = _type_str(builder, val.Ty)
|
||
to_ty_s: t.CChar | t.CPtr = _type_str(builder, to_ty)
|
||
line: t.CChar | t.CPtr = pool.alloc(256)
|
||
if line is None: return None
|
||
viperlib.snprintf(line, 256, "%s = ptrtoint %s %s to %s", name, from_ty_s, val.Name, to_ty_s)
|
||
_emit(builder, line)
|
||
return SSAValue(pool, to_ty, name)
|
||
|
||
|
||
def build_inttoptr(builder: IRBuilder | t.CPtr, val: Value | t.CPtr,
|
||
to_ty: LLVMType | t.CPtr) -> Value | t.CPtr:
|
||
"""%N = inttoptr <from_ty> <val> to <to_ty>"""
|
||
if builder is None or val is None: return None
|
||
pool: memhub.MemBuddy | t.CPtr = builder.Pool
|
||
name: t.CChar | t.CPtr = _alloc_ssa_name(builder)
|
||
from_ty_s: t.CChar | t.CPtr = _type_str(builder, val.Ty)
|
||
to_ty_s: t.CChar | t.CPtr = _type_str(builder, to_ty)
|
||
line: t.CChar | t.CPtr = pool.alloc(256)
|
||
if line is None: return None
|
||
viperlib.snprintf(line, 256, "%s = inttoptr %s %s to %s", name, from_ty_s, val.Name, to_ty_s)
|
||
_emit(builder, line)
|
||
return SSAValue(pool, to_ty, name)
|
||
|
||
|
||
# ============================================================
|
||
# 浮点转换指令
|
||
# ============================================================
|
||
def build_fpext(builder: IRBuilder | t.CPtr, val: Value | t.CPtr,
|
||
to_ty: LLVMType | t.CPtr) -> Value | t.CPtr:
|
||
"""%N = fpext <from_ty> <val> to <to_ty>"""
|
||
if builder is None or val is None: return None
|
||
pool: memhub.MemBuddy | t.CPtr = builder.Pool
|
||
name: t.CChar | t.CPtr = _alloc_ssa_name(builder)
|
||
from_ty_s: t.CChar | t.CPtr = _type_str(builder, val.Ty)
|
||
to_ty_s: t.CChar | t.CPtr = _type_str(builder, to_ty)
|
||
line: t.CChar | t.CPtr = pool.alloc(256)
|
||
if line is None: return None
|
||
viperlib.snprintf(line, 256, "%s = fpext %s %s to %s", name, from_ty_s, val.Name, to_ty_s)
|
||
_emit(builder, line)
|
||
return SSAValue(pool, to_ty, name)
|
||
|
||
|
||
def build_fptrunc(builder: IRBuilder | t.CPtr, val: Value | t.CPtr,
|
||
to_ty: LLVMType | t.CPtr) -> Value | t.CPtr:
|
||
"""%N = fptrunc <from_ty> <val> to <to_ty>"""
|
||
if builder is None or val is None: return None
|
||
pool: memhub.MemBuddy | t.CPtr = builder.Pool
|
||
name: t.CChar | t.CPtr = _alloc_ssa_name(builder)
|
||
from_ty_s: t.CChar | t.CPtr = _type_str(builder, val.Ty)
|
||
to_ty_s: t.CChar | t.CPtr = _type_str(builder, to_ty)
|
||
line: t.CChar | t.CPtr = pool.alloc(256)
|
||
if line is None: return None
|
||
viperlib.snprintf(line, 256, "%s = fptrunc %s %s to %s", name, from_ty_s, val.Name, to_ty_s)
|
||
_emit(builder, line)
|
||
return SSAValue(pool, to_ty, name)
|
||
|
||
|
||
def build_fp2si(builder: IRBuilder | t.CPtr, val: Value | t.CPtr,
|
||
to_ty: LLVMType | t.CPtr) -> Value | t.CPtr:
|
||
"""%N = fptosi <from_ty> <val> to <to_ty>"""
|
||
if builder is None or val is None: return None
|
||
pool: memhub.MemBuddy | t.CPtr = builder.Pool
|
||
name: t.CChar | t.CPtr = _alloc_ssa_name(builder)
|
||
from_ty_s: t.CChar | t.CPtr = _type_str(builder, val.Ty)
|
||
to_ty_s: t.CChar | t.CPtr = _type_str(builder, to_ty)
|
||
line: t.CChar | t.CPtr = pool.alloc(256)
|
||
if line is None: return None
|
||
viperlib.snprintf(line, 256, "%s = fptosi %s %s to %s", name, from_ty_s, val.Name, to_ty_s)
|
||
_emit(builder, line)
|
||
return SSAValue(pool, to_ty, name)
|
||
|
||
|
||
def build_si2fp(builder: IRBuilder | t.CPtr, val: Value | t.CPtr,
|
||
to_ty: LLVMType | t.CPtr) -> Value | t.CPtr:
|
||
"""%N = sitofp <from_ty> <val> to <to_ty>"""
|
||
if builder is None or val is None: return None
|
||
pool: memhub.MemBuddy | t.CPtr = builder.Pool
|
||
name: t.CChar | t.CPtr = _alloc_ssa_name(builder)
|
||
from_ty_s: t.CChar | t.CPtr = _type_str(builder, val.Ty)
|
||
to_ty_s: t.CChar | t.CPtr = _type_str(builder, to_ty)
|
||
line: t.CChar | t.CPtr = pool.alloc(256)
|
||
if line is None: return None
|
||
viperlib.snprintf(line, 256, "%s = sitofp %s %s to %s", name, from_ty_s, val.Name, to_ty_s)
|
||
_emit(builder, line)
|
||
return SSAValue(pool, to_ty, name)
|
||
|
||
|
||
def build_fp2ui(builder: IRBuilder | t.CPtr, val: Value | t.CPtr,
|
||
to_ty: LLVMType | t.CPtr) -> Value | t.CPtr:
|
||
"""%N = fptoui <from_ty> <val> to <to_ty>"""
|
||
if builder is None or val is None: return None
|
||
pool: memhub.MemBuddy | t.CPtr = builder.Pool
|
||
name: t.CChar | t.CPtr = _alloc_ssa_name(builder)
|
||
from_ty_s: t.CChar | t.CPtr = _type_str(builder, val.Ty)
|
||
to_ty_s: t.CChar | t.CPtr = _type_str(builder, to_ty)
|
||
line: t.CChar | t.CPtr = pool.alloc(256)
|
||
if line is None: return None
|
||
viperlib.snprintf(line, 256, "%s = fptoui %s %s to %s", name, from_ty_s, val.Name, to_ty_s)
|
||
_emit(builder, line)
|
||
return SSAValue(pool, to_ty, name)
|
||
|
||
|
||
def build_ui2fp(builder: IRBuilder | t.CPtr, val: Value | t.CPtr,
|
||
to_ty: LLVMType | t.CPtr) -> Value | t.CPtr:
|
||
"""%N = uitofp <from_ty> <val> to <to_ty>"""
|
||
if builder is None or val is None: return None
|
||
pool: memhub.MemBuddy | t.CPtr = builder.Pool
|
||
name: t.CChar | t.CPtr = _alloc_ssa_name(builder)
|
||
from_ty_s: t.CChar | t.CPtr = _type_str(builder, val.Ty)
|
||
to_ty_s: t.CChar | t.CPtr = _type_str(builder, to_ty)
|
||
line: t.CChar | t.CPtr = pool.alloc(256)
|
||
if line is None: return None
|
||
viperlib.snprintf(line, 256, "%s = uitofp %s %s to %s", name, from_ty_s, val.Name, to_ty_s)
|
||
_emit(builder, line)
|
||
return SSAValue(pool, to_ty, name)
|
||
|
||
|
||
# ============================================================
|
||
# GEP 指令
|
||
# ============================================================
|
||
def build_gep(builder: IRBuilder | t.CPtr, elem_ty: LLVMType | t.CPtr,
|
||
ptr: Value | t.CPtr, idx: Value | t.CPtr) -> Value | t.CPtr:
|
||
"""%N = getelementptr <elem_ty>, <ptr_ty> <ptr>, <idx_ty> <idx>"""
|
||
if builder is None or ptr is None or idx is None: return None
|
||
pool: memhub.MemBuddy | t.CPtr = builder.Pool
|
||
name: t.CChar | t.CPtr = _alloc_ssa_name(builder)
|
||
elem_ty_s: t.CChar | t.CPtr = _type_str(builder, elem_ty)
|
||
ptr_ty_s: t.CChar | t.CPtr = _type_str(builder, ptr.Ty)
|
||
idx_ty_s: t.CChar | t.CPtr = _type_str(builder, idx.Ty)
|
||
line: t.CChar | t.CPtr = pool.alloc(256)
|
||
if line is None: return None
|
||
viperlib.snprintf(line, 256, "%s = getelementptr %s, %s %s, %s %s",
|
||
name, elem_ty_s, ptr_ty_s, ptr.Name, idx_ty_s, idx.Name)
|
||
_emit(builder, line)
|
||
|
||
# GEP 结果类型是 elem_ty*
|
||
result_ty: LLVMType | t.CPtr = pool.alloc(LLVMType.__sizeof__())
|
||
if result_ty is not None:
|
||
string.memset(result_ty, 0, LLVMType.__sizeof__())
|
||
c.DerefAs(result_ty, LLVMType.Ptr(elem_ty))
|
||
return SSAValue(pool, result_ty, name)
|
||
|
||
|
||
# ============================================================
|
||
# build_gep_array — 数组双索引 GEP: getelementptr [N x ty], [N x ty]* %ptr, i32 0, i32 %idx
|
||
# ============================================================
|
||
def build_gep_array(builder: IRBuilder | t.CPtr, array_ty: LLVMType | t.CPtr,
|
||
elem_ty: LLVMType | t.CPtr,
|
||
ptr: Value | t.CPtr, idx: Value | t.CPtr) -> Value | t.CPtr:
|
||
"""%N = getelementptr [N x elem_ty], [N x elem_ty]* %ptr, i32 0, i32 %idx
|
||
|
||
结果类型是 elem_ty*
|
||
"""
|
||
if builder is None or ptr is None or idx is None: return None
|
||
pool: memhub.MemBuddy | t.CPtr = builder.Pool
|
||
name: t.CChar | t.CPtr = _alloc_ssa_name(builder)
|
||
array_ty_s: t.CChar | t.CPtr = _type_str(builder, array_ty)
|
||
ptr_ty_s: t.CChar | t.CPtr = _type_str(builder, ptr.Ty)
|
||
idx_ty_s: t.CChar | t.CPtr = _type_str(builder, idx.Ty)
|
||
line: t.CChar | t.CPtr = pool.alloc(256)
|
||
if line is None: return None
|
||
viperlib.snprintf(line, 256, "%s = getelementptr %s, %s %s, i32 0, %s %s",
|
||
name, array_ty_s, ptr_ty_s, ptr.Name, idx_ty_s, idx.Name)
|
||
_emit(builder, line)
|
||
|
||
# GEP 结果类型是 elem_ty*
|
||
result_ty: LLVMType | t.CPtr = pool.alloc(LLVMType.__sizeof__())
|
||
if result_ty is not None:
|
||
string.memset(result_ty, 0, LLVMType.__sizeof__())
|
||
c.DerefAs(result_ty, LLVMType.Ptr(elem_ty))
|
||
return SSAValue(pool, result_ty, name)
|
||
|
||
|
||
# ============================================================
|
||
# build_gep_struct — 结构体字段 GEP: getelementptr struct_ty, struct_ty* %ptr, i32 0, i32 %field_idx
|
||
# ============================================================
|
||
def build_gep_struct(builder: IRBuilder | t.CPtr, struct_ty: LLVMType | t.CPtr,
|
||
field_ty: LLVMType | t.CPtr,
|
||
ptr: Value | t.CPtr, field_idx: t.CInt) -> Value | t.CPtr:
|
||
"""%N = getelementptr struct_ty, struct_ty* %ptr, i32 0, i32 %field_idx
|
||
|
||
结果类型是 field_ty*
|
||
"""
|
||
if builder is None or ptr is None: return None
|
||
pool: memhub.MemBuddy | t.CPtr = builder.Pool
|
||
name: t.CChar | t.CPtr = _alloc_ssa_name(builder)
|
||
struct_ty_s: t.CChar | t.CPtr = _type_str(builder, struct_ty)
|
||
ptr_ty_s: t.CChar | t.CPtr = _type_str(builder, ptr.Ty)
|
||
line: t.CChar | t.CPtr = pool.alloc(2048)
|
||
if line is None:
|
||
stdio.printf("[BGS] line alloc None\n")
|
||
stdio.fflush(0)
|
||
return None
|
||
viperlib.snprintf(line, 2048, "%s = getelementptr %s, %s %s, i32 0, i32 %d",
|
||
name, struct_ty_s, ptr_ty_s, ptr.Name, field_idx)
|
||
_emit(builder, line)
|
||
|
||
# GEP 结果类型是 field_ty*
|
||
result_ty: LLVMType | t.CPtr = pool.alloc(LLVMType.__sizeof__())
|
||
if result_ty is None:
|
||
stdio.printf("[BGS] result_ty alloc None\n")
|
||
stdio.fflush(0)
|
||
else:
|
||
string.memset(result_ty, 0, LLVMType.__sizeof__())
|
||
c.DerefAs(result_ty, LLVMType.Ptr(field_ty))
|
||
rv: Value | t.CPtr = SSAValue(pool, result_ty, name)
|
||
if rv is None:
|
||
stdio.printf("[BGS] SSAValue None\n")
|
||
stdio.fflush(0)
|
||
return rv
|
||
|
||
|
||
# ============================================================
|
||
# PhiIncoming: phi 节点的入边 (value, block) 对
|
||
# 继承 GSListNode[PhiIncoming] 获取强类型 Next
|
||
#
|
||
# 注意: 必须加 @t.NoVTable(理由见 __function.py 的 Line 注释)。
|
||
# ============================================================
|
||
@t.NoVTable
|
||
class PhiIncoming(GSListNode[PhiIncoming]):
|
||
Val: Value | t.CPtr
|
||
Block: BasicBlock | t.CPtr
|
||
|
||
|
||
# PhiIncoming 硬编码大小: Next(8) + Val(8) + Block(8) = 24 字节
|
||
PHIINC_SIZE: t.CDefine = 24
|
||
|
||
def new_phi_incoming(pool: memhub.MemBuddy | t.CPtr,
|
||
val: Value | t.CPtr, block: BasicBlock | t.CPtr) -> PhiIncoming | t.CPtr:
|
||
ptr: PhiIncoming | t.CPtr = pool.alloc(PHIINC_SIZE)
|
||
if ptr is None: return None
|
||
string.memset(ptr, 0, PHIINC_SIZE)
|
||
ptr.Val = val
|
||
ptr.Block = block
|
||
return ptr
|
||
|
||
|
||
# ============================================================
|
||
# Phi 指令
|
||
# ============================================================
|
||
def build_phi(builder: IRBuilder | t.CPtr, ty: LLVMType | t.CPtr,
|
||
incoming_head: PhiIncoming | t.CPtr, count: t.CInt) -> Value | t.CPtr:
|
||
"""%N = phi <ty> [val1, %blk1], [val2, %blk2], ...
|
||
|
||
incoming_head 是 PhiIncoming 链表头,count 是入边数量。
|
||
"""
|
||
if builder is None: return None
|
||
pool: memhub.MemBuddy | t.CPtr = builder.Pool
|
||
name: t.CChar | t.CPtr = _alloc_ssa_name(builder)
|
||
ty_s: t.CChar | t.CPtr = _type_str(builder, ty)
|
||
|
||
# 构建入边列表文本: [val, %blk], [val, %blk], ...
|
||
# 入边可能很多(如 30+ 个 or 链的 bool.merge),需要大缓冲区
|
||
parts: t.CChar | t.CPtr = pool.alloc(4096)
|
||
if parts is None: return None
|
||
parts[0] = '\0'
|
||
cur: PhiIncoming | t.CPtr = incoming_head
|
||
first: t.CInt = 1
|
||
while cur is not None:
|
||
if first == 0:
|
||
_append_cstr(parts, 4096, ", ")
|
||
_append_cstr(parts, 4096, "[")
|
||
# 使用中间变量避免链式结构体成员访问被编译器丢弃
|
||
inc_val: Value | t.CPtr = cur.Val
|
||
if inc_val is not None:
|
||
inc_val_name: t.CChar | t.CPtr = inc_val.Name
|
||
if inc_val_name is not None:
|
||
_append_cstr(parts, 4096, inc_val_name)
|
||
_append_cstr(parts, 4096, ", %")
|
||
inc_blk: BasicBlock | t.CPtr = cur.Block
|
||
if inc_blk is not None:
|
||
inc_blk_name: t.CChar | t.CPtr = inc_blk.Name
|
||
if inc_blk_name is not None:
|
||
_append_cstr(parts, 4096, inc_blk_name)
|
||
_append_cstr(parts, 4096, "]")
|
||
cur = cur.Next
|
||
first = 0
|
||
|
||
line: t.CChar | t.CPtr = pool.alloc(8192)
|
||
if line is None: return None
|
||
viperlib.snprintf(line, 8192, "%s = phi %s %s", name, ty_s, parts)
|
||
_emit(builder, line)
|
||
return SSAValue(pool, ty, name)
|
||
|
||
|
||
# ============================================================
|
||
# SwitchCase: switch 指令的 case 分支
|
||
#
|
||
# 注意: 必须加 @t.NoVTable(理由见 __function.py 的 Line 注释)。
|
||
# ============================================================
|
||
@t.NoVTable
|
||
class SwitchCase(GSListNode[SwitchCase]):
|
||
CaseVal: Value | t.CPtr
|
||
Block: BasicBlock | t.CPtr
|
||
|
||
|
||
# SwitchCase 硬编码大小: Next(8) + CaseVal(8) + Block(8) = 24 字节
|
||
SWCASE_SIZE: t.CDefine = 24
|
||
|
||
def new_switch_case(pool: memhub.MemBuddy | t.CPtr,
|
||
case_val: Value | t.CPtr, block: BasicBlock | t.CPtr) -> SwitchCase | t.CPtr:
|
||
ptr: SwitchCase | t.CPtr = pool.alloc(SWCASE_SIZE)
|
||
if ptr is None: return None
|
||
string.memset(ptr, 0, SWCASE_SIZE)
|
||
ptr.CaseVal = case_val
|
||
ptr.Block = block
|
||
return ptr
|
||
|
||
|
||
# ============================================================
|
||
# Switch 指令
|
||
# ============================================================
|
||
def build_switch(builder: IRBuilder | t.CPtr, val: Value | t.CPtr,
|
||
default_blk: BasicBlock | t.CPtr,
|
||
cases_head: SwitchCase | t.CPtr, case_count: t.CInt):
|
||
"""switch <ty> <val>, label %<default> [<case_val>, label %<blk> ...]"""
|
||
if builder is None or val is None or default_blk is None: return
|
||
pool: memhub.MemBuddy | t.CPtr = builder.Pool
|
||
ty_s: t.CChar | t.CPtr = _type_str(builder, val.Ty)
|
||
|
||
# 构建主体: switch <ty> <val>, label %default
|
||
line: t.CChar | t.CPtr = pool.alloc(512)
|
||
if line is None: return
|
||
viperlib.snprintf(line, 512, "switch %s %s, label %%%s",
|
||
ty_s, val.Name, default_blk.Name)
|
||
_append_cstr(line, 512, " [")
|
||
_append_cstr(line, 512, "\n")
|
||
|
||
# 遍历 case 列表
|
||
cur: SwitchCase | t.CPtr = cases_head
|
||
case_ty_s: t.CChar | t.CPtr = _type_str(builder, val.Ty)
|
||
while cur is not None:
|
||
case_line: t.CChar | t.CPtr = pool.alloc(128)
|
||
if case_line is not None:
|
||
# 使用中间变量避免链式结构体成员访问被编译器丢弃
|
||
cv: Value | t.CPtr = cur.CaseVal
|
||
cb: BasicBlock | t.CPtr = cur.Block
|
||
if cv is not None and cb is not None:
|
||
cv_name: t.CChar | t.CPtr = cv.Name
|
||
cb_name: t.CChar | t.CPtr = cb.Name
|
||
if cv_name is not None and cb_name is not None:
|
||
viperlib.snprintf(case_line, 128, " %s %s, label %%%s\n",
|
||
case_ty_s, cv_name, cb_name)
|
||
_append_cstr(line, 512, case_line)
|
||
cur = cur.Next
|
||
|
||
_append_cstr(line, 512, "]")
|
||
_emit(builder, line)
|
||
_mark_terminated(builder)
|
||
|
||
|
||
# ============================================================
|
||
# Select 指令
|
||
# ============================================================
|
||
def build_select(builder: IRBuilder | t.CPtr, cond: Value | t.CPtr,
|
||
true_val: Value | t.CPtr, false_val: Value | t.CPtr) -> Value | t.CPtr:
|
||
"""%N = select i1 <cond>, <ty> <true_val>, <ty> <false_val>"""
|
||
if builder is None or cond is None or true_val is None or false_val is None: return None
|
||
pool: memhub.MemBuddy | t.CPtr = builder.Pool
|
||
name: t.CChar | t.CPtr = _alloc_ssa_name(builder)
|
||
ty_s: t.CChar | t.CPtr = _type_str(builder, true_val.Ty)
|
||
line: t.CChar | t.CPtr = pool.alloc(256)
|
||
if line is None: return None
|
||
viperlib.snprintf(line, 256, "%s = select i1 %s, %s %s, %s %s",
|
||
name, cond.Name, ty_s, true_val.Name, ty_s, false_val.Name)
|
||
_emit(builder, line)
|
||
return SSAValue(pool, true_val.Ty, name)
|
||
|
||
|
||
# ============================================================
|
||
# Unreachable 指令
|
||
# ============================================================
|
||
def build_unreachable(builder: IRBuilder | t.CPtr):
|
||
"""unreachable"""
|
||
if builder is None: return
|
||
pool: memhub.MemBuddy | t.CPtr = builder.Pool
|
||
line: t.CChar | t.CPtr = pool.alloc(16)
|
||
if line is None: return
|
||
string.strcpy(line, "unreachable")
|
||
_emit(builder, line)
|
||
_mark_terminated(builder)
|
||
|
||
|
||
# ============================================================
|
||
# 原子指令 (Phase 3)
|
||
# ============================================================
|
||
# AtomicRMW 操作常量
|
||
ATOMIC_XCHG: t.CDefine = 0
|
||
ATOMIC_ADD: t.CDefine = 1
|
||
ATOMIC_SUB: t.CDefine = 2
|
||
ATOMIC_AND: t.CDefine = 3
|
||
ATOMIC_NAND: t.CDefine = 4
|
||
ATOMIC_OR: t.CDefine = 5
|
||
ATOMIC_XOR: t.CDefine = 6
|
||
ATOMIC_MAX: t.CDefine = 7
|
||
ATOMIC_MIN: t.CDefine = 8
|
||
ATOMIC_UMAX: t.CDefine = 9
|
||
ATOMIC_UMIN: t.CDefine = 10
|
||
|
||
# 内存序常量
|
||
ATOMIC_ORDER_NOTATOMIC: t.CDefine = 0
|
||
ATOMIC_ORDER_UNORDERED: t.CDefine = 1
|
||
ATOMIC_ORDER_MONOTONIC: t.CDefine = 2
|
||
ATOMIC_ORDER_ACQUIRE: t.CDefine = 3
|
||
ATOMIC_ORDER_RELEASE: t.CDefine = 4
|
||
ATOMIC_ORDER_ACQ_REL: t.CDefine = 5
|
||
ATOMIC_ORDER_SEQ_CST: t.CDefine = 6
|
||
|
||
|
||
def _atomic_op_str(op: t.CInt) -> t.CChar | t.CPtr:
|
||
if op == ATOMIC_XCHG: return "xchg"
|
||
if op == ATOMIC_ADD: return "add"
|
||
if op == ATOMIC_SUB: return "sub"
|
||
if op == ATOMIC_AND: return "and"
|
||
if op == ATOMIC_NAND: return "nand"
|
||
if op == ATOMIC_OR: return "or"
|
||
if op == ATOMIC_XOR: return "xor"
|
||
if op == ATOMIC_MAX: return "max"
|
||
if op == ATOMIC_MIN: return "min"
|
||
if op == ATOMIC_UMAX: return "umax"
|
||
if op == ATOMIC_UMIN: return "umin"
|
||
return "xchg"
|
||
|
||
|
||
def _atomic_order_str(ord: t.CInt) -> t.CChar | t.CPtr:
|
||
if ord == ATOMIC_ORDER_UNORDERED: return "unordered"
|
||
if ord == ATOMIC_ORDER_MONOTONIC: return "monotonic"
|
||
if ord == ATOMIC_ORDER_ACQUIRE: return "acquire"
|
||
if ord == ATOMIC_ORDER_RELEASE: return "release"
|
||
if ord == ATOMIC_ORDER_ACQ_REL: return "acq_rel"
|
||
if ord == ATOMIC_ORDER_SEQ_CST: return "seq_cst"
|
||
return "monotonic"
|
||
|
||
|
||
def build_atomicrmw(builder: IRBuilder | t.CPtr, op: t.CInt,
|
||
ptr: Value | t.CPtr, val: Value | t.CPtr,
|
||
order: t.CInt) -> Value | t.CPtr:
|
||
"""%N = atomicrmw <op> <ptr_ty> <ptr>, <val_ty> <val> <ordering>"""
|
||
if builder is None or ptr is None or val is None: return None
|
||
pool: memhub.MemBuddy | t.CPtr = builder.Pool
|
||
name: t.CChar | t.CPtr = _alloc_ssa_name(builder)
|
||
ptr_ty_s: t.CChar | t.CPtr = _type_str(builder, ptr.Ty)
|
||
val_ty_s: t.CChar | t.CPtr = _type_str(builder, val.Ty)
|
||
op_s: t.CChar | t.CPtr = _atomic_op_str(op)
|
||
ord_s: t.CChar | t.CPtr = _atomic_order_str(order)
|
||
line: t.CChar | t.CPtr = pool.alloc(256)
|
||
if line is None: return None
|
||
viperlib.snprintf(line, 256, "%s = atomicrmw %s %s %s, %s %s %s",
|
||
name, op_s, ptr_ty_s, ptr.Name, val_ty_s, val.Name, ord_s)
|
||
_emit(builder, line)
|
||
return SSAValue(pool, val.Ty, name)
|
||
|
||
|
||
def build_cmpxchg(builder: IRBuilder | t.CPtr, ptr: Value | t.CPtr,
|
||
cmp_val: Value | t.CPtr, new_val: Value | t.CPtr,
|
||
succ_order: t.CInt, fail_order: t.CInt) -> Value | t.CPtr:
|
||
"""%N = cmpxchg <ptr_ty> <ptr>, <cmp_ty> <cmp>, <new_ty> <new> <succ_order> <fail_order>
|
||
|
||
返回 {<ty>, i1} 类型的 SSA 值(简化为返回 i64 表示的值对)
|
||
"""
|
||
if builder is None or ptr is None or cmp_val is None or new_val is None: return None
|
||
pool: memhub.MemBuddy | t.CPtr = builder.Pool
|
||
name: t.CChar | t.CPtr = _alloc_ssa_name(builder)
|
||
ptr_ty_s: t.CChar | t.CPtr = _type_str(builder, ptr.Ty)
|
||
cmp_ty_s: t.CChar | t.CPtr = _type_str(builder, cmp_val.Ty)
|
||
new_ty_s: t.CChar | t.CPtr = _type_str(builder, new_val.Ty)
|
||
succ_s: t.CChar | t.CPtr = _atomic_order_str(succ_order)
|
||
fail_s: t.CChar | t.CPtr = _atomic_order_str(fail_order)
|
||
line: t.CChar | t.CPtr = pool.alloc(384)
|
||
if line is None: return None
|
||
viperlib.snprintf(line, 384, "%s = cmpxchg %s %s, %s %s, %s %s %s %s",
|
||
name, ptr_ty_s, ptr.Name, cmp_ty_s, cmp_val.Name,
|
||
new_ty_s, new_val.Name, succ_s, fail_s)
|
||
_emit(builder, line)
|
||
# 返回原始值的类型
|
||
return SSAValue(pool, new_val.Ty, name)
|
||
|
||
|
||
# ============================================================
|
||
# 内联汇编 (Phase 3)
|
||
# ============================================================
|
||
def build_inline_asm(builder: IRBuilder | t.CPtr, ret_ty: LLVMType | t.CPtr,
|
||
asm_text: t.CChar | t.CPtr, constraints: t.CChar | t.CPtr,
|
||
has_side_effects: t.CInt) -> Value | t.CPtr:
|
||
"""%N = call <ret_ty> asm [sideeffect] "" "<constraints>"()
|
||
|
||
简化的内联汇编调用,无参数版本。
|
||
"""
|
||
if builder is None: return None
|
||
pool: memhub.MemBuddy | t.CPtr = builder.Pool
|
||
|
||
# 判断返回类型是否为 void
|
||
is_void: t.CInt = 0
|
||
match ret_ty:
|
||
case LLVMType.Void():
|
||
is_void = 1
|
||
case _:
|
||
is_void = 0
|
||
|
||
name: t.CChar | t.CPtr = None
|
||
if is_void == 0:
|
||
name = _alloc_ssa_name(builder)
|
||
|
||
ret_ty_s: t.CChar | t.CPtr = _type_str(builder, ret_ty)
|
||
line: t.CChar | t.CPtr = pool.alloc(512)
|
||
if line is None: return None
|
||
|
||
if has_side_effects != 0:
|
||
if is_void == 1:
|
||
viperlib.snprintf(line, 512, "call %s asm sideeffect \"%s\", \"%s\"()",
|
||
ret_ty_s, asm_text, constraints)
|
||
else:
|
||
viperlib.snprintf(line, 512, "%s = call %s asm sideeffect \"%s\", \"%s\"()",
|
||
name, ret_ty_s, asm_text, constraints)
|
||
else:
|
||
if is_void == 1:
|
||
viperlib.snprintf(line, 512, "call %s asm \"%s\", \"%s\"()",
|
||
ret_ty_s, asm_text, constraints)
|
||
else:
|
||
viperlib.snprintf(line, 512, "%s = call %s asm \"%s\", \"%s\"()",
|
||
name, ret_ty_s, asm_text, constraints)
|
||
_emit(builder, line)
|
||
|
||
if is_void == 1:
|
||
return None
|
||
return SSAValue(pool, ret_ty, name)
|
||
|
||
|
||
# ============================================================
|
||
# 内部辅助
|
||
# ============================================================
|
||
def _append_cstr(dst: t.CChar | t.CPtr, dst_size: t.CSizeT, src: t.CChar | t.CPtr):
|
||
"""将 C 字符串 src 追加到 dst 末尾"""
|
||
if dst is None or src is None: return
|
||
dlen: t.CSizeT = string.strlen(dst)
|
||
slen: t.CSizeT = string.strlen(src)
|
||
remain: t.CSizeT = dst_size - dlen
|
||
if remain <= 0: return
|
||
i: t.CSizeT = 0
|
||
while i < slen and i + 1 < remain:
|
||
dst[dlen + i] = src[i]
|
||
i += 1
|
||
dst[dlen + i] = '\0'
|