[llvm-branch-commits] [llvm] [CodeGen] Keep an inline asm's memory accesses described after a fold (PR #235634)

Bill Wendling via llvm-branch-commits llvm-branch-commits at lists.llvm.org
Mon Oct 26 00:34:09 PDT 2026


https://github.com/isanbard created https://github.com/llvm/llvm-project/pull/235634

The memoperands of an instruction describe all of its memory accesses. Folding gave an inline asm a single memoperand, for the stack slot, which said that it accessed no other memory even when it had an "m" operand or a "memory" clobber. Without memoperands, the asm was taken to access any memory, so it now gets one for any memory as well.

Assisted-by: Claude Opus 5.5


>From c2f5cf3cfaa6dd4d50df3bcdbfdfb6c1755a5729 Mon Sep 17 00:00:00 2001
From: Bill Wendling <isanbard at gmail.com>
Date: Mon, 26 Oct 2026 00:20:40 -0700
Subject: [PATCH] [CodeGen] Keep an inline asm's memory accesses described
 after a fold

The memoperands of an instruction describe all of its memory accesses.
Folding gave an inline asm a single memoperand, for the stack slot,
which said that it accessed no other memory even when it had an "m"
operand or a "memory" clobber. Without memoperands, the asm was taken to
access any memory, so it now gets one for any memory as well.

Assisted-by: Claude Opus 5.5
---
 llvm/lib/CodeGen/TargetInstrInfo.cpp          | 15 +++++++
 .../CodeGen/X86/greedy-inline-asm-fold.mir    | 41 +++++++++++++++++++
 2 files changed, 56 insertions(+)

diff --git a/llvm/lib/CodeGen/TargetInstrInfo.cpp b/llvm/lib/CodeGen/TargetInstrInfo.cpp
index 5de5fac41b000..81cd2cfc93693 100644
--- a/llvm/lib/CodeGen/TargetInstrInfo.cpp
+++ b/llvm/lib/CodeGen/TargetInstrInfo.cpp
@@ -788,6 +788,21 @@ static MachineInstr *foldInlineAsmMemOperand(MachineInstr &MI,
     Flags |= MachineMemOperand::MOStore;
   }
 
