编译CUDA文件时,在Clang编译器中从_____属性___((共享))到addrspace(3)的转换

编译CUDA文件时,在Clang编译器中从_____属性___((共享))到addrspace(3)的转换,cuda,clang,llvm,llvm-clang,llvm-ir,Cuda,Clang,Llvm,Llvm Clang,Llvm Ir,clang编译器包括CUDA头文件host_defines.h,其中\uuuuu shared\uuuu被定义为\uuuu属性(shared))。当使用clang将CUDA源文件编译为内部表示(IR)时,\uuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuu将转换。这些地址空间可以在clang文件第1601行作为一个数组进行观察 static const unsigned NVPTXAddrSpace

clang编译器包括CUDA头文件host_defines.h,其中
\uuuuu shared\uuuu
被定义为
\uuuu属性(shared))
。当使用clang将CUDA源文件编译为内部表示(IR)时,
\uuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuu
将转换。这些地址空间可以在clang文件第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
};

因此,具体的问题是在转换的哪个阶段,
\uuuu属性\uuuu((共享))
被转换为
addrspace(3)
。查看clang的语法分析和词法分析部分并没有对此做出任何暗示。有人能帮忙吗?

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

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

现在属性已附加到Decl,您可以使用:
D.hasAttr()
查询声明是否具有该属性。例如,在
SemaDecl.cpp
中,强制执行CUDA共享内存声明的限制,并将共享内存变量的存储类设置为static

您将再次找到CUDASharedAttr bin
clang/lib/CodeGen/CodeGenModule.cpp
,其中实际发出LLVM IR。 在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;
}
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
  }

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

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

现在属性已附加到Decl,您可以使用:
D.hasAttr()
查询声明是否具有该属性。例如,在
SemaDecl.cpp
中,强制执行CUDA共享内存声明的限制,并将共享内存变量的存储类设置为static

您将再次找到CUDASharedAttr bin
clang/lib/CodeGen/CodeGenModule.cpp
,其中实际发出LLVM IR。 在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;
}
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中添加对类似于“共享”的新内存类型“noc”的支持,我修改了所需的clang和llvm文件。从答案中,我理解了程序流程,并在/llvm/tools/clang/lib/Headers/uu clang\u cuda\u runtime\u wrapper.h中添加了#define noc_uattribute uu((noc)),其中主机定义将包含到clang中。当我用这个编译llvm并安装时,生成的IR文件没有某些字段,例如“Function Attrs:uwtable”。如果使用clang时没有为noc定义,则不存在此问题。任何直觉都会大有裨益。通常情况下,异常处理会带来不确定性。如果没有代码,很难诊断。答案中的步骤是遵循的,似乎clang编译器忽略了添加的新内存类型。为了更好地理解这个问题,我添加了一个问题:为了在CUDA中添加对新内存类型“\u noc\uu”的支持,它类似于“\u shared\uu”,我修改了所需的clang和llvm文件。从答案中,我理解了程序流程,并在/llvm/tools/clang/lib/Headers/uu clang\u cuda\u runtime\u wrapper.h中添加了#define noc_uattribute uu((noc)),其中主机定义将包含到clang中。当我用这个编译llvm并安装时,生成的IR文件没有某些字段,例如“Function Attrs:uwtable”。如果使用clang时没有为noc定义,则不存在此问题。任何直觉都会大有裨益。通常情况下,异常处理会带来不确定性。如果没有代码,很难诊断。答案中的步骤是遵循的,似乎clang编译器忽略了添加的新内存类型。为了更好地了解情况,将问题添加到: