aboutsummaryrefslogtreecommitdiff
path: root/llvm/lib/CodeGen/GlobalISel
diff options
context:
space:
mode:
authorDimitry Andric <dim@FreeBSD.org>2023-02-11 12:38:04 +0000
committerDimitry Andric <dim@FreeBSD.org>2023-02-11 12:38:11 +0000
commite3b557809604d036af6e00c60f012c2025b59a5e (patch)
tree8a11ba2269a3b669601e2fd41145b174008f4da8 /llvm/lib/CodeGen/GlobalISel
parent08e8dd7b9db7bb4a9de26d44c1cbfd24e869c014 (diff)
Diffstat (limited to 'llvm/lib/CodeGen/GlobalISel')
-rw-r--r--llvm/lib/CodeGen/GlobalISel/CSEInfo.cpp4
-rw-r--r--llvm/lib/CodeGen/GlobalISel/CSEMIRBuilder.cpp12
-rw-r--r--llvm/lib/CodeGen/GlobalISel/CallLowering.cpp45
-rw-r--r--llvm/lib/CodeGen/GlobalISel/Combiner.cpp6
-rw-r--r--llvm/lib/CodeGen/GlobalISel/CombinerHelper.cpp843
-rw-r--r--llvm/lib/CodeGen/GlobalISel/GISelKnownBits.cpp25
-rw-r--r--llvm/lib/CodeGen/GlobalISel/IRTranslator.cpp78
-rw-r--r--llvm/lib/CodeGen/GlobalISel/InstructionSelect.cpp11
-rw-r--r--llvm/lib/CodeGen/GlobalISel/LegacyLegalizerInfo.cpp2
-rw-r--r--llvm/lib/CodeGen/GlobalISel/Legalizer.cpp2
-rw-r--r--llvm/lib/CodeGen/GlobalISel/LegalizerHelper.cpp386
-rw-r--r--llvm/lib/CodeGen/GlobalISel/LegalizerInfo.cpp10
-rw-r--r--llvm/lib/CodeGen/GlobalISel/LoadStoreOpt.cpp12
-rw-r--r--llvm/lib/CodeGen/GlobalISel/Localizer.cpp11
-rw-r--r--llvm/lib/CodeGen/GlobalISel/MachineIRBuilder.cpp100
-rw-r--r--llvm/lib/CodeGen/GlobalISel/RegBankSelect.cpp79
-rw-r--r--llvm/lib/CodeGen/GlobalISel/Utils.cpp263
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);
+ }
+ }
+}