diff --git a/gcc/config/aarch64/aarch64.cc b/gcc/config/aarch64/aarch64.cc
index bfd7bcdef7cb9baee33b5ae1c8054e3bcd907c60..4e312c435769b5d6cdf10be330d15a59ea52dce6 100644
--- a/gcc/config/aarch64/aarch64.cc
+++ b/gcc/config/aarch64/aarch64.cc
@@ -2521,10 +2521,11 @@ aarch64_hard_regno_caller_save_mode (unsigned regno, unsigned,
      unnecessarily significant.  */
   if (PR_REGNUM_P (regno))
     return mode;
-  if (known_ge (GET_MODE_SIZE (mode), 4))
-    return mode;
-  else
+  if (known_lt (GET_MODE_SIZE (mode), 4)
+      && REG_CAN_CHANGE_MODE_P (regno, mode, SImode)
+      && REG_CAN_CHANGE_MODE_P (regno, SImode, mode))
     return SImode;
+  return mode;
 }
 
 /* Return true if I's bits are consecutive ones from the MSB.  */
diff --git a/gcc/testsuite/gcc.target/aarch64/sve/pr116238.c b/gcc/testsuite/gcc.target/aarch64/sve/pr116238.c
new file mode 100644
index 0000000000000000000000000000000000000000..fe66b198107f5ddc95c85554940f764bbd61a3a9
--- /dev/null
+++ b/gcc/testsuite/gcc.target/aarch64/sve/pr116238.c
@@ -0,0 +1,13 @@
+/* { dg-additional-options "-O2 -msve-vector-bits=128" } */
+
+void foo();
+typedef unsigned char v2qi __attribute__((vector_size(2)));
+void f(v2qi *ptr)
+{
+  v2qi x = *ptr;
+  asm volatile ("" :: "w" (x));
+  asm volatile ("" ::: "d8", "d9", "d10", "d11", "d12", "d13", "d14", "d15");
+  foo();
+  asm volatile ("" :: "w" (x));
+  *ptr = x;
+}