LoongArch64 Assembly Guide

 

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

lala.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

LP64ILP32 数据模型的区别仅在于 long 类型和指针类型的长度,前者是 64 位,后者是 32 位。

过程调用约定

以下内容针对 LP64D ABI

参数传递

通用寄存器通常用于传递非浮点数,浮点寄存器通常用于传递浮点数。 当寄存器不够用时,再选择栈传参。

标量类型

对于小于 64 位的标量:

  • 浮点数 使用浮点寄存器传递,若没有可用的浮点寄存器,则使用通用寄存器;
  • 非浮点数 使用通用寄存器传递,若没有可用的通用寄存器,则使用栈传递。

特别地,对于长度为 128 位的数据(例如 long double):

  • 优先使用一对(2 个)通用寄存器传递,低 64 位放入编号较小的寄存器,高 64 位放入编号较大的寄存器;
  • 如果只有一个通用寄存器可用,低 64 位存入寄存器,高 64 位存入栈;
  • 如果没有可用的通用寄存器,则使用栈传递。

复合类型

结构体、联合体、复数和可变参数传递的情况较为复杂,具体可参考相关文档。通常,较小的结构体可以通过寄存器传递,较大的结构体通过栈传递。

返回值

  • 非浮点数 返回值放在 $a0 中,如果返回值超过 64 位,$a1 也会被使用;
  • 浮点数 返回值放在 $fa0 中,如果返回值超过 64 位,$fa1 也会被使用;
  • 如果返回值长度超过两个寄存器的长度,将返回值的地址存入 $a0,并通过该地址返回数据。

  • 栈的方向:栈是向下增长的,栈指针必须 16 字节对齐。
  • 栈指针初始位置:函数入口处,栈指针应该指向传递给它的第一个参数(如果有参数)。
  • 栈的布局:从高到低依次是:参数、保存的返回地址、保存的寄存器、局部变量。并非所有部分都必须存在,如某个函数可以不接受参数,或不需要保存返回地址和寄存器等。
  • 栈操作规范:在函数中,应先对栈指针做减法来分配空间,然后再使用这段空间;不应对低于栈指针的数据作出保证。