[HN Gopher] Rules to avoid common extended inline assembly mistakes
       ___________________________________________________________________
        
       Rules to avoid common extended inline assembly mistakes
        
       Author : ingve
       Score  : 62 points
       Date   : 2024-12-20 20:03 UTC (21 hours ago)
        
 (HTM) web link (nullprogram.com)
 (TXT) w3m dump (nullprogram.com)
        
       | tom_ wrote:
       | 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.
        
         | kccqzy wrote:
         | I haven't used CodeWarrior for PowerPC, but that approach
         | sounds like it requires the C compiler to understand the
         | assembler instructions you are using. Is it? But most use cases
         | of inline assembler I've seen these days is for using
         | instructions that the compiler will not emit.
        
         | Conscat wrote:
         | Raw multi-line R"()" strings in C++ reduce some of the tedium.
         | I wrote myself an Emacs tree sitter pattern to highlight asm
         | syntax nicer than a string normally would, which helps. There
         | is also the stasm library (which I haven't used) that looks
         | like a pleasant syntax. https://github.com/stasinek/stasm
         | 
         | Clang (but not GCC) also supports the MSVC assembly syntax
         | which is derived from Borland inline assembly. Unlike MSVC,
         | Clang supports it in 64-bit mode and also for arm.
        
         | astrange wrote:
         | Most of the time I've used inline assembly it's because the
         | compiler was optimizing something badly. I don't want it to
         | rearrange anything.
         | 
         | (Scheduling is almost useless on modern desktop CPUs anyway,
         | except for some instruction fusion patterns.)
        
         | throwaway_1224 wrote:
         | +1, ^5, ditto and Amen for CodeWarrior and its inline asm. CW
         | was _way_ ahead of its time in terms of UX. Its C++ compiler
         | was well above average too, particularly in terms of codegen
         | (although all C++ compilers were effectively broken in that
         | era.)
         | 
         | The only thing that held it back was the lack of scripting. It
         | was probably a rebound rejection of the MPW days, when
         | everything was script-based (and with a crazy custom language.)
         | I remember thinking that the design team probably didn't want
         | to open that Pandora's box, lest scripting might lazily become
         | required and spoil the UX.
         | 
         | Unfortunately, this made CW unsuited to the advent of CI. Even
         | then, I still think it was stupid for Apple not to acquire
         | Metrowerks. The first 5-10 years of Xcode versions had a worse
         | UX and way worse codegen.
        
       | wyldfire wrote:
       | > 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.
        
         | bjackman wrote:
         | I have a fun exception to this!
         | 
         | When writing BPF programs, sometimes it's tricky to get the
         | compiler to generate code that passes the verifier. This can
         | lead you down a path of writing bizarre C in order to try and
         | produce the right order of checks and register allocations.
         | 
         | So, use inline asm!
         | 
         | It's not portable any more... But it's a BPF program! There's
         | nothing to port it to.
         | 
         | It's less readable... Wait no, it's _more_ readable because BPF
         | asm has good syntax and you can avoid the bizarre C backflips
         | to satisfy the verifier.
         | 
         | It's unsafe... Wait no, it's checked for safety at load time!
        
           | ryandrake wrote:
           | For the curious, BPF in this case _might_ mean Berkeley
           | Packet Filter[1]. Not sure. Kind of an obscure acronym but
           | Google search seems to have a consensus.
           | 
           | 1: https://en.wikipedia.org/wiki/Berkeley_Packet_Filter
        
             | wyldfire wrote:
             | It does. These days, it's probably eBPF and a popular
             | target is the linux kernel [1].
             | 
             | You can write C hooks for tracing and profiling, etc. -
             | with inline asm!
             | 
             | [1] https://docs.kernel.org/bpf/
        
       | fuhsnn wrote:
       | 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
        
       | brigade wrote:
       | 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.
        
       | mst wrote:
       | > 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).
        
         | smitelli wrote:
         | Is that vanilla JavaScript or TypeScript? I had always thought
         | that one of the main benefits of TS is that it would probably
         | yell about the first case. (I currently only dabble in the JS
         | world.)
        
           | zdragnar wrote:
           | The spread syntax is native to JavaScript. TS wouldn't
           | complain about the first case, because as the parent said, it
           | is a valid operation.
           | 
           | TS only complains about valid operations if there's some
           | potential mistake due to ambiguity, usually when relying on
           | to strong conversions such as adding a string and an array
           | together or some other nonsense.
        
       | nubinetwork wrote:
       | 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)...
        
       ___________________________________________________________________
       (page generated 2024-12-21 18:01 UTC)