← board

Nil Python does not build for xtensa Call0

$ printf 'x = 1\nprint(x)\n' > one.py
$ pascal26 --target=xtensa --xtensa-abi=call0 --platform=posix --xtensa-soft-mulhigh one.py one
pascal26:3407: error: target xtensa: addi immediate displacement 128 is outside
the encodable range -128..127; the code is too large for this branch form
  in: ./compiler/builtin/pyeval.pas

It failed on v447 and v448. The windowed ABI was not affected.

Two walls, one behind the other

1. The argument-block pop. On Call0 the caller pushes the arguments and pops them after the call with addi sp, sp, nArgs*4. addi encodes -128..127, and nothing checked that before emitting. pyeval's closure bridge makes a 32-argument indirect call, which is 128 bytes. It is appended to every Nil Python program, so no Nil Python program could build.

The fix is XtensaAddSp in ir_codegen_xtensa.inc, which splits the adjustment into in-range steps of 112, so sp stays 16-aligned between steps. It does not use a scratch register: every site runs right after a call, where a2/a3 hold the result. All 13 sites with a computed immediate (argument blocks, spill counts, argFree) go through it. The sites with literal immediates (-16, 16, EXC_FRAME_SIZE_XT) are in range and stay as they are.

2. Hosted xtensa refused Nil Python. Behind the first wall, a hosted build stopped with "a heap arena needs mmap and EmitMmapArena has no xtensa arm". The first cut added that arm. qemu-xtensa -strace then showed that it called syscall 90, which is mincore on xtensa (mincore(0,268435456,...) = -1 ENOMEM), and the programs passed anyway. That could only happen if nothing reads the arena. Nothing does: the only reader of BSS_HEAP_PTR/BSS_HEAP_END is the x86-64 inline allocator (symtab.inc). Xtensa allocates through builtinheap's HeapMmap, whose xtensa arm (mmap2 = 80, flags $802) was already measured. So the refusal is lifted, and no mapping is added. With the fix, -strace shows exactly one mmap2(NULL,268435456,...,MAP_PRIVATE|MAP_ANONYMOUS,-1,0), the heap's own.

A large Nil Python program on Call0 then needs --xtensa-long-calls, as it already did on the windowed ABI. The compiler names that flag itself.

Measured (2026-09-28)

Rows are in test-xtensa, after the windowed aggregate and regex rows.

Found on the way, not fixed here

A routine with 33 parameters crashes the compiler (SIGSEGV, no diagnostic), at the SHIPPED cap of 32. The test was first written with 40 parameters and hit this. It is recorded, with the unguarded staging arrays, in bug-a-max-proc-params-is-coupled-to-a-hardcoded-array-bound-by-a-comment.