BOOST_ASSERT and __assume on MSVC

Hi All, Have you considered modifying BOOST_ASSERT to use __assume on MSVC? Briefly speaking __assume(expr) is a hint for optimizer that 'expr' evaluates to nonzero. It can help optimize the code. Standalone use of __assume is not recommended because compiler does not check if the assumption is correct, and if it isn't the program is ill formed. But it fits perfectly in ASSERT macro. This way putting many ASSERTs will not only help to verify the code - it will also help the optimizer. Wow! To be sure I did a small test with MSVC: int f(int n) { // __assume(n == 0); if (n == 1) return 1; else return 0; } produces: xor eax, eax cmp DWORD PTR _n$[esp-4], 1 sete al ret 0 with __assume uncommented: xor eax, eax ret 0 And the comparison is gone. Microsoft docs for __assume are here: http://msdn.microsoft.com/library/default.asp?url=/library/en-us/vccelng/htm... cheers, Marcin

On 9/13/05, Marcin Kalicinski <kalita@poczta.onet.pl> wrote:
Hi All,
Hi,
Briefly speaking __assume(expr) is a hint for optimizer that 'expr' evaluates to nonzero. It can help optimize the code. Standalone use of __assume is not recommended because compiler does not check if the assumption is correct, and if it isn't the program is ill formed. But it fits perfectly in ASSERT macro. This way putting many ASSERTs will not only help to verify the code - it will also help the optimizer. Wow!
Wow, I liked this. I think ASSERT should be __assume when NDEBUG is defined.
And the comparison is gone.
cheers, Marcin
-- Felipe Magno de Almeida Developer from synergy and Computer Science student from State University of Campinas(UNICAMP). Unicamp: http://www.ic.unicamp.br Synergy: http://www.synergy.com.br "There is no dark side of the moon really. Matter of fact it's all dark."

Marcin Kalicinski wrote:
Hi All,
Have you considered modifying BOOST_ASSERT to use __assume on MSVC?
Briefly speaking __assume(expr) is a hint for optimizer that 'expr' evaluates to nonzero. It can help optimize the code. Standalone use of __assume is not recommended because compiler does not check if the assumption is correct, and if it isn't the program is ill formed. But it fits perfectly in ASSERT macro. This way putting many ASSERTs will not only help to verify the code - it will also help the optimizer. Wow! <snip> I don't get it, isn't the point of assert that it DOES check them? Or did you mean something like GCC's __builtin_expect? http://gcc.gnu.org/onlinedocs/gcc-4.0.1/gcc/Other-Builtins.html#index-g_t_00...

On 9/15/05, Simon Buchan <simon@hand-multimedia.co.nz> wrote:
Marcin Kalicinski wrote:
Hi All,
Have you considered modifying BOOST_ASSERT to use __assume on MSVC?
Briefly speaking __assume(expr) is a hint for optimizer that 'expr' evaluates to nonzero. It can help optimize the code. Standalone use of __assume is not recommended because compiler does not check if the assumption is correct, and if it isn't the program is ill formed. But it fits perfectly in ASSERT macro. This way putting many ASSERTs will not only help to verify the code - it will also help the optimizer. Wow! <snip> I don't get it, isn't the point of assert that it DOES check them? Or did you mean something like GCC's __builtin_expect? http://gcc.gnu.org/onlinedocs/gcc-4.0.1/gcc/Other-Builtins.html#index-g_t_00...
For what I know, the point of assert is that it checks in the debug build. But has no cost in the release builds. In this case it is even possible to optimize. I think this __assume is different from GCC's __builtin_expect because it still believes it will happens, but the __assume will simply assume that the case is impossible to happen, just like what an assertion assumes. -- Felipe Magno de Almeida Developer from synergy and Computer Science student from State University of Campinas(UNICAMP). Unicamp: http://www.ic.unicamp.br Synergy: http://www.synergy.com.br "There is no dark side of the moon really. Matter of fact it's all dark."

