Live data from Hacker News

Inline assembly in Linux

github.com

31–36 of 36 posts

Re: Inline assembly in Linux

#31
post #29

Earlier quoted context omitted.

Yes, that is really a better solution: to write the whole function in assembly. "volatile" is just a poor substitute for that.

Other than the "code smell", what do you see as the main dangers of using "__asm volatile" rather than just "__asm"? Assuming that there are cases where I do get significantly better performance from specifying the exact ordering of instructions, what can I do to minimize these dangers while keeping the better performance?

The first danger is that "asm volatile" is basically a hack to get the output you want from the compiler. But the compiler is a rather complicated piece of software, and there is no guarantee that future versions of the compiler will still give you the desired output. Perhaps it works correctly now, but if you change your optimization settings are you sure that something unexpected won't happen? Remember that "asm volatile" can still be moved around. From the GCC manual[1]:

> Do not expect a sequence of asm statements to remain perfectly consecutive after compilation, even when you are using the volatile qualifier. If certain instructions need to remain consecutive in the output, put them in a single multi-instruction asm statement.

The second danger is that "asm volatile" hides incorrect operand specification. If you examine the assembly, you might get the wrong assembly, and adding "volatile" might fix it. However, the incorrect operand specification might cause problems in other parts of the code. These are harder to diagnose. Stack Overflow is littered with questions by people who specify asm operands wrong, add "volatile" to fix the assembly, but other things are still broken. My general procedure is to work with asm blocks at -O2 or higher without using volatile, and make sure I'm getting the desired results that way (unless I'm writing some synchronization primitives).

Yet it is just so damn easy to write larger, multi-statement asm blocks. With larger blocks, the intent of the programmer is clear. It becomes obvious to both the reader and to the compiler that the assembly should be emitted as-is, rather than moved or reordered.

Finally, you can often get the results you want with the auto-vectorizer, restrict, and __builtin_assume_aligned. Whenever that is possible I'd prefer it.

[1]: https://gcc.gnu.org/onlinedocs/gcc/Extended-Asm.html

Re: Inline assembly in Linux

#32
post #30

GCC inline assembly is one of the most terrible things I've ever had to work with. Somebody seriously need to redesign it or replace it. Aside from that,a decent reference manual for the existing version would be welcome.

I'm working on a new language that has inline assembly and I pretty much just copied GCC's syntax[1]. Do you have any specific suggestions on how to do better?

[1]: https://github.com/andrewrk/zig/blob/master/std/linux_x86_64...

Re: Inline assembly in Linux

#33

Earlier quoted context omitted.

> if your stack looks like Lua -> C -> Lua, then it won't work. I don't think you can safely solve this in the general case. There is a key problem I don't think you can work around. Say your stack looks like C(1) -> Lua -> C -> Lua. The outermost C frames might not know anything about Lua (they just use some library that uses Lua as a library). Say you try to take a snapshot of this stack to create a continuation. Y…

But what if C(1) and C(2) are not exactly the same size? Say you want to resume continuation K, which has a stack of some size N. The current thread has a stack of size M. If M >= N, everything is fine: you can safely overwrite the current stack with K's stack. If M = N. You could try to snapshot the entire C stack to get around this, including the outermost C frames. Indeed! This is a solution. It wouldn't be accept…

What about references to resources not on the stack? Heap pointers, file descriptors?

Re: Inline assembly in Linux

#34

Earlier quoted context omitted.

If you restore the entire C stack to resume the Lua continuation, it will reset the loop in main() to i=0! That's the point of continuations, though. That's a feature, not a bug. When you create a continuation, you're saying "whatever happens after this, allow me to do it again at some later time." If the calling library happened to be in a loop, then the goal is to serialize that loop so that it can be invoked again…

> That's the point of continuations, though. That's a feature, not a bug. If that's what you're after, then by all means implement that. :) But I think most people would expect the Lua interpreter state to be self-contained, and not to affect the state of the surrounding C execution environment.

The lua library can already affect the surrounding C state (either through FFI with LuaJIT, or having a lua function call back into C code), so I don't see that as a real argument.

Unless you are allowing arbitrary code execution, you are likely the one passing in scripts to the interpreter - these sorts of interactions should be well documented by the lua scripts themselves...and I don't recommend allowing arbitrary lua anyhow - os.syscall and friends say hi - need to block access to those carefully. Thus, we have two situations - either you know and trust the code not to do unexpected things (or to do them in an expected manner :) ), or you've set up your lua environment in such a way to disallow such calls, and it doesn't matter.

Re: Inline assembly in Linux

#35
post #4

I've been using a lot of inline assembly lately, and while the Stockholm syndrome might be in effect, I'm coming to like the GCC syntax. For me, main thing that has helped has been to adopt a consistent syntax. Here's some examples of what I'm currently using for an AVX2 popcnt optimization, with some explanation. #define ASM_VEC_BYTE_COUNT_SET(vec, sum, mask, shuf) \ __asm volatile ("vpsrld $4, %[VEC], %[SUM]\n" \ "…

I never liked them.

The asm {} blocks of PC compilers are so much developer friendly.

I rather use an external Assembler than GCC's inline syntax.

Re: Inline assembly in Linux

#36

Is it ever the case that inline assembly is required over separate object sources just in assembly? I would have thought it would be preferred to not use inline assembly, and simply link in object files of what you need. It would seem simpler syntax-wise, too. Why prefer inline assembly?

One reason is that you just want to call a single instruction, and the overhead of making a function call to another file would be too much. Picking an example from the Linux kernel pretty much at random:

    #define mb()    asm volatile("mfence":::"memory")
    #define rmb()   asm volatile("lfence":::"memory")
    #define wmb()   asm volatile("sfence" ::: "memory")
Those are memory barriers, so they essentially must be inline (they'd be too slow and possibly even change their meaning if they were located in a separate source file and you had to call them).
Post reply on HN