brintos

brintos / llvm-project-archived public Read only

0
0
Text · 16.2 KiB · e0049dc Raw
449 lines · cpp
1//===- DXILShaderFlags.cpp - DXIL Shader Flags helper objects -------------===//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/// \file This file contains helper objects and APIs for working with DXIL10///       Shader Flags.11///12//===----------------------------------------------------------------------===//13 14#include "DXILShaderFlags.h"15#include "DirectX.h"16#include "llvm/ADT/SCCIterator.h"17#include "llvm/ADT/SmallVector.h"18#include "llvm/Analysis/CallGraph.h"19#include "llvm/Analysis/DXILResource.h"20#include "llvm/IR/Attributes.h"21#include "llvm/IR/DiagnosticInfo.h"22#include "llvm/IR/Instruction.h"23#include "llvm/IR/Instructions.h"24#include "llvm/IR/IntrinsicInst.h"25#include "llvm/IR/Intrinsics.h"26#include "llvm/IR/IntrinsicsDirectX.h"27#include "llvm/IR/Module.h"28#include "llvm/InitializePasses.h"29#include "llvm/Support/FormatVariadic.h"30#include "llvm/Support/raw_ostream.h"31 32using namespace llvm;33using namespace llvm::dxil;34 35static bool hasUAVsAtEveryStage(const DXILResourceMap &DRM,36                                const ModuleMetadataInfo &MMDI) {37  if (DRM.uavs().empty())38    return false;39 40  switch (MMDI.ShaderProfile) {41  default:42    return false;43  case Triple::EnvironmentType::Compute:44  case Triple::EnvironmentType::Pixel:45    return false;46  case Triple::EnvironmentType::Vertex:47  case Triple::EnvironmentType::Geometry:48  case Triple::EnvironmentType::Hull:49  case Triple::EnvironmentType::Domain:50    return true;51  case Triple::EnvironmentType::Library:52  case Triple::EnvironmentType::RayGeneration:53  case Triple::EnvironmentType::Intersection:54  case Triple::EnvironmentType::AnyHit:55  case Triple::EnvironmentType::ClosestHit:56  case Triple::EnvironmentType::Miss:57  case Triple::EnvironmentType::Callable:58  case Triple::EnvironmentType::Mesh:59  case Triple::EnvironmentType::Amplification:60    return MMDI.ValidatorVersion < VersionTuple(1, 8);61  }62}63 64static bool checkWaveOps(Intrinsic::ID IID) {65  // Currently unsupported intrinsics66  // case Intrinsic::dx_wave_getlanecount:67  // case Intrinsic::dx_wave_allequal:68  // case Intrinsic::dx_wave_ballot:69  // case Intrinsic::dx_wave_readfirst:70  // case Intrinsic::dx_wave_reduce.and:71  // case Intrinsic::dx_wave_reduce.or:72  // case Intrinsic::dx_wave_reduce.xor:73  // case Intrinsic::dx_wave_prefixop:74  // case Intrinsic::dx_quad.readat:75  // case Intrinsic::dx_quad.readacrossx:76  // case Intrinsic::dx_quad.readacrossy:77  // case Intrinsic::dx_quad.readacrossdiagonal:78  // case Intrinsic::dx_wave_prefixballot:79  // case Intrinsic::dx_wave_match:80  // case Intrinsic::dx_wavemulti.*:81  // case Intrinsic::dx_wavemulti.ballot:82  // case Intrinsic::dx_quad.vote:83  switch (IID) {84  default:85    return false;86  case Intrinsic::dx_wave_is_first_lane:87  case Intrinsic::dx_wave_getlaneindex:88  case Intrinsic::dx_wave_any:89  case Intrinsic::dx_wave_all:90  case Intrinsic::dx_wave_readlane:91  case Intrinsic::dx_wave_active_countbits:92  // Wave Active Op Variants93  case Intrinsic::dx_wave_reduce_sum:94  case Intrinsic::dx_wave_reduce_usum:95  case Intrinsic::dx_wave_reduce_max:96  case Intrinsic::dx_wave_reduce_umax:97  case Intrinsic::dx_wave_reduce_min:98  case Intrinsic::dx_wave_reduce_umin:99    return true;100  }101}102 103// Checks to see if the status bit from a load with status104// instruction is ever extracted. If it is, the module needs105// to have the TiledResources shader flag set.106bool checkIfStatusIsExtracted(const IntrinsicInst &II) {107  [[maybe_unused]] Intrinsic::ID IID = II.getIntrinsicID();108  assert(IID == Intrinsic::dx_resource_load_typedbuffer ||109         IID == Intrinsic::dx_resource_load_rawbuffer &&110             "unexpected intrinsic ID");111  for (const User *U : II.users()) {112    if (const ExtractValueInst *EVI = dyn_cast<ExtractValueInst>(U)) {113      // Resource load operations return a {result, status} pair.114      // Check if we extract the status115      if (EVI->getNumIndices() == 1 && EVI->getIndices()[0] == 1)116        return true;117    }118  }119 120  return false;121}122 123/// Update the shader flags mask based on the given instruction.124/// \param CSF Shader flags mask to update.125/// \param I Instruction to check.126void ModuleShaderFlags::updateFunctionFlags(ComputedShaderFlags &CSF,127                                            const Instruction &I,128                                            DXILResourceTypeMap &DRTM,129                                            const ModuleMetadataInfo &MMDI) {130  if (!CSF.Doubles)131    CSF.Doubles = I.getType()->getScalarType()->isDoubleTy();132 133  if (!CSF.Doubles) {134    for (const Value *Op : I.operands()) {135      if (Op->getType()->getScalarType()->isDoubleTy()) {136        CSF.Doubles = true;137        break;138      }139    }140  }141 142  if (CSF.Doubles) {143    switch (I.getOpcode()) {144    case Instruction::FDiv:145    case Instruction::UIToFP:146    case Instruction::SIToFP:147    case Instruction::FPToUI:148    case Instruction::FPToSI:149      CSF.DX11_1_DoubleExtensions = true;150      break;151    }152  }153 154  if (!CSF.LowPrecisionPresent)155    CSF.LowPrecisionPresent = I.getType()->getScalarType()->isIntegerTy(16) ||156                              I.getType()->getScalarType()->isHalfTy();157 158  if (!CSF.LowPrecisionPresent) {159    for (const Value *Op : I.operands()) {160      if (Op->getType()->getScalarType()->isIntegerTy(16) ||161          Op->getType()->getScalarType()->isHalfTy()) {162        CSF.LowPrecisionPresent = true;163        break;164      }165    }166  }167 168  if (CSF.LowPrecisionPresent) {169    if (CSF.NativeLowPrecisionMode)170      CSF.NativeLowPrecision = true;171    else172      CSF.MinimumPrecision = true;173  }174 175  if (!CSF.Int64Ops)176    CSF.Int64Ops = I.getType()->getScalarType()->isIntegerTy(64);177 178  if (!CSF.Int64Ops && !isa<LifetimeIntrinsic>(&I)) {179    for (const Value *Op : I.operands()) {180      if (Op->getType()->getScalarType()->isIntegerTy(64)) {181        CSF.Int64Ops = true;182        break;183      }184    }185  }186 187  if (const auto *II = dyn_cast<IntrinsicInst>(&I)) {188    switch (II->getIntrinsicID()) {189    default:190      break;191    case Intrinsic::dx_resource_handlefrombinding: {192      dxil::ResourceTypeInfo &RTI = DRTM[cast<TargetExtType>(II->getType())];193 194      // Set ResMayNotAlias if DXIL validator version >= 1.8 and the function195      // uses UAVs196      if (!CSF.ResMayNotAlias && CanSetResMayNotAlias &&197          MMDI.ValidatorVersion >= VersionTuple(1, 8) && RTI.isUAV())198        CSF.ResMayNotAlias = true;199 200      switch (RTI.getResourceKind()) {201      case dxil::ResourceKind::StructuredBuffer:202      case dxil::ResourceKind::RawBuffer:203        CSF.EnableRawAndStructuredBuffers = true;204        break;205      default:206        break;207      }208      break;209    }210    case Intrinsic::dx_resource_load_typedbuffer: {211      dxil::ResourceTypeInfo &RTI =212          DRTM[cast<TargetExtType>(II->getArgOperand(0)->getType())];213      if (RTI.isTyped())214        CSF.TypedUAVLoadAdditionalFormats |= RTI.getTyped().ElementCount > 1;215      if (!CSF.TiledResources && checkIfStatusIsExtracted(*II))216        CSF.TiledResources = true;217      break;218    }219    case Intrinsic::dx_resource_load_rawbuffer: {220      if (!CSF.TiledResources && checkIfStatusIsExtracted(*II))221        CSF.TiledResources = true;222      break;223    }224    }225  }226  // Handle call instructions227  if (auto *CI = dyn_cast<CallInst>(&I)) {228    const Function *CF = CI->getCalledFunction();229    // Merge-in shader flags mask of the called function in the current module230    if (FunctionFlags.contains(CF))231      CSF.merge(FunctionFlags[CF]);232 233    // TODO: Set DX11_1_DoubleExtensions if I is a call to DXIL intrinsic234    // DXIL::Opcode::Fma https://github.com/llvm/llvm-project/issues/114554235 236    CSF.WaveOps |= checkWaveOps(CI->getIntrinsicID());237  }238}239 240/// Set shader flags that apply to all functions within the module241ComputedShaderFlags242ModuleShaderFlags::gatherGlobalModuleFlags(const Module &M,243                                           const DXILResourceMap &DRM,244                                           const ModuleMetadataInfo &MMDI) {245 246  ComputedShaderFlags CSF;247 248  // Set DisableOptimizations flag based on the presence of OptimizeNone249  // attribute of entry functions.250  if (MMDI.EntryPropertyVec.size() > 0) {251    CSF.DisableOptimizations = MMDI.EntryPropertyVec[0].Entry->hasFnAttribute(252        llvm::Attribute::OptimizeNone);253    // Ensure all entry functions have the same optimization attribute254    for (const auto &EntryFunProps : MMDI.EntryPropertyVec)255      if (CSF.DisableOptimizations !=256          EntryFunProps.Entry->hasFnAttribute(llvm::Attribute::OptimizeNone))257        EntryFunProps.Entry->getContext().diagnose(DiagnosticInfoUnsupported(258            *(EntryFunProps.Entry), "Inconsistent optnone attribute "));259  }260 261  CSF.UAVsAtEveryStage = hasUAVsAtEveryStage(DRM, MMDI);262 263  // Set the Max64UAVs flag if the number of UAVs is > 8264  uint32_t NumUAVs = 0;265  for (auto &UAV : DRM.uavs())266    if (MMDI.ValidatorVersion < VersionTuple(1, 6))267      NumUAVs++;268    else // MMDI.ValidatorVersion >= VersionTuple(1, 6)269      NumUAVs += UAV.getBinding().Size;270  if (NumUAVs > 8)271    CSF.Max64UAVs = true;272 273  // Set the module flag that enables native low-precision execution mode.274  // NativeLowPrecisionMode can only be set when the command line option275  // -enable-16bit-types is provided. This is indicated by the dx.nativelowprec276  // module flag being set277  // This flag is needed even if the module does not use 16-bit types because a278  // corresponding debug module may include 16-bit types, and tools that use the279  // debug module may expect it to have the same flags as the original280  if (auto *NativeLowPrec = mdconst::extract_or_null<ConstantInt>(281          M.getModuleFlag("dx.nativelowprec")))282    if (MMDI.ShaderModelVersion >= VersionTuple(6, 2))283      CSF.NativeLowPrecisionMode = NativeLowPrec->getValue().getBoolValue();284 285  // Set ResMayNotAlias to true if DXIL validator version < 1.8 and there286  // are UAVs present globally.287  if (CanSetResMayNotAlias && MMDI.ValidatorVersion < VersionTuple(1, 8))288    CSF.ResMayNotAlias = !DRM.uavs().empty();289 290  return CSF;291}292 293/// Construct ModuleShaderFlags for module Module M294void ModuleShaderFlags::initialize(Module &M, DXILResourceTypeMap &DRTM,295                                   const DXILResourceMap &DRM,296                                   const ModuleMetadataInfo &MMDI) {297 298  CanSetResMayNotAlias = MMDI.DXILVersion >= VersionTuple(1, 7);299  // The command line option -res-may-alias will set the dx.resmayalias module300  // flag to 1, thereby disabling the ability to set the ResMayNotAlias flag301  if (auto *ResMayAlias = mdconst::extract_or_null<ConstantInt>(302          M.getModuleFlag("dx.resmayalias")))303    if (ResMayAlias->getValue().getBoolValue())304      CanSetResMayNotAlias = false;305 306  ComputedShaderFlags GlobalSFMask = gatherGlobalModuleFlags(M, DRM, MMDI);307 308  CallGraph CG(M);309 310  // Compute Shader Flags Mask for all functions using post-order visit of SCC311  // of the call graph.312  for (scc_iterator<CallGraph *> SCCI = scc_begin(&CG); !SCCI.isAtEnd();313       ++SCCI) {314    const std::vector<CallGraphNode *> &CurSCC = *SCCI;315 316    // Union of shader masks of all functions in CurSCC317    ComputedShaderFlags SCCSF;318    // List of functions in CurSCC that are neither external nor declarations319    // and hence whose flags are collected320    SmallVector<Function *> CurSCCFuncs;321    for (CallGraphNode *CGN : CurSCC) {322      Function *F = CGN->getFunction();323      if (!F)324        continue;325 326      if (F->isDeclaration()) {327        assert(!F->getName().starts_with("dx.op.") &&328               "DXIL Shader Flag analysis should not be run post-lowering.");329        continue;330      }331 332      ComputedShaderFlags CSF = GlobalSFMask;333      for (const auto &BB : *F)334        for (const auto &I : BB)335          updateFunctionFlags(CSF, I, DRTM, MMDI);336      // Update combined shader flags mask for all functions in this SCC337      SCCSF.merge(CSF);338 339      CurSCCFuncs.push_back(F);340    }341 342    // Update combined shader flags mask for all functions of the module343    CombinedSFMask.merge(SCCSF);344 345    // Shader flags mask of each of the functions in an SCC of the call graph is346    // the union of all functions in the SCC. Update shader flags masks of347    // functions in CurSCC accordingly. This is trivially true if SCC contains348    // one function.349    for (Function *F : CurSCCFuncs)350      // Merge SCCSF with that of F351      FunctionFlags[F].merge(SCCSF);352  }353}354 355void ComputedShaderFlags::print(raw_ostream &OS) const {356  uint64_t FlagVal = (uint64_t) * this;357  OS << formatv("; Shader Flags Value: {0:x8}\n;\n", FlagVal);358  if (FlagVal == 0)359    return;360  OS << "; Note: shader requires additional functionality:\n";361#define SHADER_FEATURE_FLAG(FeatureBit, DxilModuleNum, FlagName, Str)          \362  if (FlagName)                                                                \363    (OS << ";").indent(7) << Str << "\n";364#include "llvm/BinaryFormat/DXContainerConstants.def"365  OS << "; Note: extra DXIL module flags:\n";366#define DXIL_MODULE_FLAG(DxilModuleBit, FlagName, Str)                         \367  if (FlagName)                                                                \368    (OS << ";").indent(7) << Str << "\n";369#include "llvm/BinaryFormat/DXContainerConstants.def"370  OS << ";\n";371}372 373/// Return the shader flags mask of the specified function Func.374const ComputedShaderFlags &375ModuleShaderFlags::getFunctionFlags(const Function *Func) const {376  auto Iter = FunctionFlags.find(Func);377  assert((Iter != FunctionFlags.end() && Iter->first == Func) &&378         "Get Shader Flags : No Shader Flags Mask exists for function");379  return Iter->second;380}381 382//===----------------------------------------------------------------------===//383// ShaderFlagsAnalysis and ShaderFlagsAnalysisPrinterPass384 385// Provide an explicit template instantiation for the static ID.386AnalysisKey ShaderFlagsAnalysis::Key;387 388ModuleShaderFlags ShaderFlagsAnalysis::run(Module &M,389                                           ModuleAnalysisManager &AM) {390  DXILResourceTypeMap &DRTM = AM.getResult<DXILResourceTypeAnalysis>(M);391  DXILResourceMap &DRM = AM.getResult<DXILResourceAnalysis>(M);392  const ModuleMetadataInfo MMDI = AM.getResult<DXILMetadataAnalysis>(M);393 394  ModuleShaderFlags MSFI;395  MSFI.initialize(M, DRTM, DRM, MMDI);396 397  return MSFI;398}399 400PreservedAnalyses ShaderFlagsAnalysisPrinter::run(Module &M,401                                                  ModuleAnalysisManager &AM) {402  const ModuleShaderFlags &FlagsInfo = AM.getResult<ShaderFlagsAnalysis>(M);403  // Print description of combined shader flags for all module functions404  OS << "; Combined Shader Flags for Module\n";405  FlagsInfo.getCombinedFlags().print(OS);406  // Print shader flags mask for each of the module functions407  OS << "; Shader Flags for Module Functions\n";408  for (const auto &F : M.getFunctionList()) {409    if (F.isDeclaration())410      continue;411    const ComputedShaderFlags &SFMask = FlagsInfo.getFunctionFlags(&F);412    OS << formatv("; Function {0} : {1:x8}\n;\n", F.getName(),413                  (uint64_t)(SFMask));414  }415 416  return PreservedAnalyses::all();417}418 419//===----------------------------------------------------------------------===//420// ShaderFlagsAnalysis and ShaderFlagsAnalysisPrinterPass421 422bool ShaderFlagsAnalysisWrapper::runOnModule(Module &M) {423  DXILResourceTypeMap &DRTM =424      getAnalysis<DXILResourceTypeWrapperPass>().getResourceTypeMap();425  DXILResourceMap &DRM =426      getAnalysis<DXILResourceWrapperPass>().getResourceMap();427  const ModuleMetadataInfo MMDI =428      getAnalysis<DXILMetadataAnalysisWrapperPass>().getModuleMetadata();429 430  MSFI.initialize(M, DRTM, DRM, MMDI);431  return false;432}433 434void ShaderFlagsAnalysisWrapper::getAnalysisUsage(AnalysisUsage &AU) const {435  AU.setPreservesAll();436  AU.addRequiredTransitive<DXILResourceTypeWrapperPass>();437  AU.addRequiredTransitive<DXILResourceWrapperPass>();438  AU.addRequired<DXILMetadataAnalysisWrapperPass>();439}440 441char ShaderFlagsAnalysisWrapper::ID = 0;442 443INITIALIZE_PASS_BEGIN(ShaderFlagsAnalysisWrapper, "dx-shader-flag-analysis",444                      "DXIL Shader Flag Analysis", true, true)445INITIALIZE_PASS_DEPENDENCY(DXILResourceTypeWrapperPass)446INITIALIZE_PASS_DEPENDENCY(DXILMetadataAnalysisWrapperPass)447INITIALIZE_PASS_END(ShaderFlagsAnalysisWrapper, "dx-shader-flag-analysis",448                    "DXIL Shader Flag Analysis", true, true)449