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 + +// 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; +}