This commit is contained in:
gingerBill
2026-06-05 14:13:18 +01:00
9 changed files with 101 additions and 41 deletions

View File

@@ -3550,7 +3550,8 @@ parse_unary_expr :: proc(p: ^Parser, lhs: bool) -> ^ast.Expr {
case .Add, .Sub,
.Not, .Xor,
.And:
.And,
.Mul_Mul:
op := advance_token(p)
expr := parse_unary_expr(p, lhs)

View File

@@ -67,6 +67,8 @@ Token_Kind :: enum u32 {
Cmp_And, // &&
Cmp_Or, // ||
Mul_Mul, // **
B_Assign_Op_Begin,
Add_Eq, // +=
Sub_Eq, // -=
@@ -202,6 +204,8 @@ tokens := [Token_Kind.COUNT]string {
"&&",
"||",
"**",
"",
"+=",
"-=",

View File

@@ -679,6 +679,9 @@ scan :: proc(t: ^Tokenizer) -> Token {
if t.ch == '=' {
advance_rune(t)
kind = .Mul_Eq
} else if t.ch == '*' {
advance_rune(t)
kind = .Mul_Mul
}
case '=':
kind = .Eq

View File

@@ -1173,7 +1173,7 @@ gb_internal bool check_builtin_simd_operation(CheckerContext *c, Operand *operan
// masked_load (ptr: rawptr, values: #simd[N]T, mask: #simd[N]int_or_bool) -> #simd[N]T
// masked_store(ptr: rawptr, values: #simd[N]T, mask: #simd[N]int_or_bool)
// masked_expand_load (ptr: rawptr, values: #simd[N]T, mask: #simd[N]int_or_bool) -> #simd[N]T
// masked_expand_load (ptr: rawptr, values: #simd[N]T, mask: #simd[N]int_or_bool) -> #simd[N]T
// masked_compress_store(ptr: rawptr, values: #simd[N]T, mask: #simd[N]int_or_bool)
Operand ptr = {};

View File

@@ -2950,6 +2950,43 @@ gb_internal void check_unary_expr(CheckerContext *c, Operand *o, Token op, Ast *
return;
}
case Token_MulMul: { // 'expand_values' operator
if (!o->type) {
return;
}
Type *type = base_type(o->type);
if (!is_type_struct(type) && !is_type_array(type)) {
gbString type_str = type_to_string(o->type);
error(node, "Expected a struct or array type to 'expand_values', got '%s'", type_str);
gb_string_free(type_str);
return;
}
Type *tuple = alloc_type_tuple();
if (is_type_struct(type)) {
isize variable_count = type->Struct.fields.count;
tuple->Tuple.variables = permanent_slice_make<Entity *>(variable_count);
// NOTE(bill): don't copy the entities, this should be good enough
gb_memmove_array(tuple->Tuple.variables.data, type->Struct.fields.data, variable_count);
} else if (is_type_array(type)) {
isize variable_count = cast(isize)type->Array.count;
tuple->Tuple.variables = permanent_slice_make<Entity *>(variable_count);
for (isize i = 0; i < variable_count; i++) {
tuple->Tuple.variables[i] = alloc_entity_array_elem(nullptr, blank_token, type->Array.elem, cast(i32)i);
}
}
o->type = tuple;
o->mode = Addressing_Value;
if (tuple->Tuple.variables.count == 1) {
o->type = tuple->Tuple.variables[0]->type;
}
return;
}
}
if (!check_unary_op(c, o, op)) {

View File

@@ -1,5 +1,6 @@
gb_internal lbValue lb_emit_arith_matrix(lbProcedure *p, TokenKind op, lbValue lhs, lbValue rhs, Type *type, bool component_wise);
gb_internal lbValue lb_build_slice_expr_value(lbProcedure *p, Ast *expr);
gb_internal lbValue lb_expand_values(lbProcedure *p, lbValue val, Type *type);
gb_internal LLVMValueRef lb_const_low_bits_mask(LLVMTypeRef type, u64 bit_count) {
GB_ASSERT(bit_count <= 64);
@@ -4668,6 +4669,11 @@ gb_internal lbValue lb_build_expr_internal(lbProcedure *p, Ast *expr) {
switch (ue->op.kind) {
case Token_And:
return lb_build_unary_and(p, expr);
case Token_MulMul:
{
lbValue val = lb_build_expr(p, ue->expr);
return lb_expand_values(p, val, type);
}
default:
{
lbValue v = lb_build_expr(p, ue->expr);

View File

@@ -1324,6 +1324,48 @@ gb_internal lbValue lb_emit_call(lbProcedure *p, lbValue value, Array<lbValue> c
return result;
}
gb_internal lbValue lb_expand_values(lbProcedure *p, lbValue val, Type *type) {
Type *t = base_type(val.type);
if (!is_type_tuple(type)) {
if (t->kind == Type_Struct) {
GB_ASSERT(t->Struct.fields.count == 1);
return lb_emit_struct_ev(p, val, 0);
} else if (t->kind == Type_Array) {
GB_ASSERT(t->Array.count == 1);
return lb_emit_struct_ev(p, val, 0);
} else {
GB_PANIC("Unknown type of expand_values");
}
}
GB_ASSERT(is_type_tuple(type));
// NOTE(bill): Doesn't need to be zero because it will be initialized in the loops
lbValue tuple = lb_addr_get_ptr(p, lb_add_local_generated(p, type, false));
if (t->kind == Type_Struct) {
for_array(src_index, t->Struct.fields) {
Entity *field = t->Struct.fields[src_index];
i32 field_index = field->Variable.field_index;
lbValue f = lb_emit_struct_ev(p, val, field_index);
lbValue ep = lb_emit_struct_ep(p, tuple, cast(i32)src_index);
lb_emit_store(p, ep, f);
}
} else if (is_type_array_like(t)) {
// TODO(bill): Clean-up this code
lbValue ap = lb_address_from_load_or_generate_local(p, val);
i32 n = cast(i32)get_array_type_count(t);
for (i32 i = 0; i < n; i++) {
lbValue f = lb_emit_load(p, lb_emit_array_epi(p, ap, i));
lbValue ep = lb_emit_struct_ep(p, tuple, i);
lb_emit_store(p, ep, f);
}
} else {
GB_PANIC("Unknown type of expand_values");
}
return lb_emit_load(p, tuple);
}
gb_internal LLVMValueRef llvm_splat_int(i64 count, LLVMTypeRef type, i64 value, bool is_signed=false) {
LLVMValueRef v = LLVMConstInt(type, value, is_signed);
LLVMValueRef *values = gb_alloc_array(temporary_allocator(), LLVMValueRef, count);
@@ -3054,45 +3096,7 @@ gb_internal lbValue lb_build_builtin_proc(lbProcedure *p, Ast *expr, TypeAndValu
case BuiltinProc_expand_values: {
lbValue val = lb_build_expr(p, ce->args[0]);
Type *t = base_type(val.type);
if (!is_type_tuple(tv.type)) {
if (t->kind == Type_Struct) {
GB_ASSERT(t->Struct.fields.count == 1);
return lb_emit_struct_ev(p, val, 0);
} else if (t->kind == Type_Array) {
GB_ASSERT(t->Array.count == 1);
return lb_emit_struct_ev(p, val, 0);
} else {
GB_PANIC("Unknown type of expand_values");
}
}
GB_ASSERT(is_type_tuple(tv.type));
// NOTE(bill): Doesn't need to be zero because it will be initialized in the loops
lbValue tuple = lb_addr_get_ptr(p, lb_add_local_generated(p, tv.type, false));
if (t->kind == Type_Struct) {
for_array(src_index, t->Struct.fields) {
Entity *field = t->Struct.fields[src_index];
i32 field_index = field->Variable.field_index;
lbValue f = lb_emit_struct_ev(p, val, field_index);
lbValue ep = lb_emit_struct_ep(p, tuple, cast(i32)src_index);
lb_emit_store(p, ep, f);
}
} else if (is_type_array_like(t)) {
// TODO(bill): Clean-up this code
lbValue ap = lb_address_from_load_or_generate_local(p, val);
i32 n = cast(i32)get_array_type_count(t);
for (i32 i = 0; i < n; i++) {
lbValue f = lb_emit_load(p, lb_emit_array_epi(p, ap, i));
lbValue ep = lb_emit_struct_ep(p, tuple, i);
lb_emit_store(p, ep, f);
}
} else {
GB_PANIC("Unknown type of expand_values");
}
return lb_emit_load(p, tuple);
return lb_expand_values(p, val, tv.type);
}
case BuiltinProc_compress_values: {

View File

@@ -3474,6 +3474,7 @@ gb_internal Ast *parse_unary_expr(AstFile *f, bool lhs) {
case Token_Xor:
case Token_And:
case Token_Not:
case Token_MulMul: // 'expand_values' operator
case Token_Mul: // Used for error handling when people do C-like things
{
Token token = advance_token(f);

View File

@@ -35,6 +35,7 @@ TOKEN_KIND(Token__OperatorBegin, ""), \
TOKEN_KIND(Token_Shr, ">>"), \
TOKEN_KIND(Token_CmpAnd, "&&"), \
TOKEN_KIND(Token_CmpOr, "||"), \
TOKEN_KIND(Token_MulMul, "**"), \
\
TOKEN_KIND(Token__AssignOpBegin, ""), \
TOKEN_KIND(Token_AddEq, "+="), \
@@ -879,6 +880,9 @@ gb_internal void tokenizer_get_token(Tokenizer *t, Token *token, int repeat=0) {
if (t->curr_rune == '=') {
advance_to_next_rune(t);
token->kind = Token_MulEq;
} else if (t->curr_rune == '*') {
advance_to_next_rune(t);
token->kind = Token_MulMul;
}
break;
case '=':