diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td --- a/clang/include/clang/Basic/DiagnosticSemaKinds.td +++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td @@ -7436,6 +7436,11 @@ "volatile qualifier in structured binding declaration is deprecated">, InGroup; +def warn_deprecated_vector_compare_compat : Warning< + "Current vector compare behaviour is deprecated for vector bool and vector " + "pixel. Comparisons between vector bool/pixel types will soon return " + "a scalar value instead of a vector value by default">; + def err_catch_incomplete_ptr : Error< "cannot catch pointer to incomplete type %0">; def err_catch_incomplete_ref : Error< diff --git a/clang/include/clang/Basic/LangOptions.h b/clang/include/clang/Basic/LangOptions.h --- a/clang/include/clang/Basic/LangOptions.h +++ b/clang/include/clang/Basic/LangOptions.h @@ -244,6 +244,17 @@ All, }; + enum class VectorCompareCompatKind { + // Default clang behaviour. + // All vector compares produce scalars except vector Pixel and vector bool. + // The types vector Pixel and vector bool return vector results. + Mixed, + // All vector compares produce vector results as in GCC. + GCC, + // All vector compares produce scalars as in XL. + XL, + }; + enum class SignReturnAddressScopeKind { /// No signing for any function. None, diff --git a/clang/include/clang/Basic/LangOptions.def b/clang/include/clang/Basic/LangOptions.def --- a/clang/include/clang/Basic/LangOptions.def +++ b/clang/include/clang/Basic/LangOptions.def @@ -126,6 +126,8 @@ LANGOPT(ConstStrings , 1, 0, "const-qualified string support") ENUM_LANGOPT(LaxVectorConversions, LaxVectorConversionKind, 2, LaxVectorConversionKind::All, "lax vector conversions") +ENUM_LANGOPT(VectorCompareCompat, VectorCompareCompatKind, 2, + VectorCompareCompatKind::Mixed, "vector compare compatibility") LANGOPT(ConvergentFunctions, 1, 1, "Assume convergent functions") LANGOPT(AltiVec , 1, 0, "AltiVec-style vector initializers") LANGOPT(ZVector , 1, 0, "System z vector extensions") diff --git a/clang/include/clang/Driver/Options.td b/clang/include/clang/Driver/Options.td --- a/clang/include/clang/Driver/Options.td +++ b/clang/include/clang/Driver/Options.td @@ -3821,6 +3821,13 @@ def v : Flag<["-"], "v">, Flags<[CC1Option, CoreOption]>, HelpText<"Show commands to run and use verbose output">, MarshallingInfoFlag>; +def vector_compare_compat : Joined<["-"], "vector-compare-compat=">, + Flags<[CC1Option]>, Group, + HelpText<"Determines whether vector compare returns a vector or a scalar. Options: mixed, gcc, xl.">, + Values<"mixed,gcc,xl">, + NormalizedValuesScope<"LangOptions::VectorCompareCompatKind">, + NormalizedValues<["Mixed", "GCC", "XL"]>, + MarshallingInfoEnum, "Mixed">; def verify_debug_info : Flag<["--"], "verify-debug-info">, Flags<[NoXarchOption]>, HelpText<"Verify the binary representation of debug output">; def weak_l : Joined<["-"], "weak-l">, Flags<[LinkerInput]>; diff --git a/clang/lib/Driver/ToolChains/Clang.cpp b/clang/lib/Driver/ToolChains/Clang.cpp --- a/clang/lib/Driver/ToolChains/Clang.cpp +++ b/clang/lib/Driver/ToolChains/Clang.cpp @@ -5803,6 +5803,7 @@ (Args.hasArg(options::OPT_mkernel) && types::isCXX(InputType))) CmdArgs.push_back("-fapple-kext"); + Args.AddLastArg(CmdArgs, options::OPT_vector_compare_compat); Args.AddLastArg(CmdArgs, options::OPT_flax_vector_conversions_EQ); Args.AddLastArg(CmdArgs, options::OPT_fobjc_sender_dependent_dispatch); Args.AddLastArg(CmdArgs, options::OPT_fdiagnostics_print_source_range_info); diff --git a/clang/lib/Sema/SemaExpr.cpp b/clang/lib/Sema/SemaExpr.cpp --- a/clang/lib/Sema/SemaExpr.cpp +++ b/clang/lib/Sema/SemaExpr.cpp @@ -12213,11 +12213,29 @@ QualType LHSType = LHS.get()->getType(); - // If AltiVec, the comparison results in a numeric type, i.e. - // bool for C++, int for C - if (getLangOpts().AltiVec && - vType->castAs()->getVectorKind() == VectorType::AltiVecVector) - return Context.getLogicalOperationType(); + // Determine the return type of a vector compare. By default clang will return + // a scalar for all vector compares except vector bool and vector pixel. + // With the gcc compiler we will always return a vector type and with the xl + // compiler we will always return a scalar type. This switch allows choosing + // which behavior is prefered. + switch (getLangOpts().getVectorCompareCompat()) { + case LangOptions::VectorCompareCompatKind::Mixed: + // If AltiVec, the comparison results in a numeric type, i.e. + // bool for C++, int for C + if (getLangOpts().AltiVec && vType->castAs()->getVectorKind() == + VectorType::AltiVecVector) + return Context.getLogicalOperationType(); + else if (getLangOpts().AltiVec) + Diag(Loc, diag::warn_deprecated_vector_compare_compat); + break; + case LangOptions::VectorCompareCompatKind::GCC: + // For GCC we always return the vector type. + break; + case LangOptions::VectorCompareCompatKind::XL: + if (getLangOpts().AltiVec) + return Context.getLogicalOperationType(); + break; + } // For non-floating point types, check for self-comparisons of the form // x == x, x != x, x < x, etc. These always evaluate to a constant, and diff --git a/clang/test/CodeGen/vector-compat-pixel-bool-ternary.c b/clang/test/CodeGen/vector-compat-pixel-bool-ternary.c new file mode 100644 --- /dev/null +++ b/clang/test/CodeGen/vector-compat-pixel-bool-ternary.c @@ -0,0 +1,104 @@ +// NOTE: Assertions have been autogenerated by utils/update_cc_test_checks.py +// RUN: not %clang_cc1 -target-feature +altivec -target-feature +vsx \ +// RUN: -vector-compare-compat=mixed -triple powerpc-unknown-unknown -S -emit-llvm %s -o - 2>&1 | FileCheck %s --check-prefix=ERROR +// RUN: not %clang_cc1 -target-feature +altivec -target-feature +vsx \ +// RUN: -vector-compare-compat=gcc -triple powerpc-unknown-unknown -S -emit-llvm %s -o - 2>&1| FileCheck %s --check-prefix=ERROR +// RUN: %clang_cc1 -target-feature +altivec -target-feature +vsx \ +// RUN: -vector-compare-compat=xl -triple powerpc-unknown-unknown -S -emit-llvm %s -o - | FileCheck %s +// RUN: %clang -mcpu=pwr8 -vector-compare-compat=xl --target=powerpc-unknown-unknown -S -emit-llvm %s -o - | FileCheck %s +// RUN: %clang -mcpu=pwr9 -vector-compare-compat=xl --target=powerpc-unknown-unknown -S -emit-llvm %s -o - | FileCheck %s + +// CHECK-LABEL: @bi8( +// CHECK-NEXT: entry: +// CHECK-NEXT: [[A_ADDR:%.*]] = alloca <16 x i8>, align 16 +// CHECK-NEXT: [[B_ADDR:%.*]] = alloca <16 x i8>, align 16 +// CHECK-NEXT: store <16 x i8> [[A:%.*]], <16 x i8>* [[A_ADDR]], align 16 +// CHECK-NEXT: store <16 x i8> [[B:%.*]], <16 x i8>* [[B_ADDR]], align 16 +// CHECK-NEXT: [[TMP0:%.*]] = load <16 x i8>, <16 x i8>* [[A_ADDR]], align 16 +// CHECK-NEXT: [[TMP1:%.*]] = load <16 x i8>, <16 x i8>* [[B_ADDR]], align 16 +// CHECK-NEXT: [[TMP2:%.*]] = call i32 @llvm.ppc.altivec.vcmpequb.p(i32 2, <16 x i8> [[TMP0]], <16 x i8> [[TMP1]]) +// CHECK-NEXT: [[TOBOOL:%.*]] = icmp ne i32 [[TMP2]], 0 +// CHECK-NEXT: [[TMP3:%.*]] = zext i1 [[TOBOOL]] to i64 +// CHECK-NEXT: [[COND:%.*]] = select i1 [[TOBOOL]], i32 3, i32 7 +// CHECK-NEXT: ret i32 [[COND]] +// +// ERROR: error: used type '__attribute__((__vector_size__(16 * sizeof(char)))) char' (vector of 16 'char' values) where arithmetic or pointer type is required +int bi8(vector bool char a, vector bool char b) { + return a == b ? 3 : 7; +} + +// CHECK-LABEL: @bi16( +// CHECK-NEXT: entry: +// CHECK-NEXT: [[A_ADDR:%.*]] = alloca <8 x i16>, align 16 +// CHECK-NEXT: [[B_ADDR:%.*]] = alloca <8 x i16>, align 16 +// CHECK-NEXT: store <8 x i16> [[A:%.*]], <8 x i16>* [[A_ADDR]], align 16 +// CHECK-NEXT: store <8 x i16> [[B:%.*]], <8 x i16>* [[B_ADDR]], align 16 +// CHECK-NEXT: [[TMP0:%.*]] = load <8 x i16>, <8 x i16>* [[A_ADDR]], align 16 +// CHECK-NEXT: [[TMP1:%.*]] = load <8 x i16>, <8 x i16>* [[B_ADDR]], align 16 +// CHECK-NEXT: [[TMP2:%.*]] = call i32 @llvm.ppc.altivec.vcmpequh.p(i32 2, <8 x i16> [[TMP0]], <8 x i16> [[TMP1]]) +// CHECK-NEXT: [[TOBOOL:%.*]] = icmp ne i32 [[TMP2]], 0 +// CHECK-NEXT: [[TMP3:%.*]] = zext i1 [[TOBOOL]] to i64 +// CHECK-NEXT: [[COND:%.*]] = select i1 [[TOBOOL]], i32 3, i32 7 +// CHECK-NEXT: ret i32 [[COND]] +// +// ERROR: error: used type '__attribute__((__vector_size__(8 * sizeof(short)))) short' (vector of 8 'short' values) where arithmetic or pointer type is required +int bi16(vector bool short a, vector bool short b) { + return a == b ? 3 : 7; +} + +// CHECK-LABEL: @bi32( +// CHECK-NEXT: entry: +// CHECK-NEXT: [[A_ADDR:%.*]] = alloca <4 x i32>, align 16 +// CHECK-NEXT: [[B_ADDR:%.*]] = alloca <4 x i32>, align 16 +// CHECK-NEXT: store <4 x i32> [[A:%.*]], <4 x i32>* [[A_ADDR]], align 16 +// CHECK-NEXT: store <4 x i32> [[B:%.*]], <4 x i32>* [[B_ADDR]], align 16 +// CHECK-NEXT: [[TMP0:%.*]] = load <4 x i32>, <4 x i32>* [[A_ADDR]], align 16 +// CHECK-NEXT: [[TMP1:%.*]] = load <4 x i32>, <4 x i32>* [[B_ADDR]], align 16 +// CHECK-NEXT: [[TMP2:%.*]] = call i32 @llvm.ppc.altivec.vcmpequw.p(i32 2, <4 x i32> [[TMP0]], <4 x i32> [[TMP1]]) +// CHECK-NEXT: [[TOBOOL:%.*]] = icmp ne i32 [[TMP2]], 0 +// CHECK-NEXT: [[TMP3:%.*]] = zext i1 [[TOBOOL]] to i64 +// CHECK-NEXT: [[COND:%.*]] = select i1 [[TOBOOL]], i32 3, i32 7 +// CHECK-NEXT: ret i32 [[COND]] +// +// ERROR: error: used type '__attribute__((__vector_size__(4 * sizeof(long)))) long' (vector of 4 'long' values) where arithmetic or pointer type is required +int bi32(vector bool int a, vector bool int b) { + return a == b ? 3 : 7; +} + +// CHECK-LABEL: @bi64( +// CHECK-NEXT: entry: +// CHECK-NEXT: [[A_ADDR:%.*]] = alloca <2 x i64>, align 16 +// CHECK-NEXT: [[B_ADDR:%.*]] = alloca <2 x i64>, align 16 +// CHECK-NEXT: store <2 x i64> [[A:%.*]], <2 x i64>* [[A_ADDR]], align 16 +// CHECK-NEXT: store <2 x i64> [[B:%.*]], <2 x i64>* [[B_ADDR]], align 16 +// CHECK-NEXT: [[TMP0:%.*]] = load <2 x i64>, <2 x i64>* [[A_ADDR]], align 16 +// CHECK-NEXT: [[TMP1:%.*]] = load <2 x i64>, <2 x i64>* [[B_ADDR]], align 16 +// CHECK-NEXT: [[TMP2:%.*]] = call i32 @llvm.ppc.altivec.vcmpequd.p(i32 2, <2 x i64> [[TMP0]], <2 x i64> [[TMP1]]) +// CHECK-NEXT: [[TOBOOL:%.*]] = icmp ne i32 [[TMP2]], 0 +// CHECK-NEXT: [[TMP3:%.*]] = zext i1 [[TOBOOL]] to i64 +// CHECK-NEXT: [[COND:%.*]] = select i1 [[TOBOOL]], i32 3, i32 7 +// CHECK-NEXT: ret i32 [[COND]] +// +// ERROR: error: used type '__attribute__((__vector_size__(2 * sizeof(long long)))) long long' (vector of 2 'long long' values) where arithmetic or pointer type is required +int bi64(vector bool long long a, vector bool long long b) { + return a == b ? 3 : 7; +} + +// CHECK-LABEL: @VecPixel( +// CHECK-NEXT: entry: +// CHECK-NEXT: [[A_ADDR:%.*]] = alloca <8 x i16>, align 16 +// CHECK-NEXT: [[B_ADDR:%.*]] = alloca <8 x i16>, align 16 +// CHECK-NEXT: store <8 x i16> [[A:%.*]], <8 x i16>* [[A_ADDR]], align 16 +// CHECK-NEXT: store <8 x i16> [[B:%.*]], <8 x i16>* [[B_ADDR]], align 16 +// CHECK-NEXT: [[TMP0:%.*]] = load <8 x i16>, <8 x i16>* [[A_ADDR]], align 16 +// CHECK-NEXT: [[TMP1:%.*]] = load <8 x i16>, <8 x i16>* [[B_ADDR]], align 16 +// CHECK-NEXT: [[TMP2:%.*]] = call i32 @llvm.ppc.altivec.vcmpequh.p(i32 2, <8 x i16> [[TMP0]], <8 x i16> [[TMP1]]) +// CHECK-NEXT: [[TOBOOL:%.*]] = icmp ne i32 [[TMP2]], 0 +// CHECK-NEXT: [[TMP3:%.*]] = zext i1 [[TOBOOL]] to i64 +// CHECK-NEXT: [[COND:%.*]] = select i1 [[TOBOOL]], i32 3, i32 7 +// CHECK-NEXT: ret i32 [[COND]] +// +// ERROR: error: used type '__attribute__((__vector_size__(8 * sizeof(short)))) short' (vector of 8 'short' values) where arithmetic or pointer type is required +int VecPixel(vector pixel a, vector pixel b) { + return a == b ? 3 : 7; +} diff --git a/clang/test/CodeGen/vector-compat-pixel-bool.c b/clang/test/CodeGen/vector-compat-pixel-bool.c new file mode 100644 --- /dev/null +++ b/clang/test/CodeGen/vector-compat-pixel-bool.c @@ -0,0 +1,94 @@ +// NOTE: Assertions have been autogenerated by utils/update_cc_test_checks.py +// RUN: %clang_cc1 -target-feature +altivec -target-feature +vsx \ +// RUN: -vector-compare-compat=mixed -triple powerpc-unknown-unknown -S -emit-llvm %s -o - | FileCheck %s +// RUN: %clang_cc1 -target-feature +altivec -target-feature +vsx \ +// RUN: -vector-compare-compat=gcc -triple powerpc-unknown-unknown -S -emit-llvm %s -o - | FileCheck %s +// RUN: not %clang_cc1 -target-feature +altivec -target-feature +vsx \ +// RUN: -vector-compare-compat=xl -triple powerpc-unknown-unknown -S -emit-llvm %s -o - 2>&1 | FileCheck %s --check-prefix=ERROR +// RUN: %clang -mcpu=pwr8 -vector-compare-compat=gcc --target=powerpc-unknown-unknown -S -emit-llvm %s -o - | FileCheck %s +// RUN: %clang -mcpu=pwr9 -vector-compare-compat=gcc --target=powerpc-unknown-unknown -S -emit-llvm %s -o - | FileCheck %s + +// CHECK-LABEL: @bi8( +// CHECK-NEXT: entry: +// CHECK-NEXT: [[A_ADDR:%.*]] = alloca <16 x i8>, align 16 +// CHECK-NEXT: [[B_ADDR:%.*]] = alloca <16 x i8>, align 16 +// CHECK-NEXT: store <16 x i8> [[A:%.*]], <16 x i8>* [[A_ADDR]], align 16 +// CHECK-NEXT: store <16 x i8> [[B:%.*]], <16 x i8>* [[B_ADDR]], align 16 +// CHECK-NEXT: [[TMP0:%.*]] = load <16 x i8>, <16 x i8>* [[A_ADDR]], align 16 +// CHECK-NEXT: [[TMP1:%.*]] = load <16 x i8>, <16 x i8>* [[B_ADDR]], align 16 +// CHECK-NEXT: [[CMP:%.*]] = icmp eq <16 x i8> [[TMP0]], [[TMP1]] +// CHECK-NEXT: [[SEXT:%.*]] = sext <16 x i1> [[CMP]] to <16 x i8> +// CHECK-NEXT: ret <16 x i8> [[SEXT]] +// +// ERROR: returning 'int' from a function with incompatible result type +vector unsigned char bi8(vector bool char a, vector bool char b) { + return a == b; +} + +// CHECK-LABEL: @bi16( +// CHECK-NEXT: entry: +// CHECK-NEXT: [[A_ADDR:%.*]] = alloca <8 x i16>, align 16 +// CHECK-NEXT: [[B_ADDR:%.*]] = alloca <8 x i16>, align 16 +// CHECK-NEXT: store <8 x i16> [[A:%.*]], <8 x i16>* [[A_ADDR]], align 16 +// CHECK-NEXT: store <8 x i16> [[B:%.*]], <8 x i16>* [[B_ADDR]], align 16 +// CHECK-NEXT: [[TMP0:%.*]] = load <8 x i16>, <8 x i16>* [[A_ADDR]], align 16 +// CHECK-NEXT: [[TMP1:%.*]] = load <8 x i16>, <8 x i16>* [[B_ADDR]], align 16 +// CHECK-NEXT: [[CMP:%.*]] = icmp eq <8 x i16> [[TMP0]], [[TMP1]] +// CHECK-NEXT: [[SEXT:%.*]] = sext <8 x i1> [[CMP]] to <8 x i16> +// CHECK-NEXT: ret <8 x i16> [[SEXT]] +// +// ERROR: returning 'int' from a function with incompatible result type +vector bool short bi16(vector bool short a, vector bool short b) { + return a == b; +} + +// CHECK-LABEL: @bi32( +// CHECK-NEXT: entry: +// CHECK-NEXT: [[A_ADDR:%.*]] = alloca <4 x i32>, align 16 +// CHECK-NEXT: [[B_ADDR:%.*]] = alloca <4 x i32>, align 16 +// CHECK-NEXT: store <4 x i32> [[A:%.*]], <4 x i32>* [[A_ADDR]], align 16 +// CHECK-NEXT: store <4 x i32> [[B:%.*]], <4 x i32>* [[B_ADDR]], align 16 +// CHECK-NEXT: [[TMP0:%.*]] = load <4 x i32>, <4 x i32>* [[A_ADDR]], align 16 +// CHECK-NEXT: [[TMP1:%.*]] = load <4 x i32>, <4 x i32>* [[B_ADDR]], align 16 +// CHECK-NEXT: [[CMP:%.*]] = icmp eq <4 x i32> [[TMP0]], [[TMP1]] +// CHECK-NEXT: [[SEXT:%.*]] = sext <4 x i1> [[CMP]] to <4 x i32> +// CHECK-NEXT: ret <4 x i32> [[SEXT]] +// +// ERROR: returning 'int' from a function with incompatible result type +vector bool int bi32(vector bool int a, vector bool int b) { + return a == b; +} + +// CHECK-LABEL: @bi64( +// CHECK-NEXT: entry: +// CHECK-NEXT: [[A_ADDR:%.*]] = alloca <2 x i64>, align 16 +// CHECK-NEXT: [[B_ADDR:%.*]] = alloca <2 x i64>, align 16 +// CHECK-NEXT: store <2 x i64> [[A:%.*]], <2 x i64>* [[A_ADDR]], align 16 +// CHECK-NEXT: store <2 x i64> [[B:%.*]], <2 x i64>* [[B_ADDR]], align 16 +// CHECK-NEXT: [[TMP0:%.*]] = load <2 x i64>, <2 x i64>* [[A_ADDR]], align 16 +// CHECK-NEXT: [[TMP1:%.*]] = load <2 x i64>, <2 x i64>* [[B_ADDR]], align 16 +// CHECK-NEXT: [[CMP:%.*]] = icmp eq <2 x i64> [[TMP0]], [[TMP1]] +// CHECK-NEXT: [[SEXT:%.*]] = sext <2 x i1> [[CMP]] to <2 x i64> +// CHECK-NEXT: ret <2 x i64> [[SEXT]] +// +// ERROR: returning 'int' from a function with incompatible result type +vector long long bi64(vector bool long long a, vector bool long long b) { + return a == b; +} + +// CHECK-LABEL: @VecPixel( +// CHECK-NEXT: entry: +// CHECK-NEXT: [[A_ADDR:%.*]] = alloca <8 x i16>, align 16 +// CHECK-NEXT: [[B_ADDR:%.*]] = alloca <8 x i16>, align 16 +// CHECK-NEXT: store <8 x i16> [[A:%.*]], <8 x i16>* [[A_ADDR]], align 16 +// CHECK-NEXT: store <8 x i16> [[B:%.*]], <8 x i16>* [[B_ADDR]], align 16 +// CHECK-NEXT: [[TMP0:%.*]] = load <8 x i16>, <8 x i16>* [[A_ADDR]], align 16 +// CHECK-NEXT: [[TMP1:%.*]] = load <8 x i16>, <8 x i16>* [[B_ADDR]], align 16 +// CHECK-NEXT: [[CMP:%.*]] = icmp eq <8 x i16> [[TMP0]], [[TMP1]] +// CHECK-NEXT: [[SEXT:%.*]] = sext <8 x i1> [[CMP]] to <8 x i16> +// CHECK-NEXT: ret <8 x i16> [[SEXT]] +// +// ERROR: returning 'int' from a function with incompatible result type +vector pixel VecPixel(vector pixel a, vector pixel b) { + return a == b; +} diff --git a/clang/test/CodeGen/vector-compat-ternary.c b/clang/test/CodeGen/vector-compat-ternary.c new file mode 100644 --- /dev/null +++ b/clang/test/CodeGen/vector-compat-ternary.c @@ -0,0 +1,180 @@ +// NOTE: Assertions have been autogenerated by utils/update_cc_test_checks.py +// RUN: %clang_cc1 -target-feature +altivec -target-feature +vsx \ +// RUN: -vector-compare-compat=mixed -triple powerpc-unknown-unknown -S -emit-llvm %s -o - | FileCheck %s +// RUN: not %clang_cc1 -target-feature +altivec -target-feature +vsx \ +// RUN: -vector-compare-compat=gcc -triple powerpc-unknown-unknown -S -emit-llvm %s -o - 2>&1 | FileCheck %s --check-prefix=ERROR +// RUN: %clang_cc1 -target-feature +altivec -target-feature +vsx \ +// RUN: -vector-compare-compat=xl -triple powerpc-unknown-unknown -S -emit-llvm %s -o - | FileCheck %s +// RUN: %clang -mcpu=pwr8 -vector-compare-compat=xl --target=powerpc-unknown-unknown -S -emit-llvm %s -o - | FileCheck %s +// RUN: %clang -mcpu=pwr9 -vector-compare-compat=xl --target=powerpc-unknown-unknown -S -emit-llvm %s -o - | FileCheck %s + +// CHECK-LABEL: @ui8( +// CHECK-NEXT: entry: +// CHECK-NEXT: [[A_ADDR:%.*]] = alloca <16 x i8>, align 16 +// CHECK-NEXT: [[B_ADDR:%.*]] = alloca <16 x i8>, align 16 +// CHECK-NEXT: store <16 x i8> [[A:%.*]], <16 x i8>* [[A_ADDR]], align 16 +// CHECK-NEXT: store <16 x i8> [[B:%.*]], <16 x i8>* [[B_ADDR]], align 16 +// CHECK-NEXT: [[TMP0:%.*]] = load <16 x i8>, <16 x i8>* [[A_ADDR]], align 16 +// CHECK-NEXT: [[TMP1:%.*]] = load <16 x i8>, <16 x i8>* [[B_ADDR]], align 16 +// CHECK-NEXT: [[TMP2:%.*]] = call i32 @llvm.ppc.altivec.vcmpequb.p(i32 2, <16 x i8> [[TMP0]], <16 x i8> [[TMP1]]) +// CHECK-NEXT: [[TOBOOL:%.*]] = icmp ne i32 [[TMP2]], 0 +// CHECK-NEXT: [[TMP3:%.*]] = zext i1 [[TOBOOL]] to i64 +// CHECK-NEXT: [[COND:%.*]] = select i1 [[TOBOOL]], i32 3, i32 7 +// CHECK-NEXT: ret i32 [[COND]] +// +// ERROR: error: used type '__attribute__((__vector_size__(16 * sizeof(char)))) char' (vector of 16 'char' values) where arithmetic or pointer type is required +int ui8(vector unsigned char a, vector unsigned char b) { + return a == b ? 3 : 7; +} + +// CHECK-LABEL: @si8( +// CHECK-NEXT: entry: +// CHECK-NEXT: [[A_ADDR:%.*]] = alloca <16 x i8>, align 16 +// CHECK-NEXT: [[B_ADDR:%.*]] = alloca <16 x i8>, align 16 +// CHECK-NEXT: store <16 x i8> [[A:%.*]], <16 x i8>* [[A_ADDR]], align 16 +// CHECK-NEXT: store <16 x i8> [[B:%.*]], <16 x i8>* [[B_ADDR]], align 16 +// CHECK-NEXT: [[TMP0:%.*]] = load <16 x i8>, <16 x i8>* [[A_ADDR]], align 16 +// CHECK-NEXT: [[TMP1:%.*]] = load <16 x i8>, <16 x i8>* [[B_ADDR]], align 16 +// CHECK-NEXT: [[TMP2:%.*]] = call i32 @llvm.ppc.altivec.vcmpequb.p(i32 2, <16 x i8> [[TMP0]], <16 x i8> [[TMP1]]) +// CHECK-NEXT: [[TOBOOL:%.*]] = icmp ne i32 [[TMP2]], 0 +// CHECK-NEXT: [[TMP3:%.*]] = zext i1 [[TOBOOL]] to i64 +// CHECK-NEXT: [[COND:%.*]] = select i1 [[TOBOOL]], i32 3, i32 7 +// CHECK-NEXT: ret i32 [[COND]] +// +// ERROR: error: used type '__attribute__((__vector_size__(16 * sizeof(char)))) char' (vector of 16 'char' values) where arithmetic or pointer type is required +int si8(vector signed char a, vector signed char b) { + return a == b ? 3 : 7; +} + +// CHECK-LABEL: @ui16( +// CHECK-NEXT: entry: +// CHECK-NEXT: [[A_ADDR:%.*]] = alloca <8 x i16>, align 16 +// CHECK-NEXT: [[B_ADDR:%.*]] = alloca <8 x i16>, align 16 +// CHECK-NEXT: store <8 x i16> [[A:%.*]], <8 x i16>* [[A_ADDR]], align 16 +// CHECK-NEXT: store <8 x i16> [[B:%.*]], <8 x i16>* [[B_ADDR]], align 16 +// CHECK-NEXT: [[TMP0:%.*]] = load <8 x i16>, <8 x i16>* [[A_ADDR]], align 16 +// CHECK-NEXT: [[TMP1:%.*]] = load <8 x i16>, <8 x i16>* [[B_ADDR]], align 16 +// CHECK-NEXT: [[TMP2:%.*]] = call i32 @llvm.ppc.altivec.vcmpequh.p(i32 2, <8 x i16> [[TMP0]], <8 x i16> [[TMP1]]) +// CHECK-NEXT: [[TOBOOL:%.*]] = icmp ne i32 [[TMP2]], 0 +// CHECK-NEXT: [[TMP3:%.*]] = zext i1 [[TOBOOL]] to i64 +// CHECK-NEXT: [[COND:%.*]] = select i1 [[TOBOOL]], i32 3, i32 7 +// CHECK-NEXT: ret i32 [[COND]] +// +// ERROR: error: used type '__attribute__((__vector_size__(8 * sizeof(short)))) short' (vector of 8 'short' values) where arithmetic or pointer type is required +int ui16(vector unsigned short a, vector unsigned short b) { + return a == b ? 3 : 7; +} + +// CHECK-LABEL: @si16( +// CHECK-NEXT: entry: +// CHECK-NEXT: [[A_ADDR:%.*]] = alloca <8 x i16>, align 16 +// CHECK-NEXT: [[B_ADDR:%.*]] = alloca <8 x i16>, align 16 +// CHECK-NEXT: store <8 x i16> [[A:%.*]], <8 x i16>* [[A_ADDR]], align 16 +// CHECK-NEXT: store <8 x i16> [[B:%.*]], <8 x i16>* [[B_ADDR]], align 16 +// CHECK-NEXT: [[TMP0:%.*]] = load <8 x i16>, <8 x i16>* [[A_ADDR]], align 16 +// CHECK-NEXT: [[TMP1:%.*]] = load <8 x i16>, <8 x i16>* [[B_ADDR]], align 16 +// CHECK-NEXT: [[TMP2:%.*]] = call i32 @llvm.ppc.altivec.vcmpequh.p(i32 2, <8 x i16> [[TMP0]], <8 x i16> [[TMP1]]) +// CHECK-NEXT: [[TOBOOL:%.*]] = icmp ne i32 [[TMP2]], 0 +// CHECK-NEXT: [[TMP3:%.*]] = zext i1 [[TOBOOL]] to i64 +// CHECK-NEXT: [[COND:%.*]] = select i1 [[TOBOOL]], i32 3, i32 7 +// CHECK-NEXT: ret i32 [[COND]] +// +// ERROR: error: used type '__attribute__((__vector_size__(8 * sizeof(short)))) short' (vector of 8 'short' values) where arithmetic or pointer type is required +int si16(vector signed short a, vector signed short b) { + return a == b ? 3 : 7; +} + +// CHECK-LABEL: @ui32( +// CHECK-NEXT: entry: +// CHECK-NEXT: [[A_ADDR:%.*]] = alloca <4 x i32>, align 16 +// CHECK-NEXT: [[B_ADDR:%.*]] = alloca <4 x i32>, align 16 +// CHECK-NEXT: store <4 x i32> [[A:%.*]], <4 x i32>* [[A_ADDR]], align 16 +// CHECK-NEXT: store <4 x i32> [[B:%.*]], <4 x i32>* [[B_ADDR]], align 16 +// CHECK-NEXT: [[TMP0:%.*]] = load <4 x i32>, <4 x i32>* [[A_ADDR]], align 16 +// CHECK-NEXT: [[TMP1:%.*]] = load <4 x i32>, <4 x i32>* [[B_ADDR]], align 16 +// CHECK-NEXT: [[TMP2:%.*]] = call i32 @llvm.ppc.altivec.vcmpequw.p(i32 2, <4 x i32> [[TMP0]], <4 x i32> [[TMP1]]) +// CHECK-NEXT: [[TOBOOL:%.*]] = icmp ne i32 [[TMP2]], 0 +// CHECK-NEXT: [[TMP3:%.*]] = zext i1 [[TOBOOL]] to i64 +// CHECK-NEXT: [[COND:%.*]] = select i1 [[TOBOOL]], i32 3, i32 7 +// CHECK-NEXT: ret i32 [[COND]] +// +// ERROR: error: used type '__attribute__((__vector_size__(4 * sizeof(long)))) long' (vector of 4 'long' values) where arithmetic or pointer type is required +int ui32(vector unsigned int a, vector unsigned int b) { + return a == b ? 3 : 7; +} + +// CHECK-LABEL: @si32( +// CHECK-NEXT: entry: +// CHECK-NEXT: [[A_ADDR:%.*]] = alloca <4 x i32>, align 16 +// CHECK-NEXT: [[B_ADDR:%.*]] = alloca <4 x i32>, align 16 +// CHECK-NEXT: store <4 x i32> [[A:%.*]], <4 x i32>* [[A_ADDR]], align 16 +// CHECK-NEXT: store <4 x i32> [[B:%.*]], <4 x i32>* [[B_ADDR]], align 16 +// CHECK-NEXT: [[TMP0:%.*]] = load <4 x i32>, <4 x i32>* [[A_ADDR]], align 16 +// CHECK-NEXT: [[TMP1:%.*]] = load <4 x i32>, <4 x i32>* [[B_ADDR]], align 16 +// CHECK-NEXT: [[TMP2:%.*]] = call i32 @llvm.ppc.altivec.vcmpequw.p(i32 2, <4 x i32> [[TMP0]], <4 x i32> [[TMP1]]) +// CHECK-NEXT: [[TOBOOL:%.*]] = icmp ne i32 [[TMP2]], 0 +// CHECK-NEXT: [[TMP3:%.*]] = zext i1 [[TOBOOL]] to i64 +// CHECK-NEXT: [[COND:%.*]] = select i1 [[TOBOOL]], i32 3, i32 7 +// CHECK-NEXT: ret i32 [[COND]] +// +// ERROR: error: used type '__attribute__((__vector_size__(4 * sizeof(long)))) long' (vector of 4 'long' values) where arithmetic or pointer type is required +int si32(vector signed int a, vector signed int b) { + return a == b ? 3 : 7; +} + +// CHECK-LABEL: @si64( +// CHECK-NEXT: entry: +// CHECK-NEXT: [[A_ADDR:%.*]] = alloca <2 x i64>, align 16 +// CHECK-NEXT: [[B_ADDR:%.*]] = alloca <2 x i64>, align 16 +// CHECK-NEXT: store <2 x i64> [[A:%.*]], <2 x i64>* [[A_ADDR]], align 16 +// CHECK-NEXT: store <2 x i64> [[B:%.*]], <2 x i64>* [[B_ADDR]], align 16 +// CHECK-NEXT: [[TMP0:%.*]] = load <2 x i64>, <2 x i64>* [[A_ADDR]], align 16 +// CHECK-NEXT: [[TMP1:%.*]] = load <2 x i64>, <2 x i64>* [[B_ADDR]], align 16 +// CHECK-NEXT: [[TMP2:%.*]] = call i32 @llvm.ppc.altivec.vcmpequd.p(i32 2, <2 x i64> [[TMP0]], <2 x i64> [[TMP1]]) +// CHECK-NEXT: [[TOBOOL:%.*]] = icmp ne i32 [[TMP2]], 0 +// CHECK-NEXT: [[TMP3:%.*]] = zext i1 [[TOBOOL]] to i64 +// CHECK-NEXT: [[COND:%.*]] = select i1 [[TOBOOL]], i32 3, i32 7 +// CHECK-NEXT: ret i32 [[COND]] +// +// ERROR: error: used type '__attribute__((__vector_size__(2 * sizeof(long long)))) long long' (vector of 2 'long long' values) where arithmetic or pointer type is required +int si64(vector long long a, vector long long b) { + return a == b ? 3 : 7; +} + +// CHECK-LABEL: @f32( +// CHECK-NEXT: entry: +// CHECK-NEXT: [[A_ADDR:%.*]] = alloca <4 x float>, align 16 +// CHECK-NEXT: [[B_ADDR:%.*]] = alloca <4 x float>, align 16 +// CHECK-NEXT: store <4 x float> [[A:%.*]], <4 x float>* [[A_ADDR]], align 16 +// CHECK-NEXT: store <4 x float> [[B:%.*]], <4 x float>* [[B_ADDR]], align 16 +// CHECK-NEXT: [[TMP0:%.*]] = load <4 x float>, <4 x float>* [[A_ADDR]], align 16 +// CHECK-NEXT: [[TMP1:%.*]] = load <4 x float>, <4 x float>* [[B_ADDR]], align 16 +// CHECK-NEXT: [[TMP2:%.*]] = call i32 @llvm.ppc.altivec.vcmpeqfp.p(i32 2, <4 x float> [[TMP0]], <4 x float> [[TMP1]]) +// CHECK-NEXT: [[TOBOOL:%.*]] = icmp ne i32 [[TMP2]], 0 +// CHECK-NEXT: [[TMP3:%.*]] = zext i1 [[TOBOOL]] to i64 +// CHECK-NEXT: [[COND:%.*]] = select i1 [[TOBOOL]], i32 3, i32 7 +// CHECK-NEXT: ret i32 [[COND]] +// +// ERROR: error: used type '__attribute__((__vector_size__(4 * sizeof(long)))) long' (vector of 4 'long' values) where arithmetic or pointer type is required +int f32(vector float a, vector float b) { + return a == b ? 3 : 7; +} + +// CHECK-LABEL: @f64( +// CHECK-NEXT: entry: +// CHECK-NEXT: [[A_ADDR:%.*]] = alloca <2 x double>, align 16 +// CHECK-NEXT: [[B_ADDR:%.*]] = alloca <2 x double>, align 16 +// CHECK-NEXT: store <2 x double> [[A:%.*]], <2 x double>* [[A_ADDR]], align 16 +// CHECK-NEXT: store <2 x double> [[B:%.*]], <2 x double>* [[B_ADDR]], align 16 +// CHECK-NEXT: [[TMP0:%.*]] = load <2 x double>, <2 x double>* [[A_ADDR]], align 16 +// CHECK-NEXT: [[TMP1:%.*]] = load <2 x double>, <2 x double>* [[B_ADDR]], align 16 +// CHECK-NEXT: [[TMP2:%.*]] = call i32 @llvm.ppc.vsx.xvcmpeqdp.p(i32 2, <2 x double> [[TMP0]], <2 x double> [[TMP1]]) +// CHECK-NEXT: [[TOBOOL:%.*]] = icmp ne i32 [[TMP2]], 0 +// CHECK-NEXT: [[TMP3:%.*]] = zext i1 [[TOBOOL]] to i64 +// CHECK-NEXT: [[COND:%.*]] = select i1 [[TOBOOL]], i32 3, i32 7 +// CHECK-NEXT: ret i32 [[COND]] +// +// ERROR: error: used type '__attribute__((__vector_size__(2 * sizeof(long long)))) long long' (vector of 2 'long long' values) where arithmetic or pointer type is required +int f64(vector double a, vector double b) { + return a == b ? 3 : 7; +} diff --git a/clang/test/CodeGen/vector-compat.c b/clang/test/CodeGen/vector-compat.c new file mode 100644 --- /dev/null +++ b/clang/test/CodeGen/vector-compat.c @@ -0,0 +1,162 @@ +// NOTE: Assertions have been autogenerated by utils/update_cc_test_checks.py +// RUN: not %clang_cc1 -target-feature +altivec -target-feature +vsx \ +// RUN: -vector-compare-compat=mixed -triple powerpc-unknown-unknown -S -emit-llvm %s -o - 2>&1 | FileCheck %s --check-prefix=ERROR +// RUN: %clang_cc1 -target-feature +altivec -target-feature +vsx \ +// RUN: -vector-compare-compat=gcc -triple powerpc-unknown-unknown -S -emit-llvm %s -o - | FileCheck %s +// RUN: not %clang_cc1 -target-feature +altivec -target-feature +vsx \ +// RUN: -vector-compare-compat=xl -triple powerpc-unknown-unknown -S -emit-llvm %s -o - 2>&1 | FileCheck %s --check-prefix=ERROR +// RUN: %clang -mcpu=pwr8 -vector-compare-compat=gcc --target=powerpc-unknown-unknown -S -emit-llvm %s -o - | FileCheck %s +// RUN: %clang -mcpu=pwr9 -vector-compare-compat=gcc --target=powerpc-unknown-unknown -S -emit-llvm %s -o - | FileCheck %s + +// CHECK-LABEL: @ui8( +// CHECK-NEXT: entry: +// CHECK-NEXT: [[A_ADDR:%.*]] = alloca <16 x i8>, align 16 +// CHECK-NEXT: [[B_ADDR:%.*]] = alloca <16 x i8>, align 16 +// CHECK-NEXT: store <16 x i8> [[A:%.*]], <16 x i8>* [[A_ADDR]], align 16 +// CHECK-NEXT: store <16 x i8> [[B:%.*]], <16 x i8>* [[B_ADDR]], align 16 +// CHECK-NEXT: [[TMP0:%.*]] = load <16 x i8>, <16 x i8>* [[A_ADDR]], align 16 +// CHECK-NEXT: [[TMP1:%.*]] = load <16 x i8>, <16 x i8>* [[B_ADDR]], align 16 +// CHECK-NEXT: [[CMP:%.*]] = icmp eq <16 x i8> [[TMP0]], [[TMP1]] +// CHECK-NEXT: [[SEXT:%.*]] = sext <16 x i1> [[CMP]] to <16 x i8> +// CHECK-NEXT: ret <16 x i8> [[SEXT]] +// +// ERROR: returning 'int' from a function with incompatible result type +vector unsigned char ui8(vector unsigned char a, vector unsigned char b) { + return a == b; +} + +// CHECK-LABEL: @si8( +// CHECK-NEXT: entry: +// CHECK-NEXT: [[A_ADDR:%.*]] = alloca <16 x i8>, align 16 +// CHECK-NEXT: [[B_ADDR:%.*]] = alloca <16 x i8>, align 16 +// CHECK-NEXT: store <16 x i8> [[A:%.*]], <16 x i8>* [[A_ADDR]], align 16 +// CHECK-NEXT: store <16 x i8> [[B:%.*]], <16 x i8>* [[B_ADDR]], align 16 +// CHECK-NEXT: [[TMP0:%.*]] = load <16 x i8>, <16 x i8>* [[A_ADDR]], align 16 +// CHECK-NEXT: [[TMP1:%.*]] = load <16 x i8>, <16 x i8>* [[B_ADDR]], align 16 +// CHECK-NEXT: [[CMP:%.*]] = icmp eq <16 x i8> [[TMP0]], [[TMP1]] +// CHECK-NEXT: [[SEXT:%.*]] = sext <16 x i1> [[CMP]] to <16 x i8> +// CHECK-NEXT: ret <16 x i8> [[SEXT]] +// +// ERROR: returning 'int' from a function with incompatible result type +vector signed char si8(vector signed char a, vector signed char b) { + return a == b; +} + +// CHECK-LABEL: @ui16( +// CHECK-NEXT: entry: +// CHECK-NEXT: [[A_ADDR:%.*]] = alloca <8 x i16>, align 16 +// CHECK-NEXT: [[B_ADDR:%.*]] = alloca <8 x i16>, align 16 +// CHECK-NEXT: store <8 x i16> [[A:%.*]], <8 x i16>* [[A_ADDR]], align 16 +// CHECK-NEXT: store <8 x i16> [[B:%.*]], <8 x i16>* [[B_ADDR]], align 16 +// CHECK-NEXT: [[TMP0:%.*]] = load <8 x i16>, <8 x i16>* [[A_ADDR]], align 16 +// CHECK-NEXT: [[TMP1:%.*]] = load <8 x i16>, <8 x i16>* [[B_ADDR]], align 16 +// CHECK-NEXT: [[CMP:%.*]] = icmp eq <8 x i16> [[TMP0]], [[TMP1]] +// CHECK-NEXT: [[SEXT:%.*]] = sext <8 x i1> [[CMP]] to <8 x i16> +// CHECK-NEXT: ret <8 x i16> [[SEXT]] +// +// ERROR: returning 'int' from a function with incompatible result type +vector unsigned short ui16(vector unsigned short a, vector unsigned short b) { + return a == b; +} + +// CHECK-LABEL: @si16( +// CHECK-NEXT: entry: +// CHECK-NEXT: [[A_ADDR:%.*]] = alloca <8 x i16>, align 16 +// CHECK-NEXT: [[B_ADDR:%.*]] = alloca <8 x i16>, align 16 +// CHECK-NEXT: store <8 x i16> [[A:%.*]], <8 x i16>* [[A_ADDR]], align 16 +// CHECK-NEXT: store <8 x i16> [[B:%.*]], <8 x i16>* [[B_ADDR]], align 16 +// CHECK-NEXT: [[TMP0:%.*]] = load <8 x i16>, <8 x i16>* [[A_ADDR]], align 16 +// CHECK-NEXT: [[TMP1:%.*]] = load <8 x i16>, <8 x i16>* [[B_ADDR]], align 16 +// CHECK-NEXT: [[CMP:%.*]] = icmp eq <8 x i16> [[TMP0]], [[TMP1]] +// CHECK-NEXT: [[SEXT:%.*]] = sext <8 x i1> [[CMP]] to <8 x i16> +// CHECK-NEXT: ret <8 x i16> [[SEXT]] +// +// ERROR: returning 'int' from a function with incompatible result type +vector signed short si16(vector signed short a, vector signed short b) { + return a == b; +} + +// CHECK-LABEL: @ui32( +// CHECK-NEXT: entry: +// CHECK-NEXT: [[A_ADDR:%.*]] = alloca <4 x i32>, align 16 +// CHECK-NEXT: [[B_ADDR:%.*]] = alloca <4 x i32>, align 16 +// CHECK-NEXT: store <4 x i32> [[A:%.*]], <4 x i32>* [[A_ADDR]], align 16 +// CHECK-NEXT: store <4 x i32> [[B:%.*]], <4 x i32>* [[B_ADDR]], align 16 +// CHECK-NEXT: [[TMP0:%.*]] = load <4 x i32>, <4 x i32>* [[A_ADDR]], align 16 +// CHECK-NEXT: [[TMP1:%.*]] = load <4 x i32>, <4 x i32>* [[B_ADDR]], align 16 +// CHECK-NEXT: [[CMP:%.*]] = icmp eq <4 x i32> [[TMP0]], [[TMP1]] +// CHECK-NEXT: [[SEXT:%.*]] = sext <4 x i1> [[CMP]] to <4 x i32> +// CHECK-NEXT: ret <4 x i32> [[SEXT]] +// +// ERROR: returning 'int' from a function with incompatible result type +vector unsigned int ui32(vector unsigned int a, vector unsigned int b) { + return a == b; +} + +// CHECK-LABEL: @si32( +// CHECK-NEXT: entry: +// CHECK-NEXT: [[A_ADDR:%.*]] = alloca <4 x i32>, align 16 +// CHECK-NEXT: [[B_ADDR:%.*]] = alloca <4 x i32>, align 16 +// CHECK-NEXT: store <4 x i32> [[A:%.*]], <4 x i32>* [[A_ADDR]], align 16 +// CHECK-NEXT: store <4 x i32> [[B:%.*]], <4 x i32>* [[B_ADDR]], align 16 +// CHECK-NEXT: [[TMP0:%.*]] = load <4 x i32>, <4 x i32>* [[A_ADDR]], align 16 +// CHECK-NEXT: [[TMP1:%.*]] = load <4 x i32>, <4 x i32>* [[B_ADDR]], align 16 +// CHECK-NEXT: [[CMP:%.*]] = icmp eq <4 x i32> [[TMP0]], [[TMP1]] +// CHECK-NEXT: [[SEXT:%.*]] = sext <4 x i1> [[CMP]] to <4 x i32> +// CHECK-NEXT: ret <4 x i32> [[SEXT]] +// +// ERROR: returning 'int' from a function with incompatible result type +vector signed int si32(vector signed int a, vector signed int b) { + return a == b; +} + +// CHECK-LABEL: @si64( +// CHECK-NEXT: entry: +// CHECK-NEXT: [[A_ADDR:%.*]] = alloca <2 x i64>, align 16 +// CHECK-NEXT: [[B_ADDR:%.*]] = alloca <2 x i64>, align 16 +// CHECK-NEXT: store <2 x i64> [[A:%.*]], <2 x i64>* [[A_ADDR]], align 16 +// CHECK-NEXT: store <2 x i64> [[B:%.*]], <2 x i64>* [[B_ADDR]], align 16 +// CHECK-NEXT: [[TMP0:%.*]] = load <2 x i64>, <2 x i64>* [[A_ADDR]], align 16 +// CHECK-NEXT: [[TMP1:%.*]] = load <2 x i64>, <2 x i64>* [[B_ADDR]], align 16 +// CHECK-NEXT: [[CMP:%.*]] = icmp eq <2 x i64> [[TMP0]], [[TMP1]] +// CHECK-NEXT: [[SEXT:%.*]] = sext <2 x i1> [[CMP]] to <2 x i64> +// CHECK-NEXT: ret <2 x i64> [[SEXT]] +// +// ERROR: returning 'int' from a function with incompatible result type +vector long long si64(vector long long a, vector long long b) { + return a == b; +} + +// CHECK-LABEL: @f32( +// CHECK-NEXT: entry: +// CHECK-NEXT: [[A_ADDR:%.*]] = alloca <4 x float>, align 16 +// CHECK-NEXT: [[B_ADDR:%.*]] = alloca <4 x float>, align 16 +// CHECK-NEXT: store <4 x float> [[A:%.*]], <4 x float>* [[A_ADDR]], align 16 +// CHECK-NEXT: store <4 x float> [[B:%.*]], <4 x float>* [[B_ADDR]], align 16 +// CHECK-NEXT: [[TMP0:%.*]] = load <4 x float>, <4 x float>* [[A_ADDR]], align 16 +// CHECK-NEXT: [[TMP1:%.*]] = load <4 x float>, <4 x float>* [[B_ADDR]], align 16 +// CHECK-NEXT: [[CMP:%.*]] = fcmp oeq <4 x float> [[TMP0]], [[TMP1]] +// CHECK-NEXT: [[SEXT:%.*]] = sext <4 x i1> [[CMP]] to <4 x i32> +// CHECK-NEXT: ret <4 x i32> [[SEXT]] +// +// ERROR: returning 'int' from a function with incompatible result type +vector int f32(vector float a, vector float b) { + return a == b; +} + +// CHECK-LABEL: @f64( +// CHECK-NEXT: entry: +// CHECK-NEXT: [[A_ADDR:%.*]] = alloca <2 x double>, align 16 +// CHECK-NEXT: [[B_ADDR:%.*]] = alloca <2 x double>, align 16 +// CHECK-NEXT: store <2 x double> [[A:%.*]], <2 x double>* [[A_ADDR]], align 16 +// CHECK-NEXT: store <2 x double> [[B:%.*]], <2 x double>* [[B_ADDR]], align 16 +// CHECK-NEXT: [[TMP0:%.*]] = load <2 x double>, <2 x double>* [[A_ADDR]], align 16 +// CHECK-NEXT: [[TMP1:%.*]] = load <2 x double>, <2 x double>* [[B_ADDR]], align 16 +// CHECK-NEXT: [[CMP:%.*]] = fcmp oeq <2 x double> [[TMP0]], [[TMP1]] +// CHECK-NEXT: [[SEXT:%.*]] = sext <2 x i1> [[CMP]] to <2 x i64> +// CHECK-NEXT: ret <2 x i64> [[SEXT]] +// +// ERROR: returning 'int' from a function with incompatible result type +vector long long f64(vector double a, vector double b) { + return a == b; +}