summaryrefslogblamecommitdiffstats
path: root/src/register.c
blob: 6e575432fb60629f039b70c44540973b68a785a7 (plain) (tree)
1
2
3
4
5
6
7
8
9


                     
                     
                    
                  
                   
                   
 


                      
                      
                  
                    

                                        
                                       
 
                                                   






                                                       
                                    

                                          

                                                        

                                  
                                  


                
                                                                    


                                             
              
                      


                                         
                            
                               

               


                    
                                               



                                                 



                            
                        





                                                 








                                                                  
                                  
                      
                                      

                       



                                 


                                  
                                                                   


                                                                                



                                                                                  







                                                                                
                                     
 

                                                                                 
 



                                                

                                                 

                  


                                     

                                
                                  

                   
                             
 







                                                             
                                             
              
                               

               



                         
                                                                             
 

                                                     
                                                                 







                                           
                                           

                                                  
         
     





























                                                                             
          

                                                                             
 

                    
 







                                                                     

                                                           



                                                           

                                                         
                                     
                          



                                



                                                                            

              









                                                    
         


     
                                                                 



                                            
     
                               

 

                                                   
                                     
                                                            


                                                                         



                                                   

                                                                         
                                                            

                                
 
 























                                                                     



                                            

                               
#include "register.h"

#include <assert.h>
#include <inttypes.h>
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#define REG_NUM 5
#define REG_ADDR "x9"
#define REG_SWAP "w10"
#define REG_LOCK_MAX 3
#define REG_SIZE 4
#define SPILL_MAX 64

static const char *reg_name[REG_NUM] = {
    "w11", "w12", "w13", "w14", "w15"};

CcmmcRegPool *ccmmc_register_init(FILE *asm_output)
{
    CcmmcRegPool *pool = malloc(sizeof(CcmmcRegPool));
    pool->num = REG_NUM;
    pool->list = malloc(sizeof(CcmmcReg*) * pool->num);
    for (int i = 0; i < pool->num; i++) {
        pool->list[i] = malloc(sizeof(CcmmcReg));
        pool->list[i]->tmp = NULL;
        pool->list[i]->lock = false;
        pool->list[i]->name = reg_name[i];
    }
    pool->spill = malloc(sizeof(CcmmcTmp*) * SPILL_MAX);
    pool->top = 0;
    pool->lock_max = REG_LOCK_MAX;
    pool->lock_cnt = 0;
    pool->asm_output = asm_output;
    return pool;
}

CcmmcTmp *ccmmc_register_alloc(CcmmcRegPool *pool, uint64_t *offset)
{
    CcmmcTmp *tmp = malloc(sizeof(CcmmcTmp));
    if (pool->top < pool->num) {
        // tmp
        tmp->addr = 0;
        tmp->reg = pool->list[pool->top];

        // reg
        tmp->reg->tmp = tmp;
        tmp->reg->lock = false;

        // pool
        pool->top++;
    }
    else {
        // gen code to alloc space on the stack
        fprintf(pool->asm_output,
            "\t\t/* ccmmc_register_alloc(): */\n"
            "\t\tsub\tsp, sp, #%d\n",
            REG_SIZE);

        // tmp and offset
        *offset += REG_SIZE;
        tmp->addr = *offset;
        tmp->reg = NULL;

        // spill
        pool->spill[pool->top - pool->num] = tmp;

        // pool
        pool->top++;
    }
    return tmp;
}

const char *ccmmc_register_lock(CcmmcRegPool *pool, CcmmcTmp *tmp)
{
    const char *reg = NULL;
    if (pool->lock_cnt < pool->lock_max) {
        if (tmp->reg !=NULL) {
            if (!tmp->reg->lock) {
                // reg
                tmp->reg->lock = true;

                // pool
                pool->lock_cnt++;
            }
            reg = tmp->reg->name;
        }
        else {
            // find a unlocked reg
            int i, j;
            for (i = 0; i < pool->num && pool->list[i]->lock; i++);
            assert(i < pool->num); //must found

            // gen code to swap the tmp in the register and the tmp on the stack
            fprintf(pool->asm_output,
                "\t\t/* ccmmc_register_lock(): swap %s, [fp, #-%" PRIu64 "] */\n",
                pool->list[i]->name,
                tmp->addr);
            fprintf(pool->asm_output, // REG_ADDR holds the address on the stack
                "\t\tldr\t" REG_ADDR ", =%" PRIu64 "\n"
                "\t\tsub\t" REG_ADDR ", fp, " REG_ADDR "\n"
                "\t\tmov\t" REG_SWAP ", %s\n"
                "\t\tldr\t%s, [" REG_ADDR "]\n"
                "\t\tstr\t" REG_SWAP ", [" REG_ADDR "]\n",
                tmp->addr,
                pool->list[i]->name,
                pool->list[i]->name);

            // find the index of tmp in pool->spill
            for (j = 0; j < pool->top - pool->num && pool->spill[j] != tmp; j++);

            // spill
            pool->spill[j] = pool->list[i]->tmp;

            // old tmp of the reg
            pool->list[i]->tmp->reg = NULL;
            pool->list[i]->tmp->addr = tmp->addr;

            // tmp
            tmp->reg = pool->list[i];
            tmp->addr = 0;

            // register
            tmp->reg->tmp = tmp;
            tmp->reg->lock = true;

            // pool
            pool->lock_cnt++;

            reg = tmp->reg->name;
        }
    }
    return reg;
}

void ccmmc_register_unlock(CcmmcRegPool *pool, CcmmcTmp *tmp)
{
    if (tmp->reg != NULL && tmp->reg->lock) {
        // reg
        tmp->reg->lock = false;

        // pool
        pool->lock_cnt--;
    }
}

