icmp仅用于整数比较,fcmp专用于浮点比较;二者操作数类型、语义规则(如nan处理)、谓词集均不同,混用将导致编译错误或未定义行为。

icmp只处理整数比较,fcmp专用于浮点数
LLVM IR 中的 icmp 和 fcmp 是两类完全独立的比较指令,底层语义、操作数类型、返回值行为都不同。混淆二者会导致编译失败或运行时未定义行为——比如对浮点数用 icmp,Clang 会报错 invalid operand types for icmp;反之对整数用 fcmp 同样不合法。
-
icmp只接受整数类型(i1,i8,i32,i64等),比较结果是i1(布尔) -
fcmp只接受浮点类型(float,double,fp128等),返回值也是i1,但语义依赖 IEEE 754 的有序/无序(ordered/unordered)判定 - 两者都支持多种谓词(如
eq,ne,lt,gt),但fcmp多出oeq/one/olt/ogt(ordered)和ueq/une/ult/ugt(unordered)之分,用来显式处理 NaN
有符号 vs 无符号不是 icmp 和 fcmp 的区别,而是 icmp 内部的细分
新手常误以为 icmp slt 和 fcmp olt 是“对应关系”,其实它们解决的是不同维度的问题:slt/ult 区分的是整数的**符号解释方式**,而 olt/ult 区分的是浮点比较是否容忍 NaN(即是否要求 operands 都是有序值)。
- 整数比较必须明确指定有/无符号:用
slt比较-1和0返回true,用ult则返回false(因为-1的位模式作为无符号数远大于0) - 浮点比较必须明确指定有序性:用
fcmp olt比较NaN和任意数,结果是false;用fcmp ult则结果是true(因为 NaN 是无序的,“un”前缀表示“只要有一个无序就成立”) - 没有
fcmp slt或icmp olt这种写法——语法直接拒绝
生成 IR 时 clang 默认选哪个,取决于源码类型和优化级别
你写的 C/C++ 代码里一个 a 表达式,最终生成 <code>icmp 还是 fcmp,完全由变量声明类型决定,跟编译选项无关;但具体用哪个谓词(比如 slt 还是 ult,olt 还是 ult),可能受 -ffast-math 影响。
- 整型变量:一定生成
icmp,且 clang 会根据上下文推断符号性(int→slt,unsigned int→ult) - 浮点变量:一定生成
fcmp,默认用olt/ogt等 ordered 谓词(符合 IEEE 严格语义) - 加了
-ffast-math后,clang 可能将fcmp olt降级为fcmp ult,甚至在某些场景下省略 NaN 检查,以换取性能 - 手动写 IR 时,必须显式匹配类型和谓词,否则
llvm-as直接报错
调试时看到 icmp/fcmp 行为异常,先检查类型和谓词是否匹配
最常见的实际问题不是指令写错,而是类型隐式转换没被注意到。例如把 size_t(通常是 unsigned long)和 int 比较,在 C 源码里看似自然,但 IR 层面会触发整数提升和符号扩展,导致 icmp 的谓词选择出人意料。
- 用
clang -S -emit-llvm看生成的.ll文件,确认操作数类型是否如你预期(比如i64还是float) - 检查谓词是否与语义一致:需要处理无符号循环索引?用
ult;需要安全比较浮点结果是否有效?优先用oeq而非eq -
fcmp的ord/uno谓词常被忽略,但它才是判断 “a 是否为 NaN” 的标准方式(%nan = fcmp uno float %a, %a)











