blob: 996342766f19c059458b82e9471f29b916b7c87d [file] [log] [blame]
alan-bakerfec0a472018-11-08 18:09:40 -05001// Copyright 2018 The Clspv Authors. All rights reserved.
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7// http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15#include "clang/Basic/TargetInfo.h"
16#include "clang/CodeGen/CodeGenAction.h"
17#include "clang/Frontend/CompilerInstance.h"
18#include "clang/Frontend/FrontendPluginRegistry.h"
19#include "clang/Frontend/TextDiagnosticPrinter.h"
20#include "clang/Lex/PreprocessorOptions.h"
21#include "llvm/IR/LLVMContext.h"
22#include "llvm/IR/LegacyPassManager.h"
23#include "llvm/IR/Module.h"
24#include "llvm/IR/Verifier.h"
25#include "llvm/LinkAllPasses.h"
alan-bakerf5e5f692018-11-27 08:33:24 -050026#include "llvm/Support/Allocator.h"
alan-bakerfec0a472018-11-08 18:09:40 -050027#include "llvm/Support/CommandLine.h"
alan-bakerf5e5f692018-11-27 08:33:24 -050028#include "llvm/Support/ErrorOr.h"
alan-bakerfec0a472018-11-08 18:09:40 -050029#include "llvm/Support/MathExtras.h"
alan-bakerf5e5f692018-11-27 08:33:24 -050030#include "llvm/Support/StringSaver.h"
Diego Novillo89500852019-04-15 08:45:10 -040031#include "llvm/Support/ToolOutputFile.h"
alan-bakerfec0a472018-11-08 18:09:40 -050032#include "llvm/Support/raw_ostream.h"
33#include "llvm/Transforms/IPO/PassManagerBuilder.h"
34
Kévin Petit38c52482019-05-07 20:28:00 +080035#include "clspv/AddressSpace.h"
alan-bakerf5e5f692018-11-27 08:33:24 -050036#include "clspv/DescriptorMap.h"
alan-bakerfec0a472018-11-08 18:09:40 -050037#include "clspv/Option.h"
38#include "clspv/Passes.h"
39#include "clspv/opencl_builtins_header.h"
40
41#include "FrontendPlugin.h"
Diego Novilloa4c44fa2019-04-11 10:56:15 -040042#include "Passes.h"
alan-bakerfec0a472018-11-08 18:09:40 -050043
alan-bakerf5e5f692018-11-27 08:33:24 -050044#include <cassert>
alan-bakerfec0a472018-11-08 18:09:40 -050045#include <numeric>
alan-bakerf5e5f692018-11-27 08:33:24 -050046#include <sstream>
Diego Novillo3cc8d7a2019-04-10 13:30:34 -040047#include <string>
alan-bakerfec0a472018-11-08 18:09:40 -050048
49using namespace clang;
50
51namespace {
52// This registration must be located in the same file as the execution of the
53// action.
54static FrontendPluginRegistry::Add<clspv::ExtraValidationASTAction>
55 X("extra-validation",
56 "Perform extra validation on OpenCL C when targeting Vulkan");
57
58static llvm::cl::opt<bool> cl_single_precision_constants(
59 "cl-single-precision-constant", llvm::cl::init(false),
60 llvm::cl::desc("Treat double precision floating-point constant as single "
61 "precision constant."));
62
63static llvm::cl::opt<bool> cl_denorms_are_zero(
64 "cl-denorms-are-zero", llvm::cl::init(false),
65 llvm::cl::desc("If specified, denormalized floating point numbers may be "
66 "flushed to zero."));
67
68static llvm::cl::opt<bool> cl_fp32_correctly_rounded_divide_sqrt(
69 "cl-fp32-correctly-rounded-divide-sqrt", llvm::cl::init(false),
70 llvm::cl::desc("Single precision floating-point divide (x/y and 1/x) and "
71 "sqrt used are correctly rounded."));
72
73static llvm::cl::opt<bool>
74 cl_opt_disable("cl-opt-disable", llvm::cl::init(false),
75 llvm::cl::desc("This option disables all optimizations. The "
76 "default is optimizations are enabled."));
77
78static llvm::cl::opt<bool> cl_mad_enable(
79 "cl-mad-enable", llvm::cl::init(false),
80 llvm::cl::desc("Allow a * b + c to be replaced by a mad. The mad computes "
81 "a * b + c with reduced accuracy."));
82
83static llvm::cl::opt<bool> cl_no_signed_zeros(
84 "cl-no-signed-zeros", llvm::cl::init(false),
85 llvm::cl::desc("Allow optimizations for floating-point arithmetic that "
86 "ignore the signedness of zero."));
87
88static llvm::cl::opt<bool> cl_unsafe_math_optimizations(
89 "cl-unsafe-math-optimizations", llvm::cl::init(false),
90 llvm::cl::desc("Allow optimizations for floating-point arithmetic that (a) "
91 "assume that arguments and results are valid, (b) may "
92 "violate IEEE 754 standard and (c) may violate the OpenCL "
93 "numerical compliance requirements. This option includes "
94 "the -cl-no-signed-zeros and -cl-mad-enable options."));
95
96static llvm::cl::opt<bool> cl_finite_math_only(
97 "cl-finite-math-only", llvm::cl::init(false),
98 llvm::cl::desc("Allow optimizations for floating-point arithmetic that "
99 "assume that arguments and results are not NaNs or INFs."));
100
101static llvm::cl::opt<bool> cl_fast_relaxed_math(
102 "cl-fast-relaxed-math", llvm::cl::init(false),
103 llvm::cl::desc("This option causes the preprocessor macro "
104 "__FAST_RELAXED_MATH__ to be defined. Sets the optimization "
105 "options -cl-finite-math-only and "
106 "-cl-unsafe-math-optimizations."));
107
108static llvm::cl::list<std::string>
109 Includes(llvm::cl::Prefix, "I",
110 llvm::cl::desc("Add a directory to the list of directories "
111 "to be searched for header files."),
112 llvm::cl::ZeroOrMore, llvm::cl::value_desc("include path"));
113
114static llvm::cl::list<std::string>
115 Defines(llvm::cl::Prefix, "D",
116 llvm::cl::desc("Define a #define directive."), llvm::cl::ZeroOrMore,
117 llvm::cl::value_desc("define"));
118
119static llvm::cl::opt<std::string>
120 InputFilename(llvm::cl::Positional, llvm::cl::desc("<input .cl file>"),
121 llvm::cl::init("-"));
122
123static llvm::cl::opt<std::string>
124 OutputFilename("o", llvm::cl::desc("Override output filename"),
125 llvm::cl::value_desc("filename"));
126
127static llvm::cl::opt<std::string>
128 DescriptorMapFilename("descriptormap",
129 llvm::cl::desc("Output file for descriptor map"),
130 llvm::cl::value_desc("filename"));
131
132static llvm::cl::opt<char>
133 OptimizationLevel(llvm::cl::Prefix, "O", llvm::cl::init('2'),
134 llvm::cl::desc("Optimization level to use"),
135 llvm::cl::value_desc("level"));
136
alan-bakerfec0a472018-11-08 18:09:40 -0500137static llvm::cl::opt<std::string> OutputFormat(
138 "mfmt", llvm::cl::init(""),
139 llvm::cl::desc(
140 "Specify special output format. 'c' is as a C initializer list"),
141 llvm::cl::value_desc("format"));
142
143static llvm::cl::opt<std::string>
144 SamplerMap("samplermap", llvm::cl::desc("Literal sampler map"),
145 llvm::cl::value_desc("filename"));
146
147static llvm::cl::opt<bool> cluster_non_pointer_kernel_args(
148 "cluster-pod-kernel-args", llvm::cl::init(false),
149 llvm::cl::desc("Collect plain-old-data kernel arguments into a struct in "
150 "a single storage buffer, using a binding number after "
151 "other arguments. Use this to reduce storage buffer "
152 "descriptors."));
153
154static llvm::cl::opt<bool> verify("verify", llvm::cl::init(false),
155 llvm::cl::desc("Verify diagnostic outputs"));
156
Kévin Petit6b07cbe2019-04-02 21:52:16 +0100157static llvm::cl::opt<bool>
158 IgnoreWarnings("w", llvm::cl::init(false),
159 llvm::cl::desc("Disable all warnings"));
160
161static llvm::cl::opt<bool>
162 WarningsAsErrors("Werror", llvm::cl::init(false),
Diego Novillo3cc8d7a2019-04-10 13:30:34 -0400163 llvm::cl::desc("Turn warnings into errors"));
Kévin Petit6b07cbe2019-04-02 21:52:16 +0100164
Diego Novillo89500852019-04-15 08:45:10 -0400165static llvm::cl::opt<std::string> IROutputFile(
166 "emit-ir",
167 llvm::cl::desc(
168 "Emit LLVM IR to the given file after parsing and stop compilation."),
169 llvm::cl::value_desc("filename"));
170
alan-bakerfec0a472018-11-08 18:09:40 -0500171// Populates |SamplerMapEntries| with data from the input sampler map. Returns 0
172// if successful.
alan-bakerf5e5f692018-11-27 08:33:24 -0500173int ParseSamplerMap(const std::string &sampler_map,
174 llvm::SmallVectorImpl<std::pair<unsigned, std::string>>
175 *SamplerMapEntries) {
176 std::unique_ptr<llvm::MemoryBuffer> samplerMapBuffer(nullptr);
177 if (!sampler_map.empty()) {
178 // Parse the sampler map from the provided string.
179 samplerMapBuffer = llvm::MemoryBuffer::getMemBuffer(sampler_map);
180
181 if (!SamplerMap.empty()) {
182 llvm::outs() << "Warning: -samplermap is ignored when the sampler map is "
183 "provided through a string.\n";
184 }
185 } else if (!SamplerMap.empty()) {
186 // Parse the sampler map from the option provided file.
alan-bakerfec0a472018-11-08 18:09:40 -0500187 auto errorOrSamplerMapFile =
188 llvm::MemoryBuffer::getFile(SamplerMap.getValue());
189
190 // If there was an error in getting the sampler map file.
191 if (!errorOrSamplerMapFile) {
192 llvm::errs() << "Error: " << errorOrSamplerMapFile.getError().message()
193 << " '" << SamplerMap.getValue() << "'\n";
194 return -1;
195 }
196
alan-bakerf5e5f692018-11-27 08:33:24 -0500197 samplerMapBuffer = std::move(errorOrSamplerMapFile.get());
alan-bakerfec0a472018-11-08 18:09:40 -0500198 if (0 == samplerMapBuffer->getBufferSize()) {
199 llvm::errs() << "Error: Sampler map was an empty file!\n";
200 return -1;
201 }
alan-bakerf5e5f692018-11-27 08:33:24 -0500202 }
alan-bakerfec0a472018-11-08 18:09:40 -0500203
alan-bakerf5e5f692018-11-27 08:33:24 -0500204 // No sampler map to parse.
205 if (!samplerMapBuffer || 0 == samplerMapBuffer->getBufferSize())
206 return 0;
alan-bakerfec0a472018-11-08 18:09:40 -0500207
alan-bakerf5e5f692018-11-27 08:33:24 -0500208 llvm::SmallVector<llvm::StringRef, 3> samplerStrings;
alan-bakerfec0a472018-11-08 18:09:40 -0500209
alan-bakerf5e5f692018-11-27 08:33:24 -0500210 // We need to keep track of the beginning of the current entry.
211 const char *b = samplerMapBuffer->getBufferStart();
212 for (const char *i = b, *e = samplerMapBuffer->getBufferEnd();; i++) {
213 // If we have a separator between declarations.
214 if ((*i == '|') || (*i == ',') || (i == e)) {
215 if (i == b) {
216 llvm::errs() << "Error: Sampler map contained an empty entry!\n";
217 return -1;
alan-bakerfec0a472018-11-08 18:09:40 -0500218 }
219
alan-bakerf5e5f692018-11-27 08:33:24 -0500220 samplerStrings.push_back(llvm::StringRef(b, i - b).trim());
alan-bakerfec0a472018-11-08 18:09:40 -0500221
alan-bakerf5e5f692018-11-27 08:33:24 -0500222 // And set b the next character after i.
223 b = i + 1;
224 }
alan-bakerfec0a472018-11-08 18:09:40 -0500225
alan-bakerf5e5f692018-11-27 08:33:24 -0500226 // If we have a separator between declarations within a single sampler.
227 if ((*i == ',') || (i == e)) {
228 enum NormalizedCoords {
229 CLK_NORMALIZED_COORDS_FALSE = 0x00,
230 CLK_NORMALIZED_COORDS_TRUE = 0x01,
231 CLK_NORMALIZED_COORDS_NOT_SET
232 } NormalizedCoord = CLK_NORMALIZED_COORDS_NOT_SET;
alan-bakerfec0a472018-11-08 18:09:40 -0500233
alan-bakerf5e5f692018-11-27 08:33:24 -0500234 enum AddressingModes {
235 CLK_ADDRESS_NONE = 0x00,
236 CLK_ADDRESS_CLAMP_TO_EDGE = 0x02,
237 CLK_ADDRESS_CLAMP = 0x04,
238 CLK_ADDRESS_MIRRORED_REPEAT = 0x08,
239 CLK_ADDRESS_REPEAT = 0x06,
240 CLK_ADDRESS_NOT_SET
241 } AddressingMode = CLK_ADDRESS_NOT_SET;
242
243 enum FilterModes {
244 CLK_FILTER_NEAREST = 0x10,
245 CLK_FILTER_LINEAR = 0x20,
246 CLK_FILTER_NOT_SET
247 } FilterMode = CLK_FILTER_NOT_SET;
248
249 for (auto str : samplerStrings) {
250 if ("CLK_NORMALIZED_COORDS_FALSE" == str) {
251 if (CLK_NORMALIZED_COORDS_NOT_SET != NormalizedCoord) {
252 llvm::errs() << "Error: Sampler map normalized coordinates was "
253 "previously set!\n";
alan-bakerfec0a472018-11-08 18:09:40 -0500254 return -1;
255 }
alan-bakerf5e5f692018-11-27 08:33:24 -0500256 NormalizedCoord = CLK_NORMALIZED_COORDS_FALSE;
257 } else if ("CLK_NORMALIZED_COORDS_TRUE" == str) {
258 if (CLK_NORMALIZED_COORDS_NOT_SET != NormalizedCoord) {
259 llvm::errs() << "Error: Sampler map normalized coordinates was "
260 "previously set!\n";
261 return -1;
262 }
263 NormalizedCoord = CLK_NORMALIZED_COORDS_TRUE;
264 } else if ("CLK_ADDRESS_NONE" == str) {
265 if (CLK_ADDRESS_NOT_SET != AddressingMode) {
266 llvm::errs()
267 << "Error: Sampler map addressing mode was previously set!\n";
268 return -1;
269 }
270 AddressingMode = CLK_ADDRESS_NONE;
271 } else if ("CLK_ADDRESS_CLAMP_TO_EDGE" == str) {
272 if (CLK_ADDRESS_NOT_SET != AddressingMode) {
273 llvm::errs()
274 << "Error: Sampler map addressing mode was previously set!\n";
275 return -1;
276 }
277 AddressingMode = CLK_ADDRESS_CLAMP_TO_EDGE;
278 } else if ("CLK_ADDRESS_CLAMP" == str) {
279 if (CLK_ADDRESS_NOT_SET != AddressingMode) {
280 llvm::errs()
281 << "Error: Sampler map addressing mode was previously set!\n";
282 return -1;
283 }
284 AddressingMode = CLK_ADDRESS_CLAMP;
285 } else if ("CLK_ADDRESS_MIRRORED_REPEAT" == str) {
286 if (CLK_ADDRESS_NOT_SET != AddressingMode) {
287 llvm::errs()
288 << "Error: Sampler map addressing mode was previously set!\n";
289 return -1;
290 }
291 AddressingMode = CLK_ADDRESS_MIRRORED_REPEAT;
292 } else if ("CLK_ADDRESS_REPEAT" == str) {
293 if (CLK_ADDRESS_NOT_SET != AddressingMode) {
294 llvm::errs()
295 << "Error: Sampler map addressing mode was previously set!\n";
296 return -1;
297 }
298 AddressingMode = CLK_ADDRESS_REPEAT;
299 } else if ("CLK_FILTER_NEAREST" == str) {
300 if (CLK_FILTER_NOT_SET != FilterMode) {
301 llvm::errs()
302 << "Error: Sampler map filtering mode was previously set!\n";
303 return -1;
304 }
305 FilterMode = CLK_FILTER_NEAREST;
306 } else if ("CLK_FILTER_LINEAR" == str) {
307 if (CLK_FILTER_NOT_SET != FilterMode) {
308 llvm::errs()
309 << "Error: Sampler map filtering mode was previously set!\n";
310 return -1;
311 }
312 FilterMode = CLK_FILTER_LINEAR;
313 } else {
314 llvm::errs() << "Error: Unknown sampler string '" << str
315 << "' found!\n";
alan-bakerfec0a472018-11-08 18:09:40 -0500316 return -1;
317 }
alan-bakerfec0a472018-11-08 18:09:40 -0500318 }
319
alan-bakerf5e5f692018-11-27 08:33:24 -0500320 if (CLK_NORMALIZED_COORDS_NOT_SET == NormalizedCoord) {
321 llvm::errs() << "Error: Sampler map entry did not contain normalized "
322 "coordinates entry!\n";
323 return -1;
alan-bakerfec0a472018-11-08 18:09:40 -0500324 }
alan-bakerf5e5f692018-11-27 08:33:24 -0500325
326 if (CLK_ADDRESS_NOT_SET == AddressingMode) {
327 llvm::errs() << "Error: Sampler map entry did not contain addressing "
328 "mode entry!\n";
329 return -1;
330 }
331
332 if (CLK_FILTER_NOT_SET == FilterMode) {
333 llvm::errs()
334 << "Error: Sampler map entry did not contain filer mode entry!\n";
335 return -1;
336 }
337
338 // Generate an equivalent expression in string form. Sort the
339 // strings to get a canonical ordering.
340 std::sort(samplerStrings.begin(), samplerStrings.end(),
341 std::less<StringRef>());
342 const auto samplerExpr = std::accumulate(
343 samplerStrings.begin(), samplerStrings.end(), std::string(),
344 [](std::string left, std::string right) {
345 return left + std::string(left.empty() ? "" : "|") + right;
346 });
347
348 // SamplerMapEntries->push_back(std::make_pair(
349 // NormalizedCoord | AddressingMode | FilterMode, samplerExpr));
350 SamplerMapEntries->emplace_back(
351 NormalizedCoord | AddressingMode | FilterMode, samplerExpr);
352
353 // And reset the sampler strings for the next sampler in the map.
354 samplerStrings.clear();
355 }
356
357 // And lastly, if we are at the end of the file
358 if (i == e) {
359 break;
alan-bakerfec0a472018-11-08 18:09:40 -0500360 }
361 }
362
363 return 0;
364}
365
366// Sets |instance|'s options for compiling. Returns 0 if successful.
367int SetCompilerInstanceOptions(CompilerInstance &instance,
368 const llvm::StringRef &overiddenInputFilename,
369 const clang::FrontendInputFile &kernelFile,
alan-bakerf5e5f692018-11-27 08:33:24 -0500370 const std::string &program,
alan-bakerfec0a472018-11-08 18:09:40 -0500371 llvm::raw_string_ostream *diagnosticsStream) {
alan-bakerf5e5f692018-11-27 08:33:24 -0500372 std::unique_ptr<llvm::MemoryBuffer> memory_buffer(nullptr);
373 llvm::ErrorOr<std::unique_ptr<llvm::MemoryBuffer>> errorOrInputFile(nullptr);
374 if (program.empty()) {
375 auto errorOrInputFile =
376 llvm::MemoryBuffer::getFileOrSTDIN(InputFilename.getValue());
alan-bakerfec0a472018-11-08 18:09:40 -0500377
alan-bakerf5e5f692018-11-27 08:33:24 -0500378 // If there was an error in getting the input file.
379 if (!errorOrInputFile) {
380 llvm::errs() << "Error: " << errorOrInputFile.getError().message() << " '"
381 << InputFilename.getValue() << "'\n";
382 return -1;
383 }
384 memory_buffer.reset(errorOrInputFile.get().release());
385 } else {
386 memory_buffer = llvm::MemoryBuffer::getMemBuffer(program.c_str(),
387 overiddenInputFilename);
alan-bakerfec0a472018-11-08 18:09:40 -0500388 }
alan-bakerf5e5f692018-11-27 08:33:24 -0500389
alan-bakerfec0a472018-11-08 18:09:40 -0500390 if (verify) {
391 instance.getDiagnosticOpts().VerifyDiagnostics = true;
alan-bakerbccf62c2019-03-29 10:32:41 -0400392 instance.getDiagnosticOpts().VerifyPrefixes.push_back("expected");
alan-bakerfec0a472018-11-08 18:09:40 -0500393 }
394
Kévin Petit0fc88042019-04-09 23:25:02 +0100395 clang::LangStandard::Kind standard;
396 if (clspv::Option::CPlusPlus()) {
397 standard = clang::LangStandard::lang_openclcpp;
398 } else {
399 standard = clang::LangStandard::lang_opencl12;
400 }
alan-bakerfec0a472018-11-08 18:09:40 -0500401
402 // We are targeting OpenCL 1.2 only
403 instance.getLangOpts().OpenCLVersion = 120;
404
405 instance.getLangOpts().C99 = true;
406 instance.getLangOpts().RTTI = false;
407 instance.getLangOpts().RTTIData = false;
408 instance.getLangOpts().MathErrno = false;
409 instance.getLangOpts().Optimize = false;
410 instance.getLangOpts().NoBuiltin = true;
411 instance.getLangOpts().ModulesSearchAll = false;
412 instance.getLangOpts().SinglePrecisionConstants = true;
413 instance.getCodeGenOpts().StackRealignment = true;
414 instance.getCodeGenOpts().SimplifyLibCalls = false;
415 instance.getCodeGenOpts().EmitOpenCLArgMetadata = false;
416 instance.getCodeGenOpts().DisableO0ImplyOptNone = true;
Kévin Petit6b07cbe2019-04-02 21:52:16 +0100417 instance.getDiagnosticOpts().IgnoreWarnings = IgnoreWarnings;
alan-bakerfec0a472018-11-08 18:09:40 -0500418
419 instance.getLangOpts().SinglePrecisionConstants =
420 cl_single_precision_constants;
421 // cl_denorms_are_zero ignored for now!
422 // cl_fp32_correctly_rounded_divide_sqrt ignored for now!
423 instance.getCodeGenOpts().LessPreciseFPMAD =
424 cl_mad_enable || cl_unsafe_math_optimizations;
425 // cl_no_signed_zeros ignored for now!
426 instance.getCodeGenOpts().UnsafeFPMath =
427 cl_unsafe_math_optimizations || cl_fast_relaxed_math;
428 instance.getLangOpts().FiniteMathOnly =
429 cl_finite_math_only || cl_fast_relaxed_math;
430 instance.getLangOpts().FastRelaxedMath = cl_fast_relaxed_math;
431
432 // Preprocessor options
Kévin Petita624c0c2019-05-07 20:27:43 +0800433 if (!clspv::Option::ImageSupport()) {
434 instance.getPreprocessorOpts().addMacroUndef("__IMAGE_SUPPORT__");
435 }
alan-bakerfec0a472018-11-08 18:09:40 -0500436 if (cl_fast_relaxed_math) {
437 instance.getPreprocessorOpts().addMacroDef("__FAST_RELAXED_MATH__");
438 }
439
440 for (auto define : Defines) {
441 instance.getPreprocessorOpts().addMacroDef(define);
442 }
443
444 // Header search options
445 for (auto include : Includes) {
446 instance.getHeaderSearchOpts().AddPath(include, clang::frontend::After,
447 false, false);
448 }
449
450 // We always compile on opt 0 so we preserve as much debug information about
451 // the source as possible. We'll run optimization later, once we've had a
452 // chance to view the unoptimal code first
453 instance.getCodeGenOpts().OptimizationLevel = 0;
454
455// Debug information is disabled temporarily to call instruction.
456#if 0
457 instance.getCodeGenOpts().setDebugInfo(clang::codegenoptions::FullDebugInfo);
458#endif
459
460 // We use the 32-bit pointer-width SPIR triple
461 llvm::Triple triple("spir-unknown-unknown");
462
463 instance.getInvocation().setLangDefaults(
alan-bakerd354f1a2019-08-06 15:41:55 -0400464 instance.getLangOpts(), clang::InputKind(clang::Language::OpenCL), triple,
alan-bakerfec0a472018-11-08 18:09:40 -0500465 instance.getPreprocessorOpts(), standard);
466
467 // Override the C99 inline semantics to accommodate for more OpenCL C
468 // programs in the wild.
469 instance.getLangOpts().GNUInline = true;
Kévin Petit6b07cbe2019-04-02 21:52:16 +0100470
471 // Set up diagnostics
alan-bakerfec0a472018-11-08 18:09:40 -0500472 instance.createDiagnostics(
473 new clang::TextDiagnosticPrinter(*diagnosticsStream,
474 &instance.getDiagnosticOpts()),
475 true);
Kévin Petit6b07cbe2019-04-02 21:52:16 +0100476 instance.getDiagnostics().setWarningsAsErrors(WarningsAsErrors);
477 instance.getDiagnostics().setEnableAllWarnings(true);
alan-bakerfec0a472018-11-08 18:09:40 -0500478
479 instance.getTargetOpts().Triple = triple.str();
480
481 instance.getCodeGenOpts().MainFileName = overiddenInputFilename;
482 instance.getCodeGenOpts().PreserveVec3Type = true;
483 // Disable generation of lifetime intrinsic.
484 instance.getCodeGenOpts().DisableLifetimeMarkers = true;
485 instance.getFrontendOpts().Inputs.push_back(kernelFile);
alan-bakerf5e5f692018-11-27 08:33:24 -0500486 instance.getPreprocessorOpts().addRemappedFile(overiddenInputFilename,
487 memory_buffer.release());
alan-bakerfec0a472018-11-08 18:09:40 -0500488
489 struct OpenCLBuiltinMemoryBuffer final : public llvm::MemoryBuffer {
490 OpenCLBuiltinMemoryBuffer(const void *data, uint64_t data_length) {
491 const char *dataCasted = reinterpret_cast<const char *>(data);
492 init(dataCasted, dataCasted + data_length, true);
493 }
494
495 virtual llvm::MemoryBuffer::BufferKind getBufferKind() const override {
496 return llvm::MemoryBuffer::MemoryBuffer_Malloc;
497 }
498
499 virtual ~OpenCLBuiltinMemoryBuffer() override {}
500 };
501
502 std::unique_ptr<llvm::MemoryBuffer> openCLBuiltinMemoryBuffer(
503 new OpenCLBuiltinMemoryBuffer(opencl_builtins_header_data,
504 opencl_builtins_header_size - 1));
505
506 instance.getPreprocessorOpts().Includes.push_back("openclc.h");
507
alan-bakerf3bce4a2019-06-28 16:01:15 -0400508 std::unique_ptr<llvm::MemoryBuffer> openCLBaseBuiltinMemoryBuffer(
509 new OpenCLBuiltinMemoryBuffer(opencl_base_builtins_header_data,
510 opencl_base_builtins_header_size - 1));
511
512 instance.getPreprocessorOpts().Includes.push_back("opencl-c-base.h");
513
alan-bakerfec0a472018-11-08 18:09:40 -0500514 // Add the VULKAN macro.
515 instance.getPreprocessorOpts().addMacroDef("VULKAN=100");
516
517 // Add the __OPENCL_VERSION__ macro.
518 instance.getPreprocessorOpts().addMacroDef("__OPENCL_VERSION__=120");
519
520 instance.setTarget(clang::TargetInfo::CreateTargetInfo(
521 instance.getDiagnostics(),
522 std::make_shared<clang::TargetOptions>(instance.getTargetOpts())));
523
524 instance.createFileManager();
525 instance.createSourceManager(instance.getFileManager());
526
527#ifdef _MSC_VER
528 std::string includePrefix("include\\");
529#else
530 std::string includePrefix("include/");
531#endif
532
533 auto entry = instance.getFileManager().getVirtualFile(
534 includePrefix + "openclc.h", openCLBuiltinMemoryBuffer->getBufferSize(),
535 0);
536
537 instance.getSourceManager().overrideFileContents(
538 entry, std::move(openCLBuiltinMemoryBuffer));
539
alan-bakerf3bce4a2019-06-28 16:01:15 -0400540 auto base_entry = instance.getFileManager().getVirtualFile(
541 includePrefix + "opencl-c-base.h",
542 openCLBaseBuiltinMemoryBuffer->getBufferSize(), 0);
543
544 instance.getSourceManager().overrideFileContents(
545 base_entry, std::move(openCLBaseBuiltinMemoryBuffer));
546
alan-bakerfec0a472018-11-08 18:09:40 -0500547 return 0;
548}
549
alan-bakerf5e5f692018-11-27 08:33:24 -0500550// Populates |pm| with necessary passes to optimize and legalize the IR.
551int PopulatePassManager(
552 llvm::legacy::PassManager *pm, llvm::raw_svector_ostream *binaryStream,
553 std::vector<clspv::version0::DescriptorMapEntry> *descriptor_map_entries,
554 llvm::SmallVectorImpl<std::pair<unsigned, std::string>>
555 *SamplerMapEntries) {
alan-bakerfec0a472018-11-08 18:09:40 -0500556 llvm::PassManagerBuilder pmBuilder;
557
558 switch (OptimizationLevel) {
559 case '0':
alan-bakerf5e5f692018-11-27 08:33:24 -0500560 case '1':
561 case '2':
562 case '3':
563 case 's':
564 case 'z':
565 break;
566 default:
567 llvm::errs() << "Unknown optimization level -O" << OptimizationLevel
568 << " specified!\n";
569 return -1;
570 }
571
572 switch (OptimizationLevel) {
573 case '0':
alan-bakerfec0a472018-11-08 18:09:40 -0500574 pmBuilder.OptLevel = 0;
575 break;
576 case '1':
577 pmBuilder.OptLevel = 1;
578 break;
579 case '2':
580 pmBuilder.OptLevel = 2;
581 break;
582 case '3':
583 pmBuilder.OptLevel = 3;
584 break;
585 case 's':
586 pmBuilder.SizeLevel = 1;
587 break;
588 case 'z':
589 pmBuilder.SizeLevel = 2;
590 break;
591 default:
592 break;
593 }
594
595 pm->add(clspv::createZeroInitializeAllocasPass());
596 pm->add(clspv::createDefineOpenCLWorkItemBuiltinsPass());
597
598 if (0 < pmBuilder.OptLevel) {
599 pm->add(clspv::createOpenCLInlinerPass());
600 }
601
602 pm->add(clspv::createUndoByvalPass());
603 pm->add(clspv::createUndoSRetPass());
604 if (cluster_non_pointer_kernel_args) {
605 pm->add(clspv::createClusterPodKernelArgumentsPass());
606 }
607 pm->add(clspv::createReplaceOpenCLBuiltinPass());
608
609 // We need to run mem2reg and inst combine early because our
610 // createInlineFuncWithPointerBitCastArgPass pass cannot handle the pattern
611 // %1 = alloca i32 1
612 // store <something> %1
613 // %2 = bitcast float* %1
614 // %3 = load float %2
615 pm->add(llvm::createPromoteMemoryToRegisterPass());
616
alan-baker1b13e8f2019-08-08 17:56:51 -0400617 // Try to deal with pointer bitcasts early. This can prevent problems like
618 // issue #409 where LLVM is looser about access chain addressing than SPIR-V.
619 // This needs to happen before instcombine and after replacing OpenCL
620 // builtins. This run of the pass will not handle all pointer bitcasts that
621 // could be handled. It should be run again after other optimizations (e.g
622 // InlineFuncWithPointerBitCastArgPass).
623 pm->add(clspv::createSimplifyPointerBitcastPass());
624 pm->add(clspv::createReplacePointerBitcastPass());
625 pm->add(llvm::createDeadCodeEliminationPass());
626
alan-bakerfec0a472018-11-08 18:09:40 -0500627 // Hide loads from __constant address space away from instcombine.
628 // This prevents us from generating select between pointers-to-__constant.
629 // See https://github.com/google/clspv/issues/71
630 pm->add(clspv::createHideConstantLoadsPass());
631
632 pm->add(llvm::createInstructionCombiningPass());
633
634 if (clspv::Option::InlineEntryPoints()) {
635 pm->add(clspv::createInlineEntryPointsPass());
636 } else {
637 pm->add(clspv::createInlineFuncWithPointerBitCastArgPass());
638 pm->add(clspv::createInlineFuncWithPointerToFunctionArgPass());
639 pm->add(clspv::createInlineFuncWithSingleCallSitePass());
640 }
641
Kévin Petit0fc88042019-04-09 23:25:02 +0100642 if (clspv::Option::CPlusPlus()) {
Kévin Petit38c52482019-05-07 20:28:00 +0800643 pm->add(llvm::createInferAddressSpacesPass(clspv::AddressSpace::Generic));
Kévin Petit0fc88042019-04-09 23:25:02 +0100644 }
645
alan-bakerfec0a472018-11-08 18:09:40 -0500646 if (0 == pmBuilder.OptLevel) {
647 // Mem2Reg pass should be run early because O0 level optimization leaves
648 // redundant alloca, load and store instructions from function arguments.
649 // clspv needs to remove them ahead of transformation.
650 pm->add(llvm::createPromoteMemoryToRegisterPass());
651
652 // SROA pass is run because it will fold structs/unions that are problematic
653 // on Vulkan SPIR-V away.
654 pm->add(llvm::createSROAPass());
655
656 // InstructionCombining pass folds bitcast and gep instructions which are
657 // not supported by Vulkan SPIR-V.
658 pm->add(llvm::createInstructionCombiningPass());
659 }
660
661 // Now we add any of the LLVM optimizations we wanted
662 pmBuilder.populateModulePassManager(*pm);
663
664 // Unhide loads from __constant address space. Undoes the action of
665 // HideConstantLoadsPass.
666 pm->add(clspv::createUnhideConstantLoadsPass());
667
668 pm->add(clspv::createFunctionInternalizerPass());
669 pm->add(clspv::createReplaceLLVMIntrinsicsPass());
670 pm->add(clspv::createUndoBoolPass());
671 pm->add(clspv::createUndoTruncatedSwitchConditionPass());
672 pm->add(llvm::createStructurizeCFGPass(false));
alan-baker3fa76d92018-11-12 14:54:40 -0500673 // Must be run after structurize cfg.
alan-bakerfec0a472018-11-08 18:09:40 -0500674 pm->add(clspv::createReorderBasicBlocksPass());
675 pm->add(clspv::createUndoGetElementPtrConstantExprPass());
676 pm->add(clspv::createSplatArgPass());
677 pm->add(clspv::createSimplifyPointerBitcastPass());
678 pm->add(clspv::createReplacePointerBitcastPass());
679
680 pm->add(clspv::createUndoTranslateSamplerFoldPass());
681
682 if (clspv::Option::ModuleConstantsInStorageBuffer()) {
683 pm->add(clspv::createClusterModuleScopeConstantVars());
684 }
685
686 pm->add(clspv::createShareModuleScopeVariablesPass());
alan-bakere9308012019-03-15 10:25:13 -0400687 // This should be run after LLVM and OpenCL intrinsics are replaced.
alan-bakerfec0a472018-11-08 18:09:40 -0500688 pm->add(clspv::createAllocateDescriptorsPass(*SamplerMapEntries));
689 pm->add(llvm::createVerifierPass());
690 pm->add(clspv::createDirectResourceAccessPass());
691 // Replacing pointer bitcasts can leave some trivial GEPs
692 // that are easy to remove. Also replace GEPs of GEPS
693 // left by replacing indirect buffer accesses.
694 pm->add(clspv::createSimplifyPointerBitcastPass());
alan-baker4217b322019-03-06 08:56:12 -0500695 // Run after DRA to clean up parameters and help reduce the need for variable
696 // pointers.
697 pm->add(clspv::createRemoveUnusedArgumentsPass());
alan-bakerfec0a472018-11-08 18:09:40 -0500698
699 pm->add(clspv::createSplatSelectConditionPass());
700 pm->add(clspv::createSignedCompareFixupPass());
701 // This pass generates insertions that need to be rewritten.
702 pm->add(clspv::createScalarizePass());
703 pm->add(clspv::createRewriteInsertsPass());
alan-bakera71f1932019-04-11 11:04:34 -0400704 // UBO Transformations
705 if (clspv::Option::ConstantArgsInUniformBuffer() &&
706 !clspv::Option::InlineEntryPoints()) {
707 // MultiVersionUBOFunctionsPass will examine non-kernel functions with UBO
708 // arguments and either multi-version them as necessary or inline them if
709 // multi-versioning cannot be accomplished.
710 pm->add(clspv::createMultiVersionUBOFunctionsPass());
711 // Cleanup passes.
712 // Specialization can blindly generate GEP chains that are easily cleaned up
713 // by SimplifyPointerBitcastPass.
714 pm->add(clspv::createSimplifyPointerBitcastPass());
715 // RemoveUnusedArgumentsPass removes the actual UBO arguments that were
716 // problematic to begin with now that they have no uses.
717 pm->add(clspv::createRemoveUnusedArgumentsPass());
718 // DCE cleans up callers of the specialized functions.
719 pm->add(llvm::createDeadCodeEliminationPass());
720 }
alan-bakerfec0a472018-11-08 18:09:40 -0500721 // This pass mucks with types to point where you shouldn't rely on DataLayout
722 // anymore so leave this right before SPIR-V generation.
723 pm->add(clspv::createUBOTypeTransformPass());
alan-baker00e7a582019-06-07 12:54:21 -0400724 pm->add(clspv::createSPIRVProducerPass(*binaryStream, descriptor_map_entries,
725 *SamplerMapEntries,
726 OutputFormat == "c"));
alan-bakerf5e5f692018-11-27 08:33:24 -0500727
728 return 0;
alan-bakerfec0a472018-11-08 18:09:40 -0500729}
alan-bakerfec0a472018-11-08 18:09:40 -0500730
Kévin Petitd5db2d22019-04-04 13:55:14 +0100731int ParseOptions(const int argc, const char *const argv[]) {
alan-bakerfec0a472018-11-08 18:09:40 -0500732 // We need to change how one of the called passes works by spoofing
733 // ParseCommandLineOptions with the specific option.
734 const int llvmArgc = 2;
735 const char *llvmArgv[llvmArgc] = {
alan-bakerf5e5f692018-11-27 08:33:24 -0500736 argv[0],
737 "-simplifycfg-sink-common=false",
alan-bakerfec0a472018-11-08 18:09:40 -0500738 };
739
Kévin Petitd5db2d22019-04-04 13:55:14 +0100740 llvm::cl::ResetAllOptionOccurrences();
alan-bakerfec0a472018-11-08 18:09:40 -0500741 llvm::cl::ParseCommandLineOptions(llvmArgc, llvmArgv);
alan-bakerfec0a472018-11-08 18:09:40 -0500742 llvm::cl::ParseCommandLineOptions(argc, argv);
743
Diego Novillo3cc8d7a2019-04-10 13:30:34 -0400744 if (clspv::Option::CPlusPlus() && !clspv::Option::InlineEntryPoints()) {
Kévin Petit0fc88042019-04-09 23:25:02 +0100745 llvm::errs() << "cannot use -c++ without -inline-entry-points\n";
746 return -1;
747 }
748
Kévin Petitd5db2d22019-04-04 13:55:14 +0100749 return 0;
750}
Diego Novillo89500852019-04-15 08:45:10 -0400751
752int GenerateIRFile(llvm::legacy::PassManager *pm, llvm::Module &module,
753 std::string output) {
754 std::error_code ec;
755 std::unique_ptr<llvm::ToolOutputFile> out(
756 new llvm::ToolOutputFile(output, ec, llvm::sys::fs::F_None));
757 if (ec) {
758 llvm::errs() << output << ": " << ec.message() << '\n';
759 return -1;
760 }
761 pm->add(llvm::createPrintModulePass(out->os(), "", false));
762 pm->run(module);
763 out->keep();
764 return 0;
765}
766
Kévin Petitd5db2d22019-04-04 13:55:14 +0100767} // namespace
768
769namespace clspv {
770int Compile(const int argc, const char *const argv[]) {
771
772 if (auto error = ParseOptions(argc, argv))
773 return error;
774
alan-bakerfec0a472018-11-08 18:09:40 -0500775 llvm::SmallVector<std::pair<unsigned, std::string>, 8> SamplerMapEntries;
alan-bakerf5e5f692018-11-27 08:33:24 -0500776 if (auto error = ParseSamplerMap("", &SamplerMapEntries))
alan-bakerfec0a472018-11-08 18:09:40 -0500777 return error;
778
779 // if no output file was provided, use a default
780 llvm::StringRef overiddenInputFilename = InputFilename.getValue();
781
782 // If we are reading our input file from stdin.
783 if ("-" == InputFilename) {
784 // We need to overwrite the file name we use.
785 overiddenInputFilename = "stdin.cl";
786 }
787
788 clang::CompilerInstance instance;
alan-bakerd354f1a2019-08-06 15:41:55 -0400789 clang::FrontendInputFile kernelFile(
790 overiddenInputFilename, clang::InputKind(clang::Language::OpenCL));
alan-bakerfec0a472018-11-08 18:09:40 -0500791 std::string log;
792 llvm::raw_string_ostream diagnosticsStream(log);
alan-bakerf5e5f692018-11-27 08:33:24 -0500793 if (auto error = SetCompilerInstanceOptions(
794 instance, overiddenInputFilename, kernelFile, "", &diagnosticsStream))
alan-bakerfec0a472018-11-08 18:09:40 -0500795 return error;
796
797 // Parse.
798 llvm::LLVMContext context;
799 clang::EmitLLVMOnlyAction action(&context);
800
801 // Prepare the action for processing kernelFile
802 const bool success = action.BeginSourceFile(instance, kernelFile);
803 if (!success) {
804 return -1;
805 }
806
alan-bakerf3bce4a2019-06-28 16:01:15 -0400807 auto result = action.Execute();
alan-bakerfec0a472018-11-08 18:09:40 -0500808 action.EndSourceFile();
809
810 clang::DiagnosticConsumer *const consumer =
811 instance.getDiagnostics().getClient();
812 consumer->finish();
813
Kévin Petit6b07cbe2019-04-02 21:52:16 +0100814 auto num_warnings = consumer->getNumWarnings();
alan-bakerfec0a472018-11-08 18:09:40 -0500815 auto num_errors = consumer->getNumErrors();
Kévin Petit6b07cbe2019-04-02 21:52:16 +0100816 if ((num_errors > 0) || (num_warnings > 0)) {
817 llvm::errs() << log;
818 }
alan-bakerf3bce4a2019-06-28 16:01:15 -0400819 if (result || num_errors > 0) {
alan-bakerfec0a472018-11-08 18:09:40 -0500820 return -1;
821 }
822
Kévin Petit6b07cbe2019-04-02 21:52:16 +0100823 // Don't run the passes or produce any output in verify mode.
824 // Clang doesn't always produce a valid module.
825 if (verify) {
826 return 0;
827 }
828
alan-bakerfec0a472018-11-08 18:09:40 -0500829 llvm::PassRegistry &Registry = *llvm::PassRegistry::getPassRegistry();
830 llvm::initializeCore(Registry);
831 llvm::initializeScalarOpts(Registry);
Diego Novillo1fcff722019-05-07 13:45:53 -0400832 llvm::initializeClspvPasses(Registry);
alan-bakerfec0a472018-11-08 18:09:40 -0500833
834 std::unique_ptr<llvm::Module> module(action.takeModule());
835
836 // Optimize.
837 // Create a memory buffer for temporarily writing the result.
838 SmallVector<char, 10000> binary;
839 llvm::raw_svector_ostream binaryStream(binary);
840 std::string descriptor_map;
alan-bakerfec0a472018-11-08 18:09:40 -0500841 llvm::legacy::PassManager pm;
alan-bakerf5e5f692018-11-27 08:33:24 -0500842 std::vector<version0::DescriptorMapEntry> descriptor_map_entries;
Diego Novillo89500852019-04-15 08:45:10 -0400843
844 // If --emit-ir was requested, emit the initial LLVM IR and stop compilation.
845 if (!IROutputFile.empty()) {
846 return GenerateIRFile(&pm, *module, IROutputFile);
847 }
848
849 // Otherwise, populate the pass manager and run the regular passes.
Diego Novillo3cc8d7a2019-04-10 13:30:34 -0400850 if (auto error = PopulatePassManager(
851 &pm, &binaryStream, &descriptor_map_entries, &SamplerMapEntries))
alan-bakerf5e5f692018-11-27 08:33:24 -0500852 return error;
alan-bakerfec0a472018-11-08 18:09:40 -0500853 pm.run(*module);
854
855 // Write outputs
856
857 // Write the descriptor map, if requested.
858 std::error_code error;
859 if (!DescriptorMapFilename.empty()) {
Diego Novillo3cc8d7a2019-04-10 13:30:34 -0400860 llvm::raw_fd_ostream descriptor_map_out_fd(
861 DescriptorMapFilename, error, llvm::sys::fs::CD_CreateAlways,
862 llvm::sys::fs::FA_Write, llvm::sys::fs::F_Text);
alan-bakerfec0a472018-11-08 18:09:40 -0500863 if (error) {
864 llvm::errs() << "Unable to open descriptor map file '"
865 << DescriptorMapFilename << "': " << error.message() << '\n';
866 return -1;
867 }
alan-bakerf5e5f692018-11-27 08:33:24 -0500868 std::string descriptor_map_string;
869 std::ostringstream str(descriptor_map_string);
870 for (const auto &entry : descriptor_map_entries) {
871 str << entry << "\n";
872 }
873 descriptor_map_out_fd << str.str();
alan-bakerfec0a472018-11-08 18:09:40 -0500874 descriptor_map_out_fd.close();
875 }
876
877 // Write the resulting binary.
878 // Wait until now to try writing the file so that we only write it on
879 // successful compilation.
880 if (OutputFilename.empty()) {
Kévin Petite4786902019-04-02 21:51:47 +0100881 if (OutputFormat == "c") {
alan-bakerfec0a472018-11-08 18:09:40 -0500882 OutputFilename = "a.spvinc";
883 } else {
884 OutputFilename = "a.spv";
885 }
886 }
Diego Novillo3cc8d7a2019-04-10 13:30:34 -0400887 llvm::raw_fd_ostream outStream(OutputFilename, error,
888 llvm::sys::fs::FA_Write);
alan-bakerfec0a472018-11-08 18:09:40 -0500889
890 if (error) {
891 llvm::errs() << "Unable to open output file '" << OutputFilename
892 << "': " << error.message() << '\n';
893 return -1;
894 }
895 outStream << binaryStream.str();
896
897 return 0;
898}
alan-bakerf5e5f692018-11-27 08:33:24 -0500899
Diego Novillo3cc8d7a2019-04-10 13:30:34 -0400900int CompileFromSourceString(
901 const std::string &program, const std::string &sampler_map,
902 const std::string &options, std::vector<uint32_t> *output_binary,
903 std::vector<clspv::version0::DescriptorMapEntry> *descriptor_map_entries) {
alan-bakerf5e5f692018-11-27 08:33:24 -0500904
905 llvm::SmallVector<const char *, 20> argv;
906 llvm::BumpPtrAllocator A;
907 llvm::StringSaver Saver(A);
908 argv.push_back(Saver.save("clspv").data());
909 llvm::cl::TokenizeGNUCommandLine(options, Saver, argv);
910 int argc = static_cast<int>(argv.size());
Kévin Petitd5db2d22019-04-04 13:55:14 +0100911
912 if (auto error = ParseOptions(argc, &argv[0]))
913 return error;
alan-bakerf5e5f692018-11-27 08:33:24 -0500914
915 llvm::SmallVector<std::pair<unsigned, std::string>, 8> SamplerMapEntries;
916 if (auto error = ParseSamplerMap(sampler_map, &SamplerMapEntries))
917 return error;
918
919 InputFilename = "source.cl";
920 llvm::StringRef overiddenInputFilename = InputFilename.getValue();
921
922 clang::CompilerInstance instance;
alan-bakerd354f1a2019-08-06 15:41:55 -0400923 clang::FrontendInputFile kernelFile(
924 overiddenInputFilename, clang::InputKind(clang::Language::OpenCL));
alan-bakerf5e5f692018-11-27 08:33:24 -0500925 std::string log;
926 llvm::raw_string_ostream diagnosticsStream(log);
927 if (auto error =
928 SetCompilerInstanceOptions(instance, overiddenInputFilename,
929 kernelFile, program, &diagnosticsStream))
930 return error;
931
932 // Parse.
933 llvm::LLVMContext context;
934 clang::EmitLLVMOnlyAction action(&context);
935
936 // Prepare the action for processing kernelFile
937 const bool success = action.BeginSourceFile(instance, kernelFile);
938 if (!success) {
939 return -1;
940 }
941
alan-bakerf3bce4a2019-06-28 16:01:15 -0400942 auto result = action.Execute();
alan-bakerf5e5f692018-11-27 08:33:24 -0500943 action.EndSourceFile();
944
945 clang::DiagnosticConsumer *const consumer =
946 instance.getDiagnostics().getClient();
947 consumer->finish();
948
949 auto num_errors = consumer->getNumErrors();
alan-bakerf3bce4a2019-06-28 16:01:15 -0400950 if (result || num_errors > 0) {
alan-bakerf5e5f692018-11-27 08:33:24 -0500951 llvm::errs() << log << "\n";
952 return -1;
953 }
954
alan-bakerf5e5f692018-11-27 08:33:24 -0500955 llvm::PassRegistry &Registry = *llvm::PassRegistry::getPassRegistry();
956 llvm::initializeCore(Registry);
957 llvm::initializeScalarOpts(Registry);
Diego Novillo1fcff722019-05-07 13:45:53 -0400958 llvm::initializeClspvPasses(Registry);
alan-bakerf5e5f692018-11-27 08:33:24 -0500959
960 std::unique_ptr<llvm::Module> module(action.takeModule());
961
962 // Optimize.
963 // Create a memory buffer for temporarily writing the result.
964 SmallVector<char, 10000> binary;
965 llvm::raw_svector_ostream binaryStream(binary);
966 std::string descriptor_map;
967 llvm::legacy::PassManager pm;
Diego Novillo3cc8d7a2019-04-10 13:30:34 -0400968 if (auto error = PopulatePassManager(
969 &pm, &binaryStream, descriptor_map_entries, &SamplerMapEntries))
alan-bakerf5e5f692018-11-27 08:33:24 -0500970 return error;
971 pm.run(*module);
972
973 // Write outputs
974
975 // Write the descriptor map. This is required.
Diego Novillo3cc8d7a2019-04-10 13:30:34 -0400976 assert(descriptor_map_entries &&
977 "Valid descriptor map container is required.");
alan-bakerf5e5f692018-11-27 08:33:24 -0500978 if (!DescriptorMapFilename.empty()) {
Diego Novillo3cc8d7a2019-04-10 13:30:34 -0400979 llvm::errs() << "Warning: -descriptormap is ignored descriptor map "
980 "container is provided.\n";
alan-bakerf5e5f692018-11-27 08:33:24 -0500981 }
982
983 // Write the resulting binary.
984 // Wait until now to try writing the file so that we only write it on
985 // successful compilation.
986 assert(output_binary && "Valid binary container is required.");
987 if (!OutputFilename.empty()) {
988 llvm::outs()
989 << "Warning: -o is ignored when binary container is provided.\n";
990 }
991 output_binary->resize(binary.size() / 4);
992 memcpy(output_binary->data(), binary.data(), binary.size());
993
994 return 0;
995}
alan-bakerfec0a472018-11-08 18:09:40 -0500996} // namespace clspv