blob: 40bf8844969e677a200f656b033f9f2e278bde82 [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"
alan-baker869cd682021-03-05 11:21:19 -050022#include "llvm/IR/GlobalValue.h"
alan-bakerfec0a472018-11-08 18:09:40 -050023#include "llvm/IR/LLVMContext.h"
24#include "llvm/IR/LegacyPassManager.h"
25#include "llvm/IR/Module.h"
26#include "llvm/IR/Verifier.h"
alan-baker869cd682021-03-05 11:21:19 -050027#include "llvm/IRReader/IRReader.h"
alan-baker0e64a592019-11-18 13:36:25 -050028#include "llvm/InitializePasses.h"
alan-bakerfec0a472018-11-08 18:09:40 -050029#include "llvm/LinkAllPasses.h"
alan-baker869cd682021-03-05 11:21:19 -050030#include "llvm/Linker/Linker.h"
alan-bakerf5e5f692018-11-27 08:33:24 -050031#include "llvm/Support/Allocator.h"
alan-bakerfec0a472018-11-08 18:09:40 -050032#include "llvm/Support/CommandLine.h"
alan-bakerf5e5f692018-11-27 08:33:24 -050033#include "llvm/Support/ErrorOr.h"
alan-bakerfec0a472018-11-08 18:09:40 -050034#include "llvm/Support/MathExtras.h"
alan-bakerf5e5f692018-11-27 08:33:24 -050035#include "llvm/Support/StringSaver.h"
Diego Novillo89500852019-04-15 08:45:10 -040036#include "llvm/Support/ToolOutputFile.h"
alan-bakerfec0a472018-11-08 18:09:40 -050037#include "llvm/Support/raw_ostream.h"
38#include "llvm/Transforms/IPO/PassManagerBuilder.h"
39
Kévin Petit38c52482019-05-07 20:28:00 +080040#include "clspv/AddressSpace.h"
alan-bakerfec0a472018-11-08 18:09:40 -050041#include "clspv/Option.h"
42#include "clspv/Passes.h"
alan-baker86ce19c2020-08-05 13:09:19 -040043#include "clspv/Sampler.h"
alan-baker869cd682021-03-05 11:21:19 -050044#include "clspv/clspv_builtin_library.h"
alan-bakerfec0a472018-11-08 18:09:40 -050045#include "clspv/opencl_builtins_header.h"
46
alan-baker869cd682021-03-05 11:21:19 -050047#include "Builtins.h"
alan-bakerfec0a472018-11-08 18:09:40 -050048#include "FrontendPlugin.h"
Diego Novilloa4c44fa2019-04-11 10:56:15 -040049#include "Passes.h"
alan-bakerfec0a472018-11-08 18:09:40 -050050
alan-bakerf5e5f692018-11-27 08:33:24 -050051#include <cassert>
alan-bakerfec0a472018-11-08 18:09:40 -050052#include <numeric>
alan-bakerf5e5f692018-11-27 08:33:24 -050053#include <sstream>
Diego Novillo3cc8d7a2019-04-10 13:30:34 -040054#include <string>
alan-bakerfec0a472018-11-08 18:09:40 -050055
56using namespace clang;
57
58namespace {
59// This registration must be located in the same file as the execution of the
60// action.
61static FrontendPluginRegistry::Add<clspv::ExtraValidationASTAction>
62 X("extra-validation",
63 "Perform extra validation on OpenCL C when targeting Vulkan");
64
65static llvm::cl::opt<bool> cl_single_precision_constants(
66 "cl-single-precision-constant", llvm::cl::init(false),
67 llvm::cl::desc("Treat double precision floating-point constant as single "
68 "precision constant."));
69
70static llvm::cl::opt<bool> cl_denorms_are_zero(
71 "cl-denorms-are-zero", llvm::cl::init(false),
72 llvm::cl::desc("If specified, denormalized floating point numbers may be "
73 "flushed to zero."));
74
75static llvm::cl::opt<bool> cl_fp32_correctly_rounded_divide_sqrt(
76 "cl-fp32-correctly-rounded-divide-sqrt", llvm::cl::init(false),
77 llvm::cl::desc("Single precision floating-point divide (x/y and 1/x) and "
78 "sqrt used are correctly rounded."));
79
80static llvm::cl::opt<bool>
81 cl_opt_disable("cl-opt-disable", llvm::cl::init(false),
82 llvm::cl::desc("This option disables all optimizations. The "
83 "default is optimizations are enabled."));
84
85static llvm::cl::opt<bool> cl_mad_enable(
86 "cl-mad-enable", llvm::cl::init(false),
87 llvm::cl::desc("Allow a * b + c to be replaced by a mad. The mad computes "
88 "a * b + c with reduced accuracy."));
89
90static llvm::cl::opt<bool> cl_no_signed_zeros(
91 "cl-no-signed-zeros", llvm::cl::init(false),
92 llvm::cl::desc("Allow optimizations for floating-point arithmetic that "
93 "ignore the signedness of zero."));
94
95static llvm::cl::opt<bool> cl_unsafe_math_optimizations(
96 "cl-unsafe-math-optimizations", llvm::cl::init(false),
97 llvm::cl::desc("Allow optimizations for floating-point arithmetic that (a) "
98 "assume that arguments and results are valid, (b) may "
99 "violate IEEE 754 standard and (c) may violate the OpenCL "
100 "numerical compliance requirements. This option includes "
101 "the -cl-no-signed-zeros and -cl-mad-enable options."));
102
103static llvm::cl::opt<bool> cl_finite_math_only(
104 "cl-finite-math-only", llvm::cl::init(false),
105 llvm::cl::desc("Allow optimizations for floating-point arithmetic that "
106 "assume that arguments and results are not NaNs or INFs."));
107
108static llvm::cl::opt<bool> cl_fast_relaxed_math(
109 "cl-fast-relaxed-math", llvm::cl::init(false),
110 llvm::cl::desc("This option causes the preprocessor macro "
111 "__FAST_RELAXED_MATH__ to be defined. Sets the optimization "
112 "options -cl-finite-math-only and "
113 "-cl-unsafe-math-optimizations."));
114
115static llvm::cl::list<std::string>
116 Includes(llvm::cl::Prefix, "I",
117 llvm::cl::desc("Add a directory to the list of directories "
118 "to be searched for header files."),
119 llvm::cl::ZeroOrMore, llvm::cl::value_desc("include path"));
120
121static llvm::cl::list<std::string>
122 Defines(llvm::cl::Prefix, "D",
123 llvm::cl::desc("Define a #define directive."), llvm::cl::ZeroOrMore,
124 llvm::cl::value_desc("define"));
125
126static llvm::cl::opt<std::string>
127 InputFilename(llvm::cl::Positional, llvm::cl::desc("<input .cl file>"),
128 llvm::cl::init("-"));
129
Kévin Petitddad8f42019-09-30 15:12:08 +0100130static llvm::cl::opt<clang::Language> InputLanguage(
131 "x", llvm::cl::desc("Select input type"),
132 llvm::cl::init(clang::Language::OpenCL),
133 llvm::cl::values(clEnumValN(clang::Language::OpenCL, "cl", "OpenCL source"),
134 clEnumValN(clang::Language::LLVM_IR, "ir", "LLVM IR")));
135
alan-bakerfec0a472018-11-08 18:09:40 -0500136static llvm::cl::opt<std::string>
137 OutputFilename("o", llvm::cl::desc("Override output filename"),
138 llvm::cl::value_desc("filename"));
139
alan-bakerfec0a472018-11-08 18:09:40 -0500140static llvm::cl::opt<char>
141 OptimizationLevel(llvm::cl::Prefix, "O", llvm::cl::init('2'),
142 llvm::cl::desc("Optimization level to use"),
143 llvm::cl::value_desc("level"));
144
alan-bakerfec0a472018-11-08 18:09:40 -0500145static llvm::cl::opt<std::string> OutputFormat(
146 "mfmt", llvm::cl::init(""),
147 llvm::cl::desc(
148 "Specify special output format. 'c' is as a C initializer list"),
149 llvm::cl::value_desc("format"));
150
151static llvm::cl::opt<std::string>
alan-baker09cb9802019-12-10 13:16:27 -0500152 SamplerMap("samplermap", llvm::cl::desc("DEPRECATED - Literal sampler map"),
alan-bakerfec0a472018-11-08 18:09:40 -0500153 llvm::cl::value_desc("filename"));
154
alan-bakerfec0a472018-11-08 18:09:40 -0500155static llvm::cl::opt<bool> verify("verify", llvm::cl::init(false),
156 llvm::cl::desc("Verify diagnostic outputs"));
157
Kévin Petit6b07cbe2019-04-02 21:52:16 +0100158static llvm::cl::opt<bool>
159 IgnoreWarnings("w", llvm::cl::init(false),
160 llvm::cl::desc("Disable all warnings"));
161
162static llvm::cl::opt<bool>
163 WarningsAsErrors("Werror", llvm::cl::init(false),
Diego Novillo3cc8d7a2019-04-10 13:30:34 -0400164 llvm::cl::desc("Turn warnings into errors"));
Kévin Petit6b07cbe2019-04-02 21:52:16 +0100165
Diego Novillo89500852019-04-15 08:45:10 -0400166static llvm::cl::opt<std::string> IROutputFile(
167 "emit-ir",
168 llvm::cl::desc(
169 "Emit LLVM IR to the given file after parsing and stop compilation."),
170 llvm::cl::value_desc("filename"));
171
alan-baker869cd682021-03-05 11:21:19 -0500172namespace {
173struct OpenCLBuiltinMemoryBuffer final : public llvm::MemoryBuffer {
174 OpenCLBuiltinMemoryBuffer(const void *data, uint64_t data_length) {
175 const char *dataCasted = reinterpret_cast<const char *>(data);
176 init(dataCasted, dataCasted + data_length, true);
177 }
178
179 virtual llvm::MemoryBuffer::BufferKind getBufferKind() const override {
180 return llvm::MemoryBuffer::MemoryBuffer_Malloc;
181 }
182
183 virtual ~OpenCLBuiltinMemoryBuffer() override {}
184};
185} // namespace
186
alan-bakerfec0a472018-11-08 18:09:40 -0500187// Populates |SamplerMapEntries| with data from the input sampler map. Returns 0
188// if successful.
alan-bakerf5e5f692018-11-27 08:33:24 -0500189int ParseSamplerMap(const std::string &sampler_map,
190 llvm::SmallVectorImpl<std::pair<unsigned, std::string>>
191 *SamplerMapEntries) {
192 std::unique_ptr<llvm::MemoryBuffer> samplerMapBuffer(nullptr);
193 if (!sampler_map.empty()) {
194 // Parse the sampler map from the provided string.
195 samplerMapBuffer = llvm::MemoryBuffer::getMemBuffer(sampler_map);
196
alan-baker09cb9802019-12-10 13:16:27 -0500197 clspv::Option::SetUseSamplerMap(true);
alan-bakerf5e5f692018-11-27 08:33:24 -0500198 if (!SamplerMap.empty()) {
199 llvm::outs() << "Warning: -samplermap is ignored when the sampler map is "
200 "provided through a string.\n";
201 }
202 } else if (!SamplerMap.empty()) {
203 // Parse the sampler map from the option provided file.
alan-bakerfec0a472018-11-08 18:09:40 -0500204 auto errorOrSamplerMapFile =
205 llvm::MemoryBuffer::getFile(SamplerMap.getValue());
206
207 // If there was an error in getting the sampler map file.
208 if (!errorOrSamplerMapFile) {
209 llvm::errs() << "Error: " << errorOrSamplerMapFile.getError().message()
210 << " '" << SamplerMap.getValue() << "'\n";
211 return -1;
212 }
213
alan-baker09cb9802019-12-10 13:16:27 -0500214 clspv::Option::SetUseSamplerMap(true);
alan-bakerf5e5f692018-11-27 08:33:24 -0500215 samplerMapBuffer = std::move(errorOrSamplerMapFile.get());
alan-bakerfec0a472018-11-08 18:09:40 -0500216 if (0 == samplerMapBuffer->getBufferSize()) {
217 llvm::errs() << "Error: Sampler map was an empty file!\n";
218 return -1;
219 }
alan-bakerf5e5f692018-11-27 08:33:24 -0500220 }
alan-bakerfec0a472018-11-08 18:09:40 -0500221
alan-baker09cb9802019-12-10 13:16:27 -0500222 if (clspv::Option::UseSamplerMap()) {
223 llvm::outs()
224 << "Warning: use of the sampler map is deprecated and unnecessary\n";
225 }
226
alan-bakerf5e5f692018-11-27 08:33:24 -0500227 // No sampler map to parse.
228 if (!samplerMapBuffer || 0 == samplerMapBuffer->getBufferSize())
229 return 0;
alan-bakerfec0a472018-11-08 18:09:40 -0500230
alan-bakerf5e5f692018-11-27 08:33:24 -0500231 llvm::SmallVector<llvm::StringRef, 3> samplerStrings;
alan-bakerfec0a472018-11-08 18:09:40 -0500232
alan-bakerf5e5f692018-11-27 08:33:24 -0500233 // We need to keep track of the beginning of the current entry.
234 const char *b = samplerMapBuffer->getBufferStart();
235 for (const char *i = b, *e = samplerMapBuffer->getBufferEnd();; i++) {
236 // If we have a separator between declarations.
237 if ((*i == '|') || (*i == ',') || (i == e)) {
238 if (i == b) {
239 llvm::errs() << "Error: Sampler map contained an empty entry!\n";
240 return -1;
alan-bakerfec0a472018-11-08 18:09:40 -0500241 }
242
alan-bakerf5e5f692018-11-27 08:33:24 -0500243 samplerStrings.push_back(llvm::StringRef(b, i - b).trim());
alan-bakerfec0a472018-11-08 18:09:40 -0500244
alan-bakerf5e5f692018-11-27 08:33:24 -0500245 // And set b the next character after i.
246 b = i + 1;
247 }
alan-bakerfec0a472018-11-08 18:09:40 -0500248
alan-bakerf5e5f692018-11-27 08:33:24 -0500249 // If we have a separator between declarations within a single sampler.
250 if ((*i == ',') || (i == e)) {
alan-bakerfec0a472018-11-08 18:09:40 -0500251
alan-baker86ce19c2020-08-05 13:09:19 -0400252 clspv::SamplerNormalizedCoords NormalizedCoord =
253 clspv::CLK_NORMALIZED_COORDS_NOT_SET;
254 clspv::SamplerAddressingMode AddressingMode = clspv::CLK_ADDRESS_NOT_SET;
255 clspv::SamplerFilterMode FilterMode = clspv::CLK_FILTER_NOT_SET;
alan-bakerf5e5f692018-11-27 08:33:24 -0500256
257 for (auto str : samplerStrings) {
258 if ("CLK_NORMALIZED_COORDS_FALSE" == str) {
alan-baker86ce19c2020-08-05 13:09:19 -0400259 if (clspv::CLK_NORMALIZED_COORDS_NOT_SET != NormalizedCoord) {
alan-bakerf5e5f692018-11-27 08:33:24 -0500260 llvm::errs() << "Error: Sampler map normalized coordinates was "
261 "previously set!\n";
alan-bakerfec0a472018-11-08 18:09:40 -0500262 return -1;
263 }
alan-baker86ce19c2020-08-05 13:09:19 -0400264 NormalizedCoord = clspv::CLK_NORMALIZED_COORDS_FALSE;
alan-bakerf5e5f692018-11-27 08:33:24 -0500265 } else if ("CLK_NORMALIZED_COORDS_TRUE" == str) {
alan-baker86ce19c2020-08-05 13:09:19 -0400266 if (clspv::CLK_NORMALIZED_COORDS_NOT_SET != NormalizedCoord) {
alan-bakerf5e5f692018-11-27 08:33:24 -0500267 llvm::errs() << "Error: Sampler map normalized coordinates was "
268 "previously set!\n";
269 return -1;
270 }
alan-baker86ce19c2020-08-05 13:09:19 -0400271 NormalizedCoord = clspv::CLK_NORMALIZED_COORDS_TRUE;
alan-bakerf5e5f692018-11-27 08:33:24 -0500272 } else if ("CLK_ADDRESS_NONE" == str) {
alan-baker86ce19c2020-08-05 13:09:19 -0400273 if (clspv::CLK_ADDRESS_NOT_SET != AddressingMode) {
alan-bakerf5e5f692018-11-27 08:33:24 -0500274 llvm::errs()
275 << "Error: Sampler map addressing mode was previously set!\n";
276 return -1;
277 }
alan-baker86ce19c2020-08-05 13:09:19 -0400278 AddressingMode = clspv::CLK_ADDRESS_NONE;
alan-bakerf5e5f692018-11-27 08:33:24 -0500279 } else if ("CLK_ADDRESS_CLAMP_TO_EDGE" == str) {
alan-baker86ce19c2020-08-05 13:09:19 -0400280 if (clspv::CLK_ADDRESS_NOT_SET != AddressingMode) {
alan-bakerf5e5f692018-11-27 08:33:24 -0500281 llvm::errs()
282 << "Error: Sampler map addressing mode was previously set!\n";
283 return -1;
284 }
alan-baker86ce19c2020-08-05 13:09:19 -0400285 AddressingMode = clspv::CLK_ADDRESS_CLAMP_TO_EDGE;
alan-bakerf5e5f692018-11-27 08:33:24 -0500286 } else if ("CLK_ADDRESS_CLAMP" == str) {
alan-baker86ce19c2020-08-05 13:09:19 -0400287 if (clspv::CLK_ADDRESS_NOT_SET != AddressingMode) {
alan-bakerf5e5f692018-11-27 08:33:24 -0500288 llvm::errs()
289 << "Error: Sampler map addressing mode was previously set!\n";
290 return -1;
291 }
alan-baker86ce19c2020-08-05 13:09:19 -0400292 AddressingMode = clspv::CLK_ADDRESS_CLAMP;
alan-bakerf5e5f692018-11-27 08:33:24 -0500293 } else if ("CLK_ADDRESS_MIRRORED_REPEAT" == str) {
alan-baker86ce19c2020-08-05 13:09:19 -0400294 if (clspv::CLK_ADDRESS_NOT_SET != AddressingMode) {
alan-bakerf5e5f692018-11-27 08:33:24 -0500295 llvm::errs()
296 << "Error: Sampler map addressing mode was previously set!\n";
297 return -1;
298 }
alan-baker86ce19c2020-08-05 13:09:19 -0400299 AddressingMode = clspv::CLK_ADDRESS_MIRRORED_REPEAT;
alan-bakerf5e5f692018-11-27 08:33:24 -0500300 } else if ("CLK_ADDRESS_REPEAT" == str) {
alan-baker86ce19c2020-08-05 13:09:19 -0400301 if (clspv::CLK_ADDRESS_NOT_SET != AddressingMode) {
alan-bakerf5e5f692018-11-27 08:33:24 -0500302 llvm::errs()
303 << "Error: Sampler map addressing mode was previously set!\n";
304 return -1;
305 }
alan-baker86ce19c2020-08-05 13:09:19 -0400306 AddressingMode = clspv::CLK_ADDRESS_REPEAT;
alan-bakerf5e5f692018-11-27 08:33:24 -0500307 } else if ("CLK_FILTER_NEAREST" == str) {
alan-baker86ce19c2020-08-05 13:09:19 -0400308 if (clspv::CLK_FILTER_NOT_SET != FilterMode) {
alan-bakerf5e5f692018-11-27 08:33:24 -0500309 llvm::errs()
310 << "Error: Sampler map filtering mode was previously set!\n";
311 return -1;
312 }
alan-baker86ce19c2020-08-05 13:09:19 -0400313 FilterMode = clspv::CLK_FILTER_NEAREST;
alan-bakerf5e5f692018-11-27 08:33:24 -0500314 } else if ("CLK_FILTER_LINEAR" == str) {
alan-baker86ce19c2020-08-05 13:09:19 -0400315 if (clspv::CLK_FILTER_NOT_SET != FilterMode) {
alan-bakerf5e5f692018-11-27 08:33:24 -0500316 llvm::errs()
317 << "Error: Sampler map filtering mode was previously set!\n";
318 return -1;
319 }
alan-baker86ce19c2020-08-05 13:09:19 -0400320 FilterMode = clspv::CLK_FILTER_LINEAR;
alan-bakerf5e5f692018-11-27 08:33:24 -0500321 } else {
322 llvm::errs() << "Error: Unknown sampler string '" << str
323 << "' found!\n";
alan-bakerfec0a472018-11-08 18:09:40 -0500324 return -1;
325 }
alan-bakerfec0a472018-11-08 18:09:40 -0500326 }
327
alan-baker86ce19c2020-08-05 13:09:19 -0400328 if (clspv::CLK_NORMALIZED_COORDS_NOT_SET == NormalizedCoord) {
alan-bakerf5e5f692018-11-27 08:33:24 -0500329 llvm::errs() << "Error: Sampler map entry did not contain normalized "
330 "coordinates entry!\n";
331 return -1;
alan-bakerfec0a472018-11-08 18:09:40 -0500332 }
alan-bakerf5e5f692018-11-27 08:33:24 -0500333
alan-baker86ce19c2020-08-05 13:09:19 -0400334 if (clspv::CLK_ADDRESS_NOT_SET == AddressingMode) {
alan-bakerf5e5f692018-11-27 08:33:24 -0500335 llvm::errs() << "Error: Sampler map entry did not contain addressing "
336 "mode entry!\n";
337 return -1;
338 }
339
alan-baker86ce19c2020-08-05 13:09:19 -0400340 if (clspv::CLK_FILTER_NOT_SET == FilterMode) {
alan-bakerf5e5f692018-11-27 08:33:24 -0500341 llvm::errs()
342 << "Error: Sampler map entry did not contain filer mode entry!\n";
343 return -1;
344 }
345
346 // Generate an equivalent expression in string form. Sort the
347 // strings to get a canonical ordering.
348 std::sort(samplerStrings.begin(), samplerStrings.end(),
349 std::less<StringRef>());
350 const auto samplerExpr = std::accumulate(
351 samplerStrings.begin(), samplerStrings.end(), std::string(),
alan-baker21574d32020-01-29 16:00:31 -0500352 [](llvm::StringRef left, llvm::StringRef right) {
353 return left.str() + std::string(left.empty() ? "" : "|") +
354 right.str();
alan-bakerf5e5f692018-11-27 08:33:24 -0500355 });
356
357 // SamplerMapEntries->push_back(std::make_pair(
358 // NormalizedCoord | AddressingMode | FilterMode, samplerExpr));
359 SamplerMapEntries->emplace_back(
360 NormalizedCoord | AddressingMode | FilterMode, samplerExpr);
361
362 // And reset the sampler strings for the next sampler in the map.
363 samplerStrings.clear();
364 }
365
366 // And lastly, if we are at the end of the file
367 if (i == e) {
368 break;
alan-bakerfec0a472018-11-08 18:09:40 -0500369 }
370 }
371
372 return 0;
373}
374
Kévin Petitaab5bb82021-03-30 16:26:11 +0100375clang::TargetInfo *PrepareTargetInfo(CompilerInstance &instance) {
376 // Create target info
377 auto TargetInfo = clang::TargetInfo::CreateTargetInfo(
378 instance.getDiagnostics(),
379 std::make_shared<clang::TargetOptions>(instance.getTargetOpts()));
380
381 // The SPIR target enables all possible options, disable the ones we don't
382 // want
383 auto &Opts = TargetInfo->getSupportedOpenCLOpts();
384
385 // Conditionally disable extensions based on support
386 if (!clspv::Option::FP16()) {
387 Opts["cl_khr_fp16"] = false;
388 }
389 if (!clspv::Option::FP64()) {
390 Opts["cl_khr_fp64"] = false;
391 }
392
393 // Disable CL3.0 feature macros for unsupported features
394 if (instance.getLangOpts().LangStd == clang::LangStandard::lang_opencl30) {
395
Kévin Petitaab5bb82021-03-30 16:26:11 +0100396 // The following features are never supported
397 Opts["__opencl_c_pipes"] = false;
398 Opts["__opencl_c_generic_address_space"] = false;
Kévin Petitaab5bb82021-03-30 16:26:11 +0100399 Opts["__opencl_c_device_enqueue"] = false;
400 Opts["__opencl_c_program_scope_global_variables"] = false;
401
402 if (!clspv::Option::ImageSupport()) {
403 Opts["__opencl_c_images"] = false;
404 }
405
406 if (!clspv::Option::FP64()) {
407 Opts["__opencl_c_fp64"] = false;
408 }
409 }
410
411 return TargetInfo;
412}
413
alan-bakerfec0a472018-11-08 18:09:40 -0500414// Sets |instance|'s options for compiling. Returns 0 if successful.
415int SetCompilerInstanceOptions(CompilerInstance &instance,
416 const llvm::StringRef &overiddenInputFilename,
417 const clang::FrontendInputFile &kernelFile,
alan-bakerf5e5f692018-11-27 08:33:24 -0500418 const std::string &program,
alan-bakerfec0a472018-11-08 18:09:40 -0500419 llvm::raw_string_ostream *diagnosticsStream) {
alan-bakerf5e5f692018-11-27 08:33:24 -0500420 std::unique_ptr<llvm::MemoryBuffer> memory_buffer(nullptr);
421 llvm::ErrorOr<std::unique_ptr<llvm::MemoryBuffer>> errorOrInputFile(nullptr);
422 if (program.empty()) {
423 auto errorOrInputFile =
424 llvm::MemoryBuffer::getFileOrSTDIN(InputFilename.getValue());
alan-bakerfec0a472018-11-08 18:09:40 -0500425
alan-bakerf5e5f692018-11-27 08:33:24 -0500426 // If there was an error in getting the input file.
427 if (!errorOrInputFile) {
428 llvm::errs() << "Error: " << errorOrInputFile.getError().message() << " '"
429 << InputFilename.getValue() << "'\n";
430 return -1;
431 }
432 memory_buffer.reset(errorOrInputFile.get().release());
433 } else {
434 memory_buffer = llvm::MemoryBuffer::getMemBuffer(program.c_str(),
435 overiddenInputFilename);
alan-bakerfec0a472018-11-08 18:09:40 -0500436 }
alan-bakerf5e5f692018-11-27 08:33:24 -0500437
alan-bakerfec0a472018-11-08 18:09:40 -0500438 if (verify) {
439 instance.getDiagnosticOpts().VerifyDiagnostics = true;
alan-bakerbccf62c2019-03-29 10:32:41 -0400440 instance.getDiagnosticOpts().VerifyPrefixes.push_back("expected");
alan-bakerfec0a472018-11-08 18:09:40 -0500441 }
442
Kévin Petit0fc88042019-04-09 23:25:02 +0100443 clang::LangStandard::Kind standard;
Kévin Petitf0515712020-01-07 18:29:20 +0000444 switch (clspv::Option::Language()) {
445 case clspv::Option::SourceLanguage::OpenCL_C_10:
446 standard = clang::LangStandard::lang_opencl10;
447 break;
448 case clspv::Option::SourceLanguage::OpenCL_C_11:
449 standard = clang::LangStandard::lang_opencl11;
450 break;
451 case clspv::Option::SourceLanguage::OpenCL_C_12:
Kévin Petit0fc88042019-04-09 23:25:02 +0100452 standard = clang::LangStandard::lang_opencl12;
Kévin Petitf0515712020-01-07 18:29:20 +0000453 break;
454 case clspv::Option::SourceLanguage::OpenCL_C_20:
455 standard = clang::LangStandard::lang_opencl20;
456 break;
Kévin Petit77838ff2020-10-19 18:54:51 +0100457 case clspv::Option::SourceLanguage::OpenCL_C_30:
458 standard = clang::LangStandard::lang_opencl30;
459 break;
Kévin Petitf0515712020-01-07 18:29:20 +0000460 case clspv::Option::SourceLanguage::OpenCL_CPP:
alan-baker39706812021-08-03 13:21:39 -0400461 standard = clang::LangStandard::lang_openclcpp10;
Kévin Petitf0515712020-01-07 18:29:20 +0000462 break;
463 default:
464 llvm_unreachable("Unknown source language");
Kévin Petit0fc88042019-04-09 23:25:02 +0100465 }
alan-bakerfec0a472018-11-08 18:09:40 -0500466
alan-bakerfec0a472018-11-08 18:09:40 -0500467 instance.getLangOpts().C99 = true;
468 instance.getLangOpts().RTTI = false;
469 instance.getLangOpts().RTTIData = false;
470 instance.getLangOpts().MathErrno = false;
471 instance.getLangOpts().Optimize = false;
472 instance.getLangOpts().NoBuiltin = true;
473 instance.getLangOpts().ModulesSearchAll = false;
474 instance.getLangOpts().SinglePrecisionConstants = true;
475 instance.getCodeGenOpts().StackRealignment = true;
476 instance.getCodeGenOpts().SimplifyLibCalls = false;
477 instance.getCodeGenOpts().EmitOpenCLArgMetadata = false;
478 instance.getCodeGenOpts().DisableO0ImplyOptNone = true;
Kévin Petit6b07cbe2019-04-02 21:52:16 +0100479 instance.getDiagnosticOpts().IgnoreWarnings = IgnoreWarnings;
alan-bakerfec0a472018-11-08 18:09:40 -0500480
481 instance.getLangOpts().SinglePrecisionConstants =
482 cl_single_precision_constants;
483 // cl_denorms_are_zero ignored for now!
484 // cl_fp32_correctly_rounded_divide_sqrt ignored for now!
485 instance.getCodeGenOpts().LessPreciseFPMAD =
486 cl_mad_enable || cl_unsafe_math_optimizations;
487 // cl_no_signed_zeros ignored for now!
alan-baker869cd682021-03-05 11:21:19 -0500488 instance.getLangOpts().UnsafeFPMath = cl_unsafe_math_optimizations ||
489 cl_fast_relaxed_math ||
490 clspv::Option::NativeMath();
491 instance.getLangOpts().FiniteMathOnly = cl_finite_math_only ||
492 cl_fast_relaxed_math ||
493 clspv::Option::NativeMath();
494 instance.getLangOpts().FastRelaxedMath =
495 cl_fast_relaxed_math || clspv::Option::NativeMath();
alan-bakerfec0a472018-11-08 18:09:40 -0500496
497 // Preprocessor options
Kévin Petita624c0c2019-05-07 20:27:43 +0800498 if (!clspv::Option::ImageSupport()) {
499 instance.getPreprocessorOpts().addMacroUndef("__IMAGE_SUPPORT__");
500 }
alan-baker869cd682021-03-05 11:21:19 -0500501 if (cl_fast_relaxed_math || clspv::Option::NativeMath()) {
alan-bakerfec0a472018-11-08 18:09:40 -0500502 instance.getPreprocessorOpts().addMacroDef("__FAST_RELAXED_MATH__");
503 }
504
505 for (auto define : Defines) {
506 instance.getPreprocessorOpts().addMacroDef(define);
507 }
508
509 // Header search options
510 for (auto include : Includes) {
511 instance.getHeaderSearchOpts().AddPath(include, clang::frontend::After,
512 false, false);
513 }
514
515 // We always compile on opt 0 so we preserve as much debug information about
516 // the source as possible. We'll run optimization later, once we've had a
517 // chance to view the unoptimal code first
518 instance.getCodeGenOpts().OptimizationLevel = 0;
519
520// Debug information is disabled temporarily to call instruction.
521#if 0
522 instance.getCodeGenOpts().setDebugInfo(clang::codegenoptions::FullDebugInfo);
523#endif
524
525 // We use the 32-bit pointer-width SPIR triple
526 llvm::Triple triple("spir-unknown-unknown");
527
James Price40efe7f2021-01-18 09:19:31 -0500528 // We manually include the OpenCL headers below, so this vector is unused.
529 std::vector<std::string> includes;
530
alan-bakerfec0a472018-11-08 18:09:40 -0500531 instance.getInvocation().setLangDefaults(
alan-bakerd354f1a2019-08-06 15:41:55 -0400532 instance.getLangOpts(), clang::InputKind(clang::Language::OpenCL), triple,
James Price40efe7f2021-01-18 09:19:31 -0500533 includes, standard);
alan-bakerfec0a472018-11-08 18:09:40 -0500534
535 // Override the C99 inline semantics to accommodate for more OpenCL C
536 // programs in the wild.
537 instance.getLangOpts().GNUInline = true;
Kévin Petit6b07cbe2019-04-02 21:52:16 +0100538
539 // Set up diagnostics
alan-bakerfec0a472018-11-08 18:09:40 -0500540 instance.createDiagnostics(
541 new clang::TextDiagnosticPrinter(*diagnosticsStream,
542 &instance.getDiagnosticOpts()),
543 true);
Kévin Petit6b07cbe2019-04-02 21:52:16 +0100544 instance.getDiagnostics().setWarningsAsErrors(WarningsAsErrors);
545 instance.getDiagnostics().setEnableAllWarnings(true);
alan-bakerfec0a472018-11-08 18:09:40 -0500546
547 instance.getTargetOpts().Triple = triple.str();
548
alan-baker21574d32020-01-29 16:00:31 -0500549 instance.getCodeGenOpts().MainFileName = overiddenInputFilename.str();
alan-bakerfec0a472018-11-08 18:09:40 -0500550 instance.getCodeGenOpts().PreserveVec3Type = true;
551 // Disable generation of lifetime intrinsic.
552 instance.getCodeGenOpts().DisableLifetimeMarkers = true;
553 instance.getFrontendOpts().Inputs.push_back(kernelFile);
alan-bakerf5e5f692018-11-27 08:33:24 -0500554 instance.getPreprocessorOpts().addRemappedFile(overiddenInputFilename,
555 memory_buffer.release());
alan-bakerfec0a472018-11-08 18:09:40 -0500556
alan-bakerfec0a472018-11-08 18:09:40 -0500557 std::unique_ptr<llvm::MemoryBuffer> openCLBuiltinMemoryBuffer(
558 new OpenCLBuiltinMemoryBuffer(opencl_builtins_header_data,
559 opencl_builtins_header_size - 1));
560
James Price40efe7f2021-01-18 09:19:31 -0500561 instance.getPreprocessorOpts().Includes.push_back("opencl-c.h");
alan-bakerfec0a472018-11-08 18:09:40 -0500562
alan-bakerf3bce4a2019-06-28 16:01:15 -0400563 std::unique_ptr<llvm::MemoryBuffer> openCLBaseBuiltinMemoryBuffer(
564 new OpenCLBuiltinMemoryBuffer(opencl_base_builtins_header_data,
565 opencl_base_builtins_header_size - 1));
566
567 instance.getPreprocessorOpts().Includes.push_back("opencl-c-base.h");
568
alan-bakerfec0a472018-11-08 18:09:40 -0500569 // Add the VULKAN macro.
570 instance.getPreprocessorOpts().addMacroDef("VULKAN=100");
571
572 // Add the __OPENCL_VERSION__ macro.
573 instance.getPreprocessorOpts().addMacroDef("__OPENCL_VERSION__=120");
574
Kévin Petitaab5bb82021-03-30 16:26:11 +0100575 instance.setTarget(PrepareTargetInfo(instance));
alan-bakerfec0a472018-11-08 18:09:40 -0500576
577 instance.createFileManager();
578 instance.createSourceManager(instance.getFileManager());
579
580#ifdef _MSC_VER
581 std::string includePrefix("include\\");
582#else
583 std::string includePrefix("include/");
584#endif
585
586 auto entry = instance.getFileManager().getVirtualFile(
James Price40efe7f2021-01-18 09:19:31 -0500587 includePrefix + "opencl-c.h", openCLBuiltinMemoryBuffer->getBufferSize(),
alan-bakerfec0a472018-11-08 18:09:40 -0500588 0);
589
590 instance.getSourceManager().overrideFileContents(
591 entry, std::move(openCLBuiltinMemoryBuffer));
592
alan-bakerf3bce4a2019-06-28 16:01:15 -0400593 auto base_entry = instance.getFileManager().getVirtualFile(
594 includePrefix + "opencl-c-base.h",
595 openCLBaseBuiltinMemoryBuffer->getBufferSize(), 0);
596
597 instance.getSourceManager().overrideFileContents(
598 base_entry, std::move(openCLBaseBuiltinMemoryBuffer));
599
alan-bakerfec0a472018-11-08 18:09:40 -0500600 return 0;
601}
602
alan-bakerf5e5f692018-11-27 08:33:24 -0500603// Populates |pm| with necessary passes to optimize and legalize the IR.
604int PopulatePassManager(
605 llvm::legacy::PassManager *pm, llvm::raw_svector_ostream *binaryStream,
alan-bakerf5e5f692018-11-27 08:33:24 -0500606 llvm::SmallVectorImpl<std::pair<unsigned, std::string>>
607 *SamplerMapEntries) {
alan-bakerfec0a472018-11-08 18:09:40 -0500608 llvm::PassManagerBuilder pmBuilder;
609
610 switch (OptimizationLevel) {
611 case '0':
alan-bakerf5e5f692018-11-27 08:33:24 -0500612 case '1':
613 case '2':
614 case '3':
615 case 's':
616 case 'z':
617 break;
618 default:
619 llvm::errs() << "Unknown optimization level -O" << OptimizationLevel
620 << " specified!\n";
621 return -1;
622 }
623
624 switch (OptimizationLevel) {
625 case '0':
alan-bakerfec0a472018-11-08 18:09:40 -0500626 pmBuilder.OptLevel = 0;
627 break;
628 case '1':
629 pmBuilder.OptLevel = 1;
630 break;
631 case '2':
632 pmBuilder.OptLevel = 2;
633 break;
634 case '3':
635 pmBuilder.OptLevel = 3;
636 break;
637 case 's':
638 pmBuilder.SizeLevel = 1;
639 break;
640 case 'z':
641 pmBuilder.SizeLevel = 2;
642 break;
643 default:
644 break;
645 }
646
alan-baker869cd682021-03-05 11:21:19 -0500647 pm->add(clspv::createNativeMathPass());
alan-bakerfec0a472018-11-08 18:09:40 -0500648 pm->add(clspv::createZeroInitializeAllocasPass());
alan-baker04f3a952020-03-24 10:39:53 -0400649 pm->add(clspv::createAddFunctionAttributesPass());
alan-bakerc4579bb2020-04-29 14:15:50 -0400650 pm->add(clspv::createAutoPodArgsPass());
Kévin Petitbbbda972020-03-03 19:16:31 +0000651 pm->add(clspv::createDeclarePushConstantsPass());
alan-bakerfec0a472018-11-08 18:09:40 -0500652 pm->add(clspv::createDefineOpenCLWorkItemBuiltinsPass());
653
654 if (0 < pmBuilder.OptLevel) {
655 pm->add(clspv::createOpenCLInlinerPass());
656 }
657
658 pm->add(clspv::createUndoByvalPass());
659 pm->add(clspv::createUndoSRetPass());
alan-baker9b0ec3c2020-04-06 14:45:34 -0400660 if (clspv::Option::ClusterPodKernelArgs()) {
alan-bakerfec0a472018-11-08 18:09:40 -0500661 pm->add(clspv::createClusterPodKernelArgumentsPass());
662 }
663 pm->add(clspv::createReplaceOpenCLBuiltinPass());
664
Marco Antognini535998c2020-09-16 18:48:51 +0100665 // Lower longer vectors when requested. Note that this pass depends on
666 // ReplaceOpenCLBuiltinPass and expects DeadCodeEliminationPass to be run
667 // afterwards.
668 if (clspv::Option::LongVectorSupport()) {
669 pm->add(clspv::createLongVectorLoweringPass());
670 }
671
alan-bakerfec0a472018-11-08 18:09:40 -0500672 // We need to run mem2reg and inst combine early because our
673 // createInlineFuncWithPointerBitCastArgPass pass cannot handle the pattern
674 // %1 = alloca i32 1
675 // store <something> %1
676 // %2 = bitcast float* %1
677 // %3 = load float %2
678 pm->add(llvm::createPromoteMemoryToRegisterPass());
679
alan-baker1b13e8f2019-08-08 17:56:51 -0400680 // Try to deal with pointer bitcasts early. This can prevent problems like
681 // issue #409 where LLVM is looser about access chain addressing than SPIR-V.
682 // This needs to happen before instcombine and after replacing OpenCL
683 // builtins. This run of the pass will not handle all pointer bitcasts that
684 // could be handled. It should be run again after other optimizations (e.g
685 // InlineFuncWithPointerBitCastArgPass).
686 pm->add(clspv::createSimplifyPointerBitcastPass());
687 pm->add(clspv::createReplacePointerBitcastPass());
688 pm->add(llvm::createDeadCodeEliminationPass());
689
alan-bakerfec0a472018-11-08 18:09:40 -0500690 // Hide loads from __constant address space away from instcombine.
691 // This prevents us from generating select between pointers-to-__constant.
692 // See https://github.com/google/clspv/issues/71
693 pm->add(clspv::createHideConstantLoadsPass());
694
695 pm->add(llvm::createInstructionCombiningPass());
696
697 if (clspv::Option::InlineEntryPoints()) {
698 pm->add(clspv::createInlineEntryPointsPass());
699 } else {
700 pm->add(clspv::createInlineFuncWithPointerBitCastArgPass());
701 pm->add(clspv::createInlineFuncWithPointerToFunctionArgPass());
702 pm->add(clspv::createInlineFuncWithSingleCallSitePass());
703 }
704
Kévin Petitf0515712020-01-07 18:29:20 +0000705 if (clspv::Option::LanguageUsesGenericAddressSpace()) {
Kévin Petit38c52482019-05-07 20:28:00 +0800706 pm->add(llvm::createInferAddressSpacesPass(clspv::AddressSpace::Generic));
Kévin Petit0fc88042019-04-09 23:25:02 +0100707 }
708
alan-bakerfec0a472018-11-08 18:09:40 -0500709 if (0 == pmBuilder.OptLevel) {
710 // Mem2Reg pass should be run early because O0 level optimization leaves
711 // redundant alloca, load and store instructions from function arguments.
712 // clspv needs to remove them ahead of transformation.
713 pm->add(llvm::createPromoteMemoryToRegisterPass());
714
715 // SROA pass is run because it will fold structs/unions that are problematic
716 // on Vulkan SPIR-V away.
717 pm->add(llvm::createSROAPass());
718
719 // InstructionCombining pass folds bitcast and gep instructions which are
720 // not supported by Vulkan SPIR-V.
721 pm->add(llvm::createInstructionCombiningPass());
722 }
723
724 // Now we add any of the LLVM optimizations we wanted
725 pmBuilder.populateModulePassManager(*pm);
726
alan-bakerb5e74d62020-04-07 20:38:05 -0400727 // No point attempting to handle freeze currently so strip them from the IR.
728 pm->add(clspv::createStripFreezePass());
729
alan-bakerfec0a472018-11-08 18:09:40 -0500730 // Unhide loads from __constant address space. Undoes the action of
731 // HideConstantLoadsPass.
732 pm->add(clspv::createUnhideConstantLoadsPass());
733
alan-baker13568382020-04-02 17:29:27 -0400734 pm->add(clspv::createUndoInstCombinePass());
alan-bakerfec0a472018-11-08 18:09:40 -0500735 pm->add(clspv::createFunctionInternalizerPass());
736 pm->add(clspv::createReplaceLLVMIntrinsicsPass());
alan-bakerad1a12f2020-08-25 09:18:38 -0400737 // Replace LLVM intrinsics can leave dead code around.
738 pm->add(llvm::createDeadCodeEliminationPass());
alan-bakerfec0a472018-11-08 18:09:40 -0500739 pm->add(clspv::createUndoBoolPass());
alan-bakere711c762020-05-20 17:56:59 -0400740 pm->add(clspv::createUndoTruncateToOddIntegerPass());
alan-bakerfec0a472018-11-08 18:09:40 -0500741 pm->add(llvm::createStructurizeCFGPass(false));
alan-baker3fa76d92018-11-12 14:54:40 -0500742 // Must be run after structurize cfg.
alan-baker9580aef2020-01-07 22:31:48 -0500743 pm->add(clspv::createFixupStructuredCFGPass());
744 // Must be run after structured cfg fixup.
alan-bakerfec0a472018-11-08 18:09:40 -0500745 pm->add(clspv::createReorderBasicBlocksPass());
746 pm->add(clspv::createUndoGetElementPtrConstantExprPass());
747 pm->add(clspv::createSplatArgPass());
748 pm->add(clspv::createSimplifyPointerBitcastPass());
749 pm->add(clspv::createReplacePointerBitcastPass());
750
751 pm->add(clspv::createUndoTranslateSamplerFoldPass());
752
753 if (clspv::Option::ModuleConstantsInStorageBuffer()) {
754 pm->add(clspv::createClusterModuleScopeConstantVars());
755 }
756
757 pm->add(clspv::createShareModuleScopeVariablesPass());
alan-bakerf67468c2019-11-25 15:51:49 -0500758 // Specialize images before assigning descriptors to disambiguate the various
759 // types.
760 pm->add(clspv::createSpecializeImageTypesPass());
alan-bakere9308012019-03-15 10:25:13 -0400761 // This should be run after LLVM and OpenCL intrinsics are replaced.
alan-bakerfec0a472018-11-08 18:09:40 -0500762 pm->add(clspv::createAllocateDescriptorsPass(*SamplerMapEntries));
763 pm->add(llvm::createVerifierPass());
764 pm->add(clspv::createDirectResourceAccessPass());
765 // Replacing pointer bitcasts can leave some trivial GEPs
766 // that are easy to remove. Also replace GEPs of GEPS
767 // left by replacing indirect buffer accesses.
768 pm->add(clspv::createSimplifyPointerBitcastPass());
alan-baker4217b322019-03-06 08:56:12 -0500769 // Run after DRA to clean up parameters and help reduce the need for variable
770 // pointers.
771 pm->add(clspv::createRemoveUnusedArgumentsPass());
alan-bakerfec0a472018-11-08 18:09:40 -0500772
alan-baker3f772c02021-06-15 22:18:11 -0400773 // SPIR-V 1.4 and higher do not need to splat scalar conditions for vector
774 // data.
775 if (clspv::Option::SpvVersion() < clspv::Option::SPIRVVersion::SPIRV_1_4) {
776 pm->add(clspv::createSplatSelectConditionPass());
777 }
alan-bakerfec0a472018-11-08 18:09:40 -0500778 pm->add(clspv::createSignedCompareFixupPass());
779 // This pass generates insertions that need to be rewritten.
780 pm->add(clspv::createScalarizePass());
781 pm->add(clspv::createRewriteInsertsPass());
alan-bakera71f1932019-04-11 11:04:34 -0400782 // UBO Transformations
783 if (clspv::Option::ConstantArgsInUniformBuffer() &&
784 !clspv::Option::InlineEntryPoints()) {
785 // MultiVersionUBOFunctionsPass will examine non-kernel functions with UBO
786 // arguments and either multi-version them as necessary or inline them if
787 // multi-versioning cannot be accomplished.
788 pm->add(clspv::createMultiVersionUBOFunctionsPass());
789 // Cleanup passes.
790 // Specialization can blindly generate GEP chains that are easily cleaned up
791 // by SimplifyPointerBitcastPass.
792 pm->add(clspv::createSimplifyPointerBitcastPass());
793 // RemoveUnusedArgumentsPass removes the actual UBO arguments that were
794 // problematic to begin with now that they have no uses.
795 pm->add(clspv::createRemoveUnusedArgumentsPass());
796 // DCE cleans up callers of the specialized functions.
797 pm->add(llvm::createDeadCodeEliminationPass());
798 }
alan-bakerfec0a472018-11-08 18:09:40 -0500799 // This pass mucks with types to point where you shouldn't rely on DataLayout
800 // anymore so leave this right before SPIR-V generation.
801 pm->add(clspv::createUBOTypeTransformPass());
alan-baker3f772c02021-06-15 22:18:11 -0400802 pm->add(clspv::createSPIRVProducerPass(binaryStream, SamplerMapEntries,
alan-baker00e7a582019-06-07 12:54:21 -0400803 OutputFormat == "c"));
alan-bakerf5e5f692018-11-27 08:33:24 -0500804
805 return 0;
alan-bakerfec0a472018-11-08 18:09:40 -0500806}
alan-bakerfec0a472018-11-08 18:09:40 -0500807
Kévin Petitd5db2d22019-04-04 13:55:14 +0100808int ParseOptions(const int argc, const char *const argv[]) {
alan-baker227e9782020-06-02 15:35:37 -0400809 // We need to change how some of the called passes works by spoofing
810 // ParseCommandLineOptions with the specific options.
811 bool has_pre = false;
812 bool has_load_pre = false;
813 const std::string pre = "-enable-pre";
814 const std::string load_pre = "-enable-load-pre";
815 for (int i = 1; i < argc; ++i) {
816 std::string option(argv[i]);
817 auto pre_pos = option.find(pre);
818 auto load_pos = option.find(load_pre);
819 if (pre_pos == 0 || (pre_pos == 1 && option[0] == '-')) {
820 has_pre = true;
821 } else if (load_pos == 0 || (load_pos == 1 && option[0] == '-')) {
822 has_load_pre = true;
823 }
824 }
825
alan-baker1b333b62021-05-31 14:55:32 -0400826 int llvmArgc = 3;
827 const char *llvmArgv[5];
alan-baker227e9782020-06-02 15:35:37 -0400828 llvmArgv[0] = argv[0];
829 llvmArgv[1] = "-simplifycfg-sink-common=false";
alan-baker1b333b62021-05-31 14:55:32 -0400830 // TODO(#738): find a better solution to this.
831 llvmArgv[2] = "-disable-vector-combine";
alan-baker227e9782020-06-02 15:35:37 -0400832 if (!has_pre) {
833 llvmArgv[llvmArgc++] = "-enable-pre=0";
834 }
835 if (!has_load_pre) {
836 llvmArgv[llvmArgc++] = "-enable-load-pre=0";
837 }
alan-bakerfec0a472018-11-08 18:09:40 -0500838
Kévin Petitd5db2d22019-04-04 13:55:14 +0100839 llvm::cl::ResetAllOptionOccurrences();
alan-bakerfec0a472018-11-08 18:09:40 -0500840 llvm::cl::ParseCommandLineOptions(llvmArgc, llvmArgv);
alan-bakerfec0a472018-11-08 18:09:40 -0500841 llvm::cl::ParseCommandLineOptions(argc, argv);
842
Kévin Petitf0515712020-01-07 18:29:20 +0000843 if (clspv::Option::LanguageUsesGenericAddressSpace() &&
844 !clspv::Option::InlineEntryPoints()) {
845 llvm::errs() << "cannot compile languages that use the generic address "
846 "space (e.g. CLC++, CL2.0) without -inline-entry-points\n";
Kévin Petit0fc88042019-04-09 23:25:02 +0100847 return -1;
848 }
849
Kévin Petitbbbda972020-03-03 19:16:31 +0000850 if (clspv::Option::ScalarBlockLayout()) {
851 llvm::errs() << "scalar block layout support unimplemented\n";
852 return -1;
853 }
854
alan-baker9b0ec3c2020-04-06 14:45:34 -0400855 // Push constant option validation.
856 if (clspv::Option::PodArgsInPushConstants()) {
857 if (clspv::Option::PodArgsInUniformBuffer()) {
858 llvm::errs() << "POD arguments can only be in either uniform buffers or "
859 "push constants\n";
860 return -1;
861 }
862
863 if (!clspv::Option::ClusterPodKernelArgs()) {
864 llvm::errs()
865 << "POD arguments must be clustered to be passed as push constants\n";
866 return -1;
867 }
868
869 // Conservatively error if a module scope push constant could be used.
James Price708cf362020-05-06 19:33:45 -0400870 if (clspv::Option::GlobalOffsetPushConstant() ||
alan-baker9b0ec3c2020-04-06 14:45:34 -0400871 clspv::Option::Language() ==
872 clspv::Option::SourceLanguage::OpenCL_C_20 ||
873 clspv::Option::Language() ==
874 clspv::Option::SourceLanguage::OpenCL_CPP) {
875 llvm::errs() << "POD arguments as push constants are not compatible with "
876 "module scope push constants\n";
877 return -1;
878 }
879 }
880
Mehmet Oguz Derin047cc872021-04-15 19:56:41 +0300881 if (clspv::Option::ArmNonUniformWorkGroupSize() &&
882 clspv::Option::UniformWorkgroupSize()) {
883 llvm::errs() << "cannot enable Arm non-uniform workgroup extension support "
884 "and assume uniform workgroup sizes\n";
885 return -1;
886 }
887
Kévin Petitd5db2d22019-04-04 13:55:14 +0100888 return 0;
889}
Diego Novillo89500852019-04-15 08:45:10 -0400890
891int GenerateIRFile(llvm::legacy::PassManager *pm, llvm::Module &module,
892 std::string output) {
893 std::error_code ec;
894 std::unique_ptr<llvm::ToolOutputFile> out(
Natalie Chouinard058da872021-06-17 12:32:47 -0400895 new llvm::ToolOutputFile(output, ec, llvm::sys::fs::OF_None));
Diego Novillo89500852019-04-15 08:45:10 -0400896 if (ec) {
897 llvm::errs() << output << ": " << ec.message() << '\n';
898 return -1;
899 }
900 pm->add(llvm::createPrintModulePass(out->os(), "", false));
901 pm->run(module);
902 out->keep();
903 return 0;
904}
905
alan-baker869cd682021-03-05 11:21:19 -0500906bool LinkBuiltinLibrary(llvm::Module *module) {
907 std::unique_ptr<llvm::MemoryBuffer> buffer(new OpenCLBuiltinMemoryBuffer(
908 clspv_builtin_library_data, clspv_builtin_library_size - 1));
909
910 llvm::SMDiagnostic Err;
911 auto library = llvm::parseIR(*buffer, Err, module->getContext());
912 if (!library) {
913 llvm::errs() << "Failed to parse builtins library\n";
914 return false;
915 }
916
917 // TODO: when clang generates builtins using the generic address space,
918 // different builtins are used for pointer-based builtins. Need to do some
919 // work to ensure they are kept around.
920 // Affects: modf, remquo, lgamma_r, frexp
921
922 llvm::Linker L(*module);
923 L.linkInModule(std::move(library), 0);
924
925 return true;
926}
927
Kévin Petitd5db2d22019-04-04 13:55:14 +0100928} // namespace
929
930namespace clspv {
931int Compile(const int argc, const char *const argv[]) {
932
933 if (auto error = ParseOptions(argc, argv))
934 return error;
935
alan-bakerfec0a472018-11-08 18:09:40 -0500936 llvm::SmallVector<std::pair<unsigned, std::string>, 8> SamplerMapEntries;
alan-bakerf5e5f692018-11-27 08:33:24 -0500937 if (auto error = ParseSamplerMap("", &SamplerMapEntries))
alan-bakerfec0a472018-11-08 18:09:40 -0500938 return error;
939
940 // if no output file was provided, use a default
941 llvm::StringRef overiddenInputFilename = InputFilename.getValue();
942
943 // If we are reading our input file from stdin.
944 if ("-" == InputFilename) {
945 // We need to overwrite the file name we use.
Kévin Petitddad8f42019-09-30 15:12:08 +0100946 switch (InputLanguage) {
947 case clang::Language::OpenCL:
948 overiddenInputFilename = "stdin.cl";
949 break;
950 case clang::Language::LLVM_IR:
951 overiddenInputFilename = "stdin.ll";
952 break;
alan-baker31298a62019-10-07 13:24:30 -0400953 default:
954 // Default to fix compiler warnings/errors. Option parsing will reject a
955 // bad enum value for the option so there is no need for a message.
956 return -1;
Kévin Petitddad8f42019-09-30 15:12:08 +0100957 }
alan-bakerfec0a472018-11-08 18:09:40 -0500958 }
959
960 clang::CompilerInstance instance;
Kévin Petitddad8f42019-09-30 15:12:08 +0100961 clang::FrontendInputFile kernelFile(overiddenInputFilename,
962 clang::InputKind(InputLanguage));
alan-bakerfec0a472018-11-08 18:09:40 -0500963 std::string log;
964 llvm::raw_string_ostream diagnosticsStream(log);
alan-bakerf5e5f692018-11-27 08:33:24 -0500965 if (auto error = SetCompilerInstanceOptions(
966 instance, overiddenInputFilename, kernelFile, "", &diagnosticsStream))
alan-bakerfec0a472018-11-08 18:09:40 -0500967 return error;
968
969 // Parse.
970 llvm::LLVMContext context;
971 clang::EmitLLVMOnlyAction action(&context);
972
973 // Prepare the action for processing kernelFile
974 const bool success = action.BeginSourceFile(instance, kernelFile);
975 if (!success) {
976 return -1;
977 }
978
alan-bakerf3bce4a2019-06-28 16:01:15 -0400979 auto result = action.Execute();
alan-bakerfec0a472018-11-08 18:09:40 -0500980 action.EndSourceFile();
981
982 clang::DiagnosticConsumer *const consumer =
983 instance.getDiagnostics().getClient();
984 consumer->finish();
985
Kévin Petit6b07cbe2019-04-02 21:52:16 +0100986 auto num_warnings = consumer->getNumWarnings();
alan-bakerfec0a472018-11-08 18:09:40 -0500987 auto num_errors = consumer->getNumErrors();
Kévin Petit6b07cbe2019-04-02 21:52:16 +0100988 if ((num_errors > 0) || (num_warnings > 0)) {
989 llvm::errs() << log;
990 }
alan-bakerf3bce4a2019-06-28 16:01:15 -0400991 if (result || num_errors > 0) {
alan-bakerfec0a472018-11-08 18:09:40 -0500992 return -1;
993 }
994
Kévin Petit6b07cbe2019-04-02 21:52:16 +0100995 // Don't run the passes or produce any output in verify mode.
996 // Clang doesn't always produce a valid module.
997 if (verify) {
998 return 0;
999 }
1000
alan-bakerfec0a472018-11-08 18:09:40 -05001001 llvm::PassRegistry &Registry = *llvm::PassRegistry::getPassRegistry();
1002 llvm::initializeCore(Registry);
1003 llvm::initializeScalarOpts(Registry);
Diego Novillo1fcff722019-05-07 13:45:53 -04001004 llvm::initializeClspvPasses(Registry);
alan-bakerfec0a472018-11-08 18:09:40 -05001005
1006 std::unique_ptr<llvm::Module> module(action.takeModule());
1007
1008 // Optimize.
1009 // Create a memory buffer for temporarily writing the result.
1010 SmallVector<char, 10000> binary;
1011 llvm::raw_svector_ostream binaryStream(binary);
alan-bakerfec0a472018-11-08 18:09:40 -05001012 llvm::legacy::PassManager pm;
Diego Novillo89500852019-04-15 08:45:10 -04001013
1014 // If --emit-ir was requested, emit the initial LLVM IR and stop compilation.
1015 if (!IROutputFile.empty()) {
1016 return GenerateIRFile(&pm, *module, IROutputFile);
1017 }
1018
alan-baker869cd682021-03-05 11:21:19 -05001019 if (!LinkBuiltinLibrary(module.get())) {
1020 return -1;
1021 }
1022
Diego Novillo89500852019-04-15 08:45:10 -04001023 // Otherwise, populate the pass manager and run the regular passes.
alan-baker86ce19c2020-08-05 13:09:19 -04001024 if (auto error = PopulatePassManager(&pm, &binaryStream, &SamplerMapEntries))
alan-bakerf5e5f692018-11-27 08:33:24 -05001025 return error;
alan-bakerfec0a472018-11-08 18:09:40 -05001026 pm.run(*module);
1027
1028 // Write outputs
alan-bakerfec0a472018-11-08 18:09:40 -05001029 std::error_code error;
alan-bakerfec0a472018-11-08 18:09:40 -05001030
1031 // Write the resulting binary.
1032 // Wait until now to try writing the file so that we only write it on
1033 // successful compilation.
1034 if (OutputFilename.empty()) {
Kévin Petite4786902019-04-02 21:51:47 +01001035 if (OutputFormat == "c") {
alan-bakerfec0a472018-11-08 18:09:40 -05001036 OutputFilename = "a.spvinc";
1037 } else {
1038 OutputFilename = "a.spv";
1039 }
1040 }
Diego Novillo3cc8d7a2019-04-10 13:30:34 -04001041 llvm::raw_fd_ostream outStream(OutputFilename, error,
1042 llvm::sys::fs::FA_Write);
alan-bakerfec0a472018-11-08 18:09:40 -05001043
1044 if (error) {
1045 llvm::errs() << "Unable to open output file '" << OutputFilename
1046 << "': " << error.message() << '\n';
1047 return -1;
1048 }
1049 outStream << binaryStream.str();
1050
1051 return 0;
1052}
alan-bakerf5e5f692018-11-27 08:33:24 -05001053
alan-baker86ce19c2020-08-05 13:09:19 -04001054int CompileFromSourceString(const std::string &program,
1055 const std::string &sampler_map,
1056 const std::string &options,
Kévin Petit899162d2020-09-08 19:16:08 +01001057 std::vector<uint32_t> *output_binary,
1058 std::string *output_log) {
alan-bakerf5e5f692018-11-27 08:33:24 -05001059
1060 llvm::SmallVector<const char *, 20> argv;
1061 llvm::BumpPtrAllocator A;
1062 llvm::StringSaver Saver(A);
1063 argv.push_back(Saver.save("clspv").data());
1064 llvm::cl::TokenizeGNUCommandLine(options, Saver, argv);
1065 int argc = static_cast<int>(argv.size());
Kévin Petitd5db2d22019-04-04 13:55:14 +01001066
1067 if (auto error = ParseOptions(argc, &argv[0]))
1068 return error;
alan-bakerf5e5f692018-11-27 08:33:24 -05001069
1070 llvm::SmallVector<std::pair<unsigned, std::string>, 8> SamplerMapEntries;
1071 if (auto error = ParseSamplerMap(sampler_map, &SamplerMapEntries))
1072 return error;
1073
1074 InputFilename = "source.cl";
1075 llvm::StringRef overiddenInputFilename = InputFilename.getValue();
1076
1077 clang::CompilerInstance instance;
alan-bakerd354f1a2019-08-06 15:41:55 -04001078 clang::FrontendInputFile kernelFile(
1079 overiddenInputFilename, clang::InputKind(clang::Language::OpenCL));
alan-bakerf5e5f692018-11-27 08:33:24 -05001080 std::string log;
1081 llvm::raw_string_ostream diagnosticsStream(log);
1082 if (auto error =
1083 SetCompilerInstanceOptions(instance, overiddenInputFilename,
1084 kernelFile, program, &diagnosticsStream))
1085 return error;
1086
1087 // Parse.
1088 llvm::LLVMContext context;
1089 clang::EmitLLVMOnlyAction action(&context);
1090
1091 // Prepare the action for processing kernelFile
1092 const bool success = action.BeginSourceFile(instance, kernelFile);
1093 if (!success) {
1094 return -1;
1095 }
1096
alan-bakerf3bce4a2019-06-28 16:01:15 -04001097 auto result = action.Execute();
alan-bakerf5e5f692018-11-27 08:33:24 -05001098 action.EndSourceFile();
1099
1100 clang::DiagnosticConsumer *const consumer =
1101 instance.getDiagnostics().getClient();
1102 consumer->finish();
1103
Kévin Petit899162d2020-09-08 19:16:08 +01001104 if (output_log != nullptr) {
1105 *output_log = log;
1106 }
1107
alan-bakerf5e5f692018-11-27 08:33:24 -05001108 auto num_errors = consumer->getNumErrors();
alan-bakerf3bce4a2019-06-28 16:01:15 -04001109 if (result || num_errors > 0) {
alan-bakerf5e5f692018-11-27 08:33:24 -05001110 return -1;
1111 }
1112
alan-bakerf5e5f692018-11-27 08:33:24 -05001113 llvm::PassRegistry &Registry = *llvm::PassRegistry::getPassRegistry();
1114 llvm::initializeCore(Registry);
1115 llvm::initializeScalarOpts(Registry);
Diego Novillo1fcff722019-05-07 13:45:53 -04001116 llvm::initializeClspvPasses(Registry);
alan-bakerf5e5f692018-11-27 08:33:24 -05001117
1118 std::unique_ptr<llvm::Module> module(action.takeModule());
1119
alan-baker869cd682021-03-05 11:21:19 -05001120 if (!LinkBuiltinLibrary(module.get())) {
1121 return -1;
1122 }
1123
alan-bakerf5e5f692018-11-27 08:33:24 -05001124 // Optimize.
1125 // Create a memory buffer for temporarily writing the result.
1126 SmallVector<char, 10000> binary;
1127 llvm::raw_svector_ostream binaryStream(binary);
alan-bakerf5e5f692018-11-27 08:33:24 -05001128 llvm::legacy::PassManager pm;
alan-baker86ce19c2020-08-05 13:09:19 -04001129 if (auto error = PopulatePassManager(&pm, &binaryStream, &SamplerMapEntries))
alan-bakerf5e5f692018-11-27 08:33:24 -05001130 return error;
1131 pm.run(*module);
1132
alan-bakerf5e5f692018-11-27 08:33:24 -05001133 // Write the resulting binary.
1134 // Wait until now to try writing the file so that we only write it on
1135 // successful compilation.
1136 assert(output_binary && "Valid binary container is required.");
1137 if (!OutputFilename.empty()) {
1138 llvm::outs()
1139 << "Warning: -o is ignored when binary container is provided.\n";
1140 }
1141 output_binary->resize(binary.size() / 4);
1142 memcpy(output_binary->data(), binary.data(), binary.size());
1143
1144 return 0;
1145}
alan-bakerfec0a472018-11-08 18:09:40 -05001146} // namespace clspv