Transform assertion into optimization hints

Message ID 001a8c05-7674-6078-d4ec-087ecc109464@gmail.com
State New
Headers show
Series
  • Transform assertion into optimization hints
Related show

Commit Message

François Dumont Sept. 17, 2018, 8:38 p.m.
We talk about it a while back.

I've run testsuite several times since I have this patch on my local 
copy. Note that when I implemented it the wrong way tests started to 
fail so it is clearly having an effect on the generated code.

* include/bits/c++config [__OPTIMIZE__](__glibcxx_assert): Define as 
optimization hint

using __builtin_unreachable.

Ok to commit ?

François

Comments

Marc Glisse Sept. 17, 2018, 9:15 p.m. | #1
On Mon, 17 Sep 2018, François Dumont wrote:

> We talk about it a while back.

>

> I've run testsuite several times since I have this patch on my local copy. 

> Note that when I implemented it the wrong way tests started to fail so it is 

> clearly having an effect on the generated code.

>

> * include/bits/c++config [__OPTIMIZE__](__glibcxx_assert): Define as 

> optimization hint

>

> using __builtin_unreachable.

>

> Ok to commit ?


I see for instance in bits/regex_automaton.tcc:

               __glibcxx_assert(__m.count(__ref._M_next) > 0);

where __m is a map, which does not look so well suited for a 
__builtin_unreachable. Is it using the wrong macro?

-- 
Marc Glisse
François Dumont Sept. 18, 2018, 5:43 a.m. | #2
On 09/17/2018 11:15 PM, Marc Glisse wrote:
> On Mon, 17 Sep 2018, François Dumont wrote:

>

>> We talk about it a while back.

>>

>> I've run testsuite several times since I have this patch on my local 

>> copy. Note that when I implemented it the wrong way tests started to 

>> fail so it is clearly having an effect on the generated code.

>>

>> * include/bits/c++config [__OPTIMIZE__](__glibcxx_assert): Define as 

>> optimization hint

>>

>> using __builtin_unreachable.

>>

>> Ok to commit ?

>

> I see for instance in bits/regex_automaton.tcc:

>

>               __glibcxx_assert(__m.count(__ref._M_next) > 0);

>

> where __m is a map, which does not look so well suited for a 

> __builtin_unreachable. Is it using the wrong macro?

>

I don't know if this particular code is well covered by the testsuite. 
So I tweaked several tests in 23_containers/map and the code compiles 
just fine if it is your concern.

If your concern is rather that the condition got evaluated which will 
eventually slow down execution then I need to check generated code. Any 
good link explaining how to have a clear view on the generated code ?

Maybe a 'if __builtin_constant_p(_Condition)' could help if gcc doesn't 
do it itself already.
Marc Glisse Sept. 18, 2018, 6:11 a.m. | #3
On Tue, 18 Sep 2018, François Dumont wrote:

> If your concern is rather that the condition got evaluated which will 

> eventually slow down execution then I need to check generated code. Any good 

> link explaining how to have a clear view on the generated code ?


This.

For a file like

#include <map>

void f();
void g(std::map<int,int> const&m){
   if(m.count(42)>0)__builtin_unreachable();
   f();
}

compiled with g++ file.c -O3 -S -fdump-tree-optimized, I get a
file.c.228t.optimized that contains quite a lot of code, not just a call
to f.

> Maybe a 'if __builtin_constant_p(_Condition)' could help if gcc doesn't do it 

> itself already.


How would you use that precisely?

It may be easiest to use a different macro for trivial tests that can go
with __builtin_unreachable and for expensive tests that cannot.

-- 
Marc Glisse
François Dumont Sept. 19, 2018, 5:39 a.m. | #4
On 09/18/2018 08:11 AM, Marc Glisse wrote:
> On Tue, 18 Sep 2018, François Dumont wrote:

>

>> If your concern is rather that the condition got evaluated which will 

>> eventually slow down execution then I need to check generated code. 

>> Any good link explaining how to have a clear view on the generated 

>> code ?

>

> This.

>

> For a file like

>

> #include <map>

>

> void f();

