[llvm] [SafeStack] Don't move a scalable byval argument to the unsafe stack (PR #225067)
Timur Baidusenov via llvm-commits
llvm-commits at lists.llvm.org
Mon Sep 21 04:42:17 PDT 2026
https://github.com/bai-tim created https://github.com/llvm/llvm-project/pull/225067
The unsafe stack frame is laid out at compile time, but the size of a byval argument of a scalable type is not known then, so getTypeStoreSize() aborts with "Cannot implicitly convert a scalable size to a fixed-width size" before the argument is even classified. Skip it, the way MemCpyOpt bails out of the call-slot optimization for a byval argument of the same shape; the earlier 537f3d3a7588 fixed the other half of #182759, where the size of an access rather than of an argument was scalable.
Fixes #182759.
>From dbc21d3c752d1cae3c4defb31af2556328569801 Mon Sep 17 00:00:00 2001
From: Timur Baidusenov <timurbaidusenov at gmail.com>
Date: Fri, 18 Sep 2026 18:33:09 +0300
Subject: [PATCH] [SafeStack] Don't move a scalable byval argument to the
unsafe stack
The unsafe stack frame is laid out at compile time, but the size of a byval
argument of a scalable type is not known then, so getTypeStoreSize() aborts
with "Cannot implicitly convert a scalable size to a fixed-width size" before
the argument is even classified. Skip it, the way MemCpyOpt bails out of the
call-slot optimization for a byval argument of the same shape; the earlier
537f3d3a7588 fixed the other half of #182759, where the size of an access
rather than of an argument was scalable.
Fixes #182759.
---
llvm/lib/CodeGen/SafeStack.cpp | 9 +++++--
llvm/test/CodeGen/AArch64/safestack_scalar.ll | 26 +++++++++++++++++++
2 files changed, 33 insertions(+), 2 deletions(-)
diff --git a/llvm/lib/CodeGen/SafeStack.cpp b/llvm/lib/CodeGen/SafeStack.cpp
index 75a8762cc7090..07d8854a1629e 100644
--- a/llvm/lib/CodeGen/SafeStack.cpp
+++ b/llvm/lib/CodeGen/SafeStack.cpp
@@ -418,8 +418,13 @@ void SafeStack::findInsts(Function &F,
for (Argument &Arg : F.args()) {
if (!Arg.hasByValAttr())
continue;
- uint64_t Size = DL.getTypeStoreSize(Arg.getParamByValType());
- if (IsSafeStackAlloca(&Arg, Size))
+ TypeSize Size = DL.getTypeStoreSize(Arg.getParamByValType());
+ // The unsafe stack frame is laid out at compile time, so an argument of a
+ // scalable type has no place on it. Leave it on the regular stack rather
+ // than reject a function that is otherwise valid.
+ if (Size.isScalable())
+ continue;
+ if (IsSafeStackAlloca(&Arg, Size.getFixedValue()))
continue;
++NumUnsafeByValArguments;
diff --git a/llvm/test/CodeGen/AArch64/safestack_scalar.ll b/llvm/test/CodeGen/AArch64/safestack_scalar.ll
index f8675e7a709d3..0488218b6c848 100644
--- a/llvm/test/CodeGen/AArch64/safestack_scalar.ll
+++ b/llvm/test/CodeGen/AArch64/safestack_scalar.ll
@@ -15,3 +15,29 @@ entry:
; CHECK: load <vscale x 16 x i8>, ptr [[PTR]]
; CHECK: store ptr [[USP]], ptr @__safestack_unsafe_stack_ptr
; CHECK: ret void
+
+declare void @escape(ptr)
+
+; A byval argument of a scalable type has no size known at compile time, so it
+; cannot be placed on the unsafe stack frame and is left alone.
+
+define void @test_sve_byval(ptr byval(<vscale x 4 x i32>) %p) safestack {
+ call void @escape(ptr %p)
+ ret void
+}
+
+; CHECK-LABEL: define void @test_sve_byval(
+; CHECK-NEXT: call void @escape(ptr %p)
+; CHECK-NEXT: ret void
+
+; A byval argument of a fixed size is still copied onto the unsafe stack.
+
+define void @test_byval(ptr byval([16 x i8]) %p) safestack {
+ call void @escape(ptr %p)
+ ret void
+}
+
+; CHECK-LABEL: define void @test_byval(
+; CHECK: load ptr, ptr @__safestack_unsafe_stack_ptr
+; CHECK: call void @llvm.memcpy.p0.p0.i64(ptr align 4 [[SLOT:%.*]], ptr %p, i64 16, i1 false)
+; CHECK: call void @escape(ptr [[SLOT]])
More information about the llvm-commits
mailing list