From patchwork Wed Oct 17 19:56:35 2012 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Marc Glisse X-Patchwork-Id: 192134 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from sourceware.org (server1.sourceware.org [209.132.180.131]) by ozlabs.org (Postfix) with SMTP id D4BCE2C0096 for ; Thu, 18 Oct 2012 06:56:47 +1100 (EST) Comment: DKIM? See http://www.dkim.org DKIM-Signature: v=1; a=rsa-sha1; c=relaxed/relaxed; d=gcc.gnu.org; s=default; x=1351108608; h=Comment: DomainKey-Signature:Received:Received:Received:Received:Received: Date:From:To:cc:Subject:Message-ID:User-Agent:MIME-Version: Content-Type:Mailing-List:Precedence:List-Id:List-Unsubscribe: List-Archive:List-Post:List-Help:Sender:Delivered-To; bh=L4D6rrD cRPw1vR/0wyfByaFhro8=; b=W9Nkax9suq7tu5eg+HnToQ1Z7nkteP3WCc4r7PT NxCt8saWIvSnsTWIoZP3/lzH3yXe0MrisROnGgqnmTIgGe5GIUPIrOG00K6Ch+7B uVryNPr3G4fGMn8c1zK59kJYi5ykTGzakdmM8DfhsN94T1z0fhtGOgCr8/bCxttP qx90= Comment: DomainKeys? See http://antispam.yahoo.com/domainkeys DomainKey-Signature: a=rsa-sha1; q=dns; c=nofws; s=default; d=gcc.gnu.org; h=Received:Received:X-SWARE-Spam-Status:X-Spam-Check-By:Received:Received:Received:Date:From:To:cc:Subject:Message-ID:User-Agent:MIME-Version:Content-Type:Mailing-List:Precedence:List-Id:List-Unsubscribe:List-Archive:List-Post:List-Help:Sender:Delivered-To; b=Zh43CiqnYHnahiauL5hmG94Qb7HlDkIqtsGoX/8s+aY7Bzu/8IYGhY4a8yqV9U ReoTX8R4FVDhlVxgCnh5gn7arKakU9IdL74F2WGeAtWskgZzzAIaVWpFwaclyUcJ IuWmzZ9GT7dKh0+E4B7k3td/ruxNYoxr85eshbmLU2trU=; Received: (qmail 27590 invoked by alias); 17 Oct 2012 19:56:44 -0000 Received: (qmail 27581 invoked by uid 22791); 17 Oct 2012 19:56:43 -0000 X-SWARE-Spam-Status: No, hits=-7.2 required=5.0 tests=AWL, BAYES_00, KHOP_RCVD_UNTRUST, RCVD_IN_DNSWL_HI, RP_MATCHES_RCVD, TW_AV, TW_CX X-Spam-Check-By: sourceware.org Received: from mail4-relais-sop.national.inria.fr (HELO mail4-relais-sop.national.inria.fr) (192.134.164.105) by sourceware.org (qpsmtpd/0.43rc1) with ESMTP; Wed, 17 Oct 2012 19:56:37 +0000 Received: from stedding.saclay.inria.fr ([193.55.250.194]) by mail4-relais-sop.national.inria.fr with ESMTP/TLS/DHE-RSA-AES128-SHA; 17 Oct 2012 21:56:35 +0200 Received: from glisse (helo=localhost) by stedding.saclay.inria.fr with local-esmtp (Exim 4.80) (envelope-from ) id 1TOZjH-0004J6-4w; Wed, 17 Oct 2012 21:56:35 +0200 Date: Wed, 17 Oct 2012 21:56:35 +0200 (CEST) From: Marc Glisse To: gcc-patches@gcc.gnu.org cc: jason@redhat.com Subject: [C++] Handle ?: for vectors Message-ID: User-Agent: Alpine 2.02 (DEB 1266 2009-07-14) MIME-Version: 1.0 Mailing-List: contact gcc-patches-help@gcc.gnu.org; run by ezmlm Precedence: bulk List-Id: List-Unsubscribe: List-Archive: List-Post: List-Help: Sender: gcc-patches-owner@gcc.gnu.org Delivered-To: mailing list gcc-patches@gcc.gnu.org Hello, this patch adds support for vector conditions to the C++ front-end. Note that the testcase currently only applies to x86. This is because there is work remaining in the middle-end for the case where vector selection for this vector mode is not provided by the target. There are also many middle-end bugs, so the testcase will crash with -O. I believe it makes sense to introduce front-end support early, because this way I'll be able to add testcases when I fix middle-end issues. Not documenting until this is actually usable. gcc/ * tree.c (signed_or_unsigned_type_for): Handle vectors. gcc/cp/ * typeck.c (build_x_conditional_expr): Handle VEC_COND_EXPR. * call.c (build_conditional_expr_1): Likewise. gcc/c-family/ * c-common.c (scalar_to_vector): Handle VEC_COND_EXPR. gcc/testsuite/ * g++.dg/ext/vector19.C: New testcase. Index: tree.c =================================================================== --- tree.c (revision 192542) +++ tree.c (working copy) @@ -10229,20 +10229,31 @@ widest_int_cst_value (const_tree x) /* If TYPE is an integral or pointer type, return an integer type with the same precision which is unsigned iff UNSIGNEDP is true, or itself if TYPE is already an integer type of signedness UNSIGNEDP. */ tree signed_or_unsigned_type_for (int unsignedp, tree type) { if (TREE_CODE (type) == INTEGER_TYPE && TYPE_UNSIGNED (type) == unsignedp) return type; + if (TREE_CODE (type) == VECTOR_TYPE) + { + tree inner = TREE_TYPE (type); + tree inner2 = signed_or_unsigned_type_for (unsignedp, inner); + if (!inner2) + return NULL_TREE; + if (inner == inner2) + return type; + return build_vector_type (inner2, TYPE_VECTOR_SUBPARTS (type)); + } + if (!INTEGRAL_TYPE_P (type) && !POINTER_TYPE_P (type)) return NULL_TREE; return build_nonstandard_integer_type (TYPE_PRECISION (type), unsignedp); } /* If TYPE is an integral or pointer type, return an integer type with the same precision which is unsigned, or itself if TYPE is already an unsigned integer type. */ Index: c-family/c-common.c =================================================================== --- c-family/c-common.c (revision 192542) +++ c-family/c-common.c (working copy) @@ -11467,20 +11467,22 @@ scalar_to_vector (location_t loc, enum t return stv_firstarg; } break; case BIT_IOR_EXPR: case BIT_XOR_EXPR: case BIT_AND_EXPR: integer_only_op = true; /* ... fall through ... */ + case VEC_COND_EXPR: + case PLUS_EXPR: case MINUS_EXPR: case MULT_EXPR: case TRUNC_DIV_EXPR: case CEIL_DIV_EXPR: case FLOOR_DIV_EXPR: case ROUND_DIV_EXPR: case EXACT_DIV_EXPR: case TRUNC_MOD_EXPR: case FLOOR_MOD_EXPR: Index: cp/call.c =================================================================== --- cp/call.c (revision 192542) +++ cp/call.c (working copy) @@ -4366,43 +4366,120 @@ build_conditional_expr_1 (tree arg1, tre pedwarn (input_location, OPT_Wpedantic, "ISO C++ forbids omitting the middle term of a ?: expression"); /* Make sure that lvalues remain lvalues. See g++.oliva/ext1.C. */ if (real_lvalue_p (arg1)) arg2 = arg1 = stabilize_reference (arg1); else arg2 = arg1 = save_expr (arg1); } + /* If something has already gone wrong, just pass that fact up the + tree. */ + if (error_operand_p (arg1) + || error_operand_p (arg2) + || error_operand_p (arg3)) + return error_mark_node; + + orig_arg2 = arg2; + orig_arg3 = arg3; + + if (VECTOR_INTEGER_TYPE_P (TREE_TYPE (arg1))) + { + arg1 = force_rvalue (arg1, complain); + arg2 = force_rvalue (arg2, complain); + arg3 = force_rvalue (arg3, complain); + + tree arg1_type = TREE_TYPE (arg1); + arg2_type = TREE_TYPE (arg2); + arg3_type = TREE_TYPE (arg3); + + if (TREE_CODE (arg2_type) != VECTOR_TYPE + && TREE_CODE (arg3_type) != VECTOR_TYPE) + { + if (complain & tf_error) + error ("at least one operand of a vector conditional operator " + "must be a vector"); + return error_mark_node; + } + + if ((TREE_CODE (arg2_type) == VECTOR_TYPE) + != (TREE_CODE (arg3_type) == VECTOR_TYPE)) + { + enum stv_conv convert_flag = + scalar_to_vector (input_location, VEC_COND_EXPR, arg2, arg3, + complain & tf_error); + + switch (convert_flag) + { + case stv_error: + return error_mark_node; + case stv_firstarg: + { + arg2 = convert (TREE_TYPE (arg3_type), arg2); + arg2 = build_vector_from_val (arg3_type, arg2); + arg2_type = TREE_TYPE (arg2); + break; + } + case stv_secondarg: + { + arg3 = convert (TREE_TYPE (arg2_type), arg3); + arg3 = build_vector_from_val (arg2_type, arg3); + arg3_type = TREE_TYPE (arg3); + break; + } + default: + break; + } + } + + if (!same_type_p (arg2_type, arg3_type) + || TYPE_VECTOR_SUBPARTS (arg1_type) + != TYPE_VECTOR_SUBPARTS (arg2_type) + || TYPE_SIZE (arg1_type) != TYPE_SIZE (arg2_type)) + { + if (complain & tf_error) + error ("incompatible vector types in conditional expression: " + "%qT, %qT and %qT", TREE_TYPE (arg1), TREE_TYPE (orig_arg2), + TREE_TYPE (orig_arg3)); + return error_mark_node; + } + + if (!COMPARISON_CLASS_P (arg1)) + { + if (TYPE_UNSIGNED (TREE_TYPE (arg1_type))) + { + arg1_type = signed_type_for (arg1_type); + arg1 = convert (arg1_type, arg1); + } + arg1 = build2 (LT_EXPR, arg1_type, arg1, + build_zero_cst (arg1_type)); + } + return build3 (VEC_COND_EXPR, arg2_type, arg1, arg2, arg3); + } + /* [expr.cond] The first expression is implicitly converted to bool (clause _conv_). */ arg1 = perform_implicit_conversion_flags (boolean_type_node, arg1, complain, LOOKUP_NORMAL); - - /* If something has already gone wrong, just pass that fact up the - tree. */ - if (error_operand_p (arg1) - || error_operand_p (arg2) - || error_operand_p (arg3)) + if (error_operand_p (arg1)) return error_mark_node; /* [expr.cond] If either the second or the third operand has type (possibly cv-qualified) void, then the lvalue-to-rvalue (_conv.lval_), array-to-pointer (_conv.array_), and function-to-pointer (_conv.func_) standard conversions are performed on the second and third operands. */ - orig_arg2 = arg2; - orig_arg3 = arg3; arg2_type = unlowered_expr_type (arg2); arg3_type = unlowered_expr_type (arg3); if (VOID_TYPE_P (arg2_type) || VOID_TYPE_P (arg3_type)) { /* Do the conversions. We don't these for `void' type arguments since it can't have any effect and since decay_conversion does not handle that case gracefully. */ if (!VOID_TYPE_P (arg2_type)) arg2 = decay_conversion (arg2, complain); if (!VOID_TYPE_P (arg3_type)) Index: cp/typeck.c =================================================================== --- cp/typeck.c (revision 192542) +++ cp/typeck.c (working copy) @@ -5803,21 +5803,22 @@ build_x_conditional_expr (location_t loc || (op1 && type_dependent_expression_p (op1)) || type_dependent_expression_p (op2)) return build_min_nt_loc (loc, COND_EXPR, ifexp, op1, op2); ifexp = build_non_dependent_expr (ifexp); if (op1) op1 = build_non_dependent_expr (op1); op2 = build_non_dependent_expr (op2); } expr = build_conditional_expr (ifexp, op1, op2, complain); - if (processing_template_decl && expr != error_mark_node) + if (processing_template_decl && expr != error_mark_node + && TREE_CODE (expr) != VEC_COND_EXPR) { tree min = build_min_non_dep (COND_EXPR, expr, orig_ifexp, orig_op1, orig_op2); /* In C++11, remember that the result is an lvalue or xvalue. In C++98, lvalue_kind can just assume lvalue in a template. */ if (cxx_dialect >= cxx0x && lvalue_or_rvalue_with_address_p (expr) && !lvalue_or_rvalue_with_address_p (min)) TREE_TYPE (min) = cp_build_reference_type (TREE_TYPE (min), !real_lvalue_p (expr)); Index: testsuite/g++.dg/ext/vector19.C =================================================================== --- testsuite/g++.dg/ext/vector19.C (revision 0) +++ testsuite/g++.dg/ext/vector19.C (revision 0) @@ -0,0 +1,56 @@ +/* { dg-do compile { target i?86-*-* x86_64-*-* } } */ +/* { dg-options "-std=c++11 -mavx2" } */ + +// The target restrictions and the -mavx2 flag are meant to disappear +// once vector lowering is in place. + +typedef double vec __attribute__((vector_size(2*sizeof(double)))); +typedef signed char vec2 __attribute__((vector_size(16))); +typedef unsigned char vec2u __attribute__((vector_size(16))); + +void f (vec *x, vec *y, vec *z) +{ + *x = (*y < *z) ? *x : *y; +} + +void g (vec *x, vec *y, vec *z) +{ + *x = (*y < *z) ? *x : 42; +} + +void h (vec *x, vec *y, vec *z) +{ + *x = (*y < *z) ? 3. : *y; +} + +void i1 (vec *x, vec *y, vec *z) +{ + auto c = *y < *z; + *x = c ? *x : *y; +} + +void i2 (vec2 *x, vec2 *y, vec2u *z) +{ + *x = *y ? *x : *y; + *y = *z ? *x : *y; +} + +void j (vec2 *x, vec2 *y, vec2 *z, vec *t) +{ + *x = (*y < *z) ? *x : 4.2; /* { dg-error "" } */ + *y = (*x < *z) ? 2.5 : *y; /* { dg-error "" } */ + *t = *t ? *t : *t; /* { dg-error "" } */ + *z = (*x < *z) ? '1' : '0'; /* { dg-error "" } */ + // The last one may eventually be accepted. +} + +template +auto k (A *a, B b) -> decltype (*a ? *a : b); + +void k (...) {} + +void l (vec2 *v, double x) +{ + k (v, x); +} +