[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