基于整数溢出的GCC优化 [英] GCC optimizations based on integer overflow

查看:80
本文介绍了基于整数溢出的GCC优化的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

最近,我讨论了一个想要检查带符号的int溢出的人,例如 if(A + B< 2 * max(A,B)).让我们先忽略一下逻辑本身是错误的,然后在C/C ++的上下文中讨论有符号整数溢出.(我相信这完全是从C继承了标准的这一部分).

当前的GCC将优化哪些需要带符号整数溢出的支票,而哪些不会呢?

由于原始文本的措辞不够完善,并且显然存在争议,因此我决定对问题进行一些更改,但将原始文本保留在下面.

下面使用的所有示例均经过gcc版本 4.7.2(Debian 4.7.2-5)的测试,并使用 -O3 进行编译>

即,它是未定义的,并且GCC臭名昭著地使用它来执行一些分支简化.我想到的第一个例子是

  int i = 1;而(i> 0){我* = 2;} 

产生无限循环.这种优化开始的另一种情况是

 如果(A + 2< A){/*处理潜在的溢出*/} 

其中,假设 A 是带符号整数类型,则溢出分支将被完全删除.

更有趣的是,一些容易实现可证明整数溢出的情况没有受到影响,例如

  if(INT_MAX + 1< 0){/*您不会明确地编写此代码,但是在对程序进行静态分析之后可能显示包含这样的内容.*/} 

会触发您期望以二进制补码表示的分支.同样,此代码使条件分支保持不变

  int C = abs(A);如果(A + C <0){/*为此,必须发生上溢或下溢.*/} 

现在要提出的问题是,有一种模式大致类似于 if(A + B< C) if(A + B< c),将被优化掉吗?当我在写这篇文章之前四处搜寻时,似乎应该对最后一个代码片段进行优化,但是我无法在未明确使用常量操作的溢出检查中重现这种错误.

解决方案

许多编译器会将涉及带符号整数或指针的表达式替换为"false",例如

  a + 1<一个//有符号整数ap + 1 <1p//指针p 

当表达式仅在未定义行为的情况下才为真时.另一方面,这允许

  for(字符* q = p; q< p + 2; ++ q)... 

内联

,将q = p和q = p + 1代替而无需任何检查,所以这是一件好事.

 如果(A + abs(A)< 0) 

对于许多编译器来说可能太复杂了.请注意,对于无符号整数,没有未定义的行为.结果,使用无符号32位整数和64位指针的循环会比必要的慢,因为必须考虑到环绕行为.对于无符号的32位整数和64位指针,

 & p [i]>& p [i + 1] 

没有未定义的行为(不带有64位整数或32位指针).

Recently I had a discussion about someone who wanted to check for signed int overflow like this if (A + B < 2 * max(A, B)). Lets ignore for a second that the logic itself is wrong and discuss signed integer overflow in context of C/C++. (Which I believe fully inherits this part of standard from C).

What kinds of check that need signed integer overflow will be optimized away by current-ish GCC and which won't?

Since the original text wasn't all that well formulated and apparently controversial I decided to change the question somewhat, but leave the original text below.

All examples used below were tested gcc version 4.7.2 (Debian 4.7.2-5) and compiled using -O3

Namely, it is undefined and GCC infamously uses this to perform some branch simplifications. The first example of this that comes to mind is

int i = 1;
while (i > 0){
    i *= 2;
}

which produces an infinite loop. Another case where this kind of optimalization kicks in is

if (A + 2 < A){
    /* Handle potential overflow */
}

where, assuming A is signed integral type, the overflow branch gets completely removed.

Even more interestingly, some cases of easily provable integer overflow, are left untouched, such as

if (INT_MAX + 1 < 0){
    /* You wouldn't write this explicitly, but after static analysis the program
       could be shown to contain something like this. */
}

which triggers the branch that you would expect with two's complement representation. Similarly, this code leaves the conditional branches intact

int C = abs(A);
if (A + C < 0){
    /* For this to be hit, overflow or underflow had to happen. */
}

Now for the question, is there a pattern that looks roughly like if (A + B < C) or if (A + B < c), that will be optimized away? When I was googling around before writing this, it seemed like the last snippet should be optimized away, but I cannot reproduce this kind of error in an overflow check that doesn't operate with constant explicitly.

解决方案

Many compilers will replace expressions involving signed integers or pointers with "false", like

a + 1 < a // signed integer a
p + 1 < p // Pointer p

when the expression can only be true in the case of undefined behaviour. On the other hand, that allows

for (char* q = p; q < p + 2; ++q) ...

to be inlined, substituting q = p and q = p + 1, without any check, so that's a good thing.

if (A + abs (A) < 0)

is probably too complicated for many compilers. Note that for unsigned integers there is no undefined behaviour. As a consequence, loops using unsigned 32 bit integers with 64 bit pointers tend to be slower than necessary because the wraparound behaviour must be taken into account. For unsigned 32 bit integer and 64 bit pointers, it is possible that

&p [i] > &p [i+1]

without undefined behaviour (not with 64 bit integers or 32 bit pointers).

这篇关于基于整数溢出的GCC优化的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