diff mbox series

[2/2] Generate constant at start of loop, without UB

Message ID 20240408141815.127984-3-j@lambda.is
State New
Headers show
Series More condition coverage fixes | expand

Commit Message

Jørgen Kvalsvik April 8, 2024, 2:18 p.m. UTC
Generating the constants used for recording the edges taken for
condition coverage would trigger undefined behavior when an expression
had exactly 64 (== sizeof (1ULL)) conditions, as it would generate the
constant for the next iteration at the end of the loop body, even if there
was never a next iteration. By moving the check and constant generation
to the top of the loop and hoisting the increment flag there is no
opportunity for UB.

	PR 114627

gcc/ChangeLog:

	* tree-profile.cc (instrument_decisions): Generate constant
	at the start of loop.
---
 gcc/tree-profile.cc | 20 +++++++++++++++-----
 1 file changed, 15 insertions(+), 5 deletions(-)

Comments

Richard Biener April 9, 2024, 7:40 a.m. UTC | #1
On Mon, 8 Apr 2024, Jørgen Kvalsvik wrote:

> Generating the constants used for recording the edges taken for
> condition coverage would trigger undefined behavior when an expression
> had exactly 64 (== sizeof (1ULL)) conditions, as it would generate the
> constant for the next iteration at the end of the loop body, even if there
> was never a next iteration. By moving the check and constant generation
> to the top of the loop and hoisting the increment flag there is no
> opportunity for UB.

OK.

Thanks,
Richard.

