Basic enum support
This commit is contained in:
parent
c1f0c64757
commit
0a778aa94f
10
src/LLVM.zig
10
src/LLVM.zig
@ -1245,6 +1245,14 @@ pub const DI = struct {
|
||||
pub fn create_pointer_type(builder: *DI.Builder, element_type: *DI.Type, bit_size: u64, align_in_bits: u32, address_space: c_uint, name: []const u8) *DI.Type.Derived {
|
||||
return api.LLVMDIBuilderCreatePointerType(builder, element_type, bit_size, align_in_bits, address_space, name.ptr, name.len);
|
||||
}
|
||||
|
||||
pub fn create_enumerator(builder: *DI.Builder, name: []const u8, value: i64, is_signed: bool) *DI.Enumerator {
|
||||
return api.LLVMDIBuilderCreateEnumerator(builder, name.ptr, name.len, value, @intFromBool(is_signed));
|
||||
}
|
||||
|
||||
pub fn create_enumeration_type(builder: *DI.Builder, scope: *DI.Scope, name: []const u8, file: *DI.File, line: c_uint, bit_size: u64, align_in_bits: u32, enumeration_types: []const *DI.Enumerator, backing_type: *DI.Type) *DI.Type.Composite {
|
||||
return api.LLVMDIBuilderCreateEnumerationType(builder, scope, name.ptr, name.len, file, line, bit_size, align_in_bits, enumeration_types.ptr, @intCast(enumeration_types.len), backing_type);
|
||||
}
|
||||
};
|
||||
|
||||
pub const create_debug_location = api.LLVMDIBuilderCreateDebugLocation;
|
||||
@ -1293,6 +1301,8 @@ pub const DI = struct {
|
||||
};
|
||||
};
|
||||
|
||||
pub const Enumerator = opaque {};
|
||||
|
||||
pub const Flags = packed struct(u32) {
|
||||
visibility: Visibility = .none,
|
||||
forward_declaration: bool = false,
|
||||
|
@ -1,3 +1,12 @@
|
||||
Linux_PROT = bits u32
|
||||
{
|
||||
read: u1,
|
||||
write: u1,
|
||||
exec: u1,
|
||||
sem: u1,
|
||||
_: u28,
|
||||
}
|
||||
|
||||
OSProtectionFlags = bits
|
||||
{
|
||||
read: u1,
|
||||
@ -13,6 +22,10 @@ OSMapFlags = bits
|
||||
populate: u1,
|
||||
}
|
||||
|
||||
os_reserve = fn (base: u64, protection: OSProtectionFlags, map: OSMapFlags) &u8
|
||||
{
|
||||
}
|
||||
|
||||
Arena = struct
|
||||
{
|
||||
reserved_size: u64,
|
||||
|
@ -68,6 +68,7 @@ const GlobalKind = enum {
|
||||
@"fn",
|
||||
@"struct",
|
||||
bits,
|
||||
@"enum",
|
||||
};
|
||||
|
||||
const FunctionKeyword = enum {
|
||||
@ -1112,7 +1113,15 @@ pub const FloatType = struct {
|
||||
kind: Kind,
|
||||
};
|
||||
|
||||
pub const Enumerator = struct {};
|
||||
pub const Enumerator = struct {
|
||||
fields: []const Enumerator.Field,
|
||||
backing_type: *Type,
|
||||
|
||||
pub const Field = struct {
|
||||
name: []const u8,
|
||||
value: u64,
|
||||
};
|
||||
};
|
||||
|
||||
pub const PointerType = struct {
|
||||
type: *Type,
|
||||
@ -1205,7 +1214,7 @@ pub const Type = struct {
|
||||
pub fn get_evaluation_kind(ty: *const Type) EvaluationKind {
|
||||
return switch (ty.bb) {
|
||||
.structure, .array => .aggregate,
|
||||
.integer, .bits, .pointer => .scalar,
|
||||
.integer, .bits, .pointer, .enumerator => .scalar,
|
||||
else => @trap(),
|
||||
};
|
||||
}
|
||||
@ -1263,9 +1272,9 @@ pub const Type = struct {
|
||||
.bits => |bits| bits.backing_type.get_byte_alignment(),
|
||||
.function => 1,
|
||||
.void, .forward_declaration, .noreturn => unreachable,
|
||||
.array => |*array| array.element_type.get_byte_alignment(),
|
||||
.array => |array| array.element_type.get_byte_alignment(),
|
||||
.pointer => 8,
|
||||
.enumerator => @trap(),
|
||||
.enumerator => |enumerator| enumerator.backing_type.get_byte_alignment(),
|
||||
.float => @trap(),
|
||||
.vector => @trap(),
|
||||
};
|
||||
@ -1547,7 +1556,7 @@ const Converter = struct {
|
||||
return value;
|
||||
}
|
||||
|
||||
fn parse_integer(noalias converter: *Converter, noalias module: *Module, expected_type: *Type, sign: bool) *Value {
|
||||
fn parse_integer_value(converter: *Converter, sign: bool) u64 {
|
||||
const start = converter.offset;
|
||||
const integer_start_ch = converter.content[start];
|
||||
assert(!is_space(integer_start_ch));
|
||||
@ -1589,6 +1598,12 @@ const Converter = struct {
|
||||
else => unreachable,
|
||||
};
|
||||
|
||||
return absolute_value;
|
||||
}
|
||||
|
||||
fn parse_integer(noalias converter: *Converter, noalias module: *Module, expected_type: *Type, sign: bool) *Value {
|
||||
const absolute_value = converter.parse_integer_value(sign);
|
||||
|
||||
const value: u64 = switch (sign) {
|
||||
true => @bitCast(-@as(i64, @intCast(absolute_value))),
|
||||
false => absolute_value,
|
||||
@ -2565,6 +2580,7 @@ const Converter = struct {
|
||||
cast,
|
||||
cast_to,
|
||||
extend,
|
||||
int_from_enum,
|
||||
trap,
|
||||
truncate,
|
||||
va_start,
|
||||
@ -2661,6 +2677,29 @@ const Converter = struct {
|
||||
|
||||
return value;
|
||||
},
|
||||
.int_from_enum => {
|
||||
const source_value = converter.parse_value(module, null, .value);
|
||||
converter.skip_space();
|
||||
converter.expect_character(right_parenthesis);
|
||||
if (source_value.type.bb != .enumerator) {
|
||||
converter.report_error();
|
||||
}
|
||||
const original_target_type = source_value.type.bb.enumerator.backing_type;
|
||||
const target_type = expected_type orelse original_target_type;
|
||||
|
||||
if (target_type.bb != .integer) {
|
||||
converter.report_error();
|
||||
}
|
||||
|
||||
if (target_type.get_bit_size() < original_target_type.get_bit_size()) {
|
||||
converter.report_error();
|
||||
}
|
||||
|
||||
const value = module.values.add();
|
||||
value.* = source_value.*;
|
||||
value.type = target_type;
|
||||
return value;
|
||||
},
|
||||
.trap => {
|
||||
converter.expect_character(right_parenthesis);
|
||||
|
||||
@ -3184,6 +3223,38 @@ const Converter = struct {
|
||||
converter.skip_space();
|
||||
break :blk .not_zero;
|
||||
},
|
||||
'.' => {
|
||||
const expected_ty = expected_type orelse converter.report_error();
|
||||
if (expected_ty.bb != .enumerator) {
|
||||
converter.report_error();
|
||||
}
|
||||
converter.offset += 1;
|
||||
|
||||
converter.skip_space();
|
||||
const field_name = converter.parse_identifier();
|
||||
const field_value = for (expected_ty.bb.enumerator.fields) |*field| {
|
||||
if (lib.string.equal(field.name, field_name)) {
|
||||
break field.value;
|
||||
}
|
||||
} else {
|
||||
converter.report_error();
|
||||
};
|
||||
const value = module.values.add();
|
||||
value.* = .{
|
||||
.bb = .{
|
||||
.constant_integer = .{
|
||||
.value = field_value,
|
||||
.signed = false,
|
||||
},
|
||||
},
|
||||
.llvm = expected_ty.llvm.handle.to_integer().get_constant(field_value, @intFromBool(false)).to_value(),
|
||||
.type = expected_ty,
|
||||
.lvalue = false,
|
||||
.dereference_to_assign = false,
|
||||
};
|
||||
|
||||
return value;
|
||||
},
|
||||
else => os.abort(),
|
||||
};
|
||||
|
||||
@ -4459,8 +4530,7 @@ pub noinline fn convert(arena: *Arena, options: ConvertOptions) void {
|
||||
const global_string = converter.parse_identifier();
|
||||
converter.skip_space();
|
||||
|
||||
if (string_to_enum(GlobalKind, global_string)) |global_kind| {
|
||||
switch (global_kind) {
|
||||
if (string_to_enum(GlobalKind, global_string)) |global_kind| switch (global_kind) {
|
||||
.@"fn" => {
|
||||
var calling_convention = CallingConvention.c;
|
||||
const function_attributes = Function.Attributes{};
|
||||
@ -5151,8 +5221,8 @@ pub noinline fn convert(arena: *Arena, options: ConvertOptions) void {
|
||||
};
|
||||
},
|
||||
.bits => {
|
||||
const allow_implicit_type = converter.content[converter.offset] == left_brace;
|
||||
const maybe_backing_type: ?*Type = switch (allow_implicit_type) {
|
||||
const is_implicit_type = converter.content[converter.offset] == left_brace;
|
||||
const maybe_backing_type: ?*Type = switch (is_implicit_type) {
|
||||
true => null,
|
||||
false => converter.parse_type(module),
|
||||
};
|
||||
@ -5249,7 +5319,99 @@ pub noinline fn convert(arena: *Arena, options: ConvertOptions) void {
|
||||
},
|
||||
});
|
||||
},
|
||||
.@"enum" => {
|
||||
const is_implicit_type = converter.content[converter.offset] == left_brace;
|
||||
const maybe_backing_type: ?*Type = switch (is_implicit_type) {
|
||||
true => null,
|
||||
false => converter.parse_type(module),
|
||||
};
|
||||
|
||||
converter.skip_space();
|
||||
|
||||
converter.expect_character(left_brace);
|
||||
|
||||
var highest_value: u64 = 0;
|
||||
var lowest_value = ~@as(u64, 0);
|
||||
|
||||
var field_buffer: [64]Enumerator.Field = undefined;
|
||||
var field_count: u64 = 0;
|
||||
|
||||
while (true) : (field_count += 1) {
|
||||
converter.skip_space();
|
||||
|
||||
if (converter.consume_character_if_match(right_brace)) {
|
||||
break;
|
||||
}
|
||||
|
||||
const field_index = field_count;
|
||||
const field_name = converter.parse_identifier();
|
||||
converter.skip_space();
|
||||
|
||||
const field_value = if (converter.consume_character_if_match('=')) blk: {
|
||||
converter.skip_space();
|
||||
const field_value = converter.parse_integer_value(false);
|
||||
break :blk field_value;
|
||||
} else {
|
||||
@trap();
|
||||
};
|
||||
|
||||
field_buffer[field_index] = .{
|
||||
.name = field_name,
|
||||
.value = field_value,
|
||||
};
|
||||
|
||||
highest_value = @max(highest_value, field_value);
|
||||
lowest_value = @min(lowest_value, field_value);
|
||||
|
||||
converter.skip_space();
|
||||
converter.expect_character(',');
|
||||
}
|
||||
|
||||
converter.skip_space();
|
||||
|
||||
_ = converter.consume_character_if_match(';');
|
||||
|
||||
const backing_type = maybe_backing_type orelse blk: {
|
||||
const bits_needed = 64 - @clz(highest_value);
|
||||
const int_type = module.integer_type(bits_needed, false);
|
||||
break :blk int_type;
|
||||
};
|
||||
|
||||
if (maybe_backing_type) |bt| {
|
||||
const bits_needed = 64 - @clz(highest_value);
|
||||
if (bits_needed > bt.get_bit_size()) {
|
||||
converter.report_error();
|
||||
}
|
||||
}
|
||||
|
||||
const fields = arena.allocate(Enumerator.Field, field_count);
|
||||
@memcpy(fields, field_buffer[0..field_count]);
|
||||
|
||||
const debug_type = if (module.llvm.di_builder) |di_builder| blk: {
|
||||
var enumerator_buffer: [64]*llvm.DI.Enumerator = undefined;
|
||||
const enumerators = enumerator_buffer[0..field_count];
|
||||
for (enumerators, fields) |*enumerator_pointer, *field| {
|
||||
enumerator_pointer.* = di_builder.create_enumerator(field.name, @bitCast(field.value), false);
|
||||
}
|
||||
const alignment = 0; // TODO
|
||||
const enumeration_type = di_builder.create_enumeration_type(module.llvm.global_scope, global_name, module.llvm.file, global_line, backing_type.get_bit_size(), alignment, enumerators, backing_type.llvm.debug);
|
||||
break :blk enumeration_type.to_type();
|
||||
} else undefined;
|
||||
|
||||
_ = module.types.add(.{
|
||||
.bb = .{
|
||||
.enumerator = .{
|
||||
.backing_type = backing_type,
|
||||
.fields = fields,
|
||||
},
|
||||
},
|
||||
.llvm = .{
|
||||
.handle = backing_type.llvm.handle,
|
||||
.debug = debug_type,
|
||||
},
|
||||
.name = global_name,
|
||||
});
|
||||
},
|
||||
} else {
|
||||
converter.report_error();
|
||||
}
|
||||
|
@ -376,3 +376,7 @@ test "byte_size" {
|
||||
test "bits_no_backing_type" {
|
||||
try invsrc(@src());
|
||||
}
|
||||
|
||||
test "basic_enum" {
|
||||
try invsrc(@src());
|
||||
}
|
||||
|
@ -216,6 +216,8 @@ pub extern fn LLVMDIBuilderCreateStructType(builder: *llvm.DI.Builder, scope: *l
|
||||
pub extern fn LLVMDIBuilderCreateMemberType(builder: *llvm.DI.Builder, scope: *llvm.DI.Scope, name_pointer: [*]const u8, name_length: usize, file: *llvm.DI.File, line: c_uint, bit_size: u64, align_in_bits: u32, bit_offset: u64, flags: llvm.DI.Flags, member_type: *llvm.DI.Type) *llvm.DI.Type.Derived;
|
||||
pub extern fn LLVMDIBuilderCreateBitFieldMemberType(builder: *llvm.DI.Builder, scope: *llvm.DI.Scope, name_pointer: [*]const u8, name_length: usize, file: *llvm.DI.File, line: c_uint, bit_size: u64, bit_offset: u64, bit_storage_offset: u64, flags: llvm.DI.Flags, member_type: *llvm.DI.Type) *llvm.DI.Type.Derived;
|
||||
pub extern fn LLVMDIBuilderCreatePointerType(builder: *llvm.DI.Builder, element_type: *llvm.DI.Type, bit_size: u64, align_in_bits: u32, address_space: c_uint, name_pointer: [*]const u8, name_length: usize) *llvm.DI.Type.Derived;
|
||||
pub extern fn LLVMDIBuilderCreateEnumerator(builder: *llvm.DI.Builder, name_pointer: [*]const u8, name_length: usize, value: i64, is_unsigned: Bool) *llvm.DI.Enumerator;
|
||||
pub extern fn LLVMDIBuilderCreateEnumerationType(builder: *llvm.DI.Builder, scope: *llvm.DI.Scope, name_pointer: [*]const u8, name_length: usize, file: *llvm.DI.File, line: c_uint, bit_size: u64, align_in_bits: u32, enumerator_pointer: [*]const *llvm.DI.Enumerator, enumerator_count: c_uint, backing_type: *llvm.DI.Type) *llvm.DI.Type.Composite;
|
||||
|
||||
pub extern fn LLVMMetadataReplaceAllUsesWith(forward: *llvm.DI.Type.Composite, complete: *llvm.DI.Type.Composite) void;
|
||||
|
||||
|
@ -45,7 +45,7 @@ pub fn main(argc: c_int, argv: [*:null]const ?[*:0]const u8) callconv(.C) c_int
|
||||
.build_mode = .debug_none,
|
||||
.content = file_content,
|
||||
.path = file_path,
|
||||
.has_debug_info = false,
|
||||
.has_debug_info = true,
|
||||
.target = converter.Target.get_native(),
|
||||
});
|
||||
return 0;
|
||||
|
18
tests/basic_enum.bbb
Normal file
18
tests/basic_enum.bbb
Normal file
@ -0,0 +1,18 @@
|
||||
E = enum
|
||||
{
|
||||
zero = 0,
|
||||
one = 1,
|
||||
two = 2,
|
||||
three = 3,
|
||||
}
|
||||
|
||||
[export] main = fn [cc(c)] () s32
|
||||
{
|
||||
>a: E = .three;
|
||||
>b: E = .two;
|
||||
>c: E = .one;
|
||||
>a_int: s32 = #extend(#int_from_enum(a));
|
||||
>b_int: s32 = #extend(#int_from_enum(b));
|
||||
>c_int: s32 = #extend(#int_from_enum(c));
|
||||
return a_int - (b_int + c_int);
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user