把 includes 下 64 个 .vp 的文件头注释(含 traceback.vp 第 13-427 行的整块文件级说明)以及 2 处漏网的正文中文注释(ast/lexer.vp、json/__writer.vp)与 1 处中文 docstring(memhub.vp)逐行译为英文;同步把 fltk/gen_ffi.py 的生成模板与其自身注释英文化,使重新生成仍为英文。 只改注释/文档串文字:行数与代码逐字节不变(骨架比对 140 文件漂移 0),运行时中文字符串字面量 305 处保持原样。验证:三重重编 SUCCESS(170.21s)+ 全量 77/77 顺序回归通过 + VET 编译 SUCCESS / --search-paths 7 条 exit 0。
462 lines
19 KiB
Plaintext
462 lines
19 KiB
Plaintext
import t, c
|
|
from stdint import *
|
|
import memhub
|
|
import string
|
|
import viperlib
|
|
|
|
# ============================================================
|
|
# mlirlite -- an MLIR (llvm dialect) text emission library, isomorphic to llvmlite name for name
|
|
#
|
|
# Design principles:
|
|
# * The internal model (LLVMType/Value/Function/BasicBlock/IRBuilder/Module...) is
|
|
# **isomorphic to includes/llvmlite name for name and signature for signature**, so on the TPV side it suffices to rename
|
|
# `llvmlite.` to `mlirlite.` in order to compile;
|
|
# * The difference lies only in the "printing" stage: TypePrint / ValuePrint / FunctionPrint /
|
|
# LLVMModulePrint emit MLIR text, while the builders still generate the intermediate instruction text as before;
|
|
# * Names keep the LLVMxxx form (isomorphism first). See README.md for semantic differences.
|
|
# ============================================================
|
|
|
|
# Import submodules
|
|
from .__types import (
|
|
LLVMType, ParamNode, LLVMTypeCore,
|
|
Int1, Int8, Int16, Int32, Int64, Ptr, Func, Void, Array, Struct,
|
|
Half, Float, Double, FP128, Label,
|
|
new_param_node, param_list_append,
|
|
paramnode_get_ty, paramnode_get_next, paramnode_set_ty, paramnode_set_next,
|
|
TypePrint, PrintStructDefinition, get_struct_name,
|
|
get_struct_fields, get_struct_fcount, DeepCopyType,
|
|
)
|
|
from .__values import (
|
|
Value, new_value, ConstInt, ConstNull, ConstZero, ConstFloat, SSAValue, ValuePrint,
|
|
value_get_ty, value_get_next,
|
|
value_set_ty, value_set_next, value_set_name, value_set_isconst,
|
|
)
|
|
from .__function import (
|
|
Line, BasicBlock, Param, Function,
|
|
new_line, new_basic_block, new_param, new_function,
|
|
function_add_param, function_add_block,
|
|
block_append_line, block_append_text,
|
|
function_set_attrs, param_set_attrs,
|
|
function_set_attr_group,
|
|
function_set_dbg,
|
|
function_get_name, function_get_name_len, function_get_ret_ty, function_get_params,
|
|
function_get_param_head, function_get_next, function_is_declared,
|
|
param_get_name, param_get_ty, param_get_next,
|
|
FunctionPrint, G_PeepEnable,
|
|
DebugSetEnabled, DebugIsEnabled, DebugNoteFunc, DebugClearFunc,
|
|
DebugNoteLine, DebugResetFunc, DebugTakeText,
|
|
)
|
|
from .__module import (
|
|
LLVMModule, GlobalVariable, NamedTypeNode, DINode, DINamedMeta,
|
|
new_module, new_global_variable,
|
|
module_add_function, module_add_global, module_add_named_type,
|
|
module_set_named_type_packed,
|
|
module_set_target, module_set_datalayout,
|
|
module_add_di_node, module_add_named_metadata,
|
|
global_set_constant, global_set_linkage, global_set_unnamed_addr, global_set_section,
|
|
LLVMModulePrint, OUTPUT_FULL, OUTPUT_STUB, OUTPUT_TEXT,
|
|
module_ensure_opaque_for_type,
|
|
)
|
|
from .__builder import (
|
|
IRBuilder, new_builder, position_at_end,
|
|
builder_cur_block_is_terminated,
|
|
builder_set_debug_location, builder_clear_debug_location,
|
|
build_alloca, build_alloca_aligned, build_alloca_at_entry, build_load, build_store,
|
|
build_add, build_sub, build_mul, build_sdiv, build_udiv, build_srem, build_urem,
|
|
build_and, build_or, build_xor, build_shl, build_lshr, build_ashr,
|
|
build_fadd, build_fsub, build_fmul, build_fdiv, build_frem, build_fneg,
|
|
build_icmp, build_fcmp,
|
|
build_br, build_cond_br, build_ret, build_ret_void,
|
|
build_call, build_call_indirect, build_bitcast, build_sext, build_trunc, build_zext,
|
|
build_ptrtoint, build_inttoptr,
|
|
build_fpext, build_fptrunc, build_fp2si, build_si2fp, build_fp2ui, build_ui2fp,
|
|
build_gep, build_gep_array, build_gep_struct,
|
|
build_phi, build_switch, build_select, build_unreachable,
|
|
build_atomicrmw, build_cmpxchg, build_inline_asm, build_va_arg,
|
|
PhiIncoming, new_phi_incoming, SwitchCase, new_switch_case,
|
|
ICMP_EQ, ICMP_NE, ICMP_SGT, ICMP_SGE, ICMP_SLT, ICMP_SLE,
|
|
ICMP_UGT, ICMP_UGE, ICMP_ULT, ICMP_ULE,
|
|
FCMP_FALSE, FCMP_OEQ, FCMP_OGT, FCMP_OGE, FCMP_OLT, FCMP_OLE,
|
|
FCMP_ONE, FCMP_ORD, FCMP_UNO, FCMP_UEQ, FCMP_UGT, FCMP_UGE,
|
|
FCMP_ULT, FCMP_ULE, FCMP_UNE, FCMP_TRUE,
|
|
ATOMIC_XCHG, ATOMIC_ADD, ATOMIC_SUB, ATOMIC_AND, ATOMIC_NAND,
|
|
ATOMIC_OR, ATOMIC_XOR, ATOMIC_MAX, ATOMIC_MIN, ATOMIC_UMAX, ATOMIC_UMIN,
|
|
ATOMIC_ORDER_NOTATOMIC, ATOMIC_ORDER_UNORDERED, ATOMIC_ORDER_MONOTONIC,
|
|
ATOMIC_ORDER_ACQUIRE, ATOMIC_ORDER_RELEASE, ATOMIC_ORDER_ACQ_REL,
|
|
ATOMIC_ORDER_SEQ_CST,
|
|
)
|
|
from .__verify import (
|
|
VerifyResult, NameEntry,
|
|
verify_function, verify_module,
|
|
VERIFY_OK, VERIFY_ERR_NO_TERMINATOR, VERIFY_ERR_DUPLICATE_DEF,
|
|
VERIFY_ERR_UNDEFINED_USE, VERIFY_ERR_PHI_NOT_FIRST,
|
|
_new_verify_result,
|
|
)
|
|
|
|
|
|
# ============================================================
|
|
# Convenience factory: string copy
|
|
# ============================================================
|
|
def _str_dup(pool: memhub.MemBuddy*, src: str) -> str:
|
|
"""Allocate from pool and copy a C string."""
|
|
if src is None: return None
|
|
slen: sizet = string.strlen(src)
|
|
buf: str = pool.alloc(slen + 1)
|
|
if buf is None: return None
|
|
string.strcpy(buf, src)
|
|
return buf
|
|
|
|
|
|
# ============================================================
|
|
# Convenience factory: create a named basic block
|
|
# ============================================================
|
|
def create_block(pool: memhub.MemBuddy*, func: Function*,
|
|
name: str) -> BasicBlock*:
|
|
"""Create a basic block and add it to the function."""
|
|
# Block-name/param conflict guard: block label "entry:" is value %entry, so a param %entry
|
|
# collides; on collision append .1/.2/... (strip a leading % from Param.Name before comparing).
|
|
use_name: str = name
|
|
if func is not None and func.Params is not None and name is not None \
|
|
and name[0] != '\0':
|
|
cb_len: sizet = string.strlen(name) + 16
|
|
cb_buf: str = pool.alloc(cb_len)
|
|
if cb_buf is not None:
|
|
cb_k: int = 1
|
|
cb_collide: int = 1
|
|
while cb_collide != 0:
|
|
cb_collide = 0
|
|
cb_p: Param* = function_get_param_head(func)
|
|
while cb_p is not None:
|
|
cb_pnm: str = param_get_name(cb_p)
|
|
if cb_pnm is not None:
|
|
cb_pv: str = cb_pnm
|
|
if cb_pv[0] == '%':
|
|
cb_pv = cb_pv + 1
|
|
if string.strcmp(cb_pv, use_name) == 0:
|
|
cb_collide = 1
|
|
break
|
|
cb_p = param_get_next(cb_p)
|
|
if cb_collide != 0:
|
|
viperlib.snprintf(cb_buf, cb_len, "%s.%d", name, cb_k)
|
|
use_name = cb_buf
|
|
cb_k += 1
|
|
name_dup: str = _str_dup(pool, use_name)
|
|
blk: BasicBlock* = new_basic_block(pool, name_dup)
|
|
if blk is not None:
|
|
function_add_block(func, blk)
|
|
return blk
|
|
|
|
|
|
# ============================================================
|
|
# Convenience factory: create an integer constant value
|
|
# ============================================================
|
|
def const_int(pool: memhub.MemBuddy*, bits: int,
|
|
val: int64) -> Value*:
|
|
"""Create an integer constant value (auto-creates type + name text).
|
|
bits: bit width (1/8/16/32/64); val: integer value.
|
|
"""
|
|
# create type
|
|
ty: LLVMType* = pool.alloc(LLVMType.__sizeof__())
|
|
if ty is None: return None
|
|
string.memset(ty, 0, LLVMType.__sizeof__())
|
|
c.DerefAs(ty, LLVMType.Int(bits))
|
|
|
|
# create name text
|
|
name: str = pool.alloc(32)
|
|
if name is None: return None
|
|
# LLVM i64 literals exclude INT64_MIN: represent it as the unsigned bit pattern
|
|
# 9223372036854775808 (accepted by LLVM), else opt rejects "-9223372036854775808".
|
|
if bits == 64 and val == -9223372036854775807 - 1:
|
|
viperlib.snprintf(name, 32, "9223372036854775808")
|
|
else:
|
|
viperlib.snprintf(name, 32, "%lld", val)
|
|
|
|
return ConstInt(pool, ty, val, name)
|
|
|
|
|
|
def const_int32(pool: memhub.MemBuddy*, val: int64) -> Value*:
|
|
"""Convenience: create an i32 integer constant."""
|
|
return const_int(pool, 32, val)
|
|
|
|
|
|
def const_int64(pool: memhub.MemBuddy*, val: int64) -> Value*:
|
|
"""Convenience: create an i64 integer constant."""
|
|
return const_int(pool, 64, val)
|
|
|
|
|
|
# ============================================================
|
|
# Convenience factory: create a function and add it to the module
|
|
# ============================================================
|
|
def create_function(pool: memhub.MemBuddy*, mod: LLVMModule*,
|
|
name: str, ret_ty: LLVMType*) -> Function*:
|
|
"""Create a function and add it to the module."""
|
|
name_dup: str = _str_dup(pool, name)
|
|
func: Function* = new_function(pool, name_dup, ret_ty)
|
|
if func is not None:
|
|
module_add_function(mod, func)
|
|
return func
|
|
|
|
|
|
def add_param(pool: memhub.MemBuddy*, func: Function*,
|
|
ty: LLVMType*, name: str) -> Param*:
|
|
"""Create a parameter and add it to the function."""
|
|
name_dup: str = _str_dup(pool, name)
|
|
param: Param* = new_param(pool, ty, name_dup)
|
|
if param is not None:
|
|
function_add_param(func, param)
|
|
return param
|
|
|
|
|
|
# ============================================================
|
|
# Convenience factory: create a function declaration (declare)
|
|
# ============================================================
|
|
def create_declare(pool: memhub.MemBuddy*, mod: LLVMModule*,
|
|
name: str, ret_ty: LLVMType*) -> Function*:
|
|
"""Create a function declaration (declare, no body) and add it to the module.
|
|
Unlike create_function, it emits only: declare <ret_ty> @<name>(<params>)
|
|
"""
|
|
name_dup: str = _str_dup(pool, name)
|
|
func: Function* = new_function(pool, name_dup, ret_ty)
|
|
if func is not None:
|
|
func.IsDeclared = 1
|
|
module_add_function(mod, func)
|
|
return func
|
|
|
|
|
|
# ============================================================
|
|
# Convenience factory: create a string-constant global variable
|
|
#
|
|
# The initializer is stored in gv.Initializer as llvmlite-shaped LLVM syntax text (c"contents\00");
|
|
# the MLIR render stage (__module.vp/_MlirGlobalInit) converts it to the attribute form "contents".
|
|
# ============================================================
|
|
def create_global_string(pool: memhub.MemBuddy*, mod: LLVMModule*,
|
|
name: str, text: str) -> GlobalVariable*:
|
|
"""Create a string-constant global variable and add it to the module.
|
|
name: global name (e.g. ".str"); text: C string without trailing NUL (added automatically).
|
|
Returns: GlobalVariable pointer of type [len+1 x i8].
|
|
"""
|
|
if text is None: return None
|
|
slen: sizet = string.strlen(text)
|
|
count: int = slen + 1 # includes the trailing NUL
|
|
|
|
# create i8 type
|
|
i8_ty: LLVMType* = pool.alloc(LLVMType.__sizeof__())
|
|
if i8_ty is None: return None
|
|
string.memset(i8_ty, 0, LLVMType.__sizeof__())
|
|
c.DerefAs(i8_ty, LLVMType.Int(8))
|
|
|
|
# create [count x i8] array type
|
|
arr_ty: LLVMType* = pool.alloc(LLVMType.__sizeof__())
|
|
if arr_ty is None: return None
|
|
string.memset(arr_ty, 0, LLVMType.__sizeof__())
|
|
c.DerefAs(arr_ty, LLVMType.Array(i8_ty, count))
|
|
|
|
# create global variable
|
|
name_dup: str = _str_dup(pool, name)
|
|
gv: GlobalVariable* = new_global_variable(pool, name_dup, arr_ty)
|
|
if gv is None: return None
|
|
|
|
# set attributes: private + unnamed_addr + constant
|
|
global_set_linkage(gv, "private")
|
|
global_set_unnamed_addr(gv, 1)
|
|
global_set_constant(gv, 1)
|
|
|
|
# Build initializer text c"contents\00": LLVM IR string literal c"<chars>" with " \ and
|
|
# non-printables escaped as \xx; buffer sized for worst case (4 bytes/char) + c"..." + \00 + "
|
|
init_buf: str = pool.alloc(slen * 4 + 8)
|
|
if init_buf is None: return None
|
|
pos: sizet = 0
|
|
init_buf[pos] = 'c'
|
|
pos += 1
|
|
init_buf[pos] = '"'
|
|
pos += 1
|
|
for i in range(slen):
|
|
ch: uint8 = text[i]
|
|
if ch == 0x22 or ch == 0x5C or ch < 0x20 or ch >= 0x7F:
|
|
# escape: " -> \22, \ -> \5c, non-printable -> \xx
|
|
init_buf[pos] = '\\'
|
|
pos += 1
|
|
hi: int = (ch >> 4) & 0x0F
|
|
lo: int = ch & 0x0F
|
|
if hi < 10:
|
|
init_buf[pos] = 0x30 + hi
|
|
else:
|
|
init_buf[pos] = 0x61 + hi - 10
|
|
pos += 1
|
|
if lo < 10:
|
|
init_buf[pos] = 0x30 + lo
|
|
else:
|
|
init_buf[pos] = 0x61 + lo - 10
|
|
pos += 1
|
|
else:
|
|
init_buf[pos] = ch
|
|
pos += 1
|
|
# trailing NUL byte
|
|
init_buf[pos] = '\\'
|
|
pos += 1
|
|
init_buf[pos] = '0'
|
|
pos += 1
|
|
init_buf[pos] = '0'
|
|
pos += 1
|
|
init_buf[pos] = '"'
|
|
pos += 1
|
|
init_buf[pos] = '\0'
|
|
gv.Initializer = init_buf
|
|
|
|
module_add_global(mod, gv)
|
|
return gv
|
|
|
|
|
|
# ============================================================
|
|
# Convenience factory: create an integer global with an initializer
|
|
# ============================================================
|
|
def create_global_int(pool: memhub.MemBuddy*, mod: LLVMModule*,
|
|
name: str, bits: int, val: int64) -> GlobalVariable*:
|
|
"""Create an integer global variable and add it to the module.
|
|
MLIR output: llvm.mlir.global @<name>(<val> : i<bits>) : i<bits>
|
|
"""
|
|
# create integer type
|
|
ty: LLVMType* = pool.alloc(LLVMType.__sizeof__())
|
|
if ty is None: return None
|
|
string.memset(ty, 0, LLVMType.__sizeof__())
|
|
c.DerefAs(ty, LLVMType.Int(bits))
|
|
|
|
name_dup: str = _str_dup(pool, name)
|
|
gv: GlobalVariable* = new_global_variable(pool, name_dup, ty)
|
|
if gv is None: return None
|
|
|
|
# build initializer text "42" (the type is printed separately by the global render stage)
|
|
init_buf: str = pool.alloc(48)
|
|
if init_buf is None: return None
|
|
viperlib.snprintf(init_buf, 48, "%lld", val)
|
|
gv.Initializer = init_buf
|
|
|
|
module_add_global(mod, gv)
|
|
return gv
|
|
|
|
|
|
# ============================================================
|
|
# LLVMModuleCore: module/function/value creation core; wraps pool to avoid passing it repeatedly
|
|
#
|
|
# Usage:
|
|
# mcore: rawptr[LLVMModuleCore] = LLVMModuleCore(pool)
|
|
# mod: rawptr[LLVMModule] = mcore.NewModule("test")
|
|
# func: rawptr[Function] = mcore.CreateFunction(mod, "add", ty_i32)
|
|
# val: rawptr[Value] = mcore.ConstInt32(42)
|
|
# ============================================================
|
|
@t.NoVTable
|
|
class LLVMModuleCore:
|
|
"""Module/function/value creation core; wraps pool so callers need not pass it."""
|
|
Pool: memhub.MemBuddy*
|
|
|
|
def __init__(self, pool: memhub.MemBuddy*):
|
|
self.Pool = pool
|
|
|
|
# ---- module operations ----
|
|
def NewModule(self, name: str) -> LLVMModule*:
|
|
return new_module(self.Pool, name)
|
|
|
|
def CreateFunction(self, mod: LLVMModule*, name: str,
|
|
ret_ty: LLVMType*) -> Function*:
|
|
return create_function(self.Pool, mod, name, ret_ty)
|
|
|
|
def CreateDeclare(self, mod: LLVMModule*, name: str,
|
|
ret_ty: LLVMType*) -> Function*:
|
|
"""Create a function declaration (declare, no body)."""
|
|
return create_declare(self.Pool, mod, name, ret_ty)
|
|
|
|
def AddParam(self, func: Function*, ty: LLVMType*,
|
|
name: str) -> Param*:
|
|
return add_param(self.Pool, func, ty, name)
|
|
|
|
def FunctionSetAttrs(self, func: Function*, attrs: str):
|
|
"""Set the function-level attribute text."""
|
|
function_set_attrs(func, attrs)
|
|
|
|
def ParamSetAttrs(self, param: Param*, attrs: str):
|
|
"""Set the parameter attribute text."""
|
|
param_set_attrs(param, attrs)
|
|
|
|
def CreateBlock(self, func: Function*,
|
|
name: str) -> BasicBlock*:
|
|
return create_block(self.Pool, func, name)
|
|
|
|
def NewBuilder(self, func: Function*) -> IRBuilder*:
|
|
return new_builder(self.Pool, func)
|
|
|
|
# ---- globals ----
|
|
def NewGlobal(self, mod: LLVMModule*, name: str,
|
|
ty: LLVMType*) -> GlobalVariable*:
|
|
"""Create a global variable and add it to the module."""
|
|
name_dup: str = _str_dup(self.Pool, name)
|
|
gv: GlobalVariable* = new_global_variable(self.Pool, name_dup, ty)
|
|
if gv is not None:
|
|
module_add_global(mod, gv)
|
|
return gv
|
|
|
|
def CreateGlobalString(self, mod: LLVMModule*, name: str,
|
|
text: str) -> GlobalVariable*:
|
|
"""Create a string-constant global variable."""
|
|
return create_global_string(self.Pool, mod, name, text)
|
|
|
|
def CreateGlobalInt(self, mod: LLVMModule*, name: str,
|
|
bits: int, val: int64) -> GlobalVariable*:
|
|
"""Create an integer global with an initializer."""
|
|
return create_global_int(self.Pool, mod, name, bits, val)
|
|
|
|
def GlobalSetConstant(self, gv: GlobalVariable*, is_const: int):
|
|
global_set_constant(gv, is_const)
|
|
|
|
def GlobalSetLinkage(self, gv: GlobalVariable*, linkage: str):
|
|
global_set_linkage(gv, linkage)
|
|
|
|
def GlobalSetUnnamedAddr(self, gv: GlobalVariable*, level: int):
|
|
global_set_unnamed_addr(gv, level)
|
|
|
|
def GlobalSetSection(self, gv: GlobalVariable*, section: str):
|
|
global_set_section(gv, section)
|
|
|
|
# ---- value creation ----
|
|
def ConstInt(self, bits: int, val: int64) -> Value*:
|
|
return const_int(self.Pool, bits, val)
|
|
|
|
def ConstInt32(self, val: int64) -> Value*:
|
|
return const_int32(self.Pool, val)
|
|
|
|
def ConstInt64(self, val: int64) -> Value*:
|
|
return const_int64(self.Pool, val)
|
|
|
|
def ConstFloat(self, ty: LLVMType*, val: double) -> Value*:
|
|
return ConstFloat(self.Pool, ty, val)
|
|
|
|
def SSAValue(self, ty: LLVMType*, name: str) -> Value*:
|
|
return SSAValue(self.Pool, ty, name)
|
|
|
|
def ConstNull(self, ty: LLVMType*, name: str) -> Value*:
|
|
return ConstNull(self.Pool, ty, name)
|
|
|
|
# ---- printing ----
|
|
def PrintValue(self, buf: str, size: sizet, val: Value*):
|
|
ValuePrint(buf, size, val, self.Pool)
|
|
|
|
def PrintFunction(self, buf: str, size: sizet, func: Function*):
|
|
FunctionPrint(buf, size, func, self.Pool)
|
|
|
|
def PrintModule(self, buf: str, size: sizet, mod: LLVMModule*):
|
|
LLVMModulePrint(buf, size, mod, self.Pool, OUTPUT_FULL)
|
|
|
|
# ---- SSA verification ----
|
|
def NewVerifyResult(self, buf_size: sizet) -> VerifyResult*:
|
|
"""Create a verify-result object (buf_size = error message buffer size)."""
|
|
return _new_verify_result(self.Pool, buf_size)
|
|
|
|
def VerifyFunction(self, func: Function*,
|
|
result: VerifyResult*) -> int:
|
|
"""Verify SSA correctness of one function; returns error count (0 = pass)."""
|
|
return verify_function(self.Pool, func, result)
|
|
|
|
def VerifyModule(self, mod: LLVMModule*,
|
|
result: VerifyResult*) -> int:
|
|
"""Verify SSA correctness of all functions in the module; returns error count (0 = pass)."""
|
|
return verify_module(self.Pool, mod, result)
|