xref: /freebsd-src/contrib/llvm-project/llvm/include/llvm/CodeGen/GlobalISel/CombinerHelper.h (revision 0fca6ea1d4eea4c934cfff25ac9ee8ad6fe95583)
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