diff --git a/mach/proto/mcg/hop.h b/mach/proto/mcg/hop.h index 7dcbfd87a..ab2b39d59 100644 --- a/mach/proto/mcg/hop.h +++ b/mach/proto/mcg/hop.h @@ -26,6 +26,7 @@ struct insel struct constraint { uint32_t attrs; + struct vreg* equals_to; }; struct hop diff --git a/mach/proto/mcg/pass_instructionselection.c b/mach/proto/mcg/pass_instructionselection.c index b87ede3aa..7e38efe4b 100644 --- a/mach/proto/mcg/pass_instructionselection.c +++ b/mach/proto/mcg/pass_instructionselection.c @@ -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) diff --git a/mach/proto/mcg/pass_registerallocator.c b/mach/proto/mcg/pass_registerallocator.c index 42f43ef33..6f2cff26a 100644 --- a/mach/proto/mcg/pass_registerallocator.c +++ b/mach/proto/mcg/pass_registerallocator.c @@ -142,26 +142,74 @@ 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? + * */ - hreg = NULL; - for (i=0; iconstraints, vreg); + if (c->equals_to) { - hreg = hregs.item[i]; - if (allocatable(hreg, vreg) && - !pmap_findleft(current_outs, hreg)) + /* 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)) { - goto found; + 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; iequals_to); } + else + { + /* This is an ordinary new register. */ - /* If we couldn't find one, evict a register. */ + hreg = NULL; + for (i=0; i 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; diff --git a/util/mcgg/gram.y b/util/mcgg/gram.y index f6f39ae0f..3fe5f9c10 100644 --- a/util/mcgg/gram.y +++ b/util/mcgg/gram.y @@ -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 diff --git a/util/mcgg/iburg.c b/util/mcgg/iburg.c index bf3a698d1..a3d9568e8 100644 --- a/util/mcgg/iburg.c +++ b/util/mcgg/iburg.c @@ -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; iconstraints.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) { @@ -1129,7 +1159,9 @@ static void emitinsndata(Rule rules) int index = 0; emit_input_regs(r->pattern, &index); } - + + emit_output_constraints(r); + while (f) { switch (f->data[0]) diff --git a/util/mcgg/iburg.h b/util/mcgg/iburg.h index 34c046e13..ebd22fbe3 100644 --- a/util/mcgg/iburg.h +++ b/util/mcgg/iburg.h @@ -19,9 +19,7 @@ typedef struct term* Term; enum { - CONSTRAINT_ATTR, CONSTRAINT_EQUALS, - CONSTRAINT_NOTEQUALS }; struct constraint diff --git a/util/mcgg/mcgg.h b/util/mcgg/mcgg.h index 94e5b67bf..c0c9d87fb 100644 --- a/util/mcgg/mcgg.h +++ b/util/mcgg/mcgg.h @@ -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);