【问题标题】:Conversion from ___attribute___((shared)) to addrspace(3) in Clang compiler when compiling CUDA files编译 CUDA 文件时在 Clang 编译器中从 ___attribute___((shared)) 转换为 addrspace(3)
【发布时间】:2016-02-12 07:16:39
【问题描述】:

clang 编译器包含 CUDA 头文件 host_defines.h,其中 __shared__ 定义为 __attribute__((shared))。当使用 clang 将 CUDA 源文件编译为内部表示 (IR) 时,__shared__ 将转换为 addrspace(3)。这些地址空间可以在clang文件llvm/tools/clang/lib/Basic/Targets.cpp第1601行作为数组观察到

static const unsigned NVPTXAddrSpaceMap[] = {
    1, // opencl_global
    3, // opencl_local
    4, // opencl_constant
    // FIXME: generic has to be added to the target
    0, // opencl_generic
    1, // cuda_device
    4, // cuda_constant
    3, // cuda_shared
};

所以具体问题是在转换的哪个阶段,__attribute__((shared)) 被转换为addrspace(3)。查看 clang 的解析和词法分析部分并没有暗示这一点。有人可以帮忙吗?

【问题讨论】:

    标签: cuda clang llvm llvm-clang llvm-ir


    【解决方案1】:

    shared 属性在 clang 的 Attr.td 文件中定义,称为CUDAShared,内部表示为CUDASharedAttr。 在任何 Attrbiute 的词法分析和解析阶段,对 Attr.td 中定义的所有属性进行词法分析和解析。在这个阶段,你不会找到任何必要的见解。

    您将看到CUDASharedAttr 的有价值代码的第一个点位于clang/lib/Sema/SemaDeclAttr.cpp。 Sema 类构建 AST 并在SemaDeclAttr.cpp 中完成每个属性的处理。 对于特定的 CUDASharedAttr handleSimpleAttribute<CUDASharedAttr>(S, D, Attr); 被调用。此函数只是将属性插入给定声明 (Decl& D)。

    现在属性已附加到 Decl,您可以使用以下方法查询声明是否具有属性:D.hasAttr<CUDASharedAttr>()。例如,在SemaDecl.cpp 中,强制执行了对 CUDA 共享内存声明的限制,并且共享内存变量的存储类设置为静态。

    您将再次找到发出实际 LLVM IR 的 CUDASharedAttr bin clang/lib/CodeGen/CodeGenModule.cpp。 在 CodeGenModule.cpp 你有以下功能:

    unsigned CodeGenModule::GetGlobalVarAddressSpace(const VarDecl *D,
                                                     unsigned AddrSpace) {
      if (LangOpts.CUDA && LangOpts.CUDAIsDevice) {
        if (D->hasAttr<CUDAConstantAttr>())
          AddrSpace = getContext().getTargetAddressSpace(LangAS::cuda_constant);
        else if (D->hasAttr<CUDASharedAttr>())
          AddrSpace = getContext().getTargetAddressSpace(LangAS::cuda_shared);
        else
          AddrSpace = getContext().getTargetAddressSpace(LangAS::cuda_device);
      }
    
      return AddrSpace;
    }
    

    该函数从实际目标查询共享函数的地址空间,即对于 nvptx 目标,使用您发布的地址空间映射:

    static const unsigned NVPTXAddrSpaceMap[] = {
        1, // opencl_global
        3, // opencl_local
        4, // opencl_constant
        // FIXME: generic has to be added to the target
        0, // opencl_generic
        1, // cuda_device
        4, // cuda_constant
        3, // cuda_shared
    };
    

    LangAS::cuda_shared对应地址空间3。

    完成所有这些步骤后,您将在最终的 IR 模块中获得一个地址空间为 3 的全局变量,如下所示:

     ; ModuleID = 'sm.cu'
      target datalayout = "e-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f32:32:32-f64:64:64-v16:16:16-v32:32:32-v64:64:64-v128:128:128-n16:32:64"
      target triple = "nvptx64-unknown-unknown"
    
      @vec= internal unnamed_addr addrspace(3) global [32 x i32] zeroinitializer, align 4
    
      ; Function Attrs: nounwind readnone
      declare i32 @llvm.nvvm.read.ptx.sreg.tid.x() #0
    
      ; Function Attrs: nounwind readnone
      declare i32 @llvm.nvvm.read.ptx.sreg.tid.y() #0
    
      define ptx_kernel void @__pacxx_kernel0(i32 addrspace(1)* %tmp) {
        %1 = tail call spir_func i32 @llvm.nvvm.read.ptx.sreg.tid.x() #1
        %2 = zext i32 %1 to i64
        %3 = getelementptr i32, i32 addrspace(1)* %tmp, i64 %2
        %4 = load i32, i32 addrspace(1)* %3, align 4
        %5 = getelementptr [32 x i32], [32 x i32] addrspace(3)* @vec, i64 0, i64 %2
        store i32 %4, i32 addrspace(3)* %5, align 4
        %6 = tail call spir_func i32 @llvm.nvvm.read.ptx.sreg.tid.y() #1
        %7 = zext i32 %6 to i64
        %8 = getelementptr [32 x i32], [32 x i32] addrspace(3)* @vec, i64 0, i64 %7
        %9 = load i32, i32 addrspace(3)* %8, align 4
        %10 = getelementptr i32, i32 addrspace(1)* %tmp, i64 %7
        store i32 %9, i32 addrspace(1)* %10, align 4
        ret void
      }
    

    【讨论】:

    • 为了在 CUDA 中添加对类似于“_shared_”的新内存类型“_noc_”的支持,我修改了所需的 clang和 llvm 文件。从答案中我了解了程序流程并在 /llvm/tools/clang/lib/Headers/__clang_cuda_runtime_wrapper.h 中添加了 #define _noc_ _attribute__((noc)) ,其中 host_defines被纳入铿锵声中。当我用它编译 llvm 并安装时,生成的 IR 文件没有某些字段,例如“Function Attrs:uwtable”。当没有#define for __noc_ 使用clang 时,这个问题就不存在了。任何直觉都会有很大帮助
    • uwtable 通常来自异常处理。没有代码很难诊断。
    • 遵循了答案中的步骤,似乎clang编译器忽略了添加的新内存类型。为了更好地了解问题,请添加到:stackoverflow.com/questions/35519825/…
    猜你喜欢
    • 2021-11-02
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-07-07
    • 2021-11-24
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多