//===-- W65816InstrInfo.h - W65816 Instruction Information ------*- 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 W65816 implementation of the TargetInstrInfo class. // //===----------------------------------------------------------------------===// #ifndef LLVM_LIB_TARGET_W65816_W65816INSTRINFO_H #define LLVM_LIB_TARGET_W65816_W65816INSTRINFO_H #include "W65816RegisterInfo.h" #include "llvm/CodeGen/TargetInstrInfo.h" #define GET_INSTRINFO_HEADER #include "W65816GenInstrInfo.inc" namespace llvm { class W65816Subtarget; class W65816InstrInfo : public W65816GenInstrInfo { const W65816RegisterInfo RI; virtual void anchor(); public: explicit W65816InstrInfo(const W65816Subtarget &STI); const W65816RegisterInfo &getRegisterInfo() const { return RI; } void copyPhysReg(MachineBasicBlock &MBB, MachineBasicBlock::iterator I, const DebugLoc &DL, Register DestReg, Register SrcReg, bool KillSrc, bool RenamableDest = false, bool RenamableSrc = false) const override; void storeRegToStackSlot( MachineBasicBlock &MBB, MachineBasicBlock::iterator MI, Register SrcReg, bool isKill, int FrameIndex, const TargetRegisterClass *RC, Register VReg, MachineInstr::MIFlag Flags = MachineInstr::NoFlags) const override; void loadRegFromStackSlot( MachineBasicBlock &MBB, MachineBasicBlock::iterator MI, Register DestReg, int FrameIdx, const TargetRegisterClass *RC, Register VReg, unsigned SubReg = 0, MachineInstr::MIFlag Flags = MachineInstr::NoFlags) const override; // Override the default rematerializability check to recognise LDAfi // from a *fixed* (immutable) frame index — i.e. an arg slot — as // trivially rematerializable. Without this, the greedy allocator // spills arg loads to a fresh local slot the moment A is needed for // anything else, then reloads from the local slot at every use. // With it, the allocator just re-emits `LDA arg_slot,S` at each use // and the `STA local; LDA local; LDA local` cluster collapses to a // single `LDA arg_slot,S`. Spill-slot LDAfi (regular FI) is *not* // rematerializable — that loads a computed value. bool isReMaterializableImpl(const MachineInstr &MI) const override; // Tell the framework which pseudos are direct stack-slot loads/stores. // MachineCSE, machine-licm, and peephole-opt use these hooks to elide // redundant store/load pairs and to hoist invariants. Without them, // patterns like `STAfi A, slot; LDAfi slot, A` (introduced by the // greedy allocator's COPY-of-physreg expansion) survive into final // asm as `sta x,s; lda x,s` no-op pairs. Register isLoadFromStackSlot(const MachineInstr &MI, int &FrameIndex) const override; Register isStoreToStackSlot(const MachineInstr &MI, int &FrameIndex) const override; // Byte-accurate size of an instruction (or an upper bound for // pseudos that AsmPrinter expands to multiple MC instructions). // Used by W65816BranchExpand to compute branch distances precisely // enough to decide when to lengthen a conditional branch. Real // instructions with a Size set in tablegen get that value; // pseudos that emit nothing (PHI, COPY, ADJCALLSTACKDOWN/UP, // KILL, IMPLICIT_DEF, REG_SEQUENCE, BUNDLE, etc.) report 0 bytes; // codegen pseudos with Size==0 in tablegen but a non-trivial // AsmPrinter expansion get an upper-bound estimate. unsigned getInstSizeInBytes(const MachineInstr &MI) const override; // PEI uses this to track the running SP shift inside a call // sequence and pass it to eliminateFrameIndex as SPAdj. Our // ADJCALLSTACKDOWN does NOT physically shift SP — the PUSH16/PUSH16X // pseudos do that incrementally as args get pushed. Override the // default so PEI knows: ADJCALLSTACKDOWN/UP contribute 0 (no SP // shift), PUSH16/PUSH16X contribute +2 each (one byte-pair pushed). // Without this override, PEI applies the full ADJCALLSTACKDOWN // amount as SPAdj at the very *start* of the call sequence, // producing FI offsets that pretend SP has already shifted — and // any STAfi/LDAfi to a *local* before the actual PUSH16 happens // ends up writing past the locals into the caller's stack // (corrupting the return address, observed for `int eval(int a, // int b, int c) { return a*b + c; }` under fast regalloc). int getSPAdjust(const MachineInstr &MI) const override; // Branch-control hooks. These now decode our real branch opcodes // (BEQ/BNE/BCS/BCC/BMI/BPL/BVS/BVC and BRA/BRL/JMP_Abs) so // BranchFolder and MachineBlockPlacement can rearrange blocks. // Cond is encoded as a single Imm operand holding the conditional // branch's opcode; reverseBranchCondition flips it via opcode map. // JMP_AbsInd / JML_Long return "unanalyzable" — they're indirect or // bank-crossing, which the layout passes can't reason about. bool analyzeBranch(MachineBasicBlock &MBB, MachineBasicBlock *&TBB, MachineBasicBlock *&FBB, SmallVectorImpl &Cond, bool AllowModify) const override; unsigned removeBranch(MachineBasicBlock &MBB, int *BytesRemoved = nullptr) const override; unsigned insertBranch(MachineBasicBlock &MBB, MachineBasicBlock *TBB, MachineBasicBlock *FBB, ArrayRef Cond, const DebugLoc &DL, int *BytesAdded = nullptr) const override; bool reverseBranchCondition( SmallVectorImpl &Cond) const override; MachineBasicBlock *getBranchDestBlock( const MachineInstr &MI) const override; }; } // namespace llvm #endif