puzzling code in pcpu stuff
Christoph Mallon
christoph.mallon at gmx.de
Sun Aug 2 11:00:53 UTC 2009
Julian Elischer schrieb:
> I simplified the output of the preprocessor for a PCPU_SET(xx, newval)
> (to look at it).
>
> I came down to: (after formatting) for i386..
> {
> __typeof(((struct pcpu *)0)->pc_xx) __val;
> struct __s
> {
> u_char __b[(((sizeof(__val)) < (4)) ?
> (sizeof(__val)) : (4))];
> } __s;
>
> __val = (newval); /* aligned */
>
> if (sizeof(__val) == 1
> || sizeof(__val) == 2
> || sizeof(__val) == 4) {
> __s = *(struct __s *)(void *)&__val;
> __asm volatile("mov %1,%%fs:%0" : "=m"
> (*(struct __s *)(__builtin_offsetof(
> struct pcpu, pc_xx))) : "r" (__s));
> } else {
> *__extension__ (
> {
> __typeof(__val) *__p;
> __asm volatile("movl %%fs:%1,%0;
> addl %2,%0" : "=r" (__p) : "m"
> (*(struct pcpu *)(__builtin_offsetof(struct pcpu, pc_prvspace))),
> "i"
> (__builtin_offsetof(struct pcpu, pc_xx)));
> __p;
> }) = __val;
> }
> }
>
> having had my brain explode on this several times,
> I can't figure out exactly what teh clause after the else is doing.
>
> anyone better at reading __asm better than me care to explain it in
> simple words?
First, ({}) is a statement expression - a GCC extension (not to be
confused with expression statement, which is an expression followed by a
semicolon). It wraps a compound statement, i.e. {}, and turns it into an
expression. The value of the last statement is the value of the
expression. In this case it's __p;.
The per-cpu information can be accessed in two ways: Either by accessing
it in the %fs segment (the then clause does it) or reading its address
from %fs:pc_prvspace and then accessing it in the normal (i.e. %ds)
segment (the else clause does this).
Let's have a closer look at the else clause: The asm reads the pointer
to per-cpu information into __p and the statement expression returns it.
This pointer gets dereferenced (mind the * before __extension__ -
__extension__ does nothing, it just marks that the following is a GCC
extension) and __val is assigned.
This else clause is for assignment for things which are not 1, 2 or 4
bytes in size. For sizes 1, 2 and 4 better code can be generated for by
not first getting the pointer, but directly assigning the value into the
%fs mappinf of the per-cpu info.
Regards
Christoph
More information about the freebsd-current
mailing list