Instruction selection now happens on a shadow tree, rather than on the IR tree

itself. Currently it's semantically the same but the implementation is cleaner.
This commit is contained in:
David Given 2016-10-03 20:52:36 +02:00
parent 288ee56203
commit 68f98cbad7
7 changed files with 79 additions and 66 deletions

View file

@ -20,9 +20,6 @@ struct ir
ARRAYOF(struct ir) phivalue; ARRAYOF(struct ir) phivalue;
} u; } u;
void* state_label; /* used by the iburg instruction selector */
int insn_no; /* the table rule number for this instruction */
int goal_no; /* the semantic type of this instruction; not stmt */
IMAPOF(struct hop) hops; /* only for root IRs; by goal */ IMAPOF(struct hop) hops; /* only for root IRs; by goal */
}; };

View file

@ -4,22 +4,7 @@
#define PANIC printf #define PANIC printf
#define OP_LABEL(p) burm_calculate_label(p)
#define LEFT_CHILD(p) ((p)->left)
#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(NODEPTR_TYPE node);
extern void burm_panic_cannot_match(struct ir* ir);
static bool burm_predicate_int(struct ir* ir)
{
return ir->goal_no == 3;
}
static bool burm_predicate_float(struct ir* ir)
{
return ir->goal_no == 5;
}

View file

