src/bytecode/procs.c
// Emit code for initializing an array with an initializer.
//    var a: [11] int = {0, 1, 2, 3};
Emit code for initializing an array with an initializer.
Emit code for initializing an array with an initializer .
static void IR_emit_array_init(IR_ProcBuilder* builder, IR_Operand* array_op, IR_Operand* init_op)
{
    assert(array_op->kind == IR_OPERAND_VAR || array_op->kind == IR_OPERAND_DEREF_ADDR);
    assert(init_op->kind == IR_OPERAND_ARRAY_INIT);
    assert(array_op->type->kind == TYPE_ARRAY);
    Type* arr_type = array_op->type;
    Type* ptr_type = try_array_decay(builder->arena, &builder->type_cache->ptrs, arr_type);
    Type* elem_type = ptr_type->as_ptr.base;
    IR_Operand base_ptr_op = {.kind = IR_OPERAND_MEM_ADDR, .type = ptr_type};
    IR_get_object_addr(builder, &base_ptr_op.addr, array_op);
    IR_ArrayMemberInitializer* initzers = init_op->array_initzer.initzers;
    u64 num_initzers = init_op->array_initzer.num_initzers;
    u64 num_elems = arr_type->as_array.len;
    const int num_bits = sizeof(size_t) * 8;
    size_t num_flags = (num_elems + num_bits - 1) / num_bits;
    size_t* init_flags = alloc_array(builder->tmp_arena, size_t, num_flags, true);
    for (size_t i = 0; i < num_initzers; i += 1) {
        IR_ArrayMemberInitializer* initzer = initzers + i;
        size_t elem_index = initzer->index;
        size_t flag_index = elem_index / num_bits;
        size_t bit_index = elem_index % num_bits;
        size_t* flag = init_flags + flag_index;
        *flag |= (1 << bit_index);
        IR_Operand elem_ptr_op = {.kind = IR_OPERAND_DEREF_ADDR, .type = elem_type, .addr = base_ptr_op.addr};
        elem_ptr_op.addr.disp += elem_type->size * elem_index;
        IR_emit_assign(builder, &elem_ptr_op, &initzer->op);
        IR_try_free_op_reg(builder, &initzer->op);
    }
    IR_Operand zero_op = {.kind = IR_OPERAND_IMM, .type = elem_type, .imm = ir_zero_imm};
    for (u64 elem_index = 0; elem_index < num_elems; elem_index += 1) {
        size_t flag_index = elem_index / num_bits;
        size_t bit_index = elem_index % num_bits;
        if (init_flags[flag_index] & (1 << bit_index)) {
            continue;
        }
        IR_Operand elem_ptr_op = {.kind = IR_OPERAND_DEREF_ADDR, .type = elem_type, .addr = base_ptr_op.addr};
        elem_ptr_op.addr.disp += elem_type->size * elem_index;
        IR_emit_assign(builder, &elem_ptr_op, &zero_op);
    }
    IR_try_free_op_reg(builder, &base_ptr_op);
}
static void IR_emit_array_init ( IR_ProcBuilder * builder , IR_Operand * array_op , IR_Operand * init_op ) { assert ( array_op -> kind == IR_OPERAND_VAR || array_op -> kind == IR_OPERAND_DEREF_ADDR ) ; assert ( init_op -> kind == IR_OPERAND_ARRAY_INIT ) ; assert ( array_op -> type -> kind == TYPE_ARRAY ) ; Type * arr_type = array_op -> type ; Type * ptr_type = try_array_decay ( builder -> arena , & builder -> type_cache -> ptrs , arr_type ) ; Type * elem_type = ptr_type -> as_ptr . base ; IR_Operand base_ptr_op = { . kind = IR_OPERAND_MEM_ADDR , . type = ptr_type } ; IR_get_object_addr ( builder , & base_ptr_op . addr , array_op ) ; IR_ArrayMemberInitializer * initzers = init_op -> array_initzer . initzers ; u64 num_initzers = init_op -> array_initzer . num_initzers ; u64 num_elems = arr_type -> as_array . len ; const int num_bits = sizeof ( size_t ) * 8 ; size_t num_flags = ( num_elems + num_bits - 1 ) / num_bits ; size_t * init_flags = alloc_array ( builder -> tmp_arena , size_t , num_flags , true ) ; for ( size_t i = 0 ; i < num_initzers ; i += 1 ) { IR_ArrayMemberInitializer * initzer = initzers + i ; size_t elem_index = initzer -> index ; size_t flag_index = elem_index / num_bits ; size_t bit_index = elem_index % num_bits ; size_t * flag = init_flags + flag_index ; * flag |= ( 1 << bit_index ) ; IR_Operand elem_ptr_op = { . kind = IR_OPERAND_DEREF_ADDR , . type = elem_type , . addr = base_ptr_op . addr } ; elem_ptr_op . addr . disp += elem_type -> size * elem_index ; IR_emit_assign ( builder , & elem_ptr_op , & initzer -> op ) ; IR_try_free_op_reg ( builder , & initzer -> op ) ; } IR_Operand zero_op = { . kind = IR_OPERAND_IMM , . type = elem_type , . imm = ir_zero_imm } ; for ( u64 elem_index = 0 ; elem_index < num_elems ; elem_index += 1 ) { size_t flag_index = elem_index / num_bits ; size_t bit_index = elem_index % num_bits ; if ( init_flags [ flag_index ] & ( 1 << bit_index ) ) { continue ; } IR_Operand elem_ptr_op = { . kind = IR_OPERAND_DEREF_ADDR , . type = elem_type , . addr = base_ptr_op . addr } ; elem_ptr_op . addr . disp += elem_type -> size * elem_index ; IR_emit_assign ( builder , & elem_ptr_op , & zero_op ) ; } IR_try_free_op_reg ( builder , & base_ptr_op ) ; }
Emit code for initializing an array with an initializer.
Emit code for initializing an array with an initializer .
// Decay array into pointer to the first elem. // Create array of bit flags: 1 bit per element in array. // Bit will be set to 1 if the array element has an initializer. // Iterate through initializers and: 1. mark element as having an initializer, 2. initialize element. // Mark array element as having an initializer. // Initialize array element with value of the initializer. // For each array element, compute the pointer to the corresponding element and assign it // an default value if not yet initialized. // Skip array elements that have been initialized. // TODO: Reduce the number of assignment (mov) instructions by initializing // multiple elements at a time (one machine word's worth).