LoongArch64 汇编指南
寄存器
LoongArch 的寄存器使用约定基本和 RISC-V 相同。
通用寄存器
名称 | 助记符 | 含义 | 保存者 |
---|---|---|---|
$r0 |
$zero |
常数零 | - |
$r1 |
$ra |
返回地址 | 被调用者保存 |
$r2 |
$tp |
线程指针 | - |
$r3 |
$sp |
栈指针 | 调用者保存 |
$r4-$r5 |
$a0-$a1 |
参数/返回值寄存器 | 被调用者保存 |
$r6-$r11 |
$a2-$a7 |
参数寄存器 | 被调用者保存 |
$r12-$r20 |
$t0-$t8 |
临时寄存器 | 被调用者保存 |
$r21 |
- |
保留 | - |
$r22 |
$fp/$s9 |
帧指针/静态寄存器 | 调用者保存 |
$r23-$r31 |
$s0-$s8 |
静态寄存器 | 调用者保存 |
PC 寄存器
PC 寄存器记录当前指令的地址,因此总是 4 字节对齐的,它只能被指令间接修改。
浮点寄存器
名称 | 助记符 | 含义 | 保存者 |
---|---|---|---|
$f0-$f1 |
$fa0-$fa1 |
参数/返回值寄存器 | 被调用者保存 |
$f2-$f7 |
$fa2-$fa7 |
参数寄存器 | 被调用者保存 |
$f8-$f23 |
$ft0-$ft15 |
临时寄存器 | 被调用者保存 |
$f24-$f31 |
$fs0-$fs7 |
静态寄存器 | 调用者保存 |
条件标志寄存器
$fcc0-$fcc7
一共 8 个条件标志寄存器(CFR),每个长度都是 1 位,可以读写。
浮点控制状态寄存器
$fcsr0-$fcsr3
共四个浮点控制状态寄存器(FCSR),每个长度为 32 位,可以读写。
指令格式
LoongArch 有 9 种指令格式。这里主要介绍几种常用的指令格式。
- LoongArch 是小端序的。
- 此处只考虑 64 位指令集,即 LoongArch64。
- 整数数据类型主要分为:比特(1 位,记为“b”)、字节(8 位,记为“B”)、半字(16 位,记为“H”)、字(32 位,记为“W”)、双字(64 位,记为“D”)。
- 浮点数据类型分为两种:单精度(32 位,记为“S”)、双精度(64 位,记为“D”)。
大部分汇编指令遵循以下格式:
- 一元运算指令:
指令名 目的操作数, 源操作数
- 二元运算指令:
指令名 目的操作数, 源操作数1, 源操作数2
- 三元运算指令:
指令名 目的操作数, 源操作数1, 源操作数2, 源操作数3
- 加载指令:
指令名 目的操作数, 基址, 偏移
- 存储指令:
指令名 源操作数, 基址, 偏移
基础指令
整数指令
加法
add.w rd, rj, rk
add.d rd, rj, rk
addi.w rd, rj, si12
addi.d rd, rj, si12
addu16i.d rd, rj, si16
其中,
addu16i.d
是把 16 位立即数 si16 左移 16 位后符号扩展,再加上 rj 的值,放入 rd。
减法
sub.w rd, rj, rk
sub.d rd, rj, rk
条件置位
slt rd, rj, rk
sltu rd, rj, rk
slti rd, rj, si12
sltui rd, rj, si12
“slt” 推测为 “set if less than” 的缩写。
位运算
nor rd, rj, rk
and rd, rj, rk
or rd, rj, rk
xor rd, rj, rk
orn rd, rj, rk
andn rd, rj, rk
andi rd, rj, ui12
ori rd, rj, ui12
xori rd, rj, ui12
乘法
mul.w rd, rj, rk
mulh.w rd, rj, rk
mulh.wu rd, rj, rk
mul.d rd, rj, rk
mulh.d rd, rj, rk
mulh.du rd, rj, rk
mulw.d.w rd, rj, rk
mulw.d.wu rd, rj, rk
除法
div.w rd, rj, rk
mod.w rd, rj, rk
div.wu rd, rj, rk
mod.wu rd, rj, rk
div.d rd, rj, rk
mod.d rd, rj, rk
div.du rd, rj, rk
mod.du rd, rj, rk
除法指令不会产生异常,即使除数为 0,这时候结果未定义。
左移后加法
alsl.w rd, rj, rk, sa2
alsl.wu rd, rj, rk, sa2
alsl.d rd, rj, rk, sa2
加载立即数相关运算
lu12i.w rd, si20
lu32i.d rd, si20
lu52i.d rd, rj, si12
PC 相关运算
pcaddi rd, si20
pcalau12i rd, si20
pcaddu12i rd, si20
pcaddu18i rd, si20
移位运算
sll.w rd, rj, rk
srl.w rd, rj, rk
sra.w rd, rj, rk
sll.d rd, rj, rk
srl.d rd, rj, rk
sra.d rd, rj, rk
rotr.w rd, rj, rk
rotr.d rd, rj, rk
slli.w rd, rj, ui5
slli.d rd, rj, ui6
srli.w rd, rj, ui5
srli.d rd, rj, ui6
srai.w rd, rj, ui5
srai.d rd, rj, ui6
rotri.w rd, rj, ui5
rotri.d rd, rj, ui6
符号扩展
ext.w.h rd, rj
ext.w.b rd, rj
统计 0、1 的个数
clo.w rd, rj
clz.w rd, rj
cto.w rd, rj
ctz.w rd, rj
clo.d rd, rj
clz.d rd, rj
cto.d rd, rj
ctz.d rd, rj
字节、半字、比特逆序
revb.2h rd, rj
revb.4h rd, rj
revb.2w rd, rj
revb.d rd, rj
revh.2w rd, rj
revh.d rd, rj
bitrev.4b rd, rj
bitrev.8b rd, rj
bitrev.w rd, rj
bitrev.d rd, rj
拼接
bytepick.w rd, rj, rk, sa2
bytepick.d rd, rj, rk, sa3
条件赋值
maskeqz rd, rj, rk
masknez rd, rj, rk
替换
bstrins.w rd, rj, msbw, lsbw
bstrins.d rd, rj, msbd, lsbd
截取
bstrpick.w rd, rj, msbw, lsbw
bstrpick.d rd, rj, msbd, lsbd
访存
ld.b rd, rj, si12
ld.h rd, rj, si12
ld.w rd, rj, si12
ld.d rd, rj, si12
st.b rd, rj, si12
st.h rd, rj, si12
st.w rd, rj, si12
st.d rd, rj, si12
ld.bu rd, rj, si12
ld.hu rd, rj, si12
ld.wu rd, rj, si12
ldx.b rd, rj, rk
ldx.h rd, rj, rk
ldx.w rd, rj, rk
ldx.d rd, rj, rk
stx.b rd, rj, rk
stx.h rd, rj, rk
stx.w rd, rj, rk
stx.d rd, rj, rk
ldx.bu rd, rj, rk
ldx.hu rd, rj, rk
ldx.wu rd, rj, rk
ldptr.w rd, rj, si14
stptr.w rd, rj, si14
ldptr.d rd, rj, si14
stptr.d rd, rj, si14
预取
preld hint, rj, si12
preldx hint, rj, rk
边界检查访存
ldgt.b rd, rj, rk
ldgt.h rd, rj, rk
ldgt.w rd, rj, rk
ldgt.d rd, rj, rk
ldle.b rd, rj, rk
ldle.h rd, rj, rk
ldle.w rd, rj, rk
ldle.d rd, rj, rk
stgt.b rd, rj, rk
stgt.h rd, rj, rk
stgt.w rd, rj, rk
stgt.d rd, rj, rk
stle.b rd, rj, rk
stle.h rd, rj, rk
stle.w rd, rj, rk
stle.d rd, rj, rk
屏障
dbar hint
ibar hint
ll/sc
ll.w rd, rj, si14
sc.w rd, rj, si14
ll.d rd, rj, si14
sc.d rd, rj, si14
原子操作
amswap.w rd, rk, rj
amswap.d rd, rk, rj
amadd.w rd, rk, rj
amadd.d rd, rk, rj
amand.w rd, rk, rj
amand.d rd, rk, rj
amor.w rd, rk, rj
amor.d rd, rk, rj
amxor.w rd, rk, rj
amxor.d rd, rk, rj
ammax.w rd, rk, rj
ammax.d rd, rk, rj
ammin.w rd, rk, rj
ammin.d rd, rk, rj
ammax.wu rd, rk, rj
ammax.du rd, rk, rj
ammin.wu rd, rk, rj
ammin.du rd, rk, rj
amswap_db.w rd, rk, rj
amswap_db.d rd, rk, rj
amadd_db.w rd, rk, rj
amadd_db.d rd, rk, rj
amand_db.w rd, rk, rj
amand_db.d rd, rk, rj
amor_db.w rd, rk, rj
amor_db.d rd, rk, rj
amxor_db.w rd, rk, rj
amxor_db.d rd, rk, rj
ammax_db.w rd, rk, rj
ammax_db.d rd, rk, rj
ammin_db.w rd, rk, rj
ammin_db.d rd, rk, rj
ammax_db.wu rd, rk, rj
ammax_db.du rd, rk, rj
ammin_db.wu rd, rk, rj
ammin_db.du rd, rk, rj
CRC 校验
crc.w.b.w rd, rj, rk
crc.w.h.w rd, rj, rk
crc.w.w.w rd, rj, rk
crc.w.d.w rd, rj, rk
crcc.w.b.w rd, rj, rk
crcc.w.h.w rd, rj, rk
crcc.w.w.w rd, rj, rk
crcc.w.d.w rd, rj, rk
转移
beqz rj, offs
bnez rj, offs
jirl rd, rj, offs
b offs
bl offs
beq rj, rd, offs
bne rj, rd, offs
blt rj, rd, offs
bge rj, rd, offs
bltu rj, rd, offs
bgeu rj, rd, offs
断言
asrtle.d rj, rk
asrtgt.d rj, rk
计时器
rdtimel.w rd, rj
rdtimeh.w rd, rj
rdtime.d rd, rj
陷阱
break code
系统调用
syscall code
探测
cpucfg rd, rj
浮点指令
浮点运算
fadd.s fd, fj, fk
fadd.d fd, fj, fk
fsub.s fd, fj, fk
fsub.d fd, fj, fk
fmul.s fd, fj, fk
fmul.d fd, fj, fk
fdiv.s fd, fj, fk
fdiv.d fd, fj, fk
fmadd.s fd, fj, fk, fa
fmadd.d fd, fj, fk, fa
fmsub.s fd, fj, fk, fa
fmsub.d fd, fj, fk, fa
fnmadd.s fd, fj, fk, fa
fnmadd.d fd, fj, fk, fa
fnmsub.s fd, fj, fk, fa
fnmsub.d fd, fj, fk, fa
fmax.s fd, fj, fk
fmax.d fd, fj, fk
fmin.s fd, fj, fk
fmin.d fd, fj, fk
fmaxa.s fd, fj, fk
fmaxa.d fd, fj, fk
fmina.s fd, fj, fk
fmina.d fd, fj, fk
fabs.s fd, fj
fabs.d fd, fj
fneg.s fd, fj
fneg.d fd, fj
fsqrt.s fd, fj
fsqrt.d fd, fj
frecip.s fd, fj
frecip.d fd, fj
frsqrt.s fd, fj
frsqrt.d fd, fj
fscaleb.s fd, fj, fk
fscaleb.d fd, fj, fk
flogb.s fd, fj
flogb.d fd, fj
fcopysign.s fd, fj, fk
fcopysign.d fd, fj, fk
fclass.s fd, fj
fclass.d fd, fj
浮点比较
fcmp.caf.s cd, fj, fk
fcmp.caf.d cd, fj, fk
fcmp.saf.s cd, fj, fk
fcmp.saf.d cd, fj, fk
fcmp.clt.s cd, fj, fk
fcmp.clt.d cd, fj, fk
fcmp.slt.s cd, fj, fk
fcmp.slt.d cd, fj, fk
fcmp.ceq.s cd, fj, fk
fcmp.ceq.d cd, fj, fk
fcmp.seq.s cd, fj, fk
fcmp.seq.d cd, fj, fk
fcmp.cle.s cd, fj, fk
fcmp.cle.d cd, fj, fk
fcmp.sle.s cd, fj, fk
fcmp.sle.d cd, fj, fk
fcmp.cun.s cd, fj, fk
fcmp.cun.d cd, fj, fk
fcmp.sun.s cd, fj, fk
fcmp.sun.d cd, fj, fk
fcmp.cult.s cd, fj, fk
fcmp.cult.d cd, fj, fk
fcmp.sult.s cd, fj, fk
fcmp.sult.d cd, fj, fk
fcmp.cueq.s cd, fj, fk
fcmp.cueq.d cd, fj, fk
fcmp.sueq.s cd, fj, fk
fcmp.sueq.d cd, fj, fk
fcmp.cule.s cd, fj, fk
fcmp.cule.d cd, fj, fk
fcmp.sule.s cd, fj, fk
fcmp.sule.d cd, fj, fk
fcmp.cne.s cd, fj, fk
fcmp.cne.d cd, fj, fk
fcmp.sne.s cd, fj, fk
fcmp.sne.d cd, fj, fk
fcmp.cor.s cd, fj, fk
fcmp.cor.d cd, fj, fk
fcmp.sor.s cd, fj, fk
fcmp.sor.d cd, fj, fk
fcmp.cune.s cd, fj, fk
fcmp.cune.d cd, fj, fk
fcmp.sune.s cd, fj, fk
fcmp.sune.d cd, fj, fk
浮点转换
fcvt.s.d fd, fj
fcvt.d.s fd, fj
ftintrm.w.s fd, fj
ftintrm.w.d fd, fj
ftintrm.l.s fd, fj
ftintrm.l.d fd, fj
ftintrp.w.s fd, fj
ftintrp.w.d fd, fj
ftintrp.l.s fd, fj
ftintrp.l.d fd, fj
ftintrz.w.s fd, fj
ftintrz.w.d fd, fj
ftintrz.l.s fd, fj
ftintrz.l.d fd, fj
ftintrne.w.s fd, fj
ftintrne.w.d fd, fj
ftintrne.l.s fd, fj
ftintrne.l.d fd, fj
ftint.w.s fd, fj
ftint.w.d fd, fj
ftint.l.s fd, fj
ftint.l.d fd, fj
ffint.s.w fd, fj
ffint.s.l fd, fj
ffint.d.w fd, fj
ffint.d.l fd, fj
frint.s fd, fj
frint.d fd, fj
浮点搬运
fmov.s fd, fj
fmov.d fd, fj
fsel fd, fj, fk, ca
movgr2fr.w fd, rj
movgr2fr.d fd, rj
movgr2frh.w fd, rj
movfr2gr.s rd, fj
movfr2gr.d rd, fj
movfrh2gr.s rd, fj
movgr2fcsr fcsr, rj
movfcsr2gr rd, fcsr
movfr2cf cd, fj
movcf2fr fd, cj
movgr2cf cd, rj
movcf2gr rd, cj
浮点访存
fld.s fd, rj, si12
fst.s fd, rj, si12
fld.d fd, rj, si12
fst.d fd, rj, si12
fldx.s fd, rj, rk
fldx.d fd, rj, rk
fstx.s fd, rj, rk
fstx.d fd, rj, rk
浮点边界检查访存
fldgt.s fd, rj, rk
fldgt.d fd, rj, rk
fldle.s fd, rj, rk
fldle.d fd, rj, rk
fstgt.s fd, rj, rk
fstgt.d fd, rj, rk
fstle.s fd, rj, rk
fstle.d fd, rj, rk
浮点转移
bceqz cj, offs
bcnez cj, offs
宏指令
空操作
nop
等价于
andi $zero, $zero, 0
。
无条件转移
jr rd
等价于
jirl $zero, rd, 0
,通常用于子程序返回。
条件转移
bgt rj, rd, label
bgtu rj, rd, label
ble rj, rd, label
bleu rj, rd, label
bltz rj, rd, label
bgtz rj, rd, label
blez rj, rd, label
bgez rj, rd, label
搬运
move rd, rj
等价于
or rd, rj, $zero
。
加载立即数
li.w rd, s32
li.w rd, u32
li.d rd, s64
li.d rd, u64
li.w
加载一个 32 位立即数,并符号扩展到 64 位;li.d
加载一个 64 位立即数。
加载地址
la rd, label + addend
la.global rd, label + addend
la.local rd, label + addend
la.pcrel rd, label + addend
la.got rd, label
la.abs rd, label + addend
la
是la.global
的别名,用于加载全局的符号;la.local
用于加载局部的符号。
ABI 类型
名称 | 描述 |
---|---|
lp64s | 使用 64 位通用寄存器和栈传参,数据模型为 LP64 |
lp64f | 使用 64 位通用寄存器,32 位浮点寄存器和栈传参,数据模型为 LP64 |
lp64d | 使用 64 位通用寄存器,64 位浮点寄存器和栈传参,数据模型为 LP64 |
ilp32s | 使用 32 位通用寄存器和栈传参,数据模型为 ILP32 |
ilp32f | 使用 32 位通用寄存器,32 位浮点寄存器和栈传参,数据模型为 ILP32 |
ilp32d | 使用 32 位通用寄存器,64 位浮点寄存器和栈传参,数据模型为 ILP32 |
LP64 和 ILP32 数据模型的区别仅在于
long
类型和指针类型的长度,前者是 64 位,后者是 32 位。
过程调用约定
以下内容针对 LP64D ABI。
参数传递
通用寄存器通常用于传递非浮点数,浮点寄存器通常用于传递浮点数。 当寄存器不够用时,再选择栈传参。
标量类型
对于小于 64 位的标量:
- 浮点数 使用浮点寄存器传递,若没有可用的浮点寄存器,则使用通用寄存器;
- 非浮点数 使用通用寄存器传递,若没有可用的通用寄存器,则使用栈传递。
特别地,对于长度为 128 位的数据(例如 long double
):
- 优先使用一对(2 个)通用寄存器传递,低 64 位放入编号较小的寄存器,高 64 位放入编号较大的寄存器;
- 如果只有一个通用寄存器可用,低 64 位存入寄存器,高 64 位存入栈;
- 如果没有可用的通用寄存器,则使用栈传递。
复合类型
结构体、联合体、复数和可变参数传递的情况较为复杂,具体可参考相关文档。通常,较小的结构体可以通过寄存器传递,较大的结构体通过栈传递。
返回值
- 非浮点数 返回值放在
$a0
中,如果返回值超过 64 位,$a1
也会被使用; - 浮点数 返回值放在
$fa0
中,如果返回值超过 64 位,$fa1
也会被使用; - 如果返回值长度超过两个寄存器的长度,将返回值的地址存入
$a0
,并通过该地址返回数据。
栈
- 栈的方向:栈是向下增长的,栈指针必须 16 字节对齐。
- 栈指针初始位置:函数入口处,栈指针应该指向传递给它的第一个参数(如果有参数)。
- 栈的布局:从高到低依次是:参数、保存的返回地址、保存的寄存器、局部变量。并非所有部分都必须存在,如某个函数可以不接受参数,或不需要保存返回地址和寄存器等。
- 栈操作规范:在函数中,应先对栈指针做减法来分配空间,然后再使用这段空间;不应对低于栈指针的数据作出保证。