diff options
Diffstat (limited to 'llvm/lib')
| -rw-r--r-- | llvm/lib/CodeGen/GlobalISel/CMakeLists.txt | 2 | ||||
| -rw-r--r-- | llvm/lib/CodeGen/GlobalISel/CSEInfo.cpp | 370 | ||||
| -rw-r--r-- | llvm/lib/CodeGen/GlobalISel/CSEMIRBuilder.cpp | 231 | ||||
| -rw-r--r-- | llvm/lib/CodeGen/GlobalISel/Combiner.cpp | 48 | ||||
| -rw-r--r-- | llvm/lib/CodeGen/GlobalISel/GISelChangeObserver.cpp | 9 | ||||
| -rw-r--r-- | llvm/lib/CodeGen/GlobalISel/IRTranslator.cpp | 105 | ||||
| -rw-r--r-- | llvm/lib/CodeGen/GlobalISel/Legalizer.cpp | 54 | ||||
| -rw-r--r-- | llvm/lib/CodeGen/GlobalISel/LegalizerHelper.cpp | 12 | ||||
| -rw-r--r-- | llvm/lib/CodeGen/GlobalISel/MachineIRBuilder.cpp | 2 | ||||
| -rw-r--r-- | llvm/lib/CodeGen/GlobalISel/Utils.cpp | 51 | ||||
| -rw-r--r-- | llvm/lib/CodeGen/MachineFunction.cpp | 4 | ||||
| -rw-r--r-- | llvm/lib/Target/AArch64/AArch64PreLegalizerCombiner.cpp | 2 | ||||
| -rw-r--r-- | llvm/lib/Target/Mips/MipsPreLegalizerCombiner.cpp | 2 | 
13 files changed, 816 insertions, 76 deletions
| diff --git a/llvm/lib/CodeGen/GlobalISel/CMakeLists.txt b/llvm/lib/CodeGen/GlobalISel/CMakeLists.txt index 5f13692bbee..da2fd3b239a 100644 --- a/llvm/lib/CodeGen/GlobalISel/CMakeLists.txt +++ b/llvm/lib/CodeGen/GlobalISel/CMakeLists.txt @@ -1,4 +1,6 @@  add_llvm_library(LLVMGlobalISel +        CSEInfo.cpp +        CSEMIRBuilder.cpp          CallLowering.cpp          GlobalISel.cpp          Combiner.cpp diff --git a/llvm/lib/CodeGen/GlobalISel/CSEInfo.cpp b/llvm/lib/CodeGen/GlobalISel/CSEInfo.cpp new file mode 100644 index 00000000000..89c525c5ba1 --- /dev/null +++ b/llvm/lib/CodeGen/GlobalISel/CSEInfo.cpp @@ -0,0 +1,370 @@ +//===- CSEInfo.cpp ------------------------------===// +// +//                     The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// +//===----------------------------------------------------------------------===// +#include "llvm/CodeGen/GlobalISel/CSEInfo.h" +#include "llvm/CodeGen/MachineRegisterInfo.h" + +#define DEBUG_TYPE "cseinfo" + +using namespace llvm; +char llvm::GISelCSEAnalysisWrapperPass::ID = 0; +INITIALIZE_PASS_BEGIN(GISelCSEAnalysisWrapperPass, DEBUG_TYPE, +                      "Analysis containing CSE Info", false, true) +INITIALIZE_PASS_END(GISelCSEAnalysisWrapperPass, DEBUG_TYPE, +                    "Analysis containing CSE Info", false, true) + +/// -------- UniqueMachineInstr -------------// + +void UniqueMachineInstr::Profile(FoldingSetNodeID &ID) { +  GISelInstProfileBuilder(ID, MI->getMF()->getRegInfo()).addNodeID(MI); +} +/// ----------------------------------------- + +/// --------- CSEConfig ---------- /// +bool CSEConfig::shouldCSEOpc(unsigned Opc) { +  switch (Opc) { +  default: +    break; +  case TargetOpcode::G_ADD: +  case TargetOpcode::G_AND: +  case TargetOpcode::G_ASHR: +  case TargetOpcode::G_LSHR: +  case TargetOpcode::G_MUL: +  case TargetOpcode::G_OR: +  case TargetOpcode::G_SHL: +  case TargetOpcode::G_SUB: +  case TargetOpcode::G_XOR: +  case TargetOpcode::G_UDIV: +  case TargetOpcode::G_SDIV: +  case TargetOpcode::G_UREM: +  case TargetOpcode::G_SREM: +  case TargetOpcode::G_CONSTANT: +  case TargetOpcode::G_FCONSTANT: +  case TargetOpcode::G_ZEXT: +  case TargetOpcode::G_SEXT: +  case TargetOpcode::G_ANYEXT: +  case TargetOpcode::G_UNMERGE_VALUES: +  case TargetOpcode::G_TRUNC: +    return true; +  } +  return false; +} + +bool CSEConfigConstantOnly::shouldCSEOpc(unsigned Opc) { +  return Opc == TargetOpcode::G_CONSTANT; +} +/// ----------------------------------------- + +/// -------- GISelCSEInfo -------------// +void GISelCSEInfo::setMF(MachineFunction &MF) { +  this->MF = &MF; +  this->MRI = &MF.getRegInfo(); +} + +GISelCSEInfo::~GISelCSEInfo() {} + +bool GISelCSEInfo::isUniqueMachineInstValid( +    const UniqueMachineInstr &UMI) const { +  // Should we check here and assert that the instruction has been fully +  // constructed? +  // FIXME: Any other checks required to be done here? Remove this method if +  // none. +  return true; +} + +void GISelCSEInfo::invalidateUniqueMachineInstr(UniqueMachineInstr *UMI) { +  bool Removed = CSEMap.RemoveNode(UMI); +  (void)Removed; +  assert(Removed && "Invalidation called on invalid UMI"); +  // FIXME: Should UMI be deallocated/destroyed? +} + +UniqueMachineInstr *GISelCSEInfo::getNodeIfExists(FoldingSetNodeID &ID, +                                                  MachineBasicBlock *MBB, +                                                  void *&InsertPos) { +  auto *Node = CSEMap.FindNodeOrInsertPos(ID, InsertPos); +  if (Node) { +    if (!isUniqueMachineInstValid(*Node)) { +      invalidateUniqueMachineInstr(Node); +      return nullptr; +    } + +    if (Node->MI->getParent() != MBB) +      return nullptr; +  } +  return Node; +} + +void GISelCSEInfo::insertNode(UniqueMachineInstr *UMI, void *InsertPos) { +  handleRecordedInsts(); +  assert(UMI); +  UniqueMachineInstr *MaybeNewNode = UMI; +  if (InsertPos) +    CSEMap.InsertNode(UMI, InsertPos); +  else +    MaybeNewNode = CSEMap.GetOrInsertNode(UMI); +  if (MaybeNewNode != UMI) { +    // A similar node exists in the folding set. Let's ignore this one. +    return; +  } +  assert(InstrMapping.count(UMI->MI) == 0 && +         "This instruction should not be in the map"); +  InstrMapping[UMI->MI] = MaybeNewNode; +} + +UniqueMachineInstr *GISelCSEInfo::getUniqueInstrForMI(const MachineInstr *MI) { +  assert(shouldCSE(MI->getOpcode()) && "Trying to CSE an unsupported Node"); +  auto *Node = new (UniqueInstrAllocator) UniqueMachineInstr(MI); +  return Node; +} + +void GISelCSEInfo::insertInstr(MachineInstr *MI, void *InsertPos) { +  assert(MI); +  // If it exists in temporary insts, remove it. +  TemporaryInsts.remove(MI); +  auto *Node = getUniqueInstrForMI(MI); +  insertNode(Node, InsertPos); +} + +MachineInstr *GISelCSEInfo::getMachineInstrIfExists(FoldingSetNodeID &ID, +                                                    MachineBasicBlock *MBB, +                                                    void *&InsertPos) { +  handleRecordedInsts(); +  if (auto *Inst = getNodeIfExists(ID, MBB, InsertPos)) { +    LLVM_DEBUG(dbgs() << "CSEInfo: Found Instr " << *Inst->MI << "\n";); +    return const_cast<MachineInstr *>(Inst->MI); +  } +  return nullptr; +} + +void GISelCSEInfo::countOpcodeHit(unsigned Opc) { +#ifndef NDEBUG +  if (OpcodeHitTable.count(Opc)) +    OpcodeHitTable[Opc] += 1; +  else +    OpcodeHitTable[Opc] = 1; +#endif +  // Else do nothing. +} + +void GISelCSEInfo::recordNewInstruction(MachineInstr *MI) { +  if (shouldCSE(MI->getOpcode())) { +    TemporaryInsts.insert(MI); +    LLVM_DEBUG(dbgs() << "CSEInfo: Recording new MI" << *MI << "\n";); +  } +} + +void GISelCSEInfo::handleRecordedInst(MachineInstr *MI) { +  assert(shouldCSE(MI->getOpcode()) && "Invalid instruction for CSE"); +  auto *UMI = InstrMapping.lookup(MI); +  LLVM_DEBUG(dbgs() << "CSEInfo: Handling recorded MI" << *MI << "\n";); +  if (UMI) { +    // Invalidate this MI. +    invalidateUniqueMachineInstr(UMI); +    InstrMapping.erase(MI); +  } +  /// Now insert the new instruction. +  if (UMI) { +    /// We'll reuse the same UniqueMachineInstr to avoid the new +    /// allocation. +    *UMI = UniqueMachineInstr(MI); +    insertNode(UMI, nullptr); +  } else { +    /// This is a new instruction. Allocate a new UniqueMachineInstr and +    /// Insert. +    insertInstr(MI); +  } +} + +void GISelCSEInfo::handleRemoveInst(MachineInstr *MI) { +  if (auto *UMI = InstrMapping.lookup(MI)) { +    invalidateUniqueMachineInstr(UMI); +    InstrMapping.erase(MI); +  } +  TemporaryInsts.remove(MI); +} + +void GISelCSEInfo::handleRecordedInsts() { +  while (!TemporaryInsts.empty()) { +    auto *MI = TemporaryInsts.pop_back_val(); +    handleRecordedInst(MI); +  } +} + +bool GISelCSEInfo::shouldCSE(unsigned Opc) const { +  // Only GISel opcodes are CSEable +  if (!isPreISelGenericOpcode(Opc)) +    return false; +  assert(CSEOpt.get() && "CSEConfig not set"); +  return CSEOpt->shouldCSEOpc(Opc); +} + +void GISelCSEInfo::erasingInstr(MachineInstr &MI) { handleRemoveInst(&MI); } +void GISelCSEInfo::createdInstr(MachineInstr &MI) { recordNewInstruction(&MI); } +void GISelCSEInfo::changingInstr(MachineInstr &MI) { +  // For now, perform erase, followed by insert. +  erasingInstr(MI); +  createdInstr(MI); +} +void GISelCSEInfo::changedInstr(MachineInstr &MI) { changingInstr(MI); } + +void GISelCSEInfo::analyze(MachineFunction &MF) { +  setMF(MF); +  for (auto &MBB : MF) { +    if (MBB.empty()) +      continue; +    for (MachineInstr &MI : MBB) { +      if (!shouldCSE(MI.getOpcode())) +        continue; +      LLVM_DEBUG(dbgs() << "CSEInfo::Add MI: " << MI << "\n";); +      insertInstr(&MI); +    } +  } +} + +void GISelCSEInfo::releaseMemory() { +  // print(); +  CSEMap.clear(); +  InstrMapping.clear(); +  UniqueInstrAllocator.Reset(); +  TemporaryInsts.clear(); +  CSEOpt.reset(); +  MRI = nullptr; +  MF = nullptr; +#ifndef NDEBUG +  OpcodeHitTable.clear(); +#endif +} + +void GISelCSEInfo::print() { +#ifndef NDEBUG +  for (auto &It : OpcodeHitTable) { +    dbgs() << "CSE Count for Opc " << It.first << " : " << It.second << "\n"; +  }; +#endif +} +/// ----------------------------------------- +// ---- Profiling methods for FoldingSetNode --- // +const GISelInstProfileBuilder & +GISelInstProfileBuilder::addNodeID(const MachineInstr *MI) const { +  addNodeIDMBB(MI->getParent()); +  addNodeIDOpcode(MI->getOpcode()); +  for (auto &Op : MI->operands()) +    addNodeIDMachineOperand(Op); +  addNodeIDFlag(MI->getFlags()); +  return *this; +} + +const GISelInstProfileBuilder & +GISelInstProfileBuilder::addNodeIDOpcode(unsigned Opc) const { +  ID.AddInteger(Opc); +  return *this; +} + +const GISelInstProfileBuilder & +GISelInstProfileBuilder::addNodeIDRegType(const LLT &Ty) const { +  uint64_t Val = Ty.getUniqueRAWLLTData(); +  ID.AddInteger(Val); +  return *this; +} + +const GISelInstProfileBuilder & +GISelInstProfileBuilder::addNodeIDRegType(const TargetRegisterClass *RC) const { +  ID.AddPointer(RC); +  return *this; +} + +const GISelInstProfileBuilder & +GISelInstProfileBuilder::addNodeIDRegType(const RegisterBank *RB) const { +  ID.AddPointer(RB); +  return *this; +} + +const GISelInstProfileBuilder & +GISelInstProfileBuilder::addNodeIDImmediate(int64_t Imm) const { +  ID.AddInteger(Imm); +  return *this; +} + +const GISelInstProfileBuilder & +GISelInstProfileBuilder::addNodeIDRegNum(unsigned Reg) const { +  ID.AddInteger(Reg); +  return *this; +} + +const GISelInstProfileBuilder & +GISelInstProfileBuilder::addNodeIDRegType(const unsigned Reg) const { +  addNodeIDMachineOperand(MachineOperand::CreateReg(Reg, false)); +  return *this; +} + +const GISelInstProfileBuilder & +GISelInstProfileBuilder::addNodeIDMBB(const MachineBasicBlock *MBB) const { +  ID.AddPointer(MBB); +  return *this; +} + +const GISelInstProfileBuilder & +GISelInstProfileBuilder::addNodeIDFlag(unsigned Flag) const { +  if (Flag) +    ID.AddInteger(Flag); +  return *this; +} + +const GISelInstProfileBuilder &GISelInstProfileBuilder::addNodeIDMachineOperand( +    const MachineOperand &MO) const { +  if (MO.isReg()) { +    unsigned Reg = MO.getReg(); +    if (!MO.isDef()) +      addNodeIDRegNum(Reg); +    LLT Ty = MRI.getType(Reg); +    if (Ty.isValid()) +      addNodeIDRegType(Ty); +    auto *RB = MRI.getRegBankOrNull(Reg); +    if (RB) +      addNodeIDRegType(RB); +    auto *RC = MRI.getRegClassOrNull(Reg); +    if (RC) +      addNodeIDRegType(RC); +    assert(!MO.isImplicit() && "Unhandled case"); +  } else if (MO.isImm()) +    ID.AddInteger(MO.getImm()); +  else if (MO.isCImm()) +    ID.AddPointer(MO.getCImm()); +  else if (MO.isFPImm()) +    ID.AddPointer(MO.getFPImm()); +  else if (MO.isPredicate()) +    ID.AddInteger(MO.getPredicate()); +  else +    llvm_unreachable("Unhandled operand type"); +  // Handle other types +  return *this; +} + +GISelCSEInfo &GISelCSEAnalysisWrapper::get(std::unique_ptr<CSEConfig> CSEOpt, +                                           bool Recompute) { +  if (!AlreadyComputed || Recompute) { +    Info.setCSEConfig(std::move(CSEOpt)); +    Info.analyze(*MF); +    AlreadyComputed = true; +  } +  return Info; +} +void GISelCSEAnalysisWrapperPass::getAnalysisUsage(AnalysisUsage &AU) const { +  AU.setPreservesAll(); +  MachineFunctionPass::getAnalysisUsage(AU); +} + +bool GISelCSEAnalysisWrapperPass::runOnMachineFunction(MachineFunction &MF) { +  releaseMemory(); +  Wrapper.setMF(MF); +  return false; +} diff --git a/llvm/lib/CodeGen/GlobalISel/CSEMIRBuilder.cpp b/llvm/lib/CodeGen/GlobalISel/CSEMIRBuilder.cpp new file mode 100644 index 00000000000..863efe0c3e3 --- /dev/null +++ b/llvm/lib/CodeGen/GlobalISel/CSEMIRBuilder.cpp @@ -0,0 +1,231 @@ +//===-- llvm/CodeGen/GlobalISel/CSEMIRBuilder.cpp - MIBuilder--*- C++ -*-==// +// +//                     The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +/// \file +/// This file implements the CSEMIRBuilder class which CSEs as it builds +/// instructions. +//===----------------------------------------------------------------------===// +// + +#include "llvm/CodeGen/GlobalISel/CSEMIRBuilder.h" +#include "llvm/CodeGen/GlobalISel/GISelChangeObserver.h" + +using namespace llvm; + +bool CSEMIRBuilder::dominates(MachineBasicBlock::const_iterator A, +                              MachineBasicBlock::const_iterator B) const { +  auto MBBEnd = getMBB().end(); +  if (B == MBBEnd) +    return true; +  assert(A->getParent() == B->getParent() && +         "Iterators should be in same block"); +  const MachineBasicBlock *BBA = A->getParent(); +  MachineBasicBlock::const_iterator I = BBA->begin(); +  for (; &*I != A && &*I != B; ++I) +    ; +  return &*I == A; +} + +MachineInstrBuilder +CSEMIRBuilder::getDominatingInstrForID(FoldingSetNodeID &ID, +                                       void *&NodeInsertPos) { +  GISelCSEInfo *CSEInfo = getCSEInfo(); +  assert(CSEInfo && "Can't get here without setting CSEInfo"); +  MachineBasicBlock *CurMBB = &getMBB(); +  MachineInstr *MI = +      CSEInfo->getMachineInstrIfExists(ID, CurMBB, NodeInsertPos); +  if (MI) { +    auto CurrPos = getInsertPt(); +    if (!dominates(MI, CurrPos)) +      CurMBB->splice(CurrPos, CurMBB, MI); +    return MachineInstrBuilder(getMF(), MI); +  } +  return MachineInstrBuilder(); +} + +bool CSEMIRBuilder::canPerformCSEForOpc(unsigned Opc) const { +  const GISelCSEInfo *CSEInfo = getCSEInfo(); +  if (!CSEInfo || !CSEInfo->shouldCSE(Opc)) +    return false; +  return true; +} + +void CSEMIRBuilder::profileDstOp(const DstOp &Op, +                                 GISelInstProfileBuilder &B) const { +  switch (Op.getDstOpKind()) { +  case DstOp::DstType::Ty_RC: +    B.addNodeIDRegType(Op.getRegClass()); +    break; +  default: +    B.addNodeIDRegType(Op.getLLTTy(*getMRI())); +    break; +  } +} + +void CSEMIRBuilder::profileSrcOp(const SrcOp &Op, +                                 GISelInstProfileBuilder &B) const { +  switch (Op.getSrcOpKind()) { +  case SrcOp::SrcType::Ty_Predicate: +    B.addNodeIDImmediate(static_cast<int64_t>(Op.getPredicate())); +    break; +  default: +    B.addNodeIDRegType(Op.getReg()); +    break; +  } +} + +void CSEMIRBuilder::profileMBBOpcode(GISelInstProfileBuilder &B, +                                     unsigned Opc) const { +  // First add the MBB (Local CSE). +  B.addNodeIDMBB(&getMBB()); +  // Then add the opcode. +  B.addNodeIDOpcode(Opc); +} + +void CSEMIRBuilder::profileEverything(unsigned Opc, ArrayRef<DstOp> DstOps, +                                      ArrayRef<SrcOp> SrcOps, +                                      Optional<unsigned> Flags, +                                      GISelInstProfileBuilder &B) const { + +  profileMBBOpcode(B, Opc); +  // Then add the DstOps. +  profileDstOps(DstOps, B); +  // Then add the SrcOps. +  profileSrcOps(SrcOps, B); +  // Add Flags if passed in. +  if (Flags) +    B.addNodeIDFlag(*Flags); +} + +MachineInstrBuilder CSEMIRBuilder::memoizeMI(MachineInstrBuilder MIB, +                                             void *NodeInsertPos) { +  assert(canPerformCSEForOpc(MIB->getOpcode()) && +         "Attempting to CSE illegal op"); +  MachineInstr *MIBInstr = MIB; +  getCSEInfo()->insertInstr(MIBInstr, NodeInsertPos); +  return MIB; +} + +bool CSEMIRBuilder::checkCopyToDefsPossible(ArrayRef<DstOp> DstOps) { +  if (DstOps.size() == 1) +    return true; // always possible to emit copy to just 1 vreg. + +  return std::all_of(DstOps.begin(), DstOps.end(), [](const DstOp &Op) { +    DstOp::DstType DT = Op.getDstOpKind(); +    return DT == DstOp::DstType::Ty_LLT || DT == DstOp::DstType::Ty_RC; +  }); +} + +MachineInstrBuilder +CSEMIRBuilder::generateCopiesIfRequired(ArrayRef<DstOp> DstOps, +                                        MachineInstrBuilder &MIB) { +  assert(checkCopyToDefsPossible(DstOps) && +         "Impossible return a single MIB with copies to multiple defs"); +  if (DstOps.size() == 1) { +    const DstOp &Op = DstOps[0]; +    if (Op.getDstOpKind() == DstOp::DstType::Ty_Reg) +      return buildCopy(Op.getReg(), MIB->getOperand(0).getReg()); +  } +  return MIB; +} + +MachineInstrBuilder CSEMIRBuilder::buildInstr(unsigned Opc, +                                              ArrayRef<DstOp> DstOps, +                                              ArrayRef<SrcOp> SrcOps, +                                              Optional<unsigned> Flag) { +  switch (Opc) { +  default: +    break; +  case TargetOpcode::G_ADD: +  case TargetOpcode::G_AND: +  case TargetOpcode::G_ASHR: +  case TargetOpcode::G_LSHR: +  case TargetOpcode::G_MUL: +  case TargetOpcode::G_OR: +  case TargetOpcode::G_SHL: +  case TargetOpcode::G_SUB: +  case TargetOpcode::G_XOR: +  case TargetOpcode::G_UDIV: +  case TargetOpcode::G_SDIV: +  case TargetOpcode::G_UREM: +  case TargetOpcode::G_SREM: { +    // Try to constant fold these. +    assert(SrcOps.size() == 2 && "Invalid sources"); +    assert(DstOps.size() == 1 && "Invalid dsts"); +    if (Optional<APInt> Cst = ConstantFoldBinOp(Opc, SrcOps[0].getReg(), +                                                SrcOps[1].getReg(), *getMRI())) +      return buildConstant(DstOps[0], Cst->getSExtValue()); +    break; +  } +  } +  bool CanCopy = checkCopyToDefsPossible(DstOps); +  if (!canPerformCSEForOpc(Opc)) +    return MachineIRBuilder::buildInstr(Opc, DstOps, SrcOps, Flag); +  // If we can CSE this instruction, but involves generating copies to multiple +  // regs, give up. This frequently happens to UNMERGEs. +  if (!CanCopy) { +    auto MIB = MachineIRBuilder::buildInstr(Opc, DstOps, SrcOps, Flag); +    // CSEInfo would have tracked this instruction. Remove it from the temporary +    // insts. +    getCSEInfo()->handleRemoveInst(&*MIB); +    return MIB; +  } +  FoldingSetNodeID ID; +  GISelInstProfileBuilder ProfBuilder(ID, *getMRI()); +  void *InsertPos = nullptr; +  profileEverything(Opc, DstOps, SrcOps, Flag, ProfBuilder); +  MachineInstrBuilder MIB = getDominatingInstrForID(ID, InsertPos); +  if (MIB) { +    // Handle generating copies here. +    return generateCopiesIfRequired(DstOps, MIB); +  } +  // This instruction does not exist in the CSEInfo. Build it and CSE it. +  MachineInstrBuilder NewMIB = +      MachineIRBuilder::buildInstr(Opc, DstOps, SrcOps, Flag); +  return memoizeMI(NewMIB, InsertPos); +} + +MachineInstrBuilder CSEMIRBuilder::buildConstant(const DstOp &Res, +                                                 const ConstantInt &Val) { +  constexpr unsigned Opc = TargetOpcode::G_CONSTANT; +  if (!canPerformCSEForOpc(Opc)) +    return MachineIRBuilder::buildConstant(Res, Val); +  FoldingSetNodeID ID; +  GISelInstProfileBuilder ProfBuilder(ID, *getMRI()); +  void *InsertPos = nullptr; +  profileMBBOpcode(ProfBuilder, Opc); +  profileDstOp(Res, ProfBuilder); +  ProfBuilder.addNodeIDMachineOperand(MachineOperand::CreateCImm(&Val)); +  MachineInstrBuilder MIB = getDominatingInstrForID(ID, InsertPos); +  if (MIB) { +    // Handle generating copies here. +    return generateCopiesIfRequired({Res}, MIB); +  } +  MachineInstrBuilder NewMIB = MachineIRBuilder::buildConstant(Res, Val); +  return memoizeMI(NewMIB, InsertPos); +} + +MachineInstrBuilder CSEMIRBuilder::buildFConstant(const DstOp &Res, +                                                  const ConstantFP &Val) { +  constexpr unsigned Opc = TargetOpcode::G_FCONSTANT; +  if (!canPerformCSEForOpc(Opc)) +    return MachineIRBuilder::buildFConstant(Res, Val); +  FoldingSetNodeID ID; +  GISelInstProfileBuilder ProfBuilder(ID, *getMRI()); +  void *InsertPos = nullptr; +  profileMBBOpcode(ProfBuilder, Opc); +  profileDstOp(Res, ProfBuilder); +  ProfBuilder.addNodeIDMachineOperand(MachineOperand::CreateFPImm(&Val)); +  MachineInstrBuilder MIB = getDominatingInstrForID(ID, InsertPos); +  if (MIB) { +    // Handle generating copies here. +    return generateCopiesIfRequired({Res}, MIB); +  } +  MachineInstrBuilder NewMIB = MachineIRBuilder::buildFConstant(Res, Val); +  return memoizeMI(NewMIB, InsertPos); +} diff --git a/llvm/lib/CodeGen/GlobalISel/Combiner.cpp b/llvm/lib/CodeGen/GlobalISel/Combiner.cpp index 90fd54ec244..45b0e36fd7d 100644 --- a/llvm/lib/CodeGen/GlobalISel/Combiner.cpp +++ b/llvm/lib/CodeGen/GlobalISel/Combiner.cpp @@ -13,7 +13,9 @@  #include "llvm/CodeGen/GlobalISel/Combiner.h"  #include "llvm/ADT/PostOrderIterator.h" +#include "llvm/CodeGen/GlobalISel/CSEInfo.h"  #include "llvm/CodeGen/GlobalISel/CombinerInfo.h" +#include "llvm/CodeGen/GlobalISel/CSEMIRBuilder.h"  #include "llvm/CodeGen/GlobalISel/GISelChangeObserver.h"  #include "llvm/CodeGen/GlobalISel/GISelWorkList.h"  #include "llvm/CodeGen/GlobalISel/MachineIRBuilder.h" @@ -35,38 +37,33 @@ namespace {  /// instruction creation will schedule that instruction for a future visit.  /// Other Combiner implementations may require more complex behaviour from  /// their GISelChangeObserver subclass. -class WorkListMaintainer : public GISelChangeObserver, -                           public MachineFunction::Delegate { +class WorkListMaintainer : public GISelChangeObserver {    using WorkListTy = GISelWorkList<512>; -  MachineFunction &MF;    WorkListTy &WorkList;    /// The instructions that have been created but we want to report once they    /// have their operands. This is only maintained if debug output is requested.    SmallPtrSet<const MachineInstr *, 4> CreatedInstrs;  public: -  WorkListMaintainer(MachineFunction &MF, WorkListTy &WorkList) -      : GISelChangeObserver(), MF(MF), WorkList(WorkList) { -    MF.setDelegate(this); -  } +  WorkListMaintainer(WorkListTy &WorkList) +      : GISelChangeObserver(), WorkList(WorkList) {}    virtual ~WorkListMaintainer() { -    MF.resetDelegate(this);    } -  void erasingInstr(const MachineInstr &MI) override { +  void erasingInstr(MachineInstr &MI) override {      LLVM_DEBUG(dbgs() << "Erased: " << MI << "\n");      WorkList.remove(&MI);    } -  void createdInstr(const MachineInstr &MI) override { +  void createdInstr(MachineInstr &MI) override {      LLVM_DEBUG(dbgs() << "Creating: " << MI << "\n");      WorkList.insert(&MI);      LLVM_DEBUG(CreatedInstrs.insert(&MI));    } -  void changingInstr(const MachineInstr &MI) override { +  void changingInstr(MachineInstr &MI) override {      LLVM_DEBUG(dbgs() << "Changing: " << MI << "\n");      WorkList.insert(&MI);    } -  void changedInstr(const MachineInstr &MI) override { +  void changedInstr(MachineInstr &MI) override {      LLVM_DEBUG(dbgs() << "Changed: " << MI << "\n");      WorkList.insert(&MI);    } @@ -79,13 +76,6 @@ public:      });      LLVM_DEBUG(CreatedInstrs.clear());    } - -  void MF_HandleInsertion(const MachineInstr &MI) override { -    createdInstr(MI); -  } -  void MF_HandleRemoval(const MachineInstr &MI) override { -    erasingInstr(MI); -  }  };  } @@ -94,15 +84,20 @@ Combiner::Combiner(CombinerInfo &Info, const TargetPassConfig *TPC)    (void)this->TPC; // FIXME: Remove when used.  } -bool Combiner::combineMachineInstrs(MachineFunction &MF) { +bool Combiner::combineMachineInstrs(MachineFunction &MF, +                                    GISelCSEInfo *CSEInfo) {    // If the ISel pipeline failed, do not bother running this pass.    // FIXME: Should this be here or in individual combiner passes.    if (MF.getProperties().hasProperty(            MachineFunctionProperties::Property::FailedISel))      return false; +  Builder = +      CSEInfo ? make_unique<CSEMIRBuilder>() : make_unique<MachineIRBuilder>();    MRI = &MF.getRegInfo(); -  Builder.setMF(MF); +  Builder->setMF(MF); +  if (CSEInfo) +    Builder->setCSEInfo(CSEInfo);    LLVM_DEBUG(dbgs() << "Generic MI Combiner for: " << MF.getName() << '\n'); @@ -110,14 +105,19 @@ bool Combiner::combineMachineInstrs(MachineFunction &MF) {    bool MFChanged = false;    bool Changed; +  MachineIRBuilder &B = *Builder.get();    do {      // Collect all instructions. Do a post order traversal for basic blocks and      // insert with list bottom up, so while we pop_back_val, we'll traverse top      // down RPOT.      Changed = false; -    GISelWorkList<512> WorkList(&MF); -    WorkListMaintainer Observer(MF, WorkList); +    GISelWorkList<512> WorkList; +    WorkListMaintainer Observer(WorkList); +    GISelObserverWrapper WrapperObserver(&Observer); +    if (CSEInfo) +      WrapperObserver.addObserver(CSEInfo); +    RAIIDelegateInstaller DelInstall(MF, &WrapperObserver);      for (MachineBasicBlock *MBB : post_order(&MF)) {        if (MBB->empty())          continue; @@ -137,7 +137,7 @@ bool Combiner::combineMachineInstrs(MachineFunction &MF) {      while (!WorkList.empty()) {        MachineInstr *CurrInst = WorkList.pop_back_val();        LLVM_DEBUG(dbgs() << "\nTry combining " << *CurrInst;); -      Changed |= CInfo.combine(Observer, *CurrInst, Builder); +      Changed |= CInfo.combine(WrapperObserver, *CurrInst, B);        Observer.reportFullyCreatedInstrs();      }      MFChanged |= Changed; diff --git a/llvm/lib/CodeGen/GlobalISel/GISelChangeObserver.cpp b/llvm/lib/CodeGen/GlobalISel/GISelChangeObserver.cpp index 993a919826f..c693acbbf10 100644 --- a/llvm/lib/CodeGen/GlobalISel/GISelChangeObserver.cpp +++ b/llvm/lib/CodeGen/GlobalISel/GISelChangeObserver.cpp @@ -29,3 +29,12 @@ void GISelChangeObserver::finishedChangingAllUsesOfReg() {      changedInstr(*ChangedMI);  } +RAIIDelegateInstaller::RAIIDelegateInstaller(MachineFunction &MF, +                                             MachineFunction::Delegate *Del) +    : MF(MF), Delegate(Del) { +  // Register this as the delegate for handling insertions and deletions of +  // instructions. +  MF.setDelegate(Del); +} + +RAIIDelegateInstaller::~RAIIDelegateInstaller() { MF.resetDelegate(Delegate); } diff --git a/llvm/lib/CodeGen/GlobalISel/IRTranslator.cpp b/llvm/lib/CodeGen/GlobalISel/IRTranslator.cpp index 4db5d1c2ea1..95f6274aa06 100644 --- a/llvm/lib/CodeGen/GlobalISel/IRTranslator.cpp +++ b/llvm/lib/CodeGen/GlobalISel/IRTranslator.cpp @@ -19,6 +19,7 @@  #include "llvm/Analysis/OptimizationRemarkEmitter.h"  #include "llvm/CodeGen/Analysis.h"  #include "llvm/CodeGen/GlobalISel/CallLowering.h" +#include "llvm/CodeGen/GlobalISel/GISelChangeObserver.h"  #include "llvm/CodeGen/LowLevelType.h"  #include "llvm/CodeGen/MachineBasicBlock.h"  #include "llvm/CodeGen/MachineFrameInfo.h" @@ -75,11 +76,16 @@  using namespace llvm; +static cl::opt<bool> +    EnableCSEInIRTranslator("enable-cse-in-irtranslator", +                            cl::desc("Should enable CSE in irtranslator"), +                            cl::Optional, cl::init(false));  char IRTranslator::ID = 0;  INITIALIZE_PASS_BEGIN(IRTranslator, DEBUG_TYPE, "IRTranslator LLVM IR -> MI",                  false, false)  INITIALIZE_PASS_DEPENDENCY(TargetPassConfig) +INITIALIZE_PASS_DEPENDENCY(GISelCSEAnalysisWrapperPass)  INITIALIZE_PASS_END(IRTranslator, DEBUG_TYPE, "IRTranslator LLVM IR -> MI",                  false, false) @@ -108,18 +114,21 @@ IRTranslator::IRTranslator() : MachineFunctionPass(ID) {  namespace {  /// Verify that every instruction created has the same DILocation as the  /// instruction being translated. -class DILocationVerifier : MachineFunction::Delegate { -  MachineFunction &MF; +class DILocationVerifier : public GISelChangeObserver {    const Instruction *CurrInst = nullptr;  public: -  DILocationVerifier(MachineFunction &MF) : MF(MF) { MF.setDelegate(this); } -  ~DILocationVerifier() { MF.resetDelegate(this); } +  DILocationVerifier() = default; +  ~DILocationVerifier() = default;    const Instruction *getCurrentInst() const { return CurrInst; }    void setCurrentInst(const Instruction *Inst) { CurrInst = Inst; } -  void MF_HandleInsertion(const MachineInstr &MI) override { +  void erasingInstr(MachineInstr &MI) override {} +  void changingInstr(MachineInstr &MI) override {} +  void changedInstr(MachineInstr &MI) override {} + +  void createdInstr(MachineInstr &MI) override {      assert(getCurrentInst() && "Inserted instruction without a current MI");      // Only print the check message if we're actually checking it. @@ -130,7 +139,6 @@ public:      assert(CurrInst->getDebugLoc() == MI.getDebugLoc() &&             "Line info was not transferred to all instructions");    } -  void MF_HandleRemoval(const MachineInstr &MI) override {}  };  } // namespace  #endif // ifndef NDEBUG @@ -139,6 +147,7 @@ public:  void IRTranslator::getAnalysisUsage(AnalysisUsage &AU) const {    AU.addRequired<StackProtector>();    AU.addRequired<TargetPassConfig>(); +  AU.addRequired<GISelCSEAnalysisWrapperPass>();    getSelectionDAGFallbackAnalysisUsage(AU);    MachineFunctionPass::getAnalysisUsage(AU);  } @@ -1553,12 +1562,14 @@ bool IRTranslator::translateAtomicRMW(const User &U,  void IRTranslator::finishPendingPhis() {  #ifndef NDEBUG -  DILocationVerifier Verifier(*MF); +  DILocationVerifier Verifier; +  GISelObserverWrapper WrapperObserver(&Verifier); +  RAIIDelegateInstaller DelInstall(*MF, &WrapperObserver);  #endif // ifndef NDEBUG    for (auto &Phi : PendingPHIs) {      const PHINode *PI = Phi.first;      ArrayRef<MachineInstr *> ComponentPHIs = Phi.second; -    EntryBuilder.setDebugLoc(PI->getDebugLoc()); +    EntryBuilder->setDebugLoc(PI->getDebugLoc());  #ifndef NDEBUG      Verifier.setCurrentInst(PI);  #endif // ifndef NDEBUG @@ -1599,11 +1610,12 @@ bool IRTranslator::valueIsSplit(const Value &V,  }  bool IRTranslator::translate(const Instruction &Inst) { -  CurBuilder.setDebugLoc(Inst.getDebugLoc()); -  EntryBuilder.setDebugLoc(Inst.getDebugLoc()); +  CurBuilder->setDebugLoc(Inst.getDebugLoc()); +  EntryBuilder->setDebugLoc(Inst.getDebugLoc());    switch(Inst.getOpcode()) { -#define HANDLE_INST(NUM, OPCODE, CLASS) \ -    case Instruction::OPCODE: return translate##OPCODE(Inst, CurBuilder); +#define HANDLE_INST(NUM, OPCODE, CLASS)                                        \ +  case Instruction::OPCODE:                                                    \ +    return translate##OPCODE(Inst, *CurBuilder.get());  #include "llvm/IR/Instruction.def"    default:      return false; @@ -1612,11 +1624,11 @@ bool IRTranslator::translate(const Instruction &Inst) {  bool IRTranslator::translate(const Constant &C, unsigned Reg) {    if (auto CI = dyn_cast<ConstantInt>(&C)) -    EntryBuilder.buildConstant(Reg, *CI); +    EntryBuilder->buildConstant(Reg, *CI);    else if (auto CF = dyn_cast<ConstantFP>(&C)) -    EntryBuilder.buildFConstant(Reg, *CF); +    EntryBuilder->buildFConstant(Reg, *CF);    else if (isa<UndefValue>(C)) -    EntryBuilder.buildUndef(Reg); +    EntryBuilder->buildUndef(Reg);    else if (isa<ConstantPointerNull>(C)) {      // As we are trying to build a constant val of 0 into a pointer,      // insert a cast to make them correct with respect to types. @@ -1624,9 +1636,9 @@ bool IRTranslator::translate(const Constant &C, unsigned Reg) {      auto *ZeroTy = Type::getIntNTy(C.getContext(), NullSize);      auto *ZeroVal = ConstantInt::get(ZeroTy, 0);      unsigned ZeroReg = getOrCreateVReg(*ZeroVal); -    EntryBuilder.buildCast(Reg, ZeroReg); +    EntryBuilder->buildCast(Reg, ZeroReg);    } else if (auto GV = dyn_cast<GlobalValue>(&C)) -    EntryBuilder.buildGlobalValue(Reg, GV); +    EntryBuilder->buildGlobalValue(Reg, GV);    else if (auto CAZ = dyn_cast<ConstantAggregateZero>(&C)) {      if (!CAZ->getType()->isVectorTy())        return false; @@ -1638,7 +1650,7 @@ bool IRTranslator::translate(const Constant &C, unsigned Reg) {        Constant &Elt = *CAZ->getElementValue(i);        Ops.push_back(getOrCreateVReg(Elt));      } -    EntryBuilder.buildBuildVector(Reg, Ops); +    EntryBuilder->buildBuildVector(Reg, Ops);    } else if (auto CV = dyn_cast<ConstantDataVector>(&C)) {      // Return the scalar if it is a <1 x Ty> vector.      if (CV->getNumElements() == 1) @@ -1648,11 +1660,12 @@ bool IRTranslator::translate(const Constant &C, unsigned Reg) {        Constant &Elt = *CV->getElementAsConstant(i);        Ops.push_back(getOrCreateVReg(Elt));      } -    EntryBuilder.buildBuildVector(Reg, Ops); +    EntryBuilder->buildBuildVector(Reg, Ops);    } else if (auto CE = dyn_cast<ConstantExpr>(&C)) {      switch(CE->getOpcode()) { -#define HANDLE_INST(NUM, OPCODE, CLASS)                         \ -      case Instruction::OPCODE: return translate##OPCODE(*CE, EntryBuilder); +#define HANDLE_INST(NUM, OPCODE, CLASS)                                        \ +  case Instruction::OPCODE:                                                    \ +    return translate##OPCODE(*CE, *EntryBuilder.get());  #include "llvm/IR/Instruction.def"      default:        return false; @@ -1664,9 +1677,9 @@ bool IRTranslator::translate(const Constant &C, unsigned Reg) {      for (unsigned i = 0; i < CV->getNumOperands(); ++i) {        Ops.push_back(getOrCreateVReg(*CV->getOperand(i)));      } -    EntryBuilder.buildBuildVector(Reg, Ops); +    EntryBuilder->buildBuildVector(Reg, Ops);    } else if (auto *BA = dyn_cast<BlockAddress>(&C)) { -    EntryBuilder.buildBlockAddress(Reg, BA); +    EntryBuilder->buildBlockAddress(Reg, BA);    } else      return false; @@ -1683,8 +1696,8 @@ void IRTranslator::finalizeFunction() {    // MachineIRBuilder::DebugLoc can outlive the DILocation it holds. Clear it    // to avoid accessing free’d memory (in runOnMachineFunction) and to avoid    // destroying it twice (in ~IRTranslator() and ~LLVMContext()) -  EntryBuilder = MachineIRBuilder(); -  CurBuilder = MachineIRBuilder(); +  EntryBuilder.reset(); +  CurBuilder.reset();  }  bool IRTranslator::runOnMachineFunction(MachineFunction &CurMF) { @@ -1692,12 +1705,30 @@ bool IRTranslator::runOnMachineFunction(MachineFunction &CurMF) {    const Function &F = MF->getFunction();    if (F.empty())      return false; +  GISelCSEAnalysisWrapper &Wrapper = +      getAnalysis<GISelCSEAnalysisWrapperPass>().getCSEWrapper(); +  // Set the CSEConfig and run the analysis. +  GISelCSEInfo *CSEInfo = nullptr; +  TPC = &getAnalysis<TargetPassConfig>(); +  bool IsO0 = TPC->getOptLevel() == CodeGenOpt::Level::None; +  // Disable CSE for O0. +  bool EnableCSE = !IsO0 && EnableCSEInIRTranslator; +  if (EnableCSE) { +    EntryBuilder = make_unique<CSEMIRBuilder>(CurMF); +    std::unique_ptr<CSEConfig> Config = make_unique<CSEConfig>(); +    CSEInfo = &Wrapper.get(std::move(Config)); +    EntryBuilder->setCSEInfo(CSEInfo); +    CurBuilder = make_unique<CSEMIRBuilder>(CurMF); +    CurBuilder->setCSEInfo(CSEInfo); +  } else { +    EntryBuilder = make_unique<MachineIRBuilder>(); +    CurBuilder = make_unique<MachineIRBuilder>(); +  }    CLI = MF->getSubtarget().getCallLowering(); -  CurBuilder.setMF(*MF); -  EntryBuilder.setMF(*MF); +  CurBuilder->setMF(*MF); +  EntryBuilder->setMF(*MF);    MRI = &MF->getRegInfo();    DL = &F.getParent()->getDataLayout(); -  TPC = &getAnalysis<TargetPassConfig>();    ORE = llvm::make_unique<OptimizationRemarkEmitter>(&F);    assert(PendingPHIs.empty() && "stale PHIs"); @@ -1716,7 +1747,7 @@ bool IRTranslator::runOnMachineFunction(MachineFunction &CurMF) {    // Setup a separate basic-block for the arguments and constants    MachineBasicBlock *EntryBB = MF->CreateMachineBasicBlock();    MF->push_back(EntryBB); -  EntryBuilder.setMBB(*EntryBB); +  EntryBuilder->setMBB(*EntryBB);    // Create all blocks, in IR order, to preserve the layout.    for (const BasicBlock &BB: F) { @@ -1753,7 +1784,7 @@ bool IRTranslator::runOnMachineFunction(MachineFunction &CurMF) {      }    } -  if (!CLI->lowerFormalArguments(EntryBuilder, F, VRegArgs)) { +  if (!CLI->lowerFormalArguments(*EntryBuilder.get(), F, VRegArgs)) {      OptimizationRemarkMissed R("gisel-irtranslator", "GISelFailure",                                 F.getSubprogram(), &F.getEntryBlock());      R << "unable to lower arguments: " << ore::NV("Prototype", F.getType()); @@ -1770,22 +1801,27 @@ bool IRTranslator::runOnMachineFunction(MachineFunction &CurMF) {        assert(VRegs.empty() && "VRegs already populated?");        VRegs.push_back(VArg);      } else { -      unpackRegs(*ArgIt, VArg, EntryBuilder); +      unpackRegs(*ArgIt, VArg, *EntryBuilder.get());      }      ArgIt++;    }    // Need to visit defs before uses when translating instructions. +  GISelObserverWrapper WrapperObserver; +  if (EnableCSE && CSEInfo) +    WrapperObserver.addObserver(CSEInfo);    {      ReversePostOrderTraversal<const Function *> RPOT(&F);  #ifndef NDEBUG -    DILocationVerifier Verifier(*MF); +    DILocationVerifier Verifier; +    WrapperObserver.addObserver(&Verifier);  #endif // ifndef NDEBUG +    RAIIDelegateInstaller DelInstall(*MF, &WrapperObserver);      for (const BasicBlock *BB : RPOT) {        MachineBasicBlock &MBB = getMBB(*BB);        // Set the insertion point of all the following translations to        // the end of this basic block. -      CurBuilder.setMBB(MBB); +      CurBuilder->setMBB(MBB);        for (const Instruction &Inst : *BB) {  #ifndef NDEBUG @@ -1810,6 +1846,9 @@ bool IRTranslator::runOnMachineFunction(MachineFunction &CurMF) {          return false;        }      } +#ifndef NDEBUG +    WrapperObserver.removeObserver(&Verifier); +#endif    }    finishPendingPhis(); diff --git a/llvm/lib/CodeGen/GlobalISel/Legalizer.cpp b/llvm/lib/CodeGen/GlobalISel/Legalizer.cpp index 8f8280a21da..84131e59948 100644 --- a/llvm/lib/CodeGen/GlobalISel/Legalizer.cpp +++ b/llvm/lib/CodeGen/GlobalISel/Legalizer.cpp @@ -16,6 +16,8 @@  #include "llvm/CodeGen/GlobalISel/Legalizer.h"  #include "llvm/ADT/PostOrderIterator.h"  #include "llvm/ADT/SetVector.h" +#include "llvm/CodeGen/GlobalISel/CSEInfo.h" +#include "llvm/CodeGen/GlobalISel/CSEMIRBuilder.h"  #include "llvm/CodeGen/GlobalISel/GISelChangeObserver.h"  #include "llvm/CodeGen/GlobalISel/GISelWorkList.h"  #include "llvm/CodeGen/GlobalISel/LegalizationArtifactCombiner.h" @@ -33,11 +35,17 @@  using namespace llvm; +static cl::opt<bool> +    EnableCSEInLegalizer("enable-cse-in-legalizer", +                         cl::desc("Should enable CSE in Legalizer"), +                         cl::Optional, cl::init(false)); +  char Legalizer::ID = 0;  INITIALIZE_PASS_BEGIN(Legalizer, DEBUG_TYPE,                        "Legalize the Machine IR a function's Machine IR", false,                        false)  INITIALIZE_PASS_DEPENDENCY(TargetPassConfig) +INITIALIZE_PASS_DEPENDENCY(GISelCSEAnalysisWrapperPass)  INITIALIZE_PASS_END(Legalizer, DEBUG_TYPE,                      "Legalize the Machine IR a function's Machine IR", false,                      false) @@ -48,6 +56,8 @@ Legalizer::Legalizer() : MachineFunctionPass(ID) {  void Legalizer::getAnalysisUsage(AnalysisUsage &AU) const {    AU.addRequired<TargetPassConfig>(); +  AU.addRequired<GISelCSEAnalysisWrapperPass>(); +  AU.addPreserved<GISelCSEAnalysisWrapperPass>();    getSelectionDAGFallbackAnalysisUsage(AU);    MachineFunctionPass::getAnalysisUsage(AU);  } @@ -82,7 +92,7 @@ public:    LegalizerWorkListManager(InstListTy &Insts, ArtifactListTy &Arts)        : InstList(Insts), ArtifactList(Arts) {} -  void createdInstr(const MachineInstr &MI) override { +  void createdInstr(MachineInstr &MI) override {      // Only legalize pre-isel generic instructions.      // Legalization process could generate Target specific pseudo      // instructions with generic types. Don't record them @@ -95,17 +105,17 @@ public:      LLVM_DEBUG(dbgs() << ".. .. New MI: " << MI);    } -  void erasingInstr(const MachineInstr &MI) override { +  void erasingInstr(MachineInstr &MI) override {      LLVM_DEBUG(dbgs() << ".. .. Erasing: " << MI);      InstList.remove(&MI);      ArtifactList.remove(&MI);    } -  void changingInstr(const MachineInstr &MI) override { +  void changingInstr(MachineInstr &MI) override {      LLVM_DEBUG(dbgs() << ".. .. Changing MI: " << MI);    } -  void changedInstr(const MachineInstr &MI) override { +  void changedInstr(MachineInstr &MI) override {      // When insts change, we want to revisit them to legalize them again.      // We'll consider them the same as created.      LLVM_DEBUG(dbgs() << ".. .. Changed MI: " << MI); @@ -122,14 +132,16 @@ bool Legalizer::runOnMachineFunction(MachineFunction &MF) {    LLVM_DEBUG(dbgs() << "Legalize Machine IR for: " << MF.getName() << '\n');    init(MF);    const TargetPassConfig &TPC = getAnalysis<TargetPassConfig>(); +  GISelCSEAnalysisWrapper &Wrapper = +      getAnalysis<GISelCSEAnalysisWrapperPass>().getCSEWrapper();    MachineOptimizationRemarkEmitter MORE(MF, /*MBFI=*/nullptr);    const size_t NumBlocks = MF.size();    MachineRegisterInfo &MRI = MF.getRegInfo();    // Populate Insts -  InstListTy InstList(&MF); -  ArtifactListTy ArtifactList(&MF); +  InstListTy InstList; +  ArtifactListTy ArtifactList;    ReversePostOrderTraversal<MachineFunction *> RPOT(&MF);    // Perform legalization bottom up so we can DCE as we legalize.    // Traverse BB in RPOT and within each basic block, add insts top down, @@ -148,12 +160,34 @@ bool Legalizer::runOnMachineFunction(MachineFunction &MF) {          InstList.insert(&MI);      }    } +  std::unique_ptr<MachineIRBuilder> MIRBuilder; +  GISelCSEInfo *CSEInfo = nullptr; +  bool IsO0 = TPC.getOptLevel() == CodeGenOpt::Level::None; +  // Disable CSE for O0. +  bool EnableCSE = !IsO0 && EnableCSEInLegalizer; +  if (EnableCSE) { +    MIRBuilder = make_unique<CSEMIRBuilder>(); +    std::unique_ptr<CSEConfig> Config = make_unique<CSEConfig>(); +    CSEInfo = &Wrapper.get(std::move(Config)); +    MIRBuilder->setCSEInfo(CSEInfo); +  } else +    MIRBuilder = make_unique<MachineIRBuilder>(); +  // This observer keeps the worklist updated.    LegalizerWorkListManager WorkListObserver(InstList, ArtifactList); -  LegalizerHelper Helper(MF, WorkListObserver); +  // We want both WorkListObserver as well as CSEInfo to observe all changes. +  // Use the wrapper observer. +  GISelObserverWrapper WrapperObserver(&WorkListObserver); +  if (EnableCSE && CSEInfo) +    WrapperObserver.addObserver(CSEInfo); +  // Now install the observer as the delegate to MF. +  // This will keep all the observers notified about new insertions/deletions. +  RAIIDelegateInstaller DelInstall(MF, &WrapperObserver); +  LegalizerHelper Helper(MF, WrapperObserver, *MIRBuilder.get());    const LegalizerInfo &LInfo(Helper.getLegalizerInfo()); -  LegalizationArtifactCombiner ArtCombiner(Helper.MIRBuilder, MF.getRegInfo(), LInfo); -  auto RemoveDeadInstFromLists = [&WorkListObserver](MachineInstr *DeadMI) { -    WorkListObserver.erasingInstr(*DeadMI); +  LegalizationArtifactCombiner ArtCombiner(*MIRBuilder.get(), MF.getRegInfo(), +                                           LInfo); +  auto RemoveDeadInstFromLists = [&WrapperObserver](MachineInstr *DeadMI) { +    WrapperObserver.erasingInstr(*DeadMI);    };    bool Changed = false;    do { diff --git a/llvm/lib/CodeGen/GlobalISel/LegalizerHelper.cpp b/llvm/lib/CodeGen/GlobalISel/LegalizerHelper.cpp index 34b466a41d2..b3fc94cdec6 100644 --- a/llvm/lib/CodeGen/GlobalISel/LegalizerHelper.cpp +++ b/llvm/lib/CodeGen/GlobalISel/LegalizerHelper.cpp @@ -31,16 +31,18 @@ using namespace llvm;  using namespace LegalizeActions;  LegalizerHelper::LegalizerHelper(MachineFunction &MF, -                                 GISelChangeObserver &Observer) -    : MRI(MF.getRegInfo()), LI(*MF.getSubtarget().getLegalizerInfo()), -      Observer(Observer) { +                                 GISelChangeObserver &Observer, +                                 MachineIRBuilder &Builder) +    : MIRBuilder(Builder), MRI(MF.getRegInfo()), +      LI(*MF.getSubtarget().getLegalizerInfo()), Observer(Observer) {    MIRBuilder.setMF(MF);    MIRBuilder.setChangeObserver(Observer);  }  LegalizerHelper::LegalizerHelper(MachineFunction &MF, const LegalizerInfo &LI, -                                 GISelChangeObserver &Observer) -    : MRI(MF.getRegInfo()), LI(LI), Observer(Observer) { +                                 GISelChangeObserver &Observer, +                                 MachineIRBuilder &B) +    : MIRBuilder(B), MRI(MF.getRegInfo()), LI(LI), Observer(Observer) {    MIRBuilder.setMF(MF);    MIRBuilder.setChangeObserver(Observer);  } diff --git a/llvm/lib/CodeGen/GlobalISel/MachineIRBuilder.cpp b/llvm/lib/CodeGen/GlobalISel/MachineIRBuilder.cpp index c1109e61177..1f561106199 100644 --- a/llvm/lib/CodeGen/GlobalISel/MachineIRBuilder.cpp +++ b/llvm/lib/CodeGen/GlobalISel/MachineIRBuilder.cpp @@ -46,6 +46,8 @@ void MachineIRBuilder::setInstr(MachineInstr &MI) {    State.II = MI.getIterator();  } +void MachineIRBuilder::setCSEInfo(GISelCSEInfo *Info) { State.CSEInfo = Info; } +  void MachineIRBuilder::setInsertPt(MachineBasicBlock &MBB,                                     MachineBasicBlock::iterator II) {    assert(MBB.getParent() == &getMF() && diff --git a/llvm/lib/CodeGen/GlobalISel/Utils.cpp b/llvm/lib/CodeGen/GlobalISel/Utils.cpp index 4d3a3753559..59cbf93e7cd 100644 --- a/llvm/lib/CodeGen/GlobalISel/Utils.cpp +++ b/llvm/lib/CodeGen/GlobalISel/Utils.cpp @@ -235,6 +235,57 @@ APFloat llvm::getAPFloatFromSize(double Val, unsigned Size) {    return APF;  } +Optional<APInt> llvm::ConstantFoldBinOp(unsigned Opcode, const unsigned Op1, +                                        const unsigned Op2, +                                        const MachineRegisterInfo &MRI) { +  auto MaybeOp1Cst = getConstantVRegVal(Op1, MRI); +  auto MaybeOp2Cst = getConstantVRegVal(Op2, MRI); +  if (MaybeOp1Cst && MaybeOp2Cst) { +    LLT Ty = MRI.getType(Op1); +    APInt C1(Ty.getSizeInBits(), *MaybeOp1Cst, true); +    APInt C2(Ty.getSizeInBits(), *MaybeOp2Cst, true); +    switch (Opcode) { +    default: +      break; +    case TargetOpcode::G_ADD: +      return C1 + C2; +    case TargetOpcode::G_AND: +      return C1 & C2; +    case TargetOpcode::G_ASHR: +      return C1.ashr(C2); +    case TargetOpcode::G_LSHR: +      return C1.lshr(C2); +    case TargetOpcode::G_MUL: +      return C1 * C2; +    case TargetOpcode::G_OR: +      return C1 | C2; +    case TargetOpcode::G_SHL: +      return C1 << C2; +    case TargetOpcode::G_SUB: +      return C1 - C2; +    case TargetOpcode::G_XOR: +      return C1 ^ C2; +    case TargetOpcode::G_UDIV: +      if (!C2.getBoolValue()) +        break; +      return C1.udiv(C2); +    case TargetOpcode::G_SDIV: +      if (!C2.getBoolValue()) +        break; +      return C1.sdiv(C2); +    case TargetOpcode::G_UREM: +      if (!C2.getBoolValue()) +        break; +      return C1.urem(C2); +    case TargetOpcode::G_SREM: +      if (!C2.getBoolValue()) +        break; +      return C1.srem(C2); +    } +  } +  return None; +} +  void llvm::getSelectionDAGFallbackAnalysisUsage(AnalysisUsage &AU) {    AU.addPreserved<StackProtector>();  } diff --git a/llvm/lib/CodeGen/MachineFunction.cpp b/llvm/lib/CodeGen/MachineFunction.cpp index 3ded00b70fd..3495319670a 100644 --- a/llvm/lib/CodeGen/MachineFunction.cpp +++ b/llvm/lib/CodeGen/MachineFunction.cpp @@ -139,12 +139,12 @@ MachineFunction::MachineFunction(const Function &F,    init();  } -void MachineFunction::handleInsertion(const MachineInstr &MI) { +void MachineFunction::handleInsertion(MachineInstr &MI) {    if (TheDelegate)      TheDelegate->MF_HandleInsertion(MI);  } -void MachineFunction::handleRemoval(const MachineInstr &MI) { +void MachineFunction::handleRemoval(MachineInstr &MI) {    if (TheDelegate)      TheDelegate->MF_HandleRemoval(MI);  } diff --git a/llvm/lib/Target/AArch64/AArch64PreLegalizerCombiner.cpp b/llvm/lib/Target/AArch64/AArch64PreLegalizerCombiner.cpp index 5022b6221ab..3da9306e646 100644 --- a/llvm/lib/Target/AArch64/AArch64PreLegalizerCombiner.cpp +++ b/llvm/lib/Target/AArch64/AArch64PreLegalizerCombiner.cpp @@ -88,7 +88,7 @@ bool AArch64PreLegalizerCombiner::runOnMachineFunction(MachineFunction &MF) {    auto *TPC = &getAnalysis<TargetPassConfig>();    AArch64PreLegalizerCombinerInfo PCInfo;    Combiner C(PCInfo, TPC); -  return C.combineMachineInstrs(MF); +  return C.combineMachineInstrs(MF, /*CSEInfo*/ nullptr);  }  char AArch64PreLegalizerCombiner::ID = 0; diff --git a/llvm/lib/Target/Mips/MipsPreLegalizerCombiner.cpp b/llvm/lib/Target/Mips/MipsPreLegalizerCombiner.cpp index c355a0e86d2..1cff1c8396e 100644 --- a/llvm/lib/Target/Mips/MipsPreLegalizerCombiner.cpp +++ b/llvm/lib/Target/Mips/MipsPreLegalizerCombiner.cpp @@ -73,7 +73,7 @@ bool MipsPreLegalizerCombiner::runOnMachineFunction(MachineFunction &MF) {    auto *TPC = &getAnalysis<TargetPassConfig>();    MipsPreLegalizerCombinerInfo PCInfo;    Combiner C(PCInfo, TPC); -  return C.combineMachineInstrs(MF); +  return C.combineMachineInstrs(MF, nullptr);  }  char MipsPreLegalizerCombiner::ID = 0; | 

