Index: clang/docs/LanguageExtensions.rst =================================================================== --- clang/docs/LanguageExtensions.rst +++ clang/docs/LanguageExtensions.rst @@ -475,7 +475,7 @@ +,--,*,/,% yes yes yes -- bitwise operators &,|,^,~ yes yes yes -- >>,<< yes yes yes -- -!, &&, || yes -- yes [#]_ -- +!, &&, || yes -- yes -- ==, !=, >, <, >=, <= yes yes yes -- = yes yes yes yes :? [#]_ yes -- yes -- @@ -488,7 +488,6 @@ See also :ref:`langext-__builtin_shufflevector`, :ref:`langext-__builtin_convertvector`. -.. [#] unary operator ! is not implemented, however && and || are. .. [#] While OpenCL and GCC vectors both implement the comparison operator(?:) as a 'select', they operate somewhat differently. OpenCL selects based on signedness of the condition operands, but GCC vectors use normal bool conversions (that is, != 0). Index: clang/lib/CodeGen/CGExprScalar.cpp =================================================================== --- clang/lib/CodeGen/CGExprScalar.cpp +++ clang/lib/CodeGen/CGExprScalar.cpp @@ -2742,7 +2742,9 @@ Value *ScalarExprEmitter::VisitUnaryLNot(const UnaryOperator *E) { // Perform vector logical not on comparison with zero vector. - if (E->getType()->isExtVectorType()) { + if (E->getType()->isVectorType() && + E->getType()->castAs()->getVectorKind() == + VectorType::GenericVector) { Value *Oper = Visit(E->getSubExpr()); Value *Zero = llvm::Constant::getNullValue(Oper->getType()); Value *Result; Index: clang/lib/Sema/SemaExpr.cpp =================================================================== --- clang/lib/Sema/SemaExpr.cpp +++ clang/lib/Sema/SemaExpr.cpp @@ -14436,12 +14436,19 @@ return ExprError(Diag(OpLoc, diag::err_typecheck_unary_expr) << resultType << Input.get()->getSourceRange()); } + // Vector logical not returns the signed variant of the operand type. + resultType = GetSignedVectorType(resultType); + break; + } else if (Context.getLangOpts().CPlusPlus && resultType->isVectorType()) { + const VectorType *VTy = resultType->castAs(); + if (VTy->getVectorKind() != VectorType::GenericVector) + return ExprError(Diag(OpLoc, diag::err_typecheck_unary_expr) + << resultType << Input.get()->getSourceRange()); + // Vector logical not returns the signed variant of the operand type. resultType = GetSignedVectorType(resultType); break; } else { - // FIXME: GCC's vector extension permits the usage of '!' with a vector - // type in C++. We should allow that here too. return ExprError(Diag(OpLoc, diag::err_typecheck_unary_expr) << resultType << Input.get()->getSourceRange()); } Index: clang/test/CodeGen/vector-1.cpp =================================================================== --- /dev/null +++ clang/test/CodeGen/vector-1.cpp @@ -0,0 +1,216 @@ +// RUN: %clang_cc1 -emit-llvm %s -o - | FileCheck %s + +typedef __attribute__((__vector_size__(16))) float float4; +typedef __attribute__((__vector_size__(16))) int int4; +typedef __attribute__((__vector_size__(16))) unsigned int uint4; + +// CHECK: @_Z4testPDv4_f +// CHECK: store <4 x float> +void test(float4 *out) { + *out = ((float4){1.0f, 2.0f, 3.0f, 4.0f}); +} + +// CHECK: @_Z5test1PDv4_f +// CHECK: store <4 x float> +// CHECK: store <4 x float> +void test1(float4 *out) { + float a = 1.0f; + float b = 2.0f; + float c = 3.0f; + float d = 4.0f; + *out = ((float4){a, b, c, d}); +} + +// CHECK: @_Z5test3PDv4_fS0_f +void test3(float4 *ap, float4 *bp, float c) { + float4 a = *ap; + float4 b = *bp; + + // CHECK: fadd <4 x float> + // CHECK: fsub <4 x float> + // CHECK: fmul <4 x float> + // CHECK: fdiv <4 x float> + a = a + b; + a = a - b; + a = a * b; + a = a / b; + + // CHECK: fadd <4 x float> + // CHECK: fsub <4 x float> + // CHECK: fmul <4 x float> + // CHECK: fdiv <4 x float> + a = a + c; + a = a - c; + a = a * c; + a = a / c; + + // CHECK: fadd <4 x float> + // CHECK: fsub <4 x float> + // CHECK: fmul <4 x float> + // CHECK: fdiv <4 x float> + a += b; + a -= b; + a *= b; + a /= b; + + // CHECK: fadd <4 x float> + // CHECK: fsub <4 x float> + // CHECK: fmul <4 x float> + // CHECK: fdiv <4 x float> + a += c; + a -= c; + a *= c; + a /= c; +} + +// CHECK: @_Z5test4PDv4_iS0_i +void test4(int4 *ap, int4 *bp, int c) { + int4 a = *ap; + int4 b = *bp; + + // CHECK: add <4 x i32> + // CHECK: sub <4 x i32> + // CHECK: mul <4 x i32> + // CHECK: sdiv <4 x i32> + // CHECK: srem <4 x i32> + a = a + b; + a = a - b; + a = a * b; + a = a / b; + a = a % b; + + // CHECK: add <4 x i32> + // CHECK: sub <4 x i32> + // CHECK: mul <4 x i32> + // CHECK: sdiv <4 x i32> + // CHECK: srem <4 x i32> + a = a + c; + a = a - c; + a = a * c; + a = a / c; + a = a % c; + + // CHECK: add <4 x i32> + // CHECK: sub <4 x i32> + // CHECK: mul <4 x i32> + // CHECK: sdiv <4 x i32> + // CHECK: srem <4 x i32> + a += b; + a -= b; + a *= b; + a /= b; + a %= b; + + // CHECK: add <4 x i32> + // CHECK: sub <4 x i32> + // CHECK: mul <4 x i32> + // CHECK: sdiv <4 x i32> + // CHECK: srem <4 x i32> + a += c; + a -= c; + a *= c; + a /= c; + a %= c; + + // Vector comparisons. + // CHECK: icmp slt + // CHECK: icmp sle + // CHECK: icmp sgt + // CHECK: icmp sge + // CHECK: icmp eq + // CHECK: icmp ne + int4 cmp; + cmp = a < b; + cmp = a <= b; + cmp = a > b; + cmp = a >= b; + cmp = a == b; + cmp = a != b; +} + +// CHECK: @_Z5test5PDv4_fS0_i +void test5(float4 *ap, float4 *bp, int c) { + float4 a = *ap; + float4 b = *bp; + + // Vector comparisons. + // CHECK: fcmp olt + // CHECK: fcmp ole + // CHECK: fcmp ogt + // CHECK: fcmp oge + // CHECK: fcmp oeq + // CHECK: fcmp une + int4 cmp; + cmp = a < b; + cmp = a <= b; + cmp = a > b; + cmp = a >= b; + cmp = a == b; + cmp = a != b; +} + +// CHECK: @_Z5test6PDv4_jS0_j +void test6(uint4 *ap, uint4 *bp, unsigned c) { + uint4 a = *ap; + uint4 b = *bp; + int4 d; + + // CHECK: udiv <4 x i32> + // CHECK: urem <4 x i32> + a = a / b; + a = a % b; + + // CHECK: udiv <4 x i32> + // CHECK: urem <4 x i32> + a = a / c; + a = a % c; + + // CHECK: icmp ult + // CHECK: icmp ule + // CHECK: icmp ugt + // CHECK: icmp uge + // CHECK: icmp eq + // CHECK: icmp ne + d = a < b; + d = a <= b; + d = a > b; + d = a >= b; + d = a == b; + d = a != b; +} + +// CHECK: @_Z5test7Dv4_j +int4 test7(uint4 V0) { + // CHECK: [[CMP0:%.*]] = icmp eq <4 x i32> [[V0:%.*]], zeroinitializer + // CHECK-NEXT: [[V1:%.*]] = sext <4 x i1> [[CMP0]] to <4 x i32> + int4 V = !V0; + // CHECK: [[CMP1:%.*]] = icmp ne <4 x i32> [[V2:%.*]], zeroinitializer + // CHECK-NEXT: [[CMP2:%.*]] = icmp ne <4 x i32> [[V3:%.*]], zeroinitializer + // CHECK-NEXT: [[AND0:%.*]] = and <4 x i1> [[CMP1]], [[CMP2]] + // CHECK-NEXT: [[V4:%.*]] = sext <4 x i1> [[AND0]] to <4 x i32> + V = V && V; + // CHECK: [[CMP3:%.*]] = icmp ne <4 x i32> [[V5:%.*]], zeroinitializer + // CHECK-NEXT: [[CMP4:%.*]] = icmp ne <4 x i32> [[V6:%.*]], zeroinitializer + // CHECK-NEXT: [[OR0:%.*]] = or <4 x i1> [[CMP3]], [[CMP4]] + // CHECK-NEXT: [[V7:%.*]] = sext <4 x i1> [[OR0]] to <4 x i32> + V = V || V; + return V; +} + +// CHECK: @_Z5test8Dv4_fS_ +int4 test8(float4 V0, float4 V1) { + // CHECK: [[CMP0:%.*]] = fcmp oeq <4 x float> [[V0:%.*]], zeroinitializer + // CHECK-NEXT: [[V1:%.*]] = sext <4 x i1> [[CMP0]] to <4 x i32> + int4 V = !V0; + // CHECK: [[CMP1:%.*]] = fcmp une <4 x float> [[V2:%.*]], zeroinitializer + // CHECK-NEXT: [[CMP2:%.*]] = fcmp une <4 x float> [[V3:%.*]], zeroinitializer + // CHECK-NEXT: [[AND0:%.*]] = and <4 x i1> [[CMP1]], [[CMP2]] + // CHECK-NEXT: [[V4:%.*]] = sext <4 x i1> [[AND0]] to <4 x i32> + V = V0 && V1; + // CHECK: [[CMP3:%.*]] = fcmp une <4 x float> [[V5:%.*]], zeroinitializer + // CHECK-NEXT: [[CMP4:%.*]] = fcmp une <4 x float> [[V6:%.*]], zeroinitializer + // CHECK-NEXT: [[OR0:%.*]] = or <4 x i1> [[CMP3]], [[CMP4]] + // CHECK-NEXT: [[V7:%.*]] = sext <4 x i1> [[OR0]] to <4 x i32> + V = V0 || V1; + return V; +} Index: clang/test/Sema/vector-gcc-compat.cpp =================================================================== --- clang/test/Sema/vector-gcc-compat.cpp +++ clang/test/Sema/vector-gcc-compat.cpp @@ -83,7 +83,7 @@ v2i64 v2i64_c = (v2i64){3, 1}; // expected-warning {{compound literals are a C99-specific feature}} v2i64 v2i64_r; - v2i64_r = !v2i64_a; // expected-error {{invalid argument type 'v2i64' (vector of 2 'long long' values) to unary expression}} + v2i64_r = !v2i64_a; v2i64_r = ~v2i64_a; v2i64_r = v2i64_a ? v2i64_b : v2i64_c;