Skip to content

Commit 99ee2db

Browse files
[TargetInstrInfo] enable foldMemoryOperand for InlineAsm (#70743)
foldMemoryOperand looks at pairs of instructions (generally a load to virt reg then use of the virtreg, or def of a virtreg then a store) and attempts to combine them. This can reduce register pressure. A prior commit added the ability to mark such a MachineOperand as foldable. In terms of INLINEASM, this means that "rm" was used (rather than just "r") to denote that the INLINEASM may use a memory operand rather than a register operand. This effectively undoes decisions made by the instruction selection framework. Callers will be added in the register allocation frameworks. This has been tested with all of the above (which will come as follow up patches). Thanks to @topperc who suggested this at last years LLVM US Dev Meeting and @qcolombet who confirmed this was the right approach. Link: #20571
1 parent f99a020 commit 99ee2db

File tree

2 files changed

+72
-0
lines changed

2 files changed

+72
-0
lines changed

llvm/include/llvm/CodeGen/TargetInstrInfo.h

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2188,6 +2188,16 @@ class TargetInstrInfo : public MCInstrInfo {
21882188
// Get the call frame size just before MI.
21892189
unsigned getCallFrameSizeAt(MachineInstr &MI) const;
21902190

2191+
/// Fills in the necessary MachineOperands to refer to a frame index.
2192+
/// The best way to understand this is to print `asm(""::"m"(x));` after
2193+
/// finalize-isel. Example:
2194+
/// INLINEASM ... 262190 /* mem:m */, %stack.0.x.addr, 1, $noreg, 0, $noreg
2195+
/// we would add placeholders for: ^ ^ ^ ^
2196+
virtual void
2197+
getFrameIndexOperands(SmallVectorImpl<MachineOperand> &Ops) const {
2198+
llvm_unreachable("unknown number of operands necessary");
2199+
}
2200+
21912201
private:
21922202
mutable std::unique_ptr<MIRFormatter> Formatter;
21932203
unsigned CallFrameSetupOpcode, CallFrameDestroyOpcode;

llvm/lib/CodeGen/TargetInstrInfo.cpp

Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -565,6 +565,64 @@ static MachineInstr *foldPatchpoint(MachineFunction &MF, MachineInstr &MI,
565565
return NewMI;
566566
}
567567

568+
static void foldInlineAsmMemOperand(MachineInstr *MI, unsigned OpNo, int FI,
569+
const TargetInstrInfo &TII) {
570+
MachineOperand &MO = MI->getOperand(OpNo);
571+
const VirtRegInfo &RI = AnalyzeVirtRegInBundle(*MI, MO.getReg());
572+
573+
// If the machine operand is tied, untie it first.
574+
if (MO.isTied()) {
575+
unsigned TiedTo = MI->findTiedOperandIdx(OpNo);
576+
MI->untieRegOperand(OpNo);
577+
// Intentional recursion!
578+
foldInlineAsmMemOperand(MI, TiedTo, FI, TII);
579+
}
580+
581+
// Change the operand from a register to a frame index.
582+
MO.ChangeToFrameIndex(FI, MO.getTargetFlags());
583+
584+
SmallVector<MachineOperand, 4> NewOps;
585+
TII.getFrameIndexOperands(NewOps);
586+
assert(!NewOps.empty() && "getFrameIndexOperands didn't create any operands");
587+
MI->insert(MI->operands_begin() + OpNo + 1, NewOps);
588+
589+
// Change the previous operand to a MemKind InlineAsm::Flag. The second param
590+
// is the per-target number of operands that represent the memory operand
591+
// excluding this one (MD). This includes MO.
592+
InlineAsm::Flag F(InlineAsm::Kind::Mem, NewOps.size() + 1);
593+
F.setMemConstraint(InlineAsm::ConstraintCode::m);
594+
MachineOperand &MD = MI->getOperand(OpNo - 1);
595+
MD.setImm(F);
596+
597+
// Update mayload/maystore metadata.
598+
MachineOperand &ExtraMO = MI->getOperand(InlineAsm::MIOp_ExtraInfo);
599+
if (RI.Reads)
600+
ExtraMO.setImm(ExtraMO.getImm() | InlineAsm::Extra_MayLoad);
601+
if (RI.Writes)
602+
ExtraMO.setImm(ExtraMO.getImm() | InlineAsm::Extra_MayStore);
603+
}
604+
605+
// Returns nullptr if not possible to fold.
606+
static MachineInstr *foldInlineAsmMemOperand(MachineInstr &MI,
607+
ArrayRef<unsigned> Ops, int FI,
608+
const TargetInstrInfo &TII) {
609+
assert(MI.isInlineAsm() && "wrong opcode");
610+
if (Ops.size() > 1)
611+
return nullptr;
612+
unsigned Op = Ops[0];
613+
assert(Op && "should never be first operand");
614+
assert(MI.getOperand(Op).isReg() && "shouldn't be folding non-reg operands");
615+
616+
if (!MI.mayFoldInlineAsmRegOp(Op))
617+
return nullptr;
618+
619+
MachineInstr &NewMI = TII.duplicate(*MI.getParent(), MI.getIterator(), MI);
620+
621+
foldInlineAsmMemOperand(&NewMI, Op, FI, TII);
622+
623+
return &NewMI;
624+
}
625+
568626
MachineInstr *TargetInstrInfo::foldMemoryOperand(MachineInstr &MI,
569627
ArrayRef<unsigned> Ops, int FI,
570628
LiveIntervals *LIS,
@@ -612,6 +670,8 @@ MachineInstr *TargetInstrInfo::foldMemoryOperand(MachineInstr &MI,
612670
NewMI = foldPatchpoint(MF, MI, Ops, FI, *this);
613671
if (NewMI)
614672
MBB->insert(MI, NewMI);
673+
} else if (MI.isInlineAsm()) {
674+
NewMI = foldInlineAsmMemOperand(MI, Ops, FI, *this);
615675
} else {
616676
// Ask the target to do the actual folding.
617677
NewMI = foldMemoryOperandImpl(MF, MI, Ops, MI, FI, LIS, VRM);
@@ -683,6 +743,8 @@ MachineInstr *TargetInstrInfo::foldMemoryOperand(MachineInstr &MI,
683743
NewMI = foldPatchpoint(MF, MI, Ops, FrameIndex, *this);
684744
if (NewMI)
685745
NewMI = &*MBB.insert(MI, NewMI);
746+
} else if (MI.isInlineAsm() && isLoadFromStackSlot(LoadMI, FrameIndex)) {
747+
NewMI = foldInlineAsmMemOperand(MI, Ops, FrameIndex, *this);
686748
} else {
687749
// Ask the target to do the actual folding.
688750
NewMI = foldMemoryOperandImpl(MF, MI, Ops, MI, LoadMI, LIS);

0 commit comments

Comments
 (0)