# swgcc-hybrid-plugin **Repository Path**: swmore/swgcc-hybrid-plugin ## Basic Information - **Project Name**: swgcc-hybrid-plugin - **Description**: 为swgcc系列编译器提供主核代码触发从核代码实例化支持 - **Primary Language**: C++ - **License**: GPL-3.0 - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 7 - **Forks**: 0 - **Created**: 2022-05-19 - **Last Updated**: 2023-10-30 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README NOHP-swgcc编译插件(Not Only a Hybrid Plugin) ---------------------------------------------- 神威线程库最早的方案是文件隔离,混合链接。 长期以来,主从核混合编程是使用神威平台的一个较为困扰的问题: 1. 主从核强行分到两个文件里,逻辑的连贯性没有了。 2. 即使后续,主从核也至少要分到两个函数里,然后把同一个文件编译两遍,需要调用的地方互相 ``extern`` ,主要省下了数据结构定义的工作。 3. 到了基于swgcc进行从核C++编程的时期,2的解决方案渐渐不能满足大家对编程的便利性的追求了,尤其是: 1) 模板的实例化,由于主从核代码编译的时候相互隔离,使得模板实例化基本只能显式进行。 2) Lambda表达式加上可切换架构属性 ``__attribute__((target("xxx")))`` 已经足够实现主从核代码写在“同一个函数”里的功能,但目前编译器的后端不支持。 3) 同样,这样一来, ``athread_spawn`` 的接口还是要把参数打包到一个结构体里面,或者使用 ``std::tuple``再取地址来传递。 4) C++有更加严格的类型检查机制,所以向量类型间的直接赋值是不怎么被允许的。 5) 从核换名 ``slave_Zxxx`` 在主核C++中无法表示,强行表示会变成 ``_Zslavexxx`` 。 这是我开发这一套插件的主要动力。 目前主要实现的功能是: 1. 为C语言添加了 ``__attribute__((sw64_host))`` 和 ``__attribute__((sw64_slave))`` 属性,从而允许在IPA pass后选择性地生成RTL,这样使用 ``-mhost`` 编译时,带 ``__attribute__((sw64_slave))`` 的函数不进入RTL pass,从而可以规避主从核指令集不兼容导致的问题。(对 ``-mslave`` 而言,问题是对称的) 2. 为了促进主从一体化,原有的 ``static`` 变量,先转为非 ``static`` ,并输出插件将哪些 ``static`` 进行了转换,使用 ``sw5ld -r`` 进行主从混合临时链接后,再使用 ``sw5objcopy`` 将这些变量转为局部变量。 3. 实现了数据类型在寄存器中强转的 ``__builtin_cast_[frommode]_[tomode]`` 函数。 4. 添加了 ``__builtin_slave_func`` 解析从核换名后的函数。 5. 添加了一个RTL pass,用于消除从核上额外的 ``fcpys x,x,x`` (是由于从核上对 ``IFMOV`` 的实现是 ``UNSPEC_IFMOV`` 阻止了编译器优化导致的,这里加一个RTL pass可以删掉这类指令) 6. GCC的指令选择和指令调度相互独立,而指令选择时可能导致带来延时更大的指令选择,例如 ``a*(b+c*d*e)`` 的延时最低的方案是 ``(a*b)+(c*a)*(d*e)`` (两轮乘法延时,4次乘[加]),但根据GCC的指令选择中的开销模型,编译器会选择 ``a*(b+c*(d*e))`` (三轮乘法延时,3次乘[加])。指令选择时已经做了这个选择之后,后续的RTL pass无力对此进行优化到前一种形式,所以提供了 ``__builtin_protect_[modename]`` 以阻止编译器在指令选择时进行不合理的乘加重组。 例如,一个稍微整洁一点的 ``invsqrt`` 函数(新的向量化头文件正在开发当中,老的 ``simd.h`` 反正C++兼容有问题):: __cpe__ __v4df v_invsqrt(__v4df x) { __v4di magic = set1_v4di(0x5fe6ec85e7de30daL); __v4di xlong = __builtin_cast_v4df_v4di(x); __v4df y = __builtin_cast_v4di_v4df(magic - __builtin_cast_v4df_v4di(__builtin_sw_vcpysd(set1_v4df(0.0), __builtin_cast_v4di_v4df(xlong >> 1)))); __v4df xhalf = x * 0.5; y = y * (1.5 - xhalf * y * y); y = y * (1.5 - xhalf * y * y); y = y * (1.5 - xhalf * y * y); return y; } 例如,一个主从核融为一体的 ``main`` 函数:: __mpe__ int main(int argc, char **argv){ qthread_init(); int t0 = 1; int t1 = 2; qthread_run_lambda([=, &t1]() __cpe__ { int myid; asm volatile("rcsr %0, 0\n\t": "=r"(myid)); if (myid == 0){ printf("passing lambda: t0=%d, and set t1 = 3\n", t0); t1 = 3; } }); printf("%d\n", t1); } 插件源码位于 ``plugin`` 目录,可以在根文件夹编译。 ``bin`` 目录有一个简单包装过的编译脚本。 ``qthread-mod`` 将提供一个临时修改过的 ``qthread`` 库来支持 ``qthread_run_lambda`` 函数。 ``test`` 目前有两个测试用例: 完全面向C++的 ``hthread`` 库正在开发中,目前提供的函数有:: template hthread_parallel(T): 全部从核并行运行T的()函数 1. ``hybrid.cpp`` 用于测试编译主从混合程序 2. ``invsqrt.cpp`` 用于测试对于相关优化特性的支持 3. ``iterator.cpp`` 用于测试 ``hthread`` 的迭代器 编译时需要:: python3 ../bin/swgcc-hybrid.py in.cpp -c -msimd -O3 -I../include -I../qthread-mod 链接仍然使用 ``sw5g++ -mhybrid`` 。