Browse Source

Add `intrinsics.constant_utf16_cstring`

gingerBill 3 years ago
parent
commit
ffc45e8cc2
3 changed files with 108 additions and 18 deletions
  1. 31 18
      src/check_builtin.cpp
  2. 6 0
      src/checker_builtin_procs.hpp
  3. 71 0
      src/llvm_backend_proc.cpp

+ 31 - 18
src/check_builtin.cpp

@@ -223,31 +223,28 @@ void add_objc_proc_type(CheckerContext *c, Ast *call, Type *return_type, Slice<T
 	map_set(&c->info->objc_msgSend_types, call, data);
 	map_set(&c->info->objc_msgSend_types, call, data);
 	mutex_unlock(&c->info->objc_types_mutex);
 	mutex_unlock(&c->info->objc_types_mutex);
 
 
-	add_package_dependency(c, "runtime", "objc_lookUpClass");
-	add_package_dependency(c, "runtime", "sel_registerName");
-	add_package_dependency(c, "runtime", "objc_allocateClassPair");
-
 	add_package_dependency(c, "runtime", "objc_msgSend");
 	add_package_dependency(c, "runtime", "objc_msgSend");
 	add_package_dependency(c, "runtime", "objc_msgSend_fpret");
 	add_package_dependency(c, "runtime", "objc_msgSend_fpret");
 	add_package_dependency(c, "runtime", "objc_msgSend_fp2ret");
 	add_package_dependency(c, "runtime", "objc_msgSend_fp2ret");
 	add_package_dependency(c, "runtime", "objc_msgSend_stret");
 	add_package_dependency(c, "runtime", "objc_msgSend_stret");
 }
 }
 
 
+bool is_constant_string(CheckerContext *c, String const &builtin_name, Ast *expr, String *name_) {
+	Operand op = {};
+	check_expr(c, &op, expr);
+	if (op.mode == Addressing_Constant && op.value.kind == ExactValue_String) {
+		if (name_) *name_ = op.value.value_string;
+		return true;
+	}
+	gbString e = expr_to_string(op.expr);
+	gbString t = type_to_string(op.type);
+	error(op.expr, "'%.*s' expected a constant string value, got %s of type %s", LIT(builtin_name), e, t);
+	gb_string_free(t);
+	gb_string_free(e);
+	return false;
+}
+
 bool check_builtin_objc_procedure(CheckerContext *c, Operand *operand, Ast *call, i32 id, Type *type_hint) {
 bool check_builtin_objc_procedure(CheckerContext *c, Operand *operand, Ast *call, i32 id, Type *type_hint) {
-	auto const is_constant_string = [](CheckerContext *c, String const &builtin_name, Ast *expr, String *name_) -> bool {
-		Operand op = {};
-		check_expr(c, &op, expr);
-		if (op.mode == Addressing_Constant && op.value.kind == ExactValue_String) {
-			if (name_) *name_ = op.value.value_string;
-			return true;
-		}
-		gbString e = expr_to_string(op.expr);
-		gbString t = type_to_string(op.type);
-		error(op.expr, "'%.*s' expected a constant string value, got %s of type %s", LIT(builtin_name), e, t);
-		gb_string_free(t);
-		gb_string_free(e);
-		return false;
-	};
 	String builtin_name = builtin_procs[id].name;
 	String builtin_name = builtin_procs[id].name;
 
 
 	if (build_context.metrics.os != TargetOs_darwin) {
 	if (build_context.metrics.os != TargetOs_darwin) {
@@ -371,6 +368,10 @@ bool check_builtin_objc_procedure(CheckerContext *c, Operand *operand, Ast *call
 
 
 		}
 		}
 		operand->mode = Addressing_Value;
 		operand->mode = Addressing_Value;
+
+		add_package_dependency(c, "runtime", "objc_lookUpClass");
+		add_package_dependency(c, "runtime", "sel_registerName");
+		add_package_dependency(c, "runtime", "objc_allocateClassPair");
 		return true;
 		return true;
 	} break;
 	} break;
 	}
 	}
@@ -4086,6 +4087,18 @@ bool check_builtin_procedure(CheckerContext *c, Operand *operand, Ast *call, i32
 			break;
 			break;
 		}
 		}
 
 
+	case BuiltinProc_constant_utf16_cstring:
+		{
+			String value = {};
+			if (!is_constant_string(c, builtin_name, ce->args[0], &value)) {
+				return false;
+			}
+			operand->mode = Addressing_Value;
+			operand->type = alloc_type_multi_pointer(t_u16);
+			operand->value = {};
+			break;
+		}
+
 
 
 	}
 	}
 
 

+ 6 - 0
src/checker_builtin_procs.hpp

@@ -258,6 +258,9 @@ BuiltinProc__type_end,
 	BuiltinProc_objc_register_selector,
 	BuiltinProc_objc_register_selector,
 	BuiltinProc_objc_register_class,
 	BuiltinProc_objc_register_class,
 
 
