master
1/*
2 * Copyright (c) 2015 Andrew Kelley
3 *
4 * This file is part of zig, which is MIT licensed.
5 * See http://opensource.org/licenses/MIT
6 */
7
8
9/*
10 * The point of this file is to contain all the LLVM C++ API interaction so that:
11 * 1. The compile time of other files is kept under control.
12 * 2. Provide a C interface to the LLVM functions we need for self-hosting purposes.
13 * 3. Prevent C++ from infecting the rest of the project.
14 */
15
16#include "zig_llvm.h"
17
18#if __GNUC__ >= 9
19#pragma GCC diagnostic push
20#pragma GCC diagnostic ignored "-Winit-list-lifetime"
21#endif
22
23#include <llvm/Analysis/AliasAnalysis.h>
24#include <llvm/Analysis/TargetLibraryInfo.h>
25#include <llvm/Analysis/TargetTransformInfo.h>
26#include <llvm/Bitcode/BitcodeWriter.h>
27#include <llvm/IR/DiagnosticInfo.h>
28#include <llvm/IR/InlineAsm.h>
29#include <llvm/IR/Instructions.h>
30#include <llvm/IR/LegacyPassManager.h>
31#include <llvm/IR/Module.h>
32#include <llvm/IR/OptBisect.h>
33#include <llvm/IR/PassManager.h>
34#include <llvm/IR/Verifier.h>
35#include <llvm/InitializePasses.h>
36#include <llvm/MC/TargetRegistry.h>
37#include <llvm/Passes/OptimizationLevel.h>
38#include <llvm/Passes/PassBuilder.h>
39#include <llvm/Passes/StandardInstrumentations.h>
40#include <llvm/Object/Archive.h>
41#include <llvm/Object/ArchiveWriter.h>
42#include <llvm/PassRegistry.h>
43#include <llvm/Support/CommandLine.h>
44#include <llvm/Support/FileSystem.h>
45#include <llvm/Support/Process.h>
46#include <llvm/Support/TimeProfiler.h>
47#include <llvm/Support/Timer.h>
48#include <llvm/Support/raw_ostream.h>
49#include <llvm/Target/TargetMachine.h>
50#include <llvm/Target/TargetOptions.h>
51#include <llvm/Target/CodeGenCWrappers.h>
52#include <llvm/Transforms/IPO.h>
53#include <llvm/Transforms/IPO/AlwaysInliner.h>
54#include <llvm/Transforms/Instrumentation/ThreadSanitizer.h>
55#include <llvm/Transforms/Instrumentation/SanitizerCoverage.h>
56#include <llvm/Transforms/Scalar.h>
57#include <llvm/Transforms/Utils.h>
58#include <llvm/Transforms/Utils/AddDiscriminators.h>
59#include <llvm/Transforms/Utils/CanonicalizeAliases.h>
60#include <llvm/Transforms/Utils/NameAnonGlobals.h>
61
62#include <lld/Common/Driver.h>
63
64#if __GNUC__ >= 9
65#pragma GCC diagnostic pop
66#endif
67
68#include <new>
69
70#include <stdlib.h>
71
72using namespace llvm;
73
74#ifndef NDEBUG
75static const bool assertions_on = true;
76#else
77static const bool assertions_on = false;
78#endif
79
80LLVMTargetMachineRef ZigLLVMCreateTargetMachine(LLVMTargetRef T, const char *Triple,
81 const char *CPU, const char *Features, LLVMCodeGenOptLevel Level, LLVMRelocMode Reloc,
82 LLVMCodeModel CodeModel, bool function_sections, bool data_sections, ZigLLVMFloatABI float_abi,
83 const char *abi_name, bool emulated_tls)
84{
85 std::optional<Reloc::Model> RM;
86 switch (Reloc){
87 case LLVMRelocStatic:
88 RM = Reloc::Static;
89 break;
90 case LLVMRelocPIC:
91 RM = Reloc::PIC_;
92 break;
93 case LLVMRelocDynamicNoPic:
94 RM = Reloc::DynamicNoPIC;
95 break;
96 case LLVMRelocROPI:
97 RM = Reloc::ROPI;
98 break;
99 case LLVMRelocRWPI:
100 RM = Reloc::RWPI;
101 break;
102 case LLVMRelocROPI_RWPI:
103 RM = Reloc::ROPI_RWPI;
104 break;
105 default:
106 break;
107 }
108
109 bool JIT;
110 std::optional<CodeModel::Model> CM = unwrap(CodeModel, JIT);
111
112 CodeGenOptLevel OL;
113 switch (Level) {
114 case LLVMCodeGenLevelNone:
115 OL = CodeGenOptLevel::None;
116 break;
117 case LLVMCodeGenLevelLess:
118 OL = CodeGenOptLevel::Less;
119 break;
120 case LLVMCodeGenLevelAggressive:
121 OL = CodeGenOptLevel::Aggressive;
122 break;
123 default:
124 OL = CodeGenOptLevel::Default;
125 break;
126 }
127
128 TargetOptions opt;
129
130 opt.UseInitArray = true;
131 opt.FunctionSections = function_sections;
132 opt.DataSections = data_sections;
133 switch (float_abi) {
134 case ZigLLVMFloatABI_Default:
135 opt.FloatABIType = FloatABI::Default;
136 break;
137 case ZigLLVMFloatABI_Soft:
138 opt.FloatABIType = FloatABI::Soft;
139 break;
140 case ZigLLVMFloatABI_Hard:
141 opt.FloatABIType = FloatABI::Hard;
142 break;
143 }
144
145 if (abi_name != nullptr) {
146 opt.MCOptions.ABIName = abi_name;
147 }
148
149 if (emulated_tls) {
150 opt.EmulatedTLS = true;
151 }
152
153 TargetMachine *TM = reinterpret_cast<Target*>(T)->createTargetMachine(
154 llvm::Triple(Triple),
155 CPU,
156 Features,
157 opt,
158 RM,
159 CM,
160 OL,
161 JIT);
162
163 return reinterpret_cast<LLVMTargetMachineRef>(TM);
164}
165
166namespace {
167// LLVM's time profiler can provide a hierarchy view of the time spent
168// in each component. It generates JSON report in Chrome's "Trace Event"
169// format. So the report can be easily visualized by the Chrome browser.
170struct TimeTracerRAII {
171 // Granularity in ms
172 unsigned TimeTraceGranularity;
173 StringRef TimeTraceFile, OutputFilename;
174 bool EnableTimeTrace;
175
176 TimeTracerRAII(StringRef ProgramName, StringRef OF)
177 : TimeTraceGranularity(500U),
178 TimeTraceFile(std::getenv("ZIG_LLVM_TIME_TRACE_FILE")),
179 OutputFilename(OF),
180 EnableTimeTrace(!TimeTraceFile.empty()) {
181 if (EnableTimeTrace) {
182 if (const char *G = std::getenv("ZIG_LLVM_TIME_TRACE_GRANULARITY"))
183 TimeTraceGranularity = (unsigned)std::atoi(G);
184
185 llvm::timeTraceProfilerInitialize(TimeTraceGranularity, ProgramName);
186 }
187 }
188
189 ~TimeTracerRAII() {
190 if (EnableTimeTrace) {
191 if (auto E = llvm::timeTraceProfilerWrite(TimeTraceFile, OutputFilename)) {
192 handleAllErrors(std::move(E), [&](const StringError &SE) {
193 errs() << SE.getMessage() << "\n";
194 });
195 return;
196 }
197 timeTraceProfilerCleanup();
198 }
199 }
200};
201} // end anonymous namespace
202
203static SanitizerCoverageOptions getSanCovOptions(ZigLLVMCoverageOptions z) {
204 SanitizerCoverageOptions o;
205 o.CoverageType = (SanitizerCoverageOptions::Type)z.CoverageType;
206 o.IndirectCalls = z.IndirectCalls;
207 o.TraceBB = z.TraceBB;
208 o.TraceCmp = z.TraceCmp;
209 o.TraceDiv = z.TraceDiv;
210 o.TraceGep = z.TraceGep;
211 o.Use8bitCounters = z.Use8bitCounters;
212 o.TracePC = z.TracePC;
213 o.TracePCGuard = z.TracePCGuard;
214 o.Inline8bitCounters = z.Inline8bitCounters;
215 o.InlineBoolFlag = z.InlineBoolFlag;
216 o.PCTable = z.PCTable;
217 o.NoPrune = z.NoPrune;
218 o.StackDepth = z.StackDepth;
219 o.TraceLoads = z.TraceLoads;
220 o.TraceStores = z.TraceStores;
221 o.CollectControlFlow = z.CollectControlFlow;
222 return o;
223}
224
225ZIG_EXTERN_C bool ZigLLVMTargetMachineEmitToFile(LLVMTargetMachineRef targ_machine_ref, LLVMModuleRef module_ref,
226 char **error_message, const ZigLLVMEmitOptions *options)
227{
228 TimePassesIsEnabled = options->time_report_out != nullptr;
229
230 raw_fd_ostream *dest_asm_ptr = nullptr;
231 raw_fd_ostream *dest_bin_ptr = nullptr;
232 raw_fd_ostream *dest_bitcode_ptr = nullptr;
233
234 if (options->asm_filename) {
235 std::error_code EC;
236 dest_asm_ptr = new(std::nothrow) raw_fd_ostream(options->asm_filename, EC, sys::fs::OF_None);
237 if (EC) {
238 *error_message = strdup((const char *)StringRef(EC.message()).bytes_begin());
239 return true;
240 }
241 }
242 if (options->bin_filename) {
243 std::error_code EC;
244 dest_bin_ptr = new(std::nothrow) raw_fd_ostream(options->bin_filename, EC, sys::fs::OF_None);
245 if (EC) {
246 *error_message = strdup((const char *)StringRef(EC.message()).bytes_begin());
247 return true;
248 }
249 }
250 if (options->bitcode_filename) {
251 std::error_code EC;
252 dest_bitcode_ptr = new(std::nothrow) raw_fd_ostream(options->bitcode_filename, EC, sys::fs::OF_None);
253 if (EC) {
254 *error_message = strdup((const char *)StringRef(EC.message()).bytes_begin());
255 return true;
256 }
257 }
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 = !options->is_debug;
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
440void ZigLLVMSetOptBisectLimit(LLVMContextRef context_ref, int limit) {
441 static OptBisect opt_bisect;
442 opt_bisect.setLimit(limit);
443 unwrap(context_ref)->setOptPassGate(opt_bisect);
444}
445
446struct 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
462void ZigLLVMEnableBrokenDebugInfoCheck(LLVMContextRef context_ref) {
463 unwrap(context_ref)->setDiagnosticHandler(std::make_unique<ZigDiagnosticHandler>());
464}
465
466bool ZigLLVMGetBrokenDebugInfo(LLVMContextRef context_ref) {
467 return ((const ZigDiagnosticHandler*)
468 unwrap(context_ref)->getDiagHandlerPtr())->BrokenDebugInfo;
469}
470
471void ZigLLVMParseCommandLineOptions(size_t argc, const char *const *argv) {
472 cl::ParseCommandLineOptions(argc, argv);
473}
474
475bool ZigLLVMWriteArchive(const char *archive_name, const char **file_names, size_t file_name_count,
476 ZigLLVMArchiveKind archive_kind)
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) return true;
483 new_members.push_back(std::move(*new_member));
484 }
485 Error err = writeArchive(archive_name, new_members,
486 SymtabWritingMode::NormalSymtab, static_cast<object::Archive::Kind>(archive_kind), true, false, nullptr);
487
488 if (err) return true;
489 return false;
490}
491
492// The header file in LLD 16 exposed these functions. As of 17 they are only
493// exposed via a macro ("LLD_HAS_DRIVER") which I have copied and pasted the
494// body of here so that you don't have to wonder what it is doing.
495namespace lld {
496 namespace coff {
497 bool link(llvm::ArrayRef<const char *> args, llvm::raw_ostream &stdoutOS,
498 llvm::raw_ostream &stderrOS, bool exitEarly, bool disableOutput);
499 }
500 namespace elf {
501 bool link(llvm::ArrayRef<const char *> args, llvm::raw_ostream &stdoutOS,
502 llvm::raw_ostream &stderrOS, bool exitEarly, bool disableOutput);
503 }
504 namespace wasm {
505 bool link(llvm::ArrayRef<const char *> args, llvm::raw_ostream &stdoutOS,
506 llvm::raw_ostream &stderrOS, bool exitEarly, bool disableOutput);
507 }
508}
509
510bool ZigLLDLinkCOFF(int argc, const char **argv, bool can_exit_early, bool disable_output) {
511 std::vector<const char *> args(argv, argv + argc);
512 return lld::coff::link(args, llvm::outs(), llvm::errs(), can_exit_early, disable_output);
513}
514
515bool ZigLLDLinkELF(int argc, const char **argv, bool can_exit_early, bool disable_output) {
516 std::vector<const char *> args(argv, argv + argc);
517 return lld::elf::link(args, llvm::outs(), llvm::errs(), can_exit_early, disable_output);
518}
519
520bool ZigLLDLinkWasm(int argc, const char **argv, bool can_exit_early, bool disable_output) {
521 std::vector<const char *> args(argv, argv + argc);
522 return lld::wasm::link(args, llvm::outs(), llvm::errs(), can_exit_early, disable_output);
523}
524
525static_assert((FloatABI::ABIType)ZigLLVMFloatABI_Default == FloatABI::ABIType::Default, "");
526static_assert((FloatABI::ABIType)ZigLLVMFloatABI_Soft == FloatABI::ABIType::Soft, "");
527static_assert((FloatABI::ABIType)ZigLLVMFloatABI_Hard == FloatABI::ABIType::Hard, "");
528
529static_assert((object::Archive::Kind)ZigLLVMArchiveKind_GNU == object::Archive::Kind::K_GNU, "");
530static_assert((object::Archive::Kind)ZigLLVMArchiveKind_GNU64 == object::Archive::Kind::K_GNU64, "");
531static_assert((object::Archive::Kind)ZigLLVMArchiveKind_BSD == object::Archive::Kind::K_BSD, "");
532static_assert((object::Archive::Kind)ZigLLVMArchiveKind_DARWIN == object::Archive::Kind::K_DARWIN, "");
533static_assert((object::Archive::Kind)ZigLLVMArchiveKind_DARWIN64 == object::Archive::Kind::K_DARWIN64, "");
534static_assert((object::Archive::Kind)ZigLLVMArchiveKind_COFF == object::Archive::Kind::K_COFF, "");
535static_assert((object::Archive::Kind)ZigLLVMArchiveKind_AIXBIG == object::Archive::Kind::K_AIXBIG, "");