blob: 63919f5733a8e9308340d4d97ac170dd5ab34e9e [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"
alan-baker0e64a592019-11-18 13:36:25 -050025#include "llvm/InitializePasses.h"
alan-bakerfec0a472018-11-08 18:09:40 -050026#include "llvm/LinkAllPasses.h"
alan-bakerf5e5f692018-11-27 08:33:24 -050027#include "llvm/Support/Allocator.h"
alan-bakerfec0a472018-11-08 18:09:40 -050028#include "llvm/Support/CommandLine.h"
alan-bakerf5e5f692018-11-27 08:33:24 -050029#include "llvm/Support/ErrorOr.h"
alan-bakerfec0a472018-11-08 18:09:40 -050030#include "llvm/Support/MathExtras.h"
alan-bakerf5e5f692018-11-27 08:33:24 -050031#include "llvm/Support/StringSaver.h"
Diego Novillo89500852019-04-15 08:45:10 -040032#include "llvm/Support/ToolOutputFile.h"
alan-bakerfec0a472018-11-08 18:09:40 -050033#include "llvm/Support/raw_ostream.h"
34#include "llvm/Transforms/IPO/PassManagerBuilder.h"
35
Kévin Petit38c52482019-05-07 20:28:00 +080036#include "clspv/AddressSpace.h"
alan-bakerf5e5f692018-11-27 08:33:24 -050037#include "clspv/DescriptorMap.h"
alan-bakerfec0a472018-11-08 18:09:40 -050038#include "clspv/Option.h"
39#include "clspv/Passes.h"
40#include "clspv/opencl_builtins_header.h"
41
42#include "FrontendPlugin.h"
Diego Novilloa4c44fa2019-04-11 10:56:15 -040043#include "Passes.h"
alan-bakerfec0a472018-11-08 18:09:40 -050044
alan-bakerf5e5f692018-11-27 08:33:24 -050045#include <cassert>
alan-bakerfec0a472018-11-08 18:09:40 -050046#include <numeric>
alan-bakerf5e5f692018-11-27 08:33:24 -050047#include <sstream>
Diego Novillo3cc8d7a2019-04-10 13:30:34 -040048#include <string>
alan-bakerfec0a472018-11-08 18:09:40 -050049
50using namespace clang;
51
52namespace {
53// This registration must be located in the same file as the execution of the
54// action.
55static FrontendPluginRegistry::Add<clspv::ExtraValidationASTAction>
56 X("extra-validation",
57 "Perform extra validation on OpenCL C when targeting Vulkan");
58
59static llvm::cl::opt<bool> cl_single_precision_constants(
60 "cl-single-precision-constant", llvm::cl::init(false),
61 llvm::cl::desc("Treat double precision floating-point constant as single "
62 "precision constant."));
63
64static llvm::cl::opt<bool> cl_denorms_are_zero(
65 "cl-denorms-are-zero", llvm::cl::init(false),
66 llvm::cl::desc("If specified, denormalized floating point numbers may be "
67 "flushed to zero."));
68
69static llvm::cl::opt<bool> cl_fp32_correctly_rounded_divide_sqrt(
70 "cl-fp32-correctly-rounded-divide-sqrt", llvm::cl::init(false),
71 llvm::cl::desc("Single precision floating-point divide (x/y and 1/x) and "
72 "sqrt used are correctly rounded."));
73
74static llvm::cl::opt<bool>
75 cl_opt_disable("cl-opt-disable", llvm::cl::init(false),
76 llvm::cl::desc("This option disables all optimizations. The "
77 "default is optimizations are enabled."));
78
79static llvm::cl::opt<bool> cl_mad_enable(
80 "cl-mad-enable", llvm::cl::init(false),
81 llvm::cl::desc("Allow a * b + c to be replaced by a mad. The mad computes "
82 "a * b + c with reduced accuracy."));
83
84static llvm::cl::opt<bool> cl_no_signed_zeros(
85 "cl-no-signed-zeros", llvm::cl::init(false),
86 llvm::cl::desc("Allow optimizations for floating-point arithmetic that "
87 "ignore the signedness of zero."));
88
89static llvm::cl::opt<bool> cl_unsafe_math_optimizations(
90 "cl-unsafe-math-optimizations", llvm::cl::init(false),
91 llvm::cl::desc("Allow optimizations for floating-point arithmetic that (a) "
92 "assume that arguments and results are valid, (b) may "
93 "violate IEEE 754 standard and (c) may violate the OpenCL "
94 "numerical compliance requirements. This option includes "
95 "the -cl-no-signed-zeros and -cl-mad-enable options."));
96
97static llvm::cl::opt<bool> cl_finite_math_only(
98 "cl-finite-math-only", llvm::cl::init(false),
99 llvm::cl::desc("Allow optimizations for floating-point arithmetic that "
100 "assume that arguments and results are not NaNs or INFs."));
101
102static llvm::cl::opt<bool> cl_fast_relaxed_math(
103 "cl-fast-relaxed-math", llvm::cl::init(false),
104 llvm::cl::desc("This option causes the preprocessor macro "
105 "__FAST_RELAXED_MATH__ to be defined. Sets the optimization "
106 "options -cl-finite-math-only and "
107 "-cl-unsafe-math-optimizations."));
108
109static llvm::cl::list<std::string>
110 Includes(llvm::cl::Prefix, "I",
111 llvm::cl::desc("Add a directory to the list of directories "
112 "to be searched for header files."),
113 llvm::cl::ZeroOrMore, llvm::cl::value_desc("include path"));
114
115static llvm::cl::list<std::string>
116 Defines(llvm::cl::Prefix, "D",
117 llvm::cl::desc("Define a #define directive."), llvm::cl::ZeroOrMore,
118 llvm::cl::value_desc("define"));
119
120static llvm::cl::opt<std::string>
121 InputFilename(llvm::cl::Positional, llvm::cl::desc("<input .cl file>"),
122 llvm::cl::init("-"));
123
Kévin Petitddad8f42019-09-30 15:12:08 +0100124static llvm::cl::opt<clang::Language> InputLanguage(
125 "x", llvm::cl::desc("Select input type"),
126 llvm::cl::init(clang::Language::OpenCL),
127 llvm::cl::values(clEnumValN(clang::Language::OpenCL, "cl", "OpenCL source"),
128 clEnumValN(clang::Language::LLVM_IR, "ir", "LLVM IR")));
129
alan-bakerfec0a472018-11-08 18:09:40 -0500130static llvm::cl::opt<std::string>
131 OutputFilename("o", llvm::cl::desc("Override output filename"),
132 llvm::cl::value_desc("filename"));
133
134static llvm::cl::opt<std::string>
135 DescriptorMapFilename("descriptormap",
136 llvm::cl::desc("Output file for descriptor map"),
137 llvm::cl::value_desc("filename"));
138
139static llvm::cl::opt<char>
140 OptimizationLevel(llvm::cl::Prefix, "O", llvm::cl::init('2'),
141 llvm::cl::desc("Optimization level to use"),
142 llvm::cl::value_desc("level"));
143
alan-bakerfec0a472018-11-08 18:09:40 -0500144static llvm::cl::opt<std::string> OutputFormat(
145 "mfmt", llvm::cl::init(""),
146 llvm::cl::desc(
147 "Specify special output format. 'c' is as a C initializer list"),
148 llvm::cl::value_desc("format"));
149
150static llvm::cl::opt<std::string>
alan-baker09cb9802019-12-10 13:16:27 -0500151 SamplerMap("samplermap", llvm::cl::desc("DEPRECATED - Literal sampler map"),
alan-bakerfec0a472018-11-08 18:09:40 -0500152 llvm::cl::value_desc("filename"));
153
154static llvm::cl::opt<bool> cluster_non_pointer_kernel_args(
155 "cluster-pod-kernel-args", llvm::cl::init(false),
156 llvm::cl::desc("Collect plain-old-data kernel arguments into a struct in "
157 "a single storage buffer, using a binding number after "
158 "other arguments. Use this to reduce storage buffer "
159 "descriptors."));
160
161static llvm::cl::opt<bool> verify("verify", llvm::cl::init(false),
162 llvm::cl::desc("Verify diagnostic outputs"));
163
Kévin Petit6b07cbe2019-04-02 21:52:16 +0100164static llvm::cl::opt<bool>
165 IgnoreWarnings("w", llvm::cl::init(false),
166 llvm::cl::desc("Disable all warnings"));
167
168static llvm::cl::opt<bool>
169 WarningsAsErrors("Werror", llvm::cl::init(false),
Diego Novillo3cc8d7a2019-04-10 13:30:34 -0400170 llvm::cl::desc("Turn warnings into errors"));
Kévin Petit6b07cbe2019-04-02 21:52:16 +0100171
Diego Novillo89500852019-04-15 08:45:10 -0400172static llvm::cl::opt<std::string> IROutputFile(
173 "emit-ir",
174 llvm::cl::desc(
175 "Emit LLVM IR to the given file after parsing and stop compilation."),
176 llvm::cl::value_desc("filename"));
177
alan-bakerfec0a472018-11-08 18:09:40 -0500178// Populates |SamplerMapEntries| with data from the input sampler map. Returns 0
179// if successful.
alan-bakerf5e5f692018-11-27 08:33:24 -0500180int ParseSamplerMap(const std::string &sampler_map,
181 llvm::SmallVectorImpl<std::pair<unsigned, std::string>>
182 *SamplerMapEntries) {
183 std::unique_ptr<llvm::MemoryBuffer> samplerMapBuffer(nullptr);
184 if (!sampler_map.empty()) {
185 // Parse the sampler map from the provided string.
186 samplerMapBuffer = llvm::MemoryBuffer::getMemBuffer(sampler_map);
187
alan-baker09cb9802019-12-10 13:16:27 -0500188 clspv::Option::SetUseSamplerMap(true);
alan-bakerf5e5f692018-11-27 08:33:24 -0500189 if (!SamplerMap.empty()) {
190 llvm::outs() << "Warning: -samplermap is ignored when the sampler map is "
191 "provided through a string.\n";
192 }
193 } else if (!SamplerMap.empty()) {
194 // Parse the sampler map from the option provided file.
alan-bakerfec0a472018-11-08 18:09:40 -0500195 auto errorOrSamplerMapFile =
196 llvm::MemoryBuffer::getFile(SamplerMap.getValue());
197
198 // If there was an error in getting the sampler map file.
199 if (!errorOrSamplerMapFile) {
200 llvm::errs() << "Error: " << errorOrSamplerMapFile.getError().message()
201 << " '" << SamplerMap.getValue() << "'\n";
202 return -1;
203 }
204
alan-baker09cb9802019-12-10 13:16:27 -0500205 clspv::Option::SetUseSamplerMap(true);
alan-bakerf5e5f692018-11-27 08:33:24 -0500206 samplerMapBuffer = std::move(errorOrSamplerMapFile.get());
alan-bakerfec0a472018-11-08 18:09:40 -0500207 if (0 == samplerMapBuffer->getBufferSize()) {
208 llvm::errs() << "Error: Sampler map was an empty file!\n";
209 return -1;
210 }
alan-bakerf5e5f692018-11-27 08:33:24 -0500211 }
alan-bakerfec0a472018-11-08 18:09:40 -0500212
alan-baker09cb9802019-12-10 13:16:27 -0500213 if (clspv::Option::UseSamplerMap()) {
214 llvm::outs()
215 << "Warning: use of the sampler map is deprecated and unnecessary\n";
216 }
217
alan-bakerf5e5f692018-11-27 08:33:24 -0500218 // No sampler map to parse.
219 if (!samplerMapBuffer || 0 == samplerMapBuffer->getBufferSize())
220 return 0;
alan-bakerfec0a472018-11-08 18:09:40 -0500221
alan-bakerf5e5f692018-11-27 08:33:24 -0500222 llvm::SmallVector<llvm::StringRef, 3> samplerStrings;
alan-bakerfec0a472018-11-08 18:09:40 -0500223
alan-bakerf5e5f692018-11-27 08:33:24 -0500224 // We need to keep track of the beginning of the current entry.
225 const char *b = samplerMapBuffer->getBufferStart();
226 for (const char *i = b, *e = samplerMapBuffer->getBufferEnd();; i++) {
227 // If we have a separator between declarations.
228 if ((*i == '|') || (*i == ',') || (i == e)) {
229 if (i == b) {
230 llvm::errs() << "Error: Sampler map contained an empty entry!\n";
231 return -1;
alan-bakerfec0a472018-11-08 18:09:40 -0500232 }
233
alan-bakerf5e5f692018-11-27 08:33:24 -0500234 samplerStrings.push_back(llvm::StringRef(b, i - b).trim());
alan-bakerfec0a472018-11-08 18:09:40 -0500235
alan-bakerf5e5f692018-11-27 08:33:24 -0500236 // And set b the next character after i.
237 b = i + 1;
238 }
alan-bakerfec0a472018-11-08 18:09:40 -0500239
alan-bakerf5e5f692018-11-27 08:33:24 -0500240 // If we have a separator between declarations within a single sampler.
241 if ((*i == ',') || (i == e)) {
alan-bakerfec0a472018-11-08 18:09:40 -0500242
James Pricec05f6052020-01-14 13:37:20 -0500243 clspv::version0::SamplerNormalizedCoords NormalizedCoord =
244 clspv::version0::CLK_NORMALIZED_COORDS_NOT_SET;
245 clspv::version0::SamplerAddressingMode AddressingMode =
246 clspv::version0::CLK_ADDRESS_NOT_SET;
247 clspv::version0::SamplerFilterMode FilterMode =
248 clspv::version0::CLK_FILTER_NOT_SET;
alan-bakerf5e5f692018-11-27 08:33:24 -0500249
250 for (auto str : samplerStrings) {
251 if ("CLK_NORMALIZED_COORDS_FALSE" == str) {
James Pricec05f6052020-01-14 13:37:20 -0500252 if (clspv::version0::CLK_NORMALIZED_COORDS_NOT_SET !=
253 NormalizedCoord) {
alan-bakerf5e5f692018-11-27 08:33:24 -0500254 llvm::errs() << "Error: Sampler map normalized coordinates was "
255 "previously set!\n";
alan-bakerfec0a472018-11-08 18:09:40 -0500256 return -1;
257 }
James Pricec05f6052020-01-14 13:37:20 -0500258 NormalizedCoord = clspv::version0::CLK_NORMALIZED_COORDS_FALSE;
alan-bakerf5e5f692018-11-27 08:33:24 -0500259 } else if ("CLK_NORMALIZED_COORDS_TRUE" == str) {
James Pricec05f6052020-01-14 13:37:20 -0500260 if (clspv::version0::CLK_NORMALIZED_COORDS_NOT_SET !=
261 NormalizedCoord) {
alan-bakerf5e5f692018-11-27 08:33:24 -0500262 llvm::errs() << "Error: Sampler map normalized coordinates was "
263 "previously set!\n";
264 return -1;
265 }
James Pricec05f6052020-01-14 13:37:20 -0500266 NormalizedCoord = clspv::version0::CLK_NORMALIZED_COORDS_TRUE;
alan-bakerf5e5f692018-11-27 08:33:24 -0500267 } else if ("CLK_ADDRESS_NONE" == str) {
James Pricec05f6052020-01-14 13:37:20 -0500268 if (clspv::version0::CLK_ADDRESS_NOT_SET != AddressingMode) {
alan-bakerf5e5f692018-11-27 08:33:24 -0500269 llvm::errs()
270 << "Error: Sampler map addressing mode was previously set!\n";
271 return -1;
272 }
James Pricec05f6052020-01-14 13:37:20 -0500273 AddressingMode = clspv::version0::CLK_ADDRESS_NONE;
alan-bakerf5e5f692018-11-27 08:33:24 -0500274 } else if ("CLK_ADDRESS_CLAMP_TO_EDGE" == str) {
James Pricec05f6052020-01-14 13:37:20 -0500275 if (clspv::version0::CLK_ADDRESS_NOT_SET != AddressingMode) {
alan-bakerf5e5f692018-11-27 08:33:24 -0500276 llvm::errs()
277 << "Error: Sampler map addressing mode was previously set!\n";
278 return -1;
279 }
James Pricec05f6052020-01-14 13:37:20 -0500280 AddressingMode = clspv::version0::CLK_ADDRESS_CLAMP_TO_EDGE;
alan-bakerf5e5f692018-11-27 08:33:24 -0500281 } else if ("CLK_ADDRESS_CLAMP" == str) {
James Pricec05f6052020-01-14 13:37:20 -0500282 if (clspv::version0::CLK_ADDRESS_NOT_SET != AddressingMode) {
alan-bakerf5e5f692018-11-27 08:33:24 -0500283 llvm::errs()
284 << "Error: Sampler map addressing mode was previously set!\n";
285 return -1;
286 }
James Pricec05f6052020-01-14 13:37:20 -0500287 AddressingMode = clspv::version0::CLK_ADDRESS_CLAMP;
alan-bakerf5e5f692018-11-27 08:33:24 -0500288 } else if ("CLK_ADDRESS_MIRRORED_REPEAT" == str) {
James Pricec05f6052020-01-14 13:37:20 -0500289 if (clspv::version0::CLK_ADDRESS_NOT_SET != AddressingMode) {
alan-bakerf5e5f692018-11-27 08:33:24 -0500290 llvm::errs()
291 << "Error: Sampler map addressing mode was previously set!\n";
292 return -1;
293 }
James Pricec05f6052020-01-14 13:37:20 -0500294 AddressingMode = clspv::version0::CLK_ADDRESS_MIRRORED_REPEAT;
alan-bakerf5e5f692018-11-27 08:33:24 -0500295 } else if ("CLK_ADDRESS_REPEAT" == str) {
James Pricec05f6052020-01-14 13:37:20 -0500296 if (clspv::version0::CLK_ADDRESS_NOT_SET != AddressingMode) {
alan-bakerf5e5f692018-11-27 08:33:24 -0500297 llvm::errs()
298 << "Error: Sampler map addressing mode was previously set!\n";
299 return -1;
300 }
James Pricec05f6052020-01-14 13:37:20 -0500301 AddressingMode = clspv::version0::CLK_ADDRESS_REPEAT;
alan-bakerf5e5f692018-11-27 08:33:24 -0500302 } else if ("CLK_FILTER_NEAREST" == str) {
James Pricec05f6052020-01-14 13:37:20 -0500303 if (clspv::version0::CLK_FILTER_NOT_SET != FilterMode) {
alan-bakerf5e5f692018-11-27 08:33:24 -0500304 llvm::errs()
305 << "Error: Sampler map filtering mode was previously set!\n";
306 return -1;
307 }
James Pricec05f6052020-01-14 13:37:20 -0500308 FilterMode = clspv::version0::CLK_FILTER_NEAREST;
alan-bakerf5e5f692018-11-27 08:33:24 -0500309 } else if ("CLK_FILTER_LINEAR" == str) {
James Pricec05f6052020-01-14 13:37:20 -0500310 if (clspv::version0::CLK_FILTER_NOT_SET != FilterMode) {
alan-bakerf5e5f692018-11-27 08:33:24 -0500311 llvm::errs()
312 << "Error: Sampler map filtering mode was previously set!\n";
313 return -1;
314 }
James Pricec05f6052020-01-14 13:37:20 -0500315 FilterMode = clspv::version0::CLK_FILTER_LINEAR;
alan-bakerf5e5f692018-11-27 08:33:24 -0500316 } else {
317 llvm::errs() << "Error: Unknown sampler string '" << str
318 << "' found!\n";
alan-bakerfec0a472018-11-08 18:09:40 -0500319 return -1;
320 }
alan-bakerfec0a472018-11-08 18:09:40 -0500321 }
322
James Pricec05f6052020-01-14 13:37:20 -0500323 if (clspv::version0::CLK_NORMALIZED_COORDS_NOT_SET == NormalizedCoord) {
alan-bakerf5e5f692018-11-27 08:33:24 -0500324 llvm::errs() << "Error: Sampler map entry did not contain normalized "
325 "coordinates entry!\n";
326 return -1;
alan-bakerfec0a472018-11-08 18:09:40 -0500327 }
alan-bakerf5e5f692018-11-27 08:33:24 -0500328
James Pricec05f6052020-01-14 13:37:20 -0500329 if (clspv::version0::CLK_ADDRESS_NOT_SET == AddressingMode) {
alan-bakerf5e5f692018-11-27 08:33:24 -0500330 llvm::errs() << "Error: Sampler map entry did not contain addressing "
331 "mode entry!\n";
332 return -1;
333 }
334
James Pricec05f6052020-01-14 13:37:20 -0500335 if (clspv::version0::CLK_FILTER_NOT_SET == FilterMode) {
alan-bakerf5e5f692018-11-27 08:33:24 -0500336 llvm::errs()
337 << "Error: Sampler map entry did not contain filer mode entry!\n";
338 return -1;
339 }
340
341 // Generate an equivalent expression in string form. Sort the
342 // strings to get a canonical ordering.
343 std::sort(samplerStrings.begin(), samplerStrings.end(),
344 std::less<StringRef>());
345 const auto samplerExpr = std::accumulate(
346 samplerStrings.begin(), samplerStrings.end(), std::string(),
alan-baker21574d32020-01-29 16:00:31 -0500347 [](llvm::StringRef left, llvm::StringRef right) {
348 return left.str() + std::string(left.empty() ? "" : "|") +
349 right.str();
alan-bakerf5e5f692018-11-27 08:33:24 -0500350 });
351
352 // SamplerMapEntries->push_back(std::make_pair(
353 // NormalizedCoord | AddressingMode | FilterMode, samplerExpr));
354 SamplerMapEntries->emplace_back(
355 NormalizedCoord | AddressingMode | FilterMode, samplerExpr);
356
357 // And reset the sampler strings for the next sampler in the map.
358 samplerStrings.clear();
359 }
360
361 // And lastly, if we are at the end of the file
362 if (i == e) {
363 break;
alan-bakerfec0a472018-11-08 18:09:40 -0500364 }
365 }
366
367 return 0;
368}
369
370// Sets |instance|'s options for compiling. Returns 0 if successful.
371int SetCompilerInstanceOptions(CompilerInstance &instance,
372 const llvm::StringRef &overiddenInputFilename,
373 const clang::FrontendInputFile &kernelFile,
alan-bakerf5e5f692018-11-27 08:33:24 -0500374 const std::string &program,
alan-bakerfec0a472018-11-08 18:09:40 -0500375 llvm::raw_string_ostream *diagnosticsStream) {
alan-bakerf5e5f692018-11-27 08:33:24 -0500376 std::unique_ptr<llvm::MemoryBuffer> memory_buffer(nullptr);
377 llvm::ErrorOr<std::unique_ptr<llvm::MemoryBuffer>> errorOrInputFile(nullptr);
378 if (program.empty()) {
379 auto errorOrInputFile =
380 llvm::MemoryBuffer::getFileOrSTDIN(InputFilename.getValue());
alan-bakerfec0a472018-11-08 18:09:40 -0500381
alan-bakerf5e5f692018-11-27 08:33:24 -0500382 // If there was an error in getting the input file.
383 if (!errorOrInputFile) {
384 llvm::errs() << "Error: " << errorOrInputFile.getError().message() << " '"
385 << InputFilename.getValue() << "'\n";
386 return -1;
387 }
388 memory_buffer.reset(errorOrInputFile.get().release());
389 } else {
390 memory_buffer = llvm::MemoryBuffer::getMemBuffer(program.c_str(),
391 overiddenInputFilename);
alan-bakerfec0a472018-11-08 18:09:40 -0500392 }
alan-bakerf5e5f692018-11-27 08:33:24 -0500393
alan-bakerfec0a472018-11-08 18:09:40 -0500394 if (verify) {
395 instance.getDiagnosticOpts().VerifyDiagnostics = true;
alan-bakerbccf62c2019-03-29 10:32:41 -0400396 instance.getDiagnosticOpts().VerifyPrefixes.push_back("expected");
alan-bakerfec0a472018-11-08 18:09:40 -0500397 }
398
Kévin Petit0fc88042019-04-09 23:25:02 +0100399 clang::LangStandard::Kind standard;
Kévin Petitf0515712020-01-07 18:29:20 +0000400 switch (clspv::Option::Language()) {
401 case clspv::Option::SourceLanguage::OpenCL_C_10:
402 standard = clang::LangStandard::lang_opencl10;
403 break;
404 case clspv::Option::SourceLanguage::OpenCL_C_11:
405 standard = clang::LangStandard::lang_opencl11;
406 break;
407 case clspv::Option::SourceLanguage::OpenCL_C_12:
Kévin Petit0fc88042019-04-09 23:25:02 +0100408 standard = clang::LangStandard::lang_opencl12;
Kévin Petitf0515712020-01-07 18:29:20 +0000409 break;
410 case clspv::Option::SourceLanguage::OpenCL_C_20:
411 standard = clang::LangStandard::lang_opencl20;
412 break;
413 case clspv::Option::SourceLanguage::OpenCL_CPP:
414 standard = clang::LangStandard::lang_openclcpp;
415 break;
416 default:
417 llvm_unreachable("Unknown source language");
Kévin Petit0fc88042019-04-09 23:25:02 +0100418 }
alan-bakerfec0a472018-11-08 18:09:40 -0500419
alan-bakerfec0a472018-11-08 18:09:40 -0500420 instance.getLangOpts().C99 = true;
421 instance.getLangOpts().RTTI = false;
422 instance.getLangOpts().RTTIData = false;
423 instance.getLangOpts().MathErrno = false;
424 instance.getLangOpts().Optimize = false;
425 instance.getLangOpts().NoBuiltin = true;
426 instance.getLangOpts().ModulesSearchAll = false;
427 instance.getLangOpts().SinglePrecisionConstants = true;
428 instance.getCodeGenOpts().StackRealignment = true;
429 instance.getCodeGenOpts().SimplifyLibCalls = false;
430 instance.getCodeGenOpts().EmitOpenCLArgMetadata = false;
431 instance.getCodeGenOpts().DisableO0ImplyOptNone = true;
Kévin Petit6b07cbe2019-04-02 21:52:16 +0100432 instance.getDiagnosticOpts().IgnoreWarnings = IgnoreWarnings;
alan-bakerfec0a472018-11-08 18:09:40 -0500433
434 instance.getLangOpts().SinglePrecisionConstants =
435 cl_single_precision_constants;
436 // cl_denorms_are_zero ignored for now!
437 // cl_fp32_correctly_rounded_divide_sqrt ignored for now!
438 instance.getCodeGenOpts().LessPreciseFPMAD =
439 cl_mad_enable || cl_unsafe_math_optimizations;
440 // cl_no_signed_zeros ignored for now!
441 instance.getCodeGenOpts().UnsafeFPMath =
442 cl_unsafe_math_optimizations || cl_fast_relaxed_math;
443 instance.getLangOpts().FiniteMathOnly =
444 cl_finite_math_only || cl_fast_relaxed_math;
445 instance.getLangOpts().FastRelaxedMath = cl_fast_relaxed_math;
446
447 // Preprocessor options
Kévin Petita624c0c2019-05-07 20:27:43 +0800448 if (!clspv::Option::ImageSupport()) {
449 instance.getPreprocessorOpts().addMacroUndef("__IMAGE_SUPPORT__");
450 }
alan-bakerfec0a472018-11-08 18:09:40 -0500451 if (cl_fast_relaxed_math) {
452 instance.getPreprocessorOpts().addMacroDef("__FAST_RELAXED_MATH__");
453 }
454
455 for (auto define : Defines) {
456 instance.getPreprocessorOpts().addMacroDef(define);
457 }
458
459 // Header search options
460 for (auto include : Includes) {
461 instance.getHeaderSearchOpts().AddPath(include, clang::frontend::After,
462 false, false);
463 }
464
465 // We always compile on opt 0 so we preserve as much debug information about
466 // the source as possible. We'll run optimization later, once we've had a
467 // chance to view the unoptimal code first
468 instance.getCodeGenOpts().OptimizationLevel = 0;
469
470// Debug information is disabled temporarily to call instruction.
471#if 0
472 instance.getCodeGenOpts().setDebugInfo(clang::codegenoptions::FullDebugInfo);
473#endif
474
475 // We use the 32-bit pointer-width SPIR triple
476 llvm::Triple triple("spir-unknown-unknown");
477
478 instance.getInvocation().setLangDefaults(
alan-bakerd354f1a2019-08-06 15:41:55 -0400479 instance.getLangOpts(), clang::InputKind(clang::Language::OpenCL), triple,
alan-bakerfec0a472018-11-08 18:09:40 -0500480 instance.getPreprocessorOpts(), standard);
481
482 // Override the C99 inline semantics to accommodate for more OpenCL C
483 // programs in the wild.
484 instance.getLangOpts().GNUInline = true;
Kévin Petit6b07cbe2019-04-02 21:52:16 +0100485
486 // Set up diagnostics
alan-bakerfec0a472018-11-08 18:09:40 -0500487 instance.createDiagnostics(
488 new clang::TextDiagnosticPrinter(*diagnosticsStream,
489 &instance.getDiagnosticOpts()),
490 true);
Kévin Petit6b07cbe2019-04-02 21:52:16 +0100491 instance.getDiagnostics().setWarningsAsErrors(WarningsAsErrors);
492 instance.getDiagnostics().setEnableAllWarnings(true);
alan-bakerfec0a472018-11-08 18:09:40 -0500493
494 instance.getTargetOpts().Triple = triple.str();
495
alan-baker21574d32020-01-29 16:00:31 -0500496 instance.getCodeGenOpts().MainFileName = overiddenInputFilename.str();
alan-bakerfec0a472018-11-08 18:09:40 -0500497 instance.getCodeGenOpts().PreserveVec3Type = true;
498 // Disable generation of lifetime intrinsic.
499 instance.getCodeGenOpts().DisableLifetimeMarkers = true;
500 instance.getFrontendOpts().Inputs.push_back(kernelFile);
alan-bakerf5e5f692018-11-27 08:33:24 -0500501 instance.getPreprocessorOpts().addRemappedFile(overiddenInputFilename,
502 memory_buffer.release());
alan-bakerfec0a472018-11-08 18:09:40 -0500503
504 struct OpenCLBuiltinMemoryBuffer final : public llvm::MemoryBuffer {
505 OpenCLBuiltinMemoryBuffer(const void *data, uint64_t data_length) {
506 const char *dataCasted = reinterpret_cast<const char *>(data);
507 init(dataCasted, dataCasted + data_length, true);
508 }
509
510 virtual llvm::MemoryBuffer::BufferKind getBufferKind() const override {
511 return llvm::MemoryBuffer::MemoryBuffer_Malloc;
512 }
513
514 virtual ~OpenCLBuiltinMemoryBuffer() override {}
515 };
516
517 std::unique_ptr<llvm::MemoryBuffer> openCLBuiltinMemoryBuffer(
518 new OpenCLBuiltinMemoryBuffer(opencl_builtins_header_data,
519 opencl_builtins_header_size - 1));
520
521 instance.getPreprocessorOpts().Includes.push_back("openclc.h");
522
alan-bakerf3bce4a2019-06-28 16:01:15 -0400523 std::unique_ptr<llvm::MemoryBuffer> openCLBaseBuiltinMemoryBuffer(
524 new OpenCLBuiltinMemoryBuffer(opencl_base_builtins_header_data,
525 opencl_base_builtins_header_size - 1));
526
527 instance.getPreprocessorOpts().Includes.push_back("opencl-c-base.h");
528
alan-bakerfec0a472018-11-08 18:09:40 -0500529 // Add the VULKAN macro.
530 instance.getPreprocessorOpts().addMacroDef("VULKAN=100");
531
532 // Add the __OPENCL_VERSION__ macro.
533 instance.getPreprocessorOpts().addMacroDef("__OPENCL_VERSION__=120");
534
535 instance.setTarget(clang::TargetInfo::CreateTargetInfo(
536 instance.getDiagnostics(),
537 std::make_shared<clang::TargetOptions>(instance.getTargetOpts())));
538
539 instance.createFileManager();
540 instance.createSourceManager(instance.getFileManager());
541
542#ifdef _MSC_VER
543 std::string includePrefix("include\\");
544#else
545 std::string includePrefix("include/");
546#endif
547
548 auto entry = instance.getFileManager().getVirtualFile(
549 includePrefix + "openclc.h", openCLBuiltinMemoryBuffer->getBufferSize(),
550 0);
551
552 instance.getSourceManager().overrideFileContents(
553 entry, std::move(openCLBuiltinMemoryBuffer));
554
alan-bakerf3bce4a2019-06-28 16:01:15 -0400555 auto base_entry = instance.getFileManager().getVirtualFile(
556 includePrefix + "opencl-c-base.h",
557 openCLBaseBuiltinMemoryBuffer->getBufferSize(), 0);
558
559 instance.getSourceManager().overrideFileContents(
560 base_entry, std::move(openCLBaseBuiltinMemoryBuffer));
561
alan-bakerfec0a472018-11-08 18:09:40 -0500562 return 0;
563}
564
alan-bakerf5e5f692018-11-27 08:33:24 -0500565// Populates |pm| with necessary passes to optimize and legalize the IR.
566int PopulatePassManager(
567 llvm::legacy::PassManager *pm, llvm::raw_svector_ostream *binaryStream,
568 std::vector<clspv::version0::DescriptorMapEntry> *descriptor_map_entries,
569 llvm::SmallVectorImpl<std::pair<unsigned, std::string>>
570 *SamplerMapEntries) {
alan-bakerfec0a472018-11-08 18:09:40 -0500571 llvm::PassManagerBuilder pmBuilder;
572
573 switch (OptimizationLevel) {
574 case '0':
alan-bakerf5e5f692018-11-27 08:33:24 -0500575 case '1':
576 case '2':
577 case '3':
578 case 's':
579 case 'z':
580 break;
581 default:
582 llvm::errs() << "Unknown optimization level -O" << OptimizationLevel
583 << " specified!\n";
584 return -1;
585 }
586
587 switch (OptimizationLevel) {
588 case '0':
alan-bakerfec0a472018-11-08 18:09:40 -0500589 pmBuilder.OptLevel = 0;
590 break;
591 case '1':
592 pmBuilder.OptLevel = 1;
593 break;
594 case '2':
595 pmBuilder.OptLevel = 2;
596 break;
597 case '3':
598 pmBuilder.OptLevel = 3;
599 break;
600 case 's':
601 pmBuilder.SizeLevel = 1;
602 break;
603 case 'z':
604 pmBuilder.SizeLevel = 2;
605 break;
606 default:
607 break;
608 }
609
610 pm->add(clspv::createZeroInitializeAllocasPass());
Kévin Petitbbbda972020-03-03 19:16:31 +0000611 pm->add(clspv::createDeclarePushConstantsPass());
alan-bakerfec0a472018-11-08 18:09:40 -0500612 pm->add(clspv::createDefineOpenCLWorkItemBuiltinsPass());
613
614 if (0 < pmBuilder.OptLevel) {
615 pm->add(clspv::createOpenCLInlinerPass());
616 }
617
618 pm->add(clspv::createUndoByvalPass());
619 pm->add(clspv::createUndoSRetPass());
620 if (cluster_non_pointer_kernel_args) {
621 pm->add(clspv::createClusterPodKernelArgumentsPass());
622 }
623 pm->add(clspv::createReplaceOpenCLBuiltinPass());
624
625 // We need to run mem2reg and inst combine early because our
626 // createInlineFuncWithPointerBitCastArgPass pass cannot handle the pattern
627 // %1 = alloca i32 1
628 // store <something> %1
629 // %2 = bitcast float* %1
630 // %3 = load float %2
631 pm->add(llvm::createPromoteMemoryToRegisterPass());
632
alan-baker1b13e8f2019-08-08 17:56:51 -0400633 // Try to deal with pointer bitcasts early. This can prevent problems like
634 // issue #409 where LLVM is looser about access chain addressing than SPIR-V.
635 // This needs to happen before instcombine and after replacing OpenCL
636 // builtins. This run of the pass will not handle all pointer bitcasts that
637 // could be handled. It should be run again after other optimizations (e.g
638 // InlineFuncWithPointerBitCastArgPass).
639 pm->add(clspv::createSimplifyPointerBitcastPass());
640 pm->add(clspv::createReplacePointerBitcastPass());
641 pm->add(llvm::createDeadCodeEliminationPass());
642
alan-bakerfec0a472018-11-08 18:09:40 -0500643 // Hide loads from __constant address space away from instcombine.
644 // This prevents us from generating select between pointers-to-__constant.
645 // See https://github.com/google/clspv/issues/71
646 pm->add(clspv::createHideConstantLoadsPass());
647
648 pm->add(llvm::createInstructionCombiningPass());
649
650 if (clspv::Option::InlineEntryPoints()) {
651 pm->add(clspv::createInlineEntryPointsPass());
652 } else {
653 pm->add(clspv::createInlineFuncWithPointerBitCastArgPass());
654 pm->add(clspv::createInlineFuncWithPointerToFunctionArgPass());
655 pm->add(clspv::createInlineFuncWithSingleCallSitePass());
656 }
657
Kévin Petitf0515712020-01-07 18:29:20 +0000658 if (clspv::Option::LanguageUsesGenericAddressSpace()) {
Kévin Petit38c52482019-05-07 20:28:00 +0800659 pm->add(llvm::createInferAddressSpacesPass(clspv::AddressSpace::Generic));
Kévin Petit0fc88042019-04-09 23:25:02 +0100660 }
661
alan-bakerfec0a472018-11-08 18:09:40 -0500662 if (0 == pmBuilder.OptLevel) {
663 // Mem2Reg pass should be run early because O0 level optimization leaves
664 // redundant alloca, load and store instructions from function arguments.
665 // clspv needs to remove them ahead of transformation.
666 pm->add(llvm::createPromoteMemoryToRegisterPass());
667
668 // SROA pass is run because it will fold structs/unions that are problematic
669 // on Vulkan SPIR-V away.
670 pm->add(llvm::createSROAPass());
671
672 // InstructionCombining pass folds bitcast and gep instructions which are
673 // not supported by Vulkan SPIR-V.
674 pm->add(llvm::createInstructionCombiningPass());
675 }
676
677 // Now we add any of the LLVM optimizations we wanted
678 pmBuilder.populateModulePassManager(*pm);
679
680 // Unhide loads from __constant address space. Undoes the action of
681 // HideConstantLoadsPass.
682 pm->add(clspv::createUnhideConstantLoadsPass());
683
684 pm->add(clspv::createFunctionInternalizerPass());
685 pm->add(clspv::createReplaceLLVMIntrinsicsPass());
686 pm->add(clspv::createUndoBoolPass());
687 pm->add(clspv::createUndoTruncatedSwitchConditionPass());
688 pm->add(llvm::createStructurizeCFGPass(false));
alan-baker3fa76d92018-11-12 14:54:40 -0500689 // Must be run after structurize cfg.
alan-baker9580aef2020-01-07 22:31:48 -0500690 pm->add(clspv::createFixupStructuredCFGPass());
691 // Must be run after structured cfg fixup.
alan-bakerfec0a472018-11-08 18:09:40 -0500692 pm->add(clspv::createReorderBasicBlocksPass());
693 pm->add(clspv::createUndoGetElementPtrConstantExprPass());
694 pm->add(clspv::createSplatArgPass());
695 pm->add(clspv::createSimplifyPointerBitcastPass());
696 pm->add(clspv::createReplacePointerBitcastPass());
697
698 pm->add(clspv::createUndoTranslateSamplerFoldPass());
699
700 if (clspv::Option::ModuleConstantsInStorageBuffer()) {
701 pm->add(clspv::createClusterModuleScopeConstantVars());
702 }
703
704 pm->add(clspv::createShareModuleScopeVariablesPass());
alan-bakerf67468c2019-11-25 15:51:49 -0500705 // Specialize images before assigning descriptors to disambiguate the various
706 // types.
707 pm->add(clspv::createSpecializeImageTypesPass());
alan-bakere9308012019-03-15 10:25:13 -0400708 // This should be run after LLVM and OpenCL intrinsics are replaced.
alan-bakerfec0a472018-11-08 18:09:40 -0500709 pm->add(clspv::createAllocateDescriptorsPass(*SamplerMapEntries));
710 pm->add(llvm::createVerifierPass());
711 pm->add(clspv::createDirectResourceAccessPass());
712 // Replacing pointer bitcasts can leave some trivial GEPs
713 // that are easy to remove. Also replace GEPs of GEPS
714 // left by replacing indirect buffer accesses.
715 pm->add(clspv::createSimplifyPointerBitcastPass());
alan-baker4217b322019-03-06 08:56:12 -0500716 // Run after DRA to clean up parameters and help reduce the need for variable
717 // pointers.
718 pm->add(clspv::createRemoveUnusedArgumentsPass());
alan-bakerfec0a472018-11-08 18:09:40 -0500719
720 pm->add(clspv::createSplatSelectConditionPass());
721 pm->add(clspv::createSignedCompareFixupPass());
722 // This pass generates insertions that need to be rewritten.
723 pm->add(clspv::createScalarizePass());
724 pm->add(clspv::createRewriteInsertsPass());
alan-bakera71f1932019-04-11 11:04:34 -0400725 // UBO Transformations
726 if (clspv::Option::ConstantArgsInUniformBuffer() &&
727 !clspv::Option::InlineEntryPoints()) {
728 // MultiVersionUBOFunctionsPass will examine non-kernel functions with UBO
729 // arguments and either multi-version them as necessary or inline them if
730 // multi-versioning cannot be accomplished.
731 pm->add(clspv::createMultiVersionUBOFunctionsPass());
732 // Cleanup passes.
733 // Specialization can blindly generate GEP chains that are easily cleaned up
734 // by SimplifyPointerBitcastPass.
735 pm->add(clspv::createSimplifyPointerBitcastPass());
736 // RemoveUnusedArgumentsPass removes the actual UBO arguments that were
737 // problematic to begin with now that they have no uses.
738 pm->add(clspv::createRemoveUnusedArgumentsPass());
739 // DCE cleans up callers of the specialized functions.
740 pm->add(llvm::createDeadCodeEliminationPass());
741 }
alan-bakerfec0a472018-11-08 18:09:40 -0500742 // This pass mucks with types to point where you shouldn't rely on DataLayout
743 // anymore so leave this right before SPIR-V generation.
744 pm->add(clspv::createUBOTypeTransformPass());
alan-baker00e7a582019-06-07 12:54:21 -0400745 pm->add(clspv::createSPIRVProducerPass(*binaryStream, descriptor_map_entries,
746 *SamplerMapEntries,
747 OutputFormat == "c"));
alan-bakerf5e5f692018-11-27 08:33:24 -0500748
749 return 0;
alan-bakerfec0a472018-11-08 18:09:40 -0500750}
alan-bakerfec0a472018-11-08 18:09:40 -0500751
Kévin Petitd5db2d22019-04-04 13:55:14 +0100752int ParseOptions(const int argc, const char *const argv[]) {
alan-bakerfec0a472018-11-08 18:09:40 -0500753 // We need to change how one of the called passes works by spoofing
754 // ParseCommandLineOptions with the specific option.
755 const int llvmArgc = 2;
756 const char *llvmArgv[llvmArgc] = {
alan-bakerf5e5f692018-11-27 08:33:24 -0500757 argv[0],
758 "-simplifycfg-sink-common=false",
alan-bakerfec0a472018-11-08 18:09:40 -0500759 };
760
Kévin Petitd5db2d22019-04-04 13:55:14 +0100761 llvm::cl::ResetAllOptionOccurrences();
alan-bakerfec0a472018-11-08 18:09:40 -0500762 llvm::cl::ParseCommandLineOptions(llvmArgc, llvmArgv);
alan-bakerfec0a472018-11-08 18:09:40 -0500763 llvm::cl::ParseCommandLineOptions(argc, argv);
764
Kévin Petitf0515712020-01-07 18:29:20 +0000765 if (clspv::Option::LanguageUsesGenericAddressSpace() &&
766 !clspv::Option::InlineEntryPoints()) {
767 llvm::errs() << "cannot compile languages that use the generic address "
768 "space (e.g. CLC++, CL2.0) without -inline-entry-points\n";
Kévin Petit0fc88042019-04-09 23:25:02 +0100769 return -1;
770 }
771
Kévin Petitbbbda972020-03-03 19:16:31 +0000772 if (clspv::Option::ScalarBlockLayout()) {
773 llvm::errs() << "scalar block layout support unimplemented\n";
774 return -1;
775 }
776
Kévin Petitd5db2d22019-04-04 13:55:14 +0100777 return 0;
778}
Diego Novillo89500852019-04-15 08:45:10 -0400779
780int GenerateIRFile(llvm::legacy::PassManager *pm, llvm::Module &module,
781 std::string output) {
782 std::error_code ec;
783 std::unique_ptr<llvm::ToolOutputFile> out(
784 new llvm::ToolOutputFile(output, ec, llvm::sys::fs::F_None));
785 if (ec) {
786 llvm::errs() << output << ": " << ec.message() << '\n';
787 return -1;
788 }
789 pm->add(llvm::createPrintModulePass(out->os(), "", false));
790 pm->run(module);
791 out->keep();
792 return 0;
793}
794
Kévin Petitd5db2d22019-04-04 13:55:14 +0100795} // namespace
796
797namespace clspv {
798int Compile(const int argc, const char *const argv[]) {
799
800 if (auto error = ParseOptions(argc, argv))
801 return error;
802
alan-bakerfec0a472018-11-08 18:09:40 -0500803 llvm::SmallVector<std::pair<unsigned, std::string>, 8> SamplerMapEntries;
alan-bakerf5e5f692018-11-27 08:33:24 -0500804 if (auto error = ParseSamplerMap("", &SamplerMapEntries))
alan-bakerfec0a472018-11-08 18:09:40 -0500805 return error;
806
807 // if no output file was provided, use a default
808 llvm::StringRef overiddenInputFilename = InputFilename.getValue();
809
810 // If we are reading our input file from stdin.
811 if ("-" == InputFilename) {
812 // We need to overwrite the file name we use.
Kévin Petitddad8f42019-09-30 15:12:08 +0100813 switch (InputLanguage) {
814 case clang::Language::OpenCL:
815 overiddenInputFilename = "stdin.cl";
816 break;
817 case clang::Language::LLVM_IR:
818 overiddenInputFilename = "stdin.ll";
819 break;
alan-baker31298a62019-10-07 13:24:30 -0400820 default:
821 // Default to fix compiler warnings/errors. Option parsing will reject a
822 // bad enum value for the option so there is no need for a message.
823 return -1;
Kévin Petitddad8f42019-09-30 15:12:08 +0100824 }
alan-bakerfec0a472018-11-08 18:09:40 -0500825 }
826
827 clang::CompilerInstance instance;
Kévin Petitddad8f42019-09-30 15:12:08 +0100828 clang::FrontendInputFile kernelFile(overiddenInputFilename,
829 clang::InputKind(InputLanguage));
alan-bakerfec0a472018-11-08 18:09:40 -0500830 std::string log;
831 llvm::raw_string_ostream diagnosticsStream(log);
alan-bakerf5e5f692018-11-27 08:33:24 -0500832 if (auto error = SetCompilerInstanceOptions(
833 instance, overiddenInputFilename, kernelFile, "", &diagnosticsStream))
alan-bakerfec0a472018-11-08 18:09:40 -0500834 return error;
835
836 // Parse.
837 llvm::LLVMContext context;
838 clang::EmitLLVMOnlyAction action(&context);
839
840 // Prepare the action for processing kernelFile
841 const bool success = action.BeginSourceFile(instance, kernelFile);
842 if (!success) {
843 return -1;
844 }
845
alan-bakerf3bce4a2019-06-28 16:01:15 -0400846 auto result = action.Execute();
alan-bakerfec0a472018-11-08 18:09:40 -0500847 action.EndSourceFile();
848
849 clang::DiagnosticConsumer *const consumer =
850 instance.getDiagnostics().getClient();
851 consumer->finish();
852
Kévin Petit6b07cbe2019-04-02 21:52:16 +0100853 auto num_warnings = consumer->getNumWarnings();
alan-bakerfec0a472018-11-08 18:09:40 -0500854 auto num_errors = consumer->getNumErrors();
Kévin Petit6b07cbe2019-04-02 21:52:16 +0100855 if ((num_errors > 0) || (num_warnings > 0)) {
856 llvm::errs() << log;
857 }
alan-bakerf3bce4a2019-06-28 16:01:15 -0400858 if (result || num_errors > 0) {
alan-bakerfec0a472018-11-08 18:09:40 -0500859 return -1;
860 }
861
Kévin Petit6b07cbe2019-04-02 21:52:16 +0100862 // Don't run the passes or produce any output in verify mode.
863 // Clang doesn't always produce a valid module.
864 if (verify) {
865 return 0;
866 }
867
alan-bakerfec0a472018-11-08 18:09:40 -0500868 llvm::PassRegistry &Registry = *llvm::PassRegistry::getPassRegistry();
869 llvm::initializeCore(Registry);
870 llvm::initializeScalarOpts(Registry);
Diego Novillo1fcff722019-05-07 13:45:53 -0400871 llvm::initializeClspvPasses(Registry);
alan-bakerfec0a472018-11-08 18:09:40 -0500872
873 std::unique_ptr<llvm::Module> module(action.takeModule());
874
875 // Optimize.
876 // Create a memory buffer for temporarily writing the result.
877 SmallVector<char, 10000> binary;
878 llvm::raw_svector_ostream binaryStream(binary);
879 std::string descriptor_map;
alan-bakerfec0a472018-11-08 18:09:40 -0500880 llvm::legacy::PassManager pm;
alan-bakerf5e5f692018-11-27 08:33:24 -0500881 std::vector<version0::DescriptorMapEntry> descriptor_map_entries;
Diego Novillo89500852019-04-15 08:45:10 -0400882
883 // If --emit-ir was requested, emit the initial LLVM IR and stop compilation.
884 if (!IROutputFile.empty()) {
885 return GenerateIRFile(&pm, *module, IROutputFile);
886 }
887
888 // Otherwise, populate the pass manager and run the regular passes.
Diego Novillo3cc8d7a2019-04-10 13:30:34 -0400889 if (auto error = PopulatePassManager(
890 &pm, &binaryStream, &descriptor_map_entries, &SamplerMapEntries))
alan-bakerf5e5f692018-11-27 08:33:24 -0500891 return error;
alan-bakerfec0a472018-11-08 18:09:40 -0500892 pm.run(*module);
893
894 // Write outputs
895
896 // Write the descriptor map, if requested.
897 std::error_code error;
898 if (!DescriptorMapFilename.empty()) {
Diego Novillo3cc8d7a2019-04-10 13:30:34 -0400899 llvm::raw_fd_ostream descriptor_map_out_fd(
900 DescriptorMapFilename, error, llvm::sys::fs::CD_CreateAlways,
901 llvm::sys::fs::FA_Write, llvm::sys::fs::F_Text);
alan-bakerfec0a472018-11-08 18:09:40 -0500902 if (error) {
903 llvm::errs() << "Unable to open descriptor map file '"
904 << DescriptorMapFilename << "': " << error.message() << '\n';
905 return -1;
906 }
alan-bakerf5e5f692018-11-27 08:33:24 -0500907 std::string descriptor_map_string;
908 std::ostringstream str(descriptor_map_string);
909 for (const auto &entry : descriptor_map_entries) {
910 str << entry << "\n";
911 }
912 descriptor_map_out_fd << str.str();
alan-bakerfec0a472018-11-08 18:09:40 -0500913 descriptor_map_out_fd.close();
914 }
915
916 // Write the resulting binary.
917 // Wait until now to try writing the file so that we only write it on
918 // successful compilation.
919 if (OutputFilename.empty()) {
Kévin Petite4786902019-04-02 21:51:47 +0100920 if (OutputFormat == "c") {
alan-bakerfec0a472018-11-08 18:09:40 -0500921 OutputFilename = "a.spvinc";
922 } else {
923 OutputFilename = "a.spv";
924 }
925 }
Diego Novillo3cc8d7a2019-04-10 13:30:34 -0400926 llvm::raw_fd_ostream outStream(OutputFilename, error,
927 llvm::sys::fs::FA_Write);
alan-bakerfec0a472018-11-08 18:09:40 -0500928
929 if (error) {
930 llvm::errs() << "Unable to open output file '" << OutputFilename
931 << "': " << error.message() << '\n';
932 return -1;
933 }
934 outStream << binaryStream.str();
935
936 return 0;
937}
alan-bakerf5e5f692018-11-27 08:33:24 -0500938
Diego Novillo3cc8d7a2019-04-10 13:30:34 -0400939int CompileFromSourceString(
940 const std::string &program, const std::string &sampler_map,
941 const std::string &options, std::vector<uint32_t> *output_binary,
942 std::vector<clspv::version0::DescriptorMapEntry> *descriptor_map_entries) {
alan-bakerf5e5f692018-11-27 08:33:24 -0500943
944 llvm::SmallVector<const char *, 20> argv;
945 llvm::BumpPtrAllocator A;
946 llvm::StringSaver Saver(A);
947 argv.push_back(Saver.save("clspv").data());
948 llvm::cl::TokenizeGNUCommandLine(options, Saver, argv);
949 int argc = static_cast<int>(argv.size());
Kévin Petitd5db2d22019-04-04 13:55:14 +0100950
951 if (auto error = ParseOptions(argc, &argv[0]))
952 return error;
alan-bakerf5e5f692018-11-27 08:33:24 -0500953
954 llvm::SmallVector<std::pair<unsigned, std::string>, 8> SamplerMapEntries;
955 if (auto error = ParseSamplerMap(sampler_map, &SamplerMapEntries))
956 return error;
957
958 InputFilename = "source.cl";
959 llvm::StringRef overiddenInputFilename = InputFilename.getValue();
960
961 clang::CompilerInstance instance;
alan-bakerd354f1a2019-08-06 15:41:55 -0400962 clang::FrontendInputFile kernelFile(
963 overiddenInputFilename, clang::InputKind(clang::Language::OpenCL));
alan-bakerf5e5f692018-11-27 08:33:24 -0500964 std::string log;
965 llvm::raw_string_ostream diagnosticsStream(log);
966 if (auto error =
967 SetCompilerInstanceOptions(instance, overiddenInputFilename,
968 kernelFile, program, &diagnosticsStream))
969 return error;
970
971 // Parse.
972 llvm::LLVMContext context;
973 clang::EmitLLVMOnlyAction action(&context);
974
975 // Prepare the action for processing kernelFile
976 const bool success = action.BeginSourceFile(instance, kernelFile);
977 if (!success) {
978 return -1;
979 }
980
alan-bakerf3bce4a2019-06-28 16:01:15 -0400981 auto result = action.Execute();
alan-bakerf5e5f692018-11-27 08:33:24 -0500982 action.EndSourceFile();
983
984 clang::DiagnosticConsumer *const consumer =
985 instance.getDiagnostics().getClient();
986 consumer->finish();
987
988 auto num_errors = consumer->getNumErrors();
alan-bakerf3bce4a2019-06-28 16:01:15 -0400989 if (result || num_errors > 0) {
alan-bakerf5e5f692018-11-27 08:33:24 -0500990 llvm::errs() << log << "\n";
991 return -1;
992 }
993
alan-bakerf5e5f692018-11-27 08:33:24 -0500994 llvm::PassRegistry &Registry = *llvm::PassRegistry::getPassRegistry();
995 llvm::initializeCore(Registry);
996 llvm::initializeScalarOpts(Registry);
Diego Novillo1fcff722019-05-07 13:45:53 -0400997 llvm::initializeClspvPasses(Registry);
alan-bakerf5e5f692018-11-27 08:33:24 -0500998
999 std::unique_ptr<llvm::Module> module(action.takeModule());
1000
1001 // Optimize.
1002 // Create a memory buffer for temporarily writing the result.
1003 SmallVector<char, 10000> binary;
1004 llvm::raw_svector_ostream binaryStream(binary);
1005 std::string descriptor_map;
1006 llvm::legacy::PassManager pm;
Diego Novillo3cc8d7a2019-04-10 13:30:34 -04001007 if (auto error = PopulatePassManager(
1008 &pm, &binaryStream, descriptor_map_entries, &SamplerMapEntries))
alan-bakerf5e5f692018-11-27 08:33:24 -05001009 return error;
1010 pm.run(*module);
1011
1012 // Write outputs
1013
1014 // Write the descriptor map. This is required.
Diego Novillo3cc8d7a2019-04-10 13:30:34 -04001015 assert(descriptor_map_entries &&
1016 "Valid descriptor map container is required.");
alan-bakerf5e5f692018-11-27 08:33:24 -05001017 if (!DescriptorMapFilename.empty()) {
Diego Novillo3cc8d7a2019-04-10 13:30:34 -04001018 llvm::errs() << "Warning: -descriptormap is ignored descriptor map "
1019 "container is provided.\n";
alan-bakerf5e5f692018-11-27 08:33:24 -05001020 }
1021
1022 // Write the resulting binary.
1023 // Wait until now to try writing the file so that we only write it on
1024 // successful compilation.
1025 assert(output_binary && "Valid binary container is required.");
1026 if (!OutputFilename.empty()) {
1027 llvm::outs()
1028 << "Warning: -o is ignored when binary container is provided.\n";
1029 }
1030 output_binary->resize(binary.size() / 4);
1031 memcpy(output_binary->data(), binary.data(), binary.size());
1032
1033 return 0;
1034}
alan-bakerfec0a472018-11-08 18:09:40 -05001035} // namespace clspv