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
27 using namespace clover;
28
program(clover::context & ctx,const std::string & source)29 program::program(clover::context &ctx, const std::string &source) :
30 has_source(true), context(ctx), _source(source), _kernel_ref_counter(0) {
31 }
32
program(clover::context & ctx,const ref_vector<device> & devs,const std::vector<module> & binaries)33 program::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
44 void
compile(const ref_vector<device> & devs,const std::string & opts,const header_map & headers)45 program::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
67 void
link(const ref_vector<device> & devs,const std::string & opts,const ref_vector<program> & progs)68 program::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
91 const std::string &
source() const92 program::source() const {
93 return _source;
94 }
95
96 program::device_range
devices() const97 program::devices() const {
98 return map(evals(), _devices);
99 }
100
101 cl_build_status
status() const102 program::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
111 cl_program_binary_type
binary_type() const112 program::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
123 const struct program::build &
build(const device & dev) const124 program::build(const device &dev) const {
125 static const struct build null;
126 return _builds.count(&dev) ? _builds.find(&dev)->second : null;
127 }
128
129 const std::vector<module::symbol> &
symbols() const130 program::symbols() const {
131 if (_builds.empty())
132 throw error(CL_INVALID_PROGRAM_EXECUTABLE);
133
134 return _builds.begin()->second.binary.syms;
135 }
136
137 unsigned
kernel_ref_count() const138 program::kernel_ref_count() const {
139 return _kernel_ref_counter.ref_count();
140 }
141