Felipe Magno de Almeida wrote:
On 9/15/05, Simon Buchan <simon@hand-multimedia.co.nz> wrote:
Marcin Kalicinski wrote:
Hi All,
Have you considered modifying BOOST_ASSERT to use __assume on MSVC?
Briefly speaking __assume(expr) is a hint for optimizer that 'expr' evaluates to nonzero. It can help optimize the code. Standalone use of __assume is not recommended because compiler does not check if the assumption is correct, and if it isn't the program is ill formed. But it fits perfectly in ASSERT macro. This way putting many ASSERTs will not only help to verify the code - it will also help the optimizer. Wow!
<snip> I don't get it, isn't the point of assert that it DOES check them? Or did you mean something like GCC's __builtin_expect? http://gcc.gnu.org/onlinedocs/gcc-4.0.1/gcc/Other-Builtins.html#index-g_t_00... For what I know, the point of assert is that it checks in the debug build. But has no cost in the release builds. In this case it is even possible to optimize.
I think this __assume is different from GCC's __builtin_expect because it still believes it will happens, but the __assume will simply assume that the case is impossible to happen, just like what an assertion assumes. So... you want asserts to assure the compiler that the expression should be impossible? I can't think of too many times that would actually generate better code, and may be a source of unexpected behaviour, but better minds than I should think about it, I guess.

On 9/15/05, Simon Buchan <simon@hand-multimedia.co.nz> wrote:
Felipe Magno de Almeida wrote: So... you want asserts to assure the compiler that the expression should be impossible? I can't think of too many times that would actually generate better code, and may be a source of unexpected behaviour, but better minds than I should think about it, I guess.
Yes. I think that almost always unexpected behavior is already the case when an assertion is violated. IMO, assertions should be invariants, and as such should never(and I mean really never) be violated, no matter what. The only way I can see variants could be broken are through bugs in the library, improper use or incorrect synchronization(which is an improper use). What I'm only suggesting is using these already thought and coded invariants to be used for optimization. Maybe could have be a define in boost that could do enable this, and have the default behavior as this optimisation disabled. But more opinions would be really better in this case. best regards, -- Felipe Magno de Almeida Developer from synergy and Computer Science student from State University of Campinas(UNICAMP). Unicamp: http://www.ic.unicamp.br Synergy: http://www.synergy.com.br "There is no dark side of the moon really. Matter of fact it's all dark."

