User account creation filtered due to spam.

Bug 50060 - intrinsics not folded by the middle-end
Summary: intrinsics not folded by the middle-end
Status: RESOLVED FIXED
Alias: None
Product: gcc
Classification: Unclassified
Component: middle-end (show other bugs)
Version: 4.7.0
: P3 enhancement
Target Milestone: ---
Assignee: Not yet assigned to anyone
URL:
Keywords:
Depends on:
Blocks:
 
Reported: 2011-08-12 15:16 UTC by Paolo Carlini
Modified: 2016-07-20 14:44 UTC (History)
2 users (show)

See Also:
Host:
Target:
Build:
Known to work:
Known to fail:
Last reconfirmed:


Attachments
gcc7-pr50060.patch (1.36 KB, patch)
2016-07-15 14:21 UTC, Jakub Jelinek
Details | Diff

Note You need to log in before you can comment on or make changes to this bug.
Description Paolo Carlini 2011-08-12 15:16:40 UTC
Following up to 49813, this is a list of intrinsics, corresponding to C89 and C99 <math.h> (and C++11 <cmath>) facilities, not yet folded by the middle-end.

C89:
- fmod
- frexp

C99:
- lgamma
- llrint
- lrint
- nearbyint
- nextafter
- nexttoward
- remquo
- rint

Note: in the audit trail of PR49813, Comment #51, Jakub explains that nextafter and nexttoward should be doable rather easily.
Comment 1 Paolo Carlini 2011-08-12 16:12:56 UTC
Uhm, remquo is strange. I see a do_mpfr_remquo but the following C++11 snippet is rejected, I don't know why:

int r = 0;
constexpr double d = __builtin_remquo(1.0, 1.0, &r);
Comment 2 Paolo Carlini 2011-08-12 16:26:00 UTC
... frexp also don't understand at the moment. I see a fold_builtin_frexp but the following doesn't compile:

int r = 0;
constexpr double d = __builtin_frexp(1.0, &r);
Comment 3 Paolo Carlini 2011-08-12 17:00:10 UTC
I think we can safely scratch frexp & remquo from the list: I double checked that the middle-end functions correctly compute the constants.

(It seems more a problem with my C++ test snippets in Comments #1 / #2: I suppose any definition of such functions isn't viable for constexpr, because the body has to assign the pointed integer additionally to returning a value... If Jason could confirm it would be great)

Updated list:
C89:
- fmod

C99:
- lgamma
- llrint
- lrint
- nearbyint
- nextafter
- nexttoward
- rint
Comment 4 Jason Merrill 2011-08-12 21:17:05 UTC
(In reply to comment #3)
> (It seems more a problem with my C++ test snippets in Comments #1 / #2: I
> suppose any definition of such functions isn't viable for constexpr, because
> the body has to assign the pointed integer additionally to returning a value...
> If Jason could confirm it would be great)

Correct, the assignment makes it non-constant.
Comment 5 Paolo Carlini 2011-08-12 21:19:23 UTC
Thanks Jason.
Comment 6 Paul A. Bristow 2016-07-14 14:51:09 UTC
This is a serious 'fault' that prevents making constexpr and functions that use frexp, even though the mantissa and exponent are definitely constant.

This prevents using constexpr in Boost.Math functions and distributions, Boost.Multiprecision and Proposed Boost.Fixed-Point.

Suggestions on workaround(s)?

Two separate constexpr functions for mantissa and exponent?

One function that 'returns' both as a tuple/pair?

Either are a major nuisance to replace frexp.

(Perhaps a single function to 'return' both doesn't such a good idea now?)
Comment 7 Jakub Jelinek 2016-07-14 20:03:41 UTC
Shouldn't this be solvable in C++14 and later?
We still reject it:
error: ‘((y = 1), 6.2e-1)’ is not a constant expression
but I suppose with some hacking of cp/constexpr.c this could be handled.

constexpr double f1 (double x)
{
  int y = 0;
  return __builtin_frexp (x, &y);
}
constexpr int f2 (double x)
{
  int y = 0;
  __builtin_frexp (x, &y);
  return y;
}
constexpr double c1 = f1 (1.24);
constexpr int c2 = f2 (1.24);
Comment 8 Jakub Jelinek 2016-07-15 14:21:14 UTC
Created attachment 38912 [details]
gcc7-pr50060.patch

Untested patch (for -std=c++14 and later only).
Comment 9 Jakub Jelinek 2016-07-20 14:00:34 UTC
Author: jakub
Date: Wed Jul 20 14:00:02 2016
New Revision: 238520

URL: https://gcc.gnu.org/viewcvs?rev=238520&root=gcc&view=rev
Log:
	PR c++/50060
	* constexpr.c (cxx_eval_builtin_function_call): Pass false as lval
	when evaluating call arguments.  Use fold_builtin_call_array instead
	of fold_build_call_array_loc, return t if it returns NULL.  Otherwise
	check the result with potential_constant_expression and call
	cxx_eval_constant_expression on it.

	* g++.dg/cpp0x/constexpr-50060.C: New test.
	* g++.dg/cpp1y/constexpr-50060.C: New test.

Added:
    trunk/gcc/testsuite/g++.dg/cpp0x/constexpr-50060.C
    trunk/gcc/testsuite/g++.dg/cpp1y/constexpr-50060.C
Modified:
    trunk/gcc/cp/ChangeLog
    trunk/gcc/cp/constexpr.c
    trunk/gcc/testsuite/ChangeLog
Comment 10 Jakub Jelinek 2016-07-20 14:34:23 UTC
Should be fixed on the trunk (for C++14/C++17 and later).
Comment 11 Paul A. Bristow 2016-07-20 14:44:53 UTC
Thanks for all this, which looks helpful, but I am not able to use unreleased compiler versions, so meanwhile I am working to use a workaround (to allow me to see what other pitfalls lie ahead for the novice ;-).  FWIW my proof of concept is 

// Version that returns both mantissa and exponent as a tuple.
// Proof of concept only, ignoring sign, overflow, denorm, infinite and NaNs.
constexpr std::tuple<float, int> frexp(float f)
{
  int e = 0;

  if (f >= 1.f)
  {
    f /= 2 ;
    e++;
  }
  else if (f <= 0.1f)
  {
    f *= 2;
    e--;
  }
  return  std::make_tuple(f, e);
 }

allowing

constexpr std::tuple<float, int> ee = frexp(1.f);

(I can confirm by checking that debugging will not step into the function, and also I can assign the tuple or the elements to a constexpr variable.)

Of course, this isn't a 'drop-in' for std::frexp, nor templated on other floating-point types, like Boost.Multiprecision types, but it will help for now.

I hope that this can be resolved somehow eventually, though I fear the pointer update will always be a nono for constexpr, preventing a truely 'drop-in' solution thus preventing any function that uses frexp from being constexpr.