Index: include/llvm/IR/InstrTypes.h =================================================================== --- include/llvm/IR/InstrTypes.h +++ include/llvm/IR/InstrTypes.h @@ -1416,6 +1416,16 @@ return None; } + /// \brief Return true if this instruction has operand bundles with a tag + /// different from \p ID. + bool hasOperandBundleOtherThan(uint32_t ID) const { + for (unsigned i = 0, e = getNumOperandBundles(); i != e; ++i) + if (getOperandBundleAt(i).getTagID() != ID) + return false; + + return true; + } + /// \brief Return the list of operand bundles attached to this instruction as /// a vector of OperandBundleDefs. /// Index: lib/Transforms/Scalar/TailRecursionElimination.cpp =================================================================== --- lib/Transforms/Scalar/TailRecursionElimination.cpp +++ lib/Transforms/Scalar/TailRecursionElimination.cpp @@ -236,7 +236,8 @@ if (!CI || CI->isTailCall()) continue; - bool IsNoTail = CI->isNoTailCall(); + bool IsNoTail = CI->isNoTailCall() || + CI->hasOperandBundlesOtherThan(LLVMContext::OB_funclet); if (!IsNoTail && CI->doesNotAccessMemory()) { // A call to a readnone function whose arguments are all things computed @@ -256,6 +257,7 @@ SafeToTail = false; break; } + SafeToTail &= CI->hasOperandBundlesOtherThan(LLVMContext::OB_funclet); if (SafeToTail) { emitOptimizationRemark( F.getContext(), "tailcallelim", F, CI->getDebugLoc(), Index: test/Transforms/TailCallElim/operand-bundles.ll =================================================================== --- /dev/null +++ test/Transforms/TailCallElim/operand-bundles.ll @@ -0,0 +1,58 @@ +; RUN: opt < %s -tailcallelim -S | FileCheck %s + +define i32 @f_1(i32 %x) { +; CHECK-LABEL: @f_1( +wentry: + %cond = icmp ugt i32 %x, 0 + br i1 %cond, label %return, label %body + +body: +; CHECK: body: +; CHECK: call i32 @f_1(i32 %y) [ "deopt"() ] + %y = add i32 %x, 1 + %tmp = call i32 @f_1(i32 %y) [ "deopt"() ] + ret i32 0 + +return: + ret i32 1 +} + +define i32 @f_2(i32 %x) { +; CHECK-LABEL: @f_2 + +entry: + %cond = icmp ugt i32 %x, 0 + br i1 %cond, label %return, label %body + +body: +; CHECK: body: +; CHECK: call i32 @f_2(i32 %y) [ "unknown"() ] + %y = add i32 %x, 1 + %tmp = call i32 @f_2(i32 %y) [ "unknown"() ] + ret i32 0 + +return: + ret i32 1 +} + +declare void @func() + +define void @f_3(i1 %B) personality i8 42 { +; CHECK-LABEL: @f_3( +entry: + invoke void @func() + to label %exit unwind label %merge +merge: + %cs1 = catchswitch within none [label %catch] unwind to caller + +catch: +; CHECK: catch: +; CHECK-NOT: call +; CHECK: br + %cp = catchpad within %cs1 [] + call void @f_3(i1 %B) [ "funclet"(token %cp) ] + ret void + +exit: + ret void +}