Bits 'zero'

This commit is contained in:
David Gonzalez Martin 2025-03-23 20:20:59 +01:00
parent 4fa1ba260a
commit 209aae6959
3 changed files with 129 additions and 44 deletions

View File

@ -2950,6 +2950,12 @@ const Converter = struct {
@trap();
}
const ValueKeyword = enum {
@"_",
undefined,
zero,
};
fn parse_single_value(noalias converter: *Converter, noalias module: *Module, expected_type: ?*Type, value_kind: ValueKind) *Value {
converter.skip_space();
@ -3121,45 +3127,68 @@ const Converter = struct {
var llvm_value = bits.backing_type.llvm.handle.to_integer().get_constant(0, @intFromBool(false)).to_value();
while (converter.consume_character_if_match('.')) : (field_count += 1) {
var zero = false;
while (true) : (field_count += 1) {
converter.skip_space();
const field_name = converter.parse_identifier();
const field_index: u32 = for (bits.fields, 0..) |*field, field_index| {
if (lib.string.equal(field.name, field_name)) {
break @intCast(field_index);
if (converter.consume_character_if_match(right_brace)) {
break;
} else if (converter.consume_character_if_match('.')) {
const field_name = converter.parse_identifier();
const field_index: u32 = for (bits.fields, 0..) |*field, field_index| {
if (lib.string.equal(field.name, field_name)) {
break @intCast(field_index);
}
} else converter.report_error();
const field = bits.fields[field_index];
converter.skip_space();
converter.expect_character('=');
converter.skip_space();
const field_value = converter.parse_value(module, field.type, .value);
const extended_field_value = module.llvm.builder.create_zero_extend(field_value.llvm, bits.backing_type.llvm.handle);
const shifted_value = module.llvm.builder.create_shl(extended_field_value, bits.backing_type.llvm.handle.to_integer().get_constant(field.bit_offset, @intFromBool(false)).to_value());
const or_value = module.llvm.builder.create_or(llvm_value, shifted_value);
llvm_value = or_value;
converter.skip_space();
_ = converter.consume_character_if_match(',');
converter.skip_space();
} else {
const identifier = converter.parse_identifier();
if (string_to_enum(ValueKeyword, identifier)) |value_keyword| switch (value_keyword) {
._ => converter.report_error(),
.undefined => @trap(),
.zero => {
zero = true;
converter.skip_space();
_ = converter.consume_character_if_match(',');
converter.skip_space();
converter.expect_character(right_brace);
break;
},
} else {
converter.report_error();
}
} else converter.report_error();
const field = bits.fields[field_index];
converter.skip_space();
converter.expect_character('=');
converter.skip_space();
const field_value = converter.parse_value(module, field.type, .value);
const extended_field_value = module.llvm.builder.create_zero_extend(field_value.llvm, bits.backing_type.llvm.handle);
const shifted_value = module.llvm.builder.create_shl(extended_field_value, bits.backing_type.llvm.handle.to_integer().get_constant(field.bit_offset, @intFromBool(false)).to_value());
const or_value = module.llvm.builder.create_or(llvm_value, shifted_value);
llvm_value = or_value;
converter.skip_space();
_ = converter.consume_character_if_match(',');
converter.skip_space();
}
}
if (field_count != bits.fields.len) {
// expect: 'zero' keyword
@trap();
if (zero) {
// TODO: should we do anything?
} else {
@trap();
}
}
converter.expect_character(right_brace);
const value = module.values.add();
value.* = .{
.llvm = llvm_value,
@ -3293,20 +3322,37 @@ const Converter = struct {
'a'...'z', 'A'...'Z', '_' => b: {
if (module.current_function) |current_function| {
const identifier = converter.parse_identifier();
if (lib.string.equal(identifier, "_")) {
return module.get_infer_or_ignore_value();
} else if (lib.string.equal(identifier, "undefined")) {
const expected_ty = expected_type orelse converter.report_error();
// TODO: cache poison
const value = module.values.add();
value.* = .{
.llvm = expected_ty.llvm.handle.get_poison(),
.type = expected_ty,
.bb = .instruction, // TODO
.lvalue = false,
.dereference_to_assign = false,
};
return value;
if (string_to_enum(ValueKeyword, identifier)) |value_keyword| switch (value_keyword) {
._ => return module.get_infer_or_ignore_value(),
.undefined => {
const expected_ty = expected_type orelse converter.report_error();
// TODO: cache poison
const value = module.values.add();
value.* = .{
.llvm = expected_ty.llvm.handle.get_poison(),
.type = expected_ty,
.bb = .instruction, // TODO
.lvalue = false,
.dereference_to_assign = false,
};
return value;
},
.zero => {
const ty = expected_type orelse converter.report_error();
const value = module.values.add();
value.* = switch (ty.bb) {
.bits => |bits| .{
.llvm = bits.backing_type.llvm.handle.to_integer().get_constant(0, @intFromBool(false)).to_value(),
.lvalue = false,
.dereference_to_assign = false,
.type = ty,
.bb = .bits_initialization,
},
else => @trap(),
};
return value;
},
} else {
const variable = if (current_function.value.bb.function.locals.find(identifier)) |local| local else if (current_function.value.bb.function.arguments.find(identifier)) |argument| argument else if (module.globals.find(identifier)) |global| global else converter.report_error();

View File

@ -384,3 +384,7 @@ test "basic_enum" {
test "return_type_builtin" {
try invsrc(@src());
}
test "bits_zero" {
try invsrc(@src());
}

35
tests/bits_zero.bbb Normal file
View File

@ -0,0 +1,35 @@
require = fn (ok: u1) void
{
if (!ok)
{
#trap();
}
}
S = bits
{
a: u1,
b: u1,
c: u1,
}
[export] main = fn () s32
{
>a: S = zero;
require(a.a == 0);
require(a.b == 0);
require(a.c == 0);
>b: S = {
.a = 1,
.b = 1,
zero,
};
require(b.a == 1);
require(b.b == 1);
require(b.c == 0);
return 0;
}