MENU

Mono RISCV Issues

November 13, 2022 • 实习

在 Port mono RISCV 的过程中发现了一些可以优化 / 可能有问题的点,就此记录下来,未来可能会处理。

1. Load Imm 的实现:

在函数 mono_riscv_emit_imm 中,有一段代码被用来加载超过 32 位的立即数,很 tricky。
后期要是优化的话,参考 LLVM 中的实现使用了位移运算指令。

  • /*
  • * This is not pretty, but RV64I doesn't make it easy to load constants.
  • * Need to figure out something better.
  • */
  • riscv_jal (code, rd, sizeof (guint64));
  • *(guint64 *) code = imm;
  • code += sizeof (guint64);
  • riscv_ld (code, rd, rd, 0);

2. 会分配 Zero(X0)寄存器

C# 源码如下

  • namespace HelloWorld
  • {
  • class Program
  • {
  • static void Main()
  • {
  • int a = 0;
  • }
  • }
  • }

CIL 如下

  • iconst R59 <- [0]
  • store_membase_reg [s0 + 0xfffffffffffffff0] <- R59
  • il_seq_point intr il: 0x0
  • load_membase R44 <- [s0 + 0xfffffffffffffff8]
  • load_membase R48 <- [R44 + 0x8]
  • load_membase R49 <- [s0 + 0xfffffffffffffff8]
  • load_membase R50 <- [R49 + 0x0]
  • add_imm R51 <- s0 [-16]
  • add_imm R52 <- s0 [-32]
  • add_imm R53 <- s0 [-40]
  • add_imm R54 <- s0 [-48]
  • add_imm R55 <- s0 [-56]
  • add_imm R56 <- R48 [0]
  • voidcall_reg R50 clobbers: c
  • il_seq_point il: 0x18
  • load_membase ra <- [s0 + 0xfffffffffffffff0]
  • il_seq_point intr il: 0x19

接着 mono 会进行基于线性扫描分配寄存器。
liveness 如下:

  • liveness: ra [16 - 16]
  • liveness: s0 [2 - 0]
  • liveness: R44 [4 - 4]
  • liveness: R48 [5 - 5]
  • liveness: R49 [6 - 6]
  • liveness: R50 [7 - 7]
  • liveness: R51 [8 - 8]
  • liveness: R52 [9 - 9]
  • liveness: R53 [10 - 10]
  • liveness: R54 [11 - 11]
  • liveness: R55 [12 - 12]
  • liveness: R56 [13 - 13]

分配结果如下:

  • processing: 17 il_seq_point intr il: 0x19
  • 17 il_seq_point intr il: 0x19
  • processing: 16 load_membase ra <- [s0 + 0xfffffffffffffff0]
  • 16 load_membase ra <- [s0 + 0xfffffffffffffff0]
  • processing: 15 il_seq_point il: 0x18
  • 15 il_seq_point il: 0x18
  • processing: 14 voidcall_reg R50 clobbers: c
  • assigned arg reg zero to R51
  • assigned arg reg a0 to R52
  • assigned arg reg a1 to R53
  • assigned arg reg a2 to R54
  • assigned arg reg a3 to R55
  • assigned arg reg a4 to R56
  • assigned sreg1 a5 to R50
  • 14 voidcall_reg a5 clobbers: c
  • processing: 13 add_imm R56 <- R48 [0]
  • assigned dreg a4 to dest R56
  • freeable a4 (R56) (born in 13)
  • assigned sreg1 a4 to R48
  • 13 add_imm a4 <- a4 [0]
  • processing: 12 add_imm R55 <- s0 [-56]
  • assigned dreg a3 to dest R55
  • freeable a3 (R55) (born in 12)
  • 12 add_imm a3 <- s0 [-56]
  • processing: 11 add_imm R54 <- s0 [-48]
  • assigned dreg a2 to dest R54
  • freeable a2 (R54) (born in 11)
  • 11 add_imm a2 <- s0 [-48]
  • processing: 10 add_imm R53 <- s0 [-40]
  • assigned dreg a1 to dest R53
  • freeable a1 (R53) (born in 10)
  • 10 add_imm a1 <- s0 [-40]
  • processing: 9 add_imm R52 <- s0 [-32]
  • assigned dreg a0 to dest R52
  • freeable a0 (R52) (born in 9)
  • 9 add_imm a0 <- s0 [-32]
  • processing: 8 add_imm R51 <- s0 [-16]
  • assigned dreg zero to dest R51
  • freeable zero (R51) (born in 8)
  • 8 add_imm zero <- s0 [-16]
  • processing: 7 load_membase R50 <- [R49 + 0x0]
  • assigned dreg a5 to dest R50
  • freeable a5 (R50) (born in 7)
  • assigned sreg1 a0 to R49
  • 7 load_membase a5 <- [a0 + 0x0]
  • processing: 6 load_membase R49 <- [s0 + 0xfffffffffffffff8]
  • assigned dreg a0 to dest R49
  • freeable a0 (R49) (born in 6)
  • 6 load_membase a0 <- [s0 + 0xfffffffffffffff8]
  • processing: 5 load_membase R48 <- [R44 + 0x8]
  • assigned dreg a4 to dest R48
  • freeable a4 (R48) (born in 5)
  • assigned sreg1 a0 to R44
  • 5 load_membase a4 <- [a0 + 0x8]
  • processing: 4 load_membase R44 <- [s0 + 0xfffffffffffffff8]
  • assigned dreg a0 to dest R44
  • freeable a0 (R44) (born in 4)
  • 4 load_membase a0 <- [s0 + 0xfffffffffffffff8]
  • processing: 3 il_seq_point intr il: 0x0
  • 3 il_seq_point intr il: 0x0
  • processing: 2 store_membase_reg [s0 + 0xfffffffffffffff0] <- R59
  • assigned sreg1 a0 to R59
  • 2 store_membase_reg [s0 + 0xfffffffffffffff0] <- a0
  • processing: 1 iconst R59 <- [0]
  • assigned dreg a0 to dest R59
  • freeable a0 (R59) (born in 1)
  • 1 iconst a0 <- [0]

R51 被分配了 zero 寄存器,从 IR 来看,R51 应该是一个参数寄存器 ax,被用来给之后的 voidcall_reg 传参。