stage2: fix compile errors in LLVM backend

This commit is contained in:
Andrew Kelley 2021-07-18 22:49:46 -07:00
parent bf8e347b1b
commit 95756299af
3 changed files with 95 additions and 51 deletions

View File

@ -276,10 +276,71 @@ pub const Object = struct {
}
}
pub fn updateDecl(self: *Object, module: *Module, decl: *Module.Decl) !void {
const tracy = trace(@src());
defer tracy.end();
pub fn updateFunc(
self: *Object,
module: *Module,
func: *Module.Fn,
air: Air,
liveness: Liveness,
) !void {
var dg: DeclGen = .{
.object = self,
.module = module,
.decl = func.owner_decl,
.err_msg = null,
.gpa = module.gpa,
};
const llvm_func = try dg.resolveLLVMFunction(func.owner_decl);
// This gets the LLVM values from the function and stores them in `dg.args`.
const fn_param_len = func.owner_decl.ty.fnParamLen();
var args = try dg.gpa.alloc(*const llvm.Value, fn_param_len);
for (args) |*arg, i| {
arg.* = llvm.getParam(llvm_func, @intCast(c_uint, i));
}
// 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 builder = dg.context().createBuilder();
const entry_block = dg.context().appendBasicBlock(llvm_func, "Entry");
builder.positionBuilderAtEnd(entry_block);
var fg: FuncGen = .{
.gpa = dg.gpa,
.air = air,
.liveness = liveness,
.dg = &dg,
.builder = builder,
.args = args,
.arg_index = 0,
.func_inst_table = .{},
.entry_block = entry_block,
.latest_alloca_inst = null,
.llvm_func = llvm_func,
.blocks = .{},
};
defer fg.deinit();
fg.genBody(air.getMainBody()) catch |err| switch (err) {
error.CodegenFail => {
func.owner_decl.analysis = .codegen_failure;
try module.failed_decls.put(module.gpa, func.owner_decl, dg.err_msg.?);
dg.err_msg = null;
return;
},
else => |e| return e,
};
}
pub fn updateDecl(self: *Object, module: *Module, decl: *Module.Decl) !void {
var dg: DeclGen = .{
.object = self,
.module = module,
@ -330,45 +391,8 @@ pub const DeclGen = struct {
log.debug("gen: {s} type: {}, value: {}", .{ decl.name, decl.ty, decl.val });
if (decl.val.castTag(.function)) |func_payload| {
const func = func_payload.data;
const llvm_func = try self.resolveLLVMFunction(func.owner_decl);
// This gets the LLVM values from the function and stores them in `self.args`.
const fn_param_len = func.owner_decl.ty.fnParamLen();
var args = try self.gpa.alloc(*const llvm.Value, fn_param_len);
for (args) |*arg, i| {
arg.* = llvm.getParam(llvm_func, @intCast(c_uint, i));
}
// 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 builder = self.context().createBuilder();
const entry_block = self.context().appendBasicBlock(llvm_func, "Entry");
builder.positionBuilderAtEnd(entry_block);
var fg: FuncGen = .{
.gpa = self.gpa,
.dg = self,
.builder = builder,
.args = args,
.arg_index = 0,
.func_inst_table = .{},
.entry_block = entry_block,
.latest_alloca_inst = null,
.llvm_func = llvm_func,
.blocks = .{},
};
defer fg.deinit();
try fg.genBody(func.body);
_ = func_payload;
@panic("TODO llvm backend genDecl function pointer");
} else if (decl.val.castTag(.extern_fn)) |extern_fn| {
_ = try self.resolveLLVMFunction(extern_fn.data);
} else {
@ -596,6 +620,8 @@ pub const DeclGen = struct {
pub const FuncGen = struct {
gpa: *Allocator,
dg: *DeclGen,
air: Air,
liveness: Liveness,
builder: *const llvm.Builder,
@ -649,14 +675,15 @@ pub const FuncGen = struct {
if (self.air.value(inst)) |val| {
return self.dg.genTypedValue(.{ .ty = self.air.typeOf(inst), .val = val }, self);
}
if (self.func_inst_table.get(inst)) |value| return value;
const inst_index = Air.refToIndex(inst).?;
if (self.func_inst_table.get(inst_index)) |value| return value;
return self.todo("implement global llvm values (or the value is not in the func_inst_table table)", .{});
}
fn genBody(self: *FuncGen, body: ir.Body) error{ OutOfMemory, CodegenFail }!void {
fn genBody(self: *FuncGen, body: []const Air.Inst.Index) error{ OutOfMemory, CodegenFail }!void {
const air_tags = self.air.instructions.items(.tag);
for (body.instructions) |inst| {
for (body) |inst| {
const opt_value = switch (air_tags[inst]) {
.add => try self.airAdd(inst),
.sub => try self.airSub(inst),
@ -828,8 +855,8 @@ pub const FuncGen = struct {
// If the break doesn't break a value, then we don't have to add
// the values to the lists.
if (self.air.typeOf(branch.result).hasCodeGenBits()) {
const val = try self.resolveInst(branch.result);
if (self.air.typeOf(branch.operand).hasCodeGenBits()) {
const val = try self.resolveInst(branch.operand);
// For the phi node, we need the basic blocks and the values of the
// break instructions.

View File

@ -30,6 +30,7 @@ const DebugSymbols = @import("MachO/DebugSymbols.zig");
const Trie = @import("MachO/Trie.zig");
const CodeSignature = @import("MachO/CodeSignature.zig");
const Zld = @import("MachO/Zld.zig");
const llvm_backend = @import("../codegen/llvm.zig");
usingnamespace @import("MachO/commands.zig");
@ -37,6 +38,9 @@ pub const base_tag: File.Tag = File.Tag.macho;
base: File,
/// If this is not null, an object file is created by LLVM and linked with LLD afterwards.
llvm_object: ?*llvm_backend.Object = null,
/// Debug symbols bundle (or dSym).
d_sym: ?DebugSymbols = null,
@ -347,8 +351,13 @@ pub const SrcFn = struct {
pub fn openPath(allocator: *Allocator, sub_path: []const u8, options: link.Options) !*MachO {
assert(options.object_format == .macho);
if (options.use_llvm) return error.LLVM_BackendIsTODO_ForMachO; // TODO
if (options.use_lld) return error.LLD_LinkingIsTODO_ForMachO; // TODO
if (build_options.have_llvm and options.use_llvm) {
const self = try createEmpty(allocator, options);
errdefer self.base.destroy();
self.llvm_object = try llvm_backend.Object.create(allocator, sub_path, options);
return self;
}
const file = try options.emit.?.directory.handle.createFile(sub_path, .{
.truncate = false,

View File

@ -19,12 +19,15 @@ const build_options = @import("build_options");
const wasi_libc = @import("../wasi_libc.zig");
const Cache = @import("../Cache.zig");
const TypedValue = @import("../TypedValue.zig");
const llvm_backend = @import("../codegen/llvm.zig");
const Air = @import("../Air.zig");
const Liveness = @import("../Liveness.zig");
pub const base_tag = link.File.Tag.wasm;
base: link.File,
/// If this is not null, an object file is created by LLVM and linked with LLD afterwards.
llvm_object: ?*llvm_backend.Object = null,
/// List of all function Decls to be written to the output file. The index of
/// each Decl in this list at the time of writing the binary is used as the
/// function index. In the event where ext_funcs' size is not 0, the index of
@ -114,8 +117,13 @@ pub const DeclBlock = struct {
pub fn openPath(allocator: *Allocator, sub_path: []const u8, options: link.Options) !*Wasm {
assert(options.object_format == .wasm);
if (options.use_llvm) return error.LLVM_BackendIsTODO_ForWasm; // TODO
if (options.use_lld) return error.LLD_LinkingIsTODO_ForWasm; // TODO
if (build_options.have_llvm and options.use_llvm) {
const self = try createEmpty(allocator, options);
errdefer self.base.destroy();
self.llvm_object = try llvm_backend.Object.create(allocator, sub_path, options);
return self;
}
// TODO: read the file and keep valid parts instead of truncating
const file = try options.emit.?.directory.handle.createFile(sub_path, .{ .truncate = true, .read = true });