用-mavx

时间:2018-08-24 08:27:09

标签: c++ clang c++17

根据这个question,我认为在C ++ 17中,带有默认分配器的std :: vector应该处理对齐类型。但是,以下代码

#include <iostream>
#include <iterator>
#include <array>
#include <vector>

template<typename T, size_t N, size_t Alignment>
struct alignas(Alignment) AlignedArray : public std::array<T, N>
{
    friend std::ostream& operator<<(std::ostream& o, const AlignedArray& a)
    {
        std::copy(a.cbegin(), a.cend(), std::ostream_iterator<T>(o, " "));
        return o;
    }
};

int main()
{
    using Array = AlignedArray<double, 24, 64>;
    std::vector<Array> v(10);
    for(const auto& e : v)
    {
        auto arr(e);
        std::cout << arr << std::endl;
    }
    return 0;
}
当我使用clang 6.0.1和arr编译-mavx时,

会错误创建-mavx。如果没有clang++ -I<path_to_libcxx>/include/c++/v1 -g -mavx -std=c++17 main.cpp -stdlib=libc++ -lc++abi -o alignastest -L<path_to_libcxx>/lib -L<path_to_libcxxabi>/lib开关,它将运行正常(CPU是E5-2697 v2)。我用 std::aligned_alloc。 我在旧的RHEL 6.9上运行此代码,在该版本中我编译了clang 6.0.1和libcxx,libcxxabi。 我在另一个系统(Ubuntu 18.10,gcc 8)上进行了测试,它可以正常工作。

子问题

关于对齐方式,我发现libc ++中__config.h的实现依赖于C11功能,该功能仅在最新的glibc版本(#if __GLIBC_PREREQ(2, 17) #define _LIBCPP_HAS_C11_FEATURES #endif )中启用:

ldd (GNU libc) 2.12

很遗憾,RHEL 6.9仅安装了alignasdebug] [BaseDriver] Event 'newSessionStarted' logged at 1535090782935 (11:36:22 GMT+0530 (India Standard Time)) [W3C] Encountered internal error running command: Error: Cannot start the 'com.infosys.android.ui' application. Original error: Error executing adbExec. Original error: 'Command '/home/shubhambansal/Android/Sdk/platform-tools/adb -P 5037 -s 42007dee9bec64d3 shell am start -W -n com.infosys.android.ui/com.infosys.android.ui.controller.GroupMainActivity -S -a android.intent.action.MAIN -c android.intent.category.LAUNCHER -f 0x10200000' exited with code 1'; Stderr: 'java.lang.SecurityException: Permission Denial: starting Intent { act=android.intent.action.MAIN cat=[android.intent.category.LAUNCHER] flg=0x10200000 cmp=com.infosys.android.ui/.controller.GroupMainActivity launchParam=MultiScreenLaunchParams { mDisplayId=0 mBaseDisplayId=0 mFlags=0 } } from null (pid=5830, uid=2000) not exported from uid 10136 [W3C] at android.os.Parcel.readException(Parcel.java:1704) [W3C] at android.os.Parcel.readException(Parcel.java:1654) [W3C] at android.app.ActivityManagerProxy.startActivityAndWait(ActivityManagerNative.java:3716) [W3C] at com.android.commands.am.Am.runStart(Am.java:658) [W3C] at com.android.commands.am.Am.onRun(Am.java:392) [W3C] at com.android.internal.os.BaseCommand.run(BaseCommand.java:51) [W3C] at com.android.commands.am.Am.main(Am.java:125) [W3C] at com.android.internal.os.RuntimeInit.nativeFinishInit(Native Method) [W3C] at com.android.internal.os.RuntimeInit.main(RuntimeInit.java:315)'; Code: '1' [W3C] at ADB.callee$0$0$ (/home/linuxbrew/.linuxbrew/lib/node_modules/appium/node_modules/appium-adb/lib/tools/apk-utils.js:125:11) [W3C] at tryCatch (/home/linuxbrew/.linuxbrew/lib/node_modules/appium/node_modules/babel-runtime/regenerator/runtime.js:67:40) [W3C] at GeneratorFunctionPrototype.invoke [as _invoke] (/home/linuxbrew/.linuxbrew/lib/node_modules/appium/node_modules/babel-runtime/regenerator/runtime.js:315:22) [W3C] at GeneratorFunctionPrototype.prototype.(anonymous function) [as throw] (/home/linuxbrew/.linuxbrew/lib/node_modules/appium/node_modules/babel-runtime/regenerator/runtime.js:100:21) [W3C] at GeneratorFunctionPrototype.invoke (/home/linuxbrew/.linuxbrew/lib/node_modules/appium/node_modules/babel-runtime/regenerator/runtime.js:136:37) [HTTP] <-- POST /wd/hub/session 500 31877 ms - 3846 是否也取决于glibc版本?

1 个答案:

答案 0 :(得分:3)

我发现编译后的代码有问题,但是我还没有找到解决方案。但这表明,这只是一个叮叮当当的问题,使用g ++即可解决。

通过显示一些最终的汇编代码可以最好地说明该问题。 auto arr(e);代码行被编译为一些移动指令,以将数据从向量复制到堆栈中,clang使用(当使用-mavx进行编译时)类似于以下(AT&T语法)的avx2指令:

vmovaps 0xa0(%rax),%ymm0
vmovaps %ymm0,0x120(%rsp)
...

其中%rax是向量中当前数组的地址。目标arr位于0x80(%rsp)。该程序将以32字节的块(256位avx2指令)进行复制。

但是,在调试测试中查看以下值时,问题变得很明显:%rax = 0x55555556be70。问题是,将vmovaps(移动对齐的压缩后的单精度)移至256位avx2寄存器时,期望目标和源在256bit或32byte(0x20)边界对齐,但是%rax仅16byte对齐。当不使用alignas进行编译时,clang使用vmovups(相同的指令,但不需要对齐数据)。

所以问题是,std :: vector的分配器不遵守alignas,并且不以64byte边界对齐数组。 g ++也不将向量内的数组与32byte边界对齐,并且在不同时使用-O [not 0]时不使用avx指令。但是,g ++始终使用128位xmm寄存器,该寄存器仅需要对齐到16个字节,分配器会将这两个寄存器与两个编译器对齐。

编辑:

我刚刚意识到,我忘记了使用-std = c ++ 17进行编译。带有该标志,适用于clang ++。该代码看起来相同,但是分配器将代码正确地对齐在64字节边界处。所以我想这与一个旧库有关。也许您可以将二进制文件发送给我,然后我可以对其进行更详细的了解。