On Wed, Nov 4, 2020 at 7:33 PM Uros Bizjak via Gcc <gcc@gcc.gnu.org> wrote:
>
> Hello!
>
> I was looking at the recent linux patch series [1] where segment
> qualifiers (named address spaces) were introduced to handle percpu
> variables. In the patch [2], the author mentions that:
>
> --q--
> Unfortunately, gcc does not provide a way to remove segment
> qualifiers, which is needed to use typeof() to create local instances
> of the per-cpu variable. For this reason, do not use the segment
> qualifier for per-cpu variables, and do casting using the segment
> qualifier instead.
> --/q--
>
> The core of the problem can be seen with the following testcase:
>
> --cut here--
> #define foo(_var)                    \
>   ({                            \
>     typeof(_var) tmp__;                    \

Looks like writing

    typeof((typeof(_var))0) tmp__;

makes it work.  Assumes there's a literal zero for the type of course.
Basically I try to get at a rvalue for the typeof.

Is there a way to query the address space of an object so I can
put another variable in the same address space?

>     asm ("mov %1, %0" : "=r"(tmp__) : "m"(_var));    \
>     tmp__;                        \
>   })
>
> __seg_fs int x;
>
> int test (void)
> {
>   int y;
>
>   y = foo (x);
>   return y;
> }
> --cut here--
>
> when compiled with -O2 for x86 target, the compiler reports:
>
> pcpu.c: In function ‘test’:
> pcpu.c:14:3: error: ‘__seg_fs’ specified for auto variable ‘tmp__’
>
> It looks to me that the compiler should remove address space
> information when typeof is used, otherwise, there is no way to use
> typeof as intended in the above example.
>
> A related problem is exposed when we want to cast address from the
> named address space to a generic address space (e.g. to use it with
> LEA):
>
> --cut here--
> typedef __UINTPTR_TYPE__ uintptr_t;
>
> __seg_fs int x;
>
> uintptr_t test (void)
> {
>   uintptr_t *p = (uintptr_t *) &y;

   uintptr_t *p = (uintptr_t *)(uintptr_t) &y;

works around the warning.  I think the wording you cite
suggests (uintptr_t) &y here, not sure if there's a reliable
way to get the lea with just a uintptr_t operand though.

>   uintptr_t addr;
>
>   asm volatile ("lea %1, %0" : "=r"(addr) : "m"(*p));
>
>   return addr;
> }
> --cut here--
>
> The gcc documentation advises explicit casts:
>
> --q--
> This means that explicit casts are required to convert pointers
> between these address spaces and the generic address space.  In
> practice the application should cast to 'uintptr_t' and apply the
> segment base offset that it installed previously.
> --/q--
>
> However, a warning is emitted when compiling the above example:
>
> pcpu1.c: In function ‘test’:
> pcpu1.c:7:18: warning: cast to generic address space pointer from
> disjoint __seg_fs address space pointer
>
> but the desired result is obtained nevertheless.
>
>        lea x(%rip), %rax
>
> As shown in the referred patchset, named address spaces have quite
> some optimization potential, please see [1] for the list.
>
> [1] https://www.mail-archive.com/linux-kernel@vger.kernel.org/msg2053461.html
> [2] https://www.mail-archive.com/linux-kernel@vger.kernel.org/msg2053462.html
>
> Uros.

Reply via email to