1 // 2 // Copyright 2012-2016 Francisco Jerez 3 // Copyright 2012-2016 Advanced Micro Devices, Inc. 4 // Copyright 2014-2016 Jan Vesely 5 // Copyright 2014-2015 Serge Martin 6 // Copyright 2015 Zoltan Gilian 7 // 8 // Permission is hereby granted, free of charge, to any person obtaining a 9 // copy of this software and associated documentation files (the "Software"), 10 // to deal in the Software without restriction, including without limitation 11 // the rights to use, copy, modify, merge, publish, distribute, sublicense, 12 // and/or sell copies of the Software, and to permit persons to whom the 13 // Software is furnished to do so, subject to the following conditions: 14 // 15 // The above copyright notice and this permission notice shall be included in 16 // all copies or substantial portions of the Software. 17 // 18 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 19 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 20 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 21 // THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR 22 // OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 23 // ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 24 // OTHER DEALINGS IN THE SOFTWARE. 25 // 26 27 #include <llvm/IR/DiagnosticPrinter.h> 28 #include <llvm/IR/DiagnosticInfo.h> 29 #include <llvm/IR/LLVMContext.h> 30 #include <llvm/IR/Module.h> 31 #include <llvm/Support/raw_ostream.h> 32 #include <llvm/Transforms/IPO/Internalize.h> 33 #include <llvm-c/Target.h> 34 #ifdef HAVE_CLOVER_SPIRV 35 #include <LLVMSPIRVLib/LLVMSPIRVLib.h> 36 #endif 37 38 #include <llvm-c/TargetMachine.h> 39 #include <llvm-c/Transforms/PassBuilder.h> 40 #include <llvm/Support/CBindingWrapping.h> 41 #include <clang/CodeGen/CodeGenAction.h> 42 #include <clang/Lex/PreprocessorOptions.h> 43 #include <clang/Frontend/TextDiagnosticBuffer.h> 44 #include <clang/Frontend/TextDiagnosticPrinter.h> 45 #include <clang/Basic/TargetInfo.h> 46 47 // We need to include internal headers last, because the internal headers 48 // include CL headers which have #define's like: 49 // 50 //#define cl_khr_gl_sharing 1 51 //#define cl_khr_icd 1 52 // 53 // Which will break the compilation of clang/Basic/OpenCLOptions.h 54 55 #include "core/error.hpp" 56 #include "llvm/codegen.hpp" 57 #include "llvm/compat.hpp" 58 #include "llvm/invocation.hpp" 59 #include "llvm/metadata.hpp" 60 #include "llvm/util.hpp" 61 #ifdef HAVE_CLOVER_SPIRV 62 #include "spirv/invocation.hpp" 63 #endif 64 #include "util/algorithm.hpp" 65 66 67 using clover::binary; 68 using clover::device; 69 using clover::build_error; 70 using clover::invalid_build_options_error; 71 using clover::map; 72 using clover::header_map; 73 using namespace clover::llvm; 74 75 using ::llvm::Function; 76 using ::llvm::LLVMContext; 77 using ::llvm::Module; 78 using ::llvm::raw_string_ostream; 79 80 namespace { 81 82 static const cl_version ANY_VERSION = CL_MAKE_VERSION(9, 9, 9); 83 const cl_version cl_versions[] = { 84 CL_MAKE_VERSION(1, 1, 0), 85 CL_MAKE_VERSION(1, 2, 0), 86 CL_MAKE_VERSION(2, 0, 0), 87 CL_MAKE_VERSION(2, 1, 0), 88 CL_MAKE_VERSION(2, 2, 0), 89 CL_MAKE_VERSION(3, 0, 0), 90 }; 91 92 struct clc_version_lang_std { 93 cl_version version_number; // CLC Version 94 clang::LangStandard::Kind clc_lang_standard; 95 }; 96 97 const clc_version_lang_std cl_version_lang_stds[] = { 98 { CL_MAKE_VERSION(1, 0, 0), clang::LangStandard::lang_opencl10}, 99 { CL_MAKE_VERSION(1, 1, 0), clang::LangStandard::lang_opencl11}, 100 { CL_MAKE_VERSION(1, 2, 0), clang::LangStandard::lang_opencl12}, 101 { CL_MAKE_VERSION(2, 0, 0), clang::LangStandard::lang_opencl20}, 102 #if LLVM_VERSION_MAJOR >= 12 103 { CL_MAKE_VERSION(3, 0, 0), clang::LangStandard::lang_opencl30}, 104 #endif 105 }; 106 107 bool are_equal(cl_version_khr version1,cl_version_khr version2,bool ignore_patch_version=false)108 are_equal(cl_version_khr version1, cl_version_khr version2, 109 bool ignore_patch_version = false) { 110 if (ignore_patch_version) { 111 version1 &= ~CL_VERSION_PATCH_MASK_KHR; 112 version2 &= ~CL_VERSION_PATCH_MASK_KHR; 113 } 114 return version1 == version2; 115 } 116 117 void init_targets()118 init_targets() { 119 static bool targets_initialized = false; 120 if (!targets_initialized) { 121 LLVMInitializeAllTargets(); 122 LLVMInitializeAllTargetInfos(); 123 LLVMInitializeAllTargetMCs(); 124 LLVMInitializeAllAsmParsers(); 125 LLVMInitializeAllAsmPrinters(); 126 targets_initialized = true; 127 } 128 } 129 130 void 131 #if LLVM_VERSION_MAJOR >= 19 diagnostic_handler(const::llvm::DiagnosticInfo * di,void * data)132 diagnostic_handler(const ::llvm::DiagnosticInfo *di, void *data) { 133 if (di->getSeverity() == ::llvm::DS_Error) { 134 #else 135 diagnostic_handler(const ::llvm::DiagnosticInfo &di, void *data) { 136 if (di.getSeverity() == ::llvm::DS_Error) { 137 #endif 138 raw_string_ostream os { *reinterpret_cast<std::string *>(data) }; 139 ::llvm::DiagnosticPrinterRawOStream printer { os }; 140 #if LLVM_VERSION_MAJOR >= 19 141 di->print(printer); 142 #else 143 di.print(printer); 144 #endif 145 throw build_error(); 146 } 147 } 148 149 std::unique_ptr<LLVMContext> 150 create_context(std::string &r_log) { 151 init_targets(); 152 std::unique_ptr<LLVMContext> ctx { new LLVMContext }; 153 154 ctx->setDiagnosticHandlerCallBack(diagnostic_handler, &r_log); 155 return ctx; 156 } 157 158 const struct clc_version_lang_std& 159 get_cl_lang_standard(unsigned requested, unsigned max = ANY_VERSION) { 160 for (const struct clc_version_lang_std &version : cl_version_lang_stds) { 161 if (version.version_number == max || 162 version.version_number == requested) { 163 return version; 164 } 165 } 166 throw build_error("Unknown/Unsupported language version"); 167 } 168 169 const cl_version 170 get_cl_version(cl_version requested, 171 cl_version max = ANY_VERSION) { 172 for (const auto &version : cl_versions) { 173 if (are_equal(version, max, true) || 174 are_equal(version, requested, true)) { 175 return version; 176 } 177 } 178 throw build_error("Unknown/Unsupported language version"); 179 } 180 181 clang::LangStandard::Kind 182 get_lang_standard_from_version(const cl_version input_version, 183 bool is_build_opt = false) { 184 185 //Per CL 2.0 spec, section 5.8.4.5: 186 // If it's an option, use the value directly. 187 // If it's a device version, clamp to max 1.x version, a.k.a. 1.2 188 const cl_version version = 189 get_cl_version(input_version, is_build_opt ? ANY_VERSION : 120); 190 191 const struct clc_version_lang_std standard = 192 get_cl_lang_standard(version); 193 194 return standard.clc_lang_standard; 195 } 196 197 clang::LangStandard::Kind 198 get_language_version(const std::vector<std::string> &opts, 199 const cl_version device_version) { 200 201 const std::string search = "-cl-std=CL"; 202 203 for (auto &opt: opts) { 204 auto pos = opt.find(search); 205 if (pos == 0){ 206 std::stringstream ver_str(opt.substr(pos + search.size())); 207 unsigned int ver_major = 0; 208 char separator = '\0'; 209 unsigned int ver_minor = 0; 210 ver_str >> ver_major >> separator >> ver_minor; 211 if (ver_str.fail() || ver_str.bad() || !ver_str.eof() || 212 separator != '.') { 213 throw build_error(); 214 } 215 const auto ver = CL_MAKE_VERSION_KHR(ver_major, ver_minor, 0); 216 const auto device_ver = get_cl_version(device_version); 217 const auto requested = get_cl_version(ver); 218 if (requested > device_ver) { 219 throw build_error(); 220 } 221 return get_lang_standard_from_version(ver, true); 222 } 223 } 224 225 return get_lang_standard_from_version(device_version); 226 } 227 228 std::unique_ptr<clang::CompilerInstance> 229 create_compiler_instance(const device &dev, const std::string& ir_target, 230 const std::vector<std::string> &opts, 231 std::string &r_log) { 232 std::unique_ptr<clang::CompilerInstance> c { new clang::CompilerInstance }; 233 clang::TextDiagnosticBuffer *diag_buffer = new clang::TextDiagnosticBuffer; 234 clang::DiagnosticsEngine diag { new clang::DiagnosticIDs, 235 new clang::DiagnosticOptions, diag_buffer }; 236 237 // Parse the compiler options. A file name should be present at the end 238 // and must have the .cl extension in order for the CompilerInvocation 239 // class to recognize it as an OpenCL source file. 240 #if LLVM_VERSION_MAJOR >= 12 241 std::vector<const char *> copts; 242 #if LLVM_VERSION_MAJOR == 15 || LLVM_VERSION_MAJOR == 16 243 // Before LLVM commit 702d5de4 opaque pointers were supported but not enabled 244 // by default when building LLVM. They were made default in commit 702d5de4. 245 // LLVM commit d69e9f9d introduced -opaque-pointers/-no-opaque-pointers cc1 246 // options to enable or disable them whatever the LLVM default is. 247 248 // Those two commits follow llvmorg-15-init and precede llvmorg-15.0.0-rc1 tags. 249 250 // Since LLVM commit d785a8ea, the CLANG_ENABLE_OPAQUE_POINTERS build option of 251 // LLVM is removed, meaning there is no way to build LLVM with opaque pointers 252 // enabled by default. 253 // It was said at the time it was still possible to explicitly disable opaque 254 // pointers via cc1 -no-opaque-pointers option, but it is known a later commit 255 // broke backward compatibility provided by -no-opaque-pointers as verified with 256 // arbitrary commit d7d586e5, so there is no way to use opaque pointers starting 257 // with LLVM 16. 258 259 // Those two commits follow llvmorg-16-init and precede llvmorg-16.0.0-rc1 tags. 260 261 // Since Mesa commit 977dbfc9 opaque pointers are properly implemented in Clover 262 // and used. 263 264 // If we don't pass -opaque-pointers to Clang on LLVM versions supporting opaque 265 // pointers but disabling them by default, there will be an API mismatch between 266 // Mesa and LLVM and Clover will not work. 267 copts.push_back("-opaque-pointers"); 268 #endif 269 for (auto &opt : opts) { 270 if (opt == "-cl-denorms-are-zero") 271 copts.push_back("-fdenormal-fp-math=positive-zero"); 272 else 273 copts.push_back(opt.c_str()); 274 } 275 #else 276 const std::vector<const char *> copts = 277 map(std::mem_fn(&std::string::c_str), opts); 278 #endif 279 280 const target &target = ir_target; 281 const cl_version device_clc_version = dev.device_clc_version(); 282 283 if (!compat::create_compiler_invocation_from_args( 284 c->getInvocation(), copts, diag)) 285 throw invalid_build_options_error(); 286 287 diag_buffer->FlushDiagnostics(diag); 288 if (diag.hasErrorOccurred()) 289 throw invalid_build_options_error(); 290 291 c->getTargetOpts().CPU = target.cpu; 292 c->getTargetOpts().Triple = target.triple; 293 c->getLangOpts().NoBuiltin = true; 294 295 #if LLVM_VERSION_MAJOR >= 13 296 c->getTargetOpts().OpenCLExtensionsAsWritten.push_back("-__opencl_c_generic_address_space"); 297 c->getTargetOpts().OpenCLExtensionsAsWritten.push_back("-__opencl_c_pipes"); 298 c->getTargetOpts().OpenCLExtensionsAsWritten.push_back("-__opencl_c_device_enqueue"); 299 c->getTargetOpts().OpenCLExtensionsAsWritten.push_back("-__opencl_c_program_scope_global_variables"); 300 c->getTargetOpts().OpenCLExtensionsAsWritten.push_back("-__opencl_c_subgroups"); 301 c->getTargetOpts().OpenCLExtensionsAsWritten.push_back("-__opencl_c_work_group_collective_functions"); 302 c->getTargetOpts().OpenCLExtensionsAsWritten.push_back("-__opencl_c_atomic_scope_device"); 303 c->getTargetOpts().OpenCLExtensionsAsWritten.push_back("-__opencl_c_atomic_order_seq_cst"); 304 #endif 305 306 // This is a workaround for a Clang bug which causes the number 307 // of warnings and errors to be printed to stderr. 308 // http://www.llvm.org/bugs/show_bug.cgi?id=19735 309 c->getDiagnosticOpts().ShowCarets = false; 310 311 compat::compiler_set_lang_defaults(c, compat::ik_opencl, 312 ::llvm::Triple(target.triple), 313 get_language_version(opts, device_clc_version)); 314 315 c->createDiagnostics(new clang::TextDiagnosticPrinter( 316 *new raw_string_ostream(r_log), 317 &c->getDiagnosticOpts(), true)); 318 319 c->setTarget(clang::TargetInfo::CreateTargetInfo( 320 c->getDiagnostics(), c->getInvocation().TargetOpts)); 321 322 return c; 323 } 324 325 std::unique_ptr<Module> 326 compile(LLVMContext &ctx, clang::CompilerInstance &c, 327 const std::string &name, const std::string &source, 328 const header_map &headers, const device &dev, 329 const std::string &opts, bool use_libclc, std::string &r_log) { 330 c.getFrontendOpts().ProgramAction = clang::frontend::EmitLLVMOnly; 331 c.getHeaderSearchOpts().UseBuiltinIncludes = true; 332 c.getHeaderSearchOpts().UseStandardSystemIncludes = true; 333 c.getHeaderSearchOpts().ResourceDir = CLANG_RESOURCE_DIR; 334 335 if (use_libclc) { 336 // Add libclc generic search path 337 c.getHeaderSearchOpts().AddPath(LIBCLC_INCLUDEDIR, 338 clang::frontend::Angled, 339 false, false); 340 341 // Add libclc include 342 c.getPreprocessorOpts().Includes.push_back("clc/clc.h"); 343 } else { 344 // Add opencl-c generic search path 345 c.getHeaderSearchOpts().AddPath(CLANG_RESOURCE_DIR, 346 clang::frontend::Angled, 347 false, false); 348 349 // Add opencl include 350 c.getPreprocessorOpts().Includes.push_back("opencl-c.h"); 351 } 352 353 // Add definition for the OpenCL version 354 const auto dev_version = dev.device_version(); 355 c.getPreprocessorOpts().addMacroDef("__OPENCL_VERSION__=" + 356 std::to_string(CL_VERSION_MAJOR_KHR(dev_version)) + 357 std::to_string(CL_VERSION_MINOR_KHR(dev_version)) + "0"); 358 359 if (CL_VERSION_MAJOR(dev.version) >= 3) { 360 const auto features = dev.opencl_c_features(); 361 for (const auto &feature : features) 362 c.getPreprocessorOpts().addMacroDef(feature.name); 363 } 364 365 // clc.h requires that this macro be defined: 366 c.getPreprocessorOpts().addMacroDef("cl_clang_storage_class_specifiers"); 367 c.getPreprocessorOpts().addRemappedFile( 368 name, ::llvm::MemoryBuffer::getMemBuffer(source).release()); 369 370 if (headers.size()) { 371 const std::string tmp_header_path = "/tmp/clover/"; 372 373 c.getHeaderSearchOpts().AddPath(tmp_header_path, 374 clang::frontend::Angled, 375 false, false); 376 377 for (const auto &header : headers) 378 c.getPreprocessorOpts().addRemappedFile( 379 tmp_header_path + header.first, 380 ::llvm::MemoryBuffer::getMemBuffer(header.second).release()); 381 } 382 383 // Tell clang to link this file before performing any 384 // optimizations. This is required so that we can replace calls 385 // to the OpenCL C barrier() builtin with calls to target 386 // intrinsics that have the noduplicate attribute. This 387 // attribute will prevent Clang from creating illegal uses of 388 // barrier() (e.g. Moving barrier() inside a conditional that is 389 // no executed by all threads) during its optimizaton passes. 390 if (use_libclc) { 391 clang::CodeGenOptions::BitcodeFileToLink F; 392 393 F.Filename = LIBCLC_LIBEXECDIR + dev.ir_target() + ".bc"; 394 F.PropagateAttrs = true; 395 F.LinkFlags = ::llvm::Linker::Flags::None; 396 c.getCodeGenOpts().LinkBitcodeFiles.emplace_back(F); 397 } 398 399 // undefine __IMAGE_SUPPORT__ for device without image support 400 if (!dev.image_support()) 401 c.getPreprocessorOpts().addMacroUndef("__IMAGE_SUPPORT__"); 402 403 // Compile the code 404 clang::EmitLLVMOnlyAction act(&ctx); 405 if (!c.ExecuteAction(act)) 406 throw build_error(); 407 408 return act.takeModule(); 409 } 410 411 #ifdef HAVE_CLOVER_SPIRV 412 SPIRV::TranslatorOpts 413 get_spirv_translator_options(const device &dev) { 414 const auto supported_versions = clover::spirv::supported_versions(); 415 const auto max_supported = clover::spirv::to_spirv_version_encoding(supported_versions.back().version); 416 const auto maximum_spirv_version = 417 std::min(static_cast<SPIRV::VersionNumber>(max_supported), 418 SPIRV::VersionNumber::MaximumVersion); 419 420 SPIRV::TranslatorOpts::ExtensionsStatusMap spirv_extensions; 421 for (auto &ext : clover::spirv::supported_extensions()) { 422 #define EXT(X) if (ext == #X) spirv_extensions.insert({ SPIRV::ExtensionID::X, true }); 423 #include <LLVMSPIRVLib/LLVMSPIRVExtensions.inc> 424 #undef EXT 425 } 426 427 auto translator_opts = SPIRV::TranslatorOpts(maximum_spirv_version, spirv_extensions); 428 #if LLVM_VERSION_MAJOR >= 13 429 translator_opts.setPreserveOCLKernelArgTypeMetadataThroughString(true); 430 #endif 431 return translator_opts; 432 } 433 #endif 434 } 435 436 binary 437 clover::llvm::compile_program(const std::string &source, 438 const header_map &headers, 439 const device &dev, 440 const std::string &opts, 441 std::string &r_log) { 442 if (has_flag(debug::clc)) 443 debug::log(".cl", "// Options: " + opts + '\n' + source); 444 445 auto ctx = create_context(r_log); 446 auto c = create_compiler_instance(dev, dev.ir_target(), 447 tokenize(opts + " input.cl"), r_log); 448 auto mod = compile(*ctx, *c, "input.cl", source, headers, dev, opts, true, 449 r_log); 450 451 if (has_flag(debug::llvm)) 452 debug::log(".ll", print_module_bitcode(*mod)); 453 454 return build_module_library(*mod, binary::section::text_intermediate); 455 } 456 457 namespace { 458 void 459 optimize(Module &mod, 460 const std::string& ir_target, 461 unsigned optimization_level, 462 bool internalize_symbols) { 463 // By default, the function internalizer pass will look for a function 464 // called "main" and then mark all other functions as internal. Marking 465 // functions as internal enables the optimizer to perform optimizations 466 // like function inlining and global dead-code elimination. 467 // 468 // When there is no "main" function in a binary, the internalize pass will 469 // treat the binary like a library, and it won't internalize any functions. 470 // Since there is no "main" function in our kernels, we need to tell 471 // the internalizer pass that this binary is not a library by passing a 472 // list of kernel functions to the internalizer. The internalizer will 473 // treat the functions in the list as "main" functions and internalize 474 // all of the other functions. 475 if (internalize_symbols) { 476 std::vector<std::string> names = 477 map(std::mem_fn(&Function::getName), get_kernels(mod)); 478 internalizeModule(mod, 479 [=](const ::llvm::GlobalValue &gv) { 480 return std::find(names.begin(), names.end(), 481 gv.getName()) != names.end(); 482 }); 483 } 484 485 486 const char *opt_str = NULL; 487 LLVMCodeGenOptLevel level; 488 switch (optimization_level) { 489 case 0: 490 default: 491 opt_str = "default<O0>"; 492 level = LLVMCodeGenLevelNone; 493 break; 494 case 1: 495 opt_str = "default<O1>"; 496 level = LLVMCodeGenLevelLess; 497 break; 498 case 2: 499 opt_str = "default<O2>"; 500 level = LLVMCodeGenLevelDefault; 501 break; 502 case 3: 503 opt_str = "default<O3>"; 504 level = LLVMCodeGenLevelAggressive; 505 break; 506 } 507 508 const target &target = ir_target; 509 LLVMTargetRef targ; 510 char *err_message; 511 512 if (LLVMGetTargetFromTriple(target.triple.c_str(), &targ, &err_message)) 513 return; 514 LLVMTargetMachineRef tm = 515 LLVMCreateTargetMachine(targ, target.triple.c_str(), 516 target.cpu.c_str(), "", level, 517 LLVMRelocDefault, LLVMCodeModelDefault); 518 519 if (!tm) 520 return; 521 LLVMPassBuilderOptionsRef opts = LLVMCreatePassBuilderOptions(); 522 LLVMRunPasses(wrap(&mod), opt_str, tm, opts); 523 524 LLVMDisposeTargetMachine(tm); 525 LLVMDisposePassBuilderOptions(opts); 526 } 527 528 std::unique_ptr<Module> 529 link(LLVMContext &ctx, const clang::CompilerInstance &c, 530 const std::vector<binary> &binaries, std::string &r_log) { 531 std::unique_ptr<Module> mod { new Module("link", ctx) }; 532 std::unique_ptr< ::llvm::Linker> linker { new ::llvm::Linker(*mod) }; 533 534 for (auto &b : binaries) { 535 if (linker->linkInModule(parse_module_library(b, ctx, r_log))) 536 throw build_error(); 537 } 538 539 return mod; 540 } 541 } 542 543 binary 544 clover::llvm::link_program(const std::vector<binary> &binaries, 545 const device &dev, const std::string &opts, 546 std::string &r_log) { 547 std::vector<std::string> options = tokenize(opts + " input.cl"); 548 const bool create_library = count("-create-library", options); 549 erase_if(equals("-create-library"), options); 550 551 auto ctx = create_context(r_log); 552 auto c = create_compiler_instance(dev, dev.ir_target(), options, r_log); 553 auto mod = link(*ctx, *c, binaries, r_log); 554 555 optimize(*mod, dev.ir_target(), c->getCodeGenOpts().OptimizationLevel, !create_library); 556 557 static std::atomic_uint seq(0); 558 const std::string id = "." + mod->getModuleIdentifier() + "-" + 559 std::to_string(seq++); 560 561 if (has_flag(debug::llvm)) 562 debug::log(id + ".ll", print_module_bitcode(*mod)); 563 564 if (create_library) { 565 return build_module_library(*mod, binary::section::text_library); 566 567 } else if (dev.ir_format() == PIPE_SHADER_IR_NATIVE) { 568 if (has_flag(debug::native)) 569 debug::log(id + ".asm", print_module_native(*mod, dev.ir_target())); 570 571 return build_module_native(*mod, dev.ir_target(), *c, r_log); 572 573 } else { 574 unreachable("Unsupported IR."); 575 } 576 } 577 578 #ifdef HAVE_CLOVER_SPIRV 579 binary 580 clover::llvm::compile_to_spirv(const std::string &source, 581 const header_map &headers, 582 const device &dev, 583 const std::string &opts, 584 std::string &r_log) { 585 if (has_flag(debug::clc)) 586 debug::log(".cl", "// Options: " + opts + '\n' + source); 587 588 auto ctx = create_context(r_log); 589 const std::string target = dev.address_bits() == 32u ? 590 "-spir-unknown-unknown" : 591 "-spir64-unknown-unknown"; 592 auto c = create_compiler_instance(dev, target, 593 tokenize(opts + " -O0 -fgnu89-inline input.cl"), r_log); 594 auto mod = compile(*ctx, *c, "input.cl", source, headers, dev, opts, false, 595 r_log); 596 597 if (has_flag(debug::llvm)) 598 debug::log(".ll", print_module_bitcode(*mod)); 599 600 const auto spirv_options = get_spirv_translator_options(dev); 601 602 std::string error_msg; 603 std::ostringstream os; 604 if (!::llvm::writeSpirv(mod.get(), spirv_options, os, error_msg)) { 605 r_log += "Translation from LLVM IR to SPIR-V failed: " + error_msg + ".\n"; 606 throw error(CL_INVALID_VALUE); 607 } 608 609 const std::string osContent = os.str(); 610 std::string binary(osContent.begin(), osContent.end()); 611 if (binary.empty()) { 612 r_log += "Failed to retrieve SPIR-V binary.\n"; 613 throw error(CL_INVALID_VALUE); 614 } 615 616 if (has_flag(debug::spirv)) 617 debug::log(".spvasm", spirv::print_module(binary, dev.device_version())); 618 619 return spirv::compile_program(binary, dev, r_log); 620 } 621 #endif 622