GSoC 2024:使用 ClangIR 编译 GPU 内核
大家好!我是 7mile。我今年夏天的 GSoC 项目是 使用 ClangIR 编译 GPU 内核。这趟编译器开发之旅非常激动人心,我很高兴在这里分享我们在途中取得的进展和见解。
背景
ClangIR 项目 旨在为 Clang 建立一个新的 IR,该 IR 建立在 MLIR 之上。作为支持异构编程模型的持续努力的一部分,该项目专注于将 OpenCL C 语言支持集成到 ClangIR 中。最终目标是使使用 OpenCL C 编写的 GPU 内核能够编译成针对 SPIR-V 架构的 LLVM IR,为未来增强 SYCL 和 CUDA 支持奠定基础。
我们做了什么
我们的工作涉及几个关键领域
-
地址空间支持:其中一项基本任务是教会 ClangIR 如何处理地址空间,这是 OpenCL 等语言的重要功能。最初,我们考虑模仿 LLVM 的方法,但这对于 ClangIR 的目标来说是不够的。经过深入的讨论和一个 RFC,我们实现了一个统一的地址空间设计,该设计与 ClangIR 的目标一致,确保代码结构干净且易于维护。
-
OpenCL 语言和 SPIR-V 目标集成:我们扩展了 ClangIR 以支持 OpenCL 语言和 SPIR-V 目标。这涉及增强管道以适应最新的 OpenCL 3.0 规范,并实现语言特定和目标特定自定义的钩子。
-
向量类型支持:OpenCL 向量类型是 GPU 编程的关键功能,已被集成到 ClangIR 中。我们利用 ClangIR 现有的 cir.vector 类型来生成必要的代码,确保一致的编译结果。
-
内核和模块元数据发射:我们在 ClangIR 中添加了对发射 OpenCL 内核和模块元数据的支持,这是与 SPIR-V 目标正确集成所必需的步骤。这包括创建结构化属性来表示元数据,遵循 MLIR 对定义明确的结构的偏好。
-
具有限定符的全局和静态变量:我们实现了对具有
global
、constant
和local
等限定符的全局和静态变量的支持,确保这些结构在 ClangIR 管道中得到正确表示和降低。 -
调用约定:我们调整了 ClangIR 中的调用约定以符合 SPIR-V 要求,从默认的
cdecl
迁移到 SPIR-V 特定的约定,如SpirKernel
和SpirFunction
。这也支持大多数 OpenCL 内置函数,如barrier
和get_global_id
。 -
用户体验增强:最后,我们确保使用 ClangIR 的端到端内核编译体验流畅直观,所需的动手操作最少。
结果
该项目成功实现了其主要目标。来自 Polybench-GPU 基准测试套件的 OpenCL 内核现在可以使用 ClangIR 编译成用于 SPIR-V 的 LLVM IR。所有补丁都已合并到主要的 ClangIR 存储库中,项目的进展已在 概述问题 中得到了很好的记录。我相信这项工作不仅促进了 OpenCL 支持,而且为未来的增强奠定了坚实的基础,例如 ClangIR 中的 SYCL 和 CUDA 支持。
我们已成功编译并执行了来自 polybenchGpu 存储库的全部 20 个 OpenCL C 基准,通过了内置结果验证。有关如何使用我们的工作进行实验的详细说明,请参阅我们的 工件评估存储库。
未来工作
展望未来,有两个关键领域需要进一步发展
-
函数属性一致性:例如,
convergent
函数属性对于防止像 OpenCL 这样的 SIMT 语言中的错误优化至关重要。ClangIR 目前缺少此属性,这可能导致并行计算环境中的问题。解决这个问题是确保正确优化行为的优先事项。 -
对 OpenCL 内置类型的支持:未来工作的另一个关键领域是对 OpenCL 内置类型的支持,如
pipe
和image
。这些类型对于处理各种专用 OpenCL 应用程序中的数据流和图像处理任务至关重要。支持这些类型将显着增强 ClangIR 对 OpenCL 标准的遵守,扩大其适用范围,并确保与各种 OpenCL 程序的更好兼容性。
致谢
没有 LLVM 社区的指导和支持,这个项目是不可能实现的。我向我的导师 Julian Oppermann、Victor Lomüller 和 Bruno Cardoso Lopes 表示最衷心的感谢,他们的专业知识和鼓励在这段旅程中起到了至关重要的作用。此外,我要感谢 Vinicius Couto Espindola 对 ABI 相关工作的合作。这段经历在技术上和社区参与方面都非常有意义。