Rules to avoid common extended inline assembly mistakes

ingve | 58 points

> Because it’s so treacherous, the first rule is to avoid it if at all possible. Modern compilers are loaded with intrinsics and built-ins that replace nearly all the old inline assembly use cases.

If you take away anything from this article, it should be at least this. Intrinsics/builtins should be your first approach. Only use inline assembly if you can't express what you need using intrinsics.

wyldfire | 13 hours ago

It's always been a mystery to me why people put up with this stuff. Adding strings to the assembler output is fine if you want to assemble some unsupported instruction, and a useful getout clause. But as the only option, it sucks, and it's no fun if you want to insert more than 1 instruction.

I used CodeWarrior for PowerPC about 15 years ago, and its inline assembler was very easy to use. No markup required, and you didn't even have to really understand the ABI. Write a C function, add "register" to the parameters, put register variables inside the function, add an asm block inside it, then do your worst. It'd track variable liveness to allocate registers, and rearrange instructions to lengthen dependency chains. Any problems, you'd get an error. Very nice.

tom_ | 13 hours ago

One of my earliest surprises is: input-only and output-only may be mapped to the same register, and explicitly mapping one of them will not prevent this: https://godbolt.org/z/bo3r749Ge

fuhsnn | 9 hours ago

> Despite this, please use volatile anyway! When I do not see volatile it’s likely a defect. Stopping to consider if it’s this special case slows understanding and impedes code review.

There are quite a few things I reflexively write where I know that in the specific case I don't actually need to do that, but also know that it'll make the code easier to skim read later.

I hate having my skimming interrupted by "is this the case where this is safe?" type situations.

One can, of course, overdo it - and to what extent it's worth doing it depends on who you expect to be reading it - but it can often be quite handy.

A concrete example:

    this.attrs = { style: {}, ...attrs }
will work fine if the 'attrs' variable is null, because ...<null> is not an error in javascript and expands to nothing ... but I'll still often write

    this.attrs = { style: {}, ...(attrs??{}) }
instead because it makes it clear that the code is allowing the null case deliberately and because it means the person reading it doesn't have to remember that the null case would've worked anyway (and also because my brain finds it weird that the null case does work so it often makes me pause even though I well know it's fine once I stop and think for a second).
mst | 5 hours ago

If I'm using assembly, the entire project is assembly... granted, I don't do any low level programming on modern hardware (anything newer than 586)...

nubinetwork | 4 hours ago

There aren’t many reasons to write an inline asm block that the compiler will elide because of no apparent effects; more likely you screwed up the constraints. If it’s due to ensuring correct memory accesses relative to the compiler, it’s usually better to define appropriate “m” constraints to give the compiler appropriate visibility, or if it’s complex/loopy enough to make that impossible then that is what the “memory” clobber is for, not volatile.

So I strongly disagree with 2 and 3.

brigade | 9 hours ago