1b4e71185SQuentin Colombet //===- llvm/CodeGen/GlobalISel/Utils.cpp -------------------------*- C++ -*-==//
2b4e71185SQuentin Colombet //
32946cd70SChandler Carruth // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
42946cd70SChandler Carruth // See https://llvm.org/LICENSE.txt for license information.
52946cd70SChandler Carruth // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6b4e71185SQuentin Colombet //
7b4e71185SQuentin Colombet //===----------------------------------------------------------------------===//
8b4e71185SQuentin Colombet /// \file This file implements the utility functions used by the GlobalISel
9b4e71185SQuentin Colombet /// pipeline.
10b4e71185SQuentin Colombet //===----------------------------------------------------------------------===//
11b4e71185SQuentin Colombet
12b4e71185SQuentin Colombet #include "llvm/CodeGen/GlobalISel/Utils.h"
1391fc4e09SAditya Nandakumar #include "llvm/ADT/APFloat.h"
14520ab710SAmara Emerson #include "llvm/ADT/APInt.h"
15520ab710SAmara Emerson #include "llvm/ADT/Optional.h"
16b91d9ec0SAditya Nandakumar #include "llvm/CodeGen/GlobalISel/GISelChangeObserver.h"
17a427f15dSMatt Arsenault #include "llvm/CodeGen/GlobalISel/GISelKnownBits.h"
188bc71856SPetar Avramovic #include "llvm/CodeGen/GlobalISel/GenericMachineInstrs.h"
19ed98c1b3Sserge-sans-paille #include "llvm/CodeGen/GlobalISel/LostDebugLocObserver.h"
205c5e6d95SMatt Arsenault #include "llvm/CodeGen/GlobalISel/MIPatternMatch.h"
21b4e71185SQuentin Colombet #include "llvm/CodeGen/MachineInstr.h"
22b4e71185SQuentin Colombet #include "llvm/CodeGen/MachineInstrBuilder.h"
23ae9dadecSAhmed Bougacha #include "llvm/CodeGen/MachineOptimizationRemarkEmitter.h"
24b4e71185SQuentin Colombet #include "llvm/CodeGen/MachineRegisterInfo.h"
259a6e0afaSBenjamin Kramer #include "llvm/CodeGen/MachineSizeOpts.h"
26cb216076SMircea Trofin #include "llvm/CodeGen/RegisterBankInfo.h"
2790ad6835SMatthias Braun #include "llvm/CodeGen/StackProtector.h"
283f833edcSDavid Blaikie #include "llvm/CodeGen/TargetInstrInfo.h"
29898e42dbSSimon Pilgrim #include "llvm/CodeGen/TargetLowering.h"
30ae9dadecSAhmed Bougacha #include "llvm/CodeGen/TargetPassConfig.h"
31b3bde2eaSDavid Blaikie #include "llvm/CodeGen/TargetRegisterInfo.h"
3275ad9ccbSAditya Nandakumar #include "llvm/IR/Constants.h"
336e2a86edSPetar Avramovic #include "llvm/Target/TargetMachine.h"
3460ca2569Sserge-sans-paille #include "llvm/Transforms/Utils/SizeOpts.h"
35b4e71185SQuentin Colombet
36b4e71185SQuentin Colombet #define DEBUG_TYPE "globalisel-utils"
37b4e71185SQuentin Colombet
38b4e71185SQuentin Colombet using namespace llvm;
395c5e6d95SMatt Arsenault using namespace MIPatternMatch;
40b4e71185SQuentin Colombet
constrainRegToClass(MachineRegisterInfo & MRI,const TargetInstrInfo & TII,const RegisterBankInfo & RBI,Register Reg,const TargetRegisterClass & RegClass)41eb7f74e3SMatt Arsenault Register llvm::constrainRegToClass(MachineRegisterInfo &MRI,
42a6e2cebfSDaniel Sanders const TargetInstrInfo &TII,
43eb7f74e3SMatt Arsenault const RegisterBankInfo &RBI, Register Reg,
44a6e2cebfSDaniel Sanders const TargetRegisterClass &RegClass) {
45c596584fSMarcello Maggioni if (!RBI.constrainGenericRegister(Reg, RegClass, MRI))
46c596584fSMarcello Maggioni return MRI.createVirtualRegister(&RegClass);
47a6e2cebfSDaniel Sanders
48a6e2cebfSDaniel Sanders return Reg;
49a6e2cebfSDaniel Sanders }
50a6e2cebfSDaniel Sanders
constrainOperandRegClass(const MachineFunction & MF,const TargetRegisterInfo & TRI,MachineRegisterInfo & MRI,const TargetInstrInfo & TII,const RegisterBankInfo & RBI,MachineInstr & InsertPt,const TargetRegisterClass & RegClass,MachineOperand & RegMO)51eb7f74e3SMatt Arsenault Register llvm::constrainOperandRegClass(
52b4e71185SQuentin Colombet const MachineFunction &MF, const TargetRegisterInfo &TRI,
53b4e71185SQuentin Colombet MachineRegisterInfo &MRI, const TargetInstrInfo &TII,
54c596584fSMarcello Maggioni const RegisterBankInfo &RBI, MachineInstr &InsertPt,
552aeaaf84SGabriel Hjort Åkerlund const TargetRegisterClass &RegClass, MachineOperand &RegMO) {
560c476111SDaniel Sanders Register Reg = RegMO.getReg();
57c596584fSMarcello Maggioni // Assume physical registers are properly constrained.
582bea69bfSDaniel Sanders assert(Register::isVirtualRegister(Reg) && "PhysReg not implemented");
59c596584fSMarcello Maggioni
6093977f37SDaniel Sanders // Save the old register class to check whether
6193977f37SDaniel Sanders // the change notifications will be required.
6293977f37SDaniel Sanders // TODO: A better approach would be to pass
6393977f37SDaniel Sanders // the observers to constrainRegToClass().
6493977f37SDaniel Sanders auto *OldRegClass = MRI.getRegClassOrNull(Reg);
65eb7f74e3SMatt Arsenault Register ConstrainedReg = constrainRegToClass(MRI, TII, RBI, Reg, RegClass);
66c596584fSMarcello Maggioni // If we created a new virtual register because the class is not compatible
67c596584fSMarcello Maggioni // then create a copy between the new and the old register.
68c596584fSMarcello Maggioni if (ConstrainedReg != Reg) {
69c596584fSMarcello Maggioni MachineBasicBlock::iterator InsertIt(&InsertPt);
70c596584fSMarcello Maggioni MachineBasicBlock &MBB = *InsertPt.getParent();
71aa2d3b59SChristudasan Devadasan // FIXME: The copy needs to have the classes constrained for its operands.
72aa2d3b59SChristudasan Devadasan // Use operand's regbank to get the class for old register (Reg).
73c596584fSMarcello Maggioni if (RegMO.isUse()) {
74c596584fSMarcello Maggioni BuildMI(MBB, InsertIt, InsertPt.getDebugLoc(),
75c596584fSMarcello Maggioni TII.get(TargetOpcode::COPY), ConstrainedReg)
76c596584fSMarcello Maggioni .addReg(Reg);
77c596584fSMarcello Maggioni } else {
78c596584fSMarcello Maggioni assert(RegMO.isDef() && "Must be a definition");
79c596584fSMarcello Maggioni BuildMI(MBB, std::next(InsertIt), InsertPt.getDebugLoc(),
80c596584fSMarcello Maggioni TII.get(TargetOpcode::COPY), Reg)
81c596584fSMarcello Maggioni .addReg(ConstrainedReg);
82c596584fSMarcello Maggioni }
832aeaaf84SGabriel Hjort Åkerlund if (GISelChangeObserver *Observer = MF.getObserver()) {
842aeaaf84SGabriel Hjort Åkerlund Observer->changingInstr(*RegMO.getParent());
852aeaaf84SGabriel Hjort Åkerlund }
862aeaaf84SGabriel Hjort Åkerlund RegMO.setReg(ConstrainedReg);
872aeaaf84SGabriel Hjort Åkerlund if (GISelChangeObserver *Observer = MF.getObserver()) {
882aeaaf84SGabriel Hjort Åkerlund Observer->changedInstr(*RegMO.getParent());
892aeaaf84SGabriel Hjort Åkerlund }
9093977f37SDaniel Sanders } else if (OldRegClass != MRI.getRegClassOrNull(Reg)) {
91b91d9ec0SAditya Nandakumar if (GISelChangeObserver *Observer = MF.getObserver()) {
92b91d9ec0SAditya Nandakumar if (!RegMO.isDef()) {
93b91d9ec0SAditya Nandakumar MachineInstr *RegDef = MRI.getVRegDef(Reg);
94b91d9ec0SAditya Nandakumar Observer->changedInstr(*RegDef);
95b91d9ec0SAditya Nandakumar }
96b91d9ec0SAditya Nandakumar Observer->changingAllUsesOfReg(MRI, Reg);
97b91d9ec0SAditya Nandakumar Observer->finishedChangingAllUsesOfReg();
98b91d9ec0SAditya Nandakumar }
99c596584fSMarcello Maggioni }
100c596584fSMarcello Maggioni return ConstrainedReg;
101c596584fSMarcello Maggioni }
102c596584fSMarcello Maggioni
constrainOperandRegClass(const MachineFunction & MF,const TargetRegisterInfo & TRI,MachineRegisterInfo & MRI,const TargetInstrInfo & TII,const RegisterBankInfo & RBI,MachineInstr & InsertPt,const MCInstrDesc & II,MachineOperand & RegMO,unsigned OpIdx)103eb7f74e3SMatt Arsenault Register llvm::constrainOperandRegClass(
104c596584fSMarcello Maggioni const MachineFunction &MF, const TargetRegisterInfo &TRI,
105c596584fSMarcello Maggioni MachineRegisterInfo &MRI, const TargetInstrInfo &TII,
106b4e71185SQuentin Colombet const RegisterBankInfo &RBI, MachineInstr &InsertPt, const MCInstrDesc &II,
1072aeaaf84SGabriel Hjort Åkerlund MachineOperand &RegMO, unsigned OpIdx) {
1080c476111SDaniel Sanders Register Reg = RegMO.getReg();
109b4e71185SQuentin Colombet // Assume physical registers are properly constrained.
1102bea69bfSDaniel Sanders assert(Register::isVirtualRegister(Reg) && "PhysReg not implemented");
111b4e71185SQuentin Colombet
112aa2d3b59SChristudasan Devadasan const TargetRegisterClass *OpRC = TII.getRegClass(II, OpIdx, &TRI, MF);
11308464524SDaniel Sanders // Some of the target independent instructions, like COPY, may not impose any
11459999053SAditya Nandakumar // register class constraints on some of their operands: If it's a use, we can
11559999053SAditya Nandakumar // skip constraining as the instruction defining the register would constrain
11659999053SAditya Nandakumar // it.
117abc9871dSTom Stellard
118aa2d3b59SChristudasan Devadasan if (OpRC) {
119aa2d3b59SChristudasan Devadasan // Obtain the RC from incoming regbank if it is a proper sub-class. Operands
120aa2d3b59SChristudasan Devadasan // can have multiple regbanks for a superclass that combine different
121aa2d3b59SChristudasan Devadasan // register types (E.g., AMDGPU's VGPR and AGPR). The regbank ambiguity
122aa2d3b59SChristudasan Devadasan // resolved by targets during regbankselect should not be overridden.
123aa2d3b59SChristudasan Devadasan if (const auto *SubRC = TRI.getCommonSubClass(
124aa2d3b59SChristudasan Devadasan OpRC, TRI.getConstrainedRegClassForOperand(RegMO, MRI)))
125aa2d3b59SChristudasan Devadasan OpRC = SubRC;
126abc9871dSTom Stellard
127aa2d3b59SChristudasan Devadasan OpRC = TRI.getAllocatableClass(OpRC);
128aa2d3b59SChristudasan Devadasan }
129aa2d3b59SChristudasan Devadasan
130aa2d3b59SChristudasan Devadasan if (!OpRC) {
13159999053SAditya Nandakumar assert((!isTargetSpecificOpcode(II.getOpcode()) || RegMO.isUse()) &&
13259999053SAditya Nandakumar "Register class constraint is required unless either the "
13359999053SAditya Nandakumar "instruction is target independent or the operand is a use");
13408464524SDaniel Sanders // FIXME: Just bailing out like this here could be not enough, unless we
13508464524SDaniel Sanders // expect the users of this function to do the right thing for PHIs and
13608464524SDaniel Sanders // COPY:
13708464524SDaniel Sanders // v1 = COPY v0
13808464524SDaniel Sanders // v2 = COPY v1
13908464524SDaniel Sanders // v1 here may end up not being constrained at all. Please notice that to
14008464524SDaniel Sanders // reproduce the issue we likely need a destination pattern of a selection
14108464524SDaniel Sanders // rule producing such extra copies, not just an input GMIR with them as
14208464524SDaniel Sanders // every existing target using selectImpl handles copies before calling it
14308464524SDaniel Sanders // and they never reach this function.
14408464524SDaniel Sanders return Reg;
14508464524SDaniel Sanders }
146aa2d3b59SChristudasan Devadasan return constrainOperandRegClass(MF, TRI, MRI, TII, RBI, InsertPt, *OpRC,
1473bb0ff83SMatt Arsenault RegMO);
148b4e71185SQuentin Colombet }
149ae9dadecSAhmed Bougacha
constrainSelectedInstRegOperands(MachineInstr & I,const TargetInstrInfo & TII,const TargetRegisterInfo & TRI,const RegisterBankInfo & RBI)15018b3f9d3SAditya Nandakumar bool llvm::constrainSelectedInstRegOperands(MachineInstr &I,
15118b3f9d3SAditya Nandakumar const TargetInstrInfo &TII,
15218b3f9d3SAditya Nandakumar const TargetRegisterInfo &TRI,
15318b3f9d3SAditya Nandakumar const RegisterBankInfo &RBI) {
15408464524SDaniel Sanders assert(!isPreISelGenericOpcode(I.getOpcode()) &&
15508464524SDaniel Sanders "A selected instruction is expected");
15618b3f9d3SAditya Nandakumar MachineBasicBlock &MBB = *I.getParent();
15718b3f9d3SAditya Nandakumar MachineFunction &MF = *MBB.getParent();
15818b3f9d3SAditya Nandakumar MachineRegisterInfo &MRI = MF.getRegInfo();
15918b3f9d3SAditya Nandakumar
16018b3f9d3SAditya Nandakumar for (unsigned OpI = 0, OpE = I.getNumExplicitOperands(); OpI != OpE; ++OpI) {
16118b3f9d3SAditya Nandakumar MachineOperand &MO = I.getOperand(OpI);
16218b3f9d3SAditya Nandakumar
16318b3f9d3SAditya Nandakumar // There's nothing to be done on non-register operands.
16418b3f9d3SAditya Nandakumar if (!MO.isReg())
16518b3f9d3SAditya Nandakumar continue;
16618b3f9d3SAditya Nandakumar
167d34e60caSNicola Zaghen LLVM_DEBUG(dbgs() << "Converting operand: " << MO << '\n');
16818b3f9d3SAditya Nandakumar assert(MO.isReg() && "Unsupported non-reg operand");
16918b3f9d3SAditya Nandakumar
1700c476111SDaniel Sanders Register Reg = MO.getReg();
17118b3f9d3SAditya Nandakumar // Physical registers don't need to be constrained.
1722bea69bfSDaniel Sanders if (Register::isPhysicalRegister(Reg))
17318b3f9d3SAditya Nandakumar continue;
17418b3f9d3SAditya Nandakumar
17518b3f9d3SAditya Nandakumar // Register operands with a value of 0 (e.g. predicate operands) don't need
17618b3f9d3SAditya Nandakumar // to be constrained.
17718b3f9d3SAditya Nandakumar if (Reg == 0)
17818b3f9d3SAditya Nandakumar continue;
17918b3f9d3SAditya Nandakumar
18018b3f9d3SAditya Nandakumar // If the operand is a vreg, we should constrain its regclass, and only
18118b3f9d3SAditya Nandakumar // insert COPYs if that's impossible.
18218b3f9d3SAditya Nandakumar // constrainOperandRegClass does that for us.
1832aeaaf84SGabriel Hjort Åkerlund constrainOperandRegClass(MF, TRI, MRI, TII, RBI, I, I.getDesc(), MO, OpI);
18418b3f9d3SAditya Nandakumar
18518b3f9d3SAditya Nandakumar // Tie uses to defs as indicated in MCInstrDesc if this hasn't already been
18618b3f9d3SAditya Nandakumar // done.
18718b3f9d3SAditya Nandakumar if (MO.isUse()) {
18818b3f9d3SAditya Nandakumar int DefIdx = I.getDesc().getOperandConstraint(OpI, MCOI::TIED_TO);
18918b3f9d3SAditya Nandakumar if (DefIdx != -1 && !I.isRegTiedToUseOperand(DefIdx))
19018b3f9d3SAditya Nandakumar I.tieOperands(DefIdx, OpI);
19118b3f9d3SAditya Nandakumar }
19218b3f9d3SAditya Nandakumar }
19318b3f9d3SAditya Nandakumar return true;
19418b3f9d3SAditya Nandakumar }
19518b3f9d3SAditya Nandakumar
canReplaceReg(Register DstReg,Register SrcReg,MachineRegisterInfo & MRI)196187686a2SVolkan Keles bool llvm::canReplaceReg(Register DstReg, Register SrcReg,
197187686a2SVolkan Keles MachineRegisterInfo &MRI) {
198187686a2SVolkan Keles // Give up if either DstReg or SrcReg is a physical register.
199187686a2SVolkan Keles if (DstReg.isPhysical() || SrcReg.isPhysical())
200187686a2SVolkan Keles return false;
201187686a2SVolkan Keles // Give up if the types don't match.
202187686a2SVolkan Keles if (MRI.getType(DstReg) != MRI.getType(SrcReg))
203187686a2SVolkan Keles return false;
204187686a2SVolkan Keles // Replace if either DstReg has no constraints or the register
205187686a2SVolkan Keles // constraints match.
206187686a2SVolkan Keles return !MRI.getRegClassOrRegBank(DstReg) ||
207187686a2SVolkan Keles MRI.getRegClassOrRegBank(DstReg) == MRI.getRegClassOrRegBank(SrcReg);
208187686a2SVolkan Keles }
209187686a2SVolkan Keles
isTriviallyDead(const MachineInstr & MI,const MachineRegisterInfo & MRI)21047debaeeSVolkan Keles bool llvm::isTriviallyDead(const MachineInstr &MI,
21147debaeeSVolkan Keles const MachineRegisterInfo &MRI) {
2123e16e215SMatt Arsenault // FIXME: This logical is mostly duplicated with
2133e16e215SMatt Arsenault // DeadMachineInstructionElim::isDead. Why is LOCAL_ESCAPE not considered in
2143e16e215SMatt Arsenault // MachineInstr::isLabel?
2153e16e215SMatt Arsenault
2163e16e215SMatt Arsenault // Don't delete frame allocation labels.
2173e16e215SMatt Arsenault if (MI.getOpcode() == TargetOpcode::LOCAL_ESCAPE)
2183e16e215SMatt Arsenault return false;
21928963d89SAmara Emerson // LIFETIME markers should be preserved even if they seem dead.
22028963d89SAmara Emerson if (MI.getOpcode() == TargetOpcode::LIFETIME_START ||
22128963d89SAmara Emerson MI.getOpcode() == TargetOpcode::LIFETIME_END)
22228963d89SAmara Emerson return false;
2233e16e215SMatt Arsenault
22447debaeeSVolkan Keles // If we can move an instruction, we can remove it. Otherwise, it has
22547debaeeSVolkan Keles // a side-effect of some sort.
22647debaeeSVolkan Keles bool SawStore = false;
227cd04e366SAditya Nandakumar if (!MI.isSafeToMove(/*AA=*/nullptr, SawStore) && !MI.isPHI())
22847debaeeSVolkan Keles return false;
22947debaeeSVolkan Keles
23047debaeeSVolkan Keles // Instructions without side-effects are dead iff they only define dead vregs.
231*9e6d1f4bSKazu Hirata for (const auto &MO : MI.operands()) {
23247debaeeSVolkan Keles if (!MO.isReg() || !MO.isDef())
23347debaeeSVolkan Keles continue;
23447debaeeSVolkan Keles
2350c476111SDaniel Sanders Register Reg = MO.getReg();
2362bea69bfSDaniel Sanders if (Register::isPhysicalRegister(Reg) || !MRI.use_nodbg_empty(Reg))
23747debaeeSVolkan Keles return false;
23847debaeeSVolkan Keles }
23947debaeeSVolkan Keles return true;
24047debaeeSVolkan Keles }
24147debaeeSVolkan Keles
reportGISelDiagnostic(DiagnosticSeverity Severity,MachineFunction & MF,const TargetPassConfig & TPC,MachineOptimizationRemarkEmitter & MORE,MachineOptimizationRemarkMissed & R)2427c6ca18fSDaniel Sanders static void reportGISelDiagnostic(DiagnosticSeverity Severity,
2437c6ca18fSDaniel Sanders MachineFunction &MF,
2447c6ca18fSDaniel Sanders const TargetPassConfig &TPC,
2457c6ca18fSDaniel Sanders MachineOptimizationRemarkEmitter &MORE,
2467c6ca18fSDaniel Sanders MachineOptimizationRemarkMissed &R) {
2477c6ca18fSDaniel Sanders bool IsFatal = Severity == DS_Error &&
2487c6ca18fSDaniel Sanders TPC.isGlobalISelAbortEnabled();
2497c6ca18fSDaniel Sanders // Print the function name explicitly if we don't have a debug location (which
2507c6ca18fSDaniel Sanders // makes the diagnostic less useful) or if we're going to emit a raw error.
2517c6ca18fSDaniel Sanders if (!R.getLocation().isValid() || IsFatal)
2527c6ca18fSDaniel Sanders R << (" (in function: " + MF.getName() + ")").str();
2537c6ca18fSDaniel Sanders
2547c6ca18fSDaniel Sanders if (IsFatal)
25521661607SSimon Pilgrim report_fatal_error(Twine(R.getMsg()));
2567c6ca18fSDaniel Sanders else
2577c6ca18fSDaniel Sanders MORE.emit(R);
2587c6ca18fSDaniel Sanders }
2597c6ca18fSDaniel Sanders
reportGISelWarning(MachineFunction & MF,const TargetPassConfig & TPC,MachineOptimizationRemarkEmitter & MORE,MachineOptimizationRemarkMissed & R)2607c6ca18fSDaniel Sanders void llvm::reportGISelWarning(MachineFunction &MF, const TargetPassConfig &TPC,
2617c6ca18fSDaniel Sanders MachineOptimizationRemarkEmitter &MORE,
2627c6ca18fSDaniel Sanders MachineOptimizationRemarkMissed &R) {
2637c6ca18fSDaniel Sanders reportGISelDiagnostic(DS_Warning, MF, TPC, MORE, R);
2647c6ca18fSDaniel Sanders }
2657c6ca18fSDaniel Sanders
reportGISelFailure(MachineFunction & MF,const TargetPassConfig & TPC,MachineOptimizationRemarkEmitter & MORE,MachineOptimizationRemarkMissed & R)266ae9dadecSAhmed Bougacha void llvm::reportGISelFailure(MachineFunction &MF, const TargetPassConfig &TPC,
267ae9dadecSAhmed Bougacha MachineOptimizationRemarkEmitter &MORE,
268ae9dadecSAhmed Bougacha MachineOptimizationRemarkMissed &R) {
269ae9dadecSAhmed Bougacha MF.getProperties().set(MachineFunctionProperties::Property::FailedISel);
2707c6ca18fSDaniel Sanders reportGISelDiagnostic(DS_Error, MF, TPC, MORE, R);
271ae9dadecSAhmed Bougacha }
272ae9dadecSAhmed Bougacha
reportGISelFailure(MachineFunction & MF,const TargetPassConfig & TPC,MachineOptimizationRemarkEmitter & MORE,const char * PassName,StringRef Msg,const MachineInstr & MI)273ae9dadecSAhmed Bougacha void llvm::reportGISelFailure(MachineFunction &MF, const TargetPassConfig &TPC,
274ae9dadecSAhmed Bougacha MachineOptimizationRemarkEmitter &MORE,
275ae9dadecSAhmed Bougacha const char *PassName, StringRef Msg,
276ae9dadecSAhmed Bougacha const MachineInstr &MI) {
277ae9dadecSAhmed Bougacha MachineOptimizationRemarkMissed R(PassName, "GISelFailure: ",
278ae9dadecSAhmed Bougacha MI.getDebugLoc(), MI.getParent());
279d630a92bSAhmed Bougacha R << Msg;
280d630a92bSAhmed Bougacha // Printing MI is expensive; only do it if expensive remarks are enabled.
281abf75940SAditya Nandakumar if (TPC.isGlobalISelAbortEnabled() || MORE.allowExtraAnalysis(PassName))
282d630a92bSAhmed Bougacha R << ": " << ore::MNV("Inst", MI);
283ae9dadecSAhmed Bougacha reportGISelFailure(MF, TPC, MORE, R);
284ae9dadecSAhmed Bougacha }
28575ad9ccbSAditya Nandakumar
getIConstantVRegVal(Register VReg,const MachineRegisterInfo & MRI)286d477a7c2SPetar Avramovic Optional<APInt> llvm::getIConstantVRegVal(Register VReg,
28775ad9ccbSAditya Nandakumar const MachineRegisterInfo &MRI) {
288d477a7c2SPetar Avramovic Optional<ValueAndVReg> ValAndVReg = getIConstantVRegValWithLookThrough(
289d477a7c2SPetar Avramovic VReg, MRI, /*LookThroughInstrs*/ false);
290e77e5f44SQuentin Colombet assert((!ValAndVReg || ValAndVReg->VReg == VReg) &&
291e77e5f44SQuentin Colombet "Value found while looking through instrs");
292e77e5f44SQuentin Colombet if (!ValAndVReg)
293e77e5f44SQuentin Colombet return None;
294e77e5f44SQuentin Colombet return ValAndVReg->Value;
295e77e5f44SQuentin Colombet }
296e77e5f44SQuentin Colombet
297d477a7c2SPetar Avramovic Optional<int64_t>
getIConstantVRegSExtVal(Register VReg,const MachineRegisterInfo & MRI)298d477a7c2SPetar Avramovic llvm::getIConstantVRegSExtVal(Register VReg, const MachineRegisterInfo &MRI) {
299d477a7c2SPetar Avramovic Optional<APInt> Val = getIConstantVRegVal(VReg, MRI);
300581d13f8SMatt Arsenault if (Val && Val->getBitWidth() <= 64)
301581d13f8SMatt Arsenault return Val->getSExtValue();
302581d13f8SMatt Arsenault return None;
303581d13f8SMatt Arsenault }
304581d13f8SMatt Arsenault
305d477a7c2SPetar Avramovic namespace {
306d477a7c2SPetar Avramovic
307d477a7c2SPetar Avramovic typedef std::function<bool(const MachineInstr *)> IsOpcodeFn;
308d477a7c2SPetar Avramovic typedef std::function<Optional<APInt>(const MachineInstr *MI)> GetAPCstFn;
309d477a7c2SPetar Avramovic
getConstantVRegValWithLookThrough(Register VReg,const MachineRegisterInfo & MRI,IsOpcodeFn IsConstantOpcode,GetAPCstFn getAPCstValue,bool LookThroughInstrs=true,bool LookThroughAnyExt=false)310d477a7c2SPetar Avramovic Optional<ValueAndVReg> getConstantVRegValWithLookThrough(
311d477a7c2SPetar Avramovic Register VReg, const MachineRegisterInfo &MRI, IsOpcodeFn IsConstantOpcode,
312d477a7c2SPetar Avramovic GetAPCstFn getAPCstValue, bool LookThroughInstrs = true,
313d477a7c2SPetar Avramovic bool LookThroughAnyExt = false) {
314e77e5f44SQuentin Colombet SmallVector<std::pair<unsigned, unsigned>, 4> SeenOpcodes;
315e77e5f44SQuentin Colombet MachineInstr *MI;
316d477a7c2SPetar Avramovic
317d477a7c2SPetar Avramovic while ((MI = MRI.getVRegDef(VReg)) && !IsConstantOpcode(MI) &&
3180112123eSMarcello Maggioni LookThroughInstrs) {
319e77e5f44SQuentin Colombet switch (MI->getOpcode()) {
320a6a72dfdSMirko Brkusanin case TargetOpcode::G_ANYEXT:
321a6a72dfdSMirko Brkusanin if (!LookThroughAnyExt)
322a6a72dfdSMirko Brkusanin return None;
323a6a72dfdSMirko Brkusanin LLVM_FALLTHROUGH;
324e77e5f44SQuentin Colombet case TargetOpcode::G_TRUNC:
325e77e5f44SQuentin Colombet case TargetOpcode::G_SEXT:
326e77e5f44SQuentin Colombet case TargetOpcode::G_ZEXT:
327e77e5f44SQuentin Colombet SeenOpcodes.push_back(std::make_pair(
328e77e5f44SQuentin Colombet MI->getOpcode(),
329e77e5f44SQuentin Colombet MRI.getType(MI->getOperand(0).getReg()).getSizeInBits()));
330e77e5f44SQuentin Colombet VReg = MI->getOperand(1).getReg();
331e77e5f44SQuentin Colombet break;
332e77e5f44SQuentin Colombet case TargetOpcode::COPY:
333e77e5f44SQuentin Colombet VReg = MI->getOperand(1).getReg();
3342bea69bfSDaniel Sanders if (Register::isPhysicalRegister(VReg))
335e77e5f44SQuentin Colombet return None;
336e77e5f44SQuentin Colombet break;
3377a4d2df0SAmara Emerson case TargetOpcode::G_INTTOPTR:
3387a4d2df0SAmara Emerson VReg = MI->getOperand(1).getReg();
3397a4d2df0SAmara Emerson break;
340e77e5f44SQuentin Colombet default:
341e77e5f44SQuentin Colombet return None;
342e77e5f44SQuentin Colombet }
343e77e5f44SQuentin Colombet }
344d477a7c2SPetar Avramovic if (!MI || !IsConstantOpcode(MI))
34575ad9ccbSAditya Nandakumar return None;
34675ad9ccbSAditya Nandakumar
347d477a7c2SPetar Avramovic Optional<APInt> MaybeVal = getAPCstValue(MI);
3480112123eSMarcello Maggioni if (!MaybeVal)
3490112123eSMarcello Maggioni return None;
3500112123eSMarcello Maggioni APInt &Val = *MaybeVal;
351e77e5f44SQuentin Colombet while (!SeenOpcodes.empty()) {
352e77e5f44SQuentin Colombet std::pair<unsigned, unsigned> OpcodeAndSize = SeenOpcodes.pop_back_val();
353e77e5f44SQuentin Colombet switch (OpcodeAndSize.first) {
354e77e5f44SQuentin Colombet case TargetOpcode::G_TRUNC:
355e77e5f44SQuentin Colombet Val = Val.trunc(OpcodeAndSize.second);
356e77e5f44SQuentin Colombet break;
357a6a72dfdSMirko Brkusanin case TargetOpcode::G_ANYEXT:
358e77e5f44SQuentin Colombet case TargetOpcode::G_SEXT:
359e77e5f44SQuentin Colombet Val = Val.sext(OpcodeAndSize.second);
360e77e5f44SQuentin Colombet break;
361e77e5f44SQuentin Colombet case TargetOpcode::G_ZEXT:
362e77e5f44SQuentin Colombet Val = Val.zext(OpcodeAndSize.second);
363e77e5f44SQuentin Colombet break;
364e77e5f44SQuentin Colombet }
365e77e5f44SQuentin Colombet }
36675ad9ccbSAditya Nandakumar
367581d13f8SMatt Arsenault return ValueAndVReg{Val, VReg};
36875ad9ccbSAditya Nandakumar }
3692a735421SAditya Nandakumar
isIConstant(const MachineInstr * MI)370d477a7c2SPetar Avramovic bool isIConstant(const MachineInstr *MI) {
371d477a7c2SPetar Avramovic if (!MI)
372d477a7c2SPetar Avramovic return false;
373d477a7c2SPetar Avramovic return MI->getOpcode() == TargetOpcode::G_CONSTANT;
374d477a7c2SPetar Avramovic }
375d477a7c2SPetar Avramovic
isFConstant(const MachineInstr * MI)376d477a7c2SPetar Avramovic bool isFConstant(const MachineInstr *MI) {
377d477a7c2SPetar Avramovic if (!MI)
378d477a7c2SPetar Avramovic return false;
379d477a7c2SPetar Avramovic return MI->getOpcode() == TargetOpcode::G_FCONSTANT;
380d477a7c2SPetar Avramovic }
381d477a7c2SPetar Avramovic
isAnyConstant(const MachineInstr * MI)382d477a7c2SPetar Avramovic bool isAnyConstant(const MachineInstr *MI) {
383d477a7c2SPetar Avramovic if (!MI)
384d477a7c2SPetar Avramovic return false;
385d477a7c2SPetar Avramovic unsigned Opc = MI->getOpcode();
386d477a7c2SPetar Avramovic return Opc == TargetOpcode::G_CONSTANT || Opc == TargetOpcode::G_FCONSTANT;
387d477a7c2SPetar Avramovic }
388d477a7c2SPetar Avramovic
getCImmAsAPInt(const MachineInstr * MI)389d477a7c2SPetar Avramovic Optional<APInt> getCImmAsAPInt(const MachineInstr *MI) {
390d477a7c2SPetar Avramovic const MachineOperand &CstVal = MI->getOperand(1);
391d477a7c2SPetar Avramovic if (CstVal.isCImm())
392d477a7c2SPetar Avramovic return CstVal.getCImm()->getValue();
393d477a7c2SPetar Avramovic return None;
394d477a7c2SPetar Avramovic }
395d477a7c2SPetar Avramovic
getCImmOrFPImmAsAPInt(const MachineInstr * MI)396d477a7c2SPetar Avramovic Optional<APInt> getCImmOrFPImmAsAPInt(const MachineInstr *MI) {
397d477a7c2SPetar Avramovic const MachineOperand &CstVal = MI->getOperand(1);
398d477a7c2SPetar Avramovic if (CstVal.isCImm())
399d477a7c2SPetar Avramovic return CstVal.getCImm()->getValue();
400d477a7c2SPetar Avramovic if (CstVal.isFPImm())
401d477a7c2SPetar Avramovic return CstVal.getFPImm()->getValueAPF().bitcastToAPInt();
402d477a7c2SPetar Avramovic return None;
403d477a7c2SPetar Avramovic }
404d477a7c2SPetar Avramovic
405d477a7c2SPetar Avramovic } // end anonymous namespace
406d477a7c2SPetar Avramovic
getIConstantVRegValWithLookThrough(Register VReg,const MachineRegisterInfo & MRI,bool LookThroughInstrs)407d477a7c2SPetar Avramovic Optional<ValueAndVReg> llvm::getIConstantVRegValWithLookThrough(
408d477a7c2SPetar Avramovic Register VReg, const MachineRegisterInfo &MRI, bool LookThroughInstrs) {
409d477a7c2SPetar Avramovic return getConstantVRegValWithLookThrough(VReg, MRI, isIConstant,
410d477a7c2SPetar Avramovic getCImmAsAPInt, LookThroughInstrs);
411d477a7c2SPetar Avramovic }
412d477a7c2SPetar Avramovic
getAnyConstantVRegValWithLookThrough(Register VReg,const MachineRegisterInfo & MRI,bool LookThroughInstrs,bool LookThroughAnyExt)413d477a7c2SPetar Avramovic Optional<ValueAndVReg> llvm::getAnyConstantVRegValWithLookThrough(
414d477a7c2SPetar Avramovic Register VReg, const MachineRegisterInfo &MRI, bool LookThroughInstrs,
415d477a7c2SPetar Avramovic bool LookThroughAnyExt) {
416d477a7c2SPetar Avramovic return getConstantVRegValWithLookThrough(
417d477a7c2SPetar Avramovic VReg, MRI, isAnyConstant, getCImmOrFPImmAsAPInt, LookThroughInstrs,
418d477a7c2SPetar Avramovic LookThroughAnyExt);
419d477a7c2SPetar Avramovic }
420d477a7c2SPetar Avramovic
getFConstantVRegValWithLookThrough(Register VReg,const MachineRegisterInfo & MRI,bool LookThroughInstrs)421d477a7c2SPetar Avramovic Optional<FPValueAndVReg> llvm::getFConstantVRegValWithLookThrough(
422d477a7c2SPetar Avramovic Register VReg, const MachineRegisterInfo &MRI, bool LookThroughInstrs) {
423d477a7c2SPetar Avramovic auto Reg = getConstantVRegValWithLookThrough(
424d477a7c2SPetar Avramovic VReg, MRI, isFConstant, getCImmOrFPImmAsAPInt, LookThroughInstrs);
425d477a7c2SPetar Avramovic if (!Reg)
426d477a7c2SPetar Avramovic return None;
427d477a7c2SPetar Avramovic return FPValueAndVReg{getConstantFPVRegVal(Reg->VReg, MRI)->getValueAPF(),
428d477a7c2SPetar Avramovic Reg->VReg};
4290713c82bSPetar Avramovic }
4300713c82bSPetar Avramovic
43104a288f0SMatt Arsenault const ConstantFP *
getConstantFPVRegVal(Register VReg,const MachineRegisterInfo & MRI)432ce963363SShu-Chun Weng llvm::getConstantFPVRegVal(Register VReg, const MachineRegisterInfo &MRI) {
4332a735421SAditya Nandakumar MachineInstr *MI = MRI.getVRegDef(VReg);
4342a735421SAditya Nandakumar if (TargetOpcode::G_FCONSTANT != MI->getOpcode())
4352a735421SAditya Nandakumar return nullptr;
4362a735421SAditya Nandakumar return MI->getOperand(1).getFPImm();
4372a735421SAditya Nandakumar }
438954eea07SAditya Nandakumar
439c67e1a98SMatt Arsenault Optional<DefinitionAndSourceRegister>
getDefSrcRegIgnoringCopies(Register Reg,const MachineRegisterInfo & MRI)440c67e1a98SMatt Arsenault llvm::getDefSrcRegIgnoringCopies(Register Reg, const MachineRegisterInfo &MRI) {
441ce963363SShu-Chun Weng Register DefSrcReg = Reg;
442954eea07SAditya Nandakumar auto *DefMI = MRI.getVRegDef(Reg);
443954eea07SAditya Nandakumar auto DstTy = MRI.getType(DefMI->getOperand(0).getReg());
444954eea07SAditya Nandakumar if (!DstTy.isValid())
445ce963363SShu-Chun Weng return None;
446daffab19SJessica Paquette unsigned Opc = DefMI->getOpcode();
447daffab19SJessica Paquette while (Opc == TargetOpcode::COPY || isPreISelGenericOptimizationHint(Opc)) {
4480c476111SDaniel Sanders Register SrcReg = DefMI->getOperand(1).getReg();
449954eea07SAditya Nandakumar auto SrcTy = MRI.getType(SrcReg);
450924f31bcSMatt Arsenault if (!SrcTy.isValid())
451954eea07SAditya Nandakumar break;
452954eea07SAditya Nandakumar DefMI = MRI.getVRegDef(SrcReg);
453ce963363SShu-Chun Weng DefSrcReg = SrcReg;
454daffab19SJessica Paquette Opc = DefMI->getOpcode();
455954eea07SAditya Nandakumar }
456ce963363SShu-Chun Weng return DefinitionAndSourceRegister{DefMI, DefSrcReg};
457ce963363SShu-Chun Weng }
458ce963363SShu-Chun Weng
getDefIgnoringCopies(Register Reg,const MachineRegisterInfo & MRI)45904a288f0SMatt Arsenault MachineInstr *llvm::getDefIgnoringCopies(Register Reg,
460ce963363SShu-Chun Weng const MachineRegisterInfo &MRI) {
461ce963363SShu-Chun Weng Optional<DefinitionAndSourceRegister> DefSrcReg =
462ce963363SShu-Chun Weng getDefSrcRegIgnoringCopies(Reg, MRI);
463ce963363SShu-Chun Weng return DefSrcReg ? DefSrcReg->MI : nullptr;
464ce963363SShu-Chun Weng }
465ce963363SShu-Chun Weng
getSrcRegIgnoringCopies(Register Reg,const MachineRegisterInfo & MRI)466ce963363SShu-Chun Weng Register llvm::getSrcRegIgnoringCopies(Register Reg,
467ce963363SShu-Chun Weng const MachineRegisterInfo &MRI) {
468ce963363SShu-Chun Weng Optional<DefinitionAndSourceRegister> DefSrcReg =
469ce963363SShu-Chun Weng getDefSrcRegIgnoringCopies(Reg, MRI);
470ce963363SShu-Chun Weng return DefSrcReg ? DefSrcReg->Reg : Register();
47114a44951SMatt Arsenault }
47214a44951SMatt Arsenault
getOpcodeDef(unsigned Opcode,Register Reg,const MachineRegisterInfo & MRI)47304a288f0SMatt Arsenault MachineInstr *llvm::getOpcodeDef(unsigned Opcode, Register Reg,
47414a44951SMatt Arsenault const MachineRegisterInfo &MRI) {
47514a44951SMatt Arsenault MachineInstr *DefMI = getDefIgnoringCopies(Reg, MRI);
47614a44951SMatt Arsenault return DefMI && DefMI->getOpcode() == Opcode ? DefMI : nullptr;
477954eea07SAditya Nandakumar }
47891fc4e09SAditya Nandakumar
getAPFloatFromSize(double Val,unsigned Size)47991fc4e09SAditya Nandakumar APFloat llvm::getAPFloatFromSize(double Val, unsigned Size) {
48091fc4e09SAditya Nandakumar if (Size == 32)
48191fc4e09SAditya Nandakumar return APFloat(float(Val));
48291fc4e09SAditya Nandakumar if (Size == 64)
48391fc4e09SAditya Nandakumar return APFloat(Val);
48491fc4e09SAditya Nandakumar if (Size != 16)
48591fc4e09SAditya Nandakumar llvm_unreachable("Unsupported FPConstant size");
48691fc4e09SAditya Nandakumar bool Ignored;
48791fc4e09SAditya Nandakumar APFloat APF(Val);
48891fc4e09SAditya Nandakumar APF.convert(APFloat::IEEEhalf(), APFloat::rmNearestTiesToEven, &Ignored);
48991fc4e09SAditya Nandakumar return APF;
49091fc4e09SAditya Nandakumar }
49190ad6835SMatthias Braun
ConstantFoldBinOp(unsigned Opcode,const Register Op1,const Register Op2,const MachineRegisterInfo & MRI)4925f7e38d8SMatt Arsenault Optional<APInt> llvm::ConstantFoldBinOp(unsigned Opcode, const Register Op1,
4935f7e38d8SMatt Arsenault const Register Op2,
494500e3eadSAditya Nandakumar const MachineRegisterInfo &MRI) {
495d477a7c2SPetar Avramovic auto MaybeOp2Cst = getAnyConstantVRegValWithLookThrough(Op2, MRI, false);
4968a3340d2SMatt Arsenault if (!MaybeOp2Cst)
4978a3340d2SMatt Arsenault return None;
4988a3340d2SMatt Arsenault
499d477a7c2SPetar Avramovic auto MaybeOp1Cst = getAnyConstantVRegValWithLookThrough(Op1, MRI, false);
5008a3340d2SMatt Arsenault if (!MaybeOp1Cst)
5018a3340d2SMatt Arsenault return None;
5028a3340d2SMatt Arsenault
503d477a7c2SPetar Avramovic const APInt &C1 = MaybeOp1Cst->Value;
504d477a7c2SPetar Avramovic const APInt &C2 = MaybeOp2Cst->Value;
505500e3eadSAditya Nandakumar switch (Opcode) {
506500e3eadSAditya Nandakumar default:
507500e3eadSAditya Nandakumar break;
508500e3eadSAditya Nandakumar case TargetOpcode::G_ADD:
5095af0f097SMatt Arsenault case TargetOpcode::G_PTR_ADD:
510500e3eadSAditya Nandakumar return C1 + C2;
511500e3eadSAditya Nandakumar case TargetOpcode::G_AND:
512500e3eadSAditya Nandakumar return C1 & C2;
513500e3eadSAditya Nandakumar case TargetOpcode::G_ASHR:
514500e3eadSAditya Nandakumar return C1.ashr(C2);
515500e3eadSAditya Nandakumar case TargetOpcode::G_LSHR:
516500e3eadSAditya Nandakumar return C1.lshr(C2);
517500e3eadSAditya Nandakumar case TargetOpcode::G_MUL:
518500e3eadSAditya Nandakumar return C1 * C2;
519500e3eadSAditya Nandakumar case TargetOpcode::G_OR:
520500e3eadSAditya Nandakumar return C1 | C2;
521500e3eadSAditya Nandakumar case TargetOpcode::G_SHL:
522500e3eadSAditya Nandakumar return C1 << C2;
523500e3eadSAditya Nandakumar case TargetOpcode::G_SUB:
524500e3eadSAditya Nandakumar return C1 - C2;
525500e3eadSAditya Nandakumar case TargetOpcode::G_XOR:
526500e3eadSAditya Nandakumar return C1 ^ C2;
527500e3eadSAditya Nandakumar case TargetOpcode::G_UDIV:
528500e3eadSAditya Nandakumar if (!C2.getBoolValue())
529500e3eadSAditya Nandakumar break;
530500e3eadSAditya Nandakumar return C1.udiv(C2);
531500e3eadSAditya Nandakumar case TargetOpcode::G_SDIV:
532500e3eadSAditya Nandakumar if (!C2.getBoolValue())
533500e3eadSAditya Nandakumar break;
534500e3eadSAditya Nandakumar return C1.sdiv(C2);
535500e3eadSAditya Nandakumar case TargetOpcode::G_UREM:
536500e3eadSAditya Nandakumar if (!C2.getBoolValue())
537500e3eadSAditya Nandakumar break;
538500e3eadSAditya Nandakumar return C1.urem(C2);
539500e3eadSAditya Nandakumar case TargetOpcode::G_SREM:
540500e3eadSAditya Nandakumar if (!C2.getBoolValue())
541500e3eadSAditya Nandakumar break;
542500e3eadSAditya Nandakumar return C1.srem(C2);
543930f2498SMatt Arsenault case TargetOpcode::G_SMIN:
544930f2498SMatt Arsenault return APIntOps::smin(C1, C2);
545930f2498SMatt Arsenault case TargetOpcode::G_SMAX:
546930f2498SMatt Arsenault return APIntOps::smax(C1, C2);
547930f2498SMatt Arsenault case TargetOpcode::G_UMIN:
548930f2498SMatt Arsenault return APIntOps::umin(C1, C2);
549930f2498SMatt Arsenault case TargetOpcode::G_UMAX:
550930f2498SMatt Arsenault return APIntOps::umax(C1, C2);
551500e3eadSAditya Nandakumar }
5528a3340d2SMatt Arsenault
553500e3eadSAditya Nandakumar return None;
554500e3eadSAditya Nandakumar }
555500e3eadSAditya Nandakumar
ConstantFoldFPBinOp(unsigned Opcode,const Register Op1,const Register Op2,const MachineRegisterInfo & MRI)5569fdfd8ddSMatt Arsenault Optional<APFloat> llvm::ConstantFoldFPBinOp(unsigned Opcode, const Register Op1,
5579fdfd8ddSMatt Arsenault const Register Op2,
5589fdfd8ddSMatt Arsenault const MachineRegisterInfo &MRI) {
5599fdfd8ddSMatt Arsenault const ConstantFP *Op2Cst = getConstantFPVRegVal(Op2, MRI);
5609fdfd8ddSMatt Arsenault if (!Op2Cst)
5619fdfd8ddSMatt Arsenault return None;
5629fdfd8ddSMatt Arsenault
5639fdfd8ddSMatt Arsenault const ConstantFP *Op1Cst = getConstantFPVRegVal(Op1, MRI);
5649fdfd8ddSMatt Arsenault if (!Op1Cst)
5659fdfd8ddSMatt Arsenault return None;
5669fdfd8ddSMatt Arsenault
5679fdfd8ddSMatt Arsenault APFloat C1 = Op1Cst->getValueAPF();
5689fdfd8ddSMatt Arsenault const APFloat &C2 = Op2Cst->getValueAPF();
5699fdfd8ddSMatt Arsenault switch (Opcode) {
5709fdfd8ddSMatt Arsenault case TargetOpcode::G_FADD:
5719fdfd8ddSMatt Arsenault C1.add(C2, APFloat::rmNearestTiesToEven);
5729fdfd8ddSMatt Arsenault return C1;
5739fdfd8ddSMatt Arsenault case TargetOpcode::G_FSUB:
5749fdfd8ddSMatt Arsenault C1.subtract(C2, APFloat::rmNearestTiesToEven);
5759fdfd8ddSMatt Arsenault return C1;
5769fdfd8ddSMatt Arsenault case TargetOpcode::G_FMUL:
5779fdfd8ddSMatt Arsenault C1.multiply(C2, APFloat::rmNearestTiesToEven);
5789fdfd8ddSMatt Arsenault return C1;
5799fdfd8ddSMatt Arsenault case TargetOpcode::G_FDIV:
5809fdfd8ddSMatt Arsenault C1.divide(C2, APFloat::rmNearestTiesToEven);
5819fdfd8ddSMatt Arsenault return C1;
5829fdfd8ddSMatt Arsenault case TargetOpcode::G_FREM:
5839fdfd8ddSMatt Arsenault C1.mod(C2);
5849fdfd8ddSMatt Arsenault return C1;
5859fdfd8ddSMatt Arsenault case TargetOpcode::G_FCOPYSIGN:
5869fdfd8ddSMatt Arsenault C1.copySign(C2);
5879fdfd8ddSMatt Arsenault return C1;
5889fdfd8ddSMatt Arsenault case TargetOpcode::G_FMINNUM:
5899fdfd8ddSMatt Arsenault return minnum(C1, C2);
5909fdfd8ddSMatt Arsenault case TargetOpcode::G_FMAXNUM:
5919fdfd8ddSMatt Arsenault return maxnum(C1, C2);
5929fdfd8ddSMatt Arsenault case TargetOpcode::G_FMINIMUM:
5939fdfd8ddSMatt Arsenault return minimum(C1, C2);
5949fdfd8ddSMatt Arsenault case TargetOpcode::G_FMAXIMUM:
5959fdfd8ddSMatt Arsenault return maximum(C1, C2);
5969fdfd8ddSMatt Arsenault case TargetOpcode::G_FMINNUM_IEEE:
5979fdfd8ddSMatt Arsenault case TargetOpcode::G_FMAXNUM_IEEE:
5989fdfd8ddSMatt Arsenault // FIXME: These operations were unfortunately named. fminnum/fmaxnum do not
5999fdfd8ddSMatt Arsenault // follow the IEEE behavior for signaling nans and follow libm's fmin/fmax,
6009fdfd8ddSMatt Arsenault // and currently there isn't a nice wrapper in APFloat for the version with
6019fdfd8ddSMatt Arsenault // correct snan handling.
6029fdfd8ddSMatt Arsenault break;
6039fdfd8ddSMatt Arsenault default:
6049fdfd8ddSMatt Arsenault break;
6059fdfd8ddSMatt Arsenault }
6069fdfd8ddSMatt Arsenault
6079fdfd8ddSMatt Arsenault return None;
6089fdfd8ddSMatt Arsenault }
6099fdfd8ddSMatt Arsenault
61026e1ebd3SJay Foad SmallVector<APInt>
ConstantFoldVectorBinop(unsigned Opcode,const Register Op1,const Register Op2,const MachineRegisterInfo & MRI)61126e1ebd3SJay Foad llvm::ConstantFoldVectorBinop(unsigned Opcode, const Register Op1,
6125abce56eSAmara Emerson const Register Op2,
61326e1ebd3SJay Foad const MachineRegisterInfo &MRI) {
6145abce56eSAmara Emerson auto *SrcVec2 = getOpcodeDef<GBuildVector>(Op2, MRI);
6155abce56eSAmara Emerson if (!SrcVec2)
61626e1ebd3SJay Foad return SmallVector<APInt>();
6175abce56eSAmara Emerson
6185599c431SMatt Arsenault auto *SrcVec1 = getOpcodeDef<GBuildVector>(Op1, MRI);
6195599c431SMatt Arsenault if (!SrcVec1)
62026e1ebd3SJay Foad return SmallVector<APInt>();
6215599c431SMatt Arsenault
62226e1ebd3SJay Foad SmallVector<APInt> FoldedElements;
6235abce56eSAmara Emerson for (unsigned Idx = 0, E = SrcVec1->getNumSources(); Idx < E; ++Idx) {
6245abce56eSAmara Emerson auto MaybeCst = ConstantFoldBinOp(Opcode, SrcVec1->getSourceReg(Idx),
6255abce56eSAmara Emerson SrcVec2->getSourceReg(Idx), MRI);
6265abce56eSAmara Emerson if (!MaybeCst)
62726e1ebd3SJay Foad return SmallVector<APInt>();
62826e1ebd3SJay Foad FoldedElements.push_back(*MaybeCst);
6295abce56eSAmara Emerson }
63026e1ebd3SJay Foad return FoldedElements;
6315abce56eSAmara Emerson }
6325abce56eSAmara Emerson
isKnownNeverNaN(Register Val,const MachineRegisterInfo & MRI,bool SNaN)6336ce1b4feSMatt Arsenault bool llvm::isKnownNeverNaN(Register Val, const MachineRegisterInfo &MRI,
6346ce1b4feSMatt Arsenault bool SNaN) {
6356ce1b4feSMatt Arsenault const MachineInstr *DefMI = MRI.getVRegDef(Val);
6366ce1b4feSMatt Arsenault if (!DefMI)
6376ce1b4feSMatt Arsenault return false;
6386ce1b4feSMatt Arsenault
6396e2a86edSPetar Avramovic const TargetMachine& TM = DefMI->getMF()->getTarget();
6406e2a86edSPetar Avramovic if (DefMI->getFlag(MachineInstr::FmNoNans) || TM.Options.NoNaNsFPMath)
6416ce1b4feSMatt Arsenault return true;
6426ce1b4feSMatt Arsenault
643122c649cSPetar Avramovic // If the value is a constant, we can obviously see if it is a NaN or not.
644122c649cSPetar Avramovic if (const ConstantFP *FPVal = getConstantFPVRegVal(Val, MRI)) {
645122c649cSPetar Avramovic return !FPVal->getValueAPF().isNaN() ||
646122c649cSPetar Avramovic (SNaN && !FPVal->getValueAPF().isSignaling());
647122c649cSPetar Avramovic }
648122c649cSPetar Avramovic
649122c649cSPetar Avramovic if (DefMI->getOpcode() == TargetOpcode::G_BUILD_VECTOR) {
650122c649cSPetar Avramovic for (const auto &Op : DefMI->uses())
651122c649cSPetar Avramovic if (!isKnownNeverNaN(Op.getReg(), MRI, SNaN))
652122c649cSPetar Avramovic return false;
653122c649cSPetar Avramovic return true;
654122c649cSPetar Avramovic }
655122c649cSPetar Avramovic
656f0d65f40SPetar Avramovic switch (DefMI->getOpcode()) {
657f0d65f40SPetar Avramovic default:
658f0d65f40SPetar Avramovic break;
659f0d65f40SPetar Avramovic case TargetOpcode::G_FMINNUM_IEEE:
660f0d65f40SPetar Avramovic case TargetOpcode::G_FMAXNUM_IEEE: {
661f0d65f40SPetar Avramovic if (SNaN)
662f0d65f40SPetar Avramovic return true;
663f0d65f40SPetar Avramovic // This can return a NaN if either operand is an sNaN, or if both operands
664f0d65f40SPetar Avramovic // are NaN.
665f0d65f40SPetar Avramovic return (isKnownNeverNaN(DefMI->getOperand(1).getReg(), MRI) &&
666f0d65f40SPetar Avramovic isKnownNeverSNaN(DefMI->getOperand(2).getReg(), MRI)) ||
667f0d65f40SPetar Avramovic (isKnownNeverSNaN(DefMI->getOperand(1).getReg(), MRI) &&
668f0d65f40SPetar Avramovic isKnownNeverNaN(DefMI->getOperand(2).getReg(), MRI));
669f0d65f40SPetar Avramovic }
670f0d65f40SPetar Avramovic case TargetOpcode::G_FMINNUM:
671f0d65f40SPetar Avramovic case TargetOpcode::G_FMAXNUM: {
672f0d65f40SPetar Avramovic // Only one needs to be known not-nan, since it will be returned if the
673f0d65f40SPetar Avramovic // other ends up being one.
674f0d65f40SPetar Avramovic return isKnownNeverNaN(DefMI->getOperand(1).getReg(), MRI, SNaN) ||
675f0d65f40SPetar Avramovic isKnownNeverNaN(DefMI->getOperand(2).getReg(), MRI, SNaN);
676f0d65f40SPetar Avramovic }
677f0d65f40SPetar Avramovic }
678f0d65f40SPetar Avramovic
6796ce1b4feSMatt Arsenault if (SNaN) {
6806ce1b4feSMatt Arsenault // FP operations quiet. For now, just handle the ones inserted during
6816ce1b4feSMatt Arsenault // legalization.
6826ce1b4feSMatt Arsenault switch (DefMI->getOpcode()) {
6836ce1b4feSMatt Arsenault case TargetOpcode::G_FPEXT:
6846ce1b4feSMatt Arsenault case TargetOpcode::G_FPTRUNC:
6856ce1b4feSMatt Arsenault case TargetOpcode::G_FCANONICALIZE:
6866ce1b4feSMatt Arsenault return true;
6876ce1b4feSMatt Arsenault default:
6886ce1b4feSMatt Arsenault return false;
6896ce1b4feSMatt Arsenault }
6906ce1b4feSMatt Arsenault }
6916ce1b4feSMatt Arsenault
6926ce1b4feSMatt Arsenault return false;
6936ce1b4feSMatt Arsenault }
6946ce1b4feSMatt Arsenault
inferAlignFromPtrInfo(MachineFunction & MF,const MachinePointerInfo & MPO)695d2d6c9f5SGuillaume Chatelet Align llvm::inferAlignFromPtrInfo(MachineFunction &MF,
696fb0c35faSMatt Arsenault const MachinePointerInfo &MPO) {
697fb0c35faSMatt Arsenault auto PSV = MPO.V.dyn_cast<const PseudoSourceValue *>();
698fb0c35faSMatt Arsenault if (auto FSPV = dyn_cast_or_null<FixedStackPseudoSourceValue>(PSV)) {
699fb0c35faSMatt Arsenault MachineFrameInfo &MFI = MF.getFrameInfo();
700d2d6c9f5SGuillaume Chatelet return commonAlignment(MFI.getObjectAlign(FSPV->getFrameIndex()),
701d2d6c9f5SGuillaume Chatelet MPO.Offset);
702fb0c35faSMatt Arsenault }
703fb0c35faSMatt Arsenault
704b9a03849SMatt Arsenault if (const Value *V = MPO.V.dyn_cast<const Value *>()) {
705b9a03849SMatt Arsenault const Module *M = MF.getFunction().getParent();
706b9a03849SMatt Arsenault return V->getPointerAlignment(M->getDataLayout());
707b9a03849SMatt Arsenault }
708b9a03849SMatt Arsenault
709d2d6c9f5SGuillaume Chatelet return Align(1);
710fb0c35faSMatt Arsenault }
711fb0c35faSMatt Arsenault
getFunctionLiveInPhysReg(MachineFunction & MF,const TargetInstrInfo & TII,MCRegister PhysReg,const TargetRegisterClass & RC,const DebugLoc & DL,LLT RegTy)712f8fb7835SMatt Arsenault Register llvm::getFunctionLiveInPhysReg(MachineFunction &MF,
713f8fb7835SMatt Arsenault const TargetInstrInfo &TII,
714f8fb7835SMatt Arsenault MCRegister PhysReg,
715f8fb7835SMatt Arsenault const TargetRegisterClass &RC,
7160ba4e4b5SMatt Arsenault const DebugLoc &DL, LLT RegTy) {
717f8fb7835SMatt Arsenault MachineBasicBlock &EntryMBB = MF.front();
718f8fb7835SMatt Arsenault MachineRegisterInfo &MRI = MF.getRegInfo();
719f8fb7835SMatt Arsenault Register LiveIn = MRI.getLiveInVirtReg(PhysReg);
720f8fb7835SMatt Arsenault if (LiveIn) {
721f8fb7835SMatt Arsenault MachineInstr *Def = MRI.getVRegDef(LiveIn);
722f8fb7835SMatt Arsenault if (Def) {
723f8fb7835SMatt Arsenault // FIXME: Should the verifier check this is in the entry block?
724f8fb7835SMatt Arsenault assert(Def->getParent() == &EntryMBB && "live-in copy not in entry block");
725f8fb7835SMatt Arsenault return LiveIn;
726f8fb7835SMatt Arsenault }
727f8fb7835SMatt Arsenault
728f8fb7835SMatt Arsenault // It's possible the incoming argument register and copy was added during
729f8fb7835SMatt Arsenault // lowering, but later deleted due to being/becoming dead. If this happens,
730f8fb7835SMatt Arsenault // re-insert the copy.
731f8fb7835SMatt Arsenault } else {
732f8fb7835SMatt Arsenault // The live in register was not present, so add it.
733f8fb7835SMatt Arsenault LiveIn = MF.addLiveIn(PhysReg, &RC);
734f8fb7835SMatt Arsenault if (RegTy.isValid())
735f8fb7835SMatt Arsenault MRI.setType(LiveIn, RegTy);
736f8fb7835SMatt Arsenault }
737f8fb7835SMatt Arsenault
738f8fb7835SMatt Arsenault BuildMI(EntryMBB, EntryMBB.begin(), DL, TII.get(TargetOpcode::COPY), LiveIn)
739f8fb7835SMatt Arsenault .addReg(PhysReg);
740f8fb7835SMatt Arsenault if (!EntryMBB.isLiveIn(PhysReg))
741f8fb7835SMatt Arsenault EntryMBB.addLiveIn(PhysReg);
742f8fb7835SMatt Arsenault return LiveIn;
743f8fb7835SMatt Arsenault }
744f8fb7835SMatt Arsenault
ConstantFoldExtOp(unsigned Opcode,const Register Op1,uint64_t Imm,const MachineRegisterInfo & MRI)7455f7e38d8SMatt Arsenault Optional<APInt> llvm::ConstantFoldExtOp(unsigned Opcode, const Register Op1,
746e9a57c2bSDaniel Sanders uint64_t Imm,
747e9a57c2bSDaniel Sanders const MachineRegisterInfo &MRI) {
748d477a7c2SPetar Avramovic auto MaybeOp1Cst = getIConstantVRegVal(Op1, MRI);
749e9a57c2bSDaniel Sanders if (MaybeOp1Cst) {
750e9a57c2bSDaniel Sanders switch (Opcode) {
751e9a57c2bSDaniel Sanders default:
752e9a57c2bSDaniel Sanders break;
753581d13f8SMatt Arsenault case TargetOpcode::G_SEXT_INREG: {
754581d13f8SMatt Arsenault LLT Ty = MRI.getType(Op1);
755581d13f8SMatt Arsenault return MaybeOp1Cst->trunc(Imm).sext(Ty.getScalarSizeInBits());
756581d13f8SMatt Arsenault }
757e9a57c2bSDaniel Sanders }
758e9a57c2bSDaniel Sanders }
759e9a57c2bSDaniel Sanders return None;
760e9a57c2bSDaniel Sanders }
761e9a57c2bSDaniel Sanders
ConstantFoldIntToFloat(unsigned Opcode,LLT DstTy,Register Src,const MachineRegisterInfo & MRI)762dc4ca0dbSJay Foad Optional<APFloat> llvm::ConstantFoldIntToFloat(unsigned Opcode, LLT DstTy,
763dc4ca0dbSJay Foad Register Src,
764dc4ca0dbSJay Foad const MachineRegisterInfo &MRI) {
765dc4ca0dbSJay Foad assert(Opcode == TargetOpcode::G_SITOFP || Opcode == TargetOpcode::G_UITOFP);
766d477a7c2SPetar Avramovic if (auto MaybeSrcVal = getIConstantVRegVal(Src, MRI)) {
767dc4ca0dbSJay Foad APFloat DstVal(getFltSemanticForLLT(DstTy));
768dc4ca0dbSJay Foad DstVal.convertFromAPInt(*MaybeSrcVal, Opcode == TargetOpcode::G_SITOFP,
769dc4ca0dbSJay Foad APFloat::rmNearestTiesToEven);
770dc4ca0dbSJay Foad return DstVal;
771dc4ca0dbSJay Foad }
772dc4ca0dbSJay Foad return None;
773dc4ca0dbSJay Foad }
774dc4ca0dbSJay Foad
77508b3c0d9SAmara Emerson Optional<SmallVector<unsigned>>
ConstantFoldCTLZ(Register Src,const MachineRegisterInfo & MRI)77608b3c0d9SAmara Emerson llvm::ConstantFoldCTLZ(Register Src, const MachineRegisterInfo &MRI) {
77708b3c0d9SAmara Emerson LLT Ty = MRI.getType(Src);
77808b3c0d9SAmara Emerson SmallVector<unsigned> FoldedCTLZs;
77908b3c0d9SAmara Emerson auto tryFoldScalar = [&](Register R) -> Optional<unsigned> {
78008b3c0d9SAmara Emerson auto MaybeCst = getIConstantVRegVal(R, MRI);
78108b3c0d9SAmara Emerson if (!MaybeCst)
78208b3c0d9SAmara Emerson return None;
78308b3c0d9SAmara Emerson return MaybeCst->countLeadingZeros();
78408b3c0d9SAmara Emerson };
78508b3c0d9SAmara Emerson if (Ty.isVector()) {
78608b3c0d9SAmara Emerson // Try to constant fold each element.
78708b3c0d9SAmara Emerson auto *BV = getOpcodeDef<GBuildVector>(Src, MRI);
78808b3c0d9SAmara Emerson if (!BV)
78908b3c0d9SAmara Emerson return None;
79008b3c0d9SAmara Emerson for (unsigned SrcIdx = 0; SrcIdx < BV->getNumSources(); ++SrcIdx) {
79108b3c0d9SAmara Emerson if (auto MaybeFold = tryFoldScalar(BV->getSourceReg(SrcIdx))) {
79208b3c0d9SAmara Emerson FoldedCTLZs.emplace_back(*MaybeFold);
79308b3c0d9SAmara Emerson continue;
79408b3c0d9SAmara Emerson }
79508b3c0d9SAmara Emerson return None;
79608b3c0d9SAmara Emerson }
79708b3c0d9SAmara Emerson return FoldedCTLZs;
79808b3c0d9SAmara Emerson }
79908b3c0d9SAmara Emerson if (auto MaybeCst = tryFoldScalar(Src)) {
80008b3c0d9SAmara Emerson FoldedCTLZs.emplace_back(*MaybeCst);
80108b3c0d9SAmara Emerson return FoldedCTLZs;
80208b3c0d9SAmara Emerson }
80308b3c0d9SAmara Emerson return None;
80408b3c0d9SAmara Emerson }
80508b3c0d9SAmara Emerson
isKnownToBeAPowerOfTwo(Register Reg,const MachineRegisterInfo & MRI,GISelKnownBits * KB)806a427f15dSMatt Arsenault bool llvm::isKnownToBeAPowerOfTwo(Register Reg, const MachineRegisterInfo &MRI,
807a427f15dSMatt Arsenault GISelKnownBits *KB) {
808a427f15dSMatt Arsenault Optional<DefinitionAndSourceRegister> DefSrcReg =
809a427f15dSMatt Arsenault getDefSrcRegIgnoringCopies(Reg, MRI);
810a427f15dSMatt Arsenault if (!DefSrcReg)
811a427f15dSMatt Arsenault return false;
812a427f15dSMatt Arsenault
813a427f15dSMatt Arsenault const MachineInstr &MI = *DefSrcReg->MI;
814a427f15dSMatt Arsenault const LLT Ty = MRI.getType(Reg);
815a427f15dSMatt Arsenault
816a427f15dSMatt Arsenault switch (MI.getOpcode()) {
817a427f15dSMatt Arsenault case TargetOpcode::G_CONSTANT: {
818a427f15dSMatt Arsenault unsigned BitWidth = Ty.getScalarSizeInBits();
819a427f15dSMatt Arsenault const ConstantInt *CI = MI.getOperand(1).getCImm();
820a427f15dSMatt Arsenault return CI->getValue().zextOrTrunc(BitWidth).isPowerOf2();
821a427f15dSMatt Arsenault }
822a427f15dSMatt Arsenault case TargetOpcode::G_SHL: {
823a427f15dSMatt Arsenault // A left-shift of a constant one will have exactly one bit set because
824a427f15dSMatt Arsenault // shifting the bit off the end is undefined.
825a427f15dSMatt Arsenault
826a427f15dSMatt Arsenault // TODO: Constant splat
827d477a7c2SPetar Avramovic if (auto ConstLHS = getIConstantVRegVal(MI.getOperand(1).getReg(), MRI)) {
828a427f15dSMatt Arsenault if (*ConstLHS == 1)
829a427f15dSMatt Arsenault return true;
830a427f15dSMatt Arsenault }
831a427f15dSMatt Arsenault
832a427f15dSMatt Arsenault break;
833a427f15dSMatt Arsenault }
834a427f15dSMatt Arsenault case TargetOpcode::G_LSHR: {
835d477a7c2SPetar Avramovic if (auto ConstLHS = getIConstantVRegVal(MI.getOperand(1).getReg(), MRI)) {
836a427f15dSMatt Arsenault if (ConstLHS->isSignMask())
837a427f15dSMatt Arsenault return true;
838a427f15dSMatt Arsenault }
839a427f15dSMatt Arsenault
840a427f15dSMatt Arsenault break;
841a427f15dSMatt Arsenault }
842c34819afSMatt Arsenault case TargetOpcode::G_BUILD_VECTOR: {
843c34819afSMatt Arsenault // TODO: Probably should have a recursion depth guard since you could have
844c34819afSMatt Arsenault // bitcasted vector elements.
845bfd5dd15SKazu Hirata for (const MachineOperand &MO : llvm::drop_begin(MI.operands()))
846bfd5dd15SKazu Hirata if (!isKnownToBeAPowerOfTwo(MO.getReg(), MRI, KB))
847c34819afSMatt Arsenault return false;
848c34819afSMatt Arsenault
849c34819afSMatt Arsenault return true;
850c34819afSMatt Arsenault }
851c34819afSMatt Arsenault case TargetOpcode::G_BUILD_VECTOR_TRUNC: {
852c34819afSMatt Arsenault // Only handle constants since we would need to know if number of leading
853c34819afSMatt Arsenault // zeros is greater than the truncation amount.
854c34819afSMatt Arsenault const unsigned BitWidth = Ty.getScalarSizeInBits();
855bfd5dd15SKazu Hirata for (const MachineOperand &MO : llvm::drop_begin(MI.operands())) {
856bfd5dd15SKazu Hirata auto Const = getIConstantVRegVal(MO.getReg(), MRI);
857c34819afSMatt Arsenault if (!Const || !Const->zextOrTrunc(BitWidth).isPowerOf2())
858c34819afSMatt Arsenault return false;
859c34819afSMatt Arsenault }
860c34819afSMatt Arsenault
861c34819afSMatt Arsenault return true;
862c34819afSMatt Arsenault }
863a427f15dSMatt Arsenault default:
864a427f15dSMatt Arsenault break;
865a427f15dSMatt Arsenault }
866a427f15dSMatt Arsenault
867a427f15dSMatt Arsenault if (!KB)
868a427f15dSMatt Arsenault return false;
869a427f15dSMatt Arsenault
870a427f15dSMatt Arsenault // More could be done here, though the above checks are enough
871a427f15dSMatt Arsenault // to handle some common cases.
872a427f15dSMatt Arsenault
873a427f15dSMatt Arsenault // Fall back to computeKnownBits to catch other known cases.
874a427f15dSMatt Arsenault KnownBits Known = KB->getKnownBits(Reg);
875a427f15dSMatt Arsenault return (Known.countMaxPopulation() == 1) && (Known.countMinPopulation() == 1);
876a427f15dSMatt Arsenault }
877a427f15dSMatt Arsenault
getSelectionDAGFallbackAnalysisUsage(AnalysisUsage & AU)87890ad6835SMatthias Braun void llvm::getSelectionDAGFallbackAnalysisUsage(AnalysisUsage &AU) {
87990ad6835SMatthias Braun AU.addPreserved<StackProtector>();
88090ad6835SMatthias Braun }
881b71203a7SMatt Arsenault
getLCMSize(unsigned OrigSize,unsigned TargetSize)8821ef3ed0eSMatt Arsenault static unsigned getLCMSize(unsigned OrigSize, unsigned TargetSize) {
8831ef3ed0eSMatt Arsenault unsigned Mul = OrigSize * TargetSize;
8841ef3ed0eSMatt Arsenault unsigned GCDSize = greatestCommonDivisor(OrigSize, TargetSize);
8851ef3ed0eSMatt Arsenault return Mul / GCDSize;
886b71203a7SMatt Arsenault }
887b71203a7SMatt Arsenault
getLCMType(LLT OrigTy,LLT TargetTy)8881ef3ed0eSMatt Arsenault LLT llvm::getLCMType(LLT OrigTy, LLT TargetTy) {
8891ef3ed0eSMatt Arsenault const unsigned OrigSize = OrigTy.getSizeInBits();
8901ef3ed0eSMatt Arsenault const unsigned TargetSize = TargetTy.getSizeInBits();
8911ef3ed0eSMatt Arsenault
8921ef3ed0eSMatt Arsenault if (OrigSize == TargetSize)
8931ef3ed0eSMatt Arsenault return OrigTy;
8941ef3ed0eSMatt Arsenault
8951ef3ed0eSMatt Arsenault if (OrigTy.isVector()) {
8961ef3ed0eSMatt Arsenault const LLT OrigElt = OrigTy.getElementType();
8971ef3ed0eSMatt Arsenault
8981ef3ed0eSMatt Arsenault if (TargetTy.isVector()) {
8991ef3ed0eSMatt Arsenault const LLT TargetElt = TargetTy.getElementType();
9001ef3ed0eSMatt Arsenault
9011ef3ed0eSMatt Arsenault if (OrigElt.getSizeInBits() == TargetElt.getSizeInBits()) {
9021ef3ed0eSMatt Arsenault int GCDElts = greatestCommonDivisor(OrigTy.getNumElements(),
9031ef3ed0eSMatt Arsenault TargetTy.getNumElements());
9041ef3ed0eSMatt Arsenault // Prefer the original element type.
905d5e14ba8SSander de Smalen ElementCount Mul = OrigTy.getElementCount() * TargetTy.getNumElements();
906d5e14ba8SSander de Smalen return LLT::vector(Mul.divideCoefficientBy(GCDElts),
907d5e14ba8SSander de Smalen OrigTy.getElementType());
9081ef3ed0eSMatt Arsenault }
9091ef3ed0eSMatt Arsenault } else {
9101ef3ed0eSMatt Arsenault if (OrigElt.getSizeInBits() == TargetSize)
9111ef3ed0eSMatt Arsenault return OrigTy;
912b71203a7SMatt Arsenault }
913b71203a7SMatt Arsenault
9141ef3ed0eSMatt Arsenault unsigned LCMSize = getLCMSize(OrigSize, TargetSize);
915d5e14ba8SSander de Smalen return LLT::fixed_vector(LCMSize / OrigElt.getSizeInBits(), OrigElt);
916b71203a7SMatt Arsenault }
917b71203a7SMatt Arsenault
9181ef3ed0eSMatt Arsenault if (TargetTy.isVector()) {
9191ef3ed0eSMatt Arsenault unsigned LCMSize = getLCMSize(OrigSize, TargetSize);
920d5e14ba8SSander de Smalen return LLT::fixed_vector(LCMSize / OrigSize, OrigTy);
921b71203a7SMatt Arsenault }
922b71203a7SMatt Arsenault
9231ef3ed0eSMatt Arsenault unsigned LCMSize = getLCMSize(OrigSize, TargetSize);
9241ef3ed0eSMatt Arsenault
9251ef3ed0eSMatt Arsenault // Preserve pointer types.
9261ef3ed0eSMatt Arsenault if (LCMSize == OrigSize)
9271ef3ed0eSMatt Arsenault return OrigTy;
9281ef3ed0eSMatt Arsenault if (LCMSize == TargetSize)
9291ef3ed0eSMatt Arsenault return TargetTy;
9301ef3ed0eSMatt Arsenault
9311ef3ed0eSMatt Arsenault return LLT::scalar(LCMSize);
932b71203a7SMatt Arsenault }
933b71203a7SMatt Arsenault
getCoverTy(LLT OrigTy,LLT TargetTy)93429f88b93SPetar Avramovic LLT llvm::getCoverTy(LLT OrigTy, LLT TargetTy) {
93529f88b93SPetar Avramovic if (!OrigTy.isVector() || !TargetTy.isVector() || OrigTy == TargetTy ||
93629f88b93SPetar Avramovic (OrigTy.getScalarSizeInBits() != TargetTy.getScalarSizeInBits()))
93729f88b93SPetar Avramovic return getLCMType(OrigTy, TargetTy);
93829f88b93SPetar Avramovic
93929f88b93SPetar Avramovic unsigned OrigTyNumElts = OrigTy.getNumElements();
94029f88b93SPetar Avramovic unsigned TargetTyNumElts = TargetTy.getNumElements();
94129f88b93SPetar Avramovic if (OrigTyNumElts % TargetTyNumElts == 0)
94229f88b93SPetar Avramovic return OrigTy;
94329f88b93SPetar Avramovic
94429f88b93SPetar Avramovic unsigned NumElts = alignTo(OrigTyNumElts, TargetTyNumElts);
94529f88b93SPetar Avramovic return LLT::scalarOrVector(ElementCount::getFixed(NumElts),
94629f88b93SPetar Avramovic OrigTy.getElementType());
94729f88b93SPetar Avramovic }
94829f88b93SPetar Avramovic
getGCDType(LLT OrigTy,LLT TargetTy)949b71203a7SMatt Arsenault LLT llvm::getGCDType(LLT OrigTy, LLT TargetTy) {
95012d5bec8SMatt Arsenault const unsigned OrigSize = OrigTy.getSizeInBits();
95112d5bec8SMatt Arsenault const unsigned TargetSize = TargetTy.getSizeInBits();
95212d5bec8SMatt Arsenault
95312d5bec8SMatt Arsenault if (OrigSize == TargetSize)
95412d5bec8SMatt Arsenault return OrigTy;
95512d5bec8SMatt Arsenault
95612d5bec8SMatt Arsenault if (OrigTy.isVector()) {
95712d5bec8SMatt Arsenault LLT OrigElt = OrigTy.getElementType();
95812d5bec8SMatt Arsenault if (TargetTy.isVector()) {
95912d5bec8SMatt Arsenault LLT TargetElt = TargetTy.getElementType();
96012d5bec8SMatt Arsenault if (OrigElt.getSizeInBits() == TargetElt.getSizeInBits()) {
961b71203a7SMatt Arsenault int GCD = greatestCommonDivisor(OrigTy.getNumElements(),
962b71203a7SMatt Arsenault TargetTy.getNumElements());
963968980efSSander de Smalen return LLT::scalarOrVector(ElementCount::getFixed(GCD), OrigElt);
96412d5bec8SMatt Arsenault }
96512d5bec8SMatt Arsenault } else {
96612d5bec8SMatt Arsenault // If the source is a vector of pointers, return a pointer element.
96712d5bec8SMatt Arsenault if (OrigElt.getSizeInBits() == TargetSize)
96812d5bec8SMatt Arsenault return OrigElt;
969b71203a7SMatt Arsenault }
970b71203a7SMatt Arsenault
97112d5bec8SMatt Arsenault unsigned GCD = greatestCommonDivisor(OrigSize, TargetSize);
97212d5bec8SMatt Arsenault if (GCD == OrigElt.getSizeInBits())
97312d5bec8SMatt Arsenault return OrigElt;
97412d5bec8SMatt Arsenault
97512d5bec8SMatt Arsenault // If we can't produce the original element type, we have to use a smaller
97612d5bec8SMatt Arsenault // scalar.
97712d5bec8SMatt Arsenault if (GCD < OrigElt.getSizeInBits())
97812d5bec8SMatt Arsenault return LLT::scalar(GCD);
979d5e14ba8SSander de Smalen return LLT::fixed_vector(GCD / OrigElt.getSizeInBits(), OrigElt);
980b71203a7SMatt Arsenault }
981b71203a7SMatt Arsenault
98212d5bec8SMatt Arsenault if (TargetTy.isVector()) {
98312d5bec8SMatt Arsenault // Try to preserve the original element type.
98412d5bec8SMatt Arsenault LLT TargetElt = TargetTy.getElementType();
98512d5bec8SMatt Arsenault if (TargetElt.getSizeInBits() == OrigSize)
98612d5bec8SMatt Arsenault return OrigTy;
98712d5bec8SMatt Arsenault }
988b71203a7SMatt Arsenault
98912d5bec8SMatt Arsenault unsigned GCD = greatestCommonDivisor(OrigSize, TargetSize);
990b71203a7SMatt Arsenault return LLT::scalar(GCD);
991b71203a7SMatt Arsenault }
992d8ba6222SAmara Emerson
getSplatIndex(MachineInstr & MI)993d8ba6222SAmara Emerson Optional<int> llvm::getSplatIndex(MachineInstr &MI) {
994d8ba6222SAmara Emerson assert(MI.getOpcode() == TargetOpcode::G_SHUFFLE_VECTOR &&
995d8ba6222SAmara Emerson "Only G_SHUFFLE_VECTOR can have a splat index!");
996d8ba6222SAmara Emerson ArrayRef<int> Mask = MI.getOperand(3).getShuffleMask();
997d8ba6222SAmara Emerson auto FirstDefinedIdx = find_if(Mask, [](int Elt) { return Elt >= 0; });
998d8ba6222SAmara Emerson
999d8ba6222SAmara Emerson // If all elements are undefined, this shuffle can be considered a splat.
1000d8ba6222SAmara Emerson // Return 0 for better potential for callers to simplify.
1001d8ba6222SAmara Emerson if (FirstDefinedIdx == Mask.end())
1002d8ba6222SAmara Emerson return 0;
1003d8ba6222SAmara Emerson
1004d8ba6222SAmara Emerson // Make sure all remaining elements are either undef or the same
1005d8ba6222SAmara Emerson // as the first non-undef value.
1006d8ba6222SAmara Emerson int SplatValue = *FirstDefinedIdx;
1007d8ba6222SAmara Emerson if (any_of(make_range(std::next(FirstDefinedIdx), Mask.end()),
1008d8ba6222SAmara Emerson [&SplatValue](int Elt) { return Elt >= 0 && Elt != SplatValue; }))
1009d8ba6222SAmara Emerson return None;
1010d8ba6222SAmara Emerson
1011d8ba6222SAmara Emerson return SplatValue;
1012d8ba6222SAmara Emerson }
10135c5e6d95SMatt Arsenault
isBuildVectorOp(unsigned Opcode)10145c5e6d95SMatt Arsenault static bool isBuildVectorOp(unsigned Opcode) {
10155c5e6d95SMatt Arsenault return Opcode == TargetOpcode::G_BUILD_VECTOR ||
10165c5e6d95SMatt Arsenault Opcode == TargetOpcode::G_BUILD_VECTOR_TRUNC;
10175c5e6d95SMatt Arsenault }
10185c5e6d95SMatt Arsenault
10198bc71856SPetar Avramovic namespace {
10208bc71856SPetar Avramovic
getAnyConstantSplat(Register VReg,const MachineRegisterInfo & MRI,bool AllowUndef)10218bc71856SPetar Avramovic Optional<ValueAndVReg> getAnyConstantSplat(Register VReg,
10225c5e6d95SMatt Arsenault const MachineRegisterInfo &MRI,
10238bc71856SPetar Avramovic bool AllowUndef) {
10248bc71856SPetar Avramovic MachineInstr *MI = getDefIgnoringCopies(VReg, MRI);
10258bc71856SPetar Avramovic if (!MI)
10268bc71856SPetar Avramovic return None;
10275c5e6d95SMatt Arsenault
10288bc71856SPetar Avramovic if (!isBuildVectorOp(MI->getOpcode()))
10298bc71856SPetar Avramovic return None;
10308bc71856SPetar Avramovic
10318bc71856SPetar Avramovic Optional<ValueAndVReg> SplatValAndReg = None;
10328bc71856SPetar Avramovic for (MachineOperand &Op : MI->uses()) {
10338bc71856SPetar Avramovic Register Element = Op.getReg();
10348bc71856SPetar Avramovic auto ElementValAndReg =
10358bc71856SPetar Avramovic getAnyConstantVRegValWithLookThrough(Element, MRI, true, true);
10368bc71856SPetar Avramovic
10378bc71856SPetar Avramovic // If AllowUndef, treat undef as value that will result in a constant splat.
10388bc71856SPetar Avramovic if (!ElementValAndReg) {
10398bc71856SPetar Avramovic if (AllowUndef && isa<GImplicitDef>(MRI.getVRegDef(Element)))
10408bc71856SPetar Avramovic continue;
10418bc71856SPetar Avramovic return None;
10428bc71856SPetar Avramovic }
10438bc71856SPetar Avramovic
10448bc71856SPetar Avramovic // Record splat value
10458bc71856SPetar Avramovic if (!SplatValAndReg)
10468bc71856SPetar Avramovic SplatValAndReg = ElementValAndReg;
10478bc71856SPetar Avramovic
10488bc71856SPetar Avramovic // Different constant then the one already recorded, not a constant splat.
10498bc71856SPetar Avramovic if (SplatValAndReg->Value != ElementValAndReg->Value)
10508bc71856SPetar Avramovic return None;
10518bc71856SPetar Avramovic }
10528bc71856SPetar Avramovic
10538bc71856SPetar Avramovic return SplatValAndReg;
10548bc71856SPetar Avramovic }
10558bc71856SPetar Avramovic
1056bc5dbb0bSAbinav Puthan Purayil } // end anonymous namespace
1057bc5dbb0bSAbinav Puthan Purayil
isBuildVectorConstantSplat(const Register Reg,const MachineRegisterInfo & MRI,int64_t SplatValue,bool AllowUndef)1058bc5dbb0bSAbinav Puthan Purayil bool llvm::isBuildVectorConstantSplat(const Register Reg,
10598bc71856SPetar Avramovic const MachineRegisterInfo &MRI,
10608bc71856SPetar Avramovic int64_t SplatValue, bool AllowUndef) {
1061bc5dbb0bSAbinav Puthan Purayil if (auto SplatValAndReg = getAnyConstantSplat(Reg, MRI, AllowUndef))
10628bc71856SPetar Avramovic return mi_match(SplatValAndReg->VReg, MRI, m_SpecificICst(SplatValue));
10635c5e6d95SMatt Arsenault return false;
10645c5e6d95SMatt Arsenault }
10655c5e6d95SMatt Arsenault
isBuildVectorConstantSplat(const MachineInstr & MI,const MachineRegisterInfo & MRI,int64_t SplatValue,bool AllowUndef)1066bc5dbb0bSAbinav Puthan Purayil bool llvm::isBuildVectorConstantSplat(const MachineInstr &MI,
1067bc5dbb0bSAbinav Puthan Purayil const MachineRegisterInfo &MRI,
1068bc5dbb0bSAbinav Puthan Purayil int64_t SplatValue, bool AllowUndef) {
1069bc5dbb0bSAbinav Puthan Purayil return isBuildVectorConstantSplat(MI.getOperand(0).getReg(), MRI, SplatValue,
1070bc5dbb0bSAbinav Puthan Purayil AllowUndef);
1071bc5dbb0bSAbinav Puthan Purayil }
10725c5e6d95SMatt Arsenault
getIConstantSplatVal(const Register Reg,const MachineRegisterInfo & MRI)1073485dd0b7SAbinav Puthan Purayil Optional<APInt> llvm::getIConstantSplatVal(const Register Reg,
1074520ab710SAmara Emerson const MachineRegisterInfo &MRI) {
10758bc71856SPetar Avramovic if (auto SplatValAndReg =
1076485dd0b7SAbinav Puthan Purayil getAnyConstantSplat(Reg, MRI, /* AllowUndef */ false)) {
1077485dd0b7SAbinav Puthan Purayil Optional<ValueAndVReg> ValAndVReg =
1078485dd0b7SAbinav Puthan Purayil getIConstantVRegValWithLookThrough(SplatValAndReg->VReg, MRI);
1079485dd0b7SAbinav Puthan Purayil return ValAndVReg->Value;
1080485dd0b7SAbinav Puthan Purayil }
1081485dd0b7SAbinav Puthan Purayil
1082485dd0b7SAbinav Puthan Purayil return None;
1083485dd0b7SAbinav Puthan Purayil }
1084485dd0b7SAbinav Puthan Purayil
getIConstantSplatVal(const MachineInstr & MI,const MachineRegisterInfo & MRI)1085485dd0b7SAbinav Puthan Purayil Optional<APInt> getIConstantSplatVal(const MachineInstr &MI,
1086485dd0b7SAbinav Puthan Purayil const MachineRegisterInfo &MRI) {
1087485dd0b7SAbinav Puthan Purayil return getIConstantSplatVal(MI.getOperand(0).getReg(), MRI);
1088485dd0b7SAbinav Puthan Purayil }
1089485dd0b7SAbinav Puthan Purayil
1090485dd0b7SAbinav Puthan Purayil Optional<int64_t>
getIConstantSplatSExtVal(const Register Reg,const MachineRegisterInfo & MRI)1091485dd0b7SAbinav Puthan Purayil llvm::getIConstantSplatSExtVal(const Register Reg,
1092485dd0b7SAbinav Puthan Purayil const MachineRegisterInfo &MRI) {
1093485dd0b7SAbinav Puthan Purayil if (auto SplatValAndReg =
1094485dd0b7SAbinav Puthan Purayil getAnyConstantSplat(Reg, MRI, /* AllowUndef */ false))
10958bc71856SPetar Avramovic return getIConstantVRegSExtVal(SplatValAndReg->VReg, MRI);
1096520ab710SAmara Emerson return None;
1097520ab710SAmara Emerson }
1098520ab710SAmara Emerson
1099485dd0b7SAbinav Puthan Purayil Optional<int64_t>
getIConstantSplatSExtVal(const MachineInstr & MI,const MachineRegisterInfo & MRI)1100485dd0b7SAbinav Puthan Purayil llvm::getIConstantSplatSExtVal(const MachineInstr &MI,
1101485dd0b7SAbinav Puthan Purayil const MachineRegisterInfo &MRI) {
1102485dd0b7SAbinav Puthan Purayil return getIConstantSplatSExtVal(MI.getOperand(0).getReg(), MRI);
1103485dd0b7SAbinav Puthan Purayil }
1104485dd0b7SAbinav Puthan Purayil
getFConstantSplat(Register VReg,const MachineRegisterInfo & MRI,bool AllowUndef)11058bc71856SPetar Avramovic Optional<FPValueAndVReg> llvm::getFConstantSplat(Register VReg,
11068bc71856SPetar Avramovic const MachineRegisterInfo &MRI,
11078bc71856SPetar Avramovic bool AllowUndef) {
11088bc71856SPetar Avramovic if (auto SplatValAndReg = getAnyConstantSplat(VReg, MRI, AllowUndef))
11098bc71856SPetar Avramovic return getFConstantVRegValWithLookThrough(SplatValAndReg->VReg, MRI);
11108bc71856SPetar Avramovic return None;
1111520ab710SAmara Emerson }
1112520ab710SAmara Emerson
isBuildVectorAllZeros(const MachineInstr & MI,const MachineRegisterInfo & MRI,bool AllowUndef)11135c5e6d95SMatt Arsenault bool llvm::isBuildVectorAllZeros(const MachineInstr &MI,
11148bc71856SPetar Avramovic const MachineRegisterInfo &MRI,
11158bc71856SPetar Avramovic bool AllowUndef) {
11168bc71856SPetar Avramovic return isBuildVectorConstantSplat(MI, MRI, 0, AllowUndef);
11175c5e6d95SMatt Arsenault }
11185c5e6d95SMatt Arsenault
isBuildVectorAllOnes(const MachineInstr & MI,const MachineRegisterInfo & MRI,bool AllowUndef)11195c5e6d95SMatt Arsenault bool llvm::isBuildVectorAllOnes(const MachineInstr &MI,
11208bc71856SPetar Avramovic const MachineRegisterInfo &MRI,
11218bc71856SPetar Avramovic bool AllowUndef) {
11228bc71856SPetar Avramovic return isBuildVectorConstantSplat(MI, MRI, -1, AllowUndef);
11235c5e6d95SMatt Arsenault }
1124520ab710SAmara Emerson
getVectorSplat(const MachineInstr & MI,const MachineRegisterInfo & MRI)11255c26be21SJessica Paquette Optional<RegOrConstant> llvm::getVectorSplat(const MachineInstr &MI,
11265c26be21SJessica Paquette const MachineRegisterInfo &MRI) {
11275c26be21SJessica Paquette unsigned Opc = MI.getOpcode();
11285c26be21SJessica Paquette if (!isBuildVectorOp(Opc))
11295c26be21SJessica Paquette return None;
1130485dd0b7SAbinav Puthan Purayil if (auto Splat = getIConstantSplatSExtVal(MI, MRI))
11315c26be21SJessica Paquette return RegOrConstant(*Splat);
11325c26be21SJessica Paquette auto Reg = MI.getOperand(1).getReg();
11335c26be21SJessica Paquette if (any_of(make_range(MI.operands_begin() + 2, MI.operands_end()),
11345c26be21SJessica Paquette [&Reg](const MachineOperand &Op) { return Op.getReg() != Reg; }))
11355c26be21SJessica Paquette return None;
11365c26be21SJessica Paquette return RegOrConstant(Reg);
11375c26be21SJessica Paquette }
11385c26be21SJessica Paquette
isConstantScalar(const MachineInstr & MI,const MachineRegisterInfo & MRI,bool AllowFP=true,bool AllowOpaqueConstants=true)11390877fbccSMatt Arsenault static bool isConstantScalar(const MachineInstr &MI,
11400877fbccSMatt Arsenault const MachineRegisterInfo &MRI,
11410877fbccSMatt Arsenault bool AllowFP = true,
11420877fbccSMatt Arsenault bool AllowOpaqueConstants = true) {
11430877fbccSMatt Arsenault switch (MI.getOpcode()) {
11440877fbccSMatt Arsenault case TargetOpcode::G_CONSTANT:
11450877fbccSMatt Arsenault case TargetOpcode::G_IMPLICIT_DEF:
11460877fbccSMatt Arsenault return true;
11470877fbccSMatt Arsenault case TargetOpcode::G_FCONSTANT:
11480877fbccSMatt Arsenault return AllowFP;
11490877fbccSMatt Arsenault case TargetOpcode::G_GLOBAL_VALUE:
11500877fbccSMatt Arsenault case TargetOpcode::G_FRAME_INDEX:
11510877fbccSMatt Arsenault case TargetOpcode::G_BLOCK_ADDR:
11520877fbccSMatt Arsenault case TargetOpcode::G_JUMP_TABLE:
11530877fbccSMatt Arsenault return AllowOpaqueConstants;
11540877fbccSMatt Arsenault default:
11550877fbccSMatt Arsenault return false;
11560877fbccSMatt Arsenault }
11570877fbccSMatt Arsenault }
11580877fbccSMatt Arsenault
isConstantOrConstantVector(MachineInstr & MI,const MachineRegisterInfo & MRI)11598bfc0e06SAmara Emerson bool llvm::isConstantOrConstantVector(MachineInstr &MI,
11608bfc0e06SAmara Emerson const MachineRegisterInfo &MRI) {
11618bfc0e06SAmara Emerson Register Def = MI.getOperand(0).getReg();
11628bfc0e06SAmara Emerson if (auto C = getIConstantVRegValWithLookThrough(Def, MRI))
11638bfc0e06SAmara Emerson return true;
11648bfc0e06SAmara Emerson GBuildVector *BV = dyn_cast<GBuildVector>(&MI);
11658bfc0e06SAmara Emerson if (!BV)
11668bfc0e06SAmara Emerson return false;
11678bfc0e06SAmara Emerson for (unsigned SrcIdx = 0; SrcIdx < BV->getNumSources(); ++SrcIdx) {
11688bfc0e06SAmara Emerson if (getIConstantVRegValWithLookThrough(BV->getSourceReg(SrcIdx), MRI) ||
11698bfc0e06SAmara Emerson getOpcodeDef<GImplicitDef>(BV->getSourceReg(SrcIdx), MRI))
11708bfc0e06SAmara Emerson continue;
11718bfc0e06SAmara Emerson return false;
11728bfc0e06SAmara Emerson }
11738bfc0e06SAmara Emerson return true;
11748bfc0e06SAmara Emerson }
11758bfc0e06SAmara Emerson
isConstantOrConstantVector(const MachineInstr & MI,const MachineRegisterInfo & MRI,bool AllowFP,bool AllowOpaqueConstants)11760877fbccSMatt Arsenault bool llvm::isConstantOrConstantVector(const MachineInstr &MI,
11770877fbccSMatt Arsenault const MachineRegisterInfo &MRI,
11780877fbccSMatt Arsenault bool AllowFP, bool AllowOpaqueConstants) {
11790877fbccSMatt Arsenault if (isConstantScalar(MI, MRI, AllowFP, AllowOpaqueConstants))
11800877fbccSMatt Arsenault return true;
11810877fbccSMatt Arsenault
11820877fbccSMatt Arsenault if (!isBuildVectorOp(MI.getOpcode()))
11830877fbccSMatt Arsenault return false;
11840877fbccSMatt Arsenault
11850877fbccSMatt Arsenault const unsigned NumOps = MI.getNumOperands();
11860877fbccSMatt Arsenault for (unsigned I = 1; I != NumOps; ++I) {
11870877fbccSMatt Arsenault const MachineInstr *ElementDef = MRI.getVRegDef(MI.getOperand(I).getReg());
11880877fbccSMatt Arsenault if (!isConstantScalar(*ElementDef, MRI, AllowFP, AllowOpaqueConstants))
11890877fbccSMatt Arsenault return false;
11900877fbccSMatt Arsenault }
11910877fbccSMatt Arsenault
11920877fbccSMatt Arsenault return true;
11930877fbccSMatt Arsenault }
11940877fbccSMatt Arsenault
119580f4bb5cSAmara Emerson Optional<APInt>
isConstantOrConstantSplatVector(MachineInstr & MI,const MachineRegisterInfo & MRI)119680f4bb5cSAmara Emerson llvm::isConstantOrConstantSplatVector(MachineInstr &MI,
119780f4bb5cSAmara Emerson const MachineRegisterInfo &MRI) {
119880f4bb5cSAmara Emerson Register Def = MI.getOperand(0).getReg();
119980f4bb5cSAmara Emerson if (auto C = getIConstantVRegValWithLookThrough(Def, MRI))
120080f4bb5cSAmara Emerson return C->Value;
1201485dd0b7SAbinav Puthan Purayil auto MaybeCst = getIConstantSplatSExtVal(MI, MRI);
120280f4bb5cSAmara Emerson if (!MaybeCst)
120380f4bb5cSAmara Emerson return None;
120480f4bb5cSAmara Emerson const unsigned ScalarSize = MRI.getType(Def).getScalarSizeInBits();
120580f4bb5cSAmara Emerson return APInt(ScalarSize, *MaybeCst, true);
120680f4bb5cSAmara Emerson }
120780f4bb5cSAmara Emerson
isNullOrNullSplat(const MachineInstr & MI,const MachineRegisterInfo & MRI,bool AllowUndefs)12080877fbccSMatt Arsenault bool llvm::isNullOrNullSplat(const MachineInstr &MI,
12090877fbccSMatt Arsenault const MachineRegisterInfo &MRI, bool AllowUndefs) {
12100877fbccSMatt Arsenault switch (MI.getOpcode()) {
12110877fbccSMatt Arsenault case TargetOpcode::G_IMPLICIT_DEF:
12120877fbccSMatt Arsenault return AllowUndefs;
12130877fbccSMatt Arsenault case TargetOpcode::G_CONSTANT:
12140877fbccSMatt Arsenault return MI.getOperand(1).getCImm()->isNullValue();
12150877fbccSMatt Arsenault case TargetOpcode::G_FCONSTANT: {
12160877fbccSMatt Arsenault const ConstantFP *FPImm = MI.getOperand(1).getFPImm();
12170877fbccSMatt Arsenault return FPImm->isZero() && !FPImm->isNegative();
12180877fbccSMatt Arsenault }
12190877fbccSMatt Arsenault default:
12200877fbccSMatt Arsenault if (!AllowUndefs) // TODO: isBuildVectorAllZeros assumes undef is OK already
12210877fbccSMatt Arsenault return false;
12220877fbccSMatt Arsenault return isBuildVectorAllZeros(MI, MRI);
12230877fbccSMatt Arsenault }
12240877fbccSMatt Arsenault }
12250877fbccSMatt Arsenault
isAllOnesOrAllOnesSplat(const MachineInstr & MI,const MachineRegisterInfo & MRI,bool AllowUndefs)12260877fbccSMatt Arsenault bool llvm::isAllOnesOrAllOnesSplat(const MachineInstr &MI,
12270877fbccSMatt Arsenault const MachineRegisterInfo &MRI,
12280877fbccSMatt Arsenault bool AllowUndefs) {
12290877fbccSMatt Arsenault switch (MI.getOpcode()) {
12300877fbccSMatt Arsenault case TargetOpcode::G_IMPLICIT_DEF:
12310877fbccSMatt Arsenault return AllowUndefs;
12320877fbccSMatt Arsenault case TargetOpcode::G_CONSTANT:
12330877fbccSMatt Arsenault return MI.getOperand(1).getCImm()->isAllOnesValue();
12340877fbccSMatt Arsenault default:
12350877fbccSMatt Arsenault if (!AllowUndefs) // TODO: isBuildVectorAllOnes assumes undef is OK already
12360877fbccSMatt Arsenault return false;
12370877fbccSMatt Arsenault return isBuildVectorAllOnes(MI, MRI);
12380877fbccSMatt Arsenault }
12390877fbccSMatt Arsenault }
12400877fbccSMatt Arsenault
matchUnaryPredicate(const MachineRegisterInfo & MRI,Register Reg,std::function<bool (const Constant * ConstVal)> Match,bool AllowUndefs)1241b24436acSMatt Arsenault bool llvm::matchUnaryPredicate(
1242b24436acSMatt Arsenault const MachineRegisterInfo &MRI, Register Reg,
1243b24436acSMatt Arsenault std::function<bool(const Constant *ConstVal)> Match, bool AllowUndefs) {
1244b24436acSMatt Arsenault
1245b24436acSMatt Arsenault const MachineInstr *Def = getDefIgnoringCopies(Reg, MRI);
1246b24436acSMatt Arsenault if (AllowUndefs && Def->getOpcode() == TargetOpcode::G_IMPLICIT_DEF)
1247b24436acSMatt Arsenault return Match(nullptr);
1248b24436acSMatt Arsenault
1249b24436acSMatt Arsenault // TODO: Also handle fconstant
1250b24436acSMatt Arsenault if (Def->getOpcode() == TargetOpcode::G_CONSTANT)
1251b24436acSMatt Arsenault return Match(Def->getOperand(1).getCImm());
1252b24436acSMatt Arsenault
1253b24436acSMatt Arsenault if (Def->getOpcode() != TargetOpcode::G_BUILD_VECTOR)
1254b24436acSMatt Arsenault return false;
1255b24436acSMatt Arsenault
1256b24436acSMatt Arsenault for (unsigned I = 1, E = Def->getNumOperands(); I != E; ++I) {
1257b24436acSMatt Arsenault Register SrcElt = Def->getOperand(I).getReg();
1258b24436acSMatt Arsenault const MachineInstr *SrcDef = getDefIgnoringCopies(SrcElt, MRI);
1259b24436acSMatt Arsenault if (AllowUndefs && SrcDef->getOpcode() == TargetOpcode::G_IMPLICIT_DEF) {
1260b24436acSMatt Arsenault if (!Match(nullptr))
1261b24436acSMatt Arsenault return false;
1262b24436acSMatt Arsenault continue;
1263b24436acSMatt Arsenault }
1264b24436acSMatt Arsenault
1265b24436acSMatt Arsenault if (SrcDef->getOpcode() != TargetOpcode::G_CONSTANT ||
1266b24436acSMatt Arsenault !Match(SrcDef->getOperand(1).getCImm()))
1267b24436acSMatt Arsenault return false;
1268b24436acSMatt Arsenault }
1269b24436acSMatt Arsenault
1270b24436acSMatt Arsenault return true;
1271b24436acSMatt Arsenault }
1272b24436acSMatt Arsenault
isConstTrueVal(const TargetLowering & TLI,int64_t Val,bool IsVector,bool IsFP)1273520ab710SAmara Emerson bool llvm::isConstTrueVal(const TargetLowering &TLI, int64_t Val, bool IsVector,
1274520ab710SAmara Emerson bool IsFP) {
1275520ab710SAmara Emerson switch (TLI.getBooleanContents(IsVector, IsFP)) {
1276520ab710SAmara Emerson case TargetLowering::UndefinedBooleanContent:
1277520ab710SAmara Emerson return Val & 0x1;
1278520ab710SAmara Emerson case TargetLowering::ZeroOrOneBooleanContent:
1279520ab710SAmara Emerson return Val == 1;
1280520ab710SAmara Emerson case TargetLowering::ZeroOrNegativeOneBooleanContent:
1281520ab710SAmara Emerson return Val == -1;
1282520ab710SAmara Emerson }
1283520ab710SAmara Emerson llvm_unreachable("Invalid boolean contents");
1284520ab710SAmara Emerson }
1285cc76da7aSAmara Emerson
getICmpTrueVal(const TargetLowering & TLI,bool IsVector,bool IsFP)1286cc76da7aSAmara Emerson int64_t llvm::getICmpTrueVal(const TargetLowering &TLI, bool IsVector,
1287cc76da7aSAmara Emerson bool IsFP) {
1288cc76da7aSAmara Emerson switch (TLI.getBooleanContents(IsVector, IsFP)) {
1289cc76da7aSAmara Emerson case TargetLowering::UndefinedBooleanContent:
1290cc76da7aSAmara Emerson case TargetLowering::ZeroOrOneBooleanContent:
1291cc76da7aSAmara Emerson return 1;
1292cc76da7aSAmara Emerson case TargetLowering::ZeroOrNegativeOneBooleanContent:
1293cc76da7aSAmara Emerson return -1;
1294cc76da7aSAmara Emerson }
1295cc76da7aSAmara Emerson llvm_unreachable("Invalid boolean contents");
1296cc76da7aSAmara Emerson }
12978a316045SAmara Emerson
shouldOptForSize(const MachineBasicBlock & MBB,ProfileSummaryInfo * PSI,BlockFrequencyInfo * BFI)12988a316045SAmara Emerson bool llvm::shouldOptForSize(const MachineBasicBlock &MBB,
12998a316045SAmara Emerson ProfileSummaryInfo *PSI, BlockFrequencyInfo *BFI) {
13008a316045SAmara Emerson const auto &F = MBB.getParent()->getFunction();
13018a316045SAmara Emerson return F.hasOptSize() || F.hasMinSize() ||
13028a316045SAmara Emerson llvm::shouldOptimizeForSize(MBB.getBasicBlock(), PSI, BFI);
13038a316045SAmara Emerson }
1304e4c46dddSPetar Avramovic
saveUsesAndErase(MachineInstr & MI,MachineRegisterInfo & MRI,LostDebugLocObserver * LocObserver,SmallInstListTy & DeadInstChain)1305e4c46dddSPetar Avramovic void llvm::saveUsesAndErase(MachineInstr &MI, MachineRegisterInfo &MRI,
1306e4c46dddSPetar Avramovic LostDebugLocObserver *LocObserver,
1307e4c46dddSPetar Avramovic SmallInstListTy &DeadInstChain) {
1308e4c46dddSPetar Avramovic for (MachineOperand &Op : MI.uses()) {
1309e4c46dddSPetar Avramovic if (Op.isReg() && Op.getReg().isVirtual())
1310e4c46dddSPetar Avramovic DeadInstChain.insert(MRI.getVRegDef(Op.getReg()));
1311e4c46dddSPetar Avramovic }
1312e4c46dddSPetar Avramovic LLVM_DEBUG(dbgs() << MI << "Is dead; erasing.\n");
1313e4c46dddSPetar Avramovic DeadInstChain.remove(&MI);
13147091a7f7SAmara Emerson MI.eraseFromParent();
1315e4c46dddSPetar Avramovic if (LocObserver)
1316e4c46dddSPetar Avramovic LocObserver->checkpoint(false);
1317e4c46dddSPetar Avramovic }
1318e4c46dddSPetar Avramovic
eraseInstrs(ArrayRef<MachineInstr * > DeadInstrs,MachineRegisterInfo & MRI,LostDebugLocObserver * LocObserver)1319e4c46dddSPetar Avramovic void llvm::eraseInstrs(ArrayRef<MachineInstr *> DeadInstrs,
1320e4c46dddSPetar Avramovic MachineRegisterInfo &MRI,
1321e4c46dddSPetar Avramovic LostDebugLocObserver *LocObserver) {
1322e4c46dddSPetar Avramovic SmallInstListTy DeadInstChain;
1323e4c46dddSPetar Avramovic for (MachineInstr *MI : DeadInstrs)
1324e4c46dddSPetar Avramovic saveUsesAndErase(*MI, MRI, LocObserver, DeadInstChain);
1325e4c46dddSPetar Avramovic
1326e4c46dddSPetar Avramovic while (!DeadInstChain.empty()) {
1327e4c46dddSPetar Avramovic MachineInstr *Inst = DeadInstChain.pop_back_val();
1328e4c46dddSPetar Avramovic if (!isTriviallyDead(*Inst, MRI))
1329e4c46dddSPetar Avramovic continue;
1330e4c46dddSPetar Avramovic saveUsesAndErase(*Inst, MRI, LocObserver, DeadInstChain);
1331e4c46dddSPetar Avramovic }
1332e4c46dddSPetar Avramovic }
1333e4c46dddSPetar Avramovic
eraseInstr(MachineInstr & MI,MachineRegisterInfo & MRI,LostDebugLocObserver * LocObserver)1334e4c46dddSPetar Avramovic void llvm::eraseInstr(MachineInstr &MI, MachineRegisterInfo &MRI,
1335e4c46dddSPetar Avramovic LostDebugLocObserver *LocObserver) {
1336e4c46dddSPetar Avramovic return eraseInstrs({&MI}, MRI, LocObserver);
1337e4c46dddSPetar Avramovic }
1338