65816-llvm-mos/src/llvm/lib/Target/W65816/W65816.h
2026-06-30 20:34:32 -05:00

217 lines
10 KiB
C++

//==-- 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 <global>, 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