Мне известны такие вещи, как llvm.sadd.with.overflow, но я не думаю, что это оптимальное / эффективное решение. [...] В идеале, после каждой арифметической операции у меня должна быть просто инструкция сборки "JO", чтобы перехватывать всякий раз, когда происходит целочисленное переполнение. Это именно то, что делает UndefinedBehaviorSanitizer clang.
Что UndefinedBehaviorSanitizer делает, это генерирует вызовы к llvm.sadd.with.overflow
. Вы можете легко это проверить, скомпилировав следующую программу на C с -fsanitize=undefined
и просмотрев сгенерированный код 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
как jo
в сгенерированной сборке x64, так что это именно то, что вам нужно.
¹ Было бы правильно добавить инструкцию, если бы я добавил что-то, кроме 1, в коде C, конечно.