LLVM 项目博客

LLVM 项目新闻和细节

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 支持奠定基础。

我们做了什么

我们的工作涉及几个关键领域

  1. 地址空间支持:其中一项基本任务是教会 ClangIR 如何处理地址空间,这是 OpenCL 等语言的重要功能。最初,我们考虑模仿 LLVM 的方法,但这对于 ClangIR 的目标来说是不够的。经过深入的讨论和一个 RFC,我们实现了一个统一的地址空间设计,该设计与 ClangIR 的目标一致,确保代码结构干净且易于维护。

  2. OpenCL 语言和 SPIR-V 目标集成:我们扩展了 ClangIR 以支持 OpenCL 语言和 SPIR-V 目标。这涉及增强管道以适应最新的 OpenCL 3.0 规范,并实现语言特定和目标特定自定义的钩子。

  3. 向量类型支持:OpenCL 向量类型是 GPU 编程的关键功能,已被集成到 ClangIR 中。我们利用 ClangIR 现有的 cir.vector 类型来生成必要的代码,确保一致的编译结果。

  4. 内核和模块元数据发射:我们在 ClangIR 中添加了对发射 OpenCL 内核和模块元数据的支持,这是与 SPIR-V 目标正确集成所必需的步骤。这包括创建结构化属性来表示元数据,遵循 MLIR 对定义明确的结构的偏好。

  5. 具有限定符的全局和静态变量:我们实现了对具有 globalconstantlocal 等限定符的全局和静态变量的支持,确保这些结构在 ClangIR 管道中得到正确表示和降低。

  6. 调用约定:我们调整了 ClangIR 中的调用约定以符合 SPIR-V 要求,从默认的 cdecl 迁移到 SPIR-V 特定的约定,如 SpirKernelSpirFunction。这也支持大多数 OpenCL 内置函数,如 barrierget_global_id

  7. 用户体验增强:最后,我们确保使用 ClangIR 的端到端内核编译体验流畅直观,所需的动手操作最少。

结果

该项目成功实现了其主要目标。来自 Polybench-GPU 基准测试套件的 OpenCL 内核现在可以使用 ClangIR 编译成用于 SPIR-V 的 LLVM IR。所有补丁都已合并到主要的 ClangIR 存储库中,项目的进展已在 概述问题 中得到了很好的记录。我相信这项工作不仅促进了 OpenCL 支持,而且为未来的增强奠定了坚实的基础,例如 ClangIR 中的 SYCL 和 CUDA 支持。

我们已成功编译并执行了来自 polybenchGpu 存储库的全部 20 个 OpenCL C 基准,通过了内置结果验证。有关如何使用我们的工作进行实验的详细说明,请参阅我们的 工件评估存储库

未来工作

展望未来,有两个关键领域需要进一步发展

  1. 函数属性一致性:例如,convergent 函数属性对于防止像 OpenCL 这样的 SIMT 语言中的错误优化至关重要。ClangIR 目前缺少此属性,这可能导致并行计算环境中的问题。解决这个问题是确保正确优化行为的优先事项。

  2. 对 OpenCL 内置类型的支持:未来工作的另一个关键领域是对 OpenCL 内置类型的支持,如 pipeimage。这些类型对于处理各种专用 OpenCL 应用程序中的数据流和图像处理任务至关重要。支持这些类型将显着增强 ClangIR 对 OpenCL 标准的遵守,扩大其适用范围,并确保与各种 OpenCL 程序的更好兼容性。

致谢

没有 LLVM 社区的指导和支持,这个项目是不可能实现的。我向我的导师 Julian Oppermann、Victor Lomüller 和 Bruno Cardoso Lopes 表示最衷心的感谢,他们的专业知识和鼓励在这段旅程中起到了至关重要的作用。此外,我要感谢 Vinicius Couto Espindola 对 ABI 相关工作的合作。这段经历在技术上和社区参与方面都非常有意义。

附录