Change callbr to only define its output SSA variable on the normal

path, not the indirect targets.

Fixes: PR45565.

Differential Revision: https://reviews.llvm.org/D78341
This commit is contained in:
James Y Knight 2020-04-16 22:14:21 -04:00
parent 48e9ef4320
commit 248a5db3f2
6 changed files with 58 additions and 7 deletions

View File

@ -7366,9 +7366,8 @@ instruction in most regards. The primary difference is that it
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 <poisonvalues>`.
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

View File

@ -222,7 +222,7 @@ static bool valueDominatesPHI(Value *V, PHINode *P, const DominatorTree *DT) {
// 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<InvokeInst>(I))
!isa<InvokeInst>(I) && !isa<CallBrInst>(I))
return true;
return false;

View File

@ -4641,7 +4641,7 @@ bool llvm::canCreatePoison(const Instruction *I) {
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: {

View File

@ -134,7 +134,7 @@ bool DominatorTree::dominates(const Instruction *Def,
// dominates every instruction in UseBB.
// A PHI is dominated only if the instruction dominates every possible use in
// the UseBB.
if (isa<InvokeInst>(Def) || isa<PHINode>(User))
if (isa<InvokeInst>(Def) || isa<CallBrInst>(Def) || isa<PHINode>(User))
return dominates(Def, UseBB);
if (DefBB != UseBB)
@ -168,6 +168,13 @@ bool DominatorTree::dominates(const Instruction *Def,
return dominates(E, UseBB);
}
// Callbr results are similarly only usable in the default destination.
if (const auto *CBI = dyn_cast<CallBrInst>(Def)) {
BasicBlock *NormalDest = CBI->getDefaultDest();
BasicBlockEdge E(DefBB, NormalDest);
return dominates(E, UseBB);
}
return dominates(DefBB, UseBB);
}
@ -273,6 +280,13 @@ bool DominatorTree::dominates(const Instruction *Def, const Use &U) const {
return dominates(E, U);
}
// Callbr results are similarly only usable in the default destination.
if (const auto *CBI = dyn_cast<CallBrInst>(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::verifyAnalysis() const {
void DominatorTreeWrapperPass::print(raw_ostream &OS, const Module *) const {
DT.print(OS);
}

View File

@ -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
}

View File

@ -68,3 +68,16 @@ next:
; 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
}