如果在编译时已知边缘条件,如何省略调用?
我遇到以下情况:有一大堆模板,例如 std::vector ,它们将调用 memmove() 来移动数组的一部分。有时他们会想要“移动”长度为零的部分 - 例如,如果数组尾部被删除(如 std::vector::erase()),他们会想要移动数组的其余部分的长度恰好为零,并且在编译时将知道该零(我看到了反汇编 - 编译器知道),但编译器仍会发出 memmove()< /代码> 调用。
所以基本上我可以有一个包装器:
inline void callMemmove( void* dest, const void* source, size_t count )
{
if( count > 0 ) {
memmove( dest, source, count );
}
}
但这会引入额外的运行时检查,以防在我不想要的编译时未知的情况下。
是否可以使用 __assume 提示 向编译器表明,如果它确定 count
为零,则应该消除 memmove()
?
I have the following situation: there's a huge set of templates like std::vector
that will call memmove()
to move parts of array. Sometimes they will want to "move" parts of length zero - for example, if the array tail is removed (like std::vector::erase()
), they will want to move the remainder of the array which will happen to have length zero and that zero will be known at compile time (I saw the disassembly - the compiler is aware) yet the compiler will still emit a memmove()
call.
So basically I could have a wrapper:
inline void callMemmove( void* dest, const void* source, size_t count )
{
if( count > 0 ) {
memmove( dest, source, count );
}
}
but this would introduce an extra runtime check in cases count
is not known in compile time that I don't want.
Is it somehow possible to use __assume hint to indicate to the compiler that if it knows for sure that count
is zero it should eliminate the memmove()
?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
![扫码二维码加入Web技术交流群](/public/img/jiaqun_03.jpg)
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(4)
__assume
的目的是告诉编译器在优化时跳过部分代码。在您提供的链接中,示例是通过switch
构造的default
子句给出的 - 提示告诉编译器该子句永远不会被达到,即使理论上它可以。基本上,您是在告诉优化器,“嘿,我知道得更好,扔掉这段代码”。对于
default
,你不能不写它(除非你覆盖了case
中的整个范围,这有时会出现问题),因为这会导致编译错误。因此,您需要提示来优化您知道不需要的代码。在您的情况下 - 代码可以到达,但并非总是如此,因此
__assume
提示不会对您有太大帮助。您必须检查count
是否真的为 0。除非您确定它永远不会是 0 以外的任何值,否则就不要将其写入。The point of the
__assume
is to tell the compiler to skip portions of code when optimizing. In the link you provided the example is given with thedefault
clause of theswitch
construct - there the hint tells the compiler that the clause will never be reached even though theoretically it could. You're telling the optimizer, basically, "Hey, I know better, throw this code away".For
default
you can't not write it in (unless you cover the whole range incase
s, which is sometimes problematic) because it would cause compilation error. So you need the hint to optimize the code you know that is unneeded out.In your case - the code can be reached, but not always, so the
__assume
hint won't help you much. You have to check if thecount
is really 0. Unless you're sure it can never be anything but 0, then just don't write it in.此解决方案使用 C++ 编译时常量检测 中描述的技巧 - 该技巧使用事实上,编译时整数零可以转换为指针,并且这可以与重载一起使用来检查“编译时已知”属性。
或者,在您的情况下,由于您只想检查零,因此可以直接使用 is_const_0 以获得最大的简单性和可移植性:
注意:此处的代码使用了比链接问题中更简单的 is_const 版本。这是因为在这种情况下,Visual Studio 比 GCC 更符合标准。如果针对 gcc,您可以使用以下 is_const 变体(适合处理所有可能的整数值,包括负值和 INT_MAX):
This solution uses a trick described in C++ compile-time constant detection - the trick uses the fact compile time integer zero can be converted to a pointer, and this can be used together with overloading to check for the "compile time known" property.
Or, in your case, as you want to check for zero only anyway, one could use is_const_0 directly for maximum simplicity and portability:
Note: the code here used a version of is_const simpler than in the linked question. This is because Visual Studio is more standard conformant than GCC in this case. If targeting gcc, you could use following is_const variant (adapted to handle all possible integral values, including negative and INT_MAX):
我认为您误解了
__assume
的含义。当编译器知道值是什么时,它不会告诉编译器改变其行为,而是告诉它当编译器无法自行推断时值将是什么。就您而言,如果您告诉它
__assume
,则count > > 0
它将跳过测试,因为您已经告诉它结果将始终为true
,它将删除条件并调用memmove
总是,这正是您想要避免的。我不知道 VS 的内在函数,但在 GCC 中有一个可能/不可能内在函数 (
__builtin_expect((x),1)
) 可用于 < em>提示编译器哪个是测试最可能的结果。这不会删除测试,但会布局代码,以便最可能(如根据您的定义)分支更加高效(不会分支)。I think that you misunderstood the meaning of
__assume
. It does not tell the compiler to change its behavior when it knows what the values are, but rather it tells it what the values will be when it cannot infer it by itself.In your case, if you told it to
__assume
thatcount > 0
it will skip the test, as you already told it that the result will always betrue
, it will remove the condition and will callmemmove
always, which is exactly what you want to avoid.I don't know the intrinsics of VS, but in GCC there is a likely/unlikely intrinsic (
__builtin_expect((x),1)
) that can be used to hint the compiler as to which is the most probable outcome of the test. that will not remove the test, but will layout code so that the most probable (as in by your definition) branch is more efficient (will not branch).如果可以重命名memmove,我想是这样的
会做 - http://codepad.org/s974Fp9k
我认为没有课程也是可能的 - 必须查看转换规则
来确认。
此外,应该可以重载原始的 memmove(),例如。通过通过
对象(如 Temp(sizeof(a)) 作为第三个参数。
不确定哪种方式更方便。
If its possible to rename the memmove, I think something like this
would do - http://codepad.org/s974Fp9k
I think the same is probably possible without the class - have to look at conversion rules
to confirm it.
Also it should be possible to overload the original memmove(), eg. by passing an
object (like Temp(sizeof(a)) as 3rd argument.
Not sure which way would be more convenient.