functions.c
// Add a param/arg to a function and allocate registers & stack entries
// Structs are decomposed.
Add a param/arg to a function and allocate registers & stack entries
Structs are decomposed.
Add a param / arg to a function and allocate registers & stack entries Structs are decomposed .
void add_function_param_to_allocation(FunctionParamAllocation *fpa, Type *type) {
    if (fpa->arg_count > MAX_FUNCTION_CALL_ARGS) panic("Maximum function call arg count of %d exceeded", MAX_FUNCTION_CALL_ARGS);
    if (type->type != TYPE_STRUCT_OR_UNION) {
        add_single_stack_function_param_location(fpa, type);
    }
    else {
        if (type->type == TYPE_ARRAY) type = decay_array_to_pointer(type);
        if (type->type == TYPE_ENUM) type = new_type(TYPE_INT);
        int size = get_type_size(type);
        if (size > 16) {
            add_single_stack_function_param_location(fpa, type);
        }
        else {
            StructOrUnionScalars *scalars = malloc(sizeof(StructOrUnionScalars));
            scalars->scalars = malloc(sizeof(StructOrUnionScalar) * MAX_STRUCT_OR_UNION_SCALARS);
            scalars->count = 0;
            flatten_type(type, scalars, 0);
            char *seen_integer = malloc(sizeof(char) * 8);
            memset(seen_integer, 0, sizeof(char) * 8);
            char *seen_sse = malloc(sizeof(char) * 8);
            memset(seen_sse, 0, sizeof(char) * 8);
            char *seen_memory = malloc(sizeof(char) * 8);
            memset(seen_memory, 0, sizeof(char) * 8);
            char *member_counts = malloc(sizeof(char) * 8);
            memset(member_counts, 0, sizeof(char) * 8);
            int unaligned = 0;
            size = 0; 
            for (int i = 0; i < scalars->count; i++) {
                StructOrUnionScalar *scalar = scalars->scalars[i];
                size +=  get_type_size(scalar->type);
                int eight_byte = scalar->offset >> 3;
                member_counts[eight_byte]++;
                if (type_fits_in_single_int_register(scalar->type))
                    seen_integer[eight_byte] = 1;
                else if (is_sse_floating_point_type(scalar->type))
                    seen_sse[eight_byte] = 1;
                else {
                    seen_memory[eight_byte] = 1;
                    seen_memory[eight_byte + 1] = 1;
                }
                if (scalar->offset & (get_type_alignment(scalar->type) - 1))
                    unaligned = 1;
            }
            int eight_bytes_count = (size + 7) / 8;
            FunctionParamLocations *fpl = &(fpa->params[fpa->arg_count]);
            fpl->locations = malloc(sizeof(FunctionParamLocation) * eight_bytes_count);
            fpl->count = eight_bytes_count;
            int in_memory = 0;
            for (int i = 0; i < eight_bytes_count; i++) in_memory |= seen_memory[i];
            if  (in_memory || unaligned) {
                add_single_stack_function_param_location(fpa, type);
            }
            else {
                FunctionParamAllocation *backup_fpa = malloc(sizeof(FunctionParamAllocation));
                *backup_fpa = *fpa;
                int on_stack = 0;
                for (int i = 0; i < eight_bytes_count; i++) {
                    fpl->locations[i].stru_size = size > 8 ? 8 : size;
                    size -= 8;
                    fpl->locations[i].stru_member_count = member_counts[i];
                    fpl->locations[i].stru_offset = i * 8;
                    if (seen_integer[i])
                        add_type_to_allocation(fpa, &(fpl->locations[i]), new_type(TYPE_INT), 0);
                    else
                        add_type_to_allocation(fpa, &(fpl->locations[i]), new_type(TYPE_FLOAT), 0);
                    if (fpl->locations[i].stack_offset != -1) on_stack = 1;
                }
                if (on_stack && eight_bytes_count > 1) {
                    if (debug_function_param_allocation) printf("         ran out of registers, rewinding ... \n");
                    *fpa = *backup_fpa;
                    add_single_stack_function_param_location(fpa, type);
                }
            }
        }
    }
    fpa->arg_count++;
}
void add_function_param_to_allocation ( FunctionParamAllocation * fpa , Type * type ) { if ( fpa -> arg_count > MAX_FUNCTION_CALL_ARGS ) panic ( " " , MAX_FUNCTION_CALL_ARGS ) ; if ( type -> type != TYPE_STRUCT_OR_UNION ) { add_single_stack_function_param_location ( fpa , type ) ; } else { if ( type -> type == TYPE_ARRAY ) type = decay_array_to_pointer ( type ) ; if ( type -> type == TYPE_ENUM ) type = new_type ( TYPE_INT ) ; int size = get_type_size ( type ) ; if ( size > 16 ) { add_single_stack_function_param_location ( fpa , type ) ; } else { StructOrUnionScalars * scalars = malloc ( sizeof ( StructOrUnionScalars ) ) ; scalars -> scalars = malloc ( sizeof ( StructOrUnionScalar ) * MAX_STRUCT_OR_UNION_SCALARS ) ; scalars -> count = 0 ; flatten_type ( type , scalars , 0 ) ; char * seen_integer = malloc ( sizeof ( char ) * 8 ) ; memset ( seen_integer , 0 , sizeof ( char ) * 8 ) ; char * seen_sse = malloc ( sizeof ( char ) * 8 ) ; memset ( seen_sse , 0 , sizeof ( char ) * 8 ) ; char * seen_memory = malloc ( sizeof ( char ) * 8 ) ; memset ( seen_memory , 0 , sizeof ( char ) * 8 ) ; char * member_counts = malloc ( sizeof ( char ) * 8 ) ; memset ( member_counts , 0 , sizeof ( char ) * 8 ) ; int unaligned = 0 ; size = 0 ; for ( int i = 0 ; i < scalars -> count ; i ++ ) { StructOrUnionScalar * scalar = scalars -> scalars [ i ] ; size += get_type_size ( scalar -> type ) ; int eight_byte = scalar -> offset >> 3 ; member_counts [ eight_byte ] ++ ; if ( type_fits_in_single_int_register ( scalar -> type ) ) seen_integer [ eight_byte ] = 1 ; else if ( is_sse_floating_point_type ( scalar -> type ) ) seen_sse [ eight_byte ] = 1 ; else { seen_memory [ eight_byte ] = 1 ; seen_memory [ eight_byte + 1 ] = 1 ; } if ( scalar -> offset & ( get_type_alignment ( scalar -> type ) - 1 ) ) unaligned = 1 ; } int eight_bytes_count = ( size + 7 ) / 8 ; FunctionParamLocations * fpl = & ( fpa -> params [ fpa -> arg_count ] ) ; fpl -> locations = malloc ( sizeof ( FunctionParamLocation ) * eight_bytes_count ) ; fpl -> count = eight_bytes_count ; int in_memory = 0 ; for ( int i = 0 ; i < eight_bytes_count ; i ++ ) in_memory |= seen_memory [ i ] ; if ( in_memory || unaligned ) { add_single_stack_function_param_location ( fpa , type ) ; } else { FunctionParamAllocation * backup_fpa = malloc ( sizeof ( FunctionParamAllocation ) ) ; * backup_fpa = * fpa ; int on_stack = 0 ; for ( int i = 0 ; i < eight_bytes_count ; i ++ ) { fpl -> locations [ i ] . stru_size = size > 8 ? 8 : size ; size -= 8 ; fpl -> locations [ i ] . stru_member_count = member_counts [ i ] ; fpl -> locations [ i ] . stru_offset = i * 8 ; if ( seen_integer [ i ] ) add_type_to_allocation ( fpa , & ( fpl -> locations [ i ] ) , new_type ( TYPE_INT ) , 0 ) ; else add_type_to_allocation ( fpa , & ( fpl -> locations [ i ] ) , new_type ( TYPE_FLOAT ) , 0 ) ; if ( fpl -> locations [ i ] . stack_offset != -1 ) on_stack = 1 ; } if ( on_stack && eight_bytes_count > 1 ) { if ( debug_function_param_allocation ) printf ( " \n " ) ; * fpa = * backup_fpa ; add_single_stack_function_param_location ( fpa , type ) ; } } } } fpa -> arg_count ++ ; }
Add a param/arg to a function and allocate registers & stack entries
Structs are decomposed.
Add a param / arg to a function and allocate registers & stack entries Structs are decomposed .
// Create a single location for the arg // The entire thing is on the stack // Decompose a struct or union into up to 8 8-bytes // Classify the eight bytes // Needs recalculating to remove any paddding at the end // Determine number of 8-bytes & allocate memory // If one of the classes is MEMORY, the whole argument is passed in memory. // The entire thing is on the stack // Create a location for each eight byte // Part of the struct/union overflowed into the stack due to a shortage // of registers. Roll back & put the whole thing in the stack.