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:
1 parent
3a6296d638
commit
94b84c7dc1
1 file changed
+94
-482
@@ -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 — 应用结构体字段的默认值
|
||||
|
||||
Reference in new issue
Block a user