From 03e2d6798f2ac18348ec56bfdad96fbb371866ff Mon Sep 17 00:00:00 2001 From: David Gonzalez Martin Date: Tue, 23 Apr 2024 08:08:08 -0600 Subject: [PATCH] Trailing zeroes --- bootstrap/Compilation.zig | 42 ++++++++++++++++++++++-- bootstrap/backend/llvm.zig | 9 +++++ bootstrap/frontend/parser.zig | 19 +++++++++++ build/test_runner.zig | 5 +-- src/main.nat | 18 +++++++++- test/standalone/trailing_zeroes/main.nat | 8 +++++ 6 files changed, 96 insertions(+), 5 deletions(-) create mode 100644 test/standalone/trailing_zeroes/main.nat diff --git a/bootstrap/Compilation.zig b/bootstrap/Compilation.zig index 571bce8..8f723fe 100644 --- a/bootstrap/Compilation.zig +++ b/bootstrap/Compilation.zig @@ -3670,6 +3670,7 @@ pub const Instruction = union(enum) { integer_compare: IntegerCompare, integer_binary_operation: Instruction.IntegerBinaryOperation, jump: Jump, + leading_zeroes: V, load: Load, memcpy: Memcpy, umin: Min, @@ -3683,6 +3684,7 @@ pub const Instruction = union(enum) { store: Store, syscall: Syscall, @"switch": Switch, + trailing_zeroes: V, trap, @"unreachable", @@ -4375,11 +4377,13 @@ pub const IntrinsicId = enum { @"error", int_to_pointer, import, + leading_zeroes, min, name, size, sign_extend, syscall, + trailing_zeroes, trap, zero_extend, }; @@ -4964,6 +4968,36 @@ pub const Builder = struct { else => |t| @panic(@tagName(t)), } }, + .trailing_zeroes => { + assert(argument_node_list.len == 1); + const argument = try builder.resolveRuntimeValue(unit, context, Type.Expect.none, argument_node_list[0], .right); + const trailing_zeroes = try unit.instructions.append(context.my_allocator, .{ + .trailing_zeroes = argument, + }); + try builder.appendInstruction(unit, context, trailing_zeroes); + + return V{ + .type = argument.type, + .value = .{ + .runtime = trailing_zeroes, + }, + }; + }, + .leading_zeroes => { + assert(argument_node_list.len == 1); + const argument = try builder.resolveRuntimeValue(unit, context, Type.Expect.none, argument_node_list[0], .right); + const leading_zeroes = try unit.instructions.append(context.my_allocator, .{ + .leading_zeroes = argument, + }); + try builder.appendInstruction(unit, context, leading_zeroes); + + return V{ + .type = argument.type, + .value = .{ + .runtime = leading_zeroes, + }, + }; + }, else => |t| @panic(@tagName(t)), } } @@ -8667,6 +8701,7 @@ pub const Builder = struct { const field_node = unit.getNode(field_node_index); const identifier = switch (unit.getTokenId(field_node.token)) { .identifier => unit.getExpectedTokenBytes(field_node.token, .identifier), + .string_literal => try unit.fixupStringLiteral(context, field_node.token), .discard => try std.mem.concat(context.allocator, u8, &.{ "_", &.{'0' + b: { const ch = '0' + ignore_field_count; ignore_field_count += 1; @@ -15060,8 +15095,11 @@ pub const Builder = struct { fn resolveFieldAccess(builder: *Builder, unit: *Unit, context: *const Context, type_expect: Type.Expect, node_index: Node.Index, side: Side, new_parameters: []const V.Comptime) !V { const node = unit.getNode(node_index); const right_node = unit.getNode(node.right); - assert(right_node.id == .identifier); - const identifier = unit.getExpectedTokenBytes(right_node.token, .identifier); + const identifier = switch (right_node.id) { + .identifier => unit.getExpectedTokenBytes(right_node.token, .identifier), + .string_literal => try unit.fixupStringLiteral(context, right_node.token), + else => |t| @panic(@tagName(t)), + }; const identifier_hash = try unit.processIdentifier(context, identifier); const left_node_index = node.left; diff --git a/bootstrap/backend/llvm.zig b/bootstrap/backend/llvm.zig index a98111d..c3db85e 100644 --- a/bootstrap/backend/llvm.zig +++ b/bootstrap/backend/llvm.zig @@ -3110,6 +3110,15 @@ pub fn codegen(unit: *Compilation.Unit, context: *const Compilation.Context) !vo const intrinsic_call = try llvm.callIntrinsic("llvm.sadd.with.overflow", ¶meter_types, &arguments); try llvm.llvm_instruction_map.put_no_clobber(context.my_allocator, instruction_index, intrinsic_call); }, + .trailing_zeroes => |v| { + const intrinsic_type = try llvm.getType(unit, context, v.type); + const parameter_types = [_]*LLVM.Type{intrinsic_type}; + const value = try llvm.emitRightValue(unit, context, v); + const is_poison = llvm.context.getConstantInt(1, 0, false) orelse unreachable; + const arguments = [_]*LLVM.Value{ value, is_poison.toValue() }; + const intrinsic_call = try llvm.callIntrinsic("llvm.cttz", ¶meter_types, &arguments); + try llvm.llvm_instruction_map.put_no_clobber(context.my_allocator, instruction_index, intrinsic_call); + }, .@"switch" => |switch_expression| { const condition = try llvm.emitRightValue(unit, context, switch_expression.condition); const else_block: ?*LLVM.Value.BasicBlock = if (switch_expression.else_block != .null) b: { diff --git a/bootstrap/frontend/parser.zig b/bootstrap/frontend/parser.zig index 6e22306..78c1a0e 100644 --- a/bootstrap/frontend/parser.zig +++ b/bootstrap/frontend/parser.zig @@ -1208,6 +1208,7 @@ const Analyzer = struct { .discard, .fixed_keyword_test, .fixed_keyword_break, + .fixed_keyword_while, => break, .operator_compare_equal => .compare_equal, .operator_compare_not_equal => .compare_not_equal, @@ -2276,6 +2277,24 @@ const Analyzer = struct { .right = Node.Index.null, }), }), + .string_literal => try analyzer.addNode(.{ + .id = .field_access, + .token = blk: { + analyzer.consumeToken(); + break :blk token; + }, + .left = left, + .right = try analyzer.addNode(.{ + .id = .string_literal, + .token = blk: { + const t = analyzer.token_i; + analyzer.consumeToken(); + break :blk t; + }, + .left = Node.Index.null, + .right = Node.Index.null, + }), + }), .operator_ampersand => try analyzer.addNode(.{ .id = .address_of, .token = blk: { diff --git a/build/test_runner.zig b/build/test_runner.zig index 5744178..3825a8e 100644 --- a/build/test_runner.zig +++ b/build/test_runner.zig @@ -53,10 +53,12 @@ fn runStandalone(allocator: Allocator, args: struct { for (test_names) |test_name| { std.debug.print("{s}... ", .{test_name}); const source_file_path = try std.mem.concat(allocator, u8, &.{ args.directory_path, "/", test_name, "/main.nat" }); + const argv: []const []const u8 = &.{ args.compiler_path, if (args.is_test) "test" else "exe", "-main_source_file", source_file_path }; + // if (std.mem.eql(u8, args.compiler_path, "nat/compiler_lightly_optimize_for_speed")) @breakpoint(); const compile_run = try std.ChildProcess.run(.{ .allocator = allocator, // TODO: delete -main_source_file? - .argv = &.{ args.compiler_path, if (args.is_test) "test" else "exe", "-main_source_file", source_file_path }, + .argv = argv, .max_output_bytes = std.math.maxInt(u64), }); ran_compilation_count += 1; @@ -85,7 +87,6 @@ fn runStandalone(allocator: Allocator, args: struct { const test_path = try std.mem.concat(allocator, u8, &.{ "nat/", test_name }); const test_run = try std.ChildProcess.run(.{ .allocator = allocator, - // TODO: delete -main_source_file? .argv = &.{test_path}, .max_output_bytes = std.math.maxInt(u64), }); diff --git a/src/main.nat b/src/main.nat index 57695d8..032ccb7 100644 --- a/src/main.nat +++ b/src/main.nat @@ -20,15 +20,31 @@ const lex = fn (arena: &Arena, bytes: []const u8) *!void { // var i = index; // const top = index + max_initial_keyword_len + 1; // var space: u32 = 0; + // while (i < top) { // const is_space = bytes[i] == ' '; - // space |= #cast( + // const is_space_int: u32 = #cast(is_space); + // const space_mask = 0 -% is_space_int; + // space |= (1 << i) & space_mask; // i += 1; // } // if (space == 0) { // unreachable; // } + + // const word_byte_count = #trailing_zeroes(space); + // const word = bytes[index..][0..word_byte_count]; + + // if (byte_equal(word, #name(FileStartToken."comptime"))) { + // } else if (byte_equal(word, #name(FileStartToken."test"))) { + // } else if (byte_equal(word, #name(FileStartToken."const"))) { + // } else if (byte_equal(word, #name(FileStartToken."var"))) { + // } else { + // print("Wrong file declaration start\n"); + // } + + // break; //} } diff --git a/test/standalone/trailing_zeroes/main.nat b/test/standalone/trailing_zeroes/main.nat new file mode 100644 index 0000000..cd541c6 --- /dev/null +++ b/test/standalone/trailing_zeroes/main.nat @@ -0,0 +1,8 @@ +const std = #import("std"); +const expect = std.testing.expect; +const main = fn () *!void { + var a: u32 = 7; + try expect(#trailing_zeroes(a) == 0); + a = 8; + try expect(#trailing_zeroes(a) == 3); +}