functions.c
// Move struct/union data from registers or memory to the destination of a function call
Move struct/union data from registers or memory to the destination of a function call
Move struct / union data from registers or memory to the destination of a function call
static void add_function_call_result_moves_for_struct_or_union(Function *function, Tac *ir) {
    if (ir->dst->stack_index == 0) panic("Expected a stack index for a function call returning a struct/union");
    int stack_index = ir->dst->stack_index;
    Type *type = ir->dst->type;
    Type *function_type = ir->src1->type;
    FunctionParamAllocation *fpa = function_type->function->return_value_fpa;
    FunctionParamLocations *fpl = &(fpa->params[0]);
    Value *function_value = ir->src1;
    if (fpl->locations[0].stack_offset == -1) {
        ir->dst = 0;
        ir = ir->next;
        int *live_range_pregs = malloc(sizeof(int) * 8);
        for (int loc = 0; loc < fpl->count; loc++) {
            FunctionParamLocation *location = &(fpl->locations[loc]);
            live_range_pregs[loc] = ++function->vreg_count;
            Value *dst = new_value();
            dst->vreg = live_range_pregs[loc];
            dst->type = location->int_register != -1 ? new_type(TYPE_LONG) : new_type(TYPE_DOUBLE);
            insert_instruction_from_operation(ir, IR_CALL_ARG_REG, dst, 0, 0, 1);
        }
        for (int loc = 0; loc < fpl->count; loc++) {
            FunctionParamLocation *location = &(fpl->locations[loc]);
            int live_range_preg;
            int param_register_vreg = live_range_pregs[loc];
            if (location->int_register != -1)
                live_range_preg = make_int_struct_or_union_move_from_register_to_stack_instructions(
                    function, ir, type, location, location->int_register, stack_index,
                    &function_return_value_register_set, param_register_vreg);
            else if (location->sse_register != -1)
                live_range_preg = make_sse_struct_or_union_move_from_register_to_stack_instructions(
                    function, ir, type, location, location->sse_register, stack_index,
                    &function_return_value_register_set, param_register_vreg);
            else
                panic("Got unexpected stack offset in add_struct_or_union_param_move");
            add_to_set(function_value->return_value_live_ranges, live_range_preg);
        }
    }
    else {
        add_to_set(function_value->return_value_live_ranges, LIVE_RANGE_PREG_RAX_INDEX);
        Value *address_value = new_value();
        address_value->vreg = ++function->vreg_count;
        address_value->type = make_pointer_to_void();
        insert_instruction_from_operation(ir, IR_ADDRESS_OF, address_value, ir->dst, 0, 1);
        Value *rdi_value = new_value();
        rdi_value->vreg = ++function->vreg_count;
        rdi_value->type = make_pointer_to_void();
        rdi_value->live_range_preg = LIVE_RANGE_PREG_RDI_INDEX;
        insert_instruction_from_operation(ir, IR_MOVE, rdi_value, address_value, 0, 1);
        Value *struct_dst = ir->dst;
        ir->dst = new_value();
        ir->dst->vreg = ++function->vreg_count;
        ir->dst->type = make_pointer_to_void();
        ir->dst->live_range_preg = LIVE_RANGE_PREG_RAX_INDEX;
        Value *src1 = dup_value(ir->dst);
        src1->is_lvalue = 1;
        int size = get_type_size(type);
        ir = add_memory_copy(function, ir, struct_dst, src1, size);
    }
}
static void add_function_call_result_moves_for_struct_or_union ( Function * function , Tac * ir ) { if ( ir -> dst -> stack_index == 0 ) panic ( " " ) ; int stack_index = ir -> dst -> stack_index ; Type * type = ir -> dst -> type ; Type * function_type = ir -> src1 -> type ; FunctionParamAllocation * fpa = function_type -> function -> return_value_fpa ; FunctionParamLocations * fpl = & ( fpa -> params [ 0 ] ) ; Value * function_value = ir -> src1 ; if ( fpl -> locations [ 0 ] . stack_offset == -1 ) { ir -> dst = 0 ; ir = ir -> next ; int * live_range_pregs = malloc ( sizeof ( int ) * 8 ) ; for ( int loc = 0 ; loc < fpl -> count ; loc ++ ) { FunctionParamLocation * location = & ( fpl -> locations [ loc ] ) ; live_range_pregs [ loc ] = ++ function -> vreg_count ; Value * dst = new_value ( ) ; dst -> vreg = live_range_pregs [ loc ] ; dst -> type = location -> int_register != -1 ? new_type ( TYPE_LONG ) : new_type ( TYPE_DOUBLE ) ; insert_instruction_from_operation ( ir , IR_CALL_ARG_REG , dst , 0 , 0 , 1 ) ; } for ( int loc = 0 ; loc < fpl -> count ; loc ++ ) { FunctionParamLocation * location = & ( fpl -> locations [ loc ] ) ; int live_range_preg ; int param_register_vreg = live_range_pregs [ loc ] ; if ( location -> int_register != -1 ) live_range_preg = make_int_struct_or_union_move_from_register_to_stack_instructions ( function , ir , type , location , location -> int_register , stack_index , & function_return_value_register_set , param_register_vreg ) ; else if ( location -> sse_register != -1 ) live_range_preg = make_sse_struct_or_union_move_from_register_to_stack_instructions ( function , ir , type , location , location -> sse_register , stack_index , & function_return_value_register_set , param_register_vreg ) ; else panic ( " " ) ; add_to_set ( function_value -> return_value_live_ranges , live_range_preg ) ; } } else { add_to_set ( function_value -> return_value_live_ranges , LIVE_RANGE_PREG_RAX_INDEX ) ; Value * address_value = new_value ( ) ; address_value -> vreg = ++ function -> vreg_count ; address_value -> type = make_pointer_to_void ( ) ; insert_instruction_from_operation ( ir , IR_ADDRESS_OF , address_value , ir -> dst , 0 , 1 ) ; Value * rdi_value = new_value ( ) ; rdi_value -> vreg = ++ function -> vreg_count ; rdi_value -> type = make_pointer_to_void ( ) ; rdi_value -> live_range_preg = LIVE_RANGE_PREG_RDI_INDEX ; insert_instruction_from_operation ( ir , IR_MOVE , rdi_value , address_value , 0 , 1 ) ; Value * struct_dst = ir -> dst ; ir -> dst = new_value ( ) ; ir -> dst -> vreg = ++ function -> vreg_count ; ir -> dst -> type = make_pointer_to_void ( ) ; ir -> dst -> live_range_preg = LIVE_RANGE_PREG_RAX_INDEX ; Value * src1 = dup_value ( ir -> dst ) ; src1 -> is_lvalue = 1 ; int size = get_type_size ( type ) ; ir = add_memory_copy ( function , ir , struct_dst , src1 , size ) ; } }
Move struct/union data from registers or memory to the destination of a function call
Move struct / union data from registers or memory to the destination of a function call
// Move registers to a struct/union on the stack // Allocate result vregs and create a live range or them // Move registers to a struct/union in memory. rax contains the address // Ensure RAX doesn't get clobbered by the function call // Take address of dst struct/union on the stack // Move struct/union target address into rdi // Setup dst for rax // Prepare src1 to also be rax, but as an lvalue // Add the memory copy