328 lines
		
	
	
	
		
			7.5 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			328 lines
		
	
	
	
		
			7.5 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
| #include "mcg.h"
 | |
| 
 | |
| static int hop_count = 1;
 | |
| static struct hop* current_hop;
 | |
| static char* buffer = NULL;
 | |
| static int bufferlen = 0;
 | |
| static int buffersize = 0;
 | |
| 
 | |
| static const struct burm_emitter_data emitter_data;
 | |
| 
 | |
| struct hop* new_hop(struct basicblock* bb, struct ir* ir)
 | |
| {
 | |
| 	struct hop* hop = calloc(1, sizeof *hop);
 | |
| 	hop->id = hop_count++;
 | |
|     hop->bb = bb;
 | |
| 	hop->ir = ir;
 | |
| 	return hop;
 | |
| }
 | |
| 
 | |
| static struct insel* new_insel(enum insel_type type)
 | |
| {
 | |
| 	struct insel* insel = calloc(1, sizeof(*insel));
 | |
| 	insel->type = type;
 | |
| 	return insel;
 | |
| }
 | |
| 
 | |
| void hop_add_string_insel(struct hop* hop, const char* string)
 | |
| {
 | |
| 	struct insel* insel = new_insel(INSEL_STRING);
 | |
| 	insel->u.string = string;
 | |
| 	array_append(&hop->insels, insel);
 | |
| }
 | |
| 
 | |
| void hop_add_hreg_insel(struct hop* hop, struct hreg* hreg, int index)
 | |
| {
 | |
| 	struct insel* insel = new_insel(INSEL_HREG);
 | |
| 	insel->u.hreg = hreg;
 | |
|     insel->index = index;
 | |
| 	array_append(&hop->insels, insel);
 | |
| }
 | |
| 
 | |
| void hop_add_vreg_insel(struct hop* hop, struct vreg* vreg, int index)
 | |
| {
 | |
| 	struct insel* insel = new_insel(INSEL_VREG);
 | |
| 	insel->u.vreg = vreg;
 | |
|     insel->index = index;
 | |
| 	array_append(&hop->insels, insel);
 | |
| }
 | |
| 
 | |
| void hop_add_value_insel(struct hop* hop, struct ir* ir)
 | |
| {
 | |
| 	struct insel* insel = new_insel(INSEL_VALUE);
 | |
| 	insel->u.value = ir;
 | |
| 	array_append(&hop->insels, insel);
 | |
| }
 | |
| 
 | |
| void hop_add_st_offset_insel(struct hop* hop, struct hreg* hreg)
 | |
| {
 | |
| 	struct insel* insel = new_insel(INSEL_ST_OFFSET);
 | |
| 	insel->u.hreg = hreg;
 | |
| 	array_append(&hop->insels, insel);
 | |
| }
 | |
| 
 | |
| void hop_add_ab_offset_insel(struct hop* hop, int offset)
 | |
| {
 | |
| 	struct insel* insel = new_insel(INSEL_AB_OFFSET);
 | |
| 	insel->u.offset = offset;
 | |
| 	array_append(&hop->insels, insel);
 | |
| }
 | |
| 
 | |
| void hop_add_lb_offset_insel(struct hop* hop, int offset)
 | |
| {
 | |
| 	struct insel* insel = new_insel(INSEL_LB_OFFSET);
 | |
| 	insel->u.offset = offset;
 | |
| 	array_append(&hop->insels, insel);
 | |
| }
 | |
| 
 | |
| void hop_add_eoi_insel(struct hop* hop)
 | |
| {
 | |
| 	struct insel* insel = new_insel(INSEL_EOI);
 | |
| 	array_append(&hop->insels, insel);
 | |
| }
 | |
| 
 | |
| void hop_add_insel(struct hop* hop, const char* fmt, ...)
 | |