@ -6,28 +6,21 @@ static struct ir* current_ir;
static const struct burm_emitter_data emitter_data; static const struct burm_emitter_data emitter_data;
void burm_trace(struct ir* p, int ruleno, int cost, int bestcost) { void burm_trace(struct burm_node* p, int ruleno, int cost, int bestcost) {
const struct burm_instruction_data* insndata = &burm_instruction_data[ruleno]; const struct burm_instruction_data* insndata = &burm_instruction_data[ruleno];
//tracef('I', "I: 0x%p matched %s with cost %d vs. %d\n", p, //tracef('I', "I: 0x%p matched %s with cost %d vs. %d\n", p,
// insndata->name, cost, bestcost); // insndata->name, cost, bestcost);
} }
void burm_panic_cannot_match(struct ir* ir) void burm_panic_cannot_match(struct burm_node* node)
{ {
fprintf(stderr, "could not find any patterns to match:\n"); fprintf(stderr, "could not find any patterns to match:\n");
ir_print(0, ir); ir_print(0, node->ir);
fprintf(stderr, "aborting!\n"); fprintf(stderr, "aborting!\n");
exit(1); exit(1);
} }
int burm_calculate_label(struct ir* ir) static void emit_reg(struct burm_node* node, int goal)
{
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)
{ {
struct hop* hop = imap_get(&current_ir->hops, goal); struct hop* hop = imap_get(&current_ir->hops, goal);
@ -39,17 +32,17 @@ static void emit_string(const char* data)
hop_add_string_insel(current_hop, data); hop_add_string_insel(current_hop, data);
} }
static void emit_fragment(struct ir* ir, int goal) static void emit_fragment(struct burm_node* node, int goal)
{ {
int insn_no = burm_rule(ir->state_label, goal); int insn_no = burm_rule(node->state_label, goal);
const struct burm_instruction_data* insndata = &burm_instruction_data[insn_no]; const struct burm_instruction_data* insndata = &burm_instruction_data[insn_no];
if (insndata->emitter) if (insndata->emitter)
insndata->emitter(ir, &emitter_data); insndata->emitter(node, &emitter_data);
} }
static void emit_value(struct ir* ir) static void emit_value(struct burm_node* node)
{ {
hop_add_value_insel(current_hop, ir); hop_add_value_insel(current_hop, node->ir);
} }
static void emit_eoi(void) static void emit_eoi(void)
@ -57,15 +50,17 @@ static void emit_eoi(void)
hop_add_eoi_insel(current_hop); hop_add_eoi_insel(current_hop);
} }
static void emit_constraint_equals(struct ir* ir, int goal) static void emit_constraint_equals(struct burm_node* node, int goal)
{ {
#if 0
struct hop* hop; struct hop* hop;
if (!goal) if (!goal)
goal = 2; goal = ir->goal_no;
hop = imap_get(&current_ir->hops, goal); hop = imap_get(&current_ir->hops, goal);
current_hop->output = hop->output; current_hop->output = hop->output;
#endif
} }
static const struct burm_emitter_data emitter_data = static const struct burm_emitter_data emitter_data =
@ -79,13 +74,14 @@ static const struct burm_emitter_data emitter_data =
}; };
static void walk_instructions(struct ir* ir, int goal) static void walk_instructions(struct burm_node* node, int goal)
{ {
struct ir* children[10]; struct burm_node* children[10];
int insn_no = burm_rule(ir->state_label, goal); int insn_no = burm_rule(node->state_label, goal);
const struct burm_instruction_data* insndata = &burm_instruction_data[insn_no]; const struct burm_instruction_data* insndata = &burm_instruction_data[insn_no];
const short* nts = burm_nts[insn_no]; const short* nts = burm_nts[insn_no];
struct hop* parent_hop = NULL; struct hop* parent_hop = NULL;
struct ir* ir = node->ir;
int i; int i;
if (!insndata->is_fragment) if (!insndata->is_fragment)
@ -99,17 +95,13 @@ static void walk_instructions(struct ir* ir, int goal)
} }
} }
burm_kids(ir, insn_no, children); burm_kids(node, insn_no, children);
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->insn_no = insn_no;
if (goal != 1)
ir->goal_no = goal;
tracef('I', "I: $%d goal %d selected %s %d: %s\n", tracef('I', "I: $%d goal %d selected %s %d: %s\n",
ir->id, ir->id,
ir->goal_no, goal,
insndata->is_fragment ? "fragment" : "instruction", insndata->is_fragment ? "fragment" : "instruction",
insn_no, insn_no,
insndata->name); insndata->name);
@ -119,7 +111,7 @@ static void walk_instructions(struct ir* ir, int goal)
/* This may cause the vregs to be reassigned for this instruction (and /* This may cause the vregs to be reassigned for this instruction (and
* fragments contained within it). */ * fragments contained within it). */
insndata->emitter(ir, &emitter_data); insndata->emitter(node, &emitter_data);
hop_print('I', current_hop); hop_print('I', current_hop);
array_append(&ir->hops, current_hop); array_append(&ir->hops, current_hop);
@ -127,6 +119,27 @@ static void walk_instructions(struct ir* ir, int goal)
} }
} }
static struct burm_node* build_shadow_tree(struct ir* root, struct ir* ir)
{
struct burm_node* node = calloc(1, sizeof(*node));
node->ir = ir;
if (ir->root == root)
{
node->label = ir_to_esn(ir->opcode, ir->size);
if (ir->left)
node->left = build_shadow_tree(root, ir->left);
if (ir->right)
node->right = build_shadow_tree(root, ir->right);
}
else
node->label = ir_to_esn(IR_REG, 0);
return node;
}
static void select_instructions(void) static void select_instructions(void)
{ {
int i; int i;
@ -135,16 +148,19 @@ static void select_instructions(void)
for (i=0; i<current_bb->irs.count; i++) for (i=0; i<current_bb->irs.count; i++)
{ {
struct burm_node* shadow;
int insnno; int insnno;
current_ir = current_bb->irs.item[i];
burm_label(current_ir);
insnno = burm_rule(current_ir->state_label, 1); current_ir = current_bb->irs.item[i];
shadow = build_shadow_tree(current_ir, current_ir);
burm_label(shadow);
insnno = burm_rule(shadow->state_label, 1);
if (!insnno) if (!insnno)
burm_panic_cannot_match(current_ir); burm_panic_cannot_match(shadow);
ir_print('I', current_ir); ir_print('I', current_ir);
walk_instructions(current_ir, 1); walk_instructions(shadow, 1);
} }
} }

View file

