Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is a C compiler allowed to coalesce sequential assignments to volatile variables?

I'm having a theoretical (non-deterministic, hard to test, never happened in practice) hardware issue reported by hardware vendor where double-word write to certain memory ranges may corrupt any future bus transfers.

While I don't have any double-word writes explicitly in C code, I'm worried the compiler is allowed (in current or future implementations) to coalesce multiple adjacent word assignments into a single double-word assignment.

The compiler is not allowed to reorder assignments of volatiles, but it is unclear (to me) whether coalescing counts as reordering. My gut says it is, but I've been corrected by language lawyers before!

Example:

typedef struct {    volatile unsigned reg0;    volatile unsigned reg1; } Module;  volatile Module* module = (volatile Module*)0xFF000000u;  // two word stores, or one double-word store? module->reg0 = 1; module->reg1 = 2; 

(I'll ask my compiler vendor about this separately, but I'm curious what the canonical/community interpretation of the standard is.)

like image 328
Andreas Avatar asked May 20 '21 07:05

Andreas


People also ask

How does compiler treat volatile?

The volatile keyword is intended to prevent the compiler from applying any optimizations on objects that can change in ways that cannot be determined by the compiler. Objects declared as volatile are omitted from optimization because their values can be changed by code outside the scope of current code at any time.

How does volatile affect code optimization by compiler?

Effect of the volatile keyword on compiler optimizationIf you do not use the volatile keyword where it is needed, then the compiler might optimize accesses to the variable and generate unintended code or remove intended functionality.

What happens when a variable is declared volatile in CSS?

C's volatile keyword is a qualifier that is applied to a variable when it is declared. It tells the compiler that the value of the variable may change at any time--without any action being taken by the code the compiler finds nearby.


1 Answers

No, the compiler is absolutely not allowed to optimize those two writes into a single double word write. It's kind of hard to quote the standard since the part regarding optimizations and side effects is so fuzzily written. The relevant parts are found in C17 5.1.2.3:

The semantic descriptions in this International Standard describe the behavior of an abstract machine in which issues of optimization are irrelevant.

Accessing a volatile object, modifying an object, modifying a file, or calling a function that does any of those operations are all side effects, which are changes in the state of the execution environment.

In the abstract machine, all expressions are evaluated as specified by the semantics. An actual implementation need not evaluate part of an expression if it can deduce that its value is not used and that no needed side effects are produced (including any caused by calling a function or accessing a volatile object).

Accesses to volatile objects are evaluated strictly according to the rules of the abstract machine.

When you access part of a struct, that in itself is a side-effect, which may have consequences that the compiler can't determine. Suppose for example that your struct is a hardware register map and those registers need to be written in a certain order. Like for example some microcontroller documentation could be along the lines of: "reg0 enables the hardware peripheral and must be written to before you can configure the details in reg1".

A compiler that would merge the volatile object writes into a single one would be non-conforming and plain broken.

like image 80
Lundin Avatar answered Oct 20 '22 23:10

Lundin