[clang] [clang][RISCV] Always pass & return flexible array member structs indirectly. (PR #148541)

via cfe-commits cfe-commits at lists.llvm.org
Sun Jul 13 10:35:52 PDT 2025


llvmbot wrote:


<!--LLVM PR SUMMARY COMMENT-->
@llvm/pr-subscribers-clang-codegen

@llvm/pr-subscribers-clang

Author: Owen Anderson (resistor)

<details>
<summary>Changes</summary>

This fixes an issue reported in https://github.com/llvm/llvm-project/issues/148536 where
writes to flexible array members would sometimes be lost if the struct happened to hit
one of the cases where it would be passed in GPRs rather than on the stack.


---
Full diff: https://github.com/llvm/llvm-project/pull/148541.diff


2 Files Affected:

- (modified) clang/lib/CodeGen/Targets/RISCV.cpp (+4) 
- (added) clang/test/CodeGen/RISCV/abi-flexible-array-members.cpp (+46) 


``````````diff
diff --git a/clang/lib/CodeGen/Targets/RISCV.cpp b/clang/lib/CodeGen/Targets/RISCV.cpp
index e3232b61a693c..5bf0f29903f56 100644
--- a/clang/lib/CodeGen/Targets/RISCV.cpp
+++ b/clang/lib/CodeGen/Targets/RISCV.cpp
@@ -609,6 +609,10 @@ ABIArgInfo RISCVABIInfo::classifyArgumentType(QualType Ty, bool IsFixed,
   if (isEmptyRecord(getContext(), Ty, true) && Size == 0)
     return ABIArgInfo::getIgnore();
 
+  // Structures with flexible arrays are always indirect.
+  if (Ty->isStructureTypeWithFlexibleArrayMember())
+    return getNaturalAlignIndirect(Ty, /*ByVal=*/false);
+
   // Pass floating point values via FPRs if possible.
   if (IsFixed && Ty->isFloatingType() && !Ty->isComplexType() &&
       FLen >= Size && ArgFPRsLeft) {
diff --git a/clang/test/CodeGen/RISCV/abi-flexible-array-members.cpp b/clang/test/CodeGen/RISCV/abi-flexible-array-members.cpp
new file mode 100644
index 0000000000000..b6f25982fd3f6
--- /dev/null
+++ b/clang/test/CodeGen/RISCV/abi-flexible-array-members.cpp
@@ -0,0 +1,46 @@
+// NOTE: Assertions have been autogenerated by utils/update_cc_test_checks.py UTC_ARGS: --filter "^define |^entry:" --version 2
+// RUN: %clang_cc1 -x c++ -triple riscv32 -target-feature +f -target-abi ilp32f -emit-llvm %s -o - \
+// RUN:   | FileCheck -check-prefixes=CHECK32 %s
+// RUN: %clang_cc1 -x c++ -triple riscv32 -target-feature +f -target-feature +d -target-abi ilp32d -emit-llvm %s -o - \
+// RUN:   | FileCheck -check-prefixes=CHECK32 %s
+// RUN: %clang_cc1 -x c++ -triple riscv64 -target-feature +f -target-abi lp64f -emit-llvm %s -o - \
+// RUN:   | FileCheck -check-prefixes=CHECK64 %s
+// RUN: %clang_cc1 -x c++ -triple riscv64 -target-feature +f -target-feature +d -target-abi lp64d -emit-llvm %s -o - \
+// RUN:   | FileCheck -check-prefixes=CHECK64 %s
+
+#include <stdint.h>
+
+// Structs containing C99 flexible array members should always be passed and returned on the stack.
+
+struct s1 {
+    int a;
+    int b[];
+};
+
+// CHECK32-LABEL: define dso_local void @_Z7test_012s1
+// CHECK32-SAME: (ptr dead_on_unwind noalias writable sret([[STRUCT_S1:%.*]]) align 4 [[AGG_RESULT:%.*]], ptr noundef byval([[STRUCT_S1]]) align 4 [[A:%.*]]) #[[ATTR0:[0-9]+]] {
+// CHECK32:  entry:
+//
+// CHECK64-LABEL: define dso_local void @_Z7test_012s1
+// CHECK64-SAME: (ptr dead_on_unwind noalias writable sret([[STRUCT_S1:%.*]]) align 4 [[AGG_RESULT:%.*]], ptr noundef byval([[STRUCT_S1]]) align 4 [[A:%.*]]) #[[ATTR0:[0-9]+]] {
+// CHECK64:  entry:
+//
+struct s1 test_01(struct s1 a) {
+  return a;
+}
+
+
+// CHECK32-LABEL: define dso_local void @_Z7test_02v
+// CHECK32-SAME: (ptr dead_on_unwind noalias writable sret([[STRUCT_S1:%.*]]) align 4 [[AGG_RESULT:%.*]]) #[[ATTR0]] {
+// CHECK32:  entry:
+//
+// CHECK64-LABEL: define dso_local void @_Z7test_02v
+// CHECK64-SAME: (ptr dead_on_unwind noalias writable sret([[STRUCT_S1:%.*]]) align 4 [[AGG_RESULT:%.*]]) #[[ATTR0]] {
+// CHECK64:  entry:
+//
+struct s1 test_02() {
+    struct s1 r;
+    r.a = 0;
+    r.b[0] = 1;
+    return r;
+}

``````````

</details>


https://github.com/llvm/llvm-project/pull/148541


More information about the cfe-commits mailing list