1
0
mirror of https://github.com/RPCS3/llvm-mirror.git synced 2025-01-31 12:41:49 +01:00

[MachineOutliner] AArch64: Handle instrs that use SP and will never need fixups

This commit does two things. Firstly, it adds a collection of flags which can
be passed along to the target to encode information about the MBB that an
instruction lives in to the outliner.

Second, it adds some of those flags to the AArch64 outliner in order to add
more stack instructions to the list of legal instructions that are handled
by the outliner. The two flags added check if

- There are calls in the MachineBasicBlock containing the instruction
- The link register is available in the entire block

If the link register is available and there are no calls, then a stack
instruction can always be outlined without fixups, regardless of what it is,
since in this case, the outliner will never modify the stack to create a
call or outlined frame.

The motivation for doing this was checking which instructions are most often
missed by the outliner. Instructions like, say

%sp<def> = ADDXri %sp, 32, 0; flags: FrameDestroy

are very common, but cannot be outlined in the case that the outliner might
modify the stack. This commit allows us to outline instructions like this.
  

llvm-svn: 322048
This commit is contained in:
Jessica Paquette 2018-01-09 00:26:18 +00:00
parent 7f6e32fff6
commit 3075bb4222
7 changed files with 132 additions and 22 deletions

View File

@ -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.

View File

@ -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.

View File

@ -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;
MachineFunction *MF = MI.getParent()->getParent();
// Check if LR is available through all of the MBB. If it's not, then set
// a flag.
LiveRegUnits LRU(getRegisterInfo());
LRU.addLiveOuts(MBB);
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.

View File

@ -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,

View File

@ -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;

View File

@ -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;

View File

@ -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