diff options
-rw-r--r-- | clang/lib/CodeGen/TargetInfo.cpp | 23 | ||||
-rw-r--r-- | clang/test/CodeGen/systemz-abi-vector.c | 137 | ||||
-rw-r--r-- | clang/test/CodeGen/systemz-abi.c | 252 | ||||
-rw-r--r-- | clang/test/CodeGen/systemz-abi.cpp | 9 |
4 files changed, 413 insertions, 8 deletions
diff --git a/clang/lib/CodeGen/TargetInfo.cpp b/clang/lib/CodeGen/TargetInfo.cpp index 988b8fc80d2..081895f1e9a 100644 --- a/clang/lib/CodeGen/TargetInfo.cpp +++ b/clang/lib/CodeGen/TargetInfo.cpp @@ -5169,7 +5169,9 @@ bool SystemZABIInfo::isPromotableIntegerType(QualType Ty) const { } bool SystemZABIInfo::isCompoundType(QualType Ty) const { - return Ty->isAnyComplexType() || isAggregateTypeForABI(Ty); + return (Ty->isAnyComplexType() || + Ty->isVectorType() || + isAggregateTypeForABI(Ty)); } bool SystemZABIInfo::isFPArgumentType(QualType Ty) const { @@ -5204,11 +5206,12 @@ bool SystemZABIInfo::isFPArgumentType(QualType Ty) const { // Check the fields. for (const auto *FD : RD->fields()) { - // Empty bitfields don't affect things either way. + // For compatibility with GCC, ignore empty bitfields in C++ mode. // Unlike isSingleElementStruct(), empty structure and array fields // do count. So do anonymous bitfields that aren't zero-sized. - if (FD->isBitField() && FD->getBitWidthValue(getContext()) == 0) - return true; + if (getContext().getLangOpts().CPlusPlus && + FD->isBitField() && FD->getBitWidthValue(getContext()) == 0) + continue; // Unlike isSingleElementStruct(), arrays do not count. // Nested isFPArgumentType structures still do though. @@ -5240,17 +5243,21 @@ llvm::Value *SystemZABIInfo::EmitVAArg(llvm::Value *VAListAddr, QualType Ty, // Every argument occupies 8 bytes and is passed by preference in either // GPRs or FPRs. Ty = CGF.getContext().getCanonicalType(Ty); + llvm::Type *ArgTy = CGF.ConvertTypeForMem(Ty); + llvm::Type *APTy = llvm::PointerType::getUnqual(ArgTy); ABIArgInfo AI = classifyArgumentType(Ty); - bool InFPRs = isFPArgumentType(Ty); - - llvm::Type *APTy = llvm::PointerType::getUnqual(CGF.ConvertTypeForMem(Ty)); bool IsIndirect = AI.isIndirect(); + bool InFPRs = false; unsigned UnpaddedBitSize; if (IsIndirect) { APTy = llvm::PointerType::getUnqual(APTy); UnpaddedBitSize = 64; - } else + } else { + if (AI.getCoerceToType()) + ArgTy = AI.getCoerceToType(); + InFPRs = ArgTy->isFloatTy() || ArgTy->isDoubleTy(); UnpaddedBitSize = getContext().getTypeSize(Ty); + } unsigned PaddedBitSize = 64; assert((UnpaddedBitSize <= PaddedBitSize) && "Invalid argument size."); diff --git a/clang/test/CodeGen/systemz-abi-vector.c b/clang/test/CodeGen/systemz-abi-vector.c new file mode 100644 index 00000000000..6eff24c1e68 --- /dev/null +++ b/clang/test/CodeGen/systemz-abi-vector.c @@ -0,0 +1,137 @@ +// RUN: %clang_cc1 -triple s390x-linux-gnu -emit-llvm -o - %s | FileCheck %s + +// Vector types + +typedef __attribute__((vector_size(1))) char v1i8; + +typedef __attribute__((vector_size(2))) char v2i8; +typedef __attribute__((vector_size(2))) short v1i16; + +typedef __attribute__((vector_size(4))) char v4i8; +typedef __attribute__((vector_size(4))) short v2i16; +typedef __attribute__((vector_size(4))) int v1i32; +typedef __attribute__((vector_size(4))) float v1f32; + +typedef __attribute__((vector_size(8))) char v8i8; +typedef __attribute__((vector_size(8))) short v4i16; +typedef __attribute__((vector_size(8))) int v2i32; +typedef __attribute__((vector_size(8))) long long v1i64; +typedef __attribute__((vector_size(8))) float v2f32; +typedef __attribute__((vector_size(8))) double v1f64; + +typedef __attribute__((vector_size(16))) char v16i8; +typedef __attribute__((vector_size(16))) short v8i16; +typedef __attribute__((vector_size(16))) int v4i32; +typedef __attribute__((vector_size(16))) long long v2i64; +typedef __attribute__((vector_size(16))) __int128 v1i128; +typedef __attribute__((vector_size(16))) float v4f32; +typedef __attribute__((vector_size(16))) double v2f64; +typedef __attribute__((vector_size(16))) long double v1f128; + +typedef __attribute__((vector_size(32))) char v32i8; + +v1i8 pass_v1i8(v1i8 arg) { return arg; } +// CHECK-LABEL: define void @pass_v1i8(<1 x i8>* noalias sret %{{.*}}, <1 x i8>*) + +v2i8 pass_v2i8(v2i8 arg) { return arg; } +// CHECK-LABEL: define void @pass_v2i8(<2 x i8>* noalias sret %{{.*}}, <2 x i8>*) + +v4i8 pass_v4i8(v4i8 arg) { return arg; } +// CHECK-LABEL: define void @pass_v4i8(<4 x i8>* noalias sret %{{.*}}, <4 x i8>*) + +v8i8 pass_v8i8(v8i8 arg) { return arg; } +// CHECK-LABEL: define void @pass_v8i8(<8 x i8>* noalias sret %{{.*}}, <8 x i8>*) + +v16i8 pass_v16i8(v16i8 arg) { return arg; } +// CHECK-LABEL: define void @pass_v16i8(<16 x i8>* noalias sret %{{.*}}, <16 x i8>*) + +v32i8 pass_v32i8(v32i8 arg) { return arg; } +// CHECK-LABEL: define void @pass_v32i8(<32 x i8>* noalias sret %{{.*}}, <32 x i8>*) + +v1i16 pass_v1i16(v1i16 arg) { return arg; } +// CHECK-LABEL: define void @pass_v1i16(<1 x i16>* noalias sret %{{.*}}, <1 x i16>*) + +v2i16 pass_v2i16(v2i16 arg) { return arg; } +// CHECK-LABEL: define void @pass_v2i16(<2 x i16>* noalias sret %{{.*}}, <2 x i16>*) + +v4i16 pass_v4i16(v4i16 arg) { return arg; } +// CHECK-LABEL: define void @pass_v4i16(<4 x i16>* noalias sret %{{.*}}, <4 x i16>*) + +v8i16 pass_v8i16(v8i16 arg) { return arg; } +// CHECK-LABEL: define void @pass_v8i16(<8 x i16>* noalias sret %{{.*}}, <8 x i16>*) + +v1i32 pass_v1i32(v1i32 arg) { return arg; } +// CHECK-LABEL: define void @pass_v1i32(<1 x i32>* noalias sret %{{.*}}, <1 x i32>*) + +v2i32 pass_v2i32(v2i32 arg) { return arg; } +// CHECK-LABEL: define void @pass_v2i32(<2 x i32>* noalias sret %{{.*}}, <2 x i32>*) + +v4i32 pass_v4i32(v4i32 arg) { return arg; } +// CHECK-LABEL: define void @pass_v4i32(<4 x i32>* noalias sret %{{.*}}, <4 x i32>*) + +v1i64 pass_v1i64(v1i64 arg) { return arg; } +// CHECK-LABEL: define void @pass_v1i64(<1 x i64>* noalias sret %{{.*}}, <1 x i64>*) + +v2i64 pass_v2i64(v2i64 arg) { return arg; } +// CHECK-LABEL: define void @pass_v2i64(<2 x i64>* noalias sret %{{.*}}, <2 x i64>*) + +v1i128 pass_v1i128(v1i128 arg) { return arg; } +// CHECK-LABEL: define void @pass_v1i128(<1 x i128>* noalias sret %{{.*}}, <1 x i128>*) + +v1f32 pass_v1f32(v1f32 arg) { return arg; } +// CHECK-LABEL: define void @pass_v1f32(<1 x float>* noalias sret %{{.*}}, <1 x float>*) + +v2f32 pass_v2f32(v2f32 arg) { return arg; } +// CHECK-LABEL: define void @pass_v2f32(<2 x float>* noalias sret %{{.*}}, <2 x float>*) + +v4f32 pass_v4f32(v4f32 arg) { return arg; } +// CHECK-LABEL: define void @pass_v4f32(<4 x float>* noalias sret %{{.*}}, <4 x float>*) + +v1f64 pass_v1f64(v1f64 arg) { return arg; } +// CHECK-LABEL: define void @pass_v1f64(<1 x double>* noalias sret %{{.*}}, <1 x double>*) + +v2f64 pass_v2f64(v2f64 arg) { return arg; } +// CHECK-LABEL: define void @pass_v2f64(<2 x double>* noalias sret %{{.*}}, <2 x double>*) + +v1f128 pass_v1f128(v1f128 arg) { return arg; } +// CHECK-LABEL: define void @pass_v1f128(<1 x fp128>* noalias sret %{{.*}}, <1 x fp128>*) + + +// Accessing variable argument lists + +v1i8 va_v1i8(__builtin_va_list l) { return __builtin_va_arg(l, v1i8); } +// CHECK-LABEL: define void @va_v1i8(<1 x i8>* noalias sret %{{.*}}, %struct.__va_list_tag* %{{.*}}) +// CHECK: %reg_offset = add i64 %scaled_reg_count, 16 +// CHECK: %raw_mem_addr = getelementptr i8, i8* %overflow_arg_area, i64 0 +// CHECK: %indirect_arg = load <1 x i8>* + +v2i8 va_v2i8(__builtin_va_list l) { return __builtin_va_arg(l, v2i8); } +// CHECK-LABEL: define void @va_v2i8(<2 x i8>* noalias sret %{{.*}}, %struct.__va_list_tag* %{{.*}}) +// CHECK: %reg_offset = add i64 %scaled_reg_count, 16 +// CHECK: %raw_mem_addr = getelementptr i8, i8* %overflow_arg_area, i64 0 +// CHECK: %indirect_arg = load <2 x i8>* + +v4i8 va_v4i8(__builtin_va_list l) { return __builtin_va_arg(l, v4i8); } +// CHECK-LABEL: define void @va_v4i8(<4 x i8>* noalias sret %{{.*}}, %struct.__va_list_tag* %{{.*}}) +// CHECK: %reg_offset = add i64 %scaled_reg_count, 16 +// CHECK: %raw_mem_addr = getelementptr i8, i8* %overflow_arg_area, i64 0 +// CHECK: %indirect_arg = load <4 x i8>* + +v8i8 va_v8i8(__builtin_va_list l) { return __builtin_va_arg(l, v8i8); } +// CHECK-LABEL: define void @va_v8i8(<8 x i8>* noalias sret %{{.*}}, %struct.__va_list_tag* %{{.*}}) +// CHECK: %reg_offset = add i64 %scaled_reg_count, 16 +// CHECK: %raw_mem_addr = getelementptr i8, i8* %overflow_arg_area, i64 0 +// CHECK: %indirect_arg = load <8 x i8>* + +v16i8 va_v16i8(__builtin_va_list l) { return __builtin_va_arg(l, v16i8); } +// CHECK-LABEL: define void @va_v16i8(<16 x i8>* noalias sret %{{.*}}, %struct.__va_list_tag* %{{.*}}) +// CHECK: %reg_offset = add i64 %scaled_reg_count, 16 +// CHECK: %raw_mem_addr = getelementptr i8, i8* %overflow_arg_area, i64 0 +// CHECK: %indirect_arg = load <16 x i8>* + +v32i8 va_v32i8(__builtin_va_list l) { return __builtin_va_arg(l, v32i8); } +// CHECK-LABEL: define void @va_v32i8(<32 x i8>* noalias sret %{{.*}}, %struct.__va_list_tag* %{{.*}}) +// CHECK: %reg_offset = add i64 %scaled_reg_count, 16 +// CHECK: %raw_mem_addr = getelementptr i8, i8* %overflow_arg_area, i64 0 +// CHECK: %indirect_arg = load <32 x i8>* + diff --git a/clang/test/CodeGen/systemz-abi.c b/clang/test/CodeGen/systemz-abi.c new file mode 100644 index 00000000000..4de1d980601 --- /dev/null +++ b/clang/test/CodeGen/systemz-abi.c @@ -0,0 +1,252 @@ +// RUN: %clang_cc1 -triple s390x-linux-gnu -emit-llvm -o - %s | FileCheck %s + +// Scalar types + +char pass_char(char arg) { return arg; } +// CHECK-LABEL: define signext i8 @pass_char(i8 signext %{{.*}}) + +short pass_short(short arg) { return arg; } +// CHECK-LABEL: define signext i16 @pass_short(i16 signext %{{.*}}) + +int pass_int(int arg) { return arg; } +// CHECK-LABEL: define signext i32 @pass_int(i32 signext %{{.*}}) + +long pass_long(long arg) { return arg; } +// CHECK-LABEL: define i64 @pass_long(i64 %{{.*}}) + +long long pass_longlong(long long arg) { return arg; } +// CHECK-LABEL: define i64 @pass_longlong(i64 %{{.*}}) + +__int128 pass_int128(__int128 arg) { return arg; } +// CHECK-LABEL: define void @pass_int128(i128* noalias sret %{{.*}}, i128*) + +float pass_float(float arg) { return arg; } +// CHECK-LABEL: define float @pass_float(float %{{.*}}) + +double pass_double(double arg) { return arg; } +// CHECK-LABEL: define double @pass_double(double %{{.*}}) + +long double pass_longdouble(long double arg) { return arg; } +// CHECK-LABEL: define void @pass_longdouble(fp128* noalias sret %{{.*}}, fp128*) + + +// Complex types + +_Complex char pass_complex_char(_Complex char arg) { return arg; } +// CHECK-LABEL: define void @pass_complex_char({ i8, i8 }* noalias sret %{{.*}}, { i8, i8 }* %{{.*}}arg) + +_Complex short pass_complex_short(_Complex short arg) { return arg; } +// CHECK-LABEL: define void @pass_complex_short({ i16, i16 }* noalias sret %{{.*}}, { i16, i16 }* %{{.*}}arg) + +_Complex int pass_complex_int(_Complex int arg) { return arg; } +// CHECK-LABEL: define void @pass_complex_int({ i32, i32 }* noalias sret %{{.*}}, { i32, i32 }* %{{.*}}arg) + +_Complex long pass_complex_long(_Complex long arg) { return arg; } +// CHECK-LABEL: define void @pass_complex_long({ i64, i64 }* noalias sret %{{.*}}, { i64, i64 }* %{{.*}}arg) + +_Complex long long pass_complex_longlong(_Complex long long arg) { return arg; } +// CHECK-LABEL: define void @pass_complex_longlong({ i64, i64 }* noalias sret %{{.*}}, { i64, i64 }* %{{.*}}arg) + +_Complex float pass_complex_float(_Complex float arg) { return arg; } +// CHECK-LABEL: define void @pass_complex_float({ float, float }* noalias sret %{{.*}}, { float, float }* %{{.*}}arg) + +_Complex double pass_complex_double(_Complex double arg) { return arg; } +// CHECK-LABEL: define void @pass_complex_double({ double, double }* noalias sret %{{.*}}, { double, double }* %{{.*}}arg) + +_Complex long double pass_complex_longdouble(_Complex long double arg) { return arg; } +// CHECK-LABEL: define void @pass_complex_longdouble({ fp128, fp128 }* noalias sret %{{.*}}, { fp128, fp128 }* %{{.*}}arg) + + +// Aggregate types + +struct agg_1byte { char a[1]; }; +struct agg_1byte pass_agg_1byte(struct agg_1byte arg) { return arg; } +// CHECK-LABEL: define void @pass_agg_1byte(%struct.agg_1byte* noalias sret %{{.*}}, i8 %{{.*}}) + +struct agg_2byte { char a[2]; }; +struct agg_2byte pass_agg_2byte(struct agg_2byte arg) { return arg; } +// CHECK-LABEL: define void @pass_agg_2byte(%struct.agg_2byte* noalias sret %{{.*}}, i16 %{{.*}}) + +struct agg_3byte { char a[3]; }; +struct agg_3byte pass_agg_3byte(struct agg_3byte arg) { return arg; } +// CHECK-LABEL: define void @pass_agg_3byte(%struct.agg_3byte* noalias sret %{{.*}}, %struct.agg_3byte* %{{.*}}) + +struct agg_4byte { char a[4]; }; +struct agg_4byte pass_agg_4byte(struct agg_4byte arg) { return arg; } +// CHECK-LABEL: define void @pass_agg_4byte(%struct.agg_4byte* noalias sret %{{.*}}, i32 %{{.*}}) + +struct agg_5byte { char a[5]; }; +struct agg_5byte pass_agg_5byte(struct agg_5byte arg) { return arg; } +// CHECK-LABEL: define void @pass_agg_5byte(%struct.agg_5byte* noalias sret %{{.*}}, %struct.agg_5byte* %{{.*}}) + +struct agg_6byte { char a[6]; }; +struct agg_6byte pass_agg_6byte(struct agg_6byte arg) { return arg; } +// CHECK-LABEL: define void @pass_agg_6byte(%struct.agg_6byte* noalias sret %{{.*}}, %struct.agg_6byte* %{{.*}}) + +struct agg_7byte { char a[7]; }; +struct agg_7byte pass_agg_7byte(struct agg_7byte arg) { return arg; } +// CHECK-LABEL: define void @pass_agg_7byte(%struct.agg_7byte* noalias sret %{{.*}}, %struct.agg_7byte* %{{.*}}) + +struct agg_8byte { char a[8]; }; +struct agg_8byte pass_agg_8byte(struct agg_8byte arg) { return arg; } +// CHECK-LABEL: define void @pass_agg_8byte(%struct.agg_8byte* noalias sret %{{.*}}, i64 %{{.*}}) + +struct agg_16byte { char a[16]; }; +struct agg_16byte pass_agg_16byte(struct agg_16byte arg) { return arg; } +// CHECK-LABEL: define void @pass_agg_16byte(%struct.agg_16byte* noalias sret %{{.*}}, %struct.agg_16byte* %{{.*}}) + + +// Float-like aggregate types + +struct agg_float { float a; }; +struct agg_float pass_agg_float(struct agg_float arg) { return arg; } +// CHECK-LABEL: define void @pass_agg_float(%struct.agg_float* noalias sret %{{.*}}, float %{{.*}}) + +struct agg_double { double a; }; +struct agg_double pass_agg_double(struct agg_double arg) { return arg; } +// CHECK-LABEL: define void @pass_agg_double(%struct.agg_double* noalias sret %{{.*}}, double %{{.*}}) + +struct agg_longdouble { long double a; }; +struct agg_longdouble pass_agg_longdouble(struct agg_longdouble arg) { return arg; } +// CHECK-LABEL: define void @pass_agg_longdouble(%struct.agg_longdouble* noalias sret %{{.*}}, %struct.agg_longdouble* %{{.*}}) + +struct agg_float_a8 { float a __attribute__((aligned (8))); }; +struct agg_float_a8 pass_agg_float_a8(struct agg_float_a8 arg) { return arg; } +// CHECK-LABEL: define void @pass_agg_float_a8(%struct.agg_float_a8* noalias sret %{{.*}}, double %{{.*}}) + +struct agg_float_a16 { float a __attribute__((aligned (16))); }; +struct agg_float_a16 pass_agg_float_a16(struct agg_float_a16 arg) { return arg; } +// CHECK-LABEL: define void @pass_agg_float_a16(%struct.agg_float_a16* noalias sret %{{.*}}, %struct.agg_float_a16* %{{.*}}) + + +// Verify that the following are *not* float-like aggregate types + +struct agg_nofloat1 { float a; float b; }; +struct agg_nofloat1 pass_agg_nofloat1(struct agg_nofloat1 arg) { return arg; } +// CHECK-LABEL: define void @pass_agg_nofloat1(%struct.agg_nofloat1* noalias sret %{{.*}}, i64 %{{.*}}) + +struct agg_nofloat2 { float a; int b; }; +struct agg_nofloat2 pass_agg_nofloat2(struct agg_nofloat2 arg) { return arg; } +// CHECK-LABEL: define void @pass_agg_nofloat2(%struct.agg_nofloat2* noalias sret %{{.*}}, i64 %{{.*}}) + +struct agg_nofloat3 { float a; int : 0; }; +struct agg_nofloat3 pass_agg_nofloat3(struct agg_nofloat3 arg) { return arg; } +// CHECK-LABEL: define void @pass_agg_nofloat3(%struct.agg_nofloat3* noalias sret %{{.*}}, i32 %{{.*}}) + + +// Accessing variable argument lists + +int va_int(__builtin_va_list l) { return __builtin_va_arg(l, int); } +// CHECK-LABEL: define signext i32 @va_int(%struct.__va_list_tag* %{{.*}}) +// CHECK: %reg_offset = add i64 %scaled_reg_count, 20 +// CHECK: %raw_mem_addr = getelementptr i8, i8* %overflow_arg_area, i64 4 +// CHECK-NOT: %indirect_arg + +long va_long(__builtin_va_list l) { return __builtin_va_arg(l, long); } +// CHECK-LABEL: define i64 @va_long(%struct.__va_list_tag* %{{.*}}) +// CHECK: %reg_offset = add i64 %scaled_reg_count, 16 +// CHECK: %raw_mem_addr = getelementptr i8, i8* %overflow_arg_area, i64 0 +// CHECK-NOT: %indirect_arg + +long long va_longlong(__builtin_va_list l) { return __builtin_va_arg(l, long long); } +// CHECK-LABEL: define i64 @va_longlong(%struct.__va_list_tag* %{{.*}}) +// CHECK: %reg_offset = add i64 %scaled_reg_count, 16 +// CHECK: %raw_mem_addr = getelementptr i8, i8* %overflow_arg_area, i64 0 +// CHECK-NOT: %indirect_arg + +double va_double(__builtin_va_list l) { return __builtin_va_arg(l, double); } +// CHECK-LABEL: define double @va_double(%struct.__va_list_tag* %{{.*}}) +// CHECK: %reg_offset = add i64 %scaled_reg_count, 128 +// CHECK: %raw_mem_addr = getelementptr i8, i8* %overflow_arg_area, i64 0 +// CHECK-NOT: %indirect_arg + +long double va_longdouble(__builtin_va_list l) { return __builtin_va_arg(l, long double); } +// CHECK-LABEL: define void @va_longdouble(fp128* noalias sret %{{.*}}, %struct.__va_list_tag* %{{.*}}) +// CHECK: %reg_offset = add i64 %scaled_reg_count, 16 +// CHECK: %raw_mem_addr = getelementptr i8, i8* %overflow_arg_area, i64 0 +// CHECK: %indirect_arg = load fp128* + +_Complex char va_complex_char(__builtin_va_list l) { return __builtin_va_arg(l, _Complex char); } +// CHECK-LABEL: define void @va_complex_char({ i8, i8 }* noalias sret %{{.*}}, %struct.__va_list_tag* %{{.*}} +// CHECK: %reg_offset = add i64 %scaled_reg_count, 16 +// CHECK: %raw_mem_addr = getelementptr i8, i8* %overflow_arg_area, i64 0 +// CHECK: %indirect_arg = load { i8, i8 }* + +struct agg_1byte va_agg_1byte(__builtin_va_list l) { return __builtin_va_arg(l, struct agg_1byte); } +// CHECK-LABEL: define void @va_agg_1byte(%struct.agg_1byte* noalias sret %{{.*}}, %struct.__va_list_tag* %{{.*}} +// CHECK: %reg_offset = add i64 %scaled_reg_count, 23 +// CHECK: %raw_mem_addr = getelementptr i8, i8* %overflow_arg_area, i64 7 +// CHECK-NOT: %indirect_arg + +struct agg_2byte va_agg_2byte(__builtin_va_list l) { return __builtin_va_arg(l, struct agg_2byte); } +// CHECK-LABEL: define void @va_agg_2byte(%struct.agg_2byte* noalias sret %{{.*}}, %struct.__va_list_tag* %{{.*}} +// CHECK: %reg_offset = add i64 %scaled_reg_count, 22 +// CHECK: %raw_mem_addr = getelementptr i8, i8* %overflow_arg_area, i64 6 +// CHECK-NOT: %indirect_arg + +struct agg_3byte va_agg_3byte(__builtin_va_list l) { return __builtin_va_arg(l, struct agg_3byte); } +// CHECK-LABEL: define void @va_agg_3byte(%struct.agg_3byte* noalias sret %{{.*}}, %struct.__va_list_tag* %{{.*}} +// CHECK: %reg_offset = add i64 %scaled_reg_count, 16 +// CHECK: %raw_mem_addr = getelementptr i8, i8* %overflow_arg_area, i64 0 +// CHECK: %indirect_arg = load %struct.agg_3byte* + +struct agg_4byte va_agg_4byte(__builtin_va_list l) { return __builtin_va_arg(l, struct agg_4byte); } +// CHECK-LABEL: define void @va_agg_4byte(%struct.agg_4byte* noalias sret %{{.*}}, %struct.__va_list_tag* %{{.*}} +// CHECK: %reg_offset = add i64 %scaled_reg_count, 20 +// CHECK: %raw_mem_addr = getelementptr i8, i8* %overflow_arg_area, i64 4 +// CHECK-NOT: %indirect_arg + +struct agg_8byte va_agg_8byte(__builtin_va_list l) { return __builtin_va_arg(l, struct agg_8byte); } +// CHECK-LABEL: define void @va_agg_8byte(%struct.agg_8byte* noalias sret %{{.*}}, %struct.__va_list_tag* %{{.*}} +// CHECK: %reg_offset = add i64 %scaled_reg_count, 16 +// CHECK: %raw_mem_addr = getelementptr i8, i8* %overflow_arg_area, i64 0 +// CHECK-NOT: %indirect_arg + +struct agg_float va_agg_float(__builtin_va_list l) { return __builtin_va_arg(l, struct agg_float); } +// CHECK-LABEL: define void @va_agg_float(%struct.agg_float* noalias sret %{{.*}}, %struct.__va_list_tag* %{{.*}} +// CHECK: %reg_offset = add i64 %scaled_reg_count, 128 +// CHECK: %raw_mem_addr = getelementptr i8, i8* %overflow_arg_area, i64 4 +// CHECK-NOT: %indirect_arg + +struct agg_double va_agg_double(__builtin_va_list l) { return __builtin_va_arg(l, struct agg_double); } +// CHECK-LABEL: define void @va_agg_double(%struct.agg_double* noalias sret %{{.*}}, %struct.__va_list_tag* %{{.*}} +// CHECK: %reg_offset = add i64 %scaled_reg_count, 128 +// CHECK: %raw_mem_addr = getelementptr i8, i8* %overflow_arg_area, i64 0 +// CHECK-NOT: %indirect_arg + +struct agg_longdouble va_agg_longdouble(__builtin_va_list l) { return __builtin_va_arg(l, struct agg_longdouble); } +// CHECK-LABEL: define void @va_agg_longdouble(%struct.agg_longdouble* noalias sret %{{.*}}, %struct.__va_list_tag* %{{.*}} +// CHECK: %reg_offset = add i64 %scaled_reg_count, 16 +// CHECK: %raw_mem_addr = getelementptr i8, i8* %overflow_arg_area, i64 0 +// CHECK: %indirect_arg = load %struct.agg_longdouble* + +struct agg_float_a8 va_agg_float_a8(__builtin_va_list l) { return __builtin_va_arg(l, struct agg_float_a8); } +// CHECK-LABEL: define void @va_agg_float_a8(%struct.agg_float_a8* noalias sret %{{.*}}, %struct.__va_list_tag* %{{.*}} +// CHECK: %reg_offset = add i64 %scaled_reg_count, 128 +// CHECK: %raw_mem_addr = getelementptr i8, i8* %overflow_arg_area, i64 0 +// CHECK-NOT: %indirect_arg + +struct agg_float_a16 va_agg_float_a16(__builtin_va_list l) { return __builtin_va_arg(l, struct agg_float_a16); } +// CHECK-LABEL: define void @va_agg_float_a16(%struct.agg_float_a16* noalias sret %{{.*}}, %struct.__va_list_tag* %{{.*}} +// CHECK: %reg_offset = add i64 %scaled_reg_count, 16 +// CHECK: %raw_mem_addr = getelementptr i8, i8* %overflow_arg_area, i64 0 +// CHECK: %indirect_arg = load %struct.agg_float_a16* + +struct agg_nofloat1 va_agg_nofloat1(__builtin_va_list l) { return __builtin_va_arg(l, struct agg_nofloat1); } +// CHECK-LABEL: define void @va_agg_nofloat1(%struct.agg_nofloat1* noalias sret %{{.*}}, %struct.__va_list_tag* %{{.*}} +// CHECK: %reg_offset = add i64 %scaled_reg_count, 16 +// CHECK: %raw_mem_addr = getelementptr i8, i8* %overflow_arg_area, i64 0 +// CHECK-NOT: %indirect_arg + +struct agg_nofloat2 va_agg_nofloat2(__builtin_va_list l) { return __builtin_va_arg(l, struct agg_nofloat2); } +// CHECK-LABEL: define void @va_agg_nofloat2(%struct.agg_nofloat2* noalias sret %{{.*}}, %struct.__va_list_tag* %{{.*}} +// CHECK: %reg_offset = add i64 %scaled_reg_count, 16 +// CHECK: %raw_mem_addr = getelementptr i8, i8* %overflow_arg_area, i64 0 +// CHECK-NOT: %indirect_arg + +struct agg_nofloat3 va_agg_nofloat3(__builtin_va_list l) { return __builtin_va_arg(l, struct agg_nofloat3); } +// CHECK-LABEL: define void @va_agg_nofloat3(%struct.agg_nofloat3* noalias sret %{{.*}}, %struct.__va_list_tag* %{{.*}} +// CHECK: %reg_offset = add i64 %scaled_reg_count, 20 +// CHECK: %raw_mem_addr = getelementptr i8, i8* %overflow_arg_area, i64 4 +// CHECK-NOT: %indirect_arg + diff --git a/clang/test/CodeGen/systemz-abi.cpp b/clang/test/CodeGen/systemz-abi.cpp new file mode 100644 index 00000000000..0249e9f63c9 --- /dev/null +++ b/clang/test/CodeGen/systemz-abi.cpp @@ -0,0 +1,9 @@ +// RUN: %clang_cc1 -triple s390x-linux-gnu -emit-llvm -x c++ -o - %s | FileCheck %s + +// 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 %{{.*}}, float %{{.*}}) + |