xref: /freebsd/contrib/llvm-project/llvm/lib/Target/AArch64/GISel/AArch64InstructionSelector.cpp (revision 0fca6ea1d4eea4c934cfff25ac9ee8ad6fe95583)
15ffd83dbSDimitry Andric //===- AArch64InstructionSelector.cpp ----------------------------*- C++ -*-==//
25ffd83dbSDimitry Andric //
35ffd83dbSDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
45ffd83dbSDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
55ffd83dbSDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
65ffd83dbSDimitry Andric //
75ffd83dbSDimitry Andric //===----------------------------------------------------------------------===//
85ffd83dbSDimitry Andric /// \file
95ffd83dbSDimitry Andric /// This file implements the targeting of the InstructionSelector class for
105ffd83dbSDimitry Andric /// AArch64.
115ffd83dbSDimitry Andric /// \todo This should be generated by TableGen.
125ffd83dbSDimitry Andric //===----------------------------------------------------------------------===//
135ffd83dbSDimitry Andric 
14fe6060f1SDimitry Andric #include "AArch64GlobalISelUtils.h"
155ffd83dbSDimitry Andric #include "AArch64InstrInfo.h"
165ffd83dbSDimitry Andric #include "AArch64MachineFunctionInfo.h"
175ffd83dbSDimitry Andric #include "AArch64RegisterBankInfo.h"
185ffd83dbSDimitry Andric #include "AArch64RegisterInfo.h"
195ffd83dbSDimitry Andric #include "AArch64Subtarget.h"
205ffd83dbSDimitry Andric #include "AArch64TargetMachine.h"
215ffd83dbSDimitry Andric #include "MCTargetDesc/AArch64AddressingModes.h"
22e8d8bef9SDimitry Andric #include "MCTargetDesc/AArch64MCTargetDesc.h"
2381ad6265SDimitry Andric #include "llvm/BinaryFormat/Dwarf.h"
2406c3fb27SDimitry Andric #include "llvm/CodeGen/GlobalISel/GIMatchTableExecutorImpl.h"
25349cc55cSDimitry Andric #include "llvm/CodeGen/GlobalISel/GenericMachineInstrs.h"
265ffd83dbSDimitry Andric #include "llvm/CodeGen/GlobalISel/InstructionSelector.h"
275ffd83dbSDimitry Andric #include "llvm/CodeGen/GlobalISel/MIPatternMatch.h"
2881ad6265SDimitry Andric #include "llvm/CodeGen/GlobalISel/MachineIRBuilder.h"
2981ad6265SDimitry Andric #include "llvm/CodeGen/GlobalISel/Utils.h"
305ffd83dbSDimitry Andric #include "llvm/CodeGen/MachineBasicBlock.h"
315ffd83dbSDimitry Andric #include "llvm/CodeGen/MachineConstantPool.h"
3281ad6265SDimitry Andric #include "llvm/CodeGen/MachineFrameInfo.h"
335ffd83dbSDimitry Andric #include "llvm/CodeGen/MachineFunction.h"
345ffd83dbSDimitry Andric #include "llvm/CodeGen/MachineInstr.h"
355ffd83dbSDimitry Andric #include "llvm/CodeGen/MachineInstrBuilder.h"
36fe6060f1SDimitry Andric #include "llvm/CodeGen/MachineMemOperand.h"
375ffd83dbSDimitry Andric #include "llvm/CodeGen/MachineOperand.h"
385ffd83dbSDimitry Andric #include "llvm/CodeGen/MachineRegisterInfo.h"
395ffd83dbSDimitry Andric #include "llvm/CodeGen/TargetOpcodes.h"
405f757f3fSDimitry Andric #include "llvm/CodeGen/TargetRegisterInfo.h"
415ffd83dbSDimitry Andric #include "llvm/IR/Constants.h"
42fe6060f1SDimitry Andric #include "llvm/IR/DerivedTypes.h"
43e8d8bef9SDimitry Andric #include "llvm/IR/Instructions.h"
4481ad6265SDimitry Andric #include "llvm/IR/IntrinsicsAArch64.h"
45e8d8bef9SDimitry Andric #include "llvm/IR/PatternMatch.h"
465ffd83dbSDimitry Andric #include "llvm/IR/Type.h"
47e8d8bef9SDimitry Andric #include "llvm/Pass.h"
485ffd83dbSDimitry Andric #include "llvm/Support/Debug.h"
495ffd83dbSDimitry Andric #include "llvm/Support/raw_ostream.h"
50bdd1243dSDimitry Andric #include <optional>
515ffd83dbSDimitry Andric 
525ffd83dbSDimitry Andric #define DEBUG_TYPE "aarch64-isel"
535ffd83dbSDimitry Andric 
545ffd83dbSDimitry Andric using namespace llvm;
55e8d8bef9SDimitry Andric using namespace MIPatternMatch;
56fe6060f1SDimitry Andric using namespace AArch64GISelUtils;
57fe6060f1SDimitry Andric 
58fe6060f1SDimitry Andric namespace llvm {
59fe6060f1SDimitry Andric class BlockFrequencyInfo;
60fe6060f1SDimitry Andric class ProfileSummaryInfo;
61fe6060f1SDimitry Andric }
625ffd83dbSDimitry Andric 
635ffd83dbSDimitry Andric namespace {
645ffd83dbSDimitry Andric 
655ffd83dbSDimitry Andric #define GET_GLOBALISEL_PREDICATE_BITSET
665ffd83dbSDimitry Andric #include "AArch64GenGlobalISel.inc"
675ffd83dbSDimitry Andric #undef GET_GLOBALISEL_PREDICATE_BITSET
685ffd83dbSDimitry Andric 
6981ad6265SDimitry Andric 
705ffd83dbSDimitry Andric class AArch64InstructionSelector : public InstructionSelector {
715ffd83dbSDimitry Andric public:
725ffd83dbSDimitry Andric   AArch64InstructionSelector(const AArch64TargetMachine &TM,
735ffd83dbSDimitry Andric                              const AArch64Subtarget &STI,
745ffd83dbSDimitry Andric                              const AArch64RegisterBankInfo &RBI);
755ffd83dbSDimitry Andric 
765ffd83dbSDimitry Andric   bool select(MachineInstr &I) override;
getName()775ffd83dbSDimitry Andric   static const char *getName() { return DEBUG_TYPE; }
785ffd83dbSDimitry Andric 
setupMF(MachineFunction & MF,GISelKnownBits * KB,CodeGenCoverage * CoverageInfo,ProfileSummaryInfo * PSI,BlockFrequencyInfo * BFI)79fe6060f1SDimitry Andric   void setupMF(MachineFunction &MF, GISelKnownBits *KB,
8006c3fb27SDimitry Andric                CodeGenCoverage *CoverageInfo, ProfileSummaryInfo *PSI,
81fe6060f1SDimitry Andric                BlockFrequencyInfo *BFI) override {
82fe6060f1SDimitry Andric     InstructionSelector::setupMF(MF, KB, CoverageInfo, PSI, BFI);
83fe6060f1SDimitry Andric     MIB.setMF(MF);
845ffd83dbSDimitry Andric 
855ffd83dbSDimitry Andric     // hasFnAttribute() is expensive to call on every BRCOND selection, so
865ffd83dbSDimitry Andric     // cache it here for each run of the selector.
875ffd83dbSDimitry Andric     ProduceNonFlagSettingCondBr =
885ffd83dbSDimitry Andric         !MF.getFunction().hasFnAttribute(Attribute::SpeculativeLoadHardening);
895ffd83dbSDimitry Andric     MFReturnAddr = Register();
905ffd83dbSDimitry Andric 
915ffd83dbSDimitry Andric     processPHIs(MF);
925ffd83dbSDimitry Andric   }
935ffd83dbSDimitry Andric 
945ffd83dbSDimitry Andric private:
955ffd83dbSDimitry Andric   /// tblgen-erated 'select' implementation, used as the initial selector for
965ffd83dbSDimitry Andric   /// the patterns that don't require complex C++.
975ffd83dbSDimitry Andric   bool selectImpl(MachineInstr &I, CodeGenCoverage &CoverageInfo) const;
985ffd83dbSDimitry Andric 
995ffd83dbSDimitry Andric   // A lowering phase that runs before any selection attempts.
1005ffd83dbSDimitry Andric   // Returns true if the instruction was modified.
1015ffd83dbSDimitry Andric   bool preISelLower(MachineInstr &I);
1025ffd83dbSDimitry Andric 
1035ffd83dbSDimitry Andric   // An early selection function that runs before the selectImpl() call.
104fe6060f1SDimitry Andric   bool earlySelect(MachineInstr &I);
1055ffd83dbSDimitry Andric 
1065f757f3fSDimitry Andric   /// Save state that is shared between select calls, call select on \p I and
1075f757f3fSDimitry Andric   /// then restore the saved state. This can be used to recursively call select
1085f757f3fSDimitry Andric   /// within a select call.
1095f757f3fSDimitry Andric   bool selectAndRestoreState(MachineInstr &I);
1105f757f3fSDimitry Andric 
1115ffd83dbSDimitry Andric   // Do some preprocessing of G_PHIs before we begin selection.
1125ffd83dbSDimitry Andric   void processPHIs(MachineFunction &MF);
1135ffd83dbSDimitry Andric 
114fe6060f1SDimitry Andric   bool earlySelectSHL(MachineInstr &I, MachineRegisterInfo &MRI);
1155ffd83dbSDimitry Andric 
1165ffd83dbSDimitry Andric   /// Eliminate same-sized cross-bank copies into stores before selectImpl().
1175ffd83dbSDimitry Andric   bool contractCrossBankCopyIntoStore(MachineInstr &I,
1185ffd83dbSDimitry Andric                                       MachineRegisterInfo &MRI);
1195ffd83dbSDimitry Andric 
1205ffd83dbSDimitry Andric   bool convertPtrAddToAdd(MachineInstr &I, MachineRegisterInfo &MRI);
1215ffd83dbSDimitry Andric 
1225ffd83dbSDimitry Andric   bool selectVaStartAAPCS(MachineInstr &I, MachineFunction &MF,
1235ffd83dbSDimitry Andric                           MachineRegisterInfo &MRI) const;
1245ffd83dbSDimitry Andric   bool selectVaStartDarwin(MachineInstr &I, MachineFunction &MF,
1255ffd83dbSDimitry Andric                            MachineRegisterInfo &MRI) const;
1265ffd83dbSDimitry Andric 
127e8d8bef9SDimitry Andric   ///@{
128e8d8bef9SDimitry Andric   /// Helper functions for selectCompareBranch.
129e8d8bef9SDimitry Andric   bool selectCompareBranchFedByFCmp(MachineInstr &I, MachineInstr &FCmp,
130e8d8bef9SDimitry Andric                                     MachineIRBuilder &MIB) const;
131e8d8bef9SDimitry Andric   bool selectCompareBranchFedByICmp(MachineInstr &I, MachineInstr &ICmp,
132e8d8bef9SDimitry Andric                                     MachineIRBuilder &MIB) const;
133e8d8bef9SDimitry Andric   bool tryOptCompareBranchFedByICmp(MachineInstr &I, MachineInstr &ICmp,
134e8d8bef9SDimitry Andric                                     MachineIRBuilder &MIB) const;
135e8d8bef9SDimitry Andric   bool tryOptAndIntoCompareBranch(MachineInstr &AndInst, bool Invert,
1365ffd83dbSDimitry Andric                                   MachineBasicBlock *DstMBB,
1375ffd83dbSDimitry Andric                                   MachineIRBuilder &MIB) const;
138e8d8bef9SDimitry Andric   ///@}
139e8d8bef9SDimitry Andric 
1405ffd83dbSDimitry Andric   bool selectCompareBranch(MachineInstr &I, MachineFunction &MF,
141fe6060f1SDimitry Andric                            MachineRegisterInfo &MRI);
1425ffd83dbSDimitry Andric 
143fe6060f1SDimitry Andric   bool selectVectorAshrLshr(MachineInstr &I, MachineRegisterInfo &MRI);
144fe6060f1SDimitry Andric   bool selectVectorSHL(MachineInstr &I, MachineRegisterInfo &MRI);
1455ffd83dbSDimitry Andric 
1465ffd83dbSDimitry Andric   // Helper to generate an equivalent of scalar_to_vector into a new register,
1475ffd83dbSDimitry Andric   // returned via 'Dst'.
1485ffd83dbSDimitry Andric   MachineInstr *emitScalarToVector(unsigned EltSize,
1495ffd83dbSDimitry Andric                                    const TargetRegisterClass *DstRC,
1505ffd83dbSDimitry Andric                                    Register Scalar,
1515ffd83dbSDimitry Andric                                    MachineIRBuilder &MIRBuilder) const;
1525f757f3fSDimitry Andric   /// Helper to narrow vector that was widened by emitScalarToVector.
1535f757f3fSDimitry Andric   /// Copy lowest part of 128-bit or 64-bit vector to 64-bit or 32-bit
1545f757f3fSDimitry Andric   /// vector, correspondingly.
1555f757f3fSDimitry Andric   MachineInstr *emitNarrowVector(Register DstReg, Register SrcReg,
1565f757f3fSDimitry Andric                                  MachineIRBuilder &MIRBuilder,
1575f757f3fSDimitry Andric                                  MachineRegisterInfo &MRI) const;
1585ffd83dbSDimitry Andric 
159bdd1243dSDimitry Andric   /// Emit a lane insert into \p DstReg, or a new vector register if
160bdd1243dSDimitry Andric   /// std::nullopt is provided.
1615ffd83dbSDimitry Andric   ///
1625ffd83dbSDimitry Andric   /// The lane inserted into is defined by \p LaneIdx. The vector source
1635ffd83dbSDimitry Andric   /// register is given by \p SrcReg. The register containing the element is
1645ffd83dbSDimitry Andric   /// given by \p EltReg.
165bdd1243dSDimitry Andric   MachineInstr *emitLaneInsert(std::optional<Register> DstReg, Register SrcReg,
1665ffd83dbSDimitry Andric                                Register EltReg, unsigned LaneIdx,
1675ffd83dbSDimitry Andric                                const RegisterBank &RB,
1685ffd83dbSDimitry Andric                                MachineIRBuilder &MIRBuilder) const;
1695ffd83dbSDimitry Andric 
170fe6060f1SDimitry Andric   /// Emit a sequence of instructions representing a constant \p CV for a
171fe6060f1SDimitry Andric   /// vector register \p Dst. (E.g. a MOV, or a load from a constant pool.)
172fe6060f1SDimitry Andric   ///
173fe6060f1SDimitry Andric   /// \returns the last instruction in the sequence on success, and nullptr
174fe6060f1SDimitry Andric   /// otherwise.
175fe6060f1SDimitry Andric   MachineInstr *emitConstantVector(Register Dst, Constant *CV,
176fe6060f1SDimitry Andric                                    MachineIRBuilder &MIRBuilder,
177fe6060f1SDimitry Andric                                    MachineRegisterInfo &MRI);
178fe6060f1SDimitry Andric 
1795f757f3fSDimitry Andric   MachineInstr *tryAdvSIMDModImm8(Register Dst, unsigned DstSize, APInt Bits,
1805f757f3fSDimitry Andric                                   MachineIRBuilder &MIRBuilder);
1815f757f3fSDimitry Andric 
1825f757f3fSDimitry Andric   MachineInstr *tryAdvSIMDModImm16(Register Dst, unsigned DstSize, APInt Bits,
1835f757f3fSDimitry Andric                                    MachineIRBuilder &MIRBuilder, bool Inv);
1845f757f3fSDimitry Andric 
1855f757f3fSDimitry Andric   MachineInstr *tryAdvSIMDModImm32(Register Dst, unsigned DstSize, APInt Bits,
1865f757f3fSDimitry Andric                                    MachineIRBuilder &MIRBuilder, bool Inv);
1875f757f3fSDimitry Andric   MachineInstr *tryAdvSIMDModImm64(Register Dst, unsigned DstSize, APInt Bits,
1885f757f3fSDimitry Andric                                    MachineIRBuilder &MIRBuilder);
1895f757f3fSDimitry Andric   MachineInstr *tryAdvSIMDModImm321s(Register Dst, unsigned DstSize, APInt Bits,
1905f757f3fSDimitry Andric                                      MachineIRBuilder &MIRBuilder, bool Inv);
1915f757f3fSDimitry Andric   MachineInstr *tryAdvSIMDModImmFP(Register Dst, unsigned DstSize, APInt Bits,
1925f757f3fSDimitry Andric                                    MachineIRBuilder &MIRBuilder);
1935f757f3fSDimitry Andric 
194fe6060f1SDimitry Andric   bool tryOptConstantBuildVec(MachineInstr &MI, LLT DstTy,
195fe6060f1SDimitry Andric                               MachineRegisterInfo &MRI);
196349cc55cSDimitry Andric   /// \returns true if a G_BUILD_VECTOR instruction \p MI can be selected as a
197349cc55cSDimitry Andric   /// SUBREG_TO_REG.
198349cc55cSDimitry Andric   bool tryOptBuildVecToSubregToReg(MachineInstr &MI, MachineRegisterInfo &MRI);
199fe6060f1SDimitry Andric   bool selectBuildVector(MachineInstr &I, MachineRegisterInfo &MRI);
200fe6060f1SDimitry Andric   bool selectMergeValues(MachineInstr &I, MachineRegisterInfo &MRI);
201fe6060f1SDimitry Andric   bool selectUnmergeValues(MachineInstr &I, MachineRegisterInfo &MRI);
202fe6060f1SDimitry Andric 
203fe6060f1SDimitry Andric   bool selectShuffleVector(MachineInstr &I, MachineRegisterInfo &MRI);
204fe6060f1SDimitry Andric   bool selectExtractElt(MachineInstr &I, MachineRegisterInfo &MRI);
205fe6060f1SDimitry Andric   bool selectConcatVectors(MachineInstr &I, MachineRegisterInfo &MRI);
206fe6060f1SDimitry Andric   bool selectSplitVectorUnmerge(MachineInstr &I, MachineRegisterInfo &MRI);
207349cc55cSDimitry Andric 
208349cc55cSDimitry Andric   /// Helper function to select vector load intrinsics like
209349cc55cSDimitry Andric   /// @llvm.aarch64.neon.ld2.*, @llvm.aarch64.neon.ld4.*, etc.
210349cc55cSDimitry Andric   /// \p Opc is the opcode that the selected instruction should use.
211349cc55cSDimitry Andric   /// \p NumVecs is the number of vector destinations for the instruction.
212349cc55cSDimitry Andric   /// \p I is the original G_INTRINSIC_W_SIDE_EFFECTS instruction.
213349cc55cSDimitry Andric   bool selectVectorLoadIntrinsic(unsigned Opc, unsigned NumVecs,
214349cc55cSDimitry Andric                                  MachineInstr &I);
2155f757f3fSDimitry Andric   bool selectVectorLoadLaneIntrinsic(unsigned Opc, unsigned NumVecs,
2165f757f3fSDimitry Andric                                      MachineInstr &I);
2175f757f3fSDimitry Andric   void selectVectorStoreIntrinsic(MachineInstr &I, unsigned NumVecs,
2185f757f3fSDimitry Andric                                   unsigned Opc);
2195f757f3fSDimitry Andric   bool selectVectorStoreLaneIntrinsic(MachineInstr &I, unsigned NumVecs,
2205f757f3fSDimitry Andric                                       unsigned Opc);
2215ffd83dbSDimitry Andric   bool selectIntrinsicWithSideEffects(MachineInstr &I,
222fe6060f1SDimitry Andric                                       MachineRegisterInfo &MRI);
2235ffd83dbSDimitry Andric   bool selectIntrinsic(MachineInstr &I, MachineRegisterInfo &MRI);
224fe6060f1SDimitry Andric   bool selectJumpTable(MachineInstr &I, MachineRegisterInfo &MRI);
225fe6060f1SDimitry Andric   bool selectBrJT(MachineInstr &I, MachineRegisterInfo &MRI);
226fe6060f1SDimitry Andric   bool selectTLSGlobalValue(MachineInstr &I, MachineRegisterInfo &MRI);
227*0fca6ea1SDimitry Andric   bool selectPtrAuthGlobalValue(MachineInstr &I,
228*0fca6ea1SDimitry Andric                                 MachineRegisterInfo &MRI) const;
229fe6060f1SDimitry Andric   bool selectReduction(MachineInstr &I, MachineRegisterInfo &MRI);
2301fd87a68SDimitry Andric   bool selectMOPS(MachineInstr &I, MachineRegisterInfo &MRI);
231349cc55cSDimitry Andric   bool selectUSMovFromExtend(MachineInstr &I, MachineRegisterInfo &MRI);
232*0fca6ea1SDimitry Andric   void SelectTable(MachineInstr &I, MachineRegisterInfo &MRI, unsigned NumVecs,
233*0fca6ea1SDimitry Andric                    unsigned Opc1, unsigned Opc2, bool isExt);
2345ffd83dbSDimitry Andric 
2355f757f3fSDimitry Andric   bool selectIndexedExtLoad(MachineInstr &I, MachineRegisterInfo &MRI);
2365f757f3fSDimitry Andric   bool selectIndexedLoad(MachineInstr &I, MachineRegisterInfo &MRI);
2375f757f3fSDimitry Andric   bool selectIndexedStore(GIndexedStore &I, MachineRegisterInfo &MRI);
2385f757f3fSDimitry Andric 
2395ffd83dbSDimitry Andric   unsigned emitConstantPoolEntry(const Constant *CPVal,
2405ffd83dbSDimitry Andric                                  MachineFunction &MF) const;
2415ffd83dbSDimitry Andric   MachineInstr *emitLoadFromConstantPool(const Constant *CPVal,
2425ffd83dbSDimitry Andric                                          MachineIRBuilder &MIRBuilder) const;
2435ffd83dbSDimitry Andric 
2445ffd83dbSDimitry Andric   // Emit a vector concat operation.
245bdd1243dSDimitry Andric   MachineInstr *emitVectorConcat(std::optional<Register> Dst, Register Op1,
2465ffd83dbSDimitry Andric                                  Register Op2,
2475ffd83dbSDimitry Andric                                  MachineIRBuilder &MIRBuilder) const;
2485ffd83dbSDimitry Andric 
2495ffd83dbSDimitry Andric   // Emit an integer compare between LHS and RHS, which checks for Predicate.
250e8d8bef9SDimitry Andric   MachineInstr *emitIntegerCompare(MachineOperand &LHS, MachineOperand &RHS,
2515ffd83dbSDimitry Andric                                    MachineOperand &Predicate,
2525ffd83dbSDimitry Andric                                    MachineIRBuilder &MIRBuilder) const;
253e8d8bef9SDimitry Andric 
254e8d8bef9SDimitry Andric   /// Emit a floating point comparison between \p LHS and \p RHS.
255e8d8bef9SDimitry Andric   /// \p Pred if given is the intended predicate to use.
256bdd1243dSDimitry Andric   MachineInstr *
257bdd1243dSDimitry Andric   emitFPCompare(Register LHS, Register RHS, MachineIRBuilder &MIRBuilder,
258bdd1243dSDimitry Andric                 std::optional<CmpInst::Predicate> = std::nullopt) const;
259e8d8bef9SDimitry Andric 
260bdd1243dSDimitry Andric   MachineInstr *
261bdd1243dSDimitry Andric   emitInstr(unsigned Opcode, std::initializer_list<llvm::DstOp> DstOps,
262e8d8bef9SDimitry Andric             std::initializer_list<llvm::SrcOp> SrcOps,
263e8d8bef9SDimitry Andric             MachineIRBuilder &MIRBuilder,
264bdd1243dSDimitry Andric             const ComplexRendererFns &RenderFns = std::nullopt) const;
265e8d8bef9SDimitry Andric   /// Helper function to emit an add or sub instruction.
266e8d8bef9SDimitry Andric   ///
267e8d8bef9SDimitry Andric   /// \p AddrModeAndSizeToOpcode must contain each of the opcode variants above
268e8d8bef9SDimitry Andric   /// in a specific order.
269e8d8bef9SDimitry Andric   ///
270e8d8bef9SDimitry Andric   /// Below is an example of the expected input to \p AddrModeAndSizeToOpcode.
271e8d8bef9SDimitry Andric   ///
272e8d8bef9SDimitry Andric   /// \code
273e8d8bef9SDimitry Andric   ///   const std::array<std::array<unsigned, 2>, 4> Table {
274e8d8bef9SDimitry Andric   ///    {{AArch64::ADDXri, AArch64::ADDWri},
275e8d8bef9SDimitry Andric   ///     {AArch64::ADDXrs, AArch64::ADDWrs},
276e8d8bef9SDimitry Andric   ///     {AArch64::ADDXrr, AArch64::ADDWrr},
277e8d8bef9SDimitry Andric   ///     {AArch64::SUBXri, AArch64::SUBWri},
278e8d8bef9SDimitry Andric   ///     {AArch64::ADDXrx, AArch64::ADDWrx}}};
279e8d8bef9SDimitry Andric   /// \endcode
280e8d8bef9SDimitry Andric   ///
281e8d8bef9SDimitry Andric   /// Each row in the table corresponds to a different addressing mode. Each
282e8d8bef9SDimitry Andric   /// column corresponds to a different register size.
283e8d8bef9SDimitry Andric   ///
284e8d8bef9SDimitry Andric   /// \attention Rows must be structured as follows:
285e8d8bef9SDimitry Andric   ///   - Row 0: The ri opcode variants
286e8d8bef9SDimitry Andric   ///   - Row 1: The rs opcode variants
287e8d8bef9SDimitry Andric   ///   - Row 2: The rr opcode variants
288e8d8bef9SDimitry Andric   ///   - Row 3: The ri opcode variants for negative immediates
289e8d8bef9SDimitry Andric   ///   - Row 4: The rx opcode variants
290e8d8bef9SDimitry Andric   ///
291e8d8bef9SDimitry Andric   /// \attention Columns must be structured as follows:
292e8d8bef9SDimitry Andric   ///   - Column 0: The 64-bit opcode variants
293e8d8bef9SDimitry Andric   ///   - Column 1: The 32-bit opcode variants
294e8d8bef9SDimitry Andric   ///
295e8d8bef9SDimitry Andric   /// \p Dst is the destination register of the binop to emit.
296e8d8bef9SDimitry Andric   /// \p LHS is the left-hand operand of the binop to emit.
297e8d8bef9SDimitry Andric   /// \p RHS is the right-hand operand of the binop to emit.
298e8d8bef9SDimitry Andric   MachineInstr *emitAddSub(
299e8d8bef9SDimitry Andric       const std::array<std::array<unsigned, 2>, 5> &AddrModeAndSizeToOpcode,
300e8d8bef9SDimitry Andric       Register Dst, MachineOperand &LHS, MachineOperand &RHS,
301e8d8bef9SDimitry Andric       MachineIRBuilder &MIRBuilder) const;
302e8d8bef9SDimitry Andric   MachineInstr *emitADD(Register DefReg, MachineOperand &LHS,
303e8d8bef9SDimitry Andric                         MachineOperand &RHS,
304e8d8bef9SDimitry Andric                         MachineIRBuilder &MIRBuilder) const;
305e8d8bef9SDimitry Andric   MachineInstr *emitADDS(Register Dst, MachineOperand &LHS, MachineOperand &RHS,
306e8d8bef9SDimitry Andric                          MachineIRBuilder &MIRBuilder) const;
307e8d8bef9SDimitry Andric   MachineInstr *emitSUBS(Register Dst, MachineOperand &LHS, MachineOperand &RHS,
3085ffd83dbSDimitry Andric                          MachineIRBuilder &MIRBuilder) const;
30906c3fb27SDimitry Andric   MachineInstr *emitADCS(Register Dst, MachineOperand &LHS, MachineOperand &RHS,
31006c3fb27SDimitry Andric                          MachineIRBuilder &MIRBuilder) const;
31106c3fb27SDimitry Andric   MachineInstr *emitSBCS(Register Dst, MachineOperand &LHS, MachineOperand &RHS,
31206c3fb27SDimitry Andric                          MachineIRBuilder &MIRBuilder) const;
3135ffd83dbSDimitry Andric   MachineInstr *emitCMN(MachineOperand &LHS, MachineOperand &RHS,
3145ffd83dbSDimitry Andric                         MachineIRBuilder &MIRBuilder) const;
315e8d8bef9SDimitry Andric   MachineInstr *emitTST(MachineOperand &LHS, MachineOperand &RHS,
316e8d8bef9SDimitry Andric                         MachineIRBuilder &MIRBuilder) const;
317e8d8bef9SDimitry Andric   MachineInstr *emitSelect(Register Dst, Register LHS, Register RHS,
318e8d8bef9SDimitry Andric                            AArch64CC::CondCode CC,
3195ffd83dbSDimitry Andric                            MachineIRBuilder &MIRBuilder) const;
320bdd1243dSDimitry Andric   MachineInstr *emitExtractVectorElt(std::optional<Register> DstReg,
3215ffd83dbSDimitry Andric                                      const RegisterBank &DstRB, LLT ScalarTy,
3225ffd83dbSDimitry Andric                                      Register VecReg, unsigned LaneIdx,
3235ffd83dbSDimitry Andric                                      MachineIRBuilder &MIRBuilder) const;
324349cc55cSDimitry Andric   MachineInstr *emitCSINC(Register Dst, Register Src1, Register Src2,
325349cc55cSDimitry Andric                           AArch64CC::CondCode Pred,
326349cc55cSDimitry Andric                           MachineIRBuilder &MIRBuilder) const;
327e8d8bef9SDimitry Andric   /// Emit a CSet for a FP compare.
328e8d8bef9SDimitry Andric   ///
329e8d8bef9SDimitry Andric   /// \p Dst is expected to be a 32-bit scalar register.
330e8d8bef9SDimitry Andric   MachineInstr *emitCSetForFCmp(Register Dst, CmpInst::Predicate Pred,
331e8d8bef9SDimitry Andric                                 MachineIRBuilder &MIRBuilder) const;
332e8d8bef9SDimitry Andric 
33306c3fb27SDimitry Andric   /// Emit an instruction that sets NZCV to the carry-in expected by \p I.
33406c3fb27SDimitry Andric   /// Might elide the instruction if the previous instruction already sets NZCV
33506c3fb27SDimitry Andric   /// correctly.
33606c3fb27SDimitry Andric   MachineInstr *emitCarryIn(MachineInstr &I, Register CarryReg);
33706c3fb27SDimitry Andric 
338e8d8bef9SDimitry Andric   /// Emit the overflow op for \p Opcode.
339e8d8bef9SDimitry Andric   ///
340e8d8bef9SDimitry Andric   /// \p Opcode is expected to be an overflow op's opcode, e.g. G_UADDO,
341e8d8bef9SDimitry Andric   /// G_USUBO, etc.
342e8d8bef9SDimitry Andric   std::pair<MachineInstr *, AArch64CC::CondCode>
343e8d8bef9SDimitry Andric   emitOverflowOp(unsigned Opcode, Register Dst, MachineOperand &LHS,
344e8d8bef9SDimitry Andric                  MachineOperand &RHS, MachineIRBuilder &MIRBuilder) const;
3455ffd83dbSDimitry Andric 
34606c3fb27SDimitry Andric   bool selectOverflowOp(MachineInstr &I, MachineRegisterInfo &MRI);
34706c3fb27SDimitry Andric 
34881ad6265SDimitry Andric   /// Emit expression as a conjunction (a series of CCMP/CFCMP ops).
34981ad6265SDimitry Andric   /// In some cases this is even possible with OR operations in the expression.
35081ad6265SDimitry Andric   MachineInstr *emitConjunction(Register Val, AArch64CC::CondCode &OutCC,
35181ad6265SDimitry Andric                                 MachineIRBuilder &MIB) const;
35281ad6265SDimitry Andric   MachineInstr *emitConditionalComparison(Register LHS, Register RHS,
35381ad6265SDimitry Andric                                           CmpInst::Predicate CC,
35481ad6265SDimitry Andric                                           AArch64CC::CondCode Predicate,
35581ad6265SDimitry Andric                                           AArch64CC::CondCode OutCC,
35681ad6265SDimitry Andric                                           MachineIRBuilder &MIB) const;
35781ad6265SDimitry Andric   MachineInstr *emitConjunctionRec(Register Val, AArch64CC::CondCode &OutCC,
35881ad6265SDimitry Andric                                    bool Negate, Register CCOp,
35981ad6265SDimitry Andric                                    AArch64CC::CondCode Predicate,
36081ad6265SDimitry Andric                                    MachineIRBuilder &MIB) const;
36181ad6265SDimitry Andric 
3625ffd83dbSDimitry Andric   /// Emit a TB(N)Z instruction which tests \p Bit in \p TestReg.
3635ffd83dbSDimitry Andric   /// \p IsNegative is true if the test should be "not zero".
3645ffd83dbSDimitry Andric   /// This will also optimize the test bit instruction when possible.
3655ffd83dbSDimitry Andric   MachineInstr *emitTestBit(Register TestReg, uint64_t Bit, bool IsNegative,
3665ffd83dbSDimitry Andric                             MachineBasicBlock *DstMBB,
3675ffd83dbSDimitry Andric                             MachineIRBuilder &MIB) const;
3685ffd83dbSDimitry Andric 
369e8d8bef9SDimitry Andric   /// Emit a CB(N)Z instruction which branches to \p DestMBB.
370e8d8bef9SDimitry Andric   MachineInstr *emitCBZ(Register CompareReg, bool IsNegative,
371e8d8bef9SDimitry Andric                         MachineBasicBlock *DestMBB,
372e8d8bef9SDimitry Andric                         MachineIRBuilder &MIB) const;
373e8d8bef9SDimitry Andric 
3745ffd83dbSDimitry Andric   // Equivalent to the i32shift_a and friends from AArch64InstrInfo.td.
3755ffd83dbSDimitry Andric   // We use these manually instead of using the importer since it doesn't
3765ffd83dbSDimitry Andric   // support SDNodeXForm.
3775ffd83dbSDimitry Andric   ComplexRendererFns selectShiftA_32(const MachineOperand &Root) const;
3785ffd83dbSDimitry Andric   ComplexRendererFns selectShiftB_32(const MachineOperand &Root) const;
3795ffd83dbSDimitry Andric   ComplexRendererFns selectShiftA_64(const MachineOperand &Root) const;
3805ffd83dbSDimitry Andric   ComplexRendererFns selectShiftB_64(const MachineOperand &Root) const;
3815ffd83dbSDimitry Andric 
3825ffd83dbSDimitry Andric   ComplexRendererFns select12BitValueWithLeftShift(uint64_t Immed) const;
3835ffd83dbSDimitry Andric   ComplexRendererFns selectArithImmed(MachineOperand &Root) const;
3845ffd83dbSDimitry Andric   ComplexRendererFns selectNegArithImmed(MachineOperand &Root) const;
3855ffd83dbSDimitry Andric 
3865ffd83dbSDimitry Andric   ComplexRendererFns selectAddrModeUnscaled(MachineOperand &Root,
3875ffd83dbSDimitry Andric                                             unsigned Size) const;
3885ffd83dbSDimitry Andric 
selectAddrModeUnscaled8(MachineOperand & Root) const3895ffd83dbSDimitry Andric   ComplexRendererFns selectAddrModeUnscaled8(MachineOperand &Root) const {
3905ffd83dbSDimitry Andric     return selectAddrModeUnscaled(Root, 1);
3915ffd83dbSDimitry Andric   }
selectAddrModeUnscaled16(MachineOperand & Root) const3925ffd83dbSDimitry Andric   ComplexRendererFns selectAddrModeUnscaled16(MachineOperand &Root) const {
3935ffd83dbSDimitry Andric     return selectAddrModeUnscaled(Root, 2);
3945ffd83dbSDimitry Andric   }
selectAddrModeUnscaled32(MachineOperand & Root) const3955ffd83dbSDimitry Andric   ComplexRendererFns selectAddrModeUnscaled32(MachineOperand &Root) const {
3965ffd83dbSDimitry Andric     return selectAddrModeUnscaled(Root, 4);
3975ffd83dbSDimitry Andric   }
selectAddrModeUnscaled64(MachineOperand & Root) const3985ffd83dbSDimitry Andric   ComplexRendererFns selectAddrModeUnscaled64(MachineOperand &Root) const {
3995ffd83dbSDimitry Andric     return selectAddrModeUnscaled(Root, 8);
4005ffd83dbSDimitry Andric   }
selectAddrModeUnscaled128(MachineOperand & Root) const4015ffd83dbSDimitry Andric   ComplexRendererFns selectAddrModeUnscaled128(MachineOperand &Root) const {
4025ffd83dbSDimitry Andric     return selectAddrModeUnscaled(Root, 16);
4035ffd83dbSDimitry Andric   }
4045ffd83dbSDimitry Andric 
4055ffd83dbSDimitry Andric   /// Helper to try to fold in a GISEL_ADD_LOW into an immediate, to be used
4065ffd83dbSDimitry Andric   /// from complex pattern matchers like selectAddrModeIndexed().
4075ffd83dbSDimitry Andric   ComplexRendererFns tryFoldAddLowIntoImm(MachineInstr &RootDef, unsigned Size,
4085ffd83dbSDimitry Andric                                           MachineRegisterInfo &MRI) const;
4095ffd83dbSDimitry Andric 
4105ffd83dbSDimitry Andric   ComplexRendererFns selectAddrModeIndexed(MachineOperand &Root,
4115ffd83dbSDimitry Andric                                            unsigned Size) const;
4125ffd83dbSDimitry Andric   template <int Width>
selectAddrModeIndexed(MachineOperand & Root) const4135ffd83dbSDimitry Andric   ComplexRendererFns selectAddrModeIndexed(MachineOperand &Root) const {
4145ffd83dbSDimitry Andric     return selectAddrModeIndexed(Root, Width / 8);
4155ffd83dbSDimitry Andric   }
4165ffd83dbSDimitry Andric 
417*0fca6ea1SDimitry Andric   std::optional<bool>
418*0fca6ea1SDimitry Andric   isWorthFoldingIntoAddrMode(MachineInstr &MI,
4195ffd83dbSDimitry Andric                              const MachineRegisterInfo &MRI) const;
420*0fca6ea1SDimitry Andric 
421*0fca6ea1SDimitry Andric   bool isWorthFoldingIntoExtendedReg(MachineInstr &MI,
422*0fca6ea1SDimitry Andric                                      const MachineRegisterInfo &MRI,
423*0fca6ea1SDimitry Andric                                      bool IsAddrOperand) const;
4245ffd83dbSDimitry Andric   ComplexRendererFns
4255ffd83dbSDimitry Andric   selectAddrModeShiftedExtendXReg(MachineOperand &Root,
4265ffd83dbSDimitry Andric                                   unsigned SizeInBytes) const;
4275ffd83dbSDimitry Andric 
4285ffd83dbSDimitry Andric   /// Returns a \p ComplexRendererFns which contains a base, offset, and whether
4295ffd83dbSDimitry Andric   /// or not a shift + extend should be folded into an addressing mode. Returns
4305ffd83dbSDimitry Andric   /// None when this is not profitable or possible.
4315ffd83dbSDimitry Andric   ComplexRendererFns
4325ffd83dbSDimitry Andric   selectExtendedSHL(MachineOperand &Root, MachineOperand &Base,
4335ffd83dbSDimitry Andric                     MachineOperand &Offset, unsigned SizeInBytes,
4345ffd83dbSDimitry Andric                     bool WantsExt) const;
4355ffd83dbSDimitry Andric   ComplexRendererFns selectAddrModeRegisterOffset(MachineOperand &Root) const;
4365ffd83dbSDimitry Andric   ComplexRendererFns selectAddrModeXRO(MachineOperand &Root,
4375ffd83dbSDimitry Andric                                        unsigned SizeInBytes) const;
4385ffd83dbSDimitry Andric   template <int Width>
selectAddrModeXRO(MachineOperand & Root) const4395ffd83dbSDimitry Andric   ComplexRendererFns selectAddrModeXRO(MachineOperand &Root) const {
4405ffd83dbSDimitry Andric     return selectAddrModeXRO(Root, Width / 8);
4415ffd83dbSDimitry Andric   }
4425ffd83dbSDimitry Andric 
4435ffd83dbSDimitry Andric   ComplexRendererFns selectAddrModeWRO(MachineOperand &Root,
4445ffd83dbSDimitry Andric                                        unsigned SizeInBytes) const;
4455ffd83dbSDimitry Andric   template <int Width>
selectAddrModeWRO(MachineOperand & Root) const4465ffd83dbSDimitry Andric   ComplexRendererFns selectAddrModeWRO(MachineOperand &Root) const {
4475ffd83dbSDimitry Andric     return selectAddrModeWRO(Root, Width / 8);
4485ffd83dbSDimitry Andric   }
4495ffd83dbSDimitry Andric 
450349cc55cSDimitry Andric   ComplexRendererFns selectShiftedRegister(MachineOperand &Root,
451349cc55cSDimitry Andric                                            bool AllowROR = false) const;
4525ffd83dbSDimitry Andric 
selectArithShiftedRegister(MachineOperand & Root) const4535ffd83dbSDimitry Andric   ComplexRendererFns selectArithShiftedRegister(MachineOperand &Root) const {
4545ffd83dbSDimitry Andric     return selectShiftedRegister(Root);
4555ffd83dbSDimitry Andric   }
4565ffd83dbSDimitry Andric 
selectLogicalShiftedRegister(MachineOperand & Root) const4575ffd83dbSDimitry Andric   ComplexRendererFns selectLogicalShiftedRegister(MachineOperand &Root) const {
458349cc55cSDimitry Andric     return selectShiftedRegister(Root, true);
4595ffd83dbSDimitry Andric   }
4605ffd83dbSDimitry Andric 
4615ffd83dbSDimitry Andric   /// Given an extend instruction, determine the correct shift-extend type for
4625ffd83dbSDimitry Andric   /// that instruction.
4635ffd83dbSDimitry Andric   ///
4645ffd83dbSDimitry Andric   /// If the instruction is going to be used in a load or store, pass
4655ffd83dbSDimitry Andric   /// \p IsLoadStore = true.
4665ffd83dbSDimitry Andric   AArch64_AM::ShiftExtendType
4675ffd83dbSDimitry Andric   getExtendTypeForInst(MachineInstr &MI, MachineRegisterInfo &MRI,
4685ffd83dbSDimitry Andric                        bool IsLoadStore = false) const;
4695ffd83dbSDimitry Andric 
470eaeb601bSDimitry Andric   /// Move \p Reg to \p RC if \p Reg is not already on \p RC.
471eaeb601bSDimitry Andric   ///
472eaeb601bSDimitry Andric   /// \returns Either \p Reg if no change was necessary, or the new register
473eaeb601bSDimitry Andric   /// created by moving \p Reg.
474eaeb601bSDimitry Andric   ///
475eaeb601bSDimitry Andric   /// Note: This uses emitCopy right now.
476eaeb601bSDimitry Andric   Register moveScalarRegClass(Register Reg, const TargetRegisterClass &RC,
4775ffd83dbSDimitry Andric                               MachineIRBuilder &MIB) const;
478eaeb601bSDimitry Andric 
4795ffd83dbSDimitry Andric   ComplexRendererFns selectArithExtendedRegister(MachineOperand &Root) const;
4805ffd83dbSDimitry Andric 
48106c3fb27SDimitry Andric   ComplexRendererFns selectExtractHigh(MachineOperand &Root) const;
48206c3fb27SDimitry Andric 
4835ffd83dbSDimitry Andric   void renderTruncImm(MachineInstrBuilder &MIB, const MachineInstr &MI,
4845ffd83dbSDimitry Andric                       int OpIdx = -1) const;
4855ffd83dbSDimitry Andric   void renderLogicalImm32(MachineInstrBuilder &MIB, const MachineInstr &I,
4865ffd83dbSDimitry Andric                           int OpIdx = -1) const;
4875ffd83dbSDimitry Andric   void renderLogicalImm64(MachineInstrBuilder &MIB, const MachineInstr &I,
4885ffd83dbSDimitry Andric                           int OpIdx = -1) const;
489*0fca6ea1SDimitry Andric   void renderUbsanTrap(MachineInstrBuilder &MIB, const MachineInstr &MI,
490*0fca6ea1SDimitry Andric                        int OpIdx) const;
491fe6060f1SDimitry Andric   void renderFPImm16(MachineInstrBuilder &MIB, const MachineInstr &MI,
492fe6060f1SDimitry Andric                      int OpIdx = -1) const;
493fe6060f1SDimitry Andric   void renderFPImm32(MachineInstrBuilder &MIB, const MachineInstr &MI,
494fe6060f1SDimitry Andric                      int OpIdx = -1) const;
495fe6060f1SDimitry Andric   void renderFPImm64(MachineInstrBuilder &MIB, const MachineInstr &MI,
496fe6060f1SDimitry Andric                      int OpIdx = -1) const;
49781ad6265SDimitry Andric   void renderFPImm32SIMDModImmType4(MachineInstrBuilder &MIB,
49881ad6265SDimitry Andric                                     const MachineInstr &MI,
49981ad6265SDimitry Andric                                     int OpIdx = -1) const;
5005ffd83dbSDimitry Andric 
5015ffd83dbSDimitry Andric   // Materialize a GlobalValue or BlockAddress using a movz+movk sequence.
502fe6060f1SDimitry Andric   void materializeLargeCMVal(MachineInstr &I, const Value *V, unsigned OpFlags);
5035ffd83dbSDimitry Andric 
5045ffd83dbSDimitry Andric   // Optimization methods.
50581ad6265SDimitry Andric   bool tryOptSelect(GSelect &Sel);
50681ad6265SDimitry Andric   bool tryOptSelectConjunction(GSelect &Sel, MachineInstr &CondMI);
5075ffd83dbSDimitry Andric   MachineInstr *tryFoldIntegerCompare(MachineOperand &LHS, MachineOperand &RHS,
5085ffd83dbSDimitry Andric                                       MachineOperand &Predicate,
5095ffd83dbSDimitry Andric                                       MachineIRBuilder &MIRBuilder) const;
5105ffd83dbSDimitry Andric 
5115ffd83dbSDimitry Andric   /// Return true if \p MI is a load or store of \p NumBytes bytes.
5125ffd83dbSDimitry Andric   bool isLoadStoreOfNumBytes(const MachineInstr &MI, unsigned NumBytes) const;
5135ffd83dbSDimitry Andric 
5145ffd83dbSDimitry Andric   /// Returns true if \p MI is guaranteed to have the high-half of a 64-bit
5155ffd83dbSDimitry Andric   /// register zeroed out. In other words, the result of MI has been explicitly
5165ffd83dbSDimitry Andric   /// zero extended.
5175ffd83dbSDimitry Andric   bool isDef32(const MachineInstr &MI) const;
5185ffd83dbSDimitry Andric 
5195ffd83dbSDimitry Andric   const AArch64TargetMachine &TM;
5205ffd83dbSDimitry Andric   const AArch64Subtarget &STI;
5215ffd83dbSDimitry Andric   const AArch64InstrInfo &TII;
5225ffd83dbSDimitry Andric   const AArch64RegisterInfo &TRI;
5235ffd83dbSDimitry Andric   const AArch64RegisterBankInfo &RBI;
5245ffd83dbSDimitry Andric 
5255ffd83dbSDimitry Andric   bool ProduceNonFlagSettingCondBr = false;
5265ffd83dbSDimitry Andric 
5275ffd83dbSDimitry Andric   // Some cached values used during selection.
5285ffd83dbSDimitry Andric   // We use LR as a live-in register, and we keep track of it here as it can be
5295ffd83dbSDimitry Andric   // clobbered by calls.
5305ffd83dbSDimitry Andric   Register MFReturnAddr;
5315ffd83dbSDimitry Andric 
532fe6060f1SDimitry Andric   MachineIRBuilder MIB;
533fe6060f1SDimitry Andric 
5345ffd83dbSDimitry Andric #define GET_GLOBALISEL_PREDICATES_DECL
5355ffd83dbSDimitry Andric #include "AArch64GenGlobalISel.inc"
5365ffd83dbSDimitry Andric #undef GET_GLOBALISEL_PREDICATES_DECL
5375ffd83dbSDimitry Andric 
5385ffd83dbSDimitry Andric // We declare the temporaries used by selectImpl() in the class to minimize the
5395ffd83dbSDimitry Andric // cost of constructing placeholder values.
5405ffd83dbSDimitry Andric #define GET_GLOBALISEL_TEMPORARIES_DECL
5415ffd83dbSDimitry Andric #include "AArch64GenGlobalISel.inc"
5425ffd83dbSDimitry Andric #undef GET_GLOBALISEL_TEMPORARIES_DECL
5435ffd83dbSDimitry Andric };
5445ffd83dbSDimitry Andric 
5455ffd83dbSDimitry Andric } // end anonymous namespace
5465ffd83dbSDimitry Andric 
5475ffd83dbSDimitry Andric #define GET_GLOBALISEL_IMPL
5485ffd83dbSDimitry Andric #include "AArch64GenGlobalISel.inc"
5495ffd83dbSDimitry Andric #undef GET_GLOBALISEL_IMPL
5505ffd83dbSDimitry Andric 
AArch64InstructionSelector(const AArch64TargetMachine & TM,const AArch64Subtarget & STI,const AArch64RegisterBankInfo & RBI)5515ffd83dbSDimitry Andric AArch64InstructionSelector::AArch64InstructionSelector(
5525ffd83dbSDimitry Andric     const AArch64TargetMachine &TM, const AArch64Subtarget &STI,
5535ffd83dbSDimitry Andric     const AArch64RegisterBankInfo &RBI)
55404eeddc0SDimitry Andric     : TM(TM), STI(STI), TII(*STI.getInstrInfo()), TRI(*STI.getRegisterInfo()),
55504eeddc0SDimitry Andric       RBI(RBI),
5565ffd83dbSDimitry Andric #define GET_GLOBALISEL_PREDICATES_INIT
5575ffd83dbSDimitry Andric #include "AArch64GenGlobalISel.inc"
5585ffd83dbSDimitry Andric #undef GET_GLOBALISEL_PREDICATES_INIT
5595ffd83dbSDimitry Andric #define GET_GLOBALISEL_TEMPORARIES_INIT
5605ffd83dbSDimitry Andric #include "AArch64GenGlobalISel.inc"
5615ffd83dbSDimitry Andric #undef GET_GLOBALISEL_TEMPORARIES_INIT
5625ffd83dbSDimitry Andric {
5635ffd83dbSDimitry Andric }
5645ffd83dbSDimitry Andric 
5655ffd83dbSDimitry Andric // FIXME: This should be target-independent, inferred from the types declared
5665ffd83dbSDimitry Andric // for each class in the bank.
56781ad6265SDimitry Andric //
56881ad6265SDimitry Andric /// Given a register bank, and a type, return the smallest register class that
56981ad6265SDimitry Andric /// can represent that combination.
5705ffd83dbSDimitry Andric static const TargetRegisterClass *
getRegClassForTypeOnBank(LLT Ty,const RegisterBank & RB,bool GetAllRegSet=false)5715ffd83dbSDimitry Andric getRegClassForTypeOnBank(LLT Ty, const RegisterBank &RB,
5725ffd83dbSDimitry Andric                          bool GetAllRegSet = false) {
5735ffd83dbSDimitry Andric   if (RB.getID() == AArch64::GPRRegBankID) {
5745ffd83dbSDimitry Andric     if (Ty.getSizeInBits() <= 32)
5755ffd83dbSDimitry Andric       return GetAllRegSet ? &AArch64::GPR32allRegClass
5765ffd83dbSDimitry Andric                           : &AArch64::GPR32RegClass;
5775ffd83dbSDimitry Andric     if (Ty.getSizeInBits() == 64)
5785ffd83dbSDimitry Andric       return GetAllRegSet ? &AArch64::GPR64allRegClass
5795ffd83dbSDimitry Andric                           : &AArch64::GPR64RegClass;
580fe6060f1SDimitry Andric     if (Ty.getSizeInBits() == 128)
581fe6060f1SDimitry Andric       return &AArch64::XSeqPairsClassRegClass;
5825ffd83dbSDimitry Andric     return nullptr;
5835ffd83dbSDimitry Andric   }
5845ffd83dbSDimitry Andric 
5855ffd83dbSDimitry Andric   if (RB.getID() == AArch64::FPRRegBankID) {
586349cc55cSDimitry Andric     switch (Ty.getSizeInBits()) {
587349cc55cSDimitry Andric     case 8:
588349cc55cSDimitry Andric       return &AArch64::FPR8RegClass;
589349cc55cSDimitry Andric     case 16:
5905ffd83dbSDimitry Andric       return &AArch64::FPR16RegClass;
591349cc55cSDimitry Andric     case 32:
5925ffd83dbSDimitry Andric       return &AArch64::FPR32RegClass;
593349cc55cSDimitry Andric     case 64:
5945ffd83dbSDimitry Andric       return &AArch64::FPR64RegClass;
595349cc55cSDimitry Andric     case 128:
5965ffd83dbSDimitry Andric       return &AArch64::FPR128RegClass;
597349cc55cSDimitry Andric     }
5985ffd83dbSDimitry Andric     return nullptr;
5995ffd83dbSDimitry Andric   }
6005ffd83dbSDimitry Andric 
6015ffd83dbSDimitry Andric   return nullptr;
6025ffd83dbSDimitry Andric }
6035ffd83dbSDimitry Andric 
6045ffd83dbSDimitry Andric /// Given a register bank, and size in bits, return the smallest register class
6055ffd83dbSDimitry Andric /// that can represent that combination.
6065ffd83dbSDimitry Andric static const TargetRegisterClass *
getMinClassForRegBank(const RegisterBank & RB,TypeSize SizeInBits,bool GetAllRegSet=false)607*0fca6ea1SDimitry Andric getMinClassForRegBank(const RegisterBank &RB, TypeSize SizeInBits,
6085ffd83dbSDimitry Andric                       bool GetAllRegSet = false) {
609*0fca6ea1SDimitry Andric   if (SizeInBits.isScalable()) {
610*0fca6ea1SDimitry Andric     assert(RB.getID() == AArch64::FPRRegBankID &&
611*0fca6ea1SDimitry Andric            "Expected FPR regbank for scalable type size");
612*0fca6ea1SDimitry Andric     return &AArch64::ZPRRegClass;
613*0fca6ea1SDimitry Andric   }
614*0fca6ea1SDimitry Andric 
6155ffd83dbSDimitry Andric   unsigned RegBankID = RB.getID();
6165ffd83dbSDimitry Andric 
6175ffd83dbSDimitry Andric   if (RegBankID == AArch64::GPRRegBankID) {
6185ffd83dbSDimitry Andric     if (SizeInBits <= 32)
6195ffd83dbSDimitry Andric       return GetAllRegSet ? &AArch64::GPR32allRegClass
6205ffd83dbSDimitry Andric                           : &AArch64::GPR32RegClass;
6215ffd83dbSDimitry Andric     if (SizeInBits == 64)
6225ffd83dbSDimitry Andric       return GetAllRegSet ? &AArch64::GPR64allRegClass
6235ffd83dbSDimitry Andric                           : &AArch64::GPR64RegClass;
624fe6060f1SDimitry Andric     if (SizeInBits == 128)
625fe6060f1SDimitry Andric       return &AArch64::XSeqPairsClassRegClass;
6265ffd83dbSDimitry Andric   }
6275ffd83dbSDimitry Andric 
6285ffd83dbSDimitry Andric   if (RegBankID == AArch64::FPRRegBankID) {
6295ffd83dbSDimitry Andric     switch (SizeInBits) {
6305ffd83dbSDimitry Andric     default:
6315ffd83dbSDimitry Andric       return nullptr;
6325ffd83dbSDimitry Andric     case 8:
6335ffd83dbSDimitry Andric       return &AArch64::FPR8RegClass;
6345ffd83dbSDimitry Andric     case 16:
6355ffd83dbSDimitry Andric       return &AArch64::FPR16RegClass;
6365ffd83dbSDimitry Andric     case 32:
6375ffd83dbSDimitry Andric       return &AArch64::FPR32RegClass;
6385ffd83dbSDimitry Andric     case 64:
6395ffd83dbSDimitry Andric       return &AArch64::FPR64RegClass;
6405ffd83dbSDimitry Andric     case 128:
6415ffd83dbSDimitry Andric       return &AArch64::FPR128RegClass;
6425ffd83dbSDimitry Andric     }
6435ffd83dbSDimitry Andric   }
6445ffd83dbSDimitry Andric 
6455ffd83dbSDimitry Andric   return nullptr;
6465ffd83dbSDimitry Andric }
6475ffd83dbSDimitry Andric 
6485ffd83dbSDimitry Andric /// Returns the correct subregister to use for a given register class.
getSubRegForClass(const TargetRegisterClass * RC,const TargetRegisterInfo & TRI,unsigned & SubReg)6495ffd83dbSDimitry Andric static bool getSubRegForClass(const TargetRegisterClass *RC,
6505ffd83dbSDimitry Andric                               const TargetRegisterInfo &TRI, unsigned &SubReg) {
6515ffd83dbSDimitry Andric   switch (TRI.getRegSizeInBits(*RC)) {
6525ffd83dbSDimitry Andric   case 8:
6535ffd83dbSDimitry Andric     SubReg = AArch64::bsub;
6545ffd83dbSDimitry Andric     break;
6555ffd83dbSDimitry Andric   case 16:
6565ffd83dbSDimitry Andric     SubReg = AArch64::hsub;
6575ffd83dbSDimitry Andric     break;
6585ffd83dbSDimitry Andric   case 32:
6595ffd83dbSDimitry Andric     if (RC != &AArch64::FPR32RegClass)
6605ffd83dbSDimitry Andric       SubReg = AArch64::sub_32;
6615ffd83dbSDimitry Andric     else
6625ffd83dbSDimitry Andric       SubReg = AArch64::ssub;
6635ffd83dbSDimitry Andric     break;
6645ffd83dbSDimitry Andric   case 64:
6655ffd83dbSDimitry Andric     SubReg = AArch64::dsub;
6665ffd83dbSDimitry Andric     break;
6675ffd83dbSDimitry Andric   default:
6685ffd83dbSDimitry Andric     LLVM_DEBUG(
6695ffd83dbSDimitry Andric         dbgs() << "Couldn't find appropriate subregister for register class.");
6705ffd83dbSDimitry Andric     return false;
6715ffd83dbSDimitry Andric   }
6725ffd83dbSDimitry Andric 
6735ffd83dbSDimitry Andric   return true;
6745ffd83dbSDimitry Andric }
6755ffd83dbSDimitry Andric 
6765ffd83dbSDimitry Andric /// Returns the minimum size the given register bank can hold.
getMinSizeForRegBank(const RegisterBank & RB)6775ffd83dbSDimitry Andric static unsigned getMinSizeForRegBank(const RegisterBank &RB) {
6785ffd83dbSDimitry Andric   switch (RB.getID()) {
6795ffd83dbSDimitry Andric   case AArch64::GPRRegBankID:
6805ffd83dbSDimitry Andric     return 32;
6815ffd83dbSDimitry Andric   case AArch64::FPRRegBankID:
6825ffd83dbSDimitry Andric     return 8;
6835ffd83dbSDimitry Andric   default:
6845ffd83dbSDimitry Andric     llvm_unreachable("Tried to get minimum size for unknown register bank.");
6855ffd83dbSDimitry Andric   }
6865ffd83dbSDimitry Andric }
6875ffd83dbSDimitry Andric 
688fe6060f1SDimitry Andric /// Create a REG_SEQUENCE instruction using the registers in \p Regs.
689fe6060f1SDimitry Andric /// Helper function for functions like createDTuple and createQTuple.
690fe6060f1SDimitry Andric ///
691fe6060f1SDimitry Andric /// \p RegClassIDs - The list of register class IDs available for some tuple of
692fe6060f1SDimitry Andric /// a scalar class. E.g. QQRegClassID, QQQRegClassID, QQQQRegClassID. This is
693fe6060f1SDimitry Andric /// expected to contain between 2 and 4 tuple classes.
694fe6060f1SDimitry Andric ///
695fe6060f1SDimitry Andric /// \p SubRegs - The list of subregister classes associated with each register
696fe6060f1SDimitry Andric /// class ID in \p RegClassIDs. E.g., QQRegClassID should use the qsub0
697fe6060f1SDimitry Andric /// subregister class. The index of each subregister class is expected to
698fe6060f1SDimitry Andric /// correspond with the index of each register class.
699fe6060f1SDimitry Andric ///
700fe6060f1SDimitry Andric /// \returns Either the destination register of REG_SEQUENCE instruction that
701fe6060f1SDimitry Andric /// was created, or the 0th element of \p Regs if \p Regs contains a single
702fe6060f1SDimitry Andric /// element.
createTuple(ArrayRef<Register> Regs,const unsigned RegClassIDs[],const unsigned SubRegs[],MachineIRBuilder & MIB)703fe6060f1SDimitry Andric static Register createTuple(ArrayRef<Register> Regs,
704fe6060f1SDimitry Andric                             const unsigned RegClassIDs[],
705fe6060f1SDimitry Andric                             const unsigned SubRegs[], MachineIRBuilder &MIB) {
706fe6060f1SDimitry Andric   unsigned NumRegs = Regs.size();
707fe6060f1SDimitry Andric   if (NumRegs == 1)
708fe6060f1SDimitry Andric     return Regs[0];
709fe6060f1SDimitry Andric   assert(NumRegs >= 2 && NumRegs <= 4 &&
710fe6060f1SDimitry Andric          "Only support between two and 4 registers in a tuple!");
711fe6060f1SDimitry Andric   const TargetRegisterInfo *TRI = MIB.getMF().getSubtarget().getRegisterInfo();
712fe6060f1SDimitry Andric   auto *DesiredClass = TRI->getRegClass(RegClassIDs[NumRegs - 2]);
713fe6060f1SDimitry Andric   auto RegSequence =
714fe6060f1SDimitry Andric       MIB.buildInstr(TargetOpcode::REG_SEQUENCE, {DesiredClass}, {});
715fe6060f1SDimitry Andric   for (unsigned I = 0, E = Regs.size(); I < E; ++I) {
716fe6060f1SDimitry Andric     RegSequence.addUse(Regs[I]);
717fe6060f1SDimitry Andric     RegSequence.addImm(SubRegs[I]);
718fe6060f1SDimitry Andric   }
719fe6060f1SDimitry Andric   return RegSequence.getReg(0);
720fe6060f1SDimitry Andric }
721fe6060f1SDimitry Andric 
722fe6060f1SDimitry Andric /// Create a tuple of D-registers using the registers in \p Regs.
createDTuple(ArrayRef<Register> Regs,MachineIRBuilder & MIB)723fe6060f1SDimitry Andric static Register createDTuple(ArrayRef<Register> Regs, MachineIRBuilder &MIB) {
724fe6060f1SDimitry Andric   static const unsigned RegClassIDs[] = {
725fe6060f1SDimitry Andric       AArch64::DDRegClassID, AArch64::DDDRegClassID, AArch64::DDDDRegClassID};
726fe6060f1SDimitry Andric   static const unsigned SubRegs[] = {AArch64::dsub0, AArch64::dsub1,
727fe6060f1SDimitry Andric                                      AArch64::dsub2, AArch64::dsub3};
728fe6060f1SDimitry Andric   return createTuple(Regs, RegClassIDs, SubRegs, MIB);
729fe6060f1SDimitry Andric }
730fe6060f1SDimitry Andric 
731fe6060f1SDimitry Andric /// Create a tuple of Q-registers using the registers in \p Regs.
createQTuple(ArrayRef<Register> Regs,MachineIRBuilder & MIB)732fe6060f1SDimitry Andric static Register createQTuple(ArrayRef<Register> Regs, MachineIRBuilder &MIB) {
733fe6060f1SDimitry Andric   static const unsigned RegClassIDs[] = {
734fe6060f1SDimitry Andric       AArch64::QQRegClassID, AArch64::QQQRegClassID, AArch64::QQQQRegClassID};
735fe6060f1SDimitry Andric   static const unsigned SubRegs[] = {AArch64::qsub0, AArch64::qsub1,
736fe6060f1SDimitry Andric                                      AArch64::qsub2, AArch64::qsub3};
737fe6060f1SDimitry Andric   return createTuple(Regs, RegClassIDs, SubRegs, MIB);
738fe6060f1SDimitry Andric }
739fe6060f1SDimitry Andric 
getImmedFromMO(const MachineOperand & Root)740bdd1243dSDimitry Andric static std::optional<uint64_t> getImmedFromMO(const MachineOperand &Root) {
7415ffd83dbSDimitry Andric   auto &MI = *Root.getParent();
7425ffd83dbSDimitry Andric   auto &MBB = *MI.getParent();
7435ffd83dbSDimitry Andric   auto &MF = *MBB.getParent();
7445ffd83dbSDimitry Andric   auto &MRI = MF.getRegInfo();
7455ffd83dbSDimitry Andric   uint64_t Immed;
7465ffd83dbSDimitry Andric   if (Root.isImm())
7475ffd83dbSDimitry Andric     Immed = Root.getImm();
7485ffd83dbSDimitry Andric   else if (Root.isCImm())
7495ffd83dbSDimitry Andric     Immed = Root.getCImm()->getZExtValue();
7505ffd83dbSDimitry Andric   else if (Root.isReg()) {
7515ffd83dbSDimitry Andric     auto ValAndVReg =
752349cc55cSDimitry Andric         getIConstantVRegValWithLookThrough(Root.getReg(), MRI, true);
7535ffd83dbSDimitry Andric     if (!ValAndVReg)
754bdd1243dSDimitry Andric       return std::nullopt;
755e8d8bef9SDimitry Andric     Immed = ValAndVReg->Value.getSExtValue();
7565ffd83dbSDimitry Andric   } else
757bdd1243dSDimitry Andric     return std::nullopt;
7585ffd83dbSDimitry Andric   return Immed;
7595ffd83dbSDimitry Andric }
7605ffd83dbSDimitry Andric 
7615ffd83dbSDimitry Andric /// Check whether \p I is a currently unsupported binary operation:
7625ffd83dbSDimitry Andric /// - it has an unsized type
7635ffd83dbSDimitry Andric /// - an operand is not a vreg
7645ffd83dbSDimitry Andric /// - all operands are not in the same bank
7655ffd83dbSDimitry Andric /// These are checks that should someday live in the verifier, but right now,
7665ffd83dbSDimitry Andric /// these are mostly limitations of the aarch64 selector.
unsupportedBinOp(const MachineInstr & I,const AArch64RegisterBankInfo & RBI,const MachineRegisterInfo & MRI,const AArch64RegisterInfo & TRI)7675ffd83dbSDimitry Andric static bool unsupportedBinOp(const MachineInstr &I,
7685ffd83dbSDimitry Andric                              const AArch64RegisterBankInfo &RBI,
7695ffd83dbSDimitry Andric                              const MachineRegisterInfo &MRI,
7705ffd83dbSDimitry Andric                              const AArch64RegisterInfo &TRI) {
7715ffd83dbSDimitry Andric   LLT Ty = MRI.getType(I.getOperand(0).getReg());
7725ffd83dbSDimitry Andric   if (!Ty.isValid()) {
7735ffd83dbSDimitry Andric     LLVM_DEBUG(dbgs() << "Generic binop register should be typed\n");
7745ffd83dbSDimitry Andric     return true;
7755ffd83dbSDimitry Andric   }
7765ffd83dbSDimitry Andric 
7775ffd83dbSDimitry Andric   const RegisterBank *PrevOpBank = nullptr;
7785ffd83dbSDimitry Andric   for (auto &MO : I.operands()) {
7795ffd83dbSDimitry Andric     // FIXME: Support non-register operands.
7805ffd83dbSDimitry Andric     if (!MO.isReg()) {
7815ffd83dbSDimitry Andric       LLVM_DEBUG(dbgs() << "Generic inst non-reg operands are unsupported\n");
7825ffd83dbSDimitry Andric       return true;
7835ffd83dbSDimitry Andric     }
7845ffd83dbSDimitry Andric 
7855ffd83dbSDimitry Andric     // FIXME: Can generic operations have physical registers operands? If
7865ffd83dbSDimitry Andric     // so, this will need to be taught about that, and we'll need to get the
7875ffd83dbSDimitry Andric     // bank out of the minimal class for the register.
7885ffd83dbSDimitry Andric     // Either way, this needs to be documented (and possibly verified).
789bdd1243dSDimitry Andric     if (!MO.getReg().isVirtual()) {
7905ffd83dbSDimitry Andric       LLVM_DEBUG(dbgs() << "Generic inst has physical register operand\n");
7915ffd83dbSDimitry Andric       return true;
7925ffd83dbSDimitry Andric     }
7935ffd83dbSDimitry Andric 
7945ffd83dbSDimitry Andric     const RegisterBank *OpBank = RBI.getRegBank(MO.getReg(), MRI, TRI);
7955ffd83dbSDimitry Andric     if (!OpBank) {
7965ffd83dbSDimitry Andric       LLVM_DEBUG(dbgs() << "Generic register has no bank or class\n");
7975ffd83dbSDimitry Andric       return true;
7985ffd83dbSDimitry Andric     }
7995ffd83dbSDimitry Andric 
8005ffd83dbSDimitry Andric     if (PrevOpBank && OpBank != PrevOpBank) {
8015ffd83dbSDimitry Andric       LLVM_DEBUG(dbgs() << "Generic inst operands have different banks\n");
8025ffd83dbSDimitry Andric       return true;
8035ffd83dbSDimitry Andric     }
8045ffd83dbSDimitry Andric     PrevOpBank = OpBank;
8055ffd83dbSDimitry Andric   }
8065ffd83dbSDimitry Andric   return false;
8075ffd83dbSDimitry Andric }
8085ffd83dbSDimitry Andric 
8095ffd83dbSDimitry Andric /// Select the AArch64 opcode for the basic binary operation \p GenericOpc
8105ffd83dbSDimitry Andric /// (such as G_OR or G_SDIV), appropriate for the register bank \p RegBankID
8115ffd83dbSDimitry Andric /// and of size \p OpSize.
8125ffd83dbSDimitry Andric /// \returns \p GenericOpc if the combination is unsupported.
selectBinaryOp(unsigned GenericOpc,unsigned RegBankID,unsigned OpSize)8135ffd83dbSDimitry Andric static unsigned selectBinaryOp(unsigned GenericOpc, unsigned RegBankID,
8145ffd83dbSDimitry Andric                                unsigned OpSize) {
8155ffd83dbSDimitry Andric   switch (RegBankID) {
8165ffd83dbSDimitry Andric   case AArch64::GPRRegBankID:
8175ffd83dbSDimitry Andric     if (OpSize == 32) {
8185ffd83dbSDimitry Andric       switch (GenericOpc) {
8195ffd83dbSDimitry Andric       case TargetOpcode::G_SHL:
8205ffd83dbSDimitry Andric         return AArch64::LSLVWr;
8215ffd83dbSDimitry Andric       case TargetOpcode::G_LSHR:
8225ffd83dbSDimitry Andric         return AArch64::LSRVWr;
8235ffd83dbSDimitry Andric       case TargetOpcode::G_ASHR:
8245ffd83dbSDimitry Andric         return AArch64::ASRVWr;
8255ffd83dbSDimitry Andric       default:
8265ffd83dbSDimitry Andric         return GenericOpc;
8275ffd83dbSDimitry Andric       }
8285ffd83dbSDimitry Andric     } else if (OpSize == 64) {
8295ffd83dbSDimitry Andric       switch (GenericOpc) {
8305ffd83dbSDimitry Andric       case TargetOpcode::G_PTR_ADD:
8315ffd83dbSDimitry Andric         return AArch64::ADDXrr;
8325ffd83dbSDimitry Andric       case TargetOpcode::G_SHL:
8335ffd83dbSDimitry Andric         return AArch64::LSLVXr;
8345ffd83dbSDimitry Andric       case TargetOpcode::G_LSHR:
8355ffd83dbSDimitry Andric         return AArch64::LSRVXr;
8365ffd83dbSDimitry Andric       case TargetOpcode::G_ASHR:
8375ffd83dbSDimitry Andric         return AArch64::ASRVXr;
8385ffd83dbSDimitry Andric       default:
8395ffd83dbSDimitry Andric         return GenericOpc;
8405ffd83dbSDimitry Andric       }
8415ffd83dbSDimitry Andric     }
8425ffd83dbSDimitry Andric     break;
8435ffd83dbSDimitry Andric   case AArch64::FPRRegBankID:
8445ffd83dbSDimitry Andric     switch (OpSize) {
8455ffd83dbSDimitry Andric     case 32:
8465ffd83dbSDimitry Andric       switch (GenericOpc) {
8475ffd83dbSDimitry Andric       case TargetOpcode::G_FADD:
8485ffd83dbSDimitry Andric         return AArch64::FADDSrr;
8495ffd83dbSDimitry Andric       case TargetOpcode::G_FSUB:
8505ffd83dbSDimitry Andric         return AArch64::FSUBSrr;
8515ffd83dbSDimitry Andric       case TargetOpcode::G_FMUL:
8525ffd83dbSDimitry Andric         return AArch64::FMULSrr;
8535ffd83dbSDimitry Andric       case TargetOpcode::G_FDIV:
8545ffd83dbSDimitry Andric         return AArch64::FDIVSrr;
8555ffd83dbSDimitry Andric       default:
8565ffd83dbSDimitry Andric         return GenericOpc;
8575ffd83dbSDimitry Andric       }
8585ffd83dbSDimitry Andric     case 64:
8595ffd83dbSDimitry Andric       switch (GenericOpc) {
8605ffd83dbSDimitry Andric       case TargetOpcode::G_FADD:
8615ffd83dbSDimitry Andric         return AArch64::FADDDrr;
8625ffd83dbSDimitry Andric       case TargetOpcode::G_FSUB:
8635ffd83dbSDimitry Andric         return AArch64::FSUBDrr;
8645ffd83dbSDimitry Andric       case TargetOpcode::G_FMUL:
8655ffd83dbSDimitry Andric         return AArch64::FMULDrr;
8665ffd83dbSDimitry Andric       case TargetOpcode::G_FDIV:
8675ffd83dbSDimitry Andric         return AArch64::FDIVDrr;
8685ffd83dbSDimitry Andric       case TargetOpcode::G_OR:
8695ffd83dbSDimitry Andric         return AArch64::ORRv8i8;
8705ffd83dbSDimitry Andric       default:
8715ffd83dbSDimitry Andric         return GenericOpc;
8725ffd83dbSDimitry Andric       }
8735ffd83dbSDimitry Andric     }
8745ffd83dbSDimitry Andric     break;
8755ffd83dbSDimitry Andric   }
8765ffd83dbSDimitry Andric   return GenericOpc;
8775ffd83dbSDimitry Andric }
8785ffd83dbSDimitry Andric 
8795ffd83dbSDimitry Andric /// Select the AArch64 opcode for the G_LOAD or G_STORE operation \p GenericOpc,
8805ffd83dbSDimitry Andric /// appropriate for the (value) register bank \p RegBankID and of memory access
8815ffd83dbSDimitry Andric /// size \p OpSize.  This returns the variant with the base+unsigned-immediate
8825ffd83dbSDimitry Andric /// addressing mode (e.g., LDRXui).
8835ffd83dbSDimitry Andric /// \returns \p GenericOpc if the combination is unsupported.
selectLoadStoreUIOp(unsigned GenericOpc,unsigned RegBankID,unsigned OpSize)8845ffd83dbSDimitry Andric static unsigned selectLoadStoreUIOp(unsigned GenericOpc, unsigned RegBankID,
8855ffd83dbSDimitry Andric                                     unsigned OpSize) {
8865ffd83dbSDimitry Andric   const bool isStore = GenericOpc == TargetOpcode::G_STORE;
8875ffd83dbSDimitry Andric   switch (RegBankID) {
8885ffd83dbSDimitry Andric   case AArch64::GPRRegBankID:
8895ffd83dbSDimitry Andric     switch (OpSize) {
8905ffd83dbSDimitry Andric     case 8:
8915ffd83dbSDimitry Andric       return isStore ? AArch64::STRBBui : AArch64::LDRBBui;
8925ffd83dbSDimitry Andric     case 16:
8935ffd83dbSDimitry Andric       return isStore ? AArch64::STRHHui : AArch64::LDRHHui;
8945ffd83dbSDimitry Andric     case 32:
8955ffd83dbSDimitry Andric       return isStore ? AArch64::STRWui : AArch64::LDRWui;
8965ffd83dbSDimitry Andric     case 64:
8975ffd83dbSDimitry Andric       return isStore ? AArch64::STRXui : AArch64::LDRXui;
8985ffd83dbSDimitry Andric     }
8995ffd83dbSDimitry Andric     break;
9005ffd83dbSDimitry Andric   case AArch64::FPRRegBankID:
9015ffd83dbSDimitry Andric     switch (OpSize) {
9025ffd83dbSDimitry Andric     case 8:
9035ffd83dbSDimitry Andric       return isStore ? AArch64::STRBui : AArch64::LDRBui;
9045ffd83dbSDimitry Andric     case 16:
9055ffd83dbSDimitry Andric       return isStore ? AArch64::STRHui : AArch64::LDRHui;
9065ffd83dbSDimitry Andric     case 32:
9075ffd83dbSDimitry Andric       return isStore ? AArch64::STRSui : AArch64::LDRSui;
9085ffd83dbSDimitry Andric     case 64:
9095ffd83dbSDimitry Andric       return isStore ? AArch64::STRDui : AArch64::LDRDui;
910349cc55cSDimitry Andric     case 128:
911349cc55cSDimitry Andric       return isStore ? AArch64::STRQui : AArch64::LDRQui;
9125ffd83dbSDimitry Andric     }
9135ffd83dbSDimitry Andric     break;
9145ffd83dbSDimitry Andric   }
9155ffd83dbSDimitry Andric   return GenericOpc;
9165ffd83dbSDimitry Andric }
9175ffd83dbSDimitry Andric 
9185ffd83dbSDimitry Andric /// Helper function for selectCopy. Inserts a subregister copy from \p SrcReg
9195ffd83dbSDimitry Andric /// to \p *To.
9205ffd83dbSDimitry Andric ///
9215ffd83dbSDimitry Andric /// E.g "To = COPY SrcReg:SubReg"
copySubReg(MachineInstr & I,MachineRegisterInfo & MRI,const RegisterBankInfo & RBI,Register SrcReg,const TargetRegisterClass * To,unsigned SubReg)9225ffd83dbSDimitry Andric static bool copySubReg(MachineInstr &I, MachineRegisterInfo &MRI,
9235ffd83dbSDimitry Andric                        const RegisterBankInfo &RBI, Register SrcReg,
9245ffd83dbSDimitry Andric                        const TargetRegisterClass *To, unsigned SubReg) {
9255ffd83dbSDimitry Andric   assert(SrcReg.isValid() && "Expected a valid source register?");
9265ffd83dbSDimitry Andric   assert(To && "Destination register class cannot be null");
9275ffd83dbSDimitry Andric   assert(SubReg && "Expected a valid subregister");
9285ffd83dbSDimitry Andric 
9295ffd83dbSDimitry Andric   MachineIRBuilder MIB(I);
9305ffd83dbSDimitry Andric   auto SubRegCopy =
9315ffd83dbSDimitry Andric       MIB.buildInstr(TargetOpcode::COPY, {To}, {}).addReg(SrcReg, 0, SubReg);
9325ffd83dbSDimitry Andric   MachineOperand &RegOp = I.getOperand(1);
9335ffd83dbSDimitry Andric   RegOp.setReg(SubRegCopy.getReg(0));
9345ffd83dbSDimitry Andric 
9355ffd83dbSDimitry Andric   // It's possible that the destination register won't be constrained. Make
9365ffd83dbSDimitry Andric   // sure that happens.
937bdd1243dSDimitry Andric   if (!I.getOperand(0).getReg().isPhysical())
9385ffd83dbSDimitry Andric     RBI.constrainGenericRegister(I.getOperand(0).getReg(), *To, MRI);
9395ffd83dbSDimitry Andric 
9405ffd83dbSDimitry Andric   return true;
9415ffd83dbSDimitry Andric }
9425ffd83dbSDimitry Andric 
9435ffd83dbSDimitry Andric /// Helper function to get the source and destination register classes for a
9445ffd83dbSDimitry Andric /// copy. Returns a std::pair containing the source register class for the
9455ffd83dbSDimitry Andric /// copy, and the destination register class for the copy. If a register class
9465ffd83dbSDimitry Andric /// cannot be determined, then it will be nullptr.
9475ffd83dbSDimitry Andric static std::pair<const TargetRegisterClass *, const TargetRegisterClass *>
getRegClassesForCopy(MachineInstr & I,const TargetInstrInfo & TII,MachineRegisterInfo & MRI,const TargetRegisterInfo & TRI,const RegisterBankInfo & RBI)9485ffd83dbSDimitry Andric getRegClassesForCopy(MachineInstr &I, const TargetInstrInfo &TII,
9495ffd83dbSDimitry Andric                      MachineRegisterInfo &MRI, const TargetRegisterInfo &TRI,
9505ffd83dbSDimitry Andric                      const RegisterBankInfo &RBI) {
9515ffd83dbSDimitry Andric   Register DstReg = I.getOperand(0).getReg();
9525ffd83dbSDimitry Andric   Register SrcReg = I.getOperand(1).getReg();
9535ffd83dbSDimitry Andric   const RegisterBank &DstRegBank = *RBI.getRegBank(DstReg, MRI, TRI);
9545ffd83dbSDimitry Andric   const RegisterBank &SrcRegBank = *RBI.getRegBank(SrcReg, MRI, TRI);
955*0fca6ea1SDimitry Andric 
956*0fca6ea1SDimitry Andric   TypeSize DstSize = RBI.getSizeInBits(DstReg, MRI, TRI);
957*0fca6ea1SDimitry Andric   TypeSize SrcSize = RBI.getSizeInBits(SrcReg, MRI, TRI);
9585ffd83dbSDimitry Andric 
9595ffd83dbSDimitry Andric   // Special casing for cross-bank copies of s1s. We can technically represent
9605ffd83dbSDimitry Andric   // a 1-bit value with any size of register. The minimum size for a GPR is 32
9615ffd83dbSDimitry Andric   // bits. So, we need to put the FPR on 32 bits as well.
9625ffd83dbSDimitry Andric   //
9635ffd83dbSDimitry Andric   // FIXME: I'm not sure if this case holds true outside of copies. If it does,
9645ffd83dbSDimitry Andric   // then we can pull it into the helpers that get the appropriate class for a
9655ffd83dbSDimitry Andric   // register bank. Or make a new helper that carries along some constraint
9665ffd83dbSDimitry Andric   // information.
9675ffd83dbSDimitry Andric   if (SrcRegBank != DstRegBank && (DstSize == 1 && SrcSize == 1))
968*0fca6ea1SDimitry Andric     SrcSize = DstSize = TypeSize::getFixed(32);
9695ffd83dbSDimitry Andric 
9705ffd83dbSDimitry Andric   return {getMinClassForRegBank(SrcRegBank, SrcSize, true),
9715ffd83dbSDimitry Andric           getMinClassForRegBank(DstRegBank, DstSize, true)};
9725ffd83dbSDimitry Andric }
9735ffd83dbSDimitry Andric 
974bdd1243dSDimitry Andric // FIXME: We need some sort of API in RBI/TRI to allow generic code to
975bdd1243dSDimitry Andric // constrain operands of simple instructions given a TargetRegisterClass
976bdd1243dSDimitry Andric // and LLT
selectDebugInstr(MachineInstr & I,MachineRegisterInfo & MRI,const RegisterBankInfo & RBI)977bdd1243dSDimitry Andric static bool selectDebugInstr(MachineInstr &I, MachineRegisterInfo &MRI,
978bdd1243dSDimitry Andric                              const RegisterBankInfo &RBI) {
979bdd1243dSDimitry Andric   for (MachineOperand &MO : I.operands()) {
980bdd1243dSDimitry Andric     if (!MO.isReg())
981bdd1243dSDimitry Andric       continue;
982bdd1243dSDimitry Andric     Register Reg = MO.getReg();
983bdd1243dSDimitry Andric     if (!Reg)
984bdd1243dSDimitry Andric       continue;
985bdd1243dSDimitry Andric     if (Reg.isPhysical())
986bdd1243dSDimitry Andric       continue;
987bdd1243dSDimitry Andric     LLT Ty = MRI.getType(Reg);
988bdd1243dSDimitry Andric     const RegClassOrRegBank &RegClassOrBank = MRI.getRegClassOrRegBank(Reg);
989bdd1243dSDimitry Andric     const TargetRegisterClass *RC =
990bdd1243dSDimitry Andric         RegClassOrBank.dyn_cast<const TargetRegisterClass *>();
991bdd1243dSDimitry Andric     if (!RC) {
992bdd1243dSDimitry Andric       const RegisterBank &RB = *RegClassOrBank.get<const RegisterBank *>();
993bdd1243dSDimitry Andric       RC = getRegClassForTypeOnBank(Ty, RB);
994bdd1243dSDimitry Andric       if (!RC) {
995bdd1243dSDimitry Andric         LLVM_DEBUG(
996bdd1243dSDimitry Andric             dbgs() << "Warning: DBG_VALUE operand has unexpected size/bank\n");
997bdd1243dSDimitry Andric         break;
998bdd1243dSDimitry Andric       }
999bdd1243dSDimitry Andric     }
1000bdd1243dSDimitry Andric     RBI.constrainGenericRegister(Reg, *RC, MRI);
1001bdd1243dSDimitry Andric   }
1002bdd1243dSDimitry Andric 
1003bdd1243dSDimitry Andric   return true;
1004bdd1243dSDimitry Andric }
1005bdd1243dSDimitry Andric 
selectCopy(MachineInstr & I,const TargetInstrInfo & TII,MachineRegisterInfo & MRI,const TargetRegisterInfo & TRI,const RegisterBankInfo & RBI)10065ffd83dbSDimitry Andric static bool selectCopy(MachineInstr &I, const TargetInstrInfo &TII,
10075ffd83dbSDimitry Andric                        MachineRegisterInfo &MRI, const TargetRegisterInfo &TRI,
10085ffd83dbSDimitry Andric                        const RegisterBankInfo &RBI) {
10095ffd83dbSDimitry Andric   Register DstReg = I.getOperand(0).getReg();
10105ffd83dbSDimitry Andric   Register SrcReg = I.getOperand(1).getReg();
10115ffd83dbSDimitry Andric   const RegisterBank &DstRegBank = *RBI.getRegBank(DstReg, MRI, TRI);
10125ffd83dbSDimitry Andric   const RegisterBank &SrcRegBank = *RBI.getRegBank(SrcReg, MRI, TRI);
10135ffd83dbSDimitry Andric 
10145ffd83dbSDimitry Andric   // Find the correct register classes for the source and destination registers.
10155ffd83dbSDimitry Andric   const TargetRegisterClass *SrcRC;
10165ffd83dbSDimitry Andric   const TargetRegisterClass *DstRC;
10175ffd83dbSDimitry Andric   std::tie(SrcRC, DstRC) = getRegClassesForCopy(I, TII, MRI, TRI, RBI);
10185ffd83dbSDimitry Andric 
10195ffd83dbSDimitry Andric   if (!DstRC) {
10205ffd83dbSDimitry Andric     LLVM_DEBUG(dbgs() << "Unexpected dest size "
10215ffd83dbSDimitry Andric                       << RBI.getSizeInBits(DstReg, MRI, TRI) << '\n');
10225ffd83dbSDimitry Andric     return false;
10235ffd83dbSDimitry Andric   }
10245ffd83dbSDimitry Andric 
10255ffd83dbSDimitry Andric   // Is this a copy? If so, then we may need to insert a subregister copy.
10265ffd83dbSDimitry Andric   if (I.isCopy()) {
10275ffd83dbSDimitry Andric     // Yes. Check if there's anything to fix up.
10285ffd83dbSDimitry Andric     if (!SrcRC) {
10295ffd83dbSDimitry Andric       LLVM_DEBUG(dbgs() << "Couldn't determine source register class\n");
10305ffd83dbSDimitry Andric       return false;
10315ffd83dbSDimitry Andric     }
10325ffd83dbSDimitry Andric 
1033*0fca6ea1SDimitry Andric     const TypeSize SrcSize = TRI.getRegSizeInBits(*SrcRC);
1034*0fca6ea1SDimitry Andric     const TypeSize DstSize = TRI.getRegSizeInBits(*DstRC);
10355ffd83dbSDimitry Andric     unsigned SubReg;
10365ffd83dbSDimitry Andric 
10375ffd83dbSDimitry Andric     // If the source bank doesn't support a subregister copy small enough,
10385ffd83dbSDimitry Andric     // then we first need to copy to the destination bank.
10395ffd83dbSDimitry Andric     if (getMinSizeForRegBank(SrcRegBank) > DstSize) {
10405ffd83dbSDimitry Andric       const TargetRegisterClass *DstTempRC =
10415ffd83dbSDimitry Andric           getMinClassForRegBank(DstRegBank, SrcSize, /* GetAllRegSet */ true);
10425ffd83dbSDimitry Andric       getSubRegForClass(DstRC, TRI, SubReg);
10435ffd83dbSDimitry Andric 
10445ffd83dbSDimitry Andric       MachineIRBuilder MIB(I);
10455ffd83dbSDimitry Andric       auto Copy = MIB.buildCopy({DstTempRC}, {SrcReg});
10465ffd83dbSDimitry Andric       copySubReg(I, MRI, RBI, Copy.getReg(0), DstRC, SubReg);
10475ffd83dbSDimitry Andric     } else if (SrcSize > DstSize) {
10485ffd83dbSDimitry Andric       // If the source register is bigger than the destination we need to
10495ffd83dbSDimitry Andric       // perform a subregister copy.
10505ffd83dbSDimitry Andric       const TargetRegisterClass *SubRegRC =
10515ffd83dbSDimitry Andric           getMinClassForRegBank(SrcRegBank, DstSize, /* GetAllRegSet */ true);
10525ffd83dbSDimitry Andric       getSubRegForClass(SubRegRC, TRI, SubReg);
10535ffd83dbSDimitry Andric       copySubReg(I, MRI, RBI, SrcReg, DstRC, SubReg);
10545ffd83dbSDimitry Andric     } else if (DstSize > SrcSize) {
10555ffd83dbSDimitry Andric       // If the destination register is bigger than the source we need to do
10565ffd83dbSDimitry Andric       // a promotion using SUBREG_TO_REG.
10575ffd83dbSDimitry Andric       const TargetRegisterClass *PromotionRC =
10585ffd83dbSDimitry Andric           getMinClassForRegBank(SrcRegBank, DstSize, /* GetAllRegSet */ true);
10595ffd83dbSDimitry Andric       getSubRegForClass(SrcRC, TRI, SubReg);
10605ffd83dbSDimitry Andric 
10615ffd83dbSDimitry Andric       Register PromoteReg = MRI.createVirtualRegister(PromotionRC);
10625ffd83dbSDimitry Andric       BuildMI(*I.getParent(), I, I.getDebugLoc(),
10635ffd83dbSDimitry Andric               TII.get(AArch64::SUBREG_TO_REG), PromoteReg)
10645ffd83dbSDimitry Andric           .addImm(0)
10655ffd83dbSDimitry Andric           .addUse(SrcReg)
10665ffd83dbSDimitry Andric           .addImm(SubReg);
10675ffd83dbSDimitry Andric       MachineOperand &RegOp = I.getOperand(1);
10685ffd83dbSDimitry Andric       RegOp.setReg(PromoteReg);
10695ffd83dbSDimitry Andric     }
10705ffd83dbSDimitry Andric 
10715ffd83dbSDimitry Andric     // If the destination is a physical register, then there's nothing to
10725ffd83dbSDimitry Andric     // change, so we're done.
1073bdd1243dSDimitry Andric     if (DstReg.isPhysical())
107481ad6265SDimitry Andric       return true;
10755ffd83dbSDimitry Andric   }
10765ffd83dbSDimitry Andric 
10775ffd83dbSDimitry Andric   // No need to constrain SrcReg. It will get constrained when we hit another
10785ffd83dbSDimitry Andric   // of its use or its defs. Copies do not have constraints.
10795ffd83dbSDimitry Andric   if (!RBI.constrainGenericRegister(DstReg, *DstRC, MRI)) {
10805ffd83dbSDimitry Andric     LLVM_DEBUG(dbgs() << "Failed to constrain " << TII.getName(I.getOpcode())
10815ffd83dbSDimitry Andric                       << " operand\n");
10825ffd83dbSDimitry Andric     return false;
10835ffd83dbSDimitry Andric   }
1084fe6060f1SDimitry Andric 
1085fe6060f1SDimitry Andric   // If this a GPR ZEXT that we want to just reduce down into a copy.
1086fe6060f1SDimitry Andric   // The sizes will be mismatched with the source < 32b but that's ok.
1087fe6060f1SDimitry Andric   if (I.getOpcode() == TargetOpcode::G_ZEXT) {
1088fe6060f1SDimitry Andric     I.setDesc(TII.get(AArch64::COPY));
1089fe6060f1SDimitry Andric     assert(SrcRegBank.getID() == AArch64::GPRRegBankID);
1090fe6060f1SDimitry Andric     return selectCopy(I, TII, MRI, TRI, RBI);
1091fe6060f1SDimitry Andric   }
1092fe6060f1SDimitry Andric 
10935ffd83dbSDimitry Andric   I.setDesc(TII.get(AArch64::COPY));
109481ad6265SDimitry Andric   return true;
10955ffd83dbSDimitry Andric }
10965ffd83dbSDimitry Andric 
selectFPConvOpc(unsigned GenericOpc,LLT DstTy,LLT SrcTy)10975ffd83dbSDimitry Andric static unsigned selectFPConvOpc(unsigned GenericOpc, LLT DstTy, LLT SrcTy) {
10985ffd83dbSDimitry Andric   if (!DstTy.isScalar() || !SrcTy.isScalar())
10995ffd83dbSDimitry Andric     return GenericOpc;
11005ffd83dbSDimitry Andric 
11015ffd83dbSDimitry Andric   const unsigned DstSize = DstTy.getSizeInBits();
11025ffd83dbSDimitry Andric   const unsigned SrcSize = SrcTy.getSizeInBits();
11035ffd83dbSDimitry Andric 
11045ffd83dbSDimitry Andric   switch (DstSize) {
11055ffd83dbSDimitry Andric   case 32:
11065ffd83dbSDimitry Andric     switch (SrcSize) {
11075ffd83dbSDimitry Andric     case 32:
11085ffd83dbSDimitry Andric       switch (GenericOpc) {
11095ffd83dbSDimitry Andric       case TargetOpcode::G_SITOFP:
11105ffd83dbSDimitry Andric         return AArch64::SCVTFUWSri;
11115ffd83dbSDimitry Andric       case TargetOpcode::G_UITOFP:
11125ffd83dbSDimitry Andric         return AArch64::UCVTFUWSri;
11135ffd83dbSDimitry Andric       case TargetOpcode::G_FPTOSI:
11145ffd83dbSDimitry Andric         return AArch64::FCVTZSUWSr;
11155ffd83dbSDimitry Andric       case TargetOpcode::G_FPTOUI:
11165ffd83dbSDimitry Andric         return AArch64::FCVTZUUWSr;
11175ffd83dbSDimitry Andric       default:
11185ffd83dbSDimitry Andric         return GenericOpc;
11195ffd83dbSDimitry Andric       }
11205ffd83dbSDimitry Andric     case 64:
11215ffd83dbSDimitry Andric       switch (GenericOpc) {
11225ffd83dbSDimitry Andric       case TargetOpcode::G_SITOFP:
11235ffd83dbSDimitry Andric         return AArch64::SCVTFUXSri;
11245ffd83dbSDimitry Andric       case TargetOpcode::G_UITOFP:
11255ffd83dbSDimitry Andric         return AArch64::UCVTFUXSri;
11265ffd83dbSDimitry Andric       case TargetOpcode::G_FPTOSI:
11275ffd83dbSDimitry Andric         return AArch64::FCVTZSUWDr;
11285ffd83dbSDimitry Andric       case TargetOpcode::G_FPTOUI:
11295ffd83dbSDimitry Andric         return AArch64::FCVTZUUWDr;
11305ffd83dbSDimitry Andric       default:
11315ffd83dbSDimitry Andric         return GenericOpc;
11325ffd83dbSDimitry Andric       }
11335ffd83dbSDimitry Andric     default:
11345ffd83dbSDimitry Andric       return GenericOpc;
11355ffd83dbSDimitry Andric     }
11365ffd83dbSDimitry Andric   case 64:
11375ffd83dbSDimitry Andric     switch (SrcSize) {
11385ffd83dbSDimitry Andric     case 32:
11395ffd83dbSDimitry Andric       switch (GenericOpc) {
11405ffd83dbSDimitry Andric       case TargetOpcode::G_SITOFP:
11415ffd83dbSDimitry Andric         return AArch64::SCVTFUWDri;
11425ffd83dbSDimitry Andric       case TargetOpcode::G_UITOFP:
11435ffd83dbSDimitry Andric         return AArch64::UCVTFUWDri;
11445ffd83dbSDimitry Andric       case TargetOpcode::G_FPTOSI:
11455ffd83dbSDimitry Andric         return AArch64::FCVTZSUXSr;
11465ffd83dbSDimitry Andric       case TargetOpcode::G_FPTOUI:
11475ffd83dbSDimitry Andric         return AArch64::FCVTZUUXSr;
11485ffd83dbSDimitry Andric       default:
11495ffd83dbSDimitry Andric         return GenericOpc;
11505ffd83dbSDimitry Andric       }
11515ffd83dbSDimitry Andric     case 64:
11525ffd83dbSDimitry Andric       switch (GenericOpc) {
11535ffd83dbSDimitry Andric       case TargetOpcode::G_SITOFP:
11545ffd83dbSDimitry Andric         return AArch64::SCVTFUXDri;
11555ffd83dbSDimitry Andric       case TargetOpcode::G_UITOFP:
11565ffd83dbSDimitry Andric         return AArch64::UCVTFUXDri;
11575ffd83dbSDimitry Andric       case TargetOpcode::G_FPTOSI:
11585ffd83dbSDimitry Andric         return AArch64::FCVTZSUXDr;
11595ffd83dbSDimitry Andric       case TargetOpcode::G_FPTOUI:
11605ffd83dbSDimitry Andric         return AArch64::FCVTZUUXDr;
11615ffd83dbSDimitry Andric       default:
11625ffd83dbSDimitry Andric         return GenericOpc;
11635ffd83dbSDimitry Andric       }
11645ffd83dbSDimitry Andric     default:
11655ffd83dbSDimitry Andric       return GenericOpc;
11665ffd83dbSDimitry Andric     }
11675ffd83dbSDimitry Andric   default:
11685ffd83dbSDimitry Andric     return GenericOpc;
11695ffd83dbSDimitry Andric   };
11705ffd83dbSDimitry Andric   return GenericOpc;
11715ffd83dbSDimitry Andric }
11725ffd83dbSDimitry Andric 
1173e8d8bef9SDimitry Andric MachineInstr *
emitSelect(Register Dst,Register True,Register False,AArch64CC::CondCode CC,MachineIRBuilder & MIB) const1174e8d8bef9SDimitry Andric AArch64InstructionSelector::emitSelect(Register Dst, Register True,
1175e8d8bef9SDimitry Andric                                        Register False, AArch64CC::CondCode CC,
1176e8d8bef9SDimitry Andric                                        MachineIRBuilder &MIB) const {
1177e8d8bef9SDimitry Andric   MachineRegisterInfo &MRI = *MIB.getMRI();
1178e8d8bef9SDimitry Andric   assert(RBI.getRegBank(False, MRI, TRI)->getID() ==
1179e8d8bef9SDimitry Andric              RBI.getRegBank(True, MRI, TRI)->getID() &&
1180e8d8bef9SDimitry Andric          "Expected both select operands to have the same regbank?");
1181e8d8bef9SDimitry Andric   LLT Ty = MRI.getType(True);
1182e8d8bef9SDimitry Andric   if (Ty.isVector())
1183e8d8bef9SDimitry Andric     return nullptr;
1184e8d8bef9SDimitry Andric   const unsigned Size = Ty.getSizeInBits();
1185e8d8bef9SDimitry Andric   assert((Size == 32 || Size == 64) &&
1186e8d8bef9SDimitry Andric          "Expected 32 bit or 64 bit select only?");
1187e8d8bef9SDimitry Andric   const bool Is32Bit = Size == 32;
1188e8d8bef9SDimitry Andric   if (RBI.getRegBank(True, MRI, TRI)->getID() != AArch64::GPRRegBankID) {
1189e8d8bef9SDimitry Andric     unsigned Opc = Is32Bit ? AArch64::FCSELSrrr : AArch64::FCSELDrrr;
1190e8d8bef9SDimitry Andric     auto FCSel = MIB.buildInstr(Opc, {Dst}, {True, False}).addImm(CC);
1191e8d8bef9SDimitry Andric     constrainSelectedInstRegOperands(*FCSel, TII, TRI, RBI);
1192e8d8bef9SDimitry Andric     return &*FCSel;
11935ffd83dbSDimitry Andric   }
11945ffd83dbSDimitry Andric 
1195e8d8bef9SDimitry Andric   // By default, we'll try and emit a CSEL.
1196e8d8bef9SDimitry Andric   unsigned Opc = Is32Bit ? AArch64::CSELWr : AArch64::CSELXr;
1197e8d8bef9SDimitry Andric   bool Optimized = false;
1198e8d8bef9SDimitry Andric   auto TryFoldBinOpIntoSelect = [&Opc, Is32Bit, &CC, &MRI,
1199e8d8bef9SDimitry Andric                                  &Optimized](Register &Reg, Register &OtherReg,
1200e8d8bef9SDimitry Andric                                              bool Invert) {
1201e8d8bef9SDimitry Andric     if (Optimized)
12025ffd83dbSDimitry Andric       return false;
1203e8d8bef9SDimitry Andric 
1204e8d8bef9SDimitry Andric     // Attempt to fold:
1205e8d8bef9SDimitry Andric     //
1206e8d8bef9SDimitry Andric     // %sub = G_SUB 0, %x
1207e8d8bef9SDimitry Andric     // %select = G_SELECT cc, %reg, %sub
1208e8d8bef9SDimitry Andric     //
1209e8d8bef9SDimitry Andric     // Into:
1210e8d8bef9SDimitry Andric     // %select = CSNEG %reg, %x, cc
1211e8d8bef9SDimitry Andric     Register MatchReg;
1212e8d8bef9SDimitry Andric     if (mi_match(Reg, MRI, m_Neg(m_Reg(MatchReg)))) {
1213e8d8bef9SDimitry Andric       Opc = Is32Bit ? AArch64::CSNEGWr : AArch64::CSNEGXr;
1214e8d8bef9SDimitry Andric       Reg = MatchReg;
1215e8d8bef9SDimitry Andric       if (Invert) {
1216e8d8bef9SDimitry Andric         CC = AArch64CC::getInvertedCondCode(CC);
1217e8d8bef9SDimitry Andric         std::swap(Reg, OtherReg);
1218e8d8bef9SDimitry Andric       }
12195ffd83dbSDimitry Andric       return true;
12205ffd83dbSDimitry Andric     }
1221e8d8bef9SDimitry Andric 
1222e8d8bef9SDimitry Andric     // Attempt to fold:
1223e8d8bef9SDimitry Andric     //
1224e8d8bef9SDimitry Andric     // %xor = G_XOR %x, -1
1225e8d8bef9SDimitry Andric     // %select = G_SELECT cc, %reg, %xor
1226e8d8bef9SDimitry Andric     //
1227e8d8bef9SDimitry Andric     // Into:
1228e8d8bef9SDimitry Andric     // %select = CSINV %reg, %x, cc
1229e8d8bef9SDimitry Andric     if (mi_match(Reg, MRI, m_Not(m_Reg(MatchReg)))) {
1230e8d8bef9SDimitry Andric       Opc = Is32Bit ? AArch64::CSINVWr : AArch64::CSINVXr;
1231e8d8bef9SDimitry Andric       Reg = MatchReg;
1232e8d8bef9SDimitry Andric       if (Invert) {
1233e8d8bef9SDimitry Andric         CC = AArch64CC::getInvertedCondCode(CC);
1234e8d8bef9SDimitry Andric         std::swap(Reg, OtherReg);
1235e8d8bef9SDimitry Andric       }
1236e8d8bef9SDimitry Andric       return true;
1237e8d8bef9SDimitry Andric     }
1238e8d8bef9SDimitry Andric 
1239e8d8bef9SDimitry Andric     // Attempt to fold:
1240e8d8bef9SDimitry Andric     //
1241e8d8bef9SDimitry Andric     // %add = G_ADD %x, 1
1242e8d8bef9SDimitry Andric     // %select = G_SELECT cc, %reg, %add
1243e8d8bef9SDimitry Andric     //
1244e8d8bef9SDimitry Andric     // Into:
1245e8d8bef9SDimitry Andric     // %select = CSINC %reg, %x, cc
1246fe6060f1SDimitry Andric     if (mi_match(Reg, MRI,
1247fe6060f1SDimitry Andric                  m_any_of(m_GAdd(m_Reg(MatchReg), m_SpecificICst(1)),
1248fe6060f1SDimitry Andric                           m_GPtrAdd(m_Reg(MatchReg), m_SpecificICst(1))))) {
1249e8d8bef9SDimitry Andric       Opc = Is32Bit ? AArch64::CSINCWr : AArch64::CSINCXr;
1250e8d8bef9SDimitry Andric       Reg = MatchReg;
1251e8d8bef9SDimitry Andric       if (Invert) {
1252e8d8bef9SDimitry Andric         CC = AArch64CC::getInvertedCondCode(CC);
1253e8d8bef9SDimitry Andric         std::swap(Reg, OtherReg);
1254e8d8bef9SDimitry Andric       }
1255e8d8bef9SDimitry Andric       return true;
1256e8d8bef9SDimitry Andric     }
1257e8d8bef9SDimitry Andric 
1258e8d8bef9SDimitry Andric     return false;
1259e8d8bef9SDimitry Andric   };
1260e8d8bef9SDimitry Andric 
1261e8d8bef9SDimitry Andric   // Helper lambda which tries to use CSINC/CSINV for the instruction when its
1262e8d8bef9SDimitry Andric   // true/false values are constants.
1263e8d8bef9SDimitry Andric   // FIXME: All of these patterns already exist in tablegen. We should be
1264e8d8bef9SDimitry Andric   // able to import these.
1265e8d8bef9SDimitry Andric   auto TryOptSelectCst = [&Opc, &True, &False, &CC, Is32Bit, &MRI,
1266e8d8bef9SDimitry Andric                           &Optimized]() {
1267e8d8bef9SDimitry Andric     if (Optimized)
1268e8d8bef9SDimitry Andric       return false;
1269349cc55cSDimitry Andric     auto TrueCst = getIConstantVRegValWithLookThrough(True, MRI);
1270349cc55cSDimitry Andric     auto FalseCst = getIConstantVRegValWithLookThrough(False, MRI);
1271e8d8bef9SDimitry Andric     if (!TrueCst && !FalseCst)
1272e8d8bef9SDimitry Andric       return false;
1273e8d8bef9SDimitry Andric 
1274e8d8bef9SDimitry Andric     Register ZReg = Is32Bit ? AArch64::WZR : AArch64::XZR;
1275e8d8bef9SDimitry Andric     if (TrueCst && FalseCst) {
1276e8d8bef9SDimitry Andric       int64_t T = TrueCst->Value.getSExtValue();
1277e8d8bef9SDimitry Andric       int64_t F = FalseCst->Value.getSExtValue();
1278e8d8bef9SDimitry Andric 
1279e8d8bef9SDimitry Andric       if (T == 0 && F == 1) {
1280e8d8bef9SDimitry Andric         // G_SELECT cc, 0, 1 -> CSINC zreg, zreg, cc
1281e8d8bef9SDimitry Andric         Opc = Is32Bit ? AArch64::CSINCWr : AArch64::CSINCXr;
1282e8d8bef9SDimitry Andric         True = ZReg;
1283e8d8bef9SDimitry Andric         False = ZReg;
1284e8d8bef9SDimitry Andric         return true;
1285e8d8bef9SDimitry Andric       }
1286e8d8bef9SDimitry Andric 
1287e8d8bef9SDimitry Andric       if (T == 0 && F == -1) {
1288e8d8bef9SDimitry Andric         // G_SELECT cc 0, -1 -> CSINV zreg, zreg cc
1289e8d8bef9SDimitry Andric         Opc = Is32Bit ? AArch64::CSINVWr : AArch64::CSINVXr;
1290e8d8bef9SDimitry Andric         True = ZReg;
1291e8d8bef9SDimitry Andric         False = ZReg;
1292e8d8bef9SDimitry Andric         return true;
1293e8d8bef9SDimitry Andric       }
1294e8d8bef9SDimitry Andric     }
1295e8d8bef9SDimitry Andric 
1296e8d8bef9SDimitry Andric     if (TrueCst) {
1297e8d8bef9SDimitry Andric       int64_t T = TrueCst->Value.getSExtValue();
1298e8d8bef9SDimitry Andric       if (T == 1) {
1299e8d8bef9SDimitry Andric         // G_SELECT cc, 1, f -> CSINC f, zreg, inv_cc
1300e8d8bef9SDimitry Andric         Opc = Is32Bit ? AArch64::CSINCWr : AArch64::CSINCXr;
1301e8d8bef9SDimitry Andric         True = False;
1302e8d8bef9SDimitry Andric         False = ZReg;
1303e8d8bef9SDimitry Andric         CC = AArch64CC::getInvertedCondCode(CC);
1304e8d8bef9SDimitry Andric         return true;
1305e8d8bef9SDimitry Andric       }
1306e8d8bef9SDimitry Andric 
1307e8d8bef9SDimitry Andric       if (T == -1) {
1308e8d8bef9SDimitry Andric         // G_SELECT cc, -1, f -> CSINV f, zreg, inv_cc
1309e8d8bef9SDimitry Andric         Opc = Is32Bit ? AArch64::CSINVWr : AArch64::CSINVXr;
1310e8d8bef9SDimitry Andric         True = False;
1311e8d8bef9SDimitry Andric         False = ZReg;
1312e8d8bef9SDimitry Andric         CC = AArch64CC::getInvertedCondCode(CC);
1313e8d8bef9SDimitry Andric         return true;
1314e8d8bef9SDimitry Andric       }
1315e8d8bef9SDimitry Andric     }
1316e8d8bef9SDimitry Andric 
1317e8d8bef9SDimitry Andric     if (FalseCst) {
1318e8d8bef9SDimitry Andric       int64_t F = FalseCst->Value.getSExtValue();
1319e8d8bef9SDimitry Andric       if (F == 1) {
1320e8d8bef9SDimitry Andric         // G_SELECT cc, t, 1 -> CSINC t, zreg, cc
1321e8d8bef9SDimitry Andric         Opc = Is32Bit ? AArch64::CSINCWr : AArch64::CSINCXr;
1322e8d8bef9SDimitry Andric         False = ZReg;
1323e8d8bef9SDimitry Andric         return true;
1324e8d8bef9SDimitry Andric       }
1325e8d8bef9SDimitry Andric 
1326e8d8bef9SDimitry Andric       if (F == -1) {
1327e8d8bef9SDimitry Andric         // G_SELECT cc, t, -1 -> CSINC t, zreg, cc
1328e8d8bef9SDimitry Andric         Opc = Is32Bit ? AArch64::CSINVWr : AArch64::CSINVXr;
1329e8d8bef9SDimitry Andric         False = ZReg;
1330e8d8bef9SDimitry Andric         return true;
1331e8d8bef9SDimitry Andric       }
1332e8d8bef9SDimitry Andric     }
1333e8d8bef9SDimitry Andric     return false;
1334e8d8bef9SDimitry Andric   };
1335e8d8bef9SDimitry Andric 
1336e8d8bef9SDimitry Andric   Optimized |= TryFoldBinOpIntoSelect(False, True, /*Invert = */ false);
1337e8d8bef9SDimitry Andric   Optimized |= TryFoldBinOpIntoSelect(True, False, /*Invert = */ true);
1338e8d8bef9SDimitry Andric   Optimized |= TryOptSelectCst();
1339e8d8bef9SDimitry Andric   auto SelectInst = MIB.buildInstr(Opc, {Dst}, {True, False}).addImm(CC);
1340e8d8bef9SDimitry Andric   constrainSelectedInstRegOperands(*SelectInst, TII, TRI, RBI);
1341e8d8bef9SDimitry Andric   return &*SelectInst;
13425ffd83dbSDimitry Andric }
13435ffd83dbSDimitry Andric 
changeICMPPredToAArch64CC(CmpInst::Predicate P)13445ffd83dbSDimitry Andric static AArch64CC::CondCode changeICMPPredToAArch64CC(CmpInst::Predicate P) {
13455ffd83dbSDimitry Andric   switch (P) {
13465ffd83dbSDimitry Andric   default:
13475ffd83dbSDimitry Andric     llvm_unreachable("Unknown condition code!");
13485ffd83dbSDimitry Andric   case CmpInst::ICMP_NE:
13495ffd83dbSDimitry Andric     return AArch64CC::NE;
13505ffd83dbSDimitry Andric   case CmpInst::ICMP_EQ:
13515ffd83dbSDimitry Andric     return AArch64CC::EQ;
13525ffd83dbSDimitry Andric   case CmpInst::ICMP_SGT:
13535ffd83dbSDimitry Andric     return AArch64CC::GT;
13545ffd83dbSDimitry Andric   case CmpInst::ICMP_SGE:
13555ffd83dbSDimitry Andric     return AArch64CC::GE;
13565ffd83dbSDimitry Andric   case CmpInst::ICMP_SLT:
13575ffd83dbSDimitry Andric     return AArch64CC::LT;
13585ffd83dbSDimitry Andric   case CmpInst::ICMP_SLE:
13595ffd83dbSDimitry Andric     return AArch64CC::LE;
13605ffd83dbSDimitry Andric   case CmpInst::ICMP_UGT:
13615ffd83dbSDimitry Andric     return AArch64CC::HI;
13625ffd83dbSDimitry Andric   case CmpInst::ICMP_UGE:
13635ffd83dbSDimitry Andric     return AArch64CC::HS;
13645ffd83dbSDimitry Andric   case CmpInst::ICMP_ULT:
13655ffd83dbSDimitry Andric     return AArch64CC::LO;
13665ffd83dbSDimitry Andric   case CmpInst::ICMP_ULE:
13675ffd83dbSDimitry Andric     return AArch64CC::LS;
13685ffd83dbSDimitry Andric   }
13695ffd83dbSDimitry Andric }
13705ffd83dbSDimitry Andric 
137181ad6265SDimitry Andric /// changeFPCCToORAArch64CC - Convert an IR fp condition code to an AArch64 CC.
changeFPCCToORAArch64CC(CmpInst::Predicate CC,AArch64CC::CondCode & CondCode,AArch64CC::CondCode & CondCode2)137281ad6265SDimitry Andric static void changeFPCCToORAArch64CC(CmpInst::Predicate CC,
137381ad6265SDimitry Andric                                     AArch64CC::CondCode &CondCode,
137481ad6265SDimitry Andric                                     AArch64CC::CondCode &CondCode2) {
137581ad6265SDimitry Andric   CondCode2 = AArch64CC::AL;
137681ad6265SDimitry Andric   switch (CC) {
137781ad6265SDimitry Andric   default:
137881ad6265SDimitry Andric     llvm_unreachable("Unknown FP condition!");
137981ad6265SDimitry Andric   case CmpInst::FCMP_OEQ:
138081ad6265SDimitry Andric     CondCode = AArch64CC::EQ;
138181ad6265SDimitry Andric     break;
138281ad6265SDimitry Andric   case CmpInst::FCMP_OGT:
138381ad6265SDimitry Andric     CondCode = AArch64CC::GT;
138481ad6265SDimitry Andric     break;
138581ad6265SDimitry Andric   case CmpInst::FCMP_OGE:
138681ad6265SDimitry Andric     CondCode = AArch64CC::GE;
138781ad6265SDimitry Andric     break;
138881ad6265SDimitry Andric   case CmpInst::FCMP_OLT:
138981ad6265SDimitry Andric     CondCode = AArch64CC::MI;
139081ad6265SDimitry Andric     break;
139181ad6265SDimitry Andric   case CmpInst::FCMP_OLE:
139281ad6265SDimitry Andric     CondCode = AArch64CC::LS;
139381ad6265SDimitry Andric     break;
139481ad6265SDimitry Andric   case CmpInst::FCMP_ONE:
139581ad6265SDimitry Andric     CondCode = AArch64CC::MI;
139681ad6265SDimitry Andric     CondCode2 = AArch64CC::GT;
139781ad6265SDimitry Andric     break;
139881ad6265SDimitry Andric   case CmpInst::FCMP_ORD:
139981ad6265SDimitry Andric     CondCode = AArch64CC::VC;
140081ad6265SDimitry Andric     break;
140181ad6265SDimitry Andric   case CmpInst::FCMP_UNO:
140281ad6265SDimitry Andric     CondCode = AArch64CC::VS;
140381ad6265SDimitry Andric     break;
140481ad6265SDimitry Andric   case CmpInst::FCMP_UEQ:
140581ad6265SDimitry Andric     CondCode = AArch64CC::EQ;
140681ad6265SDimitry Andric     CondCode2 = AArch64CC::VS;
140781ad6265SDimitry Andric     break;
140881ad6265SDimitry Andric   case CmpInst::FCMP_UGT:
140981ad6265SDimitry Andric     CondCode = AArch64CC::HI;
141081ad6265SDimitry Andric     break;
141181ad6265SDimitry Andric   case CmpInst::FCMP_UGE:
141281ad6265SDimitry Andric     CondCode = AArch64CC::PL;
141381ad6265SDimitry Andric     break;
141481ad6265SDimitry Andric   case CmpInst::FCMP_ULT:
141581ad6265SDimitry Andric     CondCode = AArch64CC::LT;
141681ad6265SDimitry Andric     break;
141781ad6265SDimitry Andric   case CmpInst::FCMP_ULE:
141881ad6265SDimitry Andric     CondCode = AArch64CC::LE;
141981ad6265SDimitry Andric     break;
142081ad6265SDimitry Andric   case CmpInst::FCMP_UNE:
142181ad6265SDimitry Andric     CondCode = AArch64CC::NE;
142281ad6265SDimitry Andric     break;
142381ad6265SDimitry Andric   }
142481ad6265SDimitry Andric }
142581ad6265SDimitry Andric 
142681ad6265SDimitry Andric /// Convert an IR fp condition code to an AArch64 CC.
142781ad6265SDimitry Andric /// This differs from changeFPCCToAArch64CC in that it returns cond codes that
142881ad6265SDimitry Andric /// should be AND'ed instead of OR'ed.
changeFPCCToANDAArch64CC(CmpInst::Predicate CC,AArch64CC::CondCode & CondCode,AArch64CC::CondCode & CondCode2)142981ad6265SDimitry Andric static void changeFPCCToANDAArch64CC(CmpInst::Predicate CC,
143081ad6265SDimitry Andric                                      AArch64CC::CondCode &CondCode,
143181ad6265SDimitry Andric                                      AArch64CC::CondCode &CondCode2) {
143281ad6265SDimitry Andric   CondCode2 = AArch64CC::AL;
143381ad6265SDimitry Andric   switch (CC) {
143481ad6265SDimitry Andric   default:
143581ad6265SDimitry Andric     changeFPCCToORAArch64CC(CC, CondCode, CondCode2);
143681ad6265SDimitry Andric     assert(CondCode2 == AArch64CC::AL);
143781ad6265SDimitry Andric     break;
143881ad6265SDimitry Andric   case CmpInst::FCMP_ONE:
143981ad6265SDimitry Andric     // (a one b)
144081ad6265SDimitry Andric     // == ((a olt b) || (a ogt b))
144181ad6265SDimitry Andric     // == ((a ord b) && (a une b))
144281ad6265SDimitry Andric     CondCode = AArch64CC::VC;
144381ad6265SDimitry Andric     CondCode2 = AArch64CC::NE;
144481ad6265SDimitry Andric     break;
144581ad6265SDimitry Andric   case CmpInst::FCMP_UEQ:
144681ad6265SDimitry Andric     // (a ueq b)
144781ad6265SDimitry Andric     // == ((a uno b) || (a oeq b))
144881ad6265SDimitry Andric     // == ((a ule b) && (a uge b))
144981ad6265SDimitry Andric     CondCode = AArch64CC::PL;
145081ad6265SDimitry Andric     CondCode2 = AArch64CC::LE;
145181ad6265SDimitry Andric     break;
145281ad6265SDimitry Andric   }
145381ad6265SDimitry Andric }
145481ad6265SDimitry Andric 
14555ffd83dbSDimitry Andric /// Return a register which can be used as a bit to test in a TB(N)Z.
getTestBitReg(Register Reg,uint64_t & Bit,bool & Invert,MachineRegisterInfo & MRI)14565ffd83dbSDimitry Andric static Register getTestBitReg(Register Reg, uint64_t &Bit, bool &Invert,
14575ffd83dbSDimitry Andric                               MachineRegisterInfo &MRI) {
14585ffd83dbSDimitry Andric   assert(Reg.isValid() && "Expected valid register!");
145928a41182SDimitry Andric   bool HasZext = false;
14605ffd83dbSDimitry Andric   while (MachineInstr *MI = getDefIgnoringCopies(Reg, MRI)) {
14615ffd83dbSDimitry Andric     unsigned Opc = MI->getOpcode();
14625ffd83dbSDimitry Andric 
14635ffd83dbSDimitry Andric     if (!MI->getOperand(0).isReg() ||
14645ffd83dbSDimitry Andric         !MRI.hasOneNonDBGUse(MI->getOperand(0).getReg()))
14655ffd83dbSDimitry Andric       break;
14665ffd83dbSDimitry Andric 
14675ffd83dbSDimitry Andric     // (tbz (any_ext x), b) -> (tbz x, b) if we don't use the extended bits.
14685ffd83dbSDimitry Andric     //
14695ffd83dbSDimitry Andric     // (tbz (trunc x), b) -> (tbz x, b) is always safe, because the bit number
14705ffd83dbSDimitry Andric     // on the truncated x is the same as the bit number on x.
14715ffd83dbSDimitry Andric     if (Opc == TargetOpcode::G_ANYEXT || Opc == TargetOpcode::G_ZEXT ||
14725ffd83dbSDimitry Andric         Opc == TargetOpcode::G_TRUNC) {
147328a41182SDimitry Andric       if (Opc == TargetOpcode::G_ZEXT)
147428a41182SDimitry Andric         HasZext = true;
147528a41182SDimitry Andric 
14765ffd83dbSDimitry Andric       Register NextReg = MI->getOperand(1).getReg();
14775ffd83dbSDimitry Andric       // Did we find something worth folding?
14785ffd83dbSDimitry Andric       if (!NextReg.isValid() || !MRI.hasOneNonDBGUse(NextReg))
14795ffd83dbSDimitry Andric         break;
14805ffd83dbSDimitry Andric 
14815ffd83dbSDimitry Andric       // NextReg is worth folding. Keep looking.
14825ffd83dbSDimitry Andric       Reg = NextReg;
14835ffd83dbSDimitry Andric       continue;
14845ffd83dbSDimitry Andric     }
14855ffd83dbSDimitry Andric 
14865ffd83dbSDimitry Andric     // Attempt to find a suitable operation with a constant on one side.
1487bdd1243dSDimitry Andric     std::optional<uint64_t> C;
14885ffd83dbSDimitry Andric     Register TestReg;
14895ffd83dbSDimitry Andric     switch (Opc) {
14905ffd83dbSDimitry Andric     default:
14915ffd83dbSDimitry Andric       break;
14925ffd83dbSDimitry Andric     case TargetOpcode::G_AND:
14935ffd83dbSDimitry Andric     case TargetOpcode::G_XOR: {
14945ffd83dbSDimitry Andric       TestReg = MI->getOperand(1).getReg();
14955ffd83dbSDimitry Andric       Register ConstantReg = MI->getOperand(2).getReg();
1496349cc55cSDimitry Andric       auto VRegAndVal = getIConstantVRegValWithLookThrough(ConstantReg, MRI);
14975ffd83dbSDimitry Andric       if (!VRegAndVal) {
14985ffd83dbSDimitry Andric         // AND commutes, check the other side for a constant.
14995ffd83dbSDimitry Andric         // FIXME: Can we canonicalize the constant so that it's always on the
15005ffd83dbSDimitry Andric         // same side at some point earlier?
15015ffd83dbSDimitry Andric         std::swap(ConstantReg, TestReg);
1502349cc55cSDimitry Andric         VRegAndVal = getIConstantVRegValWithLookThrough(ConstantReg, MRI);
15035ffd83dbSDimitry Andric       }
150428a41182SDimitry Andric       if (VRegAndVal) {
150528a41182SDimitry Andric         if (HasZext)
150628a41182SDimitry Andric           C = VRegAndVal->Value.getZExtValue();
150728a41182SDimitry Andric         else
1508e8d8bef9SDimitry Andric           C = VRegAndVal->Value.getSExtValue();
150928a41182SDimitry Andric       }
15105ffd83dbSDimitry Andric       break;
15115ffd83dbSDimitry Andric     }
15125ffd83dbSDimitry Andric     case TargetOpcode::G_ASHR:
15135ffd83dbSDimitry Andric     case TargetOpcode::G_LSHR:
15145ffd83dbSDimitry Andric     case TargetOpcode::G_SHL: {
15155ffd83dbSDimitry Andric       TestReg = MI->getOperand(1).getReg();
15165ffd83dbSDimitry Andric       auto VRegAndVal =
1517349cc55cSDimitry Andric           getIConstantVRegValWithLookThrough(MI->getOperand(2).getReg(), MRI);
15185ffd83dbSDimitry Andric       if (VRegAndVal)
1519e8d8bef9SDimitry Andric         C = VRegAndVal->Value.getSExtValue();
15205ffd83dbSDimitry Andric       break;
15215ffd83dbSDimitry Andric     }
15225ffd83dbSDimitry Andric     }
15235ffd83dbSDimitry Andric 
15245ffd83dbSDimitry Andric     // Didn't find a constant or viable register. Bail out of the loop.
15255ffd83dbSDimitry Andric     if (!C || !TestReg.isValid())
15265ffd83dbSDimitry Andric       break;
15275ffd83dbSDimitry Andric 
15285ffd83dbSDimitry Andric     // We found a suitable instruction with a constant. Check to see if we can
15295ffd83dbSDimitry Andric     // walk through the instruction.
15305ffd83dbSDimitry Andric     Register NextReg;
15315ffd83dbSDimitry Andric     unsigned TestRegSize = MRI.getType(TestReg).getSizeInBits();
15325ffd83dbSDimitry Andric     switch (Opc) {
15335ffd83dbSDimitry Andric     default:
15345ffd83dbSDimitry Andric       break;
15355ffd83dbSDimitry Andric     case TargetOpcode::G_AND:
15365ffd83dbSDimitry Andric       // (tbz (and x, m), b) -> (tbz x, b) when the b-th bit of m is set.
15375ffd83dbSDimitry Andric       if ((*C >> Bit) & 1)
15385ffd83dbSDimitry Andric         NextReg = TestReg;
15395ffd83dbSDimitry Andric       break;
15405ffd83dbSDimitry Andric     case TargetOpcode::G_SHL:
15415ffd83dbSDimitry Andric       // (tbz (shl x, c), b) -> (tbz x, b-c) when b-c is positive and fits in
15425ffd83dbSDimitry Andric       // the type of the register.
15435ffd83dbSDimitry Andric       if (*C <= Bit && (Bit - *C) < TestRegSize) {
15445ffd83dbSDimitry Andric         NextReg = TestReg;
15455ffd83dbSDimitry Andric         Bit = Bit - *C;
15465ffd83dbSDimitry Andric       }
15475ffd83dbSDimitry Andric       break;
15485ffd83dbSDimitry Andric     case TargetOpcode::G_ASHR:
15495ffd83dbSDimitry Andric       // (tbz (ashr x, c), b) -> (tbz x, b+c) or (tbz x, msb) if b+c is > # bits
15505ffd83dbSDimitry Andric       // in x
15515ffd83dbSDimitry Andric       NextReg = TestReg;
15525ffd83dbSDimitry Andric       Bit = Bit + *C;
15535ffd83dbSDimitry Andric       if (Bit >= TestRegSize)
15545ffd83dbSDimitry Andric         Bit = TestRegSize - 1;
15555ffd83dbSDimitry Andric       break;
15565ffd83dbSDimitry Andric     case TargetOpcode::G_LSHR:
15575ffd83dbSDimitry Andric       // (tbz (lshr x, c), b) -> (tbz x, b+c) when b + c is < # bits in x
15585ffd83dbSDimitry Andric       if ((Bit + *C) < TestRegSize) {
15595ffd83dbSDimitry Andric         NextReg = TestReg;
15605ffd83dbSDimitry Andric         Bit = Bit + *C;
15615ffd83dbSDimitry Andric       }
15625ffd83dbSDimitry Andric       break;
15635ffd83dbSDimitry Andric     case TargetOpcode::G_XOR:
15645ffd83dbSDimitry Andric       // We can walk through a G_XOR by inverting whether we use tbz/tbnz when
15655ffd83dbSDimitry Andric       // appropriate.
15665ffd83dbSDimitry Andric       //
15675ffd83dbSDimitry Andric       // e.g. If x' = xor x, c, and the b-th bit is set in c then
15685ffd83dbSDimitry Andric       //
15695ffd83dbSDimitry Andric       // tbz x', b -> tbnz x, b
15705ffd83dbSDimitry Andric       //
15715ffd83dbSDimitry Andric       // Because x' only has the b-th bit set if x does not.
15725ffd83dbSDimitry Andric       if ((*C >> Bit) & 1)
15735ffd83dbSDimitry Andric         Invert = !Invert;
15745ffd83dbSDimitry Andric       NextReg = TestReg;
15755ffd83dbSDimitry Andric       break;
15765ffd83dbSDimitry Andric     }
15775ffd83dbSDimitry Andric 
15785ffd83dbSDimitry Andric     // Check if we found anything worth folding.
15795ffd83dbSDimitry Andric     if (!NextReg.isValid())
15805ffd83dbSDimitry Andric       return Reg;
15815ffd83dbSDimitry Andric     Reg = NextReg;
15825ffd83dbSDimitry Andric   }
15835ffd83dbSDimitry Andric 
15845ffd83dbSDimitry Andric   return Reg;
15855ffd83dbSDimitry Andric }
15865ffd83dbSDimitry Andric 
emitTestBit(Register TestReg,uint64_t Bit,bool IsNegative,MachineBasicBlock * DstMBB,MachineIRBuilder & MIB) const15875ffd83dbSDimitry Andric MachineInstr *AArch64InstructionSelector::emitTestBit(
15885ffd83dbSDimitry Andric     Register TestReg, uint64_t Bit, bool IsNegative, MachineBasicBlock *DstMBB,
15895ffd83dbSDimitry Andric     MachineIRBuilder &MIB) const {
15905ffd83dbSDimitry Andric   assert(TestReg.isValid());
15915ffd83dbSDimitry Andric   assert(ProduceNonFlagSettingCondBr &&
15925ffd83dbSDimitry Andric          "Cannot emit TB(N)Z with speculation tracking!");
15935ffd83dbSDimitry Andric   MachineRegisterInfo &MRI = *MIB.getMRI();
15945ffd83dbSDimitry Andric 
15955ffd83dbSDimitry Andric   // Attempt to optimize the test bit by walking over instructions.
15965ffd83dbSDimitry Andric   TestReg = getTestBitReg(TestReg, Bit, IsNegative, MRI);
15975ffd83dbSDimitry Andric   LLT Ty = MRI.getType(TestReg);
15985ffd83dbSDimitry Andric   unsigned Size = Ty.getSizeInBits();
15995ffd83dbSDimitry Andric   assert(!Ty.isVector() && "Expected a scalar!");
16005ffd83dbSDimitry Andric   assert(Bit < 64 && "Bit is too large!");
16015ffd83dbSDimitry Andric 
16025ffd83dbSDimitry Andric   // When the test register is a 64-bit register, we have to narrow to make
16035ffd83dbSDimitry Andric   // TBNZW work.
16045ffd83dbSDimitry Andric   bool UseWReg = Bit < 32;
16055ffd83dbSDimitry Andric   unsigned NecessarySize = UseWReg ? 32 : 64;
1606eaeb601bSDimitry Andric   if (Size != NecessarySize)
1607eaeb601bSDimitry Andric     TestReg = moveScalarRegClass(
1608eaeb601bSDimitry Andric         TestReg, UseWReg ? AArch64::GPR32RegClass : AArch64::GPR64RegClass,
1609eaeb601bSDimitry Andric         MIB);
16105ffd83dbSDimitry Andric 
16115ffd83dbSDimitry Andric   static const unsigned OpcTable[2][2] = {{AArch64::TBZX, AArch64::TBNZX},
16125ffd83dbSDimitry Andric                                           {AArch64::TBZW, AArch64::TBNZW}};
16135ffd83dbSDimitry Andric   unsigned Opc = OpcTable[UseWReg][IsNegative];
16145ffd83dbSDimitry Andric   auto TestBitMI =
16155ffd83dbSDimitry Andric       MIB.buildInstr(Opc).addReg(TestReg).addImm(Bit).addMBB(DstMBB);
16165ffd83dbSDimitry Andric   constrainSelectedInstRegOperands(*TestBitMI, TII, TRI, RBI);
16175ffd83dbSDimitry Andric   return &*TestBitMI;
16185ffd83dbSDimitry Andric }
16195ffd83dbSDimitry Andric 
tryOptAndIntoCompareBranch(MachineInstr & AndInst,bool Invert,MachineBasicBlock * DstMBB,MachineIRBuilder & MIB) const16205ffd83dbSDimitry Andric bool AArch64InstructionSelector::tryOptAndIntoCompareBranch(
1621e8d8bef9SDimitry Andric     MachineInstr &AndInst, bool Invert, MachineBasicBlock *DstMBB,
1622e8d8bef9SDimitry Andric     MachineIRBuilder &MIB) const {
1623e8d8bef9SDimitry Andric   assert(AndInst.getOpcode() == TargetOpcode::G_AND && "Expected G_AND only?");
16245ffd83dbSDimitry Andric   // Given something like this:
16255ffd83dbSDimitry Andric   //
16265ffd83dbSDimitry Andric   //  %x = ...Something...
16275ffd83dbSDimitry Andric   //  %one = G_CONSTANT i64 1
16285ffd83dbSDimitry Andric   //  %zero = G_CONSTANT i64 0
16295ffd83dbSDimitry Andric   //  %and = G_AND %x, %one
16305ffd83dbSDimitry Andric   //  %cmp = G_ICMP intpred(ne), %and, %zero
16315ffd83dbSDimitry Andric   //  %cmp_trunc = G_TRUNC %cmp
16325ffd83dbSDimitry Andric   //  G_BRCOND %cmp_trunc, %bb.3
16335ffd83dbSDimitry Andric   //
16345ffd83dbSDimitry Andric   // We want to try and fold the AND into the G_BRCOND and produce either a
16355ffd83dbSDimitry Andric   // TBNZ (when we have intpred(ne)) or a TBZ (when we have intpred(eq)).
16365ffd83dbSDimitry Andric   //
16375ffd83dbSDimitry Andric   // In this case, we'd get
16385ffd83dbSDimitry Andric   //
16395ffd83dbSDimitry Andric   // TBNZ %x %bb.3
16405ffd83dbSDimitry Andric   //
16415ffd83dbSDimitry Andric 
16425ffd83dbSDimitry Andric   // Check if the AND has a constant on its RHS which we can use as a mask.
16435ffd83dbSDimitry Andric   // If it's a power of 2, then it's the same as checking a specific bit.
16445ffd83dbSDimitry Andric   // (e.g, ANDing with 8 == ANDing with 000...100 == testing if bit 3 is set)
1645349cc55cSDimitry Andric   auto MaybeBit = getIConstantVRegValWithLookThrough(
1646e8d8bef9SDimitry Andric       AndInst.getOperand(2).getReg(), *MIB.getMRI());
1647e8d8bef9SDimitry Andric   if (!MaybeBit)
16485ffd83dbSDimitry Andric     return false;
16495ffd83dbSDimitry Andric 
1650e8d8bef9SDimitry Andric   int32_t Bit = MaybeBit->Value.exactLogBase2();
1651e8d8bef9SDimitry Andric   if (Bit < 0)
1652e8d8bef9SDimitry Andric     return false;
1653e8d8bef9SDimitry Andric 
1654e8d8bef9SDimitry Andric   Register TestReg = AndInst.getOperand(1).getReg();
16555ffd83dbSDimitry Andric 
16565ffd83dbSDimitry Andric   // Emit a TB(N)Z.
16575ffd83dbSDimitry Andric   emitTestBit(TestReg, Bit, Invert, DstMBB, MIB);
16585ffd83dbSDimitry Andric   return true;
16595ffd83dbSDimitry Andric }
16605ffd83dbSDimitry Andric 
emitCBZ(Register CompareReg,bool IsNegative,MachineBasicBlock * DestMBB,MachineIRBuilder & MIB) const1661e8d8bef9SDimitry Andric MachineInstr *AArch64InstructionSelector::emitCBZ(Register CompareReg,
1662e8d8bef9SDimitry Andric                                                   bool IsNegative,
1663e8d8bef9SDimitry Andric                                                   MachineBasicBlock *DestMBB,
1664e8d8bef9SDimitry Andric                                                   MachineIRBuilder &MIB) const {
1665e8d8bef9SDimitry Andric   assert(ProduceNonFlagSettingCondBr && "CBZ does not set flags!");
1666e8d8bef9SDimitry Andric   MachineRegisterInfo &MRI = *MIB.getMRI();
1667e8d8bef9SDimitry Andric   assert(RBI.getRegBank(CompareReg, MRI, TRI)->getID() ==
1668e8d8bef9SDimitry Andric              AArch64::GPRRegBankID &&
1669e8d8bef9SDimitry Andric          "Expected GPRs only?");
1670e8d8bef9SDimitry Andric   auto Ty = MRI.getType(CompareReg);
1671e8d8bef9SDimitry Andric   unsigned Width = Ty.getSizeInBits();
1672e8d8bef9SDimitry Andric   assert(!Ty.isVector() && "Expected scalar only?");
1673e8d8bef9SDimitry Andric   assert(Width <= 64 && "Expected width to be at most 64?");
1674e8d8bef9SDimitry Andric   static const unsigned OpcTable[2][2] = {{AArch64::CBZW, AArch64::CBZX},
1675e8d8bef9SDimitry Andric                                           {AArch64::CBNZW, AArch64::CBNZX}};
1676e8d8bef9SDimitry Andric   unsigned Opc = OpcTable[IsNegative][Width == 64];
1677e8d8bef9SDimitry Andric   auto BranchMI = MIB.buildInstr(Opc, {}, {CompareReg}).addMBB(DestMBB);
1678e8d8bef9SDimitry Andric   constrainSelectedInstRegOperands(*BranchMI, TII, TRI, RBI);
1679e8d8bef9SDimitry Andric   return &*BranchMI;
1680e8d8bef9SDimitry Andric }
16815ffd83dbSDimitry Andric 
selectCompareBranchFedByFCmp(MachineInstr & I,MachineInstr & FCmp,MachineIRBuilder & MIB) const1682e8d8bef9SDimitry Andric bool AArch64InstructionSelector::selectCompareBranchFedByFCmp(
1683e8d8bef9SDimitry Andric     MachineInstr &I, MachineInstr &FCmp, MachineIRBuilder &MIB) const {
1684e8d8bef9SDimitry Andric   assert(FCmp.getOpcode() == TargetOpcode::G_FCMP);
1685e8d8bef9SDimitry Andric   assert(I.getOpcode() == TargetOpcode::G_BRCOND);
1686e8d8bef9SDimitry Andric   // Unfortunately, the mapping of LLVM FP CC's onto AArch64 CC's isn't
1687e8d8bef9SDimitry Andric   // totally clean.  Some of them require two branches to implement.
1688e8d8bef9SDimitry Andric   auto Pred = (CmpInst::Predicate)FCmp.getOperand(1).getPredicate();
1689e8d8bef9SDimitry Andric   emitFPCompare(FCmp.getOperand(2).getReg(), FCmp.getOperand(3).getReg(), MIB,
1690e8d8bef9SDimitry Andric                 Pred);
1691e8d8bef9SDimitry Andric   AArch64CC::CondCode CC1, CC2;
1692e8d8bef9SDimitry Andric   changeFCMPPredToAArch64CC(static_cast<CmpInst::Predicate>(Pred), CC1, CC2);
16935ffd83dbSDimitry Andric   MachineBasicBlock *DestMBB = I.getOperand(1).getMBB();
1694e8d8bef9SDimitry Andric   MIB.buildInstr(AArch64::Bcc, {}, {}).addImm(CC1).addMBB(DestMBB);
1695e8d8bef9SDimitry Andric   if (CC2 != AArch64CC::AL)
1696e8d8bef9SDimitry Andric     MIB.buildInstr(AArch64::Bcc, {}, {}).addImm(CC2).addMBB(DestMBB);
1697e8d8bef9SDimitry Andric   I.eraseFromParent();
1698e8d8bef9SDimitry Andric   return true;
1699e8d8bef9SDimitry Andric }
1700e8d8bef9SDimitry Andric 
tryOptCompareBranchFedByICmp(MachineInstr & I,MachineInstr & ICmp,MachineIRBuilder & MIB) const1701e8d8bef9SDimitry Andric bool AArch64InstructionSelector::tryOptCompareBranchFedByICmp(
1702e8d8bef9SDimitry Andric     MachineInstr &I, MachineInstr &ICmp, MachineIRBuilder &MIB) const {
1703e8d8bef9SDimitry Andric   assert(ICmp.getOpcode() == TargetOpcode::G_ICMP);
1704e8d8bef9SDimitry Andric   assert(I.getOpcode() == TargetOpcode::G_BRCOND);
1705e8d8bef9SDimitry Andric   // Attempt to optimize the G_BRCOND + G_ICMP into a TB(N)Z/CB(N)Z.
1706e8d8bef9SDimitry Andric   //
1707e8d8bef9SDimitry Andric   // Speculation tracking/SLH assumes that optimized TB(N)Z/CB(N)Z
1708e8d8bef9SDimitry Andric   // instructions will not be produced, as they are conditional branch
1709e8d8bef9SDimitry Andric   // instructions that do not set flags.
1710e8d8bef9SDimitry Andric   if (!ProduceNonFlagSettingCondBr)
17115ffd83dbSDimitry Andric     return false;
17125ffd83dbSDimitry Andric 
1713e8d8bef9SDimitry Andric   MachineRegisterInfo &MRI = *MIB.getMRI();
1714e8d8bef9SDimitry Andric   MachineBasicBlock *DestMBB = I.getOperand(1).getMBB();
1715e8d8bef9SDimitry Andric   auto Pred =
1716e8d8bef9SDimitry Andric       static_cast<CmpInst::Predicate>(ICmp.getOperand(1).getPredicate());
1717e8d8bef9SDimitry Andric   Register LHS = ICmp.getOperand(2).getReg();
1718e8d8bef9SDimitry Andric   Register RHS = ICmp.getOperand(3).getReg();
1719e8d8bef9SDimitry Andric 
1720e8d8bef9SDimitry Andric   // We're allowed to emit a TB(N)Z/CB(N)Z. Try to do that.
1721349cc55cSDimitry Andric   auto VRegAndVal = getIConstantVRegValWithLookThrough(RHS, MRI);
1722e8d8bef9SDimitry Andric   MachineInstr *AndInst = getOpcodeDef(TargetOpcode::G_AND, LHS, MRI);
17235ffd83dbSDimitry Andric 
17245ffd83dbSDimitry Andric   // When we can emit a TB(N)Z, prefer that.
17255ffd83dbSDimitry Andric   //
17265ffd83dbSDimitry Andric   // Handle non-commutative condition codes first.
17275ffd83dbSDimitry Andric   // Note that we don't want to do this when we have a G_AND because it can
17285ffd83dbSDimitry Andric   // become a tst. The tst will make the test bit in the TB(N)Z redundant.
1729e8d8bef9SDimitry Andric   if (VRegAndVal && !AndInst) {
1730e8d8bef9SDimitry Andric     int64_t C = VRegAndVal->Value.getSExtValue();
17315ffd83dbSDimitry Andric 
17325ffd83dbSDimitry Andric     // When we have a greater-than comparison, we can just test if the msb is
17335ffd83dbSDimitry Andric     // zero.
17345ffd83dbSDimitry Andric     if (C == -1 && Pred == CmpInst::ICMP_SGT) {
17355ffd83dbSDimitry Andric       uint64_t Bit = MRI.getType(LHS).getSizeInBits() - 1;
17365ffd83dbSDimitry Andric       emitTestBit(LHS, Bit, /*IsNegative = */ false, DestMBB, MIB);
17375ffd83dbSDimitry Andric       I.eraseFromParent();
17385ffd83dbSDimitry Andric       return true;
17395ffd83dbSDimitry Andric     }
17405ffd83dbSDimitry Andric 
17415ffd83dbSDimitry Andric     // When we have a less than comparison, we can just test if the msb is not
17425ffd83dbSDimitry Andric     // zero.
17435ffd83dbSDimitry Andric     if (C == 0 && Pred == CmpInst::ICMP_SLT) {
17445ffd83dbSDimitry Andric       uint64_t Bit = MRI.getType(LHS).getSizeInBits() - 1;
17455ffd83dbSDimitry Andric       emitTestBit(LHS, Bit, /*IsNegative = */ true, DestMBB, MIB);
17465ffd83dbSDimitry Andric       I.eraseFromParent();
17475ffd83dbSDimitry Andric       return true;
17485ffd83dbSDimitry Andric     }
1749bdd1243dSDimitry Andric 
1750bdd1243dSDimitry Andric     // Inversely, if we have a signed greater-than-or-equal comparison to zero,
1751bdd1243dSDimitry Andric     // we can test if the msb is zero.
1752bdd1243dSDimitry Andric     if (C == 0 && Pred == CmpInst::ICMP_SGE) {
1753bdd1243dSDimitry Andric       uint64_t Bit = MRI.getType(LHS).getSizeInBits() - 1;
1754bdd1243dSDimitry Andric       emitTestBit(LHS, Bit, /*IsNegative = */ false, DestMBB, MIB);
1755bdd1243dSDimitry Andric       I.eraseFromParent();
1756bdd1243dSDimitry Andric       return true;
1757bdd1243dSDimitry Andric     }
17585ffd83dbSDimitry Andric   }
17595ffd83dbSDimitry Andric 
1760e8d8bef9SDimitry Andric   // Attempt to handle commutative condition codes. Right now, that's only
1761e8d8bef9SDimitry Andric   // eq/ne.
1762e8d8bef9SDimitry Andric   if (ICmpInst::isEquality(Pred)) {
17635ffd83dbSDimitry Andric     if (!VRegAndVal) {
17645ffd83dbSDimitry Andric       std::swap(RHS, LHS);
1765349cc55cSDimitry Andric       VRegAndVal = getIConstantVRegValWithLookThrough(RHS, MRI);
1766e8d8bef9SDimitry Andric       AndInst = getOpcodeDef(TargetOpcode::G_AND, LHS, MRI);
17675ffd83dbSDimitry Andric     }
17685ffd83dbSDimitry Andric 
1769e8d8bef9SDimitry Andric     if (VRegAndVal && VRegAndVal->Value == 0) {
1770e8d8bef9SDimitry Andric       // If there's a G_AND feeding into this branch, try to fold it away by
1771e8d8bef9SDimitry Andric       // emitting a TB(N)Z instead.
1772e8d8bef9SDimitry Andric       //
1773e8d8bef9SDimitry Andric       // Note: If we have LT, then it *is* possible to fold, but it wouldn't be
1774e8d8bef9SDimitry Andric       // beneficial. When we have an AND and LT, we need a TST/ANDS, so folding
1775e8d8bef9SDimitry Andric       // would be redundant.
1776e8d8bef9SDimitry Andric       if (AndInst &&
1777e8d8bef9SDimitry Andric           tryOptAndIntoCompareBranch(
1778e8d8bef9SDimitry Andric               *AndInst, /*Invert = */ Pred == CmpInst::ICMP_NE, DestMBB, MIB)) {
1779e8d8bef9SDimitry Andric         I.eraseFromParent();
1780e8d8bef9SDimitry Andric         return true;
1781e8d8bef9SDimitry Andric       }
1782e8d8bef9SDimitry Andric 
1783e8d8bef9SDimitry Andric       // Otherwise, try to emit a CB(N)Z instead.
1784e8d8bef9SDimitry Andric       auto LHSTy = MRI.getType(LHS);
1785e8d8bef9SDimitry Andric       if (!LHSTy.isVector() && LHSTy.getSizeInBits() <= 64) {
1786e8d8bef9SDimitry Andric         emitCBZ(LHS, /*IsNegative = */ Pred == CmpInst::ICMP_NE, DestMBB, MIB);
1787e8d8bef9SDimitry Andric         I.eraseFromParent();
1788e8d8bef9SDimitry Andric         return true;
1789e8d8bef9SDimitry Andric       }
1790e8d8bef9SDimitry Andric     }
1791e8d8bef9SDimitry Andric   }
1792e8d8bef9SDimitry Andric 
17935ffd83dbSDimitry Andric   return false;
1794e8d8bef9SDimitry Andric }
1795e8d8bef9SDimitry Andric 
selectCompareBranchFedByICmp(MachineInstr & I,MachineInstr & ICmp,MachineIRBuilder & MIB) const1796e8d8bef9SDimitry Andric bool AArch64InstructionSelector::selectCompareBranchFedByICmp(
1797e8d8bef9SDimitry Andric     MachineInstr &I, MachineInstr &ICmp, MachineIRBuilder &MIB) const {
1798e8d8bef9SDimitry Andric   assert(ICmp.getOpcode() == TargetOpcode::G_ICMP);
1799e8d8bef9SDimitry Andric   assert(I.getOpcode() == TargetOpcode::G_BRCOND);
1800e8d8bef9SDimitry Andric   if (tryOptCompareBranchFedByICmp(I, ICmp, MIB))
1801e8d8bef9SDimitry Andric     return true;
1802e8d8bef9SDimitry Andric 
1803e8d8bef9SDimitry Andric   // Couldn't optimize. Emit a compare + a Bcc.
1804e8d8bef9SDimitry Andric   MachineBasicBlock *DestMBB = I.getOperand(1).getMBB();
1805e8d8bef9SDimitry Andric   auto PredOp = ICmp.getOperand(1);
1806e8d8bef9SDimitry Andric   emitIntegerCompare(ICmp.getOperand(2), ICmp.getOperand(3), PredOp, MIB);
1807e8d8bef9SDimitry Andric   const AArch64CC::CondCode CC = changeICMPPredToAArch64CC(
1808e8d8bef9SDimitry Andric       static_cast<CmpInst::Predicate>(PredOp.getPredicate()));
18095ffd83dbSDimitry Andric   MIB.buildInstr(AArch64::Bcc, {}, {}).addImm(CC).addMBB(DestMBB);
18105ffd83dbSDimitry Andric   I.eraseFromParent();
18115ffd83dbSDimitry Andric   return true;
18125ffd83dbSDimitry Andric }
18135ffd83dbSDimitry Andric 
selectCompareBranch(MachineInstr & I,MachineFunction & MF,MachineRegisterInfo & MRI)1814e8d8bef9SDimitry Andric bool AArch64InstructionSelector::selectCompareBranch(
1815fe6060f1SDimitry Andric     MachineInstr &I, MachineFunction &MF, MachineRegisterInfo &MRI) {
1816e8d8bef9SDimitry Andric   Register CondReg = I.getOperand(0).getReg();
1817e8d8bef9SDimitry Andric   MachineInstr *CCMI = MRI.getVRegDef(CondReg);
1818e8d8bef9SDimitry Andric   // Try to select the G_BRCOND using whatever is feeding the condition if
1819e8d8bef9SDimitry Andric   // possible.
1820e8d8bef9SDimitry Andric   unsigned CCMIOpc = CCMI->getOpcode();
1821e8d8bef9SDimitry Andric   if (CCMIOpc == TargetOpcode::G_FCMP)
1822e8d8bef9SDimitry Andric     return selectCompareBranchFedByFCmp(I, *CCMI, MIB);
1823e8d8bef9SDimitry Andric   if (CCMIOpc == TargetOpcode::G_ICMP)
1824e8d8bef9SDimitry Andric     return selectCompareBranchFedByICmp(I, *CCMI, MIB);
1825e8d8bef9SDimitry Andric 
1826e8d8bef9SDimitry Andric   // Speculation tracking/SLH assumes that optimized TB(N)Z/CB(N)Z
1827e8d8bef9SDimitry Andric   // instructions will not be produced, as they are conditional branch
1828e8d8bef9SDimitry Andric   // instructions that do not set flags.
1829e8d8bef9SDimitry Andric   if (ProduceNonFlagSettingCondBr) {
1830e8d8bef9SDimitry Andric     emitTestBit(CondReg, /*Bit = */ 0, /*IsNegative = */ true,
1831e8d8bef9SDimitry Andric                 I.getOperand(1).getMBB(), MIB);
18325ffd83dbSDimitry Andric     I.eraseFromParent();
18335ffd83dbSDimitry Andric     return true;
18345ffd83dbSDimitry Andric   }
18355ffd83dbSDimitry Andric 
1836e8d8bef9SDimitry Andric   // Can't emit TB(N)Z/CB(N)Z. Emit a tst + bcc instead.
1837e8d8bef9SDimitry Andric   auto TstMI =
1838e8d8bef9SDimitry Andric       MIB.buildInstr(AArch64::ANDSWri, {LLT::scalar(32)}, {CondReg}).addImm(1);
1839e8d8bef9SDimitry Andric   constrainSelectedInstRegOperands(*TstMI, TII, TRI, RBI);
1840e8d8bef9SDimitry Andric   auto Bcc = MIB.buildInstr(AArch64::Bcc)
184106c3fb27SDimitry Andric                  .addImm(AArch64CC::NE)
1842e8d8bef9SDimitry Andric                  .addMBB(I.getOperand(1).getMBB());
18435ffd83dbSDimitry Andric   I.eraseFromParent();
1844e8d8bef9SDimitry Andric   return constrainSelectedInstRegOperands(*Bcc, TII, TRI, RBI);
18455ffd83dbSDimitry Andric }
18465ffd83dbSDimitry Andric 
18475ffd83dbSDimitry Andric /// Returns the element immediate value of a vector shift operand if found.
18485ffd83dbSDimitry Andric /// This needs to detect a splat-like operation, e.g. a G_BUILD_VECTOR.
getVectorShiftImm(Register Reg,MachineRegisterInfo & MRI)1849bdd1243dSDimitry Andric static std::optional<int64_t> getVectorShiftImm(Register Reg,
18505ffd83dbSDimitry Andric                                                 MachineRegisterInfo &MRI) {
18515ffd83dbSDimitry Andric   assert(MRI.getType(Reg).isVector() && "Expected a *vector* shift operand");
18525ffd83dbSDimitry Andric   MachineInstr *OpMI = MRI.getVRegDef(Reg);
1853fe6060f1SDimitry Andric   return getAArch64VectorSplatScalar(*OpMI, MRI);
18545ffd83dbSDimitry Andric }
18555ffd83dbSDimitry Andric 
18565ffd83dbSDimitry Andric /// Matches and returns the shift immediate value for a SHL instruction given
18575ffd83dbSDimitry Andric /// a shift operand.
getVectorSHLImm(LLT SrcTy,Register Reg,MachineRegisterInfo & MRI)1858bdd1243dSDimitry Andric static std::optional<int64_t> getVectorSHLImm(LLT SrcTy, Register Reg,
1859bdd1243dSDimitry Andric                                               MachineRegisterInfo &MRI) {
1860bdd1243dSDimitry Andric   std::optional<int64_t> ShiftImm = getVectorShiftImm(Reg, MRI);
18615ffd83dbSDimitry Andric   if (!ShiftImm)
1862bdd1243dSDimitry Andric     return std::nullopt;
18635ffd83dbSDimitry Andric   // Check the immediate is in range for a SHL.
18645ffd83dbSDimitry Andric   int64_t Imm = *ShiftImm;
18655ffd83dbSDimitry Andric   if (Imm < 0)
1866bdd1243dSDimitry Andric     return std::nullopt;
18675ffd83dbSDimitry Andric   switch (SrcTy.getElementType().getSizeInBits()) {
18685ffd83dbSDimitry Andric   default:
18695ffd83dbSDimitry Andric     LLVM_DEBUG(dbgs() << "Unhandled element type for vector shift");
1870bdd1243dSDimitry Andric     return std::nullopt;
18715ffd83dbSDimitry Andric   case 8:
18725ffd83dbSDimitry Andric     if (Imm > 7)
1873bdd1243dSDimitry Andric       return std::nullopt;
18745ffd83dbSDimitry Andric     break;
18755ffd83dbSDimitry Andric   case 16:
18765ffd83dbSDimitry Andric     if (Imm > 15)
1877bdd1243dSDimitry Andric       return std::nullopt;
18785ffd83dbSDimitry Andric     break;
18795ffd83dbSDimitry Andric   case 32:
18805ffd83dbSDimitry Andric     if (Imm > 31)
1881bdd1243dSDimitry Andric       return std::nullopt;
18825ffd83dbSDimitry Andric     break;
18835ffd83dbSDimitry Andric   case 64:
18845ffd83dbSDimitry Andric     if (Imm > 63)
1885bdd1243dSDimitry Andric       return std::nullopt;
18865ffd83dbSDimitry Andric     break;
18875ffd83dbSDimitry Andric   }
18885ffd83dbSDimitry Andric   return Imm;
18895ffd83dbSDimitry Andric }
18905ffd83dbSDimitry Andric 
selectVectorSHL(MachineInstr & I,MachineRegisterInfo & MRI)1891fe6060f1SDimitry Andric bool AArch64InstructionSelector::selectVectorSHL(MachineInstr &I,
1892fe6060f1SDimitry Andric                                                  MachineRegisterInfo &MRI) {
18935ffd83dbSDimitry Andric   assert(I.getOpcode() == TargetOpcode::G_SHL);
18945ffd83dbSDimitry Andric   Register DstReg = I.getOperand(0).getReg();
18955ffd83dbSDimitry Andric   const LLT Ty = MRI.getType(DstReg);
18965ffd83dbSDimitry Andric   Register Src1Reg = I.getOperand(1).getReg();
18975ffd83dbSDimitry Andric   Register Src2Reg = I.getOperand(2).getReg();
18985ffd83dbSDimitry Andric 
18995ffd83dbSDimitry Andric   if (!Ty.isVector())
19005ffd83dbSDimitry Andric     return false;
19015ffd83dbSDimitry Andric 
19025ffd83dbSDimitry Andric   // Check if we have a vector of constants on RHS that we can select as the
19035ffd83dbSDimitry Andric   // immediate form.
1904bdd1243dSDimitry Andric   std::optional<int64_t> ImmVal = getVectorSHLImm(Ty, Src2Reg, MRI);
19055ffd83dbSDimitry Andric 
19065ffd83dbSDimitry Andric   unsigned Opc = 0;
1907fe6060f1SDimitry Andric   if (Ty == LLT::fixed_vector(2, 64)) {
19085ffd83dbSDimitry Andric     Opc = ImmVal ? AArch64::SHLv2i64_shift : AArch64::USHLv2i64;
1909fe6060f1SDimitry Andric   } else if (Ty == LLT::fixed_vector(4, 32)) {
19105ffd83dbSDimitry Andric     Opc = ImmVal ? AArch64::SHLv4i32_shift : AArch64::USHLv4i32;
1911fe6060f1SDimitry Andric   } else if (Ty == LLT::fixed_vector(2, 32)) {
19125ffd83dbSDimitry Andric     Opc = ImmVal ? AArch64::SHLv2i32_shift : AArch64::USHLv2i32;
1913fe6060f1SDimitry Andric   } else if (Ty == LLT::fixed_vector(4, 16)) {
1914e8d8bef9SDimitry Andric     Opc = ImmVal ? AArch64::SHLv4i16_shift : AArch64::USHLv4i16;
1915fe6060f1SDimitry Andric   } else if (Ty == LLT::fixed_vector(8, 16)) {
1916e8d8bef9SDimitry Andric     Opc = ImmVal ? AArch64::SHLv8i16_shift : AArch64::USHLv8i16;
1917fe6060f1SDimitry Andric   } else if (Ty == LLT::fixed_vector(16, 8)) {
1918e8d8bef9SDimitry Andric     Opc = ImmVal ? AArch64::SHLv16i8_shift : AArch64::USHLv16i8;
1919fe6060f1SDimitry Andric   } else if (Ty == LLT::fixed_vector(8, 8)) {
1920e8d8bef9SDimitry Andric     Opc = ImmVal ? AArch64::SHLv8i8_shift : AArch64::USHLv8i8;
19215ffd83dbSDimitry Andric   } else {
19225ffd83dbSDimitry Andric     LLVM_DEBUG(dbgs() << "Unhandled G_SHL type");
19235ffd83dbSDimitry Andric     return false;
19245ffd83dbSDimitry Andric   }
19255ffd83dbSDimitry Andric 
19265ffd83dbSDimitry Andric   auto Shl = MIB.buildInstr(Opc, {DstReg}, {Src1Reg});
19275ffd83dbSDimitry Andric   if (ImmVal)
19285ffd83dbSDimitry Andric     Shl.addImm(*ImmVal);
19295ffd83dbSDimitry Andric   else
19305ffd83dbSDimitry Andric     Shl.addUse(Src2Reg);
19315ffd83dbSDimitry Andric   constrainSelectedInstRegOperands(*Shl, TII, TRI, RBI);
19325ffd83dbSDimitry Andric   I.eraseFromParent();
19335ffd83dbSDimitry Andric   return true;
19345ffd83dbSDimitry Andric }
19355ffd83dbSDimitry Andric 
selectVectorAshrLshr(MachineInstr & I,MachineRegisterInfo & MRI)1936e8d8bef9SDimitry Andric bool AArch64InstructionSelector::selectVectorAshrLshr(
1937fe6060f1SDimitry Andric     MachineInstr &I, MachineRegisterInfo &MRI) {
1938e8d8bef9SDimitry Andric   assert(I.getOpcode() == TargetOpcode::G_ASHR ||
1939e8d8bef9SDimitry Andric          I.getOpcode() == TargetOpcode::G_LSHR);
19405ffd83dbSDimitry Andric   Register DstReg = I.getOperand(0).getReg();
19415ffd83dbSDimitry Andric   const LLT Ty = MRI.getType(DstReg);
19425ffd83dbSDimitry Andric   Register Src1Reg = I.getOperand(1).getReg();
19435ffd83dbSDimitry Andric   Register Src2Reg = I.getOperand(2).getReg();
19445ffd83dbSDimitry Andric 
19455ffd83dbSDimitry Andric   if (!Ty.isVector())
19465ffd83dbSDimitry Andric     return false;
19475ffd83dbSDimitry Andric 
1948e8d8bef9SDimitry Andric   bool IsASHR = I.getOpcode() == TargetOpcode::G_ASHR;
1949e8d8bef9SDimitry Andric 
1950e8d8bef9SDimitry Andric   // We expect the immediate case to be lowered in the PostLegalCombiner to
1951e8d8bef9SDimitry Andric   // AArch64ISD::VASHR or AArch64ISD::VLSHR equivalents.
1952e8d8bef9SDimitry Andric 
19535ffd83dbSDimitry Andric   // There is not a shift right register instruction, but the shift left
19545ffd83dbSDimitry Andric   // register instruction takes a signed value, where negative numbers specify a
19555ffd83dbSDimitry Andric   // right shift.
19565ffd83dbSDimitry Andric 
19575ffd83dbSDimitry Andric   unsigned Opc = 0;
19585ffd83dbSDimitry Andric   unsigned NegOpc = 0;
1959e8d8bef9SDimitry Andric   const TargetRegisterClass *RC =
196081ad6265SDimitry Andric       getRegClassForTypeOnBank(Ty, RBI.getRegBank(AArch64::FPRRegBankID));
1961fe6060f1SDimitry Andric   if (Ty == LLT::fixed_vector(2, 64)) {
1962e8d8bef9SDimitry Andric     Opc = IsASHR ? AArch64::SSHLv2i64 : AArch64::USHLv2i64;
19635ffd83dbSDimitry Andric     NegOpc = AArch64::NEGv2i64;
1964fe6060f1SDimitry Andric   } else if (Ty == LLT::fixed_vector(4, 32)) {
1965e8d8bef9SDimitry Andric     Opc = IsASHR ? AArch64::SSHLv4i32 : AArch64::USHLv4i32;
19665ffd83dbSDimitry Andric     NegOpc = AArch64::NEGv4i32;
1967fe6060f1SDimitry Andric   } else if (Ty == LLT::fixed_vector(2, 32)) {
1968e8d8bef9SDimitry Andric     Opc = IsASHR ? AArch64::SSHLv2i32 : AArch64::USHLv2i32;
19695ffd83dbSDimitry Andric     NegOpc = AArch64::NEGv2i32;
1970fe6060f1SDimitry Andric   } else if (Ty == LLT::fixed_vector(4, 16)) {
1971e8d8bef9SDimitry Andric     Opc = IsASHR ? AArch64::SSHLv4i16 : AArch64::USHLv4i16;
1972e8d8bef9SDimitry Andric     NegOpc = AArch64::NEGv4i16;
1973fe6060f1SDimitry Andric   } else if (Ty == LLT::fixed_vector(8, 16)) {
1974e8d8bef9SDimitry Andric     Opc = IsASHR ? AArch64::SSHLv8i16 : AArch64::USHLv8i16;
1975e8d8bef9SDimitry Andric     NegOpc = AArch64::NEGv8i16;
1976fe6060f1SDimitry Andric   } else if (Ty == LLT::fixed_vector(16, 8)) {
1977e8d8bef9SDimitry Andric     Opc = IsASHR ? AArch64::SSHLv16i8 : AArch64::USHLv16i8;
197823408297SDimitry Andric     NegOpc = AArch64::NEGv16i8;
1979fe6060f1SDimitry Andric   } else if (Ty == LLT::fixed_vector(8, 8)) {
1980e8d8bef9SDimitry Andric     Opc = IsASHR ? AArch64::SSHLv8i8 : AArch64::USHLv8i8;
1981e8d8bef9SDimitry Andric     NegOpc = AArch64::NEGv8i8;
19825ffd83dbSDimitry Andric   } else {
19835ffd83dbSDimitry Andric     LLVM_DEBUG(dbgs() << "Unhandled G_ASHR type");
19845ffd83dbSDimitry Andric     return false;
19855ffd83dbSDimitry Andric   }
19865ffd83dbSDimitry Andric 
19875ffd83dbSDimitry Andric   auto Neg = MIB.buildInstr(NegOpc, {RC}, {Src2Reg});
19885ffd83dbSDimitry Andric   constrainSelectedInstRegOperands(*Neg, TII, TRI, RBI);
19895ffd83dbSDimitry Andric   auto SShl = MIB.buildInstr(Opc, {DstReg}, {Src1Reg, Neg});
19905ffd83dbSDimitry Andric   constrainSelectedInstRegOperands(*SShl, TII, TRI, RBI);
19915ffd83dbSDimitry Andric   I.eraseFromParent();
19925ffd83dbSDimitry Andric   return true;
19935ffd83dbSDimitry Andric }
19945ffd83dbSDimitry Andric 
selectVaStartAAPCS(MachineInstr & I,MachineFunction & MF,MachineRegisterInfo & MRI) const19955ffd83dbSDimitry Andric bool AArch64InstructionSelector::selectVaStartAAPCS(
19965ffd83dbSDimitry Andric     MachineInstr &I, MachineFunction &MF, MachineRegisterInfo &MRI) const {
19975ffd83dbSDimitry Andric   return false;
19985ffd83dbSDimitry Andric }
19995ffd83dbSDimitry Andric 
selectVaStartDarwin(MachineInstr & I,MachineFunction & MF,MachineRegisterInfo & MRI) const20005ffd83dbSDimitry Andric bool AArch64InstructionSelector::selectVaStartDarwin(
20015ffd83dbSDimitry Andric     MachineInstr &I, MachineFunction &MF, MachineRegisterInfo &MRI) const {
20025ffd83dbSDimitry Andric   AArch64FunctionInfo *FuncInfo = MF.getInfo<AArch64FunctionInfo>();
20035ffd83dbSDimitry Andric   Register ListReg = I.getOperand(0).getReg();
20045ffd83dbSDimitry Andric 
20055ffd83dbSDimitry Andric   Register ArgsAddrReg = MRI.createVirtualRegister(&AArch64::GPR64RegClass);
20065ffd83dbSDimitry Andric 
200706c3fb27SDimitry Andric   int FrameIdx = FuncInfo->getVarArgsStackIndex();
200806c3fb27SDimitry Andric   if (MF.getSubtarget<AArch64Subtarget>().isCallingConvWin64(
2009*0fca6ea1SDimitry Andric           MF.getFunction().getCallingConv(), MF.getFunction().isVarArg())) {
201006c3fb27SDimitry Andric     FrameIdx = FuncInfo->getVarArgsGPRSize() > 0
201106c3fb27SDimitry Andric                    ? FuncInfo->getVarArgsGPRIndex()
201206c3fb27SDimitry Andric                    : FuncInfo->getVarArgsStackIndex();
201306c3fb27SDimitry Andric   }
201406c3fb27SDimitry Andric 
20155ffd83dbSDimitry Andric   auto MIB =
20165ffd83dbSDimitry Andric       BuildMI(*I.getParent(), I, I.getDebugLoc(), TII.get(AArch64::ADDXri))
20175ffd83dbSDimitry Andric           .addDef(ArgsAddrReg)
201806c3fb27SDimitry Andric           .addFrameIndex(FrameIdx)
20195ffd83dbSDimitry Andric           .addImm(0)
20205ffd83dbSDimitry Andric           .addImm(0);
20215ffd83dbSDimitry Andric 
20225ffd83dbSDimitry Andric   constrainSelectedInstRegOperands(*MIB, TII, TRI, RBI);
20235ffd83dbSDimitry Andric 
20245ffd83dbSDimitry Andric   MIB = BuildMI(*I.getParent(), I, I.getDebugLoc(), TII.get(AArch64::STRXui))
20255ffd83dbSDimitry Andric             .addUse(ArgsAddrReg)
20265ffd83dbSDimitry Andric             .addUse(ListReg)
20275ffd83dbSDimitry Andric             .addImm(0)
20285ffd83dbSDimitry Andric             .addMemOperand(*I.memoperands_begin());
20295ffd83dbSDimitry Andric 
20305ffd83dbSDimitry Andric   constrainSelectedInstRegOperands(*MIB, TII, TRI, RBI);
20315ffd83dbSDimitry Andric   I.eraseFromParent();
20325ffd83dbSDimitry Andric   return true;
20335ffd83dbSDimitry Andric }
20345ffd83dbSDimitry Andric 
materializeLargeCMVal(MachineInstr & I,const Value * V,unsigned OpFlags)20355ffd83dbSDimitry Andric void AArch64InstructionSelector::materializeLargeCMVal(
2036fe6060f1SDimitry Andric     MachineInstr &I, const Value *V, unsigned OpFlags) {
20375ffd83dbSDimitry Andric   MachineBasicBlock &MBB = *I.getParent();
20385ffd83dbSDimitry Andric   MachineFunction &MF = *MBB.getParent();
20395ffd83dbSDimitry Andric   MachineRegisterInfo &MRI = MF.getRegInfo();
20405ffd83dbSDimitry Andric 
20415ffd83dbSDimitry Andric   auto MovZ = MIB.buildInstr(AArch64::MOVZXi, {&AArch64::GPR64RegClass}, {});
20425ffd83dbSDimitry Andric   MovZ->addOperand(MF, I.getOperand(1));
20435ffd83dbSDimitry Andric   MovZ->getOperand(1).setTargetFlags(OpFlags | AArch64II::MO_G0 |
20445ffd83dbSDimitry Andric                                      AArch64II::MO_NC);
20455ffd83dbSDimitry Andric   MovZ->addOperand(MF, MachineOperand::CreateImm(0));
20465ffd83dbSDimitry Andric   constrainSelectedInstRegOperands(*MovZ, TII, TRI, RBI);
20475ffd83dbSDimitry Andric 
20485ffd83dbSDimitry Andric   auto BuildMovK = [&](Register SrcReg, unsigned char Flags, unsigned Offset,
20495ffd83dbSDimitry Andric                        Register ForceDstReg) {
20505ffd83dbSDimitry Andric     Register DstReg = ForceDstReg
20515ffd83dbSDimitry Andric                           ? ForceDstReg
20525ffd83dbSDimitry Andric                           : MRI.createVirtualRegister(&AArch64::GPR64RegClass);
20535ffd83dbSDimitry Andric     auto MovI = MIB.buildInstr(AArch64::MOVKXi).addDef(DstReg).addUse(SrcReg);
20545ffd83dbSDimitry Andric     if (auto *GV = dyn_cast<GlobalValue>(V)) {
20555ffd83dbSDimitry Andric       MovI->addOperand(MF, MachineOperand::CreateGA(
20565ffd83dbSDimitry Andric                                GV, MovZ->getOperand(1).getOffset(), Flags));
20575ffd83dbSDimitry Andric     } else {
20585ffd83dbSDimitry Andric       MovI->addOperand(
20595ffd83dbSDimitry Andric           MF, MachineOperand::CreateBA(cast<BlockAddress>(V),
20605ffd83dbSDimitry Andric                                        MovZ->getOperand(1).getOffset(), Flags));
20615ffd83dbSDimitry Andric     }
20625ffd83dbSDimitry Andric     MovI->addOperand(MF, MachineOperand::CreateImm(Offset));
20635ffd83dbSDimitry Andric     constrainSelectedInstRegOperands(*MovI, TII, TRI, RBI);
20645ffd83dbSDimitry Andric     return DstReg;
20655ffd83dbSDimitry Andric   };
20665ffd83dbSDimitry Andric   Register DstReg = BuildMovK(MovZ.getReg(0),
20675ffd83dbSDimitry Andric                               AArch64II::MO_G1 | AArch64II::MO_NC, 16, 0);
20685ffd83dbSDimitry Andric   DstReg = BuildMovK(DstReg, AArch64II::MO_G2 | AArch64II::MO_NC, 32, 0);
20695ffd83dbSDimitry Andric   BuildMovK(DstReg, AArch64II::MO_G3, 48, I.getOperand(0).getReg());
20705ffd83dbSDimitry Andric }
20715ffd83dbSDimitry Andric 
preISelLower(MachineInstr & I)20725ffd83dbSDimitry Andric bool AArch64InstructionSelector::preISelLower(MachineInstr &I) {
20735ffd83dbSDimitry Andric   MachineBasicBlock &MBB = *I.getParent();
20745ffd83dbSDimitry Andric   MachineFunction &MF = *MBB.getParent();
20755ffd83dbSDimitry Andric   MachineRegisterInfo &MRI = MF.getRegInfo();
20765ffd83dbSDimitry Andric 
20775ffd83dbSDimitry Andric   switch (I.getOpcode()) {
2078fe6060f1SDimitry Andric   case TargetOpcode::G_STORE: {
2079fe6060f1SDimitry Andric     bool Changed = contractCrossBankCopyIntoStore(I, MRI);
2080fe6060f1SDimitry Andric     MachineOperand &SrcOp = I.getOperand(0);
2081fe6060f1SDimitry Andric     if (MRI.getType(SrcOp.getReg()).isPointer()) {
2082fe6060f1SDimitry Andric       // Allow matching with imported patterns for stores of pointers. Unlike
2083fe6060f1SDimitry Andric       // G_LOAD/G_PTR_ADD, we may not have selected all users. So, emit a copy
2084fe6060f1SDimitry Andric       // and constrain.
2085fe6060f1SDimitry Andric       auto Copy = MIB.buildCopy(LLT::scalar(64), SrcOp);
2086fe6060f1SDimitry Andric       Register NewSrc = Copy.getReg(0);
2087fe6060f1SDimitry Andric       SrcOp.setReg(NewSrc);
2088fe6060f1SDimitry Andric       RBI.constrainGenericRegister(NewSrc, AArch64::GPR64RegClass, MRI);
2089fe6060f1SDimitry Andric       Changed = true;
2090fe6060f1SDimitry Andric     }
2091fe6060f1SDimitry Andric     return Changed;
2092fe6060f1SDimitry Andric   }
20935ffd83dbSDimitry Andric   case TargetOpcode::G_PTR_ADD:
20945ffd83dbSDimitry Andric     return convertPtrAddToAdd(I, MRI);
20955ffd83dbSDimitry Andric   case TargetOpcode::G_LOAD: {
20965ffd83dbSDimitry Andric     // For scalar loads of pointers, we try to convert the dest type from p0
20975ffd83dbSDimitry Andric     // to s64 so that our imported patterns can match. Like with the G_PTR_ADD
20985ffd83dbSDimitry Andric     // conversion, this should be ok because all users should have been
20995ffd83dbSDimitry Andric     // selected already, so the type doesn't matter for them.
21005ffd83dbSDimitry Andric     Register DstReg = I.getOperand(0).getReg();
21015ffd83dbSDimitry Andric     const LLT DstTy = MRI.getType(DstReg);
21025ffd83dbSDimitry Andric     if (!DstTy.isPointer())
21035ffd83dbSDimitry Andric       return false;
21045ffd83dbSDimitry Andric     MRI.setType(DstReg, LLT::scalar(64));
21055ffd83dbSDimitry Andric     return true;
21065ffd83dbSDimitry Andric   }
2107e8d8bef9SDimitry Andric   case AArch64::G_DUP: {
2108e8d8bef9SDimitry Andric     // Convert the type from p0 to s64 to help selection.
2109e8d8bef9SDimitry Andric     LLT DstTy = MRI.getType(I.getOperand(0).getReg());
2110*0fca6ea1SDimitry Andric     if (!DstTy.isPointerVector())
2111e8d8bef9SDimitry Andric       return false;
2112e8d8bef9SDimitry Andric     auto NewSrc = MIB.buildCopy(LLT::scalar(64), I.getOperand(1).getReg());
2113e8d8bef9SDimitry Andric     MRI.setType(I.getOperand(0).getReg(),
2114e8d8bef9SDimitry Andric                 DstTy.changeElementType(LLT::scalar(64)));
2115fe6060f1SDimitry Andric     MRI.setRegClass(NewSrc.getReg(0), &AArch64::GPR64RegClass);
2116e8d8bef9SDimitry Andric     I.getOperand(1).setReg(NewSrc.getReg(0));
2117e8d8bef9SDimitry Andric     return true;
2118e8d8bef9SDimitry Andric   }
2119e8d8bef9SDimitry Andric   case TargetOpcode::G_UITOFP:
2120e8d8bef9SDimitry Andric   case TargetOpcode::G_SITOFP: {
2121e8d8bef9SDimitry Andric     // If both source and destination regbanks are FPR, then convert the opcode
2122e8d8bef9SDimitry Andric     // to G_SITOF so that the importer can select it to an fpr variant.
2123e8d8bef9SDimitry Andric     // Otherwise, it ends up matching an fpr/gpr variant and adding a cross-bank
2124e8d8bef9SDimitry Andric     // copy.
2125e8d8bef9SDimitry Andric     Register SrcReg = I.getOperand(1).getReg();
2126e8d8bef9SDimitry Andric     LLT SrcTy = MRI.getType(SrcReg);
2127e8d8bef9SDimitry Andric     LLT DstTy = MRI.getType(I.getOperand(0).getReg());
2128e8d8bef9SDimitry Andric     if (SrcTy.isVector() || SrcTy.getSizeInBits() != DstTy.getSizeInBits())
2129e8d8bef9SDimitry Andric       return false;
2130e8d8bef9SDimitry Andric 
2131e8d8bef9SDimitry Andric     if (RBI.getRegBank(SrcReg, MRI, TRI)->getID() == AArch64::FPRRegBankID) {
2132e8d8bef9SDimitry Andric       if (I.getOpcode() == TargetOpcode::G_SITOFP)
2133e8d8bef9SDimitry Andric         I.setDesc(TII.get(AArch64::G_SITOF));
2134e8d8bef9SDimitry Andric       else
2135e8d8bef9SDimitry Andric         I.setDesc(TII.get(AArch64::G_UITOF));
2136e8d8bef9SDimitry Andric       return true;
2137e8d8bef9SDimitry Andric     }
2138e8d8bef9SDimitry Andric     return false;
2139e8d8bef9SDimitry Andric   }
21405ffd83dbSDimitry Andric   default:
21415ffd83dbSDimitry Andric     return false;
21425ffd83dbSDimitry Andric   }
21435ffd83dbSDimitry Andric }
21445ffd83dbSDimitry Andric 
21455ffd83dbSDimitry Andric /// This lowering tries to look for G_PTR_ADD instructions and then converts
21465ffd83dbSDimitry Andric /// them to a standard G_ADD with a COPY on the source.
21475ffd83dbSDimitry Andric ///
21485ffd83dbSDimitry Andric /// The motivation behind this is to expose the add semantics to the imported
21495ffd83dbSDimitry Andric /// tablegen patterns. We shouldn't need to check for uses being loads/stores,
21505ffd83dbSDimitry Andric /// because the selector works bottom up, uses before defs. By the time we
21515ffd83dbSDimitry Andric /// end up trying to select a G_PTR_ADD, we should have already attempted to
21525ffd83dbSDimitry Andric /// fold this into addressing modes and were therefore unsuccessful.
convertPtrAddToAdd(MachineInstr & I,MachineRegisterInfo & MRI)21535ffd83dbSDimitry Andric bool AArch64InstructionSelector::convertPtrAddToAdd(
21545ffd83dbSDimitry Andric     MachineInstr &I, MachineRegisterInfo &MRI) {
21555ffd83dbSDimitry Andric   assert(I.getOpcode() == TargetOpcode::G_PTR_ADD && "Expected G_PTR_ADD");
21565ffd83dbSDimitry Andric   Register DstReg = I.getOperand(0).getReg();
21575ffd83dbSDimitry Andric   Register AddOp1Reg = I.getOperand(1).getReg();
21585ffd83dbSDimitry Andric   const LLT PtrTy = MRI.getType(DstReg);
21595ffd83dbSDimitry Andric   if (PtrTy.getAddressSpace() != 0)
21605ffd83dbSDimitry Andric     return false;
21615ffd83dbSDimitry Andric 
2162fe6060f1SDimitry Andric   const LLT CastPtrTy =
2163fe6060f1SDimitry Andric       PtrTy.isVector() ? LLT::fixed_vector(2, 64) : LLT::scalar(64);
21645ffd83dbSDimitry Andric   auto PtrToInt = MIB.buildPtrToInt(CastPtrTy, AddOp1Reg);
21655ffd83dbSDimitry Andric   // Set regbanks on the registers.
21665ffd83dbSDimitry Andric   if (PtrTy.isVector())
21675ffd83dbSDimitry Andric     MRI.setRegBank(PtrToInt.getReg(0), RBI.getRegBank(AArch64::FPRRegBankID));
21685ffd83dbSDimitry Andric   else
21695ffd83dbSDimitry Andric     MRI.setRegBank(PtrToInt.getReg(0), RBI.getRegBank(AArch64::GPRRegBankID));
21705ffd83dbSDimitry Andric 
21715ffd83dbSDimitry Andric   // Now turn the %dst(p0) = G_PTR_ADD %base, off into:
21725ffd83dbSDimitry Andric   // %dst(intty) = G_ADD %intbase, off
21735ffd83dbSDimitry Andric   I.setDesc(TII.get(TargetOpcode::G_ADD));
21745ffd83dbSDimitry Andric   MRI.setType(DstReg, CastPtrTy);
21755ffd83dbSDimitry Andric   I.getOperand(1).setReg(PtrToInt.getReg(0));
21765ffd83dbSDimitry Andric   if (!select(*PtrToInt)) {
21775ffd83dbSDimitry Andric     LLVM_DEBUG(dbgs() << "Failed to select G_PTRTOINT in convertPtrAddToAdd");
21785ffd83dbSDimitry Andric     return false;
21795ffd83dbSDimitry Andric   }
2180e8d8bef9SDimitry Andric 
2181e8d8bef9SDimitry Andric   // Also take the opportunity here to try to do some optimization.
2182e8d8bef9SDimitry Andric   // Try to convert this into a G_SUB if the offset is a 0-x negate idiom.
2183e8d8bef9SDimitry Andric   Register NegatedReg;
2184e8d8bef9SDimitry Andric   if (!mi_match(I.getOperand(2).getReg(), MRI, m_Neg(m_Reg(NegatedReg))))
2185e8d8bef9SDimitry Andric     return true;
2186e8d8bef9SDimitry Andric   I.getOperand(2).setReg(NegatedReg);
2187e8d8bef9SDimitry Andric   I.setDesc(TII.get(TargetOpcode::G_SUB));
21885ffd83dbSDimitry Andric   return true;
21895ffd83dbSDimitry Andric }
21905ffd83dbSDimitry Andric 
earlySelectSHL(MachineInstr & I,MachineRegisterInfo & MRI)2191fe6060f1SDimitry Andric bool AArch64InstructionSelector::earlySelectSHL(MachineInstr &I,
2192fe6060f1SDimitry Andric                                                 MachineRegisterInfo &MRI) {
21935ffd83dbSDimitry Andric   // We try to match the immediate variant of LSL, which is actually an alias
21945ffd83dbSDimitry Andric   // for a special case of UBFM. Otherwise, we fall back to the imported
21955ffd83dbSDimitry Andric   // selector which will match the register variant.
21965ffd83dbSDimitry Andric   assert(I.getOpcode() == TargetOpcode::G_SHL && "unexpected op");
21975ffd83dbSDimitry Andric   const auto &MO = I.getOperand(2);
2198349cc55cSDimitry Andric   auto VRegAndVal = getIConstantVRegVal(MO.getReg(), MRI);
21995ffd83dbSDimitry Andric   if (!VRegAndVal)
22005ffd83dbSDimitry Andric     return false;
22015ffd83dbSDimitry Andric 
22025ffd83dbSDimitry Andric   const LLT DstTy = MRI.getType(I.getOperand(0).getReg());
22035ffd83dbSDimitry Andric   if (DstTy.isVector())
22045ffd83dbSDimitry Andric     return false;
22055ffd83dbSDimitry Andric   bool Is64Bit = DstTy.getSizeInBits() == 64;
22065ffd83dbSDimitry Andric   auto Imm1Fn = Is64Bit ? selectShiftA_64(MO) : selectShiftA_32(MO);
22075ffd83dbSDimitry Andric   auto Imm2Fn = Is64Bit ? selectShiftB_64(MO) : selectShiftB_32(MO);
22085ffd83dbSDimitry Andric 
22095ffd83dbSDimitry Andric   if (!Imm1Fn || !Imm2Fn)
22105ffd83dbSDimitry Andric     return false;
22115ffd83dbSDimitry Andric 
22125ffd83dbSDimitry Andric   auto NewI =
22135ffd83dbSDimitry Andric       MIB.buildInstr(Is64Bit ? AArch64::UBFMXri : AArch64::UBFMWri,
22145ffd83dbSDimitry Andric                      {I.getOperand(0).getReg()}, {I.getOperand(1).getReg()});
22155ffd83dbSDimitry Andric 
22165ffd83dbSDimitry Andric   for (auto &RenderFn : *Imm1Fn)
22175ffd83dbSDimitry Andric     RenderFn(NewI);
22185ffd83dbSDimitry Andric   for (auto &RenderFn : *Imm2Fn)
22195ffd83dbSDimitry Andric     RenderFn(NewI);
22205ffd83dbSDimitry Andric 
22215ffd83dbSDimitry Andric   I.eraseFromParent();
22225ffd83dbSDimitry Andric   return constrainSelectedInstRegOperands(*NewI, TII, TRI, RBI);
22235ffd83dbSDimitry Andric }
22245ffd83dbSDimitry Andric 
contractCrossBankCopyIntoStore(MachineInstr & I,MachineRegisterInfo & MRI)22255ffd83dbSDimitry Andric bool AArch64InstructionSelector::contractCrossBankCopyIntoStore(
22265ffd83dbSDimitry Andric     MachineInstr &I, MachineRegisterInfo &MRI) {
22275ffd83dbSDimitry Andric   assert(I.getOpcode() == TargetOpcode::G_STORE && "Expected G_STORE");
22285ffd83dbSDimitry Andric   // If we're storing a scalar, it doesn't matter what register bank that
22295ffd83dbSDimitry Andric   // scalar is on. All that matters is the size.
22305ffd83dbSDimitry Andric   //
22315ffd83dbSDimitry Andric   // So, if we see something like this (with a 32-bit scalar as an example):
22325ffd83dbSDimitry Andric   //
22335ffd83dbSDimitry Andric   // %x:gpr(s32) = ... something ...
22345ffd83dbSDimitry Andric   // %y:fpr(s32) = COPY %x:gpr(s32)
22355ffd83dbSDimitry Andric   // G_STORE %y:fpr(s32)
22365ffd83dbSDimitry Andric   //
22375ffd83dbSDimitry Andric   // We can fix this up into something like this:
22385ffd83dbSDimitry Andric   //
22395ffd83dbSDimitry Andric   // G_STORE %x:gpr(s32)
22405ffd83dbSDimitry Andric   //
22415ffd83dbSDimitry Andric   // And then continue the selection process normally.
22425ffd83dbSDimitry Andric   Register DefDstReg = getSrcRegIgnoringCopies(I.getOperand(0).getReg(), MRI);
22435ffd83dbSDimitry Andric   if (!DefDstReg.isValid())
22445ffd83dbSDimitry Andric     return false;
22455ffd83dbSDimitry Andric   LLT DefDstTy = MRI.getType(DefDstReg);
22465ffd83dbSDimitry Andric   Register StoreSrcReg = I.getOperand(0).getReg();
22475ffd83dbSDimitry Andric   LLT StoreSrcTy = MRI.getType(StoreSrcReg);
22485ffd83dbSDimitry Andric 
22495ffd83dbSDimitry Andric   // If we get something strange like a physical register, then we shouldn't
22505ffd83dbSDimitry Andric   // go any further.
22515ffd83dbSDimitry Andric   if (!DefDstTy.isValid())
22525ffd83dbSDimitry Andric     return false;
22535ffd83dbSDimitry Andric 
22545ffd83dbSDimitry Andric   // Are the source and dst types the same size?
22555ffd83dbSDimitry Andric   if (DefDstTy.getSizeInBits() != StoreSrcTy.getSizeInBits())
22565ffd83dbSDimitry Andric     return false;
22575ffd83dbSDimitry Andric 
22585ffd83dbSDimitry Andric   if (RBI.getRegBank(StoreSrcReg, MRI, TRI) ==
22595ffd83dbSDimitry Andric       RBI.getRegBank(DefDstReg, MRI, TRI))
22605ffd83dbSDimitry Andric     return false;
22615ffd83dbSDimitry Andric 
22625ffd83dbSDimitry Andric   // We have a cross-bank copy, which is entering a store. Let's fold it.
22635ffd83dbSDimitry Andric   I.getOperand(0).setReg(DefDstReg);
22645ffd83dbSDimitry Andric   return true;
22655ffd83dbSDimitry Andric }
22665ffd83dbSDimitry Andric 
earlySelect(MachineInstr & I)2267fe6060f1SDimitry Andric bool AArch64InstructionSelector::earlySelect(MachineInstr &I) {
22685ffd83dbSDimitry Andric   assert(I.getParent() && "Instruction should be in a basic block!");
22695ffd83dbSDimitry Andric   assert(I.getParent()->getParent() && "Instruction should be in a function!");
22705ffd83dbSDimitry Andric 
22715ffd83dbSDimitry Andric   MachineBasicBlock &MBB = *I.getParent();
22725ffd83dbSDimitry Andric   MachineFunction &MF = *MBB.getParent();
22735ffd83dbSDimitry Andric   MachineRegisterInfo &MRI = MF.getRegInfo();
22745ffd83dbSDimitry Andric 
22755ffd83dbSDimitry Andric   switch (I.getOpcode()) {
2276fe6060f1SDimitry Andric   case AArch64::G_DUP: {
2277fe6060f1SDimitry Andric     // Before selecting a DUP instruction, check if it is better selected as a
2278fe6060f1SDimitry Andric     // MOV or load from a constant pool.
2279fe6060f1SDimitry Andric     Register Src = I.getOperand(1).getReg();
22805f757f3fSDimitry Andric     auto ValAndVReg = getAnyConstantVRegValWithLookThrough(Src, MRI);
2281fe6060f1SDimitry Andric     if (!ValAndVReg)
2282fe6060f1SDimitry Andric       return false;
2283fe6060f1SDimitry Andric     LLVMContext &Ctx = MF.getFunction().getContext();
2284fe6060f1SDimitry Andric     Register Dst = I.getOperand(0).getReg();
2285fe6060f1SDimitry Andric     auto *CV = ConstantDataVector::getSplat(
2286fe6060f1SDimitry Andric         MRI.getType(Dst).getNumElements(),
2287fe6060f1SDimitry Andric         ConstantInt::get(Type::getIntNTy(Ctx, MRI.getType(Src).getSizeInBits()),
2288fe6060f1SDimitry Andric                          ValAndVReg->Value));
2289fe6060f1SDimitry Andric     if (!emitConstantVector(Dst, CV, MIB, MRI))
2290fe6060f1SDimitry Andric       return false;
2291fe6060f1SDimitry Andric     I.eraseFromParent();
2292fe6060f1SDimitry Andric     return true;
2293fe6060f1SDimitry Andric   }
2294349cc55cSDimitry Andric   case TargetOpcode::G_SEXT:
2295349cc55cSDimitry Andric     // Check for i64 sext(i32 vector_extract) prior to tablegen to select SMOV
2296349cc55cSDimitry Andric     // over a normal extend.
2297349cc55cSDimitry Andric     if (selectUSMovFromExtend(I, MRI))
2298e8d8bef9SDimitry Andric       return true;
2299349cc55cSDimitry Andric     return false;
2300349cc55cSDimitry Andric   case TargetOpcode::G_BR:
2301349cc55cSDimitry Andric     return false;
23025ffd83dbSDimitry Andric   case TargetOpcode::G_SHL:
23035ffd83dbSDimitry Andric     return earlySelectSHL(I, MRI);
23045ffd83dbSDimitry Andric   case TargetOpcode::G_CONSTANT: {
23055ffd83dbSDimitry Andric     bool IsZero = false;
23065ffd83dbSDimitry Andric     if (I.getOperand(1).isCImm())
230706c3fb27SDimitry Andric       IsZero = I.getOperand(1).getCImm()->isZero();
23085ffd83dbSDimitry Andric     else if (I.getOperand(1).isImm())
23095ffd83dbSDimitry Andric       IsZero = I.getOperand(1).getImm() == 0;
23105ffd83dbSDimitry Andric 
23115ffd83dbSDimitry Andric     if (!IsZero)
23125ffd83dbSDimitry Andric       return false;
23135ffd83dbSDimitry Andric 
23145ffd83dbSDimitry Andric     Register DefReg = I.getOperand(0).getReg();
23155ffd83dbSDimitry Andric     LLT Ty = MRI.getType(DefReg);
23165ffd83dbSDimitry Andric     if (Ty.getSizeInBits() == 64) {
23175ffd83dbSDimitry Andric       I.getOperand(1).ChangeToRegister(AArch64::XZR, false);
23185ffd83dbSDimitry Andric       RBI.constrainGenericRegister(DefReg, AArch64::GPR64RegClass, MRI);
23195ffd83dbSDimitry Andric     } else if (Ty.getSizeInBits() == 32) {
23205ffd83dbSDimitry Andric       I.getOperand(1).ChangeToRegister(AArch64::WZR, false);
23215ffd83dbSDimitry Andric       RBI.constrainGenericRegister(DefReg, AArch64::GPR32RegClass, MRI);
23225ffd83dbSDimitry Andric     } else
23235ffd83dbSDimitry Andric       return false;
23245ffd83dbSDimitry Andric 
23255ffd83dbSDimitry Andric     I.setDesc(TII.get(TargetOpcode::COPY));
23265ffd83dbSDimitry Andric     return true;
23275ffd83dbSDimitry Andric   }
2328fe6060f1SDimitry Andric 
2329fe6060f1SDimitry Andric   case TargetOpcode::G_ADD: {
2330fe6060f1SDimitry Andric     // Check if this is being fed by a G_ICMP on either side.
2331fe6060f1SDimitry Andric     //
2332fe6060f1SDimitry Andric     // (cmp pred, x, y) + z
2333fe6060f1SDimitry Andric     //
2334fe6060f1SDimitry Andric     // In the above case, when the cmp is true, we increment z by 1. So, we can
2335fe6060f1SDimitry Andric     // fold the add into the cset for the cmp by using cinc.
2336fe6060f1SDimitry Andric     //
2337fe6060f1SDimitry Andric     // FIXME: This would probably be a lot nicer in PostLegalizerLowering.
2338349cc55cSDimitry Andric     Register AddDst = I.getOperand(0).getReg();
2339349cc55cSDimitry Andric     Register AddLHS = I.getOperand(1).getReg();
2340349cc55cSDimitry Andric     Register AddRHS = I.getOperand(2).getReg();
2341349cc55cSDimitry Andric     // Only handle scalars.
2342349cc55cSDimitry Andric     LLT Ty = MRI.getType(AddLHS);
2343349cc55cSDimitry Andric     if (Ty.isVector())
2344fe6060f1SDimitry Andric       return false;
2345349cc55cSDimitry Andric     // Since G_ICMP is modeled as ADDS/SUBS/ANDS, we can handle 32 bits or 64
2346349cc55cSDimitry Andric     // bits.
2347349cc55cSDimitry Andric     unsigned Size = Ty.getSizeInBits();
2348349cc55cSDimitry Andric     if (Size != 32 && Size != 64)
2349349cc55cSDimitry Andric       return false;
2350349cc55cSDimitry Andric     auto MatchCmp = [&](Register Reg) -> MachineInstr * {
2351349cc55cSDimitry Andric       if (!MRI.hasOneNonDBGUse(Reg))
2352349cc55cSDimitry Andric         return nullptr;
2353349cc55cSDimitry Andric       // If the LHS of the add is 32 bits, then we want to fold a 32-bit
2354349cc55cSDimitry Andric       // compare.
2355349cc55cSDimitry Andric       if (Size == 32)
2356349cc55cSDimitry Andric         return getOpcodeDef(TargetOpcode::G_ICMP, Reg, MRI);
2357349cc55cSDimitry Andric       // We model scalar compares using 32-bit destinations right now.
2358349cc55cSDimitry Andric       // If it's a 64-bit compare, it'll have 64-bit sources.
2359349cc55cSDimitry Andric       Register ZExt;
2360349cc55cSDimitry Andric       if (!mi_match(Reg, MRI,
2361349cc55cSDimitry Andric                     m_OneNonDBGUse(m_GZExt(m_OneNonDBGUse(m_Reg(ZExt))))))
2362349cc55cSDimitry Andric         return nullptr;
2363349cc55cSDimitry Andric       auto *Cmp = getOpcodeDef(TargetOpcode::G_ICMP, ZExt, MRI);
2364349cc55cSDimitry Andric       if (!Cmp ||
2365349cc55cSDimitry Andric           MRI.getType(Cmp->getOperand(2).getReg()).getSizeInBits() != 64)
2366349cc55cSDimitry Andric         return nullptr;
2367349cc55cSDimitry Andric       return Cmp;
2368349cc55cSDimitry Andric     };
2369349cc55cSDimitry Andric     // Try to match
2370349cc55cSDimitry Andric     // z + (cmp pred, x, y)
2371349cc55cSDimitry Andric     MachineInstr *Cmp = MatchCmp(AddRHS);
2372fe6060f1SDimitry Andric     if (!Cmp) {
2373349cc55cSDimitry Andric       // (cmp pred, x, y) + z
2374349cc55cSDimitry Andric       std::swap(AddLHS, AddRHS);
2375349cc55cSDimitry Andric       Cmp = MatchCmp(AddRHS);
2376fe6060f1SDimitry Andric       if (!Cmp)
2377fe6060f1SDimitry Andric         return false;
2378fe6060f1SDimitry Andric     }
2379349cc55cSDimitry Andric     auto &PredOp = Cmp->getOperand(1);
2380349cc55cSDimitry Andric     auto Pred = static_cast<CmpInst::Predicate>(PredOp.getPredicate());
2381349cc55cSDimitry Andric     const AArch64CC::CondCode InvCC =
2382349cc55cSDimitry Andric         changeICMPPredToAArch64CC(CmpInst::getInversePredicate(Pred));
2383349cc55cSDimitry Andric     MIB.setInstrAndDebugLoc(I);
2384349cc55cSDimitry Andric     emitIntegerCompare(/*LHS=*/Cmp->getOperand(2),
2385349cc55cSDimitry Andric                        /*RHS=*/Cmp->getOperand(3), PredOp, MIB);
2386349cc55cSDimitry Andric     emitCSINC(/*Dst=*/AddDst, /*Src =*/AddLHS, /*Src2=*/AddLHS, InvCC, MIB);
2387fe6060f1SDimitry Andric     I.eraseFromParent();
2388fe6060f1SDimitry Andric     return true;
2389fe6060f1SDimitry Andric   }
2390fe6060f1SDimitry Andric   case TargetOpcode::G_OR: {
2391fe6060f1SDimitry Andric     // Look for operations that take the lower `Width=Size-ShiftImm` bits of
2392fe6060f1SDimitry Andric     // `ShiftSrc` and insert them into the upper `Width` bits of `MaskSrc` via
2393fe6060f1SDimitry Andric     // shifting and masking that we can replace with a BFI (encoded as a BFM).
2394fe6060f1SDimitry Andric     Register Dst = I.getOperand(0).getReg();
2395fe6060f1SDimitry Andric     LLT Ty = MRI.getType(Dst);
2396fe6060f1SDimitry Andric 
2397fe6060f1SDimitry Andric     if (!Ty.isScalar())
2398fe6060f1SDimitry Andric       return false;
2399fe6060f1SDimitry Andric 
2400fe6060f1SDimitry Andric     unsigned Size = Ty.getSizeInBits();
2401fe6060f1SDimitry Andric     if (Size != 32 && Size != 64)
2402fe6060f1SDimitry Andric       return false;
2403fe6060f1SDimitry Andric 
2404fe6060f1SDimitry Andric     Register ShiftSrc;
2405fe6060f1SDimitry Andric     int64_t ShiftImm;
2406fe6060f1SDimitry Andric     Register MaskSrc;
2407fe6060f1SDimitry Andric     int64_t MaskImm;
2408fe6060f1SDimitry Andric     if (!mi_match(
2409fe6060f1SDimitry Andric             Dst, MRI,
2410fe6060f1SDimitry Andric             m_GOr(m_OneNonDBGUse(m_GShl(m_Reg(ShiftSrc), m_ICst(ShiftImm))),
2411fe6060f1SDimitry Andric                   m_OneNonDBGUse(m_GAnd(m_Reg(MaskSrc), m_ICst(MaskImm))))))
2412fe6060f1SDimitry Andric       return false;
2413fe6060f1SDimitry Andric 
2414fe6060f1SDimitry Andric     if (ShiftImm > Size || ((1ULL << ShiftImm) - 1ULL) != uint64_t(MaskImm))
2415fe6060f1SDimitry Andric       return false;
2416fe6060f1SDimitry Andric 
2417fe6060f1SDimitry Andric     int64_t Immr = Size - ShiftImm;
2418fe6060f1SDimitry Andric     int64_t Imms = Size - ShiftImm - 1;
2419fe6060f1SDimitry Andric     unsigned Opc = Size == 32 ? AArch64::BFMWri : AArch64::BFMXri;
2420fe6060f1SDimitry Andric     emitInstr(Opc, {Dst}, {MaskSrc, ShiftSrc, Immr, Imms}, MIB);
2421fe6060f1SDimitry Andric     I.eraseFromParent();
2422fe6060f1SDimitry Andric     return true;
2423fe6060f1SDimitry Andric   }
242481ad6265SDimitry Andric   case TargetOpcode::G_FENCE: {
242581ad6265SDimitry Andric     if (I.getOperand(1).getImm() == 0)
2426bdd1243dSDimitry Andric       BuildMI(MBB, I, MIMetadata(I), TII.get(TargetOpcode::MEMBARRIER));
242781ad6265SDimitry Andric     else
2428bdd1243dSDimitry Andric       BuildMI(MBB, I, MIMetadata(I), TII.get(AArch64::DMB))
242981ad6265SDimitry Andric           .addImm(I.getOperand(0).getImm() == 4 ? 0x9 : 0xb);
243081ad6265SDimitry Andric     I.eraseFromParent();
243181ad6265SDimitry Andric     return true;
243281ad6265SDimitry Andric   }
24335ffd83dbSDimitry Andric   default:
24345ffd83dbSDimitry Andric     return false;
24355ffd83dbSDimitry Andric   }
24365ffd83dbSDimitry Andric }
24375ffd83dbSDimitry Andric 
select(MachineInstr & I)24385ffd83dbSDimitry Andric bool AArch64InstructionSelector::select(MachineInstr &I) {
24395ffd83dbSDimitry Andric   assert(I.getParent() && "Instruction should be in a basic block!");
24405ffd83dbSDimitry Andric   assert(I.getParent()->getParent() && "Instruction should be in a function!");
24415ffd83dbSDimitry Andric 
24425ffd83dbSDimitry Andric   MachineBasicBlock &MBB = *I.getParent();
24435ffd83dbSDimitry Andric   MachineFunction &MF = *MBB.getParent();
24445ffd83dbSDimitry Andric   MachineRegisterInfo &MRI = MF.getRegInfo();
24455ffd83dbSDimitry Andric 
244681ad6265SDimitry Andric   const AArch64Subtarget *Subtarget = &MF.getSubtarget<AArch64Subtarget>();
24475ffd83dbSDimitry Andric   if (Subtarget->requiresStrictAlign()) {
24485ffd83dbSDimitry Andric     // We don't support this feature yet.
24495ffd83dbSDimitry Andric     LLVM_DEBUG(dbgs() << "AArch64 GISel does not support strict-align yet\n");
24505ffd83dbSDimitry Andric     return false;
24515ffd83dbSDimitry Andric   }
24525ffd83dbSDimitry Andric 
2453fe6060f1SDimitry Andric   MIB.setInstrAndDebugLoc(I);
2454fe6060f1SDimitry Andric 
24555ffd83dbSDimitry Andric   unsigned Opcode = I.getOpcode();
24565ffd83dbSDimitry Andric   // G_PHI requires same handling as PHI
24575ffd83dbSDimitry Andric   if (!I.isPreISelOpcode() || Opcode == TargetOpcode::G_PHI) {
24585ffd83dbSDimitry Andric     // Certain non-generic instructions also need some special handling.
24595ffd83dbSDimitry Andric 
24605ffd83dbSDimitry Andric     if (Opcode ==  TargetOpcode::LOAD_STACK_GUARD)
24615ffd83dbSDimitry Andric       return constrainSelectedInstRegOperands(I, TII, TRI, RBI);
24625ffd83dbSDimitry Andric 
24635ffd83dbSDimitry Andric     if (Opcode == TargetOpcode::PHI || Opcode == TargetOpcode::G_PHI) {
24645ffd83dbSDimitry Andric       const Register DefReg = I.getOperand(0).getReg();
24655ffd83dbSDimitry Andric       const LLT DefTy = MRI.getType(DefReg);
24665ffd83dbSDimitry Andric 
24675ffd83dbSDimitry Andric       const RegClassOrRegBank &RegClassOrBank =
24685ffd83dbSDimitry Andric         MRI.getRegClassOrRegBank(DefReg);
24695ffd83dbSDimitry Andric 
24705ffd83dbSDimitry Andric       const TargetRegisterClass *DefRC
24715ffd83dbSDimitry Andric         = RegClassOrBank.dyn_cast<const TargetRegisterClass *>();
24725ffd83dbSDimitry Andric       if (!DefRC) {
24735ffd83dbSDimitry Andric         if (!DefTy.isValid()) {
24745ffd83dbSDimitry Andric           LLVM_DEBUG(dbgs() << "PHI operand has no type, not a gvreg?\n");
24755ffd83dbSDimitry Andric           return false;
24765ffd83dbSDimitry Andric         }
24775ffd83dbSDimitry Andric         const RegisterBank &RB = *RegClassOrBank.get<const RegisterBank *>();
247881ad6265SDimitry Andric         DefRC = getRegClassForTypeOnBank(DefTy, RB);
24795ffd83dbSDimitry Andric         if (!DefRC) {
24805ffd83dbSDimitry Andric           LLVM_DEBUG(dbgs() << "PHI operand has unexpected size/bank\n");
24815ffd83dbSDimitry Andric           return false;
24825ffd83dbSDimitry Andric         }
24835ffd83dbSDimitry Andric       }
24845ffd83dbSDimitry Andric 
24855ffd83dbSDimitry Andric       I.setDesc(TII.get(TargetOpcode::PHI));
24865ffd83dbSDimitry Andric 
24875ffd83dbSDimitry Andric       return RBI.constrainGenericRegister(DefReg, *DefRC, MRI);
24885ffd83dbSDimitry Andric     }
24895ffd83dbSDimitry Andric 
24905ffd83dbSDimitry Andric     if (I.isCopy())
24915ffd83dbSDimitry Andric       return selectCopy(I, TII, MRI, TRI, RBI);
24925ffd83dbSDimitry Andric 
2493bdd1243dSDimitry Andric     if (I.isDebugInstr())
2494bdd1243dSDimitry Andric       return selectDebugInstr(I, MRI, RBI);
2495bdd1243dSDimitry Andric 
24965ffd83dbSDimitry Andric     return true;
24975ffd83dbSDimitry Andric   }
24985ffd83dbSDimitry Andric 
24995ffd83dbSDimitry Andric 
25005ffd83dbSDimitry Andric   if (I.getNumOperands() != I.getNumExplicitOperands()) {
25015ffd83dbSDimitry Andric     LLVM_DEBUG(
25025ffd83dbSDimitry Andric         dbgs() << "Generic instruction has unexpected implicit operands\n");
25035ffd83dbSDimitry Andric     return false;
25045ffd83dbSDimitry Andric   }
25055ffd83dbSDimitry Andric 
25065ffd83dbSDimitry Andric   // Try to do some lowering before we start instruction selecting. These
25075ffd83dbSDimitry Andric   // lowerings are purely transformations on the input G_MIR and so selection
25085ffd83dbSDimitry Andric   // must continue after any modification of the instruction.
25095ffd83dbSDimitry Andric   if (preISelLower(I)) {
25105ffd83dbSDimitry Andric     Opcode = I.getOpcode(); // The opcode may have been modified, refresh it.
25115ffd83dbSDimitry Andric   }
25125ffd83dbSDimitry Andric 
25135ffd83dbSDimitry Andric   // There may be patterns where the importer can't deal with them optimally,
25145ffd83dbSDimitry Andric   // but does select it to a suboptimal sequence so our custom C++ selection
25155ffd83dbSDimitry Andric   // code later never has a chance to work on it. Therefore, we have an early
25165ffd83dbSDimitry Andric   // selection attempt here to give priority to certain selection routines
25175ffd83dbSDimitry Andric   // over the imported ones.
25185ffd83dbSDimitry Andric   if (earlySelect(I))
25195ffd83dbSDimitry Andric     return true;
25205ffd83dbSDimitry Andric 
25215ffd83dbSDimitry Andric   if (selectImpl(I, *CoverageInfo))
25225ffd83dbSDimitry Andric     return true;
25235ffd83dbSDimitry Andric 
25245ffd83dbSDimitry Andric   LLT Ty =
25255ffd83dbSDimitry Andric       I.getOperand(0).isReg() ? MRI.getType(I.getOperand(0).getReg()) : LLT{};
25265ffd83dbSDimitry Andric 
25275ffd83dbSDimitry Andric   switch (Opcode) {
2528fe6060f1SDimitry Andric   case TargetOpcode::G_SBFX:
2529fe6060f1SDimitry Andric   case TargetOpcode::G_UBFX: {
2530fe6060f1SDimitry Andric     static const unsigned OpcTable[2][2] = {
2531fe6060f1SDimitry Andric         {AArch64::UBFMWri, AArch64::UBFMXri},
2532fe6060f1SDimitry Andric         {AArch64::SBFMWri, AArch64::SBFMXri}};
2533fe6060f1SDimitry Andric     bool IsSigned = Opcode == TargetOpcode::G_SBFX;
2534fe6060f1SDimitry Andric     unsigned Size = Ty.getSizeInBits();
2535fe6060f1SDimitry Andric     unsigned Opc = OpcTable[IsSigned][Size == 64];
2536fe6060f1SDimitry Andric     auto Cst1 =
2537349cc55cSDimitry Andric         getIConstantVRegValWithLookThrough(I.getOperand(2).getReg(), MRI);
2538fe6060f1SDimitry Andric     assert(Cst1 && "Should have gotten a constant for src 1?");
2539fe6060f1SDimitry Andric     auto Cst2 =
2540349cc55cSDimitry Andric         getIConstantVRegValWithLookThrough(I.getOperand(3).getReg(), MRI);
2541fe6060f1SDimitry Andric     assert(Cst2 && "Should have gotten a constant for src 2?");
2542fe6060f1SDimitry Andric     auto LSB = Cst1->Value.getZExtValue();
2543fe6060f1SDimitry Andric     auto Width = Cst2->Value.getZExtValue();
2544fe6060f1SDimitry Andric     auto BitfieldInst =
2545fe6060f1SDimitry Andric         MIB.buildInstr(Opc, {I.getOperand(0)}, {I.getOperand(1)})
2546fe6060f1SDimitry Andric             .addImm(LSB)
2547fe6060f1SDimitry Andric             .addImm(LSB + Width - 1);
2548fe6060f1SDimitry Andric     I.eraseFromParent();
2549fe6060f1SDimitry Andric     return constrainSelectedInstRegOperands(*BitfieldInst, TII, TRI, RBI);
2550fe6060f1SDimitry Andric   }
2551e8d8bef9SDimitry Andric   case TargetOpcode::G_BRCOND:
2552e8d8bef9SDimitry Andric     return selectCompareBranch(I, MF, MRI);
25535ffd83dbSDimitry Andric 
25545ffd83dbSDimitry Andric   case TargetOpcode::G_BRINDIRECT: {
2555*0fca6ea1SDimitry Andric     const Function &Fn = MF.getFunction();
2556*0fca6ea1SDimitry Andric     if (std::optional<uint16_t> BADisc =
2557*0fca6ea1SDimitry Andric             STI.getPtrAuthBlockAddressDiscriminatorIfEnabled(Fn)) {
2558*0fca6ea1SDimitry Andric       auto MI = MIB.buildInstr(AArch64::BRA, {}, {I.getOperand(0).getReg()});
2559*0fca6ea1SDimitry Andric       MI.addImm(AArch64PACKey::IA);
2560*0fca6ea1SDimitry Andric       MI.addImm(*BADisc);
2561*0fca6ea1SDimitry Andric       MI.addReg(/*AddrDisc=*/AArch64::XZR);
2562*0fca6ea1SDimitry Andric       I.eraseFromParent();
2563*0fca6ea1SDimitry Andric       return constrainSelectedInstRegOperands(*MI, TII, TRI, RBI);
2564*0fca6ea1SDimitry Andric     }
25655ffd83dbSDimitry Andric     I.setDesc(TII.get(AArch64::BR));
25665ffd83dbSDimitry Andric     return constrainSelectedInstRegOperands(I, TII, TRI, RBI);
25675ffd83dbSDimitry Andric   }
25685ffd83dbSDimitry Andric 
25695ffd83dbSDimitry Andric   case TargetOpcode::G_BRJT:
25705ffd83dbSDimitry Andric     return selectBrJT(I, MRI);
25715ffd83dbSDimitry Andric 
25725ffd83dbSDimitry Andric   case AArch64::G_ADD_LOW: {
25735ffd83dbSDimitry Andric     // This op may have been separated from it's ADRP companion by the localizer
25745ffd83dbSDimitry Andric     // or some other code motion pass. Given that many CPUs will try to
25755ffd83dbSDimitry Andric     // macro fuse these operations anyway, select this into a MOVaddr pseudo
25765ffd83dbSDimitry Andric     // which will later be expanded into an ADRP+ADD pair after scheduling.
25775ffd83dbSDimitry Andric     MachineInstr *BaseMI = MRI.getVRegDef(I.getOperand(1).getReg());
25785ffd83dbSDimitry Andric     if (BaseMI->getOpcode() != AArch64::ADRP) {
25795ffd83dbSDimitry Andric       I.setDesc(TII.get(AArch64::ADDXri));
25805ffd83dbSDimitry Andric       I.addOperand(MachineOperand::CreateImm(0));
25815ffd83dbSDimitry Andric       return constrainSelectedInstRegOperands(I, TII, TRI, RBI);
25825ffd83dbSDimitry Andric     }
25835ffd83dbSDimitry Andric     assert(TM.getCodeModel() == CodeModel::Small &&
25845ffd83dbSDimitry Andric            "Expected small code model");
25855ffd83dbSDimitry Andric     auto Op1 = BaseMI->getOperand(1);
25865ffd83dbSDimitry Andric     auto Op2 = I.getOperand(2);
25875ffd83dbSDimitry Andric     auto MovAddr = MIB.buildInstr(AArch64::MOVaddr, {I.getOperand(0)}, {})
25885ffd83dbSDimitry Andric                        .addGlobalAddress(Op1.getGlobal(), Op1.getOffset(),
25895ffd83dbSDimitry Andric                                          Op1.getTargetFlags())
25905ffd83dbSDimitry Andric                        .addGlobalAddress(Op2.getGlobal(), Op2.getOffset(),
25915ffd83dbSDimitry Andric                                          Op2.getTargetFlags());
25925ffd83dbSDimitry Andric     I.eraseFromParent();
25935ffd83dbSDimitry Andric     return constrainSelectedInstRegOperands(*MovAddr, TII, TRI, RBI);
25945ffd83dbSDimitry Andric   }
25955ffd83dbSDimitry Andric 
25965ffd83dbSDimitry Andric   case TargetOpcode::G_FCONSTANT:
25975ffd83dbSDimitry Andric   case TargetOpcode::G_CONSTANT: {
25985ffd83dbSDimitry Andric     const bool isFP = Opcode == TargetOpcode::G_FCONSTANT;
25995ffd83dbSDimitry Andric 
26005ffd83dbSDimitry Andric     const LLT s8 = LLT::scalar(8);
26015ffd83dbSDimitry Andric     const LLT s16 = LLT::scalar(16);
26025ffd83dbSDimitry Andric     const LLT s32 = LLT::scalar(32);
26035ffd83dbSDimitry Andric     const LLT s64 = LLT::scalar(64);
2604e8d8bef9SDimitry Andric     const LLT s128 = LLT::scalar(128);
26055ffd83dbSDimitry Andric     const LLT p0 = LLT::pointer(0, 64);
26065ffd83dbSDimitry Andric 
26075ffd83dbSDimitry Andric     const Register DefReg = I.getOperand(0).getReg();
26085ffd83dbSDimitry Andric     const LLT DefTy = MRI.getType(DefReg);
26095ffd83dbSDimitry Andric     const unsigned DefSize = DefTy.getSizeInBits();
26105ffd83dbSDimitry Andric     const RegisterBank &RB = *RBI.getRegBank(DefReg, MRI, TRI);
26115ffd83dbSDimitry Andric 
26125ffd83dbSDimitry Andric     // FIXME: Redundant check, but even less readable when factored out.
26135ffd83dbSDimitry Andric     if (isFP) {
2614349cc55cSDimitry Andric       if (Ty != s16 && Ty != s32 && Ty != s64 && Ty != s128) {
26155ffd83dbSDimitry Andric         LLVM_DEBUG(dbgs() << "Unable to materialize FP " << Ty
2616349cc55cSDimitry Andric                           << " constant, expected: " << s16 << " or " << s32
2617349cc55cSDimitry Andric                           << " or " << s64 << " or " << s128 << '\n');
26185ffd83dbSDimitry Andric         return false;
26195ffd83dbSDimitry Andric       }
26205ffd83dbSDimitry Andric 
26215ffd83dbSDimitry Andric       if (RB.getID() != AArch64::FPRRegBankID) {
26225ffd83dbSDimitry Andric         LLVM_DEBUG(dbgs() << "Unable to materialize FP " << Ty
26235ffd83dbSDimitry Andric                           << " constant on bank: " << RB
26245ffd83dbSDimitry Andric                           << ", expected: FPR\n");
26255ffd83dbSDimitry Andric         return false;
26265ffd83dbSDimitry Andric       }
26275ffd83dbSDimitry Andric 
26285ffd83dbSDimitry Andric       // The case when we have 0.0 is covered by tablegen. Reject it here so we
26295ffd83dbSDimitry Andric       // can be sure tablegen works correctly and isn't rescued by this code.
2630e8d8bef9SDimitry Andric       // 0.0 is not covered by tablegen for FP128. So we will handle this
2631e8d8bef9SDimitry Andric       // scenario in the code here.
2632e8d8bef9SDimitry Andric       if (DefSize != 128 && I.getOperand(1).getFPImm()->isExactlyValue(0.0))
26335ffd83dbSDimitry Andric         return false;
26345ffd83dbSDimitry Andric     } else {
26355ffd83dbSDimitry Andric       // s32 and s64 are covered by tablegen.
26365ffd83dbSDimitry Andric       if (Ty != p0 && Ty != s8 && Ty != s16) {
26375ffd83dbSDimitry Andric         LLVM_DEBUG(dbgs() << "Unable to materialize integer " << Ty
26385ffd83dbSDimitry Andric                           << " constant, expected: " << s32 << ", " << s64
26395ffd83dbSDimitry Andric                           << ", or " << p0 << '\n');
26405ffd83dbSDimitry Andric         return false;
26415ffd83dbSDimitry Andric       }
26425ffd83dbSDimitry Andric 
26435ffd83dbSDimitry Andric       if (RB.getID() != AArch64::GPRRegBankID) {
26445ffd83dbSDimitry Andric         LLVM_DEBUG(dbgs() << "Unable to materialize integer " << Ty
26455ffd83dbSDimitry Andric                           << " constant on bank: " << RB
26465ffd83dbSDimitry Andric                           << ", expected: GPR\n");
26475ffd83dbSDimitry Andric         return false;
26485ffd83dbSDimitry Andric       }
26495ffd83dbSDimitry Andric     }
26505ffd83dbSDimitry Andric 
26515ffd83dbSDimitry Andric     if (isFP) {
265281ad6265SDimitry Andric       const TargetRegisterClass &FPRRC = *getRegClassForTypeOnBank(DefTy, RB);
2653349cc55cSDimitry Andric       // For 16, 64, and 128b values, emit a constant pool load.
2654349cc55cSDimitry Andric       switch (DefSize) {
2655349cc55cSDimitry Andric       default:
2656349cc55cSDimitry Andric         llvm_unreachable("Unexpected destination size for G_FCONSTANT?");
2657349cc55cSDimitry Andric       case 32:
26585f757f3fSDimitry Andric       case 64: {
26595f757f3fSDimitry Andric         bool OptForSize = shouldOptForSize(&MF);
26605f757f3fSDimitry Andric         const auto &TLI = MF.getSubtarget().getTargetLowering();
26615f757f3fSDimitry Andric         // If TLI says that this fpimm is illegal, then we'll expand to a
26625f757f3fSDimitry Andric         // constant pool load.
26635f757f3fSDimitry Andric         if (TLI->isFPImmLegal(I.getOperand(1).getFPImm()->getValueAPF(),
26645f757f3fSDimitry Andric                               EVT::getFloatingPointVT(DefSize), OptForSize))
2665349cc55cSDimitry Andric           break;
2666bdd1243dSDimitry Andric         [[fallthrough]];
26675f757f3fSDimitry Andric       }
2668349cc55cSDimitry Andric       case 16:
2669349cc55cSDimitry Andric       case 128: {
26705ffd83dbSDimitry Andric         auto *FPImm = I.getOperand(1).getFPImm();
26715ffd83dbSDimitry Andric         auto *LoadMI = emitLoadFromConstantPool(FPImm, MIB);
26725ffd83dbSDimitry Andric         if (!LoadMI) {
26735ffd83dbSDimitry Andric           LLVM_DEBUG(dbgs() << "Failed to load double constant pool entry\n");
26745ffd83dbSDimitry Andric           return false;
26755ffd83dbSDimitry Andric         }
26765ffd83dbSDimitry Andric         MIB.buildCopy({DefReg}, {LoadMI->getOperand(0).getReg()});
26775ffd83dbSDimitry Andric         I.eraseFromParent();
26785ffd83dbSDimitry Andric         return RBI.constrainGenericRegister(DefReg, FPRRC, MRI);
26795ffd83dbSDimitry Andric       }
2680349cc55cSDimitry Andric       }
26815ffd83dbSDimitry Andric 
26825f757f3fSDimitry Andric       assert((DefSize == 32 || DefSize == 64) && "Unexpected const def size");
2683349cc55cSDimitry Andric       // Either emit a FMOV, or emit a copy to emit a normal mov.
26845f757f3fSDimitry Andric       const Register DefGPRReg = MRI.createVirtualRegister(
26855f757f3fSDimitry Andric           DefSize == 32 ? &AArch64::GPR32RegClass : &AArch64::GPR64RegClass);
26865ffd83dbSDimitry Andric       MachineOperand &RegOp = I.getOperand(0);
26875ffd83dbSDimitry Andric       RegOp.setReg(DefGPRReg);
26885ffd83dbSDimitry Andric       MIB.setInsertPt(MIB.getMBB(), std::next(I.getIterator()));
26895ffd83dbSDimitry Andric       MIB.buildCopy({DefReg}, {DefGPRReg});
26905ffd83dbSDimitry Andric 
26915ffd83dbSDimitry Andric       if (!RBI.constrainGenericRegister(DefReg, FPRRC, MRI)) {
26925ffd83dbSDimitry Andric         LLVM_DEBUG(dbgs() << "Failed to constrain G_FCONSTANT def operand\n");
26935ffd83dbSDimitry Andric         return false;
26945ffd83dbSDimitry Andric       }
26955ffd83dbSDimitry Andric 
26965ffd83dbSDimitry Andric       MachineOperand &ImmOp = I.getOperand(1);
26975ffd83dbSDimitry Andric       // FIXME: Is going through int64_t always correct?
26985ffd83dbSDimitry Andric       ImmOp.ChangeToImmediate(
26995ffd83dbSDimitry Andric           ImmOp.getFPImm()->getValueAPF().bitcastToAPInt().getZExtValue());
27005ffd83dbSDimitry Andric     } else if (I.getOperand(1).isCImm()) {
27015ffd83dbSDimitry Andric       uint64_t Val = I.getOperand(1).getCImm()->getZExtValue();
27025ffd83dbSDimitry Andric       I.getOperand(1).ChangeToImmediate(Val);
27035ffd83dbSDimitry Andric     } else if (I.getOperand(1).isImm()) {
27045ffd83dbSDimitry Andric       uint64_t Val = I.getOperand(1).getImm();
27055ffd83dbSDimitry Andric       I.getOperand(1).ChangeToImmediate(Val);
27065ffd83dbSDimitry Andric     }
27075ffd83dbSDimitry Andric 
2708349cc55cSDimitry Andric     const unsigned MovOpc =
2709349cc55cSDimitry Andric         DefSize == 64 ? AArch64::MOVi64imm : AArch64::MOVi32imm;
27105ffd83dbSDimitry Andric     I.setDesc(TII.get(MovOpc));
27115ffd83dbSDimitry Andric     constrainSelectedInstRegOperands(I, TII, TRI, RBI);
27125ffd83dbSDimitry Andric     return true;
27135ffd83dbSDimitry Andric   }
27145ffd83dbSDimitry Andric   case TargetOpcode::G_EXTRACT: {
27155ffd83dbSDimitry Andric     Register DstReg = I.getOperand(0).getReg();
27165ffd83dbSDimitry Andric     Register SrcReg = I.getOperand(1).getReg();
27175ffd83dbSDimitry Andric     LLT SrcTy = MRI.getType(SrcReg);
27185ffd83dbSDimitry Andric     LLT DstTy = MRI.getType(DstReg);
27195ffd83dbSDimitry Andric     (void)DstTy;
27205ffd83dbSDimitry Andric     unsigned SrcSize = SrcTy.getSizeInBits();
27215ffd83dbSDimitry Andric 
27225ffd83dbSDimitry Andric     if (SrcTy.getSizeInBits() > 64) {
27235ffd83dbSDimitry Andric       // This should be an extract of an s128, which is like a vector extract.
27245ffd83dbSDimitry Andric       if (SrcTy.getSizeInBits() != 128)
27255ffd83dbSDimitry Andric         return false;
27265ffd83dbSDimitry Andric       // Only support extracting 64 bits from an s128 at the moment.
27275ffd83dbSDimitry Andric       if (DstTy.getSizeInBits() != 64)
27285ffd83dbSDimitry Andric         return false;
27295ffd83dbSDimitry Andric 
27305ffd83dbSDimitry Andric       unsigned Offset = I.getOperand(2).getImm();
27315ffd83dbSDimitry Andric       if (Offset % 64 != 0)
27325ffd83dbSDimitry Andric         return false;
2733fe6060f1SDimitry Andric 
2734fe6060f1SDimitry Andric       // Check we have the right regbank always.
2735fe6060f1SDimitry Andric       const RegisterBank &SrcRB = *RBI.getRegBank(SrcReg, MRI, TRI);
2736fe6060f1SDimitry Andric       const RegisterBank &DstRB = *RBI.getRegBank(DstReg, MRI, TRI);
2737fe6060f1SDimitry Andric       assert(SrcRB.getID() == DstRB.getID() && "Wrong extract regbank!");
2738fe6060f1SDimitry Andric 
2739fe6060f1SDimitry Andric       if (SrcRB.getID() == AArch64::GPRRegBankID) {
2740bdd1243dSDimitry Andric         auto NewI =
2741fe6060f1SDimitry Andric             MIB.buildInstr(TargetOpcode::COPY, {DstReg}, {})
2742bdd1243dSDimitry Andric                 .addUse(SrcReg, 0,
2743bdd1243dSDimitry Andric                         Offset == 0 ? AArch64::sube64 : AArch64::subo64);
2744bdd1243dSDimitry Andric         constrainOperandRegClass(MF, TRI, MRI, TII, RBI, *NewI,
2745bdd1243dSDimitry Andric                                  AArch64::GPR64RegClass, NewI->getOperand(0));
2746fe6060f1SDimitry Andric         I.eraseFromParent();
2747fe6060f1SDimitry Andric         return true;
2748fe6060f1SDimitry Andric       }
2749fe6060f1SDimitry Andric 
2750fe6060f1SDimitry Andric       // Emit the same code as a vector extract.
2751fe6060f1SDimitry Andric       // Offset must be a multiple of 64.
27525ffd83dbSDimitry Andric       unsigned LaneIdx = Offset / 64;
27535ffd83dbSDimitry Andric       MachineInstr *Extract = emitExtractVectorElt(
27545ffd83dbSDimitry Andric           DstReg, DstRB, LLT::scalar(64), SrcReg, LaneIdx, MIB);
27555ffd83dbSDimitry Andric       if (!Extract)
27565ffd83dbSDimitry Andric         return false;
27575ffd83dbSDimitry Andric       I.eraseFromParent();
27585ffd83dbSDimitry Andric       return true;
27595ffd83dbSDimitry Andric     }
27605ffd83dbSDimitry Andric 
27615ffd83dbSDimitry Andric     I.setDesc(TII.get(SrcSize == 64 ? AArch64::UBFMXri : AArch64::UBFMWri));
27625ffd83dbSDimitry Andric     MachineInstrBuilder(MF, I).addImm(I.getOperand(2).getImm() +
27635ffd83dbSDimitry Andric                                       Ty.getSizeInBits() - 1);
27645ffd83dbSDimitry Andric 
27655ffd83dbSDimitry Andric     if (SrcSize < 64) {
27665ffd83dbSDimitry Andric       assert(SrcSize == 32 && DstTy.getSizeInBits() == 16 &&
27675ffd83dbSDimitry Andric              "unexpected G_EXTRACT types");
27685ffd83dbSDimitry Andric       return constrainSelectedInstRegOperands(I, TII, TRI, RBI);
27695ffd83dbSDimitry Andric     }
27705ffd83dbSDimitry Andric 
27715ffd83dbSDimitry Andric     DstReg = MRI.createGenericVirtualRegister(LLT::scalar(64));
27725ffd83dbSDimitry Andric     MIB.setInsertPt(MIB.getMBB(), std::next(I.getIterator()));
27735ffd83dbSDimitry Andric     MIB.buildInstr(TargetOpcode::COPY, {I.getOperand(0).getReg()}, {})
27745ffd83dbSDimitry Andric         .addReg(DstReg, 0, AArch64::sub_32);
27755ffd83dbSDimitry Andric     RBI.constrainGenericRegister(I.getOperand(0).getReg(),
27765ffd83dbSDimitry Andric                                  AArch64::GPR32RegClass, MRI);
27775ffd83dbSDimitry Andric     I.getOperand(0).setReg(DstReg);
27785ffd83dbSDimitry Andric 
27795ffd83dbSDimitry Andric     return constrainSelectedInstRegOperands(I, TII, TRI, RBI);
27805ffd83dbSDimitry Andric   }
27815ffd83dbSDimitry Andric 
27825ffd83dbSDimitry Andric   case TargetOpcode::G_INSERT: {
27835ffd83dbSDimitry Andric     LLT SrcTy = MRI.getType(I.getOperand(2).getReg());
27845ffd83dbSDimitry Andric     LLT DstTy = MRI.getType(I.getOperand(0).getReg());
27855ffd83dbSDimitry Andric     unsigned DstSize = DstTy.getSizeInBits();
27865ffd83dbSDimitry Andric     // Larger inserts are vectors, same-size ones should be something else by
27875ffd83dbSDimitry Andric     // now (split up or turned into COPYs).
27885ffd83dbSDimitry Andric     if (Ty.getSizeInBits() > 64 || SrcTy.getSizeInBits() > 32)
27895ffd83dbSDimitry Andric       return false;
27905ffd83dbSDimitry Andric 
27915ffd83dbSDimitry Andric     I.setDesc(TII.get(DstSize == 64 ? AArch64::BFMXri : AArch64::BFMWri));
27925ffd83dbSDimitry Andric     unsigned LSB = I.getOperand(3).getImm();
27935ffd83dbSDimitry Andric     unsigned Width = MRI.getType(I.getOperand(2).getReg()).getSizeInBits();
27945ffd83dbSDimitry Andric     I.getOperand(3).setImm((DstSize - LSB) % DstSize);
27955ffd83dbSDimitry Andric     MachineInstrBuilder(MF, I).addImm(Width - 1);
27965ffd83dbSDimitry Andric 
27975ffd83dbSDimitry Andric     if (DstSize < 64) {
27985ffd83dbSDimitry Andric       assert(DstSize == 32 && SrcTy.getSizeInBits() == 16 &&
27995ffd83dbSDimitry Andric              "unexpected G_INSERT types");
28005ffd83dbSDimitry Andric       return constrainSelectedInstRegOperands(I, TII, TRI, RBI);
28015ffd83dbSDimitry Andric     }
28025ffd83dbSDimitry Andric 
28035ffd83dbSDimitry Andric     Register SrcReg = MRI.createGenericVirtualRegister(LLT::scalar(64));
28045ffd83dbSDimitry Andric     BuildMI(MBB, I.getIterator(), I.getDebugLoc(),
28055ffd83dbSDimitry Andric             TII.get(AArch64::SUBREG_TO_REG))
28065ffd83dbSDimitry Andric         .addDef(SrcReg)
28075ffd83dbSDimitry Andric         .addImm(0)
28085ffd83dbSDimitry Andric         .addUse(I.getOperand(2).getReg())
28095ffd83dbSDimitry Andric         .addImm(AArch64::sub_32);
28105ffd83dbSDimitry Andric     RBI.constrainGenericRegister(I.getOperand(2).getReg(),
28115ffd83dbSDimitry Andric                                  AArch64::GPR32RegClass, MRI);
28125ffd83dbSDimitry Andric     I.getOperand(2).setReg(SrcReg);
28135ffd83dbSDimitry Andric 
28145ffd83dbSDimitry Andric     return constrainSelectedInstRegOperands(I, TII, TRI, RBI);
28155ffd83dbSDimitry Andric   }
28165ffd83dbSDimitry Andric   case TargetOpcode::G_FRAME_INDEX: {
28175ffd83dbSDimitry Andric     // allocas and G_FRAME_INDEX are only supported in addrspace(0).
28185ffd83dbSDimitry Andric     if (Ty != LLT::pointer(0, 64)) {
28195ffd83dbSDimitry Andric       LLVM_DEBUG(dbgs() << "G_FRAME_INDEX pointer has type: " << Ty
28205ffd83dbSDimitry Andric                         << ", expected: " << LLT::pointer(0, 64) << '\n');
28215ffd83dbSDimitry Andric       return false;
28225ffd83dbSDimitry Andric     }
28235ffd83dbSDimitry Andric     I.setDesc(TII.get(AArch64::ADDXri));
28245ffd83dbSDimitry Andric 
28255ffd83dbSDimitry Andric     // MOs for a #0 shifted immediate.
28265ffd83dbSDimitry Andric     I.addOperand(MachineOperand::CreateImm(0));
28275ffd83dbSDimitry Andric     I.addOperand(MachineOperand::CreateImm(0));
28285ffd83dbSDimitry Andric 
28295ffd83dbSDimitry Andric     return constrainSelectedInstRegOperands(I, TII, TRI, RBI);
28305ffd83dbSDimitry Andric   }
28315ffd83dbSDimitry Andric 
28325ffd83dbSDimitry Andric   case TargetOpcode::G_GLOBAL_VALUE: {
2833*0fca6ea1SDimitry Andric     const GlobalValue *GV = nullptr;
2834*0fca6ea1SDimitry Andric     unsigned OpFlags;
2835*0fca6ea1SDimitry Andric     if (I.getOperand(1).isSymbol()) {
2836*0fca6ea1SDimitry Andric       OpFlags = I.getOperand(1).getTargetFlags();
2837*0fca6ea1SDimitry Andric       // Currently only used by "RtLibUseGOT".
2838*0fca6ea1SDimitry Andric       assert(OpFlags == AArch64II::MO_GOT);
2839*0fca6ea1SDimitry Andric     } else {
2840*0fca6ea1SDimitry Andric       GV = I.getOperand(1).getGlobal();
28415ffd83dbSDimitry Andric       if (GV->isThreadLocal())
28425ffd83dbSDimitry Andric         return selectTLSGlobalValue(I, MRI);
2843*0fca6ea1SDimitry Andric       OpFlags = STI.ClassifyGlobalReference(GV, TM);
2844*0fca6ea1SDimitry Andric     }
28455ffd83dbSDimitry Andric 
28465ffd83dbSDimitry Andric     if (OpFlags & AArch64II::MO_GOT) {
28475ffd83dbSDimitry Andric       I.setDesc(TII.get(AArch64::LOADgot));
28485ffd83dbSDimitry Andric       I.getOperand(1).setTargetFlags(OpFlags);
28495f757f3fSDimitry Andric     } else if (TM.getCodeModel() == CodeModel::Large &&
28505f757f3fSDimitry Andric                !TM.isPositionIndependent()) {
28515ffd83dbSDimitry Andric       // Materialize the global using movz/movk instructions.
28525ffd83dbSDimitry Andric       materializeLargeCMVal(I, GV, OpFlags);
28535ffd83dbSDimitry Andric       I.eraseFromParent();
28545ffd83dbSDimitry Andric       return true;
28555ffd83dbSDimitry Andric     } else if (TM.getCodeModel() == CodeModel::Tiny) {
28565ffd83dbSDimitry Andric       I.setDesc(TII.get(AArch64::ADR));
28575ffd83dbSDimitry Andric       I.getOperand(1).setTargetFlags(OpFlags);
28585ffd83dbSDimitry Andric     } else {
28595ffd83dbSDimitry Andric       I.setDesc(TII.get(AArch64::MOVaddr));
28605ffd83dbSDimitry Andric       I.getOperand(1).setTargetFlags(OpFlags | AArch64II::MO_PAGE);
28615ffd83dbSDimitry Andric       MachineInstrBuilder MIB(MF, I);
28625ffd83dbSDimitry Andric       MIB.addGlobalAddress(GV, I.getOperand(1).getOffset(),
28635ffd83dbSDimitry Andric                            OpFlags | AArch64II::MO_PAGEOFF | AArch64II::MO_NC);
28645ffd83dbSDimitry Andric     }
28655ffd83dbSDimitry Andric     return constrainSelectedInstRegOperands(I, TII, TRI, RBI);
28665ffd83dbSDimitry Andric   }
28675ffd83dbSDimitry Andric 
2868*0fca6ea1SDimitry Andric   case TargetOpcode::G_PTRAUTH_GLOBAL_VALUE:
2869*0fca6ea1SDimitry Andric     return selectPtrAuthGlobalValue(I, MRI);
2870*0fca6ea1SDimitry Andric 
28715ffd83dbSDimitry Andric   case TargetOpcode::G_ZEXTLOAD:
28725ffd83dbSDimitry Andric   case TargetOpcode::G_LOAD:
28735ffd83dbSDimitry Andric   case TargetOpcode::G_STORE: {
2874349cc55cSDimitry Andric     GLoadStore &LdSt = cast<GLoadStore>(I);
28755ffd83dbSDimitry Andric     bool IsZExtLoad = I.getOpcode() == TargetOpcode::G_ZEXTLOAD;
2876349cc55cSDimitry Andric     LLT PtrTy = MRI.getType(LdSt.getPointerReg());
28775ffd83dbSDimitry Andric 
28785ffd83dbSDimitry Andric     if (PtrTy != LLT::pointer(0, 64)) {
28795ffd83dbSDimitry Andric       LLVM_DEBUG(dbgs() << "Load/Store pointer has type: " << PtrTy
28805ffd83dbSDimitry Andric                         << ", expected: " << LLT::pointer(0, 64) << '\n');
28815ffd83dbSDimitry Andric       return false;
28825ffd83dbSDimitry Andric     }
28835ffd83dbSDimitry Andric 
2884*0fca6ea1SDimitry Andric     uint64_t MemSizeInBytes = LdSt.getMemSize().getValue();
2885*0fca6ea1SDimitry Andric     unsigned MemSizeInBits = LdSt.getMemSizeInBits().getValue();
2886349cc55cSDimitry Andric     AtomicOrdering Order = LdSt.getMMO().getSuccessOrdering();
2887fe6060f1SDimitry Andric 
2888fe6060f1SDimitry Andric     // Need special instructions for atomics that affect ordering.
2889fe6060f1SDimitry Andric     if (Order != AtomicOrdering::NotAtomic &&
2890fe6060f1SDimitry Andric         Order != AtomicOrdering::Unordered &&
2891fe6060f1SDimitry Andric         Order != AtomicOrdering::Monotonic) {
2892349cc55cSDimitry Andric       assert(!isa<GZExtLoad>(LdSt));
2893*0fca6ea1SDimitry Andric       assert(MemSizeInBytes <= 8 &&
2894*0fca6ea1SDimitry Andric              "128-bit atomics should already be custom-legalized");
2895fe6060f1SDimitry Andric 
2896349cc55cSDimitry Andric       if (isa<GLoad>(LdSt)) {
289781ad6265SDimitry Andric         static constexpr unsigned LDAPROpcodes[] = {
289881ad6265SDimitry Andric             AArch64::LDAPRB, AArch64::LDAPRH, AArch64::LDAPRW, AArch64::LDAPRX};
289981ad6265SDimitry Andric         static constexpr unsigned LDAROpcodes[] = {
290081ad6265SDimitry Andric             AArch64::LDARB, AArch64::LDARH, AArch64::LDARW, AArch64::LDARX};
290181ad6265SDimitry Andric         ArrayRef<unsigned> Opcodes =
2902bdd1243dSDimitry Andric             STI.hasRCPC() && Order != AtomicOrdering::SequentiallyConsistent
290381ad6265SDimitry Andric                 ? LDAPROpcodes
290481ad6265SDimitry Andric                 : LDAROpcodes;
2905fe6060f1SDimitry Andric         I.setDesc(TII.get(Opcodes[Log2_32(MemSizeInBytes)]));
2906fe6060f1SDimitry Andric       } else {
290781ad6265SDimitry Andric         static constexpr unsigned Opcodes[] = {AArch64::STLRB, AArch64::STLRH,
2908fe6060f1SDimitry Andric                                                AArch64::STLRW, AArch64::STLRX};
2909349cc55cSDimitry Andric         Register ValReg = LdSt.getReg(0);
2910349cc55cSDimitry Andric         if (MRI.getType(ValReg).getSizeInBits() == 64 && MemSizeInBits != 64) {
2911349cc55cSDimitry Andric           // Emit a subreg copy of 32 bits.
2912349cc55cSDimitry Andric           Register NewVal = MRI.createVirtualRegister(&AArch64::GPR32RegClass);
2913349cc55cSDimitry Andric           MIB.buildInstr(TargetOpcode::COPY, {NewVal}, {})
2914349cc55cSDimitry Andric               .addReg(I.getOperand(0).getReg(), 0, AArch64::sub_32);
2915349cc55cSDimitry Andric           I.getOperand(0).setReg(NewVal);
2916349cc55cSDimitry Andric         }
2917fe6060f1SDimitry Andric         I.setDesc(TII.get(Opcodes[Log2_32(MemSizeInBytes)]));
2918fe6060f1SDimitry Andric       }
2919fe6060f1SDimitry Andric       constrainSelectedInstRegOperands(I, TII, TRI, RBI);
2920fe6060f1SDimitry Andric       return true;
2921fe6060f1SDimitry Andric     }
29225ffd83dbSDimitry Andric 
29235ffd83dbSDimitry Andric #ifndef NDEBUG
2924349cc55cSDimitry Andric     const Register PtrReg = LdSt.getPointerReg();
29255ffd83dbSDimitry Andric     const RegisterBank &PtrRB = *RBI.getRegBank(PtrReg, MRI, TRI);
2926349cc55cSDimitry Andric     // Check that the pointer register is valid.
29275ffd83dbSDimitry Andric     assert(PtrRB.getID() == AArch64::GPRRegBankID &&
29285ffd83dbSDimitry Andric            "Load/Store pointer operand isn't a GPR");
29295ffd83dbSDimitry Andric     assert(MRI.getType(PtrReg).isPointer() &&
29305ffd83dbSDimitry Andric            "Load/Store pointer operand isn't a pointer");
29315ffd83dbSDimitry Andric #endif
29325ffd83dbSDimitry Andric 
2933349cc55cSDimitry Andric     const Register ValReg = LdSt.getReg(0);
2934349cc55cSDimitry Andric     const LLT ValTy = MRI.getType(ValReg);
29355ffd83dbSDimitry Andric     const RegisterBank &RB = *RBI.getRegBank(ValReg, MRI, TRI);
29365ffd83dbSDimitry Andric 
2937349cc55cSDimitry Andric     // The code below doesn't support truncating stores, so we need to split it
2938349cc55cSDimitry Andric     // again.
2939349cc55cSDimitry Andric     if (isa<GStore>(LdSt) && ValTy.getSizeInBits() > MemSizeInBits) {
2940349cc55cSDimitry Andric       unsigned SubReg;
2941349cc55cSDimitry Andric       LLT MemTy = LdSt.getMMO().getMemoryType();
294281ad6265SDimitry Andric       auto *RC = getRegClassForTypeOnBank(MemTy, RB);
2943349cc55cSDimitry Andric       if (!getSubRegForClass(RC, TRI, SubReg))
2944349cc55cSDimitry Andric         return false;
2945349cc55cSDimitry Andric 
2946349cc55cSDimitry Andric       // Generate a subreg copy.
2947349cc55cSDimitry Andric       auto Copy = MIB.buildInstr(TargetOpcode::COPY, {MemTy}, {})
2948349cc55cSDimitry Andric                       .addReg(ValReg, 0, SubReg)
2949349cc55cSDimitry Andric                       .getReg(0);
2950349cc55cSDimitry Andric       RBI.constrainGenericRegister(Copy, *RC, MRI);
2951349cc55cSDimitry Andric       LdSt.getOperand(0).setReg(Copy);
2952349cc55cSDimitry Andric     } else if (isa<GLoad>(LdSt) && ValTy.getSizeInBits() > MemSizeInBits) {
2953349cc55cSDimitry Andric       // If this is an any-extending load from the FPR bank, split it into a regular
2954349cc55cSDimitry Andric       // load + extend.
2955349cc55cSDimitry Andric       if (RB.getID() == AArch64::FPRRegBankID) {
2956349cc55cSDimitry Andric         unsigned SubReg;
2957349cc55cSDimitry Andric         LLT MemTy = LdSt.getMMO().getMemoryType();
295881ad6265SDimitry Andric         auto *RC = getRegClassForTypeOnBank(MemTy, RB);
2959349cc55cSDimitry Andric         if (!getSubRegForClass(RC, TRI, SubReg))
2960349cc55cSDimitry Andric           return false;
2961349cc55cSDimitry Andric         Register OldDst = LdSt.getReg(0);
2962349cc55cSDimitry Andric         Register NewDst =
2963349cc55cSDimitry Andric             MRI.createGenericVirtualRegister(LdSt.getMMO().getMemoryType());
2964349cc55cSDimitry Andric         LdSt.getOperand(0).setReg(NewDst);
2965349cc55cSDimitry Andric         MRI.setRegBank(NewDst, RB);
2966349cc55cSDimitry Andric         // Generate a SUBREG_TO_REG to extend it.
2967349cc55cSDimitry Andric         MIB.setInsertPt(MIB.getMBB(), std::next(LdSt.getIterator()));
2968349cc55cSDimitry Andric         MIB.buildInstr(AArch64::SUBREG_TO_REG, {OldDst}, {})
2969349cc55cSDimitry Andric             .addImm(0)
2970349cc55cSDimitry Andric             .addUse(NewDst)
2971349cc55cSDimitry Andric             .addImm(SubReg);
297281ad6265SDimitry Andric         auto SubRegRC = getRegClassForTypeOnBank(MRI.getType(OldDst), RB);
2973349cc55cSDimitry Andric         RBI.constrainGenericRegister(OldDst, *SubRegRC, MRI);
2974349cc55cSDimitry Andric         MIB.setInstr(LdSt);
2975349cc55cSDimitry Andric       }
2976349cc55cSDimitry Andric     }
2977349cc55cSDimitry Andric 
2978e8d8bef9SDimitry Andric     // Helper lambda for partially selecting I. Either returns the original
2979e8d8bef9SDimitry Andric     // instruction with an updated opcode, or a new instruction.
2980e8d8bef9SDimitry Andric     auto SelectLoadStoreAddressingMode = [&]() -> MachineInstr * {
2981349cc55cSDimitry Andric       bool IsStore = isa<GStore>(I);
29825ffd83dbSDimitry Andric       const unsigned NewOpc =
29835ffd83dbSDimitry Andric           selectLoadStoreUIOp(I.getOpcode(), RB.getID(), MemSizeInBits);
29845ffd83dbSDimitry Andric       if (NewOpc == I.getOpcode())
2985e8d8bef9SDimitry Andric         return nullptr;
2986e8d8bef9SDimitry Andric       // Check if we can fold anything into the addressing mode.
2987e8d8bef9SDimitry Andric       auto AddrModeFns =
2988e8d8bef9SDimitry Andric           selectAddrModeIndexed(I.getOperand(1), MemSizeInBytes);
2989e8d8bef9SDimitry Andric       if (!AddrModeFns) {
2990e8d8bef9SDimitry Andric         // Can't fold anything. Use the original instruction.
2991e8d8bef9SDimitry Andric         I.setDesc(TII.get(NewOpc));
2992e8d8bef9SDimitry Andric         I.addOperand(MachineOperand::CreateImm(0));
2993e8d8bef9SDimitry Andric         return &I;
2994e8d8bef9SDimitry Andric       }
2995e8d8bef9SDimitry Andric 
2996e8d8bef9SDimitry Andric       // Folded something. Create a new instruction and return it.
2997e8d8bef9SDimitry Andric       auto NewInst = MIB.buildInstr(NewOpc, {}, {}, I.getFlags());
2998349cc55cSDimitry Andric       Register CurValReg = I.getOperand(0).getReg();
2999349cc55cSDimitry Andric       IsStore ? NewInst.addUse(CurValReg) : NewInst.addDef(CurValReg);
3000e8d8bef9SDimitry Andric       NewInst.cloneMemRefs(I);
3001e8d8bef9SDimitry Andric       for (auto &Fn : *AddrModeFns)
3002e8d8bef9SDimitry Andric         Fn(NewInst);
3003e8d8bef9SDimitry Andric       I.eraseFromParent();
3004e8d8bef9SDimitry Andric       return &*NewInst;
3005e8d8bef9SDimitry Andric     };
3006e8d8bef9SDimitry Andric 
3007e8d8bef9SDimitry Andric     MachineInstr *LoadStore = SelectLoadStoreAddressingMode();
3008e8d8bef9SDimitry Andric     if (!LoadStore)
30095ffd83dbSDimitry Andric       return false;
30105ffd83dbSDimitry Andric 
30115ffd83dbSDimitry Andric     // If we're storing a 0, use WZR/XZR.
3012e8d8bef9SDimitry Andric     if (Opcode == TargetOpcode::G_STORE) {
3013349cc55cSDimitry Andric       auto CVal = getIConstantVRegValWithLookThrough(
3014349cc55cSDimitry Andric           LoadStore->getOperand(0).getReg(), MRI);
3015e8d8bef9SDimitry Andric       if (CVal && CVal->Value == 0) {
3016e8d8bef9SDimitry Andric         switch (LoadStore->getOpcode()) {
3017e8d8bef9SDimitry Andric         case AArch64::STRWui:
3018e8d8bef9SDimitry Andric         case AArch64::STRHHui:
3019e8d8bef9SDimitry Andric         case AArch64::STRBBui:
3020e8d8bef9SDimitry Andric           LoadStore->getOperand(0).setReg(AArch64::WZR);
3021e8d8bef9SDimitry Andric           break;
3022e8d8bef9SDimitry Andric         case AArch64::STRXui:
3023e8d8bef9SDimitry Andric           LoadStore->getOperand(0).setReg(AArch64::XZR);
3024e8d8bef9SDimitry Andric           break;
3025e8d8bef9SDimitry Andric         }
30265ffd83dbSDimitry Andric       }
30275ffd83dbSDimitry Andric     }
30285ffd83dbSDimitry Andric 
3029*0fca6ea1SDimitry Andric     if (IsZExtLoad || (Opcode == TargetOpcode::G_LOAD &&
3030*0fca6ea1SDimitry Andric                        ValTy == LLT::scalar(64) && MemSizeInBits == 32)) {
3031*0fca6ea1SDimitry Andric       // The any/zextload from a smaller type to i32 should be handled by the
3032e8d8bef9SDimitry Andric       // importer.
3033e8d8bef9SDimitry Andric       if (MRI.getType(LoadStore->getOperand(0).getReg()).getSizeInBits() != 64)
30345ffd83dbSDimitry Andric         return false;
3035*0fca6ea1SDimitry Andric       // If we have an extending load then change the load's type to be a
3036*0fca6ea1SDimitry Andric       // narrower reg and zero_extend with SUBREG_TO_REG.
30375ffd83dbSDimitry Andric       Register LdReg = MRI.createVirtualRegister(&AArch64::GPR32RegClass);
3038e8d8bef9SDimitry Andric       Register DstReg = LoadStore->getOperand(0).getReg();
3039e8d8bef9SDimitry Andric       LoadStore->getOperand(0).setReg(LdReg);
30405ffd83dbSDimitry Andric 
3041e8d8bef9SDimitry Andric       MIB.setInsertPt(MIB.getMBB(), std::next(LoadStore->getIterator()));
30425ffd83dbSDimitry Andric       MIB.buildInstr(AArch64::SUBREG_TO_REG, {DstReg}, {})
30435ffd83dbSDimitry Andric           .addImm(0)
30445ffd83dbSDimitry Andric           .addUse(LdReg)
30455ffd83dbSDimitry Andric           .addImm(AArch64::sub_32);
3046e8d8bef9SDimitry Andric       constrainSelectedInstRegOperands(*LoadStore, TII, TRI, RBI);
30475ffd83dbSDimitry Andric       return RBI.constrainGenericRegister(DstReg, AArch64::GPR64allRegClass,
30485ffd83dbSDimitry Andric                                           MRI);
30495ffd83dbSDimitry Andric     }
3050e8d8bef9SDimitry Andric     return constrainSelectedInstRegOperands(*LoadStore, TII, TRI, RBI);
30515ffd83dbSDimitry Andric   }
30525ffd83dbSDimitry Andric 
30535f757f3fSDimitry Andric   case TargetOpcode::G_INDEXED_ZEXTLOAD:
30545f757f3fSDimitry Andric   case TargetOpcode::G_INDEXED_SEXTLOAD:
30555f757f3fSDimitry Andric     return selectIndexedExtLoad(I, MRI);
30565f757f3fSDimitry Andric   case TargetOpcode::G_INDEXED_LOAD:
30575f757f3fSDimitry Andric     return selectIndexedLoad(I, MRI);
30585f757f3fSDimitry Andric   case TargetOpcode::G_INDEXED_STORE:
30595f757f3fSDimitry Andric     return selectIndexedStore(cast<GIndexedStore>(I), MRI);
30605f757f3fSDimitry Andric 
3061e8d8bef9SDimitry Andric   case TargetOpcode::G_LSHR:
30625ffd83dbSDimitry Andric   case TargetOpcode::G_ASHR:
30635ffd83dbSDimitry Andric     if (MRI.getType(I.getOperand(0).getReg()).isVector())
3064e8d8bef9SDimitry Andric       return selectVectorAshrLshr(I, MRI);
3065bdd1243dSDimitry Andric     [[fallthrough]];
30665ffd83dbSDimitry Andric   case TargetOpcode::G_SHL:
30675ffd83dbSDimitry Andric     if (Opcode == TargetOpcode::G_SHL &&
30685ffd83dbSDimitry Andric         MRI.getType(I.getOperand(0).getReg()).isVector())
30695ffd83dbSDimitry Andric       return selectVectorSHL(I, MRI);
30704824e7fdSDimitry Andric 
30714824e7fdSDimitry Andric     // These shifts were legalized to have 64 bit shift amounts because we
30724824e7fdSDimitry Andric     // want to take advantage of the selection patterns that assume the
30734824e7fdSDimitry Andric     // immediates are s64s, however, selectBinaryOp will assume both operands
30744824e7fdSDimitry Andric     // will have the same bit size.
30754824e7fdSDimitry Andric     {
30764824e7fdSDimitry Andric       Register SrcReg = I.getOperand(1).getReg();
30774824e7fdSDimitry Andric       Register ShiftReg = I.getOperand(2).getReg();
30784824e7fdSDimitry Andric       const LLT ShiftTy = MRI.getType(ShiftReg);
30794824e7fdSDimitry Andric       const LLT SrcTy = MRI.getType(SrcReg);
30804824e7fdSDimitry Andric       if (!SrcTy.isVector() && SrcTy.getSizeInBits() == 32 &&
30814824e7fdSDimitry Andric           ShiftTy.getSizeInBits() == 64) {
30824824e7fdSDimitry Andric         assert(!ShiftTy.isVector() && "unexpected vector shift ty");
30834824e7fdSDimitry Andric         // Insert a subregister copy to implement a 64->32 trunc
30844824e7fdSDimitry Andric         auto Trunc = MIB.buildInstr(TargetOpcode::COPY, {SrcTy}, {})
30854824e7fdSDimitry Andric                          .addReg(ShiftReg, 0, AArch64::sub_32);
30864824e7fdSDimitry Andric         MRI.setRegBank(Trunc.getReg(0), RBI.getRegBank(AArch64::GPRRegBankID));
30874824e7fdSDimitry Andric         I.getOperand(2).setReg(Trunc.getReg(0));
30884824e7fdSDimitry Andric       }
30894824e7fdSDimitry Andric     }
3090bdd1243dSDimitry Andric     [[fallthrough]];
3091e8d8bef9SDimitry Andric   case TargetOpcode::G_OR: {
30925ffd83dbSDimitry Andric     // Reject the various things we don't support yet.
30935ffd83dbSDimitry Andric     if (unsupportedBinOp(I, RBI, MRI, TRI))
30945ffd83dbSDimitry Andric       return false;
30955ffd83dbSDimitry Andric 
30965ffd83dbSDimitry Andric     const unsigned OpSize = Ty.getSizeInBits();
30975ffd83dbSDimitry Andric 
30985ffd83dbSDimitry Andric     const Register DefReg = I.getOperand(0).getReg();
30995ffd83dbSDimitry Andric     const RegisterBank &RB = *RBI.getRegBank(DefReg, MRI, TRI);
31005ffd83dbSDimitry Andric 
31015ffd83dbSDimitry Andric     const unsigned NewOpc = selectBinaryOp(I.getOpcode(), RB.getID(), OpSize);
31025ffd83dbSDimitry Andric     if (NewOpc == I.getOpcode())
31035ffd83dbSDimitry Andric       return false;
31045ffd83dbSDimitry Andric 
31055ffd83dbSDimitry Andric     I.setDesc(TII.get(NewOpc));
31065ffd83dbSDimitry Andric     // FIXME: Should the type be always reset in setDesc?
31075ffd83dbSDimitry Andric 
31085ffd83dbSDimitry Andric     // Now that we selected an opcode, we need to constrain the register
31095ffd83dbSDimitry Andric     // operands to use appropriate classes.
31105ffd83dbSDimitry Andric     return constrainSelectedInstRegOperands(I, TII, TRI, RBI);
31115ffd83dbSDimitry Andric   }
31125ffd83dbSDimitry Andric 
31135ffd83dbSDimitry Andric   case TargetOpcode::G_PTR_ADD: {
3114fe6060f1SDimitry Andric     emitADD(I.getOperand(0).getReg(), I.getOperand(1), I.getOperand(2), MIB);
31155ffd83dbSDimitry Andric     I.eraseFromParent();
31165ffd83dbSDimitry Andric     return true;
31175ffd83dbSDimitry Andric   }
311806c3fb27SDimitry Andric 
311906c3fb27SDimitry Andric   case TargetOpcode::G_SADDE:
312006c3fb27SDimitry Andric   case TargetOpcode::G_UADDE:
312106c3fb27SDimitry Andric   case TargetOpcode::G_SSUBE:
312206c3fb27SDimitry Andric   case TargetOpcode::G_USUBE:
3123e8d8bef9SDimitry Andric   case TargetOpcode::G_SADDO:
3124e8d8bef9SDimitry Andric   case TargetOpcode::G_UADDO:
3125e8d8bef9SDimitry Andric   case TargetOpcode::G_SSUBO:
312606c3fb27SDimitry Andric   case TargetOpcode::G_USUBO:
312706c3fb27SDimitry Andric     return selectOverflowOp(I, MRI);
31285ffd83dbSDimitry Andric 
31295ffd83dbSDimitry Andric   case TargetOpcode::G_PTRMASK: {
31305ffd83dbSDimitry Andric     Register MaskReg = I.getOperand(2).getReg();
3131bdd1243dSDimitry Andric     std::optional<int64_t> MaskVal = getIConstantVRegSExtVal(MaskReg, MRI);
31325ffd83dbSDimitry Andric     // TODO: Implement arbitrary cases
31335ffd83dbSDimitry Andric     if (!MaskVal || !isShiftedMask_64(*MaskVal))
31345ffd83dbSDimitry Andric       return false;
31355ffd83dbSDimitry Andric 
31365ffd83dbSDimitry Andric     uint64_t Mask = *MaskVal;
31375ffd83dbSDimitry Andric     I.setDesc(TII.get(AArch64::ANDXri));
31385ffd83dbSDimitry Andric     I.getOperand(2).ChangeToImmediate(
31395ffd83dbSDimitry Andric         AArch64_AM::encodeLogicalImmediate(Mask, 64));
31405ffd83dbSDimitry Andric 
31415ffd83dbSDimitry Andric     return constrainSelectedInstRegOperands(I, TII, TRI, RBI);
31425ffd83dbSDimitry Andric   }
31435ffd83dbSDimitry Andric   case TargetOpcode::G_PTRTOINT:
31445ffd83dbSDimitry Andric   case TargetOpcode::G_TRUNC: {
31455ffd83dbSDimitry Andric     const LLT DstTy = MRI.getType(I.getOperand(0).getReg());
31465ffd83dbSDimitry Andric     const LLT SrcTy = MRI.getType(I.getOperand(1).getReg());
31475ffd83dbSDimitry Andric 
31485ffd83dbSDimitry Andric     const Register DstReg = I.getOperand(0).getReg();
31495ffd83dbSDimitry Andric     const Register SrcReg = I.getOperand(1).getReg();
31505ffd83dbSDimitry Andric 
31515ffd83dbSDimitry Andric     const RegisterBank &DstRB = *RBI.getRegBank(DstReg, MRI, TRI);
31525ffd83dbSDimitry Andric     const RegisterBank &SrcRB = *RBI.getRegBank(SrcReg, MRI, TRI);
31535ffd83dbSDimitry Andric 
31545ffd83dbSDimitry Andric     if (DstRB.getID() != SrcRB.getID()) {
31555ffd83dbSDimitry Andric       LLVM_DEBUG(
31565ffd83dbSDimitry Andric           dbgs() << "G_TRUNC/G_PTRTOINT input/output on different banks\n");
31575ffd83dbSDimitry Andric       return false;
31585ffd83dbSDimitry Andric     }
31595ffd83dbSDimitry Andric 
31605ffd83dbSDimitry Andric     if (DstRB.getID() == AArch64::GPRRegBankID) {
316181ad6265SDimitry Andric       const TargetRegisterClass *DstRC = getRegClassForTypeOnBank(DstTy, DstRB);
31625ffd83dbSDimitry Andric       if (!DstRC)
31635ffd83dbSDimitry Andric         return false;
31645ffd83dbSDimitry Andric 
316581ad6265SDimitry Andric       const TargetRegisterClass *SrcRC = getRegClassForTypeOnBank(SrcTy, SrcRB);
31665ffd83dbSDimitry Andric       if (!SrcRC)
31675ffd83dbSDimitry Andric         return false;
31685ffd83dbSDimitry Andric 
31695ffd83dbSDimitry Andric       if (!RBI.constrainGenericRegister(SrcReg, *SrcRC, MRI) ||
31705ffd83dbSDimitry Andric           !RBI.constrainGenericRegister(DstReg, *DstRC, MRI)) {
31715ffd83dbSDimitry Andric         LLVM_DEBUG(dbgs() << "Failed to constrain G_TRUNC/G_PTRTOINT\n");
31725ffd83dbSDimitry Andric         return false;
31735ffd83dbSDimitry Andric       }
31745ffd83dbSDimitry Andric 
31755ffd83dbSDimitry Andric       if (DstRC == SrcRC) {
31765ffd83dbSDimitry Andric         // Nothing to be done
31775ffd83dbSDimitry Andric       } else if (Opcode == TargetOpcode::G_TRUNC && DstTy == LLT::scalar(32) &&
31785ffd83dbSDimitry Andric                  SrcTy == LLT::scalar(64)) {
31795ffd83dbSDimitry Andric         llvm_unreachable("TableGen can import this case");
31805ffd83dbSDimitry Andric         return false;
31815ffd83dbSDimitry Andric       } else if (DstRC == &AArch64::GPR32RegClass &&
31825ffd83dbSDimitry Andric                  SrcRC == &AArch64::GPR64RegClass) {
31835ffd83dbSDimitry Andric         I.getOperand(1).setSubReg(AArch64::sub_32);
31845ffd83dbSDimitry Andric       } else {
31855ffd83dbSDimitry Andric         LLVM_DEBUG(
31865ffd83dbSDimitry Andric             dbgs() << "Unhandled mismatched classes in G_TRUNC/G_PTRTOINT\n");
31875ffd83dbSDimitry Andric         return false;
31885ffd83dbSDimitry Andric       }
31895ffd83dbSDimitry Andric 
31905ffd83dbSDimitry Andric       I.setDesc(TII.get(TargetOpcode::COPY));
31915ffd83dbSDimitry Andric       return true;
31925ffd83dbSDimitry Andric     } else if (DstRB.getID() == AArch64::FPRRegBankID) {
3193fe6060f1SDimitry Andric       if (DstTy == LLT::fixed_vector(4, 16) &&
3194fe6060f1SDimitry Andric           SrcTy == LLT::fixed_vector(4, 32)) {
31955ffd83dbSDimitry Andric         I.setDesc(TII.get(AArch64::XTNv4i16));
31965ffd83dbSDimitry Andric         constrainSelectedInstRegOperands(I, TII, TRI, RBI);
31975ffd83dbSDimitry Andric         return true;
31985ffd83dbSDimitry Andric       }
31995ffd83dbSDimitry Andric 
32005ffd83dbSDimitry Andric       if (!SrcTy.isVector() && SrcTy.getSizeInBits() == 128) {
32015ffd83dbSDimitry Andric         MachineInstr *Extract = emitExtractVectorElt(
32025ffd83dbSDimitry Andric             DstReg, DstRB, LLT::scalar(DstTy.getSizeInBits()), SrcReg, 0, MIB);
32035ffd83dbSDimitry Andric         if (!Extract)
32045ffd83dbSDimitry Andric           return false;
32055ffd83dbSDimitry Andric         I.eraseFromParent();
32065ffd83dbSDimitry Andric         return true;
32075ffd83dbSDimitry Andric       }
32085ffd83dbSDimitry Andric 
32095ffd83dbSDimitry Andric       // We might have a vector G_PTRTOINT, in which case just emit a COPY.
32105ffd83dbSDimitry Andric       if (Opcode == TargetOpcode::G_PTRTOINT) {
32115ffd83dbSDimitry Andric         assert(DstTy.isVector() && "Expected an FPR ptrtoint to be a vector");
32125ffd83dbSDimitry Andric         I.setDesc(TII.get(TargetOpcode::COPY));
3213349cc55cSDimitry Andric         return selectCopy(I, TII, MRI, TRI, RBI);
32145ffd83dbSDimitry Andric       }
32155ffd83dbSDimitry Andric     }
32165ffd83dbSDimitry Andric 
32175ffd83dbSDimitry Andric     return false;
32185ffd83dbSDimitry Andric   }
32195ffd83dbSDimitry Andric 
32205ffd83dbSDimitry Andric   case TargetOpcode::G_ANYEXT: {
3221349cc55cSDimitry Andric     if (selectUSMovFromExtend(I, MRI))
3222349cc55cSDimitry Andric       return true;
3223349cc55cSDimitry Andric 
32245ffd83dbSDimitry Andric     const Register DstReg = I.getOperand(0).getReg();
32255ffd83dbSDimitry Andric     const Register SrcReg = I.getOperand(1).getReg();
32265ffd83dbSDimitry Andric 
32275ffd83dbSDimitry Andric     const RegisterBank &RBDst = *RBI.getRegBank(DstReg, MRI, TRI);
32285ffd83dbSDimitry Andric     if (RBDst.getID() != AArch64::GPRRegBankID) {
32295ffd83dbSDimitry Andric       LLVM_DEBUG(dbgs() << "G_ANYEXT on bank: " << RBDst
32305ffd83dbSDimitry Andric                         << ", expected: GPR\n");
32315ffd83dbSDimitry Andric       return false;
32325ffd83dbSDimitry Andric     }
32335ffd83dbSDimitry Andric 
32345ffd83dbSDimitry Andric     const RegisterBank &RBSrc = *RBI.getRegBank(SrcReg, MRI, TRI);
32355ffd83dbSDimitry Andric     if (RBSrc.getID() != AArch64::GPRRegBankID) {
32365ffd83dbSDimitry Andric       LLVM_DEBUG(dbgs() << "G_ANYEXT on bank: " << RBSrc
32375ffd83dbSDimitry Andric                         << ", expected: GPR\n");
32385ffd83dbSDimitry Andric       return false;
32395ffd83dbSDimitry Andric     }
32405ffd83dbSDimitry Andric 
32415ffd83dbSDimitry Andric     const unsigned DstSize = MRI.getType(DstReg).getSizeInBits();
32425ffd83dbSDimitry Andric 
32435ffd83dbSDimitry Andric     if (DstSize == 0) {
32445ffd83dbSDimitry Andric       LLVM_DEBUG(dbgs() << "G_ANYEXT operand has no size, not a gvreg?\n");
32455ffd83dbSDimitry Andric       return false;
32465ffd83dbSDimitry Andric     }
32475ffd83dbSDimitry Andric 
32485ffd83dbSDimitry Andric     if (DstSize != 64 && DstSize > 32) {
32495ffd83dbSDimitry Andric       LLVM_DEBUG(dbgs() << "G_ANYEXT to size: " << DstSize
32505ffd83dbSDimitry Andric                         << ", expected: 32 or 64\n");
32515ffd83dbSDimitry Andric       return false;
32525ffd83dbSDimitry Andric     }
32535ffd83dbSDimitry Andric     // At this point G_ANYEXT is just like a plain COPY, but we need
32545ffd83dbSDimitry Andric     // to explicitly form the 64-bit value if any.
32555ffd83dbSDimitry Andric     if (DstSize > 32) {
32565ffd83dbSDimitry Andric       Register ExtSrc = MRI.createVirtualRegister(&AArch64::GPR64allRegClass);
32575ffd83dbSDimitry Andric       BuildMI(MBB, I, I.getDebugLoc(), TII.get(AArch64::SUBREG_TO_REG))
32585ffd83dbSDimitry Andric           .addDef(ExtSrc)
32595ffd83dbSDimitry Andric           .addImm(0)
32605ffd83dbSDimitry Andric           .addUse(SrcReg)
32615ffd83dbSDimitry Andric           .addImm(AArch64::sub_32);
32625ffd83dbSDimitry Andric       I.getOperand(1).setReg(ExtSrc);
32635ffd83dbSDimitry Andric     }
32645ffd83dbSDimitry Andric     return selectCopy(I, TII, MRI, TRI, RBI);
32655ffd83dbSDimitry Andric   }
32665ffd83dbSDimitry Andric 
32675ffd83dbSDimitry Andric   case TargetOpcode::G_ZEXT:
32685ffd83dbSDimitry Andric   case TargetOpcode::G_SEXT_INREG:
32695ffd83dbSDimitry Andric   case TargetOpcode::G_SEXT: {
3270349cc55cSDimitry Andric     if (selectUSMovFromExtend(I, MRI))
3271349cc55cSDimitry Andric       return true;
3272349cc55cSDimitry Andric 
32735ffd83dbSDimitry Andric     unsigned Opcode = I.getOpcode();
32745ffd83dbSDimitry Andric     const bool IsSigned = Opcode != TargetOpcode::G_ZEXT;
32755ffd83dbSDimitry Andric     const Register DefReg = I.getOperand(0).getReg();
32765ffd83dbSDimitry Andric     Register SrcReg = I.getOperand(1).getReg();
32775ffd83dbSDimitry Andric     const LLT DstTy = MRI.getType(DefReg);
32785ffd83dbSDimitry Andric     const LLT SrcTy = MRI.getType(SrcReg);
32795ffd83dbSDimitry Andric     unsigned DstSize = DstTy.getSizeInBits();
32805ffd83dbSDimitry Andric     unsigned SrcSize = SrcTy.getSizeInBits();
32815ffd83dbSDimitry Andric 
32825ffd83dbSDimitry Andric     // SEXT_INREG has the same src reg size as dst, the size of the value to be
32835ffd83dbSDimitry Andric     // extended is encoded in the imm.
32845ffd83dbSDimitry Andric     if (Opcode == TargetOpcode::G_SEXT_INREG)
32855ffd83dbSDimitry Andric       SrcSize = I.getOperand(2).getImm();
32865ffd83dbSDimitry Andric 
32875ffd83dbSDimitry Andric     if (DstTy.isVector())
32885ffd83dbSDimitry Andric       return false; // Should be handled by imported patterns.
32895ffd83dbSDimitry Andric 
32905ffd83dbSDimitry Andric     assert((*RBI.getRegBank(DefReg, MRI, TRI)).getID() ==
32915ffd83dbSDimitry Andric                AArch64::GPRRegBankID &&
32925ffd83dbSDimitry Andric            "Unexpected ext regbank");
32935ffd83dbSDimitry Andric 
32945ffd83dbSDimitry Andric     MachineInstr *ExtI;
32955ffd83dbSDimitry Andric 
32965ffd83dbSDimitry Andric     // First check if we're extending the result of a load which has a dest type
32975ffd83dbSDimitry Andric     // smaller than 32 bits, then this zext is redundant. GPR32 is the smallest
32985ffd83dbSDimitry Andric     // GPR register on AArch64 and all loads which are smaller automatically
32995ffd83dbSDimitry Andric     // zero-extend the upper bits. E.g.
33005ffd83dbSDimitry Andric     // %v(s8) = G_LOAD %p, :: (load 1)
33015ffd83dbSDimitry Andric     // %v2(s32) = G_ZEXT %v(s8)
33025ffd83dbSDimitry Andric     if (!IsSigned) {
33035ffd83dbSDimitry Andric       auto *LoadMI = getOpcodeDef(TargetOpcode::G_LOAD, SrcReg, MRI);
33045ffd83dbSDimitry Andric       bool IsGPR =
33055ffd83dbSDimitry Andric           RBI.getRegBank(SrcReg, MRI, TRI)->getID() == AArch64::GPRRegBankID;
33065ffd83dbSDimitry Andric       if (LoadMI && IsGPR) {
33075ffd83dbSDimitry Andric         const MachineMemOperand *MemOp = *LoadMI->memoperands_begin();
3308*0fca6ea1SDimitry Andric         unsigned BytesLoaded = MemOp->getSize().getValue();
33095ffd83dbSDimitry Andric         if (BytesLoaded < 4 && SrcTy.getSizeInBytes() == BytesLoaded)
33105ffd83dbSDimitry Andric           return selectCopy(I, TII, MRI, TRI, RBI);
33115ffd83dbSDimitry Andric       }
33125ffd83dbSDimitry Andric 
3313fe6060f1SDimitry Andric       // For the 32-bit -> 64-bit case, we can emit a mov (ORRWrs)
3314fe6060f1SDimitry Andric       // + SUBREG_TO_REG.
33155ffd83dbSDimitry Andric       if (IsGPR && SrcSize == 32 && DstSize == 64) {
3316bdd1243dSDimitry Andric         Register SubregToRegSrc =
3317bdd1243dSDimitry Andric             MRI.createVirtualRegister(&AArch64::GPR32RegClass);
3318fe6060f1SDimitry Andric         const Register ZReg = AArch64::WZR;
3319bdd1243dSDimitry Andric         MIB.buildInstr(AArch64::ORRWrs, {SubregToRegSrc}, {ZReg, SrcReg})
3320bdd1243dSDimitry Andric             .addImm(0);
3321fe6060f1SDimitry Andric 
33225ffd83dbSDimitry Andric         MIB.buildInstr(AArch64::SUBREG_TO_REG, {DefReg}, {})
33235ffd83dbSDimitry Andric             .addImm(0)
3324fe6060f1SDimitry Andric             .addUse(SubregToRegSrc)
33255ffd83dbSDimitry Andric             .addImm(AArch64::sub_32);
33265ffd83dbSDimitry Andric 
33275ffd83dbSDimitry Andric         if (!RBI.constrainGenericRegister(DefReg, AArch64::GPR64RegClass,
33285ffd83dbSDimitry Andric                                           MRI)) {
33295ffd83dbSDimitry Andric           LLVM_DEBUG(dbgs() << "Failed to constrain G_ZEXT destination\n");
33305ffd83dbSDimitry Andric           return false;
33315ffd83dbSDimitry Andric         }
33325ffd83dbSDimitry Andric 
33335ffd83dbSDimitry Andric         if (!RBI.constrainGenericRegister(SrcReg, AArch64::GPR32RegClass,
33345ffd83dbSDimitry Andric                                           MRI)) {
33355ffd83dbSDimitry Andric           LLVM_DEBUG(dbgs() << "Failed to constrain G_ZEXT source\n");
33365ffd83dbSDimitry Andric           return false;
33375ffd83dbSDimitry Andric         }
33385ffd83dbSDimitry Andric 
33395ffd83dbSDimitry Andric         I.eraseFromParent();
33405ffd83dbSDimitry Andric         return true;
33415ffd83dbSDimitry Andric       }
33425ffd83dbSDimitry Andric     }
33435ffd83dbSDimitry Andric 
33445ffd83dbSDimitry Andric     if (DstSize == 64) {
33455ffd83dbSDimitry Andric       if (Opcode != TargetOpcode::G_SEXT_INREG) {
33465ffd83dbSDimitry Andric         // FIXME: Can we avoid manually doing this?
33475ffd83dbSDimitry Andric         if (!RBI.constrainGenericRegister(SrcReg, AArch64::GPR32RegClass,
33485ffd83dbSDimitry Andric                                           MRI)) {
33495ffd83dbSDimitry Andric           LLVM_DEBUG(dbgs() << "Failed to constrain " << TII.getName(Opcode)
33505ffd83dbSDimitry Andric                             << " operand\n");
33515ffd83dbSDimitry Andric           return false;
33525ffd83dbSDimitry Andric         }
33535ffd83dbSDimitry Andric         SrcReg = MIB.buildInstr(AArch64::SUBREG_TO_REG,
33545ffd83dbSDimitry Andric                                 {&AArch64::GPR64RegClass}, {})
33555ffd83dbSDimitry Andric                      .addImm(0)
33565ffd83dbSDimitry Andric                      .addUse(SrcReg)
33575ffd83dbSDimitry Andric                      .addImm(AArch64::sub_32)
33585ffd83dbSDimitry Andric                      .getReg(0);
33595ffd83dbSDimitry Andric       }
33605ffd83dbSDimitry Andric 
33615ffd83dbSDimitry Andric       ExtI = MIB.buildInstr(IsSigned ? AArch64::SBFMXri : AArch64::UBFMXri,
33625ffd83dbSDimitry Andric                              {DefReg}, {SrcReg})
33635ffd83dbSDimitry Andric                   .addImm(0)
33645ffd83dbSDimitry Andric                   .addImm(SrcSize - 1);
33655ffd83dbSDimitry Andric     } else if (DstSize <= 32) {
33665ffd83dbSDimitry Andric       ExtI = MIB.buildInstr(IsSigned ? AArch64::SBFMWri : AArch64::UBFMWri,
33675ffd83dbSDimitry Andric                              {DefReg}, {SrcReg})
33685ffd83dbSDimitry Andric                   .addImm(0)
33695ffd83dbSDimitry Andric                   .addImm(SrcSize - 1);
33705ffd83dbSDimitry Andric     } else {
33715ffd83dbSDimitry Andric       return false;
33725ffd83dbSDimitry Andric     }
33735ffd83dbSDimitry Andric 
33745ffd83dbSDimitry Andric     constrainSelectedInstRegOperands(*ExtI, TII, TRI, RBI);
33755ffd83dbSDimitry Andric     I.eraseFromParent();
33765ffd83dbSDimitry Andric     return true;
33775ffd83dbSDimitry Andric   }
33785ffd83dbSDimitry Andric 
33795ffd83dbSDimitry Andric   case TargetOpcode::G_SITOFP:
33805ffd83dbSDimitry Andric   case TargetOpcode::G_UITOFP:
33815ffd83dbSDimitry Andric   case TargetOpcode::G_FPTOSI:
33825ffd83dbSDimitry Andric   case TargetOpcode::G_FPTOUI: {
33835ffd83dbSDimitry Andric     const LLT DstTy = MRI.getType(I.getOperand(0).getReg()),
33845ffd83dbSDimitry Andric               SrcTy = MRI.getType(I.getOperand(1).getReg());
33855ffd83dbSDimitry Andric     const unsigned NewOpc = selectFPConvOpc(Opcode, DstTy, SrcTy);
33865ffd83dbSDimitry Andric     if (NewOpc == Opcode)
33875ffd83dbSDimitry Andric       return false;
33885ffd83dbSDimitry Andric 
33895ffd83dbSDimitry Andric     I.setDesc(TII.get(NewOpc));
33905ffd83dbSDimitry Andric     constrainSelectedInstRegOperands(I, TII, TRI, RBI);
339181ad6265SDimitry Andric     I.setFlags(MachineInstr::NoFPExcept);
33925ffd83dbSDimitry Andric 
33935ffd83dbSDimitry Andric     return true;
33945ffd83dbSDimitry Andric   }
33955ffd83dbSDimitry Andric 
33965ffd83dbSDimitry Andric   case TargetOpcode::G_FREEZE:
33975ffd83dbSDimitry Andric     return selectCopy(I, TII, MRI, TRI, RBI);
33985ffd83dbSDimitry Andric 
33995ffd83dbSDimitry Andric   case TargetOpcode::G_INTTOPTR:
34005ffd83dbSDimitry Andric     // The importer is currently unable to import pointer types since they
34015ffd83dbSDimitry Andric     // didn't exist in SelectionDAG.
34025ffd83dbSDimitry Andric     return selectCopy(I, TII, MRI, TRI, RBI);
34035ffd83dbSDimitry Andric 
34045ffd83dbSDimitry Andric   case TargetOpcode::G_BITCAST:
34055ffd83dbSDimitry Andric     // Imported SelectionDAG rules can handle every bitcast except those that
34065ffd83dbSDimitry Andric     // bitcast from a type to the same type. Ideally, these shouldn't occur
34075ffd83dbSDimitry Andric     // but we might not run an optimizer that deletes them. The other exception
34085ffd83dbSDimitry Andric     // is bitcasts involving pointer types, as SelectionDAG has no knowledge
34095ffd83dbSDimitry Andric     // of them.
34105ffd83dbSDimitry Andric     return selectCopy(I, TII, MRI, TRI, RBI);
34115ffd83dbSDimitry Andric 
34125ffd83dbSDimitry Andric   case TargetOpcode::G_SELECT: {
341381ad6265SDimitry Andric     auto &Sel = cast<GSelect>(I);
341481ad6265SDimitry Andric     const Register CondReg = Sel.getCondReg();
341581ad6265SDimitry Andric     const Register TReg = Sel.getTrueReg();
341681ad6265SDimitry Andric     const Register FReg = Sel.getFalseReg();
34175ffd83dbSDimitry Andric 
341881ad6265SDimitry Andric     if (tryOptSelect(Sel))
34195ffd83dbSDimitry Andric       return true;
34205ffd83dbSDimitry Andric 
3421e8d8bef9SDimitry Andric     // Make sure to use an unused vreg instead of wzr, so that the peephole
3422e8d8bef9SDimitry Andric     // optimizations will be able to optimize these.
3423e8d8bef9SDimitry Andric     Register DeadVReg = MRI.createVirtualRegister(&AArch64::GPR32RegClass);
3424e8d8bef9SDimitry Andric     auto TstMI = MIB.buildInstr(AArch64::ANDSWri, {DeadVReg}, {CondReg})
34255ffd83dbSDimitry Andric                      .addImm(AArch64_AM::encodeLogicalImmediate(1, 32));
3426e8d8bef9SDimitry Andric     constrainSelectedInstRegOperands(*TstMI, TII, TRI, RBI);
342781ad6265SDimitry Andric     if (!emitSelect(Sel.getReg(0), TReg, FReg, AArch64CC::NE, MIB))
3428e8d8bef9SDimitry Andric       return false;
342981ad6265SDimitry Andric     Sel.eraseFromParent();
34305ffd83dbSDimitry Andric     return true;
34315ffd83dbSDimitry Andric   }
34325ffd83dbSDimitry Andric   case TargetOpcode::G_ICMP: {
34335ffd83dbSDimitry Andric     if (Ty.isVector())
3434*0fca6ea1SDimitry Andric       return false;
34355ffd83dbSDimitry Andric 
34365ffd83dbSDimitry Andric     if (Ty != LLT::scalar(32)) {
34375ffd83dbSDimitry Andric       LLVM_DEBUG(dbgs() << "G_ICMP result has type: " << Ty
34385ffd83dbSDimitry Andric                         << ", expected: " << LLT::scalar(32) << '\n');
34395ffd83dbSDimitry Andric       return false;
34405ffd83dbSDimitry Andric     }
34415ffd83dbSDimitry Andric 
3442e8d8bef9SDimitry Andric     auto Pred = static_cast<CmpInst::Predicate>(I.getOperand(1).getPredicate());
3443349cc55cSDimitry Andric     const AArch64CC::CondCode InvCC =
3444349cc55cSDimitry Andric         changeICMPPredToAArch64CC(CmpInst::getInversePredicate(Pred));
3445349cc55cSDimitry Andric     emitIntegerCompare(I.getOperand(2), I.getOperand(3), I.getOperand(1), MIB);
3446349cc55cSDimitry Andric     emitCSINC(/*Dst=*/I.getOperand(0).getReg(), /*Src1=*/AArch64::WZR,
3447349cc55cSDimitry Andric               /*Src2=*/AArch64::WZR, InvCC, MIB);
34485ffd83dbSDimitry Andric     I.eraseFromParent();
34495ffd83dbSDimitry Andric     return true;
34505ffd83dbSDimitry Andric   }
34515ffd83dbSDimitry Andric 
34525ffd83dbSDimitry Andric   case TargetOpcode::G_FCMP: {
3453e8d8bef9SDimitry Andric     CmpInst::Predicate Pred =
3454e8d8bef9SDimitry Andric         static_cast<CmpInst::Predicate>(I.getOperand(1).getPredicate());
3455fe6060f1SDimitry Andric     if (!emitFPCompare(I.getOperand(2).getReg(), I.getOperand(3).getReg(), MIB,
3456fe6060f1SDimitry Andric                        Pred) ||
3457fe6060f1SDimitry Andric         !emitCSetForFCmp(I.getOperand(0).getReg(), Pred, MIB))
34585ffd83dbSDimitry Andric       return false;
34595ffd83dbSDimitry Andric     I.eraseFromParent();
34605ffd83dbSDimitry Andric     return true;
34615ffd83dbSDimitry Andric   }
34625ffd83dbSDimitry Andric   case TargetOpcode::G_VASTART:
34635ffd83dbSDimitry Andric     return STI.isTargetDarwin() ? selectVaStartDarwin(I, MF, MRI)
34645ffd83dbSDimitry Andric                                 : selectVaStartAAPCS(I, MF, MRI);
34655ffd83dbSDimitry Andric   case TargetOpcode::G_INTRINSIC:
34665ffd83dbSDimitry Andric     return selectIntrinsic(I, MRI);
34675ffd83dbSDimitry Andric   case TargetOpcode::G_INTRINSIC_W_SIDE_EFFECTS:
34685ffd83dbSDimitry Andric     return selectIntrinsicWithSideEffects(I, MRI);
34695ffd83dbSDimitry Andric   case TargetOpcode::G_IMPLICIT_DEF: {
34705ffd83dbSDimitry Andric     I.setDesc(TII.get(TargetOpcode::IMPLICIT_DEF));
34715ffd83dbSDimitry Andric     const LLT DstTy = MRI.getType(I.getOperand(0).getReg());
34725ffd83dbSDimitry Andric     const Register DstReg = I.getOperand(0).getReg();
34735ffd83dbSDimitry Andric     const RegisterBank &DstRB = *RBI.getRegBank(DstReg, MRI, TRI);
347481ad6265SDimitry Andric     const TargetRegisterClass *DstRC = getRegClassForTypeOnBank(DstTy, DstRB);
34755ffd83dbSDimitry Andric     RBI.constrainGenericRegister(DstReg, *DstRC, MRI);
34765ffd83dbSDimitry Andric     return true;
34775ffd83dbSDimitry Andric   }
34785ffd83dbSDimitry Andric   case TargetOpcode::G_BLOCK_ADDR: {
3479*0fca6ea1SDimitry Andric     Function *BAFn = I.getOperand(1).getBlockAddress()->getFunction();
3480*0fca6ea1SDimitry Andric     if (std::optional<uint16_t> BADisc =
3481*0fca6ea1SDimitry Andric             STI.getPtrAuthBlockAddressDiscriminatorIfEnabled(*BAFn)) {
3482*0fca6ea1SDimitry Andric       MIB.buildInstr(TargetOpcode::IMPLICIT_DEF, {AArch64::X16}, {});
3483*0fca6ea1SDimitry Andric       MIB.buildInstr(TargetOpcode::IMPLICIT_DEF, {AArch64::X17}, {});
3484*0fca6ea1SDimitry Andric       MIB.buildInstr(AArch64::MOVaddrPAC)
3485*0fca6ea1SDimitry Andric           .addBlockAddress(I.getOperand(1).getBlockAddress())
3486*0fca6ea1SDimitry Andric           .addImm(AArch64PACKey::IA)
3487*0fca6ea1SDimitry Andric           .addReg(/*AddrDisc=*/AArch64::XZR)
3488*0fca6ea1SDimitry Andric           .addImm(*BADisc)
3489*0fca6ea1SDimitry Andric           .constrainAllUses(TII, TRI, RBI);
3490*0fca6ea1SDimitry Andric       MIB.buildCopy(I.getOperand(0).getReg(), Register(AArch64::X16));
3491*0fca6ea1SDimitry Andric       RBI.constrainGenericRegister(I.getOperand(0).getReg(),
3492*0fca6ea1SDimitry Andric                                    AArch64::GPR64RegClass, MRI);
3493*0fca6ea1SDimitry Andric       I.eraseFromParent();
3494*0fca6ea1SDimitry Andric       return true;
3495*0fca6ea1SDimitry Andric     }
34965f757f3fSDimitry Andric     if (TM.getCodeModel() == CodeModel::Large && !TM.isPositionIndependent()) {
34975ffd83dbSDimitry Andric       materializeLargeCMVal(I, I.getOperand(1).getBlockAddress(), 0);
34985ffd83dbSDimitry Andric       I.eraseFromParent();
34995ffd83dbSDimitry Andric       return true;
35005ffd83dbSDimitry Andric     } else {
35015ffd83dbSDimitry Andric       I.setDesc(TII.get(AArch64::MOVaddrBA));
35025ffd83dbSDimitry Andric       auto MovMI = BuildMI(MBB, I, I.getDebugLoc(), TII.get(AArch64::MOVaddrBA),
35035ffd83dbSDimitry Andric                            I.getOperand(0).getReg())
35045ffd83dbSDimitry Andric                        .addBlockAddress(I.getOperand(1).getBlockAddress(),
35055ffd83dbSDimitry Andric                                         /* Offset */ 0, AArch64II::MO_PAGE)
35065ffd83dbSDimitry Andric                        .addBlockAddress(
35075ffd83dbSDimitry Andric                            I.getOperand(1).getBlockAddress(), /* Offset */ 0,
35085ffd83dbSDimitry Andric                            AArch64II::MO_NC | AArch64II::MO_PAGEOFF);
35095ffd83dbSDimitry Andric       I.eraseFromParent();
35105ffd83dbSDimitry Andric       return constrainSelectedInstRegOperands(*MovMI, TII, TRI, RBI);
35115ffd83dbSDimitry Andric     }
35125ffd83dbSDimitry Andric   }
3513e8d8bef9SDimitry Andric   case AArch64::G_DUP: {
3514e8d8bef9SDimitry Andric     // When the scalar of G_DUP is an s8/s16 gpr, they can't be selected by
3515e8d8bef9SDimitry Andric     // imported patterns. Do it manually here. Avoiding generating s16 gpr is
3516e8d8bef9SDimitry Andric     // difficult because at RBS we may end up pessimizing the fpr case if we
3517e8d8bef9SDimitry Andric     // decided to add an anyextend to fix this. Manual selection is the most
3518e8d8bef9SDimitry Andric     // robust solution for now.
3519fe6060f1SDimitry Andric     if (RBI.getRegBank(I.getOperand(1).getReg(), MRI, TRI)->getID() !=
3520fe6060f1SDimitry Andric         AArch64::GPRRegBankID)
3521e8d8bef9SDimitry Andric       return false; // We expect the fpr regbank case to be imported.
3522fe6060f1SDimitry Andric     LLT VecTy = MRI.getType(I.getOperand(0).getReg());
3523fe6060f1SDimitry Andric     if (VecTy == LLT::fixed_vector(8, 8))
3524fe6060f1SDimitry Andric       I.setDesc(TII.get(AArch64::DUPv8i8gpr));
3525fe6060f1SDimitry Andric     else if (VecTy == LLT::fixed_vector(16, 8))
3526e8d8bef9SDimitry Andric       I.setDesc(TII.get(AArch64::DUPv16i8gpr));
3527fe6060f1SDimitry Andric     else if (VecTy == LLT::fixed_vector(4, 16))
3528fe6060f1SDimitry Andric       I.setDesc(TII.get(AArch64::DUPv4i16gpr));
3529fe6060f1SDimitry Andric     else if (VecTy == LLT::fixed_vector(8, 16))
3530fe6060f1SDimitry Andric       I.setDesc(TII.get(AArch64::DUPv8i16gpr));
3531e8d8bef9SDimitry Andric     else
3532e8d8bef9SDimitry Andric       return false;
3533e8d8bef9SDimitry Andric     return constrainSelectedInstRegOperands(I, TII, TRI, RBI);
3534e8d8bef9SDimitry Andric   }
35355ffd83dbSDimitry Andric   case TargetOpcode::G_BUILD_VECTOR:
35365ffd83dbSDimitry Andric     return selectBuildVector(I, MRI);
35375ffd83dbSDimitry Andric   case TargetOpcode::G_MERGE_VALUES:
35385ffd83dbSDimitry Andric     return selectMergeValues(I, MRI);
35395ffd83dbSDimitry Andric   case TargetOpcode::G_UNMERGE_VALUES:
35405ffd83dbSDimitry Andric     return selectUnmergeValues(I, MRI);
35415ffd83dbSDimitry Andric   case TargetOpcode::G_SHUFFLE_VECTOR:
35425ffd83dbSDimitry Andric     return selectShuffleVector(I, MRI);
35435ffd83dbSDimitry Andric   case TargetOpcode::G_EXTRACT_VECTOR_ELT:
35445ffd83dbSDimitry Andric     return selectExtractElt(I, MRI);
35455ffd83dbSDimitry Andric   case TargetOpcode::G_CONCAT_VECTORS:
35465ffd83dbSDimitry Andric     return selectConcatVectors(I, MRI);
35475ffd83dbSDimitry Andric   case TargetOpcode::G_JUMP_TABLE:
35485ffd83dbSDimitry Andric     return selectJumpTable(I, MRI);
35491fd87a68SDimitry Andric   case TargetOpcode::G_MEMCPY:
35501fd87a68SDimitry Andric   case TargetOpcode::G_MEMCPY_INLINE:
35511fd87a68SDimitry Andric   case TargetOpcode::G_MEMMOVE:
35521fd87a68SDimitry Andric   case TargetOpcode::G_MEMSET:
35531fd87a68SDimitry Andric     assert(STI.hasMOPS() && "Shouldn't get here without +mops feature");
35541fd87a68SDimitry Andric     return selectMOPS(I, MRI);
35555ffd83dbSDimitry Andric   }
35565ffd83dbSDimitry Andric 
35575ffd83dbSDimitry Andric   return false;
35585ffd83dbSDimitry Andric }
35595ffd83dbSDimitry Andric 
selectAndRestoreState(MachineInstr & I)35605f757f3fSDimitry Andric bool AArch64InstructionSelector::selectAndRestoreState(MachineInstr &I) {
35615f757f3fSDimitry Andric   MachineIRBuilderState OldMIBState = MIB.getState();
35625f757f3fSDimitry Andric   bool Success = select(I);
35635f757f3fSDimitry Andric   MIB.setState(OldMIBState);
35645f757f3fSDimitry Andric   return Success;
3565e8d8bef9SDimitry Andric }
3566e8d8bef9SDimitry Andric 
selectMOPS(MachineInstr & GI,MachineRegisterInfo & MRI)35671fd87a68SDimitry Andric bool AArch64InstructionSelector::selectMOPS(MachineInstr &GI,
35681fd87a68SDimitry Andric                                             MachineRegisterInfo &MRI) {
35691fd87a68SDimitry Andric   unsigned Mopcode;
35701fd87a68SDimitry Andric   switch (GI.getOpcode()) {
35711fd87a68SDimitry Andric   case TargetOpcode::G_MEMCPY:
35721fd87a68SDimitry Andric   case TargetOpcode::G_MEMCPY_INLINE:
35731fd87a68SDimitry Andric     Mopcode = AArch64::MOPSMemoryCopyPseudo;
35741fd87a68SDimitry Andric     break;
35751fd87a68SDimitry Andric   case TargetOpcode::G_MEMMOVE:
35761fd87a68SDimitry Andric     Mopcode = AArch64::MOPSMemoryMovePseudo;
35771fd87a68SDimitry Andric     break;
35781fd87a68SDimitry Andric   case TargetOpcode::G_MEMSET:
35791fd87a68SDimitry Andric     // For tagged memset see llvm.aarch64.mops.memset.tag
35801fd87a68SDimitry Andric     Mopcode = AArch64::MOPSMemorySetPseudo;
35811fd87a68SDimitry Andric     break;
35821fd87a68SDimitry Andric   }
35831fd87a68SDimitry Andric 
35841fd87a68SDimitry Andric   auto &DstPtr = GI.getOperand(0);
35851fd87a68SDimitry Andric   auto &SrcOrVal = GI.getOperand(1);
35861fd87a68SDimitry Andric   auto &Size = GI.getOperand(2);
35871fd87a68SDimitry Andric 
35881fd87a68SDimitry Andric   // Create copies of the registers that can be clobbered.
35891fd87a68SDimitry Andric   const Register DstPtrCopy = MRI.cloneVirtualRegister(DstPtr.getReg());
35901fd87a68SDimitry Andric   const Register SrcValCopy = MRI.cloneVirtualRegister(SrcOrVal.getReg());
35911fd87a68SDimitry Andric   const Register SizeCopy = MRI.cloneVirtualRegister(Size.getReg());
35921fd87a68SDimitry Andric 
35931fd87a68SDimitry Andric   const bool IsSet = Mopcode == AArch64::MOPSMemorySetPseudo;
35941fd87a68SDimitry Andric   const auto &SrcValRegClass =
35951fd87a68SDimitry Andric       IsSet ? AArch64::GPR64RegClass : AArch64::GPR64commonRegClass;
35961fd87a68SDimitry Andric 
35971fd87a68SDimitry Andric   // Constrain to specific registers
35981fd87a68SDimitry Andric   RBI.constrainGenericRegister(DstPtrCopy, AArch64::GPR64commonRegClass, MRI);
35991fd87a68SDimitry Andric   RBI.constrainGenericRegister(SrcValCopy, SrcValRegClass, MRI);
36001fd87a68SDimitry Andric   RBI.constrainGenericRegister(SizeCopy, AArch64::GPR64RegClass, MRI);
36011fd87a68SDimitry Andric 
36021fd87a68SDimitry Andric   MIB.buildCopy(DstPtrCopy, DstPtr);
36031fd87a68SDimitry Andric   MIB.buildCopy(SrcValCopy, SrcOrVal);
36041fd87a68SDimitry Andric   MIB.buildCopy(SizeCopy, Size);
36051fd87a68SDimitry Andric 
36061fd87a68SDimitry Andric   // New instruction uses the copied registers because it must update them.
36071fd87a68SDimitry Andric   // The defs are not used since they don't exist in G_MEM*. They are still
36081fd87a68SDimitry Andric   // tied.
36091fd87a68SDimitry Andric   // Note: order of operands is different from G_MEMSET, G_MEMCPY, G_MEMMOVE
36101fd87a68SDimitry Andric   Register DefDstPtr = MRI.createVirtualRegister(&AArch64::GPR64commonRegClass);
36111fd87a68SDimitry Andric   Register DefSize = MRI.createVirtualRegister(&AArch64::GPR64RegClass);
36121fd87a68SDimitry Andric   if (IsSet) {
36131fd87a68SDimitry Andric     MIB.buildInstr(Mopcode, {DefDstPtr, DefSize},
36141fd87a68SDimitry Andric                    {DstPtrCopy, SizeCopy, SrcValCopy});
36151fd87a68SDimitry Andric   } else {
36161fd87a68SDimitry Andric     Register DefSrcPtr = MRI.createVirtualRegister(&SrcValRegClass);
36171fd87a68SDimitry Andric     MIB.buildInstr(Mopcode, {DefDstPtr, DefSrcPtr, DefSize},
36181fd87a68SDimitry Andric                    {DstPtrCopy, SrcValCopy, SizeCopy});
36191fd87a68SDimitry Andric   }
36201fd87a68SDimitry Andric 
36211fd87a68SDimitry Andric   GI.eraseFromParent();
36221fd87a68SDimitry Andric   return true;
36231fd87a68SDimitry Andric }
36241fd87a68SDimitry Andric 
selectBrJT(MachineInstr & I,MachineRegisterInfo & MRI)36255ffd83dbSDimitry Andric bool AArch64InstructionSelector::selectBrJT(MachineInstr &I,
3626fe6060f1SDimitry Andric                                             MachineRegisterInfo &MRI) {
36275ffd83dbSDimitry Andric   assert(I.getOpcode() == TargetOpcode::G_BRJT && "Expected G_BRJT");
36285ffd83dbSDimitry Andric   Register JTAddr = I.getOperand(0).getReg();
36295ffd83dbSDimitry Andric   unsigned JTI = I.getOperand(1).getIndex();
36305ffd83dbSDimitry Andric   Register Index = I.getOperand(2).getReg();
36315ffd83dbSDimitry Andric 
3632*0fca6ea1SDimitry Andric   MF->getInfo<AArch64FunctionInfo>()->setJumpTableEntryInfo(JTI, 4, nullptr);
3633*0fca6ea1SDimitry Andric 
3634*0fca6ea1SDimitry Andric   // With aarch64-jump-table-hardening, we only expand the jump table dispatch
3635*0fca6ea1SDimitry Andric   // sequence later, to guarantee the integrity of the intermediate values.
3636*0fca6ea1SDimitry Andric   if (MF->getFunction().hasFnAttribute("aarch64-jump-table-hardening")) {
3637*0fca6ea1SDimitry Andric     CodeModel::Model CM = TM.getCodeModel();
3638*0fca6ea1SDimitry Andric     if (STI.isTargetMachO()) {
3639*0fca6ea1SDimitry Andric       if (CM != CodeModel::Small && CM != CodeModel::Large)
3640*0fca6ea1SDimitry Andric         report_fatal_error("Unsupported code-model for hardened jump-table");
3641*0fca6ea1SDimitry Andric     } else {
3642*0fca6ea1SDimitry Andric       // Note that COFF support would likely also need JUMP_TABLE_DEBUG_INFO.
3643*0fca6ea1SDimitry Andric       assert(STI.isTargetELF() &&
3644*0fca6ea1SDimitry Andric              "jump table hardening only supported on MachO/ELF");
3645*0fca6ea1SDimitry Andric       if (CM != CodeModel::Small)
3646*0fca6ea1SDimitry Andric         report_fatal_error("Unsupported code-model for hardened jump-table");
3647*0fca6ea1SDimitry Andric     }
3648*0fca6ea1SDimitry Andric 
3649*0fca6ea1SDimitry Andric     MIB.buildCopy({AArch64::X16}, I.getOperand(2).getReg());
3650*0fca6ea1SDimitry Andric     MIB.buildInstr(AArch64::BR_JumpTable)
3651*0fca6ea1SDimitry Andric         .addJumpTableIndex(I.getOperand(1).getIndex());
3652*0fca6ea1SDimitry Andric     I.eraseFromParent();
3653*0fca6ea1SDimitry Andric     return true;
3654*0fca6ea1SDimitry Andric   }
3655*0fca6ea1SDimitry Andric 
36565ffd83dbSDimitry Andric   Register TargetReg = MRI.createVirtualRegister(&AArch64::GPR64RegClass);
36575ffd83dbSDimitry Andric   Register ScratchReg = MRI.createVirtualRegister(&AArch64::GPR64spRegClass);
3658e8d8bef9SDimitry Andric 
36595ffd83dbSDimitry Andric   auto JumpTableInst = MIB.buildInstr(AArch64::JumpTableDest32,
36605ffd83dbSDimitry Andric                                       {TargetReg, ScratchReg}, {JTAddr, Index})
36615ffd83dbSDimitry Andric                            .addJumpTableIndex(JTI);
36625f757f3fSDimitry Andric   // Save the jump table info.
36635f757f3fSDimitry Andric   MIB.buildInstr(TargetOpcode::JUMP_TABLE_DEBUG_INFO, {},
36645f757f3fSDimitry Andric                  {static_cast<int64_t>(JTI)});
36655ffd83dbSDimitry Andric   // Build the indirect branch.
36665ffd83dbSDimitry Andric   MIB.buildInstr(AArch64::BR, {}, {TargetReg});
36675ffd83dbSDimitry Andric   I.eraseFromParent();
36685ffd83dbSDimitry Andric   return constrainSelectedInstRegOperands(*JumpTableInst, TII, TRI, RBI);
36695ffd83dbSDimitry Andric }
36705ffd83dbSDimitry Andric 
selectJumpTable(MachineInstr & I,MachineRegisterInfo & MRI)3671fe6060f1SDimitry Andric bool AArch64InstructionSelector::selectJumpTable(MachineInstr &I,
3672fe6060f1SDimitry Andric                                                  MachineRegisterInfo &MRI) {
36735ffd83dbSDimitry Andric   assert(I.getOpcode() == TargetOpcode::G_JUMP_TABLE && "Expected jump table");
36745ffd83dbSDimitry Andric   assert(I.getOperand(1).isJTI() && "Jump table op should have a JTI!");
36755ffd83dbSDimitry Andric 
36765ffd83dbSDimitry Andric   Register DstReg = I.getOperand(0).getReg();
36775ffd83dbSDimitry Andric   unsigned JTI = I.getOperand(1).getIndex();
36785ffd83dbSDimitry Andric   // We generate a MOVaddrJT which will get expanded to an ADRP + ADD later.
36795ffd83dbSDimitry Andric   auto MovMI =
36805ffd83dbSDimitry Andric     MIB.buildInstr(AArch64::MOVaddrJT, {DstReg}, {})
36815ffd83dbSDimitry Andric           .addJumpTableIndex(JTI, AArch64II::MO_PAGE)
36825ffd83dbSDimitry Andric           .addJumpTableIndex(JTI, AArch64II::MO_NC | AArch64II::MO_PAGEOFF);
36835ffd83dbSDimitry Andric   I.eraseFromParent();
36845ffd83dbSDimitry Andric   return constrainSelectedInstRegOperands(*MovMI, TII, TRI, RBI);
36855ffd83dbSDimitry Andric }
36865ffd83dbSDimitry Andric 
selectTLSGlobalValue(MachineInstr & I,MachineRegisterInfo & MRI)36875ffd83dbSDimitry Andric bool AArch64InstructionSelector::selectTLSGlobalValue(
3688fe6060f1SDimitry Andric     MachineInstr &I, MachineRegisterInfo &MRI) {
36895ffd83dbSDimitry Andric   if (!STI.isTargetMachO())
36905ffd83dbSDimitry Andric     return false;
36915ffd83dbSDimitry Andric   MachineFunction &MF = *I.getParent()->getParent();
36925ffd83dbSDimitry Andric   MF.getFrameInfo().setAdjustsStack(true);
36935ffd83dbSDimitry Andric 
3694fe6060f1SDimitry Andric   const auto &GlobalOp = I.getOperand(1);
3695fe6060f1SDimitry Andric   assert(GlobalOp.getOffset() == 0 &&
3696fe6060f1SDimitry Andric          "Shouldn't have an offset on TLS globals!");
3697fe6060f1SDimitry Andric   const GlobalValue &GV = *GlobalOp.getGlobal();
36985ffd83dbSDimitry Andric 
3699e8d8bef9SDimitry Andric   auto LoadGOT =
3700e8d8bef9SDimitry Andric       MIB.buildInstr(AArch64::LOADgot, {&AArch64::GPR64commonRegClass}, {})
37015ffd83dbSDimitry Andric           .addGlobalAddress(&GV, 0, AArch64II::MO_TLS);
37025ffd83dbSDimitry Andric 
37035ffd83dbSDimitry Andric   auto Load = MIB.buildInstr(AArch64::LDRXui, {&AArch64::GPR64commonRegClass},
3704e8d8bef9SDimitry Andric                              {LoadGOT.getReg(0)})
37055ffd83dbSDimitry Andric                   .addImm(0);
37065ffd83dbSDimitry Andric 
3707e8d8bef9SDimitry Andric   MIB.buildCopy(Register(AArch64::X0), LoadGOT.getReg(0));
37085ffd83dbSDimitry Andric   // TLS calls preserve all registers except those that absolutely must be
37095ffd83dbSDimitry Andric   // trashed: X0 (it takes an argument), LR (it's a call) and NZCV (let's not be
37105ffd83dbSDimitry Andric   // silly).
3711*0fca6ea1SDimitry Andric   unsigned Opcode = getBLRCallOpcode(MF);
3712*0fca6ea1SDimitry Andric 
3713*0fca6ea1SDimitry Andric   // With ptrauth-calls, the tlv access thunk pointer is authenticated (IA, 0).
3714*0fca6ea1SDimitry Andric   if (MF.getFunction().hasFnAttribute("ptrauth-calls")) {
3715*0fca6ea1SDimitry Andric     assert(Opcode == AArch64::BLR);
3716*0fca6ea1SDimitry Andric     Opcode = AArch64::BLRAAZ;
3717*0fca6ea1SDimitry Andric   }
3718*0fca6ea1SDimitry Andric 
3719*0fca6ea1SDimitry Andric   MIB.buildInstr(Opcode, {}, {Load})
3720e8d8bef9SDimitry Andric       .addUse(AArch64::X0, RegState::Implicit)
37215ffd83dbSDimitry Andric       .addDef(AArch64::X0, RegState::Implicit)
37225ffd83dbSDimitry Andric       .addRegMask(TRI.getTLSCallPreservedMask());
37235ffd83dbSDimitry Andric 
37245ffd83dbSDimitry Andric   MIB.buildCopy(I.getOperand(0).getReg(), Register(AArch64::X0));
37255ffd83dbSDimitry Andric   RBI.constrainGenericRegister(I.getOperand(0).getReg(), AArch64::GPR64RegClass,
37265ffd83dbSDimitry Andric                                MRI);
37275ffd83dbSDimitry Andric   I.eraseFromParent();
37285ffd83dbSDimitry Andric   return true;
37295ffd83dbSDimitry Andric }
37305ffd83dbSDimitry Andric 
emitScalarToVector(unsigned EltSize,const TargetRegisterClass * DstRC,Register Scalar,MachineIRBuilder & MIRBuilder) const37315ffd83dbSDimitry Andric MachineInstr *AArch64InstructionSelector::emitScalarToVector(
37325ffd83dbSDimitry Andric     unsigned EltSize, const TargetRegisterClass *DstRC, Register Scalar,
37335ffd83dbSDimitry Andric     MachineIRBuilder &MIRBuilder) const {
37345ffd83dbSDimitry Andric   auto Undef = MIRBuilder.buildInstr(TargetOpcode::IMPLICIT_DEF, {DstRC}, {});
37355ffd83dbSDimitry Andric 
37365ffd83dbSDimitry Andric   auto BuildFn = [&](unsigned SubregIndex) {
37375ffd83dbSDimitry Andric     auto Ins =
37385ffd83dbSDimitry Andric         MIRBuilder
37395ffd83dbSDimitry Andric             .buildInstr(TargetOpcode::INSERT_SUBREG, {DstRC}, {Undef, Scalar})
37405ffd83dbSDimitry Andric             .addImm(SubregIndex);
37415ffd83dbSDimitry Andric     constrainSelectedInstRegOperands(*Undef, TII, TRI, RBI);
37425ffd83dbSDimitry Andric     constrainSelectedInstRegOperands(*Ins, TII, TRI, RBI);
37435ffd83dbSDimitry Andric     return &*Ins;
37445ffd83dbSDimitry Andric   };
37455ffd83dbSDimitry Andric 
37465ffd83dbSDimitry Andric   switch (EltSize) {
374706c3fb27SDimitry Andric   case 8:
374806c3fb27SDimitry Andric     return BuildFn(AArch64::bsub);
37495ffd83dbSDimitry Andric   case 16:
37505ffd83dbSDimitry Andric     return BuildFn(AArch64::hsub);
37515ffd83dbSDimitry Andric   case 32:
37525ffd83dbSDimitry Andric     return BuildFn(AArch64::ssub);
37535ffd83dbSDimitry Andric   case 64:
37545ffd83dbSDimitry Andric     return BuildFn(AArch64::dsub);
37555ffd83dbSDimitry Andric   default:
37565ffd83dbSDimitry Andric     return nullptr;
37575ffd83dbSDimitry Andric   }
37585ffd83dbSDimitry Andric }
37595ffd83dbSDimitry Andric 
37605f757f3fSDimitry Andric MachineInstr *
emitNarrowVector(Register DstReg,Register SrcReg,MachineIRBuilder & MIB,MachineRegisterInfo & MRI) const37615f757f3fSDimitry Andric AArch64InstructionSelector::emitNarrowVector(Register DstReg, Register SrcReg,
37625f757f3fSDimitry Andric                                              MachineIRBuilder &MIB,
37635f757f3fSDimitry Andric                                              MachineRegisterInfo &MRI) const {
37645f757f3fSDimitry Andric   LLT DstTy = MRI.getType(DstReg);
37655f757f3fSDimitry Andric   const TargetRegisterClass *RC =
37665f757f3fSDimitry Andric       getRegClassForTypeOnBank(DstTy, *RBI.getRegBank(SrcReg, MRI, TRI));
37675f757f3fSDimitry Andric   if (RC != &AArch64::FPR32RegClass && RC != &AArch64::FPR64RegClass) {
37685f757f3fSDimitry Andric     LLVM_DEBUG(dbgs() << "Unsupported register class!\n");
37695f757f3fSDimitry Andric     return nullptr;
37705f757f3fSDimitry Andric   }
37715f757f3fSDimitry Andric   unsigned SubReg = 0;
37725f757f3fSDimitry Andric   if (!getSubRegForClass(RC, TRI, SubReg))
37735f757f3fSDimitry Andric     return nullptr;
37745f757f3fSDimitry Andric   if (SubReg != AArch64::ssub && SubReg != AArch64::dsub) {
37755f757f3fSDimitry Andric     LLVM_DEBUG(dbgs() << "Unsupported destination size! ("
37765f757f3fSDimitry Andric                       << DstTy.getSizeInBits() << "\n");
37775f757f3fSDimitry Andric     return nullptr;
37785f757f3fSDimitry Andric   }
37795f757f3fSDimitry Andric   auto Copy = MIB.buildInstr(TargetOpcode::COPY, {DstReg}, {})
37805f757f3fSDimitry Andric                   .addReg(SrcReg, 0, SubReg);
37815f757f3fSDimitry Andric   RBI.constrainGenericRegister(DstReg, *RC, MRI);
37825f757f3fSDimitry Andric   return Copy;
37835f757f3fSDimitry Andric }
37845f757f3fSDimitry Andric 
selectMergeValues(MachineInstr & I,MachineRegisterInfo & MRI)37855ffd83dbSDimitry Andric bool AArch64InstructionSelector::selectMergeValues(
3786fe6060f1SDimitry Andric     MachineInstr &I, MachineRegisterInfo &MRI) {
37875ffd83dbSDimitry Andric   assert(I.getOpcode() == TargetOpcode::G_MERGE_VALUES && "unexpected opcode");
37885ffd83dbSDimitry Andric   const LLT DstTy = MRI.getType(I.getOperand(0).getReg());
37895ffd83dbSDimitry Andric   const LLT SrcTy = MRI.getType(I.getOperand(1).getReg());
37905ffd83dbSDimitry Andric   assert(!DstTy.isVector() && !SrcTy.isVector() && "invalid merge operation");
37915ffd83dbSDimitry Andric   const RegisterBank &RB = *RBI.getRegBank(I.getOperand(1).getReg(), MRI, TRI);
37925ffd83dbSDimitry Andric 
37935ffd83dbSDimitry Andric   if (I.getNumOperands() != 3)
37945ffd83dbSDimitry Andric     return false;
37955ffd83dbSDimitry Andric 
37965ffd83dbSDimitry Andric   // Merging 2 s64s into an s128.
37975ffd83dbSDimitry Andric   if (DstTy == LLT::scalar(128)) {
37985ffd83dbSDimitry Andric     if (SrcTy.getSizeInBits() != 64)
37995ffd83dbSDimitry Andric       return false;
38005ffd83dbSDimitry Andric     Register DstReg = I.getOperand(0).getReg();
38015ffd83dbSDimitry Andric     Register Src1Reg = I.getOperand(1).getReg();
38025ffd83dbSDimitry Andric     Register Src2Reg = I.getOperand(2).getReg();
38035ffd83dbSDimitry Andric     auto Tmp = MIB.buildInstr(TargetOpcode::IMPLICIT_DEF, {DstTy}, {});
3804bdd1243dSDimitry Andric     MachineInstr *InsMI = emitLaneInsert(std::nullopt, Tmp.getReg(0), Src1Reg,
3805bdd1243dSDimitry Andric                                          /* LaneIdx */ 0, RB, MIB);
38065ffd83dbSDimitry Andric     if (!InsMI)
38075ffd83dbSDimitry Andric       return false;
38085ffd83dbSDimitry Andric     MachineInstr *Ins2MI = emitLaneInsert(DstReg, InsMI->getOperand(0).getReg(),
38095ffd83dbSDimitry Andric                                           Src2Reg, /* LaneIdx */ 1, RB, MIB);
38105ffd83dbSDimitry Andric     if (!Ins2MI)
38115ffd83dbSDimitry Andric       return false;
38125ffd83dbSDimitry Andric     constrainSelectedInstRegOperands(*InsMI, TII, TRI, RBI);
38135ffd83dbSDimitry Andric     constrainSelectedInstRegOperands(*Ins2MI, TII, TRI, RBI);
38145ffd83dbSDimitry Andric     I.eraseFromParent();
38155ffd83dbSDimitry Andric     return true;
38165ffd83dbSDimitry Andric   }
38175ffd83dbSDimitry Andric 
38185ffd83dbSDimitry Andric   if (RB.getID() != AArch64::GPRRegBankID)
38195ffd83dbSDimitry Andric     return false;
38205ffd83dbSDimitry Andric 
38215ffd83dbSDimitry Andric   if (DstTy.getSizeInBits() != 64 || SrcTy.getSizeInBits() != 32)
38225ffd83dbSDimitry Andric     return false;
38235ffd83dbSDimitry Andric 
38245ffd83dbSDimitry Andric   auto *DstRC = &AArch64::GPR64RegClass;
38255ffd83dbSDimitry Andric   Register SubToRegDef = MRI.createVirtualRegister(DstRC);
38265ffd83dbSDimitry Andric   MachineInstr &SubRegMI = *BuildMI(*I.getParent(), I, I.getDebugLoc(),
38275ffd83dbSDimitry Andric                                     TII.get(TargetOpcode::SUBREG_TO_REG))
38285ffd83dbSDimitry Andric                                 .addDef(SubToRegDef)
38295ffd83dbSDimitry Andric                                 .addImm(0)
38305ffd83dbSDimitry Andric                                 .addUse(I.getOperand(1).getReg())
38315ffd83dbSDimitry Andric                                 .addImm(AArch64::sub_32);
38325ffd83dbSDimitry Andric   Register SubToRegDef2 = MRI.createVirtualRegister(DstRC);
38335ffd83dbSDimitry Andric   // Need to anyext the second scalar before we can use bfm
38345ffd83dbSDimitry Andric   MachineInstr &SubRegMI2 = *BuildMI(*I.getParent(), I, I.getDebugLoc(),
38355ffd83dbSDimitry Andric                                     TII.get(TargetOpcode::SUBREG_TO_REG))
38365ffd83dbSDimitry Andric                                 .addDef(SubToRegDef2)
38375ffd83dbSDimitry Andric                                 .addImm(0)
38385ffd83dbSDimitry Andric                                 .addUse(I.getOperand(2).getReg())
38395ffd83dbSDimitry Andric                                 .addImm(AArch64::sub_32);
38405ffd83dbSDimitry Andric   MachineInstr &BFM =
38415ffd83dbSDimitry Andric       *BuildMI(*I.getParent(), I, I.getDebugLoc(), TII.get(AArch64::BFMXri))
38425ffd83dbSDimitry Andric            .addDef(I.getOperand(0).getReg())
38435ffd83dbSDimitry Andric            .addUse(SubToRegDef)
38445ffd83dbSDimitry Andric            .addUse(SubToRegDef2)
38455ffd83dbSDimitry Andric            .addImm(32)
38465ffd83dbSDimitry Andric            .addImm(31);
38475ffd83dbSDimitry Andric   constrainSelectedInstRegOperands(SubRegMI, TII, TRI, RBI);
38485ffd83dbSDimitry Andric   constrainSelectedInstRegOperands(SubRegMI2, TII, TRI, RBI);
38495ffd83dbSDimitry Andric   constrainSelectedInstRegOperands(BFM, TII, TRI, RBI);
38505ffd83dbSDimitry Andric   I.eraseFromParent();
38515ffd83dbSDimitry Andric   return true;
38525ffd83dbSDimitry Andric }
38535ffd83dbSDimitry Andric 
getLaneCopyOpcode(unsigned & CopyOpc,unsigned & ExtractSubReg,const unsigned EltSize)38545ffd83dbSDimitry Andric static bool getLaneCopyOpcode(unsigned &CopyOpc, unsigned &ExtractSubReg,
38555ffd83dbSDimitry Andric                               const unsigned EltSize) {
38565ffd83dbSDimitry Andric   // Choose a lane copy opcode and subregister based off of the size of the
38575ffd83dbSDimitry Andric   // vector's elements.
38585ffd83dbSDimitry Andric   switch (EltSize) {
3859349cc55cSDimitry Andric   case 8:
386004eeddc0SDimitry Andric     CopyOpc = AArch64::DUPi8;
3861349cc55cSDimitry Andric     ExtractSubReg = AArch64::bsub;
3862349cc55cSDimitry Andric     break;
38635ffd83dbSDimitry Andric   case 16:
386404eeddc0SDimitry Andric     CopyOpc = AArch64::DUPi16;
38655ffd83dbSDimitry Andric     ExtractSubReg = AArch64::hsub;
38665ffd83dbSDimitry Andric     break;
38675ffd83dbSDimitry Andric   case 32:
386804eeddc0SDimitry Andric     CopyOpc = AArch64::DUPi32;
38695ffd83dbSDimitry Andric     ExtractSubReg = AArch64::ssub;
38705ffd83dbSDimitry Andric     break;
38715ffd83dbSDimitry Andric   case 64:
387204eeddc0SDimitry Andric     CopyOpc = AArch64::DUPi64;
38735ffd83dbSDimitry Andric     ExtractSubReg = AArch64::dsub;
38745ffd83dbSDimitry Andric     break;
38755ffd83dbSDimitry Andric   default:
38765ffd83dbSDimitry Andric     // Unknown size, bail out.
38775ffd83dbSDimitry Andric     LLVM_DEBUG(dbgs() << "Elt size '" << EltSize << "' unsupported.\n");
38785ffd83dbSDimitry Andric     return false;
38795ffd83dbSDimitry Andric   }
38805ffd83dbSDimitry Andric   return true;
38815ffd83dbSDimitry Andric }
38825ffd83dbSDimitry Andric 
emitExtractVectorElt(std::optional<Register> DstReg,const RegisterBank & DstRB,LLT ScalarTy,Register VecReg,unsigned LaneIdx,MachineIRBuilder & MIRBuilder) const38835ffd83dbSDimitry Andric MachineInstr *AArch64InstructionSelector::emitExtractVectorElt(
3884bdd1243dSDimitry Andric     std::optional<Register> DstReg, const RegisterBank &DstRB, LLT ScalarTy,
38855ffd83dbSDimitry Andric     Register VecReg, unsigned LaneIdx, MachineIRBuilder &MIRBuilder) const {
38865ffd83dbSDimitry Andric   MachineRegisterInfo &MRI = *MIRBuilder.getMRI();
38875ffd83dbSDimitry Andric   unsigned CopyOpc = 0;
38885ffd83dbSDimitry Andric   unsigned ExtractSubReg = 0;
38895ffd83dbSDimitry Andric   if (!getLaneCopyOpcode(CopyOpc, ExtractSubReg, ScalarTy.getSizeInBits())) {
38905ffd83dbSDimitry Andric     LLVM_DEBUG(
38915ffd83dbSDimitry Andric         dbgs() << "Couldn't determine lane copy opcode for instruction.\n");
38925ffd83dbSDimitry Andric     return nullptr;
38935ffd83dbSDimitry Andric   }
38945ffd83dbSDimitry Andric 
38955ffd83dbSDimitry Andric   const TargetRegisterClass *DstRC =
389681ad6265SDimitry Andric       getRegClassForTypeOnBank(ScalarTy, DstRB, true);
38975ffd83dbSDimitry Andric   if (!DstRC) {
38985ffd83dbSDimitry Andric     LLVM_DEBUG(dbgs() << "Could not determine destination register class.\n");
38995ffd83dbSDimitry Andric     return nullptr;
39005ffd83dbSDimitry Andric   }
39015ffd83dbSDimitry Andric 
39025ffd83dbSDimitry Andric   const RegisterBank &VecRB = *RBI.getRegBank(VecReg, MRI, TRI);
39035ffd83dbSDimitry Andric   const LLT &VecTy = MRI.getType(VecReg);
39045ffd83dbSDimitry Andric   const TargetRegisterClass *VecRC =
390581ad6265SDimitry Andric       getRegClassForTypeOnBank(VecTy, VecRB, true);
39065ffd83dbSDimitry Andric   if (!VecRC) {
39075ffd83dbSDimitry Andric     LLVM_DEBUG(dbgs() << "Could not determine source register class.\n");
39085ffd83dbSDimitry Andric     return nullptr;
39095ffd83dbSDimitry Andric   }
39105ffd83dbSDimitry Andric 
39115ffd83dbSDimitry Andric   // The register that we're going to copy into.
39125ffd83dbSDimitry Andric   Register InsertReg = VecReg;
39135ffd83dbSDimitry Andric   if (!DstReg)
39145ffd83dbSDimitry Andric     DstReg = MRI.createVirtualRegister(DstRC);
39155ffd83dbSDimitry Andric   // If the lane index is 0, we just use a subregister COPY.
39165ffd83dbSDimitry Andric   if (LaneIdx == 0) {
39175ffd83dbSDimitry Andric     auto Copy = MIRBuilder.buildInstr(TargetOpcode::COPY, {*DstReg}, {})
39185ffd83dbSDimitry Andric                     .addReg(VecReg, 0, ExtractSubReg);
39195ffd83dbSDimitry Andric     RBI.constrainGenericRegister(*DstReg, *DstRC, MRI);
39205ffd83dbSDimitry Andric     return &*Copy;
39215ffd83dbSDimitry Andric   }
39225ffd83dbSDimitry Andric 
39235ffd83dbSDimitry Andric   // Lane copies require 128-bit wide registers. If we're dealing with an
39245ffd83dbSDimitry Andric   // unpacked vector, then we need to move up to that width. Insert an implicit
39255ffd83dbSDimitry Andric   // def and a subregister insert to get us there.
39265ffd83dbSDimitry Andric   if (VecTy.getSizeInBits() != 128) {
39275ffd83dbSDimitry Andric     MachineInstr *ScalarToVector = emitScalarToVector(
39285ffd83dbSDimitry Andric         VecTy.getSizeInBits(), &AArch64::FPR128RegClass, VecReg, MIRBuilder);
39295ffd83dbSDimitry Andric     if (!ScalarToVector)
39305ffd83dbSDimitry Andric       return nullptr;
39315ffd83dbSDimitry Andric     InsertReg = ScalarToVector->getOperand(0).getReg();
39325ffd83dbSDimitry Andric   }
39335ffd83dbSDimitry Andric 
39345ffd83dbSDimitry Andric   MachineInstr *LaneCopyMI =
39355ffd83dbSDimitry Andric       MIRBuilder.buildInstr(CopyOpc, {*DstReg}, {InsertReg}).addImm(LaneIdx);
39365ffd83dbSDimitry Andric   constrainSelectedInstRegOperands(*LaneCopyMI, TII, TRI, RBI);
39375ffd83dbSDimitry Andric 
39385ffd83dbSDimitry Andric   // Make sure that we actually constrain the initial copy.
39395ffd83dbSDimitry Andric   RBI.constrainGenericRegister(*DstReg, *DstRC, MRI);
39405ffd83dbSDimitry Andric   return LaneCopyMI;
39415ffd83dbSDimitry Andric }
39425ffd83dbSDimitry Andric 
selectExtractElt(MachineInstr & I,MachineRegisterInfo & MRI)39435ffd83dbSDimitry Andric bool AArch64InstructionSelector::selectExtractElt(
3944fe6060f1SDimitry Andric     MachineInstr &I, MachineRegisterInfo &MRI) {
39455ffd83dbSDimitry Andric   assert(I.getOpcode() == TargetOpcode::G_EXTRACT_VECTOR_ELT &&
39465ffd83dbSDimitry Andric          "unexpected opcode!");
39475ffd83dbSDimitry Andric   Register DstReg = I.getOperand(0).getReg();
39485ffd83dbSDimitry Andric   const LLT NarrowTy = MRI.getType(DstReg);
39495ffd83dbSDimitry Andric   const Register SrcReg = I.getOperand(1).getReg();
39505ffd83dbSDimitry Andric   const LLT WideTy = MRI.getType(SrcReg);
39515ffd83dbSDimitry Andric   (void)WideTy;
39525ffd83dbSDimitry Andric   assert(WideTy.getSizeInBits() >= NarrowTy.getSizeInBits() &&
39535ffd83dbSDimitry Andric          "source register size too small!");
3954e8d8bef9SDimitry Andric   assert(!NarrowTy.isVector() && "cannot extract vector into vector!");
39555ffd83dbSDimitry Andric 
39565ffd83dbSDimitry Andric   // Need the lane index to determine the correct copy opcode.
39575ffd83dbSDimitry Andric   MachineOperand &LaneIdxOp = I.getOperand(2);
39585ffd83dbSDimitry Andric   assert(LaneIdxOp.isReg() && "Lane index operand was not a register?");
39595ffd83dbSDimitry Andric 
39605ffd83dbSDimitry Andric   if (RBI.getRegBank(DstReg, MRI, TRI)->getID() != AArch64::FPRRegBankID) {
39615ffd83dbSDimitry Andric     LLVM_DEBUG(dbgs() << "Cannot extract into GPR.\n");
39625ffd83dbSDimitry Andric     return false;
39635ffd83dbSDimitry Andric   }
39645ffd83dbSDimitry Andric 
39655ffd83dbSDimitry Andric   // Find the index to extract from.
3966349cc55cSDimitry Andric   auto VRegAndVal = getIConstantVRegValWithLookThrough(LaneIdxOp.getReg(), MRI);
39675ffd83dbSDimitry Andric   if (!VRegAndVal)
39685ffd83dbSDimitry Andric     return false;
3969e8d8bef9SDimitry Andric   unsigned LaneIdx = VRegAndVal->Value.getSExtValue();
39705ffd83dbSDimitry Andric 
39715ffd83dbSDimitry Andric 
39725ffd83dbSDimitry Andric   const RegisterBank &DstRB = *RBI.getRegBank(DstReg, MRI, TRI);
39735ffd83dbSDimitry Andric   MachineInstr *Extract = emitExtractVectorElt(DstReg, DstRB, NarrowTy, SrcReg,
3974fe6060f1SDimitry Andric                                                LaneIdx, MIB);
39755ffd83dbSDimitry Andric   if (!Extract)
39765ffd83dbSDimitry Andric     return false;
39775ffd83dbSDimitry Andric 
39785ffd83dbSDimitry Andric   I.eraseFromParent();
39795ffd83dbSDimitry Andric   return true;
39805ffd83dbSDimitry Andric }
39815ffd83dbSDimitry Andric 
selectSplitVectorUnmerge(MachineInstr & I,MachineRegisterInfo & MRI)39825ffd83dbSDimitry Andric bool AArch64InstructionSelector::selectSplitVectorUnmerge(
3983fe6060f1SDimitry Andric     MachineInstr &I, MachineRegisterInfo &MRI) {
39845ffd83dbSDimitry Andric   unsigned NumElts = I.getNumOperands() - 1;
39855ffd83dbSDimitry Andric   Register SrcReg = I.getOperand(NumElts).getReg();
39865ffd83dbSDimitry Andric   const LLT NarrowTy = MRI.getType(I.getOperand(0).getReg());
39875ffd83dbSDimitry Andric   const LLT SrcTy = MRI.getType(SrcReg);
39885ffd83dbSDimitry Andric 
39895ffd83dbSDimitry Andric   assert(NarrowTy.isVector() && "Expected an unmerge into vectors");
39905ffd83dbSDimitry Andric   if (SrcTy.getSizeInBits() > 128) {
39915ffd83dbSDimitry Andric     LLVM_DEBUG(dbgs() << "Unexpected vector type for vec split unmerge");
39925ffd83dbSDimitry Andric     return false;
39935ffd83dbSDimitry Andric   }
39945ffd83dbSDimitry Andric 
39955ffd83dbSDimitry Andric   // We implement a split vector operation by treating the sub-vectors as
39965ffd83dbSDimitry Andric   // scalars and extracting them.
39975ffd83dbSDimitry Andric   const RegisterBank &DstRB =
39985ffd83dbSDimitry Andric       *RBI.getRegBank(I.getOperand(0).getReg(), MRI, TRI);
39995ffd83dbSDimitry Andric   for (unsigned OpIdx = 0; OpIdx < NumElts; ++OpIdx) {
40005ffd83dbSDimitry Andric     Register Dst = I.getOperand(OpIdx).getReg();
40015ffd83dbSDimitry Andric     MachineInstr *Extract =
40025ffd83dbSDimitry Andric         emitExtractVectorElt(Dst, DstRB, NarrowTy, SrcReg, OpIdx, MIB);
40035ffd83dbSDimitry Andric     if (!Extract)
40045ffd83dbSDimitry Andric       return false;
40055ffd83dbSDimitry Andric   }
40065ffd83dbSDimitry Andric   I.eraseFromParent();
40075ffd83dbSDimitry Andric   return true;
40085ffd83dbSDimitry Andric }
40095ffd83dbSDimitry Andric 
selectUnmergeValues(MachineInstr & I,MachineRegisterInfo & MRI)4010fe6060f1SDimitry Andric bool AArch64InstructionSelector::selectUnmergeValues(MachineInstr &I,
4011fe6060f1SDimitry Andric                                                      MachineRegisterInfo &MRI) {
40125ffd83dbSDimitry Andric   assert(I.getOpcode() == TargetOpcode::G_UNMERGE_VALUES &&
40135ffd83dbSDimitry Andric          "unexpected opcode");
40145ffd83dbSDimitry Andric 
40155ffd83dbSDimitry Andric   // TODO: Handle unmerging into GPRs and from scalars to scalars.
40165ffd83dbSDimitry Andric   if (RBI.getRegBank(I.getOperand(0).getReg(), MRI, TRI)->getID() !=
40175ffd83dbSDimitry Andric           AArch64::FPRRegBankID ||
40185ffd83dbSDimitry Andric       RBI.getRegBank(I.getOperand(1).getReg(), MRI, TRI)->getID() !=
40195ffd83dbSDimitry Andric           AArch64::FPRRegBankID) {
40205ffd83dbSDimitry Andric     LLVM_DEBUG(dbgs() << "Unmerging vector-to-gpr and scalar-to-scalar "
40215ffd83dbSDimitry Andric                          "currently unsupported.\n");
40225ffd83dbSDimitry Andric     return false;
40235ffd83dbSDimitry Andric   }
40245ffd83dbSDimitry Andric 
40255ffd83dbSDimitry Andric   // The last operand is the vector source register, and every other operand is
40265ffd83dbSDimitry Andric   // a register to unpack into.
40275ffd83dbSDimitry Andric   unsigned NumElts = I.getNumOperands() - 1;
40285ffd83dbSDimitry Andric   Register SrcReg = I.getOperand(NumElts).getReg();
40295ffd83dbSDimitry Andric   const LLT NarrowTy = MRI.getType(I.getOperand(0).getReg());
40305ffd83dbSDimitry Andric   const LLT WideTy = MRI.getType(SrcReg);
40315ffd83dbSDimitry Andric   (void)WideTy;
40325ffd83dbSDimitry Andric   assert((WideTy.isVector() || WideTy.getSizeInBits() == 128) &&
40335ffd83dbSDimitry Andric          "can only unmerge from vector or s128 types!");
40345ffd83dbSDimitry Andric   assert(WideTy.getSizeInBits() > NarrowTy.getSizeInBits() &&
40355ffd83dbSDimitry Andric          "source register size too small!");
40365ffd83dbSDimitry Andric 
40375ffd83dbSDimitry Andric   if (!NarrowTy.isScalar())
40385ffd83dbSDimitry Andric     return selectSplitVectorUnmerge(I, MRI);
40395ffd83dbSDimitry Andric 
40405ffd83dbSDimitry Andric   // Choose a lane copy opcode and subregister based off of the size of the
40415ffd83dbSDimitry Andric   // vector's elements.
40425ffd83dbSDimitry Andric   unsigned CopyOpc = 0;
40435ffd83dbSDimitry Andric   unsigned ExtractSubReg = 0;
40445ffd83dbSDimitry Andric   if (!getLaneCopyOpcode(CopyOpc, ExtractSubReg, NarrowTy.getSizeInBits()))
40455ffd83dbSDimitry Andric     return false;
40465ffd83dbSDimitry Andric 
40475ffd83dbSDimitry Andric   // Set up for the lane copies.
40485ffd83dbSDimitry Andric   MachineBasicBlock &MBB = *I.getParent();
40495ffd83dbSDimitry Andric 
40505ffd83dbSDimitry Andric   // Stores the registers we'll be copying from.
40515ffd83dbSDimitry Andric   SmallVector<Register, 4> InsertRegs;
40525ffd83dbSDimitry Andric 
40535ffd83dbSDimitry Andric   // We'll use the first register twice, so we only need NumElts-1 registers.
40545ffd83dbSDimitry Andric   unsigned NumInsertRegs = NumElts - 1;
40555ffd83dbSDimitry Andric 
40565ffd83dbSDimitry Andric   // If our elements fit into exactly 128 bits, then we can copy from the source
40575ffd83dbSDimitry Andric   // directly. Otherwise, we need to do a bit of setup with some subregister
40585ffd83dbSDimitry Andric   // inserts.
40595ffd83dbSDimitry Andric   if (NarrowTy.getSizeInBits() * NumElts == 128) {
40605ffd83dbSDimitry Andric     InsertRegs = SmallVector<Register, 4>(NumInsertRegs, SrcReg);
40615ffd83dbSDimitry Andric   } else {
40625ffd83dbSDimitry Andric     // No. We have to perform subregister inserts. For each insert, create an
40635ffd83dbSDimitry Andric     // implicit def and a subregister insert, and save the register we create.
406481ad6265SDimitry Andric     const TargetRegisterClass *RC = getRegClassForTypeOnBank(
406581ad6265SDimitry Andric         LLT::fixed_vector(NumElts, WideTy.getScalarSizeInBits()),
406681ad6265SDimitry Andric         *RBI.getRegBank(SrcReg, MRI, TRI));
4067fe6060f1SDimitry Andric     unsigned SubReg = 0;
4068fe6060f1SDimitry Andric     bool Found = getSubRegForClass(RC, TRI, SubReg);
4069fe6060f1SDimitry Andric     (void)Found;
4070fe6060f1SDimitry Andric     assert(Found && "expected to find last operand's subeg idx");
40715ffd83dbSDimitry Andric     for (unsigned Idx = 0; Idx < NumInsertRegs; ++Idx) {
40725ffd83dbSDimitry Andric       Register ImpDefReg = MRI.createVirtualRegister(&AArch64::FPR128RegClass);
40735ffd83dbSDimitry Andric       MachineInstr &ImpDefMI =
40745ffd83dbSDimitry Andric           *BuildMI(MBB, I, I.getDebugLoc(), TII.get(TargetOpcode::IMPLICIT_DEF),
40755ffd83dbSDimitry Andric                    ImpDefReg);
40765ffd83dbSDimitry Andric 
40775ffd83dbSDimitry Andric       // Now, create the subregister insert from SrcReg.
40785ffd83dbSDimitry Andric       Register InsertReg = MRI.createVirtualRegister(&AArch64::FPR128RegClass);
40795ffd83dbSDimitry Andric       MachineInstr &InsMI =
40805ffd83dbSDimitry Andric           *BuildMI(MBB, I, I.getDebugLoc(),
40815ffd83dbSDimitry Andric                    TII.get(TargetOpcode::INSERT_SUBREG), InsertReg)
40825ffd83dbSDimitry Andric                .addUse(ImpDefReg)
40835ffd83dbSDimitry Andric                .addUse(SrcReg)
4084fe6060f1SDimitry Andric                .addImm(SubReg);
40855ffd83dbSDimitry Andric 
40865ffd83dbSDimitry Andric       constrainSelectedInstRegOperands(ImpDefMI, TII, TRI, RBI);
40875ffd83dbSDimitry Andric       constrainSelectedInstRegOperands(InsMI, TII, TRI, RBI);
40885ffd83dbSDimitry Andric 
40895ffd83dbSDimitry Andric       // Save the register so that we can copy from it after.
40905ffd83dbSDimitry Andric       InsertRegs.push_back(InsertReg);
40915ffd83dbSDimitry Andric     }
40925ffd83dbSDimitry Andric   }
40935ffd83dbSDimitry Andric 
40945ffd83dbSDimitry Andric   // Now that we've created any necessary subregister inserts, we can
40955ffd83dbSDimitry Andric   // create the copies.
40965ffd83dbSDimitry Andric   //
40975ffd83dbSDimitry Andric   // Perform the first copy separately as a subregister copy.
40985ffd83dbSDimitry Andric   Register CopyTo = I.getOperand(0).getReg();
40995ffd83dbSDimitry Andric   auto FirstCopy = MIB.buildInstr(TargetOpcode::COPY, {CopyTo}, {})
41005ffd83dbSDimitry Andric                        .addReg(InsertRegs[0], 0, ExtractSubReg);
41015ffd83dbSDimitry Andric   constrainSelectedInstRegOperands(*FirstCopy, TII, TRI, RBI);
41025ffd83dbSDimitry Andric 
41035ffd83dbSDimitry Andric   // Now, perform the remaining copies as vector lane copies.
41045ffd83dbSDimitry Andric   unsigned LaneIdx = 1;
41055ffd83dbSDimitry Andric   for (Register InsReg : InsertRegs) {
41065ffd83dbSDimitry Andric     Register CopyTo = I.getOperand(LaneIdx).getReg();
41075ffd83dbSDimitry Andric     MachineInstr &CopyInst =
41085ffd83dbSDimitry Andric         *BuildMI(MBB, I, I.getDebugLoc(), TII.get(CopyOpc), CopyTo)
41095ffd83dbSDimitry Andric              .addUse(InsReg)
41105ffd83dbSDimitry Andric              .addImm(LaneIdx);
41115ffd83dbSDimitry Andric     constrainSelectedInstRegOperands(CopyInst, TII, TRI, RBI);
41125ffd83dbSDimitry Andric     ++LaneIdx;
41135ffd83dbSDimitry Andric   }
41145ffd83dbSDimitry Andric 
41155ffd83dbSDimitry Andric   // Separately constrain the first copy's destination. Because of the
41165ffd83dbSDimitry Andric   // limitation in constrainOperandRegClass, we can't guarantee that this will
41175ffd83dbSDimitry Andric   // actually be constrained. So, do it ourselves using the second operand.
41185ffd83dbSDimitry Andric   const TargetRegisterClass *RC =
41195ffd83dbSDimitry Andric       MRI.getRegClassOrNull(I.getOperand(1).getReg());
41205ffd83dbSDimitry Andric   if (!RC) {
41215ffd83dbSDimitry Andric     LLVM_DEBUG(dbgs() << "Couldn't constrain copy destination.\n");
41225ffd83dbSDimitry Andric     return false;
41235ffd83dbSDimitry Andric   }
41245ffd83dbSDimitry Andric 
41255ffd83dbSDimitry Andric   RBI.constrainGenericRegister(CopyTo, *RC, MRI);
41265ffd83dbSDimitry Andric   I.eraseFromParent();
41275ffd83dbSDimitry Andric   return true;
41285ffd83dbSDimitry Andric }
41295ffd83dbSDimitry Andric 
selectConcatVectors(MachineInstr & I,MachineRegisterInfo & MRI)41305ffd83dbSDimitry Andric bool AArch64InstructionSelector::selectConcatVectors(
4131fe6060f1SDimitry Andric     MachineInstr &I, MachineRegisterInfo &MRI)  {
41325ffd83dbSDimitry Andric   assert(I.getOpcode() == TargetOpcode::G_CONCAT_VECTORS &&
41335ffd83dbSDimitry Andric          "Unexpected opcode");
41345ffd83dbSDimitry Andric   Register Dst = I.getOperand(0).getReg();
41355ffd83dbSDimitry Andric   Register Op1 = I.getOperand(1).getReg();
41365ffd83dbSDimitry Andric   Register Op2 = I.getOperand(2).getReg();
4137fe6060f1SDimitry Andric   MachineInstr *ConcatMI = emitVectorConcat(Dst, Op1, Op2, MIB);
41385ffd83dbSDimitry Andric   if (!ConcatMI)
41395ffd83dbSDimitry Andric     return false;
41405ffd83dbSDimitry Andric   I.eraseFromParent();
41415ffd83dbSDimitry Andric   return true;
41425ffd83dbSDimitry Andric }
41435ffd83dbSDimitry Andric 
41445ffd83dbSDimitry Andric unsigned
emitConstantPoolEntry(const Constant * CPVal,MachineFunction & MF) const41455ffd83dbSDimitry Andric AArch64InstructionSelector::emitConstantPoolEntry(const Constant *CPVal,
41465ffd83dbSDimitry Andric                                                   MachineFunction &MF) const {
41475ffd83dbSDimitry Andric   Type *CPTy = CPVal->getType();
41485ffd83dbSDimitry Andric   Align Alignment = MF.getDataLayout().getPrefTypeAlign(CPTy);
41495ffd83dbSDimitry Andric 
41505ffd83dbSDimitry Andric   MachineConstantPool *MCP = MF.getConstantPool();
41515ffd83dbSDimitry Andric   return MCP->getConstantPoolIndex(CPVal, Alignment);
41525ffd83dbSDimitry Andric }
41535ffd83dbSDimitry Andric 
emitLoadFromConstantPool(const Constant * CPVal,MachineIRBuilder & MIRBuilder) const41545ffd83dbSDimitry Andric MachineInstr *AArch64InstructionSelector::emitLoadFromConstantPool(
41555ffd83dbSDimitry Andric     const Constant *CPVal, MachineIRBuilder &MIRBuilder) const {
415606c3fb27SDimitry Andric   const TargetRegisterClass *RC;
415706c3fb27SDimitry Andric   unsigned Opc;
415806c3fb27SDimitry Andric   bool IsTiny = TM.getCodeModel() == CodeModel::Tiny;
4159fe6060f1SDimitry Andric   unsigned Size = MIRBuilder.getDataLayout().getTypeStoreSize(CPVal->getType());
4160fe6060f1SDimitry Andric   switch (Size) {
41615ffd83dbSDimitry Andric   case 16:
416206c3fb27SDimitry Andric     RC = &AArch64::FPR128RegClass;
416306c3fb27SDimitry Andric     Opc = IsTiny ? AArch64::LDRQl : AArch64::LDRQui;
41645ffd83dbSDimitry Andric     break;
41655ffd83dbSDimitry Andric   case 8:
416606c3fb27SDimitry Andric     RC = &AArch64::FPR64RegClass;
416706c3fb27SDimitry Andric     Opc = IsTiny ? AArch64::LDRDl : AArch64::LDRDui;
4168fe6060f1SDimitry Andric     break;
4169fe6060f1SDimitry Andric   case 4:
417006c3fb27SDimitry Andric     RC = &AArch64::FPR32RegClass;
417106c3fb27SDimitry Andric     Opc = IsTiny ? AArch64::LDRSl : AArch64::LDRSui;
41725ffd83dbSDimitry Andric     break;
4173349cc55cSDimitry Andric   case 2:
417406c3fb27SDimitry Andric     RC = &AArch64::FPR16RegClass;
417506c3fb27SDimitry Andric     Opc = AArch64::LDRHui;
4176349cc55cSDimitry Andric     break;
41775ffd83dbSDimitry Andric   default:
41785ffd83dbSDimitry Andric     LLVM_DEBUG(dbgs() << "Could not load from constant pool of type "
41795ffd83dbSDimitry Andric                       << *CPVal->getType());
41805ffd83dbSDimitry Andric     return nullptr;
41815ffd83dbSDimitry Andric   }
418206c3fb27SDimitry Andric 
418306c3fb27SDimitry Andric   MachineInstr *LoadMI = nullptr;
418406c3fb27SDimitry Andric   auto &MF = MIRBuilder.getMF();
418506c3fb27SDimitry Andric   unsigned CPIdx = emitConstantPoolEntry(CPVal, MF);
418606c3fb27SDimitry Andric   if (IsTiny && (Size == 16 || Size == 8 || Size == 4)) {
418706c3fb27SDimitry Andric     // Use load(literal) for tiny code model.
418806c3fb27SDimitry Andric     LoadMI = &*MIRBuilder.buildInstr(Opc, {RC}, {}).addConstantPoolIndex(CPIdx);
418906c3fb27SDimitry Andric   } else {
419006c3fb27SDimitry Andric     auto Adrp =
419106c3fb27SDimitry Andric         MIRBuilder.buildInstr(AArch64::ADRP, {&AArch64::GPR64RegClass}, {})
419206c3fb27SDimitry Andric             .addConstantPoolIndex(CPIdx, 0, AArch64II::MO_PAGE);
419306c3fb27SDimitry Andric 
419406c3fb27SDimitry Andric     LoadMI = &*MIRBuilder.buildInstr(Opc, {RC}, {Adrp})
419506c3fb27SDimitry Andric                    .addConstantPoolIndex(
419606c3fb27SDimitry Andric                        CPIdx, 0, AArch64II::MO_PAGEOFF | AArch64II::MO_NC);
419706c3fb27SDimitry Andric 
419806c3fb27SDimitry Andric     constrainSelectedInstRegOperands(*Adrp, TII, TRI, RBI);
419906c3fb27SDimitry Andric   }
420006c3fb27SDimitry Andric 
420106c3fb27SDimitry Andric   MachinePointerInfo PtrInfo = MachinePointerInfo::getConstantPool(MF);
4202fe6060f1SDimitry Andric   LoadMI->addMemOperand(MF, MF.getMachineMemOperand(PtrInfo,
4203fe6060f1SDimitry Andric                                                     MachineMemOperand::MOLoad,
4204fe6060f1SDimitry Andric                                                     Size, Align(Size)));
42055ffd83dbSDimitry Andric   constrainSelectedInstRegOperands(*LoadMI, TII, TRI, RBI);
42065ffd83dbSDimitry Andric   return LoadMI;
42075ffd83dbSDimitry Andric }
42085ffd83dbSDimitry Andric 
42095ffd83dbSDimitry Andric /// Return an <Opcode, SubregIndex> pair to do an vector elt insert of a given
42105ffd83dbSDimitry Andric /// size and RB.
42115ffd83dbSDimitry Andric static std::pair<unsigned, unsigned>
getInsertVecEltOpInfo(const RegisterBank & RB,unsigned EltSize)42125ffd83dbSDimitry Andric getInsertVecEltOpInfo(const RegisterBank &RB, unsigned EltSize) {
42135ffd83dbSDimitry Andric   unsigned Opc, SubregIdx;
42145ffd83dbSDimitry Andric   if (RB.getID() == AArch64::GPRRegBankID) {
421506c3fb27SDimitry Andric     if (EltSize == 8) {
421606c3fb27SDimitry Andric       Opc = AArch64::INSvi8gpr;
421706c3fb27SDimitry Andric       SubregIdx = AArch64::bsub;
421806c3fb27SDimitry Andric     } else if (EltSize == 16) {
4219e8d8bef9SDimitry Andric       Opc = AArch64::INSvi16gpr;
4220e8d8bef9SDimitry Andric       SubregIdx = AArch64::ssub;
4221e8d8bef9SDimitry Andric     } else if (EltSize == 32) {
42225ffd83dbSDimitry Andric       Opc = AArch64::INSvi32gpr;
42235ffd83dbSDimitry Andric       SubregIdx = AArch64::ssub;
42245ffd83dbSDimitry Andric     } else if (EltSize == 64) {
42255ffd83dbSDimitry Andric       Opc = AArch64::INSvi64gpr;
42265ffd83dbSDimitry Andric       SubregIdx = AArch64::dsub;
42275ffd83dbSDimitry Andric     } else {
42285ffd83dbSDimitry Andric       llvm_unreachable("invalid elt size!");
42295ffd83dbSDimitry Andric     }
42305ffd83dbSDimitry Andric   } else {
42315ffd83dbSDimitry Andric     if (EltSize == 8) {
42325ffd83dbSDimitry Andric       Opc = AArch64::INSvi8lane;
42335ffd83dbSDimitry Andric       SubregIdx = AArch64::bsub;
42345ffd83dbSDimitry Andric     } else if (EltSize == 16) {
42355ffd83dbSDimitry Andric       Opc = AArch64::INSvi16lane;
42365ffd83dbSDimitry Andric       SubregIdx = AArch64::hsub;
42375ffd83dbSDimitry Andric     } else if (EltSize == 32) {
42385ffd83dbSDimitry Andric       Opc = AArch64::INSvi32lane;
42395ffd83dbSDimitry Andric       SubregIdx = AArch64::ssub;
42405ffd83dbSDimitry Andric     } else if (EltSize == 64) {
42415ffd83dbSDimitry Andric       Opc = AArch64::INSvi64lane;
42425ffd83dbSDimitry Andric       SubregIdx = AArch64::dsub;
42435ffd83dbSDimitry Andric     } else {
42445ffd83dbSDimitry Andric       llvm_unreachable("invalid elt size!");
42455ffd83dbSDimitry Andric     }
42465ffd83dbSDimitry Andric   }
42475ffd83dbSDimitry Andric   return std::make_pair(Opc, SubregIdx);
42485ffd83dbSDimitry Andric }
42495ffd83dbSDimitry Andric 
emitInstr(unsigned Opcode,std::initializer_list<llvm::DstOp> DstOps,std::initializer_list<llvm::SrcOp> SrcOps,MachineIRBuilder & MIRBuilder,const ComplexRendererFns & RenderFns) const4250e8d8bef9SDimitry Andric MachineInstr *AArch64InstructionSelector::emitInstr(
4251e8d8bef9SDimitry Andric     unsigned Opcode, std::initializer_list<llvm::DstOp> DstOps,
4252e8d8bef9SDimitry Andric     std::initializer_list<llvm::SrcOp> SrcOps, MachineIRBuilder &MIRBuilder,
4253e8d8bef9SDimitry Andric     const ComplexRendererFns &RenderFns) const {
4254e8d8bef9SDimitry Andric   assert(Opcode && "Expected an opcode?");
4255e8d8bef9SDimitry Andric   assert(!isPreISelGenericOpcode(Opcode) &&
4256e8d8bef9SDimitry Andric          "Function should only be used to produce selected instructions!");
4257e8d8bef9SDimitry Andric   auto MI = MIRBuilder.buildInstr(Opcode, DstOps, SrcOps);
4258e8d8bef9SDimitry Andric   if (RenderFns)
4259e8d8bef9SDimitry Andric     for (auto &Fn : *RenderFns)
4260e8d8bef9SDimitry Andric       Fn(MI);
4261e8d8bef9SDimitry Andric   constrainSelectedInstRegOperands(*MI, TII, TRI, RBI);
4262e8d8bef9SDimitry Andric   return &*MI;
4263e8d8bef9SDimitry Andric }
4264e8d8bef9SDimitry Andric 
emitAddSub(const std::array<std::array<unsigned,2>,5> & AddrModeAndSizeToOpcode,Register Dst,MachineOperand & LHS,MachineOperand & RHS,MachineIRBuilder & MIRBuilder) const4265e8d8bef9SDimitry Andric MachineInstr *AArch64InstructionSelector::emitAddSub(
4266e8d8bef9SDimitry Andric     const std::array<std::array<unsigned, 2>, 5> &AddrModeAndSizeToOpcode,
4267e8d8bef9SDimitry Andric     Register Dst, MachineOperand &LHS, MachineOperand &RHS,
4268e8d8bef9SDimitry Andric     MachineIRBuilder &MIRBuilder) const {
4269e8d8bef9SDimitry Andric   MachineRegisterInfo &MRI = MIRBuilder.getMF().getRegInfo();
4270e8d8bef9SDimitry Andric   assert(LHS.isReg() && RHS.isReg() && "Expected register operands?");
4271e8d8bef9SDimitry Andric   auto Ty = MRI.getType(LHS.getReg());
4272e8d8bef9SDimitry Andric   assert(!Ty.isVector() && "Expected a scalar or pointer?");
4273e8d8bef9SDimitry Andric   unsigned Size = Ty.getSizeInBits();
4274e8d8bef9SDimitry Andric   assert((Size == 32 || Size == 64) && "Expected a 32-bit or 64-bit type only");
4275e8d8bef9SDimitry Andric   bool Is32Bit = Size == 32;
4276e8d8bef9SDimitry Andric 
4277e8d8bef9SDimitry Andric   // INSTRri form with positive arithmetic immediate.
4278e8d8bef9SDimitry Andric   if (auto Fns = selectArithImmed(RHS))
4279e8d8bef9SDimitry Andric     return emitInstr(AddrModeAndSizeToOpcode[0][Is32Bit], {Dst}, {LHS},
4280e8d8bef9SDimitry Andric                      MIRBuilder, Fns);
4281e8d8bef9SDimitry Andric 
4282e8d8bef9SDimitry Andric   // INSTRri form with negative arithmetic immediate.
4283e8d8bef9SDimitry Andric   if (auto Fns = selectNegArithImmed(RHS))
4284e8d8bef9SDimitry Andric     return emitInstr(AddrModeAndSizeToOpcode[3][Is32Bit], {Dst}, {LHS},
4285e8d8bef9SDimitry Andric                      MIRBuilder, Fns);
4286e8d8bef9SDimitry Andric 
4287e8d8bef9SDimitry Andric   // INSTRrx form.
4288e8d8bef9SDimitry Andric   if (auto Fns = selectArithExtendedRegister(RHS))
4289e8d8bef9SDimitry Andric     return emitInstr(AddrModeAndSizeToOpcode[4][Is32Bit], {Dst}, {LHS},
4290e8d8bef9SDimitry Andric                      MIRBuilder, Fns);
4291e8d8bef9SDimitry Andric 
4292e8d8bef9SDimitry Andric   // INSTRrs form.
4293e8d8bef9SDimitry Andric   if (auto Fns = selectShiftedRegister(RHS))
4294e8d8bef9SDimitry Andric     return emitInstr(AddrModeAndSizeToOpcode[1][Is32Bit], {Dst}, {LHS},
4295e8d8bef9SDimitry Andric                      MIRBuilder, Fns);
4296e8d8bef9SDimitry Andric   return emitInstr(AddrModeAndSizeToOpcode[2][Is32Bit], {Dst}, {LHS, RHS},
4297e8d8bef9SDimitry Andric                    MIRBuilder);
4298e8d8bef9SDimitry Andric }
4299e8d8bef9SDimitry Andric 
43005ffd83dbSDimitry Andric MachineInstr *
emitADD(Register DefReg,MachineOperand & LHS,MachineOperand & RHS,MachineIRBuilder & MIRBuilder) const43015ffd83dbSDimitry Andric AArch64InstructionSelector::emitADD(Register DefReg, MachineOperand &LHS,
43025ffd83dbSDimitry Andric                                     MachineOperand &RHS,
43035ffd83dbSDimitry Andric                                     MachineIRBuilder &MIRBuilder) const {
4304e8d8bef9SDimitry Andric   const std::array<std::array<unsigned, 2>, 5> OpcTable{
4305e8d8bef9SDimitry Andric       {{AArch64::ADDXri, AArch64::ADDWri},
4306e8d8bef9SDimitry Andric        {AArch64::ADDXrs, AArch64::ADDWrs},
4307e8d8bef9SDimitry Andric        {AArch64::ADDXrr, AArch64::ADDWrr},
4308e8d8bef9SDimitry Andric        {AArch64::SUBXri, AArch64::SUBWri},
4309e8d8bef9SDimitry Andric        {AArch64::ADDXrx, AArch64::ADDWrx}}};
4310e8d8bef9SDimitry Andric   return emitAddSub(OpcTable, DefReg, LHS, RHS, MIRBuilder);
43115ffd83dbSDimitry Andric }
43125ffd83dbSDimitry Andric 
4313e8d8bef9SDimitry Andric MachineInstr *
emitADDS(Register Dst,MachineOperand & LHS,MachineOperand & RHS,MachineIRBuilder & MIRBuilder) const4314e8d8bef9SDimitry Andric AArch64InstructionSelector::emitADDS(Register Dst, MachineOperand &LHS,
4315e8d8bef9SDimitry Andric                                      MachineOperand &RHS,
4316e8d8bef9SDimitry Andric                                      MachineIRBuilder &MIRBuilder) const {
4317e8d8bef9SDimitry Andric   const std::array<std::array<unsigned, 2>, 5> OpcTable{
4318e8d8bef9SDimitry Andric       {{AArch64::ADDSXri, AArch64::ADDSWri},
4319e8d8bef9SDimitry Andric        {AArch64::ADDSXrs, AArch64::ADDSWrs},
4320e8d8bef9SDimitry Andric        {AArch64::ADDSXrr, AArch64::ADDSWrr},
4321e8d8bef9SDimitry Andric        {AArch64::SUBSXri, AArch64::SUBSWri},
4322e8d8bef9SDimitry Andric        {AArch64::ADDSXrx, AArch64::ADDSWrx}}};
4323e8d8bef9SDimitry Andric   return emitAddSub(OpcTable, Dst, LHS, RHS, MIRBuilder);
4324e8d8bef9SDimitry Andric }
4325e8d8bef9SDimitry Andric 
4326e8d8bef9SDimitry Andric MachineInstr *
emitSUBS(Register Dst,MachineOperand & LHS,MachineOperand & RHS,MachineIRBuilder & MIRBuilder) const4327e8d8bef9SDimitry Andric AArch64InstructionSelector::emitSUBS(Register Dst, MachineOperand &LHS,
4328e8d8bef9SDimitry Andric                                      MachineOperand &RHS,
4329e8d8bef9SDimitry Andric                                      MachineIRBuilder &MIRBuilder) const {
4330e8d8bef9SDimitry Andric   const std::array<std::array<unsigned, 2>, 5> OpcTable{
4331e8d8bef9SDimitry Andric       {{AArch64::SUBSXri, AArch64::SUBSWri},
4332e8d8bef9SDimitry Andric        {AArch64::SUBSXrs, AArch64::SUBSWrs},
4333e8d8bef9SDimitry Andric        {AArch64::SUBSXrr, AArch64::SUBSWrr},
4334e8d8bef9SDimitry Andric        {AArch64::ADDSXri, AArch64::ADDSWri},
4335e8d8bef9SDimitry Andric        {AArch64::SUBSXrx, AArch64::SUBSWrx}}};
4336e8d8bef9SDimitry Andric   return emitAddSub(OpcTable, Dst, LHS, RHS, MIRBuilder);
43375ffd83dbSDimitry Andric }
43385ffd83dbSDimitry Andric 
43395ffd83dbSDimitry Andric MachineInstr *
emitADCS(Register Dst,MachineOperand & LHS,MachineOperand & RHS,MachineIRBuilder & MIRBuilder) const434006c3fb27SDimitry Andric AArch64InstructionSelector::emitADCS(Register Dst, MachineOperand &LHS,
434106c3fb27SDimitry Andric                                      MachineOperand &RHS,
434206c3fb27SDimitry Andric                                      MachineIRBuilder &MIRBuilder) const {
434306c3fb27SDimitry Andric   assert(LHS.isReg() && RHS.isReg() && "Expected register operands?");
434406c3fb27SDimitry Andric   MachineRegisterInfo *MRI = MIRBuilder.getMRI();
434506c3fb27SDimitry Andric   bool Is32Bit = (MRI->getType(LHS.getReg()).getSizeInBits() == 32);
434606c3fb27SDimitry Andric   static const unsigned OpcTable[2] = {AArch64::ADCSXr, AArch64::ADCSWr};
434706c3fb27SDimitry Andric   return emitInstr(OpcTable[Is32Bit], {Dst}, {LHS, RHS}, MIRBuilder);
434806c3fb27SDimitry Andric }
434906c3fb27SDimitry Andric 
435006c3fb27SDimitry Andric MachineInstr *
emitSBCS(Register Dst,MachineOperand & LHS,MachineOperand & RHS,MachineIRBuilder & MIRBuilder) const435106c3fb27SDimitry Andric AArch64InstructionSelector::emitSBCS(Register Dst, MachineOperand &LHS,
435206c3fb27SDimitry Andric                                      MachineOperand &RHS,
435306c3fb27SDimitry Andric                                      MachineIRBuilder &MIRBuilder) const {
435406c3fb27SDimitry Andric   assert(LHS.isReg() && RHS.isReg() && "Expected register operands?");
435506c3fb27SDimitry Andric   MachineRegisterInfo *MRI = MIRBuilder.getMRI();
435606c3fb27SDimitry Andric   bool Is32Bit = (MRI->getType(LHS.getReg()).getSizeInBits() == 32);
435706c3fb27SDimitry Andric   static const unsigned OpcTable[2] = {AArch64::SBCSXr, AArch64::SBCSWr};
435806c3fb27SDimitry Andric   return emitInstr(OpcTable[Is32Bit], {Dst}, {LHS, RHS}, MIRBuilder);
435906c3fb27SDimitry Andric }
436006c3fb27SDimitry Andric 
436106c3fb27SDimitry Andric MachineInstr *
emitCMN(MachineOperand & LHS,MachineOperand & RHS,MachineIRBuilder & MIRBuilder) const43625ffd83dbSDimitry Andric AArch64InstructionSelector::emitCMN(MachineOperand &LHS, MachineOperand &RHS,
43635ffd83dbSDimitry Andric                                     MachineIRBuilder &MIRBuilder) const {
43645ffd83dbSDimitry Andric   MachineRegisterInfo &MRI = MIRBuilder.getMF().getRegInfo();
43655ffd83dbSDimitry Andric   bool Is32Bit = (MRI.getType(LHS.getReg()).getSizeInBits() == 32);
4366e8d8bef9SDimitry Andric   auto RC = Is32Bit ? &AArch64::GPR32RegClass : &AArch64::GPR64RegClass;
4367e8d8bef9SDimitry Andric   return emitADDS(MRI.createVirtualRegister(RC), LHS, RHS, MIRBuilder);
43685ffd83dbSDimitry Andric }
43695ffd83dbSDimitry Andric 
43705ffd83dbSDimitry Andric MachineInstr *
emitTST(MachineOperand & LHS,MachineOperand & RHS,MachineIRBuilder & MIRBuilder) const4371e8d8bef9SDimitry Andric AArch64InstructionSelector::emitTST(MachineOperand &LHS, MachineOperand &RHS,
43725ffd83dbSDimitry Andric                                     MachineIRBuilder &MIRBuilder) const {
4373e8d8bef9SDimitry Andric   assert(LHS.isReg() && RHS.isReg() && "Expected register operands?");
43745ffd83dbSDimitry Andric   MachineRegisterInfo &MRI = MIRBuilder.getMF().getRegInfo();
4375e8d8bef9SDimitry Andric   LLT Ty = MRI.getType(LHS.getReg());
4376e8d8bef9SDimitry Andric   unsigned RegSize = Ty.getSizeInBits();
43775ffd83dbSDimitry Andric   bool Is32Bit = (RegSize == 32);
4378e8d8bef9SDimitry Andric   const unsigned OpcTable[3][2] = {{AArch64::ANDSXri, AArch64::ANDSWri},
4379e8d8bef9SDimitry Andric                                    {AArch64::ANDSXrs, AArch64::ANDSWrs},
4380e8d8bef9SDimitry Andric                                    {AArch64::ANDSXrr, AArch64::ANDSWrr}};
4381e8d8bef9SDimitry Andric   // ANDS needs a logical immediate for its immediate form. Check if we can
4382e8d8bef9SDimitry Andric   // fold one in.
4383349cc55cSDimitry Andric   if (auto ValAndVReg = getIConstantVRegValWithLookThrough(RHS.getReg(), MRI)) {
4384e8d8bef9SDimitry Andric     int64_t Imm = ValAndVReg->Value.getSExtValue();
43855ffd83dbSDimitry Andric 
4386e8d8bef9SDimitry Andric     if (AArch64_AM::isLogicalImmediate(Imm, RegSize)) {
4387e8d8bef9SDimitry Andric       auto TstMI = MIRBuilder.buildInstr(OpcTable[0][Is32Bit], {Ty}, {LHS});
4388e8d8bef9SDimitry Andric       TstMI.addImm(AArch64_AM::encodeLogicalImmediate(Imm, RegSize));
43895ffd83dbSDimitry Andric       constrainSelectedInstRegOperands(*TstMI, TII, TRI, RBI);
43905ffd83dbSDimitry Andric       return &*TstMI;
43915ffd83dbSDimitry Andric     }
4392e8d8bef9SDimitry Andric   }
43935ffd83dbSDimitry Andric 
4394e8d8bef9SDimitry Andric   if (auto Fns = selectLogicalShiftedRegister(RHS))
4395e8d8bef9SDimitry Andric     return emitInstr(OpcTable[1][Is32Bit], {Ty}, {LHS}, MIRBuilder, Fns);
4396e8d8bef9SDimitry Andric   return emitInstr(OpcTable[2][Is32Bit], {Ty}, {LHS, RHS}, MIRBuilder);
4397e8d8bef9SDimitry Andric }
4398e8d8bef9SDimitry Andric 
emitIntegerCompare(MachineOperand & LHS,MachineOperand & RHS,MachineOperand & Predicate,MachineIRBuilder & MIRBuilder) const4399e8d8bef9SDimitry Andric MachineInstr *AArch64InstructionSelector::emitIntegerCompare(
44005ffd83dbSDimitry Andric     MachineOperand &LHS, MachineOperand &RHS, MachineOperand &Predicate,
44015ffd83dbSDimitry Andric     MachineIRBuilder &MIRBuilder) const {
44025ffd83dbSDimitry Andric   assert(LHS.isReg() && RHS.isReg() && "Expected LHS and RHS to be registers!");
44035ffd83dbSDimitry Andric   assert(Predicate.isPredicate() && "Expected predicate?");
44045ffd83dbSDimitry Andric   MachineRegisterInfo &MRI = MIRBuilder.getMF().getRegInfo();
44055ffd83dbSDimitry Andric   LLT CmpTy = MRI.getType(LHS.getReg());
4406e8d8bef9SDimitry Andric   assert(!CmpTy.isVector() && "Expected scalar or pointer");
4407e8d8bef9SDimitry Andric   unsigned Size = CmpTy.getSizeInBits();
4408e8d8bef9SDimitry Andric   (void)Size;
4409e8d8bef9SDimitry Andric   assert((Size == 32 || Size == 64) && "Expected a 32-bit or 64-bit LHS/RHS?");
4410e8d8bef9SDimitry Andric   // Fold the compare into a cmn or tst if possible.
4411e8d8bef9SDimitry Andric   if (auto FoldCmp = tryFoldIntegerCompare(LHS, RHS, Predicate, MIRBuilder))
4412e8d8bef9SDimitry Andric     return FoldCmp;
4413e8d8bef9SDimitry Andric   auto Dst = MRI.cloneVirtualRegister(LHS.getReg());
4414e8d8bef9SDimitry Andric   return emitSUBS(Dst, LHS, RHS, MIRBuilder);
44155ffd83dbSDimitry Andric }
44165ffd83dbSDimitry Andric 
emitCSetForFCmp(Register Dst,CmpInst::Predicate Pred,MachineIRBuilder & MIRBuilder) const4417e8d8bef9SDimitry Andric MachineInstr *AArch64InstructionSelector::emitCSetForFCmp(
4418e8d8bef9SDimitry Andric     Register Dst, CmpInst::Predicate Pred, MachineIRBuilder &MIRBuilder) const {
4419e8d8bef9SDimitry Andric   MachineRegisterInfo &MRI = *MIRBuilder.getMRI();
4420e8d8bef9SDimitry Andric #ifndef NDEBUG
4421e8d8bef9SDimitry Andric   LLT Ty = MRI.getType(Dst);
4422e8d8bef9SDimitry Andric   assert(!Ty.isVector() && Ty.getSizeInBits() == 32 &&
4423e8d8bef9SDimitry Andric          "Expected a 32-bit scalar register?");
4424e8d8bef9SDimitry Andric #endif
4425349cc55cSDimitry Andric   const Register ZReg = AArch64::WZR;
4426e8d8bef9SDimitry Andric   AArch64CC::CondCode CC1, CC2;
4427e8d8bef9SDimitry Andric   changeFCMPPredToAArch64CC(Pred, CC1, CC2);
4428349cc55cSDimitry Andric   auto InvCC1 = AArch64CC::getInvertedCondCode(CC1);
4429e8d8bef9SDimitry Andric   if (CC2 == AArch64CC::AL)
4430349cc55cSDimitry Andric     return emitCSINC(/*Dst=*/Dst, /*Src1=*/ZReg, /*Src2=*/ZReg, InvCC1,
4431349cc55cSDimitry Andric                      MIRBuilder);
4432e8d8bef9SDimitry Andric   const TargetRegisterClass *RC = &AArch64::GPR32RegClass;
4433e8d8bef9SDimitry Andric   Register Def1Reg = MRI.createVirtualRegister(RC);
4434e8d8bef9SDimitry Andric   Register Def2Reg = MRI.createVirtualRegister(RC);
4435349cc55cSDimitry Andric   auto InvCC2 = AArch64CC::getInvertedCondCode(CC2);
4436349cc55cSDimitry Andric   emitCSINC(/*Dst=*/Def1Reg, /*Src1=*/ZReg, /*Src2=*/ZReg, InvCC1, MIRBuilder);
4437349cc55cSDimitry Andric   emitCSINC(/*Dst=*/Def2Reg, /*Src1=*/ZReg, /*Src2=*/ZReg, InvCC2, MIRBuilder);
4438e8d8bef9SDimitry Andric   auto OrMI = MIRBuilder.buildInstr(AArch64::ORRWrr, {Dst}, {Def1Reg, Def2Reg});
4439e8d8bef9SDimitry Andric   constrainSelectedInstRegOperands(*OrMI, TII, TRI, RBI);
4440e8d8bef9SDimitry Andric   return &*OrMI;
4441e8d8bef9SDimitry Andric }
4442e8d8bef9SDimitry Andric 
emitFPCompare(Register LHS,Register RHS,MachineIRBuilder & MIRBuilder,std::optional<CmpInst::Predicate> Pred) const4443bdd1243dSDimitry Andric MachineInstr *AArch64InstructionSelector::emitFPCompare(
4444bdd1243dSDimitry Andric     Register LHS, Register RHS, MachineIRBuilder &MIRBuilder,
4445bdd1243dSDimitry Andric     std::optional<CmpInst::Predicate> Pred) const {
4446e8d8bef9SDimitry Andric   MachineRegisterInfo &MRI = *MIRBuilder.getMRI();
4447e8d8bef9SDimitry Andric   LLT Ty = MRI.getType(LHS);
4448e8d8bef9SDimitry Andric   if (Ty.isVector())
4449e8d8bef9SDimitry Andric     return nullptr;
4450e8d8bef9SDimitry Andric   unsigned OpSize = Ty.getSizeInBits();
4451*0fca6ea1SDimitry Andric   assert(OpSize == 16 || OpSize == 32 || OpSize == 64);
4452e8d8bef9SDimitry Andric 
4453e8d8bef9SDimitry Andric   // If this is a compare against +0.0, then we don't have
4454e8d8bef9SDimitry Andric   // to explicitly materialize a constant.
4455e8d8bef9SDimitry Andric   const ConstantFP *FPImm = getConstantFPVRegVal(RHS, MRI);
4456e8d8bef9SDimitry Andric   bool ShouldUseImm = FPImm && (FPImm->isZero() && !FPImm->isNegative());
4457e8d8bef9SDimitry Andric 
4458e8d8bef9SDimitry Andric   auto IsEqualityPred = [](CmpInst::Predicate P) {
4459e8d8bef9SDimitry Andric     return P == CmpInst::FCMP_OEQ || P == CmpInst::FCMP_ONE ||
4460e8d8bef9SDimitry Andric            P == CmpInst::FCMP_UEQ || P == CmpInst::FCMP_UNE;
4461e8d8bef9SDimitry Andric   };
4462e8d8bef9SDimitry Andric   if (!ShouldUseImm && Pred && IsEqualityPred(*Pred)) {
4463e8d8bef9SDimitry Andric     // Try commutating the operands.
4464e8d8bef9SDimitry Andric     const ConstantFP *LHSImm = getConstantFPVRegVal(LHS, MRI);
4465e8d8bef9SDimitry Andric     if (LHSImm && (LHSImm->isZero() && !LHSImm->isNegative())) {
4466e8d8bef9SDimitry Andric       ShouldUseImm = true;
4467e8d8bef9SDimitry Andric       std::swap(LHS, RHS);
4468e8d8bef9SDimitry Andric     }
4469e8d8bef9SDimitry Andric   }
4470*0fca6ea1SDimitry Andric   unsigned CmpOpcTbl[2][3] = {
4471*0fca6ea1SDimitry Andric       {AArch64::FCMPHrr, AArch64::FCMPSrr, AArch64::FCMPDrr},
4472*0fca6ea1SDimitry Andric       {AArch64::FCMPHri, AArch64::FCMPSri, AArch64::FCMPDri}};
4473*0fca6ea1SDimitry Andric   unsigned CmpOpc =
4474*0fca6ea1SDimitry Andric       CmpOpcTbl[ShouldUseImm][OpSize == 16 ? 0 : (OpSize == 32 ? 1 : 2)];
4475e8d8bef9SDimitry Andric 
4476e8d8bef9SDimitry Andric   // Partially build the compare. Decide if we need to add a use for the
4477e8d8bef9SDimitry Andric   // third operand based off whether or not we're comparing against 0.0.
4478e8d8bef9SDimitry Andric   auto CmpMI = MIRBuilder.buildInstr(CmpOpc).addUse(LHS);
447981ad6265SDimitry Andric   CmpMI.setMIFlags(MachineInstr::NoFPExcept);
4480e8d8bef9SDimitry Andric   if (!ShouldUseImm)
4481e8d8bef9SDimitry Andric     CmpMI.addUse(RHS);
44825ffd83dbSDimitry Andric   constrainSelectedInstRegOperands(*CmpMI, TII, TRI, RBI);
4483e8d8bef9SDimitry Andric   return &*CmpMI;
44845ffd83dbSDimitry Andric }
44855ffd83dbSDimitry Andric 
emitVectorConcat(std::optional<Register> Dst,Register Op1,Register Op2,MachineIRBuilder & MIRBuilder) const44865ffd83dbSDimitry Andric MachineInstr *AArch64InstructionSelector::emitVectorConcat(
4487bdd1243dSDimitry Andric     std::optional<Register> Dst, Register Op1, Register Op2,
44885ffd83dbSDimitry Andric     MachineIRBuilder &MIRBuilder) const {
44895ffd83dbSDimitry Andric   // We implement a vector concat by:
44905ffd83dbSDimitry Andric   // 1. Use scalar_to_vector to insert the lower vector into the larger dest
44915ffd83dbSDimitry Andric   // 2. Insert the upper vector into the destination's upper element
44925ffd83dbSDimitry Andric   // TODO: some of this code is common with G_BUILD_VECTOR handling.
44935ffd83dbSDimitry Andric   MachineRegisterInfo &MRI = MIRBuilder.getMF().getRegInfo();
44945ffd83dbSDimitry Andric 
44955ffd83dbSDimitry Andric   const LLT Op1Ty = MRI.getType(Op1);
44965ffd83dbSDimitry Andric   const LLT Op2Ty = MRI.getType(Op2);
44975ffd83dbSDimitry Andric 
44985ffd83dbSDimitry Andric   if (Op1Ty != Op2Ty) {
44995ffd83dbSDimitry Andric     LLVM_DEBUG(dbgs() << "Could not do vector concat of differing vector tys");
45005ffd83dbSDimitry Andric     return nullptr;
45015ffd83dbSDimitry Andric   }
45025ffd83dbSDimitry Andric   assert(Op1Ty.isVector() && "Expected a vector for vector concat");
45035ffd83dbSDimitry Andric 
45045ffd83dbSDimitry Andric   if (Op1Ty.getSizeInBits() >= 128) {
45055ffd83dbSDimitry Andric     LLVM_DEBUG(dbgs() << "Vector concat not supported for full size vectors");
45065ffd83dbSDimitry Andric     return nullptr;
45075ffd83dbSDimitry Andric   }
45085ffd83dbSDimitry Andric 
45095ffd83dbSDimitry Andric   // At the moment we just support 64 bit vector concats.
45105ffd83dbSDimitry Andric   if (Op1Ty.getSizeInBits() != 64) {
45115ffd83dbSDimitry Andric     LLVM_DEBUG(dbgs() << "Vector concat supported for 64b vectors");
45125ffd83dbSDimitry Andric     return nullptr;
45135ffd83dbSDimitry Andric   }
45145ffd83dbSDimitry Andric 
45155ffd83dbSDimitry Andric   const LLT ScalarTy = LLT::scalar(Op1Ty.getSizeInBits());
45165ffd83dbSDimitry Andric   const RegisterBank &FPRBank = *RBI.getRegBank(Op1, MRI, TRI);
45175ffd83dbSDimitry Andric   const TargetRegisterClass *DstRC =
451881ad6265SDimitry Andric       getRegClassForTypeOnBank(Op1Ty.multiplyElements(2), FPRBank);
45195ffd83dbSDimitry Andric 
45205ffd83dbSDimitry Andric   MachineInstr *WidenedOp1 =
45215ffd83dbSDimitry Andric       emitScalarToVector(ScalarTy.getSizeInBits(), DstRC, Op1, MIRBuilder);
45225ffd83dbSDimitry Andric   MachineInstr *WidenedOp2 =
45235ffd83dbSDimitry Andric       emitScalarToVector(ScalarTy.getSizeInBits(), DstRC, Op2, MIRBuilder);
45245ffd83dbSDimitry Andric   if (!WidenedOp1 || !WidenedOp2) {
45255ffd83dbSDimitry Andric     LLVM_DEBUG(dbgs() << "Could not emit a vector from scalar value");
45265ffd83dbSDimitry Andric     return nullptr;
45275ffd83dbSDimitry Andric   }
45285ffd83dbSDimitry Andric 
45295ffd83dbSDimitry Andric   // Now do the insert of the upper element.
45305ffd83dbSDimitry Andric   unsigned InsertOpc, InsSubRegIdx;
45315ffd83dbSDimitry Andric   std::tie(InsertOpc, InsSubRegIdx) =
45325ffd83dbSDimitry Andric       getInsertVecEltOpInfo(FPRBank, ScalarTy.getSizeInBits());
45335ffd83dbSDimitry Andric 
45345ffd83dbSDimitry Andric   if (!Dst)
45355ffd83dbSDimitry Andric     Dst = MRI.createVirtualRegister(DstRC);
45365ffd83dbSDimitry Andric   auto InsElt =
45375ffd83dbSDimitry Andric       MIRBuilder
45385ffd83dbSDimitry Andric           .buildInstr(InsertOpc, {*Dst}, {WidenedOp1->getOperand(0).getReg()})
45395ffd83dbSDimitry Andric           .addImm(1) /* Lane index */
45405ffd83dbSDimitry Andric           .addUse(WidenedOp2->getOperand(0).getReg())
45415ffd83dbSDimitry Andric           .addImm(0);
45425ffd83dbSDimitry Andric   constrainSelectedInstRegOperands(*InsElt, TII, TRI, RBI);
45435ffd83dbSDimitry Andric   return &*InsElt;
45445ffd83dbSDimitry Andric }
45455ffd83dbSDimitry Andric 
45465ffd83dbSDimitry Andric MachineInstr *
emitCSINC(Register Dst,Register Src1,Register Src2,AArch64CC::CondCode Pred,MachineIRBuilder & MIRBuilder) const4547349cc55cSDimitry Andric AArch64InstructionSelector::emitCSINC(Register Dst, Register Src1,
4548349cc55cSDimitry Andric                                       Register Src2, AArch64CC::CondCode Pred,
4549349cc55cSDimitry Andric                                       MachineIRBuilder &MIRBuilder) const {
4550349cc55cSDimitry Andric   auto &MRI = *MIRBuilder.getMRI();
4551349cc55cSDimitry Andric   const RegClassOrRegBank &RegClassOrBank = MRI.getRegClassOrRegBank(Dst);
4552349cc55cSDimitry Andric   // If we used a register class, then this won't necessarily have an LLT.
4553349cc55cSDimitry Andric   // Compute the size based off whether or not we have a class or bank.
4554349cc55cSDimitry Andric   unsigned Size;
4555349cc55cSDimitry Andric   if (const auto *RC = RegClassOrBank.dyn_cast<const TargetRegisterClass *>())
4556349cc55cSDimitry Andric     Size = TRI.getRegSizeInBits(*RC);
4557349cc55cSDimitry Andric   else
4558349cc55cSDimitry Andric     Size = MRI.getType(Dst).getSizeInBits();
4559349cc55cSDimitry Andric   // Some opcodes use s1.
4560349cc55cSDimitry Andric   assert(Size <= 64 && "Expected 64 bits or less only!");
4561349cc55cSDimitry Andric   static const unsigned OpcTable[2] = {AArch64::CSINCWr, AArch64::CSINCXr};
4562349cc55cSDimitry Andric   unsigned Opc = OpcTable[Size == 64];
4563349cc55cSDimitry Andric   auto CSINC = MIRBuilder.buildInstr(Opc, {Dst}, {Src1, Src2}).addImm(Pred);
4564349cc55cSDimitry Andric   constrainSelectedInstRegOperands(*CSINC, TII, TRI, RBI);
4565349cc55cSDimitry Andric   return &*CSINC;
45665ffd83dbSDimitry Andric }
45675ffd83dbSDimitry Andric 
emitCarryIn(MachineInstr & I,Register CarryReg)456806c3fb27SDimitry Andric MachineInstr *AArch64InstructionSelector::emitCarryIn(MachineInstr &I,
456906c3fb27SDimitry Andric                                                       Register CarryReg) {
457006c3fb27SDimitry Andric   MachineRegisterInfo *MRI = MIB.getMRI();
457106c3fb27SDimitry Andric   unsigned Opcode = I.getOpcode();
457206c3fb27SDimitry Andric 
457306c3fb27SDimitry Andric   // If the instruction is a SUB, we need to negate the carry,
457406c3fb27SDimitry Andric   // because borrowing is indicated by carry-flag == 0.
457506c3fb27SDimitry Andric   bool NeedsNegatedCarry =
457606c3fb27SDimitry Andric       (Opcode == TargetOpcode::G_USUBE || Opcode == TargetOpcode::G_SSUBE);
457706c3fb27SDimitry Andric 
457806c3fb27SDimitry Andric   // If the previous instruction will already produce the correct carry, do not
457906c3fb27SDimitry Andric   // emit a carry generating instruction. E.g. for G_UADDE/G_USUBE sequences
458006c3fb27SDimitry Andric   // generated during legalization of wide add/sub. This optimization depends on
458106c3fb27SDimitry Andric   // these sequences not being interrupted by other instructions.
45825f757f3fSDimitry Andric   // We have to select the previous instruction before the carry-using
45835f757f3fSDimitry Andric   // instruction is deleted by the calling function, otherwise the previous
45845f757f3fSDimitry Andric   // instruction might become dead and would get deleted.
458506c3fb27SDimitry Andric   MachineInstr *SrcMI = MRI->getVRegDef(CarryReg);
458606c3fb27SDimitry Andric   if (SrcMI == I.getPrevNode()) {
458706c3fb27SDimitry Andric     if (auto *CarrySrcMI = dyn_cast<GAddSubCarryOut>(SrcMI)) {
458806c3fb27SDimitry Andric       bool ProducesNegatedCarry = CarrySrcMI->isSub();
45895f757f3fSDimitry Andric       if (NeedsNegatedCarry == ProducesNegatedCarry &&
45905f757f3fSDimitry Andric           CarrySrcMI->isUnsigned() &&
45915f757f3fSDimitry Andric           CarrySrcMI->getCarryOutReg() == CarryReg &&
45925f757f3fSDimitry Andric           selectAndRestoreState(*SrcMI))
459306c3fb27SDimitry Andric         return nullptr;
459406c3fb27SDimitry Andric     }
459506c3fb27SDimitry Andric   }
459606c3fb27SDimitry Andric 
459706c3fb27SDimitry Andric   Register DeadReg = MRI->createVirtualRegister(&AArch64::GPR32RegClass);
459806c3fb27SDimitry Andric 
459906c3fb27SDimitry Andric   if (NeedsNegatedCarry) {
460006c3fb27SDimitry Andric     // (0 - Carry) sets !C in NZCV when Carry == 1
460106c3fb27SDimitry Andric     Register ZReg = AArch64::WZR;
460206c3fb27SDimitry Andric     return emitInstr(AArch64::SUBSWrr, {DeadReg}, {ZReg, CarryReg}, MIB);
460306c3fb27SDimitry Andric   }
460406c3fb27SDimitry Andric 
460506c3fb27SDimitry Andric   // (Carry - 1) sets !C in NZCV when Carry == 0
460606c3fb27SDimitry Andric   auto Fns = select12BitValueWithLeftShift(1);
460706c3fb27SDimitry Andric   return emitInstr(AArch64::SUBSWri, {DeadReg}, {CarryReg}, MIB, Fns);
460806c3fb27SDimitry Andric }
460906c3fb27SDimitry Andric 
selectOverflowOp(MachineInstr & I,MachineRegisterInfo & MRI)461006c3fb27SDimitry Andric bool AArch64InstructionSelector::selectOverflowOp(MachineInstr &I,
461106c3fb27SDimitry Andric                                                   MachineRegisterInfo &MRI) {
461206c3fb27SDimitry Andric   auto &CarryMI = cast<GAddSubCarryOut>(I);
461306c3fb27SDimitry Andric 
461406c3fb27SDimitry Andric   if (auto *CarryInMI = dyn_cast<GAddSubCarryInOut>(&I)) {
461506c3fb27SDimitry Andric     // Set NZCV carry according to carry-in VReg
461606c3fb27SDimitry Andric     emitCarryIn(I, CarryInMI->getCarryInReg());
461706c3fb27SDimitry Andric   }
461806c3fb27SDimitry Andric 
461906c3fb27SDimitry Andric   // Emit the operation and get the correct condition code.
462006c3fb27SDimitry Andric   auto OpAndCC = emitOverflowOp(I.getOpcode(), CarryMI.getDstReg(),
462106c3fb27SDimitry Andric                                 CarryMI.getLHS(), CarryMI.getRHS(), MIB);
462206c3fb27SDimitry Andric 
462306c3fb27SDimitry Andric   Register CarryOutReg = CarryMI.getCarryOutReg();
462406c3fb27SDimitry Andric 
462506c3fb27SDimitry Andric   // Don't convert carry-out to VReg if it is never used
462606c3fb27SDimitry Andric   if (!MRI.use_nodbg_empty(CarryOutReg)) {
462706c3fb27SDimitry Andric     // Now, put the overflow result in the register given by the first operand
462806c3fb27SDimitry Andric     // to the overflow op. CSINC increments the result when the predicate is
462906c3fb27SDimitry Andric     // false, so to get the increment when it's true, we need to use the
463006c3fb27SDimitry Andric     // inverse. In this case, we want to increment when carry is set.
463106c3fb27SDimitry Andric     Register ZReg = AArch64::WZR;
463206c3fb27SDimitry Andric     emitCSINC(/*Dst=*/CarryOutReg, /*Src1=*/ZReg, /*Src2=*/ZReg,
463306c3fb27SDimitry Andric               getInvertedCondCode(OpAndCC.second), MIB);
463406c3fb27SDimitry Andric   }
463506c3fb27SDimitry Andric 
463606c3fb27SDimitry Andric   I.eraseFromParent();
463706c3fb27SDimitry Andric   return true;
463806c3fb27SDimitry Andric }
463906c3fb27SDimitry Andric 
4640e8d8bef9SDimitry Andric std::pair<MachineInstr *, AArch64CC::CondCode>
emitOverflowOp(unsigned Opcode,Register Dst,MachineOperand & LHS,MachineOperand & RHS,MachineIRBuilder & MIRBuilder) const4641e8d8bef9SDimitry Andric AArch64InstructionSelector::emitOverflowOp(unsigned Opcode, Register Dst,
4642e8d8bef9SDimitry Andric                                            MachineOperand &LHS,
4643e8d8bef9SDimitry Andric                                            MachineOperand &RHS,
4644e8d8bef9SDimitry Andric                                            MachineIRBuilder &MIRBuilder) const {
4645e8d8bef9SDimitry Andric   switch (Opcode) {
4646e8d8bef9SDimitry Andric   default:
4647e8d8bef9SDimitry Andric     llvm_unreachable("Unexpected opcode!");
4648e8d8bef9SDimitry Andric   case TargetOpcode::G_SADDO:
4649e8d8bef9SDimitry Andric     return std::make_pair(emitADDS(Dst, LHS, RHS, MIRBuilder), AArch64CC::VS);
4650e8d8bef9SDimitry Andric   case TargetOpcode::G_UADDO:
4651e8d8bef9SDimitry Andric     return std::make_pair(emitADDS(Dst, LHS, RHS, MIRBuilder), AArch64CC::HS);
4652e8d8bef9SDimitry Andric   case TargetOpcode::G_SSUBO:
4653e8d8bef9SDimitry Andric     return std::make_pair(emitSUBS(Dst, LHS, RHS, MIRBuilder), AArch64CC::VS);
4654e8d8bef9SDimitry Andric   case TargetOpcode::G_USUBO:
4655e8d8bef9SDimitry Andric     return std::make_pair(emitSUBS(Dst, LHS, RHS, MIRBuilder), AArch64CC::LO);
465606c3fb27SDimitry Andric   case TargetOpcode::G_SADDE:
465706c3fb27SDimitry Andric     return std::make_pair(emitADCS(Dst, LHS, RHS, MIRBuilder), AArch64CC::VS);
465806c3fb27SDimitry Andric   case TargetOpcode::G_UADDE:
465906c3fb27SDimitry Andric     return std::make_pair(emitADCS(Dst, LHS, RHS, MIRBuilder), AArch64CC::HS);
466006c3fb27SDimitry Andric   case TargetOpcode::G_SSUBE:
466106c3fb27SDimitry Andric     return std::make_pair(emitSBCS(Dst, LHS, RHS, MIRBuilder), AArch64CC::VS);
466206c3fb27SDimitry Andric   case TargetOpcode::G_USUBE:
466306c3fb27SDimitry Andric     return std::make_pair(emitSBCS(Dst, LHS, RHS, MIRBuilder), AArch64CC::LO);
4664e8d8bef9SDimitry Andric   }
4665e8d8bef9SDimitry Andric }
4666e8d8bef9SDimitry Andric 
466781ad6265SDimitry Andric /// Returns true if @p Val is a tree of AND/OR/CMP operations that can be
466881ad6265SDimitry Andric /// expressed as a conjunction.
466981ad6265SDimitry Andric /// \param CanNegate    Set to true if we can negate the whole sub-tree just by
467081ad6265SDimitry Andric ///                     changing the conditions on the CMP tests.
467181ad6265SDimitry Andric ///                     (this means we can call emitConjunctionRec() with
467281ad6265SDimitry Andric ///                      Negate==true on this sub-tree)
467381ad6265SDimitry Andric /// \param MustBeFirst  Set to true if this subtree needs to be negated and we
467481ad6265SDimitry Andric ///                     cannot do the negation naturally. We are required to
467581ad6265SDimitry Andric ///                     emit the subtree first in this case.
467681ad6265SDimitry Andric /// \param WillNegate   Is true if are called when the result of this
467781ad6265SDimitry Andric ///                     subexpression must be negated. This happens when the
467881ad6265SDimitry Andric ///                     outer expression is an OR. We can use this fact to know
467981ad6265SDimitry Andric ///                     that we have a double negation (or (or ...) ...) that
468081ad6265SDimitry Andric ///                     can be implemented for free.
canEmitConjunction(Register Val,bool & CanNegate,bool & MustBeFirst,bool WillNegate,MachineRegisterInfo & MRI,unsigned Depth=0)468181ad6265SDimitry Andric static bool canEmitConjunction(Register Val, bool &CanNegate, bool &MustBeFirst,
468281ad6265SDimitry Andric                                bool WillNegate, MachineRegisterInfo &MRI,
468381ad6265SDimitry Andric                                unsigned Depth = 0) {
468481ad6265SDimitry Andric   if (!MRI.hasOneNonDBGUse(Val))
468581ad6265SDimitry Andric     return false;
468681ad6265SDimitry Andric   MachineInstr *ValDef = MRI.getVRegDef(Val);
468781ad6265SDimitry Andric   unsigned Opcode = ValDef->getOpcode();
468881ad6265SDimitry Andric   if (isa<GAnyCmp>(ValDef)) {
468981ad6265SDimitry Andric     CanNegate = true;
469081ad6265SDimitry Andric     MustBeFirst = false;
469181ad6265SDimitry Andric     return true;
469281ad6265SDimitry Andric   }
469381ad6265SDimitry Andric   // Protect against exponential runtime and stack overflow.
469481ad6265SDimitry Andric   if (Depth > 6)
469581ad6265SDimitry Andric     return false;
469681ad6265SDimitry Andric   if (Opcode == TargetOpcode::G_AND || Opcode == TargetOpcode::G_OR) {
469781ad6265SDimitry Andric     bool IsOR = Opcode == TargetOpcode::G_OR;
469881ad6265SDimitry Andric     Register O0 = ValDef->getOperand(1).getReg();
469981ad6265SDimitry Andric     Register O1 = ValDef->getOperand(2).getReg();
470081ad6265SDimitry Andric     bool CanNegateL;
470181ad6265SDimitry Andric     bool MustBeFirstL;
470281ad6265SDimitry Andric     if (!canEmitConjunction(O0, CanNegateL, MustBeFirstL, IsOR, MRI, Depth + 1))
470381ad6265SDimitry Andric       return false;
470481ad6265SDimitry Andric     bool CanNegateR;
470581ad6265SDimitry Andric     bool MustBeFirstR;
470681ad6265SDimitry Andric     if (!canEmitConjunction(O1, CanNegateR, MustBeFirstR, IsOR, MRI, Depth + 1))
470781ad6265SDimitry Andric       return false;
470881ad6265SDimitry Andric 
470981ad6265SDimitry Andric     if (MustBeFirstL && MustBeFirstR)
471081ad6265SDimitry Andric       return false;
471181ad6265SDimitry Andric 
471281ad6265SDimitry Andric     if (IsOR) {
471381ad6265SDimitry Andric       // For an OR expression we need to be able to naturally negate at least
471481ad6265SDimitry Andric       // one side or we cannot do the transformation at all.
471581ad6265SDimitry Andric       if (!CanNegateL && !CanNegateR)
471681ad6265SDimitry Andric         return false;
471781ad6265SDimitry Andric       // If we the result of the OR will be negated and we can naturally negate
471881ad6265SDimitry Andric       // the leaves, then this sub-tree as a whole negates naturally.
471981ad6265SDimitry Andric       CanNegate = WillNegate && CanNegateL && CanNegateR;
472081ad6265SDimitry Andric       // If we cannot naturally negate the whole sub-tree, then this must be
472181ad6265SDimitry Andric       // emitted first.
472281ad6265SDimitry Andric       MustBeFirst = !CanNegate;
472381ad6265SDimitry Andric     } else {
472481ad6265SDimitry Andric       assert(Opcode == TargetOpcode::G_AND && "Must be G_AND");
472581ad6265SDimitry Andric       // We cannot naturally negate an AND operation.
472681ad6265SDimitry Andric       CanNegate = false;
472781ad6265SDimitry Andric       MustBeFirst = MustBeFirstL || MustBeFirstR;
472881ad6265SDimitry Andric     }
472981ad6265SDimitry Andric     return true;
473081ad6265SDimitry Andric   }
473181ad6265SDimitry Andric   return false;
473281ad6265SDimitry Andric }
473381ad6265SDimitry Andric 
emitConditionalComparison(Register LHS,Register RHS,CmpInst::Predicate CC,AArch64CC::CondCode Predicate,AArch64CC::CondCode OutCC,MachineIRBuilder & MIB) const473481ad6265SDimitry Andric MachineInstr *AArch64InstructionSelector::emitConditionalComparison(
473581ad6265SDimitry Andric     Register LHS, Register RHS, CmpInst::Predicate CC,
473681ad6265SDimitry Andric     AArch64CC::CondCode Predicate, AArch64CC::CondCode OutCC,
473781ad6265SDimitry Andric     MachineIRBuilder &MIB) const {
473881ad6265SDimitry Andric   auto &MRI = *MIB.getMRI();
473981ad6265SDimitry Andric   LLT OpTy = MRI.getType(LHS);
474081ad6265SDimitry Andric   unsigned CCmpOpc;
4741bdd1243dSDimitry Andric   std::optional<ValueAndVReg> C;
474281ad6265SDimitry Andric   if (CmpInst::isIntPredicate(CC)) {
4743*0fca6ea1SDimitry Andric     assert(OpTy.getSizeInBits() == 32 || OpTy.getSizeInBits() == 64);
4744bdd1243dSDimitry Andric     C = getIConstantVRegValWithLookThrough(RHS, MRI);
4745*0fca6ea1SDimitry Andric     if (!C || C->Value.sgt(31) || C->Value.slt(-31))
4746*0fca6ea1SDimitry Andric       CCmpOpc = OpTy.getSizeInBits() == 32 ? AArch64::CCMPWr : AArch64::CCMPXr;
4747*0fca6ea1SDimitry Andric     else if (C->Value.ule(31))
4748bdd1243dSDimitry Andric       CCmpOpc = OpTy.getSizeInBits() == 32 ? AArch64::CCMPWi : AArch64::CCMPXi;
4749bdd1243dSDimitry Andric     else
4750*0fca6ea1SDimitry Andric       CCmpOpc = OpTy.getSizeInBits() == 32 ? AArch64::CCMNWi : AArch64::CCMNXi;
475181ad6265SDimitry Andric   } else {
4752*0fca6ea1SDimitry Andric     assert(OpTy.getSizeInBits() == 16 || OpTy.getSizeInBits() == 32 ||
4753*0fca6ea1SDimitry Andric            OpTy.getSizeInBits() == 64);
475481ad6265SDimitry Andric     switch (OpTy.getSizeInBits()) {
475581ad6265SDimitry Andric     case 16:
4756*0fca6ea1SDimitry Andric       assert(STI.hasFullFP16() && "Expected Full FP16 for fp16 comparisons");
475781ad6265SDimitry Andric       CCmpOpc = AArch64::FCCMPHrr;
475881ad6265SDimitry Andric       break;
475981ad6265SDimitry Andric     case 32:
476081ad6265SDimitry Andric       CCmpOpc = AArch64::FCCMPSrr;
476181ad6265SDimitry Andric       break;
476281ad6265SDimitry Andric     case 64:
476381ad6265SDimitry Andric       CCmpOpc = AArch64::FCCMPDrr;
476481ad6265SDimitry Andric       break;
476581ad6265SDimitry Andric     default:
476681ad6265SDimitry Andric       return nullptr;
476781ad6265SDimitry Andric     }
476881ad6265SDimitry Andric   }
476981ad6265SDimitry Andric   AArch64CC::CondCode InvOutCC = AArch64CC::getInvertedCondCode(OutCC);
477081ad6265SDimitry Andric   unsigned NZCV = AArch64CC::getNZCVToSatisfyCondCode(InvOutCC);
477181ad6265SDimitry Andric   auto CCmp =
4772bdd1243dSDimitry Andric       MIB.buildInstr(CCmpOpc, {}, {LHS});
4773bdd1243dSDimitry Andric   if (CCmpOpc == AArch64::CCMPWi || CCmpOpc == AArch64::CCMPXi)
4774bdd1243dSDimitry Andric     CCmp.addImm(C->Value.getZExtValue());
4775*0fca6ea1SDimitry Andric   else if (CCmpOpc == AArch64::CCMNWi || CCmpOpc == AArch64::CCMNXi)
4776*0fca6ea1SDimitry Andric     CCmp.addImm(C->Value.abs().getZExtValue());
4777bdd1243dSDimitry Andric   else
4778bdd1243dSDimitry Andric     CCmp.addReg(RHS);
4779bdd1243dSDimitry Andric   CCmp.addImm(NZCV).addImm(Predicate);
478081ad6265SDimitry Andric   constrainSelectedInstRegOperands(*CCmp, TII, TRI, RBI);
478181ad6265SDimitry Andric   return &*CCmp;
478281ad6265SDimitry Andric }
478381ad6265SDimitry Andric 
emitConjunctionRec(Register Val,AArch64CC::CondCode & OutCC,bool Negate,Register CCOp,AArch64CC::CondCode Predicate,MachineIRBuilder & MIB) const478481ad6265SDimitry Andric MachineInstr *AArch64InstructionSelector::emitConjunctionRec(
478581ad6265SDimitry Andric     Register Val, AArch64CC::CondCode &OutCC, bool Negate, Register CCOp,
478681ad6265SDimitry Andric     AArch64CC::CondCode Predicate, MachineIRBuilder &MIB) const {
478781ad6265SDimitry Andric   // We're at a tree leaf, produce a conditional comparison operation.
478881ad6265SDimitry Andric   auto &MRI = *MIB.getMRI();
478981ad6265SDimitry Andric   MachineInstr *ValDef = MRI.getVRegDef(Val);
479081ad6265SDimitry Andric   unsigned Opcode = ValDef->getOpcode();
479181ad6265SDimitry Andric   if (auto *Cmp = dyn_cast<GAnyCmp>(ValDef)) {
479281ad6265SDimitry Andric     Register LHS = Cmp->getLHSReg();
479381ad6265SDimitry Andric     Register RHS = Cmp->getRHSReg();
479481ad6265SDimitry Andric     CmpInst::Predicate CC = Cmp->getCond();
479581ad6265SDimitry Andric     if (Negate)
479681ad6265SDimitry Andric       CC = CmpInst::getInversePredicate(CC);
479781ad6265SDimitry Andric     if (isa<GICmp>(Cmp)) {
479881ad6265SDimitry Andric       OutCC = changeICMPPredToAArch64CC(CC);
479981ad6265SDimitry Andric     } else {
480081ad6265SDimitry Andric       // Handle special FP cases.
480181ad6265SDimitry Andric       AArch64CC::CondCode ExtraCC;
480281ad6265SDimitry Andric       changeFPCCToANDAArch64CC(CC, OutCC, ExtraCC);
480381ad6265SDimitry Andric       // Some floating point conditions can't be tested with a single condition
480481ad6265SDimitry Andric       // code. Construct an additional comparison in this case.
480581ad6265SDimitry Andric       if (ExtraCC != AArch64CC::AL) {
480681ad6265SDimitry Andric         MachineInstr *ExtraCmp;
480781ad6265SDimitry Andric         if (!CCOp)
480881ad6265SDimitry Andric           ExtraCmp = emitFPCompare(LHS, RHS, MIB, CC);
480981ad6265SDimitry Andric         else
481081ad6265SDimitry Andric           ExtraCmp =
481181ad6265SDimitry Andric               emitConditionalComparison(LHS, RHS, CC, Predicate, ExtraCC, MIB);
481281ad6265SDimitry Andric         CCOp = ExtraCmp->getOperand(0).getReg();
481381ad6265SDimitry Andric         Predicate = ExtraCC;
481481ad6265SDimitry Andric       }
481581ad6265SDimitry Andric     }
481681ad6265SDimitry Andric 
481781ad6265SDimitry Andric     // Produce a normal comparison if we are first in the chain
481881ad6265SDimitry Andric     if (!CCOp) {
481981ad6265SDimitry Andric       auto Dst = MRI.cloneVirtualRegister(LHS);
482081ad6265SDimitry Andric       if (isa<GICmp>(Cmp))
482181ad6265SDimitry Andric         return emitSUBS(Dst, Cmp->getOperand(2), Cmp->getOperand(3), MIB);
482281ad6265SDimitry Andric       return emitFPCompare(Cmp->getOperand(2).getReg(),
482381ad6265SDimitry Andric                            Cmp->getOperand(3).getReg(), MIB);
482481ad6265SDimitry Andric     }
482581ad6265SDimitry Andric     // Otherwise produce a ccmp.
482681ad6265SDimitry Andric     return emitConditionalComparison(LHS, RHS, CC, Predicate, OutCC, MIB);
482781ad6265SDimitry Andric   }
482881ad6265SDimitry Andric   assert(MRI.hasOneNonDBGUse(Val) && "Valid conjunction/disjunction tree");
482981ad6265SDimitry Andric 
483081ad6265SDimitry Andric   bool IsOR = Opcode == TargetOpcode::G_OR;
483181ad6265SDimitry Andric 
483281ad6265SDimitry Andric   Register LHS = ValDef->getOperand(1).getReg();
483381ad6265SDimitry Andric   bool CanNegateL;
483481ad6265SDimitry Andric   bool MustBeFirstL;
483581ad6265SDimitry Andric   bool ValidL = canEmitConjunction(LHS, CanNegateL, MustBeFirstL, IsOR, MRI);
483681ad6265SDimitry Andric   assert(ValidL && "Valid conjunction/disjunction tree");
483781ad6265SDimitry Andric   (void)ValidL;
483881ad6265SDimitry Andric 
483981ad6265SDimitry Andric   Register RHS = ValDef->getOperand(2).getReg();
484081ad6265SDimitry Andric   bool CanNegateR;
484181ad6265SDimitry Andric   bool MustBeFirstR;
484281ad6265SDimitry Andric   bool ValidR = canEmitConjunction(RHS, CanNegateR, MustBeFirstR, IsOR, MRI);
484381ad6265SDimitry Andric   assert(ValidR && "Valid conjunction/disjunction tree");
484481ad6265SDimitry Andric   (void)ValidR;
484581ad6265SDimitry Andric 
484681ad6265SDimitry Andric   // Swap sub-tree that must come first to the right side.
484781ad6265SDimitry Andric   if (MustBeFirstL) {
484881ad6265SDimitry Andric     assert(!MustBeFirstR && "Valid conjunction/disjunction tree");
484981ad6265SDimitry Andric     std::swap(LHS, RHS);
485081ad6265SDimitry Andric     std::swap(CanNegateL, CanNegateR);
485181ad6265SDimitry Andric     std::swap(MustBeFirstL, MustBeFirstR);
485281ad6265SDimitry Andric   }
485381ad6265SDimitry Andric 
485481ad6265SDimitry Andric   bool NegateR;
485581ad6265SDimitry Andric   bool NegateAfterR;
485681ad6265SDimitry Andric   bool NegateL;
485781ad6265SDimitry Andric   bool NegateAfterAll;
485881ad6265SDimitry Andric   if (Opcode == TargetOpcode::G_OR) {
485981ad6265SDimitry Andric     // Swap the sub-tree that we can negate naturally to the left.
486081ad6265SDimitry Andric     if (!CanNegateL) {
486181ad6265SDimitry Andric       assert(CanNegateR && "at least one side must be negatable");
486281ad6265SDimitry Andric       assert(!MustBeFirstR && "invalid conjunction/disjunction tree");
486381ad6265SDimitry Andric       assert(!Negate);
486481ad6265SDimitry Andric       std::swap(LHS, RHS);
486581ad6265SDimitry Andric       NegateR = false;
486681ad6265SDimitry Andric       NegateAfterR = true;
486781ad6265SDimitry Andric     } else {
486881ad6265SDimitry Andric       // Negate the left sub-tree if possible, otherwise negate the result.
486981ad6265SDimitry Andric       NegateR = CanNegateR;
487081ad6265SDimitry Andric       NegateAfterR = !CanNegateR;
487181ad6265SDimitry Andric     }
487281ad6265SDimitry Andric     NegateL = true;
487381ad6265SDimitry Andric     NegateAfterAll = !Negate;
487481ad6265SDimitry Andric   } else {
487581ad6265SDimitry Andric     assert(Opcode == TargetOpcode::G_AND &&
487681ad6265SDimitry Andric            "Valid conjunction/disjunction tree");
487781ad6265SDimitry Andric     assert(!Negate && "Valid conjunction/disjunction tree");
487881ad6265SDimitry Andric 
487981ad6265SDimitry Andric     NegateL = false;
488081ad6265SDimitry Andric     NegateR = false;
488181ad6265SDimitry Andric     NegateAfterR = false;
488281ad6265SDimitry Andric     NegateAfterAll = false;
488381ad6265SDimitry Andric   }
488481ad6265SDimitry Andric 
488581ad6265SDimitry Andric   // Emit sub-trees.
488681ad6265SDimitry Andric   AArch64CC::CondCode RHSCC;
488781ad6265SDimitry Andric   MachineInstr *CmpR =
488881ad6265SDimitry Andric       emitConjunctionRec(RHS, RHSCC, NegateR, CCOp, Predicate, MIB);
488981ad6265SDimitry Andric   if (NegateAfterR)
489081ad6265SDimitry Andric     RHSCC = AArch64CC::getInvertedCondCode(RHSCC);
489181ad6265SDimitry Andric   MachineInstr *CmpL = emitConjunctionRec(
489281ad6265SDimitry Andric       LHS, OutCC, NegateL, CmpR->getOperand(0).getReg(), RHSCC, MIB);
489381ad6265SDimitry Andric   if (NegateAfterAll)
489481ad6265SDimitry Andric     OutCC = AArch64CC::getInvertedCondCode(OutCC);
489581ad6265SDimitry Andric   return CmpL;
489681ad6265SDimitry Andric }
489781ad6265SDimitry Andric 
emitConjunction(Register Val,AArch64CC::CondCode & OutCC,MachineIRBuilder & MIB) const489881ad6265SDimitry Andric MachineInstr *AArch64InstructionSelector::emitConjunction(
489981ad6265SDimitry Andric     Register Val, AArch64CC::CondCode &OutCC, MachineIRBuilder &MIB) const {
490081ad6265SDimitry Andric   bool DummyCanNegate;
490181ad6265SDimitry Andric   bool DummyMustBeFirst;
490281ad6265SDimitry Andric   if (!canEmitConjunction(Val, DummyCanNegate, DummyMustBeFirst, false,
490381ad6265SDimitry Andric                           *MIB.getMRI()))
490481ad6265SDimitry Andric     return nullptr;
490581ad6265SDimitry Andric   return emitConjunctionRec(Val, OutCC, false, Register(), AArch64CC::AL, MIB);
490681ad6265SDimitry Andric }
490781ad6265SDimitry Andric 
tryOptSelectConjunction(GSelect & SelI,MachineInstr & CondMI)490881ad6265SDimitry Andric bool AArch64InstructionSelector::tryOptSelectConjunction(GSelect &SelI,
490981ad6265SDimitry Andric                                                          MachineInstr &CondMI) {
491081ad6265SDimitry Andric   AArch64CC::CondCode AArch64CC;
491181ad6265SDimitry Andric   MachineInstr *ConjMI = emitConjunction(SelI.getCondReg(), AArch64CC, MIB);
491281ad6265SDimitry Andric   if (!ConjMI)
491381ad6265SDimitry Andric     return false;
491481ad6265SDimitry Andric 
491581ad6265SDimitry Andric   emitSelect(SelI.getReg(0), SelI.getTrueReg(), SelI.getFalseReg(), AArch64CC, MIB);
491681ad6265SDimitry Andric   SelI.eraseFromParent();
491781ad6265SDimitry Andric   return true;
491881ad6265SDimitry Andric }
491981ad6265SDimitry Andric 
tryOptSelect(GSelect & I)492081ad6265SDimitry Andric bool AArch64InstructionSelector::tryOptSelect(GSelect &I) {
49215ffd83dbSDimitry Andric   MachineRegisterInfo &MRI = *MIB.getMRI();
49225ffd83dbSDimitry Andric   // We want to recognize this pattern:
49235ffd83dbSDimitry Andric   //
49245ffd83dbSDimitry Andric   // $z = G_FCMP pred, $x, $y
49255ffd83dbSDimitry Andric   // ...
49265ffd83dbSDimitry Andric   // $w = G_SELECT $z, $a, $b
49275ffd83dbSDimitry Andric   //
49285ffd83dbSDimitry Andric   // Where the value of $z is *only* ever used by the G_SELECT (possibly with
49295ffd83dbSDimitry Andric   // some copies/truncs in between.)
49305ffd83dbSDimitry Andric   //
49315ffd83dbSDimitry Andric   // If we see this, then we can emit something like this:
49325ffd83dbSDimitry Andric   //
49335ffd83dbSDimitry Andric   // fcmp $x, $y
49345ffd83dbSDimitry Andric   // fcsel $w, $a, $b, pred
49355ffd83dbSDimitry Andric   //
49365ffd83dbSDimitry Andric   // Rather than emitting both of the rather long sequences in the standard
49375ffd83dbSDimitry Andric   // G_FCMP/G_SELECT select methods.
49385ffd83dbSDimitry Andric 
49395ffd83dbSDimitry Andric   // First, check if the condition is defined by a compare.
49405ffd83dbSDimitry Andric   MachineInstr *CondDef = MRI.getVRegDef(I.getOperand(1).getReg());
4941753f127fSDimitry Andric 
49425ffd83dbSDimitry Andric   // We can only fold if all of the defs have one use.
49435ffd83dbSDimitry Andric   Register CondDefReg = CondDef->getOperand(0).getReg();
49445ffd83dbSDimitry Andric   if (!MRI.hasOneNonDBGUse(CondDefReg)) {
49455ffd83dbSDimitry Andric     // Unless it's another select.
49465ffd83dbSDimitry Andric     for (const MachineInstr &UI : MRI.use_nodbg_instructions(CondDefReg)) {
49475ffd83dbSDimitry Andric       if (CondDef == &UI)
49485ffd83dbSDimitry Andric         continue;
49495ffd83dbSDimitry Andric       if (UI.getOpcode() != TargetOpcode::G_SELECT)
49505ffd83dbSDimitry Andric         return false;
49515ffd83dbSDimitry Andric     }
49525ffd83dbSDimitry Andric   }
49535ffd83dbSDimitry Andric 
49545ffd83dbSDimitry Andric   // Is the condition defined by a compare?
49555ffd83dbSDimitry Andric   unsigned CondOpc = CondDef->getOpcode();
495681ad6265SDimitry Andric   if (CondOpc != TargetOpcode::G_ICMP && CondOpc != TargetOpcode::G_FCMP) {
495781ad6265SDimitry Andric     if (tryOptSelectConjunction(I, *CondDef))
495881ad6265SDimitry Andric       return true;
49595ffd83dbSDimitry Andric     return false;
496081ad6265SDimitry Andric   }
49615ffd83dbSDimitry Andric 
49625ffd83dbSDimitry Andric   AArch64CC::CondCode CondCode;
49635ffd83dbSDimitry Andric   if (CondOpc == TargetOpcode::G_ICMP) {
4964e8d8bef9SDimitry Andric     auto Pred =
4965e8d8bef9SDimitry Andric         static_cast<CmpInst::Predicate>(CondDef->getOperand(1).getPredicate());
4966e8d8bef9SDimitry Andric     CondCode = changeICMPPredToAArch64CC(Pred);
49675ffd83dbSDimitry Andric     emitIntegerCompare(CondDef->getOperand(2), CondDef->getOperand(3),
49685ffd83dbSDimitry Andric                        CondDef->getOperand(1), MIB);
49695ffd83dbSDimitry Andric   } else {
49705ffd83dbSDimitry Andric     // Get the condition code for the select.
4971e8d8bef9SDimitry Andric     auto Pred =
4972e8d8bef9SDimitry Andric         static_cast<CmpInst::Predicate>(CondDef->getOperand(1).getPredicate());
49735ffd83dbSDimitry Andric     AArch64CC::CondCode CondCode2;
4974e8d8bef9SDimitry Andric     changeFCMPPredToAArch64CC(Pred, CondCode, CondCode2);
49755ffd83dbSDimitry Andric 
49765ffd83dbSDimitry Andric     // changeFCMPPredToAArch64CC sets CondCode2 to AL when we require two
49775ffd83dbSDimitry Andric     // instructions to emit the comparison.
49785ffd83dbSDimitry Andric     // TODO: Handle FCMP_UEQ and FCMP_ONE. After that, this check will be
49795ffd83dbSDimitry Andric     // unnecessary.
49805ffd83dbSDimitry Andric     if (CondCode2 != AArch64CC::AL)
49815ffd83dbSDimitry Andric       return false;
49825ffd83dbSDimitry Andric 
4983e8d8bef9SDimitry Andric     if (!emitFPCompare(CondDef->getOperand(2).getReg(),
4984e8d8bef9SDimitry Andric                        CondDef->getOperand(3).getReg(), MIB)) {
4985e8d8bef9SDimitry Andric       LLVM_DEBUG(dbgs() << "Couldn't emit compare for select!\n");
49865ffd83dbSDimitry Andric       return false;
4987e8d8bef9SDimitry Andric     }
49885ffd83dbSDimitry Andric   }
49895ffd83dbSDimitry Andric 
49905ffd83dbSDimitry Andric   // Emit the select.
4991e8d8bef9SDimitry Andric   emitSelect(I.getOperand(0).getReg(), I.getOperand(2).getReg(),
4992e8d8bef9SDimitry Andric              I.getOperand(3).getReg(), CondCode, MIB);
49935ffd83dbSDimitry Andric   I.eraseFromParent();
49945ffd83dbSDimitry Andric   return true;
49955ffd83dbSDimitry Andric }
49965ffd83dbSDimitry Andric 
tryFoldIntegerCompare(MachineOperand & LHS,MachineOperand & RHS,MachineOperand & Predicate,MachineIRBuilder & MIRBuilder) const49975ffd83dbSDimitry Andric MachineInstr *AArch64InstructionSelector::tryFoldIntegerCompare(
49985ffd83dbSDimitry Andric     MachineOperand &LHS, MachineOperand &RHS, MachineOperand &Predicate,
49995ffd83dbSDimitry Andric     MachineIRBuilder &MIRBuilder) const {
50005ffd83dbSDimitry Andric   assert(LHS.isReg() && RHS.isReg() && Predicate.isPredicate() &&
50015ffd83dbSDimitry Andric          "Unexpected MachineOperand");
50025ffd83dbSDimitry Andric   MachineRegisterInfo &MRI = *MIRBuilder.getMRI();
50035ffd83dbSDimitry Andric   // We want to find this sort of thing:
50045ffd83dbSDimitry Andric   // x = G_SUB 0, y
50055ffd83dbSDimitry Andric   // G_ICMP z, x
50065ffd83dbSDimitry Andric   //
50075ffd83dbSDimitry Andric   // In this case, we can fold the G_SUB into the G_ICMP using a CMN instead.
50085ffd83dbSDimitry Andric   // e.g:
50095ffd83dbSDimitry Andric   //
50105ffd83dbSDimitry Andric   // cmn z, y
50115ffd83dbSDimitry Andric 
50125ffd83dbSDimitry Andric   // Check if the RHS or LHS of the G_ICMP is defined by a SUB
50135ffd83dbSDimitry Andric   MachineInstr *LHSDef = getDefIgnoringCopies(LHS.getReg(), MRI);
50145ffd83dbSDimitry Andric   MachineInstr *RHSDef = getDefIgnoringCopies(RHS.getReg(), MRI);
5015fe6060f1SDimitry Andric   auto P = static_cast<CmpInst::Predicate>(Predicate.getPredicate());
50165ffd83dbSDimitry Andric   // Given this:
50175ffd83dbSDimitry Andric   //
50185ffd83dbSDimitry Andric   // x = G_SUB 0, y
50195ffd83dbSDimitry Andric   // G_ICMP x, z
50205ffd83dbSDimitry Andric   //
50215ffd83dbSDimitry Andric   // Produce this:
50225ffd83dbSDimitry Andric   //
50235ffd83dbSDimitry Andric   // cmn y, z
5024fe6060f1SDimitry Andric   if (isCMN(LHSDef, P, MRI))
50255ffd83dbSDimitry Andric     return emitCMN(LHSDef->getOperand(2), RHS, MIRBuilder);
50265ffd83dbSDimitry Andric 
50275ffd83dbSDimitry Andric   // Same idea here, but with the RHS of the compare instead:
50285ffd83dbSDimitry Andric   //
50295ffd83dbSDimitry Andric   // Given this:
50305ffd83dbSDimitry Andric   //
50315ffd83dbSDimitry Andric   // x = G_SUB 0, y
50325ffd83dbSDimitry Andric   // G_ICMP z, x
50335ffd83dbSDimitry Andric   //
50345ffd83dbSDimitry Andric   // Produce this:
50355ffd83dbSDimitry Andric   //
50365ffd83dbSDimitry Andric   // cmn z, y
5037fe6060f1SDimitry Andric   if (isCMN(RHSDef, P, MRI))
50385ffd83dbSDimitry Andric     return emitCMN(LHS, RHSDef->getOperand(2), MIRBuilder);
50395ffd83dbSDimitry Andric 
50405ffd83dbSDimitry Andric   // Given this:
50415ffd83dbSDimitry Andric   //
50425ffd83dbSDimitry Andric   // z = G_AND x, y
50435ffd83dbSDimitry Andric   // G_ICMP z, 0
50445ffd83dbSDimitry Andric   //
50455ffd83dbSDimitry Andric   // Produce this if the compare is signed:
50465ffd83dbSDimitry Andric   //
50475ffd83dbSDimitry Andric   // tst x, y
5048e8d8bef9SDimitry Andric   if (!CmpInst::isUnsigned(P) && LHSDef &&
50495ffd83dbSDimitry Andric       LHSDef->getOpcode() == TargetOpcode::G_AND) {
50505ffd83dbSDimitry Andric     // Make sure that the RHS is 0.
5051349cc55cSDimitry Andric     auto ValAndVReg = getIConstantVRegValWithLookThrough(RHS.getReg(), MRI);
50525ffd83dbSDimitry Andric     if (!ValAndVReg || ValAndVReg->Value != 0)
50535ffd83dbSDimitry Andric       return nullptr;
50545ffd83dbSDimitry Andric 
5055e8d8bef9SDimitry Andric     return emitTST(LHSDef->getOperand(1),
5056e8d8bef9SDimitry Andric                    LHSDef->getOperand(2), MIRBuilder);
50575ffd83dbSDimitry Andric   }
50585ffd83dbSDimitry Andric 
50595ffd83dbSDimitry Andric   return nullptr;
50605ffd83dbSDimitry Andric }
50615ffd83dbSDimitry Andric 
selectShuffleVector(MachineInstr & I,MachineRegisterInfo & MRI)50625ffd83dbSDimitry Andric bool AArch64InstructionSelector::selectShuffleVector(
5063fe6060f1SDimitry Andric     MachineInstr &I, MachineRegisterInfo &MRI) {
50645ffd83dbSDimitry Andric   const LLT DstTy = MRI.getType(I.getOperand(0).getReg());
50655ffd83dbSDimitry Andric   Register Src1Reg = I.getOperand(1).getReg();
50665ffd83dbSDimitry Andric   const LLT Src1Ty = MRI.getType(Src1Reg);
50675ffd83dbSDimitry Andric   Register Src2Reg = I.getOperand(2).getReg();
50685ffd83dbSDimitry Andric   const LLT Src2Ty = MRI.getType(Src2Reg);
50695ffd83dbSDimitry Andric   ArrayRef<int> Mask = I.getOperand(3).getShuffleMask();
50705ffd83dbSDimitry Andric 
50715ffd83dbSDimitry Andric   MachineBasicBlock &MBB = *I.getParent();
50725ffd83dbSDimitry Andric   MachineFunction &MF = *MBB.getParent();
50735ffd83dbSDimitry Andric   LLVMContext &Ctx = MF.getFunction().getContext();
50745ffd83dbSDimitry Andric 
50755ffd83dbSDimitry Andric   // G_SHUFFLE_VECTOR is weird in that the source operands can be scalars, if
50765ffd83dbSDimitry Andric   // it's originated from a <1 x T> type. Those should have been lowered into
50775ffd83dbSDimitry Andric   // G_BUILD_VECTOR earlier.
50785ffd83dbSDimitry Andric   if (!Src1Ty.isVector() || !Src2Ty.isVector()) {
50795ffd83dbSDimitry Andric     LLVM_DEBUG(dbgs() << "Could not select a \"scalar\" G_SHUFFLE_VECTOR\n");
50805ffd83dbSDimitry Andric     return false;
50815ffd83dbSDimitry Andric   }
50825ffd83dbSDimitry Andric 
50835ffd83dbSDimitry Andric   unsigned BytesPerElt = DstTy.getElementType().getSizeInBits() / 8;
50845ffd83dbSDimitry Andric 
50855ffd83dbSDimitry Andric   SmallVector<Constant *, 64> CstIdxs;
50865ffd83dbSDimitry Andric   for (int Val : Mask) {
50875ffd83dbSDimitry Andric     // For now, any undef indexes we'll just assume to be 0. This should be
50885ffd83dbSDimitry Andric     // optimized in future, e.g. to select DUP etc.
50895ffd83dbSDimitry Andric     Val = Val < 0 ? 0 : Val;
50905ffd83dbSDimitry Andric     for (unsigned Byte = 0; Byte < BytesPerElt; ++Byte) {
50915ffd83dbSDimitry Andric       unsigned Offset = Byte + Val * BytesPerElt;
50925ffd83dbSDimitry Andric       CstIdxs.emplace_back(ConstantInt::get(Type::getInt8Ty(Ctx), Offset));
50935ffd83dbSDimitry Andric     }
50945ffd83dbSDimitry Andric   }
50955ffd83dbSDimitry Andric 
50965ffd83dbSDimitry Andric   // Use a constant pool to load the index vector for TBL.
50975ffd83dbSDimitry Andric   Constant *CPVal = ConstantVector::get(CstIdxs);
5098fe6060f1SDimitry Andric   MachineInstr *IndexLoad = emitLoadFromConstantPool(CPVal, MIB);
50995ffd83dbSDimitry Andric   if (!IndexLoad) {
51005ffd83dbSDimitry Andric     LLVM_DEBUG(dbgs() << "Could not load from a constant pool");
51015ffd83dbSDimitry Andric     return false;
51025ffd83dbSDimitry Andric   }
51035ffd83dbSDimitry Andric 
51045ffd83dbSDimitry Andric   if (DstTy.getSizeInBits() != 128) {
51055ffd83dbSDimitry Andric     assert(DstTy.getSizeInBits() == 64 && "Unexpected shuffle result ty");
51065ffd83dbSDimitry Andric     // This case can be done with TBL1.
5107bdd1243dSDimitry Andric     MachineInstr *Concat =
5108bdd1243dSDimitry Andric         emitVectorConcat(std::nullopt, Src1Reg, Src2Reg, MIB);
51095ffd83dbSDimitry Andric     if (!Concat) {
51105ffd83dbSDimitry Andric       LLVM_DEBUG(dbgs() << "Could not do vector concat for tbl1");
51115ffd83dbSDimitry Andric       return false;
51125ffd83dbSDimitry Andric     }
51135ffd83dbSDimitry Andric 
51145ffd83dbSDimitry Andric     // The constant pool load will be 64 bits, so need to convert to FPR128 reg.
5115fe6060f1SDimitry Andric     IndexLoad = emitScalarToVector(64, &AArch64::FPR128RegClass,
5116fe6060f1SDimitry Andric                                    IndexLoad->getOperand(0).getReg(), MIB);
51175ffd83dbSDimitry Andric 
5118fe6060f1SDimitry Andric     auto TBL1 = MIB.buildInstr(
51195ffd83dbSDimitry Andric         AArch64::TBLv16i8One, {&AArch64::FPR128RegClass},
51205ffd83dbSDimitry Andric         {Concat->getOperand(0).getReg(), IndexLoad->getOperand(0).getReg()});
51215ffd83dbSDimitry Andric     constrainSelectedInstRegOperands(*TBL1, TII, TRI, RBI);
51225ffd83dbSDimitry Andric 
51235ffd83dbSDimitry Andric     auto Copy =
5124fe6060f1SDimitry Andric         MIB.buildInstr(TargetOpcode::COPY, {I.getOperand(0).getReg()}, {})
51255ffd83dbSDimitry Andric             .addReg(TBL1.getReg(0), 0, AArch64::dsub);
51265ffd83dbSDimitry Andric     RBI.constrainGenericRegister(Copy.getReg(0), AArch64::FPR64RegClass, MRI);
51275ffd83dbSDimitry Andric     I.eraseFromParent();
51285ffd83dbSDimitry Andric     return true;
51295ffd83dbSDimitry Andric   }
51305ffd83dbSDimitry Andric 
51315ffd83dbSDimitry Andric   // For TBL2 we need to emit a REG_SEQUENCE to tie together two consecutive
51325ffd83dbSDimitry Andric   // Q registers for regalloc.
5133fe6060f1SDimitry Andric   SmallVector<Register, 2> Regs = {Src1Reg, Src2Reg};
5134fe6060f1SDimitry Andric   auto RegSeq = createQTuple(Regs, MIB);
5135fe6060f1SDimitry Andric   auto TBL2 = MIB.buildInstr(AArch64::TBLv16i8Two, {I.getOperand(0)},
51365ffd83dbSDimitry Andric                              {RegSeq, IndexLoad->getOperand(0)});
51375ffd83dbSDimitry Andric   constrainSelectedInstRegOperands(*TBL2, TII, TRI, RBI);
51385ffd83dbSDimitry Andric   I.eraseFromParent();
51395ffd83dbSDimitry Andric   return true;
51405ffd83dbSDimitry Andric }
51415ffd83dbSDimitry Andric 
emitLaneInsert(std::optional<Register> DstReg,Register SrcReg,Register EltReg,unsigned LaneIdx,const RegisterBank & RB,MachineIRBuilder & MIRBuilder) const51425ffd83dbSDimitry Andric MachineInstr *AArch64InstructionSelector::emitLaneInsert(
5143bdd1243dSDimitry Andric     std::optional<Register> DstReg, Register SrcReg, Register EltReg,
51445ffd83dbSDimitry Andric     unsigned LaneIdx, const RegisterBank &RB,
51455ffd83dbSDimitry Andric     MachineIRBuilder &MIRBuilder) const {
51465ffd83dbSDimitry Andric   MachineInstr *InsElt = nullptr;
51475ffd83dbSDimitry Andric   const TargetRegisterClass *DstRC = &AArch64::FPR128RegClass;
51485ffd83dbSDimitry Andric   MachineRegisterInfo &MRI = *MIRBuilder.getMRI();
51495ffd83dbSDimitry Andric 
51505ffd83dbSDimitry Andric   // Create a register to define with the insert if one wasn't passed in.
51515ffd83dbSDimitry Andric   if (!DstReg)
51525ffd83dbSDimitry Andric     DstReg = MRI.createVirtualRegister(DstRC);
51535ffd83dbSDimitry Andric 
51545ffd83dbSDimitry Andric   unsigned EltSize = MRI.getType(EltReg).getSizeInBits();
51555ffd83dbSDimitry Andric   unsigned Opc = getInsertVecEltOpInfo(RB, EltSize).first;
51565ffd83dbSDimitry Andric 
51575ffd83dbSDimitry Andric   if (RB.getID() == AArch64::FPRRegBankID) {
51585ffd83dbSDimitry Andric     auto InsSub = emitScalarToVector(EltSize, DstRC, EltReg, MIRBuilder);
51595ffd83dbSDimitry Andric     InsElt = MIRBuilder.buildInstr(Opc, {*DstReg}, {SrcReg})
51605ffd83dbSDimitry Andric                  .addImm(LaneIdx)
51615ffd83dbSDimitry Andric                  .addUse(InsSub->getOperand(0).getReg())
51625ffd83dbSDimitry Andric                  .addImm(0);
51635ffd83dbSDimitry Andric   } else {
51645ffd83dbSDimitry Andric     InsElt = MIRBuilder.buildInstr(Opc, {*DstReg}, {SrcReg})
51655ffd83dbSDimitry Andric                  .addImm(LaneIdx)
51665ffd83dbSDimitry Andric                  .addUse(EltReg);
51675ffd83dbSDimitry Andric   }
51685ffd83dbSDimitry Andric 
51695ffd83dbSDimitry Andric   constrainSelectedInstRegOperands(*InsElt, TII, TRI, RBI);
51705ffd83dbSDimitry Andric   return InsElt;
51715ffd83dbSDimitry Andric }
51725ffd83dbSDimitry Andric 
selectUSMovFromExtend(MachineInstr & MI,MachineRegisterInfo & MRI)5173349cc55cSDimitry Andric bool AArch64InstructionSelector::selectUSMovFromExtend(
5174349cc55cSDimitry Andric     MachineInstr &MI, MachineRegisterInfo &MRI) {
5175349cc55cSDimitry Andric   if (MI.getOpcode() != TargetOpcode::G_SEXT &&
5176349cc55cSDimitry Andric       MI.getOpcode() != TargetOpcode::G_ZEXT &&
5177349cc55cSDimitry Andric       MI.getOpcode() != TargetOpcode::G_ANYEXT)
5178349cc55cSDimitry Andric     return false;
5179349cc55cSDimitry Andric   bool IsSigned = MI.getOpcode() == TargetOpcode::G_SEXT;
5180349cc55cSDimitry Andric   const Register DefReg = MI.getOperand(0).getReg();
5181349cc55cSDimitry Andric   const LLT DstTy = MRI.getType(DefReg);
5182349cc55cSDimitry Andric   unsigned DstSize = DstTy.getSizeInBits();
5183349cc55cSDimitry Andric 
5184349cc55cSDimitry Andric   if (DstSize != 32 && DstSize != 64)
5185349cc55cSDimitry Andric     return false;
5186349cc55cSDimitry Andric 
5187349cc55cSDimitry Andric   MachineInstr *Extract = getOpcodeDef(TargetOpcode::G_EXTRACT_VECTOR_ELT,
5188349cc55cSDimitry Andric                                        MI.getOperand(1).getReg(), MRI);
5189349cc55cSDimitry Andric   int64_t Lane;
5190349cc55cSDimitry Andric   if (!Extract || !mi_match(Extract->getOperand(2).getReg(), MRI, m_ICst(Lane)))
5191349cc55cSDimitry Andric     return false;
5192349cc55cSDimitry Andric   Register Src0 = Extract->getOperand(1).getReg();
5193349cc55cSDimitry Andric 
5194349cc55cSDimitry Andric   const LLT &VecTy = MRI.getType(Src0);
5195349cc55cSDimitry Andric 
5196349cc55cSDimitry Andric   if (VecTy.getSizeInBits() != 128) {
5197349cc55cSDimitry Andric     const MachineInstr *ScalarToVector = emitScalarToVector(
5198349cc55cSDimitry Andric         VecTy.getSizeInBits(), &AArch64::FPR128RegClass, Src0, MIB);
5199349cc55cSDimitry Andric     assert(ScalarToVector && "Didn't expect emitScalarToVector to fail!");
5200349cc55cSDimitry Andric     Src0 = ScalarToVector->getOperand(0).getReg();
5201349cc55cSDimitry Andric   }
5202349cc55cSDimitry Andric 
5203349cc55cSDimitry Andric   unsigned Opcode;
5204349cc55cSDimitry Andric   if (DstSize == 64 && VecTy.getScalarSizeInBits() == 32)
5205349cc55cSDimitry Andric     Opcode = IsSigned ? AArch64::SMOVvi32to64 : AArch64::UMOVvi32;
5206349cc55cSDimitry Andric   else if (DstSize == 64 && VecTy.getScalarSizeInBits() == 16)
5207349cc55cSDimitry Andric     Opcode = IsSigned ? AArch64::SMOVvi16to64 : AArch64::UMOVvi16;
5208349cc55cSDimitry Andric   else if (DstSize == 64 && VecTy.getScalarSizeInBits() == 8)
5209349cc55cSDimitry Andric     Opcode = IsSigned ? AArch64::SMOVvi8to64 : AArch64::UMOVvi8;
5210349cc55cSDimitry Andric   else if (DstSize == 32 && VecTy.getScalarSizeInBits() == 16)
5211349cc55cSDimitry Andric     Opcode = IsSigned ? AArch64::SMOVvi16to32 : AArch64::UMOVvi16;
5212349cc55cSDimitry Andric   else if (DstSize == 32 && VecTy.getScalarSizeInBits() == 8)
5213349cc55cSDimitry Andric     Opcode = IsSigned ? AArch64::SMOVvi8to32 : AArch64::UMOVvi8;
5214349cc55cSDimitry Andric   else
5215349cc55cSDimitry Andric     llvm_unreachable("Unexpected type combo for S/UMov!");
5216349cc55cSDimitry Andric 
5217349cc55cSDimitry Andric   // We may need to generate one of these, depending on the type and sign of the
5218349cc55cSDimitry Andric   // input:
5219349cc55cSDimitry Andric   //  DstReg = SMOV Src0, Lane;
5220349cc55cSDimitry Andric   //  NewReg = UMOV Src0, Lane; DstReg = SUBREG_TO_REG NewReg, sub_32;
5221349cc55cSDimitry Andric   MachineInstr *ExtI = nullptr;
5222349cc55cSDimitry Andric   if (DstSize == 64 && !IsSigned) {
5223349cc55cSDimitry Andric     Register NewReg = MRI.createVirtualRegister(&AArch64::GPR32RegClass);
5224349cc55cSDimitry Andric     MIB.buildInstr(Opcode, {NewReg}, {Src0}).addImm(Lane);
5225349cc55cSDimitry Andric     ExtI = MIB.buildInstr(AArch64::SUBREG_TO_REG, {DefReg}, {})
5226349cc55cSDimitry Andric                .addImm(0)
5227349cc55cSDimitry Andric                .addUse(NewReg)
5228349cc55cSDimitry Andric                .addImm(AArch64::sub_32);
5229349cc55cSDimitry Andric     RBI.constrainGenericRegister(DefReg, AArch64::GPR64RegClass, MRI);
5230349cc55cSDimitry Andric   } else
5231349cc55cSDimitry Andric     ExtI = MIB.buildInstr(Opcode, {DefReg}, {Src0}).addImm(Lane);
5232349cc55cSDimitry Andric 
5233349cc55cSDimitry Andric   constrainSelectedInstRegOperands(*ExtI, TII, TRI, RBI);
5234349cc55cSDimitry Andric   MI.eraseFromParent();
5235349cc55cSDimitry Andric   return true;
5236349cc55cSDimitry Andric }
5237349cc55cSDimitry Andric 
tryAdvSIMDModImm8(Register Dst,unsigned DstSize,APInt Bits,MachineIRBuilder & Builder)52385f757f3fSDimitry Andric MachineInstr *AArch64InstructionSelector::tryAdvSIMDModImm8(
52395f757f3fSDimitry Andric     Register Dst, unsigned DstSize, APInt Bits, MachineIRBuilder &Builder) {
52405f757f3fSDimitry Andric   unsigned int Op;
52415f757f3fSDimitry Andric   if (DstSize == 128) {
52425f757f3fSDimitry Andric     if (Bits.getHiBits(64) != Bits.getLoBits(64))
52435f757f3fSDimitry Andric       return nullptr;
52445f757f3fSDimitry Andric     Op = AArch64::MOVIv16b_ns;
52455f757f3fSDimitry Andric   } else {
52465f757f3fSDimitry Andric     Op = AArch64::MOVIv8b_ns;
52475f757f3fSDimitry Andric   }
52485f757f3fSDimitry Andric 
52495f757f3fSDimitry Andric   uint64_t Val = Bits.zextOrTrunc(64).getZExtValue();
52505f757f3fSDimitry Andric 
52515f757f3fSDimitry Andric   if (AArch64_AM::isAdvSIMDModImmType9(Val)) {
52525f757f3fSDimitry Andric     Val = AArch64_AM::encodeAdvSIMDModImmType9(Val);
52535f757f3fSDimitry Andric     auto Mov = Builder.buildInstr(Op, {Dst}, {}).addImm(Val);
52545f757f3fSDimitry Andric     constrainSelectedInstRegOperands(*Mov, TII, TRI, RBI);
52555f757f3fSDimitry Andric     return &*Mov;
52565f757f3fSDimitry Andric   }
52575f757f3fSDimitry Andric   return nullptr;
52585f757f3fSDimitry Andric }
52595f757f3fSDimitry Andric 
tryAdvSIMDModImm16(Register Dst,unsigned DstSize,APInt Bits,MachineIRBuilder & Builder,bool Inv)52605f757f3fSDimitry Andric MachineInstr *AArch64InstructionSelector::tryAdvSIMDModImm16(
52615f757f3fSDimitry Andric     Register Dst, unsigned DstSize, APInt Bits, MachineIRBuilder &Builder,
52625f757f3fSDimitry Andric     bool Inv) {
52635f757f3fSDimitry Andric 
52645f757f3fSDimitry Andric   unsigned int Op;
52655f757f3fSDimitry Andric   if (DstSize == 128) {
52665f757f3fSDimitry Andric     if (Bits.getHiBits(64) != Bits.getLoBits(64))
52675f757f3fSDimitry Andric       return nullptr;
52685f757f3fSDimitry Andric     Op = Inv ? AArch64::MVNIv8i16 : AArch64::MOVIv8i16;
52695f757f3fSDimitry Andric   } else {
52705f757f3fSDimitry Andric     Op = Inv ? AArch64::MVNIv4i16 : AArch64::MOVIv4i16;
52715f757f3fSDimitry Andric   }
52725f757f3fSDimitry Andric 
52735f757f3fSDimitry Andric   uint64_t Val = Bits.zextOrTrunc(64).getZExtValue();
52745f757f3fSDimitry Andric   uint64_t Shift;
52755f757f3fSDimitry Andric 
52765f757f3fSDimitry Andric   if (AArch64_AM::isAdvSIMDModImmType5(Val)) {
52775f757f3fSDimitry Andric     Val = AArch64_AM::encodeAdvSIMDModImmType5(Val);
52785f757f3fSDimitry Andric     Shift = 0;
52795f757f3fSDimitry Andric   } else if (AArch64_AM::isAdvSIMDModImmType6(Val)) {
52805f757f3fSDimitry Andric     Val = AArch64_AM::encodeAdvSIMDModImmType6(Val);
52815f757f3fSDimitry Andric     Shift = 8;
52825f757f3fSDimitry Andric   } else
52835f757f3fSDimitry Andric     return nullptr;
52845f757f3fSDimitry Andric 
52855f757f3fSDimitry Andric   auto Mov = Builder.buildInstr(Op, {Dst}, {}).addImm(Val).addImm(Shift);
52865f757f3fSDimitry Andric   constrainSelectedInstRegOperands(*Mov, TII, TRI, RBI);
52875f757f3fSDimitry Andric   return &*Mov;
52885f757f3fSDimitry Andric }
52895f757f3fSDimitry Andric 
tryAdvSIMDModImm32(Register Dst,unsigned DstSize,APInt Bits,MachineIRBuilder & Builder,bool Inv)52905f757f3fSDimitry Andric MachineInstr *AArch64InstructionSelector::tryAdvSIMDModImm32(
52915f757f3fSDimitry Andric     Register Dst, unsigned DstSize, APInt Bits, MachineIRBuilder &Builder,
52925f757f3fSDimitry Andric     bool Inv) {
52935f757f3fSDimitry Andric 
52945f757f3fSDimitry Andric   unsigned int Op;
52955f757f3fSDimitry Andric   if (DstSize == 128) {
52965f757f3fSDimitry Andric     if (Bits.getHiBits(64) != Bits.getLoBits(64))
52975f757f3fSDimitry Andric       return nullptr;
52985f757f3fSDimitry Andric     Op = Inv ? AArch64::MVNIv4i32 : AArch64::MOVIv4i32;
52995f757f3fSDimitry Andric   } else {
53005f757f3fSDimitry Andric     Op = Inv ? AArch64::MVNIv2i32 : AArch64::MOVIv2i32;
53015f757f3fSDimitry Andric   }
53025f757f3fSDimitry Andric 
53035f757f3fSDimitry Andric   uint64_t Val = Bits.zextOrTrunc(64).getZExtValue();
53045f757f3fSDimitry Andric   uint64_t Shift;
53055f757f3fSDimitry Andric 
53065f757f3fSDimitry Andric   if ((AArch64_AM::isAdvSIMDModImmType1(Val))) {
53075f757f3fSDimitry Andric     Val = AArch64_AM::encodeAdvSIMDModImmType1(Val);
53085f757f3fSDimitry Andric     Shift = 0;
53095f757f3fSDimitry Andric   } else if ((AArch64_AM::isAdvSIMDModImmType2(Val))) {
53105f757f3fSDimitry Andric     Val = AArch64_AM::encodeAdvSIMDModImmType2(Val);
53115f757f3fSDimitry Andric     Shift = 8;
53125f757f3fSDimitry Andric   } else if ((AArch64_AM::isAdvSIMDModImmType3(Val))) {
53135f757f3fSDimitry Andric     Val = AArch64_AM::encodeAdvSIMDModImmType3(Val);
53145f757f3fSDimitry Andric     Shift = 16;
53155f757f3fSDimitry Andric   } else if ((AArch64_AM::isAdvSIMDModImmType4(Val))) {
53165f757f3fSDimitry Andric     Val = AArch64_AM::encodeAdvSIMDModImmType4(Val);
53175f757f3fSDimitry Andric     Shift = 24;
53185f757f3fSDimitry Andric   } else
53195f757f3fSDimitry Andric     return nullptr;
53205f757f3fSDimitry Andric 
53215f757f3fSDimitry Andric   auto Mov = Builder.buildInstr(Op, {Dst}, {}).addImm(Val).addImm(Shift);
53225f757f3fSDimitry Andric   constrainSelectedInstRegOperands(*Mov, TII, TRI, RBI);
53235f757f3fSDimitry Andric   return &*Mov;
53245f757f3fSDimitry Andric }
53255f757f3fSDimitry Andric 
tryAdvSIMDModImm64(Register Dst,unsigned DstSize,APInt Bits,MachineIRBuilder & Builder)53265f757f3fSDimitry Andric MachineInstr *AArch64InstructionSelector::tryAdvSIMDModImm64(
53275f757f3fSDimitry Andric     Register Dst, unsigned DstSize, APInt Bits, MachineIRBuilder &Builder) {
53285f757f3fSDimitry Andric 
53295f757f3fSDimitry Andric   unsigned int Op;
53305f757f3fSDimitry Andric   if (DstSize == 128) {
53315f757f3fSDimitry Andric     if (Bits.getHiBits(64) != Bits.getLoBits(64))
53325f757f3fSDimitry Andric       return nullptr;
53335f757f3fSDimitry Andric     Op = AArch64::MOVIv2d_ns;
53345f757f3fSDimitry Andric   } else {
53355f757f3fSDimitry Andric     Op = AArch64::MOVID;
53365f757f3fSDimitry Andric   }
53375f757f3fSDimitry Andric 
53385f757f3fSDimitry Andric   uint64_t Val = Bits.zextOrTrunc(64).getZExtValue();
53395f757f3fSDimitry Andric   if (AArch64_AM::isAdvSIMDModImmType10(Val)) {
53405f757f3fSDimitry Andric     Val = AArch64_AM::encodeAdvSIMDModImmType10(Val);
53415f757f3fSDimitry Andric     auto Mov = Builder.buildInstr(Op, {Dst}, {}).addImm(Val);
53425f757f3fSDimitry Andric     constrainSelectedInstRegOperands(*Mov, TII, TRI, RBI);
53435f757f3fSDimitry Andric     return &*Mov;
53445f757f3fSDimitry Andric   }
53455f757f3fSDimitry Andric   return nullptr;
53465f757f3fSDimitry Andric }
53475f757f3fSDimitry Andric 
tryAdvSIMDModImm321s(Register Dst,unsigned DstSize,APInt Bits,MachineIRBuilder & Builder,bool Inv)53485f757f3fSDimitry Andric MachineInstr *AArch64InstructionSelector::tryAdvSIMDModImm321s(
53495f757f3fSDimitry Andric     Register Dst, unsigned DstSize, APInt Bits, MachineIRBuilder &Builder,
53505f757f3fSDimitry Andric     bool Inv) {
53515f757f3fSDimitry Andric 
53525f757f3fSDimitry Andric   unsigned int Op;
53535f757f3fSDimitry Andric   if (DstSize == 128) {
53545f757f3fSDimitry Andric     if (Bits.getHiBits(64) != Bits.getLoBits(64))
53555f757f3fSDimitry Andric       return nullptr;
53565f757f3fSDimitry Andric     Op = Inv ? AArch64::MVNIv4s_msl : AArch64::MOVIv4s_msl;
53575f757f3fSDimitry Andric   } else {
53585f757f3fSDimitry Andric     Op = Inv ? AArch64::MVNIv2s_msl : AArch64::MOVIv2s_msl;
53595f757f3fSDimitry Andric   }
53605f757f3fSDimitry Andric 
53615f757f3fSDimitry Andric   uint64_t Val = Bits.zextOrTrunc(64).getZExtValue();
53625f757f3fSDimitry Andric   uint64_t Shift;
53635f757f3fSDimitry Andric 
53645f757f3fSDimitry Andric   if (AArch64_AM::isAdvSIMDModImmType7(Val)) {
53655f757f3fSDimitry Andric     Val = AArch64_AM::encodeAdvSIMDModImmType7(Val);
53665f757f3fSDimitry Andric     Shift = 264;
53675f757f3fSDimitry Andric   } else if (AArch64_AM::isAdvSIMDModImmType8(Val)) {
53685f757f3fSDimitry Andric     Val = AArch64_AM::encodeAdvSIMDModImmType8(Val);
53695f757f3fSDimitry Andric     Shift = 272;
53705f757f3fSDimitry Andric   } else
53715f757f3fSDimitry Andric     return nullptr;
53725f757f3fSDimitry Andric 
53735f757f3fSDimitry Andric   auto Mov = Builder.buildInstr(Op, {Dst}, {}).addImm(Val).addImm(Shift);
53745f757f3fSDimitry Andric   constrainSelectedInstRegOperands(*Mov, TII, TRI, RBI);
53755f757f3fSDimitry Andric   return &*Mov;
53765f757f3fSDimitry Andric }
53775f757f3fSDimitry Andric 
tryAdvSIMDModImmFP(Register Dst,unsigned DstSize,APInt Bits,MachineIRBuilder & Builder)53785f757f3fSDimitry Andric MachineInstr *AArch64InstructionSelector::tryAdvSIMDModImmFP(
53795f757f3fSDimitry Andric     Register Dst, unsigned DstSize, APInt Bits, MachineIRBuilder &Builder) {
53805f757f3fSDimitry Andric 
53815f757f3fSDimitry Andric   unsigned int Op;
53825f757f3fSDimitry Andric   bool IsWide = false;
53835f757f3fSDimitry Andric   if (DstSize == 128) {
53845f757f3fSDimitry Andric     if (Bits.getHiBits(64) != Bits.getLoBits(64))
53855f757f3fSDimitry Andric       return nullptr;
53865f757f3fSDimitry Andric     Op = AArch64::FMOVv4f32_ns;
53875f757f3fSDimitry Andric     IsWide = true;
53885f757f3fSDimitry Andric   } else {
53895f757f3fSDimitry Andric     Op = AArch64::FMOVv2f32_ns;
53905f757f3fSDimitry Andric   }
53915f757f3fSDimitry Andric 
53925f757f3fSDimitry Andric   uint64_t Val = Bits.zextOrTrunc(64).getZExtValue();
53935f757f3fSDimitry Andric 
53945f757f3fSDimitry Andric   if (AArch64_AM::isAdvSIMDModImmType11(Val)) {
53955f757f3fSDimitry Andric     Val = AArch64_AM::encodeAdvSIMDModImmType11(Val);
53965f757f3fSDimitry Andric   } else if (IsWide && AArch64_AM::isAdvSIMDModImmType12(Val)) {
53975f757f3fSDimitry Andric     Val = AArch64_AM::encodeAdvSIMDModImmType12(Val);
53985f757f3fSDimitry Andric     Op = AArch64::FMOVv2f64_ns;
53995f757f3fSDimitry Andric   } else
54005f757f3fSDimitry Andric     return nullptr;
54015f757f3fSDimitry Andric 
54025f757f3fSDimitry Andric   auto Mov = Builder.buildInstr(Op, {Dst}, {}).addImm(Val);
54035f757f3fSDimitry Andric   constrainSelectedInstRegOperands(*Mov, TII, TRI, RBI);
54045f757f3fSDimitry Andric   return &*Mov;
54055f757f3fSDimitry Andric }
54065f757f3fSDimitry Andric 
selectIndexedExtLoad(MachineInstr & MI,MachineRegisterInfo & MRI)54075f757f3fSDimitry Andric bool AArch64InstructionSelector::selectIndexedExtLoad(
54085f757f3fSDimitry Andric     MachineInstr &MI, MachineRegisterInfo &MRI) {
54097a6dacacSDimitry Andric   auto &ExtLd = cast<GIndexedAnyExtLoad>(MI);
54105f757f3fSDimitry Andric   Register Dst = ExtLd.getDstReg();
54115f757f3fSDimitry Andric   Register WriteBack = ExtLd.getWritebackReg();
54125f757f3fSDimitry Andric   Register Base = ExtLd.getBaseReg();
54135f757f3fSDimitry Andric   Register Offset = ExtLd.getOffsetReg();
54145f757f3fSDimitry Andric   LLT Ty = MRI.getType(Dst);
54155f757f3fSDimitry Andric   assert(Ty.getSizeInBits() <= 64); // Only for scalar GPRs.
54165f757f3fSDimitry Andric   unsigned MemSizeBits = ExtLd.getMMO().getMemoryType().getSizeInBits();
54175f757f3fSDimitry Andric   bool IsPre = ExtLd.isPre();
54185f757f3fSDimitry Andric   bool IsSExt = isa<GIndexedSExtLoad>(ExtLd);
54195f757f3fSDimitry Andric   bool InsertIntoXReg = false;
54205f757f3fSDimitry Andric   bool IsDst64 = Ty.getSizeInBits() == 64;
54215f757f3fSDimitry Andric 
54225f757f3fSDimitry Andric   unsigned Opc = 0;
54235f757f3fSDimitry Andric   LLT NewLdDstTy;
54245f757f3fSDimitry Andric   LLT s32 = LLT::scalar(32);
54255f757f3fSDimitry Andric   LLT s64 = LLT::scalar(64);
54265f757f3fSDimitry Andric 
54275f757f3fSDimitry Andric   if (MemSizeBits == 8) {
54285f757f3fSDimitry Andric     if (IsSExt) {
54295f757f3fSDimitry Andric       if (IsDst64)
54305f757f3fSDimitry Andric         Opc = IsPre ? AArch64::LDRSBXpre : AArch64::LDRSBXpost;
54315f757f3fSDimitry Andric       else
54325f757f3fSDimitry Andric         Opc = IsPre ? AArch64::LDRSBWpre : AArch64::LDRSBWpost;
54335f757f3fSDimitry Andric       NewLdDstTy = IsDst64 ? s64 : s32;
54345f757f3fSDimitry Andric     } else {
54355f757f3fSDimitry Andric       Opc = IsPre ? AArch64::LDRBBpre : AArch64::LDRBBpost;
54365f757f3fSDimitry Andric       InsertIntoXReg = IsDst64;
54375f757f3fSDimitry Andric       NewLdDstTy = s32;
54385f757f3fSDimitry Andric     }
54395f757f3fSDimitry Andric   } else if (MemSizeBits == 16) {
54405f757f3fSDimitry Andric     if (IsSExt) {
54415f757f3fSDimitry Andric       if (IsDst64)
54425f757f3fSDimitry Andric         Opc = IsPre ? AArch64::LDRSHXpre : AArch64::LDRSHXpost;
54435f757f3fSDimitry Andric       else
54445f757f3fSDimitry Andric         Opc = IsPre ? AArch64::LDRSHWpre : AArch64::LDRSHWpost;
54455f757f3fSDimitry Andric       NewLdDstTy = IsDst64 ? s64 : s32;
54465f757f3fSDimitry Andric     } else {
54475f757f3fSDimitry Andric       Opc = IsPre ? AArch64::LDRHHpre : AArch64::LDRHHpost;
54485f757f3fSDimitry Andric       InsertIntoXReg = IsDst64;
54495f757f3fSDimitry Andric       NewLdDstTy = s32;
54505f757f3fSDimitry Andric     }
54515f757f3fSDimitry Andric   } else if (MemSizeBits == 32) {
54525f757f3fSDimitry Andric     if (IsSExt) {
54535f757f3fSDimitry Andric       Opc = IsPre ? AArch64::LDRSWpre : AArch64::LDRSWpost;
54545f757f3fSDimitry Andric       NewLdDstTy = s64;
54555f757f3fSDimitry Andric     } else {
54565f757f3fSDimitry Andric       Opc = IsPre ? AArch64::LDRWpre : AArch64::LDRWpost;
54575f757f3fSDimitry Andric       InsertIntoXReg = IsDst64;
54585f757f3fSDimitry Andric       NewLdDstTy = s32;
54595f757f3fSDimitry Andric     }
54605f757f3fSDimitry Andric   } else {
54615f757f3fSDimitry Andric     llvm_unreachable("Unexpected size for indexed load");
54625f757f3fSDimitry Andric   }
54635f757f3fSDimitry Andric 
54645f757f3fSDimitry Andric   if (RBI.getRegBank(Dst, MRI, TRI)->getID() == AArch64::FPRRegBankID)
54655f757f3fSDimitry Andric     return false; // We should be on gpr.
54665f757f3fSDimitry Andric 
54675f757f3fSDimitry Andric   auto Cst = getIConstantVRegVal(Offset, MRI);
54685f757f3fSDimitry Andric   if (!Cst)
54695f757f3fSDimitry Andric     return false; // Shouldn't happen, but just in case.
54705f757f3fSDimitry Andric 
54715f757f3fSDimitry Andric   auto LdMI = MIB.buildInstr(Opc, {WriteBack, NewLdDstTy}, {Base})
54725f757f3fSDimitry Andric                   .addImm(Cst->getSExtValue());
54735f757f3fSDimitry Andric   LdMI.cloneMemRefs(ExtLd);
54745f757f3fSDimitry Andric   constrainSelectedInstRegOperands(*LdMI, TII, TRI, RBI);
54755f757f3fSDimitry Andric   // Make sure to select the load with the MemTy as the dest type, and then
54765f757f3fSDimitry Andric   // insert into X reg if needed.
54775f757f3fSDimitry Andric   if (InsertIntoXReg) {
54785f757f3fSDimitry Andric     // Generate a SUBREG_TO_REG.
54795f757f3fSDimitry Andric     auto SubToReg = MIB.buildInstr(TargetOpcode::SUBREG_TO_REG, {Dst}, {})
54805f757f3fSDimitry Andric                         .addImm(0)
54815f757f3fSDimitry Andric                         .addUse(LdMI.getReg(1))
54825f757f3fSDimitry Andric                         .addImm(AArch64::sub_32);
54835f757f3fSDimitry Andric     RBI.constrainGenericRegister(SubToReg.getReg(0), AArch64::GPR64RegClass,
54845f757f3fSDimitry Andric                                  MRI);
54855f757f3fSDimitry Andric   } else {
54865f757f3fSDimitry Andric     auto Copy = MIB.buildCopy(Dst, LdMI.getReg(1));
54875f757f3fSDimitry Andric     selectCopy(*Copy, TII, MRI, TRI, RBI);
54885f757f3fSDimitry Andric   }
54895f757f3fSDimitry Andric   MI.eraseFromParent();
54905f757f3fSDimitry Andric 
54915f757f3fSDimitry Andric   return true;
54925f757f3fSDimitry Andric }
54935f757f3fSDimitry Andric 
selectIndexedLoad(MachineInstr & MI,MachineRegisterInfo & MRI)54945f757f3fSDimitry Andric bool AArch64InstructionSelector::selectIndexedLoad(MachineInstr &MI,
54955f757f3fSDimitry Andric                                                    MachineRegisterInfo &MRI) {
54965f757f3fSDimitry Andric   auto &Ld = cast<GIndexedLoad>(MI);
54975f757f3fSDimitry Andric   Register Dst = Ld.getDstReg();
54985f757f3fSDimitry Andric   Register WriteBack = Ld.getWritebackReg();
54995f757f3fSDimitry Andric   Register Base = Ld.getBaseReg();
55005f757f3fSDimitry Andric   Register Offset = Ld.getOffsetReg();
55015f757f3fSDimitry Andric   assert(MRI.getType(Dst).getSizeInBits() <= 128 &&
55025f757f3fSDimitry Andric          "Unexpected type for indexed load");
55035f757f3fSDimitry Andric   unsigned MemSize = Ld.getMMO().getMemoryType().getSizeInBytes();
55045f757f3fSDimitry Andric 
55057a6dacacSDimitry Andric   if (MemSize < MRI.getType(Dst).getSizeInBytes())
55067a6dacacSDimitry Andric     return selectIndexedExtLoad(MI, MRI);
55077a6dacacSDimitry Andric 
55085f757f3fSDimitry Andric   unsigned Opc = 0;
55095f757f3fSDimitry Andric   if (Ld.isPre()) {
55105f757f3fSDimitry Andric     static constexpr unsigned GPROpcodes[] = {
55115f757f3fSDimitry Andric         AArch64::LDRBBpre, AArch64::LDRHHpre, AArch64::LDRWpre,
55125f757f3fSDimitry Andric         AArch64::LDRXpre};
55135f757f3fSDimitry Andric     static constexpr unsigned FPROpcodes[] = {
55145f757f3fSDimitry Andric         AArch64::LDRBpre, AArch64::LDRHpre, AArch64::LDRSpre, AArch64::LDRDpre,
55155f757f3fSDimitry Andric         AArch64::LDRQpre};
55165f757f3fSDimitry Andric     if (RBI.getRegBank(Dst, MRI, TRI)->getID() == AArch64::FPRRegBankID)
55175f757f3fSDimitry Andric       Opc = FPROpcodes[Log2_32(MemSize)];
55185f757f3fSDimitry Andric     else
55195f757f3fSDimitry Andric       Opc = GPROpcodes[Log2_32(MemSize)];
55205f757f3fSDimitry Andric   } else {
55215f757f3fSDimitry Andric     static constexpr unsigned GPROpcodes[] = {
55225f757f3fSDimitry Andric         AArch64::LDRBBpost, AArch64::LDRHHpost, AArch64::LDRWpost,
55235f757f3fSDimitry Andric         AArch64::LDRXpost};
55245f757f3fSDimitry Andric     static constexpr unsigned FPROpcodes[] = {
55255f757f3fSDimitry Andric         AArch64::LDRBpost, AArch64::LDRHpost, AArch64::LDRSpost,
55265f757f3fSDimitry Andric         AArch64::LDRDpost, AArch64::LDRQpost};
55275f757f3fSDimitry Andric     if (RBI.getRegBank(Dst, MRI, TRI)->getID() == AArch64::FPRRegBankID)
55285f757f3fSDimitry Andric       Opc = FPROpcodes[Log2_32(MemSize)];
55295f757f3fSDimitry Andric     else
55305f757f3fSDimitry Andric       Opc = GPROpcodes[Log2_32(MemSize)];
55315f757f3fSDimitry Andric   }
55325f757f3fSDimitry Andric   auto Cst = getIConstantVRegVal(Offset, MRI);
55335f757f3fSDimitry Andric   if (!Cst)
55345f757f3fSDimitry Andric     return false; // Shouldn't happen, but just in case.
55355f757f3fSDimitry Andric   auto LdMI =
55365f757f3fSDimitry Andric       MIB.buildInstr(Opc, {WriteBack, Dst}, {Base}).addImm(Cst->getSExtValue());
55375f757f3fSDimitry Andric   LdMI.cloneMemRefs(Ld);
55385f757f3fSDimitry Andric   constrainSelectedInstRegOperands(*LdMI, TII, TRI, RBI);
55395f757f3fSDimitry Andric   MI.eraseFromParent();
55405f757f3fSDimitry Andric   return true;
55415f757f3fSDimitry Andric }
55425f757f3fSDimitry Andric 
selectIndexedStore(GIndexedStore & I,MachineRegisterInfo & MRI)55435f757f3fSDimitry Andric bool AArch64InstructionSelector::selectIndexedStore(GIndexedStore &I,
55445f757f3fSDimitry Andric                                                     MachineRegisterInfo &MRI) {
55455f757f3fSDimitry Andric   Register Dst = I.getWritebackReg();
55465f757f3fSDimitry Andric   Register Val = I.getValueReg();
55475f757f3fSDimitry Andric   Register Base = I.getBaseReg();
55485f757f3fSDimitry Andric   Register Offset = I.getOffsetReg();
55495f757f3fSDimitry Andric   LLT ValTy = MRI.getType(Val);
55505f757f3fSDimitry Andric   assert(ValTy.getSizeInBits() <= 128 && "Unexpected type for indexed store");
55515f757f3fSDimitry Andric 
55525f757f3fSDimitry Andric   unsigned Opc = 0;
55535f757f3fSDimitry Andric   if (I.isPre()) {
55545f757f3fSDimitry Andric     static constexpr unsigned GPROpcodes[] = {
55555f757f3fSDimitry Andric         AArch64::STRBBpre, AArch64::STRHHpre, AArch64::STRWpre,
55565f757f3fSDimitry Andric         AArch64::STRXpre};
55575f757f3fSDimitry Andric     static constexpr unsigned FPROpcodes[] = {
55585f757f3fSDimitry Andric         AArch64::STRBpre, AArch64::STRHpre, AArch64::STRSpre, AArch64::STRDpre,
55595f757f3fSDimitry Andric         AArch64::STRQpre};
55605f757f3fSDimitry Andric 
55615f757f3fSDimitry Andric     if (RBI.getRegBank(Val, MRI, TRI)->getID() == AArch64::FPRRegBankID)
55625f757f3fSDimitry Andric       Opc = FPROpcodes[Log2_32(ValTy.getSizeInBytes())];
55635f757f3fSDimitry Andric     else
55645f757f3fSDimitry Andric       Opc = GPROpcodes[Log2_32(ValTy.getSizeInBytes())];
55655f757f3fSDimitry Andric   } else {
55665f757f3fSDimitry Andric     static constexpr unsigned GPROpcodes[] = {
55675f757f3fSDimitry Andric         AArch64::STRBBpost, AArch64::STRHHpost, AArch64::STRWpost,
55685f757f3fSDimitry Andric         AArch64::STRXpost};
55695f757f3fSDimitry Andric     static constexpr unsigned FPROpcodes[] = {
55705f757f3fSDimitry Andric         AArch64::STRBpost, AArch64::STRHpost, AArch64::STRSpost,
55715f757f3fSDimitry Andric         AArch64::STRDpost, AArch64::STRQpost};
55725f757f3fSDimitry Andric 
55735f757f3fSDimitry Andric     if (RBI.getRegBank(Val, MRI, TRI)->getID() == AArch64::FPRRegBankID)
55745f757f3fSDimitry Andric       Opc = FPROpcodes[Log2_32(ValTy.getSizeInBytes())];
55755f757f3fSDimitry Andric     else
55765f757f3fSDimitry Andric       Opc = GPROpcodes[Log2_32(ValTy.getSizeInBytes())];
55775f757f3fSDimitry Andric   }
55785f757f3fSDimitry Andric 
55795f757f3fSDimitry Andric   auto Cst = getIConstantVRegVal(Offset, MRI);
55805f757f3fSDimitry Andric   if (!Cst)
55815f757f3fSDimitry Andric     return false; // Shouldn't happen, but just in case.
55825f757f3fSDimitry Andric   auto Str =
55835f757f3fSDimitry Andric       MIB.buildInstr(Opc, {Dst}, {Val, Base}).addImm(Cst->getSExtValue());
55845f757f3fSDimitry Andric   Str.cloneMemRefs(I);
55855f757f3fSDimitry Andric   constrainSelectedInstRegOperands(*Str, TII, TRI, RBI);
55865f757f3fSDimitry Andric   I.eraseFromParent();
55875f757f3fSDimitry Andric   return true;
55885f757f3fSDimitry Andric }
55895f757f3fSDimitry Andric 
5590fe6060f1SDimitry Andric MachineInstr *
emitConstantVector(Register Dst,Constant * CV,MachineIRBuilder & MIRBuilder,MachineRegisterInfo & MRI)5591fe6060f1SDimitry Andric AArch64InstructionSelector::emitConstantVector(Register Dst, Constant *CV,
5592fe6060f1SDimitry Andric                                                MachineIRBuilder &MIRBuilder,
5593fe6060f1SDimitry Andric                                                MachineRegisterInfo &MRI) {
5594fe6060f1SDimitry Andric   LLT DstTy = MRI.getType(Dst);
5595fe6060f1SDimitry Andric   unsigned DstSize = DstTy.getSizeInBits();
5596fe6060f1SDimitry Andric   if (CV->isNullValue()) {
5597fe6060f1SDimitry Andric     if (DstSize == 128) {
5598fe6060f1SDimitry Andric       auto Mov =
5599fe6060f1SDimitry Andric           MIRBuilder.buildInstr(AArch64::MOVIv2d_ns, {Dst}, {}).addImm(0);
5600fe6060f1SDimitry Andric       constrainSelectedInstRegOperands(*Mov, TII, TRI, RBI);
5601fe6060f1SDimitry Andric       return &*Mov;
5602fe6060f1SDimitry Andric     }
5603fe6060f1SDimitry Andric 
5604fe6060f1SDimitry Andric     if (DstSize == 64) {
5605fe6060f1SDimitry Andric       auto Mov =
5606fe6060f1SDimitry Andric           MIRBuilder
5607fe6060f1SDimitry Andric               .buildInstr(AArch64::MOVIv2d_ns, {&AArch64::FPR128RegClass}, {})
5608fe6060f1SDimitry Andric               .addImm(0);
5609fe6060f1SDimitry Andric       auto Copy = MIRBuilder.buildInstr(TargetOpcode::COPY, {Dst}, {})
5610fe6060f1SDimitry Andric                       .addReg(Mov.getReg(0), 0, AArch64::dsub);
5611fe6060f1SDimitry Andric       RBI.constrainGenericRegister(Dst, AArch64::FPR64RegClass, MRI);
5612fe6060f1SDimitry Andric       return &*Copy;
5613fe6060f1SDimitry Andric     }
5614fe6060f1SDimitry Andric   }
5615fe6060f1SDimitry Andric 
56165f757f3fSDimitry Andric   if (CV->getSplatValue()) {
56175f757f3fSDimitry Andric     APInt DefBits = APInt::getSplat(DstSize, CV->getUniqueInteger());
5618*0fca6ea1SDimitry Andric     auto TryMOVIWithBits = [&](APInt DefBits) -> MachineInstr * {
56195f757f3fSDimitry Andric       MachineInstr *NewOp;
56205f757f3fSDimitry Andric       bool Inv = false;
56215f757f3fSDimitry Andric       if ((NewOp = tryAdvSIMDModImm64(Dst, DstSize, DefBits, MIRBuilder)) ||
5622*0fca6ea1SDimitry Andric           (NewOp =
5623*0fca6ea1SDimitry Andric                tryAdvSIMDModImm32(Dst, DstSize, DefBits, MIRBuilder, Inv)) ||
56245f757f3fSDimitry Andric           (NewOp =
56255f757f3fSDimitry Andric                tryAdvSIMDModImm321s(Dst, DstSize, DefBits, MIRBuilder, Inv)) ||
5626*0fca6ea1SDimitry Andric           (NewOp =
5627*0fca6ea1SDimitry Andric                tryAdvSIMDModImm16(Dst, DstSize, DefBits, MIRBuilder, Inv)) ||
56285f757f3fSDimitry Andric           (NewOp = tryAdvSIMDModImm8(Dst, DstSize, DefBits, MIRBuilder)) ||
56295f757f3fSDimitry Andric           (NewOp = tryAdvSIMDModImmFP(Dst, DstSize, DefBits, MIRBuilder)))
56305f757f3fSDimitry Andric         return NewOp;
56315f757f3fSDimitry Andric 
56325f757f3fSDimitry Andric       DefBits = ~DefBits;
56335f757f3fSDimitry Andric       Inv = true;
5634*0fca6ea1SDimitry Andric       if ((NewOp =
5635*0fca6ea1SDimitry Andric                tryAdvSIMDModImm32(Dst, DstSize, DefBits, MIRBuilder, Inv)) ||
56365f757f3fSDimitry Andric           (NewOp =
56375f757f3fSDimitry Andric                tryAdvSIMDModImm321s(Dst, DstSize, DefBits, MIRBuilder, Inv)) ||
56385f757f3fSDimitry Andric           (NewOp = tryAdvSIMDModImm16(Dst, DstSize, DefBits, MIRBuilder, Inv)))
56395f757f3fSDimitry Andric         return NewOp;
5640*0fca6ea1SDimitry Andric       return nullptr;
5641*0fca6ea1SDimitry Andric     };
5642*0fca6ea1SDimitry Andric 
5643*0fca6ea1SDimitry Andric     if (auto *NewOp = TryMOVIWithBits(DefBits))
5644*0fca6ea1SDimitry Andric       return NewOp;
5645*0fca6ea1SDimitry Andric 
5646*0fca6ea1SDimitry Andric     // See if a fneg of the constant can be materialized with a MOVI, etc
5647*0fca6ea1SDimitry Andric     auto TryWithFNeg = [&](APInt DefBits, int NumBits,
5648*0fca6ea1SDimitry Andric                            unsigned NegOpc) -> MachineInstr * {
5649*0fca6ea1SDimitry Andric       // FNegate each sub-element of the constant
5650*0fca6ea1SDimitry Andric       APInt Neg = APInt::getHighBitsSet(NumBits, 1).zext(DstSize);
5651*0fca6ea1SDimitry Andric       APInt NegBits(DstSize, 0);
5652*0fca6ea1SDimitry Andric       unsigned NumElts = DstSize / NumBits;
5653*0fca6ea1SDimitry Andric       for (unsigned i = 0; i < NumElts; i++)
5654*0fca6ea1SDimitry Andric         NegBits |= Neg << (NumBits * i);
5655*0fca6ea1SDimitry Andric       NegBits = DefBits ^ NegBits;
5656*0fca6ea1SDimitry Andric 
5657*0fca6ea1SDimitry Andric       // Try to create the new constants with MOVI, and if so generate a fneg
5658*0fca6ea1SDimitry Andric       // for it.
5659*0fca6ea1SDimitry Andric       if (auto *NewOp = TryMOVIWithBits(NegBits)) {
5660*0fca6ea1SDimitry Andric         Register NewDst = MRI.createVirtualRegister(&AArch64::FPR128RegClass);
5661*0fca6ea1SDimitry Andric         NewOp->getOperand(0).setReg(NewDst);
5662*0fca6ea1SDimitry Andric         return MIRBuilder.buildInstr(NegOpc, {Dst}, {NewDst});
5663*0fca6ea1SDimitry Andric       }
5664*0fca6ea1SDimitry Andric       return nullptr;
5665*0fca6ea1SDimitry Andric     };
5666*0fca6ea1SDimitry Andric     MachineInstr *R;
5667*0fca6ea1SDimitry Andric     if ((R = TryWithFNeg(DefBits, 32, AArch64::FNEGv4f32)) ||
5668*0fca6ea1SDimitry Andric         (R = TryWithFNeg(DefBits, 64, AArch64::FNEGv2f64)) ||
5669*0fca6ea1SDimitry Andric         (STI.hasFullFP16() &&
5670*0fca6ea1SDimitry Andric          (R = TryWithFNeg(DefBits, 16, AArch64::FNEGv8f16))))
5671*0fca6ea1SDimitry Andric       return R;
56725f757f3fSDimitry Andric   }
56735f757f3fSDimitry Andric 
5674fe6060f1SDimitry Andric   auto *CPLoad = emitLoadFromConstantPool(CV, MIRBuilder);
5675fe6060f1SDimitry Andric   if (!CPLoad) {
5676fe6060f1SDimitry Andric     LLVM_DEBUG(dbgs() << "Could not generate cp load for constant vector!");
5677fe6060f1SDimitry Andric     return nullptr;
5678fe6060f1SDimitry Andric   }
5679fe6060f1SDimitry Andric 
5680fe6060f1SDimitry Andric   auto Copy = MIRBuilder.buildCopy(Dst, CPLoad->getOperand(0));
5681fe6060f1SDimitry Andric   RBI.constrainGenericRegister(
5682fe6060f1SDimitry Andric       Dst, *MRI.getRegClass(CPLoad->getOperand(0).getReg()), MRI);
5683fe6060f1SDimitry Andric   return &*Copy;
5684fe6060f1SDimitry Andric }
5685fe6060f1SDimitry Andric 
tryOptConstantBuildVec(MachineInstr & I,LLT DstTy,MachineRegisterInfo & MRI)56865ffd83dbSDimitry Andric bool AArch64InstructionSelector::tryOptConstantBuildVec(
5687fe6060f1SDimitry Andric     MachineInstr &I, LLT DstTy, MachineRegisterInfo &MRI) {
56885ffd83dbSDimitry Andric   assert(I.getOpcode() == TargetOpcode::G_BUILD_VECTOR);
5689e8d8bef9SDimitry Andric   unsigned DstSize = DstTy.getSizeInBits();
5690e8d8bef9SDimitry Andric   assert(DstSize <= 128 && "Unexpected build_vec type!");
5691e8d8bef9SDimitry Andric   if (DstSize < 32)
56925ffd83dbSDimitry Andric     return false;
56935ffd83dbSDimitry Andric   // Check if we're building a constant vector, in which case we want to
56945ffd83dbSDimitry Andric   // generate a constant pool load instead of a vector insert sequence.
56955ffd83dbSDimitry Andric   SmallVector<Constant *, 16> Csts;
56965ffd83dbSDimitry Andric   for (unsigned Idx = 1; Idx < I.getNumOperands(); ++Idx) {
56975ffd83dbSDimitry Andric     // Try to find G_CONSTANT or G_FCONSTANT
56985ffd83dbSDimitry Andric     auto *OpMI =
56995ffd83dbSDimitry Andric         getOpcodeDef(TargetOpcode::G_CONSTANT, I.getOperand(Idx).getReg(), MRI);
57005ffd83dbSDimitry Andric     if (OpMI)
57015ffd83dbSDimitry Andric       Csts.emplace_back(
57025ffd83dbSDimitry Andric           const_cast<ConstantInt *>(OpMI->getOperand(1).getCImm()));
57035ffd83dbSDimitry Andric     else if ((OpMI = getOpcodeDef(TargetOpcode::G_FCONSTANT,
57045ffd83dbSDimitry Andric                                   I.getOperand(Idx).getReg(), MRI)))
57055ffd83dbSDimitry Andric       Csts.emplace_back(
57065ffd83dbSDimitry Andric           const_cast<ConstantFP *>(OpMI->getOperand(1).getFPImm()));
57075ffd83dbSDimitry Andric     else
57085ffd83dbSDimitry Andric       return false;
57095ffd83dbSDimitry Andric   }
57105ffd83dbSDimitry Andric   Constant *CV = ConstantVector::get(Csts);
5711fe6060f1SDimitry Andric   if (!emitConstantVector(I.getOperand(0).getReg(), CV, MIB, MRI))
57125ffd83dbSDimitry Andric     return false;
57135ffd83dbSDimitry Andric   I.eraseFromParent();
57145ffd83dbSDimitry Andric   return true;
57155ffd83dbSDimitry Andric }
57165ffd83dbSDimitry Andric 
tryOptBuildVecToSubregToReg(MachineInstr & I,MachineRegisterInfo & MRI)5717349cc55cSDimitry Andric bool AArch64InstructionSelector::tryOptBuildVecToSubregToReg(
5718349cc55cSDimitry Andric     MachineInstr &I, MachineRegisterInfo &MRI) {
5719349cc55cSDimitry Andric   // Given:
5720349cc55cSDimitry Andric   //  %vec = G_BUILD_VECTOR %elt, %undef, %undef, ... %undef
5721349cc55cSDimitry Andric   //
5722349cc55cSDimitry Andric   // Select the G_BUILD_VECTOR as a SUBREG_TO_REG from %elt.
5723349cc55cSDimitry Andric   Register Dst = I.getOperand(0).getReg();
5724349cc55cSDimitry Andric   Register EltReg = I.getOperand(1).getReg();
5725349cc55cSDimitry Andric   LLT EltTy = MRI.getType(EltReg);
5726349cc55cSDimitry Andric   // If the index isn't on the same bank as its elements, then this can't be a
5727349cc55cSDimitry Andric   // SUBREG_TO_REG.
5728349cc55cSDimitry Andric   const RegisterBank &EltRB = *RBI.getRegBank(EltReg, MRI, TRI);
5729349cc55cSDimitry Andric   const RegisterBank &DstRB = *RBI.getRegBank(Dst, MRI, TRI);
5730349cc55cSDimitry Andric   if (EltRB != DstRB)
5731349cc55cSDimitry Andric     return false;
57325f757f3fSDimitry Andric   if (any_of(drop_begin(I.operands(), 2), [&MRI](const MachineOperand &Op) {
57335f757f3fSDimitry Andric         return !getOpcodeDef(TargetOpcode::G_IMPLICIT_DEF, Op.getReg(), MRI);
5734349cc55cSDimitry Andric       }))
5735349cc55cSDimitry Andric     return false;
5736349cc55cSDimitry Andric   unsigned SubReg;
573781ad6265SDimitry Andric   const TargetRegisterClass *EltRC = getRegClassForTypeOnBank(EltTy, EltRB);
5738349cc55cSDimitry Andric   if (!EltRC)
5739349cc55cSDimitry Andric     return false;
5740349cc55cSDimitry Andric   const TargetRegisterClass *DstRC =
574181ad6265SDimitry Andric       getRegClassForTypeOnBank(MRI.getType(Dst), DstRB);
5742349cc55cSDimitry Andric   if (!DstRC)
5743349cc55cSDimitry Andric     return false;
5744349cc55cSDimitry Andric   if (!getSubRegForClass(EltRC, TRI, SubReg))
5745349cc55cSDimitry Andric     return false;
5746349cc55cSDimitry Andric   auto SubregToReg = MIB.buildInstr(AArch64::SUBREG_TO_REG, {Dst}, {})
5747349cc55cSDimitry Andric                          .addImm(0)
5748349cc55cSDimitry Andric                          .addUse(EltReg)
5749349cc55cSDimitry Andric                          .addImm(SubReg);
5750349cc55cSDimitry Andric   I.eraseFromParent();
5751349cc55cSDimitry Andric   constrainSelectedInstRegOperands(*SubregToReg, TII, TRI, RBI);
5752349cc55cSDimitry Andric   return RBI.constrainGenericRegister(Dst, *DstRC, MRI);
5753349cc55cSDimitry Andric }
5754349cc55cSDimitry Andric 
selectBuildVector(MachineInstr & I,MachineRegisterInfo & MRI)5755fe6060f1SDimitry Andric bool AArch64InstructionSelector::selectBuildVector(MachineInstr &I,
5756fe6060f1SDimitry Andric                                                    MachineRegisterInfo &MRI) {
57575ffd83dbSDimitry Andric   assert(I.getOpcode() == TargetOpcode::G_BUILD_VECTOR);
57585ffd83dbSDimitry Andric   // Until we port more of the optimized selections, for now just use a vector
57595ffd83dbSDimitry Andric   // insert sequence.
57605ffd83dbSDimitry Andric   const LLT DstTy = MRI.getType(I.getOperand(0).getReg());
57615ffd83dbSDimitry Andric   const LLT EltTy = MRI.getType(I.getOperand(1).getReg());
57625ffd83dbSDimitry Andric   unsigned EltSize = EltTy.getSizeInBits();
57635ffd83dbSDimitry Andric 
57645ffd83dbSDimitry Andric   if (tryOptConstantBuildVec(I, DstTy, MRI))
57655ffd83dbSDimitry Andric     return true;
5766349cc55cSDimitry Andric   if (tryOptBuildVecToSubregToReg(I, MRI))
5767349cc55cSDimitry Andric     return true;
5768349cc55cSDimitry Andric 
576906c3fb27SDimitry Andric   if (EltSize != 8 && EltSize != 16 && EltSize != 32 && EltSize != 64)
57705ffd83dbSDimitry Andric     return false; // Don't support all element types yet.
57715ffd83dbSDimitry Andric   const RegisterBank &RB = *RBI.getRegBank(I.getOperand(1).getReg(), MRI, TRI);
57725ffd83dbSDimitry Andric 
57735ffd83dbSDimitry Andric   const TargetRegisterClass *DstRC = &AArch64::FPR128RegClass;
57745ffd83dbSDimitry Andric   MachineInstr *ScalarToVec =
57755ffd83dbSDimitry Andric       emitScalarToVector(DstTy.getElementType().getSizeInBits(), DstRC,
5776fe6060f1SDimitry Andric                          I.getOperand(1).getReg(), MIB);
57775ffd83dbSDimitry Andric   if (!ScalarToVec)
57785ffd83dbSDimitry Andric     return false;
57795ffd83dbSDimitry Andric 
57805ffd83dbSDimitry Andric   Register DstVec = ScalarToVec->getOperand(0).getReg();
57815ffd83dbSDimitry Andric   unsigned DstSize = DstTy.getSizeInBits();
57825ffd83dbSDimitry Andric 
57835ffd83dbSDimitry Andric   // Keep track of the last MI we inserted. Later on, we might be able to save
57845ffd83dbSDimitry Andric   // a copy using it.
5785*0fca6ea1SDimitry Andric   MachineInstr *PrevMI = ScalarToVec;
57865ffd83dbSDimitry Andric   for (unsigned i = 2, e = DstSize / EltSize + 1; i < e; ++i) {
57875ffd83dbSDimitry Andric     // Note that if we don't do a subregister copy, we can end up making an
57885ffd83dbSDimitry Andric     // extra register.
5789*0fca6ea1SDimitry Andric     Register OpReg = I.getOperand(i).getReg();
5790*0fca6ea1SDimitry Andric     // Do not emit inserts for undefs
5791*0fca6ea1SDimitry Andric     if (!getOpcodeDef<GImplicitDef>(OpReg, MRI)) {
5792*0fca6ea1SDimitry Andric       PrevMI = &*emitLaneInsert(std::nullopt, DstVec, OpReg, i - 1, RB, MIB);
57935ffd83dbSDimitry Andric       DstVec = PrevMI->getOperand(0).getReg();
57945ffd83dbSDimitry Andric     }
5795*0fca6ea1SDimitry Andric   }
57965ffd83dbSDimitry Andric 
57975ffd83dbSDimitry Andric   // If DstTy's size in bits is less than 128, then emit a subregister copy
57985ffd83dbSDimitry Andric   // from DstVec to the last register we've defined.
57995ffd83dbSDimitry Andric   if (DstSize < 128) {
58005ffd83dbSDimitry Andric     // Force this to be FPR using the destination vector.
58015ffd83dbSDimitry Andric     const TargetRegisterClass *RC =
580281ad6265SDimitry Andric         getRegClassForTypeOnBank(DstTy, *RBI.getRegBank(DstVec, MRI, TRI));
58035ffd83dbSDimitry Andric     if (!RC)
58045ffd83dbSDimitry Andric       return false;
58055ffd83dbSDimitry Andric     if (RC != &AArch64::FPR32RegClass && RC != &AArch64::FPR64RegClass) {
58065ffd83dbSDimitry Andric       LLVM_DEBUG(dbgs() << "Unsupported register class!\n");
58075ffd83dbSDimitry Andric       return false;
58085ffd83dbSDimitry Andric     }
58095ffd83dbSDimitry Andric 
58105ffd83dbSDimitry Andric     unsigned SubReg = 0;
58115ffd83dbSDimitry Andric     if (!getSubRegForClass(RC, TRI, SubReg))
58125ffd83dbSDimitry Andric       return false;
58135ffd83dbSDimitry Andric     if (SubReg != AArch64::ssub && SubReg != AArch64::dsub) {
58145ffd83dbSDimitry Andric       LLVM_DEBUG(dbgs() << "Unsupported destination size! (" << DstSize
58155ffd83dbSDimitry Andric                         << "\n");
58165ffd83dbSDimitry Andric       return false;
58175ffd83dbSDimitry Andric     }
58185ffd83dbSDimitry Andric 
58195ffd83dbSDimitry Andric     Register Reg = MRI.createVirtualRegister(RC);
58205ffd83dbSDimitry Andric     Register DstReg = I.getOperand(0).getReg();
58215ffd83dbSDimitry Andric 
5822fe6060f1SDimitry Andric     MIB.buildInstr(TargetOpcode::COPY, {DstReg}, {}).addReg(DstVec, 0, SubReg);
58235ffd83dbSDimitry Andric     MachineOperand &RegOp = I.getOperand(1);
58245ffd83dbSDimitry Andric     RegOp.setReg(Reg);
58255ffd83dbSDimitry Andric     RBI.constrainGenericRegister(DstReg, *RC, MRI);
58265ffd83dbSDimitry Andric   } else {
5827*0fca6ea1SDimitry Andric     // We either have a vector with all elements (except the first one) undef or
5828*0fca6ea1SDimitry Andric     // at least one non-undef non-first element. In the first case, we need to
5829*0fca6ea1SDimitry Andric     // constrain the output register ourselves as we may have generated an
5830*0fca6ea1SDimitry Andric     // INSERT_SUBREG operation which is a generic operation for which the
5831*0fca6ea1SDimitry Andric     // output regclass cannot be automatically chosen.
5832*0fca6ea1SDimitry Andric     //
5833*0fca6ea1SDimitry Andric     // In the second case, there is no need to do this as it may generate an
5834*0fca6ea1SDimitry Andric     // instruction like INSvi32gpr where the regclass can be automatically
5835*0fca6ea1SDimitry Andric     // chosen.
5836*0fca6ea1SDimitry Andric     //
5837*0fca6ea1SDimitry Andric     // Also, we save a copy by re-using the destination register on the final
5838*0fca6ea1SDimitry Andric     // insert.
58395ffd83dbSDimitry Andric     PrevMI->getOperand(0).setReg(I.getOperand(0).getReg());
58405ffd83dbSDimitry Andric     constrainSelectedInstRegOperands(*PrevMI, TII, TRI, RBI);
5841*0fca6ea1SDimitry Andric 
5842*0fca6ea1SDimitry Andric     Register DstReg = PrevMI->getOperand(0).getReg();
5843*0fca6ea1SDimitry Andric     if (PrevMI == ScalarToVec && DstReg.isVirtual()) {
5844*0fca6ea1SDimitry Andric       const TargetRegisterClass *RC =
5845*0fca6ea1SDimitry Andric           getRegClassForTypeOnBank(DstTy, *RBI.getRegBank(DstVec, MRI, TRI));
5846*0fca6ea1SDimitry Andric       RBI.constrainGenericRegister(DstReg, *RC, MRI);
5847*0fca6ea1SDimitry Andric     }
58485ffd83dbSDimitry Andric   }
58495ffd83dbSDimitry Andric 
58505ffd83dbSDimitry Andric   I.eraseFromParent();
58515ffd83dbSDimitry Andric   return true;
58525ffd83dbSDimitry Andric }
58535ffd83dbSDimitry Andric 
selectVectorLoadIntrinsic(unsigned Opc,unsigned NumVecs,MachineInstr & I)5854349cc55cSDimitry Andric bool AArch64InstructionSelector::selectVectorLoadIntrinsic(unsigned Opc,
5855349cc55cSDimitry Andric                                                            unsigned NumVecs,
5856349cc55cSDimitry Andric                                                            MachineInstr &I) {
5857349cc55cSDimitry Andric   assert(I.getOpcode() == TargetOpcode::G_INTRINSIC_W_SIDE_EFFECTS);
5858349cc55cSDimitry Andric   assert(Opc && "Expected an opcode?");
5859349cc55cSDimitry Andric   assert(NumVecs > 1 && NumVecs < 5 && "Only support 2, 3, or 4 vectors");
5860349cc55cSDimitry Andric   auto &MRI = *MIB.getMRI();
5861349cc55cSDimitry Andric   LLT Ty = MRI.getType(I.getOperand(0).getReg());
5862349cc55cSDimitry Andric   unsigned Size = Ty.getSizeInBits();
5863349cc55cSDimitry Andric   assert((Size == 64 || Size == 128) &&
5864349cc55cSDimitry Andric          "Destination must be 64 bits or 128 bits?");
5865349cc55cSDimitry Andric   unsigned SubReg = Size == 64 ? AArch64::dsub0 : AArch64::qsub0;
5866349cc55cSDimitry Andric   auto Ptr = I.getOperand(I.getNumOperands() - 1).getReg();
5867349cc55cSDimitry Andric   assert(MRI.getType(Ptr).isPointer() && "Expected a pointer type?");
5868349cc55cSDimitry Andric   auto Load = MIB.buildInstr(Opc, {Ty}, {Ptr});
5869349cc55cSDimitry Andric   Load.cloneMemRefs(I);
5870349cc55cSDimitry Andric   constrainSelectedInstRegOperands(*Load, TII, TRI, RBI);
5871349cc55cSDimitry Andric   Register SelectedLoadDst = Load->getOperand(0).getReg();
5872349cc55cSDimitry Andric   for (unsigned Idx = 0; Idx < NumVecs; ++Idx) {
5873349cc55cSDimitry Andric     auto Vec = MIB.buildInstr(TargetOpcode::COPY, {I.getOperand(Idx)}, {})
5874349cc55cSDimitry Andric                    .addReg(SelectedLoadDst, 0, SubReg + Idx);
5875349cc55cSDimitry Andric     // Emit the subreg copies and immediately select them.
5876349cc55cSDimitry Andric     // FIXME: We should refactor our copy code into an emitCopy helper and
5877349cc55cSDimitry Andric     // clean up uses of this pattern elsewhere in the selector.
5878349cc55cSDimitry Andric     selectCopy(*Vec, TII, MRI, TRI, RBI);
5879349cc55cSDimitry Andric   }
5880349cc55cSDimitry Andric   return true;
58815ffd83dbSDimitry Andric }
58825ffd83dbSDimitry Andric 
selectVectorLoadLaneIntrinsic(unsigned Opc,unsigned NumVecs,MachineInstr & I)58835f757f3fSDimitry Andric bool AArch64InstructionSelector::selectVectorLoadLaneIntrinsic(
58845f757f3fSDimitry Andric     unsigned Opc, unsigned NumVecs, MachineInstr &I) {
58855f757f3fSDimitry Andric   assert(I.getOpcode() == TargetOpcode::G_INTRINSIC_W_SIDE_EFFECTS);
58865f757f3fSDimitry Andric   assert(Opc && "Expected an opcode?");
58875f757f3fSDimitry Andric   assert(NumVecs > 1 && NumVecs < 5 && "Only support 2, 3, or 4 vectors");
58885f757f3fSDimitry Andric   auto &MRI = *MIB.getMRI();
58895f757f3fSDimitry Andric   LLT Ty = MRI.getType(I.getOperand(0).getReg());
58905f757f3fSDimitry Andric   bool Narrow = Ty.getSizeInBits() == 64;
58915f757f3fSDimitry Andric 
58925f757f3fSDimitry Andric   auto FirstSrcRegIt = I.operands_begin() + NumVecs + 1;
58935f757f3fSDimitry Andric   SmallVector<Register, 4> Regs(NumVecs);
58945f757f3fSDimitry Andric   std::transform(FirstSrcRegIt, FirstSrcRegIt + NumVecs, Regs.begin(),
58955f757f3fSDimitry Andric                  [](auto MO) { return MO.getReg(); });
58965f757f3fSDimitry Andric 
58975f757f3fSDimitry Andric   if (Narrow) {
58985f757f3fSDimitry Andric     transform(Regs, Regs.begin(), [this](Register Reg) {
58995f757f3fSDimitry Andric       return emitScalarToVector(64, &AArch64::FPR128RegClass, Reg, MIB)
59005f757f3fSDimitry Andric           ->getOperand(0)
59015f757f3fSDimitry Andric           .getReg();
59025f757f3fSDimitry Andric     });
59035f757f3fSDimitry Andric     Ty = Ty.multiplyElements(2);
59045f757f3fSDimitry Andric   }
59055f757f3fSDimitry Andric 
59065f757f3fSDimitry Andric   Register Tuple = createQTuple(Regs, MIB);
59075f757f3fSDimitry Andric   auto LaneNo = getIConstantVRegVal((FirstSrcRegIt + NumVecs)->getReg(), MRI);
59085f757f3fSDimitry Andric   if (!LaneNo)
59095f757f3fSDimitry Andric     return false;
59105f757f3fSDimitry Andric 
59115f757f3fSDimitry Andric   Register Ptr = (FirstSrcRegIt + NumVecs + 1)->getReg();
59125f757f3fSDimitry Andric   auto Load = MIB.buildInstr(Opc, {Ty}, {})
59135f757f3fSDimitry Andric                   .addReg(Tuple)
59145f757f3fSDimitry Andric                   .addImm(LaneNo->getZExtValue())
59155f757f3fSDimitry Andric                   .addReg(Ptr);
59165f757f3fSDimitry Andric   Load.cloneMemRefs(I);
59175f757f3fSDimitry Andric   constrainSelectedInstRegOperands(*Load, TII, TRI, RBI);
59185f757f3fSDimitry Andric   Register SelectedLoadDst = Load->getOperand(0).getReg();
59195f757f3fSDimitry Andric   unsigned SubReg = AArch64::qsub0;
59205f757f3fSDimitry Andric   for (unsigned Idx = 0; Idx < NumVecs; ++Idx) {
59215f757f3fSDimitry Andric     auto Vec = MIB.buildInstr(TargetOpcode::COPY,
59225f757f3fSDimitry Andric                               {Narrow ? DstOp(&AArch64::FPR128RegClass)
59235f757f3fSDimitry Andric                                       : DstOp(I.getOperand(Idx).getReg())},
59245f757f3fSDimitry Andric                               {})
59255f757f3fSDimitry Andric                    .addReg(SelectedLoadDst, 0, SubReg + Idx);
59265f757f3fSDimitry Andric     Register WideReg = Vec.getReg(0);
59275f757f3fSDimitry Andric     // Emit the subreg copies and immediately select them.
59285f757f3fSDimitry Andric     selectCopy(*Vec, TII, MRI, TRI, RBI);
59295f757f3fSDimitry Andric     if (Narrow &&
59305f757f3fSDimitry Andric         !emitNarrowVector(I.getOperand(Idx).getReg(), WideReg, MIB, MRI))
59315f757f3fSDimitry Andric       return false;
59325f757f3fSDimitry Andric   }
59335f757f3fSDimitry Andric   return true;
59345f757f3fSDimitry Andric }
59355f757f3fSDimitry Andric 
selectVectorStoreIntrinsic(MachineInstr & I,unsigned NumVecs,unsigned Opc)59365f757f3fSDimitry Andric void AArch64InstructionSelector::selectVectorStoreIntrinsic(MachineInstr &I,
59375f757f3fSDimitry Andric                                                             unsigned NumVecs,
59385f757f3fSDimitry Andric                                                             unsigned Opc) {
59395f757f3fSDimitry Andric   MachineRegisterInfo &MRI = I.getParent()->getParent()->getRegInfo();
59405f757f3fSDimitry Andric   LLT Ty = MRI.getType(I.getOperand(1).getReg());
59415f757f3fSDimitry Andric   Register Ptr = I.getOperand(1 + NumVecs).getReg();
59425f757f3fSDimitry Andric 
59435f757f3fSDimitry Andric   SmallVector<Register, 2> Regs(NumVecs);
59445f757f3fSDimitry Andric   std::transform(I.operands_begin() + 1, I.operands_begin() + 1 + NumVecs,
59455f757f3fSDimitry Andric                  Regs.begin(), [](auto MO) { return MO.getReg(); });
59465f757f3fSDimitry Andric 
59475f757f3fSDimitry Andric   Register Tuple = Ty.getSizeInBits() == 128 ? createQTuple(Regs, MIB)
59485f757f3fSDimitry Andric                                              : createDTuple(Regs, MIB);
59495f757f3fSDimitry Andric   auto Store = MIB.buildInstr(Opc, {}, {Tuple, Ptr});
59505f757f3fSDimitry Andric   Store.cloneMemRefs(I);
59515f757f3fSDimitry Andric   constrainSelectedInstRegOperands(*Store, TII, TRI, RBI);
59525f757f3fSDimitry Andric }
59535f757f3fSDimitry Andric 
selectVectorStoreLaneIntrinsic(MachineInstr & I,unsigned NumVecs,unsigned Opc)59545f757f3fSDimitry Andric bool AArch64InstructionSelector::selectVectorStoreLaneIntrinsic(
59555f757f3fSDimitry Andric     MachineInstr &I, unsigned NumVecs, unsigned Opc) {
59565f757f3fSDimitry Andric   MachineRegisterInfo &MRI = I.getParent()->getParent()->getRegInfo();
59575f757f3fSDimitry Andric   LLT Ty = MRI.getType(I.getOperand(1).getReg());
59585f757f3fSDimitry Andric   bool Narrow = Ty.getSizeInBits() == 64;
59595f757f3fSDimitry Andric 
59605f757f3fSDimitry Andric   SmallVector<Register, 2> Regs(NumVecs);
59615f757f3fSDimitry Andric   std::transform(I.operands_begin() + 1, I.operands_begin() + 1 + NumVecs,
59625f757f3fSDimitry Andric                  Regs.begin(), [](auto MO) { return MO.getReg(); });
59635f757f3fSDimitry Andric 
59645f757f3fSDimitry Andric   if (Narrow)
59655f757f3fSDimitry Andric     transform(Regs, Regs.begin(), [this](Register Reg) {
59665f757f3fSDimitry Andric       return emitScalarToVector(64, &AArch64::FPR128RegClass, Reg, MIB)
59675f757f3fSDimitry Andric           ->getOperand(0)
59685f757f3fSDimitry Andric           .getReg();
59695f757f3fSDimitry Andric     });
59705f757f3fSDimitry Andric 
59715f757f3fSDimitry Andric   Register Tuple = createQTuple(Regs, MIB);
59725f757f3fSDimitry Andric 
59735f757f3fSDimitry Andric   auto LaneNo = getIConstantVRegVal(I.getOperand(1 + NumVecs).getReg(), MRI);
59745f757f3fSDimitry Andric   if (!LaneNo)
59755f757f3fSDimitry Andric     return false;
59765f757f3fSDimitry Andric   Register Ptr = I.getOperand(1 + NumVecs + 1).getReg();
59775f757f3fSDimitry Andric   auto Store = MIB.buildInstr(Opc, {}, {})
59785f757f3fSDimitry Andric                    .addReg(Tuple)
59795f757f3fSDimitry Andric                    .addImm(LaneNo->getZExtValue())
59805f757f3fSDimitry Andric                    .addReg(Ptr);
59815f757f3fSDimitry Andric   Store.cloneMemRefs(I);
59825f757f3fSDimitry Andric   constrainSelectedInstRegOperands(*Store, TII, TRI, RBI);
59835f757f3fSDimitry Andric   return true;
59845f757f3fSDimitry Andric }
59855f757f3fSDimitry Andric 
selectIntrinsicWithSideEffects(MachineInstr & I,MachineRegisterInfo & MRI)59865ffd83dbSDimitry Andric bool AArch64InstructionSelector::selectIntrinsicWithSideEffects(
5987fe6060f1SDimitry Andric     MachineInstr &I, MachineRegisterInfo &MRI) {
59885ffd83dbSDimitry Andric   // Find the intrinsic ID.
59895f757f3fSDimitry Andric   unsigned IntrinID = cast<GIntrinsic>(I).getIntrinsicID();
59905ffd83dbSDimitry Andric 
5991349cc55cSDimitry Andric   const LLT S8 = LLT::scalar(8);
5992349cc55cSDimitry Andric   const LLT S16 = LLT::scalar(16);
5993349cc55cSDimitry Andric   const LLT S32 = LLT::scalar(32);
5994349cc55cSDimitry Andric   const LLT S64 = LLT::scalar(64);
5995349cc55cSDimitry Andric   const LLT P0 = LLT::pointer(0, 64);
59965ffd83dbSDimitry Andric   // Select the instruction.
59975ffd83dbSDimitry Andric   switch (IntrinID) {
59985ffd83dbSDimitry Andric   default:
59995ffd83dbSDimitry Andric     return false;
6000fe6060f1SDimitry Andric   case Intrinsic::aarch64_ldxp:
6001fe6060f1SDimitry Andric   case Intrinsic::aarch64_ldaxp: {
6002fe6060f1SDimitry Andric     auto NewI = MIB.buildInstr(
6003fe6060f1SDimitry Andric         IntrinID == Intrinsic::aarch64_ldxp ? AArch64::LDXPX : AArch64::LDAXPX,
6004fe6060f1SDimitry Andric         {I.getOperand(0).getReg(), I.getOperand(1).getReg()},
6005fe6060f1SDimitry Andric         {I.getOperand(3)});
6006fe6060f1SDimitry Andric     NewI.cloneMemRefs(I);
6007fe6060f1SDimitry Andric     constrainSelectedInstRegOperands(*NewI, TII, TRI, RBI);
6008fe6060f1SDimitry Andric     break;
6009fe6060f1SDimitry Andric   }
60105f757f3fSDimitry Andric   case Intrinsic::aarch64_neon_ld1x2: {
60115f757f3fSDimitry Andric     LLT Ty = MRI.getType(I.getOperand(0).getReg());
60125f757f3fSDimitry Andric     unsigned Opc = 0;
60135f757f3fSDimitry Andric     if (Ty == LLT::fixed_vector(8, S8))
60145f757f3fSDimitry Andric       Opc = AArch64::LD1Twov8b;
60155f757f3fSDimitry Andric     else if (Ty == LLT::fixed_vector(16, S8))
60165f757f3fSDimitry Andric       Opc = AArch64::LD1Twov16b;
60175f757f3fSDimitry Andric     else if (Ty == LLT::fixed_vector(4, S16))
60185f757f3fSDimitry Andric       Opc = AArch64::LD1Twov4h;
60195f757f3fSDimitry Andric     else if (Ty == LLT::fixed_vector(8, S16))
60205f757f3fSDimitry Andric       Opc = AArch64::LD1Twov8h;
60215f757f3fSDimitry Andric     else if (Ty == LLT::fixed_vector(2, S32))
60225f757f3fSDimitry Andric       Opc = AArch64::LD1Twov2s;
60235f757f3fSDimitry Andric     else if (Ty == LLT::fixed_vector(4, S32))
60245f757f3fSDimitry Andric       Opc = AArch64::LD1Twov4s;
60255f757f3fSDimitry Andric     else if (Ty == LLT::fixed_vector(2, S64) || Ty == LLT::fixed_vector(2, P0))
60265f757f3fSDimitry Andric       Opc = AArch64::LD1Twov2d;
60275f757f3fSDimitry Andric     else if (Ty == S64 || Ty == P0)
60285f757f3fSDimitry Andric       Opc = AArch64::LD1Twov1d;
60295f757f3fSDimitry Andric     else
60305f757f3fSDimitry Andric       llvm_unreachable("Unexpected type for ld1x2!");
60315f757f3fSDimitry Andric     selectVectorLoadIntrinsic(Opc, 2, I);
60325f757f3fSDimitry Andric     break;
60335f757f3fSDimitry Andric   }
60345f757f3fSDimitry Andric   case Intrinsic::aarch64_neon_ld1x3: {
60355f757f3fSDimitry Andric     LLT Ty = MRI.getType(I.getOperand(0).getReg());
60365f757f3fSDimitry Andric     unsigned Opc = 0;
60375f757f3fSDimitry Andric     if (Ty == LLT::fixed_vector(8, S8))
60385f757f3fSDimitry Andric       Opc = AArch64::LD1Threev8b;
60395f757f3fSDimitry Andric     else if (Ty == LLT::fixed_vector(16, S8))
60405f757f3fSDimitry Andric       Opc = AArch64::LD1Threev16b;
60415f757f3fSDimitry Andric     else if (Ty == LLT::fixed_vector(4, S16))
60425f757f3fSDimitry Andric       Opc = AArch64::LD1Threev4h;
60435f757f3fSDimitry Andric     else if (Ty == LLT::fixed_vector(8, S16))
60445f757f3fSDimitry Andric       Opc = AArch64::LD1Threev8h;
60455f757f3fSDimitry Andric     else if (Ty == LLT::fixed_vector(2, S32))
60465f757f3fSDimitry Andric       Opc = AArch64::LD1Threev2s;
60475f757f3fSDimitry Andric     else if (Ty == LLT::fixed_vector(4, S32))
60485f757f3fSDimitry Andric       Opc = AArch64::LD1Threev4s;
60495f757f3fSDimitry Andric     else if (Ty == LLT::fixed_vector(2, S64) || Ty == LLT::fixed_vector(2, P0))
60505f757f3fSDimitry Andric       Opc = AArch64::LD1Threev2d;
60515f757f3fSDimitry Andric     else if (Ty == S64 || Ty == P0)
60525f757f3fSDimitry Andric       Opc = AArch64::LD1Threev1d;
60535f757f3fSDimitry Andric     else
60545f757f3fSDimitry Andric       llvm_unreachable("Unexpected type for ld1x3!");
60555f757f3fSDimitry Andric     selectVectorLoadIntrinsic(Opc, 3, I);
60565f757f3fSDimitry Andric     break;
60575f757f3fSDimitry Andric   }
60585f757f3fSDimitry Andric   case Intrinsic::aarch64_neon_ld1x4: {
60595f757f3fSDimitry Andric     LLT Ty = MRI.getType(I.getOperand(0).getReg());
60605f757f3fSDimitry Andric     unsigned Opc = 0;
60615f757f3fSDimitry Andric     if (Ty == LLT::fixed_vector(8, S8))
60625f757f3fSDimitry Andric       Opc = AArch64::LD1Fourv8b;
60635f757f3fSDimitry Andric     else if (Ty == LLT::fixed_vector(16, S8))
60645f757f3fSDimitry Andric       Opc = AArch64::LD1Fourv16b;
60655f757f3fSDimitry Andric     else if (Ty == LLT::fixed_vector(4, S16))
60665f757f3fSDimitry Andric       Opc = AArch64::LD1Fourv4h;
60675f757f3fSDimitry Andric     else if (Ty == LLT::fixed_vector(8, S16))
60685f757f3fSDimitry Andric       Opc = AArch64::LD1Fourv8h;
60695f757f3fSDimitry Andric     else if (Ty == LLT::fixed_vector(2, S32))
60705f757f3fSDimitry Andric       Opc = AArch64::LD1Fourv2s;
60715f757f3fSDimitry Andric     else if (Ty == LLT::fixed_vector(4, S32))
60725f757f3fSDimitry Andric       Opc = AArch64::LD1Fourv4s;
60735f757f3fSDimitry Andric     else if (Ty == LLT::fixed_vector(2, S64) || Ty == LLT::fixed_vector(2, P0))
60745f757f3fSDimitry Andric       Opc = AArch64::LD1Fourv2d;
60755f757f3fSDimitry Andric     else if (Ty == S64 || Ty == P0)
60765f757f3fSDimitry Andric       Opc = AArch64::LD1Fourv1d;
60775f757f3fSDimitry Andric     else
60785f757f3fSDimitry Andric       llvm_unreachable("Unexpected type for ld1x4!");
60795f757f3fSDimitry Andric     selectVectorLoadIntrinsic(Opc, 4, I);
60805f757f3fSDimitry Andric     break;
60815f757f3fSDimitry Andric   }
6082349cc55cSDimitry Andric   case Intrinsic::aarch64_neon_ld2: {
6083349cc55cSDimitry Andric     LLT Ty = MRI.getType(I.getOperand(0).getReg());
6084349cc55cSDimitry Andric     unsigned Opc = 0;
6085349cc55cSDimitry Andric     if (Ty == LLT::fixed_vector(8, S8))
6086349cc55cSDimitry Andric       Opc = AArch64::LD2Twov8b;
6087349cc55cSDimitry Andric     else if (Ty == LLT::fixed_vector(16, S8))
6088349cc55cSDimitry Andric       Opc = AArch64::LD2Twov16b;
6089349cc55cSDimitry Andric     else if (Ty == LLT::fixed_vector(4, S16))
6090349cc55cSDimitry Andric       Opc = AArch64::LD2Twov4h;
6091349cc55cSDimitry Andric     else if (Ty == LLT::fixed_vector(8, S16))
6092349cc55cSDimitry Andric       Opc = AArch64::LD2Twov8h;
6093349cc55cSDimitry Andric     else if (Ty == LLT::fixed_vector(2, S32))
6094349cc55cSDimitry Andric       Opc = AArch64::LD2Twov2s;
6095349cc55cSDimitry Andric     else if (Ty == LLT::fixed_vector(4, S32))
6096349cc55cSDimitry Andric       Opc = AArch64::LD2Twov4s;
6097349cc55cSDimitry Andric     else if (Ty == LLT::fixed_vector(2, S64) || Ty == LLT::fixed_vector(2, P0))
6098349cc55cSDimitry Andric       Opc = AArch64::LD2Twov2d;
6099349cc55cSDimitry Andric     else if (Ty == S64 || Ty == P0)
6100349cc55cSDimitry Andric       Opc = AArch64::LD1Twov1d;
6101349cc55cSDimitry Andric     else
6102349cc55cSDimitry Andric       llvm_unreachable("Unexpected type for ld2!");
6103349cc55cSDimitry Andric     selectVectorLoadIntrinsic(Opc, 2, I);
6104349cc55cSDimitry Andric     break;
6105349cc55cSDimitry Andric   }
61065f757f3fSDimitry Andric   case Intrinsic::aarch64_neon_ld2lane: {
61075f757f3fSDimitry Andric     LLT Ty = MRI.getType(I.getOperand(0).getReg());
61085f757f3fSDimitry Andric     unsigned Opc;
61095f757f3fSDimitry Andric     if (Ty == LLT::fixed_vector(8, S8) || Ty == LLT::fixed_vector(16, S8))
61105f757f3fSDimitry Andric       Opc = AArch64::LD2i8;
61115f757f3fSDimitry Andric     else if (Ty == LLT::fixed_vector(4, S16) || Ty == LLT::fixed_vector(8, S16))
61125f757f3fSDimitry Andric       Opc = AArch64::LD2i16;
61135f757f3fSDimitry Andric     else if (Ty == LLT::fixed_vector(2, S32) || Ty == LLT::fixed_vector(4, S32))
61145f757f3fSDimitry Andric       Opc = AArch64::LD2i32;
61155f757f3fSDimitry Andric     else if (Ty == LLT::fixed_vector(2, S64) ||
61165f757f3fSDimitry Andric              Ty == LLT::fixed_vector(2, P0) || Ty == S64 || Ty == P0)
61175f757f3fSDimitry Andric       Opc = AArch64::LD2i64;
61185f757f3fSDimitry Andric     else
61195f757f3fSDimitry Andric       llvm_unreachable("Unexpected type for st2lane!");
61205f757f3fSDimitry Andric     if (!selectVectorLoadLaneIntrinsic(Opc, 2, I))
61215f757f3fSDimitry Andric       return false;
61225f757f3fSDimitry Andric     break;
61235f757f3fSDimitry Andric   }
61245f757f3fSDimitry Andric   case Intrinsic::aarch64_neon_ld2r: {
61255f757f3fSDimitry Andric     LLT Ty = MRI.getType(I.getOperand(0).getReg());
61265f757f3fSDimitry Andric     unsigned Opc = 0;
61275f757f3fSDimitry Andric     if (Ty == LLT::fixed_vector(8, S8))
61285f757f3fSDimitry Andric       Opc = AArch64::LD2Rv8b;
61295f757f3fSDimitry Andric     else if (Ty == LLT::fixed_vector(16, S8))
61305f757f3fSDimitry Andric       Opc = AArch64::LD2Rv16b;
61315f757f3fSDimitry Andric     else if (Ty == LLT::fixed_vector(4, S16))
61325f757f3fSDimitry Andric       Opc = AArch64::LD2Rv4h;
61335f757f3fSDimitry Andric     else if (Ty == LLT::fixed_vector(8, S16))
61345f757f3fSDimitry Andric       Opc = AArch64::LD2Rv8h;
61355f757f3fSDimitry Andric     else if (Ty == LLT::fixed_vector(2, S32))
61365f757f3fSDimitry Andric       Opc = AArch64::LD2Rv2s;
61375f757f3fSDimitry Andric     else if (Ty == LLT::fixed_vector(4, S32))
61385f757f3fSDimitry Andric       Opc = AArch64::LD2Rv4s;
61395f757f3fSDimitry Andric     else if (Ty == LLT::fixed_vector(2, S64) || Ty == LLT::fixed_vector(2, P0))
61405f757f3fSDimitry Andric       Opc = AArch64::LD2Rv2d;
61415f757f3fSDimitry Andric     else if (Ty == S64 || Ty == P0)
61425f757f3fSDimitry Andric       Opc = AArch64::LD2Rv1d;
61435f757f3fSDimitry Andric     else
61445f757f3fSDimitry Andric       llvm_unreachable("Unexpected type for ld2r!");
61455f757f3fSDimitry Andric     selectVectorLoadIntrinsic(Opc, 2, I);
61465f757f3fSDimitry Andric     break;
61475f757f3fSDimitry Andric   }
61485f757f3fSDimitry Andric   case Intrinsic::aarch64_neon_ld3: {
61495f757f3fSDimitry Andric     LLT Ty = MRI.getType(I.getOperand(0).getReg());
61505f757f3fSDimitry Andric     unsigned Opc = 0;
61515f757f3fSDimitry Andric     if (Ty == LLT::fixed_vector(8, S8))
61525f757f3fSDimitry Andric       Opc = AArch64::LD3Threev8b;
61535f757f3fSDimitry Andric     else if (Ty == LLT::fixed_vector(16, S8))
61545f757f3fSDimitry Andric       Opc = AArch64::LD3Threev16b;
61555f757f3fSDimitry Andric     else if (Ty == LLT::fixed_vector(4, S16))
61565f757f3fSDimitry Andric       Opc = AArch64::LD3Threev4h;
61575f757f3fSDimitry Andric     else if (Ty == LLT::fixed_vector(8, S16))
61585f757f3fSDimitry Andric       Opc = AArch64::LD3Threev8h;
61595f757f3fSDimitry Andric     else if (Ty == LLT::fixed_vector(2, S32))
61605f757f3fSDimitry Andric       Opc = AArch64::LD3Threev2s;
61615f757f3fSDimitry Andric     else if (Ty == LLT::fixed_vector(4, S32))
61625f757f3fSDimitry Andric       Opc = AArch64::LD3Threev4s;
61635f757f3fSDimitry Andric     else if (Ty == LLT::fixed_vector(2, S64) || Ty == LLT::fixed_vector(2, P0))
61645f757f3fSDimitry Andric       Opc = AArch64::LD3Threev2d;
61655f757f3fSDimitry Andric     else if (Ty == S64 || Ty == P0)
61665f757f3fSDimitry Andric       Opc = AArch64::LD1Threev1d;
61675f757f3fSDimitry Andric     else
61685f757f3fSDimitry Andric       llvm_unreachable("Unexpected type for ld3!");
61695f757f3fSDimitry Andric     selectVectorLoadIntrinsic(Opc, 3, I);
61705f757f3fSDimitry Andric     break;
61715f757f3fSDimitry Andric   }
61725f757f3fSDimitry Andric   case Intrinsic::aarch64_neon_ld3lane: {
61735f757f3fSDimitry Andric     LLT Ty = MRI.getType(I.getOperand(0).getReg());
61745f757f3fSDimitry Andric     unsigned Opc;
61755f757f3fSDimitry Andric     if (Ty == LLT::fixed_vector(8, S8) || Ty == LLT::fixed_vector(16, S8))
61765f757f3fSDimitry Andric       Opc = AArch64::LD3i8;
61775f757f3fSDimitry Andric     else if (Ty == LLT::fixed_vector(4, S16) || Ty == LLT::fixed_vector(8, S16))
61785f757f3fSDimitry Andric       Opc = AArch64::LD3i16;
61795f757f3fSDimitry Andric     else if (Ty == LLT::fixed_vector(2, S32) || Ty == LLT::fixed_vector(4, S32))
61805f757f3fSDimitry Andric       Opc = AArch64::LD3i32;
61815f757f3fSDimitry Andric     else if (Ty == LLT::fixed_vector(2, S64) ||
61825f757f3fSDimitry Andric              Ty == LLT::fixed_vector(2, P0) || Ty == S64 || Ty == P0)
61835f757f3fSDimitry Andric       Opc = AArch64::LD3i64;
61845f757f3fSDimitry Andric     else
61855f757f3fSDimitry Andric       llvm_unreachable("Unexpected type for st3lane!");
61865f757f3fSDimitry Andric     if (!selectVectorLoadLaneIntrinsic(Opc, 3, I))
61875f757f3fSDimitry Andric       return false;
61885f757f3fSDimitry Andric     break;
61895f757f3fSDimitry Andric   }
61905f757f3fSDimitry Andric   case Intrinsic::aarch64_neon_ld3r: {
61915f757f3fSDimitry Andric     LLT Ty = MRI.getType(I.getOperand(0).getReg());
61925f757f3fSDimitry Andric     unsigned Opc = 0;
61935f757f3fSDimitry Andric     if (Ty == LLT::fixed_vector(8, S8))
61945f757f3fSDimitry Andric       Opc = AArch64::LD3Rv8b;
61955f757f3fSDimitry Andric     else if (Ty == LLT::fixed_vector(16, S8))
61965f757f3fSDimitry Andric       Opc = AArch64::LD3Rv16b;
61975f757f3fSDimitry Andric     else if (Ty == LLT::fixed_vector(4, S16))
61985f757f3fSDimitry Andric       Opc = AArch64::LD3Rv4h;
61995f757f3fSDimitry Andric     else if (Ty == LLT::fixed_vector(8, S16))
62005f757f3fSDimitry Andric       Opc = AArch64::LD3Rv8h;
62015f757f3fSDimitry Andric     else if (Ty == LLT::fixed_vector(2, S32))
62025f757f3fSDimitry Andric       Opc = AArch64::LD3Rv2s;
62035f757f3fSDimitry Andric     else if (Ty == LLT::fixed_vector(4, S32))
62045f757f3fSDimitry Andric       Opc = AArch64::LD3Rv4s;
62055f757f3fSDimitry Andric     else if (Ty == LLT::fixed_vector(2, S64) || Ty == LLT::fixed_vector(2, P0))
62065f757f3fSDimitry Andric       Opc = AArch64::LD3Rv2d;
62075f757f3fSDimitry Andric     else if (Ty == S64 || Ty == P0)
62085f757f3fSDimitry Andric       Opc = AArch64::LD3Rv1d;
62095f757f3fSDimitry Andric     else
62105f757f3fSDimitry Andric       llvm_unreachable("Unexpected type for ld3r!");
62115f757f3fSDimitry Andric     selectVectorLoadIntrinsic(Opc, 3, I);
62125f757f3fSDimitry Andric     break;
62135f757f3fSDimitry Andric   }
6214349cc55cSDimitry Andric   case Intrinsic::aarch64_neon_ld4: {
6215349cc55cSDimitry Andric     LLT Ty = MRI.getType(I.getOperand(0).getReg());
6216349cc55cSDimitry Andric     unsigned Opc = 0;
6217349cc55cSDimitry Andric     if (Ty == LLT::fixed_vector(8, S8))
6218349cc55cSDimitry Andric       Opc = AArch64::LD4Fourv8b;
6219349cc55cSDimitry Andric     else if (Ty == LLT::fixed_vector(16, S8))
6220349cc55cSDimitry Andric       Opc = AArch64::LD4Fourv16b;
6221349cc55cSDimitry Andric     else if (Ty == LLT::fixed_vector(4, S16))
6222349cc55cSDimitry Andric       Opc = AArch64::LD4Fourv4h;
6223349cc55cSDimitry Andric     else if (Ty == LLT::fixed_vector(8, S16))
6224349cc55cSDimitry Andric       Opc = AArch64::LD4Fourv8h;
6225349cc55cSDimitry Andric     else if (Ty == LLT::fixed_vector(2, S32))
6226349cc55cSDimitry Andric       Opc = AArch64::LD4Fourv2s;
6227349cc55cSDimitry Andric     else if (Ty == LLT::fixed_vector(4, S32))
6228349cc55cSDimitry Andric       Opc = AArch64::LD4Fourv4s;
6229349cc55cSDimitry Andric     else if (Ty == LLT::fixed_vector(2, S64) || Ty == LLT::fixed_vector(2, P0))
6230349cc55cSDimitry Andric       Opc = AArch64::LD4Fourv2d;
6231349cc55cSDimitry Andric     else if (Ty == S64 || Ty == P0)
6232349cc55cSDimitry Andric       Opc = AArch64::LD1Fourv1d;
6233349cc55cSDimitry Andric     else
6234349cc55cSDimitry Andric       llvm_unreachable("Unexpected type for ld4!");
6235349cc55cSDimitry Andric     selectVectorLoadIntrinsic(Opc, 4, I);
6236349cc55cSDimitry Andric     break;
6237349cc55cSDimitry Andric   }
62385f757f3fSDimitry Andric   case Intrinsic::aarch64_neon_ld4lane: {
62395f757f3fSDimitry Andric     LLT Ty = MRI.getType(I.getOperand(0).getReg());
62405f757f3fSDimitry Andric     unsigned Opc;
62415f757f3fSDimitry Andric     if (Ty == LLT::fixed_vector(8, S8) || Ty == LLT::fixed_vector(16, S8))
62425f757f3fSDimitry Andric       Opc = AArch64::LD4i8;
62435f757f3fSDimitry Andric     else if (Ty == LLT::fixed_vector(4, S16) || Ty == LLT::fixed_vector(8, S16))
62445f757f3fSDimitry Andric       Opc = AArch64::LD4i16;
62455f757f3fSDimitry Andric     else if (Ty == LLT::fixed_vector(2, S32) || Ty == LLT::fixed_vector(4, S32))
62465f757f3fSDimitry Andric       Opc = AArch64::LD4i32;
62475f757f3fSDimitry Andric     else if (Ty == LLT::fixed_vector(2, S64) ||
62485f757f3fSDimitry Andric              Ty == LLT::fixed_vector(2, P0) || Ty == S64 || Ty == P0)
62495f757f3fSDimitry Andric       Opc = AArch64::LD4i64;
62505f757f3fSDimitry Andric     else
62515f757f3fSDimitry Andric       llvm_unreachable("Unexpected type for st4lane!");
62525f757f3fSDimitry Andric     if (!selectVectorLoadLaneIntrinsic(Opc, 4, I))
62535f757f3fSDimitry Andric       return false;
62545f757f3fSDimitry Andric     break;
62555f757f3fSDimitry Andric   }
62565f757f3fSDimitry Andric   case Intrinsic::aarch64_neon_ld4r: {
62575f757f3fSDimitry Andric     LLT Ty = MRI.getType(I.getOperand(0).getReg());
62585f757f3fSDimitry Andric     unsigned Opc = 0;
62595f757f3fSDimitry Andric     if (Ty == LLT::fixed_vector(8, S8))
62605f757f3fSDimitry Andric       Opc = AArch64::LD4Rv8b;
62615f757f3fSDimitry Andric     else if (Ty == LLT::fixed_vector(16, S8))
62625f757f3fSDimitry Andric       Opc = AArch64::LD4Rv16b;
62635f757f3fSDimitry Andric     else if (Ty == LLT::fixed_vector(4, S16))
62645f757f3fSDimitry Andric       Opc = AArch64::LD4Rv4h;
62655f757f3fSDimitry Andric     else if (Ty == LLT::fixed_vector(8, S16))
62665f757f3fSDimitry Andric       Opc = AArch64::LD4Rv8h;
62675f757f3fSDimitry Andric     else if (Ty == LLT::fixed_vector(2, S32))
62685f757f3fSDimitry Andric       Opc = AArch64::LD4Rv2s;
62695f757f3fSDimitry Andric     else if (Ty == LLT::fixed_vector(4, S32))
62705f757f3fSDimitry Andric       Opc = AArch64::LD4Rv4s;
62715f757f3fSDimitry Andric     else if (Ty == LLT::fixed_vector(2, S64) || Ty == LLT::fixed_vector(2, P0))
62725f757f3fSDimitry Andric       Opc = AArch64::LD4Rv2d;
62735f757f3fSDimitry Andric     else if (Ty == S64 || Ty == P0)
62745f757f3fSDimitry Andric       Opc = AArch64::LD4Rv1d;
62755f757f3fSDimitry Andric     else
62765f757f3fSDimitry Andric       llvm_unreachable("Unexpected type for ld4r!");
62775f757f3fSDimitry Andric     selectVectorLoadIntrinsic(Opc, 4, I);
62785f757f3fSDimitry Andric     break;
62795f757f3fSDimitry Andric   }
62805f757f3fSDimitry Andric   case Intrinsic::aarch64_neon_st1x2: {
62815f757f3fSDimitry Andric     LLT Ty = MRI.getType(I.getOperand(1).getReg());
62825f757f3fSDimitry Andric     unsigned Opc;
62835f757f3fSDimitry Andric     if (Ty == LLT::fixed_vector(8, S8))
62845f757f3fSDimitry Andric       Opc = AArch64::ST1Twov8b;
62855f757f3fSDimitry Andric     else if (Ty == LLT::fixed_vector(16, S8))
62865f757f3fSDimitry Andric       Opc = AArch64::ST1Twov16b;
62875f757f3fSDimitry Andric     else if (Ty == LLT::fixed_vector(4, S16))
62885f757f3fSDimitry Andric       Opc = AArch64::ST1Twov4h;
62895f757f3fSDimitry Andric     else if (Ty == LLT::fixed_vector(8, S16))
62905f757f3fSDimitry Andric       Opc = AArch64::ST1Twov8h;
62915f757f3fSDimitry Andric     else if (Ty == LLT::fixed_vector(2, S32))
62925f757f3fSDimitry Andric       Opc = AArch64::ST1Twov2s;
62935f757f3fSDimitry Andric     else if (Ty == LLT::fixed_vector(4, S32))
62945f757f3fSDimitry Andric       Opc = AArch64::ST1Twov4s;
62955f757f3fSDimitry Andric     else if (Ty == LLT::fixed_vector(2, S64) || Ty == LLT::fixed_vector(2, P0))
62965f757f3fSDimitry Andric       Opc = AArch64::ST1Twov2d;
62975f757f3fSDimitry Andric     else if (Ty == S64 || Ty == P0)
62985f757f3fSDimitry Andric       Opc = AArch64::ST1Twov1d;
62995f757f3fSDimitry Andric     else
63005f757f3fSDimitry Andric       llvm_unreachable("Unexpected type for st1x2!");
63015f757f3fSDimitry Andric     selectVectorStoreIntrinsic(I, 2, Opc);
63025f757f3fSDimitry Andric     break;
63035f757f3fSDimitry Andric   }
63045f757f3fSDimitry Andric   case Intrinsic::aarch64_neon_st1x3: {
63055f757f3fSDimitry Andric     LLT Ty = MRI.getType(I.getOperand(1).getReg());
63065f757f3fSDimitry Andric     unsigned Opc;
63075f757f3fSDimitry Andric     if (Ty == LLT::fixed_vector(8, S8))
63085f757f3fSDimitry Andric       Opc = AArch64::ST1Threev8b;
63095f757f3fSDimitry Andric     else if (Ty == LLT::fixed_vector(16, S8))
63105f757f3fSDimitry Andric       Opc = AArch64::ST1Threev16b;
63115f757f3fSDimitry Andric     else if (Ty == LLT::fixed_vector(4, S16))
63125f757f3fSDimitry Andric       Opc = AArch64::ST1Threev4h;
63135f757f3fSDimitry Andric     else if (Ty == LLT::fixed_vector(8, S16))
63145f757f3fSDimitry Andric       Opc = AArch64::ST1Threev8h;
63155f757f3fSDimitry Andric     else if (Ty == LLT::fixed_vector(2, S32))
63165f757f3fSDimitry Andric       Opc = AArch64::ST1Threev2s;
63175f757f3fSDimitry Andric     else if (Ty == LLT::fixed_vector(4, S32))
63185f757f3fSDimitry Andric       Opc = AArch64::ST1Threev4s;
63195f757f3fSDimitry Andric     else if (Ty == LLT::fixed_vector(2, S64) || Ty == LLT::fixed_vector(2, P0))
63205f757f3fSDimitry Andric       Opc = AArch64::ST1Threev2d;
63215f757f3fSDimitry Andric     else if (Ty == S64 || Ty == P0)
63225f757f3fSDimitry Andric       Opc = AArch64::ST1Threev1d;
63235f757f3fSDimitry Andric     else
63245f757f3fSDimitry Andric       llvm_unreachable("Unexpected type for st1x3!");
63255f757f3fSDimitry Andric     selectVectorStoreIntrinsic(I, 3, Opc);
63265f757f3fSDimitry Andric     break;
63275f757f3fSDimitry Andric   }
63285f757f3fSDimitry Andric   case Intrinsic::aarch64_neon_st1x4: {
63295f757f3fSDimitry Andric     LLT Ty = MRI.getType(I.getOperand(1).getReg());
63305f757f3fSDimitry Andric     unsigned Opc;
63315f757f3fSDimitry Andric     if (Ty == LLT::fixed_vector(8, S8))
63325f757f3fSDimitry Andric       Opc = AArch64::ST1Fourv8b;
63335f757f3fSDimitry Andric     else if (Ty == LLT::fixed_vector(16, S8))
63345f757f3fSDimitry Andric       Opc = AArch64::ST1Fourv16b;
63355f757f3fSDimitry Andric     else if (Ty == LLT::fixed_vector(4, S16))
63365f757f3fSDimitry Andric       Opc = AArch64::ST1Fourv4h;
63375f757f3fSDimitry Andric     else if (Ty == LLT::fixed_vector(8, S16))
63385f757f3fSDimitry Andric       Opc = AArch64::ST1Fourv8h;
63395f757f3fSDimitry Andric     else if (Ty == LLT::fixed_vector(2, S32))
63405f757f3fSDimitry Andric       Opc = AArch64::ST1Fourv2s;
63415f757f3fSDimitry Andric     else if (Ty == LLT::fixed_vector(4, S32))
63425f757f3fSDimitry Andric       Opc = AArch64::ST1Fourv4s;
63435f757f3fSDimitry Andric     else if (Ty == LLT::fixed_vector(2, S64) || Ty == LLT::fixed_vector(2, P0))
63445f757f3fSDimitry Andric       Opc = AArch64::ST1Fourv2d;
63455f757f3fSDimitry Andric     else if (Ty == S64 || Ty == P0)
63465f757f3fSDimitry Andric       Opc = AArch64::ST1Fourv1d;
63475f757f3fSDimitry Andric     else
63485f757f3fSDimitry Andric       llvm_unreachable("Unexpected type for st1x4!");
63495f757f3fSDimitry Andric     selectVectorStoreIntrinsic(I, 4, Opc);
63505f757f3fSDimitry Andric     break;
63515f757f3fSDimitry Andric   }
6352fe6060f1SDimitry Andric   case Intrinsic::aarch64_neon_st2: {
63535f757f3fSDimitry Andric     LLT Ty = MRI.getType(I.getOperand(1).getReg());
6354fe6060f1SDimitry Andric     unsigned Opc;
6355fe6060f1SDimitry Andric     if (Ty == LLT::fixed_vector(8, S8))
6356fe6060f1SDimitry Andric       Opc = AArch64::ST2Twov8b;
6357fe6060f1SDimitry Andric     else if (Ty == LLT::fixed_vector(16, S8))
6358fe6060f1SDimitry Andric       Opc = AArch64::ST2Twov16b;
6359fe6060f1SDimitry Andric     else if (Ty == LLT::fixed_vector(4, S16))
6360fe6060f1SDimitry Andric       Opc = AArch64::ST2Twov4h;
6361fe6060f1SDimitry Andric     else if (Ty == LLT::fixed_vector(8, S16))
6362fe6060f1SDimitry Andric       Opc = AArch64::ST2Twov8h;
6363fe6060f1SDimitry Andric     else if (Ty == LLT::fixed_vector(2, S32))
6364fe6060f1SDimitry Andric       Opc = AArch64::ST2Twov2s;
6365fe6060f1SDimitry Andric     else if (Ty == LLT::fixed_vector(4, S32))
6366fe6060f1SDimitry Andric       Opc = AArch64::ST2Twov4s;
6367fe6060f1SDimitry Andric     else if (Ty == LLT::fixed_vector(2, S64) || Ty == LLT::fixed_vector(2, P0))
6368fe6060f1SDimitry Andric       Opc = AArch64::ST2Twov2d;
6369fe6060f1SDimitry Andric     else if (Ty == S64 || Ty == P0)
6370fe6060f1SDimitry Andric       Opc = AArch64::ST1Twov1d;
6371fe6060f1SDimitry Andric     else
6372fe6060f1SDimitry Andric       llvm_unreachable("Unexpected type for st2!");
63735f757f3fSDimitry Andric     selectVectorStoreIntrinsic(I, 2, Opc);
63745f757f3fSDimitry Andric     break;
63755f757f3fSDimitry Andric   }
63765f757f3fSDimitry Andric   case Intrinsic::aarch64_neon_st3: {
63775f757f3fSDimitry Andric     LLT Ty = MRI.getType(I.getOperand(1).getReg());
63785f757f3fSDimitry Andric     unsigned Opc;
63795f757f3fSDimitry Andric     if (Ty == LLT::fixed_vector(8, S8))
63805f757f3fSDimitry Andric       Opc = AArch64::ST3Threev8b;
63815f757f3fSDimitry Andric     else if (Ty == LLT::fixed_vector(16, S8))
63825f757f3fSDimitry Andric       Opc = AArch64::ST3Threev16b;
63835f757f3fSDimitry Andric     else if (Ty == LLT::fixed_vector(4, S16))
63845f757f3fSDimitry Andric       Opc = AArch64::ST3Threev4h;
63855f757f3fSDimitry Andric     else if (Ty == LLT::fixed_vector(8, S16))
63865f757f3fSDimitry Andric       Opc = AArch64::ST3Threev8h;
63875f757f3fSDimitry Andric     else if (Ty == LLT::fixed_vector(2, S32))
63885f757f3fSDimitry Andric       Opc = AArch64::ST3Threev2s;
63895f757f3fSDimitry Andric     else if (Ty == LLT::fixed_vector(4, S32))
63905f757f3fSDimitry Andric       Opc = AArch64::ST3Threev4s;
63915f757f3fSDimitry Andric     else if (Ty == LLT::fixed_vector(2, S64) || Ty == LLT::fixed_vector(2, P0))
63925f757f3fSDimitry Andric       Opc = AArch64::ST3Threev2d;
63935f757f3fSDimitry Andric     else if (Ty == S64 || Ty == P0)
63945f757f3fSDimitry Andric       Opc = AArch64::ST1Threev1d;
63955f757f3fSDimitry Andric     else
63965f757f3fSDimitry Andric       llvm_unreachable("Unexpected type for st3!");
63975f757f3fSDimitry Andric     selectVectorStoreIntrinsic(I, 3, Opc);
63985f757f3fSDimitry Andric     break;
63995f757f3fSDimitry Andric   }
64005f757f3fSDimitry Andric   case Intrinsic::aarch64_neon_st4: {
64015f757f3fSDimitry Andric     LLT Ty = MRI.getType(I.getOperand(1).getReg());
64025f757f3fSDimitry Andric     unsigned Opc;
64035f757f3fSDimitry Andric     if (Ty == LLT::fixed_vector(8, S8))
64045f757f3fSDimitry Andric       Opc = AArch64::ST4Fourv8b;
64055f757f3fSDimitry Andric     else if (Ty == LLT::fixed_vector(16, S8))
64065f757f3fSDimitry Andric       Opc = AArch64::ST4Fourv16b;
64075f757f3fSDimitry Andric     else if (Ty == LLT::fixed_vector(4, S16))
64085f757f3fSDimitry Andric       Opc = AArch64::ST4Fourv4h;
64095f757f3fSDimitry Andric     else if (Ty == LLT::fixed_vector(8, S16))
64105f757f3fSDimitry Andric       Opc = AArch64::ST4Fourv8h;
64115f757f3fSDimitry Andric     else if (Ty == LLT::fixed_vector(2, S32))
64125f757f3fSDimitry Andric       Opc = AArch64::ST4Fourv2s;
64135f757f3fSDimitry Andric     else if (Ty == LLT::fixed_vector(4, S32))
64145f757f3fSDimitry Andric       Opc = AArch64::ST4Fourv4s;
64155f757f3fSDimitry Andric     else if (Ty == LLT::fixed_vector(2, S64) || Ty == LLT::fixed_vector(2, P0))
64165f757f3fSDimitry Andric       Opc = AArch64::ST4Fourv2d;
64175f757f3fSDimitry Andric     else if (Ty == S64 || Ty == P0)
64185f757f3fSDimitry Andric       Opc = AArch64::ST1Fourv1d;
64195f757f3fSDimitry Andric     else
64205f757f3fSDimitry Andric       llvm_unreachable("Unexpected type for st4!");
64215f757f3fSDimitry Andric     selectVectorStoreIntrinsic(I, 4, Opc);
64225f757f3fSDimitry Andric     break;
64235f757f3fSDimitry Andric   }
64245f757f3fSDimitry Andric   case Intrinsic::aarch64_neon_st2lane: {
64255f757f3fSDimitry Andric     LLT Ty = MRI.getType(I.getOperand(1).getReg());
64265f757f3fSDimitry Andric     unsigned Opc;
64275f757f3fSDimitry Andric     if (Ty == LLT::fixed_vector(8, S8) || Ty == LLT::fixed_vector(16, S8))
64285f757f3fSDimitry Andric       Opc = AArch64::ST2i8;
64295f757f3fSDimitry Andric     else if (Ty == LLT::fixed_vector(4, S16) || Ty == LLT::fixed_vector(8, S16))
64305f757f3fSDimitry Andric       Opc = AArch64::ST2i16;
64315f757f3fSDimitry Andric     else if (Ty == LLT::fixed_vector(2, S32) || Ty == LLT::fixed_vector(4, S32))
64325f757f3fSDimitry Andric       Opc = AArch64::ST2i32;
64335f757f3fSDimitry Andric     else if (Ty == LLT::fixed_vector(2, S64) ||
64345f757f3fSDimitry Andric              Ty == LLT::fixed_vector(2, P0) || Ty == S64 || Ty == P0)
64355f757f3fSDimitry Andric       Opc = AArch64::ST2i64;
64365f757f3fSDimitry Andric     else
64375f757f3fSDimitry Andric       llvm_unreachable("Unexpected type for st2lane!");
64385f757f3fSDimitry Andric     if (!selectVectorStoreLaneIntrinsic(I, 2, Opc))
64395f757f3fSDimitry Andric       return false;
64405f757f3fSDimitry Andric     break;
64415f757f3fSDimitry Andric   }
64425f757f3fSDimitry Andric   case Intrinsic::aarch64_neon_st3lane: {
64435f757f3fSDimitry Andric     LLT Ty = MRI.getType(I.getOperand(1).getReg());
64445f757f3fSDimitry Andric     unsigned Opc;
64455f757f3fSDimitry Andric     if (Ty == LLT::fixed_vector(8, S8) || Ty == LLT::fixed_vector(16, S8))
64465f757f3fSDimitry Andric       Opc = AArch64::ST3i8;
64475f757f3fSDimitry Andric     else if (Ty == LLT::fixed_vector(4, S16) || Ty == LLT::fixed_vector(8, S16))
64485f757f3fSDimitry Andric       Opc = AArch64::ST3i16;
64495f757f3fSDimitry Andric     else if (Ty == LLT::fixed_vector(2, S32) || Ty == LLT::fixed_vector(4, S32))
64505f757f3fSDimitry Andric       Opc = AArch64::ST3i32;
64515f757f3fSDimitry Andric     else if (Ty == LLT::fixed_vector(2, S64) ||
64525f757f3fSDimitry Andric              Ty == LLT::fixed_vector(2, P0) || Ty == S64 || Ty == P0)
64535f757f3fSDimitry Andric       Opc = AArch64::ST3i64;
64545f757f3fSDimitry Andric     else
64555f757f3fSDimitry Andric       llvm_unreachable("Unexpected type for st3lane!");
64565f757f3fSDimitry Andric     if (!selectVectorStoreLaneIntrinsic(I, 3, Opc))
64575f757f3fSDimitry Andric       return false;
64585f757f3fSDimitry Andric     break;
64595f757f3fSDimitry Andric   }
64605f757f3fSDimitry Andric   case Intrinsic::aarch64_neon_st4lane: {
64615f757f3fSDimitry Andric     LLT Ty = MRI.getType(I.getOperand(1).getReg());
64625f757f3fSDimitry Andric     unsigned Opc;
64635f757f3fSDimitry Andric     if (Ty == LLT::fixed_vector(8, S8) || Ty == LLT::fixed_vector(16, S8))
64645f757f3fSDimitry Andric       Opc = AArch64::ST4i8;
64655f757f3fSDimitry Andric     else if (Ty == LLT::fixed_vector(4, S16) || Ty == LLT::fixed_vector(8, S16))
64665f757f3fSDimitry Andric       Opc = AArch64::ST4i16;
64675f757f3fSDimitry Andric     else if (Ty == LLT::fixed_vector(2, S32) || Ty == LLT::fixed_vector(4, S32))
64685f757f3fSDimitry Andric       Opc = AArch64::ST4i32;
64695f757f3fSDimitry Andric     else if (Ty == LLT::fixed_vector(2, S64) ||
64705f757f3fSDimitry Andric              Ty == LLT::fixed_vector(2, P0) || Ty == S64 || Ty == P0)
64715f757f3fSDimitry Andric       Opc = AArch64::ST4i64;
64725f757f3fSDimitry Andric     else
64735f757f3fSDimitry Andric       llvm_unreachable("Unexpected type for st4lane!");
64745f757f3fSDimitry Andric     if (!selectVectorStoreLaneIntrinsic(I, 4, Opc))
64755f757f3fSDimitry Andric       return false;
6476fe6060f1SDimitry Andric     break;
6477fe6060f1SDimitry Andric   }
64781fd87a68SDimitry Andric   case Intrinsic::aarch64_mops_memset_tag: {
64791fd87a68SDimitry Andric     // Transform
64801fd87a68SDimitry Andric     //    %dst:gpr(p0) = \
64811fd87a68SDimitry Andric     //      G_INTRINSIC_W_SIDE_EFFECTS intrinsic(@llvm.aarch64.mops.memset.tag),
64821fd87a68SDimitry Andric     //      \ %dst:gpr(p0), %val:gpr(s64), %n:gpr(s64)
64831fd87a68SDimitry Andric     // where %dst is updated, into
64841fd87a68SDimitry Andric     //    %Rd:GPR64common, %Rn:GPR64) = \
64851fd87a68SDimitry Andric     //      MOPSMemorySetTaggingPseudo \
64861fd87a68SDimitry Andric     //      %Rd:GPR64common, %Rn:GPR64, %Rm:GPR64
64871fd87a68SDimitry Andric     // where Rd and Rn are tied.
64881fd87a68SDimitry Andric     // It is expected that %val has been extended to s64 in legalization.
64891fd87a68SDimitry Andric     // Note that the order of the size/value operands are swapped.
64901fd87a68SDimitry Andric 
64911fd87a68SDimitry Andric     Register DstDef = I.getOperand(0).getReg();
64921fd87a68SDimitry Andric     // I.getOperand(1) is the intrinsic function
64931fd87a68SDimitry Andric     Register DstUse = I.getOperand(2).getReg();
64941fd87a68SDimitry Andric     Register ValUse = I.getOperand(3).getReg();
64951fd87a68SDimitry Andric     Register SizeUse = I.getOperand(4).getReg();
64961fd87a68SDimitry Andric 
64971fd87a68SDimitry Andric     // MOPSMemorySetTaggingPseudo has two defs; the intrinsic call has only one.
64981fd87a68SDimitry Andric     // Therefore an additional virtual register is requried for the updated size
64991fd87a68SDimitry Andric     // operand. This value is not accessible via the semantics of the intrinsic.
65001fd87a68SDimitry Andric     Register SizeDef = MRI.createGenericVirtualRegister(LLT::scalar(64));
65011fd87a68SDimitry Andric 
65021fd87a68SDimitry Andric     auto Memset = MIB.buildInstr(AArch64::MOPSMemorySetTaggingPseudo,
65031fd87a68SDimitry Andric                                  {DstDef, SizeDef}, {DstUse, SizeUse, ValUse});
65041fd87a68SDimitry Andric     Memset.cloneMemRefs(I);
65051fd87a68SDimitry Andric     constrainSelectedInstRegOperands(*Memset, TII, TRI, RBI);
65061fd87a68SDimitry Andric     break;
65071fd87a68SDimitry Andric   }
65085ffd83dbSDimitry Andric   }
65095ffd83dbSDimitry Andric 
65105ffd83dbSDimitry Andric   I.eraseFromParent();
65115ffd83dbSDimitry Andric   return true;
65125ffd83dbSDimitry Andric }
65135ffd83dbSDimitry Andric 
selectIntrinsic(MachineInstr & I,MachineRegisterInfo & MRI)65145ffd83dbSDimitry Andric bool AArch64InstructionSelector::selectIntrinsic(MachineInstr &I,
65155ffd83dbSDimitry Andric                                                  MachineRegisterInfo &MRI) {
65165f757f3fSDimitry Andric   unsigned IntrinID = cast<GIntrinsic>(I).getIntrinsicID();
65175ffd83dbSDimitry Andric 
65185ffd83dbSDimitry Andric   switch (IntrinID) {
65195ffd83dbSDimitry Andric   default:
65205ffd83dbSDimitry Andric     break;
65215ffd83dbSDimitry Andric   case Intrinsic::aarch64_crypto_sha1h: {
65225ffd83dbSDimitry Andric     Register DstReg = I.getOperand(0).getReg();
65235ffd83dbSDimitry Andric     Register SrcReg = I.getOperand(2).getReg();
65245ffd83dbSDimitry Andric 
65255ffd83dbSDimitry Andric     // FIXME: Should this be an assert?
65265ffd83dbSDimitry Andric     if (MRI.getType(DstReg).getSizeInBits() != 32 ||
65275ffd83dbSDimitry Andric         MRI.getType(SrcReg).getSizeInBits() != 32)
65285ffd83dbSDimitry Andric       return false;
65295ffd83dbSDimitry Andric 
65305ffd83dbSDimitry Andric     // The operation has to happen on FPRs. Set up some new FPR registers for
65315ffd83dbSDimitry Andric     // the source and destination if they are on GPRs.
65325ffd83dbSDimitry Andric     if (RBI.getRegBank(SrcReg, MRI, TRI)->getID() != AArch64::FPRRegBankID) {
65335ffd83dbSDimitry Andric       SrcReg = MRI.createVirtualRegister(&AArch64::FPR32RegClass);
6534fe6060f1SDimitry Andric       MIB.buildCopy({SrcReg}, {I.getOperand(2)});
65355ffd83dbSDimitry Andric 
65365ffd83dbSDimitry Andric       // Make sure the copy ends up getting constrained properly.
65375ffd83dbSDimitry Andric       RBI.constrainGenericRegister(I.getOperand(2).getReg(),
65385ffd83dbSDimitry Andric                                    AArch64::GPR32RegClass, MRI);
65395ffd83dbSDimitry Andric     }
65405ffd83dbSDimitry Andric 
65415ffd83dbSDimitry Andric     if (RBI.getRegBank(DstReg, MRI, TRI)->getID() != AArch64::FPRRegBankID)
65425ffd83dbSDimitry Andric       DstReg = MRI.createVirtualRegister(&AArch64::FPR32RegClass);
65435ffd83dbSDimitry Andric 
65445ffd83dbSDimitry Andric     // Actually insert the instruction.
6545fe6060f1SDimitry Andric     auto SHA1Inst = MIB.buildInstr(AArch64::SHA1Hrr, {DstReg}, {SrcReg});
65465ffd83dbSDimitry Andric     constrainSelectedInstRegOperands(*SHA1Inst, TII, TRI, RBI);
65475ffd83dbSDimitry Andric 
65485ffd83dbSDimitry Andric     // Did we create a new register for the destination?
65495ffd83dbSDimitry Andric     if (DstReg != I.getOperand(0).getReg()) {
65505ffd83dbSDimitry Andric       // Yep. Copy the result of the instruction back into the original
65515ffd83dbSDimitry Andric       // destination.
6552fe6060f1SDimitry Andric       MIB.buildCopy({I.getOperand(0)}, {DstReg});
65535ffd83dbSDimitry Andric       RBI.constrainGenericRegister(I.getOperand(0).getReg(),
65545ffd83dbSDimitry Andric                                    AArch64::GPR32RegClass, MRI);
65555ffd83dbSDimitry Andric     }
65565ffd83dbSDimitry Andric 
65575ffd83dbSDimitry Andric     I.eraseFromParent();
65585ffd83dbSDimitry Andric     return true;
65595ffd83dbSDimitry Andric   }
6560*0fca6ea1SDimitry Andric   case Intrinsic::ptrauth_resign: {
6561*0fca6ea1SDimitry Andric     Register DstReg = I.getOperand(0).getReg();
6562*0fca6ea1SDimitry Andric     Register ValReg = I.getOperand(2).getReg();
6563*0fca6ea1SDimitry Andric     uint64_t AUTKey = I.getOperand(3).getImm();
6564*0fca6ea1SDimitry Andric     Register AUTDisc = I.getOperand(4).getReg();
6565*0fca6ea1SDimitry Andric     uint64_t PACKey = I.getOperand(5).getImm();
6566*0fca6ea1SDimitry Andric     Register PACDisc = I.getOperand(6).getReg();
6567*0fca6ea1SDimitry Andric 
6568*0fca6ea1SDimitry Andric     Register AUTAddrDisc = AUTDisc;
6569*0fca6ea1SDimitry Andric     uint16_t AUTConstDiscC = 0;
6570*0fca6ea1SDimitry Andric     std::tie(AUTConstDiscC, AUTAddrDisc) =
6571*0fca6ea1SDimitry Andric         extractPtrauthBlendDiscriminators(AUTDisc, MRI);
6572*0fca6ea1SDimitry Andric 
6573*0fca6ea1SDimitry Andric     Register PACAddrDisc = PACDisc;
6574*0fca6ea1SDimitry Andric     uint16_t PACConstDiscC = 0;
6575*0fca6ea1SDimitry Andric     std::tie(PACConstDiscC, PACAddrDisc) =
6576*0fca6ea1SDimitry Andric         extractPtrauthBlendDiscriminators(PACDisc, MRI);
6577*0fca6ea1SDimitry Andric 
6578*0fca6ea1SDimitry Andric     MIB.buildCopy({AArch64::X16}, {ValReg});
6579*0fca6ea1SDimitry Andric     MIB.buildInstr(TargetOpcode::IMPLICIT_DEF, {AArch64::X17}, {});
6580*0fca6ea1SDimitry Andric     MIB.buildInstr(AArch64::AUTPAC)
6581*0fca6ea1SDimitry Andric         .addImm(AUTKey)
6582*0fca6ea1SDimitry Andric         .addImm(AUTConstDiscC)
6583*0fca6ea1SDimitry Andric         .addUse(AUTAddrDisc)
6584*0fca6ea1SDimitry Andric         .addImm(PACKey)
6585*0fca6ea1SDimitry Andric         .addImm(PACConstDiscC)
6586*0fca6ea1SDimitry Andric         .addUse(PACAddrDisc)
6587*0fca6ea1SDimitry Andric         .constrainAllUses(TII, TRI, RBI);
6588*0fca6ea1SDimitry Andric     MIB.buildCopy({DstReg}, Register(AArch64::X16));
6589*0fca6ea1SDimitry Andric 
6590*0fca6ea1SDimitry Andric     RBI.constrainGenericRegister(DstReg, AArch64::GPR64RegClass, MRI);
6591*0fca6ea1SDimitry Andric     I.eraseFromParent();
6592*0fca6ea1SDimitry Andric     return true;
6593*0fca6ea1SDimitry Andric   }
6594*0fca6ea1SDimitry Andric   case Intrinsic::ptrauth_auth: {
6595*0fca6ea1SDimitry Andric     Register DstReg = I.getOperand(0).getReg();
6596*0fca6ea1SDimitry Andric     Register ValReg = I.getOperand(2).getReg();
6597*0fca6ea1SDimitry Andric     uint64_t AUTKey = I.getOperand(3).getImm();
6598*0fca6ea1SDimitry Andric     Register AUTDisc = I.getOperand(4).getReg();
6599*0fca6ea1SDimitry Andric 
6600*0fca6ea1SDimitry Andric     Register AUTAddrDisc = AUTDisc;
6601*0fca6ea1SDimitry Andric     uint16_t AUTConstDiscC = 0;
6602*0fca6ea1SDimitry Andric     std::tie(AUTConstDiscC, AUTAddrDisc) =
6603*0fca6ea1SDimitry Andric         extractPtrauthBlendDiscriminators(AUTDisc, MRI);
6604*0fca6ea1SDimitry Andric 
6605*0fca6ea1SDimitry Andric     MIB.buildCopy({AArch64::X16}, {ValReg});
6606*0fca6ea1SDimitry Andric     MIB.buildInstr(TargetOpcode::IMPLICIT_DEF, {AArch64::X17}, {});
6607*0fca6ea1SDimitry Andric     MIB.buildInstr(AArch64::AUT)
6608*0fca6ea1SDimitry Andric         .addImm(AUTKey)
6609*0fca6ea1SDimitry Andric         .addImm(AUTConstDiscC)
6610*0fca6ea1SDimitry Andric         .addUse(AUTAddrDisc)
6611*0fca6ea1SDimitry Andric         .constrainAllUses(TII, TRI, RBI);
6612*0fca6ea1SDimitry Andric     MIB.buildCopy({DstReg}, Register(AArch64::X16));
6613*0fca6ea1SDimitry Andric 
6614*0fca6ea1SDimitry Andric     RBI.constrainGenericRegister(DstReg, AArch64::GPR64RegClass, MRI);
6615*0fca6ea1SDimitry Andric     I.eraseFromParent();
6616*0fca6ea1SDimitry Andric     return true;
6617*0fca6ea1SDimitry Andric   }
66185ffd83dbSDimitry Andric   case Intrinsic::frameaddress:
66195ffd83dbSDimitry Andric   case Intrinsic::returnaddress: {
66205ffd83dbSDimitry Andric     MachineFunction &MF = *I.getParent()->getParent();
66215ffd83dbSDimitry Andric     MachineFrameInfo &MFI = MF.getFrameInfo();
66225ffd83dbSDimitry Andric 
66235ffd83dbSDimitry Andric     unsigned Depth = I.getOperand(2).getImm();
66245ffd83dbSDimitry Andric     Register DstReg = I.getOperand(0).getReg();
66255ffd83dbSDimitry Andric     RBI.constrainGenericRegister(DstReg, AArch64::GPR64RegClass, MRI);
66265ffd83dbSDimitry Andric 
66275ffd83dbSDimitry Andric     if (Depth == 0 && IntrinID == Intrinsic::returnaddress) {
6628e8d8bef9SDimitry Andric       if (!MFReturnAddr) {
66295ffd83dbSDimitry Andric         // Insert the copy from LR/X30 into the entry block, before it can be
66305ffd83dbSDimitry Andric         // clobbered by anything.
6631e8d8bef9SDimitry Andric         MFI.setReturnAddressIsTaken(true);
663204eeddc0SDimitry Andric         MFReturnAddr = getFunctionLiveInPhysReg(
663304eeddc0SDimitry Andric             MF, TII, AArch64::LR, AArch64::GPR64RegClass, I.getDebugLoc());
6634e8d8bef9SDimitry Andric       }
6635e8d8bef9SDimitry Andric 
6636e8d8bef9SDimitry Andric       if (STI.hasPAuth()) {
6637fe6060f1SDimitry Andric         MIB.buildInstr(AArch64::XPACI, {DstReg}, {MFReturnAddr});
6638e8d8bef9SDimitry Andric       } else {
6639fe6060f1SDimitry Andric         MIB.buildCopy({Register(AArch64::LR)}, {MFReturnAddr});
6640fe6060f1SDimitry Andric         MIB.buildInstr(AArch64::XPACLRI);
6641fe6060f1SDimitry Andric         MIB.buildCopy({DstReg}, {Register(AArch64::LR)});
6642e8d8bef9SDimitry Andric       }
6643e8d8bef9SDimitry Andric 
66445ffd83dbSDimitry Andric       I.eraseFromParent();
66455ffd83dbSDimitry Andric       return true;
66465ffd83dbSDimitry Andric     }
66475ffd83dbSDimitry Andric 
66485ffd83dbSDimitry Andric     MFI.setFrameAddressIsTaken(true);
66495ffd83dbSDimitry Andric     Register FrameAddr(AArch64::FP);
66505ffd83dbSDimitry Andric     while (Depth--) {
66515ffd83dbSDimitry Andric       Register NextFrame = MRI.createVirtualRegister(&AArch64::GPR64spRegClass);
66525ffd83dbSDimitry Andric       auto Ldr =
6653fe6060f1SDimitry Andric           MIB.buildInstr(AArch64::LDRXui, {NextFrame}, {FrameAddr}).addImm(0);
66545ffd83dbSDimitry Andric       constrainSelectedInstRegOperands(*Ldr, TII, TRI, RBI);
66555ffd83dbSDimitry Andric       FrameAddr = NextFrame;
66565ffd83dbSDimitry Andric     }
66575ffd83dbSDimitry Andric 
66585ffd83dbSDimitry Andric     if (IntrinID == Intrinsic::frameaddress)
6659fe6060f1SDimitry Andric       MIB.buildCopy({DstReg}, {FrameAddr});
66605ffd83dbSDimitry Andric     else {
66615ffd83dbSDimitry Andric       MFI.setReturnAddressIsTaken(true);
6662e8d8bef9SDimitry Andric 
6663e8d8bef9SDimitry Andric       if (STI.hasPAuth()) {
6664e8d8bef9SDimitry Andric         Register TmpReg = MRI.createVirtualRegister(&AArch64::GPR64RegClass);
6665fe6060f1SDimitry Andric         MIB.buildInstr(AArch64::LDRXui, {TmpReg}, {FrameAddr}).addImm(1);
6666fe6060f1SDimitry Andric         MIB.buildInstr(AArch64::XPACI, {DstReg}, {TmpReg});
6667e8d8bef9SDimitry Andric       } else {
6668fe6060f1SDimitry Andric         MIB.buildInstr(AArch64::LDRXui, {Register(AArch64::LR)}, {FrameAddr})
6669fe6060f1SDimitry Andric             .addImm(1);
6670fe6060f1SDimitry Andric         MIB.buildInstr(AArch64::XPACLRI);
6671fe6060f1SDimitry Andric         MIB.buildCopy({DstReg}, {Register(AArch64::LR)});
6672e8d8bef9SDimitry Andric       }
66735ffd83dbSDimitry Andric     }
66745ffd83dbSDimitry Andric 
66755ffd83dbSDimitry Andric     I.eraseFromParent();
66765ffd83dbSDimitry Andric     return true;
66775ffd83dbSDimitry Andric   }
6678*0fca6ea1SDimitry Andric   case Intrinsic::aarch64_neon_tbl2:
6679*0fca6ea1SDimitry Andric     SelectTable(I, MRI, 2, AArch64::TBLv8i8Two, AArch64::TBLv16i8Two, false);
6680*0fca6ea1SDimitry Andric     return true;
6681*0fca6ea1SDimitry Andric   case Intrinsic::aarch64_neon_tbl3:
6682*0fca6ea1SDimitry Andric     SelectTable(I, MRI, 3, AArch64::TBLv8i8Three, AArch64::TBLv16i8Three,
6683*0fca6ea1SDimitry Andric                 false);
6684*0fca6ea1SDimitry Andric     return true;
6685*0fca6ea1SDimitry Andric   case Intrinsic::aarch64_neon_tbl4:
6686*0fca6ea1SDimitry Andric     SelectTable(I, MRI, 4, AArch64::TBLv8i8Four, AArch64::TBLv16i8Four, false);
6687*0fca6ea1SDimitry Andric     return true;
6688*0fca6ea1SDimitry Andric   case Intrinsic::aarch64_neon_tbx2:
6689*0fca6ea1SDimitry Andric     SelectTable(I, MRI, 2, AArch64::TBXv8i8Two, AArch64::TBXv16i8Two, true);
6690*0fca6ea1SDimitry Andric     return true;
6691*0fca6ea1SDimitry Andric   case Intrinsic::aarch64_neon_tbx3:
6692*0fca6ea1SDimitry Andric     SelectTable(I, MRI, 3, AArch64::TBXv8i8Three, AArch64::TBXv16i8Three, true);
6693*0fca6ea1SDimitry Andric     return true;
6694*0fca6ea1SDimitry Andric   case Intrinsic::aarch64_neon_tbx4:
6695*0fca6ea1SDimitry Andric     SelectTable(I, MRI, 4, AArch64::TBXv8i8Four, AArch64::TBXv16i8Four, true);
6696*0fca6ea1SDimitry Andric     return true;
6697fe6060f1SDimitry Andric   case Intrinsic::swift_async_context_addr:
6698fe6060f1SDimitry Andric     auto Sub = MIB.buildInstr(AArch64::SUBXri, {I.getOperand(0).getReg()},
6699fe6060f1SDimitry Andric                               {Register(AArch64::FP)})
6700fe6060f1SDimitry Andric                    .addImm(8)
6701fe6060f1SDimitry Andric                    .addImm(0);
6702fe6060f1SDimitry Andric     constrainSelectedInstRegOperands(*Sub, TII, TRI, RBI);
6703fe6060f1SDimitry Andric 
6704fe6060f1SDimitry Andric     MF->getFrameInfo().setFrameAddressIsTaken(true);
6705fe6060f1SDimitry Andric     MF->getInfo<AArch64FunctionInfo>()->setHasSwiftAsyncContext(true);
6706fe6060f1SDimitry Andric     I.eraseFromParent();
6707fe6060f1SDimitry Andric     return true;
67085ffd83dbSDimitry Andric   }
67095ffd83dbSDimitry Andric   return false;
67105ffd83dbSDimitry Andric }
67115ffd83dbSDimitry Andric 
6712*0fca6ea1SDimitry Andric // G_PTRAUTH_GLOBAL_VALUE lowering
6713*0fca6ea1SDimitry Andric //
6714*0fca6ea1SDimitry Andric // We have 3 lowering alternatives to choose from:
6715*0fca6ea1SDimitry Andric // - MOVaddrPAC: similar to MOVaddr, with added PAC.
6716*0fca6ea1SDimitry Andric //   If the GV doesn't need a GOT load (i.e., is locally defined)
6717*0fca6ea1SDimitry Andric //   materialize the pointer using adrp+add+pac. See LowerMOVaddrPAC.
6718*0fca6ea1SDimitry Andric //
6719*0fca6ea1SDimitry Andric // - LOADgotPAC: similar to LOADgot, with added PAC.
6720*0fca6ea1SDimitry Andric //   If the GV needs a GOT load, materialize the pointer using the usual
6721*0fca6ea1SDimitry Andric //   GOT adrp+ldr, +pac. Pointers in GOT are assumed to be not signed, the GOT
6722*0fca6ea1SDimitry Andric //   section is assumed to be read-only (for example, via relro mechanism). See
6723*0fca6ea1SDimitry Andric //   LowerMOVaddrPAC.
6724*0fca6ea1SDimitry Andric //
6725*0fca6ea1SDimitry Andric // - LOADauthptrstatic: similar to LOADgot, but use a
6726*0fca6ea1SDimitry Andric //   special stub slot instead of a GOT slot.
6727*0fca6ea1SDimitry Andric //   Load a signed pointer for symbol 'sym' from a stub slot named
6728*0fca6ea1SDimitry Andric //   'sym$auth_ptr$key$disc' filled by dynamic linker during relocation
6729*0fca6ea1SDimitry Andric //   resolving. This usually lowers to adrp+ldr, but also emits an entry into
6730*0fca6ea1SDimitry Andric //   .data with an
6731*0fca6ea1SDimitry Andric //   @AUTH relocation. See LowerLOADauthptrstatic.
6732*0fca6ea1SDimitry Andric //
6733*0fca6ea1SDimitry Andric // All 3 are pseudos that are expand late to longer sequences: this lets us
6734*0fca6ea1SDimitry Andric // provide integrity guarantees on the to-be-signed intermediate values.
6735*0fca6ea1SDimitry Andric //
6736*0fca6ea1SDimitry Andric // LOADauthptrstatic is undesirable because it requires a large section filled
6737*0fca6ea1SDimitry Andric // with often similarly-signed pointers, making it a good harvesting target.
6738*0fca6ea1SDimitry Andric // Thus, it's only used for ptrauth references to extern_weak to avoid null
6739*0fca6ea1SDimitry Andric // checks.
6740*0fca6ea1SDimitry Andric 
selectPtrAuthGlobalValue(MachineInstr & I,MachineRegisterInfo & MRI) const6741*0fca6ea1SDimitry Andric bool AArch64InstructionSelector::selectPtrAuthGlobalValue(
6742*0fca6ea1SDimitry Andric     MachineInstr &I, MachineRegisterInfo &MRI) const {
6743*0fca6ea1SDimitry Andric   Register DefReg = I.getOperand(0).getReg();
6744*0fca6ea1SDimitry Andric   Register Addr = I.getOperand(1).getReg();
6745*0fca6ea1SDimitry Andric   uint64_t Key = I.getOperand(2).getImm();
6746*0fca6ea1SDimitry Andric   Register AddrDisc = I.getOperand(3).getReg();
6747*0fca6ea1SDimitry Andric   uint64_t Disc = I.getOperand(4).getImm();
6748*0fca6ea1SDimitry Andric   int64_t Offset = 0;
6749*0fca6ea1SDimitry Andric 
6750*0fca6ea1SDimitry Andric   if (Key > AArch64PACKey::LAST)
6751*0fca6ea1SDimitry Andric     report_fatal_error("key in ptrauth global out of range [0, " +
6752*0fca6ea1SDimitry Andric                        Twine((int)AArch64PACKey::LAST) + "]");
6753*0fca6ea1SDimitry Andric 
6754*0fca6ea1SDimitry Andric   // Blend only works if the integer discriminator is 16-bit wide.
6755*0fca6ea1SDimitry Andric   if (!isUInt<16>(Disc))
6756*0fca6ea1SDimitry Andric     report_fatal_error(
6757*0fca6ea1SDimitry Andric         "constant discriminator in ptrauth global out of range [0, 0xffff]");
6758*0fca6ea1SDimitry Andric 
6759*0fca6ea1SDimitry Andric   // Choosing between 3 lowering alternatives is target-specific.
6760*0fca6ea1SDimitry Andric   if (!STI.isTargetELF() && !STI.isTargetMachO())
6761*0fca6ea1SDimitry Andric     report_fatal_error("ptrauth global lowering only supported on MachO/ELF");
6762*0fca6ea1SDimitry Andric 
6763*0fca6ea1SDimitry Andric   if (!MRI.hasOneDef(Addr))
6764*0fca6ea1SDimitry Andric     return false;
6765*0fca6ea1SDimitry Andric 
6766*0fca6ea1SDimitry Andric   // First match any offset we take from the real global.
6767*0fca6ea1SDimitry Andric   const MachineInstr *DefMI = &*MRI.def_instr_begin(Addr);
6768*0fca6ea1SDimitry Andric   if (DefMI->getOpcode() == TargetOpcode::G_PTR_ADD) {
6769*0fca6ea1SDimitry Andric     Register OffsetReg = DefMI->getOperand(2).getReg();
6770*0fca6ea1SDimitry Andric     if (!MRI.hasOneDef(OffsetReg))
6771*0fca6ea1SDimitry Andric       return false;
6772*0fca6ea1SDimitry Andric     const MachineInstr &OffsetMI = *MRI.def_instr_begin(OffsetReg);
6773*0fca6ea1SDimitry Andric     if (OffsetMI.getOpcode() != TargetOpcode::G_CONSTANT)
6774*0fca6ea1SDimitry Andric       return false;
6775*0fca6ea1SDimitry Andric 
6776*0fca6ea1SDimitry Andric     Addr = DefMI->getOperand(1).getReg();
6777*0fca6ea1SDimitry Andric     if (!MRI.hasOneDef(Addr))
6778*0fca6ea1SDimitry Andric       return false;
6779*0fca6ea1SDimitry Andric 
6780*0fca6ea1SDimitry Andric     DefMI = &*MRI.def_instr_begin(Addr);
6781*0fca6ea1SDimitry Andric     Offset = OffsetMI.getOperand(1).getCImm()->getSExtValue();
6782*0fca6ea1SDimitry Andric   }
6783*0fca6ea1SDimitry Andric 
6784*0fca6ea1SDimitry Andric   // We should be left with a genuine unauthenticated GlobalValue.
6785*0fca6ea1SDimitry Andric   const GlobalValue *GV;
6786*0fca6ea1SDimitry Andric   if (DefMI->getOpcode() == TargetOpcode::G_GLOBAL_VALUE) {
6787*0fca6ea1SDimitry Andric     GV = DefMI->getOperand(1).getGlobal();
6788*0fca6ea1SDimitry Andric     Offset += DefMI->getOperand(1).getOffset();
6789*0fca6ea1SDimitry Andric   } else if (DefMI->getOpcode() == AArch64::G_ADD_LOW) {
6790*0fca6ea1SDimitry Andric     GV = DefMI->getOperand(2).getGlobal();
6791*0fca6ea1SDimitry Andric     Offset += DefMI->getOperand(2).getOffset();
6792*0fca6ea1SDimitry Andric   } else {
6793*0fca6ea1SDimitry Andric     return false;
6794*0fca6ea1SDimitry Andric   }
6795*0fca6ea1SDimitry Andric 
6796*0fca6ea1SDimitry Andric   MachineIRBuilder MIB(I);
6797*0fca6ea1SDimitry Andric 
6798*0fca6ea1SDimitry Andric   // Classify the reference to determine whether it needs a GOT load.
6799*0fca6ea1SDimitry Andric   unsigned OpFlags = STI.ClassifyGlobalReference(GV, TM);
6800*0fca6ea1SDimitry Andric   const bool NeedsGOTLoad = ((OpFlags & AArch64II::MO_GOT) != 0);
6801*0fca6ea1SDimitry Andric   assert(((OpFlags & (~AArch64II::MO_GOT)) == 0) &&
6802*0fca6ea1SDimitry Andric          "unsupported non-GOT op flags on ptrauth global reference");
6803*0fca6ea1SDimitry Andric   assert((!GV->hasExternalWeakLinkage() || NeedsGOTLoad) &&
6804*0fca6ea1SDimitry Andric          "unsupported non-GOT reference to weak ptrauth global");
6805*0fca6ea1SDimitry Andric 
6806*0fca6ea1SDimitry Andric   std::optional<APInt> AddrDiscVal = getIConstantVRegVal(AddrDisc, MRI);
6807*0fca6ea1SDimitry Andric   bool HasAddrDisc = !AddrDiscVal || *AddrDiscVal != 0;
6808*0fca6ea1SDimitry Andric 
6809*0fca6ea1SDimitry Andric   // Non-extern_weak:
6810*0fca6ea1SDimitry Andric   // - No GOT load needed -> MOVaddrPAC
6811*0fca6ea1SDimitry Andric   // - GOT load for non-extern_weak -> LOADgotPAC
6812*0fca6ea1SDimitry Andric   //   Note that we disallow extern_weak refs to avoid null checks later.
6813*0fca6ea1SDimitry Andric   if (!GV->hasExternalWeakLinkage()) {
6814*0fca6ea1SDimitry Andric     MIB.buildInstr(TargetOpcode::IMPLICIT_DEF, {AArch64::X16}, {});
6815*0fca6ea1SDimitry Andric     MIB.buildInstr(TargetOpcode::IMPLICIT_DEF, {AArch64::X17}, {});
6816*0fca6ea1SDimitry Andric     MIB.buildInstr(NeedsGOTLoad ? AArch64::LOADgotPAC : AArch64::MOVaddrPAC)
6817*0fca6ea1SDimitry Andric         .addGlobalAddress(GV, Offset)
6818*0fca6ea1SDimitry Andric         .addImm(Key)
6819*0fca6ea1SDimitry Andric         .addReg(HasAddrDisc ? AddrDisc : AArch64::XZR)
6820*0fca6ea1SDimitry Andric         .addImm(Disc)
6821*0fca6ea1SDimitry Andric         .constrainAllUses(TII, TRI, RBI);
6822*0fca6ea1SDimitry Andric     MIB.buildCopy(DefReg, Register(AArch64::X16));
6823*0fca6ea1SDimitry Andric     RBI.constrainGenericRegister(DefReg, AArch64::GPR64RegClass, MRI);
6824*0fca6ea1SDimitry Andric     I.eraseFromParent();
6825*0fca6ea1SDimitry Andric     return true;
6826*0fca6ea1SDimitry Andric   }
6827*0fca6ea1SDimitry Andric 
6828*0fca6ea1SDimitry Andric   // extern_weak -> LOADauthptrstatic
6829*0fca6ea1SDimitry Andric 
6830*0fca6ea1SDimitry Andric   // Offsets and extern_weak don't mix well: ptrauth aside, you'd get the
6831*0fca6ea1SDimitry Andric   // offset alone as a pointer if the symbol wasn't available, which would
6832*0fca6ea1SDimitry Andric   // probably break null checks in users. Ptrauth complicates things further:
6833*0fca6ea1SDimitry Andric   // error out.
6834*0fca6ea1SDimitry Andric   if (Offset != 0)
6835*0fca6ea1SDimitry Andric     report_fatal_error(
6836*0fca6ea1SDimitry Andric         "unsupported non-zero offset in weak ptrauth global reference");
6837*0fca6ea1SDimitry Andric 
6838*0fca6ea1SDimitry Andric   if (HasAddrDisc)
6839*0fca6ea1SDimitry Andric     report_fatal_error("unsupported weak addr-div ptrauth global");
6840*0fca6ea1SDimitry Andric 
6841*0fca6ea1SDimitry Andric   MIB.buildInstr(AArch64::LOADauthptrstatic, {DefReg}, {})
6842*0fca6ea1SDimitry Andric       .addGlobalAddress(GV, Offset)
6843*0fca6ea1SDimitry Andric       .addImm(Key)
6844*0fca6ea1SDimitry Andric       .addImm(Disc);
6845*0fca6ea1SDimitry Andric   RBI.constrainGenericRegister(DefReg, AArch64::GPR64RegClass, MRI);
6846*0fca6ea1SDimitry Andric 
6847*0fca6ea1SDimitry Andric   I.eraseFromParent();
6848*0fca6ea1SDimitry Andric   return true;
6849*0fca6ea1SDimitry Andric }
6850*0fca6ea1SDimitry Andric 
SelectTable(MachineInstr & I,MachineRegisterInfo & MRI,unsigned NumVec,unsigned Opc1,unsigned Opc2,bool isExt)6851*0fca6ea1SDimitry Andric void AArch64InstructionSelector::SelectTable(MachineInstr &I,
6852*0fca6ea1SDimitry Andric                                              MachineRegisterInfo &MRI,
6853*0fca6ea1SDimitry Andric                                              unsigned NumVec, unsigned Opc1,
6854*0fca6ea1SDimitry Andric                                              unsigned Opc2, bool isExt) {
6855*0fca6ea1SDimitry Andric   Register DstReg = I.getOperand(0).getReg();
6856*0fca6ea1SDimitry Andric   unsigned Opc = MRI.getType(DstReg) == LLT::fixed_vector(8, 8) ? Opc1 : Opc2;
6857*0fca6ea1SDimitry Andric 
6858*0fca6ea1SDimitry Andric   // Create the REG_SEQUENCE
6859*0fca6ea1SDimitry Andric   SmallVector<Register, 4> Regs;
6860*0fca6ea1SDimitry Andric   for (unsigned i = 0; i < NumVec; i++)
6861*0fca6ea1SDimitry Andric     Regs.push_back(I.getOperand(i + 2 + isExt).getReg());
6862*0fca6ea1SDimitry Andric   Register RegSeq = createQTuple(Regs, MIB);
6863*0fca6ea1SDimitry Andric 
6864*0fca6ea1SDimitry Andric   Register IdxReg = I.getOperand(2 + NumVec + isExt).getReg();
6865*0fca6ea1SDimitry Andric   MachineInstrBuilder Instr;
6866*0fca6ea1SDimitry Andric   if (isExt) {
6867*0fca6ea1SDimitry Andric     Register Reg = I.getOperand(2).getReg();
6868*0fca6ea1SDimitry Andric     Instr = MIB.buildInstr(Opc, {DstReg}, {Reg, RegSeq, IdxReg});
6869*0fca6ea1SDimitry Andric   } else
6870*0fca6ea1SDimitry Andric     Instr = MIB.buildInstr(Opc, {DstReg}, {RegSeq, IdxReg});
6871*0fca6ea1SDimitry Andric   constrainSelectedInstRegOperands(*Instr, TII, TRI, RBI);
6872*0fca6ea1SDimitry Andric   I.eraseFromParent();
6873*0fca6ea1SDimitry Andric }
6874*0fca6ea1SDimitry Andric 
68755ffd83dbSDimitry Andric InstructionSelector::ComplexRendererFns
selectShiftA_32(const MachineOperand & Root) const68765ffd83dbSDimitry Andric AArch64InstructionSelector::selectShiftA_32(const MachineOperand &Root) const {
68775ffd83dbSDimitry Andric   auto MaybeImmed = getImmedFromMO(Root);
6878bdd1243dSDimitry Andric   if (MaybeImmed == std::nullopt || *MaybeImmed > 31)
6879bdd1243dSDimitry Andric     return std::nullopt;
68805ffd83dbSDimitry Andric   uint64_t Enc = (32 - *MaybeImmed) & 0x1f;
68815ffd83dbSDimitry Andric   return {{[=](MachineInstrBuilder &MIB) { MIB.addImm(Enc); }}};
68825ffd83dbSDimitry Andric }
68835ffd83dbSDimitry Andric 
68845ffd83dbSDimitry Andric InstructionSelector::ComplexRendererFns
selectShiftB_32(const MachineOperand & Root) const68855ffd83dbSDimitry Andric AArch64InstructionSelector::selectShiftB_32(const MachineOperand &Root) const {
68865ffd83dbSDimitry Andric   auto MaybeImmed = getImmedFromMO(Root);
6887bdd1243dSDimitry Andric   if (MaybeImmed == std::nullopt || *MaybeImmed > 31)
6888bdd1243dSDimitry Andric     return std::nullopt;
68895ffd83dbSDimitry Andric   uint64_t Enc = 31 - *MaybeImmed;
68905ffd83dbSDimitry Andric   return {{[=](MachineInstrBuilder &MIB) { MIB.addImm(Enc); }}};
68915ffd83dbSDimitry Andric }
68925ffd83dbSDimitry Andric 
68935ffd83dbSDimitry Andric InstructionSelector::ComplexRendererFns
selectShiftA_64(const MachineOperand & Root) const68945ffd83dbSDimitry Andric AArch64InstructionSelector::selectShiftA_64(const MachineOperand &Root) const {
68955ffd83dbSDimitry Andric   auto MaybeImmed = getImmedFromMO(Root);
6896bdd1243dSDimitry Andric   if (MaybeImmed == std::nullopt || *MaybeImmed > 63)
6897bdd1243dSDimitry Andric     return std::nullopt;
68985ffd83dbSDimitry Andric   uint64_t Enc = (64 - *MaybeImmed) & 0x3f;
68995ffd83dbSDimitry Andric   return {{[=](MachineInstrBuilder &MIB) { MIB.addImm(Enc); }}};
69005ffd83dbSDimitry Andric }
69015ffd83dbSDimitry Andric 
69025ffd83dbSDimitry Andric InstructionSelector::ComplexRendererFns
selectShiftB_64(const MachineOperand & Root) const69035ffd83dbSDimitry Andric AArch64InstructionSelector::selectShiftB_64(const MachineOperand &Root) const {
69045ffd83dbSDimitry Andric   auto MaybeImmed = getImmedFromMO(Root);
6905bdd1243dSDimitry Andric   if (MaybeImmed == std::nullopt || *MaybeImmed > 63)
6906bdd1243dSDimitry Andric     return std::nullopt;
69075ffd83dbSDimitry Andric   uint64_t Enc = 63 - *MaybeImmed;
69085ffd83dbSDimitry Andric   return {{[=](MachineInstrBuilder &MIB) { MIB.addImm(Enc); }}};
69095ffd83dbSDimitry Andric }
69105ffd83dbSDimitry Andric 
69115ffd83dbSDimitry Andric /// Helper to select an immediate value that can be represented as a 12-bit
69125ffd83dbSDimitry Andric /// value shifted left by either 0 or 12. If it is possible to do so, return
6913bdd1243dSDimitry Andric /// the immediate and shift value. If not, return std::nullopt.
69145ffd83dbSDimitry Andric ///
69155ffd83dbSDimitry Andric /// Used by selectArithImmed and selectNegArithImmed.
69165ffd83dbSDimitry Andric InstructionSelector::ComplexRendererFns
select12BitValueWithLeftShift(uint64_t Immed) const69175ffd83dbSDimitry Andric AArch64InstructionSelector::select12BitValueWithLeftShift(
69185ffd83dbSDimitry Andric     uint64_t Immed) const {
69195ffd83dbSDimitry Andric   unsigned ShiftAmt;
69205ffd83dbSDimitry Andric   if (Immed >> 12 == 0) {
69215ffd83dbSDimitry Andric     ShiftAmt = 0;
69225ffd83dbSDimitry Andric   } else if ((Immed & 0xfff) == 0 && Immed >> 24 == 0) {
69235ffd83dbSDimitry Andric     ShiftAmt = 12;
69245ffd83dbSDimitry Andric     Immed = Immed >> 12;
69255ffd83dbSDimitry Andric   } else
6926bdd1243dSDimitry Andric     return std::nullopt;
69275ffd83dbSDimitry Andric 
69285ffd83dbSDimitry Andric   unsigned ShVal = AArch64_AM::getShifterImm(AArch64_AM::LSL, ShiftAmt);
69295ffd83dbSDimitry Andric   return {{
69305ffd83dbSDimitry Andric       [=](MachineInstrBuilder &MIB) { MIB.addImm(Immed); },
69315ffd83dbSDimitry Andric       [=](MachineInstrBuilder &MIB) { MIB.addImm(ShVal); },
69325ffd83dbSDimitry Andric   }};
69335ffd83dbSDimitry Andric }
69345ffd83dbSDimitry Andric 
69355ffd83dbSDimitry Andric /// SelectArithImmed - Select an immediate value that can be represented as
69365ffd83dbSDimitry Andric /// a 12-bit value shifted left by either 0 or 12.  If so, return true with
69375ffd83dbSDimitry Andric /// Val set to the 12-bit value and Shift set to the shifter operand.
69385ffd83dbSDimitry Andric InstructionSelector::ComplexRendererFns
selectArithImmed(MachineOperand & Root) const69395ffd83dbSDimitry Andric AArch64InstructionSelector::selectArithImmed(MachineOperand &Root) const {
69405ffd83dbSDimitry Andric   // This function is called from the addsub_shifted_imm ComplexPattern,
69415ffd83dbSDimitry Andric   // which lists [imm] as the list of opcode it's interested in, however
69425ffd83dbSDimitry Andric   // we still need to check whether the operand is actually an immediate
69435ffd83dbSDimitry Andric   // here because the ComplexPattern opcode list is only used in
69445ffd83dbSDimitry Andric   // root-level opcode matching.
69455ffd83dbSDimitry Andric   auto MaybeImmed = getImmedFromMO(Root);
6946bdd1243dSDimitry Andric   if (MaybeImmed == std::nullopt)
6947bdd1243dSDimitry Andric     return std::nullopt;
69485ffd83dbSDimitry Andric   return select12BitValueWithLeftShift(*MaybeImmed);
69495ffd83dbSDimitry Andric }
69505ffd83dbSDimitry Andric 
69515ffd83dbSDimitry Andric /// SelectNegArithImmed - As above, but negates the value before trying to
69525ffd83dbSDimitry Andric /// select it.
69535ffd83dbSDimitry Andric InstructionSelector::ComplexRendererFns
selectNegArithImmed(MachineOperand & Root) const69545ffd83dbSDimitry Andric AArch64InstructionSelector::selectNegArithImmed(MachineOperand &Root) const {
69555ffd83dbSDimitry Andric   // We need a register here, because we need to know if we have a 64 or 32
69565ffd83dbSDimitry Andric   // bit immediate.
69575ffd83dbSDimitry Andric   if (!Root.isReg())
6958bdd1243dSDimitry Andric     return std::nullopt;
69595ffd83dbSDimitry Andric   auto MaybeImmed = getImmedFromMO(Root);
6960bdd1243dSDimitry Andric   if (MaybeImmed == std::nullopt)
6961bdd1243dSDimitry Andric     return std::nullopt;
69625ffd83dbSDimitry Andric   uint64_t Immed = *MaybeImmed;
69635ffd83dbSDimitry Andric 
69645ffd83dbSDimitry Andric   // This negation is almost always valid, but "cmp wN, #0" and "cmn wN, #0"
69655ffd83dbSDimitry Andric   // have the opposite effect on the C flag, so this pattern mustn't match under
69665ffd83dbSDimitry Andric   // those circumstances.
69675ffd83dbSDimitry Andric   if (Immed == 0)
6968bdd1243dSDimitry Andric     return std::nullopt;
69695ffd83dbSDimitry Andric 
69705ffd83dbSDimitry Andric   // Check if we're dealing with a 32-bit type on the root or a 64-bit type on
69715ffd83dbSDimitry Andric   // the root.
69725ffd83dbSDimitry Andric   MachineRegisterInfo &MRI = Root.getParent()->getMF()->getRegInfo();
69735ffd83dbSDimitry Andric   if (MRI.getType(Root.getReg()).getSizeInBits() == 32)
69745ffd83dbSDimitry Andric     Immed = ~((uint32_t)Immed) + 1;
69755ffd83dbSDimitry Andric   else
69765ffd83dbSDimitry Andric     Immed = ~Immed + 1ULL;
69775ffd83dbSDimitry Andric 
69785ffd83dbSDimitry Andric   if (Immed & 0xFFFFFFFFFF000000ULL)
6979bdd1243dSDimitry Andric     return std::nullopt;
69805ffd83dbSDimitry Andric 
69815ffd83dbSDimitry Andric   Immed &= 0xFFFFFFULL;
69825ffd83dbSDimitry Andric   return select12BitValueWithLeftShift(Immed);
69835ffd83dbSDimitry Andric }
69845ffd83dbSDimitry Andric 
6985*0fca6ea1SDimitry Andric /// Checks if we are sure that folding MI into load/store addressing mode is
6986*0fca6ea1SDimitry Andric /// beneficial or not.
6987*0fca6ea1SDimitry Andric ///
6988*0fca6ea1SDimitry Andric /// Returns:
6989*0fca6ea1SDimitry Andric /// - true if folding MI would be beneficial.
6990*0fca6ea1SDimitry Andric /// - false if folding MI would be bad.
6991*0fca6ea1SDimitry Andric /// - std::nullopt if it is not sure whether folding MI is beneficial.
6992*0fca6ea1SDimitry Andric ///
6993*0fca6ea1SDimitry Andric /// \p MI can be the offset operand of G_PTR_ADD, e.g. G_SHL in the example:
6994*0fca6ea1SDimitry Andric ///
6995*0fca6ea1SDimitry Andric /// %13:gpr(s64) = G_CONSTANT i64 1
6996*0fca6ea1SDimitry Andric /// %8:gpr(s64) = G_SHL %6, %13(s64)
6997*0fca6ea1SDimitry Andric /// %9:gpr(p0) = G_PTR_ADD %0, %8(s64)
6998*0fca6ea1SDimitry Andric /// %12:gpr(s32) = G_LOAD %9(p0) :: (load (s16))
isWorthFoldingIntoAddrMode(MachineInstr & MI,const MachineRegisterInfo & MRI) const6999*0fca6ea1SDimitry Andric std::optional<bool> AArch64InstructionSelector::isWorthFoldingIntoAddrMode(
7000*0fca6ea1SDimitry Andric     MachineInstr &MI, const MachineRegisterInfo &MRI) const {
7001*0fca6ea1SDimitry Andric   if (MI.getOpcode() == AArch64::G_SHL) {
7002*0fca6ea1SDimitry Andric     // Address operands with shifts are free, except for running on subtargets
7003*0fca6ea1SDimitry Andric     // with AddrLSLSlow14.
7004*0fca6ea1SDimitry Andric     if (const auto ValAndVeg = getIConstantVRegValWithLookThrough(
7005*0fca6ea1SDimitry Andric             MI.getOperand(2).getReg(), MRI)) {
7006*0fca6ea1SDimitry Andric       const APInt ShiftVal = ValAndVeg->Value;
7007*0fca6ea1SDimitry Andric 
7008*0fca6ea1SDimitry Andric       // Don't fold if we know this will be slow.
7009*0fca6ea1SDimitry Andric       return !(STI.hasAddrLSLSlow14() && (ShiftVal == 1 || ShiftVal == 4));
7010*0fca6ea1SDimitry Andric     }
7011*0fca6ea1SDimitry Andric   }
7012*0fca6ea1SDimitry Andric   return std::nullopt;
7013*0fca6ea1SDimitry Andric }
7014*0fca6ea1SDimitry Andric 
70155ffd83dbSDimitry Andric /// Return true if it is worth folding MI into an extended register. That is,
70165ffd83dbSDimitry Andric /// if it's safe to pull it into the addressing mode of a load or store as a
70175ffd83dbSDimitry Andric /// shift.
7018*0fca6ea1SDimitry Andric /// \p IsAddrOperand whether the def of MI is used as an address operand
7019*0fca6ea1SDimitry Andric /// (e.g. feeding into an LDR/STR).
isWorthFoldingIntoExtendedReg(MachineInstr & MI,const MachineRegisterInfo & MRI,bool IsAddrOperand) const70205ffd83dbSDimitry Andric bool AArch64InstructionSelector::isWorthFoldingIntoExtendedReg(
7021*0fca6ea1SDimitry Andric     MachineInstr &MI, const MachineRegisterInfo &MRI,
7022*0fca6ea1SDimitry Andric     bool IsAddrOperand) const {
7023*0fca6ea1SDimitry Andric 
70245ffd83dbSDimitry Andric   // Always fold if there is one use, or if we're optimizing for size.
70255ffd83dbSDimitry Andric   Register DefReg = MI.getOperand(0).getReg();
70265ffd83dbSDimitry Andric   if (MRI.hasOneNonDBGUse(DefReg) ||
7027fe6060f1SDimitry Andric       MI.getParent()->getParent()->getFunction().hasOptSize())
70285ffd83dbSDimitry Andric     return true;
70295ffd83dbSDimitry Andric 
7030*0fca6ea1SDimitry Andric   if (IsAddrOperand) {
7031*0fca6ea1SDimitry Andric     // If we are already sure that folding MI is good or bad, return the result.
7032*0fca6ea1SDimitry Andric     if (const auto Worth = isWorthFoldingIntoAddrMode(MI, MRI))
7033*0fca6ea1SDimitry Andric       return *Worth;
7034*0fca6ea1SDimitry Andric 
7035*0fca6ea1SDimitry Andric     // Fold G_PTR_ADD if its offset operand can be folded
7036*0fca6ea1SDimitry Andric     if (MI.getOpcode() == AArch64::G_PTR_ADD) {
7037*0fca6ea1SDimitry Andric       MachineInstr *OffsetInst =
7038*0fca6ea1SDimitry Andric           getDefIgnoringCopies(MI.getOperand(2).getReg(), MRI);
7039*0fca6ea1SDimitry Andric 
7040*0fca6ea1SDimitry Andric       // Note, we already know G_PTR_ADD is used by at least two instructions.
7041*0fca6ea1SDimitry Andric       // If we are also sure about whether folding is beneficial or not,
7042*0fca6ea1SDimitry Andric       // return the result.
7043*0fca6ea1SDimitry Andric       if (const auto Worth = isWorthFoldingIntoAddrMode(*OffsetInst, MRI))
7044*0fca6ea1SDimitry Andric         return *Worth;
7045*0fca6ea1SDimitry Andric     }
7046*0fca6ea1SDimitry Andric   }
7047*0fca6ea1SDimitry Andric 
7048*0fca6ea1SDimitry Andric   // FIXME: Consider checking HasALULSLFast as appropriate.
70495ffd83dbSDimitry Andric 
70505ffd83dbSDimitry Andric   // We have a fastpath, so folding a shift in and potentially computing it
70515ffd83dbSDimitry Andric   // many times may be beneficial. Check if this is only used in memory ops.
70525ffd83dbSDimitry Andric   // If it is, then we should fold.
70535ffd83dbSDimitry Andric   return all_of(MRI.use_nodbg_instructions(DefReg),
70545ffd83dbSDimitry Andric                 [](MachineInstr &Use) { return Use.mayLoadOrStore(); });
70555ffd83dbSDimitry Andric }
70565ffd83dbSDimitry Andric 
isSignExtendShiftType(AArch64_AM::ShiftExtendType Type)70575ffd83dbSDimitry Andric static bool isSignExtendShiftType(AArch64_AM::ShiftExtendType Type) {
70585ffd83dbSDimitry Andric   switch (Type) {
70595ffd83dbSDimitry Andric   case AArch64_AM::SXTB:
70605ffd83dbSDimitry Andric   case AArch64_AM::SXTH:
70615ffd83dbSDimitry Andric   case AArch64_AM::SXTW:
70625ffd83dbSDimitry Andric     return true;
70635ffd83dbSDimitry Andric   default:
70645ffd83dbSDimitry Andric     return false;
70655ffd83dbSDimitry Andric   }
70665ffd83dbSDimitry Andric }
70675ffd83dbSDimitry Andric 
70685ffd83dbSDimitry Andric InstructionSelector::ComplexRendererFns
selectExtendedSHL(MachineOperand & Root,MachineOperand & Base,MachineOperand & Offset,unsigned SizeInBytes,bool WantsExt) const70695ffd83dbSDimitry Andric AArch64InstructionSelector::selectExtendedSHL(
70705ffd83dbSDimitry Andric     MachineOperand &Root, MachineOperand &Base, MachineOperand &Offset,
70715ffd83dbSDimitry Andric     unsigned SizeInBytes, bool WantsExt) const {
70725ffd83dbSDimitry Andric   assert(Base.isReg() && "Expected base to be a register operand");
70735ffd83dbSDimitry Andric   assert(Offset.isReg() && "Expected offset to be a register operand");
70745ffd83dbSDimitry Andric 
70755ffd83dbSDimitry Andric   MachineRegisterInfo &MRI = Root.getParent()->getMF()->getRegInfo();
70765ffd83dbSDimitry Andric   MachineInstr *OffsetInst = MRI.getVRegDef(Offset.getReg());
70775ffd83dbSDimitry Andric 
70785ffd83dbSDimitry Andric   unsigned OffsetOpc = OffsetInst->getOpcode();
7079eaeb601bSDimitry Andric   bool LookedThroughZExt = false;
7080eaeb601bSDimitry Andric   if (OffsetOpc != TargetOpcode::G_SHL && OffsetOpc != TargetOpcode::G_MUL) {
7081eaeb601bSDimitry Andric     // Try to look through a ZEXT.
7082eaeb601bSDimitry Andric     if (OffsetOpc != TargetOpcode::G_ZEXT || !WantsExt)
7083bdd1243dSDimitry Andric       return std::nullopt;
70845ffd83dbSDimitry Andric 
7085eaeb601bSDimitry Andric     OffsetInst = MRI.getVRegDef(OffsetInst->getOperand(1).getReg());
7086eaeb601bSDimitry Andric     OffsetOpc = OffsetInst->getOpcode();
7087eaeb601bSDimitry Andric     LookedThroughZExt = true;
7088eaeb601bSDimitry Andric 
7089eaeb601bSDimitry Andric     if (OffsetOpc != TargetOpcode::G_SHL && OffsetOpc != TargetOpcode::G_MUL)
7090bdd1243dSDimitry Andric       return std::nullopt;
7091eaeb601bSDimitry Andric   }
70925ffd83dbSDimitry Andric   // Make sure that the memory op is a valid size.
70935ffd83dbSDimitry Andric   int64_t LegalShiftVal = Log2_32(SizeInBytes);
70945ffd83dbSDimitry Andric   if (LegalShiftVal == 0)
7095bdd1243dSDimitry Andric     return std::nullopt;
7096*0fca6ea1SDimitry Andric   if (!isWorthFoldingIntoExtendedReg(*OffsetInst, MRI, true))
7097bdd1243dSDimitry Andric     return std::nullopt;
70985ffd83dbSDimitry Andric 
70995ffd83dbSDimitry Andric   // Now, try to find the specific G_CONSTANT. Start by assuming that the
71005ffd83dbSDimitry Andric   // register we will offset is the LHS, and the register containing the
71015ffd83dbSDimitry Andric   // constant is the RHS.
71025ffd83dbSDimitry Andric   Register OffsetReg = OffsetInst->getOperand(1).getReg();
71035ffd83dbSDimitry Andric   Register ConstantReg = OffsetInst->getOperand(2).getReg();
7104349cc55cSDimitry Andric   auto ValAndVReg = getIConstantVRegValWithLookThrough(ConstantReg, MRI);
71055ffd83dbSDimitry Andric   if (!ValAndVReg) {
71065ffd83dbSDimitry Andric     // We didn't get a constant on the RHS. If the opcode is a shift, then
71075ffd83dbSDimitry Andric     // we're done.
71085ffd83dbSDimitry Andric     if (OffsetOpc == TargetOpcode::G_SHL)
7109bdd1243dSDimitry Andric       return std::nullopt;
71105ffd83dbSDimitry Andric 
71115ffd83dbSDimitry Andric     // If we have a G_MUL, we can use either register. Try looking at the RHS.
71125ffd83dbSDimitry Andric     std::swap(OffsetReg, ConstantReg);
7113349cc55cSDimitry Andric     ValAndVReg = getIConstantVRegValWithLookThrough(ConstantReg, MRI);
71145ffd83dbSDimitry Andric     if (!ValAndVReg)
7115bdd1243dSDimitry Andric       return std::nullopt;
71165ffd83dbSDimitry Andric   }
71175ffd83dbSDimitry Andric 
71185ffd83dbSDimitry Andric   // The value must fit into 3 bits, and must be positive. Make sure that is
71195ffd83dbSDimitry Andric   // true.
7120e8d8bef9SDimitry Andric   int64_t ImmVal = ValAndVReg->Value.getSExtValue();
71215ffd83dbSDimitry Andric 
71225ffd83dbSDimitry Andric   // Since we're going to pull this into a shift, the constant value must be
71235ffd83dbSDimitry Andric   // a power of 2. If we got a multiply, then we need to check this.
71245ffd83dbSDimitry Andric   if (OffsetOpc == TargetOpcode::G_MUL) {
712506c3fb27SDimitry Andric     if (!llvm::has_single_bit<uint32_t>(ImmVal))
7126bdd1243dSDimitry Andric       return std::nullopt;
71275ffd83dbSDimitry Andric 
71285ffd83dbSDimitry Andric     // Got a power of 2. So, the amount we'll shift is the log base-2 of that.
71295ffd83dbSDimitry Andric     ImmVal = Log2_32(ImmVal);
71305ffd83dbSDimitry Andric   }
71315ffd83dbSDimitry Andric 
71325ffd83dbSDimitry Andric   if ((ImmVal & 0x7) != ImmVal)
7133bdd1243dSDimitry Andric     return std::nullopt;
71345ffd83dbSDimitry Andric 
71355ffd83dbSDimitry Andric   // We are only allowed to shift by LegalShiftVal. This shift value is built
71365ffd83dbSDimitry Andric   // into the instruction, so we can't just use whatever we want.
71375ffd83dbSDimitry Andric   if (ImmVal != LegalShiftVal)
7138bdd1243dSDimitry Andric     return std::nullopt;
71395ffd83dbSDimitry Andric 
71405ffd83dbSDimitry Andric   unsigned SignExtend = 0;
71415ffd83dbSDimitry Andric   if (WantsExt) {
7142eaeb601bSDimitry Andric     // Check if the offset is defined by an extend, unless we looked through a
7143eaeb601bSDimitry Andric     // G_ZEXT earlier.
7144eaeb601bSDimitry Andric     if (!LookedThroughZExt) {
71455ffd83dbSDimitry Andric       MachineInstr *ExtInst = getDefIgnoringCopies(OffsetReg, MRI);
71465ffd83dbSDimitry Andric       auto Ext = getExtendTypeForInst(*ExtInst, MRI, true);
71475ffd83dbSDimitry Andric       if (Ext == AArch64_AM::InvalidShiftExtend)
7148bdd1243dSDimitry Andric         return std::nullopt;
71495ffd83dbSDimitry Andric 
71505ffd83dbSDimitry Andric       SignExtend = isSignExtendShiftType(Ext) ? 1 : 0;
71515ffd83dbSDimitry Andric       // We only support SXTW for signed extension here.
71525ffd83dbSDimitry Andric       if (SignExtend && Ext != AArch64_AM::SXTW)
7153bdd1243dSDimitry Andric         return std::nullopt;
7154eaeb601bSDimitry Andric       OffsetReg = ExtInst->getOperand(1).getReg();
7155eaeb601bSDimitry Andric     }
71565ffd83dbSDimitry Andric 
71575ffd83dbSDimitry Andric     // Need a 32-bit wide register here.
71585ffd83dbSDimitry Andric     MachineIRBuilder MIB(*MRI.getVRegDef(Root.getReg()));
7159eaeb601bSDimitry Andric     OffsetReg = moveScalarRegClass(OffsetReg, AArch64::GPR32RegClass, MIB);
71605ffd83dbSDimitry Andric   }
71615ffd83dbSDimitry Andric 
71625ffd83dbSDimitry Andric   // We can use the LHS of the GEP as the base, and the LHS of the shift as an
71635ffd83dbSDimitry Andric   // offset. Signify that we are shifting by setting the shift flag to 1.
71645ffd83dbSDimitry Andric   return {{[=](MachineInstrBuilder &MIB) { MIB.addUse(Base.getReg()); },
71655ffd83dbSDimitry Andric            [=](MachineInstrBuilder &MIB) { MIB.addUse(OffsetReg); },
71665ffd83dbSDimitry Andric            [=](MachineInstrBuilder &MIB) {
71675ffd83dbSDimitry Andric              // Need to add both immediates here to make sure that they are both
71685ffd83dbSDimitry Andric              // added to the instruction.
71695ffd83dbSDimitry Andric              MIB.addImm(SignExtend);
71705ffd83dbSDimitry Andric              MIB.addImm(1);
71715ffd83dbSDimitry Andric            }}};
71725ffd83dbSDimitry Andric }
71735ffd83dbSDimitry Andric 
71745ffd83dbSDimitry Andric /// This is used for computing addresses like this:
71755ffd83dbSDimitry Andric ///
71765ffd83dbSDimitry Andric /// ldr x1, [x2, x3, lsl #3]
71775ffd83dbSDimitry Andric ///
71785ffd83dbSDimitry Andric /// Where x2 is the base register, and x3 is an offset register. The shift-left
71795ffd83dbSDimitry Andric /// is a constant value specific to this load instruction. That is, we'll never
71805ffd83dbSDimitry Andric /// see anything other than a 3 here (which corresponds to the size of the
71815ffd83dbSDimitry Andric /// element being loaded.)
71825ffd83dbSDimitry Andric InstructionSelector::ComplexRendererFns
selectAddrModeShiftedExtendXReg(MachineOperand & Root,unsigned SizeInBytes) const71835ffd83dbSDimitry Andric AArch64InstructionSelector::selectAddrModeShiftedExtendXReg(
71845ffd83dbSDimitry Andric     MachineOperand &Root, unsigned SizeInBytes) const {
71855ffd83dbSDimitry Andric   if (!Root.isReg())
7186bdd1243dSDimitry Andric     return std::nullopt;
71875ffd83dbSDimitry Andric   MachineRegisterInfo &MRI = Root.getParent()->getMF()->getRegInfo();
71885ffd83dbSDimitry Andric 
71895ffd83dbSDimitry Andric   // We want to find something like this:
71905ffd83dbSDimitry Andric   //
71915ffd83dbSDimitry Andric   // val = G_CONSTANT LegalShiftVal
71925ffd83dbSDimitry Andric   // shift = G_SHL off_reg val
71935ffd83dbSDimitry Andric   // ptr = G_PTR_ADD base_reg shift
71945ffd83dbSDimitry Andric   // x = G_LOAD ptr
71955ffd83dbSDimitry Andric   //
71965ffd83dbSDimitry Andric   // And fold it into this addressing mode:
71975ffd83dbSDimitry Andric   //
71985ffd83dbSDimitry Andric   // ldr x, [base_reg, off_reg, lsl #LegalShiftVal]
71995ffd83dbSDimitry Andric 
72005ffd83dbSDimitry Andric   // Check if we can find the G_PTR_ADD.
72015ffd83dbSDimitry Andric   MachineInstr *PtrAdd =
72025ffd83dbSDimitry Andric       getOpcodeDef(TargetOpcode::G_PTR_ADD, Root.getReg(), MRI);
7203*0fca6ea1SDimitry Andric   if (!PtrAdd || !isWorthFoldingIntoExtendedReg(*PtrAdd, MRI, true))
7204bdd1243dSDimitry Andric     return std::nullopt;
72055ffd83dbSDimitry Andric 
72065ffd83dbSDimitry Andric   // Now, try to match an opcode which will match our specific offset.
72075ffd83dbSDimitry Andric   // We want a G_SHL or a G_MUL.
72085ffd83dbSDimitry Andric   MachineInstr *OffsetInst =
72095ffd83dbSDimitry Andric       getDefIgnoringCopies(PtrAdd->getOperand(2).getReg(), MRI);
72105ffd83dbSDimitry Andric   return selectExtendedSHL(Root, PtrAdd->getOperand(1),
72115ffd83dbSDimitry Andric                            OffsetInst->getOperand(0), SizeInBytes,
72125ffd83dbSDimitry Andric                            /*WantsExt=*/false);
72135ffd83dbSDimitry Andric }
72145ffd83dbSDimitry Andric 
72155ffd83dbSDimitry Andric /// This is used for computing addresses like this:
72165ffd83dbSDimitry Andric ///
72175ffd83dbSDimitry Andric /// ldr x1, [x2, x3]
72185ffd83dbSDimitry Andric ///
72195ffd83dbSDimitry Andric /// Where x2 is the base register, and x3 is an offset register.
72205ffd83dbSDimitry Andric ///
7221bdd1243dSDimitry Andric /// When possible (or profitable) to fold a G_PTR_ADD into the address
7222bdd1243dSDimitry Andric /// calculation, this will do so. Otherwise, it will return std::nullopt.
72235ffd83dbSDimitry Andric InstructionSelector::ComplexRendererFns
selectAddrModeRegisterOffset(MachineOperand & Root) const72245ffd83dbSDimitry Andric AArch64InstructionSelector::selectAddrModeRegisterOffset(
72255ffd83dbSDimitry Andric     MachineOperand &Root) const {
72265ffd83dbSDimitry Andric   MachineRegisterInfo &MRI = Root.getParent()->getMF()->getRegInfo();
72275ffd83dbSDimitry Andric 
72285ffd83dbSDimitry Andric   // We need a GEP.
72295ffd83dbSDimitry Andric   MachineInstr *Gep = MRI.getVRegDef(Root.getReg());
723081ad6265SDimitry Andric   if (Gep->getOpcode() != TargetOpcode::G_PTR_ADD)
7231bdd1243dSDimitry Andric     return std::nullopt;
72325ffd83dbSDimitry Andric 
72335ffd83dbSDimitry Andric   // If this is used more than once, let's not bother folding.
72345ffd83dbSDimitry Andric   // TODO: Check if they are memory ops. If they are, then we can still fold
72355ffd83dbSDimitry Andric   // without having to recompute anything.
72365ffd83dbSDimitry Andric   if (!MRI.hasOneNonDBGUse(Gep->getOperand(0).getReg()))
7237bdd1243dSDimitry Andric     return std::nullopt;
72385ffd83dbSDimitry Andric 
72395ffd83dbSDimitry Andric   // Base is the GEP's LHS, offset is its RHS.
72405ffd83dbSDimitry Andric   return {{[=](MachineInstrBuilder &MIB) {
72415ffd83dbSDimitry Andric              MIB.addUse(Gep->getOperand(1).getReg());
72425ffd83dbSDimitry Andric            },
72435ffd83dbSDimitry Andric            [=](MachineInstrBuilder &MIB) {
72445ffd83dbSDimitry Andric              MIB.addUse(Gep->getOperand(2).getReg());
72455ffd83dbSDimitry Andric            },
72465ffd83dbSDimitry Andric            [=](MachineInstrBuilder &MIB) {
72475ffd83dbSDimitry Andric              // Need to add both immediates here to make sure that they are both
72485ffd83dbSDimitry Andric              // added to the instruction.
72495ffd83dbSDimitry Andric              MIB.addImm(0);
72505ffd83dbSDimitry Andric              MIB.addImm(0);
72515ffd83dbSDimitry Andric            }}};
72525ffd83dbSDimitry Andric }
72535ffd83dbSDimitry Andric 
72545ffd83dbSDimitry Andric /// This is intended to be equivalent to selectAddrModeXRO in
72555ffd83dbSDimitry Andric /// AArch64ISelDAGtoDAG. It's used for selecting X register offset loads.
72565ffd83dbSDimitry Andric InstructionSelector::ComplexRendererFns
selectAddrModeXRO(MachineOperand & Root,unsigned SizeInBytes) const72575ffd83dbSDimitry Andric AArch64InstructionSelector::selectAddrModeXRO(MachineOperand &Root,
72585ffd83dbSDimitry Andric                                               unsigned SizeInBytes) const {
72595ffd83dbSDimitry Andric   MachineRegisterInfo &MRI = Root.getParent()->getMF()->getRegInfo();
7260e8d8bef9SDimitry Andric   if (!Root.isReg())
7261bdd1243dSDimitry Andric     return std::nullopt;
7262e8d8bef9SDimitry Andric   MachineInstr *PtrAdd =
7263e8d8bef9SDimitry Andric       getOpcodeDef(TargetOpcode::G_PTR_ADD, Root.getReg(), MRI);
7264e8d8bef9SDimitry Andric   if (!PtrAdd)
7265bdd1243dSDimitry Andric     return std::nullopt;
7266e8d8bef9SDimitry Andric 
7267e8d8bef9SDimitry Andric   // Check for an immediates which cannot be encoded in the [base + imm]
7268e8d8bef9SDimitry Andric   // addressing mode, and can't be encoded in an add/sub. If this happens, we'll
7269e8d8bef9SDimitry Andric   // end up with code like:
7270e8d8bef9SDimitry Andric   //
7271e8d8bef9SDimitry Andric   // mov x0, wide
7272e8d8bef9SDimitry Andric   // add x1 base, x0
7273e8d8bef9SDimitry Andric   // ldr x2, [x1, x0]
7274e8d8bef9SDimitry Andric   //
7275e8d8bef9SDimitry Andric   // In this situation, we can use the [base, xreg] addressing mode to save an
7276e8d8bef9SDimitry Andric   // add/sub:
7277e8d8bef9SDimitry Andric   //
7278e8d8bef9SDimitry Andric   // mov x0, wide
7279e8d8bef9SDimitry Andric   // ldr x2, [base, x0]
7280e8d8bef9SDimitry Andric   auto ValAndVReg =
7281349cc55cSDimitry Andric       getIConstantVRegValWithLookThrough(PtrAdd->getOperand(2).getReg(), MRI);
7282e8d8bef9SDimitry Andric   if (ValAndVReg) {
7283e8d8bef9SDimitry Andric     unsigned Scale = Log2_32(SizeInBytes);
7284e8d8bef9SDimitry Andric     int64_t ImmOff = ValAndVReg->Value.getSExtValue();
7285e8d8bef9SDimitry Andric 
7286e8d8bef9SDimitry Andric     // Skip immediates that can be selected in the load/store addresing
7287e8d8bef9SDimitry Andric     // mode.
7288e8d8bef9SDimitry Andric     if (ImmOff % SizeInBytes == 0 && ImmOff >= 0 &&
7289e8d8bef9SDimitry Andric         ImmOff < (0x1000 << Scale))
7290bdd1243dSDimitry Andric       return std::nullopt;
7291e8d8bef9SDimitry Andric 
7292e8d8bef9SDimitry Andric     // Helper lambda to decide whether or not it is preferable to emit an add.
7293e8d8bef9SDimitry Andric     auto isPreferredADD = [](int64_t ImmOff) {
7294e8d8bef9SDimitry Andric       // Constants in [0x0, 0xfff] can be encoded in an add.
7295e8d8bef9SDimitry Andric       if ((ImmOff & 0xfffffffffffff000LL) == 0x0LL)
7296e8d8bef9SDimitry Andric         return true;
7297e8d8bef9SDimitry Andric 
7298e8d8bef9SDimitry Andric       // Can it be encoded in an add lsl #12?
7299e8d8bef9SDimitry Andric       if ((ImmOff & 0xffffffffff000fffLL) != 0x0LL)
7300e8d8bef9SDimitry Andric         return false;
7301e8d8bef9SDimitry Andric 
7302e8d8bef9SDimitry Andric       // It can be encoded in an add lsl #12, but we may not want to. If it is
7303e8d8bef9SDimitry Andric       // possible to select this as a single movz, then prefer that. A single
7304e8d8bef9SDimitry Andric       // movz is faster than an add with a shift.
7305e8d8bef9SDimitry Andric       return (ImmOff & 0xffffffffff00ffffLL) != 0x0LL &&
7306e8d8bef9SDimitry Andric              (ImmOff & 0xffffffffffff0fffLL) != 0x0LL;
7307e8d8bef9SDimitry Andric     };
7308e8d8bef9SDimitry Andric 
7309e8d8bef9SDimitry Andric     // If the immediate can be encoded in a single add/sub, then bail out.
7310e8d8bef9SDimitry Andric     if (isPreferredADD(ImmOff) || isPreferredADD(-ImmOff))
7311bdd1243dSDimitry Andric       return std::nullopt;
7312e8d8bef9SDimitry Andric   }
73135ffd83dbSDimitry Andric 
73145ffd83dbSDimitry Andric   // Try to fold shifts into the addressing mode.
73155ffd83dbSDimitry Andric   auto AddrModeFns = selectAddrModeShiftedExtendXReg(Root, SizeInBytes);
73165ffd83dbSDimitry Andric   if (AddrModeFns)
73175ffd83dbSDimitry Andric     return AddrModeFns;
73185ffd83dbSDimitry Andric 
73195ffd83dbSDimitry Andric   // If that doesn't work, see if it's possible to fold in registers from
73205ffd83dbSDimitry Andric   // a GEP.
73215ffd83dbSDimitry Andric   return selectAddrModeRegisterOffset(Root);
73225ffd83dbSDimitry Andric }
73235ffd83dbSDimitry Andric 
73245ffd83dbSDimitry Andric /// This is used for computing addresses like this:
73255ffd83dbSDimitry Andric ///
73265ffd83dbSDimitry Andric /// ldr x0, [xBase, wOffset, sxtw #LegalShiftVal]
73275ffd83dbSDimitry Andric ///
73285ffd83dbSDimitry Andric /// Where we have a 64-bit base register, a 32-bit offset register, and an
73295ffd83dbSDimitry Andric /// extend (which may or may not be signed).
73305ffd83dbSDimitry Andric InstructionSelector::ComplexRendererFns
selectAddrModeWRO(MachineOperand & Root,unsigned SizeInBytes) const73315ffd83dbSDimitry Andric AArch64InstructionSelector::selectAddrModeWRO(MachineOperand &Root,
73325ffd83dbSDimitry Andric                                               unsigned SizeInBytes) const {
73335ffd83dbSDimitry Andric   MachineRegisterInfo &MRI = Root.getParent()->getMF()->getRegInfo();
73345ffd83dbSDimitry Andric 
73355ffd83dbSDimitry Andric   MachineInstr *PtrAdd =
73365ffd83dbSDimitry Andric       getOpcodeDef(TargetOpcode::G_PTR_ADD, Root.getReg(), MRI);
7337*0fca6ea1SDimitry Andric   if (!PtrAdd || !isWorthFoldingIntoExtendedReg(*PtrAdd, MRI, true))
7338bdd1243dSDimitry Andric     return std::nullopt;
73395ffd83dbSDimitry Andric 
73405ffd83dbSDimitry Andric   MachineOperand &LHS = PtrAdd->getOperand(1);
73415ffd83dbSDimitry Andric   MachineOperand &RHS = PtrAdd->getOperand(2);
73425ffd83dbSDimitry Andric   MachineInstr *OffsetInst = getDefIgnoringCopies(RHS.getReg(), MRI);
73435ffd83dbSDimitry Andric 
73445ffd83dbSDimitry Andric   // The first case is the same as selectAddrModeXRO, except we need an extend.
73455ffd83dbSDimitry Andric   // In this case, we try to find a shift and extend, and fold them into the
73465ffd83dbSDimitry Andric   // addressing mode.
73475ffd83dbSDimitry Andric   //
73485ffd83dbSDimitry Andric   // E.g.
73495ffd83dbSDimitry Andric   //
73505ffd83dbSDimitry Andric   // off_reg = G_Z/S/ANYEXT ext_reg
73515ffd83dbSDimitry Andric   // val = G_CONSTANT LegalShiftVal
73525ffd83dbSDimitry Andric   // shift = G_SHL off_reg val
73535ffd83dbSDimitry Andric   // ptr = G_PTR_ADD base_reg shift
73545ffd83dbSDimitry Andric   // x = G_LOAD ptr
73555ffd83dbSDimitry Andric   //
73565ffd83dbSDimitry Andric   // In this case we can get a load like this:
73575ffd83dbSDimitry Andric   //
73585ffd83dbSDimitry Andric   // ldr x0, [base_reg, ext_reg, sxtw #LegalShiftVal]
73595ffd83dbSDimitry Andric   auto ExtendedShl = selectExtendedSHL(Root, LHS, OffsetInst->getOperand(0),
73605ffd83dbSDimitry Andric                                        SizeInBytes, /*WantsExt=*/true);
73615ffd83dbSDimitry Andric   if (ExtendedShl)
73625ffd83dbSDimitry Andric     return ExtendedShl;
73635ffd83dbSDimitry Andric 
73645ffd83dbSDimitry Andric   // There was no shift. We can try and fold a G_Z/S/ANYEXT in alone though.
73655ffd83dbSDimitry Andric   //
73665ffd83dbSDimitry Andric   // e.g.
73675ffd83dbSDimitry Andric   // ldr something, [base_reg, ext_reg, sxtw]
7368*0fca6ea1SDimitry Andric   if (!isWorthFoldingIntoExtendedReg(*OffsetInst, MRI, true))
7369bdd1243dSDimitry Andric     return std::nullopt;
73705ffd83dbSDimitry Andric 
73715ffd83dbSDimitry Andric   // Check if this is an extend. We'll get an extend type if it is.
73725ffd83dbSDimitry Andric   AArch64_AM::ShiftExtendType Ext =
73735ffd83dbSDimitry Andric       getExtendTypeForInst(*OffsetInst, MRI, /*IsLoadStore=*/true);
73745ffd83dbSDimitry Andric   if (Ext == AArch64_AM::InvalidShiftExtend)
7375bdd1243dSDimitry Andric     return std::nullopt;
73765ffd83dbSDimitry Andric 
73775ffd83dbSDimitry Andric   // Need a 32-bit wide register.
73785ffd83dbSDimitry Andric   MachineIRBuilder MIB(*PtrAdd);
7379eaeb601bSDimitry Andric   Register ExtReg = moveScalarRegClass(OffsetInst->getOperand(1).getReg(),
7380eaeb601bSDimitry Andric                                        AArch64::GPR32RegClass, MIB);
73815ffd83dbSDimitry Andric   unsigned SignExtend = Ext == AArch64_AM::SXTW;
73825ffd83dbSDimitry Andric 
73835ffd83dbSDimitry Andric   // Base is LHS, offset is ExtReg.
73845ffd83dbSDimitry Andric   return {{[=](MachineInstrBuilder &MIB) { MIB.addUse(LHS.getReg()); },
73855ffd83dbSDimitry Andric            [=](MachineInstrBuilder &MIB) { MIB.addUse(ExtReg); },
73865ffd83dbSDimitry Andric            [=](MachineInstrBuilder &MIB) {
73875ffd83dbSDimitry Andric              MIB.addImm(SignExtend);
73885ffd83dbSDimitry Andric              MIB.addImm(0);
73895ffd83dbSDimitry Andric            }}};
73905ffd83dbSDimitry Andric }
73915ffd83dbSDimitry Andric 
73925ffd83dbSDimitry Andric /// Select a "register plus unscaled signed 9-bit immediate" address.  This
73935ffd83dbSDimitry Andric /// should only match when there is an offset that is not valid for a scaled
73945ffd83dbSDimitry Andric /// immediate addressing mode.  The "Size" argument is the size in bytes of the
73955ffd83dbSDimitry Andric /// memory reference, which is needed here to know what is valid for a scaled
73965ffd83dbSDimitry Andric /// immediate.
73975ffd83dbSDimitry Andric InstructionSelector::ComplexRendererFns
selectAddrModeUnscaled(MachineOperand & Root,unsigned Size) const73985ffd83dbSDimitry Andric AArch64InstructionSelector::selectAddrModeUnscaled(MachineOperand &Root,
73995ffd83dbSDimitry Andric                                                    unsigned Size) const {
74005ffd83dbSDimitry Andric   MachineRegisterInfo &MRI =
74015ffd83dbSDimitry Andric       Root.getParent()->getParent()->getParent()->getRegInfo();
74025ffd83dbSDimitry Andric 
74035ffd83dbSDimitry Andric   if (!Root.isReg())
7404bdd1243dSDimitry Andric     return std::nullopt;
74055ffd83dbSDimitry Andric 
74065ffd83dbSDimitry Andric   if (!isBaseWithConstantOffset(Root, MRI))
7407bdd1243dSDimitry Andric     return std::nullopt;
74085ffd83dbSDimitry Andric 
74095ffd83dbSDimitry Andric   MachineInstr *RootDef = MRI.getVRegDef(Root.getReg());
74105ffd83dbSDimitry Andric 
74115ffd83dbSDimitry Andric   MachineOperand &OffImm = RootDef->getOperand(2);
74125ffd83dbSDimitry Andric   if (!OffImm.isReg())
7413bdd1243dSDimitry Andric     return std::nullopt;
74145ffd83dbSDimitry Andric   MachineInstr *RHS = MRI.getVRegDef(OffImm.getReg());
741581ad6265SDimitry Andric   if (RHS->getOpcode() != TargetOpcode::G_CONSTANT)
7416bdd1243dSDimitry Andric     return std::nullopt;
74175ffd83dbSDimitry Andric   int64_t RHSC;
74185ffd83dbSDimitry Andric   MachineOperand &RHSOp1 = RHS->getOperand(1);
74195ffd83dbSDimitry Andric   if (!RHSOp1.isCImm() || RHSOp1.getCImm()->getBitWidth() > 64)
7420bdd1243dSDimitry Andric     return std::nullopt;
74215ffd83dbSDimitry Andric   RHSC = RHSOp1.getCImm()->getSExtValue();
74225ffd83dbSDimitry Andric 
74235ffd83dbSDimitry Andric   if (RHSC >= -256 && RHSC < 256) {
74245ffd83dbSDimitry Andric     MachineOperand &Base = RootDef->getOperand(1);
74255ffd83dbSDimitry Andric     return {{
74265ffd83dbSDimitry Andric         [=](MachineInstrBuilder &MIB) { MIB.add(Base); },
74275ffd83dbSDimitry Andric         [=](MachineInstrBuilder &MIB) { MIB.addImm(RHSC); },
74285ffd83dbSDimitry Andric     }};
74295ffd83dbSDimitry Andric   }
7430bdd1243dSDimitry Andric   return std::nullopt;
74315ffd83dbSDimitry Andric }
74325ffd83dbSDimitry Andric 
74335ffd83dbSDimitry Andric InstructionSelector::ComplexRendererFns
tryFoldAddLowIntoImm(MachineInstr & RootDef,unsigned Size,MachineRegisterInfo & MRI) const74345ffd83dbSDimitry Andric AArch64InstructionSelector::tryFoldAddLowIntoImm(MachineInstr &RootDef,
74355ffd83dbSDimitry Andric                                                  unsigned Size,
74365ffd83dbSDimitry Andric                                                  MachineRegisterInfo &MRI) const {
74375ffd83dbSDimitry Andric   if (RootDef.getOpcode() != AArch64::G_ADD_LOW)
7438bdd1243dSDimitry Andric     return std::nullopt;
74395ffd83dbSDimitry Andric   MachineInstr &Adrp = *MRI.getVRegDef(RootDef.getOperand(1).getReg());
74405ffd83dbSDimitry Andric   if (Adrp.getOpcode() != AArch64::ADRP)
7441bdd1243dSDimitry Andric     return std::nullopt;
74425ffd83dbSDimitry Andric 
74435ffd83dbSDimitry Andric   // TODO: add heuristics like isWorthFoldingADDlow() from SelectionDAG.
7444fe6060f1SDimitry Andric   auto Offset = Adrp.getOperand(1).getOffset();
7445fe6060f1SDimitry Andric   if (Offset % Size != 0)
7446bdd1243dSDimitry Andric     return std::nullopt;
7447fe6060f1SDimitry Andric 
74485ffd83dbSDimitry Andric   auto GV = Adrp.getOperand(1).getGlobal();
74495ffd83dbSDimitry Andric   if (GV->isThreadLocal())
7450bdd1243dSDimitry Andric     return std::nullopt;
74515ffd83dbSDimitry Andric 
74525ffd83dbSDimitry Andric   auto &MF = *RootDef.getParent()->getParent();
74535ffd83dbSDimitry Andric   if (GV->getPointerAlignment(MF.getDataLayout()) < Size)
7454bdd1243dSDimitry Andric     return std::nullopt;
74555ffd83dbSDimitry Andric 
74565ffd83dbSDimitry Andric   unsigned OpFlags = STI.ClassifyGlobalReference(GV, MF.getTarget());
74575ffd83dbSDimitry Andric   MachineIRBuilder MIRBuilder(RootDef);
74585ffd83dbSDimitry Andric   Register AdrpReg = Adrp.getOperand(0).getReg();
74595ffd83dbSDimitry Andric   return {{[=](MachineInstrBuilder &MIB) { MIB.addUse(AdrpReg); },
74605ffd83dbSDimitry Andric            [=](MachineInstrBuilder &MIB) {
7461fe6060f1SDimitry Andric              MIB.addGlobalAddress(GV, Offset,
74625ffd83dbSDimitry Andric                                   OpFlags | AArch64II::MO_PAGEOFF |
74635ffd83dbSDimitry Andric                                       AArch64II::MO_NC);
74645ffd83dbSDimitry Andric            }}};
74655ffd83dbSDimitry Andric }
74665ffd83dbSDimitry Andric 
74675ffd83dbSDimitry Andric /// Select a "register plus scaled unsigned 12-bit immediate" address.  The
74685ffd83dbSDimitry Andric /// "Size" argument is the size in bytes of the memory reference, which
74695ffd83dbSDimitry Andric /// determines the scale.
74705ffd83dbSDimitry Andric InstructionSelector::ComplexRendererFns
selectAddrModeIndexed(MachineOperand & Root,unsigned Size) const74715ffd83dbSDimitry Andric AArch64InstructionSelector::selectAddrModeIndexed(MachineOperand &Root,
74725ffd83dbSDimitry Andric                                                   unsigned Size) const {
74735ffd83dbSDimitry Andric   MachineFunction &MF = *Root.getParent()->getParent()->getParent();
74745ffd83dbSDimitry Andric   MachineRegisterInfo &MRI = MF.getRegInfo();
74755ffd83dbSDimitry Andric 
74765ffd83dbSDimitry Andric   if (!Root.isReg())
7477bdd1243dSDimitry Andric     return std::nullopt;
74785ffd83dbSDimitry Andric 
74795ffd83dbSDimitry Andric   MachineInstr *RootDef = MRI.getVRegDef(Root.getReg());
74805ffd83dbSDimitry Andric   if (RootDef->getOpcode() == TargetOpcode::G_FRAME_INDEX) {
74815ffd83dbSDimitry Andric     return {{
74825ffd83dbSDimitry Andric         [=](MachineInstrBuilder &MIB) { MIB.add(RootDef->getOperand(1)); },
74835ffd83dbSDimitry Andric         [=](MachineInstrBuilder &MIB) { MIB.addImm(0); },
74845ffd83dbSDimitry Andric     }};
74855ffd83dbSDimitry Andric   }
74865ffd83dbSDimitry Andric 
74875ffd83dbSDimitry Andric   CodeModel::Model CM = MF.getTarget().getCodeModel();
74885ffd83dbSDimitry Andric   // Check if we can fold in the ADD of small code model ADRP + ADD address.
74895ffd83dbSDimitry Andric   if (CM == CodeModel::Small) {
74905ffd83dbSDimitry Andric     auto OpFns = tryFoldAddLowIntoImm(*RootDef, Size, MRI);
74915ffd83dbSDimitry Andric     if (OpFns)
74925ffd83dbSDimitry Andric       return OpFns;
74935ffd83dbSDimitry Andric   }
74945ffd83dbSDimitry Andric 
74955ffd83dbSDimitry Andric   if (isBaseWithConstantOffset(Root, MRI)) {
74965ffd83dbSDimitry Andric     MachineOperand &LHS = RootDef->getOperand(1);
74975ffd83dbSDimitry Andric     MachineOperand &RHS = RootDef->getOperand(2);
74985ffd83dbSDimitry Andric     MachineInstr *LHSDef = MRI.getVRegDef(LHS.getReg());
74995ffd83dbSDimitry Andric     MachineInstr *RHSDef = MRI.getVRegDef(RHS.getReg());
750081ad6265SDimitry Andric 
75015ffd83dbSDimitry Andric     int64_t RHSC = (int64_t)RHSDef->getOperand(1).getCImm()->getZExtValue();
75025ffd83dbSDimitry Andric     unsigned Scale = Log2_32(Size);
75035ffd83dbSDimitry Andric     if ((RHSC & (Size - 1)) == 0 && RHSC >= 0 && RHSC < (0x1000 << Scale)) {
75045ffd83dbSDimitry Andric       if (LHSDef->getOpcode() == TargetOpcode::G_FRAME_INDEX)
75055ffd83dbSDimitry Andric         return {{
75065ffd83dbSDimitry Andric             [=](MachineInstrBuilder &MIB) { MIB.add(LHSDef->getOperand(1)); },
75075ffd83dbSDimitry Andric             [=](MachineInstrBuilder &MIB) { MIB.addImm(RHSC >> Scale); },
75085ffd83dbSDimitry Andric         }};
75095ffd83dbSDimitry Andric 
75105ffd83dbSDimitry Andric       return {{
75115ffd83dbSDimitry Andric           [=](MachineInstrBuilder &MIB) { MIB.add(LHS); },
75125ffd83dbSDimitry Andric           [=](MachineInstrBuilder &MIB) { MIB.addImm(RHSC >> Scale); },
75135ffd83dbSDimitry Andric       }};
75145ffd83dbSDimitry Andric     }
75155ffd83dbSDimitry Andric   }
75165ffd83dbSDimitry Andric 
75175ffd83dbSDimitry Andric   // Before falling back to our general case, check if the unscaled
75185ffd83dbSDimitry Andric   // instructions can handle this. If so, that's preferable.
751981ad6265SDimitry Andric   if (selectAddrModeUnscaled(Root, Size))
7520bdd1243dSDimitry Andric     return std::nullopt;
75215ffd83dbSDimitry Andric 
75225ffd83dbSDimitry Andric   return {{
75235ffd83dbSDimitry Andric       [=](MachineInstrBuilder &MIB) { MIB.add(Root); },
75245ffd83dbSDimitry Andric       [=](MachineInstrBuilder &MIB) { MIB.addImm(0); },
75255ffd83dbSDimitry Andric   }};
75265ffd83dbSDimitry Andric }
75275ffd83dbSDimitry Andric 
75285ffd83dbSDimitry Andric /// Given a shift instruction, return the correct shift type for that
75295ffd83dbSDimitry Andric /// instruction.
getShiftTypeForInst(MachineInstr & MI)75305ffd83dbSDimitry Andric static AArch64_AM::ShiftExtendType getShiftTypeForInst(MachineInstr &MI) {
75315ffd83dbSDimitry Andric   switch (MI.getOpcode()) {
75325ffd83dbSDimitry Andric   default:
75335ffd83dbSDimitry Andric     return AArch64_AM::InvalidShiftExtend;
75345ffd83dbSDimitry Andric   case TargetOpcode::G_SHL:
75355ffd83dbSDimitry Andric     return AArch64_AM::LSL;
75365ffd83dbSDimitry Andric   case TargetOpcode::G_LSHR:
75375ffd83dbSDimitry Andric     return AArch64_AM::LSR;
75385ffd83dbSDimitry Andric   case TargetOpcode::G_ASHR:
75395ffd83dbSDimitry Andric     return AArch64_AM::ASR;
7540349cc55cSDimitry Andric   case TargetOpcode::G_ROTR:
7541349cc55cSDimitry Andric     return AArch64_AM::ROR;
75425ffd83dbSDimitry Andric   }
75435ffd83dbSDimitry Andric }
75445ffd83dbSDimitry Andric 
75455ffd83dbSDimitry Andric /// Select a "shifted register" operand. If the value is not shifted, set the
75465ffd83dbSDimitry Andric /// shift operand to a default value of "lsl 0".
75475ffd83dbSDimitry Andric InstructionSelector::ComplexRendererFns
selectShiftedRegister(MachineOperand & Root,bool AllowROR) const7548349cc55cSDimitry Andric AArch64InstructionSelector::selectShiftedRegister(MachineOperand &Root,
7549349cc55cSDimitry Andric                                                   bool AllowROR) const {
75505ffd83dbSDimitry Andric   if (!Root.isReg())
7551bdd1243dSDimitry Andric     return std::nullopt;
75525ffd83dbSDimitry Andric   MachineRegisterInfo &MRI =
75535ffd83dbSDimitry Andric       Root.getParent()->getParent()->getParent()->getRegInfo();
75545ffd83dbSDimitry Andric 
75555ffd83dbSDimitry Andric   // Check if the operand is defined by an instruction which corresponds to
75565ffd83dbSDimitry Andric   // a ShiftExtendType. E.g. a G_SHL, G_LSHR, etc.
75575ffd83dbSDimitry Andric   MachineInstr *ShiftInst = MRI.getVRegDef(Root.getReg());
75585ffd83dbSDimitry Andric   AArch64_AM::ShiftExtendType ShType = getShiftTypeForInst(*ShiftInst);
75595ffd83dbSDimitry Andric   if (ShType == AArch64_AM::InvalidShiftExtend)
7560bdd1243dSDimitry Andric     return std::nullopt;
7561349cc55cSDimitry Andric   if (ShType == AArch64_AM::ROR && !AllowROR)
7562bdd1243dSDimitry Andric     return std::nullopt;
7563*0fca6ea1SDimitry Andric   if (!isWorthFoldingIntoExtendedReg(*ShiftInst, MRI, false))
7564bdd1243dSDimitry Andric     return std::nullopt;
75655ffd83dbSDimitry Andric 
75665ffd83dbSDimitry Andric   // Need an immediate on the RHS.
75675ffd83dbSDimitry Andric   MachineOperand &ShiftRHS = ShiftInst->getOperand(2);
75685ffd83dbSDimitry Andric   auto Immed = getImmedFromMO(ShiftRHS);
75695ffd83dbSDimitry Andric   if (!Immed)
7570bdd1243dSDimitry Andric     return std::nullopt;
75715ffd83dbSDimitry Andric 
75725ffd83dbSDimitry Andric   // We have something that we can fold. Fold in the shift's LHS and RHS into
75735ffd83dbSDimitry Andric   // the instruction.
75745ffd83dbSDimitry Andric   MachineOperand &ShiftLHS = ShiftInst->getOperand(1);
75755ffd83dbSDimitry Andric   Register ShiftReg = ShiftLHS.getReg();
75765ffd83dbSDimitry Andric 
75775ffd83dbSDimitry Andric   unsigned NumBits = MRI.getType(ShiftReg).getSizeInBits();
75785ffd83dbSDimitry Andric   unsigned Val = *Immed & (NumBits - 1);
75795ffd83dbSDimitry Andric   unsigned ShiftVal = AArch64_AM::getShifterImm(ShType, Val);
75805ffd83dbSDimitry Andric 
75815ffd83dbSDimitry Andric   return {{[=](MachineInstrBuilder &MIB) { MIB.addUse(ShiftReg); },
75825ffd83dbSDimitry Andric            [=](MachineInstrBuilder &MIB) { MIB.addImm(ShiftVal); }}};
75835ffd83dbSDimitry Andric }
75845ffd83dbSDimitry Andric 
getExtendTypeForInst(MachineInstr & MI,MachineRegisterInfo & MRI,bool IsLoadStore) const75855ffd83dbSDimitry Andric AArch64_AM::ShiftExtendType AArch64InstructionSelector::getExtendTypeForInst(
75865ffd83dbSDimitry Andric     MachineInstr &MI, MachineRegisterInfo &MRI, bool IsLoadStore) const {
75875ffd83dbSDimitry Andric   unsigned Opc = MI.getOpcode();
75885ffd83dbSDimitry Andric 
75895ffd83dbSDimitry Andric   // Handle explicit extend instructions first.
75905ffd83dbSDimitry Andric   if (Opc == TargetOpcode::G_SEXT || Opc == TargetOpcode::G_SEXT_INREG) {
75915ffd83dbSDimitry Andric     unsigned Size;
75925ffd83dbSDimitry Andric     if (Opc == TargetOpcode::G_SEXT)
75935ffd83dbSDimitry Andric       Size = MRI.getType(MI.getOperand(1).getReg()).getSizeInBits();
75945ffd83dbSDimitry Andric     else
75955ffd83dbSDimitry Andric       Size = MI.getOperand(2).getImm();
75965ffd83dbSDimitry Andric     assert(Size != 64 && "Extend from 64 bits?");
75975ffd83dbSDimitry Andric     switch (Size) {
75985ffd83dbSDimitry Andric     case 8:
7599fe6060f1SDimitry Andric       return IsLoadStore ? AArch64_AM::InvalidShiftExtend : AArch64_AM::SXTB;
76005ffd83dbSDimitry Andric     case 16:
7601fe6060f1SDimitry Andric       return IsLoadStore ? AArch64_AM::InvalidShiftExtend : AArch64_AM::SXTH;
76025ffd83dbSDimitry Andric     case 32:
76035ffd83dbSDimitry Andric       return AArch64_AM::SXTW;
76045ffd83dbSDimitry Andric     default:
76055ffd83dbSDimitry Andric       return AArch64_AM::InvalidShiftExtend;
76065ffd83dbSDimitry Andric     }
76075ffd83dbSDimitry Andric   }
76085ffd83dbSDimitry Andric 
76095ffd83dbSDimitry Andric   if (Opc == TargetOpcode::G_ZEXT || Opc == TargetOpcode::G_ANYEXT) {
76105ffd83dbSDimitry Andric     unsigned Size = MRI.getType(MI.getOperand(1).getReg()).getSizeInBits();
76115ffd83dbSDimitry Andric     assert(Size != 64 && "Extend from 64 bits?");
76125ffd83dbSDimitry Andric     switch (Size) {
76135ffd83dbSDimitry Andric     case 8:
7614fe6060f1SDimitry Andric       return IsLoadStore ? AArch64_AM::InvalidShiftExtend : AArch64_AM::UXTB;
76155ffd83dbSDimitry Andric     case 16:
7616fe6060f1SDimitry Andric       return IsLoadStore ? AArch64_AM::InvalidShiftExtend : AArch64_AM::UXTH;
76175ffd83dbSDimitry Andric     case 32:
76185ffd83dbSDimitry Andric       return AArch64_AM::UXTW;
76195ffd83dbSDimitry Andric     default:
76205ffd83dbSDimitry Andric       return AArch64_AM::InvalidShiftExtend;
76215ffd83dbSDimitry Andric     }
76225ffd83dbSDimitry Andric   }
76235ffd83dbSDimitry Andric 
76245ffd83dbSDimitry Andric   // Don't have an explicit extend. Try to handle a G_AND with a constant mask
76255ffd83dbSDimitry Andric   // on the RHS.
76265ffd83dbSDimitry Andric   if (Opc != TargetOpcode::G_AND)
76275ffd83dbSDimitry Andric     return AArch64_AM::InvalidShiftExtend;
76285ffd83dbSDimitry Andric 
7629bdd1243dSDimitry Andric   std::optional<uint64_t> MaybeAndMask = getImmedFromMO(MI.getOperand(2));
76305ffd83dbSDimitry Andric   if (!MaybeAndMask)
76315ffd83dbSDimitry Andric     return AArch64_AM::InvalidShiftExtend;
76325ffd83dbSDimitry Andric   uint64_t AndMask = *MaybeAndMask;
76335ffd83dbSDimitry Andric   switch (AndMask) {
76345ffd83dbSDimitry Andric   default:
76355ffd83dbSDimitry Andric     return AArch64_AM::InvalidShiftExtend;
76365ffd83dbSDimitry Andric   case 0xFF:
76375ffd83dbSDimitry Andric     return !IsLoadStore ? AArch64_AM::UXTB : AArch64_AM::InvalidShiftExtend;
76385ffd83dbSDimitry Andric   case 0xFFFF:
76395ffd83dbSDimitry Andric     return !IsLoadStore ? AArch64_AM::UXTH : AArch64_AM::InvalidShiftExtend;
76405ffd83dbSDimitry Andric   case 0xFFFFFFFF:
76415ffd83dbSDimitry Andric     return AArch64_AM::UXTW;
76425ffd83dbSDimitry Andric   }
76435ffd83dbSDimitry Andric }
76445ffd83dbSDimitry Andric 
moveScalarRegClass(Register Reg,const TargetRegisterClass & RC,MachineIRBuilder & MIB) const7645eaeb601bSDimitry Andric Register AArch64InstructionSelector::moveScalarRegClass(
7646eaeb601bSDimitry Andric     Register Reg, const TargetRegisterClass &RC, MachineIRBuilder &MIB) const {
76475ffd83dbSDimitry Andric   MachineRegisterInfo &MRI = *MIB.getMRI();
7648eaeb601bSDimitry Andric   auto Ty = MRI.getType(Reg);
7649eaeb601bSDimitry Andric   assert(!Ty.isVector() && "Expected scalars only!");
7650eaeb601bSDimitry Andric   if (Ty.getSizeInBits() == TRI.getRegSizeInBits(RC))
7651eaeb601bSDimitry Andric     return Reg;
76525ffd83dbSDimitry Andric 
7653eaeb601bSDimitry Andric   // Create a copy and immediately select it.
7654eaeb601bSDimitry Andric   // FIXME: We should have an emitCopy function?
7655eaeb601bSDimitry Andric   auto Copy = MIB.buildCopy({&RC}, {Reg});
76565ffd83dbSDimitry Andric   selectCopy(*Copy, TII, MRI, TRI, RBI);
76575ffd83dbSDimitry Andric   return Copy.getReg(0);
76585ffd83dbSDimitry Andric }
76595ffd83dbSDimitry Andric 
76605ffd83dbSDimitry Andric /// Select an "extended register" operand. This operand folds in an extend
76615ffd83dbSDimitry Andric /// followed by an optional left shift.
76625ffd83dbSDimitry Andric InstructionSelector::ComplexRendererFns
selectArithExtendedRegister(MachineOperand & Root) const76635ffd83dbSDimitry Andric AArch64InstructionSelector::selectArithExtendedRegister(
76645ffd83dbSDimitry Andric     MachineOperand &Root) const {
76655ffd83dbSDimitry Andric   if (!Root.isReg())
7666bdd1243dSDimitry Andric     return std::nullopt;
76675ffd83dbSDimitry Andric   MachineRegisterInfo &MRI =
76685ffd83dbSDimitry Andric       Root.getParent()->getParent()->getParent()->getRegInfo();
76695ffd83dbSDimitry Andric 
76705ffd83dbSDimitry Andric   uint64_t ShiftVal = 0;
76715ffd83dbSDimitry Andric   Register ExtReg;
76725ffd83dbSDimitry Andric   AArch64_AM::ShiftExtendType Ext;
76735ffd83dbSDimitry Andric   MachineInstr *RootDef = getDefIgnoringCopies(Root.getReg(), MRI);
76745ffd83dbSDimitry Andric   if (!RootDef)
7675bdd1243dSDimitry Andric     return std::nullopt;
76765ffd83dbSDimitry Andric 
7677*0fca6ea1SDimitry Andric   if (!isWorthFoldingIntoExtendedReg(*RootDef, MRI, false))
7678bdd1243dSDimitry Andric     return std::nullopt;
76795ffd83dbSDimitry Andric 
76805ffd83dbSDimitry Andric   // Check if we can fold a shift and an extend.
76815ffd83dbSDimitry Andric   if (RootDef->getOpcode() == TargetOpcode::G_SHL) {
76825ffd83dbSDimitry Andric     // Look for a constant on the RHS of the shift.
76835ffd83dbSDimitry Andric     MachineOperand &RHS = RootDef->getOperand(2);
7684bdd1243dSDimitry Andric     std::optional<uint64_t> MaybeShiftVal = getImmedFromMO(RHS);
76855ffd83dbSDimitry Andric     if (!MaybeShiftVal)
7686bdd1243dSDimitry Andric       return std::nullopt;
76875ffd83dbSDimitry Andric     ShiftVal = *MaybeShiftVal;
76885ffd83dbSDimitry Andric     if (ShiftVal > 4)
7689bdd1243dSDimitry Andric       return std::nullopt;
76905ffd83dbSDimitry Andric     // Look for a valid extend instruction on the LHS of the shift.
76915ffd83dbSDimitry Andric     MachineOperand &LHS = RootDef->getOperand(1);
76925ffd83dbSDimitry Andric     MachineInstr *ExtDef = getDefIgnoringCopies(LHS.getReg(), MRI);
76935ffd83dbSDimitry Andric     if (!ExtDef)
7694bdd1243dSDimitry Andric       return std::nullopt;
76955ffd83dbSDimitry Andric     Ext = getExtendTypeForInst(*ExtDef, MRI);
76965ffd83dbSDimitry Andric     if (Ext == AArch64_AM::InvalidShiftExtend)
7697bdd1243dSDimitry Andric       return std::nullopt;
76985ffd83dbSDimitry Andric     ExtReg = ExtDef->getOperand(1).getReg();
76995ffd83dbSDimitry Andric   } else {
77005ffd83dbSDimitry Andric     // Didn't get a shift. Try just folding an extend.
77015ffd83dbSDimitry Andric     Ext = getExtendTypeForInst(*RootDef, MRI);
77025ffd83dbSDimitry Andric     if (Ext == AArch64_AM::InvalidShiftExtend)
7703bdd1243dSDimitry Andric       return std::nullopt;
77045ffd83dbSDimitry Andric     ExtReg = RootDef->getOperand(1).getReg();
77055ffd83dbSDimitry Andric 
77065ffd83dbSDimitry Andric     // If we have a 32 bit instruction which zeroes out the high half of a
77075ffd83dbSDimitry Andric     // register, we get an implicit zero extend for free. Check if we have one.
77085ffd83dbSDimitry Andric     // FIXME: We actually emit the extend right now even though we don't have
77095ffd83dbSDimitry Andric     // to.
77105ffd83dbSDimitry Andric     if (Ext == AArch64_AM::UXTW && MRI.getType(ExtReg).getSizeInBits() == 32) {
77115ffd83dbSDimitry Andric       MachineInstr *ExtInst = MRI.getVRegDef(ExtReg);
771281ad6265SDimitry Andric       if (isDef32(*ExtInst))
7713bdd1243dSDimitry Andric         return std::nullopt;
77145ffd83dbSDimitry Andric     }
77155ffd83dbSDimitry Andric   }
77165ffd83dbSDimitry Andric 
77175ffd83dbSDimitry Andric   // We require a GPR32 here. Narrow the ExtReg if needed using a subregister
77185ffd83dbSDimitry Andric   // copy.
77195ffd83dbSDimitry Andric   MachineIRBuilder MIB(*RootDef);
7720eaeb601bSDimitry Andric   ExtReg = moveScalarRegClass(ExtReg, AArch64::GPR32RegClass, MIB);
77215ffd83dbSDimitry Andric 
77225ffd83dbSDimitry Andric   return {{[=](MachineInstrBuilder &MIB) { MIB.addUse(ExtReg); },
77235ffd83dbSDimitry Andric            [=](MachineInstrBuilder &MIB) {
77245ffd83dbSDimitry Andric              MIB.addImm(getArithExtendImm(Ext, ShiftVal));
77255ffd83dbSDimitry Andric            }}};
77265ffd83dbSDimitry Andric }
77275ffd83dbSDimitry Andric 
772806c3fb27SDimitry Andric InstructionSelector::ComplexRendererFns
selectExtractHigh(MachineOperand & Root) const772906c3fb27SDimitry Andric AArch64InstructionSelector::selectExtractHigh(MachineOperand &Root) const {
773006c3fb27SDimitry Andric   if (!Root.isReg())
773106c3fb27SDimitry Andric     return std::nullopt;
773206c3fb27SDimitry Andric   MachineRegisterInfo &MRI =
773306c3fb27SDimitry Andric       Root.getParent()->getParent()->getParent()->getRegInfo();
773406c3fb27SDimitry Andric 
77355f757f3fSDimitry Andric   auto Extract = getDefSrcRegIgnoringCopies(Root.getReg(), MRI);
77365f757f3fSDimitry Andric   while (Extract && Extract->MI->getOpcode() == TargetOpcode::G_BITCAST &&
77375f757f3fSDimitry Andric          STI.isLittleEndian())
77385f757f3fSDimitry Andric     Extract =
77395f757f3fSDimitry Andric         getDefSrcRegIgnoringCopies(Extract->MI->getOperand(1).getReg(), MRI);
77405f757f3fSDimitry Andric   if (!Extract)
77415f757f3fSDimitry Andric     return std::nullopt;
77425f757f3fSDimitry Andric 
77435f757f3fSDimitry Andric   if (Extract->MI->getOpcode() == TargetOpcode::G_UNMERGE_VALUES) {
77445f757f3fSDimitry Andric     if (Extract->Reg == Extract->MI->getOperand(1).getReg()) {
77455f757f3fSDimitry Andric       Register ExtReg = Extract->MI->getOperand(2).getReg();
774606c3fb27SDimitry Andric       return {{[=](MachineInstrBuilder &MIB) { MIB.addUse(ExtReg); }}};
774706c3fb27SDimitry Andric     }
77485f757f3fSDimitry Andric   }
77495f757f3fSDimitry Andric   if (Extract->MI->getOpcode() == TargetOpcode::G_EXTRACT_VECTOR_ELT) {
77505f757f3fSDimitry Andric     LLT SrcTy = MRI.getType(Extract->MI->getOperand(1).getReg());
77515f757f3fSDimitry Andric     auto LaneIdx = getIConstantVRegValWithLookThrough(
77525f757f3fSDimitry Andric         Extract->MI->getOperand(2).getReg(), MRI);
77535f757f3fSDimitry Andric     if (LaneIdx && SrcTy == LLT::fixed_vector(2, 64) &&
77545f757f3fSDimitry Andric         LaneIdx->Value.getSExtValue() == 1) {
77555f757f3fSDimitry Andric       Register ExtReg = Extract->MI->getOperand(1).getReg();
77565f757f3fSDimitry Andric       return {{[=](MachineInstrBuilder &MIB) { MIB.addUse(ExtReg); }}};
77575f757f3fSDimitry Andric     }
77585f757f3fSDimitry Andric   }
775906c3fb27SDimitry Andric 
776006c3fb27SDimitry Andric   return std::nullopt;
776106c3fb27SDimitry Andric }
776206c3fb27SDimitry Andric 
renderTruncImm(MachineInstrBuilder & MIB,const MachineInstr & MI,int OpIdx) const77635ffd83dbSDimitry Andric void AArch64InstructionSelector::renderTruncImm(MachineInstrBuilder &MIB,
77645ffd83dbSDimitry Andric                                                 const MachineInstr &MI,
77655ffd83dbSDimitry Andric                                                 int OpIdx) const {
77665ffd83dbSDimitry Andric   const MachineRegisterInfo &MRI = MI.getParent()->getParent()->getRegInfo();
77675ffd83dbSDimitry Andric   assert(MI.getOpcode() == TargetOpcode::G_CONSTANT && OpIdx == -1 &&
77685ffd83dbSDimitry Andric          "Expected G_CONSTANT");
7769bdd1243dSDimitry Andric   std::optional<int64_t> CstVal =
7770349cc55cSDimitry Andric       getIConstantVRegSExtVal(MI.getOperand(0).getReg(), MRI);
77715ffd83dbSDimitry Andric   assert(CstVal && "Expected constant value");
777281ad6265SDimitry Andric   MIB.addImm(*CstVal);
77735ffd83dbSDimitry Andric }
77745ffd83dbSDimitry Andric 
renderLogicalImm32(MachineInstrBuilder & MIB,const MachineInstr & I,int OpIdx) const77755ffd83dbSDimitry Andric void AArch64InstructionSelector::renderLogicalImm32(
77765ffd83dbSDimitry Andric   MachineInstrBuilder &MIB, const MachineInstr &I, int OpIdx) const {
77775ffd83dbSDimitry Andric   assert(I.getOpcode() == TargetOpcode::G_CONSTANT && OpIdx == -1 &&
77785ffd83dbSDimitry Andric          "Expected G_CONSTANT");
77795ffd83dbSDimitry Andric   uint64_t CstVal = I.getOperand(1).getCImm()->getZExtValue();
77805ffd83dbSDimitry Andric   uint64_t Enc = AArch64_AM::encodeLogicalImmediate(CstVal, 32);
77815ffd83dbSDimitry Andric   MIB.addImm(Enc);
77825ffd83dbSDimitry Andric }
77835ffd83dbSDimitry Andric 
renderLogicalImm64(MachineInstrBuilder & MIB,const MachineInstr & I,int OpIdx) const77845ffd83dbSDimitry Andric void AArch64InstructionSelector::renderLogicalImm64(
77855ffd83dbSDimitry Andric   MachineInstrBuilder &MIB, const MachineInstr &I, int OpIdx) const {
77865ffd83dbSDimitry Andric   assert(I.getOpcode() == TargetOpcode::G_CONSTANT && OpIdx == -1 &&
77875ffd83dbSDimitry Andric          "Expected G_CONSTANT");
77885ffd83dbSDimitry Andric   uint64_t CstVal = I.getOperand(1).getCImm()->getZExtValue();
77895ffd83dbSDimitry Andric   uint64_t Enc = AArch64_AM::encodeLogicalImmediate(CstVal, 64);
77905ffd83dbSDimitry Andric   MIB.addImm(Enc);
77915ffd83dbSDimitry Andric }
77925ffd83dbSDimitry Andric 
renderUbsanTrap(MachineInstrBuilder & MIB,const MachineInstr & MI,int OpIdx) const7793*0fca6ea1SDimitry Andric void AArch64InstructionSelector::renderUbsanTrap(MachineInstrBuilder &MIB,
7794*0fca6ea1SDimitry Andric                                                  const MachineInstr &MI,
7795*0fca6ea1SDimitry Andric                                                  int OpIdx) const {
7796*0fca6ea1SDimitry Andric   assert(MI.getOpcode() == TargetOpcode::G_UBSANTRAP && OpIdx == 0 &&
7797*0fca6ea1SDimitry Andric          "Expected G_UBSANTRAP");
7798*0fca6ea1SDimitry Andric   MIB.addImm(MI.getOperand(0).getImm() | ('U' << 8));
7799*0fca6ea1SDimitry Andric }
7800*0fca6ea1SDimitry Andric 
renderFPImm16(MachineInstrBuilder & MIB,const MachineInstr & MI,int OpIdx) const7801fe6060f1SDimitry Andric void AArch64InstructionSelector::renderFPImm16(MachineInstrBuilder &MIB,
7802fe6060f1SDimitry Andric                                                const MachineInstr &MI,
7803fe6060f1SDimitry Andric                                                int OpIdx) const {
7804fe6060f1SDimitry Andric   assert(MI.getOpcode() == TargetOpcode::G_FCONSTANT && OpIdx == -1 &&
7805fe6060f1SDimitry Andric          "Expected G_FCONSTANT");
7806fe6060f1SDimitry Andric   MIB.addImm(
7807fe6060f1SDimitry Andric       AArch64_AM::getFP16Imm(MI.getOperand(1).getFPImm()->getValueAPF()));
7808fe6060f1SDimitry Andric }
7809fe6060f1SDimitry Andric 
renderFPImm32(MachineInstrBuilder & MIB,const MachineInstr & MI,int OpIdx) const7810fe6060f1SDimitry Andric void AArch64InstructionSelector::renderFPImm32(MachineInstrBuilder &MIB,
7811fe6060f1SDimitry Andric                                                const MachineInstr &MI,
7812fe6060f1SDimitry Andric                                                int OpIdx) const {
7813fe6060f1SDimitry Andric   assert(MI.getOpcode() == TargetOpcode::G_FCONSTANT && OpIdx == -1 &&
7814fe6060f1SDimitry Andric          "Expected G_FCONSTANT");
7815fe6060f1SDimitry Andric   MIB.addImm(
7816fe6060f1SDimitry Andric       AArch64_AM::getFP32Imm(MI.getOperand(1).getFPImm()->getValueAPF()));
7817fe6060f1SDimitry Andric }
7818fe6060f1SDimitry Andric 
renderFPImm64(MachineInstrBuilder & MIB,const MachineInstr & MI,int OpIdx) const7819fe6060f1SDimitry Andric void AArch64InstructionSelector::renderFPImm64(MachineInstrBuilder &MIB,
7820fe6060f1SDimitry Andric                                                const MachineInstr &MI,
7821fe6060f1SDimitry Andric                                                int OpIdx) const {
7822fe6060f1SDimitry Andric   assert(MI.getOpcode() == TargetOpcode::G_FCONSTANT && OpIdx == -1 &&
7823fe6060f1SDimitry Andric          "Expected G_FCONSTANT");
7824fe6060f1SDimitry Andric   MIB.addImm(
7825fe6060f1SDimitry Andric       AArch64_AM::getFP64Imm(MI.getOperand(1).getFPImm()->getValueAPF()));
7826fe6060f1SDimitry Andric }
7827fe6060f1SDimitry Andric 
renderFPImm32SIMDModImmType4(MachineInstrBuilder & MIB,const MachineInstr & MI,int OpIdx) const782881ad6265SDimitry Andric void AArch64InstructionSelector::renderFPImm32SIMDModImmType4(
782981ad6265SDimitry Andric     MachineInstrBuilder &MIB, const MachineInstr &MI, int OpIdx) const {
783081ad6265SDimitry Andric   assert(MI.getOpcode() == TargetOpcode::G_FCONSTANT && OpIdx == -1 &&
783181ad6265SDimitry Andric          "Expected G_FCONSTANT");
783281ad6265SDimitry Andric   MIB.addImm(AArch64_AM::encodeAdvSIMDModImmType4(MI.getOperand(1)
783381ad6265SDimitry Andric                                                       .getFPImm()
783481ad6265SDimitry Andric                                                       ->getValueAPF()
783581ad6265SDimitry Andric                                                       .bitcastToAPInt()
783681ad6265SDimitry Andric                                                       .getZExtValue()));
783781ad6265SDimitry Andric }
783881ad6265SDimitry Andric 
isLoadStoreOfNumBytes(const MachineInstr & MI,unsigned NumBytes) const78395ffd83dbSDimitry Andric bool AArch64InstructionSelector::isLoadStoreOfNumBytes(
78405ffd83dbSDimitry Andric     const MachineInstr &MI, unsigned NumBytes) const {
78415ffd83dbSDimitry Andric   if (!MI.mayLoadOrStore())
78425ffd83dbSDimitry Andric     return false;
78435ffd83dbSDimitry Andric   assert(MI.hasOneMemOperand() &&
78445ffd83dbSDimitry Andric          "Expected load/store to have only one mem op!");
78455ffd83dbSDimitry Andric   return (*MI.memoperands_begin())->getSize() == NumBytes;
78465ffd83dbSDimitry Andric }
78475ffd83dbSDimitry Andric 
isDef32(const MachineInstr & MI) const78485ffd83dbSDimitry Andric bool AArch64InstructionSelector::isDef32(const MachineInstr &MI) const {
78495ffd83dbSDimitry Andric   const MachineRegisterInfo &MRI = MI.getParent()->getParent()->getRegInfo();
78505ffd83dbSDimitry Andric   if (MRI.getType(MI.getOperand(0).getReg()).getSizeInBits() != 32)
78515ffd83dbSDimitry Andric     return false;
78525ffd83dbSDimitry Andric 
78535ffd83dbSDimitry Andric   // Only return true if we know the operation will zero-out the high half of
78545ffd83dbSDimitry Andric   // the 64-bit register. Truncates can be subregister copies, which don't
78555ffd83dbSDimitry Andric   // zero out the high bits. Copies and other copy-like instructions can be
78565ffd83dbSDimitry Andric   // fed by truncates, or could be lowered as subregister copies.
78575ffd83dbSDimitry Andric   switch (MI.getOpcode()) {
78585ffd83dbSDimitry Andric   default:
78595ffd83dbSDimitry Andric     return true;
78605ffd83dbSDimitry Andric   case TargetOpcode::COPY:
78615ffd83dbSDimitry Andric   case TargetOpcode::G_BITCAST:
78625ffd83dbSDimitry Andric   case TargetOpcode::G_TRUNC:
78635ffd83dbSDimitry Andric   case TargetOpcode::G_PHI:
78645ffd83dbSDimitry Andric     return false;
78655ffd83dbSDimitry Andric   }
78665ffd83dbSDimitry Andric }
78675ffd83dbSDimitry Andric 
78685ffd83dbSDimitry Andric 
78695ffd83dbSDimitry Andric // Perform fixups on the given PHI instruction's operands to force them all
78705ffd83dbSDimitry Andric // to be the same as the destination regbank.
fixupPHIOpBanks(MachineInstr & MI,MachineRegisterInfo & MRI,const AArch64RegisterBankInfo & RBI)78715ffd83dbSDimitry Andric static void fixupPHIOpBanks(MachineInstr &MI, MachineRegisterInfo &MRI,
78725ffd83dbSDimitry Andric                             const AArch64RegisterBankInfo &RBI) {
78735ffd83dbSDimitry Andric   assert(MI.getOpcode() == TargetOpcode::G_PHI && "Expected a G_PHI");
78745ffd83dbSDimitry Andric   Register DstReg = MI.getOperand(0).getReg();
78755ffd83dbSDimitry Andric   const RegisterBank *DstRB = MRI.getRegBankOrNull(DstReg);
78765ffd83dbSDimitry Andric   assert(DstRB && "Expected PHI dst to have regbank assigned");
78775ffd83dbSDimitry Andric   MachineIRBuilder MIB(MI);
78785ffd83dbSDimitry Andric 
78795ffd83dbSDimitry Andric   // Go through each operand and ensure it has the same regbank.
78804824e7fdSDimitry Andric   for (MachineOperand &MO : llvm::drop_begin(MI.operands())) {
78815ffd83dbSDimitry Andric     if (!MO.isReg())
78825ffd83dbSDimitry Andric       continue;
78835ffd83dbSDimitry Andric     Register OpReg = MO.getReg();
78845ffd83dbSDimitry Andric     const RegisterBank *RB = MRI.getRegBankOrNull(OpReg);
78855ffd83dbSDimitry Andric     if (RB != DstRB) {
78865ffd83dbSDimitry Andric       // Insert a cross-bank copy.
78875ffd83dbSDimitry Andric       auto *OpDef = MRI.getVRegDef(OpReg);
78885ffd83dbSDimitry Andric       const LLT &Ty = MRI.getType(OpReg);
7889fe6060f1SDimitry Andric       MachineBasicBlock &OpDefBB = *OpDef->getParent();
7890fe6060f1SDimitry Andric 
7891fe6060f1SDimitry Andric       // Any instruction we insert must appear after all PHIs in the block
7892fe6060f1SDimitry Andric       // for the block to be valid MIR.
7893fe6060f1SDimitry Andric       MachineBasicBlock::iterator InsertPt = std::next(OpDef->getIterator());
7894fe6060f1SDimitry Andric       if (InsertPt != OpDefBB.end() && InsertPt->isPHI())
7895fe6060f1SDimitry Andric         InsertPt = OpDefBB.getFirstNonPHI();
7896fe6060f1SDimitry Andric       MIB.setInsertPt(*OpDef->getParent(), InsertPt);
78975ffd83dbSDimitry Andric       auto Copy = MIB.buildCopy(Ty, OpReg);
78985ffd83dbSDimitry Andric       MRI.setRegBank(Copy.getReg(0), *DstRB);
78995ffd83dbSDimitry Andric       MO.setReg(Copy.getReg(0));
79005ffd83dbSDimitry Andric     }
79015ffd83dbSDimitry Andric   }
79025ffd83dbSDimitry Andric }
79035ffd83dbSDimitry Andric 
processPHIs(MachineFunction & MF)79045ffd83dbSDimitry Andric void AArch64InstructionSelector::processPHIs(MachineFunction &MF) {
79055ffd83dbSDimitry Andric   // We're looking for PHIs, build a list so we don't invalidate iterators.
79065ffd83dbSDimitry Andric   MachineRegisterInfo &MRI = MF.getRegInfo();
79075ffd83dbSDimitry Andric   SmallVector<MachineInstr *, 32> Phis;
79085ffd83dbSDimitry Andric   for (auto &BB : MF) {
79095ffd83dbSDimitry Andric     for (auto &MI : BB) {
79105ffd83dbSDimitry Andric       if (MI.getOpcode() == TargetOpcode::G_PHI)
79115ffd83dbSDimitry Andric         Phis.emplace_back(&MI);
79125ffd83dbSDimitry Andric     }
79135ffd83dbSDimitry Andric   }
79145ffd83dbSDimitry Andric 
79155ffd83dbSDimitry Andric   for (auto *MI : Phis) {
79165ffd83dbSDimitry Andric     // We need to do some work here if the operand types are < 16 bit and they
79175ffd83dbSDimitry Andric     // are split across fpr/gpr banks. Since all types <32b on gpr
79185ffd83dbSDimitry Andric     // end up being assigned gpr32 regclasses, we can end up with PHIs here
79195ffd83dbSDimitry Andric     // which try to select between a gpr32 and an fpr16. Ideally RBS shouldn't
79205ffd83dbSDimitry Andric     // be selecting heterogenous regbanks for operands if possible, but we
79215ffd83dbSDimitry Andric     // still need to be able to deal with it here.
79225ffd83dbSDimitry Andric     //
79235ffd83dbSDimitry Andric     // To fix this, if we have a gpr-bank operand < 32b in size and at least
79245ffd83dbSDimitry Andric     // one other operand is on the fpr bank, then we add cross-bank copies
79255ffd83dbSDimitry Andric     // to homogenize the operand banks. For simplicity the bank that we choose
79265ffd83dbSDimitry Andric     // to settle on is whatever bank the def operand has. For example:
79275ffd83dbSDimitry Andric     //
79285ffd83dbSDimitry Andric     // %endbb:
79295ffd83dbSDimitry Andric     //   %dst:gpr(s16) = G_PHI %in1:gpr(s16), %bb1, %in2:fpr(s16), %bb2
79305ffd83dbSDimitry Andric     //  =>
79315ffd83dbSDimitry Andric     // %bb2:
79325ffd83dbSDimitry Andric     //   ...
79335ffd83dbSDimitry Andric     //   %in2_copy:gpr(s16) = COPY %in2:fpr(s16)
79345ffd83dbSDimitry Andric     //   ...
79355ffd83dbSDimitry Andric     // %endbb:
79365ffd83dbSDimitry Andric     //   %dst:gpr(s16) = G_PHI %in1:gpr(s16), %bb1, %in2_copy:gpr(s16), %bb2
79375ffd83dbSDimitry Andric     bool HasGPROp = false, HasFPROp = false;
79384824e7fdSDimitry Andric     for (const MachineOperand &MO : llvm::drop_begin(MI->operands())) {
79395ffd83dbSDimitry Andric       if (!MO.isReg())
79405ffd83dbSDimitry Andric         continue;
79415ffd83dbSDimitry Andric       const LLT &Ty = MRI.getType(MO.getReg());
79425ffd83dbSDimitry Andric       if (!Ty.isValid() || !Ty.isScalar())
79435ffd83dbSDimitry Andric         break;
79445ffd83dbSDimitry Andric       if (Ty.getSizeInBits() >= 32)
79455ffd83dbSDimitry Andric         break;
79465ffd83dbSDimitry Andric       const RegisterBank *RB = MRI.getRegBankOrNull(MO.getReg());
79475ffd83dbSDimitry Andric       // If for some reason we don't have a regbank yet. Don't try anything.
79485ffd83dbSDimitry Andric       if (!RB)
79495ffd83dbSDimitry Andric         break;
79505ffd83dbSDimitry Andric 
79515ffd83dbSDimitry Andric       if (RB->getID() == AArch64::GPRRegBankID)
79525ffd83dbSDimitry Andric         HasGPROp = true;
79535ffd83dbSDimitry Andric       else
79545ffd83dbSDimitry Andric         HasFPROp = true;
79555ffd83dbSDimitry Andric     }
79565ffd83dbSDimitry Andric     // We have heterogenous regbanks, need to fixup.
79575ffd83dbSDimitry Andric     if (HasGPROp && HasFPROp)
79585ffd83dbSDimitry Andric       fixupPHIOpBanks(*MI, MRI, RBI);
79595ffd83dbSDimitry Andric   }
79605ffd83dbSDimitry Andric }
79615ffd83dbSDimitry Andric 
79625ffd83dbSDimitry Andric namespace llvm {
79635ffd83dbSDimitry Andric InstructionSelector *
createAArch64InstructionSelector(const AArch64TargetMachine & TM,const AArch64Subtarget & Subtarget,const AArch64RegisterBankInfo & RBI)79645ffd83dbSDimitry Andric createAArch64InstructionSelector(const AArch64TargetMachine &TM,
7965*0fca6ea1SDimitry Andric                                  const AArch64Subtarget &Subtarget,
7966*0fca6ea1SDimitry Andric                                  const AArch64RegisterBankInfo &RBI) {
79675ffd83dbSDimitry Andric   return new AArch64InstructionSelector(TM, Subtarget, RBI);
79685ffd83dbSDimitry Andric }
79695ffd83dbSDimitry Andric }
7970