| {
 | |
|     va_list ap;
 | |
|     va_start(ap, fmt);
 | |
| 
 | |
|     while (*fmt)
 | |
|     {
 | |
|         if (*fmt == '%')
 | |
|         {
 | |
|             int index = 0;
 | |
|             fmt += 2;
 | |
|         again:
 | |
|             switch (fmt[-1])
 | |
|             {
 | |
|                 case '0':
 | |
|                 case '1':
 | |
|                 case '2':
 | |
|                 case '3':
 | |
|                 case '4':
 | |
|                 case '5':
 | |
|                 case '6':
 | |
|                 case '7':
 | |
|                 case '8':
 | |
|                 case '9':
 | |
|                     index = fmt[-1] - '0';
 | |
|                     fmt++;
 | |
|                     goto again;
 | |
| 
 | |
|                 case 'd':
 | |
|                     hop_add_string_insel(hop, aprintf("%d", va_arg(ap, int)));
 | |
|                     break;
 | |
| 
 | |
|                 case 's':
 | |
|                     hop_add_string_insel(hop, va_arg(ap, const char*));
 | |
|                     break;
 | |
| 
 | |
|                 case 'S':
 | |
|                     hop_add_st_offset_insel(hop, va_arg(ap, struct hreg*));
 | |
|                     break;
 | |
| 
 | |
|                 case 'A':
 | |
|                     hop_add_ab_offset_insel(hop, va_arg(ap, int));
 | |
|                     break;
 | |
| 
 | |
|                 case 'L':
 | |
|                     hop_add_lb_offset_insel(hop, va_arg(ap, int));
 | |
|                     break;
 | |
| 
 | |
|                 case 'H':
 | |
|                     hop_add_hreg_insel(hop, va_arg(ap, struct hreg*), index);
 | |
|                     break;
 | |
| 
 | |
|                 case 'V':
 | |
|                     hop_add_vreg_insel(hop, va_arg(ap, struct vreg*), index);
 | |
|                     break;
 | |
|             }
 | |
|         }
 | |
|         else
 | |
|         {
 | |
|             const char* end = strchr(fmt, '%');
 | |
|             const char* s;
 | |
|             if (end)
 | |
|             {
 | |
|                 int len = end - fmt;
 | |
|                 s = strndup(fmt, len);
 | |
|                 fmt = end;
 | |
|             }
 | |
|             else
 | |
|             {
 | |
|                 s = fmt;
 | |
|                 fmt += strlen(fmt);
 | |
|             }
 | |
| 
 | |
|             hop_add_string_insel(hop, s);
 | |
|         }
 | |
|     }
 | |
| 
 | |
|     hop_add_eoi_insel(hop);
 | |
|     va_end(ap);
 | |
| }
 | |
| 
 | |
| static void print_header(char k, struct hop* hop)
 | |
| {
 | |
|     int i;
 | |
| 
 | |
|     tracef(k, "%c: %d", k, hop->id);
 | |
|     if (hop->ir)
 | |
|         tracef(k, " from $%d", hop->ir->id);
 | |
|     tracef(k, ":");
 | |
| 
 | |
|     for (i=0; i<hop->ins.count; i++)
 | |
|         tracef(k, " r%%%d", hop->ins.item[i]->id);
 | |
|     for (i=0; i<hop->throughs.count; i++)
 | |
|         tracef(k, " =%%%d", hop->throughs.item[i]->id);
 | |
|     for (i=0; i<hop->outs.count; i++)
 | |
|         tracef(k, " w%%%d", hop->outs.item[i]->id);
 | |
|     tracef(k, " ");
 | |
| }
 | |
| 
 | |
| static char* appendf(const char* fmt, ...)
 | |
| {
 | |
|     int n;
 | |
|     char* p;
 | |
|     va_list ap;
 | |
| 
 | |
|     va_start(ap, fmt);
 | |
|     n = bufferlen + vsnprintf(NULL, 0, fmt, ap) + 1;
 | |
|     va_end(ap);
 | |
| 
 | |
|     if (n > buffersize)
 | |
|     {
 | |
|         buffersize *= 2;
 | |
| 		if (buffersize < n)
 | |
| 			buffersize = n*2;
 | |
|         buffer = realloc(buffer, buffersize);
 | |
|     }
 | |
| 
 | |
|     va_start(ap, fmt);
 | |
|     vsprintf(buffer+bufferlen, fmt, ap);
 | |
|     va_end(ap);
 | |
| 
 | |
|     bufferlen = n - 1; /* remember the \0 at the end */
 | |
|     return p;
 | |
| }
 | |
| 
 | |
| char* hop_render(struct hop* hop)
 | |
