-1

It is not ignored, that I know. So what does it add to the compiled assembly code?

Example:

 for(int j = 0; j < load; j++) {
        long p = (i % 8) * (i % 16);
        if (i % 2 == 0) {
            x += p;
        } else {
            x -= p;
        }
        asm("");
    }
Peter Cordes
  • 328,167
  • 45
  • 605
  • 847
  • 1
    In your example, it probably **will be** ignored. – tofro Jun 23 '22 at 17:19
  • 1
    `asm` emits inline assembly instructions – h0r53 Jun 23 '22 at 17:20
  • You can compare assembly [Demo](https://godbolt.org/z/f59G69aMn). – Jarod42 Jun 23 '22 at 17:21
  • You could always compile the code and see for yourself – h0r53 Jun 23 '22 at 17:22
  • 5
    Your linked thread has this explanation which answers your question precisely: "*`noinline` This function attribute prevents a function from being considered for inlining. If the function does not have side-effects, there are optimizations other than inlining that causes function calls to be optimized away, although the function call is live. **To keep such calls from being optimized away, put `asm ("");`***" In other words, it was used to trick the compiler into not optimizing away loops with no side-effects. This may or may not work. I wouldn't use it. – rustyx Jun 23 '22 at 17:26
  • If you processor has NOP (No Operation) instructions, you compiler may emit a NOP assembly instruction (if the optimization rules don't drop it first). – Thomas Matthews Jun 23 '22 at 20:31

1 Answers1

3

So what does it add to the compiled assembly code?

Let me answer this in the most literal way possible (assuming that's what you asked) and then I'll explain a little more. It adds nothing to the output assembly. No whitespace/newline/comments, nothing. The best way to illustrate this is to show what happens when you have nothing significant to compile in the first place. For example consider these two trivial functions with nothing to optimize:

void Test1(void) { }
void Test2(void) { asm(""); }

Compile it to assembly:

g++ -c -S test.cpp -o test.s

And look at the output (abridged):

_Z5Test1v:
    endbr64
    pushq   %rbp
    movq    %rsp, %rbp
    nop
    popq    %rbp
    ret

_Z5Test2v:
    endbr64
    pushq   %rbp
    movq    %rsp, %rbp
    nop
    popq    %rbp
    ret

Note that they are the same. The compiler has literally inserted an empty string ("") into the assembly output.

Even still, this little asm("") can have a profound effect on how the compiler generates code in non-trivial cases. Any user-supplied assembly is treated as volatile, which means the compiler assumes it cannot "see" what is happening behind the "" string or make assumptions about how it can be optimized. Operations cannot be re-ordered around it for example, or as Peter Cordes pointed out in the comments, if you put it in a loop, loop unrolling will be completely defeated.

In this sense what it "adds" to the compiled code is everything that the optimization passes could otherwise have done if the asm("") was not present.

A treatment of exactly what various optimizers will do given a certain source input is totally beyond the scope of a SO question like this, but you can always play around with checking assembly output given various code and optimization flag combos.

Jon Reeves
  • 2,426
  • 3
  • 14
  • Can you show me the empty line? I can't see it. – Phillip Borge Jun 23 '22 at 17:27
  • 2
    It's not an empty line, it's an empty string, meaning nothing has been inserted, not even a newline. All that's happening is the compiler sees it as 'barrier' that it can't cross for optimization. – Jon Reeves Jun 23 '22 at 17:29
  • "It will influence how the compiler generates code", true, but then you show an example that has the same generated code? – xiver77 Jun 23 '22 at 17:29
  • Also I don't see any point for compiling without optimization in this case. – xiver77 Jun 23 '22 at 17:31
  • @xiver77 The point of the example is not to show how the compiler output changes, it's to show exactly what text gets inserted into the assembly when you write out `asm("")`. – Jon Reeves Jun 23 '22 at 17:34
  • @JonReeves Alright, it seems you answered the question quite literally. – xiver77 Jun 23 '22 at 17:35
  • Ha yes indeed @xiver77, as literally as I possibly could, assuming that's what OP was interested in. – Jon Reeves Jun 23 '22 at 17:36
  • 1
    You're missing the point of putting it in a *loop*. `asm("")` is implicitly `asm volatile`, so the empty string has to "execute" as many times as it does in the abstract machine. That effectively defeats loop unrolling and loop removal. At least it's not a non-empty string like `asm("# comment")` which would also (in some GCC versions) get treated as a memory barrier, as a concession to broken code that uses GNU C Basic asm statements like this in unsafe ways; that would further defeat loop optimizations. – Peter Cordes Jun 23 '22 at 18:30
  • Seems like my original answer created some confusion so I decided to make some significant edits for posterity. Let me re-emphasize, I was trying to answer *exactly* the question that was asked, not explain the intricacies of what optimizers will do in various circumstances. That's a better topic for a text book. – Jon Reeves Jul 12 '22 at 17:07
  • Note that only `asm` statements without any output constraints are implicitly volatile. Those that have output constraints are only volatile if they have an explicit `volatile`, making them less damaging to optimization. – Chris Dodd Jul 13 '22 at 19:11