10b57cec5SDimitry Andric //===-- llvm/CodeGen/GlobalISel/CombinerHelper.h --------------*- C++ -*-===// 20b57cec5SDimitry Andric // 30b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 40b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information. 50b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 60b57cec5SDimitry Andric // 70b57cec5SDimitry Andric //===--------------------------------------------------------------------===// 8fe6060f1SDimitry Andric /// \file 90b57cec5SDimitry Andric /// This contains common combine transformations that may be used in a combine 100b57cec5SDimitry Andric /// pass,or by the target elsewhere. 110b57cec5SDimitry Andric /// Targets can pick individual opcode transformations from the helper or use 120b57cec5SDimitry Andric /// tryCombine which invokes all transformations. All of the transformations 130b57cec5SDimitry Andric /// return true if the MachineInstruction changed and false otherwise. 14fe6060f1SDimitry Andric /// 150b57cec5SDimitry Andric //===--------------------------------------------------------------------===// 160b57cec5SDimitry Andric 17fe6060f1SDimitry Andric #ifndef LLVM_CODEGEN_GLOBALISEL_COMBINERHELPER_H 18fe6060f1SDimitry Andric #define LLVM_CODEGEN_GLOBALISEL_COMBINERHELPER_H 190b57cec5SDimitry Andric 20e8d8bef9SDimitry Andric #include "llvm/ADT/DenseMap.h" 2181ad6265SDimitry Andric #include "llvm/ADT/SmallVector.h" 225f757f3fSDimitry Andric #include "llvm/CodeGen/GlobalISel/GenericMachineInstrs.h" 230b57cec5SDimitry Andric #include "llvm/CodeGen/Register.h" 24*0fca6ea1SDimitry Andric #include "llvm/CodeGenTypes/LowLevelType.h" 25bdd1243dSDimitry Andric #include "llvm/IR/InstrTypes.h" 2681ad6265SDimitry Andric #include <functional> 270b57cec5SDimitry Andric 280b57cec5SDimitry Andric namespace llvm { 290b57cec5SDimitry Andric 300b57cec5SDimitry Andric class GISelChangeObserver; 3181ad6265SDimitry Andric class APInt; 3206c3fb27SDimitry Andric class ConstantFP; 3381ad6265SDimitry Andric class GPtrAdd; 3481ad6265SDimitry Andric class GZExtLoad; 350b57cec5SDimitry Andric class MachineIRBuilder; 36e8d8bef9SDimitry Andric class MachineInstrBuilder; 370b57cec5SDimitry Andric class MachineRegisterInfo; 380b57cec5SDimitry Andric class MachineInstr; 390b57cec5SDimitry Andric class MachineOperand; 408bcb0991SDimitry Andric class GISelKnownBits; 418bcb0991SDimitry Andric class MachineDominatorTree; 425ffd83dbSDimitry Andric class LegalizerInfo; 43e8d8bef9SDimitry Andric struct LegalityQuery; 44349cc55cSDimitry Andric class RegisterBank; 45349cc55cSDimitry Andric class RegisterBankInfo; 46e8d8bef9SDimitry Andric class TargetLowering; 47349cc55cSDimitry Andric class TargetRegisterInfo; 480b57cec5SDimitry Andric 490b57cec5SDimitry Andric struct PreferredTuple { 500b57cec5SDimitry Andric LLT Ty; // The result type of the extend. 510b57cec5SDimitry Andric unsigned ExtendOpcode; // G_ANYEXT/G_SEXT/G_ZEXT 520b57cec5SDimitry Andric MachineInstr *MI; 530b57cec5SDimitry Andric }; 540b57cec5SDimitry Andric 55480093f4SDimitry Andric struct IndexedLoadStoreMatchInfo { 56480093f4SDimitry Andric Register Addr; 57480093f4SDimitry Andric Register Base; 58480093f4SDimitry Andric Register Offset; 59*0fca6ea1SDimitry Andric bool RematOffset = false; // True if Offset is a constant that needs to be 605f757f3fSDimitry Andric // rematerialized before the new load/store. 61*0fca6ea1SDimitry Andric bool IsPre = false; 62480093f4SDimitry Andric }; 63480093f4SDimitry Andric 64480093f4SDimitry Andric struct PtrAddChain { 65480093f4SDimitry Andric int64_t Imm; 66480093f4SDimitry Andric Register Base; 67349cc55cSDimitry Andric const RegisterBank *Bank; 68480093f4SDimitry Andric }; 69480093f4SDimitry Andric 70e8d8bef9SDimitry Andric struct RegisterImmPair { 71e8d8bef9SDimitry Andric Register Reg; 72e8d8bef9SDimitry Andric int64_t Imm; 73e8d8bef9SDimitry Andric }; 74e8d8bef9SDimitry Andric 75e8d8bef9SDimitry Andric struct ShiftOfShiftedLogic { 76e8d8bef9SDimitry Andric MachineInstr *Logic; 77e8d8bef9SDimitry Andric MachineInstr *Shift2; 78e8d8bef9SDimitry Andric Register LogicNonShiftReg; 79e8d8bef9SDimitry Andric uint64_t ValSum; 80e8d8bef9SDimitry Andric }; 81e8d8bef9SDimitry Andric 82349cc55cSDimitry Andric using BuildFnTy = std::function<void(MachineIRBuilder &)>; 83349cc55cSDimitry Andric 84e8d8bef9SDimitry Andric using OperandBuildSteps = 85e8d8bef9SDimitry Andric SmallVector<std::function<void(MachineInstrBuilder &)>, 4>; 86e8d8bef9SDimitry Andric struct InstructionBuildSteps { 87e8d8bef9SDimitry Andric unsigned Opcode = 0; /// The opcode for the produced instruction. 88e8d8bef9SDimitry Andric OperandBuildSteps OperandFns; /// Operands to be added to the instruction. 89e8d8bef9SDimitry Andric InstructionBuildSteps() = default; 90e8d8bef9SDimitry Andric InstructionBuildSteps(unsigned Opcode, const OperandBuildSteps &OperandFns) 91e8d8bef9SDimitry Andric : Opcode(Opcode), OperandFns(OperandFns) {} 92e8d8bef9SDimitry Andric }; 93e8d8bef9SDimitry Andric 94e8d8bef9SDimitry Andric struct InstructionStepsMatchInfo { 95e8d8bef9SDimitry Andric /// Describes instructions to be built during a combine. 96e8d8bef9SDimitry Andric SmallVector<InstructionBuildSteps, 2> InstrsToBuild; 97e8d8bef9SDimitry Andric InstructionStepsMatchInfo() = default; 98e8d8bef9SDimitry Andric InstructionStepsMatchInfo( 99e8d8bef9SDimitry Andric std::initializer_list<InstructionBuildSteps> InstrsToBuild) 100e8d8bef9SDimitry Andric : InstrsToBuild(InstrsToBuild) {} 101e8d8bef9SDimitry Andric }; 102e8d8bef9SDimitry Andric 1030b57cec5SDimitry Andric class CombinerHelper { 1048bcb0991SDimitry Andric protected: 1050b57cec5SDimitry Andric MachineIRBuilder &Builder; 1060b57cec5SDimitry Andric MachineRegisterInfo &MRI; 1070b57cec5SDimitry Andric GISelChangeObserver &Observer; 1088bcb0991SDimitry Andric GISelKnownBits *KB; 1098bcb0991SDimitry Andric MachineDominatorTree *MDT; 110bdd1243dSDimitry Andric bool IsPreLegalize; 1115ffd83dbSDimitry Andric const LegalizerInfo *LI; 112349cc55cSDimitry Andric const RegisterBankInfo *RBI; 113349cc55cSDimitry Andric const TargetRegisterInfo *TRI; 1140b57cec5SDimitry Andric 1150b57cec5SDimitry Andric public: 1168bcb0991SDimitry Andric CombinerHelper(GISelChangeObserver &Observer, MachineIRBuilder &B, 117bdd1243dSDimitry Andric bool IsPreLegalize, 1188bcb0991SDimitry Andric GISelKnownBits *KB = nullptr, 1195ffd83dbSDimitry Andric MachineDominatorTree *MDT = nullptr, 1205ffd83dbSDimitry Andric const LegalizerInfo *LI = nullptr); 1215ffd83dbSDimitry Andric 1225ffd83dbSDimitry Andric GISelKnownBits *getKnownBits() const { 1235ffd83dbSDimitry Andric return KB; 1245ffd83dbSDimitry Andric } 1250b57cec5SDimitry Andric 126bdd1243dSDimitry Andric MachineIRBuilder &getBuilder() const { 127bdd1243dSDimitry Andric return Builder; 128bdd1243dSDimitry Andric } 129bdd1243dSDimitry Andric 130e8d8bef9SDimitry Andric const TargetLowering &getTargetLowering() const; 131e8d8bef9SDimitry Andric 13281ad6265SDimitry Andric /// \returns true if the combiner is running pre-legalization. 13381ad6265SDimitry Andric bool isPreLegalize() const; 13481ad6265SDimitry Andric 13581ad6265SDimitry Andric /// \returns true if \p Query is legal on the target. 13681ad6265SDimitry Andric bool isLegal(const LegalityQuery &Query) const; 13781ad6265SDimitry Andric 138e8d8bef9SDimitry Andric /// \return true if the combine is running prior to legalization, or if \p 139e8d8bef9SDimitry Andric /// Query is legal on the target. 140e8d8bef9SDimitry Andric bool isLegalOrBeforeLegalizer(const LegalityQuery &Query) const; 141e8d8bef9SDimitry Andric 14281ad6265SDimitry Andric /// \return true if the combine is running prior to legalization, or if \p Ty 14381ad6265SDimitry Andric /// is a legal integer constant type on the target. 14481ad6265SDimitry Andric bool isConstantLegalOrBeforeLegalizer(const LLT Ty) const; 14581ad6265SDimitry Andric 1460b57cec5SDimitry Andric /// MachineRegisterInfo::replaceRegWith() and inform the observer of the changes 1470b57cec5SDimitry Andric void replaceRegWith(MachineRegisterInfo &MRI, Register FromReg, Register ToReg) const; 1480b57cec5SDimitry Andric 1490b57cec5SDimitry Andric /// Replace a single register operand with a new register and inform the 1500b57cec5SDimitry Andric /// observer of the changes. 1510b57cec5SDimitry Andric void replaceRegOpWith(MachineRegisterInfo &MRI, MachineOperand &FromRegOp, 1520b57cec5SDimitry Andric Register ToReg) const; 1530b57cec5SDimitry Andric 154349cc55cSDimitry Andric /// Replace the opcode in instruction with a new opcode and inform the 155349cc55cSDimitry Andric /// observer of the changes. 156349cc55cSDimitry Andric void replaceOpcodeWith(MachineInstr &FromMI, unsigned ToOpcode) const; 157349cc55cSDimitry Andric 158349cc55cSDimitry Andric /// Get the register bank of \p Reg. 159349cc55cSDimitry Andric /// If Reg has not been assigned a register, a register class, 160349cc55cSDimitry Andric /// or a register bank, then this returns nullptr. 161349cc55cSDimitry Andric /// 162349cc55cSDimitry Andric /// \pre Reg.isValid() 163349cc55cSDimitry Andric const RegisterBank *getRegBank(Register Reg) const; 164349cc55cSDimitry Andric 165349cc55cSDimitry Andric /// Set the register bank of \p Reg. 166349cc55cSDimitry Andric /// Does nothing if the RegBank is null. 167349cc55cSDimitry Andric /// This is the counterpart to getRegBank. 168349cc55cSDimitry Andric void setRegBank(Register Reg, const RegisterBank *RegBank); 169349cc55cSDimitry Andric 1700b57cec5SDimitry Andric /// If \p MI is COPY, try to combine it. 1710b57cec5SDimitry Andric /// Returns true if MI changed. 1720b57cec5SDimitry Andric bool tryCombineCopy(MachineInstr &MI); 1730b57cec5SDimitry Andric bool matchCombineCopy(MachineInstr &MI); 1740b57cec5SDimitry Andric void applyCombineCopy(MachineInstr &MI); 1750b57cec5SDimitry Andric 1768bcb0991SDimitry Andric /// Returns true if \p DefMI precedes \p UseMI or they are the same 1778bcb0991SDimitry Andric /// instruction. Both must be in the same basic block. 1785ffd83dbSDimitry Andric bool isPredecessor(const MachineInstr &DefMI, const MachineInstr &UseMI); 1798bcb0991SDimitry Andric 1808bcb0991SDimitry Andric /// Returns true if \p DefMI dominates \p UseMI. By definition an 1818bcb0991SDimitry Andric /// instruction dominates itself. 1828bcb0991SDimitry Andric /// 1838bcb0991SDimitry Andric /// If we haven't been provided with a MachineDominatorTree during 1848bcb0991SDimitry Andric /// construction, this function returns a conservative result that tracks just 1858bcb0991SDimitry Andric /// a single basic block. 1865ffd83dbSDimitry Andric bool dominates(const MachineInstr &DefMI, const MachineInstr &UseMI); 1878bcb0991SDimitry Andric 1880b57cec5SDimitry Andric /// If \p MI is extend that consumes the result of a load, try to combine it. 1890b57cec5SDimitry Andric /// Returns true if MI changed. 1900b57cec5SDimitry Andric bool tryCombineExtendingLoads(MachineInstr &MI); 1910b57cec5SDimitry Andric bool matchCombineExtendingLoads(MachineInstr &MI, PreferredTuple &MatchInfo); 1920b57cec5SDimitry Andric void applyCombineExtendingLoads(MachineInstr &MI, PreferredTuple &MatchInfo); 1930b57cec5SDimitry Andric 194349cc55cSDimitry Andric /// Match (and (load x), mask) -> zextload x 195349cc55cSDimitry Andric bool matchCombineLoadWithAndMask(MachineInstr &MI, BuildFnTy &MatchInfo); 196349cc55cSDimitry Andric 1975f757f3fSDimitry Andric /// Combine a G_EXTRACT_VECTOR_ELT of a load into a narrowed 1985f757f3fSDimitry Andric /// load. 1995f757f3fSDimitry Andric bool matchCombineExtractedVectorLoad(MachineInstr &MI, BuildFnTy &MatchInfo); 2005f757f3fSDimitry Andric 201480093f4SDimitry Andric bool matchCombineIndexedLoadStore(MachineInstr &MI, IndexedLoadStoreMatchInfo &MatchInfo); 202480093f4SDimitry Andric void applyCombineIndexedLoadStore(MachineInstr &MI, IndexedLoadStoreMatchInfo &MatchInfo); 2038bcb0991SDimitry Andric 204e8d8bef9SDimitry Andric bool matchSextTruncSextLoad(MachineInstr &MI); 205fe6060f1SDimitry Andric void applySextTruncSextLoad(MachineInstr &MI); 2065ffd83dbSDimitry Andric 207e8d8bef9SDimitry Andric /// Match sext_inreg(load p), imm -> sextload p 208e8d8bef9SDimitry Andric bool matchSextInRegOfLoad(MachineInstr &MI, std::tuple<Register, unsigned> &MatchInfo); 209fe6060f1SDimitry Andric void applySextInRegOfLoad(MachineInstr &MI, std::tuple<Register, unsigned> &MatchInfo); 210fe6060f1SDimitry Andric 211fe6060f1SDimitry Andric /// Try to combine G_[SU]DIV and G_[SU]REM into a single G_[SU]DIVREM 212fe6060f1SDimitry Andric /// when their source operands are identical. 213fe6060f1SDimitry Andric bool matchCombineDivRem(MachineInstr &MI, MachineInstr *&OtherMI); 214fe6060f1SDimitry Andric void applyCombineDivRem(MachineInstr &MI, MachineInstr *&OtherMI); 215e8d8bef9SDimitry Andric 216e8d8bef9SDimitry Andric /// If a brcond's true block is not the fallthrough, make it so by inverting 217e8d8bef9SDimitry Andric /// the condition and swapping operands. 218fe6060f1SDimitry Andric bool matchOptBrCondByInvertingCond(MachineInstr &MI, MachineInstr *&BrCond); 219fe6060f1SDimitry Andric void applyOptBrCondByInvertingCond(MachineInstr &MI, MachineInstr *&BrCond); 2208bcb0991SDimitry Andric 2218bcb0991SDimitry Andric /// If \p MI is G_CONCAT_VECTORS, try to combine it. 2228bcb0991SDimitry Andric /// Returns true if MI changed. 2238bcb0991SDimitry Andric /// Right now, we support: 2248bcb0991SDimitry Andric /// - concat_vector(undef, undef) => undef 2258bcb0991SDimitry Andric /// - concat_vector(build_vector(A, B), build_vector(C, D)) => 2268bcb0991SDimitry Andric /// build_vector(A, B, C, D) 227*0fca6ea1SDimitry Andric /// ========================================================== 2288bcb0991SDimitry Andric /// Check if the G_CONCAT_VECTORS \p MI is undef or if it 2298bcb0991SDimitry Andric /// can be flattened into a build_vector. 230*0fca6ea1SDimitry Andric /// In the first case \p Ops will be empty 231*0fca6ea1SDimitry Andric /// In the second case \p Ops will contain the operands 232*0fca6ea1SDimitry Andric /// needed to produce the flattened build_vector. 2338bcb0991SDimitry Andric /// 2348bcb0991SDimitry Andric /// \pre MI.getOpcode() == G_CONCAT_VECTORS. 235*0fca6ea1SDimitry Andric bool matchCombineConcatVectors(MachineInstr &MI, SmallVector<Register> &Ops); 236*0fca6ea1SDimitry Andric /// Replace \p MI with a flattened build_vector with \p Ops 237*0fca6ea1SDimitry Andric /// or an implicit_def if \p Ops is empty. 238*0fca6ea1SDimitry Andric void applyCombineConcatVectors(MachineInstr &MI, SmallVector<Register> &Ops); 239*0fca6ea1SDimitry Andric 240*0fca6ea1SDimitry Andric bool matchCombineShuffleConcat(MachineInstr &MI, SmallVector<Register> &Ops); 241*0fca6ea1SDimitry Andric /// Replace \p MI with a flattened build_vector with \p Ops 242*0fca6ea1SDimitry Andric /// or an implicit_def if \p Ops is empty. 243*0fca6ea1SDimitry Andric void applyCombineShuffleConcat(MachineInstr &MI, SmallVector<Register> &Ops); 2448bcb0991SDimitry Andric 2458bcb0991SDimitry Andric /// Try to combine G_SHUFFLE_VECTOR into G_CONCAT_VECTORS. 2468bcb0991SDimitry Andric /// Returns true if MI changed. 2478bcb0991SDimitry Andric /// 2488bcb0991SDimitry Andric /// \pre MI.getOpcode() == G_SHUFFLE_VECTOR. 2498bcb0991SDimitry Andric bool tryCombineShuffleVector(MachineInstr &MI); 2508bcb0991SDimitry Andric /// Check if the G_SHUFFLE_VECTOR \p MI can be replaced by a 2518bcb0991SDimitry Andric /// concat_vectors. 2528bcb0991SDimitry Andric /// \p Ops will contain the operands needed to produce the flattened 2538bcb0991SDimitry Andric /// concat_vectors. 2548bcb0991SDimitry Andric /// 2558bcb0991SDimitry Andric /// \pre MI.getOpcode() == G_SHUFFLE_VECTOR. 2568bcb0991SDimitry Andric bool matchCombineShuffleVector(MachineInstr &MI, 2578bcb0991SDimitry Andric SmallVectorImpl<Register> &Ops); 2588bcb0991SDimitry Andric /// Replace \p MI with a concat_vectors with \p Ops. 2598bcb0991SDimitry Andric void applyCombineShuffleVector(MachineInstr &MI, 2608bcb0991SDimitry Andric const ArrayRef<Register> Ops); 2615f757f3fSDimitry Andric bool matchShuffleToExtract(MachineInstr &MI); 2625f757f3fSDimitry Andric void applyShuffleToExtract(MachineInstr &MI); 2638bcb0991SDimitry Andric 2648bcb0991SDimitry Andric /// Optimize memcpy intrinsics et al, e.g. constant len calls. 2658bcb0991SDimitry Andric /// /p MaxLen if non-zero specifies the max length of a mem libcall to inline. 2668bcb0991SDimitry Andric /// 2678bcb0991SDimitry Andric /// For example (pre-indexed): 2688bcb0991SDimitry Andric /// 269480093f4SDimitry Andric /// $addr = G_PTR_ADD $base, $offset 2708bcb0991SDimitry Andric /// [...] 2718bcb0991SDimitry Andric /// $val = G_LOAD $addr 2728bcb0991SDimitry Andric /// [...] 2738bcb0991SDimitry Andric /// $whatever = COPY $addr 2748bcb0991SDimitry Andric /// 2758bcb0991SDimitry Andric /// --> 2768bcb0991SDimitry Andric /// 2778bcb0991SDimitry Andric /// $val, $addr = G_INDEXED_LOAD $base, $offset, 1 (IsPre) 2788bcb0991SDimitry Andric /// [...] 2798bcb0991SDimitry Andric /// $whatever = COPY $addr 2808bcb0991SDimitry Andric /// 2818bcb0991SDimitry Andric /// or (post-indexed): 2828bcb0991SDimitry Andric /// 2838bcb0991SDimitry Andric /// G_STORE $val, $base 2848bcb0991SDimitry Andric /// [...] 285480093f4SDimitry Andric /// $addr = G_PTR_ADD $base, $offset 2868bcb0991SDimitry Andric /// [...] 2878bcb0991SDimitry Andric /// $whatever = COPY $addr 2888bcb0991SDimitry Andric /// 2898bcb0991SDimitry Andric /// --> 2908bcb0991SDimitry Andric /// 2918bcb0991SDimitry Andric /// $addr = G_INDEXED_STORE $val, $base, $offset 2928bcb0991SDimitry Andric /// [...] 2938bcb0991SDimitry Andric /// $whatever = COPY $addr 2948bcb0991SDimitry Andric bool tryCombineMemCpyFamily(MachineInstr &MI, unsigned MaxLen = 0); 2950b57cec5SDimitry Andric 296480093f4SDimitry Andric bool matchPtrAddImmedChain(MachineInstr &MI, PtrAddChain &MatchInfo); 297fe6060f1SDimitry Andric void applyPtrAddImmedChain(MachineInstr &MI, PtrAddChain &MatchInfo); 298480093f4SDimitry Andric 299e8d8bef9SDimitry Andric /// Fold (shift (shift base, x), y) -> (shift base (x+y)) 300e8d8bef9SDimitry Andric bool matchShiftImmedChain(MachineInstr &MI, RegisterImmPair &MatchInfo); 301fe6060f1SDimitry Andric void applyShiftImmedChain(MachineInstr &MI, RegisterImmPair &MatchInfo); 302e8d8bef9SDimitry Andric 303e8d8bef9SDimitry Andric /// If we have a shift-by-constant of a bitwise logic op that itself has a 304e8d8bef9SDimitry Andric /// shift-by-constant operand with identical opcode, we may be able to convert 305e8d8bef9SDimitry Andric /// that into 2 independent shifts followed by the logic op. 306e8d8bef9SDimitry Andric bool matchShiftOfShiftedLogic(MachineInstr &MI, 307e8d8bef9SDimitry Andric ShiftOfShiftedLogic &MatchInfo); 308fe6060f1SDimitry Andric void applyShiftOfShiftedLogic(MachineInstr &MI, 309e8d8bef9SDimitry Andric ShiftOfShiftedLogic &MatchInfo); 310e8d8bef9SDimitry Andric 31106c3fb27SDimitry Andric bool matchCommuteShift(MachineInstr &MI, BuildFnTy &MatchInfo); 31206c3fb27SDimitry Andric 3135ffd83dbSDimitry Andric /// Transform a multiply by a power-of-2 value to a left shift. 3145ffd83dbSDimitry Andric bool matchCombineMulToShl(MachineInstr &MI, unsigned &ShiftVal); 315fe6060f1SDimitry Andric void applyCombineMulToShl(MachineInstr &MI, unsigned &ShiftVal); 3165ffd83dbSDimitry Andric 317e8d8bef9SDimitry Andric // Transform a G_SHL with an extended source into a narrower shift if 318e8d8bef9SDimitry Andric // possible. 319e8d8bef9SDimitry Andric bool matchCombineShlOfExtend(MachineInstr &MI, RegisterImmPair &MatchData); 320fe6060f1SDimitry Andric void applyCombineShlOfExtend(MachineInstr &MI, 321e8d8bef9SDimitry Andric const RegisterImmPair &MatchData); 322e8d8bef9SDimitry Andric 323fe6060f1SDimitry Andric /// Fold away a merge of an unmerge of the corresponding values. 324fe6060f1SDimitry Andric bool matchCombineMergeUnmerge(MachineInstr &MI, Register &MatchInfo); 325fe6060f1SDimitry Andric 3265ffd83dbSDimitry Andric /// Reduce a shift by a constant to an unmerge and a shift on a half sized 3275ffd83dbSDimitry Andric /// type. This will not produce a shift smaller than \p TargetShiftSize. 3285ffd83dbSDimitry Andric bool matchCombineShiftToUnmerge(MachineInstr &MI, unsigned TargetShiftSize, 3295ffd83dbSDimitry Andric unsigned &ShiftVal); 330fe6060f1SDimitry Andric void applyCombineShiftToUnmerge(MachineInstr &MI, const unsigned &ShiftVal); 3315ffd83dbSDimitry Andric bool tryCombineShiftToUnmerge(MachineInstr &MI, unsigned TargetShiftAmount); 3325ffd83dbSDimitry Andric 333e8d8bef9SDimitry Andric /// Transform <ty,...> G_UNMERGE(G_MERGE ty X, Y, Z) -> ty X, Y, Z. 334e8d8bef9SDimitry Andric bool 335e8d8bef9SDimitry Andric matchCombineUnmergeMergeToPlainValues(MachineInstr &MI, 336e8d8bef9SDimitry Andric SmallVectorImpl<Register> &Operands); 337fe6060f1SDimitry Andric void 338e8d8bef9SDimitry Andric applyCombineUnmergeMergeToPlainValues(MachineInstr &MI, 339e8d8bef9SDimitry Andric SmallVectorImpl<Register> &Operands); 340e8d8bef9SDimitry Andric 341e8d8bef9SDimitry Andric /// Transform G_UNMERGE Constant -> Constant1, Constant2, ... 342e8d8bef9SDimitry Andric bool matchCombineUnmergeConstant(MachineInstr &MI, 343e8d8bef9SDimitry Andric SmallVectorImpl<APInt> &Csts); 344fe6060f1SDimitry Andric void applyCombineUnmergeConstant(MachineInstr &MI, 345e8d8bef9SDimitry Andric SmallVectorImpl<APInt> &Csts); 346e8d8bef9SDimitry Andric 34704eeddc0SDimitry Andric /// Transform G_UNMERGE G_IMPLICIT_DEF -> G_IMPLICIT_DEF, G_IMPLICIT_DEF, ... 34804eeddc0SDimitry Andric bool 34904eeddc0SDimitry Andric matchCombineUnmergeUndef(MachineInstr &MI, 35004eeddc0SDimitry Andric std::function<void(MachineIRBuilder &)> &MatchInfo); 35104eeddc0SDimitry Andric 352e8d8bef9SDimitry Andric /// Transform X, Y<dead> = G_UNMERGE Z -> X = G_TRUNC Z. 353e8d8bef9SDimitry Andric bool matchCombineUnmergeWithDeadLanesToTrunc(MachineInstr &MI); 354fe6060f1SDimitry Andric void applyCombineUnmergeWithDeadLanesToTrunc(MachineInstr &MI); 355e8d8bef9SDimitry Andric 356e8d8bef9SDimitry Andric /// Transform X, Y = G_UNMERGE(G_ZEXT(Z)) -> X = G_ZEXT(Z); Y = G_CONSTANT 0 357e8d8bef9SDimitry Andric bool matchCombineUnmergeZExtToZExt(MachineInstr &MI); 358fe6060f1SDimitry Andric void applyCombineUnmergeZExtToZExt(MachineInstr &MI); 359e8d8bef9SDimitry Andric 360e8d8bef9SDimitry Andric /// Transform fp_instr(cst) to constant result of the fp operation. 36106c3fb27SDimitry Andric void applyCombineConstantFoldFpUnary(MachineInstr &MI, const ConstantFP *Cst); 362e8d8bef9SDimitry Andric 363e8d8bef9SDimitry Andric /// Transform IntToPtr(PtrToInt(x)) to x if cast is in the same address space. 364e8d8bef9SDimitry Andric bool matchCombineI2PToP2I(MachineInstr &MI, Register &Reg); 365fe6060f1SDimitry Andric void applyCombineI2PToP2I(MachineInstr &MI, Register &Reg); 366e8d8bef9SDimitry Andric 367e8d8bef9SDimitry Andric /// Transform PtrToInt(IntToPtr(x)) to x. 368fe6060f1SDimitry Andric void applyCombineP2IToI2P(MachineInstr &MI, Register &Reg); 369e8d8bef9SDimitry Andric 370e8d8bef9SDimitry Andric /// Transform G_ADD (G_PTRTOINT x), y -> G_PTRTOINT (G_PTR_ADD x, y) 371e8d8bef9SDimitry Andric /// Transform G_ADD y, (G_PTRTOINT x) -> G_PTRTOINT (G_PTR_ADD x, y) 372e8d8bef9SDimitry Andric bool matchCombineAddP2IToPtrAdd(MachineInstr &MI, 373e8d8bef9SDimitry Andric std::pair<Register, bool> &PtrRegAndCommute); 374fe6060f1SDimitry Andric void applyCombineAddP2IToPtrAdd(MachineInstr &MI, 375e8d8bef9SDimitry Andric std::pair<Register, bool> &PtrRegAndCommute); 376e8d8bef9SDimitry Andric 377e8d8bef9SDimitry Andric // Transform G_PTR_ADD (G_PTRTOINT C1), C2 -> C1 + C2 37804eeddc0SDimitry Andric bool matchCombineConstPtrAddToI2P(MachineInstr &MI, APInt &NewCst); 37904eeddc0SDimitry Andric void applyCombineConstPtrAddToI2P(MachineInstr &MI, APInt &NewCst); 380e8d8bef9SDimitry Andric 381e8d8bef9SDimitry Andric /// Transform anyext(trunc(x)) to x. 382e8d8bef9SDimitry Andric bool matchCombineAnyExtTrunc(MachineInstr &MI, Register &Reg); 383fe6060f1SDimitry Andric 384fe6060f1SDimitry Andric /// Transform zext(trunc(x)) to x. 385fe6060f1SDimitry Andric bool matchCombineZextTrunc(MachineInstr &MI, Register &Reg); 386e8d8bef9SDimitry Andric 387e8d8bef9SDimitry Andric /// Transform [asz]ext([asz]ext(x)) to [asz]ext x. 388e8d8bef9SDimitry Andric bool matchCombineExtOfExt(MachineInstr &MI, 389e8d8bef9SDimitry Andric std::tuple<Register, unsigned> &MatchInfo); 390fe6060f1SDimitry Andric void applyCombineExtOfExt(MachineInstr &MI, 391e8d8bef9SDimitry Andric std::tuple<Register, unsigned> &MatchInfo); 392e8d8bef9SDimitry Andric 393e8d8bef9SDimitry Andric /// Transform trunc ([asz]ext x) to x or ([asz]ext x) or (trunc x). 394e8d8bef9SDimitry Andric bool matchCombineTruncOfExt(MachineInstr &MI, 395e8d8bef9SDimitry Andric std::pair<Register, unsigned> &MatchInfo); 396fe6060f1SDimitry Andric void applyCombineTruncOfExt(MachineInstr &MI, 397e8d8bef9SDimitry Andric std::pair<Register, unsigned> &MatchInfo); 398e8d8bef9SDimitry Andric 399bdd1243dSDimitry Andric /// Transform trunc (shl x, K) to shl (trunc x), K 400bdd1243dSDimitry Andric /// if K < VT.getScalarSizeInBits(). 401bdd1243dSDimitry Andric /// 402bdd1243dSDimitry Andric /// Transforms trunc ([al]shr x, K) to (trunc ([al]shr (MidVT (trunc x)), K)) 403bdd1243dSDimitry Andric /// if K <= (MidVT.getScalarSizeInBits() - VT.getScalarSizeInBits()) 404bdd1243dSDimitry Andric /// MidVT is obtained by finding a legal type between the trunc's src and dst 405bdd1243dSDimitry Andric /// types. 406bdd1243dSDimitry Andric bool matchCombineTruncOfShift(MachineInstr &MI, 407bdd1243dSDimitry Andric std::pair<MachineInstr *, LLT> &MatchInfo); 408bdd1243dSDimitry Andric void applyCombineTruncOfShift(MachineInstr &MI, 409bdd1243dSDimitry Andric std::pair<MachineInstr *, LLT> &MatchInfo); 410e8d8bef9SDimitry Andric 4115ffd83dbSDimitry Andric /// Return true if any explicit use operand on \p MI is defined by a 4125ffd83dbSDimitry Andric /// G_IMPLICIT_DEF. 4135ffd83dbSDimitry Andric bool matchAnyExplicitUseIsUndef(MachineInstr &MI); 4145ffd83dbSDimitry Andric 4155ffd83dbSDimitry Andric /// Return true if all register explicit use operands on \p MI are defined by 4165ffd83dbSDimitry Andric /// a G_IMPLICIT_DEF. 4175ffd83dbSDimitry Andric bool matchAllExplicitUsesAreUndef(MachineInstr &MI); 4185ffd83dbSDimitry Andric 4195ffd83dbSDimitry Andric /// Return true if a G_SHUFFLE_VECTOR instruction \p MI has an undef mask. 4205ffd83dbSDimitry Andric bool matchUndefShuffleVectorMask(MachineInstr &MI); 4215ffd83dbSDimitry Andric 4225ffd83dbSDimitry Andric /// Return true if a G_STORE instruction \p MI is storing an undef value. 4235ffd83dbSDimitry Andric bool matchUndefStore(MachineInstr &MI); 4245ffd83dbSDimitry Andric 425e8d8bef9SDimitry Andric /// Return true if a G_SELECT instruction \p MI has an undef comparison. 426e8d8bef9SDimitry Andric bool matchUndefSelectCmp(MachineInstr &MI); 427e8d8bef9SDimitry Andric 428bdd1243dSDimitry Andric /// Return true if a G_{EXTRACT,INSERT}_VECTOR_ELT has an out of range index. 429bdd1243dSDimitry Andric bool matchInsertExtractVecEltOutOfBounds(MachineInstr &MI); 430bdd1243dSDimitry Andric 431e8d8bef9SDimitry Andric /// Return true if a G_SELECT instruction \p MI has a constant comparison. If 432e8d8bef9SDimitry Andric /// true, \p OpIdx will store the operand index of the known selected value. 433e8d8bef9SDimitry Andric bool matchConstantSelectCmp(MachineInstr &MI, unsigned &OpIdx); 434e8d8bef9SDimitry Andric 4355ffd83dbSDimitry Andric /// Replace an instruction with a G_FCONSTANT with value \p C. 43606c3fb27SDimitry Andric void replaceInstWithFConstant(MachineInstr &MI, double C); 4375ffd83dbSDimitry Andric 4385f757f3fSDimitry Andric /// Replace an instruction with an G_FCONSTANT with value \p CFP. 4395f757f3fSDimitry Andric void replaceInstWithFConstant(MachineInstr &MI, ConstantFP *CFP); 4405f757f3fSDimitry Andric 4415ffd83dbSDimitry Andric /// Replace an instruction with a G_CONSTANT with value \p C. 44206c3fb27SDimitry Andric void replaceInstWithConstant(MachineInstr &MI, int64_t C); 4435ffd83dbSDimitry Andric 444fe6060f1SDimitry Andric /// Replace an instruction with a G_CONSTANT with value \p C. 44506c3fb27SDimitry Andric void replaceInstWithConstant(MachineInstr &MI, APInt C); 446fe6060f1SDimitry Andric 4475ffd83dbSDimitry Andric /// Replace an instruction with a G_IMPLICIT_DEF. 44806c3fb27SDimitry Andric void replaceInstWithUndef(MachineInstr &MI); 4495ffd83dbSDimitry Andric 4505ffd83dbSDimitry Andric /// Delete \p MI and replace all of its uses with its \p OpIdx-th operand. 45106c3fb27SDimitry Andric void replaceSingleDefInstWithOperand(MachineInstr &MI, unsigned OpIdx); 4525ffd83dbSDimitry Andric 453e8d8bef9SDimitry Andric /// Delete \p MI and replace all of its uses with \p Replacement. 45406c3fb27SDimitry Andric void replaceSingleDefInstWithReg(MachineInstr &MI, Register Replacement); 455e8d8bef9SDimitry Andric 4565f757f3fSDimitry Andric /// @brief Replaces the shift amount in \p MI with ShiftAmt % BW 4575f757f3fSDimitry Andric /// @param MI 4585f757f3fSDimitry Andric void applyFunnelShiftConstantModulo(MachineInstr &MI); 4595f757f3fSDimitry Andric 4605ffd83dbSDimitry Andric /// Return true if \p MOP1 and \p MOP2 are register operands are defined by 4615ffd83dbSDimitry Andric /// equivalent instructions. 4625ffd83dbSDimitry Andric bool matchEqualDefs(const MachineOperand &MOP1, const MachineOperand &MOP2); 4635ffd83dbSDimitry Andric 4645f757f3fSDimitry Andric /// Return true if \p MOP is defined by a G_CONSTANT or splat with a value equal to 4655ffd83dbSDimitry Andric /// \p C. 4665ffd83dbSDimitry Andric bool matchConstantOp(const MachineOperand &MOP, int64_t C); 4675ffd83dbSDimitry Andric 4685f757f3fSDimitry Andric /// Return true if \p MOP is defined by a G_FCONSTANT or splat with a value exactly 4695f757f3fSDimitry Andric /// equal to \p C. 4705f757f3fSDimitry Andric bool matchConstantFPOp(const MachineOperand &MOP, double C); 4715f757f3fSDimitry Andric 4725f757f3fSDimitry Andric /// @brief Checks if constant at \p ConstIdx is larger than \p MI 's bitwidth 4735f757f3fSDimitry Andric /// @param ConstIdx Index of the constant 4745f757f3fSDimitry Andric bool matchConstantLargerBitWidth(MachineInstr &MI, unsigned ConstIdx); 4755f757f3fSDimitry Andric 4765ffd83dbSDimitry Andric /// Optimize (cond ? x : x) -> x 4775ffd83dbSDimitry Andric bool matchSelectSameVal(MachineInstr &MI); 4785ffd83dbSDimitry Andric 4795ffd83dbSDimitry Andric /// Optimize (x op x) -> x 4805ffd83dbSDimitry Andric bool matchBinOpSameVal(MachineInstr &MI); 4815ffd83dbSDimitry Andric 4825ffd83dbSDimitry Andric /// Check if operand \p OpIdx is zero. 4835ffd83dbSDimitry Andric bool matchOperandIsZero(MachineInstr &MI, unsigned OpIdx); 4845ffd83dbSDimitry Andric 485e8d8bef9SDimitry Andric /// Check if operand \p OpIdx is undef. 486e8d8bef9SDimitry Andric bool matchOperandIsUndef(MachineInstr &MI, unsigned OpIdx); 487e8d8bef9SDimitry Andric 488e8d8bef9SDimitry Andric /// Check if operand \p OpIdx is known to be a power of 2. 489e8d8bef9SDimitry Andric bool matchOperandIsKnownToBeAPowerOfTwo(MachineInstr &MI, unsigned OpIdx); 490e8d8bef9SDimitry Andric 4915ffd83dbSDimitry Andric /// Erase \p MI 49206c3fb27SDimitry Andric void eraseInst(MachineInstr &MI); 4935ffd83dbSDimitry Andric 4945ffd83dbSDimitry Andric /// Return true if MI is a G_ADD which can be simplified to a G_SUB. 4955ffd83dbSDimitry Andric bool matchSimplifyAddToSub(MachineInstr &MI, 4965ffd83dbSDimitry Andric std::tuple<Register, Register> &MatchInfo); 497fe6060f1SDimitry Andric void applySimplifyAddToSub(MachineInstr &MI, 4985ffd83dbSDimitry Andric std::tuple<Register, Register> &MatchInfo); 4995ffd83dbSDimitry Andric 500e8d8bef9SDimitry Andric /// Match (logic_op (op x...), (op y...)) -> (op (logic_op x, y)) 501e8d8bef9SDimitry Andric bool 502e8d8bef9SDimitry Andric matchHoistLogicOpWithSameOpcodeHands(MachineInstr &MI, 503e8d8bef9SDimitry Andric InstructionStepsMatchInfo &MatchInfo); 504e8d8bef9SDimitry Andric 505e8d8bef9SDimitry Andric /// Replace \p MI with a series of instructions described in \p MatchInfo. 506fe6060f1SDimitry Andric void applyBuildInstructionSteps(MachineInstr &MI, 507e8d8bef9SDimitry Andric InstructionStepsMatchInfo &MatchInfo); 508e8d8bef9SDimitry Andric 509e8d8bef9SDimitry Andric /// Match ashr (shl x, C), C -> sext_inreg (C) 510e8d8bef9SDimitry Andric bool matchAshrShlToSextInreg(MachineInstr &MI, 511e8d8bef9SDimitry Andric std::tuple<Register, int64_t> &MatchInfo); 512fe6060f1SDimitry Andric void applyAshShlToSextInreg(MachineInstr &MI, 513e8d8bef9SDimitry Andric std::tuple<Register, int64_t> &MatchInfo); 514fe6060f1SDimitry Andric 515fe6060f1SDimitry Andric /// Fold and(and(x, C1), C2) -> C1&C2 ? and(x, C1&C2) : 0 516fe6060f1SDimitry Andric bool matchOverlappingAnd(MachineInstr &MI, 517349cc55cSDimitry Andric BuildFnTy &MatchInfo); 518fe6060f1SDimitry Andric 519e8d8bef9SDimitry Andric /// \return true if \p MI is a G_AND instruction whose operands are x and y 520e8d8bef9SDimitry Andric /// where x & y == x or x & y == y. (E.g., one of operands is all-ones value.) 521e8d8bef9SDimitry Andric /// 522e8d8bef9SDimitry Andric /// \param [in] MI - The G_AND instruction. 523e8d8bef9SDimitry Andric /// \param [out] Replacement - A register the G_AND should be replaced with on 524e8d8bef9SDimitry Andric /// success. 525e8d8bef9SDimitry Andric bool matchRedundantAnd(MachineInstr &MI, Register &Replacement); 526e8d8bef9SDimitry Andric 527e8d8bef9SDimitry Andric /// \return true if \p MI is a G_OR instruction whose operands are x and y 528e8d8bef9SDimitry Andric /// where x | y == x or x | y == y. (E.g., one of operands is all-zeros 529e8d8bef9SDimitry Andric /// value.) 530e8d8bef9SDimitry Andric /// 531e8d8bef9SDimitry Andric /// \param [in] MI - The G_OR instruction. 532e8d8bef9SDimitry Andric /// \param [out] Replacement - A register the G_OR should be replaced with on 533e8d8bef9SDimitry Andric /// success. 534e8d8bef9SDimitry Andric bool matchRedundantOr(MachineInstr &MI, Register &Replacement); 535e8d8bef9SDimitry Andric 536e8d8bef9SDimitry Andric /// \return true if \p MI is a G_SEXT_INREG that can be erased. 537e8d8bef9SDimitry Andric bool matchRedundantSExtInReg(MachineInstr &MI); 538e8d8bef9SDimitry Andric 539e8d8bef9SDimitry Andric /// Combine inverting a result of a compare into the opposite cond code. 540e8d8bef9SDimitry Andric bool matchNotCmp(MachineInstr &MI, SmallVectorImpl<Register> &RegsToNegate); 541fe6060f1SDimitry Andric void applyNotCmp(MachineInstr &MI, SmallVectorImpl<Register> &RegsToNegate); 542e8d8bef9SDimitry Andric 543e8d8bef9SDimitry Andric /// Fold (xor (and x, y), y) -> (and (not x), y) 544e8d8bef9SDimitry Andric ///{ 545e8d8bef9SDimitry Andric bool matchXorOfAndWithSameReg(MachineInstr &MI, 546e8d8bef9SDimitry Andric std::pair<Register, Register> &MatchInfo); 547fe6060f1SDimitry Andric void applyXorOfAndWithSameReg(MachineInstr &MI, 548e8d8bef9SDimitry Andric std::pair<Register, Register> &MatchInfo); 549e8d8bef9SDimitry Andric ///} 550e8d8bef9SDimitry Andric 551e8d8bef9SDimitry Andric /// Combine G_PTR_ADD with nullptr to G_INTTOPTR 552e8d8bef9SDimitry Andric bool matchPtrAddZero(MachineInstr &MI); 553fe6060f1SDimitry Andric void applyPtrAddZero(MachineInstr &MI); 554e8d8bef9SDimitry Andric 555e8d8bef9SDimitry Andric /// Combine G_UREM x, (known power of 2) to an add and bitmasking. 556fe6060f1SDimitry Andric void applySimplifyURemByPow2(MachineInstr &MI); 557e8d8bef9SDimitry Andric 55881ad6265SDimitry Andric /// Push a binary operator through a select on constants. 55981ad6265SDimitry Andric /// 56081ad6265SDimitry Andric /// binop (select cond, K0, K1), K2 -> 56181ad6265SDimitry Andric /// select cond, (binop K0, K2), (binop K1, K2) 56281ad6265SDimitry Andric bool matchFoldBinOpIntoSelect(MachineInstr &MI, unsigned &SelectOpNo); 56306c3fb27SDimitry Andric void applyFoldBinOpIntoSelect(MachineInstr &MI, const unsigned &SelectOpNo); 56481ad6265SDimitry Andric 565e8d8bef9SDimitry Andric bool matchCombineInsertVecElts(MachineInstr &MI, 566e8d8bef9SDimitry Andric SmallVectorImpl<Register> &MatchInfo); 567e8d8bef9SDimitry Andric 568fe6060f1SDimitry Andric void applyCombineInsertVecElts(MachineInstr &MI, 569e8d8bef9SDimitry Andric SmallVectorImpl<Register> &MatchInfo); 570e8d8bef9SDimitry Andric 571e8d8bef9SDimitry Andric /// Match expression trees of the form 572e8d8bef9SDimitry Andric /// 573e8d8bef9SDimitry Andric /// \code 574e8d8bef9SDimitry Andric /// sN *a = ... 575e8d8bef9SDimitry Andric /// sM val = a[0] | (a[1] << N) | (a[2] << 2N) | (a[3] << 3N) ... 576e8d8bef9SDimitry Andric /// \endcode 577e8d8bef9SDimitry Andric /// 578e8d8bef9SDimitry Andric /// And check if the tree can be replaced with a M-bit load + possibly a 579e8d8bef9SDimitry Andric /// bswap. 580349cc55cSDimitry Andric bool matchLoadOrCombine(MachineInstr &MI, BuildFnTy &MatchInfo); 581349cc55cSDimitry Andric 582fe6060f1SDimitry Andric bool matchExtendThroughPhis(MachineInstr &MI, MachineInstr *&ExtMI); 583fe6060f1SDimitry Andric void applyExtendThroughPhis(MachineInstr &MI, MachineInstr *&ExtMI); 584fe6060f1SDimitry Andric 585fe6060f1SDimitry Andric bool matchExtractVecEltBuildVec(MachineInstr &MI, Register &Reg); 586fe6060f1SDimitry Andric void applyExtractVecEltBuildVec(MachineInstr &MI, Register &Reg); 587fe6060f1SDimitry Andric 588fe6060f1SDimitry Andric bool matchExtractAllEltsFromBuildVector( 589fe6060f1SDimitry Andric MachineInstr &MI, 590fe6060f1SDimitry Andric SmallVectorImpl<std::pair<Register, MachineInstr *>> &MatchInfo); 591fe6060f1SDimitry Andric void applyExtractAllEltsFromBuildVector( 592fe6060f1SDimitry Andric MachineInstr &MI, 593fe6060f1SDimitry Andric SmallVectorImpl<std::pair<Register, MachineInstr *>> &MatchInfo); 594fe6060f1SDimitry Andric 595fe6060f1SDimitry Andric /// Use a function which takes in a MachineIRBuilder to perform a combine. 596fe6060f1SDimitry Andric /// By default, it erases the instruction \p MI from the function. 597349cc55cSDimitry Andric void applyBuildFn(MachineInstr &MI, BuildFnTy &MatchInfo); 598fe6060f1SDimitry Andric /// Use a function which takes in a MachineIRBuilder to perform a combine. 599fe6060f1SDimitry Andric /// This variant does not erase \p MI after calling the build function. 600349cc55cSDimitry Andric void applyBuildFnNoErase(MachineInstr &MI, BuildFnTy &MatchInfo); 601fe6060f1SDimitry Andric 6024824e7fdSDimitry Andric bool matchOrShiftToFunnelShift(MachineInstr &MI, BuildFnTy &MatchInfo); 603fe6060f1SDimitry Andric bool matchFunnelShiftToRotate(MachineInstr &MI); 604fe6060f1SDimitry Andric void applyFunnelShiftToRotate(MachineInstr &MI); 605fe6060f1SDimitry Andric bool matchRotateOutOfRange(MachineInstr &MI); 606fe6060f1SDimitry Andric void applyRotateOutOfRange(MachineInstr &MI); 607fe6060f1SDimitry Andric 608fe6060f1SDimitry Andric /// \returns true if a G_ICMP instruction \p MI can be replaced with a true 609fe6060f1SDimitry Andric /// or false constant based off of KnownBits information. 610fe6060f1SDimitry Andric bool matchICmpToTrueFalseKnownBits(MachineInstr &MI, int64_t &MatchInfo); 611fe6060f1SDimitry Andric 612349cc55cSDimitry Andric /// \returns true if a G_ICMP \p MI can be replaced with its LHS based off of 613349cc55cSDimitry Andric /// KnownBits information. 614349cc55cSDimitry Andric bool 615349cc55cSDimitry Andric matchICmpToLHSKnownBits(MachineInstr &MI, 616349cc55cSDimitry Andric BuildFnTy &MatchInfo); 617fe6060f1SDimitry Andric 618349cc55cSDimitry Andric /// \returns true if (and (or x, c1), c2) can be replaced with (and x, c2) 619349cc55cSDimitry Andric bool matchAndOrDisjointMask(MachineInstr &MI, BuildFnTy &MatchInfo); 620349cc55cSDimitry Andric 621349cc55cSDimitry Andric bool matchBitfieldExtractFromSExtInReg(MachineInstr &MI, 622349cc55cSDimitry Andric BuildFnTy &MatchInfo); 623349cc55cSDimitry Andric /// Match: and (lshr x, cst), mask -> ubfx x, cst, width 624349cc55cSDimitry Andric bool matchBitfieldExtractFromAnd(MachineInstr &MI, BuildFnTy &MatchInfo); 625349cc55cSDimitry Andric 626349cc55cSDimitry Andric /// Match: shr (shl x, n), k -> sbfx/ubfx x, pos, width 627349cc55cSDimitry Andric bool matchBitfieldExtractFromShr(MachineInstr &MI, BuildFnTy &MatchInfo); 628349cc55cSDimitry Andric 629349cc55cSDimitry Andric /// Match: shr (and x, n), k -> ubfx x, pos, width 630349cc55cSDimitry Andric bool matchBitfieldExtractFromShrAnd(MachineInstr &MI, BuildFnTy &MatchInfo); 631349cc55cSDimitry Andric 632349cc55cSDimitry Andric // Helpers for reassociation: 633349cc55cSDimitry Andric bool matchReassocConstantInnerRHS(GPtrAdd &MI, MachineInstr *RHS, 634349cc55cSDimitry Andric BuildFnTy &MatchInfo); 635349cc55cSDimitry Andric bool matchReassocFoldConstantsInSubTree(GPtrAdd &MI, MachineInstr *LHS, 636349cc55cSDimitry Andric MachineInstr *RHS, 637349cc55cSDimitry Andric BuildFnTy &MatchInfo); 638349cc55cSDimitry Andric bool matchReassocConstantInnerLHS(GPtrAdd &MI, MachineInstr *LHS, 639349cc55cSDimitry Andric MachineInstr *RHS, BuildFnTy &MatchInfo); 640fe6060f1SDimitry Andric /// Reassociate pointer calculations with G_ADD involved, to allow better 641fe6060f1SDimitry Andric /// addressing mode usage. 642349cc55cSDimitry Andric bool matchReassocPtrAdd(MachineInstr &MI, BuildFnTy &MatchInfo); 643fe6060f1SDimitry Andric 64406c3fb27SDimitry Andric /// Try to reassociate to reassociate operands of a commutative binop. 64506c3fb27SDimitry Andric bool tryReassocBinOp(unsigned Opc, Register DstReg, Register Op0, 64606c3fb27SDimitry Andric Register Op1, BuildFnTy &MatchInfo); 64706c3fb27SDimitry Andric /// Reassociate commutative binary operations like G_ADD. 64806c3fb27SDimitry Andric bool matchReassocCommBinOp(MachineInstr &MI, BuildFnTy &MatchInfo); 64906c3fb27SDimitry Andric 650fe6060f1SDimitry Andric /// Do constant folding when opportunities are exposed after MIR building. 6515f757f3fSDimitry Andric bool matchConstantFoldCastOp(MachineInstr &MI, APInt &MatchInfo); 6525f757f3fSDimitry Andric 6535f757f3fSDimitry Andric /// Do constant folding when opportunities are exposed after MIR building. 6545f757f3fSDimitry Andric bool matchConstantFoldBinOp(MachineInstr &MI, APInt &MatchInfo); 6555f757f3fSDimitry Andric 6565f757f3fSDimitry Andric /// Do constant FP folding when opportunities are exposed after MIR building. 6575f757f3fSDimitry Andric bool matchConstantFoldFPBinOp(MachineInstr &MI, ConstantFP* &MatchInfo); 6585f757f3fSDimitry Andric 6595f757f3fSDimitry Andric /// Constant fold G_FMA/G_FMAD. 6605f757f3fSDimitry Andric bool matchConstantFoldFMA(MachineInstr &MI, ConstantFP *&MatchInfo); 661e8d8bef9SDimitry Andric 662349cc55cSDimitry Andric /// \returns true if it is possible to narrow the width of a scalar binop 663349cc55cSDimitry Andric /// feeding a G_AND instruction \p MI. 664349cc55cSDimitry Andric bool matchNarrowBinopFeedingAnd(MachineInstr &MI, BuildFnTy &MatchInfo); 665349cc55cSDimitry Andric 666349cc55cSDimitry Andric /// Given an G_UDIV \p MI expressing a divide by constant, return an 667349cc55cSDimitry Andric /// expression that implements it by multiplying by a magic number. 668349cc55cSDimitry Andric /// Ref: "Hacker's Delight" or "The PowerPC Compiler Writer's Guide". 669349cc55cSDimitry Andric MachineInstr *buildUDivUsingMul(MachineInstr &MI); 670349cc55cSDimitry Andric /// Combine G_UDIV by constant into a multiply by magic constant. 671349cc55cSDimitry Andric bool matchUDivByConst(MachineInstr &MI); 672349cc55cSDimitry Andric void applyUDivByConst(MachineInstr &MI); 673349cc55cSDimitry Andric 674bdd1243dSDimitry Andric /// Given an G_SDIV \p MI expressing a signed divide by constant, return an 675bdd1243dSDimitry Andric /// expression that implements it by multiplying by a magic number. 676bdd1243dSDimitry Andric /// Ref: "Hacker's Delight" or "The PowerPC Compiler Writer's Guide". 677bdd1243dSDimitry Andric MachineInstr *buildSDivUsingMul(MachineInstr &MI); 678bdd1243dSDimitry Andric bool matchSDivByConst(MachineInstr &MI); 679bdd1243dSDimitry Andric void applySDivByConst(MachineInstr &MI); 680bdd1243dSDimitry Andric 681*0fca6ea1SDimitry Andric /// Given an G_SDIV \p MI expressing a signed divided by a pow2 constant, 682*0fca6ea1SDimitry Andric /// return expressions that implements it by shifting. 683*0fca6ea1SDimitry Andric bool matchDivByPow2(MachineInstr &MI, bool IsSigned); 684*0fca6ea1SDimitry Andric void applySDivByPow2(MachineInstr &MI); 685*0fca6ea1SDimitry Andric /// Given an G_UDIV \p MI expressing an unsigned divided by a pow2 constant, 686*0fca6ea1SDimitry Andric /// return expressions that implements it by shifting. 687*0fca6ea1SDimitry Andric void applyUDivByPow2(MachineInstr &MI); 688*0fca6ea1SDimitry Andric 689349cc55cSDimitry Andric // G_UMULH x, (1 << c)) -> x >> (bitwidth - c) 690349cc55cSDimitry Andric bool matchUMulHToLShr(MachineInstr &MI); 691349cc55cSDimitry Andric void applyUMulHToLShr(MachineInstr &MI); 692349cc55cSDimitry Andric 6930b57cec5SDimitry Andric /// Try to transform \p MI by using all of the above 6940b57cec5SDimitry Andric /// combine functions. Returns true if changed. 6950b57cec5SDimitry Andric bool tryCombine(MachineInstr &MI); 6968bcb0991SDimitry Andric 697fe6060f1SDimitry Andric /// Emit loads and stores that perform the given memcpy. 698fe6060f1SDimitry Andric /// Assumes \p MI is a G_MEMCPY_INLINE 699fe6060f1SDimitry Andric /// TODO: implement dynamically sized inline memcpy, 700fe6060f1SDimitry Andric /// and rename: s/bool tryEmit/void emit/ 701fe6060f1SDimitry Andric bool tryEmitMemcpyInline(MachineInstr &MI); 702fe6060f1SDimitry Andric 703349cc55cSDimitry Andric /// Match: 704349cc55cSDimitry Andric /// (G_UMULO x, 2) -> (G_UADDO x, x) 705349cc55cSDimitry Andric /// (G_SMULO x, 2) -> (G_SADDO x, x) 706349cc55cSDimitry Andric bool matchMulOBy2(MachineInstr &MI, BuildFnTy &MatchInfo); 7078bcb0991SDimitry Andric 70881ad6265SDimitry Andric /// Match: 70981ad6265SDimitry Andric /// (G_*MULO x, 0) -> 0 + no carry out 71081ad6265SDimitry Andric bool matchMulOBy0(MachineInstr &MI, BuildFnTy &MatchInfo); 71181ad6265SDimitry Andric 71281ad6265SDimitry Andric /// Match: 713bdd1243dSDimitry Andric /// (G_*ADDE x, y, 0) -> (G_*ADDO x, y) 714bdd1243dSDimitry Andric /// (G_*SUBE x, y, 0) -> (G_*SUBO x, y) 715bdd1243dSDimitry Andric bool matchAddEToAddO(MachineInstr &MI, BuildFnTy &MatchInfo); 716bdd1243dSDimitry Andric 717349cc55cSDimitry Andric /// Transform (fadd x, fneg(y)) -> (fsub x, y) 718349cc55cSDimitry Andric /// (fadd fneg(x), y) -> (fsub y, x) 719349cc55cSDimitry Andric /// (fsub x, fneg(y)) -> (fadd x, y) 720349cc55cSDimitry Andric /// (fmul fneg(x), fneg(y)) -> (fmul x, y) 721349cc55cSDimitry Andric /// (fdiv fneg(x), fneg(y)) -> (fdiv x, y) 722349cc55cSDimitry Andric /// (fmad fneg(x), fneg(y), z) -> (fmad x, y, z) 723349cc55cSDimitry Andric /// (fma fneg(x), fneg(y), z) -> (fma x, y, z) 724349cc55cSDimitry Andric bool matchRedundantNegOperands(MachineInstr &MI, BuildFnTy &MatchInfo); 725349cc55cSDimitry Andric 726bdd1243dSDimitry Andric bool matchFsubToFneg(MachineInstr &MI, Register &MatchInfo); 727bdd1243dSDimitry Andric void applyFsubToFneg(MachineInstr &MI, Register &MatchInfo); 728bdd1243dSDimitry Andric 7294824e7fdSDimitry Andric bool canCombineFMadOrFMA(MachineInstr &MI, bool &AllowFusionGlobally, 7304824e7fdSDimitry Andric bool &HasFMAD, bool &Aggressive, 7314824e7fdSDimitry Andric bool CanReassociate = false); 7324824e7fdSDimitry Andric 7334824e7fdSDimitry Andric /// Transform (fadd (fmul x, y), z) -> (fma x, y, z) 7344824e7fdSDimitry Andric /// (fadd (fmul x, y), z) -> (fmad x, y, z) 7354824e7fdSDimitry Andric bool matchCombineFAddFMulToFMadOrFMA(MachineInstr &MI, BuildFnTy &MatchInfo); 7364824e7fdSDimitry Andric 7374824e7fdSDimitry Andric /// Transform (fadd (fpext (fmul x, y)), z) -> (fma (fpext x), (fpext y), z) 7384824e7fdSDimitry Andric /// (fadd (fpext (fmul x, y)), z) -> (fmad (fpext x), (fpext y), z) 7394824e7fdSDimitry Andric bool matchCombineFAddFpExtFMulToFMadOrFMA(MachineInstr &MI, 7404824e7fdSDimitry Andric BuildFnTy &MatchInfo); 7414824e7fdSDimitry Andric 7424824e7fdSDimitry Andric /// Transform (fadd (fma x, y, (fmul u, v)), z) -> (fma x, y, (fma u, v, z)) 7434824e7fdSDimitry Andric /// (fadd (fmad x, y, (fmul u, v)), z) -> (fmad x, y, (fmad u, v, z)) 7444824e7fdSDimitry Andric bool matchCombineFAddFMAFMulToFMadOrFMA(MachineInstr &MI, 7454824e7fdSDimitry Andric BuildFnTy &MatchInfo); 7464824e7fdSDimitry Andric 7474824e7fdSDimitry Andric // Transform (fadd (fma x, y, (fpext (fmul u, v))), z) 7484824e7fdSDimitry Andric // -> (fma x, y, (fma (fpext u), (fpext v), z)) 7494824e7fdSDimitry Andric // (fadd (fmad x, y, (fpext (fmul u, v))), z) 7504824e7fdSDimitry Andric // -> (fmad x, y, (fmad (fpext u), (fpext v), z)) 7514824e7fdSDimitry Andric bool matchCombineFAddFpExtFMulToFMadOrFMAAggressive(MachineInstr &MI, 7524824e7fdSDimitry Andric BuildFnTy &MatchInfo); 7534824e7fdSDimitry Andric 7544824e7fdSDimitry Andric /// Transform (fsub (fmul x, y), z) -> (fma x, y, -z) 7554824e7fdSDimitry Andric /// (fsub (fmul x, y), z) -> (fmad x, y, -z) 7564824e7fdSDimitry Andric bool matchCombineFSubFMulToFMadOrFMA(MachineInstr &MI, BuildFnTy &MatchInfo); 7574824e7fdSDimitry Andric 7584824e7fdSDimitry Andric /// Transform (fsub (fneg (fmul, x, y)), z) -> (fma (fneg x), y, (fneg z)) 7594824e7fdSDimitry Andric /// (fsub (fneg (fmul, x, y)), z) -> (fmad (fneg x), y, (fneg z)) 7604824e7fdSDimitry Andric bool matchCombineFSubFNegFMulToFMadOrFMA(MachineInstr &MI, 7614824e7fdSDimitry Andric BuildFnTy &MatchInfo); 7624824e7fdSDimitry Andric 7634824e7fdSDimitry Andric /// Transform (fsub (fpext (fmul x, y)), z) 7644824e7fdSDimitry Andric /// -> (fma (fpext x), (fpext y), (fneg z)) 7654824e7fdSDimitry Andric /// (fsub (fpext (fmul x, y)), z) 7664824e7fdSDimitry Andric /// -> (fmad (fpext x), (fpext y), (fneg z)) 7674824e7fdSDimitry Andric bool matchCombineFSubFpExtFMulToFMadOrFMA(MachineInstr &MI, 7684824e7fdSDimitry Andric BuildFnTy &MatchInfo); 7694824e7fdSDimitry Andric 7704824e7fdSDimitry Andric /// Transform (fsub (fpext (fneg (fmul x, y))), z) 7714824e7fdSDimitry Andric /// -> (fneg (fma (fpext x), (fpext y), z)) 7724824e7fdSDimitry Andric /// (fsub (fpext (fneg (fmul x, y))), z) 7734824e7fdSDimitry Andric /// -> (fneg (fmad (fpext x), (fpext y), z)) 7744824e7fdSDimitry Andric bool matchCombineFSubFpExtFNegFMulToFMadOrFMA(MachineInstr &MI, 7754824e7fdSDimitry Andric BuildFnTy &MatchInfo); 7764824e7fdSDimitry Andric 77781ad6265SDimitry Andric bool matchCombineFMinMaxNaN(MachineInstr &MI, unsigned &Info); 77881ad6265SDimitry Andric 77981ad6265SDimitry Andric /// Transform G_ADD(x, G_SUB(y, x)) to y. 78081ad6265SDimitry Andric /// Transform G_ADD(G_SUB(y, x), x) to y. 78181ad6265SDimitry Andric bool matchAddSubSameReg(MachineInstr &MI, Register &Src); 78281ad6265SDimitry Andric 783bdd1243dSDimitry Andric bool matchBuildVectorIdentityFold(MachineInstr &MI, Register &MatchInfo); 784bdd1243dSDimitry Andric bool matchTruncBuildVectorFold(MachineInstr &MI, Register &MatchInfo); 785bdd1243dSDimitry Andric bool matchTruncLshrBuildVectorFold(MachineInstr &MI, Register &MatchInfo); 786bdd1243dSDimitry Andric 787bdd1243dSDimitry Andric /// Transform: 788bdd1243dSDimitry Andric /// (x + y) - y -> x 789bdd1243dSDimitry Andric /// (x + y) - x -> y 790bdd1243dSDimitry Andric /// x - (y + x) -> 0 - y 791bdd1243dSDimitry Andric /// x - (x + z) -> 0 - z 792bdd1243dSDimitry Andric bool matchSubAddSameReg(MachineInstr &MI, BuildFnTy &MatchInfo); 793bdd1243dSDimitry Andric 794bdd1243dSDimitry Andric /// \returns true if it is possible to simplify a select instruction \p MI 795bdd1243dSDimitry Andric /// to a min/max instruction of some sort. 796bdd1243dSDimitry Andric bool matchSimplifySelectToMinMax(MachineInstr &MI, BuildFnTy &MatchInfo); 797bdd1243dSDimitry Andric 798bdd1243dSDimitry Andric /// Transform: 799bdd1243dSDimitry Andric /// (X + Y) == X -> Y == 0 800bdd1243dSDimitry Andric /// (X - Y) == X -> Y == 0 801bdd1243dSDimitry Andric /// (X ^ Y) == X -> Y == 0 802bdd1243dSDimitry Andric /// (X + Y) != X -> Y != 0 803bdd1243dSDimitry Andric /// (X - Y) != X -> Y != 0 804bdd1243dSDimitry Andric /// (X ^ Y) != X -> Y != 0 805bdd1243dSDimitry Andric bool matchRedundantBinOpInEquality(MachineInstr &MI, BuildFnTy &MatchInfo); 806bdd1243dSDimitry Andric 80706c3fb27SDimitry Andric /// Match shifts greater or equal to the bitwidth of the operation. 80806c3fb27SDimitry Andric bool matchShiftsTooBig(MachineInstr &MI); 80906c3fb27SDimitry Andric 8105f757f3fSDimitry Andric /// Match constant LHS ops that should be commuted. 8115f757f3fSDimitry Andric bool matchCommuteConstantToRHS(MachineInstr &MI); 8125f757f3fSDimitry Andric 813*0fca6ea1SDimitry Andric /// Combine sext of trunc. 814*0fca6ea1SDimitry Andric bool matchSextOfTrunc(const MachineOperand &MO, BuildFnTy &MatchInfo); 815*0fca6ea1SDimitry Andric 816*0fca6ea1SDimitry Andric /// Combine zext of trunc. 817*0fca6ea1SDimitry Andric bool matchZextOfTrunc(const MachineOperand &MO, BuildFnTy &MatchInfo); 818*0fca6ea1SDimitry Andric 819*0fca6ea1SDimitry Andric /// Combine zext nneg to sext. 820*0fca6ea1SDimitry Andric bool matchNonNegZext(const MachineOperand &MO, BuildFnTy &MatchInfo); 821*0fca6ea1SDimitry Andric 8225f757f3fSDimitry Andric /// Match constant LHS FP ops that should be commuted. 8235f757f3fSDimitry Andric bool matchCommuteFPConstantToRHS(MachineInstr &MI); 8245f757f3fSDimitry Andric 8255f757f3fSDimitry Andric // Given a binop \p MI, commute operands 1 and 2. 8265f757f3fSDimitry Andric void applyCommuteBinOpOperands(MachineInstr &MI); 8275f757f3fSDimitry Andric 828*0fca6ea1SDimitry Andric /// Combine select to integer min/max. 829*0fca6ea1SDimitry Andric bool matchSelectIMinMax(const MachineOperand &MO, BuildFnTy &MatchInfo); 830*0fca6ea1SDimitry Andric 831647cbc5dSDimitry Andric /// Combine selects. 832647cbc5dSDimitry Andric bool matchSelect(MachineInstr &MI, BuildFnTy &MatchInfo); 833647cbc5dSDimitry Andric 834*0fca6ea1SDimitry Andric /// Combine ands. 835*0fca6ea1SDimitry Andric bool matchAnd(MachineInstr &MI, BuildFnTy &MatchInfo); 836*0fca6ea1SDimitry Andric 837*0fca6ea1SDimitry Andric /// Combine ors. 838*0fca6ea1SDimitry Andric bool matchOr(MachineInstr &MI, BuildFnTy &MatchInfo); 839*0fca6ea1SDimitry Andric 840*0fca6ea1SDimitry Andric /// Combine addos. 841*0fca6ea1SDimitry Andric bool matchAddOverflow(MachineInstr &MI, BuildFnTy &MatchInfo); 842*0fca6ea1SDimitry Andric 843*0fca6ea1SDimitry Andric /// Combine extract vector element. 844*0fca6ea1SDimitry Andric bool matchExtractVectorElement(MachineInstr &MI, BuildFnTy &MatchInfo); 845*0fca6ea1SDimitry Andric 846*0fca6ea1SDimitry Andric /// Combine extract vector element with a build vector on the vector register. 847*0fca6ea1SDimitry Andric bool matchExtractVectorElementWithBuildVector(const MachineOperand &MO, 848*0fca6ea1SDimitry Andric BuildFnTy &MatchInfo); 849*0fca6ea1SDimitry Andric 850*0fca6ea1SDimitry Andric /// Combine extract vector element with a build vector trunc on the vector 851*0fca6ea1SDimitry Andric /// register. 852*0fca6ea1SDimitry Andric bool matchExtractVectorElementWithBuildVectorTrunc(const MachineOperand &MO, 853*0fca6ea1SDimitry Andric BuildFnTy &MatchInfo); 854*0fca6ea1SDimitry Andric 855*0fca6ea1SDimitry Andric /// Combine extract vector element with a shuffle vector on the vector 856*0fca6ea1SDimitry Andric /// register. 857*0fca6ea1SDimitry Andric bool matchExtractVectorElementWithShuffleVector(const MachineOperand &MO, 858*0fca6ea1SDimitry Andric BuildFnTy &MatchInfo); 859*0fca6ea1SDimitry Andric 860*0fca6ea1SDimitry Andric /// Combine extract vector element with a insert vector element on the vector 861*0fca6ea1SDimitry Andric /// register and different indices. 862*0fca6ea1SDimitry Andric bool matchExtractVectorElementWithDifferentIndices(const MachineOperand &MO, 863*0fca6ea1SDimitry Andric BuildFnTy &MatchInfo); 864*0fca6ea1SDimitry Andric /// Use a function which takes in a MachineIRBuilder to perform a combine. 865*0fca6ea1SDimitry Andric /// By default, it erases the instruction def'd on \p MO from the function. 866*0fca6ea1SDimitry Andric void applyBuildFnMO(const MachineOperand &MO, BuildFnTy &MatchInfo); 867*0fca6ea1SDimitry Andric 868*0fca6ea1SDimitry Andric /// Match FPOWI if it's safe to extend it into a series of multiplications. 869*0fca6ea1SDimitry Andric bool matchFPowIExpansion(MachineInstr &MI, int64_t Exponent); 870*0fca6ea1SDimitry Andric 871*0fca6ea1SDimitry Andric /// Expands FPOWI into a series of multiplications and a division if the 872*0fca6ea1SDimitry Andric /// exponent is negative. 873*0fca6ea1SDimitry Andric void applyExpandFPowI(MachineInstr &MI, int64_t Exponent); 874*0fca6ea1SDimitry Andric 875*0fca6ea1SDimitry Andric /// Combine insert vector element OOB. 876*0fca6ea1SDimitry Andric bool matchInsertVectorElementOOB(MachineInstr &MI, BuildFnTy &MatchInfo); 877*0fca6ea1SDimitry Andric 878*0fca6ea1SDimitry Andric bool matchFreezeOfSingleMaybePoisonOperand(MachineInstr &MI, 879*0fca6ea1SDimitry Andric BuildFnTy &MatchInfo); 880*0fca6ea1SDimitry Andric 881*0fca6ea1SDimitry Andric bool matchAddOfVScale(const MachineOperand &MO, BuildFnTy &MatchInfo); 882*0fca6ea1SDimitry Andric 883*0fca6ea1SDimitry Andric bool matchMulOfVScale(const MachineOperand &MO, BuildFnTy &MatchInfo); 884*0fca6ea1SDimitry Andric 885*0fca6ea1SDimitry Andric bool matchSubOfVScale(const MachineOperand &MO, BuildFnTy &MatchInfo); 886*0fca6ea1SDimitry Andric 887*0fca6ea1SDimitry Andric bool matchShlOfVScale(const MachineOperand &MO, BuildFnTy &MatchInfo); 888*0fca6ea1SDimitry Andric 889349cc55cSDimitry Andric private: 8905f757f3fSDimitry Andric /// Checks for legality of an indexed variant of \p LdSt. 8915f757f3fSDimitry Andric bool isIndexedLoadStoreLegal(GLoadStore &LdSt) const; 8928bcb0991SDimitry Andric /// Given a non-indexed load or store instruction \p MI, find an offset that 8938bcb0991SDimitry Andric /// can be usefully and legally folded into it as a post-indexing operation. 8948bcb0991SDimitry Andric /// 8958bcb0991SDimitry Andric /// \returns true if a candidate is found. 8965f757f3fSDimitry Andric bool findPostIndexCandidate(GLoadStore &MI, Register &Addr, Register &Base, 8975f757f3fSDimitry Andric Register &Offset, bool &RematOffset); 8988bcb0991SDimitry Andric 8998bcb0991SDimitry Andric /// Given a non-indexed load or store instruction \p MI, find an offset that 9008bcb0991SDimitry Andric /// can be usefully and legally folded into it as a pre-indexing operation. 9018bcb0991SDimitry Andric /// 9028bcb0991SDimitry Andric /// \returns true if a candidate is found. 9035f757f3fSDimitry Andric bool findPreIndexCandidate(GLoadStore &MI, Register &Addr, Register &Base, 9048bcb0991SDimitry Andric Register &Offset); 905e8d8bef9SDimitry Andric 906e8d8bef9SDimitry Andric /// Helper function for matchLoadOrCombine. Searches for Registers 907e8d8bef9SDimitry Andric /// which may have been produced by a load instruction + some arithmetic. 908e8d8bef9SDimitry Andric /// 909e8d8bef9SDimitry Andric /// \param [in] Root - The search root. 910e8d8bef9SDimitry Andric /// 911e8d8bef9SDimitry Andric /// \returns The Registers found during the search. 912bdd1243dSDimitry Andric std::optional<SmallVector<Register, 8>> 913e8d8bef9SDimitry Andric findCandidatesForLoadOrCombine(const MachineInstr *Root) const; 914e8d8bef9SDimitry Andric 915e8d8bef9SDimitry Andric /// Helper function for matchLoadOrCombine. 916e8d8bef9SDimitry Andric /// 917e8d8bef9SDimitry Andric /// Checks if every register in \p RegsToVisit is defined by a load 918e8d8bef9SDimitry Andric /// instruction + some arithmetic. 919e8d8bef9SDimitry Andric /// 920e8d8bef9SDimitry Andric /// \param [out] MemOffset2Idx - Maps the byte positions each load ends up 921e8d8bef9SDimitry Andric /// at to the index of the load. 922e8d8bef9SDimitry Andric /// \param [in] MemSizeInBits - The number of bits each load should produce. 923e8d8bef9SDimitry Andric /// 924fe6060f1SDimitry Andric /// \returns On success, a 3-tuple containing lowest-index load found, the 925fe6060f1SDimitry Andric /// lowest index, and the last load in the sequence. 926bdd1243dSDimitry Andric std::optional<std::tuple<GZExtLoad *, int64_t, GZExtLoad *>> 927fe6060f1SDimitry Andric findLoadOffsetsForLoadOrCombine( 928e8d8bef9SDimitry Andric SmallDenseMap<int64_t, int64_t, 8> &MemOffset2Idx, 929e8d8bef9SDimitry Andric const SmallVector<Register, 8> &RegsToVisit, 930e8d8bef9SDimitry Andric const unsigned MemSizeInBits); 931fe6060f1SDimitry Andric 932fe6060f1SDimitry Andric /// Examines the G_PTR_ADD instruction \p PtrAdd and determines if performing 933fe6060f1SDimitry Andric /// a re-association of its operands would break an existing legal addressing 934fe6060f1SDimitry Andric /// mode that the address computation currently represents. 935fe6060f1SDimitry Andric bool reassociationCanBreakAddressingModePattern(MachineInstr &PtrAdd); 936bdd1243dSDimitry Andric 937bdd1243dSDimitry Andric /// Behavior when a floating point min/max is given one NaN and one 938bdd1243dSDimitry Andric /// non-NaN as input. 939bdd1243dSDimitry Andric enum class SelectPatternNaNBehaviour { 940bdd1243dSDimitry Andric NOT_APPLICABLE = 0, /// NaN behavior not applicable. 941bdd1243dSDimitry Andric RETURNS_NAN, /// Given one NaN input, returns the NaN. 942bdd1243dSDimitry Andric RETURNS_OTHER, /// Given one NaN input, returns the non-NaN. 943bdd1243dSDimitry Andric RETURNS_ANY /// Given one NaN input, can return either (or both operands are 944bdd1243dSDimitry Andric /// known non-NaN.) 945bdd1243dSDimitry Andric }; 946bdd1243dSDimitry Andric 947bdd1243dSDimitry Andric /// \returns which of \p LHS and \p RHS would be the result of a non-equality 948bdd1243dSDimitry Andric /// floating point comparison where one of \p LHS and \p RHS may be NaN. 949bdd1243dSDimitry Andric /// 950bdd1243dSDimitry Andric /// If both \p LHS and \p RHS may be NaN, returns 951bdd1243dSDimitry Andric /// SelectPatternNaNBehaviour::NOT_APPLICABLE. 952bdd1243dSDimitry Andric SelectPatternNaNBehaviour 953bdd1243dSDimitry Andric computeRetValAgainstNaN(Register LHS, Register RHS, 954bdd1243dSDimitry Andric bool IsOrderedComparison) const; 955bdd1243dSDimitry Andric 956bdd1243dSDimitry Andric /// Determines the floating point min/max opcode which should be used for 957bdd1243dSDimitry Andric /// a G_SELECT fed by a G_FCMP with predicate \p Pred. 958bdd1243dSDimitry Andric /// 959bdd1243dSDimitry Andric /// \returns 0 if this G_SELECT should not be combined to a floating point 960bdd1243dSDimitry Andric /// min or max. If it should be combined, returns one of 961bdd1243dSDimitry Andric /// 962bdd1243dSDimitry Andric /// * G_FMAXNUM 963bdd1243dSDimitry Andric /// * G_FMAXIMUM 964bdd1243dSDimitry Andric /// * G_FMINNUM 965bdd1243dSDimitry Andric /// * G_FMINIMUM 966bdd1243dSDimitry Andric /// 967bdd1243dSDimitry Andric /// Helper function for matchFPSelectToMinMax. 968bdd1243dSDimitry Andric unsigned getFPMinMaxOpcForSelect(CmpInst::Predicate Pred, LLT DstTy, 969bdd1243dSDimitry Andric SelectPatternNaNBehaviour VsNaNRetVal) const; 970bdd1243dSDimitry Andric 971bdd1243dSDimitry Andric /// Handle floating point cases for matchSimplifySelectToMinMax. 972bdd1243dSDimitry Andric /// 973bdd1243dSDimitry Andric /// E.g. 974bdd1243dSDimitry Andric /// 975bdd1243dSDimitry Andric /// select (fcmp uge x, 1.0) x, 1.0 -> fmax x, 1.0 976bdd1243dSDimitry Andric /// select (fcmp uge x, 1.0) 1.0, x -> fminnm x, 1.0 977bdd1243dSDimitry Andric bool matchFPSelectToMinMax(Register Dst, Register Cond, Register TrueVal, 978bdd1243dSDimitry Andric Register FalseVal, BuildFnTy &MatchInfo); 979647cbc5dSDimitry Andric 980647cbc5dSDimitry Andric /// Try to fold selects to logical operations. 981647cbc5dSDimitry Andric bool tryFoldBoolSelectToLogic(GSelect *Select, BuildFnTy &MatchInfo); 982647cbc5dSDimitry Andric 983647cbc5dSDimitry Andric bool tryFoldSelectOfConstants(GSelect *Select, BuildFnTy &MatchInfo); 984647cbc5dSDimitry Andric 985647cbc5dSDimitry Andric bool isOneOrOneSplat(Register Src, bool AllowUndefs); 986647cbc5dSDimitry Andric bool isZeroOrZeroSplat(Register Src, bool AllowUndefs); 987647cbc5dSDimitry Andric bool isConstantSplatVector(Register Src, int64_t SplatValue, 988647cbc5dSDimitry Andric bool AllowUndefs); 989*0fca6ea1SDimitry Andric bool isConstantOrConstantVectorI(Register Src) const; 990647cbc5dSDimitry Andric 991647cbc5dSDimitry Andric std::optional<APInt> getConstantOrConstantSplatVector(Register Src); 992*0fca6ea1SDimitry Andric 993*0fca6ea1SDimitry Andric /// Fold (icmp Pred1 V1, C1) && (icmp Pred2 V2, C2) 994*0fca6ea1SDimitry Andric /// or (icmp Pred1 V1, C1) || (icmp Pred2 V2, C2) 995*0fca6ea1SDimitry Andric /// into a single comparison using range-based reasoning. 996*0fca6ea1SDimitry Andric bool tryFoldAndOrOrICmpsUsingRanges(GLogicalBinOp *Logic, 997*0fca6ea1SDimitry Andric BuildFnTy &MatchInfo); 998*0fca6ea1SDimitry Andric 999*0fca6ea1SDimitry Andric // Simplify (cmp cc0 x, y) (&& or ||) (cmp cc1 x, y) -> cmp cc2 x, y. 1000*0fca6ea1SDimitry Andric bool tryFoldLogicOfFCmps(GLogicalBinOp *Logic, BuildFnTy &MatchInfo); 10010b57cec5SDimitry Andric }; 10020b57cec5SDimitry Andric } // namespace llvm 10030b57cec5SDimitry Andric 10040b57cec5SDimitry Andric #endif 1005