Browse Source

Support swizzle selector syntax `.xyzw` for `#simd` vectors

gingerBill 1 year ago
parent
commit
c7c6852057
4 changed files with 82 additions and 32 deletions
  1. 9 4
      src/check_expr.cpp
  2. 2 2
      src/llvm_backend_expr.cpp
  3. 25 1
      src/llvm_backend_general.cpp
  4. 46 25
      src/types.cpp

+ 9 - 4
src/check_expr.cpp

@@ -4920,7 +4920,7 @@ gb_internal Entity *check_selector(CheckerContext *c, Operand *operand, Ast *nod
 		}
 		}
 	}
 	}
 
 
-	if (entity == nullptr && selector->kind == Ast_Ident && is_type_array(type_deref(operand->type))) {
+	if (entity == nullptr && selector->kind == Ast_Ident && (is_type_array(type_deref(operand->type)) || is_type_simd_vector(type_deref(operand->type)))) {
 		String field_name = selector->Ident.token.string;
 		String field_name = selector->Ident.token.string;
 		if (1 < field_name.len && field_name.len <= 4) {
 		if (1 < field_name.len && field_name.len <= 4) {
 			u8 swizzles_xyzw[4] = {'x', 'y', 'z', 'w'};
 			u8 swizzles_xyzw[4] = {'x', 'y', 'z', 'w'};
@@ -4975,8 +4975,10 @@ gb_internal Entity *check_selector(CheckerContext *c, Operand *operand, Ast *nod
 
 
 			Type *original_type = operand->type;
 			Type *original_type = operand->type;
 			Type *array_type = base_type(type_deref(original_type));
 			Type *array_type = base_type(type_deref(original_type));
-			GB_ASSERT(array_type->kind == Type_Array);
-			i64 array_count = array_type->Array.count;
+			GB_ASSERT(array_type->kind == Type_Array || array_type->kind == Type_SimdVector);
+
+			i64 array_count = get_array_type_count(array_type);
+
 			for (u8 i = 0; i < index_count; i++) {
 			for (u8 i = 0; i < index_count; i++) {
 				u8 idx = indices>>(i*2) & 3;
 				u8 idx = indices>>(i*2) & 3;
 				if (idx >= array_count) {
 				if (idx >= array_count) {
@@ -4996,7 +4998,6 @@ gb_internal Entity *check_selector(CheckerContext *c, Operand *operand, Ast *nod
 			se->swizzle_count = index_count;
 			se->swizzle_count = index_count;
 			se->swizzle_indices = indices;
 			se->swizzle_indices = indices;
 
 
-
 			AddressingMode prev_mode = operand->mode;
 			AddressingMode prev_mode = operand->mode;
 			operand->mode = Addressing_SwizzleValue;
 			operand->mode = Addressing_SwizzleValue;
 			operand->type = determine_swizzle_array_type(original_type, type_hint, index_count);
 			operand->type = determine_swizzle_array_type(original_type, type_hint, index_count);
@@ -5010,6 +5011,10 @@ gb_internal Entity *check_selector(CheckerContext *c, Operand *operand, Ast *nod
 				break;
 				break;
 			}
 			}
 
 
+			if (array_type->kind == Type_SimdVector) {
+				operand->mode = Addressing_Value;
+			}
+
 			Entity *swizzle_entity = alloc_entity_variable(nullptr, make_token_ident(field_name), operand->type, EntityState_Resolved);
 			Entity *swizzle_entity = alloc_entity_variable(nullptr, make_token_ident(field_name), operand->type, EntityState_Resolved);
 			add_type_and_value(c, operand->expr, operand->mode, operand->type, operand->value);
 			add_type_and_value(c, operand->expr, operand->mode, operand->type, operand->value);
 			return swizzle_entity;
 			return swizzle_entity;

+ 2 - 2
src/llvm_backend_expr.cpp

@@ -4655,7 +4655,7 @@ gb_internal lbAddr lb_build_addr_internal(lbProcedure *p, Ast *expr) {
 
 
 			if (se->swizzle_count > 0) {
 			if (se->swizzle_count > 0) {
 				Type *array_type = base_type(type_deref(tav.type));
 				Type *array_type = base_type(type_deref(tav.type));
-				GB_ASSERT(array_type->kind == Type_Array);
+				GB_ASSERT(array_type->kind == Type_Array || array_type->kind == Type_SimdVector);
 				u8 swizzle_count = se->swizzle_count;
 				u8 swizzle_count = se->swizzle_count;
 				u8 swizzle_indices_raw = se->swizzle_indices;
 				u8 swizzle_indices_raw = se->swizzle_indices;
 				u8 swizzle_indices[4] = {};
 				u8 swizzle_indices[4] = {};
@@ -4671,7 +4671,7 @@ gb_internal lbAddr lb_build_addr_internal(lbProcedure *p, Ast *expr) {
 					a = lb_addr_get_ptr(p, addr);
 					a = lb_addr_get_ptr(p, addr);
 				}
 				}
 
 
-				GB_ASSERT(is_type_array(expr->tav.type));
+				GB_ASSERT(is_type_array(expr->tav.type) || is_type_simd_vector(expr->tav.type));
 				return lb_addr_swizzle(a, expr->tav.type, swizzle_count, swizzle_indices);
 				return lb_addr_swizzle(a, expr->tav.type, swizzle_count, swizzle_indices);
 			}
 			}
 
 

+ 25 - 1
src/llvm_backend_general.cpp

@@ -434,7 +434,7 @@ gb_internal lbAddr lb_addr_soa_variable(lbValue addr, lbValue index, Ast *index_
 }
 }
 
 
 gb_internal lbAddr lb_addr_swizzle(lbValue addr, Type *array_type, u8 swizzle_count, u8 swizzle_indices[4]) {
 gb_internal lbAddr lb_addr_swizzle(lbValue addr, Type *array_type, u8 swizzle_count, u8 swizzle_indices[4]) {
-	GB_ASSERT(is_type_array(array_type));
+	GB_ASSERT(is_type_array(array_type) || is_type_simd_vector(array_type));
 	GB_ASSERT(1 < swizzle_count && swizzle_count <= 4);
 	GB_ASSERT(1 < swizzle_count && swizzle_count <= 4);
 	lbAddr v = {lbAddr_Swizzle, addr};
 	lbAddr v = {lbAddr_Swizzle, addr};
 	v.swizzle.type = array_type;
 	v.swizzle.type = array_type;
@@ -1264,6 +1264,30 @@ gb_internal lbValue lb_addr_load(lbProcedure *p, lbAddr const &addr) {
 		return lb_addr_load(p, res);
 		return lb_addr_load(p, res);
 	} else if (addr.kind == lbAddr_Swizzle) {
 	} else if (addr.kind == lbAddr_Swizzle) {
 		Type *array_type = base_type(addr.swizzle.type);
 		Type *array_type = base_type(addr.swizzle.type);
+		if (array_type->kind == Type_SimdVector) {
+			lbValue vec = lb_emit_load(p, addr.addr);
+			u8 index_count = addr.swizzle.count;
+			if (index_count == 0) {
+				return vec;
+			}
+
+			unsigned mask_len = cast(unsigned)index_count;
+			LLVMValueRef *mask_elems = gb_alloc_array(permanent_allocator(), LLVMValueRef, index_count);
+			for (isize i = 0; i < index_count; i++) {
+				mask_elems[i] = LLVMConstInt(lb_type(p->module, t_u32), addr.swizzle.indices[i], false);
+			}
+
+			LLVMValueRef mask = LLVMConstVector(mask_elems, mask_len);
+
+			LLVMValueRef v1 = vec.value;
+			LLVMValueRef v2 = vec.value;
+
+			lbValue res = {};
+			res.type = addr.swizzle.type;
+			res.value = LLVMBuildShuffleVector(p->builder, v1, v2, mask, "");
+			return res;
+		}
+
 		GB_ASSERT(array_type->kind == Type_Array);
 		GB_ASSERT(array_type->kind == Type_Array);
 
 
 		unsigned res_align = cast(unsigned)type_align_of(addr.swizzle.type);
 		unsigned res_align = cast(unsigned)type_align_of(addr.swizzle.type);

+ 46 - 25
src/types.cpp

@@ -3430,31 +3430,6 @@ gb_internal Selection lookup_field_with_selection(Type *type_, String field_name
 		}
 		}
 
 
 		return sel;
 		return sel;
-	} else if (type->kind == Type_Array) {
-		if (type->Array.count <= 4) {
-			// HACK(bill): Memory leak
-			switch (type->Array.count) {
-			#define _ARRAY_FIELD_CASE_IF(_length, _name) \
-				if (field_name == (_name)) { \
-					selection_add_index(&sel, (_length)-1); \
-					sel.entity = alloc_entity_array_elem(nullptr, make_token_ident(str_lit(_name)), type->Array.elem, (_length)-1); \
-					return sel; \
-				}
-			#define _ARRAY_FIELD_CASE(_length, _name0, _name1) \
-			case (_length): \
-				_ARRAY_FIELD_CASE_IF(_length, _name0); \
-				_ARRAY_FIELD_CASE_IF(_length, _name1); \
-				/*fallthrough*/
-
-			_ARRAY_FIELD_CASE(4, "w", "a");
-			_ARRAY_FIELD_CASE(3, "z", "b");
-			_ARRAY_FIELD_CASE(2, "y", "g");
-			_ARRAY_FIELD_CASE(1, "x", "r");
-			default: break;
-
-			#undef _ARRAY_FIELD_CASE
-			}
-		}
 	} else if (type->kind == Type_DynamicArray) {
 	} else if (type->kind == Type_DynamicArray) {
 		GB_ASSERT(t_allocator != nullptr);
 		GB_ASSERT(t_allocator != nullptr);
 		String allocator_str = str_lit("allocator");
 		String allocator_str = str_lit("allocator");
@@ -3475,7 +3450,53 @@ gb_internal Selection lookup_field_with_selection(Type *type_, String field_name
 			sel.entity = entity__allocator;
 			sel.entity = entity__allocator;
 			return sel;
 			return sel;
 		}
 		}
+
+
+#define _ARRAY_FIELD_CASE_IF(_length, _name) \
+	if (field_name == (_name)) { \
+		selection_add_index(&sel, (_length)-1); \
+		sel.entity = alloc_entity_array_elem(nullptr, make_token_ident(str_lit(_name)), elem, (_length)-1); \
+		return sel; \
 	}
 	}
+#define _ARRAY_FIELD_CASE(_length, _name0, _name1) \
+case (_length): \
+	_ARRAY_FIELD_CASE_IF(_length, _name0); \
+	_ARRAY_FIELD_CASE_IF(_length, _name1); \
+	/*fallthrough*/
+
+
+	} else if (type->kind == Type_Array) {
+
+		Type *elem = type->Array.elem;
+
+		if (type->Array.count <= 4) {
+			// HACK(bill): Memory leak
+			switch (type->Array.count) {
+
+			_ARRAY_FIELD_CASE(4, "w", "a");
+			_ARRAY_FIELD_CASE(3, "z", "b");
+			_ARRAY_FIELD_CASE(2, "y", "g");
+			_ARRAY_FIELD_CASE(1, "x", "r");
+			default: break;
+			}
+		}
+	} else if (type->kind == Type_SimdVector) {
+
+		Type *elem = type->SimdVector.elem;
+		if (type->SimdVector.count <= 4) {
+			// HACK(bill): Memory leak
+			switch (type->SimdVector.count) {
+			_ARRAY_FIELD_CASE(4, "w", "a");
+			_ARRAY_FIELD_CASE(3, "z", "b");
+			_ARRAY_FIELD_CASE(2, "y", "g");
+			_ARRAY_FIELD_CASE(1, "x", "r");
+			default: break;
+			}
+		}
+	}
+
+#undef _ARRAY_FIELD_CASE
+#undef _ARRAY_FIELD_CASE
 
 
 	return sel;
 	return sel;
 }
 }