使用 LLVM 进行整数溢出捕获?

Integer overflow trapping with LLVM?

我正在创建一种静态编译的编程语言,我正在使用 LLVM 作为其后端。每当发生整数溢出时,我希望我的语言 trap/crash。

我知道像 llvm.sadd.with.overflow, but I don't think that's an optimal/efficient solution. That function returns a struct of two values, instead of just giving me direct access to the OF register flag. Ideally, after each arithmetic operation I would just have a "JO" assembly instruction to trap whenever integer overflow occurs. This is exactly what clang's UndefinedBehaviorSanitizer 这样的事情。但是,我正在编译为 LLVM IR,而不是 C 或 C++。

如何直接在 LLVM IR 中使用 UndefinedBehaviorSanitizer(或完成类似的事情)来处理整数溢出?

I'm aware of things like llvm.sadd.with.overflow, but I don't think that's an optimal/efficient solution. [...] Ideally, after each arithmetic operation I would just have a "JO" assembly instruction to trap whenever integer overflow occurs. This is exactly what clang's UndefinedBehaviorSanitizer does.

UndefinedBehaviorSanitizer 所做的是生成对 llvm.sadd.with.overflow 的调用。您可以通过使用 -fsanitize=undefined 编译以下 C 程序并查看生成的 LLVM 代码来轻松验证这一点:

bla.c:

#include <stdio.h>

int main(void){
  int x;
  scanf("%d", &x);
  printf("%d\n", x+1);
  return 0;
}

命令行:

clang -fsanitize=undefined -emit-llvm -O2 -S bla.c

bla.ll(节选):

  %5 = call { i32, i1 } @llvm.sadd.with.overflow.i32(i32 %4, i32 1), !nosanitize !8
  %6 = extractvalue { i32, i1 } %5, 0, !nosanitize !8
  %7 = extractvalue { i32, i1 } %5, 1, !nosanitize !8
  br i1 %7, label %8, label %10, !prof !9, !nosanitize !8

; <label>:8:                                      ; preds = %0
  %9 = zext i32 %4 to i64, !nosanitize !8
  call void @__ubsan_handle_add_overflow(i8* bitcast ({ { [6 x i8]*, i32, i32 }, { i16, i16, [6 x i8] }* }* @1 to i8*), i64 %9, i64 1) #5, !nosanitize !8

sadd.with.overflow 将作为常规 incl 指令¹结束,而 br i1 %7 作为生成的 x64 程序集中的 jo,这正是您想要的。


¹ 当然,如果我在 C 代码中添加了 1 以外的内容,这将是一个正确的添加指令。