#include "AArch64InstrInfo.h"
#include "AArch64MachineFunctionInfo.h"
#include "AArch64Subtarget.h"
#include "MCTargetDesc/AArch64AddressingModes.h"
#include "llvm/ADT/SmallVector.h"
#include "llvm/ADT/Statistic.h"
#include "llvm/ADT/StringRef.h"
#include "llvm/ADT/iterator_range.h"
#include "llvm/Analysis/AliasAnalysis.h"
#include "llvm/CodeGen/MachineBasicBlock.h"
#include "llvm/CodeGen/MachineFunction.h"
#include "llvm/CodeGen/MachineFunctionPass.h"
#include "llvm/CodeGen/MachineInstr.h"
#include "llvm/CodeGen/MachineInstrBuilder.h"
#include "llvm/CodeGen/MachineOperand.h"
#include "llvm/CodeGen/MachineRegisterInfo.h"
#include "llvm/CodeGen/TargetRegisterInfo.h"
#include "llvm/IR/DebugLoc.h"
#include "llvm/MC/MCAsmInfo.h"
#include "llvm/MC/MCDwarf.h"
#include "llvm/MC/MCRegisterInfo.h"
#include "llvm/Pass.h"
#include "llvm/Support/CommandLine.h"
#include "llvm/Support/Debug.h"
#include "llvm/Support/DebugCounter.h"
#include "llvm/Support/ErrorHandling.h"
#include "llvm/Support/raw_ostream.h"
#include <cassert>
#include <cstdint>
#include <functional>
#include <iterator>
#include <limits>
#include <optional>
usingnamespacellvm;
#define DEBUG_TYPE …
STATISTIC(NumPairCreated, "Number of load/store pair instructions generated");
STATISTIC(NumPostFolded, "Number of post-index updates folded");
STATISTIC(NumPreFolded, "Number of pre-index updates folded");
STATISTIC(NumUnscaledPairCreated,
"Number of load/store from unscaled generated");
STATISTIC(NumZeroStoresPromoted, "Number of narrow zero stores promoted");
STATISTIC(NumLoadsFromStoresPromoted, "Number of loads from stores promoted");
STATISTIC(NumFailedAlignmentCheck, "Number of load/store pair transformation "
"not passed the alignment check");
STATISTIC(NumConstOffsetFolded,
"Number of const offset of index address folded");
DEBUG_COUNTER(RegRenamingCounter, DEBUG_TYPE "-reg-renaming",
"Controls which pairs are considered for renaming");
static cl::opt<unsigned> LdStLimit("aarch64-load-store-scan-limit",
cl::init(20), cl::Hidden);
static cl::opt<unsigned> UpdateLimit("aarch64-update-scan-limit", cl::init(100),
cl::Hidden);
static cl::opt<unsigned> LdStConstLimit("aarch64-load-store-const-scan-limit",
cl::init(10), cl::Hidden);
static cl::opt<bool> EnableRenaming("aarch64-load-store-renaming",
cl::init(true), cl::Hidden);
#define AARCH64_LOAD_STORE_OPT_NAME …
namespace {
using LdStPairFlags = struct LdStPairFlags { … };
struct AArch64LoadStoreOpt : public MachineFunctionPass { … };
char AArch64LoadStoreOpt::ID = …;
}
INITIALIZE_PASS(…)
static bool isNarrowStore(unsigned Opc) { … }
static bool isTagStore(const MachineInstr &MI) { … }
static unsigned getMatchingNonSExtOpcode(unsigned Opc,
bool *IsValidLdStrOpc = nullptr) { … }
static unsigned getMatchingWideOpcode(unsigned Opc) { … }
static unsigned getMatchingPairOpcode(unsigned Opc) { … }
static unsigned isMatchingStore(MachineInstr &LoadInst,
MachineInstr &StoreInst) { … }
static unsigned getPreIndexedOpcode(unsigned Opc) { … }
static unsigned getBaseAddressOpcode(unsigned Opc) { … }
static unsigned getPostIndexedOpcode(unsigned Opc) { … }
static bool isPreLdStPairCandidate(MachineInstr &FirstMI, MachineInstr &MI) { … }
static void getPrePostIndexedMemOpInfo(const MachineInstr &MI, int &Scale,
int &MinOffset, int &MaxOffset) { … }
static MachineOperand &getLdStRegOp(MachineInstr &MI,
unsigned PairedRegOp = 0) { … }
static bool isLdOffsetInRangeOfSt(MachineInstr &LoadInst,
MachineInstr &StoreInst,
const AArch64InstrInfo *TII) { … }
static bool isPromotableZeroStoreInst(MachineInstr &MI) { … }
static bool isPromotableLoadFromStore(MachineInstr &MI) { … }
static bool isMergeableLdStUpdate(MachineInstr &MI) { … }
static bool isMergeableIndexLdSt(MachineInstr &MI, int &Scale) { … }
static bool isRewritableImplicitDef(unsigned Opc) { … }
MachineBasicBlock::iterator
AArch64LoadStoreOpt::mergeNarrowZeroStores(MachineBasicBlock::iterator I,
MachineBasicBlock::iterator MergeMI,
const LdStPairFlags &Flags) { … }
static bool forAllMIsUntilDef(MachineInstr &MI, MCPhysReg DefReg,
const TargetRegisterInfo *TRI, unsigned Limit,
std::function<bool(MachineInstr &, bool)> &Fn) { … }
static void updateDefinedRegisters(MachineInstr &MI, LiveRegUnits &Units,
const TargetRegisterInfo *TRI) { … }
MachineBasicBlock::iterator
AArch64LoadStoreOpt::mergePairedInsns(MachineBasicBlock::iterator I,
MachineBasicBlock::iterator Paired,
const LdStPairFlags &Flags) { … }
MachineBasicBlock::iterator
AArch64LoadStoreOpt::promoteLoadFromStore(MachineBasicBlock::iterator LoadI,
MachineBasicBlock::iterator StoreI) { … }
static bool inBoundsForPair(bool IsUnscaled, int Offset, int OffsetStride) { … }
static int alignTo(int Num, int PowOf2) { … }
static bool mayAlias(MachineInstr &MIa,
SmallVectorImpl<MachineInstr *> &MemInsns,
AliasAnalysis *AA) { … }
bool AArch64LoadStoreOpt::findMatchingStore(
MachineBasicBlock::iterator I, unsigned Limit,
MachineBasicBlock::iterator &StoreI) { … }
static bool needsWinCFI(const MachineFunction *MF) { … }
static bool areCandidatesToMergeOrPair(MachineInstr &FirstMI, MachineInstr &MI,
LdStPairFlags &Flags,
const AArch64InstrInfo *TII) { … }
static bool canRenameMOP(const MachineOperand &MOP,
const TargetRegisterInfo *TRI) { … }
static bool
canRenameUpToDef(MachineInstr &FirstMI, LiveRegUnits &UsedInBetween,
SmallPtrSetImpl<const TargetRegisterClass *> &RequiredClasses,
const TargetRegisterInfo *TRI) { … }
static bool canRenameUntilSecondLoad(
MachineInstr &FirstLoad, MachineInstr &SecondLoad,
LiveRegUnits &UsedInBetween,
SmallPtrSetImpl<const TargetRegisterClass *> &RequiredClasses,
const TargetRegisterInfo *TRI) { … }
static std::optional<MCPhysReg> tryToFindRegisterToRename(
const MachineFunction &MF, Register Reg, LiveRegUnits &DefinedInBB,
LiveRegUnits &UsedInBetween,
SmallPtrSetImpl<const TargetRegisterClass *> &RequiredClasses,
const TargetRegisterInfo *TRI) { … }
static std::optional<MCPhysReg> findRenameRegForSameLdStRegPair(
std::optional<bool> MaybeCanRename, MachineInstr &FirstMI, MachineInstr &MI,
Register Reg, LiveRegUnits &DefinedInBB, LiveRegUnits &UsedInBetween,
SmallPtrSetImpl<const TargetRegisterClass *> &RequiredClasses,
const TargetRegisterInfo *TRI) { … }
MachineBasicBlock::iterator
AArch64LoadStoreOpt::findMatchingInsn(MachineBasicBlock::iterator I,
LdStPairFlags &Flags, unsigned Limit,
bool FindNarrowMerge) { … }
static MachineBasicBlock::iterator
maybeMoveCFI(MachineInstr &MI, MachineBasicBlock::iterator MaybeCFI) { … }
std::optional<MachineBasicBlock::iterator> AArch64LoadStoreOpt::mergeUpdateInsn(
MachineBasicBlock::iterator I, MachineBasicBlock::iterator Update,
bool IsForward, bool IsPreIdx, bool MergeEither) { … }
MachineBasicBlock::iterator
AArch64LoadStoreOpt::mergeConstOffsetInsn(MachineBasicBlock::iterator I,
MachineBasicBlock::iterator Update,
unsigned Offset, int Scale) { … }
bool AArch64LoadStoreOpt::isMatchingUpdateInsn(MachineInstr &MemMI,
MachineInstr &MI,
unsigned BaseReg, int Offset) { … }
bool AArch64LoadStoreOpt::isMatchingMovConstInsn(MachineInstr &MemMI,
MachineInstr &MI,
unsigned IndexReg,
unsigned &Offset) { … }
MachineBasicBlock::iterator AArch64LoadStoreOpt::findMatchingUpdateInsnForward(
MachineBasicBlock::iterator I, int UnscaledOffset, unsigned Limit) { … }
MachineBasicBlock::iterator AArch64LoadStoreOpt::findMatchingUpdateInsnBackward(
MachineBasicBlock::iterator I, unsigned Limit, bool &MergeEither) { … }
MachineBasicBlock::iterator
AArch64LoadStoreOpt::findMatchingConstOffsetBackward(
MachineBasicBlock::iterator I, unsigned Limit, unsigned &Offset) { … }
bool AArch64LoadStoreOpt::tryToPromoteLoadFromStore(
MachineBasicBlock::iterator &MBBI) { … }
bool AArch64LoadStoreOpt::tryToMergeZeroStInst(
MachineBasicBlock::iterator &MBBI) { … }
bool AArch64LoadStoreOpt::tryToPairLdStInst(MachineBasicBlock::iterator &MBBI) { … }
bool AArch64LoadStoreOpt::tryToMergeLdStUpdate
(MachineBasicBlock::iterator &MBBI) { … }
bool AArch64LoadStoreOpt::tryToMergeIndexLdSt(MachineBasicBlock::iterator &MBBI,
int Scale) { … }
bool AArch64LoadStoreOpt::optimizeBlock(MachineBasicBlock &MBB,
bool EnableNarrowZeroStOpt) { … }
bool AArch64LoadStoreOpt::runOnMachineFunction(MachineFunction &Fn) { … }
FunctionPass *llvm::createAArch64LoadStoreOptimizationPass() { … }