15ffd83dbSDimitry Andric //===- PPCMacroFusion.cpp - PowerPC Macro Fusion --------------------------===//
25ffd83dbSDimitry Andric //
35ffd83dbSDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
45ffd83dbSDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
55ffd83dbSDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
65ffd83dbSDimitry Andric //
75ffd83dbSDimitry Andric //===----------------------------------------------------------------------===//
85ffd83dbSDimitry Andric //
95ffd83dbSDimitry Andric /// \file This file contains the PowerPC implementation of the DAG scheduling
105ffd83dbSDimitry Andric /// mutation to pair instructions back to back.
115ffd83dbSDimitry Andric //
125ffd83dbSDimitry Andric //===----------------------------------------------------------------------===//
135ffd83dbSDimitry Andric
145ffd83dbSDimitry Andric #include "PPC.h"
155ffd83dbSDimitry Andric #include "PPCSubtarget.h"
165ffd83dbSDimitry Andric #include "llvm/ADT/DenseSet.h"
175ffd83dbSDimitry Andric #include "llvm/CodeGen/MacroFusion.h"
185ffd83dbSDimitry Andric
195ffd83dbSDimitry Andric using namespace llvm;
205ffd83dbSDimitry Andric namespace {
215ffd83dbSDimitry Andric
225ffd83dbSDimitry Andric class FusionFeature {
235ffd83dbSDimitry Andric public:
245ffd83dbSDimitry Andric typedef SmallDenseSet<unsigned> FusionOpSet;
255ffd83dbSDimitry Andric
265ffd83dbSDimitry Andric enum FusionKind {
275ffd83dbSDimitry Andric #define FUSION_KIND(KIND) FK_##KIND
285ffd83dbSDimitry Andric #define FUSION_FEATURE(KIND, HAS_FEATURE, DEP_OP_IDX, OPSET1, OPSET2) \
295ffd83dbSDimitry Andric FUSION_KIND(KIND),
305ffd83dbSDimitry Andric #include "PPCMacroFusion.def"
315ffd83dbSDimitry Andric FUSION_KIND(END)
325ffd83dbSDimitry Andric };
335ffd83dbSDimitry Andric private:
345ffd83dbSDimitry Andric // Each fusion feature is assigned with one fusion kind. All the
355ffd83dbSDimitry Andric // instructions with the same fusion kind have the same fusion characteristic.
365ffd83dbSDimitry Andric FusionKind Kd;
375ffd83dbSDimitry Andric // True if this feature is enabled.
385ffd83dbSDimitry Andric bool Supported;
395ffd83dbSDimitry Andric // li rx, si
405ffd83dbSDimitry Andric // load rt, ra, rx
415ffd83dbSDimitry Andric // The dependent operand index in the second op(load). And the negative means
425ffd83dbSDimitry Andric // it could be any one.
435ffd83dbSDimitry Andric int DepOpIdx;
445ffd83dbSDimitry Andric // The first fusion op set.
455ffd83dbSDimitry Andric FusionOpSet OpSet1;
465ffd83dbSDimitry Andric // The second fusion op set.
475ffd83dbSDimitry Andric FusionOpSet OpSet2;
485ffd83dbSDimitry Andric public:
FusionFeature(FusionKind Kind,bool HasFeature,int Index,const FusionOpSet & First,const FusionOpSet & Second)495ffd83dbSDimitry Andric FusionFeature(FusionKind Kind, bool HasFeature, int Index,
505ffd83dbSDimitry Andric const FusionOpSet &First, const FusionOpSet &Second) :
515ffd83dbSDimitry Andric Kd(Kind), Supported(HasFeature), DepOpIdx(Index), OpSet1(First),
525ffd83dbSDimitry Andric OpSet2(Second) {}
535ffd83dbSDimitry Andric
hasOp1(unsigned Opc) const54*af732203SDimitry Andric bool hasOp1(unsigned Opc) const { return OpSet1.contains(Opc); }
hasOp2(unsigned Opc) const55*af732203SDimitry Andric bool hasOp2(unsigned Opc) const { return OpSet2.contains(Opc); }
isSupported() const565ffd83dbSDimitry Andric bool isSupported() const { return Supported; }
depOpIdx() const575ffd83dbSDimitry Andric Optional<unsigned> depOpIdx() const {
585ffd83dbSDimitry Andric if (DepOpIdx < 0)
595ffd83dbSDimitry Andric return None;
605ffd83dbSDimitry Andric return DepOpIdx;
615ffd83dbSDimitry Andric }
625ffd83dbSDimitry Andric
getKind() const635ffd83dbSDimitry Andric FusionKind getKind() const { return Kd; }
645ffd83dbSDimitry Andric };
655ffd83dbSDimitry Andric
matchingRegOps(const MachineInstr & FirstMI,int FirstMIOpIndex,const MachineInstr & SecondMI,int SecondMIOpIndex)665ffd83dbSDimitry Andric static bool matchingRegOps(const MachineInstr &FirstMI,
675ffd83dbSDimitry Andric int FirstMIOpIndex,
685ffd83dbSDimitry Andric const MachineInstr &SecondMI,
695ffd83dbSDimitry Andric int SecondMIOpIndex) {
705ffd83dbSDimitry Andric const MachineOperand &Op1 = FirstMI.getOperand(FirstMIOpIndex);
715ffd83dbSDimitry Andric const MachineOperand &Op2 = SecondMI.getOperand(SecondMIOpIndex);
725ffd83dbSDimitry Andric if (!Op1.isReg() || !Op2.isReg())
735ffd83dbSDimitry Andric return false;
745ffd83dbSDimitry Andric
755ffd83dbSDimitry Andric return Op1.getReg() == Op2.getReg();
765ffd83dbSDimitry Andric }
775ffd83dbSDimitry Andric
785ffd83dbSDimitry Andric // Return true if the FirstMI meets the constraints of SecondMI according to
795ffd83dbSDimitry Andric // fusion specification.
checkOpConstraints(FusionFeature::FusionKind Kd,const MachineInstr & FirstMI,const MachineInstr & SecondMI)805ffd83dbSDimitry Andric static bool checkOpConstraints(FusionFeature::FusionKind Kd,
815ffd83dbSDimitry Andric const MachineInstr &FirstMI,
825ffd83dbSDimitry Andric const MachineInstr &SecondMI) {
835ffd83dbSDimitry Andric switch (Kd) {
845ffd83dbSDimitry Andric // The hardware didn't require any specific check for the fused instructions'
855ffd83dbSDimitry Andric // operands. Therefore, return true to indicate that, it is fusable.
865ffd83dbSDimitry Andric default: return true;
875ffd83dbSDimitry Andric // [addi rt,ra,si - lxvd2x xt,ra,rb] etc.
885ffd83dbSDimitry Andric case FusionFeature::FK_AddiLoad: {
895ffd83dbSDimitry Andric // lxvd2x(ra) cannot be zero
905ffd83dbSDimitry Andric const MachineOperand &RA = SecondMI.getOperand(1);
915ffd83dbSDimitry Andric if (!RA.isReg())
925ffd83dbSDimitry Andric return true;
935ffd83dbSDimitry Andric
945ffd83dbSDimitry Andric return Register::isVirtualRegister(RA.getReg()) ||
955ffd83dbSDimitry Andric (RA.getReg() != PPC::ZERO && RA.getReg() != PPC::ZERO8);
965ffd83dbSDimitry Andric }
975ffd83dbSDimitry Andric // [addis rt,ra,si - ld rt,ds(ra)] etc.
985ffd83dbSDimitry Andric case FusionFeature::FK_AddisLoad: {
995ffd83dbSDimitry Andric const MachineOperand &RT = SecondMI.getOperand(0);
1005ffd83dbSDimitry Andric if (!RT.isReg())
1015ffd83dbSDimitry Andric return true;
1025ffd83dbSDimitry Andric
1035ffd83dbSDimitry Andric // Only check it for non-virtual register.
1045ffd83dbSDimitry Andric if (!Register::isVirtualRegister(RT.getReg()))
1055ffd83dbSDimitry Andric // addis(rt) = ld(ra) = ld(rt)
1065ffd83dbSDimitry Andric // ld(rt) cannot be zero
1075ffd83dbSDimitry Andric if (!matchingRegOps(SecondMI, 0, SecondMI, 2) ||
1085ffd83dbSDimitry Andric (RT.getReg() == PPC::ZERO || RT.getReg() == PPC::ZERO8))
1095ffd83dbSDimitry Andric return false;
1105ffd83dbSDimitry Andric
1115ffd83dbSDimitry Andric // addis(si) first 12 bits must be all 1s or all 0s
1125ffd83dbSDimitry Andric const MachineOperand &SI = FirstMI.getOperand(2);
1135ffd83dbSDimitry Andric if (!SI.isImm())
1145ffd83dbSDimitry Andric return true;
1155ffd83dbSDimitry Andric int64_t Imm = SI.getImm();
1165ffd83dbSDimitry Andric if (((Imm & 0xFFF0) != 0) && ((Imm & 0xFFF0) != 0xFFF0))
1175ffd83dbSDimitry Andric return false;
1185ffd83dbSDimitry Andric
1195ffd83dbSDimitry Andric // If si = 1111111111110000 and the msb of the d/ds field of the load equals
1205ffd83dbSDimitry Andric // 1, then fusion does not occur.
1215ffd83dbSDimitry Andric if ((Imm & 0xFFF0) == 0xFFF0) {
1225ffd83dbSDimitry Andric const MachineOperand &D = SecondMI.getOperand(1);
1235ffd83dbSDimitry Andric if (!D.isImm())
1245ffd83dbSDimitry Andric return true;
1255ffd83dbSDimitry Andric
1265ffd83dbSDimitry Andric // 14 bit for DS field, while 16 bit for D field.
1275ffd83dbSDimitry Andric int MSB = 15;
1285ffd83dbSDimitry Andric if (SecondMI.getOpcode() == PPC::LD)
1295ffd83dbSDimitry Andric MSB = 13;
1305ffd83dbSDimitry Andric
1315ffd83dbSDimitry Andric return (D.getImm() & (1ULL << MSB)) == 0;
1325ffd83dbSDimitry Andric }
1335ffd83dbSDimitry Andric return true;
1345ffd83dbSDimitry Andric }
1355ffd83dbSDimitry Andric }
1365ffd83dbSDimitry Andric
1375ffd83dbSDimitry Andric llvm_unreachable("All the cases should have been handled");
1385ffd83dbSDimitry Andric return true;
1395ffd83dbSDimitry Andric }
1405ffd83dbSDimitry Andric
1415ffd83dbSDimitry Andric /// Check if the instr pair, FirstMI and SecondMI, should be fused together.
1425ffd83dbSDimitry Andric /// Given SecondMI, when FirstMI is unspecified, then check if SecondMI may be
1435ffd83dbSDimitry Andric /// part of a fused pair at all.
shouldScheduleAdjacent(const TargetInstrInfo & TII,const TargetSubtargetInfo & TSI,const MachineInstr * FirstMI,const MachineInstr & SecondMI)1445ffd83dbSDimitry Andric static bool shouldScheduleAdjacent(const TargetInstrInfo &TII,
1455ffd83dbSDimitry Andric const TargetSubtargetInfo &TSI,
1465ffd83dbSDimitry Andric const MachineInstr *FirstMI,
1475ffd83dbSDimitry Andric const MachineInstr &SecondMI) {
1485ffd83dbSDimitry Andric // We use the PPC namespace to avoid the need to prefix opcodes with PPC:: in
1495ffd83dbSDimitry Andric // the def file.
1505ffd83dbSDimitry Andric using namespace PPC;
1515ffd83dbSDimitry Andric
1525ffd83dbSDimitry Andric const PPCSubtarget &ST = static_cast<const PPCSubtarget&>(TSI);
1535ffd83dbSDimitry Andric static const FusionFeature FusionFeatures[] = {
1545ffd83dbSDimitry Andric #define FUSION_FEATURE(KIND, HAS_FEATURE, DEP_OP_IDX, OPSET1, OPSET2) { \
1555ffd83dbSDimitry Andric FusionFeature::FUSION_KIND(KIND), ST.HAS_FEATURE(), DEP_OP_IDX, { OPSET1 },\
1565ffd83dbSDimitry Andric { OPSET2 } },
1575ffd83dbSDimitry Andric #include "PPCMacroFusion.def"
1585ffd83dbSDimitry Andric };
1595ffd83dbSDimitry Andric #undef FUSION_KIND
1605ffd83dbSDimitry Andric
1615ffd83dbSDimitry Andric for (auto &Feature : FusionFeatures) {
1625ffd83dbSDimitry Andric // Skip if the feature is not supported.
1635ffd83dbSDimitry Andric if (!Feature.isSupported())
1645ffd83dbSDimitry Andric continue;
1655ffd83dbSDimitry Andric
1665ffd83dbSDimitry Andric // Only when the SecondMI is fusable, we are starting to look for the
1675ffd83dbSDimitry Andric // fusable FirstMI.
1685ffd83dbSDimitry Andric if (Feature.hasOp2(SecondMI.getOpcode())) {
1695ffd83dbSDimitry Andric // If FirstMI == nullptr, that means, we're only checking whether SecondMI
1705ffd83dbSDimitry Andric // can be fused at all.
1715ffd83dbSDimitry Andric if (!FirstMI)
1725ffd83dbSDimitry Andric return true;
1735ffd83dbSDimitry Andric
1745ffd83dbSDimitry Andric // Checking if the FirstMI is fusable with the SecondMI.
1755ffd83dbSDimitry Andric if (!Feature.hasOp1(FirstMI->getOpcode()))
1765ffd83dbSDimitry Andric continue;
1775ffd83dbSDimitry Andric
1785ffd83dbSDimitry Andric auto DepOpIdx = Feature.depOpIdx();
1795ffd83dbSDimitry Andric if (DepOpIdx.hasValue()) {
1805ffd83dbSDimitry Andric // Checking if the result of the FirstMI is the desired operand of the
1815ffd83dbSDimitry Andric // SecondMI if the DepOpIdx is set. Otherwise, ignore it.
1825ffd83dbSDimitry Andric if (!matchingRegOps(*FirstMI, 0, SecondMI, *DepOpIdx))
1835ffd83dbSDimitry Andric return false;
1845ffd83dbSDimitry Andric }
1855ffd83dbSDimitry Andric
1865ffd83dbSDimitry Andric // Checking more on the instruction operands.
1875ffd83dbSDimitry Andric if (checkOpConstraints(Feature.getKind(), *FirstMI, SecondMI))
1885ffd83dbSDimitry Andric return true;
1895ffd83dbSDimitry Andric }
1905ffd83dbSDimitry Andric }
1915ffd83dbSDimitry Andric
1925ffd83dbSDimitry Andric return false;
1935ffd83dbSDimitry Andric }
1945ffd83dbSDimitry Andric
1955ffd83dbSDimitry Andric } // end anonymous namespace
1965ffd83dbSDimitry Andric
1975ffd83dbSDimitry Andric namespace llvm {
1985ffd83dbSDimitry Andric
createPowerPCMacroFusionDAGMutation()1995ffd83dbSDimitry Andric std::unique_ptr<ScheduleDAGMutation> createPowerPCMacroFusionDAGMutation () {
2005ffd83dbSDimitry Andric return createMacroFusionDAGMutation(shouldScheduleAdjacent);
2015ffd83dbSDimitry Andric }
2025ffd83dbSDimitry Andric
2035ffd83dbSDimitry Andric } // end namespace llvm
204