diff --git a/App/lib/core/Handles/HandlesExprCall.vp b/App/lib/core/Handles/HandlesExprCall.vp index 9d2e871..d3a06ec 100644 --- a/App/lib/core/Handles/HandlesExprCall.vp +++ b/App/lib/core/Handles/HandlesExprCall.vp @@ -1625,206 +1625,25 @@ def translate_c_asm(pool: memhub.MemBuddy | t.CPtr, return None # ============================================================ -# c.LLVMIR — 内联 LLVM IR 支持 +# c.LLVMIR — 内联 LLVM IR(无返回值,直接嵌入原始 IR 文本) # # 语法: -# c.LLVMIR(f"add i32 {c.LInp(a)}, {c.LInp(b)}", t.CInt) -# c.LLVMIR(f"%{c.LOut(result)} = add i32 {c.LInp(a)}, {c.LInp(b)}", t.CInt) +# c.LLVMIR(f"add i32 {c.LInp(a)}, {c.LInp(b)}") +# c.LLVMIR(f"{c.LOut(result)} = add i32 {c.LInp(a)}, {c.LInp(b)}") # -# c.LInp(expr) - 输入操作数,翻译后替换为对应的 LLVM 值 -# c.LOut(expr) - 输出操作数,翻译后结果存储到该变量 +# c.LInp(expr) - 输入操作数,替换为 expr 的 LLVM 值引用文本(SSA 名 "%x" 或常量 "42") +# c.LOut(expr) - 输出操作数:为 expr 变量分配唯一 SSA 寄存器 %llvmirN, +# 模板嵌入后自动追加 store %llvmirN, * %expr 写回变量 # -# 支持的指令: add/sub/mul/sdiv/udiv/srem/urem/and/or/xor/shl/lshr/ashr -# fadd/fsub/fmul/fdiv -# icmp eq/ne/sgt/sge/slt/sle/ugt/uge/ult/ule -# fcmp oeq/one/olt/ogt/ole/oge -# zext/sext/trunc/bitcast/ptrtoint/inttoptr -# load/store +# 语义(2026-08-08 用户决策):不做指令解析,模板文本直接嵌入当前基本块, +# 返回 None(无返回值)。ret_ty 第二参数已废弃(兼容忽略)。 # ============================================================ LLVMIR_MAX_OPS: t.CDefine = 16 LLVMIR_TEMPLATE_BUF: t.CDefine = 512 -# ============================================================ -# _llvmir_get_op — 获取第 i 个 AsmOperand 槽位 -# ============================================================ -def _llvmir_get_op(buf: AsmOperand | t.CPtr, i: int) -> AsmOperand | t.CPtr: - """获取第 i 个操作数槽位""" - entry_size: t.CSizeT = AsmOperand.__sizeof__() - entry_addr: t.CUInt64T = t.CUInt64T(buf) + i * entry_size - return (AsmOperand | t.CPtr)(t.CVoid(entry_addr, t.CPtr)) - -# ============================================================ -# _llvmir_find_op_marker — 在字符串中查找 %__OP 并返回编号 -# -# 返回 (位置, 编号),未找到返回 (None, 0) -# ============================================================ -def _llvmir_find_op_marker(s: t.CChar | t.CPtr) -> t.CPtr: - """查找 %__OP 标记,返回标记开始位置或 None""" - if s is None: - return None - return string.strstr(s, "%__OP") - -# ============================================================ -# _llvmir_parse_op_num — 从 %__OPN__ 中解析编号 N -# -# 输入: 指向 "%__OP" 的指针 -# 返回: 操作数编号 -# ============================================================ -def _llvmir_parse_op_num(marker: t.CChar | t.CPtr) -> int: - """从 %__OPN__ 标记中解析编号 N""" - if marker is None: - return -1 - # 跳过 "%__OP" (5 字符) - num_start: t.CChar | t.CPtr = marker + 5 - if num_start is None: - return -1 - # 解析数字直到 "__" - num: int = 0 - i: t.CSizeT = 0 - ch: t.CChar = num_start[0] - while '0' <= ch <= '9': - num = num * 10 + (ch - '0') - i += 1 - ch = num_start[i] - return num - -# ============================================================ -# _llvmir_match_icmp_pred — 将预测字符串转为 ICMP 常量 -# ============================================================ -def _llvmir_match_icmp_pred(pred: str) -> int: - """将 icmp 预测字符串转为常量""" - if pred is None: - return 0 - if string.strcmp(pred, "eq") == 0: - return 0 - if string.strcmp(pred, "ne") == 0: - return 1 - if string.strcmp(pred, "sgt") == 0: - return 2 - if string.strcmp(pred, "sge") == 0: - return 3 - if string.strcmp(pred, "slt") == 0: - return 4 - if string.strcmp(pred, "sle") == 0: - return 5 - if string.strcmp(pred, "ugt") == 0: - return 6 - if string.strcmp(pred, "uge") == 0: - return 7 - if string.strcmp(pred, "ult") == 0: - return 8 - if string.strcmp(pred, "ule") == 0: - return 9 - return 0 - -# ============================================================ -# _llvmir_match_fcmp_pred — 将预测字符串转为 FCMP 常量 -# ============================================================ -def _llvmir_match_fcmp_pred(pred: str) -> int: - """将 fcmp 预测字符串转为常量""" - if pred is None: - return 0 - if string.strcmp(pred, "oeq") == 0: - return 0 - if string.strcmp(pred, "ogt") == 0: - return 1 - if string.strcmp(pred, "oge") == 0: - return 2 - if string.strcmp(pred, "olt") == 0: - return 3 - if string.strcmp(pred, "ole") == 0: - return 4 - if string.strcmp(pred, "one") == 0: - return 5 - if string.strcmp(pred, "ord") == 0: - return 6 - if string.strcmp(pred, "uno") == 0: - return 7 - if string.strcmp(pred, "ueq") == 0: - return 8 - if string.strcmp(pred, "ugt") == 0: - return 9 - if string.strcmp(pred, "uge") == 0: - return 10 - if string.strcmp(pred, "ult") == 0: - return 11 - if string.strcmp(pred, "ule") == 0: - return 12 - if string.strcmp(pred, "une") == 0: - return 13 - return 0 - -# ============================================================ -# _llvmir_extract_two_ops — 从模板中提取两个操作数编号 -# -# 通过输出参数返回 op1_num 和 op2_num -# ============================================================ -def _llvmir_extract_two_ops(template: t.CChar | t.CPtr, - out_nums: int | t.CPtr) -> int: - """从模板中提取前两个 %__OP 标记的编号 - - 结果写入 out_nums[0] 和 out_nums[1] - 返回 1 成功, 0 失败 - """ - out_nums[0] = -1 - out_nums[1] = -1 - m1: t.CChar | t.CPtr = _llvmir_find_op_marker(template) - if m1 is None: - return 0 - out_nums[0] = _llvmir_parse_op_num(m1) - - # 跳过第一个标记 "%__OPN__" - next_pos: t.CChar | t.CPtr = m1 + 5 # 跳过 "%__OP" - i: t.CSizeT = 0 - while next_pos[i] >= '0' and next_pos[i] <= '9': - i += 1 - next_pos = next_pos + i + 2 - - m2: t.CChar | t.CPtr = _llvmir_find_op_marker(next_pos) - if m2 is None: - return 1 - out_nums[1] = _llvmir_parse_op_num(m2) - return 1 - -# ============================================================ -# _llvmir_resolve_op — 根据编号解析操作数值 -# ============================================================ -def _llvmir_resolve_op(op_num: int, - all_kinds: int | t.CPtr, - all_indices: int | t.CPtr, - input_ops: AsmOperand | t.CPtr, - output_targets: AsmOperand | t.CPtr) -> llvmlite.Value | t.CPtr: - """根据操作数编号解析实际 Value""" - if op_num < 0 or op_num >= LLVMIR_MAX_OPS: - return None - kind: int = all_kinds[op_num] - idx: int = all_indices[op_num] - if kind == 0: - # 输入操作数 - op: AsmOperand | t.CPtr = _llvmir_get_op(input_ops, idx) - return op.Value - else: - # 输出操作数 - op2: AsmOperand | t.CPtr = _llvmir_get_op(output_targets, idx) - return op2.Value - -# ============================================================ -# _llvmir_store_outputs — 将结果存储到输出变量 -# ============================================================ -def _llvmir_store_outputs(pool: memhub.MemBuddy | t.CPtr, - builder: llvmlite.IRBuilder | t.CPtr, - result: llvmlite.Value | t.CPtr, - output_targets: AsmOperand | t.CPtr, - output_count: int) -> llvmlite.Value | t.CPtr: - """将结果存储到所有输出变量""" - if output_count == 0: - return result - for oi in range(output_count): - op: AsmOperand | t.CPtr = _llvmir_get_op(output_targets, oi) - if op.Value is not None and result is not None: - llvmlite.build_store(builder, result, op.Value) - return result +# c.LLVMIR LOut 唯一 SSA 寄存器名计数器(跨函数累加) +_g_llvmir_reg_seq: int = 0 # ============================================================ # translate_c_llvmir — 翻译 c.LLVMIR 内联 LLVM IR @@ -1834,53 +1653,36 @@ def translate_c_llvmir(pool: memhub.MemBuddy | t.CPtr, mod: llvmlite.LLVMModule | t.CPtr, cl: ast.Call | t.CPtr, trans: HT.Translator | t.CPtr = None) -> llvmlite.Value | t.CPtr: - """翻译 c.LLVMIR 内联 LLVM IR,返回结果 Value""" - if cl is None: + """c.LLVMIR 内联 LLVM IR:无返回值,直接嵌入原始 IR 文本 + + 不做指令解析,模板文本(c.LInp/c.LOut 替换后)用 block_append_text + 嵌入当前基本块。c.LOut 变量由唯一 SSA 寄存器 %llvmirN 接收结果, + 嵌入后自动追加 store 写回变量 alloca。返回 None(无返回值)。 + """ + if cl is None or builder is None or pool is None or trans is None: return None cargs: list[ast.AST | t.CPtr] | t.CPtr = cl.args if cargs is None or cargs.__len__() < 1: + HandlesType.fatal_error(cl, "c.LLVMIR 缺少模板参数", "TypeError") + + # LOut 写回记录(alloca 指针 + 寄存器名),最多 LLVMIR_MAX_OPS 个 + out_alloca: t.CSizeT | t.CPtr = pool.alloc(8 * LLVMIR_MAX_OPS) + out_regname: t.CSizeT | t.CPtr = pool.alloc(8 * LLVMIR_MAX_OPS) + if out_alloca is None or out_regname is None: return None + string.memset(out_alloca, 0, 8 * LLVMIR_MAX_OPS) + string.memset(out_regname, 0, 8 * LLVMIR_MAX_OPS) + out_count: int = 0 - # 分配操作数数组 - op_size: t.CSizeT = AsmOperand.__sizeof__() - input_ops: AsmOperand | t.CPtr = pool.alloc(op_size * LLVMIR_MAX_OPS) - output_targets: AsmOperand | t.CPtr = pool.alloc(op_size * LLVMIR_MAX_OPS) - if input_ops is None or output_targets is None: + # 模板文本缓冲区 + text: t.CChar | t.CPtr = pool.alloc(LLVMIR_TEMPLATE_BUF) + if text is None: return None - string.memset(input_ops, 0, op_size * LLVMIR_MAX_OPS) - string.memset(output_targets, 0, op_size * LLVMIR_MAX_OPS) - - # all_ops 映射: kinds[i]=0(inp)/1(out), indices[i]=在对应数组中的索引 - all_kinds: int | t.CPtr = pool.alloc(4 * LLVMIR_MAX_OPS) - all_indices: int | t.CPtr = pool.alloc(4 * LLVMIR_MAX_OPS) - if all_kinds is None or all_indices is None: - return None - string.memset(all_kinds, 0, 4 * LLVMIR_MAX_OPS) - string.memset(all_indices, 0, 4 * LLVMIR_MAX_OPS) - - input_count: int = 0 - output_count: int = 0 - op_seq: int = 0 - - # 分配模板缓冲区 - template: t.CChar | t.CPtr = pool.alloc(LLVMIR_TEMPLATE_BUF) - if template is None: - return None - template[0] = '\0' - - # 解析返回类型(默认 i32) - ret_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int32(pool) - if cargs.__len__() >= 2: - ret_type_node: ast.AST | t.CPtr = cargs.get(1) - if ret_type_node is not None: - resolved_ty: llvmlite.LLVMType | t.CPtr = HandlesType.resolve_annotation_type( - pool, ret_type_node, trans._imported_modules, trans._from_imports, trans) - if resolved_ty is not None: - ret_ty = resolved_ty + text[0] = '\0' # ============================================================ - # 1. 解析 IR 模板(JoinedStr 或 Constant)— 收集操作数 + # 1. 解析 IR 模板(JoinedStr 或 Constant)— 替换 LInp/LOut/表达式为值文本 # ============================================================ first_arg: ast.AST | t.CPtr = cargs.get(0) if first_arg is None: @@ -1903,275 +1705,85 @@ def translate_c_llvmir(pool: memhub.MemBuddy | t.CPtr, # 字符串字面量片段 cn: ast.Constant | t.CPtr = (ast.Constant | t.CPtr)(part) if cn.str_val is not None: - _asm_append_cstr(template, LLVMIR_TEMPLATE_BUF, cn.str_val) + _asm_append_cstr(text, LLVMIR_TEMPLATE_BUF, cn.str_val) elif pk == ast.ASTKind.FormattedValue: fv: ast.FormattedValue | t.CPtr = (ast.FormattedValue | t.CPtr)(part) fexpr: ast.AST | t.CPtr = fv.value - if fexpr is None or fexpr.kind() != ast.ASTKind.Call: - continue - fcall: ast.Call | t.CPtr = (ast.Call | t.CPtr)(fexpr) - attr_nm: str = _asm_is_c_call(fcall) - if attr_nm is None: - # 非 c.LInp/c.LOut 调用,作为普通输入处理 - ival: llvmlite.Value | t.CPtr = HandlesExpr.translate_value( - builder, pool, mod, fexpr, None, 0, trans) - if ival is not None and input_count < LLVMIR_MAX_OPS: - op_in: AsmOperand | t.CPtr = _llvmir_get_op(input_ops, input_count) - op_in.Value = ival - all_kinds[op_seq] = 0 - all_indices[op_seq] = input_count - input_count += 1 - op_seq += 1 - # 追加占位符 - viperlib.snprintf( - template + string.strlen(template), - LLVMIR_TEMPLATE_BUF - string.strlen(template), - "%%__OP%d__", op_seq - 1) + if fexpr is None: continue + # 检测 c.LInp / c.LOut + if fexpr.kind() == ast.ASTKind.Call: + fcall: ast.Call | t.CPtr = (ast.Call | t.CPtr)(fexpr) + attr_nm: str = _asm_is_c_call(fcall) + if attr_nm is not None: + fargs: list[ast.AST | t.CPtr] | t.CPtr = fcall.args + if fargs is None or fargs.__len__() < 1: + continue + val_node: ast.AST | t.CPtr = fargs.get(0) - # 处理 c.LInp / c.LOut - fargs: list[ast.AST | t.CPtr] | t.CPtr = fcall.args - if fargs is None or fargs.__len__() < 1: - continue - val_node: ast.AST | t.CPtr = fargs.get(0) + if string.strcmp(attr_nm, "LInp") == 0: + # 输入操作数:翻译值,替换为 LLVM 值引用文本(%x 或常量文本) + inp_val: llvmlite.Value | t.CPtr = HandlesExpr.translate_value( + builder, pool, mod, val_node, None, 0, trans) + if inp_val is not None and inp_val.Name is not None: + _asm_append_cstr(text, LLVMIR_TEMPLATE_BUF, inp_val.Name) - if string.strcmp(attr_nm, "LInp") == 0: - # 输入操作数:翻译值 - inp_val: llvmlite.Value | t.CPtr = HandlesExpr.translate_value( - builder, pool, mod, val_node, None, 0, trans) - if inp_val is not None and input_count < LLVMIR_MAX_OPS: - op_inp: AsmOperand | t.CPtr = _llvmir_get_op(input_ops, input_count) - op_inp.Value = inp_val - all_kinds[op_seq] = 0 - all_indices[op_seq] = input_count - input_count += 1 - op_seq += 1 - viperlib.snprintf( - template + string.strlen(template), - LLVMIR_TEMPLATE_BUF - string.strlen(template), - "%%__OP%d__", op_seq - 1) - - elif string.strcmp(attr_nm, "LOut") == 0: - # 输出操作数:获取变量 alloca - if val_node is not None and val_node.kind() == ast.ASTKind.Name: - nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(val_node) - if nm.id is not None: - alloca: llvmlite.Value | t.CPtr = HandlesVar.lookup_var(trans.SymTab, nm.id) - if alloca is not None and output_count < LLVMIR_MAX_OPS: - op_out: AsmOperand | t.CPtr = _llvmir_get_op(output_targets, output_count) - op_out.Value = alloca - all_kinds[op_seq] = 1 - all_indices[op_seq] = output_count - output_count += 1 - op_seq += 1 - viperlib.snprintf( - template + string.strlen(template), - LLVMIR_TEMPLATE_BUF - string.strlen(template), - "%%__OP%d__", op_seq - 1) + elif string.strcmp(attr_nm, "LOut") == 0: + # 输出操作数:为变量分配唯一 SSA 寄存器 %llvmirN, + # 记录写回(模板嵌入后 store 到变量 alloca) + if val_node is not None and val_node.kind() == ast.ASTKind.Name: + nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(val_node) + if nm.id is not None: + alloca: llvmlite.Value | t.CPtr = HandlesVar.lookup_var( + trans.SymTab, nm.id) + if alloca is None or out_count >= LLVMIR_MAX_OPS: + HandlesType.fatal_error( + fcall, + f"c.LOut 变量 '{nm.id}' 未定义或输出数超过 {LLVMIR_MAX_OPS}", + "TypeError") + global _g_llvmir_reg_seq + _g_llvmir_reg_seq += 1 + reg_buf: str = pool.alloc(32) + if reg_buf is not None: + viperlib.snprintf(reg_buf, 32, "%%llvmir_%d", _g_llvmir_reg_seq) + _asm_append_cstr(text, LLVMIR_TEMPLATE_BUF, reg_buf) + out_alloca[out_count] = t.CSizeT(alloca) + out_regname[out_count] = t.CSizeT(reg_buf) + out_count += 1 + continue + # 非 c.LInp/c.LOut 的 f-string 表达式:翻译值并嵌入值文本 + ival: llvmlite.Value | t.CPtr = HandlesExpr.translate_value( + builder, pool, mod, fexpr, None, 0, trans) + if ival is not None and ival.Name is not None: + _asm_append_cstr(text, LLVMIR_TEMPLATE_BUF, ival.Name) elif tk == ast.ASTKind.Constant: cn2: ast.Constant | t.CPtr = (ast.Constant | t.CPtr)(first_arg) if cn2.str_val is not None: - string.strcpy(template, cn2.str_val) + string.strcpy(text, cn2.str_val) # ============================================================ - # 2. 解析模板并生成 LLVM 指令 + # 2. 直接嵌入模板文本(不做指令解析)+ LOut 写回 # ============================================================ + llvmlite.block_append_text(pool, builder.CurBlock, text) - # 检查是否为赋值形式: %__OPN__ = <指令> - # 如果是,去掉赋值前缀,记录输出操作数编号 - assign_out_num: int = -1 - assign_marker: t.CChar | t.CPtr = _llvmir_find_op_marker(template) - if assign_marker is not None and assign_marker == template: - # 模板以 %__OP 开头 - # 查找 "=" 号 - eq_pos: t.CChar | t.CPtr = string.strchr(template, 61) # '=' = 61 - if eq_pos is not None: - # 确认 "%__OPN__ = " 格式 - assign_out_num = _llvmir_parse_op_num(assign_marker) - # 跳过 "%__OP__ = " 到实际指令开始 - # 找到 "=" 后第一个非空格字符 - instr_start: t.CChar | t.CPtr = eq_pos + 1 - while instr_start[0] == ' ' or instr_start[0] == '\t': - instr_start += 1 - # 将剩余部分复制到新模板 - tmpl2: t.CChar | t.CPtr = pool.alloc(LLVMIR_TEMPLATE_BUF) - if tmpl2 is not None: - string.strcpy(tmpl2, instr_start) - template = tmpl2 + # LOut 写回: store %llvmirN, * %var + oi: int + for oi in range(out_count): + oa: llvmlite.Value | t.CPtr = (llvmlite.Value | t.CPtr)(t.CVoid(out_alloca[oi], t.CPtr)) + rn: str = (t.CChar | t.CPtr)(t.CVoid(out_regname[oi], t.CPtr)) + if oa is None or oa.Ty is None or oa.Ty.Pointee is None or rn is None: + continue + reg_val: llvmlite.Value | t.CPtr = llvmlite.new_value(pool) + if reg_val is None: + continue + reg_val.Ty = oa.Ty.Pointee + reg_val.Name = rn + reg_val.IsConst = 0 + llvmlite.build_store(builder, reg_val, oa) - # 去除前导空格 - while template[0] == ' ' or template[0] == '\t': - template += 1 - - # 提取指令关键字(第一个单词) - instr_kw: t.CChar | t.CPtr = pool.alloc(32) - if instr_kw is None: - return None - instr_kw[0] = '\0' - ki: t.CSizeT = 0 - while template[ki] != ' ' and template[ki] != '\t' and template[ki] != '\0' and ki < 31: - instr_kw[ki] = template[ki] - ki += 1 - instr_kw[ki] = '\0' - - # ============================================================ - # 二元运算: add/sub/mul/sdiv/udiv/srem/urem/and/or/xor/shl/lshr/ashr - # ============================================================ - binop_result: llvmlite.Value | t.CPtr = None - - # 提取两个操作数编号 - op_nums: int | t.CPtr = pool.alloc(8) - if op_nums is not None: - string.memset(op_nums, 0, 8) - _llvmir_extract_two_ops(template, op_nums) - op1_num: int = -1 - op2_num: int = -1 - if op_nums is not None: - op1_num = op_nums[0] - op2_num = op_nums[1] - - lhs: llvmlite.Value | t.CPtr = _llvmir_resolve_op( - op1_num, all_kinds, all_indices, input_ops, output_targets) - rhs: llvmlite.Value | t.CPtr = _llvmir_resolve_op( - op2_num, all_kinds, all_indices, input_ops, output_targets) - - if lhs is not None and rhs is not None: - if string.strcmp(instr_kw, "add") == 0: - binop_result = llvmlite.build_add(builder, lhs, rhs) - elif string.strcmp(instr_kw, "sub") == 0: - binop_result = llvmlite.build_sub(builder, lhs, rhs) - elif string.strcmp(instr_kw, "mul") == 0: - binop_result = llvmlite.build_mul(builder, lhs, rhs) - elif string.strcmp(instr_kw, "sdiv") == 0: - binop_result = llvmlite.build_sdiv(builder, lhs, rhs) - elif string.strcmp(instr_kw, "udiv") == 0: - binop_result = llvmlite.build_udiv(builder, lhs, rhs) - elif string.strcmp(instr_kw, "srem") == 0: - binop_result = llvmlite.build_srem(builder, lhs, rhs) - elif string.strcmp(instr_kw, "urem") == 0: - binop_result = llvmlite.build_urem(builder, lhs, rhs) - elif string.strcmp(instr_kw, "and") == 0: - binop_result = llvmlite.build_and(builder, lhs, rhs) - elif string.strcmp(instr_kw, "or") == 0: - binop_result = llvmlite.build_or(builder, lhs, rhs) - elif string.strcmp(instr_kw, "xor") == 0: - binop_result = llvmlite.build_xor(builder, lhs, rhs) - elif string.strcmp(instr_kw, "shl") == 0: - binop_result = llvmlite.build_shl(builder, lhs, rhs) - elif string.strcmp(instr_kw, "lshr") == 0: - binop_result = llvmlite.build_lshr(builder, lhs, rhs) - elif string.strcmp(instr_kw, "ashr") == 0: - binop_result = llvmlite.build_ashr(builder, lhs, rhs) - elif string.strcmp(instr_kw, "fadd") == 0: - binop_result = llvmlite.build_fadd(builder, lhs, rhs) - elif string.strcmp(instr_kw, "fsub") == 0: - binop_result = llvmlite.build_fsub(builder, lhs, rhs) - elif string.strcmp(instr_kw, "fmul") == 0: - binop_result = llvmlite.build_fmul(builder, lhs, rhs) - elif string.strcmp(instr_kw, "fdiv") == 0: - binop_result = llvmlite.build_fdiv(builder, lhs, rhs) - - # ============================================================ - # icmp 比较: icmp %__OP0__, %__OP1__ - # ============================================================ - if binop_result is None and string.strcmp(instr_kw, "icmp") == 0: - # 提取预测(第二个单词) - pred_start: t.CChar | t.CPtr = template + ki + 1 - while pred_start[0] == ' ' or pred_start[0] == '\t': - pred_start += 1 - pred_str: t.CChar | t.CPtr = pool.alloc(16) - if pred_str is not None: - pred_str[0] = '\0' - pi: t.CSizeT = 0 - while pred_start[pi] != ' ' and pred_start[pi] != '\t' and pred_start[pi] != '\0' and pi < 15: - pred_str[pi] = pred_start[pi] - pi += 1 - pred_str[pi] = '\0' - pred_val: int = _llvmir_match_icmp_pred(pred_str) - if lhs is not None and rhs is not None: - binop_result = llvmlite.build_icmp(builder, pred_val, lhs, rhs) - - # ============================================================ - # fcmp 比较: fcmp %__OP0__, %__OP1__ - # ============================================================ - if binop_result is None and string.strcmp(instr_kw, "fcmp") == 0: - pred_start2: t.CChar | t.CPtr = template + ki + 1 - while pred_start2[0] == ' ' or pred_start2[0] == '\t': - pred_start2 += 1 - pred_str2: t.CChar | t.CPtr = pool.alloc(16) - if pred_str2 is not None: - pred_str2[0] = '\0' - pi2: t.CSizeT = 0 - while pred_start2[pi2] != ' ' and pred_start2[pi2] != '\t' and pred_start2[pi2] != '\0' and pi2 < 15: - pred_str2[pi2] = pred_start2[pi2] - pi2 += 1 - pred_str2[pi2] = '\0' - pred_val2: int = _llvmir_match_fcmp_pred(pred_str2) - if lhs is not None and rhs is not None: - binop_result = llvmlite.build_fcmp(builder, pred_val2, lhs, rhs) - - # ============================================================ - # store 指令: store %__OP0__, %__OP1__ - # ============================================================ - if binop_result is None and string.strcmp(instr_kw, "store") == 0: - if lhs is not None and rhs is not None: - llvmlite.build_store(builder, lhs, rhs) - return None - - # ============================================================ - # load 指令: load , %__OP0__ - # ============================================================ - if binop_result is None and string.strcmp(instr_kw, "load") == 0: - if lhs is not None: - # 从指针加载,类型由 ret_ty 指定 - binop_result = llvmlite.build_load(builder, ret_ty, lhs) - - # ============================================================ - # 类型转换: zext/sext/trunc/bitcast/ptrtoint/inttoptr - # ============================================================ - if binop_result is None: - if string.strcmp(instr_kw, "zext") == 0: - if lhs is not None: - binop_result = llvmlite.build_zext(builder, lhs, ret_ty) - elif string.strcmp(instr_kw, "sext") == 0: - if lhs is not None: - binop_result = llvmlite.build_sext(builder, lhs, ret_ty) - elif string.strcmp(instr_kw, "trunc") == 0: - if lhs is not None: - binop_result = llvmlite.build_trunc(builder, lhs, ret_ty) - elif string.strcmp(instr_kw, "bitcast") == 0: - if lhs is not None: - binop_result = llvmlite.build_bitcast(builder, lhs, ret_ty) - elif string.strcmp(instr_kw, "ptrtoint") == 0: - if lhs is not None: - binop_result = llvmlite.build_ptrtoint(builder, lhs, ret_ty) - elif string.strcmp(instr_kw, "inttoptr") == 0: - if lhs is not None: - binop_result = llvmlite.build_inttoptr(builder, lhs, ret_ty) - - # ============================================================ - # 3. 处理输出 - # ============================================================ - if binop_result is not None: - # 如果有赋值形式(%__OPN__ = ...),存储到对应输出 - if assign_out_num >= 0: - target: llvmlite.Value | t.CPtr = _llvmir_resolve_op( - assign_out_num, all_kinds, all_indices, input_ops, output_targets) - if target is not None: - llvmlite.build_store(builder, binop_result, target) - - # 存储到所有输出操作数 - _llvmir_store_outputs(pool, builder, binop_result, output_targets, output_count) - return binop_result - - # 未识别的指令:fast-fail,Python traceback 立即终止。 - # 静默返回 None 会让上层把 None 当 0 处理,产生错误 IR 或崩溃,丢失错误现场。 - HandlesType.fatal_error( - cl, - f"unsupported instruction: {instr_kw}", - "SyntaxError") + return None # ============================================================ # _apply_struct_defaults — 应用结构体字段的默认值