Index: llvm/lib/CodeGen/CodeGenPrepare.cpp =================================================================== --- llvm/lib/CodeGen/CodeGenPrepare.cpp +++ llvm/lib/CodeGen/CodeGenPrepare.cpp @@ -2097,6 +2097,7 @@ return false; PHINode *PN = nullptr; + ExtractValueInst *EVI = nullptr; BitCastInst *BCI = nullptr; Value *V = RetI->getReturnValue(); if (V) { @@ -2104,6 +2105,14 @@ if (BCI) V = BCI->getOperand(0); + EVI = dyn_cast(V); + if (EVI) { + V = EVI->getOperand(0); + for (auto i = EVI->idx_begin(), e = EVI->idx_end(); i != e; i++) + if (*i != 0) + return false; + } + PN = dyn_cast(V); if (!PN) return false; @@ -2117,7 +2126,9 @@ if (PN) { BasicBlock::iterator BI = BB->begin(); // Skip over debug and the bitcast. - do { ++BI; } while (isa(BI) || &*BI == BCI); + do { + ++BI; + } while (isa(BI) || &*BI == BCI || &*BI == EVI); if (&*BI != RetI) return false; } else { Index: llvm/lib/Transforms/Utils/BasicBlockUtils.cpp =================================================================== --- llvm/lib/Transforms/Utils/BasicBlockUtils.cpp +++ llvm/lib/Transforms/Utils/BasicBlockUtils.cpp @@ -901,9 +901,25 @@ Pred->getInstList().insert(NewRet->getIterator(), NewBC); *i = NewBC; } + + Instruction *NewEV = nullptr; + if (ExtractValueInst *EVI = dyn_cast(V)) { + V = EVI->getOperand(0); + NewEV = EVI->clone(); + if (NewBC) { + NewBC->setOperand(0, NewEV); + Pred->getInstList().insert(NewBC->getIterator(), NewEV); + } else { + Pred->getInstList().insert(NewRet->getIterator(), NewEV); + *i = NewEV; + } + } + if (PHINode *PN = dyn_cast(V)) { if (PN->getParent() == BB) { - if (NewBC) + if (NewEV) { + NewEV->setOperand(0, PN->getIncomingValueForBlock(Pred)); + } else if (NewBC) NewBC->setOperand(0, PN->getIncomingValueForBlock(Pred)); else *i = PN->getIncomingValueForBlock(Pred); Index: llvm/test/CodeGen/X86/tailcall-extract.ll =================================================================== --- /dev/null +++ llvm/test/CodeGen/X86/tailcall-extract.ll @@ -0,0 +1,47 @@ +; RUN: llc -mtriple=x86_64-linux < %s | FileCheck %s +; RUN: opt -codegenprepare -S -mtriple=x86_64-linux < %s | FileCheck %s --check-prefix OPT + +; CHECK-LABEL: test: +; CHECK: jmp bar # TAILCALL +; CHECK: jmp foo # TAILCALL + +; OPT-LABEL: test +; OPT: if.then.i: +; OPT-NEXT: tail call { i8*, i64 } @bar +; OPT-NEXT: extractvalue +; OPT-NEXT: bitcast +; OPT-NEXT: ret +; +; OPT: if.end.i: +; OPT-NEXT: tail call { i8*, i64 } @foo +; OPT-NEXT: extractvalue +; OPT-NEXT: bitcast +; OPT-NEXT: ret + +define i64* @test(i64 %size) { +entry: + %cmp.i.i = icmp ugt i64 %size, 16384 + %add.i.i = add i64 %size, 7 + %div.i.i = lshr i64 %add.i.i, 3 + %phitmp.i.i = trunc i64 %div.i.i to i32 + %cmp1.i = icmp eq i32 %phitmp.i.i, 0 + %cmp.i = or i1 %cmp.i.i, %cmp1.i + br i1 %cmp.i, label %if.end.i, label %if.then.i + +if.then.i: ; preds = %entry + %call1.i = tail call { i8*, i64 } @bar(i64 %size) + br label %exit + +if.end.i: ; preds = %entry + %call2.i = tail call { i8*, i64 } @foo(i64 %size) + br label %exit + +exit: + %call1.i.sink = phi { i8*, i64 } [ %call1.i, %if.then.i ], [ %call2.i, %if.end.i ] + %ev = extractvalue { i8*, i64 } %call1.i.sink, 0 + %result = bitcast i8* %ev to i64* + ret i64* %result +} + +declare { i8*, i64 } @foo(i64) +declare { i8*, i64 } @bar(i64)