diff --git a/llvm/include/llvm/IR/Instruction.h b/llvm/include/llvm/IR/Instruction.h --- a/llvm/include/llvm/IR/Instruction.h +++ b/llvm/include/llvm/IR/Instruction.h @@ -149,6 +149,13 @@ /// it takes constant time. bool comesBefore(const Instruction *Other) const; + /// Get the first insertion point at which the result of this instruction + /// is defined. This is *not* the directly following instruction in a number + /// of cases, e.g. phi nodes or terminators that return values. This function + /// may return null if the insertion after the definition is not possible, + /// e.g. due to a catchswitch terminator. + Instruction *getInsertionPointAfterDef(); + //===--------------------------------------------------------------------===// // Subclass classification. //===--------------------------------------------------------------------===// diff --git a/llvm/lib/IR/Instruction.cpp b/llvm/lib/IR/Instruction.cpp --- a/llvm/lib/IR/Instruction.cpp +++ b/llvm/lib/IR/Instruction.cpp @@ -116,6 +116,32 @@ return Order < Other->Order; } +Instruction *Instruction::getInsertionPointAfterDef() { + assert(!getType()->isVoidTy() && "Instruction must define result"); + BasicBlock *InsertBB; + BasicBlock::iterator InsertPt; + if (auto *PN = dyn_cast(this)) { + InsertBB = PN->getParent(); + InsertPt = InsertBB->getFirstInsertionPt(); + } else if (auto *II = dyn_cast(this)) { + InsertBB = II->getNormalDest(); + InsertPt = InsertBB->getFirstInsertionPt(); + } else if (auto *CB = dyn_cast(this)) { + InsertBB = CB->getDefaultDest(); + InsertPt = InsertBB->getFirstInsertionPt(); + } else { + assert(!isTerminator() && "Only invoke/callbr terminators return value"); + InsertBB = getParent(); + InsertPt = std::next(getIterator()); + } + + // catchswitch blocks don't have any legal insertion point (because they + // are both an exception pad and a terminator). + if (InsertPt == InsertBB->end()) + return nullptr; + return &*InsertPt; +} + bool Instruction::isOnlyUserOfAnyOperand() { return any_of(operands(), [](Value *V) { return V->hasOneUser(); }); } diff --git a/llvm/lib/Transforms/Coroutines/CoroFrame.cpp b/llvm/lib/Transforms/Coroutines/CoroFrame.cpp --- a/llvm/lib/Transforms/Coroutines/CoroFrame.cpp +++ b/llvm/lib/Transforms/Coroutines/CoroFrame.cpp @@ -2640,16 +2640,13 @@ // dbg.value or dbg.addr since they do not have the same function wide // guarantees that dbg.declare does. if (!isa(DVI) && !isa(DVI)) { - if (auto *II = dyn_cast(Storage)) - DVI->moveBefore(II->getNormalDest()->getFirstNonPHI()); - else if (auto *CBI = dyn_cast(Storage)) - DVI->moveBefore(CBI->getDefaultDest()->getFirstNonPHI()); - else if (auto *InsertPt = dyn_cast(Storage)) { - assert(!InsertPt->isTerminator() && - "Unimaged terminator that could return a storage."); - DVI->moveAfter(InsertPt); - } else if (isa(Storage)) - DVI->moveAfter(F->getEntryBlock().getFirstNonPHI()); + Instruction *InsertPt = nullptr; + if (auto *I = dyn_cast(Storage)) + InsertPt = I->getInsertionPointAfterDef(); + else if (isa(Storage)) + InsertPt = &*F->getEntryBlock().begin(); + if (InsertPt) + DVI->moveBefore(InsertPt); } } diff --git a/llvm/lib/Transforms/InstCombine/InstCombineCalls.cpp b/llvm/lib/Transforms/InstCombine/InstCombineCalls.cpp --- a/llvm/lib/Transforms/InstCombine/InstCombineCalls.cpp +++ b/llvm/lib/Transforms/InstCombine/InstCombineCalls.cpp @@ -3495,18 +3495,9 @@ NV = NC = CastInst::CreateBitOrPointerCast(NC, OldRetTy); NC->setDebugLoc(Caller->getDebugLoc()); - // If this is an invoke/callbr instruction, we should insert it after the - // first non-phi instruction in the normal successor block. - if (InvokeInst *II = dyn_cast(Caller)) { - BasicBlock::iterator I = II->getNormalDest()->getFirstInsertionPt(); - InsertNewInstBefore(NC, *I); - } else if (CallBrInst *CBI = dyn_cast(Caller)) { - BasicBlock::iterator I = CBI->getDefaultDest()->getFirstInsertionPt(); - InsertNewInstBefore(NC, *I); - } else { - // Otherwise, it's a call, just insert cast right after the call. - InsertNewInstBefore(NC, *Caller); - } + Instruction *InsertPt = NewCall->getInsertionPointAfterDef(); + assert(InsertPt && "No place to insert cast"); + InsertNewInstBefore(NC, *InsertPt); Worklist.pushUsersToWorkList(*Caller); } else { NV = PoisonValue::get(Caller->getType());