blob: f46593ff24f5f4be34017892651fab60fe4bf5e7 [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
Kévin Petitddad8f42019-09-30 15:12:08 +0100123static llvm::cl::opt<clang::Language> InputLanguage(
124 "x", llvm::cl::desc("Select input type"),
125 llvm::cl::init(clang::Language::OpenCL),
126 llvm::cl::values(clEnumValN(clang::Language::OpenCL, "cl", "OpenCL source"),
127 clEnumValN(clang::Language::LLVM_IR, "ir", "LLVM IR")));
128
alan-bakerfec0a472018-11-08 18:09:40 -0500129static llvm::cl::opt<std::string>
130 OutputFilename("o", llvm::cl::desc("Override output filename"),
131 llvm::cl::value_desc("filename"));
132
133static llvm::cl::opt<std::string>
134 DescriptorMapFilename("descriptormap",
135 llvm::cl::desc("Output file for descriptor map"),
136 llvm::cl::value_desc("filename"));
137
138static llvm::cl::opt<char>
139 OptimizationLevel(llvm::cl::Prefix, "O", llvm::cl::init('2'),
140 llvm::cl::desc("Optimization level to use"),
141 llvm::cl::value_desc("level"));
142
alan-bakerfec0a472018-11-08 18:09:40 -0500143static llvm::cl::opt<std::string> OutputFormat(
144 "mfmt", llvm::cl::init(""),
145 llvm::cl::desc(
146 "Specify special output format. 'c' is as a C initializer list"),
147 llvm::cl::value_desc("format"));
148
149static llvm::cl::opt<std::string>
150 SamplerMap("samplermap", llvm::cl::desc("Literal sampler map"),
151 llvm::cl::value_desc("filename"));
152
153static llvm::cl::opt<bool> cluster_non_pointer_kernel_args(
154 "cluster-pod-kernel-args", llvm::cl::init(false),
155 llvm::cl::desc("Collect plain-old-data kernel arguments into a struct in "
156 "a single storage buffer, using a binding number after "
157 "other arguments. Use this to reduce storage buffer "
158 "descriptors."));
159
160static llvm::cl::opt<bool> verify("verify", llvm::cl::init(false),
161 llvm::cl::desc("Verify diagnostic outputs"));
162
Kévin Petit6b07cbe2019-04-02 21:52:16 +0100163static llvm::cl::opt<bool>
164 IgnoreWarnings("w", llvm::cl::init(false),
165 llvm::cl::desc("Disable all warnings"));
166
167static llvm::cl::opt<bool>
168 WarningsAsErrors("Werror", llvm::cl::init(false),
Diego Novillo3cc8d7a2019-04-10 13:30:34 -0400169 llvm::cl::desc("Turn warnings into errors"));
Kévin Petit6b07cbe2019-04-02 21:52:16 +0100170
Diego Novillo89500852019-04-15 08:45:10 -0400171static llvm::cl::opt<std::string> IROutputFile(
172 "emit-ir",
173 llvm::cl::desc(
174 "Emit LLVM IR to the given file after parsing and stop compilation."),
175 llvm::cl::value_desc("filename"));
176
alan-bakerfec0a472018-11-08 18:09:40 -0500177// Populates |SamplerMapEntries| with data from the input sampler map. Returns 0
178// if successful.
alan-bakerf5e5f692018-11-27 08:33:24 -0500179int ParseSamplerMap(const std::string &sampler_map,
180 llvm::SmallVectorImpl<std::pair<unsigned, std::string>>
181 *SamplerMapEntries) {
182 std::unique_ptr<llvm::MemoryBuffer> samplerMapBuffer(nullptr);
183 if (!sampler_map.empty()) {
184 // Parse the sampler map from the provided string.
185 samplerMapBuffer = llvm::MemoryBuffer::getMemBuffer(sampler_map);
186
187 if (!SamplerMap.empty()) {
188 llvm::outs() << "Warning: -samplermap is ignored when the sampler map is "
189 "provided through a string.\n";
190 }
191 } else if (!SamplerMap.empty()) {
192 // Parse the sampler map from the option provided file.
alan-bakerfec0a472018-11-08 18:09:40 -0500193 auto errorOrSamplerMapFile =
194 llvm::MemoryBuffer::getFile(SamplerMap.getValue());
195
196 // If there was an error in getting the sampler map file.
197 if (!errorOrSamplerMapFile) {
198 llvm::errs() << "Error: " << errorOrSamplerMapFile.getError().message()
199 << " '" << SamplerMap.getValue() << "'\n";
200 return -1;
201 }
202
alan-bakerf5e5f692018-11-27 08:33:24 -0500203 samplerMapBuffer = std::move(errorOrSamplerMapFile.get());
alan-bakerfec0a472018-11-08 18:09:40 -0500204 if (0 == samplerMapBuffer->getBufferSize()) {
205 llvm::errs() << "Error: Sampler map was an empty file!\n";
206 return -1;
207 }
alan-bakerf5e5f692018-11-27 08:33:24 -0500208 }
alan-bakerfec0a472018-11-08 18:09:40 -0500209
alan-bakerf5e5f692018-11-27 08:33:24 -0500210 // No sampler map to parse.
211 if (!samplerMapBuffer || 0 == samplerMapBuffer->getBufferSize())
212 return 0;
alan-bakerfec0a472018-11-08 18:09:40 -0500213
alan-bakerf5e5f692018-11-27 08:33:24 -0500214 llvm::SmallVector<llvm::StringRef, 3> samplerStrings;
alan-bakerfec0a472018-11-08 18:09:40 -0500215
alan-bakerf5e5f692018-11-27 08:33:24 -0500216 // We need to keep track of the beginning of the current entry.
217 const char *b = samplerMapBuffer->getBufferStart();
218 for (const char *i = b, *e = samplerMapBuffer->getBufferEnd();; i++) {
219 // If we have a separator between declarations.
220 if ((*i == '|') || (*i == ',') || (i == e)) {
221 if (i == b) {
222 llvm::errs() << "Error: Sampler map contained an empty entry!\n";
223 return -1;
alan-bakerfec0a472018-11-08 18:09:40 -0500224 }
225
alan-bakerf5e5f692018-11-27 08:33:24 -0500226 samplerStrings.push_back(llvm::StringRef(b, i - b).trim());
alan-bakerfec0a472018-11-08 18:09:40 -0500227
alan-bakerf5e5f692018-11-27 08:33:24 -0500228 // And set b the next character after i.
229 b = i + 1;
230 }
alan-bakerfec0a472018-11-08 18:09:40 -0500231
alan-bakerf5e5f692018-11-27 08:33:24 -0500232 // If we have a separator between declarations within a single sampler.
233 if ((*i == ',') || (i == e)) {
234 enum NormalizedCoords {
235 CLK_NORMALIZED_COORDS_FALSE = 0x00,
236 CLK_NORMALIZED_COORDS_TRUE = 0x01,
237 CLK_NORMALIZED_COORDS_NOT_SET
238 } NormalizedCoord = CLK_NORMALIZED_COORDS_NOT_SET;
alan-bakerfec0a472018-11-08 18:09:40 -0500239
alan-bakerf5e5f692018-11-27 08:33:24 -0500240 enum AddressingModes {
241 CLK_ADDRESS_NONE = 0x00,
242 CLK_ADDRESS_CLAMP_TO_EDGE = 0x02,
243 CLK_ADDRESS_CLAMP = 0x04,
244 CLK_ADDRESS_MIRRORED_REPEAT = 0x08,
245 CLK_ADDRESS_REPEAT = 0x06,
246 CLK_ADDRESS_NOT_SET
247 } AddressingMode = CLK_ADDRESS_NOT_SET;
248
249 enum FilterModes {
250 CLK_FILTER_NEAREST = 0x10,
251 CLK_FILTER_LINEAR = 0x20,
252 CLK_FILTER_NOT_SET
253 } FilterMode = CLK_FILTER_NOT_SET;
254
255 for (auto str : samplerStrings) {
256 if ("CLK_NORMALIZED_COORDS_FALSE" == str) {
257 if (CLK_NORMALIZED_COORDS_NOT_SET != NormalizedCoord) {
258 llvm::errs() << "Error: Sampler map normalized coordinates was "
259 "previously set!\n";
alan-bakerfec0a472018-11-08 18:09:40 -0500260 return -1;
261 }
alan-bakerf5e5f692018-11-27 08:33:24 -0500262 NormalizedCoord = CLK_NORMALIZED_COORDS_FALSE;
263 } else if ("CLK_NORMALIZED_COORDS_TRUE" == str) {
264 if (CLK_NORMALIZED_COORDS_NOT_SET != NormalizedCoord) {
265 llvm::errs() << "Error: Sampler map normalized coordinates was "
266 "previously set!\n";
267 return -1;
268 }
269 NormalizedCoord = CLK_NORMALIZED_COORDS_TRUE;
270 } else if ("CLK_ADDRESS_NONE" == str) {
271 if (CLK_ADDRESS_NOT_SET != AddressingMode) {
272 llvm::errs()
273 << "Error: Sampler map addressing mode was previously set!\n";
274 return -1;
275 }
276 AddressingMode = CLK_ADDRESS_NONE;
277 } else if ("CLK_ADDRESS_CLAMP_TO_EDGE" == str) {
278 if (CLK_ADDRESS_NOT_SET != AddressingMode) {
279 llvm::errs()
280 << "Error: Sampler map addressing mode was previously set!\n";
281 return -1;
282 }
283 AddressingMode = CLK_ADDRESS_CLAMP_TO_EDGE;
284 } else if ("CLK_ADDRESS_CLAMP" == str) {
285 if (CLK_ADDRESS_NOT_SET != AddressingMode) {
286 llvm::errs()
287 << "Error: Sampler map addressing mode was previously set!\n";
288 return -1;
289 }
290 AddressingMode = CLK_ADDRESS_CLAMP;
291 } else if ("CLK_ADDRESS_MIRRORED_REPEAT" == str) {
292 if (CLK_ADDRESS_NOT_SET != AddressingMode) {
293 llvm::errs()
294 << "Error: Sampler map addressing mode was previously set!\n";
295 return -1;
296 }
297 AddressingMode = CLK_ADDRESS_MIRRORED_REPEAT;
298 } else if ("CLK_ADDRESS_REPEAT" == str) {
299 if (CLK_ADDRESS_NOT_SET != AddressingMode) {
300 llvm::errs()
301 << "Error: Sampler map addressing mode was previously set!\n";
302 return -1;
303 }
304 AddressingMode = CLK_ADDRESS_REPEAT;
305 } else if ("CLK_FILTER_NEAREST" == str) {
306 if (CLK_FILTER_NOT_SET != FilterMode) {
307 llvm::errs()
308 << "Error: Sampler map filtering mode was previously set!\n";
309 return -1;
310 }
311 FilterMode = CLK_FILTER_NEAREST;
312 } else if ("CLK_FILTER_LINEAR" == str) {
313 if (CLK_FILTER_NOT_SET != FilterMode) {
314 llvm::errs()
315 << "Error: Sampler map filtering mode was previously set!\n";
316 return -1;
317 }
318 FilterMode = CLK_FILTER_LINEAR;
319 } else {
320 llvm::errs() << "Error: Unknown sampler string '" << str
321 << "' found!\n";
alan-bakerfec0a472018-11-08 18:09:40 -0500322 return -1;
323 }
alan-bakerfec0a472018-11-08 18:09:40 -0500324 }
325
alan-bakerf5e5f692018-11-27 08:33:24 -0500326 if (CLK_NORMALIZED_COORDS_NOT_SET == NormalizedCoord) {
327 llvm::errs() << "Error: Sampler map entry did not contain normalized "
328 "coordinates entry!\n";
329 return -1;
alan-bakerfec0a472018-11-08 18:09:40 -0500330 }
alan-bakerf5e5f692018-11-27 08:33:24 -0500331
332 if (CLK_ADDRESS_NOT_SET == AddressingMode) {
333 llvm::errs() << "Error: Sampler map entry did not contain addressing "
334 "mode entry!\n";
335 return -1;
336 }
337
338 if (CLK_FILTER_NOT_SET == FilterMode) {
339 llvm::errs()
340 << "Error: Sampler map entry did not contain filer mode entry!\n";
341 return -1;
342 }
343
344 // Generate an equivalent expression in string form. Sort the
345 // strings to get a canonical ordering.
346 std::sort(samplerStrings.begin(), samplerStrings.end(),
347 std::less<StringRef>());
348 const auto samplerExpr = std::accumulate(
349 samplerStrings.begin(), samplerStrings.end(), std::string(),
350 [](std::string left, std::string right) {
351 return left + std::string(left.empty() ? "" : "|") + right;
352 });
353
354 // SamplerMapEntries->push_back(std::make_pair(
355 // NormalizedCoord | AddressingMode | FilterMode, samplerExpr));
356 SamplerMapEntries->emplace_back(
357 NormalizedCoord | AddressingMode | FilterMode, samplerExpr);
358
359 // And reset the sampler strings for the next sampler in the map.
360 samplerStrings.clear();
361 }
362
363 // And lastly, if we are at the end of the file
364 if (i == e) {
365 break;
alan-bakerfec0a472018-11-08 18:09:40 -0500366 }
367 }
368
369 return 0;
370}
371
372// Sets |instance|'s options for compiling. Returns 0 if successful.
373int SetCompilerInstanceOptions(CompilerInstance &instance,
374 const llvm::StringRef &overiddenInputFilename,
375 const clang::FrontendInputFile &kernelFile,
alan-bakerf5e5f692018-11-27 08:33:24 -0500376 const std::string &program,
alan-bakerfec0a472018-11-08 18:09:40 -0500377 llvm::raw_string_ostream *diagnosticsStream) {
alan-bakerf5e5f692018-11-27 08:33:24 -0500378 std::unique_ptr<llvm::MemoryBuffer> memory_buffer(nullptr);
379 llvm::ErrorOr<std::unique_ptr<llvm::MemoryBuffer>> errorOrInputFile(nullptr);
380 if (program.empty()) {
381 auto errorOrInputFile =
382 llvm::MemoryBuffer::getFileOrSTDIN(InputFilename.getValue());
alan-bakerfec0a472018-11-08 18:09:40 -0500383
alan-bakerf5e5f692018-11-27 08:33:24 -0500384 // If there was an error in getting the input file.
385 if (!errorOrInputFile) {
386 llvm::errs() << "Error: " << errorOrInputFile.getError().message() << " '"
387 << InputFilename.getValue() << "'\n";
388 return -1;
389 }
390 memory_buffer.reset(errorOrInputFile.get().release());
391 } else {
392 memory_buffer = llvm::MemoryBuffer::getMemBuffer(program.c_str(),
393 overiddenInputFilename);
alan-bakerfec0a472018-11-08 18:09:40 -0500394 }
alan-bakerf5e5f692018-11-27 08:33:24 -0500395
alan-bakerfec0a472018-11-08 18:09:40 -0500396 if (verify) {
397 instance.getDiagnosticOpts().VerifyDiagnostics = true;
alan-bakerbccf62c2019-03-29 10:32:41 -0400398 instance.getDiagnosticOpts().VerifyPrefixes.push_back("expected");
alan-bakerfec0a472018-11-08 18:09:40 -0500399 }
400
Kévin Petit0fc88042019-04-09 23:25:02 +0100401 clang::LangStandard::Kind standard;
402 if (clspv::Option::CPlusPlus()) {
403 standard = clang::LangStandard::lang_openclcpp;
404 } else {
405 standard = clang::LangStandard::lang_opencl12;
406 }
alan-bakerfec0a472018-11-08 18:09:40 -0500407
408 // We are targeting OpenCL 1.2 only
409 instance.getLangOpts().OpenCLVersion = 120;
410
411 instance.getLangOpts().C99 = true;
412 instance.getLangOpts().RTTI = false;
413 instance.getLangOpts().RTTIData = false;
414 instance.getLangOpts().MathErrno = false;
415 instance.getLangOpts().Optimize = false;
416 instance.getLangOpts().NoBuiltin = true;
417 instance.getLangOpts().ModulesSearchAll = false;
418 instance.getLangOpts().SinglePrecisionConstants = true;
419 instance.getCodeGenOpts().StackRealignment = true;
420 instance.getCodeGenOpts().SimplifyLibCalls = false;
421 instance.getCodeGenOpts().EmitOpenCLArgMetadata = false;
422 instance.getCodeGenOpts().DisableO0ImplyOptNone = true;
Kévin Petit6b07cbe2019-04-02 21:52:16 +0100423 instance.getDiagnosticOpts().IgnoreWarnings = IgnoreWarnings;
alan-bakerfec0a472018-11-08 18:09:40 -0500424
425 instance.getLangOpts().SinglePrecisionConstants =
426 cl_single_precision_constants;
427 // cl_denorms_are_zero ignored for now!
428 // cl_fp32_correctly_rounded_divide_sqrt ignored for now!
429 instance.getCodeGenOpts().LessPreciseFPMAD =
430 cl_mad_enable || cl_unsafe_math_optimizations;
431 // cl_no_signed_zeros ignored for now!
432 instance.getCodeGenOpts().UnsafeFPMath =
433 cl_unsafe_math_optimizations || cl_fast_relaxed_math;
434 instance.getLangOpts().FiniteMathOnly =
435 cl_finite_math_only || cl_fast_relaxed_math;
436 instance.getLangOpts().FastRelaxedMath = cl_fast_relaxed_math;
437
438 // Preprocessor options
Kévin Petita624c0c2019-05-07 20:27:43 +0800439 if (!clspv::Option::ImageSupport()) {
440 instance.getPreprocessorOpts().addMacroUndef("__IMAGE_SUPPORT__");
441 }
alan-bakerfec0a472018-11-08 18:09:40 -0500442 if (cl_fast_relaxed_math) {
443 instance.getPreprocessorOpts().addMacroDef("__FAST_RELAXED_MATH__");
444 }
445
446 for (auto define : Defines) {
447 instance.getPreprocessorOpts().addMacroDef(define);
448 }
449
450 // Header search options
451 for (auto include : Includes) {
452 instance.getHeaderSearchOpts().AddPath(include, clang::frontend::After,
453 false, false);
454 }
455
456 // We always compile on opt 0 so we preserve as much debug information about
457 // the source as possible. We'll run optimization later, once we've had a
458 // chance to view the unoptimal code first
459 instance.getCodeGenOpts().OptimizationLevel = 0;
460
461// Debug information is disabled temporarily to call instruction.
462#if 0
463 instance.getCodeGenOpts().setDebugInfo(clang::codegenoptions::FullDebugInfo);
464#endif
465
466 // We use the 32-bit pointer-width SPIR triple
467 llvm::Triple triple("spir-unknown-unknown");
468
469 instance.getInvocation().setLangDefaults(
alan-bakerd354f1a2019-08-06 15:41:55 -0400470 instance.getLangOpts(), clang::InputKind(clang::Language::OpenCL), triple,
alan-bakerfec0a472018-11-08 18:09:40 -0500471 instance.getPreprocessorOpts(), standard);
472
473 // Override the C99 inline semantics to accommodate for more OpenCL C
474 // programs in the wild.
475 instance.getLangOpts().GNUInline = true;
Kévin Petit6b07cbe2019-04-02 21:52:16 +0100476
477 // Set up diagnostics
alan-bakerfec0a472018-11-08 18:09:40 -0500478 instance.createDiagnostics(
479 new clang::TextDiagnosticPrinter(*diagnosticsStream,
480 &instance.getDiagnosticOpts()),
481 true);
Kévin Petit6b07cbe2019-04-02 21:52:16 +0100482 instance.getDiagnostics().setWarningsAsErrors(WarningsAsErrors);
483 instance.getDiagnostics().setEnableAllWarnings(true);
alan-bakerfec0a472018-11-08 18:09:40 -0500484
485 instance.getTargetOpts().Triple = triple.str();
486
487 instance.getCodeGenOpts().MainFileName = overiddenInputFilename;
488 instance.getCodeGenOpts().PreserveVec3Type = true;
489 // Disable generation of lifetime intrinsic.
490 instance.getCodeGenOpts().DisableLifetimeMarkers = true;
491 instance.getFrontendOpts().Inputs.push_back(kernelFile);
alan-bakerf5e5f692018-11-27 08:33:24 -0500492 instance.getPreprocessorOpts().addRemappedFile(overiddenInputFilename,
493 memory_buffer.release());
alan-bakerfec0a472018-11-08 18:09:40 -0500494
495 struct OpenCLBuiltinMemoryBuffer final : public llvm::MemoryBuffer {
496 OpenCLBuiltinMemoryBuffer(const void *data, uint64_t data_length) {
497 const char *dataCasted = reinterpret_cast<const char *>(data);
498 init(dataCasted, dataCasted + data_length, true);
499 }
500
501 virtual llvm::MemoryBuffer::BufferKind getBufferKind() const override {
502 return llvm::MemoryBuffer::MemoryBuffer_Malloc;
503 }
504
505 virtual ~OpenCLBuiltinMemoryBuffer() override {}
506 };
507
508 std::unique_ptr<llvm::MemoryBuffer> openCLBuiltinMemoryBuffer(
509 new OpenCLBuiltinMemoryBuffer(opencl_builtins_header_data,
510 opencl_builtins_header_size - 1));
511
512 instance.getPreprocessorOpts().Includes.push_back("openclc.h");
513
alan-bakerf3bce4a2019-06-28 16:01:15 -0400514 std::unique_ptr<llvm::MemoryBuffer> openCLBaseBuiltinMemoryBuffer(
515 new OpenCLBuiltinMemoryBuffer(opencl_base_builtins_header_data,
516 opencl_base_builtins_header_size - 1));
517
518 instance.getPreprocessorOpts().Includes.push_back("opencl-c-base.h");
519
alan-bakerfec0a472018-11-08 18:09:40 -0500520 // Add the VULKAN macro.
521 instance.getPreprocessorOpts().addMacroDef("VULKAN=100");
522
523 // Add the __OPENCL_VERSION__ macro.
524 instance.getPreprocessorOpts().addMacroDef("__OPENCL_VERSION__=120");
525
526 instance.setTarget(clang::TargetInfo::CreateTargetInfo(
527 instance.getDiagnostics(),
528 std::make_shared<clang::TargetOptions>(instance.getTargetOpts())));
529
530 instance.createFileManager();
531 instance.createSourceManager(instance.getFileManager());
532
533#ifdef _MSC_VER
534 std::string includePrefix("include\\");
535#else
536 std::string includePrefix("include/");
537#endif
538
539 auto entry = instance.getFileManager().getVirtualFile(
540 includePrefix + "openclc.h", openCLBuiltinMemoryBuffer->getBufferSize(),
541 0);
542
543 instance.getSourceManager().overrideFileContents(
544 entry, std::move(openCLBuiltinMemoryBuffer));
545
alan-bakerf3bce4a2019-06-28 16:01:15 -0400546 auto base_entry = instance.getFileManager().getVirtualFile(
547 includePrefix + "opencl-c-base.h",
548 openCLBaseBuiltinMemoryBuffer->getBufferSize(), 0);
549
550 instance.getSourceManager().overrideFileContents(
551 base_entry, std::move(openCLBaseBuiltinMemoryBuffer));
552
alan-bakerfec0a472018-11-08 18:09:40 -0500553 return 0;
554}
555
alan-bakerf5e5f692018-11-27 08:33:24 -0500556// Populates |pm| with necessary passes to optimize and legalize the IR.
557int PopulatePassManager(
558 llvm::legacy::PassManager *pm, llvm::raw_svector_ostream *binaryStream,
559 std::vector<clspv::version0::DescriptorMapEntry> *descriptor_map_entries,
560 llvm::SmallVectorImpl<std::pair<unsigned, std::string>>
561 *SamplerMapEntries) {
alan-bakerfec0a472018-11-08 18:09:40 -0500562 llvm::PassManagerBuilder pmBuilder;
563
564 switch (OptimizationLevel) {
565 case '0':
alan-bakerf5e5f692018-11-27 08:33:24 -0500566 case '1':
567 case '2':
568 case '3':
569 case 's':
570 case 'z':
571 break;
572 default:
573 llvm::errs() << "Unknown optimization level -O" << OptimizationLevel
574 << " specified!\n";
575 return -1;
576 }
577
578 switch (OptimizationLevel) {
579 case '0':
alan-bakerfec0a472018-11-08 18:09:40 -0500580 pmBuilder.OptLevel = 0;
581 break;
582 case '1':
583 pmBuilder.OptLevel = 1;
584 break;
585 case '2':
586 pmBuilder.OptLevel = 2;
587 break;
588 case '3':
589 pmBuilder.OptLevel = 3;
590 break;
591 case 's':
592 pmBuilder.SizeLevel = 1;
593 break;
594 case 'z':
595 pmBuilder.SizeLevel = 2;
596 break;
597 default:
598 break;
599 }
600
601 pm->add(clspv::createZeroInitializeAllocasPass());
602 pm->add(clspv::createDefineOpenCLWorkItemBuiltinsPass());
603
604 if (0 < pmBuilder.OptLevel) {
605 pm->add(clspv::createOpenCLInlinerPass());
606 }
607
608 pm->add(clspv::createUndoByvalPass());
609 pm->add(clspv::createUndoSRetPass());
610 if (cluster_non_pointer_kernel_args) {
611 pm->add(clspv::createClusterPodKernelArgumentsPass());
612 }
613 pm->add(clspv::createReplaceOpenCLBuiltinPass());
614
615 // We need to run mem2reg and inst combine early because our
616 // createInlineFuncWithPointerBitCastArgPass pass cannot handle the pattern
617 // %1 = alloca i32 1
618 // store <something> %1
619 // %2 = bitcast float* %1
620 // %3 = load float %2
621 pm->add(llvm::createPromoteMemoryToRegisterPass());
622
alan-baker1b13e8f2019-08-08 17:56:51 -0400623 // Try to deal with pointer bitcasts early. This can prevent problems like
624 // issue #409 where LLVM is looser about access chain addressing than SPIR-V.
625 // This needs to happen before instcombine and after replacing OpenCL
626 // builtins. This run of the pass will not handle all pointer bitcasts that
627 // could be handled. It should be run again after other optimizations (e.g
628 // InlineFuncWithPointerBitCastArgPass).
629 pm->add(clspv::createSimplifyPointerBitcastPass());
630 pm->add(clspv::createReplacePointerBitcastPass());
631 pm->add(llvm::createDeadCodeEliminationPass());
632
alan-bakerfec0a472018-11-08 18:09:40 -0500633 // Hide loads from __constant address space away from instcombine.
634 // This prevents us from generating select between pointers-to-__constant.
635 // See https://github.com/google/clspv/issues/71
636 pm->add(clspv::createHideConstantLoadsPass());
637
638 pm->add(llvm::createInstructionCombiningPass());
639
640 if (clspv::Option::InlineEntryPoints()) {
641 pm->add(clspv::createInlineEntryPointsPass());
642 } else {
643 pm->add(clspv::createInlineFuncWithPointerBitCastArgPass());
644 pm->add(clspv::createInlineFuncWithPointerToFunctionArgPass());
645 pm->add(clspv::createInlineFuncWithSingleCallSitePass());
646 }
647
Kévin Petit0fc88042019-04-09 23:25:02 +0100648 if (clspv::Option::CPlusPlus()) {
Kévin Petit38c52482019-05-07 20:28:00 +0800649 pm->add(llvm::createInferAddressSpacesPass(clspv::AddressSpace::Generic));
Kévin Petit0fc88042019-04-09 23:25:02 +0100650 }
651
alan-bakerfec0a472018-11-08 18:09:40 -0500652 if (0 == pmBuilder.OptLevel) {
653 // Mem2Reg pass should be run early because O0 level optimization leaves
654 // redundant alloca, load and store instructions from function arguments.
655 // clspv needs to remove them ahead of transformation.
656 pm->add(llvm::createPromoteMemoryToRegisterPass());
657
658 // SROA pass is run because it will fold structs/unions that are problematic
659 // on Vulkan SPIR-V away.
660 pm->add(llvm::createSROAPass());
661
662 // InstructionCombining pass folds bitcast and gep instructions which are
663 // not supported by Vulkan SPIR-V.
664 pm->add(llvm::createInstructionCombiningPass());
665 }
666
667 // Now we add any of the LLVM optimizations we wanted
668 pmBuilder.populateModulePassManager(*pm);
669
670 // Unhide loads from __constant address space. Undoes the action of
671 // HideConstantLoadsPass.
672 pm->add(clspv::createUnhideConstantLoadsPass());
673
674 pm->add(clspv::createFunctionInternalizerPass());
675 pm->add(clspv::createReplaceLLVMIntrinsicsPass());
676 pm->add(clspv::createUndoBoolPass());
677 pm->add(clspv::createUndoTruncatedSwitchConditionPass());
678 pm->add(llvm::createStructurizeCFGPass(false));
alan-baker3fa76d92018-11-12 14:54:40 -0500679 // Must be run after structurize cfg.
alan-bakerfec0a472018-11-08 18:09:40 -0500680 pm->add(clspv::createReorderBasicBlocksPass());
681 pm->add(clspv::createUndoGetElementPtrConstantExprPass());
682 pm->add(clspv::createSplatArgPass());
683 pm->add(clspv::createSimplifyPointerBitcastPass());
684 pm->add(clspv::createReplacePointerBitcastPass());
685
686 pm->add(clspv::createUndoTranslateSamplerFoldPass());
687
688 if (clspv::Option::ModuleConstantsInStorageBuffer()) {
689 pm->add(clspv::createClusterModuleScopeConstantVars());
690 }
691
692 pm->add(clspv::createShareModuleScopeVariablesPass());
alan-bakere9308012019-03-15 10:25:13 -0400693 // This should be run after LLVM and OpenCL intrinsics are replaced.
alan-bakerfec0a472018-11-08 18:09:40 -0500694 pm->add(clspv::createAllocateDescriptorsPass(*SamplerMapEntries));
695 pm->add(llvm::createVerifierPass());
696 pm->add(clspv::createDirectResourceAccessPass());
697 // Replacing pointer bitcasts can leave some trivial GEPs
698 // that are easy to remove. Also replace GEPs of GEPS
699 // left by replacing indirect buffer accesses.
700 pm->add(clspv::createSimplifyPointerBitcastPass());
alan-baker4217b322019-03-06 08:56:12 -0500701 // Run after DRA to clean up parameters and help reduce the need for variable
702 // pointers.
703 pm->add(clspv::createRemoveUnusedArgumentsPass());
alan-bakerfec0a472018-11-08 18:09:40 -0500704
705 pm->add(clspv::createSplatSelectConditionPass());
706 pm->add(clspv::createSignedCompareFixupPass());
707 // This pass generates insertions that need to be rewritten.
708 pm->add(clspv::createScalarizePass());
709 pm->add(clspv::createRewriteInsertsPass());
alan-bakera71f1932019-04-11 11:04:34 -0400710 // UBO Transformations
711 if (clspv::Option::ConstantArgsInUniformBuffer() &&
712 !clspv::Option::InlineEntryPoints()) {
713 // MultiVersionUBOFunctionsPass will examine non-kernel functions with UBO
714 // arguments and either multi-version them as necessary or inline them if
715 // multi-versioning cannot be accomplished.
716 pm->add(clspv::createMultiVersionUBOFunctionsPass());
717 // Cleanup passes.
718 // Specialization can blindly generate GEP chains that are easily cleaned up
719 // by SimplifyPointerBitcastPass.
720 pm->add(clspv::createSimplifyPointerBitcastPass());
721 // RemoveUnusedArgumentsPass removes the actual UBO arguments that were
722 // problematic to begin with now that they have no uses.
723 pm->add(clspv::createRemoveUnusedArgumentsPass());
724 // DCE cleans up callers of the specialized functions.
725 pm->add(llvm::createDeadCodeEliminationPass());
726 }
alan-bakerfec0a472018-11-08 18:09:40 -0500727 // This pass mucks with types to point where you shouldn't rely on DataLayout
728 // anymore so leave this right before SPIR-V generation.
729 pm->add(clspv::createUBOTypeTransformPass());
alan-baker00e7a582019-06-07 12:54:21 -0400730 pm->add(clspv::createSPIRVProducerPass(*binaryStream, descriptor_map_entries,
731 *SamplerMapEntries,
732 OutputFormat == "c"));
alan-bakerf5e5f692018-11-27 08:33:24 -0500733
734 return 0;
alan-bakerfec0a472018-11-08 18:09:40 -0500735}
alan-bakerfec0a472018-11-08 18:09:40 -0500736
Kévin Petitd5db2d22019-04-04 13:55:14 +0100737int ParseOptions(const int argc, const char *const argv[]) {
alan-bakerfec0a472018-11-08 18:09:40 -0500738 // We need to change how one of the called passes works by spoofing
739 // ParseCommandLineOptions with the specific option.
740 const int llvmArgc = 2;
741 const char *llvmArgv[llvmArgc] = {
alan-bakerf5e5f692018-11-27 08:33:24 -0500742 argv[0],
743 "-simplifycfg-sink-common=false",
alan-bakerfec0a472018-11-08 18:09:40 -0500744 };
745
Kévin Petitd5db2d22019-04-04 13:55:14 +0100746 llvm::cl::ResetAllOptionOccurrences();
alan-bakerfec0a472018-11-08 18:09:40 -0500747 llvm::cl::ParseCommandLineOptions(llvmArgc, llvmArgv);
alan-bakerfec0a472018-11-08 18:09:40 -0500748 llvm::cl::ParseCommandLineOptions(argc, argv);
749
Diego Novillo3cc8d7a2019-04-10 13:30:34 -0400750 if (clspv::Option::CPlusPlus() && !clspv::Option::InlineEntryPoints()) {
Kévin Petit0fc88042019-04-09 23:25:02 +0100751 llvm::errs() << "cannot use -c++ without -inline-entry-points\n";
752 return -1;
753 }
754
Kévin Petitd5db2d22019-04-04 13:55:14 +0100755 return 0;
756}
Diego Novillo89500852019-04-15 08:45:10 -0400757
758int GenerateIRFile(llvm::legacy::PassManager *pm, llvm::Module &module,
759 std::string output) {
760 std::error_code ec;
761 std::unique_ptr<llvm::ToolOutputFile> out(
762 new llvm::ToolOutputFile(output, ec, llvm::sys::fs::F_None));
763 if (ec) {
764 llvm::errs() << output << ": " << ec.message() << '\n';
765 return -1;
766 }
767 pm->add(llvm::createPrintModulePass(out->os(), "", false));
768 pm->run(module);
769 out->keep();
770 return 0;
771}
772
Kévin Petitd5db2d22019-04-04 13:55:14 +0100773} // namespace
774
775namespace clspv {
776int Compile(const int argc, const char *const argv[]) {
777
778 if (auto error = ParseOptions(argc, argv))
779 return error;
780
alan-bakerfec0a472018-11-08 18:09:40 -0500781 llvm::SmallVector<std::pair<unsigned, std::string>, 8> SamplerMapEntries;
alan-bakerf5e5f692018-11-27 08:33:24 -0500782 if (auto error = ParseSamplerMap("", &SamplerMapEntries))
alan-bakerfec0a472018-11-08 18:09:40 -0500783 return error;
784
785 // if no output file was provided, use a default
786 llvm::StringRef overiddenInputFilename = InputFilename.getValue();
787
788 // If we are reading our input file from stdin.
789 if ("-" == InputFilename) {
790 // We need to overwrite the file name we use.
Kévin Petitddad8f42019-09-30 15:12:08 +0100791 switch (InputLanguage) {
792 case clang::Language::OpenCL:
793 overiddenInputFilename = "stdin.cl";
794 break;
795 case clang::Language::LLVM_IR:
796 overiddenInputFilename = "stdin.ll";
797 break;
alan-baker31298a62019-10-07 13:24:30 -0400798 default:
799 // Default to fix compiler warnings/errors. Option parsing will reject a
800 // bad enum value for the option so there is no need for a message.
801 return -1;
Kévin Petitddad8f42019-09-30 15:12:08 +0100802 }
alan-bakerfec0a472018-11-08 18:09:40 -0500803 }
804
805 clang::CompilerInstance instance;
Kévin Petitddad8f42019-09-30 15:12:08 +0100806 clang::FrontendInputFile kernelFile(overiddenInputFilename,
807 clang::InputKind(InputLanguage));
alan-bakerfec0a472018-11-08 18:09:40 -0500808 std::string log;
809 llvm::raw_string_ostream diagnosticsStream(log);
alan-bakerf5e5f692018-11-27 08:33:24 -0500810 if (auto error = SetCompilerInstanceOptions(
811 instance, overiddenInputFilename, kernelFile, "", &diagnosticsStream))
alan-bakerfec0a472018-11-08 18:09:40 -0500812 return error;
813
814 // Parse.
815 llvm::LLVMContext context;
816 clang::EmitLLVMOnlyAction action(&context);
817
818 // Prepare the action for processing kernelFile
819 const bool success = action.BeginSourceFile(instance, kernelFile);
820 if (!success) {
821 return -1;
822 }
823
alan-bakerf3bce4a2019-06-28 16:01:15 -0400824 auto result = action.Execute();
alan-bakerfec0a472018-11-08 18:09:40 -0500825 action.EndSourceFile();
826
827 clang::DiagnosticConsumer *const consumer =
828 instance.getDiagnostics().getClient();
829 consumer->finish();
830
Kévin Petit6b07cbe2019-04-02 21:52:16 +0100831 auto num_warnings = consumer->getNumWarnings();
alan-bakerfec0a472018-11-08 18:09:40 -0500832 auto num_errors = consumer->getNumErrors();
Kévin Petit6b07cbe2019-04-02 21:52:16 +0100833 if ((num_errors > 0) || (num_warnings > 0)) {
834 llvm::errs() << log;
835 }
alan-bakerf3bce4a2019-06-28 16:01:15 -0400836 if (result || num_errors > 0) {
alan-bakerfec0a472018-11-08 18:09:40 -0500837 return -1;
838 }
839
Kévin Petit6b07cbe2019-04-02 21:52:16 +0100840 // Don't run the passes or produce any output in verify mode.
841 // Clang doesn't always produce a valid module.
842 if (verify) {
843 return 0;
844 }
845
alan-bakerfec0a472018-11-08 18:09:40 -0500846 llvm::PassRegistry &Registry = *llvm::PassRegistry::getPassRegistry();
847 llvm::initializeCore(Registry);
848 llvm::initializeScalarOpts(Registry);
Diego Novillo1fcff722019-05-07 13:45:53 -0400849 llvm::initializeClspvPasses(Registry);
alan-bakerfec0a472018-11-08 18:09:40 -0500850
851 std::unique_ptr<llvm::Module> module(action.takeModule());
852
853 // Optimize.
854 // Create a memory buffer for temporarily writing the result.
855 SmallVector<char, 10000> binary;
856 llvm::raw_svector_ostream binaryStream(binary);
857 std::string descriptor_map;
alan-bakerfec0a472018-11-08 18:09:40 -0500858 llvm::legacy::PassManager pm;
alan-bakerf5e5f692018-11-27 08:33:24 -0500859 std::vector<version0::DescriptorMapEntry> descriptor_map_entries;
Diego Novillo89500852019-04-15 08:45:10 -0400860
861 // If --emit-ir was requested, emit the initial LLVM IR and stop compilation.
862 if (!IROutputFile.empty()) {
863 return GenerateIRFile(&pm, *module, IROutputFile);
864 }
865
866 // Otherwise, populate the pass manager and run the regular passes.
Diego Novillo3cc8d7a2019-04-10 13:30:34 -0400867 if (auto error = PopulatePassManager(
868 &pm, &binaryStream, &descriptor_map_entries, &SamplerMapEntries))
alan-bakerf5e5f692018-11-27 08:33:24 -0500869 return error;
alan-bakerfec0a472018-11-08 18:09:40 -0500870 pm.run(*module);
871
872 // Write outputs
873
874 // Write the descriptor map, if requested.
875 std::error_code error;
876 if (!DescriptorMapFilename.empty()) {
Diego Novillo3cc8d7a2019-04-10 13:30:34 -0400877 llvm::raw_fd_ostream descriptor_map_out_fd(
878 DescriptorMapFilename, error, llvm::sys::fs::CD_CreateAlways,
879 llvm::sys::fs::FA_Write, llvm::sys::fs::F_Text);
alan-bakerfec0a472018-11-08 18:09:40 -0500880 if (error) {
881 llvm::errs() << "Unable to open descriptor map file '"
882 << DescriptorMapFilename << "': " << error.message() << '\n';
883 return -1;
884 }
alan-bakerf5e5f692018-11-27 08:33:24 -0500885 std::string descriptor_map_string;
886 std::ostringstream str(descriptor_map_string);
887 for (const auto &entry : descriptor_map_entries) {
888 str << entry << "\n";
889 }
890 descriptor_map_out_fd << str.str();
alan-bakerfec0a472018-11-08 18:09:40 -0500891 descriptor_map_out_fd.close();
892 }
893
894 // Write the resulting binary.
895 // Wait until now to try writing the file so that we only write it on
896 // successful compilation.
897 if (OutputFilename.empty()) {
Kévin Petite4786902019-04-02 21:51:47 +0100898 if (OutputFormat == "c") {
alan-bakerfec0a472018-11-08 18:09:40 -0500899 OutputFilename = "a.spvinc";
900 } else {
901 OutputFilename = "a.spv";
902 }
903 }
Diego Novillo3cc8d7a2019-04-10 13:30:34 -0400904 llvm::raw_fd_ostream outStream(OutputFilename, error,
905 llvm::sys::fs::FA_Write);
alan-bakerfec0a472018-11-08 18:09:40 -0500906
907 if (error) {
908 llvm::errs() << "Unable to open output file '" << OutputFilename
909 << "': " << error.message() << '\n';
910 return -1;
911 }
912 outStream << binaryStream.str();
913
914 return 0;
915}
alan-bakerf5e5f692018-11-27 08:33:24 -0500916
Diego Novillo3cc8d7a2019-04-10 13:30:34 -0400917int CompileFromSourceString(
918 const std::string &program, const std::string &sampler_map,
919 const std::string &options, std::vector<uint32_t> *output_binary,
920 std::vector<clspv::version0::DescriptorMapEntry> *descriptor_map_entries) {
alan-bakerf5e5f692018-11-27 08:33:24 -0500921
922 llvm::SmallVector<const char *, 20> argv;
923 llvm::BumpPtrAllocator A;
924 llvm::StringSaver Saver(A);
925 argv.push_back(Saver.save("clspv").data());
926 llvm::cl::TokenizeGNUCommandLine(options, Saver, argv);
927 int argc = static_cast<int>(argv.size());
Kévin Petitd5db2d22019-04-04 13:55:14 +0100928
929 if (auto error = ParseOptions(argc, &argv[0]))
930 return error;
alan-bakerf5e5f692018-11-27 08:33:24 -0500931
932 llvm::SmallVector<std::pair<unsigned, std::string>, 8> SamplerMapEntries;
933 if (auto error = ParseSamplerMap(sampler_map, &SamplerMapEntries))
934 return error;
935
936 InputFilename = "source.cl";
937 llvm::StringRef overiddenInputFilename = InputFilename.getValue();
938
939 clang::CompilerInstance instance;
alan-bakerd354f1a2019-08-06 15:41:55 -0400940 clang::FrontendInputFile kernelFile(
941 overiddenInputFilename, clang::InputKind(clang::Language::OpenCL));
alan-bakerf5e5f692018-11-27 08:33:24 -0500942 std::string log;
943 llvm::raw_string_ostream diagnosticsStream(log);
944 if (auto error =
945 SetCompilerInstanceOptions(instance, overiddenInputFilename,
946 kernelFile, program, &diagnosticsStream))
947 return error;
948
949 // Parse.
950 llvm::LLVMContext context;
951 clang::EmitLLVMOnlyAction action(&context);
952
953 // Prepare the action for processing kernelFile
954 const bool success = action.BeginSourceFile(instance, kernelFile);
955 if (!success) {
956 return -1;
957 }
958
alan-bakerf3bce4a2019-06-28 16:01:15 -0400959 auto result = action.Execute();
alan-bakerf5e5f692018-11-27 08:33:24 -0500960 action.EndSourceFile();
961
962 clang::DiagnosticConsumer *const consumer =
963 instance.getDiagnostics().getClient();
964 consumer->finish();
965
966 auto num_errors = consumer->getNumErrors();
alan-bakerf3bce4a2019-06-28 16:01:15 -0400967 if (result || num_errors > 0) {
alan-bakerf5e5f692018-11-27 08:33:24 -0500968 llvm::errs() << log << "\n";
969 return -1;
970 }
971
alan-bakerf5e5f692018-11-27 08:33:24 -0500972 llvm::PassRegistry &Registry = *llvm::PassRegistry::getPassRegistry();
973 llvm::initializeCore(Registry);
974 llvm::initializeScalarOpts(Registry);
Diego Novillo1fcff722019-05-07 13:45:53 -0400975 llvm::initializeClspvPasses(Registry);
alan-bakerf5e5f692018-11-27 08:33:24 -0500976
977 std::unique_ptr<llvm::Module> module(action.takeModule());
978
979 // Optimize.
980 // Create a memory buffer for temporarily writing the result.
981 SmallVector<char, 10000> binary;
982 llvm::raw_svector_ostream binaryStream(binary);
983 std::string descriptor_map;
984 llvm::legacy::PassManager pm;
Diego Novillo3cc8d7a2019-04-10 13:30:34 -0400985 if (auto error = PopulatePassManager(
986 &pm, &binaryStream, descriptor_map_entries, &SamplerMapEntries))
alan-bakerf5e5f692018-11-27 08:33:24 -0500987 return error;
988 pm.run(*module);
989
990 // Write outputs
991
992 // Write the descriptor map. This is required.
Diego Novillo3cc8d7a2019-04-10 13:30:34 -0400993 assert(descriptor_map_entries &&
994 "Valid descriptor map container is required.");
alan-bakerf5e5f692018-11-27 08:33:24 -0500995 if (!DescriptorMapFilename.empty()) {
Diego Novillo3cc8d7a2019-04-10 13:30:34 -0400996 llvm::errs() << "Warning: -descriptormap is ignored descriptor map "
997 "container is provided.\n";
alan-bakerf5e5f692018-11-27 08:33:24 -0500998 }
999
1000 // Write the resulting binary.
1001 // Wait until now to try writing the file so that we only write it on
1002 // successful compilation.
1003 assert(output_binary && "Valid binary container is required.");
1004 if (!OutputFilename.empty()) {
1005 llvm::outs()
1006 << "Warning: -o is ignored when binary container is provided.\n";
1007 }
1008 output_binary->resize(binary.size() / 4);
1009 memcpy(output_binary->data(), binary.data(), binary.size());
1010
1011 return 0;
1012}
alan-bakerfec0a472018-11-08 18:09:40 -05001013} // namespace clspv