Output register equality constraints work.
This commit is contained in:
		
							parent
							
								
									216ff5cc43
								
							
						
					
					
						commit
						98fe70a7de
					
				
					 8 changed files with 119 additions and 28 deletions
				
			
		|  | @ -26,6 +26,7 @@ struct insel | |||
| struct constraint | ||||
| { | ||||
|     uint32_t attrs; | ||||
|     struct vreg* equals_to; | ||||
| }; | ||||
| 
 | ||||
| struct hop | ||||
|  |  | |||
|  | @ -113,6 +113,13 @@ static void constrain_output_reg(uint32_t attr) | |||
|     get_constraint(vreg)->attrs = attr; | ||||
| } | ||||
| 
 | ||||
| static void constrain_output_reg_equal_to(int child) | ||||
| { | ||||
|     struct vreg* vreg = find_vreg_of_child(child); | ||||
| 
 | ||||
|     get_constraint(current_hop->output)->equals_to = vreg; | ||||
| } | ||||
| 
 | ||||
| static const struct burm_emitter_data emitter_data = | ||||
| { | ||||
|     &emit_string, | ||||
|  | @ -122,7 +129,8 @@ static const struct burm_emitter_data emitter_data = | |||
|     &emit_value, | ||||
|     &emit_eoi, | ||||
|     &constrain_input_reg, | ||||
|     &constrain_output_reg | ||||
|     &constrain_output_reg, | ||||
|     &constrain_output_reg_equal_to, | ||||
| }; | ||||
| 
 | ||||
