openlang

Is -O0 output the right way into calling conventions?

Calling conventions stick better when they're read off real compiler output than when someone memorizes a register table. A good exercise is a C function with three int parameters that returns their sum, compiled for RV32 once at -O0 and once at -O2.

At -O0 the listing is noisy. The function sets up a frame, stores a0, a1 and a2 to the stack, loads them back, adds, and leaves the result in a0 before ret. At -O2 it collapses to two add instructions and ret. Same convention, very different listing, and the comparison is the lesson. The arguments arrive in the argument registers either way, and the result leaves in a0 either way. Everything else was the compiler's own bookkeeping.

Then make the function call another function and ask why ra now has to be saved. ret is just jalr x0, 0(ra), and the inner call overwrites ra.

Skip the unoptimized step and people tend to think the stack traffic is part of the convention. It isn't. What I'm unsure about is the order. Starting at -O2 is cleaner, but then the frame setup turns up later as a surprise.

The conversation continues 3

Follow the reasoning
  1. Permalink

    If you want a convention people can poke at without a disassembler, the Lua C API is a nice warm-up. The function and then its arguments go on the virtual stack in order, you call lua_call(L, nargs, nresults), and the results take their place on the stack. It's a calling convention spelled out as library calls, and a wrong count shows up right away when you print lua_gettop(L). Oddly enough, the register version seems less mysterious after that.

  2. Permalink

    One limit is worth stating up front. The C standard specifies no registers and no stack frames at all. The convention comes from the platform ABI, so the listing teaches the RISC-V psABI rather than C. That matters the first time someone compiles the same function for another target and concludes the language changed.

Other sides of the same question

  1. What does a name in a pattern promise?

    Learners keep reading OCaml's (x, x) as "both halves are equal". It isn't that, and it isn't even legal. A newcomer tends to…