[llvm] [GlobalISel] Add support for value/constants as inline asm memory operand (PR #161501)

Pierre van Houtryve via llvm-commits llvm-commits at lists.llvm.org
Tue Oct 28 05:42:22 PDT 2025


https://github.com/Pierre-vh updated https://github.com/llvm/llvm-project/pull/161501

>From 4b6c89e99b68312bfb2fcf38f8f5be8990ea74c6 Mon Sep 17 00:00:00 2001
From: pvanhout <pierre.vanhoutryve at amd.com>
Date: Tue, 28 Oct 2025 13:08:33 +0100
Subject: [PATCH 1/2] [GlobalISel] Add support for value/constants as inline
 asm memory operand

---
 .../CodeGen/GlobalISel/InlineAsmLowering.cpp  | 43 ++++++---
 .../AArch64/GlobalISel/arm64-fallback.ll      |  9 --
 .../GlobalISel/irtranslator-inline-asm.ll     | 85 +++++++++++++++++
 .../GlobalISel/irtranslator-inline-asm.ll     | 94 +++++++++++++++++++
 4 files changed, 209 insertions(+), 22 deletions(-)

diff --git a/llvm/lib/CodeGen/GlobalISel/InlineAsmLowering.cpp b/llvm/lib/CodeGen/GlobalISel/InlineAsmLowering.cpp
index b4e64d7416d86..67ff9d59a4e3a 100644
--- a/llvm/lib/CodeGen/GlobalISel/InlineAsmLowering.cpp
+++ b/llvm/lib/CodeGen/GlobalISel/InlineAsmLowering.cpp
@@ -13,6 +13,7 @@
 
 #include "llvm/CodeGen/GlobalISel/InlineAsmLowering.h"
 #include "llvm/CodeGen/GlobalISel/MachineIRBuilder.h"
+#include "llvm/CodeGen/MachineFrameInfo.h"
 #include "llvm/CodeGen/MachineOperand.h"
 #include "llvm/CodeGen/MachineRegisterInfo.h"
 #include "llvm/CodeGen/TargetLowering.h"
@@ -454,26 +455,42 @@ bool InlineAsmLowering::lowerInlineAsm(
       }
 
       if (OpInfo.ConstraintType == TargetLowering::C_Memory) {
-
-        if (!OpInfo.isIndirect) {
-          LLVM_DEBUG(dbgs()
-                     << "Cannot indirectify memory input operands yet\n");
-          return false;
-        }
-
-        assert(OpInfo.isIndirect && "Operand must be indirect to be a mem!");
-
         const InlineAsm::ConstraintCode ConstraintID =
             TLI->getInlineAsmMemConstraint(OpInfo.ConstraintCode);
         InlineAsm::Flag OpFlags(InlineAsm::Kind::Mem, 1);
         OpFlags.setMemConstraint(ConstraintID);
         Inst.addImm(OpFlags);
+
+        if (OpInfo.isIndirect) {
+          // already indirect
+          ArrayRef<Register> SourceRegs =
+              GetOrCreateVRegs(*OpInfo.CallOperandVal);
+          assert(SourceRegs.size() == 1 && "Expected the memory input to fit "
+                                           "into a single virtual register");
+          Inst.addReg(SourceRegs[0]);
+          break;
+        }
+
+        // Needs to be made indirect. Store the value on the stack and use
+        // a pointer to it.
+        Value *OpVal = OpInfo.CallOperandVal;
+        unsigned Bytes = DL.getTypeStoreSize(OpVal->getType());
+        Align Alignment = DL.getPrefTypeAlign(OpVal->getType());
+        int FrameIdx =
+            MF.getFrameInfo().CreateStackObject(Bytes, Alignment, false);
+
+        unsigned AddrSpace = DL.getAllocaAddrSpace();
+        LLT FramePtrTy =
+            LLT::pointer(AddrSpace, DL.getPointerSizeInBits(AddrSpace));
+        auto Ptr = MIRBuilder.buildFrameIndex(FramePtrTy, FrameIdx).getReg(0);
         ArrayRef<Register> SourceRegs =
             GetOrCreateVRegs(*OpInfo.CallOperandVal);
-        assert(
-            SourceRegs.size() == 1 &&
-            "Expected the memory input to fit into a single virtual register");
-        Inst.addReg(SourceRegs[0]);
+        assert(SourceRegs.size() == 1 && "Expected the memory input to fit "
+                                          "into a single virtual register");
+        MIRBuilder.buildStore(SourceRegs[0], Ptr,
+                              MachinePointerInfo::getFixedStack(MF, FrameIdx),
+                              Alignment);
+        Inst.addReg(Ptr);
         break;
       }
 
diff --git a/llvm/test/CodeGen/AArch64/GlobalISel/arm64-fallback.ll b/llvm/test/CodeGen/AArch64/GlobalISel/arm64-fallback.ll
index 29c320da6c0a7..f8cd868a4c755 100644
--- a/llvm/test/CodeGen/AArch64/GlobalISel/arm64-fallback.ll
+++ b/llvm/test/CodeGen/AArch64/GlobalISel/arm64-fallback.ll
@@ -37,15 +37,6 @@ define i64 @strict_align_feature(ptr %p) #0 {
 
 attributes #0 = { "target-features"="+strict-align" }
 
-; FALLBACK-WITH-REPORT-ERR: remark: <unknown>:0:0: unable to translate instruction: call
-; FALLBACK-WITH-REPORT-ERR: warning: Instruction selection used fallback path for direct_mem
-; FALLBACK-WITH-REPORT-OUT-LABEL: direct_mem
-define void @direct_mem(i32 %x, i32 %y) {
-entry:
-  tail call void asm sideeffect "", "imr,imr,~{memory}"(i32 %x, i32 %y)
-  ret void
-}
-
 ; FALLBACK-WITH-REPORT-ERR: remark: <unknown>:0:0: unable to lower function{{.*}}scalable_arg
 ; FALLBACK-WITH-REPORT-OUT-LABEL: scalable_arg
 define <vscale x 16 x i8> @scalable_arg(<vscale x 16 x i1> %pred, ptr %addr) #1 {
diff --git a/llvm/test/CodeGen/AArch64/GlobalISel/irtranslator-inline-asm.ll b/llvm/test/CodeGen/AArch64/GlobalISel/irtranslator-inline-asm.ll
index 42f6570047fc7..c5e0d1ac4b33a 100644
--- a/llvm/test/CodeGen/AArch64/GlobalISel/irtranslator-inline-asm.ll
+++ b/llvm/test/CodeGen/AArch64/GlobalISel/irtranslator-inline-asm.ll
@@ -258,3 +258,88 @@ define i64 @test_input_with_matching_constraint_to_physical_register() {
   %1 = tail call i64 asm "", "={x2},0"(i64 0)
   ret i64 %1
 }
+
+define void @test_indirectify_i32_value(i32 %x, i32 %y) {
+  ; CHECK-LABEL: name: test_indirectify_i32_value
+  ; CHECK: bb.1.entry:
+  ; CHECK-NEXT:   liveins: $w0, $w1
+  ; CHECK-NEXT: {{  $}}
+  ; CHECK-NEXT:   [[COPY:%[0-9]+]]:_(s32) = COPY $w0
+  ; CHECK-NEXT:   [[COPY1:%[0-9]+]]:_(s32) = COPY $w1
+  ; CHECK-NEXT:   [[FRAME_INDEX:%[0-9]+]]:_(p0) = G_FRAME_INDEX %stack.0
+  ; CHECK-NEXT:   G_STORE [[COPY]](s32), [[FRAME_INDEX]](p0) :: (store (s32) into %stack.0)
+  ; CHECK-NEXT:   [[FRAME_INDEX1:%[0-9]+]]:_(p0) = G_FRAME_INDEX %stack.1
+  ; CHECK-NEXT:   G_STORE [[COPY1]](s32), [[FRAME_INDEX1]](p0) :: (store (s32) into %stack.1)
+  ; CHECK-NEXT:   INLINEASM &"", 25 /* sideeffect mayload maystore attdialect */, {{[0-9]+}} /* mem:m */, [[FRAME_INDEX]](p0), 262158 /* mem:m */, [[FRAME_INDEX1]](p0)
+  ; CHECK-NEXT:   RET_ReallyLR
+entry:
+  tail call void asm sideeffect "", "imr,imr,~{memory}"(i32 %x, i32 %y)
+  ret void
+}
+
+define void @test_indirectify_i32_constant() {
+  ; CHECK-LABEL: name: test_indirectify_i32_constant
+  ; CHECK: bb.1.entry:
+  ; CHECK-NEXT:   [[CONSTANT_POOL:%[0-9]+]]:_(p0) = G_CONSTANT_POOL %const.0
+  ; CHECK-NEXT:   [[CONSTANT_POOL1:%[0-9]+]]:_(p0) = G_CONSTANT_POOL %const.1
+  ; CHECK-NEXT:   INLINEASM &"", 25 /* sideeffect mayload maystore attdialect */, {{[0-9]+}} /* mem:m */, [[CONSTANT_POOL]](p0), 262158 /* mem:m */, [[CONSTANT_POOL1]](p0)
+  ; CHECK-NEXT:   RET_ReallyLR
+entry:
+  tail call void asm sideeffect "", "imr,imr,~{memory}"(i32 42, i32 0)
+  ret void
+}
+
+define void @test_indirectify_i16_value(i16 %val) {
+  ; CHECK-LABEL: name: test_indirectify_i16_value
+  ; CHECK: bb.1.entry:
+  ; CHECK-NEXT:   liveins: $w0
+  ; CHECK-NEXT: {{  $}}
+  ; CHECK-NEXT:   [[COPY:%[0-9]+]]:_(s32) = COPY $w0
+  ; CHECK-NEXT:   [[TRUNC:%[0-9]+]]:_(s16) = G_TRUNC [[COPY]](s32)
+  ; CHECK-NEXT:   [[FRAME_INDEX:%[0-9]+]]:_(p0) = G_FRAME_INDEX %stack.0
+  ; CHECK-NEXT:   G_STORE [[TRUNC]](s16), [[FRAME_INDEX]](p0) :: (store (s16) into %stack.0)
+  ; CHECK-NEXT:   INLINEASM &"", 25 /* sideeffect mayload maystore attdialect */, {{[0-9]+}} /* mem:m */, [[FRAME_INDEX]](p0)
+  ; CHECK-NEXT:   RET_ReallyLR
+entry:
+  tail call void asm sideeffect "", "imr,~{memory}"(i16 %val)
+  ret void
+}
+
+define void @test_indirectify_i16_constant() {
+  ; CHECK-LABEL: name: test_indirectify_i16_constant
+  ; CHECK: bb.1.entry:
+  ; CHECK-NEXT:   [[CONSTANT_POOL:%[0-9]+]]:_(p0) = G_CONSTANT_POOL %const.0
+  ; CHECK-NEXT:   INLINEASM &"", 25 /* sideeffect mayload maystore attdialect */, {{[0-9]+}} /* mem:m */, [[CONSTANT_POOL]](p0)
+  ; CHECK-NEXT:   RET_ReallyLR
+entry:
+  tail call void asm sideeffect "", "imr,~{memory}"(i16 42)
+  ret void
+}
+
+define void @test_indirectify_i64_value(i64 %val) {
+  ; CHECK-LABEL: name: test_indirectify_i64_value
+  ; CHECK: bb.1.entry:
+  ; CHECK-NEXT:   liveins: $x0
+  ; CHECK-NEXT: {{  $}}
+  ; CHECK-NEXT:   [[COPY:%[0-9]+]]:_(s64) = COPY $x0
+  ; CHECK-NEXT:   [[FRAME_INDEX:%[0-9]+]]:_(p0) = G_FRAME_INDEX %stack.0
+  ; CHECK-NEXT:   G_STORE [[COPY]](s64), [[FRAME_INDEX]](p0) :: (store (s64) into %stack.0)
+  ; CHECK-NEXT:   INLINEASM &"", 25 /* sideeffect mayload maystore attdialect */, {{[0-9]+}} /* mem:m */, [[FRAME_INDEX]](p0)
+  ; CHECK-NEXT:   RET_ReallyLR
+entry:
+  tail call void asm sideeffect "", "imr,~{memory}"(i64 %val)
+  ret void
+}
+
+define void @test_indirectify_i64_constant() {
+  ; CHECK-LABEL: name: test_indirectify_i64_constant
+  ; CHECK: bb.1.entry:
+  ; CHECK-NEXT:   [[CONSTANT_POOL:%[0-9]+]]:_(p0) = G_CONSTANT_POOL %const.0
+  ; CHECK-NEXT:   INLINEASM &"", 25 /* sideeffect mayload maystore attdialect */, {{[0-9]+}} /* mem:m */, [[CONSTANT_POOL]](p0)
+  ; CHECK-NEXT:   RET_ReallyLR
+entry:
+  tail call void asm sideeffect "", "imr,~{memory}"(i64 42)
+  ret void
+}
+
+; TODO: add more types
diff --git a/llvm/test/CodeGen/AMDGPU/GlobalISel/irtranslator-inline-asm.ll b/llvm/test/CodeGen/AMDGPU/GlobalISel/irtranslator-inline-asm.ll
index e5cd0710359ac..a0dccc7a4a4dd 100644
--- a/llvm/test/CodeGen/AMDGPU/GlobalISel/irtranslator-inline-asm.ll
+++ b/llvm/test/CodeGen/AMDGPU/GlobalISel/irtranslator-inline-asm.ll
@@ -331,6 +331,100 @@ define amdgpu_kernel void @asm_constraint_n_n()  {
   ret void
 }
 
+define void @test_indirectify_i32_value(i32 %x, i32 %y) {
+  ; CHECK-LABEL: name: test_indirectify_i32_value
+  ; CHECK: bb.1.entry:
+  ; CHECK-NEXT:   liveins: $vgpr0, $vgpr1
+  ; CHECK-NEXT: {{  $}}
+  ; CHECK-NEXT:   [[COPY:%[0-9]+]]:_(s32) = COPY $vgpr0
+  ; CHECK-NEXT:   [[COPY1:%[0-9]+]]:_(s32) = COPY $vgpr1
+  ; CHECK-NEXT:   [[FRAME_INDEX:%[0-9]+]]:_(p5) = G_FRAME_INDEX %stack.0
+  ; CHECK-NEXT:   G_STORE [[COPY]](s32), [[FRAME_INDEX]](p5) :: (store (s32) into %stack.0, addrspace 5)
+  ; CHECK-NEXT:   [[FRAME_INDEX1:%[0-9]+]]:_(p5) = G_FRAME_INDEX %stack.1
+  ; CHECK-NEXT:   G_STORE [[COPY1]](s32), [[FRAME_INDEX1]](p5) :: (store (s32) into %stack.1, addrspace 5)
+  ; CHECK-NEXT:   INLINEASM &"", 25 /* sideeffect mayload maystore attdialect */, 262158 /* mem:m */, [[FRAME_INDEX]](p5), 262158 /* mem:m */, [[FRAME_INDEX1]](p5)
+  ; CHECK-NEXT:   SI_RETURN
+entry:
+  tail call void asm sideeffect "", "imr,imr,~{memory}"(i32 %x, i32 %y)
+  ret void
+}
+
+define void @test_indirectify_i32_constant() {
+  ; CHECK-LABEL: name: test_indirectify_i32_constant
+  ; CHECK: bb.1.entry:
+  ; CHECK-NEXT:   [[C:%[0-9]+]]:_(s32) = G_CONSTANT i32 42
+  ; CHECK-NEXT:   [[C1:%[0-9]+]]:_(s32) = G_CONSTANT i32 0
+  ; CHECK-NEXT:   [[FRAME_INDEX:%[0-9]+]]:_(p5) = G_FRAME_INDEX %stack.0
+  ; CHECK-NEXT:   G_STORE [[C]](s32), [[FRAME_INDEX]](p5) :: (store (s32) into %stack.0, addrspace 5)
+  ; CHECK-NEXT:   [[FRAME_INDEX1:%[0-9]+]]:_(p5) = G_FRAME_INDEX %stack.1
+  ; CHECK-NEXT:   G_STORE [[C1]](s32), [[FRAME_INDEX1]](p5) :: (store (s32) into %stack.1, addrspace 5)
+  ; CHECK-NEXT:   INLINEASM &"", 25 /* sideeffect mayload maystore attdialect */, 262158 /* mem:m */, [[FRAME_INDEX]](p5), 262158 /* mem:m */, [[FRAME_INDEX1]](p5)
+  ; CHECK-NEXT:   SI_RETURN
+entry:
+  tail call void asm sideeffect "", "imr,imr,~{memory}"(i32 42, i32 0)
+  ret void
+}
+
+
+define void @test_indirectify_i16_value(i16 %val) {
+  ; CHECK-LABEL: name: test_indirectify_i16_value
+  ; CHECK: bb.1.entry:
+  ; CHECK-NEXT:   liveins: $vgpr0
+  ; CHECK-NEXT: {{  $}}
+  ; CHECK-NEXT:   [[COPY:%[0-9]+]]:_(s32) = COPY $vgpr0
+  ; CHECK-NEXT:   [[TRUNC:%[0-9]+]]:_(s16) = G_TRUNC [[COPY]](s32)
+  ; CHECK-NEXT:   [[FRAME_INDEX:%[0-9]+]]:_(p5) = G_FRAME_INDEX %stack.0
+  ; CHECK-NEXT:   G_STORE [[TRUNC]](s16), [[FRAME_INDEX]](p5) :: (store (s16) into %stack.0, addrspace 5)
+  ; CHECK-NEXT:   INLINEASM &"", 25 /* sideeffect mayload maystore attdialect */, 262158 /* mem:m */, [[FRAME_INDEX]](p5)
+  ; CHECK-NEXT:   SI_RETURN
+entry:
+  tail call void asm sideeffect "", "imr,~{memory}"(i16 %val)
+  ret void
+}
+
+define void @test_indirectify_i16_constant() {
+  ; CHECK-LABEL: name: test_indirectify_i16_constant
+  ; CHECK: bb.1.entry:
+  ; CHECK-NEXT:   [[C:%[0-9]+]]:_(s16) = G_CONSTANT i16 42
+  ; CHECK-NEXT:   [[FRAME_INDEX:%[0-9]+]]:_(p5) = G_FRAME_INDEX %stack.0
+  ; CHECK-NEXT:   G_STORE [[C]](s16), [[FRAME_INDEX]](p5) :: (store (s16) into %stack.0, addrspace 5)
+  ; CHECK-NEXT:   INLINEASM &"", 25 /* sideeffect mayload maystore attdialect */, 262158 /* mem:m */, [[FRAME_INDEX]](p5)
+  ; CHECK-NEXT:   SI_RETURN
+entry:
+  tail call void asm sideeffect "", "imr,~{memory}"(i16 42)
+  ret void
+}
+
+define void @test_indirectify_i64_value(i64 %val) {
+  ; CHECK-LABEL: name: test_indirectify_i64_value
+  ; CHECK: bb.1.entry:
+  ; CHECK-NEXT:   liveins: $vgpr0, $vgpr1
+  ; CHECK-NEXT: {{  $}}
+  ; CHECK-NEXT:   [[COPY:%[0-9]+]]:_(s32) = COPY $vgpr0
+  ; CHECK-NEXT:   [[COPY1:%[0-9]+]]:_(s32) = COPY $vgpr1
+  ; CHECK-NEXT:   [[MV:%[0-9]+]]:_(s64) = G_MERGE_VALUES [[COPY]](s32), [[COPY1]](s32)
+  ; CHECK-NEXT:   [[FRAME_INDEX:%[0-9]+]]:_(p5) = G_FRAME_INDEX %stack.0
+  ; CHECK-NEXT:   G_STORE [[MV]](s64), [[FRAME_INDEX]](p5) :: (store (s64) into %stack.0, addrspace 5)
+  ; CHECK-NEXT:   INLINEASM &"", 25 /* sideeffect mayload maystore attdialect */, 262158 /* mem:m */, [[FRAME_INDEX]](p5)
+  ; CHECK-NEXT:   SI_RETURN
+entry:
+  tail call void asm sideeffect "", "imr,~{memory}"(i64 %val)
+  ret void
+}
+
+define void @test_indirectify_i64_constant() {
+  ; CHECK-LABEL: name: test_indirectify_i64_constant
+  ; CHECK: bb.1.entry:
+  ; CHECK-NEXT:   [[C:%[0-9]+]]:_(s64) = G_CONSTANT i64 42
+  ; CHECK-NEXT:   [[FRAME_INDEX:%[0-9]+]]:_(p5) = G_FRAME_INDEX %stack.0
+  ; CHECK-NEXT:   G_STORE [[C]](s64), [[FRAME_INDEX]](p5) :: (store (s64) into %stack.0, addrspace 5)
+  ; CHECK-NEXT:   INLINEASM &"", 25 /* sideeffect mayload maystore attdialect */, 262158 /* mem:m */, [[FRAME_INDEX]](p5)
+  ; CHECK-NEXT:   SI_RETURN
+entry:
+  tail call void asm sideeffect "", "imr,~{memory}"(i64 42)
+  ret void
+}
+
 !llvm.module.flags = !{!1}
 !0 = !{i32 70}
 !1 = !{i32 1, !"amdhsa_code_object_version", i32 500}

>From 198bfb589a2b4d54e43f02befadf5355943b5684 Mon Sep 17 00:00:00 2001
From: pvanhout <pierre.vanhoutryve at amd.com>
Date: Tue, 28 Oct 2025 13:42:06 +0100
Subject: [PATCH 2/2] clang-format

---
 llvm/lib/CodeGen/GlobalISel/InlineAsmLowering.cpp | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/llvm/lib/CodeGen/GlobalISel/InlineAsmLowering.cpp b/llvm/lib/CodeGen/GlobalISel/InlineAsmLowering.cpp
index 67ff9d59a4e3a..dd352db7cc377 100644
--- a/llvm/lib/CodeGen/GlobalISel/InlineAsmLowering.cpp
+++ b/llvm/lib/CodeGen/GlobalISel/InlineAsmLowering.cpp
@@ -486,7 +486,7 @@ bool InlineAsmLowering::lowerInlineAsm(
         ArrayRef<Register> SourceRegs =
             GetOrCreateVRegs(*OpInfo.CallOperandVal);
         assert(SourceRegs.size() == 1 && "Expected the memory input to fit "
-                                          "into a single virtual register");
+                                         "into a single virtual register");
         MIRBuilder.buildStore(SourceRegs[0], Ptr,
                               MachinePointerInfo::getFixedStack(MF, FrameIdx),
                               Alignment);



More information about the llvm-commits mailing list