//==-- W65816.h - Top-level interface for W65816 representation --*- C++ -*-==// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// // // This file contains the entry points for global functions defined in the // LLVM W65816 backend. // //===----------------------------------------------------------------------===// #ifndef LLVM_LIB_TARGET_W65816_W65816_H #define LLVM_LIB_TARGET_W65816_W65816_H #include "MCTargetDesc/W65816MCTargetDesc.h" #include "llvm/Target/TargetMachine.h" namespace W65816CC { // 65816 branch condition codes. Encoded as i8 immediate operands in // the BR_CC SDNode and tablegen patterns. // // 0..7 map to single Bxx instructions. 8..11 are pseudo codes that // expand to a two-branch sequence — needed for SETGT/SETLE/SETUGT/ // SETULE when the operand we'd swap to LHS is a load (no // pattern-match for load on LHS without spilling A). Only used in // SELECT_CC16's custom inserter; never reaches a single Bxx. enum CondCode { COND_EQ = 0, // BEQ COND_NE = 1, // BNE COND_HS = 2, // BCS (unsigned >=) COND_LO = 3, // BCC (unsigned <) COND_MI = 4, // BMI (negative, signed <) COND_PL = 5, // BPL (non-negative, signed >=) COND_VS = 6, // BVS (overflow) COND_VC = 7, // BVC (no overflow) // Multi-branch pseudo codes (handled by SELECT_CC16 inserter): COND_GT_MB = 8, // signed > : take if (PL && NE) COND_LE_MB = 9, // signed <= : take if (MI || EQ) COND_HI_MB = 10, // unsigned > : take if (HS && NE) COND_LS_MB = 11, // unsigned <=: take if (LO || EQ) COND_INVALID = -1 }; } // namespace W65816CC namespace llvm { class FunctionPass; class ModulePass; class W65816TargetMachine; class PassRegistry; FunctionPass *createW65816ISelDag(W65816TargetMachine &TM, CodeGenOptLevel OptLevel); // Post-RA cleanup: removes redundant STAfi+LDAfi same-slot pairs that // the greedy allocator emits when materialising a COPY $a -> vreg as // a spill/reload cycle, even though A still holds the value. See // W65816StackSlotCleanup.cpp. FunctionPass *createW65816StackSlotCleanup(); // Post-PEI cleanup: coalesces adjacent SEP/REP toggles emitted by // STA8fi expansions when two i8 stores sit back-to-back. Each STA8fi // emits SEP/STA/REP; consecutive expansions produce REP/SEP toggles // that cancel. See W65816SepRepCleanup.cpp. FunctionPass *createW65816SepRepCleanup(); // Pre-emit pass: expands long conditional branches into the // `INVERTED_Bxx skip ; BRA target ; skip:` pattern when the byte // distance to the target exceeds the +/-128 reach of an 8-bit-PCREL // branch. The unconditional BRA is then auto-relaxed to BRL by // the assembler when its target is also far. See W65816BranchExpand.cpp. FunctionPass *createW65816BranchExpand(); // Pre-RA pass: when a tied-def Acc16 instruction has a source vreg // whose value is also used after the consumer, fast regalloc fails // to preserve it (the tied physreg gets overwritten). We insert // explicit STAfi/LDAfi spill+reload around the consumer to fix this. // See W65816TiedDefSpill.cpp. FunctionPass *createW65816TiedDefSpill(); // Pre-RA pass: same trigger as TiedDefSpill, but bridges via X/Y // (Idx16) instead of stack when the post-consumer range is free of // X/Y clobbers. Saves 6 cycles + 2 bytes per bridge versus the stack // route. See W65816ABridgeViaX.cpp. FunctionPass *createW65816ABridgeViaX(); // Pre-RA pass: promote Acc16 vregs (= {A}) to Wide16 (= {A, IMG0..7}). // Lets greedy regalloc spread i16 pressure across A and the DP-backed // imaginaries. See W65816WidenAcc16.cpp. FunctionPass *createW65816WidenAcc16(); // Post-RA peephole: replace STAfi/LDAfi spill pairs (5+5 cyc) with // TAX/TXA bridges (2+2 cyc) when X is dead during the spill window. // Targets fast-regalloc's habit of spilling A unnecessarily; the // 3x speedup is the biggest single per-iteration win we can get // without switching to a smarter allocator. See W65816SpillToX.cpp. FunctionPass *createW65816SpillToX(); // Pre-emit peephole: rewrite `LDY #neg ; (LDA|STA) (sr,S),Y` to // pre-add the offset to the pointer with Y=0. The 65816 spec for // (sr,S),Y is a 24-bit add (DBR | (mem16(sr+S) + Y)) MOD $1000000, // so signed-negative Y crosses bank boundaries. See W65816NegYIndY.cpp. FunctionPass *createW65816NegYIndY(); // IR pass: finishes the SjLjEHPrepare lowering by inserting a setjmp // at function entry and a dispatch block, then erasing the eh.sjlj.* // intrinsics our backend doesn't lower natively. Runs after // SjLjEHPrepare in addPassesToHandleExceptions. See // W65816SjLjFinalize.cpp. FunctionPass *createW65816SjLjFinalize(); // IR pass: detect `mul i32 X, Y` where the top 16 bits of both X and Y // are provably zero (via IR-level computeKnownBits, which traces // through PHIs) and rewrite to a call to `__umulhisi3` (16x16 -> 32). // IR-level analysis catches cases SDAG can't, because IndVarSimplify // widens narrow loop counters to i32 before SDAG sees them, hiding the // zext that a SDAG-level combine would key off. See W65816NarrowI32Mul.cpp. FunctionPass *createW65816NarrowI32Mul(); // Post-LSR IR pass: detect pointer-walking loops over GlobalAddress // bases and rewrite to forward-counter + indexed GEP form. LSR's // transform is faster for pointer-arg loops (single ptr increment per // iter via [dp],Y), but for global-array access the W65816 has cheap // `lda , X` indexed addressing that we'd rather use. See // W65816UnLSR.cpp. FunctionPass *createW65816UnLSR(); // Post-RA, pre-PEI pass: rewrite high-traffic i16 FrameIndex accesses // to use IMG8..15 DP slots ($C0..$CE) instead of stack-rel spills. // Picks K = (number of free IMG8..15) hottest FIs and rewrites their // STAfi/LDAfi/ADCfi/etc. pseudos to STA_DP/LDA_DP/ADC_DP/etc. with // the corresponding DP address. Net win when access count > 5 (the // per-slot save/restore in ImgCalleeSave is ~20 cyc / 12 B). See // W65816PromoteFiToImg.cpp. FunctionPass *createW65816PromoteFiToImg(); // Pre-emit pass: merge value-equivalent stack slots. LLVM's // StackSlotColoring merges slots with non-overlapping liveness; // this pass catches the case where two slots ARE simultaneously // live but always hold the same value — typically the PHI src/dst // pair PHI-elim leaves at the back-edge of a loop body. Renames // X→Y function-wide when every STA X has a "twin" STA Y of the // same source value, and erases the resulting LDA-X-STA-Y self- // copy. See W65816StackSlotMerge.cpp. FunctionPass *createW65816StackSlotMerge(); // Pre-emit pass: rewrite top-N stack-rel slot offsets to IMG0..IMG7 // DP slots ($D0..$DE). Caller-save semantics — function must only // call IMG-safe libgcc helpers (verified to not touch $D0..$DE). // See W65816StackRelToImg.cpp. FunctionPass *createW65816StackRelToImg(); // Pre-RA pass that lowers Wide32 register pairs into pairs of i16 // vregs. Without this, greedy/basic regalloc can't fit the pair- // pressure of i64-via-2-i32-via-Wide32 traffic in i64-heavy // functions (RegAllocBase crashes during allocatePhysRegs). After // this pass, only i16 vregs reach regalloc, and the pair structure // lives only in the LDAptr32S / STAptr32S / STBptr32S pseudos which // take 2 i16 ptr operands directly. FunctionPass *createW65816LowerWide32(); // Pre-emit peephole: detect the post-PEI 6-instruction `i32 += 1` // pattern (LDA-ADCi16imm-STA-LDA-ADCEi16imm-STA on consecutive i16 // stack-rel halves) and rewrite to LDA-INA-STA + INC_HI_IF_CARRY. // Saves ~13 cyc per pointer increment in the common no-carry path. // See W65816I32IncFold.cpp. FunctionPass *createW65816I32IncFold(); // Post-RA, pre-PEI pass that emits prologue save + epilogue restore for // IMG8..IMG15 if the function uses them. Makes IMG8..IMG15 behave as // callee-saved at the asm level without going through LLVM's CSR // mechanism (which would shift regalloc decisions and break other // tests). See W65816ImgCalleeSave.cpp. FunctionPass *createW65816ImgCalleeSave(); // Early IR pass: stamp the "w65816-layer2"="true"|"false" function // attribute on every Function based on the per-TU cl::opt value of // -mllvm -w65816-dbr-safe-ptrs. Stamps EVERY function on every TU // compile, so that under LTO the per-TU provenance survives bitcode // merge. Phase 1.12 of GAP_CLOSURE_PLAN.md. See W65816Layer2Gate.cpp. FunctionPass *createW65816Layer2Stamp(); // LTO-time gate ModulePass. Walks every function in the post-link // module and hard-fails if any two functions disagree on the // "w65816-layer2" attribute -- catches Layer 2 / non-Layer 2 mixing // before it produces silent miscompiles. Invoke first in any LTO // pipeline (planned: scripts/ltoLink.sh under Phase 5.2). See // W65816Layer2Gate.cpp. ModulePass *createW65816Layer2Gate(); void initializeW65816AsmPrinterPass(PassRegistry &); void initializeW65816DAGToDAGISelLegacyPass(PassRegistry &); void initializeW65816StackSlotCleanupPass(PassRegistry &); void initializeW65816I32IncFoldPass(PassRegistry &); void initializeW65816SepRepCleanupPass(PassRegistry &); void initializeW65816BranchExpandPass(PassRegistry &); void initializeW65816TiedDefSpillPass(PassRegistry &); void initializeW65816ABridgeViaXPass(PassRegistry &); void initializeW65816UnLSRPass(PassRegistry &); void initializeW65816WidenAcc16Pass(PassRegistry &); void initializeW65816SpillToXPass(PassRegistry &); void initializeW65816NegYIndYPass(PassRegistry &); void initializeW65816SjLjFinalizePass(PassRegistry &); void initializeW65816LowerWide32Pass(PassRegistry &); void initializeW65816ImgCalleeSavePass(PassRegistry &); void initializeW65816NarrowI32MulPass(PassRegistry &); void initializeW65816PromoteFiToImgPass(PassRegistry &); void initializeW65816StackSlotMergePass(PassRegistry &); void initializeW65816StackRelToImgPass(PassRegistry &); void initializeW65816Layer2StampPass(PassRegistry &); void initializeW65816Layer2GatePass(PassRegistry &); } // namespace llvm #endif