fix(codegen): split raw IR by envelope length instead of a marker string

This commit is contained in:
TermiNexus committed 2026-10-27 15:07:10 +08:00
1 parent 9e47c0ebc4
commit e761a85ca7
1 file changed
+51 -19
+51 -19
View File
@@ -56,7 +56,41 @@ MLIR_TRANSLATE_CMD: str = "mlir-translate"
# body behaves like inline IR again.
LLVM_LINK_CMD: str = "llvm-link"
INLINE_PASSES: str = "always-inline,globaldce"
define RAW_LLVM_MARKER = "//__VPC_RAW_LLVM__"
define RAW_ENVELOPE_PREFIX = "//__VPC_RAWIR__ "
def _parse_raw_envelope(ir_buf: bytes, ir_len: sizet, inline_out: int*, raw_len_out: sizet*) -> sizet:
"""Parse the FULL-artifact envelope written by mlirlite.
Format: "<prefix><inline 0|1> <raw byte length>\n<raw LLVM text><MLIR module>".
Returns the raw section's start offset (0 = no envelope) and fills the flag/length outputs.
"""
if inline_out is not None: inline_out[0] = 0
if raw_len_out is not None: raw_len_out[0] = 0
if ir_buf is None: return 0
plen: sizet = string.strlen(RAW_ENVELOPE_PREFIX)
if ir_len <= plen + 3: return 0
if string.strncmp(ir_buf, RAW_ENVELOPE_PREFIX, plen) != 0: return 0
i: sizet = plen
while i < ir_len and ir_buf[i] == ' ': i += 1
if i >= ir_len or (ir_buf[i] != '0' and ir_buf[i] != '1'): return 0
inl: int = 0
if ir_buf[i] == '1': inl = 1
i += 1
while i < ir_len and ir_buf[i] == ' ': i += 1
rl: sizet = 0
digits: int = 0
while i < ir_len and ir_buf[i] >= '0' and ir_buf[i] <= '9':
rl = rl * 10 + sizet(int(ir_buf[i]) - 48)
i += 1
digits += 1
if digits == 0: return 0
while i < ir_len and ir_buf[i] == '\r': i += 1
if i >= ir_len or ir_buf[i] != '\n': return 0
if inline_out is not None: inline_out[0] = inl
if raw_len_out is not None: raw_len_out[0] = rl
return i + 1
def _file_exists(path: str) -> int:
@@ -355,19 +389,20 @@ def build_sliced_path(base_dir: str, sha1: str, ext: str) -> str:
def write_ir_to_file(ir_buf: bytes, ir_len: sizet, output_dir: str, module_name: str) -> int:
"""Write the IR buffer to <sha1>.ll; raw LLVM text is split into <sha1>.raw.ll."""
"""Write the IR buffer to <sha1>.ll; the envelope's raw LLVM text becomes <sha1>.raw.ll."""
if ir_buf is None or output_dir is None or module_name is None: return 1
# Raw LLVM functions (__llvmir__) follow a marker after the MLIR module: split them out so
# mlir-opt only ever receives the MLIR module.
raw_pos: str = string.strstr(ir_buf, RAW_LLVM_MARKER)
mlir_len: sizet = ir_len
raw_start: sizet = 0
if raw_pos is not None:
mlir_len = sizet(uint64(raw_pos) - uint64(ir_buf))
raw_start = mlir_len + string.strlen(RAW_LLVM_MARKER)
while raw_start < ir_len and (ir_buf[raw_start] == '\r' or ir_buf[raw_start] == '\n'):
raw_start += 1
# FULL artifacts carry a length-prefixed envelope (see _parse_raw_envelope); STUB/TEXT
# artifacts have none and are written verbatim.
inline_flag: int = 0
raw_len: sizet = 0
raw_start: sizet = _parse_raw_envelope(ir_buf, ir_len, &inline_flag, &raw_len)
if raw_start > ir_len: raw_start = ir_len
if raw_len > ir_len - raw_start: raw_len = ir_len - raw_start
mlir_start: sizet = raw_start
if raw_len > 0: mlir_start = raw_start + raw_len
if mlir_start > ir_len: mlir_start = ir_len
mlir_len: sizet = ir_len - mlir_start
# build sliced path: output_dir/{sha1 prefix}/{module_name}.ll
path: str = build_sliced_path(output_dir, module_name, "ll")
@@ -377,25 +412,22 @@ def write_ir_to_file(ir_buf: bytes, ir_len: sizet, output_dir: str, module_name:
f: io.File* = io.File(path, io.MODE.W)
if f.closed: return 1
written: int64 = f.write(ir_buf, mlir_len)
written: int64 = f.write(ir_buf + mlir_start, mlir_len)
f.close()
if written < 0: return 1
if raw_pos is not None and ir_len > raw_start:
if raw_len > 0:
raw_path: str = build_sliced_path(output_dir, module_name, "raw.ll")
if raw_path is None: return 1
rf: io.File* = io.File(raw_path, io.MODE.W)
if rf.closed: return 1
rw: int64 = rf.write(ir_buf + raw_start, ir_len - raw_start)
rw: int64 = rf.write(ir_buf + raw_start, raw_len)
rf.close()
if rw < 0: return 1
# Inline-pass marker: raw LLVM functions and/or a raw-MLIR body (__mlir__) are present, so
# the object must go through opt -passes=always-inline,globaldce before llc.
need_inline: int = 0
if raw_pos is not None: need_inline = 1
elif string.strstr(ir_buf, ".__vpc_mlir_") is not None: need_inline = 1
if need_inline != 0:
if inline_flag != 0 or raw_len > 0:
flag_path: str = build_sliced_path(output_dir, module_name, "inline")
if flag_path is None: return 1
ff: io.File* = io.File(flag_path, io.MODE.W)