[Bug tree-optimization/94356] New: Missed optimisation: useless multiplication generated for pointer comparison

2020-03-27 Thread pascal_cuoq at hotmail dot com
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=94356

Bug ID: 94356
   Summary: Missed optimisation: useless multiplication generated
for pointer comparison
   Product: gcc
   Version: 9.3.0
Status: UNCONFIRMED
  Severity: normal
  Priority: P3
 Component: tree-optimization
  Assignee: unassigned at gcc dot gnu.org
  Reporter: pascal_cuoq at hotmail dot com
  Target Milestone: ---

The closest existing ticket I found for this one is
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=48316 but this seems different
enough, although it might be linked.

Consider the function:

typedef int t[10];

int f(t *p, long long o) {
return p < p+o;
}

GCC 9.3 with -O2, targeting x86-64, correctly simplifies by p, but still
generates a 64x64->64 multiplication in the computation of the offset:

f:
imulq   $40, %rsi, %rsi
xorl%eax, %eax
testq   %rsi, %rsi
setg%al
ret

(Compiler Explorer link: https://gcc.godbolt.org/z/_pT8E- )

Clang 10 avoids generating the multiplication on this example:

f:  # @f
xorl%eax, %eax
testq   %rsi, %rsi
setg%al
retq

A variant of this example is this other function g with two offsets:

int g(t *p, long long o1, long long o2) {
return p+o1 < p+o2;
}

Clang generates the same code as for “o1https://gcc.godbolt.org/z/sDJyHP

[Bug target/94650] New: Missed x86-64 peephole optimization: x >= large power of two

2020-04-18 Thread pascal_cuoq at hotmail dot com
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=94650

Bug ID: 94650
   Summary: Missed x86-64 peephole optimization: x >= large power
of two
   Product: gcc
   Version: 9.3.0
Status: UNCONFIRMED
  Severity: normal
  Priority: P3
 Component: target
  Assignee: unassigned at gcc dot gnu.org
  Reporter: pascal_cuoq at hotmail dot com
  Target Milestone: ---

Consider the three functions check, test0 and test1:

(Compiler Explorer link: https://gcc.godbolt.org/z/Sh4GpR )

#include 

#define LARGE_POWER_OF_TWO (1UL << 40)

int check(unsigned long m)
{
return m >= LARGE_POWER_OF_TWO;
}

void g(int);

void test0(unsigned long m)
{
if (m >= LARGE_POWER_OF_TWO) g(0);
}

void test1(unsigned long m)
{
if (m >= LARGE_POWER_OF_TWO) g(m);
}

At least in the case of check and test0, the optimal way to compare m to 1<<40
is to shift m by 40 and compare the result to 0. This is the code generated for
these functions by Clang 10:

check:  # @check
xorl%eax, %eax
shrq$40, %rdi
setne   %al
retq
test0:  # @test0
shrq$40, %rdi
je  .LBB1_1
xorl%edi, %edi
jmp g   # TAILCALL
.LBB1_1:
retq

In contrast, GCC 9.3 uses a 64-bit constant that needs to be loaded in a
register with movabsq:

check:
movabsq $1099511627775, %rax
cmpq%rax, %rdi
seta%al
movzbl  %al, %eax
ret
test0:
movabsq $1099511627775, %rax
cmpq%rax, %rdi
ja  .L5
ret
.L5:
xorl%edi, %edi
jmp g


In the case of the function test1 the comparison is between these two version,
because the shift is destructive:

Clang10:
test1:  # @test1
movq%rdi, %rax
shrq$40, %rax
je  .LBB2_1
jmp g   # TAILCALL
.LBB2_1:
retq

GCC9.3:
test1:
movabsq $1099511627775, %rax
cmpq%rax, %rdi
ja  .L8
ret
.L8:
jmp g

It is less obvious which approach is better in the case of the function test1,
but generally speaking the shift approach should still be faster. The
register-register move can be free on Skylake (in the sense of not needing any
execution port), whereas movabsq requires an execution port and also it's a
10-byte instruction!

[Bug middle-end/94651] New: Missed peephole optimization: m >= POWER_OF_TWO || n >= POWER_OF_TWO

2020-04-18 Thread pascal_cuoq at hotmail dot com
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=94651

Bug ID: 94651
   Summary: Missed peephole optimization: m >= POWER_OF_TWO || n
>= POWER_OF_TWO
   Product: gcc
   Version: 9.3.0
Status: UNCONFIRMED
  Severity: normal
  Priority: P3
 Component: middle-end
  Assignee: unassigned at gcc dot gnu.org
  Reporter: pascal_cuoq at hotmail dot com
  Target Milestone: ---

Consider the functions:

(Compiler Explorer link: https://gcc.godbolt.org/z/Uzd6nd )

#define POWER_OF_TWO (1UL << 20)

int check(unsigned long m, unsigned long n)
{
return m >= POWER_OF_TWO || n >= POWER_OF_TWO;
}

void g(unsigned long, unsigned long);

void test1(unsigned long m, unsigned long n)
{
if (m >= POWER_OF_TWO || n >= POWER_OF_TWO) g(m, 0);
}

void test2(unsigned long m, unsigned long n)
{
if (m >= POWER_OF_TWO || n >= POWER_OF_TWO) g(m, n);
}

At least for the test1 and test2 functions, it seems that code that implements
(m|n) >= POWER_OF_TWO will be faster on average for more input distributions
than code with two comparisons on pretty much every modern architecture. This
is what Clang 10 generates:

check:  # @check
orq %rsi, %rdi
xorl%eax, %eax
cmpq$1048575, %rdi  # imm = 0xF
seta%al
retq
test1:  # @test1
orq %rdi, %rsi
cmpq$1048576, %rsi  # imm = 0x10
jb  .LBB1_1
xorl%esi, %esi
jmp g   # TAILCALL
.LBB1_1:
retq
test2:  # @test2
movq%rsi, %rax
orq %rdi, %rax
cmpq$1048576, %rax  # imm = 0x10
jb  .LBB2_1
jmp g   # TAILCALL
.LBB2_1:
retq


GCC 9.3 does one comparison after the other. This leads to extra instructions
being necessary afterwards for the function check on x86, although it saves one
register-register move in the function test2:

check:
cmpq$1048575, %rdi
seta%al
cmpq$1048575, %rsi
seta%dl
orl %edx, %eax
movzbl  %al, %eax
ret
test1:
cmpq$1048575, %rdi
ja  .L6
cmpq$1048575, %rsi
ja  .L6
ret
.L6:
xorl%esi, %esi
jmp g
test2:
cmpq$1048575, %rdi
ja  .L10
cmpq$1048575, %rsi
ja  .L10
ret
.L10:
jmp g

[Bug c/94658] New: Incorrect transformation with -fstrict-aliasing

2020-04-19 Thread pascal_cuoq at hotmail dot com
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=94658

Bug ID: 94658
   Summary: Incorrect transformation with -fstrict-aliasing
   Product: gcc
   Version: 9.3.0
Status: UNCONFIRMED
  Severity: normal
  Priority: P3
 Component: c
  Assignee: unassigned at gcc dot gnu.org
  Reporter: pascal_cuoq at hotmail dot com
  Target Milestone: ---

C17 6.5:6 says:

The effective type of an object for an access to its stored value is the
declared type of the object, if any.88) If a value is stored into an object
having no declared type through an lvalue having a type that is not a character
type, then the type of the lvalue becomes the effective type of the object for
that access and for subsequent accesses that do not modify the stored value. If
a value is copied into an object having no declared type using memcpy or
memmove, or is copied as an array of character type, then the effective type of
the modified object for that access and for subsequent accesses that do not
modify the value is the effective type of the object from which the value is
copied, if it has one. For all other accesses to an object having no declared
type, the effective type of the object is simply the type of the lvalue used
for the access.

I interpret the words “If a value is stored into an object having no declared
type through an lvalue having a type that is not a character type, then the
type of the lvalue becomes the effective type of the object for that access and
for subsequent accesses that do not modify the stored value” as saying that the
repurposing of dynamically allocated memory is allowed in C. A write of a new
value to dynamically allocated memory is not a “subsequent access that does not
modify the stored value”, so it simply changes the type of the memory to the
type of the lvalue being used for the write.

Consider the following program, which was provided by Sorav Bansal:

(Compiler Explorer link: https://gcc.godbolt.org/z/Vg25xq )

#include 
#include 
#include 
#include 

int a;

__attribute__((__noinline__)) int foo(float *x, int *y, int *z)
{
  int sum = 1;
  for (int i = 0; i < a; i++) {
*z = 0x123;
*x = 3.0f;
sum *= *y;
*z = 0x40400300;
  }
  return sum;
}

int main()
{
  char *f;
  f = malloc(32);
  if (!f) abort();
  int i = 3;
  a = 1;
  foo((float*)f, &i, (int*)f);
  float fl;
  memcpy(&fl, f, 4);
  printf("f = %f\n", fl);
}

According to my interpretation above (“repurposing of dynamically allocated
memory is allowed”), this program does nothing wrong. The memory location that
both x and z point to is repurposed many times, but it is never read inside
function foo, and the function main reads it carefully using memcpy.

The behavior I expect for this program is to print:

f = 3.000183

(3.000183 is the float represented by 0x40400300.)

However, when -fstrict-aliasing is enabled, the compiler moves the assignment
“*x = 3.0f;” after the loop and makes the compiled program print:

f = 3.00

I think the transformation is wrong here. The function foo does not invoke UB
when passed z and x aliasing pointers to dynamically allocated memory, and the
“naïve memory model” behavior of the function should have been preserved for
such a calling context.

Yes, this would mean that Clang has independently implemented the same bug, but
I am still confident enough that the C standard intended to allow the
repurposing of dynamically allocated memory to report this. Please accept my
apologies if I am wrong. I have heard it said that the C++ standard has a
different philosophy, but this is a bug report against the C compiler.

[Bug c/94658] Incorrect transformation with -fstrict-aliasing

2020-04-19 Thread pascal_cuoq at hotmail dot com
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=94658

--- Comment #1 from Pascal Cuoq  ---
Clang bug for the same optimization in Clang 10 filed at
https://bugs.llvm.org/show_bug.cgi?id=45607

[Bug tree-optimization/57359] store motion causes wrong code for union access at -O3

2020-04-20 Thread pascal_cuoq at hotmail dot com
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=57359

--- Comment #25 from Pascal Cuoq  ---
Would it be reasonable to have three settings for -fstrict-aliasing, rather
then the current two?

- off
- strict
- assume-no-reuse

(I would let you find a better name for the third one.)

It seems to me that the wrong transformation corresponds to code patterns that
a C developers familiar with the compiled code would be able to tell are used
or not in the compiled code: repurposing of dynamically allocated memory and
access to a union through pointers.

(Note: in https://trust-in-soft.com/wp-content/uploads/2017/01/vmcai.pdf we
remarked that GCC is particularly user-friendly in both documenting what uses
of unions are compatible with -fstrict-aliasing and in sticking to the
documented behavior. The place in the GCC documentation where this is
documented would already explain a lot of the context for explaining the
difference between the strict and assume-no-reuse settings.)

Even if you set -fstrict-aliasing=assume-no-reuse as implied by -O2, this would
still be a much welcome improvement compared to the current situation. GCC
would continue to be compared fairly in benchmarks to other compilers that have
the same approximation, most programs would continue to work fine because they
do not rely on the dangerous patterns, and those that rely on the dangerous
pattern would have a way out.

It would be vaguely comparable to -ffast-math.

One possible psychological drawback may be that if the “strict” option exists,
some users may ask why GCC does not stick to it in the -On settings.

[Bug c/93031] New: Wish: When the underlying ISA does not force pointer alignment, option to make GCC not assume it

2019-12-20 Thread pascal_cuoq at hotmail dot com
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=93031

Bug ID: 93031
   Summary: Wish: When the underlying ISA does not force pointer
alignment, option to make GCC not assume it
   Product: gcc
   Version: 9.2.0
Status: UNCONFIRMED
  Severity: normal
  Priority: P3
 Component: c
  Assignee: unassigned at gcc dot gnu.org
  Reporter: pascal_cuoq at hotmail dot com
  Target Milestone: ---

GCC assumes that pointers must be aligned as part of its optimizations, even if
the ISA does not force it (for instance, x86-64 without the vector
instructions). The present feature wish as for an option to make it not make
this assumption.

Since the late 1990s, GCC has been adding optimizations based on undefined
behavior, and “breaking” existing C programs that used to “work” by relying on
the assumption that since they were compiled for architecture X, they would be
fine. The reasonable developers have been kept happy by giving them options to
preserve the old behavior. These options are -fno-strict-aliasing, -fwrapv, ...
and I think there should be another one.

In 2016, Pavel Zemtsov showed that a C program that was written assuming that
misaligned pointer accesses are allowed could be compiled by GCC to code that
did not work as intended:

http://pzemtsov.github.io/2016/11/06/bug-story-alignment-on-x86.html

This was an interesting development, but GCC's behavior was fair: Pavel had not
disabled the vector instructions, GCC had automatically inserted these
instructions in the generated code, so the target architecture was not really
one that allowed all misaligned pointer accesses. Using -mno-sse would have
fixed the behavior.

I have recently noticed that since at least version 8.1, GCC assumes that all
pointers are aligned even when the target ISA really has no such restriction.
This can be seen by compiling the two functions below (Compiler Explorer link: 
https://gcc.godbolt.org/z/UBBD2Y )

int h(int *p, int *q){
  *p = 1;
  *q = 1;
  return *p;
}

typedef __attribute__((__may_alias__)) int I;

I k(I *p, I *q){
  *p = 1;
  *q = 1;
  return *p;
}

Compiling with GCC 8.1 or 9.2, with either the options “-O2” or “-O2
-fno-strict-aliasing”, GCC generates code that assumes that the functions will
always return 1.
It does so because it assumes both p and q to be aligned pointers. I would like
to have an option in order to make it not make this assumption.

(This feature wish is not related to strict aliasing. I have only used the
option and the attribute in order to show that the optimization at play here is
not related to strict aliasing, and that there is currently no documented way
(that I know of) to disable it after having passed “-O2”.)

A context in which the functions are called may be:

int main(void) {
char t[6];
return h((int*)t, (int*)(t+2));
}

This context violates strict aliasing, but when using
__attribute__((__may_alias__)) or -fno-strict-aliasing, this should not be
relevant.

The idea here would be to have an option to keep legacy code that used to work
working. Modern C code should probably use memcpy to access sequences of bytes
that are to be treated as a word but may not be aligned in memory, since both
Clang and GCC usually makes these memcpy free.

This feature wish is partially related to the bug report about packed structs
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=51628 which ended with the
addition of a new warning -Waddress-of-packed-member, but it is concerned with
architectures on which misaligned accesses are allowed, not with architectures
on which they are not.

[Bug c/93031] Wish: When the underlying ISA does not force pointer alignment, option to make GCC not assume it

2019-12-21 Thread pascal_cuoq at hotmail dot com
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=93031

--- Comment #3 from Pascal Cuoq  ---
@amonakov

The two blog posts below exist themselves, and describe tools that exist,
because software that makes misaligned access exists, although it seems to
be a “examples too numerous to list” situation (or, more optimistically,
perhaps one where the source code is fixed upstream as problems are found).

https://blogs.oracle.com/d/on-misaligned-memory-accesses
https://blog.quarkslab.com/unaligned-accesses-in-cc-what-why-and-solutions-to-do-it-properly.html

(In the end it's the binary executable that doesn't work, and both
posts deal with that aspect at some point, but these executables were
not written in SPARC or respectively ARM assembly. If they had been,
they would have been written to work. Instead, they were written in a
higher-level language that was translated to SPARC/ARM assembly,
presumably C.)


For a specific example, fifteen minutes of looking around knowing what
one is looking for turns up the LZO implementation from
http://www.oberhumer.com/opensource/lzo/ . In the latest
version to date, 2.10:

#if (LZO_ARCH_ALPHA)
#  define LZO_OPT_AVOID_UINT_INDEX  1
#elif (LZO_ARCH_AMD64)
#  define LZO_OPT_AVOID_INT_INDEX   1
#  define LZO_OPT_AVOID_UINT_INDEX  1
#  ifndef LZO_OPT_UNALIGNED16
#  define LZO_OPT_UNALIGNED16   1
#  endif
#  ifndef LZO_OPT_UNALIGNED32
#  define LZO_OPT_UNALIGNED32   1
#  endif
#  ifndef LZO_OPT_UNALIGNED64
#  define LZO_OPT_UNALIGNED64   1
#  endif
#elif (LZO_ARCH_ARM)
#  if defined(__ARM_FEATURE_UNALIGNED)
#   if ((__ARM_FEATURE_UNALIGNED)+0)
#ifndef LZO_OPT_UNALIGNED16
#define LZO_OPT_UNALIGNED16 1
#endif
#ifndef LZO_OPT_UNALIGNED32
#define LZO_OPT_UNALIGNED32 1
#endif
#   endif
#  elif 1 && (LZO_ARCH_ARM_THUMB2)

...

#if (LZO_OPT_UNALIGNED32)
LZO_COMPILE_TIME_ASSERT_HEADER(sizeof(*(lzo_memops_TU4p)0)==4)
#define LZO_MEMOPS_COPY4(dd,ss) \
* (lzo_memops_TU4p) (lzo_memops_TU0p) (dd) = * (const lzo_memops_TU4p)
(const lzo_memops_TU0p) (ss)
#elif defined(lzo_memops_tcheck__)
#define LZO_MEMOPS_COPY4(dd,ss) \
LZO_BLOCK_BEGIN if (lzo_memops_tcheck__(lzo_memops_TU4,4,1)) { \
* (lzo_memops_TU4p) (lzo_memops_TU0p) (dd) = * (const lzo_memops_TU4p)
(const lzo_memops_TU0p) (ss); \
} else { LZO_MEMOPS_MOVE4(dd,ss); } LZO_BLOCK_END
#else
#define LZO_MEMOPS_COPY4(dd,ss) LZO_MEMOPS_MOVE4(dd,ss)
#endif

...

It is good news that this particular piece of software is already
designed to work on compilation platforms where misaligned accesses
are forbidden. But if anyone compiles it today with GCC for amd64 or
for “__ARM_FEATURE_UNALIGNED”, they are at risk of an optimization
firing and making the library not work as intended, perhaps in obscure
cases with safety or security implications.

I will state, despite the risk of tedious repetition, that the LZO
implementation invokes Undefined Behavior. I know it, Oberhumer
clearly knows it, and anyone who has read this far knows it. However
the perception of some GCC users (not me!) may be that GCC is once
again changing the rules and taking an Undefined Behavior that would
obviously never cause an actual demon to come out of one's nose, such
as a source file missing a final newline, and changing it into
one that does.

[Bug c/86026] New: Document and/or change allowed operations on integer representation of pointers

2018-06-01 Thread pascal_cuoq at hotmail dot com
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=86026

Bug ID: 86026
   Summary: Document and/or change allowed operations on integer
representation of pointers
   Product: gcc
   Version: 8.1.0
Status: UNCONFIRMED
  Severity: normal
  Priority: P3
 Component: c
  Assignee: unassigned at gcc dot gnu.org
  Reporter: pascal_cuoq at hotmail dot com
  Target Milestone: ---

This report is about GCC's handling of low-level pointer tricks such as the XOR
linked list [1]. Uses of this sort of trick are present in legacy C code and in
newly written code that push the boundaries of what is possible. If users of
GCC are going to apply GCC to this sort of code, they need to know what is
allowed. This relates to the discussion about pointer provenance, for which
Kayvan Memarian and Peter Sewell wrote a discussion draft in 2016 [3].

Consider the three functions below:

char f_ptradd(ptrdiff_t o) {
  g = 1;
  *(t + o) = 2;
  return g;
}

char f_intadd(ptrdiff_t o) {
  g = 1;
  *(char*)((uintptr_t)t + o) = 2;
  return g;
}

char f_intxor(ptrdiff_t o) {
  g = 1;
  *(char*)((uintptr_t)t ^ o) = 2;
  return g;
}

GCC 8.1 produces the following assembly for these functions [2]:

f_ptradd:
  movb $1, g(%rip)
  movl $1, %eax
  movb $2, t(%rdi)
  ret
f_intadd:
  movb $1, g(%rip)
  movl $1, %eax
  movb $2, t(%rdi)
  ret
f_intxor:
  xorq $t, %rdi
  movb $1, g(%rip)
  movb $2, (%rdi)
  movzbl g(%rip), %eax
  ret

The third function does exactly what a XOR linked list implementation does.
Sufficiently smart inlining and constant propagation would turn a generic
implementation into f_intxor.

GCC 8.1 and earlier versions compile the first two functions f_ptradd and
f_intadd as if they could never be invoked as in the following main:

int main(void) {
  f_ptradd((uintptr_t) &g - (uintptr_t) t);
  f_intadd((uintptr_t) &g - (uintptr_t) t);
  f_intxor((uintptr_t) &g ^ (uintptr_t) t);
}

This is fair in the case of f_ptradd, which invokes undefined behavior at “t +
o”. However, I would have expected f_intadd to be compiled conservatively,
because it is possible to pass a value o that, added to the integer
representation of (char*)t, produces the integer representation of g.


Of course, it is for the GCC developers to decide exactly what is allowed and
what isn't after a pointer is converted to an integer. But without an explicit
explanation in GCC's documentation of what makes f_intadd and f_intxor
different, we have to assume that the latter is no more supported than the
former, and that programs that use XOR linked lists or similar data structures
cannot be compiled by GCC.


[1] https://en.wikipedia.org/wiki/XOR_linked_list
[2] https://godbolt.org/g/DYCpjS
[3] http://www.cl.cam.ac.uk/~pes20/cerberus/n2090.html

[Bug c/86026] Document and/or change allowed operations on integer representation of pointers

2018-06-01 Thread pascal_cuoq at hotmail dot com
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=86026

--- Comment #2 from Pascal Cuoq  ---
Created attachment 44223
  --> https://gcc.gnu.org/bugzilla/attachment.cgi?id=44223&action=edit
Complete source code for functions in the description

[Bug c/91199] New: In -fexcess-precision=standard mode, the warning “floating constant truncated to zero” is misleading

2019-07-18 Thread pascal_cuoq at hotmail dot com
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=91199

Bug ID: 91199
   Summary: In -fexcess-precision=standard mode, the warning
“floating constant truncated to zero” is misleading
   Product: gcc
   Version: 9.1.0
Status: UNCONFIRMED
  Severity: normal
  Priority: P3
 Component: c
  Assignee: unassigned at gcc dot gnu.org
  Reporter: pascal_cuoq at hotmail dot com
  Target Milestone: ---

Consider the following program:

#include 
#include 

#define MY_HUGE_VALF 0x1.0p255f

float f;

int main(void) {
  f = 0x1.0p-255f * MY_HUGE_VALF;
  printf("%d, %f\n", (int)FLT_EVAL_METHOD, f);
}

When compiled with -O -fexcess-precision=standard -mfpmath=387 and executed,
this program prints “2, 1.00”, which indicates that neither factor is 0 and
neither is +inf.
Compiler Explorer link: https://gcc.godbolt.org/z/RA_tDw

This all corresponds exactly to the C standard [1] and Joseph Myers's post [2]
introducing the option -fexcess-precision=standard, but please look at the
warnings emitted during compilation:

:9:3: warning: floating constant truncated to zero [-Woverflow]

:9:3: warning: floating constant exceeds range of 'float' [-Woverflow]

The second warning, about MY_HUGE_VALF, is not wrong, and probably corresponds
to an aspect of the program that should be brought to the attention of the
developer.

The first warning is wrong: it implies that 0x1.0p-255f will be interpreted as
0 by the compiler, while it (correctly) isn't.

I would suggest to make the first warning more like the second one, along the
lines of “floating constant underflows range of 'float'”.

[1] https://port70.net/~nsz/c/c11/n1570.html#5.2.4.2.2p9
[2] https://gcc.gnu.org/ml/gcc-patches/2008-11/msg00105.html

[Bug c/89734] New: const qualifier on return type not erased inside __typeof__

2019-03-15 Thread pascal_cuoq at hotmail dot com
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=89734

Bug ID: 89734
   Summary: const qualifier on return type not erased inside
__typeof__
   Product: gcc
   Version: 8.2.0
Status: UNCONFIRMED
  Severity: normal
  Priority: P3
 Component: c
  Assignee: unassigned at gcc dot gnu.org
  Reporter: pascal_cuoq at hotmail dot com
  Target Milestone: ---

I think that this report is related to the implementation of a resolution from
DR 423 in 2017: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=39985#c5

I would expect the following C program to be accepted:

#define CONST(x) __typeof__(const __typeof__(x))
#define POINTER(x) __typeof__(__typeof__(x) *)
#define ARRAY(x, n) __typeof__(__typeof__(x)[n])
#define FUNCTION(x, y) __typeof__(__typeof__(y)(__typeof__(x)))

extern int (* const p(int))[5];

FUNCTION(int, CONST(POINTER(ARRAY(int,5 p;

According to Compiler Explorer, it is accepted by Clang, and by GCC version up
to 6.3, but not by GCC version 7 and above, which complains:

error: conflicting types for 'p'

Compiler Explorer link: https://gcc.godbolt.org/z/c_9JTu

This may be related to how function types are handled inside __typeof__. If the
const attribute is not erased inside __typeof__, then it would not match the
type build for a plain declaration, where the const attribute is erased since
revision 236231.

If that were the case, then a solution would be to make the __typeof__
extension more uniform with the rest of the language.

[Bug c/89872] New: GCC does not generate read access to volatile compound literal

2019-03-28 Thread pascal_cuoq at hotmail dot com
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=89872

Bug ID: 89872
   Summary: GCC does not generate read access to volatile compound
literal
   Product: gcc
   Version: 8.3.0
Status: UNCONFIRMED
  Severity: normal
  Priority: P3
 Component: c
  Assignee: unassigned at gcc dot gnu.org
  Reporter: pascal_cuoq at hotmail dot com
  Target Milestone: ---

This report is similar to but different from my previous report
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=82340

Consider the C code below. The report is about the compilation of the functions
g and hg. The other functions are included only for discussion of the expected
behavior.

void f(void) {
volatile int y=1, z=2;
y + z;
}

void g(void)
{
  (volatile int){1} + (volatile int){2};
}

void k(void)
{
  (volatile int){1};
}

void hf(void)
{
for (int i = 0; i < 1000; i++) f();
}

void hg(void)
{
for (int i = 0; i < 1000; i++) g();
}

void hk(void)
{
for (int i = 0; i < 1000; i++) k();
}

When compiling with -O3, the versions trunk and 8.3 of GCC on Compiler Explorer
(https://gcc.godbolt.org/z/2Il4GG ) produce the following x86-64:

f:
movl$1, -8(%rsp)
movl$2, -4(%rsp)
movl-8(%rsp), %eax
movl-4(%rsp), %eax
ret
g:
ret
k:
movl$1, -4(%rsp)
movl-4(%rsp), %eax
ret
hf:
movl$1000, %eax
.L6:
movl$1, -8(%rsp)
movl$2, -4(%rsp)
movl-8(%rsp), %edx
movl-4(%rsp), %edx
subl$1, %eax
jne .L6
ret
hg:
ret
hk:
movl$1000, %eax
.L10:
movl$1, -4(%rsp)
movl-4(%rsp), %edx
subl$1, %eax
jne .L10
ret

The functions g and hg are compiled to “ret”. Because reading from a volatile
lvalue is an observable side-effect (C11 5.1.2.3:6
https://port70.net/~nsz/c/c11/n1570.html#5.1.2.3p6 ) I would have expected them
to be compiled more similarly to f and hf respectively.

[Bug c/89888] New: When switch controlling expression is promoted from type narrower than int, GCC does not diagnose identical cases

2019-03-29 Thread pascal_cuoq at hotmail dot com
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=89888

Bug ID: 89888
   Summary: When switch controlling expression is promoted from
type narrower than int, GCC does not diagnose
identical cases
   Product: gcc
   Version: 8.3.0
Status: UNCONFIRMED
  Severity: normal
  Priority: P3
 Component: c
  Assignee: unassigned at gcc dot gnu.org
  Reporter: pascal_cuoq at hotmail dot com
  Target Milestone: ---

Consider the C function:

long long X;

void f(unsigned char x)
{
  switch(x) {
case -1: X=-1; break;
case 0x: X=0x; break;
  }
}

The controlling expression of the switch, x, has type unsigned char and is
promoted to int before its type being used as reference for the constants -1
and 0x. This is according to C11 6.8.4.2:5
(https://port70.net/~nsz/c/c11/n1570.html#6.8.4.2p5 )

GCC 8.3 emits very good warnings about each of the constants being, after
conversion, outside the range of an unsigned int and thus unreachable:

: In function 'f':
:6:5: warning: case label value is less than minimum value for type
 case -1: X=-1; break;
 ^~~~
:7:5: warning: case label value is less than minimum value for type
 case 0x: X=0x; break;
 ^~~~

(Compiler Explorer link: https://gcc.godbolt.org/z/gvnvoa )

However, GCC does not warn about the labels being identical after conversion. I
feel silly reporting this, because it only happens for discarded labels that
were unreachable, and there isn't any ambiguity about the meaning of the
program. Still, the C11 clause 6.8.4.2:3 about identical switch case labels
(after conversion) (https://port70.net/~nsz/c/c11/n1570.html#6.8.4.2p3 ) is
under a “Constraints” heading, so depending how much GCC cares about adhering
to the letter of the standard, it may want to diagnose this situation.

Clang diagnoses this situation and emits an “error”:

:7:10: error: duplicate case value '-1'

Clang also emits two misleading warnings about the constants -1 and 0x.
The wording of these warnings is so misleading that it can be considered a
Clang bug, which has been reported in the appropriate place.

[Bug c/89888] When switch controlling expression is promoted from type narrower than int, GCC does not diagnose identical cases

2019-03-29 Thread pascal_cuoq at hotmail dot com
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=89888

--- Comment #1 from Pascal Cuoq  ---
errata: “outside the range of an unsigned char”

[Bug c/90472] New: “extern int i;” declaration inside function is allowed to shadow “static int i;” at file scope

2019-05-14 Thread pascal_cuoq at hotmail dot com
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=90472

Bug ID: 90472
   Summary: “extern int i;” declaration inside function is allowed
to shadow “static int i;” at file scope
   Product: gcc
   Version: 9.1.0
Status: UNCONFIRMED
  Severity: normal
  Priority: P3
 Component: c
  Assignee: unassigned at gcc dot gnu.org
  Reporter: pascal_cuoq at hotmail dot com
  Target Milestone: ---

Consider the two compilation units below, that differ only in the name of the
automatic variable inside function f:


int *p1, *p2;

static int i = 1;

void f(void) {
p1 = &i;
int i = 2;
{
extern int i;
p2 = &i;
}
}

int *p1, *p2;

static int i = 1;

void f(void) {
p1 = &i;
int j = 2;
{
extern int i;
p2 = &i;
}
}


Using GCC 9.1, the first file is accepted and the “obvious” assembly code is
generated (the function f assigns the same value to p1 and p2). The second file
is rejected with the error message:

: In function 'f':
:9:20: error: variable previously declared 'static' redeclared 'extern'
9 | extern int i;
  |^


Compiler Explorer link: https://gcc.godbolt.org/z/wrvZ1d

I rather agree with the error message, and my understanding of C11 6.7:3
(https://port70.net/~nsz/c/c11/n1570.html#6.7p3 ) is that both compilation
units should be rejected. In any case, the two look equivalent, and they should
probably either be both accepted or both rejected.

(If you arrive to the conclusion that the C11 standard says they should both be
rejected, I will have a similar bug to report in Clang.)

[Bug c/90472] “extern int i;” declaration inside function is allowed to shadow “static int i;” at file scope

2019-05-14 Thread pascal_cuoq at hotmail dot com
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=90472

--- Comment #2 from Pascal Cuoq  ---
Thanks for this link.

So the bug report is that the file below is rejected by GCC 9.1 (and every GCC
version present on Compiler Explorer down to 4.1.2), whereas according to the
arguments in https://gcc.gnu.org/bugzilla/show_bug.cgi?id=14366 it should be
accepted.

int *p1, *p2;

static int i = 1;

void f(void) {
p1 = &i;
int i = 2;
{
extern int i;
p2 = &i;
}
}

[Bug c/84764] New: Wrong warning "so large that it is unsigned" for __int128 constant

2018-03-08 Thread pascal_cuoq at hotmail dot com
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=84764

Bug ID: 84764
   Summary: Wrong warning "so large that it is unsigned" for
__int128 constant
   Product: gcc
   Version: 7.3.0
Status: UNCONFIRMED
  Severity: normal
  Priority: P3
 Component: c
  Assignee: unassigned at gcc dot gnu.org
  Reporter: pascal_cuoq at hotmail dot com
  Target Milestone: ---

According to the output of the following program, the type of the constant
1000 is __int128, which is a signed type:

Compiler Explorer link: https://godbolt.org/g/kFTNaz

#include 

#define prtype(X) \
  _Generic((X),   \
   int: "int",\
   long: "long",  \
   long long: "long long",\
   unsigned int: "unsigned int",  \
   unsigned long: "unsigned long",\
   unsigned long long: "unsigned long long",  \
   __int128: "__int128",  \
  default: "?")

int main(void) {
  printf("1 %s\n", prtype(1));
  printf("30 %s\n", prtype(30));
  printf("1000 %s\n", prtype(1000));
}

___
Output:

1 int
30 long
1000 __int128

However a warning is emitted on the last line for the constant
1000:

prtype.c:17:66: warning: integer constant is so large that it is unsigned

This warning implies that the constant is typed as long long, which has been
the case either historically or with other -std= settings. However, for the
compilation settings at hand, the warning is wrong. It should at most say that
the constant is typed with a type outside of the "int, long, long long"
hierarchy of standard types.

For reference the relevant clause of the C11 standard is 6.4.4:
https://port70.net/~nsz/c/c11/n1570.html#6.4.4

[Bug c/84764] Wrong warning "so large that it is unsigned" for __int128 constant

2018-03-08 Thread pascal_cuoq at hotmail dot com
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=84764

--- Comment #1 from Pascal Cuoq  ---
I meant "the warning implies that the constant is typed as unsigned long
long...".

[Bug c/82340] New: volatile ignored in compound literal

2017-09-27 Thread pascal_cuoq at hotmail dot com
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=82340

Bug ID: 82340
   Summary: volatile ignored in compound literal
   Product: gcc
   Version: 8.0
Status: UNCONFIRMED
  Severity: normal
  Priority: P3
 Component: c
  Assignee: unassigned at gcc dot gnu.org
  Reporter: pascal_cuoq at hotmail dot com
  Target Milestone: ---

Consider the function f below:

int f(void) {
  volatile char *p = (volatile char[1]){1};
  for (int i=1; i<10; i++) *p=4;
  return *p;
}

Volatile access is a visible side-effect, so one may expect the generated code
for the function f to do “something” nine times, for some definition of
“something”.

In GCC 7.2 and in gcc.godbolt.org's current snapshot of “gcc (trunk)”, the
function f is compiled to:

f:
movl$4, %eax
ret

Command: gcc -O3 -std=c11 -xc -pedantic -S t.c
Link: https://godbolt.org/g/4Ua1Ud

I would expect function f to be compiled to something that ressembles the code
produced for function g, or the code produced by Clang for f:

int g(void) {
  volatile char t[1] = {1};
  volatile char *p = t;
  for (int i=1; i<10; i++) *p=4;
  return *p;
}

g:
movb$1, -1(%rsp)
movb$4, -1(%rsp)
movb$4, -1(%rsp)
movb$4, -1(%rsp)
movb$4, -1(%rsp)
movb$4, -1(%rsp)
movb$4, -1(%rsp)
movb$4, -1(%rsp)
movb$4, -1(%rsp)
movb$4, -1(%rsp)
movsbl  -1(%rsp), %eax
ret

[Bug c/82340] volatile ignored in compound literal

2017-09-27 Thread pascal_cuoq at hotmail dot com
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=82340

--- Comment #2 from Pascal Cuoq  ---
Richard:

>  I don't see how a volatile compound literal could make any sense or how 
> you'd observe the side-effect of multiple stores to it

Well, I have the same question about volatile variables the address of which is
not taken. But this is off-topic for this bug report, in which the volatile's
object's address is taken.

> (IIRC compound literals are constant!?).

The C11 standard invites the programmer to use the const qualifier if they want
a constant compound literal, and gives an explicit example of a “modifiable”
non-const compound literal: https://port70.net/~nsz/c/c11/n1570.html#6.5.2.5p12

[Bug c/80409] New: Document that va_arg(ap, void*) can be used to consume any pointer argument

2017-04-12 Thread pascal_cuoq at hotmail dot com
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=80409

Bug ID: 80409
   Summary: Document that va_arg(ap, void*) can be used to consume
any pointer argument
   Product: gcc
   Version: unknown
Status: UNCONFIRMED
  Severity: normal
  Priority: P3
 Component: c
  Assignee: unassigned at gcc dot gnu.org
  Reporter: pascal_cuoq at hotmail dot com
  Target Milestone: ---

This bug report is vaguely related to
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=26542 but whereas that report asks
for removing a warning, here there is no warning and this is a request for it
to be documented that the idiom is legal in GCC.

The C11 standard allows to confuse void* and char* when consuming arguments
from a va_list, and only these types of pointers:

http://port70.net/~nsz/c/c11/n1570.html#7.16.1.1p2

As explained by Rich Felker as part of a discussion on musl's scanf
implementation, this makes it very inconvenient to implement POSIX's positional
specifiers for scanf. Clearly the intent of POSIX's “all the leading arguments,
from the first to the (N-1)th, are pointers” is to allow these arguments to be
consumed on the spot when %N$ is encountered:

http://www.openwall.com/lists/musl/2017/04/10/3

Since the open-source world divides the C compilation platform described by the
C standard into C compilers (Clang, GCC) and standard libraries (Glibc, musl,
...), with the implementation of varargs on the compiler side and the
implementation of scanf on the standard library side, it would make sense to
document that on target platforms where the representation of pointers is
uniform, the compilers allow va_arg(ap, void*) to consume any pointer argument.

[Bug c/80410] New: Improve merging of identical branches

2017-04-12 Thread pascal_cuoq at hotmail dot com
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=80410

Bug ID: 80410
   Summary: Improve merging of identical branches
   Product: gcc
   Version: 7.0.1
Status: UNCONFIRMED
  Severity: normal
  Priority: P3
 Component: c
  Assignee: unassigned at gcc dot gnu.org
  Reporter: pascal_cuoq at hotmail dot com
  Target Milestone: ---

Consider the following code:

  va_list ap;
  void *result;

  va_start(ap, ptr_type);

  switch (ptr_type) {
case 0: result = va_arg(ap, int*); break;
case 1: result = va_arg(ap, char*); break;
case 2: result = va_arg(ap, short*); break;
default: result = va_arg(ap, void*); break;
  }

  va_end(ap);

GCC correctly recognizes that the assembly code for the cases 0, 1, 2 is
identical, which is the difficult part (the source code for the branches is
different and cannot be merged by the programmer unless
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=80409 is resolved). At the time of
writing, the Compiler Explorer trunk version produces:

movq%rax, -56(%rsp)
je  .L15
cmpl$2, %edi
je  .L15
testl   %edi, %edi
je  .L16
.L15:
movq-56(%rsp), %rax
.L16:

(Compiler Explorer link: https://godbolt.org/g/0NvnSX )

It would be nice if GCC was able to omit all the conditional branches, since
they all lead to doing the same thing at the assembly level.

[Bug c/80409] Document that va_arg(ap, void*) can be used to consume any pointer argument

2017-04-12 Thread pascal_cuoq at hotmail dot com
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=80409

--- Comment #2 from Pascal Cuoq  ---
> it should work even with standard c

Quoting from 7.6.1.1:2

  … the behavior is undefined, except for the following cases:
  * …
  * one type is pointer to void and the other is a pointer to a character type.

Why would the standard say the above, if using void* with any pointer type
worked?

> for an example %p in printf takes a void* but nobody casts it to void* when 
> passing to printf

This does not correspond to my experience. The C programmers I know fall into
two categories:

- C programmers who do not cast printf %p arguments to void*, because it works.
These programmers also write “*(float*)&uint_variable = 1.0f;”, because it
works, and “if (int_variable + 1 < int_variable) printf ("overflow!");”,
because it works.

- C programmers who do cast printf %p arguments to void*.

The good ship “we shouldn't have to document this because it obviously should
work on normal architectures even if the C standard does not say so” sailed
some time in the late nineties.

[Bug c/96788] "integer constant is so large that it is unsigned" warning is incorrect

2020-11-19 Thread pascal_cuoq at hotmail dot com via Gcc-bugs
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=96788

Pascal Cuoq  changed:

   What|Removed |Added

 CC||pascal_cuoq at hotmail dot com

--- Comment #6 from Pascal Cuoq  ---
Joseph Myers wrote:
> The warnings are attempting to cover both the C90 
> case where a decimal constant too large for signed long can be unsigned 
> long, and the case of a constant too large for intmax_t.

In the case of the constant 1000, each of the two kind of
warnings, “ integer constant is so large that it is unsigned” and “this decimal
constant is unsigned only in ISO C90” can be misleading.

Consider the compilation unit:

int x;

void f(void) {
x = -1000 < 0;
}

1/ Misleading warning “this decimal constant is unsigned only in ISO C90”

Compiler Explorer link: https://gcc.godbolt.org/z/4Eze1f

Using GCC 10.2 targeting x86, the compilation options “-O -m32 -std=c89” make
GCC compile f as below, and emit the warning “this decimal constant is unsigned
only in ISO C90”

f:
movl$0, x
ret

Actually, changing the C dialect to C99 does not make the constant not
unsigned, since GCC emits the same assembly code for f (setting x to 0) with
“-O -m32 -std=c99”

2/ Misleading warning “integer constant is so large that it is unsigned”

Compiler Explorer link: https://gcc.godbolt.org/z/MGjn5G

Using GCC 10.2 targeting x86, the compilation options “-O -m64 -std=c99” make
GCC compile f as below, and emit the warning “integer constant is so large that
it is unsigned”.

f:
movl$1, x(%rip)
ret

The constant is not unsigned. If it were, the function f would not set x to 1.

[Bug c/97986] New: ICE in force_constant_size when applying va_arg to VLA type

2020-11-25 Thread pascal_cuoq at hotmail dot com via Gcc-bugs
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=97986

Bug ID: 97986
   Summary: ICE in force_constant_size when applying va_arg to VLA
type
   Product: gcc
   Version: 11.0
Status: UNCONFIRMED
  Severity: normal
  Priority: P3
 Component: c
  Assignee: unassigned at gcc dot gnu.org
  Reporter: pascal_cuoq at hotmail dot com
  Target Milestone: ---

This bug seems most similar to (but still different from)
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=59711 (in which a comment says
that it appears to have been fixed in GCC 6).

In GCC 10.2 and some earlier versions, compiling the following program
(Compiler Explorer link: https://gcc.godbolt.org/z/11ob5j ):

#include 

int sum(int n, ...)
{
va_list ap;
va_start(ap, n);
int *input = va_arg(ap, int[n]);
int rc = 0;
for (int i = 0; i < n; i++)
rc += input[i];
return rc;
}

Produces the following error message:

In file included from :1:
: In function 'sum':
:7:29: internal compiler error: in force_constant_size, at
gimplify.c:733
7 | int *input = va_arg(ap, int[n]);
  | ^~~
Please submit a full bug report,
with preprocessed source if appropriate.
See <https://gcc.gnu.org/bugs/> for instructions.
Compiler returned: 1

[Bug c/104607] New: Struct padding not initialized when all members are provided initializers

2022-02-19 Thread pascal_cuoq at hotmail dot com via Gcc-bugs
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=104607

Bug ID: 104607
   Summary: Struct padding not initialized when all members are
provided initializers
   Product: gcc
   Version: 12.0
Status: UNCONFIRMED
  Severity: normal
  Priority: P3
 Component: c
  Assignee: unassigned at gcc dot gnu.org
  Reporter: pascal_cuoq at hotmail dot com
  Target Milestone: ---

In the GCC versions available as 11.2 and as “trunk” (as of this writing) on
Compiler Explorer, the following C code is translated to the following X86-64
assembly, with options “-O2 -std=c17”

CE link: https://gcc.godbolt.org/z/4oeh6d7vY

void g(void*);

int f(void) {
  struct s { char c; long long m64;} s12 = {1,2}, s1 = {1};
  g(&s1);
  g(&s12);
}

f:
subq$40, %rsp
pxor%xmm0, %xmm0
leaq16(%rsp), %rdi
movaps  %xmm0, 16(%rsp)
movb$1, (%rsp)
movq$2, 8(%rsp)
movb$1, 16(%rsp)
callg
movq%rsp, %rdi
callg
addq$40, %rsp
ret

Please note that GCC initializes all of s1 with “movaps  %xmm0, 16(%rsp)” and
that initializing only s1.m64 to 0 in addition to initializing s1.c to 1 would
have resulted in fewer, shorter instructions.

However, s12 is not initialized this way, and indeed the padding of s12 is not
initialized at all.

The requirement to initialize padding is a change that was introduced between
C99 and C11. The relevant clauses are in C99:

https://port70.net/~nsz/c/c99/n1256.html#6.7.8p10

If an object that has automatic storage duration is not initialized explicitly,
its value is indeterminate. If an object that has static storage duration is
not initialized explicitly, then:

if it has pointer type, it is initialized to a null pointer;
if it has arithmetic type, it is initialized to (positive or unsigned) zero;
if it is an aggregate, every member is initialized (recursively) according to
these rules;
if it is a union, the first named member is initialized (recursively) according
to these rules.

https://port70.net/~nsz/c/c99/n1256.html#6.7.8p19

The initialization shall occur in initializer list order, each initializer
provided for a particular subobject overriding any previously listed
initializer for the same subobject;132) all subobjects that are not initialized
explicitly shall be initialized implicitly the same as objects that have static
storage duration.

In C11 the clause that was numbered 6.7.8:10 in C99 becomes 6.7.9:10 and the
text is changed as follows:

If an object that has automatic storage duration is not initialized explicitly,
its value is indeterminate. If an object that has static or thread storage
duration is not initialized explicitly, then:

if it has pointer type, it is initialized to a null pointer;
if it has arithmetic type, it is initialized to (positive or unsigned) zero;
if it is an aggregate, every member is initialized (recursively) according to
these rules, and any padding is initialized to zero bits;
if it is a union, the first named member is initialized (recursively) according
to these rules, and any padding is initialized to zero bits;

Now, I agree that it's possible to read the change in a way that only forces
the initialization of partially initialized structs. But can this have been the
intention of the standardization committee when they went to the trouble of
making an explicit change to C11? The concern was likely to address some
security issues with information leaks. If structs with initializers for every
members do not have their padding initialized, then security issues with
information leaks remain for structs with initializers for every members. Why
would the committee have fixed only half of the problem?

[Bug c/104607] Struct padding not initialized when all members are provided initializers

2022-02-19 Thread pascal_cuoq at hotmail dot com via Gcc-bugs
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=104607

--- Comment #2 from Pascal Cuoq  ---
Well that's a quick resolution to a bug report that contained that actual
phrase “and any padding is initialized to zero bits”, and this in a quote from
the C11 standard, but I guess one of us can't read then.

[Bug c/109956] New: GCC reserves 9 bytes for struct s { int a; char b; char t[]; } x = {1, 2, 3};

2023-05-24 Thread pascal_cuoq at hotmail dot com via Gcc-bugs
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=109956

Bug ID: 109956
   Summary: GCC reserves 9 bytes for struct s { int a; char b;
char t[]; } x = {1, 2, 3};
   Product: gcc
   Version: 14.0
Status: UNCONFIRMED
  Severity: normal
  Priority: P3
 Component: c
  Assignee: unassigned at gcc dot gnu.org
  Reporter: pascal_cuoq at hotmail dot com
  Target Milestone: ---

Static-lifetime variables of type “struct with FAM” (flexible array member)
with an initializer for the FAM are a GCC extension.

As of GCC 13.1 and Compiler Explorer “trunk”, targeting x86, the definition
“struct s { int a; char b; char t[]; } x = {1, 2, 3};” reserves 9 bytes for x,
and in fact, with various initializers, the trailing padding for variables of
type “struct s” is always 3, as if the size to reserve for the variable was
computed as “sizeof (struct s) + n * sizeof(element)”.

Input file:
struct s { int a; char b; char t[]; } x = {1, 2, 3};

Command:
gcc -S fam_init.c

Result (with Ubuntu 9.4.0-1ubuntu1~20.04.1 which exhibits the same behavior as
the recent versions on Compiler Explorer):
.align 8
.type   x, @object
.size   x, 9
x:
.long   1
.byte   2
.byte   3
.zero   3


Clang up to version 14 used to round up the size of the variable to a multiple
of the alignment of the struct, but even this is not necessary. It is only
necessary that the size reserved for a variable of type t is at least
“sizeof(t)” bytes, and also to reserve enough space for the initializer. Clang
15 and later uses the optimal formula:

max(sizeof (struct s), offsetof(struct s, t[n]))

Compiler Explorer link: https://gcc.godbolt.org/z/5W7h4KWT1

This ticket is to suggest that GCC uses the same optimal formula as Clang 15
and later.

[Bug c/109956] GCC reserves 9 bytes for struct s { int a; char b; char t[]; } x = {1, 2, 3};

2023-05-24 Thread pascal_cuoq at hotmail dot com via Gcc-bugs
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=109956

--- Comment #3 from Pascal Cuoq  ---
@Andrew Pinski

You don't even need to invoke the fact that this is an extension. GCC could
reserve 17 bytes for each variable i of type “int”, and as long as “sizeof i”
continued to evaluate to 4 (4 being the value of “sizeof(int)” for x86), no-one
would be able to claim that GCC is not generating “correct” assembly code.

This ticket is pointing out that the current behavior for initialized FAMs is
suboptimal for programs that rely on the GCC extension, just like it would be
suboptimal to reserve 17 bytes for each “int” variable for standard C programs
(and I would open a ticket for it if I noticed such a behavior).

It's not breaking anything and it may be inconvenient to change, and as a
ticket that does not affect correctness, it can be ignored indefinitely. It's
just a suggestion for smaller binaries that might also end up marginally faster
as a result.

@Martin Uecker

Considering how casually phrased the description of FAMs was in C99 and
remained in later standards (see https://stackoverflow.com/q/73497572/139746
for me trying to make sense of some of the relevant words), I doubt that the
standard has anything to say about the compiler extension being discussed. But
if you have convincing arguments, you could spend a few minutes filing a bug
against Clang to tell them that they are making the binaries they generate too
small and efficient.

[Bug c/109956] GCC reserves 9 bytes for struct s { int a; char b; char t[]; } x = {1, 2, 3};

2023-05-26 Thread pascal_cuoq at hotmail dot com via Gcc-bugs
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=109956

--- Comment #13 from Pascal Cuoq  ---
@Martin

I completely agree with comment 12, however about the last paragraph, I would
like to point out that for purposes of memcpy'ing to or from such a struct with
initialized FAM, it is enough to recommend that programmers use the simple
formula “offsetof(struct foo, t) + n * sizeof(char)” (or “offsetof(struct foo,
t[n])”. The part that is not copied is the part that they did not intend to use
when they chose the initializer of the FAM, and that they cannot portably use
because of the padding that may or may not exist for a different target
architecture.

So since:

First, GCC currently does not always reserve enough room to allow “memcpy(…, …,
sizeof(struct foo) + n * sizeof(char))”, and 

second, using the time-proven formula as argument of malloc technically does
not always allocate enough space to make it valid to access p->t[n-1] according
to the strict interpretation of the words “it behaves as if that member were
replaced with the longest array (with the same element type) that would not
make the structure larger than the object being accessed”,

we might as well start recommending that C programmers use “offsetof(struct
foo, t) + n * sizeof(char)” as argument of memcpy, and either clarify the
meaning of the words “it behaves as if…” in the C standard or prepare for a
very unpleasant discussion when we have to tell them the formula they have to
use as argument of malloc.

[Bug c/96788] "integer constant is so large that it is unsigned" warning is incorrect

2025-03-11 Thread pascal_cuoq at hotmail dot com via Gcc-bugs
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=96788

--- Comment #11 from Pascal Cuoq  ---
@newbie-02

Sir, this is the GCC bugzilla.

You have to contact your national standardization institute so that they convey
your suggestions to ISO.

Incidentally, while it is subjective whether the individuals making up the
standardization committee are highly qualified, I can assure you that they are
not paid a cent to participate in the standardization of C.

[Bug c/120710] New: C23 enum member does not have during processing the type indicated by C23 6.7.3.4:12

2025-06-19 Thread pascal_cuoq at hotmail dot com via Gcc-bugs
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=120710

Bug ID: 120710
   Summary: C23 enum member does not have during processing the
type indicated by C23 6.7.3.4:12
   Product: gcc
   Version: 15.1.0
Status: UNCONFIRMED
  Severity: normal
  Priority: P3
 Component: c
  Assignee: unassigned at gcc dot gnu.org
  Reporter: pascal_cuoq at hotmail dot com
  Target Milestone: ---

Testcase:

#include 

enum e {
A = 0,
B = 0x8000,
C = 2
};

#define ty(e) _Generic(e, int:"int", unsigned:"unsigned", long:"long", unsigned
long:"unsigned long")

enum e1 {
G = 0,
H = -0x8001L,
I,
J = _Generic(I, int:147, long:1046)
};

int main(void) {
  printf ("A B C %s %s %s\n\n", ty(A), ty(B), ty(C));
  printf ("G H I J %s %s %s %s\n", ty(G), ty(H), ty(I), ty(J));
  printf("I %d", (int)J);
}

Compiled with GCC 15.1 for x86-64, the program outputs:

A B C unsigned unsigned unsigned

G H I J long long long long
I 147

Compiler Explorer link: https://gcc.godbolt.org/z/1dY7n7Kco

The surprising behavior is in the last output line that shows that I had type
int during the processing of enum e1. https://cigix.me/c23#6.7.3.4 says:

During the processing of each enumeration constant in the enumerator list, the
type of the enumeration constant shall be:
…
- the type of the value from the previous enumeration constant with one added
to it. If such an integer constant expression would overflow or wraparound the
value of the previous enumeration constant from the addition of one, [this is
not the case in the example above]

[Bug c/120710] C23 enum member does not have during processing the type indicated by C23 6.7.3.3:12

2025-06-19 Thread pascal_cuoq at hotmail dot com via Gcc-bugs
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=120710

Pascal Cuoq  changed:

   What|Removed |Added

Summary|C23 enum member does not|C23 enum member does not
   |have during processing the  |have during processing the
   |type indicated by C23   |type indicated by C23
   |6.7.3.4:12  |6.7.3.3:12

--- Comment #1 from Pascal Cuoq  ---
Sorry, the link to the relevant clause is https://cigix.me/c23#6.7.3.3.p12