[Mesa-dev,27/47] clover/llvm: Split shared codegen support code into separate file.

Submitted by Francisco Jerez on July 4, 2016, 12:51 a.m.

Details

Message ID 20160704005156.5703-28-currojerez@riseup.net
State New
Headers show
Series "Series without cover letter" ( rev: 1 ) in Mesa

Not browsing as part of any series.

Commit Message

Francisco Jerez July 4, 2016, 12:51 a.m.
This is the common part of the code used to generate a clover::module
from LLVM bitcode, shared between the native and LLVM paths.

Reviewed-by: Serge Martin <edb+mesa@sigluy.net>
---
 src/gallium/state_trackers/clover/Makefile.sources |   2 +
 src/gallium/state_trackers/clover/llvm/codegen.hpp |  48 +++++
 .../state_trackers/clover/llvm/codegen/common.cpp  | 210 +++++++++++++++++++++
 .../state_trackers/clover/llvm/invocation.cpp      | 158 +---------------
 4 files changed, 261 insertions(+), 157 deletions(-)
 create mode 100644 src/gallium/state_trackers/clover/llvm/codegen.hpp
 create mode 100644 src/gallium/state_trackers/clover/llvm/codegen/common.cpp

Patch hide | download patch | download mbox

diff --git a/src/gallium/state_trackers/clover/Makefile.sources b/src/gallium/state_trackers/clover/Makefile.sources
index ae9d92c..2f45611 100644
--- a/src/gallium/state_trackers/clover/Makefile.sources
+++ b/src/gallium/state_trackers/clover/Makefile.sources
@@ -54,6 +54,8 @@  CPP_SOURCES := \
 	util/tuple.hpp
 
 LLVM_SOURCES := \
+	llvm/codegen/common.cpp \
+	llvm/codegen.hpp \
 	llvm/compat.hpp \
 	llvm/invocation.cpp \
 	llvm/metadata.hpp \
