This commit is contained in:
David Gonzalez Martin 2025-04-29 06:29:32 -06:00
parent 0eee2a4ff3
commit 07c2ea7da0
5 changed files with 742 additions and 293 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) { if (ty.llvm.abi == null) {
const abi_type = switch (ty.bb) { const abi_type = switch (ty.bb) {
.void, .noreturn => module.llvm.void_type, .void, .noreturn => module.llvm.void_type,
@ -439,7 +439,11 @@ pub const Type = struct {
else => @trap(), else => @trap(),
}; };
ty.llvm.abi = abi_type; ty.llvm.abi = abi_type;
}
}
fn resolve_memory(ty: *Type, module: *Module) void {
if (ty.llvm.memory == null) {
const memory_type = switch (ty.bb) { const memory_type = switch (ty.bb) {
.void, .void,
.noreturn, .noreturn,
@ -447,7 +451,7 @@ pub const Type = struct {
.array, .array,
.structure, .structure,
.@"union", .@"union",
=> abi_type, => ty.llvm.abi.?,
.integer => module.llvm.context.get_integer_type(@intCast(ty.get_byte_size() * 8)).to_type(), .integer => module.llvm.context.get_integer_type(@intCast(ty.get_byte_size() * 8)).to_type(),
.enumerator => |enumerator| enumerator.backing_type.llvm.memory.?, .enumerator => |enumerator| enumerator.backing_type.llvm.memory.?,
.bits => |bits| bits.backing_type.llvm.memory.?, // TODO: see assert below .bits => |bits| bits.backing_type.llvm.memory.?, // TODO: see assert below
@ -456,8 +460,12 @@ pub const Type = struct {
}; };
ty.llvm.memory = memory_type; ty.llvm.memory = memory_type;
if (ty.bb == .bits) assert(ty.llvm.memory == ty.llvm.abi); if (ty.bb == .bits) assert(ty.llvm.memory == ty.llvm.abi);
}
}
fn resolve_debug(ty: *Type, module: *Module) void {
if (module.has_debug_info) { if (module.has_debug_info) {
if (ty.llvm.debug == null) {
const debug_type = switch (ty.bb) { const debug_type = switch (ty.bb) {
.void, .noreturn => module.llvm.di_builder.create_basic_type(ty.name, 0, .void, .{ .no_return = ty.bb == .noreturn }), .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) { .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, false => .unsigned,
}, },
}, .{}), }, .{}),
.pointer => |pointer| b: { .pointer => |pointer| p: {
pointer.type.resolve(module); pointer.type.resolve_debug(module);
break :b module.llvm.di_builder.create_pointer_type(pointer.type.llvm.debug.?, 64, 64, 0, ty.name).to_type(); 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(), .array => |array| module.llvm.di_builder.create_array_type(array.element_count, 0, array.element_type.llvm.debug.?, &.{}).to_type(),
.enumerator => |enumerator| blk: { .enumerator => |enumerator| blk: {
enumerator.backing_type.resolve_debug(module);
var enumerator_buffer: [64]*llvm.DI.Enumerator = undefined; var enumerator_buffer: [64]*llvm.DI.Enumerator = undefined;
const enumerators = enumerator_buffer[0..enumerator.fields.len]; const enumerators = enumerator_buffer[0..enumerator.fields.len];
for (enumerators, enumerator.fields) |*enumerator_pointer, *field| { for (enumerators, enumerator.fields) |*enumerator_pointer, *field| {
@ -483,21 +495,21 @@ pub const Type = struct {
break :blk enumeration_type.to_type(); break :blk enumeration_type.to_type();
}, },
.structure => |structure| blk: { .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); 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 = struct_type.to_type(); ty.llvm.debug = fwd.to_type();
module.llvm.debug_tag += 1; module.llvm.debug_tag += 1;
var llvm_debug_member_type_buffer: [64]*llvm.DI.Type.Derived = undefined; 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]; 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| { 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.?); 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; 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 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); forward_declared.replace_all_uses_with(debug_struct_type);
break :blk debug_struct_type.to_type(); break :blk debug_struct_type.to_type();
}, },
@ -512,6 +524,7 @@ pub const Type = struct {
break :blk struct_type.to_type(); break :blk struct_type.to_type();
}, },
.alias => |alias| blk: { .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); 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(); 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]; 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| { 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.?); 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; llvm_debug_member_type.* = member_type;
} }
@ -536,11 +549,18 @@ pub const Type = struct {
}, },
else => @trap(), else => @trap(),
}; };
ty.llvm.debug = debug_type; 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 { const Bits = struct {
fields: []const Struct.Field, fields: []const Struct.Field,
backing_type: *Type, backing_type: *Type,
@ -555,15 +575,11 @@ pub const Type = struct {
pub const Pointer = struct { pub const Pointer = struct {
type: *Type, type: *Type,
alignment: ?u32,
pub fn get_alignment(p: *Pointer) u32 { pub fn get_alignment(p: *const Pointer) u32 {
if (p.alignment) |a| return a else {
const type_alignment = p.type.get_byte_alignment(); const type_alignment = p.type.get_byte_alignment();
p.alignment = type_alignment;
return type_alignment; return type_alignment;
} }
}
}; };
pub const Function = struct { pub const Function = struct {
@ -1271,6 +1287,26 @@ pub const Module = struct {
has_debug_info: bool, has_debug_info: bool,
silent: bool, silent: bool,
const Checkpoint = struct {
offset: u64,
line_offset: u64,
line_character_offset: u64,
};
pub fn get_checkpoint(module: *Module) Checkpoint {
return .{
.offset = module.offset,
.line_offset = module.line_offset,
.line_character_offset = module.line_character_offset,
};
}
pub fn set_checkpoint(module: *Module, checkpoint: Checkpoint) void {
module.offset = checkpoint.offset;
module.line_offset = checkpoint.line_offset;
module.line_character_offset = checkpoint.line_character_offset;
}
const LLVM = struct { const LLVM = struct {
context: *llvm.Context, context: *llvm.Context,
module: *llvm.Module, module: *llvm.Module,
@ -1563,19 +1599,17 @@ pub const Module = struct {
const Pointer = struct { const Pointer = struct {
type: *Type, type: *Type,
alignment: ?u32 = null,
}; };
pub fn get_pointer_type(module: *Module, pointer: Pointer) *Type { pub fn get_pointer_type(module: *Module, pointer: Pointer) *Type {
const p = Type.Pointer{ const p = Type.Pointer{
.type = pointer.type, .type = pointer.type,
.alignment = if (pointer.alignment) |a| a else if (pointer.type.bb != .unresolved) pointer.type.get_byte_alignment() else null,
}; };
const all_types = module.types.get_slice(); const all_types = module.types.get_slice();
const pointer_type = for (module.pointer_types.get_slice()) |pointer_type_index| { const pointer_type = for (module.pointer_types.get_slice()) |pointer_type_index| {
const ty = &all_types[pointer_type_index]; const ty = &all_types[pointer_type_index];
const pointer_type = &all_types[pointer_type_index].bb.pointer; const pointer_type = &all_types[pointer_type_index].bb.pointer;
if (pointer_type.type == p.type and pointer_type.alignment == p.alignment) { if (pointer_type.type == p.type) {
break ty; break ty;
} }
} else blk: { } else blk: {
@ -1646,13 +1680,13 @@ pub const Module = struct {
}, },
false => { false => {
var length_inferred = false; var length_inferred = false;
const offset = module.offset; const checkpoint = module.get_checkpoint();
if (module.consume_character_if_match('_')) { if (module.consume_character_if_match('_')) {
module.skip_space(); module.skip_space();
if (module.consume_character_if_match(']')) { if (module.consume_character_if_match(']')) {
length_inferred = true; length_inferred = true;
} else { } else {
module.offset = offset; module.set_checkpoint(checkpoint);
} }
} }
@ -1736,11 +1770,9 @@ pub const Module = struct {
const Slice = struct { const Slice = struct {
type: *Type, type: *Type,
alignment: ?u32 = null,
}; };
pub fn get_slice_type(module: *Module, slice: Slice) *Type { pub fn get_slice_type(module: *Module, slice: Slice) *Type {
const alignment = if (slice.alignment) |a| a else slice.type.get_byte_alignment();
const all_types = module.types.get_slice(); const all_types = module.types.get_slice();
for (module.slice_types.get_slice()) |slice_type_index| { for (module.slice_types.get_slice()) |slice_type_index| {
@ -1749,13 +1781,12 @@ pub const Module = struct {
assert(struct_type.is_slice); assert(struct_type.is_slice);
assert(struct_type.fields.len == 2); assert(struct_type.fields.len == 2);
const pointer_type = struct_type.fields[0].type; const pointer_type = struct_type.fields[0].type;
if (pointer_type.bb.pointer.type == slice.type and pointer_type.bb.pointer.alignment == alignment) { if (pointer_type.bb.pointer.type == slice.type) {
return ty; return ty;
} }
} else { } else {
const pointer_type = module.get_pointer_type(.{ const pointer_type = module.get_pointer_type(.{
.type = slice.type, .type = slice.type,
.alignment = slice.alignment,
}); });
const length_type = module.integer_type(64, false); const length_type = module.integer_type(64, false);
@ -1853,17 +1884,46 @@ pub const Module = struct {
fn skip_space(noalias module: *Module) void { fn skip_space(noalias module: *Module) void {
while (true) { while (true) {
const offset = module.offset; const offset = module.offset;
while (module.offset < module.content.len and is_space(module.content[module.offset])) {
module.line_offset += @intFromBool(module.content[module.offset] == '\n'); while (true) {
module.line_character_offset = if (module.content[module.offset] == '\n') module.offset else module.line_character_offset; if (module.offset == module.content.len) {
break;
}
assert(module.offset < module.content.len);
const ch = module.content[module.offset];
const is_space_ch = is_space(ch);
if (!is_space_ch) {
break;
}
module.line_offset += @intFromBool(ch == '\n');
module.line_character_offset = if (ch == '\n') module.offset else module.line_character_offset;
module.offset += 1; module.offset += 1;
} }
if (module.offset + 1 < module.content.len) { if (module.offset + 1 < module.content.len) {
const i = module.offset; const i = module.offset;
const is_comment = module.content[i] == '/' and module.content[i + 1] == '/'; const first_ch = module.content[i];
const second_ch = module.content[i + 1];
const is_comment = first_ch == '/' and second_ch == '/';
if (is_comment) { if (is_comment) {
while (module.offset < module.content.len and module.content[module.offset] != '\n') { while (true) {
if (module.offset == module.content.len) {
break;
}
assert(module.offset < module.content.len);
const ch = module.content[module.offset];
if (ch == '\n') {
break;
}
module.offset += 1; module.offset += 1;
} }
@ -2537,7 +2597,7 @@ pub const Module = struct {
var result = value_builder.left; var result = value_builder.left;
const precedence = value_builder.precedence; const precedence = value_builder.precedence;
while (true) { while (true) {
const checkpoint = module.offset; const checkpoint = module.get_checkpoint();
const token = module.tokenize(); const token = module.tokenize();
const token_rule = &rules[@intFromEnum(token)]; const token_rule = &rules[@intFromEnum(token)];
const token_precedence: Precedence = switch (token_rule.precedence) { const token_precedence: Precedence = switch (token_rule.precedence) {
@ -2548,7 +2608,7 @@ pub const Module = struct {
else => |p| p, else => |p| p,
}; };
if (@intFromEnum(precedence) > @intFromEnum(token_precedence)) { if (@intFromEnum(precedence) > @intFromEnum(token_precedence)) {
module.offset = checkpoint; module.set_checkpoint(checkpoint);
break; break;
} }
@ -2562,12 +2622,15 @@ pub const Module = struct {
} }
fn parse_statement(module: *Module, scope: *Scope) *Statement { fn parse_statement(module: *Module, scope: *Scope) *Statement {
var require_semicolon = true;
const statement_line = module.get_line(); const statement_line = module.get_line();
const statement_column = module.get_column(); const statement_column = module.get_column();
const statement_start_character = module.content[module.offset];
const statement = module.statements.add(); const statement = module.statements.add();
var require_semicolon = true;
const statement_start_character = module.content[module.offset];
statement.* = .{ statement.* = .{
.bb = switch (statement_start_character) { .bb = switch (statement_start_character) {
'>' => blk: { '>' => blk: {
@ -2610,6 +2673,7 @@ pub const Module = struct {
.expression = module.parse_value(scope, .{}), .expression = module.parse_value(scope, .{}),
}, },
'A'...'Z', 'a'...'z' => blk: { 'A'...'Z', 'a'...'z' => blk: {
const checkpoint = module.get_checkpoint();
const statement_start_identifier = module.parse_identifier(); const statement_start_identifier = module.parse_identifier();
if (lib.string.to_enum(StatementStartKeyword, statement_start_identifier)) |statement_start_keyword| switch (statement_start_keyword) { if (lib.string.to_enum(StatementStartKeyword, statement_start_identifier)) |statement_start_keyword| switch (statement_start_keyword) {
@ -2636,10 +2700,11 @@ pub const Module = struct {
var is_else = false; var is_else = false;
if (is_identifier_start_ch(module.content[module.offset])) { if (is_identifier_start_ch(module.content[module.offset])) {
const else_checkpoint = module.get_checkpoint();
const identifier = module.parse_identifier(); const identifier = module.parse_identifier();
is_else = lib.string.equal(identifier, "else"); is_else = lib.string.equal(identifier, "else");
if (!is_else) { if (!is_else) {
module.offset -= identifier.len; module.set_checkpoint(else_checkpoint);
} else { } else {
module.skip_space(); module.skip_space();
} }
@ -2772,10 +2837,7 @@ pub const Module = struct {
const token = module.tokenize(); const token = module.tokenize();
const kind: Statement.ForEach.Kind = switch (token) { const kind: Statement.ForEach.Kind = switch (token) {
.@")" => b: { .@")" => .slice,
module.offset += 1;
break :b .slice;
},
.@".." => b: { .@".." => b: {
if (left_value_count != 1) { if (left_value_count != 1) {
module.report_error(); module.report_error();
@ -2794,28 +2856,6 @@ pub const Module = struct {
}; };
statement.bb.for_each.kind = kind; statement.bb.for_each.kind = kind;
module.skip_space();
// if (!module.consume_character_if_match(',')) {
// module.expect_character(right_parenthesis);
// @trap();
// }
//
// while (true) {
// module.skip_space();
//
// right_value_buffer[right_value_count] = module.parse_value(scope, .{
// .kind = .left,
// });
// right_value_count += 1;
//
// module.skip_space();
//
// if (!module.consume_character_if_match(',')) {
// module.expect_character(right_parenthesis);
// break;
// }
// }
if (kind == .slice and left_value_count != right_value_count) { if (kind == .slice and left_value_count != right_value_count) {
module.report_error(); module.report_error();
} }
@ -2831,6 +2871,8 @@ pub const Module = struct {
statement.bb.for_each.left_values = left_values; statement.bb.for_each.left_values = left_values;
statement.bb.for_each.right_values = right_values; statement.bb.for_each.right_values = right_values;
module.skip_space();
const predicate = module.parse_statement(&statement.bb.for_each.scope); const predicate = module.parse_statement(&statement.bb.for_each.scope);
statement.bb.for_each.predicate = predicate; statement.bb.for_each.predicate = predicate;
@ -2862,10 +2904,11 @@ pub const Module = struct {
const is_else = is_else_blk: { const is_else = is_else_blk: {
var is_else = false; var is_else = false;
if (is_identifier_start_ch(module.content[module.offset])) { if (is_identifier_start_ch(module.content[module.offset])) {
const else_checkpoint = module.get_checkpoint();
const i = module.parse_identifier(); const i = module.parse_identifier();
is_else = lib.string.equal(i, "else"); is_else = lib.string.equal(i, "else");
if (!is_else) { if (!is_else) {
module.offset -= i.len; module.set_checkpoint(else_checkpoint);
} }
} }
@ -2936,7 +2979,7 @@ pub const Module = struct {
.@"break" => break :blk .break_statement, .@"break" => break :blk .break_statement,
.@"continue" => break :blk .continue_statement, .@"continue" => break :blk .continue_statement,
} else { } else {
module.offset -= statement_start_identifier.len; module.set_checkpoint(checkpoint);
const left = module.parse_value(scope, .{ const left = module.parse_value(scope, .{
.kind = .left, .kind = .left,
@ -4010,14 +4053,17 @@ pub const Module = struct {
const global_name = module.parse_identifier(); const global_name = module.parse_identifier();
if (module.types.find_by_name(global_name) != null) {
module.report_error();
}
if (module.globals.find_by_name(global_name) != null) { if (module.globals.find_by_name(global_name) != null) {
module.report_error(); module.report_error();
} }
const forward_declaration = if (module.types.find_by_name(global_name)) |fwd| b: {
if (fwd.bb != .forward_declaration) {
module.report_error();
}
break :b fwd;
} else null;
module.skip_space(); module.skip_space();
var global_type: ?*Type = null; var global_type: ?*Type = null;
@ -4035,7 +4081,7 @@ pub const Module = struct {
var global_keyword = false; var global_keyword = false;
if (is_identifier_start_ch(module.content[module.offset])) { if (is_identifier_start_ch(module.content[module.offset])) {
const identifier_offset = module.offset; const checkpoint = module.get_checkpoint();
const global_string = module.parse_identifier(); const global_string = module.parse_identifier();
module.skip_space(); module.skip_space();
@ -4377,17 +4423,12 @@ pub const Module = struct {
.@"struct" => { .@"struct" => {
module.skip_space(); module.skip_space();
module.expect_character(left_brace); const struct_type = if (forward_declaration) |fwd| fwd else module.types.append(.{
if (module.types.find_by_name(global_name) != null) {
@trap();
}
const struct_type = module.types.append(.{
.name = global_name, .name = global_name,
.bb = .forward_declaration, .bb = .forward_declaration,
}); });
if (module.consume_character_if_match(left_brace)) {
var field_buffer: [256]Type.Struct.Field = undefined; var field_buffer: [256]Type.Struct.Field = undefined;
var field_count: u64 = 0; var field_count: u64 = 0;
var byte_offset: u64 = 0; var byte_offset: u64 = 0;
@ -4435,10 +4476,7 @@ pub const Module = struct {
module.skip_space(); module.skip_space();
switch (module.content[module.offset]) { _ = module.consume_character_if_match(',');
',' => module.offset += 1,
else => {},
}
} }
module.skip_space(); module.skip_space();
@ -4461,6 +4499,9 @@ pub const Module = struct {
.line = global_line, .line = global_line,
}, },
}; };
} else {
module.expect_character(';');
}
}, },
.typealias => { .typealias => {
const aliased_type = module.parse_type(); const aliased_type = module.parse_type();
@ -4688,10 +4729,7 @@ pub const Module = struct {
module.skip_space(); module.skip_space();
switch (module.content[module.offset]) { _ = module.consume_character_if_match(',');
',' => module.offset += 1,
else => {},
}
} }
module.skip_space(); module.skip_space();
@ -4713,7 +4751,7 @@ pub const Module = struct {
}, },
} }
} else { } else {
module.offset = identifier_offset; module.set_checkpoint(checkpoint);
} }
} }
@ -4951,7 +4989,7 @@ pub const Module = struct {
.scalar => module.create_load(.{ .type = va_arg.type, .value = llvm_address }), .scalar => module.create_load(.{ .type = va_arg.type, .value = llvm_address }),
.aggregate => if (left_llvm) |l| b: { .aggregate => if (left_llvm) |l| b: {
uint64.resolve(module); uint64.resolve(module);
_ = module.llvm.builder.create_memcpy(l, left_type.?.bb.pointer.alignment.?, llvm_address, va_arg.type.get_byte_alignment(), uint64.llvm.abi.?.to_integer().get_constant(va_arg.type.get_byte_size(), 0).to_value()); _ = module.llvm.builder.create_memcpy(l, left_type.?.bb.pointer.get_alignment(), llvm_address, va_arg.type.get_byte_alignment(), uint64.llvm.abi.?.to_integer().get_constant(va_arg.type.get_byte_size(), 0).to_value());
break :b l; break :b l;
} else llvm_address, } else llvm_address,
.complex => @trap(), .complex => @trap(),
@ -5189,20 +5227,28 @@ pub const Module = struct {
} }
} else { } else {
assert(argument_abi.abi_count == 1); assert(argument_abi.abi_count == 1);
const destination_type = argument_abi.get_coerce_to_type();
const v = switch (src.bb) {
.zero => destination_type.llvm.abi.?.get_zero().to_value(),
else => b: {
// TODO: handmade change // TODO: handmade change
if (src.type.?.bb != .pointer) { if (src.type.?.bb != .pointer) {
assert(src.kind == .right); assert(src.kind == .right);
assert(src.type.?.bb == .structure); assert(src.type.?.bb == .structure);
const ty = src.type.?;
src.type = null; src.type = null;
src.kind = .left; src.kind = .left;
module.analyze_value_type(src, .{}); module.analyze_value_type(src, .{ .type = module.get_pointer_type(.{ .type = ty }) });
} }
module.emit_value(src, .memory);
assert(src.type.?.bb == .pointer); assert(src.type.?.bb == .pointer);
assert(src.type.?.llvm.abi == module.llvm.pointer_type);
module.emit_value(src, .memory);
const source_type = src.type.?.bb.pointer.type; const source_type = src.type.?.bb.pointer.type;
assert(source_type == argument_abi.semantic_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 load = module.create_coerced_load(src.llvm.?, source_type, destination_type);
const is_cmse_ns_call = false; const is_cmse_ns_call = false;
@ -5214,7 +5260,11 @@ pub const Module = struct {
@trap(); @trap();
} }
llvm_abi_argument_value_buffer[abi_argument_count] = load; break :b load;
},
};
llvm_abi_argument_value_buffer[abi_argument_count] = v;
abi_argument_count += 1; abi_argument_count += 1;
} }
} }
@ -5866,18 +5916,18 @@ pub const Module = struct {
} }
} }
if (lib.optimization_mode == .Debug) { // if (lib.optimization_mode == .Debug) {
const verify_result = llvm_function_value.verify(); // const verify_result = llvm_function_value.verify();
if (!verify_result.success) { // if (!verify_result.success) {
lib.print_string(module.llvm.module.to_string()); // lib.print_string(module.llvm.module.to_string());
lib.print_string("============================\n"); // lib.print_string("============================\n");
lib.print_string(llvm_function_value.to_string()); // lib.print_string(llvm_function_value.to_string());
lib.print_string("============================\n"); // lib.print_string("============================\n");
lib.print_string(verify_result.error_message orelse unreachable); // lib.print_string(verify_result.error_message orelse unreachable);
lib.print_string("\n============================\n"); // lib.print_string("\n============================\n");
lib.os.abort(); // lib.os.abort();
} // }
} // }
}, },
.global => { .global => {
module.analyze(global.variable.initial_value, .{ .type = global.variable.type }, .memory); module.analyze(global.variable.initial_value, .{ .type = global.variable.type }, .memory);
@ -5917,6 +5967,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) { if (module.has_debug_info) {
module.llvm.di_builder.finalize(); module.llvm.di_builder.finalize();
} }
@ -7716,13 +7786,11 @@ pub const Module = struct {
.scalar => module.create_load(.{ .scalar => module.create_load(.{
.type = value_type, .type = value_type,
.value = variable.storage.?.llvm.?, .value = variable.storage.?.llvm.?,
.alignment = variable.storage.?.type.?.bb.pointer.alignment,
}), }),
// TODO: this might be wrong // TODO: this might be wrong
.aggregate => module.create_load(.{ .aggregate => module.create_load(.{
.type = value_type, .type = value_type,
.value = variable.storage.?.llvm.?, .value = variable.storage.?.llvm.?,
.alignment = variable.storage.?.type.?.bb.pointer.alignment,
}), }),
.complex => @trap(), .complex => @trap(),
}, },
@ -7850,7 +7918,7 @@ pub const Module = struct {
.right => module.create_load(.{ .right => module.create_load(.{
.type = dereferenceable_value.type.?.bb.pointer.type, .type = dereferenceable_value.type.?.bb.pointer.type,
.value = dereferenceable_value.llvm.?, .value = dereferenceable_value.llvm.?,
.alignment = dereferenceable_value.type.?.bb.pointer.alignment, .alignment = dereferenceable_value.type.?.bb.pointer.get_alignment(),
}), }),
}; };
break :blk result; break :blk result;
@ -8077,7 +8145,7 @@ pub const Module = struct {
const field = bits.fields[field_index]; const field = bits.fields[field_index];
field.type.resolve(module); field.type.resolve(module);
const load = module.create_load(.{ .type = ty, .alignment = pointer_type.bb.pointer.alignment, .value = v }); const load = module.create_load(.{ .type = ty, .alignment = pointer_type.bb.pointer.get_alignment(), .value = v });
const shift = module.llvm.builder.create_lshr(load, bits.backing_type.llvm.abi.?.to_integer().get_constant(field.bit_offset, 0).to_value()); const shift = module.llvm.builder.create_lshr(load, bits.backing_type.llvm.abi.?.to_integer().get_constant(field.bit_offset, 0).to_value());
const trunc = module.llvm.builder.create_truncate(shift, field.type.llvm.abi.?); const trunc = module.llvm.builder.create_truncate(shift, field.type.llvm.abi.?);
break :blk trunc; break :blk trunc;
@ -8315,93 +8383,16 @@ pub const Module = struct {
}, },
.noreturn => module.report_error(), .noreturn => module.report_error(),
else => { else => {
const return_value = rv orelse module.report_error();
module.analyze(return_value, .{
.type = return_abi.semantic_type,
}, .memory);
if (module.has_debug_info) { if (module.has_debug_info) {
module.llvm.builder.set_current_debug_location(last_statement_debug_location.*); module.llvm.builder.set_current_debug_location(last_statement_debug_location.*);
} }
// Clang equivalent: CodeGenFunction::EmitReturnStmt
const return_alloca = module.current_function.?.variable.storage.?.bb.function.return_alloca orelse module.report_error(); const return_alloca = module.current_function.?.variable.storage.?.bb.function.return_alloca orelse module.report_error();
const return_value = rv orelse module.report_error();
module.analyze_value_type(return_value, .{ .type = return_abi.semantic_type });
switch (return_abi.semantic_type.get_evaluation_kind()) { const pointer_type = module.get_pointer_type(.{ .type = return_abi.semantic_type });
.scalar => { module.emit_assignment(return_alloca, pointer_type, return_value);
switch (return_abi.flags.kind) {
.indirect => {
@trap();
},
else => {
// assert(!return_value.?.lvalue);
assert(return_value.type.?.is_abi_equal(return_abi.semantic_type, module));
_ = module.create_store(.{
.source_value = return_value.llvm.?,
.destination_value = return_alloca,
.type = return_abi.semantic_type,
});
},
}
},
// TODO: handcoded code, might be wrong
.aggregate => switch (return_value.kind) {
.left => @trap(),
.right => {
assert(return_value.type.?.is_abi_equal(return_abi.semantic_type, module));
_ = module.create_store(.{
.source_value = return_value.llvm.?,
.destination_value = return_alloca,
.type = return_abi.semantic_type,
});
},
// switch (return_value.lvalue) {
// true => {
// const abi_alignment = return_abi.semantic_type.get_byte_alignment();
// const abi_size = return_abi.semantic_type.get_byte_size();
// switch (return_abi.flags.kind) {
// .indirect => {
// _ = module.llvm.builder.create_memcpy(
// unreachable, //return_alloca,
// abi_alignment, return_value.llvm, abi_alignment, module.integer_type(64, false).llvm.handle.to_integer().get_constant(abi_size, @intFromBool(false)).to_value());
// },
// else => {
// switch (return_abi.semantic_type.get_evaluation_kind()) {
// .aggregate => {
// // TODO: this is 100% wrong, fix
// assert(abi_alignment == return_abi.semantic_type.get_byte_alignment());
// assert(abi_size == return_abi.semantic_type.get_byte_size());
// _ = module.llvm.builder.create_memcpy(
// unreachable, //return_alloca,
// abi_alignment, return_value.llvm, abi_alignment, module.integer_type(64, false).llvm.handle.to_integer().get_constant(abi_size, @intFromBool(false)).to_value());
// },
// .scalar => {
// const destination_type = return_abi.semantic_type;
// const source_type = return_abi.semantic_type;
// assert(return_value.type == source_type);
// const ret_val = switch (return_value.type.bb) {
// .pointer => return_value.llvm,
// // TODO: this feels hacky
// else => switch (return_value.lvalue) {
// true => module.create_load(.{ .type = return_value.type, .value = return_value.llvm }),
// false => return_value.llvm,
// },
// };
// _ = module.create_store(.{ .source_value = ret_val, .source_type = source_type,
// .destination_value = unreachable, //return_alloca,
// .destination_type = destination_type });
// },
// .complex => @trap(),
// }
// },
// }
// },
// false => {
// },
// }
},
.complex => @trap(),
}
}, },
} }
@ -8440,7 +8431,7 @@ pub const Module = struct {
const pointer_type = assignment.left.type.?.bb.pointer; const pointer_type = assignment.left.type.?.bb.pointer;
const element_type = pointer_type.type; const element_type = pointer_type.type;
assert(element_type.get_evaluation_kind() == .scalar); assert(element_type.get_evaluation_kind() == .scalar);
const load = module.create_load(.{ .type = element_type, .value = assignment.left.llvm.?, .alignment = pointer_type.alignment }); const load = module.create_load(.{ .type = element_type, .value = assignment.left.llvm.?, .alignment = pointer_type.get_alignment() });
module.analyze(assignment.right, .{ .type = element_type }, .memory); module.analyze(assignment.right, .{ .type = element_type }, .memory);
const a = load; const a = load;
const b = assignment.right.llvm.?; const b = assignment.right.llvm.?;
@ -8511,7 +8502,7 @@ pub const Module = struct {
.source_value = right, .source_value = right,
.destination_value = assignment.left.llvm.?, .destination_value = assignment.left.llvm.?,
.type = element_type, .type = element_type,
.alignment = pointer_type.alignment, .alignment = pointer_type.get_alignment(),
}); });
}, },
} }
@ -8667,8 +8658,10 @@ pub const Module = struct {
module.llvm.builder.clear_insertion_position(); 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(), else => @trap(),
@ -8775,7 +8768,7 @@ pub const Module = struct {
const load = module.create_load(.{ const load = module.create_load(.{
.type = aggregate_type, .type = aggregate_type,
.value = right.llvm.?, .value = right.llvm.?,
.alignment = right.type.?.bb.pointer.alignment, .alignment = right.type.?.bb.pointer.get_alignment(),
}); });
const extract_pointer = module.llvm.builder.create_extract_value(load, 0); const extract_pointer = module.llvm.builder.create_extract_value(load, 0);
const gep = module.llvm.builder.create_gep(.{ const gep = module.llvm.builder.create_gep(.{
@ -8938,7 +8931,7 @@ pub const Module = struct {
.source_value = right.llvm.?, .source_value = right.llvm.?,
.destination_value = left_llvm, .destination_value = left_llvm,
.type = v_type, .type = v_type,
.alignment = pointer_type.bb.pointer.alignment, .alignment = pointer_type.bb.pointer.get_alignment(),
}); });
}, },
.aggregate => switch (right.bb) { .aggregate => switch (right.bb) {
@ -8957,7 +8950,7 @@ pub const Module = struct {
global_variable.to_value().set_alignment(alignment); global_variable.to_value().set_alignment(alignment);
const uint64 = module.integer_type(64, false); const uint64 = module.integer_type(64, false);
uint64.resolve(module); uint64.resolve(module);
_ = module.llvm.builder.create_memcpy(left_llvm, pointer_type.bb.pointer.alignment.?, global_variable.to_value(), alignment, uint64.llvm.abi.?.to_integer().get_constant(array_initialization.values.len * pointer_type.bb.pointer.type.bb.array.element_type.get_byte_size(), @intFromBool(false)).to_value()); _ = module.llvm.builder.create_memcpy(left_llvm, pointer_type.bb.pointer.get_alignment(), global_variable.to_value(), alignment, uint64.llvm.abi.?.to_integer().get_constant(array_initialization.values.len * pointer_type.bb.pointer.type.bb.array.element_type.get_byte_size(), @intFromBool(false)).to_value());
}, },
false => { false => {
assert(v_type.bb == .array); assert(v_type.bb == .array);
@ -9034,7 +9027,7 @@ pub const Module = struct {
uint8.resolve(module); uint8.resolve(module);
const uint64 = module.integer_type(64, false); const uint64 = module.integer_type(64, false);
uint64.resolve(module); uint64.resolve(module);
_ = module.llvm.builder.create_memset(destination_pointer, uint8.llvm.abi.?.get_zero().to_value(), uint64.llvm.abi.?.to_integer().get_constant(memset_size, 0).to_value(), pointer_type.bb.pointer.alignment.?); _ = module.llvm.builder.create_memset(destination_pointer, uint8.llvm.abi.?.get_zero().to_value(), uint64.llvm.abi.?.to_integer().get_constant(memset_size, 0).to_value(), pointer_type.bb.pointer.get_alignment());
} }
}, },
.@"union" => |union_type| { .@"union" => |union_type| {
@ -9051,7 +9044,14 @@ pub const Module = struct {
const field_pointer_type = module.get_pointer_type(.{ .type = field_value_type }); const field_pointer_type = module.get_pointer_type(.{ .type = field_value_type });
module.emit_assignment(destination_pointer, field_pointer_type, value); module.emit_assignment(destination_pointer, field_pointer_type, value);
if (field_type_size < union_type.byte_size) { if (field_type_size < union_type.byte_size) {
@trap(); const uint8 = module.integer_type(8, false).llvm.abi.?;
const uint64 = module.integer_type(64, false).llvm.abi.?.to_integer();
const padding_gep = module.llvm.builder.create_gep(.{
.type = uint8,
.aggregate = destination_pointer,
.indices = &.{ uint64.get_constant(field_type_size, 0).to_value() },
});
_ = module.llvm.builder.create_memset(padding_gep, uint8.get_zero().to_value(), uint64.get_constant(union_type.byte_size - field_type_size, 0).to_value(), 1);
} else if (field_type_size > union_type.byte_size) { } else if (field_type_size > union_type.byte_size) {
unreachable; unreachable;
} }
@ -9136,7 +9136,7 @@ pub const Module = struct {
.source_value = call, .source_value = call,
.destination_value = left_llvm, .destination_value = left_llvm,
.type = s2e.struct_type, .type = s2e.struct_type,
.alignment = pointer_type.bb.pointer.alignment, .alignment = pointer_type.bb.pointer.get_alignment(),
}); });
}, },
.va_start => { .va_start => {
@ -9186,7 +9186,7 @@ pub const Module = struct {
.source_value = slice_values[0], .source_value = slice_values[0],
.destination_value = left_llvm, .destination_value = left_llvm,
.type = slice_pointer_type, .type = slice_pointer_type,
.alignment = pointer_type.bb.pointer.alignment, .alignment = pointer_type.bb.pointer.get_alignment(),
}); });
const slice_length_destination = module.llvm.builder.create_struct_gep(resolved_value_type.llvm.abi.?.to_struct(), left_llvm, 1); const slice_length_destination = module.llvm.builder.create_struct_gep(resolved_value_type.llvm.abi.?.to_struct(), left_llvm, 1);
_ = module.create_store(.{ _ = module.create_store(.{
@ -9200,13 +9200,13 @@ pub const Module = struct {
u8_type.resolve(module); u8_type.resolve(module);
const u64_type = module.integer_type(64, false); const u64_type = module.integer_type(64, false);
u64_type.resolve(module); u64_type.resolve(module);
_ = module.llvm.builder.create_memset(left_llvm, u8_type.llvm.abi.?.get_zero().to_value(), u64_type.llvm.abi.?.to_integer().get_constant(resolved_value_type.get_byte_size(), 0).to_value(), pointer_type.bb.pointer.alignment.?); _ = module.llvm.builder.create_memset(left_llvm, u8_type.llvm.abi.?.get_zero().to_value(), u64_type.llvm.abi.?.to_integer().get_constant(resolved_value_type.get_byte_size(), 0).to_value(), pointer_type.bb.pointer.get_alignment());
}, },
.variable_reference => |variable| switch (right.kind) { .variable_reference => |variable| switch (right.kind) {
.left => @trap(), .left => @trap(),
.right => { .right => {
const uint64 = module.integer_type(64, false); const uint64 = module.integer_type(64, false);
_ = module.llvm.builder.create_memcpy(left_llvm, pointer_type.bb.pointer.alignment.?, variable.storage.?.llvm.?, variable.storage.?.type.?.bb.pointer.alignment.?, uint64.llvm.abi.?.to_integer().get_constant(resolved_value_type.get_byte_size(), @intFromBool(false)).to_value()); _ = module.llvm.builder.create_memcpy(left_llvm, pointer_type.bb.pointer.get_alignment(), variable.storage.?.llvm.?, variable.storage.?.type.?.bb.pointer.get_alignment(), uint64.llvm.abi.?.to_integer().get_constant(resolved_value_type.get_byte_size(), @intFromBool(false)).to_value());
}, },
}, },
.field_access => |field_access| { .field_access => |field_access| {
@ -9220,7 +9220,7 @@ pub const Module = struct {
module.emit_value(field_access.aggregate, .memory); module.emit_value(field_access.aggregate, .memory);
const gep = module.llvm.builder.create_struct_gep(struct_type.llvm.abi.?.to_struct(), field_access.aggregate.llvm.?, field_index); const gep = module.llvm.builder.create_struct_gep(struct_type.llvm.abi.?.to_struct(), field_access.aggregate.llvm.?, field_index);
const uint64 = module.integer_type(64, false); const uint64 = module.integer_type(64, false);
_ = module.llvm.builder.create_memcpy(left_llvm, pointer_type.bb.pointer.alignment.?, gep, resolved_value_type.get_byte_alignment(), uint64.llvm.abi.?.to_integer().get_constant(resolved_value_type.get_byte_size(), @intFromBool(false)).to_value()); _ = module.llvm.builder.create_memcpy(left_llvm, pointer_type.bb.pointer.get_alignment(), gep, resolved_value_type.get_byte_alignment(), uint64.llvm.abi.?.to_integer().get_constant(resolved_value_type.get_byte_size(), @intFromBool(false)).to_value());
}, },
.undefined => {}, .undefined => {},
else => @trap(), else => @trap(),
@ -9241,7 +9241,7 @@ pub const Module = struct {
.bb = .local, .bb = .local,
.llvm = module.create_alloca(.{ .llvm = module.create_alloca(.{
.type = pointer_type.bb.pointer.type, .type = pointer_type.bb.pointer.type,
.alignment = pointer_type.bb.pointer.alignment, .alignment = pointer_type.bb.pointer.get_alignment(),
.name = local.variable.name, .name = local.variable.name,
}), }),
}; };
@ -9366,7 +9366,6 @@ pub const Module = struct {
value: *llvm.Value, value: *llvm.Value,
type: *Type, type: *Type,
} { } {
_ = module;
var source_pointer = source_value; var source_pointer = source_value;
var source_type = source_ty; var source_type = source_ty;
assert(source_type.bb == .structure and source_type.bb.structure.fields.len > 0); assert(source_type.bb == .structure and source_type.bb.structure.fields.len > 0);
@ -9376,7 +9375,15 @@ pub const Module = struct {
source_pointer = switch (first_field_size < destination_size and first_field_size < source_size) { source_pointer = switch (first_field_size < destination_size and first_field_size < source_size) {
true => source_pointer, 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 }; return .{ .value = source_pointer, .type = source_type };
@ -9497,9 +9504,10 @@ pub const Module = struct {
return result; return result;
} }
pub fn coerce_int_or_pointer_to_int_or_pointer(module: *Module, source: *llvm.Value, source_ty: *Type, destination_ty: *Type) *llvm.Value { pub fn coerce_int_or_pointer_to_int_or_pointer(module: *Module, s: *llvm.Value, source_ty: *Type, destination_ty: *Type) *llvm.Value {
const source_type = source_ty; const source_type = source_ty;
var destination_type = destination_ty; var destination_type = destination_ty;
var source = s;
switch (source_type == destination_type) { switch (source_type == destination_type) {
true => return source, true => return source,
false => { false => {
@ -9507,7 +9515,7 @@ pub const Module = struct {
@trap(); @trap();
} else { } else {
if (source_type.bb == .pointer) { if (source_type.bb == .pointer) {
@trap(); source = module.llvm.builder.create_ptr_to_int(source, module.integer_type(64, false).llvm.abi.?);
} }
if (destination_type.bb == .pointer) { if (destination_type.bb == .pointer) {
@ -9550,7 +9558,7 @@ pub const Module = struct {
if (old_child_type == new_child_type) { if (old_child_type == new_child_type) {
break :blk ty; break :blk ty;
} else { } else {
const p = module.get_pointer_type(.{ .type = new_child_type, .alignment = pointer.alignment }); const p = module.get_pointer_type(.{ .type = new_child_type });
break :blk p; break :blk p;
} }
}, },

View File

@ -586,11 +586,32 @@ CompileOptions = struct
silent: u1, silent: u1,
} }
ScopeKind = enum
{
global,
function,
local,
for_each,
macro_declaration,
macro_instantiation_function,
}
Scope = struct
{
parent: &Scope,
line: u32,
column: u32,
kind: ScopeKind,
}
Type = struct;
TypeId = enum TypeId = enum
{ {
void, void,
noreturn, noreturn,
integer, integer,
function,
} }
TypeInteger = struct TypeInteger = struct
@ -599,9 +620,23 @@ TypeInteger = struct
signed: u1, signed: u1,
} }
CallingConvention = enum
{
c,
}
TypeFunction = struct
{
semantic_return_type: &Type,
semantic_argument_types: []&Type,
calling_convention: CallingConvention,
is_variable_arguments: u1,
}
TypeContent = union TypeContent = union
{ {
integer: TypeInteger, integer: TypeInteger,
function: TypeFunction,
} }
Type = struct Type = struct
@ -630,11 +665,36 @@ Module = struct
arena: &Arena, arena: &Arena,
base_type_allocation: &Type, base_type_allocation: &Type,
void_value: &Value, void_value: &Value,
// Parser data // Parser data start
content: []u8, content: []u8,
offset: u64, offset: u64,
line_offset: u64, line_offset: u64,
line_character_offset: u64, line_character_offset: u64,
// Parser data end
scope: Scope,
}
ModuleCheckpoint = struct
{
offset: u64,
line_offset: u64,
line_character_offset: u64,
}
get_checkpoint = fn (module: &Module) ModuleCheckpoint
{
return {
.offset = module.offset,
.line_offset = module.line_offset,
.line_character_offset = module.line_character_offset,
};
}
set_checkpoint = fn (module: &Module, checkpoint: ModuleCheckpoint) void
{
module.offset = checkpoint.offset;
module.line_offset = checkpoint.line_offset;
module.line_character_offset = checkpoint.line_character_offset;
} }
module_integer_type = fn (module: &Module, integer: TypeInteger) &Type module_integer_type = fn (module: &Module, integer: TypeInteger) &Type
@ -655,6 +715,13 @@ module_noreturn_type = fn (module: &Module) &Type
return module_void_type(module) + 1; 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 is_space = fn (ch: u8) u1
{ {
return ch == ' ' or ch == '\n' or ch == '\t' or ch == '\r'; return ch == ' ' or ch == '\n' or ch == '\t' or ch == '\r';
@ -697,7 +764,7 @@ is_hex = fn (ch: u8) u1
is_identifier_start = fn (ch: u8) u1 is_identifier_start = fn (ch: u8) u1
{ {
return (ch >= 'a' and ch >= 'z') or (ch >= 'A' and ch <= 'Z') or ch == '_'; return (ch >= 'a' and ch <= 'z') or (ch >= 'A' and ch <= 'Z') or ch == '_';
} }
is_identifier = fn (ch: u8) u1 is_identifier = fn (ch: u8) u1
@ -817,8 +884,351 @@ parse_identifier = fn (module: &Module) []u8
return result; 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,
}
FunctionKeyword = enum
{
cc,
}
InlineBehavior = enum
{
default,
always_inline,
no_inline,
inline_hint,
}
FunctionAttributes = struct
{
inline_behavior: InlineBehavior,
naked: u1,
}
new_type_array = fn (module: &Module, count: u64) []&Type
{
>result = arena_allocate[&Type](module.arena, count);
return result[..count];
}
new_type = fn (module: &Module) &Type
{
>result = arena_allocate[Type](module.arena, 1);
return result;
}
new_value_array = fn (module: &Module, count: u64) []&Value
{
>result = arena_allocate[&Value](module.arena, count);
return result[..count];
}
new_value = fn (module: &Module) &Value
{
>result = arena_allocate[Value](module.arena, 1);
return result;
}
allocate_value_array = fn (module: &Module, stack_array: []&Value) []&Value
{
>result = new_value_array(module, stack_array.length);
memcpy(#pointer_cast(result.pointer), #pointer_cast(stack_array.pointer), stack_array.length * #byte_size(&Value));
}
allocate_type_array = fn (module: &Module, stack_array: []&Type) []&Type
{
>result = new_type_array(module, stack_array.length);
memcpy(#pointer_cast(result.pointer), #pointer_cast(stack_array.pointer), stack_array.length * #byte_size(&Type));
}
parse = fn (module: &Module) void 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]))
{
>checkpoint = get_checkpoint(module);
>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 => {
>calling_convention: CallingConvention = .c;
>function_attributes: FunctionAttributes = zero;
>is_variable_arguments: u1 = 0;
if (consume_character_if_match(module, left_bracket))
{
while (module.offset < module.content.length)
{
>function_identifier = parse_identifier(module);
>function_keyword_s2e = #string_to_enum(FunctionKeyword, function_identifier);
if (function_keyword_s2e.is_valid)
{
>function_keyword = function_keyword_s2e.enum_value;
skip_space(module);
switch (function_keyword)
{
.cc => {
expect_character(module, left_parenthesis);
skip_space(module);
>calling_convention_string = parse_identifier(module);
>calling_convention_s2e = #string_to_enum(CallingConvention, calling_convention_string);
if (calling_convention_s2e.is_valid)
{
calling_convention = calling_convention_s2e.enum_value;
skip_space(module);
expect_character(module, right_parenthesis);
}
else
{
report_error();
}
},
}
skip_space(module);
if (consume_character_if_match(module, right_bracket))
{
break;
}
else
{
report_error();
}
}
else
{
report_error();
}
}
}
skip_space(module);
expect_character(module, left_parenthesis);
>semantic_argument_type_buffer: [64]&Type = undefined;
>semantic_argument_name_buffer: [64][]u8 = undefined;
>semantic_argument_count: u64 = 0;
while (module.offset < module.content.length)
{
skip_space(module);
if (consume_character_if_match(module, '.'))
{
expect_character(module, '.');
expect_character(module, '.');
skip_space(module);
expect_character(module, right_parenthesis);
is_variable_arguments = 1;
break;
}
if (consume_character_if_match(module, right_parenthesis))
{
break;
}
>argument_name = parse_identifier(module);
semantic_argument_name_buffer[semantic_argument_count] = argument_name;
skip_space(module);
expect_character(module, ':');
skip_space(module);
>argument_type = parse_type(module);
semantic_argument_type_buffer[semantic_argument_count] = argument_type;
skip_space(module);
if (consume_character_if_match(module, ','))
{
skip_space(module);
}
semantic_argument_count += 1;
}
skip_space(module);
>return_type = parse_type(module);
>argument_types: []&Type = zero;
if (semantic_argument_count != 0)
{
argument_types = allocate_type_array(module, semantic_argument_type_buffer[..semantic_argument_count]);
}
skip_space(module);
>is_declaration = consume_character_if_match(module, ';');
>function_type = new_type(module);
function_type.& = {
.content = {
.function = {
.semantic_return_type = return_type,
.semantic_argument_types = argument_types,
.calling_convention = calling_convention,
.is_variable_arguments = is_variable_arguments,
},
},
.id = .function,
.name = "",
};
>storage = new_value(module);
#trap();
},
.macro => {
#trap();
},
.struct => {
#trap();
},
.typealias => {
#trap();
},
.union => {
#trap();
},
}
}
else
{
set_checkpoint(module, checkpoint);
}
}
if (!has_global_keyword)
{
>v = parse_value(module, &module.scope, zero);
skip_space(module);
expect_character(module, ';');
#trap();
}
}
} }
emit = fn (module: &Module) void emit = fn (module: &Module) void
@ -894,22 +1304,23 @@ compile = fn (arena: &Arena, options: CompileOptions) void
.name = "noreturn", .name = "noreturn",
}; };
>void_value = arena_allocate[Value](arena, 1);
void_value.& = {
.type = void_type,
.id = .infer_or_ignore,
};
>module: Module = { >module: Module = {
.arena = arena, .arena = arena,
.base_type_allocation = base_type_allocation, .base_type_allocation = base_type_allocation,
.void_value = void_value, .void_value = undefined,
.content = options.content, .content = options.content,
.offset = 0, .offset = 0,
.line_offset = 0, .line_offset = 0,
.line_character_offset = 0, .line_character_offset = 0,
}; };
>void_value = new_value(&module);
void_value.& = {
.type = void_type,
.id = .infer_or_ignore,
};
parse(&module); parse(&module);
emit(&module); emit(&module);
} }

View File

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

View File

@ -0,0 +1,17 @@
T = struct;
Foo = struct
{
t: &T,
}
T = struct
{
f: Foo,
}
[export] main = fn [cc(c)] () s32
{
>t: T = zero;
t.f.t = &t;
return 0;
}

View File

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