1fe6060f1SDimitry Andric //=== lib/CodeGen/GlobalISel/AArch64O0PreLegalizerCombiner.cpp ------------===// 2fe6060f1SDimitry Andric // 3fe6060f1SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4fe6060f1SDimitry Andric // See https://llvm.org/LICENSE.txt for license information. 5fe6060f1SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6fe6060f1SDimitry Andric // 7fe6060f1SDimitry Andric //===----------------------------------------------------------------------===// 8fe6060f1SDimitry Andric // 9fe6060f1SDimitry Andric // This pass does combining of machine instructions at the generic MI level, 10fe6060f1SDimitry Andric // before the legalizer. 11fe6060f1SDimitry Andric // 12fe6060f1SDimitry Andric //===----------------------------------------------------------------------===// 13fe6060f1SDimitry Andric 14fe6060f1SDimitry Andric #include "AArch64GlobalISelUtils.h" 15fe6060f1SDimitry Andric #include "AArch64TargetMachine.h" 16fe6060f1SDimitry Andric #include "llvm/CodeGen/GlobalISel/Combiner.h" 17fe6060f1SDimitry Andric #include "llvm/CodeGen/GlobalISel/CombinerHelper.h" 18fe6060f1SDimitry Andric #include "llvm/CodeGen/GlobalISel/CombinerInfo.h" 19*06c3fb27SDimitry Andric #include "llvm/CodeGen/GlobalISel/GIMatchTableExecutor.h" 20*06c3fb27SDimitry Andric #include "llvm/CodeGen/GlobalISel/GIMatchTableExecutorImpl.h" 21fe6060f1SDimitry Andric #include "llvm/CodeGen/GlobalISel/GISelKnownBits.h" 22fe6060f1SDimitry Andric #include "llvm/CodeGen/GlobalISel/MIPatternMatch.h" 23fe6060f1SDimitry Andric #include "llvm/CodeGen/GlobalISel/MachineIRBuilder.h" 24fe6060f1SDimitry Andric #include "llvm/CodeGen/MachineDominators.h" 25fe6060f1SDimitry Andric #include "llvm/CodeGen/MachineFunction.h" 26fe6060f1SDimitry Andric #include "llvm/CodeGen/MachineFunctionPass.h" 27fe6060f1SDimitry Andric #include "llvm/CodeGen/MachineRegisterInfo.h" 28fe6060f1SDimitry Andric #include "llvm/CodeGen/TargetPassConfig.h" 29fe6060f1SDimitry Andric #include "llvm/IR/Instructions.h" 30fe6060f1SDimitry Andric #include "llvm/Support/Debug.h" 31fe6060f1SDimitry Andric 32*06c3fb27SDimitry Andric #define GET_GICOMBINER_DEPS 33*06c3fb27SDimitry Andric #include "AArch64GenO0PreLegalizeGICombiner.inc" 34*06c3fb27SDimitry Andric #undef GET_GICOMBINER_DEPS 35*06c3fb27SDimitry Andric 36fe6060f1SDimitry Andric #define DEBUG_TYPE "aarch64-O0-prelegalizer-combiner" 37fe6060f1SDimitry Andric 38fe6060f1SDimitry Andric using namespace llvm; 39fe6060f1SDimitry Andric using namespace MIPatternMatch; 40*06c3fb27SDimitry Andric namespace { 41*06c3fb27SDimitry Andric #define GET_GICOMBINER_TYPES 42*06c3fb27SDimitry Andric #include "AArch64GenO0PreLegalizeGICombiner.inc" 43*06c3fb27SDimitry Andric #undef GET_GICOMBINER_TYPES 44fe6060f1SDimitry Andric 45*06c3fb27SDimitry Andric class AArch64O0PreLegalizerCombinerImpl : public GIMatchTableExecutor { 46fe6060f1SDimitry Andric protected: 47fe6060f1SDimitry Andric CombinerHelper &Helper; 48*06c3fb27SDimitry Andric const AArch64O0PreLegalizerCombinerImplRuleConfig &RuleConfig; 49*06c3fb27SDimitry Andric 50*06c3fb27SDimitry Andric const AArch64Subtarget &STI; 51*06c3fb27SDimitry Andric GISelChangeObserver &Observer; 52*06c3fb27SDimitry Andric MachineIRBuilder &B; 53*06c3fb27SDimitry Andric MachineFunction &MF; 54*06c3fb27SDimitry Andric 55*06c3fb27SDimitry Andric MachineRegisterInfo &MRI; 56fe6060f1SDimitry Andric 57fe6060f1SDimitry Andric public: 58*06c3fb27SDimitry Andric AArch64O0PreLegalizerCombinerImpl( 59*06c3fb27SDimitry Andric const AArch64O0PreLegalizerCombinerImplRuleConfig &RuleConfig, 60*06c3fb27SDimitry Andric GISelChangeObserver &Observer, MachineIRBuilder &B, 61*06c3fb27SDimitry Andric CombinerHelper &Helper); 62*06c3fb27SDimitry Andric 63*06c3fb27SDimitry Andric static const char *getName() { return "AArch64O0PreLegalizerCombiner"; } 64*06c3fb27SDimitry Andric 65*06c3fb27SDimitry Andric bool tryCombineAll(MachineInstr &I) const; 66*06c3fb27SDimitry Andric 67*06c3fb27SDimitry Andric private: 68*06c3fb27SDimitry Andric #define GET_GICOMBINER_CLASS_MEMBERS 69*06c3fb27SDimitry Andric #include "AArch64GenO0PreLegalizeGICombiner.inc" 70*06c3fb27SDimitry Andric #undef GET_GICOMBINER_CLASS_MEMBERS 71fe6060f1SDimitry Andric }; 72fe6060f1SDimitry Andric 73*06c3fb27SDimitry Andric #define GET_GICOMBINER_IMPL 74fe6060f1SDimitry Andric #include "AArch64GenO0PreLegalizeGICombiner.inc" 75*06c3fb27SDimitry Andric #undef GET_GICOMBINER_IMPL 76fe6060f1SDimitry Andric 77*06c3fb27SDimitry Andric AArch64O0PreLegalizerCombinerImpl::AArch64O0PreLegalizerCombinerImpl( 78*06c3fb27SDimitry Andric const AArch64O0PreLegalizerCombinerImplRuleConfig &RuleConfig, 79*06c3fb27SDimitry Andric GISelChangeObserver &Observer, MachineIRBuilder &B, CombinerHelper &Helper) 80*06c3fb27SDimitry Andric : Helper(Helper), RuleConfig(RuleConfig), 81*06c3fb27SDimitry Andric STI(B.getMF().getSubtarget<AArch64Subtarget>()), Observer(Observer), B(B), 82*06c3fb27SDimitry Andric MF(B.getMF()), MRI(*B.getMRI()), 83*06c3fb27SDimitry Andric #define GET_GICOMBINER_CONSTRUCTOR_INITS 84fe6060f1SDimitry Andric #include "AArch64GenO0PreLegalizeGICombiner.inc" 85*06c3fb27SDimitry Andric #undef GET_GICOMBINER_CONSTRUCTOR_INITS 86*06c3fb27SDimitry Andric { 87*06c3fb27SDimitry Andric } 88fe6060f1SDimitry Andric 89fe6060f1SDimitry Andric class AArch64O0PreLegalizerCombinerInfo : public CombinerInfo { 90fe6060f1SDimitry Andric GISelKnownBits *KB; 91fe6060f1SDimitry Andric MachineDominatorTree *MDT; 92*06c3fb27SDimitry Andric AArch64O0PreLegalizerCombinerImplRuleConfig RuleConfig; 93fe6060f1SDimitry Andric 94fe6060f1SDimitry Andric public: 95fe6060f1SDimitry Andric AArch64O0PreLegalizerCombinerInfo(bool EnableOpt, bool OptSize, bool MinSize, 96fe6060f1SDimitry Andric GISelKnownBits *KB, 97fe6060f1SDimitry Andric MachineDominatorTree *MDT) 98fe6060f1SDimitry Andric : CombinerInfo(/*AllowIllegalOps*/ true, /*ShouldLegalizeIllegal*/ false, 99fe6060f1SDimitry Andric /*LegalizerInfo*/ nullptr, EnableOpt, OptSize, MinSize), 100fe6060f1SDimitry Andric KB(KB), MDT(MDT) { 101*06c3fb27SDimitry Andric if (!RuleConfig.parseCommandLineOption()) 102fe6060f1SDimitry Andric report_fatal_error("Invalid rule identifier"); 103fe6060f1SDimitry Andric } 104fe6060f1SDimitry Andric 105972a253aSDimitry Andric bool combine(GISelChangeObserver &Observer, MachineInstr &MI, 106fe6060f1SDimitry Andric MachineIRBuilder &B) const override; 107fe6060f1SDimitry Andric }; 108fe6060f1SDimitry Andric 109fe6060f1SDimitry Andric bool AArch64O0PreLegalizerCombinerInfo::combine(GISelChangeObserver &Observer, 110fe6060f1SDimitry Andric MachineInstr &MI, 111fe6060f1SDimitry Andric MachineIRBuilder &B) const { 112bdd1243dSDimitry Andric CombinerHelper Helper(Observer, B, /*IsPreLegalize*/ true, KB, MDT); 113*06c3fb27SDimitry Andric AArch64O0PreLegalizerCombinerImpl Impl(RuleConfig, Observer, B, Helper); 114*06c3fb27SDimitry Andric Impl.setupMF(*MI.getMF(), KB); 115fe6060f1SDimitry Andric 116*06c3fb27SDimitry Andric if (Impl.tryCombineAll(MI)) 117fe6060f1SDimitry Andric return true; 118fe6060f1SDimitry Andric 119fe6060f1SDimitry Andric unsigned Opc = MI.getOpcode(); 120fe6060f1SDimitry Andric switch (Opc) { 121fe6060f1SDimitry Andric case TargetOpcode::G_CONCAT_VECTORS: 122fe6060f1SDimitry Andric return Helper.tryCombineConcatVectors(MI); 123fe6060f1SDimitry Andric case TargetOpcode::G_SHUFFLE_VECTOR: 124fe6060f1SDimitry Andric return Helper.tryCombineShuffleVector(MI); 125fe6060f1SDimitry Andric case TargetOpcode::G_MEMCPY_INLINE: 126fe6060f1SDimitry Andric return Helper.tryEmitMemcpyInline(MI); 127fe6060f1SDimitry Andric case TargetOpcode::G_MEMCPY: 128fe6060f1SDimitry Andric case TargetOpcode::G_MEMMOVE: 129fe6060f1SDimitry Andric case TargetOpcode::G_MEMSET: { 130fe6060f1SDimitry Andric // At -O0 set a maxlen of 32 to inline; 131fe6060f1SDimitry Andric unsigned MaxLen = 32; 132fe6060f1SDimitry Andric // Try to inline memcpy type calls if optimizations are enabled. 133fe6060f1SDimitry Andric if (Helper.tryCombineMemCpyFamily(MI, MaxLen)) 134fe6060f1SDimitry Andric return true; 135fe6060f1SDimitry Andric if (Opc == TargetOpcode::G_MEMSET) 136fe6060f1SDimitry Andric return llvm::AArch64GISelUtils::tryEmitBZero(MI, B, EnableMinSize); 137fe6060f1SDimitry Andric return false; 138fe6060f1SDimitry Andric } 139fe6060f1SDimitry Andric } 140fe6060f1SDimitry Andric 141fe6060f1SDimitry Andric return false; 142fe6060f1SDimitry Andric } 143fe6060f1SDimitry Andric 144fe6060f1SDimitry Andric // Pass boilerplate 145fe6060f1SDimitry Andric // ================ 146fe6060f1SDimitry Andric 147fe6060f1SDimitry Andric class AArch64O0PreLegalizerCombiner : public MachineFunctionPass { 148fe6060f1SDimitry Andric public: 149fe6060f1SDimitry Andric static char ID; 150fe6060f1SDimitry Andric 151fe6060f1SDimitry Andric AArch64O0PreLegalizerCombiner(); 152fe6060f1SDimitry Andric 153fe6060f1SDimitry Andric StringRef getPassName() const override { 154fe6060f1SDimitry Andric return "AArch64O0PreLegalizerCombiner"; 155fe6060f1SDimitry Andric } 156fe6060f1SDimitry Andric 157fe6060f1SDimitry Andric bool runOnMachineFunction(MachineFunction &MF) override; 158fe6060f1SDimitry Andric 159fe6060f1SDimitry Andric void getAnalysisUsage(AnalysisUsage &AU) const override; 160fe6060f1SDimitry Andric }; 161fe6060f1SDimitry Andric } // end anonymous namespace 162fe6060f1SDimitry Andric 163fe6060f1SDimitry Andric void AArch64O0PreLegalizerCombiner::getAnalysisUsage(AnalysisUsage &AU) const { 164fe6060f1SDimitry Andric AU.addRequired<TargetPassConfig>(); 165fe6060f1SDimitry Andric AU.setPreservesCFG(); 166fe6060f1SDimitry Andric getSelectionDAGFallbackAnalysisUsage(AU); 167fe6060f1SDimitry Andric AU.addRequired<GISelKnownBitsAnalysis>(); 168fe6060f1SDimitry Andric AU.addPreserved<GISelKnownBitsAnalysis>(); 169fe6060f1SDimitry Andric MachineFunctionPass::getAnalysisUsage(AU); 170fe6060f1SDimitry Andric } 171fe6060f1SDimitry Andric 172fe6060f1SDimitry Andric AArch64O0PreLegalizerCombiner::AArch64O0PreLegalizerCombiner() 173fe6060f1SDimitry Andric : MachineFunctionPass(ID) { 174fe6060f1SDimitry Andric initializeAArch64O0PreLegalizerCombinerPass(*PassRegistry::getPassRegistry()); 175fe6060f1SDimitry Andric } 176fe6060f1SDimitry Andric 177fe6060f1SDimitry Andric bool AArch64O0PreLegalizerCombiner::runOnMachineFunction(MachineFunction &MF) { 178fe6060f1SDimitry Andric if (MF.getProperties().hasProperty( 179fe6060f1SDimitry Andric MachineFunctionProperties::Property::FailedISel)) 180fe6060f1SDimitry Andric return false; 181fe6060f1SDimitry Andric auto &TPC = getAnalysis<TargetPassConfig>(); 182fe6060f1SDimitry Andric 183fe6060f1SDimitry Andric const Function &F = MF.getFunction(); 184fe6060f1SDimitry Andric GISelKnownBits *KB = &getAnalysis<GISelKnownBitsAnalysis>().get(MF); 185fe6060f1SDimitry Andric AArch64O0PreLegalizerCombinerInfo PCInfo( 186fe6060f1SDimitry Andric false, F.hasOptSize(), F.hasMinSize(), KB, nullptr /* MDT */); 187fe6060f1SDimitry Andric Combiner C(PCInfo, &TPC); 188fe6060f1SDimitry Andric return C.combineMachineInstrs(MF, nullptr /* CSEInfo */); 189fe6060f1SDimitry Andric } 190fe6060f1SDimitry Andric 191fe6060f1SDimitry Andric char AArch64O0PreLegalizerCombiner::ID = 0; 192fe6060f1SDimitry Andric INITIALIZE_PASS_BEGIN(AArch64O0PreLegalizerCombiner, DEBUG_TYPE, 193fe6060f1SDimitry Andric "Combine AArch64 machine instrs before legalization", 194fe6060f1SDimitry Andric false, false) 195fe6060f1SDimitry Andric INITIALIZE_PASS_DEPENDENCY(TargetPassConfig) 196fe6060f1SDimitry Andric INITIALIZE_PASS_DEPENDENCY(GISelKnownBitsAnalysis) 197fe6060f1SDimitry Andric INITIALIZE_PASS_DEPENDENCY(GISelCSEAnalysisWrapperPass) 198fe6060f1SDimitry Andric INITIALIZE_PASS_END(AArch64O0PreLegalizerCombiner, DEBUG_TYPE, 199fe6060f1SDimitry Andric "Combine AArch64 machine instrs before legalization", false, 200fe6060f1SDimitry Andric false) 201fe6060f1SDimitry Andric 202fe6060f1SDimitry Andric namespace llvm { 203fe6060f1SDimitry Andric FunctionPass *createAArch64O0PreLegalizerCombiner() { 204fe6060f1SDimitry Andric return new AArch64O0PreLegalizerCombiner(); 205fe6060f1SDimitry Andric } 206fe6060f1SDimitry Andric } // end namespace llvm 207