2 // Copyright 2012-2016 Francisco Jerez
3 // Copyright 2012-2016 Advanced Micro Devices, Inc.
4 // Copyright 2014-2016 Jan Vesely
5 // Copyright 2014-2015 Serge Martin
6 // Copyright 2015 Zoltan Gilian
8 // Permission is hereby granted, free of charge, to any person obtaining a
9 // copy of this software and associated documentation files (the "Software"),
10 // to deal in the Software without restriction, including without limitation
11 // the rights to use, copy, modify, merge, publish, distribute, sublicense,
12 // and/or sell copies of the Software, and to permit persons to whom the
13 // Software is furnished to do so, subject to the following conditions:
15 // The above copyright notice and this permission notice shall be included in
16 // all copies or substantial portions of the Software.
18 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
21 // THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
22 // OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
23 // ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
24 // OTHER DEALINGS IN THE SOFTWARE.
27 #include <llvm/IR/DiagnosticPrinter.h>
28 #include <llvm/IR/DiagnosticInfo.h>
29 #include <llvm/IR/LLVMContext.h>
30 #include <llvm/Support/raw_ostream.h>
31 #include <llvm/Transforms/IPO/PassManagerBuilder.h>
32 #include <llvm-c/Target.h>
34 #include <clang/CodeGen/CodeGenAction.h>
35 #include <clang/Lex/PreprocessorOptions.h>
36 #include <clang/Frontend/TextDiagnosticBuffer.h>
37 #include <clang/Frontend/TextDiagnosticPrinter.h>
38 #include <clang/Basic/TargetInfo.h>
40 // We need to include internal headers last, because the internal headers
41 // include CL headers which have #define's like:
43 //#define cl_khr_gl_sharing 1
44 //#define cl_khr_icd 1
46 // Which will break the compilation of clang/Basic/OpenCLOptions.h
48 #include "core/error.hpp"
49 #include "llvm/codegen.hpp"
50 #include "llvm/compat.hpp"
51 #include "llvm/invocation.hpp"
52 #include "llvm/metadata.hpp"
53 #include "llvm/util.hpp"
54 #include "util/algorithm.hpp"
57 using namespace clover
;
58 using namespace clover::llvm
;
60 using ::llvm::Function
;
61 using ::llvm::LLVMContext
;
63 using ::llvm::raw_string_ostream
;
68 std::string version_str
; // CL Version
69 unsigned version_number
; // Numeric CL Version
72 static const unsigned ANY_VERSION
= 999;
73 const cl_version cl_versions
[] = {
82 struct clc_version_lang_std
{
83 unsigned version_number
; // CLC Version
84 clang::LangStandard::Kind clc_lang_standard
;
87 const clc_version_lang_std cl_version_lang_stds
[] = {
88 { 100, compat::lang_opencl10
},
89 { 110, clang::LangStandard::lang_opencl11
},
90 { 120, clang::LangStandard::lang_opencl12
},
91 { 200, clang::LangStandard::lang_opencl20
},
96 static bool targets_initialized
= false;
97 if (!targets_initialized
) {
98 LLVMInitializeAllTargets();
99 LLVMInitializeAllTargetInfos();
100 LLVMInitializeAllTargetMCs();
101 LLVMInitializeAllAsmPrinters();
102 targets_initialized
= true;
107 diagnostic_handler(const ::llvm::DiagnosticInfo
&di
, void *data
) {
108 if (di
.getSeverity() == ::llvm::DS_Error
) {
109 raw_string_ostream os
{ *reinterpret_cast<std::string
*>(data
) };
110 ::llvm::DiagnosticPrinterRawOStream printer
{ os
};
116 std::unique_ptr
<LLVMContext
>
117 create_context(std::string
&r_log
) {
119 std::unique_ptr
<LLVMContext
> ctx
{ new LLVMContext
};
120 compat::set_diagnostic_handler(*ctx
, diagnostic_handler
, &r_log
);
124 const struct clc_version_lang_std
&
125 get_cl_lang_standard(unsigned requested
, unsigned max
= ANY_VERSION
) {
126 for (const struct clc_version_lang_std
&version
: cl_version_lang_stds
) {
127 if (version
.version_number
== max
||
128 version
.version_number
== requested
) {
132 throw build_error("Unknown/Unsupported language version");
135 const struct cl_version
&
136 get_cl_version(const std::string
&version_str
,
137 unsigned max
= ANY_VERSION
) {
138 for (const struct cl_version
&version
: cl_versions
) {
139 if (version
.version_number
== max
|| version
.version_str
== version_str
) {
143 throw build_error("Unknown/Unsupported language version");
146 clang::LangStandard::Kind
147 get_lang_standard_from_version_str(const std::string
&version_str
,
148 bool is_build_opt
= false) {
150 //Per CL 2.0 spec, section 5.8.4.5:
151 // If it's an option, use the value directly.
152 // If it's a device version, clamp to max 1.x version, a.k.a. 1.2
153 const cl_version version
=
154 get_cl_version(version_str
, is_build_opt
? ANY_VERSION
: 120);
156 const struct clc_version_lang_std standard
=
157 get_cl_lang_standard(version
.version_number
);
159 return standard
.clc_lang_standard
;
162 clang::LangStandard::Kind
163 get_language_version(const std::vector
<std::string
> &opts
,
164 const std::string
&device_version
) {
166 const std::string search
= "-cl-std=CL";
168 for (auto &opt
: opts
) {
169 auto pos
= opt
.find(search
);
171 const auto ver
= opt
.substr(pos
+ search
.size());
172 const auto device_ver
= get_cl_version(device_version
);
173 const auto requested
= get_cl_version(ver
);
174 if (requested
.version_number
> device_ver
.version_number
) {
177 return get_lang_standard_from_version_str(ver
, true);
181 return get_lang_standard_from_version_str(device_version
);
184 std::unique_ptr
<clang::CompilerInstance
>
185 create_compiler_instance(const device
&dev
,
186 const std::vector
<std::string
> &opts
,
187 std::string
&r_log
) {
188 std::unique_ptr
<clang::CompilerInstance
> c
{ new clang::CompilerInstance
};
189 clang::TextDiagnosticBuffer
*diag_buffer
= new clang::TextDiagnosticBuffer
;
190 clang::DiagnosticsEngine diag
{ new clang::DiagnosticIDs
,
191 new clang::DiagnosticOptions
, diag_buffer
};
193 // Parse the compiler options. A file name should be present at the end
194 // and must have the .cl extension in order for the CompilerInvocation
195 // class to recognize it as an OpenCL source file.
196 const std::vector
<const char *> copts
=
197 map(std::mem_fn(&std::string::c_str
), opts
);
199 const target
&target
= dev
.ir_target();
200 const std::string
&device_clc_version
= dev
.device_clc_version();
202 if (!clang::CompilerInvocation::CreateFromArgs(
203 c
->getInvocation(), copts
.data(), copts
.data() + copts
.size(), diag
))
204 throw invalid_build_options_error();
206 diag_buffer
->FlushDiagnostics(diag
);
207 if (diag
.hasErrorOccurred())
208 throw invalid_build_options_error();
210 c
->getTargetOpts().CPU
= target
.cpu
;
211 c
->getTargetOpts().Triple
= target
.triple
;
212 c
->getLangOpts().NoBuiltin
= true;
214 // This is a workaround for a Clang bug which causes the number
215 // of warnings and errors to be printed to stderr.
216 // http://www.llvm.org/bugs/show_bug.cgi?id=19735
217 c
->getDiagnosticOpts().ShowCarets
= false;
219 compat::set_lang_defaults(c
->getInvocation(), c
->getLangOpts(),
220 compat::ik_opencl
, ::llvm::Triple(target
.triple
),
221 c
->getPreprocessorOpts(),
222 get_language_version(opts
, device_clc_version
));
224 c
->createDiagnostics(new clang::TextDiagnosticPrinter(
225 *new raw_string_ostream(r_log
),
226 &c
->getDiagnosticOpts(), true));
228 c
->setTarget(clang::TargetInfo::CreateTargetInfo(
229 c
->getDiagnostics(), c
->getInvocation().TargetOpts
));
234 std::unique_ptr
<Module
>
235 compile(LLVMContext
&ctx
, clang::CompilerInstance
&c
,
236 const std::string
&name
, const std::string
&source
,
237 const header_map
&headers
, const device
&dev
,
238 const std::string
&opts
, std::string
&r_log
) {
239 c
.getFrontendOpts().ProgramAction
= clang::frontend::EmitLLVMOnly
;
240 c
.getHeaderSearchOpts().UseBuiltinIncludes
= true;
241 c
.getHeaderSearchOpts().UseStandardSystemIncludes
= true;
242 c
.getHeaderSearchOpts().ResourceDir
= CLANG_RESOURCE_DIR
;
244 // Add libclc generic search path
245 c
.getHeaderSearchOpts().AddPath(LIBCLC_INCLUDEDIR
,
246 clang::frontend::Angled
,
249 // Add libclc include
250 c
.getPreprocessorOpts().Includes
.push_back("clc/clc.h");
252 // Add definition for the OpenCL version
253 c
.getPreprocessorOpts().addMacroDef("__OPENCL_VERSION__=" +
254 std::to_string(get_cl_version(
255 dev
.device_version()).version_number
));
257 // clc.h requires that this macro be defined:
258 c
.getPreprocessorOpts().addMacroDef("cl_clang_storage_class_specifiers");
259 c
.getPreprocessorOpts().addRemappedFile(
260 name
, ::llvm::MemoryBuffer::getMemBuffer(source
).release());
262 if (headers
.size()) {
263 const std::string tmp_header_path
= "/tmp/clover/";
265 c
.getHeaderSearchOpts().AddPath(tmp_header_path
,
266 clang::frontend::Angled
,
269 for (const auto &header
: headers
)
270 c
.getPreprocessorOpts().addRemappedFile(
271 tmp_header_path
+ header
.first
,
272 ::llvm::MemoryBuffer::getMemBuffer(header
.second
).release());
275 // Tell clang to link this file before performing any
276 // optimizations. This is required so that we can replace calls
277 // to the OpenCL C barrier() builtin with calls to target
278 // intrinsics that have the noduplicate attribute. This
279 // attribute will prevent Clang from creating illegal uses of
280 // barrier() (e.g. Moving barrier() inside a conditional that is
281 // no executed by all threads) during its optimizaton passes.
282 compat::add_link_bitcode_file(c
.getCodeGenOpts(),
283 LIBCLC_LIBEXECDIR
+ dev
.ir_target() + ".bc");
286 clang::EmitLLVMOnlyAction
act(&ctx
);
287 if (!c
.ExecuteAction(act
))
290 return act
.takeModule();
295 clover::llvm::compile_program(const std::string
&source
,
296 const header_map
&headers
,
298 const std::string
&opts
,
299 std::string
&r_log
) {
300 if (has_flag(debug::clc
))
301 debug::log(".cl", "// Options: " + opts
+ '\n' + source
);
303 auto ctx
= create_context(r_log
);
304 auto c
= create_compiler_instance(dev
, tokenize(opts
+ " input.cl"), r_log
);
305 auto mod
= compile(*ctx
, *c
, "input.cl", source
, headers
, dev
, opts
, r_log
);
307 if (has_flag(debug::llvm
))
308 debug::log(".ll", print_module_bitcode(*mod
));
310 return build_module_library(*mod
, module::section::text_intermediate
);
315 optimize(Module
&mod
, unsigned optimization_level
,
316 bool internalize_symbols
) {
317 compat::pass_manager pm
;
319 compat::add_data_layout_pass(pm
);
321 // By default, the function internalizer pass will look for a function
322 // called "main" and then mark all other functions as internal. Marking
323 // functions as internal enables the optimizer to perform optimizations
324 // like function inlining and global dead-code elimination.
326 // When there is no "main" function in a module, the internalize pass will
327 // treat the module like a library, and it won't internalize any functions.
328 // Since there is no "main" function in our kernels, we need to tell
329 // the internalizer pass that this module is not a library by passing a
330 // list of kernel functions to the internalizer. The internalizer will
331 // treat the functions in the list as "main" functions and internalize
332 // all of the other functions.
333 if (internalize_symbols
)
334 compat::add_internalize_pass(pm
, map(std::mem_fn(&Function::getName
),
337 ::llvm::PassManagerBuilder pmb
;
338 pmb
.OptLevel
= optimization_level
;
339 pmb
.LibraryInfo
= new compat::target_library_info(
340 ::llvm::Triple(mod
.getTargetTriple()));
341 pmb
.populateModulePassManager(pm
);
345 std::unique_ptr
<Module
>
346 link(LLVMContext
&ctx
, const clang::CompilerInstance
&c
,
347 const std::vector
<module
> &modules
, std::string
&r_log
) {
348 std::unique_ptr
<Module
> mod
{ new Module("link", ctx
) };
349 auto linker
= compat::create_linker(*mod
);
351 for (auto &m
: modules
) {
352 if (compat::link_in_module(*linker
,
353 parse_module_library(m
, ctx
, r_log
)))
357 return std::move(mod
);
362 clover::llvm::link_program(const std::vector
<module
> &modules
,
364 const std::string
&opts
, std::string
&r_log
) {
365 std::vector
<std::string
> options
= tokenize(opts
+ " input.cl");
366 const bool create_library
= count("-create-library", options
);
367 erase_if(equals("-create-library"), options
);
369 auto ctx
= create_context(r_log
);
370 auto c
= create_compiler_instance(dev
, options
, r_log
);
371 auto mod
= link(*ctx
, *c
, modules
, r_log
);
373 optimize(*mod
, c
->getCodeGenOpts().OptimizationLevel
, !create_library
);
375 static std::atomic_uint
seq(0);
376 const std::string id
= "." + mod
->getModuleIdentifier() + "-" +
377 std::to_string(seq
++);
379 if (has_flag(debug::llvm
))
380 debug::log(id
+ ".ll", print_module_bitcode(*mod
));
382 if (create_library
) {
383 return build_module_library(*mod
, module::section::text_library
);
385 } else if (dev
.ir_format() == PIPE_SHADER_IR_NATIVE
) {
386 if (has_flag(debug::native
))
387 debug::log(id
+ ".asm", print_module_native(*mod
, dev
.ir_target()));
389 return build_module_native(*mod
, dev
.ir_target(), *c
, r_log
);
392 unreachable("Unsupported IR.");