来自Clang的OpenCL LLVM IR生成

时间:2014-03-17 19:12:31

标签: clang opencl llvm llvm-ir

我使用以下命令行进行clang:

clang -Dcl_clang_storage_class_specifiers -isystem $LIBCLC/generic/include -include clc/clc.h -target nvptx--nvidiacl -x cl some_kernel.cl -emit-llvm -S -o some_kernel.ll

结果是:

; ModuleID = 'kernel.cl'
target datalayout = "e-p:32:32:32-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 = "nvptx--nvidiacl"

; Function Attrs: noinline nounwind
define void @vector_add(float addrspace(1)* nocapture %vec1, float addrspace(1)* nocapture %vec2, float addrspace(1)* nocapture %vec3) #0 {
  %1 = tail call i32 @get_global_id(i32 0) #2
  %2 = getelementptr inbounds float addrspace(1)* %vec1, i32 1
  %3 = load float addrspace(1)* %2, align 4, !tbaa !2
  %4 = getelementptr inbounds float addrspace(1)* %vec2, i32 2
  %5 = load float addrspace(1)* %4, align 4, !tbaa !2
  %6 = fadd float %3, %5
  %7 = fmul float %6, 5.000000e+00
  %8 = getelementptr inbounds float addrspace(1)* %vec3, i32 %1
  store float %7, float addrspace(1)* %8, align 4, !tbaa !2
  ret void
}

declare i32 @get_global_id(i32) #1

attributes #0 = { noinline nounwind "less-precise-fpmad"="false" "no-frame-pointer-elim"="true" "no-frame-pointer-elim-non-leaf"="true" "no-infs-fp-math"="false" "no-nans-fp-math"="false" "unsafe-fp-math"="false" "use-soft-float"="false" }
attributes #1 = { "less-precise-fpmad"="false" "no-frame-pointer-elim"="true" "no-frame-pointer-elim-non-leaf"="true" "no-infs-fp-math"="false" "no-nans-fp-math"="false" "unsafe-fp-math"="false" "use-soft-float"="false" }
attributes #2 = { nounwind }

!opencl.kernels = !{!0}
!nvvm.annotations = !{!1}

!0 = metadata !{void (float addrspace(1)*, float addrspace(1)*, float addrspace(1)*)* @vector_add}
!1 = metadata !{void (float addrspace(1)*, float addrspace(1)*, float addrspace(1)*)* @vector_add, metadata !"kernel", i32 1}
!2 = metadata !{metadata !"float", metadata !3}
!3 = metadata !{metadata !"omnipotent char", metadata !4}
!4 = metadata !{metadata !"Simple C/C++ TBAA"}

正如您在参数列表中看到的那样,它会生成一个nocapture ABI。

但是当我尝试使用此代码执行此操作时:

/*Create a diagnostics*/
mCompilerInst.createDiagnostics();


/*Creating NVIDIA-CL*/
clang::TargetOptions  TO;
TO.Triple = "nvptx--nvidiacl";
TargetInfo* feTarget =
    clang::TargetInfo::CreateTargetInfo(mCompilerInst.getDiagnostics(), &TO);
mCompilerInst.setTarget(feTarget);

/*Commandline Parameters*/
std::vector<const char*> args;
args.push_back("-Dcl_clang_storage_class_specifiers");
args.push_back("-include");
args.push_back("clc/clc.h");
args.push_back("-xcl");
args.push_back("-S");
/* Create the compiler invocation */
clang::CompilerInvocation::CreateFromArgs(mCompilerInst.getInvocation(), &args[0], &args[0] + args.size(), mCompilerInst.getDiagnostics());

CodeGenerator* llvmCodeGen = clang::CreateLLVMCodeGen(
    mCompilerInst.getDiagnostics(), "kernel.cl", mCompilerInst.getCodeGenOpts(),mCompilerInst.getTargetOpts(),ctx);
ParseAST(mCompilerInst.getPreprocessor(),llvmCodeGen,mCompilerInst.getASTContext());
mCompilerInst.getDiagnosticClient().EndSourceFile();


if(mCompilerInst.getDiagnostics().hasErrorOccurred()) {
    llvm::outs() << "CAN'T COMPILE THE CODE";
}

/*GOING FOR THE LLVM BYTE_CODE*/
llvm::Module* module = llvmCodeGen->GetModule();

std::ofstream myfile;
myfile.open ("result",(std::ios::binary|std::ios::out));
llvm::AssemblyAnnotationWriter writer;
llvm::raw_os_ostream raw_stream(myfile);
module->print(raw_stream, &writer);
myfile.flush();
myfile.close();

输出的是:

; ModuleID = 'kernel.cl'
target datalayout = "e-p:32:32:32-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 = "nvptx--nvidiacl"

