const char* lvalue;
struct basicblock* bvalue;
} u;
+
+ void* state_label; /* used by the iburg instruction selector */
+
bool is_sequence : 1;
+ bool is_generated : 1;
};
extern const char* ir_names[];
{
switch (k)
{
+ case 0: return true;
case 'E': return false;
case '0': return false;
- case '1': return true;
+ case '1': return false;
case '2': return true;
default: return true;
}
extern void pass_convert_stack_ops(struct procedure* proc);
extern void pass_remove_dead_blocks(struct procedure* proc);
extern void pass_eliminate_trivial_blocks(struct procedure* proc);
+extern void pass_instruction_selector(struct procedure* proc);
extern void procedure_compile(struct procedure* proc);
#endif
}
+#if 0
static NODEPTR_TYPE tree(int op, NODEPTR_TYPE l, NODEPTR_TYPE r) {
NODEPTR_TYPE p = malloc(sizeof *p);
dumpCover(p, 1, 0);
return 0;
}
+#endif
-#include <stdio.h>
-#include <assert.h>
-#include <stdlib.h>
-#include <stdbool.h>
-#include <limits.h>
-#include <stdlib.h>
+#include "mcg.h"
+#include "mcgg.h"
-#define TRACE
-#define STATE_TYPE void*
-typedef struct tree {
- int op;
- struct tree *kids[2];
- STATE_TYPE state_label;
-} *NODEPTR_TYPE;
-#define OP_LABEL(p) ((p)->op)
-#define LEFT_CHILD(p) ((p)->kids[0])
-#define RIGHT_CHILD(p) ((p)->kids[1])
-#define STATE_LABEL(p) ((p)->state_label)
#define PANIC printf
-static void burm_trace(NODEPTR_TYPE p, int eruleno, int cost, int bestcost) {
-#ifdef TRACE
- extern const char *burm_string[];
-
- fprintf(stderr, "0x%p matched %s with cost %d vs. %d\n", p,
- burm_string[eruleno], cost, bestcost);
-#endif
+static int OP_LABEL(struct ir* ir)
+{
+ if (ir->is_generated)
+ return ir_to_esn(IR_REG, ir->size);
+ return ir_to_esn(ir->opcode, ir->size);
}
-#define burm_assert(b, s) assert(b && s)
+#define LEFT_CHILD(p) ((p)->left)
+#define RIGHT_CHILD(p) ((p)->right)
+
+#define burm_assert(b, s) assert(b)
+
+extern void burm_panic_cannot_match(struct ir* ir);
--- /dev/null
+#include "mcg.h"
+#include "mcgg.h"
+
+#if 0
+static void dumpCover(NODEPTR_TYPE p, int goalnt, int indent) {
+#ifdef TRACE
+ int eruleno = burm_rule(STATE_LABEL(p), goalnt);
+ const short *nts = burm_nts[eruleno];
+ NODEPTR_TYPE kids[10];
+ int i;
+
+ for (i = 0; i < indent; i++)
+ fprintf(stderr, " ");
+ fprintf(stderr, "%s\n", burm_string[eruleno]);
+ burm_kids(p, eruleno, kids);
+ for (i = 0; nts[i]; i++)
+ {
+ if (kids[i])
+ dumpCover(kids[i], nts[i], indent + 1);
+ else
+ fprintf(stderr, "failed!\n");
+ }
+#endif
+}
+#endif
+
+void burm_trace(struct ir* p, int ruleno, int cost, int bestcost) {
+ tracef('I', "I: 0x%p matched %s with cost %d vs. %d\n", p,
+ burm_string[ruleno], cost, bestcost);
+}
+
+void burm_panic_cannot_match(struct ir* ir)
+{
+ fprintf(stderr, "could not find any patterns to match:\n");
+ ir_print(0, ir);
+ fprintf(stderr, "aborting!\n");
+ exit(1);
+}
+
+static void queue_instructions(struct ir* ir, int goal)
+{
+ struct ir* children[10];
+ int ruleno = burm_rule(ir->state_label, goal);
+ const short* nts = burm_nts[ruleno];
+ int i;
+
+ burm_kids(ir, ruleno, children);
+ for (i=0; nts[i]; i++)
+ queue_instructions(children[i], nts[i]);
+
+ printf("selected insn %d: %s\n", ruleno, burm_string[ruleno]);
+}
+
+static void select_instructions(struct basicblock* bb)
+{
+ int i;
+
+ tracef('I', "I: BLOCK: %s\n", bb->name);
+
+ for (i=0; i<bb->irs_count; i++)
+ {
+ int insnno;
+ struct ir* ir = bb->irs[i];
+ burm_label(ir);
+
+ insnno = burm_rule(ir->state_label, 1);
+ if (!insnno)
+ burm_panic_cannot_match(ir);
+
+ queue_instructions(ir, 1);
+ }
+}
+
+void pass_instruction_selector(struct procedure* proc)
+{
+ int i;
+
+ for (i=0; i<proc->blocks_count; i++)
+ {
+ struct basicblock* bb = proc->blocks[i];
+ select_instructions(bb);
+ }
+ exit(1);
+}
+
+/* vim: set sw=4 ts=4 expandtab : */
+
pass_convert_stack_ops(proc);
print_blocks('2', proc);
+
+ pass_instruction_selector(proc);
}
/* vim: set sw=4 ts=4 expandtab : */
PATTERNS
+/* Special */
+
+ reg;
+
+ PAIR(BLOCK4, BLOCK4);
+
+
+/* Miscellaneous special things */
+
+ PUSH4(in:reg)
+ emit "push %in"
+ cost 4;
+
+ reg = POP4
+ outs out:ANY
+ emit "pop %out"
+ cost 4;
+
+ RET
+ emit "ret"
+ cost 4;
+
+ SETRET4(in:reg)
+ emit "mov r0, %in"
+ cost 4;
+
+/* Memory operations */
+
STORE4(addr:address, value:reg)
ins value:GPR
emit "str %value, %addr"
reg = LOAD4(addr:address)
outs dest:ANY
- emit "ld %dest, %addr"
+ emit "ldr %dest, %addr"
+ cost 4;
+
+ reg = LOAD1(addr:address)
+ outs dest:ANY
+ emit "ldrb %dest, %addr"
+ cost 4;
+
+ reg = CIU14(LOAD1(addr:address))
+ outs dest:ANY
+ emit "ldrb %dest, %addr"
+ cost 4;
+
+
+/* Locals */
+
+ reg = in:LOCAL4
+ outs out:GPR
+ emit "add %out, fp, #%in.ivalue"
cost 4;
+ address = in:LOCAL4
+ fragment "[fp, #%in.ivalue]";
+
+
+/* Memory addressing modes */
+
address = ADD4(addr:reg, offset:CONST)
ins addr:GPR
fragment "[%addr, #%offset.ivalue]";
ins addr:GPR
fragment "[%addr]";
- reg;
+
+/* Branches */
+
+ JUMP(addr:BLOCK4)
+ emit "b %addr.bvalue"
+ cost 4;
+
+ CJUMPEQ(value:tristate, PAIR(true:BLOCK4, false:BLOCK4))
+ emit "beq %trueblock.bvalue"
+ emit "bne %falseblock.bvalue"
+ cost 8;
+
+
+/* Comparisons */
+
+ tristate = COMPARES4(val1:reg, val2:aluparam)
+ outs CC
+ emit "cmp %val1, %val2"
+ cost 4;
+
+ reg = tristate
+ emit "mov %out, #0"
+ emit "movlt %out, #-1"
+ emit "movgt %out, #1"
+ cost 12;
+
+
+/* Conversions */
+
+ reg = CII14(CIU41(value:reg))
+ outs out:GPR
+ emit "sxtb %out, %value"
+ cost 4;
+
+ reg = CIU41(in:reg)
+ outs out:GPR
+ emit "and %out, %in, #0xff"
+ cost 4;
+
+
+/* ALU operations */
reg = ADD4(left:reg, right:aluparam)
ins left:GPR, right:GPR
cost 4;
aluparam = value:CONST4
- when { return false; }
fragment "#%value.ivalue";
aluparam = reg;
reg = value:LABEL4
outs out:GPR
- emit "adr %out, #value.lvalue"
+ emit "adr %out, %value.lvalue"
+ cost 4;
+
+ reg = value:BLOCK4
+ outs out:GPR
+ emit "adr %out, %value.bvalue"
cost 4;
reg = value:CONST4
materialise_stack();
appendir(
new_ir2(
- IR_CJUMP, 0,
+ irop, 0,
new_ir2(
- irop, size,
+ IR_COMPARES, size,
left, right
),
new_ir2(
{
switch (opcode)
{
- case op_zeq: compare0_branch2(opcode, leftbb, rightbb, IR_IFEQ); break;
- case op_zlt: compare0_branch2(opcode, leftbb, rightbb, IR_IFLT); break;
- case op_zle: compare0_branch2(opcode, leftbb, rightbb, IR_IFLE); break;
+ case op_zeq: compare0_branch2(opcode, leftbb, rightbb, IR_CJUMPEQ); break;
+ case op_zlt: compare0_branch2(opcode, leftbb, rightbb, IR_CJUMPLT); break;
+ case op_zle: compare0_branch2(opcode, leftbb, rightbb, IR_CJUMPLE); break;
- case op_zne: compare0_branch2(opcode, rightbb, leftbb, IR_IFEQ); break;
- case op_zge: compare0_branch2(opcode, rightbb, leftbb, IR_IFLT); break;
- case op_zgt: compare0_branch2(opcode, rightbb, leftbb, IR_IFLE); break;
+ case op_zne: compare0_branch2(opcode, rightbb, leftbb, IR_CJUMPEQ); break;
+ case op_zge: compare0_branch2(opcode, rightbb, leftbb, IR_CJUMPLT); break;
+ case op_zgt: compare0_branch2(opcode, rightbb, leftbb, IR_CJUMPLE); break;
case op_bra:
{
matching(filenamesof("+ircodes"), "%.c$")
},
hdrs = {
- matching(filenamesof("+ircodes"), "%.h$")
+ matching(filenamesof("+ircodes"), "%.h$"),
+ "./mcgg.h"
}
}
matching(filenamesof("+yacc"), "%.c$")
},
deps = {
- "./*.h",
+ "./iburg.h",
"+lib",
"+yacc"
}
void printlineno(void)
{
- print("#line %d\n", yylineno);
+ //print("#line %d\n", yylineno);
}
/* reach - mark all non-terminals in tree t as reachable */
{
Rule r;
+ if (!p->rules)
+ return;
+
print("%1case %d: /* %S */\n", p->esn, p);
switch (p->arity)
{
for (p = terms; p; p = p->link)
emitcase(p, ntnumber);
print("%1default:\n"
- "%2%Passert(0, PANIC(\"Bad operator %%d in %Pstate\\n\", op));\n%1}\n"
+ "%2%Ppanic_cannot_match(node);\n"
+ "%1}\n"
"%1return (STATE_TYPE)p;\n}\n\n");
}
extern void printlineno(void);
-/* Excruciating macro which packs ir opcodes and sizes into an int for iburg's benefit.
- *
- * Sizes are mapped as: 0=1, 1=1, 2=2, 4=3, 8=4.
- */
-#define ir_to_esn(iropcode, size) \
- ((iropcode)*4 + \
- (((size) == 4) ? 2 : \
- ((size) == 8) ? 3 : \
- ((size) == 0) ? 0 : \
- (size-1)))
+#include "mcgg.h"
#endif
S REG
S LABEL
S BLOCK
-S PAIR
+V PAIR
S ANY
S LOCAL
S PHI
# Flow control --- these never return
V JUMP
-V CJUMP
+V CJUMPEQ
+V CJUMPLT
+V CJUMPLE
V RET
# Special
--- /dev/null
+#ifndef MCGG_H
+#define MCGG_H
+
+/* Excruciating macro which packs ir opcodes and sizes into an int for iburg's benefit.
+ *
+ * Sizes are mapped as: 0=1, 1=1, 2=2, 4=3, 8=4.
+ */
+#define ir_to_esn(iropcode, size) \
+ ((iropcode)*4 + \
+ (((size) == 4) ? 2 : \
+ ((size) == 8) ? 3 : \
+ ((size) == 0) ? 0 : \
+ (size-1)))
+
+
+#define STATE_TYPE void*
+typedef struct ir* NODEPTR_TYPE;
+
+#define STATE_LABEL(p) ((p)->state_label)
+
+extern void* burm_label(struct ir* ir);
+extern int burm_rule(void* state, int goalnt);
+extern const char* burm_string[];
+extern const short *burm_nts[];
+extern struct ir** burm_kids(struct ir* p, int eruleno, struct ir* kids[]);
+extern void burm_trace(struct ir* p, int ruleno, int cost, int bestcost);
+
+#endif
+
+/* vim: set sw=4 ts=4 expandtab : */
<ECHO>[^%\n]* fputs(yytext, outfp);
<INITIAL>"{" {
- yylval.string = stringf("#line %d\n", yylineno);
+ yylval.string = ""; //stringf("#line %d\n", yylineno);
braces = 1;
BEGIN(CSTRING);
return CFRAGMENT;