aboutsummaryrefslogtreecommitdiff
path: root/src/link
diff options
context:
space:
mode:
authorTimon Kruiper <timonkruiper@gmail.com>2020-12-19 11:22:49 +0100
committerTimon Kruiper <timonkruiper@gmail.com>2020-12-28 21:19:40 +0100
commit071417161d5d7ab91c32073693590ef161017dbe (patch)
tree891bfd9fecd90b9b341d95dfb78399788f62c3ed /src/link
parent4a0d64300bd9ab1a8c35c634856396e3413200f1 (diff)
downloadzig-071417161d5d7ab91c32073693590ef161017dbe.tar.gz
zig-071417161d5d7ab91c32073693590ef161017dbe.zip
stage2: add initial impl of LLVM backend in self-hosted compiler
Diffstat (limited to 'src/link')
-rw-r--r--src/link/Elf.zig45
1 files changed, 43 insertions, 2 deletions
diff --git a/src/link/Elf.zig b/src/link/Elf.zig
index 6232a64e4a..479dc415e5 100644
--- a/src/link/Elf.zig
+++ b/src/link/Elf.zig
@@ -24,6 +24,7 @@ const build_options = @import("build_options");
const target_util = @import("../target.zig");
const glibc = @import("../glibc.zig");
const Cache = @import("../Cache.zig");
+const llvm_backend = @import("../llvm_backend.zig");
const default_entry_addr = 0x8000000;
@@ -33,6 +34,9 @@ base: File,
ptr_width: PtrWidth,
+/// If this is not null, an object file is created by LLVM and linked with LLD afterwards.
+llvm_ir_module: ?*llvm_backend.LLVMIRModule = null,
+
/// Stored in native-endian format, depending on target endianness needs to be bswapped on read/write.
/// Same order as in the file.
sections: std.ArrayListUnmanaged(elf.Elf64_Shdr) = std.ArrayListUnmanaged(elf.Elf64_Shdr){},
@@ -224,7 +228,13 @@ pub const SrcFn = struct {
pub fn openPath(allocator: *Allocator, sub_path: []const u8, options: link.Options) !*Elf {
assert(options.object_format == .elf);
- if (options.use_llvm) return error.LLVMBackendUnimplementedForELF; // TODO
+ if (options.use_llvm) {
+ const self = try createEmpty(allocator, options);
+ errdefer self.base.destroy();
+
+ self.llvm_ir_module = try llvm_backend.LLVMIRModule.create(allocator, sub_path, options);
+ return self;
+ }
const file = try options.emit.?.directory.handle.createFile(sub_path, .{
.truncate = false,
@@ -288,6 +298,7 @@ pub fn createEmpty(gpa: *Allocator, options: link.Options) !*Elf {
}
pub fn deinit(self: *Elf) void {
+ if (self.llvm_ir_module) |ir_module| ir_module.deinit(self.base.allocator);
self.sections.deinit(self.base.allocator);
self.program_headers.deinit(self.base.allocator);
self.shstrtab.deinit(self.base.allocator);
@@ -423,6 +434,8 @@ fn updateString(self: *Elf, old_str_off: u32, new_name: []const u8) !u32 {
}
pub fn populateMissingMetadata(self: *Elf) !void {
+ if (self.llvm_ir_module) |_| return;
+
const small_ptr = switch (self.ptr_width) {
.p32 => true,
.p64 => false,
@@ -727,6 +740,11 @@ pub fn flushModule(self: *Elf, comp: *Compilation) !void {
const tracy = trace(@src());
defer tracy.end();
+ if (self.llvm_ir_module) |llvm_ir_module| {
+ try llvm_ir_module.flushModule(comp);
+ return;
+ }
+
// TODO This linker code currently assumes there is only 1 compilation unit and it corresponds to the
// Zig source code.
const module = self.base.options.module orelse return error.LinkingWithoutZigSourceUnimplemented;
@@ -1261,6 +1279,9 @@ fn linkWithLLD(self: *Elf, comp: *Compilation) !void {
const stack_size = self.base.options.stack_size_override orelse 16777216;
const allow_shlib_undefined = self.base.options.allow_shlib_undefined orelse !self.base.options.is_native_os;
const compiler_rt_path: ?[]const u8 = if (self.base.options.include_compiler_rt) blk: {
+ // TODO: remove when stage2 can build compiler_rt.zig
+ if (!build_options.is_stage1) break :blk null;
+
if (is_exe_or_dyn_lib) {
break :blk comp.compiler_rt_static_lib.?.full_object_path;
} else {
@@ -1552,7 +1573,12 @@ fn linkWithLLD(self: *Elf, comp: *Compilation) !void {
}
// libc
- if (is_exe_or_dyn_lib and !self.base.options.skip_linker_dependencies and !self.base.options.link_libc) {
+ // TODO: enable when stage2 can build c.zig
+ if (is_exe_or_dyn_lib and
+ !self.base.options.skip_linker_dependencies and
+ !self.base.options.link_libc and
+ build_options.is_stage1)
+ {
try argv.append(comp.libc_static_lib.?.full_object_path);
}
@@ -2046,6 +2072,8 @@ fn allocateTextBlock(self: *Elf, text_block: *TextBlock, new_block_size: u64, al
}
pub fn allocateDeclIndexes(self: *Elf, decl: *Module.Decl) !void {
+ if (self.llvm_ir_module) |_| return;
+
if (decl.link.elf.local_sym_index != 0) return;
try self.local_symbols.ensureCapacity(self.base.allocator, self.local_symbols.items.len + 1);
@@ -2082,6 +2110,8 @@ pub fn allocateDeclIndexes(self: *Elf, decl: *Module.Decl) !void {
}
pub fn freeDecl(self: *Elf, decl: *Module.Decl) void {
+ if (self.llvm_ir_module) |_| return;
+
// Appending to free lists is allowed to fail because the free lists are heuristics based anyway.
self.freeTextBlock(&decl.link.elf);
if (decl.link.elf.local_sym_index != 0) {
@@ -2119,6 +2149,11 @@ pub fn updateDecl(self: *Elf, module: *Module, decl: *Module.Decl) !void {
const tracy = trace(@src());
defer tracy.end();
+ if (self.llvm_ir_module) |llvm_ir_module| {
+ try llvm_ir_module.updateDecl(module, decl);
+ return;
+ }
+
var code_buffer = std.ArrayList(u8).init(self.base.allocator);
defer code_buffer.deinit();
@@ -2594,6 +2629,8 @@ pub fn updateDeclExports(
decl: *const Module.Decl,
exports: []const *Module.Export,
) !void {
+ if (self.llvm_ir_module) |_| return;
+
const tracy = trace(@src());
defer tracy.end();
@@ -2667,6 +2704,8 @@ pub fn updateDeclLineNumber(self: *Elf, module: *Module, decl: *const Module.Dec
const tracy = trace(@src());
defer tracy.end();
+ if (self.llvm_ir_module) |_| return;
+
const container_scope = decl.scope.cast(Module.Scope.Container).?;
const tree = container_scope.file_scope.contents.tree;
const file_ast_decls = tree.root_node.decls();
@@ -2685,6 +2724,8 @@ pub fn updateDeclLineNumber(self: *Elf, module: *Module, decl: *const Module.Dec
}
pub fn deleteExport(self: *Elf, exp: Export) void {
+ if (self.llvm_ir_module) |_| return;
+
const sym_index = exp.sym_index orelse return;
self.global_symbol_free_list.append(self.base.allocator, sym_index) catch {};
self.global_symbols.items[sym_index].st_info = 0;