Opened 6 days ago
#316 new defect
Const initialization from computation is ignored within same compile unit
| Reported by: | mlbrooks | Owned by: | |
|---|---|---|---|
| Priority: | major | Component: | cfa-cc |
| Version: | 1.0 | Keywords: | const init compunit |
| Cc: |
Description
CFA allows a constant to have a nontrivial expression as its initializer (like C++), though C does not. Current lowering works for access between compile units, but fails within one compile unit, leaving the value 0 in place of the correct one.
// $ cfa -c -DSPLIT_CU=1 demo.cfa -o demo.1.o
// $ cfa -c -DSPLIT_CU=2 demo.cfa -o demo.2.o
// $ cfa demo.1.o demo.2.o
// $ ./a.out
#if SPLIT_CU == 1
const unsigned int x = 25;
const unsigned int y = 5 * 5;
void in_cu() {
printf( "in-compunit access: %u %u\n", x, y );
}
#elif SPLIT_CU == 2
extern const unsigned int x;
extern const unsigned int y;
extern void in_cu();
void cross_cu() {
printf( "cross-compunit access: %u %u\n", x, y );
}
int main() {
in_cu();
cross_cu();
}
#else
#error Bad SPLIT_CU value
#endif
Expected:
in-compunit access: 25 25 cross-compunit access: 25 25
Actual:
in-compunit access: 25 0 cross-compunit access: 25 25
We understand the reason is the CU-1 lowering produces
const unsigned int x = 25; const unsigned int y;
along with startup-time code to initialize y. There, C semantics say, "y is defined to be 'constexpr' with value 0." So, at the usage (in_cu's print), GCC does not emit loads for (x and) y. Rather, it uses the statically "known" values. This effect occurs even at -O0. As a result, even though the initialization code correctly writes the evaluation of of 5 * 5 into the location of y (via const cast, before main runs), in_cu never reads it.
We believe our current lowering "of constants as constants" is fundamentally incorrect, due to the above phenomenon. Rather, when lowering a constant that requires (early) runtime initialization, it should be lowered as a mutable global variable.