Path: blob/main/contrib/llvm-project/llvm/lib/Target/SPIRV/SPIRVPreLegalizerCombiner.cpp
213799 views
1//===-- SPIRVPreLegalizerCombiner.cpp - combine legalization ----*- C++ -*-===//2//3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.4// See https://llvm.org/LICENSE.txt for license information.5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception6//7//===----------------------------------------------------------------------===//8//9// This pass does combining of machine instructions at the generic MI level,10// before the legalizer.11//12//===----------------------------------------------------------------------===//1314#include "SPIRV.h"15#include "SPIRVTargetMachine.h"16#include "llvm/CodeGen/GlobalISel/CSEInfo.h"17#include "llvm/CodeGen/GlobalISel/Combiner.h"18#include "llvm/CodeGen/GlobalISel/CombinerHelper.h"19#include "llvm/CodeGen/GlobalISel/CombinerInfo.h"20#include "llvm/CodeGen/GlobalISel/GIMatchTableExecutorImpl.h"21#include "llvm/CodeGen/GlobalISel/GISelChangeObserver.h"22#include "llvm/CodeGen/GlobalISel/GISelValueTracking.h"23#include "llvm/CodeGen/GlobalISel/GenericMachineInstrs.h"24#include "llvm/CodeGen/GlobalISel/MIPatternMatch.h"25#include "llvm/CodeGen/GlobalISel/MachineIRBuilder.h"26#include "llvm/CodeGen/GlobalISel/Utils.h"27#include "llvm/CodeGen/MachineDominators.h"28#include "llvm/CodeGen/MachineFunctionPass.h"29#include "llvm/CodeGen/MachineRegisterInfo.h"30#include "llvm/CodeGen/TargetOpcodes.h"31#include "llvm/CodeGen/TargetPassConfig.h"32#include "llvm/IR/IntrinsicsSPIRV.h"3334#define GET_GICOMBINER_DEPS35#include "SPIRVGenPreLegalizeGICombiner.inc"36#undef GET_GICOMBINER_DEPS3738#define DEBUG_TYPE "spirv-prelegalizer-combiner"3940using namespace llvm;41using namespace MIPatternMatch;4243namespace {4445#define GET_GICOMBINER_TYPES46#include "SPIRVGenPreLegalizeGICombiner.inc"47#undef GET_GICOMBINER_TYPES4849/// This match is part of a combine that50/// rewrites length(X - Y) to distance(X, Y)51/// (f32 (g_intrinsic length52/// (g_fsub (vXf32 X) (vXf32 Y))))53/// ->54/// (f32 (g_intrinsic distance55/// (vXf32 X) (vXf32 Y)))56///57bool matchLengthToDistance(MachineInstr &MI, MachineRegisterInfo &MRI) {58if (MI.getOpcode() != TargetOpcode::G_INTRINSIC ||59cast<GIntrinsic>(MI).getIntrinsicID() != Intrinsic::spv_length)60return false;6162// First operand of MI is `G_INTRINSIC` so start at operand 2.63Register SubReg = MI.getOperand(2).getReg();64MachineInstr *SubInstr = MRI.getVRegDef(SubReg);65if (!SubInstr || SubInstr->getOpcode() != TargetOpcode::G_FSUB)66return false;6768return true;69}70void applySPIRVDistance(MachineInstr &MI, MachineRegisterInfo &MRI,71MachineIRBuilder &B) {7273// Extract the operands for X and Y from the match criteria.74Register SubDestReg = MI.getOperand(2).getReg();75MachineInstr *SubInstr = MRI.getVRegDef(SubDestReg);76Register SubOperand1 = SubInstr->getOperand(1).getReg();77Register SubOperand2 = SubInstr->getOperand(2).getReg();7879// Remove the original `spv_length` instruction.8081Register ResultReg = MI.getOperand(0).getReg();82DebugLoc DL = MI.getDebugLoc();83MachineBasicBlock &MBB = *MI.getParent();84MachineBasicBlock::iterator InsertPt = MI.getIterator();8586// Build the `spv_distance` intrinsic.87MachineInstrBuilder NewInstr =88BuildMI(MBB, InsertPt, DL, B.getTII().get(TargetOpcode::G_INTRINSIC));89NewInstr90.addDef(ResultReg) // Result register91.addIntrinsicID(Intrinsic::spv_distance) // Intrinsic ID92.addUse(SubOperand1) // Operand X93.addUse(SubOperand2); // Operand Y9495SPIRVGlobalRegistry *GR =96MI.getMF()->getSubtarget<SPIRVSubtarget>().getSPIRVGlobalRegistry();97auto RemoveAllUses = [&](Register Reg) {98SmallVector<MachineInstr *, 4> UsesToErase(99llvm::make_pointer_range(MRI.use_instructions(Reg)));100101// calling eraseFromParent to early invalidates the iterator.102for (auto *MIToErase : UsesToErase) {103GR->invalidateMachineInstr(MIToErase);104MIToErase->eraseFromParent();105}106};107RemoveAllUses(SubDestReg); // remove all uses of FSUB Result108GR->invalidateMachineInstr(SubInstr);109SubInstr->eraseFromParent(); // remove FSUB instruction110}111112class SPIRVPreLegalizerCombinerImpl : public Combiner {113protected:114const CombinerHelper Helper;115const SPIRVPreLegalizerCombinerImplRuleConfig &RuleConfig;116const SPIRVSubtarget &STI;117118public:119SPIRVPreLegalizerCombinerImpl(120MachineFunction &MF, CombinerInfo &CInfo, const TargetPassConfig *TPC,121GISelValueTracking &VT, GISelCSEInfo *CSEInfo,122const SPIRVPreLegalizerCombinerImplRuleConfig &RuleConfig,123const SPIRVSubtarget &STI, MachineDominatorTree *MDT,124const LegalizerInfo *LI);125126static const char *getName() { return "SPIRVPreLegalizerCombiner"; }127128bool tryCombineAll(MachineInstr &I) const override;129130bool tryCombineAllImpl(MachineInstr &I) const;131132private:133#define GET_GICOMBINER_CLASS_MEMBERS134#include "SPIRVGenPreLegalizeGICombiner.inc"135#undef GET_GICOMBINER_CLASS_MEMBERS136};137138#define GET_GICOMBINER_IMPL139#include "SPIRVGenPreLegalizeGICombiner.inc"140#undef GET_GICOMBINER_IMPL141142SPIRVPreLegalizerCombinerImpl::SPIRVPreLegalizerCombinerImpl(143MachineFunction &MF, CombinerInfo &CInfo, const TargetPassConfig *TPC,144GISelValueTracking &VT, GISelCSEInfo *CSEInfo,145const SPIRVPreLegalizerCombinerImplRuleConfig &RuleConfig,146const SPIRVSubtarget &STI, MachineDominatorTree *MDT,147const LegalizerInfo *LI)148: Combiner(MF, CInfo, TPC, &VT, CSEInfo),149Helper(Observer, B, /*IsPreLegalize*/ true, &VT, MDT, LI),150RuleConfig(RuleConfig), STI(STI),151#define GET_GICOMBINER_CONSTRUCTOR_INITS152#include "SPIRVGenPreLegalizeGICombiner.inc"153#undef GET_GICOMBINER_CONSTRUCTOR_INITS154{155}156157bool SPIRVPreLegalizerCombinerImpl::tryCombineAll(MachineInstr &MI) const {158return tryCombineAllImpl(MI);159}160161// Pass boilerplate162// ================163164class SPIRVPreLegalizerCombiner : public MachineFunctionPass {165public:166static char ID;167168SPIRVPreLegalizerCombiner();169170StringRef getPassName() const override { return "SPIRVPreLegalizerCombiner"; }171172bool runOnMachineFunction(MachineFunction &MF) override;173174void getAnalysisUsage(AnalysisUsage &AU) const override;175176private:177SPIRVPreLegalizerCombinerImplRuleConfig RuleConfig;178};179180} // end anonymous namespace181182void SPIRVPreLegalizerCombiner::getAnalysisUsage(AnalysisUsage &AU) const {183AU.addRequired<TargetPassConfig>();184AU.setPreservesCFG();185getSelectionDAGFallbackAnalysisUsage(AU);186AU.addRequired<GISelValueTrackingAnalysisLegacy>();187AU.addPreserved<GISelValueTrackingAnalysisLegacy>();188AU.addRequired<MachineDominatorTreeWrapperPass>();189AU.addPreserved<MachineDominatorTreeWrapperPass>();190MachineFunctionPass::getAnalysisUsage(AU);191}192193SPIRVPreLegalizerCombiner::SPIRVPreLegalizerCombiner()194: MachineFunctionPass(ID) {195if (!RuleConfig.parseCommandLineOption())196report_fatal_error("Invalid rule identifier");197}198199bool SPIRVPreLegalizerCombiner::runOnMachineFunction(MachineFunction &MF) {200if (MF.getProperties().hasFailedISel())201return false;202auto &TPC = getAnalysis<TargetPassConfig>();203204const SPIRVSubtarget &ST = MF.getSubtarget<SPIRVSubtarget>();205const auto *LI = ST.getLegalizerInfo();206207const Function &F = MF.getFunction();208bool EnableOpt =209MF.getTarget().getOptLevel() != CodeGenOptLevel::None && !skipFunction(F);210GISelValueTracking *VT =211&getAnalysis<GISelValueTrackingAnalysisLegacy>().get(MF);212MachineDominatorTree *MDT =213&getAnalysis<MachineDominatorTreeWrapperPass>().getDomTree();214CombinerInfo CInfo(/*AllowIllegalOps*/ true, /*ShouldLegalizeIllegal*/ false,215/*LegalizerInfo*/ nullptr, EnableOpt, F.hasOptSize(),216F.hasMinSize());217// Disable fixed-point iteration to reduce compile-time218CInfo.MaxIterations = 1;219CInfo.ObserverLvl = CombinerInfo::ObserverLevel::SinglePass;220// This is the first Combiner, so the input IR might contain dead221// instructions.222CInfo.EnableFullDCE = false;223SPIRVPreLegalizerCombinerImpl Impl(MF, CInfo, &TPC, *VT, /*CSEInfo*/ nullptr,224RuleConfig, ST, MDT, LI);225return Impl.combineMachineInstrs();226}227228char SPIRVPreLegalizerCombiner::ID = 0;229INITIALIZE_PASS_BEGIN(SPIRVPreLegalizerCombiner, DEBUG_TYPE,230"Combine SPIRV machine instrs before legalization", false,231false)232INITIALIZE_PASS_DEPENDENCY(TargetPassConfig)233INITIALIZE_PASS_DEPENDENCY(GISelValueTrackingAnalysisLegacy)234INITIALIZE_PASS_END(SPIRVPreLegalizerCombiner, DEBUG_TYPE,235"Combine SPIRV machine instrs before legalization", false,236false)237238namespace llvm {239FunctionPass *createSPIRVPreLegalizerCombiner() {240return new SPIRVPreLegalizerCombiner();241}242} // end namespace llvm243244245