More rigorous dealing of IR groups; no need for is_generated and is_root any
more (but now passes are required to set IR roots properly when changing instructions).
This commit is contained in:
parent
21898f784a
commit
a3cfe6047f
|
@ -68,17 +68,18 @@ struct ir* new_localir(int offset)
|
||||||
|
|
||||||
struct ir* ir_walk(struct ir* ir, ir_walker_t* cb, void* user)
|
struct ir* ir_walk(struct ir* ir, ir_walker_t* cb, void* user)
|
||||||
{
|
{
|
||||||
|
assert(ir->root);
|
||||||
if (cb(ir, user))
|
if (cb(ir, user))
|
||||||
return ir;
|
return ir;
|
||||||
|
|
||||||
if (ir->left && !ir->left->is_root)
|
if (ir->left && (ir->left->root == ir->root))
|
||||||
{
|
{
|
||||||
struct ir* irr = ir_walk(ir->left, cb, user);
|
struct ir* irr = ir_walk(ir->left, cb, user);
|
||||||
if (irr)
|
if (irr)
|
||||||
return irr;
|
return irr;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ir->right && !ir->right->is_root)
|
if (ir->right && (ir->right->root == ir->root))
|
||||||
{
|
{
|
||||||
struct ir* irr = ir_walk(ir->right, cb, user);
|
struct ir* irr = ir_walk(ir->right, cb, user);
|
||||||
if (irr)
|
if (irr)
|
||||||
|
@ -106,7 +107,7 @@ static void print_expr(char k, const struct ir* ir)
|
||||||
tracef(k, "%s", ir_data[ir->opcode].name);
|
tracef(k, "%s", ir_data[ir->opcode].name);
|
||||||
if (ir->size)
|
if (ir->size)
|
||||||
tracef(k, "%d", ir->size);
|
tracef(k, "%d", ir->size);
|
||||||
tracef(k, "(");
|
tracef(k, ":%d(", ir->id);
|
||||||
|
|
||||||
switch (ir->opcode)
|
switch (ir->opcode)
|
||||||
{
|
{
|
||||||
|
@ -123,10 +124,23 @@ static void print_expr(char k, const struct ir* ir)
|
||||||
tracef(k, "%s", ir->u.bvalue->name);
|
tracef(k, "%s", ir->u.bvalue->name);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case IR_PHI:
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
|
||||||
|
for (i=0; i<ir->u.phivalue.count; i++)
|
||||||
|
{
|
||||||
|
if (i > 0)
|
||||||
|
tracef(k, ", ");
|
||||||
|
tracef(k, "$%d", ir->u.phivalue.item[i]->id);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
default:
|
default:
|
||||||
if (ir->left)
|
if (ir->left)
|
||||||
{
|
{
|
||||||
if (ir->left->is_root)
|
if (ir->left->root == ir->root)
|
||||||
tracef(k, "$%d", ir->left->id);
|
tracef(k, "$%d", ir->left->id);
|
||||||
else
|
else
|
||||||
print_expr(k, ir->left);
|
print_expr(k, ir->left);
|
||||||
|
@ -134,7 +148,7 @@ static void print_expr(char k, const struct ir* ir)
|
||||||
if (ir->right)
|
if (ir->right)
|
||||||
{
|
{
|
||||||
tracef(k, ", ");
|
tracef(k, ", ");
|
||||||
if (ir->right->is_root)
|
if (ir->right->root == ir->root)
|
||||||
tracef(k, "$%d", ir->right->id);
|
tracef(k, "$%d", ir->right->id);
|
||||||
else
|
else
|
||||||
print_expr(k, ir->right);
|
print_expr(k, ir->right);
|
||||||
|
|
|
@ -10,21 +10,20 @@ struct ir
|
||||||
int size;
|
int size;
|
||||||
struct ir* left;
|
struct ir* left;
|
||||||
struct ir* right;
|
struct ir* right;
|
||||||
|
struct ir* root;
|
||||||
union
|
union
|
||||||
{
|
{
|
||||||
arith ivalue;
|
arith ivalue;
|
||||||
int rvalue;
|
int rvalue;
|
||||||
const char* lvalue;
|
const char* lvalue;
|
||||||
struct basicblock* bvalue;
|
struct basicblock* bvalue;
|
||||||
|
ARRAYOF(struct ir) phivalue;
|
||||||
} u;
|
} u;
|
||||||
|
|
||||||
void* state_label; /* used by the iburg instruction selector */
|
void* state_label; /* used by the iburg instruction selector */
|
||||||
int insn_no; /* the table rule number for this instruction */
|
int insn_no; /* the table rule number for this instruction */
|
||||||
int goal_no; /* the semantic type of this instruction; not stmt */
|
int goal_no; /* the semantic type of this instruction; not stmt */
|
||||||
ARRAYOF(struct hop) hops; /* only for root IRs */
|
ARRAYOF(struct hop) hops; /* only for root IRs */
|
||||||
|
|
||||||
bool is_root : 1;
|
|
||||||
bool is_generated : 1;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
extern const char* ir_names[];
|
extern const char* ir_names[];
|
||||||
|
|
|
@ -125,6 +125,7 @@ extern void pass_remove_dead_blocks(struct procedure* proc);
|
||||||
extern void pass_eliminate_trivial_blocks(struct procedure* proc);
|
extern void pass_eliminate_trivial_blocks(struct procedure* proc);
|
||||||
extern void pass_instruction_selector(struct procedure* proc);
|
extern void pass_instruction_selector(struct procedure* proc);
|
||||||
extern void pass_promote_float_ops(struct procedure* proc);
|
extern void pass_promote_float_ops(struct procedure* proc);
|
||||||
|
extern void pass_group_irs(struct procedure* proc);
|
||||||
|
|
||||||
extern void procedure_compile(struct procedure* proc);
|
extern void procedure_compile(struct procedure* proc);
|
||||||
|
|
||||||
|
|
|
@ -4,20 +4,13 @@
|
||||||
|
|
||||||
#define PANIC printf
|
#define PANIC printf
|
||||||
|
|
||||||
static int OP_LABEL(struct ir* ir)
|
#define OP_LABEL(p) burm_calculate_label(p)
|
||||||
{
|
|
||||||
if (ir->is_root && ir->is_generated)
|
|
||||||
{
|
|
||||||
return ir_to_esn(IR_REG, ir->size);
|
|
||||||
}
|
|
||||||
return ir_to_esn(ir->opcode, ir->size);
|
|
||||||
}
|
|
||||||
|
|
||||||
#define LEFT_CHILD(p) ((p)->left)
|
#define LEFT_CHILD(p) ((p)->left)
|
||||||
#define RIGHT_CHILD(p) ((p)->right)
|
#define RIGHT_CHILD(p) ((p)->right)
|
||||||
|
|
||||||
#define burm_assert(b, s) assert(b)
|
#define burm_assert(b, s) assert(b)
|
||||||
|
|
||||||
|
extern int burm_calculate_label(struct ir* ir);
|
||||||
extern void burm_panic_cannot_match(struct ir* ir);
|
extern void burm_panic_cannot_match(struct ir* ir);
|
||||||
|
|
||||||
static bool burm_predicate_int(struct ir* ir)
|
static bool burm_predicate_int(struct ir* ir)
|
||||||
|
|
|
@ -112,22 +112,20 @@ static void convert_block(struct procedure* proc, struct basicblock* bb)
|
||||||
for (i=0; i<pushes.count; i++)
|
for (i=0; i<pushes.count; i++)
|
||||||
{
|
{
|
||||||
struct ir* ir = pushes.item[i];
|
struct ir* ir = pushes.item[i];
|
||||||
assert(ir->is_root);
|
|
||||||
*ir = *ir->left;
|
*ir = *ir->left;
|
||||||
ir->is_root = true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
for (i=0; i<pops.count; i++)
|
for (i=0; i<pops.count; i++)
|
||||||
{
|
{
|
||||||
struct ir* ir = pops.item[i];
|
struct ir* ir = pops.item[i];
|
||||||
struct ir* pushir = pushes.item[0];
|
struct ir* phi = new_ir0(IR_PHI, ir->size);
|
||||||
struct ir* phi = new_ir1(IR_PHI, ir->size, pushir);
|
|
||||||
|
|
||||||
for (j=1; j<pushes.count; j++)
|
for (j=0; j<pushes.count; j++)
|
||||||
phi = new_ir2(IR_PHI, ir->size, phi, pushes.item[j]);
|
array_appendu(&phi->u.phivalue, pushes.item[j]);
|
||||||
|
phi->root = phi;
|
||||||
|
|
||||||
phi->is_root = ir->is_root;
|
|
||||||
*ir = *phi;
|
*ir = *phi;
|
||||||
|
array_insert(&bb->irs, ir, 0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
95
mach/proto/mcg/pass_groupirs.c
Normal file
95
mach/proto/mcg/pass_groupirs.c
Normal file
|
@ -0,0 +1,95 @@
|
||||||
|
#include "mcg.h"
|
||||||
|
|
||||||
|
static ARRAYOF(struct ir) allirs;
|
||||||
|
static ARRAYOF(struct ir) rootirs;
|
||||||
|
|
||||||
|
static void addall(struct ir* ir)
|
||||||
|
{
|
||||||
|
if (array_appendu(&allirs, ir))
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (ir->left)
|
||||||
|
addall(ir->left);
|
||||||
|
if (ir->right)
|
||||||
|
addall(ir->right);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void collect_irs(struct procedure* proc)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
|
||||||
|
allirs.count = rootirs.count = 0;
|
||||||
|
for (i=0; i<proc->blocks.count; i++)
|
||||||
|
{
|
||||||
|
struct basicblock* bb = proc->blocks.item[i];
|
||||||
|
int j;
|
||||||
|
|
||||||
|
for (j=0; j<bb->irs.count; j++)
|
||||||
|
{
|
||||||
|
struct ir* ir = bb->irs.item[j];
|
||||||
|
addall(ir);
|
||||||
|
array_appendu(&rootirs, ir);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void clear_roots(void)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
|
||||||
|
for (i=0; i<allirs.count; i++)
|
||||||
|
{
|
||||||
|
struct ir* ir = allirs.item[i];
|
||||||
|
ir->root = NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void find_roots(void)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
|
||||||
|
for (i=0; i<rootirs.count; i++)
|
||||||
|
{
|
||||||
|
struct ir* ir = rootirs.item[i];
|
||||||
|
assert(!ir->root);
|
||||||
|
ir->root = ir;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void recursively_mark_root(struct ir* node, struct ir* root)
|
||||||
|
{
|
||||||
|
if (node != root)
|
||||||
|
{
|
||||||
|
if (node->root)
|
||||||
|
return;
|
||||||
|
node->root = root;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (node->left)
|
||||||
|
recursively_mark_root(node->left, root);
|
||||||
|
if (node->right)
|
||||||
|
recursively_mark_root(node->right, root);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void find_non_roots(void)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
|
||||||
|
for (i=0; i<rootirs.count; i++)
|
||||||
|
{
|
||||||
|
struct ir* ir = rootirs.item[i];
|
||||||
|
recursively_mark_root(ir, ir);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void pass_group_irs(struct procedure* proc)
|
||||||
|
{
|
||||||
|
collect_irs(proc);
|
||||||
|
clear_roots();
|
||||||
|
find_roots();
|
||||||
|
find_non_roots();
|
||||||
|
}
|
||||||
|
|
||||||
|
/* vim: set sw=4 ts=4 expandtab : */
|
||||||
|
|
||||||
|
|
|
@ -2,6 +2,7 @@
|
||||||
|
|
||||||
static struct basicblock* current_bb;
|
static struct basicblock* current_bb;
|
||||||
static struct hop* current_hop;
|
static struct hop* current_hop;
|
||||||
|
static struct ir* current_ir;
|
||||||
|
|
||||||
static const struct burm_emitter_data emitter_data;
|
static const struct burm_emitter_data emitter_data;
|
||||||
|
|
||||||
|
@ -19,6 +20,13 @@ void burm_panic_cannot_match(struct ir* ir)
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int burm_calculate_label(struct ir* ir)
|
||||||
|
{
|
||||||
|
if (ir->root != current_ir)
|
||||||
|
return ir_to_esn(IR_REG, ir->size);
|
||||||
|
return ir_to_esn(ir->opcode, ir->size);
|
||||||
|
}
|
||||||
|
|
||||||
static void emit_reg(struct ir* ir, int goal)
|
static void emit_reg(struct ir* ir, int goal)
|
||||||
{
|
{
|
||||||
hop_add_reg_insel(current_hop, ir, goal);
|
hop_add_reg_insel(current_hop, ir, goal);
|
||||||
|
@ -81,14 +89,12 @@ static void walk_instructions(struct ir* ir, int goal)
|
||||||
for (i=0; nts[i]; i++)
|
for (i=0; nts[i]; i++)
|
||||||
walk_instructions(children[i], nts[i]);
|
walk_instructions(children[i], nts[i]);
|
||||||
|
|
||||||
ir->is_generated = true;
|
|
||||||
ir->insn_no = insn_no;
|
ir->insn_no = insn_no;
|
||||||
if (goal != 1)
|
if (goal != 1)
|
||||||
ir->goal_no = goal;
|
ir->goal_no = goal;
|
||||||
|
|
||||||
tracef('I', "I: $%d %s goal %d selected %s %d: %s\n",
|
tracef('I', "I: $%d goal %d selected %s %d: %s\n",
|
||||||
ir->id,
|
ir->id,
|
||||||
ir->is_root ? "S" : " ",
|
|
||||||
ir->goal_no,
|
ir->goal_no,
|
||||||
insndata->is_fragment ? "fragment" : "instruction",
|
insndata->is_fragment ? "fragment" : "instruction",
|
||||||
insn_no,
|
insn_no,
|
||||||
|
@ -114,15 +120,15 @@ static void select_instructions(void)
|
||||||
for (i=0; i<current_bb->irs.count; i++)
|
for (i=0; i<current_bb->irs.count; i++)
|
||||||
{
|
{
|
||||||
int insnno;
|
int insnno;
|
||||||
struct ir* ir = current_bb->irs.item[i];
|
current_ir = current_bb->irs.item[i];
|
||||||
burm_label(ir);
|
burm_label(current_ir);
|
||||||
|
|
||||||
insnno = burm_rule(ir->state_label, 1);
|
insnno = burm_rule(current_ir->state_label, 1);
|
||||||
if (!insnno)
|
if (!insnno)
|
||||||
burm_panic_cannot_match(ir);
|
burm_panic_cannot_match(current_ir);
|
||||||
|
|
||||||
ir_print('I', ir);
|
ir_print('I', current_ir);
|
||||||
walk_instructions(ir, 1);
|
walk_instructions(current_ir, 1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -26,6 +26,7 @@ void procedure_compile(struct procedure* proc)
|
||||||
|
|
||||||
print_blocks('1', proc);
|
print_blocks('1', proc);
|
||||||
|
|
||||||
|
pass_group_irs(proc);
|
||||||
pass_eliminate_trivial_blocks(proc);
|
pass_eliminate_trivial_blocks(proc);
|
||||||
pass_remove_dead_blocks(proc);
|
pass_remove_dead_blocks(proc);
|
||||||
pass_convert_stack_ops(proc);
|
pass_convert_stack_ops(proc);
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
#include "mcg.h"
|
#include "mcg.h"
|
||||||
|
|
||||||
static struct symbol* currentproc;
|
|
||||||
static struct basicblock* current_bb;
|
static struct basicblock* current_bb;
|
||||||
|
|
||||||
static int stackptr;
|
static int stackptr;
|
||||||
|
@ -76,7 +75,6 @@ static struct ir* appendir(struct ir* ir)
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
assert(current_bb != NULL);
|
assert(current_bb != NULL);
|
||||||
ir->is_root = true;
|
|
||||||
array_append(¤t_bb->irs, ir);
|
array_append(¤t_bb->irs, ir);
|
||||||
|
|
||||||
ir_print('0', ir);
|
ir_print('0', ir);
|
||||||
|
@ -479,8 +477,7 @@ static void insn_ivalue(int opcode, arith value)
|
||||||
case op_dup:
|
case op_dup:
|
||||||
{
|
{
|
||||||
struct ir* v = pop(value);
|
struct ir* v = pop(value);
|
||||||
if (!v->is_root)
|
appendir(v);
|
||||||
appendir(v);
|
|
||||||
push(v);
|
push(v);
|
||||||
push(v);
|
push(v);
|
||||||
break;
|
break;
|
||||||
|
|
|
@ -1,11 +1,10 @@
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <stdbool.h>
|
#include <stdbool.h>
|
||||||
|
#include <string.h>
|
||||||
#include "array.h"
|
#include "array.h"
|
||||||
|
|
||||||
void array_append(void* arrayp, void* value)
|
static void extend(struct array* array)
|
||||||
{
|
{
|
||||||
struct array* array = arrayp;
|
|
||||||
|
|
||||||
if (array->count == array->max)
|
if (array->count == array->max)
|
||||||
{
|
{
|
||||||
int newmax = (array->max == 0) ? 8 : (array->max * 2);
|
int newmax = (array->max == 0) ? 8 : (array->max * 2);
|
||||||
|
@ -14,7 +13,13 @@ void array_append(void* arrayp, void* value)
|
||||||
array->max = newmax;
|
array->max = newmax;
|
||||||
array->item = newarray;
|
array->item = newarray;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void array_append(void* arrayp, void* value)
|
||||||
|
{
|
||||||
|
struct array* array = arrayp;
|
||||||
|
|
||||||
|
extend(array);
|
||||||
array->item[array->count] = value;
|
array->item[array->count] = value;
|
||||||
array->count++;
|
array->count++;
|
||||||
}
|
}
|
||||||
|
@ -40,6 +45,17 @@ bool array_appendu(void* arrayp, void* value)
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void array_insert(void* arrayp, void* value, int before)
|
||||||
|
{
|
||||||
|
struct array* array = arrayp;
|
||||||
|
|
||||||
|
extend(array);
|
||||||
|
memmove(&array->item[before+1], &array->item[before],
|
||||||
|
(array->count-before) * sizeof(*array));
|
||||||
|
array->item[before] = value;
|
||||||
|
array->count++;
|
||||||
|
}
|
||||||
|
|
||||||
void array_remove(void* arrayp, void* value)
|
void array_remove(void* arrayp, void* value)
|
||||||
{
|
{
|
||||||
struct array* array = arrayp;
|
struct array* array = arrayp;
|
||||||
|
|
|
@ -19,6 +19,7 @@ struct array
|
||||||
|
|
||||||
extern void array_append(void* array, void* value);
|
extern void array_append(void* array, void* value);
|
||||||
extern bool array_appendu(void* array, void* value);
|
extern bool array_appendu(void* array, void* value);
|
||||||
|
extern void array_insert(void* array, void* value, int before);
|
||||||
extern void array_remove(void* array, void* value);
|
extern void array_remove(void* array, void* value);
|
||||||
extern bool array_contains(void* array, void* value);
|
extern bool array_contains(void* array, void* value);
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue