System V AMD64 ABI calling conventions

The calling convention of the System V AMD64 ABI is followed on Solaris, Linux, FreeBSD, Mac OS X, and other UNIX-like or POSIX-compliant operating systems. The first six integer or pointer arguments are passed in registers RDI, RSI, RDX, RCX, R8, and R9, while XMM0, XMM1, XMM2, XMM3, XMM4, XMM5, XMM6 and XMM7 are used for floating point arguments. For system calls, R10 is used instead of RCX. As in the Microsoft x64 calling convention, additional arguments are passed on the stack and the return value is stored in RAX.

Registers RBP, RBX, and R12-R15 are callee-save registers; all others must be saved by the caller if they wish to preserve their values.

Unlike the Microsoft calling convention, a shadow space is not provided; on function entry, the return address is adjacent to the seventh integer argument on the stack.

Over!

mips64el toolchain for x86_64

mips64el toolchain 是用于在 x86_64 平台交叉编译 mips64el 目标程序的工具集,该工具集分为两种大版本:odd-spreg 和 no-odd-spreg,其中龙芯仅适用 no-odd-spreg 版本。系统库包含 mips64el o32, n32 和 n64 多种版本的库,分别有依赖于 Linux 2.6 内核和 Linux 3.4 内核的两种版本。另外还有支持 x86_64 交叉编译 Mozilla JS 引擎的支持包。

下载
Source: mips64el-toolchain-2.src.tar.xz
no-odd-spreg
toolchain: mips64el-toolchain-2.x64.tar.xz
system libaries (Linux 2.6): mips64el-toolchain-linux-2.6-2.x64.tar.xz
system libaries (Linux 3.4): mips64el-toolchain-linux-3.4-2.x64.tar.xz
system libaries (Linux 3.4 MozJS): mips64el-toolchain-linux-3.4-mozjs-2.x64.tar.xz
odd-spreg
toolchain: mips64el-toolchain-2.x64.tar.xz
system libaries (Linux 2.6): mips64el-toolchain-linux-2.6-2.x64.tar.xz
system libaries (Linux 3.4): mips64el-toolchain-linux-3.4-2.x64.tar.xz

安装

sudo tar --numeric-owner -xf xxxx -C /

配置
设置环境变量

export PATH=${PATH}:/opt/mips64el-toolchain/bin

切换系统库

sudo ln -s -f linux-2.6 /opt/mips64el-toolchain/platforms/current

编译

# MIPS32 o32
mips64el-unknown-linux-gnu-gcc -march=mips32r2 -mabi=32 -o test test.c
# MIPS64 n32
mips64el-unknown-linux-gnu-gcc -march=mips64r2 -mabi=n32 -o test test.c
# MIPS64 n64
mips64el-unknown-linux-gnu-gcc -march=mips64r2 -mabi=64 -o test test.c

Over!

x86 pslldq to Loongson psllq

x86 pslldq 指令逻辑左移字节为单位的数据,而转换成龙芯的MMI只能使用 dsll 和 dsrl 指令模拟实现,需要特别注意的是 dsll 和 dsrl 指令移动的数据是以位为单位的。

/* SSE: pslldq (bytes) */
#define _mm_psllq(_D, _d, _s, _s64, _tf)                    \
        "subu %["#_tf"], %["#_s64"], %["#_s"] \n\t"         \
        "dsrl %["#_tf"], %["#_d"l], %["#_tf"] \n\t"         \
        "dsll %["#_D"h], %["#_d"h], %["#_s"] \n\t"          \
        "dsll %["#_D"l], %["#_d"l], %["#_s"] \n\t"          \
        "or %["#_D"h], %["#_D"h], %["#_tf"] \n\t"
pslldq $4, %xmm0 => mm_psllq(d, d, s32, s64, t)

Over!

看龙芯3A的 dmtc1 指令有多慢!

龙芯2F和3A处理器都实现了与 x86 MMX 基本兼容的 SIMD,即 MMI,该 ASE 是在浮点部件中的实现的,并且复用了 64-bit 的浮点寄存器(FPR)。在使用 MMI 时不可避免的会使用到通用寄存器向浮点器移动数据的情况,那么 dmtc1 的效率如何呢?

GPR 向 FPR 移动数据的指令共有3种:
mtc1 : 从 GPR 向 FPR 移动 32-bit 的数据,64-bit 平台上目标 FPR 的高 32-bit 清 0。
mthc1 : 从 GPR (低 32-bit)向 FPR 的高 32-bit 移动 32-bit 的数据,目标 FPR 的低 32-bit 数据保留。
dmtc1 : 从 GPR 向 FPR 移动 64-bit 数据。

从上面的说明可以看出, dmtc1 的功能是可以使用 mtc1 与 mthc1 模拟实现的,那么我们就设计个实验程序来验证一下这两条方式的时间开销分别如何吧。
程序的逻辑大致如下:

