use*_*898 40 c memory optimization sse simd
我是使用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
}
}
}
Run Code Online (Sandbox Code Playgroud)
但是,如何正确确定内存ptr点是否与16字节对齐?我认为我必须包含非对齐内存的常规C代码路径,因为我无法确保传递给此函数的每个内存都将对齐.使用内在函数将数据从未对齐的内存加载到SSE寄存器似乎非常慢(甚至比常规C代码慢).
先感谢您...
Chr*_*oph 49
#define is_aligned(POINTER, BYTE_COUNT) \
(((uintptr_t)(const void *)(POINTER)) % (BYTE_COUNT) == 0)
Run Code Online (Sandbox Code Playgroud)
转换为void *(或等效char *)是必要的,因为标准仅保证可逆转换uintptr_t为void *.
如果您想要类型安全,请考虑使用内联函数:
static inline _Bool is_aligned(const void *restrict pointer, size_t byte_count)
{ return (uintptr_t)pointer % byte_count == 0; }
Run Code Online (Sandbox Code Playgroud)
并希望编译器优化if byte_count是编译时常量.
为什么我们需要转换为 void * ?
C语言允许不同指针类型的不同表示,例如,您可以具有64位void *类型(整个地址空间)和32位foo *类型(段).
转换foo *- > void *可能涉及实际计算,例如添加偏移量.该标准还将实现在将(任意)指针转换为整数时发生的事情,但我怀疑它通常是作为noop实现的.
对于这样的实现,foo *- > uintptr_t- > foo *会起作用,但是foo *- > uintptr_t- > void *和void *- > uintptr_t- > foo *不会.对齐计算也不能可靠地工作,因为您只检查相对于段偏移的对齐,这可能是您想要的,也可能不是.
总结:始终使用void *以实现与实现无关的行为.
Pas*_*uoq 27
编辑:铸造long是一种廉价的方式来保护自己免受int和指针现在不同大小的可能性.
正如下面的评论中所指出的,如果您愿意包含标题,那么有更好的解决方案......
指针p在16字节边界iff上对齐((unsigned long)p & 15) == 0.
Cra*_*een 22
其他答案建议设置低位的AND运算,并与零进行比较.
但更直接的测试是使用所需的对齐值进行MOD,并与零进行比较.
#define ALIGNMENT_VALUE 16u
if (((uintptr_t)ptr % ALIGNMENT_VALUE) == 0)
{
// ptr is aligned
}
Run Code Online (Sandbox Code Playgroud)
使用功能模板
#include <type_traits>
template< typename T >
bool is_aligned(T* p){
return !(reinterpret_cast<uintptr_t>(p) % std::alignment_of<T>::value);
}
Run Code Online (Sandbox Code Playgroud)
你可以通过调用类似的东西在运行时检查对齐
struct foo_type{ int bar; }foo;
assert(is_aligned(&foo)); // passes
Run Code Online (Sandbox Code Playgroud)
要检查错误的对齐失败,您可以这样做
// would almost certainly fail
assert(is_aligned((foo_type*)(1 + (uintptr_t)(&foo)));
Run Code Online (Sandbox Code Playgroud)
这基本上就是我正在使用的。通过将整数用作模板,可以确保它延长了编译时间,因此无论我做什么,我都不会以缓慢的模运算结束。
我一直喜欢检查我的输入,因此喜欢编译时间断言。如果对齐值是错误的,那么它将无法编译...
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;
}
};
Run Code Online (Sandbox Code Playgroud)
要查看发生了什么,可以使用以下命令:
// 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;
Run Code Online (Sandbox Code Playgroud)
交给专业人士,
bool is_aligned(const void* ptr, std::size_t alignment) noexcept;
Run Code Online (Sandbox Code Playgroud)
例子:
char D[1];
assert( boost::alignment::is_aligned(&D[0], alignof(double)) ); // might fail, sometimes
Run Code Online (Sandbox Code Playgroud)