Author: Koakuma Date: 2024-05-15T20:49:28+07:00 New Revision: c2fba6df944e11e2c9a7073405c6a817fdba14e3
URL: https://github.com/llvm/llvm-project/commit/c2fba6df944e11e2c9a7073405c6a817fdba14e3 DIFF: https://github.com/llvm/llvm-project/commit/c2fba6df944e11e2c9a7073405c6a817fdba14e3.diff LOG: [clang][SPARC] Treat empty structs as if it's a one-bit type in the CC (#90338) Make sure that empty structs are treated as if it has a size of one bit in function parameters and return types so that it occupies a full argument and/or return register slot. This fixes crashes and miscompilations when passing and/or returning empty structs. Reviewed by: @s-barannikov Added: clang/test/CodeGen/sparcv9-class-return.cpp Modified: clang/lib/CodeGen/Targets/Sparc.cpp clang/test/CodeGen/sparcv9-abi.c Removed: ################################################################################ diff --git a/clang/lib/CodeGen/Targets/Sparc.cpp b/clang/lib/CodeGen/Targets/Sparc.cpp index 9025a633f328e..b82e9a69e1967 100644 --- a/clang/lib/CodeGen/Targets/Sparc.cpp +++ b/clang/lib/CodeGen/Targets/Sparc.cpp @@ -263,7 +263,10 @@ SparcV9ABIInfo::classifyType(QualType Ty, unsigned SizeLimit) const { CoerceBuilder CB(getVMContext(), getDataLayout()); CB.addStruct(0, StrTy); - CB.pad(llvm::alignTo(CB.DL.getTypeSizeInBits(StrTy), 64)); + // All structs, even empty ones, should take up a register argument slot, + // so pin the minimum struct size to one bit. + CB.pad(llvm::alignTo( + std::max(CB.DL.getTypeSizeInBits(StrTy).getKnownMinValue(), 1UL), 64)); // Try to use the original type for coercion. llvm::Type *CoerceTy = CB.isUsableType(StrTy) ? StrTy : CB.getType(); diff --git a/clang/test/CodeGen/sparcv9-abi.c b/clang/test/CodeGen/sparcv9-abi.c index 5e74a9a883cef..616e24e7c519d 100644 --- a/clang/test/CodeGen/sparcv9-abi.c +++ b/clang/test/CodeGen/sparcv9-abi.c @@ -21,6 +21,47 @@ char f_int_4(char x) { return x; } // CHECK-LABEL: define{{.*}} fp128 @f_ld(fp128 noundef %x) long double f_ld(long double x) { return x; } +// Zero-sized structs reserves an argument register slot if passed directly. +struct empty {}; +struct emptyarr { struct empty a[10]; }; + +// CHECK-LABEL: define{{.*}} i64 @f_empty(i64 %x.coerce) +struct empty f_empty(struct empty x) { return x; } + +// CHECK-LABEL: define{{.*}} i64 @f_emptyarr(i64 %x.coerce) +struct empty f_emptyarr(struct emptyarr x) { return x.a[0]; } + +// CHECK-LABEL: define{{.*}} i64 @f_emptyvar(i32 noundef zeroext %count, ...) +long f_emptyvar(unsigned count, ...) { + long ret; + va_list args; + va_start(args, count); + +// CHECK: %[[CUR:[^ ]+]] = load ptr, ptr %args +// CHECK-DAG: %[[NXT:[^ ]+]] = getelementptr inbounds i8, ptr %[[CUR]], i64 8 +// CHECK-DAG: store ptr %[[NXT]], ptr %args + va_arg(args, struct empty); + +// CHECK: %[[CUR:[^ ]+]] = load ptr, ptr %args +// CHECK-DAG: %[[NXT:[^ ]+]] = getelementptr inbounds i8, ptr %[[CUR]], i64 8 +// CHECK-DAG: store ptr %[[NXT]], ptr %args +// CHECK-DAG: load i64, ptr %[[CUR]] + ret = va_arg(args, long); + va_end(args); + return ret; +} + +// If the zero-sized struct is contained in a non-zero-sized struct, +// though, it doesn't reserve any registers. +struct emptymixed { struct empty a; long b; }; +struct emptyflex { unsigned count; struct empty data[10]; }; + +// CHECK-LABEL: define{{.*}} i64 @f_emptymixed(i64 %x.coerce) +long f_emptymixed(struct emptymixed x) { return x.b; } + +// CHECK-LABEL: define{{.*}} i64 @f_emptyflex(i64 %x.coerce, i64 noundef %y) +long f_emptyflex(struct emptyflex x, long y) { return y; } + // Small structs are passed in registers. struct small { int *a, *b; diff --git a/clang/test/CodeGen/sparcv9-class-return.cpp b/clang/test/CodeGen/sparcv9-class-return.cpp new file mode 100644 index 0000000000000..2428219422d8a --- /dev/null +++ b/clang/test/CodeGen/sparcv9-class-return.cpp @@ -0,0 +1,24 @@ +// RUN: %clang_cc1 -triple sparcv9-unknown-unknown -emit-llvm %s -o - | FileCheck %s + +class Empty { +}; + +class Long : public Empty { +public: + long l; +}; + +// CHECK: define{{.*}} i64 @_Z4foo15Empty(i64 %e.coerce) +Empty foo1(Empty e) { + return e; +} + +// CHECK: define{{.*}} %class.Long @_Z4foo24Long(i64 %l.coerce) +Long foo2(Long l) { + return l; +} + +// CHECK: define{{.*}} i64 @_Z4foo34Long(i64 %l.coerce) +long foo3(Long l) { + return l.l; +} _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits