ARM64 CSEL条件 B条件一览
其实整体概括下来,就是两个寄存器比大小,按照不同的格式(有符号,无符号)比
条件选择
(Conditional Selection, CSEL)
示例
CSEL X3, X1, X2, EQ
在这个例子中,如果条件码
EQ
为真(即条件寄存器的标志指示相等),那么X3
将被赋值为X1
的值,否则将被赋值为X2
的值。
- EQ (Equal): 零标志(Z)被设置,即结果为零。
- NE (Not Equal): 零标志(Z)没有被设置,即结果不为零。
- CS/HS: Carry Set/Unsigned Higher or Same: 进位标志(C)被设置,用于无符号比较(大于或等于)。
- CC/LO: Carry Clear/Unsigned Lower: 进位标志(C)没有被设置,用于无符号比较(小于)。
- MI (Minus): 负标志(N)被设置,表示结果为负。
- PL (Plus): 负标志(N)没有被设置,表示结果为正或零。
- VS (Overflow Set): 溢出标志(V)被设置。
- VC (Overflow Clear): 溢出标志(V)没有被设置。
- HI (Unsigned Higher): 进位标志(C)被设置且零标志(Z)没有被设置,用于无符号比较(严格大于)。
- LS (Unsigned Lower or Same): 进位标志(C)没有被设置或零标志(Z)被设置,用于无符号比较(小于或等于)。
- GE (Signed Greater than or Equal): 负标志(N)等于溢出标志(V),用于有符号比较(大于或等于)。
- LT (Signed Less Than): 负标志(N)不等于溢出标志(V),用于有符号比较(小于)。
- GT (Signed Greater Than): 零标志(Z)没有被设置且负标志(N)等于溢出标志(V),用于有符号比较(严格大于)。
- LE (Signed Less than or Equal): 零标志(Z)被设置或负标志(N)不等于溢出标志(V),用于有符号比较(小于或等于)。
- AL (Always): 总是执行,无条件。
- NV (Never): 从不执行,通常不使用。
条件跳转
分支跳转(分支 Branch, B)
示例
假设我们有两个整数,想要比较它们的大小并根据比较结果执行不同的代码:
MOV X0, #5 // 将值5加载到寄存器X0 MOV X1, #10 // 将值10加载到寄存器X1 CMP X0, X1 // 比较X0和X1 B.EQ equal_label // 如果X0等于X1,跳转到equal_label B.GT greater_label // 如果X0大于X1,跳转到greater_label B.LT less_label // 如果X0小于X1,跳转到less_label equal_label: // 这里的代码将在X0等于X1时执行 MOV X2, #0 // 将0加载到X2 B end_label // 跳转到结束标签 greater_label: // 这里的代码将在X0大于X1时执行 MOV X2, #1 // 将1加载到X2 B end_label // 跳转到结束标签 less_label: // 这里的代码将在X0小于X1时执行 MOV X2, #-1 // 将-1加载到X2 end_label: // 结束标签,程序在这里继续执行
解释
比较操作:
CMP X0, X1
:比较寄存器X0
和X1
的值,设置条件标志。条件跳转:
B.EQ equal_label
:如果X0
等于X1
,则跳转到equal_label
。B.GT greater_label
:如果X0
大于X1
,则跳转到greater_label
。B.LT less_label
:如果X0
小于X1
,则跳转到less_label
。执行不同的代码块:
- 在每个标签(
equal_label
、greater_label
、less_label
)处,根据比较结果执行不同的代码。结束跳转:
- 使用
B end_label
确保在执行完某个条件下的代码后跳转到程序的结束部分。
- B.EQ (Equal): 当零标志(Z)被设置时跳转,即相等时跳转。
- B.NE (Not Equal): 当零标志(Z)没有被设置时跳转,即不相等时跳转。
- B.HS (Unsigned Higher or Same): 当进位标志(C)被设置时跳转,用于无符号比较(大于或等于)。
- B.LO (Unsigned Lower): 当进位标志(C)没有被设置时跳转,用于无符号比较(小于)。
- B.MI (Minus): 当负标志(N)被设置时跳转,表示结果为负。
- B.PL (Plus): 当负标志(N)没有被设置时跳转,表示结果为正或零。
- B.VS (Overflow Set): 当溢出标志(V)被设置时跳转。
- B.VC (Overflow Clear): 当溢出标志(V)没有被设置时跳转。
- B.HI (Unsigned Higher): 当进位标志(C)被设置且零标志(Z)没有被设置时跳转,用于无符号比较(严格大于)。
- B.LS (Unsigned Lower or Same): 当进位标志(C)没有被设置或零标志(Z)被设置时跳转,用于无符号比较(小于或等于)。
- B.GE (Signed Greater than or Equal): 当负标志(N)等于溢出标志(V)时跳转,用于有符号比较(大于或等于)。
- B.LT (Signed Less Than): 当负标志(N)不等于溢出标志(V)时跳转,用于有符号比较(小于)。
- B.GT (Signed Greater Than): 当零标志(Z)没有被设置且负标志(N)等于溢出标志(V)时跳转,用于有符号比较(严格大于)。
- B.LE (Signed Less than or Equal): 当零标志(Z)被设置或负标志(N)不等于溢出标志(V)时跳转,用于有符号比较(小于或等于)。
关于CMP指令
在ARM64架构中,CMP
指令用于比较两个寄存器的值,它实际上是一个“减法”操作,不存储结果,只更新条件标志寄存器(CPSR)的状态标志。具体来说,CMP
指令会影响以下几个标志:
-
N(负标志):
- 当结果为负数时,N标志被设置。
- 具体来说,如果减法结果的最高有效位(即符号位)为1,则N标志被设置。
-
Z(零标志):
- 当结果为零时,Z标志被设置。
- 如果两个操作数相等,结果为零,Z标志被设置。
-
C(进位标志):
- 在无符号数减法中,如果借位发生,C标志被清除;如果没有借位,C标志被设置。
- 具体来说,C标志被设置当被减数大于等于减数(即没有借位)时。
-
V(溢出标志):
- 在有符号数减法中,如果结果超出了表示范围(例如,从正数溢出到负数或从负数溢出到正数),V标志被设置。
- 具体来说,如果被减数和减数的符号不同,而结果的符号与被减数的符号不同,则V标志被设置。
示例 1:无符号比较
假设我们有两个无符号整数X0
和X1
:
MOV X0, #8 // X0 = 8
MOV X1, #5 // X1 = 5
CMP X0, X1 // 比较 X0 和 X1
- N标志:未设置,因为8 - 5 = 3,结果为正。
- Z标志:未设置,因为8不等于5。
- C标志:设置,因为8大于5,无借位。
- V标志:未设置,因为无符号比较不涉及溢出。
示例 2:相等比较
MOV X0, #10 // X0 = 10
MOV X1, #10 // X1 = 10
CMP X0, X1 // 比较 X0 和 X1
- N标志:未设置,因为10 - 10 = 0,结果非负。
- Z标志:设置,因为10等于10,结果为零。
- C标志:设置,因为10大于或等于10,无借位。
- V标志:未设置,因为没有溢出。
示例 3:负数结果(有符号比较)
假设我们有两个有符号整数X0
和X1
:
MOV X0, #-3 // X0 = -3
MOV X1, #2 // X1 = 2
CMP X0, X1 // 比较 X0 和 X1
- N标志:设置,因为-3 - 2 = -5,结果为负。
- Z标志:未设置,因为-3不等于2。
- C标志:未设置,因为-3小于2,有借位。
- V标志:未设置,因为没有溢出。
示例 4:溢出情况
考虑有符号整数溢出:
MOV X0, #0x7FFFFFFF // X0 = 最大正数
MOV X1, #-1 // X1 = -1
CMP X0, X1 // 比较 X0 和 X1
- N标志:未设置,因为0x7FFFFFFF - (-1) = 0x80000000,结果为正。
- Z标志:未设置,因为0x7FFFFFFF不等于-1。
- C标志:设置,因为在无符号上下文中没有借位。
- V标志:设置,因为0x7FFFFFFF - (-1)导致从正数溢出到负数。