[Bug c++/108537] New: constexpr UB pointer dereference compiles if the dereferenced value is not used

2023-01-25 Thread ed at edwardrosten dot com via Gcc-bugs
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=108537

Bug ID: 108537
   Summary: constexpr UB pointer dereference compiles if the
dereferenced value is not used
   Product: gcc
   Version: 12.2.1
Status: UNCONFIRMED
  Severity: normal
  Priority: P3
 Component: c++
  Assignee: unassigned at gcc dot gnu.org
  Reporter: ed at edwardrosten dot com
  Target Milestone: ---

The following code compiles successfully:

constexpr int a(){
int* b = new int[1];
int r= [100]-b; //UB
b[100];  //UB
delete[] b;
return r;
}


template int N=0;

int foo(){
return N;
}


b[100] is unconditionally undefined behaviour, even though the value is never
used.

Tested on a scattering of versions (10.3, 11.2, 12.2) with -std=c++2a -O2

[Bug tree-optimization/103429] Optimization of Auto-generated condition chain is not giving good lookup tables.

2021-11-25 Thread ed at edwardrosten dot com via Gcc-bugs
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=103429

--- Comment #2 from Edward Rosten  ---
It is doing if-to-switch, but only really with N=5, and only if force-inline is
set. I think this are two problems, one is that you need to force-inline in
order to trigger if-to-switch.

The other problem is that the if-to-switch conversion triggered only works well
for exactly 5 conditions, otherwise it uses a mix of converted and unconverted.
It doesn't appear to be doing binary tree generation, more like linear search
Here's the asm for N=7:

run(int):
ret
run_inline(int):
testedi, edi
je  .L13
cmp edi, 1
je  .L14
cmp edi, 6
ja  .L3
mov edi, edi
jmp [QWORD PTR .L8[0+rdi*8]]
.L8:
.quad   .L3
.quad   .L3
.quad   .L12
.quad   .L11
.quad   .L10
.quad   .L9
.quad   .L7
.L13:
jmp void f<0>()
.L7:
jmp void f<6>()
.L12:
jmp void f<2>()
.L11:
jmp void f<3>()
.L10:
jmp void f<4>()
.L9:
jmp void f<5>()
.L14:
jmp void f<1>()
.L3:
ret

Note, it's essentially doing:

if(i==0)
f<0>();
else if(i==1)
f<1>();
else if(i > 6)
return;
else switch(i){
case 0:
case 1:   
return;
case 2: f<2>(); return;
case 3: f<3>(); return;
case 4: f<4>(); return;
case 5: f<5>(); return;
case 6: f<6>(); return;
}

It's not doing binary searches. For, e.g. N%5 == 1, the structure is more like:

if(i==0)
f<0>();
else if(i > 5){
if(i-5 > 4){
if(i-11>4){
if(i-16 > 4){ 
 // and so on, linearly
}
else switch(i-16){
 //...
}
}
else switch(i-11){
   //...
}
}
else switch(i-6){
  //...
}

}
else switch(i){
case 0:
return;
case 1: f<1>(); return;  
case 2: f<2>(); return;
case 3: f<3>(); return;
case 4: f<4>(); return;
case 5: f<5>(); return;
}

[Bug c++/103429] New: Optimization of Auto-generated condition chain is not giving good lookup tables.

2021-11-25 Thread ed at edwardrosten dot com via Gcc-bugs
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=103429

Bug ID: 103429
   Summary: Optimization of Auto-generated condition chain is not
giving good lookup tables.
   Product: gcc
   Version: 12.0
Status: UNCONFIRMED
  Keywords: missed-optimization
  Severity: normal
  Priority: P3
 Component: c++
  Assignee: unassigned at gcc dot gnu.org
  Reporter: ed at edwardrosten dot com
  Target Milestone: ---

I've got come generated condition chains (using recursive templates) and am
getting some odd/suboptimal optimization results. Code is provided below and
with a godbolt link.

In the first case (without a force inline), the compiler inlines the functions
but does not perform condition chain optimization. In the second case
(identical code but with force inline), it will optimize condition chains but
only with exactly 5 elements. Otherwise it will end up with an if-else
structure indexing optimized 5 element condition chains, and an if-else chain
for anything spare.

It only attempts the optimization from gcc 11 onwards, I checked on trunk too.


Example:
https://godbolt.org/z/c9xbPqq7r

Here's the code:
template void f();

constexpr int N=5;

template 
static inline void f_dispatch(int i){
if constexpr (I == N)
return;
else if(i == I)
f();
else
f_dispatch(i);
}

template __attribute__((always_inline)) 
static inline void f_dispatch_always_inline(int i){
if constexpr (I == N)
return;
else if(i == I)
f();
else
f_dispatch_always_inline(i);
}

void run(int i){
f_dispatch<>(i);
}

void run_inline(int i){
f_dispatch_always_inline<>(i);
}