From 99be5acb8973289f95664f8a317f6e450a0dd326 Mon Sep 17 00:00:00 2001 From: Scott Duensing Date: Fri, 8 May 2026 15:50:39 -0500 Subject: [PATCH] Checkpoint --- runtime/src/snprintf.c | 2 - .../lib/Target/W65816/W65816InstrInfo.cpp | 19 ++++- .../lib/Target/W65816/W65816SjLjFinalize.cpp | 72 +++++++++++-------- 3 files changed, 61 insertions(+), 32 deletions(-) diff --git a/runtime/src/snprintf.c b/runtime/src/snprintf.c index 4c8704c..ec72418 100644 --- a/runtime/src/snprintf.c +++ b/runtime/src/snprintf.c @@ -103,7 +103,6 @@ static void emitDec(int n) { __attribute__((noinline)) -__attribute__((optnone)) static void emitULong(unsigned long n) { char buf[11]; int i = 0; @@ -300,7 +299,6 @@ static int format(const char *fmt, va_list ap) { -__attribute__((optnone)) int snprintf(char *buf, size_t n, const char *fmt, ...) { gCur = buf; // n == 0 must NOT touch the buffer (C99 7.19.6.5). Setting diff --git a/src/llvm/lib/Target/W65816/W65816InstrInfo.cpp b/src/llvm/lib/Target/W65816/W65816InstrInfo.cpp index fb8c590..7d5c83a 100644 --- a/src/llvm/lib/Target/W65816/W65816InstrInfo.cpp +++ b/src/llvm/lib/Target/W65816/W65816InstrInfo.cpp @@ -93,11 +93,26 @@ void W65816InstrInfo::copyPhysReg(MachineBasicBlock &MBB, BuildMI(MBB, I, DL, get(W65816::STA_DP)).addImm(dstImg); return; } - // IMGn → IMGm: route through A. Caller is responsible for ensuring - // A is dead at this program point (regalloc usually arranges this). + // IMGn → IMGm: route through A, but PHA-bracket so A is preserved. + // Without the bracket, regalloc could insert this COPY between a + // def of A and the use of A (e.g. between `$a = COPY $img10` and + // `STAfi $a, slot`, when both vregs are alive simultaneously and + // the regalloc decides to shuffle img physregs in between). The + // unbracketed lda/sta clobbers A and the subsequent STAfi spills + // garbage. Observed under ptr32 + full IMG defs in the C++ try/ + // catch path: `*p = 42` after `__cxa_allocate_exception` stored + // hi-half-of-ptr at lo-half-slot, breaking the indirect-long + // address setup so 42 landed at the wrong place. + // + // PHA bracket cost: +PHA (3 cyc, 1 byte) + PLA (4 cyc, 1 byte) = +7 + // cyc, +2 bytes per IMG-IMG copy. These are rare (regalloc usually + // can avoid them by picking the same physreg for COPY's src and + // dst), so the cost is small. if (srcImg >= 0 && dstImg >= 0) { + BuildMI(MBB, I, DL, get(W65816::PHA)); BuildMI(MBB, I, DL, get(W65816::LDA_DP)).addImm(srcImg); BuildMI(MBB, I, DL, get(W65816::STA_DP)).addImm(dstImg); + BuildMI(MBB, I, DL, get(W65816::PLA)); return; } // SP -> A via TSC. Used by alloca / setjmp asm machinery. diff --git a/src/llvm/lib/Target/W65816/W65816SjLjFinalize.cpp b/src/llvm/lib/Target/W65816/W65816SjLjFinalize.cpp index a1889b4..9d45848 100644 --- a/src/llvm/lib/Target/W65816/W65816SjLjFinalize.cpp +++ b/src/llvm/lib/Target/W65816/W65816SjLjFinalize.cpp @@ -226,22 +226,45 @@ bool W65816SjLjFinalize::runOnFunction(Function &F) { Builder.CreateCondBr(IsUnwind, DispatchBB, EHContinueBB); // The landing-pad blocks each start with a `landingpad { ptr, i32 }` - // instruction. After we convert invokes to plain calls, those - // blocks are no longer reached via an unwind edge — the verifier - // requires landingpads to be reached only from invoke unwind dests. - // Remove the landingpad insts (they're no-ops now; the real - // exception ptr / selector come from explicit fn_ctx.data loads - // SjLjEHPrepare emitted right after). Replace landingpad uses with - // poison since downstream code reads via GEPs, not via the inst's - // result. + // instruction. We need its catch-clause typeinfo arguments to build + // the per-function catch table further down, so capture them BEFORE + // erasing — the catchtab loop below uses the saved data instead of + // re-reading from the IR. + // + // Capture: per call_site, list of (typeinfo Constant*) for each + // catch clause (skipping null = catch-all). De-dup landingpads + // (multiple call_sites can share a landing pad). + struct LPadInfo { + SmallVector CatchTypes; + }; + DenseMap LPadCatches; SmallVector LPads; for (auto &KV : CSToLPad) { - if (LandingPadInst *LP = KV.second->getLandingPadInst()) - LPads.push_back(LP); + BasicBlock *LPadBB = KV.second; + if (LPadCatches.count(LPadBB)) + continue; + LandingPadInst *LP = LPadBB->getLandingPadInst(); + if (!LP) + continue; + LPadInfo Info; + for (unsigned i = 0; i < LP->getNumClauses(); i++) { + if (LP->isCatch(i)) { + Constant *TIClause = cast(LP->getClause(i)); + if (TIClause->isNullValue()) + continue; + Info.CatchTypes.push_back(TIClause); + } + } + LPadCatches[LPadBB] = std::move(Info); + LPads.push_back(LP); } - // De-dup (multiple call_sites can share a landing pad). - std::sort(LPads.begin(), LPads.end()); - LPads.erase(std::unique(LPads.begin(), LPads.end()), LPads.end()); + // After we convert invokes to plain calls, landingpad blocks are no + // longer reached via an unwind edge — the verifier requires landing- + // pads to be reached only from invoke unwind dests. Erase them now + // (they're no-ops post-finalize; the real exception ptr / selector + // come from explicit fn_ctx.data loads SjLjEHPrepare emitted right + // after). Replace landingpad uses with poison since downstream + // code reads via GEPs, not via the inst's result. for (LandingPadInst *LP : LPads) { LP->replaceAllUsesWith(PoisonValue::get(LP->getType())); LP->eraseFromParent(); @@ -284,25 +307,18 @@ bool W65816SjLjFinalize::runOnFunction(Function &F) { // eh.typeid.for(@TI) calls to also yield (i32)(uintptr_t)&TI. The // icmp eq then succeeds for the matched catch. SmallVector TableRows; - // Walk each invoke (now lowered to call+br); we kept its call_site - // → unwind_dest mapping, so re-derive from CSToLPad and the lpad's - // landingpad instruction's catch clauses. + // Walk each invoke's call_site → unwind_dest mapping; emit a row per + // (call_site, catch typeinfo) pair using the LPadCatches data we + // captured BEFORE erasing the landingpad insts above. for (auto &KV : CSToLPad) { int CS = KV.first; BasicBlock *LPadBB = KV.second; - LandingPadInst *LP = LPadBB->getLandingPadInst(); - if (!LP) + auto It = LPadCatches.find(LPadBB); + if (It == LPadCatches.end()) continue; - for (unsigned i = 0; i < LP->getNumClauses(); i++) { - if (LP->isCatch(i)) { - Constant *TIClause = cast(LP->getClause(i)); - // Skip catch-all (null TI) for now — rare, and our personality - // would need to handle it specially. - if (TIClause->isNullValue()) - continue; - TableRows.push_back(ConstantInt::get(I16Ty, CS)); - TableRows.push_back(ConstantExpr::getPtrToInt(TIClause, I16Ty)); - } + for (Constant *TIClause : It->second.CatchTypes) { + TableRows.push_back(ConstantInt::get(I16Ty, CS)); + TableRows.push_back(ConstantExpr::getPtrToInt(TIClause, I16Ty)); } } // Append (0, 0) sentinel.