blob: ff3a607e236b4315f329974a5e2d316559593fc4 [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());
665 pm.addPass(clspv::ReplaceOpenCLBuiltinPass());
666 pm.addPass(clspv::ThreeElementVectorLoweringPass());
alan-bakerfec0a472018-11-08 18:09:40 -0500667
alan-baker57ce1c22022-04-26 19:10:44 -0400668 // Lower longer vectors when requested. Note that this pass depends on
669 // ReplaceOpenCLBuiltinPass and expects DeadCodeEliminationPass to be run
670 // afterwards.
671 if (clspv::Option::LongVectorSupport()) {
672 pm.addPass(clspv::LongVectorLoweringPass());
673 }
Romaric Jodin322e9ba2021-12-08 16:00:06 +0100674
alan-baker57ce1c22022-04-26 19:10:44 -0400675 // We need to run mem2reg and inst combine early because our
676 // createInlineFuncWithPointerBitCastArgPass pass cannot handle the pattern
677 // %1 = alloca i32 1
678 // store <something> %1
679 // %2 = bitcast float* %1
680 // %3 = load float %2
681 pm.addPass(llvm::createModuleToFunctionPassAdaptor(llvm::PromotePass()));
Marco Antognini535998c2020-09-16 18:48:51 +0100682
alan-baker57ce1c22022-04-26 19:10:44 -0400683 // Try to deal with pointer bitcasts early. This can prevent problems like
684 // issue #409 where LLVM is looser about access chain addressing than
685 // SPIR-V. This needs to happen before instcombine and after replacing
686 // OpenCL builtins. This run of the pass will not handle all pointer
687 // bitcasts that could be handled. It should be run again after other
688 // optimizations (e.g InlineFuncWithPointerBitCastArgPass).
689 pm.addPass(clspv::SimplifyPointerBitcastPass());
690 pm.addPass(clspv::ReplacePointerBitcastPass());
691 pm.addPass(llvm::createModuleToFunctionPassAdaptor(llvm::DCEPass()));
alan-bakerfec0a472018-11-08 18:09:40 -0500692
alan-baker57ce1c22022-04-26 19:10:44 -0400693 // Hide loads from __constant address space away from instcombine.
694 // This prevents us from generating select between pointers-to-__constant.
695 // See https://github.com/google/clspv/issues/71
696 pm.addPass(clspv::HideConstantLoadsPass());
alan-baker1b13e8f2019-08-08 17:56:51 -0400697
alan-baker57ce1c22022-04-26 19:10:44 -0400698 pm.addPass(
699 llvm::createModuleToFunctionPassAdaptor(llvm::InstCombinePass()));
alan-bakerfec0a472018-11-08 18:09:40 -0500700
alan-baker57ce1c22022-04-26 19:10:44 -0400701 if (clspv::Option::InlineEntryPoints()) {
702 pm.addPass(clspv::InlineEntryPointsPass());
703 } else {
704 pm.addPass(clspv::InlineFuncWithPointerBitCastArgPass());
705 pm.addPass(clspv::InlineFuncWithPointerToFunctionArgPass());
706 pm.addPass(clspv::InlineFuncWithSingleCallSitePass());
707 }
alan-bakerfec0a472018-11-08 18:09:40 -0500708
alan-baker57ce1c22022-04-26 19:10:44 -0400709 // Mem2Reg pass should be run early because O0 level optimization leaves
710 // redundant alloca, load and store instructions from function arguments.
711 // clspv needs to remove them ahead of transformation.
712 pm.addPass(llvm::createModuleToFunctionPassAdaptor(llvm::PromotePass()));
713
714 // SROA pass is run because it will fold structs/unions that are problematic
715 // on Vulkan SPIR-V away.
716 pm.addPass(llvm::createModuleToFunctionPassAdaptor(llvm::SROAPass()));
717
718 // InstructionCombining pass folds bitcast and gep instructions which are
719 // not supported by Vulkan SPIR-V.
720 pm.addPass(
721 llvm::createModuleToFunctionPassAdaptor(llvm::InstCombinePass()));
722
723 if (clspv::Option::LanguageUsesGenericAddressSpace()) {
724 pm.addPass(llvm::createModuleToFunctionPassAdaptor(
725 llvm::InferAddressSpacesPass(clspv::AddressSpace::Generic)));
726 }
727 });
728
729 // Run the following passes after the default LLVM pass pipeline.
730 pb.registerOptimizerLastEPCallback([binaryStream](llvm::ModulePassManager &pm,
731 llvm::OptimizationLevel) {
732 // No point attempting to handle freeze currently so strip them from the IR.
733 pm.addPass(clspv::StripFreezePass());
734
735 // Unhide loads from __constant address space. Undoes the action of
736 // HideConstantLoadsPass.
737 pm.addPass(clspv::UnhideConstantLoadsPass());
738
739 pm.addPass(clspv::UndoInstCombinePass());
740 pm.addPass(clspv::FunctionInternalizerPass());
741 pm.addPass(clspv::ReplaceLLVMIntrinsicsPass());
742 // Replace LLVM intrinsics can leave dead code around.
743 pm.addPass(llvm::createModuleToFunctionPassAdaptor(llvm::DCEPass()));
744 pm.addPass(clspv::UndoBoolPass());
745 pm.addPass(clspv::UndoTruncateToOddIntegerPass());
746 // StructurizeCFG requires LowerSwitch to run first.
747 pm.addPass(
748 llvm::createModuleToFunctionPassAdaptor(llvm::LowerSwitchPass()));
749 pm.addPass(
750 llvm::createModuleToFunctionPassAdaptor(llvm::StructurizeCFGPass()));
751 // Must be run after structurize cfg.
752 pm.addPass(llvm::createModuleToFunctionPassAdaptor(
753 clspv::FixupStructuredCFGPass()));
754 // Must be run after structured cfg fixup.
755 pm.addPass(llvm::createModuleToFunctionPassAdaptor(
756 clspv::ReorderBasicBlocksPass()));
757 pm.addPass(clspv::UndoGetElementPtrConstantExprPass());
758 pm.addPass(clspv::SplatArgPass());
759 pm.addPass(clspv::SimplifyPointerBitcastPass());
760 pm.addPass(clspv::ReplacePointerBitcastPass());
761 pm.addPass(llvm::createModuleToFunctionPassAdaptor(llvm::DCEPass()));
762
763 pm.addPass(clspv::UndoTranslateSamplerFoldPass());
764
765 if (clspv::Option::ModuleConstantsInStorageBuffer()) {
766 pm.addPass(clspv::ClusterModuleScopeConstantVars());
767 }
768
769 pm.addPass(clspv::ShareModuleScopeVariablesPass());
770 // Specialize images before assigning descriptors to disambiguate the
771 // various types.
772 pm.addPass(clspv::SpecializeImageTypesPass());
773 // This should be run after LLVM and OpenCL intrinsics are replaced.
774 pm.addPass(clspv::AllocateDescriptorsPass());
775 pm.addPass(llvm::VerifierPass());
776 pm.addPass(clspv::DirectResourceAccessPass());
777 // Replacing pointer bitcasts can leave some trivial GEPs
778 // that are easy to remove. Also replace GEPs of GEPS
779 // left by replacing indirect buffer accesses.
780 pm.addPass(clspv::SimplifyPointerBitcastPass());
781 // Run after DRA to clean up parameters and help reduce the need for
782 // variable pointers.
783 pm.addPass(clspv::RemoveUnusedArguments());
784 pm.addPass(llvm::createModuleToFunctionPassAdaptor(llvm::DCEPass()));
785
786 // SPIR-V 1.4 and higher do not need to splat scalar conditions for vector
787 // data.
788 if (clspv::Option::SpvVersion() < clspv::Option::SPIRVVersion::SPIRV_1_4) {
789 pm.addPass(clspv::SplatSelectConditionPass());
790 }
791 pm.addPass(clspv::SignedCompareFixupPass());
792 // This pass generates insertions that need to be rewritten.
793 pm.addPass(clspv::ScalarizePass());
794 pm.addPass(clspv::RewriteInsertsPass());
795 // UBO Transformations
796 if (clspv::Option::ConstantArgsInUniformBuffer() &&
797 !clspv::Option::InlineEntryPoints()) {
798 // MultiVersionUBOFunctionsPass will examine non-kernel functions with UBO
799 // arguments and either multi-version them as necessary or inline them if
800 // multi-versioning cannot be accomplished.
801 pm.addPass(clspv::MultiVersionUBOFunctionsPass());
802 // Cleanup passes.
803 // Specialization can blindly generate GEP chains that are easily cleaned
804 // up by SimplifyPointerBitcastPass.
805 pm.addPass(clspv::SimplifyPointerBitcastPass());
806 // RemoveUnusedArgumentsPass removes the actual UBO arguments that were
807 // problematic to begin with now that they have no uses.
808 pm.addPass(clspv::RemoveUnusedArguments());
809 // DCE cleans up callers of the specialized functions.
810 pm.addPass(llvm::createModuleToFunctionPassAdaptor(llvm::DCEPass()));
811 }
812 // This pass mucks with types to point where you shouldn't rely on
813 // DataLayout anymore so leave this right before SPIR-V generation.
814 pm.addPass(clspv::UBOTypeTransformPass());
815 pm.addPass(clspv::SPIRVProducerPass(binaryStream, OutputFormat == "c"));
816 });
817
818 // Add the default optimizations for the requested optimization level.
819 if (level.getSpeedupLevel() > 0) {
820 auto mpm = pb.buildPerModuleDefaultPipeline(level);
821 mpm.run(M, mam);
alan-bakerfec0a472018-11-08 18:09:40 -0500822 } else {
alan-baker57ce1c22022-04-26 19:10:44 -0400823 auto mpm = pb.buildO0DefaultPipeline(level);
824 mpm.run(M, mam);
alan-bakerfec0a472018-11-08 18:09:40 -0500825 }
826
alan-bakerf5e5f692018-11-27 08:33:24 -0500827 return 0;
alan-bakerfec0a472018-11-08 18:09:40 -0500828}
alan-bakerfec0a472018-11-08 18:09:40 -0500829
Kévin Petitd5db2d22019-04-04 13:55:14 +0100830int ParseOptions(const int argc, const char *const argv[]) {
alan-baker227e9782020-06-02 15:35:37 -0400831 // We need to change how some of the called passes works by spoofing
832 // ParseCommandLineOptions with the specific options.
833 bool has_pre = false;
834 bool has_load_pre = false;
835 const std::string pre = "-enable-pre";
836 const std::string load_pre = "-enable-load-pre";
837 for (int i = 1; i < argc; ++i) {
838 std::string option(argv[i]);
839 auto pre_pos = option.find(pre);
840 auto load_pos = option.find(load_pre);
841 if (pre_pos == 0 || (pre_pos == 1 && option[0] == '-')) {
842 has_pre = true;
843 } else if (load_pos == 0 || (load_pos == 1 && option[0] == '-')) {
844 has_load_pre = true;
845 }
846 }
847
alan-baker1b333b62021-05-31 14:55:32 -0400848 int llvmArgc = 3;
849 const char *llvmArgv[5];
alan-baker227e9782020-06-02 15:35:37 -0400850 llvmArgv[0] = argv[0];
851 llvmArgv[1] = "-simplifycfg-sink-common=false";
alan-baker1b333b62021-05-31 14:55:32 -0400852 // TODO(#738): find a better solution to this.
853 llvmArgv[2] = "-disable-vector-combine";
alan-baker227e9782020-06-02 15:35:37 -0400854 if (!has_pre) {
855 llvmArgv[llvmArgc++] = "-enable-pre=0";
856 }
857 if (!has_load_pre) {
858 llvmArgv[llvmArgc++] = "-enable-load-pre=0";
859 }
alan-bakerfec0a472018-11-08 18:09:40 -0500860
Kévin Petitd5db2d22019-04-04 13:55:14 +0100861 llvm::cl::ResetAllOptionOccurrences();
alan-bakerfec0a472018-11-08 18:09:40 -0500862 llvm::cl::ParseCommandLineOptions(llvmArgc, llvmArgv);
alan-bakerfec0a472018-11-08 18:09:40 -0500863 llvm::cl::ParseCommandLineOptions(argc, argv);
864
Kévin Petitf0515712020-01-07 18:29:20 +0000865 if (clspv::Option::LanguageUsesGenericAddressSpace() &&
866 !clspv::Option::InlineEntryPoints()) {
867 llvm::errs() << "cannot compile languages that use the generic address "
868 "space (e.g. CLC++, CL2.0) without -inline-entry-points\n";
Kévin Petit0fc88042019-04-09 23:25:02 +0100869 return -1;
870 }
871
Kévin Petitbbbda972020-03-03 19:16:31 +0000872 if (clspv::Option::ScalarBlockLayout()) {
873 llvm::errs() << "scalar block layout support unimplemented\n";
874 return -1;
875 }
876
alan-baker9b0ec3c2020-04-06 14:45:34 -0400877 // Push constant option validation.
878 if (clspv::Option::PodArgsInPushConstants()) {
879 if (clspv::Option::PodArgsInUniformBuffer()) {
880 llvm::errs() << "POD arguments can only be in either uniform buffers or "
881 "push constants\n";
882 return -1;
883 }
884
885 if (!clspv::Option::ClusterPodKernelArgs()) {
886 llvm::errs()
887 << "POD arguments must be clustered to be passed as push constants\n";
888 return -1;
889 }
890
891 // Conservatively error if a module scope push constant could be used.
James Price708cf362020-05-06 19:33:45 -0400892 if (clspv::Option::GlobalOffsetPushConstant() ||
alan-baker9b0ec3c2020-04-06 14:45:34 -0400893 clspv::Option::Language() ==
894 clspv::Option::SourceLanguage::OpenCL_C_20 ||
895 clspv::Option::Language() ==
896 clspv::Option::SourceLanguage::OpenCL_CPP) {
897 llvm::errs() << "POD arguments as push constants are not compatible with "
898 "module scope push constants\n";
899 return -1;
900 }
901 }
902
Mehmet Oguz Derin047cc872021-04-15 19:56:41 +0300903 if (clspv::Option::ArmNonUniformWorkGroupSize() &&
904 clspv::Option::UniformWorkgroupSize()) {
905 llvm::errs() << "cannot enable Arm non-uniform workgroup extension support "
906 "and assume uniform workgroup sizes\n";
907 return -1;
908 }
909
Romaric Jodine40f67d2022-01-18 16:45:08 +0100910 if (clspv::Option::Vec3ToVec4() ==
911 clspv::Option::Vec3ToVec4SupportClass::vec3ToVec4SupportError) {
912 llvm::errs() << "error: -vec3-to-vec4 and -no-vec3-to-vec4 are exclusive "
913 "so they cannot be used together!\n";
914 return -1;
915 }
916
Kévin Petitd5db2d22019-04-04 13:55:14 +0100917 return 0;
918}
Diego Novillo89500852019-04-15 08:45:10 -0400919
alan-baker57ce1c22022-04-26 19:10:44 -0400920int GenerateIRFile(llvm::Module &module, std::string output) {
Diego Novillo89500852019-04-15 08:45:10 -0400921 std::error_code ec;
922 std::unique_ptr<llvm::ToolOutputFile> out(
Natalie Chouinard058da872021-06-17 12:32:47 -0400923 new llvm::ToolOutputFile(output, ec, llvm::sys::fs::OF_None));
Diego Novillo89500852019-04-15 08:45:10 -0400924 if (ec) {
925 llvm::errs() << output << ": " << ec.message() << '\n';
926 return -1;
927 }
alan-baker57ce1c22022-04-26 19:10:44 -0400928
929 llvm::ModuleAnalysisManager mam;
930 llvm::ModulePassManager pm;
931 llvm::PassBuilder pb;
932 pb.registerModuleAnalyses(mam);
933 pm.addPass(llvm::PrintModulePass(out->os(), "", false));
934 pm.run(module, mam);
Diego Novillo89500852019-04-15 08:45:10 -0400935 out->keep();
936 return 0;
937}
938
alan-baker869cd682021-03-05 11:21:19 -0500939bool LinkBuiltinLibrary(llvm::Module *module) {
940 std::unique_ptr<llvm::MemoryBuffer> buffer(new OpenCLBuiltinMemoryBuffer(
941 clspv_builtin_library_data, clspv_builtin_library_size - 1));
942
943 llvm::SMDiagnostic Err;
944 auto library = llvm::parseIR(*buffer, Err, module->getContext());
945 if (!library) {
946 llvm::errs() << "Failed to parse builtins library\n";
947 return false;
948 }
949
950 // TODO: when clang generates builtins using the generic address space,
951 // different builtins are used for pointer-based builtins. Need to do some
952 // work to ensure they are kept around.
953 // Affects: modf, remquo, lgamma_r, frexp
954
955 llvm::Linker L(*module);
956 L.linkInModule(std::move(library), 0);
957
958 return true;
959}
960
Kévin Petitd5db2d22019-04-04 13:55:14 +0100961} // namespace
962
963namespace clspv {
Ryan Senanayake6917fb12022-02-28 18:17:02 -0500964int Compile(const llvm::StringRef &input_filename, const std::string &program,
965 const std::string &sampler_map,
966 std::vector<uint32_t> *output_binary, std::string *output_log) {
alan-bakerfec0a472018-11-08 18:09:40 -0500967 llvm::SmallVector<std::pair<unsigned, std::string>, 8> SamplerMapEntries;
Ryan Senanayake6917fb12022-02-28 18:17:02 -0500968 if (auto error = ParseSamplerMap(sampler_map, &SamplerMapEntries))
alan-bakerfec0a472018-11-08 18:09:40 -0500969 return error;
970
Ryan Senanayake6917fb12022-02-28 18:17:02 -0500971 llvm::StringRef overiddenInputFilename = input_filename;
alan-bakerfec0a472018-11-08 18:09:40 -0500972
973 clang::CompilerInstance instance;
Kévin Petitddad8f42019-09-30 15:12:08 +0100974 clang::FrontendInputFile kernelFile(overiddenInputFilename,
975 clang::InputKind(InputLanguage));
alan-bakerfec0a472018-11-08 18:09:40 -0500976 std::string log;
977 llvm::raw_string_ostream diagnosticsStream(log);
Ryan Senanayake6917fb12022-02-28 18:17:02 -0500978 std::unique_ptr<llvm::MemoryBuffer> file_memory_buffer;
alan-bakerf5e5f692018-11-27 08:33:24 -0500979 if (auto error = SetCompilerInstanceOptions(
Ryan Senanayake6917fb12022-02-28 18:17:02 -0500980 instance, overiddenInputFilename, kernelFile, program,
981 file_memory_buffer, &diagnosticsStream))
alan-bakerfec0a472018-11-08 18:09:40 -0500982 return error;
983
984 // Parse.
985 llvm::LLVMContext context;
986 clang::EmitLLVMOnlyAction action(&context);
987
988 // Prepare the action for processing kernelFile
989 const bool success = action.BeginSourceFile(instance, kernelFile);
990 if (!success) {
991 return -1;
992 }
993
alan-bakerf3bce4a2019-06-28 16:01:15 -0400994 auto result = action.Execute();
alan-bakerfec0a472018-11-08 18:09:40 -0500995 action.EndSourceFile();
996
997 clang::DiagnosticConsumer *const consumer =
998 instance.getDiagnostics().getClient();
999 consumer->finish();
1000
Kévin Petit6b07cbe2019-04-02 21:52:16 +01001001 auto num_warnings = consumer->getNumWarnings();
alan-bakerfec0a472018-11-08 18:09:40 -05001002 auto num_errors = consumer->getNumErrors();
Ryan Senanayake6917fb12022-02-28 18:17:02 -05001003 if (output_log != nullptr) {
1004 *output_log = log;
1005 } else if ((num_errors > 0) || (num_warnings > 0)) {
Kévin Petit6b07cbe2019-04-02 21:52:16 +01001006 llvm::errs() << log;
1007 }
alan-bakerf3bce4a2019-06-28 16:01:15 -04001008 if (result || num_errors > 0) {
alan-bakerfec0a472018-11-08 18:09:40 -05001009 return -1;
1010 }
1011
Kévin Petit6b07cbe2019-04-02 21:52:16 +01001012 // Don't run the passes or produce any output in verify mode.
1013 // Clang doesn't always produce a valid module.
1014 if (verify) {
1015 return 0;
1016 }
1017
alan-bakerfec0a472018-11-08 18:09:40 -05001018 std::unique_ptr<llvm::Module> module(action.takeModule());
1019
1020 // Optimize.
1021 // Create a memory buffer for temporarily writing the result.
1022 SmallVector<char, 10000> binary;
1023 llvm::raw_svector_ostream binaryStream(binary);
Diego Novillo89500852019-04-15 08:45:10 -04001024
1025 // If --emit-ir was requested, emit the initial LLVM IR and stop compilation.
1026 if (!IROutputFile.empty()) {
alan-baker57ce1c22022-04-26 19:10:44 -04001027 return GenerateIRFile(*module, IROutputFile);
Diego Novillo89500852019-04-15 08:45:10 -04001028 }
1029
alan-baker869cd682021-03-05 11:21:19 -05001030 if (!LinkBuiltinLibrary(module.get())) {
1031 return -1;
1032 }
1033
alan-baker57ce1c22022-04-26 19:10:44 -04001034 // Run the passes to produce SPIR-V.
1035 if (RunPassPipeline(*module, &binaryStream) != 0) {
1036 return -1;
1037 }
alan-bakerfec0a472018-11-08 18:09:40 -05001038
alan-bakerfec0a472018-11-08 18:09:40 -05001039 // Write the resulting binary.
1040 // Wait until now to try writing the file so that we only write it on
1041 // successful compilation.
Ryan Senanayake6917fb12022-02-28 18:17:02 -05001042 if (output_binary) {
1043 output_binary->resize(binary.size() / 4);
1044 memcpy(output_binary->data(), binary.data(), binary.size());
1045 }
1046
1047 if (!OutputFilename.empty()) {
1048 std::error_code error;
1049 llvm::raw_fd_ostream outStream(OutputFilename, error,
1050 llvm::sys::fs::FA_Write);
1051
1052 if (error) {
1053 llvm::errs() << "Unable to open output file '" << OutputFilename
1054 << "': " << error.message() << '\n';
1055 return -1;
1056 }
1057 outStream << binaryStream.str();
1058 }
1059
1060 return 0;
1061}
1062
1063int Compile(const int argc, const char *const argv[]) {
1064 if (auto error = ParseOptions(argc, argv))
1065 return error;
1066
1067 // if no input file was provided, use a default
1068 llvm::StringRef overiddenInputFilename = InputFilename.getValue();
1069
1070 // If we are reading our input file from stdin.
1071 if ("-" == InputFilename) {
1072 // We need to overwrite the file name we use.
1073 switch (InputLanguage) {
1074 case clang::Language::OpenCL:
1075 overiddenInputFilename = "stdin.cl";
1076 break;
1077 case clang::Language::LLVM_IR:
1078 overiddenInputFilename = "stdin.ll";
1079 break;
1080 default:
1081 // Default to fix compiler warnings/errors. Option parsing will reject a
1082 // bad enum value for the option so there is no need for a message.
1083 return -1;
1084 }
1085 }
1086
alan-bakerfec0a472018-11-08 18:09:40 -05001087 if (OutputFilename.empty()) {
Kévin Petite4786902019-04-02 21:51:47 +01001088 if (OutputFormat == "c") {
alan-bakerfec0a472018-11-08 18:09:40 -05001089 OutputFilename = "a.spvinc";
1090 } else {
1091 OutputFilename = "a.spv";
1092 }
1093 }
alan-bakerfec0a472018-11-08 18:09:40 -05001094
Ryan Senanayake6917fb12022-02-28 18:17:02 -05001095 return Compile(overiddenInputFilename, "", "", nullptr, nullptr);
alan-bakerfec0a472018-11-08 18:09:40 -05001096}
alan-bakerf5e5f692018-11-27 08:33:24 -05001097
alan-baker86ce19c2020-08-05 13:09:19 -04001098int CompileFromSourceString(const std::string &program,
1099 const std::string &sampler_map,
1100 const std::string &options,
Kévin Petit899162d2020-09-08 19:16:08 +01001101 std::vector<uint32_t> *output_binary,
1102 std::string *output_log) {
alan-bakerf5e5f692018-11-27 08:33:24 -05001103
1104 llvm::SmallVector<const char *, 20> argv;
1105 llvm::BumpPtrAllocator A;
1106 llvm::StringSaver Saver(A);
1107 argv.push_back(Saver.save("clspv").data());
1108 llvm::cl::TokenizeGNUCommandLine(options, Saver, argv);
1109 int argc = static_cast<int>(argv.size());
Kévin Petitd5db2d22019-04-04 13:55:14 +01001110
1111 if (auto error = ParseOptions(argc, &argv[0]))
1112 return error;
alan-bakerf5e5f692018-11-27 08:33:24 -05001113
Ryan Senanayake6917fb12022-02-28 18:17:02 -05001114 return Compile("source", program, sampler_map, output_binary, output_log);
alan-bakerf5e5f692018-11-27 08:33:24 -05001115}
alan-bakerfec0a472018-11-08 18:09:40 -05001116} // namespace clspv