Browse Source

Merge pull request #5162 from 0xrsp/tounsigned

new compiler intrinsics type_integer_to_unsigned, type_integer_to_unsigned
gingerBill 3 months ago
parent
commit
8337b7cccb

+ 3 - 0
base/intrinsics/intrinsics.odin

@@ -221,6 +221,9 @@ type_map_cell_info :: proc($T: typeid)           -> ^runtime.Map_Cell_Info ---
 type_convert_variants_to_pointers :: proc($T: typeid) -> typeid where type_is_union(T) ---
 type_convert_variants_to_pointers :: proc($T: typeid) -> typeid where type_is_union(T) ---
 type_merge :: proc($U, $V: typeid) -> typeid where type_is_union(U), type_is_union(V) ---
 type_merge :: proc($U, $V: typeid) -> typeid where type_is_union(U), type_is_union(V) ---
 
 
+type_integer_to_unsigned :: proc($T: typeid) -> type where type_is_integer(T), !type_is_unsigned(T) ---
+type_integer_to_signed   :: proc($T: typeid) -> type where type_is_integer(T), type_is_unsigned(T) ---
+
 type_has_shared_fields :: proc($U, $V: typeid) -> bool where type_is_struct(U), type_is_struct(V) ---
 type_has_shared_fields :: proc($U, $V: typeid) -> bool where type_is_struct(U), type_is_struct(V) ---
 
 
 constant_utf16_cstring :: proc($literal: string) -> [^]u16 ---
 constant_utf16_cstring :: proc($literal: string) -> [^]u16 ---

+ 81 - 0
src/check_builtin.cpp

@@ -5877,6 +5877,87 @@ gb_internal bool check_builtin_procedure(CheckerContext *c, Operand *operand, As
 		}
 		}
 		operand->mode = Addressing_Type;
 		operand->mode = Addressing_Type;
 		break;
 		break;
