mirror of
https://github.com/imjasonh/nescript
synced 2026-07-08 00:45:38 +00:00
Make IR codegen the default, fall back to AST via --use-ast
The IR-based codegen now matches all features of the AST codegen (state dispatch, multi-OAM, P1/P2 input, scroll, debug.log/assert), so flip the default. The legacy AST codegen is still available via --use-ast for comparison and fallback during validation. https://claude.ai/code/session_01W6eQFStA66EuMKHUFo2rx3
This commit is contained in:
parent
d609b77cd7
commit
3007266edf
2 changed files with 36 additions and 31 deletions
|
|
@ -371,13 +371,20 @@ These items were documented as future work but have since been implemented:
|
|||
`--debug` is set, stripped in release mode
|
||||
- **--debug CLI flag wired** — threads through `CodeGen::with_debug`
|
||||
- **IR-based codegen** — `src/codegen/ir_codegen.rs` walks `IrProgram` and
|
||||
emits 6502, handling all IR ops (load/store, arithmetic, comparisons,
|
||||
arrays, calls, draws, input, control flow). Enabled via `--use-ir` flag;
|
||||
all 7 examples compile through it. Default is still AST codegen while
|
||||
IR path is experimental.
|
||||
emits 6502 for every IR op: load/store, arithmetic, comparisons, arrays,
|
||||
calls, draws, input (P1 and P2), scroll, debug.log/assert, state
|
||||
dispatch, multi-OAM slot allocation, transitions + on_enter handlers.
|
||||
Now the default; `--use-ast` falls back to the legacy AST-based codegen.
|
||||
- **IR lowering bug fixes** — `ReadInput` now has a destination temp,
|
||||
`ButtonRead` uses the proper input temp, logical AND/OR use a new
|
||||
`emit_move` helper instead of the buggy raw VarId temp storage
|
||||
- **IR Player 2 controller** — `ReadInput(temp, player)` selects $01
|
||||
or $08 based on player index
|
||||
- **IR scroll support** — `scroll(x, y)` lowers to `IrOp::Scroll(x, y)`
|
||||
which emits two PPU $2005 writes in IR codegen
|
||||
- **IR debug.log / debug.assert** — new `IrOp::DebugLog(temps)` and
|
||||
`IrOp::DebugAssert(cond)` variants, emitted as $4800 writes in debug
|
||||
mode and stripped in release (same behavior as AST codegen)
|
||||
- **Asset pipeline @binary / @chr loading** — `resolve_sprites()` reads
|
||||
raw binary files and converts PNGs via `png_to_chr()`. Missing files
|
||||
are silently skipped (documentation-friendly)
|
||||
|
|
@ -386,16 +393,14 @@ These items were documented as future work but have since been implemented:
|
|||
|
||||
For someone picking up this codebase, the recommended order of work:
|
||||
|
||||
1. **Make IR codegen the default** — currently behind `--use-ir`. Once
|
||||
it matches AST codegen for all code paths (state dispatch, multi-OAM,
|
||||
debug statements), switch over and delete AST codegen.
|
||||
2. **IR codegen: state dispatch** — currently no main loop / dispatch
|
||||
table; IR codegen only generates function bodies. Need to emit the
|
||||
state machine dispatch like the AST codegen does.
|
||||
3. **IR codegen: multi-OAM** — currently all draws use slot 0
|
||||
4. **Audio** — SFX/music driver
|
||||
5. **on_scanline for MMC3** — scanline IRQ handlers
|
||||
6. **Language features** — structs, enums, fixed-point
|
||||
7. **Register allocator** — proper A/X/Y allocation to replace
|
||||
1. **Delete AST codegen** — IR codegen is now the default and matches
|
||||
all AST codegen features. Once confidence is high (e.g. a few weeks
|
||||
of game-writing), remove `--use-ast` and `src/codegen/mod.rs`'s
|
||||
AST-specific code. Keep the shared constants (`DEBUG_PORT`, ZP
|
||||
layout) in a common module.
|
||||
2. **Audio** — SFX/music driver
|
||||
3. **on_scanline for MMC3** — scanline IRQ handlers
|
||||
4. **Language features** — structs, enums, fixed-point
|
||||
5. **Register allocator** — proper A/X/Y allocation to replace
|
||||
zero-page spills used by the current IR codegen
|
||||
8. **Inline assembly** — `asm { }` blocks
|
||||
6. **Inline assembly** — `asm { }` blocks
|
||||
|
|
|
|||
30
src/main.rs
30
src/main.rs
|
|
@ -3,7 +3,7 @@ use std::path::{Path, PathBuf};
|
|||
|
||||
use nescript::analyzer;
|
||||
use nescript::assets;
|
||||
use nescript::codegen::CodeGen;
|
||||
use nescript::codegen::{CodeGen, IrCodeGen};
|
||||
use nescript::errors::render_diagnostics;
|
||||
use nescript::ir;
|
||||
use nescript::linker::Linker;
|
||||
|
|
@ -29,10 +29,10 @@ enum Cli {
|
|||
#[arg(long)]
|
||||
asm_dump: bool,
|
||||
|
||||
/// Use the experimental IR-based codegen instead of the
|
||||
/// AST-based codegen. Enables optimizer passes on the output.
|
||||
/// Use the legacy AST-based codegen. The default is the IR-based
|
||||
/// codegen, which runs the optimizer passes before emitting 6502.
|
||||
#[arg(long)]
|
||||
use_ir: bool,
|
||||
use_ast: bool,
|
||||
},
|
||||
/// Type-check a source file without building
|
||||
Check {
|
||||
|
|
@ -50,10 +50,10 @@ fn main() {
|
|||
output,
|
||||
debug,
|
||||
asm_dump,
|
||||
use_ir,
|
||||
use_ast,
|
||||
} => {
|
||||
let output = output.unwrap_or_else(|| input.with_extension("nes"));
|
||||
match compile(&input, debug, asm_dump, use_ir) {
|
||||
match compile(&input, debug, asm_dump, use_ast) {
|
||||
Ok(rom) => {
|
||||
std::fs::write(&output, rom).unwrap_or_else(|e| {
|
||||
eprintln!("error: failed to write {}: {e}", output.display());
|
||||
|
|
@ -86,7 +86,7 @@ fn dump_asm(instructions: &[nescript::asm::Instruction]) {
|
|||
}
|
||||
}
|
||||
|
||||
fn compile(input: &PathBuf, debug: bool, asm_dump: bool, use_ir: bool) -> Result<Vec<u8>, ()> {
|
||||
fn compile(input: &PathBuf, debug: bool, asm_dump: bool, use_ast: bool) -> Result<Vec<u8>, ()> {
|
||||
let raw_source = std::fs::read_to_string(input).map_err(|e| {
|
||||
eprintln!("error: failed to read {}: {e}", input.display());
|
||||
})?;
|
||||
|
|
@ -135,18 +135,18 @@ fn compile(input: &PathBuf, debug: bool, asm_dump: bool, use_ir: bool) -> Result
|
|||
eprintln!("error: {e}");
|
||||
})?;
|
||||
|
||||
// Code generation: choose between IR-based and AST-based codegen.
|
||||
let instructions = if use_ir {
|
||||
use nescript::codegen::IrCodeGen;
|
||||
IrCodeGen::new(&analysis.var_allocations, &ir_program)
|
||||
.with_sprites(&sprites)
|
||||
.with_debug(debug)
|
||||
.generate(&ir_program)
|
||||
} else {
|
||||
// Code generation: IR-based is the default. `--use-ast` switches to
|
||||
// the legacy AST-based codegen for comparison and fallback.
|
||||
let instructions = if use_ast {
|
||||
CodeGen::new(&analysis.var_allocations, &program.constants)
|
||||
.with_sprites(&sprites)
|
||||
.with_debug(debug)
|
||||
.generate(&program)
|
||||
} else {
|
||||
IrCodeGen::new(&analysis.var_allocations, &ir_program)
|
||||
.with_sprites(&sprites)
|
||||
.with_debug(debug)
|
||||
.generate(&ir_program)
|
||||
};
|
||||
|
||||
if asm_dump {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue