A new builtin: __builtin_stack_pointer()

One of the issues the LLVMLinux project is having is with the use of
named registers in the Linux kernel code. The kernel uses something like
this in order to assign a C variable name to a register (one for each
kernel arch).

    register unsigned long current_stack_pointer asm("esp");

clang doesn't allow this kind of thing which required a patch which less
efficient:

#define current_stack_pointer ({ \
       unsigned long esp; \
       asm("mov %%esp, %0" : "=r"(esp)); \
       esp; \
})

This works for both gcc and clang, but often adds in 3 extra
instructions since you need to copy the stack pointer to another
register, but first that register needs to be saved to the stack and
then restored after the stackpointer has been used; inefficient.

Another way would be to introduce a new builtin in parallel to others
like __builtin_return_address(). Essentially adding a
__builtin_stack_pointer() which does what the above code does. The idea
would be to get something like this added to both clang and gcc in order
to make this work across compilers, and across arches.

It ends up being a trivial patch for clang (see below). We're still
looking for someone to help us on the gcc side.

The goal is to ideally make the kernel code work equally well with both
compilers (clang and gcc).

Thoughts?

Thanks to Mark Charlebois for writing the patch below.

Behan

#define current_stack_pointer ({ \
  register unsigned long esp asm("esp"); \
  asm("" : "=r"(esp)); \
  esp; \
    })

/jakob

That seems to work! Though I'm still testing it in all our situations
for LLVMLinux. It looks like I can get this to work with LLVM 3.3 and
the LLVMLinux kernel patches. Thanks!

However, I'd still like to see __builtin_stack_pointer() added since it
is simple, obvious, and mirrors other builtins like
__builtin_frame_address().

Behan

One of the issues the LLVMLinux project is having is with the use of
named registers in the Linux kernel code. The kernel uses something like
this in order to assign a C variable name to a register (one for each
kernel arch).

   register unsigned long current_stack_pointer asm("esp");

clang doesn't allow this kind of thing which required a patch which less
efficient:

#define current_stack_pointer ({ \
      unsigned long esp; \
      asm("mov %%esp, %0" : "=r"(esp)); \
      esp; \
})

This works for both gcc and clang, but often adds in 3 extra
instructions since you need to copy the stack pointer to another
register, but first that register needs to be saved to the stack and
then restored after the stackpointer has been used; inefficient.

#define current_stack_pointer ({ \
  register unsigned long esp asm("esp"); \
  asm("" : "=r"(esp)); \
  esp; \
    })

/jakob

That seems to work! Though I'm still testing it in all our situations
for LLVMLinux. It looks like I can get this to work with LLVM 3.3 and
the LLVMLinux kernel patches. Thanks!

However, I'd still like to see __builtin_stack_pointer() added since it
is simple, obvious, and mirrors other builtins like
__builtin_frame_address().

Ping on this?

It seems like a legitimate builtin to have in clang, if only for
compatibility and the nicer IR representation.

Alp.

One of the issues the LLVMLinux project is having is with the use of
named registers in the Linux kernel code. The kernel uses something like
this in order to assign a C variable name to a register (one for each
kernel arch).

   register unsigned long current_stack_pointer asm("esp");

clang doesn't allow this kind of thing which required a patch which less
efficient:

#define current_stack_pointer ({ \
      unsigned long esp; \
      asm("mov %%esp, %0" : "=r"(esp)); \
      esp; \
})

This works for both gcc and clang, but often adds in 3 extra
instructions since you need to copy the stack pointer to another
register, but first that register needs to be saved to the stack and
then restored after the stackpointer has been used; inefficient.

#define current_stack_pointer ({ \
  register unsigned long esp asm("esp"); \
  asm("" : "=r"(esp)); \
  esp; \
    })

/jakob

That seems to work! Though I'm still testing it in all our situations
for LLVMLinux. It looks like I can get this to work with LLVM 3.3 and
the LLVMLinux kernel patches. Thanks!

However, I'd still like to see __builtin_stack_pointer() added since it
is simple, obvious, and mirrors other builtins like
__builtin_frame_address().

Ping on this?

Sorry. Been away from my desk for 2 weeks (Linux Con, Embedded Linux
Con, and a week teaching). Just catching up this week.

The suggested work around DOES work for many situations, but is ugly.
However it allows the LLVMLinux patches to work with clang/LLVM 3.3
right now which is important. But I'd love something better for LLVM 3.4

It seems like a legitimate builtin to have in clang, if only for
compatibility and the nicer IR representation.

Personally, I'd still like to see __builtin_stack_pointer() added to
clang/LLVM (and gcc too for that matter, but that's still a work in
progress). It would be very useful for our efforts in getting generic
code to work in the Linux kernel.

Thanks,

Behan

What is the desired behavior in the face of inlining?

Joerg

And #ifdef it for each arch? Builtin would be much more handy.

Actually no #ifdef is required with Jakob's suggestion (works the same
in both clang and gcc).

However the builtin is indeed nicer, easier to read and much more in
keeping with the other builtins...

Behan

11.10.2013, 01:39, “Jakob Stoklund Olesen” <stoklund@2pi.dk>:

One of the issues the LLVMLinux project is having is with the use of
named registers in the Linux kernel code. The kernel uses something like
this in order to assign a C variable name to a register (one for each
kernel arch).

register unsigned long current_stack_pointer asm(“esp”);

clang doesn’t allow this kind of thing which required a patch which less
efficient:

#define current_stack_pointer ({
unsigned long esp;
asm(“mov %%esp, %0” : “=r”(esp));
esp;
})

This works for both gcc and clang, but often adds in 3 extra
instructions since you need to copy the stack pointer to another
register, but first that register needs to be saved to the stack and
then restored after the stackpointer has been used; inefficient.

#define current_stack_pointer ({
register unsigned long esp asm(“esp”);
asm("" : “=r”(esp));
esp;
})

And #ifdef it for each arch? Builtin would be much more handy.

Actually no #ifdef is required with Jakob’s suggestion (works the same
in both clang and gcc).

It may works for both GCC and clang, it does not means it will works with every arch linux supports (ARM, PPC, AArch, …)

True enough. Which is indeed another argument for __builtin_stack_pointer(). That point is precisely one of the reasons that we’re pushing for this addition. Behan

Hi Behan,

Only saw this thread now. I think having the built-in makes sense, but you sent the description and patch to the LLVM list, not the Clang list. :wink:

I’d copy the cfe-dev, but I think now the thread is more complex than cross-posting would allow. So, maybe it’d be better if you posted there again, your original email, the patch and some of the comments on this thread.

cheers,
–renato