我是使用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代码慢)。
提前谢谢你......
答案 0 :(得分:44)
#define is_aligned(POINTER, BYTE_COUNT) \
(((uintptr_t)(const void *)(POINTER)) % (BYTE_COUNT) == 0)
转换为void *
(或等效,char *
)是必要的,因为标准只保证uintptr_t
void *
的{{1}}可转换。
如果您想要类型安全,请考虑使用内联函数:
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 *
可能涉及实际计算,例如添加偏移量。该标准还将实现在将(任意)指针转换为整数时会发生什么,但我怀疑它通常是作为noop实现的。
对于此类实施,foo *
- > uintptr_t
- > foo *
可行,但foo *
- > uintptr_t
- > void *
和void *
- > uintptr_t
- > foo *
不会。对齐计算也不能可靠地工作,因为您只检查相对于段偏移的对齐,这可能是您想要的,也可能不是。
总之:始终使用void *
来实现与实现无关的行为。
答案 1 :(得分:25)
编辑:转换为long
是一种廉价的方式来保护自己免受int和指针现在不同大小的可能性。
正如下面的评论中所指出的,如果您愿意包含标题,则有更好的解决方案......
指针p
在16字节边界上对齐iff ((unsigned long)p & 15) == 0
。
答案 2 :(得分:20)
其他答案建议设置低位的AND运算,并与零进行比较。
但更直接的测试是使用所需的对齐值进行MOD,并与零进行比较。
#define ALIGNMENT_VALUE 16u
if (((uintptr_t)ptr % ALIGNMENT_VALUE) == 0)
{
// ptr is aligned
}
答案 3 :(得分:6)
使用像
这样的功能模板#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)));
答案 4 :(得分:3)
这基本上就是我所使用的。通过使整数成为模板,我确保它扩展了编译时间,因此无论我做什么,我都不会以慢速模运算结束。
我总是喜欢检查我的输入,因此编译时断言。如果您的对齐值错误,那么它就不会编译......
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;
答案 5 :(得分:2)
你可以'和'ptr与0x03(在4s上对齐),0x07(在8s上对齐)或0x0f(在16s上对齐)来查看是否设置了任何最低位?
答案 6 :(得分:1)
将其留给专业人士
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
答案 7 :(得分:-3)
怎么样:
void *mem = malloc(1024+15);
void *ptr =( (*(char*)mem) - (*(char *)mem % 16) );