diff --git a/src/gallium/state_trackers/clover/llvm/codegen.hpp b/src/gallium/state_trackers/clover/llvm/codegen.hpp
new file mode 100644
index 0000000..23f3b17
--- /dev/null
+++ b/src/gallium/state_trackers/clover/llvm/codegen.hpp
@@ -0,0 +1,48 @@ 
+//
+// Copyright 2016 Francisco Jerez
+//
+// Permission is hereby granted, free of charge, to any person obtaining a
+// copy of this software and associated documentation files (the "Software"),
+// to deal in the Software without restriction, including without limitation
+// the rights to use, copy, modify, merge, publish, distribute, sublicense,
+// and/or sell copies of the Software, and to permit persons to whom the
+// Software is furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
+// OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+// ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+// OTHER DEALINGS IN THE SOFTWARE.
+//
+
+///
+/// \file
+/// Tools to generate various forms of binary code from existing LLVM IR in
+/// the given llvm::Module object and output the result as a clover::module.
+///
+
+#ifndef CLOVER_LLVM_CODEGEN_HPP
+#define CLOVER_LLVM_CODEGEN_HPP
+
+#include "core/module.hpp"
+
+#include <llvm/IR/Module.h>
+
+#include <clang/Frontend/CompilerInstance.h>
+
+namespace clover {
+   namespace llvm {
+      module
+      build_module_common(const ::llvm::Module &mod,
+                          const std::vector<char> &code,
+                          const std::map<std::string, unsigned> &offsets,
+                          const clang::CompilerInstance &c);
+   }
+}
+
+#endif
diff --git a/src/gallium/state_trackers/clover/llvm/codegen/common.cpp b/src/gallium/state_trackers/clover/llvm/codegen/common.cpp
new file mode 100644
index 0000000..2d52fdc
--- /dev/null
+++ b/src/gallium/state_trackers/clover/llvm/codegen/common.cpp
@@ -0,0 +1,210 @@ 
+//
+// Copyright 2012-2016 Francisco Jerez
+// Copyright 2012-2016 Advanced Micro Devices, Inc.
+// Copyright 2015 Zoltan Gilian
+//
+// Permission is hereby granted, free of charge, to any person obtaining a
+// copy of this software and associated documentation files (the "Software"),
+// to deal in the Software without restriction, including without limitation
+// the rights to use, copy, modify, merge, publish, distribute, sublicense,
+// and/or sell copies of the Software, and to permit persons to whom the
+// Software is furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
+// OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+// ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+// OTHER DEALINGS IN THE SOFTWARE.
+//
+
+///
+/// \file
+/// Codegen back-end-independent part of the construction of an executable
+/// clover::module, including kernel argument metadata extraction and
+/// formatting of the pre-generated binary code in a form that can be
+/// understood by pipe drivers.
+///
+
+#include "llvm/codegen.hpp"
+#include "llvm/metadata.hpp"
+
+#include "CL/cl.h"
+
+#include "pipe/p_state.h"
+#include "util/u_math.h"
+
+#include <clang/Basic/TargetInfo.h>
+
+using namespace clover;
+using namespace clover::llvm;
+
+using ::llvm::Module;
+using ::llvm::Function;
+using ::llvm::Type;
+using ::llvm::isa;
+using ::llvm::cast;
+using ::llvm::dyn_cast;
+
+namespace {
+   enum module::argument::type
+   get_image_type(const std::string &type,
+                  const std::string &qual) {
+      if (type == "image2d_t" && qual == "read_only")
+         return module::argument::image2d_rd;
+      else if (type == "image2d_t" && qual == "write_only")
+         return module::argument::image2d_wr;
+      else if (type == "image3d_t" && qual == "read_only")
+         return module::argument::image3d_rd;
+      else if (type == "image3d_t" && qual == "write_only")
+         return module::argument::image3d_wr;
+      else
+         unreachable("Unknown image type");
+   }
+
+   std::vector<module::argument>
+   make_kernel_args(const Module &mod, const std::string &kernel_name,
+                    const clang::CompilerInstance &c) {
+      std::vector<module::argument> args;
+      const auto address_spaces = c.getTarget().getAddressSpaceMap();
+      const Function &f = *mod.getFunction(kernel_name);
+      ::llvm::DataLayout dl(&mod);
+      const auto size_type =
+         dl.getSmallestLegalIntType(mod.getContext(), sizeof(cl_uint) * 8);
+
+      for (const auto &arg : f.args()) {
+         const auto arg_type = arg.getType();
+
+         // OpenCL 1.2 specification, Ch. 6.1.5: "A built-in data
+         // type that is not a power of two bytes in size must be
+         // aligned to the next larger power of two".  We need this
+         // alignment for three element vectors, which have
+         // non-power-of-2 store size.
+         const unsigned arg_store_size = dl.getTypeStoreSize(arg_type);
+         const unsigned arg_api_size = util_next_power_of_two(arg_store_size);
+
+         const auto target_type = !arg_type->isIntegerTy() ? arg_type :
+            dl.getSmallestLegalIntType(mod.getContext(), arg_store_size * 8);
+         const unsigned target_size = dl.getTypeStoreSize(target_type);
+         const unsigned target_align = dl.getABITypeAlignment(target_type);
+
+         const auto type_name = get_argument_metadata(f, arg,
+                                                      "kernel_arg_type");
+
+         if (type_name == "image2d_t" || type_name == "image3d_t") {
+            // Image.
+            const auto access_qual = get_argument_metadata(
+               f, arg, "kernel_arg_access_qual");
+            args.emplace_back(get_image_type(type_name, access_qual),
+                              arg_store_size, target_size,
+                              target_align, module::argument::zero_ext);
+
+         } else if (type_name == "__llvm_image_size") {
+            // Image size implicit argument.
+            args.emplace_back(module::argument::scalar, sizeof(cl_uint),
+                              dl.getTypeStoreSize(size_type),
+                              dl.getABITypeAlignment(size_type),
+                              module::argument::zero_ext,
+                              module::argument::image_size);
+
+         } else if (type_name == "__llvm_image_format") {
+            // Image format implicit argument.
+            args.emplace_back(module::argument::scalar, sizeof(cl_uint),
+                              dl.getTypeStoreSize(size_type),
+                              dl.getABITypeAlignment(size_type),
+                              module::argument::zero_ext,
+                              module::argument::image_format);
+
+         } else {
+            // Other types.
+            const auto actual_type =
+               isa<::llvm::PointerType>(arg_type) && arg.hasByValAttr() ?
+               cast<::llvm::PointerType>(arg_type)->getElementType() : arg_type;
+
+            if (actual_type->isPointerTy()) {
+               const unsigned address_space =
+                  cast<::llvm::PointerType>(actual_type)->getAddressSpace();
+
+               if (address_space == address_spaces[clang::LangAS::opencl_local
+                                                   - clang::LangAS::Offset]) {
+                  args.emplace_back(module::argument::local, arg_api_size,
+                                    target_size, target_align,
+                                    module::argument::zero_ext);
+               } else {
+                  // XXX: Correctly handle constant address space.  There is no
+                  // way for r600g to pass a handle for constant buffers back
+                  // to clover like it can for global buffers, so
+                  // creating constant arguments will break r600g.  For now,
+                  // continue treating constant buffers as global buffers
+                  // until we can come up with a way to create handles for
+                  // constant buffers.
+                  args.emplace_back(module::argument::global, arg_api_size,
+                                    target_size, target_align,
+                                    module::argument::zero_ext);
+               }
+
+            } else {
+               const bool needs_sign_ext = f.getAttributes().hasAttribute(
+                  arg.getArgNo() + 1, ::llvm::Attribute::SExt);
+
+               args.emplace_back(module::argument::scalar, arg_api_size,
+                                 target_size, target_align,
+                                 (needs_sign_ext ? module::argument::sign_ext :
+                                  module::argument::zero_ext));
+            }
+         }
+      }
+
+      // Append implicit arguments.  XXX - The types, ordering and
+      // vector size of the implicit arguments should depend on the
+      // target according to the selected calling convention.
+      args.emplace_back(module::argument::scalar, sizeof(cl_uint),
+                        dl.getTypeStoreSize(size_type),
+                        dl.getABITypeAlignment(size_type),
+                        module::argument::zero_ext,
+                        module::argument::grid_dimension);
+
+      args.emplace_back(module::argument::scalar, sizeof(cl_uint),
+                        dl.getTypeStoreSize(size_type),
+                        dl.getABITypeAlignment(size_type),
+                        module::argument::zero_ext,
+                        module::argument::grid_offset);
+
+      return args;
+   }
+
+   module::section
+   make_text_section(const std::vector<char> &code) {
+      const pipe_llvm_program_header header { uint32_t(code.size()) };
+      module::section text { 0, module::section::text, header.num_bytes, {} };
+
+      text.data.insert(text.data.end(), reinterpret_cast<const char *>(&header),
+                       reinterpret_cast<const char *>(&header) + sizeof(header));
+      text.data.insert(text.data.end(), code.begin(), code.end());
+
+      return text;
+   }
+}
+
+module
+clover::llvm::build_module_common(const Module &mod,
+                                  const std::vector<char> &code,
+                                  const std::map<std::string,
+                                                 unsigned> &offsets,
+                                  const clang::CompilerInstance &c) {
+   module m;
+
+   for (const auto &name : map(std::mem_fn(&Function::getName),
+                               get_kernels(mod))) {
+      if (offsets.count(name))
+         m.syms.emplace_back(name, 0, offsets.at(name),
+                             make_kernel_args(mod, name, c));
+   }
+
+   m.secs.push_back(make_text_section(code));
+   return m;
+}
diff --git a/src/gallium/state_trackers/clover/llvm/invocation.cpp b/src/gallium/state_trackers/clover/llvm/invocation.cpp
index a51411d..857ae2a 100644
--- a/src/gallium/state_trackers/clover/llvm/invocation.cpp
+++ b/src/gallium/state_trackers/clover/llvm/invocation.cpp
@@ -24,6 +24,7 @@ 
 // OTHER DEALINGS IN THE SOFTWARE.
 //
 
