|
@@ -10,15 +10,25 @@
|
|
|
#include "dxc/DXIL/DxilUtil.h"
|
|
|
#include "dxc/HLSL/DxilGenerationPass.h"
|
|
|
#include "dxc/HLSL/HLModule.h"
|
|
|
+#include "dxc/DXIL/DxilResourceBase.h"
|
|
|
+#include "dxc/DXIL/DxilResource.h"
|
|
|
+#include "dxc/DXIL/DxilCBuffer.h"
|
|
|
+#include "dxc/DXIL/DxilOperations.h"
|
|
|
+#include "dxc/DXIL/DxilModule.h"
|
|
|
#include "llvm/Pass.h"
|
|
|
#include "llvm/Analysis/AssumptionCache.h"
|
|
|
+#include "llvm/ADT/DenseSet.h"
|
|
|
#include "llvm/IR/Dominators.h"
|
|
|
#include "llvm/IR/Function.h"
|
|
|
#include "llvm/IR/Instruction.h"
|
|
|
#include "llvm/IR/Instructions.h"
|
|
|
+#include "llvm/IR/Intrinsics.h"
|
|
|
#include "llvm/IR/LLVMContext.h"
|
|
|
#include "llvm/IR/Module.h"
|
|
|
+#include "llvm/IR/Attributes.h"
|
|
|
+#include "llvm/IR/DebugInfo.h"
|
|
|
#include "llvm/IR/Operator.h"
|
|
|
+
|
|
|
#include "llvm/Transforms/Utils/PromoteMemToReg.h"
|
|
|
#include "llvm/Transforms/Utils/SSAUpdater.h"
|
|
|
#include <unordered_set>
|
|
@@ -223,3 +233,474 @@ ModulePass *llvm::createDxilPromoteStaticResources() {
|
|
|
INITIALIZE_PASS(DxilPromoteStaticResources,
|
|
|
"hlsl-dxil-promote-static-resources",
|
|
|
"DXIL promote static resource use", false, false)
|
|
|
+
|
|
|
+// Mutate high-level resource type into handle.
|
|
|
+// This is used for SM 6.6+, on libraries only, where
|
|
|
+// CreateHandleForLib is eliminated, and high-level resource
|
|
|
+// types are only preserved in metadata for reflection purposes.
|
|
|
+namespace {
|
|
|
+// Overview
|
|
|
+// 1. collectCandidates - collect to MutateValSet
|
|
|
+// Start from resource global variable, function parameter/ret, alloca.
|
|
|
+// Propagate to all insts, GEP/ld/st/phi/select/called functions.
|
|
|
+// 2. mutateCandidates
|
|
|
+// Mutate all non-function value types.
|
|
|
+// Mutate functions by creating new function with new type, then
|
|
|
+// splice original function blocks into new function, and
|
|
|
+// replace old argument uses with new function's arguments.
|
|
|
+class DxilMutateResourceToHandle : public ModulePass {
|
|
|
+public:
|
|
|
+ static char ID; // Pass identification, replacement for typeid
|
|
|
+ explicit DxilMutateResourceToHandle() : ModulePass(ID) {}
|
|
|
+
|
|
|
+ const char *getPassName() const override {
|
|
|
+ return "DXIL Mutate resource to handle";
|
|
|
+ }
|
|
|
+
|
|
|
+ bool runOnModule(Module &M) override {
|
|
|
+ if (M.HasHLModule()) {
|
|
|
+ auto &HLM = M.GetHLModule();
|
|
|
+ if (!HLM.GetShaderModel()->IsSM66Plus())
|
|
|
+ return false;
|
|
|
+
|
|
|
+ hdlTy = HLM.GetOP()->GetHandleType();
|
|
|
+ pTypeSys = &HLM.GetTypeSystem();
|
|
|
+ } else if (M.HasDxilModule()) {
|
|
|
+ auto &DM = M.GetDxilModule();
|
|
|
+ if (!DM.GetShaderModel()->IsSM66Plus())
|
|
|
+ return false;
|
|
|
+
|
|
|
+ hdlTy = DM.GetOP()->GetHandleType();
|
|
|
+ pTypeSys = &DM.GetTypeSystem();
|
|
|
+ } else {
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+ collectCandidates(M);
|
|
|
+ mutateCandidates(M);
|
|
|
+ // Remvoe cast to handle.
|
|
|
+ return !MutateValSet.empty();
|
|
|
+ }
|
|
|
+
|
|
|
+private:
|
|
|
+ Type *mutateToHandleTy(Type *Ty);
|
|
|
+ bool mutateTypesToHandleTy(SmallVector<Type *, 4> &Tys);
|
|
|
+
|
|
|
+ void collectGlobalResource(DxilResourceBase *Res,
|
|
|
+ SmallVector<Value *, 8> &WorkList);
|
|
|
+ void collectAlloca(Function &F, SmallVector<Value *, 8> &WorkList);
|
|
|
+
|
|
|
+ SmallVector<Value *, 8> collectHlslObjects(Module &M);
|
|
|
+
|
|
|
+ void collectCandidates(Module &M);
|
|
|
+ void mutateCandidates(Module &M);
|
|
|
+
|
|
|
+ Type *hdlTy;
|
|
|
+ DxilTypeSystem *pTypeSys;
|
|
|
+ DenseSet<Value *> MutateValSet;
|
|
|
+ DenseMap<Type *, Type *> MutateTypeMap;
|
|
|
+};
|
|
|
+
|
|
|
+char DxilMutateResourceToHandle::ID = 0;
|
|
|
+
|
|
|
+Type *DxilMutateResourceToHandle::mutateToHandleTy(Type *Ty) {
|
|
|
+ auto it = MutateTypeMap.find(Ty);
|
|
|
+ if (it != MutateTypeMap.end())
|
|
|
+ return it->second;
|
|
|
+
|
|
|
+ Type *ResultTy = nullptr;
|
|
|
+ if (ArrayType *AT = dyn_cast<ArrayType>(Ty)) {
|
|
|
+ SmallVector<unsigned, 2> nestedSize;
|
|
|
+ Type *EltTy = Ty;
|
|
|
+ while (ArrayType *NestAT = dyn_cast<ArrayType>(EltTy)) {
|
|
|
+ nestedSize.emplace_back(NestAT->getNumElements());
|
|
|
+ EltTy = NestAT->getElementType();
|
|
|
+ }
|
|
|
+ Type *mutatedTy = mutateToHandleTy(EltTy);
|
|
|
+ if (mutatedTy == EltTy) {
|
|
|
+ ResultTy = Ty;
|
|
|
+ } else {
|
|
|
+ Type *newAT = mutatedTy;
|
|
|
+ for (auto it = nestedSize.rbegin(), E = nestedSize.rend(); it != E; ++it)
|
|
|
+ newAT = ArrayType::get(newAT, *it);
|
|
|
+ ResultTy = newAT;
|
|
|
+ }
|
|
|
+ } else if (PointerType *PT = dyn_cast<PointerType>(Ty)) {
|
|
|
+ Type *EltTy = PT->getElementType();
|
|
|
+ Type *mutatedTy = mutateToHandleTy(EltTy);
|
|
|
+ if (mutatedTy == EltTy)
|
|
|
+ ResultTy = Ty;
|
|
|
+ else
|
|
|
+ ResultTy = mutatedTy->getPointerTo(PT->getAddressSpace());
|
|
|
+ } else if (dxilutil::IsHLSLResourceType(Ty)) {
|
|
|
+ ResultTy = hdlTy;
|
|
|
+ } else if (StructType *ST = dyn_cast<StructType>(Ty)) {
|
|
|
+ if (!ST->isOpaque()) {
|
|
|
+ SmallVector<Type *, 4> Elts(ST->element_begin(), ST->element_end());
|
|
|
+ if (!mutateTypesToHandleTy(Elts)) {
|
|
|
+ ResultTy = Ty;
|
|
|
+ } else {
|
|
|
+ ResultTy = StructType::create(Elts, ST->getName().str() + ".hdl");
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ if (ST->getName() == "ConstantBuffer")
|
|
|
+ ResultTy = hdlTy;
|
|
|
+ else
|
|
|
+ ResultTy = Ty;
|
|
|
+ }
|
|
|
+ } else if (FunctionType *FT = dyn_cast<FunctionType>(Ty)) {
|
|
|
+ Type *RetTy = FT->getReturnType();
|
|
|
+ SmallVector<Type *, 4> Args(FT->param_begin(), FT->param_end());
|
|
|
+ Type *mutatedRetTy = mutateToHandleTy(RetTy);
|
|
|
+ if (!mutateTypesToHandleTy(Args) && RetTy == mutatedRetTy) {
|
|
|
+ ResultTy = Ty;
|
|
|
+ } else {
|
|
|
+ ResultTy = FunctionType::get(mutatedRetTy, Args, FT->isVarArg());
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ ResultTy = Ty;
|
|
|
+ }
|
|
|
+ MutateTypeMap[Ty] = ResultTy;
|
|
|
+ return ResultTy;
|
|
|
+}
|
|
|
+
|
|
|
+bool DxilMutateResourceToHandle::mutateTypesToHandleTy(
|
|
|
+ SmallVector<Type *, 4> &Tys) {
|
|
|
+ bool bMutated = false;
|
|
|
+ for (size_t i = 0; i < Tys.size(); i++) {
|
|
|
+ Type *Ty = Tys[i];
|
|
|
+ Type *mutatedTy = mutateToHandleTy(Ty);
|
|
|
+ if (Ty != mutatedTy) {
|
|
|
+ Tys[i] = mutatedTy;
|
|
|
+ bMutated = true;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ return bMutated;
|
|
|
+}
|
|
|
+
|
|
|
+void DxilMutateResourceToHandle::collectGlobalResource(
|
|
|
+ DxilResourceBase *Res, SmallVector<Value *, 8> &WorkList) {
|
|
|
+ Value *GV = Res->GetGlobalSymbol();
|
|
|
+ // Save hlsl type before mutate to handle.
|
|
|
+ Res->SetHLSLType(GV->getType());
|
|
|
+ mutateToHandleTy(GV->getType());
|
|
|
+ WorkList.emplace_back(GV);
|
|
|
+}
|
|
|
+void DxilMutateResourceToHandle::collectAlloca(
|
|
|
+ Function &F, SmallVector<Value *, 8> &WorkList) {
|
|
|
+ if (F.isDeclaration())
|
|
|
+ return;
|
|
|
+ for (Instruction &I : F.getEntryBlock()) {
|
|
|
+ AllocaInst *AI = dyn_cast<AllocaInst>(&I);
|
|
|
+ if (!AI)
|
|
|
+ continue;
|
|
|
+ Type *Ty = AI->getType();
|
|
|
+ Type *MTy = mutateToHandleTy(Ty);
|
|
|
+ if (Ty == MTy)
|
|
|
+ continue;
|
|
|
+ WorkList.emplace_back(AI);
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+}
|
|
|
+
|
|
|
+SmallVector<Value *, 8>
|
|
|
+DxilMutateResourceToHandle::collectHlslObjects(Module &M) {
|
|
|
+ // Add all global/function/argument/alloca has resource type.
|
|
|
+ SmallVector<Value *, 8> WorkList;
|
|
|
+
|
|
|
+ // Assume this is after SROA so no struct for global/alloca.
|
|
|
+
|
|
|
+ // Functions.
|
|
|
+ for (Function &F : M) {
|
|
|
+ collectAlloca(F, WorkList);
|
|
|
+ FunctionType *FT = F.getFunctionType();
|
|
|
+ FunctionType *MFT = cast<FunctionType>(mutateToHandleTy(FT));
|
|
|
+ if (FT == MFT)
|
|
|
+ continue;
|
|
|
+ WorkList.emplace_back(&F);
|
|
|
+ // Check args.
|
|
|
+ for (Argument &Arg : F.args()) {
|
|
|
+ Type *Ty = Arg.getType();
|
|
|
+ Type *MTy = mutateToHandleTy(Ty);
|
|
|
+ if (Ty == MTy)
|
|
|
+ continue;
|
|
|
+ WorkList.emplace_back(&Arg);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ // Static globals.
|
|
|
+ for (GlobalVariable &GV : M.globals()) {
|
|
|
+ if (!dxilutil::IsStaticGlobal(&GV))
|
|
|
+ continue;
|
|
|
+ Type *Ty = dxilutil::GetArrayEltTy(GV.getValueType());
|
|
|
+ if (!dxilutil::IsHLSLObjectType(Ty))
|
|
|
+ continue;
|
|
|
+ WorkList.emplace_back(&GV);
|
|
|
+ }
|
|
|
+
|
|
|
+ // Global resources.
|
|
|
+ if (M.HasHLModule()) {
|
|
|
+ auto &HLM = M.GetHLModule();
|
|
|
+ for (auto &Res : HLM.GetCBuffers()) {
|
|
|
+ collectGlobalResource(Res.get(), WorkList);
|
|
|
+ }
|
|
|
+ for (auto &Res : HLM.GetSRVs()) {
|
|
|
+ collectGlobalResource(Res.get(), WorkList);
|
|
|
+ }
|
|
|
+ for (auto &Res : HLM.GetUAVs()) {
|
|
|
+ collectGlobalResource(Res.get(), WorkList);
|
|
|
+ }
|
|
|
+ for (auto &Res : HLM.GetSamplers()) {
|
|
|
+ collectGlobalResource(Res.get(), WorkList);
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ auto &DM = M.GetDxilModule();
|
|
|
+ for (auto &Res : DM.GetCBuffers()) {
|
|
|
+ collectGlobalResource(Res.get(), WorkList);
|
|
|
+ }
|
|
|
+ for (auto &Res : DM.GetSRVs()) {
|
|
|
+ collectGlobalResource(Res.get(), WorkList);
|
|
|
+ }
|
|
|
+ for (auto &Res : DM.GetUAVs()) {
|
|
|
+ collectGlobalResource(Res.get(), WorkList);
|
|
|
+ }
|
|
|
+ for (auto &Res : DM.GetSamplers()) {
|
|
|
+ collectGlobalResource(Res.get(), WorkList);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ return WorkList;
|
|
|
+}
|
|
|
+
|
|
|
+void DxilMutateResourceToHandle::collectCandidates(Module &M) {
|
|
|
+ SmallVector<Value *, 8> WorkList = collectHlslObjects(M);
|
|
|
+
|
|
|
+ // Propagate candidates.
|
|
|
+ while (!WorkList.empty()) {
|
|
|
+ Value *V = WorkList.pop_back_val();
|
|
|
+ MutateValSet.insert(V);
|
|
|
+
|
|
|
+ for (User *U : V->users()) {
|
|
|
+ // collect in a user.
|
|
|
+ SmallVector<Value *, 2> newCandidates;
|
|
|
+ // Should only used by ld/st/sel/phi/gep/call.
|
|
|
+ if (LoadInst *LI = dyn_cast<LoadInst>(U)) {
|
|
|
+ newCandidates.emplace_back(LI);
|
|
|
+ } else if (StoreInst *SI = dyn_cast<StoreInst>(U)) {
|
|
|
+ Value *Ptr = SI->getPointerOperand();
|
|
|
+ Value *Val = SI->getValueOperand();
|
|
|
+ if (V == Ptr)
|
|
|
+ newCandidates.emplace_back(Val);
|
|
|
+ else
|
|
|
+ newCandidates.emplace_back(Ptr);
|
|
|
+ } else if (GEPOperator *GEP = dyn_cast<GEPOperator>(U)) {
|
|
|
+ // If result type of GEP not related to resource type, skip.
|
|
|
+ Type *Ty = GEP->getType();
|
|
|
+ Type *MTy = mutateToHandleTy(Ty);
|
|
|
+ if (MTy == Ty)
|
|
|
+ continue;
|
|
|
+ newCandidates.emplace_back(GEP);
|
|
|
+ } else if (PHINode *Phi = dyn_cast<PHINode>(U)) {
|
|
|
+ // Propagate all operands.
|
|
|
+ newCandidates.emplace_back(Phi);
|
|
|
+ for (Use &PhiOp : Phi->incoming_values()) {
|
|
|
+ if (V == PhiOp)
|
|
|
+ continue;
|
|
|
+ newCandidates.emplace_back(PhiOp);
|
|
|
+ }
|
|
|
+ } else if (SelectInst *Sel = dyn_cast<SelectInst>(U)) {
|
|
|
+ // Propagate other result.
|
|
|
+ newCandidates.emplace_back(Sel);
|
|
|
+ Value *TrueV = Sel->getTrueValue();
|
|
|
+ Value *FalseV = Sel->getFalseValue();
|
|
|
+ if (TrueV == V)
|
|
|
+ newCandidates.emplace_back(FalseV);
|
|
|
+ else
|
|
|
+ newCandidates.emplace_back(TrueV);
|
|
|
+ } else if (BitCastOperator *BCO = dyn_cast<BitCastOperator>(U)) {
|
|
|
+ // Make sure only used for lifetime intrinsic.
|
|
|
+ for (User *BCUser : BCO->users()) {
|
|
|
+ if (ConstantArray *CA = dyn_cast<ConstantArray>(BCUser)) {
|
|
|
+ // For llvm.used.
|
|
|
+ if (CA->hasOneUse()) {
|
|
|
+ Value *CAUser = CA->user_back();
|
|
|
+ if (GlobalVariable *GV = dyn_cast<GlobalVariable>(CAUser)) {
|
|
|
+ if (GV->getName() == "llvm.used")
|
|
|
+ continue;
|
|
|
+ }
|
|
|
+ } else if (CA->user_empty()) {
|
|
|
+ continue;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ CallInst *CI = cast<CallInst>(BCUser);
|
|
|
+ Function *F = CI->getCalledFunction();
|
|
|
+ Intrinsic::ID ID = F->getIntrinsicID();
|
|
|
+ if (ID != Intrinsic::lifetime_start &&
|
|
|
+ ID != Intrinsic::lifetime_end) {
|
|
|
+ DXASSERT(false, "unexpected resource object user");
|
|
|
+ }
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ CallInst *CI = cast<CallInst>(U);
|
|
|
+ Type *Ty = CI->getType();
|
|
|
+ Type *MTy = mutateToHandleTy(Ty);
|
|
|
+ if (Ty != MTy)
|
|
|
+ newCandidates.emplace_back(CI);
|
|
|
+
|
|
|
+ SmallVector<Value *, 4> Args(CI->arg_operands().begin(),
|
|
|
+ CI->arg_operands().end());
|
|
|
+ for (Value *Arg : Args) {
|
|
|
+ if (Arg == V)
|
|
|
+ continue;
|
|
|
+ Type *Ty = Arg->getType();
|
|
|
+ Type *MTy = mutateToHandleTy(Ty);
|
|
|
+ if (Ty == MTy)
|
|
|
+ continue;
|
|
|
+ newCandidates.emplace_back(Arg);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ for (Value *Val : newCandidates) {
|
|
|
+ // New candidate find.
|
|
|
+ if (MutateValSet.insert(Val).second) {
|
|
|
+ WorkList.emplace_back(Val);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+void DxilMutateResourceToHandle::mutateCandidates(Module &M) {
|
|
|
+ SmallVector<Function *, 2> CandidateFns;
|
|
|
+ for (Value *V : MutateValSet) {
|
|
|
+ if (Function *F = dyn_cast<Function>(V)) {
|
|
|
+ CandidateFns.emplace_back(F);
|
|
|
+ continue;
|
|
|
+ }
|
|
|
+ Type *Ty = V->getType();
|
|
|
+ V->dump();
|
|
|
+ Type *MTy = mutateToHandleTy(Ty);
|
|
|
+ if (AllocaInst *AI = dyn_cast<AllocaInst>(V)) {
|
|
|
+ AI->setAllocatedType(MTy->getPointerElementType());
|
|
|
+ } else if (GetElementPtrInst *GEP = dyn_cast<GetElementPtrInst>(V)) {
|
|
|
+ Type *MResultEltTy = mutateToHandleTy(GEP->getResultElementType());
|
|
|
+ GEP->setResultElementType(MResultEltTy);
|
|
|
+ Type *MSrcEltTy = mutateToHandleTy(GEP->getSourceElementType());
|
|
|
+ GEP->setSourceElementType(MSrcEltTy);
|
|
|
+ } else if (GEPOperator *GEPO = dyn_cast<GEPOperator>(V)) {
|
|
|
+ // GEP operator not support setSourceElementType.
|
|
|
+ // Create a new GEP here.
|
|
|
+ Constant *C = cast<Constant>(GEPO->getPointerOperand());
|
|
|
+ IRBuilder<> B(C->getContext());
|
|
|
+ // Make sure C is mutated so the GEP get correct sourceElementType.
|
|
|
+ C->mutateType(mutateToHandleTy(C->getType()));
|
|
|
+
|
|
|
+ // Collect user of GEPs, then replace all use with undef.
|
|
|
+ SmallVector<Use *, 2> Uses;
|
|
|
+ for (Use &U : GEPO->uses()) {
|
|
|
+ Uses.emplace_back(&U);
|
|
|
+ }
|
|
|
+
|
|
|
+ SmallVector<Value *, 2> idxList(GEPO->idx_begin(), GEPO->idx_end());
|
|
|
+ Type *Ty = GEPO->getType();
|
|
|
+ GEPO->replaceAllUsesWith(UndefValue::get(Ty));
|
|
|
+ StringRef Name = GEPO->getName();
|
|
|
+
|
|
|
+ // GO and newGO will be same constant except has different
|
|
|
+ // sourceElementType. ConstantMap think they're the same constant. Have to
|
|
|
+ // remove GO first before create newGO.
|
|
|
+ C->removeDeadConstantUsers();
|
|
|
+
|
|
|
+ Value *newGO = B.CreateGEP(C, idxList, Name);
|
|
|
+ // update uses.
|
|
|
+ for (Use *U : Uses) {
|
|
|
+ U->set(newGO);
|
|
|
+ }
|
|
|
+ continue;
|
|
|
+ }
|
|
|
+ V->mutateType(MTy);
|
|
|
+ V->dump();
|
|
|
+ }
|
|
|
+
|
|
|
+ Function *createHandleForLibOnHandle = nullptr;
|
|
|
+ hlsl::OP *hlslOP = nullptr;
|
|
|
+ if (M.HasDxilModule()) {
|
|
|
+ auto &DM = M.GetDxilModule();
|
|
|
+ hlslOP = DM.GetOP();
|
|
|
+ if (hlslOP->IsDxilOpUsed(DXIL::OpCode::CreateHandleForLib)) {
|
|
|
+ createHandleForLibOnHandle =
|
|
|
+ hlslOP->GetOpFunc(DXIL::OpCode::CreateHandleForLib, hdlTy);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ // Mutate functions.
|
|
|
+ for (Function *F : CandidateFns) {
|
|
|
+ Function *MF = nullptr;
|
|
|
+ if (hlslOP) {
|
|
|
+ if (hlslOP->IsDxilOpFunc(F)) {
|
|
|
+ DXIL::OpCodeClass OpcodeClass;
|
|
|
+ if (hlslOP->GetOpCodeClass(F, OpcodeClass)) {
|
|
|
+ if (OpcodeClass == DXIL::OpCodeClass::CreateHandleForLib) {
|
|
|
+ MF = createHandleForLibOnHandle;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ if (!MF) {
|
|
|
+ FunctionType *FT = F->getFunctionType();
|
|
|
+ FunctionType *MFT = cast<FunctionType>(MutateTypeMap[FT]);
|
|
|
+
|
|
|
+ MF = Function::Create(MFT, F->getLinkage(), "", &M);
|
|
|
+ MF->takeName(F);
|
|
|
+
|
|
|
+ // Copy calling conv.
|
|
|
+ MF->setCallingConv(F->getCallingConv());
|
|
|
+ // Copy attributes.
|
|
|
+ AttributeSet AS = F->getAttributes();
|
|
|
+ MF->setAttributes(AS);
|
|
|
+ // Annotation.
|
|
|
+ if (DxilFunctionAnnotation *FnAnnot =
|
|
|
+ pTypeSys->GetFunctionAnnotation(F)) {
|
|
|
+ DxilFunctionAnnotation *newFnAnnot =
|
|
|
+ pTypeSys->AddFunctionAnnotation(MF);
|
|
|
+ DxilParameterAnnotation &RetAnnot = newFnAnnot->GetRetTypeAnnotation();
|
|
|
+ RetAnnot = FnAnnot->GetRetTypeAnnotation();
|
|
|
+ for (unsigned i = 0; i < FnAnnot->GetNumParameters(); i++) {
|
|
|
+ newFnAnnot->GetParameterAnnotation(i) =
|
|
|
+ FnAnnot->GetParameterAnnotation(i);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ // Update function debug info.
|
|
|
+ if (DISubprogram *funcDI = getDISubprogram(F))
|
|
|
+ funcDI->replaceFunction(MF);
|
|
|
+ }
|
|
|
+
|
|
|
+ for (auto it = F->user_begin(); it != F->user_end();) {
|
|
|
+ CallInst *CI = cast<CallInst>(*(it++));
|
|
|
+ CI->setCalledFunction(MF);
|
|
|
+ }
|
|
|
+
|
|
|
+ if (F->isDeclaration()) {
|
|
|
+ F->eraseFromParent();
|
|
|
+ continue;
|
|
|
+ }
|
|
|
+ // Take body of F.
|
|
|
+ // Splice the body of the old function right into the new function.
|
|
|
+ MF->getBasicBlockList().splice(MF->begin(), F->getBasicBlockList());
|
|
|
+ // Replace use of arg.
|
|
|
+ auto argIt = F->arg_begin();
|
|
|
+ for (auto MArgIt = MF->arg_begin(); MArgIt != MF->arg_end();) {
|
|
|
+ Argument *Arg = (argIt++);
|
|
|
+ Argument *MArg = (MArgIt++);
|
|
|
+ Arg->replaceAllUsesWith(MArg);
|
|
|
+ }
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+ModulePass *llvm::createDxilMutateResourceToHandlePass() {
|
|
|
+ return new DxilMutateResourceToHandle();
|
|
|
+}
|
|
|
+
|
|
|
+INITIALIZE_PASS(DxilMutateResourceToHandle,
|
|
|
+ "hlsl-dxil-resources-to-handle",
|
|
|
+ "Mutate resource to handle", false, false)
|