Index: llvm/include/llvm/IR/Instruction.h =================================================================== --- llvm/include/llvm/IR/Instruction.h +++ 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 *getAfterDefInsertionPoint(); + //===--------------------------------------------------------------------===// // Subclass classification. //===--------------------------------------------------------------------===// Index: llvm/lib/IR/Instruction.cpp =================================================================== --- llvm/lib/IR/Instruction.cpp +++ llvm/lib/IR/Instruction.cpp @@ -116,6 +116,32 @@ return Order < Other->Order; } +Instruction *Instruction::getAfterDefInsertionPoint() { + 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(); }); } Index: llvm/lib/Transforms/Coroutines/CoroFrame.cpp =================================================================== --- llvm/lib/Transforms/Coroutines/CoroFrame.cpp +++ llvm/lib/Transforms/Coroutines/CoroFrame.cpp @@ -2633,16 +2633,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->getAfterDefInsertionPoint(); + else if (isa(Storage)) + InsertPt = &*F->getEntryBlock().begin(); + if (InsertPt) + DVI->moveBefore(InsertPt); } } Index: llvm/lib/Transforms/InstCombine/InstCombineCalls.cpp =================================================================== --- llvm/lib/Transforms/InstCombine/InstCombineCalls.cpp +++ llvm/lib/Transforms/InstCombine/InstCombineCalls.cpp @@ -3448,18 +3448,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->getAfterDefInsertionPoint(); + assert(InsertPt && "No place to insert cast"); + InsertNewInstBefore(NC, *InsertPt); Worklist.pushUsersToWorkList(*Caller); } else { NV = UndefValue::get(Caller->getType()); Index: llvm/lib/Transforms/InstCombine/InstructionCombining.cpp =================================================================== --- llvm/lib/Transforms/InstCombine/InstructionCombining.cpp +++ llvm/lib/Transforms/InstCombine/InstructionCombining.cpp @@ -3861,16 +3861,10 @@ MoveBefore = &FI.getFunction()->getEntryBlock().front(); while (isa(MoveBefore)) MoveBefore = MoveBefore->getNextNode(); - } else if (auto *PN = dyn_cast(Op)) { - MoveBefore = PN->getParent()->getFirstNonPHI(); - } else if (auto *II = dyn_cast(Op)) { - MoveBefore = II->getNormalDest()->getFirstNonPHI(); - } else if (auto *CB = dyn_cast(Op)) { - MoveBefore = CB->getDefaultDest()->getFirstNonPHI(); } else { - auto *I = cast(Op); - assert(!I->isTerminator() && "Cannot be a terminator"); - MoveBefore = I->getNextNode(); + MoveBefore = cast(Op)->getAfterDefInsertionPoint(); + if (!MoveBefore) + return false; } bool Changed = false; Index: llvm/lib/Transforms/Scalar/Reassociate.cpp =================================================================== --- llvm/lib/Transforms/Scalar/Reassociate.cpp +++ llvm/lib/Transforms/Scalar/Reassociate.cpp @@ -867,40 +867,16 @@ if (TheNeg->getParent()->getParent() != BI->getParent()->getParent()) continue; - bool FoundCatchSwitch = false; - - BasicBlock::iterator InsertPt; + Instruction *InsertPt; if (Instruction *InstInput = dyn_cast(V)) { - if (InvokeInst *II = dyn_cast(InstInput)) { - InsertPt = II->getNormalDest()->begin(); - } else { - InsertPt = ++InstInput->getIterator(); - } - - const BasicBlock *BB = InsertPt->getParent(); - - // Make sure we don't move anything before PHIs or exception - // handling pads. - while (InsertPt != BB->end() && (isa(InsertPt) || - InsertPt->isEHPad())) { - if (isa(InsertPt)) - // A catchswitch cannot have anything in the block except - // itself and PHIs. We'll bail out below. - FoundCatchSwitch = true; - ++InsertPt; - } + InsertPt = InstInput->getAfterDefInsertionPoint(); + if (!InsertPt) + continue; } else { - InsertPt = TheNeg->getParent()->getParent()->getEntryBlock().begin(); + InsertPt = &*TheNeg->getFunction()->getEntryBlock().begin(); } - // We found a catchswitch in the block where we want to move the - // neg. We cannot move anything into that block. Bail and just - // create the neg before BI, as if we hadn't found an existing - // neg. - if (FoundCatchSwitch) - break; - - TheNeg->moveBefore(&*InsertPt); + TheNeg->moveBefore(InsertPt); if (TheNeg->getOpcode() == Instruction::Sub) { TheNeg->setHasNoUnsignedWrap(false); TheNeg->setHasNoSignedWrap(false); Index: llvm/test/Transforms/InstCombine/freeze.ll =================================================================== --- llvm/test/Transforms/InstCombine/freeze.ll +++ llvm/test/Transforms/InstCombine/freeze.ll @@ -233,6 +233,63 @@ ret void } +declare i32 @__CxxFrameHandler3(...) + +define void @freeze_dominated_uses_catchswitch(i1 %c, i32 %x) personality i8* bitcast (i32 (...)* @__CxxFrameHandler3 to i8*) { +; CHECK-LABEL: @freeze_dominated_uses_catchswitch( +; CHECK-NEXT: entry: +; CHECK-NEXT: br i1 [[C:%.*]], label [[IF_THEN:%.*]], label [[IF_ELSE:%.*]] +; CHECK: if.then: +; CHECK-NEXT: invoke void @use_i32(i32 0) +; CHECK-NEXT: to label [[CLEANUP:%.*]] unwind label [[CATCH_DISPATCH:%.*]] +; CHECK: if.else: +; CHECK-NEXT: invoke void @use_i32(i32 1) +; CHECK-NEXT: to label [[CLEANUP]] unwind label [[CATCH_DISPATCH]] +; CHECK: catch.dispatch: +; CHECK-NEXT: [[PHI:%.*]] = phi i32 [ 0, [[IF_THEN]] ], [ [[X:%.*]], [[IF_ELSE]] ] +; CHECK-NEXT: [[CS:%.*]] = catchswitch within none [label [[CATCH:%.*]], label %catch2] unwind to caller +; CHECK: catch: +; CHECK-NEXT: [[CP:%.*]] = catchpad within [[CS]] [i8* null, i32 64, i8* null] +; CHECK-NEXT: [[PHI_FREEZE:%.*]] = freeze i32 [[PHI]] +; CHECK-NEXT: call void @use_i32(i32 [[PHI_FREEZE]]) [ "funclet"(token [[CP]]) ] +; CHECK-NEXT: unreachable +; CHECK: catch2: +; CHECK-NEXT: [[CP2:%.*]] = catchpad within [[CS]] [i8* null, i32 64, i8* null] +; CHECK-NEXT: call void @use_i32(i32 [[PHI]]) [ "funclet"(token [[CP2]]) ] +; CHECK-NEXT: unreachable +; CHECK: cleanup: +; CHECK-NEXT: ret void +; +entry: + br i1 %c, label %if.then, label %if.else + +if.then: + invoke void @use_i32(i32 0) + to label %cleanup unwind label %catch.dispatch + +if.else: + invoke void @use_i32(i32 1) + to label %cleanup unwind label %catch.dispatch + +catch.dispatch: + %phi = phi i32 [ 0, %if.then ], [ %x, %if.else ] + %cs = catchswitch within none [label %catch, label %catch2] unwind to caller + +catch: + %cp = catchpad within %cs [i8* null, i32 64, i8* null] + %phi.freeze = freeze i32 %phi + call void @use_i32(i32 %phi.freeze) [ "funclet"(token %cp) ] + unreachable + +catch2: + %cp2 = catchpad within %cs [i8* null, i32 64, i8* null] + call void @use_i32(i32 %phi) [ "funclet"(token %cp2) ] + unreachable + +cleanup: + ret void +} + declare i32 @get_i32() define i32 @freeze_use_in_different_branches(i1 %c) { Index: llvm/test/Transforms/Reassociate/callbr.ll =================================================================== --- /dev/null +++ llvm/test/Transforms/Reassociate/callbr.ll @@ -0,0 +1,26 @@ +; NOTE: Assertions have been autogenerated by utils/update_test_checks.py +; RUN: opt -S -reassociate < %s | FileCheck %s + +define i32 @test(i1 %b) { +; CHECK-LABEL: @test( +; CHECK-NEXT: [[RES:%.*]] = callbr i32 asm "", "=r,i"(i8* blockaddress(@test, [[ABNORMAL:%.*]])) +; CHECK-NEXT: to label [[NORMAL:%.*]] [label %abnormal] +; CHECK: normal: +; CHECK-NEXT: [[TMP1:%.*]] = sub i32 0, 0 +; CHECK-NEXT: [[FACTOR:%.*]] = mul i32 [[RES]], -2 +; CHECK-NEXT: [[SUB2:%.*]] = add i32 [[FACTOR]], 5 +; CHECK-NEXT: ret i32 [[SUB2]] +; CHECK: abnormal: +; CHECK-NEXT: ret i32 0 +; + %res = callbr i32 asm "", "=r,i"(i8* blockaddress(@test, %abnormal)) + to label %normal [label %abnormal] + +normal: + %sub1 = sub nsw i32 5, %res + %sub2 = sub nsw i32 %sub1, %res + ret i32 %sub2 + +abnormal: + ret i32 0 +}