summaryrefslogtreecommitdiffstats
path: root/llvm
diff options
context:
space:
mode:
Diffstat (limited to 'llvm')
-rw-r--r--llvm/include/llvm/CodeGen/TargetInstrInfo.h9
-rw-r--r--llvm/lib/CodeGen/MachineOutliner.cpp7
-rw-r--r--llvm/lib/Target/AArch64/AArch64InstrInfo.cpp99
-rw-r--r--llvm/lib/Target/AArch64/AArch64InstrInfo.h3
-rw-r--r--llvm/lib/Target/X86/X86InstrInfo.cpp4
-rw-r--r--llvm/lib/Target/X86/X86InstrInfo.h2
-rw-r--r--llvm/test/CodeGen/AArch64/machine-outliner.mir30
7 files changed, 132 insertions, 22 deletions
diff --git a/llvm/include/llvm/CodeGen/TargetInstrInfo.h b/llvm/include/llvm/CodeGen/TargetInstrInfo.h
index 38a1b33aeca..2a91b11bd73 100644
--- a/llvm/include/llvm/CodeGen/TargetInstrInfo.h
+++ b/llvm/include/llvm/CodeGen/TargetInstrInfo.h
@@ -1607,11 +1607,18 @@ public:
enum MachineOutlinerInstrType { Legal, Illegal, Invisible };
/// Returns how or if \p MI should be outlined.
- virtual MachineOutlinerInstrType getOutliningType(MachineInstr &MI) const {
+ virtual MachineOutlinerInstrType
+ getOutliningType(MachineBasicBlock::iterator &MIT, unsigned Flags) const {
llvm_unreachable(
"Target didn't implement TargetInstrInfo::getOutliningType!");
}
+ /// \brief Returns target-defined flags defining properties of the MBB for
+ /// the outliner.
+ virtual unsigned getMachineOutlinerMBBFlags(MachineBasicBlock &MBB) const {
+ return 0x0;
+ }
+
/// Insert a custom epilogue for outlined functions.
/// This may be empty, in which case no epilogue or return statement will be
/// emitted.
diff --git a/llvm/lib/CodeGen/MachineOutliner.cpp b/llvm/lib/CodeGen/MachineOutliner.cpp
index e4eb8802ac6..58d546158a8 100644
--- a/llvm/lib/CodeGen/MachineOutliner.cpp
+++ b/llvm/lib/CodeGen/MachineOutliner.cpp
@@ -720,11 +720,13 @@ struct InstructionMapper {
void convertToUnsignedVec(MachineBasicBlock &MBB,
const TargetRegisterInfo &TRI,
const TargetInstrInfo &TII) {
+ unsigned Flags = TII.getMachineOutlinerMBBFlags(MBB);
+
for (MachineBasicBlock::iterator It = MBB.begin(), Et = MBB.end(); It != Et;
It++) {
// Keep track of where this instruction is in the module.
- switch (TII.getOutliningType(*It)) {
+ switch (TII.getOutliningType(It, Flags)) {
case TargetInstrInfo::MachineOutlinerInstrType::Illegal:
mapToIllegalUnsigned(It);
break;
@@ -1237,7 +1239,6 @@ MachineOutliner::createOutlinedFunction(Module &M, const OutlinedFunction &OF,
}
TII.insertOutlinerEpilogue(MBB, MF, OF.MInfo);
-
return &MF;
}
@@ -1341,7 +1342,7 @@ bool MachineOutliner::runOnModule(Module &M) {
MMI.getOrCreateMachineFunction(*M.begin()).getSubtarget();
const TargetRegisterInfo *TRI = STI.getRegisterInfo();
const TargetInstrInfo *TII = STI.getInstrInfo();
-
+
InstructionMapper Mapper;
// Build instruction mappings for each function in the module.
diff --git a/llvm/lib/Target/AArch64/AArch64InstrInfo.cpp b/llvm/lib/Target/AArch64/AArch64InstrInfo.cpp
index 40836b00b9e..ef0a785abfc 100644
--- a/llvm/lib/Target/AArch64/AArch64InstrInfo.cpp
+++ b/llvm/lib/Target/AArch64/AArch64InstrInfo.cpp
@@ -4696,6 +4696,11 @@ enum MachineOutlinerClass {
MachineOutlinerNoLRSave /// Emit a call and return.
};
+enum MachineOutlinerMBBFlags {
+ LRUnavailableSomewhere = 0x2,
+ HasCalls = 0x4
+};
+
bool AArch64InstrInfo::canOutlineWithoutLRSave(
MachineBasicBlock::iterator &CallInsertionPt) const {
// Was LR saved in the function containing this basic block?
@@ -4785,10 +4790,36 @@ bool AArch64InstrInfo::isFunctionSafeToOutlineFrom(
return true;
}
-AArch64GenInstrInfo::MachineOutlinerInstrType
-AArch64InstrInfo::getOutliningType(MachineInstr &MI) const {
+unsigned
+AArch64InstrInfo::getMachineOutlinerMBBFlags(MachineBasicBlock &MBB) const {
+ unsigned Flags = 0x0;
+ // Check if there's a call inside this MachineBasicBlock. If there is, then
+ // set a flag.
+ if (std::any_of(MBB.begin(), MBB.end(),
+ [](MachineInstr &MI) { return MI.isCall(); }))
+ Flags |= MachineOutlinerMBBFlags::HasCalls;
+
+ // Check if LR is available through all of the MBB. If it's not, then set
+ // a flag.
+ LiveRegUnits LRU(getRegisterInfo());
+ LRU.addLiveOuts(MBB);
- MachineFunction *MF = MI.getParent()->getParent();
+ std::for_each(MBB.rbegin(),
+ MBB.rend(),
+ [&LRU](MachineInstr &MI) { LRU.accumulate(MI); });
+
+ if (!LRU.available(AArch64::LR))
+ Flags |= MachineOutlinerMBBFlags::LRUnavailableSomewhere;
+
+ return Flags;
+}
+
+AArch64GenInstrInfo::MachineOutlinerInstrType
+AArch64InstrInfo::getOutliningType(MachineBasicBlock::iterator &MIT,
+ unsigned Flags) const {
+ MachineInstr &MI = *MIT;
+ MachineBasicBlock *MBB = MI.getParent();
+ MachineFunction *MF = MBB->getParent();
AArch64FunctionInfo *FuncInfo = MF->getInfo<AArch64FunctionInfo>();
// Don't outline LOHs.
@@ -4796,16 +4827,16 @@ AArch64InstrInfo::getOutliningType(MachineInstr &MI) const {
return MachineOutlinerInstrType::Illegal;
// Don't allow debug values to impact outlining type.
- if (MI.isDebugValue() || MI.isIndirectDebugValue())
+ if (MI.isDebugValue() || MI.isIndirectDebugValue())
return MachineOutlinerInstrType::Invisible;
-
+
// Is this a terminator for a basic block?
if (MI.isTerminator()) {
// Is this the end of a function?
if (MI.getParent()->succ_empty())
return MachineOutlinerInstrType::Legal;
-
+
// It's not, so don't outline it.
return MachineOutlinerInstrType::Illegal;
}
@@ -4833,7 +4864,7 @@ AArch64InstrInfo::getOutliningType(MachineInstr &MI) const {
// Only handle functions that we have information about.
if (!Callee)
return MachineOutlinerInstrType::Illegal;
-
+
// We have a function we have information about. Check it if it's something
// can safely outline.
@@ -4848,27 +4879,28 @@ AArch64InstrInfo::getOutliningType(MachineInstr &MI) const {
// to outline these since they might be loaded in two instructions.
for (Argument &Arg : Callee->args()) {
if (Arg.getType()->isPointerTy() &&
- Arg.getType()->getPointerElementType()->isAggregateType())
+ Arg.getType()->getPointerElementType()->isAggregateType())
return MachineOutlinerInstrType::Illegal;
}
// If the thing we're calling doesn't access memory at all, then we're good
// to go.
- if (Callee->doesNotAccessMemory())
+ if (Callee->doesNotAccessMemory())
return MachineOutlinerInstrType::Legal;
+
// It accesses memory. Get the machine function for the callee to see if
// it's safe to outline.
MachineFunction *CalleeMF = MF->getMMI().getMachineFunction(*Callee);
// We don't know what's going on with the callee at all. Don't touch it.
- if (!CalleeMF)
+ if (!CalleeMF)
return MachineOutlinerInstrType::Illegal;
// Does it pass anything on the stack? If it does, don't outline it.
if (CalleeMF->getInfo<AArch64FunctionInfo>()->getBytesInStackArgArea() != 0)
return MachineOutlinerInstrType::Illegal;
-
+
// It doesn't, so it's safe to outline and we're done.
return MachineOutlinerInstrType::Legal;
}
@@ -4896,7 +4928,52 @@ AArch64InstrInfo::getOutliningType(MachineInstr &MI) const {
// Does this use the stack?
if (MI.modifiesRegister(AArch64::SP, &RI) ||
MI.readsRegister(AArch64::SP, &RI)) {
+ // True if there is no chance that any outlined candidate from this range
+ // could require stack fixups. That is, both
+ // * LR is available in the range (No save/restore around call)
+ // * The range doesn't include calls (No save/restore in outlined frame)
+ // are true.
+ bool MightNeedStackFixUp =
+ (Flags & (MachineOutlinerMBBFlags::LRUnavailableSomewhere |
+ MachineOutlinerMBBFlags::HasCalls));
+
+ // If this instruction is in a range where it *never* needs to be fixed
+ // up, then we can *always* outline it. This is true even if it's not
+ // possible to fix that instruction up.
+ //
+ // Why? Consider two equivalent instructions I1, I2 where both I1 and I2
+ // use SP. Suppose that I1 sits within a range that definitely doesn't
+ // need stack fixups, while I2 sits in a range that does.
+ //
+ // First, I1 can be outlined as long as we *never* fix up the stack in
+ // any sequence containing it. I1 is already a safe instruction in the
+ // original program, so as long as we don't modify it we're good to go.
+ // So this leaves us with showing that outlining I2 won't break our
+ // program.
+ //
+ // Suppose I1 and I2 belong to equivalent candidate sequences. When we
+ // look at I2, we need to see if it can be fixed up. Suppose I2, (and
+ // thus I1) cannot be fixed up. Then I2 will be assigned an unique
+ // integer label; thus, I2 cannot belong to any candidate sequence (a
+ // contradiction). Suppose I2 can be fixed up. Then I1 can be fixed up
+ // as well, so we're good. Thus, I1 is always safe to outline.
+ //
+ // This gives us two things: first off, it buys us some more instructions
+ // for our search space by deeming stack instructions illegal only when
+ // they can't be fixed up AND we might have to fix them up. Second off,
+ // This allows us to catch tricky instructions like, say,
+ // %xi = ADDXri %sp, n, 0. We can't safely outline these since they might
+ // be paired with later SUBXris, which might *not* end up being outlined.
+ // If we mess with the stack to save something, then an ADDXri messes with
+ // it *after*, then we aren't going to restore the right something from
+ // the stack if we don't outline the corresponding SUBXri first. ADDXris and
+ // SUBXris are extremely common in prologue/epilogue code, so supporting
+ // them in the outliner can be a pretty big win!
+ if (!MightNeedStackFixUp)
+ return MachineOutlinerInstrType::Legal;
+ // At this point, we have a stack instruction that we might need to fix
+ // up. We'll handle it if it's a load or store.
if (MI.mayLoadOrStore()) {
unsigned Base; // Filled with the base regiser of MI.
int64_t Offset; // Filled with the offset of MI.
diff --git a/llvm/lib/Target/AArch64/AArch64InstrInfo.h b/llvm/lib/Target/AArch64/AArch64InstrInfo.h
index 2f10bef1e47..889e5f6d5f6 100644
--- a/llvm/lib/Target/AArch64/AArch64InstrInfo.h
+++ b/llvm/lib/Target/AArch64/AArch64InstrInfo.h
@@ -359,7 +359,8 @@ public:
std::pair<MachineBasicBlock::iterator, MachineBasicBlock::iterator>>
&RepeatedSequenceLocs) const override;
AArch64GenInstrInfo::MachineOutlinerInstrType
- getOutliningType(MachineInstr &MI) const override;
+ getOutliningType(MachineBasicBlock::iterator &MIT, unsigned Flags) const override;
+ unsigned getMachineOutlinerMBBFlags(MachineBasicBlock &MBB) const override;
void insertOutlinerEpilogue(MachineBasicBlock &MBB, MachineFunction &MF,
const MachineOutlinerInfo &MInfo) const override;
void insertOutlinerPrologue(MachineBasicBlock &MBB, MachineFunction &MF,
diff --git a/llvm/lib/Target/X86/X86InstrInfo.cpp b/llvm/lib/Target/X86/X86InstrInfo.cpp
index 4f6b0b5f26b..b8093641308 100644
--- a/llvm/lib/Target/X86/X86InstrInfo.cpp
+++ b/llvm/lib/Target/X86/X86InstrInfo.cpp
@@ -10937,8 +10937,8 @@ bool X86InstrInfo::isFunctionSafeToOutlineFrom(MachineFunction &MF,
}
X86GenInstrInfo::MachineOutlinerInstrType
-X86InstrInfo::getOutliningType(MachineInstr &MI) const {
-
+X86InstrInfo::getOutliningType(MachineBasicBlock::iterator &MIT, unsigned Flags) const {
+ MachineInstr &MI = *MIT;
// Don't allow debug values to impact outlining type.
if (MI.isDebugValue() || MI.isIndirectDebugValue())
return MachineOutlinerInstrType::Invisible;
diff --git a/llvm/lib/Target/X86/X86InstrInfo.h b/llvm/lib/Target/X86/X86InstrInfo.h
index 02a09c340ce..0f76ed76abd 100644
--- a/llvm/lib/Target/X86/X86InstrInfo.h
+++ b/llvm/lib/Target/X86/X86InstrInfo.h
@@ -568,7 +568,7 @@ public:
bool OutlineFromLinkOnceODRs) const override;
llvm::X86GenInstrInfo::MachineOutlinerInstrType
- getOutliningType(MachineInstr &MI) const override;
+ getOutliningType(MachineBasicBlock::iterator &MIT, unsigned Flags) const override;
void insertOutlinerEpilogue(MachineBasicBlock &MBB, MachineFunction &MF,
const MachineOutlinerInfo &MInfo) const override;
diff --git a/llvm/test/CodeGen/AArch64/machine-outliner.mir b/llvm/test/CodeGen/AArch64/machine-outliner.mir
index 708e2e42880..f8e60926d75 100644
--- a/llvm/test/CodeGen/AArch64/machine-outliner.mir
+++ b/llvm/test/CodeGen/AArch64/machine-outliner.mir
@@ -20,21 +20,29 @@
# - Create outlined functions
# - Don't outline anything to do with LR or W30
# - Save LR when it's not available
+# - Don't outline stack instructions when we might need to save + restore
#
# CHECK-LABEL: name: main
+
# CHECK: BL @OUTLINED_FUNCTION_[[F0:[0-9]+]]
# CHECK-NEXT: early-clobber %sp, %lr = LDRXpost %sp, 16
+# CHECK-NEXT: %x16 = ADDXri %sp, 48, 0
# CHECK-NEXT: STRHHroW %w16, %x9, %w30, 1, 1
# CHECK-NEXT: %lr = ORRXri %xzr, 1
+
# CHECK: BL @OUTLINED_FUNCTION_[[F0]]
# CHECK-NEXT: early-clobber %sp, %lr = LDRXpost %sp, 16
+# CHECK-NEXT: %x16 = ADDXri %sp, 48, 0
# CHECK-NEXT: STRHHroW %w16, %x9, %w30, 1, 1
# CHECK-NEXT: %lr = ORRXri %xzr, 1
+
# CHECK: BL @OUTLINED_FUNCTION_[[F0]]
# CHECK-NEXT: early-clobber %sp, %lr = LDRXpost %sp, 16
+# CHECK-NEXT: %x16 = ADDXri %sp, 48, 0
# CHECK-NEXT: STRHHroW %w16, %x9, %w30, 1, 1
# CHECK-NEXT: %lr = ORRXri %xzr, 1
name: main
+tracksRegLiveness: true
body: |
bb.0:
%sp = frame-setup SUBXri %sp, 16, 0
@@ -50,9 +58,9 @@ body: |
%w16 = ORRWri %wzr, 1
%w16 = ORRWri %wzr, 1
%w16 = ORRWri %wzr, 1
+ %x16 = ADDXri %sp, 48, 0;
STRHHroW %w16, %x9, %w30, 1, 1
%lr = ORRXri %xzr, 1
-
%w3 = ORRWri %wzr, 1993
%x20, %x19 = LDPXi %sp, 10
@@ -62,8 +70,9 @@ body: |
%w16 = ORRWri %wzr, 1
%w16 = ORRWri %wzr, 1
%w16 = ORRWri %wzr, 1
+ %x16 = ADDXri %sp, 48, 0;
STRHHroW %w16, %x9, %w30, 1, 1
- %lr = ORRXri %xzr, 1
+ %lr = ORRXri %xzr, 1
%w4 = ORRWri %wzr, 1994
@@ -74,6 +83,7 @@ body: |
%w16 = ORRWri %wzr, 1
%w16 = ORRWri %wzr, 1
%w16 = ORRWri %wzr, 1
+ %x16 = ADDXri %sp, 48, 0;
STRHHroW %w16, %x9, %w30, 1, 1
%lr = ORRXri %xzr, 1
@@ -112,8 +122,22 @@ body: |
%w17 = ORRWri %wzr, 1
BL @baz, implicit-def dead %lr, implicit %sp
%w8 = ORRWri %wzr, 0
-
+
bb.2:
+ %w15 = ORRWri %wzr, 1
+ %w15 = ORRWri %wzr, 1
+ %w15 = ORRWri %wzr, 1
+ %w15 = ORRWri %wzr, 1
+ %x15 = ADDXri %sp, 48, 0;
+ %w9 = ORRWri %wzr, 0
+ %w15 = ORRWri %wzr, 1
+ %w15 = ORRWri %wzr, 1
+ %w15 = ORRWri %wzr, 1
+ %w15 = ORRWri %wzr, 1
+ %x15 = ADDXri %sp, 48, 0;
+ %w8 = ORRWri %wzr, 0
+
+ bb.3:
%fp, %lr = LDPXi %sp, 2
%sp = ADDXri %sp, 32, 0
RET undef %lr
OpenPOWER on IntegriCloud