Skip to content

Commit

Permalink
Change the INLINEASM_BR MachineInstr to be a non-terminating instruct…
Browse files Browse the repository at this point in the history
…ion.

Before this instruction supported output values, it fit fairly
naturally as a terminator. However, being a terminator while also
supporting outputs causes some trouble, as the physreg->vreg COPY
operations cannot be in the same block.

Modeling it as a non-terminator allows it to be handled the same way
as invoke is handled already.

Most of the changes here were created by auditing all the existing
users of MachineBasicBlock::isEHPad() and
MachineBasicBlock::hasEHPadSuccessor(), and adding calls to
isInlineAsmBrIndirectTarget or mayHaveInlineAsmBr, as appropriate.

Reviewed By: nickdesaulniers, void

Differential Revision: https://reviews.llvm.org/D79794
  • Loading branch information
jyknight committed Jul 1, 2020
1 parent 78c69a0 commit 4b0aa57
Show file tree
Hide file tree
Showing 35 changed files with 366 additions and 220 deletions.
2 changes: 1 addition & 1 deletion llvm/include/llvm/CodeGen/ISDOpcodes.h
Original file line number Diff line number Diff line change
Expand Up @@ -870,7 +870,7 @@ enum NodeType {
/// SDOperands.
INLINEASM,

/// INLINEASM_BR - Terminator version of inline asm. Used by asm-goto.
/// INLINEASM_BR - Branching version of inline asm. Used by asm-goto.
INLINEASM_BR,

/// EH_LABEL - Represents a label in mid basic block used to track
Expand Down
37 changes: 11 additions & 26 deletions llvm/include/llvm/CodeGen/MachineBasicBlock.h
Original file line number Diff line number Diff line change
Expand Up @@ -167,11 +167,8 @@ class MachineBasicBlock
// Indicate that this basic block ends a section.
bool IsEndSection = false;

/// Default target of the callbr of a basic block.
bool InlineAsmBrDefaultTarget = false;

/// List of indirect targets of the callbr of a basic block.
SmallPtrSet<const MachineBasicBlock*, 4> InlineAsmBrIndirectTargets;
/// Indicate that this basic block is the indirect dest of an INLINEASM_BR.
bool IsInlineAsmBrIndirectTarget = false;

/// since getSymbol is a relatively heavy-weight operation, the symbol
/// is only computed once and is cached.
Expand Down Expand Up @@ -471,31 +468,19 @@ class MachineBasicBlock
/// Sets the section ID for this basic block.
void setSectionID(MBBSectionID V) { SectionID = V; }

/// Returns true if this block may have an INLINEASM_BR (overestimate, by
/// checking if any of the successors are indirect targets of any inlineasm_br
/// in the function).
bool mayHaveInlineAsmBr() const;

/// Returns true if this is the indirect dest of an INLINEASM_BR.
bool isInlineAsmBrIndirectTarget(const MachineBasicBlock *Tgt) const {
return InlineAsmBrIndirectTargets.count(Tgt);
bool isInlineAsmBrIndirectTarget() const {
return IsInlineAsmBrIndirectTarget;
}

/// Indicates if this is the indirect dest of an INLINEASM_BR.
void addInlineAsmBrIndirectTarget(const MachineBasicBlock *Tgt) {
InlineAsmBrIndirectTargets.insert(Tgt);
}

/// Transfers indirect targets to INLINEASM_BR's copy block.
void transferInlineAsmBrIndirectTargets(MachineBasicBlock *CopyBB) {
for (auto *Target : InlineAsmBrIndirectTargets)
CopyBB->addInlineAsmBrIndirectTarget(Target);
return InlineAsmBrIndirectTargets.clear();
}

/// Returns true if this is the default dest of an INLINEASM_BR.
bool isInlineAsmBrDefaultTarget() const {
return InlineAsmBrDefaultTarget;
}

/// Indicates if this is the default deft of an INLINEASM_BR.
void setInlineAsmBrDefaultTarget() {
InlineAsmBrDefaultTarget = true;
void setIsInlineAsmBrIndirectTarget(bool V = true) {
IsInlineAsmBrIndirectTarget = V;
}

/// Returns true if it is legal to hoist instructions into this block.
Expand Down
8 changes: 4 additions & 4 deletions llvm/include/llvm/Target/Target.td
Original file line number Diff line number Diff line change
Expand Up @@ -1017,10 +1017,10 @@ def INLINEASM_BR : StandardPseudoInstruction {
let OutOperandList = (outs);
let InOperandList = (ins variable_ops);
let AsmString = "";
let hasSideEffects = 0; // Note side effect is encoded in an operand.
let isTerminator = 1;
let isBranch = 1;
let isIndirectBranch = 1;
// Unlike INLINEASM, this is always treated as having side-effects.
let hasSideEffects = 1;
// Despite potentially branching, this instruction is intentionally _not_
// marked as a terminator or a branch.
}
def CFI_INSTRUCTION : StandardPseudoInstruction {
let OutOperandList = (outs);
Expand Down
42 changes: 24 additions & 18 deletions llvm/lib/CodeGen/BranchFolding.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1083,8 +1083,9 @@ bool BranchFolder::TailMergeBlocks(MachineFunction &MF) {
if (!UniquePreds.insert(PBB).second)
continue;

// Skip blocks which may jump to a landing pad. Can't tail merge these.
if (PBB->hasEHPadSuccessor())
// Skip blocks which may jump to a landing pad or jump from an asm blob.
// Can't tail merge these.
if (PBB->hasEHPadSuccessor() || PBB->mayHaveInlineAsmBr())
continue;

// After block placement, only consider predecessors that belong to the
Expand Down Expand Up @@ -1665,13 +1666,15 @@ bool BranchFolder::OptimizeBlock(MachineBasicBlock *MBB) {

if (!MBB->isEHPad()) {
// Check all the predecessors of this block. If one of them has no fall
// throughs, move this block right after it.
// throughs, and analyzeBranch thinks it _could_ fallthrough to this
// block, move this block right after it.
for (MachineBasicBlock *PredBB : MBB->predecessors()) {
// Analyze the branch at the end of the pred.
MachineBasicBlock *PredTBB = nullptr, *PredFBB = nullptr;
SmallVector<MachineOperand, 4> PredCond;
if (PredBB != MBB && !PredBB->canFallThrough() &&
!TII->analyzeBranch(*PredBB, PredTBB, PredFBB, PredCond, true) &&
(PredTBB == MBB || PredFBB == MBB) &&
(!CurFallsThru || !CurTBB || !CurFBB) &&
(!CurFallsThru || MBB->getNumber() >= PredBB->getNumber())) {
// If the current block doesn't fall through, just move it.
Expand All @@ -1697,21 +1700,24 @@ bool BranchFolder::OptimizeBlock(MachineBasicBlock *MBB) {
}

if (!CurFallsThru) {
// Check all successors to see if we can move this block before it.
for (MachineBasicBlock *SuccBB : MBB->successors()) {
// Analyze the branch at the end of the block before the succ.
MachineFunction::iterator SuccPrev = --SuccBB->getIterator();

// If this block doesn't already fall-through to that successor, and if
// the succ doesn't already have a block that can fall through into it,
// and if the successor isn't an EH destination, we can arrange for the
// fallthrough to happen.
if (SuccBB != MBB && &*SuccPrev != MBB &&
!SuccPrev->canFallThrough() && !CurUnAnalyzable &&
!SuccBB->isEHPad()) {
MBB->moveBefore(SuccBB);
MadeChange = true;
goto ReoptimizeBlock;
// Check analyzable branch-successors to see if we can move this block
// before one.
if (!CurUnAnalyzable) {
for (MachineBasicBlock *SuccBB : {CurFBB, CurTBB}) {
if (!SuccBB)
continue;
// Analyze the branch at the end of the block before the succ.
MachineFunction::iterator SuccPrev = --SuccBB->getIterator();

// If this block doesn't already fall-through to that successor, and
// if the succ doesn't already have a block that can fall through into
// it, we can arrange for the fallthrough to happen.
if (SuccBB != MBB && &*SuccPrev != MBB &&
!SuccPrev->canFallThrough()) {
MBB->moveBefore(SuccBB);
MadeChange = true;
goto ReoptimizeBlock;
}
}
}

Expand Down
12 changes: 10 additions & 2 deletions llvm/lib/CodeGen/MachineBasicBlock.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -277,8 +277,16 @@ LLVM_DUMP_METHOD void MachineBasicBlock::dump() const {
}
#endif

bool MachineBasicBlock::mayHaveInlineAsmBr() const {
for (const MachineBasicBlock *Succ : successors()) {
if (Succ->isInlineAsmBrIndirectTarget())
return true;
}
return false;
}

bool MachineBasicBlock::isLegalToHoistInto() const {
if (isReturnBlock() || hasEHPadSuccessor())
if (isReturnBlock() || hasEHPadSuccessor() || mayHaveInlineAsmBr())
return false;
return true;
}
Expand Down Expand Up @@ -1132,7 +1140,7 @@ bool MachineBasicBlock::canSplitCriticalEdge(

// Splitting the critical edge to a callbr's indirect block isn't advised.
// Don't do it in this generic function.
if (isInlineAsmBrIndirectTarget(Succ))
if (Succ->isInlineAsmBrIndirectTarget())
return false;

const MachineFunction *MF = getParent();
Expand Down
7 changes: 7 additions & 0 deletions llvm/lib/CodeGen/MachineSink.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -734,6 +734,13 @@ MachineSinking::FindSuccToSinkTo(MachineInstr &MI, MachineBasicBlock *MBB,
if (SuccToSinkTo && SuccToSinkTo->isEHPad())
return nullptr;

// It ought to be okay to sink instructions into an INLINEASM_BR target, but
// only if we make sure that MI occurs _before_ an INLINEASM_BR instruction in
// the source block (which this code does not yet do). So for now, forbid
// doing so.
if (SuccToSinkTo && SuccToSinkTo->isInlineAsmBrIndirectTarget())
return nullptr;

return SuccToSinkTo;
}

Expand Down
3 changes: 1 addition & 2 deletions llvm/lib/CodeGen/MachineVerifier.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -584,7 +584,6 @@ MachineVerifier::visitMachineBasicBlockBefore(const MachineBasicBlock *MBB) {
// it is an entry block or landing pad.
for (const auto &LI : MBB->liveins()) {
if (isAllocatable(LI.PhysReg) && !MBB->isEHPad() &&
!MBB->isInlineAsmBrDefaultTarget() &&
MBB->getIterator() != MBB->getParent()->begin()) {
report("MBB has allocatable live-in, but isn't entry or landing-pad.", MBB);
report_context(LI.PhysReg);
Expand Down Expand Up @@ -730,7 +729,7 @@ MachineVerifier::visitMachineBasicBlockBefore(const MachineBasicBlock *MBB) {
continue;
// Also accept successors which are for exception-handling or might be
// inlineasm_br targets.
if (SuccMBB->isEHPad() || MBB->isInlineAsmBrIndirectTarget(SuccMBB))
if (SuccMBB->isEHPad() || SuccMBB->isInlineAsmBrIndirectTarget())
continue;
report("MBB has unexpected successors which are not branch targets, "
"fallthrough, EHPads, or inlineasm_br targets.",
Expand Down
5 changes: 3 additions & 2 deletions llvm/lib/CodeGen/PHIEliminationUtils.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -26,8 +26,9 @@ llvm::findPHICopyInsertPoint(MachineBasicBlock* MBB, MachineBasicBlock* SuccMBB,

// Usually, we just want to insert the copy before the first terminator
// instruction. However, for the edge going to a landing pad, we must insert
// the copy before the call/invoke instruction.
if (!SuccMBB->isEHPad())
// the copy before the call/invoke instruction. Similarly for an INLINEASM_BR
// going to an indirect target.
if (!SuccMBB->isEHPad() && !SuccMBB->isInlineAsmBrIndirectTarget())
return MBB->getFirstTerminator();

// Discover any defs/uses in this basic block.
Expand Down
4 changes: 3 additions & 1 deletion llvm/lib/CodeGen/RegisterCoalescer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1064,7 +1064,9 @@ bool RegisterCoalescer::removePartialRedundancy(const CoalescerPair &CP,
return false;

MachineBasicBlock &MBB = *CopyMI.getParent();
if (MBB.isEHPad())
// If this block is the target of an invoke/inlineasm_br, moving the copy into
// the predecessor is tricker, and we don't handle it.
if (MBB.isEHPad() || MBB.isInlineAsmBrIndirectTarget())
return false;

if (MBB.pred_size() != 2)
Expand Down
51 changes: 0 additions & 51 deletions llvm/lib/CodeGen/SelectionDAG/ScheduleDAGSDNodes.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1033,57 +1033,6 @@ EmitSchedule(MachineBasicBlock::iterator &InsertPos) {
}
}

// Split after an INLINEASM_BR block with outputs. This allows us to keep the
// copy to/from register instructions from being between two terminator
// instructions, which causes the machine instruction verifier agita.
auto TI = llvm::find_if(*BB, [](const MachineInstr &MI){
return MI.getOpcode() == TargetOpcode::INLINEASM_BR;
});
auto SplicePt = TI != BB->end() ? std::next(TI) : BB->end();
if (TI != BB->end() && SplicePt != BB->end() &&
TI->getOpcode() == TargetOpcode::INLINEASM_BR &&
SplicePt->getOpcode() == TargetOpcode::COPY) {
MachineBasicBlock *FallThrough = BB->getFallThrough();
if (!FallThrough)
for (const MachineOperand &MO : BB->back().operands())
if (MO.isMBB()) {
FallThrough = MO.getMBB();
break;
}
assert(FallThrough && "Cannot find default dest block for callbr!");

MachineBasicBlock *CopyBB = MF.CreateMachineBasicBlock(BB->getBasicBlock());
MachineFunction::iterator BBI(*BB);
MF.insert(++BBI, CopyBB);

CopyBB->splice(CopyBB->begin(), BB, SplicePt, BB->end());
CopyBB->setInlineAsmBrDefaultTarget();

CopyBB->addSuccessor(FallThrough, BranchProbability::getOne());
BB->removeSuccessor(FallThrough);
BB->addSuccessor(CopyBB, BranchProbability::getOne());

// Mark all physical registers defined in the original block as being live
// on entry to the copy block.
for (const auto &MI : *CopyBB)
for (const MachineOperand &MO : MI.operands())
if (MO.isReg()) {
Register reg = MO.getReg();
if (Register::isPhysicalRegister(reg)) {
CopyBB->addLiveIn(reg);
break;
}
}

CopyBB->normalizeSuccProbs();
BB->normalizeSuccProbs();

BB->transferInlineAsmBrIndirectTargets(CopyBB);

InsertPos = CopyBB->end();
return CopyBB;
}

InsertPos = Emitter.getInsertPos();
return Emitter.getBlock();
}
Expand Down
16 changes: 2 additions & 14 deletions llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2885,14 +2885,13 @@ void SelectionDAGBuilder::visitCallBr(const CallBrInst &I) {

// Retrieve successors.
MachineBasicBlock *Return = FuncInfo.MBBMap[I.getDefaultDest()];
Return->setInlineAsmBrDefaultTarget();

// Update successor info.
addSuccessorWithProb(CallBrMBB, Return, BranchProbability::getOne());
for (unsigned i = 0, e = I.getNumIndirectDests(); i < e; ++i) {
MachineBasicBlock *Target = FuncInfo.MBBMap[I.getIndirectDest(i)];
addSuccessorWithProb(CallBrMBB, Target, BranchProbability::getZero());
CallBrMBB->addInlineAsmBrIndirectTarget(Target);
Target->setIsInlineAsmBrIndirectTarget();
}
CallBrMBB->normalizeSuccProbs();

Expand Down Expand Up @@ -2965,16 +2964,6 @@ void SelectionDAGBuilder::UpdateSplitBlock(MachineBasicBlock *First,
for (unsigned i = 0, e = SL->BitTestCases.size(); i != e; ++i)
if (SL->BitTestCases[i].Parent == First)
SL->BitTestCases[i].Parent = Last;

// SelectionDAGISel::FinishBasicBlock will add PHI operands for the
// successors of the fallthrough block. Here, we add PHI operands for the
// successors of the INLINEASM_BR block itself.
if (First->getFirstTerminator()->getOpcode() == TargetOpcode::INLINEASM_BR)
for (std::pair<MachineInstr *, unsigned> &pair : FuncInfo.PHINodesToUpdate)
if (First->isSuccessor(pair.first->getParent()))
MachineInstrBuilder(*First->getParent(), pair.first)
.addReg(pair.second)
.addMBB(First);
}

void SelectionDAGBuilder::visitIndirectBr(const IndirectBrInst &I) {
Expand Down Expand Up @@ -7845,7 +7834,6 @@ class SDISelAsmOperandInfo : public TargetLowering::AsmOperandInfo {
}
};

using SDISelAsmOperandInfoVector = SmallVector<SDISelAsmOperandInfo, 16>;

} // end anonymous namespace

Expand Down Expand Up @@ -8091,7 +8079,7 @@ void SelectionDAGBuilder::visitInlineAsm(const CallBase &Call) {
const InlineAsm *IA = cast<InlineAsm>(Call.getCalledOperand());

/// ConstraintOperands - Information about all of the constraints.
SDISelAsmOperandInfoVector ConstraintOperands;
SmallVector<SDISelAsmOperandInfo, 16> ConstraintOperands;

const TargetLowering &TLI = DAG.getTargetLoweringInfo();
TargetLowering::AsmOperandInfoVector TargetConstraints = TLI.ParseConstraints(
Expand Down
16 changes: 7 additions & 9 deletions llvm/lib/CodeGen/ShrinkWrap.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -494,17 +494,15 @@ bool ShrinkWrap::runOnMachineFunction(MachineFunction &MF) {
"EH Funclets are not supported yet.",
MBB.front().getDebugLoc(), &MBB);

if (MBB.isEHPad()) {
// Push the prologue and epilogue outside of
// the region that may throw by making sure
// that all the landing pads are at least at the
// boundary of the save and restore points.
// The problem with exceptions is that the throw
// is not properly modeled and in particular, a
// basic block can jump out from the middle.
if (MBB.isEHPad() || MBB.isInlineAsmBrIndirectTarget()) {
// Push the prologue and epilogue outside of the region that may throw (or
// jump out via inlineasm_br), by making sure that all the landing pads
// are at least at the boundary of the save and restore points. The
// problem is that a basic block can jump out from the middle in these
// cases, which we do not handle.
updateSaveRestorePoints(MBB, RS.get());
if (!ArePointsInteresting()) {
LLVM_DEBUG(dbgs() << "EHPad prevents shrink-wrapping\n");
LLVM_DEBUG(dbgs() << "EHPad/inlineasm_br prevents shrink-wrapping\n");
return false;
}
continue;
Expand Down
Loading

0 comments on commit 4b0aa57

Please sign in to comment.