blob: 11da3108288fc498cf5f039e5318bdd507e8e27f [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"
alan-baker57ce1c22022-04-26 19:10:44 -040024#include "llvm/IR/PassManager.h"
alan-bakerfec0a472018-11-08 18:09:40 -050025#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-baker57ce1c22022-04-26 19:10:44 -040028#include "llvm/Passes/PassBuilder.h"
alan-baker0e64a592019-11-18 13:36:25 -050029#include "llvm/InitializePasses.h"
alan-bakerfec0a472018-11-08 18:09:40 -050030#include "llvm/LinkAllPasses.h"
alan-baker869cd682021-03-05 11:21:19 -050031#include "llvm/Linker/Linker.h"
alan-bakerf5e5f692018-11-27 08:33:24 -050032#include "llvm/Support/Allocator.h"
alan-bakerfec0a472018-11-08 18:09:40 -050033#include "llvm/Support/CommandLine.h"
alan-bakerf5e5f692018-11-27 08:33:24 -050034#include "llvm/Support/ErrorOr.h"
alan-bakerfec0a472018-11-08 18:09:40 -050035#include "llvm/Support/MathExtras.h"
alan-bakerf5e5f692018-11-27 08:33:24 -050036#include "llvm/Support/StringSaver.h"
Diego Novillo89500852019-04-15 08:45:10 -040037#include "llvm/Support/ToolOutputFile.h"
alan-bakerfec0a472018-11-08 18:09:40 -050038#include "llvm/Support/raw_ostream.h"
alan-baker57ce1c22022-04-26 19:10:44 -040039#include "llvm/Transforms/InstCombine/InstCombine.h"
alan-bakerfec0a472018-11-08 18:09:40 -050040#include "llvm/Transforms/IPO/PassManagerBuilder.h"
alan-baker57ce1c22022-04-26 19:10:44 -040041#include "llvm/Transforms/Scalar/DCE.h"
42#include "llvm/Transforms/Scalar/InferAddressSpaces.h"
43#include "llvm/Transforms/Scalar/SROA.h"
44#include "llvm/Transforms/Scalar/StructurizeCFG.h"
45#include "llvm/Transforms/Utils/LowerSwitch.h"
46#include "llvm/Transforms/Utils/Mem2Reg.h"
alan-bakerfec0a472018-11-08 18:09:40 -050047
Kévin Petit38c52482019-05-07 20:28:00 +080048#include "clspv/AddressSpace.h"
alan-bakerfec0a472018-11-08 18:09:40 -050049#include "clspv/Option.h"
50#include "clspv/Passes.h"
alan-baker86ce19c2020-08-05 13:09:19 -040051#include "clspv/Sampler.h"
alan-baker869cd682021-03-05 11:21:19 -050052#include "clspv/clspv_builtin_library.h"
alan-bakerfec0a472018-11-08 18:09:40 -050053#include "clspv/opencl_builtins_header.h"
54
alan-baker869cd682021-03-05 11:21:19 -050055#include "Builtins.h"
alan-bakerfec0a472018-11-08 18:09:40 -050056#include "FrontendPlugin.h"
Diego Novilloa4c44fa2019-04-11 10:56:15 -040057#include "Passes.h"
alan-bakerfec0a472018-11-08 18:09:40 -050058
alan-bakerf5e5f692018-11-27 08:33:24 -050059#include <cassert>
alan-bakerfec0a472018-11-08 18:09:40 -050060#include <numeric>
alan-bakerf5e5f692018-11-27 08:33:24 -050061#include <sstream>
Diego Novillo3cc8d7a2019-04-10 13:30:34 -040062#include <string>
alan-bakerfec0a472018-11-08 18:09:40 -050063
64using namespace clang;
65
66namespace {
67// This registration must be located in the same file as the execution of the
68// action.
69static FrontendPluginRegistry::Add<clspv::ExtraValidationASTAction>
70 X("extra-validation",
71 "Perform extra validation on OpenCL C when targeting Vulkan");
72
73static llvm::cl::opt<bool> cl_single_precision_constants(
74 "cl-single-precision-constant", llvm::cl::init(false),
75 llvm::cl::desc("Treat double precision floating-point constant as single "
76 "precision constant."));
77
78static llvm::cl::opt<bool> cl_denorms_are_zero(
79 "cl-denorms-are-zero", llvm::cl::init(false),
80 llvm::cl::desc("If specified, denormalized floating point numbers may be "
81 "flushed to zero."));
82
83static llvm::cl::opt<bool> cl_fp32_correctly_rounded_divide_sqrt(
84 "cl-fp32-correctly-rounded-divide-sqrt", llvm::cl::init(false),
85 llvm::cl::desc("Single precision floating-point divide (x/y and 1/x) and "
86 "sqrt used are correctly rounded."));
87
88static llvm::cl::opt<bool>
89 cl_opt_disable("cl-opt-disable", llvm::cl::init(false),
90 llvm::cl::desc("This option disables all optimizations. The "
91 "default is optimizations are enabled."));
92
93static llvm::cl::opt<bool> cl_mad_enable(
94 "cl-mad-enable", llvm::cl::init(false),
95 llvm::cl::desc("Allow a * b + c to be replaced by a mad. The mad computes "
96 "a * b + c with reduced accuracy."));
97
98static llvm::cl::opt<bool> cl_no_signed_zeros(
99 "cl-no-signed-zeros", llvm::cl::init(false),
100 llvm::cl::desc("Allow optimizations for floating-point arithmetic that "
101 "ignore the signedness of zero."));
102
103static llvm::cl::opt<bool> cl_unsafe_math_optimizations(
104 "cl-unsafe-math-optimizations", llvm::cl::init(false),
105 llvm::cl::desc("Allow optimizations for floating-point arithmetic that (a) "
106 "assume that arguments and results are valid, (b) may "
107 "violate IEEE 754 standard and (c) may violate the OpenCL "
108 "numerical compliance requirements. This option includes "
109 "the -cl-no-signed-zeros and -cl-mad-enable options."));
110
111static llvm::cl::opt<bool> cl_finite_math_only(
112 "cl-finite-math-only", llvm::cl::init(false),
113 llvm::cl::desc("Allow optimizations for floating-point arithmetic that "
114 "assume that arguments and results are not NaNs or INFs."));
115
116static llvm::cl::opt<bool> cl_fast_relaxed_math(
117 "cl-fast-relaxed-math", llvm::cl::init(false),
118 llvm::cl::desc("This option causes the preprocessor macro "
119 "__FAST_RELAXED_MATH__ to be defined. Sets the optimization "
120 "options -cl-finite-math-only and "
121 "-cl-unsafe-math-optimizations."));
122
123static llvm::cl::list<std::string>
124 Includes(llvm::cl::Prefix, "I",
125 llvm::cl::desc("Add a directory to the list of directories "
126 "to be searched for header files."),
127 llvm::cl::ZeroOrMore, llvm::cl::value_desc("include path"));
128
129static llvm::cl::list<std::string>
130 Defines(llvm::cl::Prefix, "D",
131 llvm::cl::desc("Define a #define directive."), llvm::cl::ZeroOrMore,
132 llvm::cl::value_desc("define"));
133
134static llvm::cl::opt<std::string>
135 InputFilename(llvm::cl::Positional, llvm::cl::desc("<input .cl file>"),
136 llvm::cl::init("-"));
137
Kévin Petitddad8f42019-09-30 15:12:08 +0100138static llvm::cl::opt<clang::Language> InputLanguage(
139 "x", llvm::cl::desc("Select input type"),
140 llvm::cl::init(clang::Language::OpenCL),
141 llvm::cl::values(clEnumValN(clang::Language::OpenCL, "cl", "OpenCL source"),
142 clEnumValN(clang::Language::LLVM_IR, "ir", "LLVM IR")));
143
alan-bakerfec0a472018-11-08 18:09:40 -0500144static llvm::cl::opt<std::string>
145 OutputFilename("o", llvm::cl::desc("Override output filename"),
146 llvm::cl::value_desc("filename"));
147
alan-bakerfec0a472018-11-08 18:09:40 -0500148static llvm::cl::opt<char>
149 OptimizationLevel(llvm::cl::Prefix, "O", llvm::cl::init('2'),
150 llvm::cl::desc("Optimization level to use"),
151 llvm::cl::value_desc("level"));
152
alan-bakerfec0a472018-11-08 18:09:40 -0500153static llvm::cl::opt<std::string> OutputFormat(
154 "mfmt", llvm::cl::init(""),
155 llvm::cl::desc(
156 "Specify special output format. 'c' is as a C initializer list"),
157 llvm::cl::value_desc("format"));
158
159static llvm::cl::opt<std::string>
alan-baker09cb9802019-12-10 13:16:27 -0500160 SamplerMap("samplermap", llvm::cl::desc("DEPRECATED - Literal sampler map"),
alan-bakerfec0a472018-11-08 18:09:40 -0500161 llvm::cl::value_desc("filename"));
162
alan-bakerfec0a472018-11-08 18:09:40 -0500163static llvm::cl::opt<bool> verify("verify", llvm::cl::init(false),
164 llvm::cl::desc("Verify diagnostic outputs"));
165
Kévin Petit6b07cbe2019-04-02 21:52:16 +0100166static llvm::cl::opt<bool>
167 IgnoreWarnings("w", llvm::cl::init(false),
168 llvm::cl::desc("Disable all warnings"));
169
170static llvm::cl::opt<bool>
171 WarningsAsErrors("Werror", llvm::cl::init(false),
Diego Novillo3cc8d7a2019-04-10 13:30:34 -0400172 llvm::cl::desc("Turn warnings into errors"));
Kévin Petit6b07cbe2019-04-02 21:52:16 +0100173
Diego Novillo89500852019-04-15 08:45:10 -0400174static llvm::cl::opt<std::string> IROutputFile(
175 "emit-ir",
176 llvm::cl::desc(
177 "Emit LLVM IR to the given file after parsing and stop compilation."),
178 llvm::cl::value_desc("filename"));
179
alan-baker869cd682021-03-05 11:21:19 -0500180namespace {
181struct OpenCLBuiltinMemoryBuffer final : public llvm::MemoryBuffer {
182 OpenCLBuiltinMemoryBuffer(const void *data, uint64_t data_length) {
183 const char *dataCasted = reinterpret_cast<const char *>(data);
184 init(dataCasted, dataCasted + data_length, true);
185 }
186
187 virtual llvm::MemoryBuffer::BufferKind getBufferKind() const override {
188 return llvm::MemoryBuffer::MemoryBuffer_Malloc;
189 }
190
191 virtual ~OpenCLBuiltinMemoryBuffer() override {}
192};
193} // namespace
194
alan-bakerfec0a472018-11-08 18:09:40 -0500195// Populates |SamplerMapEntries| with data from the input sampler map. Returns 0
196// if successful.
alan-bakerf5e5f692018-11-27 08:33:24 -0500197int ParseSamplerMap(const std::string &sampler_map,
198 llvm::SmallVectorImpl<std::pair<unsigned, std::string>>
199 *SamplerMapEntries) {
200 std::unique_ptr<llvm::MemoryBuffer> samplerMapBuffer(nullptr);
201 if (!sampler_map.empty()) {
202 // Parse the sampler map from the provided string.
203 samplerMapBuffer = llvm::MemoryBuffer::getMemBuffer(sampler_map);
204
alan-baker09cb9802019-12-10 13:16:27 -0500205 clspv::Option::SetUseSamplerMap(true);
alan-bakerf5e5f692018-11-27 08:33:24 -0500206 if (!SamplerMap.empty()) {
207 llvm::outs() << "Warning: -samplermap is ignored when the sampler map is "
208 "provided through a string.\n";
209 }
210 } else if (!SamplerMap.empty()) {
211 // Parse the sampler map from the option provided file.
alan-bakerfec0a472018-11-08 18:09:40 -0500212 auto errorOrSamplerMapFile =
213 llvm::MemoryBuffer::getFile(SamplerMap.getValue());
214
215 // If there was an error in getting the sampler map file.
216 if (!errorOrSamplerMapFile) {
217 llvm::errs() << "Error: " << errorOrSamplerMapFile.getError().message()
218 << " '" << SamplerMap.getValue() << "'\n";
219 return -1;
220 }
221
alan-baker09cb9802019-12-10 13:16:27 -0500222 clspv::Option::SetUseSamplerMap(true);
alan-bakerf5e5f692018-11-27 08:33:24 -0500223 samplerMapBuffer = std::move(errorOrSamplerMapFile.get());
alan-bakerfec0a472018-11-08 18:09:40 -0500224 if (0 == samplerMapBuffer->getBufferSize()) {
225 llvm::errs() << "Error: Sampler map was an empty file!\n";
226 return -1;
227 }
alan-bakerf5e5f692018-11-27 08:33:24 -0500228 }
alan-bakerfec0a472018-11-08 18:09:40 -0500229
alan-baker09cb9802019-12-10 13:16:27 -0500230 if (clspv::Option::UseSamplerMap()) {
alan-baker57ce1c22022-04-26 19:10:44 -0400231 // TODO(alan-baker): Remove all APIs dealing the sampler map after landing
232 // the transition to the new pass manager.
233 llvm::errs() << "Error: use of a sampler map is no longer supported\n";
234 return -1;
alan-baker09cb9802019-12-10 13:16:27 -0500235 }
236
alan-bakerf5e5f692018-11-27 08:33:24 -0500237 // No sampler map to parse.
238 if (!samplerMapBuffer || 0 == samplerMapBuffer->getBufferSize())
239 return 0;
alan-bakerfec0a472018-11-08 18:09:40 -0500240
alan-bakerf5e5f692018-11-27 08:33:24 -0500241 llvm::SmallVector<llvm::StringRef, 3> samplerStrings;
alan-bakerfec0a472018-11-08 18:09:40 -0500242
alan-bakerf5e5f692018-11-27 08:33:24 -0500243 // We need to keep track of the beginning of the current entry.
244 const char *b = samplerMapBuffer->getBufferStart();
245 for (const char *i = b, *e = samplerMapBuffer->getBufferEnd();; i++) {
246 // If we have a separator between declarations.
247 if ((*i == '|') || (*i == ',') || (i == e)) {
248 if (i == b) {
249 llvm::errs() << "Error: Sampler map contained an empty entry!\n";
250 return -1;
alan-bakerfec0a472018-11-08 18:09:40 -0500251 }
252
alan-bakerf5e5f692018-11-27 08:33:24 -0500253 samplerStrings.push_back(llvm::StringRef(b, i - b).trim());
alan-bakerfec0a472018-11-08 18:09:40 -0500254
alan-bakerf5e5f692018-11-27 08:33:24 -0500255 // And set b the next character after i.
256 b = i + 1;
257 }
alan-bakerfec0a472018-11-08 18:09:40 -0500258
alan-bakerf5e5f692018-11-27 08:33:24 -0500259 // If we have a separator between declarations within a single sampler.
260 if ((*i == ',') || (i == e)) {
alan-bakerfec0a472018-11-08 18:09:40 -0500261
alan-baker86ce19c2020-08-05 13:09:19 -0400262 clspv::SamplerNormalizedCoords NormalizedCoord =
263 clspv::CLK_NORMALIZED_COORDS_NOT_SET;
264 clspv::SamplerAddressingMode AddressingMode = clspv::CLK_ADDRESS_NOT_SET;
265 clspv::SamplerFilterMode FilterMode = clspv::CLK_FILTER_NOT_SET;
alan-bakerf5e5f692018-11-27 08:33:24 -0500266
267 for (auto str : samplerStrings) {
268 if ("CLK_NORMALIZED_COORDS_FALSE" == str) {
alan-baker86ce19c2020-08-05 13:09:19 -0400269 if (clspv::CLK_NORMALIZED_COORDS_NOT_SET != NormalizedCoord) {
alan-bakerf5e5f692018-11-27 08:33:24 -0500270 llvm::errs() << "Error: Sampler map normalized coordinates was "
271 "previously set!\n";
alan-bakerfec0a472018-11-08 18:09:40 -0500272 return -1;
273 }
alan-baker86ce19c2020-08-05 13:09:19 -0400274 NormalizedCoord = clspv::CLK_NORMALIZED_COORDS_FALSE;
alan-bakerf5e5f692018-11-27 08:33:24 -0500275 } else if ("CLK_NORMALIZED_COORDS_TRUE" == str) {
alan-baker86ce19c2020-08-05 13:09:19 -0400276 if (clspv::CLK_NORMALIZED_COORDS_NOT_SET != NormalizedCoord) {
alan-bakerf5e5f692018-11-27 08:33:24 -0500277 llvm::errs() << "Error: Sampler map normalized coordinates was "
278 "previously set!\n";
279 return -1;
280 }
alan-baker86ce19c2020-08-05 13:09:19 -0400281 NormalizedCoord = clspv::CLK_NORMALIZED_COORDS_TRUE;
alan-bakerf5e5f692018-11-27 08:33:24 -0500282 } else if ("CLK_ADDRESS_NONE" == str) {
alan-baker86ce19c2020-08-05 13:09:19 -0400283 if (clspv::CLK_ADDRESS_NOT_SET != AddressingMode) {
alan-bakerf5e5f692018-11-27 08:33:24 -0500284 llvm::errs()
285 << "Error: Sampler map addressing mode was previously set!\n";
286 return -1;
287 }
alan-baker86ce19c2020-08-05 13:09:19 -0400288 AddressingMode = clspv::CLK_ADDRESS_NONE;
alan-bakerf5e5f692018-11-27 08:33:24 -0500289 } else if ("CLK_ADDRESS_CLAMP_TO_EDGE" == str) {
alan-baker86ce19c2020-08-05 13:09:19 -0400290 if (clspv::CLK_ADDRESS_NOT_SET != AddressingMode) {
alan-bakerf5e5f692018-11-27 08:33:24 -0500291 llvm::errs()
292 << "Error: Sampler map addressing mode was previously set!\n";
293 return -1;
294 }
alan-baker86ce19c2020-08-05 13:09:19 -0400295 AddressingMode = clspv::CLK_ADDRESS_CLAMP_TO_EDGE;
alan-bakerf5e5f692018-11-27 08:33:24 -0500296 } else if ("CLK_ADDRESS_CLAMP" == str) {
alan-baker86ce19c2020-08-05 13:09:19 -0400297 if (clspv::CLK_ADDRESS_NOT_SET != AddressingMode) {
alan-bakerf5e5f692018-11-27 08:33:24 -0500298 llvm::errs()
299 << "Error: Sampler map addressing mode was previously set!\n";
300 return -1;
301 }
alan-baker86ce19c2020-08-05 13:09:19 -0400302 AddressingMode = clspv::CLK_ADDRESS_CLAMP;
alan-bakerf5e5f692018-11-27 08:33:24 -0500303 } else if ("CLK_ADDRESS_MIRRORED_REPEAT" == str) {
alan-baker86ce19c2020-08-05 13:09:19 -0400304 if (clspv::CLK_ADDRESS_NOT_SET != AddressingMode) {
alan-bakerf5e5f692018-11-27 08:33:24 -0500305 llvm::errs()
306 << "Error: Sampler map addressing mode was previously set!\n";
307 return -1;
308 }
alan-baker86ce19c2020-08-05 13:09:19 -0400309 AddressingMode = clspv::CLK_ADDRESS_MIRRORED_REPEAT;
alan-bakerf5e5f692018-11-27 08:33:24 -0500310 } else if ("CLK_ADDRESS_REPEAT" == str) {
alan-baker86ce19c2020-08-05 13:09:19 -0400311 if (clspv::CLK_ADDRESS_NOT_SET != AddressingMode) {
alan-bakerf5e5f692018-11-27 08:33:24 -0500312 llvm::errs()
313 << "Error: Sampler map addressing mode was previously set!\n";
314 return -1;
315 }
alan-baker86ce19c2020-08-05 13:09:19 -0400316 AddressingMode = clspv::CLK_ADDRESS_REPEAT;
alan-bakerf5e5f692018-11-27 08:33:24 -0500317 } else if ("CLK_FILTER_NEAREST" == str) {
alan-baker86ce19c2020-08-05 13:09:19 -0400318 if (clspv::CLK_FILTER_NOT_SET != FilterMode) {
alan-bakerf5e5f692018-11-27 08:33:24 -0500319 llvm::errs()
320 << "Error: Sampler map filtering mode was previously set!\n";
321 return -1;
322 }
alan-baker86ce19c2020-08-05 13:09:19 -0400323 FilterMode = clspv::CLK_FILTER_NEAREST;
alan-bakerf5e5f692018-11-27 08:33:24 -0500324 } else if ("CLK_FILTER_LINEAR" == str) {
alan-baker86ce19c2020-08-05 13:09:19 -0400325 if (clspv::CLK_FILTER_NOT_SET != FilterMode) {
alan-bakerf5e5f692018-11-27 08:33:24 -0500326 llvm::errs()
327 << "Error: Sampler map filtering mode was previously set!\n";
328 return -1;
329 }
alan-baker86ce19c2020-08-05 13:09:19 -0400330 FilterMode = clspv::CLK_FILTER_LINEAR;
alan-bakerf5e5f692018-11-27 08:33:24 -0500331 } else {
332 llvm::errs() << "Error: Unknown sampler string '" << str
333 << "' found!\n";
alan-bakerfec0a472018-11-08 18:09:40 -0500334 return -1;
335 }
alan-bakerfec0a472018-11-08 18:09:40 -0500336 }
337
alan-baker86ce19c2020-08-05 13:09:19 -0400338 if (clspv::CLK_NORMALIZED_COORDS_NOT_SET == NormalizedCoord) {
alan-bakerf5e5f692018-11-27 08:33:24 -0500339 llvm::errs() << "Error: Sampler map entry did not contain normalized "
340 "coordinates entry!\n";
341 return -1;
alan-bakerfec0a472018-11-08 18:09:40 -0500342 }
alan-bakerf5e5f692018-11-27 08:33:24 -0500343
alan-baker86ce19c2020-08-05 13:09:19 -0400344 if (clspv::CLK_ADDRESS_NOT_SET == AddressingMode) {
alan-bakerf5e5f692018-11-27 08:33:24 -0500345 llvm::errs() << "Error: Sampler map entry did not contain addressing "
346 "mode entry!\n";
347 return -1;
348 }
349
alan-baker86ce19c2020-08-05 13:09:19 -0400350 if (clspv::CLK_FILTER_NOT_SET == FilterMode) {
alan-bakerf5e5f692018-11-27 08:33:24 -0500351 llvm::errs()
352 << "Error: Sampler map entry did not contain filer mode entry!\n";
353 return -1;
354 }
355
356 // Generate an equivalent expression in string form. Sort the
357 // strings to get a canonical ordering.
358 std::sort(samplerStrings.begin(), samplerStrings.end(),
359 std::less<StringRef>());
360 const auto samplerExpr = std::accumulate(
361 samplerStrings.begin(), samplerStrings.end(), std::string(),
alan-baker21574d32020-01-29 16:00:31 -0500362 [](llvm::StringRef left, llvm::StringRef right) {
363 return left.str() + std::string(left.empty() ? "" : "|") +
364 right.str();
alan-bakerf5e5f692018-11-27 08:33:24 -0500365 });
366
367 // SamplerMapEntries->push_back(std::make_pair(
368 // NormalizedCoord | AddressingMode | FilterMode, samplerExpr));
369 SamplerMapEntries->emplace_back(
370 NormalizedCoord | AddressingMode | FilterMode, samplerExpr);
371
372 // And reset the sampler strings for the next sampler in the map.
373 samplerStrings.clear();
374 }
375
376 // And lastly, if we are at the end of the file
377 if (i == e) {
378 break;
alan-bakerfec0a472018-11-08 18:09:40 -0500379 }
380 }
381
382 return 0;
383}
384
Kévin Petitaab5bb82021-03-30 16:26:11 +0100385clang::TargetInfo *PrepareTargetInfo(CompilerInstance &instance) {
386 // Create target info
387 auto TargetInfo = clang::TargetInfo::CreateTargetInfo(
388 instance.getDiagnostics(),
389 std::make_shared<clang::TargetOptions>(instance.getTargetOpts()));
390
391 // The SPIR target enables all possible options, disable the ones we don't
392 // want
393 auto &Opts = TargetInfo->getSupportedOpenCLOpts();
394
395 // Conditionally disable extensions based on support
396 if (!clspv::Option::FP16()) {
397 Opts["cl_khr_fp16"] = false;
398 }
399 if (!clspv::Option::FP64()) {
400 Opts["cl_khr_fp64"] = false;
401 }
402
403 // Disable CL3.0 feature macros for unsupported features
404 if (instance.getLangOpts().LangStd == clang::LangStandard::lang_opencl30) {
405
Kévin Petitaab5bb82021-03-30 16:26:11 +0100406 // The following features are never supported
407 Opts["__opencl_c_pipes"] = false;
408 Opts["__opencl_c_generic_address_space"] = false;
Kévin Petitaab5bb82021-03-30 16:26:11 +0100409 Opts["__opencl_c_device_enqueue"] = false;
410 Opts["__opencl_c_program_scope_global_variables"] = false;
411
412 if (!clspv::Option::ImageSupport()) {
413 Opts["__opencl_c_images"] = false;
414 }
415
416 if (!clspv::Option::FP64()) {
417 Opts["__opencl_c_fp64"] = false;
418 }
419 }
420
421 return TargetInfo;
422}
423
alan-bakerfec0a472018-11-08 18:09:40 -0500424// Sets |instance|'s options for compiling. Returns 0 if successful.
Ryan Senanayake6917fb12022-02-28 18:17:02 -0500425int SetCompilerInstanceOptions(
426 CompilerInstance &instance, const llvm::StringRef &overiddenInputFilename,
427 clang::FrontendInputFile &kernelFile, const std::string &program,
428 std::unique_ptr<llvm::MemoryBuffer> &file_memory_buffer,
429 llvm::raw_string_ostream *diagnosticsStream) {
alan-bakerf5e5f692018-11-27 08:33:24 -0500430 llvm::ErrorOr<std::unique_ptr<llvm::MemoryBuffer>> errorOrInputFile(nullptr);
431 if (program.empty()) {
432 auto errorOrInputFile =
433 llvm::MemoryBuffer::getFileOrSTDIN(InputFilename.getValue());
alan-bakerfec0a472018-11-08 18:09:40 -0500434
alan-bakerf5e5f692018-11-27 08:33:24 -0500435 // If there was an error in getting the input file.
436 if (!errorOrInputFile) {
437 llvm::errs() << "Error: " << errorOrInputFile.getError().message() << " '"
438 << InputFilename.getValue() << "'\n";
439 return -1;
440 }
Ryan Senanayake6917fb12022-02-28 18:17:02 -0500441 file_memory_buffer = std::move(errorOrInputFile.get());
alan-bakerf5e5f692018-11-27 08:33:24 -0500442 } else {
Ryan Senanayake6917fb12022-02-28 18:17:02 -0500443 file_memory_buffer =
444 llvm::MemoryBuffer::getMemBuffer(program, overiddenInputFilename);
alan-bakerfec0a472018-11-08 18:09:40 -0500445 }
alan-bakerf5e5f692018-11-27 08:33:24 -0500446
alan-bakerfec0a472018-11-08 18:09:40 -0500447 if (verify) {
448 instance.getDiagnosticOpts().VerifyDiagnostics = true;
alan-bakerbccf62c2019-03-29 10:32:41 -0400449 instance.getDiagnosticOpts().VerifyPrefixes.push_back("expected");
alan-bakerfec0a472018-11-08 18:09:40 -0500450 }
451
Kévin Petit0fc88042019-04-09 23:25:02 +0100452 clang::LangStandard::Kind standard;
Kévin Petitf0515712020-01-07 18:29:20 +0000453 switch (clspv::Option::Language()) {
454 case clspv::Option::SourceLanguage::OpenCL_C_10:
455 standard = clang::LangStandard::lang_opencl10;
456 break;
457 case clspv::Option::SourceLanguage::OpenCL_C_11:
458 standard = clang::LangStandard::lang_opencl11;
459 break;
460 case clspv::Option::SourceLanguage::OpenCL_C_12:
Kévin Petit0fc88042019-04-09 23:25:02 +0100461 standard = clang::LangStandard::lang_opencl12;
Kévin Petitf0515712020-01-07 18:29:20 +0000462 break;
463 case clspv::Option::SourceLanguage::OpenCL_C_20:
464 standard = clang::LangStandard::lang_opencl20;
465 break;
Kévin Petit77838ff2020-10-19 18:54:51 +0100466 case clspv::Option::SourceLanguage::OpenCL_C_30:
467 standard = clang::LangStandard::lang_opencl30;
468 break;
Kévin Petitf0515712020-01-07 18:29:20 +0000469 case clspv::Option::SourceLanguage::OpenCL_CPP:
alan-baker39706812021-08-03 13:21:39 -0400470 standard = clang::LangStandard::lang_openclcpp10;
Kévin Petitf0515712020-01-07 18:29:20 +0000471 break;
472 default:
473 llvm_unreachable("Unknown source language");
Kévin Petit0fc88042019-04-09 23:25:02 +0100474 }
alan-bakerfec0a472018-11-08 18:09:40 -0500475
alan-bakerfec0a472018-11-08 18:09:40 -0500476 instance.getLangOpts().C99 = true;
477 instance.getLangOpts().RTTI = false;
478 instance.getLangOpts().RTTIData = false;
479 instance.getLangOpts().MathErrno = false;
480 instance.getLangOpts().Optimize = false;
481 instance.getLangOpts().NoBuiltin = true;
482 instance.getLangOpts().ModulesSearchAll = false;
483 instance.getLangOpts().SinglePrecisionConstants = true;
484 instance.getCodeGenOpts().StackRealignment = true;
485 instance.getCodeGenOpts().SimplifyLibCalls = false;
486 instance.getCodeGenOpts().EmitOpenCLArgMetadata = false;
487 instance.getCodeGenOpts().DisableO0ImplyOptNone = true;
Kévin Petit6b07cbe2019-04-02 21:52:16 +0100488 instance.getDiagnosticOpts().IgnoreWarnings = IgnoreWarnings;
alan-bakerfec0a472018-11-08 18:09:40 -0500489
490 instance.getLangOpts().SinglePrecisionConstants =
491 cl_single_precision_constants;
492 // cl_denorms_are_zero ignored for now!
493 // cl_fp32_correctly_rounded_divide_sqrt ignored for now!
494 instance.getCodeGenOpts().LessPreciseFPMAD =
495 cl_mad_enable || cl_unsafe_math_optimizations;
496 // cl_no_signed_zeros ignored for now!
alan-baker869cd682021-03-05 11:21:19 -0500497 instance.getLangOpts().UnsafeFPMath = cl_unsafe_math_optimizations ||
498 cl_fast_relaxed_math ||
499 clspv::Option::NativeMath();
500 instance.getLangOpts().FiniteMathOnly = cl_finite_math_only ||
501 cl_fast_relaxed_math ||
502 clspv::Option::NativeMath();
503 instance.getLangOpts().FastRelaxedMath =
504 cl_fast_relaxed_math || clspv::Option::NativeMath();
alan-bakerfec0a472018-11-08 18:09:40 -0500505
506 // Preprocessor options
Kévin Petita624c0c2019-05-07 20:27:43 +0800507 if (!clspv::Option::ImageSupport()) {
508 instance.getPreprocessorOpts().addMacroUndef("__IMAGE_SUPPORT__");
509 }
alan-baker869cd682021-03-05 11:21:19 -0500510 if (cl_fast_relaxed_math || clspv::Option::NativeMath()) {
alan-bakerfec0a472018-11-08 18:09:40 -0500511 instance.getPreprocessorOpts().addMacroDef("__FAST_RELAXED_MATH__");
512 }
513
514 for (auto define : Defines) {
515 instance.getPreprocessorOpts().addMacroDef(define);
516 }
517
518 // Header search options
519 for (auto include : Includes) {
520 instance.getHeaderSearchOpts().AddPath(include, clang::frontend::After,
521 false, false);
522 }
523
524 // We always compile on opt 0 so we preserve as much debug information about
525 // the source as possible. We'll run optimization later, once we've had a
526 // chance to view the unoptimal code first
527 instance.getCodeGenOpts().OptimizationLevel = 0;
528
529// Debug information is disabled temporarily to call instruction.
530#if 0
531 instance.getCodeGenOpts().setDebugInfo(clang::codegenoptions::FullDebugInfo);
532#endif
533
534 // We use the 32-bit pointer-width SPIR triple
535 llvm::Triple triple("spir-unknown-unknown");
536
James Price40efe7f2021-01-18 09:19:31 -0500537 // We manually include the OpenCL headers below, so this vector is unused.
538 std::vector<std::string> includes;
539
alan-baker1e20bf22022-04-13 16:05:14 -0400540 LangOptions::setLangDefaults(instance.getLangOpts(), clang::Language::OpenCL,
541 triple, includes, standard);
alan-bakerfec0a472018-11-08 18:09:40 -0500542
543 // Override the C99 inline semantics to accommodate for more OpenCL C
544 // programs in the wild.
545 instance.getLangOpts().GNUInline = true;
Kévin Petit6b07cbe2019-04-02 21:52:16 +0100546
547 // Set up diagnostics
alan-bakerfec0a472018-11-08 18:09:40 -0500548 instance.createDiagnostics(
549 new clang::TextDiagnosticPrinter(*diagnosticsStream,
550 &instance.getDiagnosticOpts()),
551 true);
Kévin Petit6b07cbe2019-04-02 21:52:16 +0100552 instance.getDiagnostics().setWarningsAsErrors(WarningsAsErrors);
553 instance.getDiagnostics().setEnableAllWarnings(true);
alan-bakerfec0a472018-11-08 18:09:40 -0500554
555 instance.getTargetOpts().Triple = triple.str();
556
alan-baker21574d32020-01-29 16:00:31 -0500557 instance.getCodeGenOpts().MainFileName = overiddenInputFilename.str();
alan-bakerfec0a472018-11-08 18:09:40 -0500558 instance.getCodeGenOpts().PreserveVec3Type = true;
559 // Disable generation of lifetime intrinsic.
560 instance.getCodeGenOpts().DisableLifetimeMarkers = true;
Ryan Senanayake6917fb12022-02-28 18:17:02 -0500561 if (InputLanguage == clang::Language::OpenCL) {
562 instance.getPreprocessorOpts().addRemappedFile(
563 overiddenInputFilename, file_memory_buffer.release());
564 } else if (!program.empty()) {
565 // Can't use preprocessor to do file remapping for LLVM_IR
566 kernelFile = clang::FrontendInputFile(*file_memory_buffer,
567 clang::InputKind(InputLanguage));
568 }
alan-bakerfec0a472018-11-08 18:09:40 -0500569 instance.getFrontendOpts().Inputs.push_back(kernelFile);
alan-bakerfec0a472018-11-08 18:09:40 -0500570
alan-bakerfec0a472018-11-08 18:09:40 -0500571 std::unique_ptr<llvm::MemoryBuffer> openCLBuiltinMemoryBuffer(
572 new OpenCLBuiltinMemoryBuffer(opencl_builtins_header_data,
573 opencl_builtins_header_size - 1));
574
James Price40efe7f2021-01-18 09:19:31 -0500575 instance.getPreprocessorOpts().Includes.push_back("opencl-c.h");
alan-bakerfec0a472018-11-08 18:09:40 -0500576
alan-bakerf3bce4a2019-06-28 16:01:15 -0400577 std::unique_ptr<llvm::MemoryBuffer> openCLBaseBuiltinMemoryBuffer(
578 new OpenCLBuiltinMemoryBuffer(opencl_base_builtins_header_data,
579 opencl_base_builtins_header_size - 1));
580
581 instance.getPreprocessorOpts().Includes.push_back("opencl-c-base.h");
582
alan-bakerfec0a472018-11-08 18:09:40 -0500583 // Add the VULKAN macro.
584 instance.getPreprocessorOpts().addMacroDef("VULKAN=100");
585
586 // Add the __OPENCL_VERSION__ macro.
587 instance.getPreprocessorOpts().addMacroDef("__OPENCL_VERSION__=120");
588
Kévin Petitaab5bb82021-03-30 16:26:11 +0100589 instance.setTarget(PrepareTargetInfo(instance));
alan-bakerfec0a472018-11-08 18:09:40 -0500590
591 instance.createFileManager();
592 instance.createSourceManager(instance.getFileManager());
593
594#ifdef _MSC_VER
595 std::string includePrefix("include\\");
596#else
597 std::string includePrefix("include/");
598#endif
599
600 auto entry = instance.getFileManager().getVirtualFile(
James Price40efe7f2021-01-18 09:19:31 -0500601 includePrefix + "opencl-c.h", openCLBuiltinMemoryBuffer->getBufferSize(),
alan-bakerfec0a472018-11-08 18:09:40 -0500602 0);
603
604 instance.getSourceManager().overrideFileContents(
605 entry, std::move(openCLBuiltinMemoryBuffer));
606
alan-bakerf3bce4a2019-06-28 16:01:15 -0400607 auto base_entry = instance.getFileManager().getVirtualFile(
608 includePrefix + "opencl-c-base.h",
609 openCLBaseBuiltinMemoryBuffer->getBufferSize(), 0);
610
611 instance.getSourceManager().overrideFileContents(
612 base_entry, std::move(openCLBaseBuiltinMemoryBuffer));
613
alan-bakerfec0a472018-11-08 18:09:40 -0500614 return 0;
615}
616
alan-baker57ce1c22022-04-26 19:10:44 -0400617int RunPassPipeline(llvm::Module &M, llvm::raw_svector_ostream *binaryStream) {
618 llvm::LoopAnalysisManager lam;
619 llvm::FunctionAnalysisManager fam;
620 llvm::CGSCCAnalysisManager cgam;
621 llvm::ModuleAnalysisManager mam;
622 llvm::PassInstrumentationCallbacks PIC;
623 clspv::RegisterClspvPasses(&PIC);
624 llvm::PassBuilder pb(nullptr, llvm::PipelineTuningOptions(), llvm::None,
625 &PIC);
626 pb.registerModuleAnalyses(mam);
627 pb.registerCGSCCAnalyses(cgam);
628 pb.registerFunctionAnalyses(fam);
629 pb.registerLoopAnalyses(lam);
630 pb.crossRegisterProxies(lam, fam, cgam, mam);
631
632 llvm::ModulePassManager pm;
633 llvm::FunctionPassManager fpm;
alan-bakerfec0a472018-11-08 18:09:40 -0500634
635 switch (OptimizationLevel) {
636 case '0':
alan-bakerf5e5f692018-11-27 08:33:24 -0500637 case '1':
638 case '2':
639 case '3':
640 case 's':
641 case 'z':
642 break;
643 default:
644 llvm::errs() << "Unknown optimization level -O" << OptimizationLevel
645 << " specified!\n";
646 return -1;
647 }
648
alan-baker57ce1c22022-04-26 19:10:44 -0400649 llvm::OptimizationLevel level;
alan-bakerf5e5f692018-11-27 08:33:24 -0500650 switch (OptimizationLevel) {
651 case '0':
alan-baker57ce1c22022-04-26 19:10:44 -0400652 level = llvm::OptimizationLevel::O0;
alan-bakerfec0a472018-11-08 18:09:40 -0500653 break;
654 case '1':
alan-baker57ce1c22022-04-26 19:10:44 -0400655 level = llvm::OptimizationLevel::O1;
alan-bakerfec0a472018-11-08 18:09:40 -0500656 break;
657 case '2':
alan-baker57ce1c22022-04-26 19:10:44 -0400658 level = llvm::OptimizationLevel::O2;
alan-bakerfec0a472018-11-08 18:09:40 -0500659 break;
660 case '3':
alan-baker57ce1c22022-04-26 19:10:44 -0400661 level = llvm::OptimizationLevel::O3;
alan-bakerfec0a472018-11-08 18:09:40 -0500662 break;
663 case 's':
alan-baker57ce1c22022-04-26 19:10:44 -0400664 level = llvm::OptimizationLevel::Os;
alan-bakerfec0a472018-11-08 18:09:40 -0500665 break;
666 case 'z':
alan-baker57ce1c22022-04-26 19:10:44 -0400667 level = llvm::OptimizationLevel::Oz;
alan-bakerfec0a472018-11-08 18:09:40 -0500668 break;
669 default:
670 break;
671 }
672
alan-baker57ce1c22022-04-26 19:10:44 -0400673 // Run the following optimizations prior to the standard LLVM pass pipeline.
674 pb.registerPipelineStartEPCallback([](llvm::ModulePassManager &pm,
675 llvm::OptimizationLevel level) {
676 pm.addPass(clspv::NativeMathPass());
677 pm.addPass(clspv::ZeroInitializeAllocasPass());
678 pm.addPass(clspv::AddFunctionAttributesPass());
679 pm.addPass(clspv::AutoPodArgsPass());
680 pm.addPass(clspv::DeclarePushConstantsPass());
681 pm.addPass(clspv::DefineOpenCLWorkItemBuiltinsPass());
alan-bakerfec0a472018-11-08 18:09:40 -0500682
alan-baker57ce1c22022-04-26 19:10:44 -0400683 if (level.getSpeedupLevel() > 0) {
684 pm.addPass(clspv::OpenCLInlinerPass());
685 }
alan-bakerfec0a472018-11-08 18:09:40 -0500686
alan-baker57ce1c22022-04-26 19:10:44 -0400687 pm.addPass(clspv::UndoByvalPass());
688 pm.addPass(clspv::UndoSRetPass());
689 pm.addPass(clspv::ClusterPodKernelArgumentsPass());
690 pm.addPass(clspv::ReplaceOpenCLBuiltinPass());
691 pm.addPass(clspv::ThreeElementVectorLoweringPass());
alan-bakerfec0a472018-11-08 18:09:40 -0500692
alan-baker57ce1c22022-04-26 19:10:44 -0400693 // Lower longer vectors when requested. Note that this pass depends on
694 // ReplaceOpenCLBuiltinPass and expects DeadCodeEliminationPass to be run
695 // afterwards.
696 if (clspv::Option::LongVectorSupport()) {
697 pm.addPass(clspv::LongVectorLoweringPass());
698 }
Romaric Jodin322e9ba2021-12-08 16:00:06 +0100699
alan-baker57ce1c22022-04-26 19:10:44 -0400700 // We need to run mem2reg and inst combine early because our
701 // createInlineFuncWithPointerBitCastArgPass pass cannot handle the pattern
702 // %1 = alloca i32 1
703 // store <something> %1
704 // %2 = bitcast float* %1
705 // %3 = load float %2
706 pm.addPass(llvm::createModuleToFunctionPassAdaptor(llvm::PromotePass()));
Marco Antognini535998c2020-09-16 18:48:51 +0100707
alan-baker57ce1c22022-04-26 19:10:44 -0400708 // Try to deal with pointer bitcasts early. This can prevent problems like
709 // issue #409 where LLVM is looser about access chain addressing than
710 // SPIR-V. This needs to happen before instcombine and after replacing
711 // OpenCL builtins. This run of the pass will not handle all pointer
712 // bitcasts that could be handled. It should be run again after other
713 // optimizations (e.g InlineFuncWithPointerBitCastArgPass).
714 pm.addPass(clspv::SimplifyPointerBitcastPass());
715 pm.addPass(clspv::ReplacePointerBitcastPass());
716 pm.addPass(llvm::createModuleToFunctionPassAdaptor(llvm::DCEPass()));
alan-bakerfec0a472018-11-08 18:09:40 -0500717
alan-baker57ce1c22022-04-26 19:10:44 -0400718 // Hide loads from __constant address space away from instcombine.
719 // This prevents us from generating select between pointers-to-__constant.
720 // See https://github.com/google/clspv/issues/71
721 pm.addPass(clspv::HideConstantLoadsPass());
alan-baker1b13e8f2019-08-08 17:56:51 -0400722
alan-baker57ce1c22022-04-26 19:10:44 -0400723 pm.addPass(
724 llvm::createModuleToFunctionPassAdaptor(llvm::InstCombinePass()));
alan-bakerfec0a472018-11-08 18:09:40 -0500725
alan-baker57ce1c22022-04-26 19:10:44 -0400726 if (clspv::Option::InlineEntryPoints()) {
727 pm.addPass(clspv::InlineEntryPointsPass());
728 } else {
729 pm.addPass(clspv::InlineFuncWithPointerBitCastArgPass());
730 pm.addPass(clspv::InlineFuncWithPointerToFunctionArgPass());
731 pm.addPass(clspv::InlineFuncWithSingleCallSitePass());
732 }
alan-bakerfec0a472018-11-08 18:09:40 -0500733
alan-baker57ce1c22022-04-26 19:10:44 -0400734 // Mem2Reg pass should be run early because O0 level optimization leaves
735 // redundant alloca, load and store instructions from function arguments.
736 // clspv needs to remove them ahead of transformation.
737 pm.addPass(llvm::createModuleToFunctionPassAdaptor(llvm::PromotePass()));
738
739 // SROA pass is run because it will fold structs/unions that are problematic
740 // on Vulkan SPIR-V away.
741 pm.addPass(llvm::createModuleToFunctionPassAdaptor(llvm::SROAPass()));
742
743 // InstructionCombining pass folds bitcast and gep instructions which are
744 // not supported by Vulkan SPIR-V.
745 pm.addPass(
746 llvm::createModuleToFunctionPassAdaptor(llvm::InstCombinePass()));
747
748 if (clspv::Option::LanguageUsesGenericAddressSpace()) {
749 pm.addPass(llvm::createModuleToFunctionPassAdaptor(
750 llvm::InferAddressSpacesPass(clspv::AddressSpace::Generic)));
751 }
752 });
753
754 // Run the following passes after the default LLVM pass pipeline.
755 pb.registerOptimizerLastEPCallback([binaryStream](llvm::ModulePassManager &pm,
756 llvm::OptimizationLevel) {
757 // No point attempting to handle freeze currently so strip them from the IR.
758 pm.addPass(clspv::StripFreezePass());
759
760 // Unhide loads from __constant address space. Undoes the action of
761 // HideConstantLoadsPass.
762 pm.addPass(clspv::UnhideConstantLoadsPass());
763
764 pm.addPass(clspv::UndoInstCombinePass());
765 pm.addPass(clspv::FunctionInternalizerPass());
766 pm.addPass(clspv::ReplaceLLVMIntrinsicsPass());
767 // Replace LLVM intrinsics can leave dead code around.
768 pm.addPass(llvm::createModuleToFunctionPassAdaptor(llvm::DCEPass()));
769 pm.addPass(clspv::UndoBoolPass());
770 pm.addPass(clspv::UndoTruncateToOddIntegerPass());
771 // StructurizeCFG requires LowerSwitch to run first.
772 pm.addPass(
773 llvm::createModuleToFunctionPassAdaptor(llvm::LowerSwitchPass()));
774 pm.addPass(
775 llvm::createModuleToFunctionPassAdaptor(llvm::StructurizeCFGPass()));
776 // Must be run after structurize cfg.
777 pm.addPass(llvm::createModuleToFunctionPassAdaptor(
778 clspv::FixupStructuredCFGPass()));
779 // Must be run after structured cfg fixup.
780 pm.addPass(llvm::createModuleToFunctionPassAdaptor(
781 clspv::ReorderBasicBlocksPass()));
782 pm.addPass(clspv::UndoGetElementPtrConstantExprPass());
783 pm.addPass(clspv::SplatArgPass());
784 pm.addPass(clspv::SimplifyPointerBitcastPass());
785 pm.addPass(clspv::ReplacePointerBitcastPass());
786 pm.addPass(llvm::createModuleToFunctionPassAdaptor(llvm::DCEPass()));
787
788 pm.addPass(clspv::UndoTranslateSamplerFoldPass());
789
790 if (clspv::Option::ModuleConstantsInStorageBuffer()) {
791 pm.addPass(clspv::ClusterModuleScopeConstantVars());
792 }
793
794 pm.addPass(clspv::ShareModuleScopeVariablesPass());
795 // Specialize images before assigning descriptors to disambiguate the
796 // various types.
797 pm.addPass(clspv::SpecializeImageTypesPass());
798 // This should be run after LLVM and OpenCL intrinsics are replaced.
799 pm.addPass(clspv::AllocateDescriptorsPass());
800 pm.addPass(llvm::VerifierPass());
801 pm.addPass(clspv::DirectResourceAccessPass());
802 // Replacing pointer bitcasts can leave some trivial GEPs
803 // that are easy to remove. Also replace GEPs of GEPS
804 // left by replacing indirect buffer accesses.
805 pm.addPass(clspv::SimplifyPointerBitcastPass());
806 // Run after DRA to clean up parameters and help reduce the need for
807 // variable pointers.
808 pm.addPass(clspv::RemoveUnusedArguments());
809 pm.addPass(llvm::createModuleToFunctionPassAdaptor(llvm::DCEPass()));
810
811 // SPIR-V 1.4 and higher do not need to splat scalar conditions for vector
812 // data.
813 if (clspv::Option::SpvVersion() < clspv::Option::SPIRVVersion::SPIRV_1_4) {
814 pm.addPass(clspv::SplatSelectConditionPass());
815 }
816 pm.addPass(clspv::SignedCompareFixupPass());
817 // This pass generates insertions that need to be rewritten.
818 pm.addPass(clspv::ScalarizePass());
819 pm.addPass(clspv::RewriteInsertsPass());
820 // UBO Transformations
821 if (clspv::Option::ConstantArgsInUniformBuffer() &&
822 !clspv::Option::InlineEntryPoints()) {
823 // MultiVersionUBOFunctionsPass will examine non-kernel functions with UBO
824 // arguments and either multi-version them as necessary or inline them if
825 // multi-versioning cannot be accomplished.
826 pm.addPass(clspv::MultiVersionUBOFunctionsPass());
827 // Cleanup passes.
828 // Specialization can blindly generate GEP chains that are easily cleaned
829 // up by SimplifyPointerBitcastPass.
830 pm.addPass(clspv::SimplifyPointerBitcastPass());
831 // RemoveUnusedArgumentsPass removes the actual UBO arguments that were
832 // problematic to begin with now that they have no uses.
833 pm.addPass(clspv::RemoveUnusedArguments());
834 // DCE cleans up callers of the specialized functions.
835 pm.addPass(llvm::createModuleToFunctionPassAdaptor(llvm::DCEPass()));
836 }
837 // This pass mucks with types to point where you shouldn't rely on
838 // DataLayout anymore so leave this right before SPIR-V generation.
839 pm.addPass(clspv::UBOTypeTransformPass());
840 pm.addPass(clspv::SPIRVProducerPass(binaryStream, OutputFormat == "c"));
841 });
842
843 // Add the default optimizations for the requested optimization level.
844 if (level.getSpeedupLevel() > 0) {
845 auto mpm = pb.buildPerModuleDefaultPipeline(level);
846 mpm.run(M, mam);
alan-bakerfec0a472018-11-08 18:09:40 -0500847 } else {
alan-baker57ce1c22022-04-26 19:10:44 -0400848 auto mpm = pb.buildO0DefaultPipeline(level);
849 mpm.run(M, mam);
alan-bakerfec0a472018-11-08 18:09:40 -0500850 }
851
alan-bakerf5e5f692018-11-27 08:33:24 -0500852 return 0;
alan-bakerfec0a472018-11-08 18:09:40 -0500853}
alan-bakerfec0a472018-11-08 18:09:40 -0500854
Kévin Petitd5db2d22019-04-04 13:55:14 +0100855int ParseOptions(const int argc, const char *const argv[]) {
alan-baker227e9782020-06-02 15:35:37 -0400856 // We need to change how some of the called passes works by spoofing
857 // ParseCommandLineOptions with the specific options.
858 bool has_pre = false;
859 bool has_load_pre = false;
860 const std::string pre = "-enable-pre";
861 const std::string load_pre = "-enable-load-pre";
862 for (int i = 1; i < argc; ++i) {
863 std::string option(argv[i]);
864 auto pre_pos = option.find(pre);
865 auto load_pos = option.find(load_pre);
866 if (pre_pos == 0 || (pre_pos == 1 && option[0] == '-')) {
867 has_pre = true;
868 } else if (load_pos == 0 || (load_pos == 1 && option[0] == '-')) {
869 has_load_pre = true;
870 }
871 }
872
alan-baker1b333b62021-05-31 14:55:32 -0400873 int llvmArgc = 3;
874 const char *llvmArgv[5];
alan-baker227e9782020-06-02 15:35:37 -0400875 llvmArgv[0] = argv[0];
876 llvmArgv[1] = "-simplifycfg-sink-common=false";
alan-baker1b333b62021-05-31 14:55:32 -0400877 // TODO(#738): find a better solution to this.
878 llvmArgv[2] = "-disable-vector-combine";
alan-baker227e9782020-06-02 15:35:37 -0400879 if (!has_pre) {
880 llvmArgv[llvmArgc++] = "-enable-pre=0";
881 }
882 if (!has_load_pre) {
883 llvmArgv[llvmArgc++] = "-enable-load-pre=0";
884 }
alan-bakerfec0a472018-11-08 18:09:40 -0500885
Kévin Petitd5db2d22019-04-04 13:55:14 +0100886 llvm::cl::ResetAllOptionOccurrences();
alan-bakerfec0a472018-11-08 18:09:40 -0500887 llvm::cl::ParseCommandLineOptions(llvmArgc, llvmArgv);
alan-bakerfec0a472018-11-08 18:09:40 -0500888 llvm::cl::ParseCommandLineOptions(argc, argv);
889
Kévin Petitf0515712020-01-07 18:29:20 +0000890 if (clspv::Option::LanguageUsesGenericAddressSpace() &&
891 !clspv::Option::InlineEntryPoints()) {
892 llvm::errs() << "cannot compile languages that use the generic address "
893 "space (e.g. CLC++, CL2.0) without -inline-entry-points\n";
Kévin Petit0fc88042019-04-09 23:25:02 +0100894 return -1;
895 }
896
Kévin Petitbbbda972020-03-03 19:16:31 +0000897 if (clspv::Option::ScalarBlockLayout()) {
898 llvm::errs() << "scalar block layout support unimplemented\n";
899 return -1;
900 }
901
alan-baker9b0ec3c2020-04-06 14:45:34 -0400902 // Push constant option validation.
903 if (clspv::Option::PodArgsInPushConstants()) {
904 if (clspv::Option::PodArgsInUniformBuffer()) {
905 llvm::errs() << "POD arguments can only be in either uniform buffers or "
906 "push constants\n";
907 return -1;
908 }
909
910 if (!clspv::Option::ClusterPodKernelArgs()) {
911 llvm::errs()
912 << "POD arguments must be clustered to be passed as push constants\n";
913 return -1;
914 }
915
916 // Conservatively error if a module scope push constant could be used.
James Price708cf362020-05-06 19:33:45 -0400917 if (clspv::Option::GlobalOffsetPushConstant() ||
alan-baker9b0ec3c2020-04-06 14:45:34 -0400918 clspv::Option::Language() ==
919 clspv::Option::SourceLanguage::OpenCL_C_20 ||
920 clspv::Option::Language() ==
921 clspv::Option::SourceLanguage::OpenCL_CPP) {
922 llvm::errs() << "POD arguments as push constants are not compatible with "
923 "module scope push constants\n";
924 return -1;
925 }
926 }
927
Mehmet Oguz Derin047cc872021-04-15 19:56:41 +0300928 if (clspv::Option::ArmNonUniformWorkGroupSize() &&
929 clspv::Option::UniformWorkgroupSize()) {
930 llvm::errs() << "cannot enable Arm non-uniform workgroup extension support "
931 "and assume uniform workgroup sizes\n";
932 return -1;
933 }
934
Romaric Jodine40f67d2022-01-18 16:45:08 +0100935 if (clspv::Option::Vec3ToVec4() ==
936 clspv::Option::Vec3ToVec4SupportClass::vec3ToVec4SupportError) {
937 llvm::errs() << "error: -vec3-to-vec4 and -no-vec3-to-vec4 are exclusive "
938 "so they cannot be used together!\n";
939 return -1;
940 }
941
Kévin Petitd5db2d22019-04-04 13:55:14 +0100942 return 0;
943}
Diego Novillo89500852019-04-15 08:45:10 -0400944
alan-baker57ce1c22022-04-26 19:10:44 -0400945int GenerateIRFile(llvm::Module &module, std::string output) {
Diego Novillo89500852019-04-15 08:45:10 -0400946 std::error_code ec;
947 std::unique_ptr<llvm::ToolOutputFile> out(
Natalie Chouinard058da872021-06-17 12:32:47 -0400948 new llvm::ToolOutputFile(output, ec, llvm::sys::fs::OF_None));
Diego Novillo89500852019-04-15 08:45:10 -0400949 if (ec) {
950 llvm::errs() << output << ": " << ec.message() << '\n';
951 return -1;
952 }
alan-baker57ce1c22022-04-26 19:10:44 -0400953
954 llvm::ModuleAnalysisManager mam;
955 llvm::ModulePassManager pm;
956 llvm::PassBuilder pb;
957 pb.registerModuleAnalyses(mam);
958 pm.addPass(llvm::PrintModulePass(out->os(), "", false));
959 pm.run(module, mam);
Diego Novillo89500852019-04-15 08:45:10 -0400960 out->keep();
961 return 0;
962}
963
alan-baker869cd682021-03-05 11:21:19 -0500964bool LinkBuiltinLibrary(llvm::Module *module) {
965 std::unique_ptr<llvm::MemoryBuffer> buffer(new OpenCLBuiltinMemoryBuffer(
966 clspv_builtin_library_data, clspv_builtin_library_size - 1));
967
968 llvm::SMDiagnostic Err;
969 auto library = llvm::parseIR(*buffer, Err, module->getContext());
970 if (!library) {
971 llvm::errs() << "Failed to parse builtins library\n";
972 return false;
973 }
974
975 // TODO: when clang generates builtins using the generic address space,
976 // different builtins are used for pointer-based builtins. Need to do some
977 // work to ensure they are kept around.
978 // Affects: modf, remquo, lgamma_r, frexp
979
980 llvm::Linker L(*module);
981 L.linkInModule(std::move(library), 0);
982
983 return true;
984}
985
Kévin Petitd5db2d22019-04-04 13:55:14 +0100986} // namespace
987
988namespace clspv {
Ryan Senanayake6917fb12022-02-28 18:17:02 -0500989int Compile(const llvm::StringRef &input_filename, const std::string &program,
990 const std::string &sampler_map,
991 std::vector<uint32_t> *output_binary, std::string *output_log) {
alan-bakerfec0a472018-11-08 18:09:40 -0500992 llvm::SmallVector<std::pair<unsigned, std::string>, 8> SamplerMapEntries;
Ryan Senanayake6917fb12022-02-28 18:17:02 -0500993 if (auto error = ParseSamplerMap(sampler_map, &SamplerMapEntries))
alan-bakerfec0a472018-11-08 18:09:40 -0500994 return error;
995
Ryan Senanayake6917fb12022-02-28 18:17:02 -0500996 llvm::StringRef overiddenInputFilename = input_filename;
alan-bakerfec0a472018-11-08 18:09:40 -0500997
998 clang::CompilerInstance instance;
Kévin Petitddad8f42019-09-30 15:12:08 +0100999 clang::FrontendInputFile kernelFile(overiddenInputFilename,
1000 clang::InputKind(InputLanguage));
alan-bakerfec0a472018-11-08 18:09:40 -05001001 std::string log;
1002 llvm::raw_string_ostream diagnosticsStream(log);
Ryan Senanayake6917fb12022-02-28 18:17:02 -05001003 std::unique_ptr<llvm::MemoryBuffer> file_memory_buffer;
alan-bakerf5e5f692018-11-27 08:33:24 -05001004 if (auto error = SetCompilerInstanceOptions(
Ryan Senanayake6917fb12022-02-28 18:17:02 -05001005 instance, overiddenInputFilename, kernelFile, program,
1006 file_memory_buffer, &diagnosticsStream))
alan-bakerfec0a472018-11-08 18:09:40 -05001007 return error;
1008
1009 // Parse.
1010 llvm::LLVMContext context;
1011 clang::EmitLLVMOnlyAction action(&context);
1012
1013 // Prepare the action for processing kernelFile
1014 const bool success = action.BeginSourceFile(instance, kernelFile);
1015 if (!success) {
1016 return -1;
1017 }
1018
alan-bakerf3bce4a2019-06-28 16:01:15 -04001019 auto result = action.Execute();
alan-bakerfec0a472018-11-08 18:09:40 -05001020 action.EndSourceFile();
1021
1022 clang::DiagnosticConsumer *const consumer =
1023 instance.getDiagnostics().getClient();
1024 consumer->finish();
1025
Kévin Petit6b07cbe2019-04-02 21:52:16 +01001026 auto num_warnings = consumer->getNumWarnings();
alan-bakerfec0a472018-11-08 18:09:40 -05001027 auto num_errors = consumer->getNumErrors();
Ryan Senanayake6917fb12022-02-28 18:17:02 -05001028 if (output_log != nullptr) {
1029 *output_log = log;
1030 } else if ((num_errors > 0) || (num_warnings > 0)) {
Kévin Petit6b07cbe2019-04-02 21:52:16 +01001031 llvm::errs() << log;
1032 }
alan-bakerf3bce4a2019-06-28 16:01:15 -04001033 if (result || num_errors > 0) {
alan-bakerfec0a472018-11-08 18:09:40 -05001034 return -1;
1035 }
1036
Kévin Petit6b07cbe2019-04-02 21:52:16 +01001037 // Don't run the passes or produce any output in verify mode.
1038 // Clang doesn't always produce a valid module.
1039 if (verify) {
1040 return 0;
1041 }
1042
alan-bakerfec0a472018-11-08 18:09:40 -05001043 std::unique_ptr<llvm::Module> module(action.takeModule());
1044
1045 // Optimize.
1046 // Create a memory buffer for temporarily writing the result.
1047 SmallVector<char, 10000> binary;
1048 llvm::raw_svector_ostream binaryStream(binary);
Diego Novillo89500852019-04-15 08:45:10 -04001049
1050 // If --emit-ir was requested, emit the initial LLVM IR and stop compilation.
1051 if (!IROutputFile.empty()) {
alan-baker57ce1c22022-04-26 19:10:44 -04001052 return GenerateIRFile(*module, IROutputFile);
Diego Novillo89500852019-04-15 08:45:10 -04001053 }
1054
alan-baker869cd682021-03-05 11:21:19 -05001055 if (!LinkBuiltinLibrary(module.get())) {
1056 return -1;
1057 }
1058
alan-baker57ce1c22022-04-26 19:10:44 -04001059 // Run the passes to produce SPIR-V.
1060 if (RunPassPipeline(*module, &binaryStream) != 0) {
1061 return -1;
1062 }
alan-bakerfec0a472018-11-08 18:09:40 -05001063
alan-bakerfec0a472018-11-08 18:09:40 -05001064 // Write the resulting binary.
1065 // Wait until now to try writing the file so that we only write it on
1066 // successful compilation.
Ryan Senanayake6917fb12022-02-28 18:17:02 -05001067 if (output_binary) {
1068 output_binary->resize(binary.size() / 4);
1069 memcpy(output_binary->data(), binary.data(), binary.size());
1070 }
1071
1072 if (!OutputFilename.empty()) {
1073 std::error_code error;
1074 llvm::raw_fd_ostream outStream(OutputFilename, error,
1075 llvm::sys::fs::FA_Write);
1076
1077 if (error) {
1078 llvm::errs() << "Unable to open output file '" << OutputFilename
1079 << "': " << error.message() << '\n';
1080 return -1;
1081 }
1082 outStream << binaryStream.str();
1083 }
1084
1085 return 0;
1086}
1087
1088int Compile(const int argc, const char *const argv[]) {
1089 if (auto error = ParseOptions(argc, argv))
1090 return error;
1091
1092 // if no input file was provided, use a default
1093 llvm::StringRef overiddenInputFilename = InputFilename.getValue();
1094
1095 // If we are reading our input file from stdin.
1096 if ("-" == InputFilename) {
1097 // We need to overwrite the file name we use.
1098 switch (InputLanguage) {
1099 case clang::Language::OpenCL:
1100 overiddenInputFilename = "stdin.cl";
1101 break;
1102 case clang::Language::LLVM_IR:
1103 overiddenInputFilename = "stdin.ll";
1104 break;
1105 default:
1106 // Default to fix compiler warnings/errors. Option parsing will reject a
1107 // bad enum value for the option so there is no need for a message.
1108 return -1;
1109 }
1110 }
1111
alan-bakerfec0a472018-11-08 18:09:40 -05001112 if (OutputFilename.empty()) {
Kévin Petite4786902019-04-02 21:51:47 +01001113 if (OutputFormat == "c") {
alan-bakerfec0a472018-11-08 18:09:40 -05001114 OutputFilename = "a.spvinc";
1115 } else {
1116 OutputFilename = "a.spv";
1117 }
1118 }
alan-bakerfec0a472018-11-08 18:09:40 -05001119
Ryan Senanayake6917fb12022-02-28 18:17:02 -05001120 return Compile(overiddenInputFilename, "", "", nullptr, nullptr);
alan-bakerfec0a472018-11-08 18:09:40 -05001121}
alan-bakerf5e5f692018-11-27 08:33:24 -05001122
alan-baker86ce19c2020-08-05 13:09:19 -04001123int CompileFromSourceString(const std::string &program,
1124 const std::string &sampler_map,
1125 const std::string &options,
Kévin Petit899162d2020-09-08 19:16:08 +01001126 std::vector<uint32_t> *output_binary,
1127 std::string *output_log) {
alan-bakerf5e5f692018-11-27 08:33:24 -05001128
1129 llvm::SmallVector<const char *, 20> argv;
1130 llvm::BumpPtrAllocator A;
1131 llvm::StringSaver Saver(A);
1132 argv.push_back(Saver.save("clspv").data());
1133 llvm::cl::TokenizeGNUCommandLine(options, Saver, argv);
1134 int argc = static_cast<int>(argv.size());
Kévin Petitd5db2d22019-04-04 13:55:14 +01001135
1136 if (auto error = ParseOptions(argc, &argv[0]))
1137 return error;
alan-bakerf5e5f692018-11-27 08:33:24 -05001138
Ryan Senanayake6917fb12022-02-28 18:17:02 -05001139 return Compile("source", program, sampler_map, output_binary, output_log);
alan-bakerf5e5f692018-11-27 08:33:24 -05001140}
alan-bakerfec0a472018-11-08 18:09:40 -05001141} // namespace clspv