diff options
| author | gingerBill <bill@gingerbill.org> | 2022-08-11 14:30:14 +0100 |
|---|---|---|
| committer | gingerBill <bill@gingerbill.org> | 2022-08-11 14:30:14 +0100 |
| commit | a7c39060038f63b1840f6eb5c0750bdb47e7d3ea (patch) | |
| tree | 3ea12b5e4905ec2b571ce8b5564f50ea10c260b7 /src | |
| parent | 70dc0c15fd244bdc4a769b0d91b50ecc210bca65 (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.cpp | 49 | ||||
| -rw-r--r-- | src/llvm_backend_const.cpp | 4 | ||||
| -rw-r--r-- | src/llvm_backend_general.cpp | 48 | ||||
| -rw-r--r-- | src/types.cpp | 51 |
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; |