Page 28 - 《软件学报》2025年第12期
P. 28
沈莉 等: swJulia: 面向新一代神威超级计算机的 Julia 语言编译系统 5409
算法 1. !ldmhigh/!ldmlow 重定位修正算法.
输入: 动态库的重定位表 relaTable 以及.ldm 段 LDMSec;
输出: 重定位修正后的动态库代码段 text.
1. ldm_pstart = mmap(LDMSec.getSize(), FLAG_LDM)
2. FOR rela∈relaTable DO
3. IF rela.getType()∈{R_SW_64_LDMHI, R_SW_64_LDMLO} THEN
4. offset = rela.getSym().getVAddr() – LDMSec.getVAddr()
5. ldm_paddr = ldm_pstart + offset
6. IF rela.getType() == R_SW_64_LDMLO THEN
7. disp = ldm_paddr & 0xFFFF
8. ELSE
9. carry = (ldm_paddr >> 15) & 0x1
10. disp = ((ldm_paddr >> 16) + carry) & 0xFFFF
11. END IF
12. rela.getInstr(text).fixOffset(disp)
13. END IF
14. END FOR
该方案通过改进 swLLVM 编译器及其配套的二进制工具链, 既规避了 LDM 变量潜在的地址冲突问题, 保证
了 LLVM IR 向 CPE 汇编指令降级的正确性, 又实现了对片上存储空间的高效访问, 为 swJulia 的动态运行提供了
稳定的底层支撑.
2.3 SACA.jl
SACA (Sunway accelerate computing architecture) 是面向申威众核架构的并行加速计算编程模型, 其优化整合
了基础编译及运行时等编程接口, 为科学计算、人工智能等领域应用提供统一的编程和优化支持 [23] . SACA.jl 是
为了在 Julia 语言中支持 SACA 编程模型而开发的第三方库. 其为 Julia 开发者提供了一种便捷和高效的方式来利
用 SW26010Pro 进行计算加速, 无需用户深入了解 SACA 的底层细节, 降低了学习和开发成本.
SACA.jl 实际上由两个主要组件组成: CPE 编译器负责将 Julia 源代码转换为 CPE 上可执行的机器代码,
SACA 封装则提供了在 CPE 上执行常用操作所需的类型和接口. 本文基于 Julia 社区已有的基础设施, 在不改动
Julia 编译器底层实现的前提下, 通过 SACA.jl 实现了 Julia 语言对 SACA 编程模型的支持. SACA.jl 支持 Julia 语
言的一个子集, 但是已经证明能够满足 SW26010Pro 应用开发的现实需求.
2.3.1 CPE 编译器
图 7 展示了在 C 语言中使用 SACA API 进行向量加法的示例, 包括线程初始化、线程组创建、线程等待及
线程回收等. 其中, athread_init 接口用于进行线程的初始化操作, 使用任何 SACA 接口前都需要调用该初始化接
口. athread_spawn 接口用于创建线程组并传递运行参数, 其指定的线程任务将被提交到 CPE 阵列执行. athread_
join 接口用于等待 CPE 阵列的加速线程任务结束, 而 athread_halt 接口则用于关闭 CPE 流水线.
SACA.jl 通过 CPE 编译器支持对 Julia 函数的编译, 从而实现与 SACA C 类似的程序语义. 图 8 展示了一个基
于 SACA.jl 实现的 Julia 语言向量加法程序示例, 该程序的功能与图 7 中展示的 C 语言版本完全相同. 代码的第
2–7 行定义了一个名为 vadd 的 Kernel 函数, 该函数的风格与普通 Julia 函数相似, 但在计算迭代索引变量 i 时特别
采用了 SACA.jl 的内建函数_MYID(), 以获取当前 CPE 的逻辑编号. 与 CUDA 或 OpenCL 等异构编程模型相比,
SACA.jl 的一个显著优势在于, 它无需用户对 Kernel 进行显式的注释或封装, 从而显著提升了代码的可重用性. 在
代码的第 14 行, 程序通过@saca (config…) function(args…) 接口调用了 Kernel 函数. 这里的 config 元组用于指定

