llvm-project/clang/test/CodeGen/systemz-abi.cpp

Ignoring revisions in .git-blame-ignore-revs. Click here to bypass and see the normal blame view.

60 lines
4.8 KiB
C++
Raw Normal View History

[SystemZ] Fix some ABI corner cases Running the GCC's inter-compiler ABI compatibility test suite uncovered a couple of errors in clang's SystemZ ABI implementation. These all affect only rare corner cases: - Short vector types GCC synthetic vector types defined with __attribute__ ((vector_size ...)) are always passed and returned by reference. (This is not documented in the official ABI document, but is the de-facto ABI implemented by GCC.) clang would do that only for vector sizes >= 16 bytes, but not for shorter vector types. - Float-like aggregates and empty bitfields clang would consider any aggregate containing an empty bitfield as first element to be a float-like aggregate. That's obviously wrong. According to the ABI doc, the presence of an empty bitfield makes an aggregate to be *not* float-like. However, due to a bug in GCC, empty bitfields are ignored in C++; this patch changes clang to be compatible with this "feature" of GCC. - Float-like aggregates and va_arg The va_arg implementation would mis-detect some aggregates as float-like that aren't actually passed as such. This applies to aggregates that have only a single element of type float or double, but using an aligned attribute that increases the total struct size to more than 8 bytes. This error occurred because the va_arg implement used to have an copy of the float-like aggregate detection logic (i.e. it would call the isFPArgumentType routine, but not perform the size check). To simplify the logic, this patch removes the duplicated logic and instead simply checks the (possibly coerced) LLVM argument type as already determined by classifyArgumentType. llvm-svn: 233543
2015-03-30 21:49:01 +08:00
// RUN: %clang_cc1 -triple s390x-linux-gnu -emit-llvm -x c++ -o - %s | FileCheck %s
// RUN: %clang_cc1 -triple s390x-linux-gnu -emit-llvm -x c++ -o - %s -mfloat-abi soft \
// RUN: | FileCheck %s --check-prefix=SOFT-FLOAT
[SystemZ] Fix some ABI corner cases Running the GCC's inter-compiler ABI compatibility test suite uncovered a couple of errors in clang's SystemZ ABI implementation. These all affect only rare corner cases: - Short vector types GCC synthetic vector types defined with __attribute__ ((vector_size ...)) are always passed and returned by reference. (This is not documented in the official ABI document, but is the de-facto ABI implemented by GCC.) clang would do that only for vector sizes >= 16 bytes, but not for shorter vector types. - Float-like aggregates and empty bitfields clang would consider any aggregate containing an empty bitfield as first element to be a float-like aggregate. That's obviously wrong. According to the ABI doc, the presence of an empty bitfield makes an aggregate to be *not* float-like. However, due to a bug in GCC, empty bitfields are ignored in C++; this patch changes clang to be compatible with this "feature" of GCC. - Float-like aggregates and va_arg The va_arg implementation would mis-detect some aggregates as float-like that aren't actually passed as such. This applies to aggregates that have only a single element of type float or double, but using an aligned attribute that increases the total struct size to more than 8 bytes. This error occurred because the va_arg implement used to have an copy of the float-like aggregate detection logic (i.e. it would call the isFPArgumentType routine, but not perform the size check). To simplify the logic, this patch removes the duplicated logic and instead simply checks the (possibly coerced) LLVM argument type as already determined by classifyArgumentType. llvm-svn: 233543
2015-03-30 21:49:01 +08:00
// Verify that class types are also recognized as float-like aggregate types
class agg_float_class { float a; };
class agg_float_class pass_agg_float_class(class agg_float_class arg) { return arg; }
// CHECK-LABEL: define void @_Z20pass_agg_float_class15agg_float_class(%class.agg_float_class* noalias sret align 4 %{{.*}}, float %{{.*}})
// SOFT-FLOAT-LABEL: define void @_Z20pass_agg_float_class15agg_float_class(%class.agg_float_class* noalias sret align 4 %{{.*}}, i32 %{{.*}})
class agg_double_class { double a; };
class agg_double_class pass_agg_double_class(class agg_double_class arg) { return arg; }
// CHECK-LABEL: define void @_Z21pass_agg_double_class16agg_double_class(%class.agg_double_class* noalias sret align 8 %{{.*}}, double %{{.*}})
// SOFT-FLOAT-LABEL: define void @_Z21pass_agg_double_class16agg_double_class(%class.agg_double_class* noalias sret align 8 %{{.*}}, i64 %{{.*}})
[SystemZ] Fix some ABI corner cases Running the GCC's inter-compiler ABI compatibility test suite uncovered a couple of errors in clang's SystemZ ABI implementation. These all affect only rare corner cases: - Short vector types GCC synthetic vector types defined with __attribute__ ((vector_size ...)) are always passed and returned by reference. (This is not documented in the official ABI document, but is the de-facto ABI implemented by GCC.) clang would do that only for vector sizes >= 16 bytes, but not for shorter vector types. - Float-like aggregates and empty bitfields clang would consider any aggregate containing an empty bitfield as first element to be a float-like aggregate. That's obviously wrong. According to the ABI doc, the presence of an empty bitfield makes an aggregate to be *not* float-like. However, due to a bug in GCC, empty bitfields are ignored in C++; this patch changes clang to be compatible with this "feature" of GCC. - Float-like aggregates and va_arg The va_arg implementation would mis-detect some aggregates as float-like that aren't actually passed as such. This applies to aggregates that have only a single element of type float or double, but using an aligned attribute that increases the total struct size to more than 8 bytes. This error occurred because the va_arg implement used to have an copy of the float-like aggregate detection logic (i.e. it would call the isFPArgumentType routine, but not perform the size check). To simplify the logic, this patch removes the duplicated logic and instead simply checks the (possibly coerced) LLVM argument type as already determined by classifyArgumentType. llvm-svn: 233543
2015-03-30 21:49:01 +08:00
// For compatibility with GCC, this structure is passed in an FPR in C++,
// but passed in a GPR in C (checked in systemz-abi.c).
struct agg_float_cpp { float a; int : 0; };
struct agg_float_cpp pass_agg_float_cpp(struct agg_float_cpp arg) { return arg; }
// CHECK-LABEL: define void @_Z18pass_agg_float_cpp13agg_float_cpp(%struct.agg_float_cpp* noalias sret align 4 %{{.*}}, float %{{.*}})
// SOFT-FLOAT-LABEL: define void @_Z18pass_agg_float_cpp13agg_float_cpp(%struct.agg_float_cpp* noalias sret align 4 %{{.*}}, i32 %{{.*}})
// A field member of empty class type in C++ makes the record nonhomogeneous,
// unless it is marked as [[no_unique_address]]. This does not apply to arrays.
struct empty { };
struct agg_nofloat_empty { float a; empty dummy; };
struct agg_nofloat_empty pass_agg_nofloat_empty(struct agg_nofloat_empty arg) { return arg; }
// CHECK-LABEL: define void @_Z22pass_agg_nofloat_empty17agg_nofloat_empty(%struct.agg_nofloat_empty* noalias sret align 4 %{{.*}}, i64 %{{.*}})
// SOFT-FLOAT-LABEL: define void @_Z22pass_agg_nofloat_empty17agg_nofloat_empty(%struct.agg_nofloat_empty* noalias sret align 4 %{{.*}}, i64 %{{.*}})
struct agg_float_empty { float a; [[no_unique_address]] empty dummy; };
struct agg_float_empty pass_agg_float_empty(struct agg_float_empty arg) { return arg; }
// CHECK-LABEL: define void @_Z20pass_agg_float_empty15agg_float_empty(%struct.agg_float_empty* noalias sret align 4 %{{.*}}, float %{{.*}})
// SOFT-FLOAT-LABEL: define void @_Z20pass_agg_float_empty15agg_float_empty(%struct.agg_float_empty* noalias sret align 4 %{{.*}}, i32 %{{.*}})
struct agg_nofloat_emptyarray { float a; [[no_unique_address]] empty dummy[3]; };
struct agg_nofloat_emptyarray pass_agg_nofloat_emptyarray(struct agg_nofloat_emptyarray arg) { return arg; }
// CHECK-LABEL: define void @_Z27pass_agg_nofloat_emptyarray22agg_nofloat_emptyarray(%struct.agg_nofloat_emptyarray* noalias sret align 4 %{{.*}}, i64 %{{.*}})
// SOFT-FLOAT-LABEL: define void @_Z27pass_agg_nofloat_emptyarray22agg_nofloat_emptyarray(%struct.agg_nofloat_emptyarray* noalias sret align 4 %{{.*}}, i64 %{{.*}})
// And likewise for members of base classes.
struct noemptybase { empty dummy; };
struct agg_nofloat_emptybase : noemptybase { float a; };
struct agg_nofloat_emptybase pass_agg_nofloat_emptybase(struct agg_nofloat_emptybase arg) { return arg; }
// CHECK-LABEL: define void @_Z26pass_agg_nofloat_emptybase21agg_nofloat_emptybase(%struct.agg_nofloat_emptybase* noalias sret align 4 %{{.*}}, i64 %{{.*}})
// SOFT-FLOAT-LABEL: define void @_Z26pass_agg_nofloat_emptybase21agg_nofloat_emptybase(%struct.agg_nofloat_emptybase* noalias sret align 4 %{{.*}}, i64 %{{.*}})
struct emptybase { [[no_unique_address]] empty dummy; };
struct agg_float_emptybase : emptybase { float a; };
struct agg_float_emptybase pass_agg_float_emptybase(struct agg_float_emptybase arg) { return arg; }
// CHECK-LABEL: define void @_Z24pass_agg_float_emptybase19agg_float_emptybase(%struct.agg_float_emptybase* noalias sret align 4 %{{.*}}, float %{{.*}})
// SOFT-FLOAT-LABEL: define void @_Z24pass_agg_float_emptybase19agg_float_emptybase(%struct.agg_float_emptybase* noalias sret align 4 %{{.*}}, i32 %{{.*}})
struct noemptybasearray { [[no_unique_address]] empty dummy[3]; };
struct agg_nofloat_emptybasearray : noemptybasearray { float a; };
struct agg_nofloat_emptybasearray pass_agg_nofloat_emptybasearray(struct agg_nofloat_emptybasearray arg) { return arg; }
// CHECK-LABEL: define void @_Z31pass_agg_nofloat_emptybasearray26agg_nofloat_emptybasearray(%struct.agg_nofloat_emptybasearray* noalias sret align 4 %{{.*}}, i64 %{{.*}})
// SOFT-FLOAT-LABEL: define void @_Z31pass_agg_nofloat_emptybasearray26agg_nofloat_emptybasearray(%struct.agg_nofloat_emptybasearray* noalias sret align 4 %{{.*}}, i64 %{{.*}})