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