| static void emit(struct insn* insn) | ||||
|  |  | |||
|  | @ -142,8 +142,55 @@ static void add_output_register(struct vreg* vreg) | |||
| { | ||||
|     struct hreg* hreg; | ||||
|     int i; | ||||
|     struct constraint* c; | ||||
| 
 | ||||
|     /* Find an unused output register of the right class. */ | ||||
|     /* Is this register supposed to be the same as one of the input registers?
 | ||||
|      * */ | ||||
| 
 | ||||
|     c = pmap_findleft(¤t_hop->constraints, vreg); | ||||
|     if (c->equals_to) | ||||
|     { | ||||
|         /* This output register is constrained to be in the same hreg as an
 | ||||
|          * input register (most likely for a 2op instruction). */ | ||||
| 
 | ||||
|         hreg = pmap_findright(current_ins, c->equals_to); | ||||
| 
 | ||||
|         /* If this register is current unused as an output, use it. */ | ||||
| 
 | ||||
|         if (!pmap_findleft(current_outs, hreg)) | ||||
|         { | ||||
|             pmap_add(current_outs, hreg, vreg); | ||||
|             return; | ||||
|         } | ||||
| 
 | ||||
|         /* Okay, something's in it. Most likely it's a through being used as an
 | ||||
|          * input register.  Trying to evict it would be pointless as that would | ||||
|          * also evict the input. So, we're going to have to do this the hard | ||||
|          * way: we try to allocate a matched set of input and output registers. | ||||
|          * */ | ||||
| 
 | ||||
|         hreg = NULL; | ||||
|         for (i=0; i<hregs.count; i++) | ||||
|         { | ||||
|             hreg = hregs.item[i]; | ||||
|             if (allocatable(hreg, vreg) && | ||||
|                 !pmap_findleft(current_ins, hreg) && | ||||
|                 !pmap_findleft(current_outs, hreg)) | ||||
|             { | ||||
|                 goto found1; | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
|         /* If we couldn't find one, evict a register. */ | ||||
| 
 | ||||
|         hreg = evict(vreg); | ||||
|     found1: | ||||
|         pmap_add(current_outs, hreg, vreg); | ||||
|         pmap_add(current_ins, hreg, c->equals_to); | ||||
|     } | ||||
|     else | ||||
|     { | ||||
|         /* This is an ordinary new register. */ | ||||
| 
 | ||||
|         hreg = NULL; | ||||
|         for (i=0; i<hregs.count; i++) | ||||
|  | @ -152,7 +199,7 @@ static void add_output_register(struct vreg* vreg) | |||
|             if (allocatable(hreg, vreg) && | ||||
|                 !pmap_findleft(current_outs, hreg)) | ||||
|             { | ||||
|             goto found; | ||||
|                 goto found2; | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
|  | @ -160,9 +207,10 @@ static void add_output_register(struct vreg* vreg) | |||
| 
 | ||||
|         hreg = evict(vreg); | ||||
| 
 | ||||
| found: | ||||
|     found2: | ||||
|         pmap_add(current_outs, hreg, vreg); | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| static void find_new_home_for_evicted_register(struct vreg* vreg, struct hreg* src) | ||||
| { | ||||
|  |  | |||
|  | @ -167,33 +167,40 @@ PATTERNS | |||
|     /* Conversions to ubyte and ushort */ | ||||
| 
 | ||||
|     out:(int)ubyte = in:(int)reg | ||||
|         emit "mr %out, %in ! reg -> ubyte" | ||||
|         with %out == %in | ||||
|         emit "! reg -> ubyte" | ||||
|         cost 1; | ||||
| 
 | ||||
|     out:(int)ubyte = CIU41(value:(int)reg) | ||||
|         emit "mr %out, %value ! CIU41(reg) -> ubyte" | ||||
|         with %out == %value | ||||
|         emit "! CIU41(reg) -> ubyte" | ||||
|         cost 1; | ||||
| 
 | ||||
|     out:(int)ubyte = CIU41(CII14(CIU41(value:(int)reg))) | ||||
|         emit "mr %out, %value ! CIU41(CII14(CIU41(reg))) -> ubyte" | ||||
|         with %out == %value | ||||
|         emit "! CIU41(CII14(CIU41(reg))) -> ubyte" | ||||
|         cost 1; | ||||
| 
 | ||||
|     out:(int)ushort = in:(int)reg | ||||
|         emit "mr %out, %in ! reg -> ushort" | ||||
|         with %out == %in | ||||
|         emit "! reg -> ushort" | ||||
|         cost 1; | ||||
| 
 | ||||
|     out:(int)ushort = CIU42(value:(int)reg) | ||||
|         emit "mr %out, %value ! CIU42(reg) -> ushort" | ||||
|         with %out == %value | ||||
|         emit "! CIU42(reg) -> ushort" | ||||
|         cost 1; | ||||
| 
 | ||||
|     out:(int)ushort = CIU42(CII24(CIU42(value:(int)reg))) | ||||
|         emit "mr %out, %value ! CIU42(CII24(CIU42(reg))) -> ushort" | ||||
|         with %out == %value | ||||
|         emit "! CIU42(CII24(CIU42(reg))) -> ushort" | ||||
|         cost 1; | ||||
| 
 | ||||
|     /* Conversions from ubyte and ushort */ | ||||
| 
 | ||||
|     out:(int)reg = CIU14(in:(int)ubyte) | ||||
|         emit "mr %out, %in ! CIU14" | ||||
|         with %out == %in | ||||
|         emit "! CIU14" | ||||
|         cost 4; | ||||
| 
 | ||||
| 	 | ||||
|  |  | |||
|  | @ -143,12 +143,8 @@ constraints | |||
| 
 | ||||
| constraint | ||||
|     : '(' constraint ')'                { $$ = $2; } | ||||
|     | ID ID                             { $$ = calloc(1, sizeof(*$$)); | ||||
|                                           $$->type = CONSTRAINT_ATTR; $$->left = $1; $$->right = $2; } | ||||
|     | ID EQUALS ID                      { $$ = calloc(1, sizeof(*$$)); | ||||
|                                           $$->type = CONSTRAINT_EQUALS; $$->left = $1; $$->right = $3; } | ||||
|     | ID NOTEQUALS ID                   { $$ = calloc(1, sizeof(*$$)); | ||||
|                                           $$->type = CONSTRAINT_NOTEQUALS; $$->left = $1; $$->right = $3; } | ||||
|     | '%' ID EQUALS '%' ID              { $$ = calloc(1, sizeof(*$$)); | ||||
|                                           $$->type = CONSTRAINT_EQUALS; $$->left = $2; $$->right = $5; } | ||||
|     ; | ||||
| 
 | ||||
| qfragments | ||||
|  |  | |||
|  | @ -1096,6 +1096,36 @@ static void emit_input_regs(Tree node, int* index) | |||
| 		emit_input_regs(node->right, index); | ||||
| } | ||||
| 
 | ||||
| static void emit_output_constraints(Rule r) | ||||
| { | ||||
| 	int i; | ||||
| 	struct constraint* outputc = NULL; | ||||
| 
 | ||||
| 	for (i=0; i<r->constraints.count; i++) | ||||
| 	{ | ||||
| 		struct constraint* c = r->constraints.item[i]; | ||||
| 
 | ||||
| 		if (c->type == CONSTRAINT_EQUALS) | ||||
| 		{ | ||||
| 			if (strcmp(c->left, r->label) != 0) | ||||
| 				yyerror("equality register constraints must have an output register on the left hand side"); | ||||
| 			if (outputc != NULL) | ||||
| 				yyerror("you can't specify more than one output register constraint"); | ||||
| 			outputc = c; | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	if (outputc) | ||||
| 	{ | ||||
| 		int index = 0; | ||||
| 
 | ||||
| 		if (!find_child_index(r->pattern, outputc->right, &index, NULL)) | ||||
| 			label_not_found(r, outputc->right); | ||||
| 
 | ||||
| 		print("%1data->constrain_output_reg_equal_to(%d);\n", index); | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| /* emitinsndata - emit the code generation data */ | ||||
| static void emitinsndata(Rule rules) | ||||
| { | ||||
|  | @ -1130,6 +1160,8 @@ static void emitinsndata(Rule rules) | |||
| 			emit_input_regs(r->pattern, &index); | ||||
| 		} | ||||
| 		 | ||||
| 		emit_output_constraints(r); | ||||
| 		 | ||||
| 		while (f) | ||||
| 		{ | ||||
| 			switch (f->data[0]) | ||||
|  |  | |||
|  | @ -19,9 +19,7 @@ typedef struct term* Term; | |||
| 
 | ||||
| enum | ||||
| { | ||||
| 	CONSTRAINT_ATTR, | ||||
| 	CONSTRAINT_EQUALS, | ||||
| 	CONSTRAINT_NOTEQUALS | ||||
| }; | ||||
| 
 | ||||
| struct constraint | ||||
|  |  | |||
|  | @ -46,6 +46,7 @@ struct burm_emitter_data | |||
|     void (*emit_eoi)(void); | ||||
|     void (*constrain_input_reg)(int child, uint32_t attr); | ||||
|     void (*constrain_output_reg)(uint32_t attr); | ||||
|     void (*constrain_output_reg_equal_to)(int child); | ||||
| }; | ||||
| 
 | ||||
| typedef void burm_emitter_t(const struct burm_emitter_data* data); | ||||
|  |  | |||
		Loading…
	
	Add table
		
		Reference in a new issue