Browse Source

Support `count_ones` etc with #simd

gingerBill 3 years ago
parent
commit
20e7b5c88a
4 changed files with 26 additions and 12 deletions
  1. 4 4
      core/intrinsics/intrinsics.odin
  2. 10 5
      core/simd/simd.odin
  3. 8 1
      src/check_builtin.cpp
  4. 4 2
      src/llvm_backend_utility.cpp

+ 4 - 4
core/intrinsics/intrinsics.odin

@@ -22,10 +22,10 @@ alloca             :: proc(size, align: int) -> [^]u8 ---
 cpu_relax          :: proc() ---
 read_cycle_counter :: proc() -> i64 ---
 
-count_ones           :: proc(x: $T) -> T where type_is_integer(T) ---
-count_zeros          :: proc(x: $T) -> T where type_is_integer(T) ---
-count_trailing_zeros :: proc(x: $T) -> T where type_is_integer(T) ---
-count_leading_zeros  :: proc(x: $T) -> T where type_is_integer(T) ---
+count_ones           :: proc(x: $T) -> T where type_is_integer(T) || type_is_simd_vector(T) ---
+count_zeros          :: proc(x: $T) -> T where type_is_integer(T) || type_is_simd_vector(T) ---
+count_trailing_zeros :: proc(x: $T) -> T where type_is_integer(T) || type_is_simd_vector(T) ---
+count_leading_zeros  :: proc(x: $T) -> T where type_is_integer(T) || type_is_simd_vector(T) ---
 reverse_bits         :: proc(x: $T) -> T where type_is_integer(T) ---
 byte_swap            :: proc(x: $T) -> T where type_is_integer(T) || type_is_float(T) ---
 

+ 10 - 5
core/simd/simd.odin

@@ -104,6 +104,11 @@ reverse :: intrinsics.simd_reverse
 rotate_left  :: intrinsics.simd_rotate_left
 rotate_right :: intrinsics.simd_rotate_right
 
+count_ones           :: intrinsics.count_ones
+count_zeros          :: intrinsics.count_zeros
+count_trailing_zeros :: intrinsics.count_trailing_zeros
+count_leading_zeros  :: intrinsics.count_leading_zeros
+
 to_array_ptr :: #force_inline proc "contextless" (v: ^#simd[$LANES]$E) -> ^[LANES]E {
 	return (^[LANES]E)(v)
 }
@@ -129,16 +134,16 @@ bit_not :: #force_inline proc "contextless" (v: $T/#simd[$LANES]$E) -> T where i
 
 copysign :: #force_inline proc "contextless" (v, sign: $T/#simd[$LANES]$E) -> T where intrinsics.type_is_float(E) {
 	neg_zero := to_bits(T(-0.0))
-	sign_bit := and(to_bits(sign), neg_zero)
-	magnitude := and(to_bits(v), bit_not(neg_zero))
-	return transmute(T)or(sign_bit, magnitude)
+	sign_bit := to_bits(sign) & neg_zero
+	magnitude := to_bits(v) &~ neg_zero
+	return transmute(T)(sign_bit|magnitude)
 }
 
 signum :: #force_inline proc "contextless" (v: $T/#simd[$LANES]$E) -> T where intrinsics.type_is_float(E) {
-	is_nan := ne(v, v)
+	is_nan := lanes_ne(v, v)
 	return select(is_nan, v, copysign(T(1), v))
 }
 
 recip :: #force_inline proc "contextless" (v: $T/#simd[$LANES]$E) -> T where intrinsics.type_is_float(E) {
-	return div(T(1), v)
+	return T(1) / v
 }

+ 8 - 1
src/check_builtin.cpp

@@ -3559,7 +3559,14 @@ bool check_builtin_procedure(CheckerContext *c, Operand *operand, Ast *call, i32
 				return false;
 			}
 
-			if (!is_type_integer_like(x.type)) {
+			if (is_type_simd_vector(x.type) && id != BuiltinProc_reverse_bits) {
+				Type *elem = base_array_type(x.type);
+				if (!is_type_integer_like(elem)) {
+					gbString xts = type_to_string(x.type);
+					error(x.expr, "#simd values passed to '%.*s' must have an element of an integer-like type (integer, boolean, enum, bit_set), got %s", LIT(builtin_name), xts);
+					gb_string_free(xts);
+				}
+			} else if (!is_type_integer_like(x.type)) {
 				gbString xts = type_to_string(x.type);
 				error(x.expr, "Values passed to '%.*s' must be an integer-like type (integer, boolean, enum, bit_set), got %s", LIT(builtin_name), xts);
 				gb_string_free(xts);

+ 4 - 2
src/llvm_backend_utility.cpp

@@ -485,8 +485,10 @@ lbValue lb_emit_count_ones(lbProcedure *p, lbValue x, Type *type) {
 }
 
 lbValue lb_emit_count_zeros(lbProcedure *p, lbValue x, Type *type) {
-	i64 sz = 8*type_size_of(type);
-	lbValue size = lb_const_int(p->module, type, cast(u64)sz);
+	Type *elem = base_array_type(type);
+	i64 sz = 8*type_size_of(elem);
+	lbValue size = lb_const_int(p->module, elem, cast(u64)sz);
+	size = lb_emit_conv(p, size, type);
 	lbValue count = lb_emit_count_ones(p, x, type);
 	return lb_emit_arith(p, Token_Sub, size, count, type);
 }