parse bitcode

This commit is contained in:
David Gonzalez Martin 2024-05-10 14:27:41 -06:00
parent a379ba9cf1
commit 7094d59372
5 changed files with 191 additions and 182 deletions

View File

@ -157,6 +157,9 @@ pub extern fn NativityLLVMModuleSetTargetMachineDataLayout(module: *LLVM.Module,
pub extern fn NativityLLVMModuleSetTargetTriple(module: *LLVM.Module, target_triple_ptr: [*]const u8, target_triple_len: usize) void;
pub extern fn NativityLLVMTypeAssertEqual(a: *LLVM.Type, b: *LLVM.Type) void;
pub extern fn LLVMCreateMemoryBufferWithMemoryRange(InputData: [*]const u8, InputDataLength: usize, BufferName: ?[*:0]const u8, RequiresNullTerminator: c_int) *LLVM.MemoryBuffer;
pub extern fn LLVMParseBitcodeInContext2(context: *LLVM.Context, memory_buffer: *LLVM.MemoryBuffer, out_module: **LLVM.Module) c_int;
pub extern fn LLVMInitializeAArch64TargetInfo() void;
pub extern fn LLVMInitializeAMDGPUTargetInfo() void;
pub extern fn LLVMInitializeARMTargetInfo() void;

View File

@ -886,72 +886,72 @@ pub fn make() void {
}
// TODO: Prune
// if (do_codegen) {
// for (threads) |*thread| {
// thread.add_thread_work(Job{
// .id = switch (codegen_backend) {
// .llvm => .llvm_codegen_thread_module,
// },
// });
// }
//
// while (true) {
// var to_do: u64 = 0;
// for (threads) |*thread| {
// const jobs_to_do = thread.task_system.job.to_do - thread.task_system.job.completed;
// const asks_to_do = thread.task_system.ask.to_do - thread.task_system.ask.completed;
// assert(asks_to_do == 0);
//
// to_do += jobs_to_do;
// }
//
// if (to_do == 0) {
// break;
// }
// }
//
// var modules_present = PinnedArray(usize){};
// for (threads, 0..) |*thread, i| {
// if (thread.functions.length > 0) {
// _ = modules_present.append(i);
// }
// }
//
// switch (modules_present.length) {
// 0 => unreachable,
// 1 => unreachable,
// 2 => {
// const first = modules_present.slice()[0];
// const second = modules_present.slice()[1];
// const destination = threads[first].llvm.module;
// {
// var message: []const u8 = undefined;
// destination.toString(&message.ptr, &message.len);
// std.debug.print("{s}\n", .{message});
// }
// const source = threads[second].llvm.module;
// {
// var message: []const u8 = undefined;
// source.toString(&message.ptr, &message.len);
// std.debug.print("{s}\n", .{message});
// }
//
// if (!destination.link(source, .{
// .override_from_source = true,
// .link_only_needed = false,
// })) {
// exit(1);
// }
//
// var message: []const u8 = undefined;
// destination.toString(&message.ptr, &message.len);
// std.debug.print("============\n===========\n{s}\n", .{message});
// },
// else => unreachable,
// }
// }
if (do_codegen) {
for (threads) |*thread| {
thread.add_thread_work(Job{
.id = switch (codegen_backend) {
.llvm => .llvm_codegen_thread_module,
},
});
}
// while (true) {}
while (true) {
var to_do: u64 = 0;
for (threads) |*thread| {
const jobs_to_do = thread.task_system.job.to_do - thread.task_system.job.completed;
const asks_to_do = thread.task_system.ask.to_do - thread.task_system.ask.completed;
assert(asks_to_do == 0);
to_do += jobs_to_do;
}
if (to_do == 0) {
break;
}
}
var modules_present = PinnedArray(usize){};
for (threads, 0..) |*thread, i| {
if (thread.functions.length > 0) {
_ = modules_present.append(i);
}
}
switch (modules_present.length) {
0 => unreachable,
1 => {},
2 => {
// const first = modules_present.slice()[0];
// const second = modules_present.slice()[1];
// const destination = threads[first].llvm.module;
// {
// var message: []const u8 = undefined;
// destination.toString(&message.ptr, &message.len);
// std.debug.print("{s}\n", .{message});
// }
// const source = threads[second].llvm.module;
// {
// var message: []const u8 = undefined;
// source.toString(&message.ptr, &message.len);
// std.debug.print("{s}\n", .{message});
// }
//
// if (!destination.link(source, .{
// .override_from_source = true,
// .link_only_needed = false,
// })) {
// exit(1);
// }
//
// var message: []const u8 = undefined;
// destination.toString(&message.ptr, &message.len);
// std.debug.print("============\n===========\n{s}\n", .{message});
},
else => unreachable,
}
}
while (true) {}
}
fn intern_identifier(pool: *PinnedHashMap(u32, []const u8), identifier: []const u8) u32 {
@ -1252,109 +1252,113 @@ fn thread_callback(thread_index: u32) void {
},
.llvm_codegen_thread_module => {
if (thread.functions.length > 0) {
const debug_info = true;
const ExternalRef = struct{
gsr: GlobalSymbolReference,
thread: u16,
};
var external_hashmap = PinnedHashMap(ExternalRef, *LLVM.Value.Constant.Function){};
for (thread.external_functions.slice()) |*nat_function| {
_ = llvm_get_function(thread, nat_function, true);
}
_ = &external_hashmap; // autofix
for (thread.functions.slice()) |*nat_function| {
_ = llvm_get_function(thread, &nat_function.declaration, false);
}
for (thread.functions.slice()) |*nat_function| {
const function = nat_function.declaration.llvm.?;
const nat_entry_basic_block = thread.basic_blocks.get(nat_function.entry_block);
assert(nat_entry_basic_block.predecessors.length == 0);
const entry_block_name = "entry_block_name";
const entry_block = thread.llvm.context.createBasicBlock(entry_block_name, entry_block_name.len, function, null);
thread.llvm.builder.setInsertPoint(entry_block);
for (nat_entry_basic_block.instructions.slice()) |instruction| {
const value: *LLVM.Value = switch (instruction.id) {
.ret => block: {
const return_instruction = thread.returns.get(@enumFromInt(instruction.index));
const return_value = llvm_get_value(thread, return_instruction.value);
const ret = thread.llvm.builder.createRet(return_value);
break :block ret.toValue();
},
.call => block: {
const call = thread.calls.get(@enumFromInt(instruction.index));
const callee = if (call.value.sema.thread == thread.get_index()) switch (call.value.sema.id) {
.global_symbol => blk: {
const global_symbol: GlobalSymbolReference = @bitCast(call.value.sema.index);
break :blk switch (global_symbol.id) {
.function_declaration => b: {
const external_function = thread.external_functions.slice()[global_symbol.index];
break :b external_function.llvm.?;
},
else => |t| @panic(@tagName(t)),
};
},
else => |t| @panic(@tagName(t)),
} else exit(1);
const function_type = callee.getType();
const arguments: []const *LLVM.Value = &.{};
const call_i = thread.llvm.builder.createCall(function_type, callee.toValue(), arguments.ptr, arguments.len, "", "".len, null);
break :block call_i.toValue();
},
else => |t| @panic(@tagName(t)),
};
instruction.llvm = value;
}
if (debug_info) {
const file_index = nat_function.declaration.file;
const llvm_file = thread.debug_info_file_map.get_pointer(file_index).?;
const subprogram = function.getSubprogram();
llvm_file.builder.finalizeSubprogram(subprogram, function);
}
const verify_function = true;
if (verify_function) {
var message: []const u8 = undefined;
const verification_success = function.verify(&message.ptr, &message.len);
if (!verification_success) {
var function_msg: []const u8 = undefined;
function.toString(&function_msg.ptr, &function_msg.len);
write(function_msg);
write("\n");
exit_with_error(message);
}
}
}
if (debug_info) {
const file_index = thread.functions.slice()[0].declaration.file;
const llvm_file = thread.debug_info_file_map.get_pointer(file_index).?;
llvm_file.builder.finalize();
}
const verify_module = true;
if (verify_module) {
var verification_message: []const u8 = undefined;
const verification_success = thread.llvm.module.verify(&verification_message.ptr, &verification_message.len);
if (!verification_success) {
const print_module = true;
if (print_module) {
var module_content: []const u8 = undefined;
thread.llvm.module.toString(&module_content.ptr, &module_content.len);
write(module_content);
write("\n");
}
exit_with_error(verification_message);
}
}
const context = LLVM.Context.create();
const result = context.parse_bitcode("foo");
_ = result; // autofix
exit(0);
// const debug_info = true;
//
// const ExternalRef = struct{
// gsr: GlobalSymbolReference,
// thread: u16,
// };
// var external_hashmap = PinnedHashMap(ExternalRef, *LLVM.Value.Constant.Function){};
//
// for (thread.external_functions.slice()) |*nat_function| {
// _ = llvm_get_function(thread, nat_function, true);
// }
//
// _ = &external_hashmap; // autofix
// for (thread.functions.slice()) |*nat_function| {
// _ = llvm_get_function(thread, &nat_function.declaration, false);
// }
//
// for (thread.functions.slice()) |*nat_function| {
// const function = nat_function.declaration.llvm.?;
// const nat_entry_basic_block = thread.basic_blocks.get(nat_function.entry_block);
// assert(nat_entry_basic_block.predecessors.length == 0);
// const entry_block_name = "entry_block_name";
// const entry_block = thread.llvm.context.createBasicBlock(entry_block_name, entry_block_name.len, function, null);
// thread.llvm.builder.setInsertPoint(entry_block);
//
// for (nat_entry_basic_block.instructions.slice()) |instruction| {
// const value: *LLVM.Value = switch (instruction.id) {
// .ret => block: {
// const return_instruction = thread.returns.get(@enumFromInt(instruction.index));
// const return_value = llvm_get_value(thread, return_instruction.value);
// const ret = thread.llvm.builder.createRet(return_value);
// break :block ret.toValue();
// },
// .call => block: {
// const call = thread.calls.get(@enumFromInt(instruction.index));
// const callee = if (call.value.sema.thread == thread.get_index()) switch (call.value.sema.id) {
// .global_symbol => blk: {
// const global_symbol: GlobalSymbolReference = @bitCast(call.value.sema.index);
// break :blk switch (global_symbol.id) {
// .function_declaration => b: {
// const external_function = thread.external_functions.slice()[global_symbol.index];
// break :b external_function.llvm.?;
// },
// else => |t| @panic(@tagName(t)),
// };
// },
// else => |t| @panic(@tagName(t)),
// } else exit(1);
// const function_type = callee.getType();
//
// const arguments: []const *LLVM.Value = &.{};
// const call_i = thread.llvm.builder.createCall(function_type, callee.toValue(), arguments.ptr, arguments.len, "", "".len, null);
// break :block call_i.toValue();
// },
// else => |t| @panic(@tagName(t)),
// };
//
// instruction.llvm = value;
// }
//
// if (debug_info) {
// const file_index = nat_function.declaration.file;
// const llvm_file = thread.debug_info_file_map.get_pointer(file_index).?;
// const subprogram = function.getSubprogram();
// llvm_file.builder.finalizeSubprogram(subprogram, function);
// }
//
// const verify_function = true;
// if (verify_function) {
// var message: []const u8 = undefined;
// const verification_success = function.verify(&message.ptr, &message.len);
// if (!verification_success) {
// var function_msg: []const u8 = undefined;
// function.toString(&function_msg.ptr, &function_msg.len);
// write(function_msg);
// write("\n");
// exit_with_error(message);
// }
// }
// }
//
// if (debug_info) {
// const file_index = thread.functions.slice()[0].declaration.file;
// const llvm_file = thread.debug_info_file_map.get_pointer(file_index).?;
// llvm_file.builder.finalize();
// }
//
// const verify_module = true;
// if (verify_module) {
// var verification_message: []const u8 = undefined;
// const verification_success = thread.llvm.module.verify(&verification_message.ptr, &verification_message.len);
// if (!verification_success) {
// const print_module = true;
// if (print_module) {
// var module_content: []const u8 = undefined;
// thread.llvm.module.toString(&module_content.ptr, &module_content.len);
// write(module_content);
// write("\n");
// }
//
// exit_with_error(verification_message);
// }
// }
}
},
}
@ -1939,6 +1943,17 @@ pub const LLVM = struct {
const getAttributeFromString = bindings.NativityLLVMContextGetAttributeFromString;
const getAttributeFromType = bindings.NativityLLVMContextGetAttributeFromType;
const getAttributeSet = bindings.NativityLLVMContextGetAttributeSet;
pub fn parse_bitcode(context: *LLVM.Context, bytes: []const u8) ?*LLVM.Module {
const memory_buffer = bindings.LLVMCreateMemoryBufferWithMemoryRange(bytes.ptr, bytes.len, null, 0);
var out_module: *LLVM.Module = undefined;
if (bindings.LLVMParseBitcodeInContext2(context, memory_buffer, &out_module) != 0) {
return out_module;
} else {
return null;
}
}
};
pub const Module = opaque {
@ -2579,6 +2594,8 @@ pub const LLVM = struct {
};
pub const MemoryBuffer = opaque{};
pub const Value = opaque {
const setName = bindings.NativityLLVMValueSetName;
const getType = bindings.NativityLLVMValueGetType;

View File

@ -153,9 +153,8 @@ pub fn DynamicBoundedArray(comptime T: type) type {
const pinned_array_page_size = 2 * 1024 * 1024;
const pinned_array_max_size = std.math.maxInt(u32) - pinned_array_page_size;
const pinned_array_default_granularity = pinned_array_page_size;
const small_granularity = 0x1000;
const small_granularity = std.mem.page_size;
const large_granularity = 2 * 1024 * 1024;
// This must be used with big arrays, which are not resizeable (can't be cleared)
pub fn PinnedArray(comptime T: type) type {

View File

@ -1,6 +1,4 @@
import "file.nat";
fn [cc(.c)] main [export]() s32
{
return file.foo();
return 0;
}

View File

@ -4,6 +4,7 @@
#include "llvm/IR/Module.h"
#include "llvm/IR/Verifier.h"
#include "llvm/IR/DIBuilder.h"
#include "llvm/Bitcode/BitcodeReader.h"
#include "llvm/ExecutionEngine/Orc/ThreadSafeModule.h"
@ -22,8 +23,6 @@
using namespace llvm;
using llvm::orc::ThreadSafeContext;
using llvm::orc::ThreadSafeModule;
extern "C" LLVMContext* NativityLLVMCreateContext()
{
@ -1077,13 +1076,6 @@ extern "C" CallInst* NativityLLVMBuilderCreateMemcpy(IRBuilder<>& builder, Value
return memcpy;
}
extern "C" bool NativityLLVMLinkModules(Module& destination, Module* source)
{
auto src = std::unique_ptr<Module>(source);
bool result = Linker::linkModules(destination, std::move(src));
// Invert the condition because LLVM boolean concept is lame
return !result;
}
extern "C" void NativityLLVMTypeAssertEqual(Type* a, Type* b)
{
assert(a == b);