blob: 1b6cbe78cf6d5e8295cfb4b3e2114a14384fd4b3 [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
alan-bakerfec0a472018-11-08 18:09:40 -0500103static llvm::cl::list<std::string>
104 Includes(llvm::cl::Prefix, "I",
105 llvm::cl::desc("Add a directory to the list of directories "
106 "to be searched for header files."),
107 llvm::cl::ZeroOrMore, llvm::cl::value_desc("include path"));
108
109static llvm::cl::list<std::string>
110 Defines(llvm::cl::Prefix, "D",
111 llvm::cl::desc("Define a #define directive."), llvm::cl::ZeroOrMore,
112 llvm::cl::value_desc("define"));
113
114static llvm::cl::opt<std::string>
115 InputFilename(llvm::cl::Positional, llvm::cl::desc("<input .cl file>"),
116 llvm::cl::init("-"));
117
Kévin Petitddad8f42019-09-30 15:12:08 +0100118static llvm::cl::opt<clang::Language> InputLanguage(
119 "x", llvm::cl::desc("Select input type"),
120 llvm::cl::init(clang::Language::OpenCL),
121 llvm::cl::values(clEnumValN(clang::Language::OpenCL, "cl", "OpenCL source"),
122 clEnumValN(clang::Language::LLVM_IR, "ir", "LLVM IR")));
123
alan-bakerfec0a472018-11-08 18:09:40 -0500124static llvm::cl::opt<std::string>
125 OutputFilename("o", llvm::cl::desc("Override output filename"),
126 llvm::cl::value_desc("filename"));
127
alan-bakerfec0a472018-11-08 18:09:40 -0500128static llvm::cl::opt<char>
129 OptimizationLevel(llvm::cl::Prefix, "O", llvm::cl::init('2'),
130 llvm::cl::desc("Optimization level to use"),
131 llvm::cl::value_desc("level"));
132
alan-bakerfec0a472018-11-08 18:09:40 -0500133static llvm::cl::opt<std::string> OutputFormat(
134 "mfmt", llvm::cl::init(""),
135 llvm::cl::desc(
136 "Specify special output format. 'c' is as a C initializer list"),
137 llvm::cl::value_desc("format"));
138
139static llvm::cl::opt<std::string>
alan-baker09cb9802019-12-10 13:16:27 -0500140 SamplerMap("samplermap", llvm::cl::desc("DEPRECATED - Literal sampler map"),
alan-bakerfec0a472018-11-08 18:09:40 -0500141 llvm::cl::value_desc("filename"));
142
alan-bakerfec0a472018-11-08 18:09:40 -0500143static llvm::cl::opt<bool> verify("verify", llvm::cl::init(false),
144 llvm::cl::desc("Verify diagnostic outputs"));
145
Kévin Petit6b07cbe2019-04-02 21:52:16 +0100146static llvm::cl::opt<bool>
147 IgnoreWarnings("w", llvm::cl::init(false),
148 llvm::cl::desc("Disable all warnings"));
149
150static llvm::cl::opt<bool>
151 WarningsAsErrors("Werror", llvm::cl::init(false),
Diego Novillo3cc8d7a2019-04-10 13:30:34 -0400152 llvm::cl::desc("Turn warnings into errors"));
Kévin Petit6b07cbe2019-04-02 21:52:16 +0100153
Diego Novillo89500852019-04-15 08:45:10 -0400154static llvm::cl::opt<std::string> IROutputFile(
155 "emit-ir",
156 llvm::cl::desc(
157 "Emit LLVM IR to the given file after parsing and stop compilation."),
158 llvm::cl::value_desc("filename"));
159
alan-baker869cd682021-03-05 11:21:19 -0500160namespace {
161struct OpenCLBuiltinMemoryBuffer final : public llvm::MemoryBuffer {
162 OpenCLBuiltinMemoryBuffer(const void *data, uint64_t data_length) {
163 const char *dataCasted = reinterpret_cast<const char *>(data);
164 init(dataCasted, dataCasted + data_length, true);
165 }
166
167 virtual llvm::MemoryBuffer::BufferKind getBufferKind() const override {
168 return llvm::MemoryBuffer::MemoryBuffer_Malloc;
169 }
170
171 virtual ~OpenCLBuiltinMemoryBuffer() override {}
172};
173} // namespace
174
alan-bakerfec0a472018-11-08 18:09:40 -0500175// Populates |SamplerMapEntries| with data from the input sampler map. Returns 0
176// if successful.
alan-bakerf5e5f692018-11-27 08:33:24 -0500177int ParseSamplerMap(const std::string &sampler_map,
178 llvm::SmallVectorImpl<std::pair<unsigned, std::string>>
179 *SamplerMapEntries) {
180 std::unique_ptr<llvm::MemoryBuffer> samplerMapBuffer(nullptr);
181 if (!sampler_map.empty()) {
182 // Parse the sampler map from the provided string.
183 samplerMapBuffer = llvm::MemoryBuffer::getMemBuffer(sampler_map);
184
alan-baker09cb9802019-12-10 13:16:27 -0500185 clspv::Option::SetUseSamplerMap(true);
alan-bakerf5e5f692018-11-27 08:33:24 -0500186 if (!SamplerMap.empty()) {
187 llvm::outs() << "Warning: -samplermap is ignored when the sampler map is "
188 "provided through a string.\n";
189 }
190 } else if (!SamplerMap.empty()) {
191 // Parse the sampler map from the option provided file.
alan-bakerfec0a472018-11-08 18:09:40 -0500192 auto errorOrSamplerMapFile =
193 llvm::MemoryBuffer::getFile(SamplerMap.getValue());
194
195 // If there was an error in getting the sampler map file.
196 if (!errorOrSamplerMapFile) {
197 llvm::errs() << "Error: " << errorOrSamplerMapFile.getError().message()
198 << " '" << SamplerMap.getValue() << "'\n";
199 return -1;
200 }
201
alan-baker09cb9802019-12-10 13:16:27 -0500202 clspv::Option::SetUseSamplerMap(true);
alan-bakerf5e5f692018-11-27 08:33:24 -0500203 samplerMapBuffer = std::move(errorOrSamplerMapFile.get());
alan-bakerfec0a472018-11-08 18:09:40 -0500204 if (0 == samplerMapBuffer->getBufferSize()) {
205 llvm::errs() << "Error: Sampler map was an empty file!\n";
206 return -1;
207 }
alan-bakerf5e5f692018-11-27 08:33:24 -0500208 }
alan-bakerfec0a472018-11-08 18:09:40 -0500209
alan-baker09cb9802019-12-10 13:16:27 -0500210 if (clspv::Option::UseSamplerMap()) {
alan-baker57ce1c22022-04-26 19:10:44 -0400211 // TODO(alan-baker): Remove all APIs dealing the sampler map after landing
212 // the transition to the new pass manager.
213 llvm::errs() << "Error: use of a sampler map is no longer supported\n";
214 return -1;
alan-baker09cb9802019-12-10 13:16:27 -0500215 }
216
alan-bakerf5e5f692018-11-27 08:33:24 -0500217 // No sampler map to parse.
218 if (!samplerMapBuffer || 0 == samplerMapBuffer->getBufferSize())
219 return 0;
alan-bakerfec0a472018-11-08 18:09:40 -0500220
alan-bakerf5e5f692018-11-27 08:33:24 -0500221 llvm::SmallVector<llvm::StringRef, 3> samplerStrings;
alan-bakerfec0a472018-11-08 18:09:40 -0500222
alan-bakerf5e5f692018-11-27 08:33:24 -0500223 // We need to keep track of the beginning of the current entry.
224 const char *b = samplerMapBuffer->getBufferStart();
225 for (const char *i = b, *e = samplerMapBuffer->getBufferEnd();; i++) {
226 // If we have a separator between declarations.
227 if ((*i == '|') || (*i == ',') || (i == e)) {
228 if (i == b) {
229 llvm::errs() << "Error: Sampler map contained an empty entry!\n";
230 return -1;
alan-bakerfec0a472018-11-08 18:09:40 -0500231 }
232
alan-bakerf5e5f692018-11-27 08:33:24 -0500233 samplerStrings.push_back(llvm::StringRef(b, i - b).trim());
alan-bakerfec0a472018-11-08 18:09:40 -0500234
alan-bakerf5e5f692018-11-27 08:33:24 -0500235 // And set b the next character after i.
236 b = i + 1;
237 }
alan-bakerfec0a472018-11-08 18:09:40 -0500238
alan-bakerf5e5f692018-11-27 08:33:24 -0500239 // If we have a separator between declarations within a single sampler.
240 if ((*i == ',') || (i == e)) {
alan-bakerfec0a472018-11-08 18:09:40 -0500241
alan-baker86ce19c2020-08-05 13:09:19 -0400242 clspv::SamplerNormalizedCoords NormalizedCoord =
243 clspv::CLK_NORMALIZED_COORDS_NOT_SET;
244 clspv::SamplerAddressingMode AddressingMode = clspv::CLK_ADDRESS_NOT_SET;
245 clspv::SamplerFilterMode FilterMode = clspv::CLK_FILTER_NOT_SET;
alan-bakerf5e5f692018-11-27 08:33:24 -0500246
247 for (auto str : samplerStrings) {
248 if ("CLK_NORMALIZED_COORDS_FALSE" == str) {
alan-baker86ce19c2020-08-05 13:09:19 -0400249 if (clspv::CLK_NORMALIZED_COORDS_NOT_SET != NormalizedCoord) {
alan-bakerf5e5f692018-11-27 08:33:24 -0500250 llvm::errs() << "Error: Sampler map normalized coordinates was "
251 "previously set!\n";
alan-bakerfec0a472018-11-08 18:09:40 -0500252 return -1;
253 }
alan-baker86ce19c2020-08-05 13:09:19 -0400254 NormalizedCoord = clspv::CLK_NORMALIZED_COORDS_FALSE;
alan-bakerf5e5f692018-11-27 08:33:24 -0500255 } else if ("CLK_NORMALIZED_COORDS_TRUE" == str) {
alan-baker86ce19c2020-08-05 13:09:19 -0400256 if (clspv::CLK_NORMALIZED_COORDS_NOT_SET != NormalizedCoord) {
alan-bakerf5e5f692018-11-27 08:33:24 -0500257 llvm::errs() << "Error: Sampler map normalized coordinates was "
258 "previously set!\n";
259 return -1;
260 }
alan-baker86ce19c2020-08-05 13:09:19 -0400261 NormalizedCoord = clspv::CLK_NORMALIZED_COORDS_TRUE;
alan-bakerf5e5f692018-11-27 08:33:24 -0500262 } else if ("CLK_ADDRESS_NONE" == str) {
alan-baker86ce19c2020-08-05 13:09:19 -0400263 if (clspv::CLK_ADDRESS_NOT_SET != AddressingMode) {
alan-bakerf5e5f692018-11-27 08:33:24 -0500264 llvm::errs()
265 << "Error: Sampler map addressing mode was previously set!\n";
266 return -1;
267 }
alan-baker86ce19c2020-08-05 13:09:19 -0400268 AddressingMode = clspv::CLK_ADDRESS_NONE;
alan-bakerf5e5f692018-11-27 08:33:24 -0500269 } else if ("CLK_ADDRESS_CLAMP_TO_EDGE" == str) {
alan-baker86ce19c2020-08-05 13:09:19 -0400270 if (clspv::CLK_ADDRESS_NOT_SET != AddressingMode) {
alan-bakerf5e5f692018-11-27 08:33:24 -0500271 llvm::errs()
272 << "Error: Sampler map addressing mode was previously set!\n";
273 return -1;
274 }
alan-baker86ce19c2020-08-05 13:09:19 -0400275 AddressingMode = clspv::CLK_ADDRESS_CLAMP_TO_EDGE;
alan-bakerf5e5f692018-11-27 08:33:24 -0500276 } else if ("CLK_ADDRESS_CLAMP" == str) {
alan-baker86ce19c2020-08-05 13:09:19 -0400277 if (clspv::CLK_ADDRESS_NOT_SET != AddressingMode) {
alan-bakerf5e5f692018-11-27 08:33:24 -0500278 llvm::errs()
279 << "Error: Sampler map addressing mode was previously set!\n";
280 return -1;
281 }
alan-baker86ce19c2020-08-05 13:09:19 -0400282 AddressingMode = clspv::CLK_ADDRESS_CLAMP;
alan-bakerf5e5f692018-11-27 08:33:24 -0500283 } else if ("CLK_ADDRESS_MIRRORED_REPEAT" == str) {
alan-baker86ce19c2020-08-05 13:09:19 -0400284 if (clspv::CLK_ADDRESS_NOT_SET != AddressingMode) {
alan-bakerf5e5f692018-11-27 08:33:24 -0500285 llvm::errs()
286 << "Error: Sampler map addressing mode was previously set!\n";
287 return -1;
288 }
alan-baker86ce19c2020-08-05 13:09:19 -0400289 AddressingMode = clspv::CLK_ADDRESS_MIRRORED_REPEAT;
alan-bakerf5e5f692018-11-27 08:33:24 -0500290 } else if ("CLK_ADDRESS_REPEAT" == str) {
alan-baker86ce19c2020-08-05 13:09:19 -0400291 if (clspv::CLK_ADDRESS_NOT_SET != AddressingMode) {
alan-bakerf5e5f692018-11-27 08:33:24 -0500292 llvm::errs()
293 << "Error: Sampler map addressing mode was previously set!\n";
294 return -1;
295 }
alan-baker86ce19c2020-08-05 13:09:19 -0400296 AddressingMode = clspv::CLK_ADDRESS_REPEAT;
alan-bakerf5e5f692018-11-27 08:33:24 -0500297 } else if ("CLK_FILTER_NEAREST" == str) {
alan-baker86ce19c2020-08-05 13:09:19 -0400298 if (clspv::CLK_FILTER_NOT_SET != FilterMode) {
alan-bakerf5e5f692018-11-27 08:33:24 -0500299 llvm::errs()
300 << "Error: Sampler map filtering mode was previously set!\n";
301 return -1;
302 }
alan-baker86ce19c2020-08-05 13:09:19 -0400303 FilterMode = clspv::CLK_FILTER_NEAREST;
alan-bakerf5e5f692018-11-27 08:33:24 -0500304 } else if ("CLK_FILTER_LINEAR" == str) {
alan-baker86ce19c2020-08-05 13:09:19 -0400305 if (clspv::CLK_FILTER_NOT_SET != FilterMode) {
alan-bakerf5e5f692018-11-27 08:33:24 -0500306 llvm::errs()
307 << "Error: Sampler map filtering mode was previously set!\n";
308 return -1;
309 }
alan-baker86ce19c2020-08-05 13:09:19 -0400310 FilterMode = clspv::CLK_FILTER_LINEAR;
alan-bakerf5e5f692018-11-27 08:33:24 -0500311 } else {
312 llvm::errs() << "Error: Unknown sampler string '" << str
313 << "' found!\n";
alan-bakerfec0a472018-11-08 18:09:40 -0500314 return -1;
315 }
alan-bakerfec0a472018-11-08 18:09:40 -0500316 }
317
alan-baker86ce19c2020-08-05 13:09:19 -0400318 if (clspv::CLK_NORMALIZED_COORDS_NOT_SET == NormalizedCoord) {
alan-bakerf5e5f692018-11-27 08:33:24 -0500319 llvm::errs() << "Error: Sampler map entry did not contain normalized "
320 "coordinates entry!\n";
321 return -1;
alan-bakerfec0a472018-11-08 18:09:40 -0500322 }
alan-bakerf5e5f692018-11-27 08:33:24 -0500323
alan-baker86ce19c2020-08-05 13:09:19 -0400324 if (clspv::CLK_ADDRESS_NOT_SET == AddressingMode) {
alan-bakerf5e5f692018-11-27 08:33:24 -0500325 llvm::errs() << "Error: Sampler map entry did not contain addressing "
326 "mode entry!\n";
327 return -1;
328 }
329
alan-baker86ce19c2020-08-05 13:09:19 -0400330 if (clspv::CLK_FILTER_NOT_SET == FilterMode) {
alan-bakerf5e5f692018-11-27 08:33:24 -0500331 llvm::errs()
332 << "Error: Sampler map entry did not contain filer mode entry!\n";
333 return -1;
334 }
335
336 // Generate an equivalent expression in string form. Sort the
337 // strings to get a canonical ordering.
338 std::sort(samplerStrings.begin(), samplerStrings.end(),
339 std::less<StringRef>());
340 const auto samplerExpr = std::accumulate(
341 samplerStrings.begin(), samplerStrings.end(), std::string(),
alan-baker21574d32020-01-29 16:00:31 -0500342 [](llvm::StringRef left, llvm::StringRef right) {
343 return left.str() + std::string(left.empty() ? "" : "|") +
344 right.str();
alan-bakerf5e5f692018-11-27 08:33:24 -0500345 });
346
347 // SamplerMapEntries->push_back(std::make_pair(
348 // NormalizedCoord | AddressingMode | FilterMode, samplerExpr));
349 SamplerMapEntries->emplace_back(
350 NormalizedCoord | AddressingMode | FilterMode, samplerExpr);
351
352 // And reset the sampler strings for the next sampler in the map.
353 samplerStrings.clear();
354 }
355
356 // And lastly, if we are at the end of the file
357 if (i == e) {
358 break;
alan-bakerfec0a472018-11-08 18:09:40 -0500359 }
360 }
361
362 return 0;
363}
364
Kévin Petitaab5bb82021-03-30 16:26:11 +0100365clang::TargetInfo *PrepareTargetInfo(CompilerInstance &instance) {
366 // Create target info
367 auto TargetInfo = clang::TargetInfo::CreateTargetInfo(
368 instance.getDiagnostics(),
369 std::make_shared<clang::TargetOptions>(instance.getTargetOpts()));
370
371 // The SPIR target enables all possible options, disable the ones we don't
372 // want
373 auto &Opts = TargetInfo->getSupportedOpenCLOpts();
374
375 // Conditionally disable extensions based on support
376 if (!clspv::Option::FP16()) {
377 Opts["cl_khr_fp16"] = false;
378 }
379 if (!clspv::Option::FP64()) {
380 Opts["cl_khr_fp64"] = false;
381 }
382
383 // Disable CL3.0 feature macros for unsupported features
384 if (instance.getLangOpts().LangStd == clang::LangStandard::lang_opencl30) {
385
Kévin Petitaab5bb82021-03-30 16:26:11 +0100386 // The following features are never supported
387 Opts["__opencl_c_pipes"] = false;
388 Opts["__opencl_c_generic_address_space"] = false;
Kévin Petitaab5bb82021-03-30 16:26:11 +0100389 Opts["__opencl_c_device_enqueue"] = false;
390 Opts["__opencl_c_program_scope_global_variables"] = false;
391
392 if (!clspv::Option::ImageSupport()) {
393 Opts["__opencl_c_images"] = false;
394 }
395
396 if (!clspv::Option::FP64()) {
397 Opts["__opencl_c_fp64"] = false;
398 }
399 }
400
401 return TargetInfo;
402}
403
alan-bakerfec0a472018-11-08 18:09:40 -0500404// Sets |instance|'s options for compiling. Returns 0 if successful.
Ryan Senanayake6917fb12022-02-28 18:17:02 -0500405int SetCompilerInstanceOptions(
406 CompilerInstance &instance, const llvm::StringRef &overiddenInputFilename,
407 clang::FrontendInputFile &kernelFile, const std::string &program,
408 std::unique_ptr<llvm::MemoryBuffer> &file_memory_buffer,
409 llvm::raw_string_ostream *diagnosticsStream) {
alan-bakerf5e5f692018-11-27 08:33:24 -0500410 llvm::ErrorOr<std::unique_ptr<llvm::MemoryBuffer>> errorOrInputFile(nullptr);
411 if (program.empty()) {
412 auto errorOrInputFile =
413 llvm::MemoryBuffer::getFileOrSTDIN(InputFilename.getValue());
alan-bakerfec0a472018-11-08 18:09:40 -0500414
alan-bakerf5e5f692018-11-27 08:33:24 -0500415 // If there was an error in getting the input file.
416 if (!errorOrInputFile) {
417 llvm::errs() << "Error: " << errorOrInputFile.getError().message() << " '"
418 << InputFilename.getValue() << "'\n";
419 return -1;
420 }
Ryan Senanayake6917fb12022-02-28 18:17:02 -0500421 file_memory_buffer = std::move(errorOrInputFile.get());
alan-bakerf5e5f692018-11-27 08:33:24 -0500422 } else {
Ryan Senanayake6917fb12022-02-28 18:17:02 -0500423 file_memory_buffer =
424 llvm::MemoryBuffer::getMemBuffer(program, overiddenInputFilename);
alan-bakerfec0a472018-11-08 18:09:40 -0500425 }
alan-bakerf5e5f692018-11-27 08:33:24 -0500426
alan-bakerfec0a472018-11-08 18:09:40 -0500427 if (verify) {
428 instance.getDiagnosticOpts().VerifyDiagnostics = true;
alan-bakerbccf62c2019-03-29 10:32:41 -0400429 instance.getDiagnosticOpts().VerifyPrefixes.push_back("expected");
alan-bakerfec0a472018-11-08 18:09:40 -0500430 }
431
Kévin Petit0fc88042019-04-09 23:25:02 +0100432 clang::LangStandard::Kind standard;
Kévin Petitf0515712020-01-07 18:29:20 +0000433 switch (clspv::Option::Language()) {
434 case clspv::Option::SourceLanguage::OpenCL_C_10:
435 standard = clang::LangStandard::lang_opencl10;
436 break;
437 case clspv::Option::SourceLanguage::OpenCL_C_11:
438 standard = clang::LangStandard::lang_opencl11;
439 break;
440 case clspv::Option::SourceLanguage::OpenCL_C_12:
Kévin Petit0fc88042019-04-09 23:25:02 +0100441 standard = clang::LangStandard::lang_opencl12;
Kévin Petitf0515712020-01-07 18:29:20 +0000442 break;
443 case clspv::Option::SourceLanguage::OpenCL_C_20:
444 standard = clang::LangStandard::lang_opencl20;
445 break;
Kévin Petit77838ff2020-10-19 18:54:51 +0100446 case clspv::Option::SourceLanguage::OpenCL_C_30:
447 standard = clang::LangStandard::lang_opencl30;
448 break;
Kévin Petitf0515712020-01-07 18:29:20 +0000449 case clspv::Option::SourceLanguage::OpenCL_CPP:
alan-baker39706812021-08-03 13:21:39 -0400450 standard = clang::LangStandard::lang_openclcpp10;
Kévin Petitf0515712020-01-07 18:29:20 +0000451 break;
452 default:
453 llvm_unreachable("Unknown source language");
Kévin Petit0fc88042019-04-09 23:25:02 +0100454 }
alan-bakerfec0a472018-11-08 18:09:40 -0500455
alan-bakerfec0a472018-11-08 18:09:40 -0500456 instance.getLangOpts().C99 = true;
457 instance.getLangOpts().RTTI = false;
458 instance.getLangOpts().RTTIData = false;
459 instance.getLangOpts().MathErrno = false;
460 instance.getLangOpts().Optimize = false;
461 instance.getLangOpts().NoBuiltin = true;
462 instance.getLangOpts().ModulesSearchAll = false;
463 instance.getLangOpts().SinglePrecisionConstants = true;
464 instance.getCodeGenOpts().StackRealignment = true;
465 instance.getCodeGenOpts().SimplifyLibCalls = false;
466 instance.getCodeGenOpts().EmitOpenCLArgMetadata = false;
467 instance.getCodeGenOpts().DisableO0ImplyOptNone = true;
Kévin Petit6b07cbe2019-04-02 21:52:16 +0100468 instance.getDiagnosticOpts().IgnoreWarnings = IgnoreWarnings;
alan-bakerfec0a472018-11-08 18:09:40 -0500469
470 instance.getLangOpts().SinglePrecisionConstants =
471 cl_single_precision_constants;
472 // cl_denorms_are_zero ignored for now!
473 // cl_fp32_correctly_rounded_divide_sqrt ignored for now!
474 instance.getCodeGenOpts().LessPreciseFPMAD =
alan-baker7b664822022-05-02 18:03:04 -0400475 cl_mad_enable || clspv::Option::UnsafeMath();
alan-bakerfec0a472018-11-08 18:09:40 -0500476 // cl_no_signed_zeros ignored for now!
alan-baker7b664822022-05-02 18:03:04 -0400477 instance.getLangOpts().UnsafeFPMath = clspv::Option::UnsafeMath();
478 instance.getLangOpts().FiniteMathOnly = clspv::Option::FiniteMath();
479 instance.getLangOpts().FastRelaxedMath = clspv::Option::FastRelaxedMath();
alan-bakerfec0a472018-11-08 18:09:40 -0500480
481 // Preprocessor options
Kévin Petita624c0c2019-05-07 20:27:43 +0800482 if (!clspv::Option::ImageSupport()) {
483 instance.getPreprocessorOpts().addMacroUndef("__IMAGE_SUPPORT__");
484 }
alan-baker7b664822022-05-02 18:03:04 -0400485 if (clspv::Option::FastRelaxedMath()) {
alan-bakerfec0a472018-11-08 18:09:40 -0500486 instance.getPreprocessorOpts().addMacroDef("__FAST_RELAXED_MATH__");
487 }
488
489 for (auto define : Defines) {
490 instance.getPreprocessorOpts().addMacroDef(define);
491 }
492
493 // Header search options
494 for (auto include : Includes) {
495 instance.getHeaderSearchOpts().AddPath(include, clang::frontend::After,
496 false, false);
497 }
498
499 // We always compile on opt 0 so we preserve as much debug information about
500 // the source as possible. We'll run optimization later, once we've had a
501 // chance to view the unoptimal code first
502 instance.getCodeGenOpts().OptimizationLevel = 0;
503
504// Debug information is disabled temporarily to call instruction.
505#if 0
506 instance.getCodeGenOpts().setDebugInfo(clang::codegenoptions::FullDebugInfo);
507#endif
508
509 // We use the 32-bit pointer-width SPIR triple
510 llvm::Triple triple("spir-unknown-unknown");
511
James Price40efe7f2021-01-18 09:19:31 -0500512 // We manually include the OpenCL headers below, so this vector is unused.
513 std::vector<std::string> includes;
514
alan-baker1e20bf22022-04-13 16:05:14 -0400515 LangOptions::setLangDefaults(instance.getLangOpts(), clang::Language::OpenCL,
516 triple, includes, standard);
alan-bakerfec0a472018-11-08 18:09:40 -0500517
518 // Override the C99 inline semantics to accommodate for more OpenCL C
519 // programs in the wild.
520 instance.getLangOpts().GNUInline = true;
Kévin Petit6b07cbe2019-04-02 21:52:16 +0100521
522 // Set up diagnostics
alan-bakerfec0a472018-11-08 18:09:40 -0500523 instance.createDiagnostics(
524 new clang::TextDiagnosticPrinter(*diagnosticsStream,
525 &instance.getDiagnosticOpts()),
526 true);
Kévin Petit6b07cbe2019-04-02 21:52:16 +0100527 instance.getDiagnostics().setWarningsAsErrors(WarningsAsErrors);
528 instance.getDiagnostics().setEnableAllWarnings(true);
alan-bakerfec0a472018-11-08 18:09:40 -0500529
530 instance.getTargetOpts().Triple = triple.str();
531
alan-baker21574d32020-01-29 16:00:31 -0500532 instance.getCodeGenOpts().MainFileName = overiddenInputFilename.str();
alan-bakerfec0a472018-11-08 18:09:40 -0500533 instance.getCodeGenOpts().PreserveVec3Type = true;
534 // Disable generation of lifetime intrinsic.
535 instance.getCodeGenOpts().DisableLifetimeMarkers = true;
Ryan Senanayake6917fb12022-02-28 18:17:02 -0500536 if (InputLanguage == clang::Language::OpenCL) {
537 instance.getPreprocessorOpts().addRemappedFile(
538 overiddenInputFilename, file_memory_buffer.release());
539 } else if (!program.empty()) {
540 // Can't use preprocessor to do file remapping for LLVM_IR
541 kernelFile = clang::FrontendInputFile(*file_memory_buffer,
542 clang::InputKind(InputLanguage));
543 }
alan-bakerfec0a472018-11-08 18:09:40 -0500544 instance.getFrontendOpts().Inputs.push_back(kernelFile);
alan-bakerfec0a472018-11-08 18:09:40 -0500545
alan-bakerfec0a472018-11-08 18:09:40 -0500546 std::unique_ptr<llvm::MemoryBuffer> openCLBuiltinMemoryBuffer(
547 new OpenCLBuiltinMemoryBuffer(opencl_builtins_header_data,
548 opencl_builtins_header_size - 1));
549
James Price40efe7f2021-01-18 09:19:31 -0500550 instance.getPreprocessorOpts().Includes.push_back("opencl-c.h");
alan-bakerfec0a472018-11-08 18:09:40 -0500551
alan-bakerf3bce4a2019-06-28 16:01:15 -0400552 std::unique_ptr<llvm::MemoryBuffer> openCLBaseBuiltinMemoryBuffer(
553 new OpenCLBuiltinMemoryBuffer(opencl_base_builtins_header_data,
554 opencl_base_builtins_header_size - 1));
555
556 instance.getPreprocessorOpts().Includes.push_back("opencl-c-base.h");
557
alan-bakerfec0a472018-11-08 18:09:40 -0500558 // Add the VULKAN macro.
559 instance.getPreprocessorOpts().addMacroDef("VULKAN=100");
560
561 // Add the __OPENCL_VERSION__ macro.
562 instance.getPreprocessorOpts().addMacroDef("__OPENCL_VERSION__=120");
563
Kévin Petitaab5bb82021-03-30 16:26:11 +0100564 instance.setTarget(PrepareTargetInfo(instance));
alan-bakerfec0a472018-11-08 18:09:40 -0500565
566 instance.createFileManager();
567 instance.createSourceManager(instance.getFileManager());
568
569#ifdef _MSC_VER
570 std::string includePrefix("include\\");
571#else
572 std::string includePrefix("include/");
573#endif
574
575 auto entry = instance.getFileManager().getVirtualFile(
James Price40efe7f2021-01-18 09:19:31 -0500576 includePrefix + "opencl-c.h", openCLBuiltinMemoryBuffer->getBufferSize(),
alan-bakerfec0a472018-11-08 18:09:40 -0500577 0);
578
579 instance.getSourceManager().overrideFileContents(
580 entry, std::move(openCLBuiltinMemoryBuffer));
581
alan-bakerf3bce4a2019-06-28 16:01:15 -0400582 auto base_entry = instance.getFileManager().getVirtualFile(
583 includePrefix + "opencl-c-base.h",
584 openCLBaseBuiltinMemoryBuffer->getBufferSize(), 0);
585
586 instance.getSourceManager().overrideFileContents(
587 base_entry, std::move(openCLBaseBuiltinMemoryBuffer));
588
alan-bakerfec0a472018-11-08 18:09:40 -0500589 return 0;
590}
591
alan-baker57ce1c22022-04-26 19:10:44 -0400592int RunPassPipeline(llvm::Module &M, llvm::raw_svector_ostream *binaryStream) {
593 llvm::LoopAnalysisManager lam;
594 llvm::FunctionAnalysisManager fam;
595 llvm::CGSCCAnalysisManager cgam;
596 llvm::ModuleAnalysisManager mam;
597 llvm::PassInstrumentationCallbacks PIC;
598 clspv::RegisterClspvPasses(&PIC);
599 llvm::PassBuilder pb(nullptr, llvm::PipelineTuningOptions(), llvm::None,
600 &PIC);
601 pb.registerModuleAnalyses(mam);
602 pb.registerCGSCCAnalyses(cgam);
603 pb.registerFunctionAnalyses(fam);
604 pb.registerLoopAnalyses(lam);
605 pb.crossRegisterProxies(lam, fam, cgam, mam);
606
607 llvm::ModulePassManager pm;
608 llvm::FunctionPassManager fpm;
alan-bakerfec0a472018-11-08 18:09:40 -0500609
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
alan-baker57ce1c22022-04-26 19:10:44 -0400624 llvm::OptimizationLevel level;
alan-bakerf5e5f692018-11-27 08:33:24 -0500625 switch (OptimizationLevel) {
626 case '0':
alan-baker57ce1c22022-04-26 19:10:44 -0400627 level = llvm::OptimizationLevel::O0;
alan-bakerfec0a472018-11-08 18:09:40 -0500628 break;
629 case '1':
alan-baker57ce1c22022-04-26 19:10:44 -0400630 level = llvm::OptimizationLevel::O1;
alan-bakerfec0a472018-11-08 18:09:40 -0500631 break;
632 case '2':
alan-baker57ce1c22022-04-26 19:10:44 -0400633 level = llvm::OptimizationLevel::O2;
alan-bakerfec0a472018-11-08 18:09:40 -0500634 break;
635 case '3':
alan-baker57ce1c22022-04-26 19:10:44 -0400636 level = llvm::OptimizationLevel::O3;
alan-bakerfec0a472018-11-08 18:09:40 -0500637 break;
638 case 's':
alan-baker57ce1c22022-04-26 19:10:44 -0400639 level = llvm::OptimizationLevel::Os;
alan-bakerfec0a472018-11-08 18:09:40 -0500640 break;
641 case 'z':
alan-baker57ce1c22022-04-26 19:10:44 -0400642 level = llvm::OptimizationLevel::Oz;
alan-bakerfec0a472018-11-08 18:09:40 -0500643 break;
644 default:
645 break;
646 }
647
alan-baker57ce1c22022-04-26 19:10:44 -0400648 // Run the following optimizations prior to the standard LLVM pass pipeline.
649 pb.registerPipelineStartEPCallback([](llvm::ModulePassManager &pm,
650 llvm::OptimizationLevel level) {
651 pm.addPass(clspv::NativeMathPass());
652 pm.addPass(clspv::ZeroInitializeAllocasPass());
653 pm.addPass(clspv::AddFunctionAttributesPass());
654 pm.addPass(clspv::AutoPodArgsPass());
655 pm.addPass(clspv::DeclarePushConstantsPass());
656 pm.addPass(clspv::DefineOpenCLWorkItemBuiltinsPass());
alan-bakerfec0a472018-11-08 18:09:40 -0500657
alan-baker57ce1c22022-04-26 19:10:44 -0400658 if (level.getSpeedupLevel() > 0) {
659 pm.addPass(clspv::OpenCLInlinerPass());
660 }
alan-bakerfec0a472018-11-08 18:09:40 -0500661
alan-baker57ce1c22022-04-26 19:10:44 -0400662 pm.addPass(clspv::UndoByvalPass());
663 pm.addPass(clspv::UndoSRetPass());
664 pm.addPass(clspv::ClusterPodKernelArgumentsPass());
Romaric Jodin71fdb322022-05-03 17:01:10 +0200665 // ReplaceOpenCLBuiltinPass can generate vec8 and vec16 elements. It needs
666 // to be before the potential LongVectorLoweringPass pass.
alan-baker57ce1c22022-04-26 19:10:44 -0400667 pm.addPass(clspv::ReplaceOpenCLBuiltinPass());
668 pm.addPass(clspv::ThreeElementVectorLoweringPass());
alan-bakerfec0a472018-11-08 18:09:40 -0500669
alan-baker57ce1c22022-04-26 19:10:44 -0400670 // Lower longer vectors when requested. Note that this pass depends on
671 // ReplaceOpenCLBuiltinPass and expects DeadCodeEliminationPass to be run
672 // afterwards.
673 if (clspv::Option::LongVectorSupport()) {
674 pm.addPass(clspv::LongVectorLoweringPass());
675 }
Romaric Jodin322e9ba2021-12-08 16:00:06 +0100676
alan-baker57ce1c22022-04-26 19:10:44 -0400677 // We need to run mem2reg and inst combine early because our
678 // createInlineFuncWithPointerBitCastArgPass pass cannot handle the pattern
679 // %1 = alloca i32 1
680 // store <something> %1
681 // %2 = bitcast float* %1
682 // %3 = load float %2
683 pm.addPass(llvm::createModuleToFunctionPassAdaptor(llvm::PromotePass()));
Marco Antognini535998c2020-09-16 18:48:51 +0100684
alan-baker57ce1c22022-04-26 19:10:44 -0400685 // Try to deal with pointer bitcasts early. This can prevent problems like
686 // issue #409 where LLVM is looser about access chain addressing than
687 // SPIR-V. This needs to happen before instcombine and after replacing
688 // OpenCL builtins. This run of the pass will not handle all pointer
689 // bitcasts that could be handled. It should be run again after other
690 // optimizations (e.g InlineFuncWithPointerBitCastArgPass).
691 pm.addPass(clspv::SimplifyPointerBitcastPass());
692 pm.addPass(clspv::ReplacePointerBitcastPass());
693 pm.addPass(llvm::createModuleToFunctionPassAdaptor(llvm::DCEPass()));
alan-bakerfec0a472018-11-08 18:09:40 -0500694
alan-baker57ce1c22022-04-26 19:10:44 -0400695 // Hide loads from __constant address space away from instcombine.
696 // This prevents us from generating select between pointers-to-__constant.
697 // See https://github.com/google/clspv/issues/71
698 pm.addPass(clspv::HideConstantLoadsPass());
alan-baker1b13e8f2019-08-08 17:56:51 -0400699
alan-baker57ce1c22022-04-26 19:10:44 -0400700 pm.addPass(
701 llvm::createModuleToFunctionPassAdaptor(llvm::InstCombinePass()));
alan-bakerfec0a472018-11-08 18:09:40 -0500702
alan-baker57ce1c22022-04-26 19:10:44 -0400703 if (clspv::Option::InlineEntryPoints()) {
704 pm.addPass(clspv::InlineEntryPointsPass());
705 } else {
706 pm.addPass(clspv::InlineFuncWithPointerBitCastArgPass());
707 pm.addPass(clspv::InlineFuncWithPointerToFunctionArgPass());
708 pm.addPass(clspv::InlineFuncWithSingleCallSitePass());
709 }
alan-bakerfec0a472018-11-08 18:09:40 -0500710
alan-baker57ce1c22022-04-26 19:10:44 -0400711 // Mem2Reg pass should be run early because O0 level optimization leaves
712 // redundant alloca, load and store instructions from function arguments.
713 // clspv needs to remove them ahead of transformation.
714 pm.addPass(llvm::createModuleToFunctionPassAdaptor(llvm::PromotePass()));
715
716 // SROA pass is run because it will fold structs/unions that are problematic
717 // on Vulkan SPIR-V away.
718 pm.addPass(llvm::createModuleToFunctionPassAdaptor(llvm::SROAPass()));
719
720 // InstructionCombining pass folds bitcast and gep instructions which are
721 // not supported by Vulkan SPIR-V.
722 pm.addPass(
723 llvm::createModuleToFunctionPassAdaptor(llvm::InstCombinePass()));
724
725 if (clspv::Option::LanguageUsesGenericAddressSpace()) {
726 pm.addPass(llvm::createModuleToFunctionPassAdaptor(
727 llvm::InferAddressSpacesPass(clspv::AddressSpace::Generic)));
728 }
729 });
730
731 // Run the following passes after the default LLVM pass pipeline.
732 pb.registerOptimizerLastEPCallback([binaryStream](llvm::ModulePassManager &pm,
733 llvm::OptimizationLevel) {
734 // No point attempting to handle freeze currently so strip them from the IR.
735 pm.addPass(clspv::StripFreezePass());
736
737 // Unhide loads from __constant address space. Undoes the action of
738 // HideConstantLoadsPass.
739 pm.addPass(clspv::UnhideConstantLoadsPass());
740
741 pm.addPass(clspv::UndoInstCombinePass());
742 pm.addPass(clspv::FunctionInternalizerPass());
743 pm.addPass(clspv::ReplaceLLVMIntrinsicsPass());
744 // Replace LLVM intrinsics can leave dead code around.
745 pm.addPass(llvm::createModuleToFunctionPassAdaptor(llvm::DCEPass()));
746 pm.addPass(clspv::UndoBoolPass());
747 pm.addPass(clspv::UndoTruncateToOddIntegerPass());
748 // StructurizeCFG requires LowerSwitch to run first.
749 pm.addPass(
750 llvm::createModuleToFunctionPassAdaptor(llvm::LowerSwitchPass()));
751 pm.addPass(
752 llvm::createModuleToFunctionPassAdaptor(llvm::StructurizeCFGPass()));
753 // Must be run after structurize cfg.
754 pm.addPass(llvm::createModuleToFunctionPassAdaptor(
755 clspv::FixupStructuredCFGPass()));
756 // Must be run after structured cfg fixup.
757 pm.addPass(llvm::createModuleToFunctionPassAdaptor(
758 clspv::ReorderBasicBlocksPass()));
759 pm.addPass(clspv::UndoGetElementPtrConstantExprPass());
760 pm.addPass(clspv::SplatArgPass());
761 pm.addPass(clspv::SimplifyPointerBitcastPass());
762 pm.addPass(clspv::ReplacePointerBitcastPass());
763 pm.addPass(llvm::createModuleToFunctionPassAdaptor(llvm::DCEPass()));
764
765 pm.addPass(clspv::UndoTranslateSamplerFoldPass());
766
767 if (clspv::Option::ModuleConstantsInStorageBuffer()) {
768 pm.addPass(clspv::ClusterModuleScopeConstantVars());
769 }
770
771 pm.addPass(clspv::ShareModuleScopeVariablesPass());
772 // Specialize images before assigning descriptors to disambiguate the
773 // various types.
774 pm.addPass(clspv::SpecializeImageTypesPass());
775 // This should be run after LLVM and OpenCL intrinsics are replaced.
776 pm.addPass(clspv::AllocateDescriptorsPass());
777 pm.addPass(llvm::VerifierPass());
778 pm.addPass(clspv::DirectResourceAccessPass());
779 // Replacing pointer bitcasts can leave some trivial GEPs
780 // that are easy to remove. Also replace GEPs of GEPS
781 // left by replacing indirect buffer accesses.
782 pm.addPass(clspv::SimplifyPointerBitcastPass());
783 // Run after DRA to clean up parameters and help reduce the need for
784 // variable pointers.
785 pm.addPass(clspv::RemoveUnusedArguments());
786 pm.addPass(llvm::createModuleToFunctionPassAdaptor(llvm::DCEPass()));
787
788 // SPIR-V 1.4 and higher do not need to splat scalar conditions for vector
789 // data.
790 if (clspv::Option::SpvVersion() < clspv::Option::SPIRVVersion::SPIRV_1_4) {
791 pm.addPass(clspv::SplatSelectConditionPass());
792 }
793 pm.addPass(clspv::SignedCompareFixupPass());
794 // This pass generates insertions that need to be rewritten.
795 pm.addPass(clspv::ScalarizePass());
796 pm.addPass(clspv::RewriteInsertsPass());
797 // UBO Transformations
798 if (clspv::Option::ConstantArgsInUniformBuffer() &&
799 !clspv::Option::InlineEntryPoints()) {
800 // MultiVersionUBOFunctionsPass will examine non-kernel functions with UBO
801 // arguments and either multi-version them as necessary or inline them if
802 // multi-versioning cannot be accomplished.
803 pm.addPass(clspv::MultiVersionUBOFunctionsPass());
804 // Cleanup passes.
805 // Specialization can blindly generate GEP chains that are easily cleaned
806 // up by SimplifyPointerBitcastPass.
807 pm.addPass(clspv::SimplifyPointerBitcastPass());
808 // RemoveUnusedArgumentsPass removes the actual UBO arguments that were
809 // problematic to begin with now that they have no uses.
810 pm.addPass(clspv::RemoveUnusedArguments());
811 // DCE cleans up callers of the specialized functions.
812 pm.addPass(llvm::createModuleToFunctionPassAdaptor(llvm::DCEPass()));
813 }
814 // This pass mucks with types to point where you shouldn't rely on
815 // DataLayout anymore so leave this right before SPIR-V generation.
816 pm.addPass(clspv::UBOTypeTransformPass());
817 pm.addPass(clspv::SPIRVProducerPass(binaryStream, OutputFormat == "c"));
818 });
819
820 // Add the default optimizations for the requested optimization level.
821 if (level.getSpeedupLevel() > 0) {
822 auto mpm = pb.buildPerModuleDefaultPipeline(level);
823 mpm.run(M, mam);
alan-bakerfec0a472018-11-08 18:09:40 -0500824 } else {
alan-baker57ce1c22022-04-26 19:10:44 -0400825 auto mpm = pb.buildO0DefaultPipeline(level);
826 mpm.run(M, mam);
alan-bakerfec0a472018-11-08 18:09:40 -0500827 }
828
alan-bakerf5e5f692018-11-27 08:33:24 -0500829 return 0;
alan-bakerfec0a472018-11-08 18:09:40 -0500830}
alan-bakerfec0a472018-11-08 18:09:40 -0500831
Kévin Petitd5db2d22019-04-04 13:55:14 +0100832int ParseOptions(const int argc, const char *const argv[]) {
alan-baker227e9782020-06-02 15:35:37 -0400833 // We need to change how some of the called passes works by spoofing
834 // ParseCommandLineOptions with the specific options.
835 bool has_pre = false;
836 bool has_load_pre = false;
837 const std::string pre = "-enable-pre";
838 const std::string load_pre = "-enable-load-pre";
839 for (int i = 1; i < argc; ++i) {
840 std::string option(argv[i]);
841 auto pre_pos = option.find(pre);
842 auto load_pos = option.find(load_pre);
843 if (pre_pos == 0 || (pre_pos == 1 && option[0] == '-')) {
844 has_pre = true;
845 } else if (load_pos == 0 || (load_pos == 1 && option[0] == '-')) {
846 has_load_pre = true;
847 }
848 }
849
alan-baker1b333b62021-05-31 14:55:32 -0400850 int llvmArgc = 3;
851 const char *llvmArgv[5];
alan-baker227e9782020-06-02 15:35:37 -0400852 llvmArgv[0] = argv[0];
853 llvmArgv[1] = "-simplifycfg-sink-common=false";
alan-baker1b333b62021-05-31 14:55:32 -0400854 // TODO(#738): find a better solution to this.
855 llvmArgv[2] = "-disable-vector-combine";
alan-baker227e9782020-06-02 15:35:37 -0400856 if (!has_pre) {
857 llvmArgv[llvmArgc++] = "-enable-pre=0";
858 }
859 if (!has_load_pre) {
860 llvmArgv[llvmArgc++] = "-enable-load-pre=0";
861 }
alan-bakerfec0a472018-11-08 18:09:40 -0500862
Kévin Petitd5db2d22019-04-04 13:55:14 +0100863 llvm::cl::ResetAllOptionOccurrences();
alan-bakerfec0a472018-11-08 18:09:40 -0500864 llvm::cl::ParseCommandLineOptions(llvmArgc, llvmArgv);
alan-bakerfec0a472018-11-08 18:09:40 -0500865 llvm::cl::ParseCommandLineOptions(argc, argv);
866
Kévin Petitf0515712020-01-07 18:29:20 +0000867 if (clspv::Option::LanguageUsesGenericAddressSpace() &&
868 !clspv::Option::InlineEntryPoints()) {
869 llvm::errs() << "cannot compile languages that use the generic address "
870 "space (e.g. CLC++, CL2.0) without -inline-entry-points\n";
Kévin Petit0fc88042019-04-09 23:25:02 +0100871 return -1;
872 }
873
Kévin Petitbbbda972020-03-03 19:16:31 +0000874 if (clspv::Option::ScalarBlockLayout()) {
875 llvm::errs() << "scalar block layout support unimplemented\n";
876 return -1;
877 }
878
alan-baker9b0ec3c2020-04-06 14:45:34 -0400879 // Push constant option validation.
880 if (clspv::Option::PodArgsInPushConstants()) {
881 if (clspv::Option::PodArgsInUniformBuffer()) {
882 llvm::errs() << "POD arguments can only be in either uniform buffers or "
883 "push constants\n";
884 return -1;
885 }
886
887 if (!clspv::Option::ClusterPodKernelArgs()) {
888 llvm::errs()
889 << "POD arguments must be clustered to be passed as push constants\n";
890 return -1;
891 }
892
893 // Conservatively error if a module scope push constant could be used.
James Price708cf362020-05-06 19:33:45 -0400894 if (clspv::Option::GlobalOffsetPushConstant() ||
alan-baker9b0ec3c2020-04-06 14:45:34 -0400895 clspv::Option::Language() ==
896 clspv::Option::SourceLanguage::OpenCL_C_20 ||
897 clspv::Option::Language() ==
898 clspv::Option::SourceLanguage::OpenCL_CPP) {
899 llvm::errs() << "POD arguments as push constants are not compatible with "
900 "module scope push constants\n";
901 return -1;
902 }
903 }
904
Mehmet Oguz Derin047cc872021-04-15 19:56:41 +0300905 if (clspv::Option::ArmNonUniformWorkGroupSize() &&
906 clspv::Option::UniformWorkgroupSize()) {
907 llvm::errs() << "cannot enable Arm non-uniform workgroup extension support "
908 "and assume uniform workgroup sizes\n";
909 return -1;
910 }
911
Romaric Jodine40f67d2022-01-18 16:45:08 +0100912 if (clspv::Option::Vec3ToVec4() ==
913 clspv::Option::Vec3ToVec4SupportClass::vec3ToVec4SupportError) {
914 llvm::errs() << "error: -vec3-to-vec4 and -no-vec3-to-vec4 are exclusive "
915 "so they cannot be used together!\n";
916 return -1;
917 }
918
Kévin Petitd5db2d22019-04-04 13:55:14 +0100919 return 0;
920}
Diego Novillo89500852019-04-15 08:45:10 -0400921
alan-baker57ce1c22022-04-26 19:10:44 -0400922int GenerateIRFile(llvm::Module &module, std::string output) {
Diego Novillo89500852019-04-15 08:45:10 -0400923 std::error_code ec;
924 std::unique_ptr<llvm::ToolOutputFile> out(
Natalie Chouinard058da872021-06-17 12:32:47 -0400925 new llvm::ToolOutputFile(output, ec, llvm::sys::fs::OF_None));
Diego Novillo89500852019-04-15 08:45:10 -0400926 if (ec) {
927 llvm::errs() << output << ": " << ec.message() << '\n';
928 return -1;
929 }
alan-baker57ce1c22022-04-26 19:10:44 -0400930
931 llvm::ModuleAnalysisManager mam;
932 llvm::ModulePassManager pm;
933 llvm::PassBuilder pb;
934 pb.registerModuleAnalyses(mam);
935 pm.addPass(llvm::PrintModulePass(out->os(), "", false));
936 pm.run(module, mam);
Diego Novillo89500852019-04-15 08:45:10 -0400937 out->keep();
938 return 0;
939}
940
alan-baker869cd682021-03-05 11:21:19 -0500941bool LinkBuiltinLibrary(llvm::Module *module) {
942 std::unique_ptr<llvm::MemoryBuffer> buffer(new OpenCLBuiltinMemoryBuffer(
943 clspv_builtin_library_data, clspv_builtin_library_size - 1));
944
945 llvm::SMDiagnostic Err;
946 auto library = llvm::parseIR(*buffer, Err, module->getContext());
947 if (!library) {
948 llvm::errs() << "Failed to parse builtins library\n";
949 return false;
950 }
951
952 // TODO: when clang generates builtins using the generic address space,
953 // different builtins are used for pointer-based builtins. Need to do some
954 // work to ensure they are kept around.
955 // Affects: modf, remquo, lgamma_r, frexp
956
957 llvm::Linker L(*module);
958 L.linkInModule(std::move(library), 0);
959
960 return true;
961}
962
Kévin Petitd5db2d22019-04-04 13:55:14 +0100963} // namespace
964
965namespace clspv {
Ryan Senanayake6917fb12022-02-28 18:17:02 -0500966int Compile(const llvm::StringRef &input_filename, const std::string &program,
967 const std::string &sampler_map,
968 std::vector<uint32_t> *output_binary, std::string *output_log) {
alan-bakerfec0a472018-11-08 18:09:40 -0500969 llvm::SmallVector<std::pair<unsigned, std::string>, 8> SamplerMapEntries;
Ryan Senanayake6917fb12022-02-28 18:17:02 -0500970 if (auto error = ParseSamplerMap(sampler_map, &SamplerMapEntries))
alan-bakerfec0a472018-11-08 18:09:40 -0500971 return error;
972
Ryan Senanayake6917fb12022-02-28 18:17:02 -0500973 llvm::StringRef overiddenInputFilename = input_filename;
alan-bakerfec0a472018-11-08 18:09:40 -0500974
975 clang::CompilerInstance instance;
Kévin Petitddad8f42019-09-30 15:12:08 +0100976 clang::FrontendInputFile kernelFile(overiddenInputFilename,
977 clang::InputKind(InputLanguage));
alan-bakerfec0a472018-11-08 18:09:40 -0500978 std::string log;
979 llvm::raw_string_ostream diagnosticsStream(log);
Ryan Senanayake6917fb12022-02-28 18:17:02 -0500980 std::unique_ptr<llvm::MemoryBuffer> file_memory_buffer;
alan-bakerf5e5f692018-11-27 08:33:24 -0500981 if (auto error = SetCompilerInstanceOptions(
Ryan Senanayake6917fb12022-02-28 18:17:02 -0500982 instance, overiddenInputFilename, kernelFile, program,
983 file_memory_buffer, &diagnosticsStream))
alan-bakerfec0a472018-11-08 18:09:40 -0500984 return error;
985
986 // Parse.
987 llvm::LLVMContext context;
988 clang::EmitLLVMOnlyAction action(&context);
989
990 // Prepare the action for processing kernelFile
991 const bool success = action.BeginSourceFile(instance, kernelFile);
992 if (!success) {
993 return -1;
994 }
995
alan-bakerf3bce4a2019-06-28 16:01:15 -0400996 auto result = action.Execute();
alan-bakerfec0a472018-11-08 18:09:40 -0500997 action.EndSourceFile();
998
999 clang::DiagnosticConsumer *const consumer =
1000 instance.getDiagnostics().getClient();
1001 consumer->finish();
1002
Kévin Petit6b07cbe2019-04-02 21:52:16 +01001003 auto num_warnings = consumer->getNumWarnings();
alan-bakerfec0a472018-11-08 18:09:40 -05001004 auto num_errors = consumer->getNumErrors();
Ryan Senanayake6917fb12022-02-28 18:17:02 -05001005 if (output_log != nullptr) {
1006 *output_log = log;
1007 } else if ((num_errors > 0) || (num_warnings > 0)) {
Kévin Petit6b07cbe2019-04-02 21:52:16 +01001008 llvm::errs() << log;
1009 }
alan-bakerf3bce4a2019-06-28 16:01:15 -04001010 if (result || num_errors > 0) {
alan-bakerfec0a472018-11-08 18:09:40 -05001011 return -1;
1012 }
1013
Kévin Petit6b07cbe2019-04-02 21:52:16 +01001014 // Don't run the passes or produce any output in verify mode.
1015 // Clang doesn't always produce a valid module.
1016 if (verify) {
1017 return 0;
1018 }
1019
alan-bakerfec0a472018-11-08 18:09:40 -05001020 std::unique_ptr<llvm::Module> module(action.takeModule());
1021
1022 // Optimize.
1023 // Create a memory buffer for temporarily writing the result.
1024 SmallVector<char, 10000> binary;
1025 llvm::raw_svector_ostream binaryStream(binary);
Diego Novillo89500852019-04-15 08:45:10 -04001026
1027 // If --emit-ir was requested, emit the initial LLVM IR and stop compilation.
1028 if (!IROutputFile.empty()) {
alan-baker57ce1c22022-04-26 19:10:44 -04001029 return GenerateIRFile(*module, IROutputFile);
Diego Novillo89500852019-04-15 08:45:10 -04001030 }
1031
alan-baker869cd682021-03-05 11:21:19 -05001032 if (!LinkBuiltinLibrary(module.get())) {
1033 return -1;
1034 }
1035
alan-baker57ce1c22022-04-26 19:10:44 -04001036 // Run the passes to produce SPIR-V.
1037 if (RunPassPipeline(*module, &binaryStream) != 0) {
1038 return -1;
1039 }
alan-bakerfec0a472018-11-08 18:09:40 -05001040
alan-bakerfec0a472018-11-08 18:09:40 -05001041 // Write the resulting binary.
1042 // Wait until now to try writing the file so that we only write it on
1043 // successful compilation.
Ryan Senanayake6917fb12022-02-28 18:17:02 -05001044 if (output_binary) {
1045 output_binary->resize(binary.size() / 4);
1046 memcpy(output_binary->data(), binary.data(), binary.size());
1047 }
1048
1049 if (!OutputFilename.empty()) {
1050 std::error_code error;
1051 llvm::raw_fd_ostream outStream(OutputFilename, error,
1052 llvm::sys::fs::FA_Write);
1053
1054 if (error) {
1055 llvm::errs() << "Unable to open output file '" << OutputFilename
1056 << "': " << error.message() << '\n';
1057 return -1;
1058 }
1059 outStream << binaryStream.str();
1060 }
1061
1062 return 0;
1063}
1064
1065int Compile(const int argc, const char *const argv[]) {
1066 if (auto error = ParseOptions(argc, argv))
1067 return error;
1068
1069 // if no input file was provided, use a default
1070 llvm::StringRef overiddenInputFilename = InputFilename.getValue();
1071
1072 // If we are reading our input file from stdin.
1073 if ("-" == InputFilename) {
1074 // We need to overwrite the file name we use.
1075 switch (InputLanguage) {
1076 case clang::Language::OpenCL:
1077 overiddenInputFilename = "stdin.cl";
1078 break;
1079 case clang::Language::LLVM_IR:
1080 overiddenInputFilename = "stdin.ll";
1081 break;
1082 default:
1083 // Default to fix compiler warnings/errors. Option parsing will reject a
1084 // bad enum value for the option so there is no need for a message.
1085 return -1;
1086 }
1087 }
1088
alan-bakerfec0a472018-11-08 18:09:40 -05001089 if (OutputFilename.empty()) {
Kévin Petite4786902019-04-02 21:51:47 +01001090 if (OutputFormat == "c") {
alan-bakerfec0a472018-11-08 18:09:40 -05001091 OutputFilename = "a.spvinc";
1092 } else {
1093 OutputFilename = "a.spv";
1094 }
1095 }
alan-bakerfec0a472018-11-08 18:09:40 -05001096
Ryan Senanayake6917fb12022-02-28 18:17:02 -05001097 return Compile(overiddenInputFilename, "", "", nullptr, nullptr);
alan-bakerfec0a472018-11-08 18:09:40 -05001098}
alan-bakerf5e5f692018-11-27 08:33:24 -05001099
alan-baker86ce19c2020-08-05 13:09:19 -04001100int CompileFromSourceString(const std::string &program,
1101 const std::string &sampler_map,
1102 const std::string &options,
Kévin Petit899162d2020-09-08 19:16:08 +01001103 std::vector<uint32_t> *output_binary,
1104 std::string *output_log) {
alan-bakerf5e5f692018-11-27 08:33:24 -05001105
1106 llvm::SmallVector<const char *, 20> argv;
1107 llvm::BumpPtrAllocator A;
1108 llvm::StringSaver Saver(A);
1109 argv.push_back(Saver.save("clspv").data());
1110 llvm::cl::TokenizeGNUCommandLine(options, Saver, argv);
1111 int argc = static_cast<int>(argv.size());
Kévin Petitd5db2d22019-04-04 13:55:14 +01001112
1113 if (auto error = ParseOptions(argc, &argv[0]))
1114 return error;
alan-bakerf5e5f692018-11-27 08:33:24 -05001115
Ryan Senanayake6917fb12022-02-28 18:17:02 -05001116 return Compile("source", program, sampler_map, output_binary, output_log);
alan-bakerf5e5f692018-11-27 08:33:24 -05001117}
alan-bakerfec0a472018-11-08 18:09:40 -05001118} // namespace clspv