@ -174,6 +174,7 @@ static bool rewrite_loads_cb(struct ir* ir, void* user)
if (is_local(ir)) if (is_local(ir))
{ {
ir->opcode = IR_NOP; ir->opcode = IR_NOP;
ir->size = 0;
ir->left = definition; ir->left = definition;
ir->right = NULL; ir->right = NULL;
} }
@ -214,6 +215,7 @@ static void recursively_rewrite_tree(struct basicblock* bb)
if (ir->opcode == IR_STORE) if (ir->opcode == IR_STORE)
{ {
ir->opcode = IR_NOP; ir->opcode = IR_NOP;
ir->size = 0;
ir->left = ir->right; ir->left = ir->right;
ir->right = NULL; ir->right = NULL;
} }

View file

@ -67,12 +67,12 @@ PATTERNS
emit "add sp, sp, %delta" emit "add sp, sp, %delta"
cost 4; cost 4;
reg = in:REG4 reg = in:REG
with (reg == in) with (reg == in)
emit "reg %reg" emit "reg %reg"
cost 1; cost 1;
reg = NOP4(in:reg) reg = NOP(in:reg)
with (reg == in) with (reg == in)
cost 1; cost 1;

View file

@ -5,14 +5,14 @@
# Simple terminals # Simple terminals
S CONST # must be followed by float form S CONST # must be followed by float form
S CONSTF S CONSTF
S REG V REG
S NOP V NOP
S LABEL S LABEL
S BLOCK S BLOCK
V PAIR V PAIR
S ANY S ANY
S LOCAL S LOCAL
S PHI V PHI
# Magic stack operations # Magic stack operations
S PUSH S PUSH

View file

@ -13,27 +13,40 @@
(size-1))) (size-1)))
#define STATE_TYPE void* #define STATE_TYPE void*
typedef struct ir* NODEPTR_TYPE;
#define STATE_LABEL(p) ((p)->state_label) #define STATE_LABEL(p) ((p)->state_label)
#define OP_LABEL(p) ((p)->label)
#define LEFT_CHILD(p) ((p)->left)
#define RIGHT_CHILD(p) ((p)->right)
extern void* burm_label(struct ir* ir); struct burm_node
{
int label;
void* state_label;
struct burm_node* left;
struct burm_node* right;
struct ir* ir;
};
typedef struct burm_node* NODEPTR_TYPE;
extern void* burm_label(NODEPTR_TYPE node);
extern int burm_rule(void* state, int goalnt); extern int burm_rule(void* state, int goalnt);
extern const short *burm_nts[]; extern const short *burm_nts[];
extern struct ir** burm_kids(struct ir* p, int eruleno, struct ir* kids[]); extern NODEPTR_TYPE* burm_kids(NODEPTR_TYPE p, int eruleno, NODEPTR_TYPE kids[]);
extern void burm_trace(struct ir* p, int ruleno, int cost, int bestcost); extern void burm_trace(NODEPTR_TYPE p, int ruleno, int cost, int bestcost);
struct burm_emitter_data struct burm_emitter_data
{ {
void (*emit_string)(const char* data); void (*emit_string)(const char* data);
void (*emit_fragment)(struct ir* ir, int goal); void (*emit_fragment)(NODEPTR_TYPE node, int goal);
void (*emit_reg)(struct ir* ir, int goal); void (*emit_reg)(NODEPTR_TYPE node, int goal);
void (*emit_value)(struct ir* ir); void (*emit_value)(NODEPTR_TYPE node);
void (*emit_eoi)(void); void (*emit_eoi)(void);
void (*emit_constraint_equals)(struct ir* rightir, int rightgoal); void (*emit_constraint_equals)(NODEPTR_TYPE node, int goal);
}; };
typedef void burm_emitter_t(struct ir* ir, const struct burm_emitter_data* data); typedef void burm_emitter_t(NODEPTR_TYPE node, const struct burm_emitter_data* data);
struct burm_instruction_data struct burm_instruction_data
{ {