[llvm] 31b7f1f - [GlobalISel] Add support for value/constants as inline asm memory operand (#161501)
via llvm-commits
llvm-commits at lists.llvm.org
Fri Nov 14 01:34:42 PST 2025
Author: Pierre van Houtryve
Date: 2025-11-14T10:34:38+01:00
New Revision: 31b7f1fa0b8c24a7549d60d67faa882d5bf2eaae
URL: https://github.com/llvm/llvm-project/commit/31b7f1fa0b8c24a7549d60d67faa882d5bf2eaae
DIFF: https://github.com/llvm/llvm-project/commit/31b7f1fa0b8c24a7549d60d67faa882d5bf2eaae.diff
LOG: [GlobalISel] Add support for value/constants as inline asm memory operand (#161501)
InlineAsmLowering rejected inline assembly with memory reference inputs
if the values passed to the inline asm weren't pointers. The DAG
lowering however handled them just fine.
This patch updates InlineAsmLowering to store such values on the stack,
and then use the stack pointer as the "indirect" version of the operand.
Added:
Modified:
llvm/lib/CodeGen/GlobalISel/InlineAsmLowering.cpp
llvm/test/CodeGen/AArch64/GlobalISel/arm64-fallback.ll
llvm/test/CodeGen/AArch64/GlobalISel/irtranslator-inline-asm.ll
llvm/test/CodeGen/AMDGPU/GlobalISel/irtranslator-inline-asm.ll
Removed:
################################################################################
diff --git a/llvm/lib/CodeGen/GlobalISel/InlineAsmLowering.cpp b/llvm/lib/CodeGen/GlobalISel/InlineAsmLowering.cpp
index b4e64d7416d86..a8661ce629a4f 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,52 @@ 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);
+ if (SourceRegs.size() != 1) {
+ LLVM_DEBUG(dbgs() << "Expected the memory input to fit into a "
+ "single virtual register "
+ "for constraint '"
+ << OpInfo.ConstraintCode << "'\n");
+ return false;
+ }
+ 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]);
+ if (SourceRegs.size() != 1) {
+ LLVM_DEBUG(dbgs() << "Expected the memory input to fit into a single "
+ "virtual register "
+ "for constraint '"
+ << OpInfo.ConstraintCode << "'\n");
+ return false;
+ }
+ 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..8597ceb9ed87a 100644
--- a/llvm/test/CodeGen/AArch64/GlobalISel/irtranslator-inline-asm.ll
+++ b/llvm/test/CodeGen/AArch64/GlobalISel/irtranslator-inline-asm.ll
@@ -258,3 +258,96 @@ 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: [[C:%[0-9]+]]:_(s32) = G_CONSTANT i32 42
+ ; CHECK-NEXT: [[C1:%[0-9]+]]:_(s32) = G_CONSTANT i32 0
+ ; CHECK-NEXT: [[FRAME_INDEX:%[0-9]+]]:_(p0) = G_FRAME_INDEX %stack.0
+ ; CHECK-NEXT: G_STORE [[C]](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 [[C1]](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 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: [[C:%[0-9]+]]:_(s16) = G_CONSTANT i16 42
+ ; CHECK-NEXT: [[FRAME_INDEX:%[0-9]+]]:_(p0) = G_FRAME_INDEX %stack.0
+ ; CHECK-NEXT: G_STORE [[C]](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 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: [[C:%[0-9]+]]:_(s64) = G_CONSTANT i64 42
+ ; CHECK-NEXT: [[FRAME_INDEX:%[0-9]+]]:_(p0) = G_FRAME_INDEX %stack.0
+ ; CHECK-NEXT: G_STORE [[C]](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 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 70ff92f8eda92..b290c314f1154 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}
More information about the llvm-commits
mailing list