我正在编写一个包装器容器模板类,std::vector它会自动创建一个multi-resolution pyramid元素std::vector.
现在的关键问题是我希望金字塔的创建是(GCC)自动矢量化的.
内部存储在std :: vector和我的解析金字塔中的所有数据数组都是使用标准的new或allocator模板参数在堆上创建的.有没有我可以帮助编译器强制对我的数据进行特定对齐,以便矢量化可以在具有最佳对齐的元素(数组)(块)上运行(通常为16).
因此我使用自定义分配器, AlignmentAllocator但GCC自动向量化消息输出仍然在第144行中声明包含表达式的未对齐内存std::mr_vector::construct_pyramidmulti_resolution.hpp
for (size_t s = 1; s < snum; s++) { // for each cached scale
...
}
Run Code Online (Sandbox Code Playgroud)
如下
tests/../multi_resolution.hpp:144: note: Detected interleaving *D.3088_68 and MEM[(const value_type &)D.3087_61]
tests/../multi_resolution.hpp:144: note: versioning for alias required: can't determine dependence between *D.3088_68 and *D.3082_53
tests/../multi_resolution.hpp:144: note: mark for run-time aliasing test between *D.3088_68 and *D.3082_53
tests/../multi_resolution.hpp:144: note: versioning for alias …Run Code Online (Sandbox Code Playgroud) c++ gcc vectorization memory-alignment dynamic-memory-allocation
我知道多继承的内存布局没有定义,所以我不应该依赖它.但是,我可以在特殊情况下依赖它.也就是说,一个班级只有一个"真正的"超级班级.所有其他都是"空类",即既没有字段也没有虚拟方法的类(即它们只有非虚方法).在这种情况下,这些附加类不应该向类的内存布局添加任何内容.(更简洁地说,在C++ 11中,该类具有标准布局)
我可以推断出所有超类都没有偏移吗?例如:
#include <iostream>
class X{
int a;
int b;
};
class I{};
class J{};
class Y : public I, public X, public J{};
int main(){
Y* y = new Y();
X* x = y;
I* i = y;
J* j = y;
std::cout << sizeof(Y) << std::endl
<< y << std::endl
<< x << std::endl
<< i << std::endl
<< j << std::endl;
}
Run Code Online (Sandbox Code Playgroud)
这里,Y类X是唯一真正的基类.程序的输出(在linux上用g ++ 4.6编译时)如下:
8
0x233f010
0x233f010
0x233f010
0x233f010 …
从这个问题开始,人们可以开始相信联盟的一致性不低于其个体成员的最大一致性.但我对long longgcc/g ++中的类型有问题.完整的示例可以在这里找到,但这里是我的问题的相关部分:
union ull {
long long m;
};
struct sll {
long long m;
};
int main() {
#define pr(v) cout << #v ": " << (v) << endl
pr(sizeof(long long));
pr(__alignof__(long long));
pr(sizeof(ull));
pr(__alignof__(ull));
pr(sizeof(sll));
pr(__alignof__(sll));
};
Run Code Online (Sandbox Code Playgroud)
这导致以下输出:
sizeof(long long): 8
__alignof__(long long): 8
sizeof(ull): 8
__alignof__(ull): 4
sizeof(sll): 8
__alignof__(sll): 4
Run Code Online (Sandbox Code Playgroud)
为什么union成员的对齐大于包含union的对齐?
[UPDATE]
根据基思的回答,对齐在这里是错误的.但我测试了以下内容,似乎alignof 告诉我们真实情况.看到:
union ull {
long long m;
};
long long a;
char b; …Run Code Online (Sandbox Code Playgroud) 我有一个对象,其地址不是4字节对齐的.当存在STR指令保存2个寄存器时,这会在cpu中导致HardFault错误.
这是生成的代码:
00000000 <_ZN8BaseAreaC1EPcmm>:
0: b510 push {r4, lr}
2: 4604 mov r4, r0
4: 6042 str r2, [r0, #4]
6: e9c4 3102 strd r3, r1, [r4, #8]
a: 2001 movs r0, #1
c: 7420 strb r0, [r4, #16]
e: b921 cbnz r1, 1a <_ZN8BaseAreaC1EPcmm+0x1a>
Run Code Online (Sandbox Code Playgroud)
这些是在"4:6042 ......"行的寄存器
R0 08738B82 R8 0
R1 08738BAE R9 0
R2 0 R10 082723E0
R3 2FCC R11 0
R4 08738B82 R12 0
R5 20007630 R13 2000CB38
Run Code Online (Sandbox Code Playgroud)
如图所示,STR指令的目标寄存器未在4字节上对齐.该指令STR r2, [r0, #4]执行正常.但它就是HardFaults的下一个STRD r3, r1, …
我在Cell处理器上调整DMA传输的内存时遇到问题.我需要地址的最后4位为0.
我有4个数组,unsigned int其中每个元素必须在内存中对齐,以便其(十六进制)地址以零结尾.
例如
int main()
{
size_t i;
static unsigned int a[2] __attribute__ ((aligned (16)));
static unsigned int b[2] __attribute__ ((aligned (16)));
static unsigned int c[2] __attribute__ ((aligned (16)));
static unsigned int d[2] __attribute__ ((aligned (16)));
for (i = 0; i < 2; ++i) {
printf("a[%u] = %p\n", &a[i]);
printf("b[%u] = %p\n", &b[i]);
printf("c[%u] = %p\n", &c[i]);
printf("d[%u] = %p\n", &d[i]);
}
return 0;
}
Run Code Online (Sandbox Code Playgroud)
输出:
a[0] = 0x10010b60
b[0] = 0x10010b50
c[0] = 0x10010b40 …Run Code Online (Sandbox Code Playgroud) 我在某处读到了在页面边界旁边执行未对齐的加载或存储之前(例如使用_mm_loadu_si128/ _mm_storeu_si128intrinsics),代码应首先检查整个向量(在这种情况下是16个字节)是否属于同一页面,如果不是,则切换到非向量指令.我知道如果下一页不属于进程,则需要这样做以防止coredump.
但是,如果两个页面都属于进程(例如,它们是一个缓冲区的一部分,并且我知道该缓冲区的大小),该怎么办?我写了一个小的测试程序,它执行了未对齐的加载和跨越页面边界的存储,并没有崩溃.在这种情况下,我是否必须始终检查页面边界,还是足以确保我不会溢出缓冲区?
环境:Linux,x86_64,gcc
这是我在编写某些类系统软件时使用C/C++的最重要原因之一,但它只不过是一个非常常见的编译器扩展.为什么委员会不考虑正式支持它?它是否与现有规范中的任何子句不兼容,例如public和private是否对对象的内存布局有影响?
我试图清楚地了解谁(调用者或被调用者)负责堆栈对齐.64位汇编的情况相当清楚,它是由调用者.
参考System V AMD64 ABI,第3.2.2节"堆栈帧":
输入参数区域的末尾应在16(32,如果在堆栈上传递__m256)字节边界上对齐.
换句话说,应该可以安全地假设,对于被调用函数的每个入口点:
16 | (%rsp + 8)
保持(额外八个是因为call隐含地在堆栈上推送返回地址).
它在32位世界中的表现(假设是cdecl)?我注意到,使用以下构造gcc将对齐放置在被调用函数内:
and esp, -16
Run Code Online (Sandbox Code Playgroud)
这似乎表明,这是被召唤者的责任.
为了更清楚,请考虑以下代码:
global main
extern printf
extern scanf
section .rodata
s_fmt db "%d %d", 0
s_res db `%d with remainder %d\n`, 0
section .text
main:
start 0, 0
sub esp, 8
mov DWORD [ebp-4], 0 ; dividend
mov DWORD [ebp-8], 0 ; divisor
lea eax, [ebp-8]
push …Run Code Online (Sandbox Code Playgroud) 在C ++中,至少在GCC和Clang上,嵌入在容器(std :: vector)中的超对齐类型似乎被不同地对待,具体取决于该类型是超对齐结构还是超对齐枚举。对于struct版本,每个元素都对齐,而对于枚举,只有整个缓冲区具有指定的对齐方式。该行为是否由标准指定?如果是这样,哪一部分提到了?还是实现定义的,不应该依赖?
考虑以下:
#include<cstdint>
#include<iostream>
#include<vector>
struct alignas(16) byte_struct {std::uint8_t value;};
enum alignas(16) byte_enum : std::uint8_t {};
int main() {
{//with struct
std::vector<byte_struct> bytes;
bytes.push_back(byte_struct{1});
bytes.push_back(byte_struct{2});
bytes.push_back(byte_struct{3});
for(auto it = bytes.begin(); it!= bytes.end(); ++it) {
std::cout<<&*it<<std::endl;
}
}
{//with enum
std::vector<byte_enum> bytes;
bytes.push_back(byte_enum{1});
bytes.push_back(byte_enum{2});
bytes.push_back(byte_enum{3});
for(auto it = bytes.begin(); it!= bytes.end(); ++it) {
std::cout<<&*it<<std::endl;
}
}
}
Run Code Online (Sandbox Code Playgroud)
具有过度对齐的结构的版本将打印以下内容
0x10a9ec0 0x10a9ed0 0x10a9ee0
带有过度对齐的枚举的版本将打印以下内容
0x10a9e70 0x10a9e71 0x10a9e72
在向量存储区中,每个byte_struct都对齐到16个字节的边界,而byte_enum的对齐方式只适用于整个缓冲区,而不适用于每个单独的元素。
在GCC 9.1和Clang 8.0上,此行为相同,而MSVC 19.20遇到内部编译器错误。
编译器资源管理器的链接为:https : //godbolt.org/z/GUg2ft