diff --git a/src/compiler.bbb b/src/compiler.bbb index f1456f8..51cff58 100644 --- a/src/compiler.bbb +++ b/src/compiler.bbb @@ -70,6 +70,7 @@ os_linux_map_flags = fn(map_flags: OS_MapFlags) OS_Linux_MAP .anonymous = map_flags.anonymous, .no_reserve = map_flags.no_reserve, .populate = map_flags.populate, + zero, }; } diff --git a/src/converter.zig b/src/converter.zig index 3d1cbc3..9ad76b2 100644 --- a/src/converter.zig +++ b/src/converter.zig @@ -1144,6 +1144,7 @@ const StructType = struct { const Bits = struct { fields: []const Field, backing_type: *Type, + implicit_backing_type: bool, }; pub const ArrayType = struct { @@ -1170,6 +1171,7 @@ pub const FloatType = struct { pub const Enumerator = struct { fields: []const Enumerator.Field, backing_type: *Type, + implicit_backing_type: bool, pub const Field = struct { name: []const u8, @@ -2758,9 +2760,11 @@ const Converter = struct { }, .select => { const condition_value = converter.parse_value(module, null, .value); + if (condition_value.type.bb != .integer) { converter.report_error(); } + if (condition_value.type.bb.integer.bit_count != 1) { converter.report_error(); } @@ -3257,7 +3261,7 @@ const Converter = struct { return value; }, - .bits => |*bits| { + .bits => |bits| { var field_count: usize = 0; var llvm_value = bits.backing_type.llvm.handle.to_integer().get_constant(0, @intFromBool(false)).to_value(); @@ -3318,7 +3322,7 @@ const Converter = struct { if (field_count != bits.fields.len) { // expect: 'zero' keyword - if (zero) { + if (zero or bits.implicit_backing_type) { // TODO: should we do anything? } else { @trap(); @@ -3542,10 +3546,18 @@ const Converter = struct { } const value = module.values.add(); + value.* = .{ - .type = bits.backing_type, - .llvm = bitfield_masked, .bb = .instruction, + .llvm = switch (bits.backing_type == field.type) { + true => bitfield_masked, + false => blk: { + assert(bits.backing_type.get_bit_size() > field.type.get_bit_size()); + const trunc = module.llvm.builder.create_truncate(bitfield_masked, field.type.llvm.handle); + break :blk trunc; + }, + }, + .type = field.type, .lvalue = false, .dereference_to_assign = false, }; @@ -5516,6 +5528,7 @@ pub noinline fn convert(arena: *Arena, options: ConvertOptions) void { .bits = .{ .fields = fields, .backing_type = backing_type, + .implicit_backing_type = is_implicit_type, }, }, }); @@ -5604,6 +5617,7 @@ pub noinline fn convert(arena: *Arena, options: ConvertOptions) void { .enumerator = .{ .backing_type = backing_type, .fields = fields, + .implicit_backing_type = is_implicit_type, }, }, .llvm = .{ diff --git a/src/converter_test.zig b/src/converter_test.zig index 5a51a1e..bf03b6e 100644 --- a/src/converter_test.zig +++ b/src/converter_test.zig @@ -396,3 +396,7 @@ test "struct_zero" { test "select" { try invsrc(@src()); } + +test "bits_return_u1" { + try invsrc(@src()); +} diff --git a/tests/bits_return_u1.bbb b/tests/bits_return_u1.bbb new file mode 100644 index 0000000..af251ce --- /dev/null +++ b/tests/bits_return_u1.bbb @@ -0,0 +1,17 @@ +S = bits u32 +{ + a: u1, + b: u1, + c: u1, +} + +foo = fn () u1 +{ + >a: S = { .a = 1, .b = 1, .c = 0 }; + return a.c; +} + +[export] main = fn [cc(c)] () s32 +{ + return #extend(foo() == 1); +}