Implement pointers

This commit is contained in:
David Gonzalez Martin 2024-06-07 10:52:34 -06:00
parent 088c8d8d5d
commit 3381aa0625
3 changed files with 304 additions and 144 deletions

View File

@ -1,5 +1,4 @@
pointers
function pointers function pointers
for loops for loops
arrays struct
c abi c abi

View File

@ -157,6 +157,7 @@ const LocalSymbol = struct {
attributes: Attributes = .{}, attributes: Attributes = .{},
local_declaration: LocalDeclaration, local_declaration: LocalDeclaration,
type: *Type, type: *Type,
appointee_type: ?*Type = null,
instruction: Instruction, instruction: Instruction,
alignment: u32, alignment: u32,
@ -622,6 +623,7 @@ const Parser = struct{
return value; return value;
}, },
'[' => { '[' => {
// This is an array expression
parser.i += 1; parser.i += 1;
const ty = maybe_type orelse exit(1); const ty = maybe_type orelse exit(1);
@ -905,17 +907,20 @@ const Parser = struct{
}, },
}; };
}, },
' ', ',', ';', ')' => { '&' => {
const declaration_value = switch (lookup_result.declaration.*.id) { parser.i += 1;
.local => block: {
const local_declaration = lookup_result.declaration.*.get_payload(.local); const local_declaration = lookup_result.declaration.*.get_payload(.local);
const local_symbol = local_declaration.to_symbol(); const local_symbol = local_declaration.to_symbol();
return &local_symbol.instruction.value;
},
'@' => {
parser.i += 1;
if (maybe_type) |ty| { const local_declaration = lookup_result.declaration.*.get_payload(.local);
switch (typecheck(ty, local_symbol.type)) { const local_symbol = local_declaration.to_symbol();
.success => {}, assert(local_symbol.type.sema.id == .pointer);
} assert(local_symbol.appointee_type != null);
}
const load = thread.loads.append(.{ const load = thread.loads.append(.{
.instruction = .{ .instruction = .{
@ -934,7 +939,73 @@ const Parser = struct{
.is_volatile = false, .is_volatile = false,
}); });
_ = analyzer.current_basic_block.instructions.append(&load.instruction); _ = analyzer.current_basic_block.instructions.append(&load.instruction);
break :block &load.instruction.value;
return switch (side) {
.left => &load.instruction.value,
.right => block: {
const pointer_load_type = local_symbol.appointee_type.?;
if (maybe_type) |ty| {
switch (typecheck(ty, pointer_load_type)) {
.success => {},
}
}
const pointer_load = thread.loads.append(.{
.instruction = .{
.value = .{
.sema = .{
.thread = thread.get_index(),
.resolved = true,
.id = .instruction,
},
},
.id = .load,
},
.value = &load.instruction.value,
.type = pointer_load_type,
.alignment = pointer_load_type.alignment,
.is_volatile = false,
});
_ = analyzer.current_basic_block.instructions.append(&pointer_load.instruction);
break :block &pointer_load.instruction.value;
},
};
},
' ', ',', ';', ')' => {
const declaration_value = switch (lookup_result.declaration.*.id) {
.local => block: {
const local_declaration = lookup_result.declaration.*.get_payload(.local);
const local_symbol = local_declaration.to_symbol();
if (maybe_type) |ty| {
switch (typecheck(ty, local_symbol.type)) {
.success => {},
}
}
break :block switch (side) {
.right => b: {
const load = thread.loads.append(.{
.instruction = .{
.value = .{
.sema = .{
.thread = thread.get_index(),
.resolved = true,
.id = .instruction,
},
},
.id = .load,
},
.value = &local_symbol.instruction.value,
.type = local_symbol.type,
.alignment = local_symbol.type.alignment,
.is_volatile = false,
});
_ = analyzer.current_basic_block.instructions.append(&load.instruction);
break :b &load.instruction.value;
},
.left => &local_symbol.instruction.value,
};
}, },
.argument => block: { .argument => block: {
const argument_declaration = lookup_result.declaration.*.get_payload(.argument); const argument_declaration = lookup_result.declaration.*.get_payload(.argument);
@ -944,6 +1015,8 @@ const Parser = struct{
.success => {}, .success => {},
} }
} }
break :block switch (side) {
.right => b: {
const load = thread.loads.append(.{ const load = thread.loads.append(.{
.instruction = .{ .instruction = .{
.value = .{ .value = .{
@ -961,7 +1034,10 @@ const Parser = struct{
.is_volatile = false, .is_volatile = false,
}); });
_ = analyzer.current_basic_block.instructions.append(&load.instruction); _ = analyzer.current_basic_block.instructions.append(&load.instruction);
break :block &load.instruction.value; break :b &load.instruction.value;
},
.left => &argument_symbol.instruction.value,
};
}, },
.global => block: { .global => block: {
const global_declaration = lookup_result.declaration.*.get_payload(.global); const global_declaration = lookup_result.declaration.*.get_payload(.global);
@ -981,6 +1057,8 @@ const Parser = struct{
} }
} }
break :block switch (side) {
.right => b: {
const load = thread.loads.append(.{ const load = thread.loads.append(.{
.instruction = .{ .instruction = .{
.value = .{ .value = .{
@ -998,12 +1076,18 @@ const Parser = struct{
.is_volatile = false, .is_volatile = false,
}); });
_ = analyzer.current_basic_block.instructions.append(&load.instruction); _ = analyzer.current_basic_block.instructions.append(&load.instruction);
break :block &load.instruction.value; break :b &load.instruction.value;
},
.left => &global_symbol.value,
};
}, },
}; };
const declaration_type = declaration_value.get_type(); const declaration_type = declaration_value.get_type();
if (unary != .none) assert(side == .right);
if (side == .left) assert(side == .left);
return switch (unary) { return switch (unary) {
.none => declaration_value, .none => declaration_value,
.one_complement => block: { .one_complement => block: {
@ -1119,6 +1203,10 @@ const Parser = struct{
var it_ty: ?*Type = ty; var it_ty: ?*Type = ty;
while (true) { while (true) {
// if (src[parser.i] == ';') {
// break;
// }
if (iterations == 1 and it_ty == null) { if (iterations == 1 and it_ty == null) {
it_ty = previous_value.get_type(); it_ty = previous_value.get_type();
} }
@ -1724,6 +1812,9 @@ const Value = struct {
const lz = instruction.get_payload(.leading_zeroes); const lz = instruction.get_payload(.leading_zeroes);
return lz.value.get_type(); return lz.value.get_type();
}, },
.local_symbol => {
return &instance.threads[value.sema.thread].pointer;
},
else => |t| @panic(@tagName(t)), else => |t| @panic(@tagName(t)),
}; };
}, },
@ -1731,6 +1822,16 @@ const Value = struct {
const constant_int = value.get_payload(.constant_int); const constant_int = value.get_payload(.constant_int);
return constant_int.type; return constant_int.type;
}, },
.global_symbol => {
const global_symbol = value.get_payload(.global_symbol);
return switch (global_symbol.id) {
.global_variable => b: {
const global_variable = global_symbol.get_payload(.global_variable);
break :b global_variable.type;
},
else => |t| @panic(@tagName(t)),
};
},
else => |t| @panic(@tagName(t)), else => |t| @panic(@tagName(t)),
}; };
} }
@ -1753,6 +1854,7 @@ const Type = struct {
void, void,
integer, integer,
array, array,
pointer,
}; };
const Integer = struct { const Integer = struct {
@ -1781,6 +1883,7 @@ const Type = struct {
.void = void, .void = void,
.integer = Integer, .integer = Integer,
.array = Array, .array = Array,
.pointer = void,
}); });
fn get_payload(ty: *Type, comptime id: Id) *id_to_type_map.get(id) { fn get_payload(ty: *Type, comptime id: Id) *id_to_type_map.get(id) {
@ -2277,6 +2380,15 @@ const Thread = struct{
.size = 0, .size = 0,
.alignment = 0, .alignment = 0,
}, },
pointer: Type = .{
.sema = .{
.thread = undefined,
.id = .pointer,
.resolved = true,
},
.size = 8,
.alignment = 8,
},
handle: std.Thread = undefined, handle: std.Thread = undefined,
fn add_thread_work(thread: *Thread, job: Job) void { fn add_thread_work(thread: *Thread, job: Job) void {
@ -3833,8 +3945,13 @@ fn llvm_get_type(thread: *Thread, ty: *Type) *LLVM.Type {
const array_type = LLVM.Type.Array.get(element_type, array_ty.descriptor.element_count); const array_type = LLVM.Type.Array.get(element_type, array_ty.descriptor.element_count);
break :b array_type.toType(); break :b array_type.toType();
}, },
.pointer => b: {
const pointer_type = thread.llvm.context.getPointerType(0);
break :b pointer_type.toType();
},
else => |t| @panic(@tagName(t)), else => |t| @panic(@tagName(t)),
}; };
return llvm_type; return llvm_type;
} }
} }
@ -4053,6 +4170,7 @@ pub fn analyze_local_block(thread: *Thread, analyzer: *Analyzer, parser: *Parser
initial_value: *Value, initial_value: *Value,
type: *Type, type: *Type,
}; };
const result: LocalResult = switch (src[parser.i]) { const result: LocalResult = switch (src[parser.i]) {
':' => block: { ':' => block: {
parser.i += 1; parser.i += 1;
@ -4115,6 +4233,22 @@ pub fn analyze_local_block(thread: *Thread, analyzer: *Analyzer, parser: *Parser
.alignment = result.type.alignment, .alignment = result.type.alignment,
}); });
if (local_symbol.type.sema.id == .pointer) {
switch (result.initial_value.sema.id) {
.instruction => {
const instruction = result.initial_value.get_payload(.instruction);
switch (instruction.id) {
.local_symbol => {
const right_local_symbol = instruction.get_payload(.local_symbol);
local_symbol.appointee_type = right_local_symbol.type;
},
else => |t| @panic(@tagName(t)),
}
},
else => |t| @panic(@tagName(t)),
}
}
_ = analyzer.current_function.stack_slots.append(local_symbol); _ = analyzer.current_function.stack_slots.append(local_symbol);
const store = thread.stores.append(.{ const store = thread.stores.append(.{
@ -4290,21 +4424,9 @@ pub fn analyze_local_block(thread: *Thread, analyzer: *Analyzer, parser: *Parser
} }
if (statement_start_ch_index == parser.i) { if (statement_start_ch_index == parser.i) {
if (is_identifier_char_start(statement_start_ch)) { const left = parser.parse_single_expression(analyzer, thread, file, null, .left);
const raw_identifier = parser.parse_raw_identifier(src);
const keyword_index = parse_keyword(raw_identifier);
const is_keyword = keyword_index != ~@as(u32, 0);
if (is_keyword) {
const keyword: Keyword = @enumFromInt(keyword_index);
switch (keyword) {
else => |t| @panic(@tagName(t)),
}
} else {
const identifier = intern_identifier(&thread.identifiers, raw_identifier);
parser.skip_space(src); parser.skip_space(src);
const declaration_lookup = analyzer.current_scope.get_declaration(identifier) orelse unreachable;
const operation_index = parser.i; const operation_index = parser.i;
const operation_ch = src[operation_index]; const operation_ch = src[operation_index];
var is_binary_operation = false; var is_binary_operation = false;
@ -4324,34 +4446,74 @@ pub fn analyze_local_block(thread: *Thread, analyzer: *Analyzer, parser: *Parser
parser.skip_space(src); parser.skip_space(src);
const declaration_value = get_declaration_value(analyzer, thread, declaration_lookup.declaration.*, null, .right); const expected_right_type = switch (left.sema.id) {
const declaration_type = switch (declaration_lookup.declaration.*.id) { .instruction => b: {
.argument => block: { const instruction = left.get_payload(.instruction);
const argument_declaration = declaration_lookup.declaration.*.get_payload(.argument); switch (instruction.id) {
const argument_symbol = argument_declaration.to_symbol(); .load => {
break :block argument_symbol.type; const load = instruction.get_payload(.load);
}, switch (load.value.sema.id) {
.local => block: { .instruction => {
const local_declaration = declaration_lookup.declaration.*.get_payload(.local); const load_instruction = load.value.get_payload(.instruction);
const local_symbol = local_declaration.to_symbol(); switch (load_instruction.id) {
break :block local_symbol.type; .local_symbol => {
}, const local_symbol = load_instruction.get_payload(.local_symbol);
.global => block: { if (local_symbol.type.sema.id == .pointer) {
const global_declaration = declaration_lookup.declaration.*.get_payload(.global); break :b local_symbol.appointee_type.?;
const global_symbol = global_declaration.to_symbol(); } else {
switch (global_symbol.id) { break :b local_symbol.type;
.global_variable => { }
const global_variable = global_symbol.get_payload(.global_variable);
break :block global_variable.type;
}, },
else => |t| @panic(@tagName(t)), else => |t| @panic(@tagName(t)),
} }
}, },
else => |t| @panic(@tagName(t)),
}
},
.local_symbol => {
const local_symbol = instruction.get_payload(.local_symbol);
assert(local_symbol.appointee_type == null);
break :b local_symbol.type;
},
else => |t| @panic(@tagName(t)),
}
},
.global_symbol => b: {
const global_symbol = left.get_payload(.global_symbol);
break :b switch (global_symbol.id) {
.global_variable => gv: {
const global_variable = global_symbol.get_payload(.global_variable);
break :gv global_variable.type;
},
else => |t| @panic(@tagName(t)),
}; };
const right = parser.parse_expression(analyzer, thread, file, declaration_type, .right); },
else => |t| @panic(@tagName(t)),
};
const source = switch (is_binary_operation) { const source = switch (is_binary_operation) {
false => right, false => parser.parse_expression(analyzer, thread, file, expected_right_type, .right),
true => block: { true => block: {
const left_load = thread.loads.append(.{
.instruction = .{
.id = .load,
.value = .{
.sema = .{
.thread = thread.get_index(),
.resolved = true,
.id = .instruction,
},
},
},
.value = left,
.type = expected_right_type,
.alignment = expected_right_type.alignment,
.is_volatile = false,
});
_ = analyzer.current_basic_block.instructions.append(&left_load.instruction);
const right = parser.parse_expression(analyzer, thread, file, expected_right_type, .right);
const binary_operation_id: IntegerBinaryOperation.Id = switch (operation_ch) { const binary_operation_id: IntegerBinaryOperation.Id = switch (operation_ch) {
'+' => .add, '+' => .add,
else => unreachable, else => unreachable,
@ -4368,20 +4530,17 @@ pub fn analyze_local_block(thread: *Thread, analyzer: *Analyzer, parser: *Parser
}, },
}, },
}, },
.left = declaration_value, .left = &left_load.instruction.value,
.right = right, .right = right,
.type = declaration_type, .type = expected_right_type,
}); });
_ = analyzer.current_basic_block.instructions.append(&binary_operation.instruction); _ = analyzer.current_basic_block.instructions.append(&binary_operation.instruction);
break :block &binary_operation.instruction.value; break :block &binary_operation.instruction.value;
}, },
}; };
parser.skip_space(src); parser.skip_space(src);
parser.expect_character(src, ';'); parser.expect_character(src, ';');
const declaration_pointer = get_declaration_value(analyzer, thread, declaration_lookup.declaration.*, null, .left);
const store = thread.stores.append(.{ const store = thread.stores.append(.{
.instruction = .{ .instruction = .{
.id = .store, .id = .store,
@ -4393,9 +4552,9 @@ pub fn analyze_local_block(thread: *Thread, analyzer: *Analyzer, parser: *Parser
}, },
}, },
}, },
.destination = declaration_pointer, .destination = left,
.source = source, .source = source,
.alignment = declaration_type.alignment, .alignment = expected_right_type.alignment,
.is_volatile = false, .is_volatile = false,
}); });
_ = analyzer.current_basic_block.instructions.append(&store.instruction); _ = analyzer.current_basic_block.instructions.append(&store.instruction);
@ -4403,10 +4562,6 @@ pub fn analyze_local_block(thread: *Thread, analyzer: *Analyzer, parser: *Parser
else => @panic((src.ptr + parser.i)[0..1]), else => @panic((src.ptr + parser.i)[0..1]),
} }
} }
} else {
exit_with_error("Unrecognized statement initial char");
}
}
} }
parser.expect_character(src, brace_close); parser.expect_character(src, brace_close);

View File

@ -0,0 +1,6 @@
fn[cc(.c)] main[export]() s32 {
>a: s32 = 0;
>pointer = a&;
pointer@ = 4;
return pointer@ - a;
}