[llvm-branch-commits] [llvm] [TargetInstrInfo] Fix folding inline asm operands next to tied operands (PR #229627)

Bill Wendling via llvm-branch-commits llvm-branch-commits at lists.llvm.org
Thu Oct 8 00:19:52 PDT 2026


================
@@ -650,59 +650,112 @@ static MachineInstr *foldPatchpoint(MachineFunction &MF, MachineInstr &MI,
   return NewMI;
 }
 
-static void foldInlineAsmMemOperand(MachineInstr *MI, unsigned OpNo, int FI,
-                                    const TargetInstrInfo &TII) {
-  // If the machine operand is tied, untie it first.
-  if (MI->getOperand(OpNo).isTied()) {
-    unsigned TiedTo = MI->findTiedOperandIdx(OpNo);
-    MI->untieRegOperand(OpNo);
-    // Intentional recursion!
-    foldInlineAsmMemOperand(MI, TiedTo, FI, TII);
+/// Rewrite the register operands \p Ops of the inline asm \p MI to refer to
+/// stack slot \p FI. The use tied to a folded def is folded along with it,
+/// since the two name a single location.
+static void foldInlineAsmMemOperands(MachineInstr &MI, ArrayRef<unsigned> Ops,
+                                     int FI, const TargetInstrInfo &TII) {
+  SmallVector<MachineOperand, 5> MemOps;
+  TII.getFrameIndexOperands(MemOps, FI);
+  assert(!MemOps.empty() && "getFrameIndexOperands didn't create any operands");
+  InlineAsm::Flag MemFlag(InlineAsm::Kind::Mem, MemOps.size());
+  MemFlag.setMemConstraint(InlineAsm::ConstraintCode::m);
+
+  // Find the uses to fold along with their defs, and the ties to keep.
+  SmallVector<unsigned, 4> FoldOps(Ops);
+  SmallVector<std::pair<unsigned, unsigned>, 4> Ties;
+  for (unsigned I = InlineAsm::MIOp_FirstOperand, E = MI.getNumOperands();
+       I != E; ++I) {
+    const MachineOperand &MO = MI.getOperand(I);
+    if (!MO.isReg() || !MO.isTied() || !MO.isUse())
+      continue;
+
+    unsigned DefIdx = MI.findTiedOperandIdx(I);
+    if (is_contained(Ops, DefIdx))
+      FoldOps.push_back(I);
+    else
+      Ties.emplace_back(DefIdx, I);
   }
 
-  SmallVector<MachineOperand, 5> NewOps;
-  TII.getFrameIndexOperands(NewOps, FI);
-  assert(!NewOps.empty() && "getFrameIndexOperands didn't create any operands");
-  MI->removeOperand(OpNo);
-  MI->insert(MI->operands_begin() + OpNo, NewOps);
+  // A folded operand becomes MemOps.size() operands, moving every later one,
+  // and MachineInstr can't move a tied operand. So untie everything, re-add
+  // the operands from the first folded one on, and re-tie the pairs that are
+  // still registers at their new positions.
+  for (unsigned I = InlineAsm::MIOp_FirstOperand, E = MI.getNumOperands();
+       I != E; ++I)
+    MI.untieRegOperand(I);
+
+  unsigned First = *llvm::min_element(FoldOps);
----------------
isanbard wrote:

It looks like every call to this function ensures that `Opts` is not empty, but I suppose it's not horrible to. I'll add it in the calling function.

https://github.com/llvm/llvm-project/pull/229627


More information about the llvm-branch-commits mailing list