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) # ============================================================ 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* 的 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 , """ 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 , """ 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 , """ 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 , """ 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 , """ 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 , """ 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 , """ 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 , """ 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 , """ 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 , """ 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 , """ 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 , """ 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 , """ 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 , """ 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 , """ 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 , """ 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 , """ 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 , """ 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 , """ 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 , """ return _build_binop(builder, "frem", lhs, rhs) def build_fneg(builder: IRBuilder | t.CPtr, val: Value | t.CPtr) -> Value | t.CPtr: """%N = fneg """ 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 , 返回类型为 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 , 返回类型为 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 %""" 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 , label %, label %""" 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 """ 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 @() 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 %callee() # # 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 %callee() 间接调用: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 to """ 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 to """ 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 to """ 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 to """ 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 to """ 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 to """ 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 to """ 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 to """ 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 to """ 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 to """ 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 to """ 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 to """ 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 , , """ 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 # ============================================================ 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 [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 分支 # ============================================================ 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 , label % [, label % ...]""" 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 , 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 , , """ 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 , """ 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 , , 返回 {, 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 asm [sideeffect] "" ""() 简化的内联汇编调用,无参数版本。 """ 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'