Trailing zeroes

This commit is contained in:
David Gonzalez Martin 2024-04-23 08:08:08 -06:00
parent c5712d4f3a
commit 03e2d6798f
6 changed files with 96 additions and 5 deletions

View File

@ -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;

View File

@ -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", &parameter_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", &parameter_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: {

View File

@ -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: {

View File

@ -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),
});

View File

@ -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;
//}
}

View File

@ -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);
}