commit 2df2f0020f4ddc41b3b914cd17efcb403cf0f6ad (tree)
parent f75d4cbe56f9f8212581f00700600a57ce545ba1
Author: Andrew Kelley <andrew@ziglang.org>
Date: Mon, 28 Dec 2020 15:07:21 -0800
Merge pull request #7498 from FireFox317/stage2-llvm
stage2: add initial impl of LLVM backend in self-hosted compiler
Diffstat:
14 files changed, 1069 insertions(+), 293 deletions(-)
diff --git a/CMakeLists.txt b/CMakeLists.txt
@@ -527,7 +527,6 @@ set(ZIG_STAGE2_SOURCES
"${CMAKE_SOURCE_DIR}/src/codegen/aarch64.zig"
"${CMAKE_SOURCE_DIR}/src/codegen/arm.zig"
"${CMAKE_SOURCE_DIR}/src/codegen/c.zig"
- "${CMAKE_SOURCE_DIR}/src/codegen/llvm.zig"
"${CMAKE_SOURCE_DIR}/src/codegen/riscv64.zig"
"${CMAKE_SOURCE_DIR}/src/codegen/spu-mk2.zig"
"${CMAKE_SOURCE_DIR}/src/codegen/wasm.zig"
@@ -549,7 +548,8 @@ set(ZIG_STAGE2_SOURCES
"${CMAKE_SOURCE_DIR}/src/link/cbe.h"
"${CMAKE_SOURCE_DIR}/src/link/msdos-stub.bin"
"${CMAKE_SOURCE_DIR}/src/liveness.zig"
- "${CMAKE_SOURCE_DIR}/src/llvm.zig"
+ "${CMAKE_SOURCE_DIR}/src/llvm_backend.zig"
+ "${CMAKE_SOURCE_DIR}/src/llvm_bindings.zig"
"${CMAKE_SOURCE_DIR}/src/main.zig"
"${CMAKE_SOURCE_DIR}/src/mingw.zig"
"${CMAKE_SOURCE_DIR}/src/musl.zig"
diff --git a/build.zig b/build.zig
@@ -91,6 +91,20 @@ pub fn build(b: *Builder) !void {
exe.addBuildOption(bool, "have_llvm", enable_llvm);
if (enable_llvm) {
const cmake_cfg = if (static_llvm) null else findAndParseConfigH(b, config_h_path_option);
+
+ const exe_cflags = [_][]const u8{
+ "-std=c++14",
+ "-D__STDC_CONSTANT_MACROS",
+ "-D__STDC_FORMAT_MACROS",
+ "-D__STDC_LIMIT_MACROS",
+ "-D_GNU_SOURCE",
+ "-fvisibility-inlines-hidden",
+ "-fno-exceptions",
+ "-fno-rtti",
+ "-Werror=type-limits",
+ "-Wno-missing-braces",
+ "-Wno-comment",
+ };
if (is_stage1) {
exe.addIncludeDir("src");
exe.addIncludeDir("deps/SoftFloat-3e/source/include");
@@ -109,19 +123,6 @@ pub fn build(b: *Builder) !void {
softfloat.addCSourceFiles(&softfloat_sources, &[_][]const u8{ "-std=c99", "-O3" });
exe.linkLibrary(softfloat);
- const exe_cflags = [_][]const u8{
- "-std=c++14",
- "-D__STDC_CONSTANT_MACROS",
- "-D__STDC_FORMAT_MACROS",
- "-D__STDC_LIMIT_MACROS",
- "-D_GNU_SOURCE",
- "-fvisibility-inlines-hidden",
- "-fno-exceptions",
- "-fno-rtti",
- "-Werror=type-limits",
- "-Wno-missing-braces",
- "-Wno-comment",
- };
exe.addCSourceFiles(&stage1_sources, &exe_cflags);
exe.addCSourceFiles(&optimized_c_sources, &[_][]const u8{ "-std=c99", "-O3" });
if (cmake_cfg == null) {
@@ -205,6 +206,12 @@ pub fn build(b: *Builder) !void {
exe.linkSystemLibrary(lib_name);
}
+ // We need this because otherwise zig_clang_cc1_main.cpp ends up pulling
+ // in a dependency on llvm::cfg::Update<llvm::BasicBlock*>::dump() which is
+ // unavailable when LLVM is compiled in Release mode.
+ const zig_cpp_cflags = exe_cflags ++ [_][]const u8{"-DNDEBUG=1"};
+ exe.addCSourceFiles(&zig_cpp_sources, &zig_cpp_cflags);
+
// This means we rely on clang-or-zig-built LLVM, Clang, LLD libraries.
exe.linkSystemLibrary("c++");
diff --git a/src/Compilation.zig b/src/Compilation.zig
@@ -2106,7 +2106,7 @@ pub fn addCCArgs(
try argv.append("-D_LIBCXXABI_DISABLE_VISIBILITY_ANNOTATIONS");
}
- const llvm_triple = try @import("codegen/llvm.zig").targetTriple(arena, target);
+ const llvm_triple = try @import("llvm_backend.zig").targetTriple(arena, target);
try argv.appendSlice(&[_][]const u8{ "-target", llvm_triple });
switch (ext) {
diff --git a/src/codegen/llvm.zig b/src/codegen/llvm.zig
@@ -1,125 +0,0 @@
-const std = @import("std");
-const Allocator = std.mem.Allocator;
-
-pub fn targetTriple(allocator: *Allocator, target: std.Target) ![]u8 {
- const llvm_arch = switch (target.cpu.arch) {
- .arm => "arm",
- .armeb => "armeb",
- .aarch64 => "aarch64",
- .aarch64_be => "aarch64_be",
- .aarch64_32 => "aarch64_32",
- .arc => "arc",
- .avr => "avr",
- .bpfel => "bpfel",
- .bpfeb => "bpfeb",
- .hexagon => "hexagon",
- .mips => "mips",
- .mipsel => "mipsel",
- .mips64 => "mips64",
- .mips64el => "mips64el",
- .msp430 => "msp430",
- .powerpc => "powerpc",
- .powerpc64 => "powerpc64",
- .powerpc64le => "powerpc64le",
- .r600 => "r600",
- .amdgcn => "amdgcn",
- .riscv32 => "riscv32",
- .riscv64 => "riscv64",
- .sparc => "sparc",
- .sparcv9 => "sparcv9",
- .sparcel => "sparcel",
- .s390x => "s390x",
- .tce => "tce",
- .tcele => "tcele",
- .thumb => "thumb",
- .thumbeb => "thumbeb",
- .i386 => "i386",
- .x86_64 => "x86_64",
- .xcore => "xcore",
- .nvptx => "nvptx",
- .nvptx64 => "nvptx64",
- .le32 => "le32",
- .le64 => "le64",
- .amdil => "amdil",
- .amdil64 => "amdil64",
- .hsail => "hsail",
- .hsail64 => "hsail64",
- .spir => "spir",
- .spir64 => "spir64",
- .kalimba => "kalimba",
- .shave => "shave",
- .lanai => "lanai",
- .wasm32 => "wasm32",
- .wasm64 => "wasm64",
- .renderscript32 => "renderscript32",
- .renderscript64 => "renderscript64",
- .ve => "ve",
- .spu_2 => return error.LLVMBackendDoesNotSupportSPUMarkII,
- };
- // TODO Add a sub-arch for some architectures depending on CPU features.
-
- const llvm_os = switch (target.os.tag) {
- .freestanding => "unknown",
- .ananas => "ananas",
- .cloudabi => "cloudabi",
- .dragonfly => "dragonfly",
- .freebsd => "freebsd",
- .fuchsia => "fuchsia",
- .ios => "ios",
- .kfreebsd => "kfreebsd",
- .linux => "linux",
- .lv2 => "lv2",
- .macos => "macosx",
- .netbsd => "netbsd",
- .openbsd => "openbsd",
- .solaris => "solaris",
- .windows => "windows",
- .haiku => "haiku",
- .minix => "minix",
- .rtems => "rtems",
- .nacl => "nacl",
- .cnk => "cnk",
- .aix => "aix",
- .cuda => "cuda",
- .nvcl => "nvcl",
- .amdhsa => "amdhsa",
- .ps4 => "ps4",
- .elfiamcu => "elfiamcu",
- .tvos => "tvos",
- .watchos => "watchos",
- .mesa3d => "mesa3d",
- .contiki => "contiki",
- .amdpal => "amdpal",
- .hermit => "hermit",
- .hurd => "hurd",
- .wasi => "wasi",
- .emscripten => "emscripten",
- .uefi => "windows",
- .other => "unknown",
- };
-
- const llvm_abi = switch (target.abi) {
- .none => "unknown",
- .gnu => "gnu",
- .gnuabin32 => "gnuabin32",
- .gnuabi64 => "gnuabi64",
- .gnueabi => "gnueabi",
- .gnueabihf => "gnueabihf",
- .gnux32 => "gnux32",
- .code16 => "code16",
- .eabi => "eabi",
- .eabihf => "eabihf",
- .android => "android",
- .musl => "musl",
- .musleabi => "musleabi",
- .musleabihf => "musleabihf",
- .msvc => "msvc",
- .itanium => "itanium",
- .cygnus => "cygnus",
- .coreclr => "coreclr",
- .simulator => "simulator",
- .macabi => "macabi",
- };
-
- return std.fmt.allocPrint(allocator, "{}-unknown-{}-{}", .{ llvm_arch, llvm_os, llvm_abi });
-}
diff --git a/src/link.zig b/src/link.zig
@@ -567,7 +567,7 @@ pub const File = struct {
std.debug.print("\n", .{});
}
- const llvm = @import("llvm.zig");
+ const llvm = @import("llvm_bindings.zig");
const os_type = @import("target.zig").osToLLVM(base.options.target.os.tag);
const bad = llvm.WriteArchive(full_out_path_z, object_files.items.ptr, object_files.items.len, os_type);
if (bad) return error.UnableToWriteArchive;
diff --git a/src/link/Coff.zig b/src/link/Coff.zig
@@ -16,6 +16,7 @@ const link = @import("../link.zig");
const build_options = @import("build_options");
const Cache = @import("../Cache.zig");
const mingw = @import("../mingw.zig");
+const llvm_backend = @import("../llvm_backend.zig");
const allocation_padding = 4 / 3;
const minimum_text_block_size = 64 * allocation_padding;
@@ -32,6 +33,9 @@ pub const base_tag: link.File.Tag = .coff;
const msdos_stub = @embedFile("msdos-stub.bin");
+/// If this is not null, an object file is created by LLVM and linked with LLD afterwards.
+llvm_ir_module: ?*llvm_backend.LLVMIRModule = null,
+
base: link.File,
ptr_width: PtrWidth,
error_flags: link.File.ErrorFlags = .{},
@@ -121,8 +125,13 @@ pub const SrcFn = void;
pub fn openPath(allocator: *Allocator, sub_path: []const u8, options: link.Options) !*Coff {
assert(options.object_format == .coff);
- if (options.use_llvm) return error.LLVM_BackendIsTODO_ForCoff; // TODO
- if (options.use_lld) return error.LLD_LinkingIsTODO_ForCoff; // TODO
+ if (build_options.have_llvm and 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,
@@ -404,6 +413,8 @@ pub fn createEmpty(gpa: *Allocator, options: link.Options) !*Coff {
}
pub fn allocateDeclIndexes(self: *Coff, decl: *Module.Decl) !void {
+ if (self.llvm_ir_module) |_| return;
+
try self.offset_table.ensureCapacity(self.base.allocator, self.offset_table.items.len + 1);
if (self.offset_table_free_list.popOrNull()) |i| {
@@ -648,6 +659,9 @@ pub fn updateDecl(self: *Coff, module: *Module, decl: *Module.Decl) !void {
const tracy = trace(@src());
defer tracy.end();
+ if (build_options.have_llvm)
+ if (self.llvm_ir_module) |llvm_ir_module| return try llvm_ir_module.updateDecl(module, decl);
+
var code_buffer = std.ArrayList(u8).init(self.base.allocator);
defer code_buffer.deinit();
@@ -698,12 +712,16 @@ pub fn updateDecl(self: *Coff, module: *Module, decl: *Module.Decl) !void {
}
pub fn freeDecl(self: *Coff, 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.coff);
self.offset_table_free_list.append(self.base.allocator, decl.link.coff.offset_table_index) catch {};
}
pub fn updateDeclExports(self: *Coff, module: *Module, decl: *const Module.Decl, exports: []const *Module.Export) !void {
+ if (self.llvm_ir_module) |_| return;
+
for (exports) |exp| {
if (exp.options.section) |section_name| {
if (!mem.eql(u8, section_name, ".text")) {
@@ -744,6 +762,9 @@ pub fn flushModule(self: *Coff, comp: *Compilation) !void {
const tracy = trace(@src());
defer tracy.end();
+ if (build_options.have_llvm)
+ if (self.llvm_ir_module) |llvm_ir_module| return try llvm_ir_module.flushModule(comp);
+
if (self.text_section_size_dirty) {
// Write the new raw size in the .text header
var buf: [4]u8 = undefined;
@@ -1124,8 +1145,9 @@ fn linkWithLLD(self: *Coff, comp: *Compilation) !void {
try argv.append(comp.libunwind_static_lib.?.full_object_path);
}
+ // TODO: remove when stage2 can build compiler_rt.zig, c.zig and ssp.zig
// compiler-rt, libc and libssp
- if (is_exe_or_dyn_lib and !self.base.options.skip_linker_dependencies) {
+ if (is_exe_or_dyn_lib and !self.base.options.skip_linker_dependencies and build_options.is_stage1) {
if (!self.base.options.link_libc) {
try argv.append(comp.libc_static_lib.?.full_object_path);
}
@@ -1227,6 +1249,7 @@ fn linkWithLLD(self: *Coff, comp: *Compilation) !void {
}
pub fn getDeclVAddr(self: *Coff, decl: *const Module.Decl) u64 {
+ assert(self.llvm_ir_module == null);
return self.text_section_virtual_address + decl.link.coff.text_offset;
}
@@ -1235,6 +1258,9 @@ pub fn updateDeclLineNumber(self: *Coff, module: *Module, decl: *Module.Decl) !v
}
pub fn deinit(self: *Coff) void {
+ if (build_options.have_llvm)
+ if (self.llvm_ir_module) |ir_module| ir_module.deinit(self.base.allocator);
+
self.text_block_free_list.deinit(self.base.allocator);
self.offset_table.deinit(self.base.allocator);
self.offset_table_free_list.deinit(self.base.allocator);
diff --git 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 (build_options.have_llvm and 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,10 @@ pub fn createEmpty(gpa: *Allocator, options: link.Options) !*Elf {
}
pub fn deinit(self: *Elf) void {
+ if (build_options.have_llvm)
+ 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);
@@ -304,6 +318,7 @@ pub fn deinit(self: *Elf) void {
}
pub fn getDeclVAddr(self: *Elf, decl: *const Module.Decl) u64 {
+ assert(self.llvm_ir_module == null);
assert(decl.link.elf.local_sym_index != 0);
return self.local_symbols.items[decl.link.elf.local_sym_index].st_value;
}
@@ -423,6 +438,8 @@ fn updateString(self: *Elf, old_str_off: u32, new_name: []const u8) !u32 {
}
pub fn populateMissingMetadata(self: *Elf) !void {
+ assert(self.llvm_ir_module == null);
+
const small_ptr = switch (self.ptr_width) {
.p32 => true,
.p64 => false,
@@ -727,6 +744,9 @@ pub fn flushModule(self: *Elf, comp: *Compilation) !void {
const tracy = trace(@src());
defer tracy.end();
+ if (build_options.have_llvm)
+ if (self.llvm_ir_module) |llvm_ir_module| return try llvm_ir_module.flushModule(comp);
+
// 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 +1281,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 +1575,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 +2074,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 +2112,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 +2151,9 @@ pub fn updateDecl(self: *Elf, module: *Module, decl: *Module.Decl) !void {
const tracy = trace(@src());
defer tracy.end();
+ if (build_options.have_llvm)
+ if (self.llvm_ir_module) |llvm_ir_module| return try llvm_ir_module.updateDecl(module, decl);
+
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;
diff --git a/src/llvm.zig b/src/llvm.zig
@@ -1,140 +0,0 @@
-//! We do this instead of @cImport because the self-hosted compiler is easier
-//! to bootstrap if it does not depend on translate-c.
-
-extern fn ZigLLDLinkCOFF(argc: c_int, argv: [*:null]const ?[*:0]const u8, can_exit_early: bool) c_int;
-extern fn ZigLLDLinkELF(argc: c_int, argv: [*:null]const ?[*:0]const u8, can_exit_early: bool) c_int;
-extern fn ZigLLDLinkMachO(argc: c_int, argv: [*:null]const ?[*:0]const u8, can_exit_early: bool) c_int;
-extern fn ZigLLDLinkWasm(argc: c_int, argv: [*:null]const ?[*:0]const u8, can_exit_early: bool) c_int;
-
-pub const LinkCOFF = ZigLLDLinkCOFF;
-pub const LinkELF = ZigLLDLinkELF;
-pub const LinkMachO = ZigLLDLinkMachO;
-pub const LinkWasm = ZigLLDLinkWasm;
-
-pub const ObjectFormatType = extern enum(c_int) {
- Unknown,
- COFF,
- ELF,
- MachO,
- Wasm,
- XCOFF,
-};
-
-pub const GetHostCPUName = LLVMGetHostCPUName;
-extern fn LLVMGetHostCPUName() ?[*:0]u8;
-
-pub const GetNativeFeatures = ZigLLVMGetNativeFeatures;
-extern fn ZigLLVMGetNativeFeatures() ?[*:0]u8;
-
-pub const WriteArchive = ZigLLVMWriteArchive;
-extern fn ZigLLVMWriteArchive(
- archive_name: [*:0]const u8,
- file_names_ptr: [*]const [*:0]const u8,
- file_names_len: usize,
- os_type: OSType,
-) bool;
-
-pub const OSType = extern enum(c_int) {
- UnknownOS = 0,
- Ananas = 1,
- CloudABI = 2,
- Darwin = 3,
- DragonFly = 4,
- FreeBSD = 5,
- Fuchsia = 6,
- IOS = 7,
- KFreeBSD = 8,
- Linux = 9,
- Lv2 = 10,
- MacOSX = 11,
- NetBSD = 12,
- OpenBSD = 13,
- Solaris = 14,
- Win32 = 15,
- Haiku = 16,
- Minix = 17,
- RTEMS = 18,
- NaCl = 19,
- CNK = 20,
- AIX = 21,
- CUDA = 22,
- NVCL = 23,
- AMDHSA = 24,
- PS4 = 25,
- ELFIAMCU = 26,
- TvOS = 27,
- WatchOS = 28,
- Mesa3D = 29,
- Contiki = 30,
- AMDPAL = 31,
- HermitCore = 32,
- Hurd = 33,
- WASI = 34,
- Emscripten = 35,
-};
-
-pub const ArchType = extern enum(c_int) {
- UnknownArch = 0,
- arm = 1,
- armeb = 2,
- aarch64 = 3,
- aarch64_be = 4,
- aarch64_32 = 5,
- arc = 6,
- avr = 7,
- bpfel = 8,
- bpfeb = 9,
- hexagon = 10,
- mips = 11,
- mipsel = 12,
- mips64 = 13,
- mips64el = 14,
- msp430 = 15,
- ppc = 16,
- ppc64 = 17,
- ppc64le = 18,
- r600 = 19,
- amdgcn = 20,
- riscv32 = 21,
- riscv64 = 22,
- sparc = 23,
- sparcv9 = 24,
- sparcel = 25,
- systemz = 26,
- tce = 27,
- tcele = 28,
- thumb = 29,
- thumbeb = 30,
- x86 = 31,
- x86_64 = 32,
- xcore = 33,
- nvptx = 34,
- nvptx64 = 35,
- le32 = 36,
- le64 = 37,
- amdil = 38,
- amdil64 = 39,
- hsail = 40,
- hsail64 = 41,
- spir = 42,
- spir64 = 43,
- kalimba = 44,
- shave = 45,
- lanai = 46,
- wasm32 = 47,
- wasm64 = 48,
- renderscript32 = 49,
- renderscript64 = 50,
- ve = 51,
-};
-
-pub const ParseCommandLineOptions = ZigLLVMParseCommandLineOptions;
-extern fn ZigLLVMParseCommandLineOptions(argc: usize, argv: [*]const [*:0]const u8) void;
-
-pub const WriteImportLibrary = ZigLLVMWriteImportLibrary;
-extern fn ZigLLVMWriteImportLibrary(
- def_path: [*:0]const u8,
- arch: ArchType,
- output_lib_path: [*c]const u8,
- kill_at: bool,
-) bool;
diff --git a/src/llvm_backend.zig b/src/llvm_backend.zig
@@ -0,0 +1,442 @@
+const std = @import("std");
+const Allocator = std.mem.Allocator;
+const Compilation = @import("Compilation.zig");
+const llvm = @import("llvm_bindings.zig");
+const link = @import("link.zig");
+
+const Module = @import("Module.zig");
+const TypedValue = @import("TypedValue.zig");
+const ir = @import("ir.zig");
+const Inst = ir.Inst;
+
+const Value = @import("value.zig").Value;
+const Type = @import("type.zig").Type;
+
+pub fn targetTriple(allocator: *Allocator, target: std.Target) ![:0]u8 {
+ const llvm_arch = switch (target.cpu.arch) {
+ .arm => "arm",
+ .armeb => "armeb",
+ .aarch64 => "aarch64",
+ .aarch64_be => "aarch64_be",
+ .aarch64_32 => "aarch64_32",
+ .arc => "arc",
+ .avr => "avr",
+ .bpfel => "bpfel",
+ .bpfeb => "bpfeb",
+ .hexagon => "hexagon",
+ .mips => "mips",
+ .mipsel => "mipsel",
+ .mips64 => "mips64",
+ .mips64el => "mips64el",
+ .msp430 => "msp430",
+ .powerpc => "powerpc",
+ .powerpc64 => "powerpc64",
+ .powerpc64le => "powerpc64le",
+ .r600 => "r600",
+ .amdgcn => "amdgcn",
+ .riscv32 => "riscv32",
+ .riscv64 => "riscv64",
+ .sparc => "sparc",
+ .sparcv9 => "sparcv9",
+ .sparcel => "sparcel",
+ .s390x => "s390x",
+ .tce => "tce",
+ .tcele => "tcele",
+ .thumb => "thumb",
+ .thumbeb => "thumbeb",
+ .i386 => "i386",
+ .x86_64 => "x86_64",
+ .xcore => "xcore",
+ .nvptx => "nvptx",
+ .nvptx64 => "nvptx64",
+ .le32 => "le32",
+ .le64 => "le64",
+ .amdil => "amdil",
+ .amdil64 => "amdil64",
+ .hsail => "hsail",
+ .hsail64 => "hsail64",
+ .spir => "spir",
+ .spir64 => "spir64",
+ .kalimba => "kalimba",
+ .shave => "shave",
+ .lanai => "lanai",
+ .wasm32 => "wasm32",
+ .wasm64 => "wasm64",
+ .renderscript32 => "renderscript32",
+ .renderscript64 => "renderscript64",
+ .ve => "ve",
+ .spu_2 => return error.LLVMBackendDoesNotSupportSPUMarkII,
+ };
+ // TODO Add a sub-arch for some architectures depending on CPU features.
+
+ const llvm_os = switch (target.os.tag) {
+ .freestanding => "unknown",
+ .ananas => "ananas",
+ .cloudabi => "cloudabi",
+ .dragonfly => "dragonfly",
+ .freebsd => "freebsd",
+ .fuchsia => "fuchsia",
+ .ios => "ios",
+ .kfreebsd => "kfreebsd",
+ .linux => "linux",
+ .lv2 => "lv2",
+ .macos => "macosx",
+ .netbsd => "netbsd",
+ .openbsd => "openbsd",
+ .solaris => "solaris",
+ .windows => "windows",
+ .haiku => "haiku",
+ .minix => "minix",
+ .rtems => "rtems",
+ .nacl => "nacl",
+ .cnk => "cnk",
+ .aix => "aix",
+ .cuda => "cuda",
+ .nvcl => "nvcl",
+ .amdhsa => "amdhsa",
+ .ps4 => "ps4",
+ .elfiamcu => "elfiamcu",
+ .tvos => "tvos",
+ .watchos => "watchos",
+ .mesa3d => "mesa3d",
+ .contiki => "contiki",
+ .amdpal => "amdpal",
+ .hermit => "hermit",
+ .hurd => "hurd",
+ .wasi => "wasi",
+ .emscripten => "emscripten",
+ .uefi => "windows",
+ .other => "unknown",
+ };
+
+ const llvm_abi = switch (target.abi) {
+ .none => "unknown",
+ .gnu => "gnu",
+ .gnuabin32 => "gnuabin32",
+ .gnuabi64 => "gnuabi64",
+ .gnueabi => "gnueabi",
+ .gnueabihf => "gnueabihf",
+ .gnux32 => "gnux32",
+ .code16 => "code16",
+ .eabi => "eabi",
+ .eabihf => "eabihf",
+ .android => "android",
+ .musl => "musl",
+ .musleabi => "musleabi",
+ .musleabihf => "musleabihf",
+ .msvc => "msvc",
+ .itanium => "itanium",
+ .cygnus => "cygnus",
+ .coreclr => "coreclr",
+ .simulator => "simulator",
+ .macabi => "macabi",
+ };
+
+ return std.fmt.allocPrintZ(allocator, "{}-unknown-{}-{}", .{ llvm_arch, llvm_os, llvm_abi });
+}
+
+pub const LLVMIRModule = struct {
+ module: *Module,
+ llvm_module: *const llvm.ModuleRef,
+ target_machine: *const llvm.TargetMachineRef,
+ builder: *const llvm.BuilderRef,
+
+ output_path: []const u8,
+
+ gpa: *Allocator,
+ err_msg: ?*Compilation.ErrorMsg = null,
+
+ pub fn create(allocator: *Allocator, sub_path: []const u8, options: link.Options) !*LLVMIRModule {
+ const self = try allocator.create(LLVMIRModule);
+ errdefer allocator.destroy(self);
+
+ const gpa = options.module.?.gpa;
+
+ initializeLLVMTargets();
+
+ const root_nameZ = try gpa.dupeZ(u8, options.root_name);
+ defer gpa.free(root_nameZ);
+ const llvm_module = llvm.ModuleRef.createWithName(root_nameZ.ptr);
+ errdefer llvm_module.disposeModule();
+
+ const llvm_target_triple = try targetTriple(gpa, options.target);
+ defer gpa.free(llvm_target_triple);
+
+ var error_message: [*:0]const u8 = undefined;
+ var target_ref: *const llvm.TargetRef = undefined;
+ if (llvm.TargetRef.getTargetFromTriple(llvm_target_triple.ptr, &target_ref, &error_message)) {
+ defer llvm.disposeMessage(error_message);
+
+ const stderr = std.io.getStdErr().outStream();
+ try stderr.print(
+ \\Zig is expecting LLVM to understand this target: '{s}'
+ \\However LLVM responded with: "{s}"
+ \\Zig is unable to continue. This is a bug in Zig:
+ \\https://github.com/ziglang/zig/issues/438
+ \\
+ ,
+ .{
+ llvm_target_triple,
+ error_message,
+ },
+ );
+ return error.InvalidLLVMTriple;
+ }
+
+ const opt_level: llvm.CodeGenOptLevel = if (options.optimize_mode == .Debug) .None else .Aggressive;
+ const target_machine = llvm.TargetMachineRef.createTargetMachine(
+ target_ref,
+ llvm_target_triple.ptr,
+ "",
+ "",
+ opt_level,
+ .Static,
+ .Default,
+ );
+ errdefer target_machine.disposeTargetMachine();
+
+ const builder = llvm.BuilderRef.createBuilder();
+ errdefer builder.disposeBuilder();
+
+ self.* = .{
+ .module = options.module.?,
+ .llvm_module = llvm_module,
+ .target_machine = target_machine,
+ .builder = builder,
+ .output_path = sub_path,
+ .gpa = gpa,
+ };
+ return self;
+ }
+
+ pub fn deinit(self: *LLVMIRModule, allocator: *Allocator) void {
+ self.builder.disposeBuilder();
+ self.target_machine.disposeTargetMachine();
+ self.llvm_module.disposeModule();
+ allocator.destroy(self);
+ }
+
+ fn initializeLLVMTargets() void {
+ llvm.initializeAllTargets();
+ llvm.initializeAllTargetInfos();
+ llvm.initializeAllTargetMCs();
+ llvm.initializeAllAsmPrinters();
+ llvm.initializeAllAsmParsers();
+ }
+
+ pub fn flushModule(self: *LLVMIRModule, comp: *Compilation) !void {
+ if (comp.verbose_llvm_ir) {
+ const dump = self.llvm_module.printToString();
+ defer llvm.disposeMessage(dump);
+
+ const stderr = std.io.getStdErr().outStream();
+ try stderr.writeAll(std.mem.spanZ(dump));
+ }
+
+ {
+ var error_message: [*:0]const u8 = undefined;
+ // verifyModule always allocs the error_message even if there is no error
+ defer llvm.disposeMessage(error_message);
+
+ if (self.llvm_module.verifyModule(.ReturnStatus, &error_message)) {
+ const stderr = std.io.getStdErr().outStream();
+ try stderr.print("broken LLVM module found: {s}\nThis is a bug in the Zig compiler.", .{error_message});
+ return error.BrokenLLVMModule;
+ }
+ }
+
+ const output_pathZ = try self.gpa.dupeZ(u8, self.output_path);
+ defer self.gpa.free(output_pathZ);
+
+ var error_message: [*:0]const u8 = undefined;
+ // TODO: where to put the output object, zig-cache something?
+ // TODO: caching?
+ if (self.target_machine.emitToFile(
+ self.llvm_module,
+ output_pathZ.ptr,
+ .ObjectFile,
+ &error_message,
+ )) {
+ defer llvm.disposeMessage(error_message);
+
+ const stderr = std.io.getStdErr().outStream();
+ try stderr.print("LLVM failed to emit file: {s}\n", .{error_message});
+ return error.FailedToEmit;
+ }
+ }
+
+ pub fn updateDecl(self: *LLVMIRModule, module: *Module, decl: *Module.Decl) !void {
+ const typed_value = decl.typed_value.most_recent.typed_value;
+ self.gen(module, typed_value, decl.src()) catch |err| switch (err) {
+ error.CodegenFail => {
+ decl.analysis = .codegen_failure;
+ try module.failed_decls.put(module.gpa, decl, self.err_msg.?);
+ return;
+ },
+ else => |e| return e,
+ };
+ }
+
+ fn gen(self: *LLVMIRModule, module: *Module, typed_value: TypedValue, src: usize) !void {
+ switch (typed_value.ty.zigTypeTag()) {
+ .Fn => {
+ const func = typed_value.val.cast(Value.Payload.Function).?.func;
+
+ const llvm_func = try self.resolveLLVMFunction(func);
+
+ // We remove all the basic blocks of a function to support incremental
+ // compilation!
+ // TODO: remove all basic blocks if functions can have more than one
+ if (llvm_func.getFirstBasicBlock()) |bb| {
+ bb.deleteBasicBlock();
+ }
+
+ const entry_block = llvm_func.appendBasicBlock("Entry");
+ self.builder.positionBuilderAtEnd(entry_block);
+
+ const instructions = func.analysis.success.instructions;
+ for (instructions) |inst| {
+ switch (inst.tag) {
+ .breakpoint => try self.genBreakpoint(inst.castTag(.breakpoint).?),
+ .call => try self.genCall(inst.castTag(.call).?),
+ .unreach => self.genUnreach(inst.castTag(.unreach).?),
+ .retvoid => self.genRetVoid(inst.castTag(.retvoid).?),
+ .arg => self.genArg(inst.castTag(.arg).?),
+ .dbg_stmt => {
+ // TODO: implement debug info
+ },
+ else => |tag| return self.fail(src, "TODO implement LLVM codegen for Zir instruction: {}", .{tag}),
+ }
+ }
+ },
+ else => |ty| return self.fail(src, "TODO implement LLVM codegen for top-level decl type: {}", .{ty}),
+ }
+ }
+
+ fn genCall(self: *LLVMIRModule, inst: *Inst.Call) !void {
+ if (inst.func.cast(Inst.Constant)) |func_inst| {
+ if (func_inst.val.cast(Value.Payload.Function)) |func_val| {
+ const func = func_val.func;
+ const zig_fn_type = func.owner_decl.typed_value.most_recent.typed_value.ty;
+ const llvm_fn = try self.resolveLLVMFunction(func);
+
+ const num_args = inst.args.len;
+
+ const llvm_param_vals = try self.gpa.alloc(*const llvm.ValueRef, num_args);
+ defer self.gpa.free(llvm_param_vals);
+
+ for (inst.args) |arg, i| {
+ llvm_param_vals[i] = try self.resolveInst(arg);
+ }
+
+ // TODO: LLVMBuildCall2 handles opaque function pointers, according to llvm docs
+ // Do we need that?
+ const call = self.builder.buildCall(
+ llvm_fn,
+ if (num_args == 0) null else llvm_param_vals.ptr,
+ @intCast(c_uint, num_args),
+ "",
+ );
+
+ if (zig_fn_type.fnReturnType().zigTypeTag() == .NoReturn) {
+ _ = self.builder.buildUnreachable();
+ }
+ }
+ }
+ }
+
+ fn genRetVoid(self: *LLVMIRModule, inst: *Inst.NoOp) void {
+ _ = self.builder.buildRetVoid();
+ }
+
+ fn genUnreach(self: *LLVMIRModule, inst: *Inst.NoOp) void {
+ _ = self.builder.buildUnreachable();
+ }
+
+ fn genArg(self: *LLVMIRModule, inst: *Inst.Arg) void {
+ // TODO: implement this
+ }
+
+ fn genBreakpoint(self: *LLVMIRModule, inst: *Inst.NoOp) !void {
+ // TODO: Store this function somewhere such that we dont have to add it again
+ const fn_type = llvm.TypeRef.functionType(llvm.voidType(), null, 0, false);
+ const func = self.llvm_module.addFunction("llvm.debugtrap", fn_type);
+ // TODO: add assertion: LLVMGetIntrinsicID
+ _ = self.builder.buildCall(func, null, 0, "");
+ }
+
+ fn resolveInst(self: *LLVMIRModule, inst: *ir.Inst) !*const llvm.ValueRef {
+ if (inst.castTag(.constant)) |const_inst| {
+ return self.genTypedValue(inst.src, .{ .ty = inst.ty, .val = const_inst.val });
+ }
+ return self.fail(inst.src, "TODO implement resolveInst", .{});
+ }
+
+ fn genTypedValue(self: *LLVMIRModule, src: usize, typed_value: TypedValue) !*const llvm.ValueRef {
+ const llvm_type = self.getLLVMType(typed_value.ty);
+
+ if (typed_value.val.isUndef())
+ return llvm_type.getUndef();
+
+ switch (typed_value.ty.zigTypeTag()) {
+ .Bool => return if (typed_value.val.toBool()) llvm_type.constAllOnes() else llvm_type.constNull(),
+ else => return self.fail(src, "TODO implement const of type '{}'", .{typed_value.ty}),
+ }
+ }
+
+ /// If the llvm function does not exist, create it
+ fn resolveLLVMFunction(self: *LLVMIRModule, func: *Module.Fn) !*const llvm.ValueRef {
+ // TODO: do we want to store this in our own datastructure?
+ if (self.llvm_module.getNamedFunction(func.owner_decl.name)) |llvm_fn| return llvm_fn;
+
+ const zig_fn_type = func.owner_decl.typed_value.most_recent.typed_value.ty;
+ const return_type = zig_fn_type.fnReturnType();
+
+ const fn_param_len = zig_fn_type.fnParamLen();
+
+ const fn_param_types = try self.gpa.alloc(Type, fn_param_len);
+ defer self.gpa.free(fn_param_types);
+ zig_fn_type.fnParamTypes(fn_param_types);
+
+ const llvm_param = try self.gpa.alloc(*const llvm.TypeRef, fn_param_len);
+ defer self.gpa.free(llvm_param);
+
+ for (fn_param_types) |fn_param, i| {
+ llvm_param[i] = self.getLLVMType(fn_param);
+ }
+
+ const fn_type = llvm.TypeRef.functionType(
+ self.getLLVMType(return_type),
+ if (fn_param_len == 0) null else llvm_param.ptr,
+ @intCast(c_uint, fn_param_len),
+ false,
+ );
+ const llvm_fn = self.llvm_module.addFunction(func.owner_decl.name, fn_type);
+
+ if (return_type.zigTypeTag() == .NoReturn) {
+ llvm_fn.addFnAttr("noreturn");
+ }
+
+ return llvm_fn;
+ }
+
+ fn getLLVMType(self: *LLVMIRModule, t: Type) *const llvm.TypeRef {
+ switch (t.zigTypeTag()) {
+ .Void => return llvm.voidType(),
+ .NoReturn => return llvm.voidType(),
+ .Int => {
+ const info = t.intInfo(self.module.getTarget());
+ return llvm.intType(info.bits);
+ },
+ .Bool => return llvm.intType(1),
+ else => unreachable,
+ }
+ }
+
+ pub fn fail(self: *LLVMIRModule, src: usize, comptime format: []const u8, args: anytype) error{ OutOfMemory, CodegenFail } {
+ @setCold(true);
+ std.debug.assert(self.err_msg == null);
+ self.err_msg = try Compilation.ErrorMsg.create(self.gpa, src, format, args);
+ return error.CodegenFail;
+ }
+};
diff --git a/src/llvm_bindings.zig b/src/llvm_bindings.zig
@@ -0,0 +1,507 @@
+//! We do this instead of @cImport because the self-hosted compiler is easier
+//! to bootstrap if it does not depend on translate-c.
+
+const std = @import("std");
+const assert = std.debug.assert;
+
+const LLVMBool = bool;
+pub const LLVMAttributeIndex = c_uint;
+
+pub const ValueRef = opaque {
+ pub const addAttributeAtIndex = LLVMAddAttributeAtIndex;
+ extern fn LLVMAddAttributeAtIndex(*const ValueRef, Idx: LLVMAttributeIndex, A: *const AttributeRef) void;
+
+ pub const appendBasicBlock = LLVMAppendBasicBlock;
+ extern fn LLVMAppendBasicBlock(Fn: *const ValueRef, Name: [*:0]const u8) *const BasicBlockRef;
+
+ pub const getFirstBasicBlock = LLVMGetFirstBasicBlock;
+ extern fn LLVMGetFirstBasicBlock(Fn: *const ValueRef) ?*const BasicBlockRef;
+
+ // Helper functions
+ // TODO: Do we want to put these functions here? It allows for convienient function calls
+ // on ValueRef: llvm_fn.addFnAttr("noreturn")
+ fn addAttr(val: *const ValueRef, index: LLVMAttributeIndex, name: []const u8) void {
+ const kind_id = getEnumAttributeKindForName(name.ptr, name.len);
+ assert(kind_id != 0);
+ const llvm_attr = ContextRef.getGlobal().createEnumAttribute(kind_id, 0);
+ val.addAttributeAtIndex(index, llvm_attr);
+ }
+
+ pub fn addFnAttr(val: *const ValueRef, attr_name: []const u8) void {
+ // TODO: improve this API, `addAttr(-1, attr_name)`
+ val.addAttr(std.math.maxInt(LLVMAttributeIndex), attr_name);
+ }
+};
+
+pub const TypeRef = opaque {
+ pub const functionType = LLVMFunctionType;
+ extern fn LLVMFunctionType(ReturnType: *const TypeRef, ParamTypes: ?[*]*const TypeRef, ParamCount: c_uint, IsVarArg: LLVMBool) *const TypeRef;
+
+ pub const constNull = LLVMConstNull;
+ extern fn LLVMConstNull(Ty: *const TypeRef) *const ValueRef;
+
+ pub const constAllOnes = LLVMConstAllOnes;
+ extern fn LLVMConstAllOnes(Ty: *const TypeRef) *const ValueRef;
+
+ pub const getUndef = LLVMGetUndef;
+ extern fn LLVMGetUndef(Ty: *const TypeRef) *const ValueRef;
+};
+
+pub const ModuleRef = opaque {
+ pub const createWithName = LLVMModuleCreateWithName;
+ extern fn LLVMModuleCreateWithName(ModuleID: [*:0]const u8) *const ModuleRef;
+
+ pub const disposeModule = LLVMDisposeModule;
+ extern fn LLVMDisposeModule(*const ModuleRef) void;
+
+ pub const verifyModule = LLVMVerifyModule;
+ extern fn LLVMVerifyModule(*const ModuleRef, Action: VerifierFailureAction, OutMessage: *[*:0]const u8) LLVMBool;
+
+ pub const addFunction = LLVMAddFunction;
+ extern fn LLVMAddFunction(*const ModuleRef, Name: [*:0]const u8, FunctionTy: *const TypeRef) *const ValueRef;
+
+ pub const getNamedFunction = LLVMGetNamedFunction;
+ extern fn LLVMGetNamedFunction(*const ModuleRef, Name: [*:0]const u8) ?*const ValueRef;
+
+ pub const printToString = LLVMPrintModuleToString;
+ extern fn LLVMPrintModuleToString(*const ModuleRef) [*:0]const u8;
+};
+
+pub const disposeMessage = LLVMDisposeMessage;
+extern fn LLVMDisposeMessage(Message: [*:0]const u8) void;
+
+pub const VerifierFailureAction = extern enum {
+ AbortProcess,
+ PrintMessage,
+ ReturnStatus,
+};
+
+pub const voidType = LLVMVoidType;
+extern fn LLVMVoidType() *const TypeRef;
+
+pub const getEnumAttributeKindForName = LLVMGetEnumAttributeKindForName;
+extern fn LLVMGetEnumAttributeKindForName(Name: [*]const u8, SLen: usize) c_uint;
+
+pub const AttributeRef = opaque {};
+
+pub const ContextRef = opaque {
+ pub const createEnumAttribute = LLVMCreateEnumAttribute;
+ extern fn LLVMCreateEnumAttribute(*const ContextRef, KindID: c_uint, Val: u64) *const AttributeRef;
+
+ pub const getGlobal = LLVMGetGlobalContext;
+ extern fn LLVMGetGlobalContext() *const ContextRef;
+};
+
+pub const intType = LLVMIntType;
+extern fn LLVMIntType(NumBits: c_uint) *const TypeRef;
+
+pub const BuilderRef = opaque {
+ pub const createBuilder = LLVMCreateBuilder;
+ extern fn LLVMCreateBuilder() *const BuilderRef;
+
+ pub const disposeBuilder = LLVMDisposeBuilder;
+ extern fn LLVMDisposeBuilder(Builder: *const BuilderRef) void;
+
+ pub const positionBuilderAtEnd = LLVMPositionBuilderAtEnd;
+ extern fn LLVMPositionBuilderAtEnd(Builder: *const BuilderRef, Block: *const BasicBlockRef) void;
+
+ pub const getInsertBlock = LLVMGetInsertBlock;
+ extern fn LLVMGetInsertBlock(Builder: *const BuilderRef) *const BasicBlockRef;
+
+ pub const buildCall = LLVMBuildCall;
+ extern fn LLVMBuildCall(*const BuilderRef, Fn: *const ValueRef, Args: ?[*]*const ValueRef, NumArgs: c_uint, Name: [*:0]const u8) *const ValueRef;
+
+ pub const buildCall2 = LLVMBuildCall2;
+ extern fn LLVMBuildCall2(*const BuilderRef, *const TypeRef, Fn: *const ValueRef, Args: [*]*const ValueRef, NumArgs: c_uint, Name: [*:0]const u8) *const ValueRef;
+
+ pub const buildRetVoid = LLVMBuildRetVoid;
+ extern fn LLVMBuildRetVoid(*const BuilderRef) *const ValueRef;
+
+ pub const buildUnreachable = LLVMBuildUnreachable;
+ extern fn LLVMBuildUnreachable(*const BuilderRef) *const ValueRef;
+
+ pub const buildAlloca = LLVMBuildAlloca;
+ extern fn LLVMBuildAlloca(*const BuilderRef, Ty: *const TypeRef, Name: [*:0]const u8) *const ValueRef;
+};
+
+pub const BasicBlockRef = opaque {
+ pub const deleteBasicBlock = LLVMDeleteBasicBlock;
+ extern fn LLVMDeleteBasicBlock(BB: *const BasicBlockRef) void;
+};
+
+pub const TargetMachineRef = opaque {
+ pub const createTargetMachine = LLVMCreateTargetMachine;
+ extern fn LLVMCreateTargetMachine(
+ T: *const TargetRef,
+ Triple: [*:0]const u8,
+ CPU: [*:0]const u8,
+ Features: [*:0]const u8,
+ Level: CodeGenOptLevel,
+ Reloc: RelocMode,
+ CodeModel: CodeMode,
+ ) *const TargetMachineRef;
+
+ pub const disposeTargetMachine = LLVMDisposeTargetMachine;
+ extern fn LLVMDisposeTargetMachine(T: *const TargetMachineRef) void;
+
+ pub const emitToFile = LLVMTargetMachineEmitToFile;
+ extern fn LLVMTargetMachineEmitToFile(*const TargetMachineRef, M: *const ModuleRef, Filename: [*:0]const u8, codegen: CodeGenFileType, ErrorMessage: *[*:0]const u8) LLVMBool;
+};
+
+pub const CodeMode = extern enum {
+ Default,
+ JITDefault,
+ Tiny,
+ Small,
+ Kernel,
+ Medium,
+ Large,
+};
+
+pub const CodeGenOptLevel = extern enum {
+ None,
+ Less,
+ Default,
+ Aggressive,
+};
+
+pub const RelocMode = extern enum {
+ Default,
+ Static,
+ PIC,
+ DynamicNoPic,
+ ROPI,
+ RWPI,
+ ROPI_RWPI,
+};
+
+pub const CodeGenFileType = extern enum {
+ AssemblyFile,
+ ObjectFile,
+};
+
+pub const TargetRef = opaque {
+ pub const getTargetFromTriple = LLVMGetTargetFromTriple;
+ extern fn LLVMGetTargetFromTriple(Triple: [*:0]const u8, T: **const TargetRef, ErrorMessage: *[*:0]const u8) LLVMBool;
+};
+
+extern fn LLVMInitializeAArch64TargetInfo() void;
+extern fn LLVMInitializeAMDGPUTargetInfo() void;
+extern fn LLVMInitializeARMTargetInfo() void;
+extern fn LLVMInitializeAVRTargetInfo() void;
+extern fn LLVMInitializeBPFTargetInfo() void;
+extern fn LLVMInitializeHexagonTargetInfo() void;
+extern fn LLVMInitializeLanaiTargetInfo() void;
+extern fn LLVMInitializeMipsTargetInfo() void;
+extern fn LLVMInitializeMSP430TargetInfo() void;
+extern fn LLVMInitializeNVPTXTargetInfo() void;
+extern fn LLVMInitializePowerPCTargetInfo() void;
+extern fn LLVMInitializeRISCVTargetInfo() void;
+extern fn LLVMInitializeSparcTargetInfo() void;
+extern fn LLVMInitializeSystemZTargetInfo() void;
+extern fn LLVMInitializeWebAssemblyTargetInfo() void;
+extern fn LLVMInitializeX86TargetInfo() void;
+extern fn LLVMInitializeXCoreTargetInfo() void;
+extern fn LLVMInitializeAArch64Target() void;
+extern fn LLVMInitializeAMDGPUTarget() void;
+extern fn LLVMInitializeARMTarget() void;
+extern fn LLVMInitializeAVRTarget() void;
+extern fn LLVMInitializeBPFTarget() void;
+extern fn LLVMInitializeHexagonTarget() void;
+extern fn LLVMInitializeLanaiTarget() void;
+extern fn LLVMInitializeMipsTarget() void;
+extern fn LLVMInitializeMSP430Target() void;
+extern fn LLVMInitializeNVPTXTarget() void;
+extern fn LLVMInitializePowerPCTarget() void;
+extern fn LLVMInitializeRISCVTarget() void;
+extern fn LLVMInitializeSparcTarget() void;
+extern fn LLVMInitializeSystemZTarget() void;
+extern fn LLVMInitializeWebAssemblyTarget() void;
+extern fn LLVMInitializeX86Target() void;
+extern fn LLVMInitializeXCoreTarget() void;
+extern fn LLVMInitializeAArch64TargetMC() void;
+extern fn LLVMInitializeAMDGPUTargetMC() void;
+extern fn LLVMInitializeARMTargetMC() void;
+extern fn LLVMInitializeAVRTargetMC() void;
+extern fn LLVMInitializeBPFTargetMC() void;
+extern fn LLVMInitializeHexagonTargetMC() void;
+extern fn LLVMInitializeLanaiTargetMC() void;
+extern fn LLVMInitializeMipsTargetMC() void;
+extern fn LLVMInitializeMSP430TargetMC() void;
+extern fn LLVMInitializeNVPTXTargetMC() void;
+extern fn LLVMInitializePowerPCTargetMC() void;
+extern fn LLVMInitializeRISCVTargetMC() void;
+extern fn LLVMInitializeSparcTargetMC() void;
+extern fn LLVMInitializeSystemZTargetMC() void;
+extern fn LLVMInitializeWebAssemblyTargetMC() void;
+extern fn LLVMInitializeX86TargetMC() void;
+extern fn LLVMInitializeXCoreTargetMC() void;
+extern fn LLVMInitializeAArch64AsmPrinter() void;
+extern fn LLVMInitializeAMDGPUAsmPrinter() void;
+extern fn LLVMInitializeARMAsmPrinter() void;
+extern fn LLVMInitializeAVRAsmPrinter() void;
+extern fn LLVMInitializeBPFAsmPrinter() void;
+extern fn LLVMInitializeHexagonAsmPrinter() void;
+extern fn LLVMInitializeLanaiAsmPrinter() void;
+extern fn LLVMInitializeMipsAsmPrinter() void;
+extern fn LLVMInitializeMSP430AsmPrinter() void;
+extern fn LLVMInitializeNVPTXAsmPrinter() void;
+extern fn LLVMInitializePowerPCAsmPrinter() void;
+extern fn LLVMInitializeRISCVAsmPrinter() void;
+extern fn LLVMInitializeSparcAsmPrinter() void;
+extern fn LLVMInitializeSystemZAsmPrinter() void;
+extern fn LLVMInitializeWebAssemblyAsmPrinter() void;
+extern fn LLVMInitializeX86AsmPrinter() void;
+extern fn LLVMInitializeXCoreAsmPrinter() void;
+extern fn LLVMInitializeAArch64AsmParser() void;
+extern fn LLVMInitializeAMDGPUAsmParser() void;
+extern fn LLVMInitializeARMAsmParser() void;
+extern fn LLVMInitializeAVRAsmParser() void;
+extern fn LLVMInitializeBPFAsmParser() void;
+extern fn LLVMInitializeHexagonAsmParser() void;
+extern fn LLVMInitializeLanaiAsmParser() void;
+extern fn LLVMInitializeMipsAsmParser() void;
+extern fn LLVMInitializeMSP430AsmParser() void;
+extern fn LLVMInitializePowerPCAsmParser() void;
+extern fn LLVMInitializeRISCVAsmParser() void;
+extern fn LLVMInitializeSparcAsmParser() void;
+extern fn LLVMInitializeSystemZAsmParser() void;
+extern fn LLVMInitializeWebAssemblyAsmParser() void;
+extern fn LLVMInitializeX86AsmParser() void;
+
+pub const initializeAllTargetInfos = LLVMInitializeAllTargetInfos;
+fn LLVMInitializeAllTargetInfos() callconv(.C) void {
+ LLVMInitializeAArch64TargetInfo();
+ LLVMInitializeAMDGPUTargetInfo();
+ LLVMInitializeARMTargetInfo();
+ LLVMInitializeAVRTargetInfo();
+ LLVMInitializeBPFTargetInfo();
+ LLVMInitializeHexagonTargetInfo();
+ LLVMInitializeLanaiTargetInfo();
+ LLVMInitializeMipsTargetInfo();
+ LLVMInitializeMSP430TargetInfo();
+ LLVMInitializeNVPTXTargetInfo();
+ LLVMInitializePowerPCTargetInfo();
+ LLVMInitializeRISCVTargetInfo();
+ LLVMInitializeSparcTargetInfo();
+ LLVMInitializeSystemZTargetInfo();
+ LLVMInitializeWebAssemblyTargetInfo();
+ LLVMInitializeX86TargetInfo();
+ LLVMInitializeXCoreTargetInfo();
+}
+pub const initializeAllTargets = LLVMInitializeAllTargets;
+fn LLVMInitializeAllTargets() callconv(.C) void {
+ LLVMInitializeAArch64Target();
+ LLVMInitializeAMDGPUTarget();
+ LLVMInitializeARMTarget();
+ LLVMInitializeAVRTarget();
+ LLVMInitializeBPFTarget();
+ LLVMInitializeHexagonTarget();
+ LLVMInitializeLanaiTarget();
+ LLVMInitializeMipsTarget();
+ LLVMInitializeMSP430Target();
+ LLVMInitializeNVPTXTarget();
+ LLVMInitializePowerPCTarget();
+ LLVMInitializeRISCVTarget();
+ LLVMInitializeSparcTarget();
+ LLVMInitializeSystemZTarget();
+ LLVMInitializeWebAssemblyTarget();
+ LLVMInitializeX86Target();
+ LLVMInitializeXCoreTarget();
+}
+pub const initializeAllTargetMCs = LLVMInitializeAllTargetMCs;
+fn LLVMInitializeAllTargetMCs() callconv(.C) void {
+ LLVMInitializeAArch64TargetMC();
+ LLVMInitializeAMDGPUTargetMC();
+ LLVMInitializeARMTargetMC();
+ LLVMInitializeAVRTargetMC();
+ LLVMInitializeBPFTargetMC();
+ LLVMInitializeHexagonTargetMC();
+ LLVMInitializeLanaiTargetMC();
+ LLVMInitializeMipsTargetMC();
+ LLVMInitializeMSP430TargetMC();
+ LLVMInitializeNVPTXTargetMC();
+ LLVMInitializePowerPCTargetMC();
+ LLVMInitializeRISCVTargetMC();
+ LLVMInitializeSparcTargetMC();
+ LLVMInitializeSystemZTargetMC();
+ LLVMInitializeWebAssemblyTargetMC();
+ LLVMInitializeX86TargetMC();
+ LLVMInitializeXCoreTargetMC();
+}
+pub const initializeAllAsmPrinters = LLVMInitializeAllAsmPrinters;
+fn LLVMInitializeAllAsmPrinters() callconv(.C) void {
+ LLVMInitializeAArch64AsmPrinter();
+ LLVMInitializeAMDGPUAsmPrinter();
+ LLVMInitializeARMAsmPrinter();
+ LLVMInitializeAVRAsmPrinter();
+ LLVMInitializeBPFAsmPrinter();
+ LLVMInitializeHexagonAsmPrinter();
+ LLVMInitializeLanaiAsmPrinter();
+ LLVMInitializeMipsAsmPrinter();
+ LLVMInitializeMSP430AsmPrinter();
+ LLVMInitializeNVPTXAsmPrinter();
+ LLVMInitializePowerPCAsmPrinter();
+ LLVMInitializeRISCVAsmPrinter();
+ LLVMInitializeSparcAsmPrinter();
+ LLVMInitializeSystemZAsmPrinter();
+ LLVMInitializeWebAssemblyAsmPrinter();
+ LLVMInitializeX86AsmPrinter();
+ LLVMInitializeXCoreAsmPrinter();
+}
+pub const initializeAllAsmParsers = LLVMInitializeAllAsmParsers;
+fn LLVMInitializeAllAsmParsers() callconv(.C) void {
+ LLVMInitializeAArch64AsmParser();
+ LLVMInitializeAMDGPUAsmParser();
+ LLVMInitializeARMAsmParser();
+ LLVMInitializeAVRAsmParser();
+ LLVMInitializeBPFAsmParser();
+ LLVMInitializeHexagonAsmParser();
+ LLVMInitializeLanaiAsmParser();
+ LLVMInitializeMipsAsmParser();
+ LLVMInitializeMSP430AsmParser();
+ LLVMInitializePowerPCAsmParser();
+ LLVMInitializeRISCVAsmParser();
+ LLVMInitializeSparcAsmParser();
+ LLVMInitializeSystemZAsmParser();
+ LLVMInitializeWebAssemblyAsmParser();
+ LLVMInitializeX86AsmParser();
+}
+
+extern fn ZigLLDLinkCOFF(argc: c_int, argv: [*:null]const ?[*:0]const u8, can_exit_early: bool) c_int;
+extern fn ZigLLDLinkELF(argc: c_int, argv: [*:null]const ?[*:0]const u8, can_exit_early: bool) c_int;
+extern fn ZigLLDLinkMachO(argc: c_int, argv: [*:null]const ?[*:0]const u8, can_exit_early: bool) c_int;
+extern fn ZigLLDLinkWasm(argc: c_int, argv: [*:null]const ?[*:0]const u8, can_exit_early: bool) c_int;
+
+pub const LinkCOFF = ZigLLDLinkCOFF;
+pub const LinkELF = ZigLLDLinkELF;
+pub const LinkMachO = ZigLLDLinkMachO;
+pub const LinkWasm = ZigLLDLinkWasm;
+
+pub const ObjectFormatType = extern enum(c_int) {
+ Unknown,
+ COFF,
+ ELF,
+ MachO,
+ Wasm,
+ XCOFF,
+};
+
+pub const GetHostCPUName = LLVMGetHostCPUName;
+extern fn LLVMGetHostCPUName() ?[*:0]u8;
+
+pub const GetNativeFeatures = ZigLLVMGetNativeFeatures;
+extern fn ZigLLVMGetNativeFeatures() ?[*:0]u8;
+
+pub const WriteArchive = ZigLLVMWriteArchive;
+extern fn ZigLLVMWriteArchive(
+ archive_name: [*:0]const u8,
+ file_names_ptr: [*]const [*:0]const u8,
+ file_names_len: usize,
+ os_type: OSType,
+) bool;
+
+pub const OSType = extern enum(c_int) {
+ UnknownOS = 0,
+ Ananas = 1,
+ CloudABI = 2,
+ Darwin = 3,
+ DragonFly = 4,
+ FreeBSD = 5,
+ Fuchsia = 6,
+ IOS = 7,
+ KFreeBSD = 8,
+ Linux = 9,
+ Lv2 = 10,
+ MacOSX = 11,
+ NetBSD = 12,
+ OpenBSD = 13,
+ Solaris = 14,
+ Win32 = 15,
+ Haiku = 16,
+ Minix = 17,
+ RTEMS = 18,
+ NaCl = 19,
+ CNK = 20,
+ AIX = 21,
+ CUDA = 22,
+ NVCL = 23,
+ AMDHSA = 24,
+ PS4 = 25,
+ ELFIAMCU = 26,
+ TvOS = 27,
+ WatchOS = 28,
+ Mesa3D = 29,
+ Contiki = 30,
+ AMDPAL = 31,
+ HermitCore = 32,
+ Hurd = 33,
+ WASI = 34,
+ Emscripten = 35,
+};
+
+pub const ArchType = extern enum(c_int) {
+ UnknownArch = 0,
+ arm = 1,
+ armeb = 2,
+ aarch64 = 3,
+ aarch64_be = 4,
+ aarch64_32 = 5,
+ arc = 6,
+ avr = 7,
+ bpfel = 8,
+ bpfeb = 9,
+ hexagon = 10,
+ mips = 11,
+ mipsel = 12,
+ mips64 = 13,
+ mips64el = 14,
+ msp430 = 15,
+ ppc = 16,
+ ppc64 = 17,
+ ppc64le = 18,
+ r600 = 19,
+ amdgcn = 20,
+ riscv32 = 21,
+ riscv64 = 22,
+ sparc = 23,
+ sparcv9 = 24,
+ sparcel = 25,
+ systemz = 26,
+ tce = 27,
+ tcele = 28,
+ thumb = 29,
+ thumbeb = 30,
+ x86 = 31,
+ x86_64 = 32,
+ xcore = 33,
+ nvptx = 34,
+ nvptx64 = 35,
+ le32 = 36,
+ le64 = 37,
+ amdil = 38,
+ amdil64 = 39,
+ hsail = 40,
+ hsail64 = 41,
+ spir = 42,
+ spir64 = 43,
+ kalimba = 44,
+ shave = 45,
+ lanai = 46,
+ wasm32 = 47,
+ wasm64 = 48,
+ renderscript32 = 49,
+ renderscript64 = 50,
+ ve = 51,
+};
+
+pub const ParseCommandLineOptions = ZigLLVMParseCommandLineOptions;
+extern fn ZigLLVMParseCommandLineOptions(argc: usize, argv: [*]const [*:0]const u8) void;
+
+pub const WriteImportLibrary = ZigLLVMWriteImportLibrary;
+extern fn ZigLLVMWriteImportLibrary(
+ def_path: [*:0]const u8,
+ arch: ArchType,
+ output_lib_path: [*c]const u8,
+ kill_at: bool,
+) bool;
diff --git a/src/main.zig b/src/main.zig
@@ -1676,7 +1676,7 @@ fn buildOutputType(
if (build_options.have_llvm and emit_asm != .no) {
// LLVM has no way to set this non-globally.
const argv = [_][*:0]const u8{ "zig (LLVM option parsing)", "--x86-asm-syntax=intel" };
- @import("llvm.zig").ParseCommandLineOptions(argv.len, &argv);
+ @import("llvm_bindings.zig").ParseCommandLineOptions(argv.len, &argv);
}
gimmeMoreOfThoseSweetSweetFileDescriptors();
@@ -2839,7 +2839,7 @@ pub fn punt_to_lld(arena: *Allocator, args: []const []const u8) error{OutOfMemor
argv[i] = try arena.dupeZ(u8, arg); // TODO If there was an argsAllocZ we could avoid this allocation.
}
const exit_code = rc: {
- const llvm = @import("llvm.zig");
+ const llvm = @import("llvm_bindings.zig");
const argc = @intCast(c_int, argv.len);
if (mem.eql(u8, args[1], "ld.lld")) {
break :rc llvm.LinkELF(argc, argv.ptr, true);
@@ -3224,7 +3224,7 @@ fn detectNativeTargetInfo(gpa: *Allocator, cross_target: std.zig.CrossTarget) !s
if (!build_options.have_llvm)
fatal("CPU features detection is not yet available for {} without LLVM extensions", .{@tagName(arch)});
- const llvm = @import("llvm.zig");
+ const llvm = @import("llvm_bindings.zig");
const llvm_cpu_name = llvm.GetHostCPUName();
const llvm_cpu_features = llvm.GetNativeFeatures();
info.target.cpu = try detectNativeCpuWithLLVM(arch, llvm_cpu_name, llvm_cpu_features);
diff --git a/src/mingw.zig b/src/mingw.zig
@@ -405,7 +405,7 @@ pub fn buildImportLib(comp: *Compilation, lib_name: []const u8) !void {
});
errdefer comp.gpa.free(lib_final_path);
- const llvm = @import("llvm.zig");
+ const llvm = @import("llvm_bindings.zig");
const arch_type = @import("target.zig").archToLLVM(target.cpu.arch);
const def_final_path_z = try arena.dupeZ(u8, def_final_path);
const lib_final_path_z = try arena.dupeZ(u8, lib_final_path);
diff --git a/src/target.zig b/src/target.zig
@@ -1,5 +1,5 @@
const std = @import("std");
-const llvm = @import("llvm.zig");
+const llvm = @import("llvm_bindings.zig");
pub const ArchOsAbi = struct {
arch: std.Target.Cpu.Arch,
diff --git a/src/zig_clang.h b/src/zig_clang.h
@@ -8,14 +8,32 @@
#ifndef ZIG_ZIG_CLANG_H
#define ZIG_ZIG_CLANG_H
-#include "stage1/stage2.h"
#include <inttypes.h>
#include <stdbool.h>
+#include <stddef.h>
+
+#ifdef __cplusplus
+#define ZIG_EXTERN_C extern "C"
+#else
+#define ZIG_EXTERN_C
+#endif
// ATTENTION: If you modify this file, be sure to update the corresponding
// extern function declarations in the self-hosted compiler file
// src/clang.zig.
+// ABI warning
+struct Stage2ErrorMsg {
+ const char *filename_ptr; // can be null
+ size_t filename_len;
+ const char *msg_ptr;
+ size_t msg_len;
+ const char *source; // valid until the ASTUnit is freed. can be null
+ unsigned line; // 0 based
+ unsigned column; // 0 based
+ unsigned offset; // byte offset into source
+};
+
struct ZigClangSourceLocation {
unsigned ID;
};