/*========================== begin_copyright_notice ============================ Copyright (C) 2017-2021 Intel Corporation SPDX-License-Identifier: MIT ============================= end_copyright_notice ===========================*/ #include "GenISAIntrinsics/GenIntrinsics.h" #include "Compiler/CodeGenPublicEnums.h" #include "Compiler/CodeGenPublic.h" #include "Compiler/MetaDataUtilsWrapper.h" #include "LLVM3DBuilder/MetadataBuilder.h" #include "common/LLVMWarningsPush.hpp" #include #include #include #include "common/LLVMWarningsPop.hpp" #include "LLVM3DBuilder/BuiltinsFrontend.hpp" #include "common/FunctionUpgrader.h" using namespace IGC; using namespace IGC::IGCMD; using namespace llvm; class LinkMultiRateShader : public ModulePass { public: LinkMultiRateShader() : ModulePass(ID) { } static char ID; bool runOnModule(llvm::Module& M); void getAnalysisUsage(llvm::AnalysisUsage& AU) const { AU.addRequired(); AU.addRequired(); } virtual llvm::StringRef getPassName() const { return "LinkMultirateShader"; } private: void Link(Function* pixelPhase, Function* samplePhase, Module& M); Function* PatchSamplePhaseSignature( Function* samplePhase, SmallDenseMap & linkSignature); void GetPixelPhaseOutput( Function* pixelPhase, SmallVector & outputs, const SmallDenseMap & linkSignature); }; char LinkMultiRateShader::ID = 0; Pass* CreateLinkMultiRateShaderPass() { return new LinkMultiRateShader(); } bool LinkMultiRateShader::runOnModule(llvm::Module& M) { Function* pixelPhase = nullptr; Function* samplePhase = nullptr; NamedMDNode* pixelNode = M.getNamedMetadata("pixel_phase"); NamedMDNode* sampleNode = M.getNamedMetadata("sample_phase"); if (sampleNode == nullptr) { // if there is no sample phase no need to link return false; } if (pixelNode) { pixelPhase = mdconst::dyn_extract(pixelNode->getOperand(0)->getOperand(0)); } if (sampleNode) { samplePhase = mdconst::dyn_extract(sampleNode->getOperand(0)->getOperand(0)); } if (pixelPhase == nullptr) { IRBuilder<> builder(M.getContext()); pixelPhase = Function::Create(FunctionType::get(builder.getVoidTy(), false), GlobalValue::ExternalLinkage, "multiRatePS", &M); BasicBlock* bb = BasicBlock::Create(M.getContext(), "dummyBB", pixelPhase); builder.SetInsertPoint(bb); builder.CreateRetVoid(); MetadataBuilder metadatBuilder(&M); metadatBuilder.SetShadingRate(pixelPhase, PSPHASE_PIXEL); } Link(pixelPhase, samplePhase, M); sampleNode->eraseFromParent(); MetaDataUtils* pMdUtils = getAnalysis().getMetaDataUtils(); pMdUtils->clearFunctionsInfo(); IGCMetaDataHelper::addFunction(*pMdUtils, pixelPhase); NamedMDNode* coarseNode = M.getNamedMetadata(NAMED_METADATA_COARSE_PHASE); if (coarseNode != nullptr) { Function* coarsePhase = llvm::mdconst::dyn_extract(coarseNode->getOperand(0)->getOperand(0)); IGCMetaDataHelper::addFunction(*pMdUtils, coarsePhase); } return true; } void LinkMultiRateShader::GetPixelPhaseOutput( Function* pixelPhase, SmallVector & outputs, const SmallDenseMap & linkSignature) { Function* phaseInput = GenISAIntrinsic::getDeclaration( pixelPhase->getParent(), GenISAIntrinsic::GenISA_PHASE_OUTPUT, Type::getFloatTy(pixelPhase->getContext())); Function* phaseHalfInput = GenISAIntrinsic::getDeclaration( pixelPhase->getParent(), GenISAIntrinsic::GenISA_PHASE_OUTPUT, Type::getHalfTy(pixelPhase->getContext())); SmallVector phaseIntrinsics; auto getPhaseInputs = [&phaseIntrinsics, &outputs, &linkSignature, pixelPhase](User* user) { if (Instruction * inst = dyn_cast(user)) { if (inst->getParent()->getParent() == pixelPhase) { unsigned int index = (unsigned int)cast(inst->getOperand(1))->getZExtValue(); auto it = linkSignature.find(index); if (it != linkSignature.end()) { unsigned int location = it->second; outputs[location + 1] = inst->getOperand(0); } phaseIntrinsics.push_back(inst); } } }; for (auto* user : phaseInput->users()) { getPhaseInputs(user); } for (auto* user : phaseHalfInput->users()) { getPhaseInputs(user); } for (auto phaseIntrinsic : phaseIntrinsics) { phaseIntrinsic->eraseFromParent(); } } void LinkMultiRateShader::Link(Function* pixelPhase, Function* samplePhase, Module& M) { IGCLLVM::IRBuilder<> builder(M.getContext()); SmallDenseMap linkSignature; Function* samplePhasePatched = PatchSamplePhaseSignature(samplePhase, linkSignature); BasicBlock* returnBB = &pixelPhase->getBasicBlockList().back(); BasicBlock* loopHeader = BasicBlock::Create(M.getContext(), "SampleLoopHeader", pixelPhase); BasicBlock* loopBlock = BasicBlock::Create(M.getContext(), "LoopBlock", pixelPhase); BasicBlock* newRet = BasicBlock::Create(M.getContext(), "ret", pixelPhase); returnBB->getTerminator()->eraseFromParent(); builder.SetInsertPoint(returnBB); builder.CreateBr(loopHeader); builder.SetInsertPoint(&(*pixelPhase->getEntryBlock().begin())); Value* loopCounterPtr = builder.CreateAlloca(builder.getInt32Ty()); // Initialize the loop counter in the loop header builder.SetInsertPoint(loopHeader); unsigned int addrSpaceRsc = IGC::EncodeAS4GFXResource(*builder.getInt32(0), RENDER_TARGET); PointerType* ptrTy = llvm::PointerType::get(builder.getInt32Ty(), addrSpaceRsc); Value* pRsrc = ConstantPointerNull::get(ptrTy); Function* sampleInfoptr = GenISAIntrinsic::getDeclaration(&M, GenISAIntrinsic::GenISA_sampleinfoptr, pRsrc->getType()); Value* sampleInfoValue = builder.CreateCall(sampleInfoptr, pRsrc); Value* msaaRate = builder.CreateExtractElement(sampleInfoValue, builder.getInt32(0)); builder.CreateStore(msaaRate, loopCounterPtr); builder.CreateBr(loopBlock); //Loop block decrement the counter and call the sample phase builder.SetInsertPoint(loopBlock); Value* counter = builder.CreateLoad(loopCounterPtr); counter = builder.CreateAdd(counter, builder.getInt32(-1)); SmallVector inputs(linkSignature.size() + 1, UndefValue::get(builder.getFloatTy())); inputs[0] = counter; GetPixelPhaseOutput(pixelPhase, inputs, linkSignature); builder.CreateStore(counter, loopCounterPtr); builder.CreateCall(samplePhasePatched, inputs); Value* cond = builder.CreateICmp(CmpInst::Predicate::ICMP_EQ, counter, builder.getInt32(0)); builder.CreateCondBr(cond, newRet, loopBlock); // The new return block is empty builder.SetInsertPoint(newRet); builder.CreateRetVoid(); } Function* LinkMultiRateShader::PatchSamplePhaseSignature( Function* samplePhase, SmallDenseMap & linkSignature) { SmallDenseMap linkArguments; Module* M = samplePhase->getParent(); CodeGenContext* ctx = getAnalysis().getCodeGenContext(); LLVM3DBuilder<> builder(samplePhase->getContext(), ctx->platform.getPlatformInfo()); FunctionUpgrader FuncUpgrader; FuncUpgrader.SetFunctionToUpgrade(samplePhase); // find all the phase inputs Function* phaseInput = GenISAIntrinsic::getDeclaration( M, GenISAIntrinsic::GenISA_PHASE_INPUT, builder.getFloatTy()); Function* phaseHalfInput = GenISAIntrinsic::getDeclaration( M, GenISAIntrinsic::GenISA_PHASE_INPUT, builder.getHalfTy()); Value* sampleIndex = FuncUpgrader.AddArgument("", builder.getInt32Ty()); SmallVector funcSignature; funcSignature.push_back(builder.getInt32Ty()); unsigned int inputLocation = 0; auto getLinkInfo = [samplePhase, &linkArguments, &linkSignature, &FuncUpgrader, &funcSignature, &inputLocation](User* user) { if (Instruction * inst = dyn_cast(user)) { if (inst->getParent()->getParent() == samplePhase) { int index = (int)cast(inst->getOperand(0))->getZExtValue(); Value* arg = nullptr; auto it = linkArguments.find(index); if (it != linkArguments.end()) { arg = it->second; } else { arg = FuncUpgrader.AddArgument("", inst->getType()); funcSignature.push_back(inst->getType()); linkArguments[index] = arg; linkSignature[index] = inputLocation++; } inst->replaceAllUsesWith(arg); } } }; for (auto* user : phaseInput->users()) { getLinkInfo(user); } for (auto* user : phaseHalfInput->users()) { getLinkInfo(user); } Function* newSamplePhase = FuncUpgrader.RebuildFunction(); samplePhase->eraseFromParent(); samplePhase = newSamplePhase; samplePhase->addFnAttr(llvm::Attribute::AlwaysInline); sampleIndex = FuncUpgrader.GetArgumentFromRebuild(sampleIndex); FuncUpgrader.Clean(); // Replace sample index intrinsic Function* SGV = GenISAIntrinsic::getDeclaration( M, GenISAIntrinsic::GenISA_DCL_SystemValue, builder.getFloatTy()); for (auto I = SGV->user_begin(), E = SGV->user_end(); I != E; ++I) { if (Instruction * inst = dyn_cast(*I)) { if (inst->getParent()->getParent() == samplePhase) { builder.SetInsertPoint(inst->getNextNode()); SGVUsage usage = (SGVUsage)cast(inst->getOperand(0))->getZExtValue(); if (usage == SAMPLEINDEX) { Value* sampleIndexCast = builder.CreateBitCast(sampleIndex, builder.getFloatTy()); inst->replaceAllUsesWith(sampleIndexCast); } } } } Function* input = GenISAIntrinsic::getDeclaration( M, GenISAIntrinsic::GenISA_DCL_inputVec, builder.getFloatTy()); for (auto I = input->user_begin(), E = input->user_end(); I != E; ++I) { if (Instruction * inst = dyn_cast(*I)) { if (inst->getParent()->getParent() == samplePhase) { e_interpolation interpolationMode = (e_interpolation)llvm::cast(inst->getOperand(1))->getZExtValue(); bool perspective = true; if (interpolationMode == EINTERPOLATION_LINEARNOPERSPECTIVE || interpolationMode == EINTERPOLATION_LINEARNOPERSPECTIVECENTROID || interpolationMode == EINTERPOLATION_LINEARNOPERSPECTIVESAMPLE) { perspective = false; } builder.SetInsertPoint(inst); Value* InputAtSamplePos = builder.CreateEvalSampleIndex( inst->getOperand(0), sampleIndex, builder.getInt1(perspective)); inst->replaceAllUsesWith(InputAtSamplePos); } } } Function* rtRead = GenISAIntrinsic::getDeclaration( M, GenISAIntrinsic::GenISA_RenderTargetRead); for (auto I = rtRead->user_begin(), E = rtRead->user_end(); I != E; ++I) { if (Instruction * inst = dyn_cast(*I)) { if (inst->getParent()->getParent() == samplePhase) { builder.SetInsertPoint(inst->getNextNode()); Value* rtReadSampleFreqargs[] = { inst->getOperand(0), sampleIndex }; Function* pRTSampleFreqIntrinsic = llvm::GenISAIntrinsic::getDeclaration( M, llvm::GenISAIntrinsic::GenISA_RenderTargetReadSampleFreq ); CallInst* rtReadSampleFreqInst = builder.CreateCall( pRTSampleFreqIntrinsic, rtReadSampleFreqargs); inst->replaceAllUsesWith(rtReadSampleFreqInst); } } } Function* rtWrite = GenISAIntrinsic::getDeclaration( M, GenISAIntrinsic::GenISA_RTWrite, builder.getFloatTy()); for (auto I = rtWrite->user_begin(), E = rtWrite->user_end(); I != E; ++I) { if (RTWritIntrinsic * inst = dyn_cast(*I)) { if (inst->getParent()->getParent() == samplePhase) { inst->setPerSample(); inst->setSampleIndex(sampleIndex); } } } Function* dualBlend = GenISAIntrinsic::getDeclaration( M, GenISAIntrinsic::GenISA_RTDualBlendSource, builder.getFloatTy()); for (auto I = dualBlend->user_begin(), E = dualBlend->user_end(); I != E; ++I) { if (RTDualBlendSourceIntrinsic * inst = dyn_cast(*I)) { if (inst->getParent()->getParent() == samplePhase) { inst->setPerSample(); inst->setSampleIndex(sampleIndex); } } } return samplePhase; }