We are working on getting the documentation cleaned up to the point where it can be released. If you look at the test cases, you can infer what needs to be done. Basically since this is targeted for OpenCL, we annotate OpenCL kernels slightly different than normal functions and that is what causes the code to be generated. That being said, on my list of things to do is fix this so that any function will be generated correctly and also create calling conventions that differentiate between kernels and non-kernels. Micah From: Daniels, Marcus G [mailto:mdaniels at lanl.gov] Sent: Tuesday, December 13, 2011 7:19 AM To: Villmow, Micah Cc: LLVM Developers Mailing List Subject: Re: [LLVMdev] AMD IL Code Generator Backend for OpenCL On Dec 12, 2011, at 9:09 AM, Villmow, Micah wrote: LLVM-IR that isn't generated from AMD's OpenCL frontend does not produce any AMDIL. Is this because of the way metadata is handled? If so, will that technique be documented? Or can it be reasonably inferred from the source code? Thanks, Marcus -------------- next part -------------- An HTML attachment was scrubbed... URL: <http://lists.llvm.org/pipermail/llvm-dev/attachments/20111213/bfa22f71/attachment.html>
Daniels, Marcus G
2011-Dec-13 21:34 UTC
[LLVMdev] AMD IL Code Generator Backend for OpenCL
Hi Micah, all, On Dec 13, 2011, at 8:49 AM, Villmow, Micah wrote: If you look at the test cases, you can infer what needs to be done. Basically since this is targeted for OpenCL, we annotate OpenCL kernels slightly different than normal functions and that is what causes the code to be generated. That being said, on my list of things to do is fix this so that any function will be generated correctly and also create calling conventions that differentiate between kernels and non-kernels. `triple.ll' in your patch has this metadata, but I can't see how to construct it with clang.. %0 = type { i8*, i8*, i8*, i8*, i32 } @sgv = internal addrspace(2) constant [1 x i8] zeroinitializer @fgv = internal addrspace(2) constant [1 x i8] zeroinitializer @lvgv = internal constant [0 x i8*] zeroinitializer @llvm.global.annotations = appending global [1 x %0] [%0 { i8* bitcast (void ()* @__OpenCL_foo_kernel to i8*), i8* bitcast ([1 x i8] addrspace(2)* @sgv to i8*), i8* bitcast ([1 x i8] addrspace(2)* @fgv to i8*), i8* bitcast ([0 x i8*]* @lvgv to i8*), i32 0 }], section "llvm.metadata" define void @__OpenCL_foo_kernel() nounwind readnone { entry: ret void } Here's my attempt.. I'm guessing that __kernel in OpenCL triggers your annotation, but when I try to use annotate("doesNothing") there's no sign of "doesNothing" in the resulting IR. Thus, my attempt with the function pointers. %0 still has a different form, however. What do "sgv" and "fgv" stand for? Stack & Frame? The semantics of these isn't obvious from the test cases. $ cat a.c static const char __attribute__ ((address_space(2))) sgv[1]; static const char __attribute__ ((address_space(2))) fgv[1]; static const char* lvgv[0]; void __attribute__ ((annotate("doesNothing"))) func () { char val; val = sgv[0]; val = fgv[0]; val = *lvgv[0]; } void __attribute__ ((annotate("foobar"))) (*__OpenCL_my_kernel) () = func; $ clang -S -emit-llvm a.c $ cat a.s ; ModuleID = 'a.c' 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-v64:64:64-v128:128:128-a0:0:64-s0:64:64-f80:128:128-n8:16:32:64" target triple = "x86_64-unknown-linux-gnu" %0 = type { i8*, i8*, i8*, i32 } @sgv = internal addrspace(2) constant [1 x i8] zeroinitializer, align 1 @fgv = internal addrspace(2) constant [1 x i8] zeroinitializer, align 1 @lvgv = internal global [0 x i8*] zeroinitializer, align 8 @__OpenCL_my_kernel = global void (...)* bitcast (void ()* @func to void (...)*), align 8 @__OpenCL_my_kernel1 = private global [7 x i8] c"foobar\00" @.str = private unnamed_addr global [4 x i8] c"a.c\00" @llvm.global.annotations = appending global [1 x %0] [%0 { i8* bitcast (void (...)** @__OpenCL_my_kernel to i8*), i8* getelementptr inbounds ([7 x i8]* @__OpenCL_my_kernel1, i32 0, i32 0), i8* getelementptr inbounds ([4 x i8]* @.str, i32 0, i32 0), i32 12 }], section "llvm.metadata" define void @func() nounwind { %val = alloca i8, align 1 %1 = load i8 addrspace(2)* getelementptr inbounds ([1 x i8] addrspace(2)* @sgv, i32 0, i64 0) store i8 %1, i8* %val, align 1 %2 = load i8 addrspace(2)* getelementptr inbounds ([1 x i8] addrspace(2)* @fgv, i32 0, i64 0) store i8 %2, i8* %val, align 1 %3 = load i8** getelementptr inbounds ([0 x i8*]* @lvgv, i32 0, i64 0) %4 = load i8* %3 store i8 %4, i8* %val, align 1 ret void } Adding "__kernel" to "func" does create some metadata when clang is in OpenCL mode, and the IR looks like this: !opencl.kernels = !{!0} !0 = metadata !{void ()* @func} Cheers, Marcus -------------- next part -------------- An HTML attachment was scrubbed... URL: <http://lists.llvm.org/pipermail/llvm-dev/attachments/20111213/2649ee01/attachment.html>
sgv stands for string global variable, and is a string to represent certain attributes in LLVM-IR. This is fairly ancient and in the future we will be using named metadata/metadata nodes. You can look at AMDILModuleInfo.cpp:parseSGV to see what the string can contain, but for most cases, it can be a zero initialized array of i8 of size 1. FGV stores the filename. LVGV stores information about local arrays that are declared at the kernel scope in OpenCL. So, basically the structure looks like this: struct { const char* kernel; const char* sgv; const char* fgv; const char* lvgv; unsigned kernel#; } llvm_global_annotations a[]. If you encode your function name with __OpenCL_<name>_kernel, it should trigger code generation. Also, we do not use clang for our frontend, so I'm not sure how it would generate code. Micah From: Daniels, Marcus G [mailto:mdaniels at lanl.gov] Sent: Tuesday, December 13, 2011 1:34 PM To: Villmow, Micah Cc: LLVM Developers Mailing List Subject: Re: [LLVMdev] AMD IL Code Generator Backend for OpenCL Hi Micah, all, On Dec 13, 2011, at 8:49 AM, Villmow, Micah wrote: If you look at the test cases, you can infer what needs to be done. Basically since this is targeted for OpenCL, we annotate OpenCL kernels slightly different than normal functions and that is what causes the code to be generated. That being said, on my list of things to do is fix this so that any function will be generated correctly and also create calling conventions that differentiate between kernels and non-kernels. `triple.ll' in your patch has this metadata, but I can't see how to construct it with clang.. %0 = type { i8*, i8*, i8*, i8*, i32 } @sgv = internal addrspace(2) constant [1 x i8] zeroinitializer @fgv = internal addrspace(2) constant [1 x i8] zeroinitializer @lvgv = internal constant [0 x i8*] zeroinitializer @llvm.global.annotations = appending global [1 x %0] [%0 { i8* bitcast (void ()* @__OpenCL_foo_kernel to i8*), i8* bitcast ([1 x i8] addrspace(2)* @sgv to i8*), i8* bitcast ([1 x i8] addrspace(2)* @fgv to i8*), i8* bitcast ([0 x i8*]* @lvgv to i8*), i32 0 }], section "llvm.metadata" define void @__OpenCL_foo_kernel() nounwind readnone { entry: ret void } Here's my attempt.. I'm guessing that __kernel in OpenCL triggers your annotation, but when I try to use annotate("doesNothing") there's no sign of "doesNothing" in the resulting IR. Thus, my attempt with the function pointers. %0 still has a different form, however. What do "sgv" and "fgv" stand for? Stack & Frame? The semantics of these isn't obvious from the test cases. $ cat a.c static const char __attribute__ ((address_space(2))) sgv[1]; static const char __attribute__ ((address_space(2))) fgv[1]; static const char* lvgv[0]; void __attribute__ ((annotate("doesNothing"))) func () { char val; val = sgv[0]; val = fgv[0]; val = *lvgv[0]; } void __attribute__ ((annotate("foobar"))) (*__OpenCL_my_kernel) () = func; $ clang -S -emit-llvm a.c $ cat a.s ; ModuleID = 'a.c' 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-v64:64:64-v128:128:128-a0:0:64-s0:64:64-f80:128:128-n8:16:32:64" target triple = "x86_64-unknown-linux-gnu" %0 = type { i8*, i8*, i8*, i32 } @sgv = internal addrspace(2) constant [1 x i8] zeroinitializer, align 1 @fgv = internal addrspace(2) constant [1 x i8] zeroinitializer, align 1 @lvgv = internal global [0 x i8*] zeroinitializer, align 8 @__OpenCL_my_kernel = global void (...)* bitcast (void ()* @func to void (...)*), align 8 @__OpenCL_my_kernel1 = private global [7 x i8] c"foobar\00" @.str = private unnamed_addr global [4 x i8] c"a.c\00" @llvm.global.annotations = appending global [1 x %0] [%0 { i8* bitcast (void (...)** @__OpenCL_my_kernel to i8*), i8* getelementptr inbounds ([7 x i8]* @__OpenCL_my_kernel1, i32 0, i32 0), i8* getelementptr inbounds ([4 x i8]* @.str, i32 0, i32 0), i32 12 }], section "llvm.metadata" define void @func() nounwind { %val = alloca i8, align 1 %1 = load i8 addrspace(2)* getelementptr inbounds ([1 x i8] addrspace(2)* @sgv, i32 0, i64 0) store i8 %1, i8* %val, align 1 %2 = load i8 addrspace(2)* getelementptr inbounds ([1 x i8] addrspace(2)* @fgv, i32 0, i64 0) store i8 %2, i8* %val, align 1 %3 = load i8** getelementptr inbounds ([0 x i8*]* @lvgv, i32 0, i64 0) %4 = load i8* %3 store i8 %4, i8* %val, align 1 ret void } Adding "__kernel" to "func" does create some metadata when clang is in OpenCL mode, and the IR looks like this: !opencl.kernels = !{!0} !0 = metadata !{void ()* @func} Cheers, Marcus -------------- next part -------------- An HTML attachment was scrubbed... URL: <http://lists.llvm.org/pipermail/llvm-dev/attachments/20111213/4d337b7e/attachment.html>