On 9/15/05, Simon Buchan <simon@hand-multimedia.co.nz> wrote:
Felipe Magno de Almeida wrote: So... you want asserts to assure the compiler that the expression should be impossible? I can't think of too many times that would actually generate better code, and may be a source of unexpected behaviour, but better minds than I should think about it, I guess.
Yes. I think that almost always unexpected behavior is already the case when an assertion is violated. IMO, assertions should be invariants, and as such should never(and I mean really never) be violated, no matter what. The only way I can see variants could be broken are through bugs in the library, improper use or incorrect synchronization(which is an improper use). What I'm only suggesting is using these already thought and coded invariants to be used for optimization. Maybe could have be a define in boost that could do enable this, and have the default behavior as this optimisation disabled.
Besides helping optimization __assume suppresses some warnings: int f() { if ( ... some condition ...) return 0; __assume(0); // warning if no assume present here } Without __assume compiler emits obvious warning: 'not all control paths return a value'. That means with __assume you don't have to put junk return statements that will never get executed, and may actually cause some unneeded code to be generated. To see if there's actually any code generated for such an extra return statement (added only to suppress the warning) I did another test with MSVC: int f(int n) { if (n == 0) return 7; else if (n == 1) return 19; else //__assume(0); // return 0; } Code generated with 'return 0;' at the end: mov eax, DWORD PTR _n$[esp-4] test eax, eax jne SHORT $LN4@f mov eax, 7 ret 0 $LN4@f: sub eax, 1 neg eax sbb eax, eax and eax, -19 add eax, 19 ret 0 Code generated with '__assume(0);' at the end: mov eax, DWORD PTR _n$[esp-4] neg eax sbb eax, eax and eax, 12 add eax, 7 ret 0 Note the clever way compiler avoids a conditional in 'assume' case, while it is unable to do it with redundant 'return 0'. This is the first case that came to my mind, there might as well be cases where the gains are bigger. Marcin

From: Simon Buchan <simon@hand-multimedia.co.nz>
Marcin Kalicinski wrote:
Have you considered modifying BOOST_ASSERT to use __assume on MSVC?
Briefly speaking __assume(expr) is a hint for optimizer that 'expr' evaluates to nonzero. It can help optimize the code. Standalone use of __assume is not recommended because compiler does not check if the assumption is correct, and if it isn't the program is ill formed. But it fits perfectly in ASSERT macro. This way putting many ASSERTs will not only help to verify the code - it will also help the optimizer. Wow!
<snip> I don't get it, isn't the point of assert that it DOES check them? Or
The point is that a violated assertion makes the program die. It isn't supposed to happen. However, since assertions are often used only in debug builds, they only help if you run a debug build. Thus, if you write assertions, but your clients only run release builds, they don't help much. Given that the asserted condition holds, then telling the compiler about that condition gives the compiler information it might be able to use to optimize better. IOW, putting __assume() in the non-debug assertion means, effectively, "assuming that the asserted condition is true (verified in debug builds by an assertion), you may apply any additional optimizations you might otherwise have skipped." If the checking of a debug build isn't brought to bear, then the asserted condition may well be violated anyway. So, whether you get bad results due to "overly agressive" optimization or due to assumptions made by the code following the assertion hardly matters. I think the addition is a great idea. Do other compilers offer anything similar? I'd hate to miss this opportunity on other platforms. -- Rob Stewart stewart@sig.com Software Engineer http://www.sig.com Susquehanna International Group, LLP using std::disclaimer;

Rob Stewart wrote:
From: Simon Buchan <simon@hand-multimedia.co.nz>
Marcin Kalicinski wrote:
Have you considered modifying BOOST_ASSERT to use __assume on MSVC?
Briefly speaking __assume(expr) is a hint for optimizer that 'expr' evaluates to nonzero. It can help optimize the code. Standalone use of __assume is not recommended because compiler does not check if the assumption is correct, and if it isn't the program is ill formed. But it fits perfectly in ASSERT macro. This way putting many ASSERTs will not only help to verify the code - it will also help the optimizer. Wow!
<snip> I don't get it, isn't the point of assert that it DOES check them? Or
The point is that a violated assertion makes the program die. It isn't supposed to happen. However, since assertions are often used only in debug builds, they only help if you run a debug build. Thus, if you write assertions, but your clients only run release builds, they don't help much.
Given that the asserted condition holds, then telling the compiler about that condition gives the compiler information it might be able to use to optimize better. IOW, putting __assume() in the non-debug assertion means, effectively, "assuming that the asserted condition is true (verified in debug builds by an assertion), you may apply any additional optimizations you might otherwise have skipped."
If the checking of a debug build isn't brought to bear, then the asserted condition may well be violated anyway. So, whether you get bad results due to "overly agressive" optimization or due to assumptions made by the code following the assertion hardly matters.
I think the addition is a great idea. Do other compilers offer anything similar? I'd hate to miss this opportunity on other platforms. OK, cool. I think the closest GCC comes to just assuming is __builtin_expect, but as an optimisation, it should be good enough. (Personnely, I don't think optimization levels should change the semantics of a program, but assertions are obviously an edge-case)
PS: Don't take me too seriously, I have proven myself to be a complete idiot many a time :D

Marcin Kalicinski <kalita <at> poczta.onet.pl> writes:
Hi All,
Have you considered modifying BOOST_ASSERT to use __assume on MSVC?
I thought about optimizing assert in this way some time ago but I never looked for implementation.
Briefly speaking __assume(expr) is a hint for optimizer that 'expr' evaluates to nonzero. It can help optimize the code. Standalone use of __assume is not recommended because compiler does not check if the assumption is correct, and if it isn't the program is ill formed. But it fits perfectly in ASSERT macro. This way putting many ASSERTs will not only help to verify the code - it will also help the optimizer. Wow!
Wow!
To be sure I did a small test with MSVC:
int f(int n) { // __assume(n == 0); if (n == 1) return 1; else return 0; }
I recall now how I came to that idea. I was reading http://www.hackersdelight.org/basics.pdf section 2.20 "Alternating among Two or More Values" when I realized that this kind of optimization is possible without bits magic. Marcin, could you try an example from the book void f(int& n) { // __assume(n == 0 || n == 1); if (n == 0) n = 1; else n = 0; } with and without __assume? -- Alexander Nasonov
participants (5)
-
Alexander Nasonov
-
Felipe Magno de Almeida
-
Marcin Kalicinski
-
Rob Stewart
-
Simon Buchan