import t, c
from stdint import *
import string
import viperlib
import memhub
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_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(256)
    if args_buf is None: return None
    args_buf[0] = '\0'
    func_ty_buf: t.CChar | t.CPtr = pool.alloc(256)
    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, 256, ", ")
            _append_cstr(func_ty_buf, 256, ", ")
        arg_ty_s: t.CChar | t.CPtr = _type_str(builder, cur.Ty)
        _append_cstr(args_buf, 256, arg_ty_s)
        _append_cstr(args_buf, 256, " ")
        if cur.Name is not None:
            _append_cstr(args_buf, 256, cur.Name)
        _append_cstr(func_ty_buf, 256, arg_ty_s)
        cur = cur.Next
        first = 0
    if is_variadic == 1:
        if first == 0:
            _append_cstr(func_ty_buf, 256, ", ")
        _append_cstr(func_ty_buf, 256, "...")

    # 构造带引号的 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(512)
    if line is None: return None
    if is_variadic == 1:
        if is_void == 1:
            viperlib.snprintf(line, 512, "call %s (%s) @%s(%s)", ret_ty_s, func_ty_buf, callee_buf, args_buf)
        else:
            viperlib.snprintf(line, 512, "%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, 512, "call %s @%s(%s)", ret_ty_s, callee_buf, args_buf)
        else:
            viperlib.snprintf(line, 512, "%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(256)
    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, 256, ", ")
        arg_ty_s: t.CChar | t.CPtr = _type_str(builder, cur.Ty)
        _append_cstr(args_buf, 256, arg_ty_s)
        _append_cstr(args_buf, 256, " ")
        if cur.Name is not None:
            _append_cstr(args_buf, 256, cur.Name)
        cur = cur.Next
        first = 0

    line: t.CChar | t.CPtr = pool.alloc(512)
    if line is None: return None
    if is_void == 1:
        viperlib.snprintf(line, 512, "call %s %s(%s)", ret_ty_s, callee_val.Name, args_buf)
    else:
        viperlib.snprintf(line, 512, "%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: 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 not None:
        string.memset(result_ty, 0, LLVMType.__sizeof__())
        c.DerefAs(result_ty, LLVMType.Ptr(field_ty))
    return SSAValue(pool, result_ty, name)


# ============================================================
# 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], ...
    parts: t.CChar | t.CPtr = pool.alloc(512)
    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, 512, ", ")
        _append_cstr(parts, 512, "[")
        # 使用中间变量避免链式结构体成员访问被编译器丢弃
        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, 512, inc_val_name)
        _append_cstr(parts, 512, ", %")
        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, 512, inc_blk_name)
        _append_cstr(parts, 512, "]")
        cur = cur.Next
        first = 0

    line: t.CChar | t.CPtr = pool.alloc(640)
    if line is None: return None
    viperlib.snprintf(line, 640, "%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'
