2019-09-21 02:40:21 +00:00
|
|
|
const std = @import("std");
|
|
|
|
const ast = @import("ast.zig");
|
|
|
|
const llvm = @import("llvm.zig");
|
|
|
|
|
2019-09-22 02:56:22 +00:00
|
|
|
fn sliceify(non_slice: ?[*]const u8) []const u8 {
|
|
|
|
if (non_slice == null) return "";
|
|
|
|
return non_slice.?[0..std.mem.len(u8, non_slice.?)];
|
|
|
|
}
|
|
|
|
|
2019-09-22 21:26:00 +00:00
|
|
|
pub const CompileError = error{LLVMError};
|
|
|
|
|
2019-09-21 02:40:21 +00:00
|
|
|
pub const Codegen = struct {
|
|
|
|
allocator: *std.mem.Allocator,
|
|
|
|
|
|
|
|
pub fn init(allocator: *std.mem.Allocator) Codegen {
|
|
|
|
return Codegen{ .allocator = allocator };
|
|
|
|
}
|
|
|
|
|
|
|
|
fn genNode(
|
|
|
|
self: *Codegen,
|
|
|
|
mod: llvm.LLVMModuleRef,
|
|
|
|
node: *const ast.Node,
|
|
|
|
) !void {
|
|
|
|
switch (node.*) {
|
|
|
|
.Root => @panic("Should not have gotten Root"),
|
|
|
|
.FnDecl => |decl| {
|
|
|
|
const name = decl.func_name.lexeme;
|
|
|
|
const name_cstr = try std.cstr.addNullByte(self.allocator, name);
|
|
|
|
errdefer self.allocator.free(name_cstr);
|
|
|
|
|
|
|
|
//const ret_type = decl.return_type.lexeme;
|
|
|
|
|
|
|
|
var param_types = llvm.LLVMTypeList.init(self.allocator);
|
|
|
|
errdefer param_types.deinit();
|
|
|
|
|
|
|
|
for (decl.params.toSlice()) |param| {
|
|
|
|
try param_types.append(llvm.LLVMInt32Type());
|
|
|
|
}
|
|
|
|
|
|
|
|
var ret_type = llvm.LLVMFunctionType(
|
|
|
|
llvm.LLVMInt32Type(),
|
|
|
|
param_types.toSlice().ptr,
|
|
|
|
@intCast(c_uint, param_types.len),
|
|
|
|
0,
|
|
|
|
);
|
|
|
|
|
|
|
|
var func = llvm.LLVMAddFunction(mod, name_cstr.ptr, ret_type);
|
|
|
|
var entry = llvm.LLVMAppendBasicBlock(func, c"entry");
|
|
|
|
|
|
|
|
var builder = llvm.LLVMCreateBuilder();
|
|
|
|
llvm.LLVMPositionBuilderAtEnd(builder, entry);
|
|
|
|
|
|
|
|
// TODO codegen decl.body
|
|
|
|
var tmp = llvm.LLVMBuildAdd(
|
|
|
|
builder,
|
|
|
|
llvm.LLVMGetParam(func, 0),
|
|
|
|
llvm.LLVMGetParam(func, 1),
|
|
|
|
c"tmp",
|
|
|
|
);
|
|
|
|
|
|
|
|
_ = llvm.LLVMBuildRet(builder, tmp);
|
|
|
|
std.debug.warn("cgen: fn decl done\n");
|
|
|
|
},
|
|
|
|
else => {
|
|
|
|
std.debug.warn("got unhandled Node {}\n", node.*);
|
|
|
|
unreachable;
|
|
|
|
},
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn gen(self: *Codegen, root: *ast.Node) !void {
|
|
|
|
std.debug.warn("cgen: start gen\n");
|
2019-09-22 02:56:22 +00:00
|
|
|
_ = llvm.LLVMInitializeNativeTarget();
|
2019-09-21 15:31:47 +00:00
|
|
|
|
|
|
|
var mod = llvm.LLVMModuleCreateWithName(c"awoo").?;
|
2019-09-21 02:40:21 +00:00
|
|
|
defer llvm.LLVMDisposeModule(mod);
|
|
|
|
|
|
|
|
for (root.Root.toSlice()) |child| {
|
|
|
|
std.debug.warn("cgen: gen child {}\n", child);
|
|
|
|
try self.genNode(mod, &child);
|
|
|
|
}
|
|
|
|
|
|
|
|
var err: ?[*]u8 = null;
|
2019-09-22 02:56:22 +00:00
|
|
|
defer llvm.LLVMDisposeMessage(err);
|
|
|
|
|
2019-09-21 02:40:21 +00:00
|
|
|
_ = llvm.LLVMVerifyModule(
|
|
|
|
mod,
|
|
|
|
llvm.LLVMVerifierFailureAction.LLVMAbortProcessAction,
|
|
|
|
&err,
|
|
|
|
);
|
2019-09-21 15:37:41 +00:00
|
|
|
|
|
|
|
if (llvm.LLVMWriteBitcodeToFile(mod, c"awoo.bc") != 0) {
|
2019-09-22 02:56:22 +00:00
|
|
|
std.debug.warn("error writing bitcode to file: {}\n", sliceify(err));
|
2019-09-22 21:26:00 +00:00
|
|
|
return CompileError.LLVMError;
|
2019-09-22 02:56:22 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
//llvm.InitializeAllTargetInfos();
|
|
|
|
//llvm.InitializeAllTargets();
|
|
|
|
//llvm.InitializeAllTargetMCs();
|
|
|
|
//llvm.InitializeAllAsmParsers();
|
|
|
|
//llvm.InitializeAllAsmPrinters();
|
|
|
|
|
|
|
|
var engine: llvm.LLVMExecutionEngineRef = undefined;
|
|
|
|
if (llvm.LLVMCreateExecutionEngineForModule(&engine, mod, &err) != 0) {
|
|
|
|
std.debug.warn("failed to create execution engine: {}\n", sliceify(err));
|
2019-09-22 21:26:00 +00:00
|
|
|
return CompileError.LLVMError;
|
2019-09-22 02:56:22 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
var machine = llvm.LLVMGetExecutionEngineTargetMachine(engine);
|
|
|
|
defer llvm.LLVMDisposeTargetMachine(machine);
|
|
|
|
|
|
|
|
var target = llvm.LLVMGetTargetMachineTarget(machine);
|
|
|
|
var target_data = llvm.LLVMCreateTargetDataLayout(machine);
|
|
|
|
var data_layout = llvm.LLVMCopyStringRepOfTargetData(target_data);
|
|
|
|
llvm.LLVMSetDataLayout(mod, data_layout);
|
|
|
|
|
|
|
|
var outpath = try std.mem.dupe(self.allocator, u8, "output.o");
|
|
|
|
var outpath_cstr = try std.cstr.addNullByte(self.allocator, outpath);
|
|
|
|
|
|
|
|
var desc = llvm.LLVMGetTargetDescription(target);
|
|
|
|
var features = llvm.LLVMGetTargetMachineFeatureString(machine);
|
|
|
|
var triple = llvm.LLVMGetTargetMachineTriple(machine);
|
|
|
|
|
|
|
|
std.debug.warn("target: {}\n", sliceify(desc));
|
|
|
|
std.debug.warn("triple: {}\n", sliceify(triple));
|
|
|
|
std.debug.warn("features: {}\n", sliceify(features));
|
|
|
|
|
|
|
|
if (llvm.LLVMTargetMachineEmitToFile(
|
|
|
|
machine,
|
|
|
|
mod,
|
|
|
|
outpath_cstr.ptr,
|
|
|
|
llvm.LLVMCodeGenFileType.LLVMObjectFile,
|
|
|
|
&err,
|
|
|
|
) != 0) {
|
|
|
|
std.debug.warn("failed to emit to file: {}\n", sliceify(err));
|
2019-09-22 21:26:00 +00:00
|
|
|
return CompileError.LLVMError;
|
2019-09-21 15:37:41 +00:00
|
|
|
}
|
2019-09-21 02:40:21 +00:00
|
|
|
}
|
|
|
|
};
|