如何创建一个不会破坏严格别名的uint8_t数组? [英] How to create an uint8_t array that does not undermine strict aliasing?
问题描述
我最近问过这个问题:
问题是我正在写一个类型的数组 uint8_t
,并且编译器将其视为可以使用方法的 this
指针$ c> struct T * ),因为 void *
和 code> uint8_t *
)可以总是别名C ++中的任何其他指针。此行为导致错过优化机会。我想避免这一点,当然。所以问题是:我可以声明一个强制执行严格别名的 uint8_t
数组,即编译器将其视为从未使用任何其他类型的指针别名吗?也就是说,我正在寻找类似于 strict_uint8_t
类型的类,它是一个具有特殊别名行为的 uint8_t
。是否有办法实现这一点?
示例代码显示我的意思,借用其他问题和简化。有关详细信息,请阅读链接的问题及其接受的答案:
struct T {
uint8_t * target;
void unpack3bit(char * source,int size){
while(size> 0){
uint64_t t = * reinterpret_cast< uint64_t *>
/ **`this-> target`不能被缓存在这里的寄存器中,但
被重载16次,因为编译器
认为`this-> target`可能是别名与this本身。
我想要的是一个特殊的uint8_t类型,不会触发
这种行为。 * /
this-> target [0] = t& 0x7;
this-> target [1] =(t>> 3)& 0x7;
this-> target [2] =(t>> 6)& 0x7;
this-> target [3] =(t>> 9)& 0x7;
this-> target [4] =(t>> 12)& 0x7;
this-> target [5] =(t>> 15)& 0x7;
this-> target [6] =(t>> 18)& 0x7;
this-> target [7] =(t>> 21)& 0x7;
this-> target [8] =(t>> 24)& 0x7;
this-> target [9] =(t>> 27)& 0x7;
this-> target [10] =(t>> 30)& 0x7;
this-> target [11] =(t>> 33)& 0x7;
this-> target [12] =(t>> 36)& 0x7;
this-> target [13] =(t>> 39)& 0x7;
this-> target [14] =(t>> 42)& 0x7;
this-> target [15] =(t>> 45)& 0x7;
Source + = 6;
size- = 6;
target + = 16;
}
}
};
您可以使用 struct :
<$
类型p $ p> struct X {uint8_t i:CHAR_BIT; X(uint8_t i):i(i){}};
这似乎消除了别名pessimization(用gcc 4.9.0测试): http://goo.gl/S1NbsB
即使 [t] bit-field属性不是类成员类型的一部分( [class.bit] / 1)使成员位字段似乎必要de -pessimize the generated code。
I recently asked this question:
Using this pointer causes strange deoptimization in hot loop
The problem was that I was writing to an array of type uint8_t
and the compiler treated it as if it could alias with the this
pointer of the method (of type struct T*
), because void*
and char*
(=uint8_t*
) can always alias any other pointer in C++. This behaviour caused a missed optimization opportunity. I want to avoid this, of course. So the question is: Can I declare an uint8_t
array that enforces strict aliasing, i.e., that the compiler treats as never aliased with any pointer of another type? I.e., I am looking for something like a strict_uint8_t
type that is an uint8_t
with special aliasing behaviour. Is there a way to achieve this?
Example code to show what I mean, borrowed from other question and simplified. For more details, read the linked question and its accepted answer:
struct T{
uint8_t* target;
void unpack3bit(char* source, int size) {
while(size > 0){
uint64_t t = *reinterpret_cast<uint64_t*>(source);
/** `this->target` cannot be cached in a register here but has
to be reloaded 16 times because the compiler
thinks that `this->target` could alias with `this` itself.
What I want is a special uint8_t type that does not trigger
this behaviour. */
this->target[0] = t & 0x7;
this->target[1] = (t >> 3) & 0x7;
this->target[2] = (t >> 6) & 0x7;
this->target[3] = (t >> 9) & 0x7;
this->target[4] = (t >> 12) & 0x7;
this->target[5] = (t >> 15) & 0x7;
this->target[6] = (t >> 18) & 0x7;
this->target[7] = (t >> 21) & 0x7;
this->target[8] = (t >> 24) & 0x7;
this->target[9] = (t >> 27) & 0x7;
this->target[10] = (t >> 30) & 0x7;
this->target[11] = (t >> 33) & 0x7;
this->target[12] = (t >> 36) & 0x7;
this->target[13] = (t >> 39) & 0x7;
this->target[14] = (t >> 42) & 0x7;
this->target[15] = (t >> 45) & 0x7;
source+=6;
size-=6;
target+=16;
}
}
};
You can use a struct
type (i.e. a strong typedef) backed by a bitfield with base type uint8_t
:
struct X { uint8_t i : CHAR_BIT; X(uint8_t i) : i(i) {} };
This appears to eliminate the aliasing pessimization (tested with gcc 4.9.0): http://goo.gl/S1NbsB
Even though "[t]he bit-field attribute is not part of the type of the class member" ([class.bit]/1) making the member a bit-field seems necessary to de-pessimize the generated code.
这篇关于如何创建一个不会破坏严格别名的uint8_t数组?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!