浮点运算作为现代处理器的基础功能,其实现质量直接影响科学计算、图形渲染等关键领域的性能。ARM架构从v7开始引入硬件浮点运算单元(VFP),到v8时已形成完整的浮点指令集。IEEE 754标准定义了浮点数的二进制表示和运算规则,主要包括三个部分:
在ARM架构中,浮点控制寄存器(FPCR)负责管理运算行为:
armasm复制FPCR结构:
| 位域 | 名称 | 功能描述 |
|------|--------|------------------------------|
| 24 | AH | 替代处理模式使能 |
| 23 | DN | 默认NaN模式 |
| 22 | FZ | 刷新到零模式 |
| 21 | RMode | 舍入模式(00:最近偶数 01:正无穷 10:负无穷 11:向零) |
| 20 | FZ16 | 半精度刷新到零 |
FPMax函数有三个重载版本,核心实现处理16/32/64位浮点数比较:
pseudocode复制func FPMax{N}(op1: bits(N), op2: bits(N), fpcr_in: FPCR_Type,
altfp: boolean, fpexc: boolean) => bits(N)
参数说明:
op1/op2:待比较的浮点数(N=16/32/64)fpcr_in:浮点控制寄存器状态altfp:是否启用替代浮点行为(受FPCR.AH控制)fpexc:是否触发浮点异常pseudocode复制let (type1,sign1,value1) = FPUnpack{N}(op1, fpcr, fpexc);
let (type2,sign2,value2) = FPUnpack{N}(op2, fpcr, fpexc);
FPUnpack将二进制浮点拆解为三部分:
pseudocode复制if altfp && type1 == FPType_Zero && type2 == FPType_Zero && sign1 != sign2 then
return FPZero{N}(sign2); // 返回第二个操作数的符号
elsif altfp && (type1是NaN || type2是NaN) then
if fpexc then FPProcessException(FPExc_InvalidOp, fpcr); end;
return (if type2 == FPType_Zero then FPZero{N}(sign2) else op2);
end;
AFP扩展下的特殊规则:
pseudocode复制(done,result) = FPProcessNaNs{N}(type1, type2, op1, op2, fpcr, fpexc);
if !done then
// 常规数值比较逻辑
if value1 > value2 then
(fptype,sign,value) = (type1,sign1,value1);
else
(fptype,sign,value) = (type2,sign2,value2);
end;
// ...后续处理
end;
NaN处理优先级:
若任一操作数为SNaN,触发无效操作异常
若启用AFP且双操作数均为NaN,返回第一个NaN
单个QNaN时返回非NaN操作数
结果舍入:
pseudocode复制let rounding : FPRounding = FPRoundingMode(fpcr);
result = FPRound{N}(value, fpcr, rounding, fpexc);
舍入模式由FPCR.RMode控制:
FPMin与FPMax的核心差异在于比较逻辑和零值符号处理:
pseudocode复制// FPMax的零值符号处理
sign = sign1 AND sign2; // 取最正值
// FPMin的零值符号处理
sign = sign1 OR sign2; // 取最负值
// 数值比较逻辑
if value1 < value2 then // FPMax使用>比较
(fptype,sign,value) = (type1,sign1,value1);
else
(fptype,sign,value) = (type2,sign2,value2);
end;
pseudocode复制if altfp && N != 16 && (type1 == FPType_Denormal || type2 == FPType_Denormal) then
FPProcessException(FPExc_InputDenorm, fpcr);
end;
反规范数(Denormal)指指数全零时的非规约形式:
当FPCR.AH=1时启用:
pseudocode复制if altfp && op1_nan && op2_nan then
result = FPProcessNaN{N}(type_nan, op1, fpcr, fpexc);
end;
通过泛型参数N实现16/32/64位统一处理:
pseudocode复制assert N IN {16,32,64};
let E : integer = (if N == 16 then 5 else (if N == 32 then 8 else 11));
let F : integer = N - (E + 1);
pseudocode复制(done,result) = FPProcessNaNs(...);
if !done then // 无NaN时才执行完整比较
// 主比较逻辑
end;
pseudocode复制if likely(value1 > value2) then // 伪代码示意
// 优先处理路径
end;
pseudocode复制let (type1,sign1,value1) = FPUnpack(op1...); // 并行解包
let (type2,sign2,value2) = FPUnpack(op2...);
FPCR控制的异常类型:
pseudocode复制enum FPExc {
InvalidOp = 0, // 无效操作(如0*∞)
DivideByZero = 1, // 除零
Overflow = 2, // 上溢
Underflow = 3, // 下溢
Inexact = 4, // 精度损失
InputDenorm = 7 // 反规范数输入
}
异常处理流程:
armasm复制// ARM NEON示例
FMAX Vd.4S, Vn.4S, Vm.4S // 同时比较4个单精度浮点
c复制// 使用FPMax实现快速比较
float vec_max(float a, float b) {
float ret;
asm("fmax %s0, %s1, %s2" : "=w"(ret) : "w"(a), "w"(b));
return ret;
}
关键提示:在启用AFP扩展的芯片(如Cortex-X2)上,零值比较性能可提升约15%,但需注意结果与IEEE标准的差异。