blob: 6229e9f44e114c88962cd71a03385c7be2cd9f4d [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-baker2ceb6592022-06-07 09:41:35 -0400160static llvm::cl::opt<bool> OpaquePointers("enable-opaque-pointers",
161 llvm::cl::desc("Use opaque pointers"),
162 llvm::cl::init(false));
163
alan-baker869cd682021-03-05 11:21:19 -0500164namespace {
165struct OpenCLBuiltinMemoryBuffer final : public llvm::MemoryBuffer {
166 OpenCLBuiltinMemoryBuffer(const void *data, uint64_t data_length) {
167 const char *dataCasted = reinterpret_cast<const char *>(data);
168 init(dataCasted, dataCasted + data_length, true);
169 }
170
171 virtual llvm::MemoryBuffer::BufferKind getBufferKind() const override {
172 return llvm::MemoryBuffer::MemoryBuffer_Malloc;
173 }
174
175 virtual ~OpenCLBuiltinMemoryBuffer() override {}
176};
177} // namespace
178
alan-bakerfec0a472018-11-08 18:09:40 -0500179// Populates |SamplerMapEntries| with data from the input sampler map. Returns 0
180// if successful.
alan-bakerf5e5f692018-11-27 08:33:24 -0500181int ParseSamplerMap(const std::string &sampler_map,
182 llvm::SmallVectorImpl<std::pair<unsigned, std::string>>
183 *SamplerMapEntries) {
184 std::unique_ptr<llvm::MemoryBuffer> samplerMapBuffer(nullptr);
185 if (!sampler_map.empty()) {
186 // Parse the sampler map from the provided string.
187 samplerMapBuffer = llvm::MemoryBuffer::getMemBuffer(sampler_map);
188
alan-baker09cb9802019-12-10 13:16:27 -0500189 clspv::Option::SetUseSamplerMap(true);
alan-bakerf5e5f692018-11-27 08:33:24 -0500190 if (!SamplerMap.empty()) {
191 llvm::outs() << "Warning: -samplermap is ignored when the sampler map is "
192 "provided through a string.\n";
193 }
194 } else if (!SamplerMap.empty()) {
195 // Parse the sampler map from the option provided file.
alan-bakerfec0a472018-11-08 18:09:40 -0500196 auto errorOrSamplerMapFile =
197 llvm::MemoryBuffer::getFile(SamplerMap.getValue());
198
199 // If there was an error in getting the sampler map file.
200 if (!errorOrSamplerMapFile) {
201 llvm::errs() << "Error: " << errorOrSamplerMapFile.getError().message()
202 << " '" << SamplerMap.getValue() << "'\n";
203 return -1;
204 }
205
alan-baker09cb9802019-12-10 13:16:27 -0500206 clspv::Option::SetUseSamplerMap(true);
alan-bakerf5e5f692018-11-27 08:33:24 -0500207 samplerMapBuffer = std::move(errorOrSamplerMapFile.get());
alan-bakerfec0a472018-11-08 18:09:40 -0500208 if (0 == samplerMapBuffer->getBufferSize()) {
209 llvm::errs() << "Error: Sampler map was an empty file!\n";
210 return -1;
211 }
alan-bakerf5e5f692018-11-27 08:33:24 -0500212 }
alan-bakerfec0a472018-11-08 18:09:40 -0500213
alan-baker09cb9802019-12-10 13:16:27 -0500214 if (clspv::Option::UseSamplerMap()) {
alan-baker57ce1c22022-04-26 19:10:44 -0400215 // TODO(alan-baker): Remove all APIs dealing the sampler map after landing
216 // the transition to the new pass manager.
217 llvm::errs() << "Error: use of a sampler map is no longer supported\n";
218 return -1;
alan-baker09cb9802019-12-10 13:16:27 -0500219 }
220
alan-bakerf5e5f692018-11-27 08:33:24 -0500221 // No sampler map to parse.
222 if (!samplerMapBuffer || 0 == samplerMapBuffer->getBufferSize())
223 return 0;
alan-bakerfec0a472018-11-08 18:09:40 -0500224
alan-bakerf5e5f692018-11-27 08:33:24 -0500225 llvm::SmallVector<llvm::StringRef, 3> samplerStrings;
alan-bakerfec0a472018-11-08 18:09:40 -0500226
alan-bakerf5e5f692018-11-27 08:33:24 -0500227 // We need to keep track of the beginning of the current entry.
228 const char *b = samplerMapBuffer->getBufferStart();
229 for (const char *i = b, *e = samplerMapBuffer->getBufferEnd();; i++) {
230 // If we have a separator between declarations.
231 if ((*i == '|') || (*i == ',') || (i == e)) {
232 if (i == b) {
233 llvm::errs() << "Error: Sampler map contained an empty entry!\n";
234 return -1;
alan-bakerfec0a472018-11-08 18:09:40 -0500235 }
236
alan-bakerf5e5f692018-11-27 08:33:24 -0500237 samplerStrings.push_back(llvm::StringRef(b, i - b).trim());
alan-bakerfec0a472018-11-08 18:09:40 -0500238
alan-bakerf5e5f692018-11-27 08:33:24 -0500239 // And set b the next character after i.
240 b = i + 1;
241 }
alan-bakerfec0a472018-11-08 18:09:40 -0500242
alan-bakerf5e5f692018-11-27 08:33:24 -0500243 // If we have a separator between declarations within a single sampler.
244 if ((*i == ',') || (i == e)) {
alan-bakerfec0a472018-11-08 18:09:40 -0500245
alan-baker86ce19c2020-08-05 13:09:19 -0400246 clspv::SamplerNormalizedCoords NormalizedCoord =
247 clspv::CLK_NORMALIZED_COORDS_NOT_SET;
248 clspv::SamplerAddressingMode AddressingMode = clspv::CLK_ADDRESS_NOT_SET;
249 clspv::SamplerFilterMode FilterMode = clspv::CLK_FILTER_NOT_SET;
alan-bakerf5e5f692018-11-27 08:33:24 -0500250
251 for (auto str : samplerStrings) {
252 if ("CLK_NORMALIZED_COORDS_FALSE" == str) {
alan-baker86ce19c2020-08-05 13:09:19 -0400253 if (clspv::CLK_NORMALIZED_COORDS_NOT_SET != NormalizedCoord) {
alan-bakerf5e5f692018-11-27 08:33:24 -0500254 llvm::errs() << "Error: Sampler map normalized coordinates was "
255 "previously set!\n";
alan-bakerfec0a472018-11-08 18:09:40 -0500256 return -1;
257 }
alan-baker86ce19c2020-08-05 13:09:19 -0400258 NormalizedCoord = clspv::CLK_NORMALIZED_COORDS_FALSE;
alan-bakerf5e5f692018-11-27 08:33:24 -0500259 } else if ("CLK_NORMALIZED_COORDS_TRUE" == str) {
alan-baker86ce19c2020-08-05 13:09:19 -0400260 if (clspv::CLK_NORMALIZED_COORDS_NOT_SET != NormalizedCoord) {
alan-bakerf5e5f692018-11-27 08:33:24 -0500261 llvm::errs() << "Error: Sampler map normalized coordinates was "
262 "previously set!\n";
263 return -1;
264 }
alan-baker86ce19c2020-08-05 13:09:19 -0400265 NormalizedCoord = clspv::CLK_NORMALIZED_COORDS_TRUE;
alan-bakerf5e5f692018-11-27 08:33:24 -0500266 } else if ("CLK_ADDRESS_NONE" == str) {
alan-baker86ce19c2020-08-05 13:09:19 -0400267 if (clspv::CLK_ADDRESS_NOT_SET != AddressingMode) {
alan-bakerf5e5f692018-11-27 08:33:24 -0500268 llvm::errs()
269 << "Error: Sampler map addressing mode was previously set!\n";
270 return -1;
271 }
alan-baker86ce19c2020-08-05 13:09:19 -0400272 AddressingMode = clspv::CLK_ADDRESS_NONE;
alan-bakerf5e5f692018-11-27 08:33:24 -0500273 } else if ("CLK_ADDRESS_CLAMP_TO_EDGE" == str) {
alan-baker86ce19c2020-08-05 13:09:19 -0400274 if (clspv::CLK_ADDRESS_NOT_SET != AddressingMode) {
alan-bakerf5e5f692018-11-27 08:33:24 -0500275 llvm::errs()
276 << "Error: Sampler map addressing mode was previously set!\n";
277 return -1;
278 }
alan-baker86ce19c2020-08-05 13:09:19 -0400279 AddressingMode = clspv::CLK_ADDRESS_CLAMP_TO_EDGE;
alan-bakerf5e5f692018-11-27 08:33:24 -0500280 } else if ("CLK_ADDRESS_CLAMP" == str) {
alan-baker86ce19c2020-08-05 13:09:19 -0400281 if (clspv::CLK_ADDRESS_NOT_SET != AddressingMode) {
alan-bakerf5e5f692018-11-27 08:33:24 -0500282 llvm::errs()
283 << "Error: Sampler map addressing mode was previously set!\n";
284 return -1;
285 }
alan-baker86ce19c2020-08-05 13:09:19 -0400286 AddressingMode = clspv::CLK_ADDRESS_CLAMP;
alan-bakerf5e5f692018-11-27 08:33:24 -0500287 } else if ("CLK_ADDRESS_MIRRORED_REPEAT" == str) {
alan-baker86ce19c2020-08-05 13:09:19 -0400288 if (clspv::CLK_ADDRESS_NOT_SET != AddressingMode) {
alan-bakerf5e5f692018-11-27 08:33:24 -0500289 llvm::errs()
290 << "Error: Sampler map addressing mode was previously set!\n";
291 return -1;
292 }
alan-baker86ce19c2020-08-05 13:09:19 -0400293 AddressingMode = clspv::CLK_ADDRESS_MIRRORED_REPEAT;
alan-bakerf5e5f692018-11-27 08:33:24 -0500294 } else if ("CLK_ADDRESS_REPEAT" == str) {
alan-baker86ce19c2020-08-05 13:09:19 -0400295 if (clspv::CLK_ADDRESS_NOT_SET != AddressingMode) {
alan-bakerf5e5f692018-11-27 08:33:24 -0500296 llvm::errs()
297 << "Error: Sampler map addressing mode was previously set!\n";
298 return -1;
299 }
alan-baker86ce19c2020-08-05 13:09:19 -0400300 AddressingMode = clspv::CLK_ADDRESS_REPEAT;
alan-bakerf5e5f692018-11-27 08:33:24 -0500301 } else if ("CLK_FILTER_NEAREST" == str) {
alan-baker86ce19c2020-08-05 13:09:19 -0400302 if (clspv::CLK_FILTER_NOT_SET != FilterMode) {
alan-bakerf5e5f692018-11-27 08:33:24 -0500303 llvm::errs()
304 << "Error: Sampler map filtering mode was previously set!\n";
305 return -1;
306 }
alan-baker86ce19c2020-08-05 13:09:19 -0400307 FilterMode = clspv::CLK_FILTER_NEAREST;
alan-bakerf5e5f692018-11-27 08:33:24 -0500308 } else if ("CLK_FILTER_LINEAR" == str) {
alan-baker86ce19c2020-08-05 13:09:19 -0400309 if (clspv::CLK_FILTER_NOT_SET != FilterMode) {
alan-bakerf5e5f692018-11-27 08:33:24 -0500310 llvm::errs()
311 << "Error: Sampler map filtering mode was previously set!\n";
312 return -1;
313 }
alan-baker86ce19c2020-08-05 13:09:19 -0400314 FilterMode = clspv::CLK_FILTER_LINEAR;
alan-bakerf5e5f692018-11-27 08:33:24 -0500315 } else {
316 llvm::errs() << "Error: Unknown sampler string '" << str
317 << "' found!\n";
alan-bakerfec0a472018-11-08 18:09:40 -0500318 return -1;
319 }
alan-bakerfec0a472018-11-08 18:09:40 -0500320 }
321
alan-baker86ce19c2020-08-05 13:09:19 -0400322 if (clspv::CLK_NORMALIZED_COORDS_NOT_SET == NormalizedCoord) {
alan-bakerf5e5f692018-11-27 08:33:24 -0500323 llvm::errs() << "Error: Sampler map entry did not contain normalized "
324 "coordinates entry!\n";
325 return -1;
alan-bakerfec0a472018-11-08 18:09:40 -0500326 }
alan-bakerf5e5f692018-11-27 08:33:24 -0500327
alan-baker86ce19c2020-08-05 13:09:19 -0400328 if (clspv::CLK_ADDRESS_NOT_SET == AddressingMode) {
alan-bakerf5e5f692018-11-27 08:33:24 -0500329 llvm::errs() << "Error: Sampler map entry did not contain addressing "
330 "mode entry!\n";
331 return -1;
332 }
333
alan-baker86ce19c2020-08-05 13:09:19 -0400334 if (clspv::CLK_FILTER_NOT_SET == FilterMode) {
alan-bakerf5e5f692018-11-27 08:33:24 -0500335 llvm::errs()
336 << "Error: Sampler map entry did not contain filer mode entry!\n";
337 return -1;
338 }
339
340 // Generate an equivalent expression in string form. Sort the
341 // strings to get a canonical ordering.
342 std::sort(samplerStrings.begin(), samplerStrings.end(),
343 std::less<StringRef>());
344 const auto samplerExpr = std::accumulate(
345 samplerStrings.begin(), samplerStrings.end(), std::string(),
alan-baker21574d32020-01-29 16:00:31 -0500346 [](llvm::StringRef left, llvm::StringRef right) {
347 return left.str() + std::string(left.empty() ? "" : "|") +
348 right.str();
alan-bakerf5e5f692018-11-27 08:33:24 -0500349 });
350
351 // SamplerMapEntries->push_back(std::make_pair(
352 // NormalizedCoord | AddressingMode | FilterMode, samplerExpr));
353 SamplerMapEntries->emplace_back(
354 NormalizedCoord | AddressingMode | FilterMode, samplerExpr);
355
356 // And reset the sampler strings for the next sampler in the map.
357 samplerStrings.clear();
358 }
359
360 // And lastly, if we are at the end of the file
361 if (i == e) {
362 break;
alan-bakerfec0a472018-11-08 18:09:40 -0500363 }
364 }
365
366 return 0;
367}
368
Kévin Petitaab5bb82021-03-30 16:26:11 +0100369clang::TargetInfo *PrepareTargetInfo(CompilerInstance &instance) {
370 // Create target info
371 auto TargetInfo = clang::TargetInfo::CreateTargetInfo(
372 instance.getDiagnostics(),
373 std::make_shared<clang::TargetOptions>(instance.getTargetOpts()));
374
375 // The SPIR target enables all possible options, disable the ones we don't
376 // want
377 auto &Opts = TargetInfo->getSupportedOpenCLOpts();
378
379 // Conditionally disable extensions based on support
380 if (!clspv::Option::FP16()) {
381 Opts["cl_khr_fp16"] = false;
382 }
383 if (!clspv::Option::FP64()) {
384 Opts["cl_khr_fp64"] = false;
385 }
386
387 // Disable CL3.0 feature macros for unsupported features
388 if (instance.getLangOpts().LangStd == clang::LangStandard::lang_opencl30) {
389
Kévin Petitaab5bb82021-03-30 16:26:11 +0100390 // The following features are never supported
391 Opts["__opencl_c_pipes"] = false;
392 Opts["__opencl_c_generic_address_space"] = false;
Kévin Petitaab5bb82021-03-30 16:26:11 +0100393 Opts["__opencl_c_device_enqueue"] = false;
394 Opts["__opencl_c_program_scope_global_variables"] = false;
395
396 if (!clspv::Option::ImageSupport()) {
397 Opts["__opencl_c_images"] = false;
398 }
399
400 if (!clspv::Option::FP64()) {
401 Opts["__opencl_c_fp64"] = false;
402 }
403 }
404
405 return TargetInfo;
406}
407
alan-bakerfec0a472018-11-08 18:09:40 -0500408// Sets |instance|'s options for compiling. Returns 0 if successful.
Ryan Senanayake6917fb12022-02-28 18:17:02 -0500409int SetCompilerInstanceOptions(
410 CompilerInstance &instance, const llvm::StringRef &overiddenInputFilename,
411 clang::FrontendInputFile &kernelFile, const std::string &program,
412 std::unique_ptr<llvm::MemoryBuffer> &file_memory_buffer,
413 llvm::raw_string_ostream *diagnosticsStream) {
alan-bakerf5e5f692018-11-27 08:33:24 -0500414 llvm::ErrorOr<std::unique_ptr<llvm::MemoryBuffer>> errorOrInputFile(nullptr);
415 if (program.empty()) {
416 auto errorOrInputFile =
417 llvm::MemoryBuffer::getFileOrSTDIN(InputFilename.getValue());
alan-bakerfec0a472018-11-08 18:09:40 -0500418
alan-bakerf5e5f692018-11-27 08:33:24 -0500419 // If there was an error in getting the input file.
420 if (!errorOrInputFile) {
421 llvm::errs() << "Error: " << errorOrInputFile.getError().message() << " '"
422 << InputFilename.getValue() << "'\n";
423 return -1;
424 }
Ryan Senanayake6917fb12022-02-28 18:17:02 -0500425 file_memory_buffer = std::move(errorOrInputFile.get());
alan-bakerf5e5f692018-11-27 08:33:24 -0500426 } else {
Ryan Senanayake6917fb12022-02-28 18:17:02 -0500427 file_memory_buffer =
428 llvm::MemoryBuffer::getMemBuffer(program, overiddenInputFilename);
alan-bakerfec0a472018-11-08 18:09:40 -0500429 }
alan-bakerf5e5f692018-11-27 08:33:24 -0500430
alan-bakerfec0a472018-11-08 18:09:40 -0500431 if (verify) {
432 instance.getDiagnosticOpts().VerifyDiagnostics = true;
alan-bakerbccf62c2019-03-29 10:32:41 -0400433 instance.getDiagnosticOpts().VerifyPrefixes.push_back("expected");
alan-bakerfec0a472018-11-08 18:09:40 -0500434 }
435
Kévin Petit0fc88042019-04-09 23:25:02 +0100436 clang::LangStandard::Kind standard;
Kévin Petitf0515712020-01-07 18:29:20 +0000437 switch (clspv::Option::Language()) {
438 case clspv::Option::SourceLanguage::OpenCL_C_10:
439 standard = clang::LangStandard::lang_opencl10;
440 break;
441 case clspv::Option::SourceLanguage::OpenCL_C_11:
442 standard = clang::LangStandard::lang_opencl11;
443 break;
444 case clspv::Option::SourceLanguage::OpenCL_C_12:
Kévin Petit0fc88042019-04-09 23:25:02 +0100445 standard = clang::LangStandard::lang_opencl12;
Kévin Petitf0515712020-01-07 18:29:20 +0000446 break;
447 case clspv::Option::SourceLanguage::OpenCL_C_20:
448 standard = clang::LangStandard::lang_opencl20;
449 break;
Kévin Petit77838ff2020-10-19 18:54:51 +0100450 case clspv::Option::SourceLanguage::OpenCL_C_30:
451 standard = clang::LangStandard::lang_opencl30;
452 break;
Kévin Petitf0515712020-01-07 18:29:20 +0000453 case clspv::Option::SourceLanguage::OpenCL_CPP:
alan-baker39706812021-08-03 13:21:39 -0400454 standard = clang::LangStandard::lang_openclcpp10;
Kévin Petitf0515712020-01-07 18:29:20 +0000455 break;
456 default:
457 llvm_unreachable("Unknown source language");
Kévin Petit0fc88042019-04-09 23:25:02 +0100458 }
alan-bakerfec0a472018-11-08 18:09:40 -0500459
alan-bakerfec0a472018-11-08 18:09:40 -0500460 instance.getLangOpts().C99 = true;
461 instance.getLangOpts().RTTI = false;
462 instance.getLangOpts().RTTIData = false;
463 instance.getLangOpts().MathErrno = false;
464 instance.getLangOpts().Optimize = false;
465 instance.getLangOpts().NoBuiltin = true;
466 instance.getLangOpts().ModulesSearchAll = false;
467 instance.getLangOpts().SinglePrecisionConstants = true;
468 instance.getCodeGenOpts().StackRealignment = true;
469 instance.getCodeGenOpts().SimplifyLibCalls = false;
470 instance.getCodeGenOpts().EmitOpenCLArgMetadata = false;
471 instance.getCodeGenOpts().DisableO0ImplyOptNone = true;
alan-baker2ceb6592022-06-07 09:41:35 -0400472 instance.getCodeGenOpts().OpaquePointers = OpaquePointers;
Kévin Petit6b07cbe2019-04-02 21:52:16 +0100473 instance.getDiagnosticOpts().IgnoreWarnings = IgnoreWarnings;
alan-bakerfec0a472018-11-08 18:09:40 -0500474
475 instance.getLangOpts().SinglePrecisionConstants =
476 cl_single_precision_constants;
477 // cl_denorms_are_zero ignored for now!
478 // cl_fp32_correctly_rounded_divide_sqrt ignored for now!
479 instance.getCodeGenOpts().LessPreciseFPMAD =
alan-baker7b664822022-05-02 18:03:04 -0400480 cl_mad_enable || clspv::Option::UnsafeMath();
alan-bakerfec0a472018-11-08 18:09:40 -0500481 // cl_no_signed_zeros ignored for now!
alan-baker7b664822022-05-02 18:03:04 -0400482 instance.getLangOpts().UnsafeFPMath = clspv::Option::UnsafeMath();
483 instance.getLangOpts().FiniteMathOnly = clspv::Option::FiniteMath();
484 instance.getLangOpts().FastRelaxedMath = clspv::Option::FastRelaxedMath();
alan-bakerfec0a472018-11-08 18:09:40 -0500485
486 // Preprocessor options
Kévin Petita624c0c2019-05-07 20:27:43 +0800487 if (!clspv::Option::ImageSupport()) {
488 instance.getPreprocessorOpts().addMacroUndef("__IMAGE_SUPPORT__");
489 }
alan-baker7b664822022-05-02 18:03:04 -0400490 if (clspv::Option::FastRelaxedMath()) {
alan-bakerfec0a472018-11-08 18:09:40 -0500491 instance.getPreprocessorOpts().addMacroDef("__FAST_RELAXED_MATH__");
492 }
493
494 for (auto define : Defines) {
495 instance.getPreprocessorOpts().addMacroDef(define);
496 }
497
498 // Header search options
499 for (auto include : Includes) {
500 instance.getHeaderSearchOpts().AddPath(include, clang::frontend::After,
501 false, false);
502 }
503
504 // We always compile on opt 0 so we preserve as much debug information about
505 // the source as possible. We'll run optimization later, once we've had a
506 // chance to view the unoptimal code first
507 instance.getCodeGenOpts().OptimizationLevel = 0;
508
509// Debug information is disabled temporarily to call instruction.
510#if 0
511 instance.getCodeGenOpts().setDebugInfo(clang::codegenoptions::FullDebugInfo);
512#endif
513
514 // We use the 32-bit pointer-width SPIR triple
515 llvm::Triple triple("spir-unknown-unknown");
516
James Price40efe7f2021-01-18 09:19:31 -0500517 // We manually include the OpenCL headers below, so this vector is unused.
518 std::vector<std::string> includes;
519
alan-baker1e20bf22022-04-13 16:05:14 -0400520 LangOptions::setLangDefaults(instance.getLangOpts(), clang::Language::OpenCL,
521 triple, includes, standard);
alan-bakerfec0a472018-11-08 18:09:40 -0500522
523 // Override the C99 inline semantics to accommodate for more OpenCL C
524 // programs in the wild.
525 instance.getLangOpts().GNUInline = true;
Kévin Petit6b07cbe2019-04-02 21:52:16 +0100526
527 // Set up diagnostics
alan-bakerfec0a472018-11-08 18:09:40 -0500528 instance.createDiagnostics(
529 new clang::TextDiagnosticPrinter(*diagnosticsStream,
530 &instance.getDiagnosticOpts()),
531 true);
Kévin Petit6b07cbe2019-04-02 21:52:16 +0100532 instance.getDiagnostics().setWarningsAsErrors(WarningsAsErrors);
533 instance.getDiagnostics().setEnableAllWarnings(true);
alan-bakerfec0a472018-11-08 18:09:40 -0500534
535 instance.getTargetOpts().Triple = triple.str();
536
alan-baker21574d32020-01-29 16:00:31 -0500537 instance.getCodeGenOpts().MainFileName = overiddenInputFilename.str();
alan-bakerfec0a472018-11-08 18:09:40 -0500538 instance.getCodeGenOpts().PreserveVec3Type = true;
539 // Disable generation of lifetime intrinsic.
540 instance.getCodeGenOpts().DisableLifetimeMarkers = true;
Ryan Senanayake6917fb12022-02-28 18:17:02 -0500541 if (InputLanguage == clang::Language::OpenCL) {
542 instance.getPreprocessorOpts().addRemappedFile(
543 overiddenInputFilename, file_memory_buffer.release());
544 } else if (!program.empty()) {
545 // Can't use preprocessor to do file remapping for LLVM_IR
546 kernelFile = clang::FrontendInputFile(*file_memory_buffer,
547 clang::InputKind(InputLanguage));
548 }
alan-bakerfec0a472018-11-08 18:09:40 -0500549 instance.getFrontendOpts().Inputs.push_back(kernelFile);
alan-bakerfec0a472018-11-08 18:09:40 -0500550
alan-bakerfec0a472018-11-08 18:09:40 -0500551 std::unique_ptr<llvm::MemoryBuffer> openCLBuiltinMemoryBuffer(
552 new OpenCLBuiltinMemoryBuffer(opencl_builtins_header_data,
553 opencl_builtins_header_size - 1));
554
James Price40efe7f2021-01-18 09:19:31 -0500555 instance.getPreprocessorOpts().Includes.push_back("opencl-c.h");
alan-bakerfec0a472018-11-08 18:09:40 -0500556
alan-bakerf3bce4a2019-06-28 16:01:15 -0400557 std::unique_ptr<llvm::MemoryBuffer> openCLBaseBuiltinMemoryBuffer(
558 new OpenCLBuiltinMemoryBuffer(opencl_base_builtins_header_data,
559 opencl_base_builtins_header_size - 1));
560
561 instance.getPreprocessorOpts().Includes.push_back("opencl-c-base.h");
562
alan-bakerfec0a472018-11-08 18:09:40 -0500563 // Add the VULKAN macro.
564 instance.getPreprocessorOpts().addMacroDef("VULKAN=100");
565
566 // Add the __OPENCL_VERSION__ macro.
567 instance.getPreprocessorOpts().addMacroDef("__OPENCL_VERSION__=120");
568
Kévin Petitaab5bb82021-03-30 16:26:11 +0100569 instance.setTarget(PrepareTargetInfo(instance));
alan-bakerfec0a472018-11-08 18:09:40 -0500570
571 instance.createFileManager();
572 instance.createSourceManager(instance.getFileManager());
573
574#ifdef _MSC_VER
575 std::string includePrefix("include\\");
576#else
577 std::string includePrefix("include/");
578#endif
579
580 auto entry = instance.getFileManager().getVirtualFile(
James Price40efe7f2021-01-18 09:19:31 -0500581 includePrefix + "opencl-c.h", openCLBuiltinMemoryBuffer->getBufferSize(),
alan-bakerfec0a472018-11-08 18:09:40 -0500582 0);
583
584 instance.getSourceManager().overrideFileContents(
585 entry, std::move(openCLBuiltinMemoryBuffer));
586
alan-bakerf3bce4a2019-06-28 16:01:15 -0400587 auto base_entry = instance.getFileManager().getVirtualFile(
588 includePrefix + "opencl-c-base.h",
589 openCLBaseBuiltinMemoryBuffer->getBufferSize(), 0);
590
591 instance.getSourceManager().overrideFileContents(
592 base_entry, std::move(openCLBaseBuiltinMemoryBuffer));
593
alan-bakerfec0a472018-11-08 18:09:40 -0500594 return 0;
595}
596
alan-baker57ce1c22022-04-26 19:10:44 -0400597int RunPassPipeline(llvm::Module &M, llvm::raw_svector_ostream *binaryStream) {
598 llvm::LoopAnalysisManager lam;
599 llvm::FunctionAnalysisManager fam;
600 llvm::CGSCCAnalysisManager cgam;
601 llvm::ModuleAnalysisManager mam;
602 llvm::PassInstrumentationCallbacks PIC;
603 clspv::RegisterClspvPasses(&PIC);
604 llvm::PassBuilder pb(nullptr, llvm::PipelineTuningOptions(), llvm::None,
605 &PIC);
606 pb.registerModuleAnalyses(mam);
607 pb.registerCGSCCAnalyses(cgam);
608 pb.registerFunctionAnalyses(fam);
609 pb.registerLoopAnalyses(lam);
610 pb.crossRegisterProxies(lam, fam, cgam, mam);
611
612 llvm::ModulePassManager pm;
613 llvm::FunctionPassManager fpm;
alan-bakerfec0a472018-11-08 18:09:40 -0500614
615 switch (OptimizationLevel) {
616 case '0':
alan-bakerf5e5f692018-11-27 08:33:24 -0500617 case '1':
618 case '2':
619 case '3':
620 case 's':
621 case 'z':
622 break;
623 default:
624 llvm::errs() << "Unknown optimization level -O" << OptimizationLevel
625 << " specified!\n";
626 return -1;
627 }
628
alan-baker57ce1c22022-04-26 19:10:44 -0400629 llvm::OptimizationLevel level;
alan-bakerf5e5f692018-11-27 08:33:24 -0500630 switch (OptimizationLevel) {
631 case '0':
alan-baker57ce1c22022-04-26 19:10:44 -0400632 level = llvm::OptimizationLevel::O0;
alan-bakerfec0a472018-11-08 18:09:40 -0500633 break;
634 case '1':
alan-baker57ce1c22022-04-26 19:10:44 -0400635 level = llvm::OptimizationLevel::O1;
alan-bakerfec0a472018-11-08 18:09:40 -0500636 break;
637 case '2':
alan-baker57ce1c22022-04-26 19:10:44 -0400638 level = llvm::OptimizationLevel::O2;
alan-bakerfec0a472018-11-08 18:09:40 -0500639 break;
640 case '3':
alan-baker57ce1c22022-04-26 19:10:44 -0400641 level = llvm::OptimizationLevel::O3;
alan-bakerfec0a472018-11-08 18:09:40 -0500642 break;
643 case 's':
alan-baker57ce1c22022-04-26 19:10:44 -0400644 level = llvm::OptimizationLevel::Os;
alan-bakerfec0a472018-11-08 18:09:40 -0500645 break;
646 case 'z':
alan-baker57ce1c22022-04-26 19:10:44 -0400647 level = llvm::OptimizationLevel::Oz;
alan-bakerfec0a472018-11-08 18:09:40 -0500648 break;
649 default:
650 break;
651 }
652
alan-baker57ce1c22022-04-26 19:10:44 -0400653 // Run the following optimizations prior to the standard LLVM pass pipeline.
654 pb.registerPipelineStartEPCallback([](llvm::ModulePassManager &pm,
655 llvm::OptimizationLevel level) {
656 pm.addPass(clspv::NativeMathPass());
657 pm.addPass(clspv::ZeroInitializeAllocasPass());
658 pm.addPass(clspv::AddFunctionAttributesPass());
659 pm.addPass(clspv::AutoPodArgsPass());
660 pm.addPass(clspv::DeclarePushConstantsPass());
661 pm.addPass(clspv::DefineOpenCLWorkItemBuiltinsPass());
alan-bakerfec0a472018-11-08 18:09:40 -0500662
alan-baker57ce1c22022-04-26 19:10:44 -0400663 if (level.getSpeedupLevel() > 0) {
664 pm.addPass(clspv::OpenCLInlinerPass());
665 }
alan-bakerfec0a472018-11-08 18:09:40 -0500666
alan-baker57ce1c22022-04-26 19:10:44 -0400667 pm.addPass(clspv::UndoByvalPass());
668 pm.addPass(clspv::UndoSRetPass());
669 pm.addPass(clspv::ClusterPodKernelArgumentsPass());
Romaric Jodin71fdb322022-05-03 17:01:10 +0200670 // ReplaceOpenCLBuiltinPass can generate vec8 and vec16 elements. It needs
671 // to be before the potential LongVectorLoweringPass pass.
alan-baker57ce1c22022-04-26 19:10:44 -0400672 pm.addPass(clspv::ReplaceOpenCLBuiltinPass());
673 pm.addPass(clspv::ThreeElementVectorLoweringPass());
alan-bakerfec0a472018-11-08 18:09:40 -0500674
alan-baker57ce1c22022-04-26 19:10:44 -0400675 // Lower longer vectors when requested. Note that this pass depends on
676 // ReplaceOpenCLBuiltinPass and expects DeadCodeEliminationPass to be run
677 // afterwards.
678 if (clspv::Option::LongVectorSupport()) {
679 pm.addPass(clspv::LongVectorLoweringPass());
680 }
Romaric Jodin322e9ba2021-12-08 16:00:06 +0100681
alan-baker57ce1c22022-04-26 19:10:44 -0400682 // We need to run mem2reg and inst combine early because our
683 // createInlineFuncWithPointerBitCastArgPass pass cannot handle the pattern
684 // %1 = alloca i32 1
685 // store <something> %1
686 // %2 = bitcast float* %1
687 // %3 = load float %2
688 pm.addPass(llvm::createModuleToFunctionPassAdaptor(llvm::PromotePass()));
Marco Antognini535998c2020-09-16 18:48:51 +0100689
alan-baker57ce1c22022-04-26 19:10:44 -0400690 // Try to deal with pointer bitcasts early. This can prevent problems like
691 // issue #409 where LLVM is looser about access chain addressing than
692 // SPIR-V. This needs to happen before instcombine and after replacing
693 // OpenCL builtins. This run of the pass will not handle all pointer
694 // bitcasts that could be handled. It should be run again after other
695 // optimizations (e.g InlineFuncWithPointerBitCastArgPass).
696 pm.addPass(clspv::SimplifyPointerBitcastPass());
697 pm.addPass(clspv::ReplacePointerBitcastPass());
698 pm.addPass(llvm::createModuleToFunctionPassAdaptor(llvm::DCEPass()));
alan-bakerfec0a472018-11-08 18:09:40 -0500699
alan-baker57ce1c22022-04-26 19:10:44 -0400700 // Hide loads from __constant address space away from instcombine.
701 // This prevents us from generating select between pointers-to-__constant.
702 // See https://github.com/google/clspv/issues/71
703 pm.addPass(clspv::HideConstantLoadsPass());
alan-baker1b13e8f2019-08-08 17:56:51 -0400704
alan-baker57ce1c22022-04-26 19:10:44 -0400705 pm.addPass(
706 llvm::createModuleToFunctionPassAdaptor(llvm::InstCombinePass()));
alan-bakerfec0a472018-11-08 18:09:40 -0500707
alan-baker57ce1c22022-04-26 19:10:44 -0400708 if (clspv::Option::InlineEntryPoints()) {
709 pm.addPass(clspv::InlineEntryPointsPass());
710 } else {
711 pm.addPass(clspv::InlineFuncWithPointerBitCastArgPass());
712 pm.addPass(clspv::InlineFuncWithPointerToFunctionArgPass());
713 pm.addPass(clspv::InlineFuncWithSingleCallSitePass());
714 }
alan-bakerfec0a472018-11-08 18:09:40 -0500715
alan-baker57ce1c22022-04-26 19:10:44 -0400716 // Mem2Reg pass should be run early because O0 level optimization leaves
717 // redundant alloca, load and store instructions from function arguments.
718 // clspv needs to remove them ahead of transformation.
719 pm.addPass(llvm::createModuleToFunctionPassAdaptor(llvm::PromotePass()));
720
721 // SROA pass is run because it will fold structs/unions that are problematic
722 // on Vulkan SPIR-V away.
723 pm.addPass(llvm::createModuleToFunctionPassAdaptor(llvm::SROAPass()));
724
725 // InstructionCombining pass folds bitcast and gep instructions which are
726 // not supported by Vulkan SPIR-V.
727 pm.addPass(
728 llvm::createModuleToFunctionPassAdaptor(llvm::InstCombinePass()));
729
730 if (clspv::Option::LanguageUsesGenericAddressSpace()) {
731 pm.addPass(llvm::createModuleToFunctionPassAdaptor(
732 llvm::InferAddressSpacesPass(clspv::AddressSpace::Generic)));
733 }
734 });
735
736 // Run the following passes after the default LLVM pass pipeline.
737 pb.registerOptimizerLastEPCallback([binaryStream](llvm::ModulePassManager &pm,
738 llvm::OptimizationLevel) {
739 // No point attempting to handle freeze currently so strip them from the IR.
740 pm.addPass(clspv::StripFreezePass());
741
742 // Unhide loads from __constant address space. Undoes the action of
743 // HideConstantLoadsPass.
744 pm.addPass(clspv::UnhideConstantLoadsPass());
745
746 pm.addPass(clspv::UndoInstCombinePass());
747 pm.addPass(clspv::FunctionInternalizerPass());
748 pm.addPass(clspv::ReplaceLLVMIntrinsicsPass());
749 // Replace LLVM intrinsics can leave dead code around.
750 pm.addPass(llvm::createModuleToFunctionPassAdaptor(llvm::DCEPass()));
751 pm.addPass(clspv::UndoBoolPass());
752 pm.addPass(clspv::UndoTruncateToOddIntegerPass());
753 // StructurizeCFG requires LowerSwitch to run first.
754 pm.addPass(
755 llvm::createModuleToFunctionPassAdaptor(llvm::LowerSwitchPass()));
756 pm.addPass(
757 llvm::createModuleToFunctionPassAdaptor(llvm::StructurizeCFGPass()));
758 // Must be run after structurize cfg.
759 pm.addPass(llvm::createModuleToFunctionPassAdaptor(
760 clspv::FixupStructuredCFGPass()));
761 // Must be run after structured cfg fixup.
762 pm.addPass(llvm::createModuleToFunctionPassAdaptor(
763 clspv::ReorderBasicBlocksPass()));
764 pm.addPass(clspv::UndoGetElementPtrConstantExprPass());
765 pm.addPass(clspv::SplatArgPass());
766 pm.addPass(clspv::SimplifyPointerBitcastPass());
767 pm.addPass(clspv::ReplacePointerBitcastPass());
768 pm.addPass(llvm::createModuleToFunctionPassAdaptor(llvm::DCEPass()));
769
770 pm.addPass(clspv::UndoTranslateSamplerFoldPass());
771
772 if (clspv::Option::ModuleConstantsInStorageBuffer()) {
773 pm.addPass(clspv::ClusterModuleScopeConstantVars());
774 }
775
776 pm.addPass(clspv::ShareModuleScopeVariablesPass());
777 // Specialize images before assigning descriptors to disambiguate the
778 // various types.
779 pm.addPass(clspv::SpecializeImageTypesPass());
780 // This should be run after LLVM and OpenCL intrinsics are replaced.
781 pm.addPass(clspv::AllocateDescriptorsPass());
782 pm.addPass(llvm::VerifierPass());
783 pm.addPass(clspv::DirectResourceAccessPass());
784 // Replacing pointer bitcasts can leave some trivial GEPs
785 // that are easy to remove. Also replace GEPs of GEPS
786 // left by replacing indirect buffer accesses.
787 pm.addPass(clspv::SimplifyPointerBitcastPass());
788 // Run after DRA to clean up parameters and help reduce the need for
789 // variable pointers.
790 pm.addPass(clspv::RemoveUnusedArguments());
791 pm.addPass(llvm::createModuleToFunctionPassAdaptor(llvm::DCEPass()));
792
793 // SPIR-V 1.4 and higher do not need to splat scalar conditions for vector
794 // data.
795 if (clspv::Option::SpvVersion() < clspv::Option::SPIRVVersion::SPIRV_1_4) {
796 pm.addPass(clspv::SplatSelectConditionPass());
797 }
798 pm.addPass(clspv::SignedCompareFixupPass());
799 // This pass generates insertions that need to be rewritten.
800 pm.addPass(clspv::ScalarizePass());
801 pm.addPass(clspv::RewriteInsertsPass());
802 // UBO Transformations
803 if (clspv::Option::ConstantArgsInUniformBuffer() &&
804 !clspv::Option::InlineEntryPoints()) {
805 // MultiVersionUBOFunctionsPass will examine non-kernel functions with UBO
806 // arguments and either multi-version them as necessary or inline them if
807 // multi-versioning cannot be accomplished.
808 pm.addPass(clspv::MultiVersionUBOFunctionsPass());
809 // Cleanup passes.
810 // Specialization can blindly generate GEP chains that are easily cleaned
811 // up by SimplifyPointerBitcastPass.
812 pm.addPass(clspv::SimplifyPointerBitcastPass());
813 // RemoveUnusedArgumentsPass removes the actual UBO arguments that were
814 // problematic to begin with now that they have no uses.
815 pm.addPass(clspv::RemoveUnusedArguments());
816 // DCE cleans up callers of the specialized functions.
817 pm.addPass(llvm::createModuleToFunctionPassAdaptor(llvm::DCEPass()));
818 }
819 // This pass mucks with types to point where you shouldn't rely on
820 // DataLayout anymore so leave this right before SPIR-V generation.
821 pm.addPass(clspv::UBOTypeTransformPass());
822 pm.addPass(clspv::SPIRVProducerPass(binaryStream, OutputFormat == "c"));
823 });
824
825 // Add the default optimizations for the requested optimization level.
826 if (level.getSpeedupLevel() > 0) {
827 auto mpm = pb.buildPerModuleDefaultPipeline(level);
828 mpm.run(M, mam);
alan-bakerfec0a472018-11-08 18:09:40 -0500829 } else {
alan-baker57ce1c22022-04-26 19:10:44 -0400830 auto mpm = pb.buildO0DefaultPipeline(level);
831 mpm.run(M, mam);
alan-bakerfec0a472018-11-08 18:09:40 -0500832 }
833
alan-bakerf5e5f692018-11-27 08:33:24 -0500834 return 0;
alan-bakerfec0a472018-11-08 18:09:40 -0500835}
alan-bakerfec0a472018-11-08 18:09:40 -0500836
Kévin Petitd5db2d22019-04-04 13:55:14 +0100837int ParseOptions(const int argc, const char *const argv[]) {
alan-baker227e9782020-06-02 15:35:37 -0400838 // We need to change how some of the called passes works by spoofing
839 // ParseCommandLineOptions with the specific options.
840 bool has_pre = false;
841 bool has_load_pre = false;
842 const std::string pre = "-enable-pre";
843 const std::string load_pre = "-enable-load-pre";
844 for (int i = 1; i < argc; ++i) {
845 std::string option(argv[i]);
846 auto pre_pos = option.find(pre);
847 auto load_pos = option.find(load_pre);
848 if (pre_pos == 0 || (pre_pos == 1 && option[0] == '-')) {
849 has_pre = true;
850 } else if (load_pos == 0 || (load_pos == 1 && option[0] == '-')) {
851 has_load_pre = true;
852 }
853 }
854
alan-baker1b333b62021-05-31 14:55:32 -0400855 int llvmArgc = 3;
alan-baker158b1e42022-06-02 22:38:08 -0400856 const char *llvmArgv[6];
alan-baker227e9782020-06-02 15:35:37 -0400857 llvmArgv[0] = argv[0];
858 llvmArgv[1] = "-simplifycfg-sink-common=false";
alan-baker1b333b62021-05-31 14:55:32 -0400859 // TODO(#738): find a better solution to this.
860 llvmArgv[2] = "-disable-vector-combine";
alan-baker227e9782020-06-02 15:35:37 -0400861 if (!has_pre) {
862 llvmArgv[llvmArgc++] = "-enable-pre=0";
863 }
864 if (!has_load_pre) {
865 llvmArgv[llvmArgc++] = "-enable-load-pre=0";
866 }
alan-bakerfec0a472018-11-08 18:09:40 -0500867
Kévin Petitd5db2d22019-04-04 13:55:14 +0100868 llvm::cl::ResetAllOptionOccurrences();
alan-bakerfec0a472018-11-08 18:09:40 -0500869 llvm::cl::ParseCommandLineOptions(llvmArgc, llvmArgv);
alan-bakerfec0a472018-11-08 18:09:40 -0500870 llvm::cl::ParseCommandLineOptions(argc, argv);
871
Kévin Petitf0515712020-01-07 18:29:20 +0000872 if (clspv::Option::LanguageUsesGenericAddressSpace() &&
873 !clspv::Option::InlineEntryPoints()) {
874 llvm::errs() << "cannot compile languages that use the generic address "
875 "space (e.g. CLC++, CL2.0) without -inline-entry-points\n";
Kévin Petit0fc88042019-04-09 23:25:02 +0100876 return -1;
877 }
878
Kévin Petitbbbda972020-03-03 19:16:31 +0000879 if (clspv::Option::ScalarBlockLayout()) {
880 llvm::errs() << "scalar block layout support unimplemented\n";
881 return -1;
882 }
883
alan-baker9b0ec3c2020-04-06 14:45:34 -0400884 // Push constant option validation.
885 if (clspv::Option::PodArgsInPushConstants()) {
886 if (clspv::Option::PodArgsInUniformBuffer()) {
887 llvm::errs() << "POD arguments can only be in either uniform buffers or "
888 "push constants\n";
889 return -1;
890 }
891
892 if (!clspv::Option::ClusterPodKernelArgs()) {
893 llvm::errs()
894 << "POD arguments must be clustered to be passed as push constants\n";
895 return -1;
896 }
897
898 // Conservatively error if a module scope push constant could be used.
James Price708cf362020-05-06 19:33:45 -0400899 if (clspv::Option::GlobalOffsetPushConstant() ||
alan-baker9b0ec3c2020-04-06 14:45:34 -0400900 clspv::Option::Language() ==
901 clspv::Option::SourceLanguage::OpenCL_C_20 ||
902 clspv::Option::Language() ==
903 clspv::Option::SourceLanguage::OpenCL_CPP) {
904 llvm::errs() << "POD arguments as push constants are not compatible with "
905 "module scope push constants\n";
906 return -1;
907 }
908 }
909
Mehmet Oguz Derin047cc872021-04-15 19:56:41 +0300910 if (clspv::Option::ArmNonUniformWorkGroupSize() &&
911 clspv::Option::UniformWorkgroupSize()) {
912 llvm::errs() << "cannot enable Arm non-uniform workgroup extension support "
913 "and assume uniform workgroup sizes\n";
914 return -1;
915 }
916
Romaric Jodine40f67d2022-01-18 16:45:08 +0100917 if (clspv::Option::Vec3ToVec4() ==
918 clspv::Option::Vec3ToVec4SupportClass::vec3ToVec4SupportError) {
919 llvm::errs() << "error: -vec3-to-vec4 and -no-vec3-to-vec4 are exclusive "
920 "so they cannot be used together!\n";
921 return -1;
922 }
923
Kévin Petitd5db2d22019-04-04 13:55:14 +0100924 return 0;
925}
Diego Novillo89500852019-04-15 08:45:10 -0400926
alan-baker57ce1c22022-04-26 19:10:44 -0400927int GenerateIRFile(llvm::Module &module, std::string output) {
Diego Novillo89500852019-04-15 08:45:10 -0400928 std::error_code ec;
929 std::unique_ptr<llvm::ToolOutputFile> out(
Natalie Chouinard058da872021-06-17 12:32:47 -0400930 new llvm::ToolOutputFile(output, ec, llvm::sys::fs::OF_None));
Diego Novillo89500852019-04-15 08:45:10 -0400931 if (ec) {
932 llvm::errs() << output << ": " << ec.message() << '\n';
933 return -1;
934 }
alan-baker57ce1c22022-04-26 19:10:44 -0400935
936 llvm::ModuleAnalysisManager mam;
937 llvm::ModulePassManager pm;
938 llvm::PassBuilder pb;
939 pb.registerModuleAnalyses(mam);
940 pm.addPass(llvm::PrintModulePass(out->os(), "", false));
941 pm.run(module, mam);
Diego Novillo89500852019-04-15 08:45:10 -0400942 out->keep();
943 return 0;
944}
945
alan-baker869cd682021-03-05 11:21:19 -0500946bool LinkBuiltinLibrary(llvm::Module *module) {
947 std::unique_ptr<llvm::MemoryBuffer> buffer(new OpenCLBuiltinMemoryBuffer(
948 clspv_builtin_library_data, clspv_builtin_library_size - 1));
949
950 llvm::SMDiagnostic Err;
951 auto library = llvm::parseIR(*buffer, Err, module->getContext());
952 if (!library) {
953 llvm::errs() << "Failed to parse builtins library\n";
954 return false;
955 }
956
957 // TODO: when clang generates builtins using the generic address space,
958 // different builtins are used for pointer-based builtins. Need to do some
959 // work to ensure they are kept around.
960 // Affects: modf, remquo, lgamma_r, frexp
961
962 llvm::Linker L(*module);
963 L.linkInModule(std::move(library), 0);
964
965 return true;
966}
967
Kévin Petitd5db2d22019-04-04 13:55:14 +0100968} // namespace
969
970namespace clspv {
Ryan Senanayake6917fb12022-02-28 18:17:02 -0500971int Compile(const llvm::StringRef &input_filename, const std::string &program,
972 const std::string &sampler_map,
973 std::vector<uint32_t> *output_binary, std::string *output_log) {
alan-bakerfec0a472018-11-08 18:09:40 -0500974 llvm::SmallVector<std::pair<unsigned, std::string>, 8> SamplerMapEntries;
Ryan Senanayake6917fb12022-02-28 18:17:02 -0500975 if (auto error = ParseSamplerMap(sampler_map, &SamplerMapEntries))
alan-bakerfec0a472018-11-08 18:09:40 -0500976 return error;
977
Ryan Senanayake6917fb12022-02-28 18:17:02 -0500978 llvm::StringRef overiddenInputFilename = input_filename;
alan-bakerfec0a472018-11-08 18:09:40 -0500979
980 clang::CompilerInstance instance;
Kévin Petitddad8f42019-09-30 15:12:08 +0100981 clang::FrontendInputFile kernelFile(overiddenInputFilename,
982 clang::InputKind(InputLanguage));
alan-bakerfec0a472018-11-08 18:09:40 -0500983 std::string log;
984 llvm::raw_string_ostream diagnosticsStream(log);
Ryan Senanayake6917fb12022-02-28 18:17:02 -0500985 std::unique_ptr<llvm::MemoryBuffer> file_memory_buffer;
alan-bakerf5e5f692018-11-27 08:33:24 -0500986 if (auto error = SetCompilerInstanceOptions(
Ryan Senanayake6917fb12022-02-28 18:17:02 -0500987 instance, overiddenInputFilename, kernelFile, program,
988 file_memory_buffer, &diagnosticsStream))
alan-bakerfec0a472018-11-08 18:09:40 -0500989 return error;
990
991 // Parse.
992 llvm::LLVMContext context;
993 clang::EmitLLVMOnlyAction action(&context);
994
995 // Prepare the action for processing kernelFile
996 const bool success = action.BeginSourceFile(instance, kernelFile);
997 if (!success) {
998 return -1;
999 }
1000
alan-bakerf3bce4a2019-06-28 16:01:15 -04001001 auto result = action.Execute();
alan-bakerfec0a472018-11-08 18:09:40 -05001002 action.EndSourceFile();
1003
1004 clang::DiagnosticConsumer *const consumer =
1005 instance.getDiagnostics().getClient();
1006 consumer->finish();
1007
Kévin Petit6b07cbe2019-04-02 21:52:16 +01001008 auto num_warnings = consumer->getNumWarnings();
alan-bakerfec0a472018-11-08 18:09:40 -05001009 auto num_errors = consumer->getNumErrors();
Ryan Senanayake6917fb12022-02-28 18:17:02 -05001010 if (output_log != nullptr) {
1011 *output_log = log;
1012 } else if ((num_errors > 0) || (num_warnings > 0)) {
Kévin Petit6b07cbe2019-04-02 21:52:16 +01001013 llvm::errs() << log;
1014 }
alan-bakerf3bce4a2019-06-28 16:01:15 -04001015 if (result || num_errors > 0) {
alan-bakerfec0a472018-11-08 18:09:40 -05001016 return -1;
1017 }
1018
Kévin Petit6b07cbe2019-04-02 21:52:16 +01001019 // Don't run the passes or produce any output in verify mode.
1020 // Clang doesn't always produce a valid module.
1021 if (verify) {
1022 return 0;
1023 }
1024
alan-bakerfec0a472018-11-08 18:09:40 -05001025 std::unique_ptr<llvm::Module> module(action.takeModule());
1026
1027 // Optimize.
1028 // Create a memory buffer for temporarily writing the result.
1029 SmallVector<char, 10000> binary;
1030 llvm::raw_svector_ostream binaryStream(binary);
Diego Novillo89500852019-04-15 08:45:10 -04001031
1032 // If --emit-ir was requested, emit the initial LLVM IR and stop compilation.
1033 if (!IROutputFile.empty()) {
alan-baker57ce1c22022-04-26 19:10:44 -04001034 return GenerateIRFile(*module, IROutputFile);
Diego Novillo89500852019-04-15 08:45:10 -04001035 }
1036
alan-baker869cd682021-03-05 11:21:19 -05001037 if (!LinkBuiltinLibrary(module.get())) {
1038 return -1;
1039 }
1040
alan-baker57ce1c22022-04-26 19:10:44 -04001041 // Run the passes to produce SPIR-V.
1042 if (RunPassPipeline(*module, &binaryStream) != 0) {
1043 return -1;
1044 }
alan-bakerfec0a472018-11-08 18:09:40 -05001045
alan-bakerfec0a472018-11-08 18:09:40 -05001046 // Write the resulting binary.
1047 // Wait until now to try writing the file so that we only write it on
1048 // successful compilation.
Ryan Senanayake6917fb12022-02-28 18:17:02 -05001049 if (output_binary) {
1050 output_binary->resize(binary.size() / 4);
1051 memcpy(output_binary->data(), binary.data(), binary.size());
1052 }
1053
1054 if (!OutputFilename.empty()) {
1055 std::error_code error;
1056 llvm::raw_fd_ostream outStream(OutputFilename, error,
1057 llvm::sys::fs::FA_Write);
1058
1059 if (error) {
1060 llvm::errs() << "Unable to open output file '" << OutputFilename
1061 << "': " << error.message() << '\n';
1062 return -1;
1063 }
1064 outStream << binaryStream.str();
1065 }
1066
1067 return 0;
1068}
1069
1070int Compile(const int argc, const char *const argv[]) {
1071 if (auto error = ParseOptions(argc, argv))
1072 return error;
1073
1074 // if no input file was provided, use a default
1075 llvm::StringRef overiddenInputFilename = InputFilename.getValue();
1076
1077 // If we are reading our input file from stdin.
1078 if ("-" == InputFilename) {
1079 // We need to overwrite the file name we use.
1080 switch (InputLanguage) {
1081 case clang::Language::OpenCL:
1082 overiddenInputFilename = "stdin.cl";
1083 break;
1084 case clang::Language::LLVM_IR:
1085 overiddenInputFilename = "stdin.ll";
1086 break;
1087 default:
1088 // Default to fix compiler warnings/errors. Option parsing will reject a
1089 // bad enum value for the option so there is no need for a message.
1090 return -1;
1091 }
1092 }
1093
alan-bakerfec0a472018-11-08 18:09:40 -05001094 if (OutputFilename.empty()) {
Kévin Petite4786902019-04-02 21:51:47 +01001095 if (OutputFormat == "c") {
alan-bakerfec0a472018-11-08 18:09:40 -05001096 OutputFilename = "a.spvinc";
1097 } else {
1098 OutputFilename = "a.spv";
1099 }
1100 }
alan-bakerfec0a472018-11-08 18:09:40 -05001101
Ryan Senanayake6917fb12022-02-28 18:17:02 -05001102 return Compile(overiddenInputFilename, "", "", nullptr, nullptr);
alan-bakerfec0a472018-11-08 18:09:40 -05001103}
alan-bakerf5e5f692018-11-27 08:33:24 -05001104
alan-baker86ce19c2020-08-05 13:09:19 -04001105int CompileFromSourceString(const std::string &program,
1106 const std::string &sampler_map,
1107 const std::string &options,
Kévin Petit899162d2020-09-08 19:16:08 +01001108 std::vector<uint32_t> *output_binary,
1109 std::string *output_log) {
alan-bakerf5e5f692018-11-27 08:33:24 -05001110
1111 llvm::SmallVector<const char *, 20> argv;
1112 llvm::BumpPtrAllocator A;
1113 llvm::StringSaver Saver(A);
1114 argv.push_back(Saver.save("clspv").data());
1115 llvm::cl::TokenizeGNUCommandLine(options, Saver, argv);
1116 int argc = static_cast<int>(argv.size());
Kévin Petitd5db2d22019-04-04 13:55:14 +01001117
1118 if (auto error = ParseOptions(argc, &argv[0]))
1119 return error;
alan-bakerf5e5f692018-11-27 08:33:24 -05001120
Ryan Senanayake6917fb12022-02-28 18:17:02 -05001121 return Compile("source", program, sampler_map, output_binary, output_log);
alan-bakerf5e5f692018-11-27 08:33:24 -05001122}
alan-bakerfec0a472018-11-08 18:09:40 -05001123} // namespace clspv