[Bug libstdc++/50724] isnan broken by -ffinite-math-only in g++
http://gcc.gnu.org/bugzilla/show_bug.cgi?id=50724 Ethan Tira-Thompson changed: What|Removed |Added Status|RESOLVED|UNCONFIRMED Resolution|INVALID | --- Comment #2 from Ethan Tira-Thompson 2011-10-14 14:27:13 UTC --- Well, that's not actually true: -fno-finite-math is telling the compiler to assume finite results during computation, but that doesn't mean there are "no NaNs". For example, I need isnan/isfinite to validate my users' input before I can ensure that invariant afterward. Clearly the bit pattern still exists in the universe. I'd also argue classification functions are not "arithmetic" and thus not covered by -fno-finite-math ("Allow optimizations for floating-point arithmetic") Finally, I think you're being quick to brush off the consistency issue, both with earlier gcc versions and with math.h. I find it quite disconcerting that isnan behavior changes between the two headers. Is your concern that __builtin_isnan is called internally during fp computations and we need to optimize that away in order to provide the speed advantages requested by -fno-finite-math? In that case, I propose cmath should be updated to check __FINITE_MATH_ONLY__ in its user-facing isnan and fall back to a safe method like math.h is currently using (apparently __isnan/__isnanf). Otherwise, as I established above, I don't think it's safe to 'optimize' away the floating point classification functions: the first issue above is code safety/security, the second is pedantic regarding documentation, and the third is a consistency issue. Thanks!
[Bug middle-end/50724] isnan broken by -ffinite-math-only in g++
http://gcc.gnu.org/bugzilla/show_bug.cgi?id=50724 --- Comment #9 from Ethan Tira-Thompson 2011-10-14 20:07:41 UTC --- Thanks, I think Michael hit the nail on the head for summarizing my intention, I'm satisfied to file this as a feature request (although personally I'd still call it a bug ;)) For reference regarding the test case, I agree with your point that 0.f/0 needn't be a reliable NaN generator under -ffast-math. The original source was actually using std::numeric_limits::quiet_NaN() and/or signaling_NaN(), but I switched to 0.f/0 in order to test under C (not-++) and forgot to switch back. So yeah, considering numeric_limits still returns the NaN bit patterns regardless of -ff-m-o, it's unbalanced that isnan is prevented from detecting them. Regardless, disabling classification routines is going beyond the scope of "math" and "arithmetic" as per the name of the flag and its documentation. (For those oversimplifying -ff-m-o as "No NaNs", perhaps you would like to add a new -fno-nans or perhaps -fno-quiet-nans flag if that is what you really want -ffinite-math-only to mean...) In the three linked bug reports, the first is basically a "don't do that" without discussion, the second specifically complains about the lack of discussion, and the third is redirected toward fixing an issue in -mno-ieee without resolving the -ffinite-math-only aspect.
[Bug middle-end/50724] isnan broken by -ffinite-math-only in g++
http://gcc.gnu.org/bugzilla/show_bug.cgi?id=50724 --- Comment #11 from Ethan Tira-Thompson 2011-10-14 22:07:44 UTC --- Marc: is this code perusable? I'm curious because I expect either the calculations may generate NaN or not at all. If they might and you even have test cases to handle it, then I'm surprised you would ever want to support running with -ff-m-o. Conversely if you knew the code doesn't generate the nonfinite values, then you don't need the classifications in the first place...? I'm guessing (and apologies if this is inaccurate) that this might boil down to saying that you want to interpret an end user setting -ff-m-o as an opportunity to skip validating their input or skip doing assertions during its processing, which could be a reasonable thing to do, but that's a choice I'd rather leave to individual developers, e.g. can also wrap code with #if __FINITE_MATH_ONLY__==0 or such... Or in other words, it's only a missed optimization if you wind up with classification calls, whereas it's a full-fledged execution error when NaN gets past validation.
[Bug middle-end/50724] isnan broken by -ffinite-math-only in g++
http://gcc.gnu.org/bugzilla/show_bug.cgi?id=50724 Ethan Tira-Thompson changed: What|Removed |Added Status|RESOLVED|REOPENED Resolution|INVALID | --- Comment #14 from Ethan Tira-Thompson 2011-10-15 14:01:11 UTC --- Richard said: > The documentation states > "Allow optimizations for floating-point arithmetic that > assume that arguments and results are not NaNs or +-Infs." Yes, that's my argument as well. Note ARITHMETIC. Also note MATH in the name of both --finite-MATH-only, and -ffast-MATH it falls under. And it doesn't reference the 'math library' to qualify that. Basically, if you want to close on this point, I want to see you explicitly argue why the classification functions should be considered arithmetic. I'm going to nail this down and list there are 5 classification functions (fpclassify, infinite, isinf, isnan, isnormal) and the vast majority of the other library functions are obviously proper arithmetic operations. The ones that aren't (signbit, copysign, nextafter, nan), you're exactly right that we should carefully consider the result of NaN optimization ("special cases"). You don't have to do this if *you* don't want to, but it should be done and it sounds like no one has. > This has been discussed to death already, and the present behavior is how > GCC behaved since ever. Except also NOT TRUE. It currently doesn't behave this way with math.h. It didn't behave this way in 4.1 (Fedora) or 4.2 (Apple). I only got screwed by this by the CHANGE in behavior on upgrading to 4.4. (Not sure about 4.3). I already presented this in the original post at the top (except the Apple test is a new data point; FYI Apple gcc math.h also 'works', so either 4.2 was generally consistent or Apple likes to patch theirs for consistency) This is further evidence gcc has not had a good policy discussion of where NaN optimizations should be applied, because the implementation keeps changing, and it's not even consistent between math.h and cmath within any given version other than 4.2-Apple. Marc said: >> __FINITE_MATH_ONLY__ > Not very portable afaik. Neither is -ffast-math, add a 'defined(__FINITE_MATH_ONLY__) &&' and it will be applied opportunistically when available, or even better: the user can -D__FINITE_MATH_ONLY__=1 themselves on non-gcc platforms and still get the performance benefit you're looking for even without -ffast-math support, so it's a double win. IMHO, on the other hand it's harder and more error prone to override isnan with my own implementation.
[Bug middle-end/50724] isnan broken by -ffinite-math-only in g++
http://gcc.gnu.org/bugzilla/show_bug.cgi?id=50724 Ethan Tira-Thompson changed: What|Removed |Added Status|RESOLVED|REOPENED Resolution|INVALID | --- Comment #17 from Ethan Tira-Thompson 2011-10-17 04:12:31 UTC --- Richard said: > math.h is not part of GCC But the point is there is value in consistency between math.h and cmath regardless of who owns math.h. I'm asserting that this value is greater than that gained by 'optimizing away' the classification functions in cmath. Inconsistency leads to confused users and therefore bugs, missed optimization is only going to cause slower code. I get that you want to make the most of -ffast-math, and if it were a big speedup it could be worthwhile, but it seems reasonable that if someone is serious about optimizing away their classification sanity checks in a release build, they would be better served by using assert() or an #ifdef instead of relying of the vagaries of -ffast-math for this purpose. > The only way out I see that not breaks other users uses would be a new > flag, like -fpreserve-ieee-fp-classification that, ontop of > -ffinite-math-only, I'm not opposed to a new flag, but I'd suggest the reverse semantics. Disabling classification is an extra degree of non-compliance beyond ignoring non-finite math operations. I'd rather users add flags to progressively become less compliant, rather than add a flag to get some compliance back. But to rewind a second, I want to address the "breaks other users" comment... here is the status AFAIK: 1) Older versions (4.1, 4.2) of gcc did not do this optimization of classification functions. Thus, "legacy" code expects classification to work even in the face of -ffast-math, which was changed circa 4.3/4.4 2) Removing classification 'breaks' code because it fundamentally strips execution paths which may otherwise be used. 3) Leaving classification in could be considered a missed optimization, but is at worst only a performance penalty, not a change in execution values. 4) Personal conjecture: I doubt the classification routines are a performance bottleneck in the areas where -ff-m-o is being applied, so (3) is pretty minimal. And I seriously doubt anyone is relying on the removal of classification in a code-correctness context, that doesn't make any sense. Are we on the same page with these points? So if you are concerned with the breakage of existing code, isn't the solution to revert to the previous scope of the -ff-m-o optimization ASAP, and then if there is a desire to extend the finite-only optimization to classification functions, *that* would be a new feature request, perhaps with its own flag? > (Note that they are folded to arithmetic, !(x==x), so that transform > has to be disabled as well, and on some architectures you might get > library calls because of this instead of inline expansions). I'd rather leave comparison optimizations as they are under -ff-m-o, that seems a sensible expectation of the 'arithmetic' scope, and is relatively well-known, long-standing effect of -ffast-math. It's only the 5 explicit fp classification calls which I think deserve protection to allow data validation in a non-hacky manner before doing core computations with the finite invariant. Unless you are saying things like std::isnan cannot be implemented separately from !(x==x)? That has not been my understanding.
[Bug libstdc++/50724] cmath's floating-point classification implementations inconsistent with math.h
http://gcc.gnu.org/bugzilla/show_bug.cgi?id=50724 Ethan Tira-Thompson changed: What|Removed |Added Status|RESOLVED|REOPENED Component|middle-end |libstdc++ Resolution|DUPLICATE | Summary|isnan broken by |cmath's floating-point |-ffinite-math-only in g++ |classification ||implementations ||inconsistent with math.h Severity|enhancement |normal --- Comment #19 from Ethan Tira-Thompson 2011-10-17 15:31:12 UTC --- Richard said: >> 1) Older versions (4.1, 4.2) of gcc did not do this optimization > Sure they did. Dude, I tested this in my very first post. I'm only here because we had working code which has broken on the upgrade to Ubuntu 10.04. There's no point in discussing with you if you're just going to deny the state of the world and not offer any data to back up your side. But before you start coding a test case, read on, turns out I've already done this for you below. > I expect the checks to be optimized away when using the FP exception path. I hate using this rationale, but have you considered that this is not a required or portable behavior and you shouldn't rely on it? And what happens if the checks are left in? Is anything actually 'broken' by this? You keep using that word, I do not think it means what you think it means. I lose data validation when the classifications are disabled. My code does something fundamentally different as a result. This is demonstrable 'breakage'. To quote a wise man, "We should not break this without a very very very good reason. Which this isn't." ;) > [isnan implementation ...] So what's your point again? There are various ways to define isnan and friends. I'm requesting one which is consistent with math.h's isnan and also previous behavior. That could be bitmask operations, it could be calling __isnan or math.h's isnan(), etc. I think we need some new data to move this along... I did a little investigation on how these functions have been defined over time: In 4.1 and 4.2, cmath provides: std::isnan() forwards to __gnu_cxx::__capture_isnan() __gnu_cxx::__capture_isnan() forwards to math.h ::isnan() math.h ::isnan forwards to __isnan() as of this patch: http://gcc.gnu.org/viewcvs/trunk/libstdc%2B%2B-v3/include/c_std/cmath?r1=119611&r2=130443 This has changed to simply: std::isnan() forwards to __builtin_isnan() Huh, that's interesting, let's cut out the middle men and see what these underlying functions do across history: const float qNaN = std::numeric_limits::quiet_NaN(); std::cout << __builtin_isnan(qNaN) << ' ' << __isnan(qNaN) << ' ' << !(qNaN==qNaN) << '\n'; Compiled with -ffast-math on 3 different machines 0 1 0 // Fedora 9, gcc 4.1.2 0 1 0 // Apple 10.7, gcc 4.2.1 0 1 0 // Ubuntu 10.04, gcc 4.4.3 Hey, you're right insofar as the 'internal' implementations haven't changed at all. What changed is where cmath sends its implementation (and fyi, I did originally file this under libstdc++, just by lucky guess ;). cmath used to explicitly call the math.h definition (aka __isnan), which is not optimized by -ffast-math. For reference, I checked the headers on the Apple machine as well, and found some relevant results. cmath starts the same with std::isnan → __capture_isnan → ::isnan, but the abridged math.h ::isnan definition is: #if defined( __GNUC__ ) && 0 == __FINITE_MATH_ONLY__ #define isnan(x) __inline_isnanT((T)(x)) inline int __inline_isnanT( T __x ) { return __x != __x; } #else #define isnan(x) __isnanT((T)(x)) extern int __isnanT(T); #endif (full source http://www.opensource.apple.com/source/Libm/Libm-315/Source/Intel/math.h) Which is all prepended by this comment: > Yes, that's right. You only get the fast iswhatever() macros if you do NOT > turn on -ffast-math. These inline functions require the compiler to be > compiling to standard in order to work. -ffast-math, among other things, > implies that NaNs don't happen. The compiler can in that case optimize > x != x to be false always, wheras it would be true for NaNs. That breaks > __inline_isnan() below. So, to whatever degree you care what major users are doing, at least one popular platform considers it breakage to disable fp classification, and falls back on a function call to preserve it in the face of -ffast-math. > The point is backward-compatible behavior of -ffast-math. I agree! And I even found the exact patch that broke it. So would anyone (Hi Paolo :)) like to chime in on the rationale of the linked patch above and how best to restore consistency of the user-facing classification functions? In particular, can std::isnan (and its classification
[Bug middle-end/50724] cmath's floating-point classification implementations inconsistent with math.h
http://gcc.gnu.org/bugzilla/show_bug.cgi?id=50724 Ethan Tira-Thompson changed: What|Removed |Added Status|RESOLVED|REOPENED Resolution|DUPLICATE | --- Comment #22 from Ethan Tira-Thompson 2011-10-17 16:46:27 UTC --- Paolo: thanks for the quick reply, but it would help if you could explain why that is the case? Also, a follow-up, is __builtin_isnan and friends used anywhere except cmath? It appears not, other than tr1/special_function_util.h, which is also providing an __isnan.
[Bug middle-end/50724] cmath's floating-point classification implementations inconsistent with math.h
http://gcc.gnu.org/bugzilla/show_bug.cgi?id=50724 Ethan Tira-Thompson changed: What|Removed |Added Status|RESOLVED|REOPENED Resolution|DUPLICATE | --- Comment #24 from Ethan Tira-Thompson 2011-10-17 18:38:05 UTC --- Please don't change bug status without comment. We already have bug 25975 listed as a duplicate in the history several times now. That bug report was never really resolved, the user just found a workaround and went away. Further, he was using math.h, which has been stated is outside gcc, whereas I am addressing the cmath implementation. So not even the same issue anyway. So that we can find a resolution to this issue, please explain why cmath cannot use math.h? I'm assuming there's a good reason, I just don't know the history there. Is it performance, portability, licensing, what? (Those who don't understand history (me) are doomed to repeat it...) Alternatively, another potential solution would be to tweak the __builtins to restore the original behavior in cmath, which is what you (Paolo) were actually suggesting early on... grepping around, it certainly looks like cmath is the only thing using them. Am I missing anything there?
[Bug middle-end/50724] cmath's floating-point classification implementations inconsistent with math.h
http://gcc.gnu.org/bugzilla/show_bug.cgi?id=50724 Ethan Tira-Thompson changed: What|Removed |Added Status|RESOLVED|REOPENED Resolution|DUPLICATE | --- Comment #26 from Ethan Tira-Thompson 2011-10-17 19:21:56 UTC --- I'm just asking about a patch that broke existing code and this is how you respond? It's nothing personal, mistakes happen, I'm just trying to figure out how to fix it for others. (And why'd you remove someone else's name off the cc list? Whatever...) If you don't have time to support your code then just say so or ignore it, no need to be an ass about it.
[Bug middle-end/50724] cmath's floating-point classification implementations inconsistent with math.h
http://gcc.gnu.org/bugzilla/show_bug.cgi?id=50724 Ethan Tira-Thompson changed: What|Removed |Added Status|RESOLVED|REOPENED Resolution|DUPLICATE | --- Comment #28 from Ethan Tira-Thompson 2011-10-17 20:21:27 UTC --- So then there are a variety of potential solutions to evaluate: A) Don't use the builtin, go back to __isnan, perhaps only when -ff-m-o is in effect. Paolo says this is bad, but it's not clear why. Seems like a decent solution except for his apparent disapproval. B) Change the builtin implementation, just for example with bitmasks: inline bool isnan(float x) { const int EXP = 0x7f80; const int FRAC = 0x007f; const int y = *((int*)(&x)); return ((y&EXP)==EXP && (y&FRAC)!=0); } (this is what I'm using to reproduce isnan in my own code, maybe there are better ways?) But this may be a portability issue to support different float point standards, right? That's just as much an argument to not have users trying to do this themselves though. C) This is getting out of my knowledge, but Paolo also suggested "splitting the computation in parts via the new optimization attribute and pragma, keep the is_nan & co classifications outside the -fast-math cores." That sounds elegant and possibly straightforward if it's just a matter of adding an attribute. D) Combination of A, B and/or C: add new 'safe' builtins, have cmath use them when -ff-m-o is in effect, but otherwise use the presumably faster/more easily optimized normal builtins when these optimizations won't change behavior. E) Screw compatibility with older gcc or Apple's current gcc or other forks, just update the documentation. Make it clear -ff-m-o includes both classification and arithmetic functions, that this behavior is not portable or consistent even within math.h vs. cmath, and let the users suck it up. Generating warnings on calling the nan-generation functions like nan(char*) or numeric_limits::quiet_NaN() and maybe the classification functions too (e.g. "isX always evaluates to true/false") would be a plus. I'll be pretty disappointed with gcc quality control if you really choose (E), but it's there.
[Bug middle-end/50724] cmath's floating-point classification implementations inconsistent with math.h
http://gcc.gnu.org/bugzilla/show_bug.cgi?id=50724 --- Comment #31 from Ethan Tira-Thompson 2011-10-18 00:33:41 UTC --- I don't see what the hurry is to close the bug while it's still under discussion. I guess you guys just like hit that 'resolved' button before you've actually committed any resolution. OK, when in Rome... > Maybe you should consider that the maintainers have actually thought about > it and might know what they're talking about? What is __isnan? Is that > reliably available on all supported platforms? (Hint: no) Is __builtin_isnan > reliably available? (Hint: yes) This was exactly the information I was asking for. I explicitly asked if it was a portability issue (vs. performance or licensing, thought perhaps maybe it was some GPL thing). Maybe it sounded patronizing because it was such a obvious question to you, but please have a little patience with people who are new to the project internals. Heck, how many people do you think even know that __isnan is from libm and __builtin_isnan is from gcc, or the relationship between the two? This stuff is not well documented nor common knowledge, and if maintainers don't want to answer questions then what do you expect? A fair bit of this thread has been wasted on a subset of maintainers saying 'gcc hasn't changed, finite-math has always been this way', directly in response to me showing code demonstrating the change and eventually tracking down the patch that caused it in spite of the derogatory comments, like even yours just now. So similarly you might consider a user who has spent a fair bit of time finding the problem and presenting it to you on a silver platter, is probably not hallucinating the whole thing. (Hint: no) Fair enough? This is probably moot, but if you'd like to get this back on topic, I'm still on board. So then, just for reference, does no part of gcc rely on libm now? Or is there a config mechanism that lets parts of gcc use libm when it is available? I ask because gcc (well, libstdc++) used to use libm, so that begs the question what is the current status? > If you want your code to conform to floating point standards THEN DON'T > USE -ffinite-math-only! It's there in the manual for all to see. My concern is not 'conformance' per se. Obviously then I just wouldn't be using the flag. 1) Inconsistency between math.h and cmath (unpredictable optimization application, maybe I use math.h, but someone includes cmath before my header, perhaps a precompiled header across translation units, now my code behaves differently, and this might vary per-translation unit within the program.) 2) Inconsistency with older versions/forks of gcc (breaking legacy code/portability, maybe even security issues?) 3) Insufficient documentation regarding the expected degree of non-compliance ("arithmetic" includes classification?) 4) What is really the *desired* degree of non-compliance in practical usage, is this throwing out the baby with the bathwater? (For most of the finite-math effects, garbage-in-garbage-out is fair enough; but the classification functions often lead to code paths with side effects, e.g. triggering UI, skipping data records, etc, so it's a much broader effect.) So yes, I could just not use the flag. But it's useful, it's just gotten too aggressive. As a user, it's hard to reproduce isnan (and friends) to do validation when finite-math is active (and since build systems make it easy for end users to recompile with additional flags, it's not entirely controllable either, other than saying "don't do that", I'd rather it wasn't all-or-nothing.) Since gcc used to provide this more limited finite-math optimization, I was hoping it would not be hard to restore it. I also used to think there would be a concern regarding how the user-visible scope of finite-math had changed, breaking code. *shrug* > That would be something for user code to do, not the library. > Feel free to do it in your code. I can't add an attribute to the system isnan from my user code, or can I? I've never been quite sure what Paolo was referring to, can someone clue me in? It sounded like he was saying the builtins could be given an attribute to specify -fno-finite-math-only which would only affect their specific usage? Maybe he just meant I could apply different flags in different translation units of my own code, in which case I've misunderstood. Basically, what's the "new optimization attribute and pragma"? Thanks!
[Bug rtl-optimization/50782] New: optimize pragma not applying fast-math
http://gcc.gnu.org/bugzilla/show_bug.cgi?id=50782 Bug #: 50782 Summary: optimize pragma not applying fast-math Classification: Unclassified Product: gcc Version: unknown Status: UNCONFIRMED Severity: normal Priority: P3 Component: rtl-optimization AssignedTo: unassig...@gcc.gnu.org ReportedBy: ejtt...@gmail.com Summary: The optimize attribute works, but the pragma doesn't (for fast-math). Test case: #include #include #include float n = std::numeric_limits::quiet_NaN(); void test1() __attribute__((optimize("fast-math"))); void test1() { std::cout << std::isnan(n)<<__builtin_isnan(n)<<(n!=n) << std::endl; } #pragma GCC optimize ("fast-math") void test2(); void test2() { std::cout << std::isnan(n)<<__builtin_isnan(n)<<(n!=n) << std::endl; } int main(int argc, char** argv) { test1(); test2(); return 0; } Output of 4.6.1-9ubuntu3 with -O3: 100 111 Expected output: 100 100 The two lines should be identical, yes? It seems the attribute is applied to test1, but the pragma isn't catching test2. Apologies if I'm not using the pragma correctly. Also, I'm not really sure what to expect for the first two values of each line, it depends on whether the inlining is done before or after optimization. It appears the built-in is expanded before optimization, but the isnan() is after (I checked with nm, isnan is indeed inlined due to -O). So up to you if that is an issue. Ironically, this is exactly the behavior I was looking for in bug 50724, but I wouldn't want to rely on this since you could decide to make this attribute apply after inlining... however, if there is a definite behavior regarding inlined function calls, you might want to document that? Finally, this may be a tangent, but the implied finite-math-only is not setting __FINITE_MATH_ONLY__==1. That seems reasonable for the attribute, because AFAIK this attribute processing runs after the preprocessor is done, right? But maybe the pragma could be setting it? This might warrant a note in the 'optimize' attribute/pragma docs regarding the (in)ability of each to update preprocessor flags. Thanks!
[Bug middle-end/50724] cmath's floating-point classification implementations inconsistent with math.h
http://gcc.gnu.org/bugzilla/show_bug.cgi?id=50724 --- Comment #35 from Ethan Tira-Thompson 2011-10-18 21:09:07 UTC --- Thanks all for the info! I should have realized there was literally an attribute/pragma called 'optimize' (duh), and it's already in the docs... for some reason I had gotten the impression this was a brand new development (i.e. hadn't been released yet), I should've checked. FYI, the optimize attribute seems to work for fast-math, but interestingly, the pragma doesn't. I've created a new bug 50782 for this. > change RTL optimizers to not do comparison code folding based on > flag_finite_math_only (so you can expand isnan to !(x==x) even with > -ffinite-math-only) What would you say to a solution which allows finite math to optimize the comparisons, but at the cost of explicit classification being full function calls? And of course when finite math is not in effect, everything is inlined as normal. This would allow core computations to be fully optimized and only explicit classification calls would be affected. This presumes the classification calls are less common in order to be a good tradeoff, my intuition is that this is the case. It also allows those of you who want to optimize-away nan checks to continue to do so, just use a (x!=x), and as a bonus this approach will also work consistently between gcc variants. What do you think? This is also easy to implement without touching the compiler source, just apply attributes in libstdc++ to keep the classification calls no-finite-math-only, for example the isnan implementation would be: #if defined(__FINITE_MATH_ONLY__) && __FINITE_MATH_ONLY__ // apply attributes to retain classification functionality template inline typename __gnu_cxx::__enable_if<__is_arithmetic<_Tp>::__value, int>::__type isnan(_Tp __f) __attribute__ ((optimize ("no-finite-math-only"),noinline)); #endif template inline typename __gnu_cxx::__enable_if<__is_arithmetic<_Tp>::__value, int>::__type isnan(_Tp __f) { return std::__is_integer<_Tp>::__value ? false : __builtin_isnan(__f); } (and obviously similar for fpclassify, isfinite, isinf, and isnormal) I tweaked isnan to short circuit on __is_integer instead of a roundabout promotion to double. If you don't like that it can certainly go back to the promotion style. This works (tested with 4.6.1) because __builtin_isnan is expanded in the isnan context, where the optimize attribute is in effect. If you think that expansion behavior is subject to change (see also bug 50782), we could bump this up to apply to the builtin itself instead of the user function...? As written, this relies on the noinline attribute trumping the inline keyword. We rewrite this to avoid that conflict if needed. (Is the inline keyword superfluous here anyway? Testing it appears so.)
[Bug rtl-optimization/50782] optimize pragma not applying fast-math
http://gcc.gnu.org/bugzilla/show_bug.cgi?id=50782 --- Comment #1 from Ethan Tira-Thompson 2011-10-18 21:16:23 UTC --- I'm sorry, apparently I messed something up in my testing. The output of -O3 is actually: 000 111 The output of -O0 is: 100 111 So the optimize attribute is being applied after/including any inlined functions. Obviously, when the function is not inlined, it is not affected by the attribute. The primary bug of the two lines not being the same remains the same.
[Bug rtl-optimization/50782] optimize pragma not applying fast-math
http://gcc.gnu.org/bugzilla/show_bug.cgi?id=50782 --- Comment #2 from Ethan Tira-Thompson 2011-10-18 21:28:42 UTC --- Argh, sorry for the spastic updates, but I checked again and I definitely have these lines in my console history: $ g++ test.cc -o test -Wall -g -O3 && ./test 100 111 But now I'm getting the 000/111 output for the same build command... I don't understand the inconsistency *shrug* see what you get O:-)
[Bug rtl-optimization/50782] optimize pragma not applying fast-math
http://gcc.gnu.org/bugzilla/show_bug.cgi?id=50782 --- Comment #3 from Ethan Tira-Thompson 2011-10-18 23:55:47 UTC --- I figured out what I did differently, I did some 'minor cleanup' and moved n out of the function scope. This actually changes the optimization results. This is just for reference in case you are interested: Looking at the assembly for the three tests below, I confirmed printf is being passed a constant value in each of them. My theory is that in test1 gcc does a const-eval of the isnan outside of the test function scope, whereas in the other two it inlined isnan first and then optimized the constants within the scope of the attribute. Anyway this is just an example that the relationship between the optimize attribute and inlined functions may be hard to predict (at least, for people who aren't gcc maintainers ;)) #include #include #include void test1() __attribute__((optimize("fast-math"))); void test1() { const float n = std::numeric_limits::quiet_NaN(); printf("%d\n",std::isnan(n)); } void test2() __attribute__((optimize("fast-math"))); void test2() { static const float n = std::numeric_limits::quiet_NaN(); printf("%d\n",std::isnan(n)); } const float n = std::numeric_limits::quiet_NaN(); void test3() __attribute__((optimize("fast-math"))); void test3() { printf("%d\n",std::isnan(n)); } int main(int argc, char** argv) { test1(); test2(); test3(); return 0; } Output: ejt@vbox-ubuntu-11:~$ g++ test.cc -o test -Wall -g -O3 && ./test 1 0 0 ejt@vbox-ubuntu-11:~$ nm test | c++filt | grep -i isnan ejt@vbox-ubuntu-11:~$ g++ test.cc -o test -Wall -g -O0 && ./test 1 1 1 ejt@vbox-ubuntu-11:~$ nm test | c++filt | grep -i isnan 0040073a W __gnu_cxx::__enable_if::__value, int>::__type std::isnan(float)