Browse Source

Add simd.{sqrt, ceil, floor, trunc, nearest}

gingerBill 3 years ago
parent
commit
0fd43c1a0b

+ 6 - 0
core/intrinsics/intrinsics.odin

@@ -239,6 +239,12 @@ simd_shuffle :: proc(a, b: #simd[N]T, indices: ..int) -> #simd[len(indices)]T --
 simd_select  :: proc(cond: #simd[N]boolean_or_integer, true, false: #simd[N]T) -> #simd[N]T ---
 
 
+simd_sqrt    :: proc(a: #simd[N]any_float) -> #simd[N]any_float ---
+simd_ceil    :: proc(a: #simd[N]any_float) -> #simd[N]any_float ---
+simd_floor   :: proc(a: #simd[N]any_float) -> #simd[N]any_float ---
+simd_trunc   :: proc(a: #simd[N]any_float) -> #simd[N]any_float ---
+simd_nearest :: proc(a: #simd[N]any_float) -> #simd[N]any_float ---
+
 // WASM targets only
 wasm_memory_grow :: proc(index, delta: uintptr) -> int ---
 wasm_memory_size :: proc(index: uintptr)        -> int ---

+ 7 - 0
core/simd/simd.odin

@@ -83,6 +83,13 @@ shuffle :: intrinsics.simd_shuffle
 // select :: proc(cond: #simd[N]boolean_or_integer, true, false: #simd[N]T) -> #simd[N]T
 select :: intrinsics.simd_select
 
+
+sqrt    :: intrinsics.simd_sqrt
+ceil    :: intrinsics.simd_ceil
+floor   :: intrinsics.simd_floor
+trunc   :: intrinsics.simd_trunc
+nearest :: intrinsics.simd_nearest
+
 splat :: #force_inline proc "contextless" ($T: typeid/#simd[$LANES]$E, value: E) -> T {
 	return T{0..<LANES = value}
 }

+ 26 - 0
src/check_builtin.cpp

@@ -886,6 +886,32 @@ bool check_builtin_simd_operation(CheckerContext *c, Operand *operand, Ast *call
 			return true;
 		}
 
+	case BuiltinProc_simd_sqrt:
+	case BuiltinProc_simd_ceil:
+	case BuiltinProc_simd_floor:
+	case BuiltinProc_simd_trunc:
+	case BuiltinProc_simd_nearest:
+		{
+			Operand x = {};
+			check_expr(c, &x, ce->args[0]); if (x.mode == Addressing_Invalid) { return false; }
+
+			if (!is_type_simd_vector(x.type)) {
+				error(x.expr, "'%.*s' expected a simd vector boolean type", LIT(builtin_name));
+				return false;
+			}
+			Type *elem = base_array_type(x.type);
+			if (!is_type_float(elem)) {
+				gbString x_str = type_to_string(x.type);
+				error(x.expr, "'%.*s' expected a simd vector floating point type, got '%s'", LIT(builtin_name), x_str);
+				gb_string_free(x_str);
+				return false;
+			}
+
+			operand->mode = Addressing_Value;
+			operand->type = x.type;
+			return true;
+		}
+
 
 	default:
 		GB_PANIC("Unhandled simd intrinsic: %.*s", LIT(builtin_name));

+ 5 - 2
src/check_type.cpp

@@ -2797,7 +2797,7 @@ bool check_type_internal(CheckerContext *ctx, Ast *e, Type **type, Type *named_t
 				} else if (name == "simd") {
 					if (!is_type_valid_vector_elem(elem) && !is_type_polymorphic(elem)) {
 						gbString str = type_to_string(elem);
-						error(at->elem, "Invalid element type for 'intrinsics.simd_vector', expected an integer, float, or boolean with no specific endianness, got '%s'", str);
+						error(at->elem, "Invalid element type for #simd, expected an integer, float, or boolean with no specific endianness, got '%s'", str);
 						gb_string_free(str);
 						*type = alloc_type_array(elem, count, generic_type);
 						goto array_end;
@@ -2806,7 +2806,7 @@ bool check_type_internal(CheckerContext *ctx, Ast *e, Type **type, Type *named_t
 					if (is_type_polymorphic(elem)) {
 						// Ignore
 					} else if (count < 1 || !is_power_of_two(count)) {
-						error(at->count, "Invalid length for 'intrinsics.simd_vector', expected a power of two length, got '%lld'", cast(long long)count);
+						error(at->count, "Invalid length for #simd, expected a power of two length, got '%lld'", cast(long long)count);
 						*type = alloc_type_array(elem, count, generic_type);
 						goto array_end;
 					} else
@@ -2817,6 +2817,9 @@ bool check_type_internal(CheckerContext *ctx, Ast *e, Type **type, Type *named_t
 							error(at->count, "wasm based targets are limited to 128-bit types");
 						}
 					}
+					if (count > SIMD_ELEMENT_COUNT_MAX) {
+						error(at->count, "#simd support a maximum element count of %d, got %lld", SIMD_ELEMENT_COUNT_MAX, cast(long long)count);
+					}
 				} else {
 					error(at->tag, "Invalid tag applied to array, got #%.*s", LIT(name));
 					*type = alloc_type_array(elem, count, generic_type);

+ 12 - 0
src/checker_builtin_procs.hpp

@@ -159,6 +159,12 @@ BuiltinProc__simd_begin,
 
 	BuiltinProc_simd_shuffle,
 	BuiltinProc_simd_select,
+
+	BuiltinProc_simd_sqrt,
+	BuiltinProc_simd_ceil,
+	BuiltinProc_simd_floor,
+	BuiltinProc_simd_trunc,
+	BuiltinProc_simd_nearest,
 BuiltinProc__simd_end,
 	
 	// Platform specific intrinsics
@@ -421,6 +427,12 @@ gb_global BuiltinProc builtin_procs[BuiltinProc_COUNT] = {
 
 	{STR_LIT("simd_shuffle"), 2, true,  Expr_Expr, BuiltinProcPkg_intrinsics},
 	{STR_LIT("simd_select"),  3, false, Expr_Expr, BuiltinProcPkg_intrinsics},
+
+	{STR_LIT("simd_sqrt") , 1, false, Expr_Expr, BuiltinProcPkg_intrinsics},
+	{STR_LIT("simd_ceil") , 1, false, Expr_Expr, BuiltinProcPkg_intrinsics},
+	{STR_LIT("simd_floor"), 1, false, Expr_Expr, BuiltinProcPkg_intrinsics},
+	{STR_LIT("simd_trunc"), 1, false, Expr_Expr, BuiltinProcPkg_intrinsics},
+	{STR_LIT("simd_nearest"), 1, false, Expr_Expr, BuiltinProcPkg_intrinsics},
 	{STR_LIT(""), 0, false, Expr_Stmt, BuiltinProcPkg_intrinsics},
 
 

+ 27 - 3
src/llvm_backend_proc.cpp

@@ -1231,9 +1231,7 @@ lbValue lb_build_builtin_simd_proc(lbProcedure *p, Ast *expr, TypeAndValue const
 			GB_ASSERT_MSG(id != 0, "Unable to find %s.%s", name, LLVMPrintTypeToString(types[0]));
 			LLVMValueRef ip = LLVMGetIntrinsicDeclaration(p->module->mod, id, types, gb_count_of(types));
 
-			lbValue res = {};
 			res.value = LLVMBuildCall(p->builder, ip, args, cast(unsigned)args_count, "");
-			res.type = tv.type;
 			return res;
 		}
 	case BuiltinProc_simd_reduce_min:
@@ -1274,7 +1272,6 @@ lbValue lb_build_builtin_simd_proc(lbProcedure *p, Ast *expr, TypeAndValue const
 			LLVMValueRef args[1] = {};
 			args[0] = arg0.value;
 
-			lbValue res = {};
 			res.value = LLVMBuildCall(p->builder, ip, args, gb_count_of(args), "");
 			return res;
 		}
@@ -1314,6 +1311,33 @@ lbValue lb_build_builtin_simd_proc(lbProcedure *p, Ast *expr, TypeAndValue const
 			return res;
 		}
 
+	case BuiltinProc_simd_sqrt:
+	case BuiltinProc_simd_ceil:
+	case BuiltinProc_simd_floor:
+	case BuiltinProc_simd_trunc:
+	case BuiltinProc_simd_nearest:
+		{
+			char const *name = nullptr;
+			switch (builtin_id) {
+			case BuiltinProc_simd_sqrt:    name = "llvm.sqrt"; break;
+			case BuiltinProc_simd_ceil:    name = "llvm.ceil"; break;
+			case BuiltinProc_simd_floor:   name = "llvm.floor"; break;
+			case BuiltinProc_simd_trunc:   name = "llvm.trunc"; break;
+			case BuiltinProc_simd_nearest: name = "llvm.nearbyint"; break;
+			}
+
+			LLVMTypeRef types[1] = {lb_type(p->module, arg0.type)};
+			unsigned id = LLVMLookupIntrinsicID(name, gb_strlen(name));
+			GB_ASSERT_MSG(id != 0, "Unable to find %s.%s", name, LLVMPrintTypeToString(types[0]));
+			LLVMValueRef ip = LLVMGetIntrinsicDeclaration(p->module->mod, id, types, gb_count_of(types));
+
+			LLVMValueRef args[1] = {};
+			args[0] = arg0.value;
+
+			res.value = LLVMBuildCall(p->builder, ip, args, gb_count_of(args), "");
+			return res;
+		}
+
 	}
 	GB_PANIC("Unhandled simd intrinsic: '%.*s'", LIT(builtin_procs[builtin_id].name));
 

+ 3 - 0
src/types.cpp

@@ -363,6 +363,9 @@ enum : int {
 	MATRIX_ELEMENT_COUNT_MIN = 1,
 	MATRIX_ELEMENT_COUNT_MAX = 16,
 	MATRIX_ELEMENT_MAX_SIZE = MATRIX_ELEMENT_COUNT_MAX * (2 * 8), // complex128
+
+	SIMD_ELEMENT_COUNT_MIN = 1,
+	SIMD_ELEMENT_COUNT_MAX = 64,
 };