wip
This commit is contained in:
parent
0e789d3f13
commit
bdc9428e05
@ -996,10 +996,15 @@ pub const GlobalVariable = opaque {
|
|||||||
pub const set_initializer = api.LLVMSetInitializer;
|
pub const set_initializer = api.LLVMSetInitializer;
|
||||||
pub const erase_from_parent = api.LLVMDeleteGlobal;
|
pub const erase_from_parent = api.LLVMDeleteGlobal;
|
||||||
pub const delete = api.llvm_global_variable_delete;
|
pub const delete = api.llvm_global_variable_delete;
|
||||||
|
|
||||||
pub fn to_value(global_variable: *GlobalVariable) *Value {
|
pub fn to_value(global_variable: *GlobalVariable) *Value {
|
||||||
return @ptrCast(global_variable);
|
return @ptrCast(global_variable);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn to_constant(global_variable: *GlobalVariable) *Constant {
|
||||||
|
return @ptrCast(global_variable);
|
||||||
|
}
|
||||||
|
|
||||||
pub const UnnamedAddress = enum(c_uint) {
|
pub const UnnamedAddress = enum(c_uint) {
|
||||||
none,
|
none,
|
||||||
local,
|
local,
|
||||||
@ -1060,6 +1065,10 @@ pub const Constant = opaque {
|
|||||||
pub fn to_value(constant: *Constant.Integer) *Value {
|
pub fn to_value(constant: *Constant.Integer) *Value {
|
||||||
return @ptrCast(constant);
|
return @ptrCast(constant);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn to_constant(constant: *Constant.Integer) *Constant {
|
||||||
|
return @ptrCast(constant);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
pub const get_sign_extended_value = api.LLVMConstIntGetSExtValue;
|
pub const get_sign_extended_value = api.LLVMConstIntGetSExtValue;
|
||||||
|
@ -206,6 +206,7 @@ pub const ResolvedType = struct {
|
|||||||
|
|
||||||
pub const Enumerator = struct {
|
pub const Enumerator = struct {
|
||||||
fields: []const Enumerator.Field,
|
fields: []const Enumerator.Field,
|
||||||
|
string_to_enum: ?*llvm.Function = null,
|
||||||
backing_type: *Type,
|
backing_type: *Type,
|
||||||
line: u32,
|
line: u32,
|
||||||
implicit_backing_type: bool,
|
implicit_backing_type: bool,
|
||||||
@ -755,6 +756,7 @@ pub const Value = struct {
|
|||||||
int_from_pointer: *Value,
|
int_from_pointer: *Value,
|
||||||
pointer_cast: *Value,
|
pointer_cast: *Value,
|
||||||
select: Select,
|
select: Select,
|
||||||
|
string_to_enum: StringToEnum,
|
||||||
trap,
|
trap,
|
||||||
truncate: *Value,
|
truncate: *Value,
|
||||||
va_start,
|
va_start,
|
||||||
@ -770,6 +772,7 @@ pub const Value = struct {
|
|||||||
int_from_pointer,
|
int_from_pointer,
|
||||||
pointer_cast,
|
pointer_cast,
|
||||||
select,
|
select,
|
||||||
|
string_to_enum,
|
||||||
trap,
|
trap,
|
||||||
truncate,
|
truncate,
|
||||||
va_start,
|
va_start,
|
||||||
@ -788,6 +791,11 @@ pub const Value = struct {
|
|||||||
list: *Value,
|
list: *Value,
|
||||||
type: *Type,
|
type: *Type,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const StringToEnum = struct {
|
||||||
|
enum_type: *Type,
|
||||||
|
string_value: *Value,
|
||||||
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
fn is_constant(value: *Value) bool {
|
fn is_constant(value: *Value) bool {
|
||||||
@ -1011,6 +1019,7 @@ pub const Module = struct {
|
|||||||
pointer_type: *llvm.Type,
|
pointer_type: *llvm.Type,
|
||||||
void_type: *llvm.Type,
|
void_type: *llvm.Type,
|
||||||
intrinsic_table: IntrinsicTable,
|
intrinsic_table: IntrinsicTable,
|
||||||
|
memcmp: ?*llvm.Function = null,
|
||||||
debug_tag: u32,
|
debug_tag: u32,
|
||||||
|
|
||||||
const IntrinsicTable = struct {
|
const IntrinsicTable = struct {
|
||||||
@ -2770,7 +2779,27 @@ pub const Module = struct {
|
|||||||
.false_value = false_value,
|
.false_value = false_value,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
} };
|
}, };
|
||||||
|
},
|
||||||
|
.string_to_enum => blk: {
|
||||||
|
module.skip_space();
|
||||||
|
module.expect_character(left_parenthesis);
|
||||||
|
module.skip_space();
|
||||||
|
const enum_type = module.parse_type(function);
|
||||||
|
module.expect_character(',');
|
||||||
|
module.skip_space();
|
||||||
|
const string_value = module.parse_value(function, .{});
|
||||||
|
module.skip_space();
|
||||||
|
module.expect_character(right_parenthesis);
|
||||||
|
|
||||||
|
break :blk .{ .bb = .{
|
||||||
|
.intrinsic = .{
|
||||||
|
.string_to_enum = .{
|
||||||
|
.enum_type = enum_type,
|
||||||
|
.string_value = string_value,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}, };
|
||||||
},
|
},
|
||||||
.trap => blk: {
|
.trap => blk: {
|
||||||
module.skip_space();
|
module.skip_space();
|
||||||
@ -5466,6 +5495,13 @@ pub const Module = struct {
|
|||||||
const int_ty = module.integer_type(64, false);
|
const int_ty = module.integer_type(64, false);
|
||||||
break :blk int_ty;
|
break :blk int_ty;
|
||||||
},
|
},
|
||||||
|
.string_to_enum => |string_to_enum| blk: {
|
||||||
|
module.analyze_value_type(function, string_to_enum.string_value, .{ .type = module.get_slice_type(.{ .type = module.integer_type(8, false) }) });
|
||||||
|
if (string_to_enum.enum_type.bb != .enumerator) {
|
||||||
|
module.report_error();
|
||||||
|
}
|
||||||
|
break :blk string_to_enum.enum_type;
|
||||||
|
},
|
||||||
.trap => module.noreturn_type,
|
.trap => module.noreturn_type,
|
||||||
.va_start => module.get_va_list_type(),
|
.va_start => module.get_va_list_type(),
|
||||||
.va_end => |va_list| blk: {
|
.va_end => |va_list| blk: {
|
||||||
@ -5886,6 +5922,165 @@ pub const Module = struct {
|
|||||||
const result = module.llvm.builder.create_select(condition, select.true_value.llvm.?, select.false_value.llvm.?);
|
const result = module.llvm.builder.create_select(condition, select.true_value.llvm.?, select.false_value.llvm.?);
|
||||||
break :blk result;
|
break :blk result;
|
||||||
},
|
},
|
||||||
|
.string_to_enum => |string_to_enum| {
|
||||||
|
const fields = string_to_enum.enum_type.bb.enumerator.fields;
|
||||||
|
const array_element_count = fields.len;
|
||||||
|
const string_to_enum_function = if (string_to_enum.enum_type.bb.enumerator.string_to_enum) |string_to_enum_function| {
|
||||||
|
_ = string_to_enum_function;
|
||||||
|
@trap();
|
||||||
|
} else string_to_enum: {
|
||||||
|
const insert_block = module.llvm.builder.get_insert_block();
|
||||||
|
defer module.llvm.builder.position_at_end(insert_block.?);
|
||||||
|
|
||||||
|
const uint8 = module.integer_type(8, false).resolve(module).handle;
|
||||||
|
const aligned_backing_type = module.align_integer_type(string_to_enum.enum_type.bb.enumerator.backing_type);
|
||||||
|
const return_struct_type = module.llvm.context.get_struct_type(&.{aligned_backing_type.resolve(module).handle, uint8 });
|
||||||
|
const uint64 = module.integer_type(64, false).resolve(module).handle;
|
||||||
|
const llvm_function_type = llvm.Type.Function.get(return_struct_type.to_type(), &.{uint64, uint64}, false);
|
||||||
|
const slice_struct_type = module.llvm.context.get_struct_type(&.{module.llvm.pointer_type, uint64});
|
||||||
|
|
||||||
|
const llvm_function_value = module.llvm.module.create_function(.{
|
||||||
|
.name = module.arena.join_string(&.{ "string_to_enum.", string_to_enum.enum_type.name }),
|
||||||
|
.linkage = .InternalLinkage,
|
||||||
|
.type = llvm_function_type,
|
||||||
|
});
|
||||||
|
|
||||||
|
var name_before: ?*llvm.GlobalVariable = null;
|
||||||
|
var value_constant_buffer: [64]*llvm.Constant = undefined;
|
||||||
|
var name_constant_buffer: [64]*llvm.Constant = undefined;
|
||||||
|
|
||||||
|
for (fields, 0..) |field, field_index| {
|
||||||
|
const value_global = aligned_backing_type.llvm.handle.?.to_integer().get_constant(field.value, 0);
|
||||||
|
value_constant_buffer[field_index] = value_global.to_constant();
|
||||||
|
|
||||||
|
const null_terminate = true;
|
||||||
|
const name_global = module.llvm.module.create_global_variable(.{
|
||||||
|
.type = uint8.get_array_type(field.name.len + @intFromBool(null_terminate)).to_type(),
|
||||||
|
.linkage = .InternalLinkage,
|
||||||
|
.name = module.arena.join_string(&.{"string.", string_to_enum.enum_type.name, ".", field.name}),
|
||||||
|
.initial_value = module.llvm.context.get_constant_string(field.name, null_terminate),
|
||||||
|
.is_constant = true,
|
||||||
|
.before = name_before,
|
||||||
|
});
|
||||||
|
name_before = name_global;
|
||||||
|
|
||||||
|
const slice_constant = module.llvm.context.get_anonymous_constant_struct(&.{
|
||||||
|
name_global.to_constant(),
|
||||||
|
uint64.to_integer().get_constant(field.name.len, 0).to_constant(),
|
||||||
|
}, false);
|
||||||
|
name_constant_buffer[field_index] = slice_constant;
|
||||||
|
}
|
||||||
|
|
||||||
|
const value_array = aligned_backing_type.llvm.handle.?.get_constant_array(value_constant_buffer[0..array_element_count]);
|
||||||
|
const name_array = slice_struct_type.to_type().get_constant_array(name_constant_buffer[0..array_element_count]);
|
||||||
|
|
||||||
|
const value_array_variable_type = aligned_backing_type.resolve(module).handle.get_array_type(array_element_count);
|
||||||
|
const value_array_variable = module.llvm.module.create_global_variable(.{
|
||||||
|
.type = value_array_variable_type.to_type(),
|
||||||
|
.linkage = .InternalLinkage,
|
||||||
|
.initial_value = value_array,
|
||||||
|
.name = "value.array.enum",
|
||||||
|
});
|
||||||
|
_ = value_array_variable;
|
||||||
|
|
||||||
|
const name_array_variable_type = slice_struct_type.to_type().get_array_type(array_element_count);
|
||||||
|
const name_array_variable = module.llvm.module.create_global_variable(.{
|
||||||
|
.type = name_array_variable_type.to_type(),
|
||||||
|
.linkage = .InternalLinkage,
|
||||||
|
.initial_value = name_array,
|
||||||
|
.name = "name.array.enum",
|
||||||
|
});
|
||||||
|
|
||||||
|
const function_entry_block = module.llvm.context.create_basic_block("entry", llvm_function_value);
|
||||||
|
const return_block = module.llvm.context.create_basic_block("return_block", llvm_function_value);
|
||||||
|
const loop_entry_block = module.llvm.context.create_basic_block("loop.entry", llvm_function_value);
|
||||||
|
const loop_body_block = module.llvm.context.create_basic_block("loop.body", llvm_function_value);
|
||||||
|
const loop_exit_block = module.llvm.context.create_basic_block("loop.exit", llvm_function_value);
|
||||||
|
module.llvm.builder.position_at_end(function_entry_block);
|
||||||
|
|
||||||
|
const return_alloca = module.llvm.builder.create_alloca(return_struct_type.to_type(), "retval");
|
||||||
|
const index_alloca = module.llvm.builder.create_alloca(uint64, "idx");
|
||||||
|
_ = module.llvm.builder.create_store(uint64.get_zero().to_value(), index_alloca);
|
||||||
|
_ = module.llvm.builder.create_branch(loop_entry_block);
|
||||||
|
module.llvm.builder.position_at_end(loop_entry_block);
|
||||||
|
const index_load = module.llvm.builder.create_load(uint64, index_alloca);
|
||||||
|
const loop_cmp = module.llvm.builder.create_integer_compare(.ult, index_load, uint64.to_integer().get_constant(array_element_count, 0).to_value());
|
||||||
|
_ = module.llvm.builder.create_conditional_branch(loop_cmp, loop_body_block, loop_exit_block);
|
||||||
|
|
||||||
|
module.llvm.builder.position_at_end(loop_body_block);
|
||||||
|
|
||||||
|
var arguments: [2]*llvm.Argument = undefined;
|
||||||
|
llvm_function_value.get_arguments(&arguments);
|
||||||
|
|
||||||
|
const body_index_load = module.llvm.builder.create_load(uint64, index_alloca);
|
||||||
|
const array_element_pointer = module.llvm.builder.create_gep(.{
|
||||||
|
.type = name_array_variable_type.to_type(),
|
||||||
|
.aggregate = name_array_variable.to_value(),
|
||||||
|
.indices = &.{body_index_load},
|
||||||
|
});
|
||||||
|
|
||||||
|
const element_length_pointer = module.llvm.builder.create_struct_gep(slice_struct_type, array_element_pointer, 1);
|
||||||
|
const element_length = module.llvm.builder.create_load(uint64, element_length_pointer);
|
||||||
|
|
||||||
|
const length_comparison = module.llvm.builder.create_integer_compare(.eq, arguments[1].to_value(), element_length);
|
||||||
|
|
||||||
|
const length_match_block = module.llvm.context.create_basic_block("length.match", llvm_function_value);
|
||||||
|
const length_mismatch_block = module.llvm.context.create_basic_block("length.mismatch", llvm_function_value);
|
||||||
|
_ = module.llvm.builder.create_conditional_branch(length_comparison, length_match_block, length_mismatch_block);
|
||||||
|
|
||||||
|
module.llvm.builder.position_at_end(length_match_block);
|
||||||
|
const memcmp = if (module.llvm.memcmp) |memcmp| {
|
||||||
|
_ = memcmp;
|
||||||
|
@trap();
|
||||||
|
} else b: {
|
||||||
|
const memcmp = module.llvm.module.create_function(.{
|
||||||
|
.name = "memcmp",
|
||||||
|
.linkage = .ExternalLinkage,
|
||||||
|
.type = llvm.Type.Function.get(module.integer_type(32, true).resolve(module).handle, &.{module.llvm.pointer_type, module.llvm.pointer_type, uint64}, false),
|
||||||
|
});
|
||||||
|
module.llvm.memcmp = memcmp;
|
||||||
|
break :b memcmp;
|
||||||
|
};
|
||||||
|
const element_pointer_pointer = module.llvm.builder.create_struct_gep(slice_struct_type, array_element_pointer, 0);
|
||||||
|
const element_pointer = module.llvm.builder.create_load(uint64, element_pointer_pointer);
|
||||||
|
const memcmp_return_result = module.llvm.builder.create_call(memcmp.get_type(), memcmp.to_value(), &.{arguments[0].to_value(), element_pointer, element_length});
|
||||||
|
const content_comparison = module.llvm.builder.create_integer_compare(.eq, memcmp_return_result, module.integer_type(32, true).resolve(module).handle.get_zero().to_value());
|
||||||
|
const content_match_block = module.llvm.context.create_basic_block("content.match", llvm_function_value);
|
||||||
|
_ = module.llvm.builder.create_conditional_branch(content_comparison, content_match_block, length_mismatch_block);
|
||||||
|
|
||||||
|
module.llvm.builder.position_at_end(content_match_block);
|
||||||
|
const value_array_element_pointer = module.llvm.builder.create_gep(.{
|
||||||
|
.type = name_array_variable_type.to_type(),
|
||||||
|
.aggregate = name_array_variable.to_value(),
|
||||||
|
.indices = &.{body_index_load},
|
||||||
|
});
|
||||||
|
const enum_value_load = module.llvm.builder.create_load(aligned_backing_type.resolve(module).handle, value_array_element_pointer);
|
||||||
|
const ret_result_enum = module.llvm.builder.create_struct_gep(return_struct_type, return_alloca, 0);
|
||||||
|
_ = module.llvm.builder.create_store(enum_value_load, ret_result_enum);
|
||||||
|
const ret_result_bool = module.llvm.builder.create_struct_gep(return_struct_type, return_alloca, 1);
|
||||||
|
_ = module.llvm.builder.create_store(uint8.to_integer().get_constant(1, 0).to_value(), ret_result_bool);
|
||||||
|
_ = module.llvm.builder.create_branch(return_block);
|
||||||
|
|
||||||
|
module.llvm.builder.position_at_end(length_mismatch_block);
|
||||||
|
const inc = module.llvm.builder.create_add(body_index_load, uint64.to_integer().get_constant(1, 0).to_value());
|
||||||
|
_ = module.llvm.builder.create_store(inc, index_alloca);
|
||||||
|
_ = module.llvm.builder.create_branch(loop_entry_block);
|
||||||
|
|
||||||
|
module.llvm.builder.position_at_end(loop_exit_block);
|
||||||
|
_ = module.llvm.builder.create_store(return_struct_type.to_type().get_zero().to_value(), return_alloca);
|
||||||
|
_ = module.llvm.builder.create_branch(return_block);
|
||||||
|
|
||||||
|
module.llvm.builder.position_at_end(return_block);
|
||||||
|
const ret_load = module.llvm.builder.create_load(return_struct_type.to_type(), return_alloca);
|
||||||
|
module.llvm.builder.create_ret(ret_load);
|
||||||
|
|
||||||
|
lib.print_string(llvm_function_value.to_string());
|
||||||
|
|
||||||
|
break :string_to_enum llvm_function_value;
|
||||||
|
};
|
||||||
|
_ = string_to_enum_function;
|
||||||
|
@trap();
|
||||||
|
},
|
||||||
.trap => blk: {
|
.trap => blk: {
|
||||||
// TODO: lookup in advance
|
// TODO: lookup in advance
|
||||||
const intrinsic_id = module.llvm.intrinsic_table.trap;
|
const intrinsic_id = module.llvm.intrinsic_table.trap;
|
||||||
|
@ -225,13 +225,25 @@ global_state_initialize = fn () void
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
CompilerCommand = enum
|
||||||
|
{
|
||||||
|
compile,
|
||||||
|
test,
|
||||||
|
}
|
||||||
|
|
||||||
[export] main = fn [cc(c)] (argument_count: u32, argv: &&u8) s32
|
[export] main = fn [cc(c)] (argument_count: u32, argv: &&u8) s32
|
||||||
{
|
{
|
||||||
|
global_state_initialize();
|
||||||
|
|
||||||
if (argument_count < 2)
|
if (argument_count < 2)
|
||||||
{
|
{
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
>command_string = c_string_to_slice(argv[1]);
|
||||||
|
|
||||||
|
> a = #string_to_enum(CompilerCommand, command_string);
|
||||||
|
|
||||||
>relative_file_path_pointer = argv[2];
|
>relative_file_path_pointer = argv[2];
|
||||||
if (!relative_file_path_pointer)
|
if (!relative_file_path_pointer)
|
||||||
{
|
{
|
||||||
@ -256,6 +268,5 @@ global_state_initialize = fn () void
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
global_state_initialize();
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
13
tests/string_to_enum.bbb
Normal file
13
tests/string_to_enum.bbb
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
E = enum
|
||||||
|
{
|
||||||
|
asd,
|
||||||
|
dsa,
|
||||||
|
gsa,
|
||||||
|
}
|
||||||
|
|
||||||
|
[export] main = fn [cc(c)] () s32
|
||||||
|
{
|
||||||
|
>e = "dsa";
|
||||||
|
#string_to_enum(E, e);
|
||||||
|
return 0;
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user