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!

龙芯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!

Mozilla JavaScript 的 MIPS N32 ABI 支持补丁

Mozilla JavaScript 17.0 已经合并了 MIPS 公司开发的 MIPS 相关 JIT 补丁,仅支持 O32 ABI 的,此补丁用于增加 N32 ABI 的支持。

Mozilla JavaScript 官方版本:http://ftp.mozilla.org/pub/mozilla.org/js/mozjs17.0.0.tar.gz
N32 ABI 支持补丁:http://mirrors.heiher.info/sources/extra/js/

jit-test

python2 ./jit_test.py ../js17                                                                                                         
[4876|   0|   0|4876]    100% =======================================>|  466.9s
PASSED ALL

v8 benchmark

../js17 -m -n -f run.js
Richards: 838
DeltaBlue: 1063
Crypto: 1098
RayTrace: 330
EarleyBoyer: 991
RegExp: 128
Splay: 1182
NavierStokes: 732
----
Score (version 7): 659

Over!