[IR] Don't use blockaddresses as callbr arguments
Following some recent discussions, this changes the representation
of callbrs in IR. The current blockaddress arguments are replaced
with `!` label constraints that refer directly to callbr indirect
destinations:
; Before:
%res = callbr i8* asm "", "=r,r,i"(i8* %x, i8* blockaddress(@test8, %foo))
to label %asm.fallthrough [label %foo]
; After:
%res = callbr i8* asm "", "=r,r,!i"(i8* %x)
to label %asm.fallthrough [label %foo]
The benefit of this is that we can easily update the successors of
a callbr, without having to worry about also updating blockaddress
references. This should allow us to remove some limitations:
* Allow unrolling/peeling/rotation of callbr, or any other
clone-based optimizations
(https://github.com/llvm/llvm-project/issues/41834)
* Allow duplicate successors
(https://github.com/llvm/llvm-project/issues/45248)
This is just the IR representation change though, I will follow up
with patches to remove limtations in various transformation passes
that are no longer needed.
Differential Revision: https://reviews.llvm.org/D129288
This commit is contained in:
@@ -5510,6 +5510,61 @@ Error BitcodeReader::parseFunctionBody(Function *F) {
|
||||
if (!OperandBundles.empty())
|
||||
UpgradeOperandBundles(OperandBundles);
|
||||
|
||||
if (auto *IA = dyn_cast<InlineAsm>(Callee)) {
|
||||
InlineAsm::ConstraintInfoVector ConstraintInfo = IA->ParseConstraints();
|
||||
auto IsLabelConstraint = [](const InlineAsm::ConstraintInfo &CI) {
|
||||
return CI.Type == InlineAsm::isLabel;
|
||||
};
|
||||
if (none_of(ConstraintInfo, IsLabelConstraint)) {
|
||||
// Upgrade explicit blockaddress arguments to label constraints.
|
||||
// Verify that the last arguments are blockaddress arguments that
|
||||
// match the indirect destinations. Clang always generates callbr
|
||||
// in this form. We could support reordering with more effort.
|
||||
unsigned FirstBlockArg = Args.size() - IndirectDests.size();
|
||||
for (unsigned ArgNo = FirstBlockArg; ArgNo < Args.size(); ++ArgNo) {
|
||||
unsigned LabelNo = ArgNo - FirstBlockArg;
|
||||
auto *BA = dyn_cast<BlockAddress>(Args[ArgNo]);
|
||||
if (!BA || BA->getFunction() != F ||
|
||||
LabelNo > IndirectDests.size() ||
|
||||
BA->getBasicBlock() != IndirectDests[LabelNo])
|
||||
return error("callbr argument does not match indirect dest");
|
||||
}
|
||||
|
||||
// Remove blockaddress arguments.
|
||||
Args.erase(Args.begin() + FirstBlockArg, Args.end());
|
||||
ArgTyIDs.erase(ArgTyIDs.begin() + FirstBlockArg, ArgTyIDs.end());
|
||||
|
||||
// Recreate the function type with less arguments.
|
||||
SmallVector<Type *> ArgTys;
|
||||
for (Value *Arg : Args)
|
||||
ArgTys.push_back(Arg->getType());
|
||||
FTy =
|
||||
FunctionType::get(FTy->getReturnType(), ArgTys, FTy->isVarArg());
|
||||
|
||||
// Update constraint string to use label constraints.
|
||||
std::string Constraints = IA->getConstraintString();
|
||||
unsigned ArgNo = 0;
|
||||
size_t Pos = 0;
|
||||
for (const auto &CI : ConstraintInfo) {
|
||||
if (CI.hasArg()) {
|
||||
if (ArgNo >= FirstBlockArg)
|
||||
Constraints.insert(Pos, "!");
|
||||
++ArgNo;
|
||||
}
|
||||
|
||||
// Go to next constraint in string.
|
||||
Pos = Constraints.find(',', Pos);
|
||||
if (Pos == std::string::npos)
|
||||
break;
|
||||
++Pos;
|
||||
}
|
||||
|
||||
Callee = InlineAsm::get(FTy, IA->getAsmString(), Constraints,
|
||||
IA->hasSideEffects(), IA->isAlignStack(),
|
||||
IA->getDialect(), IA->canThrow());
|
||||
}
|
||||
}
|
||||
|
||||
I = CallBrInst::Create(FTy, Callee, DefaultDest, IndirectDests, Args,
|
||||
OperandBundles);
|
||||
ResTypeID = getContainedTypeID(FTyID);
|
||||
|
||||
Reference in New Issue
Block a user