> void g(std::map<int,int> const&m){

>   if(m.count(42)>0)__builtin_unreachable();

>   f();

> }

>

> compiled with g++ file.c -O3 -S -fdump-tree-optimized, I get a

> file.c.228t.optimized that contains quite a lot of code, not just a call

> to f.


Too bad, and thanks for the tip on how to generate this.

>

>> Maybe a 'if __builtin_constant_p(_Condition)' could help if gcc 

>> doesn't do it itself already.

>

> How would you use that precisely?


I wouldn't, I wasn't totally waken up when I proposed this, it makes no 
sens.

>

> It may be easiest to use a different macro for trivial tests that can go

> with __builtin_unreachable and for expensive tests that cannot.

>

Even if I think that doing this kind of operation in an assert call is 
too much I agree that it makes this change invalid.

I'll see if I need to introduce a macro the day I want to add a 
__builtin_unreachable.

François
Jonathan Wakely Sept. 19, 2018, 9:16 a.m. | #5
On 17/09/18 23:15 +0200, Marc Glisse wrote:
>On Mon, 17 Sep 2018, François Dumont wrote:

>

>>We talk about it a while back.

>>

>>I've run testsuite several times since I have this patch on my local 

>>copy. Note that when I implemented it the wrong way tests started to 

>>fail so it is clearly having an effect on the generated code.

>>

>>* include/bits/c++config [__OPTIMIZE__](__glibcxx_assert): Define as 

>>optimization hint

>>

>>using __builtin_unreachable.

>>

>>Ok to commit ?

>

>I see for instance in bits/regex_automaton.tcc:

>

>              __glibcxx_assert(__m.count(__ref._M_next) > 0);

>

>where __m is a map, which does not look so well suited for a 

>__builtin_unreachable. Is it using the wrong macro?


Yes, that looks like it's checking the implementation, but we should
only add assertions to check what users do (we just need to get our
own implementation right).

PR 85184 points out some similar assertions.
Jonathan Wakely Sept. 19, 2018, 9:42 a.m. | #6
On 19/09/18 10:16 +0100, Jonathan Wakely wrote:
>On 17/09/18 23:15 +0200, Marc Glisse wrote:

>>On Mon, 17 Sep 2018, François Dumont wrote:

>>

>>>We talk about it a while back.

>>>

>>>I've run testsuite several times since I have this patch on my 

>>>local copy. Note that when I implemented it the wrong way tests 

>>>started to fail so it is clearly having an effect on the generated 

>>>code.

>>>

>>>* include/bits/c++config [__OPTIMIZE__](__glibcxx_assert): Define 

>>>as optimization hint

>>>

>>>using __builtin_unreachable.

>>>

>>>Ok to commit ?

>>

>>I see for instance in bits/regex_automaton.tcc:

>>

>>             __glibcxx_assert(__m.count(__ref._M_next) > 0);

>>

>>where __m is a map, which does not look so well suited for a 

>>__builtin_unreachable. Is it using the wrong macro?

>

>Yes, that looks like it's checking the implementation, but we should

>only add assertions to check what users do (we just need to get our

>own implementation right).


I'll test this patch.
diff --git a/libstdc++-v3/include/bits/regex_automaton.tcc b/libstdc++-v3/include/bits/regex_automaton.tcc
index 7a0e6a36a7a..5993fcfeeaf 100644
--- a/libstdc++-v3/include/bits/regex_automaton.tcc
+++ b/libstdc++-v3/include/bits/regex_automaton.tcc
@@ -220,16 +220,9 @@ namespace __detail
 	  auto __v = __it.second;
 	  auto& __ref = _M_nfa[__v];
 	  if (__ref._M_next != _S_invalid_state_id)
-	    {
-	      __glibcxx_assert(__m.count(__ref._M_next) > 0);
-	      __ref._M_next = __m[__ref._M_next];
-	    }
-	  if (__ref._M_has_alt())
-	    if (__ref._M_alt != _S_invalid_state_id)
-	      {
-		__glibcxx_assert(__m.count(__ref._M_alt) > 0);
-		__ref._M_alt = __m[__ref._M_alt];
-	      }
+	    __ref._M_next = __m.find(__ref._M_next)->second;
+	  if (__ref._M_has_alt() && __ref._M_alt != _S_invalid_state_id)
+	    __ref._M_alt = __m.find(__ref._M_alt)->second;
 	}
       return _StateSeq(_M_nfa, __m[_M_start], __m[_M_end]);
     }
