This commit is contained in:
David Gonzalez Martin 2025-04-29 06:29:32 -06:00
parent 0eee2a4ff3
commit f46763ee48
4 changed files with 295 additions and 45 deletions

View File

@ -396,7 +396,7 @@ pub const Type = struct {
};
}
fn resolve(ty: *Type, module: *Module) void {
fn resolve_abi(ty: *Type, module: *Module) void {
if (ty.llvm.abi == null) {
const abi_type = switch (ty.bb) {
.void, .noreturn => module.llvm.void_type,
@ -439,7 +439,11 @@ pub const Type = struct {
else => @trap(),
};
ty.llvm.abi = abi_type;
}
}
fn resolve_memory(ty: *Type, module: *Module) void {
if (ty.llvm.memory == null) {
const memory_type = switch (ty.bb) {
.void,
.noreturn,
@ -447,7 +451,7 @@ pub const Type = struct {
.array,
.structure,
.@"union",
=> abi_type,
=> ty.llvm.abi.?,
.integer => module.llvm.context.get_integer_type(@intCast(ty.get_byte_size() * 8)).to_type(),
.enumerator => |enumerator| enumerator.backing_type.llvm.memory.?,
.bits => |bits| bits.backing_type.llvm.memory.?, // TODO: see assert below
@ -456,8 +460,12 @@ pub const Type = struct {
};
ty.llvm.memory = memory_type;
if (ty.bb == .bits) assert(ty.llvm.memory == ty.llvm.abi);
}
}
if (module.has_debug_info) {
fn resolve_debug(ty: *Type, module: *Module) void {
if (module.has_debug_info) {
if (ty.llvm.debug == null) {
const debug_type = switch (ty.bb) {
.void, .noreturn => module.llvm.di_builder.create_basic_type(ty.name, 0, .void, .{ .no_return = ty.bb == .noreturn }),
.integer => |integer| module.llvm.di_builder.create_basic_type(ty.name, @max(lib.next_power_of_two(integer.bit_count), 8), switch (integer.bit_count) {
@ -467,12 +475,16 @@ pub const Type = struct {
false => .unsigned,
},
}, .{}),
.pointer => |pointer| b: {
pointer.type.resolve(module);
break :b module.llvm.di_builder.create_pointer_type(pointer.type.llvm.debug.?, 64, 64, 0, ty.name).to_type();
.pointer => |pointer| p: {
pointer.type.resolve_debug(module);
break :p if (ty.llvm.debug) |d| d else b: {
const pointer_type = module.llvm.di_builder.create_pointer_type(pointer.type.llvm.debug.?, 64, 64, 0, ty.name).to_type();
break :b pointer_type;
};
},
.array => |array| module.llvm.di_builder.create_array_type(array.element_count, 0, array.element_type.llvm.debug.?, &.{}).to_type(),
.enumerator => |enumerator| blk: {
enumerator.backing_type.resolve_debug(module);
var enumerator_buffer: [64]*llvm.DI.Enumerator = undefined;
const enumerators = enumerator_buffer[0..enumerator.fields.len];
for (enumerators, enumerator.fields) |*enumerator_pointer, *field| {
@ -483,21 +495,21 @@ pub const Type = struct {
break :blk enumeration_type.to_type();
},
.structure => |structure| blk: {
const struct_type = module.llvm.di_builder.create_replaceable_composite_type(module.llvm.debug_tag, ty.name, module.scope.llvm.?, module.llvm.file, structure.line);
ty.llvm.debug = struct_type.to_type();
const fwd = module.llvm.di_builder.create_replaceable_composite_type(module.llvm.debug_tag, ty.name, module.scope.llvm.?, module.llvm.file, structure.line);
ty.llvm.debug = fwd.to_type();
module.llvm.debug_tag += 1;
var llvm_debug_member_type_buffer: [64]*llvm.DI.Type.Derived = undefined;
const llvm_debug_member_types = llvm_debug_member_type_buffer[0..structure.fields.len];
for (structure.fields, llvm_debug_member_types) |field, *llvm_debug_member_type| {
field.type.resolve(module);
field.type.resolve_debug(module);
const member_type = module.llvm.di_builder.create_member_type(module.scope.llvm.?, field.name, module.llvm.file, field.line, field.type.get_byte_size() * 8, @intCast(field.type.get_byte_alignment() * 8), field.bit_offset, .{}, field.type.llvm.debug.?);
llvm_debug_member_type.* = member_type;
}
const debug_struct_type = module.llvm.di_builder.create_struct_type(module.scope.llvm.?, ty.name, module.llvm.file, structure.line, structure.bit_size, @intCast(structure.bit_alignment), .{}, llvm_debug_member_types);
const forward_declared: *llvm.DI.Type.Composite = @ptrCast(ty.llvm.debug);
const forward_declared: *llvm.DI.Type.Composite = @ptrCast(fwd);
forward_declared.replace_all_uses_with(debug_struct_type);
break :blk debug_struct_type.to_type();
},
@ -512,6 +524,7 @@ pub const Type = struct {
break :blk struct_type.to_type();
},
.alias => |alias| blk: {
alias.type.resolve_debug(module);
const typedef = module.llvm.di_builder.create_typedef(alias.type.llvm.debug.?, ty.name, module.llvm.file, alias.line, alias.scope.llvm.?, 0);
break :blk typedef.to_type();
},
@ -524,7 +537,7 @@ pub const Type = struct {
const llvm_debug_member_types = llvm_debug_member_type_buffer[0..union_type.fields.len];
for (union_type.fields, llvm_debug_member_types) |field, *llvm_debug_member_type| {
field.type.resolve(module);
field.type.resolve_debug(module);
const member_type = module.llvm.di_builder.create_member_type(module.scope.llvm.?, field.name, module.llvm.file, field.line, field.type.get_byte_size() * 8, @intCast(field.type.get_byte_alignment() * 8), 0, .{}, field.type.llvm.debug.?);
llvm_debug_member_type.* = member_type;
}
@ -536,11 +549,18 @@ pub const Type = struct {
},
else => @trap(),
};
ty.llvm.debug = debug_type;
}
}
}
fn resolve(ty: *Type, module: *Module) void {
ty.resolve_abi(module);
ty.resolve_memory(module);
ty.resolve_debug(module);
}
const Bits = struct {
fields: []const Struct.Field,
backing_type: *Type,
@ -1569,7 +1589,7 @@ pub const Module = struct {
pub fn get_pointer_type(module: *Module, pointer: Pointer) *Type {
const p = Type.Pointer{
.type = pointer.type,
.alignment = if (pointer.alignment) |a| a else if (pointer.type.bb != .unresolved) pointer.type.get_byte_alignment() else null,
.alignment = if (pointer.alignment) |a| a else if (pointer.type.bb != .unresolved and pointer.type.bb != .forward_declaration) pointer.type.get_byte_alignment() else null,
};
const all_types = module.types.get_slice();
const pointer_type = for (module.pointer_types.get_slice()) |pointer_type_index| {
@ -5193,29 +5213,40 @@ pub const Module = struct {
if (src.type.?.bb != .pointer) {
assert(src.kind == .right);
assert(src.type.?.bb == .structure);
const ty = src.type.?;
src.type = null;
src.kind = .left;
module.analyze_value_type(src, .{});
module.analyze_value_type(src, .{ .type = ty });
}
module.emit_value(src, .memory);
assert(src.type.?.bb == .pointer);
const source_type = src.type.?.bb.pointer.type;
assert(source_type == argument_abi.semantic_type);
const destination_type = argument_abi.get_coerce_to_type();
const load = module.create_coerced_load(src.llvm.?, source_type, destination_type);
const is_cmse_ns_call = false;
if (is_cmse_ns_call) {
@trap();
}
const maybe_undef = false;
if (maybe_undef) {
@trap();
}
if (src.type.?.bb == .pointer) {
module.emit_value(src, .memory);
llvm_abi_argument_value_buffer[abi_argument_count] = load;
abi_argument_count += 1;
const source_type = src.type.?.bb.pointer.type;
assert(source_type == argument_abi.semantic_type);
const load = module.create_coerced_load(src.llvm.?, source_type, destination_type);
const is_cmse_ns_call = false;
if (is_cmse_ns_call) {
@trap();
}
const maybe_undef = false;
if (maybe_undef) {
@trap();
}
llvm_abi_argument_value_buffer[abi_argument_count] = load;
abi_argument_count += 1;
} else switch (src.bb) {
.zero => {
const zero = destination_type.llvm.abi.?.get_zero();
llvm_abi_argument_value_buffer[abi_argument_count] = zero.to_value();
abi_argument_count += 1;
},
else => @trap(),
}
}
}
},
@ -5866,18 +5897,18 @@ pub const Module = struct {
}
}
if (lib.optimization_mode == .Debug) {
const verify_result = llvm_function_value.verify();
if (!verify_result.success) {
lib.print_string(module.llvm.module.to_string());
lib.print_string("============================\n");
lib.print_string(llvm_function_value.to_string());
lib.print_string("============================\n");
lib.print_string(verify_result.error_message orelse unreachable);
lib.print_string("\n============================\n");
lib.os.abort();
}
}
// if (lib.optimization_mode == .Debug) {
// const verify_result = llvm_function_value.verify();
// if (!verify_result.success) {
// lib.print_string(module.llvm.module.to_string());
// lib.print_string("============================\n");
// lib.print_string(llvm_function_value.to_string());
// lib.print_string("============================\n");
// lib.print_string(verify_result.error_message orelse unreachable);
// lib.print_string("\n============================\n");
// lib.os.abort();
// }
// }
},
.global => {
module.analyze(global.variable.initial_value, .{ .type = global.variable.type }, .memory);
@ -5917,6 +5948,26 @@ pub const Module = struct {
}
}
if (false) {
const fwd = module.llvm.di_builder.create_replaceable_composite_type(0, "S", module.scope.llvm.?, module.llvm.file, 0);
var types: [1]*llvm.DI.Type.Derived = undefined;
const pointer_type = module.llvm.di_builder.create_pointer_type(fwd.to_type(), 64, 64, 0, "&S");
types[0] = module.llvm.di_builder.create_member_type(module.scope.llvm.?, "self", module.llvm.file, 0, 64, 64, 0, .{}, pointer_type.to_type());
const debug_struct_type = module.llvm.di_builder.create_struct_type(module.scope.llvm.?, "S", module.llvm.file, 0, 64, 64, .{}, &types);
fwd.replace_all_uses_with(debug_struct_type);
const struct_type = module.llvm.context.get_struct_type(&.{module.llvm.pointer_type});
const llvm_function_type = llvm.Type.Function.get(struct_type.to_type(), &.{}, false);
const llvm_function_value = module.llvm.module.create_function(.{
.name = "foo",
.linkage = .ExternalLinkage,
.type = llvm_function_type,
});
const subroutine_type = module.llvm.di_builder.create_subroutine_type(module.llvm.file, &.{debug_struct_type.to_type()}, .{});
const subprogram = module.llvm.di_builder.create_function(module.scope.llvm.?, "foo", "foo", module.llvm.file, 0, subroutine_type, false, false, 0, .{}, false);
llvm_function_value.set_subprogram(subprogram);
}
if (module.has_debug_info) {
module.llvm.di_builder.finalize();
}
@ -8667,8 +8718,10 @@ pub const Module = struct {
module.llvm.builder.clear_insertion_position();
}
if (!all_blocks_terminated) {
module.llvm.builder.position_at_end(exit_block);
module.llvm.builder.position_at_end(exit_block);
if (all_blocks_terminated) {
_ = module.llvm.builder.create_unreachable();
module.llvm.builder.clear_insertion_position();
}
},
else => @trap(),
@ -9366,7 +9419,6 @@ pub const Module = struct {
value: *llvm.Value,
type: *Type,
} {
_ = module;
var source_pointer = source_value;
var source_type = source_ty;
assert(source_type.bb == .structure and source_type.bb.structure.fields.len > 0);
@ -9376,7 +9428,15 @@ pub const Module = struct {
source_pointer = switch (first_field_size < destination_size and first_field_size < source_size) {
true => source_pointer,
false => @trap(), // TODO: make sure `source_type` is also updated here
false => b: {
source_pointer = module.llvm.builder.create_struct_gep(source_type.llvm.memory.?.to_struct(), source_pointer, 0);
source_type = module.get_pointer_type(.{ .type = first_field_type });
if (first_field_type.bb == .structure) {
@trap();
} else {
break :b source_pointer;
}
},
};
return .{ .value = source_pointer, .type = source_type };

View File

@ -586,6 +586,24 @@ CompileOptions = struct
silent: u1,
}
ScopeKind = enum
{
global,
function,
local,
for_each,
macro_declaration,
macro_instantiation_function,
}
Scope = struct
{
parent: &Scope,
line: u32,
column: u32,
kind: ScopeKind,
}
TypeId = enum
{
void,
@ -630,11 +648,13 @@ Module = struct
arena: &Arena,
base_type_allocation: &Type,
void_value: &Value,
// Parser data
// Parser data start
content: []u8,
offset: u64,
line_offset: u64,
line_character_offset: u64,
// Parser data end
scope: Scope,
}
module_integer_type = fn (module: &Module, integer: TypeInteger) &Type
@ -655,6 +675,13 @@ module_noreturn_type = fn (module: &Module) &Type
return module_void_type(module) + 1;
}
left_bracket: u8 = '[';
right_bracket: u8 = '[';
left_parenthesis: u8 = '(';
right_parenthesis: u8 = ')';
left_brace: u8 = '{';
right_brace: u8 = '}';
is_space = fn (ch: u8) u1
{
return ch == ' ' or ch == '\n' or ch == '\t' or ch == '\r';
@ -817,8 +844,159 @@ parse_identifier = fn (module: &Module) []u8
return result;
}
parse_type = fn (module: &Module) &Type
{
}
ValueBuilder = struct
{
foo: u32,
}
parse_value = fn (module: &Module, scope: &Scope, v: ValueBuilder) &Value
{
}
GlobalKeyword = enum
{
export,
extern,
}
GlobalKind = enum
{
bits,
enum,
fn,
macro,
struct,
typealias,
union,
}
parse = fn (module: &Module) void
{
while (1)
{
skip_space(module);
if (module.offset == module.content.length)
{
break;
}
>is_export: u1 = 0;
>is_extern: u1 = 0;
>global_line = get_line(module);
>global_column = get_column(module);
if (consume_character_if_match(module, left_bracket))
{
while (module.offset < module.content.length)
{
>global_keyword_string = parse_identifier(module);
>global_keyword_s2e = #string_to_enum(GlobalKeyword, global_keyword_string);
if (!global_keyword_s2e.is_valid)
{
report_error();
}
>global_keyword = global_keyword_s2e.enum_value;
switch (global_keyword)
{
.export => { is_export = 1; }
.extern => { is_extern = 1; }
}
if (consume_character_if_match(module, right_bracket))
{
break;
}
report_error();
}
skip_space(module);
}
>global_name = parse_identifier(module);
// TODO: check if the name is repeated in global namespace
skip_space(module);
>global_type: &Type = zero;
if (consume_character_if_match(module, ':'))
{
skip_space(module);
global_type = parse_type(module);
skip_space(module);
}
expect_character(module, '=');
skip_space(module);
>has_global_keyword: u1 = 0;
if (is_identifier_start(module.content[module.offset]))
{
>identifier_offset = module.offset;
>global_string = parse_identifier(module);
skip_space(module);
>global_kind_s2e = #string_to_enum(GlobalKind, global_string);
if (global_kind_s2e.is_valid)
{
>global_kind = global_kind_s2e.enum_value;
switch (global_kind)
{
.bits => {
#trap();
},
.enum => {
#trap();
},
.fn => {
#trap();
},
.macro => {
#trap();
},
.struct => {
#trap();
},
.typealias => {
#trap();
},
.union => {
#trap();
},
}
}
else
{
module.offset = identifier_offset;
}
}
if (!has_global_keyword)
{
>v = parse_value(module, &module.scope, zero);
skip_space(module);
expect_character(module, ';');
#trap();
}
}
}
emit = fn (module: &Module) void

View File

@ -332,4 +332,5 @@ const names = &[_][]const u8{
"generic_pointer_macro",
"break_continue",
"noreturn_macro",
"self_referential_struct",
};

View File

@ -0,0 +1,11 @@
S = struct
{
self: &S,
}
[export] main = fn [cc(c)] () s32
{
>s: S = zero;
s.self = &s;
return 0;
}