Allow swizzling assign, eg. abc.xz += { 5, 10 };

This commit is contained in:
Christoffer Lerno
2025-03-04 02:18:24 +01:00
parent 0a905d8458
commit 0ef99c23a8
7 changed files with 116 additions and 20 deletions

View File

@@ -16,6 +16,7 @@ static LLVMValueRef llvm_emit_dynamic_search(GenContext *c, LLVMValueRef type_id
static inline void llvm_emit_bitassign_array(GenContext *c, LLVMValueRef result, BEValue parent, Decl *parent_decl, Decl *member);
static inline void llvm_emit_builtin_access(GenContext *c, BEValue *be_value, Expr *expr);
static inline void llvm_emit_const_initialize_reference(GenContext *c, BEValue *ref, Expr *expr);
static void llvm_emit_swizzle_from_value(GenContext *c, LLVMValueRef vector_value, BEValue *value, Expr *expr);
static inline void llvm_emit_optional(GenContext *c, BEValue *be_value, Expr *expr);
static inline void llvm_emit_inc_dec_change(GenContext *c, BEValue *addr, BEValue *after, BEValue *before, Expr *expr, int diff,
@@ -4343,17 +4344,58 @@ static void llvm_emit_vector_assign_expr(GenContext *c, BEValue *be_value, Expr
Expr *left = exprptr(expr->binary_expr.left);
BinaryOp binary_op = expr->binary_expr.operator;
BEValue addr;
BEValue index;
bool is_swizzle = left->expr_kind == EXPR_SWIZZLE;
if (left->expr_kind == EXPR_SWIZZLE)
{
// Emit the variable
llvm_emit_exprid(c, &addr, left->swizzle_expr.parent);
}
else
{
// Emit the variable
llvm_emit_exprid(c, &addr, left->subscript_expr.expr);
}
// Emit the variable
llvm_emit_exprid(c, &addr, left->subscript_expr.expr);
llvm_value_addr(c, &addr);
LLVMValueRef vector_value = llvm_load_value_store(c, &addr);
LLVMValueRef vector_value = llvm_load_value_store(c, &addr);
if (is_swizzle)
{
if (addr.type->array.base == type_bool) vector_value = llvm_emit_trunc_bool(c, vector_value);
if (binary_op > BINARYOP_ASSIGN)
{
BEValue lhs;
llvm_emit_swizzle_from_value(c, llvm_load_value_store(c, &addr), &lhs, left);
BinaryOp base_op = binaryop_assign_base_op(binary_op);
ASSERT(base_op != BINARYOP_ERROR);
llvm_value_rvalue(c, &lhs);
llvm_emit_binary(c, be_value, expr, &lhs, base_op);
}
else
{
llvm_emit_expr(c, be_value, exprptr(expr->binary_expr.right));
}
llvm_value_rvalue(c, be_value);
const char *sw_ptr = left->swizzle_expr.swizzle;
unsigned vec_len = be_value->type->array.len;
LLVMValueRef result = be_value->value;
for (unsigned i = 0; i < vec_len; i++)
{
int index = (swizzle[(int)sw_ptr[i]] - 1) & 0xF;
LLVMValueRef val = llvm_emit_extract_value(c, result, i);
vector_value = llvm_emit_insert_value(c, vector_value, val, index);
}
llvm_value_set(be_value, vector_value, addr.type);
llvm_store(c, &addr, be_value);
llvm_value_set(be_value, result, expr->type);
return;
}
// Emit the index
BEValue index;
llvm_emit_exprid(c, &index, left->subscript_expr.index.expr);
LLVMValueRef index_val = llvm_load_value_store(c, &index);
if (binary_op > BINARYOP_ASSIGN)
{
BinaryOp base_op = binaryop_assign_base_op(binary_op);
@@ -4367,15 +4409,17 @@ static void llvm_emit_vector_assign_expr(GenContext *c, BEValue *be_value, Expr
llvm_emit_expr(c, be_value, exprptr(expr->binary_expr.right));
}
LLVMValueRef new_value = LLVMBuildInsertElement(c->builder, vector_value, llvm_load_value_store(c, be_value), index_val, "elemset");
LLVMValueRef new_value = LLVMBuildInsertElement(c->builder, vector_value, llvm_load_value_store(c, be_value),
index_val, "elemset");
llvm_store_raw(c, &addr, new_value);
}
static void llvm_emit_binary_expr(GenContext *c, BEValue *be_value, Expr *expr)
{
BinaryOp binary_op = expr->binary_expr.operator;
// Vector assign is handled separately.
if (binary_op >= BINARYOP_ASSIGN && expr_is_vector_index(exprptr(expr->binary_expr.left)))
if (binary_op >= BINARYOP_ASSIGN && expr_is_vector_index_or_swizzle(exprptr(expr->binary_expr.left)))
{
llvm_emit_vector_assign_expr(c, be_value, expr);
return;
@@ -6675,12 +6719,8 @@ static void llmv_emit_test_hook(GenContext *c, BEValue *value, Expr *expr)
llvm_value_set_address_abi_aligned(value, get_global, expr->type);
}
static void llvm_emit_swizzle(GenContext *c, BEValue *value, Expr *expr)
static void llvm_emit_swizzle_from_value(GenContext *c, LLVMValueRef vector_value, BEValue *value, Expr *expr)
{
llvm_emit_exprid(c, value, expr->swizzle_expr.parent);
llvm_value_rvalue(c, value);
LLVMValueRef parent = value->value;
LLVMTypeRef result_type = llvm_get_type(c, expr->type);
unsigned vec_len = LLVMGetVectorSize(result_type);
LLVMValueRef mask_val[4];
@@ -6691,10 +6731,17 @@ static void llvm_emit_swizzle(GenContext *c, BEValue *value, Expr *expr)
int index = (swizzle[(int)sw_ptr[i]] - 1) & 0xF;
mask_val[i] = llvm_const_int(c, type_uint, index);
}
LLVMValueRef res = LLVMBuildShuffleVector(c->builder, parent, LLVMGetUndef(LLVMTypeOf(parent)), LLVMConstVector(mask_val, vec_len), sw_ptr);
LLVMValueRef res = LLVMBuildShuffleVector(c->builder, vector_value, LLVMGetUndef(LLVMTypeOf(vector_value)), LLVMConstVector(mask_val, vec_len), sw_ptr);
llvm_value_set(value, res, expr->type);
}
static void llvm_emit_swizzle(GenContext *c, BEValue *value, Expr *expr)
{
llvm_emit_exprid(c, value, expr->swizzle_expr.parent);
llvm_value_rvalue(c, value);
llvm_emit_swizzle_from_value(c, value->value, value, expr);
}
static void llvm_emit_default_arg(GenContext *c, BEValue *value, Expr *expr)
{
if (llvm_use_debug(c))