register caching of static variables

J

jacob navia

As far as I understood the standard, non-automatic variables
(static/global data) can't be cached in registers because in a
multiprocessing or multi-threading environment, another
thread/processor could read a wrong value from main
memory, if the compiler would do so

Even if the variable has local scope (static variable enclosed
in a function scope) this would still hold since another
processor/thread could run the same code at the same time
and read a wrong value from memory when the variable
lives in a register.

At each sequence point the compiler is supposed to present a
coherent view of memory, with all assignments stored into
main memory.

The standard says:

" At certain specified points in the execution sequence called
sequence points, all side effects of previous evaluations shall
be complete and no side effects of subsequent evaluations
shall have taken place."

This can be guaranteed in a multi-processing/multi-threaded
environment only for automatic variables, not globals
or static variables.

Is this reasoning correct?

jacob
 
I

Ian Woods

As far as I understood the standard, non-automatic variables
(static/global data) can't be cached in registers because in a
multiprocessing or multi-threading environment, another
thread/processor could read a wrong value from main
memory, if the compiler would do so
Even if the variable has local scope (static variable enclosed
in a function scope) this would still hold since another
processor/thread could run the same code at the same time
and read a wrong value from memory when the variable
lives in a register.

At each sequence point the compiler is supposed to present a
coherent view of memory, with all assignments stored into
main memory.

The standard says:

" At certain specified points in the execution sequence called
sequence points, all side effects of previous evaluations shall
be complete and no side effects of subsequent evaluations
shall have taken place."

This can be guaranteed in a multi-processing/multi-threaded
environment only for automatic variables, not globals
or static variables.

Is this reasoning correct?

jacob

As far as the C standard is concerned, threads don't exist. AFAIK, a C
compiler can, if it chooses, hold static and/or global data in registers.
Only objects which are of type volatile sig_atomic_t are guarenteed to
have a nice state during an interupt in execution (i.e. signal handlers).
There's no other mechanism for 'interrupting' the execution of a C
program in the C standard AFAIK.

Individual implementations might make some guarentees about the behaviour
of different kinds of objects wrt threads, but they're extensions and not
part of C itself.

Ian Woods
 
D

Derk Gwen

# As far as I understood the standard, non-automatic variables
# (static/global data) can't be cached in registers because in a
# multiprocessing or multi-threading environment, another
# thread/processor could read a wrong value from main
# memory, if the compiler would do so
#
# Even if the variable has local scope (static variable enclosed
# in a function scope) this would still hold since another
# processor/thread could run the same code at the same time
# and read a wrong value from memory when the variable
# lives in a register.
#
# At each sequence point the compiler is supposed to present a
# coherent view of memory, with all assignments stored into
# main memory.
#
# The standard says:
#
# " At certain specified points in the execution sequence called
# sequence points, all side effects of previous evaluations shall
# be complete and no side effects of subsequent evaluations
# shall have taken place."

That has to do with all aliases in one process referring to the same result.
If you don't take the address of the variable, you don't have aliasses.

# This can be guaranteed in a multi-processing/multi-threaded
# environment only for automatic variables, not globals
# or static variables.

That's what volatile is for: noting variables that can be changed by
something outside the current process.
 
J

jacob navia

Ian Woods said:
reader5.wanadoo.fr:

As far as the C standard is concerned, threads don't exist. AFAIK, a C
compiler can, if it chooses, hold static and/or global data in registers.
Only objects which are of type volatile sig_atomic_t are guarenteed to
have a nice state during an interupt in execution (i.e. signal handlers).
There's no other mechanism for 'interrupting' the execution of a C
program in the C standard AFAIK.

Individual implementations might make some guarentees about the behaviour
of different kinds of objects wrt threads, but they're extensions and not
part of C itself.

Ian Woods

Consider:
static int a;
int fn(void)
{
a = a+1;
// sequence point <S> here
return a;
}

The compiler is supposed to have done the assignment when
the sequence point <S> is reached. If the variable is cached
in a register that is not the case.

The storage class of the variable has been changed from static to
register.

Note that I dropped any references to threads here.
 
C

Chris Torek

Consider:
static int a;
int fn(void)
{
a = a+1;
// sequence point <S> here
return a;
}