; Function Attrs: noinline nounwind
define void @mat_ex(float addrspace(1)* %vec1, float addrspace(1)* %vec2, float addrspace(1)* %vec3) #0 {
  %1 = alloca float addrspace(1)*, align 4
  %2 = alloca float addrspace(1)*, align 4
  %3 = alloca float addrspace(1)*, align 4
  %den = alloca i32, align 4
  %offset = alloca i32, align 4
  %i = alloca i32, align 4
  store float addrspace(1)* %vec1, float addrspace(1)** %1, align 4, !tbaa !2
  store float addrspace(1)* %vec2, float addrspace(1)** %2, align 4, !tbaa !2
  store float addrspace(1)* %vec3, float addrspace(1)** %3, align 4, !tbaa !2
  %4 = call i32 @get_global_id(i32 0)
  store i32 %4, i32* %i, align 4, !tbaa !5
  store i32 4, i32* %den, align 4, !tbaa !5
  %5 = load i32* %den, align 4, !tbaa !5
  %6 = sdiv i32 2, %5
  %7 = mul nsw i32 %6, 4
  %8 = add nsw i32 5, %7
  store i32 %8, i32* %offset, align 4, !tbaa !5
  %9 = load i32* %i, align 4, !tbaa !5
  %10 = load float addrspace(1)** %1, align 4, !tbaa !2
  %11 = getelementptr inbounds float addrspace(1)* %10, i32 %9
  %12 = load float addrspace(1)* %11, align 4, !tbaa !6
  %13 = load i32* %i, align 4, !tbaa !5
  %14 = load float addrspace(1)** %2, align 4, !tbaa !2
  %15 = getelementptr inbounds float addrspace(1)* %14, i32 %13
  %16 = load float addrspace(1)* %15, align 4, !tbaa !6
  %17 = fadd float %12, %16
  %18 = load i32* %offset, align 4, !tbaa !5
  %19 = sitofp i32 %18 to float
  %20 = fmul float %17, %19
  %21 = load i32* %i, align 4, !tbaa !5
  %22 = load float addrspace(1)** %3, align 4, !tbaa !2
  %23 = getelementptr inbounds float addrspace(1)* %22, i32 %21
  store float %20, float addrspace(1)* %23, align 4, !tbaa !6
  ret void
}

declare i32 @get_global_id(i32) #1

attributes #0 = { noinline nounwind "less-precise-fpmad"="false" "no-frame-pointer-elim"="false" "no-frame-pointer-elim-non-leaf"="false" "no-infs-fp-math"="false" "no-nans-fp-math"="false" "unsafe-fp-math"="false" "use-soft-float"="false" }
attributes #1 = { "less-precise-fpmad"="false" "no-frame-pointer-elim"="false" "no-frame-pointer-elim-non-leaf"="false" "no-infs-fp-math"="false" "no-nans-fp-math"="false" "unsafe-fp-math"="false" "use-soft-float"="false" }

!opencl.kernels = !{!0}
!nvvm.annotations = !{!1}

!0 = metadata !{void (float addrspace(1)*, float addrspace(1)*, float addrspace(1)*)* @mat_ex}
!1 = metadata !{void (float addrspace(1)*, float addrspace(1)*, float addrspace(1)*)* @mat_ex, metadata !"kernel", i32 1}
!2 = metadata !{metadata !"any pointer", metadata !3}
!3 = metadata !{metadata !"omnipotent char", metadata !4}
!4 = metadata !{metadata !"Simple C/C++ TBAA"}
!5 = metadata !{metadata !"int", metadata !3}
!6 = metadata !{metadata !"float", metadata !3}

基本上它不匹配,我无法弄清楚为什么。为什么没有“nocaptures”?我认为额外的代码是由于缺少“nocapture”而生成的。

1 个答案:

答案 0 :(得分:2)

命令行

clang ... -emit-llvm ...

运行Clang驱动程序,它首先运行Clang前端以生成LLVM IR,然后运行LLVM来处理IR,然后发出已处理的IR。

代码

ParseAST(mCompilerInst.getPreprocessor(),llvmCodeGen,mCompilerInst.getASTContext());
另一方面,

只将AST解析为IR文件,然后不再进行任何操作。你根本没有调用LLVM,只有Clang前端,这就是你看到不同代码的原因。它实际上具有相同的语义* - 它只是未经优化。

要解决此问题,您需要在模块上实际运行一些传递(或者更好,使用传递管理器)。您可以查看chapter 4 of the kaleidoscope tutorial以获取相关帮助。


*实际上两个模块不等同于。第一个代码相当于:

kernel void vector_add(global float* vec1, global float* vec2, global float* vec3) {
    int i = get_global_id(0);
    vec3[i] = (vec1[1] + vec2[2]) * 5f;
}

虽然第二个是:

kernel void vector_add(global float* vec1, global float* vec2, global float* vec3) {
    int i = get_global_id(0);
    vec3[i] = (vec1[i] + vec2[i]) * 5f;
}

注意使用的不同索引(i vs 12) - 我猜第二个版本就是你想要的。如果这不是简单的复制粘贴错误,我建议您重新检查您的流程以验证您是否正在处理正确的文件。