Skip to content

Commit 9523a1c

Browse files
committed
Merging r371262:
------------------------------------------------------------------------ r371262 | nickdesaulniers | 2019-09-06 23:50:11 +0200 (Fri, 06 Sep 2019) | 45 lines [IR] CallBrInst: scan+update arg list when indirect dest list changes Summary: There's an unspoken invariant of callbr that the list of BlockAddress Constants in the "function args" list match the BasicBlocks in the "other labels" list. (This invariant is being added to the LangRef in https://reviews.llvm.org/D67196). When modifying the any of the indirect destinations of a callbr instruction (possible jump targets), we need to update the function arguments if the argument is a BlockAddress whose BasicBlock refers to the indirect destination BasicBlock being replaced. Otherwise, many transforms that modify successors will end up violating that invariant. A recent change to the arm64 Linux kernel exposed this bug, which prevents the kernel from booting. I considered maintaining a mapping from indirect destination BasicBlock to argument operand BlockAddress, but this ends up being a one to potentially many (though usually one) mapping. Also, the list of arguments to a function (or more typically inline assembly) ends up being less than 10. The implementation is significantly simpler to just rescan the full list of arguments. Because of the one to potentially many relationship, the full arg list must be scanned (we can't stop at the first instance). Thanks to the following folks that reported the issue and helped debug it: * Nathan Chancellor * Will Deacon * Andrew Murray * Craig Topper Link: https://bugs.llvm.org/show_bug.cgi?id=43222 Link: ClangBuiltLinux/linux#649 Link: https://lists.infradead.org/pipermail/linux-arm-kernel/2019-September/678330.html Reviewers: craig.topper, chandlerc Reviewed By: craig.topper Subscribers: void, javed.absar, kristof.beyls, hiraditya, llvm-commits, nathanchance, srhines Tags: #llvm Differential Revision: https://reviews.llvm.org/D67252 ------------------------------------------------------------------------ llvm-svn: 371376
1 parent 7b927f7 commit 9523a1c

File tree

3 files changed

+70
-5
lines changed

3 files changed

+70
-5
lines changed

llvm/include/llvm/IR/Instructions.h

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3938,6 +3938,9 @@ class CallBrInst : public CallBase {
39383938
ArrayRef<BasicBlock *> IndirectDests, ArrayRef<Value *> Args,
39393939
ArrayRef<OperandBundleDef> Bundles, const Twine &NameStr);
39403940

3941+
/// Should the Indirect Destinations change, scan + update the Arg list.
3942+
void updateArgBlockAddresses(unsigned i, BasicBlock *B);
3943+
39413944
/// Compute the number of operands to allocate.
39423945
static int ComputeNumOperands(int NumArgs, int NumIndirectDests,
39433946
int NumBundleInputs = 0) {
@@ -4075,7 +4078,7 @@ class CallBrInst : public CallBase {
40754078
return cast<BasicBlock>(*(&Op<-1>() - getNumIndirectDests() - 1));
40764079
}
40774080
BasicBlock *getIndirectDest(unsigned i) const {
4078-
return cast<BasicBlock>(*(&Op<-1>() - getNumIndirectDests() + i));
4081+
return cast_or_null<BasicBlock>(*(&Op<-1>() - getNumIndirectDests() + i));
40794082
}
40804083
SmallVector<BasicBlock *, 16> getIndirectDests() const {
40814084
SmallVector<BasicBlock *, 16> IndirectDests;
@@ -4087,6 +4090,7 @@ class CallBrInst : public CallBase {
40874090
*(&Op<-1>() - getNumIndirectDests() - 1) = reinterpret_cast<Value *>(B);
40884091
}
40894092
void setIndirectDest(unsigned i, BasicBlock *B) {
4093+
updateArgBlockAddresses(i, B);
40904094
*(&Op<-1>() - getNumIndirectDests() + i) = reinterpret_cast<Value *>(B);
40914095
}
40924096

@@ -4096,11 +4100,10 @@ class CallBrInst : public CallBase {
40964100
return i == 0 ? getDefaultDest() : getIndirectDest(i - 1);
40974101
}
40984102

4099-
void setSuccessor(unsigned idx, BasicBlock *NewSucc) {
4100-
assert(idx < getNumIndirectDests() + 1 &&
4103+
void setSuccessor(unsigned i, BasicBlock *NewSucc) {
4104+
assert(i < getNumIndirectDests() + 1 &&
41014105
"Successor # out of range for callbr!");
4102-
*(&Op<-1>() - getNumIndirectDests() -1 + idx) =
4103-
reinterpret_cast<Value *>(NewSucc);
4106+
return i == 0 ? setDefaultDest(NewSucc) : setIndirectDest(i - 1, NewSucc);
41044107
}
41054108

41064109
unsigned getNumSuccessors() const { return getNumIndirectDests() + 1; }

llvm/lib/IR/Instructions.cpp

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -822,6 +822,17 @@ void CallBrInst::init(FunctionType *FTy, Value *Fn, BasicBlock *Fallthrough,
822822
setName(NameStr);
823823
}
824824

825+
void CallBrInst::updateArgBlockAddresses(unsigned i, BasicBlock *B) {
826+
assert(getNumIndirectDests() > i && "IndirectDest # out of range for callbr");
827+
if (BasicBlock *OldBB = getIndirectDest(i)) {
828+
BlockAddress *Old = BlockAddress::get(OldBB);
829+
BlockAddress *New = BlockAddress::get(B);
830+
for (unsigned ArgNo = 0, e = getNumArgOperands(); ArgNo != e; ++ArgNo)
831+
if (dyn_cast<BlockAddress>(getArgOperand(ArgNo)) == Old)
832+
setArgOperand(ArgNo, New);
833+
}
834+
}
835+
825836
CallBrInst::CallBrInst(const CallBrInst &CBI)
826837
: CallBase(CBI.Attrs, CBI.FTy, CBI.getType(), Instruction::CallBr,
827838
OperandTraits<CallBase>::op_end(this) - CBI.getNumOperands(),

llvm/unittests/IR/InstructionsTest.cpp

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1061,5 +1061,56 @@ TEST(InstructionsTest, FNegInstruction) {
10611061
FNeg->deleteValue();
10621062
}
10631063

1064+
TEST(InstructionsTest, CallBrInstruction) {
1065+
LLVMContext Context;
1066+
std::unique_ptr<Module> M = parseIR(Context, R"(
1067+
define void @foo() {
1068+
entry:
1069+
callbr void asm sideeffect "// XXX: ${0:l}", "X"(i8* blockaddress(@foo, %branch_test.exit))
1070+
to label %land.rhs.i [label %branch_test.exit]
1071+
1072+
land.rhs.i:
1073+
br label %branch_test.exit
1074+
1075+
branch_test.exit:
1076+
%0 = phi i1 [ true, %entry ], [ false, %land.rhs.i ]
1077+
br i1 %0, label %if.end, label %if.then
1078+
1079+
if.then:
1080+
ret void
1081+
1082+
if.end:
1083+
ret void
1084+
}
1085+
)");
1086+
Function *Foo = M->getFunction("foo");
1087+
auto BBs = Foo->getBasicBlockList().begin();
1088+
CallBrInst &CBI = cast<CallBrInst>(BBs->front());
1089+
++BBs;
1090+
++BBs;
1091+
BasicBlock &BranchTestExit = *BBs;
1092+
++BBs;
1093+
BasicBlock &IfThen = *BBs;
1094+
1095+
// Test that setting the first indirect destination of callbr updates the dest
1096+
EXPECT_EQ(&BranchTestExit, CBI.getIndirectDest(0));
1097+
CBI.setIndirectDest(0, &IfThen);
1098+
EXPECT_EQ(&IfThen, CBI.getIndirectDest(0));
1099+
1100+
// Further, test that changing the indirect destination updates the arg
1101+
// operand to use the block address of the new indirect destination basic
1102+
// block. This is a critical invariant of CallBrInst.
1103+
BlockAddress *IndirectBA = BlockAddress::get(CBI.getIndirectDest(0));
1104+
BlockAddress *ArgBA = cast<BlockAddress>(CBI.getArgOperand(0));
1105+
EXPECT_EQ(IndirectBA, ArgBA)
1106+
<< "After setting the indirect destination, callbr had an indirect "
1107+
"destination of '"
1108+
<< CBI.getIndirectDest(0)->getName() << "', but a argument of '"
1109+
<< ArgBA->getBasicBlock()->getName() << "'. These should always match:\n"
1110+
<< CBI;
1111+
EXPECT_EQ(IndirectBA->getBasicBlock(), &IfThen);
1112+
EXPECT_EQ(ArgBA->getBasicBlock(), &IfThen);
1113+
}
1114+
10641115
} // end anonymous namespace
10651116
} // end namespace llvm

0 commit comments

Comments
 (0)