跳转至

FEXIT

说明

函数出口(Function Exit)
本指令更新栈指针寄存器(SP)后,从新指针指向的内存中连续加载 8 字节数据,写入由起止寄存器指定的连续寄存器组。

该指令用于函数出口的收栈操作(Function Epilogue)。

汇编语法

    FEXIT [DstBegin ~ DstEnd], sp!, uimm

汇编符号

  • sp!:栈指针寄存器,块内部会更新该寄存器值。
  • uimm:表示收栈空间大小的立即数(以8字节为单位),该参数编码于uimm[14:3]字段。
  • DstBegin ~ DstEnd:指示出栈起止寄存器,表示R2至R23中一段连续的寄存器。

注意!

当DstBegin的索引大于DstEnd的索引时,出栈寄存器顺序会发生卷绕。具体而言就是先将DstBegin至R23出栈,再将R2至DstEnd出栈。

编码格式

FEXIT

执行方式

  • 产生指令并push到指令队列:Generate()
  • 转换为十进制数:UInt()

硬件模板块状态机会将该指令展开为以下微指令去执行:

bits(15) immediate = uimm << 3;

if immediate[14:12] != 0 then
    Generate(lui immediate[14:12], ->t);
    Generate(addi t#1, immediate[11:0], ->t);
    Generate(add sp, t#1, ->sp);
else
    Generate(addi sp, immediate[11:0], ->sp);

integer M = UInt(DstBegin);
integer N = UInt(DstEnd);
integer offset = -8;

// 如果DstEnd 编码小于 DstBegin,那么出栈寄存器发生卷绕
if M > N then N += 24;

foreach (i from M to N by 1 in dec)
    integer idx = i % 24;
    if idx == 0 || idx == 1 then continue;
    Generate(ldi [sp, offset], -> R[idx]);
    offset -= 8;

stackspace

汇编示例

出栈寄存器顺序未发生卷绕的场景,以块指令 f.exit [s0 ~ s6], sp!, 72 为例:

addi sp, 72, ->sp

ldi [sp,  -8], ->s0     ; 从栈上load至R11
ldi [sp, -16], ->s1     ; 从栈上load至R12
ldi [sp, -24], ->s2     ; 从栈上load至R13
ldi [sp, -32], ->s3     ; 从栈上load至R14
ldi [sp, -40], ->s4     ; 从栈上load至R15
ldi [sp, -48], ->s5     ; 从栈上load至R16
ldi [sp, -56], ->s6     ; 从栈上load至R17

出栈寄存器顺序发生卷绕的场景,以块指令 f.exit [x0 ~ a7], sp!, 104 为例:

addi sp, 104, ->sp

ldi [sp,  -8], ->x0     ; 从栈上load至R20
ldi [sp, -16], ->x1     ; 从栈上load至R21
ldi [sp, -24], ->x2     ; 从栈上load至R22
ldi [sp, -32], ->x3     ; 从栈上load至R23
ldi [sp, -40], ->a0     ; 从栈上load至R2(发生卷绕)
ldi [sp, -48], ->a1     ; 从栈上load至R3
ldi [sp, -56], ->a2     ; 从栈上load至R4
ldi [sp, -64], ->a3     ; 从栈上load至R5
ldi [sp, -72], ->a4     ; 从栈上load至R6
ldi [sp, -80], ->a5     ; 从栈上load至R7
ldi [sp, -88], ->a6     ; 从栈上load至R8
ldi [sp, -96], ->a7     ; 从栈上load至R9

注意事项

  • 本块指令的跳转类型为顺延(Fall)

块指令展开微指令数计算

该模板块展开的微指令数计算公式为:InstCount = cnt1(更新sp寄存器指令数) + cnt2(出栈指令数)

// 更新sp寄存器指令数
integer cnt1 = (uimm > 4088 ? 3 : 1);
// 出栈指令数
integer M = UInt(DstBegin), N = UInt(DstEnd);
integer cnt2 = (M <= N ? (N - M + 1) : (23 - M + N))

备注

此指令属于模板块指令。