+	BuiltinProc_constant_utf16_cstring,
+
+
 	BuiltinProc_COUNT,
 	BuiltinProc_COUNT,
 };
 };
 gb_global BuiltinProc builtin_procs[BuiltinProc_COUNT] = {
 gb_global BuiltinProc builtin_procs[BuiltinProc_COUNT] = {
@@ -517,4 +520,7 @@ gb_global BuiltinProc builtin_procs[BuiltinProc_COUNT] = {
 	{STR_LIT("objc_find_class"),        1, false, Expr_Expr, BuiltinProcPkg_intrinsics},
 	{STR_LIT("objc_find_class"),        1, false, Expr_Expr, BuiltinProcPkg_intrinsics},
 	{STR_LIT("objc_register_selector"), 1, false, Expr_Expr, BuiltinProcPkg_intrinsics},
 	{STR_LIT("objc_register_selector"), 1, false, Expr_Expr, BuiltinProcPkg_intrinsics},
 	{STR_LIT("objc_register_class"),    1, false, Expr_Expr, BuiltinProcPkg_intrinsics},
 	{STR_LIT("objc_register_class"),    1, false, Expr_Expr, BuiltinProcPkg_intrinsics},
+
+	{STR_LIT("constant_utf16_cstring"), 1, false, Expr_Expr, BuiltinProcPkg_intrinsics},
+
 };
 };

+ 71 - 0
src/llvm_backend_proc.cpp

@@ -2122,6 +2122,77 @@ lbValue lb_build_builtin_proc(lbProcedure *p, Ast *expr, TypeAndValue const &tv,
 	case BuiltinProc_objc_find_class:        return lb_handle_objc_find_class(p, expr);
 	case BuiltinProc_objc_find_class:        return lb_handle_objc_find_class(p, expr);
 	case BuiltinProc_objc_register_selector: return lb_handle_objc_register_selector(p, expr);
 	case BuiltinProc_objc_register_selector: return lb_handle_objc_register_selector(p, expr);
 	case BuiltinProc_objc_register_class:    return lb_handle_objc_register_class(p, expr);
 	case BuiltinProc_objc_register_class:    return lb_handle_objc_register_class(p, expr);
+
+
+	case BuiltinProc_constant_utf16_cstring:
+		{
+			auto const encode_surrogate_pair = [](Rune r, u16 *r1, u16 *r2) {
+				if (r < 0x10000 || r > 0x10ffff) {
+					*r1 = 0xfffd;
+					*r2 = 0xfffd;
+				} else {
+					r -= 0x10000;
+					*r1 = 0xd800 + ((r>>10)&0x3ff);
+					*r2 = 0xdc00 + (r&0x3ff);
+				}
+			};
+
+			lbModule *m = p->module;
+
+			auto tav = type_and_value_of_expr(ce->args[0]);
+			GB_ASSERT(tav.value.kind == ExactValue_String);
+			String value = tav.value.value_string;
+
+			LLVMTypeRef llvm_u16 = lb_type(m, t_u16);
+
+			isize max_len = value.len*2 + 1;
+			LLVMValueRef *buffer = gb_alloc_array(temporary_allocator(), LLVMValueRef, max_len);
+			isize n = 0;
+			while (value.len > 0) {
+				Rune r = 0;
+				isize w = gb_utf8_decode(value.text, value.len, &r);
+				value.text += w;
+				value.len  -= w;
+				if ((0 <= r && r < 0xd800) || (0xe000 <= r && r < 0x10000)) {
+					buffer[n++] = LLVMConstInt(llvm_u16, cast(u16)r, false);
+				} else if (0x10000 <= r && r <= 0x10ffff) {
+					u16 r1, r2;
+					encode_surrogate_pair(r, &r1, &r2);
+					buffer[n++] = LLVMConstInt(llvm_u16, r1, false);
+					buffer[n++] = LLVMConstInt(llvm_u16, r2, false);
+				} else {
+					buffer[n++] = LLVMConstInt(llvm_u16, 0xfffd, false);
+				}
+			}
+
+			buffer[n++] = LLVMConstInt(llvm_u16, 0, false);
+
+			LLVMValueRef array = LLVMConstArray(llvm_u16, buffer, cast(unsigned int)n);
+
+			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;
+			}
+			LLVMValueRef global_data = LLVMAddGlobal(m->mod, LLVMTypeOf(array), name);
+			LLVMSetInitializer(global_data, array);
+			LLVMSetLinkage(global_data, LLVMInternalLinkage);
+
+
+
+			LLVMValueRef indices[] = {
+				LLVMConstInt(lb_type(m, t_u32), 0, false),
+				LLVMConstInt(lb_type(m, t_u32), 0, false),
+			};
+			lbValue res = {};
+			res.type = tv.type;
+			res.value = LLVMBuildInBoundsGEP(p->builder, global_data, indices, gb_count_of(indices), "");
+			return res;
+
+		}
 	}
 	}
 
 
 	GB_PANIC("Unhandled built-in procedure %.*s", LIT(builtin_procs[id].name));
 	GB_PANIC("Unhandled built-in procedure %.*s", LIT(builtin_procs[id].name));