aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorgingerBill <bill@gingerbill.org>2022-08-11 14:30:14 +0100
committergingerBill <bill@gingerbill.org>2022-08-11 14:30:14 +0100
commita7c39060038f63b1840f6eb5c0750bdb47e7d3ea (patch)
tree3ea12b5e4905ec2b571ce8b5564f50ea10c260b7 /src
parent70dc0c15fd244bdc4a769b0d91b50ecc210bca65 (diff)
`#load(path, type)`
where `type` can be `string` or `[]T` where `T` is a simple type
Diffstat (limited to 'src')
-rw-r--r--src/check_builtin.cpp49
-rw-r--r--src/llvm_backend_const.cpp4
-rw-r--r--src/llvm_backend_general.cpp48
-rw-r--r--src/types.cpp51
4 files changed, 143 insertions, 9 deletions
diff --git a/src/check_builtin.cpp b/src/check_builtin.cpp
index 122d3a461..36c9ea001 100644
--- a/src/check_builtin.cpp
+++ b/src/check_builtin.cpp
@@ -1169,11 +1169,11 @@ LoadDirectiveResult check_load_directive(CheckerContext *c, Operand *operand, As
String name = bd->name.string;
GB_ASSERT(name == "load");
- if (ce->args.count != 1) {
+ if (ce->args.count != 1 && ce->args.count != 2) {
if (ce->args.count == 0) {
- error(ce->close, "'#load' expects 1 argument, got 0");
+ error(ce->close, "'#%.*s' expects 1 or 2 arguments, got 0", LIT(name));
} else {
- error(ce->args[0], "'#load' expects 1 argument, got %td", ce->args.count);
+ error(ce->args[0], "'#%.*s' expects 1 or 2 arguments, got %td", LIT(name), ce->args.count);
}
return LoadDirective_Error;
@@ -1183,13 +1183,13 @@ LoadDirectiveResult check_load_directive(CheckerContext *c, Operand *operand, As
Operand o = {};
check_expr(c, &o, arg);
if (o.mode != Addressing_Constant) {
- error(arg, "'#load' expected a constant string argument");
+ error(arg, "'#%.*s' expected a constant string argument", LIT(name));
return LoadDirective_Error;
}
if (!is_type_string(o.type)) {
gbString str = type_to_string(o.type);
- error(arg, "'#load' expected a constant string, got %s", str);
+ error(arg, "'#%.*s' expected a constant string, got %s", LIT(name), str);
gb_string_free(str);
return LoadDirective_Error;
}
@@ -1197,8 +1197,43 @@ LoadDirectiveResult check_load_directive(CheckerContext *c, Operand *operand, As
GB_ASSERT(o.value.kind == ExactValue_String);
operand->type = t_u8_slice;
- if (type_hint && is_type_string(type_hint)) {
- operand->type = type_hint;
+ if (ce->args.count == 1) {
+ if (type_hint && is_type_string(type_hint)) {
+ operand->type = type_hint;
+ }
+ } else if (ce->args.count == 2) {
+ bool failed = false;
+ Ast *arg_type = ce->args[1];
+ Type *type = check_type(c, arg_type);
+ if (type != nullptr && type != t_invalid) {
+ if (is_type_string(type)) {
+ operand->type = type;
+ } else if (is_type_slice(type) /*|| is_type_array(type) || is_type_enumerated_array(type)*/) {
+ Type *elem = nullptr;
+ Type *bt = base_type(type);
+ if (bt->kind == Type_Slice) {
+ elem = bt->Slice.elem;
+ } else if (bt->kind == Type_Array) {
+ elem = bt->Array.elem;
+ } else if (bt->kind == Type_EnumeratedArray) {
+ elem = bt->EnumeratedArray.elem;
+ }
+ GB_ASSERT(elem != nullptr);
+ if (is_type_load_safe(elem)) {
+ operand->type = type;
+ } else {
+ failed = true;
+ }
+ } else {
+ failed = true;
+ }
+ }
+
+ if (failed) {
+ gbString type_str = type_to_string(type);
+ error(arg_type, "'#%.*s' invalid type, expected a string, or slice of simple types, got %s", LIT(name), type_str);
+ gb_string_free(type_str);
+ }
}
operand->mode = Addressing_Constant;
diff --git a/src/llvm_backend_const.cpp b/src/llvm_backend_const.cpp
index 954778bb6..2d14070e2 100644
--- a/src/llvm_backend_const.cpp
+++ b/src/llvm_backend_const.cpp
@@ -391,8 +391,8 @@ lbValue lb_const_value(lbModule *m, Type *type, ExactValue value, bool allow_loc
if (is_type_slice(type)) {
if (value.kind == ExactValue_String) {
- GB_ASSERT(is_type_u8_slice(type));
- res.value = lb_find_or_add_entity_string_byte_slice(m, value.value_string).value;
+ GB_ASSERT(is_type_slice(type));
+ res.value = lb_find_or_add_entity_string_byte_slice_with_type(m, value.value_string, original_type).value;
return res;
} else {
ast_node(cl, CompoundLit, value.value_compound);
diff --git a/src/llvm_backend_general.cpp b/src/llvm_backend_general.cpp
index 082163b2f..8704bc7c7 100644
--- a/src/llvm_backend_general.cpp
+++ b/src/llvm_backend_general.cpp
@@ -2523,7 +2523,55 @@ lbValue lb_find_or_add_entity_string_byte_slice(lbModule *m, String const &str)
res.type = t_u8_slice;
return res;
}
+lbValue lb_find_or_add_entity_string_byte_slice_with_type(lbModule *m, String const &str, Type *slice_type) {
+ GB_ASSERT(is_type_slice(slice_type));
+ LLVMValueRef indices[2] = {llvm_zero(m), llvm_zero(m)};
+ LLVMValueRef data = LLVMConstStringInContext(m->ctx,
+ cast(char const *)str.text,
+ cast(unsigned)str.len,
+ false);
+
+
+ char *name = nullptr;
+ {
+ isize max_len = 7+8+1;
+ name = gb_alloc_array(permanent_allocator(), char, max_len);
+ u32 id = m->gen->global_array_index.fetch_add(1);
+ isize len = gb_snprintf(name, max_len, "csbs$%x", id);
+ len -= 1;
+ }
+ LLVMTypeRef type = LLVMTypeOf(data);
+ LLVMValueRef global_data = LLVMAddGlobal(m->mod, type, name);
+ LLVMSetInitializer(global_data, data);
+ LLVMSetLinkage(global_data, LLVMPrivateLinkage);
+ LLVMSetUnnamedAddress(global_data, LLVMGlobalUnnamedAddr);
+ LLVMSetAlignment(global_data, 1);
+ LLVMSetGlobalConstant(global_data, true);
+ i64 data_len = str.len;
+ LLVMValueRef ptr = nullptr;
+ if (data_len != 0) {
+ ptr = LLVMConstInBoundsGEP2(type, global_data, indices, 2);
+ } else {
+ ptr = LLVMConstNull(lb_type(m, t_u8_ptr));
+ }
+ if (!is_type_u8_slice(slice_type)) {
+ Type *bt = base_type(slice_type);
+ Type *elem = bt->Slice.elem;
+ i64 sz = type_size_of(elem);
+ GB_ASSERT(sz > 0);
+ ptr = LLVMConstPointerCast(ptr, lb_type(m, alloc_type_pointer(elem)));
+ data_len /= sz;
+ }
+
+ LLVMValueRef len = LLVMConstInt(lb_type(m, t_int), data_len, true);
+ LLVMValueRef values[2] = {ptr, len};
+
+ lbValue res = {};
+ res.value = llvm_const_named_struct(m, slice_type, values, 2);
+ res.type = slice_type;
+ return res;
+}
diff --git a/src/types.cpp b/src/types.cpp
index cba27fd6f..1f4804430 100644
--- a/src/types.cpp
+++ b/src/types.cpp
@@ -2398,6 +2398,57 @@ bool is_type_simple_compare(Type *t) {
return false;
}
+bool is_type_load_safe(Type *type) {
+ GB_ASSERT(type != nullptr);
+ type = core_type(core_array_type(type));
+ switch (type->kind) {
+ case Type_Basic:
+ return (type->Basic.flags & (BasicFlag_Boolean|BasicFlag_Numeric|BasicFlag_Rune)) != 0;
+
+ case Type_BitSet:
+ if (type->BitSet.underlying) {
+ return is_type_load_safe(type->BitSet.underlying);
+ }
+ return true;
+
+ case Type_RelativePointer:
+ case Type_RelativeSlice:
+ return true;
+
+ case Type_Pointer:
+ case Type_MultiPointer:
+ case Type_Slice:
+ case Type_DynamicArray:
+ case Type_Proc:
+ case Type_SoaPointer:
+ return false;
+
+ case Type_Enum:
+ case Type_EnumeratedArray:
+ case Type_Array:
+ case Type_SimdVector:
+ case Type_Matrix:
+ GB_PANIC("should never be hit");
+ return false;
+
+ case Type_Struct:
+ for_array(i, type->Struct.fields) {
+ if (!is_type_load_safe(type->Struct.fields[i]->type)) {
+ return false;
+ }
+ }
+ return type_size_of(type) > 0;
+ case Type_Union:
+ for_array(i, type->Union.variants) {
+ if (!is_type_load_safe(type->Union.variants[i])) {
+ return false;
+ }
+ }
+ return type_size_of(type) > 0;
+ }
+ return false;
+}
+
String lookup_subtype_polymorphic_field(Type *dst, Type *src) {
Type *prev_src = src;
// Type *prev_dst = dst;