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, clang::LangStandard::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();
201 if (!clang::CompilerInvocation::CreateFromArgs(
202 c
->getInvocation(), copts
.data(), copts
.data() + copts
.size(), diag
))
203 throw invalid_build_options_error();
205 diag_buffer
->FlushDiagnostics(diag
);
206 if (diag
.hasErrorOccurred())
207 throw invalid_build_options_error();
209 c
->getTargetOpts().CPU
= target
.cpu
;
210 c
->getTargetOpts().Triple
= target
.triple
;
211 c
->getLangOpts().NoBuiltin
= true;
213 // This is a workaround for a Clang bug which causes the number
214 // of warnings and errors to be printed to stderr.
215 // http://www.llvm.org/bugs/show_bug.cgi?id=19735
216 c
->getDiagnosticOpts().ShowCarets
= false;
218 compat::set_lang_defaults(c
->getInvocation(), c
->getLangOpts(),
219 compat::ik_opencl
, ::llvm::Triple(target
.triple
),
220 c
->getPreprocessorOpts(),
221 clang::LangStandard::lang_opencl11
);
223 c
->createDiagnostics(new clang::TextDiagnosticPrinter(
224 *new raw_string_ostream(r_log
),
225 &c
->getDiagnosticOpts(), true));
227 c
->setTarget(clang::TargetInfo::CreateTargetInfo(
228 c
->getDiagnostics(), c
->getInvocation().TargetOpts
));
233 std::unique_ptr
<Module
>
234 compile(LLVMContext
&ctx
, clang::CompilerInstance
&c
,
235 const std::string
&name
, const std::string
&source
,
236 const header_map
&headers
, const device
&dev
,
237 const std::string
&opts
, std::string
&r_log
) {
238 c
.getFrontendOpts().ProgramAction
= clang::frontend::EmitLLVMOnly
;
239 c
.getHeaderSearchOpts().UseBuiltinIncludes
= true;
240 c
.getHeaderSearchOpts().UseStandardSystemIncludes
= true;
241 c
.getHeaderSearchOpts().ResourceDir
= CLANG_RESOURCE_DIR
;
243 // Add libclc generic search path
244 c
.getHeaderSearchOpts().AddPath(LIBCLC_INCLUDEDIR
,
245 clang::frontend::Angled
,
248 // Add libclc include
249 c
.getPreprocessorOpts().Includes
.push_back("clc/clc.h");
251 // Add definition for the OpenCL version
252 c
.getPreprocessorOpts().addMacroDef("__OPENCL_VERSION__=110");
254 // clc.h requires that this macro be defined:
255 c
.getPreprocessorOpts().addMacroDef("cl_clang_storage_class_specifiers");
256 c
.getPreprocessorOpts().addRemappedFile(
257 name
, ::llvm::MemoryBuffer::getMemBuffer(source
).release());
259 if (headers
.size()) {
260 const std::string tmp_header_path
= "/tmp/clover/";
262 c
.getHeaderSearchOpts().AddPath(tmp_header_path
,
263 clang::frontend::Angled
,
266 for (const auto &header
: headers
)
267 c
.getPreprocessorOpts().addRemappedFile(
268 tmp_header_path
+ header
.first
,
269 ::llvm::MemoryBuffer::getMemBuffer(header
.second
).release());
272 // Tell clang to link this file before performing any
273 // optimizations. This is required so that we can replace calls
274 // to the OpenCL C barrier() builtin with calls to target
275 // intrinsics that have the noduplicate attribute. This
276 // attribute will prevent Clang from creating illegal uses of
277 // barrier() (e.g. Moving barrier() inside a conditional that is
278 // no executed by all threads) during its optimizaton passes.
279 compat::add_link_bitcode_file(c
.getCodeGenOpts(),
280 LIBCLC_LIBEXECDIR
+ dev
.ir_target() + ".bc");
283 clang::EmitLLVMOnlyAction
act(&ctx
);
284 if (!c
.ExecuteAction(act
))
287 return act
.takeModule();
292 clover::llvm::compile_program(const std::string
&source
,
293 const header_map
&headers
,
295 const std::string
&opts
,
296 std::string
&r_log
) {
297 if (has_flag(debug::clc
))
298 debug::log(".cl", "// Options: " + opts
+ '\n' + source
);
300 auto ctx
= create_context(r_log
);
301 auto c
= create_compiler_instance(dev
, tokenize(opts
+ " input.cl"), r_log
);
302 auto mod
= compile(*ctx
, *c
, "input.cl", source
, headers
, dev
, opts
, r_log
);
304 if (has_flag(debug::llvm
))
305 debug::log(".ll", print_module_bitcode(*mod
));
307 return build_module_library(*mod
, module::section::text_intermediate
);
312 optimize(Module
&mod
, unsigned optimization_level
,
313 bool internalize_symbols
) {
314 compat::pass_manager pm
;
316 compat::add_data_layout_pass(pm
);
318 // By default, the function internalizer pass will look for a function
319 // called "main" and then mark all other functions as internal. Marking
320 // functions as internal enables the optimizer to perform optimizations
321 // like function inlining and global dead-code elimination.
323 // When there is no "main" function in a module, the internalize pass will
324 // treat the module like a library, and it won't internalize any functions.
325 // Since there is no "main" function in our kernels, we need to tell
326 // the internalizer pass that this module is not a library by passing a
327 // list of kernel functions to the internalizer. The internalizer will
328 // treat the functions in the list as "main" functions and internalize
329 // all of the other functions.
330 if (internalize_symbols
)
331 compat::add_internalize_pass(pm
, map(std::mem_fn(&Function::getName
),
334 ::llvm::PassManagerBuilder pmb
;
335 pmb
.OptLevel
= optimization_level
;
336 pmb
.LibraryInfo
= new compat::target_library_info(
337 ::llvm::Triple(mod
.getTargetTriple()));
338 pmb
.populateModulePassManager(pm
);
342 std::unique_ptr
<Module
>
343 link(LLVMContext
&ctx
, const clang::CompilerInstance
&c
,
344 const std::vector
<module
> &modules
, std::string
&r_log
) {
345 std::unique_ptr
<Module
> mod
{ new Module("link", ctx
) };
346 auto linker
= compat::create_linker(*mod
);
348 for (auto &m
: modules
) {
349 if (compat::link_in_module(*linker
,
350 parse_module_library(m
, ctx
, r_log
)))
354 return std::move(mod
);
359 clover::llvm::link_program(const std::vector
<module
> &modules
,
361 const std::string
&opts
, std::string
&r_log
) {
362 std::vector
<std::string
> options
= tokenize(opts
+ " input.cl");
363 const bool create_library
= count("-create-library", options
);
364 erase_if(equals("-create-library"), options
);
366 auto ctx
= create_context(r_log
);
367 auto c
= create_compiler_instance(dev
, options
, r_log
);
368 auto mod
= link(*ctx
, *c
, modules
, r_log
);
370 optimize(*mod
, c
->getCodeGenOpts().OptimizationLevel
, !create_library
);
372 static std::atomic_uint
seq(0);
373 const std::string id
= "." + mod
->getModuleIdentifier() + "-" +
374 std::to_string(seq
++);
376 if (has_flag(debug::llvm
))
377 debug::log(id
+ ".ll", print_module_bitcode(*mod
));
379 if (create_library
) {
380 return build_module_library(*mod
, module::section::text_library
);
382 } else if (dev
.ir_format() == PIPE_SHADER_IR_NATIVE
) {
383 if (has_flag(debug::native
))
384 debug::log(id
+ ".asm", print_module_native(*mod
, dev
.ir_target()));
386 return build_module_native(*mod
, dev
.ir_target(), *c
, r_log
);
389 unreachable("Unsupported IR.");