204 lines
		
	
	
		
			6.7 KiB
		
	
	
	
		
			C++
		
	
	
	
			
		
		
	
	
			204 lines
		
	
	
		
			6.7 KiB
		
	
	
	
		
			C++
		
	
	
	
//===- PPCMacroFusion.cpp - PowerPC Macro Fusion --------------------------===//
 | 
						|
//
 | 
						|
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
 | 
						|
// See https://llvm.org/LICENSE.txt for license information.
 | 
						|
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
 | 
						|
//
 | 
						|
//===----------------------------------------------------------------------===//
 | 
						|
//
 | 
						|
/// \file This file contains the PowerPC implementation of the DAG scheduling
 | 
						|
///  mutation to pair instructions back to back.
 | 
						|
//
 | 
						|
//===----------------------------------------------------------------------===//
 | 
						|
 | 
						|
#include "PPC.h"
 | 
						|
#include "PPCSubtarget.h"
 | 
						|
#include "llvm/ADT/DenseSet.h"
 | 
						|
#include "llvm/CodeGen/MacroFusion.h"
 | 
						|
 | 
						|
using namespace llvm;
 | 
						|
namespace {
 | 
						|
 | 
						|
class FusionFeature {
 | 
						|
public:
 | 
						|
  typedef SmallDenseSet<unsigned> FusionOpSet;
 | 
						|
 | 
						|
  enum FusionKind {
 | 
						|
  #define FUSION_KIND(KIND) FK_##KIND
 | 
						|
  #define FUSION_FEATURE(KIND, HAS_FEATURE, DEP_OP_IDX, OPSET1, OPSET2) \
 | 
						|
    FUSION_KIND(KIND),
 | 
						|
  #include "PPCMacroFusion.def"
 | 
						|
  FUSION_KIND(END)
 | 
						|
  };
 | 
						|
private:
 | 
						|
  // Each fusion feature is assigned with one fusion kind. All the
 | 
						|
  // instructions with the same fusion kind have the same fusion characteristic.
 | 
						|
  FusionKind Kd;
 | 
						|
  // True if this feature is enabled.
 | 
						|
  bool Supported;
 | 
						|
  // li rx, si
 | 
						|
  // load rt, ra, rx
 | 
						|
  // The dependent operand index in the second op(load). And the negative means
 | 
						|
  // it could be any one. 
 | 
						|
  int DepOpIdx;
 | 
						|
  // The first fusion op set.
 | 
						|
  FusionOpSet OpSet1;
 | 
						|
  // The second fusion op set.
 | 
						|
  FusionOpSet OpSet2;
 | 
						|
public:
 | 
						|
  FusionFeature(FusionKind Kind, bool HasFeature, int Index,
 | 
						|
                const FusionOpSet &First, const FusionOpSet &Second) :
 | 
						|
    Kd(Kind), Supported(HasFeature), DepOpIdx(Index), OpSet1(First), 
 | 
						|
    OpSet2(Second) {}
 | 
						|
 | 
						|
  bool hasOp1(unsigned Opc) const { return OpSet1.contains(Opc); }
 | 
						|
  bool hasOp2(unsigned Opc) const { return OpSet2.contains(Opc); }
 | 
						|
  bool isSupported() const { return Supported; }
 | 
						|
  Optional<unsigned> depOpIdx() const {
 | 
						|
    if (DepOpIdx < 0)
 | 
						|
      return None;
 | 
						|
    return DepOpIdx;
 | 
						|
  }
 | 
						|
 | 
						|
  FusionKind getKind() const { return Kd; }
 | 
						|
};
 | 
						|
 | 
						|
static bool matchingRegOps(const MachineInstr &FirstMI,
 | 
						|
                           int FirstMIOpIndex,
 | 
						|
                           const MachineInstr &SecondMI,
 | 
						|
                           int SecondMIOpIndex) {
 | 
						|
  const MachineOperand &Op1 = FirstMI.getOperand(FirstMIOpIndex);
 | 
						|
  const MachineOperand &Op2 = SecondMI.getOperand(SecondMIOpIndex);
 | 
						|
  if (!Op1.isReg() || !Op2.isReg())
 | 
						|
    return false;
 | 
						|
 | 
						|
  return Op1.getReg() == Op2.getReg();
 | 
						|
}
 | 
						|
 | 
						|
// Return true if the FirstMI meets the constraints of SecondMI according to
 | 
						|
// fusion specification.
 | 
						|
static bool checkOpConstraints(FusionFeature::FusionKind Kd,
 | 
						|
                               const MachineInstr &FirstMI,
 | 
						|
                               const MachineInstr &SecondMI) {
 | 
						|
  switch (Kd) {
 | 
						|
  // The hardware didn't require any specific check for the fused instructions'
 | 
						|
  // operands. Therefore, return true to indicate that, it is fusable.
 | 
						|
  default: return true;
 | 
						|
  // [addi rt,ra,si - lxvd2x xt,ra,rb] etc.
 | 
						|
  case FusionFeature::FK_AddiLoad: {
 | 
						|
    // lxvd2x(ra) cannot be zero
 | 
						|
    const MachineOperand &RA = SecondMI.getOperand(1);
 | 
						|
    if (!RA.isReg())
 | 
						|
      return true;
 | 
						|
 | 
						|
    return Register::isVirtualRegister(RA.getReg()) ||
 | 
						|
      (RA.getReg() != PPC::ZERO && RA.getReg() != PPC::ZERO8);
 | 
						|
  }
 | 
						|
  // [addis rt,ra,si - ld rt,ds(ra)] etc.
 | 
						|
  case FusionFeature::FK_AddisLoad: {
 | 
						|
    const MachineOperand &RT = SecondMI.getOperand(0);
 | 
						|
    if (!RT.isReg())
 | 
						|
      return true;
 | 
						|
 | 
						|
    // Only check it for non-virtual register.
 | 
						|
    if (!Register::isVirtualRegister(RT.getReg()))
 | 
						|
      // addis(rt) = ld(ra) = ld(rt)
 | 
						|
      // ld(rt) cannot be zero
 | 
						|
      if (!matchingRegOps(SecondMI, 0, SecondMI, 2) ||
 | 
						|
          (RT.getReg() == PPC::ZERO || RT.getReg() == PPC::ZERO8))
 | 
						|
          return false;
 | 
						|
 | 
						|
    // addis(si) first 12 bits must be all 1s or all 0s
 | 
						|
    const MachineOperand &SI = FirstMI.getOperand(2);
 | 
						|
    if (!SI.isImm())
 | 
						|
      return true;
 | 
						|
    int64_t Imm = SI.getImm();
 | 
						|
    if (((Imm & 0xFFF0) != 0) && ((Imm & 0xFFF0) != 0xFFF0))
 | 
						|
      return false;
 | 
						|
 | 
						|
    // If si = 1111111111110000 and the msb of the d/ds field of the load equals 
 | 
						|
    // 1, then fusion does not occur.
 | 
						|
    if ((Imm & 0xFFF0) == 0xFFF0) {
 | 
						|
      const MachineOperand &D = SecondMI.getOperand(1);
 | 
						|
      if (!D.isImm())
 | 
						|
        return true;
 | 
						|
 | 
						|
      // 14 bit for DS field, while 16 bit for D field.
 | 
						|
      int MSB = 15;
 | 
						|
      if (SecondMI.getOpcode() == PPC::LD)
 | 
						|
        MSB = 13;
 | 
						|
 | 
						|
      return (D.getImm() & (1ULL << MSB)) == 0;
 | 
						|
    }
 | 
						|
    return true;
 | 
						|
  }
 | 
						|
  }
 | 
						|
 | 
						|
  llvm_unreachable("All the cases should have been handled");
 | 
						|
  return true;
 | 
						|
}
 | 
						|
 | 
						|
/// Check if the instr pair, FirstMI and SecondMI, should be fused together.
 | 
						|
/// Given SecondMI, when FirstMI is unspecified, then check if SecondMI may be
 | 
						|
/// part of a fused pair at all.
 | 
						|
static bool shouldScheduleAdjacent(const TargetInstrInfo &TII,
 | 
						|
                                   const TargetSubtargetInfo &TSI,
 | 
						|
                                   const MachineInstr *FirstMI,
 | 
						|
                                   const MachineInstr &SecondMI) {
 | 
						|
  // We use the PPC namespace to avoid the need to prefix opcodes with PPC:: in
 | 
						|
  // the def file.
 | 
						|
  using namespace PPC;
 | 
						|
 | 
						|
  const PPCSubtarget &ST = static_cast<const PPCSubtarget&>(TSI);
 | 
						|
  static const FusionFeature FusionFeatures[] = {
 | 
						|
  #define FUSION_FEATURE(KIND, HAS_FEATURE, DEP_OP_IDX, OPSET1, OPSET2) { \
 | 
						|
    FusionFeature::FUSION_KIND(KIND), ST.HAS_FEATURE(), DEP_OP_IDX, { OPSET1 },\
 | 
						|
    { OPSET2 } },
 | 
						|
   #include "PPCMacroFusion.def"
 | 
						|
  };
 | 
						|
  #undef FUSION_KIND
 | 
						|
 | 
						|
  for (auto &Feature : FusionFeatures) {
 | 
						|
    // Skip if the feature is not supported.
 | 
						|
    if (!Feature.isSupported())
 | 
						|
      continue;
 | 
						|
 | 
						|
    // Only when the SecondMI is fusable, we are starting to look for the
 | 
						|
    // fusable FirstMI.
 | 
						|
    if (Feature.hasOp2(SecondMI.getOpcode())) {
 | 
						|
      // If FirstMI == nullptr, that means, we're only checking whether SecondMI
 | 
						|
      // can be fused at all.
 | 
						|
      if (!FirstMI)
 | 
						|
        return true;
 | 
						|
 | 
						|
      // Checking if the FirstMI is fusable with the SecondMI.
 | 
						|
      if (!Feature.hasOp1(FirstMI->getOpcode()))
 | 
						|
        continue;
 | 
						|
 | 
						|
      auto DepOpIdx = Feature.depOpIdx();
 | 
						|
      if (DepOpIdx.hasValue()) {
 | 
						|
        // Checking if the result of the FirstMI is the desired operand of the
 | 
						|
        // SecondMI if the DepOpIdx is set. Otherwise, ignore it.
 | 
						|
        if (!matchingRegOps(*FirstMI, 0, SecondMI, *DepOpIdx))
 | 
						|
          return false;
 | 
						|
      }
 | 
						|
  
 | 
						|
      // Checking more on the instruction operands.
 | 
						|
      if (checkOpConstraints(Feature.getKind(), *FirstMI, SecondMI))
 | 
						|
        return true;
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  return false;
 | 
						|
}
 | 
						|
 | 
						|
} // end anonymous namespace
 | 
						|
 | 
						|
namespace llvm {
 | 
						|
 | 
						|
std::unique_ptr<ScheduleDAGMutation> createPowerPCMacroFusionDAGMutation () {
 | 
						|
  return createMacroFusionDAGMutation(shouldScheduleAdjacent);
 | 
						|
}
 | 
						|
 | 
						|
} // end namespace llvm
 |