From e761a85ca766ada64072082173bed674263fef57 Mon Sep 17 00:00:00 2001 From: TermiNexus Date: Tue, 27 Oct 2026 15:06:36 +0800 Subject: [PATCH] fix(codegen): split raw IR by envelope length instead of a marker string --- App/lib/Phase/BuildPipeline.vp | 70 +++++++++++++++++++++++++--------- 1 file changed, 51 insertions(+), 19 deletions(-) diff --git a/App/lib/Phase/BuildPipeline.vp b/App/lib/Phase/BuildPipeline.vp index 70b34b0..ffeb2c6 100644 --- a/App/lib/Phase/BuildPipeline.vp +++ b/App/lib/Phase/BuildPipeline.vp @@ -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: " \n". + 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 .ll; raw LLVM text is split into .raw.ll.""" + """Write the IR buffer to .ll; the envelope's raw LLVM text becomes .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)