|
@@ -344,9 +344,137 @@ private:
|
|
|
}
|
|
|
|
|
|
namespace {
|
|
|
+
|
|
|
+void CreateOperandSelect(Instruction *SelInst, Value *EmptyVal,
|
|
|
+ std::unordered_map<Instruction *, Instruction *>
|
|
|
+ &selInstToSelOperandInstMap) {
|
|
|
+ IRBuilder<> Builder(SelInst);
|
|
|
+
|
|
|
+ if (SelectInst *Sel = dyn_cast<SelectInst>(SelInst)) {
|
|
|
+ Instruction *newSel = cast<Instruction>(
|
|
|
+ Builder.CreateSelect(Sel->getCondition(), EmptyVal, EmptyVal));
|
|
|
+
|
|
|
+ selInstToSelOperandInstMap[SelInst] = newSel;
|
|
|
+ } else {
|
|
|
+ PHINode *Phi = cast<PHINode>(SelInst);
|
|
|
+ unsigned numIncoming = Phi->getNumIncomingValues();
|
|
|
+
|
|
|
+ // Don't replace constant int operand.
|
|
|
+ PHINode *newSel = Builder.CreatePHI(EmptyVal->getType(), numIncoming);
|
|
|
+ for (unsigned j = 0; j < numIncoming; j++) {
|
|
|
+ BasicBlock *BB = Phi->getIncomingBlock(j);
|
|
|
+ newSel->addIncoming(EmptyVal, BB);
|
|
|
+ }
|
|
|
+
|
|
|
+ selInstToSelOperandInstMap[SelInst] = newSel;
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+void UpdateOperandSelect(Instruction *SelInst, Instruction *Prototype,
|
|
|
+ unsigned operandIdx,
|
|
|
+ std::unordered_map<Instruction *, Instruction *>
|
|
|
+ &selInstToSelOperandInstMap) {
|
|
|
+ unsigned numOperands = SelInst->getNumOperands();
|
|
|
+
|
|
|
+ unsigned startOpIdx = 0;
|
|
|
+ // Skip Cond for Select.
|
|
|
+ if (SelectInst *Sel = dyn_cast<SelectInst>(SelInst)) {
|
|
|
+ startOpIdx = 1;
|
|
|
+ }
|
|
|
+
|
|
|
+ Instruction *newSel = selInstToSelOperandInstMap[SelInst];
|
|
|
+ // Transform
|
|
|
+ // phi0 = phi a0, b0, c0
|
|
|
+ // phi1 = phi a1, b1, c1
|
|
|
+ // NewInst = Add(phi0, phi1);
|
|
|
+ // into
|
|
|
+ // A = Add(a0, a1);
|
|
|
+ // B = Add(b0, b1);
|
|
|
+ // C = Add(c0, c1);
|
|
|
+ // NewSelInst = phi A, B, C
|
|
|
+ // Only support 1 operand now, other oerands should be Constant.
|
|
|
+
|
|
|
+ // Each operand of newInst is a clone of prototype inst.
|
|
|
+ // Now we set A operands based on operand 0 of phi0 and phi1.
|
|
|
+ for (unsigned i = startOpIdx; i < numOperands; i++) {
|
|
|
+ Instruction *selOp = cast<Instruction>(SelInst->getOperand(i));
|
|
|
+ auto it = selInstToSelOperandInstMap.find(selOp);
|
|
|
+ if (it != selInstToSelOperandInstMap.end()) {
|
|
|
+ // Operand is an select.
|
|
|
+ // Map to new created select inst.
|
|
|
+ Instruction *newSelOp = it->second;
|
|
|
+ newSel->setOperand(i, newSelOp);
|
|
|
+ } else {
|
|
|
+ // The operand is not select.
|
|
|
+ // just use it for prototype operand.
|
|
|
+ // Make sure function is the same.
|
|
|
+ Instruction *op = Prototype->clone();
|
|
|
+ op->setOperand(operandIdx, selOp);
|
|
|
+ if (PHINode *phi = dyn_cast<PHINode>(SelInst)) {
|
|
|
+ BasicBlock *BB = phi->getIncomingBlock(i);
|
|
|
+ IRBuilder<> TmpBuilder(BB->getTerminator());
|
|
|
+ TmpBuilder.Insert(op);
|
|
|
+ } else {
|
|
|
+ IRBuilder<> TmpBuilder(newSel);
|
|
|
+ TmpBuilder.Insert(op);
|
|
|
+ }
|
|
|
+ newSel->setOperand(i, op);
|
|
|
+ }
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
void TranslateHLCreateHandle(Function *F, hlsl::OP &hlslOP) {
|
|
|
Value *opArg = hlslOP.GetU32Const(
|
|
|
(unsigned)DXIL::OpCode::CreateHandleFromResourceStructForLib);
|
|
|
+
|
|
|
+ // Remove PhiNode createHandle first.
|
|
|
+ std::vector<Instruction *> resSelects;
|
|
|
+ std::unordered_set<llvm::Instruction *> selectSet;
|
|
|
+ for (auto U = F->user_begin(); U != F->user_end();) {
|
|
|
+ Value *user = *(U++);
|
|
|
+ if (!isa<Instruction>(user))
|
|
|
+ continue;
|
|
|
+ // must be call inst
|
|
|
+ CallInst *CI = cast<CallInst>(user);
|
|
|
+ Value *res = CI->getArgOperand(HLOperandIndex::kUnaryOpSrc0Idx);
|
|
|
+ if (isa<SelectInst>(res) || isa<PHINode>(res))
|
|
|
+ dxilutil::CollectSelect(cast<Instruction>(res), selectSet);
|
|
|
+ }
|
|
|
+
|
|
|
+ if (!selectSet.empty()) {
|
|
|
+ FunctionType *FT = F->getFunctionType();
|
|
|
+ Type *ResTy = FT->getParamType(HLOperandIndex::kUnaryOpSrc0Idx);
|
|
|
+
|
|
|
+ Value *UndefHandle = UndefValue::get(F->getReturnType());
|
|
|
+ std::unordered_map<Instruction *, Instruction *> handleMap;
|
|
|
+ for (Instruction *SelInst : selectSet) {
|
|
|
+ CreateOperandSelect(SelInst, UndefHandle, handleMap);
|
|
|
+ }
|
|
|
+
|
|
|
+ Value *UndefRes = UndefValue::get(ResTy);
|
|
|
+ std::unique_ptr<CallInst> PrototypeCall(
|
|
|
+ CallInst::Create(F, {opArg, UndefRes}));
|
|
|
+
|
|
|
+ for (Instruction *SelInst : selectSet) {
|
|
|
+ UpdateOperandSelect(SelInst, PrototypeCall.get(),
|
|
|
+ HLOperandIndex::kUnaryOpSrc0Idx, handleMap);
|
|
|
+ }
|
|
|
+
|
|
|
+ // Replace createHandle on select with select on createHandle.
|
|
|
+ for (Instruction *SelInst : selectSet) {
|
|
|
+ Value *NewSel = handleMap[SelInst];
|
|
|
+ for (auto U = SelInst->user_begin(); U != SelInst->user_end();) {
|
|
|
+ Value *user = *(U++);
|
|
|
+ if (CallInst *CI = dyn_cast<CallInst>(user)) {
|
|
|
+ if (CI->getCalledFunction() == F) {
|
|
|
+ CI->replaceAllUsesWith(NewSel);
|
|
|
+ CI->eraseFromParent();
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
for (auto U = F->user_begin(); U != F->user_end();) {
|
|
|
Value *user = *(U++);
|
|
|
if (!isa<Instruction>(user))
|
|
@@ -356,21 +484,18 @@ void TranslateHLCreateHandle(Function *F, hlsl::OP &hlslOP) {
|
|
|
Value *res = CI->getArgOperand(HLOperandIndex::kUnaryOpSrc0Idx);
|
|
|
Value *newHandle = nullptr;
|
|
|
IRBuilder<> Builder(CI);
|
|
|
- if (LoadInst *LI = dyn_cast<LoadInst>(res)) {
|
|
|
- Function *createHandle =
|
|
|
- hlslOP.GetOpFunc(DXIL::OpCode::CreateHandleFromResourceStructForLib,
|
|
|
- LI->getType());
|
|
|
- newHandle = Builder.CreateCall(createHandle, {opArg, LI});
|
|
|
- } else {
|
|
|
- Function *createHandle =
|
|
|
- hlslOP.GetOpFunc(DXIL::OpCode::CreateHandleFromResourceStructForLib,
|
|
|
- res->getType());
|
|
|
- CallInst *newHandleCI = Builder.CreateCall(createHandle, {opArg, res});
|
|
|
- // Change select/phi on operands into select/phi on operation.
|
|
|
- newHandle =
|
|
|
- dxilutil::SelectOnOperation(newHandleCI, HLOperandIndex::kUnaryOpSrc0Idx);
|
|
|
- }
|
|
|
+ // Must be load.
|
|
|
+ LoadInst *LI = cast<LoadInst>(res);
|
|
|
+ Function *createHandle = hlslOP.GetOpFunc(
|
|
|
+ DXIL::OpCode::CreateHandleFromResourceStructForLib, LI->getType());
|
|
|
+ newHandle = Builder.CreateCall(createHandle, {opArg, LI});
|
|
|
+
|
|
|
CI->replaceAllUsesWith(newHandle);
|
|
|
+ if (res->user_empty()) {
|
|
|
+ if (Instruction *I = dyn_cast<Instruction>(res))
|
|
|
+ I->eraseFromParent();
|
|
|
+ }
|
|
|
+
|
|
|
CI->eraseFromParent();
|
|
|
}
|
|
|
}
|