Merge pull request #7498 from FireFox317/stage2-llvm

stage2: add initial impl of LLVM backend in self-hosted compiler
This commit is contained in:
Andrew Kelley 2020-12-28 15:07:21 -08:00 committed by GitHub
commit 2df2f0020f
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
14 changed files with 1069 additions and 293 deletions

View File

@ -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"

View File

@ -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++");

View File

@ -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) {

View File

@ -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 });
}

View File

@ -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;

View File

@ -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);

View File

@ -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;

View File

@ -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;

442
src/llvm_backend.zig Normal file
View File

@ -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;
}
};

507
src/llvm_bindings.zig Normal file
View File

@ -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;

View File

@ -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);

View File

@ -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);

View File

@ -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,

View File

@ -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;
};