Commit 6f49c66e by Hans-Peter Nilsson

PR94600: fix volatile access to the whole of a compound object.

The store to the whole of each volatile object was picked apart
like there had been an individual assignment to each of the
fields.  Reads were added as part of that; see PR for details.
The reads from volatile memory were a clear bug; individual
stores questionable.  A separate patch clarifies the docs.

gcc:

2020-07-09  Richard Biener  <rguenther@suse.de>

	PR middle-end/94600
	* expr.c (expand_constructor): Make a temporary also if we're
	storing to volatile memory.

gcc/testsuite:

2020-07-09  Hans-Peter Nilsson  <hp@axis.com>

	PR middle-end/94600
	* gcc.dg/pr94600-1.c, gcc.dg/pr94600-2.c, gcc.dg/pr94600-3.c,
	gcc.dg/pr94600-4.c, gcc.dg/pr94600-5.c, gcc.dg/pr94600-6.c,
	gcc.dg/pr94600-7.c, gcc.dg/pr94600-8.c: New tests.

(cherry picked from commit a4aca1edaf37d43b2b7e9111825837a7a317b1b0)
parent afe0d1fa
......@@ -8268,7 +8268,10 @@ expand_constructor (tree exp, rtx target, enum expand_modifier modifier,
/* Handle calls that pass values in multiple non-contiguous
locations. The Irix 6 ABI has examples of this. */
if (target == 0 || ! safe_from_p (target, exp, 1)
|| GET_CODE (target) == PARALLEL || modifier == EXPAND_STACK_PARM)
|| GET_CODE (target) == PARALLEL || modifier == EXPAND_STACK_PARM
/* Also make a temporary if the store is to volatile memory, to
avoid individual accesses to aggregate members. */
|| (GET_CODE (target) == MEM && MEM_VOLATILE_P (target)))
{
if (avoid_temp_mem)
return NULL_RTX;
......
/* { dg-do compile } */
/* { dg-require-effective-target size32plus } */
/* { dg-options "-fdump-rtl-final -O2" } */
/* Assignments to a whole struct of suitable size (32 bytes) must not be
picked apart into field accesses. */
typedef struct {
unsigned int f0 : 4;
unsigned int f1 : 11;
unsigned int f2 : 10;
unsigned int f3 : 7;
} t0;
static t0 a0[] = {
{ .f0 = 7, .f1 = 99, .f3 = 1, },
{ .f0 = 7, .f1 = 251, .f3 = 1, },
{ .f0 = 8, .f1 = 127, .f3 = 5, },
{ .f0 = 5, .f1 = 1, .f3 = 1, },
{ .f0 = 5, .f1 = 1, .f3 = 1, },
{ .f0 = 5, .f1 = 1, .f3 = 1, },
};
void
foo(void)
{
__SIZE_TYPE__ i;
__SIZE_TYPE__ base = 0x000a0000;
for (i = 0; i < (sizeof (a0) / sizeof ((a0)[0])); i++) {
*(volatile t0 *) (base + 44 + i * 4) = a0[i];
}
}
/* The only volatile accesses should be the obvious writes. */
/* { dg-final { scan-rtl-dump-times {\(mem/v} 6 "final" } } */
/* { dg-final { scan-rtl-dump-times {\(set \(mem/v} 6 "final" } } */
/* { dg-do compile } */
/* { dg-require-effective-target size32plus } */
/* { dg-options "-fdump-rtl-final -O2" } */
/* Unrolled version of pr94600-1.c. */
typedef struct {
unsigned int f0 : 4;
unsigned int f1 : 11;
unsigned int f2 : 10;
unsigned int f3 : 7;
} t0;
void
bar(void)
{
t0 a00 = { .f0 = 7, .f1 = 99, .f3 = 1, };
t0 a01 = { .f0 = 7, .f1 = 251, .f3 = 1, };
t0 a02 = { .f0 = 8, .f1 = 127, .f3 = 5, };
t0 a03 = { .f0 = 5, .f1 = 1, .f3 = 1, };
t0 a04 = { .f0 = 5, .f1 = 1, .f3 = 1, };
t0 a05 = { .f0 = 5, .f1 = 1, .f3 = 1, };
__SIZE_TYPE__ base = 0x000a0000;
*(volatile t0 *) ((base) + 44 + (0) * 4) = a00;
*(volatile t0 *) ((base) + 44 + (1) * 4) = a01;
*(volatile t0 *) ((base) + 44 + (2) * 4) = a02;
*(volatile t0 *) ((base) + 44 + (3) * 4) = a03;
*(volatile t0 *) ((base) + 44 + (4) * 4) = a04;
*(volatile t0 *) ((base) + 44 + (5) * 4) = a05;
}
/* { dg-final { scan-rtl-dump-times {\(mem/v} 6 "final" } } */
/* { dg-final { scan-rtl-dump-times {\(set \(mem/v} 6 "final" } } */
/* { dg-do compile } */
/* { dg-require-effective-target size32plus } */
/* { dg-options "-fdump-rtl-final -O2 -fno-unroll-loops" } */
/* Same-address version of pr94600-1.c. */
typedef struct {
unsigned int f0 : 4;
unsigned int f1 : 11;
unsigned int f2 : 10;
unsigned int f3 : 7;
} t0;
static t0 a0[] = {
{ .f0 = 7, .f1 = 99, .f3 = 1, },
{ .f0 = 7, .f1 = 251, .f3 = 1, },
{ .f0 = 8, .f1 = 127, .f3 = 5, },
{ .f0 = 5, .f1 = 1, .f3 = 1, },
{ .f0 = 5, .f1 = 1, .f3 = 1, },
{ .f0 = 5, .f1 = 1, .f3 = 1, },
};
void
foo(void)
{
__SIZE_TYPE__ i;
__SIZE_TYPE__ base = 0x000a0000;
for (i = 0; i < (sizeof (a0) / sizeof ((a0)[0])); i++) {
*(volatile t0 *) (base + 44) = a0[i];
}
}
/* The loop isn't unrolled. */
/* { dg-final { scan-rtl-dump-times {\(mem/v} 1 "final" } } */
/* { dg-final { scan-rtl-dump-times {\(set \(mem/v} 1 "final" } } */
/* { dg-do compile } */
/* { dg-require-effective-target size32plus } */
/* { dg-options "-fdump-rtl-final -O2" } */
/* Unrolled version of pr94600-2.c. */
typedef struct {
unsigned int f0 : 4;
unsigned int f1 : 11;
unsigned int f2 : 10;
unsigned int f3 : 7;
} t0;
void
bar(void)
{
t0 a00 = { .f0 = 7, .f1 = 99, .f3 = 1, };
t0 a01 = { .f0 = 7, .f1 = 251, .f3 = 1, };
t0 a02 = { .f0 = 8, .f1 = 127, .f3 = 5, };
t0 a03 = { .f0 = 5, .f1 = 1, .f3 = 1, };
t0 a04 = { .f0 = 5, .f1 = 1, .f3 = 1, };
t0 a05 = { .f0 = 5, .f1 = 1, .f3 = 1, };
__SIZE_TYPE__ base = 0x000a0000;
*(volatile t0 *) ((base) + 44) = a00;
*(volatile t0 *) ((base) + 44) = a01;
*(volatile t0 *) ((base) + 44) = a02;
*(volatile t0 *) ((base) + 44) = a03;
*(volatile t0 *) ((base) + 44) = a04;
*(volatile t0 *) ((base) + 44) = a05;
}
/* { dg-final { scan-rtl-dump-times {\(mem/v} 6 "final" } } */
/* { dg-final { scan-rtl-dump-times {\(set \(mem/v} 6 "final" } } */
/* { dg-do compile } */
/* { dg-require-effective-target size32plus } */
/* { dg-options "-fdump-rtl-final -O2 -fno-unroll-loops" } */
/* Target-as-parameter version of pr94600-1.c. */
typedef struct {
unsigned int f0 : 4;
unsigned int f1 : 11;
unsigned int f2 : 10;
unsigned int f3 : 7;
} t0;
static t0 a0[] = {
{ .f0 = 7, .f1 = 99, .f3 = 1, },
{ .f0 = 7, .f1 = 251, .f3 = 1, },
{ .f0 = 8, .f1 = 127, .f3 = 5, },
{ .f0 = 5, .f1 = 1, .f3 = 1, },
{ .f0 = 5, .f1 = 1, .f3 = 1, },
{ .f0 = 5, .f1 = 1, .f3 = 1, },
};
void
foo(volatile t0 *b)
{
__SIZE_TYPE__ i;
for (i = 0; i < (sizeof (a0) / sizeof ((a0)[0])); i++) {
b[i+11] = a0[i];
}
}
/* The loop isn't unrolled. */
/* { dg-final { scan-rtl-dump-times {\(mem/v} 1 "final" } } */
/* { dg-final { scan-rtl-dump-times {\(set \(mem/v} 1 "final" } } */
/* { dg-do compile } */
/* { dg-require-effective-target size32plus } */
/* { dg-options "-fdump-rtl-final -O2" } */
/* Target-as-parameter version of pr94600-2.c. */
typedef struct {
unsigned int f0 : 4;
unsigned int f1 : 11;
unsigned int f2 : 10;
unsigned int f3 : 7;
} t0;
void
bar(volatile t0 *b)
{
t0 a00 = { .f0 = 7, .f1 = 99, .f3 = 1, };
t0 a01 = { .f0 = 7, .f1 = 251, .f3 = 1, };
t0 a02 = { .f0 = 8, .f1 = 127, .f3 = 5, };
t0 a03 = { .f0 = 5, .f1 = 1, .f3 = 1, };
t0 a04 = { .f0 = 5, .f1 = 1, .f3 = 1, };
t0 a05 = { .f0 = 5, .f1 = 1, .f3 = 1, };
b[11+0] = a00;
b[11+1] = a01;
b[11+2] = a02;
b[11+3] = a03;
b[11+4] = a04;
b[11+5] = a05;
}
/* { dg-final { scan-rtl-dump-times {\(mem/v} 6 "final" } } */
/* { dg-final { scan-rtl-dump-times {\(set \(mem/v} 6 "final" } } */
/* { dg-do compile } */
/* { dg-require-effective-target size32plus } */
/* { dg-options "-fdump-rtl-final -O2 -fno-unroll-loops" } */
/* Target-as-parameter version of pr94600-3.c. */
typedef struct {
unsigned int f0 : 4;
unsigned int f1 : 11;
unsigned int f2 : 10;
unsigned int f3 : 7;
} t0;
static t0 a0[] = {
{ .f0 = 7, .f1 = 99, .f3 = 1, },
{ .f0 = 7, .f1 = 251, .f3 = 1, },
{ .f0 = 8, .f1 = 127, .f3 = 5, },
{ .f0 = 5, .f1 = 1, .f3 = 1, },
{ .f0 = 5, .f1 = 1, .f3 = 1, },
{ .f0 = 5, .f1 = 1, .f3 = 1, },
};
void
foo(volatile t0 *b)
{
__SIZE_TYPE__ i;
for (i = 0; i < (sizeof (a0) / sizeof ((a0)[0])); i++) {
b[11] = a0[i];
}
}
/* { dg-final { scan-rtl-dump-times {\(mem/v} 1 "final" } } */
/* { dg-final { scan-rtl-dump-times {\(set \(mem/v} 1 "final" } } */
/* { dg-do compile } */
/* { dg-require-effective-target size32plus } */
/* { dg-options "-fdump-rtl-final -O2" } */
/* Unrolled version of pr94600-2.c. */
typedef struct {
unsigned int f0 : 4;
unsigned int f1 : 11;
unsigned int f2 : 10;
unsigned int f3 : 7;
} t0;
void
bar(volatile t0 *b)
{
t0 a00 = { .f0 = 7, .f1 = 99, .f3 = 1, };
t0 a01 = { .f0 = 7, .f1 = 251, .f3 = 1, };
t0 a02 = { .f0 = 8, .f1 = 127, .f3 = 5, };
t0 a03 = { .f0 = 5, .f1 = 1, .f3 = 1, };
t0 a04 = { .f0 = 5, .f1 = 1, .f3 = 1, };
t0 a05 = { .f0 = 5, .f1 = 1, .f3 = 1, };
b[11] = a00;
b[11] = a01;
b[11] = a02;
b[11] = a03;
b[11] = a04;
b[11] = a05;
}
/* { dg-final { scan-rtl-dump-times {\(mem/v} 6 "final" } } */
/* { dg-final { scan-rtl-dump-times {\(set \(mem/v} 6 "final" } } */
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment