blob: 3af1044ed0b1a918eb5835fc0f8086a9d9c7a472 [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
alan-baker0d095d62020-03-12 14:59:47 -040015#include "clang/Basic/FileManager.h"
alan-bakerfec0a472018-11-08 18:09:40 -050016#include "clang/Basic/TargetInfo.h"
17#include "clang/CodeGen/CodeGenAction.h"
18#include "clang/Frontend/CompilerInstance.h"
19#include "clang/Frontend/FrontendPluginRegistry.h"
20#include "clang/Frontend/TextDiagnosticPrinter.h"
21#include "clang/Lex/PreprocessorOptions.h"
22#include "llvm/IR/LLVMContext.h"
23#include "llvm/IR/LegacyPassManager.h"
24#include "llvm/IR/Module.h"
25#include "llvm/IR/Verifier.h"
alan-baker0e64a592019-11-18 13:36:25 -050026#include "llvm/InitializePasses.h"
alan-bakerfec0a472018-11-08 18:09:40 -050027#include "llvm/LinkAllPasses.h"
alan-bakerf5e5f692018-11-27 08:33:24 -050028#include "llvm/Support/Allocator.h"
alan-bakerfec0a472018-11-08 18:09:40 -050029#include "llvm/Support/CommandLine.h"
alan-bakerf5e5f692018-11-27 08:33:24 -050030#include "llvm/Support/ErrorOr.h"
alan-bakerfec0a472018-11-08 18:09:40 -050031#include "llvm/Support/MathExtras.h"
alan-bakerf5e5f692018-11-27 08:33:24 -050032#include "llvm/Support/StringSaver.h"
Diego Novillo89500852019-04-15 08:45:10 -040033#include "llvm/Support/ToolOutputFile.h"
alan-bakerfec0a472018-11-08 18:09:40 -050034#include "llvm/Support/raw_ostream.h"
35#include "llvm/Transforms/IPO/PassManagerBuilder.h"
36
Kévin Petit38c52482019-05-07 20:28:00 +080037#include "clspv/AddressSpace.h"
alan-bakerfec0a472018-11-08 18:09:40 -050038#include "clspv/Option.h"
39#include "clspv/Passes.h"
alan-baker86ce19c2020-08-05 13:09:19 -040040#include "clspv/Sampler.h"
alan-bakerfec0a472018-11-08 18:09:40 -050041#include "clspv/opencl_builtins_header.h"
42
43#include "FrontendPlugin.h"
Diego Novilloa4c44fa2019-04-11 10:56:15 -040044#include "Passes.h"
alan-bakerfec0a472018-11-08 18:09:40 -050045
alan-bakerf5e5f692018-11-27 08:33:24 -050046#include <cassert>
alan-bakerfec0a472018-11-08 18:09:40 -050047#include <numeric>
alan-bakerf5e5f692018-11-27 08:33:24 -050048#include <sstream>
Diego Novillo3cc8d7a2019-04-10 13:30:34 -040049#include <string>
alan-bakerfec0a472018-11-08 18:09:40 -050050
51using namespace clang;
52
53namespace {
54// This registration must be located in the same file as the execution of the
55// action.
56static FrontendPluginRegistry::Add<clspv::ExtraValidationASTAction>
57 X("extra-validation",
58 "Perform extra validation on OpenCL C when targeting Vulkan");
59
60static llvm::cl::opt<bool> cl_single_precision_constants(
61 "cl-single-precision-constant", llvm::cl::init(false),
62 llvm::cl::desc("Treat double precision floating-point constant as single "
63 "precision constant."));
64
65static llvm::cl::opt<bool> cl_denorms_are_zero(
66 "cl-denorms-are-zero", llvm::cl::init(false),
67 llvm::cl::desc("If specified, denormalized floating point numbers may be "
68 "flushed to zero."));
69
70static llvm::cl::opt<bool> cl_fp32_correctly_rounded_divide_sqrt(
71 "cl-fp32-correctly-rounded-divide-sqrt", llvm::cl::init(false),
72 llvm::cl::desc("Single precision floating-point divide (x/y and 1/x) and "
73 "sqrt used are correctly rounded."));
74
75static llvm::cl::opt<bool>
76 cl_opt_disable("cl-opt-disable", llvm::cl::init(false),
77 llvm::cl::desc("This option disables all optimizations. The "
78 "default is optimizations are enabled."));
79
80static llvm::cl::opt<bool> cl_mad_enable(
81 "cl-mad-enable", llvm::cl::init(false),
82 llvm::cl::desc("Allow a * b + c to be replaced by a mad. The mad computes "
83 "a * b + c with reduced accuracy."));
84
85static llvm::cl::opt<bool> cl_no_signed_zeros(
86 "cl-no-signed-zeros", llvm::cl::init(false),
87 llvm::cl::desc("Allow optimizations for floating-point arithmetic that "
88 "ignore the signedness of zero."));
89
90static llvm::cl::opt<bool> cl_unsafe_math_optimizations(
91 "cl-unsafe-math-optimizations", llvm::cl::init(false),
92 llvm::cl::desc("Allow optimizations for floating-point arithmetic that (a) "
93 "assume that arguments and results are valid, (b) may "
94 "violate IEEE 754 standard and (c) may violate the OpenCL "
95 "numerical compliance requirements. This option includes "
96 "the -cl-no-signed-zeros and -cl-mad-enable options."));
97
98static llvm::cl::opt<bool> cl_finite_math_only(
99 "cl-finite-math-only", llvm::cl::init(false),
100 llvm::cl::desc("Allow optimizations for floating-point arithmetic that "
101 "assume that arguments and results are not NaNs or INFs."));
102
103static llvm::cl::opt<bool> cl_fast_relaxed_math(
104 "cl-fast-relaxed-math", llvm::cl::init(false),
105 llvm::cl::desc("This option causes the preprocessor macro "
106 "__FAST_RELAXED_MATH__ to be defined. Sets the optimization "
107 "options -cl-finite-math-only and "
108 "-cl-unsafe-math-optimizations."));
109
110static llvm::cl::list<std::string>
111 Includes(llvm::cl::Prefix, "I",
112 llvm::cl::desc("Add a directory to the list of directories "
113 "to be searched for header files."),
114 llvm::cl::ZeroOrMore, llvm::cl::value_desc("include path"));
115
116static llvm::cl::list<std::string>
117 Defines(llvm::cl::Prefix, "D",
118 llvm::cl::desc("Define a #define directive."), llvm::cl::ZeroOrMore,
119 llvm::cl::value_desc("define"));
120
121static llvm::cl::opt<std::string>
122 InputFilename(llvm::cl::Positional, llvm::cl::desc("<input .cl file>"),
123 llvm::cl::init("-"));
124
Kévin Petitddad8f42019-09-30 15:12:08 +0100125static llvm::cl::opt<clang::Language> InputLanguage(
126 "x", llvm::cl::desc("Select input type"),
127 llvm::cl::init(clang::Language::OpenCL),
128 llvm::cl::values(clEnumValN(clang::Language::OpenCL, "cl", "OpenCL source"),
129 clEnumValN(clang::Language::LLVM_IR, "ir", "LLVM IR")));
130
alan-bakerfec0a472018-11-08 18:09:40 -0500131static llvm::cl::opt<std::string>
132 OutputFilename("o", llvm::cl::desc("Override output filename"),
133 llvm::cl::value_desc("filename"));
134
alan-bakerfec0a472018-11-08 18:09:40 -0500135static llvm::cl::opt<char>
136 OptimizationLevel(llvm::cl::Prefix, "O", llvm::cl::init('2'),
137 llvm::cl::desc("Optimization level to use"),
138 llvm::cl::value_desc("level"));
139
alan-bakerfec0a472018-11-08 18:09:40 -0500140static llvm::cl::opt<std::string> OutputFormat(
141 "mfmt", llvm::cl::init(""),
142 llvm::cl::desc(
143 "Specify special output format. 'c' is as a C initializer list"),
144 llvm::cl::value_desc("format"));
145
146static llvm::cl::opt<std::string>
alan-baker09cb9802019-12-10 13:16:27 -0500147 SamplerMap("samplermap", llvm::cl::desc("DEPRECATED - Literal sampler map"),
alan-bakerfec0a472018-11-08 18:09:40 -0500148 llvm::cl::value_desc("filename"));
149
alan-bakerfec0a472018-11-08 18:09:40 -0500150static llvm::cl::opt<bool> verify("verify", llvm::cl::init(false),
151 llvm::cl::desc("Verify diagnostic outputs"));
152
Kévin Petit6b07cbe2019-04-02 21:52:16 +0100153static llvm::cl::opt<bool>
154 IgnoreWarnings("w", llvm::cl::init(false),
155 llvm::cl::desc("Disable all warnings"));
156
157static llvm::cl::opt<bool>
158 WarningsAsErrors("Werror", llvm::cl::init(false),
Diego Novillo3cc8d7a2019-04-10 13:30:34 -0400159 llvm::cl::desc("Turn warnings into errors"));
Kévin Petit6b07cbe2019-04-02 21:52:16 +0100160
Diego Novillo89500852019-04-15 08:45:10 -0400161static llvm::cl::opt<std::string> IROutputFile(
162 "emit-ir",
163 llvm::cl::desc(
164 "Emit LLVM IR to the given file after parsing and stop compilation."),
165 llvm::cl::value_desc("filename"));
166
alan-bakerfec0a472018-11-08 18:09:40 -0500167// Populates |SamplerMapEntries| with data from the input sampler map. Returns 0
168// if successful.
alan-bakerf5e5f692018-11-27 08:33:24 -0500169int ParseSamplerMap(const std::string &sampler_map,
170 llvm::SmallVectorImpl<std::pair<unsigned, std::string>>
171 *SamplerMapEntries) {
172 std::unique_ptr<llvm::MemoryBuffer> samplerMapBuffer(nullptr);
173 if (!sampler_map.empty()) {
174 // Parse the sampler map from the provided string.
175 samplerMapBuffer = llvm::MemoryBuffer::getMemBuffer(sampler_map);
176
alan-baker09cb9802019-12-10 13:16:27 -0500177 clspv::Option::SetUseSamplerMap(true);
alan-bakerf5e5f692018-11-27 08:33:24 -0500178 if (!SamplerMap.empty()) {
179 llvm::outs() << "Warning: -samplermap is ignored when the sampler map is "
180 "provided through a string.\n";
181 }
182 } else if (!SamplerMap.empty()) {
183 // Parse the sampler map from the option provided file.
alan-bakerfec0a472018-11-08 18:09:40 -0500184 auto errorOrSamplerMapFile =
185 llvm::MemoryBuffer::getFile(SamplerMap.getValue());
186
187 // If there was an error in getting the sampler map file.
188 if (!errorOrSamplerMapFile) {
189 llvm::errs() << "Error: " << errorOrSamplerMapFile.getError().message()
190 << " '" << SamplerMap.getValue() << "'\n";
191 return -1;
192 }
193
alan-baker09cb9802019-12-10 13:16:27 -0500194 clspv::Option::SetUseSamplerMap(true);
alan-bakerf5e5f692018-11-27 08:33:24 -0500195 samplerMapBuffer = std::move(errorOrSamplerMapFile.get());
alan-bakerfec0a472018-11-08 18:09:40 -0500196 if (0 == samplerMapBuffer->getBufferSize()) {
197 llvm::errs() << "Error: Sampler map was an empty file!\n";
198 return -1;
199 }
alan-bakerf5e5f692018-11-27 08:33:24 -0500200 }
alan-bakerfec0a472018-11-08 18:09:40 -0500201
alan-baker09cb9802019-12-10 13:16:27 -0500202 if (clspv::Option::UseSamplerMap()) {
203 llvm::outs()
204 << "Warning: use of the sampler map is deprecated and unnecessary\n";
205 }
206
alan-bakerf5e5f692018-11-27 08:33:24 -0500207 // No sampler map to parse.
208 if (!samplerMapBuffer || 0 == samplerMapBuffer->getBufferSize())
209 return 0;
alan-bakerfec0a472018-11-08 18:09:40 -0500210
alan-bakerf5e5f692018-11-27 08:33:24 -0500211 llvm::SmallVector<llvm::StringRef, 3> samplerStrings;
alan-bakerfec0a472018-11-08 18:09:40 -0500212
alan-bakerf5e5f692018-11-27 08:33:24 -0500213 // We need to keep track of the beginning of the current entry.
214 const char *b = samplerMapBuffer->getBufferStart();
215 for (const char *i = b, *e = samplerMapBuffer->getBufferEnd();; i++) {
216 // If we have a separator between declarations.
217 if ((*i == '|') || (*i == ',') || (i == e)) {
218 if (i == b) {
219 llvm::errs() << "Error: Sampler map contained an empty entry!\n";
220 return -1;
alan-bakerfec0a472018-11-08 18:09:40 -0500221 }
222
alan-bakerf5e5f692018-11-27 08:33:24 -0500223 samplerStrings.push_back(llvm::StringRef(b, i - b).trim());
alan-bakerfec0a472018-11-08 18:09:40 -0500224
alan-bakerf5e5f692018-11-27 08:33:24 -0500225 // And set b the next character after i.
226 b = i + 1;
227 }
alan-bakerfec0a472018-11-08 18:09:40 -0500228
alan-bakerf5e5f692018-11-27 08:33:24 -0500229 // If we have a separator between declarations within a single sampler.
230 if ((*i == ',') || (i == e)) {
alan-bakerfec0a472018-11-08 18:09:40 -0500231
alan-baker86ce19c2020-08-05 13:09:19 -0400232 clspv::SamplerNormalizedCoords NormalizedCoord =
233 clspv::CLK_NORMALIZED_COORDS_NOT_SET;
234 clspv::SamplerAddressingMode AddressingMode = clspv::CLK_ADDRESS_NOT_SET;
235 clspv::SamplerFilterMode FilterMode = clspv::CLK_FILTER_NOT_SET;
alan-bakerf5e5f692018-11-27 08:33:24 -0500236
237 for (auto str : samplerStrings) {
238 if ("CLK_NORMALIZED_COORDS_FALSE" == str) {
alan-baker86ce19c2020-08-05 13:09:19 -0400239 if (clspv::CLK_NORMALIZED_COORDS_NOT_SET != NormalizedCoord) {
alan-bakerf5e5f692018-11-27 08:33:24 -0500240 llvm::errs() << "Error: Sampler map normalized coordinates was "
241 "previously set!\n";
alan-bakerfec0a472018-11-08 18:09:40 -0500242 return -1;
243 }
alan-baker86ce19c2020-08-05 13:09:19 -0400244 NormalizedCoord = clspv::CLK_NORMALIZED_COORDS_FALSE;
alan-bakerf5e5f692018-11-27 08:33:24 -0500245 } else if ("CLK_NORMALIZED_COORDS_TRUE" == str) {
alan-baker86ce19c2020-08-05 13:09:19 -0400246 if (clspv::CLK_NORMALIZED_COORDS_NOT_SET != NormalizedCoord) {
alan-bakerf5e5f692018-11-27 08:33:24 -0500247 llvm::errs() << "Error: Sampler map normalized coordinates was "
248 "previously set!\n";
249 return -1;
250 }
alan-baker86ce19c2020-08-05 13:09:19 -0400251 NormalizedCoord = clspv::CLK_NORMALIZED_COORDS_TRUE;
alan-bakerf5e5f692018-11-27 08:33:24 -0500252 } else if ("CLK_ADDRESS_NONE" == str) {
alan-baker86ce19c2020-08-05 13:09:19 -0400253 if (clspv::CLK_ADDRESS_NOT_SET != AddressingMode) {
alan-bakerf5e5f692018-11-27 08:33:24 -0500254 llvm::errs()
255 << "Error: Sampler map addressing mode was previously set!\n";
256 return -1;
257 }
alan-baker86ce19c2020-08-05 13:09:19 -0400258 AddressingMode = clspv::CLK_ADDRESS_NONE;
alan-bakerf5e5f692018-11-27 08:33:24 -0500259 } else if ("CLK_ADDRESS_CLAMP_TO_EDGE" == str) {
alan-baker86ce19c2020-08-05 13:09:19 -0400260 if (clspv::CLK_ADDRESS_NOT_SET != AddressingMode) {
alan-bakerf5e5f692018-11-27 08:33:24 -0500261 llvm::errs()
262 << "Error: Sampler map addressing mode was previously set!\n";
263 return -1;
264 }
alan-baker86ce19c2020-08-05 13:09:19 -0400265 AddressingMode = clspv::CLK_ADDRESS_CLAMP_TO_EDGE;
alan-bakerf5e5f692018-11-27 08:33:24 -0500266 } else if ("CLK_ADDRESS_CLAMP" == str) {
alan-baker86ce19c2020-08-05 13:09:19 -0400267 if (clspv::CLK_ADDRESS_NOT_SET != AddressingMode) {
alan-bakerf5e5f692018-11-27 08:33:24 -0500268 llvm::errs()
269 << "Error: Sampler map addressing mode was previously set!\n";
270 return -1;
271 }
alan-baker86ce19c2020-08-05 13:09:19 -0400272 AddressingMode = clspv::CLK_ADDRESS_CLAMP;
alan-bakerf5e5f692018-11-27 08:33:24 -0500273 } else if ("CLK_ADDRESS_MIRRORED_REPEAT" == str) {
alan-baker86ce19c2020-08-05 13:09:19 -0400274 if (clspv::CLK_ADDRESS_NOT_SET != AddressingMode) {
alan-bakerf5e5f692018-11-27 08:33:24 -0500275 llvm::errs()
276 << "Error: Sampler map addressing mode was previously set!\n";
277 return -1;
278 }
alan-baker86ce19c2020-08-05 13:09:19 -0400279 AddressingMode = clspv::CLK_ADDRESS_MIRRORED_REPEAT;
alan-bakerf5e5f692018-11-27 08:33:24 -0500280 } else if ("CLK_ADDRESS_REPEAT" == str) {
alan-baker86ce19c2020-08-05 13:09:19 -0400281 if (clspv::CLK_ADDRESS_NOT_SET != AddressingMode) {
alan-bakerf5e5f692018-11-27 08:33:24 -0500282 llvm::errs()
283 << "Error: Sampler map addressing mode was previously set!\n";
284 return -1;
285 }
alan-baker86ce19c2020-08-05 13:09:19 -0400286 AddressingMode = clspv::CLK_ADDRESS_REPEAT;
alan-bakerf5e5f692018-11-27 08:33:24 -0500287 } else if ("CLK_FILTER_NEAREST" == str) {
alan-baker86ce19c2020-08-05 13:09:19 -0400288 if (clspv::CLK_FILTER_NOT_SET != FilterMode) {
alan-bakerf5e5f692018-11-27 08:33:24 -0500289 llvm::errs()
290 << "Error: Sampler map filtering mode was previously set!\n";
291 return -1;
292 }
alan-baker86ce19c2020-08-05 13:09:19 -0400293 FilterMode = clspv::CLK_FILTER_NEAREST;
alan-bakerf5e5f692018-11-27 08:33:24 -0500294 } else if ("CLK_FILTER_LINEAR" == str) {
alan-baker86ce19c2020-08-05 13:09:19 -0400295 if (clspv::CLK_FILTER_NOT_SET != FilterMode) {
alan-bakerf5e5f692018-11-27 08:33:24 -0500296 llvm::errs()
297 << "Error: Sampler map filtering mode was previously set!\n";
298 return -1;
299 }
alan-baker86ce19c2020-08-05 13:09:19 -0400300 FilterMode = clspv::CLK_FILTER_LINEAR;
alan-bakerf5e5f692018-11-27 08:33:24 -0500301 } else {
302 llvm::errs() << "Error: Unknown sampler string '" << str
303 << "' found!\n";
alan-bakerfec0a472018-11-08 18:09:40 -0500304 return -1;
305 }
alan-bakerfec0a472018-11-08 18:09:40 -0500306 }
307
alan-baker86ce19c2020-08-05 13:09:19 -0400308 if (clspv::CLK_NORMALIZED_COORDS_NOT_SET == NormalizedCoord) {
alan-bakerf5e5f692018-11-27 08:33:24 -0500309 llvm::errs() << "Error: Sampler map entry did not contain normalized "
310 "coordinates entry!\n";
311 return -1;
alan-bakerfec0a472018-11-08 18:09:40 -0500312 }
alan-bakerf5e5f692018-11-27 08:33:24 -0500313
alan-baker86ce19c2020-08-05 13:09:19 -0400314 if (clspv::CLK_ADDRESS_NOT_SET == AddressingMode) {
alan-bakerf5e5f692018-11-27 08:33:24 -0500315 llvm::errs() << "Error: Sampler map entry did not contain addressing "
316 "mode entry!\n";
317 return -1;
318 }
319
alan-baker86ce19c2020-08-05 13:09:19 -0400320 if (clspv::CLK_FILTER_NOT_SET == FilterMode) {
alan-bakerf5e5f692018-11-27 08:33:24 -0500321 llvm::errs()
322 << "Error: Sampler map entry did not contain filer mode entry!\n";
323 return -1;
324 }
325
326 // Generate an equivalent expression in string form. Sort the
327 // strings to get a canonical ordering.
328 std::sort(samplerStrings.begin(), samplerStrings.end(),
329 std::less<StringRef>());
330 const auto samplerExpr = std::accumulate(
331 samplerStrings.begin(), samplerStrings.end(), std::string(),
alan-baker21574d32020-01-29 16:00:31 -0500332 [](llvm::StringRef left, llvm::StringRef right) {
333 return left.str() + std::string(left.empty() ? "" : "|") +
334 right.str();
alan-bakerf5e5f692018-11-27 08:33:24 -0500335 });
336
337 // SamplerMapEntries->push_back(std::make_pair(
338 // NormalizedCoord | AddressingMode | FilterMode, samplerExpr));
339 SamplerMapEntries->emplace_back(
340 NormalizedCoord | AddressingMode | FilterMode, samplerExpr);
341
342 // And reset the sampler strings for the next sampler in the map.
343 samplerStrings.clear();
344 }
345
346 // And lastly, if we are at the end of the file
347 if (i == e) {
348 break;
alan-bakerfec0a472018-11-08 18:09:40 -0500349 }
350 }
351
352 return 0;
353}
354
355// Sets |instance|'s options for compiling. Returns 0 if successful.
356int SetCompilerInstanceOptions(CompilerInstance &instance,
357 const llvm::StringRef &overiddenInputFilename,
358 const clang::FrontendInputFile &kernelFile,
alan-bakerf5e5f692018-11-27 08:33:24 -0500359 const std::string &program,
alan-bakerfec0a472018-11-08 18:09:40 -0500360 llvm::raw_string_ostream *diagnosticsStream) {
alan-bakerf5e5f692018-11-27 08:33:24 -0500361 std::unique_ptr<llvm::MemoryBuffer> memory_buffer(nullptr);
362 llvm::ErrorOr<std::unique_ptr<llvm::MemoryBuffer>> errorOrInputFile(nullptr);
363 if (program.empty()) {
364 auto errorOrInputFile =
365 llvm::MemoryBuffer::getFileOrSTDIN(InputFilename.getValue());
alan-bakerfec0a472018-11-08 18:09:40 -0500366
alan-bakerf5e5f692018-11-27 08:33:24 -0500367 // If there was an error in getting the input file.
368 if (!errorOrInputFile) {
369 llvm::errs() << "Error: " << errorOrInputFile.getError().message() << " '"
370 << InputFilename.getValue() << "'\n";
371 return -1;
372 }
373 memory_buffer.reset(errorOrInputFile.get().release());
374 } else {
375 memory_buffer = llvm::MemoryBuffer::getMemBuffer(program.c_str(),
376 overiddenInputFilename);
alan-bakerfec0a472018-11-08 18:09:40 -0500377 }
alan-bakerf5e5f692018-11-27 08:33:24 -0500378
alan-bakerfec0a472018-11-08 18:09:40 -0500379 if (verify) {
380 instance.getDiagnosticOpts().VerifyDiagnostics = true;
alan-bakerbccf62c2019-03-29 10:32:41 -0400381 instance.getDiagnosticOpts().VerifyPrefixes.push_back("expected");
alan-bakerfec0a472018-11-08 18:09:40 -0500382 }
383
Kévin Petit0fc88042019-04-09 23:25:02 +0100384 clang::LangStandard::Kind standard;
Kévin Petitf0515712020-01-07 18:29:20 +0000385 switch (clspv::Option::Language()) {
386 case clspv::Option::SourceLanguage::OpenCL_C_10:
387 standard = clang::LangStandard::lang_opencl10;
388 break;
389 case clspv::Option::SourceLanguage::OpenCL_C_11:
390 standard = clang::LangStandard::lang_opencl11;
391 break;
392 case clspv::Option::SourceLanguage::OpenCL_C_12:
Kévin Petit0fc88042019-04-09 23:25:02 +0100393 standard = clang::LangStandard::lang_opencl12;
Kévin Petitf0515712020-01-07 18:29:20 +0000394 break;
395 case clspv::Option::SourceLanguage::OpenCL_C_20:
396 standard = clang::LangStandard::lang_opencl20;
397 break;
Kévin Petit77838ff2020-10-19 18:54:51 +0100398 case clspv::Option::SourceLanguage::OpenCL_C_30:
399 standard = clang::LangStandard::lang_opencl30;
alan-bakera1001772021-02-08 16:42:33 -0500400 // TODO: See #705, find a better solution for this.
401 instance.getPreprocessorOpts().addMacroUndef("cl_khr_3d_image_writes");
Kévin Petit77838ff2020-10-19 18:54:51 +0100402 break;
Kévin Petitf0515712020-01-07 18:29:20 +0000403 case clspv::Option::SourceLanguage::OpenCL_CPP:
404 standard = clang::LangStandard::lang_openclcpp;
405 break;
406 default:
407 llvm_unreachable("Unknown source language");
Kévin Petit0fc88042019-04-09 23:25:02 +0100408 }
alan-bakerfec0a472018-11-08 18:09:40 -0500409
alan-bakerfec0a472018-11-08 18:09:40 -0500410 instance.getLangOpts().C99 = true;
411 instance.getLangOpts().RTTI = false;
412 instance.getLangOpts().RTTIData = false;
413 instance.getLangOpts().MathErrno = false;
414 instance.getLangOpts().Optimize = false;
415 instance.getLangOpts().NoBuiltin = true;
416 instance.getLangOpts().ModulesSearchAll = false;
417 instance.getLangOpts().SinglePrecisionConstants = true;
418 instance.getCodeGenOpts().StackRealignment = true;
419 instance.getCodeGenOpts().SimplifyLibCalls = false;
420 instance.getCodeGenOpts().EmitOpenCLArgMetadata = false;
421 instance.getCodeGenOpts().DisableO0ImplyOptNone = true;
Kévin Petit6b07cbe2019-04-02 21:52:16 +0100422 instance.getDiagnosticOpts().IgnoreWarnings = IgnoreWarnings;
alan-bakerfec0a472018-11-08 18:09:40 -0500423
424 instance.getLangOpts().SinglePrecisionConstants =
425 cl_single_precision_constants;
426 // cl_denorms_are_zero ignored for now!
427 // cl_fp32_correctly_rounded_divide_sqrt ignored for now!
428 instance.getCodeGenOpts().LessPreciseFPMAD =
429 cl_mad_enable || cl_unsafe_math_optimizations;
430 // cl_no_signed_zeros ignored for now!
alan-baker0f814cd2020-06-02 15:35:14 -0400431 instance.getLangOpts().UnsafeFPMath =
alan-bakerfec0a472018-11-08 18:09:40 -0500432 cl_unsafe_math_optimizations || cl_fast_relaxed_math;
433 instance.getLangOpts().FiniteMathOnly =
434 cl_finite_math_only || cl_fast_relaxed_math;
435 instance.getLangOpts().FastRelaxedMath = cl_fast_relaxed_math;
436
437 // Preprocessor options
Kévin Petita624c0c2019-05-07 20:27:43 +0800438 if (!clspv::Option::ImageSupport()) {
439 instance.getPreprocessorOpts().addMacroUndef("__IMAGE_SUPPORT__");
440 }
alan-bakerfec0a472018-11-08 18:09:40 -0500441 if (cl_fast_relaxed_math) {
442 instance.getPreprocessorOpts().addMacroDef("__FAST_RELAXED_MATH__");
443 }
444
445 for (auto define : Defines) {
446 instance.getPreprocessorOpts().addMacroDef(define);
447 }
448
449 // Header search options
450 for (auto include : Includes) {
451 instance.getHeaderSearchOpts().AddPath(include, clang::frontend::After,
452 false, false);
453 }
454
455 // We always compile on opt 0 so we preserve as much debug information about
456 // the source as possible. We'll run optimization later, once we've had a
457 // chance to view the unoptimal code first
458 instance.getCodeGenOpts().OptimizationLevel = 0;
459
460// Debug information is disabled temporarily to call instruction.
461#if 0
462 instance.getCodeGenOpts().setDebugInfo(clang::codegenoptions::FullDebugInfo);
463#endif
464
465 // We use the 32-bit pointer-width SPIR triple
466 llvm::Triple triple("spir-unknown-unknown");
467
James Price40efe7f2021-01-18 09:19:31 -0500468 // We manually include the OpenCL headers below, so this vector is unused.
469 std::vector<std::string> includes;
470
alan-bakerfec0a472018-11-08 18:09:40 -0500471 instance.getInvocation().setLangDefaults(
alan-bakerd354f1a2019-08-06 15:41:55 -0400472 instance.getLangOpts(), clang::InputKind(clang::Language::OpenCL), triple,
James Price40efe7f2021-01-18 09:19:31 -0500473 includes, standard);
alan-bakerfec0a472018-11-08 18:09:40 -0500474
475 // Override the C99 inline semantics to accommodate for more OpenCL C
476 // programs in the wild.
477 instance.getLangOpts().GNUInline = true;
Kévin Petit6b07cbe2019-04-02 21:52:16 +0100478
479 // Set up diagnostics
alan-bakerfec0a472018-11-08 18:09:40 -0500480 instance.createDiagnostics(
481 new clang::TextDiagnosticPrinter(*diagnosticsStream,
482 &instance.getDiagnosticOpts()),
483 true);
Kévin Petit6b07cbe2019-04-02 21:52:16 +0100484 instance.getDiagnostics().setWarningsAsErrors(WarningsAsErrors);
485 instance.getDiagnostics().setEnableAllWarnings(true);
alan-bakerfec0a472018-11-08 18:09:40 -0500486
487 instance.getTargetOpts().Triple = triple.str();
488
alan-baker21574d32020-01-29 16:00:31 -0500489 instance.getCodeGenOpts().MainFileName = overiddenInputFilename.str();
alan-bakerfec0a472018-11-08 18:09:40 -0500490 instance.getCodeGenOpts().PreserveVec3Type = true;
491 // Disable generation of lifetime intrinsic.
492 instance.getCodeGenOpts().DisableLifetimeMarkers = true;
493 instance.getFrontendOpts().Inputs.push_back(kernelFile);
alan-bakerf5e5f692018-11-27 08:33:24 -0500494 instance.getPreprocessorOpts().addRemappedFile(overiddenInputFilename,
495 memory_buffer.release());
alan-bakerfec0a472018-11-08 18:09:40 -0500496
497 struct OpenCLBuiltinMemoryBuffer final : public llvm::MemoryBuffer {
498 OpenCLBuiltinMemoryBuffer(const void *data, uint64_t data_length) {
499 const char *dataCasted = reinterpret_cast<const char *>(data);
500 init(dataCasted, dataCasted + data_length, true);
501 }
502
503 virtual llvm::MemoryBuffer::BufferKind getBufferKind() const override {
504 return llvm::MemoryBuffer::MemoryBuffer_Malloc;
505 }
506
507 virtual ~OpenCLBuiltinMemoryBuffer() override {}
508 };
509
510 std::unique_ptr<llvm::MemoryBuffer> openCLBuiltinMemoryBuffer(
511 new OpenCLBuiltinMemoryBuffer(opencl_builtins_header_data,
512 opencl_builtins_header_size - 1));
513
James Price40efe7f2021-01-18 09:19:31 -0500514 instance.getPreprocessorOpts().Includes.push_back("opencl-c.h");
alan-bakerfec0a472018-11-08 18:09:40 -0500515
alan-bakerf3bce4a2019-06-28 16:01:15 -0400516 std::unique_ptr<llvm::MemoryBuffer> openCLBaseBuiltinMemoryBuffer(
517 new OpenCLBuiltinMemoryBuffer(opencl_base_builtins_header_data,
518 opencl_base_builtins_header_size - 1));
519
520 instance.getPreprocessorOpts().Includes.push_back("opencl-c-base.h");
521
alan-bakerfec0a472018-11-08 18:09:40 -0500522 // Add the VULKAN macro.
523 instance.getPreprocessorOpts().addMacroDef("VULKAN=100");
524
525 // Add the __OPENCL_VERSION__ macro.
526 instance.getPreprocessorOpts().addMacroDef("__OPENCL_VERSION__=120");
527
528 instance.setTarget(clang::TargetInfo::CreateTargetInfo(
529 instance.getDiagnostics(),
530 std::make_shared<clang::TargetOptions>(instance.getTargetOpts())));
531
532 instance.createFileManager();
533 instance.createSourceManager(instance.getFileManager());
534
535#ifdef _MSC_VER
536 std::string includePrefix("include\\");
537#else
538 std::string includePrefix("include/");
539#endif
540
541 auto entry = instance.getFileManager().getVirtualFile(
James Price40efe7f2021-01-18 09:19:31 -0500542 includePrefix + "opencl-c.h", openCLBuiltinMemoryBuffer->getBufferSize(),
alan-bakerfec0a472018-11-08 18:09:40 -0500543 0);
544
545 instance.getSourceManager().overrideFileContents(
546 entry, std::move(openCLBuiltinMemoryBuffer));
547
alan-bakerf3bce4a2019-06-28 16:01:15 -0400548 auto base_entry = instance.getFileManager().getVirtualFile(
549 includePrefix + "opencl-c-base.h",
550 openCLBaseBuiltinMemoryBuffer->getBufferSize(), 0);
551
552 instance.getSourceManager().overrideFileContents(
553 base_entry, std::move(openCLBaseBuiltinMemoryBuffer));
554
alan-bakerfec0a472018-11-08 18:09:40 -0500555 return 0;
556}
557
alan-bakerf5e5f692018-11-27 08:33:24 -0500558// Populates |pm| with necessary passes to optimize and legalize the IR.
559int PopulatePassManager(
560 llvm::legacy::PassManager *pm, llvm::raw_svector_ostream *binaryStream,
alan-bakerf5e5f692018-11-27 08:33:24 -0500561 llvm::SmallVectorImpl<std::pair<unsigned, std::string>>
562 *SamplerMapEntries) {
alan-bakerfec0a472018-11-08 18:09:40 -0500563 llvm::PassManagerBuilder pmBuilder;
564
565 switch (OptimizationLevel) {
566 case '0':
alan-bakerf5e5f692018-11-27 08:33:24 -0500567 case '1':
568 case '2':
569 case '3':
570 case 's':
571 case 'z':
572 break;
573 default:
574 llvm::errs() << "Unknown optimization level -O" << OptimizationLevel
575 << " specified!\n";
576 return -1;
577 }
578
579 switch (OptimizationLevel) {
580 case '0':
alan-bakerfec0a472018-11-08 18:09:40 -0500581 pmBuilder.OptLevel = 0;
582 break;
583 case '1':
584 pmBuilder.OptLevel = 1;
585 break;
586 case '2':
587 pmBuilder.OptLevel = 2;
588 break;
589 case '3':
590 pmBuilder.OptLevel = 3;
591 break;
592 case 's':
593 pmBuilder.SizeLevel = 1;
594 break;
595 case 'z':
596 pmBuilder.SizeLevel = 2;
597 break;
598 default:
599 break;
600 }
601
602 pm->add(clspv::createZeroInitializeAllocasPass());
alan-baker04f3a952020-03-24 10:39:53 -0400603 pm->add(clspv::createAddFunctionAttributesPass());
alan-bakerc4579bb2020-04-29 14:15:50 -0400604 pm->add(clspv::createAutoPodArgsPass());
Kévin Petitbbbda972020-03-03 19:16:31 +0000605 pm->add(clspv::createDeclarePushConstantsPass());
alan-bakerfec0a472018-11-08 18:09:40 -0500606 pm->add(clspv::createDefineOpenCLWorkItemBuiltinsPass());
607
608 if (0 < pmBuilder.OptLevel) {
609 pm->add(clspv::createOpenCLInlinerPass());
610 }
611
612 pm->add(clspv::createUndoByvalPass());
613 pm->add(clspv::createUndoSRetPass());
alan-baker9b0ec3c2020-04-06 14:45:34 -0400614 if (clspv::Option::ClusterPodKernelArgs()) {
alan-bakerfec0a472018-11-08 18:09:40 -0500615 pm->add(clspv::createClusterPodKernelArgumentsPass());
616 }
617 pm->add(clspv::createReplaceOpenCLBuiltinPass());
618
Marco Antognini535998c2020-09-16 18:48:51 +0100619 // Lower longer vectors when requested. Note that this pass depends on
620 // ReplaceOpenCLBuiltinPass and expects DeadCodeEliminationPass to be run
621 // afterwards.
622 if (clspv::Option::LongVectorSupport()) {
623 pm->add(clspv::createLongVectorLoweringPass());
624 }
625
alan-bakerfec0a472018-11-08 18:09:40 -0500626 // We need to run mem2reg and inst combine early because our
627 // createInlineFuncWithPointerBitCastArgPass pass cannot handle the pattern
628 // %1 = alloca i32 1
629 // store <something> %1
630 // %2 = bitcast float* %1
631 // %3 = load float %2
632 pm->add(llvm::createPromoteMemoryToRegisterPass());
633
alan-baker1b13e8f2019-08-08 17:56:51 -0400634 // Try to deal with pointer bitcasts early. This can prevent problems like
635 // issue #409 where LLVM is looser about access chain addressing than SPIR-V.
636 // This needs to happen before instcombine and after replacing OpenCL
637 // builtins. This run of the pass will not handle all pointer bitcasts that
638 // could be handled. It should be run again after other optimizations (e.g
639 // InlineFuncWithPointerBitCastArgPass).
640 pm->add(clspv::createSimplifyPointerBitcastPass());
641 pm->add(clspv::createReplacePointerBitcastPass());
642 pm->add(llvm::createDeadCodeEliminationPass());
643
alan-bakerfec0a472018-11-08 18:09:40 -0500644 // Hide loads from __constant address space away from instcombine.
645 // This prevents us from generating select between pointers-to-__constant.
646 // See https://github.com/google/clspv/issues/71
647 pm->add(clspv::createHideConstantLoadsPass());
648
649 pm->add(llvm::createInstructionCombiningPass());
650
651 if (clspv::Option::InlineEntryPoints()) {
652 pm->add(clspv::createInlineEntryPointsPass());
653 } else {
654 pm->add(clspv::createInlineFuncWithPointerBitCastArgPass());
655 pm->add(clspv::createInlineFuncWithPointerToFunctionArgPass());
656 pm->add(clspv::createInlineFuncWithSingleCallSitePass());
657 }
658
Kévin Petitf0515712020-01-07 18:29:20 +0000659 if (clspv::Option::LanguageUsesGenericAddressSpace()) {
Kévin Petit38c52482019-05-07 20:28:00 +0800660 pm->add(llvm::createInferAddressSpacesPass(clspv::AddressSpace::Generic));
Kévin Petit0fc88042019-04-09 23:25:02 +0100661 }
662
alan-bakerfec0a472018-11-08 18:09:40 -0500663 if (0 == pmBuilder.OptLevel) {
664 // Mem2Reg pass should be run early because O0 level optimization leaves
665 // redundant alloca, load and store instructions from function arguments.
666 // clspv needs to remove them ahead of transformation.
667 pm->add(llvm::createPromoteMemoryToRegisterPass());
668
669 // SROA pass is run because it will fold structs/unions that are problematic
670 // on Vulkan SPIR-V away.
671 pm->add(llvm::createSROAPass());
672
673 // InstructionCombining pass folds bitcast and gep instructions which are
674 // not supported by Vulkan SPIR-V.
675 pm->add(llvm::createInstructionCombiningPass());
676 }
677
678 // Now we add any of the LLVM optimizations we wanted
679 pmBuilder.populateModulePassManager(*pm);
680
alan-bakerb5e74d62020-04-07 20:38:05 -0400681 // No point attempting to handle freeze currently so strip them from the IR.
682 pm->add(clspv::createStripFreezePass());
683
alan-bakerfec0a472018-11-08 18:09:40 -0500684 // Unhide loads from __constant address space. Undoes the action of
685 // HideConstantLoadsPass.
686 pm->add(clspv::createUnhideConstantLoadsPass());
687
alan-baker13568382020-04-02 17:29:27 -0400688 pm->add(clspv::createUndoInstCombinePass());
alan-bakerfec0a472018-11-08 18:09:40 -0500689 pm->add(clspv::createFunctionInternalizerPass());
690 pm->add(clspv::createReplaceLLVMIntrinsicsPass());
alan-bakerad1a12f2020-08-25 09:18:38 -0400691 // Replace LLVM intrinsics can leave dead code around.
692 pm->add(llvm::createDeadCodeEliminationPass());
alan-bakerfec0a472018-11-08 18:09:40 -0500693 pm->add(clspv::createUndoBoolPass());
alan-bakere711c762020-05-20 17:56:59 -0400694 pm->add(clspv::createUndoTruncateToOddIntegerPass());
alan-bakerfec0a472018-11-08 18:09:40 -0500695 pm->add(llvm::createStructurizeCFGPass(false));
alan-baker3fa76d92018-11-12 14:54:40 -0500696 // Must be run after structurize cfg.
alan-baker9580aef2020-01-07 22:31:48 -0500697 pm->add(clspv::createFixupStructuredCFGPass());
698 // Must be run after structured cfg fixup.
alan-bakerfec0a472018-11-08 18:09:40 -0500699 pm->add(clspv::createReorderBasicBlocksPass());
700 pm->add(clspv::createUndoGetElementPtrConstantExprPass());
701 pm->add(clspv::createSplatArgPass());
702 pm->add(clspv::createSimplifyPointerBitcastPass());
703 pm->add(clspv::createReplacePointerBitcastPass());
704
705 pm->add(clspv::createUndoTranslateSamplerFoldPass());
706
707 if (clspv::Option::ModuleConstantsInStorageBuffer()) {
708 pm->add(clspv::createClusterModuleScopeConstantVars());
709 }
710
711 pm->add(clspv::createShareModuleScopeVariablesPass());
alan-bakerf67468c2019-11-25 15:51:49 -0500712 // Specialize images before assigning descriptors to disambiguate the various
713 // types.
714 pm->add(clspv::createSpecializeImageTypesPass());
alan-bakere9308012019-03-15 10:25:13 -0400715 // This should be run after LLVM and OpenCL intrinsics are replaced.
alan-bakerfec0a472018-11-08 18:09:40 -0500716 pm->add(clspv::createAllocateDescriptorsPass(*SamplerMapEntries));
717 pm->add(llvm::createVerifierPass());
718 pm->add(clspv::createDirectResourceAccessPass());
719 // Replacing pointer bitcasts can leave some trivial GEPs
720 // that are easy to remove. Also replace GEPs of GEPS
721 // left by replacing indirect buffer accesses.
722 pm->add(clspv::createSimplifyPointerBitcastPass());
alan-baker4217b322019-03-06 08:56:12 -0500723 // Run after DRA to clean up parameters and help reduce the need for variable
724 // pointers.
725 pm->add(clspv::createRemoveUnusedArgumentsPass());
alan-bakerfec0a472018-11-08 18:09:40 -0500726
727 pm->add(clspv::createSplatSelectConditionPass());
728 pm->add(clspv::createSignedCompareFixupPass());
729 // This pass generates insertions that need to be rewritten.
730 pm->add(clspv::createScalarizePass());
731 pm->add(clspv::createRewriteInsertsPass());
alan-bakera71f1932019-04-11 11:04:34 -0400732 // UBO Transformations
733 if (clspv::Option::ConstantArgsInUniformBuffer() &&
734 !clspv::Option::InlineEntryPoints()) {
735 // MultiVersionUBOFunctionsPass will examine non-kernel functions with UBO
736 // arguments and either multi-version them as necessary or inline them if
737 // multi-versioning cannot be accomplished.
738 pm->add(clspv::createMultiVersionUBOFunctionsPass());
739 // Cleanup passes.
740 // Specialization can blindly generate GEP chains that are easily cleaned up
741 // by SimplifyPointerBitcastPass.
742 pm->add(clspv::createSimplifyPointerBitcastPass());
743 // RemoveUnusedArgumentsPass removes the actual UBO arguments that were
744 // problematic to begin with now that they have no uses.
745 pm->add(clspv::createRemoveUnusedArgumentsPass());
746 // DCE cleans up callers of the specialized functions.
747 pm->add(llvm::createDeadCodeEliminationPass());
748 }
alan-bakerfec0a472018-11-08 18:09:40 -0500749 // This pass mucks with types to point where you shouldn't rely on DataLayout
750 // anymore so leave this right before SPIR-V generation.
751 pm->add(clspv::createUBOTypeTransformPass());
alan-baker86ce19c2020-08-05 13:09:19 -0400752 pm->add(clspv::createSPIRVProducerPass(*binaryStream, *SamplerMapEntries,
alan-baker00e7a582019-06-07 12:54:21 -0400753 OutputFormat == "c"));
alan-bakerf5e5f692018-11-27 08:33:24 -0500754
755 return 0;
alan-bakerfec0a472018-11-08 18:09:40 -0500756}
alan-bakerfec0a472018-11-08 18:09:40 -0500757
Kévin Petitd5db2d22019-04-04 13:55:14 +0100758int ParseOptions(const int argc, const char *const argv[]) {
alan-baker227e9782020-06-02 15:35:37 -0400759 // We need to change how some of the called passes works by spoofing
760 // ParseCommandLineOptions with the specific options.
761 bool has_pre = false;
762 bool has_load_pre = false;
763 const std::string pre = "-enable-pre";
764 const std::string load_pre = "-enable-load-pre";
765 for (int i = 1; i < argc; ++i) {
766 std::string option(argv[i]);
767 auto pre_pos = option.find(pre);
768 auto load_pos = option.find(load_pre);
769 if (pre_pos == 0 || (pre_pos == 1 && option[0] == '-')) {
770 has_pre = true;
771 } else if (load_pos == 0 || (load_pos == 1 && option[0] == '-')) {
772 has_load_pre = true;
773 }
774 }
775
776 int llvmArgc = 2;
777 const char *llvmArgv[4];
778 llvmArgv[0] = argv[0];
779 llvmArgv[1] = "-simplifycfg-sink-common=false";
780 if (!has_pre) {
781 llvmArgv[llvmArgc++] = "-enable-pre=0";
782 }
783 if (!has_load_pre) {
784 llvmArgv[llvmArgc++] = "-enable-load-pre=0";
785 }
alan-bakerfec0a472018-11-08 18:09:40 -0500786
Kévin Petitd5db2d22019-04-04 13:55:14 +0100787 llvm::cl::ResetAllOptionOccurrences();
alan-bakerfec0a472018-11-08 18:09:40 -0500788 llvm::cl::ParseCommandLineOptions(llvmArgc, llvmArgv);
alan-bakerfec0a472018-11-08 18:09:40 -0500789 llvm::cl::ParseCommandLineOptions(argc, argv);
790
Kévin Petitf0515712020-01-07 18:29:20 +0000791 if (clspv::Option::LanguageUsesGenericAddressSpace() &&
792 !clspv::Option::InlineEntryPoints()) {
793 llvm::errs() << "cannot compile languages that use the generic address "
794 "space (e.g. CLC++, CL2.0) without -inline-entry-points\n";
Kévin Petit0fc88042019-04-09 23:25:02 +0100795 return -1;
796 }
797
Kévin Petitbbbda972020-03-03 19:16:31 +0000798 if (clspv::Option::ScalarBlockLayout()) {
799 llvm::errs() << "scalar block layout support unimplemented\n";
800 return -1;
801 }
802
alan-baker9b0ec3c2020-04-06 14:45:34 -0400803 // Push constant option validation.
804 if (clspv::Option::PodArgsInPushConstants()) {
805 if (clspv::Option::PodArgsInUniformBuffer()) {
806 llvm::errs() << "POD arguments can only be in either uniform buffers or "
807 "push constants\n";
808 return -1;
809 }
810
811 if (!clspv::Option::ClusterPodKernelArgs()) {
812 llvm::errs()
813 << "POD arguments must be clustered to be passed as push constants\n";
814 return -1;
815 }
816
817 // Conservatively error if a module scope push constant could be used.
James Price708cf362020-05-06 19:33:45 -0400818 if (clspv::Option::GlobalOffsetPushConstant() ||
alan-baker9b0ec3c2020-04-06 14:45:34 -0400819 clspv::Option::Language() ==
820 clspv::Option::SourceLanguage::OpenCL_C_20 ||
821 clspv::Option::Language() ==
822 clspv::Option::SourceLanguage::OpenCL_CPP) {
823 llvm::errs() << "POD arguments as push constants are not compatible with "
824 "module scope push constants\n";
825 return -1;
826 }
827 }
828
Kévin Petitd5db2d22019-04-04 13:55:14 +0100829 return 0;
830}
Diego Novillo89500852019-04-15 08:45:10 -0400831
832int GenerateIRFile(llvm::legacy::PassManager *pm, llvm::Module &module,
833 std::string output) {
834 std::error_code ec;
835 std::unique_ptr<llvm::ToolOutputFile> out(
836 new llvm::ToolOutputFile(output, ec, llvm::sys::fs::F_None));
837 if (ec) {
838 llvm::errs() << output << ": " << ec.message() << '\n';
839 return -1;
840 }
841 pm->add(llvm::createPrintModulePass(out->os(), "", false));
842 pm->run(module);
843 out->keep();
844 return 0;
845}
846
Kévin Petitd5db2d22019-04-04 13:55:14 +0100847} // namespace
848
849namespace clspv {
850int Compile(const int argc, const char *const argv[]) {
851
852 if (auto error = ParseOptions(argc, argv))
853 return error;
854
alan-bakerfec0a472018-11-08 18:09:40 -0500855 llvm::SmallVector<std::pair<unsigned, std::string>, 8> SamplerMapEntries;
alan-bakerf5e5f692018-11-27 08:33:24 -0500856 if (auto error = ParseSamplerMap("", &SamplerMapEntries))
alan-bakerfec0a472018-11-08 18:09:40 -0500857 return error;
858
859 // if no output file was provided, use a default
860 llvm::StringRef overiddenInputFilename = InputFilename.getValue();
861
862 // If we are reading our input file from stdin.
863 if ("-" == InputFilename) {
864 // We need to overwrite the file name we use.
Kévin Petitddad8f42019-09-30 15:12:08 +0100865 switch (InputLanguage) {
866 case clang::Language::OpenCL:
867 overiddenInputFilename = "stdin.cl";
868 break;
869 case clang::Language::LLVM_IR:
870 overiddenInputFilename = "stdin.ll";
871 break;
alan-baker31298a62019-10-07 13:24:30 -0400872 default:
873 // Default to fix compiler warnings/errors. Option parsing will reject a
874 // bad enum value for the option so there is no need for a message.
875 return -1;
Kévin Petitddad8f42019-09-30 15:12:08 +0100876 }
alan-bakerfec0a472018-11-08 18:09:40 -0500877 }
878
879 clang::CompilerInstance instance;
Kévin Petitddad8f42019-09-30 15:12:08 +0100880 clang::FrontendInputFile kernelFile(overiddenInputFilename,
881 clang::InputKind(InputLanguage));
alan-bakerfec0a472018-11-08 18:09:40 -0500882 std::string log;
883 llvm::raw_string_ostream diagnosticsStream(log);
alan-bakerf5e5f692018-11-27 08:33:24 -0500884 if (auto error = SetCompilerInstanceOptions(
885 instance, overiddenInputFilename, kernelFile, "", &diagnosticsStream))
alan-bakerfec0a472018-11-08 18:09:40 -0500886 return error;
887
888 // Parse.
889 llvm::LLVMContext context;
890 clang::EmitLLVMOnlyAction action(&context);
891
892 // Prepare the action for processing kernelFile
893 const bool success = action.BeginSourceFile(instance, kernelFile);
894 if (!success) {
895 return -1;
896 }
897
alan-bakerf3bce4a2019-06-28 16:01:15 -0400898 auto result = action.Execute();
alan-bakerfec0a472018-11-08 18:09:40 -0500899 action.EndSourceFile();
900
901 clang::DiagnosticConsumer *const consumer =
902 instance.getDiagnostics().getClient();
903 consumer->finish();
904
Kévin Petit6b07cbe2019-04-02 21:52:16 +0100905 auto num_warnings = consumer->getNumWarnings();
alan-bakerfec0a472018-11-08 18:09:40 -0500906 auto num_errors = consumer->getNumErrors();
Kévin Petit6b07cbe2019-04-02 21:52:16 +0100907 if ((num_errors > 0) || (num_warnings > 0)) {
908 llvm::errs() << log;
909 }
alan-bakerf3bce4a2019-06-28 16:01:15 -0400910 if (result || num_errors > 0) {
alan-bakerfec0a472018-11-08 18:09:40 -0500911 return -1;
912 }
913
Kévin Petit6b07cbe2019-04-02 21:52:16 +0100914 // Don't run the passes or produce any output in verify mode.
915 // Clang doesn't always produce a valid module.
916 if (verify) {
917 return 0;
918 }
919
alan-bakerfec0a472018-11-08 18:09:40 -0500920 llvm::PassRegistry &Registry = *llvm::PassRegistry::getPassRegistry();
921 llvm::initializeCore(Registry);
922 llvm::initializeScalarOpts(Registry);
Diego Novillo1fcff722019-05-07 13:45:53 -0400923 llvm::initializeClspvPasses(Registry);
alan-bakerfec0a472018-11-08 18:09:40 -0500924
925 std::unique_ptr<llvm::Module> module(action.takeModule());
926
927 // Optimize.
928 // Create a memory buffer for temporarily writing the result.
929 SmallVector<char, 10000> binary;
930 llvm::raw_svector_ostream binaryStream(binary);
alan-bakerfec0a472018-11-08 18:09:40 -0500931 llvm::legacy::PassManager pm;
Diego Novillo89500852019-04-15 08:45:10 -0400932
933 // If --emit-ir was requested, emit the initial LLVM IR and stop compilation.
934 if (!IROutputFile.empty()) {
935 return GenerateIRFile(&pm, *module, IROutputFile);
936 }
937
938 // Otherwise, populate the pass manager and run the regular passes.
alan-baker86ce19c2020-08-05 13:09:19 -0400939 if (auto error = PopulatePassManager(&pm, &binaryStream, &SamplerMapEntries))
alan-bakerf5e5f692018-11-27 08:33:24 -0500940 return error;
alan-bakerfec0a472018-11-08 18:09:40 -0500941 pm.run(*module);
942
943 // Write outputs
alan-bakerfec0a472018-11-08 18:09:40 -0500944 std::error_code error;
alan-bakerfec0a472018-11-08 18:09:40 -0500945
946 // Write the resulting binary.
947 // Wait until now to try writing the file so that we only write it on
948 // successful compilation.
949 if (OutputFilename.empty()) {
Kévin Petite4786902019-04-02 21:51:47 +0100950 if (OutputFormat == "c") {
alan-bakerfec0a472018-11-08 18:09:40 -0500951 OutputFilename = "a.spvinc";
952 } else {
953 OutputFilename = "a.spv";
954 }
955 }
Diego Novillo3cc8d7a2019-04-10 13:30:34 -0400956 llvm::raw_fd_ostream outStream(OutputFilename, error,
957 llvm::sys::fs::FA_Write);
alan-bakerfec0a472018-11-08 18:09:40 -0500958
959 if (error) {
960 llvm::errs() << "Unable to open output file '" << OutputFilename
961 << "': " << error.message() << '\n';
962 return -1;
963 }
964 outStream << binaryStream.str();
965
966 return 0;
967}
alan-bakerf5e5f692018-11-27 08:33:24 -0500968
alan-baker86ce19c2020-08-05 13:09:19 -0400969int CompileFromSourceString(const std::string &program,
970 const std::string &sampler_map,
971 const std::string &options,
Kévin Petit899162d2020-09-08 19:16:08 +0100972 std::vector<uint32_t> *output_binary,
973 std::string *output_log) {
alan-bakerf5e5f692018-11-27 08:33:24 -0500974
975 llvm::SmallVector<const char *, 20> argv;
976 llvm::BumpPtrAllocator A;
977 llvm::StringSaver Saver(A);
978 argv.push_back(Saver.save("clspv").data());
979 llvm::cl::TokenizeGNUCommandLine(options, Saver, argv);
980 int argc = static_cast<int>(argv.size());
Kévin Petitd5db2d22019-04-04 13:55:14 +0100981
982 if (auto error = ParseOptions(argc, &argv[0]))
983 return error;
alan-bakerf5e5f692018-11-27 08:33:24 -0500984
985 llvm::SmallVector<std::pair<unsigned, std::string>, 8> SamplerMapEntries;
986 if (auto error = ParseSamplerMap(sampler_map, &SamplerMapEntries))
987 return error;
988
989 InputFilename = "source.cl";
990 llvm::StringRef overiddenInputFilename = InputFilename.getValue();
991
992 clang::CompilerInstance instance;
alan-bakerd354f1a2019-08-06 15:41:55 -0400993 clang::FrontendInputFile kernelFile(
994 overiddenInputFilename, clang::InputKind(clang::Language::OpenCL));
alan-bakerf5e5f692018-11-27 08:33:24 -0500995 std::string log;
996 llvm::raw_string_ostream diagnosticsStream(log);
997 if (auto error =
998 SetCompilerInstanceOptions(instance, overiddenInputFilename,
999 kernelFile, program, &diagnosticsStream))
1000 return error;
1001
1002 // Parse.
1003 llvm::LLVMContext context;
1004 clang::EmitLLVMOnlyAction action(&context);
1005
1006 // Prepare the action for processing kernelFile
1007 const bool success = action.BeginSourceFile(instance, kernelFile);
1008 if (!success) {
1009 return -1;
1010 }
1011
alan-bakerf3bce4a2019-06-28 16:01:15 -04001012 auto result = action.Execute();
alan-bakerf5e5f692018-11-27 08:33:24 -05001013 action.EndSourceFile();
1014
1015 clang::DiagnosticConsumer *const consumer =
1016 instance.getDiagnostics().getClient();
1017 consumer->finish();
1018
Kévin Petit899162d2020-09-08 19:16:08 +01001019 if (output_log != nullptr) {
1020 *output_log = log;
1021 }
1022
alan-bakerf5e5f692018-11-27 08:33:24 -05001023 auto num_errors = consumer->getNumErrors();
alan-bakerf3bce4a2019-06-28 16:01:15 -04001024 if (result || num_errors > 0) {
alan-bakerf5e5f692018-11-27 08:33:24 -05001025 return -1;
1026 }
1027
alan-bakerf5e5f692018-11-27 08:33:24 -05001028 llvm::PassRegistry &Registry = *llvm::PassRegistry::getPassRegistry();
1029 llvm::initializeCore(Registry);
1030 llvm::initializeScalarOpts(Registry);
Diego Novillo1fcff722019-05-07 13:45:53 -04001031 llvm::initializeClspvPasses(Registry);
alan-bakerf5e5f692018-11-27 08:33:24 -05001032
1033 std::unique_ptr<llvm::Module> module(action.takeModule());
1034
1035 // Optimize.
1036 // Create a memory buffer for temporarily writing the result.
1037 SmallVector<char, 10000> binary;
1038 llvm::raw_svector_ostream binaryStream(binary);
alan-bakerf5e5f692018-11-27 08:33:24 -05001039 llvm::legacy::PassManager pm;
alan-baker86ce19c2020-08-05 13:09:19 -04001040 if (auto error = PopulatePassManager(&pm, &binaryStream, &SamplerMapEntries))
alan-bakerf5e5f692018-11-27 08:33:24 -05001041 return error;
1042 pm.run(*module);
1043
alan-bakerf5e5f692018-11-27 08:33:24 -05001044 // Write the resulting binary.
1045 // Wait until now to try writing the file so that we only write it on
1046 // successful compilation.
1047 assert(output_binary && "Valid binary container is required.");
1048 if (!OutputFilename.empty()) {
1049 llvm::outs()
1050 << "Warning: -o is ignored when binary container is provided.\n";
1051 }
1052 output_binary->resize(binary.size() / 4);
1053 memcpy(output_binary->data(), binary.data(), binary.size());
1054
1055 return 0;
1056}
alan-bakerfec0a472018-11-08 18:09:40 -05001057} // namespace clspv