Merge pull request #162 from birth-software/trailing-zeroes
Trailing zeroes
This commit is contained in:
commit
887bcc676c
@ -3670,6 +3670,7 @@ pub const Instruction = union(enum) {
|
|||||||
integer_compare: IntegerCompare,
|
integer_compare: IntegerCompare,
|
||||||
integer_binary_operation: Instruction.IntegerBinaryOperation,
|
integer_binary_operation: Instruction.IntegerBinaryOperation,
|
||||||
jump: Jump,
|
jump: Jump,
|
||||||
|
leading_zeroes: V,
|
||||||
load: Load,
|
load: Load,
|
||||||
memcpy: Memcpy,
|
memcpy: Memcpy,
|
||||||
umin: Min,
|
umin: Min,
|
||||||
@ -3683,6 +3684,7 @@ pub const Instruction = union(enum) {
|
|||||||
store: Store,
|
store: Store,
|
||||||
syscall: Syscall,
|
syscall: Syscall,
|
||||||
@"switch": Switch,
|
@"switch": Switch,
|
||||||
|
trailing_zeroes: V,
|
||||||
trap,
|
trap,
|
||||||
@"unreachable",
|
@"unreachable",
|
||||||
|
|
||||||
@ -4375,11 +4377,13 @@ pub const IntrinsicId = enum {
|
|||||||
@"error",
|
@"error",
|
||||||
int_to_pointer,
|
int_to_pointer,
|
||||||
import,
|
import,
|
||||||
|
leading_zeroes,
|
||||||
min,
|
min,
|
||||||
name,
|
name,
|
||||||
size,
|
size,
|
||||||
sign_extend,
|
sign_extend,
|
||||||
syscall,
|
syscall,
|
||||||
|
trailing_zeroes,
|
||||||
trap,
|
trap,
|
||||||
zero_extend,
|
zero_extend,
|
||||||
};
|
};
|
||||||
@ -4964,6 +4968,36 @@ pub const Builder = struct {
|
|||||||
else => |t| @panic(@tagName(t)),
|
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)),
|
else => |t| @panic(@tagName(t)),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -8667,6 +8701,7 @@ pub const Builder = struct {
|
|||||||
const field_node = unit.getNode(field_node_index);
|
const field_node = unit.getNode(field_node_index);
|
||||||
const identifier = switch (unit.getTokenId(field_node.token)) {
|
const identifier = switch (unit.getTokenId(field_node.token)) {
|
||||||
.identifier => unit.getExpectedTokenBytes(field_node.token, .identifier),
|
.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: {
|
.discard => try std.mem.concat(context.allocator, u8, &.{ "_", &.{'0' + b: {
|
||||||
const ch = '0' + ignore_field_count;
|
const ch = '0' + ignore_field_count;
|
||||||
ignore_field_count += 1;
|
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 {
|
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 node = unit.getNode(node_index);
|
||||||
const right_node = unit.getNode(node.right);
|
const right_node = unit.getNode(node.right);
|
||||||
assert(right_node.id == .identifier);
|
const identifier = switch (right_node.id) {
|
||||||
const identifier = unit.getExpectedTokenBytes(right_node.token, .identifier);
|
.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 identifier_hash = try unit.processIdentifier(context, identifier);
|
||||||
|
|
||||||
const left_node_index = node.left;
|
const left_node_index = node.left;
|
||||||
|
@ -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);
|
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);
|
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| {
|
.@"switch" => |switch_expression| {
|
||||||
const condition = try llvm.emitRightValue(unit, context, switch_expression.condition);
|
const condition = try llvm.emitRightValue(unit, context, switch_expression.condition);
|
||||||
const else_block: ?*LLVM.Value.BasicBlock = if (switch_expression.else_block != .null) b: {
|
const else_block: ?*LLVM.Value.BasicBlock = if (switch_expression.else_block != .null) b: {
|
||||||
|
@ -1208,6 +1208,7 @@ const Analyzer = struct {
|
|||||||
.discard,
|
.discard,
|
||||||
.fixed_keyword_test,
|
.fixed_keyword_test,
|
||||||
.fixed_keyword_break,
|
.fixed_keyword_break,
|
||||||
|
.fixed_keyword_while,
|
||||||
=> break,
|
=> break,
|
||||||
.operator_compare_equal => .compare_equal,
|
.operator_compare_equal => .compare_equal,
|
||||||
.operator_compare_not_equal => .compare_not_equal,
|
.operator_compare_not_equal => .compare_not_equal,
|
||||||
@ -2276,6 +2277,24 @@ const Analyzer = struct {
|
|||||||
.right = Node.Index.null,
|
.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(.{
|
.operator_ampersand => try analyzer.addNode(.{
|
||||||
.id = .address_of,
|
.id = .address_of,
|
||||||
.token = blk: {
|
.token = blk: {
|
||||||
|
@ -53,10 +53,12 @@ fn runStandalone(allocator: Allocator, args: struct {
|
|||||||
for (test_names) |test_name| {
|
for (test_names) |test_name| {
|
||||||
std.debug.print("{s}... ", .{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 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(.{
|
const compile_run = try std.ChildProcess.run(.{
|
||||||
.allocator = allocator,
|
.allocator = allocator,
|
||||||
// TODO: delete -main_source_file?
|
// 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),
|
.max_output_bytes = std.math.maxInt(u64),
|
||||||
});
|
});
|
||||||
ran_compilation_count += 1;
|
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_path = try std.mem.concat(allocator, u8, &.{ "nat/", test_name });
|
||||||
const test_run = try std.ChildProcess.run(.{
|
const test_run = try std.ChildProcess.run(.{
|
||||||
.allocator = allocator,
|
.allocator = allocator,
|
||||||
// TODO: delete -main_source_file?
|
|
||||||
.argv = &.{test_path},
|
.argv = &.{test_path},
|
||||||
.max_output_bytes = std.math.maxInt(u64),
|
.max_output_bytes = std.math.maxInt(u64),
|
||||||
});
|
});
|
||||||
|
18
src/main.nat
18
src/main.nat
@ -20,15 +20,31 @@ const lex = fn (arena: &Arena, bytes: []const u8) *!void {
|
|||||||
// var i = index;
|
// var i = index;
|
||||||
// const top = index + max_initial_keyword_len + 1;
|
// const top = index + max_initial_keyword_len + 1;
|
||||||
// var space: u32 = 0;
|
// var space: u32 = 0;
|
||||||
|
|
||||||
// while (i < top) {
|
// while (i < top) {
|
||||||
// const is_space = bytes[i] == ' ';
|
// 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;
|
// i += 1;
|
||||||
// }
|
// }
|
||||||
|
|
||||||
// if (space == 0) {
|
// if (space == 0) {
|
||||||
// unreachable;
|
// 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;
|
||||||
//}
|
//}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
8
test/standalone/trailing_zeroes/main.nat
Normal file
8
test/standalone/trailing_zeroes/main.nat
Normal 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);
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user