/// * Non-instruction Defs dominate everything.
/// * Def does not dominate a use in Def itself (outside of degenerate cases
/// like unreachable code or trivial phi cycles).
- /// * Invoke/callbr Defs only dominate uses in their default destination.
+ /// * Invoke Defs only dominate uses in their default destination.
bool dominates(const Value *Def, const Use &U) const;
/// Return true if value Def dominates all possible uses inside instruction
/// User. Same comments as for the Use-based API apply.
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);
}
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)
InsertBB = II->getNormalDest();
InsertPt = InsertBB->getFirstInsertionPt();
} else if (auto *CB = dyn_cast<CallBrInst>(this)) {
- InsertBB = CB->getDefaultDest();
- InsertPt = InsertBB->getFirstInsertionPt();
+ // Def is available in multiple successors, there's no single dominating
+ // insertion point.
+ return nullptr;
} else {
assert(!isTerminator() && "Only invoke/callbr terminators return value");
InsertBB = getParent();
}
/// If the callee is a constexpr cast of a function, attempt to move the cast to
-/// the arguments of the call/callbr/invoke.
+/// the arguments of the call/invoke.
+/// CallBrInst is not supported.
bool InstCombinerImpl::transformConstExprCastCall(CallBase &Call) {
auto *Callee =
dyn_cast<Function>(Call.getCalledOperand()->stripPointerCasts());
if (!Callee)
return false;
+ assert(!isa<CallBrInst>(Call) &&
+ "CallBr's don't have a single point after a def to insert at");
+
// If this is a call to a thunk function, don't remove the cast. Thunks are
// used to transparently forward all incoming parameters and outgoing return
// values, so it's important to leave the cast in place.
return false; // Attribute not compatible with transformed value.
}
- // If the callbase is an invoke/callbr instruction, and the return value is
+ // If the callbase is an invoke instruction, and the return value is
// used by a PHI node in a successor, we cannot change the return type of
// the call because there is no place to put the cast instruction (without
// breaking the critical edge). Bail out in this case.
BasicBlock *PhisNotSupportedBlock = nullptr;
if (auto *II = dyn_cast<InvokeInst>(Caller))
PhisNotSupportedBlock = II->getNormalDest();
- if (auto *CB = dyn_cast<CallBrInst>(Caller))
- PhisNotSupportedBlock = CB->getDefaultDest();
if (PhisNotSupportedBlock)
for (User *U : Caller->users())
if (PHINode *PN = dyn_cast<PHINode>(U))
if (InvokeInst *II = dyn_cast<InvokeInst>(Caller)) {
NewCall = Builder.CreateInvoke(Callee, II->getNormalDest(),
II->getUnwindDest(), Args, OpBundles);
- } else if (CallBrInst *CBI = dyn_cast<CallBrInst>(Caller)) {
- NewCall = Builder.CreateCallBr(Callee, CBI->getDefaultDest(),
- CBI->getIndirectDests(), Args, OpBundles);
} else {
NewCall = Builder.CreateCall(Callee, Args, OpBundles);
cast<CallInst>(NewCall)->setTailCallKind(
; CHECK: %[[CALLBR_RES:.+]] = callbr i32 asm
; CHECK-NEXT: to label %[[DEFAULT_DEST:.+]] [label
; CHECK: [[DEFAULT_DEST]]:
-; CHECK-NEXT: call void @llvm.dbg.declare(metadata i32 %[[CALLBR_RES]]
+; CHECK-NOT: {{.*}}:
+; CHECK: call void @llvm.dbg.declare(metadata i32 %[[CALLBR_RES]]
; CHECK: define internal fastcc void @f.destroy(%f.Frame* noundef nonnull align 8 dereferenceable(40) %FramePtr) #0 personality i32 0 !dbg ![[DESTROY:[0-9]+]]
; CHECK: define internal fastcc void @f.cleanup(%f.Frame* noundef nonnull align 8 dereferenceable(40) %FramePtr) #0 personality i32 0 !dbg ![[CLEANUP:[0-9]+]]
; CHECK-NEXT: to label [[CALLBR_CONT:%.*]] []
; CHECK: callbr.cont:
; CHECK-NEXT: [[PHI:%.*]] = phi i32 [ [[X]], [[ENTRY:%.*]] ], [ 0, [[CALLBR_CONT]] ]
+; CHECK-NEXT: call void @use_i32(i32 [[X]])
; CHECK-NEXT: [[FR:%.*]] = freeze i32 [[X]]
; CHECK-NEXT: call void @use_i32(i32 [[FR]])
-; CHECK-NEXT: call void @use_i32(i32 [[FR]])
; CHECK-NEXT: call void @use_i32(i32 [[PHI]])
; CHECK-NEXT: br label [[CALLBR_CONT]]
;
; CHECK-NEXT: [[RES:%.*]] = callbr i32 asm "", "=r,!i"()
; CHECK-NEXT: to label [[NORMAL:%.*]] [label %abnormal]
; CHECK: normal:
-; CHECK-NEXT: [[FACTOR:%.*]] = mul i32 [[RES]], -2
-; CHECK-NEXT: [[SUB2:%.*]] = add i32 [[FACTOR]], 5
+; CHECK-NEXT: [[RES_NEG:%.*]] = sub i32 0, [[RES]]
+; CHECK-NEXT: [[SUB1:%.*]] = add i32 [[RES_NEG]], 5
+; CHECK-NEXT: [[RES_NEG1:%.*]] = sub i32 0, [[RES]]
+; CHECK-NEXT: [[SUB2:%.*]] = add i32 [[SUB1]], [[RES_NEG1]]
; CHECK-NEXT: ret i32 [[SUB2]]
; CHECK: abnormal:
; CHECK-NEXT: ret i32 0
ret void
}
-;; Ensure you cannot use the return value of a callbr in indirect targets.
-; CHECK: Instruction does not dominate all uses!
-; CHECK-NEXT: #test4
+;; Ensure you can use the return value of a callbr in indirect targets.
+;; No issue!
define i32 @test4(i1 %var) {
entry:
%ret = callbr i32 asm sideeffect "#test4", "=r,!i"() to label %normal [label %abnormal]
; CHECK-NEXT: %x = phi i32 [ %y, %entry ]
}
+;; No issue!
define i32 @f6(i32 %x) {
bb0:
%y1 = callbr i32 asm "", "=r,!i"() to label %bb1 [label %bb2]
ret i32 0
bb2:
ret i32 %y1
-; CHECK: Instruction does not dominate all uses!
-; CHECK-NEXT: %y1 = callbr i32 asm "", "=r,!i"()
-; CHECK-NEXT: to label %bb1 [label %bb2]
-; CHECK-NEXT: ret i32 %y1
}
EXPECT_TRUE(DT->dominates(C, U));
});
}
+TEST(DominatorTree, CallBrDomination) {
+ StringRef ModuleString = R"(
+define void @x() {
+ %y = alloca i32
+ %w = callbr i32 asm "", "=r,!i"()
+ to label %asm.fallthrough [label %z]
+
+asm.fallthrough:
+ br label %cleanup
+
+z:
+ store i32 %w, ptr %y
+ br label %cleanup
+
+cleanup:
+ ret void
+})";
+
+ LLVMContext Context;
+ std::unique_ptr<Module> M = makeLLVMModule(Context, ModuleString);
+
+ runWithDomTree(
+ *M, "x", [&](Function &F, DominatorTree *DT, PostDominatorTree *PDT) {
+ Function::iterator FI = F.begin();
+
+ BasicBlock *Entry = &*FI++;
+ BasicBlock *ASMFallthrough = &*FI++;
+ BasicBlock *Z = &*FI++;
+
+ EXPECT_TRUE(DT->dominates(Entry, ASMFallthrough));
+ EXPECT_TRUE(DT->dominates(Entry, Z));
+
+ BasicBlock::iterator BBI = Entry->begin();
+ ++BBI;
+ Instruction &I = *BBI;
+ EXPECT_TRUE(isa<CallBrInst>(I));
+ EXPECT_TRUE(isa<Value>(I));
+ for (const User *U : I.users()) {
+ EXPECT_TRUE(isa<Instruction>(U));
+ EXPECT_TRUE(DT->dominates(cast<Value>(&I), cast<Instruction>(U)));
+ }
+ });
+}