Index: include/llvm/CodeGen/GlobalISel/Combiner.h =================================================================== --- /dev/null +++ include/llvm/CodeGen/GlobalISel/Combiner.h @@ -0,0 +1,43 @@ +//== ----- llvm/CodeGen/GlobalISel/Combiner.h --------------------- == // +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +/// This contains common code to drive combines. Combiner Passes will need to +/// setup a CombinerInfo and call combineMachineFunction. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CODEGEN_GLOBALISEL_COMBINER_H +#define LLVM_CODEGEN_GLOBALISEL_COMBINER_H + +#include "llvm/CodeGen/GlobalISel/MachineIRBuilder.h" +#include "llvm/CodeGen/MachineFunctionPass.h" + +namespace llvm { +class MachineRegisterInfo; +class CombinerInfo; +class TargetPassConfig; +class MachineFunction; + +class Combiner { +public: + Combiner(CombinerInfo &CombinerInfo, const TargetPassConfig *TPC); + + bool combineMachineInstrs(MachineFunction &MF); + +protected: + CombinerInfo &CInfo; + + MachineRegisterInfo *MRI = nullptr; + const TargetPassConfig *TPC; + MachineIRBuilder Builder; +}; + +} // End namespace llvm. + +#endif // LLVM_CODEGEN_GLOBALISEL_GICOMBINER_H Index: include/llvm/CodeGen/GlobalISel/CombinerHelper.h =================================================================== --- /dev/null +++ include/llvm/CodeGen/GlobalISel/CombinerHelper.h @@ -0,0 +1,44 @@ +//== llvm/CodeGen/GlobalISel/CombinerHelper.h ---------------- -*- C++ -*-==// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +/// This contains common combine transformations that may be used in a combine +/// pass,or by the target elsewhere. +/// Targets can pick individual opcode transformations from the helper or use +/// tryCombine which invokes all transformations. All of the transformations return +/// true if the MachineInstruction changed and false otherwise. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CODEGEN_GLOBALISEL_COMBINER_HELPER_H +#define LLVM_CODEGEN_GLOBALISEL_COMBINER_HELPER_H + +namespace llvm { + +class MachineIRBuilder; +class MachineRegisterInfo; +class MachineInstr; + +class CombinerHelper { + MachineIRBuilder &Builder; + MachineRegisterInfo &MRI; + +public: + CombinerHelper(MachineIRBuilder &B); + + /// If \p MI is COPY, try to combine it. + /// Returns true if MI changed. + bool tryCombineCopy(MachineInstr &MI); + + /// Try to transform \p MI by using all of the above + /// combine functions. Returns true if changed. + bool tryCombine(MachineInstr &MI); +}; +} // namespace llvm + +#endif Index: include/llvm/CodeGen/GlobalISel/CombinerInfo.h =================================================================== --- /dev/null +++ include/llvm/CodeGen/GlobalISel/CombinerInfo.h @@ -0,0 +1,47 @@ +//===- llvm/CodeGen/GlobalISel/CombinerInfo.h ------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +/// Interface for Targets to specify which operations are combined how and when. +/// // +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CODEGEN_GLOBALISEL_COMBINER_INFO_H +#define LLVM_CODEGEN_GLOBALISEL_COMBINER_INFO_H + +namespace llvm { + +class LegalizerInfo; +class MachineInstr; +class MachineIRBuilder; +class MachineRegisterInfo; +// Contains information relevant to enabling/disabling various combines for a +// pass. +class CombinerInfo { +public: + CombinerInfo(bool AllowIllegalOps, bool ShouldLegalizeIllegal, + LegalizerInfo *LInfo) + : IllegalOpsAllowed(AllowIllegalOps), + LegalizeIllegalOps(ShouldLegalizeIllegal), LInfo(LInfo) { + assert(((AllowIllegalOps || !LegalizeIllegalOps) || LInfo) && + "Expecting legalizerInfo when illegalops not allowed"); + } + virtual ~CombinerInfo() = default; + /// If \p IllegalOpsAllowed is false, the CombinerHelper will make use of + /// the legalizerInfo to check for legality before each transformation. + bool IllegalOpsAllowed; // TODO: Make use of this. + + /// If \p LegalizeIllegalOps is true, the Combiner will also legalize the + /// illegal ops that are created. + bool LegalizeIllegalOps; // TODO: Make use of this. + const LegalizerInfo *LInfo; + virtual bool combine(MachineInstr &MI, MachineIRBuilder &B) const = 0; +}; +} // namespace llvm + +#endif Index: include/llvm/CodeGen/GlobalISel/PreLegalizeCombiner.h =================================================================== --- /dev/null +++ include/llvm/CodeGen/GlobalISel/PreLegalizeCombiner.h @@ -0,0 +1,50 @@ +//== llvm/include/CodeGen/GlobalISel/PreLegalizeCombiner.h -----------------// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This pass runs before legalization. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CODEGEN_GLOBALISEL_PRELEGALIZE_GICOMBINER_H +#define LLVM_CODEGEN_GLOBALISEL_PRELEGALIZE_GICOMBINER_H + +#include "llvm/CodeGen/GlobalISel/Combiner.h" +#include "llvm/CodeGen/GlobalISel/CombinerInfo.h" +#include "llvm/CodeGen/GlobalISel/MachineIRBuilder.h" +#include "llvm/CodeGen/MachineFunctionPass.h" +#include "llvm/CodeGen/MachineOptimizationRemarkEmitter.h" +#include "llvm/CodeGen/TargetPassConfig.h" + +namespace llvm { +class MachineRegisterInfo; + +class PreLegalizeCombinerInfo : public CombinerInfo { +public: + PreLegalizeCombinerInfo() + : CombinerInfo(/*AllowIllegalOps*/ true, /*ShouldLegalizeIllegal*/ false, + /*LegalizerInfo*/ nullptr) {} + virtual bool combine(MachineInstr &MI, MachineIRBuilder &B) const override; +}; + +class PreLegalizeCombiner : public MachineFunctionPass { +public: + static char ID; + + PreLegalizeCombiner() : MachineFunctionPass(ID) {} + + StringRef getPassName() const override { return "PreLegalizeCombiner"; } + + bool runOnMachineFunction(MachineFunction &MF) override; + + void getAnalysisUsage(AnalysisUsage &AU) const override; +}; + +} // End namespace llvm. + +#endif // LLVM_CODEGEN_GLOBALISEL_PRELEGALIZE_GICOMBINER_H Index: include/llvm/InitializePasses.h =================================================================== --- include/llvm/InitializePasses.h +++ include/llvm/InitializePasses.h @@ -151,6 +151,7 @@ void initializeGVNHoistLegacyPassPass(PassRegistry&); void initializeGVNLegacyPassPass(PassRegistry&); void initializeGVNSinkLegacyPassPass(PassRegistry&); +void initializePreLegalizeCombinerPass(PassRegistry &); void initializeGlobalDCELegacyPassPass(PassRegistry&); void initializeGlobalMergePass(PassRegistry&); void initializeGlobalOptLegacyPassPass(PassRegistry&); Index: lib/CodeGen/GlobalISel/CMakeLists.txt =================================================================== --- lib/CodeGen/GlobalISel/CMakeLists.txt +++ lib/CodeGen/GlobalISel/CMakeLists.txt @@ -1,6 +1,9 @@ add_llvm_library(LLVMGlobalISel CallLowering.cpp GlobalISel.cpp + Combiner.cpp + CombinerHelper.cpp + PreLegalizeCombiner.cpp IRTranslator.cpp InstructionSelect.cpp InstructionSelector.cpp Index: lib/CodeGen/GlobalISel/Combiner.cpp =================================================================== --- /dev/null +++ lib/CodeGen/GlobalISel/Combiner.cpp @@ -0,0 +1,81 @@ +//===-- lib/CodeGen/GlobalISel/GICombiner.cpp -----------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file constains common code to combine machine functions at generic +// level. // +//===----------------------------------------------------------------------===// + +#include "llvm/CodeGen/GlobalISel/Combiner.h" +#include "llvm/CodeGen/GlobalISel/CombinerInfo.h" +#include "llvm/CodeGen/GlobalISel/MachineIRBuilder.h" +#include "llvm/CodeGen/MachineOptimizationRemarkEmitter.h" +#include "llvm/CodeGen/GlobalISel/GISelWorkList.h" +#include "llvm/ADT/PostOrderIterator.h" +#include "llvm/CodeGen/GlobalISel/Utils.h" +#include "llvm/CodeGen/MachineRegisterInfo.h" +#include "llvm/Support/Debug.h" + +#define DEBUG_TYPE "gi-combiner" + +using namespace llvm; + +Combiner::Combiner(CombinerInfo &Info, const TargetPassConfig *TPC) + : CInfo(Info), TPC(TPC) { + (void)this->TPC; // FIXME: Remove when used. +} + +bool Combiner::combineMachineInstrs(MachineFunction &MF) { + // 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; + + MRI = &MF.getRegInfo(); + Builder.setMF(MF); + + DEBUG(dbgs() << "Generic MI Combiner for: " << MF.getName() << '\n'); + + MachineOptimizationRemarkEmitter MORE(MF, /*MBFI=*/nullptr); + + bool MFChanged = false; + bool Changed; + + 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; + for (MachineBasicBlock *MBB : post_order(&MF)) { + if (MBB->empty()) + continue; + for (auto MII = MBB->rbegin(), MIE = MBB->rend(); MII != MIE;) { + MachineInstr *CurMI = &*MII; + ++MII; + // Erase dead insts before even adding to the list. + if (isTriviallyDead(*CurMI, *MRI)) { + DEBUG(dbgs() << *CurMI << "Is dead; erasing.\n"); + CurMI->eraseFromParentAndMarkDBGValuesForRemoval(); + continue; + } + WorkList.insert(CurMI); + } + } + // Main Loop. Process the instructions here. + while (!WorkList.empty()) { + MachineInstr *CurrInst = WorkList.pop_back_val(); + DEBUG(dbgs() << "Try combining " << *CurrInst << "\n";); + Changed |= CInfo.combine(*CurrInst, Builder); + } + MFChanged |= Changed; + } while (Changed); + + return MFChanged; +} Index: lib/CodeGen/GlobalISel/CombinerHelper.cpp =================================================================== --- /dev/null +++ lib/CodeGen/GlobalISel/CombinerHelper.cpp @@ -0,0 +1,42 @@ +//== ---lib/CodeGen/GlobalISel/GICombinerHelper.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/CombinerHelper.h" +#include "llvm/CodeGen/GlobalISel/MachineIRBuilder.h" +#include "llvm/CodeGen/GlobalISel/Utils.h" +#include "llvm/CodeGen/MachineInstr.h" +#include "llvm/CodeGen/MachineRegisterInfo.h" + +#define DEBUG_TYPE "gi-combine" + +using namespace llvm; + +CombinerHelper::CombinerHelper(MachineIRBuilder &B) : + Builder(B), MRI(Builder.getMF().getRegInfo()) {} + +bool CombinerHelper::tryCombineCopy(MachineInstr &MI) { + if (MI.getOpcode() != TargetOpcode::COPY) + return false; + unsigned DstReg = MI.getOperand(0).getReg(); + unsigned SrcReg = MI.getOperand(1).getReg(); + LLT DstTy = MRI.getType(DstReg); + LLT SrcTy = MRI.getType(SrcReg); + // Simple Copy Propagation. + // a(sx) = COPY b(sx) -> Replace all uses of a with b. + if (DstTy.isValid() && SrcTy.isValid() && DstTy == SrcTy) { + MI.eraseFromParent(); + MRI.replaceRegWith(DstReg, SrcReg); + return true; + } + return false; +} + +bool CombinerHelper::tryCombine(MachineInstr &MI) { + // Right now just do the above. + return tryCombineCopy(MI); +} Index: lib/CodeGen/GlobalISel/GlobalISel.cpp =================================================================== --- lib/CodeGen/GlobalISel/GlobalISel.cpp +++ lib/CodeGen/GlobalISel/GlobalISel.cpp @@ -19,6 +19,7 @@ void llvm::initializeGlobalISel(PassRegistry &Registry) { initializeIRTranslatorPass(Registry); initializeLegalizerPass(Registry); + initializePreLegalizeCombinerPass(Registry); initializeLocalizerPass(Registry); initializeRegBankSelectPass(Registry); initializeInstructionSelectPass(Registry); Index: lib/CodeGen/GlobalISel/PreLegalizeCombiner.cpp =================================================================== --- /dev/null +++ lib/CodeGen/GlobalISel/PreLegalizeCombiner.cpp @@ -0,0 +1,60 @@ +//=== lib/CodeGen/GlobalISel/PreLegalizeCombiner.cpp -------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This pass does combining of machine instructions at the generic MI level, +// before the legalizer. +// +//===----------------------------------------------------------------------===// + +#include "llvm/CodeGen/GlobalISel/PreLegalizeCombiner.h" +#include "llvm/CodeGen/GlobalISel/Combiner.h" +#include "llvm/CodeGen/GlobalISel/CombinerHelper.h" +#include "llvm/CodeGen/GlobalISel/Utils.h" +#include "llvm/CodeGen/MachineRegisterInfo.h" +#include "llvm/Support/Debug.h" + +#define DEBUG_TYPE "prelegalize-combiner" + +using namespace llvm; + +static cl::opt EnablePreLegalizeCombiner( + "enable-prelegalize-gi-combiner", cl::Hidden, + cl::desc("Enable the prelegalize machine instruction combiner"), + cl::init(true)); + +char PreLegalizeCombiner::ID = 0; +INITIALIZE_PASS_BEGIN(PreLegalizeCombiner, DEBUG_TYPE, + "Combine generic instructions before legalization", false, + false) +INITIALIZE_PASS_DEPENDENCY(TargetPassConfig) +INITIALIZE_PASS_END(PreLegalizeCombiner, DEBUG_TYPE, + "Combine generic instructions before legalization", false, + false) + +void PreLegalizeCombiner::getAnalysisUsage(AnalysisUsage &AU) const { + AU.addRequired(); + MachineFunctionPass::getAnalysisUsage(AU); +} + +bool PreLegalizeCombiner::runOnMachineFunction(MachineFunction &MF) { + if (!EnablePreLegalizeCombiner) { + DEBUG(dbgs() << "PreLegalizeCombiner is disabled\n"); + return false; + } + const auto *TPC = &getAnalysis(); + PreLegalizeCombinerInfo PCInfo; + Combiner Combiner(PCInfo, TPC); + return Combiner.combineMachineInstrs(MF); +} + +bool PreLegalizeCombinerInfo::combine(MachineInstr &MI, MachineIRBuilder &B) const { + CombinerHelper Helper(B); + // For now try all combines in the combiner helper. + return Helper.tryCombine(MI); +} Index: test/CodeGen/AArch64/GlobalISel/combine-copy.mir =================================================================== --- /dev/null +++ test/CodeGen/AArch64/GlobalISel/combine-copy.mir @@ -0,0 +1,27 @@ +# NOTE: Assertions have been autogenerated by utils/update_mir_test_checks.py +# RUN: llc -O0 -run-pass=prelegalize-combiner -global-isel %s -o - | FileCheck %s + +--- | + target datalayout = "e-m:o-i64:64-i128:128-n32:64-S128" + target triple = "aarch64--" + define void @test_copy_propagation() { + entry: + ret void + } +... + +--- +name: test_copy_propagation +body: | + bb.0.entry: + liveins: %x0, %x1, %x2, %x3 + + ; CHECK-LABEL: name: test_copy_propagation + ; CHECK: [[COPY:%[0-9]+]]:_(s64) = COPY %x0 + ; CHECK: %x0 = COPY [[COPY]](s64) + %0:_(s64) = COPY %x0 + %1:_(s64) = COPY %0 + %2:_(s64) = COPY %1 + %x0 = COPY %2 +... +