The compiler is supposed to have done the assignment when
the sequence point <S> is reached. If the variable is cached
in a register that is not the case.

Here the variable "a" has file scope and internal linkage. A
C compiler would be allowed to rewrite the code as:

int fn(void) {
static int a;
register int temp = a;
... do all the work in temp ...
a = temp;
return a;
}

*if* it can prove that no other code in this translation unit
refers to this same object "a".

(The original code in fn() is short and simple enough that this
transformation would likely gain nothing as is, but if the code
were more complex than just "a = a + 1" it might be worthwhile.
Similar arguments apply if the code in fn() is hoisted into its
callers -- but note that fn() itself has file scope and external
linkage, so unless compilation is done at link time, there must
be a "vanilla version" accompanying the inline expanded versions.)

If fn() calls other functions which might drop back into "this
translation unit" and refer to the same "a", then the register
caching can *still* occur provided the cached value is stored
back into "memory" before and after those points. The variable
"a" may need to move back to file scope (from the block scope I
gave it above). If "a"'s address is never taken (or if the CPU
provides &cpuregister in hardware, as a few do) it would be
legal to use a "global CPU register" for the variable "a".

The "Big Hammer spelled volatile" is the way to tell a compiler
"please do not make provably-correct-according-to-the-Standard
optimizations", as one might need for multi-threaded code here. :)
Most compilers simply do not bother attempting to optimize in these
cases, though, as the list of exceptions to "allowed register
shadowing" gets complicated quickly, and in most cases I suspect
there is not much benefit.
 
H

Hallvard B Furuseth

jacob said:
As far as I understood the standard, non-automatic variables
(static/global data) can't be cached in registers

Correct, because...
because in a
multiprocessing or multi-threading environment, another
thread/processor could read a wrong value from main
memory, if the compiler would do so

Correct if you replace threads with signals.
Consider:
static int a;
int fn(void)
{
a = a+1;
// sequence point <S> here
return a;
}

The compiler is supposed to have done the assignment when
the sequence point <S> is reached. If the variable is cached
in a register that is not the case.

This is not correct. The implementation is required to act _as if_
variable updates happened at each sequence point, but only I/O and
volatile variables are required to actually be updated at those times.
If the compiler can prove that `a' will not be accessed during the
execution of some code, it need not ensure that `a' has the correct
value while that code is executing.

However, since the compiler would have to analyze the entire program to
check that no signal handlers are installed (or threads, if the compiler
is aware of threading), you are mostly right in practice. I doubt many
compilers do so. Maybe some compilers support pragmas to inform the
compiler that no thread/signal handler will do that to a particular set
of variables or in a particular translation unit, but I don't know if
you consider such extensions relevant to your question or not.
The storage class of the variable has been changed from static to
register.

No, it hasn't. The static/register storage classes are features of
variables in the abstract machine. The actual program only need to
behave _as if_ it executed the abstract machine.
 
C

Christian Bau

"jacob navia said:
As far as I understood the standard, non-automatic variables
(static/global data) can't be cached in registers because in a
multiprocessing or multi-threading environment, another
thread/processor could read a wrong value from main
memory, if the compiler would do so

Even if the variable has local scope (static variable enclosed
in a function scope) this would still hold since another
processor/thread could run the same code at the same time
and read a wrong value from memory when the variable
lives in a register.

At each sequence point the compiler is supposed to present a
coherent view of memory, with all assignments stored into
main memory.

The standard says:

" At certain specified points in the execution sequence called
sequence points, all side effects of previous evaluations shall
be complete and no side effects of subsequent evaluations
shall have taken place."

This can be guaranteed in a multi-processing/multi-threaded
environment only for automatic variables, not globals
or static variables.

The C Standard doesn't mention threads at all, so whatever a second
thread does lies outside the scope of the C Standard. So if a second
thread modifies a non-volatile static variable that my code accesses,
that's outside the C Standard already.

If you are interested, you might take a look at the Java Language and
Java Virtual Machine specifications, where this kind of stuff is
handled.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,769
Messages
2,569,580
Members
45,055
Latest member
SlimSparkKetoACVReview

Latest Threads

Top