refactor(compiler): c.LLVMIR 改无返回值直接嵌入 IR 文本(不做指令解析)

translate_c_llvmir 重写:LInp 替换为值引用文本、LOut 分配唯一 SSA
寄存器 %llvmirN 并自动 store 写回变量 alloca;模板经 block_append_text
直接嵌入当前基本块;返回 None(ret_ty 废弃)。删除 9 个旧指令解析
辅助函数。
This commit is contained in:
TermiNexus committed 2026-08-08 16:10:29 +08:00
1 parent 3a6296d638
commit 94b84c7dc1
1 file changed
+94 -482
+94 -482
View File
@@ -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 <ty> %llvmirN, <ty>* %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<digits>__ = " 到实际指令开始
# 找到 "=" 后第一个非空格字符
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 <ty> %llvmirN, <ty>* %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 <pred> <ty> %__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 <pred> <ty> %__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 <ty> %__OP0__, <ty> %__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 <ty>, <ty> %__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 — 应用结构体字段的默认值