Jonathan Wakely Sept. 19, 2018, 11:21 a.m. | #7
On 19/09/18 10:42 +0100, Jonathan Wakely wrote:
>On 19/09/18 10:16 +0100, Jonathan Wakely wrote:

>>On 17/09/18 23:15 +0200, Marc Glisse wrote:

>>>On Mon, 17 Sep 2018, François Dumont wrote:

>>>

>>>>We talk about it a while back.

>>>>

>>>>I've run testsuite several times since I have this patch on my 

>>>>local copy. Note that when I implemented it the wrong way tests 

>>>>started to fail so it is clearly having an effect on the 

>>>>generated code.

>>>>

>>>>* include/bits/c++config [__OPTIMIZE__](__glibcxx_assert): 

>>>>Define as optimization hint

>>>>

>>>>using __builtin_unreachable.

>>>>

>>>>Ok to commit ?

>>>

>>>I see for instance in bits/regex_automaton.tcc:

>>>

>>>            __glibcxx_assert(__m.count(__ref._M_next) > 0);

>>>

>>>where __m is a map, which does not look so well suited for a 

>>>__builtin_unreachable. Is it using the wrong macro?

>>

>>Yes, that looks like it's checking the implementation, but we should

>>only add assertions to check what users do (we just need to get our

>>own implementation right).

>

>I'll test this patch.


Committed to trunk.

       * include/bits/regex_automaton.tcc (_StateSeq<_TraitsT>::_M_clone()):
       Remove __glibcxx_assert statements and use map::find instead of
       map::operator[].


>diff --git a/libstdc++-v3/include/bits/regex_automaton.tcc b/libstdc++-v3/include/bits/regex_automaton.tcc

>index 7a0e6a36a7a..5993fcfeeaf 100644

>--- a/libstdc++-v3/include/bits/regex_automaton.tcc

>+++ b/libstdc++-v3/include/bits/regex_automaton.tcc

>@@ -220,16 +220,9 @@ namespace __detail

> 	  auto __v = __it.second;

> 	  auto& __ref = _M_nfa[__v];

> 	  if (__ref._M_next != _S_invalid_state_id)

>-	    {

>-	      __glibcxx_assert(__m.count(__ref._M_next) > 0);

>-	      __ref._M_next = __m[__ref._M_next];

>-	    }

>-	  if (__ref._M_has_alt())

>-	    if (__ref._M_alt != _S_invalid_state_id)

>-	      {

>-		__glibcxx_assert(__m.count(__ref._M_alt) > 0);

>-		__ref._M_alt = __m[__ref._M_alt];

>-	      }

>+	    __ref._M_next = __m.find(__ref._M_next)->second;

>+	  if (__ref._M_has_alt() && __ref._M_alt != _S_invalid_state_id)

>+	    __ref._M_alt = __m.find(__ref._M_alt)->second;

> 	}

>       return _StateSeq(_M_nfa, __m[_M_start], __m[_M_end]);

>     }

Patch

diff --git a/libstdc++-v3/include/bits/c++config b/libstdc++-v3/include/bits/c++config
index d499d32b51e..24bdc97e0f5 100644
--- a/libstdc++-v3/include/bits/c++config
+++ b/libstdc++-v3/include/bits/c++config
@@ -466,6 +466,9 @@  namespace std
 
 #if defined(_GLIBCXX_ASSERTIONS)
 # define __glibcxx_assert(_Condition) __glibcxx_assert_impl(_Condition)
+#elif defined(__OPTIMIZE__)
+# define __glibcxx_assert(_Condition)					 \
+  do { if (! (_Condition)) __builtin_unreachable(); } while (false)
 #else
 # define __glibcxx_assert(_Condition)
 #endif