for (i=0; i<100000000; i++) {
#if 0
    move $2, $3
    mtc1 $3, $f31
    dsra $3, 32
    mthc1 $3, $f31
    move $3, $2
    ....
    ....
#else
    dmtc1 $3, $f31
    dmtc1 $3, $f31
     ....
     ....
#endif
}

结果:
在 MIPS64 系统上,每个循环中做8次GPR2FPR的数据移动,其 dmtc1 实现时间大概为 0m4.463s,而 mtc1 与 mthc1 组合实现为 0m3.857s,后者如不做寄存器的保存恢复,开销仅为 0m1.791s。

Over!

Firefox 30.0a1 for 龙芯3初步评测

经过一段时间的 OdinMonkey for MIPS N32 的移植,现在 Firefox 30.0a1 终于可以在龙芯3A笔记本上跑起来了,OdinMonkey for MIPS N32 基于 OdinMonkey for MIPS O32,这过程中感谢 Branislav Rankov 的热心帮助。初步跑了一下 Octane 2.0 性能评测,得分为 1010,比 Firefox 17.0.1 增加了 405 分。下一步的工作是针对龙芯平台的特定优化。

617834d12f2eb9385d05ca44d7628535e4dd6fbf

虽然 JavaScript 的性能有所提升了,但部分页面滚动的响应仍然不是太好,经简单的分析发现瓶颈有可能在 Xorg 上。

Over!

GDB 使用自定义命令实现一次执行多个命令

在调试 JIT 的过程中,经常要输出一些信息再跳过断点,使用 GDB 的自定义命令可以使工作变得简单。

(gdb) define mynext
Type commands for definition of "mynext".
End with a line saying just "end".
>i r
>x/8x $sp
>set $pc = $pc + 4
>c
>end
(gdb) mynext

Over!

MIPS o32 ‘__sync_add_and_fetch_8’ for Loongson

编译 WebKitGtk 过程中,链接测试程序阶段报出 undefined symbol ‘__sync_add_and_fetch_8’,这是由于 ‘__sync_add_and_fetch_8’ 在 MIPS O32 平台上没有实现,但龙芯实际上是 64-bit 的 CPU,所以可以使用下面的实现:

#include <sys/regdef.h>
#include <sys/asm.h>
 
LEAF(__sync_add_and_fetch_8)
    .set push
    .set mips64r2
    .set noreorder
    dins t0, a2, 0, 32
    dins t0, a3, 32, 32
    sync
_retry:
    lld t1, 0(a0)
    daddu t1, t1, t0
    scd t1, 0(a0)
    beqz t1, _retry
    daddu t1, t1, t0
    sync
    dext v0, t1, 0, 32
    jr ra
    dext v1, t1, 32, 32
    .set pop
END(__sync_add_and_fetch_8)

Over!

MIPS mtc1 & mthc1 组合使用问题

在 Port SpiderMonkey MIPS N32 时,有个测试始终跑不过,调试定位到一个 double 类型的立即数装载到 FPR 时用了大概这样的一个指令序列:

li t0, 0x41dfffff
mthc1 t0, $f21
li t0, 0xf2400000
mtc1 t0, $f21

结果 $f21 就杯具的等于了 0x00000000f2400000

查找手册后发现 mtc1 指令将 GPR 的低32位移动到 FPR 的低32位后,FPR 的高32位的值是未定义的,龙芯3上实测值是 0,解决方法是先做 mtc1,再做 mthc1。

Over!

龙芯3的 128-bit 访存指令

龙芯3实现了两组 128-bit 的访存指令 gslq, gssq, gslqc1, gssqc1,分别用于加载、存储 128-bit 数据至通用寄存器和浮点寄存器。这两组指令都要求地址对齐到 16 字节,另外由于指令占用 lwc2, swc2 编码域,所以如果要使用需要启用 CP2。

gslq/gssq

gslq gpr0, gpr1, off(gpr2) // match: 0xc8000020, mask: 0xfc008020
gssq gpr0, gpr1, off(gpr2) // match: 0xe8000020, mask: 0xfc008020
 
gpr0 : 编码域 bit0-bit4,取值 0-32,高 64-bit
gpr1 : 编码域 bit16-bit20,取值 0-32,低 64-bit
off  : 编码域 bit6-bit14,取值 -256-255,实际偏移值需要左移 4 位,即 -4096-4080
gpr2 : 编码域 bit21-bit25,取值 0-32

gslqc1/gssqc1

gslqc1 fpr0, fpr1, off(gpr0) // match: 0xc8008020, mask: 0xfc008020
gssqc1 fpr0, fpr1, off(gpr0) // match: 0xe8008020, mask: 0xfc008020
 
fpr0 : 编码域 bit0-bit4,取值 0-32,高 64-bit
fpr1 : 编码域 bit16-bit20,取值 0-32,低 64-bit
off  : 编码域 bit6-bit14,取值 -256-255,实际偏移值需要左移 4 位,即 -4096-4080
gpr0 : 编码域 bit21-bit25,取值 0-32

Over!