target/whirl.c
static WhirlCodeSegment *generate_jump_table(WhirlCodeSegment *first_segment) {
    WhirlCodeSegment *table_start = new_segment(NULL, NULL);
    int table_segment_size = 300;
    bool made_table = false;

    while (!made_table) {
        RingState *state = &(RingState) {
            .active_ring  = MATH_RING,
            .cur_op_pos   = OP_IF,
            .cur_math_pos = MATH_NOOP,
            .op_dir       = CLOCKWISE,
            .math_dir     = CLOCKWISE,
            .last_is_zero = false,
        };

        // The jump table consists of a list of code segments which jump to the
        // appropriate piece of code for each PC value. Each code segment is a
        // fixed size, so to jump to the correct segment we multiply the PC value
        // by that fixed size to get the correct jump amount.
        set_mem(table_start, state, table_segment_size);
        move_to_reg(table_start, state, PC_REG_NUM);
        generate_math_command(table_start, state, MATH_LOAD);
        move_back_from_reg(table_start, state, PC_REG_NUM);
        generate_math_command(table_start, state, MATH_MULT);

        // We need to add 1 to the jump amount to the get the correct jump amount
        generate_math_command(table_start, state, MATH_STORE);
        generate_math_command(table_start, state, MATH_EQUAL);
        generate_math_command(table_start, state, MATH_ADD);
        generate_math_command(table_start, state, MATH_STORE);
        generate_op_command(table_start, state, OP_LOAD);

        // Jump to the correct segment implementing the jump we want
        generate_op_command(table_start, state, OP_PADD);

        RingState saved_jump_state = *state;
        int last_pc = -1;
        int num_jumps = 0;

        WhirlCodeSegment *last_table_segment = table_start;

        bool table_failed = false;

        for (WhirlCodeSegment *segment = first_segment; segment != NULL; segment = segment->next) {
            if (segment->inst->pc != last_pc) {
                // If we encounter a new PC value, we create a new segment
                // implementing the jump
                num_jumps++;

                int jump_amount = table_start->len + segment->total_code_len + table_segment_size * num_jumps - 1;
                WhirlCodeSegment *new_segment = generate_jump_for_table(last_table_segment, saved_jump_state, jump_amount, table_segment_size);

                if (new_segment == NULL) {
                    table_failed = true;
                    break;
                }

                last_table_segment = new_segment;
                last_pc = segment->inst->pc;
            }
        }

        // If we were unable to create the table, we increase the segment size
        // and try again.
        if (table_failed) {
            table_segment_size += 100;
            table_start = new_segment(NULL, NULL);
        }
        else {
            made_table = true;
        }
    }

    return table_start;
}
// Generates the jump table at the end of the program. Since the program will be
// completely generated by this point, we will know how far to jump backwards in
// the code for each PC value. 
Generates the jump table at the end of the program. Since the program will be
completely generated by this point, we will know how far to jump backwards in
the code for each PC value.
Generates the jump table at the end of the program . Since the program will be completely generated by this point we will know how far to jump backwards in the code for each PC value .
static WhirlCodeSegment *generate_jump_table(WhirlCodeSegment *first_segment) {
    WhirlCodeSegment *table_start = new_segment(NULL, NULL);
    int table_segment_size = 300;
    bool made_table = false;
    while (!made_table) {
        RingState *state = &(RingState) {
            .active_ring  = MATH_RING,
            .cur_op_pos   = OP_IF,
            .cur_math_pos = MATH_NOOP,
            .op_dir       = CLOCKWISE,
            .math_dir     = CLOCKWISE,
            .last_is_zero = false,
        };
        set_mem(table_start, state, table_segment_size);
        move_to_reg(table_start, state, PC_REG_NUM);
        generate_math_command(table_start, state, MATH_LOAD);
        move_back_from_reg(table_start, state, PC_REG_NUM);
        generate_math_command(table_start, state, MATH_MULT);
        generate_math_command(table_start, state, MATH_STORE);
        generate_math_command(table_start, state, MATH_EQUAL);
        generate_math_command(table_start, state, MATH_ADD);
        generate_math_command(table_start, state, MATH_STORE);
        generate_op_command(table_start, state, OP_LOAD);
        generate_op_command(table_start, state, OP_PADD);
        RingState saved_jump_state = *state;
        int last_pc = -1;
        int num_jumps = 0;
        WhirlCodeSegment *last_table_segment = table_start;
        bool table_failed = false;
        for (WhirlCodeSegment *segment = first_segment; segment != NULL; segment = segment->next) {
            if (segment->inst->pc != last_pc) {
                num_jumps++;
                int jump_amount = table_start->len + segment->total_code_len + table_segment_size * num_jumps - 1;
                WhirlCodeSegment *new_segment = generate_jump_for_table(last_table_segment, saved_jump_state, jump_amount, table_segment_size);
                if (new_segment == NULL) {
                    table_failed = true;
                    break;
                }
                last_table_segment = new_segment;
                last_pc = segment->inst->pc;
            }
        }
        if (table_failed) {
            table_segment_size += 100;
            table_start = new_segment(NULL, NULL);
        }
        else {
            made_table = true;
        }
    }
    return table_start;
}
static WhirlCodeSegment * generate_jump_table ( WhirlCodeSegment * first_segment ) { WhirlCodeSegment * table_start = new_segment ( NULL , NULL ) ; int table_segment_size = 300 ; bool made_table = false ; while ( ! made_table ) { RingState * state = & ( RingState ) { . active_ring = MATH_RING , . cur_op_pos = OP_IF , . cur_math_pos = MATH_NOOP , . op_dir = CLOCKWISE , . math_dir = CLOCKWISE , . last_is_zero = false , } ; set_mem ( table_start , state , table_segment_size ) ; move_to_reg ( table_start , state , PC_REG_NUM ) ; generate_math_command ( table_start , state , MATH_LOAD ) ; move_back_from_reg ( table_start , state , PC_REG_NUM ) ; generate_math_command ( table_start , state , MATH_MULT ) ; generate_math_command ( table_start , state , MATH_STORE ) ; generate_math_command ( table_start , state , MATH_EQUAL ) ; generate_math_command ( table_start , state , MATH_ADD ) ; generate_math_command ( table_start , state , MATH_STORE ) ; generate_op_command ( table_start , state , OP_LOAD ) ; generate_op_command ( table_start , state , OP_PADD ) ; RingState saved_jump_state = * state ; int last_pc = -1 ; int num_jumps = 0 ; WhirlCodeSegment * last_table_segment = table_start ; bool table_failed = false ; for ( WhirlCodeSegment * segment = first_segment ; segment != NULL ; segment = segment -> next ) { if ( segment -> inst -> pc != last_pc ) { num_jumps ++ ; int jump_amount = table_start -> len + segment -> total_code_len + table_segment_size * num_jumps - 1 ; WhirlCodeSegment * new_segment = generate_jump_for_table ( last_table_segment , saved_jump_state , jump_amount , table_segment_size ) ; if ( new_segment == NULL ) { table_failed = true ; break ; } last_table_segment = new_segment ; last_pc = segment -> inst -> pc ; } } if ( table_failed ) { table_segment_size += 100 ; table_start = new_segment ( NULL , NULL ) ; } else { made_table = true ; } } return table_start ; }
Generates the jump table at the end of the program.
Generates the jump table at the end of the program .
// The jump table consists of a list of code segments which jump to the // appropriate piece of code for each PC value. Each code segment is a // fixed size, so to jump to the correct segment we multiply the PC value // by that fixed size to get the correct jump amount. // We need to add 1 to the jump amount to the get the correct jump amount // Jump to the correct segment implementing the jump we want // If we encounter a new PC value, we create a new segment // implementing the jump // If we were unable to create the table, we increase the segment size // and try again.