1c6db1b3396384186aab5b685fe1fd540e17b3a62Francisco Jerez//
2a8a966ddb5ad805421bb9548b150055d14fb5c63Francisco Jerez// Copyright 2012-2016 Francisco Jerez
3a8a966ddb5ad805421bb9548b150055d14fb5c63Francisco Jerez// Copyright 2012-2016 Advanced Micro Devices, Inc.
4a8a966ddb5ad805421bb9548b150055d14fb5c63Francisco Jerez// Copyright 2014-2016 Jan Vesely
5a8a966ddb5ad805421bb9548b150055d14fb5c63Francisco Jerez// Copyright 2014-2015 Serge Martin
6a8a966ddb5ad805421bb9548b150055d14fb5c63Francisco Jerez// Copyright 2015 Zoltan Gilian
7c6db1b3396384186aab5b685fe1fd540e17b3a62Francisco Jerez//
8c6db1b3396384186aab5b685fe1fd540e17b3a62Francisco Jerez// Permission is hereby granted, free of charge, to any person obtaining a
9c6db1b3396384186aab5b685fe1fd540e17b3a62Francisco Jerez// copy of this software and associated documentation files (the "Software"),
10c6db1b3396384186aab5b685fe1fd540e17b3a62Francisco Jerez// to deal in the Software without restriction, including without limitation
11c6db1b3396384186aab5b685fe1fd540e17b3a62Francisco Jerez// the rights to use, copy, modify, merge, publish, distribute, sublicense,
12c6db1b3396384186aab5b685fe1fd540e17b3a62Francisco Jerez// and/or sell copies of the Software, and to permit persons to whom the
13c6db1b3396384186aab5b685fe1fd540e17b3a62Francisco Jerez// Software is furnished to do so, subject to the following conditions:
14c6db1b3396384186aab5b685fe1fd540e17b3a62Francisco Jerez//
15c6db1b3396384186aab5b685fe1fd540e17b3a62Francisco Jerez// The above copyright notice and this permission notice shall be included in
16c6db1b3396384186aab5b685fe1fd540e17b3a62Francisco Jerez// all copies or substantial portions of the Software.
17c6db1b3396384186aab5b685fe1fd540e17b3a62Francisco Jerez//
18c6db1b3396384186aab5b685fe1fd540e17b3a62Francisco Jerez// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19c6db1b3396384186aab5b685fe1fd540e17b3a62Francisco Jerez// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20c6db1b3396384186aab5b685fe1fd540e17b3a62Francisco Jerez// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
21f0cb66b69904b0a3e4083aa8874af63cf1c14321Kenneth Graunke// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
22f0cb66b69904b0a3e4083aa8874af63cf1c14321Kenneth Graunke// OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
23f0cb66b69904b0a3e4083aa8874af63cf1c14321Kenneth Graunke// ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
24f0cb66b69904b0a3e4083aa8874af63cf1c14321Kenneth Graunke// OTHER DEALINGS IN THE SOFTWARE.
25c6db1b3396384186aab5b685fe1fd540e17b3a62Francisco Jerez//
26c6db1b3396384186aab5b685fe1fd540e17b3a62Francisco Jerez
2776136c29bbd78ea414c86402d4031855218dc42bTom Stellard#include <llvm/IR/DiagnosticPrinter.h>
2886100e13abc6182d2dd51eeb491b113d5a070fa1Francisco Jerez#include <llvm/IR/DiagnosticInfo.h>
29aa1c734b3ca445b5af743b9bad6a48ca7ba21f3cTom Stellard#include <llvm/IR/LLVMContext.h>
3086100e13abc6182d2dd51eeb491b113d5a070fa1Francisco Jerez#include <llvm/Support/raw_ostream.h>
3146a13b3b11d859e131399853c11ae2be0eb02f0aTom Stellard#include <llvm/Transforms/IPO/PassManagerBuilder.h>
328e7df519bd8556591794b2de08a833a67e34d526Tom Stellard#include <llvm-c/Target.h>
33c6db1b3396384186aab5b685fe1fd540e17b3a62Francisco Jerez
3486100e13abc6182d2dd51eeb491b113d5a070fa1Francisco Jerez#include <clang/CodeGen/CodeGenAction.h>
35a73bf11a63ea93640c26b5701c533b06d3a6f3e9Tom Stellard#include <clang/Lex/PreprocessorOptions.h>
3686100e13abc6182d2dd51eeb491b113d5a070fa1Francisco Jerez#include <clang/Frontend/TextDiagnosticBuffer.h>
3786100e13abc6182d2dd51eeb491b113d5a070fa1Francisco Jerez#include <clang/Frontend/TextDiagnosticPrinter.h>
3886100e13abc6182d2dd51eeb491b113d5a070fa1Francisco Jerez#include <clang/Basic/TargetInfo.h>
39c6db1b3396384186aab5b685fe1fd540e17b3a62Francisco Jerez
40106946153fb237e0867d65d53fb3a8461f3a13eeTom Stellard// We need to include internal headers last, because the internal headers
41106946153fb237e0867d65d53fb3a8461f3a13eeTom Stellard// include CL headers which have #define's like:
42106946153fb237e0867d65d53fb3a8461f3a13eeTom Stellard//
43106946153fb237e0867d65d53fb3a8461f3a13eeTom Stellard//#define cl_khr_gl_sharing 1
44106946153fb237e0867d65d53fb3a8461f3a13eeTom Stellard//#define cl_khr_icd 1
45106946153fb237e0867d65d53fb3a8461f3a13eeTom Stellard//
46106946153fb237e0867d65d53fb3a8461f3a13eeTom Stellard// Which will break the compilation of clang/Basic/OpenCLOptions.h
47106946153fb237e0867d65d53fb3a8461f3a13eeTom Stellard
48106946153fb237e0867d65d53fb3a8461f3a13eeTom Stellard#include "core/error.hpp"
49106946153fb237e0867d65d53fb3a8461f3a13eeTom Stellard#include "llvm/codegen.hpp"
50106946153fb237e0867d65d53fb3a8461f3a13eeTom Stellard#include "llvm/compat.hpp"
51106946153fb237e0867d65d53fb3a8461f3a13eeTom Stellard#include "llvm/invocation.hpp"
52106946153fb237e0867d65d53fb3a8461f3a13eeTom Stellard#include "llvm/metadata.hpp"
53106946153fb237e0867d65d53fb3a8461f3a13eeTom Stellard#include "llvm/util.hpp"
54106946153fb237e0867d65d53fb3a8461f3a13eeTom Stellard#include "util/algorithm.hpp"
55106946153fb237e0867d65d53fb3a8461f3a13eeTom Stellard
56106946153fb237e0867d65d53fb3a8461f3a13eeTom Stellard
57c6db1b3396384186aab5b685fe1fd540e17b3a62Francisco Jerezusing namespace clover;
58251054220eeaf23f20e0f8447071a22b11225ac6Francisco Jerezusing namespace clover::llvm;
59251054220eeaf23f20e0f8447071a22b11225ac6Francisco Jerez
60251054220eeaf23f20e0f8447071a22b11225ac6Francisco Jerezusing ::llvm::Function;
61714b167f5705a5eec29b2b83dac0d61c5d5746f2Francisco Jerezusing ::llvm::LLVMContext;
62251054220eeaf23f20e0f8447071a22b11225ac6Francisco Jerezusing ::llvm::Module;
63251054220eeaf23f20e0f8447071a22b11225ac6Francisco Jerezusing ::llvm::raw_string_ostream;
64c6db1b3396384186aab5b685fe1fd540e17b3a62Francisco Jerez
65c6db1b3396384186aab5b685fe1fd540e17b3a62Francisco Jereznamespace {
66714b167f5705a5eec29b2b83dac0d61c5d5746f2Francisco Jerez   void
67714b167f5705a5eec29b2b83dac0d61c5d5746f2Francisco Jerez   init_targets() {
68714b167f5705a5eec29b2b83dac0d61c5d5746f2Francisco Jerez      static bool targets_initialized = false;
69714b167f5705a5eec29b2b83dac0d61c5d5746f2Francisco Jerez      if (!targets_initialized) {
70714b167f5705a5eec29b2b83dac0d61c5d5746f2Francisco Jerez         LLVMInitializeAllTargets();
71714b167f5705a5eec29b2b83dac0d61c5d5746f2Francisco Jerez         LLVMInitializeAllTargetInfos();
72714b167f5705a5eec29b2b83dac0d61c5d5746f2Francisco Jerez         LLVMInitializeAllTargetMCs();
73714b167f5705a5eec29b2b83dac0d61c5d5746f2Francisco Jerez         LLVMInitializeAllAsmPrinters();
74714b167f5705a5eec29b2b83dac0d61c5d5746f2Francisco Jerez         targets_initialized = true;
75714b167f5705a5eec29b2b83dac0d61c5d5746f2Francisco Jerez      }
76714b167f5705a5eec29b2b83dac0d61c5d5746f2Francisco Jerez   }
77714b167f5705a5eec29b2b83dac0d61c5d5746f2Francisco Jerez
78714b167f5705a5eec29b2b83dac0d61c5d5746f2Francisco Jerez   void
79423eecb76a24e014198ab2281805e60d76d8f1aeFrancisco Jerez   diagnostic_handler(const ::llvm::DiagnosticInfo &di, void *data) {
80423eecb76a24e014198ab2281805e60d76d8f1aeFrancisco Jerez      if (di.getSeverity() == ::llvm::DS_Error) {
81423eecb76a24e014198ab2281805e60d76d8f1aeFrancisco Jerez         raw_string_ostream os { *reinterpret_cast<std::string *>(data) };
82423eecb76a24e014198ab2281805e60d76d8f1aeFrancisco Jerez         ::llvm::DiagnosticPrinterRawOStream printer { os };
83423eecb76a24e014198ab2281805e60d76d8f1aeFrancisco Jerez         di.print(printer);
844ef1c0918da4363aa20b7c1a91d344fae6c01942Francisco Jerez         throw build_error();
85714b167f5705a5eec29b2b83dac0d61c5d5746f2Francisco Jerez      }
86714b167f5705a5eec29b2b83dac0d61c5d5746f2Francisco Jerez   }
87714b167f5705a5eec29b2b83dac0d61c5d5746f2Francisco Jerez
88714b167f5705a5eec29b2b83dac0d61c5d5746f2Francisco Jerez   std::unique_ptr<LLVMContext>
89714b167f5705a5eec29b2b83dac0d61c5d5746f2Francisco Jerez   create_context(std::string &r_log) {
90714b167f5705a5eec29b2b83dac0d61c5d5746f2Francisco Jerez      init_targets();
91714b167f5705a5eec29b2b83dac0d61c5d5746f2Francisco Jerez      std::unique_ptr<LLVMContext> ctx { new LLVMContext };
92714b167f5705a5eec29b2b83dac0d61c5d5746f2Francisco Jerez      ctx->setDiagnosticHandler(diagnostic_handler, &r_log);
93714b167f5705a5eec29b2b83dac0d61c5d5746f2Francisco Jerez      return ctx;
94714b167f5705a5eec29b2b83dac0d61c5d5746f2Francisco Jerez   }
95714b167f5705a5eec29b2b83dac0d61c5d5746f2Francisco Jerez
96a27d4ec3b9658c76e6caf19dd9024d901e543a7fFrancisco Jerez   std::unique_ptr<clang::CompilerInstance>
97a27d4ec3b9658c76e6caf19dd9024d901e543a7fFrancisco Jerez   create_compiler_instance(const target &target,
98a27d4ec3b9658c76e6caf19dd9024d901e543a7fFrancisco Jerez                            const std::vector<std::string> &opts,
99a27d4ec3b9658c76e6caf19dd9024d901e543a7fFrancisco Jerez                            std::string &r_log) {
100a27d4ec3b9658c76e6caf19dd9024d901e543a7fFrancisco Jerez      std::unique_ptr<clang::CompilerInstance> c { new clang::CompilerInstance };
101d9fef848a651b47520cbeb72c38b93d4fbf842a8Vedran Miletić      clang::TextDiagnosticBuffer *diag_buffer = new clang::TextDiagnosticBuffer;
102a27d4ec3b9658c76e6caf19dd9024d901e543a7fFrancisco Jerez      clang::DiagnosticsEngine diag { new clang::DiagnosticIDs,
103d9fef848a651b47520cbeb72c38b93d4fbf842a8Vedran Miletić            new clang::DiagnosticOptions, diag_buffer };
104a27d4ec3b9658c76e6caf19dd9024d901e543a7fFrancisco Jerez
105a27d4ec3b9658c76e6caf19dd9024d901e543a7fFrancisco Jerez      // Parse the compiler options.  A file name should be present at the end
106a27d4ec3b9658c76e6caf19dd9024d901e543a7fFrancisco Jerez      // and must have the .cl extension in order for the CompilerInvocation
107a27d4ec3b9658c76e6caf19dd9024d901e543a7fFrancisco Jerez      // class to recognize it as an OpenCL source file.
108a27d4ec3b9658c76e6caf19dd9024d901e543a7fFrancisco Jerez      const std::vector<const char *> copts =
109a27d4ec3b9658c76e6caf19dd9024d901e543a7fFrancisco Jerez         map(std::mem_fn(&std::string::c_str), opts);
110a27d4ec3b9658c76e6caf19dd9024d901e543a7fFrancisco Jerez
111a27d4ec3b9658c76e6caf19dd9024d901e543a7fFrancisco Jerez      if (!clang::CompilerInvocation::CreateFromArgs(
112a27d4ec3b9658c76e6caf19dd9024d901e543a7fFrancisco Jerez             c->getInvocation(), copts.data(), copts.data() + copts.size(), diag))
1132a73ae662cb393bef0d2d0ab71bfd1072adbafb6Francisco Jerez         throw invalid_build_options_error();
114a27d4ec3b9658c76e6caf19dd9024d901e543a7fFrancisco Jerez
115d9fef848a651b47520cbeb72c38b93d4fbf842a8Vedran Miletić      diag_buffer->FlushDiagnostics(diag);
116d9fef848a651b47520cbeb72c38b93d4fbf842a8Vedran Miletić      if (diag.hasErrorOccurred())
117d9fef848a651b47520cbeb72c38b93d4fbf842a8Vedran Miletić         throw invalid_build_options_error();
118d9fef848a651b47520cbeb72c38b93d4fbf842a8Vedran Miletić
119a27d4ec3b9658c76e6caf19dd9024d901e543a7fFrancisco Jerez      c->getTargetOpts().CPU = target.cpu;
120a27d4ec3b9658c76e6caf19dd9024d901e543a7fFrancisco Jerez      c->getTargetOpts().Triple = target.triple;
121a27d4ec3b9658c76e6caf19dd9024d901e543a7fFrancisco Jerez      c->getLangOpts().NoBuiltin = true;
122a27d4ec3b9658c76e6caf19dd9024d901e543a7fFrancisco Jerez
123a27d4ec3b9658c76e6caf19dd9024d901e543a7fFrancisco Jerez      // This is a workaround for a Clang bug which causes the number
124a27d4ec3b9658c76e6caf19dd9024d901e543a7fFrancisco Jerez      // of warnings and errors to be printed to stderr.
125a27d4ec3b9658c76e6caf19dd9024d901e543a7fFrancisco Jerez      // http://www.llvm.org/bugs/show_bug.cgi?id=19735
126a27d4ec3b9658c76e6caf19dd9024d901e543a7fFrancisco Jerez      c->getDiagnosticOpts().ShowCarets = false;
127a27d4ec3b9658c76e6caf19dd9024d901e543a7fFrancisco Jerez
128a27d4ec3b9658c76e6caf19dd9024d901e543a7fFrancisco Jerez      compat::set_lang_defaults(c->getInvocation(), c->getLangOpts(),
129a27d4ec3b9658c76e6caf19dd9024d901e543a7fFrancisco Jerez                                clang::IK_OpenCL, ::llvm::Triple(target.triple),
130a27d4ec3b9658c76e6caf19dd9024d901e543a7fFrancisco Jerez                                c->getPreprocessorOpts(),
131a27d4ec3b9658c76e6caf19dd9024d901e543a7fFrancisco Jerez                                clang::LangStandard::lang_opencl11);
132a27d4ec3b9658c76e6caf19dd9024d901e543a7fFrancisco Jerez
133a27d4ec3b9658c76e6caf19dd9024d901e543a7fFrancisco Jerez      c->createDiagnostics(new clang::TextDiagnosticPrinter(
134a27d4ec3b9658c76e6caf19dd9024d901e543a7fFrancisco Jerez                              *new raw_string_ostream(r_log),
135a27d4ec3b9658c76e6caf19dd9024d901e543a7fFrancisco Jerez                              &c->getDiagnosticOpts(), true));
136a27d4ec3b9658c76e6caf19dd9024d901e543a7fFrancisco Jerez
137a27d4ec3b9658c76e6caf19dd9024d901e543a7fFrancisco Jerez      c->setTarget(clang::TargetInfo::CreateTargetInfo(
138a27d4ec3b9658c76e6caf19dd9024d901e543a7fFrancisco Jerez                           c->getDiagnostics(), c->getInvocation().TargetOpts));
139a27d4ec3b9658c76e6caf19dd9024d901e543a7fFrancisco Jerez
140a27d4ec3b9658c76e6caf19dd9024d901e543a7fFrancisco Jerez      return c;
141a27d4ec3b9658c76e6caf19dd9024d901e543a7fFrancisco Jerez   }
142a27d4ec3b9658c76e6caf19dd9024d901e543a7fFrancisco Jerez
143bdc27f13d53759ce9c1c7f58e62a259a18b2ca33Francisco Jerez   std::unique_ptr<Module>
144bdc27f13d53759ce9c1c7f58e62a259a18b2ca33Francisco Jerez   compile(LLVMContext &ctx, clang::CompilerInstance &c,
145bdc27f13d53759ce9c1c7f58e62a259a18b2ca33Francisco Jerez           const std::string &name, const std::string &source,
146bdc27f13d53759ce9c1c7f58e62a259a18b2ca33Francisco Jerez           const header_map &headers, const std::string &target,
147bdc27f13d53759ce9c1c7f58e62a259a18b2ca33Francisco Jerez           const std::string &opts, std::string &r_log) {
14846a13b3b11d859e131399853c11ae2be0eb02f0aTom Stellard      c.getFrontendOpts().ProgramAction = clang::frontend::EmitLLVMOnly;
14946a13b3b11d859e131399853c11ae2be0eb02f0aTom Stellard      c.getHeaderSearchOpts().UseBuiltinIncludes = true;
15046a13b3b11d859e131399853c11ae2be0eb02f0aTom Stellard      c.getHeaderSearchOpts().UseStandardSystemIncludes = true;
15146a13b3b11d859e131399853c11ae2be0eb02f0aTom Stellard      c.getHeaderSearchOpts().ResourceDir = CLANG_RESOURCE_DIR;
15246a13b3b11d859e131399853c11ae2be0eb02f0aTom Stellard
15346a13b3b11d859e131399853c11ae2be0eb02f0aTom Stellard      // Add libclc generic search path
154959e83d65075513f989cb1fe634dca314a7e185fJohannes Obermayr      c.getHeaderSearchOpts().AddPath(LIBCLC_INCLUDEDIR,
15546a13b3b11d859e131399853c11ae2be0eb02f0aTom Stellard                                      clang::frontend::Angled,
156bdc27f13d53759ce9c1c7f58e62a259a18b2ca33Francisco Jerez                                      false, false);
15746a13b3b11d859e131399853c11ae2be0eb02f0aTom Stellard
15846a13b3b11d859e131399853c11ae2be0eb02f0aTom Stellard      // Add libclc include
15946a13b3b11d859e131399853c11ae2be0eb02f0aTom Stellard      c.getPreprocessorOpts().Includes.push_back("clc/clc.h");
16046a13b3b11d859e131399853c11ae2be0eb02f0aTom Stellard
161cfa914a1b4e20e7ef416171f5212f21e8224befcNiels Ole Salscheider      // Add definition for the OpenCL version
162cfa914a1b4e20e7ef416171f5212f21e8224befcNiels Ole Salscheider      c.getPreprocessorOpts().addMacroDef("__OPENCL_VERSION__=110");
163cfa914a1b4e20e7ef416171f5212f21e8224befcNiels Ole Salscheider
16446a13b3b11d859e131399853c11ae2be0eb02f0aTom Stellard      // clc.h requires that this macro be defined:
16546a13b3b11d859e131399853c11ae2be0eb02f0aTom Stellard      c.getPreprocessorOpts().addMacroDef("cl_clang_storage_class_specifiers");
166bdc27f13d53759ce9c1c7f58e62a259a18b2ca33Francisco Jerez      c.getPreprocessorOpts().addRemappedFile(
167bdc27f13d53759ce9c1c7f58e62a259a18b2ca33Francisco Jerez              name, ::llvm::MemoryBuffer::getMemBuffer(source).release());
16846a13b3b11d859e131399853c11ae2be0eb02f0aTom Stellard
169611d66fe4513e53bde052dd2bab95d448c909a2aSerge Martin      if (headers.size()) {
170611d66fe4513e53bde052dd2bab95d448c909a2aSerge Martin         const std::string tmp_header_path = "/tmp/clover/";
171611d66fe4513e53bde052dd2bab95d448c909a2aSerge Martin
172611d66fe4513e53bde052dd2bab95d448c909a2aSerge Martin         c.getHeaderSearchOpts().AddPath(tmp_header_path,
173611d66fe4513e53bde052dd2bab95d448c909a2aSerge Martin                                         clang::frontend::Angled,
174bdc27f13d53759ce9c1c7f58e62a259a18b2ca33Francisco Jerez                                         false, false);
175bdc27f13d53759ce9c1c7f58e62a259a18b2ca33Francisco Jerez
176bdc27f13d53759ce9c1c7f58e62a259a18b2ca33Francisco Jerez         for (const auto &header : headers)
177bdc27f13d53759ce9c1c7f58e62a259a18b2ca33Francisco Jerez            c.getPreprocessorOpts().addRemappedFile(
178bdc27f13d53759ce9c1c7f58e62a259a18b2ca33Francisco Jerez               tmp_header_path + header.first,
179bdc27f13d53759ce9c1c7f58e62a259a18b2ca33Francisco Jerez               ::llvm::MemoryBuffer::getMemBuffer(header.second).release());
180611d66fe4513e53bde052dd2bab95d448c909a2aSerge Martin      }
181611d66fe4513e53bde052dd2bab95d448c909a2aSerge Martin
182251054220eeaf23f20e0f8447071a22b11225ac6Francisco Jerez      // Tell clang to link this file before performing any
183251054220eeaf23f20e0f8447071a22b11225ac6Francisco Jerez      // optimizations.  This is required so that we can replace calls
184251054220eeaf23f20e0f8447071a22b11225ac6Francisco Jerez      // to the OpenCL C barrier() builtin with calls to target
185251054220eeaf23f20e0f8447071a22b11225ac6Francisco Jerez      // intrinsics that have the noduplicate attribute.  This
186251054220eeaf23f20e0f8447071a22b11225ac6Francisco Jerez      // attribute will prevent Clang from creating illegal uses of
187251054220eeaf23f20e0f8447071a22b11225ac6Francisco Jerez      // barrier() (e.g. Moving barrier() inside a conditional that is
188251054220eeaf23f20e0f8447071a22b11225ac6Francisco Jerez      // no executed by all threads) during its optimizaton passes.
189c513cfa747bdb9ac3059ab4e436cd7083c50aed0Francisco Jerez      compat::add_link_bitcode_file(c.getCodeGenOpts(),
190c513cfa747bdb9ac3059ab4e436cd7083c50aed0Francisco Jerez                                    LIBCLC_LIBEXECDIR + target + ".bc");
191251054220eeaf23f20e0f8447071a22b11225ac6Francisco Jerez
19246a13b3b11d859e131399853c11ae2be0eb02f0aTom Stellard      // Compile the code
193bdc27f13d53759ce9c1c7f58e62a259a18b2ca33Francisco Jerez      clang::EmitLLVMOnlyAction act(&ctx);
194a27d4ec3b9658c76e6caf19dd9024d901e543a7fFrancisco Jerez      if (!c.ExecuteAction(act))
1954ef1c0918da4363aa20b7c1a91d344fae6c01942Francisco Jerez         throw build_error();
19646a13b3b11d859e131399853c11ae2be0eb02f0aTom Stellard
197bdc27f13d53759ce9c1c7f58e62a259a18b2ca33Francisco Jerez      return act.takeModule();
19846a13b3b11d859e131399853c11ae2be0eb02f0aTom Stellard   }
199132b6ccd4f81eac3cad5bef42325319708498240Francisco Jerez}
200132b6ccd4f81eac3cad5bef42325319708498240Francisco Jerez
201132b6ccd4f81eac3cad5bef42325319708498240Francisco Jerezmodule
202132b6ccd4f81eac3cad5bef42325319708498240Francisco Jerezclover::llvm::compile_program(const std::string &source,
203132b6ccd4f81eac3cad5bef42325319708498240Francisco Jerez                              const header_map &headers,
204132b6ccd4f81eac3cad5bef42325319708498240Francisco Jerez                              const std::string &target,
205132b6ccd4f81eac3cad5bef42325319708498240Francisco Jerez                              const std::string &opts,
206132b6ccd4f81eac3cad5bef42325319708498240Francisco Jerez                              std::string &r_log) {
207132b6ccd4f81eac3cad5bef42325319708498240Francisco Jerez   if (has_flag(debug::clc))
208132b6ccd4f81eac3cad5bef42325319708498240Francisco Jerez      debug::log(".cl", "// Options: " + opts + '\n' + source);
20946a13b3b11d859e131399853c11ae2be0eb02f0aTom Stellard
210132b6ccd4f81eac3cad5bef42325319708498240Francisco Jerez   auto ctx = create_context(r_log);
211132b6ccd4f81eac3cad5bef42325319708498240Francisco Jerez   auto c = create_compiler_instance(target, tokenize(opts + " input.cl"),
212132b6ccd4f81eac3cad5bef42325319708498240Francisco Jerez                                     r_log);
213132b6ccd4f81eac3cad5bef42325319708498240Francisco Jerez   auto mod = compile(*ctx, *c, "input.cl", source, headers, target, opts,
214132b6ccd4f81eac3cad5bef42325319708498240Francisco Jerez                      r_log);
215132b6ccd4f81eac3cad5bef42325319708498240Francisco Jerez
216132b6ccd4f81eac3cad5bef42325319708498240Francisco Jerez   if (has_flag(debug::llvm))
217132b6ccd4f81eac3cad5bef42325319708498240Francisco Jerez      debug::log(".ll", print_module_bitcode(*mod));
218132b6ccd4f81eac3cad5bef42325319708498240Francisco Jerez
219cc495055cdfe7e39002180d095d09fe4b6905eb9Serge Martin   return build_module_library(*mod, module::section::text_intermediate);
220132b6ccd4f81eac3cad5bef42325319708498240Francisco Jerez}
221132b6ccd4f81eac3cad5bef42325319708498240Francisco Jerez
222132b6ccd4f81eac3cad5bef42325319708498240Francisco Jereznamespace {
223ca8fa0230896727af81ee54197f6e2233d49481dTom Stellard   void
224fb3eeb1314c3269818e58e64b460d045ea5b466dFrancisco Jerez   optimize(Module &mod, unsigned optimization_level,
225fb3eeb1314c3269818e58e64b460d045ea5b466dFrancisco Jerez            bool internalize_symbols) {
2265884dfbc2a39adbbcc8ef7e7b53d4299ba2616ffFrancisco Jerez      compat::pass_manager pm;
22746a13b3b11d859e131399853c11ae2be0eb02f0aTom Stellard
2285884dfbc2a39adbbcc8ef7e7b53d4299ba2616ffFrancisco Jerez      compat::add_data_layout_pass(pm);
2297df256add2ae9fb916c3e0f80c879e42d1c8a7a0Shawn Starr
230ca8fa0230896727af81ee54197f6e2233d49481dTom Stellard      // By default, the function internalizer pass will look for a function
231ca8fa0230896727af81ee54197f6e2233d49481dTom Stellard      // called "main" and then mark all other functions as internal.  Marking
232ca8fa0230896727af81ee54197f6e2233d49481dTom Stellard      // functions as internal enables the optimizer to perform optimizations
233ca8fa0230896727af81ee54197f6e2233d49481dTom Stellard      // like function inlining and global dead-code elimination.
234ca8fa0230896727af81ee54197f6e2233d49481dTom Stellard      //
235ca8fa0230896727af81ee54197f6e2233d49481dTom Stellard      // When there is no "main" function in a module, the internalize pass will
236ca8fa0230896727af81ee54197f6e2233d49481dTom Stellard      // treat the module like a library, and it won't internalize any functions.
237ca8fa0230896727af81ee54197f6e2233d49481dTom Stellard      // Since there is no "main" function in our kernels, we need to tell
238ca8fa0230896727af81ee54197f6e2233d49481dTom Stellard      // the internalizer pass that this module is not a library by passing a
239ca8fa0230896727af81ee54197f6e2233d49481dTom Stellard      // list of kernel functions to the internalizer.  The internalizer will
240ca8fa0230896727af81ee54197f6e2233d49481dTom Stellard      // treat the functions in the list as "main" functions and internalize
241ca8fa0230896727af81ee54197f6e2233d49481dTom Stellard      // all of the other functions.
242fb3eeb1314c3269818e58e64b460d045ea5b466dFrancisco Jerez      if (internalize_symbols)
243fb3eeb1314c3269818e58e64b460d045ea5b466dFrancisco Jerez         compat::add_internalize_pass(pm, map(std::mem_fn(&Function::getName),
244fb3eeb1314c3269818e58e64b460d045ea5b466dFrancisco Jerez                                              get_kernels(mod)));
2455884dfbc2a39adbbcc8ef7e7b53d4299ba2616ffFrancisco Jerez
2465884dfbc2a39adbbcc8ef7e7b53d4299ba2616ffFrancisco Jerez      ::llvm::PassManagerBuilder pmb;
2475884dfbc2a39adbbcc8ef7e7b53d4299ba2616ffFrancisco Jerez      pmb.OptLevel = optimization_level;
2485884dfbc2a39adbbcc8ef7e7b53d4299ba2616ffFrancisco Jerez      pmb.LibraryInfo = new compat::target_library_info(
2495884dfbc2a39adbbcc8ef7e7b53d4299ba2616ffFrancisco Jerez         ::llvm::Triple(mod.getTargetTriple()));
2505884dfbc2a39adbbcc8ef7e7b53d4299ba2616ffFrancisco Jerez      pmb.populateModulePassManager(pm);
2515884dfbc2a39adbbcc8ef7e7b53d4299ba2616ffFrancisco Jerez      pm.run(mod);
25246a13b3b11d859e131399853c11ae2be0eb02f0aTom Stellard   }
2539de3f4a59f2f588368a5994a9fe49d4136393852Francisco Jerez
2549de3f4a59f2f588368a5994a9fe49d4136393852Francisco Jerez   std::unique_ptr<Module>
2559de3f4a59f2f588368a5994a9fe49d4136393852Francisco Jerez   link(LLVMContext &ctx, const clang::CompilerInstance &c,
2569de3f4a59f2f588368a5994a9fe49d4136393852Francisco Jerez        const std::vector<module> &modules, std::string &r_log) {
2579de3f4a59f2f588368a5994a9fe49d4136393852Francisco Jerez      std::unique_ptr<Module> mod { new Module("link", ctx) };
2589de3f4a59f2f588368a5994a9fe49d4136393852Francisco Jerez      auto linker = compat::create_linker(*mod);
2599de3f4a59f2f588368a5994a9fe49d4136393852Francisco Jerez
2609de3f4a59f2f588368a5994a9fe49d4136393852Francisco Jerez      for (auto &m : modules) {
2619de3f4a59f2f588368a5994a9fe49d4136393852Francisco Jerez         if (compat::link_in_module(*linker,
2629de3f4a59f2f588368a5994a9fe49d4136393852Francisco Jerez                                    parse_module_library(m, ctx, r_log)))
2634ef1c0918da4363aa20b7c1a91d344fae6c01942Francisco Jerez            throw build_error();
2649de3f4a59f2f588368a5994a9fe49d4136393852Francisco Jerez      }
2659de3f4a59f2f588368a5994a9fe49d4136393852Francisco Jerez
2669de3f4a59f2f588368a5994a9fe49d4136393852Francisco Jerez      return std::move(mod);
2679de3f4a59f2f588368a5994a9fe49d4136393852Francisco Jerez   }
26886100e13abc6182d2dd51eeb491b113d5a070fa1Francisco Jerez}
269e1d363b3ffbfb85133a6871c63068a4ba841b2cdTom Stellard
270c6db1b3396384186aab5b685fe1fd540e17b3a62Francisco Jerezmodule
271132b6ccd4f81eac3cad5bef42325319708498240Francisco Jerezclover::llvm::link_program(const std::vector<module> &modules,
272132b6ccd4f81eac3cad5bef42325319708498240Francisco Jerez                           enum pipe_shader_ir ir, const std::string &target,
273132b6ccd4f81eac3cad5bef42325319708498240Francisco Jerez                           const std::string &opts, std::string &r_log) {
274132b6ccd4f81eac3cad5bef42325319708498240Francisco Jerez   std::vector<std::string> options = tokenize(opts + " input.cl");
275fb3eeb1314c3269818e58e64b460d045ea5b466dFrancisco Jerez   const bool create_library = count("-create-library", options);
276fb3eeb1314c3269818e58e64b460d045ea5b466dFrancisco Jerez   erase_if(equals("-create-library"), options);
277fb3eeb1314c3269818e58e64b460d045ea5b466dFrancisco Jerez
278714b167f5705a5eec29b2b83dac0d61c5d5746f2Francisco Jerez   auto ctx = create_context(r_log);
279132b6ccd4f81eac3cad5bef42325319708498240Francisco Jerez   auto c = create_compiler_instance(target, options, r_log);
2809de3f4a59f2f588368a5994a9fe49d4136393852Francisco Jerez   auto mod = link(*ctx, *c, modules, r_log);
28146a13b3b11d859e131399853c11ae2be0eb02f0aTom Stellard
282fb3eeb1314c3269818e58e64b460d045ea5b466dFrancisco Jerez   optimize(*mod, c->getCodeGenOpts().OptimizationLevel, !create_library);
28346a13b3b11d859e131399853c11ae2be0eb02f0aTom Stellard
28426fa9bfd0dfccf06358180ae740121522d09b51fFrancisco Jerez   if (has_flag(debug::llvm))
28526fa9bfd0dfccf06358180ae740121522d09b51fFrancisco Jerez      debug::log(".ll", print_module_bitcode(*mod));
286e1d363b3ffbfb85133a6871c63068a4ba841b2cdTom Stellard
287fb3eeb1314c3269818e58e64b460d045ea5b466dFrancisco Jerez   if (create_library) {
288cc495055cdfe7e39002180d095d09fe4b6905eb9Serge Martin      return build_module_library(*mod, module::section::text_library);
289fb3eeb1314c3269818e58e64b460d045ea5b466dFrancisco Jerez
290fb3eeb1314c3269818e58e64b460d045ea5b466dFrancisco Jerez   } else if (ir == PIPE_SHADER_IR_LLVM) {
291fb3eeb1314c3269818e58e64b460d045ea5b466dFrancisco Jerez      return build_module_bitcode(*mod, *c);
292bdc27f13d53759ce9c1c7f58e62a259a18b2ca33Francisco Jerez
293fb3eeb1314c3269818e58e64b460d045ea5b466dFrancisco Jerez   } else if (ir == PIPE_SHADER_IR_NATIVE) {
294fb3eeb1314c3269818e58e64b460d045ea5b466dFrancisco Jerez      if (has_flag(debug::native))
295fb3eeb1314c3269818e58e64b460d045ea5b466dFrancisco Jerez         debug::log(".asm", print_module_native(*mod, target));
296fb3eeb1314c3269818e58e64b460d045ea5b466dFrancisco Jerez
297fb3eeb1314c3269818e58e64b460d045ea5b466dFrancisco Jerez      return build_module_native(*mod, target, *c, r_log);
298fb3eeb1314c3269818e58e64b460d045ea5b466dFrancisco Jerez
299fb3eeb1314c3269818e58e64b460d045ea5b466dFrancisco Jerez   } else {
300fb3eeb1314c3269818e58e64b460d045ea5b466dFrancisco Jerez      unreachable("Unsupported IR.");
301fb3eeb1314c3269818e58e64b460d045ea5b466dFrancisco Jerez   }
302c6db1b3396384186aab5b685fe1fd540e17b3a62Francisco Jerez}
303