> 	PR 114627
> 
> gcc/ChangeLog:
> 
> 	* tree-profile.cc (instrument_decisions): Generate constant
> 	at the start of loop.
> ---
>  gcc/tree-profile.cc | 20 +++++++++++++++-----
>  1 file changed, 15 insertions(+), 5 deletions(-)
> 
> diff --git a/gcc/tree-profile.cc b/gcc/tree-profile.cc
> index 33ff550a7bc..e58f5c83472 100644
> --- a/gcc/tree-profile.cc
> +++ b/gcc/tree-profile.cc
> @@ -1049,6 +1049,7 @@ instrument_decisions (array_slice<basic_block> expr, size_t condno,
>      zerocounter[2] = zero;
>  
>      unsigned xi = 0;
> +    bool increment = false;
>      tree rhs = build_int_cst (gcov_type_node, 1ULL << xi);
>      for (basic_block current : expr)
>      {
> @@ -1057,7 +1058,14 @@ instrument_decisions (array_slice<basic_block> expr, size_t condno,
>  	    candidates.safe_push (zerocounter);
>  	counters prev = resolve_counters (candidates);
>  
> -	int increment = 0;
> +	if (increment)
> +	{
> +	    xi += 1;
> +	    gcc_checking_assert (xi < sizeof (uint64_t) * BITS_PER_UNIT);
> +	    rhs = build_int_cst (gcov_type_node, 1ULL << xi);
> +	    increment = false;
> +	}
> +
>  	for (edge e : current->succs)
>  	{
>  	    counters next = prev;
> @@ -1072,7 +1080,7 @@ instrument_decisions (array_slice<basic_block> expr, size_t condno,
>  		    tree m = build_int_cst (gcov_type_node, masks[2*xi + k]);
>  		    next[2] = emit_bitwise_op (e, prev[2], BIT_IOR_EXPR, m);
>  		}
> -		increment = 1;
> +		increment = true;
>  	    }
>  	    else if (e->flags & EDGE_COMPLEX)
>  	    {
> @@ -1085,11 +1093,13 @@ instrument_decisions (array_slice<basic_block> expr, size_t condno,
>  	    }
>  	    table.get_or_insert (e->dest).safe_push (next);
>  	}
> -	xi += increment;
> -	if (increment)
> -	    rhs = build_int_cst (gcov_type_node, 1ULL << xi);
>      }
>  
> +    /* Since this is also the return value, the number of conditions, make sure
> +       to include the increment of the last basic block.  */
> +    if (increment)
> +	xi += 1;
> +
>      gcc_assert (xi == bitmap_count_bits (core));
>  
>      const tree relaxed = build_int_cst (integer_type_node, MEMMODEL_RELAXED);
>
Jørgen Kvalsvik April 9, 2024, 7:58 a.m. UTC | #2
On 09/04/2024 09:40, Richard Biener wrote:
> On Mon, 8 Apr 2024, Jørgen Kvalsvik wrote:
> 
>> Generating the constants used for recording the edges taken for
>> condition coverage would trigger undefined behavior when an expression
>> had exactly 64 (== sizeof (1ULL)) conditions, as it would generate the
>> constant for the next iteration at the end of the loop body, even if there
>> was never a next iteration. By moving the check and constant generation
>> to the top of the loop and hoisting the increment flag there is no
>> opportunity for UB.
> 
> OK.
> 
> Thanks,
> Richard.

Thanks, committed.

> 
>> 	PR 114627
>>
>> gcc/ChangeLog:
>>
>> 	* tree-profile.cc (instrument_decisions): Generate constant
>> 	at the start of loop.
>> ---
>>   gcc/tree-profile.cc | 20 +++++++++++++++-----
>>   1 file changed, 15 insertions(+), 5 deletions(-)
>>
>> diff --git a/gcc/tree-profile.cc b/gcc/tree-profile.cc
>> index 33ff550a7bc..e58f5c83472 100644
>> --- a/gcc/tree-profile.cc
>> +++ b/gcc/tree-profile.cc
>> @@ -1049,6 +1049,7 @@ instrument_decisions (array_slice<basic_block> expr, size_t condno,
>>       zerocounter[2] = zero;
>>   
>>       unsigned xi = 0;
>> +    bool increment = false;
>>       tree rhs = build_int_cst (gcov_type_node, 1ULL << xi);
>>       for (basic_block current : expr)
>>       {
>> @@ -1057,7 +1058,14 @@ instrument_decisions (array_slice<basic_block> expr, size_t condno,
>>   	    candidates.safe_push (zerocounter);
>>   	counters prev = resolve_counters (candidates);
>>   
>> -	int increment = 0;
>> +	if (increment)
>> +	{
>> +	    xi += 1;
>> +	    gcc_checking_assert (xi < sizeof (uint64_t) * BITS_PER_UNIT);
>> +	    rhs = build_int_cst (gcov_type_node, 1ULL << xi);
>> +	    increment = false;
>> +	}
>> +
>>   	for (edge e : current->succs)
>>   	{
>>   	    counters next = prev;
>> @@ -1072,7 +1080,7 @@ instrument_decisions (array_slice<basic_block> expr, size_t condno,
>>   		    tree m = build_int_cst (gcov_type_node, masks[2*xi + k]);
>>   		    next[2] = emit_bitwise_op (e, prev[2], BIT_IOR_EXPR, m);
>>   		}
>> -		increment = 1;
>> +		increment = true;
>>   	    }
>>   	    else if (e->flags & EDGE_COMPLEX)
>>   	    {
>> @@ -1085,11 +1093,13 @@ instrument_decisions (array_slice<basic_block> expr, size_t condno,
>>   	    }
>>   	    table.get_or_insert (e->dest).safe_push (next);
>>   	}
>> -	xi += increment;
>> -	if (increment)
>> -	    rhs = build_int_cst (gcov_type_node, 1ULL << xi);
>>       }
>>   
>> +    /* Since this is also the return value, the number of conditions, make sure
>> +       to include the increment of the last basic block.  */
>> +    if (increment)
>> +	xi += 1;
>> +
>>       gcc_assert (xi == bitmap_count_bits (core));
>>   
>>       const tree relaxed = build_int_cst (integer_type_node, MEMMODEL_RELAXED);
>>
>
diff mbox series

Patch

diff --git a/gcc/tree-profile.cc b/gcc/tree-profile.cc
index 33ff550a7bc..e58f5c83472 100644
--- a/gcc/tree-profile.cc
+++ b/gcc/tree-profile.cc
@@ -1049,6 +1049,7 @@  instrument_decisions (array_slice<basic_block> expr, size_t condno,
     zerocounter[2] = zero;
 
     unsigned xi = 0;
+    bool increment = false;
     tree rhs = build_int_cst (gcov_type_node, 1ULL << xi);
     for (basic_block current : expr)
     {
@@ -1057,7 +1058,14 @@  instrument_decisions (array_slice<basic_block> expr, size_t condno,
 	    candidates.safe_push (zerocounter);
 	counters prev = resolve_counters (candidates);
 
-	int increment = 0;
+	if (increment)
+	{
+	    xi += 1;
+	    gcc_checking_assert (xi < sizeof (uint64_t) * BITS_PER_UNIT);
+	    rhs = build_int_cst (gcov_type_node, 1ULL << xi);
+	    increment = false;
+	}
+
 	for (edge e : current->succs)
 	{
 	    counters next = prev;
@@ -1072,7 +1080,7 @@  instrument_decisions (array_slice<basic_block> expr, size_t condno,
 		    tree m = build_int_cst (gcov_type_node, masks[2*xi + k]);
 		    next[2] = emit_bitwise_op (e, prev[2], BIT_IOR_EXPR, m);
 		}
-		increment = 1;
+		increment = true;
 	    }
 	    else if (e->flags & EDGE_COMPLEX)
 	    {
@@ -1085,11 +1093,13 @@  instrument_decisions (array_slice<basic_block> expr, size_t condno,
 	    }
 	    table.get_or_insert (e->dest).safe_push (next);
 	}
-	xi += increment;
-	if (increment)
-	    rhs = build_int_cst (gcov_type_node, 1ULL << xi);
     }
 
+    /* Since this is also the return value, the number of conditions, make sure
+       to include the increment of the last basic block.  */
+    if (increment)
+	xi += 1;
+
     gcc_assert (xi == bitmap_count_bits (core));
 
     const tree relaxed = build_int_cst (integer_type_node, MEMMODEL_RELAXED);