+	case BuiltinProc_type_integer_to_unsigned:
+		if (operand->mode != Addressing_Type) {
+			error(operand->expr, "Expected a type for '%.*s'", LIT(builtin_name));
+			return false;
+		} 
+
+		if (is_type_polymorphic(operand->type)) {
+			gbString t = type_to_string(operand->type);
+			error(operand->expr, "Expected a non-polymorphic type for '%.*s', got %s", LIT(builtin_name), t);
+			gb_string_free(t);
+			return false;
+		}
+
+		{
+			Type *bt = base_type(operand->type);
+
+			if (bt->kind != Type_Basic || 
+				(bt->Basic.flags & BasicFlag_Unsigned) != 0 || 
+				(bt->Basic.flags & BasicFlag_Integer) == 0) {
+				gbString t = type_to_string(operand->type);
+				error(operand->expr, "Expected a signed integer type for '%.*s', got %s", LIT(builtin_name), t);
+				gb_string_free(t);
+				return false;
+			}
+
+			if ((bt->Basic.flags & BasicFlag_Untyped) != 0) {
+				gbString t = type_to_string(operand->type);
+				error(operand->expr, "Expected a non-untyped integer type for '%.*s', got %s", LIT(builtin_name), t);
+				gb_string_free(t);
+				return false;
+			}
+
+			Type *u_type = &basic_types[bt->Basic.kind + 1];
+
+			operand->type = u_type;
+		}
+		break;
+	case BuiltinProc_type_integer_to_signed:
+		if (operand->mode != Addressing_Type) {
+			error(operand->expr, "Expected a type for '%.*s'", LIT(builtin_name));
+			return false;
+		} 
+
+		if (is_type_polymorphic(operand->type)) {
+			gbString t = type_to_string(operand->type);
+			error(operand->expr, "Expected a non-polymorphic type for '%.*s', got %s", LIT(builtin_name), t);
+			gb_string_free(t);
+			return false;
+		}
+
+		{
+			Type *bt = base_type(operand->type);
+
+			if (bt->kind != Type_Basic || 
+				(bt->Basic.flags & BasicFlag_Unsigned) == 0 || 
+				(bt->Basic.flags & BasicFlag_Integer) == 0) {
+				gbString t = type_to_string(operand->type);
+				error(operand->expr, "Expected an unsigned integer type for '%.*s', got %s", LIT(builtin_name), t);
+				gb_string_free(t);
+				return false;
+			}
+
+			if ((bt->Basic.flags & BasicFlag_Untyped) != 0) {
+				gbString t = type_to_string(operand->type);
+				error(operand->expr, "Expected a non-untyped integer type for '%.*s', got %s", LIT(builtin_name), t);
+				gb_string_free(t);
+				return false;
+			}
+
+			if (bt->Basic.kind == Basic_uintptr) {
+				gbString t = type_to_string(operand->type);
+				error(operand->expr, "Type %s does not have a signed integer mapping for '%.*s'", t, LIT(builtin_name));
+				gb_string_free(t);
+				return false;
+			}
+
+			Type *u_type = &basic_types[bt->Basic.kind - 1];
+
+			operand->type = u_type;
+		}
+		break;
 	case BuiltinProc_type_merge:
 	case BuiltinProc_type_merge:
 		{
 		{
 			operand->mode = Addressing_Type;
 			operand->mode = Addressing_Type;

+ 6 - 0
src/checker_builtin_procs.hpp

@@ -235,6 +235,9 @@ BuiltinProc__type_begin,
 	BuiltinProc_type_convert_variants_to_pointers,
 	BuiltinProc_type_convert_variants_to_pointers,
 	BuiltinProc_type_merge,
 	BuiltinProc_type_merge,
 
 
+	BuiltinProc_type_integer_to_unsigned,
+	BuiltinProc_type_integer_to_signed,
+
 BuiltinProc__type_simple_boolean_begin,
 BuiltinProc__type_simple_boolean_begin,
 	BuiltinProc_type_is_boolean,
 	BuiltinProc_type_is_boolean,
 	BuiltinProc_type_is_integer,
 	BuiltinProc_type_is_integer,
@@ -585,6 +588,9 @@ gb_global BuiltinProc builtin_procs[BuiltinProc_COUNT] = {
 	{STR_LIT("type_convert_variants_to_pointers"), 1, false, Expr_Expr, BuiltinProcPkg_intrinsics},
 	{STR_LIT("type_convert_variants_to_pointers"), 1, false, Expr_Expr, BuiltinProcPkg_intrinsics},
 	{STR_LIT("type_merge"),                2, false, Expr_Expr, BuiltinProcPkg_intrinsics},
 	{STR_LIT("type_merge"),                2, false, Expr_Expr, BuiltinProcPkg_intrinsics},
 
 
+	{STR_LIT("type_integer_to_unsigned"),  1, false, Expr_Expr, BuiltinProcPkg_intrinsics},
+	{STR_LIT("type_integer_to_signed"),    1, false, Expr_Expr, BuiltinProcPkg_intrinsics},
+
 	{STR_LIT(""), 0, false, Expr_Stmt, BuiltinProcPkg_intrinsics},
 	{STR_LIT(""), 0, false, Expr_Stmt, BuiltinProcPkg_intrinsics},
 	{STR_LIT("type_is_boolean"),           1, false, Expr_Expr, BuiltinProcPkg_intrinsics},
 	{STR_LIT("type_is_boolean"),           1, false, Expr_Expr, BuiltinProcPkg_intrinsics},
 	{STR_LIT("type_is_integer"),           1, false, Expr_Expr, BuiltinProcPkg_intrinsics},
 	{STR_LIT("type_is_integer"),           1, false, Expr_Expr, BuiltinProcPkg_intrinsics},

+ 34 - 0
tests/internal/test_intrinsics_integer_to.odin

@@ -0,0 +1,34 @@
+package test_internal
+
+import "base:intrinsics"
+import "core:testing"
+
+/*
+example_usage :: proc(#any_int x: int) -> intrinsics.type_integer_to_unsigned(type_of(x)) {
+	T :: intrinsics.type_integer_to_unsigned(type_of(x))
+	return 1<<T(x)
+}
+*/
+
+@test
+test_intrinsic_integer_to :: proc(t: ^testing.T) {
+	testing.expect_value(t, typeid_of(intrinsics.type_integer_to_unsigned(i16le)), typeid_of(u16le))
+	testing.expect_value(t, typeid_of(intrinsics.type_integer_to_unsigned(i32le)), typeid_of(u32le))
+	testing.expect_value(t, typeid_of(intrinsics.type_integer_to_unsigned(i64le)), typeid_of(u64le))
+	testing.expect_value(t, typeid_of(intrinsics.type_integer_to_unsigned(i128le)), typeid_of(u128le))
+	testing.expect_value(t, typeid_of(intrinsics.type_integer_to_unsigned(i16be)), typeid_of(u16be))
+	testing.expect_value(t, typeid_of(intrinsics.type_integer_to_unsigned(i32be)), typeid_of(u32be))
+	testing.expect_value(t, typeid_of(intrinsics.type_integer_to_unsigned(i64be)), typeid_of(u64be))
+	testing.expect_value(t, typeid_of(intrinsics.type_integer_to_unsigned(i128be)), typeid_of(u128be))
+	testing.expect_value(t, typeid_of(intrinsics.type_integer_to_unsigned(int)), typeid_of(uint))
+
+	testing.expect_value(t, typeid_of(intrinsics.type_integer_to_signed(u16le)), typeid_of(i16le))
+	testing.expect_value(t, typeid_of(intrinsics.type_integer_to_signed(u32le)), typeid_of(i32le))
+	testing.expect_value(t, typeid_of(intrinsics.type_integer_to_signed(u64le)), typeid_of(i64le))
+	testing.expect_value(t, typeid_of(intrinsics.type_integer_to_signed(u128le)), typeid_of(i128le))
+	testing.expect_value(t, typeid_of(intrinsics.type_integer_to_signed(u16be)), typeid_of(i16be))
+	testing.expect_value(t, typeid_of(intrinsics.type_integer_to_signed(u32be)), typeid_of(i32be))
+	testing.expect_value(t, typeid_of(intrinsics.type_integer_to_signed(u64be)), typeid_of(i64be))
+	testing.expect_value(t, typeid_of(intrinsics.type_integer_to_signed(u128be)), typeid_of(i128be))
+	testing.expect_value(t, typeid_of(intrinsics.type_integer_to_signed(uint)), typeid_of(int))
+}