简体   繁体   中英

Why “long long” arguments need to “aligned even-odd register pair” in RISC-V

As RISC-V calling convention documentation says:

When primitive arguments twice the size of a pointer-word are passed on the stack, they are naturally aligned. When they are passed in the integer registers, they reside in an aligned even-odd register pair, with the even register holding the least-significant bits. In RV32, for example, the function void foo(int, long long) is passed its first argument in a0 and its second in a2 and a3. Nothing is passed in a1.

Why not just use a1 and a2 instead of a2 and a3 ? So we can pass more arguments by registers.

Usually, this kind of thing is done so that straightforward code can flush all the registers to memory and get what you'd expect as if the memory had been used in the first place to pass nicely aligned parameters — this is typically important with varargs functions.

However, we should note that neither clang nor gcc follow this directly for non-varargs functions. They both use a0 for the int and a1 , a2 for the long long (where a1 is the low order and a2 the high order of the long long ).

long long square(int num, long long foo) {
    return foo + 100;
}

results in

square:
    addi    a0, a1, 100
    sltu    a1, a0, a1
    add     a1, a1, a2
    ret

clang: https://godbolt.org/z/9Pez4r

gcc: https://godbolt.org/z/b4dMsr


Only if we do varargs do we see the compilers skip a1 :

long long square(int num, ...);

int test () {
    square ( 100, (long long) 200 );
}

results in

test:
    addi    a0, zero, 100
    addi    a2, zero, 200
    mv      a3, zero
    tail    square

https://godbolt.org/z/4xWc1E

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM