brintos

brintos / llvm-project-archived public Read only

0
0
Text · 14.2 KiB · 751ae0f Raw
407 lines · cpp
1//===-- SPIRVPostLegalizer.cpp - ammend info after legalization -*- C++ -*-===//2//3// which may appear after the legalizer pass4//5// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.6// See https://llvm.org/LICENSE.txt for license information.7// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception8//9//===----------------------------------------------------------------------===//10//11// The pass partially apply pre-legalization logic to new instructions inserted12// as a result of legalization:13// - assigns SPIR-V types to registers for new instructions.14//15//===----------------------------------------------------------------------===//16 17#include "SPIRV.h"18#include "SPIRVSubtarget.h"19#include "SPIRVUtils.h"20#include "llvm/IR/IntrinsicsSPIRV.h"21#include "llvm/Support/Debug.h"22#include <stack>23 24#define DEBUG_TYPE "spirv-postlegalizer"25 26using namespace llvm;27 28namespace {29class SPIRVPostLegalizer : public MachineFunctionPass {30public:31  static char ID;32  SPIRVPostLegalizer() : MachineFunctionPass(ID) {}33  bool runOnMachineFunction(MachineFunction &MF) override;34};35} // namespace36 37namespace llvm {38//  Defined in SPIRVPreLegalizer.cpp.39extern void insertAssignInstr(Register Reg, Type *Ty, SPIRVType *SpirvTy,40                              SPIRVGlobalRegistry *GR, MachineIRBuilder &MIB,41                              MachineRegisterInfo &MRI);42extern void processInstr(MachineInstr &MI, MachineIRBuilder &MIB,43                         MachineRegisterInfo &MRI, SPIRVGlobalRegistry *GR,44                         SPIRVType *KnownResType);45} // namespace llvm46 47static SPIRVType *deduceIntTypeFromResult(Register ResVReg,48                                          MachineIRBuilder &MIB,49                                          SPIRVGlobalRegistry *GR) {50  const LLT &Ty = MIB.getMRI()->getType(ResVReg);51  return GR->getOrCreateSPIRVIntegerType(Ty.getScalarSizeInBits(), MIB);52}53 54static bool deduceAndAssignTypeForGUnmerge(MachineInstr *I, MachineFunction &MF,55                                           SPIRVGlobalRegistry *GR) {56  MachineRegisterInfo &MRI = MF.getRegInfo();57  Register SrcReg = I->getOperand(I->getNumOperands() - 1).getReg();58  SPIRVType *ScalarType = nullptr;59  if (SPIRVType *DefType = GR->getSPIRVTypeForVReg(SrcReg)) {60    assert(DefType->getOpcode() == SPIRV::OpTypeVector);61    ScalarType = GR->getSPIRVTypeForVReg(DefType->getOperand(1).getReg());62  }63 64  if (!ScalarType) {65    // If we could not deduce the type from the source, try to deduce it from66    // the uses of the results.67    for (unsigned i = 0; i < I->getNumDefs() && !ScalarType; ++i) {68      for (const auto &Use :69           MRI.use_nodbg_instructions(I->getOperand(i).getReg())) {70        assert(Use.getOpcode() == TargetOpcode::G_BUILD_VECTOR &&71               "Expected use of G_UNMERGE_VALUES to be a G_BUILD_VECTOR");72        if (auto *VecType =73                GR->getSPIRVTypeForVReg(Use.getOperand(0).getReg())) {74          ScalarType = GR->getScalarOrVectorComponentType(VecType);75          break;76        }77      }78    }79  }80 81  if (!ScalarType)82    return false;83 84  for (unsigned i = 0; i < I->getNumDefs(); ++i) {85    Register DefReg = I->getOperand(i).getReg();86    if (GR->getSPIRVTypeForVReg(DefReg))87      continue;88 89    LLT DefLLT = MRI.getType(DefReg);90    SPIRVType *ResType =91        DefLLT.isVector()92            ? GR->getOrCreateSPIRVVectorType(93                  ScalarType, DefLLT.getNumElements(), *I,94                  *MF.getSubtarget<SPIRVSubtarget>().getInstrInfo())95            : ScalarType;96    setRegClassType(DefReg, ResType, GR, &MRI, MF);97  }98  return true;99}100 101static SPIRVType *deduceTypeFromSingleOperand(MachineInstr *I,102                                              MachineIRBuilder &MIB,103                                              SPIRVGlobalRegistry *GR,104                                              unsigned OpIdx) {105  Register OpReg = I->getOperand(OpIdx).getReg();106  if (SPIRVType *OpType = GR->getSPIRVTypeForVReg(OpReg)) {107    if (SPIRVType *CompType = GR->getScalarOrVectorComponentType(OpType)) {108      Register ResVReg = I->getOperand(0).getReg();109      const LLT &ResLLT = MIB.getMRI()->getType(ResVReg);110      if (ResLLT.isVector())111        return GR->getOrCreateSPIRVVectorType(CompType, ResLLT.getNumElements(),112                                              MIB, false);113      return CompType;114    }115  }116  return nullptr;117}118 119static SPIRVType *deduceTypeFromOperandRange(MachineInstr *I,120                                             MachineIRBuilder &MIB,121                                             SPIRVGlobalRegistry *GR,122                                             unsigned StartOp, unsigned EndOp) {123  SPIRVType *ResType = nullptr;124  for (unsigned i = StartOp; i < EndOp; ++i) {125    if (SPIRVType *Type = deduceTypeFromSingleOperand(I, MIB, GR, i)) {126#ifdef EXPENSIVE_CHECKS127      assert(!ResType || Type == ResType && "Conflicting type from operands.");128      ResType = Type;129#else130      return Type;131#endif132    }133  }134  return ResType;135}136 137static SPIRVType *deduceTypeForResultRegister(MachineInstr *Use,138                                              Register UseRegister,139                                              SPIRVGlobalRegistry *GR,140                                              MachineIRBuilder &MIB) {141  for (const MachineOperand &MO : Use->defs()) {142    if (!MO.isReg())143      continue;144    if (SPIRVType *OpType = GR->getSPIRVTypeForVReg(MO.getReg())) {145      if (SPIRVType *CompType = GR->getScalarOrVectorComponentType(OpType)) {146        const LLT &ResLLT = MIB.getMRI()->getType(UseRegister);147        if (ResLLT.isVector())148          return GR->getOrCreateSPIRVVectorType(149              CompType, ResLLT.getNumElements(), MIB, false);150        return CompType;151      }152    }153  }154  return nullptr;155}156 157static SPIRVType *deduceTypeFromUses(Register Reg, MachineFunction &MF,158                                     SPIRVGlobalRegistry *GR,159                                     MachineIRBuilder &MIB) {160  MachineRegisterInfo &MRI = MF.getRegInfo();161  for (MachineInstr &Use : MRI.use_nodbg_instructions(Reg)) {162    SPIRVType *ResType = nullptr;163    switch (Use.getOpcode()) {164    case TargetOpcode::G_BUILD_VECTOR:165    case TargetOpcode::G_EXTRACT_VECTOR_ELT:166    case TargetOpcode::G_UNMERGE_VALUES:167      LLVM_DEBUG(dbgs() << "Looking at use " << Use << "\n");168      ResType = deduceTypeForResultRegister(&Use, Reg, GR, MIB);169      break;170    }171    if (ResType)172      return ResType;173  }174  return nullptr;175}176 177static SPIRVType *deduceResultTypeFromOperands(MachineInstr *I,178                                               SPIRVGlobalRegistry *GR,179                                               MachineIRBuilder &MIB) {180  Register ResVReg = I->getOperand(0).getReg();181  switch (I->getOpcode()) {182  case TargetOpcode::G_CONSTANT:183  case TargetOpcode::G_ANYEXT:184    return deduceIntTypeFromResult(ResVReg, MIB, GR);185  case TargetOpcode::G_BUILD_VECTOR:186    return deduceTypeFromOperandRange(I, MIB, GR, 1, I->getNumOperands());187  case TargetOpcode::G_SHUFFLE_VECTOR:188    return deduceTypeFromOperandRange(I, MIB, GR, 1, 3);189  default:190    if (I->getNumDefs() == 1 && I->getNumOperands() > 1 &&191        I->getOperand(1).isReg())192      return deduceTypeFromSingleOperand(I, MIB, GR, 1);193    return nullptr;194  }195}196 197static bool deduceAndAssignSpirvType(MachineInstr *I, MachineFunction &MF,198                                     SPIRVGlobalRegistry *GR,199                                     MachineIRBuilder &MIB) {200  LLVM_DEBUG(dbgs() << "\nProcessing instruction: " << *I);201  MachineRegisterInfo &MRI = MF.getRegInfo();202  Register ResVReg = I->getOperand(0).getReg();203 204  // G_UNMERGE_VALUES is handled separately because it has multiple definitions,205  // unlike the other instructions which have a single result register. The main206  // deduction logic is designed for the single-definition case.207  if (I->getOpcode() == TargetOpcode::G_UNMERGE_VALUES)208    return deduceAndAssignTypeForGUnmerge(I, MF, GR);209 210  LLVM_DEBUG(dbgs() << "Inferring type from operands\n");211  SPIRVType *ResType = deduceResultTypeFromOperands(I, GR, MIB);212  if (!ResType) {213    LLVM_DEBUG(dbgs() << "Inferring type from uses\n");214    ResType = deduceTypeFromUses(ResVReg, MF, GR, MIB);215  }216 217  if (!ResType)218    return false;219 220  LLVM_DEBUG(dbgs() << "Assigned type to " << *I << ": " << *ResType);221  GR->assignSPIRVTypeToVReg(ResType, ResVReg, MF);222 223  if (!MRI.getRegClassOrNull(ResVReg)) {224    LLVM_DEBUG(dbgs() << "Updating the register class.\n");225    setRegClassType(ResVReg, ResType, GR, &MRI, *GR->CurMF, true);226  }227  return true;228}229 230static bool requiresSpirvType(MachineInstr &I, SPIRVGlobalRegistry *GR,231                              MachineRegisterInfo &MRI) {232  LLVM_DEBUG(dbgs() << "Checking if instruction requires a SPIR-V type: "233                    << I;);234  if (I.getNumDefs() == 0) {235    LLVM_DEBUG(dbgs() << "Instruction does not have a definition.\n");236    return false;237  }238 239  if (!I.isPreISelOpcode()) {240    LLVM_DEBUG(dbgs() << "Instruction is not a generic instruction.\n");241    return false;242  }243 244  Register ResultRegister = I.defs().begin()->getReg();245  if (GR->getSPIRVTypeForVReg(ResultRegister)) {246    LLVM_DEBUG(dbgs() << "Instruction already has a SPIR-V type.\n");247    if (!MRI.getRegClassOrNull(ResultRegister)) {248      LLVM_DEBUG(dbgs() << "Updating the register class.\n");249      setRegClassType(ResultRegister, GR->getSPIRVTypeForVReg(ResultRegister),250                      GR, &MRI, *GR->CurMF, true);251    }252    return false;253  }254 255  return true;256}257 258static void registerSpirvTypeForNewInstructions(MachineFunction &MF,259                                                SPIRVGlobalRegistry *GR) {260  MachineRegisterInfo &MRI = MF.getRegInfo();261  SmallVector<MachineInstr *, 8> Worklist;262  for (MachineBasicBlock &MBB : MF) {263    for (MachineInstr &I : MBB) {264      if (requiresSpirvType(I, GR, MRI)) {265        Worklist.push_back(&I);266      }267    }268  }269 270  if (Worklist.empty()) {271    LLVM_DEBUG(dbgs() << "Initial worklist is empty.\n");272    return;273  }274 275  LLVM_DEBUG(dbgs() << "Initial worklist:\n";276             for (auto *I : Worklist) { I->dump(); });277 278  bool Changed;279  do {280    Changed = false;281    SmallVector<MachineInstr *, 8> NextWorklist;282 283    for (MachineInstr *I : Worklist) {284      MachineIRBuilder MIB(*I);285      if (deduceAndAssignSpirvType(I, MF, GR, MIB)) {286        Changed = true;287      } else {288        NextWorklist.push_back(I);289      }290    }291    Worklist = std::move(NextWorklist);292    LLVM_DEBUG(dbgs() << "Worklist size: " << Worklist.size() << "\n");293  } while (Changed);294 295  if (Worklist.empty())296    return;297 298  for (auto *I : Worklist) {299    MachineIRBuilder MIB(*I);300    Register ResVReg = I->getOperand(0).getReg();301    const LLT &ResLLT = MRI.getType(ResVReg);302    SPIRVType *ResType = nullptr;303    if (ResLLT.isVector()) {304      SPIRVType *CompType = GR->getOrCreateSPIRVIntegerType(305          ResLLT.getElementType().getSizeInBits(), MIB);306      ResType = GR->getOrCreateSPIRVVectorType(307          CompType, ResLLT.getNumElements(), MIB, false);308    } else {309      ResType = GR->getOrCreateSPIRVIntegerType(ResLLT.getSizeInBits(), MIB);310    }311    LLVM_DEBUG(dbgs() << "Could not determine type for " << *I312                      << ", defaulting to " << *ResType << "\n");313    setRegClassType(ResVReg, ResType, GR, &MRI, MF, true);314  }315}316 317static void ensureAssignTypeForTypeFolding(MachineFunction &MF,318                                           SPIRVGlobalRegistry *GR) {319  LLVM_DEBUG(dbgs() << "Entering ensureAssignTypeForTypeFolding for function "320                    << MF.getName() << "\n");321  MachineRegisterInfo &MRI = MF.getRegInfo();322  for (MachineBasicBlock &MBB : MF) {323    for (MachineInstr &MI : MBB) {324      if (!isTypeFoldingSupported(MI.getOpcode()))325        continue;326      if (MI.getNumOperands() == 1 || !MI.getOperand(1).isReg())327        continue;328 329      LLVM_DEBUG(dbgs() << "Processing instruction: " << MI);330 331      // Check uses of MI to see if it already has an use in SPIRV::ASSIGN_TYPE332      bool HasAssignType = false;333      Register ResultRegister = MI.defs().begin()->getReg();334      // All uses of Result register335      for (MachineInstr &UseInstr :336           MRI.use_nodbg_instructions(ResultRegister)) {337        if (UseInstr.getOpcode() == SPIRV::ASSIGN_TYPE) {338          HasAssignType = true;339          LLVM_DEBUG(dbgs() << "  Instruction already has an ASSIGN_TYPE use: "340                            << UseInstr);341          break;342        }343      }344 345      if (!HasAssignType) {346        Register ResultRegister = MI.defs().begin()->getReg();347        SPIRVType *ResultType = GR->getSPIRVTypeForVReg(ResultRegister);348        LLVM_DEBUG(349            dbgs() << "  Adding ASSIGN_TYPE for ResultRegister: "350                   << printReg(ResultRegister, MRI.getTargetRegisterInfo())351                   << " with type: " << *ResultType);352        MachineIRBuilder MIB(MI);353        insertAssignInstr(ResultRegister, nullptr, ResultType, GR, MIB, MRI);354      }355    }356  }357}358 359// Do a preorder traversal of the CFG starting from the BB |Start|.360// point. Calls |op| on each basic block encountered during the traversal.361void visit(MachineFunction &MF, MachineBasicBlock &Start,362           std::function<void(MachineBasicBlock *)> op) {363  std::stack<MachineBasicBlock *> ToVisit;364  SmallPtrSet<MachineBasicBlock *, 8> Seen;365 366  ToVisit.push(&Start);367  Seen.insert(ToVisit.top());368  while (ToVisit.size() != 0) {369    MachineBasicBlock *MBB = ToVisit.top();370    ToVisit.pop();371 372    op(MBB);373 374    for (auto Succ : MBB->successors()) {375      if (Seen.contains(Succ))376        continue;377      ToVisit.push(Succ);378      Seen.insert(Succ);379    }380  }381}382 383// Do a preorder traversal of the CFG starting from the given function's entry384// point. Calls |op| on each basic block encountered during the traversal.385void visit(MachineFunction &MF, std::function<void(MachineBasicBlock *)> op) {386  visit(MF, *MF.begin(), std::move(op));387}388 389bool SPIRVPostLegalizer::runOnMachineFunction(MachineFunction &MF) {390  // Initialize the type registry.391  const SPIRVSubtarget &ST = MF.getSubtarget<SPIRVSubtarget>();392  SPIRVGlobalRegistry *GR = ST.getSPIRVGlobalRegistry();393  GR->setCurrentFunc(MF);394  registerSpirvTypeForNewInstructions(MF, GR);395  ensureAssignTypeForTypeFolding(MF, GR);396  return true;397}398 399INITIALIZE_PASS(SPIRVPostLegalizer, DEBUG_TYPE, "SPIRV post legalizer", false,400                false)401 402char SPIRVPostLegalizer::ID = 0;403 404FunctionPass *llvm::createSPIRVPostLegalizerPass() {405  return new SPIRVPostLegalizer();406}407