1//
2// Copyright 2012 Francisco Jerez
3//
4// Permission is hereby granted, free of charge, to any person obtaining a
5// copy of this software and associated documentation files (the "Software"),
6// to deal in the Software without restriction, including without limitation
7// the rights to use, copy, modify, merge, publish, distribute, sublicense,
8// and/or sell copies of the Software, and to permit persons to whom the
9// Software is furnished to do so, subject to the following conditions:
10//
11// The above copyright notice and this permission notice shall be included in
12// all copies or substantial portions of the Software.
13//
14// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
17// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
18// OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
19// ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
20// OTHER DEALINGS IN THE SOFTWARE.
21//
22
23#include "core/program.hpp"
24#include "llvm/invocation.hpp"
25#include "tgsi/invocation.hpp"
26
27using namespace clover;
28
29program::program(clover::context &ctx, const std::string &source) :
30   has_source(true), context(ctx), _source(source), _kernel_ref_counter(0) {
31}
32
33program::program(clover::context &ctx,
34                 const ref_vector<device> &devs,
35                 const std::vector<module> &binaries) :
36   has_source(false), context(ctx),
37   _devices(devs), _kernel_ref_counter(0) {
38   for_each([&](device &dev, const module &bin) {
39         _builds[&dev] = { bin };
40      },
41      devs, binaries);
42}
43
44void
45program::compile(const ref_vector<device> &devs, const std::string &opts,
46                 const header_map &headers) {
47   if (has_source) {
48      _devices = devs;
49
50      for (auto &dev : devs) {
51         std::string log;
52
53         try {
54            const module m = (dev.ir_format() == PIPE_SHADER_IR_TGSI ?
55                              tgsi::compile_program(_source, log) :
56                              llvm::compile_program(_source, headers,
57                                                    dev.ir_target(), opts, log));
58            _builds[&dev] = { m, opts, log };
59         } catch (...) {
60            _builds[&dev] = { module(), opts, log };
61            throw;
62         }
63      }
64   }
65}
66
67void
68program::link(const ref_vector<device> &devs, const std::string &opts,
69              const ref_vector<program> &progs) {
70   _devices = devs;
71
72   for (auto &dev : devs) {
73      const std::vector<module> ms = map([&](const program &prog) {
74         return prog.build(dev).binary;
75         }, progs);
76      std::string log = _builds[&dev].log;
77
78      try {
79         const module m = (dev.ir_format() == PIPE_SHADER_IR_TGSI ?
80                           tgsi::link_program(ms) :
81                           llvm::link_program(ms, dev.ir_format(),
82                                              dev.ir_target(), opts, log));
83         _builds[&dev] = { m, opts, log };
84      } catch (...) {
85         _builds[&dev] = { module(), opts, log };
86         throw;
87      }
88   }
89}
90
91const std::string &
92program::source() const {
93   return _source;
94}
95
96program::device_range
97program::devices() const {
98   return map(evals(), _devices);
99}
100
101cl_build_status
102program::build::status() const {
103   if (!binary.secs.empty())
104      return CL_BUILD_SUCCESS;
105   else if (log.size())
106      return CL_BUILD_ERROR;
107   else
108      return CL_BUILD_NONE;
109}
110
111cl_program_binary_type
112program::build::binary_type() const {
113   if (any_of(type_equals(module::section::text_intermediate), binary.secs))
114      return CL_PROGRAM_BINARY_TYPE_COMPILED_OBJECT;
115   else if (any_of(type_equals(module::section::text_library), binary.secs))
116      return CL_PROGRAM_BINARY_TYPE_LIBRARY;
117   else if (any_of(type_equals(module::section::text_executable), binary.secs))
118      return CL_PROGRAM_BINARY_TYPE_EXECUTABLE;
119   else
120      return CL_PROGRAM_BINARY_TYPE_NONE;
121}
122
123const struct program::build &
124program::build(const device &dev) const {
125   static const struct build null;
126   return _builds.count(&dev) ? _builds.find(&dev)->second : null;
127}
128
129const std::vector<module::symbol> &
130program::symbols() const {
131   if (_builds.empty())
132      throw error(CL_INVALID_PROGRAM_EXECUTABLE);
133
134   return _builds.begin()->second.binary.syms;
135}
136
137unsigned
138program::kernel_ref_count() const {
139   return _kernel_ref_counter.ref_count();
140}
141