From patchwork Fri Jul 15 18:42:31 2016 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jakub Jelinek X-Patchwork-Id: 648949 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]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 3rrhJl5Lcqz9sBR for ; Sat, 16 Jul 2016 04:42:47 +1000 (AEST) Authentication-Results: ozlabs.org; dkim=pass (1024-bit key; unprotected) header.d=gcc.gnu.org header.i=@gcc.gnu.org header.b=AlF9ckji; dkim-atps=neutral DomainKey-Signature: a=rsa-sha1; c=nofws; d=gcc.gnu.org; h=list-id :list-unsubscribe:list-archive:list-post:list-help:sender:date :from:to:cc:subject:message-id:reply-to:mime-version :content-type; q=dns; s=default; b=KNWlS0zI9Pq4QebCzEc+IJgGeVZMT louaTuajTEhdzj66tDNwnhYQO2MMd2ZwQmrakzRKI4whYobEHI6g7AwOh8/OUBKb bzRzaoEqqrG38YNihn4KUJvuFpQ1Tbrm/4WIDkYOjckQmh8BBALumsW82GX5EyvG GM/CkR+oxI8Hpk= DKIM-Signature: v=1; a=rsa-sha1; c=relaxed; d=gcc.gnu.org; h=list-id :list-unsubscribe:list-archive:list-post:list-help:sender:date :from:to:cc:subject:message-id:reply-to:mime-version :content-type; s=default; bh=XKvx/45m1HHCn7+6anpeCh1S4nk=; b=AlF 9ckji60yWC5w7rDfCvte54U4kxJcxNzKTW+eMVx+pqTImNibQOo/s4oCCMSZVZaX 2Y/wl/WYyLm4gCeXr5EEQi2dort/nLmRdZ7d1t9ymIqG5MrU/JhvsuWlYs9LX669 2Fev1uOnXfjtLLHX0G05KJ/iyN64AKhtkXkrxZPY= Received: (qmail 115227 invoked by alias); 15 Jul 2016 18:42:40 -0000 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 Received: (qmail 115218 invoked by uid 89); 15 Jul 2016 18:42:39 -0000 Authentication-Results: sourceware.org; auth=none X-Virus-Found: No X-Spam-SWARE-Status: No, score=-3.2 required=5.0 tests=BAYES_00, RP_MATCHES_RCVD, SPF_HELO_PASS autolearn=ham version=3.3.2 spammy=021, 025, 725, folds X-HELO: mx1.redhat.com Received: from mx1.redhat.com (HELO mx1.redhat.com) (209.132.183.28) by sourceware.org (qpsmtpd/0.93/v0.84-503-g423c35a) with (AES256-GCM-SHA384 encrypted) ESMTPS; Fri, 15 Jul 2016 18:42:38 +0000 Received: from int-mx10.intmail.prod.int.phx2.redhat.com (int-mx10.intmail.prod.int.phx2.redhat.com [10.5.11.23]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mx1.redhat.com (Postfix) with ESMTPS id C7ED1883B1 for ; Fri, 15 Jul 2016 18:42:36 +0000 (UTC) Received: from tucnak.zalov.cz (ovpn-204-98.brq.redhat.com [10.40.204.98]) by int-mx10.intmail.prod.int.phx2.redhat.com (8.14.4/8.14.4) with ESMTP id u6FIgZ6F015118 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-GCM-SHA384 bits=256 verify=NO); Fri, 15 Jul 2016 14:42:36 -0400 Received: from tucnak.zalov.cz (localhost [127.0.0.1]) by tucnak.zalov.cz (8.15.2/8.15.2) with ESMTP id u6FIgXQa000792; Fri, 15 Jul 2016 20:42:33 +0200 Received: (from jakub@localhost) by tucnak.zalov.cz (8.15.2/8.15.2/Submit) id u6FIgWC7000791; Fri, 15 Jul 2016 20:42:32 +0200 Date: Fri, 15 Jul 2016 20:42:31 +0200 From: Jakub Jelinek To: Jason Merrill Cc: gcc-patches@gcc.gnu.org Subject: [C++ PATCH] Allow frexp etc. builtins in c++14 constexpr (PR c++/50060) Message-ID: <20160715184231.GX7387@tucnak.redhat.com> Reply-To: Jakub Jelinek MIME-Version: 1.0 Content-Disposition: inline User-Agent: Mutt/1.5.24 (2015-08-30) X-IsSubscribed: yes Hi! While in C++11, builtins returning two results, one of them by dereferencing a pointer argument can't be constexpr, in my understanding in C++14 generalized constexprs they can. So, this patch tweaks cxx_eval_builtin_function_call so that it handles how builtins.c folds these builtins (i.e. COMPOUND_EXPR with first operand being *arg = const1 and second operand const2, optionally all wrapped into a NON_LVALUE_EXPR. In addition, I've noticed that the lval argument is passed down to evaluation of arguments, that doesn't make sense to me, IMHO arguments should be always evakyated as rvalues (and for non-builtins they are). sincos (which has stores 2 results through pointers) is folded earlier into cexpi and thus worked already before. Bootstrapped/regtested on x86_64-linux and i686-linux, ok for trunk? 2016-07-15 Jakub Jelinek PR c++/50060 * constexpr.c (cxx_eval_builtin_function_call): Pass false as lval when evaluating call arguments, make the lval argument nameless. For C++14 and later, if new_call is COMPOUND_EXPR with a assignment and constant, evaluate the assignment and return the constant. * g++.dg/cpp1y/constexpr-50060.C: New test. Jakub --- gcc/cp/constexpr.c.jj 2016-07-11 22:18:01.000000000 +0200 +++ gcc/cp/constexpr.c 2016-07-15 15:27:50.820085561 +0200 @@ -1078,8 +1078,7 @@ get_nth_callarg (tree t, int n) static tree cxx_eval_builtin_function_call (const constexpr_ctx *ctx, tree t, tree fun, - bool lval, - bool *non_constant_p, bool *overflow_p) + bool, bool *non_constant_p, bool *overflow_p) { const int nargs = call_expr_nargs (t); tree *args = (tree *) alloca (nargs * sizeof (tree)); @@ -1105,7 +1104,7 @@ cxx_eval_builtin_function_call (const co for (i = 0; i < nargs; ++i) { args[i] = cxx_eval_constant_expression (&new_ctx, CALL_EXPR_ARG (t, i), - lval, &dummy1, &dummy2); + false, &dummy1, &dummy2); if (bi_const_p) /* For __built_in_constant_p, fold all expressions with constant values even if they aren't C++ constant-expressions. */ @@ -1119,6 +1118,27 @@ cxx_eval_builtin_function_call (const co /* Fold away the NOP_EXPR from fold_builtin_n. */ new_call = fold (new_call); force_folding_builtin_constant_p = save_ffbcp; + + if (cxx_dialect >= cxx14) + { + tree r = new_call; + if (TREE_CODE (r) == NON_LVALUE_EXPR) + r = TREE_OPERAND (r, 0); + if (TREE_CODE (r) == COMPOUND_EXPR + && TREE_CODE (TREE_OPERAND (r, 0)) == MODIFY_EXPR + && reduced_constant_expression_p (TREE_OPERAND (TREE_OPERAND (r, 0), + 1))) + { + /* The frexp, modf, remquo and lgamma_r builtins (and their variants) + with &var as last argument are folded into + (var = const1), const2, sometimes wrapped into + NON_LVALUE_EXPR. */ + cxx_eval_constant_expression (&new_ctx, TREE_OPERAND (r, 0), + false, non_constant_p, overflow_p); + new_call = TREE_OPERAND (r, 1); + } + } + VERIFY_CONSTANT (new_call); return new_call; } --- gcc/testsuite/g++.dg/cpp1y/constexpr-50060.C.jj 2016-07-15 15:34:12.469124944 +0200 +++ gcc/testsuite/g++.dg/cpp1y/constexpr-50060.C 2016-07-15 15:59:36.285303078 +0200 @@ -0,0 +1,100 @@ +// PR c++/50060 +// { dg-do compile { target c++14 } } + +// sincos and lgamma_r aren't available in -std=c++14, +// only in -std=gnu++14. Use __builtin_* in that case. +extern "C" void sincos (double, double *, double *); +extern "C" double frexp (double, int *); +extern "C" double modf (double, double *); +extern "C" double remquo (double, double, int *); +extern "C" double lgamma_r (double, int *); + +constexpr double +f0 (double x) +{ + double y {}; + double z {}; + __builtin_sincos (x, &y, &z); + return y; +} + +constexpr double +f1 (double x) +{ + double y {}; + double z {}; + __builtin_sincos (x, &y, &z); + return z; +} + +constexpr double +f2 (double x) +{ + int y {}; + return frexp (x, &y); +} + +constexpr int +f3 (double x) +{ + int y {}; + frexp (x, &y); + return y; +} + +constexpr double +f4 (double x) +{ + double y {}; + return modf (x, &y); +} + +constexpr double +f5 (double x) +{ + double y {}; + modf (x, &y); + return y; +} + +constexpr double +f6 (double x, double y) +{ + int z {}; + return remquo (x, y, &z); +} + +constexpr int +f7 (double x, double y) +{ + int z {}; + remquo (x, y, &z); + return z; +} + +constexpr double +f8 (double x) +{ + int y {}; + return __builtin_lgamma_r (x, &y); +} + +constexpr int +f9 (double x) +{ + int y {}; + __builtin_lgamma_r (x, &y); + return y; +} + +static_assert (f0 (0.0) == 0.0, ""); +static_assert (f1 (0.0) == 1.0, ""); +static_assert (f2 (6.5) == 0.8125, ""); +static_assert (f3 (6.5) == 3, ""); +static_assert (f4 (-7.25) == -0.25, ""); +static_assert (f5 (-7.25) == -7.0, ""); +static_assert (f6 (3.0, 2.0) == -1.0, ""); +static_assert (f7 (3.0, 2.0) == 2, ""); +static_assert (f8 (0.75) >= 0.20 && f8 (0.75) <= 0.21, ""); +static_assert (f8 (0.75) >= 0.20 && f8 (0.75) <= 0.21, ""); +static_assert (f9 (0.75) == 1, "");