xref: /freebsd/contrib/llvm-project/llvm/lib/CodeGen/GlobalISel/LegalizerHelper.cpp (revision 7a6dacaca14b62ca4b74406814becb87a3fefac0)
10b57cec5SDimitry Andric //===-- llvm/CodeGen/GlobalISel/LegalizerHelper.cpp -----------------------===//
20b57cec5SDimitry Andric //
30b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
40b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
50b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
60b57cec5SDimitry Andric //
70b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
80b57cec5SDimitry Andric //
90b57cec5SDimitry Andric /// \file This file implements the LegalizerHelper class to legalize
100b57cec5SDimitry Andric /// individual instructions and the LegalizeMachineIR wrapper pass for the
110b57cec5SDimitry Andric /// primary legalization.
120b57cec5SDimitry Andric //
130b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
140b57cec5SDimitry Andric 
150b57cec5SDimitry Andric #include "llvm/CodeGen/GlobalISel/LegalizerHelper.h"
160b57cec5SDimitry Andric #include "llvm/CodeGen/GlobalISel/CallLowering.h"
170b57cec5SDimitry Andric #include "llvm/CodeGen/GlobalISel/GISelChangeObserver.h"
1806c3fb27SDimitry Andric #include "llvm/CodeGen/GlobalISel/GISelKnownBits.h"
1981ad6265SDimitry Andric #include "llvm/CodeGen/GlobalISel/GenericMachineInstrs.h"
200b57cec5SDimitry Andric #include "llvm/CodeGen/GlobalISel/LegalizerInfo.h"
21fe6060f1SDimitry Andric #include "llvm/CodeGen/GlobalISel/LostDebugLocObserver.h"
22e8d8bef9SDimitry Andric #include "llvm/CodeGen/GlobalISel/MIPatternMatch.h"
2381ad6265SDimitry Andric #include "llvm/CodeGen/GlobalISel/MachineIRBuilder.h"
24fe6060f1SDimitry Andric #include "llvm/CodeGen/GlobalISel/Utils.h"
2506c3fb27SDimitry Andric #include "llvm/CodeGen/MachineConstantPool.h"
2681ad6265SDimitry Andric #include "llvm/CodeGen/MachineFrameInfo.h"
270b57cec5SDimitry Andric #include "llvm/CodeGen/MachineRegisterInfo.h"
281db9f3b2SDimitry Andric #include "llvm/CodeGen/RuntimeLibcalls.h"
298bcb0991SDimitry Andric #include "llvm/CodeGen/TargetFrameLowering.h"
300b57cec5SDimitry Andric #include "llvm/CodeGen/TargetInstrInfo.h"
310b57cec5SDimitry Andric #include "llvm/CodeGen/TargetLowering.h"
32fe6060f1SDimitry Andric #include "llvm/CodeGen/TargetOpcodes.h"
330b57cec5SDimitry Andric #include "llvm/CodeGen/TargetSubtargetInfo.h"
34fe6060f1SDimitry Andric #include "llvm/IR/Instructions.h"
350b57cec5SDimitry Andric #include "llvm/Support/Debug.h"
360b57cec5SDimitry Andric #include "llvm/Support/MathExtras.h"
370b57cec5SDimitry Andric #include "llvm/Support/raw_ostream.h"
38349cc55cSDimitry Andric #include "llvm/Target/TargetMachine.h"
39bdd1243dSDimitry Andric #include <numeric>
40bdd1243dSDimitry Andric #include <optional>
410b57cec5SDimitry Andric 
420b57cec5SDimitry Andric #define DEBUG_TYPE "legalizer"
430b57cec5SDimitry Andric 
440b57cec5SDimitry Andric using namespace llvm;
450b57cec5SDimitry Andric using namespace LegalizeActions;
46e8d8bef9SDimitry Andric using namespace MIPatternMatch;
470b57cec5SDimitry Andric 
480b57cec5SDimitry Andric /// Try to break down \p OrigTy into \p NarrowTy sized pieces.
490b57cec5SDimitry Andric ///
500b57cec5SDimitry Andric /// Returns the number of \p NarrowTy elements needed to reconstruct \p OrigTy,
510b57cec5SDimitry Andric /// with any leftover piece as type \p LeftoverTy
520b57cec5SDimitry Andric ///
530b57cec5SDimitry Andric /// Returns -1 in the first element of the pair if the breakdown is not
540b57cec5SDimitry Andric /// satisfiable.
550b57cec5SDimitry Andric static std::pair<int, int>
560b57cec5SDimitry Andric getNarrowTypeBreakDown(LLT OrigTy, LLT NarrowTy, LLT &LeftoverTy) {
570b57cec5SDimitry Andric   assert(!LeftoverTy.isValid() && "this is an out argument");
580b57cec5SDimitry Andric 
590b57cec5SDimitry Andric   unsigned Size = OrigTy.getSizeInBits();
600b57cec5SDimitry Andric   unsigned NarrowSize = NarrowTy.getSizeInBits();
610b57cec5SDimitry Andric   unsigned NumParts = Size / NarrowSize;
620b57cec5SDimitry Andric   unsigned LeftoverSize = Size - NumParts * NarrowSize;
630b57cec5SDimitry Andric   assert(Size > NarrowSize);
640b57cec5SDimitry Andric 
650b57cec5SDimitry Andric   if (LeftoverSize == 0)
660b57cec5SDimitry Andric     return {NumParts, 0};
670b57cec5SDimitry Andric 
680b57cec5SDimitry Andric   if (NarrowTy.isVector()) {
690b57cec5SDimitry Andric     unsigned EltSize = OrigTy.getScalarSizeInBits();
700b57cec5SDimitry Andric     if (LeftoverSize % EltSize != 0)
710b57cec5SDimitry Andric       return {-1, -1};
72fe6060f1SDimitry Andric     LeftoverTy = LLT::scalarOrVector(
73fe6060f1SDimitry Andric         ElementCount::getFixed(LeftoverSize / EltSize), EltSize);
740b57cec5SDimitry Andric   } else {
750b57cec5SDimitry Andric     LeftoverTy = LLT::scalar(LeftoverSize);
760b57cec5SDimitry Andric   }
770b57cec5SDimitry Andric 
780b57cec5SDimitry Andric   int NumLeftover = LeftoverSize / LeftoverTy.getSizeInBits();
790b57cec5SDimitry Andric   return std::make_pair(NumParts, NumLeftover);
800b57cec5SDimitry Andric }
810b57cec5SDimitry Andric 
825ffd83dbSDimitry Andric static Type *getFloatTypeForLLT(LLVMContext &Ctx, LLT Ty) {
835ffd83dbSDimitry Andric 
845ffd83dbSDimitry Andric   if (!Ty.isScalar())
855ffd83dbSDimitry Andric     return nullptr;
865ffd83dbSDimitry Andric 
875ffd83dbSDimitry Andric   switch (Ty.getSizeInBits()) {
885ffd83dbSDimitry Andric   case 16:
895ffd83dbSDimitry Andric     return Type::getHalfTy(Ctx);
905ffd83dbSDimitry Andric   case 32:
915ffd83dbSDimitry Andric     return Type::getFloatTy(Ctx);
925ffd83dbSDimitry Andric   case 64:
935ffd83dbSDimitry Andric     return Type::getDoubleTy(Ctx);
94e8d8bef9SDimitry Andric   case 80:
95e8d8bef9SDimitry Andric     return Type::getX86_FP80Ty(Ctx);
965ffd83dbSDimitry Andric   case 128:
975ffd83dbSDimitry Andric     return Type::getFP128Ty(Ctx);
985ffd83dbSDimitry Andric   default:
995ffd83dbSDimitry Andric     return nullptr;
1005ffd83dbSDimitry Andric   }
1015ffd83dbSDimitry Andric }
1025ffd83dbSDimitry Andric 
1030b57cec5SDimitry Andric LegalizerHelper::LegalizerHelper(MachineFunction &MF,
1040b57cec5SDimitry Andric                                  GISelChangeObserver &Observer,
1050b57cec5SDimitry Andric                                  MachineIRBuilder &Builder)
1065ffd83dbSDimitry Andric     : MIRBuilder(Builder), Observer(Observer), MRI(MF.getRegInfo()),
107e8d8bef9SDimitry Andric       LI(*MF.getSubtarget().getLegalizerInfo()),
10806c3fb27SDimitry Andric       TLI(*MF.getSubtarget().getTargetLowering()), KB(nullptr) {}
1090b57cec5SDimitry Andric 
1100b57cec5SDimitry Andric LegalizerHelper::LegalizerHelper(MachineFunction &MF, const LegalizerInfo &LI,
1110b57cec5SDimitry Andric                                  GISelChangeObserver &Observer,
11206c3fb27SDimitry Andric                                  MachineIRBuilder &B, GISelKnownBits *KB)
113e8d8bef9SDimitry Andric     : MIRBuilder(B), Observer(Observer), MRI(MF.getRegInfo()), LI(LI),
11406c3fb27SDimitry Andric       TLI(*MF.getSubtarget().getTargetLowering()), KB(KB) {}
115e8d8bef9SDimitry Andric 
1160b57cec5SDimitry Andric LegalizerHelper::LegalizeResult
117fe6060f1SDimitry Andric LegalizerHelper::legalizeInstrStep(MachineInstr &MI,
118fe6060f1SDimitry Andric                                    LostDebugLocObserver &LocObserver) {
1195ffd83dbSDimitry Andric   LLVM_DEBUG(dbgs() << "Legalizing: " << MI);
1205ffd83dbSDimitry Andric 
1215ffd83dbSDimitry Andric   MIRBuilder.setInstrAndDebugLoc(MI);
1220b57cec5SDimitry Andric 
1235f757f3fSDimitry Andric   if (isa<GIntrinsic>(MI))
1245ffd83dbSDimitry Andric     return LI.legalizeIntrinsic(*this, MI) ? Legalized : UnableToLegalize;
1250b57cec5SDimitry Andric   auto Step = LI.getAction(MI, MRI);
1260b57cec5SDimitry Andric   switch (Step.Action) {
1270b57cec5SDimitry Andric   case Legal:
1280b57cec5SDimitry Andric     LLVM_DEBUG(dbgs() << ".. Already legal\n");
1290b57cec5SDimitry Andric     return AlreadyLegal;
1300b57cec5SDimitry Andric   case Libcall:
1310b57cec5SDimitry Andric     LLVM_DEBUG(dbgs() << ".. Convert to libcall\n");
132fe6060f1SDimitry Andric     return libcall(MI, LocObserver);
1330b57cec5SDimitry Andric   case NarrowScalar:
1340b57cec5SDimitry Andric     LLVM_DEBUG(dbgs() << ".. Narrow scalar\n");
1350b57cec5SDimitry Andric     return narrowScalar(MI, Step.TypeIdx, Step.NewType);
1360b57cec5SDimitry Andric   case WidenScalar:
1370b57cec5SDimitry Andric     LLVM_DEBUG(dbgs() << ".. Widen scalar\n");
1380b57cec5SDimitry Andric     return widenScalar(MI, Step.TypeIdx, Step.NewType);
1395ffd83dbSDimitry Andric   case Bitcast:
1405ffd83dbSDimitry Andric     LLVM_DEBUG(dbgs() << ".. Bitcast type\n");
1415ffd83dbSDimitry Andric     return bitcast(MI, Step.TypeIdx, Step.NewType);
1420b57cec5SDimitry Andric   case Lower:
1430b57cec5SDimitry Andric     LLVM_DEBUG(dbgs() << ".. Lower\n");
1440b57cec5SDimitry Andric     return lower(MI, Step.TypeIdx, Step.NewType);
1450b57cec5SDimitry Andric   case FewerElements:
1460b57cec5SDimitry Andric     LLVM_DEBUG(dbgs() << ".. Reduce number of elements\n");
1470b57cec5SDimitry Andric     return fewerElementsVector(MI, Step.TypeIdx, Step.NewType);
1480b57cec5SDimitry Andric   case MoreElements:
1490b57cec5SDimitry Andric     LLVM_DEBUG(dbgs() << ".. Increase number of elements\n");
1500b57cec5SDimitry Andric     return moreElementsVector(MI, Step.TypeIdx, Step.NewType);
1510b57cec5SDimitry Andric   case Custom:
1520b57cec5SDimitry Andric     LLVM_DEBUG(dbgs() << ".. Custom legalization\n");
1531db9f3b2SDimitry Andric     return LI.legalizeCustom(*this, MI, LocObserver) ? Legalized
1541db9f3b2SDimitry Andric                                                      : UnableToLegalize;
1550b57cec5SDimitry Andric   default:
1560b57cec5SDimitry Andric     LLVM_DEBUG(dbgs() << ".. Unable to legalize\n");
1570b57cec5SDimitry Andric     return UnableToLegalize;
1580b57cec5SDimitry Andric   }
1590b57cec5SDimitry Andric }
1600b57cec5SDimitry Andric 
1610b57cec5SDimitry Andric void LegalizerHelper::insertParts(Register DstReg,
1620b57cec5SDimitry Andric                                   LLT ResultTy, LLT PartTy,
1630b57cec5SDimitry Andric                                   ArrayRef<Register> PartRegs,
1640b57cec5SDimitry Andric                                   LLT LeftoverTy,
1650b57cec5SDimitry Andric                                   ArrayRef<Register> LeftoverRegs) {
1660b57cec5SDimitry Andric   if (!LeftoverTy.isValid()) {
1670b57cec5SDimitry Andric     assert(LeftoverRegs.empty());
1680b57cec5SDimitry Andric 
1690b57cec5SDimitry Andric     if (!ResultTy.isVector()) {
170bdd1243dSDimitry Andric       MIRBuilder.buildMergeLikeInstr(DstReg, PartRegs);
1710b57cec5SDimitry Andric       return;
1720b57cec5SDimitry Andric     }
1730b57cec5SDimitry Andric 
1740b57cec5SDimitry Andric     if (PartTy.isVector())
1750b57cec5SDimitry Andric       MIRBuilder.buildConcatVectors(DstReg, PartRegs);
1760b57cec5SDimitry Andric     else
1770b57cec5SDimitry Andric       MIRBuilder.buildBuildVector(DstReg, PartRegs);
1780b57cec5SDimitry Andric     return;
1790b57cec5SDimitry Andric   }
1800b57cec5SDimitry Andric 
1810eae32dcSDimitry Andric   // Merge sub-vectors with different number of elements and insert into DstReg.
1820eae32dcSDimitry Andric   if (ResultTy.isVector()) {
1830eae32dcSDimitry Andric     assert(LeftoverRegs.size() == 1 && "Expected one leftover register");
1840eae32dcSDimitry Andric     SmallVector<Register, 8> AllRegs;
1850eae32dcSDimitry Andric     for (auto Reg : concat<const Register>(PartRegs, LeftoverRegs))
1860eae32dcSDimitry Andric       AllRegs.push_back(Reg);
1870eae32dcSDimitry Andric     return mergeMixedSubvectors(DstReg, AllRegs);
1880eae32dcSDimitry Andric   }
1890eae32dcSDimitry Andric 
190fe6060f1SDimitry Andric   SmallVector<Register> GCDRegs;
191fe6060f1SDimitry Andric   LLT GCDTy = getGCDType(getGCDType(ResultTy, LeftoverTy), PartTy);
192fe6060f1SDimitry Andric   for (auto PartReg : concat<const Register>(PartRegs, LeftoverRegs))
193fe6060f1SDimitry Andric     extractGCDType(GCDRegs, GCDTy, PartReg);
194fe6060f1SDimitry Andric   LLT ResultLCMTy = buildLCMMergePieces(ResultTy, LeftoverTy, GCDTy, GCDRegs);
195fe6060f1SDimitry Andric   buildWidenedRemergeToDst(DstReg, ResultLCMTy, GCDRegs);
1960b57cec5SDimitry Andric }
1970b57cec5SDimitry Andric 
1980eae32dcSDimitry Andric void LegalizerHelper::appendVectorElts(SmallVectorImpl<Register> &Elts,
1990eae32dcSDimitry Andric                                        Register Reg) {
2000eae32dcSDimitry Andric   LLT Ty = MRI.getType(Reg);
2010eae32dcSDimitry Andric   SmallVector<Register, 8> RegElts;
202*7a6dacacSDimitry Andric   extractParts(Reg, Ty.getScalarType(), Ty.getNumElements(), RegElts,
203*7a6dacacSDimitry Andric                MIRBuilder, MRI);
2040eae32dcSDimitry Andric   Elts.append(RegElts);
2050eae32dcSDimitry Andric }
2060eae32dcSDimitry Andric 
2070eae32dcSDimitry Andric /// Merge \p PartRegs with different types into \p DstReg.
2080eae32dcSDimitry Andric void LegalizerHelper::mergeMixedSubvectors(Register DstReg,
2090eae32dcSDimitry Andric                                            ArrayRef<Register> PartRegs) {
2100eae32dcSDimitry Andric   SmallVector<Register, 8> AllElts;
2110eae32dcSDimitry Andric   for (unsigned i = 0; i < PartRegs.size() - 1; ++i)
2120eae32dcSDimitry Andric     appendVectorElts(AllElts, PartRegs[i]);
2130eae32dcSDimitry Andric 
2140eae32dcSDimitry Andric   Register Leftover = PartRegs[PartRegs.size() - 1];
2150eae32dcSDimitry Andric   if (MRI.getType(Leftover).isScalar())
2160eae32dcSDimitry Andric     AllElts.push_back(Leftover);
2170eae32dcSDimitry Andric   else
2180eae32dcSDimitry Andric     appendVectorElts(AllElts, Leftover);
2190eae32dcSDimitry Andric 
220bdd1243dSDimitry Andric   MIRBuilder.buildMergeLikeInstr(DstReg, AllElts);
2210eae32dcSDimitry Andric }
2220eae32dcSDimitry Andric 
223e8d8bef9SDimitry Andric /// Append the result registers of G_UNMERGE_VALUES \p MI to \p Regs.
2245ffd83dbSDimitry Andric static void getUnmergeResults(SmallVectorImpl<Register> &Regs,
2255ffd83dbSDimitry Andric                               const MachineInstr &MI) {
2265ffd83dbSDimitry Andric   assert(MI.getOpcode() == TargetOpcode::G_UNMERGE_VALUES);
2275ffd83dbSDimitry Andric 
228e8d8bef9SDimitry Andric   const int StartIdx = Regs.size();
2295ffd83dbSDimitry Andric   const int NumResults = MI.getNumOperands() - 1;
230e8d8bef9SDimitry Andric   Regs.resize(Regs.size() + NumResults);
2315ffd83dbSDimitry Andric   for (int I = 0; I != NumResults; ++I)
232e8d8bef9SDimitry Andric     Regs[StartIdx + I] = MI.getOperand(I).getReg();
2335ffd83dbSDimitry Andric }
2345ffd83dbSDimitry Andric 
235e8d8bef9SDimitry Andric void LegalizerHelper::extractGCDType(SmallVectorImpl<Register> &Parts,
236e8d8bef9SDimitry Andric                                      LLT GCDTy, Register SrcReg) {
2375ffd83dbSDimitry Andric   LLT SrcTy = MRI.getType(SrcReg);
2385ffd83dbSDimitry Andric   if (SrcTy == GCDTy) {
2395ffd83dbSDimitry Andric     // If the source already evenly divides the result type, we don't need to do
2405ffd83dbSDimitry Andric     // anything.
2415ffd83dbSDimitry Andric     Parts.push_back(SrcReg);
2425ffd83dbSDimitry Andric   } else {
2435ffd83dbSDimitry Andric     // Need to split into common type sized pieces.
2445ffd83dbSDimitry Andric     auto Unmerge = MIRBuilder.buildUnmerge(GCDTy, SrcReg);
2455ffd83dbSDimitry Andric     getUnmergeResults(Parts, *Unmerge);
2465ffd83dbSDimitry Andric   }
247e8d8bef9SDimitry Andric }
2485ffd83dbSDimitry Andric 
249e8d8bef9SDimitry Andric LLT LegalizerHelper::extractGCDType(SmallVectorImpl<Register> &Parts, LLT DstTy,
250e8d8bef9SDimitry Andric                                     LLT NarrowTy, Register SrcReg) {
251e8d8bef9SDimitry Andric   LLT SrcTy = MRI.getType(SrcReg);
252e8d8bef9SDimitry Andric   LLT GCDTy = getGCDType(getGCDType(SrcTy, NarrowTy), DstTy);
253e8d8bef9SDimitry Andric   extractGCDType(Parts, GCDTy, SrcReg);
2545ffd83dbSDimitry Andric   return GCDTy;
2555ffd83dbSDimitry Andric }
2565ffd83dbSDimitry Andric 
2575ffd83dbSDimitry Andric LLT LegalizerHelper::buildLCMMergePieces(LLT DstTy, LLT NarrowTy, LLT GCDTy,
2585ffd83dbSDimitry Andric                                          SmallVectorImpl<Register> &VRegs,
2595ffd83dbSDimitry Andric                                          unsigned PadStrategy) {
2605ffd83dbSDimitry Andric   LLT LCMTy = getLCMType(DstTy, NarrowTy);
2615ffd83dbSDimitry Andric 
2625ffd83dbSDimitry Andric   int NumParts = LCMTy.getSizeInBits() / NarrowTy.getSizeInBits();
2635ffd83dbSDimitry Andric   int NumSubParts = NarrowTy.getSizeInBits() / GCDTy.getSizeInBits();
2645ffd83dbSDimitry Andric   int NumOrigSrc = VRegs.size();
2655ffd83dbSDimitry Andric 
2665ffd83dbSDimitry Andric   Register PadReg;
2675ffd83dbSDimitry Andric 
2685ffd83dbSDimitry Andric   // Get a value we can use to pad the source value if the sources won't evenly
2695ffd83dbSDimitry Andric   // cover the result type.
2705ffd83dbSDimitry Andric   if (NumOrigSrc < NumParts * NumSubParts) {
2715ffd83dbSDimitry Andric     if (PadStrategy == TargetOpcode::G_ZEXT)
2725ffd83dbSDimitry Andric       PadReg = MIRBuilder.buildConstant(GCDTy, 0).getReg(0);
2735ffd83dbSDimitry Andric     else if (PadStrategy == TargetOpcode::G_ANYEXT)
2745ffd83dbSDimitry Andric       PadReg = MIRBuilder.buildUndef(GCDTy).getReg(0);
2755ffd83dbSDimitry Andric     else {
2765ffd83dbSDimitry Andric       assert(PadStrategy == TargetOpcode::G_SEXT);
2775ffd83dbSDimitry Andric 
2785ffd83dbSDimitry Andric       // Shift the sign bit of the low register through the high register.
2795ffd83dbSDimitry Andric       auto ShiftAmt =
2805ffd83dbSDimitry Andric         MIRBuilder.buildConstant(LLT::scalar(64), GCDTy.getSizeInBits() - 1);
2815ffd83dbSDimitry Andric       PadReg = MIRBuilder.buildAShr(GCDTy, VRegs.back(), ShiftAmt).getReg(0);
2825ffd83dbSDimitry Andric     }
2835ffd83dbSDimitry Andric   }
2845ffd83dbSDimitry Andric 
2855ffd83dbSDimitry Andric   // Registers for the final merge to be produced.
2865ffd83dbSDimitry Andric   SmallVector<Register, 4> Remerge(NumParts);
2875ffd83dbSDimitry Andric 
2885ffd83dbSDimitry Andric   // Registers needed for intermediate merges, which will be merged into a
2895ffd83dbSDimitry Andric   // source for Remerge.
2905ffd83dbSDimitry Andric   SmallVector<Register, 4> SubMerge(NumSubParts);
2915ffd83dbSDimitry Andric 
2925ffd83dbSDimitry Andric   // Once we've fully read off the end of the original source bits, we can reuse
2935ffd83dbSDimitry Andric   // the same high bits for remaining padding elements.
2945ffd83dbSDimitry Andric   Register AllPadReg;
2955ffd83dbSDimitry Andric 
2965ffd83dbSDimitry Andric   // Build merges to the LCM type to cover the original result type.
2975ffd83dbSDimitry Andric   for (int I = 0; I != NumParts; ++I) {
2985ffd83dbSDimitry Andric     bool AllMergePartsArePadding = true;
2995ffd83dbSDimitry Andric 
3005ffd83dbSDimitry Andric     // Build the requested merges to the requested type.
3015ffd83dbSDimitry Andric     for (int J = 0; J != NumSubParts; ++J) {
3025ffd83dbSDimitry Andric       int Idx = I * NumSubParts + J;
3035ffd83dbSDimitry Andric       if (Idx >= NumOrigSrc) {
3045ffd83dbSDimitry Andric         SubMerge[J] = PadReg;
3055ffd83dbSDimitry Andric         continue;
3065ffd83dbSDimitry Andric       }
3075ffd83dbSDimitry Andric 
3085ffd83dbSDimitry Andric       SubMerge[J] = VRegs[Idx];
3095ffd83dbSDimitry Andric 
3105ffd83dbSDimitry Andric       // There are meaningful bits here we can't reuse later.
3115ffd83dbSDimitry Andric       AllMergePartsArePadding = false;
3125ffd83dbSDimitry Andric     }
3135ffd83dbSDimitry Andric 
3145ffd83dbSDimitry Andric     // If we've filled up a complete piece with padding bits, we can directly
3155ffd83dbSDimitry Andric     // emit the natural sized constant if applicable, rather than a merge of
3165ffd83dbSDimitry Andric     // smaller constants.
3175ffd83dbSDimitry Andric     if (AllMergePartsArePadding && !AllPadReg) {
3185ffd83dbSDimitry Andric       if (PadStrategy == TargetOpcode::G_ANYEXT)
3195ffd83dbSDimitry Andric         AllPadReg = MIRBuilder.buildUndef(NarrowTy).getReg(0);
3205ffd83dbSDimitry Andric       else if (PadStrategy == TargetOpcode::G_ZEXT)
3215ffd83dbSDimitry Andric         AllPadReg = MIRBuilder.buildConstant(NarrowTy, 0).getReg(0);
3225ffd83dbSDimitry Andric 
3235ffd83dbSDimitry Andric       // If this is a sign extension, we can't materialize a trivial constant
3245ffd83dbSDimitry Andric       // with the right type and have to produce a merge.
3255ffd83dbSDimitry Andric     }
3265ffd83dbSDimitry Andric 
3275ffd83dbSDimitry Andric     if (AllPadReg) {
3285ffd83dbSDimitry Andric       // Avoid creating additional instructions if we're just adding additional
3295ffd83dbSDimitry Andric       // copies of padding bits.
3305ffd83dbSDimitry Andric       Remerge[I] = AllPadReg;
3315ffd83dbSDimitry Andric       continue;
3325ffd83dbSDimitry Andric     }
3335ffd83dbSDimitry Andric 
3345ffd83dbSDimitry Andric     if (NumSubParts == 1)
3355ffd83dbSDimitry Andric       Remerge[I] = SubMerge[0];
3365ffd83dbSDimitry Andric     else
337bdd1243dSDimitry Andric       Remerge[I] = MIRBuilder.buildMergeLikeInstr(NarrowTy, SubMerge).getReg(0);
3385ffd83dbSDimitry Andric 
3395ffd83dbSDimitry Andric     // In the sign extend padding case, re-use the first all-signbit merge.
3405ffd83dbSDimitry Andric     if (AllMergePartsArePadding && !AllPadReg)
3415ffd83dbSDimitry Andric       AllPadReg = Remerge[I];
3425ffd83dbSDimitry Andric   }
3435ffd83dbSDimitry Andric 
3445ffd83dbSDimitry Andric   VRegs = std::move(Remerge);
3455ffd83dbSDimitry Andric   return LCMTy;
3465ffd83dbSDimitry Andric }
3475ffd83dbSDimitry Andric 
3485ffd83dbSDimitry Andric void LegalizerHelper::buildWidenedRemergeToDst(Register DstReg, LLT LCMTy,
3495ffd83dbSDimitry Andric                                                ArrayRef<Register> RemergeRegs) {
3505ffd83dbSDimitry Andric   LLT DstTy = MRI.getType(DstReg);
3515ffd83dbSDimitry Andric 
3525ffd83dbSDimitry Andric   // Create the merge to the widened source, and extract the relevant bits into
3535ffd83dbSDimitry Andric   // the result.
3545ffd83dbSDimitry Andric 
3555ffd83dbSDimitry Andric   if (DstTy == LCMTy) {
356bdd1243dSDimitry Andric     MIRBuilder.buildMergeLikeInstr(DstReg, RemergeRegs);
3575ffd83dbSDimitry Andric     return;
3585ffd83dbSDimitry Andric   }
3595ffd83dbSDimitry Andric 
360bdd1243dSDimitry Andric   auto Remerge = MIRBuilder.buildMergeLikeInstr(LCMTy, RemergeRegs);
3615ffd83dbSDimitry Andric   if (DstTy.isScalar() && LCMTy.isScalar()) {
3625ffd83dbSDimitry Andric     MIRBuilder.buildTrunc(DstReg, Remerge);
3635ffd83dbSDimitry Andric     return;
3645ffd83dbSDimitry Andric   }
3655ffd83dbSDimitry Andric 
3665ffd83dbSDimitry Andric   if (LCMTy.isVector()) {
367e8d8bef9SDimitry Andric     unsigned NumDefs = LCMTy.getSizeInBits() / DstTy.getSizeInBits();
368e8d8bef9SDimitry Andric     SmallVector<Register, 8> UnmergeDefs(NumDefs);
369e8d8bef9SDimitry Andric     UnmergeDefs[0] = DstReg;
370e8d8bef9SDimitry Andric     for (unsigned I = 1; I != NumDefs; ++I)
371e8d8bef9SDimitry Andric       UnmergeDefs[I] = MRI.createGenericVirtualRegister(DstTy);
372e8d8bef9SDimitry Andric 
373e8d8bef9SDimitry Andric     MIRBuilder.buildUnmerge(UnmergeDefs,
374bdd1243dSDimitry Andric                             MIRBuilder.buildMergeLikeInstr(LCMTy, RemergeRegs));
3755ffd83dbSDimitry Andric     return;
3765ffd83dbSDimitry Andric   }
3775ffd83dbSDimitry Andric 
3785ffd83dbSDimitry Andric   llvm_unreachable("unhandled case");
3795ffd83dbSDimitry Andric }
3805ffd83dbSDimitry Andric 
3810b57cec5SDimitry Andric static RTLIB::Libcall getRTLibDesc(unsigned Opcode, unsigned Size) {
382e8d8bef9SDimitry Andric #define RTLIBCASE_INT(LibcallPrefix)                                           \
3835ffd83dbSDimitry Andric   do {                                                                         \
3845ffd83dbSDimitry Andric     switch (Size) {                                                            \
3855ffd83dbSDimitry Andric     case 32:                                                                   \
3865ffd83dbSDimitry Andric       return RTLIB::LibcallPrefix##32;                                         \
3875ffd83dbSDimitry Andric     case 64:                                                                   \
3885ffd83dbSDimitry Andric       return RTLIB::LibcallPrefix##64;                                         \
3895ffd83dbSDimitry Andric     case 128:                                                                  \
3905ffd83dbSDimitry Andric       return RTLIB::LibcallPrefix##128;                                        \
3915ffd83dbSDimitry Andric     default:                                                                   \
3925ffd83dbSDimitry Andric       llvm_unreachable("unexpected size");                                     \
3935ffd83dbSDimitry Andric     }                                                                          \
3945ffd83dbSDimitry Andric   } while (0)
3955ffd83dbSDimitry Andric 
396e8d8bef9SDimitry Andric #define RTLIBCASE(LibcallPrefix)                                               \
397e8d8bef9SDimitry Andric   do {                                                                         \
398e8d8bef9SDimitry Andric     switch (Size) {                                                            \
399e8d8bef9SDimitry Andric     case 32:                                                                   \
400e8d8bef9SDimitry Andric       return RTLIB::LibcallPrefix##32;                                         \
401e8d8bef9SDimitry Andric     case 64:                                                                   \
402e8d8bef9SDimitry Andric       return RTLIB::LibcallPrefix##64;                                         \
403e8d8bef9SDimitry Andric     case 80:                                                                   \
404e8d8bef9SDimitry Andric       return RTLIB::LibcallPrefix##80;                                         \
405e8d8bef9SDimitry Andric     case 128:                                                                  \
406e8d8bef9SDimitry Andric       return RTLIB::LibcallPrefix##128;                                        \
407e8d8bef9SDimitry Andric     default:                                                                   \
408e8d8bef9SDimitry Andric       llvm_unreachable("unexpected size");                                     \
409e8d8bef9SDimitry Andric     }                                                                          \
410e8d8bef9SDimitry Andric   } while (0)
4115ffd83dbSDimitry Andric 
4120b57cec5SDimitry Andric   switch (Opcode) {
413bdd1243dSDimitry Andric   case TargetOpcode::G_MUL:
414bdd1243dSDimitry Andric     RTLIBCASE_INT(MUL_I);
4150b57cec5SDimitry Andric   case TargetOpcode::G_SDIV:
416e8d8bef9SDimitry Andric     RTLIBCASE_INT(SDIV_I);
4170b57cec5SDimitry Andric   case TargetOpcode::G_UDIV:
418e8d8bef9SDimitry Andric     RTLIBCASE_INT(UDIV_I);
4190b57cec5SDimitry Andric   case TargetOpcode::G_SREM:
420e8d8bef9SDimitry Andric     RTLIBCASE_INT(SREM_I);
4210b57cec5SDimitry Andric   case TargetOpcode::G_UREM:
422e8d8bef9SDimitry Andric     RTLIBCASE_INT(UREM_I);
4230b57cec5SDimitry Andric   case TargetOpcode::G_CTLZ_ZERO_UNDEF:
424e8d8bef9SDimitry Andric     RTLIBCASE_INT(CTLZ_I);
4250b57cec5SDimitry Andric   case TargetOpcode::G_FADD:
4265ffd83dbSDimitry Andric     RTLIBCASE(ADD_F);
4270b57cec5SDimitry Andric   case TargetOpcode::G_FSUB:
4285ffd83dbSDimitry Andric     RTLIBCASE(SUB_F);
4290b57cec5SDimitry Andric   case TargetOpcode::G_FMUL:
4305ffd83dbSDimitry Andric     RTLIBCASE(MUL_F);
4310b57cec5SDimitry Andric   case TargetOpcode::G_FDIV:
4325ffd83dbSDimitry Andric     RTLIBCASE(DIV_F);
4330b57cec5SDimitry Andric   case TargetOpcode::G_FEXP:
4345ffd83dbSDimitry Andric     RTLIBCASE(EXP_F);
4350b57cec5SDimitry Andric   case TargetOpcode::G_FEXP2:
4365ffd83dbSDimitry Andric     RTLIBCASE(EXP2_F);
4375f757f3fSDimitry Andric   case TargetOpcode::G_FEXP10:
4385f757f3fSDimitry Andric     RTLIBCASE(EXP10_F);
4390b57cec5SDimitry Andric   case TargetOpcode::G_FREM:
4405ffd83dbSDimitry Andric     RTLIBCASE(REM_F);
4410b57cec5SDimitry Andric   case TargetOpcode::G_FPOW:
4425ffd83dbSDimitry Andric     RTLIBCASE(POW_F);
4431db9f3b2SDimitry Andric   case TargetOpcode::G_FPOWI:
4441db9f3b2SDimitry Andric     RTLIBCASE(POWI_F);
4450b57cec5SDimitry Andric   case TargetOpcode::G_FMA:
4465ffd83dbSDimitry Andric     RTLIBCASE(FMA_F);
4470b57cec5SDimitry Andric   case TargetOpcode::G_FSIN:
4485ffd83dbSDimitry Andric     RTLIBCASE(SIN_F);
4490b57cec5SDimitry Andric   case TargetOpcode::G_FCOS:
4505ffd83dbSDimitry Andric     RTLIBCASE(COS_F);
4510b57cec5SDimitry Andric   case TargetOpcode::G_FLOG10:
4525ffd83dbSDimitry Andric     RTLIBCASE(LOG10_F);
4530b57cec5SDimitry Andric   case TargetOpcode::G_FLOG:
4545ffd83dbSDimitry Andric     RTLIBCASE(LOG_F);
4550b57cec5SDimitry Andric   case TargetOpcode::G_FLOG2:
4565ffd83dbSDimitry Andric     RTLIBCASE(LOG2_F);
45706c3fb27SDimitry Andric   case TargetOpcode::G_FLDEXP:
45806c3fb27SDimitry Andric     RTLIBCASE(LDEXP_F);
4590b57cec5SDimitry Andric   case TargetOpcode::G_FCEIL:
4605ffd83dbSDimitry Andric     RTLIBCASE(CEIL_F);
4610b57cec5SDimitry Andric   case TargetOpcode::G_FFLOOR:
4625ffd83dbSDimitry Andric     RTLIBCASE(FLOOR_F);
4635ffd83dbSDimitry Andric   case TargetOpcode::G_FMINNUM:
4645ffd83dbSDimitry Andric     RTLIBCASE(FMIN_F);
4655ffd83dbSDimitry Andric   case TargetOpcode::G_FMAXNUM:
4665ffd83dbSDimitry Andric     RTLIBCASE(FMAX_F);
4675ffd83dbSDimitry Andric   case TargetOpcode::G_FSQRT:
4685ffd83dbSDimitry Andric     RTLIBCASE(SQRT_F);
4695ffd83dbSDimitry Andric   case TargetOpcode::G_FRINT:
4705ffd83dbSDimitry Andric     RTLIBCASE(RINT_F);
4715ffd83dbSDimitry Andric   case TargetOpcode::G_FNEARBYINT:
4725ffd83dbSDimitry Andric     RTLIBCASE(NEARBYINT_F);
473e8d8bef9SDimitry Andric   case TargetOpcode::G_INTRINSIC_ROUNDEVEN:
474e8d8bef9SDimitry Andric     RTLIBCASE(ROUNDEVEN_F);
4750b57cec5SDimitry Andric   }
4760b57cec5SDimitry Andric   llvm_unreachable("Unknown libcall function");
4770b57cec5SDimitry Andric }
4780b57cec5SDimitry Andric 
4798bcb0991SDimitry Andric /// True if an instruction is in tail position in its caller. Intended for
4808bcb0991SDimitry Andric /// legalizing libcalls as tail calls when possible.
4811db9f3b2SDimitry Andric static bool isLibCallInTailPosition(const CallLowering::ArgInfo &Result,
4821db9f3b2SDimitry Andric                                     MachineInstr &MI,
483fe6060f1SDimitry Andric                                     const TargetInstrInfo &TII,
484fe6060f1SDimitry Andric                                     MachineRegisterInfo &MRI) {
4855ffd83dbSDimitry Andric   MachineBasicBlock &MBB = *MI.getParent();
4865ffd83dbSDimitry Andric   const Function &F = MBB.getParent()->getFunction();
4878bcb0991SDimitry Andric 
4888bcb0991SDimitry Andric   // Conservatively require the attributes of the call to match those of
4898bcb0991SDimitry Andric   // the return. Ignore NoAlias and NonNull because they don't affect the
4908bcb0991SDimitry Andric   // call sequence.
4918bcb0991SDimitry Andric   AttributeList CallerAttrs = F.getAttributes();
49204eeddc0SDimitry Andric   if (AttrBuilder(F.getContext(), CallerAttrs.getRetAttrs())
4938bcb0991SDimitry Andric           .removeAttribute(Attribute::NoAlias)
4948bcb0991SDimitry Andric           .removeAttribute(Attribute::NonNull)
4958bcb0991SDimitry Andric           .hasAttributes())
4968bcb0991SDimitry Andric     return false;
4978bcb0991SDimitry Andric 
4988bcb0991SDimitry Andric   // It's not safe to eliminate the sign / zero extension of the return value.
499349cc55cSDimitry Andric   if (CallerAttrs.hasRetAttr(Attribute::ZExt) ||
500349cc55cSDimitry Andric       CallerAttrs.hasRetAttr(Attribute::SExt))
5018bcb0991SDimitry Andric     return false;
5028bcb0991SDimitry Andric 
503fe6060f1SDimitry Andric   // Only tail call if the following instruction is a standard return or if we
504fe6060f1SDimitry Andric   // have a `thisreturn` callee, and a sequence like:
505fe6060f1SDimitry Andric   //
506fe6060f1SDimitry Andric   //   G_MEMCPY %0, %1, %2
507fe6060f1SDimitry Andric   //   $x0 = COPY %0
508fe6060f1SDimitry Andric   //   RET_ReallyLR implicit $x0
5095ffd83dbSDimitry Andric   auto Next = next_nodbg(MI.getIterator(), MBB.instr_end());
510fe6060f1SDimitry Andric   if (Next != MBB.instr_end() && Next->isCopy()) {
5111db9f3b2SDimitry Andric     if (MI.getOpcode() == TargetOpcode::G_BZERO)
512fe6060f1SDimitry Andric       return false;
513fe6060f1SDimitry Andric 
5141db9f3b2SDimitry Andric     // For MEMCPY/MOMMOVE/MEMSET these will be the first use (the dst), as the
5151db9f3b2SDimitry Andric     // mempy/etc routines return the same parameter. For other it will be the
5161db9f3b2SDimitry Andric     // returned value.
517fe6060f1SDimitry Andric     Register VReg = MI.getOperand(0).getReg();
518fe6060f1SDimitry Andric     if (!VReg.isVirtual() || VReg != Next->getOperand(1).getReg())
519fe6060f1SDimitry Andric       return false;
520fe6060f1SDimitry Andric 
521fe6060f1SDimitry Andric     Register PReg = Next->getOperand(0).getReg();
522fe6060f1SDimitry Andric     if (!PReg.isPhysical())
523fe6060f1SDimitry Andric       return false;
524fe6060f1SDimitry Andric 
525fe6060f1SDimitry Andric     auto Ret = next_nodbg(Next, MBB.instr_end());
526fe6060f1SDimitry Andric     if (Ret == MBB.instr_end() || !Ret->isReturn())
527fe6060f1SDimitry Andric       return false;
528fe6060f1SDimitry Andric 
529fe6060f1SDimitry Andric     if (Ret->getNumImplicitOperands() != 1)
530fe6060f1SDimitry Andric       return false;
531fe6060f1SDimitry Andric 
5321db9f3b2SDimitry Andric     if (!Ret->getOperand(0).isReg() || PReg != Ret->getOperand(0).getReg())
533fe6060f1SDimitry Andric       return false;
534fe6060f1SDimitry Andric 
535fe6060f1SDimitry Andric     // Skip over the COPY that we just validated.
536fe6060f1SDimitry Andric     Next = Ret;
537fe6060f1SDimitry Andric   }
538fe6060f1SDimitry Andric 
5395ffd83dbSDimitry Andric   if (Next == MBB.instr_end() || TII.isTailCall(*Next) || !Next->isReturn())
5408bcb0991SDimitry Andric     return false;
5418bcb0991SDimitry Andric 
5428bcb0991SDimitry Andric   return true;
5438bcb0991SDimitry Andric }
5448bcb0991SDimitry Andric 
5450b57cec5SDimitry Andric LegalizerHelper::LegalizeResult
5465ffd83dbSDimitry Andric llvm::createLibcall(MachineIRBuilder &MIRBuilder, const char *Name,
5470b57cec5SDimitry Andric                     const CallLowering::ArgInfo &Result,
5485ffd83dbSDimitry Andric                     ArrayRef<CallLowering::ArgInfo> Args,
5491db9f3b2SDimitry Andric                     const CallingConv::ID CC, LostDebugLocObserver &LocObserver,
5501db9f3b2SDimitry Andric                     MachineInstr *MI) {
5510b57cec5SDimitry Andric   auto &CLI = *MIRBuilder.getMF().getSubtarget().getCallLowering();
5520b57cec5SDimitry Andric 
5538bcb0991SDimitry Andric   CallLowering::CallLoweringInfo Info;
5545ffd83dbSDimitry Andric   Info.CallConv = CC;
5558bcb0991SDimitry Andric   Info.Callee = MachineOperand::CreateES(Name);
5568bcb0991SDimitry Andric   Info.OrigRet = Result;
5571db9f3b2SDimitry Andric   if (MI)
5581db9f3b2SDimitry Andric     Info.IsTailCall =
5591db9f3b2SDimitry Andric         (Result.Ty->isVoidTy() ||
5601db9f3b2SDimitry Andric          Result.Ty == MIRBuilder.getMF().getFunction().getReturnType()) &&
5611db9f3b2SDimitry Andric         isLibCallInTailPosition(Result, *MI, MIRBuilder.getTII(),
5621db9f3b2SDimitry Andric                                 *MIRBuilder.getMRI());
5631db9f3b2SDimitry Andric 
5648bcb0991SDimitry Andric   std::copy(Args.begin(), Args.end(), std::back_inserter(Info.OrigArgs));
5658bcb0991SDimitry Andric   if (!CLI.lowerCall(MIRBuilder, Info))
5660b57cec5SDimitry Andric     return LegalizerHelper::UnableToLegalize;
5670b57cec5SDimitry Andric 
5681db9f3b2SDimitry Andric   if (MI && Info.LoweredTailCall) {
5691db9f3b2SDimitry Andric     assert(Info.IsTailCall && "Lowered tail call when it wasn't a tail call?");
5701db9f3b2SDimitry Andric 
5711db9f3b2SDimitry Andric     // Check debug locations before removing the return.
5721db9f3b2SDimitry Andric     LocObserver.checkpoint(true);
5731db9f3b2SDimitry Andric 
5741db9f3b2SDimitry Andric     // We must have a return following the call (or debug insts) to get past
5751db9f3b2SDimitry Andric     // isLibCallInTailPosition.
5761db9f3b2SDimitry Andric     do {
5771db9f3b2SDimitry Andric       MachineInstr *Next = MI->getNextNode();
5781db9f3b2SDimitry Andric       assert(Next &&
5791db9f3b2SDimitry Andric              (Next->isCopy() || Next->isReturn() || Next->isDebugInstr()) &&
5801db9f3b2SDimitry Andric              "Expected instr following MI to be return or debug inst?");
5811db9f3b2SDimitry Andric       // We lowered a tail call, so the call is now the return from the block.
5821db9f3b2SDimitry Andric       // Delete the old return.
5831db9f3b2SDimitry Andric       Next->eraseFromParent();
5841db9f3b2SDimitry Andric     } while (MI->getNextNode());
5851db9f3b2SDimitry Andric 
5861db9f3b2SDimitry Andric     // We expect to lose the debug location from the return.
5871db9f3b2SDimitry Andric     LocObserver.checkpoint(false);
5881db9f3b2SDimitry Andric   }
5890b57cec5SDimitry Andric   return LegalizerHelper::Legalized;
5900b57cec5SDimitry Andric }
5910b57cec5SDimitry Andric 
5925ffd83dbSDimitry Andric LegalizerHelper::LegalizeResult
5935ffd83dbSDimitry Andric llvm::createLibcall(MachineIRBuilder &MIRBuilder, RTLIB::Libcall Libcall,
5945ffd83dbSDimitry Andric                     const CallLowering::ArgInfo &Result,
5951db9f3b2SDimitry Andric                     ArrayRef<CallLowering::ArgInfo> Args,
5961db9f3b2SDimitry Andric                     LostDebugLocObserver &LocObserver, MachineInstr *MI) {
5975ffd83dbSDimitry Andric   auto &TLI = *MIRBuilder.getMF().getSubtarget().getTargetLowering();
5985ffd83dbSDimitry Andric   const char *Name = TLI.getLibcallName(Libcall);
5995ffd83dbSDimitry Andric   const CallingConv::ID CC = TLI.getLibcallCallingConv(Libcall);
6001db9f3b2SDimitry Andric   return createLibcall(MIRBuilder, Name, Result, Args, CC, LocObserver, MI);
6015ffd83dbSDimitry Andric }
6025ffd83dbSDimitry Andric 
6030b57cec5SDimitry Andric // Useful for libcalls where all operands have the same type.
6040b57cec5SDimitry Andric static LegalizerHelper::LegalizeResult
6050b57cec5SDimitry Andric simpleLibcall(MachineInstr &MI, MachineIRBuilder &MIRBuilder, unsigned Size,
6061db9f3b2SDimitry Andric               Type *OpType, LostDebugLocObserver &LocObserver) {
6070b57cec5SDimitry Andric   auto Libcall = getRTLibDesc(MI.getOpcode(), Size);
6080b57cec5SDimitry Andric 
609fe6060f1SDimitry Andric   // FIXME: What does the original arg index mean here?
6100b57cec5SDimitry Andric   SmallVector<CallLowering::ArgInfo, 3> Args;
6114824e7fdSDimitry Andric   for (const MachineOperand &MO : llvm::drop_begin(MI.operands()))
6124824e7fdSDimitry Andric     Args.push_back({MO.getReg(), OpType, 0});
613fe6060f1SDimitry Andric   return createLibcall(MIRBuilder, Libcall,
6141db9f3b2SDimitry Andric                        {MI.getOperand(0).getReg(), OpType, 0}, Args,
6151db9f3b2SDimitry Andric                        LocObserver, &MI);
6160b57cec5SDimitry Andric }
6170b57cec5SDimitry Andric 
6188bcb0991SDimitry Andric LegalizerHelper::LegalizeResult
6198bcb0991SDimitry Andric llvm::createMemLibcall(MachineIRBuilder &MIRBuilder, MachineRegisterInfo &MRI,
620fe6060f1SDimitry Andric                        MachineInstr &MI, LostDebugLocObserver &LocObserver) {
6218bcb0991SDimitry Andric   auto &Ctx = MIRBuilder.getMF().getFunction().getContext();
6228bcb0991SDimitry Andric 
6238bcb0991SDimitry Andric   SmallVector<CallLowering::ArgInfo, 3> Args;
6248bcb0991SDimitry Andric   // Add all the args, except for the last which is an imm denoting 'tail'.
625e8d8bef9SDimitry Andric   for (unsigned i = 0; i < MI.getNumOperands() - 1; ++i) {
6268bcb0991SDimitry Andric     Register Reg = MI.getOperand(i).getReg();
6278bcb0991SDimitry Andric 
6288bcb0991SDimitry Andric     // Need derive an IR type for call lowering.
6298bcb0991SDimitry Andric     LLT OpLLT = MRI.getType(Reg);
6308bcb0991SDimitry Andric     Type *OpTy = nullptr;
6318bcb0991SDimitry Andric     if (OpLLT.isPointer())
6325f757f3fSDimitry Andric       OpTy = PointerType::get(Ctx, OpLLT.getAddressSpace());
6338bcb0991SDimitry Andric     else
6348bcb0991SDimitry Andric       OpTy = IntegerType::get(Ctx, OpLLT.getSizeInBits());
635fe6060f1SDimitry Andric     Args.push_back({Reg, OpTy, 0});
6368bcb0991SDimitry Andric   }
6378bcb0991SDimitry Andric 
6388bcb0991SDimitry Andric   auto &CLI = *MIRBuilder.getMF().getSubtarget().getCallLowering();
6398bcb0991SDimitry Andric   auto &TLI = *MIRBuilder.getMF().getSubtarget().getTargetLowering();
6408bcb0991SDimitry Andric   RTLIB::Libcall RTLibcall;
641fe6060f1SDimitry Andric   unsigned Opc = MI.getOpcode();
642fe6060f1SDimitry Andric   switch (Opc) {
643fe6060f1SDimitry Andric   case TargetOpcode::G_BZERO:
644fe6060f1SDimitry Andric     RTLibcall = RTLIB::BZERO;
645fe6060f1SDimitry Andric     break;
646e8d8bef9SDimitry Andric   case TargetOpcode::G_MEMCPY:
6478bcb0991SDimitry Andric     RTLibcall = RTLIB::MEMCPY;
648fe6060f1SDimitry Andric     Args[0].Flags[0].setReturned();
6498bcb0991SDimitry Andric     break;
650e8d8bef9SDimitry Andric   case TargetOpcode::G_MEMMOVE:
6518bcb0991SDimitry Andric     RTLibcall = RTLIB::MEMMOVE;
652fe6060f1SDimitry Andric     Args[0].Flags[0].setReturned();
6538bcb0991SDimitry Andric     break;
654e8d8bef9SDimitry Andric   case TargetOpcode::G_MEMSET:
655e8d8bef9SDimitry Andric     RTLibcall = RTLIB::MEMSET;
656fe6060f1SDimitry Andric     Args[0].Flags[0].setReturned();
657e8d8bef9SDimitry Andric     break;
6588bcb0991SDimitry Andric   default:
659fe6060f1SDimitry Andric     llvm_unreachable("unsupported opcode");
6608bcb0991SDimitry Andric   }
6618bcb0991SDimitry Andric   const char *Name = TLI.getLibcallName(RTLibcall);
6628bcb0991SDimitry Andric 
663fe6060f1SDimitry Andric   // Unsupported libcall on the target.
664fe6060f1SDimitry Andric   if (!Name) {
665fe6060f1SDimitry Andric     LLVM_DEBUG(dbgs() << ".. .. Could not find libcall name for "
666fe6060f1SDimitry Andric                       << MIRBuilder.getTII().getName(Opc) << "\n");
667fe6060f1SDimitry Andric     return LegalizerHelper::UnableToLegalize;
668fe6060f1SDimitry Andric   }
669fe6060f1SDimitry Andric 
6708bcb0991SDimitry Andric   CallLowering::CallLoweringInfo Info;
6718bcb0991SDimitry Andric   Info.CallConv = TLI.getLibcallCallingConv(RTLibcall);
6728bcb0991SDimitry Andric   Info.Callee = MachineOperand::CreateES(Name);
673fe6060f1SDimitry Andric   Info.OrigRet = CallLowering::ArgInfo({0}, Type::getVoidTy(Ctx), 0);
6741db9f3b2SDimitry Andric   Info.IsTailCall =
6751db9f3b2SDimitry Andric       MI.getOperand(MI.getNumOperands() - 1).getImm() &&
6761db9f3b2SDimitry Andric       isLibCallInTailPosition(Info.OrigRet, MI, MIRBuilder.getTII(), MRI);
6778bcb0991SDimitry Andric 
6788bcb0991SDimitry Andric   std::copy(Args.begin(), Args.end(), std::back_inserter(Info.OrigArgs));
6798bcb0991SDimitry Andric   if (!CLI.lowerCall(MIRBuilder, Info))
6808bcb0991SDimitry Andric     return LegalizerHelper::UnableToLegalize;
6818bcb0991SDimitry Andric 
6828bcb0991SDimitry Andric   if (Info.LoweredTailCall) {
6838bcb0991SDimitry Andric     assert(Info.IsTailCall && "Lowered tail call when it wasn't a tail call?");
684fe6060f1SDimitry Andric 
685fe6060f1SDimitry Andric     // Check debug locations before removing the return.
686fe6060f1SDimitry Andric     LocObserver.checkpoint(true);
687fe6060f1SDimitry Andric 
6885ffd83dbSDimitry Andric     // We must have a return following the call (or debug insts) to get past
6898bcb0991SDimitry Andric     // isLibCallInTailPosition.
6905ffd83dbSDimitry Andric     do {
6915ffd83dbSDimitry Andric       MachineInstr *Next = MI.getNextNode();
692fe6060f1SDimitry Andric       assert(Next &&
693fe6060f1SDimitry Andric              (Next->isCopy() || Next->isReturn() || Next->isDebugInstr()) &&
6945ffd83dbSDimitry Andric              "Expected instr following MI to be return or debug inst?");
6958bcb0991SDimitry Andric       // We lowered a tail call, so the call is now the return from the block.
6968bcb0991SDimitry Andric       // Delete the old return.
6975ffd83dbSDimitry Andric       Next->eraseFromParent();
6985ffd83dbSDimitry Andric     } while (MI.getNextNode());
699fe6060f1SDimitry Andric 
700fe6060f1SDimitry Andric     // We expect to lose the debug location from the return.
701fe6060f1SDimitry Andric     LocObserver.checkpoint(false);
7028bcb0991SDimitry Andric   }
7038bcb0991SDimitry Andric 
7048bcb0991SDimitry Andric   return LegalizerHelper::Legalized;
7058bcb0991SDimitry Andric }
7068bcb0991SDimitry Andric 
7071db9f3b2SDimitry Andric static RTLIB::Libcall getOutlineAtomicLibcall(MachineInstr &MI) {
7081db9f3b2SDimitry Andric   unsigned Opc = MI.getOpcode();
7091db9f3b2SDimitry Andric   auto &AtomicMI = cast<GMemOperation>(MI);
7101db9f3b2SDimitry Andric   auto &MMO = AtomicMI.getMMO();
7111db9f3b2SDimitry Andric   auto Ordering = MMO.getMergedOrdering();
7121db9f3b2SDimitry Andric   LLT MemType = MMO.getMemoryType();
7131db9f3b2SDimitry Andric   uint64_t MemSize = MemType.getSizeInBytes();
7141db9f3b2SDimitry Andric   if (MemType.isVector())
7151db9f3b2SDimitry Andric     return RTLIB::UNKNOWN_LIBCALL;
7161db9f3b2SDimitry Andric 
7171db9f3b2SDimitry Andric #define LCALLS(A, B)                                                           \
7181db9f3b2SDimitry Andric   { A##B##_RELAX, A##B##_ACQ, A##B##_REL, A##B##_ACQ_REL }
7191db9f3b2SDimitry Andric #define LCALL5(A)                                                              \
7201db9f3b2SDimitry Andric   LCALLS(A, 1), LCALLS(A, 2), LCALLS(A, 4), LCALLS(A, 8), LCALLS(A, 16)
7211db9f3b2SDimitry Andric   switch (Opc) {
7221db9f3b2SDimitry Andric   case TargetOpcode::G_ATOMIC_CMPXCHG:
7231db9f3b2SDimitry Andric   case TargetOpcode::G_ATOMIC_CMPXCHG_WITH_SUCCESS: {
7241db9f3b2SDimitry Andric     const RTLIB::Libcall LC[5][4] = {LCALL5(RTLIB::OUTLINE_ATOMIC_CAS)};
7251db9f3b2SDimitry Andric     return getOutlineAtomicHelper(LC, Ordering, MemSize);
7261db9f3b2SDimitry Andric   }
7271db9f3b2SDimitry Andric   case TargetOpcode::G_ATOMICRMW_XCHG: {
7281db9f3b2SDimitry Andric     const RTLIB::Libcall LC[5][4] = {LCALL5(RTLIB::OUTLINE_ATOMIC_SWP)};
7291db9f3b2SDimitry Andric     return getOutlineAtomicHelper(LC, Ordering, MemSize);
7301db9f3b2SDimitry Andric   }
7311db9f3b2SDimitry Andric   case TargetOpcode::G_ATOMICRMW_ADD:
7321db9f3b2SDimitry Andric   case TargetOpcode::G_ATOMICRMW_SUB: {
7331db9f3b2SDimitry Andric     const RTLIB::Libcall LC[5][4] = {LCALL5(RTLIB::OUTLINE_ATOMIC_LDADD)};
7341db9f3b2SDimitry Andric     return getOutlineAtomicHelper(LC, Ordering, MemSize);
7351db9f3b2SDimitry Andric   }
7361db9f3b2SDimitry Andric   case TargetOpcode::G_ATOMICRMW_AND: {
7371db9f3b2SDimitry Andric     const RTLIB::Libcall LC[5][4] = {LCALL5(RTLIB::OUTLINE_ATOMIC_LDCLR)};
7381db9f3b2SDimitry Andric     return getOutlineAtomicHelper(LC, Ordering, MemSize);
7391db9f3b2SDimitry Andric   }
7401db9f3b2SDimitry Andric   case TargetOpcode::G_ATOMICRMW_OR: {
7411db9f3b2SDimitry Andric     const RTLIB::Libcall LC[5][4] = {LCALL5(RTLIB::OUTLINE_ATOMIC_LDSET)};
7421db9f3b2SDimitry Andric     return getOutlineAtomicHelper(LC, Ordering, MemSize);
7431db9f3b2SDimitry Andric   }
7441db9f3b2SDimitry Andric   case TargetOpcode::G_ATOMICRMW_XOR: {
7451db9f3b2SDimitry Andric     const RTLIB::Libcall LC[5][4] = {LCALL5(RTLIB::OUTLINE_ATOMIC_LDEOR)};
7461db9f3b2SDimitry Andric     return getOutlineAtomicHelper(LC, Ordering, MemSize);
7471db9f3b2SDimitry Andric   }
7481db9f3b2SDimitry Andric   default:
7491db9f3b2SDimitry Andric     return RTLIB::UNKNOWN_LIBCALL;
7501db9f3b2SDimitry Andric   }
7511db9f3b2SDimitry Andric #undef LCALLS
7521db9f3b2SDimitry Andric #undef LCALL5
7531db9f3b2SDimitry Andric }
7541db9f3b2SDimitry Andric 
7551db9f3b2SDimitry Andric static LegalizerHelper::LegalizeResult
7561db9f3b2SDimitry Andric createAtomicLibcall(MachineIRBuilder &MIRBuilder, MachineInstr &MI) {
7571db9f3b2SDimitry Andric   auto &Ctx = MIRBuilder.getMF().getFunction().getContext();
7581db9f3b2SDimitry Andric 
7591db9f3b2SDimitry Andric   Type *RetTy;
7601db9f3b2SDimitry Andric   SmallVector<Register> RetRegs;
7611db9f3b2SDimitry Andric   SmallVector<CallLowering::ArgInfo, 3> Args;
7621db9f3b2SDimitry Andric   unsigned Opc = MI.getOpcode();
7631db9f3b2SDimitry Andric   switch (Opc) {
7641db9f3b2SDimitry Andric   case TargetOpcode::G_ATOMIC_CMPXCHG:
7651db9f3b2SDimitry Andric   case TargetOpcode::G_ATOMIC_CMPXCHG_WITH_SUCCESS: {
7661db9f3b2SDimitry Andric     Register Success;
7671db9f3b2SDimitry Andric     LLT SuccessLLT;
7681db9f3b2SDimitry Andric     auto [Ret, RetLLT, Mem, MemLLT, Cmp, CmpLLT, New, NewLLT] =
7691db9f3b2SDimitry Andric         MI.getFirst4RegLLTs();
7701db9f3b2SDimitry Andric     RetRegs.push_back(Ret);
7711db9f3b2SDimitry Andric     RetTy = IntegerType::get(Ctx, RetLLT.getSizeInBits());
7721db9f3b2SDimitry Andric     if (Opc == TargetOpcode::G_ATOMIC_CMPXCHG_WITH_SUCCESS) {
7731db9f3b2SDimitry Andric       std::tie(Ret, RetLLT, Success, SuccessLLT, Mem, MemLLT, Cmp, CmpLLT, New,
7741db9f3b2SDimitry Andric                NewLLT) = MI.getFirst5RegLLTs();
7751db9f3b2SDimitry Andric       RetRegs.push_back(Success);
7761db9f3b2SDimitry Andric       RetTy = StructType::get(
7771db9f3b2SDimitry Andric           Ctx, {RetTy, IntegerType::get(Ctx, SuccessLLT.getSizeInBits())});
7781db9f3b2SDimitry Andric     }
7791db9f3b2SDimitry Andric     Args.push_back({Cmp, IntegerType::get(Ctx, CmpLLT.getSizeInBits()), 0});
7801db9f3b2SDimitry Andric     Args.push_back({New, IntegerType::get(Ctx, NewLLT.getSizeInBits()), 0});
7811db9f3b2SDimitry Andric     Args.push_back({Mem, PointerType::get(Ctx, MemLLT.getAddressSpace()), 0});
7821db9f3b2SDimitry Andric     break;
7831db9f3b2SDimitry Andric   }
7841db9f3b2SDimitry Andric   case TargetOpcode::G_ATOMICRMW_XCHG:
7851db9f3b2SDimitry Andric   case TargetOpcode::G_ATOMICRMW_ADD:
7861db9f3b2SDimitry Andric   case TargetOpcode::G_ATOMICRMW_SUB:
7871db9f3b2SDimitry Andric   case TargetOpcode::G_ATOMICRMW_AND:
7881db9f3b2SDimitry Andric   case TargetOpcode::G_ATOMICRMW_OR:
7891db9f3b2SDimitry Andric   case TargetOpcode::G_ATOMICRMW_XOR: {
7901db9f3b2SDimitry Andric     auto [Ret, RetLLT, Mem, MemLLT, Val, ValLLT] = MI.getFirst3RegLLTs();
7911db9f3b2SDimitry Andric     RetRegs.push_back(Ret);
7921db9f3b2SDimitry Andric     RetTy = IntegerType::get(Ctx, RetLLT.getSizeInBits());
7931db9f3b2SDimitry Andric     if (Opc == TargetOpcode::G_ATOMICRMW_AND)
7941db9f3b2SDimitry Andric       Val =
7951db9f3b2SDimitry Andric           MIRBuilder.buildXor(ValLLT, MIRBuilder.buildConstant(ValLLT, -1), Val)
7961db9f3b2SDimitry Andric               .getReg(0);
7971db9f3b2SDimitry Andric     else if (Opc == TargetOpcode::G_ATOMICRMW_SUB)
7981db9f3b2SDimitry Andric       Val =
7991db9f3b2SDimitry Andric           MIRBuilder.buildSub(ValLLT, MIRBuilder.buildConstant(ValLLT, 0), Val)
8001db9f3b2SDimitry Andric               .getReg(0);
8011db9f3b2SDimitry Andric     Args.push_back({Val, IntegerType::get(Ctx, ValLLT.getSizeInBits()), 0});
8021db9f3b2SDimitry Andric     Args.push_back({Mem, PointerType::get(Ctx, MemLLT.getAddressSpace()), 0});
8031db9f3b2SDimitry Andric     break;
8041db9f3b2SDimitry Andric   }
8051db9f3b2SDimitry Andric   default:
8061db9f3b2SDimitry Andric     llvm_unreachable("unsupported opcode");
8071db9f3b2SDimitry Andric   }
8081db9f3b2SDimitry Andric 
8091db9f3b2SDimitry Andric   auto &CLI = *MIRBuilder.getMF().getSubtarget().getCallLowering();
8101db9f3b2SDimitry Andric   auto &TLI = *MIRBuilder.getMF().getSubtarget().getTargetLowering();
8111db9f3b2SDimitry Andric   RTLIB::Libcall RTLibcall = getOutlineAtomicLibcall(MI);
8121db9f3b2SDimitry Andric   const char *Name = TLI.getLibcallName(RTLibcall);
8131db9f3b2SDimitry Andric 
8141db9f3b2SDimitry Andric   // Unsupported libcall on the target.
8151db9f3b2SDimitry Andric   if (!Name) {
8161db9f3b2SDimitry Andric     LLVM_DEBUG(dbgs() << ".. .. Could not find libcall name for "
8171db9f3b2SDimitry Andric                       << MIRBuilder.getTII().getName(Opc) << "\n");
8181db9f3b2SDimitry Andric     return LegalizerHelper::UnableToLegalize;
8191db9f3b2SDimitry Andric   }
8201db9f3b2SDimitry Andric 
8211db9f3b2SDimitry Andric   CallLowering::CallLoweringInfo Info;
8221db9f3b2SDimitry Andric   Info.CallConv = TLI.getLibcallCallingConv(RTLibcall);
8231db9f3b2SDimitry Andric   Info.Callee = MachineOperand::CreateES(Name);
8241db9f3b2SDimitry Andric   Info.OrigRet = CallLowering::ArgInfo(RetRegs, RetTy, 0);
8251db9f3b2SDimitry Andric 
8261db9f3b2SDimitry Andric   std::copy(Args.begin(), Args.end(), std::back_inserter(Info.OrigArgs));
8271db9f3b2SDimitry Andric   if (!CLI.lowerCall(MIRBuilder, Info))
8281db9f3b2SDimitry Andric     return LegalizerHelper::UnableToLegalize;
8291db9f3b2SDimitry Andric 
8301db9f3b2SDimitry Andric   return LegalizerHelper::Legalized;
8311db9f3b2SDimitry Andric }
8321db9f3b2SDimitry Andric 
8330b57cec5SDimitry Andric static RTLIB::Libcall getConvRTLibDesc(unsigned Opcode, Type *ToType,
8340b57cec5SDimitry Andric                                        Type *FromType) {
8350b57cec5SDimitry Andric   auto ToMVT = MVT::getVT(ToType);
8360b57cec5SDimitry Andric   auto FromMVT = MVT::getVT(FromType);
8370b57cec5SDimitry Andric 
8380b57cec5SDimitry Andric   switch (Opcode) {
8390b57cec5SDimitry Andric   case TargetOpcode::G_FPEXT:
8400b57cec5SDimitry Andric     return RTLIB::getFPEXT(FromMVT, ToMVT);
8410b57cec5SDimitry Andric   case TargetOpcode::G_FPTRUNC:
8420b57cec5SDimitry Andric     return RTLIB::getFPROUND(FromMVT, ToMVT);
8430b57cec5SDimitry Andric   case TargetOpcode::G_FPTOSI:
8440b57cec5SDimitry Andric     return RTLIB::getFPTOSINT(FromMVT, ToMVT);
8450b57cec5SDimitry Andric   case TargetOpcode::G_FPTOUI:
8460b57cec5SDimitry Andric     return RTLIB::getFPTOUINT(FromMVT, ToMVT);
8470b57cec5SDimitry Andric   case TargetOpcode::G_SITOFP:
8480b57cec5SDimitry Andric     return RTLIB::getSINTTOFP(FromMVT, ToMVT);
8490b57cec5SDimitry Andric   case TargetOpcode::G_UITOFP:
8500b57cec5SDimitry Andric     return RTLIB::getUINTTOFP(FromMVT, ToMVT);
8510b57cec5SDimitry Andric   }
8520b57cec5SDimitry Andric   llvm_unreachable("Unsupported libcall function");
8530b57cec5SDimitry Andric }
8540b57cec5SDimitry Andric 
8550b57cec5SDimitry Andric static LegalizerHelper::LegalizeResult
8560b57cec5SDimitry Andric conversionLibcall(MachineInstr &MI, MachineIRBuilder &MIRBuilder, Type *ToType,
8571db9f3b2SDimitry Andric                   Type *FromType, LostDebugLocObserver &LocObserver) {
8580b57cec5SDimitry Andric   RTLIB::Libcall Libcall = getConvRTLibDesc(MI.getOpcode(), ToType, FromType);
8591db9f3b2SDimitry Andric   return createLibcall(
8601db9f3b2SDimitry Andric       MIRBuilder, Libcall, {MI.getOperand(0).getReg(), ToType, 0},
8611db9f3b2SDimitry Andric       {{MI.getOperand(1).getReg(), FromType, 0}}, LocObserver, &MI);
8620b57cec5SDimitry Andric }
8630b57cec5SDimitry Andric 
8645f757f3fSDimitry Andric static RTLIB::Libcall
8655f757f3fSDimitry Andric getStateLibraryFunctionFor(MachineInstr &MI, const TargetLowering &TLI) {
8665f757f3fSDimitry Andric   RTLIB::Libcall RTLibcall;
8675f757f3fSDimitry Andric   switch (MI.getOpcode()) {
868297eecfbSDimitry Andric   case TargetOpcode::G_GET_FPENV:
869297eecfbSDimitry Andric     RTLibcall = RTLIB::FEGETENV;
870297eecfbSDimitry Andric     break;
871297eecfbSDimitry Andric   case TargetOpcode::G_SET_FPENV:
872297eecfbSDimitry Andric   case TargetOpcode::G_RESET_FPENV:
873297eecfbSDimitry Andric     RTLibcall = RTLIB::FESETENV;
874297eecfbSDimitry Andric     break;
8755f757f3fSDimitry Andric   case TargetOpcode::G_GET_FPMODE:
8765f757f3fSDimitry Andric     RTLibcall = RTLIB::FEGETMODE;
8775f757f3fSDimitry Andric     break;
8785f757f3fSDimitry Andric   case TargetOpcode::G_SET_FPMODE:
8795f757f3fSDimitry Andric   case TargetOpcode::G_RESET_FPMODE:
8805f757f3fSDimitry Andric     RTLibcall = RTLIB::FESETMODE;
8815f757f3fSDimitry Andric     break;
8825f757f3fSDimitry Andric   default:
8835f757f3fSDimitry Andric     llvm_unreachable("Unexpected opcode");
8845f757f3fSDimitry Andric   }
8855f757f3fSDimitry Andric   return RTLibcall;
8865f757f3fSDimitry Andric }
8875f757f3fSDimitry Andric 
8885f757f3fSDimitry Andric // Some library functions that read FP state (fegetmode, fegetenv) write the
8895f757f3fSDimitry Andric // state into a region in memory. IR intrinsics that do the same operations
8905f757f3fSDimitry Andric // (get_fpmode, get_fpenv) return the state as integer value. To implement these
8915f757f3fSDimitry Andric // intrinsics via the library functions, we need to use temporary variable,
8925f757f3fSDimitry Andric // for example:
8935f757f3fSDimitry Andric //
8945f757f3fSDimitry Andric //     %0:_(s32) = G_GET_FPMODE
8955f757f3fSDimitry Andric //
8965f757f3fSDimitry Andric // is transformed to:
8975f757f3fSDimitry Andric //
8985f757f3fSDimitry Andric //     %1:_(p0) = G_FRAME_INDEX %stack.0
8995f757f3fSDimitry Andric //     BL &fegetmode
9005f757f3fSDimitry Andric //     %0:_(s32) = G_LOAD % 1
9015f757f3fSDimitry Andric //
9025f757f3fSDimitry Andric LegalizerHelper::LegalizeResult
9035f757f3fSDimitry Andric LegalizerHelper::createGetStateLibcall(MachineIRBuilder &MIRBuilder,
9041db9f3b2SDimitry Andric                                        MachineInstr &MI,
9051db9f3b2SDimitry Andric                                        LostDebugLocObserver &LocObserver) {
9065f757f3fSDimitry Andric   const DataLayout &DL = MIRBuilder.getDataLayout();
9075f757f3fSDimitry Andric   auto &MF = MIRBuilder.getMF();
9085f757f3fSDimitry Andric   auto &MRI = *MIRBuilder.getMRI();
9095f757f3fSDimitry Andric   auto &Ctx = MF.getFunction().getContext();
9105f757f3fSDimitry Andric 
9115f757f3fSDimitry Andric   // Create temporary, where library function will put the read state.
9125f757f3fSDimitry Andric   Register Dst = MI.getOperand(0).getReg();
9135f757f3fSDimitry Andric   LLT StateTy = MRI.getType(Dst);
9145f757f3fSDimitry Andric   TypeSize StateSize = StateTy.getSizeInBytes();
9155f757f3fSDimitry Andric   Align TempAlign = getStackTemporaryAlignment(StateTy);
9165f757f3fSDimitry Andric   MachinePointerInfo TempPtrInfo;
9175f757f3fSDimitry Andric   auto Temp = createStackTemporary(StateSize, TempAlign, TempPtrInfo);
9185f757f3fSDimitry Andric 
9195f757f3fSDimitry Andric   // Create a call to library function, with the temporary as an argument.
9205f757f3fSDimitry Andric   unsigned TempAddrSpace = DL.getAllocaAddrSpace();
9215f757f3fSDimitry Andric   Type *StatePtrTy = PointerType::get(Ctx, TempAddrSpace);
9225f757f3fSDimitry Andric   RTLIB::Libcall RTLibcall = getStateLibraryFunctionFor(MI, TLI);
9235f757f3fSDimitry Andric   auto Res =
9245f757f3fSDimitry Andric       createLibcall(MIRBuilder, RTLibcall,
9255f757f3fSDimitry Andric                     CallLowering::ArgInfo({0}, Type::getVoidTy(Ctx), 0),
9261db9f3b2SDimitry Andric                     CallLowering::ArgInfo({Temp.getReg(0), StatePtrTy, 0}),
9271db9f3b2SDimitry Andric                     LocObserver, nullptr);
9285f757f3fSDimitry Andric   if (Res != LegalizerHelper::Legalized)
9295f757f3fSDimitry Andric     return Res;
9305f757f3fSDimitry Andric 
9315f757f3fSDimitry Andric   // Create a load from the temporary.
9325f757f3fSDimitry Andric   MachineMemOperand *MMO = MF.getMachineMemOperand(
9335f757f3fSDimitry Andric       TempPtrInfo, MachineMemOperand::MOLoad, StateTy, TempAlign);
9345f757f3fSDimitry Andric   MIRBuilder.buildLoadInstr(TargetOpcode::G_LOAD, Dst, Temp, *MMO);
9355f757f3fSDimitry Andric 
9365f757f3fSDimitry Andric   return LegalizerHelper::Legalized;
9375f757f3fSDimitry Andric }
9385f757f3fSDimitry Andric 
9395f757f3fSDimitry Andric // Similar to `createGetStateLibcall` the function calls a library function
9405f757f3fSDimitry Andric // using transient space in stack. In this case the library function reads
9415f757f3fSDimitry Andric // content of memory region.
9425f757f3fSDimitry Andric LegalizerHelper::LegalizeResult
9435f757f3fSDimitry Andric LegalizerHelper::createSetStateLibcall(MachineIRBuilder &MIRBuilder,
9441db9f3b2SDimitry Andric                                        MachineInstr &MI,
9451db9f3b2SDimitry Andric                                        LostDebugLocObserver &LocObserver) {
9465f757f3fSDimitry Andric   const DataLayout &DL = MIRBuilder.getDataLayout();
9475f757f3fSDimitry Andric   auto &MF = MIRBuilder.getMF();
9485f757f3fSDimitry Andric   auto &MRI = *MIRBuilder.getMRI();
9495f757f3fSDimitry Andric   auto &Ctx = MF.getFunction().getContext();
9505f757f3fSDimitry Andric 
9515f757f3fSDimitry Andric   // Create temporary, where library function will get the new state.
9525f757f3fSDimitry Andric   Register Src = MI.getOperand(0).getReg();
9535f757f3fSDimitry Andric   LLT StateTy = MRI.getType(Src);
9545f757f3fSDimitry Andric   TypeSize StateSize = StateTy.getSizeInBytes();
9555f757f3fSDimitry Andric   Align TempAlign = getStackTemporaryAlignment(StateTy);
9565f757f3fSDimitry Andric   MachinePointerInfo TempPtrInfo;
9575f757f3fSDimitry Andric   auto Temp = createStackTemporary(StateSize, TempAlign, TempPtrInfo);
9585f757f3fSDimitry Andric 
9595f757f3fSDimitry Andric   // Put the new state into the temporary.
9605f757f3fSDimitry Andric   MachineMemOperand *MMO = MF.getMachineMemOperand(
9615f757f3fSDimitry Andric       TempPtrInfo, MachineMemOperand::MOStore, StateTy, TempAlign);
9625f757f3fSDimitry Andric   MIRBuilder.buildStore(Src, Temp, *MMO);
9635f757f3fSDimitry Andric 
9645f757f3fSDimitry Andric   // Create a call to library function, with the temporary as an argument.
9655f757f3fSDimitry Andric   unsigned TempAddrSpace = DL.getAllocaAddrSpace();
9665f757f3fSDimitry Andric   Type *StatePtrTy = PointerType::get(Ctx, TempAddrSpace);
9675f757f3fSDimitry Andric   RTLIB::Libcall RTLibcall = getStateLibraryFunctionFor(MI, TLI);
9685f757f3fSDimitry Andric   return createLibcall(MIRBuilder, RTLibcall,
9695f757f3fSDimitry Andric                        CallLowering::ArgInfo({0}, Type::getVoidTy(Ctx), 0),
9701db9f3b2SDimitry Andric                        CallLowering::ArgInfo({Temp.getReg(0), StatePtrTy, 0}),
9711db9f3b2SDimitry Andric                        LocObserver, nullptr);
9725f757f3fSDimitry Andric }
9735f757f3fSDimitry Andric 
9745f757f3fSDimitry Andric // The function is used to legalize operations that set default environment
9755f757f3fSDimitry Andric // state. In C library a call like `fesetmode(FE_DFL_MODE)` is used for that.
9765f757f3fSDimitry Andric // On most targets supported in glibc FE_DFL_MODE is defined as
9775f757f3fSDimitry Andric // `((const femode_t *) -1)`. Such assumption is used here. If for some target
9785f757f3fSDimitry Andric // it is not true, the target must provide custom lowering.
9795f757f3fSDimitry Andric LegalizerHelper::LegalizeResult
9805f757f3fSDimitry Andric LegalizerHelper::createResetStateLibcall(MachineIRBuilder &MIRBuilder,
9811db9f3b2SDimitry Andric                                          MachineInstr &MI,
9821db9f3b2SDimitry Andric                                          LostDebugLocObserver &LocObserver) {
9835f757f3fSDimitry Andric   const DataLayout &DL = MIRBuilder.getDataLayout();
9845f757f3fSDimitry Andric   auto &MF = MIRBuilder.getMF();
9855f757f3fSDimitry Andric   auto &Ctx = MF.getFunction().getContext();
9865f757f3fSDimitry Andric 
9875f757f3fSDimitry Andric   // Create an argument for the library function.
9885f757f3fSDimitry Andric   unsigned AddrSpace = DL.getDefaultGlobalsAddressSpace();
9895f757f3fSDimitry Andric   Type *StatePtrTy = PointerType::get(Ctx, AddrSpace);
9905f757f3fSDimitry Andric   unsigned PtrSize = DL.getPointerSizeInBits(AddrSpace);
9915f757f3fSDimitry Andric   LLT MemTy = LLT::pointer(AddrSpace, PtrSize);
9925f757f3fSDimitry Andric   auto DefValue = MIRBuilder.buildConstant(LLT::scalar(PtrSize), -1LL);
9935f757f3fSDimitry Andric   DstOp Dest(MRI.createGenericVirtualRegister(MemTy));
9945f757f3fSDimitry Andric   MIRBuilder.buildIntToPtr(Dest, DefValue);
9955f757f3fSDimitry Andric 
9965f757f3fSDimitry Andric   RTLIB::Libcall RTLibcall = getStateLibraryFunctionFor(MI, TLI);
9975f757f3fSDimitry Andric   return createLibcall(MIRBuilder, RTLibcall,
9985f757f3fSDimitry Andric                        CallLowering::ArgInfo({0}, Type::getVoidTy(Ctx), 0),
9991db9f3b2SDimitry Andric                        CallLowering::ArgInfo({Dest.getReg(), StatePtrTy, 0}),
10001db9f3b2SDimitry Andric                        LocObserver, &MI);
10015f757f3fSDimitry Andric }
10025f757f3fSDimitry Andric 
10030b57cec5SDimitry Andric LegalizerHelper::LegalizeResult
1004fe6060f1SDimitry Andric LegalizerHelper::libcall(MachineInstr &MI, LostDebugLocObserver &LocObserver) {
10050b57cec5SDimitry Andric   auto &Ctx = MIRBuilder.getMF().getFunction().getContext();
10060b57cec5SDimitry Andric 
10070b57cec5SDimitry Andric   switch (MI.getOpcode()) {
10080b57cec5SDimitry Andric   default:
10090b57cec5SDimitry Andric     return UnableToLegalize;
1010bdd1243dSDimitry Andric   case TargetOpcode::G_MUL:
10110b57cec5SDimitry Andric   case TargetOpcode::G_SDIV:
10120b57cec5SDimitry Andric   case TargetOpcode::G_UDIV:
10130b57cec5SDimitry Andric   case TargetOpcode::G_SREM:
10140b57cec5SDimitry Andric   case TargetOpcode::G_UREM:
10150b57cec5SDimitry Andric   case TargetOpcode::G_CTLZ_ZERO_UNDEF: {
10165f757f3fSDimitry Andric     LLT LLTy = MRI.getType(MI.getOperand(0).getReg());
10175f757f3fSDimitry Andric     unsigned Size = LLTy.getSizeInBits();
10180b57cec5SDimitry Andric     Type *HLTy = IntegerType::get(Ctx, Size);
10191db9f3b2SDimitry Andric     auto Status = simpleLibcall(MI, MIRBuilder, Size, HLTy, LocObserver);
10200b57cec5SDimitry Andric     if (Status != Legalized)
10210b57cec5SDimitry Andric       return Status;
10220b57cec5SDimitry Andric     break;
10230b57cec5SDimitry Andric   }
10240b57cec5SDimitry Andric   case TargetOpcode::G_FADD:
10250b57cec5SDimitry Andric   case TargetOpcode::G_FSUB:
10260b57cec5SDimitry Andric   case TargetOpcode::G_FMUL:
10270b57cec5SDimitry Andric   case TargetOpcode::G_FDIV:
10280b57cec5SDimitry Andric   case TargetOpcode::G_FMA:
10290b57cec5SDimitry Andric   case TargetOpcode::G_FPOW:
10300b57cec5SDimitry Andric   case TargetOpcode::G_FREM:
10310b57cec5SDimitry Andric   case TargetOpcode::G_FCOS:
10320b57cec5SDimitry Andric   case TargetOpcode::G_FSIN:
10330b57cec5SDimitry Andric   case TargetOpcode::G_FLOG10:
10340b57cec5SDimitry Andric   case TargetOpcode::G_FLOG:
10350b57cec5SDimitry Andric   case TargetOpcode::G_FLOG2:
103606c3fb27SDimitry Andric   case TargetOpcode::G_FLDEXP:
10370b57cec5SDimitry Andric   case TargetOpcode::G_FEXP:
10380b57cec5SDimitry Andric   case TargetOpcode::G_FEXP2:
10395f757f3fSDimitry Andric   case TargetOpcode::G_FEXP10:
10400b57cec5SDimitry Andric   case TargetOpcode::G_FCEIL:
10415ffd83dbSDimitry Andric   case TargetOpcode::G_FFLOOR:
10425ffd83dbSDimitry Andric   case TargetOpcode::G_FMINNUM:
10435ffd83dbSDimitry Andric   case TargetOpcode::G_FMAXNUM:
10445ffd83dbSDimitry Andric   case TargetOpcode::G_FSQRT:
10455ffd83dbSDimitry Andric   case TargetOpcode::G_FRINT:
1046e8d8bef9SDimitry Andric   case TargetOpcode::G_FNEARBYINT:
1047e8d8bef9SDimitry Andric   case TargetOpcode::G_INTRINSIC_ROUNDEVEN: {
10485f757f3fSDimitry Andric     LLT LLTy = MRI.getType(MI.getOperand(0).getReg());
10495f757f3fSDimitry Andric     unsigned Size = LLTy.getSizeInBits();
10505ffd83dbSDimitry Andric     Type *HLTy = getFloatTypeForLLT(Ctx, LLTy);
1051e8d8bef9SDimitry Andric     if (!HLTy || (Size != 32 && Size != 64 && Size != 80 && Size != 128)) {
1052e8d8bef9SDimitry Andric       LLVM_DEBUG(dbgs() << "No libcall available for type " << LLTy << ".\n");
10530b57cec5SDimitry Andric       return UnableToLegalize;
10540b57cec5SDimitry Andric     }
10551db9f3b2SDimitry Andric     auto Status = simpleLibcall(MI, MIRBuilder, Size, HLTy, LocObserver);
10561db9f3b2SDimitry Andric     if (Status != Legalized)
10571db9f3b2SDimitry Andric       return Status;
10581db9f3b2SDimitry Andric     break;
10591db9f3b2SDimitry Andric   }
10601db9f3b2SDimitry Andric   case TargetOpcode::G_FPOWI: {
10611db9f3b2SDimitry Andric     LLT LLTy = MRI.getType(MI.getOperand(0).getReg());
10621db9f3b2SDimitry Andric     unsigned Size = LLTy.getSizeInBits();
10631db9f3b2SDimitry Andric     Type *HLTy = getFloatTypeForLLT(Ctx, LLTy);
10641db9f3b2SDimitry Andric     Type *ITy = IntegerType::get(
10651db9f3b2SDimitry Andric         Ctx, MRI.getType(MI.getOperand(2).getReg()).getSizeInBits());
10661db9f3b2SDimitry Andric     if (!HLTy || (Size != 32 && Size != 64 && Size != 80 && Size != 128)) {
10671db9f3b2SDimitry Andric       LLVM_DEBUG(dbgs() << "No libcall available for type " << LLTy << ".\n");
10681db9f3b2SDimitry Andric       return UnableToLegalize;
10691db9f3b2SDimitry Andric     }
10701db9f3b2SDimitry Andric     auto Libcall = getRTLibDesc(MI.getOpcode(), Size);
10711db9f3b2SDimitry Andric     std::initializer_list<CallLowering::ArgInfo> Args = {
10721db9f3b2SDimitry Andric         {MI.getOperand(1).getReg(), HLTy, 0},
10731db9f3b2SDimitry Andric         {MI.getOperand(2).getReg(), ITy, 1}};
10741db9f3b2SDimitry Andric     LegalizeResult Status =
10751db9f3b2SDimitry Andric         createLibcall(MIRBuilder, Libcall, {MI.getOperand(0).getReg(), HLTy, 0},
10761db9f3b2SDimitry Andric                       Args, LocObserver, &MI);
10770b57cec5SDimitry Andric     if (Status != Legalized)
10780b57cec5SDimitry Andric       return Status;
10790b57cec5SDimitry Andric     break;
10800b57cec5SDimitry Andric   }
10815ffd83dbSDimitry Andric   case TargetOpcode::G_FPEXT:
10820b57cec5SDimitry Andric   case TargetOpcode::G_FPTRUNC: {
10835ffd83dbSDimitry Andric     Type *FromTy = getFloatTypeForLLT(Ctx,  MRI.getType(MI.getOperand(1).getReg()));
10845ffd83dbSDimitry Andric     Type *ToTy = getFloatTypeForLLT(Ctx, MRI.getType(MI.getOperand(0).getReg()));
10855ffd83dbSDimitry Andric     if (!FromTy || !ToTy)
10860b57cec5SDimitry Andric       return UnableToLegalize;
10871db9f3b2SDimitry Andric     LegalizeResult Status =
10881db9f3b2SDimitry Andric         conversionLibcall(MI, MIRBuilder, ToTy, FromTy, LocObserver);
10890b57cec5SDimitry Andric     if (Status != Legalized)
10900b57cec5SDimitry Andric       return Status;
10910b57cec5SDimitry Andric     break;
10920b57cec5SDimitry Andric   }
10930b57cec5SDimitry Andric   case TargetOpcode::G_FPTOSI:
10940b57cec5SDimitry Andric   case TargetOpcode::G_FPTOUI: {
10950b57cec5SDimitry Andric     // FIXME: Support other types
10960b57cec5SDimitry Andric     unsigned FromSize = MRI.getType(MI.getOperand(1).getReg()).getSizeInBits();
10970b57cec5SDimitry Andric     unsigned ToSize = MRI.getType(MI.getOperand(0).getReg()).getSizeInBits();
10980b57cec5SDimitry Andric     if ((ToSize != 32 && ToSize != 64) || (FromSize != 32 && FromSize != 64))
10990b57cec5SDimitry Andric       return UnableToLegalize;
11000b57cec5SDimitry Andric     LegalizeResult Status = conversionLibcall(
11010b57cec5SDimitry Andric         MI, MIRBuilder,
11020b57cec5SDimitry Andric         ToSize == 32 ? Type::getInt32Ty(Ctx) : Type::getInt64Ty(Ctx),
11031db9f3b2SDimitry Andric         FromSize == 64 ? Type::getDoubleTy(Ctx) : Type::getFloatTy(Ctx),
11041db9f3b2SDimitry Andric         LocObserver);
11050b57cec5SDimitry Andric     if (Status != Legalized)
11060b57cec5SDimitry Andric       return Status;
11070b57cec5SDimitry Andric     break;
11080b57cec5SDimitry Andric   }
11090b57cec5SDimitry Andric   case TargetOpcode::G_SITOFP:
11100b57cec5SDimitry Andric   case TargetOpcode::G_UITOFP: {
11110b57cec5SDimitry Andric     // FIXME: Support other types
11120b57cec5SDimitry Andric     unsigned FromSize = MRI.getType(MI.getOperand(1).getReg()).getSizeInBits();
11130b57cec5SDimitry Andric     unsigned ToSize = MRI.getType(MI.getOperand(0).getReg()).getSizeInBits();
11140b57cec5SDimitry Andric     if ((FromSize != 32 && FromSize != 64) || (ToSize != 32 && ToSize != 64))
11150b57cec5SDimitry Andric       return UnableToLegalize;
11160b57cec5SDimitry Andric     LegalizeResult Status = conversionLibcall(
11170b57cec5SDimitry Andric         MI, MIRBuilder,
11180b57cec5SDimitry Andric         ToSize == 64 ? Type::getDoubleTy(Ctx) : Type::getFloatTy(Ctx),
11191db9f3b2SDimitry Andric         FromSize == 32 ? Type::getInt32Ty(Ctx) : Type::getInt64Ty(Ctx),
11201db9f3b2SDimitry Andric         LocObserver);
11211db9f3b2SDimitry Andric     if (Status != Legalized)
11221db9f3b2SDimitry Andric       return Status;
11231db9f3b2SDimitry Andric     break;
11241db9f3b2SDimitry Andric   }
11251db9f3b2SDimitry Andric   case TargetOpcode::G_ATOMICRMW_XCHG:
11261db9f3b2SDimitry Andric   case TargetOpcode::G_ATOMICRMW_ADD:
11271db9f3b2SDimitry Andric   case TargetOpcode::G_ATOMICRMW_SUB:
11281db9f3b2SDimitry Andric   case TargetOpcode::G_ATOMICRMW_AND:
11291db9f3b2SDimitry Andric   case TargetOpcode::G_ATOMICRMW_OR:
11301db9f3b2SDimitry Andric   case TargetOpcode::G_ATOMICRMW_XOR:
11311db9f3b2SDimitry Andric   case TargetOpcode::G_ATOMIC_CMPXCHG:
11321db9f3b2SDimitry Andric   case TargetOpcode::G_ATOMIC_CMPXCHG_WITH_SUCCESS: {
11331db9f3b2SDimitry Andric     auto Status = createAtomicLibcall(MIRBuilder, MI);
11340b57cec5SDimitry Andric     if (Status != Legalized)
11350b57cec5SDimitry Andric       return Status;
11360b57cec5SDimitry Andric     break;
11370b57cec5SDimitry Andric   }
1138fe6060f1SDimitry Andric   case TargetOpcode::G_BZERO:
1139e8d8bef9SDimitry Andric   case TargetOpcode::G_MEMCPY:
1140e8d8bef9SDimitry Andric   case TargetOpcode::G_MEMMOVE:
1141e8d8bef9SDimitry Andric   case TargetOpcode::G_MEMSET: {
1142fe6060f1SDimitry Andric     LegalizeResult Result =
1143fe6060f1SDimitry Andric         createMemLibcall(MIRBuilder, *MIRBuilder.getMRI(), MI, LocObserver);
1144fe6060f1SDimitry Andric     if (Result != Legalized)
1145fe6060f1SDimitry Andric       return Result;
1146e8d8bef9SDimitry Andric     MI.eraseFromParent();
1147e8d8bef9SDimitry Andric     return Result;
1148e8d8bef9SDimitry Andric   }
1149297eecfbSDimitry Andric   case TargetOpcode::G_GET_FPENV:
11505f757f3fSDimitry Andric   case TargetOpcode::G_GET_FPMODE: {
11511db9f3b2SDimitry Andric     LegalizeResult Result = createGetStateLibcall(MIRBuilder, MI, LocObserver);
11525f757f3fSDimitry Andric     if (Result != Legalized)
11535f757f3fSDimitry Andric       return Result;
11545f757f3fSDimitry Andric     break;
11555f757f3fSDimitry Andric   }
1156297eecfbSDimitry Andric   case TargetOpcode::G_SET_FPENV:
11575f757f3fSDimitry Andric   case TargetOpcode::G_SET_FPMODE: {
11581db9f3b2SDimitry Andric     LegalizeResult Result = createSetStateLibcall(MIRBuilder, MI, LocObserver);
11595f757f3fSDimitry Andric     if (Result != Legalized)
11605f757f3fSDimitry Andric       return Result;
11615f757f3fSDimitry Andric     break;
11625f757f3fSDimitry Andric   }
1163297eecfbSDimitry Andric   case TargetOpcode::G_RESET_FPENV:
11645f757f3fSDimitry Andric   case TargetOpcode::G_RESET_FPMODE: {
11651db9f3b2SDimitry Andric     LegalizeResult Result =
11661db9f3b2SDimitry Andric         createResetStateLibcall(MIRBuilder, MI, LocObserver);
11675f757f3fSDimitry Andric     if (Result != Legalized)
11685f757f3fSDimitry Andric       return Result;
11695f757f3fSDimitry Andric     break;
11705f757f3fSDimitry Andric   }
11710b57cec5SDimitry Andric   }
11720b57cec5SDimitry Andric 
11730b57cec5SDimitry Andric   MI.eraseFromParent();
11740b57cec5SDimitry Andric   return Legalized;
11750b57cec5SDimitry Andric }
11760b57cec5SDimitry Andric 
11770b57cec5SDimitry Andric LegalizerHelper::LegalizeResult LegalizerHelper::narrowScalar(MachineInstr &MI,
11780b57cec5SDimitry Andric                                                               unsigned TypeIdx,
11790b57cec5SDimitry Andric                                                               LLT NarrowTy) {
11800b57cec5SDimitry Andric   uint64_t SizeOp0 = MRI.getType(MI.getOperand(0).getReg()).getSizeInBits();
11810b57cec5SDimitry Andric   uint64_t NarrowSize = NarrowTy.getSizeInBits();
11820b57cec5SDimitry Andric 
11830b57cec5SDimitry Andric   switch (MI.getOpcode()) {
11840b57cec5SDimitry Andric   default:
11850b57cec5SDimitry Andric     return UnableToLegalize;
11860b57cec5SDimitry Andric   case TargetOpcode::G_IMPLICIT_DEF: {
11875ffd83dbSDimitry Andric     Register DstReg = MI.getOperand(0).getReg();
11885ffd83dbSDimitry Andric     LLT DstTy = MRI.getType(DstReg);
11895ffd83dbSDimitry Andric 
11905ffd83dbSDimitry Andric     // If SizeOp0 is not an exact multiple of NarrowSize, emit
11915ffd83dbSDimitry Andric     // G_ANYEXT(G_IMPLICIT_DEF). Cast result to vector if needed.
11925ffd83dbSDimitry Andric     // FIXME: Although this would also be legal for the general case, it causes
11935ffd83dbSDimitry Andric     //  a lot of regressions in the emitted code (superfluous COPYs, artifact
11945ffd83dbSDimitry Andric     //  combines not being hit). This seems to be a problem related to the
11955ffd83dbSDimitry Andric     //  artifact combiner.
11965ffd83dbSDimitry Andric     if (SizeOp0 % NarrowSize != 0) {
11975ffd83dbSDimitry Andric       LLT ImplicitTy = NarrowTy;
11985ffd83dbSDimitry Andric       if (DstTy.isVector())
1199fe6060f1SDimitry Andric         ImplicitTy = LLT::vector(DstTy.getElementCount(), ImplicitTy);
12005ffd83dbSDimitry Andric 
12015ffd83dbSDimitry Andric       Register ImplicitReg = MIRBuilder.buildUndef(ImplicitTy).getReg(0);
12025ffd83dbSDimitry Andric       MIRBuilder.buildAnyExt(DstReg, ImplicitReg);
12035ffd83dbSDimitry Andric 
12045ffd83dbSDimitry Andric       MI.eraseFromParent();
12055ffd83dbSDimitry Andric       return Legalized;
12065ffd83dbSDimitry Andric     }
12075ffd83dbSDimitry Andric 
12080b57cec5SDimitry Andric     int NumParts = SizeOp0 / NarrowSize;
12090b57cec5SDimitry Andric 
12100b57cec5SDimitry Andric     SmallVector<Register, 2> DstRegs;
12110b57cec5SDimitry Andric     for (int i = 0; i < NumParts; ++i)
12125ffd83dbSDimitry Andric       DstRegs.push_back(MIRBuilder.buildUndef(NarrowTy).getReg(0));
12130b57cec5SDimitry Andric 
12145ffd83dbSDimitry Andric     if (DstTy.isVector())
12150b57cec5SDimitry Andric       MIRBuilder.buildBuildVector(DstReg, DstRegs);
12160b57cec5SDimitry Andric     else
1217bdd1243dSDimitry Andric       MIRBuilder.buildMergeLikeInstr(DstReg, DstRegs);
12180b57cec5SDimitry Andric     MI.eraseFromParent();
12190b57cec5SDimitry Andric     return Legalized;
12200b57cec5SDimitry Andric   }
12210b57cec5SDimitry Andric   case TargetOpcode::G_CONSTANT: {
12220b57cec5SDimitry Andric     LLT Ty = MRI.getType(MI.getOperand(0).getReg());
12230b57cec5SDimitry Andric     const APInt &Val = MI.getOperand(1).getCImm()->getValue();
12240b57cec5SDimitry Andric     unsigned TotalSize = Ty.getSizeInBits();
12250b57cec5SDimitry Andric     unsigned NarrowSize = NarrowTy.getSizeInBits();
12260b57cec5SDimitry Andric     int NumParts = TotalSize / NarrowSize;
12270b57cec5SDimitry Andric 
12280b57cec5SDimitry Andric     SmallVector<Register, 4> PartRegs;
12290b57cec5SDimitry Andric     for (int I = 0; I != NumParts; ++I) {
12300b57cec5SDimitry Andric       unsigned Offset = I * NarrowSize;
12310b57cec5SDimitry Andric       auto K = MIRBuilder.buildConstant(NarrowTy,
12320b57cec5SDimitry Andric                                         Val.lshr(Offset).trunc(NarrowSize));
12330b57cec5SDimitry Andric       PartRegs.push_back(K.getReg(0));
12340b57cec5SDimitry Andric     }
12350b57cec5SDimitry Andric 
12360b57cec5SDimitry Andric     LLT LeftoverTy;
12370b57cec5SDimitry Andric     unsigned LeftoverBits = TotalSize - NumParts * NarrowSize;
12380b57cec5SDimitry Andric     SmallVector<Register, 1> LeftoverRegs;
12390b57cec5SDimitry Andric     if (LeftoverBits != 0) {
12400b57cec5SDimitry Andric       LeftoverTy = LLT::scalar(LeftoverBits);
12410b57cec5SDimitry Andric       auto K = MIRBuilder.buildConstant(
12420b57cec5SDimitry Andric         LeftoverTy,
12430b57cec5SDimitry Andric         Val.lshr(NumParts * NarrowSize).trunc(LeftoverBits));
12440b57cec5SDimitry Andric       LeftoverRegs.push_back(K.getReg(0));
12450b57cec5SDimitry Andric     }
12460b57cec5SDimitry Andric 
12470b57cec5SDimitry Andric     insertParts(MI.getOperand(0).getReg(),
12480b57cec5SDimitry Andric                 Ty, NarrowTy, PartRegs, LeftoverTy, LeftoverRegs);
12490b57cec5SDimitry Andric 
12500b57cec5SDimitry Andric     MI.eraseFromParent();
12510b57cec5SDimitry Andric     return Legalized;
12520b57cec5SDimitry Andric   }
12535ffd83dbSDimitry Andric   case TargetOpcode::G_SEXT:
12545ffd83dbSDimitry Andric   case TargetOpcode::G_ZEXT:
12555ffd83dbSDimitry Andric   case TargetOpcode::G_ANYEXT:
12565ffd83dbSDimitry Andric     return narrowScalarExt(MI, TypeIdx, NarrowTy);
12578bcb0991SDimitry Andric   case TargetOpcode::G_TRUNC: {
12588bcb0991SDimitry Andric     if (TypeIdx != 1)
12598bcb0991SDimitry Andric       return UnableToLegalize;
12608bcb0991SDimitry Andric 
12618bcb0991SDimitry Andric     uint64_t SizeOp1 = MRI.getType(MI.getOperand(1).getReg()).getSizeInBits();
12628bcb0991SDimitry Andric     if (NarrowTy.getSizeInBits() * 2 != SizeOp1) {
12638bcb0991SDimitry Andric       LLVM_DEBUG(dbgs() << "Can't narrow trunc to type " << NarrowTy << "\n");
12648bcb0991SDimitry Andric       return UnableToLegalize;
12658bcb0991SDimitry Andric     }
12668bcb0991SDimitry Andric 
12675ffd83dbSDimitry Andric     auto Unmerge = MIRBuilder.buildUnmerge(NarrowTy, MI.getOperand(1));
12685ffd83dbSDimitry Andric     MIRBuilder.buildCopy(MI.getOperand(0), Unmerge.getReg(0));
12698bcb0991SDimitry Andric     MI.eraseFromParent();
12708bcb0991SDimitry Andric     return Legalized;
12718bcb0991SDimitry Andric   }
12728bcb0991SDimitry Andric 
12730eae32dcSDimitry Andric   case TargetOpcode::G_FREEZE: {
12740eae32dcSDimitry Andric     if (TypeIdx != 0)
12750eae32dcSDimitry Andric       return UnableToLegalize;
12760eae32dcSDimitry Andric 
12770eae32dcSDimitry Andric     LLT Ty = MRI.getType(MI.getOperand(0).getReg());
12780eae32dcSDimitry Andric     // Should widen scalar first
12790eae32dcSDimitry Andric     if (Ty.getSizeInBits() % NarrowTy.getSizeInBits() != 0)
12800eae32dcSDimitry Andric       return UnableToLegalize;
12810eae32dcSDimitry Andric 
12820eae32dcSDimitry Andric     auto Unmerge = MIRBuilder.buildUnmerge(NarrowTy, MI.getOperand(1).getReg());
12830eae32dcSDimitry Andric     SmallVector<Register, 8> Parts;
12840eae32dcSDimitry Andric     for (unsigned i = 0; i < Unmerge->getNumDefs(); ++i) {
12850eae32dcSDimitry Andric       Parts.push_back(
12860eae32dcSDimitry Andric           MIRBuilder.buildFreeze(NarrowTy, Unmerge.getReg(i)).getReg(0));
12870eae32dcSDimitry Andric     }
12880eae32dcSDimitry Andric 
1289bdd1243dSDimitry Andric     MIRBuilder.buildMergeLikeInstr(MI.getOperand(0).getReg(), Parts);
12900eae32dcSDimitry Andric     MI.eraseFromParent();
12910eae32dcSDimitry Andric     return Legalized;
12920eae32dcSDimitry Andric   }
1293fe6060f1SDimitry Andric   case TargetOpcode::G_ADD:
1294fe6060f1SDimitry Andric   case TargetOpcode::G_SUB:
1295fe6060f1SDimitry Andric   case TargetOpcode::G_SADDO:
1296fe6060f1SDimitry Andric   case TargetOpcode::G_SSUBO:
1297fe6060f1SDimitry Andric   case TargetOpcode::G_SADDE:
1298fe6060f1SDimitry Andric   case TargetOpcode::G_SSUBE:
1299fe6060f1SDimitry Andric   case TargetOpcode::G_UADDO:
1300fe6060f1SDimitry Andric   case TargetOpcode::G_USUBO:
1301fe6060f1SDimitry Andric   case TargetOpcode::G_UADDE:
1302fe6060f1SDimitry Andric   case TargetOpcode::G_USUBE:
1303fe6060f1SDimitry Andric     return narrowScalarAddSub(MI, TypeIdx, NarrowTy);
13040b57cec5SDimitry Andric   case TargetOpcode::G_MUL:
13050b57cec5SDimitry Andric   case TargetOpcode::G_UMULH:
13060b57cec5SDimitry Andric     return narrowScalarMul(MI, NarrowTy);
13070b57cec5SDimitry Andric   case TargetOpcode::G_EXTRACT:
13080b57cec5SDimitry Andric     return narrowScalarExtract(MI, TypeIdx, NarrowTy);
13090b57cec5SDimitry Andric   case TargetOpcode::G_INSERT:
13100b57cec5SDimitry Andric     return narrowScalarInsert(MI, TypeIdx, NarrowTy);
13110b57cec5SDimitry Andric   case TargetOpcode::G_LOAD: {
1312fe6060f1SDimitry Andric     auto &LoadMI = cast<GLoad>(MI);
1313fe6060f1SDimitry Andric     Register DstReg = LoadMI.getDstReg();
13140b57cec5SDimitry Andric     LLT DstTy = MRI.getType(DstReg);
13150b57cec5SDimitry Andric     if (DstTy.isVector())
13160b57cec5SDimitry Andric       return UnableToLegalize;
13170b57cec5SDimitry Andric 
1318fe6060f1SDimitry Andric     if (8 * LoadMI.getMemSize() != DstTy.getSizeInBits()) {
13190b57cec5SDimitry Andric       Register TmpReg = MRI.createGenericVirtualRegister(NarrowTy);
1320fe6060f1SDimitry Andric       MIRBuilder.buildLoad(TmpReg, LoadMI.getPointerReg(), LoadMI.getMMO());
13210b57cec5SDimitry Andric       MIRBuilder.buildAnyExt(DstReg, TmpReg);
1322fe6060f1SDimitry Andric       LoadMI.eraseFromParent();
13230b57cec5SDimitry Andric       return Legalized;
13240b57cec5SDimitry Andric     }
13250b57cec5SDimitry Andric 
1326fe6060f1SDimitry Andric     return reduceLoadStoreWidth(LoadMI, TypeIdx, NarrowTy);
13270b57cec5SDimitry Andric   }
13280b57cec5SDimitry Andric   case TargetOpcode::G_ZEXTLOAD:
13290b57cec5SDimitry Andric   case TargetOpcode::G_SEXTLOAD: {
1330fe6060f1SDimitry Andric     auto &LoadMI = cast<GExtLoad>(MI);
1331fe6060f1SDimitry Andric     Register DstReg = LoadMI.getDstReg();
1332fe6060f1SDimitry Andric     Register PtrReg = LoadMI.getPointerReg();
13330b57cec5SDimitry Andric 
13340b57cec5SDimitry Andric     Register TmpReg = MRI.createGenericVirtualRegister(NarrowTy);
1335fe6060f1SDimitry Andric     auto &MMO = LoadMI.getMMO();
1336e8d8bef9SDimitry Andric     unsigned MemSize = MMO.getSizeInBits();
1337e8d8bef9SDimitry Andric 
1338e8d8bef9SDimitry Andric     if (MemSize == NarrowSize) {
13390b57cec5SDimitry Andric       MIRBuilder.buildLoad(TmpReg, PtrReg, MMO);
1340e8d8bef9SDimitry Andric     } else if (MemSize < NarrowSize) {
1341fe6060f1SDimitry Andric       MIRBuilder.buildLoadInstr(LoadMI.getOpcode(), TmpReg, PtrReg, MMO);
1342e8d8bef9SDimitry Andric     } else if (MemSize > NarrowSize) {
1343e8d8bef9SDimitry Andric       // FIXME: Need to split the load.
1344e8d8bef9SDimitry Andric       return UnableToLegalize;
13450b57cec5SDimitry Andric     }
13460b57cec5SDimitry Andric 
1347fe6060f1SDimitry Andric     if (isa<GZExtLoad>(LoadMI))
13480b57cec5SDimitry Andric       MIRBuilder.buildZExt(DstReg, TmpReg);
13490b57cec5SDimitry Andric     else
13500b57cec5SDimitry Andric       MIRBuilder.buildSExt(DstReg, TmpReg);
13510b57cec5SDimitry Andric 
1352fe6060f1SDimitry Andric     LoadMI.eraseFromParent();
13530b57cec5SDimitry Andric     return Legalized;
13540b57cec5SDimitry Andric   }
13550b57cec5SDimitry Andric   case TargetOpcode::G_STORE: {
1356fe6060f1SDimitry Andric     auto &StoreMI = cast<GStore>(MI);
13570b57cec5SDimitry Andric 
1358fe6060f1SDimitry Andric     Register SrcReg = StoreMI.getValueReg();
13590b57cec5SDimitry Andric     LLT SrcTy = MRI.getType(SrcReg);
13600b57cec5SDimitry Andric     if (SrcTy.isVector())
13610b57cec5SDimitry Andric       return UnableToLegalize;
13620b57cec5SDimitry Andric 
13630b57cec5SDimitry Andric     int NumParts = SizeOp0 / NarrowSize;
13640b57cec5SDimitry Andric     unsigned HandledSize = NumParts * NarrowTy.getSizeInBits();
13650b57cec5SDimitry Andric     unsigned LeftoverBits = SrcTy.getSizeInBits() - HandledSize;
13660b57cec5SDimitry Andric     if (SrcTy.isVector() && LeftoverBits != 0)
13670b57cec5SDimitry Andric       return UnableToLegalize;
13680b57cec5SDimitry Andric 
1369fe6060f1SDimitry Andric     if (8 * StoreMI.getMemSize() != SrcTy.getSizeInBits()) {
13700b57cec5SDimitry Andric       Register TmpReg = MRI.createGenericVirtualRegister(NarrowTy);
13710b57cec5SDimitry Andric       MIRBuilder.buildTrunc(TmpReg, SrcReg);
1372fe6060f1SDimitry Andric       MIRBuilder.buildStore(TmpReg, StoreMI.getPointerReg(), StoreMI.getMMO());
1373fe6060f1SDimitry Andric       StoreMI.eraseFromParent();
13740b57cec5SDimitry Andric       return Legalized;
13750b57cec5SDimitry Andric     }
13760b57cec5SDimitry Andric 
1377fe6060f1SDimitry Andric     return reduceLoadStoreWidth(StoreMI, 0, NarrowTy);
13780b57cec5SDimitry Andric   }
13790b57cec5SDimitry Andric   case TargetOpcode::G_SELECT:
13800b57cec5SDimitry Andric     return narrowScalarSelect(MI, TypeIdx, NarrowTy);
13810b57cec5SDimitry Andric   case TargetOpcode::G_AND:
13820b57cec5SDimitry Andric   case TargetOpcode::G_OR:
13830b57cec5SDimitry Andric   case TargetOpcode::G_XOR: {
13840b57cec5SDimitry Andric     // Legalize bitwise operation:
13850b57cec5SDimitry Andric     // A = BinOp<Ty> B, C
13860b57cec5SDimitry Andric     // into:
13870b57cec5SDimitry Andric     // B1, ..., BN = G_UNMERGE_VALUES B
13880b57cec5SDimitry Andric     // C1, ..., CN = G_UNMERGE_VALUES C
13890b57cec5SDimitry Andric     // A1 = BinOp<Ty/N> B1, C2
13900b57cec5SDimitry Andric     // ...
13910b57cec5SDimitry Andric     // AN = BinOp<Ty/N> BN, CN
13920b57cec5SDimitry Andric     // A = G_MERGE_VALUES A1, ..., AN
13930b57cec5SDimitry Andric     return narrowScalarBasic(MI, TypeIdx, NarrowTy);
13940b57cec5SDimitry Andric   }
13950b57cec5SDimitry Andric   case TargetOpcode::G_SHL:
13960b57cec5SDimitry Andric   case TargetOpcode::G_LSHR:
13970b57cec5SDimitry Andric   case TargetOpcode::G_ASHR:
13980b57cec5SDimitry Andric     return narrowScalarShift(MI, TypeIdx, NarrowTy);
13990b57cec5SDimitry Andric   case TargetOpcode::G_CTLZ:
14000b57cec5SDimitry Andric   case TargetOpcode::G_CTLZ_ZERO_UNDEF:
14010b57cec5SDimitry Andric   case TargetOpcode::G_CTTZ:
14020b57cec5SDimitry Andric   case TargetOpcode::G_CTTZ_ZERO_UNDEF:
14030b57cec5SDimitry Andric   case TargetOpcode::G_CTPOP:
14045ffd83dbSDimitry Andric     if (TypeIdx == 1)
14055ffd83dbSDimitry Andric       switch (MI.getOpcode()) {
14065ffd83dbSDimitry Andric       case TargetOpcode::G_CTLZ:
14075ffd83dbSDimitry Andric       case TargetOpcode::G_CTLZ_ZERO_UNDEF:
14085ffd83dbSDimitry Andric         return narrowScalarCTLZ(MI, TypeIdx, NarrowTy);
14095ffd83dbSDimitry Andric       case TargetOpcode::G_CTTZ:
14105ffd83dbSDimitry Andric       case TargetOpcode::G_CTTZ_ZERO_UNDEF:
14115ffd83dbSDimitry Andric         return narrowScalarCTTZ(MI, TypeIdx, NarrowTy);
14125ffd83dbSDimitry Andric       case TargetOpcode::G_CTPOP:
14135ffd83dbSDimitry Andric         return narrowScalarCTPOP(MI, TypeIdx, NarrowTy);
14145ffd83dbSDimitry Andric       default:
14155ffd83dbSDimitry Andric         return UnableToLegalize;
14165ffd83dbSDimitry Andric       }
14170b57cec5SDimitry Andric 
14180b57cec5SDimitry Andric     Observer.changingInstr(MI);
14190b57cec5SDimitry Andric     narrowScalarDst(MI, NarrowTy, 0, TargetOpcode::G_ZEXT);
14200b57cec5SDimitry Andric     Observer.changedInstr(MI);
14210b57cec5SDimitry Andric     return Legalized;
14220b57cec5SDimitry Andric   case TargetOpcode::G_INTTOPTR:
14230b57cec5SDimitry Andric     if (TypeIdx != 1)
14240b57cec5SDimitry Andric       return UnableToLegalize;
14250b57cec5SDimitry Andric 
14260b57cec5SDimitry Andric     Observer.changingInstr(MI);
14270b57cec5SDimitry Andric     narrowScalarSrc(MI, NarrowTy, 1);
14280b57cec5SDimitry Andric     Observer.changedInstr(MI);
14290b57cec5SDimitry Andric     return Legalized;
14300b57cec5SDimitry Andric   case TargetOpcode::G_PTRTOINT:
14310b57cec5SDimitry Andric     if (TypeIdx != 0)
14320b57cec5SDimitry Andric       return UnableToLegalize;
14330b57cec5SDimitry Andric 
14340b57cec5SDimitry Andric     Observer.changingInstr(MI);
14350b57cec5SDimitry Andric     narrowScalarDst(MI, NarrowTy, 0, TargetOpcode::G_ZEXT);
14360b57cec5SDimitry Andric     Observer.changedInstr(MI);
14370b57cec5SDimitry Andric     return Legalized;
14380b57cec5SDimitry Andric   case TargetOpcode::G_PHI: {
1439d409305fSDimitry Andric     // FIXME: add support for when SizeOp0 isn't an exact multiple of
1440d409305fSDimitry Andric     // NarrowSize.
1441d409305fSDimitry Andric     if (SizeOp0 % NarrowSize != 0)
1442d409305fSDimitry Andric       return UnableToLegalize;
1443d409305fSDimitry Andric 
14440b57cec5SDimitry Andric     unsigned NumParts = SizeOp0 / NarrowSize;
14455ffd83dbSDimitry Andric     SmallVector<Register, 2> DstRegs(NumParts);
14465ffd83dbSDimitry Andric     SmallVector<SmallVector<Register, 2>, 2> SrcRegs(MI.getNumOperands() / 2);
14470b57cec5SDimitry Andric     Observer.changingInstr(MI);
14480b57cec5SDimitry Andric     for (unsigned i = 1; i < MI.getNumOperands(); i += 2) {
14490b57cec5SDimitry Andric       MachineBasicBlock &OpMBB = *MI.getOperand(i + 1).getMBB();
1450bdd1243dSDimitry Andric       MIRBuilder.setInsertPt(OpMBB, OpMBB.getFirstTerminatorForward());
14510b57cec5SDimitry Andric       extractParts(MI.getOperand(i).getReg(), NarrowTy, NumParts,
1452*7a6dacacSDimitry Andric                    SrcRegs[i / 2], MIRBuilder, MRI);
14530b57cec5SDimitry Andric     }
14540b57cec5SDimitry Andric     MachineBasicBlock &MBB = *MI.getParent();
14550b57cec5SDimitry Andric     MIRBuilder.setInsertPt(MBB, MI);
14560b57cec5SDimitry Andric     for (unsigned i = 0; i < NumParts; ++i) {
14570b57cec5SDimitry Andric       DstRegs[i] = MRI.createGenericVirtualRegister(NarrowTy);
14580b57cec5SDimitry Andric       MachineInstrBuilder MIB =
14590b57cec5SDimitry Andric           MIRBuilder.buildInstr(TargetOpcode::G_PHI).addDef(DstRegs[i]);
14600b57cec5SDimitry Andric       for (unsigned j = 1; j < MI.getNumOperands(); j += 2)
14610b57cec5SDimitry Andric         MIB.addUse(SrcRegs[j / 2][i]).add(MI.getOperand(j + 1));
14620b57cec5SDimitry Andric     }
14638bcb0991SDimitry Andric     MIRBuilder.setInsertPt(MBB, MBB.getFirstNonPHI());
1464bdd1243dSDimitry Andric     MIRBuilder.buildMergeLikeInstr(MI.getOperand(0), DstRegs);
14650b57cec5SDimitry Andric     Observer.changedInstr(MI);
14660b57cec5SDimitry Andric     MI.eraseFromParent();
14670b57cec5SDimitry Andric     return Legalized;
14680b57cec5SDimitry Andric   }
14690b57cec5SDimitry Andric   case TargetOpcode::G_EXTRACT_VECTOR_ELT:
14700b57cec5SDimitry Andric   case TargetOpcode::G_INSERT_VECTOR_ELT: {
14710b57cec5SDimitry Andric     if (TypeIdx != 2)
14720b57cec5SDimitry Andric       return UnableToLegalize;
14730b57cec5SDimitry Andric 
14740b57cec5SDimitry Andric     int OpIdx = MI.getOpcode() == TargetOpcode::G_EXTRACT_VECTOR_ELT ? 2 : 3;
14750b57cec5SDimitry Andric     Observer.changingInstr(MI);
14760b57cec5SDimitry Andric     narrowScalarSrc(MI, NarrowTy, OpIdx);
14770b57cec5SDimitry Andric     Observer.changedInstr(MI);
14780b57cec5SDimitry Andric     return Legalized;
14790b57cec5SDimitry Andric   }
14800b57cec5SDimitry Andric   case TargetOpcode::G_ICMP: {
1481fe6060f1SDimitry Andric     Register LHS = MI.getOperand(2).getReg();
1482fe6060f1SDimitry Andric     LLT SrcTy = MRI.getType(LHS);
1483fe6060f1SDimitry Andric     uint64_t SrcSize = SrcTy.getSizeInBits();
14840b57cec5SDimitry Andric     CmpInst::Predicate Pred =
14850b57cec5SDimitry Andric         static_cast<CmpInst::Predicate>(MI.getOperand(1).getPredicate());
14860b57cec5SDimitry Andric 
1487fe6060f1SDimitry Andric     // TODO: Handle the non-equality case for weird sizes.
1488fe6060f1SDimitry Andric     if (NarrowSize * 2 != SrcSize && !ICmpInst::isEquality(Pred))
1489fe6060f1SDimitry Andric       return UnableToLegalize;
1490fe6060f1SDimitry Andric 
1491fe6060f1SDimitry Andric     LLT LeftoverTy; // Example: s88 -> s64 (NarrowTy) + s24 (leftover)
1492fe6060f1SDimitry Andric     SmallVector<Register, 4> LHSPartRegs, LHSLeftoverRegs;
1493fe6060f1SDimitry Andric     if (!extractParts(LHS, SrcTy, NarrowTy, LeftoverTy, LHSPartRegs,
1494*7a6dacacSDimitry Andric                       LHSLeftoverRegs, MIRBuilder, MRI))
1495fe6060f1SDimitry Andric       return UnableToLegalize;
1496fe6060f1SDimitry Andric 
1497fe6060f1SDimitry Andric     LLT Unused; // Matches LeftoverTy; G_ICMP LHS and RHS are the same type.
1498fe6060f1SDimitry Andric     SmallVector<Register, 4> RHSPartRegs, RHSLeftoverRegs;
1499fe6060f1SDimitry Andric     if (!extractParts(MI.getOperand(3).getReg(), SrcTy, NarrowTy, Unused,
1500*7a6dacacSDimitry Andric                       RHSPartRegs, RHSLeftoverRegs, MIRBuilder, MRI))
1501fe6060f1SDimitry Andric       return UnableToLegalize;
1502fe6060f1SDimitry Andric 
1503fe6060f1SDimitry Andric     // We now have the LHS and RHS of the compare split into narrow-type
1504fe6060f1SDimitry Andric     // registers, plus potentially some leftover type.
1505fe6060f1SDimitry Andric     Register Dst = MI.getOperand(0).getReg();
1506fe6060f1SDimitry Andric     LLT ResTy = MRI.getType(Dst);
1507fe6060f1SDimitry Andric     if (ICmpInst::isEquality(Pred)) {
1508fe6060f1SDimitry Andric       // For each part on the LHS and RHS, keep track of the result of XOR-ing
1509fe6060f1SDimitry Andric       // them together. For each equal part, the result should be all 0s. For
1510fe6060f1SDimitry Andric       // each non-equal part, we'll get at least one 1.
1511fe6060f1SDimitry Andric       auto Zero = MIRBuilder.buildConstant(NarrowTy, 0);
1512fe6060f1SDimitry Andric       SmallVector<Register, 4> Xors;
1513fe6060f1SDimitry Andric       for (auto LHSAndRHS : zip(LHSPartRegs, RHSPartRegs)) {
1514fe6060f1SDimitry Andric         auto LHS = std::get<0>(LHSAndRHS);
1515fe6060f1SDimitry Andric         auto RHS = std::get<1>(LHSAndRHS);
1516fe6060f1SDimitry Andric         auto Xor = MIRBuilder.buildXor(NarrowTy, LHS, RHS).getReg(0);
1517fe6060f1SDimitry Andric         Xors.push_back(Xor);
1518fe6060f1SDimitry Andric       }
1519fe6060f1SDimitry Andric 
1520fe6060f1SDimitry Andric       // Build a G_XOR for each leftover register. Each G_XOR must be widened
1521fe6060f1SDimitry Andric       // to the desired narrow type so that we can OR them together later.
1522fe6060f1SDimitry Andric       SmallVector<Register, 4> WidenedXors;
1523fe6060f1SDimitry Andric       for (auto LHSAndRHS : zip(LHSLeftoverRegs, RHSLeftoverRegs)) {
1524fe6060f1SDimitry Andric         auto LHS = std::get<0>(LHSAndRHS);
1525fe6060f1SDimitry Andric         auto RHS = std::get<1>(LHSAndRHS);
1526fe6060f1SDimitry Andric         auto Xor = MIRBuilder.buildXor(LeftoverTy, LHS, RHS).getReg(0);
1527fe6060f1SDimitry Andric         LLT GCDTy = extractGCDType(WidenedXors, NarrowTy, LeftoverTy, Xor);
1528fe6060f1SDimitry Andric         buildLCMMergePieces(LeftoverTy, NarrowTy, GCDTy, WidenedXors,
1529fe6060f1SDimitry Andric                             /* PadStrategy = */ TargetOpcode::G_ZEXT);
1530fe6060f1SDimitry Andric         Xors.insert(Xors.end(), WidenedXors.begin(), WidenedXors.end());
1531fe6060f1SDimitry Andric       }
1532fe6060f1SDimitry Andric 
1533fe6060f1SDimitry Andric       // Now, for each part we broke up, we know if they are equal/not equal
1534fe6060f1SDimitry Andric       // based off the G_XOR. We can OR these all together and compare against
1535fe6060f1SDimitry Andric       // 0 to get the result.
1536fe6060f1SDimitry Andric       assert(Xors.size() >= 2 && "Should have gotten at least two Xors?");
1537fe6060f1SDimitry Andric       auto Or = MIRBuilder.buildOr(NarrowTy, Xors[0], Xors[1]);
1538fe6060f1SDimitry Andric       for (unsigned I = 2, E = Xors.size(); I < E; ++I)
1539fe6060f1SDimitry Andric         Or = MIRBuilder.buildOr(NarrowTy, Or, Xors[I]);
1540fe6060f1SDimitry Andric       MIRBuilder.buildICmp(Pred, Dst, Or, Zero);
15410b57cec5SDimitry Andric     } else {
1542fe6060f1SDimitry Andric       // TODO: Handle non-power-of-two types.
1543fe6060f1SDimitry Andric       assert(LHSPartRegs.size() == 2 && "Expected exactly 2 LHS part regs?");
1544fe6060f1SDimitry Andric       assert(RHSPartRegs.size() == 2 && "Expected exactly 2 RHS part regs?");
1545fe6060f1SDimitry Andric       Register LHSL = LHSPartRegs[0];
1546fe6060f1SDimitry Andric       Register LHSH = LHSPartRegs[1];
1547fe6060f1SDimitry Andric       Register RHSL = RHSPartRegs[0];
1548fe6060f1SDimitry Andric       Register RHSH = RHSPartRegs[1];
15498bcb0991SDimitry Andric       MachineInstrBuilder CmpH = MIRBuilder.buildICmp(Pred, ResTy, LHSH, RHSH);
15500b57cec5SDimitry Andric       MachineInstrBuilder CmpHEQ =
15518bcb0991SDimitry Andric           MIRBuilder.buildICmp(CmpInst::Predicate::ICMP_EQ, ResTy, LHSH, RHSH);
15520b57cec5SDimitry Andric       MachineInstrBuilder CmpLU = MIRBuilder.buildICmp(
15538bcb0991SDimitry Andric           ICmpInst::getUnsignedPredicate(Pred), ResTy, LHSL, RHSL);
1554fe6060f1SDimitry Andric       MIRBuilder.buildSelect(Dst, CmpHEQ, CmpLU, CmpH);
15550b57cec5SDimitry Andric     }
15560b57cec5SDimitry Andric     MI.eraseFromParent();
15570b57cec5SDimitry Andric     return Legalized;
15580b57cec5SDimitry Andric   }
15598bcb0991SDimitry Andric   case TargetOpcode::G_SEXT_INREG: {
15608bcb0991SDimitry Andric     if (TypeIdx != 0)
15618bcb0991SDimitry Andric       return UnableToLegalize;
15628bcb0991SDimitry Andric 
15638bcb0991SDimitry Andric     int64_t SizeInBits = MI.getOperand(2).getImm();
15648bcb0991SDimitry Andric 
15658bcb0991SDimitry Andric     // So long as the new type has more bits than the bits we're extending we
15668bcb0991SDimitry Andric     // don't need to break it apart.
15675f757f3fSDimitry Andric     if (NarrowTy.getScalarSizeInBits() > SizeInBits) {
15688bcb0991SDimitry Andric       Observer.changingInstr(MI);
15698bcb0991SDimitry Andric       // We don't lose any non-extension bits by truncating the src and
15708bcb0991SDimitry Andric       // sign-extending the dst.
15718bcb0991SDimitry Andric       MachineOperand &MO1 = MI.getOperand(1);
15725ffd83dbSDimitry Andric       auto TruncMIB = MIRBuilder.buildTrunc(NarrowTy, MO1);
15735ffd83dbSDimitry Andric       MO1.setReg(TruncMIB.getReg(0));
15748bcb0991SDimitry Andric 
15758bcb0991SDimitry Andric       MachineOperand &MO2 = MI.getOperand(0);
15768bcb0991SDimitry Andric       Register DstExt = MRI.createGenericVirtualRegister(NarrowTy);
15778bcb0991SDimitry Andric       MIRBuilder.setInsertPt(MIRBuilder.getMBB(), ++MIRBuilder.getInsertPt());
15785ffd83dbSDimitry Andric       MIRBuilder.buildSExt(MO2, DstExt);
15798bcb0991SDimitry Andric       MO2.setReg(DstExt);
15808bcb0991SDimitry Andric       Observer.changedInstr(MI);
15818bcb0991SDimitry Andric       return Legalized;
15828bcb0991SDimitry Andric     }
15838bcb0991SDimitry Andric 
15848bcb0991SDimitry Andric     // Break it apart. Components below the extension point are unmodified. The
15858bcb0991SDimitry Andric     // component containing the extension point becomes a narrower SEXT_INREG.
15868bcb0991SDimitry Andric     // Components above it are ashr'd from the component containing the
15878bcb0991SDimitry Andric     // extension point.
15888bcb0991SDimitry Andric     if (SizeOp0 % NarrowSize != 0)
15898bcb0991SDimitry Andric       return UnableToLegalize;
15908bcb0991SDimitry Andric     int NumParts = SizeOp0 / NarrowSize;
15918bcb0991SDimitry Andric 
15928bcb0991SDimitry Andric     // List the registers where the destination will be scattered.
15938bcb0991SDimitry Andric     SmallVector<Register, 2> DstRegs;
15948bcb0991SDimitry Andric     // List the registers where the source will be split.
15958bcb0991SDimitry Andric     SmallVector<Register, 2> SrcRegs;
15968bcb0991SDimitry Andric 
15978bcb0991SDimitry Andric     // Create all the temporary registers.
15988bcb0991SDimitry Andric     for (int i = 0; i < NumParts; ++i) {
15998bcb0991SDimitry Andric       Register SrcReg = MRI.createGenericVirtualRegister(NarrowTy);
16008bcb0991SDimitry Andric 
16018bcb0991SDimitry Andric       SrcRegs.push_back(SrcReg);
16028bcb0991SDimitry Andric     }
16038bcb0991SDimitry Andric 
16048bcb0991SDimitry Andric     // Explode the big arguments into smaller chunks.
16055ffd83dbSDimitry Andric     MIRBuilder.buildUnmerge(SrcRegs, MI.getOperand(1));
16068bcb0991SDimitry Andric 
16078bcb0991SDimitry Andric     Register AshrCstReg =
16088bcb0991SDimitry Andric         MIRBuilder.buildConstant(NarrowTy, NarrowTy.getScalarSizeInBits() - 1)
16095ffd83dbSDimitry Andric             .getReg(0);
16105f757f3fSDimitry Andric     Register FullExtensionReg;
16115f757f3fSDimitry Andric     Register PartialExtensionReg;
16128bcb0991SDimitry Andric 
16138bcb0991SDimitry Andric     // Do the operation on each small part.
16148bcb0991SDimitry Andric     for (int i = 0; i < NumParts; ++i) {
16155f757f3fSDimitry Andric       if ((i + 1) * NarrowTy.getScalarSizeInBits() <= SizeInBits) {
16168bcb0991SDimitry Andric         DstRegs.push_back(SrcRegs[i]);
16175f757f3fSDimitry Andric         PartialExtensionReg = DstRegs.back();
16185f757f3fSDimitry Andric       } else if (i * NarrowTy.getScalarSizeInBits() >= SizeInBits) {
16198bcb0991SDimitry Andric         assert(PartialExtensionReg &&
16208bcb0991SDimitry Andric                "Expected to visit partial extension before full");
16218bcb0991SDimitry Andric         if (FullExtensionReg) {
16228bcb0991SDimitry Andric           DstRegs.push_back(FullExtensionReg);
16238bcb0991SDimitry Andric           continue;
16248bcb0991SDimitry Andric         }
16255ffd83dbSDimitry Andric         DstRegs.push_back(
16265ffd83dbSDimitry Andric             MIRBuilder.buildAShr(NarrowTy, PartialExtensionReg, AshrCstReg)
16275ffd83dbSDimitry Andric                 .getReg(0));
16288bcb0991SDimitry Andric         FullExtensionReg = DstRegs.back();
16298bcb0991SDimitry Andric       } else {
16308bcb0991SDimitry Andric         DstRegs.push_back(
16318bcb0991SDimitry Andric             MIRBuilder
16328bcb0991SDimitry Andric                 .buildInstr(
16338bcb0991SDimitry Andric                     TargetOpcode::G_SEXT_INREG, {NarrowTy},
16348bcb0991SDimitry Andric                     {SrcRegs[i], SizeInBits % NarrowTy.getScalarSizeInBits()})
16355ffd83dbSDimitry Andric                 .getReg(0));
16368bcb0991SDimitry Andric         PartialExtensionReg = DstRegs.back();
16378bcb0991SDimitry Andric       }
16388bcb0991SDimitry Andric     }
16398bcb0991SDimitry Andric 
16408bcb0991SDimitry Andric     // Gather the destination registers into the final destination.
16418bcb0991SDimitry Andric     Register DstReg = MI.getOperand(0).getReg();
1642bdd1243dSDimitry Andric     MIRBuilder.buildMergeLikeInstr(DstReg, DstRegs);
16438bcb0991SDimitry Andric     MI.eraseFromParent();
16448bcb0991SDimitry Andric     return Legalized;
16458bcb0991SDimitry Andric   }
1646480093f4SDimitry Andric   case TargetOpcode::G_BSWAP:
1647480093f4SDimitry Andric   case TargetOpcode::G_BITREVERSE: {
1648480093f4SDimitry Andric     if (SizeOp0 % NarrowSize != 0)
1649480093f4SDimitry Andric       return UnableToLegalize;
1650480093f4SDimitry Andric 
1651480093f4SDimitry Andric     Observer.changingInstr(MI);
1652480093f4SDimitry Andric     SmallVector<Register, 2> SrcRegs, DstRegs;
1653480093f4SDimitry Andric     unsigned NumParts = SizeOp0 / NarrowSize;
1654*7a6dacacSDimitry Andric     extractParts(MI.getOperand(1).getReg(), NarrowTy, NumParts, SrcRegs,
1655*7a6dacacSDimitry Andric                  MIRBuilder, MRI);
1656480093f4SDimitry Andric 
1657480093f4SDimitry Andric     for (unsigned i = 0; i < NumParts; ++i) {
1658480093f4SDimitry Andric       auto DstPart = MIRBuilder.buildInstr(MI.getOpcode(), {NarrowTy},
1659480093f4SDimitry Andric                                            {SrcRegs[NumParts - 1 - i]});
1660480093f4SDimitry Andric       DstRegs.push_back(DstPart.getReg(0));
1661480093f4SDimitry Andric     }
1662480093f4SDimitry Andric 
1663bdd1243dSDimitry Andric     MIRBuilder.buildMergeLikeInstr(MI.getOperand(0), DstRegs);
1664480093f4SDimitry Andric 
1665480093f4SDimitry Andric     Observer.changedInstr(MI);
1666480093f4SDimitry Andric     MI.eraseFromParent();
1667480093f4SDimitry Andric     return Legalized;
1668480093f4SDimitry Andric   }
1669e8d8bef9SDimitry Andric   case TargetOpcode::G_PTR_ADD:
16705ffd83dbSDimitry Andric   case TargetOpcode::G_PTRMASK: {
16715ffd83dbSDimitry Andric     if (TypeIdx != 1)
16725ffd83dbSDimitry Andric       return UnableToLegalize;
16735ffd83dbSDimitry Andric     Observer.changingInstr(MI);
16745ffd83dbSDimitry Andric     narrowScalarSrc(MI, NarrowTy, 2);
16755ffd83dbSDimitry Andric     Observer.changedInstr(MI);
16765ffd83dbSDimitry Andric     return Legalized;
16770b57cec5SDimitry Andric   }
167823408297SDimitry Andric   case TargetOpcode::G_FPTOUI:
167923408297SDimitry Andric   case TargetOpcode::G_FPTOSI:
168023408297SDimitry Andric     return narrowScalarFPTOI(MI, TypeIdx, NarrowTy);
1681e8d8bef9SDimitry Andric   case TargetOpcode::G_FPEXT:
1682e8d8bef9SDimitry Andric     if (TypeIdx != 0)
1683e8d8bef9SDimitry Andric       return UnableToLegalize;
1684e8d8bef9SDimitry Andric     Observer.changingInstr(MI);
1685e8d8bef9SDimitry Andric     narrowScalarDst(MI, NarrowTy, 0, TargetOpcode::G_FPEXT);
1686e8d8bef9SDimitry Andric     Observer.changedInstr(MI);
1687e8d8bef9SDimitry Andric     return Legalized;
168806c3fb27SDimitry Andric   case TargetOpcode::G_FLDEXP:
168906c3fb27SDimitry Andric   case TargetOpcode::G_STRICT_FLDEXP:
169006c3fb27SDimitry Andric     return narrowScalarFLDEXP(MI, TypeIdx, NarrowTy);
16910b57cec5SDimitry Andric   }
16925ffd83dbSDimitry Andric }
16935ffd83dbSDimitry Andric 
16945ffd83dbSDimitry Andric Register LegalizerHelper::coerceToScalar(Register Val) {
16955ffd83dbSDimitry Andric   LLT Ty = MRI.getType(Val);
16965ffd83dbSDimitry Andric   if (Ty.isScalar())
16975ffd83dbSDimitry Andric     return Val;
16985ffd83dbSDimitry Andric 
16995ffd83dbSDimitry Andric   const DataLayout &DL = MIRBuilder.getDataLayout();
17005ffd83dbSDimitry Andric   LLT NewTy = LLT::scalar(Ty.getSizeInBits());
17015ffd83dbSDimitry Andric   if (Ty.isPointer()) {
17025ffd83dbSDimitry Andric     if (DL.isNonIntegralAddressSpace(Ty.getAddressSpace()))
17035ffd83dbSDimitry Andric       return Register();
17045ffd83dbSDimitry Andric     return MIRBuilder.buildPtrToInt(NewTy, Val).getReg(0);
17055ffd83dbSDimitry Andric   }
17065ffd83dbSDimitry Andric 
17075ffd83dbSDimitry Andric   Register NewVal = Val;
17085ffd83dbSDimitry Andric 
17095ffd83dbSDimitry Andric   assert(Ty.isVector());
17105ffd83dbSDimitry Andric   LLT EltTy = Ty.getElementType();
17115ffd83dbSDimitry Andric   if (EltTy.isPointer())
17125ffd83dbSDimitry Andric     NewVal = MIRBuilder.buildPtrToInt(NewTy, NewVal).getReg(0);
17135ffd83dbSDimitry Andric   return MIRBuilder.buildBitcast(NewTy, NewVal).getReg(0);
17145ffd83dbSDimitry Andric }
17150b57cec5SDimitry Andric 
17160b57cec5SDimitry Andric void LegalizerHelper::widenScalarSrc(MachineInstr &MI, LLT WideTy,
17170b57cec5SDimitry Andric                                      unsigned OpIdx, unsigned ExtOpcode) {
17180b57cec5SDimitry Andric   MachineOperand &MO = MI.getOperand(OpIdx);
17195ffd83dbSDimitry Andric   auto ExtB = MIRBuilder.buildInstr(ExtOpcode, {WideTy}, {MO});
17205ffd83dbSDimitry Andric   MO.setReg(ExtB.getReg(0));
17210b57cec5SDimitry Andric }
17220b57cec5SDimitry Andric 
17230b57cec5SDimitry Andric void LegalizerHelper::narrowScalarSrc(MachineInstr &MI, LLT NarrowTy,
17240b57cec5SDimitry Andric                                       unsigned OpIdx) {
17250b57cec5SDimitry Andric   MachineOperand &MO = MI.getOperand(OpIdx);
17265ffd83dbSDimitry Andric   auto ExtB = MIRBuilder.buildTrunc(NarrowTy, MO);
17275ffd83dbSDimitry Andric   MO.setReg(ExtB.getReg(0));
17280b57cec5SDimitry Andric }
17290b57cec5SDimitry Andric 
17300b57cec5SDimitry Andric void LegalizerHelper::widenScalarDst(MachineInstr &MI, LLT WideTy,
17310b57cec5SDimitry Andric                                      unsigned OpIdx, unsigned TruncOpcode) {
17320b57cec5SDimitry Andric   MachineOperand &MO = MI.getOperand(OpIdx);
17330b57cec5SDimitry Andric   Register DstExt = MRI.createGenericVirtualRegister(WideTy);
17340b57cec5SDimitry Andric   MIRBuilder.setInsertPt(MIRBuilder.getMBB(), ++MIRBuilder.getInsertPt());
17355ffd83dbSDimitry Andric   MIRBuilder.buildInstr(TruncOpcode, {MO}, {DstExt});
17360b57cec5SDimitry Andric   MO.setReg(DstExt);
17370b57cec5SDimitry Andric }
17380b57cec5SDimitry Andric 
17390b57cec5SDimitry Andric void LegalizerHelper::narrowScalarDst(MachineInstr &MI, LLT NarrowTy,
17400b57cec5SDimitry Andric                                       unsigned OpIdx, unsigned ExtOpcode) {
17410b57cec5SDimitry Andric   MachineOperand &MO = MI.getOperand(OpIdx);
17420b57cec5SDimitry Andric   Register DstTrunc = MRI.createGenericVirtualRegister(NarrowTy);
17430b57cec5SDimitry Andric   MIRBuilder.setInsertPt(MIRBuilder.getMBB(), ++MIRBuilder.getInsertPt());
17445ffd83dbSDimitry Andric   MIRBuilder.buildInstr(ExtOpcode, {MO}, {DstTrunc});
17450b57cec5SDimitry Andric   MO.setReg(DstTrunc);
17460b57cec5SDimitry Andric }
17470b57cec5SDimitry Andric 
17480b57cec5SDimitry Andric void LegalizerHelper::moreElementsVectorDst(MachineInstr &MI, LLT WideTy,
17490b57cec5SDimitry Andric                                             unsigned OpIdx) {
17500b57cec5SDimitry Andric   MachineOperand &MO = MI.getOperand(OpIdx);
17510b57cec5SDimitry Andric   MIRBuilder.setInsertPt(MIRBuilder.getMBB(), ++MIRBuilder.getInsertPt());
17520eae32dcSDimitry Andric   Register Dst = MO.getReg();
17530eae32dcSDimitry Andric   Register DstExt = MRI.createGenericVirtualRegister(WideTy);
17540eae32dcSDimitry Andric   MO.setReg(DstExt);
17550eae32dcSDimitry Andric   MIRBuilder.buildDeleteTrailingVectorElements(Dst, DstExt);
17560b57cec5SDimitry Andric }
17570b57cec5SDimitry Andric 
17580b57cec5SDimitry Andric void LegalizerHelper::moreElementsVectorSrc(MachineInstr &MI, LLT MoreTy,
17590b57cec5SDimitry Andric                                             unsigned OpIdx) {
17600b57cec5SDimitry Andric   MachineOperand &MO = MI.getOperand(OpIdx);
17610eae32dcSDimitry Andric   SmallVector<Register, 8> Regs;
17620eae32dcSDimitry Andric   MO.setReg(MIRBuilder.buildPadVectorWithUndefElements(MoreTy, MO).getReg(0));
17630b57cec5SDimitry Andric }
17640b57cec5SDimitry Andric 
17655ffd83dbSDimitry Andric void LegalizerHelper::bitcastSrc(MachineInstr &MI, LLT CastTy, unsigned OpIdx) {
17665ffd83dbSDimitry Andric   MachineOperand &Op = MI.getOperand(OpIdx);
17675ffd83dbSDimitry Andric   Op.setReg(MIRBuilder.buildBitcast(CastTy, Op).getReg(0));
17685ffd83dbSDimitry Andric }
17695ffd83dbSDimitry Andric 
17705ffd83dbSDimitry Andric void LegalizerHelper::bitcastDst(MachineInstr &MI, LLT CastTy, unsigned OpIdx) {
17715ffd83dbSDimitry Andric   MachineOperand &MO = MI.getOperand(OpIdx);
17725ffd83dbSDimitry Andric   Register CastDst = MRI.createGenericVirtualRegister(CastTy);
17735ffd83dbSDimitry Andric   MIRBuilder.setInsertPt(MIRBuilder.getMBB(), ++MIRBuilder.getInsertPt());
17745ffd83dbSDimitry Andric   MIRBuilder.buildBitcast(MO, CastDst);
17755ffd83dbSDimitry Andric   MO.setReg(CastDst);
17765ffd83dbSDimitry Andric }
17775ffd83dbSDimitry Andric 
17780b57cec5SDimitry Andric LegalizerHelper::LegalizeResult
17790b57cec5SDimitry Andric LegalizerHelper::widenScalarMergeValues(MachineInstr &MI, unsigned TypeIdx,
17800b57cec5SDimitry Andric                                         LLT WideTy) {
17810b57cec5SDimitry Andric   if (TypeIdx != 1)
17820b57cec5SDimitry Andric     return UnableToLegalize;
17830b57cec5SDimitry Andric 
178406c3fb27SDimitry Andric   auto [DstReg, DstTy, Src1Reg, Src1Ty] = MI.getFirst2RegLLTs();
17850b57cec5SDimitry Andric   if (DstTy.isVector())
17860b57cec5SDimitry Andric     return UnableToLegalize;
17870b57cec5SDimitry Andric 
178806c3fb27SDimitry Andric   LLT SrcTy = MRI.getType(Src1Reg);
17890b57cec5SDimitry Andric   const int DstSize = DstTy.getSizeInBits();
17900b57cec5SDimitry Andric   const int SrcSize = SrcTy.getSizeInBits();
17910b57cec5SDimitry Andric   const int WideSize = WideTy.getSizeInBits();
17920b57cec5SDimitry Andric   const int NumMerge = (DstSize + WideSize - 1) / WideSize;
17930b57cec5SDimitry Andric 
17940b57cec5SDimitry Andric   unsigned NumOps = MI.getNumOperands();
17950b57cec5SDimitry Andric   unsigned NumSrc = MI.getNumOperands() - 1;
17960b57cec5SDimitry Andric   unsigned PartSize = DstTy.getSizeInBits() / NumSrc;
17970b57cec5SDimitry Andric 
17980b57cec5SDimitry Andric   if (WideSize >= DstSize) {
17990b57cec5SDimitry Andric     // Directly pack the bits in the target type.
180006c3fb27SDimitry Andric     Register ResultReg = MIRBuilder.buildZExt(WideTy, Src1Reg).getReg(0);
18010b57cec5SDimitry Andric 
18020b57cec5SDimitry Andric     for (unsigned I = 2; I != NumOps; ++I) {
18030b57cec5SDimitry Andric       const unsigned Offset = (I - 1) * PartSize;
18040b57cec5SDimitry Andric 
18050b57cec5SDimitry Andric       Register SrcReg = MI.getOperand(I).getReg();
18060b57cec5SDimitry Andric       assert(MRI.getType(SrcReg) == LLT::scalar(PartSize));
18070b57cec5SDimitry Andric 
18080b57cec5SDimitry Andric       auto ZextInput = MIRBuilder.buildZExt(WideTy, SrcReg);
18090b57cec5SDimitry Andric 
18108bcb0991SDimitry Andric       Register NextResult = I + 1 == NumOps && WideTy == DstTy ? DstReg :
18110b57cec5SDimitry Andric         MRI.createGenericVirtualRegister(WideTy);
18120b57cec5SDimitry Andric 
18130b57cec5SDimitry Andric       auto ShiftAmt = MIRBuilder.buildConstant(WideTy, Offset);
18140b57cec5SDimitry Andric       auto Shl = MIRBuilder.buildShl(WideTy, ZextInput, ShiftAmt);
18150b57cec5SDimitry Andric       MIRBuilder.buildOr(NextResult, ResultReg, Shl);
18160b57cec5SDimitry Andric       ResultReg = NextResult;
18170b57cec5SDimitry Andric     }
18180b57cec5SDimitry Andric 
18190b57cec5SDimitry Andric     if (WideSize > DstSize)
18200b57cec5SDimitry Andric       MIRBuilder.buildTrunc(DstReg, ResultReg);
18218bcb0991SDimitry Andric     else if (DstTy.isPointer())
18228bcb0991SDimitry Andric       MIRBuilder.buildIntToPtr(DstReg, ResultReg);
18230b57cec5SDimitry Andric 
18240b57cec5SDimitry Andric     MI.eraseFromParent();
18250b57cec5SDimitry Andric     return Legalized;
18260b57cec5SDimitry Andric   }
18270b57cec5SDimitry Andric 
18280b57cec5SDimitry Andric   // Unmerge the original values to the GCD type, and recombine to the next
18290b57cec5SDimitry Andric   // multiple greater than the original type.
18300b57cec5SDimitry Andric   //
18310b57cec5SDimitry Andric   // %3:_(s12) = G_MERGE_VALUES %0:_(s4), %1:_(s4), %2:_(s4) -> s6
18320b57cec5SDimitry Andric   // %4:_(s2), %5:_(s2) = G_UNMERGE_VALUES %0
18330b57cec5SDimitry Andric   // %6:_(s2), %7:_(s2) = G_UNMERGE_VALUES %1
18340b57cec5SDimitry Andric   // %8:_(s2), %9:_(s2) = G_UNMERGE_VALUES %2
18350b57cec5SDimitry Andric   // %10:_(s6) = G_MERGE_VALUES %4, %5, %6
18360b57cec5SDimitry Andric   // %11:_(s6) = G_MERGE_VALUES %7, %8, %9
18370b57cec5SDimitry Andric   // %12:_(s12) = G_MERGE_VALUES %10, %11
18380b57cec5SDimitry Andric   //
18390b57cec5SDimitry Andric   // Padding with undef if necessary:
18400b57cec5SDimitry Andric   //
18410b57cec5SDimitry Andric   // %2:_(s8) = G_MERGE_VALUES %0:_(s4), %1:_(s4) -> s6
18420b57cec5SDimitry Andric   // %3:_(s2), %4:_(s2) = G_UNMERGE_VALUES %0
18430b57cec5SDimitry Andric   // %5:_(s2), %6:_(s2) = G_UNMERGE_VALUES %1
18440b57cec5SDimitry Andric   // %7:_(s2) = G_IMPLICIT_DEF
18450b57cec5SDimitry Andric   // %8:_(s6) = G_MERGE_VALUES %3, %4, %5
18460b57cec5SDimitry Andric   // %9:_(s6) = G_MERGE_VALUES %6, %7, %7
18470b57cec5SDimitry Andric   // %10:_(s12) = G_MERGE_VALUES %8, %9
18480b57cec5SDimitry Andric 
1849bdd1243dSDimitry Andric   const int GCD = std::gcd(SrcSize, WideSize);
18500b57cec5SDimitry Andric   LLT GCDTy = LLT::scalar(GCD);
18510b57cec5SDimitry Andric 
18520b57cec5SDimitry Andric   SmallVector<Register, 8> Parts;
18530b57cec5SDimitry Andric   SmallVector<Register, 8> NewMergeRegs;
18540b57cec5SDimitry Andric   SmallVector<Register, 8> Unmerges;
18550b57cec5SDimitry Andric   LLT WideDstTy = LLT::scalar(NumMerge * WideSize);
18560b57cec5SDimitry Andric 
18570b57cec5SDimitry Andric   // Decompose the original operands if they don't evenly divide.
18584824e7fdSDimitry Andric   for (const MachineOperand &MO : llvm::drop_begin(MI.operands())) {
18594824e7fdSDimitry Andric     Register SrcReg = MO.getReg();
18600b57cec5SDimitry Andric     if (GCD == SrcSize) {
18610b57cec5SDimitry Andric       Unmerges.push_back(SrcReg);
18620b57cec5SDimitry Andric     } else {
18630b57cec5SDimitry Andric       auto Unmerge = MIRBuilder.buildUnmerge(GCDTy, SrcReg);
18640b57cec5SDimitry Andric       for (int J = 0, JE = Unmerge->getNumOperands() - 1; J != JE; ++J)
18650b57cec5SDimitry Andric         Unmerges.push_back(Unmerge.getReg(J));
18660b57cec5SDimitry Andric     }
18670b57cec5SDimitry Andric   }
18680b57cec5SDimitry Andric 
18690b57cec5SDimitry Andric   // Pad with undef to the next size that is a multiple of the requested size.
18700b57cec5SDimitry Andric   if (static_cast<int>(Unmerges.size()) != NumMerge * WideSize) {
18710b57cec5SDimitry Andric     Register UndefReg = MIRBuilder.buildUndef(GCDTy).getReg(0);
18720b57cec5SDimitry Andric     for (int I = Unmerges.size(); I != NumMerge * WideSize; ++I)
18730b57cec5SDimitry Andric       Unmerges.push_back(UndefReg);
18740b57cec5SDimitry Andric   }
18750b57cec5SDimitry Andric 
18760b57cec5SDimitry Andric   const int PartsPerGCD = WideSize / GCD;
18770b57cec5SDimitry Andric 
18780b57cec5SDimitry Andric   // Build merges of each piece.
18790b57cec5SDimitry Andric   ArrayRef<Register> Slicer(Unmerges);
18800b57cec5SDimitry Andric   for (int I = 0; I != NumMerge; ++I, Slicer = Slicer.drop_front(PartsPerGCD)) {
1881bdd1243dSDimitry Andric     auto Merge =
1882bdd1243dSDimitry Andric         MIRBuilder.buildMergeLikeInstr(WideTy, Slicer.take_front(PartsPerGCD));
18830b57cec5SDimitry Andric     NewMergeRegs.push_back(Merge.getReg(0));
18840b57cec5SDimitry Andric   }
18850b57cec5SDimitry Andric 
18860b57cec5SDimitry Andric   // A truncate may be necessary if the requested type doesn't evenly divide the
18870b57cec5SDimitry Andric   // original result type.
18880b57cec5SDimitry Andric   if (DstTy.getSizeInBits() == WideDstTy.getSizeInBits()) {
1889bdd1243dSDimitry Andric     MIRBuilder.buildMergeLikeInstr(DstReg, NewMergeRegs);
18900b57cec5SDimitry Andric   } else {
1891bdd1243dSDimitry Andric     auto FinalMerge = MIRBuilder.buildMergeLikeInstr(WideDstTy, NewMergeRegs);
18920b57cec5SDimitry Andric     MIRBuilder.buildTrunc(DstReg, FinalMerge.getReg(0));
18930b57cec5SDimitry Andric   }
18940b57cec5SDimitry Andric 
18950b57cec5SDimitry Andric   MI.eraseFromParent();
18960b57cec5SDimitry Andric   return Legalized;
18970b57cec5SDimitry Andric }
18980b57cec5SDimitry Andric 
18990b57cec5SDimitry Andric LegalizerHelper::LegalizeResult
19000b57cec5SDimitry Andric LegalizerHelper::widenScalarUnmergeValues(MachineInstr &MI, unsigned TypeIdx,
19010b57cec5SDimitry Andric                                           LLT WideTy) {
19020b57cec5SDimitry Andric   if (TypeIdx != 0)
19030b57cec5SDimitry Andric     return UnableToLegalize;
19040b57cec5SDimitry Andric 
19055ffd83dbSDimitry Andric   int NumDst = MI.getNumOperands() - 1;
19060b57cec5SDimitry Andric   Register SrcReg = MI.getOperand(NumDst).getReg();
19070b57cec5SDimitry Andric   LLT SrcTy = MRI.getType(SrcReg);
19085ffd83dbSDimitry Andric   if (SrcTy.isVector())
19090b57cec5SDimitry Andric     return UnableToLegalize;
19100b57cec5SDimitry Andric 
19110b57cec5SDimitry Andric   Register Dst0Reg = MI.getOperand(0).getReg();
19120b57cec5SDimitry Andric   LLT DstTy = MRI.getType(Dst0Reg);
19130b57cec5SDimitry Andric   if (!DstTy.isScalar())
19140b57cec5SDimitry Andric     return UnableToLegalize;
19150b57cec5SDimitry Andric 
19165ffd83dbSDimitry Andric   if (WideTy.getSizeInBits() >= SrcTy.getSizeInBits()) {
19175ffd83dbSDimitry Andric     if (SrcTy.isPointer()) {
19185ffd83dbSDimitry Andric       const DataLayout &DL = MIRBuilder.getDataLayout();
19195ffd83dbSDimitry Andric       if (DL.isNonIntegralAddressSpace(SrcTy.getAddressSpace())) {
19205ffd83dbSDimitry Andric         LLVM_DEBUG(
19215ffd83dbSDimitry Andric             dbgs() << "Not casting non-integral address space integer\n");
19225ffd83dbSDimitry Andric         return UnableToLegalize;
19230b57cec5SDimitry Andric       }
19240b57cec5SDimitry Andric 
19255ffd83dbSDimitry Andric       SrcTy = LLT::scalar(SrcTy.getSizeInBits());
19265ffd83dbSDimitry Andric       SrcReg = MIRBuilder.buildPtrToInt(SrcTy, SrcReg).getReg(0);
19275ffd83dbSDimitry Andric     }
19280b57cec5SDimitry Andric 
19295ffd83dbSDimitry Andric     // Widen SrcTy to WideTy. This does not affect the result, but since the
19305ffd83dbSDimitry Andric     // user requested this size, it is probably better handled than SrcTy and
193104eeddc0SDimitry Andric     // should reduce the total number of legalization artifacts.
19325ffd83dbSDimitry Andric     if (WideTy.getSizeInBits() > SrcTy.getSizeInBits()) {
19335ffd83dbSDimitry Andric       SrcTy = WideTy;
19345ffd83dbSDimitry Andric       SrcReg = MIRBuilder.buildAnyExt(WideTy, SrcReg).getReg(0);
19355ffd83dbSDimitry Andric     }
19360b57cec5SDimitry Andric 
19375ffd83dbSDimitry Andric     // Theres no unmerge type to target. Directly extract the bits from the
19385ffd83dbSDimitry Andric     // source type
19395ffd83dbSDimitry Andric     unsigned DstSize = DstTy.getSizeInBits();
19400b57cec5SDimitry Andric 
19415ffd83dbSDimitry Andric     MIRBuilder.buildTrunc(Dst0Reg, SrcReg);
19425ffd83dbSDimitry Andric     for (int I = 1; I != NumDst; ++I) {
19435ffd83dbSDimitry Andric       auto ShiftAmt = MIRBuilder.buildConstant(SrcTy, DstSize * I);
19445ffd83dbSDimitry Andric       auto Shr = MIRBuilder.buildLShr(SrcTy, SrcReg, ShiftAmt);
19455ffd83dbSDimitry Andric       MIRBuilder.buildTrunc(MI.getOperand(I), Shr);
19465ffd83dbSDimitry Andric     }
19475ffd83dbSDimitry Andric 
19485ffd83dbSDimitry Andric     MI.eraseFromParent();
19495ffd83dbSDimitry Andric     return Legalized;
19505ffd83dbSDimitry Andric   }
19515ffd83dbSDimitry Andric 
19525ffd83dbSDimitry Andric   // Extend the source to a wider type.
19535ffd83dbSDimitry Andric   LLT LCMTy = getLCMType(SrcTy, WideTy);
19545ffd83dbSDimitry Andric 
19555ffd83dbSDimitry Andric   Register WideSrc = SrcReg;
19565ffd83dbSDimitry Andric   if (LCMTy.getSizeInBits() != SrcTy.getSizeInBits()) {
19575ffd83dbSDimitry Andric     // TODO: If this is an integral address space, cast to integer and anyext.
19585ffd83dbSDimitry Andric     if (SrcTy.isPointer()) {
19595ffd83dbSDimitry Andric       LLVM_DEBUG(dbgs() << "Widening pointer source types not implemented\n");
19605ffd83dbSDimitry Andric       return UnableToLegalize;
19615ffd83dbSDimitry Andric     }
19625ffd83dbSDimitry Andric 
19635ffd83dbSDimitry Andric     WideSrc = MIRBuilder.buildAnyExt(LCMTy, WideSrc).getReg(0);
19645ffd83dbSDimitry Andric   }
19655ffd83dbSDimitry Andric 
19665ffd83dbSDimitry Andric   auto Unmerge = MIRBuilder.buildUnmerge(WideTy, WideSrc);
19675ffd83dbSDimitry Andric 
1968e8d8bef9SDimitry Andric   // Create a sequence of unmerges and merges to the original results. Since we
1969e8d8bef9SDimitry Andric   // may have widened the source, we will need to pad the results with dead defs
1970e8d8bef9SDimitry Andric   // to cover the source register.
1971e8d8bef9SDimitry Andric   // e.g. widen s48 to s64:
1972e8d8bef9SDimitry Andric   // %1:_(s48), %2:_(s48) = G_UNMERGE_VALUES %0:_(s96)
19735ffd83dbSDimitry Andric   //
19745ffd83dbSDimitry Andric   // =>
1975e8d8bef9SDimitry Andric   //  %4:_(s192) = G_ANYEXT %0:_(s96)
1976e8d8bef9SDimitry Andric   //  %5:_(s64), %6, %7 = G_UNMERGE_VALUES %4 ; Requested unmerge
1977e8d8bef9SDimitry Andric   //  ; unpack to GCD type, with extra dead defs
1978e8d8bef9SDimitry Andric   //  %8:_(s16), %9, %10, %11 = G_UNMERGE_VALUES %5:_(s64)
1979e8d8bef9SDimitry Andric   //  %12:_(s16), %13, dead %14, dead %15 = G_UNMERGE_VALUES %6:_(s64)
1980e8d8bef9SDimitry Andric   //  dead %16:_(s16), dead %17, dead %18, dead %18 = G_UNMERGE_VALUES %7:_(s64)
1981e8d8bef9SDimitry Andric   //  %1:_(s48) = G_MERGE_VALUES %8:_(s16), %9, %10   ; Remerge to destination
1982e8d8bef9SDimitry Andric   //  %2:_(s48) = G_MERGE_VALUES %11:_(s16), %12, %13 ; Remerge to destination
1983e8d8bef9SDimitry Andric   const LLT GCDTy = getGCDType(WideTy, DstTy);
19845ffd83dbSDimitry Andric   const int NumUnmerge = Unmerge->getNumOperands() - 1;
1985e8d8bef9SDimitry Andric   const int PartsPerRemerge = DstTy.getSizeInBits() / GCDTy.getSizeInBits();
1986e8d8bef9SDimitry Andric 
1987e8d8bef9SDimitry Andric   // Directly unmerge to the destination without going through a GCD type
1988e8d8bef9SDimitry Andric   // if possible
1989e8d8bef9SDimitry Andric   if (PartsPerRemerge == 1) {
19905ffd83dbSDimitry Andric     const int PartsPerUnmerge = WideTy.getSizeInBits() / DstTy.getSizeInBits();
19915ffd83dbSDimitry Andric 
19925ffd83dbSDimitry Andric     for (int I = 0; I != NumUnmerge; ++I) {
19935ffd83dbSDimitry Andric       auto MIB = MIRBuilder.buildInstr(TargetOpcode::G_UNMERGE_VALUES);
19945ffd83dbSDimitry Andric 
19955ffd83dbSDimitry Andric       for (int J = 0; J != PartsPerUnmerge; ++J) {
19965ffd83dbSDimitry Andric         int Idx = I * PartsPerUnmerge + J;
19975ffd83dbSDimitry Andric         if (Idx < NumDst)
19985ffd83dbSDimitry Andric           MIB.addDef(MI.getOperand(Idx).getReg());
19995ffd83dbSDimitry Andric         else {
20005ffd83dbSDimitry Andric           // Create dead def for excess components.
20015ffd83dbSDimitry Andric           MIB.addDef(MRI.createGenericVirtualRegister(DstTy));
20025ffd83dbSDimitry Andric         }
20035ffd83dbSDimitry Andric       }
20045ffd83dbSDimitry Andric 
20055ffd83dbSDimitry Andric       MIB.addUse(Unmerge.getReg(I));
20065ffd83dbSDimitry Andric     }
2007e8d8bef9SDimitry Andric   } else {
2008e8d8bef9SDimitry Andric     SmallVector<Register, 16> Parts;
2009e8d8bef9SDimitry Andric     for (int J = 0; J != NumUnmerge; ++J)
2010e8d8bef9SDimitry Andric       extractGCDType(Parts, GCDTy, Unmerge.getReg(J));
2011e8d8bef9SDimitry Andric 
2012e8d8bef9SDimitry Andric     SmallVector<Register, 8> RemergeParts;
2013e8d8bef9SDimitry Andric     for (int I = 0; I != NumDst; ++I) {
2014e8d8bef9SDimitry Andric       for (int J = 0; J < PartsPerRemerge; ++J) {
2015e8d8bef9SDimitry Andric         const int Idx = I * PartsPerRemerge + J;
2016e8d8bef9SDimitry Andric         RemergeParts.emplace_back(Parts[Idx]);
2017e8d8bef9SDimitry Andric       }
2018e8d8bef9SDimitry Andric 
2019bdd1243dSDimitry Andric       MIRBuilder.buildMergeLikeInstr(MI.getOperand(I).getReg(), RemergeParts);
2020e8d8bef9SDimitry Andric       RemergeParts.clear();
2021e8d8bef9SDimitry Andric     }
2022e8d8bef9SDimitry Andric   }
20235ffd83dbSDimitry Andric 
20245ffd83dbSDimitry Andric   MI.eraseFromParent();
20250b57cec5SDimitry Andric   return Legalized;
20260b57cec5SDimitry Andric }
20270b57cec5SDimitry Andric 
20280b57cec5SDimitry Andric LegalizerHelper::LegalizeResult
20290b57cec5SDimitry Andric LegalizerHelper::widenScalarExtract(MachineInstr &MI, unsigned TypeIdx,
20300b57cec5SDimitry Andric                                     LLT WideTy) {
203106c3fb27SDimitry Andric   auto [DstReg, DstTy, SrcReg, SrcTy] = MI.getFirst2RegLLTs();
20320b57cec5SDimitry Andric   unsigned Offset = MI.getOperand(2).getImm();
20330b57cec5SDimitry Andric 
20340b57cec5SDimitry Andric   if (TypeIdx == 0) {
20350b57cec5SDimitry Andric     if (SrcTy.isVector() || DstTy.isVector())
20360b57cec5SDimitry Andric       return UnableToLegalize;
20370b57cec5SDimitry Andric 
20380b57cec5SDimitry Andric     SrcOp Src(SrcReg);
20390b57cec5SDimitry Andric     if (SrcTy.isPointer()) {
20400b57cec5SDimitry Andric       // Extracts from pointers can be handled only if they are really just
20410b57cec5SDimitry Andric       // simple integers.
20420b57cec5SDimitry Andric       const DataLayout &DL = MIRBuilder.getDataLayout();
20430b57cec5SDimitry Andric       if (DL.isNonIntegralAddressSpace(SrcTy.getAddressSpace()))
20440b57cec5SDimitry Andric         return UnableToLegalize;
20450b57cec5SDimitry Andric 
20460b57cec5SDimitry Andric       LLT SrcAsIntTy = LLT::scalar(SrcTy.getSizeInBits());
20470b57cec5SDimitry Andric       Src = MIRBuilder.buildPtrToInt(SrcAsIntTy, Src);
20480b57cec5SDimitry Andric       SrcTy = SrcAsIntTy;
20490b57cec5SDimitry Andric     }
20500b57cec5SDimitry Andric 
20510b57cec5SDimitry Andric     if (DstTy.isPointer())
20520b57cec5SDimitry Andric       return UnableToLegalize;
20530b57cec5SDimitry Andric 
20540b57cec5SDimitry Andric     if (Offset == 0) {
20550b57cec5SDimitry Andric       // Avoid a shift in the degenerate case.
20560b57cec5SDimitry Andric       MIRBuilder.buildTrunc(DstReg,
20570b57cec5SDimitry Andric                             MIRBuilder.buildAnyExtOrTrunc(WideTy, Src));
20580b57cec5SDimitry Andric       MI.eraseFromParent();
20590b57cec5SDimitry Andric       return Legalized;
20600b57cec5SDimitry Andric     }
20610b57cec5SDimitry Andric 
20620b57cec5SDimitry Andric     // Do a shift in the source type.
20630b57cec5SDimitry Andric     LLT ShiftTy = SrcTy;
20640b57cec5SDimitry Andric     if (WideTy.getSizeInBits() > SrcTy.getSizeInBits()) {
20650b57cec5SDimitry Andric       Src = MIRBuilder.buildAnyExt(WideTy, Src);
20660b57cec5SDimitry Andric       ShiftTy = WideTy;
2067e8d8bef9SDimitry Andric     }
20680b57cec5SDimitry Andric 
20690b57cec5SDimitry Andric     auto LShr = MIRBuilder.buildLShr(
20700b57cec5SDimitry Andric       ShiftTy, Src, MIRBuilder.buildConstant(ShiftTy, Offset));
20710b57cec5SDimitry Andric     MIRBuilder.buildTrunc(DstReg, LShr);
20720b57cec5SDimitry Andric     MI.eraseFromParent();
20730b57cec5SDimitry Andric     return Legalized;
20740b57cec5SDimitry Andric   }
20750b57cec5SDimitry Andric 
20760b57cec5SDimitry Andric   if (SrcTy.isScalar()) {
20770b57cec5SDimitry Andric     Observer.changingInstr(MI);
20780b57cec5SDimitry Andric     widenScalarSrc(MI, WideTy, 1, TargetOpcode::G_ANYEXT);
20790b57cec5SDimitry Andric     Observer.changedInstr(MI);
20800b57cec5SDimitry Andric     return Legalized;
20810b57cec5SDimitry Andric   }
20820b57cec5SDimitry Andric 
20830b57cec5SDimitry Andric   if (!SrcTy.isVector())
20840b57cec5SDimitry Andric     return UnableToLegalize;
20850b57cec5SDimitry Andric 
20860b57cec5SDimitry Andric   if (DstTy != SrcTy.getElementType())
20870b57cec5SDimitry Andric     return UnableToLegalize;
20880b57cec5SDimitry Andric 
20890b57cec5SDimitry Andric   if (Offset % SrcTy.getScalarSizeInBits() != 0)
20900b57cec5SDimitry Andric     return UnableToLegalize;
20910b57cec5SDimitry Andric 
20920b57cec5SDimitry Andric   Observer.changingInstr(MI);
20930b57cec5SDimitry Andric   widenScalarSrc(MI, WideTy, 1, TargetOpcode::G_ANYEXT);
20940b57cec5SDimitry Andric 
20950b57cec5SDimitry Andric   MI.getOperand(2).setImm((WideTy.getSizeInBits() / SrcTy.getSizeInBits()) *
20960b57cec5SDimitry Andric                           Offset);
20970b57cec5SDimitry Andric   widenScalarDst(MI, WideTy.getScalarType(), 0);
20980b57cec5SDimitry Andric   Observer.changedInstr(MI);
20990b57cec5SDimitry Andric   return Legalized;
21000b57cec5SDimitry Andric }
21010b57cec5SDimitry Andric 
21020b57cec5SDimitry Andric LegalizerHelper::LegalizeResult
21030b57cec5SDimitry Andric LegalizerHelper::widenScalarInsert(MachineInstr &MI, unsigned TypeIdx,
21040b57cec5SDimitry Andric                                    LLT WideTy) {
2105e8d8bef9SDimitry Andric   if (TypeIdx != 0 || WideTy.isVector())
21060b57cec5SDimitry Andric     return UnableToLegalize;
21070b57cec5SDimitry Andric   Observer.changingInstr(MI);
21080b57cec5SDimitry Andric   widenScalarSrc(MI, WideTy, 1, TargetOpcode::G_ANYEXT);
21090b57cec5SDimitry Andric   widenScalarDst(MI, WideTy);
21100b57cec5SDimitry Andric   Observer.changedInstr(MI);
21110b57cec5SDimitry Andric   return Legalized;
21120b57cec5SDimitry Andric }
21130b57cec5SDimitry Andric 
21140b57cec5SDimitry Andric LegalizerHelper::LegalizeResult
2115fe6060f1SDimitry Andric LegalizerHelper::widenScalarAddSubOverflow(MachineInstr &MI, unsigned TypeIdx,
2116e8d8bef9SDimitry Andric                                            LLT WideTy) {
2117fe6060f1SDimitry Andric   unsigned Opcode;
2118fe6060f1SDimitry Andric   unsigned ExtOpcode;
2119bdd1243dSDimitry Andric   std::optional<Register> CarryIn;
2120fe6060f1SDimitry Andric   switch (MI.getOpcode()) {
2121fe6060f1SDimitry Andric   default:
2122fe6060f1SDimitry Andric     llvm_unreachable("Unexpected opcode!");
2123fe6060f1SDimitry Andric   case TargetOpcode::G_SADDO:
2124fe6060f1SDimitry Andric     Opcode = TargetOpcode::G_ADD;
2125fe6060f1SDimitry Andric     ExtOpcode = TargetOpcode::G_SEXT;
2126fe6060f1SDimitry Andric     break;
2127fe6060f1SDimitry Andric   case TargetOpcode::G_SSUBO:
2128fe6060f1SDimitry Andric     Opcode = TargetOpcode::G_SUB;
2129fe6060f1SDimitry Andric     ExtOpcode = TargetOpcode::G_SEXT;
2130fe6060f1SDimitry Andric     break;
2131fe6060f1SDimitry Andric   case TargetOpcode::G_UADDO:
2132fe6060f1SDimitry Andric     Opcode = TargetOpcode::G_ADD;
2133fe6060f1SDimitry Andric     ExtOpcode = TargetOpcode::G_ZEXT;
2134fe6060f1SDimitry Andric     break;
2135fe6060f1SDimitry Andric   case TargetOpcode::G_USUBO:
2136fe6060f1SDimitry Andric     Opcode = TargetOpcode::G_SUB;
2137fe6060f1SDimitry Andric     ExtOpcode = TargetOpcode::G_ZEXT;
2138fe6060f1SDimitry Andric     break;
2139fe6060f1SDimitry Andric   case TargetOpcode::G_SADDE:
2140fe6060f1SDimitry Andric     Opcode = TargetOpcode::G_UADDE;
2141fe6060f1SDimitry Andric     ExtOpcode = TargetOpcode::G_SEXT;
2142fe6060f1SDimitry Andric     CarryIn = MI.getOperand(4).getReg();
2143fe6060f1SDimitry Andric     break;
2144fe6060f1SDimitry Andric   case TargetOpcode::G_SSUBE:
2145fe6060f1SDimitry Andric     Opcode = TargetOpcode::G_USUBE;
2146fe6060f1SDimitry Andric     ExtOpcode = TargetOpcode::G_SEXT;
2147fe6060f1SDimitry Andric     CarryIn = MI.getOperand(4).getReg();
2148fe6060f1SDimitry Andric     break;
2149fe6060f1SDimitry Andric   case TargetOpcode::G_UADDE:
2150fe6060f1SDimitry Andric     Opcode = TargetOpcode::G_UADDE;
2151fe6060f1SDimitry Andric     ExtOpcode = TargetOpcode::G_ZEXT;
2152fe6060f1SDimitry Andric     CarryIn = MI.getOperand(4).getReg();
2153fe6060f1SDimitry Andric     break;
2154fe6060f1SDimitry Andric   case TargetOpcode::G_USUBE:
2155fe6060f1SDimitry Andric     Opcode = TargetOpcode::G_USUBE;
2156fe6060f1SDimitry Andric     ExtOpcode = TargetOpcode::G_ZEXT;
2157fe6060f1SDimitry Andric     CarryIn = MI.getOperand(4).getReg();
2158fe6060f1SDimitry Andric     break;
2159fe6060f1SDimitry Andric   }
2160fe6060f1SDimitry Andric 
216181ad6265SDimitry Andric   if (TypeIdx == 1) {
216281ad6265SDimitry Andric     unsigned BoolExtOp = MIRBuilder.getBoolExtOp(WideTy.isVector(), false);
216381ad6265SDimitry Andric 
216481ad6265SDimitry Andric     Observer.changingInstr(MI);
216581ad6265SDimitry Andric     if (CarryIn)
216681ad6265SDimitry Andric       widenScalarSrc(MI, WideTy, 4, BoolExtOp);
2167bdd1243dSDimitry Andric     widenScalarDst(MI, WideTy, 1);
216881ad6265SDimitry Andric 
216981ad6265SDimitry Andric     Observer.changedInstr(MI);
217081ad6265SDimitry Andric     return Legalized;
217181ad6265SDimitry Andric   }
217281ad6265SDimitry Andric 
2173e8d8bef9SDimitry Andric   auto LHSExt = MIRBuilder.buildInstr(ExtOpcode, {WideTy}, {MI.getOperand(2)});
2174e8d8bef9SDimitry Andric   auto RHSExt = MIRBuilder.buildInstr(ExtOpcode, {WideTy}, {MI.getOperand(3)});
2175e8d8bef9SDimitry Andric   // Do the arithmetic in the larger type.
2176fe6060f1SDimitry Andric   Register NewOp;
2177fe6060f1SDimitry Andric   if (CarryIn) {
2178fe6060f1SDimitry Andric     LLT CarryOutTy = MRI.getType(MI.getOperand(1).getReg());
2179fe6060f1SDimitry Andric     NewOp = MIRBuilder
2180fe6060f1SDimitry Andric                 .buildInstr(Opcode, {WideTy, CarryOutTy},
2181fe6060f1SDimitry Andric                             {LHSExt, RHSExt, *CarryIn})
2182fe6060f1SDimitry Andric                 .getReg(0);
2183fe6060f1SDimitry Andric   } else {
2184fe6060f1SDimitry Andric     NewOp = MIRBuilder.buildInstr(Opcode, {WideTy}, {LHSExt, RHSExt}).getReg(0);
2185fe6060f1SDimitry Andric   }
2186e8d8bef9SDimitry Andric   LLT OrigTy = MRI.getType(MI.getOperand(0).getReg());
2187e8d8bef9SDimitry Andric   auto TruncOp = MIRBuilder.buildTrunc(OrigTy, NewOp);
2188e8d8bef9SDimitry Andric   auto ExtOp = MIRBuilder.buildInstr(ExtOpcode, {WideTy}, {TruncOp});
2189e8d8bef9SDimitry Andric   // There is no overflow if the ExtOp is the same as NewOp.
2190e8d8bef9SDimitry Andric   MIRBuilder.buildICmp(CmpInst::ICMP_NE, MI.getOperand(1), NewOp, ExtOp);
2191e8d8bef9SDimitry Andric   // Now trunc the NewOp to the original result.
2192e8d8bef9SDimitry Andric   MIRBuilder.buildTrunc(MI.getOperand(0), NewOp);
2193e8d8bef9SDimitry Andric   MI.eraseFromParent();
2194e8d8bef9SDimitry Andric   return Legalized;
2195e8d8bef9SDimitry Andric }
2196e8d8bef9SDimitry Andric 
2197e8d8bef9SDimitry Andric LegalizerHelper::LegalizeResult
2198e8d8bef9SDimitry Andric LegalizerHelper::widenScalarAddSubShlSat(MachineInstr &MI, unsigned TypeIdx,
21995ffd83dbSDimitry Andric                                          LLT WideTy) {
22005ffd83dbSDimitry Andric   bool IsSigned = MI.getOpcode() == TargetOpcode::G_SADDSAT ||
2201e8d8bef9SDimitry Andric                   MI.getOpcode() == TargetOpcode::G_SSUBSAT ||
2202e8d8bef9SDimitry Andric                   MI.getOpcode() == TargetOpcode::G_SSHLSAT;
2203e8d8bef9SDimitry Andric   bool IsShift = MI.getOpcode() == TargetOpcode::G_SSHLSAT ||
2204e8d8bef9SDimitry Andric                  MI.getOpcode() == TargetOpcode::G_USHLSAT;
22055ffd83dbSDimitry Andric   // We can convert this to:
22065ffd83dbSDimitry Andric   //   1. Any extend iN to iM
22075ffd83dbSDimitry Andric   //   2. SHL by M-N
2208e8d8bef9SDimitry Andric   //   3. [US][ADD|SUB|SHL]SAT
22095ffd83dbSDimitry Andric   //   4. L/ASHR by M-N
22105ffd83dbSDimitry Andric   //
22115ffd83dbSDimitry Andric   // It may be more efficient to lower this to a min and a max operation in
22125ffd83dbSDimitry Andric   // the higher precision arithmetic if the promoted operation isn't legal,
22135ffd83dbSDimitry Andric   // but this decision is up to the target's lowering request.
22145ffd83dbSDimitry Andric   Register DstReg = MI.getOperand(0).getReg();
22150b57cec5SDimitry Andric 
22165ffd83dbSDimitry Andric   unsigned NewBits = WideTy.getScalarSizeInBits();
22175ffd83dbSDimitry Andric   unsigned SHLAmount = NewBits - MRI.getType(DstReg).getScalarSizeInBits();
22185ffd83dbSDimitry Andric 
2219e8d8bef9SDimitry Andric   // Shifts must zero-extend the RHS to preserve the unsigned quantity, and
2220e8d8bef9SDimitry Andric   // must not left shift the RHS to preserve the shift amount.
22215ffd83dbSDimitry Andric   auto LHS = MIRBuilder.buildAnyExt(WideTy, MI.getOperand(1));
2222e8d8bef9SDimitry Andric   auto RHS = IsShift ? MIRBuilder.buildZExt(WideTy, MI.getOperand(2))
2223e8d8bef9SDimitry Andric                      : MIRBuilder.buildAnyExt(WideTy, MI.getOperand(2));
22245ffd83dbSDimitry Andric   auto ShiftK = MIRBuilder.buildConstant(WideTy, SHLAmount);
22255ffd83dbSDimitry Andric   auto ShiftL = MIRBuilder.buildShl(WideTy, LHS, ShiftK);
2226e8d8bef9SDimitry Andric   auto ShiftR = IsShift ? RHS : MIRBuilder.buildShl(WideTy, RHS, ShiftK);
22275ffd83dbSDimitry Andric 
22285ffd83dbSDimitry Andric   auto WideInst = MIRBuilder.buildInstr(MI.getOpcode(), {WideTy},
22295ffd83dbSDimitry Andric                                         {ShiftL, ShiftR}, MI.getFlags());
22305ffd83dbSDimitry Andric 
22315ffd83dbSDimitry Andric   // Use a shift that will preserve the number of sign bits when the trunc is
22325ffd83dbSDimitry Andric   // folded away.
22335ffd83dbSDimitry Andric   auto Result = IsSigned ? MIRBuilder.buildAShr(WideTy, WideInst, ShiftK)
22345ffd83dbSDimitry Andric                          : MIRBuilder.buildLShr(WideTy, WideInst, ShiftK);
22355ffd83dbSDimitry Andric 
22365ffd83dbSDimitry Andric   MIRBuilder.buildTrunc(DstReg, Result);
22375ffd83dbSDimitry Andric   MI.eraseFromParent();
22385ffd83dbSDimitry Andric   return Legalized;
22395ffd83dbSDimitry Andric }
22405ffd83dbSDimitry Andric 
22415ffd83dbSDimitry Andric LegalizerHelper::LegalizeResult
2242fe6060f1SDimitry Andric LegalizerHelper::widenScalarMulo(MachineInstr &MI, unsigned TypeIdx,
2243fe6060f1SDimitry Andric                                  LLT WideTy) {
224481ad6265SDimitry Andric   if (TypeIdx == 1) {
224581ad6265SDimitry Andric     Observer.changingInstr(MI);
224681ad6265SDimitry Andric     widenScalarDst(MI, WideTy, 1);
224781ad6265SDimitry Andric     Observer.changedInstr(MI);
224881ad6265SDimitry Andric     return Legalized;
224981ad6265SDimitry Andric   }
2250fe6060f1SDimitry Andric 
2251fe6060f1SDimitry Andric   bool IsSigned = MI.getOpcode() == TargetOpcode::G_SMULO;
225206c3fb27SDimitry Andric   auto [Result, OriginalOverflow, LHS, RHS] = MI.getFirst4Regs();
2253fe6060f1SDimitry Andric   LLT SrcTy = MRI.getType(LHS);
2254fe6060f1SDimitry Andric   LLT OverflowTy = MRI.getType(OriginalOverflow);
2255fe6060f1SDimitry Andric   unsigned SrcBitWidth = SrcTy.getScalarSizeInBits();
2256fe6060f1SDimitry Andric 
2257fe6060f1SDimitry Andric   // To determine if the result overflowed in the larger type, we extend the
2258fe6060f1SDimitry Andric   // input to the larger type, do the multiply (checking if it overflows),
2259fe6060f1SDimitry Andric   // then also check the high bits of the result to see if overflow happened
2260fe6060f1SDimitry Andric   // there.
2261fe6060f1SDimitry Andric   unsigned ExtOp = IsSigned ? TargetOpcode::G_SEXT : TargetOpcode::G_ZEXT;
2262fe6060f1SDimitry Andric   auto LeftOperand = MIRBuilder.buildInstr(ExtOp, {WideTy}, {LHS});
2263fe6060f1SDimitry Andric   auto RightOperand = MIRBuilder.buildInstr(ExtOp, {WideTy}, {RHS});
2264fe6060f1SDimitry Andric 
22655f757f3fSDimitry Andric   // Multiplication cannot overflow if the WideTy is >= 2 * original width,
22665f757f3fSDimitry Andric   // so we don't need to check the overflow result of larger type Mulo.
22675f757f3fSDimitry Andric   bool WideMulCanOverflow = WideTy.getScalarSizeInBits() < 2 * SrcBitWidth;
22685f757f3fSDimitry Andric 
22695f757f3fSDimitry Andric   unsigned MulOpc =
22705f757f3fSDimitry Andric       WideMulCanOverflow ? MI.getOpcode() : (unsigned)TargetOpcode::G_MUL;
22715f757f3fSDimitry Andric 
22725f757f3fSDimitry Andric   MachineInstrBuilder Mulo;
22735f757f3fSDimitry Andric   if (WideMulCanOverflow)
22745f757f3fSDimitry Andric     Mulo = MIRBuilder.buildInstr(MulOpc, {WideTy, OverflowTy},
2275fe6060f1SDimitry Andric                                  {LeftOperand, RightOperand});
22765f757f3fSDimitry Andric   else
22775f757f3fSDimitry Andric     Mulo = MIRBuilder.buildInstr(MulOpc, {WideTy}, {LeftOperand, RightOperand});
22785f757f3fSDimitry Andric 
2279fe6060f1SDimitry Andric   auto Mul = Mulo->getOperand(0);
2280fe6060f1SDimitry Andric   MIRBuilder.buildTrunc(Result, Mul);
2281fe6060f1SDimitry Andric 
2282fe6060f1SDimitry Andric   MachineInstrBuilder ExtResult;
2283fe6060f1SDimitry Andric   // Overflow occurred if it occurred in the larger type, or if the high part
2284fe6060f1SDimitry Andric   // of the result does not zero/sign-extend the low part.  Check this second
2285fe6060f1SDimitry Andric   // possibility first.
2286fe6060f1SDimitry Andric   if (IsSigned) {
2287fe6060f1SDimitry Andric     // For signed, overflow occurred when the high part does not sign-extend
2288fe6060f1SDimitry Andric     // the low part.
2289fe6060f1SDimitry Andric     ExtResult = MIRBuilder.buildSExtInReg(WideTy, Mul, SrcBitWidth);
2290fe6060f1SDimitry Andric   } else {
2291fe6060f1SDimitry Andric     // Unsigned overflow occurred when the high part does not zero-extend the
2292fe6060f1SDimitry Andric     // low part.
2293fe6060f1SDimitry Andric     ExtResult = MIRBuilder.buildZExtInReg(WideTy, Mul, SrcBitWidth);
2294fe6060f1SDimitry Andric   }
2295fe6060f1SDimitry Andric 
22965f757f3fSDimitry Andric   if (WideMulCanOverflow) {
2297fe6060f1SDimitry Andric     auto Overflow =
2298fe6060f1SDimitry Andric         MIRBuilder.buildICmp(CmpInst::ICMP_NE, OverflowTy, Mul, ExtResult);
2299fe6060f1SDimitry Andric     // Finally check if the multiplication in the larger type itself overflowed.
2300fe6060f1SDimitry Andric     MIRBuilder.buildOr(OriginalOverflow, Mulo->getOperand(1), Overflow);
2301fe6060f1SDimitry Andric   } else {
2302fe6060f1SDimitry Andric     MIRBuilder.buildICmp(CmpInst::ICMP_NE, OriginalOverflow, Mul, ExtResult);
2303fe6060f1SDimitry Andric   }
2304fe6060f1SDimitry Andric   MI.eraseFromParent();
2305fe6060f1SDimitry Andric   return Legalized;
2306fe6060f1SDimitry Andric }
2307fe6060f1SDimitry Andric 
2308fe6060f1SDimitry Andric LegalizerHelper::LegalizeResult
23095ffd83dbSDimitry Andric LegalizerHelper::widenScalar(MachineInstr &MI, unsigned TypeIdx, LLT WideTy) {
23100b57cec5SDimitry Andric   switch (MI.getOpcode()) {
23110b57cec5SDimitry Andric   default:
23120b57cec5SDimitry Andric     return UnableToLegalize;
2313fe6060f1SDimitry Andric   case TargetOpcode::G_ATOMICRMW_XCHG:
2314fe6060f1SDimitry Andric   case TargetOpcode::G_ATOMICRMW_ADD:
2315fe6060f1SDimitry Andric   case TargetOpcode::G_ATOMICRMW_SUB:
2316fe6060f1SDimitry Andric   case TargetOpcode::G_ATOMICRMW_AND:
2317fe6060f1SDimitry Andric   case TargetOpcode::G_ATOMICRMW_OR:
2318fe6060f1SDimitry Andric   case TargetOpcode::G_ATOMICRMW_XOR:
2319fe6060f1SDimitry Andric   case TargetOpcode::G_ATOMICRMW_MIN:
2320fe6060f1SDimitry Andric   case TargetOpcode::G_ATOMICRMW_MAX:
2321fe6060f1SDimitry Andric   case TargetOpcode::G_ATOMICRMW_UMIN:
2322fe6060f1SDimitry Andric   case TargetOpcode::G_ATOMICRMW_UMAX:
2323fe6060f1SDimitry Andric     assert(TypeIdx == 0 && "atomicrmw with second scalar type");
2324fe6060f1SDimitry Andric     Observer.changingInstr(MI);
2325fe6060f1SDimitry Andric     widenScalarSrc(MI, WideTy, 2, TargetOpcode::G_ANYEXT);
2326fe6060f1SDimitry Andric     widenScalarDst(MI, WideTy, 0);
2327fe6060f1SDimitry Andric     Observer.changedInstr(MI);
2328fe6060f1SDimitry Andric     return Legalized;
2329fe6060f1SDimitry Andric   case TargetOpcode::G_ATOMIC_CMPXCHG:
2330fe6060f1SDimitry Andric     assert(TypeIdx == 0 && "G_ATOMIC_CMPXCHG with second scalar type");
2331fe6060f1SDimitry Andric     Observer.changingInstr(MI);
2332fe6060f1SDimitry Andric     widenScalarSrc(MI, WideTy, 2, TargetOpcode::G_ANYEXT);
2333fe6060f1SDimitry Andric     widenScalarSrc(MI, WideTy, 3, TargetOpcode::G_ANYEXT);
2334fe6060f1SDimitry Andric     widenScalarDst(MI, WideTy, 0);
2335fe6060f1SDimitry Andric     Observer.changedInstr(MI);
2336fe6060f1SDimitry Andric     return Legalized;
2337fe6060f1SDimitry Andric   case TargetOpcode::G_ATOMIC_CMPXCHG_WITH_SUCCESS:
2338fe6060f1SDimitry Andric     if (TypeIdx == 0) {
2339fe6060f1SDimitry Andric       Observer.changingInstr(MI);
2340fe6060f1SDimitry Andric       widenScalarSrc(MI, WideTy, 3, TargetOpcode::G_ANYEXT);
2341fe6060f1SDimitry Andric       widenScalarSrc(MI, WideTy, 4, TargetOpcode::G_ANYEXT);
2342fe6060f1SDimitry Andric       widenScalarDst(MI, WideTy, 0);
2343fe6060f1SDimitry Andric       Observer.changedInstr(MI);
2344fe6060f1SDimitry Andric       return Legalized;
2345fe6060f1SDimitry Andric     }
2346fe6060f1SDimitry Andric     assert(TypeIdx == 1 &&
2347fe6060f1SDimitry Andric            "G_ATOMIC_CMPXCHG_WITH_SUCCESS with third scalar type");
2348fe6060f1SDimitry Andric     Observer.changingInstr(MI);
2349fe6060f1SDimitry Andric     widenScalarDst(MI, WideTy, 1);
2350fe6060f1SDimitry Andric     Observer.changedInstr(MI);
2351fe6060f1SDimitry Andric     return Legalized;
23520b57cec5SDimitry Andric   case TargetOpcode::G_EXTRACT:
23530b57cec5SDimitry Andric     return widenScalarExtract(MI, TypeIdx, WideTy);
23540b57cec5SDimitry Andric   case TargetOpcode::G_INSERT:
23550b57cec5SDimitry Andric     return widenScalarInsert(MI, TypeIdx, WideTy);
23560b57cec5SDimitry Andric   case TargetOpcode::G_MERGE_VALUES:
23570b57cec5SDimitry Andric     return widenScalarMergeValues(MI, TypeIdx, WideTy);
23580b57cec5SDimitry Andric   case TargetOpcode::G_UNMERGE_VALUES:
23590b57cec5SDimitry Andric     return widenScalarUnmergeValues(MI, TypeIdx, WideTy);
2360e8d8bef9SDimitry Andric   case TargetOpcode::G_SADDO:
2361e8d8bef9SDimitry Andric   case TargetOpcode::G_SSUBO:
23620b57cec5SDimitry Andric   case TargetOpcode::G_UADDO:
2363e8d8bef9SDimitry Andric   case TargetOpcode::G_USUBO:
2364fe6060f1SDimitry Andric   case TargetOpcode::G_SADDE:
2365fe6060f1SDimitry Andric   case TargetOpcode::G_SSUBE:
2366fe6060f1SDimitry Andric   case TargetOpcode::G_UADDE:
2367fe6060f1SDimitry Andric   case TargetOpcode::G_USUBE:
2368fe6060f1SDimitry Andric     return widenScalarAddSubOverflow(MI, TypeIdx, WideTy);
2369fe6060f1SDimitry Andric   case TargetOpcode::G_UMULO:
2370fe6060f1SDimitry Andric   case TargetOpcode::G_SMULO:
2371fe6060f1SDimitry Andric     return widenScalarMulo(MI, TypeIdx, WideTy);
23725ffd83dbSDimitry Andric   case TargetOpcode::G_SADDSAT:
23735ffd83dbSDimitry Andric   case TargetOpcode::G_SSUBSAT:
2374e8d8bef9SDimitry Andric   case TargetOpcode::G_SSHLSAT:
23755ffd83dbSDimitry Andric   case TargetOpcode::G_UADDSAT:
23765ffd83dbSDimitry Andric   case TargetOpcode::G_USUBSAT:
2377e8d8bef9SDimitry Andric   case TargetOpcode::G_USHLSAT:
2378e8d8bef9SDimitry Andric     return widenScalarAddSubShlSat(MI, TypeIdx, WideTy);
23790b57cec5SDimitry Andric   case TargetOpcode::G_CTTZ:
23800b57cec5SDimitry Andric   case TargetOpcode::G_CTTZ_ZERO_UNDEF:
23810b57cec5SDimitry Andric   case TargetOpcode::G_CTLZ:
23820b57cec5SDimitry Andric   case TargetOpcode::G_CTLZ_ZERO_UNDEF:
23830b57cec5SDimitry Andric   case TargetOpcode::G_CTPOP: {
23840b57cec5SDimitry Andric     if (TypeIdx == 0) {
23850b57cec5SDimitry Andric       Observer.changingInstr(MI);
23860b57cec5SDimitry Andric       widenScalarDst(MI, WideTy, 0);
23870b57cec5SDimitry Andric       Observer.changedInstr(MI);
23880b57cec5SDimitry Andric       return Legalized;
23890b57cec5SDimitry Andric     }
23900b57cec5SDimitry Andric 
23910b57cec5SDimitry Andric     Register SrcReg = MI.getOperand(1).getReg();
23920b57cec5SDimitry Andric 
2393349cc55cSDimitry Andric     // First extend the input.
2394349cc55cSDimitry Andric     unsigned ExtOpc = MI.getOpcode() == TargetOpcode::G_CTTZ ||
2395349cc55cSDimitry Andric                               MI.getOpcode() == TargetOpcode::G_CTTZ_ZERO_UNDEF
2396349cc55cSDimitry Andric                           ? TargetOpcode::G_ANYEXT
2397349cc55cSDimitry Andric                           : TargetOpcode::G_ZEXT;
2398349cc55cSDimitry Andric     auto MIBSrc = MIRBuilder.buildInstr(ExtOpc, {WideTy}, {SrcReg});
23990b57cec5SDimitry Andric     LLT CurTy = MRI.getType(SrcReg);
2400349cc55cSDimitry Andric     unsigned NewOpc = MI.getOpcode();
2401349cc55cSDimitry Andric     if (NewOpc == TargetOpcode::G_CTTZ) {
24020b57cec5SDimitry Andric       // The count is the same in the larger type except if the original
24030b57cec5SDimitry Andric       // value was zero.  This can be handled by setting the bit just off
24040b57cec5SDimitry Andric       // the top of the original type.
24050b57cec5SDimitry Andric       auto TopBit =
24060b57cec5SDimitry Andric           APInt::getOneBitSet(WideTy.getSizeInBits(), CurTy.getSizeInBits());
24070b57cec5SDimitry Andric       MIBSrc = MIRBuilder.buildOr(
24080b57cec5SDimitry Andric         WideTy, MIBSrc, MIRBuilder.buildConstant(WideTy, TopBit));
2409349cc55cSDimitry Andric       // Now we know the operand is non-zero, use the more relaxed opcode.
2410349cc55cSDimitry Andric       NewOpc = TargetOpcode::G_CTTZ_ZERO_UNDEF;
24110b57cec5SDimitry Andric     }
24120b57cec5SDimitry Andric 
24130b57cec5SDimitry Andric     // Perform the operation at the larger size.
2414349cc55cSDimitry Andric     auto MIBNewOp = MIRBuilder.buildInstr(NewOpc, {WideTy}, {MIBSrc});
24150b57cec5SDimitry Andric     // This is already the correct result for CTPOP and CTTZs
24160b57cec5SDimitry Andric     if (MI.getOpcode() == TargetOpcode::G_CTLZ ||
24170b57cec5SDimitry Andric         MI.getOpcode() == TargetOpcode::G_CTLZ_ZERO_UNDEF) {
24180b57cec5SDimitry Andric       // The correct result is NewOp - (Difference in widety and current ty).
24190b57cec5SDimitry Andric       unsigned SizeDiff = WideTy.getSizeInBits() - CurTy.getSizeInBits();
24205ffd83dbSDimitry Andric       MIBNewOp = MIRBuilder.buildSub(
24215ffd83dbSDimitry Andric           WideTy, MIBNewOp, MIRBuilder.buildConstant(WideTy, SizeDiff));
24220b57cec5SDimitry Andric     }
24230b57cec5SDimitry Andric 
24240b57cec5SDimitry Andric     MIRBuilder.buildZExtOrTrunc(MI.getOperand(0), MIBNewOp);
24250b57cec5SDimitry Andric     MI.eraseFromParent();
24260b57cec5SDimitry Andric     return Legalized;
24270b57cec5SDimitry Andric   }
24280b57cec5SDimitry Andric   case TargetOpcode::G_BSWAP: {
24290b57cec5SDimitry Andric     Observer.changingInstr(MI);
24300b57cec5SDimitry Andric     Register DstReg = MI.getOperand(0).getReg();
24310b57cec5SDimitry Andric 
24320b57cec5SDimitry Andric     Register ShrReg = MRI.createGenericVirtualRegister(WideTy);
24330b57cec5SDimitry Andric     Register DstExt = MRI.createGenericVirtualRegister(WideTy);
24340b57cec5SDimitry Andric     Register ShiftAmtReg = MRI.createGenericVirtualRegister(WideTy);
24350b57cec5SDimitry Andric     widenScalarSrc(MI, WideTy, 1, TargetOpcode::G_ANYEXT);
24360b57cec5SDimitry Andric 
24370b57cec5SDimitry Andric     MI.getOperand(0).setReg(DstExt);
24380b57cec5SDimitry Andric 
24390b57cec5SDimitry Andric     MIRBuilder.setInsertPt(MIRBuilder.getMBB(), ++MIRBuilder.getInsertPt());
24400b57cec5SDimitry Andric 
24410b57cec5SDimitry Andric     LLT Ty = MRI.getType(DstReg);
24420b57cec5SDimitry Andric     unsigned DiffBits = WideTy.getScalarSizeInBits() - Ty.getScalarSizeInBits();
24430b57cec5SDimitry Andric     MIRBuilder.buildConstant(ShiftAmtReg, DiffBits);
24445ffd83dbSDimitry Andric     MIRBuilder.buildLShr(ShrReg, DstExt, ShiftAmtReg);
24450b57cec5SDimitry Andric 
24460b57cec5SDimitry Andric     MIRBuilder.buildTrunc(DstReg, ShrReg);
24470b57cec5SDimitry Andric     Observer.changedInstr(MI);
24480b57cec5SDimitry Andric     return Legalized;
24490b57cec5SDimitry Andric   }
24508bcb0991SDimitry Andric   case TargetOpcode::G_BITREVERSE: {
24518bcb0991SDimitry Andric     Observer.changingInstr(MI);
24528bcb0991SDimitry Andric 
24538bcb0991SDimitry Andric     Register DstReg = MI.getOperand(0).getReg();
24548bcb0991SDimitry Andric     LLT Ty = MRI.getType(DstReg);
24558bcb0991SDimitry Andric     unsigned DiffBits = WideTy.getScalarSizeInBits() - Ty.getScalarSizeInBits();
24568bcb0991SDimitry Andric 
24578bcb0991SDimitry Andric     Register DstExt = MRI.createGenericVirtualRegister(WideTy);
24588bcb0991SDimitry Andric     widenScalarSrc(MI, WideTy, 1, TargetOpcode::G_ANYEXT);
24598bcb0991SDimitry Andric     MI.getOperand(0).setReg(DstExt);
24608bcb0991SDimitry Andric     MIRBuilder.setInsertPt(MIRBuilder.getMBB(), ++MIRBuilder.getInsertPt());
24618bcb0991SDimitry Andric 
24628bcb0991SDimitry Andric     auto ShiftAmt = MIRBuilder.buildConstant(WideTy, DiffBits);
24638bcb0991SDimitry Andric     auto Shift = MIRBuilder.buildLShr(WideTy, DstExt, ShiftAmt);
24648bcb0991SDimitry Andric     MIRBuilder.buildTrunc(DstReg, Shift);
24658bcb0991SDimitry Andric     Observer.changedInstr(MI);
24668bcb0991SDimitry Andric     return Legalized;
24678bcb0991SDimitry Andric   }
24685ffd83dbSDimitry Andric   case TargetOpcode::G_FREEZE:
24695ffd83dbSDimitry Andric     Observer.changingInstr(MI);
24705ffd83dbSDimitry Andric     widenScalarSrc(MI, WideTy, 1, TargetOpcode::G_ANYEXT);
24715ffd83dbSDimitry Andric     widenScalarDst(MI, WideTy);
24725ffd83dbSDimitry Andric     Observer.changedInstr(MI);
24735ffd83dbSDimitry Andric     return Legalized;
24745ffd83dbSDimitry Andric 
2475fe6060f1SDimitry Andric   case TargetOpcode::G_ABS:
2476fe6060f1SDimitry Andric     Observer.changingInstr(MI);
2477fe6060f1SDimitry Andric     widenScalarSrc(MI, WideTy, 1, TargetOpcode::G_SEXT);
2478fe6060f1SDimitry Andric     widenScalarDst(MI, WideTy);
2479fe6060f1SDimitry Andric     Observer.changedInstr(MI);
2480fe6060f1SDimitry Andric     return Legalized;
2481fe6060f1SDimitry Andric 
24820b57cec5SDimitry Andric   case TargetOpcode::G_ADD:
24830b57cec5SDimitry Andric   case TargetOpcode::G_AND:
24840b57cec5SDimitry Andric   case TargetOpcode::G_MUL:
24850b57cec5SDimitry Andric   case TargetOpcode::G_OR:
24860b57cec5SDimitry Andric   case TargetOpcode::G_XOR:
24870b57cec5SDimitry Andric   case TargetOpcode::G_SUB:
24880b57cec5SDimitry Andric     // Perform operation at larger width (any extension is fines here, high bits
24890b57cec5SDimitry Andric     // don't affect the result) and then truncate the result back to the
24900b57cec5SDimitry Andric     // original type.
24910b57cec5SDimitry Andric     Observer.changingInstr(MI);
24920b57cec5SDimitry Andric     widenScalarSrc(MI, WideTy, 1, TargetOpcode::G_ANYEXT);
24930b57cec5SDimitry Andric     widenScalarSrc(MI, WideTy, 2, TargetOpcode::G_ANYEXT);
24940b57cec5SDimitry Andric     widenScalarDst(MI, WideTy);
24950b57cec5SDimitry Andric     Observer.changedInstr(MI);
24960b57cec5SDimitry Andric     return Legalized;
24970b57cec5SDimitry Andric 
2498fe6060f1SDimitry Andric   case TargetOpcode::G_SBFX:
2499fe6060f1SDimitry Andric   case TargetOpcode::G_UBFX:
2500fe6060f1SDimitry Andric     Observer.changingInstr(MI);
2501fe6060f1SDimitry Andric 
2502fe6060f1SDimitry Andric     if (TypeIdx == 0) {
2503fe6060f1SDimitry Andric       widenScalarSrc(MI, WideTy, 1, TargetOpcode::G_ANYEXT);
2504fe6060f1SDimitry Andric       widenScalarDst(MI, WideTy);
2505fe6060f1SDimitry Andric     } else {
2506fe6060f1SDimitry Andric       widenScalarSrc(MI, WideTy, 2, TargetOpcode::G_ZEXT);
2507fe6060f1SDimitry Andric       widenScalarSrc(MI, WideTy, 3, TargetOpcode::G_ZEXT);
2508fe6060f1SDimitry Andric     }
2509fe6060f1SDimitry Andric 
2510fe6060f1SDimitry Andric     Observer.changedInstr(MI);
2511fe6060f1SDimitry Andric     return Legalized;
2512fe6060f1SDimitry Andric 
25130b57cec5SDimitry Andric   case TargetOpcode::G_SHL:
25140b57cec5SDimitry Andric     Observer.changingInstr(MI);
25150b57cec5SDimitry Andric 
25160b57cec5SDimitry Andric     if (TypeIdx == 0) {
25170b57cec5SDimitry Andric       widenScalarSrc(MI, WideTy, 1, TargetOpcode::G_ANYEXT);
25180b57cec5SDimitry Andric       widenScalarDst(MI, WideTy);
25190b57cec5SDimitry Andric     } else {
25200b57cec5SDimitry Andric       assert(TypeIdx == 1);
25210b57cec5SDimitry Andric       // The "number of bits to shift" operand must preserve its value as an
25220b57cec5SDimitry Andric       // unsigned integer:
25230b57cec5SDimitry Andric       widenScalarSrc(MI, WideTy, 2, TargetOpcode::G_ZEXT);
25240b57cec5SDimitry Andric     }
25250b57cec5SDimitry Andric 
25260b57cec5SDimitry Andric     Observer.changedInstr(MI);
25270b57cec5SDimitry Andric     return Legalized;
25280b57cec5SDimitry Andric 
25295f757f3fSDimitry Andric   case TargetOpcode::G_ROTR:
25305f757f3fSDimitry Andric   case TargetOpcode::G_ROTL:
25315f757f3fSDimitry Andric     if (TypeIdx != 1)
25325f757f3fSDimitry Andric       return UnableToLegalize;
25335f757f3fSDimitry Andric 
25345f757f3fSDimitry Andric     Observer.changingInstr(MI);
25355f757f3fSDimitry Andric     widenScalarSrc(MI, WideTy, 2, TargetOpcode::G_ZEXT);
25365f757f3fSDimitry Andric     Observer.changedInstr(MI);
25375f757f3fSDimitry Andric     return Legalized;
25385f757f3fSDimitry Andric 
25390b57cec5SDimitry Andric   case TargetOpcode::G_SDIV:
25400b57cec5SDimitry Andric   case TargetOpcode::G_SREM:
25410b57cec5SDimitry Andric   case TargetOpcode::G_SMIN:
25420b57cec5SDimitry Andric   case TargetOpcode::G_SMAX:
25430b57cec5SDimitry Andric     Observer.changingInstr(MI);
25440b57cec5SDimitry Andric     widenScalarSrc(MI, WideTy, 1, TargetOpcode::G_SEXT);
25450b57cec5SDimitry Andric     widenScalarSrc(MI, WideTy, 2, TargetOpcode::G_SEXT);
25460b57cec5SDimitry Andric     widenScalarDst(MI, WideTy);
25470b57cec5SDimitry Andric     Observer.changedInstr(MI);
25480b57cec5SDimitry Andric     return Legalized;
25490b57cec5SDimitry Andric 
2550fe6060f1SDimitry Andric   case TargetOpcode::G_SDIVREM:
2551fe6060f1SDimitry Andric     Observer.changingInstr(MI);
2552fe6060f1SDimitry Andric     widenScalarSrc(MI, WideTy, 2, TargetOpcode::G_SEXT);
2553fe6060f1SDimitry Andric     widenScalarSrc(MI, WideTy, 3, TargetOpcode::G_SEXT);
2554fe6060f1SDimitry Andric     widenScalarDst(MI, WideTy);
2555fe6060f1SDimitry Andric     widenScalarDst(MI, WideTy, 1);
2556fe6060f1SDimitry Andric     Observer.changedInstr(MI);
2557fe6060f1SDimitry Andric     return Legalized;
2558fe6060f1SDimitry Andric 
25590b57cec5SDimitry Andric   case TargetOpcode::G_ASHR:
25600b57cec5SDimitry Andric   case TargetOpcode::G_LSHR:
25610b57cec5SDimitry Andric     Observer.changingInstr(MI);
25620b57cec5SDimitry Andric 
25630b57cec5SDimitry Andric     if (TypeIdx == 0) {
25640b57cec5SDimitry Andric       unsigned CvtOp = MI.getOpcode() == TargetOpcode::G_ASHR ?
25650b57cec5SDimitry Andric         TargetOpcode::G_SEXT : TargetOpcode::G_ZEXT;
25660b57cec5SDimitry Andric 
25670b57cec5SDimitry Andric       widenScalarSrc(MI, WideTy, 1, CvtOp);
25680b57cec5SDimitry Andric       widenScalarDst(MI, WideTy);
25690b57cec5SDimitry Andric     } else {
25700b57cec5SDimitry Andric       assert(TypeIdx == 1);
25710b57cec5SDimitry Andric       // The "number of bits to shift" operand must preserve its value as an
25720b57cec5SDimitry Andric       // unsigned integer:
25730b57cec5SDimitry Andric       widenScalarSrc(MI, WideTy, 2, TargetOpcode::G_ZEXT);
25740b57cec5SDimitry Andric     }
25750b57cec5SDimitry Andric 
25760b57cec5SDimitry Andric     Observer.changedInstr(MI);
25770b57cec5SDimitry Andric     return Legalized;
25780b57cec5SDimitry Andric   case TargetOpcode::G_UDIV:
25790b57cec5SDimitry Andric   case TargetOpcode::G_UREM:
25800b57cec5SDimitry Andric   case TargetOpcode::G_UMIN:
25810b57cec5SDimitry Andric   case TargetOpcode::G_UMAX:
25820b57cec5SDimitry Andric     Observer.changingInstr(MI);
25830b57cec5SDimitry Andric     widenScalarSrc(MI, WideTy, 1, TargetOpcode::G_ZEXT);
25840b57cec5SDimitry Andric     widenScalarSrc(MI, WideTy, 2, TargetOpcode::G_ZEXT);
25850b57cec5SDimitry Andric     widenScalarDst(MI, WideTy);
25860b57cec5SDimitry Andric     Observer.changedInstr(MI);
25870b57cec5SDimitry Andric     return Legalized;
25880b57cec5SDimitry Andric 
2589fe6060f1SDimitry Andric   case TargetOpcode::G_UDIVREM:
2590fe6060f1SDimitry Andric     Observer.changingInstr(MI);
2591fe6060f1SDimitry Andric     widenScalarSrc(MI, WideTy, 2, TargetOpcode::G_ZEXT);
2592fe6060f1SDimitry Andric     widenScalarSrc(MI, WideTy, 3, TargetOpcode::G_ZEXT);
2593fe6060f1SDimitry Andric     widenScalarDst(MI, WideTy);
2594fe6060f1SDimitry Andric     widenScalarDst(MI, WideTy, 1);
2595fe6060f1SDimitry Andric     Observer.changedInstr(MI);
2596fe6060f1SDimitry Andric     return Legalized;
2597fe6060f1SDimitry Andric 
25980b57cec5SDimitry Andric   case TargetOpcode::G_SELECT:
25990b57cec5SDimitry Andric     Observer.changingInstr(MI);
26000b57cec5SDimitry Andric     if (TypeIdx == 0) {
26010b57cec5SDimitry Andric       // Perform operation at larger width (any extension is fine here, high
26020b57cec5SDimitry Andric       // bits don't affect the result) and then truncate the result back to the
26030b57cec5SDimitry Andric       // original type.
26040b57cec5SDimitry Andric       widenScalarSrc(MI, WideTy, 2, TargetOpcode::G_ANYEXT);
26050b57cec5SDimitry Andric       widenScalarSrc(MI, WideTy, 3, TargetOpcode::G_ANYEXT);
26060b57cec5SDimitry Andric       widenScalarDst(MI, WideTy);
26070b57cec5SDimitry Andric     } else {
26080b57cec5SDimitry Andric       bool IsVec = MRI.getType(MI.getOperand(1).getReg()).isVector();
26090b57cec5SDimitry Andric       // Explicit extension is required here since high bits affect the result.
26100b57cec5SDimitry Andric       widenScalarSrc(MI, WideTy, 1, MIRBuilder.getBoolExtOp(IsVec, false));
26110b57cec5SDimitry Andric     }
26120b57cec5SDimitry Andric     Observer.changedInstr(MI);
26130b57cec5SDimitry Andric     return Legalized;
26140b57cec5SDimitry Andric 
26150b57cec5SDimitry Andric   case TargetOpcode::G_FPTOSI:
26160b57cec5SDimitry Andric   case TargetOpcode::G_FPTOUI:
26175f757f3fSDimitry Andric   case TargetOpcode::G_IS_FPCLASS:
26180b57cec5SDimitry Andric     Observer.changingInstr(MI);
26198bcb0991SDimitry Andric 
26208bcb0991SDimitry Andric     if (TypeIdx == 0)
26210b57cec5SDimitry Andric       widenScalarDst(MI, WideTy);
26228bcb0991SDimitry Andric     else
26238bcb0991SDimitry Andric       widenScalarSrc(MI, WideTy, 1, TargetOpcode::G_FPEXT);
26248bcb0991SDimitry Andric 
26250b57cec5SDimitry Andric     Observer.changedInstr(MI);
26260b57cec5SDimitry Andric     return Legalized;
26270b57cec5SDimitry Andric   case TargetOpcode::G_SITOFP:
26280b57cec5SDimitry Andric     Observer.changingInstr(MI);
2629e8d8bef9SDimitry Andric 
2630e8d8bef9SDimitry Andric     if (TypeIdx == 0)
2631e8d8bef9SDimitry Andric       widenScalarDst(MI, WideTy, 0, TargetOpcode::G_FPTRUNC);
2632e8d8bef9SDimitry Andric     else
26330b57cec5SDimitry Andric       widenScalarSrc(MI, WideTy, 1, TargetOpcode::G_SEXT);
2634e8d8bef9SDimitry Andric 
26350b57cec5SDimitry Andric     Observer.changedInstr(MI);
26360b57cec5SDimitry Andric     return Legalized;
26370b57cec5SDimitry Andric   case TargetOpcode::G_UITOFP:
26380b57cec5SDimitry Andric     Observer.changingInstr(MI);
2639e8d8bef9SDimitry Andric 
2640e8d8bef9SDimitry Andric     if (TypeIdx == 0)
2641e8d8bef9SDimitry Andric       widenScalarDst(MI, WideTy, 0, TargetOpcode::G_FPTRUNC);
2642e8d8bef9SDimitry Andric     else
26430b57cec5SDimitry Andric       widenScalarSrc(MI, WideTy, 1, TargetOpcode::G_ZEXT);
2644e8d8bef9SDimitry Andric 
26450b57cec5SDimitry Andric     Observer.changedInstr(MI);
26460b57cec5SDimitry Andric     return Legalized;
26470b57cec5SDimitry Andric   case TargetOpcode::G_LOAD:
26480b57cec5SDimitry Andric   case TargetOpcode::G_SEXTLOAD:
26490b57cec5SDimitry Andric   case TargetOpcode::G_ZEXTLOAD:
26500b57cec5SDimitry Andric     Observer.changingInstr(MI);
26510b57cec5SDimitry Andric     widenScalarDst(MI, WideTy);
26520b57cec5SDimitry Andric     Observer.changedInstr(MI);
26530b57cec5SDimitry Andric     return Legalized;
26540b57cec5SDimitry Andric 
26550b57cec5SDimitry Andric   case TargetOpcode::G_STORE: {
26560b57cec5SDimitry Andric     if (TypeIdx != 0)
26570b57cec5SDimitry Andric       return UnableToLegalize;
26580b57cec5SDimitry Andric 
26590b57cec5SDimitry Andric     LLT Ty = MRI.getType(MI.getOperand(0).getReg());
2660e8d8bef9SDimitry Andric     if (!Ty.isScalar())
26610b57cec5SDimitry Andric       return UnableToLegalize;
26620b57cec5SDimitry Andric 
26630b57cec5SDimitry Andric     Observer.changingInstr(MI);
26640b57cec5SDimitry Andric 
26650b57cec5SDimitry Andric     unsigned ExtType = Ty.getScalarSizeInBits() == 1 ?
26660b57cec5SDimitry Andric       TargetOpcode::G_ZEXT : TargetOpcode::G_ANYEXT;
26670b57cec5SDimitry Andric     widenScalarSrc(MI, WideTy, 0, ExtType);
26680b57cec5SDimitry Andric 
26690b57cec5SDimitry Andric     Observer.changedInstr(MI);
26700b57cec5SDimitry Andric     return Legalized;
26710b57cec5SDimitry Andric   }
26720b57cec5SDimitry Andric   case TargetOpcode::G_CONSTANT: {
26730b57cec5SDimitry Andric     MachineOperand &SrcMO = MI.getOperand(1);
26740b57cec5SDimitry Andric     LLVMContext &Ctx = MIRBuilder.getMF().getFunction().getContext();
2675480093f4SDimitry Andric     unsigned ExtOpc = LI.getExtOpcodeForWideningConstant(
2676480093f4SDimitry Andric         MRI.getType(MI.getOperand(0).getReg()));
2677480093f4SDimitry Andric     assert((ExtOpc == TargetOpcode::G_ZEXT || ExtOpc == TargetOpcode::G_SEXT ||
2678480093f4SDimitry Andric             ExtOpc == TargetOpcode::G_ANYEXT) &&
2679480093f4SDimitry Andric            "Illegal Extend");
2680480093f4SDimitry Andric     const APInt &SrcVal = SrcMO.getCImm()->getValue();
2681480093f4SDimitry Andric     const APInt &Val = (ExtOpc == TargetOpcode::G_SEXT)
2682480093f4SDimitry Andric                            ? SrcVal.sext(WideTy.getSizeInBits())
2683480093f4SDimitry Andric                            : SrcVal.zext(WideTy.getSizeInBits());
26840b57cec5SDimitry Andric     Observer.changingInstr(MI);
26850b57cec5SDimitry Andric     SrcMO.setCImm(ConstantInt::get(Ctx, Val));
26860b57cec5SDimitry Andric 
26870b57cec5SDimitry Andric     widenScalarDst(MI, WideTy);
26880b57cec5SDimitry Andric     Observer.changedInstr(MI);
26890b57cec5SDimitry Andric     return Legalized;
26900b57cec5SDimitry Andric   }
26910b57cec5SDimitry Andric   case TargetOpcode::G_FCONSTANT: {
2692fcaf7f86SDimitry Andric     // To avoid changing the bits of the constant due to extension to a larger
2693fcaf7f86SDimitry Andric     // type and then using G_FPTRUNC, we simply convert to a G_CONSTANT.
26940b57cec5SDimitry Andric     MachineOperand &SrcMO = MI.getOperand(1);
2695fcaf7f86SDimitry Andric     APInt Val = SrcMO.getFPImm()->getValueAPF().bitcastToAPInt();
2696fcaf7f86SDimitry Andric     MIRBuilder.setInstrAndDebugLoc(MI);
2697fcaf7f86SDimitry Andric     auto IntCst = MIRBuilder.buildConstant(MI.getOperand(0).getReg(), Val);
2698fcaf7f86SDimitry Andric     widenScalarDst(*IntCst, WideTy, 0, TargetOpcode::G_TRUNC);
2699fcaf7f86SDimitry Andric     MI.eraseFromParent();
27000b57cec5SDimitry Andric     return Legalized;
27010b57cec5SDimitry Andric   }
27020b57cec5SDimitry Andric   case TargetOpcode::G_IMPLICIT_DEF: {
27030b57cec5SDimitry Andric     Observer.changingInstr(MI);
27040b57cec5SDimitry Andric     widenScalarDst(MI, WideTy);
27050b57cec5SDimitry Andric     Observer.changedInstr(MI);
27060b57cec5SDimitry Andric     return Legalized;
27070b57cec5SDimitry Andric   }
27080b57cec5SDimitry Andric   case TargetOpcode::G_BRCOND:
27090b57cec5SDimitry Andric     Observer.changingInstr(MI);
27100b57cec5SDimitry Andric     widenScalarSrc(MI, WideTy, 0, MIRBuilder.getBoolExtOp(false, false));
27110b57cec5SDimitry Andric     Observer.changedInstr(MI);
27120b57cec5SDimitry Andric     return Legalized;
27130b57cec5SDimitry Andric 
27140b57cec5SDimitry Andric   case TargetOpcode::G_FCMP:
27150b57cec5SDimitry Andric     Observer.changingInstr(MI);
27160b57cec5SDimitry Andric     if (TypeIdx == 0)
27170b57cec5SDimitry Andric       widenScalarDst(MI, WideTy);
27180b57cec5SDimitry Andric     else {
27190b57cec5SDimitry Andric       widenScalarSrc(MI, WideTy, 2, TargetOpcode::G_FPEXT);
27200b57cec5SDimitry Andric       widenScalarSrc(MI, WideTy, 3, TargetOpcode::G_FPEXT);
27210b57cec5SDimitry Andric     }
27220b57cec5SDimitry Andric     Observer.changedInstr(MI);
27230b57cec5SDimitry Andric     return Legalized;
27240b57cec5SDimitry Andric 
27250b57cec5SDimitry Andric   case TargetOpcode::G_ICMP:
27260b57cec5SDimitry Andric     Observer.changingInstr(MI);
27270b57cec5SDimitry Andric     if (TypeIdx == 0)
27280b57cec5SDimitry Andric       widenScalarDst(MI, WideTy);
27290b57cec5SDimitry Andric     else {
27300b57cec5SDimitry Andric       unsigned ExtOpcode = CmpInst::isSigned(static_cast<CmpInst::Predicate>(
27310b57cec5SDimitry Andric                                MI.getOperand(1).getPredicate()))
27320b57cec5SDimitry Andric                                ? TargetOpcode::G_SEXT
27330b57cec5SDimitry Andric                                : TargetOpcode::G_ZEXT;
27340b57cec5SDimitry Andric       widenScalarSrc(MI, WideTy, 2, ExtOpcode);
27350b57cec5SDimitry Andric       widenScalarSrc(MI, WideTy, 3, ExtOpcode);
27360b57cec5SDimitry Andric     }
27370b57cec5SDimitry Andric     Observer.changedInstr(MI);
27380b57cec5SDimitry Andric     return Legalized;
27390b57cec5SDimitry Andric 
2740480093f4SDimitry Andric   case TargetOpcode::G_PTR_ADD:
2741480093f4SDimitry Andric     assert(TypeIdx == 1 && "unable to legalize pointer of G_PTR_ADD");
27420b57cec5SDimitry Andric     Observer.changingInstr(MI);
27430b57cec5SDimitry Andric     widenScalarSrc(MI, WideTy, 2, TargetOpcode::G_SEXT);
27440b57cec5SDimitry Andric     Observer.changedInstr(MI);
27450b57cec5SDimitry Andric     return Legalized;
27460b57cec5SDimitry Andric 
27470b57cec5SDimitry Andric   case TargetOpcode::G_PHI: {
27480b57cec5SDimitry Andric     assert(TypeIdx == 0 && "Expecting only Idx 0");
27490b57cec5SDimitry Andric 
27500b57cec5SDimitry Andric     Observer.changingInstr(MI);
27510b57cec5SDimitry Andric     for (unsigned I = 1; I < MI.getNumOperands(); I += 2) {
27520b57cec5SDimitry Andric       MachineBasicBlock &OpMBB = *MI.getOperand(I + 1).getMBB();
2753bdd1243dSDimitry Andric       MIRBuilder.setInsertPt(OpMBB, OpMBB.getFirstTerminatorForward());
27540b57cec5SDimitry Andric       widenScalarSrc(MI, WideTy, I, TargetOpcode::G_ANYEXT);
27550b57cec5SDimitry Andric     }
27560b57cec5SDimitry Andric 
27570b57cec5SDimitry Andric     MachineBasicBlock &MBB = *MI.getParent();
27580b57cec5SDimitry Andric     MIRBuilder.setInsertPt(MBB, --MBB.getFirstNonPHI());
27590b57cec5SDimitry Andric     widenScalarDst(MI, WideTy);
27600b57cec5SDimitry Andric     Observer.changedInstr(MI);
27610b57cec5SDimitry Andric     return Legalized;
27620b57cec5SDimitry Andric   }
27630b57cec5SDimitry Andric   case TargetOpcode::G_EXTRACT_VECTOR_ELT: {
27640b57cec5SDimitry Andric     if (TypeIdx == 0) {
27650b57cec5SDimitry Andric       Register VecReg = MI.getOperand(1).getReg();
27660b57cec5SDimitry Andric       LLT VecTy = MRI.getType(VecReg);
27670b57cec5SDimitry Andric       Observer.changingInstr(MI);
27680b57cec5SDimitry Andric 
2769fe6060f1SDimitry Andric       widenScalarSrc(
2770fe6060f1SDimitry Andric           MI, LLT::vector(VecTy.getElementCount(), WideTy.getSizeInBits()), 1,
2771349cc55cSDimitry Andric           TargetOpcode::G_ANYEXT);
27720b57cec5SDimitry Andric 
27730b57cec5SDimitry Andric       widenScalarDst(MI, WideTy, 0);
27740b57cec5SDimitry Andric       Observer.changedInstr(MI);
27750b57cec5SDimitry Andric       return Legalized;
27760b57cec5SDimitry Andric     }
27770b57cec5SDimitry Andric 
27780b57cec5SDimitry Andric     if (TypeIdx != 2)
27790b57cec5SDimitry Andric       return UnableToLegalize;
27800b57cec5SDimitry Andric     Observer.changingInstr(MI);
2781480093f4SDimitry Andric     // TODO: Probably should be zext
27820b57cec5SDimitry Andric     widenScalarSrc(MI, WideTy, 2, TargetOpcode::G_SEXT);
27830b57cec5SDimitry Andric     Observer.changedInstr(MI);
27840b57cec5SDimitry Andric     return Legalized;
27850b57cec5SDimitry Andric   }
2786480093f4SDimitry Andric   case TargetOpcode::G_INSERT_VECTOR_ELT: {
27875f757f3fSDimitry Andric     if (TypeIdx == 0) {
27885f757f3fSDimitry Andric       Observer.changingInstr(MI);
27895f757f3fSDimitry Andric       const LLT WideEltTy = WideTy.getElementType();
27905f757f3fSDimitry Andric 
27915f757f3fSDimitry Andric       widenScalarSrc(MI, WideTy, 1, TargetOpcode::G_ANYEXT);
27925f757f3fSDimitry Andric       widenScalarSrc(MI, WideEltTy, 2, TargetOpcode::G_ANYEXT);
27935f757f3fSDimitry Andric       widenScalarDst(MI, WideTy, 0);
27945f757f3fSDimitry Andric       Observer.changedInstr(MI);
27955f757f3fSDimitry Andric       return Legalized;
27965f757f3fSDimitry Andric     }
27975f757f3fSDimitry Andric 
2798480093f4SDimitry Andric     if (TypeIdx == 1) {
2799480093f4SDimitry Andric       Observer.changingInstr(MI);
2800480093f4SDimitry Andric 
2801480093f4SDimitry Andric       Register VecReg = MI.getOperand(1).getReg();
2802480093f4SDimitry Andric       LLT VecTy = MRI.getType(VecReg);
2803fe6060f1SDimitry Andric       LLT WideVecTy = LLT::vector(VecTy.getElementCount(), WideTy);
2804480093f4SDimitry Andric 
2805480093f4SDimitry Andric       widenScalarSrc(MI, WideVecTy, 1, TargetOpcode::G_ANYEXT);
2806480093f4SDimitry Andric       widenScalarSrc(MI, WideTy, 2, TargetOpcode::G_ANYEXT);
2807480093f4SDimitry Andric       widenScalarDst(MI, WideVecTy, 0);
2808480093f4SDimitry Andric       Observer.changedInstr(MI);
2809480093f4SDimitry Andric       return Legalized;
2810480093f4SDimitry Andric     }
2811480093f4SDimitry Andric 
2812480093f4SDimitry Andric     if (TypeIdx == 2) {
2813480093f4SDimitry Andric       Observer.changingInstr(MI);
2814480093f4SDimitry Andric       // TODO: Probably should be zext
2815480093f4SDimitry Andric       widenScalarSrc(MI, WideTy, 3, TargetOpcode::G_SEXT);
2816480093f4SDimitry Andric       Observer.changedInstr(MI);
28175ffd83dbSDimitry Andric       return Legalized;
2818480093f4SDimitry Andric     }
2819480093f4SDimitry Andric 
28205ffd83dbSDimitry Andric     return UnableToLegalize;
2821480093f4SDimitry Andric   }
28220b57cec5SDimitry Andric   case TargetOpcode::G_FADD:
28230b57cec5SDimitry Andric   case TargetOpcode::G_FMUL:
28240b57cec5SDimitry Andric   case TargetOpcode::G_FSUB:
28250b57cec5SDimitry Andric   case TargetOpcode::G_FMA:
28268bcb0991SDimitry Andric   case TargetOpcode::G_FMAD:
28270b57cec5SDimitry Andric   case TargetOpcode::G_FNEG:
28280b57cec5SDimitry Andric   case TargetOpcode::G_FABS:
28290b57cec5SDimitry Andric   case TargetOpcode::G_FCANONICALIZE:
28300b57cec5SDimitry Andric   case TargetOpcode::G_FMINNUM:
28310b57cec5SDimitry Andric   case TargetOpcode::G_FMAXNUM:
28320b57cec5SDimitry Andric   case TargetOpcode::G_FMINNUM_IEEE:
28330b57cec5SDimitry Andric   case TargetOpcode::G_FMAXNUM_IEEE:
28340b57cec5SDimitry Andric   case TargetOpcode::G_FMINIMUM:
28350b57cec5SDimitry Andric   case TargetOpcode::G_FMAXIMUM:
28360b57cec5SDimitry Andric   case TargetOpcode::G_FDIV:
28370b57cec5SDimitry Andric   case TargetOpcode::G_FREM:
28380b57cec5SDimitry Andric   case TargetOpcode::G_FCEIL:
28390b57cec5SDimitry Andric   case TargetOpcode::G_FFLOOR:
28400b57cec5SDimitry Andric   case TargetOpcode::G_FCOS:
28410b57cec5SDimitry Andric   case TargetOpcode::G_FSIN:
28420b57cec5SDimitry Andric   case TargetOpcode::G_FLOG10:
28430b57cec5SDimitry Andric   case TargetOpcode::G_FLOG:
28440b57cec5SDimitry Andric   case TargetOpcode::G_FLOG2:
28450b57cec5SDimitry Andric   case TargetOpcode::G_FRINT:
28460b57cec5SDimitry Andric   case TargetOpcode::G_FNEARBYINT:
28470b57cec5SDimitry Andric   case TargetOpcode::G_FSQRT:
28480b57cec5SDimitry Andric   case TargetOpcode::G_FEXP:
28490b57cec5SDimitry Andric   case TargetOpcode::G_FEXP2:
28505f757f3fSDimitry Andric   case TargetOpcode::G_FEXP10:
28510b57cec5SDimitry Andric   case TargetOpcode::G_FPOW:
28520b57cec5SDimitry Andric   case TargetOpcode::G_INTRINSIC_TRUNC:
28530b57cec5SDimitry Andric   case TargetOpcode::G_INTRINSIC_ROUND:
2854e8d8bef9SDimitry Andric   case TargetOpcode::G_INTRINSIC_ROUNDEVEN:
28550b57cec5SDimitry Andric     assert(TypeIdx == 0);
28560b57cec5SDimitry Andric     Observer.changingInstr(MI);
28570b57cec5SDimitry Andric 
28580b57cec5SDimitry Andric     for (unsigned I = 1, E = MI.getNumOperands(); I != E; ++I)
28590b57cec5SDimitry Andric       widenScalarSrc(MI, WideTy, I, TargetOpcode::G_FPEXT);
28600b57cec5SDimitry Andric 
28610b57cec5SDimitry Andric     widenScalarDst(MI, WideTy, 0, TargetOpcode::G_FPTRUNC);
28620b57cec5SDimitry Andric     Observer.changedInstr(MI);
28630b57cec5SDimitry Andric     return Legalized;
286406c3fb27SDimitry Andric   case TargetOpcode::G_FPOWI:
286506c3fb27SDimitry Andric   case TargetOpcode::G_FLDEXP:
286606c3fb27SDimitry Andric   case TargetOpcode::G_STRICT_FLDEXP: {
286706c3fb27SDimitry Andric     if (TypeIdx == 0) {
286806c3fb27SDimitry Andric       if (MI.getOpcode() == TargetOpcode::G_STRICT_FLDEXP)
2869e8d8bef9SDimitry Andric         return UnableToLegalize;
287006c3fb27SDimitry Andric 
2871e8d8bef9SDimitry Andric       Observer.changingInstr(MI);
2872e8d8bef9SDimitry Andric       widenScalarSrc(MI, WideTy, 1, TargetOpcode::G_FPEXT);
2873e8d8bef9SDimitry Andric       widenScalarDst(MI, WideTy, 0, TargetOpcode::G_FPTRUNC);
2874e8d8bef9SDimitry Andric       Observer.changedInstr(MI);
2875e8d8bef9SDimitry Andric       return Legalized;
2876e8d8bef9SDimitry Andric     }
287706c3fb27SDimitry Andric 
287806c3fb27SDimitry Andric     if (TypeIdx == 1) {
287906c3fb27SDimitry Andric       // For some reason SelectionDAG tries to promote to a libcall without
288006c3fb27SDimitry Andric       // actually changing the integer type for promotion.
288106c3fb27SDimitry Andric       Observer.changingInstr(MI);
288206c3fb27SDimitry Andric       widenScalarSrc(MI, WideTy, 2, TargetOpcode::G_SEXT);
288306c3fb27SDimitry Andric       Observer.changedInstr(MI);
288406c3fb27SDimitry Andric       return Legalized;
288506c3fb27SDimitry Andric     }
288606c3fb27SDimitry Andric 
288706c3fb27SDimitry Andric     return UnableToLegalize;
288806c3fb27SDimitry Andric   }
288906c3fb27SDimitry Andric   case TargetOpcode::G_FFREXP: {
289006c3fb27SDimitry Andric     Observer.changingInstr(MI);
289106c3fb27SDimitry Andric 
289206c3fb27SDimitry Andric     if (TypeIdx == 0) {
289306c3fb27SDimitry Andric       widenScalarSrc(MI, WideTy, 2, TargetOpcode::G_FPEXT);
289406c3fb27SDimitry Andric       widenScalarDst(MI, WideTy, 0, TargetOpcode::G_FPTRUNC);
289506c3fb27SDimitry Andric     } else {
289606c3fb27SDimitry Andric       widenScalarDst(MI, WideTy, 1);
289706c3fb27SDimitry Andric     }
289806c3fb27SDimitry Andric 
289906c3fb27SDimitry Andric     Observer.changedInstr(MI);
290006c3fb27SDimitry Andric     return Legalized;
290106c3fb27SDimitry Andric   }
29020b57cec5SDimitry Andric   case TargetOpcode::G_INTTOPTR:
29030b57cec5SDimitry Andric     if (TypeIdx != 1)
29040b57cec5SDimitry Andric       return UnableToLegalize;
29050b57cec5SDimitry Andric 
29060b57cec5SDimitry Andric     Observer.changingInstr(MI);
29070b57cec5SDimitry Andric     widenScalarSrc(MI, WideTy, 1, TargetOpcode::G_ZEXT);
29080b57cec5SDimitry Andric     Observer.changedInstr(MI);
29090b57cec5SDimitry Andric     return Legalized;
29100b57cec5SDimitry Andric   case TargetOpcode::G_PTRTOINT:
29110b57cec5SDimitry Andric     if (TypeIdx != 0)
29120b57cec5SDimitry Andric       return UnableToLegalize;
29130b57cec5SDimitry Andric 
29140b57cec5SDimitry Andric     Observer.changingInstr(MI);
29150b57cec5SDimitry Andric     widenScalarDst(MI, WideTy, 0);
29160b57cec5SDimitry Andric     Observer.changedInstr(MI);
29170b57cec5SDimitry Andric     return Legalized;
29180b57cec5SDimitry Andric   case TargetOpcode::G_BUILD_VECTOR: {
29190b57cec5SDimitry Andric     Observer.changingInstr(MI);
29200b57cec5SDimitry Andric 
29210b57cec5SDimitry Andric     const LLT WideEltTy = TypeIdx == 1 ? WideTy : WideTy.getElementType();
29220b57cec5SDimitry Andric     for (int I = 1, E = MI.getNumOperands(); I != E; ++I)
29230b57cec5SDimitry Andric       widenScalarSrc(MI, WideEltTy, I, TargetOpcode::G_ANYEXT);
29240b57cec5SDimitry Andric 
29250b57cec5SDimitry Andric     // Avoid changing the result vector type if the source element type was
29260b57cec5SDimitry Andric     // requested.
29270b57cec5SDimitry Andric     if (TypeIdx == 1) {
2928e8d8bef9SDimitry Andric       MI.setDesc(MIRBuilder.getTII().get(TargetOpcode::G_BUILD_VECTOR_TRUNC));
29290b57cec5SDimitry Andric     } else {
29300b57cec5SDimitry Andric       widenScalarDst(MI, WideTy, 0);
29310b57cec5SDimitry Andric     }
29320b57cec5SDimitry Andric 
29330b57cec5SDimitry Andric     Observer.changedInstr(MI);
29340b57cec5SDimitry Andric     return Legalized;
29350b57cec5SDimitry Andric   }
29368bcb0991SDimitry Andric   case TargetOpcode::G_SEXT_INREG:
29378bcb0991SDimitry Andric     if (TypeIdx != 0)
29388bcb0991SDimitry Andric       return UnableToLegalize;
29398bcb0991SDimitry Andric 
29408bcb0991SDimitry Andric     Observer.changingInstr(MI);
29418bcb0991SDimitry Andric     widenScalarSrc(MI, WideTy, 1, TargetOpcode::G_ANYEXT);
29428bcb0991SDimitry Andric     widenScalarDst(MI, WideTy, 0, TargetOpcode::G_TRUNC);
29438bcb0991SDimitry Andric     Observer.changedInstr(MI);
29448bcb0991SDimitry Andric     return Legalized;
29455ffd83dbSDimitry Andric   case TargetOpcode::G_PTRMASK: {
29465ffd83dbSDimitry Andric     if (TypeIdx != 1)
29475ffd83dbSDimitry Andric       return UnableToLegalize;
29485ffd83dbSDimitry Andric     Observer.changingInstr(MI);
29495ffd83dbSDimitry Andric     widenScalarSrc(MI, WideTy, 2, TargetOpcode::G_ZEXT);
29505ffd83dbSDimitry Andric     Observer.changedInstr(MI);
29515ffd83dbSDimitry Andric     return Legalized;
29525ffd83dbSDimitry Andric   }
29535f757f3fSDimitry Andric   case TargetOpcode::G_VECREDUCE_FADD:
29541db9f3b2SDimitry Andric   case TargetOpcode::G_VECREDUCE_FMUL:
29555f757f3fSDimitry Andric   case TargetOpcode::G_VECREDUCE_FMIN:
29565f757f3fSDimitry Andric   case TargetOpcode::G_VECREDUCE_FMAX:
29575f757f3fSDimitry Andric   case TargetOpcode::G_VECREDUCE_FMINIMUM:
29585f757f3fSDimitry Andric   case TargetOpcode::G_VECREDUCE_FMAXIMUM:
29595f757f3fSDimitry Andric     if (TypeIdx != 0)
29605f757f3fSDimitry Andric       return UnableToLegalize;
29615f757f3fSDimitry Andric     Observer.changingInstr(MI);
29625f757f3fSDimitry Andric     Register VecReg = MI.getOperand(1).getReg();
29635f757f3fSDimitry Andric     LLT VecTy = MRI.getType(VecReg);
29645f757f3fSDimitry Andric     LLT WideVecTy = VecTy.isVector()
29655f757f3fSDimitry Andric                         ? LLT::vector(VecTy.getElementCount(), WideTy)
29665f757f3fSDimitry Andric                         : WideTy;
29675f757f3fSDimitry Andric     widenScalarSrc(MI, WideVecTy, 1, TargetOpcode::G_FPEXT);
29685f757f3fSDimitry Andric     widenScalarDst(MI, WideTy, 0, TargetOpcode::G_FPTRUNC);
29695f757f3fSDimitry Andric     Observer.changedInstr(MI);
29705f757f3fSDimitry Andric     return Legalized;
29715ffd83dbSDimitry Andric   }
29725ffd83dbSDimitry Andric }
29735ffd83dbSDimitry Andric 
29745ffd83dbSDimitry Andric static void getUnmergePieces(SmallVectorImpl<Register> &Pieces,
29755ffd83dbSDimitry Andric                              MachineIRBuilder &B, Register Src, LLT Ty) {
29765ffd83dbSDimitry Andric   auto Unmerge = B.buildUnmerge(Ty, Src);
29775ffd83dbSDimitry Andric   for (int I = 0, E = Unmerge->getNumOperands() - 1; I != E; ++I)
29785ffd83dbSDimitry Andric     Pieces.push_back(Unmerge.getReg(I));
29795ffd83dbSDimitry Andric }
29805ffd83dbSDimitry Andric 
29815ffd83dbSDimitry Andric LegalizerHelper::LegalizeResult
298206c3fb27SDimitry Andric LegalizerHelper::lowerFConstant(MachineInstr &MI) {
29835ffd83dbSDimitry Andric   Register Dst = MI.getOperand(0).getReg();
29845ffd83dbSDimitry Andric 
298506c3fb27SDimitry Andric   MachineFunction &MF = MIRBuilder.getMF();
298606c3fb27SDimitry Andric   const DataLayout &DL = MIRBuilder.getDataLayout();
298706c3fb27SDimitry Andric 
298806c3fb27SDimitry Andric   unsigned AddrSpace = DL.getDefaultGlobalsAddressSpace();
298906c3fb27SDimitry Andric   LLT AddrPtrTy = LLT::pointer(AddrSpace, DL.getPointerSizeInBits(AddrSpace));
299006c3fb27SDimitry Andric   Align Alignment = Align(DL.getABITypeAlign(
299106c3fb27SDimitry Andric       getFloatTypeForLLT(MF.getFunction().getContext(), MRI.getType(Dst))));
299206c3fb27SDimitry Andric 
299306c3fb27SDimitry Andric   auto Addr = MIRBuilder.buildConstantPool(
299406c3fb27SDimitry Andric       AddrPtrTy, MF.getConstantPool()->getConstantPoolIndex(
299506c3fb27SDimitry Andric                      MI.getOperand(1).getFPImm(), Alignment));
299606c3fb27SDimitry Andric 
299706c3fb27SDimitry Andric   MachineMemOperand *MMO = MF.getMachineMemOperand(
299806c3fb27SDimitry Andric       MachinePointerInfo::getConstantPool(MF), MachineMemOperand::MOLoad,
299906c3fb27SDimitry Andric       MRI.getType(Dst), Alignment);
300006c3fb27SDimitry Andric 
300106c3fb27SDimitry Andric   MIRBuilder.buildLoadInstr(TargetOpcode::G_LOAD, Dst, Addr, *MMO);
300206c3fb27SDimitry Andric   MI.eraseFromParent();
300306c3fb27SDimitry Andric 
300406c3fb27SDimitry Andric   return Legalized;
300506c3fb27SDimitry Andric }
300606c3fb27SDimitry Andric 
300706c3fb27SDimitry Andric LegalizerHelper::LegalizeResult
300806c3fb27SDimitry Andric LegalizerHelper::lowerBitcast(MachineInstr &MI) {
300906c3fb27SDimitry Andric   auto [Dst, DstTy, Src, SrcTy] = MI.getFirst2RegLLTs();
30105ffd83dbSDimitry Andric   if (SrcTy.isVector()) {
30115ffd83dbSDimitry Andric     LLT SrcEltTy = SrcTy.getElementType();
30125ffd83dbSDimitry Andric     SmallVector<Register, 8> SrcRegs;
30135ffd83dbSDimitry Andric 
30145ffd83dbSDimitry Andric     if (DstTy.isVector()) {
30155ffd83dbSDimitry Andric       int NumDstElt = DstTy.getNumElements();
30165ffd83dbSDimitry Andric       int NumSrcElt = SrcTy.getNumElements();
30175ffd83dbSDimitry Andric 
30185ffd83dbSDimitry Andric       LLT DstEltTy = DstTy.getElementType();
30195ffd83dbSDimitry Andric       LLT DstCastTy = DstEltTy; // Intermediate bitcast result type
30205ffd83dbSDimitry Andric       LLT SrcPartTy = SrcEltTy; // Original unmerge result type.
30215ffd83dbSDimitry Andric 
30225ffd83dbSDimitry Andric       // If there's an element size mismatch, insert intermediate casts to match
30235ffd83dbSDimitry Andric       // the result element type.
30245ffd83dbSDimitry Andric       if (NumSrcElt < NumDstElt) { // Source element type is larger.
30255ffd83dbSDimitry Andric         // %1:_(<4 x s8>) = G_BITCAST %0:_(<2 x s16>)
30265ffd83dbSDimitry Andric         //
30275ffd83dbSDimitry Andric         // =>
30285ffd83dbSDimitry Andric         //
30295ffd83dbSDimitry Andric         // %2:_(s16), %3:_(s16) = G_UNMERGE_VALUES %0
30305ffd83dbSDimitry Andric         // %3:_(<2 x s8>) = G_BITCAST %2
30315ffd83dbSDimitry Andric         // %4:_(<2 x s8>) = G_BITCAST %3
30325ffd83dbSDimitry Andric         // %1:_(<4 x s16>) = G_CONCAT_VECTORS %3, %4
3033fe6060f1SDimitry Andric         DstCastTy = LLT::fixed_vector(NumDstElt / NumSrcElt, DstEltTy);
30345ffd83dbSDimitry Andric         SrcPartTy = SrcEltTy;
30355ffd83dbSDimitry Andric       } else if (NumSrcElt > NumDstElt) { // Source element type is smaller.
30365ffd83dbSDimitry Andric         //
30375ffd83dbSDimitry Andric         // %1:_(<2 x s16>) = G_BITCAST %0:_(<4 x s8>)
30385ffd83dbSDimitry Andric         //
30395ffd83dbSDimitry Andric         // =>
30405ffd83dbSDimitry Andric         //
30415ffd83dbSDimitry Andric         // %2:_(<2 x s8>), %3:_(<2 x s8>) = G_UNMERGE_VALUES %0
30425ffd83dbSDimitry Andric         // %3:_(s16) = G_BITCAST %2
30435ffd83dbSDimitry Andric         // %4:_(s16) = G_BITCAST %3
30445ffd83dbSDimitry Andric         // %1:_(<2 x s16>) = G_BUILD_VECTOR %3, %4
3045fe6060f1SDimitry Andric         SrcPartTy = LLT::fixed_vector(NumSrcElt / NumDstElt, SrcEltTy);
30465ffd83dbSDimitry Andric         DstCastTy = DstEltTy;
30475ffd83dbSDimitry Andric       }
30485ffd83dbSDimitry Andric 
30495ffd83dbSDimitry Andric       getUnmergePieces(SrcRegs, MIRBuilder, Src, SrcPartTy);
30505ffd83dbSDimitry Andric       for (Register &SrcReg : SrcRegs)
30515ffd83dbSDimitry Andric         SrcReg = MIRBuilder.buildBitcast(DstCastTy, SrcReg).getReg(0);
30525ffd83dbSDimitry Andric     } else
30535ffd83dbSDimitry Andric       getUnmergePieces(SrcRegs, MIRBuilder, Src, SrcEltTy);
30545ffd83dbSDimitry Andric 
3055bdd1243dSDimitry Andric     MIRBuilder.buildMergeLikeInstr(Dst, SrcRegs);
30565ffd83dbSDimitry Andric     MI.eraseFromParent();
30575ffd83dbSDimitry Andric     return Legalized;
30585ffd83dbSDimitry Andric   }
30595ffd83dbSDimitry Andric 
30605ffd83dbSDimitry Andric   if (DstTy.isVector()) {
30615ffd83dbSDimitry Andric     SmallVector<Register, 8> SrcRegs;
30625ffd83dbSDimitry Andric     getUnmergePieces(SrcRegs, MIRBuilder, Src, DstTy.getElementType());
3063bdd1243dSDimitry Andric     MIRBuilder.buildMergeLikeInstr(Dst, SrcRegs);
30645ffd83dbSDimitry Andric     MI.eraseFromParent();
30655ffd83dbSDimitry Andric     return Legalized;
30665ffd83dbSDimitry Andric   }
30675ffd83dbSDimitry Andric 
30685ffd83dbSDimitry Andric   return UnableToLegalize;
30695ffd83dbSDimitry Andric }
30705ffd83dbSDimitry Andric 
3071e8d8bef9SDimitry Andric /// Figure out the bit offset into a register when coercing a vector index for
3072e8d8bef9SDimitry Andric /// the wide element type. This is only for the case when promoting vector to
3073e8d8bef9SDimitry Andric /// one with larger elements.
3074e8d8bef9SDimitry Andric //
3075e8d8bef9SDimitry Andric ///
3076e8d8bef9SDimitry Andric /// %offset_idx = G_AND %idx, ~(-1 << Log2(DstEltSize / SrcEltSize))
3077e8d8bef9SDimitry Andric /// %offset_bits = G_SHL %offset_idx, Log2(SrcEltSize)
3078e8d8bef9SDimitry Andric static Register getBitcastWiderVectorElementOffset(MachineIRBuilder &B,
3079e8d8bef9SDimitry Andric                                                    Register Idx,
3080e8d8bef9SDimitry Andric                                                    unsigned NewEltSize,
3081e8d8bef9SDimitry Andric                                                    unsigned OldEltSize) {
3082e8d8bef9SDimitry Andric   const unsigned Log2EltRatio = Log2_32(NewEltSize / OldEltSize);
3083e8d8bef9SDimitry Andric   LLT IdxTy = B.getMRI()->getType(Idx);
3084e8d8bef9SDimitry Andric 
3085e8d8bef9SDimitry Andric   // Now figure out the amount we need to shift to get the target bits.
3086e8d8bef9SDimitry Andric   auto OffsetMask = B.buildConstant(
3087349cc55cSDimitry Andric       IdxTy, ~(APInt::getAllOnes(IdxTy.getSizeInBits()) << Log2EltRatio));
3088e8d8bef9SDimitry Andric   auto OffsetIdx = B.buildAnd(IdxTy, Idx, OffsetMask);
3089e8d8bef9SDimitry Andric   return B.buildShl(IdxTy, OffsetIdx,
3090e8d8bef9SDimitry Andric                     B.buildConstant(IdxTy, Log2_32(OldEltSize))).getReg(0);
3091e8d8bef9SDimitry Andric }
3092e8d8bef9SDimitry Andric 
3093e8d8bef9SDimitry Andric /// Perform a G_EXTRACT_VECTOR_ELT in a different sized vector element. If this
3094e8d8bef9SDimitry Andric /// is casting to a vector with a smaller element size, perform multiple element
3095e8d8bef9SDimitry Andric /// extracts and merge the results. If this is coercing to a vector with larger
3096e8d8bef9SDimitry Andric /// elements, index the bitcasted vector and extract the target element with bit
3097e8d8bef9SDimitry Andric /// operations. This is intended to force the indexing in the native register
3098e8d8bef9SDimitry Andric /// size for architectures that can dynamically index the register file.
30995ffd83dbSDimitry Andric LegalizerHelper::LegalizeResult
3100e8d8bef9SDimitry Andric LegalizerHelper::bitcastExtractVectorElt(MachineInstr &MI, unsigned TypeIdx,
3101e8d8bef9SDimitry Andric                                          LLT CastTy) {
3102e8d8bef9SDimitry Andric   if (TypeIdx != 1)
3103e8d8bef9SDimitry Andric     return UnableToLegalize;
3104e8d8bef9SDimitry Andric 
310506c3fb27SDimitry Andric   auto [Dst, DstTy, SrcVec, SrcVecTy, Idx, IdxTy] = MI.getFirst3RegLLTs();
3106e8d8bef9SDimitry Andric 
3107e8d8bef9SDimitry Andric   LLT SrcEltTy = SrcVecTy.getElementType();
3108e8d8bef9SDimitry Andric   unsigned NewNumElts = CastTy.isVector() ? CastTy.getNumElements() : 1;
3109e8d8bef9SDimitry Andric   unsigned OldNumElts = SrcVecTy.getNumElements();
3110e8d8bef9SDimitry Andric 
3111e8d8bef9SDimitry Andric   LLT NewEltTy = CastTy.isVector() ? CastTy.getElementType() : CastTy;
3112e8d8bef9SDimitry Andric   Register CastVec = MIRBuilder.buildBitcast(CastTy, SrcVec).getReg(0);
3113e8d8bef9SDimitry Andric 
3114e8d8bef9SDimitry Andric   const unsigned NewEltSize = NewEltTy.getSizeInBits();
3115e8d8bef9SDimitry Andric   const unsigned OldEltSize = SrcEltTy.getSizeInBits();
3116e8d8bef9SDimitry Andric   if (NewNumElts > OldNumElts) {
3117e8d8bef9SDimitry Andric     // Decreasing the vector element size
3118e8d8bef9SDimitry Andric     //
3119e8d8bef9SDimitry Andric     // e.g. i64 = extract_vector_elt x:v2i64, y:i32
3120e8d8bef9SDimitry Andric     //  =>
3121e8d8bef9SDimitry Andric     //  v4i32:castx = bitcast x:v2i64
3122e8d8bef9SDimitry Andric     //
3123e8d8bef9SDimitry Andric     // i64 = bitcast
3124e8d8bef9SDimitry Andric     //   (v2i32 build_vector (i32 (extract_vector_elt castx, (2 * y))),
3125e8d8bef9SDimitry Andric     //                       (i32 (extract_vector_elt castx, (2 * y + 1)))
3126e8d8bef9SDimitry Andric     //
3127e8d8bef9SDimitry Andric     if (NewNumElts % OldNumElts != 0)
3128e8d8bef9SDimitry Andric       return UnableToLegalize;
3129e8d8bef9SDimitry Andric 
3130e8d8bef9SDimitry Andric     // Type of the intermediate result vector.
3131e8d8bef9SDimitry Andric     const unsigned NewEltsPerOldElt = NewNumElts / OldNumElts;
3132fe6060f1SDimitry Andric     LLT MidTy =
3133fe6060f1SDimitry Andric         LLT::scalarOrVector(ElementCount::getFixed(NewEltsPerOldElt), NewEltTy);
3134e8d8bef9SDimitry Andric 
3135e8d8bef9SDimitry Andric     auto NewEltsPerOldEltK = MIRBuilder.buildConstant(IdxTy, NewEltsPerOldElt);
3136e8d8bef9SDimitry Andric 
3137e8d8bef9SDimitry Andric     SmallVector<Register, 8> NewOps(NewEltsPerOldElt);
3138e8d8bef9SDimitry Andric     auto NewBaseIdx = MIRBuilder.buildMul(IdxTy, Idx, NewEltsPerOldEltK);
3139e8d8bef9SDimitry Andric 
3140e8d8bef9SDimitry Andric     for (unsigned I = 0; I < NewEltsPerOldElt; ++I) {
3141e8d8bef9SDimitry Andric       auto IdxOffset = MIRBuilder.buildConstant(IdxTy, I);
3142e8d8bef9SDimitry Andric       auto TmpIdx = MIRBuilder.buildAdd(IdxTy, NewBaseIdx, IdxOffset);
3143e8d8bef9SDimitry Andric       auto Elt = MIRBuilder.buildExtractVectorElement(NewEltTy, CastVec, TmpIdx);
3144e8d8bef9SDimitry Andric       NewOps[I] = Elt.getReg(0);
3145e8d8bef9SDimitry Andric     }
3146e8d8bef9SDimitry Andric 
3147e8d8bef9SDimitry Andric     auto NewVec = MIRBuilder.buildBuildVector(MidTy, NewOps);
3148e8d8bef9SDimitry Andric     MIRBuilder.buildBitcast(Dst, NewVec);
3149e8d8bef9SDimitry Andric     MI.eraseFromParent();
3150e8d8bef9SDimitry Andric     return Legalized;
3151e8d8bef9SDimitry Andric   }
3152e8d8bef9SDimitry Andric 
3153e8d8bef9SDimitry Andric   if (NewNumElts < OldNumElts) {
3154e8d8bef9SDimitry Andric     if (NewEltSize % OldEltSize != 0)
3155e8d8bef9SDimitry Andric       return UnableToLegalize;
3156e8d8bef9SDimitry Andric 
3157e8d8bef9SDimitry Andric     // This only depends on powers of 2 because we use bit tricks to figure out
3158e8d8bef9SDimitry Andric     // the bit offset we need to shift to get the target element. A general
3159e8d8bef9SDimitry Andric     // expansion could emit division/multiply.
3160e8d8bef9SDimitry Andric     if (!isPowerOf2_32(NewEltSize / OldEltSize))
3161e8d8bef9SDimitry Andric       return UnableToLegalize;
3162e8d8bef9SDimitry Andric 
3163e8d8bef9SDimitry Andric     // Increasing the vector element size.
3164e8d8bef9SDimitry Andric     // %elt:_(small_elt) = G_EXTRACT_VECTOR_ELT %vec:_(<N x small_elt>), %idx
3165e8d8bef9SDimitry Andric     //
3166e8d8bef9SDimitry Andric     //   =>
3167e8d8bef9SDimitry Andric     //
3168e8d8bef9SDimitry Andric     // %cast = G_BITCAST %vec
3169e8d8bef9SDimitry Andric     // %scaled_idx = G_LSHR %idx, Log2(DstEltSize / SrcEltSize)
3170e8d8bef9SDimitry Andric     // %wide_elt  = G_EXTRACT_VECTOR_ELT %cast, %scaled_idx
3171e8d8bef9SDimitry Andric     // %offset_idx = G_AND %idx, ~(-1 << Log2(DstEltSize / SrcEltSize))
3172e8d8bef9SDimitry Andric     // %offset_bits = G_SHL %offset_idx, Log2(SrcEltSize)
3173e8d8bef9SDimitry Andric     // %elt_bits = G_LSHR %wide_elt, %offset_bits
3174e8d8bef9SDimitry Andric     // %elt = G_TRUNC %elt_bits
3175e8d8bef9SDimitry Andric 
3176e8d8bef9SDimitry Andric     const unsigned Log2EltRatio = Log2_32(NewEltSize / OldEltSize);
3177e8d8bef9SDimitry Andric     auto Log2Ratio = MIRBuilder.buildConstant(IdxTy, Log2EltRatio);
3178e8d8bef9SDimitry Andric 
3179e8d8bef9SDimitry Andric     // Divide to get the index in the wider element type.
3180e8d8bef9SDimitry Andric     auto ScaledIdx = MIRBuilder.buildLShr(IdxTy, Idx, Log2Ratio);
3181e8d8bef9SDimitry Andric 
3182e8d8bef9SDimitry Andric     Register WideElt = CastVec;
3183e8d8bef9SDimitry Andric     if (CastTy.isVector()) {
3184e8d8bef9SDimitry Andric       WideElt = MIRBuilder.buildExtractVectorElement(NewEltTy, CastVec,
3185e8d8bef9SDimitry Andric                                                      ScaledIdx).getReg(0);
3186e8d8bef9SDimitry Andric     }
3187e8d8bef9SDimitry Andric 
3188e8d8bef9SDimitry Andric     // Compute the bit offset into the register of the target element.
3189e8d8bef9SDimitry Andric     Register OffsetBits = getBitcastWiderVectorElementOffset(
3190e8d8bef9SDimitry Andric       MIRBuilder, Idx, NewEltSize, OldEltSize);
3191e8d8bef9SDimitry Andric 
3192e8d8bef9SDimitry Andric     // Shift the wide element to get the target element.
3193e8d8bef9SDimitry Andric     auto ExtractedBits = MIRBuilder.buildLShr(NewEltTy, WideElt, OffsetBits);
3194e8d8bef9SDimitry Andric     MIRBuilder.buildTrunc(Dst, ExtractedBits);
3195e8d8bef9SDimitry Andric     MI.eraseFromParent();
3196e8d8bef9SDimitry Andric     return Legalized;
3197e8d8bef9SDimitry Andric   }
3198e8d8bef9SDimitry Andric 
3199e8d8bef9SDimitry Andric   return UnableToLegalize;
3200e8d8bef9SDimitry Andric }
3201e8d8bef9SDimitry Andric 
3202e8d8bef9SDimitry Andric /// Emit code to insert \p InsertReg into \p TargetRet at \p OffsetBits in \p
3203e8d8bef9SDimitry Andric /// TargetReg, while preserving other bits in \p TargetReg.
3204e8d8bef9SDimitry Andric ///
3205e8d8bef9SDimitry Andric /// (InsertReg << Offset) | (TargetReg & ~(-1 >> InsertReg.size()) << Offset)
3206e8d8bef9SDimitry Andric static Register buildBitFieldInsert(MachineIRBuilder &B,
3207e8d8bef9SDimitry Andric                                     Register TargetReg, Register InsertReg,
3208e8d8bef9SDimitry Andric                                     Register OffsetBits) {
3209e8d8bef9SDimitry Andric   LLT TargetTy = B.getMRI()->getType(TargetReg);
3210e8d8bef9SDimitry Andric   LLT InsertTy = B.getMRI()->getType(InsertReg);
3211e8d8bef9SDimitry Andric   auto ZextVal = B.buildZExt(TargetTy, InsertReg);
3212e8d8bef9SDimitry Andric   auto ShiftedInsertVal = B.buildShl(TargetTy, ZextVal, OffsetBits);
3213e8d8bef9SDimitry Andric 
3214e8d8bef9SDimitry Andric   // Produce a bitmask of the value to insert
3215e8d8bef9SDimitry Andric   auto EltMask = B.buildConstant(
3216e8d8bef9SDimitry Andric     TargetTy, APInt::getLowBitsSet(TargetTy.getSizeInBits(),
3217e8d8bef9SDimitry Andric                                    InsertTy.getSizeInBits()));
3218e8d8bef9SDimitry Andric   // Shift it into position
3219e8d8bef9SDimitry Andric   auto ShiftedMask = B.buildShl(TargetTy, EltMask, OffsetBits);
3220e8d8bef9SDimitry Andric   auto InvShiftedMask = B.buildNot(TargetTy, ShiftedMask);
3221e8d8bef9SDimitry Andric 
3222e8d8bef9SDimitry Andric   // Clear out the bits in the wide element
3223e8d8bef9SDimitry Andric   auto MaskedOldElt = B.buildAnd(TargetTy, TargetReg, InvShiftedMask);
3224e8d8bef9SDimitry Andric 
3225e8d8bef9SDimitry Andric   // The value to insert has all zeros already, so stick it into the masked
3226e8d8bef9SDimitry Andric   // wide element.
3227e8d8bef9SDimitry Andric   return B.buildOr(TargetTy, MaskedOldElt, ShiftedInsertVal).getReg(0);
3228e8d8bef9SDimitry Andric }
3229e8d8bef9SDimitry Andric 
3230e8d8bef9SDimitry Andric /// Perform a G_INSERT_VECTOR_ELT in a different sized vector element. If this
3231e8d8bef9SDimitry Andric /// is increasing the element size, perform the indexing in the target element
3232e8d8bef9SDimitry Andric /// type, and use bit operations to insert at the element position. This is
3233e8d8bef9SDimitry Andric /// intended for architectures that can dynamically index the register file and
3234e8d8bef9SDimitry Andric /// want to force indexing in the native register size.
3235e8d8bef9SDimitry Andric LegalizerHelper::LegalizeResult
3236e8d8bef9SDimitry Andric LegalizerHelper::bitcastInsertVectorElt(MachineInstr &MI, unsigned TypeIdx,
3237e8d8bef9SDimitry Andric                                         LLT CastTy) {
32385ffd83dbSDimitry Andric   if (TypeIdx != 0)
32395ffd83dbSDimitry Andric     return UnableToLegalize;
32405ffd83dbSDimitry Andric 
324106c3fb27SDimitry Andric   auto [Dst, DstTy, SrcVec, SrcVecTy, Val, ValTy, Idx, IdxTy] =
324206c3fb27SDimitry Andric       MI.getFirst4RegLLTs();
324306c3fb27SDimitry Andric   LLT VecTy = DstTy;
3244e8d8bef9SDimitry Andric 
3245e8d8bef9SDimitry Andric   LLT VecEltTy = VecTy.getElementType();
3246e8d8bef9SDimitry Andric   LLT NewEltTy = CastTy.isVector() ? CastTy.getElementType() : CastTy;
3247e8d8bef9SDimitry Andric   const unsigned NewEltSize = NewEltTy.getSizeInBits();
3248e8d8bef9SDimitry Andric   const unsigned OldEltSize = VecEltTy.getSizeInBits();
3249e8d8bef9SDimitry Andric 
3250e8d8bef9SDimitry Andric   unsigned NewNumElts = CastTy.isVector() ? CastTy.getNumElements() : 1;
3251e8d8bef9SDimitry Andric   unsigned OldNumElts = VecTy.getNumElements();
3252e8d8bef9SDimitry Andric 
3253e8d8bef9SDimitry Andric   Register CastVec = MIRBuilder.buildBitcast(CastTy, SrcVec).getReg(0);
3254e8d8bef9SDimitry Andric   if (NewNumElts < OldNumElts) {
3255e8d8bef9SDimitry Andric     if (NewEltSize % OldEltSize != 0)
32565ffd83dbSDimitry Andric       return UnableToLegalize;
32575ffd83dbSDimitry Andric 
3258e8d8bef9SDimitry Andric     // This only depends on powers of 2 because we use bit tricks to figure out
3259e8d8bef9SDimitry Andric     // the bit offset we need to shift to get the target element. A general
3260e8d8bef9SDimitry Andric     // expansion could emit division/multiply.
3261e8d8bef9SDimitry Andric     if (!isPowerOf2_32(NewEltSize / OldEltSize))
32625ffd83dbSDimitry Andric       return UnableToLegalize;
32635ffd83dbSDimitry Andric 
3264e8d8bef9SDimitry Andric     const unsigned Log2EltRatio = Log2_32(NewEltSize / OldEltSize);
3265e8d8bef9SDimitry Andric     auto Log2Ratio = MIRBuilder.buildConstant(IdxTy, Log2EltRatio);
3266e8d8bef9SDimitry Andric 
3267e8d8bef9SDimitry Andric     // Divide to get the index in the wider element type.
3268e8d8bef9SDimitry Andric     auto ScaledIdx = MIRBuilder.buildLShr(IdxTy, Idx, Log2Ratio);
3269e8d8bef9SDimitry Andric 
3270e8d8bef9SDimitry Andric     Register ExtractedElt = CastVec;
3271e8d8bef9SDimitry Andric     if (CastTy.isVector()) {
3272e8d8bef9SDimitry Andric       ExtractedElt = MIRBuilder.buildExtractVectorElement(NewEltTy, CastVec,
3273e8d8bef9SDimitry Andric                                                           ScaledIdx).getReg(0);
32745ffd83dbSDimitry Andric     }
32755ffd83dbSDimitry Andric 
3276e8d8bef9SDimitry Andric     // Compute the bit offset into the register of the target element.
3277e8d8bef9SDimitry Andric     Register OffsetBits = getBitcastWiderVectorElementOffset(
3278e8d8bef9SDimitry Andric       MIRBuilder, Idx, NewEltSize, OldEltSize);
3279e8d8bef9SDimitry Andric 
3280e8d8bef9SDimitry Andric     Register InsertedElt = buildBitFieldInsert(MIRBuilder, ExtractedElt,
3281e8d8bef9SDimitry Andric                                                Val, OffsetBits);
3282e8d8bef9SDimitry Andric     if (CastTy.isVector()) {
3283e8d8bef9SDimitry Andric       InsertedElt = MIRBuilder.buildInsertVectorElement(
3284e8d8bef9SDimitry Andric         CastTy, CastVec, InsertedElt, ScaledIdx).getReg(0);
3285e8d8bef9SDimitry Andric     }
3286e8d8bef9SDimitry Andric 
3287e8d8bef9SDimitry Andric     MIRBuilder.buildBitcast(Dst, InsertedElt);
3288e8d8bef9SDimitry Andric     MI.eraseFromParent();
32895ffd83dbSDimitry Andric     return Legalized;
32905ffd83dbSDimitry Andric   }
3291e8d8bef9SDimitry Andric 
32925ffd83dbSDimitry Andric   return UnableToLegalize;
32930b57cec5SDimitry Andric }
32940b57cec5SDimitry Andric 
3295fe6060f1SDimitry Andric LegalizerHelper::LegalizeResult LegalizerHelper::lowerLoad(GAnyLoad &LoadMI) {
32960b57cec5SDimitry Andric   // Lower to a memory-width G_LOAD and a G_SEXT/G_ZEXT/G_ANYEXT
3297fe6060f1SDimitry Andric   Register DstReg = LoadMI.getDstReg();
3298fe6060f1SDimitry Andric   Register PtrReg = LoadMI.getPointerReg();
32990b57cec5SDimitry Andric   LLT DstTy = MRI.getType(DstReg);
3300fe6060f1SDimitry Andric   MachineMemOperand &MMO = LoadMI.getMMO();
3301fe6060f1SDimitry Andric   LLT MemTy = MMO.getMemoryType();
3302fe6060f1SDimitry Andric   MachineFunction &MF = MIRBuilder.getMF();
33030b57cec5SDimitry Andric 
3304fe6060f1SDimitry Andric   unsigned MemSizeInBits = MemTy.getSizeInBits();
3305fe6060f1SDimitry Andric   unsigned MemStoreSizeInBits = 8 * MemTy.getSizeInBytes();
3306fe6060f1SDimitry Andric 
3307fe6060f1SDimitry Andric   if (MemSizeInBits != MemStoreSizeInBits) {
3308349cc55cSDimitry Andric     if (MemTy.isVector())
3309349cc55cSDimitry Andric       return UnableToLegalize;
3310349cc55cSDimitry Andric 
3311fe6060f1SDimitry Andric     // Promote to a byte-sized load if not loading an integral number of
3312fe6060f1SDimitry Andric     // bytes.  For example, promote EXTLOAD:i20 -> EXTLOAD:i24.
3313fe6060f1SDimitry Andric     LLT WideMemTy = LLT::scalar(MemStoreSizeInBits);
3314fe6060f1SDimitry Andric     MachineMemOperand *NewMMO =
3315fe6060f1SDimitry Andric         MF.getMachineMemOperand(&MMO, MMO.getPointerInfo(), WideMemTy);
3316fe6060f1SDimitry Andric 
3317fe6060f1SDimitry Andric     Register LoadReg = DstReg;
3318fe6060f1SDimitry Andric     LLT LoadTy = DstTy;
3319fe6060f1SDimitry Andric 
3320fe6060f1SDimitry Andric     // If this wasn't already an extending load, we need to widen the result
3321fe6060f1SDimitry Andric     // register to avoid creating a load with a narrower result than the source.
3322fe6060f1SDimitry Andric     if (MemStoreSizeInBits > DstTy.getSizeInBits()) {
3323fe6060f1SDimitry Andric       LoadTy = WideMemTy;
3324fe6060f1SDimitry Andric       LoadReg = MRI.createGenericVirtualRegister(WideMemTy);
3325fe6060f1SDimitry Andric     }
3326fe6060f1SDimitry Andric 
3327fe6060f1SDimitry Andric     if (isa<GSExtLoad>(LoadMI)) {
3328fe6060f1SDimitry Andric       auto NewLoad = MIRBuilder.buildLoad(LoadTy, PtrReg, *NewMMO);
3329fe6060f1SDimitry Andric       MIRBuilder.buildSExtInReg(LoadReg, NewLoad, MemSizeInBits);
333081ad6265SDimitry Andric     } else if (isa<GZExtLoad>(LoadMI) || WideMemTy == LoadTy) {
3331fe6060f1SDimitry Andric       auto NewLoad = MIRBuilder.buildLoad(LoadTy, PtrReg, *NewMMO);
3332fe6060f1SDimitry Andric       // The extra bits are guaranteed to be zero, since we stored them that
3333fe6060f1SDimitry Andric       // way.  A zext load from Wide thus automatically gives zext from MemVT.
3334fe6060f1SDimitry Andric       MIRBuilder.buildAssertZExt(LoadReg, NewLoad, MemSizeInBits);
3335fe6060f1SDimitry Andric     } else {
3336fe6060f1SDimitry Andric       MIRBuilder.buildLoad(LoadReg, PtrReg, *NewMMO);
3337fe6060f1SDimitry Andric     }
3338fe6060f1SDimitry Andric 
3339fe6060f1SDimitry Andric     if (DstTy != LoadTy)
3340fe6060f1SDimitry Andric       MIRBuilder.buildTrunc(DstReg, LoadReg);
3341fe6060f1SDimitry Andric 
3342fe6060f1SDimitry Andric     LoadMI.eraseFromParent();
3343fe6060f1SDimitry Andric     return Legalized;
3344fe6060f1SDimitry Andric   }
3345fe6060f1SDimitry Andric 
3346fe6060f1SDimitry Andric   // Big endian lowering not implemented.
3347fe6060f1SDimitry Andric   if (MIRBuilder.getDataLayout().isBigEndian())
3348fe6060f1SDimitry Andric     return UnableToLegalize;
3349fe6060f1SDimitry Andric 
3350349cc55cSDimitry Andric   // This load needs splitting into power of 2 sized loads.
3351349cc55cSDimitry Andric   //
33528bcb0991SDimitry Andric   // Our strategy here is to generate anyextending loads for the smaller
33538bcb0991SDimitry Andric   // types up to next power-2 result type, and then combine the two larger
33548bcb0991SDimitry Andric   // result values together, before truncating back down to the non-pow-2
33558bcb0991SDimitry Andric   // type.
33568bcb0991SDimitry Andric   // E.g. v1 = i24 load =>
33575ffd83dbSDimitry Andric   // v2 = i32 zextload (2 byte)
33588bcb0991SDimitry Andric   // v3 = i32 load (1 byte)
33598bcb0991SDimitry Andric   // v4 = i32 shl v3, 16
33608bcb0991SDimitry Andric   // v5 = i32 or v4, v2
33618bcb0991SDimitry Andric   // v1 = i24 trunc v5
33628bcb0991SDimitry Andric   // By doing this we generate the correct truncate which should get
33638bcb0991SDimitry Andric   // combined away as an artifact with a matching extend.
3364349cc55cSDimitry Andric 
3365349cc55cSDimitry Andric   uint64_t LargeSplitSize, SmallSplitSize;
3366349cc55cSDimitry Andric 
3367349cc55cSDimitry Andric   if (!isPowerOf2_32(MemSizeInBits)) {
3368349cc55cSDimitry Andric     // This load needs splitting into power of 2 sized loads.
336906c3fb27SDimitry Andric     LargeSplitSize = llvm::bit_floor(MemSizeInBits);
3370349cc55cSDimitry Andric     SmallSplitSize = MemSizeInBits - LargeSplitSize;
3371349cc55cSDimitry Andric   } else {
3372349cc55cSDimitry Andric     // This is already a power of 2, but we still need to split this in half.
3373349cc55cSDimitry Andric     //
3374349cc55cSDimitry Andric     // Assume we're being asked to decompose an unaligned load.
3375349cc55cSDimitry Andric     // TODO: If this requires multiple splits, handle them all at once.
3376349cc55cSDimitry Andric     auto &Ctx = MF.getFunction().getContext();
3377349cc55cSDimitry Andric     if (TLI.allowsMemoryAccess(Ctx, MIRBuilder.getDataLayout(), MemTy, MMO))
3378349cc55cSDimitry Andric       return UnableToLegalize;
3379349cc55cSDimitry Andric 
3380349cc55cSDimitry Andric     SmallSplitSize = LargeSplitSize = MemSizeInBits / 2;
3381349cc55cSDimitry Andric   }
3382349cc55cSDimitry Andric 
3383349cc55cSDimitry Andric   if (MemTy.isVector()) {
3384349cc55cSDimitry Andric     // TODO: Handle vector extloads
3385349cc55cSDimitry Andric     if (MemTy != DstTy)
3386349cc55cSDimitry Andric       return UnableToLegalize;
3387349cc55cSDimitry Andric 
3388349cc55cSDimitry Andric     // TODO: We can do better than scalarizing the vector and at least split it
3389349cc55cSDimitry Andric     // in half.
3390349cc55cSDimitry Andric     return reduceLoadStoreWidth(LoadMI, 0, DstTy.getElementType());
3391349cc55cSDimitry Andric   }
33928bcb0991SDimitry Andric 
33938bcb0991SDimitry Andric   MachineMemOperand *LargeMMO =
33948bcb0991SDimitry Andric       MF.getMachineMemOperand(&MMO, 0, LargeSplitSize / 8);
3395fe6060f1SDimitry Andric   MachineMemOperand *SmallMMO =
3396fe6060f1SDimitry Andric       MF.getMachineMemOperand(&MMO, LargeSplitSize / 8, SmallSplitSize / 8);
33978bcb0991SDimitry Andric 
33988bcb0991SDimitry Andric   LLT PtrTy = MRI.getType(PtrReg);
3399fe6060f1SDimitry Andric   unsigned AnyExtSize = PowerOf2Ceil(DstTy.getSizeInBits());
34008bcb0991SDimitry Andric   LLT AnyExtTy = LLT::scalar(AnyExtSize);
3401fe6060f1SDimitry Andric   auto LargeLoad = MIRBuilder.buildLoadInstr(TargetOpcode::G_ZEXTLOAD, AnyExtTy,
3402fe6060f1SDimitry Andric                                              PtrReg, *LargeMMO);
34038bcb0991SDimitry Andric 
3404fe6060f1SDimitry Andric   auto OffsetCst = MIRBuilder.buildConstant(LLT::scalar(PtrTy.getSizeInBits()),
3405fe6060f1SDimitry Andric                                             LargeSplitSize / 8);
3406480093f4SDimitry Andric   Register PtrAddReg = MRI.createGenericVirtualRegister(PtrTy);
3407fe6060f1SDimitry Andric   auto SmallPtr = MIRBuilder.buildPtrAdd(PtrAddReg, PtrReg, OffsetCst);
3408fe6060f1SDimitry Andric   auto SmallLoad = MIRBuilder.buildLoadInstr(LoadMI.getOpcode(), AnyExtTy,
3409fe6060f1SDimitry Andric                                              SmallPtr, *SmallMMO);
34108bcb0991SDimitry Andric 
34118bcb0991SDimitry Andric   auto ShiftAmt = MIRBuilder.buildConstant(AnyExtTy, LargeSplitSize);
34128bcb0991SDimitry Andric   auto Shift = MIRBuilder.buildShl(AnyExtTy, SmallLoad, ShiftAmt);
3413fe6060f1SDimitry Andric 
3414fe6060f1SDimitry Andric   if (AnyExtTy == DstTy)
3415fe6060f1SDimitry Andric     MIRBuilder.buildOr(DstReg, Shift, LargeLoad);
3416349cc55cSDimitry Andric   else if (AnyExtTy.getSizeInBits() != DstTy.getSizeInBits()) {
34178bcb0991SDimitry Andric     auto Or = MIRBuilder.buildOr(AnyExtTy, Shift, LargeLoad);
3418fe6060f1SDimitry Andric     MIRBuilder.buildTrunc(DstReg, {Or});
3419349cc55cSDimitry Andric   } else {
3420349cc55cSDimitry Andric     assert(DstTy.isPointer() && "expected pointer");
3421349cc55cSDimitry Andric     auto Or = MIRBuilder.buildOr(AnyExtTy, Shift, LargeLoad);
3422349cc55cSDimitry Andric 
3423349cc55cSDimitry Andric     // FIXME: We currently consider this to be illegal for non-integral address
3424349cc55cSDimitry Andric     // spaces, but we need still need a way to reinterpret the bits.
3425349cc55cSDimitry Andric     MIRBuilder.buildIntToPtr(DstReg, Or);
3426fe6060f1SDimitry Andric   }
3427fe6060f1SDimitry Andric 
3428fe6060f1SDimitry Andric   LoadMI.eraseFromParent();
34298bcb0991SDimitry Andric   return Legalized;
34308bcb0991SDimitry Andric }
3431e8d8bef9SDimitry Andric 
3432fe6060f1SDimitry Andric LegalizerHelper::LegalizeResult LegalizerHelper::lowerStore(GStore &StoreMI) {
34338bcb0991SDimitry Andric   // Lower a non-power of 2 store into multiple pow-2 stores.
34348bcb0991SDimitry Andric   // E.g. split an i24 store into an i16 store + i8 store.
34358bcb0991SDimitry Andric   // We do this by first extending the stored value to the next largest power
34368bcb0991SDimitry Andric   // of 2 type, and then using truncating stores to store the components.
34378bcb0991SDimitry Andric   // By doing this, likewise with G_LOAD, generate an extend that can be
34388bcb0991SDimitry Andric   // artifact-combined away instead of leaving behind extracts.
3439fe6060f1SDimitry Andric   Register SrcReg = StoreMI.getValueReg();
3440fe6060f1SDimitry Andric   Register PtrReg = StoreMI.getPointerReg();
34418bcb0991SDimitry Andric   LLT SrcTy = MRI.getType(SrcReg);
3442fe6060f1SDimitry Andric   MachineFunction &MF = MIRBuilder.getMF();
3443fe6060f1SDimitry Andric   MachineMemOperand &MMO = **StoreMI.memoperands_begin();
3444fe6060f1SDimitry Andric   LLT MemTy = MMO.getMemoryType();
3445fe6060f1SDimitry Andric 
3446fe6060f1SDimitry Andric   unsigned StoreWidth = MemTy.getSizeInBits();
3447fe6060f1SDimitry Andric   unsigned StoreSizeInBits = 8 * MemTy.getSizeInBytes();
3448fe6060f1SDimitry Andric 
3449fe6060f1SDimitry Andric   if (StoreWidth != StoreSizeInBits) {
3450349cc55cSDimitry Andric     if (SrcTy.isVector())
3451349cc55cSDimitry Andric       return UnableToLegalize;
3452349cc55cSDimitry Andric 
3453fe6060f1SDimitry Andric     // Promote to a byte-sized store with upper bits zero if not
3454fe6060f1SDimitry Andric     // storing an integral number of bytes.  For example, promote
3455fe6060f1SDimitry Andric     // TRUNCSTORE:i1 X -> TRUNCSTORE:i8 (and X, 1)
3456fe6060f1SDimitry Andric     LLT WideTy = LLT::scalar(StoreSizeInBits);
3457fe6060f1SDimitry Andric 
3458fe6060f1SDimitry Andric     if (StoreSizeInBits > SrcTy.getSizeInBits()) {
3459fe6060f1SDimitry Andric       // Avoid creating a store with a narrower source than result.
3460fe6060f1SDimitry Andric       SrcReg = MIRBuilder.buildAnyExt(WideTy, SrcReg).getReg(0);
3461fe6060f1SDimitry Andric       SrcTy = WideTy;
3462fe6060f1SDimitry Andric     }
3463fe6060f1SDimitry Andric 
3464fe6060f1SDimitry Andric     auto ZextInReg = MIRBuilder.buildZExtInReg(SrcTy, SrcReg, StoreWidth);
3465fe6060f1SDimitry Andric 
3466fe6060f1SDimitry Andric     MachineMemOperand *NewMMO =
3467fe6060f1SDimitry Andric         MF.getMachineMemOperand(&MMO, MMO.getPointerInfo(), WideTy);
3468fe6060f1SDimitry Andric     MIRBuilder.buildStore(ZextInReg, PtrReg, *NewMMO);
3469fe6060f1SDimitry Andric     StoreMI.eraseFromParent();
3470fe6060f1SDimitry Andric     return Legalized;
3471fe6060f1SDimitry Andric   }
3472fe6060f1SDimitry Andric 
3473349cc55cSDimitry Andric   if (MemTy.isVector()) {
3474349cc55cSDimitry Andric     // TODO: Handle vector trunc stores
3475349cc55cSDimitry Andric     if (MemTy != SrcTy)
3476349cc55cSDimitry Andric       return UnableToLegalize;
3477349cc55cSDimitry Andric 
3478349cc55cSDimitry Andric     // TODO: We can do better than scalarizing the vector and at least split it
3479349cc55cSDimitry Andric     // in half.
3480349cc55cSDimitry Andric     return reduceLoadStoreWidth(StoreMI, 0, SrcTy.getElementType());
3481349cc55cSDimitry Andric   }
3482349cc55cSDimitry Andric 
3483349cc55cSDimitry Andric   unsigned MemSizeInBits = MemTy.getSizeInBits();
3484349cc55cSDimitry Andric   uint64_t LargeSplitSize, SmallSplitSize;
3485349cc55cSDimitry Andric 
3486349cc55cSDimitry Andric   if (!isPowerOf2_32(MemSizeInBits)) {
348706c3fb27SDimitry Andric     LargeSplitSize = llvm::bit_floor<uint64_t>(MemTy.getSizeInBits());
3488349cc55cSDimitry Andric     SmallSplitSize = MemTy.getSizeInBits() - LargeSplitSize;
3489349cc55cSDimitry Andric   } else {
3490349cc55cSDimitry Andric     auto &Ctx = MF.getFunction().getContext();
3491349cc55cSDimitry Andric     if (TLI.allowsMemoryAccess(Ctx, MIRBuilder.getDataLayout(), MemTy, MMO))
34928bcb0991SDimitry Andric       return UnableToLegalize; // Don't know what we're being asked to do.
34938bcb0991SDimitry Andric 
3494349cc55cSDimitry Andric     SmallSplitSize = LargeSplitSize = MemSizeInBits / 2;
3495349cc55cSDimitry Andric   }
3496349cc55cSDimitry Andric 
3497fe6060f1SDimitry Andric   // Extend to the next pow-2. If this store was itself the result of lowering,
3498fe6060f1SDimitry Andric   // e.g. an s56 store being broken into s32 + s24, we might have a stored type
3499349cc55cSDimitry Andric   // that's wider than the stored size.
3500349cc55cSDimitry Andric   unsigned AnyExtSize = PowerOf2Ceil(MemTy.getSizeInBits());
3501349cc55cSDimitry Andric   const LLT NewSrcTy = LLT::scalar(AnyExtSize);
3502349cc55cSDimitry Andric 
3503349cc55cSDimitry Andric   if (SrcTy.isPointer()) {
3504349cc55cSDimitry Andric     const LLT IntPtrTy = LLT::scalar(SrcTy.getSizeInBits());
3505349cc55cSDimitry Andric     SrcReg = MIRBuilder.buildPtrToInt(IntPtrTy, SrcReg).getReg(0);
3506349cc55cSDimitry Andric   }
3507349cc55cSDimitry Andric 
3508fe6060f1SDimitry Andric   auto ExtVal = MIRBuilder.buildAnyExtOrTrunc(NewSrcTy, SrcReg);
35098bcb0991SDimitry Andric 
35108bcb0991SDimitry Andric   // Obtain the smaller value by shifting away the larger value.
3511fe6060f1SDimitry Andric   auto ShiftAmt = MIRBuilder.buildConstant(NewSrcTy, LargeSplitSize);
3512fe6060f1SDimitry Andric   auto SmallVal = MIRBuilder.buildLShr(NewSrcTy, ExtVal, ShiftAmt);
35138bcb0991SDimitry Andric 
3514480093f4SDimitry Andric   // Generate the PtrAdd and truncating stores.
35158bcb0991SDimitry Andric   LLT PtrTy = MRI.getType(PtrReg);
35165ffd83dbSDimitry Andric   auto OffsetCst = MIRBuilder.buildConstant(
35175ffd83dbSDimitry Andric     LLT::scalar(PtrTy.getSizeInBits()), LargeSplitSize / 8);
3518480093f4SDimitry Andric   auto SmallPtr =
3519349cc55cSDimitry Andric     MIRBuilder.buildPtrAdd(PtrTy, PtrReg, OffsetCst);
35208bcb0991SDimitry Andric 
35218bcb0991SDimitry Andric   MachineMemOperand *LargeMMO =
35228bcb0991SDimitry Andric     MF.getMachineMemOperand(&MMO, 0, LargeSplitSize / 8);
35238bcb0991SDimitry Andric   MachineMemOperand *SmallMMO =
35248bcb0991SDimitry Andric     MF.getMachineMemOperand(&MMO, LargeSplitSize / 8, SmallSplitSize / 8);
3525fe6060f1SDimitry Andric   MIRBuilder.buildStore(ExtVal, PtrReg, *LargeMMO);
3526fe6060f1SDimitry Andric   MIRBuilder.buildStore(SmallVal, SmallPtr, *SmallMMO);
3527fe6060f1SDimitry Andric   StoreMI.eraseFromParent();
35288bcb0991SDimitry Andric   return Legalized;
35298bcb0991SDimitry Andric }
3530e8d8bef9SDimitry Andric 
3531e8d8bef9SDimitry Andric LegalizerHelper::LegalizeResult
3532e8d8bef9SDimitry Andric LegalizerHelper::bitcast(MachineInstr &MI, unsigned TypeIdx, LLT CastTy) {
3533e8d8bef9SDimitry Andric   switch (MI.getOpcode()) {
3534e8d8bef9SDimitry Andric   case TargetOpcode::G_LOAD: {
3535e8d8bef9SDimitry Andric     if (TypeIdx != 0)
3536e8d8bef9SDimitry Andric       return UnableToLegalize;
3537fe6060f1SDimitry Andric     MachineMemOperand &MMO = **MI.memoperands_begin();
3538fe6060f1SDimitry Andric 
3539fe6060f1SDimitry Andric     // Not sure how to interpret a bitcast of an extending load.
3540fe6060f1SDimitry Andric     if (MMO.getMemoryType().getSizeInBits() != CastTy.getSizeInBits())
3541fe6060f1SDimitry Andric       return UnableToLegalize;
3542e8d8bef9SDimitry Andric 
3543e8d8bef9SDimitry Andric     Observer.changingInstr(MI);
3544e8d8bef9SDimitry Andric     bitcastDst(MI, CastTy, 0);
3545fe6060f1SDimitry Andric     MMO.setType(CastTy);
3546e8d8bef9SDimitry Andric     Observer.changedInstr(MI);
3547e8d8bef9SDimitry Andric     return Legalized;
3548e8d8bef9SDimitry Andric   }
3549e8d8bef9SDimitry Andric   case TargetOpcode::G_STORE: {
3550e8d8bef9SDimitry Andric     if (TypeIdx != 0)
3551e8d8bef9SDimitry Andric       return UnableToLegalize;
3552e8d8bef9SDimitry Andric 
3553fe6060f1SDimitry Andric     MachineMemOperand &MMO = **MI.memoperands_begin();
3554fe6060f1SDimitry Andric 
3555fe6060f1SDimitry Andric     // Not sure how to interpret a bitcast of a truncating store.
3556fe6060f1SDimitry Andric     if (MMO.getMemoryType().getSizeInBits() != CastTy.getSizeInBits())
3557fe6060f1SDimitry Andric       return UnableToLegalize;
3558fe6060f1SDimitry Andric 
3559e8d8bef9SDimitry Andric     Observer.changingInstr(MI);
3560e8d8bef9SDimitry Andric     bitcastSrc(MI, CastTy, 0);
3561fe6060f1SDimitry Andric     MMO.setType(CastTy);
3562e8d8bef9SDimitry Andric     Observer.changedInstr(MI);
3563e8d8bef9SDimitry Andric     return Legalized;
3564e8d8bef9SDimitry Andric   }
3565e8d8bef9SDimitry Andric   case TargetOpcode::G_SELECT: {
3566e8d8bef9SDimitry Andric     if (TypeIdx != 0)
3567e8d8bef9SDimitry Andric       return UnableToLegalize;
3568e8d8bef9SDimitry Andric 
3569e8d8bef9SDimitry Andric     if (MRI.getType(MI.getOperand(1).getReg()).isVector()) {
3570e8d8bef9SDimitry Andric       LLVM_DEBUG(
3571e8d8bef9SDimitry Andric           dbgs() << "bitcast action not implemented for vector select\n");
3572e8d8bef9SDimitry Andric       return UnableToLegalize;
3573e8d8bef9SDimitry Andric     }
3574e8d8bef9SDimitry Andric 
3575e8d8bef9SDimitry Andric     Observer.changingInstr(MI);
3576e8d8bef9SDimitry Andric     bitcastSrc(MI, CastTy, 2);
3577e8d8bef9SDimitry Andric     bitcastSrc(MI, CastTy, 3);
3578e8d8bef9SDimitry Andric     bitcastDst(MI, CastTy, 0);
3579e8d8bef9SDimitry Andric     Observer.changedInstr(MI);
3580e8d8bef9SDimitry Andric     return Legalized;
3581e8d8bef9SDimitry Andric   }
3582e8d8bef9SDimitry Andric   case TargetOpcode::G_AND:
3583e8d8bef9SDimitry Andric   case TargetOpcode::G_OR:
3584e8d8bef9SDimitry Andric   case TargetOpcode::G_XOR: {
3585e8d8bef9SDimitry Andric     Observer.changingInstr(MI);
3586e8d8bef9SDimitry Andric     bitcastSrc(MI, CastTy, 1);
3587e8d8bef9SDimitry Andric     bitcastSrc(MI, CastTy, 2);
3588e8d8bef9SDimitry Andric     bitcastDst(MI, CastTy, 0);
3589e8d8bef9SDimitry Andric     Observer.changedInstr(MI);
3590e8d8bef9SDimitry Andric     return Legalized;
3591e8d8bef9SDimitry Andric   }
3592e8d8bef9SDimitry Andric   case TargetOpcode::G_EXTRACT_VECTOR_ELT:
3593e8d8bef9SDimitry Andric     return bitcastExtractVectorElt(MI, TypeIdx, CastTy);
3594e8d8bef9SDimitry Andric   case TargetOpcode::G_INSERT_VECTOR_ELT:
3595e8d8bef9SDimitry Andric     return bitcastInsertVectorElt(MI, TypeIdx, CastTy);
3596e8d8bef9SDimitry Andric   default:
3597e8d8bef9SDimitry Andric     return UnableToLegalize;
3598e8d8bef9SDimitry Andric   }
3599e8d8bef9SDimitry Andric }
3600e8d8bef9SDimitry Andric 
3601e8d8bef9SDimitry Andric // Legalize an instruction by changing the opcode in place.
3602e8d8bef9SDimitry Andric void LegalizerHelper::changeOpcode(MachineInstr &MI, unsigned NewOpcode) {
3603e8d8bef9SDimitry Andric     Observer.changingInstr(MI);
3604e8d8bef9SDimitry Andric     MI.setDesc(MIRBuilder.getTII().get(NewOpcode));
3605e8d8bef9SDimitry Andric     Observer.changedInstr(MI);
3606e8d8bef9SDimitry Andric }
3607e8d8bef9SDimitry Andric 
3608e8d8bef9SDimitry Andric LegalizerHelper::LegalizeResult
3609e8d8bef9SDimitry Andric LegalizerHelper::lower(MachineInstr &MI, unsigned TypeIdx, LLT LowerHintTy) {
3610e8d8bef9SDimitry Andric   using namespace TargetOpcode;
3611e8d8bef9SDimitry Andric 
3612e8d8bef9SDimitry Andric   switch(MI.getOpcode()) {
3613e8d8bef9SDimitry Andric   default:
3614e8d8bef9SDimitry Andric     return UnableToLegalize;
361506c3fb27SDimitry Andric   case TargetOpcode::G_FCONSTANT:
361606c3fb27SDimitry Andric     return lowerFConstant(MI);
3617e8d8bef9SDimitry Andric   case TargetOpcode::G_BITCAST:
3618e8d8bef9SDimitry Andric     return lowerBitcast(MI);
3619e8d8bef9SDimitry Andric   case TargetOpcode::G_SREM:
3620e8d8bef9SDimitry Andric   case TargetOpcode::G_UREM: {
3621e8d8bef9SDimitry Andric     LLT Ty = MRI.getType(MI.getOperand(0).getReg());
3622e8d8bef9SDimitry Andric     auto Quot =
3623e8d8bef9SDimitry Andric         MIRBuilder.buildInstr(MI.getOpcode() == G_SREM ? G_SDIV : G_UDIV, {Ty},
3624e8d8bef9SDimitry Andric                               {MI.getOperand(1), MI.getOperand(2)});
3625e8d8bef9SDimitry Andric 
3626e8d8bef9SDimitry Andric     auto Prod = MIRBuilder.buildMul(Ty, Quot, MI.getOperand(2));
3627e8d8bef9SDimitry Andric     MIRBuilder.buildSub(MI.getOperand(0), MI.getOperand(1), Prod);
3628e8d8bef9SDimitry Andric     MI.eraseFromParent();
3629e8d8bef9SDimitry Andric     return Legalized;
3630e8d8bef9SDimitry Andric   }
3631e8d8bef9SDimitry Andric   case TargetOpcode::G_SADDO:
3632e8d8bef9SDimitry Andric   case TargetOpcode::G_SSUBO:
3633e8d8bef9SDimitry Andric     return lowerSADDO_SSUBO(MI);
3634e8d8bef9SDimitry Andric   case TargetOpcode::G_UMULH:
3635e8d8bef9SDimitry Andric   case TargetOpcode::G_SMULH:
3636e8d8bef9SDimitry Andric     return lowerSMULH_UMULH(MI);
3637e8d8bef9SDimitry Andric   case TargetOpcode::G_SMULO:
3638e8d8bef9SDimitry Andric   case TargetOpcode::G_UMULO: {
3639e8d8bef9SDimitry Andric     // Generate G_UMULH/G_SMULH to check for overflow and a normal G_MUL for the
3640e8d8bef9SDimitry Andric     // result.
364106c3fb27SDimitry Andric     auto [Res, Overflow, LHS, RHS] = MI.getFirst4Regs();
3642e8d8bef9SDimitry Andric     LLT Ty = MRI.getType(Res);
3643e8d8bef9SDimitry Andric 
3644e8d8bef9SDimitry Andric     unsigned Opcode = MI.getOpcode() == TargetOpcode::G_SMULO
3645e8d8bef9SDimitry Andric                           ? TargetOpcode::G_SMULH
3646e8d8bef9SDimitry Andric                           : TargetOpcode::G_UMULH;
3647e8d8bef9SDimitry Andric 
3648e8d8bef9SDimitry Andric     Observer.changingInstr(MI);
3649e8d8bef9SDimitry Andric     const auto &TII = MIRBuilder.getTII();
3650e8d8bef9SDimitry Andric     MI.setDesc(TII.get(TargetOpcode::G_MUL));
365181ad6265SDimitry Andric     MI.removeOperand(1);
3652e8d8bef9SDimitry Andric     Observer.changedInstr(MI);
3653e8d8bef9SDimitry Andric 
3654e8d8bef9SDimitry Andric     auto HiPart = MIRBuilder.buildInstr(Opcode, {Ty}, {LHS, RHS});
3655e8d8bef9SDimitry Andric     auto Zero = MIRBuilder.buildConstant(Ty, 0);
3656e8d8bef9SDimitry Andric 
3657e8d8bef9SDimitry Andric     // Move insert point forward so we can use the Res register if needed.
3658e8d8bef9SDimitry Andric     MIRBuilder.setInsertPt(MIRBuilder.getMBB(), ++MIRBuilder.getInsertPt());
3659e8d8bef9SDimitry Andric 
3660e8d8bef9SDimitry Andric     // For *signed* multiply, overflow is detected by checking:
3661e8d8bef9SDimitry Andric     // (hi != (lo >> bitwidth-1))
3662e8d8bef9SDimitry Andric     if (Opcode == TargetOpcode::G_SMULH) {
3663e8d8bef9SDimitry Andric       auto ShiftAmt = MIRBuilder.buildConstant(Ty, Ty.getSizeInBits() - 1);
3664e8d8bef9SDimitry Andric       auto Shifted = MIRBuilder.buildAShr(Ty, Res, ShiftAmt);
3665e8d8bef9SDimitry Andric       MIRBuilder.buildICmp(CmpInst::ICMP_NE, Overflow, HiPart, Shifted);
3666e8d8bef9SDimitry Andric     } else {
3667e8d8bef9SDimitry Andric       MIRBuilder.buildICmp(CmpInst::ICMP_NE, Overflow, HiPart, Zero);
3668e8d8bef9SDimitry Andric     }
3669e8d8bef9SDimitry Andric     return Legalized;
3670e8d8bef9SDimitry Andric   }
3671e8d8bef9SDimitry Andric   case TargetOpcode::G_FNEG: {
367206c3fb27SDimitry Andric     auto [Res, SubByReg] = MI.getFirst2Regs();
3673e8d8bef9SDimitry Andric     LLT Ty = MRI.getType(Res);
3674e8d8bef9SDimitry Andric 
3675e8d8bef9SDimitry Andric     // TODO: Handle vector types once we are able to
3676e8d8bef9SDimitry Andric     // represent them.
3677e8d8bef9SDimitry Andric     if (Ty.isVector())
3678e8d8bef9SDimitry Andric       return UnableToLegalize;
3679e8d8bef9SDimitry Andric     auto SignMask =
3680e8d8bef9SDimitry Andric         MIRBuilder.buildConstant(Ty, APInt::getSignMask(Ty.getSizeInBits()));
3681e8d8bef9SDimitry Andric     MIRBuilder.buildXor(Res, SubByReg, SignMask);
3682e8d8bef9SDimitry Andric     MI.eraseFromParent();
3683e8d8bef9SDimitry Andric     return Legalized;
3684e8d8bef9SDimitry Andric   }
3685bdd1243dSDimitry Andric   case TargetOpcode::G_FSUB:
3686bdd1243dSDimitry Andric   case TargetOpcode::G_STRICT_FSUB: {
368706c3fb27SDimitry Andric     auto [Res, LHS, RHS] = MI.getFirst3Regs();
3688e8d8bef9SDimitry Andric     LLT Ty = MRI.getType(Res);
3689e8d8bef9SDimitry Andric 
3690e8d8bef9SDimitry Andric     // Lower (G_FSUB LHS, RHS) to (G_FADD LHS, (G_FNEG RHS)).
3691bdd1243dSDimitry Andric     auto Neg = MIRBuilder.buildFNeg(Ty, RHS);
3692bdd1243dSDimitry Andric 
3693bdd1243dSDimitry Andric     if (MI.getOpcode() == TargetOpcode::G_STRICT_FSUB)
3694bdd1243dSDimitry Andric       MIRBuilder.buildStrictFAdd(Res, LHS, Neg, MI.getFlags());
3695bdd1243dSDimitry Andric     else
3696e8d8bef9SDimitry Andric       MIRBuilder.buildFAdd(Res, LHS, Neg, MI.getFlags());
3697bdd1243dSDimitry Andric 
3698e8d8bef9SDimitry Andric     MI.eraseFromParent();
3699e8d8bef9SDimitry Andric     return Legalized;
3700e8d8bef9SDimitry Andric   }
3701e8d8bef9SDimitry Andric   case TargetOpcode::G_FMAD:
3702e8d8bef9SDimitry Andric     return lowerFMad(MI);
3703e8d8bef9SDimitry Andric   case TargetOpcode::G_FFLOOR:
3704e8d8bef9SDimitry Andric     return lowerFFloor(MI);
3705e8d8bef9SDimitry Andric   case TargetOpcode::G_INTRINSIC_ROUND:
3706e8d8bef9SDimitry Andric     return lowerIntrinsicRound(MI);
37075f757f3fSDimitry Andric   case TargetOpcode::G_FRINT: {
3708e8d8bef9SDimitry Andric     // Since round even is the assumed rounding mode for unconstrained FP
3709e8d8bef9SDimitry Andric     // operations, rint and roundeven are the same operation.
37105f757f3fSDimitry Andric     changeOpcode(MI, TargetOpcode::G_INTRINSIC_ROUNDEVEN);
3711e8d8bef9SDimitry Andric     return Legalized;
3712e8d8bef9SDimitry Andric   }
3713e8d8bef9SDimitry Andric   case TargetOpcode::G_ATOMIC_CMPXCHG_WITH_SUCCESS: {
371406c3fb27SDimitry Andric     auto [OldValRes, SuccessRes, Addr, CmpVal, NewVal] = MI.getFirst5Regs();
3715e8d8bef9SDimitry Andric     MIRBuilder.buildAtomicCmpXchg(OldValRes, Addr, CmpVal, NewVal,
3716e8d8bef9SDimitry Andric                                   **MI.memoperands_begin());
3717e8d8bef9SDimitry Andric     MIRBuilder.buildICmp(CmpInst::ICMP_EQ, SuccessRes, OldValRes, CmpVal);
3718e8d8bef9SDimitry Andric     MI.eraseFromParent();
3719e8d8bef9SDimitry Andric     return Legalized;
3720e8d8bef9SDimitry Andric   }
3721e8d8bef9SDimitry Andric   case TargetOpcode::G_LOAD:
3722e8d8bef9SDimitry Andric   case TargetOpcode::G_SEXTLOAD:
3723e8d8bef9SDimitry Andric   case TargetOpcode::G_ZEXTLOAD:
3724fe6060f1SDimitry Andric     return lowerLoad(cast<GAnyLoad>(MI));
3725e8d8bef9SDimitry Andric   case TargetOpcode::G_STORE:
3726fe6060f1SDimitry Andric     return lowerStore(cast<GStore>(MI));
37270b57cec5SDimitry Andric   case TargetOpcode::G_CTLZ_ZERO_UNDEF:
37280b57cec5SDimitry Andric   case TargetOpcode::G_CTTZ_ZERO_UNDEF:
37290b57cec5SDimitry Andric   case TargetOpcode::G_CTLZ:
37300b57cec5SDimitry Andric   case TargetOpcode::G_CTTZ:
37310b57cec5SDimitry Andric   case TargetOpcode::G_CTPOP:
3732e8d8bef9SDimitry Andric     return lowerBitCount(MI);
37330b57cec5SDimitry Andric   case G_UADDO: {
373406c3fb27SDimitry Andric     auto [Res, CarryOut, LHS, RHS] = MI.getFirst4Regs();
37350b57cec5SDimitry Andric 
37360b57cec5SDimitry Andric     MIRBuilder.buildAdd(Res, LHS, RHS);
37370b57cec5SDimitry Andric     MIRBuilder.buildICmp(CmpInst::ICMP_ULT, CarryOut, Res, RHS);
37380b57cec5SDimitry Andric 
37390b57cec5SDimitry Andric     MI.eraseFromParent();
37400b57cec5SDimitry Andric     return Legalized;
37410b57cec5SDimitry Andric   }
37420b57cec5SDimitry Andric   case G_UADDE: {
374306c3fb27SDimitry Andric     auto [Res, CarryOut, LHS, RHS, CarryIn] = MI.getFirst5Regs();
37445f757f3fSDimitry Andric     const LLT CondTy = MRI.getType(CarryOut);
37455f757f3fSDimitry Andric     const LLT Ty = MRI.getType(Res);
37460b57cec5SDimitry Andric 
37475f757f3fSDimitry Andric     // Initial add of the two operands.
37485ffd83dbSDimitry Andric     auto TmpRes = MIRBuilder.buildAdd(Ty, LHS, RHS);
37495f757f3fSDimitry Andric 
37505f757f3fSDimitry Andric     // Initial check for carry.
37515f757f3fSDimitry Andric     auto Carry = MIRBuilder.buildICmp(CmpInst::ICMP_ULT, CondTy, TmpRes, LHS);
37525f757f3fSDimitry Andric 
37535f757f3fSDimitry Andric     // Add the sum and the carry.
37545ffd83dbSDimitry Andric     auto ZExtCarryIn = MIRBuilder.buildZExt(Ty, CarryIn);
37550b57cec5SDimitry Andric     MIRBuilder.buildAdd(Res, TmpRes, ZExtCarryIn);
37565f757f3fSDimitry Andric 
37575f757f3fSDimitry Andric     // Second check for carry. We can only carry if the initial sum is all 1s
37585f757f3fSDimitry Andric     // and the carry is set, resulting in a new sum of 0.
37595f757f3fSDimitry Andric     auto Zero = MIRBuilder.buildConstant(Ty, 0);
37605f757f3fSDimitry Andric     auto ResEqZero = MIRBuilder.buildICmp(CmpInst::ICMP_EQ, CondTy, Res, Zero);
37615f757f3fSDimitry Andric     auto Carry2 = MIRBuilder.buildAnd(CondTy, ResEqZero, CarryIn);
37625f757f3fSDimitry Andric     MIRBuilder.buildOr(CarryOut, Carry, Carry2);
37630b57cec5SDimitry Andric 
37640b57cec5SDimitry Andric     MI.eraseFromParent();
37650b57cec5SDimitry Andric     return Legalized;
37660b57cec5SDimitry Andric   }
37670b57cec5SDimitry Andric   case G_USUBO: {
376806c3fb27SDimitry Andric     auto [Res, BorrowOut, LHS, RHS] = MI.getFirst4Regs();
37690b57cec5SDimitry Andric 
37700b57cec5SDimitry Andric     MIRBuilder.buildSub(Res, LHS, RHS);
37710b57cec5SDimitry Andric     MIRBuilder.buildICmp(CmpInst::ICMP_ULT, BorrowOut, LHS, RHS);
37720b57cec5SDimitry Andric 
37730b57cec5SDimitry Andric     MI.eraseFromParent();
37740b57cec5SDimitry Andric     return Legalized;
37750b57cec5SDimitry Andric   }
37760b57cec5SDimitry Andric   case G_USUBE: {
377706c3fb27SDimitry Andric     auto [Res, BorrowOut, LHS, RHS, BorrowIn] = MI.getFirst5Regs();
37785ffd83dbSDimitry Andric     const LLT CondTy = MRI.getType(BorrowOut);
37795ffd83dbSDimitry Andric     const LLT Ty = MRI.getType(Res);
37800b57cec5SDimitry Andric 
37815f757f3fSDimitry Andric     // Initial subtract of the two operands.
37825ffd83dbSDimitry Andric     auto TmpRes = MIRBuilder.buildSub(Ty, LHS, RHS);
37835f757f3fSDimitry Andric 
37845f757f3fSDimitry Andric     // Initial check for borrow.
37855f757f3fSDimitry Andric     auto Borrow = MIRBuilder.buildICmp(CmpInst::ICMP_UGT, CondTy, TmpRes, LHS);
37865f757f3fSDimitry Andric 
37875f757f3fSDimitry Andric     // Subtract the borrow from the first subtract.
37885ffd83dbSDimitry Andric     auto ZExtBorrowIn = MIRBuilder.buildZExt(Ty, BorrowIn);
37890b57cec5SDimitry Andric     MIRBuilder.buildSub(Res, TmpRes, ZExtBorrowIn);
37905ffd83dbSDimitry Andric 
37915f757f3fSDimitry Andric     // Second check for borrow. We can only borrow if the initial difference is
37925f757f3fSDimitry Andric     // 0 and the borrow is set, resulting in a new difference of all 1s.
37935f757f3fSDimitry Andric     auto Zero = MIRBuilder.buildConstant(Ty, 0);
37945f757f3fSDimitry Andric     auto TmpResEqZero =
37955f757f3fSDimitry Andric         MIRBuilder.buildICmp(CmpInst::ICMP_EQ, CondTy, TmpRes, Zero);
37965f757f3fSDimitry Andric     auto Borrow2 = MIRBuilder.buildAnd(CondTy, TmpResEqZero, BorrowIn);
37975f757f3fSDimitry Andric     MIRBuilder.buildOr(BorrowOut, Borrow, Borrow2);
37980b57cec5SDimitry Andric 
37990b57cec5SDimitry Andric     MI.eraseFromParent();
38000b57cec5SDimitry Andric     return Legalized;
38010b57cec5SDimitry Andric   }
38020b57cec5SDimitry Andric   case G_UITOFP:
3803e8d8bef9SDimitry Andric     return lowerUITOFP(MI);
38040b57cec5SDimitry Andric   case G_SITOFP:
3805e8d8bef9SDimitry Andric     return lowerSITOFP(MI);
38068bcb0991SDimitry Andric   case G_FPTOUI:
3807e8d8bef9SDimitry Andric     return lowerFPTOUI(MI);
38085ffd83dbSDimitry Andric   case G_FPTOSI:
38095ffd83dbSDimitry Andric     return lowerFPTOSI(MI);
38105ffd83dbSDimitry Andric   case G_FPTRUNC:
3811e8d8bef9SDimitry Andric     return lowerFPTRUNC(MI);
3812e8d8bef9SDimitry Andric   case G_FPOWI:
3813e8d8bef9SDimitry Andric     return lowerFPOWI(MI);
38140b57cec5SDimitry Andric   case G_SMIN:
38150b57cec5SDimitry Andric   case G_SMAX:
38160b57cec5SDimitry Andric   case G_UMIN:
38170b57cec5SDimitry Andric   case G_UMAX:
3818e8d8bef9SDimitry Andric     return lowerMinMax(MI);
38190b57cec5SDimitry Andric   case G_FCOPYSIGN:
3820e8d8bef9SDimitry Andric     return lowerFCopySign(MI);
38210b57cec5SDimitry Andric   case G_FMINNUM:
38220b57cec5SDimitry Andric   case G_FMAXNUM:
38230b57cec5SDimitry Andric     return lowerFMinNumMaxNum(MI);
38245ffd83dbSDimitry Andric   case G_MERGE_VALUES:
38255ffd83dbSDimitry Andric     return lowerMergeValues(MI);
38268bcb0991SDimitry Andric   case G_UNMERGE_VALUES:
38278bcb0991SDimitry Andric     return lowerUnmergeValues(MI);
38288bcb0991SDimitry Andric   case TargetOpcode::G_SEXT_INREG: {
38298bcb0991SDimitry Andric     assert(MI.getOperand(2).isImm() && "Expected immediate");
38308bcb0991SDimitry Andric     int64_t SizeInBits = MI.getOperand(2).getImm();
38318bcb0991SDimitry Andric 
383206c3fb27SDimitry Andric     auto [DstReg, SrcReg] = MI.getFirst2Regs();
38338bcb0991SDimitry Andric     LLT DstTy = MRI.getType(DstReg);
38348bcb0991SDimitry Andric     Register TmpRes = MRI.createGenericVirtualRegister(DstTy);
38358bcb0991SDimitry Andric 
38368bcb0991SDimitry Andric     auto MIBSz = MIRBuilder.buildConstant(DstTy, DstTy.getScalarSizeInBits() - SizeInBits);
38375ffd83dbSDimitry Andric     MIRBuilder.buildShl(TmpRes, SrcReg, MIBSz->getOperand(0));
38385ffd83dbSDimitry Andric     MIRBuilder.buildAShr(DstReg, TmpRes, MIBSz->getOperand(0));
38398bcb0991SDimitry Andric     MI.eraseFromParent();
38408bcb0991SDimitry Andric     return Legalized;
38418bcb0991SDimitry Andric   }
3842e8d8bef9SDimitry Andric   case G_EXTRACT_VECTOR_ELT:
3843e8d8bef9SDimitry Andric   case G_INSERT_VECTOR_ELT:
3844e8d8bef9SDimitry Andric     return lowerExtractInsertVectorElt(MI);
38458bcb0991SDimitry Andric   case G_SHUFFLE_VECTOR:
38468bcb0991SDimitry Andric     return lowerShuffleVector(MI);
38478bcb0991SDimitry Andric   case G_DYN_STACKALLOC:
38488bcb0991SDimitry Andric     return lowerDynStackAlloc(MI);
38495f757f3fSDimitry Andric   case G_STACKSAVE:
38505f757f3fSDimitry Andric     return lowerStackSave(MI);
38515f757f3fSDimitry Andric   case G_STACKRESTORE:
38525f757f3fSDimitry Andric     return lowerStackRestore(MI);
38538bcb0991SDimitry Andric   case G_EXTRACT:
38548bcb0991SDimitry Andric     return lowerExtract(MI);
38558bcb0991SDimitry Andric   case G_INSERT:
38568bcb0991SDimitry Andric     return lowerInsert(MI);
3857480093f4SDimitry Andric   case G_BSWAP:
3858480093f4SDimitry Andric     return lowerBswap(MI);
3859480093f4SDimitry Andric   case G_BITREVERSE:
3860480093f4SDimitry Andric     return lowerBitreverse(MI);
3861480093f4SDimitry Andric   case G_READ_REGISTER:
38625ffd83dbSDimitry Andric   case G_WRITE_REGISTER:
38635ffd83dbSDimitry Andric     return lowerReadWriteRegister(MI);
3864e8d8bef9SDimitry Andric   case G_UADDSAT:
3865e8d8bef9SDimitry Andric   case G_USUBSAT: {
3866e8d8bef9SDimitry Andric     // Try to make a reasonable guess about which lowering strategy to use. The
3867e8d8bef9SDimitry Andric     // target can override this with custom lowering and calling the
3868e8d8bef9SDimitry Andric     // implementation functions.
3869e8d8bef9SDimitry Andric     LLT Ty = MRI.getType(MI.getOperand(0).getReg());
3870e8d8bef9SDimitry Andric     if (LI.isLegalOrCustom({G_UMIN, Ty}))
3871e8d8bef9SDimitry Andric       return lowerAddSubSatToMinMax(MI);
3872e8d8bef9SDimitry Andric     return lowerAddSubSatToAddoSubo(MI);
38730b57cec5SDimitry Andric   }
3874e8d8bef9SDimitry Andric   case G_SADDSAT:
3875e8d8bef9SDimitry Andric   case G_SSUBSAT: {
3876e8d8bef9SDimitry Andric     LLT Ty = MRI.getType(MI.getOperand(0).getReg());
3877e8d8bef9SDimitry Andric 
3878e8d8bef9SDimitry Andric     // FIXME: It would probably make more sense to see if G_SADDO is preferred,
3879e8d8bef9SDimitry Andric     // since it's a shorter expansion. However, we would need to figure out the
3880e8d8bef9SDimitry Andric     // preferred boolean type for the carry out for the query.
3881e8d8bef9SDimitry Andric     if (LI.isLegalOrCustom({G_SMIN, Ty}) && LI.isLegalOrCustom({G_SMAX, Ty}))
3882e8d8bef9SDimitry Andric       return lowerAddSubSatToMinMax(MI);
3883e8d8bef9SDimitry Andric     return lowerAddSubSatToAddoSubo(MI);
3884e8d8bef9SDimitry Andric   }
3885e8d8bef9SDimitry Andric   case G_SSHLSAT:
3886e8d8bef9SDimitry Andric   case G_USHLSAT:
3887e8d8bef9SDimitry Andric     return lowerShlSat(MI);
3888fe6060f1SDimitry Andric   case G_ABS:
3889fe6060f1SDimitry Andric     return lowerAbsToAddXor(MI);
3890e8d8bef9SDimitry Andric   case G_SELECT:
3891e8d8bef9SDimitry Andric     return lowerSelect(MI);
3892bdd1243dSDimitry Andric   case G_IS_FPCLASS:
3893bdd1243dSDimitry Andric     return lowerISFPCLASS(MI);
3894fe6060f1SDimitry Andric   case G_SDIVREM:
3895fe6060f1SDimitry Andric   case G_UDIVREM:
3896fe6060f1SDimitry Andric     return lowerDIVREM(MI);
3897fe6060f1SDimitry Andric   case G_FSHL:
3898fe6060f1SDimitry Andric   case G_FSHR:
3899fe6060f1SDimitry Andric     return lowerFunnelShift(MI);
3900fe6060f1SDimitry Andric   case G_ROTL:
3901fe6060f1SDimitry Andric   case G_ROTR:
3902fe6060f1SDimitry Andric     return lowerRotate(MI);
3903349cc55cSDimitry Andric   case G_MEMSET:
3904349cc55cSDimitry Andric   case G_MEMCPY:
3905349cc55cSDimitry Andric   case G_MEMMOVE:
3906349cc55cSDimitry Andric     return lowerMemCpyFamily(MI);
3907349cc55cSDimitry Andric   case G_MEMCPY_INLINE:
3908349cc55cSDimitry Andric     return lowerMemcpyInline(MI);
39095f757f3fSDimitry Andric   case G_ZEXT:
39105f757f3fSDimitry Andric   case G_SEXT:
39115f757f3fSDimitry Andric   case G_ANYEXT:
39125f757f3fSDimitry Andric     return lowerEXT(MI);
39135f757f3fSDimitry Andric   case G_TRUNC:
39145f757f3fSDimitry Andric     return lowerTRUNC(MI);
3915349cc55cSDimitry Andric   GISEL_VECREDUCE_CASES_NONSEQ
3916349cc55cSDimitry Andric     return lowerVectorReduction(MI);
39175f757f3fSDimitry Andric   case G_VAARG:
39185f757f3fSDimitry Andric     return lowerVAArg(MI);
3919e8d8bef9SDimitry Andric   }
3920e8d8bef9SDimitry Andric }
3921e8d8bef9SDimitry Andric 
3922e8d8bef9SDimitry Andric Align LegalizerHelper::getStackTemporaryAlignment(LLT Ty,
3923e8d8bef9SDimitry Andric                                                   Align MinAlign) const {
3924e8d8bef9SDimitry Andric   // FIXME: We're missing a way to go back from LLT to llvm::Type to query the
3925e8d8bef9SDimitry Andric   // datalayout for the preferred alignment. Also there should be a target hook
3926e8d8bef9SDimitry Andric   // for this to allow targets to reduce the alignment and ignore the
3927e8d8bef9SDimitry Andric   // datalayout. e.g. AMDGPU should always use a 4-byte alignment, regardless of
3928e8d8bef9SDimitry Andric   // the type.
3929e8d8bef9SDimitry Andric   return std::max(Align(PowerOf2Ceil(Ty.getSizeInBytes())), MinAlign);
3930e8d8bef9SDimitry Andric }
3931e8d8bef9SDimitry Andric 
3932e8d8bef9SDimitry Andric MachineInstrBuilder
3933e8d8bef9SDimitry Andric LegalizerHelper::createStackTemporary(TypeSize Bytes, Align Alignment,
3934e8d8bef9SDimitry Andric                                       MachinePointerInfo &PtrInfo) {
3935e8d8bef9SDimitry Andric   MachineFunction &MF = MIRBuilder.getMF();
3936e8d8bef9SDimitry Andric   const DataLayout &DL = MIRBuilder.getDataLayout();
3937e8d8bef9SDimitry Andric   int FrameIdx = MF.getFrameInfo().CreateStackObject(Bytes, Alignment, false);
3938e8d8bef9SDimitry Andric 
3939e8d8bef9SDimitry Andric   unsigned AddrSpace = DL.getAllocaAddrSpace();
3940e8d8bef9SDimitry Andric   LLT FramePtrTy = LLT::pointer(AddrSpace, DL.getPointerSizeInBits(AddrSpace));
3941e8d8bef9SDimitry Andric 
3942e8d8bef9SDimitry Andric   PtrInfo = MachinePointerInfo::getFixedStack(MF, FrameIdx);
3943e8d8bef9SDimitry Andric   return MIRBuilder.buildFrameIndex(FramePtrTy, FrameIdx);
3944e8d8bef9SDimitry Andric }
3945e8d8bef9SDimitry Andric 
3946e8d8bef9SDimitry Andric static Register clampDynamicVectorIndex(MachineIRBuilder &B, Register IdxReg,
3947e8d8bef9SDimitry Andric                                         LLT VecTy) {
3948e8d8bef9SDimitry Andric   int64_t IdxVal;
3949e8d8bef9SDimitry Andric   if (mi_match(IdxReg, *B.getMRI(), m_ICst(IdxVal)))
3950e8d8bef9SDimitry Andric     return IdxReg;
3951e8d8bef9SDimitry Andric 
3952e8d8bef9SDimitry Andric   LLT IdxTy = B.getMRI()->getType(IdxReg);
3953e8d8bef9SDimitry Andric   unsigned NElts = VecTy.getNumElements();
3954e8d8bef9SDimitry Andric   if (isPowerOf2_32(NElts)) {
3955e8d8bef9SDimitry Andric     APInt Imm = APInt::getLowBitsSet(IdxTy.getSizeInBits(), Log2_32(NElts));
3956e8d8bef9SDimitry Andric     return B.buildAnd(IdxTy, IdxReg, B.buildConstant(IdxTy, Imm)).getReg(0);
3957e8d8bef9SDimitry Andric   }
3958e8d8bef9SDimitry Andric 
3959e8d8bef9SDimitry Andric   return B.buildUMin(IdxTy, IdxReg, B.buildConstant(IdxTy, NElts - 1))
3960e8d8bef9SDimitry Andric       .getReg(0);
3961e8d8bef9SDimitry Andric }
3962e8d8bef9SDimitry Andric 
3963e8d8bef9SDimitry Andric Register LegalizerHelper::getVectorElementPointer(Register VecPtr, LLT VecTy,
3964e8d8bef9SDimitry Andric                                                   Register Index) {
3965e8d8bef9SDimitry Andric   LLT EltTy = VecTy.getElementType();
3966e8d8bef9SDimitry Andric 
3967e8d8bef9SDimitry Andric   // Calculate the element offset and add it to the pointer.
3968e8d8bef9SDimitry Andric   unsigned EltSize = EltTy.getSizeInBits() / 8; // FIXME: should be ABI size.
3969e8d8bef9SDimitry Andric   assert(EltSize * 8 == EltTy.getSizeInBits() &&
3970e8d8bef9SDimitry Andric          "Converting bits to bytes lost precision");
3971e8d8bef9SDimitry Andric 
3972e8d8bef9SDimitry Andric   Index = clampDynamicVectorIndex(MIRBuilder, Index, VecTy);
3973e8d8bef9SDimitry Andric 
3974e8d8bef9SDimitry Andric   LLT IdxTy = MRI.getType(Index);
3975e8d8bef9SDimitry Andric   auto Mul = MIRBuilder.buildMul(IdxTy, Index,
3976e8d8bef9SDimitry Andric                                  MIRBuilder.buildConstant(IdxTy, EltSize));
3977e8d8bef9SDimitry Andric 
3978e8d8bef9SDimitry Andric   LLT PtrTy = MRI.getType(VecPtr);
3979e8d8bef9SDimitry Andric   return MIRBuilder.buildPtrAdd(PtrTy, VecPtr, Mul).getReg(0);
39800b57cec5SDimitry Andric }
39810b57cec5SDimitry Andric 
39820eae32dcSDimitry Andric #ifndef NDEBUG
39830eae32dcSDimitry Andric /// Check that all vector operands have same number of elements. Other operands
39840eae32dcSDimitry Andric /// should be listed in NonVecOp.
39850eae32dcSDimitry Andric static bool hasSameNumEltsOnAllVectorOperands(
39860eae32dcSDimitry Andric     GenericMachineInstr &MI, MachineRegisterInfo &MRI,
39870eae32dcSDimitry Andric     std::initializer_list<unsigned> NonVecOpIndices) {
39880eae32dcSDimitry Andric   if (MI.getNumMemOperands() != 0)
39890eae32dcSDimitry Andric     return false;
39900b57cec5SDimitry Andric 
39910eae32dcSDimitry Andric   LLT VecTy = MRI.getType(MI.getReg(0));
39920eae32dcSDimitry Andric   if (!VecTy.isVector())
39930eae32dcSDimitry Andric     return false;
39940eae32dcSDimitry Andric   unsigned NumElts = VecTy.getNumElements();
39950b57cec5SDimitry Andric 
39960eae32dcSDimitry Andric   for (unsigned OpIdx = 1; OpIdx < MI.getNumOperands(); ++OpIdx) {
39970eae32dcSDimitry Andric     MachineOperand &Op = MI.getOperand(OpIdx);
39980eae32dcSDimitry Andric     if (!Op.isReg()) {
39990eae32dcSDimitry Andric       if (!is_contained(NonVecOpIndices, OpIdx))
40000eae32dcSDimitry Andric         return false;
40010eae32dcSDimitry Andric       continue;
40020eae32dcSDimitry Andric     }
40030b57cec5SDimitry Andric 
40040eae32dcSDimitry Andric     LLT Ty = MRI.getType(Op.getReg());
40050eae32dcSDimitry Andric     if (!Ty.isVector()) {
40060eae32dcSDimitry Andric       if (!is_contained(NonVecOpIndices, OpIdx))
40070eae32dcSDimitry Andric         return false;
40080eae32dcSDimitry Andric       continue;
40090eae32dcSDimitry Andric     }
40100eae32dcSDimitry Andric 
40110eae32dcSDimitry Andric     if (Ty.getNumElements() != NumElts)
40120eae32dcSDimitry Andric       return false;
40130eae32dcSDimitry Andric   }
40140eae32dcSDimitry Andric 
40150eae32dcSDimitry Andric   return true;
40160eae32dcSDimitry Andric }
40170eae32dcSDimitry Andric #endif
40180eae32dcSDimitry Andric 
40190eae32dcSDimitry Andric /// Fill \p DstOps with DstOps that have same number of elements combined as
40200eae32dcSDimitry Andric /// the Ty. These DstOps have either scalar type when \p NumElts = 1 or are
40210eae32dcSDimitry Andric /// vectors with \p NumElts elements. When Ty.getNumElements() is not multiple
40220eae32dcSDimitry Andric /// of \p NumElts last DstOp (leftover) has fewer then \p NumElts elements.
40230eae32dcSDimitry Andric static void makeDstOps(SmallVectorImpl<DstOp> &DstOps, LLT Ty,
40240eae32dcSDimitry Andric                        unsigned NumElts) {
40250eae32dcSDimitry Andric   LLT LeftoverTy;
40260eae32dcSDimitry Andric   assert(Ty.isVector() && "Expected vector type");
40270eae32dcSDimitry Andric   LLT EltTy = Ty.getElementType();
40280eae32dcSDimitry Andric   LLT NarrowTy = (NumElts == 1) ? EltTy : LLT::fixed_vector(NumElts, EltTy);
40290eae32dcSDimitry Andric   int NumParts, NumLeftover;
40300eae32dcSDimitry Andric   std::tie(NumParts, NumLeftover) =
40310eae32dcSDimitry Andric       getNarrowTypeBreakDown(Ty, NarrowTy, LeftoverTy);
40320eae32dcSDimitry Andric 
40330eae32dcSDimitry Andric   assert(NumParts > 0 && "Error in getNarrowTypeBreakDown");
40340eae32dcSDimitry Andric   for (int i = 0; i < NumParts; ++i) {
40350eae32dcSDimitry Andric     DstOps.push_back(NarrowTy);
40360eae32dcSDimitry Andric   }
40370eae32dcSDimitry Andric 
40380eae32dcSDimitry Andric   if (LeftoverTy.isValid()) {
40390eae32dcSDimitry Andric     assert(NumLeftover == 1 && "expected exactly one leftover");
40400eae32dcSDimitry Andric     DstOps.push_back(LeftoverTy);
40410eae32dcSDimitry Andric   }
40420eae32dcSDimitry Andric }
40430eae32dcSDimitry Andric 
40440eae32dcSDimitry Andric /// Operand \p Op is used on \p N sub-instructions. Fill \p Ops with \p N SrcOps
40450eae32dcSDimitry Andric /// made from \p Op depending on operand type.
40460eae32dcSDimitry Andric static void broadcastSrcOp(SmallVectorImpl<SrcOp> &Ops, unsigned N,
40470eae32dcSDimitry Andric                            MachineOperand &Op) {
40480eae32dcSDimitry Andric   for (unsigned i = 0; i < N; ++i) {
40490eae32dcSDimitry Andric     if (Op.isReg())
40500eae32dcSDimitry Andric       Ops.push_back(Op.getReg());
40510eae32dcSDimitry Andric     else if (Op.isImm())
40520eae32dcSDimitry Andric       Ops.push_back(Op.getImm());
40530eae32dcSDimitry Andric     else if (Op.isPredicate())
40540eae32dcSDimitry Andric       Ops.push_back(static_cast<CmpInst::Predicate>(Op.getPredicate()));
40550eae32dcSDimitry Andric     else
40560eae32dcSDimitry Andric       llvm_unreachable("Unsupported type");
40570eae32dcSDimitry Andric   }
40580b57cec5SDimitry Andric }
40590b57cec5SDimitry Andric 
40600b57cec5SDimitry Andric // Handle splitting vector operations which need to have the same number of
40610b57cec5SDimitry Andric // elements in each type index, but each type index may have a different element
40620b57cec5SDimitry Andric // type.
40630b57cec5SDimitry Andric //
40640b57cec5SDimitry Andric // e.g.  <4 x s64> = G_SHL <4 x s64>, <4 x s32> ->
40650b57cec5SDimitry Andric //       <2 x s64> = G_SHL <2 x s64>, <2 x s32>
40660b57cec5SDimitry Andric //       <2 x s64> = G_SHL <2 x s64>, <2 x s32>
40670b57cec5SDimitry Andric //
40680b57cec5SDimitry Andric // Also handles some irregular breakdown cases, e.g.
40690b57cec5SDimitry Andric // e.g.  <3 x s64> = G_SHL <3 x s64>, <3 x s32> ->
40700b57cec5SDimitry Andric //       <2 x s64> = G_SHL <2 x s64>, <2 x s32>
40710b57cec5SDimitry Andric //             s64 = G_SHL s64, s32
40720b57cec5SDimitry Andric LegalizerHelper::LegalizeResult
40730b57cec5SDimitry Andric LegalizerHelper::fewerElementsVectorMultiEltType(
40740eae32dcSDimitry Andric     GenericMachineInstr &MI, unsigned NumElts,
40750eae32dcSDimitry Andric     std::initializer_list<unsigned> NonVecOpIndices) {
40760eae32dcSDimitry Andric   assert(hasSameNumEltsOnAllVectorOperands(MI, MRI, NonVecOpIndices) &&
40770eae32dcSDimitry Andric          "Non-compatible opcode or not specified non-vector operands");
40780eae32dcSDimitry Andric   unsigned OrigNumElts = MRI.getType(MI.getReg(0)).getNumElements();
40790b57cec5SDimitry Andric 
40800eae32dcSDimitry Andric   unsigned NumInputs = MI.getNumOperands() - MI.getNumDefs();
40810eae32dcSDimitry Andric   unsigned NumDefs = MI.getNumDefs();
40820b57cec5SDimitry Andric 
40830eae32dcSDimitry Andric   // Create DstOps (sub-vectors with NumElts elts + Leftover) for each output.
40840eae32dcSDimitry Andric   // Build instructions with DstOps to use instruction found by CSE directly.
40850eae32dcSDimitry Andric   // CSE copies found instruction into given vreg when building with vreg dest.
40860eae32dcSDimitry Andric   SmallVector<SmallVector<DstOp, 8>, 2> OutputOpsPieces(NumDefs);
40870eae32dcSDimitry Andric   // Output registers will be taken from created instructions.
40880eae32dcSDimitry Andric   SmallVector<SmallVector<Register, 8>, 2> OutputRegs(NumDefs);
40890eae32dcSDimitry Andric   for (unsigned i = 0; i < NumDefs; ++i) {
40900eae32dcSDimitry Andric     makeDstOps(OutputOpsPieces[i], MRI.getType(MI.getReg(i)), NumElts);
40910b57cec5SDimitry Andric   }
40920b57cec5SDimitry Andric 
40930eae32dcSDimitry Andric   // Split vector input operands into sub-vectors with NumElts elts + Leftover.
40940eae32dcSDimitry Andric   // Operands listed in NonVecOpIndices will be used as is without splitting;
40950eae32dcSDimitry Andric   // examples: compare predicate in icmp and fcmp (op 1), vector select with i1
40960eae32dcSDimitry Andric   // scalar condition (op 1), immediate in sext_inreg (op 2).
40970eae32dcSDimitry Andric   SmallVector<SmallVector<SrcOp, 8>, 3> InputOpsPieces(NumInputs);
40980eae32dcSDimitry Andric   for (unsigned UseIdx = NumDefs, UseNo = 0; UseIdx < MI.getNumOperands();
40990eae32dcSDimitry Andric        ++UseIdx, ++UseNo) {
41000eae32dcSDimitry Andric     if (is_contained(NonVecOpIndices, UseIdx)) {
41010eae32dcSDimitry Andric       broadcastSrcOp(InputOpsPieces[UseNo], OutputOpsPieces[0].size(),
41020eae32dcSDimitry Andric                      MI.getOperand(UseIdx));
41030b57cec5SDimitry Andric     } else {
41040eae32dcSDimitry Andric       SmallVector<Register, 8> SplitPieces;
4105*7a6dacacSDimitry Andric       extractVectorParts(MI.getReg(UseIdx), NumElts, SplitPieces, MIRBuilder,
4106*7a6dacacSDimitry Andric                          MRI);
41070eae32dcSDimitry Andric       for (auto Reg : SplitPieces)
41080eae32dcSDimitry Andric         InputOpsPieces[UseNo].push_back(Reg);
41090eae32dcSDimitry Andric     }
41100b57cec5SDimitry Andric   }
41110b57cec5SDimitry Andric 
41120eae32dcSDimitry Andric   unsigned NumLeftovers = OrigNumElts % NumElts ? 1 : 0;
41130eae32dcSDimitry Andric 
41140eae32dcSDimitry Andric   // Take i-th piece of each input operand split and build sub-vector/scalar
41150eae32dcSDimitry Andric   // instruction. Set i-th DstOp(s) from OutputOpsPieces as destination(s).
41160eae32dcSDimitry Andric   for (unsigned i = 0; i < OrigNumElts / NumElts + NumLeftovers; ++i) {
41170eae32dcSDimitry Andric     SmallVector<DstOp, 2> Defs;
41180eae32dcSDimitry Andric     for (unsigned DstNo = 0; DstNo < NumDefs; ++DstNo)
41190eae32dcSDimitry Andric       Defs.push_back(OutputOpsPieces[DstNo][i]);
41200eae32dcSDimitry Andric 
41210eae32dcSDimitry Andric     SmallVector<SrcOp, 3> Uses;
41220eae32dcSDimitry Andric     for (unsigned InputNo = 0; InputNo < NumInputs; ++InputNo)
41230eae32dcSDimitry Andric       Uses.push_back(InputOpsPieces[InputNo][i]);
41240eae32dcSDimitry Andric 
41250eae32dcSDimitry Andric     auto I = MIRBuilder.buildInstr(MI.getOpcode(), Defs, Uses, MI.getFlags());
41260eae32dcSDimitry Andric     for (unsigned DstNo = 0; DstNo < NumDefs; ++DstNo)
41270eae32dcSDimitry Andric       OutputRegs[DstNo].push_back(I.getReg(DstNo));
41280b57cec5SDimitry Andric   }
41290b57cec5SDimitry Andric 
41300eae32dcSDimitry Andric   // Merge small outputs into MI's output for each def operand.
41310eae32dcSDimitry Andric   if (NumLeftovers) {
41320eae32dcSDimitry Andric     for (unsigned i = 0; i < NumDefs; ++i)
41330eae32dcSDimitry Andric       mergeMixedSubvectors(MI.getReg(i), OutputRegs[i]);
41340eae32dcSDimitry Andric   } else {
41350eae32dcSDimitry Andric     for (unsigned i = 0; i < NumDefs; ++i)
4136bdd1243dSDimitry Andric       MIRBuilder.buildMergeLikeInstr(MI.getReg(i), OutputRegs[i]);
41370eae32dcSDimitry Andric   }
41380b57cec5SDimitry Andric 
41390b57cec5SDimitry Andric   MI.eraseFromParent();
41400b57cec5SDimitry Andric   return Legalized;
41410b57cec5SDimitry Andric }
41420b57cec5SDimitry Andric 
41430b57cec5SDimitry Andric LegalizerHelper::LegalizeResult
41440eae32dcSDimitry Andric LegalizerHelper::fewerElementsVectorPhi(GenericMachineInstr &MI,
41450eae32dcSDimitry Andric                                         unsigned NumElts) {
41460eae32dcSDimitry Andric   unsigned OrigNumElts = MRI.getType(MI.getReg(0)).getNumElements();
41470b57cec5SDimitry Andric 
41480eae32dcSDimitry Andric   unsigned NumInputs = MI.getNumOperands() - MI.getNumDefs();
41490eae32dcSDimitry Andric   unsigned NumDefs = MI.getNumDefs();
41500b57cec5SDimitry Andric 
41510eae32dcSDimitry Andric   SmallVector<DstOp, 8> OutputOpsPieces;
41520eae32dcSDimitry Andric   SmallVector<Register, 8> OutputRegs;
41530eae32dcSDimitry Andric   makeDstOps(OutputOpsPieces, MRI.getType(MI.getReg(0)), NumElts);
41540b57cec5SDimitry Andric 
41550eae32dcSDimitry Andric   // Instructions that perform register split will be inserted in basic block
41560eae32dcSDimitry Andric   // where register is defined (basic block is in the next operand).
41570eae32dcSDimitry Andric   SmallVector<SmallVector<Register, 8>, 3> InputOpsPieces(NumInputs / 2);
41580eae32dcSDimitry Andric   for (unsigned UseIdx = NumDefs, UseNo = 0; UseIdx < MI.getNumOperands();
41590eae32dcSDimitry Andric        UseIdx += 2, ++UseNo) {
41600eae32dcSDimitry Andric     MachineBasicBlock &OpMBB = *MI.getOperand(UseIdx + 1).getMBB();
4161bdd1243dSDimitry Andric     MIRBuilder.setInsertPt(OpMBB, OpMBB.getFirstTerminatorForward());
4162*7a6dacacSDimitry Andric     extractVectorParts(MI.getReg(UseIdx), NumElts, InputOpsPieces[UseNo],
4163*7a6dacacSDimitry Andric                        MIRBuilder, MRI);
41640b57cec5SDimitry Andric   }
41650eae32dcSDimitry Andric 
41660eae32dcSDimitry Andric   // Build PHIs with fewer elements.
41670eae32dcSDimitry Andric   unsigned NumLeftovers = OrigNumElts % NumElts ? 1 : 0;
41680eae32dcSDimitry Andric   MIRBuilder.setInsertPt(*MI.getParent(), MI);
41690eae32dcSDimitry Andric   for (unsigned i = 0; i < OrigNumElts / NumElts + NumLeftovers; ++i) {
41700eae32dcSDimitry Andric     auto Phi = MIRBuilder.buildInstr(TargetOpcode::G_PHI);
41710eae32dcSDimitry Andric     Phi.addDef(
41720eae32dcSDimitry Andric         MRI.createGenericVirtualRegister(OutputOpsPieces[i].getLLTTy(MRI)));
41730eae32dcSDimitry Andric     OutputRegs.push_back(Phi.getReg(0));
41740eae32dcSDimitry Andric 
41750eae32dcSDimitry Andric     for (unsigned j = 0; j < NumInputs / 2; ++j) {
41760eae32dcSDimitry Andric       Phi.addUse(InputOpsPieces[j][i]);
41770eae32dcSDimitry Andric       Phi.add(MI.getOperand(1 + j * 2 + 1));
41780eae32dcSDimitry Andric     }
41790eae32dcSDimitry Andric   }
41800eae32dcSDimitry Andric 
41810eae32dcSDimitry Andric   // Merge small outputs into MI's def.
41820eae32dcSDimitry Andric   if (NumLeftovers) {
41830eae32dcSDimitry Andric     mergeMixedSubvectors(MI.getReg(0), OutputRegs);
41840eae32dcSDimitry Andric   } else {
4185bdd1243dSDimitry Andric     MIRBuilder.buildMergeLikeInstr(MI.getReg(0), OutputRegs);
41860b57cec5SDimitry Andric   }
41870b57cec5SDimitry Andric 
41880b57cec5SDimitry Andric   MI.eraseFromParent();
41890b57cec5SDimitry Andric   return Legalized;
41900b57cec5SDimitry Andric }
41910b57cec5SDimitry Andric 
41920b57cec5SDimitry Andric LegalizerHelper::LegalizeResult
41938bcb0991SDimitry Andric LegalizerHelper::fewerElementsVectorUnmergeValues(MachineInstr &MI,
41948bcb0991SDimitry Andric                                                   unsigned TypeIdx,
41958bcb0991SDimitry Andric                                                   LLT NarrowTy) {
41968bcb0991SDimitry Andric   const int NumDst = MI.getNumOperands() - 1;
41978bcb0991SDimitry Andric   const Register SrcReg = MI.getOperand(NumDst).getReg();
41980eae32dcSDimitry Andric   LLT DstTy = MRI.getType(MI.getOperand(0).getReg());
41998bcb0991SDimitry Andric   LLT SrcTy = MRI.getType(SrcReg);
42008bcb0991SDimitry Andric 
42010eae32dcSDimitry Andric   if (TypeIdx != 1 || NarrowTy == DstTy)
42028bcb0991SDimitry Andric     return UnableToLegalize;
42038bcb0991SDimitry Andric 
42040eae32dcSDimitry Andric   // Requires compatible types. Otherwise SrcReg should have been defined by
42050eae32dcSDimitry Andric   // merge-like instruction that would get artifact combined. Most likely
42060eae32dcSDimitry Andric   // instruction that defines SrcReg has to perform more/fewer elements
42070eae32dcSDimitry Andric   // legalization compatible with NarrowTy.
42080eae32dcSDimitry Andric   assert(SrcTy.isVector() && NarrowTy.isVector() && "Expected vector types");
42090eae32dcSDimitry Andric   assert((SrcTy.getScalarType() == NarrowTy.getScalarType()) && "bad type");
42108bcb0991SDimitry Andric 
42110eae32dcSDimitry Andric   if ((SrcTy.getSizeInBits() % NarrowTy.getSizeInBits() != 0) ||
42120eae32dcSDimitry Andric       (NarrowTy.getSizeInBits() % DstTy.getSizeInBits() != 0))
42130eae32dcSDimitry Andric     return UnableToLegalize;
42140eae32dcSDimitry Andric 
42150eae32dcSDimitry Andric   // This is most likely DstTy (smaller then register size) packed in SrcTy
42160eae32dcSDimitry Andric   // (larger then register size) and since unmerge was not combined it will be
42170eae32dcSDimitry Andric   // lowered to bit sequence extracts from register. Unpack SrcTy to NarrowTy
42180eae32dcSDimitry Andric   // (register size) pieces first. Then unpack each of NarrowTy pieces to DstTy.
42190eae32dcSDimitry Andric 
42200eae32dcSDimitry Andric   // %1:_(DstTy), %2, %3, %4 = G_UNMERGE_VALUES %0:_(SrcTy)
42210eae32dcSDimitry Andric   //
42220eae32dcSDimitry Andric   // %5:_(NarrowTy), %6 = G_UNMERGE_VALUES %0:_(SrcTy) - reg sequence
42230eae32dcSDimitry Andric   // %1:_(DstTy), %2 = G_UNMERGE_VALUES %5:_(NarrowTy) - sequence of bits in reg
42240eae32dcSDimitry Andric   // %3:_(DstTy), %4 = G_UNMERGE_VALUES %6:_(NarrowTy)
42250eae32dcSDimitry Andric   auto Unmerge = MIRBuilder.buildUnmerge(NarrowTy, SrcReg);
42268bcb0991SDimitry Andric   const int NumUnmerge = Unmerge->getNumOperands() - 1;
42278bcb0991SDimitry Andric   const int PartsPerUnmerge = NumDst / NumUnmerge;
42288bcb0991SDimitry Andric 
42298bcb0991SDimitry Andric   for (int I = 0; I != NumUnmerge; ++I) {
42308bcb0991SDimitry Andric     auto MIB = MIRBuilder.buildInstr(TargetOpcode::G_UNMERGE_VALUES);
42318bcb0991SDimitry Andric 
42328bcb0991SDimitry Andric     for (int J = 0; J != PartsPerUnmerge; ++J)
42338bcb0991SDimitry Andric       MIB.addDef(MI.getOperand(I * PartsPerUnmerge + J).getReg());
42348bcb0991SDimitry Andric     MIB.addUse(Unmerge.getReg(I));
42358bcb0991SDimitry Andric   }
42368bcb0991SDimitry Andric 
42378bcb0991SDimitry Andric   MI.eraseFromParent();
42388bcb0991SDimitry Andric   return Legalized;
42398bcb0991SDimitry Andric }
42408bcb0991SDimitry Andric 
4241fe6060f1SDimitry Andric LegalizerHelper::LegalizeResult
4242e8d8bef9SDimitry Andric LegalizerHelper::fewerElementsVectorMerge(MachineInstr &MI, unsigned TypeIdx,
4243e8d8bef9SDimitry Andric                                           LLT NarrowTy) {
424406c3fb27SDimitry Andric   auto [DstReg, DstTy, SrcReg, SrcTy] = MI.getFirst2RegLLTs();
42450eae32dcSDimitry Andric   // Requires compatible types. Otherwise user of DstReg did not perform unmerge
42460eae32dcSDimitry Andric   // that should have been artifact combined. Most likely instruction that uses
42470eae32dcSDimitry Andric   // DstReg has to do more/fewer elements legalization compatible with NarrowTy.
42480eae32dcSDimitry Andric   assert(DstTy.isVector() && NarrowTy.isVector() && "Expected vector types");
42490eae32dcSDimitry Andric   assert((DstTy.getScalarType() == NarrowTy.getScalarType()) && "bad type");
42500eae32dcSDimitry Andric   if (NarrowTy == SrcTy)
42510eae32dcSDimitry Andric     return UnableToLegalize;
42528bcb0991SDimitry Andric 
42530eae32dcSDimitry Andric   // This attempts to lower part of LCMTy merge/unmerge sequence. Intended use
42540eae32dcSDimitry Andric   // is for old mir tests. Since the changes to more/fewer elements it should no
42550eae32dcSDimitry Andric   // longer be possible to generate MIR like this when starting from llvm-ir
42560eae32dcSDimitry Andric   // because LCMTy approach was replaced with merge/unmerge to vector elements.
42570eae32dcSDimitry Andric   if (TypeIdx == 1) {
42580eae32dcSDimitry Andric     assert(SrcTy.isVector() && "Expected vector types");
42590eae32dcSDimitry Andric     assert((SrcTy.getScalarType() == NarrowTy.getScalarType()) && "bad type");
42600eae32dcSDimitry Andric     if ((DstTy.getSizeInBits() % NarrowTy.getSizeInBits() != 0) ||
42610eae32dcSDimitry Andric         (NarrowTy.getNumElements() >= SrcTy.getNumElements()))
42620eae32dcSDimitry Andric       return UnableToLegalize;
42630eae32dcSDimitry Andric     // %2:_(DstTy) = G_CONCAT_VECTORS %0:_(SrcTy), %1:_(SrcTy)
42640eae32dcSDimitry Andric     //
42650eae32dcSDimitry Andric     // %3:_(EltTy), %4, %5 = G_UNMERGE_VALUES %0:_(SrcTy)
42660eae32dcSDimitry Andric     // %6:_(EltTy), %7, %8 = G_UNMERGE_VALUES %1:_(SrcTy)
42670eae32dcSDimitry Andric     // %9:_(NarrowTy) = G_BUILD_VECTOR %3:_(EltTy), %4
42680eae32dcSDimitry Andric     // %10:_(NarrowTy) = G_BUILD_VECTOR %5:_(EltTy), %6
42690eae32dcSDimitry Andric     // %11:_(NarrowTy) = G_BUILD_VECTOR %7:_(EltTy), %8
42700eae32dcSDimitry Andric     // %2:_(DstTy) = G_CONCAT_VECTORS %9:_(NarrowTy), %10, %11
4271e8d8bef9SDimitry Andric 
42720eae32dcSDimitry Andric     SmallVector<Register, 8> Elts;
42730eae32dcSDimitry Andric     LLT EltTy = MRI.getType(MI.getOperand(1).getReg()).getScalarType();
42740eae32dcSDimitry Andric     for (unsigned i = 1; i < MI.getNumOperands(); ++i) {
42750eae32dcSDimitry Andric       auto Unmerge = MIRBuilder.buildUnmerge(EltTy, MI.getOperand(i).getReg());
42760eae32dcSDimitry Andric       for (unsigned j = 0; j < Unmerge->getNumDefs(); ++j)
42770eae32dcSDimitry Andric         Elts.push_back(Unmerge.getReg(j));
42780eae32dcSDimitry Andric     }
4279e8d8bef9SDimitry Andric 
42800eae32dcSDimitry Andric     SmallVector<Register, 8> NarrowTyElts;
42810eae32dcSDimitry Andric     unsigned NumNarrowTyElts = NarrowTy.getNumElements();
42820eae32dcSDimitry Andric     unsigned NumNarrowTyPieces = DstTy.getNumElements() / NumNarrowTyElts;
42830eae32dcSDimitry Andric     for (unsigned i = 0, Offset = 0; i < NumNarrowTyPieces;
42840eae32dcSDimitry Andric          ++i, Offset += NumNarrowTyElts) {
42850eae32dcSDimitry Andric       ArrayRef<Register> Pieces(&Elts[Offset], NumNarrowTyElts);
4286bdd1243dSDimitry Andric       NarrowTyElts.push_back(
4287bdd1243dSDimitry Andric           MIRBuilder.buildMergeLikeInstr(NarrowTy, Pieces).getReg(0));
42880eae32dcSDimitry Andric     }
4289e8d8bef9SDimitry Andric 
4290bdd1243dSDimitry Andric     MIRBuilder.buildMergeLikeInstr(DstReg, NarrowTyElts);
42910eae32dcSDimitry Andric     MI.eraseFromParent();
42920eae32dcSDimitry Andric     return Legalized;
42930eae32dcSDimitry Andric   }
42940eae32dcSDimitry Andric 
42950eae32dcSDimitry Andric   assert(TypeIdx == 0 && "Bad type index");
42960eae32dcSDimitry Andric   if ((NarrowTy.getSizeInBits() % SrcTy.getSizeInBits() != 0) ||
42970eae32dcSDimitry Andric       (DstTy.getSizeInBits() % NarrowTy.getSizeInBits() != 0))
42980eae32dcSDimitry Andric     return UnableToLegalize;
42990eae32dcSDimitry Andric 
43000eae32dcSDimitry Andric   // This is most likely SrcTy (smaller then register size) packed in DstTy
43010eae32dcSDimitry Andric   // (larger then register size) and since merge was not combined it will be
43020eae32dcSDimitry Andric   // lowered to bit sequence packing into register. Merge SrcTy to NarrowTy
43030eae32dcSDimitry Andric   // (register size) pieces first. Then merge each of NarrowTy pieces to DstTy.
43040eae32dcSDimitry Andric 
43050eae32dcSDimitry Andric   // %0:_(DstTy) = G_MERGE_VALUES %1:_(SrcTy), %2, %3, %4
43060eae32dcSDimitry Andric   //
43070eae32dcSDimitry Andric   // %5:_(NarrowTy) = G_MERGE_VALUES %1:_(SrcTy), %2 - sequence of bits in reg
43080eae32dcSDimitry Andric   // %6:_(NarrowTy) = G_MERGE_VALUES %3:_(SrcTy), %4
43090eae32dcSDimitry Andric   // %0:_(DstTy)  = G_MERGE_VALUES %5:_(NarrowTy), %6 - reg sequence
43100eae32dcSDimitry Andric   SmallVector<Register, 8> NarrowTyElts;
43110eae32dcSDimitry Andric   unsigned NumParts = DstTy.getNumElements() / NarrowTy.getNumElements();
43120eae32dcSDimitry Andric   unsigned NumSrcElts = SrcTy.isVector() ? SrcTy.getNumElements() : 1;
43130eae32dcSDimitry Andric   unsigned NumElts = NarrowTy.getNumElements() / NumSrcElts;
43140eae32dcSDimitry Andric   for (unsigned i = 0; i < NumParts; ++i) {
43150eae32dcSDimitry Andric     SmallVector<Register, 8> Sources;
43160eae32dcSDimitry Andric     for (unsigned j = 0; j < NumElts; ++j)
43170eae32dcSDimitry Andric       Sources.push_back(MI.getOperand(1 + i * NumElts + j).getReg());
4318bdd1243dSDimitry Andric     NarrowTyElts.push_back(
4319bdd1243dSDimitry Andric         MIRBuilder.buildMergeLikeInstr(NarrowTy, Sources).getReg(0));
43200eae32dcSDimitry Andric   }
43210eae32dcSDimitry Andric 
4322bdd1243dSDimitry Andric   MIRBuilder.buildMergeLikeInstr(DstReg, NarrowTyElts);
4323e8d8bef9SDimitry Andric   MI.eraseFromParent();
4324e8d8bef9SDimitry Andric   return Legalized;
43258bcb0991SDimitry Andric }
43268bcb0991SDimitry Andric 
4327e8d8bef9SDimitry Andric LegalizerHelper::LegalizeResult
4328e8d8bef9SDimitry Andric LegalizerHelper::fewerElementsVectorExtractInsertVectorElt(MachineInstr &MI,
4329e8d8bef9SDimitry Andric                                                            unsigned TypeIdx,
4330e8d8bef9SDimitry Andric                                                            LLT NarrowVecTy) {
433106c3fb27SDimitry Andric   auto [DstReg, SrcVec] = MI.getFirst2Regs();
4332e8d8bef9SDimitry Andric   Register InsertVal;
4333e8d8bef9SDimitry Andric   bool IsInsert = MI.getOpcode() == TargetOpcode::G_INSERT_VECTOR_ELT;
4334e8d8bef9SDimitry Andric 
4335e8d8bef9SDimitry Andric   assert((IsInsert ? TypeIdx == 0 : TypeIdx == 1) && "not a vector type index");
4336e8d8bef9SDimitry Andric   if (IsInsert)
4337e8d8bef9SDimitry Andric     InsertVal = MI.getOperand(2).getReg();
4338e8d8bef9SDimitry Andric 
4339e8d8bef9SDimitry Andric   Register Idx = MI.getOperand(MI.getNumOperands() - 1).getReg();
4340e8d8bef9SDimitry Andric 
4341e8d8bef9SDimitry Andric   // TODO: Handle total scalarization case.
4342e8d8bef9SDimitry Andric   if (!NarrowVecTy.isVector())
4343e8d8bef9SDimitry Andric     return UnableToLegalize;
4344e8d8bef9SDimitry Andric 
4345e8d8bef9SDimitry Andric   LLT VecTy = MRI.getType(SrcVec);
4346e8d8bef9SDimitry Andric 
4347e8d8bef9SDimitry Andric   // If the index is a constant, we can really break this down as you would
4348e8d8bef9SDimitry Andric   // expect, and index into the target size pieces.
4349e8d8bef9SDimitry Andric   int64_t IdxVal;
4350349cc55cSDimitry Andric   auto MaybeCst = getIConstantVRegValWithLookThrough(Idx, MRI);
4351fe6060f1SDimitry Andric   if (MaybeCst) {
4352fe6060f1SDimitry Andric     IdxVal = MaybeCst->Value.getSExtValue();
4353e8d8bef9SDimitry Andric     // Avoid out of bounds indexing the pieces.
4354e8d8bef9SDimitry Andric     if (IdxVal >= VecTy.getNumElements()) {
4355e8d8bef9SDimitry Andric       MIRBuilder.buildUndef(DstReg);
4356e8d8bef9SDimitry Andric       MI.eraseFromParent();
4357e8d8bef9SDimitry Andric       return Legalized;
43588bcb0991SDimitry Andric     }
43598bcb0991SDimitry Andric 
4360e8d8bef9SDimitry Andric     SmallVector<Register, 8> VecParts;
4361e8d8bef9SDimitry Andric     LLT GCDTy = extractGCDType(VecParts, VecTy, NarrowVecTy, SrcVec);
4362e8d8bef9SDimitry Andric 
4363e8d8bef9SDimitry Andric     // Build a sequence of NarrowTy pieces in VecParts for this operand.
4364e8d8bef9SDimitry Andric     LLT LCMTy = buildLCMMergePieces(VecTy, NarrowVecTy, GCDTy, VecParts,
4365e8d8bef9SDimitry Andric                                     TargetOpcode::G_ANYEXT);
4366e8d8bef9SDimitry Andric 
4367e8d8bef9SDimitry Andric     unsigned NewNumElts = NarrowVecTy.getNumElements();
4368e8d8bef9SDimitry Andric 
4369e8d8bef9SDimitry Andric     LLT IdxTy = MRI.getType(Idx);
4370e8d8bef9SDimitry Andric     int64_t PartIdx = IdxVal / NewNumElts;
4371e8d8bef9SDimitry Andric     auto NewIdx =
4372e8d8bef9SDimitry Andric         MIRBuilder.buildConstant(IdxTy, IdxVal - NewNumElts * PartIdx);
4373e8d8bef9SDimitry Andric 
4374e8d8bef9SDimitry Andric     if (IsInsert) {
4375e8d8bef9SDimitry Andric       LLT PartTy = MRI.getType(VecParts[PartIdx]);
4376e8d8bef9SDimitry Andric 
4377e8d8bef9SDimitry Andric       // Use the adjusted index to insert into one of the subvectors.
4378e8d8bef9SDimitry Andric       auto InsertPart = MIRBuilder.buildInsertVectorElement(
4379e8d8bef9SDimitry Andric           PartTy, VecParts[PartIdx], InsertVal, NewIdx);
4380e8d8bef9SDimitry Andric       VecParts[PartIdx] = InsertPart.getReg(0);
4381e8d8bef9SDimitry Andric 
4382e8d8bef9SDimitry Andric       // Recombine the inserted subvector with the others to reform the result
4383e8d8bef9SDimitry Andric       // vector.
4384e8d8bef9SDimitry Andric       buildWidenedRemergeToDst(DstReg, LCMTy, VecParts);
4385e8d8bef9SDimitry Andric     } else {
4386e8d8bef9SDimitry Andric       MIRBuilder.buildExtractVectorElement(DstReg, VecParts[PartIdx], NewIdx);
43878bcb0991SDimitry Andric     }
43888bcb0991SDimitry Andric 
43898bcb0991SDimitry Andric     MI.eraseFromParent();
43908bcb0991SDimitry Andric     return Legalized;
43918bcb0991SDimitry Andric   }
43928bcb0991SDimitry Andric 
4393e8d8bef9SDimitry Andric   // With a variable index, we can't perform the operation in a smaller type, so
4394e8d8bef9SDimitry Andric   // we're forced to expand this.
4395e8d8bef9SDimitry Andric   //
4396e8d8bef9SDimitry Andric   // TODO: We could emit a chain of compare/select to figure out which piece to
4397e8d8bef9SDimitry Andric   // index.
4398e8d8bef9SDimitry Andric   return lowerExtractInsertVectorElt(MI);
4399e8d8bef9SDimitry Andric }
4400e8d8bef9SDimitry Andric 
44018bcb0991SDimitry Andric LegalizerHelper::LegalizeResult
4402fe6060f1SDimitry Andric LegalizerHelper::reduceLoadStoreWidth(GLoadStore &LdStMI, unsigned TypeIdx,
44030b57cec5SDimitry Andric                                       LLT NarrowTy) {
44040b57cec5SDimitry Andric   // FIXME: Don't know how to handle secondary types yet.
44050b57cec5SDimitry Andric   if (TypeIdx != 0)
44060b57cec5SDimitry Andric     return UnableToLegalize;
44070b57cec5SDimitry Andric 
44080b57cec5SDimitry Andric   // This implementation doesn't work for atomics. Give up instead of doing
44090b57cec5SDimitry Andric   // something invalid.
4410fe6060f1SDimitry Andric   if (LdStMI.isAtomic())
44110b57cec5SDimitry Andric     return UnableToLegalize;
44120b57cec5SDimitry Andric 
4413fe6060f1SDimitry Andric   bool IsLoad = isa<GLoad>(LdStMI);
4414fe6060f1SDimitry Andric   Register ValReg = LdStMI.getReg(0);
4415fe6060f1SDimitry Andric   Register AddrReg = LdStMI.getPointerReg();
44160b57cec5SDimitry Andric   LLT ValTy = MRI.getType(ValReg);
44170b57cec5SDimitry Andric 
44185ffd83dbSDimitry Andric   // FIXME: Do we need a distinct NarrowMemory legalize action?
4419fe6060f1SDimitry Andric   if (ValTy.getSizeInBits() != 8 * LdStMI.getMemSize()) {
44205ffd83dbSDimitry Andric     LLVM_DEBUG(dbgs() << "Can't narrow extload/truncstore\n");
44215ffd83dbSDimitry Andric     return UnableToLegalize;
44225ffd83dbSDimitry Andric   }
44235ffd83dbSDimitry Andric 
44240b57cec5SDimitry Andric   int NumParts = -1;
44250b57cec5SDimitry Andric   int NumLeftover = -1;
44260b57cec5SDimitry Andric   LLT LeftoverTy;
44270b57cec5SDimitry Andric   SmallVector<Register, 8> NarrowRegs, NarrowLeftoverRegs;
44280b57cec5SDimitry Andric   if (IsLoad) {
44290b57cec5SDimitry Andric     std::tie(NumParts, NumLeftover) = getNarrowTypeBreakDown(ValTy, NarrowTy, LeftoverTy);
44300b57cec5SDimitry Andric   } else {
44310b57cec5SDimitry Andric     if (extractParts(ValReg, ValTy, NarrowTy, LeftoverTy, NarrowRegs,
4432*7a6dacacSDimitry Andric                      NarrowLeftoverRegs, MIRBuilder, MRI)) {
44330b57cec5SDimitry Andric       NumParts = NarrowRegs.size();
44340b57cec5SDimitry Andric       NumLeftover = NarrowLeftoverRegs.size();
44350b57cec5SDimitry Andric     }
44360b57cec5SDimitry Andric   }
44370b57cec5SDimitry Andric 
44380b57cec5SDimitry Andric   if (NumParts == -1)
44390b57cec5SDimitry Andric     return UnableToLegalize;
44400b57cec5SDimitry Andric 
4441e8d8bef9SDimitry Andric   LLT PtrTy = MRI.getType(AddrReg);
4442e8d8bef9SDimitry Andric   const LLT OffsetTy = LLT::scalar(PtrTy.getSizeInBits());
44430b57cec5SDimitry Andric 
44440b57cec5SDimitry Andric   unsigned TotalSize = ValTy.getSizeInBits();
44450b57cec5SDimitry Andric 
44460b57cec5SDimitry Andric   // Split the load/store into PartTy sized pieces starting at Offset. If this
44470b57cec5SDimitry Andric   // is a load, return the new registers in ValRegs. For a store, each elements
44480b57cec5SDimitry Andric   // of ValRegs should be PartTy. Returns the next offset that needs to be
44490b57cec5SDimitry Andric   // handled.
445081ad6265SDimitry Andric   bool isBigEndian = MIRBuilder.getDataLayout().isBigEndian();
4451fe6060f1SDimitry Andric   auto MMO = LdStMI.getMMO();
44520b57cec5SDimitry Andric   auto splitTypePieces = [=](LLT PartTy, SmallVectorImpl<Register> &ValRegs,
445381ad6265SDimitry Andric                              unsigned NumParts, unsigned Offset) -> unsigned {
44540b57cec5SDimitry Andric     MachineFunction &MF = MIRBuilder.getMF();
44550b57cec5SDimitry Andric     unsigned PartSize = PartTy.getSizeInBits();
44560b57cec5SDimitry Andric     for (unsigned Idx = 0, E = NumParts; Idx != E && Offset < TotalSize;
445781ad6265SDimitry Andric          ++Idx) {
44580b57cec5SDimitry Andric       unsigned ByteOffset = Offset / 8;
44590b57cec5SDimitry Andric       Register NewAddrReg;
44600b57cec5SDimitry Andric 
4461480093f4SDimitry Andric       MIRBuilder.materializePtrAdd(NewAddrReg, AddrReg, OffsetTy, ByteOffset);
44620b57cec5SDimitry Andric 
44630b57cec5SDimitry Andric       MachineMemOperand *NewMMO =
4464fe6060f1SDimitry Andric           MF.getMachineMemOperand(&MMO, ByteOffset, PartTy);
44650b57cec5SDimitry Andric 
44660b57cec5SDimitry Andric       if (IsLoad) {
44670b57cec5SDimitry Andric         Register Dst = MRI.createGenericVirtualRegister(PartTy);
44680b57cec5SDimitry Andric         ValRegs.push_back(Dst);
44690b57cec5SDimitry Andric         MIRBuilder.buildLoad(Dst, NewAddrReg, *NewMMO);
44700b57cec5SDimitry Andric       } else {
44710b57cec5SDimitry Andric         MIRBuilder.buildStore(ValRegs[Idx], NewAddrReg, *NewMMO);
44720b57cec5SDimitry Andric       }
447381ad6265SDimitry Andric       Offset = isBigEndian ? Offset - PartSize : Offset + PartSize;
44740b57cec5SDimitry Andric     }
44750b57cec5SDimitry Andric 
44760b57cec5SDimitry Andric     return Offset;
44770b57cec5SDimitry Andric   };
44780b57cec5SDimitry Andric 
447981ad6265SDimitry Andric   unsigned Offset = isBigEndian ? TotalSize - NarrowTy.getSizeInBits() : 0;
448081ad6265SDimitry Andric   unsigned HandledOffset =
448181ad6265SDimitry Andric       splitTypePieces(NarrowTy, NarrowRegs, NumParts, Offset);
44820b57cec5SDimitry Andric 
44830b57cec5SDimitry Andric   // Handle the rest of the register if this isn't an even type breakdown.
44840b57cec5SDimitry Andric   if (LeftoverTy.isValid())
448581ad6265SDimitry Andric     splitTypePieces(LeftoverTy, NarrowLeftoverRegs, NumLeftover, HandledOffset);
44860b57cec5SDimitry Andric 
44870b57cec5SDimitry Andric   if (IsLoad) {
44880b57cec5SDimitry Andric     insertParts(ValReg, ValTy, NarrowTy, NarrowRegs,
44890b57cec5SDimitry Andric                 LeftoverTy, NarrowLeftoverRegs);
44900b57cec5SDimitry Andric   }
44910b57cec5SDimitry Andric 
4492fe6060f1SDimitry Andric   LdStMI.eraseFromParent();
44930b57cec5SDimitry Andric   return Legalized;
44940b57cec5SDimitry Andric }
44950b57cec5SDimitry Andric 
44960b57cec5SDimitry Andric LegalizerHelper::LegalizeResult
44970b57cec5SDimitry Andric LegalizerHelper::fewerElementsVector(MachineInstr &MI, unsigned TypeIdx,
44980b57cec5SDimitry Andric                                      LLT NarrowTy) {
44990b57cec5SDimitry Andric   using namespace TargetOpcode;
45000eae32dcSDimitry Andric   GenericMachineInstr &GMI = cast<GenericMachineInstr>(MI);
45010eae32dcSDimitry Andric   unsigned NumElts = NarrowTy.isVector() ? NarrowTy.getNumElements() : 1;
45020b57cec5SDimitry Andric 
45030b57cec5SDimitry Andric   switch (MI.getOpcode()) {
45040b57cec5SDimitry Andric   case G_IMPLICIT_DEF:
45055ffd83dbSDimitry Andric   case G_TRUNC:
45060b57cec5SDimitry Andric   case G_AND:
45070b57cec5SDimitry Andric   case G_OR:
45080b57cec5SDimitry Andric   case G_XOR:
45090b57cec5SDimitry Andric   case G_ADD:
45100b57cec5SDimitry Andric   case G_SUB:
45110b57cec5SDimitry Andric   case G_MUL:
4512e8d8bef9SDimitry Andric   case G_PTR_ADD:
45130b57cec5SDimitry Andric   case G_SMULH:
45140b57cec5SDimitry Andric   case G_UMULH:
45150b57cec5SDimitry Andric   case G_FADD:
45160b57cec5SDimitry Andric   case G_FMUL:
45170b57cec5SDimitry Andric   case G_FSUB:
45180b57cec5SDimitry Andric   case G_FNEG:
45190b57cec5SDimitry Andric   case G_FABS:
45200b57cec5SDimitry Andric   case G_FCANONICALIZE:
45210b57cec5SDimitry Andric   case G_FDIV:
45220b57cec5SDimitry Andric   case G_FREM:
45230b57cec5SDimitry Andric   case G_FMA:
45248bcb0991SDimitry Andric   case G_FMAD:
45250b57cec5SDimitry Andric   case G_FPOW:
45260b57cec5SDimitry Andric   case G_FEXP:
45270b57cec5SDimitry Andric   case G_FEXP2:
45285f757f3fSDimitry Andric   case G_FEXP10:
45290b57cec5SDimitry Andric   case G_FLOG:
45300b57cec5SDimitry Andric   case G_FLOG2:
45310b57cec5SDimitry Andric   case G_FLOG10:
453206c3fb27SDimitry Andric   case G_FLDEXP:
45330b57cec5SDimitry Andric   case G_FNEARBYINT:
45340b57cec5SDimitry Andric   case G_FCEIL:
45350b57cec5SDimitry Andric   case G_FFLOOR:
45360b57cec5SDimitry Andric   case G_FRINT:
45370b57cec5SDimitry Andric   case G_INTRINSIC_ROUND:
4538e8d8bef9SDimitry Andric   case G_INTRINSIC_ROUNDEVEN:
45390b57cec5SDimitry Andric   case G_INTRINSIC_TRUNC:
45400b57cec5SDimitry Andric   case G_FCOS:
45410b57cec5SDimitry Andric   case G_FSIN:
45420b57cec5SDimitry Andric   case G_FSQRT:
45430b57cec5SDimitry Andric   case G_BSWAP:
45448bcb0991SDimitry Andric   case G_BITREVERSE:
45450b57cec5SDimitry Andric   case G_SDIV:
4546480093f4SDimitry Andric   case G_UDIV:
4547480093f4SDimitry Andric   case G_SREM:
4548480093f4SDimitry Andric   case G_UREM:
4549fe6060f1SDimitry Andric   case G_SDIVREM:
4550fe6060f1SDimitry Andric   case G_UDIVREM:
45510b57cec5SDimitry Andric   case G_SMIN:
45520b57cec5SDimitry Andric   case G_SMAX:
45530b57cec5SDimitry Andric   case G_UMIN:
45540b57cec5SDimitry Andric   case G_UMAX:
4555fe6060f1SDimitry Andric   case G_ABS:
45560b57cec5SDimitry Andric   case G_FMINNUM:
45570b57cec5SDimitry Andric   case G_FMAXNUM:
45580b57cec5SDimitry Andric   case G_FMINNUM_IEEE:
45590b57cec5SDimitry Andric   case G_FMAXNUM_IEEE:
45600b57cec5SDimitry Andric   case G_FMINIMUM:
45610b57cec5SDimitry Andric   case G_FMAXIMUM:
45625ffd83dbSDimitry Andric   case G_FSHL:
45635ffd83dbSDimitry Andric   case G_FSHR:
4564349cc55cSDimitry Andric   case G_ROTL:
4565349cc55cSDimitry Andric   case G_ROTR:
45665ffd83dbSDimitry Andric   case G_FREEZE:
45675ffd83dbSDimitry Andric   case G_SADDSAT:
45685ffd83dbSDimitry Andric   case G_SSUBSAT:
45695ffd83dbSDimitry Andric   case G_UADDSAT:
45705ffd83dbSDimitry Andric   case G_USUBSAT:
4571fe6060f1SDimitry Andric   case G_UMULO:
4572fe6060f1SDimitry Andric   case G_SMULO:
45730b57cec5SDimitry Andric   case G_SHL:
45740b57cec5SDimitry Andric   case G_LSHR:
45750b57cec5SDimitry Andric   case G_ASHR:
4576e8d8bef9SDimitry Andric   case G_SSHLSAT:
4577e8d8bef9SDimitry Andric   case G_USHLSAT:
45780b57cec5SDimitry Andric   case G_CTLZ:
45790b57cec5SDimitry Andric   case G_CTLZ_ZERO_UNDEF:
45800b57cec5SDimitry Andric   case G_CTTZ:
45810b57cec5SDimitry Andric   case G_CTTZ_ZERO_UNDEF:
45820b57cec5SDimitry Andric   case G_CTPOP:
45830b57cec5SDimitry Andric   case G_FCOPYSIGN:
45840b57cec5SDimitry Andric   case G_ZEXT:
45850b57cec5SDimitry Andric   case G_SEXT:
45860b57cec5SDimitry Andric   case G_ANYEXT:
45870b57cec5SDimitry Andric   case G_FPEXT:
45880b57cec5SDimitry Andric   case G_FPTRUNC:
45890b57cec5SDimitry Andric   case G_SITOFP:
45900b57cec5SDimitry Andric   case G_UITOFP:
45910b57cec5SDimitry Andric   case G_FPTOSI:
45920b57cec5SDimitry Andric   case G_FPTOUI:
45930b57cec5SDimitry Andric   case G_INTTOPTR:
45940b57cec5SDimitry Andric   case G_PTRTOINT:
45950b57cec5SDimitry Andric   case G_ADDRSPACE_CAST:
459681ad6265SDimitry Andric   case G_UADDO:
459781ad6265SDimitry Andric   case G_USUBO:
459881ad6265SDimitry Andric   case G_UADDE:
459981ad6265SDimitry Andric   case G_USUBE:
460081ad6265SDimitry Andric   case G_SADDO:
460181ad6265SDimitry Andric   case G_SSUBO:
460281ad6265SDimitry Andric   case G_SADDE:
460381ad6265SDimitry Andric   case G_SSUBE:
4604bdd1243dSDimitry Andric   case G_STRICT_FADD:
4605bdd1243dSDimitry Andric   case G_STRICT_FSUB:
4606bdd1243dSDimitry Andric   case G_STRICT_FMUL:
4607bdd1243dSDimitry Andric   case G_STRICT_FMA:
460806c3fb27SDimitry Andric   case G_STRICT_FLDEXP:
460906c3fb27SDimitry Andric   case G_FFREXP:
46100eae32dcSDimitry Andric     return fewerElementsVectorMultiEltType(GMI, NumElts);
46110b57cec5SDimitry Andric   case G_ICMP:
46120b57cec5SDimitry Andric   case G_FCMP:
46130eae32dcSDimitry Andric     return fewerElementsVectorMultiEltType(GMI, NumElts, {1 /*cpm predicate*/});
4614bdd1243dSDimitry Andric   case G_IS_FPCLASS:
4615bdd1243dSDimitry Andric     return fewerElementsVectorMultiEltType(GMI, NumElts, {2, 3 /*mask,fpsem*/});
46160b57cec5SDimitry Andric   case G_SELECT:
46170eae32dcSDimitry Andric     if (MRI.getType(MI.getOperand(1).getReg()).isVector())
46180eae32dcSDimitry Andric       return fewerElementsVectorMultiEltType(GMI, NumElts);
46190eae32dcSDimitry Andric     return fewerElementsVectorMultiEltType(GMI, NumElts, {1 /*scalar cond*/});
46200b57cec5SDimitry Andric   case G_PHI:
46210eae32dcSDimitry Andric     return fewerElementsVectorPhi(GMI, NumElts);
46228bcb0991SDimitry Andric   case G_UNMERGE_VALUES:
46238bcb0991SDimitry Andric     return fewerElementsVectorUnmergeValues(MI, TypeIdx, NarrowTy);
46248bcb0991SDimitry Andric   case G_BUILD_VECTOR:
4625e8d8bef9SDimitry Andric     assert(TypeIdx == 0 && "not a vector type index");
4626e8d8bef9SDimitry Andric     return fewerElementsVectorMerge(MI, TypeIdx, NarrowTy);
4627e8d8bef9SDimitry Andric   case G_CONCAT_VECTORS:
4628e8d8bef9SDimitry Andric     if (TypeIdx != 1) // TODO: This probably does work as expected already.
4629e8d8bef9SDimitry Andric       return UnableToLegalize;
4630e8d8bef9SDimitry Andric     return fewerElementsVectorMerge(MI, TypeIdx, NarrowTy);
4631e8d8bef9SDimitry Andric   case G_EXTRACT_VECTOR_ELT:
4632e8d8bef9SDimitry Andric   case G_INSERT_VECTOR_ELT:
4633e8d8bef9SDimitry Andric     return fewerElementsVectorExtractInsertVectorElt(MI, TypeIdx, NarrowTy);
46340b57cec5SDimitry Andric   case G_LOAD:
46350b57cec5SDimitry Andric   case G_STORE:
4636fe6060f1SDimitry Andric     return reduceLoadStoreWidth(cast<GLoadStore>(MI), TypeIdx, NarrowTy);
46375ffd83dbSDimitry Andric   case G_SEXT_INREG:
46380eae32dcSDimitry Andric     return fewerElementsVectorMultiEltType(GMI, NumElts, {2 /*imm*/});
4639fe6060f1SDimitry Andric   GISEL_VECREDUCE_CASES_NONSEQ
4640fe6060f1SDimitry Andric     return fewerElementsVectorReductions(MI, TypeIdx, NarrowTy);
46411db9f3b2SDimitry Andric   case TargetOpcode::G_VECREDUCE_SEQ_FADD:
46421db9f3b2SDimitry Andric   case TargetOpcode::G_VECREDUCE_SEQ_FMUL:
46431db9f3b2SDimitry Andric     return fewerElementsVectorSeqReductions(MI, TypeIdx, NarrowTy);
4644fe6060f1SDimitry Andric   case G_SHUFFLE_VECTOR:
4645fe6060f1SDimitry Andric     return fewerElementsVectorShuffle(MI, TypeIdx, NarrowTy);
46461db9f3b2SDimitry Andric   case G_FPOWI:
46471db9f3b2SDimitry Andric     return fewerElementsVectorMultiEltType(GMI, NumElts, {2 /*pow*/});
46480b57cec5SDimitry Andric   default:
46490b57cec5SDimitry Andric     return UnableToLegalize;
46500b57cec5SDimitry Andric   }
46510b57cec5SDimitry Andric }
46520b57cec5SDimitry Andric 
4653fe6060f1SDimitry Andric LegalizerHelper::LegalizeResult LegalizerHelper::fewerElementsVectorShuffle(
4654fe6060f1SDimitry Andric     MachineInstr &MI, unsigned int TypeIdx, LLT NarrowTy) {
4655fe6060f1SDimitry Andric   assert(MI.getOpcode() == TargetOpcode::G_SHUFFLE_VECTOR);
4656fe6060f1SDimitry Andric   if (TypeIdx != 0)
4657fe6060f1SDimitry Andric     return UnableToLegalize;
4658fe6060f1SDimitry Andric 
465906c3fb27SDimitry Andric   auto [DstReg, DstTy, Src1Reg, Src1Ty, Src2Reg, Src2Ty] =
466006c3fb27SDimitry Andric       MI.getFirst3RegLLTs();
4661fe6060f1SDimitry Andric   ArrayRef<int> Mask = MI.getOperand(3).getShuffleMask();
4662fe6060f1SDimitry Andric   // The shuffle should be canonicalized by now.
4663fe6060f1SDimitry Andric   if (DstTy != Src1Ty)
4664fe6060f1SDimitry Andric     return UnableToLegalize;
4665fe6060f1SDimitry Andric   if (DstTy != Src2Ty)
4666fe6060f1SDimitry Andric     return UnableToLegalize;
4667fe6060f1SDimitry Andric 
4668fe6060f1SDimitry Andric   if (!isPowerOf2_32(DstTy.getNumElements()))
4669fe6060f1SDimitry Andric     return UnableToLegalize;
4670fe6060f1SDimitry Andric 
4671fe6060f1SDimitry Andric   // We only support splitting a shuffle into 2, so adjust NarrowTy accordingly.
4672fe6060f1SDimitry Andric   // Further legalization attempts will be needed to do split further.
4673fe6060f1SDimitry Andric   NarrowTy =
4674fe6060f1SDimitry Andric       DstTy.changeElementCount(DstTy.getElementCount().divideCoefficientBy(2));
4675fe6060f1SDimitry Andric   unsigned NewElts = NarrowTy.getNumElements();
4676fe6060f1SDimitry Andric 
4677fe6060f1SDimitry Andric   SmallVector<Register> SplitSrc1Regs, SplitSrc2Regs;
4678*7a6dacacSDimitry Andric   extractParts(Src1Reg, NarrowTy, 2, SplitSrc1Regs, MIRBuilder, MRI);
4679*7a6dacacSDimitry Andric   extractParts(Src2Reg, NarrowTy, 2, SplitSrc2Regs, MIRBuilder, MRI);
4680fe6060f1SDimitry Andric   Register Inputs[4] = {SplitSrc1Regs[0], SplitSrc1Regs[1], SplitSrc2Regs[0],
4681fe6060f1SDimitry Andric                         SplitSrc2Regs[1]};
4682fe6060f1SDimitry Andric 
4683fe6060f1SDimitry Andric   Register Hi, Lo;
4684fe6060f1SDimitry Andric 
4685fe6060f1SDimitry Andric   // If Lo or Hi uses elements from at most two of the four input vectors, then
4686fe6060f1SDimitry Andric   // express it as a vector shuffle of those two inputs.  Otherwise extract the
4687fe6060f1SDimitry Andric   // input elements by hand and construct the Lo/Hi output using a BUILD_VECTOR.
4688fe6060f1SDimitry Andric   SmallVector<int, 16> Ops;
4689fe6060f1SDimitry Andric   for (unsigned High = 0; High < 2; ++High) {
4690fe6060f1SDimitry Andric     Register &Output = High ? Hi : Lo;
4691fe6060f1SDimitry Andric 
4692fe6060f1SDimitry Andric     // Build a shuffle mask for the output, discovering on the fly which
4693fe6060f1SDimitry Andric     // input vectors to use as shuffle operands (recorded in InputUsed).
4694fe6060f1SDimitry Andric     // If building a suitable shuffle vector proves too hard, then bail
4695fe6060f1SDimitry Andric     // out with useBuildVector set.
4696fe6060f1SDimitry Andric     unsigned InputUsed[2] = {-1U, -1U}; // Not yet discovered.
4697fe6060f1SDimitry Andric     unsigned FirstMaskIdx = High * NewElts;
4698fe6060f1SDimitry Andric     bool UseBuildVector = false;
4699fe6060f1SDimitry Andric     for (unsigned MaskOffset = 0; MaskOffset < NewElts; ++MaskOffset) {
4700fe6060f1SDimitry Andric       // The mask element.  This indexes into the input.
4701fe6060f1SDimitry Andric       int Idx = Mask[FirstMaskIdx + MaskOffset];
4702fe6060f1SDimitry Andric 
4703fe6060f1SDimitry Andric       // The input vector this mask element indexes into.
4704fe6060f1SDimitry Andric       unsigned Input = (unsigned)Idx / NewElts;
4705fe6060f1SDimitry Andric 
4706bdd1243dSDimitry Andric       if (Input >= std::size(Inputs)) {
4707fe6060f1SDimitry Andric         // The mask element does not index into any input vector.
4708fe6060f1SDimitry Andric         Ops.push_back(-1);
4709fe6060f1SDimitry Andric         continue;
4710fe6060f1SDimitry Andric       }
4711fe6060f1SDimitry Andric 
4712fe6060f1SDimitry Andric       // Turn the index into an offset from the start of the input vector.
4713fe6060f1SDimitry Andric       Idx -= Input * NewElts;
4714fe6060f1SDimitry Andric 
4715fe6060f1SDimitry Andric       // Find or create a shuffle vector operand to hold this input.
4716fe6060f1SDimitry Andric       unsigned OpNo;
4717bdd1243dSDimitry Andric       for (OpNo = 0; OpNo < std::size(InputUsed); ++OpNo) {
4718fe6060f1SDimitry Andric         if (InputUsed[OpNo] == Input) {
4719fe6060f1SDimitry Andric           // This input vector is already an operand.
4720fe6060f1SDimitry Andric           break;
4721fe6060f1SDimitry Andric         } else if (InputUsed[OpNo] == -1U) {
4722fe6060f1SDimitry Andric           // Create a new operand for this input vector.
4723fe6060f1SDimitry Andric           InputUsed[OpNo] = Input;
4724fe6060f1SDimitry Andric           break;
4725fe6060f1SDimitry Andric         }
4726fe6060f1SDimitry Andric       }
4727fe6060f1SDimitry Andric 
4728bdd1243dSDimitry Andric       if (OpNo >= std::size(InputUsed)) {
4729fe6060f1SDimitry Andric         // More than two input vectors used!  Give up on trying to create a
4730fe6060f1SDimitry Andric         // shuffle vector.  Insert all elements into a BUILD_VECTOR instead.
4731fe6060f1SDimitry Andric         UseBuildVector = true;
4732fe6060f1SDimitry Andric         break;
4733fe6060f1SDimitry Andric       }
4734fe6060f1SDimitry Andric 
4735fe6060f1SDimitry Andric       // Add the mask index for the new shuffle vector.
4736fe6060f1SDimitry Andric       Ops.push_back(Idx + OpNo * NewElts);
4737fe6060f1SDimitry Andric     }
4738fe6060f1SDimitry Andric 
4739fe6060f1SDimitry Andric     if (UseBuildVector) {
4740fe6060f1SDimitry Andric       LLT EltTy = NarrowTy.getElementType();
4741fe6060f1SDimitry Andric       SmallVector<Register, 16> SVOps;
4742fe6060f1SDimitry Andric 
4743fe6060f1SDimitry Andric       // Extract the input elements by hand.
4744fe6060f1SDimitry Andric       for (unsigned MaskOffset = 0; MaskOffset < NewElts; ++MaskOffset) {
4745fe6060f1SDimitry Andric         // The mask element.  This indexes into the input.
4746fe6060f1SDimitry Andric         int Idx = Mask[FirstMaskIdx + MaskOffset];
4747fe6060f1SDimitry Andric 
4748fe6060f1SDimitry Andric         // The input vector this mask element indexes into.
4749fe6060f1SDimitry Andric         unsigned Input = (unsigned)Idx / NewElts;
4750fe6060f1SDimitry Andric 
4751bdd1243dSDimitry Andric         if (Input >= std::size(Inputs)) {
4752fe6060f1SDimitry Andric           // The mask element is "undef" or indexes off the end of the input.
4753fe6060f1SDimitry Andric           SVOps.push_back(MIRBuilder.buildUndef(EltTy).getReg(0));
4754fe6060f1SDimitry Andric           continue;
4755fe6060f1SDimitry Andric         }
4756fe6060f1SDimitry Andric 
4757fe6060f1SDimitry Andric         // Turn the index into an offset from the start of the input vector.
4758fe6060f1SDimitry Andric         Idx -= Input * NewElts;
4759fe6060f1SDimitry Andric 
4760fe6060f1SDimitry Andric         // Extract the vector element by hand.
4761fe6060f1SDimitry Andric         SVOps.push_back(MIRBuilder
4762fe6060f1SDimitry Andric                             .buildExtractVectorElement(
4763fe6060f1SDimitry Andric                                 EltTy, Inputs[Input],
4764fe6060f1SDimitry Andric                                 MIRBuilder.buildConstant(LLT::scalar(32), Idx))
4765fe6060f1SDimitry Andric                             .getReg(0));
4766fe6060f1SDimitry Andric       }
4767fe6060f1SDimitry Andric 
4768fe6060f1SDimitry Andric       // Construct the Lo/Hi output using a G_BUILD_VECTOR.
4769fe6060f1SDimitry Andric       Output = MIRBuilder.buildBuildVector(NarrowTy, SVOps).getReg(0);
4770fe6060f1SDimitry Andric     } else if (InputUsed[0] == -1U) {
4771fe6060f1SDimitry Andric       // No input vectors were used! The result is undefined.
4772fe6060f1SDimitry Andric       Output = MIRBuilder.buildUndef(NarrowTy).getReg(0);
4773fe6060f1SDimitry Andric     } else {
4774fe6060f1SDimitry Andric       Register Op0 = Inputs[InputUsed[0]];
4775fe6060f1SDimitry Andric       // If only one input was used, use an undefined vector for the other.
4776fe6060f1SDimitry Andric       Register Op1 = InputUsed[1] == -1U
4777fe6060f1SDimitry Andric                          ? MIRBuilder.buildUndef(NarrowTy).getReg(0)
4778fe6060f1SDimitry Andric                          : Inputs[InputUsed[1]];
4779fe6060f1SDimitry Andric       // At least one input vector was used. Create a new shuffle vector.
4780fe6060f1SDimitry Andric       Output = MIRBuilder.buildShuffleVector(NarrowTy, Op0, Op1, Ops).getReg(0);
4781fe6060f1SDimitry Andric     }
4782fe6060f1SDimitry Andric 
4783fe6060f1SDimitry Andric     Ops.clear();
4784fe6060f1SDimitry Andric   }
4785fe6060f1SDimitry Andric 
4786fe6060f1SDimitry Andric   MIRBuilder.buildConcatVectors(DstReg, {Lo, Hi});
4787fe6060f1SDimitry Andric   MI.eraseFromParent();
4788fe6060f1SDimitry Andric   return Legalized;
4789fe6060f1SDimitry Andric }
4790fe6060f1SDimitry Andric 
4791349cc55cSDimitry Andric LegalizerHelper::LegalizeResult LegalizerHelper::fewerElementsVectorReductions(
4792349cc55cSDimitry Andric     MachineInstr &MI, unsigned int TypeIdx, LLT NarrowTy) {
47935f757f3fSDimitry Andric   auto &RdxMI = cast<GVecReduce>(MI);
4794349cc55cSDimitry Andric 
4795349cc55cSDimitry Andric   if (TypeIdx != 1)
4796349cc55cSDimitry Andric     return UnableToLegalize;
4797349cc55cSDimitry Andric 
4798349cc55cSDimitry Andric   // The semantics of the normal non-sequential reductions allow us to freely
4799349cc55cSDimitry Andric   // re-associate the operation.
48005f757f3fSDimitry Andric   auto [DstReg, DstTy, SrcReg, SrcTy] = RdxMI.getFirst2RegLLTs();
4801349cc55cSDimitry Andric 
4802349cc55cSDimitry Andric   if (NarrowTy.isVector() &&
4803349cc55cSDimitry Andric       (SrcTy.getNumElements() % NarrowTy.getNumElements() != 0))
4804349cc55cSDimitry Andric     return UnableToLegalize;
4805349cc55cSDimitry Andric 
48065f757f3fSDimitry Andric   unsigned ScalarOpc = RdxMI.getScalarOpcForReduction();
4807349cc55cSDimitry Andric   SmallVector<Register> SplitSrcs;
4808349cc55cSDimitry Andric   // If NarrowTy is a scalar then we're being asked to scalarize.
4809349cc55cSDimitry Andric   const unsigned NumParts =
4810349cc55cSDimitry Andric       NarrowTy.isVector() ? SrcTy.getNumElements() / NarrowTy.getNumElements()
4811349cc55cSDimitry Andric                           : SrcTy.getNumElements();
4812349cc55cSDimitry Andric 
4813*7a6dacacSDimitry Andric   extractParts(SrcReg, NarrowTy, NumParts, SplitSrcs, MIRBuilder, MRI);
4814349cc55cSDimitry Andric   if (NarrowTy.isScalar()) {
4815349cc55cSDimitry Andric     if (DstTy != NarrowTy)
4816349cc55cSDimitry Andric       return UnableToLegalize; // FIXME: handle implicit extensions.
4817349cc55cSDimitry Andric 
4818349cc55cSDimitry Andric     if (isPowerOf2_32(NumParts)) {
4819349cc55cSDimitry Andric       // Generate a tree of scalar operations to reduce the critical path.
4820349cc55cSDimitry Andric       SmallVector<Register> PartialResults;
4821349cc55cSDimitry Andric       unsigned NumPartsLeft = NumParts;
4822349cc55cSDimitry Andric       while (NumPartsLeft > 1) {
4823349cc55cSDimitry Andric         for (unsigned Idx = 0; Idx < NumPartsLeft - 1; Idx += 2) {
4824349cc55cSDimitry Andric           PartialResults.emplace_back(
4825349cc55cSDimitry Andric               MIRBuilder
4826349cc55cSDimitry Andric                   .buildInstr(ScalarOpc, {NarrowTy},
4827349cc55cSDimitry Andric                               {SplitSrcs[Idx], SplitSrcs[Idx + 1]})
4828349cc55cSDimitry Andric                   .getReg(0));
4829349cc55cSDimitry Andric         }
4830349cc55cSDimitry Andric         SplitSrcs = PartialResults;
4831349cc55cSDimitry Andric         PartialResults.clear();
4832349cc55cSDimitry Andric         NumPartsLeft = SplitSrcs.size();
4833349cc55cSDimitry Andric       }
4834349cc55cSDimitry Andric       assert(SplitSrcs.size() == 1);
4835349cc55cSDimitry Andric       MIRBuilder.buildCopy(DstReg, SplitSrcs[0]);
4836349cc55cSDimitry Andric       MI.eraseFromParent();
4837349cc55cSDimitry Andric       return Legalized;
4838349cc55cSDimitry Andric     }
4839349cc55cSDimitry Andric     // If we can't generate a tree, then just do sequential operations.
4840349cc55cSDimitry Andric     Register Acc = SplitSrcs[0];
4841349cc55cSDimitry Andric     for (unsigned Idx = 1; Idx < NumParts; ++Idx)
4842349cc55cSDimitry Andric       Acc = MIRBuilder.buildInstr(ScalarOpc, {NarrowTy}, {Acc, SplitSrcs[Idx]})
4843349cc55cSDimitry Andric                 .getReg(0);
4844349cc55cSDimitry Andric     MIRBuilder.buildCopy(DstReg, Acc);
4845349cc55cSDimitry Andric     MI.eraseFromParent();
4846349cc55cSDimitry Andric     return Legalized;
4847349cc55cSDimitry Andric   }
4848349cc55cSDimitry Andric   SmallVector<Register> PartialReductions;
4849349cc55cSDimitry Andric   for (unsigned Part = 0; Part < NumParts; ++Part) {
4850349cc55cSDimitry Andric     PartialReductions.push_back(
48515f757f3fSDimitry Andric         MIRBuilder.buildInstr(RdxMI.getOpcode(), {DstTy}, {SplitSrcs[Part]})
48525f757f3fSDimitry Andric             .getReg(0));
4853349cc55cSDimitry Andric   }
4854349cc55cSDimitry Andric 
4855fe6060f1SDimitry Andric   // If the types involved are powers of 2, we can generate intermediate vector
4856fe6060f1SDimitry Andric   // ops, before generating a final reduction operation.
4857fe6060f1SDimitry Andric   if (isPowerOf2_32(SrcTy.getNumElements()) &&
4858fe6060f1SDimitry Andric       isPowerOf2_32(NarrowTy.getNumElements())) {
4859fe6060f1SDimitry Andric     return tryNarrowPow2Reduction(MI, SrcReg, SrcTy, NarrowTy, ScalarOpc);
4860fe6060f1SDimitry Andric   }
4861fe6060f1SDimitry Andric 
4862fe6060f1SDimitry Andric   Register Acc = PartialReductions[0];
4863fe6060f1SDimitry Andric   for (unsigned Part = 1; Part < NumParts; ++Part) {
4864fe6060f1SDimitry Andric     if (Part == NumParts - 1) {
4865fe6060f1SDimitry Andric       MIRBuilder.buildInstr(ScalarOpc, {DstReg},
4866fe6060f1SDimitry Andric                             {Acc, PartialReductions[Part]});
4867fe6060f1SDimitry Andric     } else {
4868fe6060f1SDimitry Andric       Acc = MIRBuilder
4869fe6060f1SDimitry Andric                 .buildInstr(ScalarOpc, {DstTy}, {Acc, PartialReductions[Part]})
4870fe6060f1SDimitry Andric                 .getReg(0);
4871fe6060f1SDimitry Andric     }
4872fe6060f1SDimitry Andric   }
4873fe6060f1SDimitry Andric   MI.eraseFromParent();
4874fe6060f1SDimitry Andric   return Legalized;
4875fe6060f1SDimitry Andric }
4876fe6060f1SDimitry Andric 
4877fe6060f1SDimitry Andric LegalizerHelper::LegalizeResult
48781db9f3b2SDimitry Andric LegalizerHelper::fewerElementsVectorSeqReductions(MachineInstr &MI,
48791db9f3b2SDimitry Andric                                                   unsigned int TypeIdx,
48801db9f3b2SDimitry Andric                                                   LLT NarrowTy) {
48811db9f3b2SDimitry Andric   auto [DstReg, DstTy, ScalarReg, ScalarTy, SrcReg, SrcTy] =
48821db9f3b2SDimitry Andric       MI.getFirst3RegLLTs();
48831db9f3b2SDimitry Andric   if (!NarrowTy.isScalar() || TypeIdx != 2 || DstTy != ScalarTy ||
48841db9f3b2SDimitry Andric       DstTy != NarrowTy)
48851db9f3b2SDimitry Andric     return UnableToLegalize;
48861db9f3b2SDimitry Andric 
48871db9f3b2SDimitry Andric   assert((MI.getOpcode() == TargetOpcode::G_VECREDUCE_SEQ_FADD ||
48881db9f3b2SDimitry Andric           MI.getOpcode() == TargetOpcode::G_VECREDUCE_SEQ_FMUL) &&
48891db9f3b2SDimitry Andric          "Unexpected vecreduce opcode");
48901db9f3b2SDimitry Andric   unsigned ScalarOpc = MI.getOpcode() == TargetOpcode::G_VECREDUCE_SEQ_FADD
48911db9f3b2SDimitry Andric                            ? TargetOpcode::G_FADD
48921db9f3b2SDimitry Andric                            : TargetOpcode::G_FMUL;
48931db9f3b2SDimitry Andric 
48941db9f3b2SDimitry Andric   SmallVector<Register> SplitSrcs;
48951db9f3b2SDimitry Andric   unsigned NumParts = SrcTy.getNumElements();
4896*7a6dacacSDimitry Andric   extractParts(SrcReg, NarrowTy, NumParts, SplitSrcs, MIRBuilder, MRI);
48971db9f3b2SDimitry Andric   Register Acc = ScalarReg;
48981db9f3b2SDimitry Andric   for (unsigned i = 0; i < NumParts; i++)
48991db9f3b2SDimitry Andric     Acc = MIRBuilder.buildInstr(ScalarOpc, {NarrowTy}, {Acc, SplitSrcs[i]})
49001db9f3b2SDimitry Andric               .getReg(0);
49011db9f3b2SDimitry Andric 
49021db9f3b2SDimitry Andric   MIRBuilder.buildCopy(DstReg, Acc);
49031db9f3b2SDimitry Andric   MI.eraseFromParent();
49041db9f3b2SDimitry Andric   return Legalized;
49051db9f3b2SDimitry Andric }
49061db9f3b2SDimitry Andric 
49071db9f3b2SDimitry Andric LegalizerHelper::LegalizeResult
4908fe6060f1SDimitry Andric LegalizerHelper::tryNarrowPow2Reduction(MachineInstr &MI, Register SrcReg,
4909fe6060f1SDimitry Andric                                         LLT SrcTy, LLT NarrowTy,
4910fe6060f1SDimitry Andric                                         unsigned ScalarOpc) {
4911fe6060f1SDimitry Andric   SmallVector<Register> SplitSrcs;
4912fe6060f1SDimitry Andric   // Split the sources into NarrowTy size pieces.
4913fe6060f1SDimitry Andric   extractParts(SrcReg, NarrowTy,
4914*7a6dacacSDimitry Andric                SrcTy.getNumElements() / NarrowTy.getNumElements(), SplitSrcs,
4915*7a6dacacSDimitry Andric                MIRBuilder, MRI);
4916fe6060f1SDimitry Andric   // We're going to do a tree reduction using vector operations until we have
4917fe6060f1SDimitry Andric   // one NarrowTy size value left.
4918fe6060f1SDimitry Andric   while (SplitSrcs.size() > 1) {
4919fe6060f1SDimitry Andric     SmallVector<Register> PartialRdxs;
4920fe6060f1SDimitry Andric     for (unsigned Idx = 0; Idx < SplitSrcs.size()-1; Idx += 2) {
4921fe6060f1SDimitry Andric       Register LHS = SplitSrcs[Idx];
4922fe6060f1SDimitry Andric       Register RHS = SplitSrcs[Idx + 1];
4923fe6060f1SDimitry Andric       // Create the intermediate vector op.
4924fe6060f1SDimitry Andric       Register Res =
4925fe6060f1SDimitry Andric           MIRBuilder.buildInstr(ScalarOpc, {NarrowTy}, {LHS, RHS}).getReg(0);
4926fe6060f1SDimitry Andric       PartialRdxs.push_back(Res);
4927fe6060f1SDimitry Andric     }
4928fe6060f1SDimitry Andric     SplitSrcs = std::move(PartialRdxs);
4929fe6060f1SDimitry Andric   }
4930fe6060f1SDimitry Andric   // Finally generate the requested NarrowTy based reduction.
4931fe6060f1SDimitry Andric   Observer.changingInstr(MI);
4932fe6060f1SDimitry Andric   MI.getOperand(1).setReg(SplitSrcs[0]);
4933fe6060f1SDimitry Andric   Observer.changedInstr(MI);
4934fe6060f1SDimitry Andric   return Legalized;
4935fe6060f1SDimitry Andric }
4936fe6060f1SDimitry Andric 
49370b57cec5SDimitry Andric LegalizerHelper::LegalizeResult
49380b57cec5SDimitry Andric LegalizerHelper::narrowScalarShiftByConstant(MachineInstr &MI, const APInt &Amt,
49390b57cec5SDimitry Andric                                              const LLT HalfTy, const LLT AmtTy) {
49400b57cec5SDimitry Andric 
49410b57cec5SDimitry Andric   Register InL = MRI.createGenericVirtualRegister(HalfTy);
49420b57cec5SDimitry Andric   Register InH = MRI.createGenericVirtualRegister(HalfTy);
49435ffd83dbSDimitry Andric   MIRBuilder.buildUnmerge({InL, InH}, MI.getOperand(1));
49440b57cec5SDimitry Andric 
4945349cc55cSDimitry Andric   if (Amt.isZero()) {
4946bdd1243dSDimitry Andric     MIRBuilder.buildMergeLikeInstr(MI.getOperand(0), {InL, InH});
49470b57cec5SDimitry Andric     MI.eraseFromParent();
49480b57cec5SDimitry Andric     return Legalized;
49490b57cec5SDimitry Andric   }
49500b57cec5SDimitry Andric 
49510b57cec5SDimitry Andric   LLT NVT = HalfTy;
49520b57cec5SDimitry Andric   unsigned NVTBits = HalfTy.getSizeInBits();
49530b57cec5SDimitry Andric   unsigned VTBits = 2 * NVTBits;
49540b57cec5SDimitry Andric 
49550b57cec5SDimitry Andric   SrcOp Lo(Register(0)), Hi(Register(0));
49560b57cec5SDimitry Andric   if (MI.getOpcode() == TargetOpcode::G_SHL) {
49570b57cec5SDimitry Andric     if (Amt.ugt(VTBits)) {
49580b57cec5SDimitry Andric       Lo = Hi = MIRBuilder.buildConstant(NVT, 0);
49590b57cec5SDimitry Andric     } else if (Amt.ugt(NVTBits)) {
49600b57cec5SDimitry Andric       Lo = MIRBuilder.buildConstant(NVT, 0);
49610b57cec5SDimitry Andric       Hi = MIRBuilder.buildShl(NVT, InL,
49620b57cec5SDimitry Andric                                MIRBuilder.buildConstant(AmtTy, Amt - NVTBits));
49630b57cec5SDimitry Andric     } else if (Amt == NVTBits) {
49640b57cec5SDimitry Andric       Lo = MIRBuilder.buildConstant(NVT, 0);
49650b57cec5SDimitry Andric       Hi = InL;
49660b57cec5SDimitry Andric     } else {
49670b57cec5SDimitry Andric       Lo = MIRBuilder.buildShl(NVT, InL, MIRBuilder.buildConstant(AmtTy, Amt));
49680b57cec5SDimitry Andric       auto OrLHS =
49690b57cec5SDimitry Andric           MIRBuilder.buildShl(NVT, InH, MIRBuilder.buildConstant(AmtTy, Amt));
49700b57cec5SDimitry Andric       auto OrRHS = MIRBuilder.buildLShr(
49710b57cec5SDimitry Andric           NVT, InL, MIRBuilder.buildConstant(AmtTy, -Amt + NVTBits));
49720b57cec5SDimitry Andric       Hi = MIRBuilder.buildOr(NVT, OrLHS, OrRHS);
49730b57cec5SDimitry Andric     }
49740b57cec5SDimitry Andric   } else if (MI.getOpcode() == TargetOpcode::G_LSHR) {
49750b57cec5SDimitry Andric     if (Amt.ugt(VTBits)) {
49760b57cec5SDimitry Andric       Lo = Hi = MIRBuilder.buildConstant(NVT, 0);
49770b57cec5SDimitry Andric     } else if (Amt.ugt(NVTBits)) {
49780b57cec5SDimitry Andric       Lo = MIRBuilder.buildLShr(NVT, InH,
49790b57cec5SDimitry Andric                                 MIRBuilder.buildConstant(AmtTy, Amt - NVTBits));
49800b57cec5SDimitry Andric       Hi = MIRBuilder.buildConstant(NVT, 0);
49810b57cec5SDimitry Andric     } else if (Amt == NVTBits) {
49820b57cec5SDimitry Andric       Lo = InH;
49830b57cec5SDimitry Andric       Hi = MIRBuilder.buildConstant(NVT, 0);
49840b57cec5SDimitry Andric     } else {
49850b57cec5SDimitry Andric       auto ShiftAmtConst = MIRBuilder.buildConstant(AmtTy, Amt);
49860b57cec5SDimitry Andric 
49870b57cec5SDimitry Andric       auto OrLHS = MIRBuilder.buildLShr(NVT, InL, ShiftAmtConst);
49880b57cec5SDimitry Andric       auto OrRHS = MIRBuilder.buildShl(
49890b57cec5SDimitry Andric           NVT, InH, MIRBuilder.buildConstant(AmtTy, -Amt + NVTBits));
49900b57cec5SDimitry Andric 
49910b57cec5SDimitry Andric       Lo = MIRBuilder.buildOr(NVT, OrLHS, OrRHS);
49920b57cec5SDimitry Andric       Hi = MIRBuilder.buildLShr(NVT, InH, ShiftAmtConst);
49930b57cec5SDimitry Andric     }
49940b57cec5SDimitry Andric   } else {
49950b57cec5SDimitry Andric     if (Amt.ugt(VTBits)) {
49960b57cec5SDimitry Andric       Hi = Lo = MIRBuilder.buildAShr(
49970b57cec5SDimitry Andric           NVT, InH, MIRBuilder.buildConstant(AmtTy, NVTBits - 1));
49980b57cec5SDimitry Andric     } else if (Amt.ugt(NVTBits)) {
49990b57cec5SDimitry Andric       Lo = MIRBuilder.buildAShr(NVT, InH,
50000b57cec5SDimitry Andric                                 MIRBuilder.buildConstant(AmtTy, Amt - NVTBits));
50010b57cec5SDimitry Andric       Hi = MIRBuilder.buildAShr(NVT, InH,
50020b57cec5SDimitry Andric                                 MIRBuilder.buildConstant(AmtTy, NVTBits - 1));
50030b57cec5SDimitry Andric     } else if (Amt == NVTBits) {
50040b57cec5SDimitry Andric       Lo = InH;
50050b57cec5SDimitry Andric       Hi = MIRBuilder.buildAShr(NVT, InH,
50060b57cec5SDimitry Andric                                 MIRBuilder.buildConstant(AmtTy, NVTBits - 1));
50070b57cec5SDimitry Andric     } else {
50080b57cec5SDimitry Andric       auto ShiftAmtConst = MIRBuilder.buildConstant(AmtTy, Amt);
50090b57cec5SDimitry Andric 
50100b57cec5SDimitry Andric       auto OrLHS = MIRBuilder.buildLShr(NVT, InL, ShiftAmtConst);
50110b57cec5SDimitry Andric       auto OrRHS = MIRBuilder.buildShl(
50120b57cec5SDimitry Andric           NVT, InH, MIRBuilder.buildConstant(AmtTy, -Amt + NVTBits));
50130b57cec5SDimitry Andric 
50140b57cec5SDimitry Andric       Lo = MIRBuilder.buildOr(NVT, OrLHS, OrRHS);
50150b57cec5SDimitry Andric       Hi = MIRBuilder.buildAShr(NVT, InH, ShiftAmtConst);
50160b57cec5SDimitry Andric     }
50170b57cec5SDimitry Andric   }
50180b57cec5SDimitry Andric 
5019bdd1243dSDimitry Andric   MIRBuilder.buildMergeLikeInstr(MI.getOperand(0), {Lo, Hi});
50200b57cec5SDimitry Andric   MI.eraseFromParent();
50210b57cec5SDimitry Andric 
50220b57cec5SDimitry Andric   return Legalized;
50230b57cec5SDimitry Andric }
50240b57cec5SDimitry Andric 
50250b57cec5SDimitry Andric // TODO: Optimize if constant shift amount.
50260b57cec5SDimitry Andric LegalizerHelper::LegalizeResult
50270b57cec5SDimitry Andric LegalizerHelper::narrowScalarShift(MachineInstr &MI, unsigned TypeIdx,
50280b57cec5SDimitry Andric                                    LLT RequestedTy) {
50290b57cec5SDimitry Andric   if (TypeIdx == 1) {
50300b57cec5SDimitry Andric     Observer.changingInstr(MI);
50310b57cec5SDimitry Andric     narrowScalarSrc(MI, RequestedTy, 2);
50320b57cec5SDimitry Andric     Observer.changedInstr(MI);
50330b57cec5SDimitry Andric     return Legalized;
50340b57cec5SDimitry Andric   }
50350b57cec5SDimitry Andric 
50360b57cec5SDimitry Andric   Register DstReg = MI.getOperand(0).getReg();
50370b57cec5SDimitry Andric   LLT DstTy = MRI.getType(DstReg);
50380b57cec5SDimitry Andric   if (DstTy.isVector())
50390b57cec5SDimitry Andric     return UnableToLegalize;
50400b57cec5SDimitry Andric 
50410b57cec5SDimitry Andric   Register Amt = MI.getOperand(2).getReg();
50420b57cec5SDimitry Andric   LLT ShiftAmtTy = MRI.getType(Amt);
50430b57cec5SDimitry Andric   const unsigned DstEltSize = DstTy.getScalarSizeInBits();
50440b57cec5SDimitry Andric   if (DstEltSize % 2 != 0)
50450b57cec5SDimitry Andric     return UnableToLegalize;
50460b57cec5SDimitry Andric 
50470b57cec5SDimitry Andric   // Ignore the input type. We can only go to exactly half the size of the
50480b57cec5SDimitry Andric   // input. If that isn't small enough, the resulting pieces will be further
50490b57cec5SDimitry Andric   // legalized.
50500b57cec5SDimitry Andric   const unsigned NewBitSize = DstEltSize / 2;
50510b57cec5SDimitry Andric   const LLT HalfTy = LLT::scalar(NewBitSize);
50520b57cec5SDimitry Andric   const LLT CondTy = LLT::scalar(1);
50530b57cec5SDimitry Andric 
5054349cc55cSDimitry Andric   if (auto VRegAndVal = getIConstantVRegValWithLookThrough(Amt, MRI)) {
5055349cc55cSDimitry Andric     return narrowScalarShiftByConstant(MI, VRegAndVal->Value, HalfTy,
5056349cc55cSDimitry Andric                                        ShiftAmtTy);
50570b57cec5SDimitry Andric   }
50580b57cec5SDimitry Andric 
50590b57cec5SDimitry Andric   // TODO: Expand with known bits.
50600b57cec5SDimitry Andric 
50610b57cec5SDimitry Andric   // Handle the fully general expansion by an unknown amount.
50620b57cec5SDimitry Andric   auto NewBits = MIRBuilder.buildConstant(ShiftAmtTy, NewBitSize);
50630b57cec5SDimitry Andric 
50640b57cec5SDimitry Andric   Register InL = MRI.createGenericVirtualRegister(HalfTy);
50650b57cec5SDimitry Andric   Register InH = MRI.createGenericVirtualRegister(HalfTy);
50665ffd83dbSDimitry Andric   MIRBuilder.buildUnmerge({InL, InH}, MI.getOperand(1));
50670b57cec5SDimitry Andric 
50680b57cec5SDimitry Andric   auto AmtExcess = MIRBuilder.buildSub(ShiftAmtTy, Amt, NewBits);
50690b57cec5SDimitry Andric   auto AmtLack = MIRBuilder.buildSub(ShiftAmtTy, NewBits, Amt);
50700b57cec5SDimitry Andric 
50710b57cec5SDimitry Andric   auto Zero = MIRBuilder.buildConstant(ShiftAmtTy, 0);
50720b57cec5SDimitry Andric   auto IsShort = MIRBuilder.buildICmp(ICmpInst::ICMP_ULT, CondTy, Amt, NewBits);
50730b57cec5SDimitry Andric   auto IsZero = MIRBuilder.buildICmp(ICmpInst::ICMP_EQ, CondTy, Amt, Zero);
50740b57cec5SDimitry Andric 
50750b57cec5SDimitry Andric   Register ResultRegs[2];
50760b57cec5SDimitry Andric   switch (MI.getOpcode()) {
50770b57cec5SDimitry Andric   case TargetOpcode::G_SHL: {
50780b57cec5SDimitry Andric     // Short: ShAmt < NewBitSize
50798bcb0991SDimitry Andric     auto LoS = MIRBuilder.buildShl(HalfTy, InL, Amt);
50800b57cec5SDimitry Andric 
50818bcb0991SDimitry Andric     auto LoOr = MIRBuilder.buildLShr(HalfTy, InL, AmtLack);
50828bcb0991SDimitry Andric     auto HiOr = MIRBuilder.buildShl(HalfTy, InH, Amt);
50838bcb0991SDimitry Andric     auto HiS = MIRBuilder.buildOr(HalfTy, LoOr, HiOr);
50840b57cec5SDimitry Andric 
50850b57cec5SDimitry Andric     // Long: ShAmt >= NewBitSize
50860b57cec5SDimitry Andric     auto LoL = MIRBuilder.buildConstant(HalfTy, 0);         // Lo part is zero.
50870b57cec5SDimitry Andric     auto HiL = MIRBuilder.buildShl(HalfTy, InL, AmtExcess); // Hi from Lo part.
50880b57cec5SDimitry Andric 
50890b57cec5SDimitry Andric     auto Lo = MIRBuilder.buildSelect(HalfTy, IsShort, LoS, LoL);
50900b57cec5SDimitry Andric     auto Hi = MIRBuilder.buildSelect(
50910b57cec5SDimitry Andric         HalfTy, IsZero, InH, MIRBuilder.buildSelect(HalfTy, IsShort, HiS, HiL));
50920b57cec5SDimitry Andric 
50930b57cec5SDimitry Andric     ResultRegs[0] = Lo.getReg(0);
50940b57cec5SDimitry Andric     ResultRegs[1] = Hi.getReg(0);
50950b57cec5SDimitry Andric     break;
50960b57cec5SDimitry Andric   }
50978bcb0991SDimitry Andric   case TargetOpcode::G_LSHR:
50980b57cec5SDimitry Andric   case TargetOpcode::G_ASHR: {
50990b57cec5SDimitry Andric     // Short: ShAmt < NewBitSize
51008bcb0991SDimitry Andric     auto HiS = MIRBuilder.buildInstr(MI.getOpcode(), {HalfTy}, {InH, Amt});
51010b57cec5SDimitry Andric 
51028bcb0991SDimitry Andric     auto LoOr = MIRBuilder.buildLShr(HalfTy, InL, Amt);
51038bcb0991SDimitry Andric     auto HiOr = MIRBuilder.buildShl(HalfTy, InH, AmtLack);
51048bcb0991SDimitry Andric     auto LoS = MIRBuilder.buildOr(HalfTy, LoOr, HiOr);
51050b57cec5SDimitry Andric 
51060b57cec5SDimitry Andric     // Long: ShAmt >= NewBitSize
51078bcb0991SDimitry Andric     MachineInstrBuilder HiL;
51088bcb0991SDimitry Andric     if (MI.getOpcode() == TargetOpcode::G_LSHR) {
51098bcb0991SDimitry Andric       HiL = MIRBuilder.buildConstant(HalfTy, 0);            // Hi part is zero.
51108bcb0991SDimitry Andric     } else {
51118bcb0991SDimitry Andric       auto ShiftAmt = MIRBuilder.buildConstant(ShiftAmtTy, NewBitSize - 1);
51128bcb0991SDimitry Andric       HiL = MIRBuilder.buildAShr(HalfTy, InH, ShiftAmt);    // Sign of Hi part.
51138bcb0991SDimitry Andric     }
51148bcb0991SDimitry Andric     auto LoL = MIRBuilder.buildInstr(MI.getOpcode(), {HalfTy},
51158bcb0991SDimitry Andric                                      {InH, AmtExcess});     // Lo from Hi part.
51160b57cec5SDimitry Andric 
51170b57cec5SDimitry Andric     auto Lo = MIRBuilder.buildSelect(
51180b57cec5SDimitry Andric         HalfTy, IsZero, InL, MIRBuilder.buildSelect(HalfTy, IsShort, LoS, LoL));
51190b57cec5SDimitry Andric 
51200b57cec5SDimitry Andric     auto Hi = MIRBuilder.buildSelect(HalfTy, IsShort, HiS, HiL);
51210b57cec5SDimitry Andric 
51220b57cec5SDimitry Andric     ResultRegs[0] = Lo.getReg(0);
51230b57cec5SDimitry Andric     ResultRegs[1] = Hi.getReg(0);
51240b57cec5SDimitry Andric     break;
51250b57cec5SDimitry Andric   }
51260b57cec5SDimitry Andric   default:
51270b57cec5SDimitry Andric     llvm_unreachable("not a shift");
51280b57cec5SDimitry Andric   }
51290b57cec5SDimitry Andric 
5130bdd1243dSDimitry Andric   MIRBuilder.buildMergeLikeInstr(DstReg, ResultRegs);
51310b57cec5SDimitry Andric   MI.eraseFromParent();
51320b57cec5SDimitry Andric   return Legalized;
51330b57cec5SDimitry Andric }
51340b57cec5SDimitry Andric 
51350b57cec5SDimitry Andric LegalizerHelper::LegalizeResult
51360b57cec5SDimitry Andric LegalizerHelper::moreElementsVectorPhi(MachineInstr &MI, unsigned TypeIdx,
51370b57cec5SDimitry Andric                                        LLT MoreTy) {
51380b57cec5SDimitry Andric   assert(TypeIdx == 0 && "Expecting only Idx 0");
51390b57cec5SDimitry Andric 
51400b57cec5SDimitry Andric   Observer.changingInstr(MI);
51410b57cec5SDimitry Andric   for (unsigned I = 1, E = MI.getNumOperands(); I != E; I += 2) {
51420b57cec5SDimitry Andric     MachineBasicBlock &OpMBB = *MI.getOperand(I + 1).getMBB();
51430b57cec5SDimitry Andric     MIRBuilder.setInsertPt(OpMBB, OpMBB.getFirstTerminator());
51440b57cec5SDimitry Andric     moreElementsVectorSrc(MI, MoreTy, I);
51450b57cec5SDimitry Andric   }
51460b57cec5SDimitry Andric 
51470b57cec5SDimitry Andric   MachineBasicBlock &MBB = *MI.getParent();
51480b57cec5SDimitry Andric   MIRBuilder.setInsertPt(MBB, --MBB.getFirstNonPHI());
51490b57cec5SDimitry Andric   moreElementsVectorDst(MI, MoreTy, 0);
51500b57cec5SDimitry Andric   Observer.changedInstr(MI);
51510b57cec5SDimitry Andric   return Legalized;
51520b57cec5SDimitry Andric }
51530b57cec5SDimitry Andric 
51540b57cec5SDimitry Andric LegalizerHelper::LegalizeResult
51550b57cec5SDimitry Andric LegalizerHelper::moreElementsVector(MachineInstr &MI, unsigned TypeIdx,
51560b57cec5SDimitry Andric                                     LLT MoreTy) {
51570b57cec5SDimitry Andric   unsigned Opc = MI.getOpcode();
51580b57cec5SDimitry Andric   switch (Opc) {
51598bcb0991SDimitry Andric   case TargetOpcode::G_IMPLICIT_DEF:
51608bcb0991SDimitry Andric   case TargetOpcode::G_LOAD: {
51618bcb0991SDimitry Andric     if (TypeIdx != 0)
51628bcb0991SDimitry Andric       return UnableToLegalize;
51630b57cec5SDimitry Andric     Observer.changingInstr(MI);
51640b57cec5SDimitry Andric     moreElementsVectorDst(MI, MoreTy, 0);
51650b57cec5SDimitry Andric     Observer.changedInstr(MI);
51660b57cec5SDimitry Andric     return Legalized;
51670b57cec5SDimitry Andric   }
51688bcb0991SDimitry Andric   case TargetOpcode::G_STORE:
51698bcb0991SDimitry Andric     if (TypeIdx != 0)
51708bcb0991SDimitry Andric       return UnableToLegalize;
51718bcb0991SDimitry Andric     Observer.changingInstr(MI);
51728bcb0991SDimitry Andric     moreElementsVectorSrc(MI, MoreTy, 0);
51738bcb0991SDimitry Andric     Observer.changedInstr(MI);
51748bcb0991SDimitry Andric     return Legalized;
51750b57cec5SDimitry Andric   case TargetOpcode::G_AND:
51760b57cec5SDimitry Andric   case TargetOpcode::G_OR:
51770b57cec5SDimitry Andric   case TargetOpcode::G_XOR:
51780eae32dcSDimitry Andric   case TargetOpcode::G_ADD:
51790eae32dcSDimitry Andric   case TargetOpcode::G_SUB:
51800eae32dcSDimitry Andric   case TargetOpcode::G_MUL:
51810eae32dcSDimitry Andric   case TargetOpcode::G_FADD:
51825f757f3fSDimitry Andric   case TargetOpcode::G_FSUB:
51830eae32dcSDimitry Andric   case TargetOpcode::G_FMUL:
51845f757f3fSDimitry Andric   case TargetOpcode::G_FDIV:
51850eae32dcSDimitry Andric   case TargetOpcode::G_UADDSAT:
51860eae32dcSDimitry Andric   case TargetOpcode::G_USUBSAT:
51870eae32dcSDimitry Andric   case TargetOpcode::G_SADDSAT:
51880eae32dcSDimitry Andric   case TargetOpcode::G_SSUBSAT:
51890b57cec5SDimitry Andric   case TargetOpcode::G_SMIN:
51900b57cec5SDimitry Andric   case TargetOpcode::G_SMAX:
51910b57cec5SDimitry Andric   case TargetOpcode::G_UMIN:
5192480093f4SDimitry Andric   case TargetOpcode::G_UMAX:
5193480093f4SDimitry Andric   case TargetOpcode::G_FMINNUM:
5194480093f4SDimitry Andric   case TargetOpcode::G_FMAXNUM:
5195480093f4SDimitry Andric   case TargetOpcode::G_FMINNUM_IEEE:
5196480093f4SDimitry Andric   case TargetOpcode::G_FMAXNUM_IEEE:
5197480093f4SDimitry Andric   case TargetOpcode::G_FMINIMUM:
5198bdd1243dSDimitry Andric   case TargetOpcode::G_FMAXIMUM:
5199bdd1243dSDimitry Andric   case TargetOpcode::G_STRICT_FADD:
5200bdd1243dSDimitry Andric   case TargetOpcode::G_STRICT_FSUB:
5201*7a6dacacSDimitry Andric   case TargetOpcode::G_STRICT_FMUL:
5202*7a6dacacSDimitry Andric   case TargetOpcode::G_SHL:
5203*7a6dacacSDimitry Andric   case TargetOpcode::G_ASHR:
5204*7a6dacacSDimitry Andric   case TargetOpcode::G_LSHR: {
52050b57cec5SDimitry Andric     Observer.changingInstr(MI);
52060b57cec5SDimitry Andric     moreElementsVectorSrc(MI, MoreTy, 1);
52070b57cec5SDimitry Andric     moreElementsVectorSrc(MI, MoreTy, 2);
52080b57cec5SDimitry Andric     moreElementsVectorDst(MI, MoreTy, 0);
52090b57cec5SDimitry Andric     Observer.changedInstr(MI);
52100b57cec5SDimitry Andric     return Legalized;
52110b57cec5SDimitry Andric   }
52120eae32dcSDimitry Andric   case TargetOpcode::G_FMA:
5213bdd1243dSDimitry Andric   case TargetOpcode::G_STRICT_FMA:
52140eae32dcSDimitry Andric   case TargetOpcode::G_FSHR:
52150eae32dcSDimitry Andric   case TargetOpcode::G_FSHL: {
52160eae32dcSDimitry Andric     Observer.changingInstr(MI);
52170eae32dcSDimitry Andric     moreElementsVectorSrc(MI, MoreTy, 1);
52180eae32dcSDimitry Andric     moreElementsVectorSrc(MI, MoreTy, 2);
52190eae32dcSDimitry Andric     moreElementsVectorSrc(MI, MoreTy, 3);
52200eae32dcSDimitry Andric     moreElementsVectorDst(MI, MoreTy, 0);
52210eae32dcSDimitry Andric     Observer.changedInstr(MI);
52220eae32dcSDimitry Andric     return Legalized;
52230eae32dcSDimitry Andric   }
522406c3fb27SDimitry Andric   case TargetOpcode::G_EXTRACT_VECTOR_ELT:
52250b57cec5SDimitry Andric   case TargetOpcode::G_EXTRACT:
52260b57cec5SDimitry Andric     if (TypeIdx != 1)
52270b57cec5SDimitry Andric       return UnableToLegalize;
52280b57cec5SDimitry Andric     Observer.changingInstr(MI);
52290b57cec5SDimitry Andric     moreElementsVectorSrc(MI, MoreTy, 1);
52300b57cec5SDimitry Andric     Observer.changedInstr(MI);
52310b57cec5SDimitry Andric     return Legalized;
52320b57cec5SDimitry Andric   case TargetOpcode::G_INSERT:
523306c3fb27SDimitry Andric   case TargetOpcode::G_INSERT_VECTOR_ELT:
52345ffd83dbSDimitry Andric   case TargetOpcode::G_FREEZE:
52350eae32dcSDimitry Andric   case TargetOpcode::G_FNEG:
52360eae32dcSDimitry Andric   case TargetOpcode::G_FABS:
52375f757f3fSDimitry Andric   case TargetOpcode::G_FSQRT:
52385f757f3fSDimitry Andric   case TargetOpcode::G_FCEIL:
52395f757f3fSDimitry Andric   case TargetOpcode::G_FFLOOR:
52405f757f3fSDimitry Andric   case TargetOpcode::G_FNEARBYINT:
52415f757f3fSDimitry Andric   case TargetOpcode::G_FRINT:
52425f757f3fSDimitry Andric   case TargetOpcode::G_INTRINSIC_ROUND:
52435f757f3fSDimitry Andric   case TargetOpcode::G_INTRINSIC_ROUNDEVEN:
52445f757f3fSDimitry Andric   case TargetOpcode::G_INTRINSIC_TRUNC:
52450eae32dcSDimitry Andric   case TargetOpcode::G_BSWAP:
52460eae32dcSDimitry Andric   case TargetOpcode::G_FCANONICALIZE:
52470eae32dcSDimitry Andric   case TargetOpcode::G_SEXT_INREG:
52480b57cec5SDimitry Andric     if (TypeIdx != 0)
52490b57cec5SDimitry Andric       return UnableToLegalize;
52500b57cec5SDimitry Andric     Observer.changingInstr(MI);
52510b57cec5SDimitry Andric     moreElementsVectorSrc(MI, MoreTy, 1);
52520b57cec5SDimitry Andric     moreElementsVectorDst(MI, MoreTy, 0);
52530b57cec5SDimitry Andric     Observer.changedInstr(MI);
52540b57cec5SDimitry Andric     return Legalized;
525581ad6265SDimitry Andric   case TargetOpcode::G_SELECT: {
525606c3fb27SDimitry Andric     auto [DstReg, DstTy, CondReg, CondTy] = MI.getFirst2RegLLTs();
525781ad6265SDimitry Andric     if (TypeIdx == 1) {
525881ad6265SDimitry Andric       if (!CondTy.isScalar() ||
525981ad6265SDimitry Andric           DstTy.getElementCount() != MoreTy.getElementCount())
52600b57cec5SDimitry Andric         return UnableToLegalize;
526181ad6265SDimitry Andric 
526281ad6265SDimitry Andric       // This is turning a scalar select of vectors into a vector
526381ad6265SDimitry Andric       // select. Broadcast the select condition.
526481ad6265SDimitry Andric       auto ShufSplat = MIRBuilder.buildShuffleSplat(MoreTy, CondReg);
526581ad6265SDimitry Andric       Observer.changingInstr(MI);
526681ad6265SDimitry Andric       MI.getOperand(1).setReg(ShufSplat.getReg(0));
526781ad6265SDimitry Andric       Observer.changedInstr(MI);
526881ad6265SDimitry Andric       return Legalized;
526981ad6265SDimitry Andric     }
527081ad6265SDimitry Andric 
527181ad6265SDimitry Andric     if (CondTy.isVector())
52720b57cec5SDimitry Andric       return UnableToLegalize;
52730b57cec5SDimitry Andric 
52740b57cec5SDimitry Andric     Observer.changingInstr(MI);
52750b57cec5SDimitry Andric     moreElementsVectorSrc(MI, MoreTy, 2);
52760b57cec5SDimitry Andric     moreElementsVectorSrc(MI, MoreTy, 3);
52770b57cec5SDimitry Andric     moreElementsVectorDst(MI, MoreTy, 0);
52780b57cec5SDimitry Andric     Observer.changedInstr(MI);
52790b57cec5SDimitry Andric     return Legalized;
528081ad6265SDimitry Andric   }
52810eae32dcSDimitry Andric   case TargetOpcode::G_UNMERGE_VALUES:
52828bcb0991SDimitry Andric     return UnableToLegalize;
52830b57cec5SDimitry Andric   case TargetOpcode::G_PHI:
52840b57cec5SDimitry Andric     return moreElementsVectorPhi(MI, TypeIdx, MoreTy);
5285fe6060f1SDimitry Andric   case TargetOpcode::G_SHUFFLE_VECTOR:
5286fe6060f1SDimitry Andric     return moreElementsVectorShuffle(MI, TypeIdx, MoreTy);
52870eae32dcSDimitry Andric   case TargetOpcode::G_BUILD_VECTOR: {
52880eae32dcSDimitry Andric     SmallVector<SrcOp, 8> Elts;
52890eae32dcSDimitry Andric     for (auto Op : MI.uses()) {
52900eae32dcSDimitry Andric       Elts.push_back(Op.getReg());
52910eae32dcSDimitry Andric     }
52920eae32dcSDimitry Andric 
52930eae32dcSDimitry Andric     for (unsigned i = Elts.size(); i < MoreTy.getNumElements(); ++i) {
52940eae32dcSDimitry Andric       Elts.push_back(MIRBuilder.buildUndef(MoreTy.getScalarType()));
52950eae32dcSDimitry Andric     }
52960eae32dcSDimitry Andric 
52970eae32dcSDimitry Andric     MIRBuilder.buildDeleteTrailingVectorElements(
52980eae32dcSDimitry Andric         MI.getOperand(0).getReg(), MIRBuilder.buildInstr(Opc, {MoreTy}, Elts));
52990eae32dcSDimitry Andric     MI.eraseFromParent();
53000eae32dcSDimitry Andric     return Legalized;
53010eae32dcSDimitry Andric   }
53025f757f3fSDimitry Andric   case TargetOpcode::G_TRUNC:
530306c3fb27SDimitry Andric   case TargetOpcode::G_FPTRUNC:
53045f757f3fSDimitry Andric   case TargetOpcode::G_FPEXT:
53055f757f3fSDimitry Andric   case TargetOpcode::G_FPTOSI:
53065f757f3fSDimitry Andric   case TargetOpcode::G_FPTOUI:
53075f757f3fSDimitry Andric   case TargetOpcode::G_SITOFP:
53085f757f3fSDimitry Andric   case TargetOpcode::G_UITOFP: {
530906c3fb27SDimitry Andric     if (TypeIdx != 0)
531006c3fb27SDimitry Andric       return UnableToLegalize;
531106c3fb27SDimitry Andric     Observer.changingInstr(MI);
531206c3fb27SDimitry Andric     LLT SrcTy = LLT::fixed_vector(
531306c3fb27SDimitry Andric         MoreTy.getNumElements(),
531406c3fb27SDimitry Andric         MRI.getType(MI.getOperand(1).getReg()).getElementType());
531506c3fb27SDimitry Andric     moreElementsVectorSrc(MI, SrcTy, 1);
531606c3fb27SDimitry Andric     moreElementsVectorDst(MI, MoreTy, 0);
531706c3fb27SDimitry Andric     Observer.changedInstr(MI);
531806c3fb27SDimitry Andric     return Legalized;
531906c3fb27SDimitry Andric   }
5320*7a6dacacSDimitry Andric   case TargetOpcode::G_ICMP: {
5321*7a6dacacSDimitry Andric     // TODO: the symmetric MoreTy works for targets like, e.g. NEON.
5322*7a6dacacSDimitry Andric     // For targets, like e.g. MVE, the result is a predicated vector (i1).
5323*7a6dacacSDimitry Andric     // This will need some refactoring.
5324*7a6dacacSDimitry Andric     Observer.changingInstr(MI);
5325*7a6dacacSDimitry Andric     moreElementsVectorSrc(MI, MoreTy, 2);
5326*7a6dacacSDimitry Andric     moreElementsVectorSrc(MI, MoreTy, 3);
5327*7a6dacacSDimitry Andric     moreElementsVectorDst(MI, MoreTy, 0);
5328*7a6dacacSDimitry Andric     Observer.changedInstr(MI);
5329*7a6dacacSDimitry Andric     return Legalized;
5330*7a6dacacSDimitry Andric   }
53310b57cec5SDimitry Andric   default:
53320b57cec5SDimitry Andric     return UnableToLegalize;
53330b57cec5SDimitry Andric   }
53340b57cec5SDimitry Andric }
53350b57cec5SDimitry Andric 
533606c3fb27SDimitry Andric LegalizerHelper::LegalizeResult
533706c3fb27SDimitry Andric LegalizerHelper::equalizeVectorShuffleLengths(MachineInstr &MI) {
533806c3fb27SDimitry Andric   auto [DstReg, DstTy, SrcReg, SrcTy] = MI.getFirst2RegLLTs();
5339bdd1243dSDimitry Andric   ArrayRef<int> Mask = MI.getOperand(3).getShuffleMask();
5340bdd1243dSDimitry Andric   unsigned MaskNumElts = Mask.size();
5341bdd1243dSDimitry Andric   unsigned SrcNumElts = SrcTy.getNumElements();
5342bdd1243dSDimitry Andric   LLT DestEltTy = DstTy.getElementType();
5343bdd1243dSDimitry Andric 
534406c3fb27SDimitry Andric   if (MaskNumElts == SrcNumElts)
534506c3fb27SDimitry Andric     return Legalized;
534606c3fb27SDimitry Andric 
534706c3fb27SDimitry Andric   if (MaskNumElts < SrcNumElts) {
534806c3fb27SDimitry Andric     // Extend mask to match new destination vector size with
534906c3fb27SDimitry Andric     // undef values.
535006c3fb27SDimitry Andric     SmallVector<int, 16> NewMask(Mask);
535106c3fb27SDimitry Andric     for (unsigned I = MaskNumElts; I < SrcNumElts; ++I)
535206c3fb27SDimitry Andric       NewMask.push_back(-1);
535306c3fb27SDimitry Andric 
535406c3fb27SDimitry Andric     moreElementsVectorDst(MI, SrcTy, 0);
535506c3fb27SDimitry Andric     MIRBuilder.setInstrAndDebugLoc(MI);
535606c3fb27SDimitry Andric     MIRBuilder.buildShuffleVector(MI.getOperand(0).getReg(),
535706c3fb27SDimitry Andric                                   MI.getOperand(1).getReg(),
535806c3fb27SDimitry Andric                                   MI.getOperand(2).getReg(), NewMask);
535906c3fb27SDimitry Andric     MI.eraseFromParent();
536006c3fb27SDimitry Andric 
536106c3fb27SDimitry Andric     return Legalized;
5362bdd1243dSDimitry Andric   }
5363bdd1243dSDimitry Andric 
5364bdd1243dSDimitry Andric   unsigned PaddedMaskNumElts = alignTo(MaskNumElts, SrcNumElts);
5365bdd1243dSDimitry Andric   unsigned NumConcat = PaddedMaskNumElts / SrcNumElts;
5366bdd1243dSDimitry Andric   LLT PaddedTy = LLT::fixed_vector(PaddedMaskNumElts, DestEltTy);
5367bdd1243dSDimitry Andric 
5368bdd1243dSDimitry Andric   // Create new source vectors by concatenating the initial
5369bdd1243dSDimitry Andric   // source vectors with undefined vectors of the same size.
5370bdd1243dSDimitry Andric   auto Undef = MIRBuilder.buildUndef(SrcTy);
5371bdd1243dSDimitry Andric   SmallVector<Register, 8> MOps1(NumConcat, Undef.getReg(0));
5372bdd1243dSDimitry Andric   SmallVector<Register, 8> MOps2(NumConcat, Undef.getReg(0));
5373bdd1243dSDimitry Andric   MOps1[0] = MI.getOperand(1).getReg();
5374bdd1243dSDimitry Andric   MOps2[0] = MI.getOperand(2).getReg();
5375bdd1243dSDimitry Andric 
5376bdd1243dSDimitry Andric   auto Src1 = MIRBuilder.buildConcatVectors(PaddedTy, MOps1);
5377bdd1243dSDimitry Andric   auto Src2 = MIRBuilder.buildConcatVectors(PaddedTy, MOps2);
5378bdd1243dSDimitry Andric 
5379bdd1243dSDimitry Andric   // Readjust mask for new input vector length.
5380bdd1243dSDimitry Andric   SmallVector<int, 8> MappedOps(PaddedMaskNumElts, -1);
5381bdd1243dSDimitry Andric   for (unsigned I = 0; I != MaskNumElts; ++I) {
5382bdd1243dSDimitry Andric     int Idx = Mask[I];
5383bdd1243dSDimitry Andric     if (Idx >= static_cast<int>(SrcNumElts))
5384bdd1243dSDimitry Andric       Idx += PaddedMaskNumElts - SrcNumElts;
5385bdd1243dSDimitry Andric     MappedOps[I] = Idx;
5386bdd1243dSDimitry Andric   }
5387bdd1243dSDimitry Andric 
5388bdd1243dSDimitry Andric   // If we got more elements than required, extract subvector.
5389bdd1243dSDimitry Andric   if (MaskNumElts != PaddedMaskNumElts) {
5390bdd1243dSDimitry Andric     auto Shuffle =
5391bdd1243dSDimitry Andric         MIRBuilder.buildShuffleVector(PaddedTy, Src1, Src2, MappedOps);
5392bdd1243dSDimitry Andric 
5393bdd1243dSDimitry Andric     SmallVector<Register, 16> Elts(MaskNumElts);
5394bdd1243dSDimitry Andric     for (unsigned I = 0; I < MaskNumElts; ++I) {
5395bdd1243dSDimitry Andric       Elts[I] =
5396bdd1243dSDimitry Andric           MIRBuilder.buildExtractVectorElementConstant(DestEltTy, Shuffle, I)
5397bdd1243dSDimitry Andric               .getReg(0);
5398bdd1243dSDimitry Andric     }
5399bdd1243dSDimitry Andric     MIRBuilder.buildBuildVector(DstReg, Elts);
5400bdd1243dSDimitry Andric   } else {
5401bdd1243dSDimitry Andric     MIRBuilder.buildShuffleVector(DstReg, Src1, Src2, MappedOps);
5402bdd1243dSDimitry Andric   }
5403bdd1243dSDimitry Andric 
5404bdd1243dSDimitry Andric   MI.eraseFromParent();
5405bdd1243dSDimitry Andric   return LegalizerHelper::LegalizeResult::Legalized;
5406bdd1243dSDimitry Andric }
5407bdd1243dSDimitry Andric 
5408fe6060f1SDimitry Andric LegalizerHelper::LegalizeResult
5409fe6060f1SDimitry Andric LegalizerHelper::moreElementsVectorShuffle(MachineInstr &MI,
5410fe6060f1SDimitry Andric                                            unsigned int TypeIdx, LLT MoreTy) {
541106c3fb27SDimitry Andric   auto [DstTy, Src1Ty, Src2Ty] = MI.getFirst3LLTs();
5412fe6060f1SDimitry Andric   ArrayRef<int> Mask = MI.getOperand(3).getShuffleMask();
5413fe6060f1SDimitry Andric   unsigned NumElts = DstTy.getNumElements();
5414fe6060f1SDimitry Andric   unsigned WidenNumElts = MoreTy.getNumElements();
5415fe6060f1SDimitry Andric 
5416bdd1243dSDimitry Andric   if (DstTy.isVector() && Src1Ty.isVector() &&
541706c3fb27SDimitry Andric       DstTy.getNumElements() != Src1Ty.getNumElements()) {
541806c3fb27SDimitry Andric     return equalizeVectorShuffleLengths(MI);
5419bdd1243dSDimitry Andric   }
5420bdd1243dSDimitry Andric 
5421bdd1243dSDimitry Andric   if (TypeIdx != 0)
5422bdd1243dSDimitry Andric     return UnableToLegalize;
5423bdd1243dSDimitry Andric 
5424fe6060f1SDimitry Andric   // Expect a canonicalized shuffle.
5425fe6060f1SDimitry Andric   if (DstTy != Src1Ty || DstTy != Src2Ty)
5426fe6060f1SDimitry Andric     return UnableToLegalize;
5427fe6060f1SDimitry Andric 
5428fe6060f1SDimitry Andric   moreElementsVectorSrc(MI, MoreTy, 1);
5429fe6060f1SDimitry Andric   moreElementsVectorSrc(MI, MoreTy, 2);
5430fe6060f1SDimitry Andric 
5431fe6060f1SDimitry Andric   // Adjust mask based on new input vector length.
5432fe6060f1SDimitry Andric   SmallVector<int, 16> NewMask;
5433fe6060f1SDimitry Andric   for (unsigned I = 0; I != NumElts; ++I) {
5434fe6060f1SDimitry Andric     int Idx = Mask[I];
5435fe6060f1SDimitry Andric     if (Idx < static_cast<int>(NumElts))
5436fe6060f1SDimitry Andric       NewMask.push_back(Idx);
5437fe6060f1SDimitry Andric     else
5438fe6060f1SDimitry Andric       NewMask.push_back(Idx - NumElts + WidenNumElts);
5439fe6060f1SDimitry Andric   }
5440fe6060f1SDimitry Andric   for (unsigned I = NumElts; I != WidenNumElts; ++I)
5441fe6060f1SDimitry Andric     NewMask.push_back(-1);
5442fe6060f1SDimitry Andric   moreElementsVectorDst(MI, MoreTy, 0);
5443fe6060f1SDimitry Andric   MIRBuilder.setInstrAndDebugLoc(MI);
5444fe6060f1SDimitry Andric   MIRBuilder.buildShuffleVector(MI.getOperand(0).getReg(),
5445fe6060f1SDimitry Andric                                 MI.getOperand(1).getReg(),
5446fe6060f1SDimitry Andric                                 MI.getOperand(2).getReg(), NewMask);
5447fe6060f1SDimitry Andric   MI.eraseFromParent();
5448fe6060f1SDimitry Andric   return Legalized;
5449fe6060f1SDimitry Andric }
5450fe6060f1SDimitry Andric 
54510b57cec5SDimitry Andric void LegalizerHelper::multiplyRegisters(SmallVectorImpl<Register> &DstRegs,
54520b57cec5SDimitry Andric                                         ArrayRef<Register> Src1Regs,
54530b57cec5SDimitry Andric                                         ArrayRef<Register> Src2Regs,
54540b57cec5SDimitry Andric                                         LLT NarrowTy) {
54550b57cec5SDimitry Andric   MachineIRBuilder &B = MIRBuilder;
54560b57cec5SDimitry Andric   unsigned SrcParts = Src1Regs.size();
54570b57cec5SDimitry Andric   unsigned DstParts = DstRegs.size();
54580b57cec5SDimitry Andric 
54590b57cec5SDimitry Andric   unsigned DstIdx = 0; // Low bits of the result.
54600b57cec5SDimitry Andric   Register FactorSum =
54610b57cec5SDimitry Andric       B.buildMul(NarrowTy, Src1Regs[DstIdx], Src2Regs[DstIdx]).getReg(0);
54620b57cec5SDimitry Andric   DstRegs[DstIdx] = FactorSum;
54630b57cec5SDimitry Andric 
54640b57cec5SDimitry Andric   unsigned CarrySumPrevDstIdx;
54650b57cec5SDimitry Andric   SmallVector<Register, 4> Factors;
54660b57cec5SDimitry Andric 
54670b57cec5SDimitry Andric   for (DstIdx = 1; DstIdx < DstParts; DstIdx++) {
54680b57cec5SDimitry Andric     // Collect low parts of muls for DstIdx.
54690b57cec5SDimitry Andric     for (unsigned i = DstIdx + 1 < SrcParts ? 0 : DstIdx - SrcParts + 1;
54700b57cec5SDimitry Andric          i <= std::min(DstIdx, SrcParts - 1); ++i) {
54710b57cec5SDimitry Andric       MachineInstrBuilder Mul =
54720b57cec5SDimitry Andric           B.buildMul(NarrowTy, Src1Regs[DstIdx - i], Src2Regs[i]);
54730b57cec5SDimitry Andric       Factors.push_back(Mul.getReg(0));
54740b57cec5SDimitry Andric     }
54750b57cec5SDimitry Andric     // Collect high parts of muls from previous DstIdx.
54760b57cec5SDimitry Andric     for (unsigned i = DstIdx < SrcParts ? 0 : DstIdx - SrcParts;
54770b57cec5SDimitry Andric          i <= std::min(DstIdx - 1, SrcParts - 1); ++i) {
54780b57cec5SDimitry Andric       MachineInstrBuilder Umulh =
54790b57cec5SDimitry Andric           B.buildUMulH(NarrowTy, Src1Regs[DstIdx - 1 - i], Src2Regs[i]);
54800b57cec5SDimitry Andric       Factors.push_back(Umulh.getReg(0));
54810b57cec5SDimitry Andric     }
5482480093f4SDimitry Andric     // Add CarrySum from additions calculated for previous DstIdx.
54830b57cec5SDimitry Andric     if (DstIdx != 1) {
54840b57cec5SDimitry Andric       Factors.push_back(CarrySumPrevDstIdx);
54850b57cec5SDimitry Andric     }
54860b57cec5SDimitry Andric 
54870b57cec5SDimitry Andric     Register CarrySum;
54880b57cec5SDimitry Andric     // Add all factors and accumulate all carries into CarrySum.
54890b57cec5SDimitry Andric     if (DstIdx != DstParts - 1) {
54900b57cec5SDimitry Andric       MachineInstrBuilder Uaddo =
54910b57cec5SDimitry Andric           B.buildUAddo(NarrowTy, LLT::scalar(1), Factors[0], Factors[1]);
54920b57cec5SDimitry Andric       FactorSum = Uaddo.getReg(0);
54930b57cec5SDimitry Andric       CarrySum = B.buildZExt(NarrowTy, Uaddo.getReg(1)).getReg(0);
54940b57cec5SDimitry Andric       for (unsigned i = 2; i < Factors.size(); ++i) {
54950b57cec5SDimitry Andric         MachineInstrBuilder Uaddo =
54960b57cec5SDimitry Andric             B.buildUAddo(NarrowTy, LLT::scalar(1), FactorSum, Factors[i]);
54970b57cec5SDimitry Andric         FactorSum = Uaddo.getReg(0);
54980b57cec5SDimitry Andric         MachineInstrBuilder Carry = B.buildZExt(NarrowTy, Uaddo.getReg(1));
54990b57cec5SDimitry Andric         CarrySum = B.buildAdd(NarrowTy, CarrySum, Carry).getReg(0);
55000b57cec5SDimitry Andric       }
55010b57cec5SDimitry Andric     } else {
55020b57cec5SDimitry Andric       // Since value for the next index is not calculated, neither is CarrySum.
55030b57cec5SDimitry Andric       FactorSum = B.buildAdd(NarrowTy, Factors[0], Factors[1]).getReg(0);
55040b57cec5SDimitry Andric       for (unsigned i = 2; i < Factors.size(); ++i)
55050b57cec5SDimitry Andric         FactorSum = B.buildAdd(NarrowTy, FactorSum, Factors[i]).getReg(0);
55060b57cec5SDimitry Andric     }
55070b57cec5SDimitry Andric 
55080b57cec5SDimitry Andric     CarrySumPrevDstIdx = CarrySum;
55090b57cec5SDimitry Andric     DstRegs[DstIdx] = FactorSum;
55100b57cec5SDimitry Andric     Factors.clear();
55110b57cec5SDimitry Andric   }
55120b57cec5SDimitry Andric }
55130b57cec5SDimitry Andric 
55140b57cec5SDimitry Andric LegalizerHelper::LegalizeResult
5515fe6060f1SDimitry Andric LegalizerHelper::narrowScalarAddSub(MachineInstr &MI, unsigned TypeIdx,
5516fe6060f1SDimitry Andric                                     LLT NarrowTy) {
5517fe6060f1SDimitry Andric   if (TypeIdx != 0)
5518fe6060f1SDimitry Andric     return UnableToLegalize;
5519fe6060f1SDimitry Andric 
5520fe6060f1SDimitry Andric   Register DstReg = MI.getOperand(0).getReg();
5521fe6060f1SDimitry Andric   LLT DstType = MRI.getType(DstReg);
5522fe6060f1SDimitry Andric   // FIXME: add support for vector types
5523fe6060f1SDimitry Andric   if (DstType.isVector())
5524fe6060f1SDimitry Andric     return UnableToLegalize;
5525fe6060f1SDimitry Andric 
5526fe6060f1SDimitry Andric   unsigned Opcode = MI.getOpcode();
5527fe6060f1SDimitry Andric   unsigned OpO, OpE, OpF;
5528fe6060f1SDimitry Andric   switch (Opcode) {
5529fe6060f1SDimitry Andric   case TargetOpcode::G_SADDO:
5530fe6060f1SDimitry Andric   case TargetOpcode::G_SADDE:
5531fe6060f1SDimitry Andric   case TargetOpcode::G_UADDO:
5532fe6060f1SDimitry Andric   case TargetOpcode::G_UADDE:
5533fe6060f1SDimitry Andric   case TargetOpcode::G_ADD:
5534fe6060f1SDimitry Andric     OpO = TargetOpcode::G_UADDO;
5535fe6060f1SDimitry Andric     OpE = TargetOpcode::G_UADDE;
5536fe6060f1SDimitry Andric     OpF = TargetOpcode::G_UADDE;
5537fe6060f1SDimitry Andric     if (Opcode == TargetOpcode::G_SADDO || Opcode == TargetOpcode::G_SADDE)
5538fe6060f1SDimitry Andric       OpF = TargetOpcode::G_SADDE;
5539fe6060f1SDimitry Andric     break;
5540fe6060f1SDimitry Andric   case TargetOpcode::G_SSUBO:
5541fe6060f1SDimitry Andric   case TargetOpcode::G_SSUBE:
5542fe6060f1SDimitry Andric   case TargetOpcode::G_USUBO:
5543fe6060f1SDimitry Andric   case TargetOpcode::G_USUBE:
5544fe6060f1SDimitry Andric   case TargetOpcode::G_SUB:
5545fe6060f1SDimitry Andric     OpO = TargetOpcode::G_USUBO;
5546fe6060f1SDimitry Andric     OpE = TargetOpcode::G_USUBE;
5547fe6060f1SDimitry Andric     OpF = TargetOpcode::G_USUBE;
5548fe6060f1SDimitry Andric     if (Opcode == TargetOpcode::G_SSUBO || Opcode == TargetOpcode::G_SSUBE)
5549fe6060f1SDimitry Andric       OpF = TargetOpcode::G_SSUBE;
5550fe6060f1SDimitry Andric     break;
5551fe6060f1SDimitry Andric   default:
5552fe6060f1SDimitry Andric     llvm_unreachable("Unexpected add/sub opcode!");
5553fe6060f1SDimitry Andric   }
5554fe6060f1SDimitry Andric 
5555fe6060f1SDimitry Andric   // 1 for a plain add/sub, 2 if this is an operation with a carry-out.
5556fe6060f1SDimitry Andric   unsigned NumDefs = MI.getNumExplicitDefs();
5557fe6060f1SDimitry Andric   Register Src1 = MI.getOperand(NumDefs).getReg();
5558fe6060f1SDimitry Andric   Register Src2 = MI.getOperand(NumDefs + 1).getReg();
5559fe6060f1SDimitry Andric   Register CarryDst, CarryIn;
5560fe6060f1SDimitry Andric   if (NumDefs == 2)
5561fe6060f1SDimitry Andric     CarryDst = MI.getOperand(1).getReg();
5562fe6060f1SDimitry Andric   if (MI.getNumOperands() == NumDefs + 3)
5563fe6060f1SDimitry Andric     CarryIn = MI.getOperand(NumDefs + 2).getReg();
5564fe6060f1SDimitry Andric 
5565fe6060f1SDimitry Andric   LLT RegTy = MRI.getType(MI.getOperand(0).getReg());
5566fe6060f1SDimitry Andric   LLT LeftoverTy, DummyTy;
5567fe6060f1SDimitry Andric   SmallVector<Register, 2> Src1Regs, Src2Regs, Src1Left, Src2Left, DstRegs;
5568*7a6dacacSDimitry Andric   extractParts(Src1, RegTy, NarrowTy, LeftoverTy, Src1Regs, Src1Left,
5569*7a6dacacSDimitry Andric                MIRBuilder, MRI);
5570*7a6dacacSDimitry Andric   extractParts(Src2, RegTy, NarrowTy, DummyTy, Src2Regs, Src2Left, MIRBuilder,
5571*7a6dacacSDimitry Andric                MRI);
5572fe6060f1SDimitry Andric 
5573fe6060f1SDimitry Andric   int NarrowParts = Src1Regs.size();
5574fe6060f1SDimitry Andric   for (int I = 0, E = Src1Left.size(); I != E; ++I) {
5575fe6060f1SDimitry Andric     Src1Regs.push_back(Src1Left[I]);
5576fe6060f1SDimitry Andric     Src2Regs.push_back(Src2Left[I]);
5577fe6060f1SDimitry Andric   }
5578fe6060f1SDimitry Andric   DstRegs.reserve(Src1Regs.size());
5579fe6060f1SDimitry Andric 
5580fe6060f1SDimitry Andric   for (int i = 0, e = Src1Regs.size(); i != e; ++i) {
5581fe6060f1SDimitry Andric     Register DstReg =
5582fe6060f1SDimitry Andric         MRI.createGenericVirtualRegister(MRI.getType(Src1Regs[i]));
5583fe6060f1SDimitry Andric     Register CarryOut = MRI.createGenericVirtualRegister(LLT::scalar(1));
5584fe6060f1SDimitry Andric     // Forward the final carry-out to the destination register
5585fe6060f1SDimitry Andric     if (i == e - 1 && CarryDst)
5586fe6060f1SDimitry Andric       CarryOut = CarryDst;
5587fe6060f1SDimitry Andric 
5588fe6060f1SDimitry Andric     if (!CarryIn) {
5589fe6060f1SDimitry Andric       MIRBuilder.buildInstr(OpO, {DstReg, CarryOut},
5590fe6060f1SDimitry Andric                             {Src1Regs[i], Src2Regs[i]});
5591fe6060f1SDimitry Andric     } else if (i == e - 1) {
5592fe6060f1SDimitry Andric       MIRBuilder.buildInstr(OpF, {DstReg, CarryOut},
5593fe6060f1SDimitry Andric                             {Src1Regs[i], Src2Regs[i], CarryIn});
5594fe6060f1SDimitry Andric     } else {
5595fe6060f1SDimitry Andric       MIRBuilder.buildInstr(OpE, {DstReg, CarryOut},
5596fe6060f1SDimitry Andric                             {Src1Regs[i], Src2Regs[i], CarryIn});
5597fe6060f1SDimitry Andric     }
5598fe6060f1SDimitry Andric 
5599fe6060f1SDimitry Andric     DstRegs.push_back(DstReg);
5600fe6060f1SDimitry Andric     CarryIn = CarryOut;
5601fe6060f1SDimitry Andric   }
5602fe6060f1SDimitry Andric   insertParts(MI.getOperand(0).getReg(), RegTy, NarrowTy,
5603bdd1243dSDimitry Andric               ArrayRef(DstRegs).take_front(NarrowParts), LeftoverTy,
5604bdd1243dSDimitry Andric               ArrayRef(DstRegs).drop_front(NarrowParts));
5605fe6060f1SDimitry Andric 
5606fe6060f1SDimitry Andric   MI.eraseFromParent();
5607fe6060f1SDimitry Andric   return Legalized;
5608fe6060f1SDimitry Andric }
5609fe6060f1SDimitry Andric 
5610fe6060f1SDimitry Andric LegalizerHelper::LegalizeResult
56110b57cec5SDimitry Andric LegalizerHelper::narrowScalarMul(MachineInstr &MI, LLT NarrowTy) {
561206c3fb27SDimitry Andric   auto [DstReg, Src1, Src2] = MI.getFirst3Regs();
56130b57cec5SDimitry Andric 
56140b57cec5SDimitry Andric   LLT Ty = MRI.getType(DstReg);
56150b57cec5SDimitry Andric   if (Ty.isVector())
56160b57cec5SDimitry Andric     return UnableToLegalize;
56170b57cec5SDimitry Andric 
5618349cc55cSDimitry Andric   unsigned Size = Ty.getSizeInBits();
56190b57cec5SDimitry Andric   unsigned NarrowSize = NarrowTy.getSizeInBits();
5620349cc55cSDimitry Andric   if (Size % NarrowSize != 0)
56210b57cec5SDimitry Andric     return UnableToLegalize;
56220b57cec5SDimitry Andric 
5623349cc55cSDimitry Andric   unsigned NumParts = Size / NarrowSize;
56240b57cec5SDimitry Andric   bool IsMulHigh = MI.getOpcode() == TargetOpcode::G_UMULH;
5625349cc55cSDimitry Andric   unsigned DstTmpParts = NumParts * (IsMulHigh ? 2 : 1);
56260b57cec5SDimitry Andric 
56275ffd83dbSDimitry Andric   SmallVector<Register, 2> Src1Parts, Src2Parts;
56285ffd83dbSDimitry Andric   SmallVector<Register, 2> DstTmpRegs(DstTmpParts);
5629*7a6dacacSDimitry Andric   extractParts(Src1, NarrowTy, NumParts, Src1Parts, MIRBuilder, MRI);
5630*7a6dacacSDimitry Andric   extractParts(Src2, NarrowTy, NumParts, Src2Parts, MIRBuilder, MRI);
56310b57cec5SDimitry Andric   multiplyRegisters(DstTmpRegs, Src1Parts, Src2Parts, NarrowTy);
56320b57cec5SDimitry Andric 
56330b57cec5SDimitry Andric   // Take only high half of registers if this is high mul.
5634349cc55cSDimitry Andric   ArrayRef<Register> DstRegs(&DstTmpRegs[DstTmpParts - NumParts], NumParts);
5635bdd1243dSDimitry Andric   MIRBuilder.buildMergeLikeInstr(DstReg, DstRegs);
56360b57cec5SDimitry Andric   MI.eraseFromParent();
56370b57cec5SDimitry Andric   return Legalized;
56380b57cec5SDimitry Andric }
56390b57cec5SDimitry Andric 
56400b57cec5SDimitry Andric LegalizerHelper::LegalizeResult
564123408297SDimitry Andric LegalizerHelper::narrowScalarFPTOI(MachineInstr &MI, unsigned TypeIdx,
564223408297SDimitry Andric                                    LLT NarrowTy) {
564323408297SDimitry Andric   if (TypeIdx != 0)
564423408297SDimitry Andric     return UnableToLegalize;
564523408297SDimitry Andric 
564623408297SDimitry Andric   bool IsSigned = MI.getOpcode() == TargetOpcode::G_FPTOSI;
564723408297SDimitry Andric 
564823408297SDimitry Andric   Register Src = MI.getOperand(1).getReg();
564923408297SDimitry Andric   LLT SrcTy = MRI.getType(Src);
565023408297SDimitry Andric 
565123408297SDimitry Andric   // If all finite floats fit into the narrowed integer type, we can just swap
565223408297SDimitry Andric   // out the result type. This is practically only useful for conversions from
565323408297SDimitry Andric   // half to at least 16-bits, so just handle the one case.
565423408297SDimitry Andric   if (SrcTy.getScalarType() != LLT::scalar(16) ||
5655fe6060f1SDimitry Andric       NarrowTy.getScalarSizeInBits() < (IsSigned ? 17u : 16u))
565623408297SDimitry Andric     return UnableToLegalize;
565723408297SDimitry Andric 
565823408297SDimitry Andric   Observer.changingInstr(MI);
565923408297SDimitry Andric   narrowScalarDst(MI, NarrowTy, 0,
566023408297SDimitry Andric                   IsSigned ? TargetOpcode::G_SEXT : TargetOpcode::G_ZEXT);
566123408297SDimitry Andric   Observer.changedInstr(MI);
566223408297SDimitry Andric   return Legalized;
566323408297SDimitry Andric }
566423408297SDimitry Andric 
566523408297SDimitry Andric LegalizerHelper::LegalizeResult
56660b57cec5SDimitry Andric LegalizerHelper::narrowScalarExtract(MachineInstr &MI, unsigned TypeIdx,
56670b57cec5SDimitry Andric                                      LLT NarrowTy) {
56680b57cec5SDimitry Andric   if (TypeIdx != 1)
56690b57cec5SDimitry Andric     return UnableToLegalize;
56700b57cec5SDimitry Andric 
56710b57cec5SDimitry Andric   uint64_t NarrowSize = NarrowTy.getSizeInBits();
56720b57cec5SDimitry Andric 
56730b57cec5SDimitry Andric   int64_t SizeOp1 = MRI.getType(MI.getOperand(1).getReg()).getSizeInBits();
56740b57cec5SDimitry Andric   // FIXME: add support for when SizeOp1 isn't an exact multiple of
56750b57cec5SDimitry Andric   // NarrowSize.
56760b57cec5SDimitry Andric   if (SizeOp1 % NarrowSize != 0)
56770b57cec5SDimitry Andric     return UnableToLegalize;
56780b57cec5SDimitry Andric   int NumParts = SizeOp1 / NarrowSize;
56790b57cec5SDimitry Andric 
56800b57cec5SDimitry Andric   SmallVector<Register, 2> SrcRegs, DstRegs;
56810b57cec5SDimitry Andric   SmallVector<uint64_t, 2> Indexes;
5682*7a6dacacSDimitry Andric   extractParts(MI.getOperand(1).getReg(), NarrowTy, NumParts, SrcRegs,
5683*7a6dacacSDimitry Andric                MIRBuilder, MRI);
56840b57cec5SDimitry Andric 
56850b57cec5SDimitry Andric   Register OpReg = MI.getOperand(0).getReg();
56860b57cec5SDimitry Andric   uint64_t OpStart = MI.getOperand(2).getImm();
56870b57cec5SDimitry Andric   uint64_t OpSize = MRI.getType(OpReg).getSizeInBits();
56880b57cec5SDimitry Andric   for (int i = 0; i < NumParts; ++i) {
56890b57cec5SDimitry Andric     unsigned SrcStart = i * NarrowSize;
56900b57cec5SDimitry Andric 
56910b57cec5SDimitry Andric     if (SrcStart + NarrowSize <= OpStart || SrcStart >= OpStart + OpSize) {
56920b57cec5SDimitry Andric       // No part of the extract uses this subregister, ignore it.
56930b57cec5SDimitry Andric       continue;
56940b57cec5SDimitry Andric     } else if (SrcStart == OpStart && NarrowTy == MRI.getType(OpReg)) {
56950b57cec5SDimitry Andric       // The entire subregister is extracted, forward the value.
56960b57cec5SDimitry Andric       DstRegs.push_back(SrcRegs[i]);
56970b57cec5SDimitry Andric       continue;
56980b57cec5SDimitry Andric     }
56990b57cec5SDimitry Andric 
57000b57cec5SDimitry Andric     // OpSegStart is where this destination segment would start in OpReg if it
57010b57cec5SDimitry Andric     // extended infinitely in both directions.
57020b57cec5SDimitry Andric     int64_t ExtractOffset;
57030b57cec5SDimitry Andric     uint64_t SegSize;
57040b57cec5SDimitry Andric     if (OpStart < SrcStart) {
57050b57cec5SDimitry Andric       ExtractOffset = 0;
57060b57cec5SDimitry Andric       SegSize = std::min(NarrowSize, OpStart + OpSize - SrcStart);
57070b57cec5SDimitry Andric     } else {
57080b57cec5SDimitry Andric       ExtractOffset = OpStart - SrcStart;
57090b57cec5SDimitry Andric       SegSize = std::min(SrcStart + NarrowSize - OpStart, OpSize);
57100b57cec5SDimitry Andric     }
57110b57cec5SDimitry Andric 
57120b57cec5SDimitry Andric     Register SegReg = SrcRegs[i];
57130b57cec5SDimitry Andric     if (ExtractOffset != 0 || SegSize != NarrowSize) {
57140b57cec5SDimitry Andric       // A genuine extract is needed.
57150b57cec5SDimitry Andric       SegReg = MRI.createGenericVirtualRegister(LLT::scalar(SegSize));
57160b57cec5SDimitry Andric       MIRBuilder.buildExtract(SegReg, SrcRegs[i], ExtractOffset);
57170b57cec5SDimitry Andric     }
57180b57cec5SDimitry Andric 
57190b57cec5SDimitry Andric     DstRegs.push_back(SegReg);
57200b57cec5SDimitry Andric   }
57210b57cec5SDimitry Andric 
57220b57cec5SDimitry Andric   Register DstReg = MI.getOperand(0).getReg();
57230b57cec5SDimitry Andric   if (MRI.getType(DstReg).isVector())
57240b57cec5SDimitry Andric     MIRBuilder.buildBuildVector(DstReg, DstRegs);
57255ffd83dbSDimitry Andric   else if (DstRegs.size() > 1)
5726bdd1243dSDimitry Andric     MIRBuilder.buildMergeLikeInstr(DstReg, DstRegs);
57275ffd83dbSDimitry Andric   else
57285ffd83dbSDimitry Andric     MIRBuilder.buildCopy(DstReg, DstRegs[0]);
57290b57cec5SDimitry Andric   MI.eraseFromParent();
57300b57cec5SDimitry Andric   return Legalized;
57310b57cec5SDimitry Andric }
57320b57cec5SDimitry Andric 
57330b57cec5SDimitry Andric LegalizerHelper::LegalizeResult
57340b57cec5SDimitry Andric LegalizerHelper::narrowScalarInsert(MachineInstr &MI, unsigned TypeIdx,
57350b57cec5SDimitry Andric                                     LLT NarrowTy) {
57360b57cec5SDimitry Andric   // FIXME: Don't know how to handle secondary types yet.
57370b57cec5SDimitry Andric   if (TypeIdx != 0)
57380b57cec5SDimitry Andric     return UnableToLegalize;
57390b57cec5SDimitry Andric 
5740fe6060f1SDimitry Andric   SmallVector<Register, 2> SrcRegs, LeftoverRegs, DstRegs;
57410b57cec5SDimitry Andric   SmallVector<uint64_t, 2> Indexes;
5742fe6060f1SDimitry Andric   LLT RegTy = MRI.getType(MI.getOperand(0).getReg());
5743fe6060f1SDimitry Andric   LLT LeftoverTy;
5744fe6060f1SDimitry Andric   extractParts(MI.getOperand(1).getReg(), RegTy, NarrowTy, LeftoverTy, SrcRegs,
5745*7a6dacacSDimitry Andric                LeftoverRegs, MIRBuilder, MRI);
57460b57cec5SDimitry Andric 
5747fe6060f1SDimitry Andric   for (Register Reg : LeftoverRegs)
5748fe6060f1SDimitry Andric     SrcRegs.push_back(Reg);
5749fe6060f1SDimitry Andric 
5750fe6060f1SDimitry Andric   uint64_t NarrowSize = NarrowTy.getSizeInBits();
57510b57cec5SDimitry Andric   Register OpReg = MI.getOperand(2).getReg();
57520b57cec5SDimitry Andric   uint64_t OpStart = MI.getOperand(3).getImm();
57530b57cec5SDimitry Andric   uint64_t OpSize = MRI.getType(OpReg).getSizeInBits();
5754fe6060f1SDimitry Andric   for (int I = 0, E = SrcRegs.size(); I != E; ++I) {
5755fe6060f1SDimitry Andric     unsigned DstStart = I * NarrowSize;
57560b57cec5SDimitry Andric 
5757fe6060f1SDimitry Andric     if (DstStart == OpStart && NarrowTy == MRI.getType(OpReg)) {
57580b57cec5SDimitry Andric       // The entire subregister is defined by this insert, forward the new
57590b57cec5SDimitry Andric       // value.
57600b57cec5SDimitry Andric       DstRegs.push_back(OpReg);
57610b57cec5SDimitry Andric       continue;
57620b57cec5SDimitry Andric     }
57630b57cec5SDimitry Andric 
5764fe6060f1SDimitry Andric     Register SrcReg = SrcRegs[I];
5765fe6060f1SDimitry Andric     if (MRI.getType(SrcRegs[I]) == LeftoverTy) {
5766fe6060f1SDimitry Andric       // The leftover reg is smaller than NarrowTy, so we need to extend it.
5767fe6060f1SDimitry Andric       SrcReg = MRI.createGenericVirtualRegister(NarrowTy);
5768fe6060f1SDimitry Andric       MIRBuilder.buildAnyExt(SrcReg, SrcRegs[I]);
5769fe6060f1SDimitry Andric     }
5770fe6060f1SDimitry Andric 
5771fe6060f1SDimitry Andric     if (DstStart + NarrowSize <= OpStart || DstStart >= OpStart + OpSize) {
5772fe6060f1SDimitry Andric       // No part of the insert affects this subregister, forward the original.
5773fe6060f1SDimitry Andric       DstRegs.push_back(SrcReg);
5774fe6060f1SDimitry Andric       continue;
5775fe6060f1SDimitry Andric     }
5776fe6060f1SDimitry Andric 
57770b57cec5SDimitry Andric     // OpSegStart is where this destination segment would start in OpReg if it
57780b57cec5SDimitry Andric     // extended infinitely in both directions.
57790b57cec5SDimitry Andric     int64_t ExtractOffset, InsertOffset;
57800b57cec5SDimitry Andric     uint64_t SegSize;
57810b57cec5SDimitry Andric     if (OpStart < DstStart) {
57820b57cec5SDimitry Andric       InsertOffset = 0;
57830b57cec5SDimitry Andric       ExtractOffset = DstStart - OpStart;
57840b57cec5SDimitry Andric       SegSize = std::min(NarrowSize, OpStart + OpSize - DstStart);
57850b57cec5SDimitry Andric     } else {
57860b57cec5SDimitry Andric       InsertOffset = OpStart - DstStart;
57870b57cec5SDimitry Andric       ExtractOffset = 0;
57880b57cec5SDimitry Andric       SegSize =
57890b57cec5SDimitry Andric         std::min(NarrowSize - InsertOffset, OpStart + OpSize - DstStart);
57900b57cec5SDimitry Andric     }
57910b57cec5SDimitry Andric 
57920b57cec5SDimitry Andric     Register SegReg = OpReg;
57930b57cec5SDimitry Andric     if (ExtractOffset != 0 || SegSize != OpSize) {
57940b57cec5SDimitry Andric       // A genuine extract is needed.
57950b57cec5SDimitry Andric       SegReg = MRI.createGenericVirtualRegister(LLT::scalar(SegSize));
57960b57cec5SDimitry Andric       MIRBuilder.buildExtract(SegReg, OpReg, ExtractOffset);
57970b57cec5SDimitry Andric     }
57980b57cec5SDimitry Andric 
57990b57cec5SDimitry Andric     Register DstReg = MRI.createGenericVirtualRegister(NarrowTy);
5800fe6060f1SDimitry Andric     MIRBuilder.buildInsert(DstReg, SrcReg, SegReg, InsertOffset);
58010b57cec5SDimitry Andric     DstRegs.push_back(DstReg);
58020b57cec5SDimitry Andric   }
58030b57cec5SDimitry Andric 
5804fe6060f1SDimitry Andric   uint64_t WideSize = DstRegs.size() * NarrowSize;
58050b57cec5SDimitry Andric   Register DstReg = MI.getOperand(0).getReg();
5806fe6060f1SDimitry Andric   if (WideSize > RegTy.getSizeInBits()) {
5807fe6060f1SDimitry Andric     Register MergeReg = MRI.createGenericVirtualRegister(LLT::scalar(WideSize));
5808bdd1243dSDimitry Andric     MIRBuilder.buildMergeLikeInstr(MergeReg, DstRegs);
5809fe6060f1SDimitry Andric     MIRBuilder.buildTrunc(DstReg, MergeReg);
5810fe6060f1SDimitry Andric   } else
5811bdd1243dSDimitry Andric     MIRBuilder.buildMergeLikeInstr(DstReg, DstRegs);
5812fe6060f1SDimitry Andric 
58130b57cec5SDimitry Andric   MI.eraseFromParent();
58140b57cec5SDimitry Andric   return Legalized;
58150b57cec5SDimitry Andric }
58160b57cec5SDimitry Andric 
58170b57cec5SDimitry Andric LegalizerHelper::LegalizeResult
58180b57cec5SDimitry Andric LegalizerHelper::narrowScalarBasic(MachineInstr &MI, unsigned TypeIdx,
58190b57cec5SDimitry Andric                                    LLT NarrowTy) {
58200b57cec5SDimitry Andric   Register DstReg = MI.getOperand(0).getReg();
58210b57cec5SDimitry Andric   LLT DstTy = MRI.getType(DstReg);
58220b57cec5SDimitry Andric 
58230b57cec5SDimitry Andric   assert(MI.getNumOperands() == 3 && TypeIdx == 0);
58240b57cec5SDimitry Andric 
58250b57cec5SDimitry Andric   SmallVector<Register, 4> DstRegs, DstLeftoverRegs;
58260b57cec5SDimitry Andric   SmallVector<Register, 4> Src0Regs, Src0LeftoverRegs;
58270b57cec5SDimitry Andric   SmallVector<Register, 4> Src1Regs, Src1LeftoverRegs;
58280b57cec5SDimitry Andric   LLT LeftoverTy;
58290b57cec5SDimitry Andric   if (!extractParts(MI.getOperand(1).getReg(), DstTy, NarrowTy, LeftoverTy,
5830*7a6dacacSDimitry Andric                     Src0Regs, Src0LeftoverRegs, MIRBuilder, MRI))
58310b57cec5SDimitry Andric     return UnableToLegalize;
58320b57cec5SDimitry Andric 
58330b57cec5SDimitry Andric   LLT Unused;
58340b57cec5SDimitry Andric   if (!extractParts(MI.getOperand(2).getReg(), DstTy, NarrowTy, Unused,
5835*7a6dacacSDimitry Andric                     Src1Regs, Src1LeftoverRegs, MIRBuilder, MRI))
58360b57cec5SDimitry Andric     llvm_unreachable("inconsistent extractParts result");
58370b57cec5SDimitry Andric 
58380b57cec5SDimitry Andric   for (unsigned I = 0, E = Src1Regs.size(); I != E; ++I) {
58390b57cec5SDimitry Andric     auto Inst = MIRBuilder.buildInstr(MI.getOpcode(), {NarrowTy},
58400b57cec5SDimitry Andric                                         {Src0Regs[I], Src1Regs[I]});
58415ffd83dbSDimitry Andric     DstRegs.push_back(Inst.getReg(0));
58420b57cec5SDimitry Andric   }
58430b57cec5SDimitry Andric 
58440b57cec5SDimitry Andric   for (unsigned I = 0, E = Src1LeftoverRegs.size(); I != E; ++I) {
58450b57cec5SDimitry Andric     auto Inst = MIRBuilder.buildInstr(
58460b57cec5SDimitry Andric       MI.getOpcode(),
58470b57cec5SDimitry Andric       {LeftoverTy}, {Src0LeftoverRegs[I], Src1LeftoverRegs[I]});
58485ffd83dbSDimitry Andric     DstLeftoverRegs.push_back(Inst.getReg(0));
58490b57cec5SDimitry Andric   }
58500b57cec5SDimitry Andric 
58510b57cec5SDimitry Andric   insertParts(DstReg, DstTy, NarrowTy, DstRegs,
58520b57cec5SDimitry Andric               LeftoverTy, DstLeftoverRegs);
58530b57cec5SDimitry Andric 
58540b57cec5SDimitry Andric   MI.eraseFromParent();
58550b57cec5SDimitry Andric   return Legalized;
58560b57cec5SDimitry Andric }
58570b57cec5SDimitry Andric 
58580b57cec5SDimitry Andric LegalizerHelper::LegalizeResult
58595ffd83dbSDimitry Andric LegalizerHelper::narrowScalarExt(MachineInstr &MI, unsigned TypeIdx,
58605ffd83dbSDimitry Andric                                  LLT NarrowTy) {
58615ffd83dbSDimitry Andric   if (TypeIdx != 0)
58625ffd83dbSDimitry Andric     return UnableToLegalize;
58635ffd83dbSDimitry Andric 
586406c3fb27SDimitry Andric   auto [DstReg, SrcReg] = MI.getFirst2Regs();
58655ffd83dbSDimitry Andric 
58665ffd83dbSDimitry Andric   LLT DstTy = MRI.getType(DstReg);
58675ffd83dbSDimitry Andric   if (DstTy.isVector())
58685ffd83dbSDimitry Andric     return UnableToLegalize;
58695ffd83dbSDimitry Andric 
58705ffd83dbSDimitry Andric   SmallVector<Register, 8> Parts;
58715ffd83dbSDimitry Andric   LLT GCDTy = extractGCDType(Parts, DstTy, NarrowTy, SrcReg);
58725ffd83dbSDimitry Andric   LLT LCMTy = buildLCMMergePieces(DstTy, NarrowTy, GCDTy, Parts, MI.getOpcode());
58735ffd83dbSDimitry Andric   buildWidenedRemergeToDst(DstReg, LCMTy, Parts);
58745ffd83dbSDimitry Andric 
58755ffd83dbSDimitry Andric   MI.eraseFromParent();
58765ffd83dbSDimitry Andric   return Legalized;
58775ffd83dbSDimitry Andric }
58785ffd83dbSDimitry Andric 
58795ffd83dbSDimitry Andric LegalizerHelper::LegalizeResult
58800b57cec5SDimitry Andric LegalizerHelper::narrowScalarSelect(MachineInstr &MI, unsigned TypeIdx,
58810b57cec5SDimitry Andric                                     LLT NarrowTy) {
58820b57cec5SDimitry Andric   if (TypeIdx != 0)
58830b57cec5SDimitry Andric     return UnableToLegalize;
58840b57cec5SDimitry Andric 
58850b57cec5SDimitry Andric   Register CondReg = MI.getOperand(1).getReg();
58860b57cec5SDimitry Andric   LLT CondTy = MRI.getType(CondReg);
58870b57cec5SDimitry Andric   if (CondTy.isVector()) // TODO: Handle vselect
58880b57cec5SDimitry Andric     return UnableToLegalize;
58890b57cec5SDimitry Andric 
58900b57cec5SDimitry Andric   Register DstReg = MI.getOperand(0).getReg();
58910b57cec5SDimitry Andric   LLT DstTy = MRI.getType(DstReg);
58920b57cec5SDimitry Andric 
58930b57cec5SDimitry Andric   SmallVector<Register, 4> DstRegs, DstLeftoverRegs;
58940b57cec5SDimitry Andric   SmallVector<Register, 4> Src1Regs, Src1LeftoverRegs;
58950b57cec5SDimitry Andric   SmallVector<Register, 4> Src2Regs, Src2LeftoverRegs;
58960b57cec5SDimitry Andric   LLT LeftoverTy;
58970b57cec5SDimitry Andric   if (!extractParts(MI.getOperand(2).getReg(), DstTy, NarrowTy, LeftoverTy,
5898*7a6dacacSDimitry Andric                     Src1Regs, Src1LeftoverRegs, MIRBuilder, MRI))
58990b57cec5SDimitry Andric     return UnableToLegalize;
59000b57cec5SDimitry Andric 
59010b57cec5SDimitry Andric   LLT Unused;
59020b57cec5SDimitry Andric   if (!extractParts(MI.getOperand(3).getReg(), DstTy, NarrowTy, Unused,
5903*7a6dacacSDimitry Andric                     Src2Regs, Src2LeftoverRegs, MIRBuilder, MRI))
59040b57cec5SDimitry Andric     llvm_unreachable("inconsistent extractParts result");
59050b57cec5SDimitry Andric 
59060b57cec5SDimitry Andric   for (unsigned I = 0, E = Src1Regs.size(); I != E; ++I) {
59070b57cec5SDimitry Andric     auto Select = MIRBuilder.buildSelect(NarrowTy,
59080b57cec5SDimitry Andric                                          CondReg, Src1Regs[I], Src2Regs[I]);
59095ffd83dbSDimitry Andric     DstRegs.push_back(Select.getReg(0));
59100b57cec5SDimitry Andric   }
59110b57cec5SDimitry Andric 
59120b57cec5SDimitry Andric   for (unsigned I = 0, E = Src1LeftoverRegs.size(); I != E; ++I) {
59130b57cec5SDimitry Andric     auto Select = MIRBuilder.buildSelect(
59140b57cec5SDimitry Andric       LeftoverTy, CondReg, Src1LeftoverRegs[I], Src2LeftoverRegs[I]);
59155ffd83dbSDimitry Andric     DstLeftoverRegs.push_back(Select.getReg(0));
59160b57cec5SDimitry Andric   }
59170b57cec5SDimitry Andric 
59180b57cec5SDimitry Andric   insertParts(DstReg, DstTy, NarrowTy, DstRegs,
59190b57cec5SDimitry Andric               LeftoverTy, DstLeftoverRegs);
59200b57cec5SDimitry Andric 
59210b57cec5SDimitry Andric   MI.eraseFromParent();
59220b57cec5SDimitry Andric   return Legalized;
59230b57cec5SDimitry Andric }
59240b57cec5SDimitry Andric 
59250b57cec5SDimitry Andric LegalizerHelper::LegalizeResult
59265ffd83dbSDimitry Andric LegalizerHelper::narrowScalarCTLZ(MachineInstr &MI, unsigned TypeIdx,
59275ffd83dbSDimitry Andric                                   LLT NarrowTy) {
59285ffd83dbSDimitry Andric   if (TypeIdx != 1)
59295ffd83dbSDimitry Andric     return UnableToLegalize;
59305ffd83dbSDimitry Andric 
593106c3fb27SDimitry Andric   auto [DstReg, DstTy, SrcReg, SrcTy] = MI.getFirst2RegLLTs();
59325ffd83dbSDimitry Andric   unsigned NarrowSize = NarrowTy.getSizeInBits();
59335ffd83dbSDimitry Andric 
59345ffd83dbSDimitry Andric   if (SrcTy.isScalar() && SrcTy.getSizeInBits() == 2 * NarrowSize) {
59355ffd83dbSDimitry Andric     const bool IsUndef = MI.getOpcode() == TargetOpcode::G_CTLZ_ZERO_UNDEF;
59365ffd83dbSDimitry Andric 
59375ffd83dbSDimitry Andric     MachineIRBuilder &B = MIRBuilder;
59385ffd83dbSDimitry Andric     auto UnmergeSrc = B.buildUnmerge(NarrowTy, SrcReg);
59395ffd83dbSDimitry Andric     // ctlz(Hi:Lo) -> Hi == 0 ? (NarrowSize + ctlz(Lo)) : ctlz(Hi)
59405ffd83dbSDimitry Andric     auto C_0 = B.buildConstant(NarrowTy, 0);
59415ffd83dbSDimitry Andric     auto HiIsZero = B.buildICmp(CmpInst::ICMP_EQ, LLT::scalar(1),
59425ffd83dbSDimitry Andric                                 UnmergeSrc.getReg(1), C_0);
59435ffd83dbSDimitry Andric     auto LoCTLZ = IsUndef ?
59445ffd83dbSDimitry Andric       B.buildCTLZ_ZERO_UNDEF(DstTy, UnmergeSrc.getReg(0)) :
59455ffd83dbSDimitry Andric       B.buildCTLZ(DstTy, UnmergeSrc.getReg(0));
59465ffd83dbSDimitry Andric     auto C_NarrowSize = B.buildConstant(DstTy, NarrowSize);
59475ffd83dbSDimitry Andric     auto HiIsZeroCTLZ = B.buildAdd(DstTy, LoCTLZ, C_NarrowSize);
59485ffd83dbSDimitry Andric     auto HiCTLZ = B.buildCTLZ_ZERO_UNDEF(DstTy, UnmergeSrc.getReg(1));
59495ffd83dbSDimitry Andric     B.buildSelect(DstReg, HiIsZero, HiIsZeroCTLZ, HiCTLZ);
59505ffd83dbSDimitry Andric 
59515ffd83dbSDimitry Andric     MI.eraseFromParent();
59525ffd83dbSDimitry Andric     return Legalized;
59535ffd83dbSDimitry Andric   }
59545ffd83dbSDimitry Andric 
59555ffd83dbSDimitry Andric   return UnableToLegalize;
59565ffd83dbSDimitry Andric }
59575ffd83dbSDimitry Andric 
59585ffd83dbSDimitry Andric LegalizerHelper::LegalizeResult
59595ffd83dbSDimitry Andric LegalizerHelper::narrowScalarCTTZ(MachineInstr &MI, unsigned TypeIdx,
59605ffd83dbSDimitry Andric                                   LLT NarrowTy) {
59615ffd83dbSDimitry Andric   if (TypeIdx != 1)
59625ffd83dbSDimitry Andric     return UnableToLegalize;
59635ffd83dbSDimitry Andric 
596406c3fb27SDimitry Andric   auto [DstReg, DstTy, SrcReg, SrcTy] = MI.getFirst2RegLLTs();
59655ffd83dbSDimitry Andric   unsigned NarrowSize = NarrowTy.getSizeInBits();
59665ffd83dbSDimitry Andric 
59675ffd83dbSDimitry Andric   if (SrcTy.isScalar() && SrcTy.getSizeInBits() == 2 * NarrowSize) {
59685ffd83dbSDimitry Andric     const bool IsUndef = MI.getOpcode() == TargetOpcode::G_CTTZ_ZERO_UNDEF;
59695ffd83dbSDimitry Andric 
59705ffd83dbSDimitry Andric     MachineIRBuilder &B = MIRBuilder;
59715ffd83dbSDimitry Andric     auto UnmergeSrc = B.buildUnmerge(NarrowTy, SrcReg);
59725ffd83dbSDimitry Andric     // cttz(Hi:Lo) -> Lo == 0 ? (cttz(Hi) + NarrowSize) : cttz(Lo)
59735ffd83dbSDimitry Andric     auto C_0 = B.buildConstant(NarrowTy, 0);
59745ffd83dbSDimitry Andric     auto LoIsZero = B.buildICmp(CmpInst::ICMP_EQ, LLT::scalar(1),
59755ffd83dbSDimitry Andric                                 UnmergeSrc.getReg(0), C_0);
59765ffd83dbSDimitry Andric     auto HiCTTZ = IsUndef ?
59775ffd83dbSDimitry Andric       B.buildCTTZ_ZERO_UNDEF(DstTy, UnmergeSrc.getReg(1)) :
59785ffd83dbSDimitry Andric       B.buildCTTZ(DstTy, UnmergeSrc.getReg(1));
59795ffd83dbSDimitry Andric     auto C_NarrowSize = B.buildConstant(DstTy, NarrowSize);
59805ffd83dbSDimitry Andric     auto LoIsZeroCTTZ = B.buildAdd(DstTy, HiCTTZ, C_NarrowSize);
59815ffd83dbSDimitry Andric     auto LoCTTZ = B.buildCTTZ_ZERO_UNDEF(DstTy, UnmergeSrc.getReg(0));
59825ffd83dbSDimitry Andric     B.buildSelect(DstReg, LoIsZero, LoIsZeroCTTZ, LoCTTZ);
59835ffd83dbSDimitry Andric 
59845ffd83dbSDimitry Andric     MI.eraseFromParent();
59855ffd83dbSDimitry Andric     return Legalized;
59865ffd83dbSDimitry Andric   }
59875ffd83dbSDimitry Andric 
59885ffd83dbSDimitry Andric   return UnableToLegalize;
59895ffd83dbSDimitry Andric }
59905ffd83dbSDimitry Andric 
59915ffd83dbSDimitry Andric LegalizerHelper::LegalizeResult
59925ffd83dbSDimitry Andric LegalizerHelper::narrowScalarCTPOP(MachineInstr &MI, unsigned TypeIdx,
59935ffd83dbSDimitry Andric                                    LLT NarrowTy) {
59945ffd83dbSDimitry Andric   if (TypeIdx != 1)
59955ffd83dbSDimitry Andric     return UnableToLegalize;
59965ffd83dbSDimitry Andric 
599706c3fb27SDimitry Andric   auto [DstReg, DstTy, SrcReg, SrcTy] = MI.getFirst2RegLLTs();
59985ffd83dbSDimitry Andric   unsigned NarrowSize = NarrowTy.getSizeInBits();
59995ffd83dbSDimitry Andric 
60005ffd83dbSDimitry Andric   if (SrcTy.isScalar() && SrcTy.getSizeInBits() == 2 * NarrowSize) {
60015ffd83dbSDimitry Andric     auto UnmergeSrc = MIRBuilder.buildUnmerge(NarrowTy, MI.getOperand(1));
60025ffd83dbSDimitry Andric 
60035ffd83dbSDimitry Andric     auto LoCTPOP = MIRBuilder.buildCTPOP(DstTy, UnmergeSrc.getReg(0));
60045ffd83dbSDimitry Andric     auto HiCTPOP = MIRBuilder.buildCTPOP(DstTy, UnmergeSrc.getReg(1));
60055ffd83dbSDimitry Andric     MIRBuilder.buildAdd(DstReg, HiCTPOP, LoCTPOP);
60065ffd83dbSDimitry Andric 
60075ffd83dbSDimitry Andric     MI.eraseFromParent();
60085ffd83dbSDimitry Andric     return Legalized;
60095ffd83dbSDimitry Andric   }
60105ffd83dbSDimitry Andric 
60115ffd83dbSDimitry Andric   return UnableToLegalize;
60125ffd83dbSDimitry Andric }
60135ffd83dbSDimitry Andric 
60145ffd83dbSDimitry Andric LegalizerHelper::LegalizeResult
601506c3fb27SDimitry Andric LegalizerHelper::narrowScalarFLDEXP(MachineInstr &MI, unsigned TypeIdx,
601606c3fb27SDimitry Andric                                     LLT NarrowTy) {
601706c3fb27SDimitry Andric   if (TypeIdx != 1)
601806c3fb27SDimitry Andric     return UnableToLegalize;
601906c3fb27SDimitry Andric 
602006c3fb27SDimitry Andric   MachineIRBuilder &B = MIRBuilder;
602106c3fb27SDimitry Andric   Register ExpReg = MI.getOperand(2).getReg();
602206c3fb27SDimitry Andric   LLT ExpTy = MRI.getType(ExpReg);
602306c3fb27SDimitry Andric 
602406c3fb27SDimitry Andric   unsigned ClampSize = NarrowTy.getScalarSizeInBits();
602506c3fb27SDimitry Andric 
602606c3fb27SDimitry Andric   // Clamp the exponent to the range of the target type.
602706c3fb27SDimitry Andric   auto MinExp = B.buildConstant(ExpTy, minIntN(ClampSize));
602806c3fb27SDimitry Andric   auto ClampMin = B.buildSMax(ExpTy, ExpReg, MinExp);
602906c3fb27SDimitry Andric   auto MaxExp = B.buildConstant(ExpTy, maxIntN(ClampSize));
603006c3fb27SDimitry Andric   auto Clamp = B.buildSMin(ExpTy, ClampMin, MaxExp);
603106c3fb27SDimitry Andric 
603206c3fb27SDimitry Andric   auto Trunc = B.buildTrunc(NarrowTy, Clamp);
603306c3fb27SDimitry Andric   Observer.changingInstr(MI);
603406c3fb27SDimitry Andric   MI.getOperand(2).setReg(Trunc.getReg(0));
603506c3fb27SDimitry Andric   Observer.changedInstr(MI);
603606c3fb27SDimitry Andric   return Legalized;
603706c3fb27SDimitry Andric }
603806c3fb27SDimitry Andric 
603906c3fb27SDimitry Andric LegalizerHelper::LegalizeResult
6040e8d8bef9SDimitry Andric LegalizerHelper::lowerBitCount(MachineInstr &MI) {
60410b57cec5SDimitry Andric   unsigned Opc = MI.getOpcode();
6042e8d8bef9SDimitry Andric   const auto &TII = MIRBuilder.getTII();
60430b57cec5SDimitry Andric   auto isSupported = [this](const LegalityQuery &Q) {
60440b57cec5SDimitry Andric     auto QAction = LI.getAction(Q).Action;
60450b57cec5SDimitry Andric     return QAction == Legal || QAction == Libcall || QAction == Custom;
60460b57cec5SDimitry Andric   };
60470b57cec5SDimitry Andric   switch (Opc) {
60480b57cec5SDimitry Andric   default:
60490b57cec5SDimitry Andric     return UnableToLegalize;
60500b57cec5SDimitry Andric   case TargetOpcode::G_CTLZ_ZERO_UNDEF: {
60510b57cec5SDimitry Andric     // This trivially expands to CTLZ.
60520b57cec5SDimitry Andric     Observer.changingInstr(MI);
60530b57cec5SDimitry Andric     MI.setDesc(TII.get(TargetOpcode::G_CTLZ));
60540b57cec5SDimitry Andric     Observer.changedInstr(MI);
60550b57cec5SDimitry Andric     return Legalized;
60560b57cec5SDimitry Andric   }
60570b57cec5SDimitry Andric   case TargetOpcode::G_CTLZ: {
605806c3fb27SDimitry Andric     auto [DstReg, DstTy, SrcReg, SrcTy] = MI.getFirst2RegLLTs();
60595ffd83dbSDimitry Andric     unsigned Len = SrcTy.getSizeInBits();
60605ffd83dbSDimitry Andric 
60615ffd83dbSDimitry Andric     if (isSupported({TargetOpcode::G_CTLZ_ZERO_UNDEF, {DstTy, SrcTy}})) {
60620b57cec5SDimitry Andric       // If CTLZ_ZERO_UNDEF is supported, emit that and a select for zero.
60635ffd83dbSDimitry Andric       auto CtlzZU = MIRBuilder.buildCTLZ_ZERO_UNDEF(DstTy, SrcReg);
60645ffd83dbSDimitry Andric       auto ZeroSrc = MIRBuilder.buildConstant(SrcTy, 0);
60655ffd83dbSDimitry Andric       auto ICmp = MIRBuilder.buildICmp(
60665ffd83dbSDimitry Andric           CmpInst::ICMP_EQ, SrcTy.changeElementSize(1), SrcReg, ZeroSrc);
60675ffd83dbSDimitry Andric       auto LenConst = MIRBuilder.buildConstant(DstTy, Len);
60685ffd83dbSDimitry Andric       MIRBuilder.buildSelect(DstReg, ICmp, LenConst, CtlzZU);
60690b57cec5SDimitry Andric       MI.eraseFromParent();
60700b57cec5SDimitry Andric       return Legalized;
60710b57cec5SDimitry Andric     }
60720b57cec5SDimitry Andric     // for now, we do this:
60730b57cec5SDimitry Andric     // NewLen = NextPowerOf2(Len);
60740b57cec5SDimitry Andric     // x = x | (x >> 1);
60750b57cec5SDimitry Andric     // x = x | (x >> 2);
60760b57cec5SDimitry Andric     // ...
60770b57cec5SDimitry Andric     // x = x | (x >>16);
60780b57cec5SDimitry Andric     // x = x | (x >>32); // for 64-bit input
60790b57cec5SDimitry Andric     // Upto NewLen/2
60800b57cec5SDimitry Andric     // return Len - popcount(x);
60810b57cec5SDimitry Andric     //
60820b57cec5SDimitry Andric     // Ref: "Hacker's Delight" by Henry Warren
60830b57cec5SDimitry Andric     Register Op = SrcReg;
60840b57cec5SDimitry Andric     unsigned NewLen = PowerOf2Ceil(Len);
60850b57cec5SDimitry Andric     for (unsigned i = 0; (1U << i) <= (NewLen / 2); ++i) {
60865ffd83dbSDimitry Andric       auto MIBShiftAmt = MIRBuilder.buildConstant(SrcTy, 1ULL << i);
60875ffd83dbSDimitry Andric       auto MIBOp = MIRBuilder.buildOr(
60885ffd83dbSDimitry Andric           SrcTy, Op, MIRBuilder.buildLShr(SrcTy, Op, MIBShiftAmt));
60895ffd83dbSDimitry Andric       Op = MIBOp.getReg(0);
60900b57cec5SDimitry Andric     }
60915ffd83dbSDimitry Andric     auto MIBPop = MIRBuilder.buildCTPOP(DstTy, Op);
60925ffd83dbSDimitry Andric     MIRBuilder.buildSub(MI.getOperand(0), MIRBuilder.buildConstant(DstTy, Len),
60935ffd83dbSDimitry Andric                         MIBPop);
60940b57cec5SDimitry Andric     MI.eraseFromParent();
60950b57cec5SDimitry Andric     return Legalized;
60960b57cec5SDimitry Andric   }
60970b57cec5SDimitry Andric   case TargetOpcode::G_CTTZ_ZERO_UNDEF: {
60980b57cec5SDimitry Andric     // This trivially expands to CTTZ.
60990b57cec5SDimitry Andric     Observer.changingInstr(MI);
61000b57cec5SDimitry Andric     MI.setDesc(TII.get(TargetOpcode::G_CTTZ));
61010b57cec5SDimitry Andric     Observer.changedInstr(MI);
61020b57cec5SDimitry Andric     return Legalized;
61030b57cec5SDimitry Andric   }
61040b57cec5SDimitry Andric   case TargetOpcode::G_CTTZ: {
610506c3fb27SDimitry Andric     auto [DstReg, DstTy, SrcReg, SrcTy] = MI.getFirst2RegLLTs();
61065ffd83dbSDimitry Andric 
61075ffd83dbSDimitry Andric     unsigned Len = SrcTy.getSizeInBits();
61085ffd83dbSDimitry Andric     if (isSupported({TargetOpcode::G_CTTZ_ZERO_UNDEF, {DstTy, SrcTy}})) {
61090b57cec5SDimitry Andric       // If CTTZ_ZERO_UNDEF is legal or custom, emit that and a select with
61100b57cec5SDimitry Andric       // zero.
61115ffd83dbSDimitry Andric       auto CttzZU = MIRBuilder.buildCTTZ_ZERO_UNDEF(DstTy, SrcReg);
61125ffd83dbSDimitry Andric       auto Zero = MIRBuilder.buildConstant(SrcTy, 0);
61135ffd83dbSDimitry Andric       auto ICmp = MIRBuilder.buildICmp(
61145ffd83dbSDimitry Andric           CmpInst::ICMP_EQ, DstTy.changeElementSize(1), SrcReg, Zero);
61155ffd83dbSDimitry Andric       auto LenConst = MIRBuilder.buildConstant(DstTy, Len);
61165ffd83dbSDimitry Andric       MIRBuilder.buildSelect(DstReg, ICmp, LenConst, CttzZU);
61170b57cec5SDimitry Andric       MI.eraseFromParent();
61180b57cec5SDimitry Andric       return Legalized;
61190b57cec5SDimitry Andric     }
61200b57cec5SDimitry Andric     // for now, we use: { return popcount(~x & (x - 1)); }
61210b57cec5SDimitry Andric     // unless the target has ctlz but not ctpop, in which case we use:
61220b57cec5SDimitry Andric     // { return 32 - nlz(~x & (x-1)); }
61230b57cec5SDimitry Andric     // Ref: "Hacker's Delight" by Henry Warren
6124e8d8bef9SDimitry Andric     auto MIBCstNeg1 = MIRBuilder.buildConstant(SrcTy, -1);
6125e8d8bef9SDimitry Andric     auto MIBNot = MIRBuilder.buildXor(SrcTy, SrcReg, MIBCstNeg1);
61265ffd83dbSDimitry Andric     auto MIBTmp = MIRBuilder.buildAnd(
6127e8d8bef9SDimitry Andric         SrcTy, MIBNot, MIRBuilder.buildAdd(SrcTy, SrcReg, MIBCstNeg1));
6128e8d8bef9SDimitry Andric     if (!isSupported({TargetOpcode::G_CTPOP, {SrcTy, SrcTy}}) &&
6129e8d8bef9SDimitry Andric         isSupported({TargetOpcode::G_CTLZ, {SrcTy, SrcTy}})) {
6130e8d8bef9SDimitry Andric       auto MIBCstLen = MIRBuilder.buildConstant(SrcTy, Len);
61315ffd83dbSDimitry Andric       MIRBuilder.buildSub(MI.getOperand(0), MIBCstLen,
6132e8d8bef9SDimitry Andric                           MIRBuilder.buildCTLZ(SrcTy, MIBTmp));
61330b57cec5SDimitry Andric       MI.eraseFromParent();
61340b57cec5SDimitry Andric       return Legalized;
61350b57cec5SDimitry Andric     }
61365f757f3fSDimitry Andric     Observer.changingInstr(MI);
61370b57cec5SDimitry Andric     MI.setDesc(TII.get(TargetOpcode::G_CTPOP));
61385ffd83dbSDimitry Andric     MI.getOperand(1).setReg(MIBTmp.getReg(0));
61395f757f3fSDimitry Andric     Observer.changedInstr(MI);
61405ffd83dbSDimitry Andric     return Legalized;
61415ffd83dbSDimitry Andric   }
61425ffd83dbSDimitry Andric   case TargetOpcode::G_CTPOP: {
6143e8d8bef9SDimitry Andric     Register SrcReg = MI.getOperand(1).getReg();
6144e8d8bef9SDimitry Andric     LLT Ty = MRI.getType(SrcReg);
61455ffd83dbSDimitry Andric     unsigned Size = Ty.getSizeInBits();
61465ffd83dbSDimitry Andric     MachineIRBuilder &B = MIRBuilder;
61475ffd83dbSDimitry Andric 
61485ffd83dbSDimitry Andric     // Count set bits in blocks of 2 bits. Default approach would be
61495ffd83dbSDimitry Andric     // B2Count = { val & 0x55555555 } + { (val >> 1) & 0x55555555 }
61505ffd83dbSDimitry Andric     // We use following formula instead:
61515ffd83dbSDimitry Andric     // B2Count = val - { (val >> 1) & 0x55555555 }
61525ffd83dbSDimitry Andric     // since it gives same result in blocks of 2 with one instruction less.
61535ffd83dbSDimitry Andric     auto C_1 = B.buildConstant(Ty, 1);
6154e8d8bef9SDimitry Andric     auto B2Set1LoTo1Hi = B.buildLShr(Ty, SrcReg, C_1);
61555ffd83dbSDimitry Andric     APInt B2Mask1HiTo0 = APInt::getSplat(Size, APInt(8, 0x55));
61565ffd83dbSDimitry Andric     auto C_B2Mask1HiTo0 = B.buildConstant(Ty, B2Mask1HiTo0);
61575ffd83dbSDimitry Andric     auto B2Count1Hi = B.buildAnd(Ty, B2Set1LoTo1Hi, C_B2Mask1HiTo0);
6158e8d8bef9SDimitry Andric     auto B2Count = B.buildSub(Ty, SrcReg, B2Count1Hi);
61595ffd83dbSDimitry Andric 
61605ffd83dbSDimitry Andric     // In order to get count in blocks of 4 add values from adjacent block of 2.
61615ffd83dbSDimitry Andric     // B4Count = { B2Count & 0x33333333 } + { (B2Count >> 2) & 0x33333333 }
61625ffd83dbSDimitry Andric     auto C_2 = B.buildConstant(Ty, 2);
61635ffd83dbSDimitry Andric     auto B4Set2LoTo2Hi = B.buildLShr(Ty, B2Count, C_2);
61645ffd83dbSDimitry Andric     APInt B4Mask2HiTo0 = APInt::getSplat(Size, APInt(8, 0x33));
61655ffd83dbSDimitry Andric     auto C_B4Mask2HiTo0 = B.buildConstant(Ty, B4Mask2HiTo0);
61665ffd83dbSDimitry Andric     auto B4HiB2Count = B.buildAnd(Ty, B4Set2LoTo2Hi, C_B4Mask2HiTo0);
61675ffd83dbSDimitry Andric     auto B4LoB2Count = B.buildAnd(Ty, B2Count, C_B4Mask2HiTo0);
61685ffd83dbSDimitry Andric     auto B4Count = B.buildAdd(Ty, B4HiB2Count, B4LoB2Count);
61695ffd83dbSDimitry Andric 
61705ffd83dbSDimitry Andric     // For count in blocks of 8 bits we don't have to mask high 4 bits before
61715ffd83dbSDimitry Andric     // addition since count value sits in range {0,...,8} and 4 bits are enough
61725ffd83dbSDimitry Andric     // to hold such binary values. After addition high 4 bits still hold count
61735ffd83dbSDimitry Andric     // of set bits in high 4 bit block, set them to zero and get 8 bit result.
61745ffd83dbSDimitry Andric     // B8Count = { B4Count + (B4Count >> 4) } & 0x0F0F0F0F
61755ffd83dbSDimitry Andric     auto C_4 = B.buildConstant(Ty, 4);
61765ffd83dbSDimitry Andric     auto B8HiB4Count = B.buildLShr(Ty, B4Count, C_4);
61775ffd83dbSDimitry Andric     auto B8CountDirty4Hi = B.buildAdd(Ty, B8HiB4Count, B4Count);
61785ffd83dbSDimitry Andric     APInt B8Mask4HiTo0 = APInt::getSplat(Size, APInt(8, 0x0F));
61795ffd83dbSDimitry Andric     auto C_B8Mask4HiTo0 = B.buildConstant(Ty, B8Mask4HiTo0);
61805ffd83dbSDimitry Andric     auto B8Count = B.buildAnd(Ty, B8CountDirty4Hi, C_B8Mask4HiTo0);
61815ffd83dbSDimitry Andric 
61825ffd83dbSDimitry Andric     assert(Size<=128 && "Scalar size is too large for CTPOP lower algorithm");
61835ffd83dbSDimitry Andric     // 8 bits can hold CTPOP result of 128 bit int or smaller. Mul with this
61845ffd83dbSDimitry Andric     // bitmask will set 8 msb in ResTmp to sum of all B8Counts in 8 bit blocks.
61855ffd83dbSDimitry Andric     auto MulMask = B.buildConstant(Ty, APInt::getSplat(Size, APInt(8, 0x01)));
61865ffd83dbSDimitry Andric     auto ResTmp = B.buildMul(Ty, B8Count, MulMask);
61875ffd83dbSDimitry Andric 
61885ffd83dbSDimitry Andric     // Shift count result from 8 high bits to low bits.
61895ffd83dbSDimitry Andric     auto C_SizeM8 = B.buildConstant(Ty, Size - 8);
61905ffd83dbSDimitry Andric     B.buildLShr(MI.getOperand(0).getReg(), ResTmp, C_SizeM8);
61915ffd83dbSDimitry Andric 
61925ffd83dbSDimitry Andric     MI.eraseFromParent();
61930b57cec5SDimitry Andric     return Legalized;
61940b57cec5SDimitry Andric   }
61950b57cec5SDimitry Andric   }
61960b57cec5SDimitry Andric }
61970b57cec5SDimitry Andric 
6198fe6060f1SDimitry Andric // Check that (every element of) Reg is undef or not an exact multiple of BW.
6199fe6060f1SDimitry Andric static bool isNonZeroModBitWidthOrUndef(const MachineRegisterInfo &MRI,
6200fe6060f1SDimitry Andric                                         Register Reg, unsigned BW) {
6201fe6060f1SDimitry Andric   return matchUnaryPredicate(
6202fe6060f1SDimitry Andric       MRI, Reg,
6203fe6060f1SDimitry Andric       [=](const Constant *C) {
6204fe6060f1SDimitry Andric         // Null constant here means an undef.
6205fe6060f1SDimitry Andric         const ConstantInt *CI = dyn_cast_or_null<ConstantInt>(C);
6206fe6060f1SDimitry Andric         return !CI || CI->getValue().urem(BW) != 0;
6207fe6060f1SDimitry Andric       },
6208fe6060f1SDimitry Andric       /*AllowUndefs*/ true);
6209fe6060f1SDimitry Andric }
6210fe6060f1SDimitry Andric 
6211fe6060f1SDimitry Andric LegalizerHelper::LegalizeResult
6212fe6060f1SDimitry Andric LegalizerHelper::lowerFunnelShiftWithInverse(MachineInstr &MI) {
621306c3fb27SDimitry Andric   auto [Dst, X, Y, Z] = MI.getFirst4Regs();
6214fe6060f1SDimitry Andric   LLT Ty = MRI.getType(Dst);
6215fe6060f1SDimitry Andric   LLT ShTy = MRI.getType(Z);
6216fe6060f1SDimitry Andric 
6217fe6060f1SDimitry Andric   unsigned BW = Ty.getScalarSizeInBits();
6218fe6060f1SDimitry Andric 
6219fe6060f1SDimitry Andric   if (!isPowerOf2_32(BW))
6220fe6060f1SDimitry Andric     return UnableToLegalize;
6221fe6060f1SDimitry Andric 
6222fe6060f1SDimitry Andric   const bool IsFSHL = MI.getOpcode() == TargetOpcode::G_FSHL;
6223fe6060f1SDimitry Andric   unsigned RevOpcode = IsFSHL ? TargetOpcode::G_FSHR : TargetOpcode::G_FSHL;
6224fe6060f1SDimitry Andric 
6225fe6060f1SDimitry Andric   if (isNonZeroModBitWidthOrUndef(MRI, Z, BW)) {
6226fe6060f1SDimitry Andric     // fshl X, Y, Z -> fshr X, Y, -Z
6227fe6060f1SDimitry Andric     // fshr X, Y, Z -> fshl X, Y, -Z
6228fe6060f1SDimitry Andric     auto Zero = MIRBuilder.buildConstant(ShTy, 0);
6229fe6060f1SDimitry Andric     Z = MIRBuilder.buildSub(Ty, Zero, Z).getReg(0);
6230fe6060f1SDimitry Andric   } else {
6231fe6060f1SDimitry Andric     // fshl X, Y, Z -> fshr (srl X, 1), (fshr X, Y, 1), ~Z
6232fe6060f1SDimitry Andric     // fshr X, Y, Z -> fshl (fshl X, Y, 1), (shl Y, 1), ~Z
6233fe6060f1SDimitry Andric     auto One = MIRBuilder.buildConstant(ShTy, 1);
6234fe6060f1SDimitry Andric     if (IsFSHL) {
6235fe6060f1SDimitry Andric       Y = MIRBuilder.buildInstr(RevOpcode, {Ty}, {X, Y, One}).getReg(0);
6236fe6060f1SDimitry Andric       X = MIRBuilder.buildLShr(Ty, X, One).getReg(0);
6237fe6060f1SDimitry Andric     } else {
6238fe6060f1SDimitry Andric       X = MIRBuilder.buildInstr(RevOpcode, {Ty}, {X, Y, One}).getReg(0);
6239fe6060f1SDimitry Andric       Y = MIRBuilder.buildShl(Ty, Y, One).getReg(0);
6240fe6060f1SDimitry Andric     }
6241fe6060f1SDimitry Andric 
6242fe6060f1SDimitry Andric     Z = MIRBuilder.buildNot(ShTy, Z).getReg(0);
6243fe6060f1SDimitry Andric   }
6244fe6060f1SDimitry Andric 
6245fe6060f1SDimitry Andric   MIRBuilder.buildInstr(RevOpcode, {Dst}, {X, Y, Z});
6246fe6060f1SDimitry Andric   MI.eraseFromParent();
6247fe6060f1SDimitry Andric   return Legalized;
6248fe6060f1SDimitry Andric }
6249fe6060f1SDimitry Andric 
6250fe6060f1SDimitry Andric LegalizerHelper::LegalizeResult
6251fe6060f1SDimitry Andric LegalizerHelper::lowerFunnelShiftAsShifts(MachineInstr &MI) {
625206c3fb27SDimitry Andric   auto [Dst, X, Y, Z] = MI.getFirst4Regs();
6253fe6060f1SDimitry Andric   LLT Ty = MRI.getType(Dst);
6254fe6060f1SDimitry Andric   LLT ShTy = MRI.getType(Z);
6255fe6060f1SDimitry Andric 
6256fe6060f1SDimitry Andric   const unsigned BW = Ty.getScalarSizeInBits();
6257fe6060f1SDimitry Andric   const bool IsFSHL = MI.getOpcode() == TargetOpcode::G_FSHL;
6258fe6060f1SDimitry Andric 
6259fe6060f1SDimitry Andric   Register ShX, ShY;
6260fe6060f1SDimitry Andric   Register ShAmt, InvShAmt;
6261fe6060f1SDimitry Andric 
6262fe6060f1SDimitry Andric   // FIXME: Emit optimized urem by constant instead of letting it expand later.
6263fe6060f1SDimitry Andric   if (isNonZeroModBitWidthOrUndef(MRI, Z, BW)) {
6264fe6060f1SDimitry Andric     // fshl: X << C | Y >> (BW - C)
6265fe6060f1SDimitry Andric     // fshr: X << (BW - C) | Y >> C
6266fe6060f1SDimitry Andric     // where C = Z % BW is not zero
6267fe6060f1SDimitry Andric     auto BitWidthC = MIRBuilder.buildConstant(ShTy, BW);
6268fe6060f1SDimitry Andric     ShAmt = MIRBuilder.buildURem(ShTy, Z, BitWidthC).getReg(0);
6269fe6060f1SDimitry Andric     InvShAmt = MIRBuilder.buildSub(ShTy, BitWidthC, ShAmt).getReg(0);
6270fe6060f1SDimitry Andric     ShX = MIRBuilder.buildShl(Ty, X, IsFSHL ? ShAmt : InvShAmt).getReg(0);
6271fe6060f1SDimitry Andric     ShY = MIRBuilder.buildLShr(Ty, Y, IsFSHL ? InvShAmt : ShAmt).getReg(0);
6272fe6060f1SDimitry Andric   } else {
6273fe6060f1SDimitry Andric     // fshl: X << (Z % BW) | Y >> 1 >> (BW - 1 - (Z % BW))
6274fe6060f1SDimitry Andric     // fshr: X << 1 << (BW - 1 - (Z % BW)) | Y >> (Z % BW)
6275fe6060f1SDimitry Andric     auto Mask = MIRBuilder.buildConstant(ShTy, BW - 1);
6276fe6060f1SDimitry Andric     if (isPowerOf2_32(BW)) {
6277fe6060f1SDimitry Andric       // Z % BW -> Z & (BW - 1)
6278fe6060f1SDimitry Andric       ShAmt = MIRBuilder.buildAnd(ShTy, Z, Mask).getReg(0);
6279fe6060f1SDimitry Andric       // (BW - 1) - (Z % BW) -> ~Z & (BW - 1)
6280fe6060f1SDimitry Andric       auto NotZ = MIRBuilder.buildNot(ShTy, Z);
6281fe6060f1SDimitry Andric       InvShAmt = MIRBuilder.buildAnd(ShTy, NotZ, Mask).getReg(0);
6282fe6060f1SDimitry Andric     } else {
6283fe6060f1SDimitry Andric       auto BitWidthC = MIRBuilder.buildConstant(ShTy, BW);
6284fe6060f1SDimitry Andric       ShAmt = MIRBuilder.buildURem(ShTy, Z, BitWidthC).getReg(0);
6285fe6060f1SDimitry Andric       InvShAmt = MIRBuilder.buildSub(ShTy, Mask, ShAmt).getReg(0);
6286fe6060f1SDimitry Andric     }
6287fe6060f1SDimitry Andric 
6288fe6060f1SDimitry Andric     auto One = MIRBuilder.buildConstant(ShTy, 1);
6289fe6060f1SDimitry Andric     if (IsFSHL) {
6290fe6060f1SDimitry Andric       ShX = MIRBuilder.buildShl(Ty, X, ShAmt).getReg(0);
6291fe6060f1SDimitry Andric       auto ShY1 = MIRBuilder.buildLShr(Ty, Y, One);
6292fe6060f1SDimitry Andric       ShY = MIRBuilder.buildLShr(Ty, ShY1, InvShAmt).getReg(0);
6293fe6060f1SDimitry Andric     } else {
6294fe6060f1SDimitry Andric       auto ShX1 = MIRBuilder.buildShl(Ty, X, One);
6295fe6060f1SDimitry Andric       ShX = MIRBuilder.buildShl(Ty, ShX1, InvShAmt).getReg(0);
6296fe6060f1SDimitry Andric       ShY = MIRBuilder.buildLShr(Ty, Y, ShAmt).getReg(0);
6297fe6060f1SDimitry Andric     }
6298fe6060f1SDimitry Andric   }
6299fe6060f1SDimitry Andric 
6300fe6060f1SDimitry Andric   MIRBuilder.buildOr(Dst, ShX, ShY);
6301fe6060f1SDimitry Andric   MI.eraseFromParent();
6302fe6060f1SDimitry Andric   return Legalized;
6303fe6060f1SDimitry Andric }
6304fe6060f1SDimitry Andric 
6305fe6060f1SDimitry Andric LegalizerHelper::LegalizeResult
6306fe6060f1SDimitry Andric LegalizerHelper::lowerFunnelShift(MachineInstr &MI) {
6307fe6060f1SDimitry Andric   // These operations approximately do the following (while avoiding undefined
6308fe6060f1SDimitry Andric   // shifts by BW):
6309fe6060f1SDimitry Andric   // G_FSHL: (X << (Z % BW)) | (Y >> (BW - (Z % BW)))
6310fe6060f1SDimitry Andric   // G_FSHR: (X << (BW - (Z % BW))) | (Y >> (Z % BW))
6311fe6060f1SDimitry Andric   Register Dst = MI.getOperand(0).getReg();
6312fe6060f1SDimitry Andric   LLT Ty = MRI.getType(Dst);
6313fe6060f1SDimitry Andric   LLT ShTy = MRI.getType(MI.getOperand(3).getReg());
6314fe6060f1SDimitry Andric 
6315fe6060f1SDimitry Andric   bool IsFSHL = MI.getOpcode() == TargetOpcode::G_FSHL;
6316fe6060f1SDimitry Andric   unsigned RevOpcode = IsFSHL ? TargetOpcode::G_FSHR : TargetOpcode::G_FSHL;
6317fe6060f1SDimitry Andric 
6318fe6060f1SDimitry Andric   // TODO: Use smarter heuristic that accounts for vector legalization.
6319fe6060f1SDimitry Andric   if (LI.getAction({RevOpcode, {Ty, ShTy}}).Action == Lower)
6320fe6060f1SDimitry Andric     return lowerFunnelShiftAsShifts(MI);
6321fe6060f1SDimitry Andric 
6322fe6060f1SDimitry Andric   // This only works for powers of 2, fallback to shifts if it fails.
6323fe6060f1SDimitry Andric   LegalizerHelper::LegalizeResult Result = lowerFunnelShiftWithInverse(MI);
6324fe6060f1SDimitry Andric   if (Result == UnableToLegalize)
6325fe6060f1SDimitry Andric     return lowerFunnelShiftAsShifts(MI);
6326fe6060f1SDimitry Andric   return Result;
6327fe6060f1SDimitry Andric }
6328fe6060f1SDimitry Andric 
63295f757f3fSDimitry Andric LegalizerHelper::LegalizeResult LegalizerHelper::lowerEXT(MachineInstr &MI) {
63305f757f3fSDimitry Andric   auto [Dst, Src] = MI.getFirst2Regs();
63315f757f3fSDimitry Andric   LLT DstTy = MRI.getType(Dst);
63325f757f3fSDimitry Andric   LLT SrcTy = MRI.getType(Src);
63335f757f3fSDimitry Andric 
63345f757f3fSDimitry Andric   uint32_t DstTySize = DstTy.getSizeInBits();
63355f757f3fSDimitry Andric   uint32_t DstTyScalarSize = DstTy.getScalarSizeInBits();
63365f757f3fSDimitry Andric   uint32_t SrcTyScalarSize = SrcTy.getScalarSizeInBits();
63375f757f3fSDimitry Andric 
63385f757f3fSDimitry Andric   if (!isPowerOf2_32(DstTySize) || !isPowerOf2_32(DstTyScalarSize) ||
63395f757f3fSDimitry Andric       !isPowerOf2_32(SrcTyScalarSize))
63405f757f3fSDimitry Andric     return UnableToLegalize;
63415f757f3fSDimitry Andric 
63425f757f3fSDimitry Andric   // The step between extend is too large, split it by creating an intermediate
63435f757f3fSDimitry Andric   // extend instruction
63445f757f3fSDimitry Andric   if (SrcTyScalarSize * 2 < DstTyScalarSize) {
63455f757f3fSDimitry Andric     LLT MidTy = SrcTy.changeElementSize(SrcTyScalarSize * 2);
63465f757f3fSDimitry Andric     // If the destination type is illegal, split it into multiple statements
63475f757f3fSDimitry Andric     // zext x -> zext(merge(zext(unmerge), zext(unmerge)))
63485f757f3fSDimitry Andric     auto NewExt = MIRBuilder.buildInstr(MI.getOpcode(), {MidTy}, {Src});
63495f757f3fSDimitry Andric     // Unmerge the vector
63505f757f3fSDimitry Andric     LLT EltTy = MidTy.changeElementCount(
63515f757f3fSDimitry Andric         MidTy.getElementCount().divideCoefficientBy(2));
63525f757f3fSDimitry Andric     auto UnmergeSrc = MIRBuilder.buildUnmerge(EltTy, NewExt);
63535f757f3fSDimitry Andric 
63545f757f3fSDimitry Andric     // ZExt the vectors
63555f757f3fSDimitry Andric     LLT ZExtResTy = DstTy.changeElementCount(
63565f757f3fSDimitry Andric         DstTy.getElementCount().divideCoefficientBy(2));
63575f757f3fSDimitry Andric     auto ZExtRes1 = MIRBuilder.buildInstr(MI.getOpcode(), {ZExtResTy},
63585f757f3fSDimitry Andric                                           {UnmergeSrc.getReg(0)});
63595f757f3fSDimitry Andric     auto ZExtRes2 = MIRBuilder.buildInstr(MI.getOpcode(), {ZExtResTy},
63605f757f3fSDimitry Andric                                           {UnmergeSrc.getReg(1)});
63615f757f3fSDimitry Andric 
63625f757f3fSDimitry Andric     // Merge the ending vectors
63635f757f3fSDimitry Andric     MIRBuilder.buildMergeLikeInstr(Dst, {ZExtRes1, ZExtRes2});
63645f757f3fSDimitry Andric 
63655f757f3fSDimitry Andric     MI.eraseFromParent();
63665f757f3fSDimitry Andric     return Legalized;
63675f757f3fSDimitry Andric   }
63685f757f3fSDimitry Andric   return UnableToLegalize;
63695f757f3fSDimitry Andric }
63705f757f3fSDimitry Andric 
63715f757f3fSDimitry Andric LegalizerHelper::LegalizeResult LegalizerHelper::lowerTRUNC(MachineInstr &MI) {
63725f757f3fSDimitry Andric   // MachineIRBuilder &MIRBuilder = Helper.MIRBuilder;
63735f757f3fSDimitry Andric   MachineRegisterInfo &MRI = *MIRBuilder.getMRI();
63745f757f3fSDimitry Andric   // Similar to how operand splitting is done in SelectiondDAG, we can handle
63755f757f3fSDimitry Andric   // %res(v8s8) = G_TRUNC %in(v8s32) by generating:
63765f757f3fSDimitry Andric   //   %inlo(<4x s32>), %inhi(<4 x s32>) = G_UNMERGE %in(<8 x s32>)
63775f757f3fSDimitry Andric   //   %lo16(<4 x s16>) = G_TRUNC %inlo
63785f757f3fSDimitry Andric   //   %hi16(<4 x s16>) = G_TRUNC %inhi
63795f757f3fSDimitry Andric   //   %in16(<8 x s16>) = G_CONCAT_VECTORS %lo16, %hi16
63805f757f3fSDimitry Andric   //   %res(<8 x s8>) = G_TRUNC %in16
63815f757f3fSDimitry Andric 
63825f757f3fSDimitry Andric   assert(MI.getOpcode() == TargetOpcode::G_TRUNC);
63835f757f3fSDimitry Andric 
63845f757f3fSDimitry Andric   Register DstReg = MI.getOperand(0).getReg();
63855f757f3fSDimitry Andric   Register SrcReg = MI.getOperand(1).getReg();
63865f757f3fSDimitry Andric   LLT DstTy = MRI.getType(DstReg);
63875f757f3fSDimitry Andric   LLT SrcTy = MRI.getType(SrcReg);
63885f757f3fSDimitry Andric 
63895f757f3fSDimitry Andric   if (DstTy.isVector() && isPowerOf2_32(DstTy.getNumElements()) &&
63905f757f3fSDimitry Andric       isPowerOf2_32(DstTy.getScalarSizeInBits()) &&
63915f757f3fSDimitry Andric       isPowerOf2_32(SrcTy.getNumElements()) &&
63925f757f3fSDimitry Andric       isPowerOf2_32(SrcTy.getScalarSizeInBits())) {
63935f757f3fSDimitry Andric     // Split input type.
63945f757f3fSDimitry Andric     LLT SplitSrcTy = SrcTy.changeElementCount(
63955f757f3fSDimitry Andric         SrcTy.getElementCount().divideCoefficientBy(2));
63965f757f3fSDimitry Andric 
63975f757f3fSDimitry Andric     // First, split the source into two smaller vectors.
63985f757f3fSDimitry Andric     SmallVector<Register, 2> SplitSrcs;
6399*7a6dacacSDimitry Andric     extractParts(SrcReg, SplitSrcTy, 2, SplitSrcs, MIRBuilder, MRI);
64005f757f3fSDimitry Andric 
64015f757f3fSDimitry Andric     // Truncate the splits into intermediate narrower elements.
64025f757f3fSDimitry Andric     LLT InterTy;
64035f757f3fSDimitry Andric     if (DstTy.getScalarSizeInBits() * 2 < SrcTy.getScalarSizeInBits())
64045f757f3fSDimitry Andric       InterTy = SplitSrcTy.changeElementSize(DstTy.getScalarSizeInBits() * 2);
64055f757f3fSDimitry Andric     else
64065f757f3fSDimitry Andric       InterTy = SplitSrcTy.changeElementSize(DstTy.getScalarSizeInBits());
64075f757f3fSDimitry Andric     for (unsigned I = 0; I < SplitSrcs.size(); ++I) {
64085f757f3fSDimitry Andric       SplitSrcs[I] = MIRBuilder.buildTrunc(InterTy, SplitSrcs[I]).getReg(0);
64095f757f3fSDimitry Andric     }
64105f757f3fSDimitry Andric 
64115f757f3fSDimitry Andric     // Combine the new truncates into one vector
64125f757f3fSDimitry Andric     auto Merge = MIRBuilder.buildMergeLikeInstr(
64135f757f3fSDimitry Andric         DstTy.changeElementSize(InterTy.getScalarSizeInBits()), SplitSrcs);
64145f757f3fSDimitry Andric 
64155f757f3fSDimitry Andric     // Truncate the new vector to the final result type
64165f757f3fSDimitry Andric     if (DstTy.getScalarSizeInBits() * 2 < SrcTy.getScalarSizeInBits())
64175f757f3fSDimitry Andric       MIRBuilder.buildTrunc(MI.getOperand(0).getReg(), Merge.getReg(0));
64185f757f3fSDimitry Andric     else
64195f757f3fSDimitry Andric       MIRBuilder.buildCopy(MI.getOperand(0).getReg(), Merge.getReg(0));
64205f757f3fSDimitry Andric 
64215f757f3fSDimitry Andric     MI.eraseFromParent();
64225f757f3fSDimitry Andric 
64235f757f3fSDimitry Andric     return Legalized;
64245f757f3fSDimitry Andric   }
64255f757f3fSDimitry Andric   return UnableToLegalize;
64265f757f3fSDimitry Andric }
64275f757f3fSDimitry Andric 
6428fe6060f1SDimitry Andric LegalizerHelper::LegalizeResult
6429fe6060f1SDimitry Andric LegalizerHelper::lowerRotateWithReverseRotate(MachineInstr &MI) {
643006c3fb27SDimitry Andric   auto [Dst, DstTy, Src, SrcTy, Amt, AmtTy] = MI.getFirst3RegLLTs();
6431fe6060f1SDimitry Andric   auto Zero = MIRBuilder.buildConstant(AmtTy, 0);
6432fe6060f1SDimitry Andric   bool IsLeft = MI.getOpcode() == TargetOpcode::G_ROTL;
6433fe6060f1SDimitry Andric   unsigned RevRot = IsLeft ? TargetOpcode::G_ROTR : TargetOpcode::G_ROTL;
6434fe6060f1SDimitry Andric   auto Neg = MIRBuilder.buildSub(AmtTy, Zero, Amt);
6435fe6060f1SDimitry Andric   MIRBuilder.buildInstr(RevRot, {Dst}, {Src, Neg});
6436fe6060f1SDimitry Andric   MI.eraseFromParent();
6437fe6060f1SDimitry Andric   return Legalized;
6438fe6060f1SDimitry Andric }
6439fe6060f1SDimitry Andric 
6440fe6060f1SDimitry Andric LegalizerHelper::LegalizeResult LegalizerHelper::lowerRotate(MachineInstr &MI) {
644106c3fb27SDimitry Andric   auto [Dst, DstTy, Src, SrcTy, Amt, AmtTy] = MI.getFirst3RegLLTs();
6442fe6060f1SDimitry Andric 
6443fe6060f1SDimitry Andric   unsigned EltSizeInBits = DstTy.getScalarSizeInBits();
6444fe6060f1SDimitry Andric   bool IsLeft = MI.getOpcode() == TargetOpcode::G_ROTL;
6445fe6060f1SDimitry Andric 
6446fe6060f1SDimitry Andric   MIRBuilder.setInstrAndDebugLoc(MI);
6447fe6060f1SDimitry Andric 
6448fe6060f1SDimitry Andric   // If a rotate in the other direction is supported, use it.
6449fe6060f1SDimitry Andric   unsigned RevRot = IsLeft ? TargetOpcode::G_ROTR : TargetOpcode::G_ROTL;
6450fe6060f1SDimitry Andric   if (LI.isLegalOrCustom({RevRot, {DstTy, SrcTy}}) &&
6451fe6060f1SDimitry Andric       isPowerOf2_32(EltSizeInBits))
6452fe6060f1SDimitry Andric     return lowerRotateWithReverseRotate(MI);
6453fe6060f1SDimitry Andric 
6454349cc55cSDimitry Andric   // If a funnel shift is supported, use it.
6455349cc55cSDimitry Andric   unsigned FShOpc = IsLeft ? TargetOpcode::G_FSHL : TargetOpcode::G_FSHR;
6456349cc55cSDimitry Andric   unsigned RevFsh = !IsLeft ? TargetOpcode::G_FSHL : TargetOpcode::G_FSHR;
6457349cc55cSDimitry Andric   bool IsFShLegal = false;
6458349cc55cSDimitry Andric   if ((IsFShLegal = LI.isLegalOrCustom({FShOpc, {DstTy, AmtTy}})) ||
6459349cc55cSDimitry Andric       LI.isLegalOrCustom({RevFsh, {DstTy, AmtTy}})) {
6460349cc55cSDimitry Andric     auto buildFunnelShift = [&](unsigned Opc, Register R1, Register R2,
6461349cc55cSDimitry Andric                                 Register R3) {
6462349cc55cSDimitry Andric       MIRBuilder.buildInstr(Opc, {R1}, {R2, R2, R3});
6463349cc55cSDimitry Andric       MI.eraseFromParent();
6464349cc55cSDimitry Andric       return Legalized;
6465349cc55cSDimitry Andric     };
6466349cc55cSDimitry Andric     // If a funnel shift in the other direction is supported, use it.
6467349cc55cSDimitry Andric     if (IsFShLegal) {
6468349cc55cSDimitry Andric       return buildFunnelShift(FShOpc, Dst, Src, Amt);
6469349cc55cSDimitry Andric     } else if (isPowerOf2_32(EltSizeInBits)) {
6470349cc55cSDimitry Andric       Amt = MIRBuilder.buildNeg(DstTy, Amt).getReg(0);
6471349cc55cSDimitry Andric       return buildFunnelShift(RevFsh, Dst, Src, Amt);
6472349cc55cSDimitry Andric     }
6473349cc55cSDimitry Andric   }
6474349cc55cSDimitry Andric 
6475fe6060f1SDimitry Andric   auto Zero = MIRBuilder.buildConstant(AmtTy, 0);
6476fe6060f1SDimitry Andric   unsigned ShOpc = IsLeft ? TargetOpcode::G_SHL : TargetOpcode::G_LSHR;
6477fe6060f1SDimitry Andric   unsigned RevShiftOpc = IsLeft ? TargetOpcode::G_LSHR : TargetOpcode::G_SHL;
6478fe6060f1SDimitry Andric   auto BitWidthMinusOneC = MIRBuilder.buildConstant(AmtTy, EltSizeInBits - 1);
6479fe6060f1SDimitry Andric   Register ShVal;
6480fe6060f1SDimitry Andric   Register RevShiftVal;
6481fe6060f1SDimitry Andric   if (isPowerOf2_32(EltSizeInBits)) {
6482fe6060f1SDimitry Andric     // (rotl x, c) -> x << (c & (w - 1)) | x >> (-c & (w - 1))
6483fe6060f1SDimitry Andric     // (rotr x, c) -> x >> (c & (w - 1)) | x << (-c & (w - 1))
6484fe6060f1SDimitry Andric     auto NegAmt = MIRBuilder.buildSub(AmtTy, Zero, Amt);
6485fe6060f1SDimitry Andric     auto ShAmt = MIRBuilder.buildAnd(AmtTy, Amt, BitWidthMinusOneC);
6486fe6060f1SDimitry Andric     ShVal = MIRBuilder.buildInstr(ShOpc, {DstTy}, {Src, ShAmt}).getReg(0);
6487fe6060f1SDimitry Andric     auto RevAmt = MIRBuilder.buildAnd(AmtTy, NegAmt, BitWidthMinusOneC);
6488fe6060f1SDimitry Andric     RevShiftVal =
6489fe6060f1SDimitry Andric         MIRBuilder.buildInstr(RevShiftOpc, {DstTy}, {Src, RevAmt}).getReg(0);
6490fe6060f1SDimitry Andric   } else {
6491fe6060f1SDimitry Andric     // (rotl x, c) -> x << (c % w) | x >> 1 >> (w - 1 - (c % w))
6492fe6060f1SDimitry Andric     // (rotr x, c) -> x >> (c % w) | x << 1 << (w - 1 - (c % w))
6493fe6060f1SDimitry Andric     auto BitWidthC = MIRBuilder.buildConstant(AmtTy, EltSizeInBits);
6494fe6060f1SDimitry Andric     auto ShAmt = MIRBuilder.buildURem(AmtTy, Amt, BitWidthC);
6495fe6060f1SDimitry Andric     ShVal = MIRBuilder.buildInstr(ShOpc, {DstTy}, {Src, ShAmt}).getReg(0);
6496fe6060f1SDimitry Andric     auto RevAmt = MIRBuilder.buildSub(AmtTy, BitWidthMinusOneC, ShAmt);
6497fe6060f1SDimitry Andric     auto One = MIRBuilder.buildConstant(AmtTy, 1);
6498fe6060f1SDimitry Andric     auto Inner = MIRBuilder.buildInstr(RevShiftOpc, {DstTy}, {Src, One});
6499fe6060f1SDimitry Andric     RevShiftVal =
6500fe6060f1SDimitry Andric         MIRBuilder.buildInstr(RevShiftOpc, {DstTy}, {Inner, RevAmt}).getReg(0);
6501fe6060f1SDimitry Andric   }
6502fe6060f1SDimitry Andric   MIRBuilder.buildOr(Dst, ShVal, RevShiftVal);
6503fe6060f1SDimitry Andric   MI.eraseFromParent();
6504fe6060f1SDimitry Andric   return Legalized;
6505fe6060f1SDimitry Andric }
6506fe6060f1SDimitry Andric 
65070b57cec5SDimitry Andric // Expand s32 = G_UITOFP s64 using bit operations to an IEEE float
65080b57cec5SDimitry Andric // representation.
65090b57cec5SDimitry Andric LegalizerHelper::LegalizeResult
65100b57cec5SDimitry Andric LegalizerHelper::lowerU64ToF32BitOps(MachineInstr &MI) {
651106c3fb27SDimitry Andric   auto [Dst, Src] = MI.getFirst2Regs();
65120b57cec5SDimitry Andric   const LLT S64 = LLT::scalar(64);
65130b57cec5SDimitry Andric   const LLT S32 = LLT::scalar(32);
65140b57cec5SDimitry Andric   const LLT S1 = LLT::scalar(1);
65150b57cec5SDimitry Andric 
65160b57cec5SDimitry Andric   assert(MRI.getType(Src) == S64 && MRI.getType(Dst) == S32);
65170b57cec5SDimitry Andric 
65180b57cec5SDimitry Andric   // unsigned cul2f(ulong u) {
65190b57cec5SDimitry Andric   //   uint lz = clz(u);
65200b57cec5SDimitry Andric   //   uint e = (u != 0) ? 127U + 63U - lz : 0;
65210b57cec5SDimitry Andric   //   u = (u << lz) & 0x7fffffffffffffffUL;
65220b57cec5SDimitry Andric   //   ulong t = u & 0xffffffffffUL;
65230b57cec5SDimitry Andric   //   uint v = (e << 23) | (uint)(u >> 40);
65240b57cec5SDimitry Andric   //   uint r = t > 0x8000000000UL ? 1U : (t == 0x8000000000UL ? v & 1U : 0U);
65250b57cec5SDimitry Andric   //   return as_float(v + r);
65260b57cec5SDimitry Andric   // }
65270b57cec5SDimitry Andric 
65280b57cec5SDimitry Andric   auto Zero32 = MIRBuilder.buildConstant(S32, 0);
65290b57cec5SDimitry Andric   auto Zero64 = MIRBuilder.buildConstant(S64, 0);
65300b57cec5SDimitry Andric 
65310b57cec5SDimitry Andric   auto LZ = MIRBuilder.buildCTLZ_ZERO_UNDEF(S32, Src);
65320b57cec5SDimitry Andric 
65330b57cec5SDimitry Andric   auto K = MIRBuilder.buildConstant(S32, 127U + 63U);
65340b57cec5SDimitry Andric   auto Sub = MIRBuilder.buildSub(S32, K, LZ);
65350b57cec5SDimitry Andric 
65360b57cec5SDimitry Andric   auto NotZero = MIRBuilder.buildICmp(CmpInst::ICMP_NE, S1, Src, Zero64);
65370b57cec5SDimitry Andric   auto E = MIRBuilder.buildSelect(S32, NotZero, Sub, Zero32);
65380b57cec5SDimitry Andric 
65390b57cec5SDimitry Andric   auto Mask0 = MIRBuilder.buildConstant(S64, (-1ULL) >> 1);
65400b57cec5SDimitry Andric   auto ShlLZ = MIRBuilder.buildShl(S64, Src, LZ);
65410b57cec5SDimitry Andric 
65420b57cec5SDimitry Andric   auto U = MIRBuilder.buildAnd(S64, ShlLZ, Mask0);
65430b57cec5SDimitry Andric 
65440b57cec5SDimitry Andric   auto Mask1 = MIRBuilder.buildConstant(S64, 0xffffffffffULL);
65450b57cec5SDimitry Andric   auto T = MIRBuilder.buildAnd(S64, U, Mask1);
65460b57cec5SDimitry Andric 
65470b57cec5SDimitry Andric   auto UShl = MIRBuilder.buildLShr(S64, U, MIRBuilder.buildConstant(S64, 40));
65480b57cec5SDimitry Andric   auto ShlE = MIRBuilder.buildShl(S32, E, MIRBuilder.buildConstant(S32, 23));
65490b57cec5SDimitry Andric   auto V = MIRBuilder.buildOr(S32, ShlE, MIRBuilder.buildTrunc(S32, UShl));
65500b57cec5SDimitry Andric 
65510b57cec5SDimitry Andric   auto C = MIRBuilder.buildConstant(S64, 0x8000000000ULL);
65520b57cec5SDimitry Andric   auto RCmp = MIRBuilder.buildICmp(CmpInst::ICMP_UGT, S1, T, C);
65530b57cec5SDimitry Andric   auto TCmp = MIRBuilder.buildICmp(CmpInst::ICMP_EQ, S1, T, C);
65540b57cec5SDimitry Andric   auto One = MIRBuilder.buildConstant(S32, 1);
65550b57cec5SDimitry Andric 
65560b57cec5SDimitry Andric   auto VTrunc1 = MIRBuilder.buildAnd(S32, V, One);
65570b57cec5SDimitry Andric   auto Select0 = MIRBuilder.buildSelect(S32, TCmp, VTrunc1, Zero32);
65580b57cec5SDimitry Andric   auto R = MIRBuilder.buildSelect(S32, RCmp, One, Select0);
65590b57cec5SDimitry Andric   MIRBuilder.buildAdd(Dst, V, R);
65600b57cec5SDimitry Andric 
65615ffd83dbSDimitry Andric   MI.eraseFromParent();
65620b57cec5SDimitry Andric   return Legalized;
65630b57cec5SDimitry Andric }
65640b57cec5SDimitry Andric 
6565e8d8bef9SDimitry Andric LegalizerHelper::LegalizeResult LegalizerHelper::lowerUITOFP(MachineInstr &MI) {
656606c3fb27SDimitry Andric   auto [Dst, DstTy, Src, SrcTy] = MI.getFirst2RegLLTs();
65670b57cec5SDimitry Andric 
6568480093f4SDimitry Andric   if (SrcTy == LLT::scalar(1)) {
6569480093f4SDimitry Andric     auto True = MIRBuilder.buildFConstant(DstTy, 1.0);
6570480093f4SDimitry Andric     auto False = MIRBuilder.buildFConstant(DstTy, 0.0);
6571480093f4SDimitry Andric     MIRBuilder.buildSelect(Dst, Src, True, False);
6572480093f4SDimitry Andric     MI.eraseFromParent();
6573480093f4SDimitry Andric     return Legalized;
6574480093f4SDimitry Andric   }
6575480093f4SDimitry Andric 
65760b57cec5SDimitry Andric   if (SrcTy != LLT::scalar(64))
65770b57cec5SDimitry Andric     return UnableToLegalize;
65780b57cec5SDimitry Andric 
65790b57cec5SDimitry Andric   if (DstTy == LLT::scalar(32)) {
65800b57cec5SDimitry Andric     // TODO: SelectionDAG has several alternative expansions to port which may
65810b57cec5SDimitry Andric     // be more reasonble depending on the available instructions. If a target
65820b57cec5SDimitry Andric     // has sitofp, does not have CTLZ, or can efficiently use f64 as an
65830b57cec5SDimitry Andric     // intermediate type, this is probably worse.
65840b57cec5SDimitry Andric     return lowerU64ToF32BitOps(MI);
65850b57cec5SDimitry Andric   }
65860b57cec5SDimitry Andric 
65870b57cec5SDimitry Andric   return UnableToLegalize;
65880b57cec5SDimitry Andric }
65890b57cec5SDimitry Andric 
6590e8d8bef9SDimitry Andric LegalizerHelper::LegalizeResult LegalizerHelper::lowerSITOFP(MachineInstr &MI) {
659106c3fb27SDimitry Andric   auto [Dst, DstTy, Src, SrcTy] = MI.getFirst2RegLLTs();
65920b57cec5SDimitry Andric 
65930b57cec5SDimitry Andric   const LLT S64 = LLT::scalar(64);
65940b57cec5SDimitry Andric   const LLT S32 = LLT::scalar(32);
65950b57cec5SDimitry Andric   const LLT S1 = LLT::scalar(1);
65960b57cec5SDimitry Andric 
6597480093f4SDimitry Andric   if (SrcTy == S1) {
6598480093f4SDimitry Andric     auto True = MIRBuilder.buildFConstant(DstTy, -1.0);
6599480093f4SDimitry Andric     auto False = MIRBuilder.buildFConstant(DstTy, 0.0);
6600480093f4SDimitry Andric     MIRBuilder.buildSelect(Dst, Src, True, False);
6601480093f4SDimitry Andric     MI.eraseFromParent();
6602480093f4SDimitry Andric     return Legalized;
6603480093f4SDimitry Andric   }
6604480093f4SDimitry Andric 
66050b57cec5SDimitry Andric   if (SrcTy != S64)
66060b57cec5SDimitry Andric     return UnableToLegalize;
66070b57cec5SDimitry Andric 
66080b57cec5SDimitry Andric   if (DstTy == S32) {
66090b57cec5SDimitry Andric     // signed cl2f(long l) {
66100b57cec5SDimitry Andric     //   long s = l >> 63;
66110b57cec5SDimitry Andric     //   float r = cul2f((l + s) ^ s);
66120b57cec5SDimitry Andric     //   return s ? -r : r;
66130b57cec5SDimitry Andric     // }
66140b57cec5SDimitry Andric     Register L = Src;
66150b57cec5SDimitry Andric     auto SignBit = MIRBuilder.buildConstant(S64, 63);
66160b57cec5SDimitry Andric     auto S = MIRBuilder.buildAShr(S64, L, SignBit);
66170b57cec5SDimitry Andric 
66180b57cec5SDimitry Andric     auto LPlusS = MIRBuilder.buildAdd(S64, L, S);
66190b57cec5SDimitry Andric     auto Xor = MIRBuilder.buildXor(S64, LPlusS, S);
66200b57cec5SDimitry Andric     auto R = MIRBuilder.buildUITOFP(S32, Xor);
66210b57cec5SDimitry Andric 
66220b57cec5SDimitry Andric     auto RNeg = MIRBuilder.buildFNeg(S32, R);
66230b57cec5SDimitry Andric     auto SignNotZero = MIRBuilder.buildICmp(CmpInst::ICMP_NE, S1, S,
66240b57cec5SDimitry Andric                                             MIRBuilder.buildConstant(S64, 0));
66250b57cec5SDimitry Andric     MIRBuilder.buildSelect(Dst, SignNotZero, RNeg, R);
66265ffd83dbSDimitry Andric     MI.eraseFromParent();
66270b57cec5SDimitry Andric     return Legalized;
66280b57cec5SDimitry Andric   }
66290b57cec5SDimitry Andric 
66300b57cec5SDimitry Andric   return UnableToLegalize;
66310b57cec5SDimitry Andric }
66320b57cec5SDimitry Andric 
6633e8d8bef9SDimitry Andric LegalizerHelper::LegalizeResult LegalizerHelper::lowerFPTOUI(MachineInstr &MI) {
663406c3fb27SDimitry Andric   auto [Dst, DstTy, Src, SrcTy] = MI.getFirst2RegLLTs();
66358bcb0991SDimitry Andric   const LLT S64 = LLT::scalar(64);
66368bcb0991SDimitry Andric   const LLT S32 = LLT::scalar(32);
66378bcb0991SDimitry Andric 
66388bcb0991SDimitry Andric   if (SrcTy != S64 && SrcTy != S32)
66398bcb0991SDimitry Andric     return UnableToLegalize;
66408bcb0991SDimitry Andric   if (DstTy != S32 && DstTy != S64)
66418bcb0991SDimitry Andric     return UnableToLegalize;
66428bcb0991SDimitry Andric 
66438bcb0991SDimitry Andric   // FPTOSI gives same result as FPTOUI for positive signed integers.
66448bcb0991SDimitry Andric   // FPTOUI needs to deal with fp values that convert to unsigned integers
66458bcb0991SDimitry Andric   // greater or equal to 2^31 for float or 2^63 for double. For brevity 2^Exp.
66468bcb0991SDimitry Andric 
66478bcb0991SDimitry Andric   APInt TwoPExpInt = APInt::getSignMask(DstTy.getSizeInBits());
66488bcb0991SDimitry Andric   APFloat TwoPExpFP(SrcTy.getSizeInBits() == 32 ? APFloat::IEEEsingle()
66498bcb0991SDimitry Andric                                                 : APFloat::IEEEdouble(),
6650349cc55cSDimitry Andric                     APInt::getZero(SrcTy.getSizeInBits()));
66518bcb0991SDimitry Andric   TwoPExpFP.convertFromAPInt(TwoPExpInt, false, APFloat::rmNearestTiesToEven);
66528bcb0991SDimitry Andric 
66538bcb0991SDimitry Andric   MachineInstrBuilder FPTOSI = MIRBuilder.buildFPTOSI(DstTy, Src);
66548bcb0991SDimitry Andric 
66558bcb0991SDimitry Andric   MachineInstrBuilder Threshold = MIRBuilder.buildFConstant(SrcTy, TwoPExpFP);
66568bcb0991SDimitry Andric   // For fp Value greater or equal to Threshold(2^Exp), we use FPTOSI on
66578bcb0991SDimitry Andric   // (Value - 2^Exp) and add 2^Exp by setting highest bit in result to 1.
66588bcb0991SDimitry Andric   MachineInstrBuilder FSub = MIRBuilder.buildFSub(SrcTy, Src, Threshold);
66598bcb0991SDimitry Andric   MachineInstrBuilder ResLowBits = MIRBuilder.buildFPTOSI(DstTy, FSub);
66608bcb0991SDimitry Andric   MachineInstrBuilder ResHighBit = MIRBuilder.buildConstant(DstTy, TwoPExpInt);
66618bcb0991SDimitry Andric   MachineInstrBuilder Res = MIRBuilder.buildXor(DstTy, ResLowBits, ResHighBit);
66628bcb0991SDimitry Andric 
6663480093f4SDimitry Andric   const LLT S1 = LLT::scalar(1);
6664480093f4SDimitry Andric 
66658bcb0991SDimitry Andric   MachineInstrBuilder FCMP =
6666480093f4SDimitry Andric       MIRBuilder.buildFCmp(CmpInst::FCMP_ULT, S1, Src, Threshold);
66678bcb0991SDimitry Andric   MIRBuilder.buildSelect(Dst, FCMP, FPTOSI, Res);
66688bcb0991SDimitry Andric 
66698bcb0991SDimitry Andric   MI.eraseFromParent();
66708bcb0991SDimitry Andric   return Legalized;
66718bcb0991SDimitry Andric }
66728bcb0991SDimitry Andric 
66735ffd83dbSDimitry Andric LegalizerHelper::LegalizeResult LegalizerHelper::lowerFPTOSI(MachineInstr &MI) {
667406c3fb27SDimitry Andric   auto [Dst, DstTy, Src, SrcTy] = MI.getFirst2RegLLTs();
66755ffd83dbSDimitry Andric   const LLT S64 = LLT::scalar(64);
66765ffd83dbSDimitry Andric   const LLT S32 = LLT::scalar(32);
66775ffd83dbSDimitry Andric 
66785ffd83dbSDimitry Andric   // FIXME: Only f32 to i64 conversions are supported.
66795ffd83dbSDimitry Andric   if (SrcTy.getScalarType() != S32 || DstTy.getScalarType() != S64)
66805ffd83dbSDimitry Andric     return UnableToLegalize;
66815ffd83dbSDimitry Andric 
66825ffd83dbSDimitry Andric   // Expand f32 -> i64 conversion
66835ffd83dbSDimitry Andric   // This algorithm comes from compiler-rt's implementation of fixsfdi:
6684fe6060f1SDimitry Andric   // https://github.com/llvm/llvm-project/blob/main/compiler-rt/lib/builtins/fixsfdi.c
66855ffd83dbSDimitry Andric 
66865ffd83dbSDimitry Andric   unsigned SrcEltBits = SrcTy.getScalarSizeInBits();
66875ffd83dbSDimitry Andric 
66885ffd83dbSDimitry Andric   auto ExponentMask = MIRBuilder.buildConstant(SrcTy, 0x7F800000);
66895ffd83dbSDimitry Andric   auto ExponentLoBit = MIRBuilder.buildConstant(SrcTy, 23);
66905ffd83dbSDimitry Andric 
66915ffd83dbSDimitry Andric   auto AndExpMask = MIRBuilder.buildAnd(SrcTy, Src, ExponentMask);
66925ffd83dbSDimitry Andric   auto ExponentBits = MIRBuilder.buildLShr(SrcTy, AndExpMask, ExponentLoBit);
66935ffd83dbSDimitry Andric 
66945ffd83dbSDimitry Andric   auto SignMask = MIRBuilder.buildConstant(SrcTy,
66955ffd83dbSDimitry Andric                                            APInt::getSignMask(SrcEltBits));
66965ffd83dbSDimitry Andric   auto AndSignMask = MIRBuilder.buildAnd(SrcTy, Src, SignMask);
66975ffd83dbSDimitry Andric   auto SignLowBit = MIRBuilder.buildConstant(SrcTy, SrcEltBits - 1);
66985ffd83dbSDimitry Andric   auto Sign = MIRBuilder.buildAShr(SrcTy, AndSignMask, SignLowBit);
66995ffd83dbSDimitry Andric   Sign = MIRBuilder.buildSExt(DstTy, Sign);
67005ffd83dbSDimitry Andric 
67015ffd83dbSDimitry Andric   auto MantissaMask = MIRBuilder.buildConstant(SrcTy, 0x007FFFFF);
67025ffd83dbSDimitry Andric   auto AndMantissaMask = MIRBuilder.buildAnd(SrcTy, Src, MantissaMask);
67035ffd83dbSDimitry Andric   auto K = MIRBuilder.buildConstant(SrcTy, 0x00800000);
67045ffd83dbSDimitry Andric 
67055ffd83dbSDimitry Andric   auto R = MIRBuilder.buildOr(SrcTy, AndMantissaMask, K);
67065ffd83dbSDimitry Andric   R = MIRBuilder.buildZExt(DstTy, R);
67075ffd83dbSDimitry Andric 
67085ffd83dbSDimitry Andric   auto Bias = MIRBuilder.buildConstant(SrcTy, 127);
67095ffd83dbSDimitry Andric   auto Exponent = MIRBuilder.buildSub(SrcTy, ExponentBits, Bias);
67105ffd83dbSDimitry Andric   auto SubExponent = MIRBuilder.buildSub(SrcTy, Exponent, ExponentLoBit);
67115ffd83dbSDimitry Andric   auto ExponentSub = MIRBuilder.buildSub(SrcTy, ExponentLoBit, Exponent);
67125ffd83dbSDimitry Andric 
67135ffd83dbSDimitry Andric   auto Shl = MIRBuilder.buildShl(DstTy, R, SubExponent);
67145ffd83dbSDimitry Andric   auto Srl = MIRBuilder.buildLShr(DstTy, R, ExponentSub);
67155ffd83dbSDimitry Andric 
67165ffd83dbSDimitry Andric   const LLT S1 = LLT::scalar(1);
67175ffd83dbSDimitry Andric   auto CmpGt = MIRBuilder.buildICmp(CmpInst::ICMP_SGT,
67185ffd83dbSDimitry Andric                                     S1, Exponent, ExponentLoBit);
67195ffd83dbSDimitry Andric 
67205ffd83dbSDimitry Andric   R = MIRBuilder.buildSelect(DstTy, CmpGt, Shl, Srl);
67215ffd83dbSDimitry Andric 
67225ffd83dbSDimitry Andric   auto XorSign = MIRBuilder.buildXor(DstTy, R, Sign);
67235ffd83dbSDimitry Andric   auto Ret = MIRBuilder.buildSub(DstTy, XorSign, Sign);
67245ffd83dbSDimitry Andric 
67255ffd83dbSDimitry Andric   auto ZeroSrcTy = MIRBuilder.buildConstant(SrcTy, 0);
67265ffd83dbSDimitry Andric 
67275ffd83dbSDimitry Andric   auto ExponentLt0 = MIRBuilder.buildICmp(CmpInst::ICMP_SLT,
67285ffd83dbSDimitry Andric                                           S1, Exponent, ZeroSrcTy);
67295ffd83dbSDimitry Andric 
67305ffd83dbSDimitry Andric   auto ZeroDstTy = MIRBuilder.buildConstant(DstTy, 0);
67315ffd83dbSDimitry Andric   MIRBuilder.buildSelect(Dst, ExponentLt0, ZeroDstTy, Ret);
67325ffd83dbSDimitry Andric 
67335ffd83dbSDimitry Andric   MI.eraseFromParent();
67345ffd83dbSDimitry Andric   return Legalized;
67355ffd83dbSDimitry Andric }
67365ffd83dbSDimitry Andric 
67375ffd83dbSDimitry Andric // f64 -> f16 conversion using round-to-nearest-even rounding mode.
67385ffd83dbSDimitry Andric LegalizerHelper::LegalizeResult
67395ffd83dbSDimitry Andric LegalizerHelper::lowerFPTRUNC_F64_TO_F16(MachineInstr &MI) {
674006c3fb27SDimitry Andric   const LLT S1 = LLT::scalar(1);
674106c3fb27SDimitry Andric   const LLT S32 = LLT::scalar(32);
674206c3fb27SDimitry Andric 
674306c3fb27SDimitry Andric   auto [Dst, Src] = MI.getFirst2Regs();
674406c3fb27SDimitry Andric   assert(MRI.getType(Dst).getScalarType() == LLT::scalar(16) &&
674506c3fb27SDimitry Andric          MRI.getType(Src).getScalarType() == LLT::scalar(64));
67465ffd83dbSDimitry Andric 
67475ffd83dbSDimitry Andric   if (MRI.getType(Src).isVector()) // TODO: Handle vectors directly.
67485ffd83dbSDimitry Andric     return UnableToLegalize;
67495ffd83dbSDimitry Andric 
675006c3fb27SDimitry Andric   if (MIRBuilder.getMF().getTarget().Options.UnsafeFPMath) {
675106c3fb27SDimitry Andric     unsigned Flags = MI.getFlags();
675206c3fb27SDimitry Andric     auto Src32 = MIRBuilder.buildFPTrunc(S32, Src, Flags);
675306c3fb27SDimitry Andric     MIRBuilder.buildFPTrunc(Dst, Src32, Flags);
675406c3fb27SDimitry Andric     MI.eraseFromParent();
675506c3fb27SDimitry Andric     return Legalized;
675606c3fb27SDimitry Andric   }
675706c3fb27SDimitry Andric 
67585ffd83dbSDimitry Andric   const unsigned ExpMask = 0x7ff;
67595ffd83dbSDimitry Andric   const unsigned ExpBiasf64 = 1023;
67605ffd83dbSDimitry Andric   const unsigned ExpBiasf16 = 15;
67615ffd83dbSDimitry Andric 
67625ffd83dbSDimitry Andric   auto Unmerge = MIRBuilder.buildUnmerge(S32, Src);
67635ffd83dbSDimitry Andric   Register U = Unmerge.getReg(0);
67645ffd83dbSDimitry Andric   Register UH = Unmerge.getReg(1);
67655ffd83dbSDimitry Andric 
67665ffd83dbSDimitry Andric   auto E = MIRBuilder.buildLShr(S32, UH, MIRBuilder.buildConstant(S32, 20));
67675ffd83dbSDimitry Andric   E = MIRBuilder.buildAnd(S32, E, MIRBuilder.buildConstant(S32, ExpMask));
67685ffd83dbSDimitry Andric 
67695ffd83dbSDimitry Andric   // Subtract the fp64 exponent bias (1023) to get the real exponent and
67705ffd83dbSDimitry Andric   // add the f16 bias (15) to get the biased exponent for the f16 format.
67715ffd83dbSDimitry Andric   E = MIRBuilder.buildAdd(
67725ffd83dbSDimitry Andric     S32, E, MIRBuilder.buildConstant(S32, -ExpBiasf64 + ExpBiasf16));
67735ffd83dbSDimitry Andric 
67745ffd83dbSDimitry Andric   auto M = MIRBuilder.buildLShr(S32, UH, MIRBuilder.buildConstant(S32, 8));
67755ffd83dbSDimitry Andric   M = MIRBuilder.buildAnd(S32, M, MIRBuilder.buildConstant(S32, 0xffe));
67765ffd83dbSDimitry Andric 
67775ffd83dbSDimitry Andric   auto MaskedSig = MIRBuilder.buildAnd(S32, UH,
67785ffd83dbSDimitry Andric                                        MIRBuilder.buildConstant(S32, 0x1ff));
67795ffd83dbSDimitry Andric   MaskedSig = MIRBuilder.buildOr(S32, MaskedSig, U);
67805ffd83dbSDimitry Andric 
67815ffd83dbSDimitry Andric   auto Zero = MIRBuilder.buildConstant(S32, 0);
67825ffd83dbSDimitry Andric   auto SigCmpNE0 = MIRBuilder.buildICmp(CmpInst::ICMP_NE, S1, MaskedSig, Zero);
67835ffd83dbSDimitry Andric   auto Lo40Set = MIRBuilder.buildZExt(S32, SigCmpNE0);
67845ffd83dbSDimitry Andric   M = MIRBuilder.buildOr(S32, M, Lo40Set);
67855ffd83dbSDimitry Andric 
67865ffd83dbSDimitry Andric   // (M != 0 ? 0x0200 : 0) | 0x7c00;
67875ffd83dbSDimitry Andric   auto Bits0x200 = MIRBuilder.buildConstant(S32, 0x0200);
67885ffd83dbSDimitry Andric   auto CmpM_NE0 = MIRBuilder.buildICmp(CmpInst::ICMP_NE, S1, M, Zero);
67895ffd83dbSDimitry Andric   auto SelectCC = MIRBuilder.buildSelect(S32, CmpM_NE0, Bits0x200, Zero);
67905ffd83dbSDimitry Andric 
67915ffd83dbSDimitry Andric   auto Bits0x7c00 = MIRBuilder.buildConstant(S32, 0x7c00);
67925ffd83dbSDimitry Andric   auto I = MIRBuilder.buildOr(S32, SelectCC, Bits0x7c00);
67935ffd83dbSDimitry Andric 
67945ffd83dbSDimitry Andric   // N = M | (E << 12);
67955ffd83dbSDimitry Andric   auto EShl12 = MIRBuilder.buildShl(S32, E, MIRBuilder.buildConstant(S32, 12));
67965ffd83dbSDimitry Andric   auto N = MIRBuilder.buildOr(S32, M, EShl12);
67975ffd83dbSDimitry Andric 
67985ffd83dbSDimitry Andric   // B = clamp(1-E, 0, 13);
67995ffd83dbSDimitry Andric   auto One = MIRBuilder.buildConstant(S32, 1);
68005ffd83dbSDimitry Andric   auto OneSubExp = MIRBuilder.buildSub(S32, One, E);
68015ffd83dbSDimitry Andric   auto B = MIRBuilder.buildSMax(S32, OneSubExp, Zero);
68025ffd83dbSDimitry Andric   B = MIRBuilder.buildSMin(S32, B, MIRBuilder.buildConstant(S32, 13));
68035ffd83dbSDimitry Andric 
68045ffd83dbSDimitry Andric   auto SigSetHigh = MIRBuilder.buildOr(S32, M,
68055ffd83dbSDimitry Andric                                        MIRBuilder.buildConstant(S32, 0x1000));
68065ffd83dbSDimitry Andric 
68075ffd83dbSDimitry Andric   auto D = MIRBuilder.buildLShr(S32, SigSetHigh, B);
68085ffd83dbSDimitry Andric   auto D0 = MIRBuilder.buildShl(S32, D, B);
68095ffd83dbSDimitry Andric 
68105ffd83dbSDimitry Andric   auto D0_NE_SigSetHigh = MIRBuilder.buildICmp(CmpInst::ICMP_NE, S1,
68115ffd83dbSDimitry Andric                                              D0, SigSetHigh);
68125ffd83dbSDimitry Andric   auto D1 = MIRBuilder.buildZExt(S32, D0_NE_SigSetHigh);
68135ffd83dbSDimitry Andric   D = MIRBuilder.buildOr(S32, D, D1);
68145ffd83dbSDimitry Andric 
68155ffd83dbSDimitry Andric   auto CmpELtOne = MIRBuilder.buildICmp(CmpInst::ICMP_SLT, S1, E, One);
68165ffd83dbSDimitry Andric   auto V = MIRBuilder.buildSelect(S32, CmpELtOne, D, N);
68175ffd83dbSDimitry Andric 
68185ffd83dbSDimitry Andric   auto VLow3 = MIRBuilder.buildAnd(S32, V, MIRBuilder.buildConstant(S32, 7));
68195ffd83dbSDimitry Andric   V = MIRBuilder.buildLShr(S32, V, MIRBuilder.buildConstant(S32, 2));
68205ffd83dbSDimitry Andric 
68215ffd83dbSDimitry Andric   auto VLow3Eq3 = MIRBuilder.buildICmp(CmpInst::ICMP_EQ, S1, VLow3,
68225ffd83dbSDimitry Andric                                        MIRBuilder.buildConstant(S32, 3));
68235ffd83dbSDimitry Andric   auto V0 = MIRBuilder.buildZExt(S32, VLow3Eq3);
68245ffd83dbSDimitry Andric 
68255ffd83dbSDimitry Andric   auto VLow3Gt5 = MIRBuilder.buildICmp(CmpInst::ICMP_SGT, S1, VLow3,
68265ffd83dbSDimitry Andric                                        MIRBuilder.buildConstant(S32, 5));
68275ffd83dbSDimitry Andric   auto V1 = MIRBuilder.buildZExt(S32, VLow3Gt5);
68285ffd83dbSDimitry Andric 
68295ffd83dbSDimitry Andric   V1 = MIRBuilder.buildOr(S32, V0, V1);
68305ffd83dbSDimitry Andric   V = MIRBuilder.buildAdd(S32, V, V1);
68315ffd83dbSDimitry Andric 
68325ffd83dbSDimitry Andric   auto CmpEGt30 = MIRBuilder.buildICmp(CmpInst::ICMP_SGT,  S1,
68335ffd83dbSDimitry Andric                                        E, MIRBuilder.buildConstant(S32, 30));
68345ffd83dbSDimitry Andric   V = MIRBuilder.buildSelect(S32, CmpEGt30,
68355ffd83dbSDimitry Andric                              MIRBuilder.buildConstant(S32, 0x7c00), V);
68365ffd83dbSDimitry Andric 
68375ffd83dbSDimitry Andric   auto CmpEGt1039 = MIRBuilder.buildICmp(CmpInst::ICMP_EQ, S1,
68385ffd83dbSDimitry Andric                                          E, MIRBuilder.buildConstant(S32, 1039));
68395ffd83dbSDimitry Andric   V = MIRBuilder.buildSelect(S32, CmpEGt1039, I, V);
68405ffd83dbSDimitry Andric 
68415ffd83dbSDimitry Andric   // Extract the sign bit.
68425ffd83dbSDimitry Andric   auto Sign = MIRBuilder.buildLShr(S32, UH, MIRBuilder.buildConstant(S32, 16));
68435ffd83dbSDimitry Andric   Sign = MIRBuilder.buildAnd(S32, Sign, MIRBuilder.buildConstant(S32, 0x8000));
68445ffd83dbSDimitry Andric 
68455ffd83dbSDimitry Andric   // Insert the sign bit
68465ffd83dbSDimitry Andric   V = MIRBuilder.buildOr(S32, Sign, V);
68475ffd83dbSDimitry Andric 
68485ffd83dbSDimitry Andric   MIRBuilder.buildTrunc(Dst, V);
68495ffd83dbSDimitry Andric   MI.eraseFromParent();
68505ffd83dbSDimitry Andric   return Legalized;
68515ffd83dbSDimitry Andric }
68525ffd83dbSDimitry Andric 
68535ffd83dbSDimitry Andric LegalizerHelper::LegalizeResult
6854e8d8bef9SDimitry Andric LegalizerHelper::lowerFPTRUNC(MachineInstr &MI) {
685506c3fb27SDimitry Andric   auto [DstTy, SrcTy] = MI.getFirst2LLTs();
68565ffd83dbSDimitry Andric   const LLT S64 = LLT::scalar(64);
68575ffd83dbSDimitry Andric   const LLT S16 = LLT::scalar(16);
68585ffd83dbSDimitry Andric 
68595ffd83dbSDimitry Andric   if (DstTy.getScalarType() == S16 && SrcTy.getScalarType() == S64)
68605ffd83dbSDimitry Andric     return lowerFPTRUNC_F64_TO_F16(MI);
68615ffd83dbSDimitry Andric 
68625ffd83dbSDimitry Andric   return UnableToLegalize;
68635ffd83dbSDimitry Andric }
68645ffd83dbSDimitry Andric 
6865e8d8bef9SDimitry Andric // TODO: If RHS is a constant SelectionDAGBuilder expands this into a
6866e8d8bef9SDimitry Andric // multiplication tree.
6867e8d8bef9SDimitry Andric LegalizerHelper::LegalizeResult LegalizerHelper::lowerFPOWI(MachineInstr &MI) {
686806c3fb27SDimitry Andric   auto [Dst, Src0, Src1] = MI.getFirst3Regs();
6869e8d8bef9SDimitry Andric   LLT Ty = MRI.getType(Dst);
6870e8d8bef9SDimitry Andric 
6871e8d8bef9SDimitry Andric   auto CvtSrc1 = MIRBuilder.buildSITOFP(Ty, Src1);
6872e8d8bef9SDimitry Andric   MIRBuilder.buildFPow(Dst, Src0, CvtSrc1, MI.getFlags());
6873e8d8bef9SDimitry Andric   MI.eraseFromParent();
6874e8d8bef9SDimitry Andric   return Legalized;
6875e8d8bef9SDimitry Andric }
6876e8d8bef9SDimitry Andric 
68770b57cec5SDimitry Andric static CmpInst::Predicate minMaxToCompare(unsigned Opc) {
68780b57cec5SDimitry Andric   switch (Opc) {
68790b57cec5SDimitry Andric   case TargetOpcode::G_SMIN:
68800b57cec5SDimitry Andric     return CmpInst::ICMP_SLT;
68810b57cec5SDimitry Andric   case TargetOpcode::G_SMAX:
68820b57cec5SDimitry Andric     return CmpInst::ICMP_SGT;
68830b57cec5SDimitry Andric   case TargetOpcode::G_UMIN:
68840b57cec5SDimitry Andric     return CmpInst::ICMP_ULT;
68850b57cec5SDimitry Andric   case TargetOpcode::G_UMAX:
68860b57cec5SDimitry Andric     return CmpInst::ICMP_UGT;
68870b57cec5SDimitry Andric   default:
68880b57cec5SDimitry Andric     llvm_unreachable("not in integer min/max");
68890b57cec5SDimitry Andric   }
68900b57cec5SDimitry Andric }
68910b57cec5SDimitry Andric 
6892e8d8bef9SDimitry Andric LegalizerHelper::LegalizeResult LegalizerHelper::lowerMinMax(MachineInstr &MI) {
689306c3fb27SDimitry Andric   auto [Dst, Src0, Src1] = MI.getFirst3Regs();
68940b57cec5SDimitry Andric 
68950b57cec5SDimitry Andric   const CmpInst::Predicate Pred = minMaxToCompare(MI.getOpcode());
68960b57cec5SDimitry Andric   LLT CmpType = MRI.getType(Dst).changeElementSize(1);
68970b57cec5SDimitry Andric 
68980b57cec5SDimitry Andric   auto Cmp = MIRBuilder.buildICmp(Pred, CmpType, Src0, Src1);
68990b57cec5SDimitry Andric   MIRBuilder.buildSelect(Dst, Cmp, Src0, Src1);
69000b57cec5SDimitry Andric 
69010b57cec5SDimitry Andric   MI.eraseFromParent();
69020b57cec5SDimitry Andric   return Legalized;
69030b57cec5SDimitry Andric }
69040b57cec5SDimitry Andric 
69050b57cec5SDimitry Andric LegalizerHelper::LegalizeResult
6906e8d8bef9SDimitry Andric LegalizerHelper::lowerFCopySign(MachineInstr &MI) {
690706c3fb27SDimitry Andric   auto [Dst, DstTy, Src0, Src0Ty, Src1, Src1Ty] = MI.getFirst3RegLLTs();
69080b57cec5SDimitry Andric   const int Src0Size = Src0Ty.getScalarSizeInBits();
69090b57cec5SDimitry Andric   const int Src1Size = Src1Ty.getScalarSizeInBits();
69100b57cec5SDimitry Andric 
69110b57cec5SDimitry Andric   auto SignBitMask = MIRBuilder.buildConstant(
69120b57cec5SDimitry Andric     Src0Ty, APInt::getSignMask(Src0Size));
69130b57cec5SDimitry Andric 
69140b57cec5SDimitry Andric   auto NotSignBitMask = MIRBuilder.buildConstant(
69150b57cec5SDimitry Andric     Src0Ty, APInt::getLowBitsSet(Src0Size, Src0Size - 1));
69160b57cec5SDimitry Andric 
6917fe6060f1SDimitry Andric   Register And0 = MIRBuilder.buildAnd(Src0Ty, Src0, NotSignBitMask).getReg(0);
6918fe6060f1SDimitry Andric   Register And1;
69190b57cec5SDimitry Andric   if (Src0Ty == Src1Ty) {
6920fe6060f1SDimitry Andric     And1 = MIRBuilder.buildAnd(Src1Ty, Src1, SignBitMask).getReg(0);
69210b57cec5SDimitry Andric   } else if (Src0Size > Src1Size) {
69220b57cec5SDimitry Andric     auto ShiftAmt = MIRBuilder.buildConstant(Src0Ty, Src0Size - Src1Size);
69230b57cec5SDimitry Andric     auto Zext = MIRBuilder.buildZExt(Src0Ty, Src1);
69240b57cec5SDimitry Andric     auto Shift = MIRBuilder.buildShl(Src0Ty, Zext, ShiftAmt);
6925fe6060f1SDimitry Andric     And1 = MIRBuilder.buildAnd(Src0Ty, Shift, SignBitMask).getReg(0);
69260b57cec5SDimitry Andric   } else {
69270b57cec5SDimitry Andric     auto ShiftAmt = MIRBuilder.buildConstant(Src1Ty, Src1Size - Src0Size);
69280b57cec5SDimitry Andric     auto Shift = MIRBuilder.buildLShr(Src1Ty, Src1, ShiftAmt);
69290b57cec5SDimitry Andric     auto Trunc = MIRBuilder.buildTrunc(Src0Ty, Shift);
6930fe6060f1SDimitry Andric     And1 = MIRBuilder.buildAnd(Src0Ty, Trunc, SignBitMask).getReg(0);
69310b57cec5SDimitry Andric   }
69320b57cec5SDimitry Andric 
69330b57cec5SDimitry Andric   // Be careful about setting nsz/nnan/ninf on every instruction, since the
69340b57cec5SDimitry Andric   // constants are a nan and -0.0, but the final result should preserve
69350b57cec5SDimitry Andric   // everything.
6936fe6060f1SDimitry Andric   unsigned Flags = MI.getFlags();
6937fe6060f1SDimitry Andric   MIRBuilder.buildOr(Dst, And0, And1, Flags);
69380b57cec5SDimitry Andric 
69390b57cec5SDimitry Andric   MI.eraseFromParent();
69400b57cec5SDimitry Andric   return Legalized;
69410b57cec5SDimitry Andric }
69420b57cec5SDimitry Andric 
69430b57cec5SDimitry Andric LegalizerHelper::LegalizeResult
69440b57cec5SDimitry Andric LegalizerHelper::lowerFMinNumMaxNum(MachineInstr &MI) {
69450b57cec5SDimitry Andric   unsigned NewOp = MI.getOpcode() == TargetOpcode::G_FMINNUM ?
69460b57cec5SDimitry Andric     TargetOpcode::G_FMINNUM_IEEE : TargetOpcode::G_FMAXNUM_IEEE;
69470b57cec5SDimitry Andric 
694806c3fb27SDimitry Andric   auto [Dst, Src0, Src1] = MI.getFirst3Regs();
69490b57cec5SDimitry Andric   LLT Ty = MRI.getType(Dst);
69500b57cec5SDimitry Andric 
69510b57cec5SDimitry Andric   if (!MI.getFlag(MachineInstr::FmNoNans)) {
69520b57cec5SDimitry Andric     // Insert canonicalizes if it's possible we need to quiet to get correct
69530b57cec5SDimitry Andric     // sNaN behavior.
69540b57cec5SDimitry Andric 
69550b57cec5SDimitry Andric     // Note this must be done here, and not as an optimization combine in the
69560b57cec5SDimitry Andric     // absence of a dedicate quiet-snan instruction as we're using an
69570b57cec5SDimitry Andric     // omni-purpose G_FCANONICALIZE.
69580b57cec5SDimitry Andric     if (!isKnownNeverSNaN(Src0, MRI))
69590b57cec5SDimitry Andric       Src0 = MIRBuilder.buildFCanonicalize(Ty, Src0, MI.getFlags()).getReg(0);
69600b57cec5SDimitry Andric 
69610b57cec5SDimitry Andric     if (!isKnownNeverSNaN(Src1, MRI))
69620b57cec5SDimitry Andric       Src1 = MIRBuilder.buildFCanonicalize(Ty, Src1, MI.getFlags()).getReg(0);
69630b57cec5SDimitry Andric   }
69640b57cec5SDimitry Andric 
69650b57cec5SDimitry Andric   // If there are no nans, it's safe to simply replace this with the non-IEEE
69660b57cec5SDimitry Andric   // version.
69670b57cec5SDimitry Andric   MIRBuilder.buildInstr(NewOp, {Dst}, {Src0, Src1}, MI.getFlags());
69680b57cec5SDimitry Andric   MI.eraseFromParent();
69690b57cec5SDimitry Andric   return Legalized;
69700b57cec5SDimitry Andric }
69718bcb0991SDimitry Andric 
69728bcb0991SDimitry Andric LegalizerHelper::LegalizeResult LegalizerHelper::lowerFMad(MachineInstr &MI) {
69738bcb0991SDimitry Andric   // Expand G_FMAD a, b, c -> G_FADD (G_FMUL a, b), c
69748bcb0991SDimitry Andric   Register DstReg = MI.getOperand(0).getReg();
69758bcb0991SDimitry Andric   LLT Ty = MRI.getType(DstReg);
69768bcb0991SDimitry Andric   unsigned Flags = MI.getFlags();
69778bcb0991SDimitry Andric 
69788bcb0991SDimitry Andric   auto Mul = MIRBuilder.buildFMul(Ty, MI.getOperand(1), MI.getOperand(2),
69798bcb0991SDimitry Andric                                   Flags);
69808bcb0991SDimitry Andric   MIRBuilder.buildFAdd(DstReg, Mul, MI.getOperand(3), Flags);
69818bcb0991SDimitry Andric   MI.eraseFromParent();
69828bcb0991SDimitry Andric   return Legalized;
69838bcb0991SDimitry Andric }
69848bcb0991SDimitry Andric 
69858bcb0991SDimitry Andric LegalizerHelper::LegalizeResult
6986480093f4SDimitry Andric LegalizerHelper::lowerIntrinsicRound(MachineInstr &MI) {
698706c3fb27SDimitry Andric   auto [DstReg, X] = MI.getFirst2Regs();
69885ffd83dbSDimitry Andric   const unsigned Flags = MI.getFlags();
69895ffd83dbSDimitry Andric   const LLT Ty = MRI.getType(DstReg);
69905ffd83dbSDimitry Andric   const LLT CondTy = Ty.changeElementSize(1);
69915ffd83dbSDimitry Andric 
69925ffd83dbSDimitry Andric   // round(x) =>
69935ffd83dbSDimitry Andric   //  t = trunc(x);
69945ffd83dbSDimitry Andric   //  d = fabs(x - t);
69955f757f3fSDimitry Andric   //  o = copysign(d >= 0.5 ? 1.0 : 0.0, x);
69965f757f3fSDimitry Andric   //  return t + o;
69975ffd83dbSDimitry Andric 
69985ffd83dbSDimitry Andric   auto T = MIRBuilder.buildIntrinsicTrunc(Ty, X, Flags);
69995ffd83dbSDimitry Andric 
70005ffd83dbSDimitry Andric   auto Diff = MIRBuilder.buildFSub(Ty, X, T, Flags);
70015ffd83dbSDimitry Andric   auto AbsDiff = MIRBuilder.buildFAbs(Ty, Diff, Flags);
70025f757f3fSDimitry Andric 
70035ffd83dbSDimitry Andric   auto Half = MIRBuilder.buildFConstant(Ty, 0.5);
70045f757f3fSDimitry Andric   auto Cmp =
70055f757f3fSDimitry Andric       MIRBuilder.buildFCmp(CmpInst::FCMP_OGE, CondTy, AbsDiff, Half, Flags);
70065ffd83dbSDimitry Andric 
70075f757f3fSDimitry Andric   // Could emit G_UITOFP instead
70085f757f3fSDimitry Andric   auto One = MIRBuilder.buildFConstant(Ty, 1.0);
70095f757f3fSDimitry Andric   auto Zero = MIRBuilder.buildFConstant(Ty, 0.0);
70105f757f3fSDimitry Andric   auto BoolFP = MIRBuilder.buildSelect(Ty, Cmp, One, Zero);
70115f757f3fSDimitry Andric   auto SignedOffset = MIRBuilder.buildFCopysign(Ty, BoolFP, X);
70125ffd83dbSDimitry Andric 
70135f757f3fSDimitry Andric   MIRBuilder.buildFAdd(DstReg, T, SignedOffset, Flags);
70145ffd83dbSDimitry Andric 
70155ffd83dbSDimitry Andric   MI.eraseFromParent();
70165ffd83dbSDimitry Andric   return Legalized;
70175ffd83dbSDimitry Andric }
70185ffd83dbSDimitry Andric 
701906c3fb27SDimitry Andric LegalizerHelper::LegalizeResult LegalizerHelper::lowerFFloor(MachineInstr &MI) {
702006c3fb27SDimitry Andric   auto [DstReg, SrcReg] = MI.getFirst2Regs();
7021480093f4SDimitry Andric   unsigned Flags = MI.getFlags();
7022480093f4SDimitry Andric   LLT Ty = MRI.getType(DstReg);
7023480093f4SDimitry Andric   const LLT CondTy = Ty.changeElementSize(1);
7024480093f4SDimitry Andric 
7025480093f4SDimitry Andric   // result = trunc(src);
7026480093f4SDimitry Andric   // if (src < 0.0 && src != result)
7027480093f4SDimitry Andric   //   result += -1.0.
7028480093f4SDimitry Andric 
7029480093f4SDimitry Andric   auto Trunc = MIRBuilder.buildIntrinsicTrunc(Ty, SrcReg, Flags);
70305ffd83dbSDimitry Andric   auto Zero = MIRBuilder.buildFConstant(Ty, 0.0);
7031480093f4SDimitry Andric 
7032480093f4SDimitry Andric   auto Lt0 = MIRBuilder.buildFCmp(CmpInst::FCMP_OLT, CondTy,
7033480093f4SDimitry Andric                                   SrcReg, Zero, Flags);
7034480093f4SDimitry Andric   auto NeTrunc = MIRBuilder.buildFCmp(CmpInst::FCMP_ONE, CondTy,
7035480093f4SDimitry Andric                                       SrcReg, Trunc, Flags);
7036480093f4SDimitry Andric   auto And = MIRBuilder.buildAnd(CondTy, Lt0, NeTrunc);
7037480093f4SDimitry Andric   auto AddVal = MIRBuilder.buildSITOFP(Ty, And);
7038480093f4SDimitry Andric 
70395ffd83dbSDimitry Andric   MIRBuilder.buildFAdd(DstReg, Trunc, AddVal, Flags);
70405ffd83dbSDimitry Andric   MI.eraseFromParent();
70415ffd83dbSDimitry Andric   return Legalized;
70425ffd83dbSDimitry Andric }
70435ffd83dbSDimitry Andric 
70445ffd83dbSDimitry Andric LegalizerHelper::LegalizeResult
70455ffd83dbSDimitry Andric LegalizerHelper::lowerMergeValues(MachineInstr &MI) {
70465ffd83dbSDimitry Andric   const unsigned NumOps = MI.getNumOperands();
704706c3fb27SDimitry Andric   auto [DstReg, DstTy, Src0Reg, Src0Ty] = MI.getFirst2RegLLTs();
704806c3fb27SDimitry Andric   unsigned PartSize = Src0Ty.getSizeInBits();
70495ffd83dbSDimitry Andric 
70505ffd83dbSDimitry Andric   LLT WideTy = LLT::scalar(DstTy.getSizeInBits());
70515ffd83dbSDimitry Andric   Register ResultReg = MIRBuilder.buildZExt(WideTy, Src0Reg).getReg(0);
70525ffd83dbSDimitry Andric 
70535ffd83dbSDimitry Andric   for (unsigned I = 2; I != NumOps; ++I) {
70545ffd83dbSDimitry Andric     const unsigned Offset = (I - 1) * PartSize;
70555ffd83dbSDimitry Andric 
70565ffd83dbSDimitry Andric     Register SrcReg = MI.getOperand(I).getReg();
70575ffd83dbSDimitry Andric     auto ZextInput = MIRBuilder.buildZExt(WideTy, SrcReg);
70585ffd83dbSDimitry Andric 
70595ffd83dbSDimitry Andric     Register NextResult = I + 1 == NumOps && WideTy == DstTy ? DstReg :
70605ffd83dbSDimitry Andric       MRI.createGenericVirtualRegister(WideTy);
70615ffd83dbSDimitry Andric 
70625ffd83dbSDimitry Andric     auto ShiftAmt = MIRBuilder.buildConstant(WideTy, Offset);
70635ffd83dbSDimitry Andric     auto Shl = MIRBuilder.buildShl(WideTy, ZextInput, ShiftAmt);
70645ffd83dbSDimitry Andric     MIRBuilder.buildOr(NextResult, ResultReg, Shl);
70655ffd83dbSDimitry Andric     ResultReg = NextResult;
70665ffd83dbSDimitry Andric   }
70675ffd83dbSDimitry Andric 
70685ffd83dbSDimitry Andric   if (DstTy.isPointer()) {
70695ffd83dbSDimitry Andric     if (MIRBuilder.getDataLayout().isNonIntegralAddressSpace(
70705ffd83dbSDimitry Andric           DstTy.getAddressSpace())) {
70715ffd83dbSDimitry Andric       LLVM_DEBUG(dbgs() << "Not casting nonintegral address space\n");
70725ffd83dbSDimitry Andric       return UnableToLegalize;
70735ffd83dbSDimitry Andric     }
70745ffd83dbSDimitry Andric 
70755ffd83dbSDimitry Andric     MIRBuilder.buildIntToPtr(DstReg, ResultReg);
70765ffd83dbSDimitry Andric   }
70775ffd83dbSDimitry Andric 
7078480093f4SDimitry Andric   MI.eraseFromParent();
7079480093f4SDimitry Andric   return Legalized;
7080480093f4SDimitry Andric }
7081480093f4SDimitry Andric 
7082480093f4SDimitry Andric LegalizerHelper::LegalizeResult
70838bcb0991SDimitry Andric LegalizerHelper::lowerUnmergeValues(MachineInstr &MI) {
70848bcb0991SDimitry Andric   const unsigned NumDst = MI.getNumOperands() - 1;
70855ffd83dbSDimitry Andric   Register SrcReg = MI.getOperand(NumDst).getReg();
70868bcb0991SDimitry Andric   Register Dst0Reg = MI.getOperand(0).getReg();
70878bcb0991SDimitry Andric   LLT DstTy = MRI.getType(Dst0Reg);
70885ffd83dbSDimitry Andric   if (DstTy.isPointer())
70895ffd83dbSDimitry Andric     return UnableToLegalize; // TODO
70908bcb0991SDimitry Andric 
70915ffd83dbSDimitry Andric   SrcReg = coerceToScalar(SrcReg);
70925ffd83dbSDimitry Andric   if (!SrcReg)
70935ffd83dbSDimitry Andric     return UnableToLegalize;
70948bcb0991SDimitry Andric 
70958bcb0991SDimitry Andric   // Expand scalarizing unmerge as bitcast to integer and shift.
70965ffd83dbSDimitry Andric   LLT IntTy = MRI.getType(SrcReg);
70978bcb0991SDimitry Andric 
70985ffd83dbSDimitry Andric   MIRBuilder.buildTrunc(Dst0Reg, SrcReg);
70998bcb0991SDimitry Andric 
71008bcb0991SDimitry Andric   const unsigned DstSize = DstTy.getSizeInBits();
71018bcb0991SDimitry Andric   unsigned Offset = DstSize;
71028bcb0991SDimitry Andric   for (unsigned I = 1; I != NumDst; ++I, Offset += DstSize) {
71038bcb0991SDimitry Andric     auto ShiftAmt = MIRBuilder.buildConstant(IntTy, Offset);
71045ffd83dbSDimitry Andric     auto Shift = MIRBuilder.buildLShr(IntTy, SrcReg, ShiftAmt);
71058bcb0991SDimitry Andric     MIRBuilder.buildTrunc(MI.getOperand(I), Shift);
71068bcb0991SDimitry Andric   }
71078bcb0991SDimitry Andric 
71088bcb0991SDimitry Andric   MI.eraseFromParent();
71098bcb0991SDimitry Andric   return Legalized;
71108bcb0991SDimitry Andric }
71118bcb0991SDimitry Andric 
7112e8d8bef9SDimitry Andric /// Lower a vector extract or insert by writing the vector to a stack temporary
7113e8d8bef9SDimitry Andric /// and reloading the element or vector.
7114e8d8bef9SDimitry Andric ///
7115e8d8bef9SDimitry Andric /// %dst = G_EXTRACT_VECTOR_ELT %vec, %idx
7116e8d8bef9SDimitry Andric ///  =>
7117e8d8bef9SDimitry Andric ///  %stack_temp = G_FRAME_INDEX
7118e8d8bef9SDimitry Andric ///  G_STORE %vec, %stack_temp
7119e8d8bef9SDimitry Andric ///  %idx = clamp(%idx, %vec.getNumElements())
7120e8d8bef9SDimitry Andric ///  %element_ptr = G_PTR_ADD %stack_temp, %idx
7121e8d8bef9SDimitry Andric ///  %dst = G_LOAD %element_ptr
7122e8d8bef9SDimitry Andric LegalizerHelper::LegalizeResult
7123e8d8bef9SDimitry Andric LegalizerHelper::lowerExtractInsertVectorElt(MachineInstr &MI) {
7124e8d8bef9SDimitry Andric   Register DstReg = MI.getOperand(0).getReg();
7125e8d8bef9SDimitry Andric   Register SrcVec = MI.getOperand(1).getReg();
7126e8d8bef9SDimitry Andric   Register InsertVal;
7127e8d8bef9SDimitry Andric   if (MI.getOpcode() == TargetOpcode::G_INSERT_VECTOR_ELT)
7128e8d8bef9SDimitry Andric     InsertVal = MI.getOperand(2).getReg();
7129e8d8bef9SDimitry Andric 
7130e8d8bef9SDimitry Andric   Register Idx = MI.getOperand(MI.getNumOperands() - 1).getReg();
7131e8d8bef9SDimitry Andric 
7132e8d8bef9SDimitry Andric   LLT VecTy = MRI.getType(SrcVec);
7133e8d8bef9SDimitry Andric   LLT EltTy = VecTy.getElementType();
71340eae32dcSDimitry Andric   unsigned NumElts = VecTy.getNumElements();
71350eae32dcSDimitry Andric 
71360eae32dcSDimitry Andric   int64_t IdxVal;
71370eae32dcSDimitry Andric   if (mi_match(Idx, MRI, m_ICst(IdxVal)) && IdxVal <= NumElts) {
71380eae32dcSDimitry Andric     SmallVector<Register, 8> SrcRegs;
7139*7a6dacacSDimitry Andric     extractParts(SrcVec, EltTy, NumElts, SrcRegs, MIRBuilder, MRI);
71400eae32dcSDimitry Andric 
71410eae32dcSDimitry Andric     if (InsertVal) {
71420eae32dcSDimitry Andric       SrcRegs[IdxVal] = MI.getOperand(2).getReg();
7143bdd1243dSDimitry Andric       MIRBuilder.buildMergeLikeInstr(DstReg, SrcRegs);
71440eae32dcSDimitry Andric     } else {
71450eae32dcSDimitry Andric       MIRBuilder.buildCopy(DstReg, SrcRegs[IdxVal]);
71460eae32dcSDimitry Andric     }
71470eae32dcSDimitry Andric 
71480eae32dcSDimitry Andric     MI.eraseFromParent();
71490eae32dcSDimitry Andric     return Legalized;
71500eae32dcSDimitry Andric   }
71510eae32dcSDimitry Andric 
7152e8d8bef9SDimitry Andric   if (!EltTy.isByteSized()) { // Not implemented.
7153e8d8bef9SDimitry Andric     LLVM_DEBUG(dbgs() << "Can't handle non-byte element vectors yet\n");
7154e8d8bef9SDimitry Andric     return UnableToLegalize;
7155e8d8bef9SDimitry Andric   }
7156e8d8bef9SDimitry Andric 
7157e8d8bef9SDimitry Andric   unsigned EltBytes = EltTy.getSizeInBytes();
7158e8d8bef9SDimitry Andric   Align VecAlign = getStackTemporaryAlignment(VecTy);
7159e8d8bef9SDimitry Andric   Align EltAlign;
7160e8d8bef9SDimitry Andric 
7161e8d8bef9SDimitry Andric   MachinePointerInfo PtrInfo;
71625f757f3fSDimitry Andric   auto StackTemp = createStackTemporary(
71635f757f3fSDimitry Andric       TypeSize::getFixed(VecTy.getSizeInBytes()), VecAlign, PtrInfo);
7164e8d8bef9SDimitry Andric   MIRBuilder.buildStore(SrcVec, StackTemp, PtrInfo, VecAlign);
7165e8d8bef9SDimitry Andric 
7166e8d8bef9SDimitry Andric   // Get the pointer to the element, and be sure not to hit undefined behavior
7167e8d8bef9SDimitry Andric   // if the index is out of bounds.
7168e8d8bef9SDimitry Andric   Register EltPtr = getVectorElementPointer(StackTemp.getReg(0), VecTy, Idx);
7169e8d8bef9SDimitry Andric 
7170e8d8bef9SDimitry Andric   if (mi_match(Idx, MRI, m_ICst(IdxVal))) {
7171e8d8bef9SDimitry Andric     int64_t Offset = IdxVal * EltBytes;
7172e8d8bef9SDimitry Andric     PtrInfo = PtrInfo.getWithOffset(Offset);
7173e8d8bef9SDimitry Andric     EltAlign = commonAlignment(VecAlign, Offset);
7174e8d8bef9SDimitry Andric   } else {
7175e8d8bef9SDimitry Andric     // We lose information with a variable offset.
7176e8d8bef9SDimitry Andric     EltAlign = getStackTemporaryAlignment(EltTy);
7177e8d8bef9SDimitry Andric     PtrInfo = MachinePointerInfo(MRI.getType(EltPtr).getAddressSpace());
7178e8d8bef9SDimitry Andric   }
7179e8d8bef9SDimitry Andric 
7180e8d8bef9SDimitry Andric   if (InsertVal) {
7181e8d8bef9SDimitry Andric     // Write the inserted element
7182e8d8bef9SDimitry Andric     MIRBuilder.buildStore(InsertVal, EltPtr, PtrInfo, EltAlign);
7183e8d8bef9SDimitry Andric 
7184e8d8bef9SDimitry Andric     // Reload the whole vector.
7185e8d8bef9SDimitry Andric     MIRBuilder.buildLoad(DstReg, StackTemp, PtrInfo, VecAlign);
7186e8d8bef9SDimitry Andric   } else {
7187e8d8bef9SDimitry Andric     MIRBuilder.buildLoad(DstReg, EltPtr, PtrInfo, EltAlign);
7188e8d8bef9SDimitry Andric   }
7189e8d8bef9SDimitry Andric 
7190e8d8bef9SDimitry Andric   MI.eraseFromParent();
7191e8d8bef9SDimitry Andric   return Legalized;
7192e8d8bef9SDimitry Andric }
7193e8d8bef9SDimitry Andric 
71948bcb0991SDimitry Andric LegalizerHelper::LegalizeResult
71958bcb0991SDimitry Andric LegalizerHelper::lowerShuffleVector(MachineInstr &MI) {
719606c3fb27SDimitry Andric   auto [DstReg, DstTy, Src0Reg, Src0Ty, Src1Reg, Src1Ty] =
719706c3fb27SDimitry Andric       MI.getFirst3RegLLTs();
71988bcb0991SDimitry Andric   LLT IdxTy = LLT::scalar(32);
71998bcb0991SDimitry Andric 
7200480093f4SDimitry Andric   ArrayRef<int> Mask = MI.getOperand(3).getShuffleMask();
72018bcb0991SDimitry Andric   Register Undef;
72028bcb0991SDimitry Andric   SmallVector<Register, 32> BuildVec;
72035f757f3fSDimitry Andric   LLT EltTy = DstTy.getScalarType();
72048bcb0991SDimitry Andric 
72058bcb0991SDimitry Andric   for (int Idx : Mask) {
72068bcb0991SDimitry Andric     if (Idx < 0) {
72078bcb0991SDimitry Andric       if (!Undef.isValid())
72088bcb0991SDimitry Andric         Undef = MIRBuilder.buildUndef(EltTy).getReg(0);
72098bcb0991SDimitry Andric       BuildVec.push_back(Undef);
72108bcb0991SDimitry Andric       continue;
72118bcb0991SDimitry Andric     }
72128bcb0991SDimitry Andric 
72138bcb0991SDimitry Andric     if (Src0Ty.isScalar()) {
72148bcb0991SDimitry Andric       BuildVec.push_back(Idx == 0 ? Src0Reg : Src1Reg);
72158bcb0991SDimitry Andric     } else {
72168bcb0991SDimitry Andric       int NumElts = Src0Ty.getNumElements();
72178bcb0991SDimitry Andric       Register SrcVec = Idx < NumElts ? Src0Reg : Src1Reg;
72188bcb0991SDimitry Andric       int ExtractIdx = Idx < NumElts ? Idx : Idx - NumElts;
72198bcb0991SDimitry Andric       auto IdxK = MIRBuilder.buildConstant(IdxTy, ExtractIdx);
72208bcb0991SDimitry Andric       auto Extract = MIRBuilder.buildExtractVectorElement(EltTy, SrcVec, IdxK);
72218bcb0991SDimitry Andric       BuildVec.push_back(Extract.getReg(0));
72228bcb0991SDimitry Andric     }
72238bcb0991SDimitry Andric   }
72248bcb0991SDimitry Andric 
72255f757f3fSDimitry Andric   if (DstTy.isScalar())
72265f757f3fSDimitry Andric     MIRBuilder.buildCopy(DstReg, BuildVec[0]);
72275f757f3fSDimitry Andric   else
72288bcb0991SDimitry Andric     MIRBuilder.buildBuildVector(DstReg, BuildVec);
72298bcb0991SDimitry Andric   MI.eraseFromParent();
72308bcb0991SDimitry Andric   return Legalized;
72318bcb0991SDimitry Andric }
72328bcb0991SDimitry Andric 
72335f757f3fSDimitry Andric Register LegalizerHelper::getDynStackAllocTargetPtr(Register SPReg,
72345f757f3fSDimitry Andric                                                     Register AllocSize,
72355f757f3fSDimitry Andric                                                     Align Alignment,
72365f757f3fSDimitry Andric                                                     LLT PtrTy) {
72378bcb0991SDimitry Andric   LLT IntPtrTy = LLT::scalar(PtrTy.getSizeInBits());
72388bcb0991SDimitry Andric 
72398bcb0991SDimitry Andric   auto SPTmp = MIRBuilder.buildCopy(PtrTy, SPReg);
72408bcb0991SDimitry Andric   SPTmp = MIRBuilder.buildCast(IntPtrTy, SPTmp);
72418bcb0991SDimitry Andric 
72428bcb0991SDimitry Andric   // Subtract the final alloc from the SP. We use G_PTRTOINT here so we don't
72438bcb0991SDimitry Andric   // have to generate an extra instruction to negate the alloc and then use
7244480093f4SDimitry Andric   // G_PTR_ADD to add the negative offset.
72458bcb0991SDimitry Andric   auto Alloc = MIRBuilder.buildSub(IntPtrTy, SPTmp, AllocSize);
72465ffd83dbSDimitry Andric   if (Alignment > Align(1)) {
72475ffd83dbSDimitry Andric     APInt AlignMask(IntPtrTy.getSizeInBits(), Alignment.value(), true);
72488bcb0991SDimitry Andric     AlignMask.negate();
72498bcb0991SDimitry Andric     auto AlignCst = MIRBuilder.buildConstant(IntPtrTy, AlignMask);
72508bcb0991SDimitry Andric     Alloc = MIRBuilder.buildAnd(IntPtrTy, Alloc, AlignCst);
72518bcb0991SDimitry Andric   }
72528bcb0991SDimitry Andric 
72535f757f3fSDimitry Andric   return MIRBuilder.buildCast(PtrTy, Alloc).getReg(0);
72545f757f3fSDimitry Andric }
72555f757f3fSDimitry Andric 
72565f757f3fSDimitry Andric LegalizerHelper::LegalizeResult
72575f757f3fSDimitry Andric LegalizerHelper::lowerDynStackAlloc(MachineInstr &MI) {
72585f757f3fSDimitry Andric   const auto &MF = *MI.getMF();
72595f757f3fSDimitry Andric   const auto &TFI = *MF.getSubtarget().getFrameLowering();
72605f757f3fSDimitry Andric   if (TFI.getStackGrowthDirection() == TargetFrameLowering::StackGrowsUp)
72615f757f3fSDimitry Andric     return UnableToLegalize;
72625f757f3fSDimitry Andric 
72635f757f3fSDimitry Andric   Register Dst = MI.getOperand(0).getReg();
72645f757f3fSDimitry Andric   Register AllocSize = MI.getOperand(1).getReg();
72655f757f3fSDimitry Andric   Align Alignment = assumeAligned(MI.getOperand(2).getImm());
72665f757f3fSDimitry Andric 
72675f757f3fSDimitry Andric   LLT PtrTy = MRI.getType(Dst);
72685f757f3fSDimitry Andric   Register SPReg = TLI.getStackPointerRegisterToSaveRestore();
72695f757f3fSDimitry Andric   Register SPTmp =
72705f757f3fSDimitry Andric       getDynStackAllocTargetPtr(SPReg, AllocSize, Alignment, PtrTy);
72715f757f3fSDimitry Andric 
72728bcb0991SDimitry Andric   MIRBuilder.buildCopy(SPReg, SPTmp);
72738bcb0991SDimitry Andric   MIRBuilder.buildCopy(Dst, SPTmp);
72748bcb0991SDimitry Andric 
72758bcb0991SDimitry Andric   MI.eraseFromParent();
72768bcb0991SDimitry Andric   return Legalized;
72778bcb0991SDimitry Andric }
72788bcb0991SDimitry Andric 
72798bcb0991SDimitry Andric LegalizerHelper::LegalizeResult
72805f757f3fSDimitry Andric LegalizerHelper::lowerStackSave(MachineInstr &MI) {
72815f757f3fSDimitry Andric   Register StackPtr = TLI.getStackPointerRegisterToSaveRestore();
72825f757f3fSDimitry Andric   if (!StackPtr)
72835f757f3fSDimitry Andric     return UnableToLegalize;
72845f757f3fSDimitry Andric 
72855f757f3fSDimitry Andric   MIRBuilder.buildCopy(MI.getOperand(0), StackPtr);
72865f757f3fSDimitry Andric   MI.eraseFromParent();
72875f757f3fSDimitry Andric   return Legalized;
72885f757f3fSDimitry Andric }
72895f757f3fSDimitry Andric 
72905f757f3fSDimitry Andric LegalizerHelper::LegalizeResult
72915f757f3fSDimitry Andric LegalizerHelper::lowerStackRestore(MachineInstr &MI) {
72925f757f3fSDimitry Andric   Register StackPtr = TLI.getStackPointerRegisterToSaveRestore();
72935f757f3fSDimitry Andric   if (!StackPtr)
72945f757f3fSDimitry Andric     return UnableToLegalize;
72955f757f3fSDimitry Andric 
72965f757f3fSDimitry Andric   MIRBuilder.buildCopy(StackPtr, MI.getOperand(0));
72975f757f3fSDimitry Andric   MI.eraseFromParent();
72985f757f3fSDimitry Andric   return Legalized;
72995f757f3fSDimitry Andric }
73005f757f3fSDimitry Andric 
73015f757f3fSDimitry Andric LegalizerHelper::LegalizeResult
73028bcb0991SDimitry Andric LegalizerHelper::lowerExtract(MachineInstr &MI) {
730306c3fb27SDimitry Andric   auto [DstReg, DstTy, SrcReg, SrcTy] = MI.getFirst2RegLLTs();
73048bcb0991SDimitry Andric   unsigned Offset = MI.getOperand(2).getImm();
73058bcb0991SDimitry Andric 
73060eae32dcSDimitry Andric   // Extract sub-vector or one element
73070eae32dcSDimitry Andric   if (SrcTy.isVector()) {
73080eae32dcSDimitry Andric     unsigned SrcEltSize = SrcTy.getElementType().getSizeInBits();
73090eae32dcSDimitry Andric     unsigned DstSize = DstTy.getSizeInBits();
73100eae32dcSDimitry Andric 
73110eae32dcSDimitry Andric     if ((Offset % SrcEltSize == 0) && (DstSize % SrcEltSize == 0) &&
73120eae32dcSDimitry Andric         (Offset + DstSize <= SrcTy.getSizeInBits())) {
73130eae32dcSDimitry Andric       // Unmerge and allow access to each Src element for the artifact combiner.
731406c3fb27SDimitry Andric       auto Unmerge = MIRBuilder.buildUnmerge(SrcTy.getElementType(), SrcReg);
73150eae32dcSDimitry Andric 
73160eae32dcSDimitry Andric       // Take element(s) we need to extract and copy it (merge them).
73170eae32dcSDimitry Andric       SmallVector<Register, 8> SubVectorElts;
73180eae32dcSDimitry Andric       for (unsigned Idx = Offset / SrcEltSize;
73190eae32dcSDimitry Andric            Idx < (Offset + DstSize) / SrcEltSize; ++Idx) {
73200eae32dcSDimitry Andric         SubVectorElts.push_back(Unmerge.getReg(Idx));
73210eae32dcSDimitry Andric       }
73220eae32dcSDimitry Andric       if (SubVectorElts.size() == 1)
732306c3fb27SDimitry Andric         MIRBuilder.buildCopy(DstReg, SubVectorElts[0]);
73240eae32dcSDimitry Andric       else
732506c3fb27SDimitry Andric         MIRBuilder.buildMergeLikeInstr(DstReg, SubVectorElts);
73260eae32dcSDimitry Andric 
73270eae32dcSDimitry Andric       MI.eraseFromParent();
73280eae32dcSDimitry Andric       return Legalized;
73290eae32dcSDimitry Andric     }
73300eae32dcSDimitry Andric   }
73310eae32dcSDimitry Andric 
73328bcb0991SDimitry Andric   if (DstTy.isScalar() &&
73338bcb0991SDimitry Andric       (SrcTy.isScalar() ||
73348bcb0991SDimitry Andric        (SrcTy.isVector() && DstTy == SrcTy.getElementType()))) {
73358bcb0991SDimitry Andric     LLT SrcIntTy = SrcTy;
73368bcb0991SDimitry Andric     if (!SrcTy.isScalar()) {
73378bcb0991SDimitry Andric       SrcIntTy = LLT::scalar(SrcTy.getSizeInBits());
733806c3fb27SDimitry Andric       SrcReg = MIRBuilder.buildBitcast(SrcIntTy, SrcReg).getReg(0);
73398bcb0991SDimitry Andric     }
73408bcb0991SDimitry Andric 
73418bcb0991SDimitry Andric     if (Offset == 0)
734206c3fb27SDimitry Andric       MIRBuilder.buildTrunc(DstReg, SrcReg);
73438bcb0991SDimitry Andric     else {
73448bcb0991SDimitry Andric       auto ShiftAmt = MIRBuilder.buildConstant(SrcIntTy, Offset);
734506c3fb27SDimitry Andric       auto Shr = MIRBuilder.buildLShr(SrcIntTy, SrcReg, ShiftAmt);
734606c3fb27SDimitry Andric       MIRBuilder.buildTrunc(DstReg, Shr);
73478bcb0991SDimitry Andric     }
73488bcb0991SDimitry Andric 
73498bcb0991SDimitry Andric     MI.eraseFromParent();
73508bcb0991SDimitry Andric     return Legalized;
73518bcb0991SDimitry Andric   }
73528bcb0991SDimitry Andric 
73538bcb0991SDimitry Andric   return UnableToLegalize;
73548bcb0991SDimitry Andric }
73558bcb0991SDimitry Andric 
73568bcb0991SDimitry Andric LegalizerHelper::LegalizeResult LegalizerHelper::lowerInsert(MachineInstr &MI) {
735706c3fb27SDimitry Andric   auto [Dst, Src, InsertSrc] = MI.getFirst3Regs();
73588bcb0991SDimitry Andric   uint64_t Offset = MI.getOperand(3).getImm();
73598bcb0991SDimitry Andric 
73608bcb0991SDimitry Andric   LLT DstTy = MRI.getType(Src);
73618bcb0991SDimitry Andric   LLT InsertTy = MRI.getType(InsertSrc);
73628bcb0991SDimitry Andric 
73630eae32dcSDimitry Andric   // Insert sub-vector or one element
73640eae32dcSDimitry Andric   if (DstTy.isVector() && !InsertTy.isPointer()) {
73650eae32dcSDimitry Andric     LLT EltTy = DstTy.getElementType();
73660eae32dcSDimitry Andric     unsigned EltSize = EltTy.getSizeInBits();
73670eae32dcSDimitry Andric     unsigned InsertSize = InsertTy.getSizeInBits();
73680eae32dcSDimitry Andric 
73690eae32dcSDimitry Andric     if ((Offset % EltSize == 0) && (InsertSize % EltSize == 0) &&
73700eae32dcSDimitry Andric         (Offset + InsertSize <= DstTy.getSizeInBits())) {
73710eae32dcSDimitry Andric       auto UnmergeSrc = MIRBuilder.buildUnmerge(EltTy, Src);
73720eae32dcSDimitry Andric       SmallVector<Register, 8> DstElts;
73730eae32dcSDimitry Andric       unsigned Idx = 0;
73740eae32dcSDimitry Andric       // Elements from Src before insert start Offset
73750eae32dcSDimitry Andric       for (; Idx < Offset / EltSize; ++Idx) {
73760eae32dcSDimitry Andric         DstElts.push_back(UnmergeSrc.getReg(Idx));
73770eae32dcSDimitry Andric       }
73780eae32dcSDimitry Andric 
73790eae32dcSDimitry Andric       // Replace elements in Src with elements from InsertSrc
73800eae32dcSDimitry Andric       if (InsertTy.getSizeInBits() > EltSize) {
73810eae32dcSDimitry Andric         auto UnmergeInsertSrc = MIRBuilder.buildUnmerge(EltTy, InsertSrc);
73820eae32dcSDimitry Andric         for (unsigned i = 0; Idx < (Offset + InsertSize) / EltSize;
73830eae32dcSDimitry Andric              ++Idx, ++i) {
73840eae32dcSDimitry Andric           DstElts.push_back(UnmergeInsertSrc.getReg(i));
73850eae32dcSDimitry Andric         }
73860eae32dcSDimitry Andric       } else {
73870eae32dcSDimitry Andric         DstElts.push_back(InsertSrc);
73880eae32dcSDimitry Andric         ++Idx;
73890eae32dcSDimitry Andric       }
73900eae32dcSDimitry Andric 
73910eae32dcSDimitry Andric       // Remaining elements from Src after insert
73920eae32dcSDimitry Andric       for (; Idx < DstTy.getNumElements(); ++Idx) {
73930eae32dcSDimitry Andric         DstElts.push_back(UnmergeSrc.getReg(Idx));
73940eae32dcSDimitry Andric       }
73950eae32dcSDimitry Andric 
7396bdd1243dSDimitry Andric       MIRBuilder.buildMergeLikeInstr(Dst, DstElts);
73970eae32dcSDimitry Andric       MI.eraseFromParent();
73980eae32dcSDimitry Andric       return Legalized;
73990eae32dcSDimitry Andric     }
74000eae32dcSDimitry Andric   }
74010eae32dcSDimitry Andric 
74025ffd83dbSDimitry Andric   if (InsertTy.isVector() ||
74035ffd83dbSDimitry Andric       (DstTy.isVector() && DstTy.getElementType() != InsertTy))
74045ffd83dbSDimitry Andric     return UnableToLegalize;
74055ffd83dbSDimitry Andric 
74065ffd83dbSDimitry Andric   const DataLayout &DL = MIRBuilder.getDataLayout();
74075ffd83dbSDimitry Andric   if ((DstTy.isPointer() &&
74085ffd83dbSDimitry Andric        DL.isNonIntegralAddressSpace(DstTy.getAddressSpace())) ||
74095ffd83dbSDimitry Andric       (InsertTy.isPointer() &&
74105ffd83dbSDimitry Andric        DL.isNonIntegralAddressSpace(InsertTy.getAddressSpace()))) {
74115ffd83dbSDimitry Andric     LLVM_DEBUG(dbgs() << "Not casting non-integral address space integer\n");
74125ffd83dbSDimitry Andric     return UnableToLegalize;
74135ffd83dbSDimitry Andric   }
74145ffd83dbSDimitry Andric 
74158bcb0991SDimitry Andric   LLT IntDstTy = DstTy;
74165ffd83dbSDimitry Andric 
74178bcb0991SDimitry Andric   if (!DstTy.isScalar()) {
74188bcb0991SDimitry Andric     IntDstTy = LLT::scalar(DstTy.getSizeInBits());
74195ffd83dbSDimitry Andric     Src = MIRBuilder.buildCast(IntDstTy, Src).getReg(0);
74205ffd83dbSDimitry Andric   }
74215ffd83dbSDimitry Andric 
74225ffd83dbSDimitry Andric   if (!InsertTy.isScalar()) {
74235ffd83dbSDimitry Andric     const LLT IntInsertTy = LLT::scalar(InsertTy.getSizeInBits());
74245ffd83dbSDimitry Andric     InsertSrc = MIRBuilder.buildPtrToInt(IntInsertTy, InsertSrc).getReg(0);
74258bcb0991SDimitry Andric   }
74268bcb0991SDimitry Andric 
74278bcb0991SDimitry Andric   Register ExtInsSrc = MIRBuilder.buildZExt(IntDstTy, InsertSrc).getReg(0);
74288bcb0991SDimitry Andric   if (Offset != 0) {
74298bcb0991SDimitry Andric     auto ShiftAmt = MIRBuilder.buildConstant(IntDstTy, Offset);
74308bcb0991SDimitry Andric     ExtInsSrc = MIRBuilder.buildShl(IntDstTy, ExtInsSrc, ShiftAmt).getReg(0);
74318bcb0991SDimitry Andric   }
74328bcb0991SDimitry Andric 
74335ffd83dbSDimitry Andric   APInt MaskVal = APInt::getBitsSetWithWrap(
74345ffd83dbSDimitry Andric       DstTy.getSizeInBits(), Offset + InsertTy.getSizeInBits(), Offset);
74358bcb0991SDimitry Andric 
74368bcb0991SDimitry Andric   auto Mask = MIRBuilder.buildConstant(IntDstTy, MaskVal);
74378bcb0991SDimitry Andric   auto MaskedSrc = MIRBuilder.buildAnd(IntDstTy, Src, Mask);
74388bcb0991SDimitry Andric   auto Or = MIRBuilder.buildOr(IntDstTy, MaskedSrc, ExtInsSrc);
74398bcb0991SDimitry Andric 
74405ffd83dbSDimitry Andric   MIRBuilder.buildCast(Dst, Or);
74418bcb0991SDimitry Andric   MI.eraseFromParent();
74428bcb0991SDimitry Andric   return Legalized;
74438bcb0991SDimitry Andric }
74448bcb0991SDimitry Andric 
74458bcb0991SDimitry Andric LegalizerHelper::LegalizeResult
74468bcb0991SDimitry Andric LegalizerHelper::lowerSADDO_SSUBO(MachineInstr &MI) {
744706c3fb27SDimitry Andric   auto [Dst0, Dst0Ty, Dst1, Dst1Ty, LHS, LHSTy, RHS, RHSTy] =
744806c3fb27SDimitry Andric       MI.getFirst4RegLLTs();
74498bcb0991SDimitry Andric   const bool IsAdd = MI.getOpcode() == TargetOpcode::G_SADDO;
74508bcb0991SDimitry Andric 
745106c3fb27SDimitry Andric   LLT Ty = Dst0Ty;
745206c3fb27SDimitry Andric   LLT BoolTy = Dst1Ty;
74538bcb0991SDimitry Andric 
74548bcb0991SDimitry Andric   if (IsAdd)
74558bcb0991SDimitry Andric     MIRBuilder.buildAdd(Dst0, LHS, RHS);
74568bcb0991SDimitry Andric   else
74578bcb0991SDimitry Andric     MIRBuilder.buildSub(Dst0, LHS, RHS);
74588bcb0991SDimitry Andric 
74598bcb0991SDimitry Andric   // TODO: If SADDSAT/SSUBSAT is legal, compare results to detect overflow.
74608bcb0991SDimitry Andric 
74618bcb0991SDimitry Andric   auto Zero = MIRBuilder.buildConstant(Ty, 0);
74628bcb0991SDimitry Andric 
74638bcb0991SDimitry Andric   // For an addition, the result should be less than one of the operands (LHS)
74648bcb0991SDimitry Andric   // if and only if the other operand (RHS) is negative, otherwise there will
74658bcb0991SDimitry Andric   // be overflow.
74668bcb0991SDimitry Andric   // For a subtraction, the result should be less than one of the operands
74678bcb0991SDimitry Andric   // (LHS) if and only if the other operand (RHS) is (non-zero) positive,
74688bcb0991SDimitry Andric   // otherwise there will be overflow.
74698bcb0991SDimitry Andric   auto ResultLowerThanLHS =
74708bcb0991SDimitry Andric       MIRBuilder.buildICmp(CmpInst::ICMP_SLT, BoolTy, Dst0, LHS);
74718bcb0991SDimitry Andric   auto ConditionRHS = MIRBuilder.buildICmp(
74728bcb0991SDimitry Andric       IsAdd ? CmpInst::ICMP_SLT : CmpInst::ICMP_SGT, BoolTy, RHS, Zero);
74738bcb0991SDimitry Andric 
74748bcb0991SDimitry Andric   MIRBuilder.buildXor(Dst1, ConditionRHS, ResultLowerThanLHS);
74758bcb0991SDimitry Andric   MI.eraseFromParent();
74768bcb0991SDimitry Andric   return Legalized;
74778bcb0991SDimitry Andric }
7478480093f4SDimitry Andric 
7479480093f4SDimitry Andric LegalizerHelper::LegalizeResult
7480e8d8bef9SDimitry Andric LegalizerHelper::lowerAddSubSatToMinMax(MachineInstr &MI) {
748106c3fb27SDimitry Andric   auto [Res, LHS, RHS] = MI.getFirst3Regs();
7482e8d8bef9SDimitry Andric   LLT Ty = MRI.getType(Res);
7483e8d8bef9SDimitry Andric   bool IsSigned;
7484e8d8bef9SDimitry Andric   bool IsAdd;
7485e8d8bef9SDimitry Andric   unsigned BaseOp;
7486e8d8bef9SDimitry Andric   switch (MI.getOpcode()) {
7487e8d8bef9SDimitry Andric   default:
7488e8d8bef9SDimitry Andric     llvm_unreachable("unexpected addsat/subsat opcode");
7489e8d8bef9SDimitry Andric   case TargetOpcode::G_UADDSAT:
7490e8d8bef9SDimitry Andric     IsSigned = false;
7491e8d8bef9SDimitry Andric     IsAdd = true;
7492e8d8bef9SDimitry Andric     BaseOp = TargetOpcode::G_ADD;
7493e8d8bef9SDimitry Andric     break;
7494e8d8bef9SDimitry Andric   case TargetOpcode::G_SADDSAT:
7495e8d8bef9SDimitry Andric     IsSigned = true;
7496e8d8bef9SDimitry Andric     IsAdd = true;
7497e8d8bef9SDimitry Andric     BaseOp = TargetOpcode::G_ADD;
7498e8d8bef9SDimitry Andric     break;
7499e8d8bef9SDimitry Andric   case TargetOpcode::G_USUBSAT:
7500e8d8bef9SDimitry Andric     IsSigned = false;
7501e8d8bef9SDimitry Andric     IsAdd = false;
7502e8d8bef9SDimitry Andric     BaseOp = TargetOpcode::G_SUB;
7503e8d8bef9SDimitry Andric     break;
7504e8d8bef9SDimitry Andric   case TargetOpcode::G_SSUBSAT:
7505e8d8bef9SDimitry Andric     IsSigned = true;
7506e8d8bef9SDimitry Andric     IsAdd = false;
7507e8d8bef9SDimitry Andric     BaseOp = TargetOpcode::G_SUB;
7508e8d8bef9SDimitry Andric     break;
7509e8d8bef9SDimitry Andric   }
7510e8d8bef9SDimitry Andric 
7511e8d8bef9SDimitry Andric   if (IsSigned) {
7512e8d8bef9SDimitry Andric     // sadd.sat(a, b) ->
7513e8d8bef9SDimitry Andric     //   hi = 0x7fffffff - smax(a, 0)
7514e8d8bef9SDimitry Andric     //   lo = 0x80000000 - smin(a, 0)
7515e8d8bef9SDimitry Andric     //   a + smin(smax(lo, b), hi)
7516e8d8bef9SDimitry Andric     // ssub.sat(a, b) ->
7517e8d8bef9SDimitry Andric     //   lo = smax(a, -1) - 0x7fffffff
7518e8d8bef9SDimitry Andric     //   hi = smin(a, -1) - 0x80000000
7519e8d8bef9SDimitry Andric     //   a - smin(smax(lo, b), hi)
7520e8d8bef9SDimitry Andric     // TODO: AMDGPU can use a "median of 3" instruction here:
7521e8d8bef9SDimitry Andric     //   a +/- med3(lo, b, hi)
7522e8d8bef9SDimitry Andric     uint64_t NumBits = Ty.getScalarSizeInBits();
7523e8d8bef9SDimitry Andric     auto MaxVal =
7524e8d8bef9SDimitry Andric         MIRBuilder.buildConstant(Ty, APInt::getSignedMaxValue(NumBits));
7525e8d8bef9SDimitry Andric     auto MinVal =
7526e8d8bef9SDimitry Andric         MIRBuilder.buildConstant(Ty, APInt::getSignedMinValue(NumBits));
7527e8d8bef9SDimitry Andric     MachineInstrBuilder Hi, Lo;
7528e8d8bef9SDimitry Andric     if (IsAdd) {
7529e8d8bef9SDimitry Andric       auto Zero = MIRBuilder.buildConstant(Ty, 0);
7530e8d8bef9SDimitry Andric       Hi = MIRBuilder.buildSub(Ty, MaxVal, MIRBuilder.buildSMax(Ty, LHS, Zero));
7531e8d8bef9SDimitry Andric       Lo = MIRBuilder.buildSub(Ty, MinVal, MIRBuilder.buildSMin(Ty, LHS, Zero));
7532e8d8bef9SDimitry Andric     } else {
7533e8d8bef9SDimitry Andric       auto NegOne = MIRBuilder.buildConstant(Ty, -1);
7534e8d8bef9SDimitry Andric       Lo = MIRBuilder.buildSub(Ty, MIRBuilder.buildSMax(Ty, LHS, NegOne),
7535e8d8bef9SDimitry Andric                                MaxVal);
7536e8d8bef9SDimitry Andric       Hi = MIRBuilder.buildSub(Ty, MIRBuilder.buildSMin(Ty, LHS, NegOne),
7537e8d8bef9SDimitry Andric                                MinVal);
7538e8d8bef9SDimitry Andric     }
7539e8d8bef9SDimitry Andric     auto RHSClamped =
7540e8d8bef9SDimitry Andric         MIRBuilder.buildSMin(Ty, MIRBuilder.buildSMax(Ty, Lo, RHS), Hi);
7541e8d8bef9SDimitry Andric     MIRBuilder.buildInstr(BaseOp, {Res}, {LHS, RHSClamped});
7542e8d8bef9SDimitry Andric   } else {
7543e8d8bef9SDimitry Andric     // uadd.sat(a, b) -> a + umin(~a, b)
7544e8d8bef9SDimitry Andric     // usub.sat(a, b) -> a - umin(a, b)
7545e8d8bef9SDimitry Andric     Register Not = IsAdd ? MIRBuilder.buildNot(Ty, LHS).getReg(0) : LHS;
7546e8d8bef9SDimitry Andric     auto Min = MIRBuilder.buildUMin(Ty, Not, RHS);
7547e8d8bef9SDimitry Andric     MIRBuilder.buildInstr(BaseOp, {Res}, {LHS, Min});
7548e8d8bef9SDimitry Andric   }
7549e8d8bef9SDimitry Andric 
7550e8d8bef9SDimitry Andric   MI.eraseFromParent();
7551e8d8bef9SDimitry Andric   return Legalized;
7552e8d8bef9SDimitry Andric }
7553e8d8bef9SDimitry Andric 
7554e8d8bef9SDimitry Andric LegalizerHelper::LegalizeResult
7555e8d8bef9SDimitry Andric LegalizerHelper::lowerAddSubSatToAddoSubo(MachineInstr &MI) {
755606c3fb27SDimitry Andric   auto [Res, LHS, RHS] = MI.getFirst3Regs();
7557e8d8bef9SDimitry Andric   LLT Ty = MRI.getType(Res);
7558e8d8bef9SDimitry Andric   LLT BoolTy = Ty.changeElementSize(1);
7559e8d8bef9SDimitry Andric   bool IsSigned;
7560e8d8bef9SDimitry Andric   bool IsAdd;
7561e8d8bef9SDimitry Andric   unsigned OverflowOp;
7562e8d8bef9SDimitry Andric   switch (MI.getOpcode()) {
7563e8d8bef9SDimitry Andric   default:
7564e8d8bef9SDimitry Andric     llvm_unreachable("unexpected addsat/subsat opcode");
7565e8d8bef9SDimitry Andric   case TargetOpcode::G_UADDSAT:
7566e8d8bef9SDimitry Andric     IsSigned = false;
7567e8d8bef9SDimitry Andric     IsAdd = true;
7568e8d8bef9SDimitry Andric     OverflowOp = TargetOpcode::G_UADDO;
7569e8d8bef9SDimitry Andric     break;
7570e8d8bef9SDimitry Andric   case TargetOpcode::G_SADDSAT:
7571e8d8bef9SDimitry Andric     IsSigned = true;
7572e8d8bef9SDimitry Andric     IsAdd = true;
7573e8d8bef9SDimitry Andric     OverflowOp = TargetOpcode::G_SADDO;
7574e8d8bef9SDimitry Andric     break;
7575e8d8bef9SDimitry Andric   case TargetOpcode::G_USUBSAT:
7576e8d8bef9SDimitry Andric     IsSigned = false;
7577e8d8bef9SDimitry Andric     IsAdd = false;
7578e8d8bef9SDimitry Andric     OverflowOp = TargetOpcode::G_USUBO;
7579e8d8bef9SDimitry Andric     break;
7580e8d8bef9SDimitry Andric   case TargetOpcode::G_SSUBSAT:
7581e8d8bef9SDimitry Andric     IsSigned = true;
7582e8d8bef9SDimitry Andric     IsAdd = false;
7583e8d8bef9SDimitry Andric     OverflowOp = TargetOpcode::G_SSUBO;
7584e8d8bef9SDimitry Andric     break;
7585e8d8bef9SDimitry Andric   }
7586e8d8bef9SDimitry Andric 
7587e8d8bef9SDimitry Andric   auto OverflowRes =
7588e8d8bef9SDimitry Andric       MIRBuilder.buildInstr(OverflowOp, {Ty, BoolTy}, {LHS, RHS});
7589e8d8bef9SDimitry Andric   Register Tmp = OverflowRes.getReg(0);
7590e8d8bef9SDimitry Andric   Register Ov = OverflowRes.getReg(1);
7591e8d8bef9SDimitry Andric   MachineInstrBuilder Clamp;
7592e8d8bef9SDimitry Andric   if (IsSigned) {
7593e8d8bef9SDimitry Andric     // sadd.sat(a, b) ->
7594e8d8bef9SDimitry Andric     //   {tmp, ov} = saddo(a, b)
7595e8d8bef9SDimitry Andric     //   ov ? (tmp >>s 31) + 0x80000000 : r
7596e8d8bef9SDimitry Andric     // ssub.sat(a, b) ->
7597e8d8bef9SDimitry Andric     //   {tmp, ov} = ssubo(a, b)
7598e8d8bef9SDimitry Andric     //   ov ? (tmp >>s 31) + 0x80000000 : r
7599e8d8bef9SDimitry Andric     uint64_t NumBits = Ty.getScalarSizeInBits();
7600e8d8bef9SDimitry Andric     auto ShiftAmount = MIRBuilder.buildConstant(Ty, NumBits - 1);
7601e8d8bef9SDimitry Andric     auto Sign = MIRBuilder.buildAShr(Ty, Tmp, ShiftAmount);
7602e8d8bef9SDimitry Andric     auto MinVal =
7603e8d8bef9SDimitry Andric         MIRBuilder.buildConstant(Ty, APInt::getSignedMinValue(NumBits));
7604e8d8bef9SDimitry Andric     Clamp = MIRBuilder.buildAdd(Ty, Sign, MinVal);
7605e8d8bef9SDimitry Andric   } else {
7606e8d8bef9SDimitry Andric     // uadd.sat(a, b) ->
7607e8d8bef9SDimitry Andric     //   {tmp, ov} = uaddo(a, b)
7608e8d8bef9SDimitry Andric     //   ov ? 0xffffffff : tmp
7609e8d8bef9SDimitry Andric     // usub.sat(a, b) ->
7610e8d8bef9SDimitry Andric     //   {tmp, ov} = usubo(a, b)
7611e8d8bef9SDimitry Andric     //   ov ? 0 : tmp
7612e8d8bef9SDimitry Andric     Clamp = MIRBuilder.buildConstant(Ty, IsAdd ? -1 : 0);
7613e8d8bef9SDimitry Andric   }
7614e8d8bef9SDimitry Andric   MIRBuilder.buildSelect(Res, Ov, Clamp, Tmp);
7615e8d8bef9SDimitry Andric 
7616e8d8bef9SDimitry Andric   MI.eraseFromParent();
7617e8d8bef9SDimitry Andric   return Legalized;
7618e8d8bef9SDimitry Andric }
7619e8d8bef9SDimitry Andric 
7620e8d8bef9SDimitry Andric LegalizerHelper::LegalizeResult
7621e8d8bef9SDimitry Andric LegalizerHelper::lowerShlSat(MachineInstr &MI) {
7622e8d8bef9SDimitry Andric   assert((MI.getOpcode() == TargetOpcode::G_SSHLSAT ||
7623e8d8bef9SDimitry Andric           MI.getOpcode() == TargetOpcode::G_USHLSAT) &&
7624e8d8bef9SDimitry Andric          "Expected shlsat opcode!");
7625e8d8bef9SDimitry Andric   bool IsSigned = MI.getOpcode() == TargetOpcode::G_SSHLSAT;
762606c3fb27SDimitry Andric   auto [Res, LHS, RHS] = MI.getFirst3Regs();
7627e8d8bef9SDimitry Andric   LLT Ty = MRI.getType(Res);
7628e8d8bef9SDimitry Andric   LLT BoolTy = Ty.changeElementSize(1);
7629e8d8bef9SDimitry Andric 
7630e8d8bef9SDimitry Andric   unsigned BW = Ty.getScalarSizeInBits();
7631e8d8bef9SDimitry Andric   auto Result = MIRBuilder.buildShl(Ty, LHS, RHS);
7632e8d8bef9SDimitry Andric   auto Orig = IsSigned ? MIRBuilder.buildAShr(Ty, Result, RHS)
7633e8d8bef9SDimitry Andric                        : MIRBuilder.buildLShr(Ty, Result, RHS);
7634e8d8bef9SDimitry Andric 
7635e8d8bef9SDimitry Andric   MachineInstrBuilder SatVal;
7636e8d8bef9SDimitry Andric   if (IsSigned) {
7637e8d8bef9SDimitry Andric     auto SatMin = MIRBuilder.buildConstant(Ty, APInt::getSignedMinValue(BW));
7638e8d8bef9SDimitry Andric     auto SatMax = MIRBuilder.buildConstant(Ty, APInt::getSignedMaxValue(BW));
7639e8d8bef9SDimitry Andric     auto Cmp = MIRBuilder.buildICmp(CmpInst::ICMP_SLT, BoolTy, LHS,
7640e8d8bef9SDimitry Andric                                     MIRBuilder.buildConstant(Ty, 0));
7641e8d8bef9SDimitry Andric     SatVal = MIRBuilder.buildSelect(Ty, Cmp, SatMin, SatMax);
7642e8d8bef9SDimitry Andric   } else {
7643e8d8bef9SDimitry Andric     SatVal = MIRBuilder.buildConstant(Ty, APInt::getMaxValue(BW));
7644e8d8bef9SDimitry Andric   }
7645e8d8bef9SDimitry Andric   auto Ov = MIRBuilder.buildICmp(CmpInst::ICMP_NE, BoolTy, LHS, Orig);
7646e8d8bef9SDimitry Andric   MIRBuilder.buildSelect(Res, Ov, SatVal, Result);
7647e8d8bef9SDimitry Andric 
7648e8d8bef9SDimitry Andric   MI.eraseFromParent();
7649e8d8bef9SDimitry Andric   return Legalized;
7650e8d8bef9SDimitry Andric }
7651e8d8bef9SDimitry Andric 
765206c3fb27SDimitry Andric LegalizerHelper::LegalizeResult LegalizerHelper::lowerBswap(MachineInstr &MI) {
765306c3fb27SDimitry Andric   auto [Dst, Src] = MI.getFirst2Regs();
7654480093f4SDimitry Andric   const LLT Ty = MRI.getType(Src);
76555ffd83dbSDimitry Andric   unsigned SizeInBytes = (Ty.getScalarSizeInBits() + 7) / 8;
7656480093f4SDimitry Andric   unsigned BaseShiftAmt = (SizeInBytes - 1) * 8;
7657480093f4SDimitry Andric 
7658480093f4SDimitry Andric   // Swap most and least significant byte, set remaining bytes in Res to zero.
7659480093f4SDimitry Andric   auto ShiftAmt = MIRBuilder.buildConstant(Ty, BaseShiftAmt);
7660480093f4SDimitry Andric   auto LSByteShiftedLeft = MIRBuilder.buildShl(Ty, Src, ShiftAmt);
7661480093f4SDimitry Andric   auto MSByteShiftedRight = MIRBuilder.buildLShr(Ty, Src, ShiftAmt);
7662480093f4SDimitry Andric   auto Res = MIRBuilder.buildOr(Ty, MSByteShiftedRight, LSByteShiftedLeft);
7663480093f4SDimitry Andric 
7664480093f4SDimitry Andric   // Set i-th high/low byte in Res to i-th low/high byte from Src.
7665480093f4SDimitry Andric   for (unsigned i = 1; i < SizeInBytes / 2; ++i) {
7666480093f4SDimitry Andric     // AND with Mask leaves byte i unchanged and sets remaining bytes to 0.
7667480093f4SDimitry Andric     APInt APMask(SizeInBytes * 8, 0xFF << (i * 8));
7668480093f4SDimitry Andric     auto Mask = MIRBuilder.buildConstant(Ty, APMask);
7669480093f4SDimitry Andric     auto ShiftAmt = MIRBuilder.buildConstant(Ty, BaseShiftAmt - 16 * i);
7670480093f4SDimitry Andric     // Low byte shifted left to place of high byte: (Src & Mask) << ShiftAmt.
7671480093f4SDimitry Andric     auto LoByte = MIRBuilder.buildAnd(Ty, Src, Mask);
7672480093f4SDimitry Andric     auto LoShiftedLeft = MIRBuilder.buildShl(Ty, LoByte, ShiftAmt);
7673480093f4SDimitry Andric     Res = MIRBuilder.buildOr(Ty, Res, LoShiftedLeft);
7674480093f4SDimitry Andric     // High byte shifted right to place of low byte: (Src >> ShiftAmt) & Mask.
7675480093f4SDimitry Andric     auto SrcShiftedRight = MIRBuilder.buildLShr(Ty, Src, ShiftAmt);
7676480093f4SDimitry Andric     auto HiShiftedRight = MIRBuilder.buildAnd(Ty, SrcShiftedRight, Mask);
7677480093f4SDimitry Andric     Res = MIRBuilder.buildOr(Ty, Res, HiShiftedRight);
7678480093f4SDimitry Andric   }
7679480093f4SDimitry Andric   Res.getInstr()->getOperand(0).setReg(Dst);
7680480093f4SDimitry Andric 
7681480093f4SDimitry Andric   MI.eraseFromParent();
7682480093f4SDimitry Andric   return Legalized;
7683480093f4SDimitry Andric }
7684480093f4SDimitry Andric 
7685480093f4SDimitry Andric //{ (Src & Mask) >> N } | { (Src << N) & Mask }
7686480093f4SDimitry Andric static MachineInstrBuilder SwapN(unsigned N, DstOp Dst, MachineIRBuilder &B,
7687480093f4SDimitry Andric                                  MachineInstrBuilder Src, APInt Mask) {
7688480093f4SDimitry Andric   const LLT Ty = Dst.getLLTTy(*B.getMRI());
7689480093f4SDimitry Andric   MachineInstrBuilder C_N = B.buildConstant(Ty, N);
7690480093f4SDimitry Andric   MachineInstrBuilder MaskLoNTo0 = B.buildConstant(Ty, Mask);
7691480093f4SDimitry Andric   auto LHS = B.buildLShr(Ty, B.buildAnd(Ty, Src, MaskLoNTo0), C_N);
7692480093f4SDimitry Andric   auto RHS = B.buildAnd(Ty, B.buildShl(Ty, Src, C_N), MaskLoNTo0);
7693480093f4SDimitry Andric   return B.buildOr(Dst, LHS, RHS);
7694480093f4SDimitry Andric }
7695480093f4SDimitry Andric 
7696480093f4SDimitry Andric LegalizerHelper::LegalizeResult
7697480093f4SDimitry Andric LegalizerHelper::lowerBitreverse(MachineInstr &MI) {
769806c3fb27SDimitry Andric   auto [Dst, Src] = MI.getFirst2Regs();
7699480093f4SDimitry Andric   const LLT Ty = MRI.getType(Src);
7700480093f4SDimitry Andric   unsigned Size = Ty.getSizeInBits();
7701480093f4SDimitry Andric 
7702480093f4SDimitry Andric   MachineInstrBuilder BSWAP =
7703480093f4SDimitry Andric       MIRBuilder.buildInstr(TargetOpcode::G_BSWAP, {Ty}, {Src});
7704480093f4SDimitry Andric 
7705480093f4SDimitry Andric   // swap high and low 4 bits in 8 bit blocks 7654|3210 -> 3210|7654
7706480093f4SDimitry Andric   //    [(val & 0xF0F0F0F0) >> 4] | [(val & 0x0F0F0F0F) << 4]
7707480093f4SDimitry Andric   // -> [(val & 0xF0F0F0F0) >> 4] | [(val << 4) & 0xF0F0F0F0]
7708480093f4SDimitry Andric   MachineInstrBuilder Swap4 =
7709480093f4SDimitry Andric       SwapN(4, Ty, MIRBuilder, BSWAP, APInt::getSplat(Size, APInt(8, 0xF0)));
7710480093f4SDimitry Andric 
7711480093f4SDimitry Andric   // swap high and low 2 bits in 4 bit blocks 32|10 76|54 -> 10|32 54|76
7712480093f4SDimitry Andric   //    [(val & 0xCCCCCCCC) >> 2] & [(val & 0x33333333) << 2]
7713480093f4SDimitry Andric   // -> [(val & 0xCCCCCCCC) >> 2] & [(val << 2) & 0xCCCCCCCC]
7714480093f4SDimitry Andric   MachineInstrBuilder Swap2 =
7715480093f4SDimitry Andric       SwapN(2, Ty, MIRBuilder, Swap4, APInt::getSplat(Size, APInt(8, 0xCC)));
7716480093f4SDimitry Andric 
7717480093f4SDimitry Andric   // swap high and low 1 bit in 2 bit blocks 1|0 3|2 5|4 7|6 -> 0|1 2|3 4|5 6|7
7718480093f4SDimitry Andric   //    [(val & 0xAAAAAAAA) >> 1] & [(val & 0x55555555) << 1]
7719480093f4SDimitry Andric   // -> [(val & 0xAAAAAAAA) >> 1] & [(val << 1) & 0xAAAAAAAA]
7720480093f4SDimitry Andric   SwapN(1, Dst, MIRBuilder, Swap2, APInt::getSplat(Size, APInt(8, 0xAA)));
7721480093f4SDimitry Andric 
7722480093f4SDimitry Andric   MI.eraseFromParent();
7723480093f4SDimitry Andric   return Legalized;
7724480093f4SDimitry Andric }
7725480093f4SDimitry Andric 
7726480093f4SDimitry Andric LegalizerHelper::LegalizeResult
77275ffd83dbSDimitry Andric LegalizerHelper::lowerReadWriteRegister(MachineInstr &MI) {
7728480093f4SDimitry Andric   MachineFunction &MF = MIRBuilder.getMF();
77295ffd83dbSDimitry Andric 
77305ffd83dbSDimitry Andric   bool IsRead = MI.getOpcode() == TargetOpcode::G_READ_REGISTER;
77315ffd83dbSDimitry Andric   int NameOpIdx = IsRead ? 1 : 0;
77325ffd83dbSDimitry Andric   int ValRegIndex = IsRead ? 0 : 1;
77335ffd83dbSDimitry Andric 
77345ffd83dbSDimitry Andric   Register ValReg = MI.getOperand(ValRegIndex).getReg();
77355ffd83dbSDimitry Andric   const LLT Ty = MRI.getType(ValReg);
77365ffd83dbSDimitry Andric   const MDString *RegStr = cast<MDString>(
77375ffd83dbSDimitry Andric     cast<MDNode>(MI.getOperand(NameOpIdx).getMetadata())->getOperand(0));
77385ffd83dbSDimitry Andric 
7739e8d8bef9SDimitry Andric   Register PhysReg = TLI.getRegisterByName(RegStr->getString().data(), Ty, MF);
77405ffd83dbSDimitry Andric   if (!PhysReg.isValid())
7741480093f4SDimitry Andric     return UnableToLegalize;
7742480093f4SDimitry Andric 
77435ffd83dbSDimitry Andric   if (IsRead)
77445ffd83dbSDimitry Andric     MIRBuilder.buildCopy(ValReg, PhysReg);
77455ffd83dbSDimitry Andric   else
77465ffd83dbSDimitry Andric     MIRBuilder.buildCopy(PhysReg, ValReg);
77475ffd83dbSDimitry Andric 
7748480093f4SDimitry Andric   MI.eraseFromParent();
7749480093f4SDimitry Andric   return Legalized;
7750480093f4SDimitry Andric }
7751e8d8bef9SDimitry Andric 
7752e8d8bef9SDimitry Andric LegalizerHelper::LegalizeResult
7753e8d8bef9SDimitry Andric LegalizerHelper::lowerSMULH_UMULH(MachineInstr &MI) {
7754e8d8bef9SDimitry Andric   bool IsSigned = MI.getOpcode() == TargetOpcode::G_SMULH;
7755e8d8bef9SDimitry Andric   unsigned ExtOp = IsSigned ? TargetOpcode::G_SEXT : TargetOpcode::G_ZEXT;
7756e8d8bef9SDimitry Andric   Register Result = MI.getOperand(0).getReg();
7757e8d8bef9SDimitry Andric   LLT OrigTy = MRI.getType(Result);
7758e8d8bef9SDimitry Andric   auto SizeInBits = OrigTy.getScalarSizeInBits();
7759e8d8bef9SDimitry Andric   LLT WideTy = OrigTy.changeElementSize(SizeInBits * 2);
7760e8d8bef9SDimitry Andric 
7761e8d8bef9SDimitry Andric   auto LHS = MIRBuilder.buildInstr(ExtOp, {WideTy}, {MI.getOperand(1)});
7762e8d8bef9SDimitry Andric   auto RHS = MIRBuilder.buildInstr(ExtOp, {WideTy}, {MI.getOperand(2)});
7763e8d8bef9SDimitry Andric   auto Mul = MIRBuilder.buildMul(WideTy, LHS, RHS);
7764e8d8bef9SDimitry Andric   unsigned ShiftOp = IsSigned ? TargetOpcode::G_ASHR : TargetOpcode::G_LSHR;
7765e8d8bef9SDimitry Andric 
7766e8d8bef9SDimitry Andric   auto ShiftAmt = MIRBuilder.buildConstant(WideTy, SizeInBits);
7767e8d8bef9SDimitry Andric   auto Shifted = MIRBuilder.buildInstr(ShiftOp, {WideTy}, {Mul, ShiftAmt});
7768e8d8bef9SDimitry Andric   MIRBuilder.buildTrunc(Result, Shifted);
7769e8d8bef9SDimitry Andric 
7770e8d8bef9SDimitry Andric   MI.eraseFromParent();
7771e8d8bef9SDimitry Andric   return Legalized;
7772e8d8bef9SDimitry Andric }
7773e8d8bef9SDimitry Andric 
7774bdd1243dSDimitry Andric LegalizerHelper::LegalizeResult
7775bdd1243dSDimitry Andric LegalizerHelper::lowerISFPCLASS(MachineInstr &MI) {
777606c3fb27SDimitry Andric   auto [DstReg, DstTy, SrcReg, SrcTy] = MI.getFirst2RegLLTs();
777706c3fb27SDimitry Andric   FPClassTest Mask = static_cast<FPClassTest>(MI.getOperand(2).getImm());
7778bdd1243dSDimitry Andric 
777906c3fb27SDimitry Andric   if (Mask == fcNone) {
7780bdd1243dSDimitry Andric     MIRBuilder.buildConstant(DstReg, 0);
7781bdd1243dSDimitry Andric     MI.eraseFromParent();
7782bdd1243dSDimitry Andric     return Legalized;
7783bdd1243dSDimitry Andric   }
778406c3fb27SDimitry Andric   if (Mask == fcAllFlags) {
7785bdd1243dSDimitry Andric     MIRBuilder.buildConstant(DstReg, 1);
7786bdd1243dSDimitry Andric     MI.eraseFromParent();
7787bdd1243dSDimitry Andric     return Legalized;
7788bdd1243dSDimitry Andric   }
7789bdd1243dSDimitry Andric 
779006c3fb27SDimitry Andric   // TODO: Try inverting the test with getInvertedFPClassTest like the DAG
779106c3fb27SDimitry Andric   // version
779206c3fb27SDimitry Andric 
7793bdd1243dSDimitry Andric   unsigned BitSize = SrcTy.getScalarSizeInBits();
7794bdd1243dSDimitry Andric   const fltSemantics &Semantics = getFltSemanticForLLT(SrcTy.getScalarType());
7795bdd1243dSDimitry Andric 
7796bdd1243dSDimitry Andric   LLT IntTy = LLT::scalar(BitSize);
7797bdd1243dSDimitry Andric   if (SrcTy.isVector())
7798bdd1243dSDimitry Andric     IntTy = LLT::vector(SrcTy.getElementCount(), IntTy);
7799bdd1243dSDimitry Andric   auto AsInt = MIRBuilder.buildCopy(IntTy, SrcReg);
7800bdd1243dSDimitry Andric 
7801bdd1243dSDimitry Andric   // Various masks.
7802bdd1243dSDimitry Andric   APInt SignBit = APInt::getSignMask(BitSize);
7803bdd1243dSDimitry Andric   APInt ValueMask = APInt::getSignedMaxValue(BitSize);     // All bits but sign.
7804bdd1243dSDimitry Andric   APInt Inf = APFloat::getInf(Semantics).bitcastToAPInt(); // Exp and int bit.
7805bdd1243dSDimitry Andric   APInt ExpMask = Inf;
7806bdd1243dSDimitry Andric   APInt AllOneMantissa = APFloat::getLargest(Semantics).bitcastToAPInt() & ~Inf;
7807bdd1243dSDimitry Andric   APInt QNaNBitMask =
7808bdd1243dSDimitry Andric       APInt::getOneBitSet(BitSize, AllOneMantissa.getActiveBits() - 1);
780906c3fb27SDimitry Andric   APInt InvertionMask = APInt::getAllOnes(DstTy.getScalarSizeInBits());
7810bdd1243dSDimitry Andric 
7811bdd1243dSDimitry Andric   auto SignBitC = MIRBuilder.buildConstant(IntTy, SignBit);
7812bdd1243dSDimitry Andric   auto ValueMaskC = MIRBuilder.buildConstant(IntTy, ValueMask);
7813bdd1243dSDimitry Andric   auto InfC = MIRBuilder.buildConstant(IntTy, Inf);
7814bdd1243dSDimitry Andric   auto ExpMaskC = MIRBuilder.buildConstant(IntTy, ExpMask);
7815bdd1243dSDimitry Andric   auto ZeroC = MIRBuilder.buildConstant(IntTy, 0);
7816bdd1243dSDimitry Andric 
7817bdd1243dSDimitry Andric   auto Abs = MIRBuilder.buildAnd(IntTy, AsInt, ValueMaskC);
7818bdd1243dSDimitry Andric   auto Sign =
7819bdd1243dSDimitry Andric       MIRBuilder.buildICmp(CmpInst::Predicate::ICMP_NE, DstTy, AsInt, Abs);
7820bdd1243dSDimitry Andric 
7821bdd1243dSDimitry Andric   auto Res = MIRBuilder.buildConstant(DstTy, 0);
782206c3fb27SDimitry Andric   // Clang doesn't support capture of structured bindings:
782306c3fb27SDimitry Andric   LLT DstTyCopy = DstTy;
7824bdd1243dSDimitry Andric   const auto appendToRes = [&](MachineInstrBuilder ToAppend) {
782506c3fb27SDimitry Andric     Res = MIRBuilder.buildOr(DstTyCopy, Res, ToAppend);
7826bdd1243dSDimitry Andric   };
7827bdd1243dSDimitry Andric 
7828bdd1243dSDimitry Andric   // Tests that involve more than one class should be processed first.
7829bdd1243dSDimitry Andric   if ((Mask & fcFinite) == fcFinite) {
7830bdd1243dSDimitry Andric     // finite(V) ==> abs(V) u< exp_mask
7831bdd1243dSDimitry Andric     appendToRes(MIRBuilder.buildICmp(CmpInst::Predicate::ICMP_ULT, DstTy, Abs,
7832bdd1243dSDimitry Andric                                      ExpMaskC));
7833bdd1243dSDimitry Andric     Mask &= ~fcFinite;
7834bdd1243dSDimitry Andric   } else if ((Mask & fcFinite) == fcPosFinite) {
7835bdd1243dSDimitry Andric     // finite(V) && V > 0 ==> V u< exp_mask
7836bdd1243dSDimitry Andric     appendToRes(MIRBuilder.buildICmp(CmpInst::Predicate::ICMP_ULT, DstTy, AsInt,
7837bdd1243dSDimitry Andric                                      ExpMaskC));
7838bdd1243dSDimitry Andric     Mask &= ~fcPosFinite;
7839bdd1243dSDimitry Andric   } else if ((Mask & fcFinite) == fcNegFinite) {
7840bdd1243dSDimitry Andric     // finite(V) && V < 0 ==> abs(V) u< exp_mask && signbit == 1
7841bdd1243dSDimitry Andric     auto Cmp = MIRBuilder.buildICmp(CmpInst::Predicate::ICMP_ULT, DstTy, Abs,
7842bdd1243dSDimitry Andric                                     ExpMaskC);
7843bdd1243dSDimitry Andric     auto And = MIRBuilder.buildAnd(DstTy, Cmp, Sign);
7844bdd1243dSDimitry Andric     appendToRes(And);
7845bdd1243dSDimitry Andric     Mask &= ~fcNegFinite;
7846bdd1243dSDimitry Andric   }
7847bdd1243dSDimitry Andric 
784806c3fb27SDimitry Andric   if (FPClassTest PartialCheck = Mask & (fcZero | fcSubnormal)) {
784906c3fb27SDimitry Andric     // fcZero | fcSubnormal => test all exponent bits are 0
785006c3fb27SDimitry Andric     // TODO: Handle sign bit specific cases
785106c3fb27SDimitry Andric     // TODO: Handle inverted case
785206c3fb27SDimitry Andric     if (PartialCheck == (fcZero | fcSubnormal)) {
785306c3fb27SDimitry Andric       auto ExpBits = MIRBuilder.buildAnd(IntTy, AsInt, ExpMaskC);
785406c3fb27SDimitry Andric       appendToRes(MIRBuilder.buildICmp(CmpInst::Predicate::ICMP_EQ, DstTy,
785506c3fb27SDimitry Andric                                        ExpBits, ZeroC));
785606c3fb27SDimitry Andric       Mask &= ~PartialCheck;
785706c3fb27SDimitry Andric     }
785806c3fb27SDimitry Andric   }
785906c3fb27SDimitry Andric 
7860bdd1243dSDimitry Andric   // Check for individual classes.
786106c3fb27SDimitry Andric   if (FPClassTest PartialCheck = Mask & fcZero) {
7862bdd1243dSDimitry Andric     if (PartialCheck == fcPosZero)
7863bdd1243dSDimitry Andric       appendToRes(MIRBuilder.buildICmp(CmpInst::Predicate::ICMP_EQ, DstTy,
7864bdd1243dSDimitry Andric                                        AsInt, ZeroC));
7865bdd1243dSDimitry Andric     else if (PartialCheck == fcZero)
7866bdd1243dSDimitry Andric       appendToRes(
7867bdd1243dSDimitry Andric           MIRBuilder.buildICmp(CmpInst::Predicate::ICMP_EQ, DstTy, Abs, ZeroC));
7868bdd1243dSDimitry Andric     else // fcNegZero
7869bdd1243dSDimitry Andric       appendToRes(MIRBuilder.buildICmp(CmpInst::Predicate::ICMP_EQ, DstTy,
7870bdd1243dSDimitry Andric                                        AsInt, SignBitC));
7871bdd1243dSDimitry Andric   }
7872bdd1243dSDimitry Andric 
787306c3fb27SDimitry Andric   if (FPClassTest PartialCheck = Mask & fcSubnormal) {
787406c3fb27SDimitry Andric     // issubnormal(V) ==> unsigned(abs(V) - 1) u< (all mantissa bits set)
787506c3fb27SDimitry Andric     // issubnormal(V) && V>0 ==> unsigned(V - 1) u< (all mantissa bits set)
787606c3fb27SDimitry Andric     auto V = (PartialCheck == fcPosSubnormal) ? AsInt : Abs;
787706c3fb27SDimitry Andric     auto OneC = MIRBuilder.buildConstant(IntTy, 1);
787806c3fb27SDimitry Andric     auto VMinusOne = MIRBuilder.buildSub(IntTy, V, OneC);
787906c3fb27SDimitry Andric     auto SubnormalRes =
788006c3fb27SDimitry Andric         MIRBuilder.buildICmp(CmpInst::Predicate::ICMP_ULT, DstTy, VMinusOne,
788106c3fb27SDimitry Andric                              MIRBuilder.buildConstant(IntTy, AllOneMantissa));
788206c3fb27SDimitry Andric     if (PartialCheck == fcNegSubnormal)
788306c3fb27SDimitry Andric       SubnormalRes = MIRBuilder.buildAnd(DstTy, SubnormalRes, Sign);
788406c3fb27SDimitry Andric     appendToRes(SubnormalRes);
788506c3fb27SDimitry Andric   }
788606c3fb27SDimitry Andric 
788706c3fb27SDimitry Andric   if (FPClassTest PartialCheck = Mask & fcInf) {
7888bdd1243dSDimitry Andric     if (PartialCheck == fcPosInf)
7889bdd1243dSDimitry Andric       appendToRes(MIRBuilder.buildICmp(CmpInst::Predicate::ICMP_EQ, DstTy,
7890bdd1243dSDimitry Andric                                        AsInt, InfC));
7891bdd1243dSDimitry Andric     else if (PartialCheck == fcInf)
7892bdd1243dSDimitry Andric       appendToRes(
7893bdd1243dSDimitry Andric           MIRBuilder.buildICmp(CmpInst::Predicate::ICMP_EQ, DstTy, Abs, InfC));
7894bdd1243dSDimitry Andric     else { // fcNegInf
7895bdd1243dSDimitry Andric       APInt NegInf = APFloat::getInf(Semantics, true).bitcastToAPInt();
7896bdd1243dSDimitry Andric       auto NegInfC = MIRBuilder.buildConstant(IntTy, NegInf);
7897bdd1243dSDimitry Andric       appendToRes(MIRBuilder.buildICmp(CmpInst::Predicate::ICMP_EQ, DstTy,
7898bdd1243dSDimitry Andric                                        AsInt, NegInfC));
7899bdd1243dSDimitry Andric     }
7900bdd1243dSDimitry Andric   }
7901bdd1243dSDimitry Andric 
790206c3fb27SDimitry Andric   if (FPClassTest PartialCheck = Mask & fcNan) {
7903bdd1243dSDimitry Andric     auto InfWithQnanBitC = MIRBuilder.buildConstant(IntTy, Inf | QNaNBitMask);
7904bdd1243dSDimitry Andric     if (PartialCheck == fcNan) {
7905bdd1243dSDimitry Andric       // isnan(V) ==> abs(V) u> int(inf)
7906bdd1243dSDimitry Andric       appendToRes(
7907bdd1243dSDimitry Andric           MIRBuilder.buildICmp(CmpInst::Predicate::ICMP_UGT, DstTy, Abs, InfC));
7908bdd1243dSDimitry Andric     } else if (PartialCheck == fcQNan) {
7909bdd1243dSDimitry Andric       // isquiet(V) ==> abs(V) u>= (unsigned(Inf) | quiet_bit)
7910bdd1243dSDimitry Andric       appendToRes(MIRBuilder.buildICmp(CmpInst::Predicate::ICMP_UGE, DstTy, Abs,
7911bdd1243dSDimitry Andric                                        InfWithQnanBitC));
7912bdd1243dSDimitry Andric     } else { // fcSNan
7913bdd1243dSDimitry Andric       // issignaling(V) ==> abs(V) u> unsigned(Inf) &&
7914bdd1243dSDimitry Andric       //                    abs(V) u< (unsigned(Inf) | quiet_bit)
7915bdd1243dSDimitry Andric       auto IsNan =
7916bdd1243dSDimitry Andric           MIRBuilder.buildICmp(CmpInst::Predicate::ICMP_UGT, DstTy, Abs, InfC);
7917bdd1243dSDimitry Andric       auto IsNotQnan = MIRBuilder.buildICmp(CmpInst::Predicate::ICMP_ULT, DstTy,
7918bdd1243dSDimitry Andric                                             Abs, InfWithQnanBitC);
7919bdd1243dSDimitry Andric       appendToRes(MIRBuilder.buildAnd(DstTy, IsNan, IsNotQnan));
7920bdd1243dSDimitry Andric     }
7921bdd1243dSDimitry Andric   }
7922bdd1243dSDimitry Andric 
792306c3fb27SDimitry Andric   if (FPClassTest PartialCheck = Mask & fcNormal) {
7924bdd1243dSDimitry Andric     // isnormal(V) ==> (0 u< exp u< max_exp) ==> (unsigned(exp-1) u<
7925bdd1243dSDimitry Andric     // (max_exp-1))
7926bdd1243dSDimitry Andric     APInt ExpLSB = ExpMask & ~(ExpMask.shl(1));
7927bdd1243dSDimitry Andric     auto ExpMinusOne = MIRBuilder.buildSub(
7928bdd1243dSDimitry Andric         IntTy, Abs, MIRBuilder.buildConstant(IntTy, ExpLSB));
7929bdd1243dSDimitry Andric     APInt MaxExpMinusOne = ExpMask - ExpLSB;
7930bdd1243dSDimitry Andric     auto NormalRes =
7931bdd1243dSDimitry Andric         MIRBuilder.buildICmp(CmpInst::Predicate::ICMP_ULT, DstTy, ExpMinusOne,
7932bdd1243dSDimitry Andric                              MIRBuilder.buildConstant(IntTy, MaxExpMinusOne));
7933bdd1243dSDimitry Andric     if (PartialCheck == fcNegNormal)
7934bdd1243dSDimitry Andric       NormalRes = MIRBuilder.buildAnd(DstTy, NormalRes, Sign);
7935bdd1243dSDimitry Andric     else if (PartialCheck == fcPosNormal) {
7936bdd1243dSDimitry Andric       auto PosSign = MIRBuilder.buildXor(
7937bdd1243dSDimitry Andric           DstTy, Sign, MIRBuilder.buildConstant(DstTy, InvertionMask));
7938bdd1243dSDimitry Andric       NormalRes = MIRBuilder.buildAnd(DstTy, NormalRes, PosSign);
7939bdd1243dSDimitry Andric     }
7940bdd1243dSDimitry Andric     appendToRes(NormalRes);
7941bdd1243dSDimitry Andric   }
7942bdd1243dSDimitry Andric 
7943bdd1243dSDimitry Andric   MIRBuilder.buildCopy(DstReg, Res);
7944bdd1243dSDimitry Andric   MI.eraseFromParent();
7945bdd1243dSDimitry Andric   return Legalized;
7946bdd1243dSDimitry Andric }
7947bdd1243dSDimitry Andric 
7948e8d8bef9SDimitry Andric LegalizerHelper::LegalizeResult LegalizerHelper::lowerSelect(MachineInstr &MI) {
7949e8d8bef9SDimitry Andric   // Implement vector G_SELECT in terms of XOR, AND, OR.
795006c3fb27SDimitry Andric   auto [DstReg, DstTy, MaskReg, MaskTy, Op1Reg, Op1Ty, Op2Reg, Op2Ty] =
795106c3fb27SDimitry Andric       MI.getFirst4RegLLTs();
7952e8d8bef9SDimitry Andric   if (!DstTy.isVector())
7953e8d8bef9SDimitry Andric     return UnableToLegalize;
7954e8d8bef9SDimitry Andric 
7955bdd1243dSDimitry Andric   bool IsEltPtr = DstTy.getElementType().isPointer();
7956bdd1243dSDimitry Andric   if (IsEltPtr) {
7957bdd1243dSDimitry Andric     LLT ScalarPtrTy = LLT::scalar(DstTy.getScalarSizeInBits());
7958bdd1243dSDimitry Andric     LLT NewTy = DstTy.changeElementType(ScalarPtrTy);
7959bdd1243dSDimitry Andric     Op1Reg = MIRBuilder.buildPtrToInt(NewTy, Op1Reg).getReg(0);
7960bdd1243dSDimitry Andric     Op2Reg = MIRBuilder.buildPtrToInt(NewTy, Op2Reg).getReg(0);
7961bdd1243dSDimitry Andric     DstTy = NewTy;
7962bdd1243dSDimitry Andric   }
7963bdd1243dSDimitry Andric 
7964e8d8bef9SDimitry Andric   if (MaskTy.isScalar()) {
796581ad6265SDimitry Andric     // Turn the scalar condition into a vector condition mask.
796681ad6265SDimitry Andric 
7967e8d8bef9SDimitry Andric     Register MaskElt = MaskReg;
796881ad6265SDimitry Andric 
796981ad6265SDimitry Andric     // The condition was potentially zero extended before, but we want a sign
797081ad6265SDimitry Andric     // extended boolean.
7971bdd1243dSDimitry Andric     if (MaskTy != LLT::scalar(1))
797281ad6265SDimitry Andric       MaskElt = MIRBuilder.buildSExtInReg(MaskTy, MaskElt, 1).getReg(0);
7973e8d8bef9SDimitry Andric 
797481ad6265SDimitry Andric     // Continue the sign extension (or truncate) to match the data type.
797581ad6265SDimitry Andric     MaskElt = MIRBuilder.buildSExtOrTrunc(DstTy.getElementType(),
797681ad6265SDimitry Andric                                           MaskElt).getReg(0);
797781ad6265SDimitry Andric 
797881ad6265SDimitry Andric     // Generate a vector splat idiom.
797981ad6265SDimitry Andric     auto ShufSplat = MIRBuilder.buildShuffleSplat(DstTy, MaskElt);
798081ad6265SDimitry Andric     MaskReg = ShufSplat.getReg(0);
798181ad6265SDimitry Andric     MaskTy = DstTy;
798281ad6265SDimitry Andric   }
798381ad6265SDimitry Andric 
798481ad6265SDimitry Andric   if (MaskTy.getSizeInBits() != DstTy.getSizeInBits()) {
7985e8d8bef9SDimitry Andric     return UnableToLegalize;
7986e8d8bef9SDimitry Andric   }
7987e8d8bef9SDimitry Andric 
7988e8d8bef9SDimitry Andric   auto NotMask = MIRBuilder.buildNot(MaskTy, MaskReg);
7989e8d8bef9SDimitry Andric   auto NewOp1 = MIRBuilder.buildAnd(MaskTy, Op1Reg, MaskReg);
7990e8d8bef9SDimitry Andric   auto NewOp2 = MIRBuilder.buildAnd(MaskTy, Op2Reg, NotMask);
7991bdd1243dSDimitry Andric   if (IsEltPtr) {
7992bdd1243dSDimitry Andric     auto Or = MIRBuilder.buildOr(DstTy, NewOp1, NewOp2);
7993bdd1243dSDimitry Andric     MIRBuilder.buildIntToPtr(DstReg, Or);
7994bdd1243dSDimitry Andric   } else {
7995e8d8bef9SDimitry Andric     MIRBuilder.buildOr(DstReg, NewOp1, NewOp2);
7996bdd1243dSDimitry Andric   }
7997e8d8bef9SDimitry Andric   MI.eraseFromParent();
7998e8d8bef9SDimitry Andric   return Legalized;
7999e8d8bef9SDimitry Andric }
8000fe6060f1SDimitry Andric 
8001fe6060f1SDimitry Andric LegalizerHelper::LegalizeResult LegalizerHelper::lowerDIVREM(MachineInstr &MI) {
8002fe6060f1SDimitry Andric   // Split DIVREM into individual instructions.
8003fe6060f1SDimitry Andric   unsigned Opcode = MI.getOpcode();
8004fe6060f1SDimitry Andric 
8005fe6060f1SDimitry Andric   MIRBuilder.buildInstr(
8006fe6060f1SDimitry Andric       Opcode == TargetOpcode::G_SDIVREM ? TargetOpcode::G_SDIV
8007fe6060f1SDimitry Andric                                         : TargetOpcode::G_UDIV,
8008fe6060f1SDimitry Andric       {MI.getOperand(0).getReg()}, {MI.getOperand(2), MI.getOperand(3)});
8009fe6060f1SDimitry Andric   MIRBuilder.buildInstr(
8010fe6060f1SDimitry Andric       Opcode == TargetOpcode::G_SDIVREM ? TargetOpcode::G_SREM
8011fe6060f1SDimitry Andric                                         : TargetOpcode::G_UREM,
8012fe6060f1SDimitry Andric       {MI.getOperand(1).getReg()}, {MI.getOperand(2), MI.getOperand(3)});
8013fe6060f1SDimitry Andric   MI.eraseFromParent();
8014fe6060f1SDimitry Andric   return Legalized;
8015fe6060f1SDimitry Andric }
8016fe6060f1SDimitry Andric 
8017fe6060f1SDimitry Andric LegalizerHelper::LegalizeResult
8018fe6060f1SDimitry Andric LegalizerHelper::lowerAbsToAddXor(MachineInstr &MI) {
8019fe6060f1SDimitry Andric   // Expand %res = G_ABS %a into:
8020fe6060f1SDimitry Andric   // %v1 = G_ASHR %a, scalar_size-1
8021fe6060f1SDimitry Andric   // %v2 = G_ADD %a, %v1
8022fe6060f1SDimitry Andric   // %res = G_XOR %v2, %v1
8023fe6060f1SDimitry Andric   LLT DstTy = MRI.getType(MI.getOperand(0).getReg());
8024fe6060f1SDimitry Andric   Register OpReg = MI.getOperand(1).getReg();
8025fe6060f1SDimitry Andric   auto ShiftAmt =
8026fe6060f1SDimitry Andric       MIRBuilder.buildConstant(DstTy, DstTy.getScalarSizeInBits() - 1);
8027fe6060f1SDimitry Andric   auto Shift = MIRBuilder.buildAShr(DstTy, OpReg, ShiftAmt);
8028fe6060f1SDimitry Andric   auto Add = MIRBuilder.buildAdd(DstTy, OpReg, Shift);
8029fe6060f1SDimitry Andric   MIRBuilder.buildXor(MI.getOperand(0).getReg(), Add, Shift);
8030fe6060f1SDimitry Andric   MI.eraseFromParent();
8031fe6060f1SDimitry Andric   return Legalized;
8032fe6060f1SDimitry Andric }
8033fe6060f1SDimitry Andric 
8034fe6060f1SDimitry Andric LegalizerHelper::LegalizeResult
8035fe6060f1SDimitry Andric LegalizerHelper::lowerAbsToMaxNeg(MachineInstr &MI) {
8036fe6060f1SDimitry Andric   // Expand %res = G_ABS %a into:
8037fe6060f1SDimitry Andric   // %v1 = G_CONSTANT 0
8038fe6060f1SDimitry Andric   // %v2 = G_SUB %v1, %a
8039fe6060f1SDimitry Andric   // %res = G_SMAX %a, %v2
8040fe6060f1SDimitry Andric   Register SrcReg = MI.getOperand(1).getReg();
8041fe6060f1SDimitry Andric   LLT Ty = MRI.getType(SrcReg);
8042fe6060f1SDimitry Andric   auto Zero = MIRBuilder.buildConstant(Ty, 0).getReg(0);
8043fe6060f1SDimitry Andric   auto Sub = MIRBuilder.buildSub(Ty, Zero, SrcReg).getReg(0);
8044fe6060f1SDimitry Andric   MIRBuilder.buildSMax(MI.getOperand(0), SrcReg, Sub);
8045fe6060f1SDimitry Andric   MI.eraseFromParent();
8046fe6060f1SDimitry Andric   return Legalized;
8047fe6060f1SDimitry Andric }
8048349cc55cSDimitry Andric 
8049349cc55cSDimitry Andric LegalizerHelper::LegalizeResult
8050349cc55cSDimitry Andric LegalizerHelper::lowerVectorReduction(MachineInstr &MI) {
8051349cc55cSDimitry Andric   Register SrcReg = MI.getOperand(1).getReg();
8052349cc55cSDimitry Andric   LLT SrcTy = MRI.getType(SrcReg);
8053349cc55cSDimitry Andric   LLT DstTy = MRI.getType(SrcReg);
8054349cc55cSDimitry Andric 
8055349cc55cSDimitry Andric   // The source could be a scalar if the IR type was <1 x sN>.
8056349cc55cSDimitry Andric   if (SrcTy.isScalar()) {
8057349cc55cSDimitry Andric     if (DstTy.getSizeInBits() > SrcTy.getSizeInBits())
8058349cc55cSDimitry Andric       return UnableToLegalize; // FIXME: handle extension.
8059349cc55cSDimitry Andric     // This can be just a plain copy.
8060349cc55cSDimitry Andric     Observer.changingInstr(MI);
8061349cc55cSDimitry Andric     MI.setDesc(MIRBuilder.getTII().get(TargetOpcode::COPY));
8062349cc55cSDimitry Andric     Observer.changedInstr(MI);
8063349cc55cSDimitry Andric     return Legalized;
8064349cc55cSDimitry Andric   }
806506c3fb27SDimitry Andric   return UnableToLegalize;
8066349cc55cSDimitry Andric }
8067349cc55cSDimitry Andric 
80685f757f3fSDimitry Andric static Type *getTypeForLLT(LLT Ty, LLVMContext &C);
80695f757f3fSDimitry Andric 
80705f757f3fSDimitry Andric LegalizerHelper::LegalizeResult LegalizerHelper::lowerVAArg(MachineInstr &MI) {
80715f757f3fSDimitry Andric   MachineFunction &MF = *MI.getMF();
80725f757f3fSDimitry Andric   const DataLayout &DL = MIRBuilder.getDataLayout();
80735f757f3fSDimitry Andric   LLVMContext &Ctx = MF.getFunction().getContext();
80745f757f3fSDimitry Andric   Register ListPtr = MI.getOperand(1).getReg();
80755f757f3fSDimitry Andric   LLT PtrTy = MRI.getType(ListPtr);
80765f757f3fSDimitry Andric 
80775f757f3fSDimitry Andric   // LstPtr is a pointer to the head of the list. Get the address
80785f757f3fSDimitry Andric   // of the head of the list.
80795f757f3fSDimitry Andric   Align PtrAlignment = DL.getABITypeAlign(getTypeForLLT(PtrTy, Ctx));
80805f757f3fSDimitry Andric   MachineMemOperand *PtrLoadMMO = MF.getMachineMemOperand(
80815f757f3fSDimitry Andric       MachinePointerInfo(), MachineMemOperand::MOLoad, PtrTy, PtrAlignment);
80825f757f3fSDimitry Andric   auto VAList = MIRBuilder.buildLoad(PtrTy, ListPtr, *PtrLoadMMO).getReg(0);
80835f757f3fSDimitry Andric 
80845f757f3fSDimitry Andric   const Align A(MI.getOperand(2).getImm());
80855f757f3fSDimitry Andric   LLT PtrTyAsScalarTy = LLT::scalar(PtrTy.getSizeInBits());
80865f757f3fSDimitry Andric   if (A > TLI.getMinStackArgumentAlignment()) {
80875f757f3fSDimitry Andric     Register AlignAmt =
80885f757f3fSDimitry Andric         MIRBuilder.buildConstant(PtrTyAsScalarTy, A.value() - 1).getReg(0);
80895f757f3fSDimitry Andric     auto AddDst = MIRBuilder.buildPtrAdd(PtrTy, VAList, AlignAmt);
80905f757f3fSDimitry Andric     auto AndDst = MIRBuilder.buildMaskLowPtrBits(PtrTy, AddDst, Log2(A));
80915f757f3fSDimitry Andric     VAList = AndDst.getReg(0);
80925f757f3fSDimitry Andric   }
80935f757f3fSDimitry Andric 
80945f757f3fSDimitry Andric   // Increment the pointer, VAList, to the next vaarg
80955f757f3fSDimitry Andric   // The list should be bumped by the size of element in the current head of
80965f757f3fSDimitry Andric   // list.
80975f757f3fSDimitry Andric   Register Dst = MI.getOperand(0).getReg();
80985f757f3fSDimitry Andric   LLT LLTTy = MRI.getType(Dst);
80995f757f3fSDimitry Andric   Type *Ty = getTypeForLLT(LLTTy, Ctx);
81005f757f3fSDimitry Andric   auto IncAmt =
81015f757f3fSDimitry Andric       MIRBuilder.buildConstant(PtrTyAsScalarTy, DL.getTypeAllocSize(Ty));
81025f757f3fSDimitry Andric   auto Succ = MIRBuilder.buildPtrAdd(PtrTy, VAList, IncAmt);
81035f757f3fSDimitry Andric 
81045f757f3fSDimitry Andric   // Store the increment VAList to the legalized pointer
81055f757f3fSDimitry Andric   MachineMemOperand *StoreMMO = MF.getMachineMemOperand(
81065f757f3fSDimitry Andric       MachinePointerInfo(), MachineMemOperand::MOStore, PtrTy, PtrAlignment);
81075f757f3fSDimitry Andric   MIRBuilder.buildStore(Succ, ListPtr, *StoreMMO);
81085f757f3fSDimitry Andric   // Load the actual argument out of the pointer VAList
81095f757f3fSDimitry Andric   Align EltAlignment = DL.getABITypeAlign(Ty);
81105f757f3fSDimitry Andric   MachineMemOperand *EltLoadMMO = MF.getMachineMemOperand(
81115f757f3fSDimitry Andric       MachinePointerInfo(), MachineMemOperand::MOLoad, LLTTy, EltAlignment);
81125f757f3fSDimitry Andric   MIRBuilder.buildLoad(Dst, VAList, *EltLoadMMO);
81135f757f3fSDimitry Andric 
81145f757f3fSDimitry Andric   MI.eraseFromParent();
81155f757f3fSDimitry Andric   return Legalized;
81165f757f3fSDimitry Andric }
81175f757f3fSDimitry Andric 
8118349cc55cSDimitry Andric static bool shouldLowerMemFuncForSize(const MachineFunction &MF) {
8119349cc55cSDimitry Andric   // On Darwin, -Os means optimize for size without hurting performance, so
8120349cc55cSDimitry Andric   // only really optimize for size when -Oz (MinSize) is used.
8121349cc55cSDimitry Andric   if (MF.getTarget().getTargetTriple().isOSDarwin())
8122349cc55cSDimitry Andric     return MF.getFunction().hasMinSize();
8123349cc55cSDimitry Andric   return MF.getFunction().hasOptSize();
8124349cc55cSDimitry Andric }
8125349cc55cSDimitry Andric 
8126349cc55cSDimitry Andric // Returns a list of types to use for memory op lowering in MemOps. A partial
8127349cc55cSDimitry Andric // port of findOptimalMemOpLowering in TargetLowering.
8128349cc55cSDimitry Andric static bool findGISelOptimalMemOpLowering(std::vector<LLT> &MemOps,
8129349cc55cSDimitry Andric                                           unsigned Limit, const MemOp &Op,
8130349cc55cSDimitry Andric                                           unsigned DstAS, unsigned SrcAS,
8131349cc55cSDimitry Andric                                           const AttributeList &FuncAttributes,
8132349cc55cSDimitry Andric                                           const TargetLowering &TLI) {
8133349cc55cSDimitry Andric   if (Op.isMemcpyWithFixedDstAlign() && Op.getSrcAlign() < Op.getDstAlign())
8134349cc55cSDimitry Andric     return false;
8135349cc55cSDimitry Andric 
8136349cc55cSDimitry Andric   LLT Ty = TLI.getOptimalMemOpLLT(Op, FuncAttributes);
8137349cc55cSDimitry Andric 
8138349cc55cSDimitry Andric   if (Ty == LLT()) {
8139349cc55cSDimitry Andric     // Use the largest scalar type whose alignment constraints are satisfied.
8140349cc55cSDimitry Andric     // We only need to check DstAlign here as SrcAlign is always greater or
8141349cc55cSDimitry Andric     // equal to DstAlign (or zero).
8142349cc55cSDimitry Andric     Ty = LLT::scalar(64);
8143349cc55cSDimitry Andric     if (Op.isFixedDstAlign())
8144349cc55cSDimitry Andric       while (Op.getDstAlign() < Ty.getSizeInBytes() &&
8145349cc55cSDimitry Andric              !TLI.allowsMisalignedMemoryAccesses(Ty, DstAS, Op.getDstAlign()))
8146349cc55cSDimitry Andric         Ty = LLT::scalar(Ty.getSizeInBytes());
8147349cc55cSDimitry Andric     assert(Ty.getSizeInBits() > 0 && "Could not find valid type");
8148349cc55cSDimitry Andric     // FIXME: check for the largest legal type we can load/store to.
8149349cc55cSDimitry Andric   }
8150349cc55cSDimitry Andric 
8151349cc55cSDimitry Andric   unsigned NumMemOps = 0;
8152349cc55cSDimitry Andric   uint64_t Size = Op.size();
8153349cc55cSDimitry Andric   while (Size) {
8154349cc55cSDimitry Andric     unsigned TySize = Ty.getSizeInBytes();
8155349cc55cSDimitry Andric     while (TySize > Size) {
8156349cc55cSDimitry Andric       // For now, only use non-vector load / store's for the left-over pieces.
8157349cc55cSDimitry Andric       LLT NewTy = Ty;
8158349cc55cSDimitry Andric       // FIXME: check for mem op safety and legality of the types. Not all of
8159349cc55cSDimitry Andric       // SDAGisms map cleanly to GISel concepts.
8160349cc55cSDimitry Andric       if (NewTy.isVector())
8161349cc55cSDimitry Andric         NewTy = NewTy.getSizeInBits() > 64 ? LLT::scalar(64) : LLT::scalar(32);
816206c3fb27SDimitry Andric       NewTy = LLT::scalar(llvm::bit_floor(NewTy.getSizeInBits() - 1));
8163349cc55cSDimitry Andric       unsigned NewTySize = NewTy.getSizeInBytes();
8164349cc55cSDimitry Andric       assert(NewTySize > 0 && "Could not find appropriate type");
8165349cc55cSDimitry Andric 
8166349cc55cSDimitry Andric       // If the new LLT cannot cover all of the remaining bits, then consider
8167349cc55cSDimitry Andric       // issuing a (or a pair of) unaligned and overlapping load / store.
8168bdd1243dSDimitry Andric       unsigned Fast;
8169349cc55cSDimitry Andric       // Need to get a VT equivalent for allowMisalignedMemoryAccesses().
8170349cc55cSDimitry Andric       MVT VT = getMVTForLLT(Ty);
8171349cc55cSDimitry Andric       if (NumMemOps && Op.allowOverlap() && NewTySize < Size &&
8172349cc55cSDimitry Andric           TLI.allowsMisalignedMemoryAccesses(
8173349cc55cSDimitry Andric               VT, DstAS, Op.isFixedDstAlign() ? Op.getDstAlign() : Align(1),
8174349cc55cSDimitry Andric               MachineMemOperand::MONone, &Fast) &&
8175349cc55cSDimitry Andric           Fast)
8176349cc55cSDimitry Andric         TySize = Size;
8177349cc55cSDimitry Andric       else {
8178349cc55cSDimitry Andric         Ty = NewTy;
8179349cc55cSDimitry Andric         TySize = NewTySize;
8180349cc55cSDimitry Andric       }
8181349cc55cSDimitry Andric     }
8182349cc55cSDimitry Andric 
8183349cc55cSDimitry Andric     if (++NumMemOps > Limit)
8184349cc55cSDimitry Andric       return false;
8185349cc55cSDimitry Andric 
8186349cc55cSDimitry Andric     MemOps.push_back(Ty);
8187349cc55cSDimitry Andric     Size -= TySize;
8188349cc55cSDimitry Andric   }
8189349cc55cSDimitry Andric 
8190349cc55cSDimitry Andric   return true;
8191349cc55cSDimitry Andric }
8192349cc55cSDimitry Andric 
8193349cc55cSDimitry Andric static Type *getTypeForLLT(LLT Ty, LLVMContext &C) {
8194349cc55cSDimitry Andric   if (Ty.isVector())
8195349cc55cSDimitry Andric     return FixedVectorType::get(IntegerType::get(C, Ty.getScalarSizeInBits()),
8196349cc55cSDimitry Andric                                 Ty.getNumElements());
8197349cc55cSDimitry Andric   return IntegerType::get(C, Ty.getSizeInBits());
8198349cc55cSDimitry Andric }
8199349cc55cSDimitry Andric 
8200349cc55cSDimitry Andric // Get a vectorized representation of the memset value operand, GISel edition.
8201349cc55cSDimitry Andric static Register getMemsetValue(Register Val, LLT Ty, MachineIRBuilder &MIB) {
8202349cc55cSDimitry Andric   MachineRegisterInfo &MRI = *MIB.getMRI();
8203349cc55cSDimitry Andric   unsigned NumBits = Ty.getScalarSizeInBits();
8204349cc55cSDimitry Andric   auto ValVRegAndVal = getIConstantVRegValWithLookThrough(Val, MRI);
8205349cc55cSDimitry Andric   if (!Ty.isVector() && ValVRegAndVal) {
820681ad6265SDimitry Andric     APInt Scalar = ValVRegAndVal->Value.trunc(8);
8207349cc55cSDimitry Andric     APInt SplatVal = APInt::getSplat(NumBits, Scalar);
8208349cc55cSDimitry Andric     return MIB.buildConstant(Ty, SplatVal).getReg(0);
8209349cc55cSDimitry Andric   }
8210349cc55cSDimitry Andric 
8211349cc55cSDimitry Andric   // Extend the byte value to the larger type, and then multiply by a magic
8212349cc55cSDimitry Andric   // value 0x010101... in order to replicate it across every byte.
8213349cc55cSDimitry Andric   // Unless it's zero, in which case just emit a larger G_CONSTANT 0.
8214349cc55cSDimitry Andric   if (ValVRegAndVal && ValVRegAndVal->Value == 0) {
8215349cc55cSDimitry Andric     return MIB.buildConstant(Ty, 0).getReg(0);
8216349cc55cSDimitry Andric   }
8217349cc55cSDimitry Andric 
8218349cc55cSDimitry Andric   LLT ExtType = Ty.getScalarType();
8219349cc55cSDimitry Andric   auto ZExt = MIB.buildZExtOrTrunc(ExtType, Val);
8220349cc55cSDimitry Andric   if (NumBits > 8) {
8221349cc55cSDimitry Andric     APInt Magic = APInt::getSplat(NumBits, APInt(8, 0x01));
8222349cc55cSDimitry Andric     auto MagicMI = MIB.buildConstant(ExtType, Magic);
8223349cc55cSDimitry Andric     Val = MIB.buildMul(ExtType, ZExt, MagicMI).getReg(0);
8224349cc55cSDimitry Andric   }
8225349cc55cSDimitry Andric 
8226349cc55cSDimitry Andric   // For vector types create a G_BUILD_VECTOR.
8227349cc55cSDimitry Andric   if (Ty.isVector())
8228349cc55cSDimitry Andric     Val = MIB.buildSplatVector(Ty, Val).getReg(0);
8229349cc55cSDimitry Andric 
8230349cc55cSDimitry Andric   return Val;
8231349cc55cSDimitry Andric }
8232349cc55cSDimitry Andric 
8233349cc55cSDimitry Andric LegalizerHelper::LegalizeResult
8234349cc55cSDimitry Andric LegalizerHelper::lowerMemset(MachineInstr &MI, Register Dst, Register Val,
8235349cc55cSDimitry Andric                              uint64_t KnownLen, Align Alignment,
8236349cc55cSDimitry Andric                              bool IsVolatile) {
8237349cc55cSDimitry Andric   auto &MF = *MI.getParent()->getParent();
8238349cc55cSDimitry Andric   const auto &TLI = *MF.getSubtarget().getTargetLowering();
8239349cc55cSDimitry Andric   auto &DL = MF.getDataLayout();
8240349cc55cSDimitry Andric   LLVMContext &C = MF.getFunction().getContext();
8241349cc55cSDimitry Andric 
8242349cc55cSDimitry Andric   assert(KnownLen != 0 && "Have a zero length memset length!");
8243349cc55cSDimitry Andric 
8244349cc55cSDimitry Andric   bool DstAlignCanChange = false;
8245349cc55cSDimitry Andric   MachineFrameInfo &MFI = MF.getFrameInfo();
8246349cc55cSDimitry Andric   bool OptSize = shouldLowerMemFuncForSize(MF);
8247349cc55cSDimitry Andric 
8248349cc55cSDimitry Andric   MachineInstr *FIDef = getOpcodeDef(TargetOpcode::G_FRAME_INDEX, Dst, MRI);
8249349cc55cSDimitry Andric   if (FIDef && !MFI.isFixedObjectIndex(FIDef->getOperand(1).getIndex()))
8250349cc55cSDimitry Andric     DstAlignCanChange = true;
8251349cc55cSDimitry Andric 
8252349cc55cSDimitry Andric   unsigned Limit = TLI.getMaxStoresPerMemset(OptSize);
8253349cc55cSDimitry Andric   std::vector<LLT> MemOps;
8254349cc55cSDimitry Andric 
8255349cc55cSDimitry Andric   const auto &DstMMO = **MI.memoperands_begin();
8256349cc55cSDimitry Andric   MachinePointerInfo DstPtrInfo = DstMMO.getPointerInfo();
8257349cc55cSDimitry Andric 
8258349cc55cSDimitry Andric   auto ValVRegAndVal = getIConstantVRegValWithLookThrough(Val, MRI);
8259349cc55cSDimitry Andric   bool IsZeroVal = ValVRegAndVal && ValVRegAndVal->Value == 0;
8260349cc55cSDimitry Andric 
8261349cc55cSDimitry Andric   if (!findGISelOptimalMemOpLowering(MemOps, Limit,
8262349cc55cSDimitry Andric                                      MemOp::Set(KnownLen, DstAlignCanChange,
8263349cc55cSDimitry Andric                                                 Alignment,
8264349cc55cSDimitry Andric                                                 /*IsZeroMemset=*/IsZeroVal,
8265349cc55cSDimitry Andric                                                 /*IsVolatile=*/IsVolatile),
8266349cc55cSDimitry Andric                                      DstPtrInfo.getAddrSpace(), ~0u,
8267349cc55cSDimitry Andric                                      MF.getFunction().getAttributes(), TLI))
8268349cc55cSDimitry Andric     return UnableToLegalize;
8269349cc55cSDimitry Andric 
8270349cc55cSDimitry Andric   if (DstAlignCanChange) {
8271349cc55cSDimitry Andric     // Get an estimate of the type from the LLT.
8272349cc55cSDimitry Andric     Type *IRTy = getTypeForLLT(MemOps[0], C);
8273349cc55cSDimitry Andric     Align NewAlign = DL.getABITypeAlign(IRTy);
8274349cc55cSDimitry Andric     if (NewAlign > Alignment) {
8275349cc55cSDimitry Andric       Alignment = NewAlign;
8276349cc55cSDimitry Andric       unsigned FI = FIDef->getOperand(1).getIndex();
8277349cc55cSDimitry Andric       // Give the stack frame object a larger alignment if needed.
8278349cc55cSDimitry Andric       if (MFI.getObjectAlign(FI) < Alignment)
8279349cc55cSDimitry Andric         MFI.setObjectAlignment(FI, Alignment);
8280349cc55cSDimitry Andric     }
8281349cc55cSDimitry Andric   }
8282349cc55cSDimitry Andric 
8283349cc55cSDimitry Andric   MachineIRBuilder MIB(MI);
8284349cc55cSDimitry Andric   // Find the largest store and generate the bit pattern for it.
8285349cc55cSDimitry Andric   LLT LargestTy = MemOps[0];
8286349cc55cSDimitry Andric   for (unsigned i = 1; i < MemOps.size(); i++)
8287349cc55cSDimitry Andric     if (MemOps[i].getSizeInBits() > LargestTy.getSizeInBits())
8288349cc55cSDimitry Andric       LargestTy = MemOps[i];
8289349cc55cSDimitry Andric 
8290349cc55cSDimitry Andric   // The memset stored value is always defined as an s8, so in order to make it
8291349cc55cSDimitry Andric   // work with larger store types we need to repeat the bit pattern across the
8292349cc55cSDimitry Andric   // wider type.
8293349cc55cSDimitry Andric   Register MemSetValue = getMemsetValue(Val, LargestTy, MIB);
8294349cc55cSDimitry Andric 
8295349cc55cSDimitry Andric   if (!MemSetValue)
8296349cc55cSDimitry Andric     return UnableToLegalize;
8297349cc55cSDimitry Andric 
8298349cc55cSDimitry Andric   // Generate the stores. For each store type in the list, we generate the
8299349cc55cSDimitry Andric   // matching store of that type to the destination address.
8300349cc55cSDimitry Andric   LLT PtrTy = MRI.getType(Dst);
8301349cc55cSDimitry Andric   unsigned DstOff = 0;
8302349cc55cSDimitry Andric   unsigned Size = KnownLen;
8303349cc55cSDimitry Andric   for (unsigned I = 0; I < MemOps.size(); I++) {
8304349cc55cSDimitry Andric     LLT Ty = MemOps[I];
8305349cc55cSDimitry Andric     unsigned TySize = Ty.getSizeInBytes();
8306349cc55cSDimitry Andric     if (TySize > Size) {
8307349cc55cSDimitry Andric       // Issuing an unaligned load / store pair that overlaps with the previous
8308349cc55cSDimitry Andric       // pair. Adjust the offset accordingly.
8309349cc55cSDimitry Andric       assert(I == MemOps.size() - 1 && I != 0);
8310349cc55cSDimitry Andric       DstOff -= TySize - Size;
8311349cc55cSDimitry Andric     }
8312349cc55cSDimitry Andric 
8313349cc55cSDimitry Andric     // If this store is smaller than the largest store see whether we can get
8314349cc55cSDimitry Andric     // the smaller value for free with a truncate.
8315349cc55cSDimitry Andric     Register Value = MemSetValue;
8316349cc55cSDimitry Andric     if (Ty.getSizeInBits() < LargestTy.getSizeInBits()) {
8317349cc55cSDimitry Andric       MVT VT = getMVTForLLT(Ty);
8318349cc55cSDimitry Andric       MVT LargestVT = getMVTForLLT(LargestTy);
8319349cc55cSDimitry Andric       if (!LargestTy.isVector() && !Ty.isVector() &&
8320349cc55cSDimitry Andric           TLI.isTruncateFree(LargestVT, VT))
8321349cc55cSDimitry Andric         Value = MIB.buildTrunc(Ty, MemSetValue).getReg(0);
8322349cc55cSDimitry Andric       else
8323349cc55cSDimitry Andric         Value = getMemsetValue(Val, Ty, MIB);
8324349cc55cSDimitry Andric       if (!Value)
8325349cc55cSDimitry Andric         return UnableToLegalize;
8326349cc55cSDimitry Andric     }
8327349cc55cSDimitry Andric 
8328349cc55cSDimitry Andric     auto *StoreMMO = MF.getMachineMemOperand(&DstMMO, DstOff, Ty);
8329349cc55cSDimitry Andric 
8330349cc55cSDimitry Andric     Register Ptr = Dst;
8331349cc55cSDimitry Andric     if (DstOff != 0) {
8332349cc55cSDimitry Andric       auto Offset =
8333349cc55cSDimitry Andric           MIB.buildConstant(LLT::scalar(PtrTy.getSizeInBits()), DstOff);
8334349cc55cSDimitry Andric       Ptr = MIB.buildPtrAdd(PtrTy, Dst, Offset).getReg(0);
8335349cc55cSDimitry Andric     }
8336349cc55cSDimitry Andric 
8337349cc55cSDimitry Andric     MIB.buildStore(Value, Ptr, *StoreMMO);
8338349cc55cSDimitry Andric     DstOff += Ty.getSizeInBytes();
8339349cc55cSDimitry Andric     Size -= TySize;
8340349cc55cSDimitry Andric   }
8341349cc55cSDimitry Andric 
8342349cc55cSDimitry Andric   MI.eraseFromParent();
8343349cc55cSDimitry Andric   return Legalized;
8344349cc55cSDimitry Andric }
8345349cc55cSDimitry Andric 
8346349cc55cSDimitry Andric LegalizerHelper::LegalizeResult
8347349cc55cSDimitry Andric LegalizerHelper::lowerMemcpyInline(MachineInstr &MI) {
8348349cc55cSDimitry Andric   assert(MI.getOpcode() == TargetOpcode::G_MEMCPY_INLINE);
8349349cc55cSDimitry Andric 
835006c3fb27SDimitry Andric   auto [Dst, Src, Len] = MI.getFirst3Regs();
8351349cc55cSDimitry Andric 
8352349cc55cSDimitry Andric   const auto *MMOIt = MI.memoperands_begin();
8353349cc55cSDimitry Andric   const MachineMemOperand *MemOp = *MMOIt;
8354349cc55cSDimitry Andric   bool IsVolatile = MemOp->isVolatile();
8355349cc55cSDimitry Andric 
8356349cc55cSDimitry Andric   // See if this is a constant length copy
8357349cc55cSDimitry Andric   auto LenVRegAndVal = getIConstantVRegValWithLookThrough(Len, MRI);
8358349cc55cSDimitry Andric   // FIXME: support dynamically sized G_MEMCPY_INLINE
835981ad6265SDimitry Andric   assert(LenVRegAndVal &&
8360349cc55cSDimitry Andric          "inline memcpy with dynamic size is not yet supported");
8361349cc55cSDimitry Andric   uint64_t KnownLen = LenVRegAndVal->Value.getZExtValue();
8362349cc55cSDimitry Andric   if (KnownLen == 0) {
8363349cc55cSDimitry Andric     MI.eraseFromParent();
8364349cc55cSDimitry Andric     return Legalized;
8365349cc55cSDimitry Andric   }
8366349cc55cSDimitry Andric 
8367349cc55cSDimitry Andric   const auto &DstMMO = **MI.memoperands_begin();
8368349cc55cSDimitry Andric   const auto &SrcMMO = **std::next(MI.memoperands_begin());
8369349cc55cSDimitry Andric   Align DstAlign = DstMMO.getBaseAlign();
8370349cc55cSDimitry Andric   Align SrcAlign = SrcMMO.getBaseAlign();
8371349cc55cSDimitry Andric 
8372349cc55cSDimitry Andric   return lowerMemcpyInline(MI, Dst, Src, KnownLen, DstAlign, SrcAlign,
8373349cc55cSDimitry Andric                            IsVolatile);
8374349cc55cSDimitry Andric }
8375349cc55cSDimitry Andric 
8376349cc55cSDimitry Andric LegalizerHelper::LegalizeResult
8377349cc55cSDimitry Andric LegalizerHelper::lowerMemcpyInline(MachineInstr &MI, Register Dst, Register Src,
8378349cc55cSDimitry Andric                                    uint64_t KnownLen, Align DstAlign,
8379349cc55cSDimitry Andric                                    Align SrcAlign, bool IsVolatile) {
8380349cc55cSDimitry Andric   assert(MI.getOpcode() == TargetOpcode::G_MEMCPY_INLINE);
8381349cc55cSDimitry Andric   return lowerMemcpy(MI, Dst, Src, KnownLen,
8382349cc55cSDimitry Andric                      std::numeric_limits<uint64_t>::max(), DstAlign, SrcAlign,
8383349cc55cSDimitry Andric                      IsVolatile);
8384349cc55cSDimitry Andric }
8385349cc55cSDimitry Andric 
8386349cc55cSDimitry Andric LegalizerHelper::LegalizeResult
8387349cc55cSDimitry Andric LegalizerHelper::lowerMemcpy(MachineInstr &MI, Register Dst, Register Src,
8388349cc55cSDimitry Andric                              uint64_t KnownLen, uint64_t Limit, Align DstAlign,
8389349cc55cSDimitry Andric                              Align SrcAlign, bool IsVolatile) {
8390349cc55cSDimitry Andric   auto &MF = *MI.getParent()->getParent();
8391349cc55cSDimitry Andric   const auto &TLI = *MF.getSubtarget().getTargetLowering();
8392349cc55cSDimitry Andric   auto &DL = MF.getDataLayout();
8393349cc55cSDimitry Andric   LLVMContext &C = MF.getFunction().getContext();
8394349cc55cSDimitry Andric 
8395349cc55cSDimitry Andric   assert(KnownLen != 0 && "Have a zero length memcpy length!");
8396349cc55cSDimitry Andric 
8397349cc55cSDimitry Andric   bool DstAlignCanChange = false;
8398349cc55cSDimitry Andric   MachineFrameInfo &MFI = MF.getFrameInfo();
839981ad6265SDimitry Andric   Align Alignment = std::min(DstAlign, SrcAlign);
8400349cc55cSDimitry Andric 
8401349cc55cSDimitry Andric   MachineInstr *FIDef = getOpcodeDef(TargetOpcode::G_FRAME_INDEX, Dst, MRI);
8402349cc55cSDimitry Andric   if (FIDef && !MFI.isFixedObjectIndex(FIDef->getOperand(1).getIndex()))
8403349cc55cSDimitry Andric     DstAlignCanChange = true;
8404349cc55cSDimitry Andric 
8405349cc55cSDimitry Andric   // FIXME: infer better src pointer alignment like SelectionDAG does here.
8406349cc55cSDimitry Andric   // FIXME: also use the equivalent of isMemSrcFromConstant and alwaysinlining
8407349cc55cSDimitry Andric   // if the memcpy is in a tail call position.
8408349cc55cSDimitry Andric 
8409349cc55cSDimitry Andric   std::vector<LLT> MemOps;
8410349cc55cSDimitry Andric 
8411349cc55cSDimitry Andric   const auto &DstMMO = **MI.memoperands_begin();
8412349cc55cSDimitry Andric   const auto &SrcMMO = **std::next(MI.memoperands_begin());
8413349cc55cSDimitry Andric   MachinePointerInfo DstPtrInfo = DstMMO.getPointerInfo();
8414349cc55cSDimitry Andric   MachinePointerInfo SrcPtrInfo = SrcMMO.getPointerInfo();
8415349cc55cSDimitry Andric 
8416349cc55cSDimitry Andric   if (!findGISelOptimalMemOpLowering(
8417349cc55cSDimitry Andric           MemOps, Limit,
8418349cc55cSDimitry Andric           MemOp::Copy(KnownLen, DstAlignCanChange, Alignment, SrcAlign,
8419349cc55cSDimitry Andric                       IsVolatile),
8420349cc55cSDimitry Andric           DstPtrInfo.getAddrSpace(), SrcPtrInfo.getAddrSpace(),
8421349cc55cSDimitry Andric           MF.getFunction().getAttributes(), TLI))
8422349cc55cSDimitry Andric     return UnableToLegalize;
8423349cc55cSDimitry Andric 
8424349cc55cSDimitry Andric   if (DstAlignCanChange) {
8425349cc55cSDimitry Andric     // Get an estimate of the type from the LLT.
8426349cc55cSDimitry Andric     Type *IRTy = getTypeForLLT(MemOps[0], C);
8427349cc55cSDimitry Andric     Align NewAlign = DL.getABITypeAlign(IRTy);
8428349cc55cSDimitry Andric 
8429349cc55cSDimitry Andric     // Don't promote to an alignment that would require dynamic stack
8430349cc55cSDimitry Andric     // realignment.
8431349cc55cSDimitry Andric     const TargetRegisterInfo *TRI = MF.getSubtarget().getRegisterInfo();
8432349cc55cSDimitry Andric     if (!TRI->hasStackRealignment(MF))
8433349cc55cSDimitry Andric       while (NewAlign > Alignment && DL.exceedsNaturalStackAlignment(NewAlign))
843481ad6265SDimitry Andric         NewAlign = NewAlign.previous();
8435349cc55cSDimitry Andric 
8436349cc55cSDimitry Andric     if (NewAlign > Alignment) {
8437349cc55cSDimitry Andric       Alignment = NewAlign;
8438349cc55cSDimitry Andric       unsigned FI = FIDef->getOperand(1).getIndex();
8439349cc55cSDimitry Andric       // Give the stack frame object a larger alignment if needed.
8440349cc55cSDimitry Andric       if (MFI.getObjectAlign(FI) < Alignment)
8441349cc55cSDimitry Andric         MFI.setObjectAlignment(FI, Alignment);
8442349cc55cSDimitry Andric     }
8443349cc55cSDimitry Andric   }
8444349cc55cSDimitry Andric 
8445349cc55cSDimitry Andric   LLVM_DEBUG(dbgs() << "Inlining memcpy: " << MI << " into loads & stores\n");
8446349cc55cSDimitry Andric 
8447349cc55cSDimitry Andric   MachineIRBuilder MIB(MI);
8448349cc55cSDimitry Andric   // Now we need to emit a pair of load and stores for each of the types we've
8449349cc55cSDimitry Andric   // collected. I.e. for each type, generate a load from the source pointer of
8450349cc55cSDimitry Andric   // that type width, and then generate a corresponding store to the dest buffer
8451349cc55cSDimitry Andric   // of that value loaded. This can result in a sequence of loads and stores
8452349cc55cSDimitry Andric   // mixed types, depending on what the target specifies as good types to use.
8453349cc55cSDimitry Andric   unsigned CurrOffset = 0;
8454349cc55cSDimitry Andric   unsigned Size = KnownLen;
8455349cc55cSDimitry Andric   for (auto CopyTy : MemOps) {
8456349cc55cSDimitry Andric     // Issuing an unaligned load / store pair  that overlaps with the previous
8457349cc55cSDimitry Andric     // pair. Adjust the offset accordingly.
8458349cc55cSDimitry Andric     if (CopyTy.getSizeInBytes() > Size)
8459349cc55cSDimitry Andric       CurrOffset -= CopyTy.getSizeInBytes() - Size;
8460349cc55cSDimitry Andric 
8461349cc55cSDimitry Andric     // Construct MMOs for the accesses.
8462349cc55cSDimitry Andric     auto *LoadMMO =
8463349cc55cSDimitry Andric         MF.getMachineMemOperand(&SrcMMO, CurrOffset, CopyTy.getSizeInBytes());
8464349cc55cSDimitry Andric     auto *StoreMMO =
8465349cc55cSDimitry Andric         MF.getMachineMemOperand(&DstMMO, CurrOffset, CopyTy.getSizeInBytes());
8466349cc55cSDimitry Andric 
8467349cc55cSDimitry Andric     // Create the load.
8468349cc55cSDimitry Andric     Register LoadPtr = Src;
8469349cc55cSDimitry Andric     Register Offset;
8470349cc55cSDimitry Andric     if (CurrOffset != 0) {
84714824e7fdSDimitry Andric       LLT SrcTy = MRI.getType(Src);
84724824e7fdSDimitry Andric       Offset = MIB.buildConstant(LLT::scalar(SrcTy.getSizeInBits()), CurrOffset)
8473349cc55cSDimitry Andric                    .getReg(0);
84744824e7fdSDimitry Andric       LoadPtr = MIB.buildPtrAdd(SrcTy, Src, Offset).getReg(0);
8475349cc55cSDimitry Andric     }
8476349cc55cSDimitry Andric     auto LdVal = MIB.buildLoad(CopyTy, LoadPtr, *LoadMMO);
8477349cc55cSDimitry Andric 
8478349cc55cSDimitry Andric     // Create the store.
84794824e7fdSDimitry Andric     Register StorePtr = Dst;
84804824e7fdSDimitry Andric     if (CurrOffset != 0) {
84814824e7fdSDimitry Andric       LLT DstTy = MRI.getType(Dst);
84824824e7fdSDimitry Andric       StorePtr = MIB.buildPtrAdd(DstTy, Dst, Offset).getReg(0);
84834824e7fdSDimitry Andric     }
8484349cc55cSDimitry Andric     MIB.buildStore(LdVal, StorePtr, *StoreMMO);
8485349cc55cSDimitry Andric     CurrOffset += CopyTy.getSizeInBytes();
8486349cc55cSDimitry Andric     Size -= CopyTy.getSizeInBytes();
8487349cc55cSDimitry Andric   }
8488349cc55cSDimitry Andric 
8489349cc55cSDimitry Andric   MI.eraseFromParent();
8490349cc55cSDimitry Andric   return Legalized;
8491349cc55cSDimitry Andric }
8492349cc55cSDimitry Andric 
8493349cc55cSDimitry Andric LegalizerHelper::LegalizeResult
8494349cc55cSDimitry Andric LegalizerHelper::lowerMemmove(MachineInstr &MI, Register Dst, Register Src,
8495349cc55cSDimitry Andric                               uint64_t KnownLen, Align DstAlign, Align SrcAlign,
8496349cc55cSDimitry Andric                               bool IsVolatile) {
8497349cc55cSDimitry Andric   auto &MF = *MI.getParent()->getParent();
8498349cc55cSDimitry Andric   const auto &TLI = *MF.getSubtarget().getTargetLowering();
8499349cc55cSDimitry Andric   auto &DL = MF.getDataLayout();
8500349cc55cSDimitry Andric   LLVMContext &C = MF.getFunction().getContext();
8501349cc55cSDimitry Andric 
8502349cc55cSDimitry Andric   assert(KnownLen != 0 && "Have a zero length memmove length!");
8503349cc55cSDimitry Andric 
8504349cc55cSDimitry Andric   bool DstAlignCanChange = false;
8505349cc55cSDimitry Andric   MachineFrameInfo &MFI = MF.getFrameInfo();
8506349cc55cSDimitry Andric   bool OptSize = shouldLowerMemFuncForSize(MF);
850781ad6265SDimitry Andric   Align Alignment = std::min(DstAlign, SrcAlign);
8508349cc55cSDimitry Andric 
8509349cc55cSDimitry Andric   MachineInstr *FIDef = getOpcodeDef(TargetOpcode::G_FRAME_INDEX, Dst, MRI);
8510349cc55cSDimitry Andric   if (FIDef && !MFI.isFixedObjectIndex(FIDef->getOperand(1).getIndex()))
8511349cc55cSDimitry Andric     DstAlignCanChange = true;
8512349cc55cSDimitry Andric 
8513349cc55cSDimitry Andric   unsigned Limit = TLI.getMaxStoresPerMemmove(OptSize);
8514349cc55cSDimitry Andric   std::vector<LLT> MemOps;
8515349cc55cSDimitry Andric 
8516349cc55cSDimitry Andric   const auto &DstMMO = **MI.memoperands_begin();
8517349cc55cSDimitry Andric   const auto &SrcMMO = **std::next(MI.memoperands_begin());
8518349cc55cSDimitry Andric   MachinePointerInfo DstPtrInfo = DstMMO.getPointerInfo();
8519349cc55cSDimitry Andric   MachinePointerInfo SrcPtrInfo = SrcMMO.getPointerInfo();
8520349cc55cSDimitry Andric 
8521349cc55cSDimitry Andric   // FIXME: SelectionDAG always passes false for 'AllowOverlap', apparently due
8522349cc55cSDimitry Andric   // to a bug in it's findOptimalMemOpLowering implementation. For now do the
8523349cc55cSDimitry Andric   // same thing here.
8524349cc55cSDimitry Andric   if (!findGISelOptimalMemOpLowering(
8525349cc55cSDimitry Andric           MemOps, Limit,
8526349cc55cSDimitry Andric           MemOp::Copy(KnownLen, DstAlignCanChange, Alignment, SrcAlign,
8527349cc55cSDimitry Andric                       /*IsVolatile*/ true),
8528349cc55cSDimitry Andric           DstPtrInfo.getAddrSpace(), SrcPtrInfo.getAddrSpace(),
8529349cc55cSDimitry Andric           MF.getFunction().getAttributes(), TLI))
8530349cc55cSDimitry Andric     return UnableToLegalize;
8531349cc55cSDimitry Andric 
8532349cc55cSDimitry Andric   if (DstAlignCanChange) {
8533349cc55cSDimitry Andric     // Get an estimate of the type from the LLT.
8534349cc55cSDimitry Andric     Type *IRTy = getTypeForLLT(MemOps[0], C);
8535349cc55cSDimitry Andric     Align NewAlign = DL.getABITypeAlign(IRTy);
8536349cc55cSDimitry Andric 
8537349cc55cSDimitry Andric     // Don't promote to an alignment that would require dynamic stack
8538349cc55cSDimitry Andric     // realignment.
8539349cc55cSDimitry Andric     const TargetRegisterInfo *TRI = MF.getSubtarget().getRegisterInfo();
8540349cc55cSDimitry Andric     if (!TRI->hasStackRealignment(MF))
8541349cc55cSDimitry Andric       while (NewAlign > Alignment && DL.exceedsNaturalStackAlignment(NewAlign))
854281ad6265SDimitry Andric         NewAlign = NewAlign.previous();
8543349cc55cSDimitry Andric 
8544349cc55cSDimitry Andric     if (NewAlign > Alignment) {
8545349cc55cSDimitry Andric       Alignment = NewAlign;
8546349cc55cSDimitry Andric       unsigned FI = FIDef->getOperand(1).getIndex();
8547349cc55cSDimitry Andric       // Give the stack frame object a larger alignment if needed.
8548349cc55cSDimitry Andric       if (MFI.getObjectAlign(FI) < Alignment)
8549349cc55cSDimitry Andric         MFI.setObjectAlignment(FI, Alignment);
8550349cc55cSDimitry Andric     }
8551349cc55cSDimitry Andric   }
8552349cc55cSDimitry Andric 
8553349cc55cSDimitry Andric   LLVM_DEBUG(dbgs() << "Inlining memmove: " << MI << " into loads & stores\n");
8554349cc55cSDimitry Andric 
8555349cc55cSDimitry Andric   MachineIRBuilder MIB(MI);
8556349cc55cSDimitry Andric   // Memmove requires that we perform the loads first before issuing the stores.
8557349cc55cSDimitry Andric   // Apart from that, this loop is pretty much doing the same thing as the
8558349cc55cSDimitry Andric   // memcpy codegen function.
8559349cc55cSDimitry Andric   unsigned CurrOffset = 0;
8560349cc55cSDimitry Andric   SmallVector<Register, 16> LoadVals;
8561349cc55cSDimitry Andric   for (auto CopyTy : MemOps) {
8562349cc55cSDimitry Andric     // Construct MMO for the load.
8563349cc55cSDimitry Andric     auto *LoadMMO =
8564349cc55cSDimitry Andric         MF.getMachineMemOperand(&SrcMMO, CurrOffset, CopyTy.getSizeInBytes());
8565349cc55cSDimitry Andric 
8566349cc55cSDimitry Andric     // Create the load.
8567349cc55cSDimitry Andric     Register LoadPtr = Src;
8568349cc55cSDimitry Andric     if (CurrOffset != 0) {
85694824e7fdSDimitry Andric       LLT SrcTy = MRI.getType(Src);
8570349cc55cSDimitry Andric       auto Offset =
85714824e7fdSDimitry Andric           MIB.buildConstant(LLT::scalar(SrcTy.getSizeInBits()), CurrOffset);
85724824e7fdSDimitry Andric       LoadPtr = MIB.buildPtrAdd(SrcTy, Src, Offset).getReg(0);
8573349cc55cSDimitry Andric     }
8574349cc55cSDimitry Andric     LoadVals.push_back(MIB.buildLoad(CopyTy, LoadPtr, *LoadMMO).getReg(0));
8575349cc55cSDimitry Andric     CurrOffset += CopyTy.getSizeInBytes();
8576349cc55cSDimitry Andric   }
8577349cc55cSDimitry Andric 
8578349cc55cSDimitry Andric   CurrOffset = 0;
8579349cc55cSDimitry Andric   for (unsigned I = 0; I < MemOps.size(); ++I) {
8580349cc55cSDimitry Andric     LLT CopyTy = MemOps[I];
8581349cc55cSDimitry Andric     // Now store the values loaded.
8582349cc55cSDimitry Andric     auto *StoreMMO =
8583349cc55cSDimitry Andric         MF.getMachineMemOperand(&DstMMO, CurrOffset, CopyTy.getSizeInBytes());
8584349cc55cSDimitry Andric 
8585349cc55cSDimitry Andric     Register StorePtr = Dst;
8586349cc55cSDimitry Andric     if (CurrOffset != 0) {
85874824e7fdSDimitry Andric       LLT DstTy = MRI.getType(Dst);
8588349cc55cSDimitry Andric       auto Offset =
85894824e7fdSDimitry Andric           MIB.buildConstant(LLT::scalar(DstTy.getSizeInBits()), CurrOffset);
85904824e7fdSDimitry Andric       StorePtr = MIB.buildPtrAdd(DstTy, Dst, Offset).getReg(0);
8591349cc55cSDimitry Andric     }
8592349cc55cSDimitry Andric     MIB.buildStore(LoadVals[I], StorePtr, *StoreMMO);
8593349cc55cSDimitry Andric     CurrOffset += CopyTy.getSizeInBytes();
8594349cc55cSDimitry Andric   }
8595349cc55cSDimitry Andric   MI.eraseFromParent();
8596349cc55cSDimitry Andric   return Legalized;
8597349cc55cSDimitry Andric }
8598349cc55cSDimitry Andric 
8599349cc55cSDimitry Andric LegalizerHelper::LegalizeResult
8600349cc55cSDimitry Andric LegalizerHelper::lowerMemCpyFamily(MachineInstr &MI, unsigned MaxLen) {
8601349cc55cSDimitry Andric   const unsigned Opc = MI.getOpcode();
8602349cc55cSDimitry Andric   // This combine is fairly complex so it's not written with a separate
8603349cc55cSDimitry Andric   // matcher function.
8604349cc55cSDimitry Andric   assert((Opc == TargetOpcode::G_MEMCPY || Opc == TargetOpcode::G_MEMMOVE ||
8605349cc55cSDimitry Andric           Opc == TargetOpcode::G_MEMSET) &&
8606349cc55cSDimitry Andric          "Expected memcpy like instruction");
8607349cc55cSDimitry Andric 
8608349cc55cSDimitry Andric   auto MMOIt = MI.memoperands_begin();
8609349cc55cSDimitry Andric   const MachineMemOperand *MemOp = *MMOIt;
8610349cc55cSDimitry Andric 
8611349cc55cSDimitry Andric   Align DstAlign = MemOp->getBaseAlign();
8612349cc55cSDimitry Andric   Align SrcAlign;
861306c3fb27SDimitry Andric   auto [Dst, Src, Len] = MI.getFirst3Regs();
8614349cc55cSDimitry Andric 
8615349cc55cSDimitry Andric   if (Opc != TargetOpcode::G_MEMSET) {
8616349cc55cSDimitry Andric     assert(MMOIt != MI.memoperands_end() && "Expected a second MMO on MI");
8617349cc55cSDimitry Andric     MemOp = *(++MMOIt);
8618349cc55cSDimitry Andric     SrcAlign = MemOp->getBaseAlign();
8619349cc55cSDimitry Andric   }
8620349cc55cSDimitry Andric 
8621349cc55cSDimitry Andric   // See if this is a constant length copy
8622349cc55cSDimitry Andric   auto LenVRegAndVal = getIConstantVRegValWithLookThrough(Len, MRI);
8623349cc55cSDimitry Andric   if (!LenVRegAndVal)
8624349cc55cSDimitry Andric     return UnableToLegalize;
8625349cc55cSDimitry Andric   uint64_t KnownLen = LenVRegAndVal->Value.getZExtValue();
8626349cc55cSDimitry Andric 
8627349cc55cSDimitry Andric   if (KnownLen == 0) {
8628349cc55cSDimitry Andric     MI.eraseFromParent();
8629349cc55cSDimitry Andric     return Legalized;
8630349cc55cSDimitry Andric   }
8631349cc55cSDimitry Andric 
8632349cc55cSDimitry Andric   bool IsVolatile = MemOp->isVolatile();
8633349cc55cSDimitry Andric   if (Opc == TargetOpcode::G_MEMCPY_INLINE)
8634349cc55cSDimitry Andric     return lowerMemcpyInline(MI, Dst, Src, KnownLen, DstAlign, SrcAlign,
8635349cc55cSDimitry Andric                              IsVolatile);
8636349cc55cSDimitry Andric 
8637349cc55cSDimitry Andric   // Don't try to optimize volatile.
8638349cc55cSDimitry Andric   if (IsVolatile)
8639349cc55cSDimitry Andric     return UnableToLegalize;
8640349cc55cSDimitry Andric 
8641349cc55cSDimitry Andric   if (MaxLen && KnownLen > MaxLen)
8642349cc55cSDimitry Andric     return UnableToLegalize;
8643349cc55cSDimitry Andric 
8644349cc55cSDimitry Andric   if (Opc == TargetOpcode::G_MEMCPY) {
8645349cc55cSDimitry Andric     auto &MF = *MI.getParent()->getParent();
8646349cc55cSDimitry Andric     const auto &TLI = *MF.getSubtarget().getTargetLowering();
8647349cc55cSDimitry Andric     bool OptSize = shouldLowerMemFuncForSize(MF);
8648349cc55cSDimitry Andric     uint64_t Limit = TLI.getMaxStoresPerMemcpy(OptSize);
8649349cc55cSDimitry Andric     return lowerMemcpy(MI, Dst, Src, KnownLen, Limit, DstAlign, SrcAlign,
8650349cc55cSDimitry Andric                        IsVolatile);
8651349cc55cSDimitry Andric   }
8652349cc55cSDimitry Andric   if (Opc == TargetOpcode::G_MEMMOVE)
8653349cc55cSDimitry Andric     return lowerMemmove(MI, Dst, Src, KnownLen, DstAlign, SrcAlign, IsVolatile);
8654349cc55cSDimitry Andric   if (Opc == TargetOpcode::G_MEMSET)
8655349cc55cSDimitry Andric     return lowerMemset(MI, Dst, Src, KnownLen, DstAlign, IsVolatile);
8656349cc55cSDimitry Andric   return UnableToLegalize;
8657349cc55cSDimitry Andric }
8658