Skip to content

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

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 1 commit into
base: main
Choose a base branch
from

Conversation

resistor
Copy link
Collaborator

This fixes an issue reported in #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.

…irectly.

This fixes an issue reported in llvm#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.
@llvmbot llvmbot added clang Clang issues not falling into any other category backend:RISC-V clang:codegen IR generation bugs: mangling, exceptions, etc. labels Jul 13, 2025
@llvmbot
Copy link
Member

llvmbot commented Jul 13, 2025

@llvm/pr-subscribers-clang-codegen

@llvm/pr-subscribers-clang

Author: Owen Anderson (resistor)

Changes

This fixes an issue reported in #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 --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;
+}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
backend:RISC-V clang:codegen IR generation bugs: mangling, exceptions, etc. clang Clang issues not falling into any other category
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants