diff options
| author | Dimitry Andric <dim@FreeBSD.org> | 2023-02-11 12:38:04 +0000 |
|---|---|---|
| committer | Dimitry Andric <dim@FreeBSD.org> | 2023-02-11 12:38:11 +0000 |
| commit | e3b557809604d036af6e00c60f012c2025b59a5e (patch) | |
| tree | 8a11ba2269a3b669601e2fd41145b174008f4da8 /llvm/lib/CodeGen/GlobalISel | |
| parent | 08e8dd7b9db7bb4a9de26d44c1cbfd24e869c014 (diff) | |
Diffstat (limited to 'llvm/lib/CodeGen/GlobalISel')
| -rw-r--r-- | llvm/lib/CodeGen/GlobalISel/CSEInfo.cpp | 4 | ||||
| -rw-r--r-- | llvm/lib/CodeGen/GlobalISel/CSEMIRBuilder.cpp | 12 | ||||
| -rw-r--r-- | llvm/lib/CodeGen/GlobalISel/CallLowering.cpp | 45 | ||||
| -rw-r--r-- | llvm/lib/CodeGen/GlobalISel/Combiner.cpp | 6 | ||||
| -rw-r--r-- | llvm/lib/CodeGen/GlobalISel/CombinerHelper.cpp | 843 | ||||
| -rw-r--r-- | llvm/lib/CodeGen/GlobalISel/GISelKnownBits.cpp | 25 | ||||
| -rw-r--r-- | llvm/lib/CodeGen/GlobalISel/IRTranslator.cpp | 78 | ||||
| -rw-r--r-- | llvm/lib/CodeGen/GlobalISel/InstructionSelect.cpp | 11 | ||||
| -rw-r--r-- | llvm/lib/CodeGen/GlobalISel/LegacyLegalizerInfo.cpp | 2 | ||||
| -rw-r--r-- | llvm/lib/CodeGen/GlobalISel/Legalizer.cpp | 2 | ||||
| -rw-r--r-- | llvm/lib/CodeGen/GlobalISel/LegalizerHelper.cpp | 386 | ||||
| -rw-r--r-- | llvm/lib/CodeGen/GlobalISel/LegalizerInfo.cpp | 10 | ||||
| -rw-r--r-- | llvm/lib/CodeGen/GlobalISel/LoadStoreOpt.cpp | 12 | ||||
| -rw-r--r-- | llvm/lib/CodeGen/GlobalISel/Localizer.cpp | 11 | ||||
| -rw-r--r-- | llvm/lib/CodeGen/GlobalISel/MachineIRBuilder.cpp | 100 | ||||
| -rw-r--r-- | llvm/lib/CodeGen/GlobalISel/RegBankSelect.cpp | 79 | ||||
| -rw-r--r-- | llvm/lib/CodeGen/GlobalISel/Utils.cpp | 263 |
17 files changed, 1423 insertions, 466 deletions
diff --git a/llvm/lib/CodeGen/GlobalISel/CSEInfo.cpp b/llvm/lib/CodeGen/GlobalISel/CSEInfo.cpp index 6a0d1c33d3e3..356d208fc881 100644 --- a/llvm/lib/CodeGen/GlobalISel/CSEInfo.cpp +++ b/llvm/lib/CodeGen/GlobalISel/CSEInfo.cpp @@ -61,6 +61,10 @@ bool CSEConfigFull::shouldCSEOpc(unsigned Opc) { case TargetOpcode::G_TRUNC: case TargetOpcode::G_PTR_ADD: case TargetOpcode::G_EXTRACT: + case TargetOpcode::G_SELECT: + case TargetOpcode::G_BUILD_VECTOR: + case TargetOpcode::G_BUILD_VECTOR_TRUNC: + case TargetOpcode::G_SEXT_INREG: return true; } return false; diff --git a/llvm/lib/CodeGen/GlobalISel/CSEMIRBuilder.cpp b/llvm/lib/CodeGen/GlobalISel/CSEMIRBuilder.cpp index a432e4ed7fb7..64e2d517e3b9 100644 --- a/llvm/lib/CodeGen/GlobalISel/CSEMIRBuilder.cpp +++ b/llvm/lib/CodeGen/GlobalISel/CSEMIRBuilder.cpp @@ -107,7 +107,7 @@ void CSEMIRBuilder::profileMBBOpcode(GISelInstProfileBuilder &B, void CSEMIRBuilder::profileEverything(unsigned Opc, ArrayRef<DstOp> DstOps, ArrayRef<SrcOp> SrcOps, - Optional<unsigned> Flags, + std::optional<unsigned> Flags, GISelInstProfileBuilder &B) const { profileMBBOpcode(B, Opc); @@ -170,7 +170,7 @@ CSEMIRBuilder::generateCopiesIfRequired(ArrayRef<DstOp> DstOps, MachineInstrBuilder CSEMIRBuilder::buildInstr(unsigned Opc, ArrayRef<DstOp> DstOps, ArrayRef<SrcOp> SrcOps, - Optional<unsigned> Flag) { + std::optional<unsigned> Flag) { switch (Opc) { default: break; @@ -210,8 +210,8 @@ MachineInstrBuilder CSEMIRBuilder::buildInstr(unsigned Opc, break; } - if (Optional<APInt> Cst = ConstantFoldBinOp(Opc, SrcOps[0].getReg(), - SrcOps[1].getReg(), *getMRI())) + if (std::optional<APInt> Cst = ConstantFoldBinOp( + Opc, SrcOps[0].getReg(), SrcOps[1].getReg(), *getMRI())) return buildConstant(DstOps[0], *Cst); break; } @@ -230,7 +230,7 @@ MachineInstrBuilder CSEMIRBuilder::buildInstr(unsigned Opc, // Try to constant fold these. assert(SrcOps.size() == 2 && "Invalid sources"); assert(DstOps.size() == 1 && "Invalid dsts"); - if (Optional<APFloat> Cst = ConstantFoldFPBinOp( + if (std::optional<APFloat> Cst = ConstantFoldFPBinOp( Opc, SrcOps[0].getReg(), SrcOps[1].getReg(), *getMRI())) return buildFConstant(DstOps[0], *Cst); break; @@ -251,7 +251,7 @@ MachineInstrBuilder CSEMIRBuilder::buildInstr(unsigned Opc, // Try to constant fold these. assert(SrcOps.size() == 1 && "Invalid sources"); assert(DstOps.size() == 1 && "Invalid dsts"); - if (Optional<APFloat> Cst = ConstantFoldIntToFloat( + if (std::optional<APFloat> Cst = ConstantFoldIntToFloat( Opc, DstOps[0].getLLTTy(*getMRI()), SrcOps[0].getReg(), *getMRI())) return buildFConstant(DstOps[0], *Cst); break; diff --git a/llvm/lib/CodeGen/GlobalISel/CallLowering.cpp b/llvm/lib/CodeGen/GlobalISel/CallLowering.cpp index 6c36c6445c65..89872259cfca 100644 --- a/llvm/lib/CodeGen/GlobalISel/CallLowering.cpp +++ b/llvm/lib/CodeGen/GlobalISel/CallLowering.cpp @@ -70,6 +70,15 @@ ISD::ArgFlagsTy CallLowering::getAttributesForArgIdx(const CallBase &Call, return Flags; } +ISD::ArgFlagsTy +CallLowering::getAttributesForReturn(const CallBase &Call) const { + ISD::ArgFlagsTy Flags; + addFlagsUsingAttrFn(Flags, [&Call](Attribute::AttrKind Attr) { + return Call.hasRetAttr(Attr); + }); + return Flags; +} + void CallLowering::addArgFlagsFromAttributes(ISD::ArgFlagsTy &Flags, const AttributeList &Attrs, unsigned OpIdx) const { @@ -141,7 +150,7 @@ bool CallLowering::lowerCall(MachineIRBuilder &MIRBuilder, const CallBase &CB, Register ReturnHintAlignReg; Align ReturnHintAlign; - Info.OrigRet = ArgInfo{ResRegs, RetTy, 0, ISD::ArgFlagsTy{}}; + Info.OrigRet = ArgInfo{ResRegs, RetTy, 0, getAttributesForReturn(CB)}; if (!Info.OrigRet.Ty->isVoidTy()) { setArgFlags(Info.OrigRet, AttributeList::ReturnIndex, DL, CB); @@ -155,6 +164,12 @@ bool CallLowering::lowerCall(MachineIRBuilder &MIRBuilder, const CallBase &CB, } } + auto Bundle = CB.getOperandBundle(LLVMContext::OB_kcfi); + if (Bundle && CB.isIndirectCall()) { + Info.CFIType = cast<ConstantInt>(Bundle->Inputs[0]); + assert(Info.CFIType->getType()->isIntegerTy(32) && "Invalid CFI type"); + } + Info.CB = &CB; Info.KnownCallees = CB.getMetadata(LLVMContext::MD_callees); Info.CallConv = CallConv; @@ -291,8 +306,8 @@ mergeVectorRegsToResultRegs(MachineIRBuilder &B, ArrayRef<Register> DstRegs, Register UnmergeSrcReg; if (LCMTy != PartLLT) { assert(DstRegs.size() == 1); - return B.buildDeleteTrailingVectorElements(DstRegs[0], - B.buildMerge(LCMTy, SrcRegs)); + return B.buildDeleteTrailingVectorElements( + DstRegs[0], B.buildMergeLikeInstr(LCMTy, SrcRegs)); } else { // We don't need to widen anything if we're extracting a scalar which was // promoted to a vector e.g. s8 -> v4s8 -> s8 @@ -371,11 +386,11 @@ static void buildCopyFromRegs(MachineIRBuilder &B, ArrayRef<Register> OrigRegs, assert(OrigRegs.size() == 1); LLT OrigTy = MRI.getType(OrigRegs[0]); - unsigned SrcSize = PartLLT.getSizeInBits().getFixedSize() * Regs.size(); + unsigned SrcSize = PartLLT.getSizeInBits().getFixedValue() * Regs.size(); if (SrcSize == OrigTy.getSizeInBits()) - B.buildMerge(OrigRegs[0], Regs); + B.buildMergeValues(OrigRegs[0], Regs); else { - auto Widened = B.buildMerge(LLT::scalar(SrcSize), Regs); + auto Widened = B.buildMergeLikeInstr(LLT::scalar(SrcSize), Regs); B.buildTrunc(OrigRegs[0], Widened); } @@ -443,7 +458,8 @@ static void buildCopyFromRegs(MachineIRBuilder &B, ArrayRef<Register> OrigRegs, assert(DstEltTy.getSizeInBits() % PartLLT.getSizeInBits() == 0); for (int I = 0, NumElts = LLTy.getNumElements(); I != NumElts; ++I) { - auto Merge = B.buildMerge(RealDstEltTy, Regs.take_front(PartsPerElt)); + auto Merge = + B.buildMergeLikeInstr(RealDstEltTy, Regs.take_front(PartsPerElt)); // Fix the type in case this is really a vector of pointers. MRI.setType(Merge.getReg(0), RealDstEltTy); EltMerges.push_back(Merge.getReg(0)); @@ -489,6 +505,15 @@ static void buildCopyToRegs(MachineIRBuilder &B, ArrayRef<Register> DstRegs, return; } + if (SrcTy.isVector() && PartTy.isVector() && + PartTy.getScalarSizeInBits() == SrcTy.getScalarSizeInBits() && + SrcTy.getNumElements() < PartTy.getNumElements()) { + // A coercion like: v2f32 -> v4f32. + Register DstReg = DstRegs.front(); + B.buildPadVectorWithUndefElements(DstReg, SrcReg); + return; + } + LLT GCDTy = getGCDType(SrcTy, PartTy); if (GCDTy == PartTy) { // If this already evenly divisible, we can create a simple unmerge. @@ -525,7 +550,7 @@ static void buildCopyToRegs(MachineIRBuilder &B, ArrayRef<Register> DstRegs, SmallVector<Register, 8> MergeParts(1, SrcReg); for (unsigned Size = SrcSize; Size != CoveringSize; Size += SrcSize) MergeParts.push_back(Undef); - UnmergeSrc = B.buildMerge(LCMTy, MergeParts).getReg(0); + UnmergeSrc = B.buildMergeLikeInstr(LCMTy, MergeParts).getReg(0); } } @@ -656,7 +681,7 @@ bool CallLowering::handleAssignments(ValueHandler &Handler, if (VA.needsCustom()) { std::function<void()> Thunk; unsigned NumArgRegs = Handler.assignCustomValue( - Args[i], makeArrayRef(ArgLocs).slice(j), &Thunk); + Args[i], ArrayRef(ArgLocs).slice(j), &Thunk); if (Thunk) DelayedOutgoingRegAssignments.emplace_back(Thunk); if (!NumArgRegs) @@ -1196,7 +1221,7 @@ static bool isCopyCompatibleType(LLT SrcTy, LLT DstTy) { DstTy = DstTy.getScalarType(); return (SrcTy.isPointer() && DstTy.isScalar()) || - (DstTy.isScalar() && SrcTy.isPointer()); + (DstTy.isPointer() && SrcTy.isScalar()); } void CallLowering::IncomingValueHandler::assignValueToReg(Register ValVReg, diff --git a/llvm/lib/CodeGen/GlobalISel/Combiner.cpp b/llvm/lib/CodeGen/GlobalISel/Combiner.cpp index 1a5fe3e84c17..748fa273d499 100644 --- a/llvm/lib/CodeGen/GlobalISel/Combiner.cpp +++ b/llvm/lib/CodeGen/GlobalISel/Combiner.cpp @@ -12,6 +12,7 @@ #include "llvm/CodeGen/GlobalISel/Combiner.h" #include "llvm/ADT/PostOrderIterator.h" +#include "llvm/ADT/SetVector.h" #include "llvm/CodeGen/GlobalISel/CSEInfo.h" #include "llvm/CodeGen/GlobalISel/CSEMIRBuilder.h" #include "llvm/CodeGen/GlobalISel/CombinerInfo.h" @@ -52,7 +53,9 @@ class WorkListMaintainer : public GISelChangeObserver { WorkListTy &WorkList; /// The instructions that have been created but we want to report once they /// have their operands. This is only maintained if debug output is requested. - SmallPtrSet<const MachineInstr *, 4> CreatedInstrs; +#ifndef NDEBUG + SetVector<const MachineInstr *> CreatedInstrs; +#endif public: WorkListMaintainer(WorkListTy &WorkList) : WorkList(WorkList) {} @@ -132,6 +135,7 @@ bool Combiner::combineMachineInstrs(MachineFunction &MF, // Erase dead insts before even adding to the list. if (isTriviallyDead(CurMI, *MRI)) { LLVM_DEBUG(dbgs() << CurMI << "Is dead; erasing.\n"); + llvm::salvageDebugInfo(*MRI, CurMI); CurMI.eraseFromParent(); continue; } diff --git a/llvm/lib/CodeGen/GlobalISel/CombinerHelper.cpp b/llvm/lib/CodeGen/GlobalISel/CombinerHelper.cpp index 05a25bc3078e..af4bb1634746 100644 --- a/llvm/lib/CodeGen/GlobalISel/CombinerHelper.cpp +++ b/llvm/lib/CodeGen/GlobalISel/CombinerHelper.cpp @@ -27,10 +27,13 @@ #include "llvm/CodeGen/TargetLowering.h" #include "llvm/CodeGen/TargetOpcodes.h" #include "llvm/IR/DataLayout.h" +#include "llvm/IR/InstrTypes.h" #include "llvm/Support/Casting.h" #include "llvm/Support/DivisionByConstantInfo.h" #include "llvm/Support/MathExtras.h" #include "llvm/Target/TargetMachine.h" +#include <cmath> +#include <optional> #include <tuple> #define DEBUG_TYPE "gi-combiner" @@ -46,11 +49,12 @@ static cl::opt<bool> "legal for the GlobalISel combiner")); CombinerHelper::CombinerHelper(GISelChangeObserver &Observer, - MachineIRBuilder &B, GISelKnownBits *KB, - MachineDominatorTree *MDT, + MachineIRBuilder &B, bool IsPreLegalize, + GISelKnownBits *KB, MachineDominatorTree *MDT, const LegalizerInfo *LI) : Builder(B), MRI(Builder.getMF().getRegInfo()), Observer(Observer), KB(KB), - MDT(MDT), LI(LI), RBI(Builder.getMF().getSubtarget().getRegBankInfo()), + MDT(MDT), IsPreLegalize(IsPreLegalize), LI(LI), + RBI(Builder.getMF().getSubtarget().getRegBankInfo()), TRI(Builder.getMF().getSubtarget().getRegisterInfo()) { (void)this->KB; } @@ -93,8 +97,8 @@ static unsigned bigEndianByteAt(const unsigned ByteWidth, const unsigned I) { /// \param MemOffset2Idx maps memory offsets to address offsets. /// \param LowestIdx is the lowest index in \p MemOffset2Idx. /// -/// \returns true if the map corresponds to a big endian byte pattern, false -/// if it corresponds to a little endian byte pattern, and None otherwise. +/// \returns true if the map corresponds to a big endian byte pattern, false if +/// it corresponds to a little endian byte pattern, and std::nullopt otherwise. /// /// E.g. given a 32-bit type x, and x[AddrOffset], the in-memory byte patterns /// are as follows: @@ -104,24 +108,24 @@ static unsigned bigEndianByteAt(const unsigned ByteWidth, const unsigned I) { /// 1 1 2 /// 2 2 1 /// 3 3 0 -static Optional<bool> +static std::optional<bool> isBigEndian(const SmallDenseMap<int64_t, int64_t, 8> &MemOffset2Idx, int64_t LowestIdx) { // Need at least two byte positions to decide on endianness. unsigned Width = MemOffset2Idx.size(); if (Width < 2) - return None; + return std::nullopt; bool BigEndian = true, LittleEndian = true; for (unsigned MemOffset = 0; MemOffset < Width; ++ MemOffset) { auto MemOffsetAndIdx = MemOffset2Idx.find(MemOffset); if (MemOffsetAndIdx == MemOffset2Idx.end()) - return None; + return std::nullopt; const int64_t Idx = MemOffsetAndIdx->second - LowestIdx; assert(Idx >= 0 && "Expected non-negative byte offset?"); LittleEndian &= Idx == littleEndianByteAt(Width, MemOffset); BigEndian &= Idx == bigEndianByteAt(Width, MemOffset); if (!BigEndian && !LittleEndian) - return None; + return std::nullopt; } assert((BigEndian != LittleEndian) && @@ -129,7 +133,7 @@ isBigEndian(const SmallDenseMap<int64_t, int64_t, 8> &MemOffset2Idx, return BigEndian; } -bool CombinerHelper::isPreLegalize() const { return !LI; } +bool CombinerHelper::isPreLegalize() const { return IsPreLegalize; } bool CombinerHelper::isLegal(const LegalityQuery &Query) const { assert(LI && "Must have LegalizerInfo to query isLegal!"); @@ -385,7 +389,7 @@ void CombinerHelper::applyCombineShuffleVector(MachineInstr &MI, if (Ops.size() == 1) Builder.buildCopy(NewDstReg, Ops[0]); else - Builder.buildMerge(NewDstReg, Ops); + Builder.buildMergeLikeInstr(NewDstReg, Ops); MI.eraseFromParent(); replaceRegWith(MRI, DstReg, NewDstReg); @@ -485,6 +489,24 @@ bool CombinerHelper::tryCombineExtendingLoads(MachineInstr &MI) { return false; } +static unsigned getExtLoadOpcForExtend(unsigned ExtOpc) { + unsigned CandidateLoadOpc; + switch (ExtOpc) { + case TargetOpcode::G_ANYEXT: + CandidateLoadOpc = TargetOpcode::G_LOAD; + break; + case TargetOpcode::G_SEXT: + CandidateLoadOpc = TargetOpcode::G_SEXTLOAD; + break; + case TargetOpcode::G_ZEXT: + CandidateLoadOpc = TargetOpcode::G_ZEXTLOAD; + break; + default: + llvm_unreachable("Unexpected extend opc"); + } + return CandidateLoadOpc; +} + bool CombinerHelper::matchCombineExtendingLoads(MachineInstr &MI, PreferredTuple &Preferred) { // We match the loads and follow the uses to the extend instead of matching @@ -535,11 +557,12 @@ bool CombinerHelper::matchCombineExtendingLoads(MachineInstr &MI, if (MMO.isAtomic() && UseMI.getOpcode() != TargetOpcode::G_ANYEXT) continue; // Check for legality. - if (LI) { + if (!isPreLegalize()) { LegalityQuery::MemDesc MMDesc(MMO); + unsigned CandidateLoadOpc = getExtLoadOpcForExtend(UseMI.getOpcode()); LLT UseTy = MRI.getType(UseMI.getOperand(0).getReg()); LLT SrcTy = MRI.getType(LoadMI->getPointerReg()); - if (LI->getAction({LoadMI->getOpcode(), {UseTy, SrcTy}, {MMDesc}}) + if (LI->getAction({CandidateLoadOpc, {UseTy, SrcTy}, {MMDesc}}) .Action != LegalizeActions::Legal) continue; } @@ -587,12 +610,8 @@ void CombinerHelper::applyCombineExtendingLoads(MachineInstr &MI, }; Observer.changingInstr(MI); - MI.setDesc( - Builder.getTII().get(Preferred.ExtendOpcode == TargetOpcode::G_SEXT - ? TargetOpcode::G_SEXTLOAD - : Preferred.ExtendOpcode == TargetOpcode::G_ZEXT - ? TargetOpcode::G_ZEXTLOAD - : TargetOpcode::G_LOAD)); + unsigned LoadOpc = getExtLoadOpcForExtend(Preferred.ExtendOpcode); + MI.setDesc(Builder.getTII().get(LoadOpc)); // Rewrite all the uses to fix up the types. auto &LoadValue = MI.getOperand(0); @@ -1266,12 +1285,12 @@ bool CombinerHelper::tryCombineMemCpyFamily(MachineInstr &MI, unsigned MaxLen) { LegalizerHelper::LegalizeResult::Legalized; } -static Optional<APFloat> constantFoldFpUnary(unsigned Opcode, LLT DstTy, - const Register Op, - const MachineRegisterInfo &MRI) { +static std::optional<APFloat> +constantFoldFpUnary(unsigned Opcode, LLT DstTy, const Register Op, + const MachineRegisterInfo &MRI) { const ConstantFP *MaybeCst = getConstantFPVRegVal(Op, MRI); if (!MaybeCst) - return None; + return std::nullopt; APFloat V = MaybeCst->getValueAPF(); switch (Opcode) { @@ -1308,8 +1327,8 @@ static Optional<APFloat> constantFoldFpUnary(unsigned Opcode, LLT DstTy, return V; } -bool CombinerHelper::matchCombineConstantFoldFpUnary(MachineInstr &MI, - Optional<APFloat> &Cst) { +bool CombinerHelper::matchCombineConstantFoldFpUnary( + MachineInstr &MI, std::optional<APFloat> &Cst) { Register DstReg = MI.getOperand(0).getReg(); Register SrcReg = MI.getOperand(1).getReg(); LLT DstTy = MRI.getType(DstReg); @@ -1317,8 +1336,8 @@ bool CombinerHelper::matchCombineConstantFoldFpUnary(MachineInstr &MI, return Cst.has_value(); } -void CombinerHelper::applyCombineConstantFoldFpUnary(MachineInstr &MI, - Optional<APFloat> &Cst) { +void CombinerHelper::applyCombineConstantFoldFpUnary( + MachineInstr &MI, std::optional<APFloat> &Cst) { assert(Cst && "Optional is unexpectedly empty!"); Builder.setInstrAndDebugLoc(MI); MachineFunction &MF = Builder.getMF(); @@ -1580,6 +1599,13 @@ void CombinerHelper::applyShiftOfShiftedLogic(MachineInstr &MI, Register Shift1 = Builder.buildInstr(Opcode, {DestType}, {Shift1Base, Const}).getReg(0); + // If LogicNonShiftReg is the same to Shift1Base, and shift1 const is the same + // to MatchInfo.Shift2 const, CSEMIRBuilder will reuse the old shift1 when + // build shift2. So, if we erase MatchInfo.Shift2 at the end, actually we + // remove old shift1. And it will cause crash later. So erase it earlier to + // avoid the crash. + MatchInfo.Shift2->eraseFromParent(); + Register Shift2Const = MI.getOperand(2).getReg(); Register Shift2 = Builder .buildInstr(Opcode, {DestType}, @@ -1589,8 +1615,7 @@ void CombinerHelper::applyShiftOfShiftedLogic(MachineInstr &MI, Register Dest = MI.getOperand(0).getReg(); Builder.buildInstr(MatchInfo.Logic->getOpcode(), {Dest}, {Shift1, Shift2}); - // These were one use so it's safe to remove them. - MatchInfo.Shift2->eraseFromParent(); + // This was one use so it's safe to remove it. MatchInfo.Logic->eraseFromParent(); MI.eraseFromParent(); @@ -1706,7 +1731,7 @@ bool CombinerHelper::matchCombineUnmergeMergeToPlainValues( auto &Unmerge = cast<GUnmerge>(MI); Register SrcReg = peekThroughBitcast(Unmerge.getSourceReg(), MRI); - auto *SrcInstr = getOpcodeDef<GMergeLikeOp>(SrcReg, MRI); + auto *SrcInstr = getOpcodeDef<GMergeLikeInstr>(SrcReg, MRI); if (!SrcInstr) return false; @@ -1947,7 +1972,7 @@ void CombinerHelper::applyCombineShiftToUnmerge(MachineInstr &MI, } auto Zero = Builder.buildConstant(HalfTy, 0); - Builder.buildMerge(DstReg, { Narrowed, Zero }); + Builder.buildMergeLikeInstr(DstReg, {Narrowed, Zero}); } else if (MI.getOpcode() == TargetOpcode::G_SHL) { Register Narrowed = Unmerge.getReg(0); // dst = G_SHL s64:x, C for C >= 32 @@ -1960,7 +1985,7 @@ void CombinerHelper::applyCombineShiftToUnmerge(MachineInstr &MI, } auto Zero = Builder.buildConstant(HalfTy, 0); - Builder.buildMerge(DstReg, { Zero, Narrowed }); + Builder.buildMergeLikeInstr(DstReg, {Zero, Narrowed}); } else { assert(MI.getOpcode() == TargetOpcode::G_ASHR); auto Hi = Builder.buildAShr( @@ -1970,13 +1995,13 @@ void CombinerHelper::applyCombineShiftToUnmerge(MachineInstr &MI, if (ShiftVal == HalfSize) { // (G_ASHR i64:x, 32) -> // G_MERGE_VALUES hi_32(x), (G_ASHR hi_32(x), 31) - Builder.buildMerge(DstReg, { Unmerge.getReg(1), Hi }); + Builder.buildMergeLikeInstr(DstReg, {Unmerge.getReg(1), Hi}); } else if (ShiftVal == Size - 1) { // Don't need a second shift. // (G_ASHR i64:x, 63) -> // %narrowed = (G_ASHR hi_32(x), 31) // G_MERGE_VALUES %narrowed, %narrowed - Builder.buildMerge(DstReg, { Hi, Hi }); + Builder.buildMergeLikeInstr(DstReg, {Hi, Hi}); } else { auto Lo = Builder.buildAShr( HalfTy, Unmerge.getReg(1), @@ -1984,7 +2009,7 @@ void CombinerHelper::applyCombineShiftToUnmerge(MachineInstr &MI, // (G_ASHR i64:x, C) ->, for C >= 32 // G_MERGE_VALUES (G_ASHR hi_32(x), C - 32), (G_ASHR hi_32(x), 31) - Builder.buildMerge(DstReg, { Lo, Hi }); + Builder.buildMergeLikeInstr(DstReg, {Lo, Hi}); } } @@ -2019,12 +2044,6 @@ void CombinerHelper::applyCombineI2PToP2I(MachineInstr &MI, Register &Reg) { MI.eraseFromParent(); } -bool CombinerHelper::matchCombineP2IToI2P(MachineInstr &MI, Register &Reg) { - assert(MI.getOpcode() == TargetOpcode::G_PTRTOINT && "Expected a G_PTRTOINT"); - Register SrcReg = MI.getOperand(1).getReg(); - return mi_match(SrcReg, MRI, m_GIntToPtr(m_Reg(Reg))); -} - void CombinerHelper::applyCombineP2IToI2P(MachineInstr &MI, Register &Reg) { assert(MI.getOpcode() == TargetOpcode::G_PTRTOINT && "Expected a G_PTRTOINT"); Register DstReg = MI.getOperand(0).getReg(); @@ -2195,19 +2214,6 @@ void CombinerHelper::applyCombineMulByNegativeOne(MachineInstr &MI) { MI.eraseFromParent(); } -bool CombinerHelper::matchCombineFNegOfFNeg(MachineInstr &MI, Register &Reg) { - assert(MI.getOpcode() == TargetOpcode::G_FNEG && "Expected a G_FNEG"); - Register SrcReg = MI.getOperand(1).getReg(); - return mi_match(SrcReg, MRI, m_GFNeg(m_Reg(Reg))); -} - -bool CombinerHelper::matchCombineFAbsOfFAbs(MachineInstr &MI, Register &Src) { - assert(MI.getOpcode() == TargetOpcode::G_FABS && "Expected a G_FABS"); - Src = MI.getOperand(1).getReg(); - Register AbsSrc; - return mi_match(Src, MRI, m_GFabs(m_Reg(AbsSrc))); -} - bool CombinerHelper::matchCombineFAbsOfFNeg(MachineInstr &MI, BuildFnTy &MatchInfo) { assert(MI.getOpcode() == TargetOpcode::G_FABS && "Expected a G_FABS"); @@ -2260,44 +2266,109 @@ void CombinerHelper::applyCombineTruncOfExt( MI.eraseFromParent(); } -bool CombinerHelper::matchCombineTruncOfShl( - MachineInstr &MI, std::pair<Register, Register> &MatchInfo) { - assert(MI.getOpcode() == TargetOpcode::G_TRUNC && "Expected a G_TRUNC"); - Register DstReg = MI.getOperand(0).getReg(); - Register SrcReg = MI.getOperand(1).getReg(); - LLT DstTy = MRI.getType(DstReg); - Register ShiftSrc; - Register ShiftAmt; +static LLT getMidVTForTruncRightShiftCombine(LLT ShiftTy, LLT TruncTy) { + const unsigned ShiftSize = ShiftTy.getScalarSizeInBits(); + const unsigned TruncSize = TruncTy.getScalarSizeInBits(); - if (MRI.hasOneNonDBGUse(SrcReg) && - mi_match(SrcReg, MRI, m_GShl(m_Reg(ShiftSrc), m_Reg(ShiftAmt))) && - isLegalOrBeforeLegalizer( - {TargetOpcode::G_SHL, - {DstTy, getTargetLowering().getPreferredShiftAmountTy(DstTy)}})) { - KnownBits Known = KB->getKnownBits(ShiftAmt); - unsigned Size = DstTy.getSizeInBits(); - if (Known.countMaxActiveBits() <= Log2_32(Size)) { - MatchInfo = std::make_pair(ShiftSrc, ShiftAmt); - return true; - } - } - return false; + // ShiftTy > 32 > TruncTy -> 32 + if (ShiftSize > 32 && TruncSize < 32) + return ShiftTy.changeElementSize(32); + + // TODO: We could also reduce to 16 bits, but that's more target-dependent. + // Some targets like it, some don't, some only like it under certain + // conditions/processor versions, etc. + // A TL hook might be needed for this. + + // Don't combine + return ShiftTy; } -void CombinerHelper::applyCombineTruncOfShl( - MachineInstr &MI, std::pair<Register, Register> &MatchInfo) { +bool CombinerHelper::matchCombineTruncOfShift( + MachineInstr &MI, std::pair<MachineInstr *, LLT> &MatchInfo) { assert(MI.getOpcode() == TargetOpcode::G_TRUNC && "Expected a G_TRUNC"); Register DstReg = MI.getOperand(0).getReg(); Register SrcReg = MI.getOperand(1).getReg(); + + if (!MRI.hasOneNonDBGUse(SrcReg)) + return false; + + LLT SrcTy = MRI.getType(SrcReg); LLT DstTy = MRI.getType(DstReg); - MachineInstr *SrcMI = MRI.getVRegDef(SrcReg); - Register ShiftSrc = MatchInfo.first; - Register ShiftAmt = MatchInfo.second; + MachineInstr *SrcMI = getDefIgnoringCopies(SrcReg, MRI); + const auto &TL = getTargetLowering(); + + LLT NewShiftTy; + switch (SrcMI->getOpcode()) { + default: + return false; + case TargetOpcode::G_SHL: { + NewShiftTy = DstTy; + + // Make sure new shift amount is legal. + KnownBits Known = KB->getKnownBits(SrcMI->getOperand(2).getReg()); + if (Known.getMaxValue().uge(NewShiftTy.getScalarSizeInBits())) + return false; + break; + } + case TargetOpcode::G_LSHR: + case TargetOpcode::G_ASHR: { + // For right shifts, we conservatively do not do the transform if the TRUNC + // has any STORE users. The reason is that if we change the type of the + // shift, we may break the truncstore combine. + // + // TODO: Fix truncstore combine to handle (trunc(lshr (trunc x), k)). + for (auto &User : MRI.use_instructions(DstReg)) + if (User.getOpcode() == TargetOpcode::G_STORE) + return false; + + NewShiftTy = getMidVTForTruncRightShiftCombine(SrcTy, DstTy); + if (NewShiftTy == SrcTy) + return false; + + // Make sure we won't lose information by truncating the high bits. + KnownBits Known = KB->getKnownBits(SrcMI->getOperand(2).getReg()); + if (Known.getMaxValue().ugt(NewShiftTy.getScalarSizeInBits() - + DstTy.getScalarSizeInBits())) + return false; + break; + } + } + + if (!isLegalOrBeforeLegalizer( + {SrcMI->getOpcode(), + {NewShiftTy, TL.getPreferredShiftAmountTy(NewShiftTy)}})) + return false; + + MatchInfo = std::make_pair(SrcMI, NewShiftTy); + return true; +} + +void CombinerHelper::applyCombineTruncOfShift( + MachineInstr &MI, std::pair<MachineInstr *, LLT> &MatchInfo) { Builder.setInstrAndDebugLoc(MI); - auto TruncShiftSrc = Builder.buildTrunc(DstTy, ShiftSrc); - Builder.buildShl(DstReg, TruncShiftSrc, ShiftAmt, SrcMI->getFlags()); - MI.eraseFromParent(); + + MachineInstr *ShiftMI = MatchInfo.first; + LLT NewShiftTy = MatchInfo.second; + + Register Dst = MI.getOperand(0).getReg(); + LLT DstTy = MRI.getType(Dst); + + Register ShiftAmt = ShiftMI->getOperand(2).getReg(); + Register ShiftSrc = ShiftMI->getOperand(1).getReg(); + ShiftSrc = Builder.buildTrunc(NewShiftTy, ShiftSrc).getReg(0); + + Register NewShift = + Builder + .buildInstr(ShiftMI->getOpcode(), {NewShiftTy}, {ShiftSrc, ShiftAmt}) + .getReg(0); + + if (NewShiftTy == DstTy) + replaceRegWith(MRI, Dst, NewShift); + else + Builder.buildTrunc(Dst, NewShift); + + eraseInst(MI); } bool CombinerHelper::matchAnyExplicitUseIsUndef(MachineInstr &MI) { @@ -2332,6 +2403,19 @@ bool CombinerHelper::matchUndefSelectCmp(MachineInstr &MI) { MRI); } +bool CombinerHelper::matchInsertExtractVecEltOutOfBounds(MachineInstr &MI) { + assert((MI.getOpcode() == TargetOpcode::G_INSERT_VECTOR_ELT || + MI.getOpcode() == TargetOpcode::G_EXTRACT_VECTOR_ELT) && + "Expected an insert/extract element op"); + LLT VecTy = MRI.getType(MI.getOperand(1).getReg()); + unsigned IdxIdx = + MI.getOpcode() == TargetOpcode::G_EXTRACT_VECTOR_ELT ? 2 : 3; + auto Idx = getIConstantVRegVal(MI.getOperand(IdxIdx).getReg(), MRI); + if (!Idx) + return false; + return Idx->getZExtValue() >= VecTy.getNumElements(); +} + bool CombinerHelper::matchConstantSelectCmp(MachineInstr &MI, unsigned &OpIdx) { GSelect &SelMI = cast<GSelect>(MI); auto Cst = @@ -2579,7 +2663,7 @@ bool CombinerHelper::matchCombineInsertVecElts( while (mi_match( CurrInst->getOperand(0).getReg(), MRI, m_GInsertVecElt(m_MInstr(TmpInst), m_Reg(TmpReg), m_ICst(IntImm)))) { - if (IntImm >= NumElts) + if (IntImm >= NumElts || IntImm < 0) return false; if (!MatchInfo[IntImm]) MatchInfo[IntImm] = TmpReg; @@ -2738,9 +2822,9 @@ bool CombinerHelper::matchAshrShlToSextInreg( assert(MI.getOpcode() == TargetOpcode::G_ASHR); int64_t ShlCst, AshrCst; Register Src; - // FIXME: detect splat constant vectors. if (!mi_match(MI.getOperand(0).getReg(), MRI, - m_GAShr(m_GShl(m_Reg(Src), m_ICst(ShlCst)), m_ICst(AshrCst)))) + m_GAShr(m_GShl(m_Reg(Src), m_ICstOrSplat(ShlCst)), + m_ICstOrSplat(AshrCst)))) return false; if (ShlCst != AshrCst) return false; @@ -2812,12 +2896,6 @@ bool CombinerHelper::matchRedundantAnd(MachineInstr &MI, return false; Register AndDst = MI.getOperand(0).getReg(); - LLT DstTy = MRI.getType(AndDst); - - // FIXME: This should be removed once GISelKnownBits supports vectors. - if (DstTy.isVector()) - return false; - Register LHS = MI.getOperand(1).getReg(); Register RHS = MI.getOperand(2).getReg(); KnownBits LHSBits = KB->getKnownBits(LHS); @@ -2858,12 +2936,6 @@ bool CombinerHelper::matchRedundantOr(MachineInstr &MI, Register &Replacement) { return false; Register OrDst = MI.getOperand(0).getReg(); - LLT DstTy = MRI.getType(OrDst); - - // FIXME: This should be removed once GISelKnownBits supports vectors. - if (DstTy.isVector()) - return false; - Register LHS = MI.getOperand(1).getReg(); Register RHS = MI.getOperand(2).getReg(); KnownBits LHSBits = KB->getKnownBits(LHS); @@ -3190,14 +3262,12 @@ bool CombinerHelper::applyFoldBinOpIntoSelect(MachineInstr &MI, } Builder.buildSelect(Dst, SelectCond, FoldTrue, FoldFalse, MI.getFlags()); - Observer.erasingInstr(*Select); - Select->eraseFromParent(); MI.eraseFromParent(); return true; } -Optional<SmallVector<Register, 8>> +std::optional<SmallVector<Register, 8>> CombinerHelper::findCandidatesForLoadOrCombine(const MachineInstr *Root) const { assert(Root->getOpcode() == TargetOpcode::G_OR && "Expected G_OR only!"); // We want to detect if Root is part of a tree which represents a bunch @@ -3239,7 +3309,7 @@ CombinerHelper::findCandidatesForLoadOrCombine(const MachineInstr *Root) const { // In the combine, we want to elimate the entire tree. if (!MRI.hasOneNonDBGUse(OrLHS) || !MRI.hasOneNonDBGUse(OrRHS)) - return None; + return std::nullopt; // If it's a G_OR, save it and continue to walk. If it's not, then it's // something that may be a load + arithmetic. @@ -3256,7 +3326,7 @@ CombinerHelper::findCandidatesForLoadOrCombine(const MachineInstr *Root) const { // We're going to try and merge each register into a wider power-of-2 type, // so we ought to have an even number of registers. if (RegsToVisit.empty() || RegsToVisit.size() % 2 != 0) - return None; + return std::nullopt; return RegsToVisit; } @@ -3268,7 +3338,7 @@ CombinerHelper::findCandidatesForLoadOrCombine(const MachineInstr *Root) const { /// e.g. x[i] << 24 /// /// \returns The load instruction and the byte offset it is moved into. -static Optional<std::pair<GZExtLoad *, int64_t>> +static std::optional<std::pair<GZExtLoad *, int64_t>> matchLoadAndBytePosition(Register Reg, unsigned MemSizeInBits, const MachineRegisterInfo &MRI) { assert(MRI.hasOneNonDBGUse(Reg) && @@ -3282,20 +3352,20 @@ matchLoadAndBytePosition(Register Reg, unsigned MemSizeInBits, } if (Shift % MemSizeInBits != 0) - return None; + return std::nullopt; // TODO: Handle other types of loads. auto *Load = getOpcodeDef<GZExtLoad>(MaybeLoad, MRI); if (!Load) - return None; + return std::nullopt; if (!Load->isUnordered() || Load->getMemSizeInBits() != MemSizeInBits) - return None; + return std::nullopt; return std::make_pair(Load, Shift / MemSizeInBits); } -Optional<std::tuple<GZExtLoad *, int64_t, GZExtLoad *>> +std::optional<std::tuple<GZExtLoad *, int64_t, GZExtLoad *>> CombinerHelper::findLoadOffsetsForLoadOrCombine( SmallDenseMap<int64_t, int64_t, 8> &MemOffset2Idx, const SmallVector<Register, 8> &RegsToVisit, const unsigned MemSizeInBits) { @@ -3335,7 +3405,7 @@ CombinerHelper::findLoadOffsetsForLoadOrCombine( // shifted) value. auto LoadAndPos = matchLoadAndBytePosition(Reg, MemSizeInBits, MRI); if (!LoadAndPos) - return None; + return std::nullopt; GZExtLoad *Load; int64_t DstPos; std::tie(Load, DstPos) = *LoadAndPos; @@ -3346,14 +3416,14 @@ CombinerHelper::findLoadOffsetsForLoadOrCombine( if (!MBB) MBB = LoadMBB; if (LoadMBB != MBB) - return None; + return std::nullopt; // Make sure that the MachineMemOperands of every seen load are compatible. auto &LoadMMO = Load->getMMO(); if (!MMO) MMO = &LoadMMO; if (MMO->getAddrSpace() != LoadMMO.getAddrSpace()) - return None; + return std::nullopt; // Find out what the base pointer and index for the load is. Register LoadPtr; @@ -3366,7 +3436,7 @@ CombinerHelper::findLoadOffsetsForLoadOrCombine( // Don't combine things like a[i], a[i] -> a bigger load. if (!SeenIdx.insert(Idx).second) - return None; + return std::nullopt; // Every load must share the same base pointer; don't combine things like: // @@ -3374,7 +3444,7 @@ CombinerHelper::findLoadOffsetsForLoadOrCombine( if (!BasePtr.isValid()) BasePtr = LoadPtr; if (BasePtr != LoadPtr) - return None; + return std::nullopt; if (Idx < LowestIdx) { LowestIdx = Idx; @@ -3386,7 +3456,7 @@ CombinerHelper::findLoadOffsetsForLoadOrCombine( // // a[i] << 16, a[i + k] << 16 -> a bigger load. if (!MemOffset2Idx.try_emplace(DstPos, Idx).second) - return None; + return std::nullopt; Loads.insert(Load); // Keep track of the position of the earliest/latest loads in the pattern. @@ -3421,9 +3491,9 @@ CombinerHelper::findLoadOffsetsForLoadOrCombine( if (Loads.count(&MI)) continue; if (MI.isLoadFoldBarrier()) - return None; + return std::nullopt; if (Iter++ == MaxIter) - return None; + return std::nullopt; } return std::make_tuple(LowestIdxLoad, LowestIdx, LatestLoad); @@ -3487,7 +3557,7 @@ bool CombinerHelper::matchLoadOrCombine( // pattern. If it does, then we can represent it using a load + possibly a // BSWAP. bool IsBigEndianTarget = MF.getDataLayout().isBigEndian(); - Optional<bool> IsBigEndian = isBigEndian(MemOffset2Idx, LowestIdx); + std::optional<bool> IsBigEndian = isBigEndian(MemOffset2Idx, LowestIdx); if (!IsBigEndian) return false; bool NeedsBSwap = IsBigEndianTarget != *IsBigEndian; @@ -3527,7 +3597,7 @@ bool CombinerHelper::matchLoadOrCombine( // Load must be allowed and fast on the target. LLVMContext &C = MF.getFunction().getContext(); auto &DL = MF.getDataLayout(); - bool Fast = false; + unsigned Fast = 0; if (!getTargetLowering().allowsMemoryAccess(C, DL, Ty, *NewMMO, &Fast) || !Fast) return false; @@ -3548,11 +3618,12 @@ bool CombinerHelper::matchLoadOrCombine( /// value found. /// On match, returns the start byte offset of the \p SrcVal that is being /// stored. -static Optional<int64_t> getTruncStoreByteOffset(GStore &Store, Register &SrcVal, - MachineRegisterInfo &MRI) { +static std::optional<int64_t> +getTruncStoreByteOffset(GStore &Store, Register &SrcVal, + MachineRegisterInfo &MRI) { Register TruncVal; if (!mi_match(Store.getValueReg(), MRI, m_GTrunc(m_Reg(TruncVal)))) - return None; + return std::nullopt; // The shift amount must be a constant multiple of the narrow type. // It is translated to the offset address in the wide source value "y". @@ -3570,21 +3641,21 @@ static Optional<int64_t> getTruncStoreByteOffset(GStore &Store, Register &SrcVal SrcVal = TruncVal; return 0; // If it's the lowest index store. } - return None; + return std::nullopt; } unsigned NarrowBits = Store.getMMO().getMemoryType().getScalarSizeInBits(); if (ShiftAmt % NarrowBits!= 0) - return None; + return std::nullopt; const unsigned Offset = ShiftAmt / NarrowBits; if (SrcVal.isValid() && FoundSrcVal != SrcVal) - return None; + return std::nullopt; if (!SrcVal.isValid()) SrcVal = FoundSrcVal; else if (MRI.getType(SrcVal) != MRI.getType(FoundSrcVal)) - return None; + return std::nullopt; return Offset; } @@ -3732,7 +3803,7 @@ bool CombinerHelper::matchTruncStoreMerge(MachineInstr &MI, const auto &DL = LastStore.getMF()->getDataLayout(); auto &C = LastStore.getMF()->getFunction().getContext(); // Check that a store of the wide type is both allowed and fast on the target - bool Fast = false; + unsigned Fast = 0; bool Allowed = getTargetLowering().allowsMemoryAccess( C, DL, WideStoreTy, LowestIdxStore->getMMO(), &Fast); if (!Allowed || !Fast) @@ -3917,33 +3988,30 @@ bool CombinerHelper::matchExtractVecEltBuildVec(MachineInstr &MI, // and find the source register that the index maps to. Register SrcVec = MI.getOperand(1).getReg(); LLT SrcTy = MRI.getType(SrcVec); - if (!isLegalOrBeforeLegalizer( - {TargetOpcode::G_BUILD_VECTOR, {SrcTy, SrcTy.getElementType()}})) - return false; auto Cst = getIConstantVRegValWithLookThrough(MI.getOperand(2).getReg(), MRI); if (!Cst || Cst->Value.getZExtValue() >= SrcTy.getNumElements()) return false; unsigned VecIdx = Cst->Value.getZExtValue(); - MachineInstr *BuildVecMI = - getOpcodeDef(TargetOpcode::G_BUILD_VECTOR, SrcVec, MRI); - if (!BuildVecMI) { - BuildVecMI = getOpcodeDef(TargetOpcode::G_BUILD_VECTOR_TRUNC, SrcVec, MRI); - if (!BuildVecMI) - return false; - LLT ScalarTy = MRI.getType(BuildVecMI->getOperand(1).getReg()); - if (!isLegalOrBeforeLegalizer( - {TargetOpcode::G_BUILD_VECTOR_TRUNC, {SrcTy, ScalarTy}})) - return false; + + // Check if we have a build_vector or build_vector_trunc with an optional + // trunc in front. + MachineInstr *SrcVecMI = MRI.getVRegDef(SrcVec); + if (SrcVecMI->getOpcode() == TargetOpcode::G_TRUNC) { + SrcVecMI = MRI.getVRegDef(SrcVecMI->getOperand(1).getReg()); } + if (SrcVecMI->getOpcode() != TargetOpcode::G_BUILD_VECTOR && + SrcVecMI->getOpcode() != TargetOpcode::G_BUILD_VECTOR_TRUNC) + return false; + EVT Ty(getMVTForLLT(SrcTy)); if (!MRI.hasOneNonDBGUse(SrcVec) && !getTargetLowering().aggressivelyPreferBuildVectorSources(Ty)) return false; - Reg = BuildVecMI->getOperand(VecIdx + 1).getReg(); + Reg = SrcVecMI->getOperand(VecIdx + 1).getReg(); return true; } @@ -4146,7 +4214,7 @@ bool CombinerHelper::matchICmpToTrueFalseKnownBits(MachineInstr &MI, auto Pred = static_cast<CmpInst::Predicate>(MI.getOperand(1).getPredicate()); auto KnownLHS = KB->getKnownBits(MI.getOperand(2).getReg()); auto KnownRHS = KB->getKnownBits(MI.getOperand(3).getReg()); - Optional<bool> KnownVal; + std::optional<bool> KnownVal; switch (Pred) { default: llvm_unreachable("Unexpected G_ICMP predicate?"); @@ -4542,7 +4610,7 @@ bool CombinerHelper::matchReassocConstantInnerLHS(GPtrAdd &MI, // G_PTR_ADD (G_PTR_ADD X, C), Y) -> (G_PTR_ADD (G_PTR_ADD(X, Y), C) // if and only if (G_PTR_ADD X, C) has one use. Register LHSBase; - Optional<ValueAndVReg> LHSCstOff; + std::optional<ValueAndVReg> LHSCstOff; if (!mi_match(MI.getBaseReg(), MRI, m_OneNonDBGUse(m_GPtrAdd(m_Reg(LHSBase), m_GCst(LHSCstOff))))) return false; @@ -4554,8 +4622,10 @@ bool CombinerHelper::matchReassocConstantInnerLHS(GPtrAdd &MI, // doesn't happen. LHSPtrAdd->moveBefore(&MI); Register RHSReg = MI.getOffsetReg(); + // set VReg will cause type mismatch if it comes from extend/trunc + auto NewCst = B.buildConstant(MRI.getType(RHSReg), LHSCstOff->Value); Observer.changingInstr(MI); - MI.getOperand(2).setReg(LHSCstOff->VReg); + MI.getOperand(2).setReg(NewCst.getReg(0)); Observer.changedInstr(MI); Observer.changingInstr(*LHSPtrAdd); LHSPtrAdd->getOperand(2).setReg(RHSReg); @@ -4781,6 +4851,83 @@ bool CombinerHelper::matchAddOBy0(MachineInstr &MI, BuildFnTy &MatchInfo) { return true; } +bool CombinerHelper::matchAddEToAddO(MachineInstr &MI, BuildFnTy &MatchInfo) { + // (G_*ADDE x, y, 0) -> (G_*ADDO x, y) + // (G_*SUBE x, y, 0) -> (G_*SUBO x, y) + assert(MI.getOpcode() == TargetOpcode::G_UADDE || + MI.getOpcode() == TargetOpcode::G_SADDE || + MI.getOpcode() == TargetOpcode::G_USUBE || + MI.getOpcode() == TargetOpcode::G_SSUBE); + if (!mi_match(MI.getOperand(4).getReg(), MRI, m_SpecificICstOrSplat(0))) + return false; + MatchInfo = [&](MachineIRBuilder &B) { + unsigned NewOpcode; + switch (MI.getOpcode()) { + case TargetOpcode::G_UADDE: + NewOpcode = TargetOpcode::G_UADDO; + break; + case TargetOpcode::G_SADDE: + NewOpcode = TargetOpcode::G_SADDO; + break; + case TargetOpcode::G_USUBE: + NewOpcode = TargetOpcode::G_USUBO; + break; + case TargetOpcode::G_SSUBE: + NewOpcode = TargetOpcode::G_SSUBO; + break; + } + Observer.changingInstr(MI); + MI.setDesc(B.getTII().get(NewOpcode)); + MI.removeOperand(4); + Observer.changedInstr(MI); + }; + return true; +} + +bool CombinerHelper::matchSubAddSameReg(MachineInstr &MI, + BuildFnTy &MatchInfo) { + assert(MI.getOpcode() == TargetOpcode::G_SUB); + Register Dst = MI.getOperand(0).getReg(); + // (x + y) - z -> x (if y == z) + // (x + y) - z -> y (if x == z) + Register X, Y, Z; + if (mi_match(Dst, MRI, m_GSub(m_GAdd(m_Reg(X), m_Reg(Y)), m_Reg(Z)))) { + Register ReplaceReg; + int64_t CstX, CstY; + if (Y == Z || (mi_match(Y, MRI, m_ICstOrSplat(CstY)) && + mi_match(Z, MRI, m_SpecificICstOrSplat(CstY)))) + ReplaceReg = X; + else if (X == Z || (mi_match(X, MRI, m_ICstOrSplat(CstX)) && + mi_match(Z, MRI, m_SpecificICstOrSplat(CstX)))) + ReplaceReg = Y; + if (ReplaceReg) { + MatchInfo = [=](MachineIRBuilder &B) { B.buildCopy(Dst, ReplaceReg); }; + return true; + } + } + + // x - (y + z) -> 0 - y (if x == z) + // x - (y + z) -> 0 - z (if x == y) + if (mi_match(Dst, MRI, m_GSub(m_Reg(X), m_GAdd(m_Reg(Y), m_Reg(Z))))) { + Register ReplaceReg; + int64_t CstX; + if (X == Z || (mi_match(X, MRI, m_ICstOrSplat(CstX)) && + mi_match(Z, MRI, m_SpecificICstOrSplat(CstX)))) + ReplaceReg = Y; + else if (X == Y || (mi_match(X, MRI, m_ICstOrSplat(CstX)) && + mi_match(Y, MRI, m_SpecificICstOrSplat(CstX)))) + ReplaceReg = Z; + if (ReplaceReg) { + MatchInfo = [=](MachineIRBuilder &B) { + auto Zero = B.buildConstant(MRI.getType(Dst), 0); + B.buildSub(Dst, Zero, ReplaceReg); + }; + return true; + } + } + return false; +} + MachineInstr *CombinerHelper::buildUDivUsingMul(MachineInstr &MI) { assert(MI.getOpcode() == TargetOpcode::G_UDIV); auto &UDiv = cast<GenericMachineInstr>(MI); @@ -4801,34 +4948,33 @@ MachineInstr *CombinerHelper::buildUDivUsingMul(MachineInstr &MI) { auto BuildUDIVPattern = [&](const Constant *C) { auto *CI = cast<ConstantInt>(C); const APInt &Divisor = CI->getValue(); - UnsignedDivisionByConstantInfo magics = - UnsignedDivisionByConstantInfo::get(Divisor); + + bool SelNPQ = false; + APInt Magic(Divisor.getBitWidth(), 0); unsigned PreShift = 0, PostShift = 0; - // If the divisor is even, we can avoid using the expensive fixup by - // shifting the divided value upfront. - if (magics.IsAdd && !Divisor[0]) { - PreShift = Divisor.countTrailingZeros(); - // Get magic number for the shifted divisor. - magics = - UnsignedDivisionByConstantInfo::get(Divisor.lshr(PreShift), PreShift); - assert(!magics.IsAdd && "Should use cheap fixup now"); - } + // Magic algorithm doesn't work for division by 1. We need to emit a select + // at the end. + // TODO: Use undef values for divisor of 1. + if (!Divisor.isOneValue()) { + UnsignedDivisionByConstantInfo magics = + UnsignedDivisionByConstantInfo::get(Divisor); - unsigned SelNPQ; - if (!magics.IsAdd || Divisor.isOneValue()) { - assert(magics.ShiftAmount < Divisor.getBitWidth() && + Magic = std::move(magics.Magic); + + assert(magics.PreShift < Divisor.getBitWidth() && "We shouldn't generate an undefined shift!"); - PostShift = magics.ShiftAmount; - SelNPQ = false; - } else { - PostShift = magics.ShiftAmount - 1; - SelNPQ = true; + assert(magics.PostShift < Divisor.getBitWidth() && + "We shouldn't generate an undefined shift!"); + assert((!magics.IsAdd || magics.PreShift == 0) && "Unexpected pre-shift"); + PreShift = magics.PreShift; + PostShift = magics.PostShift; + SelNPQ = magics.IsAdd; } PreShifts.push_back( MIB.buildConstant(ScalarShiftAmtTy, PreShift).getReg(0)); - MagicFactors.push_back(MIB.buildConstant(ScalarTy, magics.Magic).getReg(0)); + MagicFactors.push_back(MIB.buildConstant(ScalarTy, Magic).getReg(0)); NPQFactors.push_back( MIB.buildConstant(ScalarTy, SelNPQ ? APInt::getOneBitSet(EltBits, EltBits - 1) @@ -4935,6 +5081,108 @@ void CombinerHelper::applyUDivByConst(MachineInstr &MI) { replaceSingleDefInstWithReg(MI, NewMI->getOperand(0).getReg()); } +bool CombinerHelper::matchSDivByConst(MachineInstr &MI) { + assert(MI.getOpcode() == TargetOpcode::G_SDIV && "Expected SDIV"); + Register Dst = MI.getOperand(0).getReg(); + Register RHS = MI.getOperand(2).getReg(); + LLT DstTy = MRI.getType(Dst); + + auto &MF = *MI.getMF(); + AttributeList Attr = MF.getFunction().getAttributes(); + const auto &TLI = getTargetLowering(); + LLVMContext &Ctx = MF.getFunction().getContext(); + auto &DL = MF.getDataLayout(); + if (TLI.isIntDivCheap(getApproximateEVTForLLT(DstTy, DL, Ctx), Attr)) + return false; + + // Don't do this for minsize because the instruction sequence is usually + // larger. + if (MF.getFunction().hasMinSize()) + return false; + + // If the sdiv has an 'exact' flag we can use a simpler lowering. + if (MI.getFlag(MachineInstr::MIFlag::IsExact)) { + return matchUnaryPredicate( + MRI, RHS, [](const Constant *C) { return C && !C->isZeroValue(); }); + } + + // Don't support the general case for now. + return false; +} + +void CombinerHelper::applySDivByConst(MachineInstr &MI) { + auto *NewMI = buildSDivUsingMul(MI); + replaceSingleDefInstWithReg(MI, NewMI->getOperand(0).getReg()); +} + +MachineInstr *CombinerHelper::buildSDivUsingMul(MachineInstr &MI) { + assert(MI.getOpcode() == TargetOpcode::G_SDIV && "Expected SDIV"); + auto &SDiv = cast<GenericMachineInstr>(MI); + Register Dst = SDiv.getReg(0); + Register LHS = SDiv.getReg(1); + Register RHS = SDiv.getReg(2); + LLT Ty = MRI.getType(Dst); + LLT ScalarTy = Ty.getScalarType(); + LLT ShiftAmtTy = getTargetLowering().getPreferredShiftAmountTy(Ty); + LLT ScalarShiftAmtTy = ShiftAmtTy.getScalarType(); + auto &MIB = Builder; + MIB.setInstrAndDebugLoc(MI); + + bool UseSRA = false; + SmallVector<Register, 16> Shifts, Factors; + + auto *RHSDef = cast<GenericMachineInstr>(getDefIgnoringCopies(RHS, MRI)); + bool IsSplat = getIConstantSplatVal(*RHSDef, MRI).has_value(); + + auto BuildSDIVPattern = [&](const Constant *C) { + // Don't recompute inverses for each splat element. + if (IsSplat && !Factors.empty()) { + Shifts.push_back(Shifts[0]); + Factors.push_back(Factors[0]); + return true; + } + + auto *CI = cast<ConstantInt>(C); + APInt Divisor = CI->getValue(); + unsigned Shift = Divisor.countTrailingZeros(); + if (Shift) { + Divisor.ashrInPlace(Shift); + UseSRA = true; + } + + // Calculate the multiplicative inverse modulo BW. + // 2^W requires W + 1 bits, so we have to extend and then truncate. + unsigned W = Divisor.getBitWidth(); + APInt Factor = Divisor.zext(W + 1) + .multiplicativeInverse(APInt::getSignedMinValue(W + 1)) + .trunc(W); + Shifts.push_back(MIB.buildConstant(ScalarShiftAmtTy, Shift).getReg(0)); + Factors.push_back(MIB.buildConstant(ScalarTy, Factor).getReg(0)); + return true; + }; + + // Collect all magic values from the build vector. + bool Matched = matchUnaryPredicate(MRI, RHS, BuildSDIVPattern); + (void)Matched; + assert(Matched && "Expected unary predicate match to succeed"); + + Register Shift, Factor; + if (Ty.isVector()) { + Shift = MIB.buildBuildVector(ShiftAmtTy, Shifts).getReg(0); + Factor = MIB.buildBuildVector(Ty, Factors).getReg(0); + } else { + Shift = Shifts[0]; + Factor = Factors[0]; + } + + Register Res = LHS; + + if (UseSRA) + Res = MIB.buildAShr(Ty, Res, Shift, MachineInstr::IsExact).getReg(0); + + return MIB.buildMul(Ty, Res, Factor); +} + bool CombinerHelper::matchUMulHToLShr(MachineInstr &MI) { assert(MI.getOpcode() == TargetOpcode::G_UMULH); Register RHS = MI.getOperand(2).getReg(); @@ -5014,6 +5262,38 @@ bool CombinerHelper::matchRedundantNegOperands(MachineInstr &MI, return true; } +bool CombinerHelper::matchFsubToFneg(MachineInstr &MI, Register &MatchInfo) { + assert(MI.getOpcode() == TargetOpcode::G_FSUB); + + Register LHS = MI.getOperand(1).getReg(); + MatchInfo = MI.getOperand(2).getReg(); + LLT Ty = MRI.getType(MI.getOperand(0).getReg()); + + const auto LHSCst = Ty.isVector() + ? getFConstantSplat(LHS, MRI, /* allowUndef */ true) + : getFConstantVRegValWithLookThrough(LHS, MRI); + if (!LHSCst) + return false; + + // -0.0 is always allowed + if (LHSCst->Value.isNegZero()) + return true; + + // +0.0 is only allowed if nsz is set. + if (LHSCst->Value.isPosZero()) + return MI.getFlag(MachineInstr::FmNsz); + + return false; +} + +void CombinerHelper::applyFsubToFneg(MachineInstr &MI, Register &MatchInfo) { + Builder.setInstrAndDebugLoc(MI); + Register Dst = MI.getOperand(0).getReg(); + Builder.buildFNeg( + Dst, Builder.buildFCanonicalize(MRI.getType(Dst), MatchInfo).getReg(0)); + eraseInst(MI); +} + /// Checks if \p MI is TargetOpcode::G_FMUL and contractable either /// due to global flags or MachineInstr flags. static bool isContractableFMul(MachineInstr &MI, bool AllowFusionGlobally) { @@ -5045,7 +5325,7 @@ bool CombinerHelper::canCombineFMadOrFMA(MachineInstr &MI, return false; // Floating-point multiply-add with intermediate rounding. - HasFMAD = (LI && TLI.isFMADLegal(MI, DstType)); + HasFMAD = (!isPreLegalize() && TLI.isFMADLegal(MI, DstType)); // Floating-point multiply-add without intermediate rounding. bool HasFMA = TLI.isFMAFasterThanFMulAndFAdd(*MF, DstType) && isLegalOrBeforeLegalizer({TargetOpcode::G_FMA, {DstType}}); @@ -5670,6 +5950,241 @@ bool CombinerHelper::matchAddSubSameReg(MachineInstr &MI, Register &Src) { return CheckFold(LHS, RHS) || CheckFold(RHS, LHS); } +bool CombinerHelper::matchBuildVectorIdentityFold(MachineInstr &MI, + Register &MatchInfo) { + // This combine folds the following patterns: + // + // G_BUILD_VECTOR_TRUNC (G_BITCAST(x), G_LSHR(G_BITCAST(x), k)) + // G_BUILD_VECTOR(G_TRUNC(G_BITCAST(x)), G_TRUNC(G_LSHR(G_BITCAST(x), k))) + // into + // x + // if + // k == sizeof(VecEltTy)/2 + // type(x) == type(dst) + // + // G_BUILD_VECTOR(G_TRUNC(G_BITCAST(x)), undef) + // into + // x + // if + // type(x) == type(dst) + + LLT DstVecTy = MRI.getType(MI.getOperand(0).getReg()); + LLT DstEltTy = DstVecTy.getElementType(); + + Register Lo, Hi; + + if (mi_match( + MI, MRI, + m_GBuildVector(m_GTrunc(m_GBitcast(m_Reg(Lo))), m_GImplicitDef()))) { + MatchInfo = Lo; + return MRI.getType(MatchInfo) == DstVecTy; + } + + std::optional<ValueAndVReg> ShiftAmount; + const auto LoPattern = m_GBitcast(m_Reg(Lo)); + const auto HiPattern = m_GLShr(m_GBitcast(m_Reg(Hi)), m_GCst(ShiftAmount)); + if (mi_match( + MI, MRI, + m_any_of(m_GBuildVectorTrunc(LoPattern, HiPattern), + m_GBuildVector(m_GTrunc(LoPattern), m_GTrunc(HiPattern))))) { + if (Lo == Hi && ShiftAmount->Value == DstEltTy.getSizeInBits()) { + MatchInfo = Lo; + return MRI.getType(MatchInfo) == DstVecTy; + } + } + + return false; +} + +bool CombinerHelper::matchTruncBuildVectorFold(MachineInstr &MI, + Register &MatchInfo) { + // Replace (G_TRUNC (G_BITCAST (G_BUILD_VECTOR x, y)) with just x + // if type(x) == type(G_TRUNC) + if (!mi_match(MI.getOperand(1).getReg(), MRI, + m_GBitcast(m_GBuildVector(m_Reg(MatchInfo), m_Reg())))) + return false; + + return MRI.getType(MatchInfo) == MRI.getType(MI.getOperand(0).getReg()); +} + +bool CombinerHelper::matchTruncLshrBuildVectorFold(MachineInstr &MI, + Register &MatchInfo) { + // Replace (G_TRUNC (G_LSHR (G_BITCAST (G_BUILD_VECTOR x, y)), K)) with + // y if K == size of vector element type + std::optional<ValueAndVReg> ShiftAmt; + if (!mi_match(MI.getOperand(1).getReg(), MRI, + m_GLShr(m_GBitcast(m_GBuildVector(m_Reg(), m_Reg(MatchInfo))), + m_GCst(ShiftAmt)))) + return false; + + LLT MatchTy = MRI.getType(MatchInfo); + return ShiftAmt->Value.getZExtValue() == MatchTy.getSizeInBits() && + MatchTy == MRI.getType(MI.getOperand(0).getReg()); +} + +unsigned CombinerHelper::getFPMinMaxOpcForSelect( + CmpInst::Predicate Pred, LLT DstTy, + SelectPatternNaNBehaviour VsNaNRetVal) const { + assert(VsNaNRetVal != SelectPatternNaNBehaviour::NOT_APPLICABLE && + "Expected a NaN behaviour?"); + // Choose an opcode based off of legality or the behaviour when one of the + // LHS/RHS may be NaN. + switch (Pred) { + default: + return 0; + case CmpInst::FCMP_UGT: + case CmpInst::FCMP_UGE: + case CmpInst::FCMP_OGT: + case CmpInst::FCMP_OGE: + if (VsNaNRetVal == SelectPatternNaNBehaviour::RETURNS_OTHER) + return TargetOpcode::G_FMAXNUM; + if (VsNaNRetVal == SelectPatternNaNBehaviour::RETURNS_NAN) + return TargetOpcode::G_FMAXIMUM; + if (isLegal({TargetOpcode::G_FMAXNUM, {DstTy}})) + return TargetOpcode::G_FMAXNUM; + if (isLegal({TargetOpcode::G_FMAXIMUM, {DstTy}})) + return TargetOpcode::G_FMAXIMUM; + return 0; + case CmpInst::FCMP_ULT: + case CmpInst::FCMP_ULE: + case CmpInst::FCMP_OLT: + case CmpInst::FCMP_OLE: + if (VsNaNRetVal == SelectPatternNaNBehaviour::RETURNS_OTHER) + return TargetOpcode::G_FMINNUM; + if (VsNaNRetVal == SelectPatternNaNBehaviour::RETURNS_NAN) + return TargetOpcode::G_FMINIMUM; + if (isLegal({TargetOpcode::G_FMINNUM, {DstTy}})) + return TargetOpcode::G_FMINNUM; + if (!isLegal({TargetOpcode::G_FMINIMUM, {DstTy}})) + return 0; + return TargetOpcode::G_FMINIMUM; + } +} + +CombinerHelper::SelectPatternNaNBehaviour +CombinerHelper::computeRetValAgainstNaN(Register LHS, Register RHS, + bool IsOrderedComparison) const { + bool LHSSafe = isKnownNeverNaN(LHS, MRI); + bool RHSSafe = isKnownNeverNaN(RHS, MRI); + // Completely unsafe. + if (!LHSSafe && !RHSSafe) + return SelectPatternNaNBehaviour::NOT_APPLICABLE; + if (LHSSafe && RHSSafe) + return SelectPatternNaNBehaviour::RETURNS_ANY; + // An ordered comparison will return false when given a NaN, so it + // returns the RHS. + if (IsOrderedComparison) + return LHSSafe ? SelectPatternNaNBehaviour::RETURNS_NAN + : SelectPatternNaNBehaviour::RETURNS_OTHER; + // An unordered comparison will return true when given a NaN, so it + // returns the LHS. + return LHSSafe ? SelectPatternNaNBehaviour::RETURNS_OTHER + : SelectPatternNaNBehaviour::RETURNS_NAN; +} + +bool CombinerHelper::matchFPSelectToMinMax(Register Dst, Register Cond, + Register TrueVal, Register FalseVal, + BuildFnTy &MatchInfo) { + // Match: select (fcmp cond x, y) x, y + // select (fcmp cond x, y) y, x + // And turn it into fminnum/fmaxnum or fmin/fmax based off of the condition. + LLT DstTy = MRI.getType(Dst); + // Bail out early on pointers, since we'll never want to fold to a min/max. + if (DstTy.isPointer()) + return false; + // Match a floating point compare with a less-than/greater-than predicate. + // TODO: Allow multiple users of the compare if they are all selects. + CmpInst::Predicate Pred; + Register CmpLHS, CmpRHS; + if (!mi_match(Cond, MRI, + m_OneNonDBGUse( + m_GFCmp(m_Pred(Pred), m_Reg(CmpLHS), m_Reg(CmpRHS)))) || + CmpInst::isEquality(Pred)) + return false; + SelectPatternNaNBehaviour ResWithKnownNaNInfo = + computeRetValAgainstNaN(CmpLHS, CmpRHS, CmpInst::isOrdered(Pred)); + if (ResWithKnownNaNInfo == SelectPatternNaNBehaviour::NOT_APPLICABLE) + return false; + if (TrueVal == CmpRHS && FalseVal == CmpLHS) { + std::swap(CmpLHS, CmpRHS); + Pred = CmpInst::getSwappedPredicate(Pred); + if (ResWithKnownNaNInfo == SelectPatternNaNBehaviour::RETURNS_NAN) + ResWithKnownNaNInfo = SelectPatternNaNBehaviour::RETURNS_OTHER; + else if (ResWithKnownNaNInfo == SelectPatternNaNBehaviour::RETURNS_OTHER) + ResWithKnownNaNInfo = SelectPatternNaNBehaviour::RETURNS_NAN; + } + if (TrueVal != CmpLHS || FalseVal != CmpRHS) + return false; + // Decide what type of max/min this should be based off of the predicate. + unsigned Opc = getFPMinMaxOpcForSelect(Pred, DstTy, ResWithKnownNaNInfo); + if (!Opc || !isLegal({Opc, {DstTy}})) + return false; + // Comparisons between signed zero and zero may have different results... + // unless we have fmaximum/fminimum. In that case, we know -0 < 0. + if (Opc != TargetOpcode::G_FMAXIMUM && Opc != TargetOpcode::G_FMINIMUM) { + // We don't know if a comparison between two 0s will give us a consistent + // result. Be conservative and only proceed if at least one side is + // non-zero. + auto KnownNonZeroSide = getFConstantVRegValWithLookThrough(CmpLHS, MRI); + if (!KnownNonZeroSide || !KnownNonZeroSide->Value.isNonZero()) { + KnownNonZeroSide = getFConstantVRegValWithLookThrough(CmpRHS, MRI); + if (!KnownNonZeroSide || !KnownNonZeroSide->Value.isNonZero()) + return false; + } + } + MatchInfo = [=](MachineIRBuilder &B) { + B.buildInstr(Opc, {Dst}, {CmpLHS, CmpRHS}); + }; + return true; +} + +bool CombinerHelper::matchSimplifySelectToMinMax(MachineInstr &MI, + BuildFnTy &MatchInfo) { + // TODO: Handle integer cases. + assert(MI.getOpcode() == TargetOpcode::G_SELECT); + // Condition may be fed by a truncated compare. + Register Cond = MI.getOperand(1).getReg(); + Register MaybeTrunc; + if (mi_match(Cond, MRI, m_OneNonDBGUse(m_GTrunc(m_Reg(MaybeTrunc))))) + Cond = MaybeTrunc; + Register Dst = MI.getOperand(0).getReg(); + Register TrueVal = MI.getOperand(2).getReg(); + Register FalseVal = MI.getOperand(3).getReg(); + return matchFPSelectToMinMax(Dst, Cond, TrueVal, FalseVal, MatchInfo); +} + +bool CombinerHelper::matchRedundantBinOpInEquality(MachineInstr &MI, + BuildFnTy &MatchInfo) { + assert(MI.getOpcode() == TargetOpcode::G_ICMP); + // (X + Y) == X --> Y == 0 + // (X + Y) != X --> Y != 0 + // (X - Y) == X --> Y == 0 + // (X - Y) != X --> Y != 0 + // (X ^ Y) == X --> Y == 0 + // (X ^ Y) != X --> Y != 0 + Register Dst = MI.getOperand(0).getReg(); + CmpInst::Predicate Pred; + Register X, Y, OpLHS, OpRHS; + bool MatchedSub = mi_match( + Dst, MRI, + m_c_GICmp(m_Pred(Pred), m_Reg(X), m_GSub(m_Reg(OpLHS), m_Reg(Y)))); + if (MatchedSub && X != OpLHS) + return false; + if (!MatchedSub) { + if (!mi_match(Dst, MRI, + m_c_GICmp(m_Pred(Pred), m_Reg(X), + m_any_of(m_GAdd(m_Reg(OpLHS), m_Reg(OpRHS)), + m_GXor(m_Reg(OpLHS), m_Reg(OpRHS)))))) + return false; + Y = X == OpLHS ? OpRHS : X == OpRHS ? OpLHS : Register(); + } + MatchInfo = [=](MachineIRBuilder &B) { + auto Zero = B.buildConstant(MRI.getType(Y), 0); + B.buildICmp(Pred, Dst, Y, Zero); + }; + return CmpInst::isEquality(Pred) && Y.isValid(); +} + bool CombinerHelper::tryCombine(MachineInstr &MI) { if (tryCombineCopy(MI)) return true; diff --git a/llvm/lib/CodeGen/GlobalISel/GISelKnownBits.cpp b/llvm/lib/CodeGen/GlobalISel/GISelKnownBits.cpp index 4f03af0fce82..bfbe7e1c3e55 100644 --- a/llvm/lib/CodeGen/GlobalISel/GISelKnownBits.cpp +++ b/llvm/lib/CodeGen/GlobalISel/GISelKnownBits.cpp @@ -39,8 +39,7 @@ Align GISelKnownBits::computeKnownAlignment(Register R, unsigned Depth) { return computeKnownAlignment(MI->getOperand(1).getReg(), Depth); case TargetOpcode::G_ASSERT_ALIGN: { // TODO: Min with source - int64_t LogAlign = MI->getOperand(2).getImm(); - return Align(1ull << LogAlign); + return Align(MI->getOperand(2).getImm()); } case TargetOpcode::G_FRAME_INDEX: { int FrameIdx = MI->getOperand(1).getIndex(); @@ -286,7 +285,7 @@ void GISelKnownBits::computeKnownBitsImpl(Register R, KnownBits &Known, LLT Ty = MRI.getType(MI.getOperand(1).getReg()); if (DL.isNonIntegralAddressSpace(Ty.getAddressSpace())) break; - LLVM_FALLTHROUGH; + [[fallthrough]]; } case TargetOpcode::G_ADD: { computeKnownBitsImpl(MI.getOperand(1).getReg(), Known, DemandedElts, @@ -447,7 +446,7 @@ void GISelKnownBits::computeKnownBitsImpl(Register R, KnownBits &Known, if (DstTy.isVector()) break; // Fall through and handle them the same as zext/trunc. - LLVM_FALLTHROUGH; + [[fallthrough]]; case TargetOpcode::G_ASSERT_ZEXT: case TargetOpcode::G_ZEXT: case TargetOpcode::G_TRUNC: { @@ -472,9 +471,7 @@ void GISelKnownBits::computeKnownBitsImpl(Register R, KnownBits &Known, break; } case TargetOpcode::G_ASSERT_ALIGN: { - int64_t LogOfAlign = MI.getOperand(2).getImm(); - if (LogOfAlign == 0) - break; + int64_t LogOfAlign = Log2_64(MI.getOperand(2).getImm()); // TODO: Should use maximum with source // If a node is guaranteed to be aligned, set low zero bits accordingly as @@ -533,7 +530,7 @@ void GISelKnownBits::computeKnownBitsImpl(Register R, KnownBits &Known, // We can bound the space the count needs. Also, bits known to be zero can't // contribute to the population. unsigned BitsPossiblySet = Known2.countMaxPopulation(); - unsigned LowBits = Log2_32(BitsPossiblySet)+1; + unsigned LowBits = llvm::bit_width(BitsPossiblySet); Known.Zero.setBitsFrom(LowBits); // TODO: we could bound Known.One using the lower bound on the number of // bits which might be set provided by popcnt KnownOne2. @@ -714,6 +711,18 @@ unsigned GISelKnownBits::computeNumSignBits(Register R, break; } + case TargetOpcode::G_FCMP: + case TargetOpcode::G_ICMP: { + bool IsFP = Opcode == TargetOpcode::G_FCMP; + if (TyBits == 1) + break; + auto BC = TL.getBooleanContents(DstTy.isVector(), IsFP); + if (BC == TargetLoweringBase::ZeroOrNegativeOneBooleanContent) + return TyBits; // All bits are sign bits. + if (BC == TargetLowering::ZeroOrOneBooleanContent) + return TyBits - 1; // Every always-zero bit is a sign bit. + break; + } case TargetOpcode::G_INTRINSIC: case TargetOpcode::G_INTRINSIC_W_SIDE_EFFECTS: default: { diff --git a/llvm/lib/CodeGen/GlobalISel/IRTranslator.cpp b/llvm/lib/CodeGen/GlobalISel/IRTranslator.cpp index 2f9187bbf2ad..7d811dc0ad8f 100644 --- a/llvm/lib/CodeGen/GlobalISel/IRTranslator.cpp +++ b/llvm/lib/CodeGen/GlobalISel/IRTranslator.cpp @@ -16,7 +16,9 @@ #include "llvm/ADT/SmallSet.h" #include "llvm/ADT/SmallVector.h" #include "llvm/Analysis/AliasAnalysis.h" +#include "llvm/Analysis/AssumptionCache.h" #include "llvm/Analysis/BranchProbabilityInfo.h" +#include "llvm/Analysis/Loads.h" #include "llvm/Analysis/OptimizationRemarkEmitter.h" #include "llvm/Analysis/ValueTracking.h" #include "llvm/CodeGen/Analysis.h" @@ -61,6 +63,7 @@ #include "llvm/IR/LLVMContext.h" #include "llvm/IR/Metadata.h" #include "llvm/IR/PatternMatch.h" +#include "llvm/IR/Statepoint.h" #include "llvm/IR/Type.h" #include "llvm/IR/User.h" #include "llvm/IR/Value.h" @@ -81,6 +84,7 @@ #include <cassert> #include <cstdint> #include <iterator> +#include <optional> #include <string> #include <utility> #include <vector> @@ -167,6 +171,7 @@ void IRTranslator::getAnalysisUsage(AnalysisUsage &AU) const { AU.addRequired<StackProtector>(); AU.addRequired<TargetPassConfig>(); AU.addRequired<GISelCSEAnalysisWrapperPass>(); + AU.addRequired<AssumptionCacheTracker>(); if (OptLevel != CodeGenOpt::None) { AU.addRequired<BranchProbabilityInfoWrapperPass>(); AU.addRequired<AAResultsWrapperPass>(); @@ -1064,7 +1069,7 @@ void IRTranslator::emitBitTestCase(SwitchCG::BitTestBlock &BB, LLT SwitchTy = getLLTForMVT(BB.RegVT); Register Cmp; - unsigned PopCount = countPopulation(B.Mask); + unsigned PopCount = llvm::popcount(B.Mask); if (PopCount == 1) { // Testing for a single bit; just compare the shift count with what it // would need to be to shift a 1 bit in that position. @@ -1301,16 +1306,12 @@ bool IRTranslator::translateLoad(const User &U, MachineIRBuilder &MIRBuilder) { } auto &TLI = *MF->getSubtarget().getTargetLowering(); - MachineMemOperand::Flags Flags = TLI.getLoadMemOperandFlags(LI, *DL); + MachineMemOperand::Flags Flags = + TLI.getLoadMemOperandFlags(LI, *DL, AC, LibInfo); if (AA && !(Flags & MachineMemOperand::MOInvariant)) { if (AA->pointsToConstantMemory( MemoryLocation(Ptr, LocationSize::precise(StoreSize), AAInfo))) { Flags |= MachineMemOperand::MOInvariant; - - // FIXME: pointsToConstantMemory probably does not imply dereferenceable, - // but the previous usage implied it did. Probably should check - // isDereferenceableAndAlignedPointer. - Flags |= MachineMemOperand::MODereferenceable; } } @@ -1882,10 +1883,8 @@ bool IRTranslator::translateKnownIntrinsic(const CallInst &CI, Intrinsic::ID ID, MachineIRBuilder &MIRBuilder) { if (auto *MI = dyn_cast<AnyMemIntrinsic>(&CI)) { if (ORE->enabled()) { - const Function &F = *MI->getParent()->getParent(); - auto &TLI = getAnalysis<TargetLibraryInfoWrapperPass>().getTLI(F); - if (MemoryOpRemark::canHandle(MI, TLI)) { - MemoryOpRemark R(*ORE, "gisel-irtranslator-memsize", *DL, TLI); + if (MemoryOpRemark::canHandle(MI, *LibInfo)) { + MemoryOpRemark R(*ORE, "gisel-irtranslator-memsize", *DL, *LibInfo); R.visit(MI); } } @@ -2301,7 +2300,7 @@ bool IRTranslator::translateKnownIntrinsic(const CallInst &CI, Intrinsic::ID ID, // Convert the metadata argument to a constant integer Metadata *MD = cast<MetadataAsValue>(CI.getArgOperand(1))->getMetadata(); - Optional<RoundingMode> RoundMode = + std::optional<RoundingMode> RoundMode = convertStrToRoundingMode(cast<MDString>(MD)->getString()); // Add the Rounding mode as an integer @@ -2313,6 +2312,17 @@ bool IRTranslator::translateKnownIntrinsic(const CallInst &CI, Intrinsic::ID ID, return true; } + case Intrinsic::is_fpclass: { + Value *FpValue = CI.getOperand(0); + ConstantInt *TestMaskValue = cast<ConstantInt>(CI.getOperand(1)); + + MIRBuilder + .buildInstr(TargetOpcode::G_IS_FPCLASS, {getOrCreateVReg(CI)}, + {getOrCreateVReg(*FpValue)}) + .addImm(TestMaskValue->getZExtValue()); + + return true; + } #define INSTRUCTION(NAME, NARG, ROUND_MODE, INTRINSIC) \ case Intrinsic::INTRINSIC: #include "llvm/IR/ConstrainedOps.def" @@ -2352,7 +2362,7 @@ bool IRTranslator::translateCallBase(const CallBase &CB, SwiftInVReg = MRI->createGenericVirtualRegister(Ty); MIRBuilder.buildCopy(SwiftInVReg, SwiftError.getOrCreateVRegUseAt( &CB, &MIRBuilder.getMBB(), Arg)); - Args.emplace_back(makeArrayRef(SwiftInVReg)); + Args.emplace_back(ArrayRef(SwiftInVReg)); SwiftErrorVReg = SwiftError.getOrCreateVRegDefAt(&CB, &MIRBuilder.getMBB(), Arg); continue; @@ -2362,10 +2372,8 @@ bool IRTranslator::translateCallBase(const CallBase &CB, if (auto *CI = dyn_cast<CallInst>(&CB)) { if (ORE->enabled()) { - const Function &F = *CI->getParent()->getParent(); - auto &TLI = getAnalysis<TargetLibraryInfoWrapperPass>().getTLI(F); - if (MemoryOpRemark::canHandle(CI, TLI)) { - MemoryOpRemark R(*ORE, "gisel-irtranslator-memsize", *DL, TLI); + if (MemoryOpRemark::canHandle(CI, *LibInfo)) { + MemoryOpRemark R(*ORE, "gisel-irtranslator-memsize", *DL, *LibInfo); R.visit(CI); } } @@ -2403,6 +2411,10 @@ bool IRTranslator::translateCall(const User &U, MachineIRBuilder &MIRBuilder) { if (CI.countOperandBundlesOfType(LLVMContext::OB_cfguardtarget)) return false; + // FIXME: support statepoints and related. + if (isa<GCStatepointInst, GCRelocateInst, GCResultInst>(U)) + return false; + if (CI.isInlineAsm()) return translateInlineAsm(CI, MIRBuilder); @@ -2475,8 +2487,16 @@ bool IRTranslator::translateCall(const User &U, MachineIRBuilder &MIRBuilder) { LLT MemTy = Info.memVT.isSimple() ? getLLTForMVT(Info.memVT.getSimpleVT()) : LLT::scalar(Info.memVT.getStoreSizeInBits()); - MIB.addMemOperand(MF->getMachineMemOperand(MachinePointerInfo(Info.ptrVal), - Info.flags, MemTy, Alignment)); + + // TODO: We currently just fallback to address space 0 if getTgtMemIntrinsic + // didn't yield anything useful. + MachinePointerInfo MPI; + if (Info.ptrVal) + MPI = MachinePointerInfo(Info.ptrVal, Info.offset); + else if (Info.fallbackAddressSpace) + MPI = MachinePointerInfo(*Info.fallbackAddressSpace); + MIB.addMemOperand( + MF->getMachineMemOperand(MPI, Info.flags, MemTy, Alignment, CI.getAAMetadata())); } return true; @@ -2566,14 +2586,12 @@ bool IRTranslator::translateInvoke(const User &U, bool LowerInlineAsm = I.isInlineAsm(); bool NeedEHLabel = true; - // If it can't throw then use a fast-path without emitting EH labels. - if (LowerInlineAsm) - NeedEHLabel = (cast<InlineAsm>(I.getCalledOperand()))->canThrow(); // Emit the actual call, bracketed by EH_LABELs so that the MF knows about // the region covered by the try. MCSymbol *BeginSymbol = nullptr; if (NeedEHLabel) { + MIRBuilder.buildInstr(TargetOpcode::G_INVOKE_REGION_START); BeginSymbol = Context.createTempSymbol(); MIRBuilder.buildInstr(TargetOpcode::EH_LABEL).addSym(BeginSymbol); } @@ -2808,7 +2826,7 @@ bool IRTranslator::translateExtractElement(const User &U, Register Idx; if (auto *CI = dyn_cast<ConstantInt>(U.getOperand(1))) { if (CI->getBitWidth() != PreferredVecIdxWidth) { - APInt NewIdx = CI->getValue().sextOrTrunc(PreferredVecIdxWidth); + APInt NewIdx = CI->getValue().zextOrTrunc(PreferredVecIdxWidth); auto *NewIdxCI = ConstantInt::get(CI->getContext(), NewIdx); Idx = getOrCreateVReg(*NewIdxCI); } @@ -2817,7 +2835,7 @@ bool IRTranslator::translateExtractElement(const User &U, Idx = getOrCreateVReg(*U.getOperand(1)); if (MRI->getType(Idx).getSizeInBits() != PreferredVecIdxWidth) { const LLT VecIdxTy = LLT::scalar(PreferredVecIdxWidth); - Idx = MIRBuilder.buildSExtOrTrunc(VecIdxTy, Idx).getReg(0); + Idx = MIRBuilder.buildZExtOrTrunc(VecIdxTy, Idx).getReg(0); } MIRBuilder.buildExtractVectorElement(Res, Val, Idx); return true; @@ -2934,6 +2952,12 @@ bool IRTranslator::translateAtomicRMW(const User &U, case AtomicRMWInst::FMin: Opcode = TargetOpcode::G_ATOMICRMW_FMIN; break; + case AtomicRMWInst::UIncWrap: + Opcode = TargetOpcode::G_ATOMICRMW_UINC_WRAP; + break; + case AtomicRMWInst::UDecWrap: + Opcode = TargetOpcode::G_ATOMICRMW_UDEC_WRAP; + break; } MIRBuilder.buildAtomicRMW( @@ -3003,6 +3027,7 @@ void IRTranslator::finishPendingPhis() { bool IRTranslator::translate(const Instruction &Inst) { CurBuilder->setDebugLoc(Inst.getDebugLoc()); + CurBuilder->setPCSections(Inst.getMetadata(LLVMContext::MD_pcsections)); auto &TLI = *MF->getSubtarget().getTargetLowering(); if (TLI.fallBackToDAGISel(Inst)) @@ -3393,6 +3418,9 @@ bool IRTranslator::runOnMachineFunction(MachineFunction &CurMF) { FuncInfo.BPI = nullptr; } + AC = &getAnalysis<AssumptionCacheTracker>().getAssumptionCache( + MF->getFunction()); + LibInfo = &getAnalysis<TargetLibraryInfoWrapperPass>().getTLI(F); FuncInfo.CanLowerReturn = CLI->checkReturnTypeForCallConv(*MF); const auto &TLI = *MF->getSubtarget().getTargetLowering(); @@ -3437,7 +3465,7 @@ bool IRTranslator::runOnMachineFunction(MachineFunction &CurMF) { MF->push_back(MBB); if (BB.hasAddressTaken()) - MBB->setHasAddressTaken(); + MBB->setAddressTakenIRBlock(const_cast<BasicBlock *>(&BB)); if (!HasMustTailInVarArgFn) HasMustTailInVarArgFn = checkForMustTailInVarArgFn(IsVarArg, BB); diff --git a/llvm/lib/CodeGen/GlobalISel/InstructionSelect.cpp b/llvm/lib/CodeGen/GlobalISel/InstructionSelect.cpp index 28f3b425c67d..f780050ca3f1 100644 --- a/llvm/lib/CodeGen/GlobalISel/InstructionSelect.cpp +++ b/llvm/lib/CodeGen/GlobalISel/InstructionSelect.cpp @@ -160,6 +160,7 @@ bool InstructionSelect::runOnMachineFunction(MachineFunction &MF) { // If so, erase it. if (isTriviallyDead(MI, MRI)) { LLVM_DEBUG(dbgs() << "Is dead; erasing.\n"); + salvageDebugInfo(MRI, MI); MI.eraseFromParent(); continue; } @@ -183,6 +184,11 @@ bool InstructionSelect::runOnMachineFunction(MachineFunction &MF) { continue; } + if (MI.getOpcode() == TargetOpcode::G_INVOKE_REGION_START) { + MI.eraseFromParent(); + continue; + } + if (!ISel->select(MI)) { // FIXME: It would be nice to dump all inserted instructions. It's // not obvious how, esp. considering select() can insert after MI. @@ -229,8 +235,7 @@ bool InstructionSelect::runOnMachineFunction(MachineFunction &MF) { continue; Register SrcReg = MI.getOperand(1).getReg(); Register DstReg = MI.getOperand(0).getReg(); - if (Register::isVirtualRegister(SrcReg) && - Register::isVirtualRegister(DstReg)) { + if (SrcReg.isVirtual() && DstReg.isVirtual()) { auto SrcRC = MRI.getRegClass(SrcReg); auto DstRC = MRI.getRegClass(DstReg); if (SrcRC == DstRC) { @@ -247,7 +252,7 @@ bool InstructionSelect::runOnMachineFunction(MachineFunction &MF) { // that the size of the now-constrained vreg is unchanged and that it has a // register class. for (unsigned I = 0, E = MRI.getNumVirtRegs(); I != E; ++I) { - unsigned VReg = Register::index2VirtReg(I); + Register VReg = Register::index2VirtReg(I); MachineInstr *MI = nullptr; if (!MRI.def_empty(VReg)) diff --git a/llvm/lib/CodeGen/GlobalISel/LegacyLegalizerInfo.cpp b/llvm/lib/CodeGen/GlobalISel/LegacyLegalizerInfo.cpp index 6271a4514c27..8cfb1b786c24 100644 --- a/llvm/lib/CodeGen/GlobalISel/LegacyLegalizerInfo.cpp +++ b/llvm/lib/CodeGen/GlobalISel/LegacyLegalizerInfo.cpp @@ -264,7 +264,7 @@ LegacyLegalizerInfo::findAction(const SizeAndActionsVec &Vec, const uint32_t Siz // Special case for scalarization: if (Vec == SizeAndActionsVec({{1, FewerElements}})) return {1, FewerElements}; - LLVM_FALLTHROUGH; + [[fallthrough]]; case NarrowScalar: { // The following needs to be a loop, as for now, we do allow needing to // go over "Unsupported" bit sizes before finding a legalizable bit size. diff --git a/llvm/lib/CodeGen/GlobalISel/Legalizer.cpp b/llvm/lib/CodeGen/GlobalISel/Legalizer.cpp index f09e5b7ce783..1a13f39c100c 100644 --- a/llvm/lib/CodeGen/GlobalISel/Legalizer.cpp +++ b/llvm/lib/CodeGen/GlobalISel/Legalizer.cpp @@ -225,6 +225,7 @@ Legalizer::legalizeMachineFunction(MachineFunction &MF, const LegalizerInfo &LI, assert(isPreISelGenericOpcode(MI.getOpcode()) && "Expecting generic opcode"); if (isTriviallyDead(MI, MRI)) { + salvageDebugInfo(MRI, MI); eraseInstr(MI, MRI, &LocObserver); continue; } @@ -272,6 +273,7 @@ Legalizer::legalizeMachineFunction(MachineFunction &MF, const LegalizerInfo &LI, assert(isPreISelGenericOpcode(MI.getOpcode()) && "Expecting generic opcode"); if (isTriviallyDead(MI, MRI)) { + salvageDebugInfo(MRI, MI); eraseInstr(MI, MRI, &LocObserver); continue; } diff --git a/llvm/lib/CodeGen/GlobalISel/LegalizerHelper.cpp b/llvm/lib/CodeGen/GlobalISel/LegalizerHelper.cpp index 52ee13757f27..8a1fce2d3d65 100644 --- a/llvm/lib/CodeGen/GlobalISel/LegalizerHelper.cpp +++ b/llvm/lib/CodeGen/GlobalISel/LegalizerHelper.cpp @@ -33,6 +33,8 @@ #include "llvm/Support/MathExtras.h" #include "llvm/Support/raw_ostream.h" #include "llvm/Target/TargetMachine.h" +#include <numeric> +#include <optional> #define DEBUG_TYPE "legalizer" @@ -233,7 +235,7 @@ void LegalizerHelper::extractVectorParts(Register Reg, unsigned NumElts, // Requested sub-vectors of NarrowTy. for (unsigned i = 0; i < NumNarrowTyPieces; ++i, Offset += NumElts) { ArrayRef<Register> Pieces(&Elts[Offset], NumElts); - VRegs.push_back(MIRBuilder.buildMerge(NarrowTy, Pieces).getReg(0)); + VRegs.push_back(MIRBuilder.buildMergeLikeInstr(NarrowTy, Pieces).getReg(0)); } // Leftover element(s). @@ -242,7 +244,8 @@ void LegalizerHelper::extractVectorParts(Register Reg, unsigned NumElts, } else { LLT LeftoverTy = LLT::fixed_vector(LeftoverNumElts, EltTy); ArrayRef<Register> Pieces(&Elts[Offset], LeftoverNumElts); - VRegs.push_back(MIRBuilder.buildMerge(LeftoverTy, Pieces).getReg(0)); + VRegs.push_back( + MIRBuilder.buildMergeLikeInstr(LeftoverTy, Pieces).getReg(0)); } } @@ -255,7 +258,7 @@ void LegalizerHelper::insertParts(Register DstReg, assert(LeftoverRegs.empty()); if (!ResultTy.isVector()) { - MIRBuilder.buildMerge(DstReg, PartRegs); + MIRBuilder.buildMergeLikeInstr(DstReg, PartRegs); return; } @@ -304,7 +307,7 @@ void LegalizerHelper::mergeMixedSubvectors(Register DstReg, else appendVectorElts(AllElts, Leftover); - MIRBuilder.buildMerge(DstReg, AllElts); + MIRBuilder.buildMergeLikeInstr(DstReg, AllElts); } /// Append the result registers of G_UNMERGE_VALUES \p MI to \p Regs. @@ -421,7 +424,7 @@ LLT LegalizerHelper::buildLCMMergePieces(LLT DstTy, LLT NarrowTy, LLT GCDTy, if (NumSubParts == 1) Remerge[I] = SubMerge[0]; else - Remerge[I] = MIRBuilder.buildMerge(NarrowTy, SubMerge).getReg(0); + Remerge[I] = MIRBuilder.buildMergeLikeInstr(NarrowTy, SubMerge).getReg(0); // In the sign extend padding case, re-use the first all-signbit merge. if (AllMergePartsArePadding && !AllPadReg) @@ -440,11 +443,11 @@ void LegalizerHelper::buildWidenedRemergeToDst(Register DstReg, LLT LCMTy, // the result. if (DstTy == LCMTy) { - MIRBuilder.buildMerge(DstReg, RemergeRegs); + MIRBuilder.buildMergeLikeInstr(DstReg, RemergeRegs); return; } - auto Remerge = MIRBuilder.buildMerge(LCMTy, RemergeRegs); + auto Remerge = MIRBuilder.buildMergeLikeInstr(LCMTy, RemergeRegs); if (DstTy.isScalar() && LCMTy.isScalar()) { MIRBuilder.buildTrunc(DstReg, Remerge); return; @@ -458,7 +461,7 @@ void LegalizerHelper::buildWidenedRemergeToDst(Register DstReg, LLT LCMTy, UnmergeDefs[I] = MRI.createGenericVirtualRegister(DstTy); MIRBuilder.buildUnmerge(UnmergeDefs, - MIRBuilder.buildMerge(LCMTy, RemergeRegs)); + MIRBuilder.buildMergeLikeInstr(LCMTy, RemergeRegs)); return; } @@ -497,6 +500,8 @@ static RTLIB::Libcall getRTLibDesc(unsigned Opcode, unsigned Size) { } while (0) switch (Opcode) { + case TargetOpcode::G_MUL: + RTLIBCASE_INT(MUL_I); case TargetOpcode::G_SDIV: RTLIBCASE_INT(SDIV_I); case TargetOpcode::G_UDIV: @@ -795,6 +800,7 @@ LegalizerHelper::libcall(MachineInstr &MI, LostDebugLocObserver &LocObserver) { switch (MI.getOpcode()) { default: return UnableToLegalize; + case TargetOpcode::G_MUL: case TargetOpcode::G_SDIV: case TargetOpcode::G_UDIV: case TargetOpcode::G_SREM: @@ -936,7 +942,7 @@ LegalizerHelper::LegalizeResult LegalizerHelper::narrowScalar(MachineInstr &MI, if (DstTy.isVector()) MIRBuilder.buildBuildVector(DstReg, DstRegs); else - MIRBuilder.buildMerge(DstReg, DstRegs); + MIRBuilder.buildMergeLikeInstr(DstReg, DstRegs); MI.eraseFromParent(); return Legalized; } @@ -1008,7 +1014,7 @@ LegalizerHelper::LegalizeResult LegalizerHelper::narrowScalar(MachineInstr &MI, MIRBuilder.buildFreeze(NarrowTy, Unmerge.getReg(i)).getReg(0)); } - MIRBuilder.buildMerge(MI.getOperand(0).getReg(), Parts); + MIRBuilder.buildMergeLikeInstr(MI.getOperand(0).getReg(), Parts); MI.eraseFromParent(); return Legalized; } @@ -1169,7 +1175,7 @@ LegalizerHelper::LegalizeResult LegalizerHelper::narrowScalar(MachineInstr &MI, Observer.changingInstr(MI); for (unsigned i = 1; i < MI.getNumOperands(); i += 2) { MachineBasicBlock &OpMBB = *MI.getOperand(i + 1).getMBB(); - MIRBuilder.setInsertPt(OpMBB, OpMBB.getFirstTerminator()); + MIRBuilder.setInsertPt(OpMBB, OpMBB.getFirstTerminatorForward()); extractParts(MI.getOperand(i).getReg(), NarrowTy, NumParts, SrcRegs[i / 2]); } @@ -1183,7 +1189,7 @@ LegalizerHelper::LegalizeResult LegalizerHelper::narrowScalar(MachineInstr &MI, MIB.addUse(SrcRegs[j / 2][i]).add(MI.getOperand(j + 1)); } MIRBuilder.setInsertPt(MBB, MBB.getFirstNonPHI()); - MIRBuilder.buildMerge(MI.getOperand(0), DstRegs); + MIRBuilder.buildMergeLikeInstr(MI.getOperand(0), DstRegs); Observer.changedInstr(MI); MI.eraseFromParent(); return Legalized; @@ -1360,7 +1366,7 @@ LegalizerHelper::LegalizeResult LegalizerHelper::narrowScalar(MachineInstr &MI, // Gather the destination registers into the final destination. Register DstReg = MI.getOperand(0).getReg(); - MIRBuilder.buildMerge(DstReg, DstRegs); + MIRBuilder.buildMergeLikeInstr(DstReg, DstRegs); MI.eraseFromParent(); return Legalized; } @@ -1380,7 +1386,7 @@ LegalizerHelper::LegalizeResult LegalizerHelper::narrowScalar(MachineInstr &MI, DstRegs.push_back(DstPart.getReg(0)); } - MIRBuilder.buildMerge(MI.getOperand(0), DstRegs); + MIRBuilder.buildMergeLikeInstr(MI.getOperand(0), DstRegs); Observer.changedInstr(MI); MI.eraseFromParent(); @@ -1565,7 +1571,7 @@ LegalizerHelper::widenScalarMergeValues(MachineInstr &MI, unsigned TypeIdx, // %9:_(s6) = G_MERGE_VALUES %6, %7, %7 // %10:_(s12) = G_MERGE_VALUES %8, %9 - const int GCD = greatestCommonDivisor(SrcSize, WideSize); + const int GCD = std::gcd(SrcSize, WideSize); LLT GCDTy = LLT::scalar(GCD); SmallVector<Register, 8> Parts; @@ -1597,16 +1603,17 @@ LegalizerHelper::widenScalarMergeValues(MachineInstr &MI, unsigned TypeIdx, // Build merges of each piece. ArrayRef<Register> Slicer(Unmerges); for (int I = 0; I != NumMerge; ++I, Slicer = Slicer.drop_front(PartsPerGCD)) { - auto Merge = MIRBuilder.buildMerge(WideTy, Slicer.take_front(PartsPerGCD)); + auto Merge = + MIRBuilder.buildMergeLikeInstr(WideTy, Slicer.take_front(PartsPerGCD)); NewMergeRegs.push_back(Merge.getReg(0)); } // A truncate may be necessary if the requested type doesn't evenly divide the // original result type. if (DstTy.getSizeInBits() == WideDstTy.getSizeInBits()) { - MIRBuilder.buildMerge(DstReg, NewMergeRegs); + MIRBuilder.buildMergeLikeInstr(DstReg, NewMergeRegs); } else { - auto FinalMerge = MIRBuilder.buildMerge(WideDstTy, NewMergeRegs); + auto FinalMerge = MIRBuilder.buildMergeLikeInstr(WideDstTy, NewMergeRegs); MIRBuilder.buildTrunc(DstReg, FinalMerge.getReg(0)); } @@ -1734,7 +1741,7 @@ LegalizerHelper::widenScalarUnmergeValues(MachineInstr &MI, unsigned TypeIdx, RemergeParts.emplace_back(Parts[Idx]); } - MIRBuilder.buildMerge(MI.getOperand(I).getReg(), RemergeParts); + MIRBuilder.buildMergeLikeInstr(MI.getOperand(I).getReg(), RemergeParts); RemergeParts.clear(); } } @@ -1838,7 +1845,7 @@ LegalizerHelper::widenScalarAddSubOverflow(MachineInstr &MI, unsigned TypeIdx, LLT WideTy) { unsigned Opcode; unsigned ExtOpcode; - Optional<Register> CarryIn = None; + std::optional<Register> CarryIn; switch (MI.getOpcode()) { default: llvm_unreachable("Unexpected opcode!"); @@ -1884,9 +1891,9 @@ LegalizerHelper::widenScalarAddSubOverflow(MachineInstr &MI, unsigned TypeIdx, unsigned BoolExtOp = MIRBuilder.getBoolExtOp(WideTy.isVector(), false); Observer.changingInstr(MI); - widenScalarDst(MI, WideTy, 1); if (CarryIn) widenScalarSrc(MI, WideTy, 4, BoolExtOp); + widenScalarDst(MI, WideTy, 1); Observer.changedInstr(MI); return Legalized; @@ -2454,7 +2461,7 @@ LegalizerHelper::widenScalar(MachineInstr &MI, unsigned TypeIdx, LLT WideTy) { Observer.changingInstr(MI); for (unsigned I = 1; I < MI.getNumOperands(); I += 2) { MachineBasicBlock &OpMBB = *MI.getOperand(I + 1).getMBB(); - MIRBuilder.setInsertPt(OpMBB, OpMBB.getFirstTerminator()); + MIRBuilder.setInsertPt(OpMBB, OpMBB.getFirstTerminatorForward()); widenScalarSrc(MI, WideTy, I, TargetOpcode::G_ANYEXT); } @@ -2675,7 +2682,7 @@ LegalizerHelper::lowerBitcast(MachineInstr &MI) { } else getUnmergePieces(SrcRegs, MIRBuilder, Src, SrcEltTy); - MIRBuilder.buildMerge(Dst, SrcRegs); + MIRBuilder.buildMergeLikeInstr(Dst, SrcRegs); MI.eraseFromParent(); return Legalized; } @@ -2683,7 +2690,7 @@ LegalizerHelper::lowerBitcast(MachineInstr &MI) { if (DstTy.isVector()) { SmallVector<Register, 8> SrcRegs; getUnmergePieces(SrcRegs, MIRBuilder, Src, DstTy.getElementType()); - MIRBuilder.buildMerge(Dst, SrcRegs); + MIRBuilder.buildMergeLikeInstr(Dst, SrcRegs); MI.eraseFromParent(); return Legalized; } @@ -3315,7 +3322,8 @@ LegalizerHelper::lower(MachineInstr &MI, unsigned TypeIdx, LLT LowerHintTy) { MI.eraseFromParent(); return Legalized; } - case TargetOpcode::G_FSUB: { + case TargetOpcode::G_FSUB: + case TargetOpcode::G_STRICT_FSUB: { Register Res = MI.getOperand(0).getReg(); LLT Ty = MRI.getType(Res); @@ -3326,9 +3334,13 @@ LegalizerHelper::lower(MachineInstr &MI, unsigned TypeIdx, LLT LowerHintTy) { return UnableToLegalize; Register LHS = MI.getOperand(1).getReg(); Register RHS = MI.getOperand(2).getReg(); - Register Neg = MRI.createGenericVirtualRegister(Ty); - MIRBuilder.buildFNeg(Neg, RHS); - MIRBuilder.buildFAdd(Res, LHS, Neg, MI.getFlags()); + auto Neg = MIRBuilder.buildFNeg(Ty, RHS); + + if (MI.getOpcode() == TargetOpcode::G_STRICT_FSUB) + MIRBuilder.buildStrictFAdd(Res, LHS, Neg, MI.getFlags()); + else + MIRBuilder.buildFAdd(Res, LHS, Neg, MI.getFlags()); + MI.eraseFromParent(); return Legalized; } @@ -3515,6 +3527,8 @@ LegalizerHelper::lower(MachineInstr &MI, unsigned TypeIdx, LLT LowerHintTy) { return lowerAbsToAddXor(MI); case G_SELECT: return lowerSelect(MI); + case G_IS_FPCLASS: + return lowerISFPCLASS(MI); case G_SDIVREM: case G_UDIVREM: return lowerDIVREM(MI); @@ -3748,7 +3762,7 @@ LegalizerHelper::fewerElementsVectorMultiEltType( mergeMixedSubvectors(MI.getReg(i), OutputRegs[i]); } else { for (unsigned i = 0; i < NumDefs; ++i) - MIRBuilder.buildMerge(MI.getReg(i), OutputRegs[i]); + MIRBuilder.buildMergeLikeInstr(MI.getReg(i), OutputRegs[i]); } MI.eraseFromParent(); @@ -3773,7 +3787,7 @@ LegalizerHelper::fewerElementsVectorPhi(GenericMachineInstr &MI, for (unsigned UseIdx = NumDefs, UseNo = 0; UseIdx < MI.getNumOperands(); UseIdx += 2, ++UseNo) { MachineBasicBlock &OpMBB = *MI.getOperand(UseIdx + 1).getMBB(); - MIRBuilder.setInsertPt(OpMBB, OpMBB.getFirstTerminator()); + MIRBuilder.setInsertPt(OpMBB, OpMBB.getFirstTerminatorForward()); extractVectorParts(MI.getReg(UseIdx), NumElts, InputOpsPieces[UseNo]); } @@ -3796,7 +3810,7 @@ LegalizerHelper::fewerElementsVectorPhi(GenericMachineInstr &MI, if (NumLeftovers) { mergeMixedSubvectors(MI.getReg(0), OutputRegs); } else { - MIRBuilder.buildMerge(MI.getReg(0), OutputRegs); + MIRBuilder.buildMergeLikeInstr(MI.getReg(0), OutputRegs); } MI.eraseFromParent(); @@ -3899,10 +3913,11 @@ LegalizerHelper::fewerElementsVectorMerge(MachineInstr &MI, unsigned TypeIdx, for (unsigned i = 0, Offset = 0; i < NumNarrowTyPieces; ++i, Offset += NumNarrowTyElts) { ArrayRef<Register> Pieces(&Elts[Offset], NumNarrowTyElts); - NarrowTyElts.push_back(MIRBuilder.buildMerge(NarrowTy, Pieces).getReg(0)); + NarrowTyElts.push_back( + MIRBuilder.buildMergeLikeInstr(NarrowTy, Pieces).getReg(0)); } - MIRBuilder.buildMerge(DstReg, NarrowTyElts); + MIRBuilder.buildMergeLikeInstr(DstReg, NarrowTyElts); MI.eraseFromParent(); return Legalized; } @@ -3930,10 +3945,11 @@ LegalizerHelper::fewerElementsVectorMerge(MachineInstr &MI, unsigned TypeIdx, SmallVector<Register, 8> Sources; for (unsigned j = 0; j < NumElts; ++j) Sources.push_back(MI.getOperand(1 + i * NumElts + j).getReg()); - NarrowTyElts.push_back(MIRBuilder.buildMerge(NarrowTy, Sources).getReg(0)); + NarrowTyElts.push_back( + MIRBuilder.buildMergeLikeInstr(NarrowTy, Sources).getReg(0)); } - MIRBuilder.buildMerge(DstReg, NarrowTyElts); + MIRBuilder.buildMergeLikeInstr(DstReg, NarrowTyElts); MI.eraseFromParent(); return Legalized; } @@ -4214,10 +4230,16 @@ LegalizerHelper::fewerElementsVector(MachineInstr &MI, unsigned TypeIdx, case G_SSUBO: case G_SADDE: case G_SSUBE: + case G_STRICT_FADD: + case G_STRICT_FSUB: + case G_STRICT_FMUL: + case G_STRICT_FMA: return fewerElementsVectorMultiEltType(GMI, NumElts); case G_ICMP: case G_FCMP: return fewerElementsVectorMultiEltType(GMI, NumElts, {1 /*cpm predicate*/}); + case G_IS_FPCLASS: + return fewerElementsVectorMultiEltType(GMI, NumElts, {2, 3 /*mask,fpsem*/}); case G_SELECT: if (MRI.getType(MI.getOperand(1).getReg()).isVector()) return fewerElementsVectorMultiEltType(GMI, NumElts); @@ -4307,7 +4329,7 @@ LegalizerHelper::LegalizeResult LegalizerHelper::fewerElementsVectorShuffle( // The input vector this mask element indexes into. unsigned Input = (unsigned)Idx / NewElts; - if (Input >= array_lengthof(Inputs)) { + if (Input >= std::size(Inputs)) { // The mask element does not index into any input vector. Ops.push_back(-1); continue; @@ -4318,7 +4340,7 @@ LegalizerHelper::LegalizeResult LegalizerHelper::fewerElementsVectorShuffle( // Find or create a shuffle vector operand to hold this input. unsigned OpNo; - for (OpNo = 0; OpNo < array_lengthof(InputUsed); ++OpNo) { + for (OpNo = 0; OpNo < std::size(InputUsed); ++OpNo) { if (InputUsed[OpNo] == Input) { // This input vector is already an operand. break; @@ -4329,7 +4351,7 @@ LegalizerHelper::LegalizeResult LegalizerHelper::fewerElementsVectorShuffle( } } - if (OpNo >= array_lengthof(InputUsed)) { + if (OpNo >= std::size(InputUsed)) { // More than two input vectors used! Give up on trying to create a // shuffle vector. Insert all elements into a BUILD_VECTOR instead. UseBuildVector = true; @@ -4352,7 +4374,7 @@ LegalizerHelper::LegalizeResult LegalizerHelper::fewerElementsVectorShuffle( // The input vector this mask element indexes into. unsigned Input = (unsigned)Idx / NewElts; - if (Input >= array_lengthof(Inputs)) { + if (Input >= std::size(Inputs)) { // The mask element is "undef" or indexes off the end of the input. SVOps.push_back(MIRBuilder.buildUndef(EltTy).getReg(0)); continue; @@ -4570,7 +4592,7 @@ LegalizerHelper::narrowScalarShiftByConstant(MachineInstr &MI, const APInt &Amt, MIRBuilder.buildUnmerge({InL, InH}, MI.getOperand(1)); if (Amt.isZero()) { - MIRBuilder.buildMerge(MI.getOperand(0), {InL, InH}); + MIRBuilder.buildMergeLikeInstr(MI.getOperand(0), {InL, InH}); MI.eraseFromParent(); return Legalized; } @@ -4643,7 +4665,7 @@ LegalizerHelper::narrowScalarShiftByConstant(MachineInstr &MI, const APInt &Amt, } } - MIRBuilder.buildMerge(MI.getOperand(0), {Lo, Hi}); + MIRBuilder.buildMergeLikeInstr(MI.getOperand(0), {Lo, Hi}); MI.eraseFromParent(); return Legalized; @@ -4754,7 +4776,7 @@ LegalizerHelper::narrowScalarShift(MachineInstr &MI, unsigned TypeIdx, llvm_unreachable("not a shift"); } - MIRBuilder.buildMerge(DstReg, ResultRegs); + MIRBuilder.buildMergeLikeInstr(DstReg, ResultRegs); MI.eraseFromParent(); return Legalized; } @@ -4820,7 +4842,10 @@ LegalizerHelper::moreElementsVector(MachineInstr &MI, unsigned TypeIdx, case TargetOpcode::G_FMINNUM_IEEE: case TargetOpcode::G_FMAXNUM_IEEE: case TargetOpcode::G_FMINIMUM: - case TargetOpcode::G_FMAXIMUM: { + case TargetOpcode::G_FMAXIMUM: + case TargetOpcode::G_STRICT_FADD: + case TargetOpcode::G_STRICT_FSUB: + case TargetOpcode::G_STRICT_FMUL: { Observer.changingInstr(MI); moreElementsVectorSrc(MI, MoreTy, 1); moreElementsVectorSrc(MI, MoreTy, 2); @@ -4829,6 +4854,7 @@ LegalizerHelper::moreElementsVector(MachineInstr &MI, unsigned TypeIdx, return Legalized; } case TargetOpcode::G_FMA: + case TargetOpcode::G_STRICT_FMA: case TargetOpcode::G_FSHR: case TargetOpcode::G_FSHL: { Observer.changingInstr(MI); @@ -4922,12 +4948,72 @@ LegalizerHelper::moreElementsVector(MachineInstr &MI, unsigned TypeIdx, } } +/// Expand source vectors to the size of destination vector. +static LegalizerHelper::LegalizeResult +equalizeVectorShuffleLengths(MachineInstr &MI, MachineIRBuilder &MIRBuilder) { + MachineRegisterInfo &MRI = *MIRBuilder.getMRI(); + + LLT DstTy = MRI.getType(MI.getOperand(0).getReg()); + LLT SrcTy = MRI.getType(MI.getOperand(1).getReg()); + ArrayRef<int> Mask = MI.getOperand(3).getShuffleMask(); + unsigned MaskNumElts = Mask.size(); + unsigned SrcNumElts = SrcTy.getNumElements(); + Register DstReg = MI.getOperand(0).getReg(); + LLT DestEltTy = DstTy.getElementType(); + + // TODO: Normalize the shuffle vector since mask and vector length don't + // match. + if (MaskNumElts <= SrcNumElts) { + return LegalizerHelper::LegalizeResult::UnableToLegalize; + } + + unsigned PaddedMaskNumElts = alignTo(MaskNumElts, SrcNumElts); + unsigned NumConcat = PaddedMaskNumElts / SrcNumElts; + LLT PaddedTy = LLT::fixed_vector(PaddedMaskNumElts, DestEltTy); + + // Create new source vectors by concatenating the initial + // source vectors with undefined vectors of the same size. + auto Undef = MIRBuilder.buildUndef(SrcTy); + SmallVector<Register, 8> MOps1(NumConcat, Undef.getReg(0)); + SmallVector<Register, 8> MOps2(NumConcat, Undef.getReg(0)); + MOps1[0] = MI.getOperand(1).getReg(); + MOps2[0] = MI.getOperand(2).getReg(); + + auto Src1 = MIRBuilder.buildConcatVectors(PaddedTy, MOps1); + auto Src2 = MIRBuilder.buildConcatVectors(PaddedTy, MOps2); + + // Readjust mask for new input vector length. + SmallVector<int, 8> MappedOps(PaddedMaskNumElts, -1); + for (unsigned I = 0; I != MaskNumElts; ++I) { + int Idx = Mask[I]; + if (Idx >= static_cast<int>(SrcNumElts)) + Idx += PaddedMaskNumElts - SrcNumElts; + MappedOps[I] = Idx; + } + + // If we got more elements than required, extract subvector. + if (MaskNumElts != PaddedMaskNumElts) { + auto Shuffle = + MIRBuilder.buildShuffleVector(PaddedTy, Src1, Src2, MappedOps); + + SmallVector<Register, 16> Elts(MaskNumElts); + for (unsigned I = 0; I < MaskNumElts; ++I) { + Elts[I] = + MIRBuilder.buildExtractVectorElementConstant(DestEltTy, Shuffle, I) + .getReg(0); + } + MIRBuilder.buildBuildVector(DstReg, Elts); + } else { + MIRBuilder.buildShuffleVector(DstReg, Src1, Src2, MappedOps); + } + + MI.eraseFromParent(); + return LegalizerHelper::LegalizeResult::Legalized; +} + LegalizerHelper::LegalizeResult LegalizerHelper::moreElementsVectorShuffle(MachineInstr &MI, unsigned int TypeIdx, LLT MoreTy) { - if (TypeIdx != 0) - return UnableToLegalize; - Register DstReg = MI.getOperand(0).getReg(); Register Src1Reg = MI.getOperand(1).getReg(); Register Src2Reg = MI.getOperand(2).getReg(); @@ -4938,6 +5024,14 @@ LegalizerHelper::moreElementsVectorShuffle(MachineInstr &MI, unsigned NumElts = DstTy.getNumElements(); unsigned WidenNumElts = MoreTy.getNumElements(); + if (DstTy.isVector() && Src1Ty.isVector() && + DstTy.getNumElements() > Src1Ty.getNumElements()) { + return equalizeVectorShuffleLengths(MI, MIRBuilder); + } + + if (TypeIdx != 0) + return UnableToLegalize; + // Expect a canonicalized shuffle. if (DstTy != Src1Ty || DstTy != Src2Ty) return UnableToLegalize; @@ -5115,8 +5209,8 @@ LegalizerHelper::narrowScalarAddSub(MachineInstr &MI, unsigned TypeIdx, CarryIn = CarryOut; } insertParts(MI.getOperand(0).getReg(), RegTy, NarrowTy, - makeArrayRef(DstRegs).take_front(NarrowParts), LeftoverTy, - makeArrayRef(DstRegs).drop_front(NarrowParts)); + ArrayRef(DstRegs).take_front(NarrowParts), LeftoverTy, + ArrayRef(DstRegs).drop_front(NarrowParts)); MI.eraseFromParent(); return Legalized; @@ -5149,7 +5243,7 @@ LegalizerHelper::narrowScalarMul(MachineInstr &MI, LLT NarrowTy) { // Take only high half of registers if this is high mul. ArrayRef<Register> DstRegs(&DstTmpRegs[DstTmpParts - NumParts], NumParts); - MIRBuilder.buildMerge(DstReg, DstRegs); + MIRBuilder.buildMergeLikeInstr(DstReg, DstRegs); MI.eraseFromParent(); return Legalized; } @@ -5239,7 +5333,7 @@ LegalizerHelper::narrowScalarExtract(MachineInstr &MI, unsigned TypeIdx, if (MRI.getType(DstReg).isVector()) MIRBuilder.buildBuildVector(DstReg, DstRegs); else if (DstRegs.size() > 1) - MIRBuilder.buildMerge(DstReg, DstRegs); + MIRBuilder.buildMergeLikeInstr(DstReg, DstRegs); else MIRBuilder.buildCopy(DstReg, DstRegs[0]); MI.eraseFromParent(); @@ -5321,10 +5415,10 @@ LegalizerHelper::narrowScalarInsert(MachineInstr &MI, unsigned TypeIdx, Register DstReg = MI.getOperand(0).getReg(); if (WideSize > RegTy.getSizeInBits()) { Register MergeReg = MRI.createGenericVirtualRegister(LLT::scalar(WideSize)); - MIRBuilder.buildMerge(MergeReg, DstRegs); + MIRBuilder.buildMergeLikeInstr(MergeReg, DstRegs); MIRBuilder.buildTrunc(DstReg, MergeReg); } else - MIRBuilder.buildMerge(DstReg, DstRegs); + MIRBuilder.buildMergeLikeInstr(DstReg, DstRegs); MI.eraseFromParent(); return Legalized; @@ -6582,7 +6676,7 @@ LegalizerHelper::lowerExtractInsertVectorElt(MachineInstr &MI) { if (InsertVal) { SrcRegs[IdxVal] = MI.getOperand(2).getReg(); - MIRBuilder.buildMerge(DstReg, SrcRegs); + MIRBuilder.buildMergeLikeInstr(DstReg, SrcRegs); } else { MIRBuilder.buildCopy(DstReg, SrcRegs[IdxVal]); } @@ -6754,7 +6848,7 @@ LegalizerHelper::lowerExtract(MachineInstr &MI) { if (SubVectorElts.size() == 1) MIRBuilder.buildCopy(Dst, SubVectorElts[0]); else - MIRBuilder.buildMerge(Dst, SubVectorElts); + MIRBuilder.buildMergeLikeInstr(Dst, SubVectorElts); MI.eraseFromParent(); return Legalized; @@ -6827,7 +6921,7 @@ LegalizerHelper::LegalizeResult LegalizerHelper::lowerInsert(MachineInstr &MI) { DstElts.push_back(UnmergeSrc.getReg(Idx)); } - MIRBuilder.buildMerge(Dst, DstElts); + MIRBuilder.buildMergeLikeInstr(Dst, DstElts); MI.eraseFromParent(); return Legalized; } @@ -7216,6 +7310,166 @@ LegalizerHelper::lowerSMULH_UMULH(MachineInstr &MI) { return Legalized; } +LegalizerHelper::LegalizeResult +LegalizerHelper::lowerISFPCLASS(MachineInstr &MI) { + Register DstReg = MI.getOperand(0).getReg(); + Register SrcReg = MI.getOperand(1).getReg(); + LLT DstTy = MRI.getType(DstReg); + LLT SrcTy = MRI.getType(SrcReg); + uint64_t Mask = MI.getOperand(2).getImm(); + + if (Mask == 0) { + MIRBuilder.buildConstant(DstReg, 0); + MI.eraseFromParent(); + return Legalized; + } + if ((Mask & fcAllFlags) == fcAllFlags) { + MIRBuilder.buildConstant(DstReg, 1); + MI.eraseFromParent(); + return Legalized; + } + + unsigned BitSize = SrcTy.getScalarSizeInBits(); + const fltSemantics &Semantics = getFltSemanticForLLT(SrcTy.getScalarType()); + + LLT IntTy = LLT::scalar(BitSize); + if (SrcTy.isVector()) + IntTy = LLT::vector(SrcTy.getElementCount(), IntTy); + auto AsInt = MIRBuilder.buildCopy(IntTy, SrcReg); + + // Various masks. + APInt SignBit = APInt::getSignMask(BitSize); + APInt ValueMask = APInt::getSignedMaxValue(BitSize); // All bits but sign. + APInt Inf = APFloat::getInf(Semantics).bitcastToAPInt(); // Exp and int bit. + APInt ExpMask = Inf; + APInt AllOneMantissa = APFloat::getLargest(Semantics).bitcastToAPInt() & ~Inf; + APInt QNaNBitMask = + APInt::getOneBitSet(BitSize, AllOneMantissa.getActiveBits() - 1); + APInt InvertionMask = APInt::getAllOnesValue(DstTy.getScalarSizeInBits()); + + auto SignBitC = MIRBuilder.buildConstant(IntTy, SignBit); + auto ValueMaskC = MIRBuilder.buildConstant(IntTy, ValueMask); + auto InfC = MIRBuilder.buildConstant(IntTy, Inf); + auto ExpMaskC = MIRBuilder.buildConstant(IntTy, ExpMask); + auto ZeroC = MIRBuilder.buildConstant(IntTy, 0); + + auto Abs = MIRBuilder.buildAnd(IntTy, AsInt, ValueMaskC); + auto Sign = + MIRBuilder.buildICmp(CmpInst::Predicate::ICMP_NE, DstTy, AsInt, Abs); + + auto Res = MIRBuilder.buildConstant(DstTy, 0); + const auto appendToRes = [&](MachineInstrBuilder ToAppend) { + Res = MIRBuilder.buildOr(DstTy, Res, ToAppend); + }; + + // Tests that involve more than one class should be processed first. + if ((Mask & fcFinite) == fcFinite) { + // finite(V) ==> abs(V) u< exp_mask + appendToRes(MIRBuilder.buildICmp(CmpInst::Predicate::ICMP_ULT, DstTy, Abs, + ExpMaskC)); + Mask &= ~fcFinite; + } else if ((Mask & fcFinite) == fcPosFinite) { + // finite(V) && V > 0 ==> V u< exp_mask + appendToRes(MIRBuilder.buildICmp(CmpInst::Predicate::ICMP_ULT, DstTy, AsInt, + ExpMaskC)); + Mask &= ~fcPosFinite; + } else if ((Mask & fcFinite) == fcNegFinite) { + // finite(V) && V < 0 ==> abs(V) u< exp_mask && signbit == 1 + auto Cmp = MIRBuilder.buildICmp(CmpInst::Predicate::ICMP_ULT, DstTy, Abs, + ExpMaskC); + auto And = MIRBuilder.buildAnd(DstTy, Cmp, Sign); + appendToRes(And); + Mask &= ~fcNegFinite; + } + + // Check for individual classes. + if (unsigned PartialCheck = Mask & fcZero) { + if (PartialCheck == fcPosZero) + appendToRes(MIRBuilder.buildICmp(CmpInst::Predicate::ICMP_EQ, DstTy, + AsInt, ZeroC)); + else if (PartialCheck == fcZero) + appendToRes( + MIRBuilder.buildICmp(CmpInst::Predicate::ICMP_EQ, DstTy, Abs, ZeroC)); + else // fcNegZero + appendToRes(MIRBuilder.buildICmp(CmpInst::Predicate::ICMP_EQ, DstTy, + AsInt, SignBitC)); + } + + if (unsigned PartialCheck = Mask & fcInf) { + if (PartialCheck == fcPosInf) + appendToRes(MIRBuilder.buildICmp(CmpInst::Predicate::ICMP_EQ, DstTy, + AsInt, InfC)); + else if (PartialCheck == fcInf) + appendToRes( + MIRBuilder.buildICmp(CmpInst::Predicate::ICMP_EQ, DstTy, Abs, InfC)); + else { // fcNegInf + APInt NegInf = APFloat::getInf(Semantics, true).bitcastToAPInt(); + auto NegInfC = MIRBuilder.buildConstant(IntTy, NegInf); + appendToRes(MIRBuilder.buildICmp(CmpInst::Predicate::ICMP_EQ, DstTy, + AsInt, NegInfC)); + } + } + + if (unsigned PartialCheck = Mask & fcNan) { + auto InfWithQnanBitC = MIRBuilder.buildConstant(IntTy, Inf | QNaNBitMask); + if (PartialCheck == fcNan) { + // isnan(V) ==> abs(V) u> int(inf) + appendToRes( + MIRBuilder.buildICmp(CmpInst::Predicate::ICMP_UGT, DstTy, Abs, InfC)); + } else if (PartialCheck == fcQNan) { + // isquiet(V) ==> abs(V) u>= (unsigned(Inf) | quiet_bit) + appendToRes(MIRBuilder.buildICmp(CmpInst::Predicate::ICMP_UGE, DstTy, Abs, + InfWithQnanBitC)); + } else { // fcSNan + // issignaling(V) ==> abs(V) u> unsigned(Inf) && + // abs(V) u< (unsigned(Inf) | quiet_bit) + auto IsNan = + MIRBuilder.buildICmp(CmpInst::Predicate::ICMP_UGT, DstTy, Abs, InfC); + auto IsNotQnan = MIRBuilder.buildICmp(CmpInst::Predicate::ICMP_ULT, DstTy, + Abs, InfWithQnanBitC); + appendToRes(MIRBuilder.buildAnd(DstTy, IsNan, IsNotQnan)); + } + } + + if (unsigned PartialCheck = Mask & fcSubnormal) { + // issubnormal(V) ==> unsigned(abs(V) - 1) u< (all mantissa bits set) + // issubnormal(V) && V>0 ==> unsigned(V - 1) u< (all mantissa bits set) + auto V = (PartialCheck == fcPosSubnormal) ? AsInt : Abs; + auto OneC = MIRBuilder.buildConstant(IntTy, 1); + auto VMinusOne = MIRBuilder.buildSub(IntTy, V, OneC); + auto SubnormalRes = + MIRBuilder.buildICmp(CmpInst::Predicate::ICMP_ULT, DstTy, VMinusOne, + MIRBuilder.buildConstant(IntTy, AllOneMantissa)); + if (PartialCheck == fcNegSubnormal) + SubnormalRes = MIRBuilder.buildAnd(DstTy, SubnormalRes, Sign); + appendToRes(SubnormalRes); + } + + if (unsigned PartialCheck = Mask & fcNormal) { + // isnormal(V) ==> (0 u< exp u< max_exp) ==> (unsigned(exp-1) u< + // (max_exp-1)) + APInt ExpLSB = ExpMask & ~(ExpMask.shl(1)); + auto ExpMinusOne = MIRBuilder.buildSub( + IntTy, Abs, MIRBuilder.buildConstant(IntTy, ExpLSB)); + APInt MaxExpMinusOne = ExpMask - ExpLSB; + auto NormalRes = + MIRBuilder.buildICmp(CmpInst::Predicate::ICMP_ULT, DstTy, ExpMinusOne, + MIRBuilder.buildConstant(IntTy, MaxExpMinusOne)); + if (PartialCheck == fcNegNormal) + NormalRes = MIRBuilder.buildAnd(DstTy, NormalRes, Sign); + else if (PartialCheck == fcPosNormal) { + auto PosSign = MIRBuilder.buildXor( + DstTy, Sign, MIRBuilder.buildConstant(DstTy, InvertionMask)); + NormalRes = MIRBuilder.buildAnd(DstTy, NormalRes, PosSign); + } + appendToRes(NormalRes); + } + + MIRBuilder.buildCopy(DstReg, Res); + MI.eraseFromParent(); + return Legalized; +} + LegalizerHelper::LegalizeResult LegalizerHelper::lowerSelect(MachineInstr &MI) { // Implement vector G_SELECT in terms of XOR, AND, OR. Register DstReg = MI.getOperand(0).getReg(); @@ -7227,6 +7481,15 @@ LegalizerHelper::LegalizeResult LegalizerHelper::lowerSelect(MachineInstr &MI) { if (!DstTy.isVector()) return UnableToLegalize; + bool IsEltPtr = DstTy.getElementType().isPointer(); + if (IsEltPtr) { + LLT ScalarPtrTy = LLT::scalar(DstTy.getScalarSizeInBits()); + LLT NewTy = DstTy.changeElementType(ScalarPtrTy); + Op1Reg = MIRBuilder.buildPtrToInt(NewTy, Op1Reg).getReg(0); + Op2Reg = MIRBuilder.buildPtrToInt(NewTy, Op2Reg).getReg(0); + DstTy = NewTy; + } + if (MaskTy.isScalar()) { // Turn the scalar condition into a vector condition mask. @@ -7234,10 +7497,8 @@ LegalizerHelper::LegalizeResult LegalizerHelper::lowerSelect(MachineInstr &MI) { // The condition was potentially zero extended before, but we want a sign // extended boolean. - if (MaskTy.getSizeInBits() <= DstTy.getScalarSizeInBits() && - MaskTy != LLT::scalar(1)) { + if (MaskTy != LLT::scalar(1)) MaskElt = MIRBuilder.buildSExtInReg(MaskTy, MaskElt, 1).getReg(0); - } // Continue the sign extension (or truncate) to match the data type. MaskElt = MIRBuilder.buildSExtOrTrunc(DstTy.getElementType(), @@ -7256,7 +7517,12 @@ LegalizerHelper::LegalizeResult LegalizerHelper::lowerSelect(MachineInstr &MI) { auto NotMask = MIRBuilder.buildNot(MaskTy, MaskReg); auto NewOp1 = MIRBuilder.buildAnd(MaskTy, Op1Reg, MaskReg); auto NewOp2 = MIRBuilder.buildAnd(MaskTy, Op2Reg, NotMask); - MIRBuilder.buildOr(DstReg, NewOp1, NewOp2); + if (IsEltPtr) { + auto Or = MIRBuilder.buildOr(DstTy, NewOp1, NewOp2); + MIRBuilder.buildIntToPtr(DstReg, Or); + } else { + MIRBuilder.buildOr(DstReg, NewOp1, NewOp2); + } MI.eraseFromParent(); return Legalized; } @@ -7378,7 +7644,7 @@ static bool findGISelOptimalMemOpLowering(std::vector<LLT> &MemOps, // If the new LLT cannot cover all of the remaining bits, then consider // issuing a (or a pair of) unaligned and overlapping load / store. - bool Fast; + unsigned Fast; // Need to get a VT equivalent for allowMisalignedMemoryAccesses(). MVT VT = getMVTForLLT(Ty); if (NumMemOps && Op.allowOverlap() && NewTySize < Size && diff --git a/llvm/lib/CodeGen/GlobalISel/LegalizerInfo.cpp b/llvm/lib/CodeGen/GlobalISel/LegalizerInfo.cpp index 6adb7ddb5b66..4b6c3a156709 100644 --- a/llvm/lib/CodeGen/GlobalISel/LegalizerInfo.cpp +++ b/llvm/lib/CodeGen/GlobalISel/LegalizerInfo.cpp @@ -126,7 +126,7 @@ static bool mutationIsSane(const LegalizeRule &Rule, case FewerElements: if (!OldTy.isVector()) return false; - LLVM_FALLTHROUGH; + [[fallthrough]]; case MoreElements: { // MoreElements can go from scalar to vector. const ElementCount OldElts = OldTy.isVector() ? @@ -296,7 +296,7 @@ LegalizeRuleSet &LegalizerInfo::getActionDefinitionsBuilder( std::initializer_list<unsigned> Opcodes) { unsigned Representative = *Opcodes.begin(); - assert(!llvm::empty(Opcodes) && Opcodes.begin() + 1 != Opcodes.end() && + assert(Opcodes.size() >= 2 && "Initializer list must have at least two opcodes"); for (unsigned Op : llvm::drop_begin(Opcodes)) @@ -330,7 +330,7 @@ LegalizerInfo::getAction(const MachineInstr &MI, const MachineRegisterInfo &MRI) const { SmallVector<LLT, 8> Types; SmallBitVector SeenTypes(8); - const MCOperandInfo *OpInfo = MI.getDesc().OpInfo; + ArrayRef<MCOperandInfo> OpInfo = MI.getDesc().operands(); // FIXME: probably we'll need to cache the results here somehow? for (unsigned i = 0; i < MI.getDesc().getNumOperands(); ++i) { if (!OpInfo[i].isGenericType()) @@ -379,14 +379,14 @@ void LegalizerInfo::verify(const MCInstrInfo &MII) const { for (unsigned Opcode = FirstOp; Opcode <= LastOp; ++Opcode) { const MCInstrDesc &MCID = MII.get(Opcode); const unsigned NumTypeIdxs = std::accumulate( - MCID.opInfo_begin(), MCID.opInfo_end(), 0U, + MCID.operands().begin(), MCID.operands().end(), 0U, [](unsigned Acc, const MCOperandInfo &OpInfo) { return OpInfo.isGenericType() ? std::max(OpInfo.getGenericTypeIndex() + 1U, Acc) : Acc; }); const unsigned NumImmIdxs = std::accumulate( - MCID.opInfo_begin(), MCID.opInfo_end(), 0U, + MCID.operands().begin(), MCID.operands().end(), 0U, [](unsigned Acc, const MCOperandInfo &OpInfo) { return OpInfo.isGenericImm() ? std::max(OpInfo.getGenericImmIndex() + 1U, Acc) diff --git a/llvm/lib/CodeGen/GlobalISel/LoadStoreOpt.cpp b/llvm/lib/CodeGen/GlobalISel/LoadStoreOpt.cpp index be1bc865d1e1..7c6eac8c8ce0 100644 --- a/llvm/lib/CodeGen/GlobalISel/LoadStoreOpt.cpp +++ b/llvm/lib/CodeGen/GlobalISel/LoadStoreOpt.cpp @@ -306,7 +306,7 @@ bool LoadStoreOpt::mergeStores(SmallVectorImpl<GStore *> &StoresToMerge) { bool AnyMerged = false; do { unsigned NumPow2 = PowerOf2Floor(StoresToMerge.size()); - unsigned MaxSizeBits = NumPow2 * OrigTy.getSizeInBits().getFixedSize(); + unsigned MaxSizeBits = NumPow2 * OrigTy.getSizeInBits().getFixedValue(); // Compute the biggest store we can generate to handle the number of stores. unsigned MergeSizeBits; for (MergeSizeBits = MaxSizeBits; MergeSizeBits > 1; MergeSizeBits /= 2) { @@ -352,13 +352,13 @@ bool LoadStoreOpt::doSingleStoreMerge(SmallVectorImpl<GStore *> &Stores) { const unsigned NumStores = Stores.size(); LLT SmallTy = MRI->getType(FirstStore->getValueReg()); LLT WideValueTy = - LLT::scalar(NumStores * SmallTy.getSizeInBits().getFixedSize()); + LLT::scalar(NumStores * SmallTy.getSizeInBits().getFixedValue()); // For each store, compute pairwise merged debug locs. - DebugLoc MergedLoc; - for (unsigned AIdx = 0, BIdx = 1; BIdx < NumStores; ++AIdx, ++BIdx) - MergedLoc = DILocation::getMergedLocation(Stores[AIdx]->getDebugLoc(), - Stores[BIdx]->getDebugLoc()); + DebugLoc MergedLoc = Stores.front()->getDebugLoc(); + for (auto *Store : drop_begin(Stores)) + MergedLoc = DILocation::getMergedLocation(MergedLoc, Store->getDebugLoc()); + Builder.setInstr(*Stores.back()); Builder.setDebugLoc(MergedLoc); diff --git a/llvm/lib/CodeGen/GlobalISel/Localizer.cpp b/llvm/lib/CodeGen/GlobalISel/Localizer.cpp index c1287693e74d..bf4dcc2c2459 100644 --- a/llvm/lib/CodeGen/GlobalISel/Localizer.cpp +++ b/llvm/lib/CodeGen/GlobalISel/Localizer.cpp @@ -181,6 +181,17 @@ bool Localizer::localizeIntraBlock(LocalizedSetVecT &LocalizedInstrs) { MI->removeFromParent(); MBB.insert(II, MI); Changed = true; + + // If the instruction (constant) being localized has single user, we can + // propagate debug location from user. + if (Users.size() == 1) { + const auto &DefDL = MI->getDebugLoc(); + const auto &UserDL = (*Users.begin())->getDebugLoc(); + + if ((!DefDL || DefDL.getLine() == 0) && UserDL && UserDL.getLine() != 0) { + MI->setDebugLoc(UserDL); + } + } } return Changed; } diff --git a/llvm/lib/CodeGen/GlobalISel/MachineIRBuilder.cpp b/llvm/lib/CodeGen/GlobalISel/MachineIRBuilder.cpp index 2e22dae35e5a..9100e064f30f 100644 --- a/llvm/lib/CodeGen/GlobalISel/MachineIRBuilder.cpp +++ b/llvm/lib/CodeGen/GlobalISel/MachineIRBuilder.cpp @@ -27,6 +27,7 @@ void MachineIRBuilder::setMF(MachineFunction &MF) { State.MRI = &MF.getRegInfo(); State.TII = MF.getSubtarget().getInstrInfo(); State.DL = DebugLoc(); + State.PCSections = nullptr; State.II = MachineBasicBlock::iterator(); State.Observer = nullptr; } @@ -36,8 +37,7 @@ void MachineIRBuilder::setMF(MachineFunction &MF) { //------------------------------------------------------------------------------ MachineInstrBuilder MachineIRBuilder::buildInstrNoInsert(unsigned Opcode) { - MachineInstrBuilder MIB = BuildMI(getMF(), getDL(), getTII().get(Opcode)); - return MIB; + return BuildMI(getMF(), {getDL(), getPCSections()}, getTII().get(Opcode)); } MachineInstrBuilder MachineIRBuilder::insertInstr(MachineInstrBuilder MIB) { @@ -96,13 +96,23 @@ MachineInstrBuilder MachineIRBuilder::buildConstDbgValue(const Constant &C, cast<DILocalVariable>(Variable)->isValidLocationForIntrinsic(getDL()) && "Expected inlined-at fields to agree"); auto MIB = buildInstrNoInsert(TargetOpcode::DBG_VALUE); - if (auto *CI = dyn_cast<ConstantInt>(&C)) { + + auto *NumericConstant = [&] () -> const Constant* { + if (const auto *CE = dyn_cast<ConstantExpr>(&C)) + if (CE->getOpcode() == Instruction::IntToPtr) + return CE->getOperand(0); + return &C; + }(); + + if (auto *CI = dyn_cast<ConstantInt>(NumericConstant)) { if (CI->getBitWidth() > 64) MIB.addCImm(CI); else MIB.addImm(CI->getZExtValue()); - } else if (auto *CFP = dyn_cast<ConstantFP>(&C)) { + } else if (auto *CFP = dyn_cast<ConstantFP>(NumericConstant)) { MIB.addFPImm(CFP); + } else if (isa<ConstantPointerNull>(NumericConstant)) { + MIB.addImm(0); } else { // Insert $noreg if we didn't find a usable constant and had to drop it. MIB.addReg(Register()); @@ -187,7 +197,7 @@ MachineInstrBuilder MachineIRBuilder::buildPtrAdd(const DstOp &Res, return buildInstr(TargetOpcode::G_PTR_ADD, {Res}, {Op0, Op1}); } -Optional<MachineInstrBuilder> +std::optional<MachineInstrBuilder> MachineIRBuilder::materializePtrAdd(Register &Res, Register Op0, const LLT ValueTy, uint64_t Value) { assert(Res == 0 && "Res is a result argument"); @@ -195,7 +205,7 @@ MachineIRBuilder::materializePtrAdd(Register &Res, Register Op0, if (Value == 0) { Res = Op0; - return None; + return std::nullopt; } Res = getMRI()->createGenericVirtualRegister(getMRI()->getType(Op0)); @@ -233,7 +243,7 @@ MachineIRBuilder::buildPadVectorWithUndefElements(const DstOp &Res, unsigned NumberOfPadElts = ResTy.getNumElements() - Regs.size(); for (unsigned i = 0; i < NumberOfPadElts; ++i) Regs.push_back(Undef); - return buildMerge(Res, Regs); + return buildMergeLikeInstr(Res, Regs); } MachineInstrBuilder @@ -252,7 +262,7 @@ MachineIRBuilder::buildDeleteTrailingVectorElements(const DstOp &Res, auto Unmerge = buildUnmerge(Op0Ty.getElementType(), Op0); for (unsigned i = 0; i < ResTy.getNumElements(); ++i) Regs.push_back(Unmerge.getReg(i)); - return buildMerge(Res, Regs); + return buildMergeLikeInstr(Res, Regs); } MachineInstrBuilder MachineIRBuilder::buildBr(MachineBasicBlock &Dest) { @@ -587,8 +597,8 @@ MachineInstrBuilder MachineIRBuilder::buildUndef(const DstOp &Res) { return buildInstr(TargetOpcode::G_IMPLICIT_DEF, {Res}, {}); } -MachineInstrBuilder MachineIRBuilder::buildMerge(const DstOp &Res, - ArrayRef<Register> Ops) { +MachineInstrBuilder MachineIRBuilder::buildMergeValues(const DstOp &Res, + ArrayRef<Register> Ops) { // Unfortunately to convert from ArrayRef<LLT> to ArrayRef<SrcOp>, // we need some temporary storage for the DstOp objects. Here we use a // sufficiently large SmallVector to not go through the heap. @@ -598,10 +608,32 @@ MachineInstrBuilder MachineIRBuilder::buildMerge(const DstOp &Res, } MachineInstrBuilder -MachineIRBuilder::buildMerge(const DstOp &Res, - std::initializer_list<SrcOp> Ops) { +MachineIRBuilder::buildMergeLikeInstr(const DstOp &Res, + ArrayRef<Register> Ops) { + // Unfortunately to convert from ArrayRef<LLT> to ArrayRef<SrcOp>, + // we need some temporary storage for the DstOp objects. Here we use a + // sufficiently large SmallVector to not go through the heap. + SmallVector<SrcOp, 8> TmpVec(Ops.begin(), Ops.end()); + assert(TmpVec.size() > 1); + return buildInstr(getOpcodeForMerge(Res, TmpVec), Res, TmpVec); +} + +MachineInstrBuilder +MachineIRBuilder::buildMergeLikeInstr(const DstOp &Res, + std::initializer_list<SrcOp> Ops) { assert(Ops.size() > 1); - return buildInstr(TargetOpcode::G_MERGE_VALUES, Res, Ops); + return buildInstr(getOpcodeForMerge(Res, Ops), Res, Ops); +} + +unsigned MachineIRBuilder::getOpcodeForMerge(const DstOp &DstOp, + ArrayRef<SrcOp> SrcOps) const { + if (DstOp.getLLTTy(*getMRI()).isVector()) { + if (SrcOps[0].getLLTTy(*getMRI()).isVector()) + return TargetOpcode::G_CONCAT_VECTORS; + return TargetOpcode::G_BUILD_VECTOR; + } + + return TargetOpcode::G_MERGE_VALUES; } MachineInstrBuilder MachineIRBuilder::buildUnmerge(ArrayRef<LLT> Res, @@ -664,6 +696,9 @@ MachineIRBuilder::buildBuildVectorTrunc(const DstOp &Res, // we need some temporary storage for the DstOp objects. Here we use a // sufficiently large SmallVector to not go through the heap. SmallVector<SrcOp, 8> TmpVec(Ops.begin(), Ops.end()); + if (TmpVec[0].getLLTTy(*getMRI()).getSizeInBits() == + Res.getLLTTy(*getMRI()).getElementType().getSizeInBits()) + return buildInstr(TargetOpcode::G_BUILD_VECTOR, Res, TmpVec); return buildInstr(TargetOpcode::G_BUILD_VECTOR_TRUNC, Res, TmpVec); } @@ -752,9 +787,9 @@ MachineInstrBuilder MachineIRBuilder::buildTrunc(const DstOp &Res, return buildInstr(TargetOpcode::G_TRUNC, Res, Op); } -MachineInstrBuilder MachineIRBuilder::buildFPTrunc(const DstOp &Res, - const SrcOp &Op, - Optional<unsigned> Flags) { +MachineInstrBuilder +MachineIRBuilder::buildFPTrunc(const DstOp &Res, const SrcOp &Op, + std::optional<unsigned> Flags) { return buildInstr(TargetOpcode::G_FPTRUNC, Res, Op, Flags); } @@ -769,16 +804,15 @@ MachineInstrBuilder MachineIRBuilder::buildFCmp(CmpInst::Predicate Pred, const DstOp &Res, const SrcOp &Op0, const SrcOp &Op1, - Optional<unsigned> Flags) { + std::optional<unsigned> Flags) { return buildInstr(TargetOpcode::G_FCMP, Res, {Pred, Op0, Op1}, Flags); } -MachineInstrBuilder MachineIRBuilder::buildSelect(const DstOp &Res, - const SrcOp &Tst, - const SrcOp &Op0, - const SrcOp &Op1, - Optional<unsigned> Flags) { +MachineInstrBuilder +MachineIRBuilder::buildSelect(const DstOp &Res, const SrcOp &Tst, + const SrcOp &Op0, const SrcOp &Op1, + std::optional<unsigned> Flags) { return buildInstr(TargetOpcode::G_SELECT, {Res}, {Tst, Op0, Op1}, Flags); } @@ -1019,10 +1053,10 @@ void MachineIRBuilder::validateSelectOp(const LLT ResTy, const LLT TstTy, #endif } -MachineInstrBuilder MachineIRBuilder::buildInstr(unsigned Opc, - ArrayRef<DstOp> DstOps, - ArrayRef<SrcOp> SrcOps, - Optional<unsigned> Flags) { +MachineInstrBuilder +MachineIRBuilder::buildInstr(unsigned Opc, ArrayRef<DstOp> DstOps, + ArrayRef<SrcOp> SrcOps, + std::optional<unsigned> Flags) { switch (Opc) { default: break; @@ -1150,7 +1184,7 @@ MachineInstrBuilder MachineIRBuilder::buildInstr(unsigned Opc, break; } case TargetOpcode::G_MERGE_VALUES: { - assert(!SrcOps.empty() && "invalid trivial sequence"); + assert(SrcOps.size() >= 2 && "invalid trivial sequence"); assert(DstOps.size() == 1 && "Invalid Dst"); assert(llvm::all_of(SrcOps, [&, this](const SrcOp &Op) { @@ -1162,13 +1196,8 @@ MachineInstrBuilder MachineIRBuilder::buildInstr(unsigned Opc, SrcOps[0].getLLTTy(*getMRI()).getSizeInBits() == DstOps[0].getLLTTy(*getMRI()).getSizeInBits() && "input operands do not cover output register"); - if (SrcOps.size() == 1) - return buildCast(DstOps[0], SrcOps[0]); - if (DstOps[0].getLLTTy(*getMRI()).isVector()) { - if (SrcOps[0].getLLTTy(*getMRI()).isVector()) - return buildInstr(TargetOpcode::G_CONCAT_VECTORS, DstOps, SrcOps); - return buildInstr(TargetOpcode::G_BUILD_VECTOR, DstOps, SrcOps); - } + assert(!DstOps[0].getLLTTy(*getMRI()).isVector() && + "vectors should be built with G_CONCAT_VECTOR or G_BUILD_VECTOR"); break; } case TargetOpcode::G_EXTRACT_VECTOR_ELT: { @@ -1228,9 +1257,6 @@ MachineInstrBuilder MachineIRBuilder::buildInstr(unsigned Opc, SrcOps[0].getLLTTy(*getMRI()); }) && "type mismatch in input list"); - if (SrcOps[0].getLLTTy(*getMRI()).getSizeInBits() == - DstOps[0].getLLTTy(*getMRI()).getElementType().getSizeInBits()) - return buildInstr(TargetOpcode::G_BUILD_VECTOR, DstOps, SrcOps); break; } case TargetOpcode::G_CONCAT_VECTORS: { diff --git a/llvm/lib/CodeGen/GlobalISel/RegBankSelect.cpp b/llvm/lib/CodeGen/GlobalISel/RegBankSelect.cpp index bce850ee212c..080f3ca540f2 100644 --- a/llvm/lib/CodeGen/GlobalISel/RegBankSelect.cpp +++ b/llvm/lib/CodeGen/GlobalISel/RegBankSelect.cpp @@ -153,8 +153,7 @@ bool RegBankSelect::repairReg( if (MO.isDef()) std::swap(Src, Dst); - assert((RepairPt.getNumInsertPoints() == 1 || - Register::isPhysicalRegister(Dst)) && + assert((RepairPt.getNumInsertPoints() == 1 || Dst.isPhysical()) && "We are about to create several defs for Dst"); // Build the instruction used to repair, then clone it at the right @@ -398,7 +397,7 @@ void RegBankSelect::tryAvoidingSplit( // Check if this is a physical or virtual register. Register Reg = MO.getReg(); - if (Register::isPhysicalRegister(Reg)) { + if (Reg.isPhysical()) { // We are going to split every outgoing edges. // Check that this is possible. // FIXME: The machine representation is currently broken @@ -458,6 +457,7 @@ RegBankSelect::MappingCost RegBankSelect::computeMapping( LLVM_DEBUG(dbgs() << "Mapping is too expensive from the start\n"); return Cost; } + const MachineRegisterInfo &MRI = MI.getMF()->getRegInfo(); // Moreover, to realize this mapping, the register bank of each operand must // match this mapping. In other words, we may need to locally reassign the @@ -471,6 +471,10 @@ RegBankSelect::MappingCost RegBankSelect::computeMapping( Register Reg = MO.getReg(); if (!Reg) continue; + LLT Ty = MRI.getType(Reg); + if (!Ty.isValid()) + continue; + LLVM_DEBUG(dbgs() << "Opd" << OpIdx << '\n'); const RegisterBankInfo::ValueMapping &ValMapping = InstrMapping.getOperandMapping(OpIdx); @@ -603,6 +607,9 @@ bool RegBankSelect::applyMapping( MRI->setRegBank(Reg, *ValMapping.BreakDown[0].RegBank); break; case RepairingPlacement::Insert: + // Don't insert additional instruction for debug instruction. + if (MI.isDebugInstr()) + break; OpdMapper.createVRegs(OpIdx); if (!repairReg(MO, ValMapping, RepairPt, OpdMapper.getVRegs(OpIdx))) return false; @@ -667,31 +674,7 @@ bool RegBankSelect::assignInstr(MachineInstr &MI) { return applyMapping(MI, *BestMapping, RepairPts); } -bool RegBankSelect::runOnMachineFunction(MachineFunction &MF) { - // If the ISel pipeline failed, do not bother running that pass. - if (MF.getProperties().hasProperty( - MachineFunctionProperties::Property::FailedISel)) - return false; - - LLVM_DEBUG(dbgs() << "Assign register banks for: " << MF.getName() << '\n'); - const Function &F = MF.getFunction(); - Mode SaveOptMode = OptMode; - if (F.hasOptNone()) - OptMode = Mode::Fast; - init(MF); - -#ifndef NDEBUG - // Check that our input is fully legal: we require the function to have the - // Legalized property, so it should be. - // FIXME: This should be in the MachineVerifier. - if (!DisableGISelLegalityCheck) - if (const MachineInstr *MI = machineFunctionIsIllegal(MF)) { - reportGISelFailure(MF, *TPC, *MORE, "gisel-regbankselect", - "instruction is not legal", *MI); - return false; - } -#endif - +bool RegBankSelect::assignRegisterBanks(MachineFunction &MF) { // Walk the function and assign register banks to all operands. // Use a RPOT to make sure all registers are assigned before we choose // the best mapping of the current instruction. @@ -716,10 +699,6 @@ bool RegBankSelect::runOnMachineFunction(MachineFunction &MF) { if (MI.isInlineAsm()) continue; - // Ignore debug info. - if (MI.isDebugInstr()) - continue; - // Ignore IMPLICIT_DEF which must have a regclass. if (MI.isImplicitDef()) continue; @@ -732,6 +711,42 @@ bool RegBankSelect::runOnMachineFunction(MachineFunction &MF) { } } + return true; +} + +bool RegBankSelect::checkFunctionIsLegal(MachineFunction &MF) const { +#ifndef NDEBUG + if (!DisableGISelLegalityCheck) { + if (const MachineInstr *MI = machineFunctionIsIllegal(MF)) { + reportGISelFailure(MF, *TPC, *MORE, "gisel-regbankselect", + "instruction is not legal", *MI); + return false; + } + } +#endif + return true; +} + +bool RegBankSelect::runOnMachineFunction(MachineFunction &MF) { + // If the ISel pipeline failed, do not bother running that pass. + if (MF.getProperties().hasProperty( + MachineFunctionProperties::Property::FailedISel)) + return false; + + LLVM_DEBUG(dbgs() << "Assign register banks for: " << MF.getName() << '\n'); + const Function &F = MF.getFunction(); + Mode SaveOptMode = OptMode; + if (F.hasOptNone()) + OptMode = Mode::Fast; + init(MF); + +#ifndef NDEBUG + if (!checkFunctionIsLegal(MF)) + return false; +#endif + + assignRegisterBanks(MF); + OptMode = SaveOptMode; return false; } diff --git a/llvm/lib/CodeGen/GlobalISel/Utils.cpp b/llvm/lib/CodeGen/GlobalISel/Utils.cpp index 013c8700e8ae..07448548c295 100644 --- a/llvm/lib/CodeGen/GlobalISel/Utils.cpp +++ b/llvm/lib/CodeGen/GlobalISel/Utils.cpp @@ -12,7 +12,7 @@ #include "llvm/CodeGen/GlobalISel/Utils.h" #include "llvm/ADT/APFloat.h" #include "llvm/ADT/APInt.h" -#include "llvm/ADT/Optional.h" +#include "llvm/CodeGen/CodeGenCommonISel.h" #include "llvm/CodeGen/GlobalISel/GISelChangeObserver.h" #include "llvm/CodeGen/GlobalISel/GISelKnownBits.h" #include "llvm/CodeGen/GlobalISel/GenericMachineInstrs.h" @@ -32,6 +32,8 @@ #include "llvm/IR/Constants.h" #include "llvm/Target/TargetMachine.h" #include "llvm/Transforms/Utils/SizeOpts.h" +#include <numeric> +#include <optional> #define DEBUG_TYPE "globalisel-utils" @@ -55,7 +57,7 @@ Register llvm::constrainOperandRegClass( const TargetRegisterClass &RegClass, MachineOperand &RegMO) { Register Reg = RegMO.getReg(); // Assume physical registers are properly constrained. - assert(Register::isVirtualRegister(Reg) && "PhysReg not implemented"); + assert(Reg.isVirtual() && "PhysReg not implemented"); // Save the old register class to check whether // the change notifications will be required. @@ -107,7 +109,7 @@ Register llvm::constrainOperandRegClass( MachineOperand &RegMO, unsigned OpIdx) { Register Reg = RegMO.getReg(); // Assume physical registers are properly constrained. - assert(Register::isVirtualRegister(Reg) && "PhysReg not implemented"); + assert(Reg.isVirtual() && "PhysReg not implemented"); const TargetRegisterClass *OpRC = TII.getRegClass(II, OpIdx, &TRI, MF); // Some of the target independent instructions, like COPY, may not impose any @@ -169,7 +171,7 @@ bool llvm::constrainSelectedInstRegOperands(MachineInstr &I, Register Reg = MO.getReg(); // Physical registers don't need to be constrained. - if (Register::isPhysicalRegister(Reg)) + if (Reg.isPhysical()) continue; // Register operands with a value of 0 (e.g. predicate operands) don't need @@ -233,7 +235,7 @@ bool llvm::isTriviallyDead(const MachineInstr &MI, continue; Register Reg = MO.getReg(); - if (Register::isPhysicalRegister(Reg) || !MRI.use_nodbg_empty(Reg)) + if (Reg.isPhysical() || !MRI.use_nodbg_empty(Reg)) return false; } return true; @@ -283,31 +285,31 @@ void llvm::reportGISelFailure(MachineFunction &MF, const TargetPassConfig &TPC, reportGISelFailure(MF, TPC, MORE, R); } -Optional<APInt> llvm::getIConstantVRegVal(Register VReg, - const MachineRegisterInfo &MRI) { - Optional<ValueAndVReg> ValAndVReg = getIConstantVRegValWithLookThrough( +std::optional<APInt> llvm::getIConstantVRegVal(Register VReg, + const MachineRegisterInfo &MRI) { + std::optional<ValueAndVReg> ValAndVReg = getIConstantVRegValWithLookThrough( VReg, MRI, /*LookThroughInstrs*/ false); assert((!ValAndVReg || ValAndVReg->VReg == VReg) && "Value found while looking through instrs"); if (!ValAndVReg) - return None; + return std::nullopt; return ValAndVReg->Value; } -Optional<int64_t> +std::optional<int64_t> llvm::getIConstantVRegSExtVal(Register VReg, const MachineRegisterInfo &MRI) { - Optional<APInt> Val = getIConstantVRegVal(VReg, MRI); + std::optional<APInt> Val = getIConstantVRegVal(VReg, MRI); if (Val && Val->getBitWidth() <= 64) return Val->getSExtValue(); - return None; + return std::nullopt; } namespace { typedef std::function<bool(const MachineInstr *)> IsOpcodeFn; -typedef std::function<Optional<APInt>(const MachineInstr *MI)> GetAPCstFn; +typedef std::function<std::optional<APInt>(const MachineInstr *MI)> GetAPCstFn; -Optional<ValueAndVReg> getConstantVRegValWithLookThrough( +std::optional<ValueAndVReg> getConstantVRegValWithLookThrough( Register VReg, const MachineRegisterInfo &MRI, IsOpcodeFn IsConstantOpcode, GetAPCstFn getAPCstValue, bool LookThroughInstrs = true, bool LookThroughAnyExt = false) { @@ -319,8 +321,8 @@ Optional<ValueAndVReg> getConstantVRegValWithLookThrough( switch (MI->getOpcode()) { case TargetOpcode::G_ANYEXT: if (!LookThroughAnyExt) - return None; - LLVM_FALLTHROUGH; + return std::nullopt; + [[fallthrough]]; case TargetOpcode::G_TRUNC: case TargetOpcode::G_SEXT: case TargetOpcode::G_ZEXT: @@ -331,22 +333,22 @@ Optional<ValueAndVReg> getConstantVRegValWithLookThrough( break; case TargetOpcode::COPY: VReg = MI->getOperand(1).getReg(); - if (Register::isPhysicalRegister(VReg)) - return None; + if (VReg.isPhysical()) + return std::nullopt; break; case TargetOpcode::G_INTTOPTR: VReg = MI->getOperand(1).getReg(); break; default: - return None; + return std::nullopt; } } if (!MI || !IsConstantOpcode(MI)) - return None; + return std::nullopt; - Optional<APInt> MaybeVal = getAPCstValue(MI); + std::optional<APInt> MaybeVal = getAPCstValue(MI); if (!MaybeVal) - return None; + return std::nullopt; APInt &Val = *MaybeVal; while (!SeenOpcodes.empty()) { std::pair<unsigned, unsigned> OpcodeAndSize = SeenOpcodes.pop_back_val(); @@ -386,31 +388,31 @@ bool isAnyConstant(const MachineInstr *MI) { return Opc == TargetOpcode::G_CONSTANT || Opc == TargetOpcode::G_FCONSTANT; } -Optional<APInt> getCImmAsAPInt(const MachineInstr *MI) { +std::optional<APInt> getCImmAsAPInt(const MachineInstr *MI) { const MachineOperand &CstVal = MI->getOperand(1); if (CstVal.isCImm()) return CstVal.getCImm()->getValue(); - return None; + return std::nullopt; } -Optional<APInt> getCImmOrFPImmAsAPInt(const MachineInstr *MI) { +std::optional<APInt> getCImmOrFPImmAsAPInt(const MachineInstr *MI) { const MachineOperand &CstVal = MI->getOperand(1); if (CstVal.isCImm()) return CstVal.getCImm()->getValue(); if (CstVal.isFPImm()) return CstVal.getFPImm()->getValueAPF().bitcastToAPInt(); - return None; + return std::nullopt; } } // end anonymous namespace -Optional<ValueAndVReg> llvm::getIConstantVRegValWithLookThrough( +std::optional<ValueAndVReg> llvm::getIConstantVRegValWithLookThrough( Register VReg, const MachineRegisterInfo &MRI, bool LookThroughInstrs) { return getConstantVRegValWithLookThrough(VReg, MRI, isIConstant, getCImmAsAPInt, LookThroughInstrs); } -Optional<ValueAndVReg> llvm::getAnyConstantVRegValWithLookThrough( +std::optional<ValueAndVReg> llvm::getAnyConstantVRegValWithLookThrough( Register VReg, const MachineRegisterInfo &MRI, bool LookThroughInstrs, bool LookThroughAnyExt) { return getConstantVRegValWithLookThrough( @@ -418,12 +420,12 @@ Optional<ValueAndVReg> llvm::getAnyConstantVRegValWithLookThrough( LookThroughAnyExt); } -Optional<FPValueAndVReg> llvm::getFConstantVRegValWithLookThrough( +std::optional<FPValueAndVReg> llvm::getFConstantVRegValWithLookThrough( Register VReg, const MachineRegisterInfo &MRI, bool LookThroughInstrs) { auto Reg = getConstantVRegValWithLookThrough( VReg, MRI, isFConstant, getCImmOrFPImmAsAPInt, LookThroughInstrs); if (!Reg) - return None; + return std::nullopt; return FPValueAndVReg{getConstantFPVRegVal(Reg->VReg, MRI)->getValueAPF(), Reg->VReg}; } @@ -436,13 +438,13 @@ llvm::getConstantFPVRegVal(Register VReg, const MachineRegisterInfo &MRI) { return MI->getOperand(1).getFPImm(); } -Optional<DefinitionAndSourceRegister> +std::optional<DefinitionAndSourceRegister> llvm::getDefSrcRegIgnoringCopies(Register Reg, const MachineRegisterInfo &MRI) { Register DefSrcReg = Reg; auto *DefMI = MRI.getVRegDef(Reg); auto DstTy = MRI.getType(DefMI->getOperand(0).getReg()); if (!DstTy.isValid()) - return None; + return std::nullopt; unsigned Opc = DefMI->getOpcode(); while (Opc == TargetOpcode::COPY || isPreISelGenericOptimizationHint(Opc)) { Register SrcReg = DefMI->getOperand(1).getReg(); @@ -458,14 +460,14 @@ llvm::getDefSrcRegIgnoringCopies(Register Reg, const MachineRegisterInfo &MRI) { MachineInstr *llvm::getDefIgnoringCopies(Register Reg, const MachineRegisterInfo &MRI) { - Optional<DefinitionAndSourceRegister> DefSrcReg = + std::optional<DefinitionAndSourceRegister> DefSrcReg = getDefSrcRegIgnoringCopies(Reg, MRI); return DefSrcReg ? DefSrcReg->MI : nullptr; } Register llvm::getSrcRegIgnoringCopies(Register Reg, const MachineRegisterInfo &MRI) { - Optional<DefinitionAndSourceRegister> DefSrcReg = + std::optional<DefinitionAndSourceRegister> DefSrcReg = getDefSrcRegIgnoringCopies(Reg, MRI); return DefSrcReg ? DefSrcReg->Reg : Register(); } @@ -489,16 +491,17 @@ APFloat llvm::getAPFloatFromSize(double Val, unsigned Size) { return APF; } -Optional<APInt> llvm::ConstantFoldBinOp(unsigned Opcode, const Register Op1, - const Register Op2, - const MachineRegisterInfo &MRI) { +std::optional<APInt> llvm::ConstantFoldBinOp(unsigned Opcode, + const Register Op1, + const Register Op2, + const MachineRegisterInfo &MRI) { auto MaybeOp2Cst = getAnyConstantVRegValWithLookThrough(Op2, MRI, false); if (!MaybeOp2Cst) - return None; + return std::nullopt; auto MaybeOp1Cst = getAnyConstantVRegValWithLookThrough(Op1, MRI, false); if (!MaybeOp1Cst) - return None; + return std::nullopt; const APInt &C1 = MaybeOp1Cst->Value; const APInt &C2 = MaybeOp2Cst->Value; @@ -550,19 +553,19 @@ Optional<APInt> llvm::ConstantFoldBinOp(unsigned Opcode, const Register Op1, return APIntOps::umax(C1, C2); } - return None; + return std::nullopt; } -Optional<APFloat> llvm::ConstantFoldFPBinOp(unsigned Opcode, const Register Op1, - const Register Op2, - const MachineRegisterInfo &MRI) { +std::optional<APFloat> +llvm::ConstantFoldFPBinOp(unsigned Opcode, const Register Op1, + const Register Op2, const MachineRegisterInfo &MRI) { const ConstantFP *Op2Cst = getConstantFPVRegVal(Op2, MRI); if (!Op2Cst) - return None; + return std::nullopt; const ConstantFP *Op1Cst = getConstantFPVRegVal(Op1, MRI); if (!Op1Cst) - return None; + return std::nullopt; APFloat C1 = Op1Cst->getValueAPF(); const APFloat &C2 = Op2Cst->getValueAPF(); @@ -604,7 +607,7 @@ Optional<APFloat> llvm::ConstantFoldFPBinOp(unsigned Opcode, const Register Op1, break; } - return None; + return std::nullopt; } SmallVector<APInt> @@ -656,6 +659,20 @@ bool llvm::isKnownNeverNaN(Register Val, const MachineRegisterInfo &MRI, switch (DefMI->getOpcode()) { default: break; + case TargetOpcode::G_FADD: + case TargetOpcode::G_FSUB: + case TargetOpcode::G_FMUL: + case TargetOpcode::G_FDIV: + case TargetOpcode::G_FREM: + case TargetOpcode::G_FSIN: + case TargetOpcode::G_FCOS: + case TargetOpcode::G_FMA: + case TargetOpcode::G_FMAD: + if (SNaN) + return true; + + // TODO: Need isKnownNeverInfinity + return false; case TargetOpcode::G_FMINNUM_IEEE: case TargetOpcode::G_FMAXNUM_IEEE: { if (SNaN) @@ -742,9 +759,9 @@ Register llvm::getFunctionLiveInPhysReg(MachineFunction &MF, return LiveIn; } -Optional<APInt> llvm::ConstantFoldExtOp(unsigned Opcode, const Register Op1, - uint64_t Imm, - const MachineRegisterInfo &MRI) { +std::optional<APInt> llvm::ConstantFoldExtOp(unsigned Opcode, + const Register Op1, uint64_t Imm, + const MachineRegisterInfo &MRI) { auto MaybeOp1Cst = getIConstantVRegVal(Op1, MRI); if (MaybeOp1Cst) { switch (Opcode) { @@ -756,12 +773,12 @@ Optional<APInt> llvm::ConstantFoldExtOp(unsigned Opcode, const Register Op1, } } } - return None; + return std::nullopt; } -Optional<APFloat> llvm::ConstantFoldIntToFloat(unsigned Opcode, LLT DstTy, - Register Src, - const MachineRegisterInfo &MRI) { +std::optional<APFloat> +llvm::ConstantFoldIntToFloat(unsigned Opcode, LLT DstTy, Register Src, + const MachineRegisterInfo &MRI) { assert(Opcode == TargetOpcode::G_SITOFP || Opcode == TargetOpcode::G_UITOFP); if (auto MaybeSrcVal = getIConstantVRegVal(Src, MRI)) { APFloat DstVal(getFltSemanticForLLT(DstTy)); @@ -769,30 +786,30 @@ Optional<APFloat> llvm::ConstantFoldIntToFloat(unsigned Opcode, LLT DstTy, APFloat::rmNearestTiesToEven); return DstVal; } - return None; + return std::nullopt; } -Optional<SmallVector<unsigned>> +std::optional<SmallVector<unsigned>> llvm::ConstantFoldCTLZ(Register Src, const MachineRegisterInfo &MRI) { LLT Ty = MRI.getType(Src); SmallVector<unsigned> FoldedCTLZs; - auto tryFoldScalar = [&](Register R) -> Optional<unsigned> { + auto tryFoldScalar = [&](Register R) -> std::optional<unsigned> { auto MaybeCst = getIConstantVRegVal(R, MRI); if (!MaybeCst) - return None; + return std::nullopt; return MaybeCst->countLeadingZeros(); }; if (Ty.isVector()) { // Try to constant fold each element. auto *BV = getOpcodeDef<GBuildVector>(Src, MRI); if (!BV) - return None; + return std::nullopt; for (unsigned SrcIdx = 0; SrcIdx < BV->getNumSources(); ++SrcIdx) { if (auto MaybeFold = tryFoldScalar(BV->getSourceReg(SrcIdx))) { FoldedCTLZs.emplace_back(*MaybeFold); continue; } - return None; + return std::nullopt; } return FoldedCTLZs; } @@ -800,12 +817,12 @@ llvm::ConstantFoldCTLZ(Register Src, const MachineRegisterInfo &MRI) { FoldedCTLZs.emplace_back(*MaybeCst); return FoldedCTLZs; } - return None; + return std::nullopt; } bool llvm::isKnownToBeAPowerOfTwo(Register Reg, const MachineRegisterInfo &MRI, GISelKnownBits *KB) { - Optional<DefinitionAndSourceRegister> DefSrcReg = + std::optional<DefinitionAndSourceRegister> DefSrcReg = getDefSrcRegIgnoringCopies(Reg, MRI); if (!DefSrcReg) return false; @@ -879,12 +896,6 @@ void llvm::getSelectionDAGFallbackAnalysisUsage(AnalysisUsage &AU) { AU.addPreserved<StackProtector>(); } -static unsigned getLCMSize(unsigned OrigSize, unsigned TargetSize) { - unsigned Mul = OrigSize * TargetSize; - unsigned GCDSize = greatestCommonDivisor(OrigSize, TargetSize); - return Mul / GCDSize; -} - LLT llvm::getLCMType(LLT OrigTy, LLT TargetTy) { const unsigned OrigSize = OrigTy.getSizeInBits(); const unsigned TargetSize = TargetTy.getSizeInBits(); @@ -899,8 +910,8 @@ LLT llvm::getLCMType(LLT OrigTy, LLT TargetTy) { const LLT TargetElt = TargetTy.getElementType(); if (OrigElt.getSizeInBits() == TargetElt.getSizeInBits()) { - int GCDElts = greatestCommonDivisor(OrigTy.getNumElements(), - TargetTy.getNumElements()); + int GCDElts = + std::gcd(OrigTy.getNumElements(), TargetTy.getNumElements()); // Prefer the original element type. ElementCount Mul = OrigTy.getElementCount() * TargetTy.getNumElements(); return LLT::vector(Mul.divideCoefficientBy(GCDElts), @@ -911,16 +922,16 @@ LLT llvm::getLCMType(LLT OrigTy, LLT TargetTy) { return OrigTy; } - unsigned LCMSize = getLCMSize(OrigSize, TargetSize); + unsigned LCMSize = std::lcm(OrigSize, TargetSize); return LLT::fixed_vector(LCMSize / OrigElt.getSizeInBits(), OrigElt); } if (TargetTy.isVector()) { - unsigned LCMSize = getLCMSize(OrigSize, TargetSize); + unsigned LCMSize = std::lcm(OrigSize, TargetSize); return LLT::fixed_vector(LCMSize / OrigSize, OrigTy); } - unsigned LCMSize = getLCMSize(OrigSize, TargetSize); + unsigned LCMSize = std::lcm(OrigSize, TargetSize); // Preserve pointer types. if (LCMSize == OrigSize) @@ -958,8 +969,7 @@ LLT llvm::getGCDType(LLT OrigTy, LLT TargetTy) { if (TargetTy.isVector()) { LLT TargetElt = TargetTy.getElementType(); if (OrigElt.getSizeInBits() == TargetElt.getSizeInBits()) { - int GCD = greatestCommonDivisor(OrigTy.getNumElements(), - TargetTy.getNumElements()); + int GCD = std::gcd(OrigTy.getNumElements(), TargetTy.getNumElements()); return LLT::scalarOrVector(ElementCount::getFixed(GCD), OrigElt); } } else { @@ -968,7 +978,7 @@ LLT llvm::getGCDType(LLT OrigTy, LLT TargetTy) { return OrigElt; } - unsigned GCD = greatestCommonDivisor(OrigSize, TargetSize); + unsigned GCD = std::gcd(OrigSize, TargetSize); if (GCD == OrigElt.getSizeInBits()) return OrigElt; @@ -986,11 +996,11 @@ LLT llvm::getGCDType(LLT OrigTy, LLT TargetTy) { return OrigTy; } - unsigned GCD = greatestCommonDivisor(OrigSize, TargetSize); + unsigned GCD = std::gcd(OrigSize, TargetSize); return LLT::scalar(GCD); } -Optional<int> llvm::getSplatIndex(MachineInstr &MI) { +std::optional<int> llvm::getSplatIndex(MachineInstr &MI) { assert(MI.getOpcode() == TargetOpcode::G_SHUFFLE_VECTOR && "Only G_SHUFFLE_VECTOR can have a splat index!"); ArrayRef<int> Mask = MI.getOperand(3).getShuffleMask(); @@ -1006,7 +1016,7 @@ Optional<int> llvm::getSplatIndex(MachineInstr &MI) { int SplatValue = *FirstDefinedIdx; if (any_of(make_range(std::next(FirstDefinedIdx), Mask.end()), [&SplatValue](int Elt) { return Elt >= 0 && Elt != SplatValue; })) - return None; + return std::nullopt; return SplatValue; } @@ -1018,36 +1028,41 @@ static bool isBuildVectorOp(unsigned Opcode) { namespace { -Optional<ValueAndVReg> getAnyConstantSplat(Register VReg, - const MachineRegisterInfo &MRI, - bool AllowUndef) { +std::optional<ValueAndVReg> getAnyConstantSplat(Register VReg, + const MachineRegisterInfo &MRI, + bool AllowUndef) { MachineInstr *MI = getDefIgnoringCopies(VReg, MRI); if (!MI) - return None; + return std::nullopt; - if (!isBuildVectorOp(MI->getOpcode())) - return None; + bool isConcatVectorsOp = MI->getOpcode() == TargetOpcode::G_CONCAT_VECTORS; + if (!isBuildVectorOp(MI->getOpcode()) && !isConcatVectorsOp) + return std::nullopt; - Optional<ValueAndVReg> SplatValAndReg = None; + std::optional<ValueAndVReg> SplatValAndReg; for (MachineOperand &Op : MI->uses()) { Register Element = Op.getReg(); + // If we have a G_CONCAT_VECTOR, we recursively look into the + // vectors that we're concatenating to see if they're splats. auto ElementValAndReg = - getAnyConstantVRegValWithLookThrough(Element, MRI, true, true); + isConcatVectorsOp + ? getAnyConstantSplat(Element, MRI, AllowUndef) + : getAnyConstantVRegValWithLookThrough(Element, MRI, true, true); // If AllowUndef, treat undef as value that will result in a constant splat. if (!ElementValAndReg) { if (AllowUndef && isa<GImplicitDef>(MRI.getVRegDef(Element))) continue; - return None; + return std::nullopt; } // Record splat value if (!SplatValAndReg) SplatValAndReg = ElementValAndReg; - // Different constant then the one already recorded, not a constant splat. + // Different constant than the one already recorded, not a constant splat. if (SplatValAndReg->Value != ElementValAndReg->Value) - return None; + return std::nullopt; } return SplatValAndReg; @@ -1070,44 +1085,45 @@ bool llvm::isBuildVectorConstantSplat(const MachineInstr &MI, AllowUndef); } -Optional<APInt> llvm::getIConstantSplatVal(const Register Reg, - const MachineRegisterInfo &MRI) { +std::optional<APInt> +llvm::getIConstantSplatVal(const Register Reg, const MachineRegisterInfo &MRI) { if (auto SplatValAndReg = getAnyConstantSplat(Reg, MRI, /* AllowUndef */ false)) { - Optional<ValueAndVReg> ValAndVReg = + std::optional<ValueAndVReg> ValAndVReg = getIConstantVRegValWithLookThrough(SplatValAndReg->VReg, MRI); return ValAndVReg->Value; } - return None; + return std::nullopt; } -Optional<APInt> getIConstantSplatVal(const MachineInstr &MI, - const MachineRegisterInfo &MRI) { +std::optional<APInt> +llvm::getIConstantSplatVal(const MachineInstr &MI, + const MachineRegisterInfo &MRI) { return getIConstantSplatVal(MI.getOperand(0).getReg(), MRI); } -Optional<int64_t> +std::optional<int64_t> llvm::getIConstantSplatSExtVal(const Register Reg, const MachineRegisterInfo &MRI) { if (auto SplatValAndReg = getAnyConstantSplat(Reg, MRI, /* AllowUndef */ false)) return getIConstantVRegSExtVal(SplatValAndReg->VReg, MRI); - return None; + return std::nullopt; } -Optional<int64_t> +std::optional<int64_t> llvm::getIConstantSplatSExtVal(const MachineInstr &MI, const MachineRegisterInfo &MRI) { return getIConstantSplatSExtVal(MI.getOperand(0).getReg(), MRI); } -Optional<FPValueAndVReg> llvm::getFConstantSplat(Register VReg, - const MachineRegisterInfo &MRI, - bool AllowUndef) { +std::optional<FPValueAndVReg> +llvm::getFConstantSplat(Register VReg, const MachineRegisterInfo &MRI, + bool AllowUndef) { if (auto SplatValAndReg = getAnyConstantSplat(VReg, MRI, AllowUndef)) return getFConstantVRegValWithLookThrough(SplatValAndReg->VReg, MRI); - return None; + return std::nullopt; } bool llvm::isBuildVectorAllZeros(const MachineInstr &MI, @@ -1122,17 +1138,17 @@ bool llvm::isBuildVectorAllOnes(const MachineInstr &MI, return isBuildVectorConstantSplat(MI, MRI, -1, AllowUndef); } -Optional<RegOrConstant> llvm::getVectorSplat(const MachineInstr &MI, - const MachineRegisterInfo &MRI) { +std::optional<RegOrConstant> +llvm::getVectorSplat(const MachineInstr &MI, const MachineRegisterInfo &MRI) { unsigned Opc = MI.getOpcode(); if (!isBuildVectorOp(Opc)) - return None; + return std::nullopt; if (auto Splat = getIConstantSplatSExtVal(MI, MRI)) return RegOrConstant(*Splat); auto Reg = MI.getOperand(1).getReg(); if (any_of(make_range(MI.operands_begin() + 2, MI.operands_end()), [&Reg](const MachineOperand &Op) { return Op.getReg() != Reg; })) - return None; + return std::nullopt; return RegOrConstant(Reg); } @@ -1192,7 +1208,7 @@ bool llvm::isConstantOrConstantVector(const MachineInstr &MI, return true; } -Optional<APInt> +std::optional<APInt> llvm::isConstantOrConstantSplatVector(MachineInstr &MI, const MachineRegisterInfo &MRI) { Register Def = MI.getOperand(0).getReg(); @@ -1200,7 +1216,7 @@ llvm::isConstantOrConstantSplatVector(MachineInstr &MI, return C->Value; auto MaybeCst = getIConstantSplatSExtVal(MI, MRI); if (!MaybeCst) - return None; + return std::nullopt; const unsigned ScalarSize = MRI.getType(Def).getScalarSizeInBits(); return APInt(ScalarSize, *MaybeCst, true); } @@ -1283,6 +1299,18 @@ bool llvm::isConstTrueVal(const TargetLowering &TLI, int64_t Val, bool IsVector, llvm_unreachable("Invalid boolean contents"); } +bool llvm::isConstFalseVal(const TargetLowering &TLI, int64_t Val, + bool IsVector, bool IsFP) { + switch (TLI.getBooleanContents(IsVector, IsFP)) { + case TargetLowering::UndefinedBooleanContent: + return ~Val & 0x1; + case TargetLowering::ZeroOrOneBooleanContent: + case TargetLowering::ZeroOrNegativeOneBooleanContent: + return Val == 0; + } + llvm_unreachable("Invalid boolean contents"); +} + int64_t llvm::getICmpTrueVal(const TargetLowering &TLI, bool IsVector, bool IsFP) { switch (TLI.getBooleanContents(IsVector, IsFP)) { @@ -1335,3 +1363,22 @@ void llvm::eraseInstr(MachineInstr &MI, MachineRegisterInfo &MRI, LostDebugLocObserver *LocObserver) { return eraseInstrs({&MI}, MRI, LocObserver); } + +void llvm::salvageDebugInfo(const MachineRegisterInfo &MRI, MachineInstr &MI) { + for (auto &Def : MI.defs()) { + assert(Def.isReg() && "Must be a reg"); + + SmallVector<MachineOperand *, 16> DbgUsers; + for (auto &MOUse : MRI.use_operands(Def.getReg())) { + MachineInstr *DbgValue = MOUse.getParent(); + // Ignore partially formed DBG_VALUEs. + if (DbgValue->isNonListDebugValue() && DbgValue->getNumOperands() == 4) { + DbgUsers.push_back(&MOUse); + } + } + + if (!DbgUsers.empty()) { + salvageDebugInfoForDbgValue(MRI, MI, DbgUsers); + } + } +} |
