diff --git a/bootstrap/Compilation.zig b/bootstrap/Compilation.zig index cef6fac..497c0a9 100644 --- a/bootstrap/Compilation.zig +++ b/bootstrap/Compilation.zig @@ -3764,6 +3764,22 @@ pub const Builder = struct { true => unreachable, false => switch (unit.types.get(pointer.type).*) { .array => |array| { + const pointer_gep = try unit.instructions.append(context.allocator, .{ + .get_element_pointer = .{ + .pointer = expression_to_slice.value.runtime, + .base_type = array.type, + .index = range_start, + }, + }); + try builder.appendInstruction(unit, context, pointer_gep); + + const pointer_type = try unit.getPointerType(context, .{ + .type = array.type, + .termination = .none, + .mutability = pointer.mutability, + .many = false, + .nullable = false, + }); const slice_builder = try unit.instructions.append(context.allocator, .{ .insert_value = .{ .expression = V{ @@ -3776,7 +3792,12 @@ pub const Builder = struct { }, }, .index = 0, - .new_value = expression_to_slice, + .new_value = .{ + .value = .{ + .runtime = pointer_gep, + }, + .type = pointer_type, + }, }, }); try builder.appendInstruction(unit, context, slice_builder); @@ -4227,9 +4248,25 @@ pub const Builder = struct { }; }, .array => |array| b: { + const loaded_array_like = switch (array_like_expression.value) { + .runtime => |instruction_index| switch (unit.instructions.get(instruction_index).*) { + .argument_declaration, .stack_slot => arg: { + const load = try unit.instructions.append(context.allocator, .{ + .load = .{ + .value = array_like_expression, + }, + }); + try builder.appendInstruction(unit, context, load); + break :arg load; + }, + else => |t| @panic(@tagName(t)), + }, + else => |t| @panic(@tagName(t)), + }; + const gep = try unit.instructions.append(context.allocator, .{ .get_element_pointer = .{ - .pointer = array_like_expression.value.runtime, + .pointer = loaded_array_like, .base_type = array.type, .index = index, }, @@ -4310,6 +4347,38 @@ pub const Builder = struct { .type = gep_type, }; }, + .array => |array| b: { + switch (array_like_expression.value) { + .runtime => |instruction_index| switch (unit.instructions.get(instruction_index).*) { + .stack_slot => {}, + else => |t| @panic(@tagName(t)), + }, + else => |t| @panic(@tagName(t)), + } + + const gep = try unit.instructions.append(context.allocator, .{ + .get_element_pointer = .{ + .pointer = array_like_expression.value.runtime, + .base_type = array.type, + .index = index, + }, + }); + + const gep_type = try unit.getPointerType(context, .{ + .type = array.type, + .termination = .none, + .mutability = .@"var", + .many = false, + .nullable = false, + }); + + break :b .{ + .value = .{ + .runtime = gep, + }, + .type = gep_type, + }; + }, else => |t| @panic(@tagName(t)), }; @@ -4342,6 +4411,7 @@ pub const Builder = struct { break :b unit.types.get(gep.type).pointer.type; }, + .none => unit.types.get(gep.type).pointer.type, else => |t| @panic(@tagName(t)), }, }; diff --git a/bootstrap/backend/llvm.zig b/bootstrap/backend/llvm.zig index 2281b8b..8b0a709 100644 --- a/bootstrap/backend/llvm.zig +++ b/bootstrap/backend/llvm.zig @@ -2459,7 +2459,6 @@ pub const LLVM = struct { } fn emitLeftValue(llvm: *LLVM, unit: *Compilation.Unit, context: *const Compilation.Context, v: Compilation.V) !*LLVM.Value { - _ = context; // autofix switch (v.value) { .runtime => |instruction_index| { if (llvm.llvm_instruction_map.get(instruction_index)) |value| { @@ -2471,6 +2470,17 @@ pub const LLVM = struct { const global_variable = llvm.global_variable_map.get(global_declaration).?; return global_variable.toValue(); }, + .get_element_pointer => |gep| { + const pointer = llvm.llvm_instruction_map.get(gep.pointer).?; + const index = try llvm.emitRightValue(unit, context, gep.index); + const indices = [1]*LLVM.Value{ index }; + const base_type = try llvm.getType(unit, context, gep.base_type); + const in_bounds = true; + const get_element_pointer = llvm.builder.createGEP(base_type, pointer, &indices, indices.len, "gep", "gep".len, in_bounds) orelse unreachable; + try llvm.llvm_value_map.putNoClobber(context.allocator, v, get_element_pointer); + try llvm.llvm_instruction_map.putNoClobber(context.allocator, instruction_index, get_element_pointer); + return get_element_pointer; + }, else => |t| @panic(@tagName(t)), } } @@ -3091,6 +3101,15 @@ pub fn codegen(unit: *Compilation.Unit, context: *const Compilation.Context) !vo const global_variable = llvm.global_variable_map.get(global).?; break :b global_variable.toValue(); }, + .get_element_pointer => |gep| b: { + const index = try llvm.emitRightValue(unit, context, gep.index); + const pointer = llvm.llvm_instruction_map.get(gep.pointer).?; + const t = try llvm.getType(unit, context, gep.base_type); + const indices = [1]*LLVM.Value{index}; + const in_bounds = true; + const get_element_pointer = llvm.builder.createGEP(t, pointer, &indices, indices.len, "gep", "gep".len, in_bounds) orelse unreachable; + break :b get_element_pointer; + }, else => |t| @panic(@tagName(t)), }, else => |t| @panic(@tagName(t)), diff --git a/build/test_runner.zig b/build/test_runner.zig index f4328ed..aabc8d6 100644 --- a/build/test_runner.zig +++ b/build/test_runner.zig @@ -22,7 +22,7 @@ pub fn main() !void { while (try standalone_iterator.next()) |entry| { switch (entry.kind) { - .directory => try standalone_test_names.append(allocator, entry.name), + .directory => try standalone_test_names.append(allocator, try allocator.dupe(u8, entry.name)), else => return error.junk_in_test_directory, } } @@ -38,6 +38,7 @@ pub fn main() !void { const total_test_count = standalone_test_names.items.len; for (standalone_test_names.items) |standalone_test_name| { + std.debug.assert(!std.mem.eql(u8, standalone_test_name, "else_ifrld")); std.debug.print("{s}... ", .{standalone_test_name}); const source_file_path = try std.mem.concat(allocator, u8, &.{standalone_test_dir_path, "/", standalone_test_name, "/main.nat"}); const compile_run = try std.ChildProcess.run(.{ diff --git a/lib/std/std.nat b/lib/std/std.nat index 0ce116e..d6bb3d2 100644 --- a/lib/std/std.nat +++ b/lib/std/std.nat @@ -28,7 +28,9 @@ const format_usize = fn(n: usize, buffer: &[65]u8) []u8 { while (true) { const digit: u8 = #cast(absolute % 10); index -= 1; - buffer[index] = '0' + digit; + const ch = '0' + digit; + buffer[index] = ch; + #assert(buffer[index] == ch); absolute /= 10; if (absolute == 0) { diff --git a/test/standalone/array_pointer_store/main.nat b/test/standalone/array_pointer_store/main.nat new file mode 100644 index 0000000..9eb4251 --- /dev/null +++ b/test/standalone/array_pointer_store/main.nat @@ -0,0 +1,10 @@ +const main = fn () s32 { + const ch = 'a'; + var buffer: [1]u8 = undefined; + var ptr: &[1]u8 = buffer.&; + var index: usize = 0; + ptr[index] = ch; + const sub: u8 = ptr[index] - ch; + const result: u32 = sub; + return #cast(result); +} diff --git a/test/standalone/array_pointer_store_function/main.nat b/test/standalone/array_pointer_store_function/main.nat new file mode 100644 index 0000000..00c7cc7 --- /dev/null +++ b/test/standalone/array_pointer_store_function/main.nat @@ -0,0 +1,14 @@ +const main = fn () s32 { + var buffer: [2]u8 = undefined; + const expected = 'a'; + const index: usize = 1; + foo(buffer.&, index, expected); + const ch = buffer[index]; + const sub = expected - ch; + const result: u32 = sub; + return #cast(result); +} + +const foo = fn (buffer: &[2]u8, index: usize, ch: u8) void { + buffer[index] = ch; +} diff --git a/test/standalone/array_store/main.nat b/test/standalone/array_store/main.nat new file mode 100644 index 0000000..d21022d --- /dev/null +++ b/test/standalone/array_store/main.nat @@ -0,0 +1,9 @@ +const main = fn () s32 { + const ch = 'a'; + var buffer: [1]u8 = undefined; + var index: usize = 0; + buffer[index] = ch; + const sub: u8 = buffer[index] - ch; + const result: u32 = sub; + return #cast(result); +}