diff --git a/llvm/lib/IR/User.cpp b/llvm/lib/IR/User.cpp --- a/llvm/lib/IR/User.cpp +++ b/llvm/lib/IR/User.cpp @@ -10,6 +10,8 @@ #include "llvm/IR/Constant.h" #include "llvm/IR/GlobalValue.h" +#include "llvm/Support/raw_ostream.h" // + namespace llvm { class BasicBlock; @@ -23,13 +25,16 @@ assert((!isa(this) || isa(this)) && "Cannot call User::replaceUsesOfWith on a constant!"); - for (unsigned i = 0, E = getNumOperands(); i != E; ++i) + for (unsigned i = 0, E = getNumOperands(); i != E; ++i) { + //llvm::errs() << "op " << i << ": " << *getOperand(i) << "\n"; if (getOperand(i) == From) { // Is This operand is pointing to oldval? // The side effects of this setOperand call include linking to // "To", adding "this" to the uses list of To, and // most importantly, removing "this" from the use list of "From". setOperand(i, To); // Fix it now... + //llvm::errs() << __func__ << ": " << *From << " -> " << *To << "\n"; } + } } //===----------------------------------------------------------------------===// diff --git a/llvm/lib/Transforms/Utils/BasicBlockUtils.cpp b/llvm/lib/Transforms/Utils/BasicBlockUtils.cpp --- a/llvm/lib/Transforms/Utils/BasicBlockUtils.cpp +++ b/llvm/lib/Transforms/Utils/BasicBlockUtils.cpp @@ -743,14 +743,23 @@ // Move the edges from Preds to point to NewBB instead of BB. for (unsigned i = 0, e = Preds.size(); i != e; ++i) { + Instruction* T = Preds[i]->getTerminator(); // This is slightly more strict than necessary; the minimum requirement // is that there be no more than one indirectbr branching to BB. And // all BlockAddress uses would need to be updated. - assert(!isa(Preds[i]->getTerminator()) && + assert(!isa(T) && "Cannot split an edge from an IndirectBrInst"); - assert(!isa(Preds[i]->getTerminator()) && - "Cannot split an edge from a CallBrInst"); - Preds[i]->getTerminator()->replaceUsesOfWith(BB, NewBB); + //assert(!isa(Preds[i]->getTerminator()) && + //"Cannot split an edge from a CallBrInst"); + if (auto CBR = dyn_cast(T)) { + for (unsigned j = 0, E = CBR->getIndirectDests().size(); j != E; ++j) + if (CBR->getIndirectDest(j) == NewBB) + CBR->setIndirectDest(j, NewBB); + } else + T->replaceUsesOfWith(BB, NewBB); + llvm::errs() << "XXX: " << *T << "\n"; + DT->print(llvm::errs()); + } // Insert a new PHI node into NewBB for every PHI node in BB and that new PHI diff --git a/llvm/unittests/IR/InstructionsTest.cpp b/llvm/unittests/IR/InstructionsTest.cpp --- a/llvm/unittests/IR/InstructionsTest.cpp +++ b/llvm/unittests/IR/InstructionsTest.cpp @@ -1158,26 +1158,35 @@ FNeg->deleteValue(); } +void VerifyCallBr(const CallBrInst &CBI, const BasicBlock &Expected, const + std::string &F) { + BlockAddress *IndirectBA = BlockAddress::get(CBI.getIndirectDest(0)); + BlockAddress *ArgBA = cast(CBI.getArgOperand(0)); + EXPECT_EQ(IndirectBA, ArgBA) + << "After " << F << ", callbr had an indirect destination of '" + << CBI.getIndirectDest(0)->getName() << "', but a argument of '" + << ArgBA->getBasicBlock()->getName() << "'. These should always match:\n" + << CBI; + EXPECT_EQ(IndirectBA->getBasicBlock(), &Expected); + EXPECT_EQ(ArgBA->getBasicBlock(), &Expected); +} + TEST(InstructionsTest, CallBrInstruction) { LLVMContext Context; std::unique_ptr M = parseIR(Context, R"( define void @foo() { entry: - callbr void asm sideeffect "// XXX: ${0:l}", "X"(i8* blockaddress(@foo, %branch_test.exit)) + callbr void asm sideeffect "", "X"(i8* blockaddress(@foo, %branch_test.exit)) to label %land.rhs.i [label %branch_test.exit] land.rhs.i: br label %branch_test.exit branch_test.exit: - %0 = phi i1 [ true, %entry ], [ false, %land.rhs.i ] - br i1 %0, label %if.end, label %if.then + br label %if.then if.then: ret void - -if.end: - ret void } )"); Function *Foo = M->getFunction("foo"); @@ -1197,16 +1206,11 @@ // Further, test that changing the indirect destination updates the arg // operand to use the block address of the new indirect destination basic // block. This is a critical invariant of CallBrInst. - BlockAddress *IndirectBA = BlockAddress::get(CBI.getIndirectDest(0)); - BlockAddress *ArgBA = cast(CBI.getArgOperand(0)); - EXPECT_EQ(IndirectBA, ArgBA) - << "After setting the indirect destination, callbr had an indirect " - "destination of '" - << CBI.getIndirectDest(0)->getName() << "', but a argument of '" - << ArgBA->getBasicBlock()->getName() << "'. These should always match:\n" - << CBI; - EXPECT_EQ(IndirectBA->getBasicBlock(), &IfThen); - EXPECT_EQ(ArgBA->getBasicBlock(), &IfThen); + VerifyCallBr(CBI, IfThen, "CallBrInst::setIndirectDest()"); + + // Now try changing it back with User::replaceUsesOfWith(). + CBI.replaceUsesOfWith(CBI.getIndirectDest(0), &BranchTestExit); + VerifyCallBr(CBI, BranchTestExit, "User::replaceUsesOfWith()"); } TEST(InstructionsTest, UnaryOperator) {