+  // The memoperands of an instruction describe all of its memory accesses. An
+  // asm without any may still access memory, e.g. through an "m" operand or a
+  // "memory" clobber, so give it one for any memory as well as the slot's.
+  if (MI.memoperands_empty() && (MI.mayLoad() || MI.mayStore())) {
+    MachineMemOperand::Flags OtherFlags = MachineMemOperand::MONone;
+    if (MI.mayLoad())
+      OtherFlags |= MachineMemOperand::MOLoad;
+    if (MI.mayStore())
+      OtherFlags |= MachineMemOperand::MOStore;
+    NewMI.addMemOperand(
+        MF, MF.getMachineMemOperand(MachinePointerInfo(), OtherFlags,
+                                    LocationSize::beforeOrAfterPointer(),
+                                    Align(1)));
+  }
+
   const MachineFrameInfo &MFI = MF.getFrameInfo();
   MachineMemOperand *MMO =
       MF.getMachineMemOperand(MachinePointerInfo::getFixedStack(MF, FI), Flags,
diff --git a/llvm/test/CodeGen/X86/greedy-inline-asm-fold.mir b/llvm/test/CodeGen/X86/greedy-inline-asm-fold.mir
index 1f870984228c1..5b9c791d65e7a 100644
--- a/llvm/test/CodeGen/X86/greedy-inline-asm-fold.mir
+++ b/llvm/test/CodeGen/X86/greedy-inline-asm-fold.mir
@@ -447,6 +447,47 @@ body: |
     RET 0
 ...
 ---
+# The memoperands of an instruction describe all of its memory accesses, so
+# the stack slot's isn't added to an asm that accesses other memory without
+# memoperands, here through an "=m" output.
+#
+#   void rm_and_m(long a, long b, long c, long d, long e, long f, long g) {
+#     long x;
+#     asm volatile("" : "=m"(x) : "rm"(a), "r"(b), "r"(c), "r"(d), "r"(e),
+#                                 "r"(f), "r"(g) : CLOBBERS);
+#   }
+name: rm_and_m
+tracksRegLiveness: true
+fixedStack:
+  - { id: 0, size: 8, alignment: 16, isImmutable: true }
+stack:
+  - { id: 0, size: 8, alignment: 8 }
+body: |
+  bb.0:
+    liveins: $rdi, $rsi, $rdx, $rcx, $r8, $r9
+    ; CHECK-LABEL: name: rm_and_m
+    ; CHECK: liveins: $rdi, $rsi, $rdx, $rcx, $r8, $r9
+    ; CHECK-NEXT: {{  $}}
+    ; CHECK-NEXT: MOV64mr %stack.1, 1, $noreg, 0, $noreg, $rdi :: (store (s64) into %stack.1)
+    ; CHECK-NEXT: [[COPY:%[0-9]+]]:gr64 = COPY $rsi
+    ; CHECK-NEXT: [[COPY1:%[0-9]+]]:gr64 = COPY $rdx
+    ; CHECK-NEXT: [[COPY2:%[0-9]+]]:gr64 = COPY $rcx
+    ; CHECK-NEXT: [[COPY3:%[0-9]+]]:gr64 = COPY $r8
+    ; CHECK-NEXT: [[COPY4:%[0-9]+]]:gr64 = COPY $r9
+    ; CHECK-NEXT: [[MOV64rm:%[0-9]+]]:gr64 = MOV64rm %fixed-stack.0, 1, $noreg, 0, $noreg :: (load (s64) from %fixed-stack.0, align 16)
+    ; CHECK-NEXT: INLINEASM &"", sideeffect mayload maystore attdialect, mem:m ops:5, %stack.0, 1, $noreg, 0, $noreg, mem:m ops:5, %stack.1, 1, $noreg, 0, $noreg, reguse:GR64, [[COPY]], reguse:GR64, [[COPY1]], reguse:GR64, [[COPY2]], reguse:GR64, [[COPY3]], reguse:GR64, [[COPY4]], reguse:GR64, [[MOV64rm]], clobber, implicit-def dead early-clobber $rax, clobber, implicit-def dead early-clobber $rbx, clobber, implicit-def dead early-clobber $rbp, clobber, implicit-def dead early-clobber $r10, clobber, implicit-def dead early-clobber $r11, clobber, implicit-def dead early-clobber $r12, clobber, implicit-def dead early-clobber $r13, clobber, implicit-def dead early-clobber $r14, clobber, implicit-def dead early-clobber $r15 :: (store unknown-size, align 1), (load (s64) from %stack.1)
+    ; CHECK-NEXT: RET 0
+    %0:gr64 = COPY $rdi
+    %1:gr64 = COPY $rsi
+    %2:gr64 = COPY $rdx
+    %3:gr64 = COPY $rcx
+    %4:gr64 = COPY $r8
+    %5:gr64 = COPY $r9
+    %6:gr64 = MOV64rm %fixed-stack.0, 1, $noreg, 0, $noreg :: (load (s64) from %fixed-stack.0, align 16)
+    INLINEASM &"", sideeffect maystore attdialect, mem:m ops:5, %stack.0, 1, $noreg, 0, $noreg, reguse:GR64 foldable, %0, reguse:GR64, %1, reguse:GR64, %2, reguse:GR64, %3, reguse:GR64, %4, reguse:GR64, %5, reguse:GR64, %6, clobber, implicit-def dead early-clobber $rax, clobber, implicit-def dead early-clobber $rbx, clobber, implicit-def dead early-clobber $rbp, clobber, implicit-def dead early-clobber $r10, clobber, implicit-def dead early-clobber $r11, clobber, implicit-def dead early-clobber $r12, clobber, implicit-def dead early-clobber $r13, clobber, implicit-def dead early-clobber $r14, clobber, implicit-def dead early-clobber $r15
+    RET 0
+...
+---
 # A constant passed to an "rm" operand is spilled and folded rather than
 # rematerialized into a register, which would need a register that the asm
 # doesn't leave.



More information about the llvm-branch-commits mailing list