| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214 |
- ///////////////////////////////////////////////////////////////////////////////
- // //
- // DxilSignature.cpp //
- // Copyright (C) Microsoft Corporation. All rights reserved. //
- // This file is distributed under the University of Illinois Open Source //
- // License. See LICENSE.TXT for details. //
- // //
- // DxilLegalizeSampleOffsetPass implementation. //
- // //
- ///////////////////////////////////////////////////////////////////////////////
- #include "dxc/HLSL/DxilGenerationPass.h"
- #include "dxc/HLSL/DxilModule.h"
- #include "dxc/HLSL/DxilOperations.h"
- #include "llvm/Analysis/InstructionSimplify.h"
- #include "llvm/Analysis/LoopInfo.h"
- #include "llvm/IR/Constants.h"
- #include "llvm/IR/Dominators.h"
- #include "llvm/IR/Instructions.h"
- #include "llvm/IR/LLVMContext.h"
- #include "llvm/IR/LegacyPassManager.h"
- #include "llvm/IR/PassManager.h"
- #include "llvm/Pass.h"
- #include "llvm/Transforms/Scalar.h"
- #include <unordered_set>
- using std::vector;
- using std::unique_ptr;
- using namespace llvm;
- using namespace hlsl;
- ///////////////////////////////////////////////////////////////////////////////
- // Legalize Sample offset.
- namespace {
- // When optimizations are disabled, try to legalize sample offset.
- class DxilLegalizeSampleOffsetPass : public FunctionPass {
- public:
- static char ID; // Pass identification, replacement for typeid
- explicit DxilLegalizeSampleOffsetPass() : FunctionPass(ID) {}
- const char *getPassName() const override {
- return "DXIL legalize sample offset";
- }
- bool runOnFunction(Function &F) override {
- DxilModule &DM = F.getParent()->GetOrCreateDxilModule();
- hlsl::OP *hlslOP = DM.GetOP();
- std::vector<Instruction *> illegalOffsets;
- CollectIllegalOffsets(illegalOffsets, F, hlslOP);
- if (illegalOffsets.empty())
- return false;
- // Loop unroll if has offset inside loop.
- TryUnrollLoop(illegalOffsets, F);
- // Collect offset again after mem2reg.
- std::vector<Instruction *> ssaIllegalOffsets;
- CollectIllegalOffsets(ssaIllegalOffsets, F, hlslOP);
- // Run simple optimization to legalize offsets.
- LegalizeOffsets(ssaIllegalOffsets);
- // Remove PHINodes to keep code shape.
- legacy::FunctionPassManager PM(F.getParent());
- PM.add(createDemoteRegisterToMemoryHlslPass());
- PM.run(F);
- FinalCheck(illegalOffsets, F, hlslOP);
- return true;
- }
- private:
- void TryUnrollLoop(std::vector<Instruction *> &illegalOffsets, Function &F);
- void CollectIllegalOffsets(std::vector<Instruction *> &illegalOffsets,
- Function &F, hlsl::OP *hlslOP);
- void CollectIllegalOffsets(std::vector<Instruction *> &illegalOffsets,
- Function &F, DXIL::OpCode opcode,
- hlsl::OP *hlslOP);
- void LegalizeOffsets(const std::vector<Instruction *> &illegalOffsets);
- void FinalCheck(std::vector<Instruction *> &illegalOffsets, Function &F,
- hlsl::OP *hlslOP);
- };
- char DxilLegalizeSampleOffsetPass::ID = 0;
- bool HasIllegalOffsetInLoop(std::vector<Instruction *> &illegalOffsets,
- Function &F) {
- DominatorTreeAnalysis DTA;
- DominatorTree DT = DTA.run(F);
- LoopInfo LI;
- LI.Analyze(DT);
- bool findOffset = false;
- for (Instruction *I : illegalOffsets) {
- BasicBlock *BB = I->getParent();
- if (LI.getLoopFor(BB)) {
- findOffset = true;
- break;
- }
- }
- return findOffset;
- }
- void CollectIllegalOffset(CallInst *CI,
- std::vector<Instruction *> &illegalOffsets) {
- Value *offset0 =
- CI->getArgOperand(DXIL::OperandIndex::kTextureSampleOffset0OpIdx);
- // No offset.
- if (isa<UndefValue>(offset0))
- return;
- for (unsigned i = DXIL::OperandIndex::kTextureSampleOffset0OpIdx;
- i <= DXIL::OperandIndex::kTextureSampleOffset2OpIdx; i++) {
- Value *offset = CI->getArgOperand(i);
- if (Instruction *I = dyn_cast<Instruction>(offset))
- illegalOffsets.emplace_back(I);
- }
- }
- }
- void DxilLegalizeSampleOffsetPass::FinalCheck(
- std::vector<Instruction *> &illegalOffsets, Function &F, hlsl::OP *hlslOP) {
- // Collect offset to make sure no illegal offsets.
- std::vector<Instruction *> finalIllegalOffsets;
- CollectIllegalOffsets(finalIllegalOffsets, F, hlslOP);
- if (!finalIllegalOffsets.empty()) {
- const StringRef kIllegalOffsetError =
- "Offsets for Sample* must be immediated value. "
- "Consider unroll the loop manually and use O3, it may help in some "
- "cases\n";
- std::string errorMsg;
- raw_string_ostream errorStr(errorMsg);
- for (Instruction *offset : finalIllegalOffsets) {
- if (const DebugLoc &L = offset->getDebugLoc())
- L.print(errorStr);
- errorStr << " " << kIllegalOffsetError;
- }
- errorStr.flush();
- F.getContext().emitError(errorMsg);
- }
- }
- void DxilLegalizeSampleOffsetPass::TryUnrollLoop(
- std::vector<Instruction *> &illegalOffsets, Function &F) {
- legacy::FunctionPassManager PM(F.getParent());
- // Scalarize aggregates as mem2reg only applies on scalars.
- PM.add(createSROAPass());
- // Always need mem2reg for simplify illegal offsets.
- PM.add(createPromoteMemoryToRegisterPass());
- if (HasIllegalOffsetInLoop(illegalOffsets, F)) {
- PM.add(createCFGSimplificationPass());
- PM.add(createLCSSAPass());
- PM.add(createLoopSimplifyPass());
- PM.add(createLoopRotatePass());
- PM.add(createLoopUnrollPass(-2, -1, 0, 0));
- }
- PM.run(F);
- }
- void DxilLegalizeSampleOffsetPass::CollectIllegalOffsets(
- std::vector<Instruction *> &illegalOffsets, Function &CurF,
- hlsl::OP *hlslOP) {
- CollectIllegalOffsets(illegalOffsets, CurF, DXIL::OpCode::Sample, hlslOP);
- CollectIllegalOffsets(illegalOffsets, CurF, DXIL::OpCode::SampleBias, hlslOP);
- CollectIllegalOffsets(illegalOffsets, CurF, DXIL::OpCode::SampleCmp, hlslOP);
- CollectIllegalOffsets(illegalOffsets, CurF, DXIL::OpCode::SampleCmpLevelZero,
- hlslOP);
- CollectIllegalOffsets(illegalOffsets, CurF, DXIL::OpCode::SampleGrad, hlslOP);
- CollectIllegalOffsets(illegalOffsets, CurF, DXIL::OpCode::SampleLevel,
- hlslOP);
- }
- void DxilLegalizeSampleOffsetPass::CollectIllegalOffsets(
- std::vector<Instruction *> &illegalOffsets, Function &CurF,
- DXIL::OpCode opcode, hlsl::OP *hlslOP) {
- auto &intrFuncList = hlslOP->GetOpFuncList(opcode);
- for (auto it : intrFuncList) {
- Function *intrFunc = it.second;
- if (!intrFunc)
- continue;
- for (User *U : intrFunc->users()) {
- CallInst *CI = cast<CallInst>(U);
- // Skip inst not in current function.
- if (CI->getParent()->getParent() != &CurF)
- continue;
- CollectIllegalOffset(CI, illegalOffsets);
- }
- }
- }
- void DxilLegalizeSampleOffsetPass::LegalizeOffsets(
- const std::vector<Instruction *> &illegalOffsets) {
- for (Instruction *I : illegalOffsets)
- llvm::recursivelySimplifyInstruction(I);
- }
- FunctionPass *llvm::createDxilLegalizeSampleOffsetPass() {
- return new DxilLegalizeSampleOffsetPass();
- }
- INITIALIZE_PASS(DxilLegalizeSampleOffsetPass, "dxil-legalize-sample-offset",
- "DXIL legalize sample offset", false, false)
|