Files
Viper_VRTE/llvmlite/__builder.vp
T

1828 lines
73 KiB
Plaintext
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import t, c
from stdint import *
import string
import viperlib
import memhub
import stdio
import stdlib
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, block_set_terminated, block_get_terminated, function_move_block_to_end, _ll_name_needs_quote, block_insert_text_before_terminator
# ============================================================
# 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 保持一致
# (方法以实例方法实现,无虚表;文件末尾的同名顶层函数为一行委托)。
# ============================================================
@t.NoVTable
class IRBuilder:
Pool: memhub.MemBuddy | t.CPtr # 内存池
Func: Function | t.CPtr # 所属函数
CurBlock: BasicBlock | t.CPtr # 当前插入点
Counter: t.CInt # SSA 名计数器
# ============================================================
# 内部辅助
# ============================================================
def _alloc_ssa_name(self) -> t.CChar | t.CPtr:
"""分配一个 SSA 名字符串 "%N" 并递增计数器"""
pool: memhub.MemBuddy | t.CPtr = self.Pool
buf: t.CChar | t.CPtr = pool.alloc(16)
if buf is None: return None
viperlib.snprintf(buf, 16, "%%%d", self.Counter)
self.Counter += 1
return buf
def _type_str(self, ty: LLVMType | t.CPtr) -> t.CChar | t.CPtr:
"""获取类型的 IR 文本(从 pool 分配 512 字节缓冲区)
注意:复杂结构体类型(如 13 方法的虚表 {i8*,i8*,...})可能超过 64 字节,
必须使用足够大的缓冲区,否则 '}' 会被截断导致 IR 语法错误。
"""
pool: memhub.MemBuddy | t.CPtr = self.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(self, text: t.CChar | t.CPtr):
"""将指令文本追加到当前块"""
if self is None or self.CurBlock is None: return
block_append_text(self.Pool, self.CurBlock, text)
def _mark_terminated(self):
"""标记当前块已终止"""
if self is None or self.CurBlock is None: return
block_set_terminated(self.CurBlock, 1)
def _build_binop(self, op: t.CChar | t.CPtr,
lhs: Value | t.CPtr, rhs: Value | t.CPtr) -> Value | t.CPtr:
"""二元运算通用实现"""
if self is None or lhs is None or rhs is None: return None
pool: memhub.MemBuddy | t.CPtr = self.Pool
name: t.CChar | t.CPtr = self._alloc_ssa_name()
ty_s: t.CChar | t.CPtr = self._type_str(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)
self._emit(line)
return SSAValue(pool, lhs.Ty, name)
# ============================================================
# 块定位
# ============================================================
def position_at_end(self, block: BasicBlock | t.CPtr):
"""将插入点设为 block 的末尾,并把 block 移到函数块链表末尾。
移动 block 是为了保证 BB 文本输出顺序与控制流(position)顺序一致,
避免 SSA 名在文本中非单调递增导致 llc 编译失败。
"""
if self is None: return
self.CurBlock = block
if self.Func is not None:
function_move_block_to_end(self.Func, block)
def builder_cur_block_is_terminated(self) -> t.CInt:
"""检查当前块的 IsTerminated 标志
通过 block_get_terminated 辅助函数访问,避免链式属性
self.CurBlock.IsTerminated 在跨模块场景下 BasicBlock 为 opaque
导致的 GEP 静默跳过问题。
"""
if self is None or self.CurBlock is None:
return 1
return block_get_terminated(self.CurBlock)
# ============================================================
# 内存指令
# ============================================================
def build_alloca(self, ty: LLVMType | t.CPtr) -> Value | t.CPtr:
"""%N = alloca <ty>
返回类型为 ty* 的 SSA 值(默认对齐,由后端决定)。
注意:TPC 并行编译时 include 模块的函数默认参数不会预注册(argN 名回退),
因此本函数不设默认参数;需要显式对齐请用 build_alloca_aligned。
"""
if self is None: return None
pool: memhub.MemBuddy | t.CPtr = self.Pool
name: t.CChar | t.CPtr = self._alloc_ssa_name()
ty_s: t.CChar | t.CPtr = self._type_str(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)
self._emit(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_aligned(self, ty: LLVMType | t.CPtr,
align: int) -> Value | t.CPtr:
"""%N = alloca <ty>, align N
返回类型为 ty* 的 SSA 值;显式指定对齐(如 va_list 24 字节缓冲区需 16 对齐)。
align 不设默认值(TPC 并行编译时 include 默认参数不预注册),调用方必须显式传入。
"""
if self is None: return None
pool: memhub.MemBuddy | t.CPtr = self.Pool
name: t.CChar | t.CPtr = self._alloc_ssa_name()
ty_s: t.CChar | t.CPtr = self._type_str(ty)
line: t.CChar | t.CPtr = pool.alloc(128)
if line is None: return None
viperlib.snprintf(line, 128, "%s = alloca %s, align %d", name, ty_s, align)
self._emit(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(self, ty: LLVMType | t.CPtr) -> Value | t.CPtr:
"""%N = alloca <ty>(在函数入口块生成,确保支配性)
在入口块的终止指令之前插入 alloca,避免在条件分支内生成 alloca
导致的支配性违规(Instruction does not dominate all uses)。
"""
if self is None: return None
pool: memhub.MemBuddy | t.CPtr = self.Pool
func: Function | t.CPtr = self.Func
if func is None or func.Blocks is None:
return self.build_alloca(ty)
entry_blk: BasicBlock | t.CPtr = func.Blocks.Head
if entry_blk is None:
return self.build_alloca(ty)
name: t.CChar | t.CPtr = self._alloc_ssa_name()
ty_s: t.CChar | t.CPtr = self._type_str(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(self, ty: LLVMType | t.CPtr,
ptr: Value | t.CPtr) -> Value | t.CPtr:
"""%N = load <ty>, <ptr_ty> <ptr>"""
if self is None or ptr is None: return None
pool: memhub.MemBuddy | t.CPtr = self.Pool
name: t.CChar | t.CPtr = self._alloc_ssa_name()
ty_s: t.CChar | t.CPtr = self._type_str(ty)
ptr_ty_s: t.CChar | t.CPtr = self._type_str(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)
self._emit(line)
return SSAValue(pool, ty, name)
def build_store(self, val: Value | t.CPtr, ptr: Value | t.CPtr):
"""store <val_ty> <val>, <ptr_ty> <ptr>"""
if self is None or val is None or ptr is None: return
pool: memhub.MemBuddy | t.CPtr = self.Pool
val_ty_s: t.CChar | t.CPtr = self._type_str(val.Ty)
ptr_ty_s: t.CChar | t.CPtr = self._type_str(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)
self._emit(line)
# ============================================================
# 二元运算指令
# ============================================================
def build_add(self, lhs: Value | t.CPtr,
rhs: Value | t.CPtr) -> Value | t.CPtr:
"""%N = add <ty> <lhs>, <rhs>"""
return self._build_binop("add", lhs, rhs)
def build_sub(self, lhs: Value | t.CPtr,
rhs: Value | t.CPtr) -> Value | t.CPtr:
"""%N = sub <ty> <lhs>, <rhs>"""
return self._build_binop("sub", lhs, rhs)
def build_mul(self, lhs: Value | t.CPtr,
rhs: Value | t.CPtr) -> Value | t.CPtr:
"""%N = mul <ty> <lhs>, <rhs>"""
return self._build_binop("mul", lhs, rhs)
def build_sdiv(self, lhs: Value | t.CPtr,
rhs: Value | t.CPtr) -> Value | t.CPtr:
"""%N = sdiv <ty> <lhs>, <rhs>"""
return self._build_binop("sdiv", lhs, rhs)
def build_udiv(self, lhs: Value | t.CPtr,
rhs: Value | t.CPtr) -> Value | t.CPtr:
"""%N = udiv <ty> <lhs>, <rhs>"""
return self._build_binop("udiv", lhs, rhs)
def build_srem(self, lhs: Value | t.CPtr,
rhs: Value | t.CPtr) -> Value | t.CPtr:
"""%N = srem <ty> <lhs>, <rhs>"""
return self._build_binop("srem", lhs, rhs)
def build_urem(self, lhs: Value | t.CPtr,
rhs: Value | t.CPtr) -> Value | t.CPtr:
"""%N = urem <ty> <lhs>, <rhs>"""
return self._build_binop("urem", lhs, rhs)
def build_and(self, lhs: Value | t.CPtr,
rhs: Value | t.CPtr) -> Value | t.CPtr:
"""%N = and <ty> <lhs>, <rhs>"""
return self._build_binop("and", lhs, rhs)
def build_or(self, lhs: Value | t.CPtr,
rhs: Value | t.CPtr) -> Value | t.CPtr:
"""%N = or <ty> <lhs>, <rhs>"""
return self._build_binop("or", lhs, rhs)
def build_xor(self, lhs: Value | t.CPtr,
rhs: Value | t.CPtr) -> Value | t.CPtr:
"""%N = xor <ty> <lhs>, <rhs>"""
return self._build_binop("xor", lhs, rhs)
def build_shl(self, lhs: Value | t.CPtr,
rhs: Value | t.CPtr) -> Value | t.CPtr:
"""%N = shl <ty> <lhs>, <rhs>"""
return self._build_binop("shl", lhs, rhs)
def build_lshr(self, lhs: Value | t.CPtr,
rhs: Value | t.CPtr) -> Value | t.CPtr:
"""%N = lshr <ty> <lhs>, <rhs>"""
return self._build_binop("lshr", lhs, rhs)
def build_ashr(self, lhs: Value | t.CPtr,
rhs: Value | t.CPtr) -> Value | t.CPtr:
"""%N = ashr <ty> <lhs>, <rhs>"""
return self._build_binop("ashr", lhs, rhs)
# ============================================================
# 浮点二元运算指令
# ============================================================
def build_fadd(self, lhs: Value | t.CPtr,
rhs: Value | t.CPtr) -> Value | t.CPtr:
"""%N = fadd <ty> <lhs>, <rhs>"""
return self._build_binop("fadd", lhs, rhs)
def build_fsub(self, lhs: Value | t.CPtr,
rhs: Value | t.CPtr) -> Value | t.CPtr:
"""%N = fsub <ty> <lhs>, <rhs>"""
return self._build_binop("fsub", lhs, rhs)
def build_fmul(self, lhs: Value | t.CPtr,
rhs: Value | t.CPtr) -> Value | t.CPtr:
"""%N = fmul <ty> <lhs>, <rhs>"""
return self._build_binop("fmul", lhs, rhs)
def build_fdiv(self, lhs: Value | t.CPtr,
rhs: Value | t.CPtr) -> Value | t.CPtr:
"""%N = fdiv <ty> <lhs>, <rhs>"""
return self._build_binop("fdiv", lhs, rhs)
def build_frem(self, lhs: Value | t.CPtr,
rhs: Value | t.CPtr) -> Value | t.CPtr:
"""%N = frem <ty> <lhs>, <rhs>"""
return self._build_binop("frem", lhs, rhs)
def build_fneg(self, val: Value | t.CPtr) -> Value | t.CPtr:
"""%N = fneg <ty> <val>"""
if self is None or val is None: return None
pool: memhub.MemBuddy | t.CPtr = self.Pool
name: t.CChar | t.CPtr = self._alloc_ssa_name()
ty_s: t.CChar | t.CPtr = self._type_str(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)
self._emit(line)
return SSAValue(pool, val.Ty, name)
# ============================================================
# 比较指令
# ============================================================
def build_icmp(self, pred: t.CInt,
lhs: Value | t.CPtr, rhs: Value | t.CPtr) -> Value | t.CPtr:
"""%N = icmp <pred> <ty> <lhs>, <rhs>
返回类型为 i1 的 SSA 值
"""
if self is None or lhs is None or rhs is None: return None
pool: memhub.MemBuddy | t.CPtr = self.Pool
name: t.CChar | t.CPtr = self._alloc_ssa_name()
ty_s: t.CChar | t.CPtr = self._type_str(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)
self._emit(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(self, pred: t.CInt,
lhs: Value | t.CPtr, rhs: Value | t.CPtr) -> Value | t.CPtr:
"""%N = fcmp <pred> <ty> <lhs>, <rhs>
返回类型为 i1 的 SSA 值
"""
if self is None or lhs is None or rhs is None: return None
pool: memhub.MemBuddy | t.CPtr = self.Pool
name: t.CChar | t.CPtr = self._alloc_ssa_name()
ty_s: t.CChar | t.CPtr = self._type_str(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)
self._emit(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(self, target: BasicBlock | t.CPtr):
"""br label %<target>"""
if self is None or target is None: return
pool: memhub.MemBuddy | t.CPtr = self.Pool
line: t.CChar | t.CPtr = pool.alloc(64)
if line is None: return
viperlib.snprintf(line, 64, "br label %%%s", target.Name)
self._emit(line)
self._mark_terminated()
def build_cond_br(self, cond: Value | t.CPtr,
then_blk: BasicBlock | t.CPtr, else_blk: BasicBlock | t.CPtr):
"""br i1 <cond>, label %<then>, label %<else_>"""
if self is None or cond is None or then_blk is None or else_blk is None: return
pool: memhub.MemBuddy | t.CPtr = self.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)
self._emit(line)
self._mark_terminated()
def build_ret(self, val: Value | t.CPtr):
"""ret <ty> <val>"""
if self is None or val is None: return
pool: memhub.MemBuddy | t.CPtr = self.Pool
ty_s: t.CChar | t.CPtr = self._type_str(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)
self._emit(line)
self._mark_terminated()
def build_ret_void(self):
"""ret void"""
if self is None: return
pool: memhub.MemBuddy | t.CPtr = self.Pool
line: t.CChar | t.CPtr = pool.alloc(16)
if line is None: return
string.strcpy(line, "ret void")
self._emit(line)
self._mark_terminated()
# ============================================================
# 调用指令
# ============================================================
def build_call(self, 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 self is None: return None
pool: memhub.MemBuddy | t.CPtr = self.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 = self._alloc_ssa_name()
ret_ty_s: t.CChar | t.CPtr = self._type_str(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 = self._type_str(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)
self._emit(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(self, 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 self is None or callee_val is None: return None
pool: memhub.MemBuddy | t.CPtr = self.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 = self._alloc_ssa_name()
ret_ty_s: t.CChar | t.CPtr = self._type_str(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 = self._type_str(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)
self._emit(line)
if is_void == 1:
return None
return SSAValue(pool, ret_ty, name)
# ============================================================
# 类型转换指令
# ============================================================
def build_bitcast(self, val: Value | t.CPtr,
to_ty: LLVMType | t.CPtr) -> Value | t.CPtr:
"""%N = bitcast <from_ty> <val> to <to_ty>"""
if self is None or val is None:
return None
pool: memhub.MemBuddy | t.CPtr = self.Pool
name: t.CChar | t.CPtr = self._alloc_ssa_name()
from_ty_s: t.CChar | t.CPtr = self._type_str(val.Ty)
to_ty_s: t.CChar | t.CPtr = self._type_str(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)
self._emit(line)
ret: Value | t.CPtr = SSAValue(pool, to_ty, name)
return ret
def build_sext(self, val: Value | t.CPtr,
to_ty: LLVMType | t.CPtr) -> Value | t.CPtr:
"""%N = sext <from_ty> <val> to <to_ty>"""
if self is None or val is None: return None
pool: memhub.MemBuddy | t.CPtr = self.Pool
name: t.CChar | t.CPtr = self._alloc_ssa_name()
from_ty_s: t.CChar | t.CPtr = self._type_str(val.Ty)
to_ty_s: t.CChar | t.CPtr = self._type_str(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)
self._emit(line)
return SSAValue(pool, to_ty, name)
def build_trunc(self, val: Value | t.CPtr,
to_ty: LLVMType | t.CPtr) -> Value | t.CPtr:
"""%N = trunc <from_ty> <val> to <to_ty>"""
if self is None or val is None: return None
pool: memhub.MemBuddy | t.CPtr = self.Pool
name: t.CChar | t.CPtr = self._alloc_ssa_name()
from_ty_s: t.CChar | t.CPtr = self._type_str(val.Ty)
to_ty_s: t.CChar | t.CPtr = self._type_str(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)
self._emit(line)
return SSAValue(pool, to_ty, name)
def build_zext(self, val: Value | t.CPtr,
to_ty: LLVMType | t.CPtr) -> Value | t.CPtr:
"""%N = zext <from_ty> <val> to <to_ty>"""
if self is None or val is None: return None
pool: memhub.MemBuddy | t.CPtr = self.Pool
name: t.CChar | t.CPtr = self._alloc_ssa_name()
from_ty_s: t.CChar | t.CPtr = self._type_str(val.Ty)
to_ty_s: t.CChar | t.CPtr = self._type_str(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)
self._emit(line)
return SSAValue(pool, to_ty, name)
def build_ptrtoint(self, val: Value | t.CPtr,
to_ty: LLVMType | t.CPtr) -> Value | t.CPtr:
"""%N = ptrtoint <from_ty> <val> to <to_ty>"""
if self is None or val is None: return None
pool: memhub.MemBuddy | t.CPtr = self.Pool
name: t.CChar | t.CPtr = self._alloc_ssa_name()
from_ty_s: t.CChar | t.CPtr = self._type_str(val.Ty)
to_ty_s: t.CChar | t.CPtr = self._type_str(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)
self._emit(line)
return SSAValue(pool, to_ty, name)
def build_inttoptr(self, val: Value | t.CPtr,
to_ty: LLVMType | t.CPtr) -> Value | t.CPtr:
"""%N = inttoptr <from_ty> <val> to <to_ty>"""
if self is None or val is None: return None
pool: memhub.MemBuddy | t.CPtr = self.Pool
name: t.CChar | t.CPtr = self._alloc_ssa_name()
from_ty_s: t.CChar | t.CPtr = self._type_str(val.Ty)
to_ty_s: t.CChar | t.CPtr = self._type_str(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)
self._emit(line)
return SSAValue(pool, to_ty, name)
# ============================================================
# 浮点转换指令
# ============================================================
def build_fpext(self, val: Value | t.CPtr,
to_ty: LLVMType | t.CPtr) -> Value | t.CPtr:
"""%N = fpext <from_ty> <val> to <to_ty>"""
if self is None or val is None: return None
pool: memhub.MemBuddy | t.CPtr = self.Pool
name: t.CChar | t.CPtr = self._alloc_ssa_name()
from_ty_s: t.CChar | t.CPtr = self._type_str(val.Ty)
to_ty_s: t.CChar | t.CPtr = self._type_str(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)
self._emit(line)
return SSAValue(pool, to_ty, name)
def build_fptrunc(self, val: Value | t.CPtr,
to_ty: LLVMType | t.CPtr) -> Value | t.CPtr:
"""%N = fptrunc <from_ty> <val> to <to_ty>"""
if self is None or val is None: return None
pool: memhub.MemBuddy | t.CPtr = self.Pool
name: t.CChar | t.CPtr = self._alloc_ssa_name()
from_ty_s: t.CChar | t.CPtr = self._type_str(val.Ty)
to_ty_s: t.CChar | t.CPtr = self._type_str(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)
self._emit(line)
return SSAValue(pool, to_ty, name)
def build_fp2si(self, val: Value | t.CPtr,
to_ty: LLVMType | t.CPtr) -> Value | t.CPtr:
"""%N = fptosi <from_ty> <val> to <to_ty>"""
if self is None or val is None: return None
pool: memhub.MemBuddy | t.CPtr = self.Pool
name: t.CChar | t.CPtr = self._alloc_ssa_name()
from_ty_s: t.CChar | t.CPtr = self._type_str(val.Ty)
to_ty_s: t.CChar | t.CPtr = self._type_str(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)
self._emit(line)
return SSAValue(pool, to_ty, name)
def build_si2fp(self, val: Value | t.CPtr,
to_ty: LLVMType | t.CPtr) -> Value | t.CPtr:
"""%N = sitofp <from_ty> <val> to <to_ty>"""
if self is None or val is None: return None
pool: memhub.MemBuddy | t.CPtr = self.Pool
name: t.CChar | t.CPtr = self._alloc_ssa_name()
from_ty_s: t.CChar | t.CPtr = self._type_str(val.Ty)
to_ty_s: t.CChar | t.CPtr = self._type_str(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)
self._emit(line)
return SSAValue(pool, to_ty, name)
def build_fp2ui(self, val: Value | t.CPtr,
to_ty: LLVMType | t.CPtr) -> Value | t.CPtr:
"""%N = fptoui <from_ty> <val> to <to_ty>"""
if self is None or val is None: return None
pool: memhub.MemBuddy | t.CPtr = self.Pool
name: t.CChar | t.CPtr = self._alloc_ssa_name()
from_ty_s: t.CChar | t.CPtr = self._type_str(val.Ty)
to_ty_s: t.CChar | t.CPtr = self._type_str(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)
self._emit(line)
return SSAValue(pool, to_ty, name)
def build_ui2fp(self, val: Value | t.CPtr,
to_ty: LLVMType | t.CPtr) -> Value | t.CPtr:
"""%N = uitofp <from_ty> <val> to <to_ty>"""
if self is None or val is None: return None
pool: memhub.MemBuddy | t.CPtr = self.Pool
name: t.CChar | t.CPtr = self._alloc_ssa_name()
from_ty_s: t.CChar | t.CPtr = self._type_str(val.Ty)
to_ty_s: t.CChar | t.CPtr = self._type_str(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)
self._emit(line)
return SSAValue(pool, to_ty, name)
# ============================================================
# GEP 指令
# ============================================================
def build_gep(self, 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 self is None or ptr is None or idx is None: return None
# 防御性检查: ptr.Ty 必须是指针类型,否则 llc 报错
# "base of getelementptr must be a pointer"
# 当 translate_value 返回非指针值(如 i32 常量 0)时,
# 直接 GEP 会导致 llc 编译失败
if _is_ptr_type(ptr.Ty) == 0:
return None
pool: memhub.MemBuddy | t.CPtr = self.Pool
name: t.CChar | t.CPtr = self._alloc_ssa_name()
elem_ty_s: t.CChar | t.CPtr = self._type_str(elem_ty)
ptr_ty_s: t.CChar | t.CPtr = self._type_str(ptr.Ty)
idx_ty_s: t.CChar | t.CPtr = self._type_str(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)
self._emit(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(self, 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 self is None or ptr is None or idx is None: return None
pool: memhub.MemBuddy | t.CPtr = self.Pool
name: t.CChar | t.CPtr = self._alloc_ssa_name()
array_ty_s: t.CChar | t.CPtr = self._type_str(array_ty)
ptr_ty_s: t.CChar | t.CPtr = self._type_str(ptr.Ty)
idx_ty_s: t.CChar | t.CPtr = self._type_str(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)
self._emit(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(self, 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 self is None or ptr is None: return None
pool: memhub.MemBuddy | t.CPtr = self.Pool
name: t.CChar | t.CPtr = self._alloc_ssa_name()
struct_ty_s: t.CChar | t.CPtr = self._type_str(struct_ty)
ptr_ty_s: t.CChar | t.CPtr = self._type_str(ptr.Ty)
line: t.CChar | t.CPtr = pool.alloc(2048)
if line is None:
stdio.printf("[BGS] line alloc None\n")
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)
self._emit(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")
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")
return rv
# ============================================================
# Phi 指令
# ============================================================
def build_phi(self, 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 self is None: return None
pool: memhub.MemBuddy | t.CPtr = self.Pool
name: t.CChar | t.CPtr = self._alloc_ssa_name()
ty_s: t.CChar | t.CPtr = self._type_str(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)
self._emit(line)
return SSAValue(pool, ty, name)
# ============================================================
# Switch 指令
# ============================================================
def build_switch(self, 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 self is None or val is None or default_blk is None: return
pool: memhub.MemBuddy | t.CPtr = self.Pool
ty_s: t.CChar | t.CPtr = self._type_str(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 = self._type_str(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, "]")
self._emit(line)
self._mark_terminated()
# ============================================================
# Select 指令
# ============================================================
def build_select(self, 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 self is None or cond is None or true_val is None or false_val is None: return None
pool: memhub.MemBuddy | t.CPtr = self.Pool
name: t.CChar | t.CPtr = self._alloc_ssa_name()
ty_s: t.CChar | t.CPtr = self._type_str(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)
self._emit(line)
return SSAValue(pool, true_val.Ty, name)
# ============================================================
# Unreachable 指令
# ============================================================
def build_unreachable(self):
"""unreachable"""
if self is None: return
pool: memhub.MemBuddy | t.CPtr = self.Pool
line: t.CChar | t.CPtr = pool.alloc(16)
if line is None: return
string.strcpy(line, "unreachable")
self._emit(line)
self._mark_terminated()
# ============================================================
# 原子指令 (Phase 3)
# ============================================================
def build_atomicrmw(self, 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 self is None or ptr is None or val is None: return None
pool: memhub.MemBuddy | t.CPtr = self.Pool
name: t.CChar | t.CPtr = self._alloc_ssa_name()
ptr_ty_s: t.CChar | t.CPtr = self._type_str(ptr.Ty)
val_ty_s: t.CChar | t.CPtr = self._type_str(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)
self._emit(line)
return SSAValue(pool, val.Ty, name)
def build_cmpxchg(self, 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 self is None or ptr is None or cmp_val is None or new_val is None: return None
pool: memhub.MemBuddy | t.CPtr = self.Pool
name: t.CChar | t.CPtr = self._alloc_ssa_name()
ptr_ty_s: t.CChar | t.CPtr = self._type_str(ptr.Ty)
cmp_ty_s: t.CChar | t.CPtr = self._type_str(cmp_val.Ty)
new_ty_s: t.CChar | t.CPtr = self._type_str(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)
self._emit(line)
# 返回原始值的类型
return SSAValue(pool, new_val.Ty, name)
# ============================================================
# va_arg 指令: 从 va_list 读取下一个变长参数
# ============================================================
def build_va_arg(self,
va_list_ptr: Value | t.CPtr,
arg_ty: LLVMType | t.CPtr) -> Value | t.CPtr:
"""%N = va_arg <va_list_ty> <va_list_ptr>, <arg_ty>"""
if self is None or va_list_ptr is None or arg_ty is None:
return None
pool: memhub.MemBuddy | t.CPtr = self.Pool
name: t.CChar | t.CPtr = self._alloc_ssa_name()
va_list_ty_s: t.CChar | t.CPtr = self._type_str(va_list_ptr.Ty)
arg_ty_s: t.CChar | t.CPtr = self._type_str(arg_ty)
line: t.CChar | t.CPtr = pool.alloc(256)
if line is None: return None
if va_list_ptr.Name is None:
return None
viperlib.snprintf(line, 256, "%s = va_arg %s %s, %s",
name, va_list_ty_s, va_list_ptr.Name, arg_ty_s)
self._emit(line)
return SSAValue(pool, arg_ty, name)
# ============================================================
# 内联汇编 (Phase 3)
# ============================================================
def build_inline_asm(self, 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 self is None: return None
pool: memhub.MemBuddy | t.CPtr = self.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 = self._alloc_ssa_name()
ret_ty_s: t.CChar | t.CPtr = self._type_str(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)
self._emit(line)
if is_void == 1:
return None
return SSAValue(pool, ret_ty, name)
# ============================================================
# 工厂函数
# ============================================================
# 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 编译失败。
"""
builder.position_at_end(block)
# ============================================================
# 内部辅助
# ============================================================
def _alloc_ssa_name(builder: IRBuilder | t.CPtr) -> t.CChar | t.CPtr:
"""分配一个 SSA 名字符串 "%N" 并递增计数器"""
return builder._alloc_ssa_name()
def _type_str(builder: IRBuilder | t.CPtr, ty: LLVMType | t.CPtr) -> t.CChar | t.CPtr:
"""获取类型的 IR 文本(从 pool 分配 512 字节缓冲区)
注意:复杂结构体类型(如 13 方法的虚表 {i8*,i8*,...})可能超过 64 字节,
必须使用足够大的缓冲区,否则 '}' 会被截断导致 IR 语法错误。
"""
return builder._type_str(ty)
def _emit(builder: IRBuilder | t.CPtr, text: t.CChar | t.CPtr):
"""将指令文本追加到当前块"""
builder._emit(text)
def _mark_terminated(builder: IRBuilder | t.CPtr):
"""标记当前块已终止"""
builder._mark_terminated()
def builder_cur_block_is_terminated(builder: IRBuilder | t.CPtr) -> t.CInt:
"""检查当前块的 IsTerminated 标志
通过 block_get_terminated 辅助函数访问,避免链式属性
builder.CurBlock.IsTerminated 在跨模块场景下 BasicBlock 为 opaque
导致的 GEP 静默跳过问题。
"""
return builder.builder_cur_block_is_terminated()
# ============================================================
# 内存指令
# ============================================================
def build_alloca(builder: IRBuilder | t.CPtr, ty: LLVMType | t.CPtr) -> Value | t.CPtr:
"""%N = alloca <ty>
返回类型为 ty* 的 SSA 值(默认对齐,由后端决定)。
注意:TPC 并行编译时 include 模块的函数默认参数不会预注册(argN 名回退),
因此本函数不设默认参数;需要显式对齐请用 build_alloca_aligned。
"""
return builder.build_alloca(ty)
def build_alloca_aligned(builder: IRBuilder | t.CPtr, ty: LLVMType | t.CPtr,
align: int) -> Value | t.CPtr:
"""%N = alloca <ty>, align N
返回类型为 ty* 的 SSA 值;显式指定对齐(如 va_list 24 字节缓冲区需 16 对齐)。
align 不设默认值(TPC 并行编译时 include 默认参数不预注册),调用方必须显式传入。
"""
return builder.build_alloca_aligned(ty, align)
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)。
"""
return builder.build_alloca_at_entry(ty)
def build_load(builder: IRBuilder | t.CPtr, ty: LLVMType | t.CPtr,
ptr: Value | t.CPtr) -> Value | t.CPtr:
"""%N = load <ty>, <ptr_ty> <ptr>"""
return builder.build_load(ty, ptr)
def build_store(builder: IRBuilder | t.CPtr, val: Value | t.CPtr, ptr: Value | t.CPtr):
"""store <val_ty> <val>, <ptr_ty> <ptr>"""
builder.build_store(val, ptr)
# ============================================================
# 二元运算指令
# ============================================================
def build_add(builder: IRBuilder | t.CPtr, lhs: Value | t.CPtr,
rhs: Value | t.CPtr) -> Value | t.CPtr:
"""%N = add <ty> <lhs>, <rhs>"""
return builder.build_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 builder.build_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 builder.build_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 builder.build_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 builder.build_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 builder.build_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 builder.build_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 builder.build_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 builder.build_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 builder.build_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 builder.build_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 builder.build_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 builder.build_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 builder.build_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 builder.build_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 builder.build_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 builder.build_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 builder.build_frem(lhs, rhs)
def build_fneg(builder: IRBuilder | t.CPtr, val: Value | t.CPtr) -> Value | t.CPtr:
"""%N = fneg <ty> <val>"""
return builder.build_fneg(val)
def _build_binop(builder: IRBuilder | t.CPtr, op: t.CChar | t.CPtr,
lhs: Value | t.CPtr, rhs: Value | t.CPtr) -> Value | t.CPtr:
"""二元运算通用实现"""
return builder._build_binop(op, lhs, rhs)
# ============================================================
# 比较指令
# ============================================================
# 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 值
"""
return builder.build_icmp(pred, lhs, rhs)
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 值
"""
return builder.build_fcmp(pred, lhs, rhs)
# ============================================================
# 终止指令
# ============================================================
def build_br(builder: IRBuilder | t.CPtr, target: BasicBlock | t.CPtr):
"""br label %<target>"""
builder.build_br(target)
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_>"""
builder.build_cond_br(cond, then_blk, else_blk)
def build_ret(builder: IRBuilder | t.CPtr, val: Value | t.CPtr):
"""ret <ty> <val>"""
builder.build_ret(val)
def build_ret_void(builder: IRBuilder | t.CPtr):
"""ret void"""
builder.build_ret_void()
# ============================================================
# 调用指令
# ============================================================
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)。
"""
return builder.build_call(callee, args, arg_count, ret_ty, is_variadic)
# ============================================================
# 间接调用指令: 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 值。
"""
return builder.build_call_indirect(callee_val, args, arg_count, ret_ty)
# ============================================================
# 类型转换指令
# ============================================================
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>"""
return builder.build_bitcast(val, to_ty)
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>"""
return builder.build_sext(val, to_ty)
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>"""
return builder.build_trunc(val, to_ty)
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>"""
return builder.build_zext(val, to_ty)
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>"""
return builder.build_ptrtoint(val, to_ty)
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>"""
return builder.build_inttoptr(val, to_ty)
# ============================================================
# 浮点转换指令
# ============================================================
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>"""
return builder.build_fpext(val, to_ty)
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>"""
return builder.build_fptrunc(val, to_ty)
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>"""
return builder.build_fp2si(val, to_ty)
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>"""
return builder.build_si2fp(val, to_ty)
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>"""
return builder.build_fp2ui(val, to_ty)
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>"""
return builder.build_ui2fp(val, to_ty)
# ============================================================
# GEP 指令
# ============================================================
def _is_ptr_type(ty: LLVMType | t.CPtr) -> int:
"""检查 ty 是否是 Ptr 类型(独立函数,避免嵌套 match 的编译器 BUG)"""
if ty is None:
return 0
match ty:
case LLVMType.Ptr(pointee):
return 1
case _:
return 0
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>"""
return builder.build_gep(elem_ty, ptr, idx)
# ============================================================
# 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*
"""
return builder.build_gep_array(array_ty, elem_ty, ptr, idx)
# ============================================================
# 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*
"""
return builder.build_gep_struct(struct_ty, field_ty, ptr, field_idx)
# ============================================================
# 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 是入边数量。
"""
return builder.build_phi(ty, incoming_head, count)
# ============================================================
# 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> ...]"""
builder.build_switch(val, default_blk, cases_head, case_count)
# ============================================================
# 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>"""
return builder.build_select(cond, true_val, false_val)
# ============================================================
# Unreachable 指令
# ============================================================
def build_unreachable(builder: IRBuilder | t.CPtr):
"""unreachable"""
builder.build_unreachable()
# ============================================================
# 原子指令 (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>"""
return builder.build_atomicrmw(op, ptr, val, order)
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 表示的值对)
"""
return builder.build_cmpxchg(ptr, cmp_val, new_val, succ_order, fail_order)
# ============================================================
# va_arg 指令: 从 va_list 读取下一个变长参数
# ============================================================
def build_va_arg(builder: IRBuilder | t.CPtr,
va_list_ptr: Value | t.CPtr,
arg_ty: LLVMType | t.CPtr) -> Value | t.CPtr:
"""%N = va_arg <va_list_ty> <va_list_ptr>, <arg_ty>"""
return builder.build_va_arg(va_list_ptr, arg_ty)
# ============================================================
# 内联汇编 (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>"()
简化的内联汇编调用,无参数版本。
"""
return builder.build_inline_asm(ret_ty, asm_text, constraints, has_side_effects)
# ============================================================
# 内部辅助
# ============================================================
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)
# 无符号下溢防护:dlen 超过缓冲大小时(缓冲已被破坏/悬空)直接返回,
# 否则 remain = dst_size - dlen 下溢成巨值会把 dst[dlen+i] 写穿到缓冲外
if dlen >= dst_size:
return
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'