feat(mir/llvm): Phase 273 P0-P1 DomainPlan→CorePlan + LLVM arg fix

Phase 273 P0-P1: Two-layer plan architecture
- DomainPlan: Pattern-specific knowledge (ScanWithInit)
- CorePlan: Fixed vocabulary (Seq, Loop, If, Effect, Exit)
- ValueId references only (String expressions forbidden)
- Pipeline: Extractor→Normalizer→Verifier→Lowerer

New plan/ module:
- mod.rs: Type definitions, SSOT spec
- normalizer.rs: DomainPlan→CorePlan + ID allocation
- verifier.rs: V1-V6 invariant checks (fail-fast)
- lowerer.rs: CorePlan→MIR (pattern-agnostic)

LLVM fix (ChatGPT):
- function_lower.py: Fix argument reference bug
- Phase 258 index_of_string now PASS on LLVM backend

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
2025-12-22 22:42:56 +09:00
parent f07c2e7874
commit 960241795d
20 changed files with 1728 additions and 388 deletions

View File

@ -104,38 +104,76 @@ def lower_function(builder, func_data: Dict[str, Any]):
if func is None:
func = ir.Function(builder.module, func_ty, name=name)
# Map parameters to vmap. Prefer mapping by referenced value-ids that have no
# local definition (common in v0 JSON where params appear as lhs/rhs ids).
# Map parameters to vmap.
#
# SSOT: If `func_data["params"]` is present, it defines the ValueId ↔ arg position contract.
# Use it first to avoid heuristic mis-mapping (which can silently ignore some parameters).
#
# Fallback: If params are missing (older JSON / legacy emit), use a heuristic:
# - map "used but not defined" ValueIds to args in ascending ValueId order.
try:
arity = len(func.args)
# Collect defined and used ids
defs = set()
uses = set()
for bb in (blocks or []):
for ins in (bb.get('instructions') or []):
try:
dstv = ins.get('dst')
if isinstance(dstv, int):
defs.add(int(dstv))
except Exception:
pass
for k in ('lhs','rhs','value','cond','box_val'):
params_list = func_data.get("params", []) or []
if (
isinstance(params_list, list)
and len(params_list) == arity
and all(isinstance(v, int) for v in params_list)
):
for i in range(arity):
builder.vmap[int(params_list[i])] = func.args[i]
else:
# Collect defined and used ids
defs = set()
uses = set()
for bb in (blocks or []):
for ins in (bb.get('instructions') or []):
try:
v = ins.get(k)
if isinstance(v, int):
uses.add(int(v))
dstv = ins.get('dst')
if isinstance(dstv, int):
defs.add(int(dstv))
except Exception:
pass
cand = [vid for vid in uses if vid not in defs]
cand.sort()
mapped = 0
for i in range(min(arity, len(cand))):
builder.vmap[int(cand[i])] = func.args[i]
mapped += 1
# Fallback: also map positional 0..arity-1 to args if not already mapped
for i in range(arity):
if i not in builder.vmap:
builder.vmap[i] = func.args[i]
for k in ('lhs', 'rhs', 'value', 'cond', 'box_val', 'box', 'src'):
try:
v = ins.get(k)
if isinstance(v, int):
uses.add(int(v))
except Exception:
pass
# List operands
try:
a = ins.get('args')
if isinstance(a, list):
for v in a:
if isinstance(v, int):
uses.add(int(v))
except Exception:
pass
# Unified calls: mir_call.args
try:
mc = ins.get('mir_call')
if isinstance(mc, dict):
a = mc.get('args')
if isinstance(a, list):
for v in a:
if isinstance(v, int):
uses.add(int(v))
except Exception:
pass
cand = [vid for vid in uses if vid not in defs]
cand.sort()
for i in range(min(arity, len(cand))):
builder.vmap[int(cand[i])] = func.args[i]
# Legacy fallback: map positional 0..arity-1 only when params are missing.
for i in range(arity):
if i not in builder.vmap:
builder.vmap[i] = func.args[i]
except Exception:
pass