Browse Source

`#load(path, type)`

where `type` can be `string` or `[]T` where `T` is a simple type
gingerBill 3 years ago
parent
commit
a7c3906003
4 changed files with 143 additions and 9 deletions
  1. 42 7
      src/check_builtin.cpp
  2. 2 2
      src/llvm_backend_const.cpp
  3. 48 0
      src/llvm_backend_general.cpp
  4. 51 0
      src/types.cpp

+ 42 - 7
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;
 

+ 2 - 2
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);

+ 48 - 0
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;
+}
 
 
 

+ 51 - 0
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;