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 static bool targets_initialized
= false;
69 if (!targets_initialized
) {
70 LLVMInitializeAllTargets();
71 LLVMInitializeAllTargetInfos();
72 LLVMInitializeAllTargetMCs();
73 LLVMInitializeAllAsmPrinters();
74 targets_initialized
= true;
79 diagnostic_handler(const ::llvm::DiagnosticInfo
&di
, void *data
) {
80 if (di
.getSeverity() == ::llvm::DS_Error
) {
81 raw_string_ostream os
{ *reinterpret_cast<std::string
*>(data
) };
82 ::llvm::DiagnosticPrinterRawOStream printer
{ os
};
88 std::unique_ptr
<LLVMContext
>
89 create_context(std::string
&r_log
) {
91 std::unique_ptr
<LLVMContext
> ctx
{ new LLVMContext
};
92 ctx
->setDiagnosticHandler(diagnostic_handler
, &r_log
);
96 std::unique_ptr
<clang::CompilerInstance
>
97 create_compiler_instance(const target
&target
,
98 const std::vector
<std::string
> &opts
,
100 std::unique_ptr
<clang::CompilerInstance
> c
{ new clang::CompilerInstance
};
101 clang::DiagnosticsEngine diag
{ new clang::DiagnosticIDs
,
102 new clang::DiagnosticOptions
, new clang::TextDiagnosticBuffer
};
104 // Parse the compiler options. A file name should be present at the end
105 // and must have the .cl extension in order for the CompilerInvocation
106 // class to recognize it as an OpenCL source file.
107 const std::vector
<const char *> copts
=
108 map(std::mem_fn(&std::string::c_str
), opts
);
110 if (!clang::CompilerInvocation::CreateFromArgs(
111 c
->getInvocation(), copts
.data(), copts
.data() + copts
.size(), diag
))
112 throw invalid_build_options_error();
114 c
->getTargetOpts().CPU
= target
.cpu
;
115 c
->getTargetOpts().Triple
= target
.triple
;
116 c
->getLangOpts().NoBuiltin
= true;
118 // This is a workaround for a Clang bug which causes the number
119 // of warnings and errors to be printed to stderr.
120 // http://www.llvm.org/bugs/show_bug.cgi?id=19735
121 c
->getDiagnosticOpts().ShowCarets
= false;
123 compat::set_lang_defaults(c
->getInvocation(), c
->getLangOpts(),
124 clang::IK_OpenCL
, ::llvm::Triple(target
.triple
),
125 c
->getPreprocessorOpts(),
126 clang::LangStandard::lang_opencl11
);
128 c
->createDiagnostics(new clang::TextDiagnosticPrinter(
129 *new raw_string_ostream(r_log
),
130 &c
->getDiagnosticOpts(), true));
132 c
->setTarget(clang::TargetInfo::CreateTargetInfo(
133 c
->getDiagnostics(), c
->getInvocation().TargetOpts
));
138 std::unique_ptr
<Module
>
139 compile(LLVMContext
&ctx
, clang::CompilerInstance
&c
,
140 const std::string
&name
, const std::string
&source
,
141 const header_map
&headers
, const std::string
&target
,
142 const std::string
&opts
, std::string
&r_log
) {
143 c
.getFrontendOpts().ProgramAction
= clang::frontend::EmitLLVMOnly
;
144 c
.getHeaderSearchOpts().UseBuiltinIncludes
= true;
145 c
.getHeaderSearchOpts().UseStandardSystemIncludes
= true;
146 c
.getHeaderSearchOpts().ResourceDir
= CLANG_RESOURCE_DIR
;
148 // Add libclc generic search path
149 c
.getHeaderSearchOpts().AddPath(LIBCLC_INCLUDEDIR
,
150 clang::frontend::Angled
,
153 // Add libclc include
154 c
.getPreprocessorOpts().Includes
.push_back("clc/clc.h");
156 // Add definition for the OpenCL version
157 c
.getPreprocessorOpts().addMacroDef("__OPENCL_VERSION__=110");
159 // clc.h requires that this macro be defined:
160 c
.getPreprocessorOpts().addMacroDef("cl_clang_storage_class_specifiers");
161 c
.getPreprocessorOpts().addRemappedFile(
162 name
, ::llvm::MemoryBuffer::getMemBuffer(source
).release());
164 if (headers
.size()) {
165 const std::string tmp_header_path
= "/tmp/clover/";
167 c
.getHeaderSearchOpts().AddPath(tmp_header_path
,
168 clang::frontend::Angled
,
171 for (const auto &header
: headers
)
172 c
.getPreprocessorOpts().addRemappedFile(
173 tmp_header_path
+ header
.first
,
174 ::llvm::MemoryBuffer::getMemBuffer(header
.second
).release());
177 // Tell clang to link this file before performing any
178 // optimizations. This is required so that we can replace calls
179 // to the OpenCL C barrier() builtin with calls to target
180 // intrinsics that have the noduplicate attribute. This
181 // attribute will prevent Clang from creating illegal uses of
182 // barrier() (e.g. Moving barrier() inside a conditional that is
183 // no executed by all threads) during its optimizaton passes.
184 compat::add_link_bitcode_file(c
.getCodeGenOpts(),
185 LIBCLC_LIBEXECDIR
+ target
+ ".bc");
188 clang::EmitLLVMOnlyAction
act(&ctx
);
189 if (!c
.ExecuteAction(act
))
192 return act
.takeModule();
197 clover::llvm::compile_program(const std::string
&source
,
198 const header_map
&headers
,
199 const std::string
&target
,
200 const std::string
&opts
,
201 std::string
&r_log
) {
202 if (has_flag(debug::clc
))
203 debug::log(".cl", "// Options: " + opts
+ '\n' + source
);
205 auto ctx
= create_context(r_log
);
206 auto c
= create_compiler_instance(target
, tokenize(opts
+ " input.cl"),
208 auto mod
= compile(*ctx
, *c
, "input.cl", source
, headers
, target
, opts
,
211 if (has_flag(debug::llvm
))
212 debug::log(".ll", print_module_bitcode(*mod
));
214 return build_module_library(*mod
, module::section::text_intermediate
);
219 optimize(Module
&mod
, unsigned optimization_level
,
220 bool internalize_symbols
) {
221 compat::pass_manager pm
;
223 compat::add_data_layout_pass(pm
);
225 // By default, the function internalizer pass will look for a function
226 // called "main" and then mark all other functions as internal. Marking
227 // functions as internal enables the optimizer to perform optimizations
228 // like function inlining and global dead-code elimination.
230 // When there is no "main" function in a module, the internalize pass will
231 // treat the module like a library, and it won't internalize any functions.
232 // Since there is no "main" function in our kernels, we need to tell
233 // the internalizer pass that this module is not a library by passing a
234 // list of kernel functions to the internalizer. The internalizer will
235 // treat the functions in the list as "main" functions and internalize
236 // all of the other functions.
237 if (internalize_symbols
)
238 compat::add_internalize_pass(pm
, map(std::mem_fn(&Function::getName
),
241 ::llvm::PassManagerBuilder pmb
;
242 pmb
.OptLevel
= optimization_level
;
243 pmb
.LibraryInfo
= new compat::target_library_info(
244 ::llvm::Triple(mod
.getTargetTriple()));
245 pmb
.populateModulePassManager(pm
);
249 std::unique_ptr
<Module
>
250 link(LLVMContext
&ctx
, const clang::CompilerInstance
&c
,
251 const std::vector
<module
> &modules
, std::string
&r_log
) {
252 std::unique_ptr
<Module
> mod
{ new Module("link", ctx
) };
253 auto linker
= compat::create_linker(*mod
);
255 for (auto &m
: modules
) {
256 if (compat::link_in_module(*linker
,
257 parse_module_library(m
, ctx
, r_log
)))
261 return std::move(mod
);
266 clover::llvm::link_program(const std::vector
<module
> &modules
,
267 enum pipe_shader_ir ir
, const std::string
&target
,
268 const std::string
&opts
, std::string
&r_log
) {
269 std::vector
<std::string
> options
= tokenize(opts
+ " input.cl");
270 const bool create_library
= count("-create-library", options
);
271 erase_if(equals("-create-library"), options
);
273 auto ctx
= create_context(r_log
);
274 auto c
= create_compiler_instance(target
, options
, r_log
);
275 auto mod
= link(*ctx
, *c
, modules
, r_log
);
277 optimize(*mod
, c
->getCodeGenOpts().OptimizationLevel
, !create_library
);
279 if (has_flag(debug::llvm
))
280 debug::log(".ll", print_module_bitcode(*mod
));
282 if (create_library
) {
283 return build_module_library(*mod
, module::section::text_library
);
285 } else if (ir
== PIPE_SHADER_IR_LLVM
) {
286 return build_module_bitcode(*mod
, *c
);
288 } else if (ir
== PIPE_SHADER_IR_NATIVE
) {
289 if (has_flag(debug::native
))
290 debug::log(".asm", print_module_native(*mod
, target
));
292 return build_module_native(*mod
, target
, *c
, r_log
);
295 unreachable("Unsupported IR.");