╭─────────────╮ │scroll to top│ ╰─────────────╯ ╭ zig_llvm.cpp ─────────────────────────────────────────────────╮ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ ╰───────────────────────────────────────────────────────────────╯
╭ find file ─ ─ ─ ─ ─ ─ ─ ─ ─ ─╮ ╭────╮ ╭ clone ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ╮ │ │ │http│ ssh │ │ ╰ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─╯ ╰────╯ ╰ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ╯
258 259 std::unique_ptr<raw_fd_ostream> dest_asm(dest_asm_ptr), 260 dest_bin(dest_bin_ptr), 261 dest_bitcode(dest_bitcode_ptr); 262 263 264 auto PID = sys::Process::getProcessId(); 265 std::string ProcName = "zig-"; 266 ProcName += std::to_string(PID); 267 TimeTracerRAII TimeTracer(ProcName, 268 options->bin_filename? options->bin_filename : options->asm_filename); 269 270 TargetMachine &target_machine = *reinterpret_cast<TargetMachine*>(targ_machine_ref); 271 272 if (options->allow_fast_isel) { 273 target_machine.setO0WantsFastISel(true); 274 } else { 275 target_machine.setFastISel(false); 276 } 277 278 if (!options->allow_machine_outliner) { 279 target_machine.setMachineOutliner(false); 280 } 281 282 Module &llvm_module = *unwrap(module_ref); 283 284 // Pipeline configurations 285 PipelineTuningOptions pipeline_opts; 286 pipeline_opts.LoopUnrolling = !options->is_debug; 287 pipeline_opts.SLPVectorization = !options->is_debug; 288 pipeline_opts.LoopVectorization = false; // https://github.com/llvm/llvm-project/issues/186922 289 pipeline_opts.LoopInterleaving = !options->is_debug; 290 pipeline_opts.MergeFunctions = !options->is_debug; 291 292 // Instrumentations 293 PassInstrumentationCallbacks instr_callbacks; 294 StandardInstrumentations std_instrumentations(llvm_module.getContext(), false); 295 std_instrumentations.registerCallbacks(instr_callbacks); 296 297 std::optional<PGOOptions> opt_pgo_options = {}; 298 PassBuilder pass_builder(&target_machine, pipeline_opts, 299 opt_pgo_options, &instr_callbacks); 300 301 LoopAnalysisManager loop_am; 302 FunctionAnalysisManager function_am; 303 CGSCCAnalysisManager cgscc_am; 304 ModuleAnalysisManager module_am; 305 306 // Register the AA manager first so that our version is the one used 307 function_am.registerPass([&] { 308 return pass_builder.buildDefaultAAPipeline(); 309 }); 310 311 Triple target_triple(llvm_module.getTargetTriple()); 312 auto tlii = std::make_unique<TargetLibraryInfoImpl>(target_triple); 313 function_am.registerPass([&] { return TargetLibraryAnalysis(*tlii); }); 314 315 // Initialize the AnalysisManagers 316 pass_builder.registerModuleAnalyses(module_am); 317 pass_builder.registerCGSCCAnalyses(cgscc_am); 318 pass_builder.registerFunctionAnalyses(function_am); 319 pass_builder.registerLoopAnalyses(loop_am); 320 pass_builder.crossRegisterProxies(loop_am, function_am, cgscc_am, module_am); 321 322 pass_builder.registerPipelineStartEPCallback([&](ModulePassManager &module_pm, OptimizationLevel level) { 323 // Verify the input 324 if (assertions_on) { 325 module_pm.addPass(VerifierPass()); 326 } 327 328 if (!options->is_debug) { 329 module_pm.addPass(createModuleToFunctionPassAdaptor(AddDiscriminatorsPass())); 330 } 331 }); 332 333 const bool early_san = options->is_debug; 334 335 pass_builder.registerOptimizerEarlyEPCallback([&](ModulePassManager &module_pm, OptimizationLevel level, ThinOrFullLTOPhase lto_phase) { 336 if (early_san) { 337 // Code coverage instrumentation. 338 if (options->sancov) { 339 module_pm.addPass(SanitizerCoveragePass(getSanCovOptions(options->coverage))); 340 } 341 342 // Thread sanitizer 343 if (options->tsan) { 344 module_pm.addPass(ModuleThreadSanitizerPass()); 345 module_pm.addPass(createModuleToFunctionPassAdaptor(ThreadSanitizerPass())); 346 } 347 } 348 }); 349 350 pass_builder.registerOptimizerLastEPCallback([&](ModulePassManager &module_pm, OptimizationLevel level, ThinOrFullLTOPhase lto_phase) { 351 if (!early_san) { 352 // Code coverage instrumentation. 353 if (options->sancov) { 354 module_pm.addPass(SanitizerCoveragePass(getSanCovOptions(options->coverage))); 355 } 356 357 // Thread sanitizer 358 if (options->tsan) { 359 module_pm.addPass(ModuleThreadSanitizerPass()); 360 module_pm.addPass(createModuleToFunctionPassAdaptor(ThreadSanitizerPass())); 361 } 362 } 363 364 // Verify the output 365 if (assertions_on) { 366 module_pm.addPass(VerifierPass()); 367 } 368 }); 369 370 ModulePassManager module_pm; 371 OptimizationLevel opt_level; 372 // Setting up the optimization level 373 if (options->is_debug) 374 opt_level = OptimizationLevel::O0; 375 else if (options->is_small) 376 opt_level = OptimizationLevel::Oz; 377 else 378 opt_level = OptimizationLevel::O3; 379 380 // Initialize the PassManager 381 if (opt_level == OptimizationLevel::O0) { 382 module_pm = pass_builder.buildO0DefaultPipeline(opt_level, static_cast<ThinOrFullLTOPhase>(options->lto)); 383 } else if (options->lto) { 384 module_pm = pass_builder.buildLTOPreLinkDefaultPipeline(opt_level); 385 } else { 386 module_pm = pass_builder.buildPerModuleDefaultPipeline(opt_level); 387 } 388 389 // Unfortunately we don't have new PM for code generation 390 legacy::PassManager codegen_pm; 391 codegen_pm.add( 392 createTargetTransformInfoWrapperPass(target_machine.getTargetIRAnalysis())); 393 394 if (dest_bin && !options->lto) { 395 if (target_machine.addPassesToEmitFile(codegen_pm, *dest_bin, nullptr, CodeGenFileType::ObjectFile)) { 396 *error_message = strdup("TargetMachine can't emit an object file"); 397 return true; 398 } 399 } 400 if (dest_asm) { 401 if (target_machine.addPassesToEmitFile(codegen_pm, *dest_asm, nullptr, CodeGenFileType::AssemblyFile)) { 402 *error_message = strdup("TargetMachine can't emit an assembly file"); 403 return true; 404 } 405 } 406 407 // Optimization phase 408 module_pm.run(llvm_module, module_am); 409 410 // Code generation phase 411 codegen_pm.run(llvm_module); 412 413 if (options->llvm_ir_filename) { 414 if (LLVMPrintModuleToFile(module_ref, options->llvm_ir_filename, error_message)) { 415 return true; 416 } 417 } 418 419 if (dest_bin && options->lto) { 420 WriteBitcodeToFile(llvm_module, *dest_bin); 421 } 422 if (dest_bitcode) { 423 WriteBitcodeToFile(llvm_module, *dest_bitcode); 424 } 425 426 // This must only happen once we know we've succeeded and will be returning `false`, because 427 // this code `malloc`s memory which will become owned by the caller (in Zig code). 428 if (options->time_report_out != nullptr) { 429 std::string out_str; 430 auto os = raw_string_ostream(out_str); 431 TimerGroup::printAll(os); 432 TimerGroup::clearAll(); 433 auto c_str = (char *)malloc(out_str.length() + 1); 434 strcpy(c_str, out_str.c_str()); 435 *options->time_report_out = c_str; 436 } 437 return false; 438 } 439 440 void ZigLLVMSetOptBisectLimit(LLVMContextRef context_ref, int limit) { 441 static OptBisect opt_bisect; 442 opt_bisect.setIntervals({0, limit}); 443 unwrap(context_ref)->setOptPassGate(opt_bisect); 444 } 445 446 struct ZigDiagnosticHandler : public DiagnosticHandler { 447 bool BrokenDebugInfo; 448 ZigDiagnosticHandler() : BrokenDebugInfo(false) {} 449 bool handleDiagnostics(const DiagnosticInfo &DI) override { 450 // This dyn_cast should be casting to DiagnosticInfoIgnoringInvalidDebugMetadata 451 // but DiagnosticInfoIgnoringInvalidDebugMetadata is treated as DiagnosticInfoDebugMetadataVersion 452 // because of a bug in LLVM (see https://github.com/ziglang/zig/issues/19161). 453 // After this is fixed add an additional check for DiagnosticInfoIgnoringInvalidDebugMetadata 454 // but don't remove the current one as both indicate that debug info is broken. 455 if (auto *Remark = dyn_cast<DiagnosticInfoDebugMetadataVersion>(&DI)) { 456 BrokenDebugInfo = true; 457 } 458 return false; 459 } 460 }; 461 462 void ZigLLVMEnableBrokenDebugInfoCheck(LLVMContextRef context_ref) { 463 unwrap(context_ref)->setDiagnosticHandler(std::make_unique<ZigDiagnosticHandler>()); 464 } 465 466 bool ZigLLVMGetBrokenDebugInfo(LLVMContextRef context_ref) { 467 return ((const ZigDiagnosticHandler*) 468 unwrap(context_ref)->getDiagHandlerPtr())->BrokenDebugInfo; 469 } 470 471 void ZigLLVMParseCommandLineOptions(size_t argc, const char *const *argv) { 472 cl::ParseCommandLineOptions(argc, argv); 473 } 474 475 bool ZigLLVMWriteArchive(const char *archive_name, const char **file_names, size_t file_name_count, 476 ZigLLVMArchiveKind archive_kind, size_t *err_file_index_out, char **err_msg_out) 477 { 478 SmallVector<NewArchiveMember, 4> new_members; 479 for (size_t i = 0; i < file_name_count; i += 1) { 480 Expected<NewArchiveMember> new_member = NewArchiveMember::getFile(file_names[i], true); 481 Error err = new_member.takeError(); 482 if (err) { 483 *err_file_index_out = i; 484 const std::string msg = toString(std::move(err)); 485 *err_msg_out = (char *)malloc(msg.length() + 1); 486 strcpy(*err_msg_out, msg.c_str()); 487 return true; 488 } 489 new_members.push_back(std::move(*new_member)); 490 } 491 Error err = writeArchive(archive_name, new_members, 492 SymtabWritingMode::NormalSymtab, static_cast<object::Archive::Kind>(archive_kind), true, false, nullptr); 493 494 if (err) { 495 *err_file_index_out = file_name_count; 496 const std::string msg = toString(std::move(err)); 497 *err_msg_out = (char *)malloc(msg.length() + 1); 498 strcpy(*err_msg_out, msg.c_str()); 499 return true; 500 } 501 502 return false; 503 } 504 505 // The header file in LLD 16 exposed these functions. As of 17 they are only 506 // exposed via a macro ("LLD_HAS_DRIVER") which I have copied and pasted the 507 // body of here so that you don't have to wonder what it is doing. 508 namespace lld { 509 namespace coff { 510 bool link(llvm::ArrayRef<const char *> args, llvm::raw_ostream &stdoutOS, 511 llvm::raw_ostream &stderrOS, bool exitEarly, bool disableOutput); 512 } 513 namespace elf { 514 bool link(llvm::ArrayRef<const char *> args, llvm::raw_ostream &stdoutOS, 515 llvm::raw_ostream &stderrOS, bool exitEarly, bool disableOutput); 516 } 517 namespace wasm { 518 bool link(llvm::ArrayRef<const char *> args, llvm::raw_ostream &stdoutOS, 519 llvm::raw_ostream &stderrOS, bool exitEarly, bool disableOutput); 520 } 521 } 522 523 bool ZigLLDLinkCOFF(int argc, const char **argv, bool can_exit_early, bool disable_output) { 524 std::vector<const char *> args(argv, argv + argc); 525 return lld::coff::link(args, llvm::outs(), llvm::errs(), can_exit_early, disable_output); 526 } 527 528 bool ZigLLDLinkELF(int argc, const char **argv, bool can_exit_early, bool disable_output) { 529 std::vector<const char *> args(argv, argv + argc); 530 return lld::elf::link(args, llvm::outs(), llvm::errs(), can_exit_early, disable_output); 531 } 532 533 bool ZigLLDLinkWasm(int argc, const char **argv, bool can_exit_early, bool disable_output) { 534 std::vector<const char *> args(argv, argv + argc); 535 return lld::wasm::link(args, llvm::outs(), llvm::errs(), can_exit_early, disable_output); 536 } 537 538 static_assert((FloatABI::ABIType)ZigLLVMFloatABI_Default == FloatABI::ABIType::Default, ""); 539 static_assert((FloatABI::ABIType)ZigLLVMFloatABI_Soft == FloatABI::ABIType::Soft, ""); 540 static_assert((FloatABI::ABIType)ZigLLVMFloatABI_Hard == FloatABI::ABIType::Hard, ""); 541 542 static_assert((object::Archive::Kind)ZigLLVMArchiveKind_GNU == object::Archive::Kind::K_GNU, ""); 543 static_assert((object::Archive::Kind)ZigLLVMArchiveKind_GNU64 == object::Archive::Kind::K_GNU64, ""); 544 static_assert((object::Archive::Kind)ZigLLVMArchiveKind_BSD == object::Archive::Kind::K_BSD, ""); 545 static_assert((object::Archive::Kind)ZigLLVMArchiveKind_DARWIN == object::Archive::Kind::K_DARWIN, ""); 546 static_assert((object::Archive::Kind)ZigLLVMArchiveKind_DARWIN64 == object::Archive::Kind::K_DARWIN64, ""); 547 static_assert((object::Archive::Kind)ZigLLVMArchiveKind_COFF == object::Archive::Kind::K_COFF, ""); 548 static_assert((object::Archive::Kind)ZigLLVMArchiveKind_AIXBIG == object::Archive::Kind::K_AIXBIG, ""); 549