| {
 | |
|     int i;
 | |
| 
 | |
|     appendf(""); /* ensure the buffer has been allocated */
 | |
|     bufferlen = 0;
 | |
| 	buffer[0] = '\0';
 | |
| 
 | |
| 	for (i=0; i<hop->insels.count; i++)
 | |
| 	{
 | |
| 		struct insel* insel = hop->insels.item[i];
 | |
| 
 | |
| 		switch (insel->type)
 | |
| 		{
 | |
| 			case INSEL_EOI:
 | |
| 				appendf("\n");
 | |
| 				break;
 | |
| 
 | |
|             case INSEL_HREG:
 | |
|             {
 | |
|                 struct hreg* hreg = insel->u.hreg;
 | |
|                 if (hreg->brd)
 | |
|                     appendf("%s", hreg->brd->names[insel->index]);
 | |
|                 else
 | |
|                     appendf("%s.%d", hreg->id, insel->index);
 | |
|                 break;
 | |
|             }
 | |
| 
 | |
| 			case INSEL_VREG:
 | |
|             {
 | |
|                 struct vreg* vreg = insel->u.vreg;
 | |
|                 struct hreg* hreg = pmap_findright(&hop->regsin, vreg);
 | |
|                 if (!hreg)
 | |
|                     hreg = pmap_findright(&hop->regsout, vreg);
 | |
|                 if (hreg)
 | |
|                     appendf("%s", hreg->brd->names[insel->index]);
 | |
|                 else
 | |
|                     appendf("%%%d.%d", vreg->id, insel->index);
 | |
| 				break;
 | |
|             }
 | |
| 
 | |
| 			case INSEL_STRING:
 | |
| 				appendf("%s", insel->u.string);
 | |
| 				break;
 | |
| 
 | |
|             case INSEL_ST_OFFSET:
 | |
|                 appendf("%d", current_proc->fp_to_sb + insel->u.hreg->offset);
 | |
|                 break;
 | |
| 
 | |
|             case INSEL_AB_OFFSET:
 | |
|                 appendf("%d", current_proc->fp_to_ab + insel->u.offset);
 | |
|                 break;
 | |
| 
 | |
|             case INSEL_LB_OFFSET:
 | |
|                 appendf("%d", current_proc->fp_to_lb + insel->u.offset);
 | |
|                 break;
 | |
| 
 | |
| 			case INSEL_VALUE:
 | |
| 			{
 | |
| 				struct ir* ir = insel->u.value;
 | |
| 				switch (ir->opcode)
 | |
| 				{
 | |
| 					case IR_BLOCK:
 | |
| 						appendf("%s", platform_label(ir->u.bvalue->name));
 | |
| 						break;
 | |
| 
 | |
| 					case IR_LABEL:
 | |
| 						appendf("%s", platform_label(ir->u.lvalue));
 | |
| 						break;
 | |
| 
 | |
| 					case IR_LOCAL:
 | |
|                         if (ir->u.ivalue >= 0)
 | |
|                             appendf("%d", current_proc->fp_to_ab + ir->u.ivalue);
 | |
|                         else
 | |
|                             appendf("%d", current_proc->fp_to_lb + ir->u.ivalue);
 | |
|                         break;
 | |
| 
 | |
| 					case IR_CONST:
 | |
| 						appendf("%d", ir->u.ivalue);
 | |
| 						break;
 | |
| 
 | |
|                     default:
 | |
|                         assert(false);
 | |
| 				}
 | |
| 				break;
 | |
| 			}
 | |
| 
 | |
|             default:
 | |
|                 assert(false);
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
|     return buffer;
 | |
| }
 | |
| 
 | |
| void hop_print(char k, struct hop* hop)
 | |
| {
 | |
| 	int i;
 | |
| 	bool soi = false;
 | |
|     char* p;
 | |
| 
 | |
|     hop_render(hop);
 | |
| 
 | |
|     p = strtok(buffer, "\n");
 | |
|     print_header(k, hop);
 | |
|     while (p)
 | |
|     {
 | |
|         tracef(k, "%s", p);
 | |
|         p = strtok(NULL, "\n");
 | |
|         if (p)
 | |
|         {
 | |
|             tracef(k, "\n");
 | |
|             print_header(k, hop);
 | |
|         }
 | |
|     }
 | |
|     tracef(k, "\n");
 | |
| }
 | |
| 
 | |
| /* vim: set sw=4 ts=4 expandtab : */
 | |
| 
 |