-
Notifications
You must be signed in to change notification settings - Fork 2
Expand file tree
/
Copy pathemit_llvm_module.py
More file actions
105 lines (79 loc) · 3.8 KB
/
emit_llvm_module.py
File metadata and controls
105 lines (79 loc) · 3.8 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
#!/usr/bin/env python3
"""Emit/check the Example 05 LLVM module from its published lowering.
Compatibility wrapper around the generic lowered-unit-kind LLVM emitter.
"""
from __future__ import annotations
import argparse
import subprocess
import sys
from pathlib import Path
try:
from .llvm_lowering_emitter import LLVMEmissionError, emit_llvm_from_lowering_path, normalize_text, write_text
except ImportError: # pragma: no cover
from llvm_lowering_emitter import LLVMEmissionError, emit_llvm_from_lowering_path, normalize_text, write_text # type: ignore
ROOT = Path(__file__).resolve().parents[4]
DEFAULT_LOWERING = ROOT / "Examples" / "05_bounded_ui_accumulator" / "main.lowering.json"
DEFAULT_EXPECTED_MODULE = ROOT / "Implementations" / "Reference" / "LLVM" / "examples" / "05_bounded_ui_accumulator" / "module.ll"
DEFAULT_EXAMPLE_DIR = DEFAULT_EXPECTED_MODULE.parent
def check_expected(generated: str, expected_path: Path) -> bool:
expected = expected_path.read_text(encoding="utf-8")
return normalize_text(generated) == normalize_text(expected)
def run_build(example_dir: Path) -> int:
build_script = example_dir / "build.sh"
if not build_script.is_file():
raise LLVMEmissionError(f"missing build script: {build_script}")
result = subprocess.run(
["bash", str(build_script)],
cwd=example_dir,
text=True,
stdout=subprocess.PIPE,
stderr=subprocess.PIPE,
check=False,
)
if result.stdout:
print(result.stdout.rstrip())
if result.stderr:
print(result.stderr.rstrip(), file=sys.stderr)
return result.returncode
def parse_args(argv: list[str]) -> argparse.Namespace:
parser = argparse.ArgumentParser(description="Emit/check Example 05 LLVM module from lowering.")
parser.add_argument("--lowering", type=Path, default=DEFAULT_LOWERING)
parser.add_argument("--output", type=Path, default=None)
parser.add_argument("--expected", type=Path, default=DEFAULT_EXPECTED_MODULE)
parser.add_argument("--check", action="store_true")
parser.add_argument("--print", action="store_true", dest="print_module")
parser.add_argument("--build", action="store_true")
return parser.parse_args(argv)
def main(argv: list[str] | None = None) -> int:
args = parse_args(argv or [])
lowering_path = args.lowering if args.lowering.is_absolute() else ROOT / args.lowering
expected_path = args.expected if args.expected.is_absolute() else ROOT / args.expected
output_path = args.output if args.output is None or args.output.is_absolute() else ROOT / args.output
try:
generated = emit_llvm_from_lowering_path(lowering_path)
if output_path is not None:
write_text(output_path, generated)
print(f"wrote LLVM module: {output_path}")
if args.print_module:
sys.stdout.write(normalize_text(generated))
if args.check:
if not check_expected(generated, expected_path):
print("LLVM module emission check: FAILED", file=sys.stderr)
print(f"lowering: {lowering_path}", file=sys.stderr)
print(f"expected: {expected_path}", file=sys.stderr)
return 1
print("LLVM module emission check: ok")
print(f"lowering: {lowering_path.relative_to(ROOT)}")
print(f"expected: {expected_path.relative_to(ROOT)}")
if args.build:
code = run_build(DEFAULT_EXAMPLE_DIR)
if code != 0:
print(f"LLVM build check: FAILED (exit {code})", file=sys.stderr)
return code
print("LLVM build check: ok")
return 0
except LLVMEmissionError as exc:
print(f"LLVM module emission error: {exc}", file=sys.stderr)
return 2
if __name__ == "__main__":
raise SystemExit(main(sys.argv[1:]))