+#include "llvm/codegen.hpp"
 #include "llvm/compat.hpp"
 #include "llvm/metadata.hpp"
 #include "llvm/util.hpp"
@@ -249,163 +250,6 @@  namespace {
       pm.run(mod);
    }
 
-   enum module::argument::type
-   get_image_type(const std::string &type,
-                  const std::string &qual) {
-      if (type == "image2d_t" && qual == "read_only")
-         return module::argument::image2d_rd;
-      else if (type == "image2d_t" && qual == "write_only")
-         return module::argument::image2d_wr;
-      else if (type == "image3d_t" && qual == "read_only")
-         return module::argument::image3d_rd;
-      else if (type == "image3d_t" && qual == "write_only")
-         return module::argument::image3d_wr;
-      else
-         unreachable("Unknown image type");
-   }
-
-   std::vector<module::argument>
-   make_kernel_args(const Module &mod, const std::string &kernel_name,
-                    const clang::CompilerInstance &c) {
-      std::vector<module::argument> args;
-      const auto address_spaces = c.getTarget().getAddressSpaceMap();
-      const Function &f = *mod.getFunction(kernel_name);
-      ::llvm::DataLayout dl(&mod);
-      const auto size_type =
-         dl.getSmallestLegalIntType(mod.getContext(), sizeof(cl_uint) * 8);
-
-      for (const auto &arg : f.args()) {
-         const auto arg_type = arg.getType();
-
-         // OpenCL 1.2 specification, Ch. 6.1.5: "A built-in data
-         // type that is not a power of two bytes in size must be
-         // aligned to the next larger power of two".  We need this
-         // alignment for three element vectors, which have
-         // non-power-of-2 store size.
-         const unsigned arg_store_size = dl.getTypeStoreSize(arg_type);
-         const unsigned arg_api_size = util_next_power_of_two(arg_store_size);
-
-         const auto target_type = !arg_type->isIntegerTy() ? arg_type :
-            dl.getSmallestLegalIntType(mod.getContext(), arg_store_size * 8);
-         const unsigned target_size = dl.getTypeStoreSize(target_type);
-         const unsigned target_align = dl.getABITypeAlignment(target_type);
-
-         const auto type_name = get_argument_metadata(f, arg,
-                                                      "kernel_arg_type");
-
-         if (type_name == "image2d_t" || type_name == "image3d_t") {
-            // Image.
-            const auto access_qual = get_argument_metadata(
-               f, arg, "kernel_arg_access_qual");
-            args.emplace_back(get_image_type(type_name, access_qual),
-                              arg_store_size, target_size,
-                              target_align, module::argument::zero_ext);
-
-         } else if (type_name == "__llvm_image_size") {
-            // Image size implicit argument.
-            args.emplace_back(module::argument::scalar, sizeof(cl_uint),
-                              dl.getTypeStoreSize(size_type),
-                              dl.getABITypeAlignment(size_type),
-                              module::argument::zero_ext,
-                              module::argument::image_size);
-
-         } else if (type_name == "__llvm_image_format") {
-            // Image format implicit argument.
-            args.emplace_back(module::argument::scalar, sizeof(cl_uint),
-                              dl.getTypeStoreSize(size_type),
-                              dl.getABITypeAlignment(size_type),
-                              module::argument::zero_ext,
-                              module::argument::image_format);
-
-         } else {
-            // Other types.
-            const auto actual_type =
-               isa<::llvm::PointerType>(arg_type) && arg.hasByValAttr() ?
-               cast<::llvm::PointerType>(arg_type)->getElementType() : arg_type;
-
-            if (actual_type->isPointerTy()) {
-               const unsigned address_space =
-                  cast<::llvm::PointerType>(actual_type)->getAddressSpace();
-
-               if (address_space == address_spaces[clang::LangAS::opencl_local
-                                                   - clang::LangAS::Offset]) {
-                  args.emplace_back(module::argument::local, arg_api_size,
-                                    target_size, target_align,
-                                    module::argument::zero_ext);
-               } else {
-                  // XXX: Correctly handle constant address space.  There is no
-                  // way for r600g to pass a handle for constant buffers back
-                  // to clover like it can for global buffers, so
-                  // creating constant arguments will break r600g.  For now,
-                  // continue treating constant buffers as global buffers
-                  // until we can come up with a way to create handles for
-                  // constant buffers.
-                  args.emplace_back(module::argument::global, arg_api_size,
-                                    target_size, target_align,
-                                    module::argument::zero_ext);
-               }
-
-            } else {
-               const bool needs_sign_ext = f.getAttributes().hasAttribute(
-                  arg.getArgNo() + 1, ::llvm::Attribute::SExt);
-
-               args.emplace_back(module::argument::scalar, arg_api_size,
-                                 target_size, target_align,
-                                 (needs_sign_ext ? module::argument::sign_ext :
-                                  module::argument::zero_ext));
-            }
-         }
-      }
-
-      // Append implicit arguments.  XXX - The types, ordering and
-      // vector size of the implicit arguments should depend on the
-      // target according to the selected calling convention.
-      args.emplace_back(module::argument::scalar, sizeof(cl_uint),
-                        dl.getTypeStoreSize(size_type),
-                        dl.getABITypeAlignment(size_type),
-                        module::argument::zero_ext,
-                        module::argument::grid_dimension);
-
-      args.emplace_back(module::argument::scalar, sizeof(cl_uint),
-                        dl.getTypeStoreSize(size_type),
-                        dl.getABITypeAlignment(size_type),
-                        module::argument::zero_ext,
-                        module::argument::grid_offset);
-
-      return args;
-   }
-
-   module::section
-   make_text_section(const std::vector<char> &code) {
-      const pipe_llvm_program_header header { uint32_t(code.size()) };
-      module::section text { 0, module::section::text, header.num_bytes, {} };
-
-      text.data.insert(text.data.end(), reinterpret_cast<const char *>(&header),
-                       reinterpret_cast<const char *>(&header) + sizeof(header));
-      text.data.insert(text.data.end(), code.begin(), code.end());
-
-      return text;
-   }
-
-   module
-   build_module_common(const Module &mod,
-                       const std::vector<char> &code,
-                       const std::map<std::string,
-                                      unsigned> &offsets,
-                       const clang::CompilerInstance &c) {
-      module m;
-
-      for (const auto &name : map(std::mem_fn(&Function::getName),
-                                  get_kernels(mod))) {
-         if (offsets.count(name))
-            m.syms.emplace_back(name, 0, offsets.at(name),
-                                make_kernel_args(mod, name, c));
-      }
-
-      m.secs.push_back(make_text_section(code));
-      return m;
-   }
-
    std::map<std::string, unsigned>
    get_symbol_offsets(const ::llvm::Module &mod) {
       std::map<std::string, unsigned> offsets;