-
Notifications
You must be signed in to change notification settings - Fork 14.3k
[InlineSpiller] Check rematerialization before folding operand #134015
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -11,6 +11,7 @@ | |
// | ||
//===----------------------------------------------------------------------===// | ||
|
||
#include "AllocationOrder.h" | ||
#include "SplitKit.h" | ||
#include "llvm/ADT/ArrayRef.h" | ||
#include "llvm/ADT/DenseMap.h" | ||
|
@@ -23,6 +24,7 @@ | |
#include "llvm/CodeGen/LiveInterval.h" | ||
#include "llvm/CodeGen/LiveIntervals.h" | ||
#include "llvm/CodeGen/LiveRangeEdit.h" | ||
#include "llvm/CodeGen/LiveRegMatrix.h" | ||
#include "llvm/CodeGen/LiveStacks.h" | ||
#include "llvm/CodeGen/MachineBasicBlock.h" | ||
#include "llvm/CodeGen/MachineBlockFrequencyInfo.h" | ||
|
@@ -149,12 +151,14 @@ class InlineSpiller : public Spiller { | |
MachineRegisterInfo &MRI; | ||
const TargetInstrInfo &TII; | ||
const TargetRegisterInfo &TRI; | ||
LiveRegMatrix *Matrix = nullptr; | ||
|
||
// Variables that are valid during spill(), but used by multiple methods. | ||
LiveRangeEdit *Edit = nullptr; | ||
LiveInterval *StackInt = nullptr; | ||
int StackSlot; | ||
Register Original; | ||
AllocationOrder *Order = nullptr; | ||
|
||
// All registers to spill to StackSlot, including the main register. | ||
SmallVector<Register, 8> RegsToSpill; | ||
|
@@ -184,13 +188,13 @@ class InlineSpiller : public Spiller { | |
|
||
public: | ||
InlineSpiller(const Spiller::RequiredAnalyses &Analyses, MachineFunction &MF, | ||
VirtRegMap &VRM, VirtRegAuxInfo &VRAI) | ||
VirtRegMap &VRM, VirtRegAuxInfo &VRAI, LiveRegMatrix *Matrix) | ||
: MF(MF), LIS(Analyses.LIS), LSS(Analyses.LSS), VRM(VRM), | ||
MRI(MF.getRegInfo()), TII(*MF.getSubtarget().getInstrInfo()), | ||
TRI(*MF.getSubtarget().getRegisterInfo()), HSpiller(Analyses, MF, VRM), | ||
VRAI(VRAI) {} | ||
TRI(*MF.getSubtarget().getRegisterInfo()), Matrix(Matrix), | ||
HSpiller(Analyses, MF, VRM), VRAI(VRAI) {} | ||
|
||
void spill(LiveRangeEdit &) override; | ||
void spill(LiveRangeEdit &, AllocationOrder *Order = nullptr) override; | ||
ArrayRef<Register> getSpilledRegs() override { return RegsToSpill; } | ||
ArrayRef<Register> getReplacedRegs() override { return RegsReplaced; } | ||
void postOptimization() override; | ||
|
@@ -207,6 +211,7 @@ class InlineSpiller : public Spiller { | |
|
||
void markValueUsed(LiveInterval*, VNInfo*); | ||
bool canGuaranteeAssignmentAfterRemat(Register VReg, MachineInstr &MI); | ||
bool hasPhysRegAvailable(const MachineInstr &MI); | ||
bool reMaterializeFor(LiveInterval &, MachineInstr &MI); | ||
void reMaterializeAll(); | ||
|
||
|
@@ -229,8 +234,8 @@ void Spiller::anchor() {} | |
Spiller * | ||
llvm::createInlineSpiller(const InlineSpiller::RequiredAnalyses &Analyses, | ||
MachineFunction &MF, VirtRegMap &VRM, | ||
VirtRegAuxInfo &VRAI) { | ||
return new InlineSpiller(Analyses, MF, VRM, VRAI); | ||
VirtRegAuxInfo &VRAI, LiveRegMatrix *Matrix) { | ||
return new InlineSpiller(Analyses, MF, VRM, VRAI, Matrix); | ||
} | ||
|
||
//===----------------------------------------------------------------------===// | ||
|
@@ -615,6 +620,23 @@ bool InlineSpiller::canGuaranteeAssignmentAfterRemat(Register VReg, | |
return true; | ||
} | ||
|
||
/// hasPhysRegAvailable - Check if there is an available physical register for | ||
/// rematerialization. | ||
bool InlineSpiller::hasPhysRegAvailable(const MachineInstr &MI) { | ||
if (!Order || !Matrix) | ||
return false; | ||
|
||
SlotIndex UseIdx = LIS.getInstructionIndex(MI).getRegSlot(true); | ||
SlotIndex PrevIdx = UseIdx.getPrevSlot(); | ||
|
||
for (MCPhysReg PhysReg : *Order) { | ||
if (!Matrix->checkInterference(PrevIdx, UseIdx, PhysReg)) | ||
return true; | ||
} | ||
Comment on lines
+632
to
+635
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The inline spiller should not be doing full availability checks. This is algorithmically really bad. The existing tryAssign loop is bad enough There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Do you worry about compile time or something else? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yes. This is quite likely the single slowest operation in LLVM. The inline spiller should not need to do this and you should find another approach There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This function is called only when an MI has following properties:
I don't expect many instructions satisfy them. I will run a compile time test for it. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. It has almost no impact on compile time test. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. ping There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. ping, @arsenm There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Basically nothing here is going to matter for X86, this could be disastrous on a GPU. I also think this is conceptually not the way to address this problem, please revert |
||
|
||
return false; | ||
} | ||
|
||
/// reMaterializeFor - Attempt to rematerialize before MI instead of reloading. | ||
bool InlineSpiller::reMaterializeFor(LiveInterval &VirtReg, MachineInstr &MI) { | ||
// Analyze instruction | ||
|
@@ -661,6 +683,7 @@ bool InlineSpiller::reMaterializeFor(LiveInterval &VirtReg, MachineInstr &MI) { | |
// Before rematerializing into a register for a single instruction, try to | ||
// fold a load into the instruction. That avoids allocating a new register. | ||
if (RM.OrigMI->canFoldAsLoad() && | ||
(RM.OrigMI->mayLoad() || !hasPhysRegAvailable(MI)) && | ||
foldMemoryOperand(Ops, RM.OrigMI)) { | ||
Edit->markRematerialized(RM.ParentVNI); | ||
++NumFoldedLoads; | ||
|
@@ -1282,9 +1305,10 @@ void InlineSpiller::spillAll() { | |
Edit->eraseVirtReg(Reg); | ||
} | ||
|
||
void InlineSpiller::spill(LiveRangeEdit &edit) { | ||
void InlineSpiller::spill(LiveRangeEdit &edit, AllocationOrder *order) { | ||
++NumSpilledRanges; | ||
Edit = &edit; | ||
Order = order; | ||
assert(!edit.getReg().isStack() && "Trying to spill a stack slot."); | ||
// Share a stack slot among all descendants of Original. | ||
Original = VRM.getOriginal(edit.getReg()); | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should not be optional
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The InlineSpiller is used by multiple register allocators, but not all of them use AllocationOrder, so we may not always get a valid Order. Maybe that allocator(PBQP) should be fixed.