/////////////////////////////////////////////////////////////////////////////// // // // DxilPrecisePropagatePass.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. // // // /////////////////////////////////////////////////////////////////////////////// #include "dxc/DXIL/DxilModule.h" #include "dxc/HLSL/DxilGenerationPass.h" #include "dxc/HLSL/HLModule.h" #include "dxc/HLSL/HLOperations.h" #include "llvm/Pass.h" #include "llvm/IR/Function.h" #include "llvm/IR/Instruction.h" #include "llvm/IR/Instructions.h" #include "llvm/IR/Operator.h" #include "llvm/IR/Module.h" #include "llvm/Support/Casting.h" #include #include using namespace llvm; using namespace hlsl; namespace { class DxilPrecisePropagatePass : public ModulePass { public: static char ID; // Pass identification, replacement for typeid explicit DxilPrecisePropagatePass() : ModulePass(ID) {} const char *getPassName() const override { return "DXIL Precise Propagate"; } bool runOnModule(Module &M) override { DxilModule &dxilModule = M.GetOrCreateDxilModule(); DxilTypeSystem &typeSys = dxilModule.GetTypeSystem(); std::unordered_set processedSet; std::vector deadList; for (Function &F : M.functions()) { if (HLModule::HasPreciseAttribute(&F)) { PropagatePreciseOnFunctionUser(F, typeSys, processedSet); deadList.emplace_back(&F); } } for (Function *F : deadList) F->eraseFromParent(); return true; } private: void PropagatePreciseOnFunctionUser( Function &F, DxilTypeSystem &typeSys, std::unordered_set &processedSet); }; char DxilPrecisePropagatePass::ID = 0; } static void PropagatePreciseAttribute(Instruction *I, DxilTypeSystem &typeSys, std::unordered_set &processedSet); static void PropagatePreciseAttributeOnOperand( Value *V, DxilTypeSystem &typeSys, LLVMContext &Context, std::unordered_set &processedSet) { Instruction *I = dyn_cast(V); // Skip none inst. if (!I) return; FPMathOperator *FPMath = dyn_cast(I); // Skip none FPMath if (!FPMath) return; // Skip inst already marked. if (processedSet.count(I) > 0) return; // TODO: skip precise on integer type, sample instruction... processedSet.insert(I); // Set precise fast math on those instructions that support it. if (DxilModule::PreservesFastMathFlags(I)) DxilModule::SetPreciseFastMathFlags(I); // Fast math not work on call, use metadata. if (CallInst *CI = dyn_cast(I)) HLModule::MarkPreciseAttributeWithMetadata(CI); PropagatePreciseAttribute(I, typeSys, processedSet); } static void PropagatePreciseAttributeOnPointer( Value *Ptr, DxilTypeSystem &typeSys, LLVMContext &Context, std::unordered_set &processedSet) { // Find all store and propagate on the val operand of store. // For CallInst, if Ptr is used as out parameter, mark it. for (User *U : Ptr->users()) { Instruction *user = cast(U); if (StoreInst *stInst = dyn_cast(user)) { Value *val = stInst->getValueOperand(); PropagatePreciseAttributeOnOperand(val, typeSys, Context, processedSet); } else if (CallInst *CI = dyn_cast(user)) { bool bReadOnly = true; Function *F = CI->getCalledFunction(); const DxilFunctionAnnotation *funcAnnotation = typeSys.GetFunctionAnnotation(F); for (unsigned i = 0; i < CI->getNumArgOperands(); ++i) { if (Ptr != CI->getArgOperand(i)) continue; const DxilParameterAnnotation ¶mAnnotation = funcAnnotation->GetParameterAnnotation(i); // OutputPatch and OutputStream will be checked after scalar repl. // Here only check out/inout if (paramAnnotation.GetParamInputQual() == DxilParamInputQual::Out || paramAnnotation.GetParamInputQual() == DxilParamInputQual::Inout) { bReadOnly = false; break; } } if (!bReadOnly) PropagatePreciseAttributeOnOperand(CI, typeSys, Context, processedSet); } } } static void PropagatePreciseAttribute(Instruction *I, DxilTypeSystem &typeSys, std::unordered_set &processedSet) { LLVMContext &Context = I->getContext(); if (AllocaInst *AI = dyn_cast(I)) { PropagatePreciseAttributeOnPointer(AI, typeSys, Context, processedSet); } else if (dyn_cast(I)) { // Propagate every argument. // TODO: only propagate precise argument. for (Value *src : I->operands()) PropagatePreciseAttributeOnOperand(src, typeSys, Context, processedSet); } else if (dyn_cast(I)) { // TODO: only propagate precise argument. for (Value *src : I->operands()) PropagatePreciseAttributeOnOperand(src, typeSys, Context, processedSet); } else if (LoadInst *ldInst = dyn_cast(I)) { Value *Ptr = ldInst->getPointerOperand(); PropagatePreciseAttributeOnPointer(Ptr, typeSys, Context, processedSet); } else if (GetElementPtrInst *GEP = dyn_cast(I)) PropagatePreciseAttributeOnPointer(GEP, typeSys, Context, processedSet); // TODO: support more case which need } void DxilPrecisePropagatePass::PropagatePreciseOnFunctionUser( Function &F, DxilTypeSystem &typeSys, std::unordered_set &processedSet) { LLVMContext &Context = F.getContext(); for (auto U = F.user_begin(), E = F.user_end(); U != E;) { CallInst *CI = cast(*(U++)); Value *V = CI->getArgOperand(0); PropagatePreciseAttributeOnOperand(V, typeSys, Context, processedSet); CI->eraseFromParent(); } } ModulePass *llvm::createDxilPrecisePropagatePass() { return new DxilPrecisePropagatePass(); } INITIALIZE_PASS(DxilPrecisePropagatePass, "hlsl-dxil-precise", "DXIL precise attribute propagate", false, false)