nativity/bootstrap/compiler.zig
David Gonzalez Martin aade460a50 bitcode split
2024-05-11 11:53:32 -06:00

3750 lines
140 KiB
Zig

const std = @import("std");
const library = @import("library.zig");
const assert = library.assert;
const Arena = library.Arena;
const PinnedArray = library.PinnedArray;
const PinnedHashMap = library.PinnedHashMap;
const hash_bytes = library.my_hash;
const byte_equal = library.byte_equal;
fn exit(exit_code: u8) noreturn {
@setCold(true);
if (@import("builtin").mode == .Debug) {
if (exit_code != 0) @trap();
}
std.posix.exit(exit_code);
}
fn is_space(ch: u8) bool {
const is_whitespace = ch == ' ';
const is_tab = ch == '\t';
const is_line_feed = ch == '\n';
const is_carry_return = ch == '\r';
const result = (is_whitespace or is_tab) or (is_line_feed or is_carry_return);
return result;
}
fn write(string: []const u8) void {
std.io.getStdOut().writeAll(string) catch unreachable;
}
fn exit_with_error(string: []const u8) noreturn {
@setCold(true);
write("error: ");
write(string);
write("\n");
exit(1);
}
fn is_lower(ch: u8) bool {
return ch >= 'a' and ch <= 'z';
}
fn is_upper(ch: u8) bool {
return ch >= 'A' and ch <= 'Z';
}
fn is_decimal_digit(ch: u8) bool {
return ch >= '0' and ch <= '9';
}
fn is_alphabetic(ch: u8) bool {
const lower = is_lower(ch);
const upper = is_upper(ch);
return lower or upper;
}
fn is_identifier_char_start(ch: u8) bool {
const is_alpha = is_alphabetic(ch);
const is_underscore = ch == '_';
return is_alpha or is_underscore;
}
fn is_identifier_char(ch: u8) bool {
const is_identifier_start_ch = is_identifier_char_start(ch);
const is_digit = is_decimal_digit(ch);
return is_identifier_start_ch or is_digit;
}
const GlobalSymbol = struct {
attributes: Attributes = .{},
name: u32,
const Attributes = struct {
@"export": bool = false,
@"extern": bool = false,
};
const Attribute = enum {
@"export",
@"extern",
const Mask = std.EnumSet(Attribute);
};
};
const Parser = struct {
i: u64 = 0,
current_line: u32 = 0,
line_offset: u32 = 0,
fn skip_space(parser: *Parser, file: []const u8) void {
const original_i = parser.i;
if (!is_space(file[original_i])) return;
while (parser.i < file.len) : (parser.i += 1) {
const ch = file[parser.i];
const new_line = ch == '\n';
parser.current_line += @intFromBool(new_line);
if (new_line) {
parser.line_offset = @intCast(parser.i);
}
if (!is_space(ch)) {
return;
}
}
}
fn parse_raw_identifier(parser: *Parser, file: []const u8) []const u8 {
const identifier_start = parser.i;
const is_string_literal_identifier = file[identifier_start] == '"';
parser.i += @intFromBool(is_string_literal_identifier);
const start_ch = file[parser.i];
const is_valid_identifier_start = is_identifier_char_start(start_ch);
parser.i += @intFromBool(is_valid_identifier_start);
if (is_valid_identifier_start) {
while (parser.i < file.len) {
const ch = file[parser.i];
const is_ident = is_identifier_char(ch);
parser.i += @intFromBool(is_ident);
if (!is_ident) {
if (is_string_literal_identifier) {
if (file[parser.i] != '"') {
exit(1);
}
}
const identifier = file[identifier_start..parser.i];
return identifier;
}
} else {
exit(1);
}
} else {
exit(1);
}
}
fn parse_identifier(parser: *Parser, thread: *Thread, file: []const u8) u32 {
const identifier = parser.parse_raw_identifier(file);
if (identifier[0] != '"') {
const keyword = parse_keyword(identifier);
if (keyword != ~(@as(u32, 0))) {
exit(1);
}
}
const hash = intern_identifier(&thread.identifiers, identifier);
return hash;
}
fn parse_non_escaped_string_literal(parser: *Parser, src: []const u8) []const u8 {
const start = parser.i;
const is_double_quote = src[start] == '"';
parser.i += @intFromBool(is_double_quote);
if (!is_double_quote) {
exit(1);
}
while (src[parser.i] != '"') : (parser.i += 1) {
if (src[parser.i] == '\\') exit(1);
}
parser.i += 1;
const end = parser.i;
return src[start..end];
}
fn parse_non_escaped_string_literal_content(parser: *Parser, src: []const u8) []const u8 {
const string_literal = parser.parse_non_escaped_string_literal(src);
return string_literal[1..][0 .. string_literal.len - 2];
}
fn expect_character(parser: *Parser, file: []const u8, expected: u8) void {
const index = parser.i;
if (index < file.len) {
const ch = file[index];
const matches = ch == expected;
parser.i += @intFromBool(matches);
if (!matches) {
exit(1);
}
} else {
exit(1);
}
}
fn parse_type_expression(parser: *Parser, thread: *Thread, src: []const u8) *Type {
const starting_ch = src[parser.i];
const is_start_u = starting_ch == 'u';
const is_start_s = starting_ch == 's';
const float_start = starting_ch == 'f';
const integer_start = is_start_s or is_start_u;
const is_number_type_start = integer_start or float_start;
if (is_number_type_start) {
const expected_digit_start = parser.i + 1;
var i = expected_digit_start;
var decimal_digit_count: u32 = 0;
const top = i + 5;
while (i < top) : (i += 1) {
const ch = src[i];
const is_digit = is_decimal_digit(ch);
decimal_digit_count += @intFromBool(is_digit);
if (!is_digit) {
const is_alpha = is_alphabetic(ch);
if (is_alpha) decimal_digit_count = 0;
break;
}
}
if (decimal_digit_count != 0) {
parser.i += 1;
if (integer_start) {
const signedness: Type.Integer.Signedness = @enumFromInt(@intFromBool(is_start_s));
const bit_count: u32 = switch (decimal_digit_count) {
0 => unreachable,
1 => src[parser.i] - '0',
2 => @as(u32, src[parser.i] - '0') * 10 + (src[parser.i + 1] - '0'),
else => exit(1),
};
parser.i += decimal_digit_count;
const index = bit_count + (@intFromEnum(signedness) * @as(u32, 64) + @intFromEnum(signedness));
const t = &thread.types.slice()[index];
return t;
} else if (float_start) {
exit(1);
} else {
unreachable;
}
} else {
exit(1);
}
} else {
exit(1);
}
}
fn parse_typed_expression(parser: *Parser, analyzer: *Analyzer, thread: *Thread, file: *File, ty: *Type) *Value {
const src = file.source_code;
assert(ty.sema.id != .unresolved);
const starting_ch = src[parser.i];
const is_digit_start = is_decimal_digit(starting_ch);
const is_alpha_start = is_alphabetic(starting_ch);
if (is_digit_start) {
switch (ty.sema.id) {
.integer => {
if (starting_ch == '0') {
const follow_up_character = src[parser.i + 1];
const is_hex_start = follow_up_character == 'x';
const is_octal_start = follow_up_character == 'o';
const is_bin_start = follow_up_character == 'b';
const is_prefixed_start = is_hex_start or is_octal_start or is_bin_start;
const follow_up_alpha = is_alphabetic(follow_up_character);
const follow_up_digit = is_decimal_digit(follow_up_character);
const is_valid_after_zero = is_space(follow_up_character) or (!follow_up_digit and !follow_up_alpha);
//
if (is_prefixed_start) {
exit(1);
} else if (is_valid_after_zero) {
parser.i += 1;
const constant_int_index = thread.constant_ints.append_index(.{
.value = 0,
.type = ty,
});
const value = thread.values.append(.{
.sema = .{
.id = .constant_int,
.index = @intCast(constant_int_index),
.thread = @intCast(thread.get_index()),
.resolved = true,
},
});
return value;
} else {
exit(1);
}
}
exit(0);
},
else => unreachable,
}
} else if (is_alpha_start) {
const file_scope = thread.file_scopes.get(@enumFromInt(file.scope.index));
var resolved = true;
const identifier = parser.parse_identifier(thread, src);
const lazy_expression = thread.lazy_expressions.add_one();
if (file_scope.declarations.get_pointer(identifier)) |declaration| {
switch (declaration.id) {
.unresolved_import => {
resolved = false;
lazy_expression.* = LazyExpression.init(declaration);
while (true) {
switch (src[parser.i]) {
'.' => {
parser.i += 1;
const right = parser.parse_identifier(thread, src);
lazy_expression.add(right);
},
'(' => break,
else => @panic((src.ptr + parser.i)[0..1]),
}
}
const expression = thread.values.append(.{
.sema = .{
.id = .lazy_expression,
.index = thread.lazy_expressions.get_index(lazy_expression),
.thread = thread.get_index(),
.resolved = false,
},
});
switch (src[parser.i]) {
'(' => {
parser.i += 1;
// TODO: arguments
parser.expect_character(src, ')');
const call = thread.calls.append_index(.{
.value = expression,
});
const call_i = thread.instructions.append(.{
.id = .call,
.index = @intCast(call),
});
_ = analyzer.current_basic_block.instructions.append(call_i);
const call_value = thread.values.append(.{
.sema = .{
.id = .instruction,
.index = thread.instructions.get_index(call_i),
.thread = thread.get_index(),
.resolved = false,
},
});
_ = thread.pending_file_values.get(@enumFromInt(declaration.index)).append(call_value);
return call_value;
},
else => @panic((src.ptr + parser.i)[0..1]),
}
},
else => |t| @panic(@tagName(t)),
}
} else {
exit(1);
}
} else {
exit(1);
}
}
};
const LazyExpression = union(enum) {
dynamic: struct {
names: PinnedArray(u32) = .{},
outsider: *GlobalSymbolReference,
},
static: struct {
names: [4]u32 = .{0} ** 4,
outsider: *GlobalSymbolReference,
},
fn init(gsr: *GlobalSymbolReference) LazyExpression {
return .{
.static = .{
.outsider = gsr,
},
};
}
fn length(lazy_expression: *LazyExpression) u32 {
return switch (lazy_expression.*) {
.dynamic => |d| d.names.length,
.static => |*s| for (s.names, 0..) |n, i| {
if (n == 0) break @intCast(i);
} else s.names.len,
};
}
fn names(lazy_expression: *LazyExpression) []const u32 {
return switch (lazy_expression.*) {
.dynamic => |*d| d.names.slice(),
.static => |*s| s.names[0..for (s.names, 0..) |n, i| {
if (n == 0) break @intCast(i);
} else s.names.len],
};
}
fn add(lazy_expression: *LazyExpression, name: u32) void {
const index = lazy_expression.length();
if (index < 4) {
lazy_expression.static.names[index] = name;
} else {
unreachable;
}
}
};
fn Descriptor(comptime Id: type, comptime Integer: type) type {
return packed struct(Integer) {
index: @Type(.{
.Int = .{
.signedness = .unsigned,
.bits = @typeInfo(Integer).Int.bits - @typeInfo(@typeInfo(Id).Enum.tag_type).Int.bits,
},
}),
id: Id,
pub const Index = PinnedArray(@This()).Index;
};
}
const Expression = struct {
type: *Type,
value: *Value,
};
const Value = struct {
llvm: ?*LLVM.Value = null,
sema: packed struct(u64) {
index: u32,
thread: u16,
resolved: bool,
reserved: u7 = 0,
id: Id,
},
const Id = enum(u8) {
constant_int,
lazy_expression,
instruction,
global_symbol,
};
};
const Type = struct {
llvm: ?*LLVM.Type = null,
sema: packed struct(u32) {
index: u24,
id: Id,
},
const Id = enum(u8) {
unresolved,
void,
integer,
};
const Integer = packed struct(u32) {
bit_count: u16,
signedness: Signedness,
reserved: u7 = 0,
id: Id = .integer,
const Signedness = enum(u1) {
unsigned,
signed,
};
};
};
fn integer_bit_count(t: *Type) u16 {
const integer: Type.Integer = @bitCast(t.sema);
return integer.bit_count;
}
fn integer_signedness(t: *Type) Type.Integer.Signedness {
const integer: Type.Integer = @bitCast(t.sema);
return integer.signedness;
}
const IntegerType = struct {};
const Keyword = enum {
@"for",
};
fn parse_keyword(identifier: []const u8) u32 {
inline for (@typeInfo(Keyword).Enum.fields) |keyword| {
if (byte_equal(identifier, keyword.name)) {
return keyword.value;
}
} else {
return ~@as(u32, 0);
}
}
const Scope = Descriptor(enum(u3) {
file,
function,
local,
}, u32);
const Range = struct {
start: u32,
end: u32,
};
const FileScope = struct {
declarations: PinnedHashMap(u32, GlobalSymbolReference) = .{},
};
const GlobalSymbolReference = Descriptor(enum(u3) {
function_definition,
function_declaration,
file,
unresolved_import,
}, u32);
const BasicBlock = struct {
instructions: PinnedArray(*Instruction) = .{},
predecessors: PinnedArray(u32) = .{},
is_terminated: bool = false,
const Index = PinnedArray(BasicBlock).Index;
};
const Function = struct {
declaration: Function.Declaration,
entry_block: BasicBlock.Index,
const Attributes = struct {
calling_convention: CallingConvention = .custom,
};
const Attribute = enum {
cc,
pub const Mask = std.EnumSet(Function.Attribute);
};
const Declaration = struct {
attributes: Attributes = .{},
global: GlobalSymbol,
return_type: *Type,
argument_types: []const Type = &.{},
file: u32,
llvm: ?*LLVM.Value.Constant.Function = null,
};
};
const Instruction = struct {
index: u24,
id: Id,
llvm: ?*LLVM.Value = null,
const Id = enum {
call,
ret,
ret_void,
};
};
const ConstantInt = struct {
value: u64,
type: *Type,
};
const Call = struct {
value: *Value,
const Index = PinnedArray(Call).Index;
};
const Return = struct {
value: *Value,
const Index = PinnedArray(Call).Index;
};
const Thread = struct {
arena: *Arena = undefined,
functions: PinnedArray(Function) = .{},
external_functions: PinnedArray(Function.Declaration) = .{},
identifiers: PinnedHashMap(u32, []const u8) = .{},
instructions: PinnedArray(Instruction) = .{},
constant_ints: PinnedArray(ConstantInt) = .{},
basic_blocks: PinnedArray(BasicBlock) = .{},
task_system: TaskSystem = .{},
analyzed_file_count: u32 = 0,
debug_info_file_map: PinnedHashMap(u32, LLVMFile) = .{},
local_files: PinnedHashMap(u32, u32) = .{},
pending_files: PinnedArray(u32) = .{},
pending_file_values: PinnedArray(PinnedArray(*Value)) = .{},
file_scopes: PinnedArray(FileScope) = .{},
expressions: PinnedArray(Expression) = .{},
calls: PinnedArray(Call) = .{},
returns: PinnedArray(Return) = .{},
types: PinnedArray(Type) = .{},
values: PinnedArray(Value) = .{},
lazy_expressions: PinnedArray(LazyExpression) = .{},
llvm: struct {
context: *LLVM.Context,
module: *LLVM.Module,
builder: *LLVM.Builder,
attributes: LLVM.Attributes,
} = undefined,
fn add_thread_work(thread: *Thread, job: Job) void {
thread.task_system.job.queue_job(job);
}
fn add_control_work(thread: *Thread, job: Job) void {
thread.task_system.ask.queue_job(job);
}
pub fn get_index(thread: *Thread) u16 {
const index = @divExact(@intFromPtr(thread) - @intFromPtr(threads.ptr), @sizeOf(Thread));
return @intCast(index);
}
};
const instrument = true;
const LLVMFile = struct {
file: *LLVM.DebugInfo.File,
compile_unit: *LLVM.DebugInfo.CompileUnit,
builder: *LLVM.DebugInfo.Builder,
};
const Job = packed struct(u64) {
offset: u32 = 0,
count: u24 = 0,
id: Id,
const Id = enum(u8) {
analyze_file,
llvm_setup,
notify_file_resolved,
resolve_thread_module,
llvm_codegen_thread_module,
};
};
const TaskSystem = struct {
job: JobQueue = .{},
ask: JobQueue = .{},
};
const JobQueue = struct {
entries: [64]Job = [1]Job{@bitCast(@as(u64, 0))} ** 64,
to_do: u64 = 0,
completed: u64 = 0,
fn queue_job(job_queue: *JobQueue, job: Job) void {
const index = job_queue.to_do;
job_queue.entries[index] = job;
job_queue.to_do += 1;
}
};
var threads: []Thread = undefined;
const Instance = struct {
files: PinnedArray(File) = .{},
file_paths: PinnedArray(u32) = .{},
arena: *Arena = undefined,
};
const File = struct {
scope: Scope,
source_code: []const u8,
path: []const u8,
functions: Range = .{
.start = 0,
.end = 0,
},
state: State = .queued,
thread: u32 = 0,
interested_threads: PinnedArray(u32) = .{},
pub fn get_directory_path(file: *const File) []const u8 {
return std.fs.path.dirname(file.path) orelse unreachable;
}
const State = enum {
queued,
analyzing,
};
const Index = PinnedArray(File).Index;
};
var instance = Instance{};
const do_codegen = true;
const codegen_backend = CodegenBackend.llvm;
const CodegenBackend = enum {
llvm,
};
fn add_file(file_absolute_path: []const u8, interested_threads: []const u32) File.Index {
const hash = hash_bytes(file_absolute_path);
const new_file = instance.files.add_one();
_ = instance.file_paths.append(hash);
const new_file_index = instance.files.get_typed_index(new_file);
new_file.* = .{
.scope = @bitCast(@as(u32, 0)),
.source_code = &.{},
.path = file_absolute_path,
};
new_file.interested_threads.append_slice(interested_threads);
return new_file_index;
}
pub fn make() void {
instance.arena = library.Arena.init(4 * 1024 * 1024) catch unreachable;
// var modules: [2]*LLVM.Module = undefined;
// {
// const context = LLVM.Context.create();
// const module_name: []const u8 = "thread";
// const module = LLVM.Module.create(module_name.ptr, module_name.len, context);
// const builder = LLVM.Builder.create(context);
// // const attributes = LLVM.Attributes{
// // .naked = context.getAttributeFromEnum(.Naked, 0),
// // .noreturn = context.getAttributeFromEnum(.NoReturn, 0),
// // .nounwind = context.getAttributeFromEnum(.NoUnwind, 0),
// // .inreg = context.getAttributeFromEnum(.InReg, 0),
// // .@"noalias" = context.getAttributeFromEnum(.NoAlias, 0),
// // };
// const int32 = context.getIntegerType(32);
// const function_type = LLVM.getFunctionType(int32.toType(), undefined, 0, false);
// const function = module.createFunction(function_type, .internal, 0, "foo", "foo".len);
// const entry_basic_block = context.createBasicBlock("", "".len, function, null);
// builder.setInsertPoint(entry_basic_block);
//
// const call_function = module.createFunction(function_type, .@"extern", 0, "fa", "fa".len);
//
// const call = builder.createCall(function_type, call_function.toValue(), undefined, 0, "", "".len, null);
// _ = builder.createRet(call.toValue());
// var message: []const u8 = undefined;
// //_ = message; // autofix
// const v = module.verify(&message.ptr, &message.len);
// if (!v) exit_with_error(message);
// modules[0] = module;
// }
//
// {
// const context = LLVM.Context.create();
// const module_name: []const u8 = "thread";
// const module = LLVM.Module.create(module_name.ptr, module_name.len, context);
// const builder = LLVM.Builder.create(context);
// // const attributes = LLVM.Attributes{
// // .naked = context.getAttributeFromEnum(.Naked, 0),
// // .noreturn = context.getAttributeFromEnum(.NoReturn, 0),
// // .nounwind = context.getAttributeFromEnum(.NoUnwind, 0),
// // .inreg = context.getAttributeFromEnum(.InReg, 0),
// // .@"noalias" = context.getAttributeFromEnum(.NoAlias, 0),
// // };
// const int32 = context.getIntegerType(32);
// const function_type = LLVM.getFunctionType(int32.toType(), undefined, 0, false);
// const function = module.createFunction(function_type, .@"internal", 0, "fa", "fa".len);
// const entry_basic_block = context.createBasicBlock("", "".len, function, null);
// builder.setInsertPoint(entry_basic_block);
//
// const constant_int = context.getConstantInt(32, 5, false);
// _ = builder.createRet(constant_int.toValue());
// var message: []const u8 = undefined;
// const v = module.verify(&message.ptr, &message.len);
// if (!v) exit_with_error(message);
// modules[1] = module;
// }
//
// const result = LLVMLinkModules2(modules[0], modules[1]);
// var foo: []const u8 = undefined;
// modules[0].toString(&foo.ptr, &foo.len);
// std.debug.print("Result: {}\n{s}\n", .{result, foo});
const thread_count = std.Thread.getCpuCount() catch unreachable;
cpu_count = @intCast(thread_count);
threads = instance.arena.new_array(Thread, cpu_count - 1) catch unreachable;
for (threads) |*thread| {
thread.* = .{};
}
cpu_count -= 2;
_ = std.Thread.spawn(.{}, thread_callback, .{cpu_count}) catch unreachable;
// Initialize LLVM in all threads
if (do_codegen) {
const llvm_job = Job{
.offset = 0,
.count = 0,
.id = .llvm_setup,
};
for (threads) |*thread| {
thread.add_thread_work(llvm_job);
}
}
const first_file_relative_path = "retest/standalone/first/main.nat";
const first_file_absolute_path = library.realpath(instance.arena, std.fs.cwd(), first_file_relative_path) catch unreachable;
const new_file_index = add_file(first_file_absolute_path, &.{});
var last_assigned_thread_index: u32 = 0;
threads[last_assigned_thread_index].add_thread_work(Job{
.offset = @intFromEnum(new_file_index),
.id = .analyze_file,
});
while (true) {
var worker_pending_tasks: u64 = 0;
var control_pending_tasks: u64 = 0;
for (threads) |*thread| {
worker_pending_tasks += thread.task_system.job.to_do - thread.task_system.job.completed;
control_pending_tasks += thread.task_system.ask.to_do - thread.task_system.ask.completed;
}
const pending_tasks = worker_pending_tasks + control_pending_tasks;
if (pending_tasks == 0) {
break;
}
if (control_pending_tasks > 0) {
for (threads, 0..) |*thread, i| {
const control_pending = thread.task_system.ask.to_do - thread.task_system.ask.completed;
if (control_pending != 0) {
const jobs_to_do = thread.task_system.ask.entries[thread.task_system.ask.completed..thread.task_system.ask.to_do];
for (jobs_to_do) |job| {
switch (job.id) {
.analyze_file => {
last_assigned_thread_index += 1;
const analyze_file_path_hash = job.offset;
for (instance.file_paths.slice()) |file_path_hash| {
if (analyze_file_path_hash == file_path_hash) {
exit(1);
}
} else {
last_assigned_thread_index += 1;
const thread_index = last_assigned_thread_index % threads.len;
const file_absolute_path = thread.identifiers.get(analyze_file_path_hash).?;
const interested_thread_index: u32 = @intCast(i);
const file_index = add_file(file_absolute_path, &.{interested_thread_index});
const assigned_thread = &threads[thread_index];
assigned_thread.add_thread_work(Job{
.offset = @intFromEnum(file_index),
.id = .analyze_file,
});
}
},
.notify_file_resolved => {
const file_index = job.offset;
const thread_index = job.count;
const destination_thread = &threads[thread_index];
const file = instance.files.get(@enumFromInt(file_index));
const file_path_hash = hash_bytes(file.path);
destination_thread.add_thread_work(.{
.id = .notify_file_resolved,
.count = @intCast(file_index),
.offset = file_path_hash,
});
},
else => |t| @panic(@tagName(t)),
}
}
thread.task_system.ask.completed += jobs_to_do.len;
}
}
}
}
{
// finish thread semantic analysis
for (threads) |*thread| {
thread.add_thread_work(Job{
.id = .resolve_thread_module,
});
}
}
// 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 => {},
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 {
const start_index = @intFromBool(identifier[0] == '"');
const end_index = identifier.len - start_index;
const hash = hash_bytes(identifier[start_index..end_index]);
pool.put(hash, identifier);
return hash;
}
// fn resolve_call(thread: *Thread, file_index: u32, expression: *Expression) void {
// assert(expression.kind == .unresolved and expression.kind.unresolved == .call_expression);
// const unresolved_call_expression = expression.kind.unresolved.call_expression;
// resolve_expression(thread, file_index, unresolved_call_expression.callee);
// const function_expression = unresolved_call_expression.callee;
// switch (function_expression.kind) {
// .resolved => |resolved| switch (resolved) {
// .declaration => |declaration| switch (declaration.id) {
// .function_definition => |fn_def| {
// _ = fn_def; // autofix
// _ = expression.instruction;
// const basic_block = thread.basic_blocks.get(expression.basic_block);
// const call = thread.calls.append_index(.{});
// const instruction = thread.instructions.append(.{
// .id = .call,
// .index = @intCast(@intFromEnum(call)),
// });
// _ = basic_block.instructions.append(instruction);
// expression.kind = .{
// .resolved = .{
// .instruction = instruction,
// },
// };
// },
// else => |t| @panic(@tagName(t)),
// },
// else => |t| @panic(@tagName(t)),
// },
// else => |t| @panic(@tagName(t)),
// }
// }
fn resolve_value(thread: *Thread, file_index: u32, value: *Value) void {
_ = thread; // autofix
_ = file_index; // autofix
_ = value; // autofix
unreachable;
// switch (expression.kind) {
// .unresolved => |unresolved_expression| switch (unresolved_expression) {
// .import => |declaration| {
// declaration.* = .{
// .id = .file,
// .index = @intCast(file_index),
// };
//
// expression.kind = .{
// .resolved = .{
// .import = declaration,
// },
// };
// },
// .call_expression => resolve_call(thread, file_index, expression),
// .field_expression => |field_expression| {
// resolve_expression(thread, file_index, field_expression.left);
//
// switch (field_expression.left.kind) {
// .resolved => |resolved_expression| switch (resolved_expression) {
// .import => |declaration| {
// assert(declaration.id == .file);
// const resolved_file_index = declaration.index;
// const file = &instance.files.pointer[resolved_file_index];
//
// const file_scope = &threads[file.thread].file_scopes.pointer[file.scope.index];
// if (file_scope.declarations.get_pointer(field_expression.right)) |symbol| {
// expression.kind = .{
// .resolved = .{
// .declaration = symbol,
// },
// };
// } else {
// exit(1);
// }
// },
// else => |t| @panic(@tagName(t)),
// },
// else => |t| @panic(@tagName(t)),
// }
// },
// },
// .resolved => {},
// }
}
const Bitcode = struct {};
fn write_bitcode() void {
var buffer = PinnedArray(u8){};
// Magic
const magic = [_]u8{ 0x42, 0x43, 0xc0, 0xde };
buffer.append_slice(&magic);
const identification_block = [_]u8{
0x35, 0x14, 0x00, 0x00,
0x05, 0x00, 0x00, 0x00,
0x62, 0x0c, 0x30, 0x24,
0x4a, 0x59, 0xbe, 0x66,
0xbd, 0xfb, 0xb4, 0xaf,
0x0b, 0x51, 0x80, 0x4c,
0x01, 0x00, 0x00, 0x00,
};
buffer.append_slice(&identification_block);
// ==================
// MODULE BLOCK START
// ==================
const module_block_start = [_]u8{
0x21, 0x0c, 0x00, 0x00,
0x1f, 0x01, 0x00, 0x00,
0x0b, 0x02, 0x21, 0x00,
};
buffer.append_slice(&module_block_start);
const blockinfo_block = [_]u8{
0x02, 0x00, 0x00, 0x00,
0x16, 0x00, 0x00, 0x00,
0x07, 0x81, 0x23, 0x91,
0x41, 0xc8, 0x04, 0x49,
0x06, 0x10, 0x32, 0x39,
0x92, 0x01, 0x84, 0x0c,
0x25, 0x05, 0x08, 0x19,
0x1e, 0x04, 0x8b, 0x62,
0x80, 0x04, 0x45, 0x02,
0x42, 0x92, 0x0b, 0x42,
0x24, 0x10, 0x32, 0x14,
0x38, 0x08, 0x18, 0x4b,
0x0a, 0x32, 0x12, 0x88,
0x48, 0x70, 0xc4, 0x21,
0x23, 0x44, 0x12, 0x87,
0x8c, 0x10, 0x41, 0x92,
0x02, 0x64, 0xc8, 0x08,
0xb1, 0x14, 0x20, 0x43,
0x46, 0x88, 0x20, 0xc9,
0x01, 0x32, 0x12, 0x84,
0x18, 0x2a, 0x28, 0x2a,
0x90, 0x31, 0x7c, 0xb0,
0x5c, 0x91, 0x20, 0xc1,
0xc8, 0x00, 0x00, 0x00,
};
buffer.append_slice(&blockinfo_block);
const typeinfo_block = [_]u8{
0x89, 0x20, 0x00, 0x00,
0x08, 0x00, 0x00, 0x00,
0x22, 0x66, 0x04, 0x10,
0xb2, 0x42, 0x82, 0x49,
0x10, 0x52, 0x42, 0x82,
0x49, 0x90, 0x71, 0xc2,
0x50, 0x48, 0x0a, 0x09,
0x26, 0x41, 0xc6, 0x05,
0x42, 0x12, 0x26, 0x08,
0x82, 0x81, 0x00, 0x00,
0x1a, 0x21, 0x4c, 0x0e,
0x13, 0x36, 0xdb, 0xde,
0x6e, 0xb1, 0xd3, 0xee,
0xb5, 0xc4, 0x06, 0x81,
0xa2, 0x24, 0x01, 0x00,
};
buffer.append_slice(&typeinfo_block);
const metadata_kind_block = [_]u8{
0x00, 0xb1, 0x18, 0x00,
0xb9, 0x00, 0x00, 0x00,
0x33, 0x08, 0x80, 0x1c,
0xc4, 0xe1, 0x1c, 0x66,
0x14, 0x01, 0x3d, 0x88,
0x43, 0x38, 0x84, 0xc3,
0x8c, 0x42, 0x80, 0x07,
0x79, 0x78, 0x07, 0x73,
0x98, 0x71, 0x0c, 0xe6,
0x00, 0x0f, 0xed, 0x10,
0x0e, 0xf4, 0x80, 0x0e,
0x33, 0x0c, 0x42, 0x1e,
0xc2, 0xc1, 0x1d, 0xce,
0xa1, 0x1c, 0x66, 0x30,
0x05, 0x3d, 0x88, 0x43,
0x38, 0x84, 0x83, 0x1b,
0xcc, 0x03, 0x3d, 0xc8,
0x43, 0x3d, 0x8c, 0x03,
0x3d, 0xcc, 0x78, 0x8c,
0x74, 0x70, 0x07, 0x7b,
0x08, 0x07, 0x79, 0x48,
0x87, 0x70, 0x70, 0x07,
0x7a, 0x70, 0x03, 0x76,
0x78, 0x87, 0x70, 0x20,
0x87, 0x19, 0xcc, 0x11,
0x0e, 0xec, 0x90, 0x0e,
0xe1, 0x30, 0x0f, 0x6e,
0x30, 0x0f, 0xe3, 0xf0,
0x0e, 0xf0, 0x50, 0x0e,
0x33, 0x10, 0xc4, 0x1d,
0xde, 0x21, 0x1c, 0xd8,
0x21, 0x1d, 0xc2, 0x61,
0x1e, 0x66, 0x30, 0x89,
0x3b, 0xbc, 0x83, 0x3b,
0xd0, 0x43, 0x39, 0xb4,
0x03, 0x3c, 0xbc, 0x83,
0x3c, 0x84, 0x03, 0x3b,
0xcc, 0xf0, 0x14, 0x76,
0x60, 0x07, 0x7b, 0x68,
0x07, 0x37, 0x68, 0x87,
0x72, 0x68, 0x07, 0x37,
0x80, 0x87, 0x70, 0x90,
0x87, 0x70, 0x60, 0x07,
0x76, 0x28, 0x07, 0x76,
0xf8, 0x05, 0x76, 0x78,
0x87, 0x77, 0x80, 0x87,
0x5f, 0x08, 0x87, 0x71,
0x18, 0x87, 0x72, 0x98,
0x87, 0x79, 0x98, 0x81,
0x2c, 0xee, 0xf0, 0x0e,
0xee, 0xe0, 0x0e, 0xf5,
0xc0, 0x0e, 0xec, 0x30,
0x03, 0x62, 0xc8, 0xa1,
0x1c, 0xe4, 0xa1, 0x1c,
0xcc, 0xa1, 0x1c, 0xe4,
0xa1, 0x1c, 0xdc, 0x61,
0x1c, 0xca, 0x21, 0x1c,
0xc4, 0x81, 0x1d, 0xca,
0x61, 0x06, 0xd6, 0x90,
0x43, 0x39, 0xc8, 0x43,
0x39, 0x98, 0x43, 0x39,
0xc8, 0x43, 0x39, 0xb8,
0xc3, 0x38, 0x94, 0x43,
0x38, 0x88, 0x03, 0x3b,
0x94, 0xc3, 0x2f, 0xbc,
0x83, 0x3c, 0xfc, 0x82,
0x3b, 0xd4, 0x03, 0x3b,
0xb0, 0xc3, 0x0c, 0xc7,
0x69, 0x87, 0x70, 0x58,
0x87, 0x72, 0x70, 0x83,
0x74, 0x68, 0x07, 0x78,
0x60, 0x87, 0x74, 0x18,
0x87, 0x74, 0xa0, 0x87,
0x19, 0xce, 0x53, 0x0f,
0xee, 0x00, 0x0f, 0xf2,
0x50, 0x0e, 0xe4, 0x90,
0x0e, 0xe3, 0x40, 0x0f,
0xe1, 0x20, 0x0e, 0xec,
0x50, 0x0e, 0x33, 0x20,
0x28, 0x1d, 0xdc, 0xc1,
0x1e, 0xc2, 0x41, 0x1e,
0xd2, 0x21, 0x1c, 0xdc,
0x81, 0x1e, 0xdc, 0xe0,
0x1c, 0xe4, 0xe1, 0x1d,
0xea, 0x01, 0x1e, 0x66,
0x18, 0x51, 0x38, 0xb0,
0x43, 0x3a, 0x9c, 0x83,
0x3b, 0xcc, 0x50, 0x24,
0x76, 0x60, 0x07, 0x7b,
0x68, 0x07, 0x37, 0x60,
0x87, 0x77, 0x78, 0x07,
0x78, 0x98, 0x51, 0x4c,
0xf4, 0x90, 0x0f, 0xf0,
0x50, 0x0e, 0x33, 0x1e,
0x6a, 0x1e, 0xca, 0x61,
0x1c, 0xe8, 0x21, 0x1d,
0xde, 0xc1, 0x1d, 0x7e,
0x01, 0x1e, 0xe4, 0xa1,
0x1c, 0xcc, 0x21, 0x1d,
0xf0, 0x61, 0x06, 0x54,
0x85, 0x83, 0x38, 0xcc,
0xc3, 0x3b, 0xb0, 0x43,
0x3d, 0xd0, 0x43, 0x39,
0xfc, 0xc2, 0x3c, 0xe4,
0x43, 0x3b, 0x88, 0xc3,
0x3b, 0xb0, 0xc3, 0x8c,
0xc5, 0x0a, 0x87, 0x79,
0x98, 0x87, 0x77, 0x18,
0x87, 0x74, 0x08, 0x07,
0x7a, 0x28, 0x07, 0x72,
0x98, 0x81, 0x5c, 0xe3,
0x10, 0x0e, 0xec, 0xc0,
0x0e, 0xe5, 0x50, 0x0e,
0xf3, 0x30, 0x23, 0xc1,
0xd2, 0x41, 0x1e, 0xe4,
0xe1, 0x17, 0xd8, 0xe1,
0x1d, 0xde, 0x01, 0x1e,
0x66, 0x48, 0x19, 0x3b,
0xb0, 0x83, 0x3d, 0xb4,
0x83, 0x1b, 0x84, 0xc3,
0x38, 0x8c, 0x43, 0x39,
0xcc, 0xc3, 0x3c, 0xb8,
0xc1, 0x39, 0xc8, 0xc3,
0x3b, 0xd4, 0x03, 0x3c,
0xcc, 0x48, 0xb4, 0x71,
0x08, 0x07, 0x76, 0x60,
0x07, 0x71, 0x08, 0x87,
0x71, 0x58, 0x87, 0x19,
0xdb, 0xc6, 0x0e, 0xec,
0x60, 0x0f, 0xed, 0xe0,
0x06, 0xf0, 0x20, 0x0f,
0xe5, 0x30, 0x0f, 0xe5,
0x20, 0x0f, 0xf6, 0x50,
0x0e, 0x6e, 0x10, 0x0e,
0xe3, 0x30, 0x0e, 0xe5,
0x30, 0x0f, 0xf3, 0xe0,
0x06, 0xe9, 0xe0, 0x0e,
0xe4, 0x50, 0x0e, 0xf8,
0x30, 0x23, 0xe2, 0xec,
0x61, 0x1c, 0xc2, 0x81,
0x1d, 0xd8, 0xe1, 0x17,
0xec, 0x21, 0x1d, 0xe6,
0x21, 0x1d, 0xc4, 0x21,
0x1d, 0xd8, 0x21, 0x1d,
0xe8, 0x21, 0x1f, 0x66,
0x20, 0x9d, 0x3b, 0xbc,
0x43, 0x3d, 0xb8, 0x03,
0x39, 0x94, 0x83, 0x39,
0xcc, 0x58, 0xbc, 0x70,
0x70, 0x07, 0x77, 0x78,
0x07, 0x7a, 0x08, 0x07,
0x7a, 0x48, 0x87, 0x77,
0x70, 0x87, 0x19, 0xcb,
0xe7, 0x0e, 0xef, 0x30,
0x0f, 0xe1, 0xe0, 0x0e,
0xe9, 0x40, 0x0f, 0xe9,
0xa0, 0x0f, 0xe5, 0x30,
0xc3, 0x01, 0x03, 0x73,
0xa8, 0x07, 0x77, 0x18,
0x87, 0x5f, 0x98, 0x87,
0x70, 0x70, 0x87, 0x74,
0xa0, 0x87, 0x74, 0xd0,
0x87, 0x72, 0x98, 0x81,
0x84, 0x41, 0x39, 0xe0,
0xc3, 0x38, 0xb0, 0x43,
0x3d, 0x90, 0x43, 0x39,
0xcc, 0x40, 0xc4, 0xa0,
0x1d, 0xca, 0xa1, 0x1d,
0xe0, 0x41, 0x1e, 0xde,
0xc1, 0x1c, 0x66, 0x24,
0x63, 0x30, 0x0e, 0xe1,
0xc0, 0x0e, 0xec, 0x30,
0x0f, 0xe9, 0x40, 0x0f,
0xe5, 0x30, 0x43, 0x21,
0x83, 0x75, 0x18, 0x07,
0x73, 0x48, 0x87, 0x5f,
0xa0, 0x87, 0x7c, 0x80,
0x87, 0x72, 0x98, 0xb1,
0x94, 0x01, 0x3c, 0x8c,
0xc3, 0x3c, 0x94, 0xc3,
0x38, 0xd0, 0x43, 0x3a,
0xbc, 0x83, 0x3b, 0xcc,
0xc3, 0x8c, 0xc5, 0x0c,
0x48, 0x21, 0x15, 0x42,
0x61, 0x1e, 0xe6, 0x21,
0x1d, 0xce, 0xc1, 0x1d,
0x52, 0x81, 0x14, 0x00,
};
buffer.append_slice(&metadata_kind_block);
const operand_bundle_tag = [_]u8{
0xa9, 0x18, 0x00, 0x00,
0x2d, 0x00, 0x00, 0x00,
0x0b, 0x0a, 0x72, 0x28,
0x87, 0x77, 0x80, 0x07,
0x7a, 0x58, 0x70, 0x98,
0x43, 0x3d, 0xb8, 0xc3,
0x38, 0xb0, 0x43, 0x39,
0xd0, 0xc3, 0x82, 0xe6,
0x1c, 0xc6, 0xa1, 0x0d,
0xe8, 0x41, 0x1e, 0xc2,
0xc1, 0x1d, 0xe6, 0x21,
0x1d, 0xe8, 0x21, 0x1d,
0xde, 0xc1, 0x1d, 0x16,
0x34, 0xe3, 0x60, 0x0e,
0xe7, 0x50, 0x0f, 0xe1,
0x20, 0x0f, 0xe4, 0x40,
0x0f, 0xe1, 0x20, 0x0f,
0xe7, 0x50, 0x0e, 0xf4,
0xb0, 0x80, 0x81, 0x07,
0x79, 0x28, 0x87, 0x70,
0x60, 0x07, 0x76, 0x78,
0x87, 0x71, 0x08, 0x07,
0x7a, 0x28, 0x07, 0x72,
0x58, 0x70, 0x9c, 0xc3,
0x38, 0xb4, 0x01, 0x3b,
0xa4, 0x83, 0x3d, 0x94,
0xc3, 0x02, 0x6b, 0x1c,
0xd8, 0x21, 0x1c, 0xdc,
0xe1, 0x1c, 0xdc, 0x20,
0x1c, 0xe4, 0x61, 0x1c,
0xdc, 0x20, 0x1c, 0xe8,
0x81, 0x1e, 0xc2, 0x61,
0x1c, 0xd0, 0xa1, 0x1c,
0xc8, 0x61, 0x1c, 0xc2,
0x81, 0x1d, 0xd8, 0x61,
0xc1, 0x01, 0x0f, 0xf4,
0x20, 0x0f, 0xe1, 0x50,
0x0f, 0xf4, 0x80, 0x0e,
0x0b, 0x88, 0x75, 0x18,
0x07, 0x73, 0x48, 0x87,
0x05, 0xcf, 0x38, 0xbc,
0x83, 0x3b, 0xd8, 0x43,
0x39, 0xc8, 0xc3, 0x39,
0x94, 0x83, 0x3b, 0x8c,
0x43, 0x39, 0x8c, 0x03,
0x3d, 0xc8, 0x03, 0x3b,
0x00, 0x00, 0x00, 0x00,
};
buffer.append_slice(&operand_bundle_tag);
const value26 = [_]u8{
0xd1, 0x10, 0x00, 0x00,
0x06, 0x00, 0x00, 0x00,
0x07, 0xcc, 0x3c, 0xa4,
0x83, 0x3b, 0x9c, 0x03,
0x3b, 0x94, 0x03, 0x3d,
0xa0, 0x83, 0x3c, 0x94,
0x43, 0x38, 0x90, 0xc3,
0x01, 0x00, 0x00, 0x00,
};
buffer.append_slice(&value26);
const value_symtab = [_]u8{
0x71, 0x20, 0x00, 0x00,
0x02, 0x00, 0x00, 0x00,
0x32, 0x0e, 0x10, 0x22,
0x04, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00,
};
buffer.append_slice(&value_symtab);
const strtab = [_]u8{
0x5d, 0x0c, 0x00, 0x00,
0x06, 0x00, 0x00, 0x00,
0x12, 0x03, 0x94, 0x0f,
0x31, 0x37, 0x2e, 0x30,
0x2e, 0x36, 0x6c, 0x6c,
0x76, 0x6d, 0x2d, 0x6c,
0x69, 0x6e, 0x6b, 0x00,
0x00, 0x00, 0x00, 0x00,
};
buffer.append_slice(&strtab);
assert(buffer.length == sample_bitcode.len);
const context = LLVM.Context.create();
const module = context.parse_bitcode(buffer.slice()) orelse exit(1);
_ = module; // autofix
//
exit(0);
}
const sample_bitcode = [_]u8{
// Magic
0x42, 0x43, 0xc0, 0xde,
// Start of the identification block
0x35, 0x14, 0x00, 0x00,
0x05, 0x00, 0x00, 0x00,
0x62, 0x0c, 0x30, 0x24,
0x4a, 0x59, 0xbe, 0x66,
0xbd, 0xfb, 0xb4, 0xaf,
0x0b, 0x51, 0x80, 0x4c,
0x01, 0x00, 0x00, 0x00,
// It looks like this is the start of the module block
0x21, 0x0c, 0x00, 0x00,
0x1f, 0x01, 0x00, 0x00,
0x0b, 0x02, 0x21, 0x00,
// start of the blockinfo block?
0x02, 0x00, 0x00, 0x00,
0x16, 0x00, 0x00, 0x00,
0x07, 0x81, 0x23, 0x91,
0x41, 0xc8, 0x04, 0x49,
0x06, 0x10, 0x32, 0x39,
0x92, 0x01, 0x84, 0x0c,
0x25, 0x05, 0x08, 0x19,
0x1e, 0x04, 0x8b, 0x62,
0x80, 0x04, 0x45, 0x02,
0x42, 0x92, 0x0b, 0x42,
0x24, 0x10, 0x32, 0x14,
0x38, 0x08, 0x18, 0x4b,
0x0a, 0x32, 0x12, 0x88,
0x48, 0x70, 0xc4, 0x21,
0x23, 0x44, 0x12, 0x87,
0x8c, 0x10, 0x41, 0x92,
0x02, 0x64, 0xc8, 0x08,
0xb1, 0x14, 0x20, 0x43,
0x46, 0x88, 0x20, 0xc9,
0x01, 0x32, 0x12, 0x84,
0x18, 0x2a, 0x28, 0x2a,
0x90, 0x31, 0x7c, 0xb0,
0x5c, 0x91, 0x20, 0xc1,
0xc8, 0x00, 0x00, 0x00,
// type block?
0x89, 0x20, 0x00, 0x00,
0x08, 0x00, 0x00, 0x00,
0x22, 0x66, 0x04, 0x10,
0xb2, 0x42, 0x82, 0x49,
0x10, 0x52, 0x42, 0x82,
0x49, 0x90, 0x71, 0xc2,
0x50, 0x48, 0x0a, 0x09,
0x26, 0x41, 0xc6, 0x05,
0x42, 0x12, 0x26, 0x08,
0x82, 0x81, 0x00, 0x00,
0x1a, 0x21, 0x4c, 0x0e,
0x13, 0x36, 0xdb, 0xde,
0x6e, 0xb1, 0xd3, 0xee,
0xb5, 0xc4, 0x06, 0x81,
0xa2, 0x24, 0x01, 0x00,
// metadata kind block?
0x00, 0xb1, 0x18, 0x00,
0xb9, 0x00, 0x00, 0x00,
0x33, 0x08, 0x80, 0x1c,
0xc4, 0xe1, 0x1c, 0x66,
0x14, 0x01, 0x3d, 0x88,
0x43, 0x38, 0x84, 0xc3,
0x8c, 0x42, 0x80, 0x07,
0x79, 0x78, 0x07, 0x73,
0x98, 0x71, 0x0c, 0xe6,
0x00, 0x0f, 0xed, 0x10,
0x0e, 0xf4, 0x80, 0x0e,
0x33, 0x0c, 0x42, 0x1e,
0xc2, 0xc1, 0x1d, 0xce,
0xa1, 0x1c, 0x66, 0x30,
0x05, 0x3d, 0x88, 0x43,
0x38, 0x84, 0x83, 0x1b,
0xcc, 0x03, 0x3d, 0xc8,
0x43, 0x3d, 0x8c, 0x03,
0x3d, 0xcc, 0x78, 0x8c,
0x74, 0x70, 0x07, 0x7b,
0x08, 0x07, 0x79, 0x48,
0x87, 0x70, 0x70, 0x07,
0x7a, 0x70, 0x03, 0x76,
0x78, 0x87, 0x70, 0x20,
0x87, 0x19, 0xcc, 0x11,
0x0e, 0xec, 0x90, 0x0e,
0xe1, 0x30, 0x0f, 0x6e,
0x30, 0x0f, 0xe3, 0xf0,
0x0e, 0xf0, 0x50, 0x0e,
0x33, 0x10, 0xc4, 0x1d,
0xde, 0x21, 0x1c, 0xd8,
0x21, 0x1d, 0xc2, 0x61,
0x1e, 0x66, 0x30, 0x89,
0x3b, 0xbc, 0x83, 0x3b,
0xd0, 0x43, 0x39, 0xb4,
0x03, 0x3c, 0xbc, 0x83,
0x3c, 0x84, 0x03, 0x3b,
0xcc, 0xf0, 0x14, 0x76,
0x60, 0x07, 0x7b, 0x68,
0x07, 0x37, 0x68, 0x87,
0x72, 0x68, 0x07, 0x37,
0x80, 0x87, 0x70, 0x90,
0x87, 0x70, 0x60, 0x07,
0x76, 0x28, 0x07, 0x76,
0xf8, 0x05, 0x76, 0x78,
0x87, 0x77, 0x80, 0x87,
0x5f, 0x08, 0x87, 0x71,
0x18, 0x87, 0x72, 0x98,
0x87, 0x79, 0x98, 0x81,
0x2c, 0xee, 0xf0, 0x0e,
0xee, 0xe0, 0x0e, 0xf5,
0xc0, 0x0e, 0xec, 0x30,
0x03, 0x62, 0xc8, 0xa1,
0x1c, 0xe4, 0xa1, 0x1c,
0xcc, 0xa1, 0x1c, 0xe4,
0xa1, 0x1c, 0xdc, 0x61,
0x1c, 0xca, 0x21, 0x1c,
0xc4, 0x81, 0x1d, 0xca,
0x61, 0x06, 0xd6, 0x90,
0x43, 0x39, 0xc8, 0x43,
0x39, 0x98, 0x43, 0x39,
0xc8, 0x43, 0x39, 0xb8,
0xc3, 0x38, 0x94, 0x43,
0x38, 0x88, 0x03, 0x3b,
0x94, 0xc3, 0x2f, 0xbc,
0x83, 0x3c, 0xfc, 0x82,
0x3b, 0xd4, 0x03, 0x3b,
0xb0, 0xc3, 0x0c, 0xc7,
0x69, 0x87, 0x70, 0x58,
0x87, 0x72, 0x70, 0x83,
0x74, 0x68, 0x07, 0x78,
0x60, 0x87, 0x74, 0x18,
0x87, 0x74, 0xa0, 0x87,
0x19, 0xce, 0x53, 0x0f,
0xee, 0x00, 0x0f, 0xf2,
0x50, 0x0e, 0xe4, 0x90,
0x0e, 0xe3, 0x40, 0x0f,
0xe1, 0x20, 0x0e, 0xec,
0x50, 0x0e, 0x33, 0x20,
0x28, 0x1d, 0xdc, 0xc1,
0x1e, 0xc2, 0x41, 0x1e,
0xd2, 0x21, 0x1c, 0xdc,
0x81, 0x1e, 0xdc, 0xe0,
0x1c, 0xe4, 0xe1, 0x1d,
0xea, 0x01, 0x1e, 0x66,
0x18, 0x51, 0x38, 0xb0,
0x43, 0x3a, 0x9c, 0x83,
0x3b, 0xcc, 0x50, 0x24,
0x76, 0x60, 0x07, 0x7b,
0x68, 0x07, 0x37, 0x60,
0x87, 0x77, 0x78, 0x07,
0x78, 0x98, 0x51, 0x4c,
0xf4, 0x90, 0x0f, 0xf0,
0x50, 0x0e, 0x33, 0x1e,
0x6a, 0x1e, 0xca, 0x61,
0x1c, 0xe8, 0x21, 0x1d,
0xde, 0xc1, 0x1d, 0x7e,
0x01, 0x1e, 0xe4, 0xa1,
0x1c, 0xcc, 0x21, 0x1d,
0xf0, 0x61, 0x06, 0x54,
0x85, 0x83, 0x38, 0xcc,
0xc3, 0x3b, 0xb0, 0x43,
0x3d, 0xd0, 0x43, 0x39,
0xfc, 0xc2, 0x3c, 0xe4,
0x43, 0x3b, 0x88, 0xc3,
0x3b, 0xb0, 0xc3, 0x8c,
0xc5, 0x0a, 0x87, 0x79,
0x98, 0x87, 0x77, 0x18,
0x87, 0x74, 0x08, 0x07,
0x7a, 0x28, 0x07, 0x72,
0x98, 0x81, 0x5c, 0xe3,
0x10, 0x0e, 0xec, 0xc0,
0x0e, 0xe5, 0x50, 0x0e,
0xf3, 0x30, 0x23, 0xc1,
0xd2, 0x41, 0x1e, 0xe4,
0xe1, 0x17, 0xd8, 0xe1,
0x1d, 0xde, 0x01, 0x1e,
0x66, 0x48, 0x19, 0x3b,
0xb0, 0x83, 0x3d, 0xb4,
0x83, 0x1b, 0x84, 0xc3,
0x38, 0x8c, 0x43, 0x39,
0xcc, 0xc3, 0x3c, 0xb8,
0xc1, 0x39, 0xc8, 0xc3,
0x3b, 0xd4, 0x03, 0x3c,
0xcc, 0x48, 0xb4, 0x71,
0x08, 0x07, 0x76, 0x60,
0x07, 0x71, 0x08, 0x87,
0x71, 0x58, 0x87, 0x19,
0xdb, 0xc6, 0x0e, 0xec,
0x60, 0x0f, 0xed, 0xe0,
0x06, 0xf0, 0x20, 0x0f,
0xe5, 0x30, 0x0f, 0xe5,
0x20, 0x0f, 0xf6, 0x50,
0x0e, 0x6e, 0x10, 0x0e,
0xe3, 0x30, 0x0e, 0xe5,
0x30, 0x0f, 0xf3, 0xe0,
0x06, 0xe9, 0xe0, 0x0e,
0xe4, 0x50, 0x0e, 0xf8,
0x30, 0x23, 0xe2, 0xec,
0x61, 0x1c, 0xc2, 0x81,
0x1d, 0xd8, 0xe1, 0x17,
0xec, 0x21, 0x1d, 0xe6,
0x21, 0x1d, 0xc4, 0x21,
0x1d, 0xd8, 0x21, 0x1d,
0xe8, 0x21, 0x1f, 0x66,
0x20, 0x9d, 0x3b, 0xbc,
0x43, 0x3d, 0xb8, 0x03,
0x39, 0x94, 0x83, 0x39,
0xcc, 0x58, 0xbc, 0x70,
0x70, 0x07, 0x77, 0x78,
0x07, 0x7a, 0x08, 0x07,
0x7a, 0x48, 0x87, 0x77,
0x70, 0x87, 0x19, 0xcb,
0xe7, 0x0e, 0xef, 0x30,
0x0f, 0xe1, 0xe0, 0x0e,
0xe9, 0x40, 0x0f, 0xe9,
0xa0, 0x0f, 0xe5, 0x30,
0xc3, 0x01, 0x03, 0x73,
0xa8, 0x07, 0x77, 0x18,
0x87, 0x5f, 0x98, 0x87,
0x70, 0x70, 0x87, 0x74,
0xa0, 0x87, 0x74, 0xd0,
0x87, 0x72, 0x98, 0x81,
0x84, 0x41, 0x39, 0xe0,
0xc3, 0x38, 0xb0, 0x43,
0x3d, 0x90, 0x43, 0x39,
0xcc, 0x40, 0xc4, 0xa0,
0x1d, 0xca, 0xa1, 0x1d,
0xe0, 0x41, 0x1e, 0xde,
0xc1, 0x1c, 0x66, 0x24,
0x63, 0x30, 0x0e, 0xe1,
0xc0, 0x0e, 0xec, 0x30,
0x0f, 0xe9, 0x40, 0x0f,
0xe5, 0x30, 0x43, 0x21,
0x83, 0x75, 0x18, 0x07,
0x73, 0x48, 0x87, 0x5f,
0xa0, 0x87, 0x7c, 0x80,
0x87, 0x72, 0x98, 0xb1,
0x94, 0x01, 0x3c, 0x8c,
0xc3, 0x3c, 0x94, 0xc3,
0x38, 0xd0, 0x43, 0x3a,
0xbc, 0x83, 0x3b, 0xcc,
0xc3, 0x8c, 0xc5, 0x0c,
0x48, 0x21, 0x15, 0x42,
0x61, 0x1e, 0xe6, 0x21,
0x1d, 0xce, 0xc1, 0x1d,
0x52, 0x81, 0x14, 0x00,
// operand bundle tags block?
0xa9, 0x18, 0x00, 0x00,
0x2d, 0x00, 0x00, 0x00,
0x0b, 0x0a, 0x72, 0x28,
0x87, 0x77, 0x80, 0x07,
0x7a, 0x58, 0x70, 0x98,
0x43, 0x3d, 0xb8, 0xc3,
0x38, 0xb0, 0x43, 0x39,
0xd0, 0xc3, 0x82, 0xe6,
0x1c, 0xc6, 0xa1, 0x0d,
0xe8, 0x41, 0x1e, 0xc2,
0xc1, 0x1d, 0xe6, 0x21,
0x1d, 0xe8, 0x21, 0x1d,
0xde, 0xc1, 0x1d, 0x16,
0x34, 0xe3, 0x60, 0x0e,
0xe7, 0x50, 0x0f, 0xe1,
0x20, 0x0f, 0xe4, 0x40,
0x0f, 0xe1, 0x20, 0x0f,
0xe7, 0x50, 0x0e, 0xf4,
0xb0, 0x80, 0x81, 0x07,
0x79, 0x28, 0x87, 0x70,
0x60, 0x07, 0x76, 0x78,
0x87, 0x71, 0x08, 0x07,
0x7a, 0x28, 0x07, 0x72,
0x58, 0x70, 0x9c, 0xc3,
0x38, 0xb4, 0x01, 0x3b,
0xa4, 0x83, 0x3d, 0x94,
0xc3, 0x02, 0x6b, 0x1c,
0xd8, 0x21, 0x1c, 0xdc,
0xe1, 0x1c, 0xdc, 0x20,
0x1c, 0xe4, 0x61, 0x1c,
0xdc, 0x20, 0x1c, 0xe8,
0x81, 0x1e, 0xc2, 0x61,
0x1c, 0xd0, 0xa1, 0x1c,
0xc8, 0x61, 0x1c, 0xc2,
0x81, 0x1d, 0xd8, 0x61,
0xc1, 0x01, 0x0f, 0xf4,
0x20, 0x0f, 0xe1, 0x50,
0x0f, 0xf4, 0x80, 0x0e,
0x0b, 0x88, 0x75, 0x18,
0x07, 0x73, 0x48, 0x87,
0x05, 0xcf, 0x38, 0xbc,
0x83, 0x3b, 0xd8, 0x43,
0x39, 0xc8, 0xc3, 0x39,
0x94, 0x83, 0x3b, 0x8c,
0x43, 0x39, 0x8c, 0x03,
0x3d, 0xc8, 0x03, 0x3b,
0x00, 0x00, 0x00, 0x00,
// Unknown block 26?
0xd1, 0x10, 0x00, 0x00,
0x06, 0x00, 0x00, 0x00,
0x07, 0xcc, 0x3c, 0xa4,
0x83, 0x3b, 0x9c, 0x03,
0x3b, 0x94, 0x03, 0x3d,
0xa0, 0x83, 0x3c, 0x94,
0x43, 0x38, 0x90, 0xc3,
0x01, 0x00, 0x00, 0x00,
// Value symtab block?
0x71, 0x20, 0x00, 0x00,
0x02, 0x00, 0x00, 0x00,
0x32, 0x0e, 0x10, 0x22,
0x04, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00,
// Start of the strtab block
0x5d, 0x0c, 0x00, 0x00,
0x06, 0x00, 0x00, 0x00,
0x12, 0x03, 0x94, 0x0f,
0x31, 0x37, 0x2e, 0x30,
0x2e, 0x36, 0x6c, 0x6c,
0x76, 0x6d, 0x2d, 0x6c,
0x69, 0x6e, 0x6b, 0x00,
0x00, 0x00, 0x00, 0x00,
};
const CallingConvention = enum {
c,
custom,
};
const Analyzer = struct {
current_basic_block: *BasicBlock = undefined,
current_function: *Function = undefined,
};
const bracket_open = 0x7b;
const bracket_close = 0x7d;
var cpu_count: u32 = 0;
const address_space = 0;
fn thread_callback(thread_index: u32) void {
var created_thread_count: u32 = 0;
while (true) {
const local_cpu_count = cpu_count;
if (local_cpu_count == 0) {
break;
}
if (@cmpxchgWeak(u32, &cpu_count, local_cpu_count, local_cpu_count - 1, .seq_cst, .seq_cst) == null) {
created_thread_count += 1;
const t = std.Thread.spawn(.{}, thread_callback, .{local_cpu_count - 1}) catch unreachable;
_ = t; // autofix
}
}
const thread = &threads[thread_index];
thread.arena = Arena.init(4 * 1024 * 1024) catch unreachable;
while (true) {
const to_do = thread.task_system.job.to_do;
const completed = thread.task_system.job.completed;
if (completed < to_do) {
const jobs = thread.task_system.job.entries[completed..to_do];
for (jobs) |job| {
switch (job.id) {
.llvm_setup => {
for ([_]Type.Integer.Signedness{ .unsigned, .signed }) |signedness| {
for (0..64 + 1) |bit_count| {
const integer_type = Type.Integer{
.bit_count = @intCast(bit_count),
.signedness = signedness,
};
_ = thread.types.append(.{
.sema = @bitCast(integer_type),
});
}
}
},
.analyze_file => {
const file_index = job.offset;
const file = &instance.files.slice()[file_index];
file.scope = .{
.id = .file,
.index = @intCast(thread.file_scopes.append_index(.{})),
};
file.state = .analyzing;
file.source_code = library.read_file(thread.arena, std.fs.cwd(), file.path);
file.thread = thread_index;
analyze_file(thread, file_index);
// if (do_codegen and codegen_backend == .llvm) {
// }
thread.analyzed_file_count += 1;
for (file.interested_threads.slice()) |ti| {
thread.add_control_work(.{
.id = .notify_file_resolved,
.offset = file_index,
.count = @intCast(ti),
});
}
},
.notify_file_resolved => {
const file_path_hash = job.offset;
const file_index = job.count;
const file = &instance.files.pointer[file_index];
const file_scope = threads[file.thread].file_scopes.get(@enumFromInt(file.scope.index));
if (&threads[file.thread] == thread) {
exit_with_error("Threads match!");
} else {
const pending_file_index = for (thread.pending_files.slice(), 0..) |pending_file_path_hash, i| {
if (file_path_hash == pending_file_path_hash) {
break i;
}
} else {
exit(1);
};
// _ = pending_file_index; // autofix
const pending_file_values = thread.pending_file_values.get(@enumFromInt(pending_file_index));
for (pending_file_values.slice()) |value| {
assert(value.sema.thread == thread.get_index());
if (!value.sema.resolved) {
switch (value.sema.id) {
.instruction => {
const instruction = thread.instructions.get(@enumFromInt(value.sema.index));
switch (instruction.id) {
.call => {
const call = thread.calls.get(@enumFromInt(instruction.index));
const callable = call.value;
assert(!callable.sema.resolved);
switch (callable.sema.id) {
.lazy_expression => {
const lazy_expression = thread.lazy_expressions.get(@enumFromInt(callable.sema.index));
assert(lazy_expression.* == .static);
const names = lazy_expression.names();
assert(names.len > 0);
const declaration = lazy_expression.static.outsider;
switch (declaration.id) {
.file => {},
// .unresolved_import => {
// assert(declaration.index == pending_file_index);
// declaration.id = .file;
// declaration.index = file_index;
// value.resolved = true;
// unreachable;
// },
else => |t| @panic(@tagName(t)),
}
assert(names.len == 1);
if (file_scope.declarations.get(names[0])) |callable_declaration| switch (callable_declaration.id) {
.function_definition => {
const function_definition = threads[file.thread].functions.get_unchecked(callable_declaration.index);
const external_fn = thread.external_functions.append(function_definition.declaration);
external_fn.global.attributes.@"export" = false;
external_fn.global.attributes.@"extern" = true;
const new_callable_declaration = GlobalSymbolReference{
.id = .function_declaration,
.index = @intCast(thread.external_functions.get_index(external_fn)),
};
const new_callable_value = thread.values.append(.{
.sema = .{
.id = .global_symbol,
.index = @bitCast(new_callable_declaration),
.thread = thread.get_index(),
.resolved = true,
},
});
call.value = new_callable_value;
value.sema.resolved = true;
},
else => |t| @panic(@tagName(t)),
// unreachable;
// // const new_callable_value = thread.values.append(.{
// // .id = .global_symbol,
// // .index = @bitCast(callable_declaration),
// // .thread = @intCast(file.thread),
// // .resolved = true,
// // });
// // call.value = new_callable_value;
// // value.resolved = true;
} else exit(1);
},
else => |t| @panic(@tagName(t)),
}
},
else => |t| @panic(@tagName(t)),
}
},
.lazy_expression => {
const lazy_expression = thread.lazy_expressions.get(@enumFromInt(value.sema.index));
assert(lazy_expression.* == .static);
for (lazy_expression.static.names) |n| {
assert(n == 0);
}
const declaration = lazy_expression.static.outsider;
switch (declaration.id) {
.unresolved_import => {
assert(declaration.index == pending_file_index);
declaration.id = .file;
declaration.index = file_index;
value.sema.resolved = true;
},
else => |t| @panic(@tagName(t)),
}
},
else => |t| @panic(@tagName(t)),
}
}
}
}
},
.resolve_thread_module => {
// exit(0);
},
.llvm_codegen_thread_module => {
if (thread.functions.length > 0) {
// const bytes = library.read_file(instance.arena, std.fs.cwd(), "/home/david/empty.ll");
// for (bytes, 0..) |b, i| {
// if (i % 4 == 0) {
// std.debug.print("\n ", .{});
// }
// std.debug.print("0x{x:0>2}, ", .{b});
// }
write_bitcode();
// _ = result; // autofix
exit(0);
// const bytes = library.read_file(instance.arena, std.fs.cwd(), "/home/david/mybitcode.ll");
// for (bytes, 0..) |*b, i| {
// if (i % 4 == 0) {
// std.debug.print("\n[{}] 0x{x:<8}: ", .{i, @as(*const u32, @alignCast(@ptrCast(b))).*});
// }
// std.debug.print("[{}] 0x{x:<2} ", .{i, b.*});
// }
// write("\n");
// 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);
// }
// }
}
},
}
thread.task_system.job.completed += 1;
}
}
std.atomic.spinLoopHint();
}
}
fn llvm_get_value(thread: *Thread, value: *Value) *LLVM.Value {
if (value.llvm) |llvm| return llvm else {
const value_id = value.sema.id;
const llvm_value: *LLVM.Value = switch (value_id) {
.constant_int => b: {
const constant_int = thread.constant_ints.get(@enumFromInt(value.sema.index));
const integer_value = constant_int.value;
const bit_count = integer_bit_count(constant_int.type);
const signedness = integer_signedness(constant_int.type);
const result = thread.llvm.context.getConstantInt(bit_count, integer_value, @intFromEnum(signedness) != 0);
break :b result.toValue();
},
.lazy_expression => {
// const lazy_expression = thread.expressions.get(@enumFromInt(value.index));
// switch (lazy_expression.kind) {
// .resolved => |resolved| switch (resolved) {
// .instruction => |instruction| switch (instruction.id) {
// else => |t| @panic(@tagName(t)),
// },
// else => |t| @panic(@tagName(t)),
// },
// else => |t| @panic(@tagName(t)),
// }
@trap();
},
.instruction => block: {
const instruction = thread.instructions.get_unchecked(value.sema.index);
break :block instruction.llvm.?;
},
else => |t| @panic(@tagName(t)),
};
value.llvm = llvm_value;
return llvm_value;
}
}
fn llvm_get_type(thread: *Thread, ty: *Type) *LLVM.Type {
var store = true;
if (ty.llvm) |llvm| {
if (llvm.getContext() == thread.llvm.context) {
return llvm;
}
store = false;
}
{
const llvm_type: *LLVM.Type = switch (ty.sema.id) {
.integer => b: {
const bit_count = integer_bit_count(ty);
const integer_type = thread.llvm.context.getIntegerType(bit_count);
break :b integer_type.toType();
},
else => |t| @panic(@tagName(t)),
};
if (store) {
ty.llvm = llvm_type;
}
return llvm_type;
}
}
fn llvm_get_file(thread: *Thread, file_index: u32) *LLVMFile {
if (thread.debug_info_file_map.get_pointer(file_index)) |llvm| return llvm else {
const builder = thread.llvm.module.createDebugInfoBuilder();
const file = &instance.files.slice()[file_index];
const filename = std.fs.path.basename(file.path);
const directory = file.path[0 .. file.path.len - filename.len];
const llvm_file = builder.createFile(filename.ptr, filename.len, directory.ptr, directory.len);
const producer = "nativity";
const is_optimized = false;
const flags = "";
const runtime_version = 0;
const splitname = "";
const DWOId = 0;
const debug_info_kind = LLVM.DebugInfo.CompileUnit.EmissionKind.full_debug;
const split_debug_inlining = true;
const debug_info_for_profiling = false;
const name_table_kind = LLVM.DebugInfo.CompileUnit.NameTableKind.default;
const ranges_base_address = false;
const sysroot = "";
const sdk = "";
const compile_unit = builder.createCompileUnit(LLVM.DebugInfo.Language.c, llvm_file, producer, producer.len, is_optimized, flags, flags.len, runtime_version, splitname, splitname.len, debug_info_kind, DWOId, split_debug_inlining, debug_info_for_profiling, name_table_kind, ranges_base_address, sysroot, sysroot.len, sdk, sdk.len);
thread.debug_info_file_map.put_no_clobber(file_index, .{
.file = llvm_file,
.compile_unit = compile_unit,
.builder = builder,
});
return thread.debug_info_file_map.get_pointer(file_index).?;
}
}
fn llvm_get_function(thread: *Thread, nat_function: *Function.Declaration, override_extern: bool) *LLVM.Value.Constant.Function {
if (nat_function.llvm) |llvm| return llvm else {
_ = override_extern; // autofix
const function_name = thread.identifiers.get(nat_function.global.name) orelse unreachable;
const return_type = llvm_get_type(thread, nat_function.return_type);
var argument_types = PinnedArray(*LLVM.Type){};
_ = &argument_types;
for (nat_function.argument_types) |argument_type| {
_ = argument_type; // autofix
exit(1);
}
const is_var_args = false;
const function_type = LLVM.getFunctionType(return_type, argument_types.pointer, argument_types.length, is_var_args);
const is_extern_function = nat_function.global.attributes.@"extern";
const export_or_extern = nat_function.global.attributes.@"export" or is_extern_function;
const linkage: LLVM.Linkage = switch (export_or_extern) {
true => .@"extern",
false => .internal,
};
const function = thread.llvm.module.createFunction(function_type, linkage, address_space, function_name.ptr, function_name.len);
const debug_info = true;
if (debug_info) {
const file_index = nat_function.file;
const llvm_file = llvm_get_file(thread, file_index);
var debug_argument_types = PinnedArray(*LLVM.DebugInfo.Type){};
_ = &debug_argument_types;
for (nat_function.argument_types) |argument_type| {
_ = argument_type; // autofix
exit(1);
}
const subroutine_type_flags = LLVM.DebugInfo.Node.Flags{
.visibility = .none,
.forward_declaration = is_extern_function,
.apple_block = false,
.block_by_ref_struct = false,
.virtual = false,
.artificial = false,
.explicit = false,
.prototyped = false,
.objective_c_class_complete = false,
.object_pointer = false,
.vector = false,
.static_member = false,
.lvalue_reference = false,
.rvalue_reference = false,
.reserved = false,
.inheritance = .none,
.introduced_virtual = false,
.bit_field = false,
.no_return = false,
.type_pass_by_value = false,
.type_pass_by_reference = false,
.enum_class = false,
.thunk = false,
.non_trivial = false,
.big_endian = false,
.little_endian = false,
.all_calls_described = false,
};
const subroutine_type_calling_convention = LLVM.DebugInfo.CallingConvention.none;
const subroutine_type = llvm_file.builder.createSubroutineType(debug_argument_types.pointer, debug_argument_types.length, subroutine_type_flags, subroutine_type_calling_convention);
const subprogram_flags = LLVM.DebugInfo.Subprogram.Flags{
.virtuality = .none,
.local_to_unit = !export_or_extern,
.definition = !is_extern_function,
.optimized = false,
.pure = false,
.elemental = false,
.recursive = false,
.main_subprogram = false,
.deleted = false,
.object_c_direct = false,
};
const subprogram_declaration = null;
const file = llvm_file.file;
const scope = file.toScope();
const line = 0;
const scope_line = 0;
const subprogram = llvm_file.builder.createFunction(scope, function_name.ptr, function_name.len, function_name.ptr, function_name.len, file, line, subroutine_type, scope_line, subroutine_type_flags, subprogram_flags, subprogram_declaration);
function.setSubprogram(subprogram);
}
nat_function.llvm = function;
return function;
}
}
pub fn analyze_file(thread: *Thread, file_index: u32) void {
const file = instance.files.get(@enumFromInt(file_index));
const src = file.source_code;
if (src.len > std.math.maxInt(u32)) {
exit(1);
}
file.functions.start = @intCast(thread.functions.length);
var parser = Parser{};
var analyzer = Analyzer{};
while (true) {
parser.skip_space(src);
if (parser.i >= src.len) break;
const declaration_start_i = parser.i;
const declaration_start_ch = src[declaration_start_i];
switch (declaration_start_ch) {
'>' => {
parser.i += 1;
parser.skip_space(src);
const symbol_identifier_start = parser.i;
_ = symbol_identifier_start; // autofix
const identifier = parser.parse_identifier(thread, src);
_ = identifier; // autofix
exit(1);
},
'f' => {
if (src[parser.i + 1] == 'n') {
parser.i += 2;
parser.skip_space(src);
const function = thread.functions.add_one();
const function_index = thread.functions.get_index(function);
const entry_block = thread.basic_blocks.append(.{});
const entry_block_index = thread.basic_blocks.get_typed_index(entry_block);
analyzer.current_function = function;
analyzer.current_basic_block = entry_block;
function.* = .{
.declaration = .{
.return_type = undefined,
.global = .{
.name = undefined,
},
.file = file_index,
},
.entry_block = entry_block_index,
};
const has_function_attributes = src[parser.i] == '[';
parser.i += @intFromBool(has_function_attributes);
if (has_function_attributes) {
var attribute_mask = Function.Attribute.Mask.initEmpty();
while (true) {
parser.skip_space(src);
if (src[parser.i] == ']') break;
const attribute_identifier = parser.parse_raw_identifier(src);
b: inline for (@typeInfo(Function.Attribute).Enum.fields) |fa_field| {
if (byte_equal(fa_field.name, attribute_identifier)) {
const function_attribute = @field(Function.Attribute, fa_field.name);
if (attribute_mask.contains(function_attribute)) {
exit(1);
}
attribute_mask.setPresent(function_attribute, true);
switch (function_attribute) {
.cc => {
parser.skip_space(src);
parser.expect_character(src, '(');
parser.skip_space(src);
parser.expect_character(src, '.');
const cc_identifier = parser.parse_raw_identifier(src);
parser.skip_space(src);
parser.expect_character(src, ')');
inline for (@typeInfo(CallingConvention).Enum.fields) |cc_field| {
if (byte_equal(cc_field.name, cc_identifier)) {
const calling_convention = @field(CallingConvention, cc_field.name);
function.declaration.attributes.calling_convention = calling_convention;
break :b;
}
} else {
exit(1);
}
},
}
}
} else {
exit(1);
}
parser.skip_space(src);
const after_ch = src[parser.i];
switch (after_ch) {
']' => {},
else => unreachable,
}
}
parser.i += 1;
parser.skip_space(src);
}
function.declaration.global.name = parser.parse_identifier(thread, src);
parser.skip_space(src);
const has_symbol_attributes = src[parser.i] == '[';
parser.i += @intFromBool(has_symbol_attributes);
if (has_symbol_attributes) {
var attribute_mask = GlobalSymbol.Attribute.Mask.initEmpty();
while (true) {
parser.skip_space(src);
if (src[parser.i] == ']') break;
const attribute_identifier = parser.parse_raw_identifier(src);
inline for (@typeInfo(GlobalSymbol.Attribute).Enum.fields) |fa_field| {
if (byte_equal(fa_field.name, attribute_identifier)) {
const global_attribute = @field(GlobalSymbol.Attribute, fa_field.name);
if (attribute_mask.contains(global_attribute)) {
exit(1);
}
attribute_mask.setPresent(global_attribute, true);
switch (global_attribute) {
.@"export" => {},
.@"extern" => {},
}
const after_ch = src[parser.i];
switch (after_ch) {
']' => {},
else => unreachable,
}
break;
}
} else {
exit(1);
}
parser.skip_space(src);
const after_ch = src[parser.i];
switch (after_ch) {
']' => {},
else => unreachable,
}
}
parser.i += 1;
parser.skip_space(src);
}
const split_modules = true;
if (split_modules) {
function.declaration.global.attributes.@"export" = true;
}
parser.expect_character(src, '(');
while (true) {
parser.skip_space(src);
if (src[parser.i] == ')') break;
exit(1);
}
parser.expect_character(src, ')');
parser.skip_space(src);
function.declaration.return_type = parser.parse_type_expression(thread, src);
parser.skip_space(src);
const block_start = parser.i;
const block_line = parser.current_line + 1;
_ = block_line; // autofix
const block_column = block_start - parser.line_offset + 1;
_ = block_column; // autofix
//
parser.expect_character(src, bracket_open);
const file_scope = thread.file_scopes.get(@enumFromInt(file.scope.index));
file_scope.declarations.put_no_clobber(function.declaration.global.name, .{
.id = .function_definition,
.index = @intCast(function_index),
});
parser.skip_space(src);
while (true) {
parser.skip_space(src);
if (src[parser.i] == bracket_close) break;
if (src[parser.i] == 'r') {
const identifier = parser.parse_raw_identifier(src);
if (byte_equal(identifier, "return")) {
parser.skip_space(src);
if (function.declaration.return_type.sema.id != .unresolved) {
const return_value = parser.parse_typed_expression(&analyzer, thread, file, function.declaration.return_type);
parser.expect_character(src, ';');
const return_expression = thread.returns.append_index(.{
.value = return_value,
});
const return_instruction = thread.instructions.append(.{
.id = .ret,
.index = @intCast(return_expression),
});
_ = analyzer.current_basic_block.instructions.append(return_instruction);
analyzer.current_basic_block.is_terminated = true;
} else {
exit(1);
}
} else {
exit(1);
}
} else {
exit(1);
}
}
parser.expect_character(src, bracket_close);
} else {
exit(1);
}
},
'i' => {
const import_keyword = "import";
if (byte_equal(src[parser.i..][0..import_keyword.len], import_keyword)) {
parser.i += import_keyword.len;
parser.skip_space(src);
const string_literal = parser.parse_non_escaped_string_literal_content(src);
parser.skip_space(src);
parser.expect_character(src, ';');
const filename = std.fs.path.basename(string_literal);
const has_right_extension = filename.len > ".nat".len and byte_equal(filename[filename.len - ".nat".len ..], ".nat");
if (!has_right_extension) {
exit(1);
}
const filename_without_extension = filename[0 .. filename.len - ".nat".len];
const filename_without_extension_hash = hash_bytes(filename_without_extension);
const directory_path = file.get_directory_path();
const directory = std.fs.openDirAbsolute(directory_path, .{}) catch unreachable;
const file_path = library.realpath(thread.arena, directory, string_literal) catch unreachable;
const file_path_hash = intern_identifier(&thread.identifiers, file_path);
if (thread.local_files.get(file_path_hash)) |import_file_index| {
_ = import_file_index; // autofix
exit(1);
} else {
for (thread.pending_files.slice()) |pending_file| {
if (pending_file == file_path_hash) {
exit(1);
}
} else {
thread.add_control_work(.{
.id = .analyze_file,
.offset = file_path_hash,
});
const index = thread.pending_files.append_index(file_path_hash);
const file_scope = thread.file_scopes.get(@enumFromInt(file.scope.index));
file_scope.declarations.put_no_clobber(filename_without_extension_hash, .{
.id = .unresolved_import,
.index = @intCast(index),
});
const ptr = file_scope.declarations.get_pointer(filename_without_extension_hash) orelse unreachable;
const list = thread.pending_file_values.append(.{});
const lazy_expression = thread.lazy_expressions.append(LazyExpression.init(ptr));
const declaration = thread.values.append(.{
.sema = .{
.id = .lazy_expression,
.index = thread.lazy_expressions.get_index(lazy_expression),
.thread = thread.get_index(),
.resolved = false,
},
});
_ = list.append(declaration);
}
}
} else {
exit(1);
}
},
else => exit(1),
}
}
}
pub const LLVM = struct {
const bindings = @import("backend/llvm_bindings.zig");
pub const x86_64 = struct {
pub const initializeTarget = bindings.LLVMInitializeX86Target;
pub const initializeTargetInfo = bindings.LLVMInitializeX86TargetInfo;
pub const initializeTargetMC = bindings.LLVMInitializeX86TargetMC;
pub const initializeAsmPrinter = bindings.LLVMInitializeX86AsmPrinter;
pub const initializeAsmParser = bindings.LLVMInitializeX86AsmParser;
};
pub const aarch64 = struct {
pub const initializeTarget = bindings.LLVMInitializeAArch64Target;
pub const initializeTargetInfo = bindings.LLVMInitializeAArch64TargetInfo;
pub const initializeTargetMC = bindings.LLVMInitializeAArch64TargetMC;
pub const initializeAsmPrinter = bindings.LLVMInitializeAArch64AsmPrinter;
pub const initializeAsmParser = bindings.LLVMInitializeAArch64AsmParser;
};
pub const Attributes = struct {
noreturn: *Attribute,
naked: *Attribute,
nounwind: *Attribute,
inreg: *Attribute,
@"noalias": *Attribute,
};
pub const Linkage = enum(c_uint) {
@"extern" = 0,
available_external = 1,
link_once_any = 2,
link_once_odr = 3,
weak_any = 4,
weak_odr = 5,
appending = 6,
internal = 7,
private = 8,
external_weak = 9,
common = 10,
};
pub const ThreadLocalMode = enum(c_uint) {
not_thread_local = 0,
};
const getFunctionType = bindings.NativityLLVMGetFunctionType;
pub const Context = opaque {
const create = bindings.NativityLLVMCreateContext;
const createBasicBlock = bindings.NativityLLVMCreateBasicBlock;
const getConstantInt = bindings.NativityLLVMContextGetConstantInt;
const getConstString = bindings.NativityLLVMContextGetConstString;
const getVoidType = bindings.NativityLLVMGetVoidType;
const getIntegerType = bindings.NativityLLVMGetIntegerType;
const getPointerType = bindings.NativityLLVMGetPointerType;
const getStructType = bindings.NativityLLVMGetStructType;
const getIntrinsicType = bindings.NativityLLVMContextGetIntrinsicType;
const getAttributeFromEnum = bindings.NativityLLVMContextGetAttributeFromEnum;
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 {
const addGlobalVariable = bindings.NativityLLVMModuleAddGlobalVariable;
const create = bindings.NativityLLVMCreateModule;
const getFunction = bindings.NativityLLVMModuleGetFunction;
const createFunction = bindings.NativityLLVModuleCreateFunction;
const verify = bindings.NativityLLVMVerifyModule;
const toString = bindings.NativityLLVMModuleToString;
const getIntrinsicDeclaration = bindings.NativityLLVMModuleGetIntrinsicDeclaration;
const createDebugInfoBuilder = bindings.NativityLLVMModuleCreateDebugInfoBuilder;
const setTargetMachineDataLayout = bindings.NativityLLVMModuleSetTargetMachineDataLayout;
const setTargetTriple = bindings.NativityLLVMModuleSetTargetTriple;
const runOptimizationPipeline = bindings.NativityLLVMRunOptimizationPipeline;
const addPassesToEmitFile = bindings.NativityLLVMModuleAddPassesToEmitFile;
const link = bindings.NativityLLVMLinkModules;
};
pub const LinkFlags = packed struct(c_uint) {
override_from_source: bool,
link_only_needed: bool,
_: u30 = 0,
};
pub const Builder = opaque {
const create = bindings.NativityLLVMCreateBuilder;
const setInsertPoint = bindings.NativityLLVMBuilderSetInsertPoint;
const createAdd = bindings.NativityLLVMBuilderCreateAdd;
const createAlloca = bindings.NativityLLVMBuilderCreateAlloca;
const createAnd = bindings.NativityLLVMBuilderCreateAnd;
const createOr = bindings.NativityLLVMBuilderCreateOr;
const createCall = bindings.NativityLLVMBuilderCreateCall;
const createCast = bindings.NativityLLVMBuilderCreateCast;
const createBranch = bindings.NativityLLVMBuilderCreateBranch;
const createConditionalBranch = bindings.NativityLLVMBuilderCreateConditionalBranch;
const createSwitch = bindings.NativityLLVMBuilderCreateSwitch;
const createGEP = bindings.NativityLLVMBuilderCreateGEP;
const createStructGEP = bindings.NativityLLVMBuilderCreateStructGEP;
const createICmp = bindings.NativityLLVMBuilderCreateICmp;
const createLoad = bindings.NativityLLVMBuilderCreateLoad;
const createMultiply = bindings.NativityLLVMBuilderCreateMultiply;
const createRet = bindings.NativityLLVMBuilderCreateRet;
const createShiftLeft = bindings.NativityLLVMBuilderCreateShiftLeft;
const createArithmeticShiftRight = bindings.NativityLLVMBuilderCreateArithmeticShiftRight;
const createLogicalShiftRight = bindings.NativityLLVMBuilderCreateLogicalShiftRight;
const createStore = bindings.NativityLLVMBuilderCreateStore;
const createSub = bindings.NativityLLVMBuilderCreateSub;
const createUnreachable = bindings.NativityLLVMBuilderCreateUnreachable;
const createXor = bindings.NativityLLVMBuilderCreateXor;
const createUDiv = bindings.NativityLLVMBuilderCreateUDiv;
const createSDiv = bindings.NativityLLVMBuilderCreateSDiv;
const createURem = bindings.NativityLLVMBuilderCreateURem;
const createSRem = bindings.NativityLLVMBuilderCreateSRem;
const createExtractValue = bindings.NativityLLVMBuilderCreateExtractValue;
const createInsertValue = bindings.NativityLLVMBuilderCreateInsertValue;
const createGlobalString = bindings.NativityLLVMBuilderCreateGlobalString;
const createGlobalStringPointer = bindings.NativityLLVMBuilderCreateGlobalStringPointer;
const createPhi = bindings.NativityLLVMBuilderCreatePhi;
const createMemcpy = bindings.NativityLLVMBuilderCreateMemcpy;
const getInsertBlock = bindings.NativityLLVMBuilderGetInsertBlock;
const isCurrentBlockTerminated = bindings.NativityLLVMBuilderIsCurrentBlockTerminated;
const setCurrentDebugLocation = bindings.NativityLLVMBuilderSetCurrentDebugLocation;
};
pub const DebugInfo = struct {
pub const AttributeType = enum(c_uint) {
address = 0x01,
boolean = 0x02,
complex_float = 0x03,
float = 0x04,
signed = 0x05,
signed_char = 0x06,
unsigned = 0x07,
unsigned_char = 0x08,
imaginary_float = 0x09,
packed_decimal = 0x0a,
numeric_string = 0x0b,
edited = 0x0c,
signed_fixed = 0x0d,
unsigned_fixed = 0x0e,
decimal_float = 0x0f,
UTF = 0x10,
UCS = 0x11,
ASCII = 0x12,
};
pub const CallingConvention = enum(c_uint) {
none = 0,
normal = 0x01,
program = 0x02,
nocall = 0x03,
pass_by_reference = 0x04,
pass_by_value = 0x05,
// Vendor extensions
GNU_renesas_sh = 0x40,
GNU_borland_fastcall_i386 = 0x41,
BORLAND_safecall = 0xb0,
BORLAND_stdcall = 0xb1,
BORLAND_pascal = 0xb2,
BORLAND_msfastcall = 0xb3,
BORLAND_msreturn = 0xb4,
BORLAND_thiscall = 0xb5,
BORLAND_fastcall = 0xb6,
LLVM_vectorcall = 0xc0,
LLVM_Win64 = 0xc1,
LLVM_X86_64SysV = 0xc2,
LLVM_AAPCS = 0xc3,
LLVM_AAPCS_VFP = 0xc4,
LLVM_IntelOclBicc = 0xc5,
LLVM_SpirFunction = 0xc6,
LLVM_OpenCLKernel = 0xc7,
LLVM_Swift = 0xc8,
LLVM_PreserveMost = 0xc9,
LLVM_PreserveAll = 0xca,
LLVM_X86RegCall = 0xcb,
GDB_IBM_OpenCL = 0xff,
};
pub const Builder = opaque {
const createCompileUnit = bindings.NativityLLVMDebugInfoBuilderCreateCompileUnit;
const createFile = bindings.NativityLLVMDebugInfoBuilderCreateFile;
const createFunction = bindings.NativityLLVMDebugInfoBuilderCreateFunction;
const createSubroutineType = bindings.NativityLLVMDebugInfoBuilderCreateSubroutineType;
const createLexicalBlock = bindings.NativityLLVMDebugInfoBuilderCreateLexicalBlock;
const createParameterVariable = bindings.NativityLLVMDebugInfoBuilderCreateParameterVariable;
const createAutoVariable = bindings.NativityLLVMDebugInfoBuilderCreateAutoVariable;
const createGlobalVariableExpression = bindings.NativityLLVMDebugInfoBuilderCreateGlobalVariableExpression;
const createExpression = bindings.NativityLLVMDebugInfoBuilderCreateExpression;
const createBasicType = bindings.NativityLLVMDebugInfoBuilderCreateBasicType;
const createPointerType = bindings.NativityLLVMDebugInfoBuilderCreatePointerType;
const createStructType = bindings.NativityLLVMDebugInfoBuilderCreateStructType;
const createArrayType = bindings.NativityLLVMDebugInfoBuilderCreateArrayType;
const createEnumerationType = bindings.NativityLLVMDebugInfoBuilderCreateEnumerationType;
const createEnumerator = bindings.NativityLLVMDebugInfoBuilderCreateEnumerator;
const createReplaceableCompositeType = bindings.NativityLLVMDebugInfoBuilderCreateReplaceableCompositeType;
const createMemberType = bindings.NativityLLVMDebugInfoBuilderCreateMemberType;
const insertDeclare = bindings.NativityLLVMDebugInfoBuilderInsertDeclare;
const finalizeSubprogram = bindings.NativityLLVMDebugInfoBuilderFinalizeSubprogram;
const finalize = bindings.NativityLLVMDebugInfoBuilderFinalize;
const replaceCompositeTypes = bindings.NativityLLVMDebugInfoBuilderCompositeTypeReplaceTypes;
};
pub const CompileUnit = opaque {
fn toScope(this: *@This()) *LLVM.DebugInfo.Scope {
return @ptrCast(this);
}
pub const EmissionKind = enum(c_uint) {
no_debug = 0,
full_debug = 1,
line_tables_only = 2,
debug_directives_only = 3,
};
pub const NameTableKind = enum(c_uint) {
default = 0,
gnu = 1,
none = 2,
};
};
pub const Expression = opaque {};
pub const GlobalVariableExpression = opaque {};
pub const LocalVariable = opaque {};
pub const LexicalBlock = opaque {
fn toScope(this: *@This()) *LLVM.DebugInfo.Scope {
return @ptrCast(this);
}
};
pub const Node = opaque {
pub const Flags = packed struct(u32) {
visibility: Visibility,
forward_declaration: bool,
apple_block: bool,
block_by_ref_struct: bool,
virtual: bool,
artificial: bool,
explicit: bool,
prototyped: bool,
objective_c_class_complete: bool,
object_pointer: bool,
vector: bool,
static_member: bool,
lvalue_reference: bool,
rvalue_reference: bool,
reserved: bool = false,
inheritance: Inheritance,
introduced_virtual: bool,
bit_field: bool,
no_return: bool,
type_pass_by_value: bool,
type_pass_by_reference: bool,
enum_class: bool,
thunk: bool,
non_trivial: bool,
big_endian: bool,
little_endian: bool,
all_calls_described: bool,
_: u3 = 0,
const Visibility = enum(u2) {
none = 0,
private = 1,
protected = 2,
public = 3,
};
const Inheritance = enum(u2) {
none = 0,
single = 1,
multiple = 2,
virtual = 3,
};
};
};
pub const File = opaque {
fn toScope(this: *@This()) *LLVM.DebugInfo.Scope {
return @ptrCast(this);
}
};
pub const Language = enum(c_uint) {
c = 0x02,
};
pub const Scope = opaque {
const toSubprogram = bindings.NativityLLVMDebugInfoScopeToSubprogram;
};
pub const LocalScope = opaque {
fn toScope(this: *@This()) *LLVM.DebugInfo.Scope {
return @ptrCast(this);
}
};
pub const Subprogram = opaque {
const getFile = bindings.NativityLLVMDebugInfoSubprogramGetFile;
const getArgumentType = bindings.NativityLLVMDebugInfoSubprogramGetArgumentType;
fn toLocalScope(this: *@This()) *LocalScope {
return @ptrCast(this);
}
pub const Flags = packed struct(u32) {
virtuality: Virtuality,
local_to_unit: bool,
definition: bool,
optimized: bool,
pure: bool,
elemental: bool,
recursive: bool,
main_subprogram: bool,
deleted: bool,
reserved: bool = false,
object_c_direct: bool,
_: u20 = 0,
const Virtuality = enum(u2) {
none = 0,
virtual = 1,
pure_virtual = 2,
};
};
};
pub const Type = opaque {
const isResolved = bindings.NativityLLLVMDITypeIsResolved;
fn toScope(this: *@This()) *LLVM.DebugInfo.Scope {
return @ptrCast(this);
}
pub const Derived = opaque {
fn toType(this: *@This()) *LLVM.DebugInfo.Type {
return @ptrCast(this);
}
};
pub const Composite = opaque {
fn toType(this: *@This()) *LLVM.DebugInfo.Type {
return @ptrCast(this);
}
};
pub const Enumerator = opaque {};
pub const Subroutine = opaque {
fn toType(this: *@This()) *LLVM.DebugInfo.Type {
return @ptrCast(this);
}
};
};
};
pub const FloatAbi = enum(c_uint) {
default = 0,
soft = 1,
hard = 2,
};
pub const FloatOperationFusionMode = enum(c_uint) {
fast = 0,
standard = 1,
strict = 2,
};
pub const JumpTableType = enum(c_uint) {
single = 0,
arity = 1,
simplified = 2,
full = 3,
};
pub const ThreadModel = enum(c_uint) {
posix = 0,
single = 1,
};
pub const BasicBlockSection = enum(c_uint) {
all = 0,
list = 1,
labels = 2,
preset = 3,
none = 4,
};
pub const EAbi = enum(c_uint) {
unknown = 0,
default = 1,
eabi4 = 2,
eabi5 = 3,
gnu = 4,
};
pub const DebuggerKind = enum(c_uint) {
default = 0,
gdb = 1,
lldb = 2,
sce = 3,
dbx = 4,
};
pub const GlobalISelAbortMode = enum(c_uint) {
disable = 0,
enable = 1,
disable_with_diagnostic = 2,
};
pub const DebugCompressionType = enum(c_uint) {
none = 0,
zlib = 1,
zstd = 2,
};
pub const RelocationModel = enum(c_uint) {
static = 0,
pic = 1,
dynamic_no_pic = 2,
ropi = 3,
rwpi = 4,
ropi_rwpi = 5,
};
pub const CodeModel = enum(c_uint) {
tiny = 0,
small = 1,
kernel = 2,
medium = 3,
large = 4,
};
pub const PicLevel = enum(c_uint) {
not_pic = 0,
small_pic = 1,
big_pic = 2,
};
pub const PieLevel = enum(c_uint) {
default = 0,
small = 1,
large = 2,
};
pub const TlsModel = enum(c_uint) {
general_dynamic = 0,
local_dynamic = 1,
initial_exec = 2,
local_exec = 3,
};
pub const CodegenOptimizationLevel = enum(c_int) {
none = 0,
less = 1,
default = 2,
aggressive = 3,
};
pub const OptimizationLevel = extern struct {
speed_level: c_uint,
size_level: c_uint,
};
pub const FramePointerKind = enum(c_uint) {
none = 0,
non_leaf = 1,
all = 2,
};
pub const CodeGenFileType = enum(c_uint) {
assembly = 0,
object = 1,
null = 2,
};
pub const Target = opaque {
const createTargetMachine = bindings.NativityLLVMTargetCreateTargetMachine;
pub const Machine = opaque {};
// This is a non-LLVM struct
const Options = extern struct {
bin_utils_version: struct { i32, i32 },
fp_math: extern struct {
unsafe: bool,
no_infs: bool,
no_nans: bool,
no_traping: bool,
no_signed_zeroes: bool,
approx_func: bool,
enable_aix_extended_altivec_abi: bool,
honor_sign_dependent_rounding: bool,
},
no_zeroes_in_bss: bool,
guaranteed_tail_call_optimization: bool,
stack_symbol_ordering: bool,
enable_fast_isel: bool,
enable_global_isel: bool,
global_isel_abort_mode: GlobalISelAbortMode,
use_init_array: bool,
disable_integrated_assembler: bool,
debug_compression_type: DebugCompressionType,
relax_elf_relocations: bool,
function_sections: bool,
data_sections: bool,
ignore_xcoff_visibility: bool,
xcoff_traceback_table: bool,
unique_section_names: bool,
unique_basic_block_section_names: bool,
trap_unreachable: bool,
no_trap_after_noreturn: bool,
tls_size: u8,
emulated_tls: bool,
enable_ipra: bool,
emit_stack_size_section: bool,
enable_machine_outliner: bool,
enable_machine_function_splitter: bool,
support_default_outlining: bool,
emit_address_significance_table: bool,
bb_sections: BasicBlockSection,
emit_call_site_info: bool,
support_debug_entry_values: bool,
enable_debug_entry_values: bool,
value_tracking_variable_locations: bool,
force_dwarf_frame_section: bool,
xray_function_index: bool,
debug_strict_dwarf: bool,
hotpatch: bool,
ppc_gen_scalar_mass_entries: bool,
jmc_instrument: bool,
cfi_fixup: bool,
loop_alignment: u32 = 0,
float_abi_type: FloatAbi,
fp_operation_fusion: FloatOperationFusionMode,
thread_model: ThreadModel,
eabi_version: EAbi,
debugger_tuning: DebuggerKind,
};
};
const lookupIntrinsic = bindings.NativityLLVMLookupIntrinsic;
const newPhiNode = bindings.NativityLLVMCreatePhiNode;
pub const Metadata = opaque {
pub const Node = opaque {};
pub const Tuple = opaque {};
};
pub const Attribute = opaque {
pub const Set = opaque {};
pub const Id = enum(u32) {
AllocAlign = 1,
AllocatedPointer = 2,
AlwaysInline = 3,
Builtin = 4,
Cold = 5,
Convergent = 6,
DisableSanitizerInstrumentation = 7,
FnRetThunkExtern = 8,
Hot = 9,
ImmArg = 10,
InReg = 11,
InlineHint = 12,
JumpTable = 13,
MinSize = 14,
MustProgress = 15,
Naked = 16,
Nest = 17,
NoAlias = 18,
NoBuiltin = 19,
NoCallback = 20,
NoCapture = 21,
NoCfCheck = 22,
NoDuplicate = 23,
NoFree = 24,
NoImplicitFloat = 25,
NoInline = 26,
NoMerge = 27,
NoProfile = 28,
NoRecurse = 29,
NoRedZone = 30,
NoReturn = 31,
NoSanitizeBounds = 32,
NoSanitizeCoverage = 33,
NoSync = 34,
NoUndef = 35,
NoUnwind = 36,
NonLazyBind = 37,
NonNull = 38,
NullPointerIsValid = 39,
OptForFuzzing = 40,
OptimizeForSize = 41,
OptimizeNone = 42,
PresplitCoroutine = 43,
ReadNone = 44,
ReadOnly = 45,
Returned = 46,
ReturnsTwice = 47,
SExt = 48,
SafeStack = 49,
SanitizeAddress = 50,
SanitizeHWAddress = 51,
SanitizeMemTag = 52,
SanitizeMemory = 53,
SanitizeThread = 54,
ShadowCallStack = 55,
SkipProfile = 56,
Speculatable = 57,
SpeculativeLoadHardening = 58,
StackProtect = 59,
StackProtectReq = 60,
StackProtectStrong = 61,
StrictFP = 62,
SwiftAsync = 63,
SwiftError = 64,
SwiftSelf = 65,
WillReturn = 66,
WriteOnly = 67,
ZExt = 68,
ByRef = 69,
ByVal = 70,
ElementType = 71,
InAlloca = 72,
Preallocated = 73,
StructRet = 74,
Alignment = 75,
AllocKind = 76,
AllocSize = 77,
Dereferenceable = 78,
DereferenceableOrNull = 79,
Memory = 80,
StackAlignment = 81,
UWTable = 82,
VScaleRange = 83,
};
};
pub const Type = opaque {
const compare = bindings.NativityLLVMCompareTypes;
const toStruct = bindings.NativityLLVMTypeToStruct;
const toFunction = bindings.NativityLLVMTypeToFunction;
const toArray = bindings.NativityLLVMTypeToArray;
const toPointer = bindings.NativityLLVMTypeToPointer;
const isPointer = bindings.NativityLLVMTypeIsPointer;
const isInteger = bindings.NativityLLVMTypeIsInteger;
const isVoid = bindings.NativityLLVMTypeIsVoid;
const assertEqual = bindings.NativityLLVMTypeAssertEqual;
const getPoison = bindings.NativityLLVMGetPoisonValue;
const getContext = bindings.NativityLLVMTypeGetContext;
pub const Array = opaque {
fn toType(integer: *@This()) *LLVM.Type {
return @ptrCast(integer);
}
const get = bindings.NativityLLVMGetArrayType;
const getConstant = bindings.NativityLLVMGetConstantArray;
const getElementType = bindings.NativityLLVMArrayTypeGetElementType;
};
pub const Integer = opaque {
fn toType(integer: *@This()) *LLVM.Type {
return @ptrCast(integer);
}
};
pub const Function = opaque {
fn toType(integer: *@This()) *LLVM.Type {
return @ptrCast(integer);
}
const getArgumentType = bindings.NativityLLVMFunctionTypeGetArgumentType;
const getReturnType = bindings.NativityLLVMFunctionTypeGetReturnType;
};
pub const Pointer = opaque {
fn toType(integer: *@This()) *LLVM.Type {
return @ptrCast(integer);
}
const getNull = bindings.NativityLLVMPointerTypeGetNull;
};
pub const Struct = opaque {
const getConstant = bindings.NativityLLVMGetConstantStruct;
fn toType(integer: *@This()) *LLVM.Type {
return @ptrCast(integer);
}
};
pub const Error = error{
void,
function,
integer,
pointer,
@"struct",
intrinsic,
array,
};
};
pub const MemoryBuffer = opaque {};
pub const Value = opaque {
const setName = bindings.NativityLLVMValueSetName;
const getType = bindings.NativityLLVMValueGetType;
const toConstant = bindings.NativityLLVMValueToConstant;
const toFunction = bindings.NativityLLVMValueToFunction;
const toAlloca = bindings.NativityLLVMValueToAlloca;
const toString = bindings.NativityLLVMValueToString;
pub const IntrinsicID = enum(u32) {
none = 0,
_,
};
pub const BasicBlock = opaque {
const remove = bindings.NativityLLVMBasicBlockRemoveFromParent;
fn toValue(this: *@This()) *LLVM.Value {
return @ptrCast(this);
}
};
pub const Argument = opaque {
const getIndex = bindings.NativityLLVMArgumentGetIndex;
fn toValue(this: *@This()) *LLVM.Value {
return @ptrCast(this);
}
};
pub const Instruction = opaque {
fn toValue(this: *@This()) *LLVM.Value {
return @ptrCast(this);
}
pub const Alloca = opaque {
fn toValue(this: *@This()) *LLVM.Value {
return @ptrCast(this);
}
const getAllocatedType = bindings.NativityLLVMAllocatGetAllocatedType;
};
pub const Branch = opaque {
fn toValue(this: *@This()) *LLVM.Value {
return @ptrCast(this);
}
};
pub const Call = opaque {
const setCallingConvention = bindings.NativityLLVMCallSetCallingConvention;
const setAttributes = bindings.NativityLLVMCallSetAttributes;
fn toValue(this: *@This()) *LLVM.Value {
return @ptrCast(this);
}
};
pub const Cast = opaque {
pub const Type = enum(c_uint) {
truncate = 38,
zero_extend = 39,
sign_extend = 40,
float_to_unsigned_integer = 41,
float_to_signed_integer = 42,
unsigned_integer_to_float = 43,
signed_integer_to_float = 44,
float_truncate = 45,
float_extend = 46,
pointer_to_int = 47,
int_to_pointer = 48,
bitcast = 49,
address_space_cast = 50,
};
fn toValue(this: *@This()) *LLVM.Value {
return @ptrCast(this);
}
};
pub const ICmp = opaque {
fn toValue(this: *@This()) *LLVM.Value {
return @ptrCast(this);
}
pub const Kind = enum(c_uint) {
eq = 32, // equal
ne = 33, // not equal
ugt = 34, // unsigned greater than
uge = 35, // unsigned greater or equal
ult = 36, // unsigned less than
ule = 37, // unsigned less or equal
sgt = 38, // signed greater than
sge = 39, // signed greater or equal
slt = 40, // signed less than
sle = 41, // signed less or equal
};
};
pub const Load = opaque {
fn toValue(this: *@This()) *LLVM.Value {
return @ptrCast(this);
}
};
pub const PhiNode = opaque {
pub const addIncoming = bindings.NativityLLVMPhiAddIncoming;
fn toValue(this: *@This()) *LLVM.Value {
return @ptrCast(this);
}
};
pub const Store = opaque {
fn toValue(this: *@This()) *LLVM.Value {
return @ptrCast(this);
}
};
pub const Switch = opaque {
fn toValue(this: *@This()) *LLVM.Value {
return @ptrCast(this);
}
};
pub const Ret = opaque {
fn toValue(this: *@This()) *LLVM.Value {
return @ptrCast(this);
}
};
pub const Unreachable = opaque {
fn toValue(this: *@This()) *LLVM.Value {
return @ptrCast(this);
}
};
pub const Error = error{
add,
alloca,
@"and",
arithmetic_shift_right,
call,
cast,
conditional_branch,
extract_value,
gep,
icmp,
insert_value,
load,
logical_shift_right,
multiply,
@"or",
ret,
sdiv,
shift_left,
store,
udiv,
@"unreachable",
xor,
};
};
pub const Constant = opaque {
pub const Function = opaque {
const getArgument = bindings.NativityLLVMFunctionGetArgument;
const getArguments = bindings.NativityLLVMFunctionGetArguments;
const getType = bindings.NativityLLVMFunctionGetType;
// const addAttributeKey = bindings.NativityLLVMFunctionAddAttributeKey;
const verify = bindings.NativityLLVMVerifyFunction;
const toString = bindings.NativityLLVMFunctionToString;
const setCallingConvention = bindings.NativityLLVMFunctionSetCallingConvention;
const getCallingConvention = bindings.NativityLLVMFunctionGetCallingConvention;
const setSubprogram = bindings.NativityLLVMFunctionSetSubprogram;
const getSubprogram = bindings.NativityLLVMFunctionGetSubprogram;
const setAttributes = bindings.NativityLLVMFunctionSetAttributes;
fn toValue(this: *@This()) *LLVM.Value {
return @ptrCast(this);
}
fn toConstant(this: *@This()) *Constant {
return @ptrCast(this);
}
pub const CallingConvention = enum(c_uint) {
/// The default llvm calling convention, compatible with C. This convention
/// is the only one that supports varargs calls. As with typical C calling
/// conventions, the callee/caller have to tolerate certain amounts of
/// prototype mismatch.
C = 0,
// Generic LLVM calling conventions. None of these support varargs calls,
// and all assume that the caller and callee prototype exactly match.
/// Attempts to make calls as fast as possible (e.g. by passing things in
/// registers).
Fast = 8,
/// Attempts to make code in the caller as efficient as possible under the
/// assumption that the call is not commonly executed. As such, these calls
/// often preserve all registers so that the call does not break any live
/// ranges in the caller side.
Cold = 9,
/// Used by the Glasgow Haskell Compiler (GHC).
GHC = 10,
/// Used by the High-Performance Erlang Compiler (HiPE).
HiPE = 11,
/// Used for stack based JavaScript calls
WebKit_JS = 12,
/// Used for dynamic register based calls (e.g. stackmap and patchpoint
/// intrinsics).
AnyReg = 13,
/// Used for runtime calls that preserves most registers.
PreserveMost = 14,
/// Used for runtime calls that preserves (almost) all registers.
PreserveAll = 15,
/// Calling convention for Swift.
Swift = 16,
/// Used for access functions.
CXX_FAST_TLS = 17,
/// Attemps to make calls as fast as possible while guaranteeing that tail
/// call optimization can always be performed.
Tail = 18,
/// Special calling convention on Windows for calling the Control Guard
/// Check ICall funtion. The function takes exactly one argument (address of
/// the target function) passed in the first argument register, and has no
/// return value. All register values are preserved.
CFGuard_Check = 19,
/// This follows the Swift calling convention in how arguments are passed
/// but guarantees tail calls will be made by making the callee clean up
/// their stack.
SwiftTail = 20,
/// This is the start of the target-specific calling conventions, e.g.
/// fastcall and thiscall on X86.
// FirstTargetCC = 64,
/// stdcall is mostly used by the Win32 API. It is basically the same as the
/// C convention with the difference in that the callee is responsible for
/// popping the arguments from the stack.
X86_StdCall = 64,
/// 'fast' analog of X86_StdCall. Passes first two arguments in ECX:EDX
/// registers, others - via stack. Callee is responsible for stack cleaning.
X86_FastCall = 65,
/// ARM Procedure Calling Standard (obsolete, but still used on some
/// targets).
ARM_APCS = 66,
/// ARM Architecture Procedure Calling Standard calling convention (aka
/// EABI). Soft float variant.
ARM_AAPCS = 67,
/// Same as ARM_AAPCS, but uses hard floating point ABI.
ARM_AAPCS_VFP = 68,
/// Used for MSP430 interrupt routines.
MSP430_INTR = 69,
/// Similar to X86_StdCall. Passes first argument in ECX, others via stack.
/// Callee is responsible for stack cleaning. MSVC uses this by default for
/// methods in its ABI.
X86_ThisCall = 70,
/// Call to a PTX kernel. Passes all arguments in parameter space.
PTX_Kernel = 71,
/// Call to a PTX device function. Passes all arguments in register or
/// parameter space.
PTX_Device = 72,
/// Used for SPIR non-kernel device functions. No lowering or expansion of
/// arguments. Structures are passed as a pointer to a struct with the
/// byval attribute. Functions can only call SPIR_FUNC and SPIR_KERNEL
/// functions. Functions can only have zero or one return values. Variable
/// arguments are not allowed, except for printf. How arguments/return
/// values are lowered are not specified. Functions are only visible to the
/// devices.
SPIR_FUNC = 75,
/// Used for SPIR kernel functions. Inherits the restrictions of SPIR_FUNC,
/// except it cannot have non-void return values, it cannot have variable
/// arguments, it can also be called by the host or it is externally
/// visible.
SPIR_KERNEL = 76,
/// Used for Intel OpenCL built-ins.
Intel_OCL_BI = 77,
/// The C convention as specified in the x86-64 supplement to the System V
/// ABI, used on most non-Windows systems.
X86_64_SysV = 78,
/// The C convention as implemented on Windows/x86-64 and AArch64. It
/// differs from the more common \c X86_64_SysV convention in a number of
/// ways, most notably in that XMM registers used to pass arguments are
/// shadowed by GPRs, and vice versa. On AArch64, this is identical to the
/// normal C (AAPCS) calling convention for normal functions, but floats are
/// passed in integer registers to variadic functions.
Win64 = 79,
/// MSVC calling convention that passes vectors and vector aggregates in SSE
/// registers.
X86_VectorCall = 80,
/// Used by HipHop Virtual Machine (HHVM) to perform calls to and from
/// translation cache, and for calling PHP functions. HHVM calling
/// convention supports tail/sibling call elimination.
HHVM = 81,
/// HHVM calling convention for invoking C/C++ helpers.
HHVM_C = 82,
/// x86 hardware interrupt context. Callee may take one or two parameters,
/// where the 1st represents a pointer to hardware context frame and the 2nd
/// represents hardware error code, the presence of the later depends on the
/// interrupt vector taken. Valid for both 32- and 64-bit subtargets.
X86_INTR = 83,
/// Used for AVR interrupt routines.
AVR_INTR = 84,
/// Used for AVR signal routines.
AVR_SIGNAL = 85,
/// Used for special AVR rtlib functions which have an "optimized"
/// convention to preserve registers.
AVR_BUILTIN = 86,
/// Used for Mesa vertex shaders, or AMDPAL last shader stage before
/// rasterization (vertex shader if tessellation and geometry are not in
/// use, or otherwise copy shader if one is needed).
AMDGPU_VS = 87,
/// Used for Mesa/AMDPAL geometry shaders.
AMDGPU_GS = 88,
/// Used for Mesa/AMDPAL pixel shaders.
AMDGPU_PS = 89,
/// Used for Mesa/AMDPAL compute shaders.
AMDGPU_CS = 90,
/// Used for AMDGPU code object kernels.
AMDGPU_KERNEL = 91,
/// Register calling convention used for parameters transfer optimization
X86_RegCall = 92,
/// Used for Mesa/AMDPAL hull shaders (= tessellation control shaders).
AMDGPU_HS = 93,
/// Used for special MSP430 rtlib functions which have an "optimized"
/// convention using additional registers.
MSP430_BUILTIN = 94,
/// Used for AMDPAL vertex shader if tessellation is in use.
AMDGPU_LS = 95,
/// Used for AMDPAL shader stage before geometry shader if geometry is in
/// use. So either the domain (= tessellation evaluation) shader if
/// tessellation is in use, or otherwise the vertex shader.
AMDGPU_ES = 96,
/// Used between AArch64 Advanced SIMD functions
AArch64_VectorCall = 97,
/// Used between AArch64 SVE functions
AArch64_SVE_VectorCall = 98,
/// For emscripten __invoke_* functions. The first argument is required to
/// be the function ptr being indirectly called. The remainder matches the
/// regular calling convention.
WASM_EmscriptenInvoke = 99,
/// Used for AMD graphics targets.
AMDGPU_Gfx = 100,
/// Used for M68k interrupt routines.
M68k_INTR = 101,
/// Preserve X0-X13, X19-X29, SP, Z0-Z31, P0-P15.
AArch64_SME_ABI_Support_Routines_PreserveMost_From_X0 = 102,
/// Preserve X2-X15, X19-X29, SP, Z0-Z31, P0-P15.
AArch64_SME_ABI_Support_Routines_PreserveMost_From_X2 = 103,
/// The highest possible ID. Must be some 2^k - 1.
MaxID = 1023,
};
};
pub const Int = opaque {
fn toValue(this: *@This()) *LLVM.Value {
return @ptrCast(this);
}
fn toConstant(this: *@This()) *Constant {
return @ptrCast(this);
}
};
pub const GlobalVariable = opaque {
pub const setInitializer = bindings.NativityLLVMGlobalVariableSetInitializer;
fn toValue(this: *@This()) *LLVM.Value {
return @ptrCast(this);
}
fn toConstant(this: *@This()) *Constant {
return @ptrCast(this);
}
};
pub const PointerNull = opaque {
fn toValue(this: *@This()) *LLVM.Value {
return @ptrCast(this);
}
fn toConstant(this: *@This()) *Constant {
return @ptrCast(this);
}
};
pub const Undefined = opaque {
fn toConstant(this: *@This()) *Constant {
return @ptrCast(this);
}
fn toValue(this: *@This()) *LLVM.Value {
return @ptrCast(this);
}
};
pub const Poison = opaque {
fn toConstant(this: *@This()) *Constant {
return @ptrCast(this);
}
fn toValue(this: *@This()) *LLVM.Value {
return @ptrCast(this);
}
};
fn toValue(this: *@This()) *LLVM.Value {
return @ptrCast(this);
}
const toInt = bindings.NativityLLVMConstantToInt;
};
pub const InlineAssembly = opaque {
pub const Dialect = enum(c_uint) {
@"at&t",
intel,
};
const get = bindings.NativityLLVMGetInlineAssembly;
fn toValue(this: *@This()) *LLVM.Value {
return @ptrCast(this);
}
};
pub const Error = error{
constant_struct,
constant_int,
constant_array,
inline_assembly,
global_variable,
intrinsic,
};
};
};