[PATCH] D70401: [RISCV] Complete RV32E/ilp32e implementation
Wang Pengcheng via Phabricator via llvm-commits
llvm-commits at lists.llvm.org
Wed Mar 23 01:50:08 PDT 2022
pcwang-thead added a comment.
Herald added a subscriber: StephenFan.
In D70401#3391561 <https://reviews.llvm.org/D70401#3391561>, @khchen wrote:
> I found https://github.com/llvm/llvm-test-suite/blob/main/SingleSource/UnitTests/2003-05-26-Shorts.c result is mismatched with gcc's (-march=rv32e -mabi=ilp32e).
> Did you have same issue?
I got the same issue, but it may be not this patch's problem.
Here is the reduced case:
#include <stdio.h>
unsigned long long getL() { return 0xafafafafc5c5b8a3ull; }
int main(int argc, char **argv) {
unsigned long long UL = getL(); /* 0xafafafafc5c5b8a3 */
unsigned int ui = (unsigned int)UL; /* 0xc5c5b8a3 = 3318069411 */
printf("ui = %u (0x%x)\t\tUL-ui = %lld (0x%llx)\n", ui, ui, UL - ui, UL - ui);
}
GCC output is:
ui = 3318069411 (0xc5c5b8a3) UL-ui = -5787213829993660416 (0xafafafaf00000000)
LLVM output is:
ui = 3318069411 (0xc5c5b8a3) UL-ui = 0 (0xafafafaf)
The problem is the way to pass arguments to `printf`.
GCC asm:
li a4,-1347440640
addi sp,sp,-24
addi a4,a4,-81
sw a4,8(sp)
lw a5,8(sp)
li a2,-976896000
addi a2,a2,-1885
lui a0,%hi(.LC1)
sw a5,0(sp)
li a3,0
li a5,0
mv a1,a2
addi a0,a0,%lo(.LC1)
sw ra,20(sp)
sw a3,4(sp)
call printf
LLVM asm:
addi sp, sp, -16
sw ra, 12(sp) # 4-byte Folded Spill
sw s0, 8(sp) # 4-byte Folded Spill
addi s0, sp, 16
andi sp, sp, -8
lui a0, 719611
addi a5, a0, -81
sw a5, 4(sp)
lui a0, %hi(.L.str)
addi a0, a0, %lo(.L.str)
lui a1, 810076
addi a1, a1, -1885
sw zero, 0(sp)
mv a2, a1
mv a4, zero
call printf
Both GCC and LLVM pass format string and two `ui` by `a0, a1, a2`, the difference is how they pass rest variadic arguments.
`UL-ui` is with 2*XLEN size, so it will be spilt to two part (low and high 32-bits). Low part is 0x00000000, high part is 0xafafafaf.
For GCC:
First UL-ui : low -> a3, high -> a4
Second UL-ui : low -> a5, high -> stack.0
For LLVM:
First UL-ui : low -> a4, high -> a5
Second UL-ui : low -> stack.0, high -> stack.1
Because we use GLIBC compiled by GCC while linking with LLVM's output, so in `printf`'s view:
a3 -> undefined, so it is zero.
a4 -> low part, 0x00000000
a5 -> high part, 0xafafafaf
stack.0 -> low part, 0x00000000
stack.1 -> not used
It get `0x0000000000000000` and `0x00000000afafafaf` for two `UL-ui` (seen as the output).
In the ABI specification, it says (Integer Calling Convention <https://github.com/riscv-non-isa/riscv-elf-psabi-doc/blob/master/riscv-cc.adoc#integer-calling-convention>):
In the base integer calling convention, variadic arguments are passed in the same manner as named arguments, with one exception. Variadic arguments with 2×XLEN-bit alignment and size at most 2×XLEN bits are passed in an aligned register pair (i.e., the first register in the pair is even-numbered), or on the stack by value if none is available. After a variadic argument has been passed on the stack, all future arguments will also be passed on the stack (i.e. the last argument register may be left unused due to the aligned register pair rule).
And this is what LLVM do for ILP32E currently.
I saw the same issue on Github(Inconsistent variadic argument passing behavior between ilp32 and ilp32e for long long/double <https://github.com/riscv-collab/riscv-gcc/issues/148>), so shall LLVM be compatible with GCC's behavior?
@kito-cheng @khchen
Repository:
rG LLVM Github Monorepo
CHANGES SINCE LAST ACTION
https://reviews.llvm.org/D70401/new/
https://reviews.llvm.org/D70401
More information about the llvm-commits
mailing list