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; } const debug_main_bitcode align(@sizeOf(u32)) = [_]u8 { 0x42, 0x43, 0xc0, 0xde, 0x35, 0x14, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x62, 0x0c, 0x30, 0x24, 0x4a, 0x59, 0xbe, 0x66, 0xcd, 0xfb, 0xb5, 0xaf, 0x0b, 0x51, 0x80, 0x4c, 0x01, 0x00, 0x00, 0x00, 0x21, 0x0c, 0x00, 0x00, 0x77, 0x02, 0x00, 0x00, 0x0b, 0x02, 0x21, 0x00, 0x02, 0x00, 0x00, 0x00, 0x17, 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, 0x0c, 0x45, 0x02, 0x42, 0x92, 0x0b, 0x42, 0x64, 0x10, 0x32, 0x14, 0x38, 0x08, 0x18, 0x4b, 0x0a, 0x32, 0x32, 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, 0x32, 0x84, 0x58, 0x0e, 0x90, 0x91, 0x21, 0x44, 0x90, 0xa1, 0x82, 0xa2, 0x02, 0x19, 0xc3, 0x07, 0xcb, 0x15, 0x09, 0x32, 0x8c, 0x0c, 0x89, 0x20, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x22, 0x66, 0x04, 0x10, 0xb2, 0x42, 0x82, 0xc9, 0x10, 0x52, 0x42, 0x82, 0xc9, 0x90, 0x71, 0xc2, 0x50, 0x48, 0x0a, 0x09, 0x26, 0x43, 0xc6, 0x05, 0x42, 0x32, 0x26, 0x08, 0x0c, 0x9a, 0x23, 0x00, 0x83, 0x32, 0x24, 0x18, 0x01, 0x18, 0x08, 0x28, 0xc4, 0x48, 0x02, 0x00, 0x51, 0x18, 0x00, 0x00, 0x51, 0x00, 0x00, 0x00, 0x1b, 0x54, 0x23, 0xf8, 0xff, 0xff, 0xff, 0xff, 0x01, 0x70, 0x00, 0x09, 0x28, 0x83, 0x20, 0x0c, 0x04, 0xc2, 0x1c, 0xe4, 0x21, 0x1c, 0xda, 0xa1, 0x1c, 0xda, 0x00, 0x1e, 0xde, 0x21, 0x1d, 0xdc, 0x81, 0x1e, 0xca, 0x41, 0x1e, 0x80, 0x70, 0x60, 0x07, 0x76, 0x00, 0x88, 0x76, 0x48, 0x07, 0x77, 0x68, 0x03, 0x76, 0x28, 0x87, 0x73, 0x08, 0x07, 0x76, 0x68, 0x03, 0x7b, 0x28, 0x87, 0x71, 0xa0, 0x87, 0x77, 0x90, 0x87, 0x36, 0xb8, 0x87, 0x74, 0x20, 0x07, 0x7a, 0x40, 0x07, 0x00, 0x0e, 0x00, 0xc2, 0x1d, 0xde, 0xa1, 0x0d, 0xe8, 0x41, 0x1e, 0xc2, 0x01, 0x1e, 0xe0, 0x21, 0x1d, 0xdc, 0xe1, 0x1c, 0xda, 0xa0, 0x1d, 0xc2, 0x81, 0x1e, 0xd0, 0x01, 0xa0, 0x07, 0x79, 0xa8, 0x87, 0x72, 0x00, 0x88, 0x79, 0xa0, 0x87, 0x70, 0x18, 0x87, 0x75, 0x68, 0x03, 0x78, 0x90, 0x87, 0x77, 0xa0, 0x87, 0x72, 0x18, 0x07, 0x7a, 0x78, 0x07, 0x79, 0x68, 0x03, 0x71, 0xa8, 0x07, 0x73, 0x30, 0x87, 0x72, 0x90, 0x87, 0x36, 0x98, 0x87, 0x74, 0xd0, 0x87, 0x72, 0x00, 0xf0, 0x00, 0x20, 0xe8, 0x21, 0x1c, 0xe4, 0xe1, 0x1c, 0xca, 0x81, 0x1e, 0xda, 0x60, 0x1c, 0xe0, 0xa1, 0x1e, 0x00, 0x7c, 0xc0, 0x03, 0x3b, 0x68, 0x03, 0x3b, 0xa0, 0x03, 0x80, 0xa0, 0x87, 0x70, 0x90, 0x87, 0x73, 0x28, 0x07, 0x7a, 0x68, 0x03, 0x73, 0x28, 0x87, 0x70, 0xa0, 0x87, 0x7a, 0x90, 0x87, 0x72, 0x98, 0x07, 0x60, 0x0d, 0xc6, 0xa1, 0x1d, 0xde, 0xc1, 0x1e, 0xd8, 0x60, 0x0d, 0xc6, 0x01, 0x1f, 0xf0, 0x80, 0x0d, 0xd6, 0xc0, 0x1c, 0xf0, 0x61, 0x1e, 0xe4, 0x81, 0x0d, 0xd6, 0xa0, 0x1d, 0xda, 0x01, 0x1f, 0xd8, 0x60, 0x0d, 0xe6, 0x61, 0x1e, 0xca, 0x81, 0x0d, 0xd6, 0x60, 0x1e, 0xe6, 0xa1, 0x1c, 0xe4, 0x80, 0x0d, 0xd6, 0x00, 0x1f, 0xf0, 0xe0, 0x0e, 0x00, 0x82, 0x1e, 0xea, 0xc1, 0x1d, 0xca, 0xa1, 0x0d, 0xc6, 0x01, 0x1e, 0xea, 0x01, 0x38, 0x87, 0x72, 0x70, 0x87, 0x72, 0x90, 0x87, 0x74, 0x18, 0x07, 0x60, 0x03, 0x21, 0x04, 0x00, 0x29, 0x6c, 0x20, 0x06, 0x01, 0x20, 0x85, 0x0d, 0x11, 0xf1, 0xff, 0xff, 0xff, 0xff, 0x03, 0x70, 0x0a, 0x80, 0x1f, 0x00, 0x7f, 0x00, 0x48, 0x40, 0x1d, 0x00, 0x7d, 0x10, 0xd8, 0x02, 0x00, 0x00, 0x49, 0x18, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x13, 0x86, 0x40, 0x18, 0x26, 0x04, 0x04, 0x00, 0x13, 0x30, 0x7c, 0xc0, 0x03, 0x3b, 0xf8, 0x05, 0x3b, 0xa0, 0x83, 0x36, 0xa8, 0x07, 0x77, 0x58, 0x07, 0x77, 0x78, 0x87, 0x7b, 0x70, 0x87, 0x36, 0x60, 0x87, 0x74, 0x70, 0x87, 0x7a, 0xc0, 0x87, 0x36, 0x38, 0x07, 0x77, 0xa8, 0x87, 0x0d, 0xaf, 0x50, 0x0e, 0x6d, 0xd0, 0x0e, 0x7a, 0x50, 0x0e, 0x6d, 0x00, 0x0f, 0x72, 0x70, 0x07, 0x70, 0xa0, 0x07, 0x73, 0x20, 0x07, 0x7a, 0x30, 0x07, 0x72, 0xd0, 0x06, 0xf0, 0x20, 0x07, 0x77, 0x10, 0x07, 0x7a, 0x30, 0x07, 0x72, 0xa0, 0x07, 0x73, 0x20, 0x07, 0x6d, 0x00, 0x0f, 0x72, 0x70, 0x07, 0x72, 0xa0, 0x07, 0x76, 0x40, 0x07, 0x7a, 0x60, 0x07, 0x74, 0xd0, 0x06, 0xe9, 0x60, 0x07, 0x74, 0xa0, 0x07, 0x76, 0x40, 0x07, 0x6d, 0x90, 0x0e, 0x71, 0x20, 0x07, 0x78, 0xa0, 0x07, 0x71, 0x20, 0x07, 0x78, 0xd0, 0x06, 0xe6, 0x80, 0x07, 0x70, 0xa0, 0x07, 0x71, 0x20, 0x07, 0x78, 0xd0, 0x06, 0xee, 0x80, 0x07, 0x7a, 0x10, 0x07, 0x76, 0xa0, 0x07, 0x73, 0x20, 0x07, 0x7a, 0x60, 0x07, 0x74, 0xd0, 0x06, 0xb3, 0x10, 0x07, 0x72, 0x80, 0x07, 0x1a, 0x21, 0x0c, 0x69, 0x30, 0x00, 0xd2, 0xf8, 0xc2, 0x90, 0x0a, 0x20, 0x04, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x02, 0x18, 0x52, 0x11, 0x50, 0x01, 0x04, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x12, 0x1b, 0x04, 0x8a, 0xee, 0x09, 0x00, 0x00, 0x64, 0x81, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x32, 0x1e, 0x98, 0x10, 0x19, 0x11, 0x4c, 0x90, 0x8c, 0x09, 0x26, 0x47, 0xc6, 0x04, 0x43, 0x4a, 0x39, 0x94, 0x42, 0x11, 0x94, 0x41, 0x09, 0x14, 0x42, 0x41, 0x00, 0x00, 0xb1, 0x18, 0x00, 0x00, 0xc1, 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, 0x66, 0x4c, 0x67, 0x30, 0x0e, 0xef, 0x20, 0x0f, 0xef, 0xe0, 0x06, 0xef, 0x50, 0x0f, 0xf4, 0x30, 0x0f, 0xe9, 0x40, 0x0e, 0xe5, 0xe0, 0x06, 0xe6, 0x20, 0x0f, 0xe1, 0xd0, 0x0e, 0xe5, 0x00, 0x00, 0x00, 0x79, 0x20, 0x00, 0x00, 0x6a, 0x00, 0x00, 0x00, 0x72, 0x1e, 0x48, 0x20, 0x43, 0x88, 0x0c, 0x19, 0x09, 0x72, 0x32, 0x48, 0x20, 0x23, 0x81, 0x8c, 0x91, 0x91, 0xd1, 0x44, 0xa0, 0x10, 0x28, 0x64, 0x3c, 0x31, 0x32, 0x42, 0x8e, 0x90, 0x21, 0xa3, 0xb8, 0x30, 0xf4, 0x01, 0xc6, 0x02, 0x06, 0xe8, 0xd0, 0x48, 0x4a, 0x92, 0x1c, 0x0d, 0x00, 0x00, 0x6d, 0x61, 0x69, 0x6e, 0x2e, 0x63, 0x2f, 0x68, 0x6f, 0x6d, 0x65, 0x2f, 0x64, 0x61, 0x76, 0x69, 0x64, 0x64, 0x35, 0x36, 0x65, 0x30, 0x63, 0x30, 0x39, 0x62, 0x30, 0x32, 0x32, 0x33, 0x37, 0x61, 0x61, 0x37, 0x38, 0x63, 0x61, 0x62, 0x39, 0x39, 0x64, 0x35, 0x36, 0x65, 0x65, 0x65, 0x36, 0x63, 0x63, 0x63, 0x6c, 0x61, 0x6e, 0x67, 0x20, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x20, 0x31, 0x38, 0x2e, 0x31, 0x2e, 0x36, 0x20, 0x28, 0x68, 0x74, 0x74, 0x70, 0x73, 0x3a, 0x2f, 0x2f, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x6c, 0x6c, 0x76, 0x6d, 0x2f, 0x6c, 0x6c, 0x76, 0x6d, 0x2d, 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x2e, 0x67, 0x69, 0x74, 0x20, 0x62, 0x63, 0x65, 0x39, 0x33, 0x39, 0x33, 0x32, 0x39, 0x31, 0x61, 0x32, 0x64, 0x61, 0x61, 0x38, 0x30, 0x30, 0x36, 0x64, 0x31, 0x64, 0x61, 0x36, 0x32, 0x39, 0x61, 0x61, 0x32, 0x37, 0x36, 0x35, 0x65, 0x30, 0x30, 0x66, 0x34, 0x65, 0x37, 0x30, 0x29, 0x44, 0x77, 0x61, 0x72, 0x66, 0x20, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x44, 0x65, 0x62, 0x75, 0x67, 0x20, 0x49, 0x6e, 0x66, 0x6f, 0x20, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x77, 0x63, 0x68, 0x61, 0x72, 0x5f, 0x73, 0x69, 0x7a, 0x65, 0x50, 0x49, 0x43, 0x20, 0x4c, 0x65, 0x76, 0x65, 0x6c, 0x50, 0x49, 0x45, 0x20, 0x4c, 0x65, 0x76, 0x65, 0x6c, 0x75, 0x77, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x66, 0x72, 0x61, 0x6d, 0x65, 0x2d, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x23, 0x08, 0x81, 0x30, 0x82, 0x10, 0x0c, 0x23, 0x08, 0x01, 0x31, 0x82, 0x10, 0x14, 0x23, 0x08, 0x81, 0x31, 0x82, 0x10, 0x1c, 0x23, 0x08, 0x01, 0x32, 0x94, 0x15, 0x74, 0x14, 0x01, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x03, 0x15, 0x40, 0x20, 0x04, 0xc3, 0x0c, 0x03, 0x53, 0x34, 0x33, 0x0c, 0x8e, 0xf1, 0xcc, 0x30, 0x40, 0x47, 0x34, 0xc3, 0x20, 0x21, 0xce, 0x0c, 0x03, 0x93, 0x38, 0x33, 0x0c, 0x8c, 0xe2, 0xcc, 0x30, 0x30, 0x8b, 0x33, 0x43, 0x40, 0xc8, 0x48, 0x60, 0x82, 0x72, 0x61, 0x63, 0xb3, 0x6b, 0x73, 0x21, 0x13, 0x3b, 0x73, 0x19, 0xab, 0x1b, 0x25, 0x90, 0x32, 0x62, 0x63, 0xb3, 0x6b, 0x73, 0x69, 0x7b, 0x23, 0xab, 0x63, 0x2b, 0x73, 0x31, 0x63, 0x0b, 0x3b, 0x9b, 0x1b, 0xe5, 0xa0, 0x2a, 0xeb, 0xc2, 0x32, 0x2d, 0x15, 0x36, 0x36, 0xbb, 0x36, 0x97, 0x34, 0xb2, 0x32, 0x37, 0xba, 0x51, 0x82, 0x0d, 0x00, 0x00, 0x00, 0x00, 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, 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, 0x61, 0x20, 0x00, 0x00, 0x4d, 0x00, 0x00, 0x00, 0x13, 0x04, 0x41, 0x2c, 0x10, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x94, 0x11, 0x00, 0x00, 0xf1, 0x30, 0x00, 0x00, 0x24, 0x00, 0x00, 0x00, 0x22, 0x47, 0xc8, 0x90, 0x51, 0x16, 0xc4, 0x05, 0xc4, 0x40, 0x10, 0x04, 0x6d, 0x61, 0x69, 0x6e, 0x69, 0x6e, 0x74, 0x63, 0x68, 0x61, 0x72, 0x61, 0x72, 0x67, 0x63, 0x61, 0x72, 0x67, 0x76, 0x00, 0xab, 0xa8, 0x83, 0xea, 0x00, 0x2a, 0x40, 0x03, 0x01, 0x40, 0x00, 0x10, 0x99, 0x00, 0x20, 0x0d, 0x00, 0x00, 0x00, 0xf6, 0x1c, 0x00, 0x19, 0x78, 0x60, 0x00, 0x14, 0xc0, 0x9e, 0x03, 0x20, 0x83, 0x0f, 0x01, 0x0c, 0x60, 0x91, 0x03, 0x3c, 0x00, 0x00, 0x00, 0x64, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x00, 0xb0, 0xc8, 0x01, 0x1e, 0x00, 0x00, 0x80, 0x32, 0x00, 0x05, 0x00, 0x00, 0x00, 0x00, 0xd8, 0x30, 0x8c, 0xc1, 0x18, 0x98, 0xc1, 0x26, 0x42, 0x00, 0xce, 0x00, 0xd8, 0x00, 0x8c, 0x53, 0x04, 0x31, 0x00, 0x03, 0x2a, 0x18, 0x83, 0x00, 0x00, 0x80, 0x75, 0x81, 0x31, 0x4e, 0x11, 0xc4, 0x20, 0x0c, 0xa8, 0xc0, 0x0c, 0x04, 0x00, 0x00, 0x26, 0x08, 0x40, 0x33, 0x41, 0x00, 0x1c, 0x00, 0x00, 0x33, 0x11, 0x41, 0x60, 0x8c, 0xc2, 0x4c, 0x44, 0x10, 0x18, 0xa3, 0x30, 0x13, 0x01, 0x04, 0x06, 0x29, 0x0c, 0x1b, 0x10, 0x03, 0x31, 0x00, 0xc3, 0x06, 0x84, 0x60, 0x0c, 0xc0, 0x88, 0xc1, 0x01, 0x80, 0x20, 0x18, 0x14, 0xce, 0xf8, 0xff, 0xff, 0xff, 0x0f, 0xe6, 0xff, 0xff, 0xff, 0x3f, 0x94, 0xff, 0xff, 0xff, 0xff, 0x30, 0x63, 0x50, 0x04, 0x8e, 0x18, 0x00, 0xc0, 0xb0, 0x01, 0x11, 0x14, 0x04, 0x30, 0x62, 0x70, 0x00, 0x20, 0x08, 0x06, 0x85, 0x23, 0xfe, 0xff, 0xff, 0xff, 0x03, 0xf9, 0xff, 0xff, 0xff, 0x0f, 0xe5, 0xff, 0xff, 0xff, 0x3f, 0xcc, 0x18, 0x14, 0xc1, 0x26, 0x06, 0x00, 0xc0, 0xc4, 0x8c, 0x41, 0x31, 0x14, 0x62, 0x00, 0x00, 0x01, 0x31, 0x00, 0x02, 0x00, 0x00, 0x00, 0x5b, 0x04, 0x20, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x21, 0x31, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x0b, 0x86, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x71, 0x20, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x32, 0x0e, 0x10, 0x22, 0x84, 0x00, 0xac, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x65, 0x0c, 0x00, 0x00, 0x25, 0x00, 0x00, 0x00, 0x12, 0x03, 0x94, 0x28, 0x01, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x2f, 0x00, 0x00, 0x00, 0x4c, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x58, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x58, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x88, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x43, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x5b, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x88, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0x00, 0x24, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0x08, 0x2c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x5d, 0x0c, 0x00, 0x00, 0x1c, 0x00, 0x00, 0x00, 0x12, 0x03, 0x94, 0xe1, 0x00, 0x00, 0x00, 0x00, 0x6d, 0x61, 0x69, 0x6e, 0x6c, 0x6c, 0x76, 0x6d, 0x2e, 0x64, 0x62, 0x67, 0x2e, 0x64, 0x65, 0x63, 0x6c, 0x61, 0x72, 0x65, 0x31, 0x38, 0x2e, 0x31, 0x2e, 0x36, 0x20, 0x62, 0x63, 0x65, 0x39, 0x33, 0x39, 0x33, 0x32, 0x39, 0x31, 0x61, 0x32, 0x64, 0x61, 0x61, 0x38, 0x30, 0x30, 0x36, 0x64, 0x31, 0x64, 0x61, 0x36, 0x32, 0x39, 0x61, 0x61, 0x32, 0x37, 0x36, 0x35, 0x65, 0x30, 0x30, 0x66, 0x34, 0x65, 0x37, 0x30, 0x78, 0x38, 0x36, 0x5f, 0x36, 0x34, 0x2d, 0x75, 0x6e, 0x6b, 0x6e, 0x6f, 0x77, 0x6e, 0x2d, 0x6c, 0x69, 0x6e, 0x75, 0x78, 0x2d, 0x67, 0x6e, 0x75, 0x6d, 0x61, 0x69, 0x6e, 0x2e, 0x63, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, }; 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 { const Block = struct{ start_size_index: u32, previous_code_size: u32, previous_abbreviations: PinnedArray(*Abbreviation) = .{}, }; const BlockInfo = struct{ id: u32, abbreviations: PinnedArray(*Abbreviation) = .{}, }; const BlockId = enum(u8){ block_info = 0, module = 8, parameter_attribute = 9, parameter_attribute_group = 10, constant = 11, function = 12, identification = 13, value_symtab = 14, metadata = 15, metadata_attachment = 16, type = 17, uselist = 18, module_strtab = 19, global_value_summary = 20, operand_bundle_tags = 21, metadata_kind = 22, strtab = 23, full_lto_global_value_summary = 24, symtab = 25, sync_scope_names = 26, }; const ValueSymtabAbbreviationId = enum(u8){ const base = @intFromEnum(FixedAbbreviationId.first_application_abbrev); entry8 = base + 0, entry7 = base + 1, entry6 = base + 2, bb_entry6 = base + 3, }; const ConstantAbbreviationId = enum(u8) { const base = @intFromEnum(FixedAbbreviationId.first_application_abbrev); set_type = base + 0, integer = base + 1, cast = base + 2, null = base + 3, }; const FunctionAbbreviationId = enum(u8) { const base = @intFromEnum(FixedAbbreviationId.first_application_abbrev); load = base + 0, unary_op = base + 1, unary_op_flags = base + 2, binary_op = base + 3, binary_op_flags = base + 4, cast = base + 5, cast_flags = base + 6, ret_void = base + 7, ret_val = base + 8, @"unreachable" = base + 9, gep = base + 10, }; const Abbreviation = struct{ operands: PinnedArray(Op) = .{}, const Op = struct{ value: u64, encoding: Encoding, is_literal: bool, const Encoding = enum(u3) { fixed = 1, vbr = 2, array = 3, char6 = 4, blob = 5, _, }; pub fn get_encoding_data(operand: Op) ?u64 { return switch (operand.encoding) { .fixed, .vbr => operand.value, .array, .char6, .blob => null, _ => unreachable, }; } }; pub fn add_literal(abbreviation: *Abbreviation, value: u64) void { abbreviation.add_with_encoding_advanced(.{ .value = value, .encoding = @enumFromInt(0), .is_literal = true, }); } pub fn add_with_encoding(abbreviation: *Abbreviation, data: struct { encoding: Op.Encoding, value: u64 = 0, }) void { abbreviation.add_with_encoding_advanced(.{ .value = data.value, .encoding = data.encoding, .is_literal = false, }); } pub fn add_with_encoding_advanced(abbreviation: *Abbreviation, op: Op) void { _ = abbreviation.operands.append(op); } }; const FixedAbbreviationId = enum(u8) { end_block = 0, enter_subblock = 1, define_abbrev = 2, unabbrev_record = 3, first_application_abbrev = 4, }; const width = struct { const block_id = 8; const code_length = 8; const block_size = 32; }; const IdentificationCode = enum(u2) { string = 1, epoch = 2, }; const ModuleCode = enum(u8) { version = 1, triple = 2, data_layout = 3, @"asm" = 4, section_name = 5, dep_lib = 6, global_var = 7, function = 8, alias_old = 9, gc_name = 11, comdat = 12, vst_offset = 13, alias = 14, metadata_values_unused = 15, source_filename = 16, hash = 17, ifunc = 18, }; const ValueSymtabCode = enum(u8) { entry = 1, bb_entry = 2, fn_entry = 3, combined_entry = 5, }; const ConstantCode = enum(u8) { set_type = 1, null = 2, undef = 3, integer = 4, wide_integer = 5, float = 6, aggregate = 7, string = 8, cstring = 9, binary_op = 10, cast = 11, gep = 12, select = 13, extract_element = 14, insert_element = 15, shuffle_vector = 16, cmp = 17, inline_assembly_old = 18, shuffle_vector_ex = 19, inbounds_gep = 20, block_address = 21, data = 22, inline_asm_old2 = 23, gep_with_inrange_index = 24, unary_op = 25, poison = 26, dso_local_equivalent = 27, inline_asm_old3 = 28, no_cfi_value = 29, inline_asm = 30, }; const FunctionCode = enum(u8) { declare_blocks = 1, binary_op = 2, cast = 3, gep_old = 4, select = 5, extract_element = 6, insert_element = 7, shuffle_vector = 8, cmp = 9, ret = 10, br = 11, @"switch" = 12, invoke = 13, @"unreachable" = 15, phi = 16, alloca = 19, load = 20, vaarg = 23, store_old = 24, extract_value = 26, insert_value = 27, cmp2 = 28, vselect = 29, inbounds_gep_old = 30, indirect_br = 31, debug_loc_again = 33, call = 34, debug_loc = 35, fence = 36, cmpxchg_old = 37, atomic_rmw_old = 38, @"resume" = 39, landing_pad_old = 40, load_atomic = 41, store_atomic_old = 42, gep = 43, store = 44, store_atomic = 45, cmpxchg = 46, landing_pad = 47, cleanup_ret = 48, catch_ret = 49, catch_pad = 50, cleanup_pad = 51, catch_switch = 52, operand_bundle = 55, unary_op = 56, call_br = 57, freeze = 58, atomic_rmw = 59, block_addr_users = 60, }; const TypeCode = enum(u8) { num_entry = 1, void = 2, float = 3, double = 4, label = 5, @"opaque" = 6, integer = 7, pointer = 8, function_old = 9, half = 10, array = 11, vector = 12, x86_fp80 = 13, fp128 = 14, ppc_fp128 = 15, metadata = 16, x86_mmx = 17, struct_anon = 18, struct_name = 19, struct_named = 20, function = 21, token = 22, bfloat = 23, x86_amx = 24, opaque_pointer = 25, target_type = 26, }; const BlockInfoCode = enum(u8) { set_bid = 1, block_name = 2, set_record_name = 3, }; const AttributeKindCode = enum(u8) { alignment = 1, always_inline = 2, by_val = 3, inline_hint = 4, in_reg = 5, min_size = 6, naked = 7, nest = 8, no_alias = 9, no_builtin = 10, no_capture = 11, no_duplicate = 12, no_implicit_float = 13, no_inline = 14, non_lazy_bind = 15, no_red_zone = 16, no_return = 17, no_unwind = 18, optimize_for_size = 19, read_none = 20, read_only = 21, returned = 22, returns_twice = 23, s_ext = 24, stack_alignment = 25, stack_protect = 26, stack_protect_req = 27, stack_protect_strong = 28, struct_ret = 29, sanitize_address = 30, sanitize_thread = 31, sanitize_memory = 32, uw_table = 33, z_ext = 34, builtin = 35, cold = 36, optimize_none = 37, in_alloca = 38, non_null = 39, jump_table = 40, dereferenceable = 41, dereferenceable_or_null = 42, convergent = 43, safestack = 44, argmemonly = 45, swift_self = 46, swift_error = 47, no_recurse = 48, inaccessiblemem_only = 49, inaccessiblemem_or_argmemonly = 50, alloc_size = 51, writeonly = 52, speculatable = 53, strict_fp = 54, sanitize_hwaddress = 55, nocf_check = 56, opt_for_fuzzing = 57, shadowcallstack = 58, speculative_load_hardening = 59, immarg = 60, willreturn = 61, nofree = 62, nosync = 63, sanitize_memtag = 64, preallocated = 65, no_merge = 66, null_pointer_is_valid = 67, noundef = 68, byref = 69, mustprogress = 70, no_callback = 71, hot = 72, no_profile = 73, vscale_range = 74, swift_async = 75, no_sanitize_coverage = 76, elementtype = 77, disable_sanitizer_instrumentation = 78, no_sanitize_bounds = 79, alloc_align = 80, allocated_pointer = 81, alloc_kind = 82, presplit_coroutine = 83, fnretthunk_extern = 84, skip_profile = 85, memory = 86, nofpclass = 87, optimize_for_debugging = 88, writable = 89, coro_only_destroy_when_complete = 90, dead_on_unwind = 91, pub fn is_enum(attribute_kind: AttributeKindCode) bool { return switch (attribute_kind) { .alloc_align, .allocated_pointer, .always_inline, .builtin, .cold, .convergent, .disable_sanitizer_instrumentation, .fnretthunk_extern, .hot, .immarg, .inreg, .inline_hint, .jump_table, .min_size, .mustprogress, .naked, .nest, .no_alias, .no_builtin, .no_callback, .no_capture, .nocf_check, .no_duplicate, .nofree, .no_implicit_float, .no_inline, .no_merge, .no_profile, .no_recurse, .no_red_zone, .no_return, .no_sanitize_bounds, .no_sanitize_coverage, .no_sync, .noundef, .no_unwind, .non_lazy_bind, .non_null, .null_pointer_is_valid, .opt_for_fuzzing, .optimize_for_size, .optimize_none, .presplit_coroutine, .read_none, .read_only, .returned, .returns_twice, .s_ext, .safestack, .sanitize_address, .sanitize_hwaddress, .sanitize_memtag, .sanitize_memory, .sanitize_thread, .shadowcallstack, .skip_profile, .speculatable, .speculative_load_hardening, .stack_protect, .stack_protect_req, .stack_protect_strong, .strict_fp, .swift_async, .swift_error, .swift_self, .willreturn, .writeonly, .z_ext, => true, else => false, }; } pub fn is_int(attribute_kind: AttributeKindCode) bool { return switch (attribute_kind) { .alignment, .alloc_kind, .alloc_size, .dereferenceable, .dereferenceable_or_null, .memory, .nofpclass, .stack_alignment, .uw_table, .vscale_range, => true, else => false, }; } pub fn is_type(attribute_kind: AttributeKindCode) bool { return switch (attribute_kind) { .byref, .byval, .elementtype, .in_alloca, .preallocated, .struct_ret, => true, else => false, }; } }; const AttributeCode = enum(u8) { entry_old = 1, entry = 2, group_entry = 3, }; const MetadataCode = enum(u8) { string_old = 1, // mdstring: [values] value = 2, // value: [type num, value num] node = 3, // node: [n x md num] name = 4, // string: [values] distinct_node = 5, // distinct_node: [n x md num] kind = 6, // [n x [id, name]] location = 7, // [distinct, line, col, scope, inlined-at?] old_node = 8, // old_node: [n x (type num, value num)] old_fn_node = 9, // old_fn_node: [n x (type num, value num)] named_node = 10, // named_node: [n x mdnodes] attachment = 11, // [m x [value, [n x [id, mdnode]]] generic_debug = 12, // [distinct, tag, vers, header, n x md num] subrange = 13, // [distinct, count, lo] enumerator = 14, // [isunsigned|distinct, value, name] basic_type = 15, // [distinct, tag, name, size, align, enc] file = 16, // [distinct, filename, directory, checksumkind, checksum] derived_type = 17, // [distinct, ...] composite_type = 18, // [distinct, ...] subroutine_type = 19, // [distinct, flags, types, cc] compile_unit = 20, // [distinct, ...] subprogram = 21, // [distinct, ...] lexical_block = 22, // [distinct, scope, file, line, column] lexical_block_file = 23, //[distinct, scope, file, discriminator] namespace = 24, // [distinct, scope, file, name, line, exportsymbols] template_type = 25, // [distinct, scope, name, type, ...] template_value = 26, // [distinct, scope, name, type, value, ...] global_var = 27, // [distinct, ...] local_var = 28, // [distinct, ...] expression = 29, // [distinct, n x element] objc_property = 30, // [distinct, name, file, line, ...] imported_entity = 31, // [distinct, tag, scope, entity, line, name] module = 32, // [distinct, scope, name, ...] macro = 33, // [distinct, macinfo, line, name, value] macro_file = 34, // [distinct, macinfo, line, file, ...] strings = 35, // [count, offset] blob([lengths][chars]) global_decl_attachment = 36, // [valueid, n x [id, mdnode]] global_var_expr = 37, // [distinct, var, expr] index_offset = 38, // [offset] index = 39, // [bitpos] label = 40, // [distinct, scope, name, file, line] string_type = 41, // [distinct, name, size, align,...] // codes 42 and 43 are reserved for support for fortran array specific debug // info. common_block = 44, // [distinct, scope, name, variable,...] generic_subrange = 45, // [distinct, count, lo, up, stride] arg_list = 46, // [n x [type num, value num]] assign_id = 47, // [distinct, ...] }; fn print_hex_slice(bytes: []const u8) void { for (bytes, 0..) |b, i| { if (i % 4 == 0) { std.debug.print("\n ", .{}); } std.debug.print("0x{x:0>2}, ", .{b}); } } const Writer = struct { buffer: PinnedArray(u32) = .{}, block_scope: PinnedArray(Block) = .{}, current_abbreviations: PinnedArray(*Abbreviation) = .{}, abbreviation_buffer: PinnedArray(Abbreviation) = .{}, block_info_records: PinnedArray(BlockInfo) = .{}, vst_offset_placeholder: u64 = 0, current_bit: u32 = 0, current_value: u32 = 0, current_codesize: u32 = 2, block_info_current_block_id: u32 = 0, strtab_content: PinnedArray(u8) = .{}, fn get_type_count(writer: *Writer) u32 { _ = writer; // autofix return dummy_types.len; } fn compute_bits_required_for_type_indices(writer: *Writer) u32 { if (true) { return std.math.log2_int_ceil(u32, writer.get_type_count() + 1); } else { const n = (writer.get_type_count() + 1); const result = 32 - @ctz(n); return result; } } fn get_byte_slice(writer: *Writer) []const u8 { const final_slice_len = writer.buffer.length * @sizeOf(u32); const final_slice_ptr: [*]const u8 = @alignCast(@ptrCast(writer.buffer.pointer)); const final_slice = final_slice_ptr[0..final_slice_len]; return final_slice; } // TODO: fix? fn get_byte_position(writer: *Writer) u32 { return writer.buffer.length * @sizeOf(u32); } fn write_module_block(writer: *Writer) void { const raw = false; if (raw) { const module_block align(4) = [_]u8 { 0x21, 0x0c, 0x00, 0x00, 0x77, 0x02, 0x00, 0x00, 0x0b, 0x02, 0x21, 0x00, 0x02, 0x00, 0x00, 0x00, 0x17, 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, 0x0c, 0x45, 0x02, 0x42, 0x92, 0x0b, 0x42, 0x64, 0x10, 0x32, 0x14, 0x38, 0x08, 0x18, 0x4b, 0x0a, 0x32, 0x32, 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, 0x32, 0x84, 0x58, 0x0e, 0x90, 0x91, 0x21, 0x44, 0x90, 0xa1, 0x82, 0xa2, 0x02, 0x19, 0xc3, 0x07, 0xcb, 0x15, 0x09, 0x32, 0x8c, 0x0c, 0x89, 0x20, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x22, 0x66, 0x04, 0x10, 0xb2, 0x42, 0x82, 0xc9, 0x10, 0x52, 0x42, 0x82, 0xc9, 0x90, 0x71, 0xc2, 0x50, 0x48, 0x0a, 0x09, 0x26, 0x43, 0xc6, 0x05, 0x42, 0x32, 0x26, 0x08, 0x0c, 0x9a, 0x23, 0x00, 0x83, 0x32, 0x24, 0x18, 0x01, 0x18, 0x08, 0x28, 0xc4, 0x48, 0x02, 0x00, 0x51, 0x18, 0x00, 0x00, 0x51, 0x00, 0x00, 0x00, 0x1b, 0x54, 0x23, 0xf8, 0xff, 0xff, 0xff, 0xff, 0x01, 0x70, 0x00, 0x09, 0x28, 0x83, 0x20, 0x0c, 0x04, 0xc2, 0x1c, 0xe4, 0x21, 0x1c, 0xda, 0xa1, 0x1c, 0xda, 0x00, 0x1e, 0xde, 0x21, 0x1d, 0xdc, 0x81, 0x1e, 0xca, 0x41, 0x1e, 0x80, 0x70, 0x60, 0x07, 0x76, 0x00, 0x88, 0x76, 0x48, 0x07, 0x77, 0x68, 0x03, 0x76, 0x28, 0x87, 0x73, 0x08, 0x07, 0x76, 0x68, 0x03, 0x7b, 0x28, 0x87, 0x71, 0xa0, 0x87, 0x77, 0x90, 0x87, 0x36, 0xb8, 0x87, 0x74, 0x20, 0x07, 0x7a, 0x40, 0x07, 0x00, 0x0e, 0x00, 0xc2, 0x1d, 0xde, 0xa1, 0x0d, 0xe8, 0x41, 0x1e, 0xc2, 0x01, 0x1e, 0xe0, 0x21, 0x1d, 0xdc, 0xe1, 0x1c, 0xda, 0xa0, 0x1d, 0xc2, 0x81, 0x1e, 0xd0, 0x01, 0xa0, 0x07, 0x79, 0xa8, 0x87, 0x72, 0x00, 0x88, 0x79, 0xa0, 0x87, 0x70, 0x18, 0x87, 0x75, 0x68, 0x03, 0x78, 0x90, 0x87, 0x77, 0xa0, 0x87, 0x72, 0x18, 0x07, 0x7a, 0x78, 0x07, 0x79, 0x68, 0x03, 0x71, 0xa8, 0x07, 0x73, 0x30, 0x87, 0x72, 0x90, 0x87, 0x36, 0x98, 0x87, 0x74, 0xd0, 0x87, 0x72, 0x00, 0xf0, 0x00, 0x20, 0xe8, 0x21, 0x1c, 0xe4, 0xe1, 0x1c, 0xca, 0x81, 0x1e, 0xda, 0x60, 0x1c, 0xe0, 0xa1, 0x1e, 0x00, 0x7c, 0xc0, 0x03, 0x3b, 0x68, 0x03, 0x3b, 0xa0, 0x03, 0x80, 0xa0, 0x87, 0x70, 0x90, 0x87, 0x73, 0x28, 0x07, 0x7a, 0x68, 0x03, 0x73, 0x28, 0x87, 0x70, 0xa0, 0x87, 0x7a, 0x90, 0x87, 0x72, 0x98, 0x07, 0x60, 0x0d, 0xc6, 0xa1, 0x1d, 0xde, 0xc1, 0x1e, 0xd8, 0x60, 0x0d, 0xc6, 0x01, 0x1f, 0xf0, 0x80, 0x0d, 0xd6, 0xc0, 0x1c, 0xf0, 0x61, 0x1e, 0xe4, 0x81, 0x0d, 0xd6, 0xa0, 0x1d, 0xda, 0x01, 0x1f, 0xd8, 0x60, 0x0d, 0xe6, 0x61, 0x1e, 0xca, 0x81, 0x0d, 0xd6, 0x60, 0x1e, 0xe6, 0xa1, 0x1c, 0xe4, 0x80, 0x0d, 0xd6, 0x00, 0x1f, 0xf0, 0xe0, 0x0e, 0x00, 0x82, 0x1e, 0xea, 0xc1, 0x1d, 0xca, 0xa1, 0x0d, 0xc6, 0x01, 0x1e, 0xea, 0x01, 0x38, 0x87, 0x72, 0x70, 0x87, 0x72, 0x90, 0x87, 0x74, 0x18, 0x07, 0x60, 0x03, 0x21, 0x04, 0x00, 0x29, 0x6c, 0x20, 0x06, 0x01, 0x20, 0x85, 0x0d, 0x11, 0xf1, 0xff, 0xff, 0xff, 0xff, 0x03, 0x70, 0x0a, 0x80, 0x1f, 0x00, 0x7f, 0x00, 0x48, 0x40, 0x1d, 0x00, 0x7d, 0x10, 0xd8, 0x02, 0x00, 0x00, 0x49, 0x18, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x13, 0x86, 0x40, 0x18, 0x26, 0x04, 0x04, 0x00, 0x13, 0x30, 0x7c, 0xc0, 0x03, 0x3b, 0xf8, 0x05, 0x3b, 0xa0, 0x83, 0x36, 0xa8, 0x07, 0x77, 0x58, 0x07, 0x77, 0x78, 0x87, 0x7b, 0x70, 0x87, 0x36, 0x60, 0x87, 0x74, 0x70, 0x87, 0x7a, 0xc0, 0x87, 0x36, 0x38, 0x07, 0x77, 0xa8, 0x87, 0x0d, 0xaf, 0x50, 0x0e, 0x6d, 0xd0, 0x0e, 0x7a, 0x50, 0x0e, 0x6d, 0x00, 0x0f, 0x72, 0x70, 0x07, 0x70, 0xa0, 0x07, 0x73, 0x20, 0x07, 0x7a, 0x30, 0x07, 0x72, 0xd0, 0x06, 0xf0, 0x20, 0x07, 0x77, 0x10, 0x07, 0x7a, 0x30, 0x07, 0x72, 0xa0, 0x07, 0x73, 0x20, 0x07, 0x6d, 0x00, 0x0f, 0x72, 0x70, 0x07, 0x72, 0xa0, 0x07, 0x76, 0x40, 0x07, 0x7a, 0x60, 0x07, 0x74, 0xd0, 0x06, 0xe9, 0x60, 0x07, 0x74, 0xa0, 0x07, 0x76, 0x40, 0x07, 0x6d, 0x90, 0x0e, 0x71, 0x20, 0x07, 0x78, 0xa0, 0x07, 0x71, 0x20, 0x07, 0x78, 0xd0, 0x06, 0xe6, 0x80, 0x07, 0x70, 0xa0, 0x07, 0x71, 0x20, 0x07, 0x78, 0xd0, 0x06, 0xee, 0x80, 0x07, 0x7a, 0x10, 0x07, 0x76, 0xa0, 0x07, 0x73, 0x20, 0x07, 0x7a, 0x60, 0x07, 0x74, 0xd0, 0x06, 0xb3, 0x10, 0x07, 0x72, 0x80, 0x07, 0x1a, 0x21, 0x0c, 0x69, 0x30, 0x00, 0xd2, 0xf8, 0xc2, 0x90, 0x0a, 0x20, 0x04, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x02, 0x18, 0x52, 0x11, 0x50, 0x01, 0x04, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x12, 0x1b, 0x04, 0x8a, 0xee, 0x09, 0x00, 0x00, 0x64, 0x81, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x32, 0x1e, 0x98, 0x10, 0x19, 0x11, 0x4c, 0x90, 0x8c, 0x09, 0x26, 0x47, 0xc6, 0x04, 0x43, 0x4a, 0x39, 0x94, 0x42, 0x11, 0x94, 0x41, 0x09, 0x14, 0x42, 0x41, 0x00, 0x00, 0xb1, 0x18, 0x00, 0x00, 0xc1, 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, 0x66, 0x4c, 0x67, 0x30, 0x0e, 0xef, 0x20, 0x0f, 0xef, 0xe0, 0x06, 0xef, 0x50, 0x0f, 0xf4, 0x30, 0x0f, 0xe9, 0x40, 0x0e, 0xe5, 0xe0, 0x06, 0xe6, 0x20, 0x0f, 0xe1, 0xd0, 0x0e, 0xe5, 0x00, 0x00, 0x00, 0x79, 0x20, 0x00, 0x00, 0x6a, 0x00, 0x00, 0x00, 0x72, 0x1e, 0x48, 0x20, 0x43, 0x88, 0x0c, 0x19, 0x09, 0x72, 0x32, 0x48, 0x20, 0x23, 0x81, 0x8c, 0x91, 0x91, 0xd1, 0x44, 0xa0, 0x10, 0x28, 0x64, 0x3c, 0x31, 0x32, 0x42, 0x8e, 0x90, 0x21, 0xa3, 0xb8, 0x30, 0xf4, 0x01, 0xc6, 0x02, 0x06, 0xe8, 0xd0, 0x48, 0x4a, 0x92, 0x1c, 0x0d, 0x00, 0x00, 0x6d, 0x61, 0x69, 0x6e, 0x2e, 0x63, 0x2f, 0x68, 0x6f, 0x6d, 0x65, 0x2f, 0x64, 0x61, 0x76, 0x69, 0x64, 0x64, 0x35, 0x36, 0x65, 0x30, 0x63, 0x30, 0x39, 0x62, 0x30, 0x32, 0x32, 0x33, 0x37, 0x61, 0x61, 0x37, 0x38, 0x63, 0x61, 0x62, 0x39, 0x39, 0x64, 0x35, 0x36, 0x65, 0x65, 0x65, 0x36, 0x63, 0x63, 0x63, 0x6c, 0x61, 0x6e, 0x67, 0x20, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x20, 0x31, 0x38, 0x2e, 0x31, 0x2e, 0x36, 0x20, 0x28, 0x68, 0x74, 0x74, 0x70, 0x73, 0x3a, 0x2f, 0x2f, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x6c, 0x6c, 0x76, 0x6d, 0x2f, 0x6c, 0x6c, 0x76, 0x6d, 0x2d, 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x2e, 0x67, 0x69, 0x74, 0x20, 0x62, 0x63, 0x65, 0x39, 0x33, 0x39, 0x33, 0x32, 0x39, 0x31, 0x61, 0x32, 0x64, 0x61, 0x61, 0x38, 0x30, 0x30, 0x36, 0x64, 0x31, 0x64, 0x61, 0x36, 0x32, 0x39, 0x61, 0x61, 0x32, 0x37, 0x36, 0x35, 0x65, 0x30, 0x30, 0x66, 0x34, 0x65, 0x37, 0x30, 0x29, 0x44, 0x77, 0x61, 0x72, 0x66, 0x20, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x44, 0x65, 0x62, 0x75, 0x67, 0x20, 0x49, 0x6e, 0x66, 0x6f, 0x20, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x77, 0x63, 0x68, 0x61, 0x72, 0x5f, 0x73, 0x69, 0x7a, 0x65, 0x50, 0x49, 0x43, 0x20, 0x4c, 0x65, 0x76, 0x65, 0x6c, 0x50, 0x49, 0x45, 0x20, 0x4c, 0x65, 0x76, 0x65, 0x6c, 0x75, 0x77, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x66, 0x72, 0x61, 0x6d, 0x65, 0x2d, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x23, 0x08, 0x81, 0x30, 0x82, 0x10, 0x0c, 0x23, 0x08, 0x01, 0x31, 0x82, 0x10, 0x14, 0x23, 0x08, 0x81, 0x31, 0x82, 0x10, 0x1c, 0x23, 0x08, 0x01, 0x32, 0x94, 0x15, 0x74, 0x14, 0x01, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x03, 0x15, 0x40, 0x20, 0x04, 0xc3, 0x0c, 0x03, 0x53, 0x34, 0x33, 0x0c, 0x8e, 0xf1, 0xcc, 0x30, 0x40, 0x47, 0x34, 0xc3, 0x20, 0x21, 0xce, 0x0c, 0x03, 0x93, 0x38, 0x33, 0x0c, 0x8c, 0xe2, 0xcc, 0x30, 0x30, 0x8b, 0x33, 0x43, 0x40, 0xc8, 0x48, 0x60, 0x82, 0x72, 0x61, 0x63, 0xb3, 0x6b, 0x73, 0x21, 0x13, 0x3b, 0x73, 0x19, 0xab, 0x1b, 0x25, 0x90, 0x32, 0x62, 0x63, 0xb3, 0x6b, 0x73, 0x69, 0x7b, 0x23, 0xab, 0x63, 0x2b, 0x73, 0x31, 0x63, 0x0b, 0x3b, 0x9b, 0x1b, 0xe5, 0xa0, 0x2a, 0xeb, 0xc2, 0x32, 0x2d, 0x15, 0x36, 0x36, 0xbb, 0x36, 0x97, 0x34, 0xb2, 0x32, 0x37, 0xba, 0x51, 0x82, 0x0d, 0x00, 0x00, 0x00, 0x00, 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, 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, 0x61, 0x20, 0x00, 0x00, 0x4d, 0x00, 0x00, 0x00, 0x13, 0x04, 0x41, 0x2c, 0x10, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x94, 0x11, 0x00, 0x00, 0xf1, 0x30, 0x00, 0x00, 0x24, 0x00, 0x00, 0x00, 0x22, 0x47, 0xc8, 0x90, 0x51, 0x16, 0xc4, 0x05, 0xc4, 0x40, 0x10, 0x04, 0x6d, 0x61, 0x69, 0x6e, 0x69, 0x6e, 0x74, 0x63, 0x68, 0x61, 0x72, 0x61, 0x72, 0x67, 0x63, 0x61, 0x72, 0x67, 0x76, 0x00, 0xab, 0xa8, 0x83, 0xea, 0x00, 0x2a, 0x40, 0x03, 0x01, 0x40, 0x00, 0x10, 0x99, 0x00, 0x20, 0x0d, 0x00, 0x00, 0x00, 0xf6, 0x1c, 0x00, 0x19, 0x78, 0x60, 0x00, 0x14, 0xc0, 0x9e, 0x03, 0x20, 0x83, 0x0f, 0x01, 0x0c, 0x60, 0x91, 0x03, 0x3c, 0x00, 0x00, 0x00, 0x64, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x00, 0xb0, 0xc8, 0x01, 0x1e, 0x00, 0x00, 0x80, 0x32, 0x00, 0x05, 0x00, 0x00, 0x00, 0x00, 0xd8, 0x30, 0x8c, 0xc1, 0x18, 0x98, 0xc1, 0x26, 0x42, 0x00, 0xce, 0x00, 0xd8, 0x00, 0x8c, 0x53, 0x04, 0x31, 0x00, 0x03, 0x2a, 0x18, 0x83, 0x00, 0x00, 0x80, 0x75, 0x81, 0x31, 0x4e, 0x11, 0xc4, 0x20, 0x0c, 0xa8, 0xc0, 0x0c, 0x04, 0x00, 0x00, 0x26, 0x08, 0x40, 0x33, 0x41, 0x00, 0x1c, 0x00, 0x00, 0x33, 0x11, 0x41, 0x60, 0x8c, 0xc2, 0x4c, 0x44, 0x10, 0x18, 0xa3, 0x30, 0x13, 0x01, 0x04, 0x06, 0x29, 0x0c, 0x1b, 0x10, 0x03, 0x31, 0x00, 0xc3, 0x06, 0x84, 0x60, 0x0c, 0xc0, 0x88, 0xc1, 0x01, 0x80, 0x20, 0x18, 0x14, 0xce, 0xf8, 0xff, 0xff, 0xff, 0x0f, 0xe6, 0xff, 0xff, 0xff, 0x3f, 0x94, 0xff, 0xff, 0xff, 0xff, 0x30, 0x63, 0x50, 0x04, 0x8e, 0x18, 0x00, 0xc0, 0xb0, 0x01, 0x11, 0x14, 0x04, 0x30, 0x62, 0x70, 0x00, 0x20, 0x08, 0x06, 0x85, 0x23, 0xfe, 0xff, 0xff, 0xff, 0x03, 0xf9, 0xff, 0xff, 0xff, 0x0f, 0xe5, 0xff, 0xff, 0xff, 0x3f, 0xcc, 0x18, 0x14, 0xc1, 0x26, 0x06, 0x00, 0xc0, 0xc4, 0x8c, 0x41, 0x31, 0x14, 0x62, 0x00, 0x00, 0x01, 0x31, 0x00, 0x02, 0x00, 0x00, 0x00, 0x5b, 0x04, 0x20, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x21, 0x31, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x0b, 0x86, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x71, 0x20, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x32, 0x0e, 0x10, 0x22, 0x84, 0x00, 0xac, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, }; writer.append_bytes(&module_block); } else { const module_version_start = writer.buffer.length; _ = module_version_start; // autofix writer.enter_subblock(.identification, 3); const block_start_position = writer.get_byte_position(); _ = block_start_position; // autofix writer.write_module_version(); writer.write_block_info(); writer.write_type_table(); writer.write_attribute_group_table(); writer.write_attribute_table(); // TODO // writer.write_comdats(); writer.write_module_info(); writer.write_module_constants(); writer.write_module_metadata_kinds(); writer.write_module_metadata(); // TODO: const should_preserve_use_list_order = false; if (should_preserve_use_list_order) { writer.write_use_list_block(null); } writer.write_operand_bundle_tags(); writer.write_sync_scope_names(); // TODO: functions // for (functions) |function| { // if (!function.is_declaration) { // write.write_function(function); // } // } // // TODO: module summary // if (index) { // writer.write_per_module_global_value_summary(); // } // TODO: // writer.write_global_value_symbol_table(map); // writer.write_module_hash(block_start_position); writer.exit_block(); } } fn write_symtab(writer: *Writer) void { // TODO: const symtab_block align(4) = [_]u8{ 0x65, 0x0c, 0x00, 0x00, 0x25, 0x00, 0x00, 0x00, 0x12, 0x03, 0x94, 0x28, 0x01, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x2f, 0x00, 0x00, 0x00, 0x4c, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x58, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x58, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x88, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x43, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x5b, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x88, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0x00, 0x24, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0x08, 0x2c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, }; writer.append_bytes(&symtab_block); } fn write_strtab(writer: *Writer) void { // TODO: const strtab_block align(4) = .{ 0x5d, 0x0c, 0x00, 0x00, 0x1c, 0x00, 0x00, 0x00, 0x12, 0x03, 0x94, 0xe1, 0x00, 0x00, 0x00, 0x00, 0x6d, 0x61, 0x69, 0x6e, 0x6c, 0x6c, 0x76, 0x6d, 0x2e, 0x64, 0x62, 0x67, 0x2e, 0x64, 0x65, 0x63, 0x6c, 0x61, 0x72, 0x65, 0x31, 0x38, 0x2e, 0x31, 0x2e, 0x36, 0x20, 0x62, 0x63, 0x65, 0x39, 0x33, 0x39, 0x33, 0x32, 0x39, 0x31, 0x61, 0x32, 0x64, 0x61, 0x61, 0x38, 0x30, 0x30, 0x36, 0x64, 0x31, 0x64, 0x61, 0x36, 0x32, 0x39, 0x61, 0x61, 0x32, 0x37, 0x36, 0x35, 0x65, 0x30, 0x30, 0x66, 0x34, 0x65, 0x37, 0x30, 0x78, 0x38, 0x36, 0x5f, 0x36, 0x34, 0x2d, 0x75, 0x6e, 0x6b, 0x6e, 0x6f, 0x77, 0x6e, 0x2d, 0x6c, 0x69, 0x6e, 0x75, 0x78, 0x2d, 0x67, 0x6e, 0x75, 0x6d, 0x61, 0x69, 0x6e, 0x2e, 0x63, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, }; writer.append_bytes(&strtab_block); } pub fn write(writer: *Writer) void { const magic align(4) = [_]u8{ 0x42, 0x43, 0xc0, 0xde }; writer.append_bytes(&magic); writer.write_identification_block(); writer.write_module_block(); writer.write_symtab(); writer.write_strtab(); } fn write_module_version(writer: *Writer) void { writer.emit_record(u64, @intFromEnum(ModuleCode.version), &.{2}, 0); } fn enter_block_info_block(writer: *Writer) void { writer.enter_subblock(BlockId.block_info, 2); writer.block_info_current_block_id = ~@as(u32, 0); writer.block_info_records.clear(); } fn write_block_info(writer: *Writer) void { writer.enter_block_info_block(); const start = writer.buffer.length * 4; { const abbreviation = writer.abbreviation_buffer.append(.{}); abbreviation.add_with_encoding(.{ .encoding = .fixed, .value = 3 }); abbreviation.add_with_encoding(.{ .encoding = .vbr, .value = 8 }); abbreviation.add_with_encoding(.{ .encoding = .array }); abbreviation.add_with_encoding(.{ .encoding = .fixed, .value = 8 }); const block_info_abbrev = writer.emit_block_info_abbrev(@intFromEnum(BlockId.value_symtab), abbreviation); if (block_info_abbrev != @intFromEnum(ValueSymtabAbbreviationId.entry8)) unreachable; } { const abbreviation = writer.abbreviation_buffer.append(.{}); abbreviation.add_literal(@intFromEnum(ValueSymtabCode.entry)); abbreviation.add_with_encoding(.{ .encoding = .vbr, .value = 8 }); abbreviation.add_with_encoding(.{ .encoding = .array }); abbreviation.add_with_encoding(.{ .encoding = .fixed, .value = 7 }); const block_info_abbrev = writer.emit_block_info_abbrev(@intFromEnum(BlockId.value_symtab), abbreviation); if (block_info_abbrev != @intFromEnum(ValueSymtabAbbreviationId.entry7)) unreachable; } { const abbreviation = writer.abbreviation_buffer.append(.{}); abbreviation.add_literal(@intFromEnum(ValueSymtabCode.entry)); abbreviation.add_with_encoding(.{ .encoding = .vbr, .value = 8 }); abbreviation.add_with_encoding(.{ .encoding = .array }); abbreviation.add_with_encoding(.{ .encoding = .char6 }); const block_info_abbrev = writer.emit_block_info_abbrev(@intFromEnum(BlockId.value_symtab), abbreviation); if (block_info_abbrev != @intFromEnum(ValueSymtabAbbreviationId.entry6)) unreachable; } { const abbreviation = writer.abbreviation_buffer.append(.{}); abbreviation.add_literal(@intFromEnum(ValueSymtabCode.bb_entry)); abbreviation.add_with_encoding(.{ .encoding = .vbr, .value = 8 }); abbreviation.add_with_encoding(.{ .encoding = .array }); abbreviation.add_with_encoding(.{ .encoding = .char6 }); const block_info_abbrev = writer.emit_block_info_abbrev(@intFromEnum(BlockId.value_symtab), abbreviation); if (block_info_abbrev != @intFromEnum(ValueSymtabAbbreviationId.bb_entry6)) unreachable; } { const abbreviation = writer.abbreviation_buffer.append(.{}); abbreviation.add_literal(@intFromEnum(ConstantCode.set_type)); abbreviation.add_with_encoding(.{ .encoding = .fixed, .value = writer.compute_bits_required_for_type_indices() }); const block_info_abbrev = writer.emit_block_info_abbrev(@intFromEnum(BlockId.constant), abbreviation); if (block_info_abbrev != @intFromEnum(ConstantAbbreviationId.set_type)) unreachable; } { const abbreviation = writer.abbreviation_buffer.append(.{}); abbreviation.add_literal(@intFromEnum(ConstantCode.integer)); abbreviation.add_with_encoding(.{ .encoding = .vbr, .value = 8 }); const block_info_abbrev = writer.emit_block_info_abbrev(@intFromEnum(BlockId.constant), abbreviation); if (block_info_abbrev != @intFromEnum(ConstantAbbreviationId.integer)) unreachable; } { const abbreviation = writer.abbreviation_buffer.append(.{}); abbreviation.add_literal(@intFromEnum(ConstantCode.cast)); abbreviation.add_with_encoding(.{ .encoding = .fixed, .value = 4 }); abbreviation.add_with_encoding(.{ .encoding = .fixed, .value = writer.compute_bits_required_for_type_indices() }); abbreviation.add_with_encoding(.{ .encoding = .vbr, .value = 8 }); const block_info_abbrev = writer.emit_block_info_abbrev(@intFromEnum(BlockId.constant), abbreviation); if (block_info_abbrev != @intFromEnum(ConstantAbbreviationId.cast)) unreachable; } { const abbreviation = writer.abbreviation_buffer.append(.{}); abbreviation.add_literal(@intFromEnum(ConstantCode.null)); const block_info_abbrev = writer.emit_block_info_abbrev(@intFromEnum(BlockId.constant), abbreviation); if (block_info_abbrev != @intFromEnum(ConstantAbbreviationId.null)) unreachable; } // TODO: check FIXME in LLVM code { const abbreviation = writer.abbreviation_buffer.append(.{}); abbreviation.add_literal(@intFromEnum(FunctionCode.load)); abbreviation.add_with_encoding(.{ .encoding = .vbr, .value = 6 }); abbreviation.add_with_encoding(.{ .encoding = .fixed, .value = writer.compute_bits_required_for_type_indices() }); abbreviation.add_with_encoding(.{ .encoding = .vbr, .value = 4 }); abbreviation.add_with_encoding(.{ .encoding = .fixed, .value = 1 }); const block_info_abbrev = writer.emit_block_info_abbrev(@intFromEnum(BlockId.function), abbreviation); if (block_info_abbrev != @intFromEnum(FunctionAbbreviationId.load)) unreachable; } { const abbreviation = writer.abbreviation_buffer.append(.{}); abbreviation.add_literal(@intFromEnum(FunctionCode.unary_op)); abbreviation.add_with_encoding(.{ .encoding = .vbr, .value = 6 }); abbreviation.add_with_encoding(.{ .encoding = .fixed, .value = 4 }); const block_info_abbrev = writer.emit_block_info_abbrev(@intFromEnum(BlockId.function), abbreviation); if (block_info_abbrev != @intFromEnum(FunctionAbbreviationId.unary_op)) unreachable; } { const abbreviation = writer.abbreviation_buffer.append(.{}); abbreviation.add_literal(@intFromEnum(FunctionCode.unary_op)); abbreviation.add_with_encoding(.{ .encoding = .vbr, .value = 6 }); abbreviation.add_with_encoding(.{ .encoding = .fixed, .value = 4 }); abbreviation.add_with_encoding(.{ .encoding = .fixed, .value = 8 }); const block_info_abbrev = writer.emit_block_info_abbrev(@intFromEnum(BlockId.function), abbreviation); if (block_info_abbrev != @intFromEnum(FunctionAbbreviationId.unary_op_flags)) unreachable; } { const abbreviation = writer.abbreviation_buffer.append(.{}); abbreviation.add_literal(@intFromEnum(FunctionCode.binary_op)); abbreviation.add_with_encoding(.{ .encoding = .vbr, .value = 6 }); abbreviation.add_with_encoding(.{ .encoding = .vbr, .value = 6 }); abbreviation.add_with_encoding(.{ .encoding = .fixed, .value = 4 }); const block_info_abbrev = writer.emit_block_info_abbrev(@intFromEnum(BlockId.function), abbreviation); if (block_info_abbrev != @intFromEnum(FunctionAbbreviationId.binary_op)) unreachable; } { const abbreviation = writer.abbreviation_buffer.append(.{}); abbreviation.add_literal(@intFromEnum(FunctionCode.binary_op)); abbreviation.add_with_encoding(.{ .encoding = .vbr, .value = 6 }); abbreviation.add_with_encoding(.{ .encoding = .vbr, .value = 6 }); abbreviation.add_with_encoding(.{ .encoding = .fixed, .value = 4 }); abbreviation.add_with_encoding(.{ .encoding = .fixed, .value = 8 }); const block_info_abbrev = writer.emit_block_info_abbrev(@intFromEnum(BlockId.function), abbreviation); if (block_info_abbrev != @intFromEnum(FunctionAbbreviationId.binary_op_flags)) unreachable; } { const abbreviation = writer.abbreviation_buffer.append(.{}); abbreviation.add_literal(@intFromEnum(FunctionCode.cast)); abbreviation.add_with_encoding(.{ .encoding = .vbr, .value = 6 }); abbreviation.add_with_encoding(.{ .encoding = .fixed, .value = writer.compute_bits_required_for_type_indices() }); abbreviation.add_with_encoding(.{ .encoding = .fixed, .value = 4 }); const block_info_abbrev = writer.emit_block_info_abbrev(@intFromEnum(BlockId.function), abbreviation); if (block_info_abbrev != @intFromEnum(FunctionAbbreviationId.cast)) unreachable; } { const abbreviation = writer.abbreviation_buffer.append(.{}); abbreviation.add_literal(@intFromEnum(FunctionCode.cast)); abbreviation.add_with_encoding(.{ .encoding = .vbr, .value = 6 }); abbreviation.add_with_encoding(.{ .encoding = .fixed, .value = writer.compute_bits_required_for_type_indices() }); abbreviation.add_with_encoding(.{ .encoding = .fixed, .value = 4 }); abbreviation.add_with_encoding(.{ .encoding = .fixed, .value = 8 }); const block_info_abbrev = writer.emit_block_info_abbrev(@intFromEnum(BlockId.function), abbreviation); if (block_info_abbrev != @intFromEnum(FunctionAbbreviationId.cast_flags)) unreachable; } { const abbreviation = writer.abbreviation_buffer.append(.{}); abbreviation.add_literal(@intFromEnum(FunctionCode.ret)); const block_info_abbrev = writer.emit_block_info_abbrev(@intFromEnum(BlockId.function), abbreviation); if (block_info_abbrev != @intFromEnum(FunctionAbbreviationId.ret_void)) unreachable; } { const abbreviation = writer.abbreviation_buffer.append(.{}); abbreviation.add_literal(@intFromEnum(FunctionCode.ret)); abbreviation.add_with_encoding(.{ .encoding = .vbr, .value = 6 }); const block_info_abbrev = writer.emit_block_info_abbrev(@intFromEnum(BlockId.function), abbreviation); if (block_info_abbrev != @intFromEnum(FunctionAbbreviationId.ret_val)) unreachable; } { const abbreviation = writer.abbreviation_buffer.append(.{}); abbreviation.add_literal(@intFromEnum(FunctionCode.@"unreachable")); const block_info_abbrev = writer.emit_block_info_abbrev(@intFromEnum(BlockId.function), abbreviation); if (block_info_abbrev != @intFromEnum(FunctionAbbreviationId.@"unreachable")) unreachable; } { const abbreviation = writer.abbreviation_buffer.append(.{}); abbreviation.add_literal(@intFromEnum(FunctionCode.gep)); abbreviation.add_with_encoding(.{ .encoding = .fixed, .value = 1 }); abbreviation.add_with_encoding(.{ .encoding = .fixed, .value = writer.compute_bits_required_for_type_indices() }); abbreviation.add_with_encoding(.{ .encoding = .array }); abbreviation.add_with_encoding(.{ .encoding = .vbr, .value = 6 }); const block_info_abbrev = writer.emit_block_info_abbrev(@intFromEnum(BlockId.function), abbreviation); if (block_info_abbrev != @intFromEnum(FunctionAbbreviationId.gep)) unreachable; } writer.exit_block(); const end = writer.buffer.length * 4; const expected = debug_main_bitcode[start..end]; const have = writer.get_byte_slice()[start..end]; std.testing.expectEqualSlices(u8, expected, have) catch unreachable; } const DummyType = union(enum){ pointer, integer: u16, function: struct{ varargs: bool, return_type: u64, parameter_types: []const u64, }, metadata, void, }; const dummy_types = [_]DummyType{.pointer, .{ .integer = 32 }, .{ .function = .{ .varargs = false, .return_type = 1, .parameter_types = &.{ 1, 0 }, } }, .void, .metadata, .{ .function = .{ .varargs = false, .return_type = 3, .parameter_types = &.{ 4, 4, 4 }, }, } }; comptime { assert(dummy_types.len == 6); } fn write_type_table(writer: *Writer) void { writer.enter_subblock(.type, 4); const start = writer.buffer.length * 4; var type_values = std.BoundedArray(u64, 64){}; // TODO: compute const opaque_pointer_abbreviation = blk: { const abbreviation = writer.abbreviation_buffer.append(.{}); abbreviation.add_literal(@intFromEnum(TypeCode.opaque_pointer)); abbreviation.add_literal(0); break :blk writer.emit_abbreviation(abbreviation); }; const function_abbreviation = blk: { const abbreviation = writer.abbreviation_buffer.append(.{}); abbreviation.add_literal(@intFromEnum(TypeCode.function)); abbreviation.add_with_encoding(.{ .encoding = .fixed, .value = 1 }); abbreviation.add_with_encoding(.{ .encoding = .array }); abbreviation.add_with_encoding(.{ .encoding = .fixed, .value = writer.compute_bits_required_for_type_indices() }); break :blk writer.emit_abbreviation(abbreviation); }; const struct_anon_abbreviation = blk: { const abbreviation = writer.abbreviation_buffer.append(.{}); abbreviation.add_literal(@intFromEnum(TypeCode.struct_anon)); abbreviation.add_with_encoding(.{ .encoding = .fixed, .value = 1 }); abbreviation.add_with_encoding(.{ .encoding = .array }); abbreviation.add_with_encoding(.{ .encoding = .fixed, .value = writer.compute_bits_required_for_type_indices() }); break :blk writer.emit_abbreviation(abbreviation); }; _ = struct_anon_abbreviation; // autofix const struct_name_abbreviation = blk: { const abbreviation = writer.abbreviation_buffer.append(.{}); abbreviation.add_literal(@intFromEnum(TypeCode.struct_name)); abbreviation.add_with_encoding(.{ .encoding = .array }); abbreviation.add_with_encoding(.{ .encoding = .char6 }); break :blk writer.emit_abbreviation(abbreviation); }; const struct_named_abbreviation = blk: { const abbreviation = writer.abbreviation_buffer.append(.{}); abbreviation.add_literal(@intFromEnum(TypeCode.struct_named)); abbreviation.add_with_encoding(.{ .encoding = .fixed, .value = 1 }); abbreviation.add_with_encoding(.{ .encoding = .array }); abbreviation.add_with_encoding(.{ .encoding = .fixed, .value = writer.compute_bits_required_for_type_indices() }); break :blk writer.emit_abbreviation(abbreviation); }; _ = struct_named_abbreviation; // autofix const array_abbreviation = blk: { const abbreviation = writer.abbreviation_buffer.append(.{}); abbreviation.add_literal(@intFromEnum(TypeCode.array)); abbreviation.add_with_encoding(.{ .encoding = .vbr, .value = 8 }); abbreviation.add_with_encoding(.{ .encoding = .fixed, .value = writer.compute_bits_required_for_type_indices() }); break :blk writer.emit_abbreviation(abbreviation); }; _ = array_abbreviation; // autofix _ = struct_name_abbreviation; // autofix // type_values.appendAssumeCapacity(writer.get_type_count()); writer.emit_record(u64, @intFromEnum(TypeCode.num_entry), type_values.constSlice(), 0); type_values.resize(0) catch unreachable; const EmissionInfo = struct{ abbreviation: u32 = 0, code: u32 = 0, }; for (dummy_types) |ty| { // std.debug.print("Ty: {s}\n", .{@tagName(ty)}); const emission_info: EmissionInfo = switch (ty) { .pointer => b: { type_values.appendAssumeCapacity(address_space); break :b .{ .abbreviation = opaque_pointer_abbreviation, .code = @intFromEnum(TypeCode.opaque_pointer), }; }, .integer => |bit_count| b: { type_values.appendAssumeCapacity(bit_count); break :b .{ .code = @intFromEnum(TypeCode.integer), }; }, .function => |f| b: { type_values.appendAssumeCapacity(@intFromBool(f.varargs)); type_values.appendAssumeCapacity(f.return_type); for (f.parameter_types) |parameter_type_index| { type_values.appendAssumeCapacity(parameter_type_index); } break :b .{ .code = @intFromEnum(TypeCode.function), .abbreviation = function_abbreviation, }; }, .metadata => .{ .code = @intFromEnum(TypeCode.metadata), }, .void => .{ .code = @intFromEnum(TypeCode.void), }, }; writer.emit_record(u64, emission_info.code, type_values.constSlice(), emission_info.abbreviation); type_values.resize(0) catch unreachable; } writer.exit_block(); const end = writer.buffer.length * 4; const expected = debug_main_bitcode[start..end]; const have = writer.get_byte_slice()[start..end]; std.debug.print("Start: {}\n", .{start}); std.testing.expectEqualSlices(u8, expected, have) catch unreachable; } const DummyAttribute = union(enum) { string: struct{ key: []const u8, value: []const u8, }, enumeration: AttributeKindCode, int: struct{ value: u64, key: AttributeKindCode, }, // TODO type: AttributeKindCode, }; const AttributeGroup = struct{ attributes: []const DummyAttribute, parameter_index: u32, }; const attribute_groups = [_]AttributeGroup{ .{ .parameter_index = 0xffff_ffff, .attributes = &.{ .{ .enumeration = .no_inline }, .{ .enumeration = .no_unwind }, .{ .enumeration = .optimize_none }, .{ .int = .{ .key = .uw_table, .value = 2, }, }, .{ .string = .{ .key = "frame-pointer", .value = "all", }, }, .{ .string = .{ .key = "min-legal-vector-width", .value = "0", }, }, .{ .string = .{ .key = "no-trapping-math", .value = "true", }, }, .{ .string = .{ .key = "stack-protector-buffer-size", .value = "8", }, }, .{ .string = .{ .key = "target-cpu", .value = "x86-64", }, }, .{ .string = .{ .key = "target-features", .value = "+cmov,+cx8,+fxsr,+mmx,+sse,+sse2,+x87", }, }, .{ .string = .{ .key = "tune-cpu", .value = "generic", }, }, }, }, .{ .parameter_index = 1, .attributes = &.{ .{ .enumeration = .noundef }, }, }, .{ .parameter_index = 2, .attributes = &.{ .{ .enumeration = .noundef }, }, }, .{ .parameter_index = 0xffff_ffff, .attributes = &.{ .{ .enumeration = .no_callback }, .{ .enumeration = .nofree }, .{ .enumeration = .nosync }, .{ .enumeration = .no_unwind }, .{ .enumeration = .speculatable }, .{ .enumeration = .willreturn }, .{ .int = .{ .key = .memory, .value = 0, }, }, }, }, }; fn write_attribute_group_table(writer: *Writer) void { if (attribute_groups.len > 0) { writer.enter_subblock(.parameter_attribute_group, 3); const start = writer.buffer.length * 4; var records = std.BoundedArray(u64, 4096){}; for (attribute_groups, 0..) |attribute_group, attribute_group_index| { std.debug.print("====\nWriting attribute group #{}...\n====\n", .{attribute_group_index}); defer std.debug.print("====\nEnded attribute group #{}...\n====\n", .{attribute_group_index}); records.appendAssumeCapacity(attribute_group_index + 1); records.appendAssumeCapacity(attribute_group.parameter_index); for (attribute_group.attributes) |attribute| { switch (attribute) { .enumeration => |e| { records.appendAssumeCapacity(0); records.appendAssumeCapacity(@intFromEnum(e)); }, .int => |i| { records.appendAssumeCapacity(1); records.appendAssumeCapacity(@intFromEnum(i.key)); records.appendAssumeCapacity(i.value); }, .string => |s| { records.appendAssumeCapacity(@as(u64, 3) + @intFromBool(s.value.len > 0)); for (s.key) |b| { records.appendAssumeCapacity(b); } records.appendAssumeCapacity(0); if (s.value.len > 0) { for (s.value) |b| { records.appendAssumeCapacity(b); } records.appendAssumeCapacity(0); } }, else => |t| @panic(@tagName(t)), } } writer.emit_record(u64, @intFromEnum(AttributeCode.group_entry), records.constSlice(), 0); records.resize(0) catch unreachable; } writer.exit_block(); const end = writer.buffer.length * 4; const expected = debug_main_bitcode[start..end]; const have = writer.get_byte_slice()[start..end]; std.debug.print("Start: {}\n", .{start}); std.testing.expectEqualSlices(u8, expected, have) catch unreachable; } } const AttributeList = struct{ attribute_groups: []const u32, }; const attribute_lists = [_]AttributeList{ .{ .attribute_groups = &.{1, 2, 3} }, .{ .attribute_groups = &.{4} }, }; fn write_attribute_table(writer: *Writer) void { if (attribute_groups.len > 0) { writer.enter_subblock(.parameter_attribute, 3); const start = writer.buffer.length * 4; var records = std.BoundedArray(u64, 4096){}; for (attribute_lists) |attribute_list| { for (attribute_list.attribute_groups) |attribute_group_index| { const attribute_group = attribute_groups[attribute_group_index - 1]; if (attribute_group.attributes.len > 0) { records.appendAssumeCapacity(attribute_group_index); } } writer.emit_record(u64, @intFromEnum(AttributeCode.entry), records.constSlice(), 0); records.resize(0) catch unreachable; } writer.exit_block(); const end = writer.buffer.length * 4; const expected = debug_main_bitcode[start..end]; const have = writer.get_byte_slice()[start..end]; std.debug.print("Start: {}\n", .{start}); std.testing.expectEqualSlices(u8, expected, have) catch unreachable; } } var foo: u32 = undefined; fn write_module_info(writer: *Writer) void { foo = writer.buffer.length * 4; const start = writer.buffer.length * 4; _ = start; // autofix const target_triple = "x86_64-unknown-linux-gnu"; writer.write_string_record(@intFromEnum(ModuleCode.triple), target_triple, // TODO in LLVM code 0); const data_layout = "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-i128:128-f80:128-n8:16:32:64-S128"; writer.write_string_record(@intFromEnum(ModuleCode.data_layout), data_layout, // TODO in LLVM code 0); // TODO: global inline assembly // const global_inline_assembly = ""; // write_string_record(@intFromEnum(ModuleCode.@"asm"), global_inline_assembly, // // TODO in LLVM code // 0); // // TODO: section names // TODO: global abbreviation var values = std.BoundedArray(u32, 64){}; { const source_filename = "main.c"; const source_string_encoding = get_string_encoding(source_filename); const abbreviation = writer.abbreviation_buffer.append(.{}); abbreviation.add_literal(@intFromEnum(ModuleCode.source_filename)); abbreviation.add_with_encoding(.{ .encoding = .array }); switch (source_string_encoding) { .char6 => abbreviation.add_with_encoding(.{ .encoding = .char6 }), .fixed7 => abbreviation.add_with_encoding(.{ .encoding = .fixed, .value = 7 }), .fixed8 => abbreviation.add_with_encoding(.{ .encoding = .fixed, .value = 8 }), } const filename_abbreviation = writer.emit_abbreviation(abbreviation); for (source_filename) |ch| { values.appendAssumeCapacity(ch); } writer.emit_record(u32, @intFromEnum(ModuleCode.source_filename), values.constSlice(), filename_abbreviation); values.resize(0) catch unreachable; } // TODO: global variables for (dummy_functions) |function| { std.debug.print("====\nFUNCTION START\n====\n", .{}); defer std.debug.print("====\nFUNCTION END\n====\n", .{}); // const loop_start = writer.buffer.length * 4; const offset = writer.strtab_content.length; std.debug.print("Offset: {}\n", .{offset}); writer.strtab_content.append_slice(function.name); values.appendAssumeCapacity(offset); values.appendAssumeCapacity(@intCast(function.name.len)); values.appendAssumeCapacity(function.type); values.appendAssumeCapacity(@intFromEnum(function.calling_convention)); values.appendAssumeCapacity(@intFromBool(function.is_declaration)); values.appendAssumeCapacity(@intFromEnum(function.linkage)); values.appendAssumeCapacity(function.attribute_list_id); values.appendAssumeCapacity(function.alignment); values.appendAssumeCapacity(function.section); values.appendAssumeCapacity(@intFromEnum(function.visibility)); values.appendAssumeCapacity(@intFromBool(function.gc)); values.appendAssumeCapacity(@intFromEnum(function.unnamed_address)); values.appendAssumeCapacity(@intFromEnum(function.dll_storage_class)); values.appendAssumeCapacity(function.prologued_data); values.appendAssumeCapacity(function.comdat); values.appendAssumeCapacity(function.prefix_data); values.appendAssumeCapacity(function.personality); values.appendAssumeCapacity(@intFromBool(function.dso_local)); values.appendAssumeCapacity(function.address_space); values.appendAssumeCapacity(function.partition_offset); values.appendAssumeCapacity(function.partition_len); assert(writer.current_codesize != 8); writer.emit_record(@TypeOf(values.constSlice()[0]), @intFromEnum(ModuleCode.function), values.constSlice(), 0); values.resize(0) catch unreachable; // const loop_end = writer.buffer.length * 4; // const expected = debug_main_bitcode[loop_start..loop_end]; // const have = writer.get_byte_slice()[loop_start..loop_end]; // std.debug.print("Start: {}\n", .{loop_start}); // std.testing.expectEqualSlices(u8, expected, have) catch unreachable; } // TODO: global aliases // TODO: global ifunc writer.write_value_symbol_table_forward_declaration(); // // const end = writer.buffer.length * 4; // const expected = debug_main_bitcode[start..end]; // const have = writer.get_byte_slice()[start..end]; // std.debug.print("Start: {}\n", .{start}); // std.testing.expectEqualSlices(u8, expected, have) catch unreachable; } const DummyFunction = struct{ name: []const u8, type: u32, calling_convention: LLVM.Value.Constant.Function.CallingConvention, is_declaration: bool, linkage: LLVM.BitcodeLinkage, attribute_list_id: u32, alignment: u32, section: u32, visibility: LLVM.GlobalVisibility, gc: bool = false, unnamed_address: LLVM.GlobalUnnamedAddress, prologued_data: u32, dll_storage_class: LLVM.DLLStorageClass, comdat: u32, prefix_data: u32, personality: u32, dso_local: bool, address_space: u32, partition_offset: u32, partition_len: u32, }; const dummy_functions = [_]DummyFunction{ .{ .name = "main", .type = 2, .calling_convention = .C, .is_declaration = false, .linkage = .external, .attribute_list_id = 1, .alignment = 0, .section = 0, .visibility = .default, .unnamed_address = .none, .prologued_data = 0, .dll_storage_class = .default, .comdat = 0, .prefix_data = 0, .personality = 0, .dso_local = true, .address_space = 0, .partition_offset = 4, .partition_len = 0, }, .{ .name = "llvm.dbg.declare", .type = 5, .calling_convention = .C, .is_declaration = true, .linkage = .external, .attribute_list_id = 2, .alignment = 0, .section = 0, .visibility = .default, .unnamed_address = .none, .prologued_data = 0, .dll_storage_class = .default, .comdat = 0, .prefix_data = 0, .personality = 0, .dso_local = false, .address_space = 0, .partition_offset = 4, .partition_len = 0, }, }; fn write_module_constants(writer: *Writer) void { std.debug.print("Module constants start\n", .{}); writer.write_constants(0, 15, true); // 0x81, 0x00, 0x00, 0x00, // 0x07, 0x00, 0x00, 0x00, // 0x32, 0x1e, 0x98, 0x10, // 0x19, 0x11, 0x4c, 0x90, // 0x8c, 0x09, 0x26, 0x47, // 0xc6, 0x04, 0x43, 0x4a, // 0x39, 0x94, 0x42, 0x11, // 0x94, 0x41, 0x09, 0x14, // 0x42, 0x41, 0x00, 0x00, } fn write_constants(writer: *Writer, first_value: u32, last_value: u32, is_global: bool) void { if (first_value == last_value) return; writer.enter_subblock(.constant, 4); const start = writer.buffer.length * 4; const abbreviations: struct { aggregate: u32 = 0, string8: u32 = 0, cstring7: u32 = 0, cstring6: u32 = 0, } = switch (is_global) { true => blk: { std.debug.print("===\nAggregate\n===\n", .{}); const aggregate_abbreviation = abv: { const abbreviation = writer.abbreviation_buffer.append(.{}); abbreviation.add_literal(@intFromEnum(ConstantCode.aggregate)); abbreviation.add_with_encoding(.{ .encoding = .array }); abbreviation.add_with_encoding(.{ .encoding = .fixed, .value = std.math.log2_int_ceil(u32, last_value + 1) }); break :abv writer.emit_abbreviation(abbreviation); }; std.debug.print("===\nstring8\n===\n", .{}); const string8_abbreviation = abv: { const abbreviation = writer.abbreviation_buffer.append(.{}); abbreviation.add_literal(@intFromEnum(ConstantCode.string)); abbreviation.add_with_encoding(.{ .encoding = .array }); abbreviation.add_with_encoding(.{ .encoding = .fixed, .value = 8 }); break :abv writer.emit_abbreviation(abbreviation); }; std.debug.print("===\ncstring7\n===\n", .{}); const cstring7_abbreviation = abv: { const abbreviation = writer.abbreviation_buffer.append(.{}); abbreviation.add_literal(@intFromEnum(ConstantCode.cstring)); abbreviation.add_with_encoding(.{ .encoding = .array }); abbreviation.add_with_encoding(.{ .encoding = .fixed, .value = 7 }); break :abv writer.emit_abbreviation(abbreviation); }; std.debug.print("===\ncstring6\n===\n", .{}); const cstring6_abbreviation = abv: { const abbreviation = writer.abbreviation_buffer.append(.{}); abbreviation.add_literal(@intFromEnum(ConstantCode.cstring)); abbreviation.add_with_encoding(.{ .encoding = .array }); abbreviation.add_with_encoding(.{ .encoding = .char6 }); break :abv writer.emit_abbreviation(abbreviation); }; std.debug.print("===\nEND\n===\n", .{}); break :blk .{ .aggregate = aggregate_abbreviation, .string8 = string8_abbreviation, .cstring7 = cstring7_abbreviation, .cstring6 = cstring6_abbreviation, }; }, false => .{}, }; _ = abbreviations; // autofix var records = std.BoundedArray(u64, 64){}; // Hardcoded: { std.debug.print("SETTYPE\n", .{}); defer std.debug.print("END SETTYPE\n", .{}); // Type 1: i32 records.appendAssumeCapacity(1); writer.emit_record(u64, @intFromEnum(ConstantCode.set_type), records.constSlice(), @intFromEnum(ConstantAbbreviationId.set_type)); records.resize(0) catch unreachable; } const Integer = struct{ value: u64, }; _ = Integer; // autofix const integers = [7]u64{7, 5, 2, 3, 1, 4, 8}; for (integers) |int| { const v = encode_signed_int(int); records.appendAssumeCapacity(v); const code = ConstantCode.integer; const abbreviation = ConstantAbbreviationId.integer; writer.emit_record(u64, @intFromEnum(code), records.constSlice(), @intFromEnum(abbreviation)); records.resize(0) catch unreachable; } writer.exit_block(); const end = writer.buffer.length * 4; const expected = debug_main_bitcode[start..end]; const have = writer.get_byte_slice()[start..end]; print_hex_slice(expected); std.debug.print("\n\nStart: {}\n", .{start}); std.testing.expectEqualSlices(u8, expected, have) catch unreachable; } fn encode_signed_int(value: u64) u64 { const sv: i64 = @bitCast(value); if (sv >= 0) { return value << 1; } else { return @bitCast((-sv << 1) | 1); } } fn write_module_metadata_kinds(writer: *Writer) void { writer.enter_subblock(.metadata_kind, 3); const start = writer.buffer.length * 4; const names = [40][]const u8{ "dbg", "tbaa", "prof", "fpmath", "range", "tbaa.struct", "invariant.load", "alias.scope", "noalias", "nontemporal", "llvm.mem.parallel_loop_access", "nonnull", "dereferenceable", "dereferenceable_or_null", "make.implicit", "unpredictable", "invariant.group", "align", "llvm.loop", "type", "section_prefix", "absolute_symbol", "associated", "callees", "irr_loop", "llvm.access.group", "callback", "llvm.preserve.access.index", "vcall_visibility", "noundef", "annotation", "nosanitize", "func_sanitize", "exclude", "memprof", "callsite", "kcfi_type", "pcsections", "DIAssignID", "coro.outside.frame", }; var records = std.BoundedArray(u64, 64){}; for (names, 0..) |name, name_index| { records.appendAssumeCapacity(name_index); for (name) |b| { records.appendAssumeCapacity(b); } writer.emit_record(u64, @intFromEnum(MetadataCode.kind), records.constSlice(), 0); records.resize(0) catch unreachable; } writer.exit_block(); const end = writer.buffer.length * 4; const expected = debug_main_bitcode[start..end]; const have = writer.get_byte_slice()[start..end]; print_hex_slice(expected); std.debug.print("\n\nStart: {}\n", .{start}); std.testing.expectEqualSlices(u8, expected, have) catch unreachable; } fn write_module_metadata(writer: *Writer) void { _ = writer; // autofix // TODO: } fn write_use_list_block(writer: *Writer, function: ?*u32) void { _ = function; // autofix _ = writer; // autofix // TODO: } fn write_operand_bundle_tags(writer: *Writer) void { _ = writer; // autofix } fn write_sync_scope_names(writer: *Writer) void { _ = writer; // autofix } fn write_value_symbol_table_forward_declaration(writer: *Writer) void { std.debug.print("Emitting abbreviation...\n", .{}); const abbreviation = writer.abbreviation_buffer.append(.{}); abbreviation.add_literal(@intFromEnum(ModuleCode.vst_offset)); abbreviation.add_with_encoding(.{ .encoding = .fixed, .value = 32 }); const vst_offset_abbreviation = writer.emit_abbreviation(abbreviation); std.debug.print("Emitting abbreviation record...\n", .{}); const values = [_]u64{@intFromEnum(ModuleCode.vst_offset), 0}; writer.emit_record_with_abbrev(u64, vst_offset_abbreviation, &values); std.debug.print("End emitting abbreviation record...\n", .{}); writer.vst_offset_placeholder = (writer.buffer.length * 32) - 32; } fn emit_record_with_abbrev(writer: *Writer, comptime T: type, abbreviation: u32, values: []const T) void { writer.emit_record_with_abbrev_impl(T, abbreviation, values, null, null); } fn switch_to_block_id(writer: *Writer, block_id: u32) void { if (block_id != writer.block_info_current_block_id) { const v = [1]u32{block_id}; writer.emit_record(u32, @intFromEnum(BlockInfoCode.set_bid), &v, 0); writer.block_info_current_block_id = block_id; } } fn get_block_info(writer: *Writer, block_id: u32) ?*BlockInfo { if (writer.block_info_records.length > 0) { const last = &writer.block_info_records.slice()[writer.block_info_records.length - 1]; if (last.id == block_id) { return last; } for (writer.block_info_records.slice()) |*block_info| { if (block_info.id == block_id) { return block_info; } } } return null; } fn get_or_create_block_info(writer: *Writer, block_id: u32) *BlockInfo { if (writer.get_block_info(block_id)) |block_info| return block_info else { const result = writer.block_info_records.append(.{ .id = block_id, }); return result; } } fn emit_block_info_abbrev(writer: *Writer, block_id: u32, abbreviation: *Abbreviation) u32 { writer.switch_to_block_id(block_id); writer.encode_abbreviation(abbreviation); const block_info = writer.get_or_create_block_info(block_id); _ = block_info.abbreviations.append(abbreviation); return block_info.abbreviations.length - 1 + @intFromEnum(FixedAbbreviationId.first_application_abbrev); } fn write_raw(writer: *Writer, value: u32) void { std.debug.print("[{}-{}] Flushing buffer 0x{x}\n", .{writer.buffer.length, writer.buffer.length * 4, value}); // if (writer.buffer.length == (712) / 4 - 1) @breakpoint(); // if (writer.buffer.length == (152 + 32) / 4) @breakpoint(); _ = writer.buffer.append(value); } pub fn append_bytes(writer: *Writer, bytes: []const u8) void { assert(bytes.len % 4 == 0); var slice: []const u32 = undefined; slice.ptr = @alignCast(@ptrCast(bytes.ptr)); slice.len = @divExact(bytes.len, @sizeOf(u32)); writer.buffer.append_slice(slice); } fn emit(writer: *Writer, value: u32, bit_count: u32) void { std.debug.print("ASK: [[32-B-IDX[0x{x}] 8-bit IDX[{}] - CVAL=0x{x} - CBIT={}]] Writing 0x{x} for {} bits\n", .{writer.buffer.length, writer.buffer.length * 4, writer.current_value, writer.current_bit, value, bit_count}); assert(bit_count > 0 and bit_count <= 32); assert(value & ~(~@as(u32, 0) >> @as(u5, @intCast(32 - bit_count))) == 0); const shifted = value << @as(u5, @intCast(writer.current_bit)); writer.current_value |= shifted; if (writer.current_bit + bit_count < 32) { writer.current_bit += bit_count; } else { writer.write_raw(writer.current_value); if (writer.current_bit != 0) { writer.current_value = value >> @as(u5, @intCast(32 - writer.current_bit)); } else { writer.current_value = 0; } writer.current_bit = (writer.current_bit + bit_count) & 31; } } fn flush(writer: *Writer) void { if (writer.current_bit != 0) { writer.write_raw(writer.current_value); writer.current_bit = 0; writer.current_value = 0; } } fn encode_abbreviation(writer: *Writer, abbreviation: *Abbreviation) void { writer.emit_code(@intFromEnum(FixedAbbreviationId.define_abbrev)); writer.emit_vbr(abbreviation.operands.length, 5); for (abbreviation.operands.const_slice()) |*operand| { writer.emit(@intFromBool(operand.is_literal), 1); if (operand.is_literal) { writer.emit_vbr64(operand.value, 8); } else { writer.emit(@intFromEnum(operand.encoding), 3); if (operand.get_encoding_data()) |encoding_data| { writer.emit_vbr64(encoding_data, 5); } } } } fn emit_abbreviation(writer: *Writer, abbreviation: *Abbreviation) u32 { writer.encode_abbreviation(abbreviation); _ = writer.current_abbreviations.append(abbreviation); return writer.current_abbreviations.length - 1 + @intFromEnum(FixedAbbreviationId.first_application_abbrev); } fn emit_abbreviated_literal(writer: *Writer, comptime T: type, operand: *Abbreviation.Op, value: T) void { _ = writer; // autofix assert(operand.is_literal); assert(value == operand.value); } fn write_identification_block(writer: *Writer) void { writer.enter_subblock(.identification, 5); { const abbreviation = writer.abbreviation_buffer.append(.{}); abbreviation.add_literal(@intFromEnum(IdentificationCode.string)); abbreviation.add_with_encoding(.{ .encoding = .array }); abbreviation.add_with_encoding(.{ .encoding = .char6 }); const string_abbreviation = writer.emit_abbreviation(abbreviation); writer.write_string_record(@intFromEnum(IdentificationCode.string), "LLVM17.0.6", string_abbreviation); } { const abbreviation = writer.abbreviation_buffer.append(.{}); abbreviation.add_literal(@intFromEnum(IdentificationCode.epoch)); abbreviation.add_with_encoding_advanced(.{ .encoding = .vbr, .value = 6, .is_literal = false, }); const epoch_abbreviation = writer.emit_abbreviation(abbreviation); const current_epoch = 0; const values = [1]u32{current_epoch}; writer.emit_record(u32, @intFromEnum(IdentificationCode.epoch), &values, epoch_abbreviation); writer.exit_block(); } 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, }; std.testing.expectEqualSlices(u8, &identification_block, writer.get_byte_slice()[4..]) catch unreachable; } fn exit_block(writer: *Writer) void { assert(writer.block_scope.length != 0); const last = &writer.block_scope.slice()[writer.block_scope.length - 1]; writer.emit_code(@intFromEnum(FixedAbbreviationId.end_block)); writer.flush(); const size32 = writer.buffer.length - last.start_size_index - 1; writer.buffer.slice()[last.start_size_index] = size32; std.debug.print("\n\n\n[EXIT BLOCK] Current code size: {}. Previous code size: {}. Swapping...\n\n\n", .{writer.current_codesize, last.previous_code_size}); writer.current_codesize = last.previous_code_size; writer.current_abbreviations = last.previous_abbreviations; writer.block_scope.length -= 1; } fn is_char6(ch: u8) bool { return (is_alphabetic(ch) or is_decimal_digit(ch)) or (ch == '.' or ch == '_'); } fn write_string_record(writer: *Writer, code: u32, string: []const u8, abbreviation_to_use: u32) void { var values = std.BoundedArray(u32, 128){}; var a = abbreviation_to_use; for (string) |ch| { if (a != 0 and !is_char6(ch)) { a = 0; } values.appendAssumeCapacity(ch); } writer.emit_record(u32, code, values.constSlice(), a); } fn emit_record(writer: *Writer, comptime T: type, code: u32, values: []const T, abbreviation: u32) void { if (abbreviation == 0) { const count: u32 = @intCast(values.len); writer.emit_code(@intFromEnum(FixedAbbreviationId.unabbrev_record)); writer.emit_vbr(code, 6); writer.emit_vbr(count, 6); for (values, 0..) |v, i| { std.debug.print("Value #{} at [{}]: 0x{x}\n", .{i, writer.buffer.length * 4, v}); writer.emit_vbr64(v, 6); } } else { writer.emit_record_with_abbrev_impl(T, abbreviation, values, null, code); } } fn emit_record_with_abbrev_impl(writer: *Writer, comptime T: type, abbreviation_int: u32, values: []const T, string: ?[]const u8, code: ?u32) void { const abbreviation_number = abbreviation_int - @intFromEnum(FixedAbbreviationId.first_application_abbrev); assert(abbreviation_number < writer.current_abbreviations.length); const abbreviation = writer.current_abbreviations.slice()[abbreviation_number]; writer.emit_code(abbreviation_int); const operand_count = abbreviation.operands.length; var operand_index: u32 = 0; if (code) |c| { assert(operand_count > 0); const operand = &abbreviation.operands.slice()[operand_index]; operand_index += 1; if (operand.is_literal) { writer.emit_abbreviated_literal(u32, operand, c); } else { unreachable; } } var record_index: u32 = 0; while (operand_index < operand_count) : (operand_index += 1) { const operand = &abbreviation.operands.slice()[operand_index]; if (operand.is_literal) { assert(record_index < values.len); writer.emit_abbreviated_literal(T, operand, values[record_index]); record_index += 1; } else if (operand.encoding == .array) { assert(operand_index + 2 == operand_count); operand_index += 1; const elt_enc = &abbreviation.operands.slice()[operand_index]; if (string) |s| { _ = s; // autofix unreachable; } else { writer.emit_vbr(@intCast(values.len - record_index), 6); while (record_index < values.len) : (record_index += 1) { writer.emit_abbreviated_field(T, elt_enc, values[record_index]); } } } else if (operand.encoding == .blob) { unreachable; } else { assert(record_index < values.len); writer.emit_abbreviated_field(T, operand, values[record_index]); record_index += 1; } } assert(record_index == values.len); } fn emit_abbreviated_field(writer: *Writer, comptime T: type, operand: *Abbreviation.Op, value: T) void { assert(!operand.is_literal); switch (operand.encoding) { else => unreachable, .fixed => { if (operand.get_encoding_data()) |v| { writer.emit(@intCast(value), @intCast(v)); } }, .vbr => { if (operand.get_encoding_data()) |v| { writer.emit_vbr64(value, @intCast(v)); } }, .char6 => { const ch6 = encode_char6(@intCast(value)); writer.emit(ch6, 6); }, } } fn encode_char6(ch: u8) u32 { if (is_lower(ch)) return ch - 'a'; if (is_upper(ch)) return ch - 'A' + 26; if (is_decimal_digit(ch)) return ch - '0' + 26 + 26; if (ch == '.') return 62; if (ch == '_') return 63; unreachable; } const StringEncoding = enum{ char6, fixed7, fixed8, }; fn get_string_encoding(string: []const u8) StringEncoding{ var char6 = true; for (string) |ch| { if (char6) { char6 = is_char6(ch); } if (ch & 128 != 0) { return .fixed8; } } return if (char6) .char6 else .fixed7; } fn enter_subblock(writer: *Writer, block_id: BlockId, code_length: u32) void { writer.emit_code(@intFromEnum(FixedAbbreviationId.enter_subblock)); writer.emit_vbr(@intFromEnum(block_id), width.block_id); writer.emit_vbr(code_length, width.code_length); writer.flush(); const block_size_index = writer.buffer.length; const old_code_size = writer.current_codesize; writer.write_raw(0); writer.current_codesize = code_length; const block = writer.block_scope.append(.{ .start_size_index = block_size_index, .previous_code_size = old_code_size, }); block.previous_abbreviations = writer.current_abbreviations; writer.current_abbreviations = .{}; // getBlockInfo if (writer.get_block_info(@intFromEnum(block_id))) |block_info| { writer.current_abbreviations.append_slice(block_info.abbreviations.const_slice()); } } fn emit_code(writer: *Writer, value: u32) void { writer.emit(value, writer.current_codesize); } fn emit_vbr(writer: *Writer, value: u32, bit_count: u32) void { std.debug.print("Emitting VBR{}: 0x{x}...\n", .{bit_count, value}); assert(bit_count <= 32); const shifter: u5 = @intCast(bit_count - 1); const threshold = @as(u32, 1) << shifter; var v = value; while (v >= threshold) : (v >>= shifter) { const value_to_emit = (v & (threshold - 1)) | threshold; writer.emit(value_to_emit, bit_count); } writer.emit(v, bit_count); } fn emit_vbr64(writer: *Writer, value: u64, bit_count: u32) void { std.debug.print("Emitting VBR{}: 0x{x}...\n", .{bit_count, value}); assert(bit_count <= 32); if (@as(u32, @truncate(value)) == value) { writer.emit_vbr(@truncate(value), bit_count); } else { const shifter: u5 = @intCast(bit_count - 1); const threshold = @as(u32, 1) << shifter; var v = value; while (v >= threshold) : (v >>= shifter) { const v32: u32 = @truncate(v); const value_to_emit = (v32 & (threshold - 1)) | threshold; writer.emit(value_to_emit, bit_count); } writer.emit(@truncate(v), bit_count); } } }; }; fn write_bitcode() void { var writer = Bitcode.Writer{}; if (false) { // const file = std.fs.cwd().readFileAlloc(std.heap.page_allocator, "/home/david/clang18.ll", 0xfffffffff) catch unreachable; // Bitcode.print_hex_slice(file); // writer.append_bytes(file); } else { writer.write(); } const context = LLVM.Context.create(); const module = context.parse_bitcode(writer.get_byte_slice()) orelse exit(1); _ = module; // autofix exit(0); } 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/main.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 BitcodeLinkage = enum(c_uint) { external = 0, appending = 2, internal = 3, external_weak = 7, common = 8, private = 9, available_external = 12, weak_any = 16, weak_odr = 17, link_once_any = 18, link_once_odr = 19, }; 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 GlobalVisibility = enum(u8) { default = 0, hidden = 1, protected = 2, }; pub const GlobalUnnamedAddress = enum(u8) { none = 0, local = 1, global = 2, }; pub const DLLStorageClass = enum(u8) { default = 0, import = 1, @"export" = 2, }; 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, /// Used on AMDGPUs to give the middle-end more control over argument /// placement. AMDGPU_CS_Chain = 104, /// Used on AMDGPUs to give the middle-end more control over argument /// placement. Preserves active lane values for input VGPRs. AMDGPU_CS_ChainPreserve = 105, /// 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, }; }; };