题
我是新来使用SSE / SSE2指令集优化代码,直至现在我已经不是很远得到。据我所知,共同SSE优化的功能是这样的:
void sse_func(const float* const ptr, int len){
if( ptr is aligned )
{
for( ... ){
// unroll loop by 4 or 2 elements
}
for( ....){
// handle the rest
// (non-optimized code)
}
} else {
for( ....){
// regular C code to handle non-aligned memory
}
}
}
然而,如何正确地确定存储器ptr
点到由例如对准16个字节?我想我必须包括不结盟内存常规的C代码路径,因为我不能确保传递给这个函数的每个内存将保持一致。以及使用该内在函数来从未对齐的内存数据加载到SSE寄存器似乎是可怕慢(甚至比常规的C代码更慢)。
感谢您提前...
解决方案
编辑:铸造long
是为了保护自己不受int和指针是不同尺寸时下最有可能的可能性,一种廉价的方式。
由于在下面的评论中指出,有更好的解决方案,如果你愿意,包括头...
一个指针p
上一个16字节边界IFF ((unsigned long)p & 15) == 0
对齐。
其他提示
#define is_aligned(POINTER, BYTE_COUNT) \
(((uintptr_t)(const void *)(POINTER)) % (BYTE_COUNT) == 0)
在浇铸到void *
(或,equivalenty,char *
)是必要的,因为标准只保证可逆转换为uintptr_t
void *
。
如果你想要的类型安全,可以考虑使用内联函数:
static inline _Bool is_aligned(const void *restrict pointer, size_t byte_count)
{ return (uintptr_t)pointer % byte_count == 0; }
和希望编译器优化如果byte_count
是一个编译时间常数。
为什么我们需要转换为 void *
?
在C语言允许对不同的指针类型不同的表示,例如,你可以有一个64位void *
类型(整个地址空间)和一个32位foo *
类型(段)。
转换foo *
- > void *
可能涉及一个实际的计算中,例如将偏移。该标准还保留这些给转换(任意)指向整数时会发生什么执行,但我怀疑它常被作为一个空操作执行。
有关这样的实现,foo *
- > uintptr_t
- > foo *
将工作,但foo *
- > uintptr_t
- > void *
和void *
- > uintptr_t
- > foo *
不会。对准计算也将无法可靠地工作,因为你只检查相对于段偏移,这可能会或可能不是你想要的是比对。
在结论:始终使用void *
得到实现,独立的行为
其他的答案提示与操作与设定为低位,并且与零进行比较。
但是,更直接的测试将是做一个MOD与期望的对准值,并比较为零。
#define ALIGNMENT_VALUE 16u
if (((uintptr_t)ptr % ALIGNMENT_VALUE) == 0)
{
// ptr is aligned
}
使用类似
的函数模板#include <type_traits>
template< typename T >
bool is_aligned(T* p){
return !(reinterpret_cast<uintptr_t>(p) % std::alignment_of<T>::value);
}
您可以通过调用类似检查在运行时对准
struct foo_type{ int bar; }foo;
assert(is_aligned(&foo)); // passes
要检查坏的比对失败,你可以做
// would almost certainly fail
assert(is_aligned((foo_type*)(1 + (uintptr_t)(&foo)));
这基本上是我使用的是什么。通过使整数一个模板,我保证它的扩展编译时间,所以我不会有一个缓慢的模运算无论我做什么结束了。
我总是像检查我输入,所以因此编译时断言。如果你的定位值是错误的,还有那么它将不能编译...
template <unsigned int alignment>
struct IsAligned
{
static_assert((alignment & (alignment - 1)) == 0, "Alignment must be a power of 2");
static inline bool Value(const void * ptr)
{
return (((uintptr_t)ptr) & (alignment - 1)) == 0;
}
};
要看看发生了什么事情,你可以使用这样的:
// 1 of them is aligned...
int* ptr = new int[8];
for (int i = 0; i < 8; ++i)
std::cout << IsAligned<32>::Value(ptr + i) << std::endl;
// Should give '1'
int* ptr2 = (int*)_aligned_malloc(32, 32);
std::cout << IsAligned<32>::Value(ptr2) << std::endl;
你能只是“和” 0×03与在PTR(4S上对齐),0×07(上787-8对齐)或为0x0F(16S上对齐),以查看是否有任何的最低位被设置?
把这种方式留给专业人员,
bool is_aligned(const void* ptr, std::size_t alignment) noexcept;
示例:
char D[1];
assert( boost::alignment::is_aligned(&D[0], alignof(double)) ); // might fail, sometimes
如何:
void *mem = malloc(1024+15);
void *ptr =( (*(char*)mem) - (*(char *)mem % 16) );