diff --git a/llvm/docs/LangRef.rst b/llvm/docs/LangRef.rst --- a/llvm/docs/LangRef.rst +++ b/llvm/docs/LangRef.rst @@ -7366,9 +7366,8 @@ establishes an association with additional labels to define where control flow goes after the call. -Outputs of a '``callbr``' instruction are valid only on the '``fallthrough``' -path. Use of outputs on the '``indirect``' path(s) results in :ref:`poison -values `. +The output values of a '``callbr``' instruction are available only to +the '``fallthrough``' block, not to any '``indirect``' blocks(s). The only use of this today is to implement the "goto" feature of gcc inline assembly where additional labels can be provided as locations for the inline diff --git a/llvm/lib/Analysis/InstructionSimplify.cpp b/llvm/lib/Analysis/InstructionSimplify.cpp --- a/llvm/lib/Analysis/InstructionSimplify.cpp +++ b/llvm/lib/Analysis/InstructionSimplify.cpp @@ -222,7 +222,7 @@ // Otherwise, if the instruction is in the entry block and is not an invoke, // then it obviously dominates all phi nodes. if (I->getParent() == &I->getFunction()->getEntryBlock() && - !isa(I)) + !isa(I) && !isa(I)) return true; return false; diff --git a/llvm/lib/Analysis/ValueTracking.cpp b/llvm/lib/Analysis/ValueTracking.cpp --- a/llvm/lib/Analysis/ValueTracking.cpp +++ b/llvm/lib/Analysis/ValueTracking.cpp @@ -4642,7 +4642,7 @@ case Instruction::CallBr: case Instruction::Invoke: // Function calls can return a poison value even if args are non-poison - // values. CallBr returns poison when jumping to indirect labels. + // values. return true; case Instruction::InsertElement: case Instruction::ExtractElement: { diff --git a/llvm/lib/IR/Dominators.cpp b/llvm/lib/IR/Dominators.cpp --- a/llvm/lib/IR/Dominators.cpp +++ b/llvm/lib/IR/Dominators.cpp @@ -134,7 +134,7 @@ // dominates every instruction in UseBB. // A PHI is dominated only if the instruction dominates every possible use in // the UseBB. - if (isa(Def) || isa(User)) + if (isa(Def) || isa(Def) || isa(User)) return dominates(Def, UseBB); if (DefBB != UseBB) @@ -168,6 +168,13 @@ return dominates(E, UseBB); } + // Callbr results are similarly only usable in the default destination. + if (const auto *CBI = dyn_cast(Def)) { + BasicBlock *NormalDest = CBI->getDefaultDest(); + BasicBlockEdge E(DefBB, NormalDest); + return dominates(E, UseBB); + } + return dominates(DefBB, UseBB); } @@ -273,6 +280,13 @@ return dominates(E, U); } + // Callbr results are similarly only usable in the default destination. + if (const auto *CBI = dyn_cast(Def)) { + BasicBlock *NormalDest = CBI->getDefaultDest(); + BasicBlockEdge E(DefBB, NormalDest); + return dominates(E, U); + } + // If the def and use are in different blocks, do a simple CFG dominator // tree query. if (DefBB != UseBB) @@ -371,4 +385,3 @@ void DominatorTreeWrapperPass::print(raw_ostream &OS, const Module *) const { DT.print(OS); } - diff --git a/llvm/test/CodeGen/X86/callbr-codegenprepare.ll b/llvm/test/CodeGen/X86/callbr-codegenprepare.ll new file mode 100644 --- /dev/null +++ b/llvm/test/CodeGen/X86/callbr-codegenprepare.ll @@ -0,0 +1,26 @@ +;; RUN: opt -S -codegenprepare < %s | FileCheck %s + +;; Ensure that codegenprepare (via InstSimplify) doesn't eliminate the +;; phi here (which would cause a module verification error). + +;; CHECK: phi + +target datalayout = "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128" +target triple = "x86_64-unknown-linux-gnu" + +declare void @foo(i32) + +define dso_local i32 @futex_lock_pi_atomic() local_unnamed_addr { +entry: + %0 = callbr i32 asm "", "=r,X,~{dirflag},~{fpsr},~{flags}"(i8* blockaddress(@futex_lock_pi_atomic, %b.exit)) + to label %asm.fallthrough.i [label %b.exit] + +asm.fallthrough.i: + br label %b.exit + +b.exit: + %g.0 = phi i32 [ %0, %asm.fallthrough.i ], [ undef, %entry ] + tail call void @foo(i32 %g.0) + ret i32 undef +} + diff --git a/llvm/test/Verifier/dominates.ll b/llvm/test/Verifier/dominates.ll --- a/llvm/test/Verifier/dominates.ll +++ b/llvm/test/Verifier/dominates.ll @@ -68,3 +68,16 @@ ; CHECK-NEXT: %y = phi i32 [ 0, %entry ] ; CHECK-NEXT: %x = phi i32 [ %y, %entry ] } + +define i32 @f6(i32 %x) { +bb0: + %y1 = callbr i32 asm "", "=r"() to label %bb1 [label %bb2] +bb1: + ret i32 0 +bb2: + ret i32 %y1 +; CHECK: Instruction does not dominate all uses! +; CHECK-NEXT: %y1 = callbr i32 asm "", "=r"() +; CHECK-NEXT: to label %bb1 [label %bb2] +; CHECK-NEXT: ret i32 %y1 +}