void ccmmc_register_free(CcmmcRegPool *pool, CcmmcTmp *tmp, uint64_t *offset)
{
    // find the index of register associated with tmp
    int i;
    for (i = 0; i < pool->num && pool->list[i]->tmp != tmp; i++);
    if (pool->top <= pool->num) {
        // tmp
        free(tmp);

        // pool
        pool->top--;
        assert(i < pool->num); //must found
        if (i < pool->top) {
            CcmmcReg *swap = pool->list[i];
            pool->list[i] = pool->list[pool->top];
            pool->list[pool->top] = swap;
        }
    }
    else if (i < pool->num) {
        // pool
        pool->top--;

        // gen code to move the last tmp to this register
        fprintf(pool->asm_output,
            "\t\t/* ccmmc_register_free(): mov %s, [fp, #-%" PRIu64 "] */\n",
            tmp->reg->name, pool->spill[pool->top - pool->num]->addr);
        fprintf(pool->asm_output, // REG_ADDR holds the address on the stack
            "\t\tldr\t" REG_ADDR ", =%" PRIu64 "\n"
            "\t\tsub\t" REG_ADDR ", fp, " REG_ADDR "\n"
            "\t\tldr\t%s, [" REG_ADDR "]\n"
            "\t\tadd\tsp, sp, #%d\n",
            pool->spill[pool->top - pool->num]->addr,
            tmp->reg->name,
            REG_SIZE);

        // offset
        *offset -= REG_SIZE;

        // reg
        tmp->reg->tmp = pool->spill[pool->top - pool->num];

        // the last tmp
        tmp->reg->tmp->reg = tmp->reg;
        tmp->reg->tmp->addr = 0;

        // tmp
        free(tmp);
    }
    else {
        for (i = 0; i < pool->top - pool->num && pool->spill[i] != tmp; i++);
        assert(i < pool->top - pool->num); //must found

        // pool
        pool->top--;

        if (i < pool->top - pool->num) {
            // gen code to move the last tmp to the hole
            fprintf(pool->asm_output,
                "\t\t/* ccmmc_register_free(): "
                "mov [fp, #-%" PRIu64 "] , [fp, #-%" PRIu64 "] */\n",
                pool->spill[i]->addr,
                pool->spill[pool->top - pool->num]->addr);
            fprintf(pool->asm_output,
                "\t\tldr\t" REG_ADDR ", =%" PRIu64 "\n"
                "\t\tsub\t" REG_ADDR ", fp, " REG_ADDR "\n"
                "\t\tldr\t" REG_SWAP ", [" REG_ADDR "]\n"
                "\t\tldr\t" REG_ADDR ", =%" PRIu64 "\n"
                "\t\tsub\t" REG_ADDR ", fp, " REG_ADDR "\n"
                "\t\tstr\t" REG_SWAP ", [" REG_ADDR "]\n"
                "\t\tadd\tsp, sp, #%d\n",
                pool->spill[pool->top - pool->num]->addr,
                pool->spill[i]->addr,
                REG_SIZE);

            // offset
            *offset -= REG_SIZE;

            // spill
            pool->spill[pool->top - pool->num]->addr = pool->spill[i]->addr;
            free(pool->spill[i]);
            pool->spill[i] = pool->spill[pool->top - pool->num];
        }
        else {
            // gen code to remove the last tmp
            fprintf(pool->asm_output,
                "\t\t/* ccmmc_register_free(): */\n"
                "\t\tadd\tsp, sp, #%d\n", REG_SIZE);

            // offset
            *offset -= REG_SIZE;

            // spill
            free(pool->spill[i]);
        }
    }
}

void ccmmc_register_extend_name(CcmmcTmp *tmp, char *extend_name)
{
    if (tmp->reg != NULL) {
        strcpy(extend_name, tmp->reg->name);
        extend_name[0] = 'x';
    }
    else extend_name[0] = '\0';
}

void ccmmc_register_caller_save(CcmmcRegPool *pool)
{
    for (int i = 0; i < REG_NUM; i++)
        fprintf(pool->asm_output, "\tstr\t%s, [sp, #-%d]\n",
            reg_name[i],
            (i + 1) * REG_SIZE);
    fprintf(pool->asm_output, "\tsub\tsp, sp, %d\n", REG_NUM * REG_SIZE);
}

void ccmmc_register_caller_load(CcmmcRegPool *pool)
{
    fprintf(pool->asm_output, "\tadd\tsp, sp, %d\n", REG_NUM * REG_SIZE);
    for (int i = 0; i < REG_NUM; i++)
        fprintf(pool->asm_output, "\tldr\t%s, [sp, #-%d]\n",
            reg_name[i],
            (i + 1) * REG_SIZE);
}

void ccmmc_register_save_arguments(CcmmcRegPool *pool, int arg_count)
{
    if (arg_count <= 0)
        return;
    if (arg_count >= 8)
        arg_count = 8;
    for (int i = 0; i < arg_count; i++)
        fprintf(pool->asm_output, "\tstr\tx%d, [sp, #-%d]\n",
            i, (i + 1) * 8);
    fprintf(pool->asm_output, "\tsub\tsp, sp, %d\n", arg_count * 8);
}

void ccmmc_register_load_arguments(CcmmcRegPool *pool, int arg_count)
{
    if (arg_count <= 0)
        return;
    if (arg_count >= 8)
        arg_count = 8;
    fprintf(pool->asm_output, "\tadd\tsp, sp, %d\n", arg_count * 8);
    for (int i = 0; i < arg_count; i++)
        fprintf(pool->asm_output, "\tldr\tx%d, [sp, #-%d]\n",
            i, (i + 1) * 8);
}

void ccmmc_register_fini(CcmmcRegPool *pool)
{
    // TODO: free register pool
}

// vim: set sw=4 ts=4 sts=4 et: