cvsuser 03/02/28 06:21:45
Modified: . .cvsignore MANIFEST jit.c packfile.c
config/gen/makefiles imcc.in
jit/i386 jit_emit.h
languages/imcc cfg.c cfg.h imc.c imcc.y instructions.c
instructions.h optimizer.c pbc.c pbc.h symreg.c
Added: languages/imcc jit.c
Log:
imcc-Oj-3 s. the announce on perl6-internals
Revision Changes Path
1.25 +2 -0 parrot/.cvsignore
Index: .cvsignore
===================================================================
RCS file: /cvs/public/parrot/.cvsignore,v
retrieving revision 1.24
retrieving revision 1.25
diff -u -w -r1.24 -r1.25
--- .cvsignore 5 Dec 2002 01:42:44 -0000 1.24
+++ .cvsignore 28 Feb 2003 14:21:38 -0000 1.25
@@ -2,6 +2,8 @@
config.opt
*_ops_cg.h
core_ops_cg.c
+*_ops_cgp.h
+core_ops_cgp.c
core_ops.c
core_ops_prederef.c
disassemble
1.319 +1 -0 parrot/MANIFEST
Index: MANIFEST
===================================================================
RCS file: /cvs/public/parrot/MANIFEST,v
retrieving revision 1.318
retrieving revision 1.319
diff -u -w -r1.318 -r1.319
--- MANIFEST 24 Feb 2003 06:58:37 -0000 1.318
+++ MANIFEST 28 Feb 2003 14:21:38 -0000 1.319
@@ -1389,6 +1389,7 @@
languages/imcc/imcparser.h
languages/imcc/instructions.c
languages/imcc/instructions.h
+languages/imcc/jit.c
languages/imcc/main.c
languages/imcc/optimizer.c
languages/imcc/optimizer.h
1.60 +119 -58 parrot/jit.c
Index: jit.c
===================================================================
RCS file: /cvs/public/parrot/jit.c,v
retrieving revision 1.59
retrieving revision 1.60
diff -u -w -r1.59 -r1.60
--- jit.c 25 Feb 2003 10:25:32 -0000 1.59
+++ jit.c 28 Feb 2003 14:21:38 -0000 1.60
@@ -1,13 +1,15 @@
/*
* jit.c
*
- * $Id: jit.c,v 1.59 2003/02/25 10:25:32 leo Exp $
+ * $Id: jit.c,v 1.60 2003/02/28 14:21:38 leo Exp $
*/
#include <parrot/parrot.h>
+#include <assert.h>
#include "parrot/jit.h"
#define JIT_EMIT 0
#include "parrot/jit_emit.h"
+#include "parrot/packfile.h"
/*
* s. jit/$arch/jit_emit.h for the meaning of these defs
@@ -52,7 +54,25 @@
void Parrot_jit_debug(struct Parrot_Interp* interpreter);
#endif
-/* #define JIT_IMCC_OJ */
+/* look at fixups, mark all fixup entries as branch target */
+static void
+insert_fixup_targets(struct Parrot_Interp* interpreter, char *branch,
+ size_t limit)
+{
+ struct PackFile_FixupTable *ft = interpreter->code->fixup_table;
+ int i;
+
+ if (!ft)
+ return;
+ for (i = 0; i < ft->fixup_count; i++) {
+ switch (ft->fixups[i]->type) {
+ case 0:
+ if ((size_t)ft->fixups[i]->u.t0.offset < limit)
+ branch[ft->fixups[i]->u.t0.offset] |= JIT_BRANCH_TARGET;
+ break;
+ }
+ }
+}
/*
* optimizer->map_branch parallels the opcodes with a list of
@@ -161,20 +181,7 @@
/* Move to the next opcode */
cur_op += op_info->arg_count;
}
- /* now look at fixups, mark all fixup entries as branch target */
- {
- struct PackFile_FixupTable *ft = interpreter->code->fixup_table;
- int i;
- if (!ft)
- return;
- for (i = 0; i < ft->fixup_count; i++) {
- switch (ft->fixups[i]->type) {
- case 0:
- branch[ft->fixups[i]->u.t0.offset] |= JIT_BRANCH_TARGET;
- break;
- }
- }
- }
+ insert_fixup_targets(interpreter, branch, code_end - code_start);
}
static void
@@ -200,10 +207,8 @@
case PARROT_ARG_I:
case PARROT_ARG_KI:
typ = 0;
-#ifdef JIT_IMCC_OJ
if (idx < 0)
idx = -1 - idx;
-#endif /* JIT_IMCC_OJ */
break;
case PARROT_ARG_P:
case PARROT_ARG_K:
@@ -213,10 +218,8 @@
typ = 2;
break;
case PARROT_ARG_N:
-#ifdef JIT_IMCC_OJ
if (idx < 0)
idx = -1 - idx;
-#endif /* JIT_IMCC_OJ */
typ = 3;
break;
default:
@@ -241,8 +244,11 @@
UINTVAL flags = PObj_get_FLAGS(key);
if (flags & KEY_register_FLAG) {
INTVAL n = key->cache.int_val;
- if (flags & KEY_integer_FLAG)
+ if (flags & KEY_integer_FLAG) {
typ = 0;
+ if (n < 0)
+ n = -1 - n;
+ }
else if (flags & KEY_pmc_FLAG)
typ = 1;
else if (flags & KEY_string_FLAG)
@@ -277,7 +283,7 @@
opcode_t *next_op;
op_info_t *op_info;
char *branch;
- int i, typ, branched, start_new;
+ int branched, start_new;
branch = optimizer->map_branch;
@@ -479,13 +485,6 @@
}
}
ru[typ].registers_used = k;
-#ifdef JIT_IMCC_OJ
- for (i = 0; i < to_map[typ]; i++) {
- ru[typ].reg_usage[i] = i;
- /* set rn1, N1 */
- }
- ru[typ].registers_used = to_map[typ];
-#endif /* JIT_IMCC_OJ */
}
next = cur_section->next;
prev = cur_section;
@@ -511,16 +510,13 @@
assign_registers(struct Parrot_Interp *interpreter,
Parrot_jit_optimizer_t *optimizer,
Parrot_jit_optimizer_section_ptr cur_section,
- opcode_t * code_start)
+ opcode_t * code_start, int from_imcc)
{
char *map;
op_info_t *op_info;
int i, op_arg, typ;
opcode_t * cur_op;
char * maps[] = {0, 0, 0, 0};
-#ifdef JIT_IMCC_OJ
- int to_map[] = { INT_REGISTERS_TO_MAP, 0, 0, FLOAT_REGISTERS_TO_MAP };
-#endif
maps[0] = intval_map;
maps[3] = floatval_map;
@@ -543,21 +539,18 @@
if (!maps[typ])
continue;
/* If the argument is in most used list for this typ */
-#ifndef JIT_IMCC_OJ
- for (i = 0; i < cur_section->ru[typ].registers_used; i++)
- if (cur_op[op_arg] ==
- (opcode_t)cur_section->ru[typ].reg_usage[i]) {
-#else /* JIT_IMCC_OJ */
- for (i = 0; i < to_map[typ]; i++)
- if (-1 - cur_op[op_arg] ==
- (opcode_t)cur_section->ru[typ].reg_usage[i]) {
-#endif /* JIT_IMCC_OJ */
+ for (i = 0; i < cur_section->ru[typ].registers_used; i++) {
+ opcode_t idx = cur_op[op_arg];
+ if (from_imcc)
+ idx = -1 - idx;
+ if (idx == (opcode_t)cur_section->ru[typ].reg_usage[i]) {
map[cur_op + op_arg - code_start] = maps[typ][i];
cur_section->maps++;
break;
}
}
}
+ }
/* Move to the next opcode */
cur_op += op_info->arg_count;
@@ -576,7 +569,7 @@
/* While there is section */
while (cur_section) {
- assign_registers(interpreter, optimizer, cur_section, code_start);
+ assign_registers(interpreter, optimizer, cur_section, code_start, 0);
/* Move to the next section */
cur_section = cur_section->next;
@@ -702,6 +695,69 @@
return optimizer;
}
+/* generate optimizer stuff from the _JIT section in the packfile */
+static Parrot_jit_optimizer_t *
+optimize_imcc_jit(struct Parrot_Interp *interpreter, opcode_t *cur_op,
+ opcode_t *code_start, opcode_t *code_end,
+ struct PackFile_Segment *jit_seg)
+{
+ Parrot_jit_optimizer_t *optimizer;
+ size_t size, i, typ;
+ int j;
+ opcode_t *ptr, offs;
+ Parrot_jit_optimizer_section_ptr section, prev;
+ char *branch;
+ op_info_t *op_info;
+
+ /* Allocate space for the optimizer */
+ optimizer = (Parrot_jit_optimizer_t *)
+ mem_sys_allocate_zeroed(sizeof(Parrot_jit_optimizer_t));
+ optimizer->map_branch = branch =
+ (char *)mem_sys_allocate_zeroed((size_t)(code_end - code_start));
+ ptr = jit_seg->data;
+ size = jit_seg->size;
+ assert(jit_seg->itype == 0);
+ assert((size % 6) == 0);
+ cur_op = code_start;
+ for (prev = NULL, i = 0; i < size/6; i++, prev = section) {
+ section = (Parrot_jit_optimizer_section_t *)
+ mem_sys_allocate_zeroed(sizeof(Parrot_jit_optimizer_section_t));
+ if (prev)
+ prev->next = section;
+ else
+ optimizer->sections = section;
+ section->prev = prev;
+ section->block = i;
+ offs = *ptr++;
+ if (offs & 0x80000000) {
+ offs &= ~0x80000000;
+ branch[offs] = JIT_BRANCH_TARGET;
+ }
+ section->begin = code_start + offs;
+ section->end = code_start + *ptr++;
+ section->isjit = 1;
+ for (typ = 0; typ < 4; typ++) {
+ section->ru[typ].registers_used = *ptr++;
+ for (j = 0; j < section->ru[typ].registers_used; j++)
+ section->ru[typ].reg_usage[j] = j;
+
+ }
+ while (cur_op <= section->end) {
+ op_info = &interpreter->op_info_table[*cur_op];
+ set_register_usage(interpreter, optimizer, section,
+ op_info, cur_op, code_start);
+ section->op_count++;
+ cur_op += op_info->arg_count;
+ }
+ assign_registers(interpreter, optimizer, section, code_start, 1);
+ }
+ insert_fixup_targets(interpreter, branch, code_end - code_start);
+#if JIT_DEBUG
+ debug_sections(interpreter, optimizer, code_start);
+#endif
+ return optimizer;
+}
+
static char *
reg_addr(struct Parrot_Interp * interpreter, int typ, int i)
{
@@ -830,6 +886,8 @@
Parrot_jit_info_t *jit_info = NULL;
opcode_t cur_opcode_byte, *cur_op;
Parrot_jit_optimizer_section_ptr cur_section;
+ struct PackFile_Segment *jit_seg;
+ char *name;
char *map;
@@ -842,7 +900,16 @@
jit_info = interpreter->jit_info =
mem_sys_allocate(sizeof(Parrot_jit_info_t));
- jit_info->optimizer = optimize_jit(interpreter, pc, code_start, code_end);
+ name = malloc(strlen(interpreter->code->cur_cs->base.name) + 5);
+ sprintf(name, "%s_JIT", interpreter->code->cur_cs->base.name);
+ jit_seg = PackFile_find_segment(interpreter->code, name);
+ free(name);
+ if (jit_seg)
+ jit_info->optimizer =
+ optimize_imcc_jit(interpreter, pc, code_start, code_end, jit_seg);
+ else
+ jit_info->optimizer =
+ optimize_jit(interpreter, pc, code_start, code_end);
/* Attach the register map to the jit_info structure */
jit_info->intval_map = intval_map;
@@ -899,11 +966,9 @@
cur_op = jit_info->cur_op = cur_section->begin;
/* Load mapped registers for this section, if JIT */
-#ifndef JIT_IMCC_OJ
- if (cur_section->isjit) {
+ if (!jit_seg && cur_section->isjit) {
Parrot_jit_load_registers(jit_info, interpreter);
}
-#endif /* JIT_IMCC_OJ */
/* The first opcode of each section doesn't have a previous one since
* it's impossible to be sure which was it */
@@ -935,14 +1000,12 @@
* and also, if we have a jitted sections and encounter
* and "end" opcode, e.g. in evaled code
*/
-#ifndef JIT_IMCC_OJ
if ((((map[cur_op - code_start] == JIT_BRANCH_SOURCE) &&
(cur_section->branch_target != cur_section)) ||
!cur_opcode_byte) &&
cur_section->isjit) {
Parrot_jit_save_registers(jit_info, interpreter);
}
-#endif /* JIT_IMCC_OJ */
/* Generate native code for current op */
(op_jit[cur_opcode_byte].fn) (jit_info, interpreter);
@@ -975,10 +1038,8 @@
}
/* Save mapped registers back to the Parrot registers */
-#ifndef JIT_IMCC_OJ
- if (cur_section->isjit)
+ if (!jit_seg && cur_section->isjit)
Parrot_jit_save_registers(jit_info, interpreter);
-#endif /* JIT_IMCC_OJ */
/* update the offset for saved registers */
jit_info->arena.op_map[jit_info->op_i].offset =
1.78 +3 -2 parrot/packfile.c
Index: packfile.c
===================================================================
RCS file: /cvs/public/parrot/packfile.c,v
retrieving revision 1.77
retrieving revision 1.78
diff -u -w -r1.77 -r1.78
--- packfile.c 18 Feb 2003 20:36:59 -0000 1.77
+++ packfile.c 28 Feb 2003 14:21:38 -0000 1.78
@@ -7,7 +7,7 @@
** This program is free software. It is subject to the same
** license as Parrot itself.
**
-** $Id: packfile.c,v 1.77 2003/02/18 20:36:59 leo Exp $
+** $Id: packfile.c,v 1.78 2003/02/28 14:21:38 leo Exp $
**
** History:
** Rework by Melvin; new bytecode format, make bytecode portable.
@@ -845,7 +845,8 @@
if (i % 8)
PIO_printf(interpreter, "\n %04x: ", (int) i);
- for ( ; i < self->file_offset+self->op_count; i++) {
+ for ( ; i < (self->size ? self->file_offset+self->size + 4 :
+ self->file_offset + self->op_count); i++) {
if (i % 8 == 0) {
PIO_printf(interpreter, "\n %04x: ", (int) i);
}
1.13 +1 -1 parrot/config/gen/makefiles/imcc.in
Index: imcc.in
===================================================================
RCS file: /cvs/public/parrot/config/gen/makefiles/imcc.in,v
retrieving revision 1.12
retrieving revision 1.13
diff -u -w -r1.12 -r1.13
--- imcc.in 8 Feb 2003 17:16:13 -0000 1.12
+++ imcc.in 28 Feb 2003 14:21:39 -0000 1.13
@@ -14,7 +14,7 @@
IMCC_O_FILES = imcparser$(O) imclexer$(O) imc$(O) stacks$(O) symreg$(O) \
instructions$(O) cfg$(O) sets$(O) debug$(O) \
- optimizer$(O) pbc$(O) main$(O) parser_util$(O)
+ optimizer$(O) pbc$(O) main$(O) parser_util$(O) jit$(O)
O_FILES = $(IMCC_O_FILES) \
1.58 +1 -5 parrot/jit/i386/jit_emit.h
Index: jit_emit.h
===================================================================
RCS file: /cvs/public/parrot/jit/i386/jit_emit.h,v
retrieving revision 1.57
retrieving revision 1.58
diff -u -w -r1.57 -r1.58
--- jit_emit.h 25 Feb 2003 10:25:38 -0000 1.57
+++ jit_emit.h 28 Feb 2003 14:21:41 -0000 1.58
@@ -3,7 +3,7 @@
*
* i386
*
- * $Id: jit_emit.h,v 1.57 2003/02/25 10:25:38 leo Exp $
+ * $Id: jit_emit.h,v 1.58 2003/02/28 14:21:41 leo Exp $
*/
#include <assert.h>
@@ -2714,10 +2714,6 @@
* set this to 1 or 0 to change allocation scheme
*/
# define ALLOCATE_REGISTERS_PER_SECTION 1
-
-#define MAP(i) OMAP(i)
-#undef MAP
-#define MAP(i) (i) >= 0 : 0 ? OMAP(i)
/*
1.21 +99 -73 parrot/languages/imcc/cfg.c
Index: cfg.c
===================================================================
RCS file: /cvs/public/parrot/languages/imcc/cfg.c,v
retrieving revision 1.20
retrieving revision 1.21
diff -u -w -r1.20 -r1.21
--- cfg.c 23 Feb 2003 20:21:09 -0000 1.20
+++ cfg.c 28 Feb 2003 14:21:43 -0000 1.21
@@ -14,13 +14,14 @@
* flow of execution between blocks.
*/
+static void add_instruc_reads(Instruction *ins, SymReg *r0);
/* Code: */
void find_basic_blocks () {
Basic_block *bb;
- Instruction *ins, *lab;
+ Instruction *ins;
int nu = 0;
int i;
@@ -29,7 +30,7 @@
for(i = 0; i < HASH_SIZE; i++) {
SymReg * r = hash[i];
if (r && (r->type & VTADDRESS)) {
- r->first_ins = r->last_ins = NULL;
+ r->last_ins = NULL;
}
}
@@ -37,11 +38,7 @@
ins->index = i = 0;
bb = make_basic_block(ins);
- if ( (ins->type & ITLABEL)) {
- /* set the labels address (ins) */
- ins->r[0]->first_ins = ins;
- }
- else if (ins->type & ITBRANCH) {
+ if (ins->type & ITBRANCH) {
SymReg * addr = get_branch_reg(bb->end);
if (addr)
addr->last_ins = ins;
@@ -51,6 +48,17 @@
bb->end = ins;
ins->bbindex = n_basic_blocks - 1;
+ /* invoke w/o arg implicitly uses P0, so mark it as doing so
+ * XXX but in the parser
+ */
+ if (ins->opsize == 1 && !strcmp(ins->op, "invoke")) {
+ SymReg * p0 = mk_pasm_reg(str_dup("P0"));
+ add_instruc_reads(ins, p0);
+ ins->type |= 1; /* mark branch register */
+ dont_optimize = 1; /* too complex, to follow */
+ optimizer_level &= ~OPT_PASM;
+ p0->use_count++;
+ }
/* a LABEL starts a new basic block, but not, if we have
* a new one (last was a branch) */
if ( (ins->type & ITLABEL)) {
@@ -60,6 +68,11 @@
if (nu)
nu = 0;
else if ( (ins->type & ITLABEL)) {
+ /* XXX look at this change bb->end did include the label,
+ * now no more
+ * s. t/rx/basic_6
+ */
+ bb->end = ins->prev;
bb = make_basic_block(ins);
}
/* a branch is the end of a basic block
@@ -77,28 +90,31 @@
if (!strcmp(ins->op, "bsr") || !strcmp(ins->op, "set_addr")) {
char *name =
*ins->op == 'b' ? ins->r[0]->name : ins->r[1]->name;
- found = 0;
- /* TODO get_sym */
- for (lab = instructions; lab; lab = lab->next) {
- if ((lab->type & ITLABEL) &&
- !strcmp(lab->r[0]->name, name)) {
- int j = 0;
- found = 1;
- /* XXX look if first 5 ins have saveall
- * this is a ugly but working hack ;-)
- */
- for (lab = lab->next; j < 5 && lab;
+ SymReg *r = get_sym(name);
+ if (*ins->op == 'b') {
+ Instruction * lab;
+ found = r != NULL && r->first_ins;
+ debug(DEBUG_CFG, "bsr %s local:%s\n",
+ name, found ? "yes": "no");
+ if (r) {
+ int j;
+ lab = r->first_ins;
+ if (lab)
+ for (j = 0, lab = lab->next; j < 5 && lab;
lab = lab->next, j++) {
if (!strcmp(lab->op, "saveall")) {
- found = 0;
+ ins->type |= ITSAVES;
+ lab->type |= ITSAVES;
+ debug(DEBUG_CFG, "\ttype saveall\n");
break;
}
}
- break;
}
}
- debug(DEBUG_CFG, "bsr %s local:%s\n",
- name, found ? "yes": "no");
+ else {
+ /* treat the set_addr as jump source */
+ found = 1;
+ }
}
if (found) {
if (ins->next)
@@ -120,7 +136,7 @@
void build_cfg() {
int i, j;
SymReg * addr;
- Basic_block *last, *bb;
+ Basic_block *last = NULL, *bb;
Edge *pred;
info(2, "build_cfg\n");
@@ -135,30 +151,47 @@
if (addr)
bb_findadd_edge(bb, addr);
if (!strcmp(bb->end->op, "ret")) {
+ int found = 0;
debug(DEBUG_CFG, "found ret in bb %d\n", i);
/* now go back, find labels and connect these with
* bsrs
*/
- for (pred = bb->pred_list; pred; pred=pred->pred_next) {
+ for (pred = bb->pred_list; pred; pred=pred->next) {
if (!strcmp(pred->from->end->op, "bsr")) {
+ Instruction * sub;
+
SymReg *r = pred->from->end->r[0];
- int found = 0;
j = pred->from->index;
- debug(DEBUG_CFG, "\tcalled from bb %d label '%s'? - ",
- j, r->name);
- if ((bb->start->type & ITLABEL) &&
- (!strcmp(bb->start->r[0]->name, r->name)))
+ sub = pred->to->start;
+ if ((sub->type & ITLABEL) &&
+ (!strcmp(sub->r[0]->name, r->name)))
found = 1;
if (found) {
- debug(DEBUG_CFG, "yep!\n");
+ int saves = 0;
+ debug(DEBUG_CFG, "\tcalled from bb %d '%s'\n",
+ j, ins_string(pred->from->end));
+ for (; sub && sub != bb->end; sub = sub->next) {
+ if (!strcmp(sub->op, "saveall"))
+ if (!(sub->type & ITSAVES)) {
+ break;
+ }
+ bb_list[sub->bbindex]->flag |= BB_IS_SUB;
+ if (!strcmp(sub->op, "restoreall")) {
+ sub->type |= ITSAVES;
+ saves = 1;
+ }
+ }
+ if (!saves)
bb_add_edge(bb, bb_list[j+1]);
+ debug(DEBUG_CFG, "\tand does saevall %s\n",
+ saves ? "yes" : "no");
+ break;
}
- else
- debug(DEBUG_CFG, "na!\n");
-
}
}
+ if (!found)
+ debug(DEBUG_CFG, "\tcalled from unknown!\n");
}
last = bb;
@@ -169,29 +202,23 @@
/* find the placement of the label, and link the two nodes */
void bb_findadd_edge(Basic_block *from, SymReg *label) {
-#if 0
- /* ugly slow quadratic search for a label takes ~35 s for
- * ../../t/op/stacks_33
- */
Instruction *ins;
-
- for (ins = instructions; ins; ins = ins->next) {
- if ((ins->type & ITLABEL) && label == ins->r[0]){
-
- bb_add_edge(from, bb_list[ins->bbindex]);
- return;
-
- /* a label appears just once */
-
- }
- }
-#else
- SymReg *r = get_sym(label->name);
+ SymReg *r = find_sym(label->name);
if (r && (r->type & VTADDRESS) && r->first_ins)
bb_add_edge(from, bb_list[r->first_ins->bbindex]);
-
-#endif
+ else {
+ debug(DEBUG_CFG, "register branch %s ",
+ ins_string(from->end));
+ for (ins = from->end; ins; ins = ins->prev) {
+ if ((ins->type & ITBRANCH) && !strcmp(ins->op, "set_addr")) {
+ bb_add_edge(from, bb_list[ins->r[1]->first_ins->bbindex]);
+ debug(DEBUG_CFG, "(%s) ", ins->r[1]->name);
+ break;
+ }
+ }
+ debug(DEBUG_CFG, "\n");
+ }
}
@@ -310,12 +337,6 @@
ins = curr;
}
}
- /* invoke w/o arg implicitly uses P0, so mark it as doing so */
- else if (ins->opsize == 1 && !strcmp(ins->op, "invoke")) {
- SymReg * p0 = mk_pasm_reg(str_dup("P0"));
- add_instruc_reads(ins, p0);
- p0->use_count++;
- }
}
if (IMCC_DEBUG & DEBUG_CFG) {
debug(DEBUG_CFG, "\nAfter propagate_alias\n");
@@ -367,11 +388,14 @@
void free_life_info(SymReg *r)
{
int i;
+ if (r->life_info) {
for (i=0; i < n_basic_blocks; i++) {
if (r->life_info[i])
free(r->life_info[i]);
}
free(r->life_info);
+ r->life_info = NULL;
+ }
}
/* analyse_life_block studies the state of the var r
@@ -569,7 +593,7 @@
* order of finding loops
*/
for (i = 0; i < n_loops-1; i++) {
- int first = -1, last;
+ int first = -1, last = 0;
loop_info[i]->depth = 1;
/* we could also take the depth of the first contained
* block, but below is a check, that a inner loop is fully
@@ -730,10 +754,12 @@
void clear_basic_blocks() {
int i;
+ if (bb_list) {
for (i=0; i < n_basic_blocks; i++)
free(bb_list[i]);
free(bb_list);
bb_list = NULL;
+ }
free_edge();
free_dominators();
free_loops();
1.7 +5 -0 parrot/languages/imcc/cfg.h
Index: cfg.h
===================================================================
RCS file: /cvs/public/parrot/languages/imcc/cfg.h,v
retrieving revision 1.6
retrieving revision 1.7
diff -u -w -r1.6 -r1.7
--- cfg.h 22 Dec 2002 17:23:04 -0000 1.6
+++ cfg.h 28 Feb 2003 14:21:43 -0000 1.7
@@ -19,7 +19,12 @@
Edge *succ_list;
int loop_depth;
int index; /*on bb_list*/
+ int flag;
} Basic_block;
+
+enum {
+ BB_IS_SUB = 1 << 0
+} block_enum_flags;
/* Globals: */
EXTERN Basic_block **bb_list;
1.41 +50 -208 parrot/languages/imcc/imc.c
Index: imc.c
===================================================================
RCS file: /cvs/public/parrot/languages/imcc/imc.c,v
retrieving revision 1.40
retrieving revision 1.41
diff -u -w -r1.40 -r1.41
--- imc.c 25 Feb 2003 10:25:45 -0000 1.40
+++ imc.c 28 Feb 2003 14:21:43 -0000 1.41
@@ -15,14 +15,10 @@
#include <assert.h>
#include "imc.h"
#include "optimizer.h"
-#define JIT_IMCC
-#include "parrot/jit.h"
-#include "parrot/jit_emit.h"
static void make_stat(int *sets, int *cols);
static void imc_stat_init(void);
static void print_stat(void);
-static void allocate_jit(struct Parrot_Interp *interpreter);
extern int pasm_file;
/* Globals: */
@@ -54,7 +50,7 @@
return;
nodeStack = imcstack_new();
- dont_optimize = n_spilled = 0;
+ n_spilled = 0;
todo = first = 1;
while (todo) {
@@ -115,15 +111,8 @@
}
if (IMCC_DEBUG & DEBUG_IMC)
dump_instructions();
- if (optimizer_level & OPT_J) {
- allocate_jit(interpreter);
- if (IMCC_DEBUG & DEBUG_IMC)
- dump_instructions();
- }
if (IMCC_VERBOSE > 1 || (IMCC_DEBUG & DEBUG_IMC))
print_stat();
- free_reglist();
- clear_basic_blocks(); /* and cfg ... */
imcstack_free(nodeStack);
}
@@ -133,8 +122,12 @@
interference_graph = 0;
}
if (reglist) {
+ int i;
+ for (i = 0; i < n_symbols; i++)
+ free_life_info(reglist[i]);
free(reglist);
- reglist = 0;
+ reglist = NULL;
+ n_symbols = 0;
}
}
@@ -274,8 +267,11 @@
* same time
*/
-void build_interference_graph() {
+void
+build_interference_graph()
+{
int x, y;
+
if (!n_symbols)
return;
@@ -463,15 +459,36 @@
l0 = r0->life_info[i];
l1 = r1->life_info[i];
+ /* one or both are not alive in this block, so we have
+ * no conflict
+ */
if (!l0->first_ins || !l1->first_ins)
continue;
+ /* if the registers don't overlap, i.e first_x > last_y
+ * then no interference
+ */
if (l0->first_ins->index > l1->last_ins->index)
continue;
-
if (l1->first_ins->index > l0->last_ins->index)
continue;
+#if 1
+ /* if they only overlap one instruction and one is used RHS only
+ * and the other LHS, then that's ok
+ */
+ if (l0->first_ins->index == l1->last_ins->index &&
+ instruction_writes(l0->first_ins, r0) &&
+ instruction_reads(l1->last_ins, r1) &&
+ !instruction_reads(l0->first_ins, r0))
+ continue;
+ if (l1->first_ins->index == l0->last_ins->index &&
+ instruction_writes(l1->first_ins, r1) &&
+ instruction_reads(l0->last_ins, r0) &&
+ !instruction_reads(l1->first_ins, r1))
+ continue;
+#endif
+
return 1;
}
@@ -529,7 +546,7 @@
*/
void order_spilling () {
- int min_score, total_score;
+ int min_score = 0, total_score;
int min_node;
int x;
@@ -763,181 +780,6 @@
return cnt;
}
-
-/* PASM registers are already in most used order, so now:
- * - consider the top N registers as processor registers
- * - look at the instruction stream and insert register load/store ins
- * for e.g. calling out to unJITted functions
- * This is of course processor dependend
- *
- * NOTE: rx_ ops may have a inout INT parameter for position/mark.
- * Actually, the either branch or update the inout parameter
- * so they are save.
- */
-
-#ifndef EXTCALL
-# define EXTCALL(op) op_jit[*(op)].extcall
-#endif
-
-#ifndef INT_REGISTERS_TO_MAP
-# define INT_REGISTERS_TO_MAP 0
-#endif
-
-#ifndef FLOAT_REGISTERS_TO_MAP
-# define FLOAT_REGISTERS_TO_MAP 0
-#endif
-
-#ifndef PRESERVED_INT_REGS
-# define PRESERVED_INT_REGS MAX_MAPPED
-#endif
-
-#ifndef PRESERVED_FLOAT_REGS
-# define PRESERVED_FLOAT_REGS MAX_MAPPED
-#endif
-
-static void
-allocate_jit(struct Parrot_Interp *interpreter)
-{
- int c, j, k, typ;
- int to_map[4] = {0,0,0,0};
-#define MAX_MAPPED 32
- int preserved[] =
- {PRESERVED_INT_REGS, MAX_MAPPED, MAX_MAPPED, PRESERVED_FLOAT_REGS};
- const char *types = "IPSN";
- Instruction * ins, *last, *tmp, *prev;
- SymReg * r;
- SymReg * regs[IMCC_MAX_REGS];
- static SymReg *cpu[4][MAX_MAPPED];
- static SymReg *par[4][MAX_MAPPED];
- int reads[4][MAX_MAPPED], writes[4][MAX_MAPPED], nr, nw;
- int maxc[4] = {0,0,0,0};
-
- assert(INT_REGISTERS_TO_MAP < MAX_MAPPED);
- assert(FLOAT_REGISTERS_TO_MAP < MAX_MAPPED);
- to_map[0] = INT_REGISTERS_TO_MAP;
- to_map[3] = FLOAT_REGISTERS_TO_MAP;
- /* make a list of mapped cpu regs */
- if (cpu[0][0] == NULL) {
- for (typ = 0; typ < 4; typ++)
- for (k = 0; k < to_map[typ]; k++) {
- char name[16];
- sprintf(name, "%c%d#c", types[typ], k);
- cpu[typ][k] = mk_pasm_reg(str_dup(name));
- cpu[typ][k]->color = -1 - k;
- sprintf(name, "%c%d#p", types[typ], k);
- par[typ][k] = mk_pasm_reg(str_dup(name));
- }
- }
- prev = last = NULL;
- nr = nw = 0;
- /* change all mappable registers to mapped ones */
- for (j = 0; j < n_symbols; j++) {
- r = reglist[j];
- typ = strchr(types, r->set) - types;
- if (r->color < to_map[typ]) {
- if (r->color >= maxc[typ])
- maxc[typ] = r->color + 1;
- r->color = -1 - r->color;
- }
-
- }
- to_map[0] = maxc[0];
- to_map[3] = maxc[3];
- /* clear all used regs at beginning */
- for (typ = 0; typ < 4; typ++)
- for (j = 0; j < to_map[typ]; j++) {
- regs[0] = cpu[typ][j];
- regs[1] = par[typ][j];
- tmp = INS(interpreter, "set", "%s, %s\t# init",
- regs, 2, 0, 0);
- insert_ins(NULL, tmp);
- }
- /* TODO restore regs before end if non main */
- for (ins = instructions; ins; prev = ins, ins = ins->next) {
- /* clear preserved regs, set rw of non preserved regs */
- for (typ = 0; ins != instructions && typ < 4; typ++)
- for (k = 0; k < to_map[typ]; k++) {
- reads[typ][k] = writes[typ][k] =
- k >= preserved[typ];
- }
- /* if extern, go through regs and check the usage */
- if (ins->opnum >= 0 && EXTCALL(&ins->opnum)) {
- nr = nw = 1;
- /* TODO stop at basic block end */
- for (last = ins; ins && ins->opnum >= 0 && EXTCALL(&ins->opnum);
- ins = ins->next) {
- ins->type |= ITEXT;
- for (j = 0; j < n_symbols; j++) {
- r = reglist[j];
- if (r->color >= 0)
- continue;
- typ = strchr(types, r->set) - types;
- c = -1 - r->color;
- if (instruction_reads(ins, r) &&
- instruction_writes(ins, r)) {
- reads[typ][c] = 1;
- writes[typ][c] = 1;
- nr = nw = 1;
- }
- else if (instruction_reads(ins, r)) {
- reads[typ][c] = 1;
- nr = 1;
- }
- else if (instruction_writes(ins, r)) {
- writes[typ][c] = 1;
- nw = 1;
- }
- }
- /* changed mapped regs to parrot regs */
- for (j = 0; (r = ins->r[j]) && j < IMCC_MAX_REGS; j++) {
- typ = strchr(types, r->set) - types;
- if ((r->type & VTREGISTER) && r->color < 0)
- ins->r[j] = par[typ][-1 - r->color];
- }
- /* remember last extern opcode, all loads are inserted
- * after this instruction
- */
- last = ins;
- if (ins->type & ITBRANCH) {
- break;
- }
- }
- }
- /* insert load ins after non JIT block */
- if (last && nw) {
- for (typ = 0; typ < 4; typ++)
- for (j = 0; j < to_map[typ]; j++) {
- if (!writes[typ][j])
- continue;
- regs[0] = cpu[typ][j];
- regs[1] = par[typ][j];
- tmp = INS(interpreter, "set", "%s, %s\t# load",
- regs, 2, 0, 0);
- insert_ins(last, tmp);
- }
- nw = 0;
- }
- /* insert save ins before extern op */
- if (nr) {
- for (typ = 0; typ < 4; typ++)
- for (j = 0; j < to_map[typ]; j++) {
- if (!reads[typ][j])
- continue;
- regs[0] = par[typ][j];
- regs[1] = cpu[typ][j];
- tmp = INS(interpreter, "set", "%s, %s\t# save",
- regs, 2, 0, 0);
- insert_ins(prev, tmp);
- }
- nr = 0;
- }
- /* continue with/after last non JIT ins */
- if (last)
- ins = last;
- last = NULL;
- }
-}
-
/*
* Utility functions
*/
1.50 +6 -0 parrot/languages/imcc/imcc.y
Index: imcc.y
===================================================================
RCS file: /cvs/public/parrot/languages/imcc/imcc.y,v
retrieving revision 1.49
retrieving revision 1.50
diff -u -w -r1.49 -r1.50
--- imcc.y 25 Feb 2003 10:25:45 -0000 1.49
+++ imcc.y 28 Feb 2003 14:21:43 -0000 1.50
@@ -121,6 +121,7 @@
static Instruction * iLABEL(SymReg * r0) {
Instruction *i = _mk_instruction("","%s:", R1(r0), 0);
i->type = ITLABEL;
+ r0->first_ins = i;
i = emitb(i);
clear_state();
return i;
@@ -356,6 +357,11 @@
ins->type = ITBRANCH | (1 << (nargs-1));
if (!strcmp(name, "branch") || !strcmp(name, "end"))
ins->type |= IF_goto;
+ if (!strcmp(fullname, "jump_i") ||
+ !strcmp(fullname, "jsr_i") ||
+ !strcmp(fullname, "branch_i") ||
+ !strcmp(fullname, "bsr_i"))
+ dont_optimize = 1;
}
}
else if (!strcmp(name, "set") && nargs == 2) {
1.30 +22 -10 parrot/languages/imcc/instructions.c
Index: instructions.c
===================================================================
RCS file: /cvs/public/parrot/languages/imcc/instructions.c,v
retrieving revision 1.29
retrieving revision 1.30
diff -u -w -r1.29 -r1.30
--- instructions.c 25 Feb 2003 10:25:45 -0000 1.29
+++ instructions.c 28 Feb 2003 14:21:43 -0000 1.30
@@ -62,14 +62,17 @@
void
close_comp_unit(void)
{
+ free_reglist();
+ clear_basic_blocks(); /* and cfg ... */
if (!n_comp_units)
fatal(1, "close_comp_unit", "non existent comp_unit\n");
n_comp_units--;
instructions = comp_unit[n_comp_units].instructions;
last_ins = comp_unit[n_comp_units].last_ins;
clear_tables();
- free(comp_unit[n_comp_units].hash[0]);
if (n_comp_units) {
+ free(comp_unit[n_comp_units].hash[0]);
+ comp_unit[n_comp_units].hash[0] = NULL;
hash = comp_unit[n_comp_units-1].hash[0];
}
else {
@@ -98,7 +101,7 @@
new->type |= VT_REGP;
new->reg = p;
/* link in both dirs, so that usage can be determined */
- p->reg = new;
+ /* p->reg = new; */
debug(DEBUG_LEXER, "found outer scope sym '%s'\n",
p->name);
return new;
@@ -158,7 +161,6 @@
};
const char *writes[] = {
"restoreall",
- "pushi", "pushn", "pushp", "pushs",
"popi", "popn", "popp", "pops",
"cleari", "clearn", "clearp", "clears",
};
@@ -217,18 +219,24 @@
int instruction_reads(Instruction* ins, SymReg* r) {
int f, i;
SymReg *key;
+ SymReg *ri;
f = ins->flags;
- for (i = 0; ins->r[i] && i < IMCC_MAX_REGS; i++)
+ for (i = 0; (ri = ins->r[i]) && i < IMCC_MAX_REGS; i++) {
if (f & (1<<i)) {
- if (ins->r[i] == r)
+ if (ri == r)
return 1;
- if ((ins->r[i]->type & VT_REGP) && ins->r[i]->reg == r)
+ if ((ri->type & VT_REGP) && ri->reg == r)
return 1;
- for (key = ins->r[i]->nextkey; key; key = key->nextkey)
+ /* this additional test for _kc ops seems to slow
+ * down instruction_reads by a huge amount compared to the
+ * _writes below
+ */
+ for (key = ri->nextkey; key; key = key->nextkey)
if (key->reg && key->reg == r)
return 1;
}
+ }
return 0;
}
@@ -313,6 +321,7 @@
ins->next = tmp;
tmp->prev = ins;
tmp->next = next;
+ if (next)
next->prev = tmp;
if (!tmp->line)
tmp->line = ins->line;
@@ -491,8 +500,8 @@
}
Emitter emitters[2] = {
- {e_file_open, e_file_emit, e_file_close},
- {e_pbc_open, e_pbc_emit, e_pbc_close},
+ {e_file_open, e_file_emit, (int (*)(void *))NULLfunc, e_file_close},
+ {e_pbc_open, e_pbc_emit, e_pbc_new_sub, e_pbc_close},
};
static int emitter;
@@ -501,6 +510,7 @@
{
emitter = type;
has_compile = 0;
+ dont_optimize = 0;
return (emitters[emitter]).open(param);
return 0;
}
@@ -526,6 +536,8 @@
spill_ins = iNEW(interpreter, p31, str_dup("PerlArray"), 0);
insert_ins(ins, spill_ins);
}
+ if (emitters[emitter].new_sub)
+ (emitters[emitter]).new_sub(param);
for (ins = instructions; ins; ins = ins->next) {
(emitters[emitter]).emit(param, ins);
}
1.20 +3 -1 parrot/languages/imcc/instructions.h
Index: instructions.h
===================================================================
RCS file: /cvs/public/parrot/languages/imcc/instructions.h,v
retrieving revision 1.19
retrieving revision 1.20
diff -u -w -r1.19 -r1.20
--- instructions.h 25 Feb 2003 10:25:45 -0000 1.19
+++ instructions.h 28 Feb 2003 14:21:43 -0000 1.20
@@ -9,7 +9,8 @@
ITALIAS = 0x100000, /* set P,P */
ITADDR = 0x200000, /* set_addr P, addr*/
ITSPILL = 0x400000, /* set P31,x ; set x, p31 spilling */
- ITEXT = 0x800000 /* instruction is extcall in JIT */
+ ITEXT = 0x800000, /* instruction is extcall in JIT */
+ ITSAVES = 0x1000000 /* saveall/restoreall in a bsr */
};
@@ -103,6 +104,7 @@
typedef struct _emittert {
int (*open)(void *param);
int (*emit)(void *param, Instruction *ins);
+ int (*new_sub)(void *param);
int (*close)(void *param);
} Emitter;
1.22 +7 -3 parrot/languages/imcc/optimizer.c
Index: optimizer.c
===================================================================
RCS file: /cvs/public/parrot/languages/imcc/optimizer.c,v
retrieving revision 1.21
retrieving revision 1.22
diff -u -w -r1.21 -r1.22
--- optimizer.c 23 Feb 2003 13:17:34 -0000 1.21
+++ optimizer.c 28 Feb 2003 14:21:43 -0000 1.22
@@ -70,12 +70,15 @@
subst_constants_c(interp);
subst_constants_if(interp);
strength_reduce(interp);
+ if (!dont_optimize)
if_branch(interp);
}
}
int cfg_optimize(struct Parrot_Interp *interp) {
UNUSED(interp);
+ if (dont_optimize)
+ return 0;
if (optimizer_level & OPT_PRE) {
info(2, "cfg_optimize\n");
if (branch_branch())
@@ -1004,7 +1007,7 @@
is_invariant(Instruction *ins)
{
int ok = 0;
- int what;
+ int what = 0;
if (! strcmp(ins->op, "new") &&
!strcmp(ins->r[1]->name, "PerlUndef")) {
ok = 1;
@@ -1022,6 +1025,7 @@
return 0;
}
+#define MOVE_INS_1_BL
#ifdef MOVE_INS_1_BL
static Basic_block *
find_outer(Basic_block * blk)
@@ -1057,7 +1061,7 @@
debug(DEBUG_OPT2, "outer loop not found (CFG?)\n");
return 0;
}
- out = pred->end->prev;
+ out = pred->end;
next = (*ins)->next;
(*ins)->bbindex = pred->index;
debug(DEBUG_OPT2, "inserting it in blk %d after %s\n", pred->index,
1.29 +65 -4 parrot/languages/imcc/pbc.c
Index: pbc.c
===================================================================
RCS file: /cvs/public/parrot/languages/imcc/pbc.c,v
retrieving revision 1.28
retrieving revision 1.29
diff -u -w -r1.28 -r1.29
--- pbc.c 21 Feb 2003 12:26:40 -0000 1.28
+++ pbc.c 28 Feb 2003 14:21:43 -0000 1.29
@@ -41,6 +41,7 @@
struct subs {
size_t size; /* code size in ops */
int ins_line; /* line# for debug */
+ int n_basic_blocks; /* block count */
SymReg * labels[HASH_SIZE]; /* label names */
SymReg * bsrs[HASH_SIZE]; /* bsr, set_addr locations */
struct subs *prev;
@@ -50,6 +51,7 @@
/* subs are kept per code segment */
struct cs_t {
struct PackFile_ByteCode *seg; /* bytecode seg */
+ struct PackFile_Segment *jit_info; /* bblocks, register usage */
struct subs *subs; /* current sub data */
struct subs *first; /* first sub of code seg */
struct cs_t *prev; /* prev cs */
@@ -114,6 +116,7 @@
cs->next = NULL;
cs->subs = NULL;
cs->first = NULL;
+ cs->jit_info = NULL;
if (!globals.first)
globals.first = cs;
else
@@ -123,8 +126,46 @@
return 0;
}
+/* get size/line of bytecode in ops till now */
+static int
+old_blocks(void)
+{
+ size_t size;
+ struct subs *s;
+
+ size = 0;
+ for (s = globals.cs->subs; s; s = s->prev) {
+ size += s->n_basic_blocks;
+ }
+ return size;
+}
+
+opcode_t *
+make_jit_info(struct Parrot_Interp *interpreter)
+{
+ char *name;
+ size_t size, old;
+
+ if (!globals.cs->jit_info) {
+ name = malloc(strlen(globals.cs->seg->base.name) + 5);
+ sprintf(name, "%s_JIT", globals.cs->seg->base.name);
+ globals.cs->jit_info =
+ PackFile_Segment_new_seg(interpreter->code, PF_UNKNOWN_SEG, name, 1);
+ free(name);
+ }
+ size = n_basic_blocks + (old = old_blocks());
+ /* store current size */
+ globals.cs->subs->n_basic_blocks = n_basic_blocks;
+ /* offset of block start and end, 4 * registers_used */
+ globals.cs->jit_info->data = realloc(globals.cs->jit_info->data,
+ size * sizeof(opcode_t) * 6);
+ globals.cs->jit_info->size = size * 6;
+ return globals.cs->jit_info->data + old * 6;
+}
+
/* allocate a new globals.cs->subs structure */
-static void make_new_sub(void)
+static void
+make_new_sub(struct Parrot_Interp *interpreter)
{
struct subs *s = mem_sys_allocate_zeroed(sizeof(struct subs));
if (!s)
@@ -136,6 +177,9 @@
if (!globals.cs->first)
globals.cs->first = s;
globals.cs->subs = s;
+ if ((optimizer_level & OPT_J)) {
+ allocate_jit(interpreter);
+ }
}
@@ -291,6 +335,8 @@
/* XXX labels should be mangled with current subroutine name
* they should only be reachable from eval's in current sub
*/
+ debug(DEBUG_PBC_FIXUP, "write fixup '%s' offs %d\n",
+ ins->r[0]->name, ins->r[0]->color + oldsize);
PackFile_FixupTable_new_entry_t0(interpreter,
ins->r[0]->name, ins->r[0]->color + oldsize);
}
@@ -568,6 +614,10 @@
*pc++ = PARROT_ARG_S;
else
fatal(1, "build_key", "wrong register set\n");
+ /* don't emit mapped regs in key parts */
+ if (r->color < 0)
+ *pc++ = -1 - r->color;
+ else
*pc++ = r->color;
sprintf(s+strlen(s), "%c%d", r->set, r->color);
debug(DEBUG_PBC_CONST, " keypart reg %s %c%d\n",
@@ -664,12 +714,24 @@
}
}
+int
+e_pbc_new_sub(void *param)
+{
+ struct Parrot_Interp *interpreter = (struct Parrot_Interp *)param;
+
+ if (!instructions)
+ return 0;
+ make_new_sub(interpreter); /* we start a new compilation unit */
+ return 0;
+}
/*
* now let the fun begin, actually emit code for one ins
*/
-int e_pbc_emit(void *param, Instruction * ins) {
+int
+e_pbc_emit(void *param, Instruction * ins)
+{
struct Parrot_Interp *interpreter = (struct Parrot_Interp *)param;
int ok = 0;
static opcode_t * pc, npc;
@@ -684,7 +746,6 @@
int oldsize;
int bytes;
- make_new_sub(); /* we start a new compilation unit */
oldsize = get_old_size(interpreter, &ins_line);
code_size = store_labels(interpreter, &ins_size, oldsize);
debug(DEBUG_PBC, "code_size(ops) %d oldsize %d\n", code_size, oldsize);
1.4 +3 -0 parrot/languages/imcc/pbc.h
Index: pbc.h
===================================================================
RCS file: /cvs/public/parrot/languages/imcc/pbc.h,v
retrieving revision 1.3
retrieving revision 1.4
diff -u -w -r1.3 -r1.4
--- pbc.h 31 Jan 2003 10:54:08 -0000 1.3
+++ pbc.h 28 Feb 2003 14:21:43 -0000 1.4
@@ -3,7 +3,10 @@
int e_pbc_open(void *);
int e_pbc_emit(void *, Instruction * ins);
+int e_pbc_new_sub(void *);
int e_pbc_close(void *);
void fixup_bsrs(struct Parrot_Interp *interpreter);
+void allocate_jit(struct Parrot_Interp *interpreter);
+opcode_t * make_jit_info(struct Parrot_Interp *interpreter);
#endif
1.17 +5 -0 parrot/languages/imcc/symreg.c
Index: symreg.c
===================================================================
RCS file: /cvs/public/parrot/languages/imcc/symreg.c,v
retrieving revision 1.16
retrieving revision 1.17
diff -u -w -r1.16 -r1.17
--- symreg.c 17 Feb 2003 15:10:52 -0000 1.16
+++ symreg.c 28 Feb 2003 14:21:43 -0000 1.17
@@ -345,6 +345,11 @@
}
hash[i] = NULL;
}
+ for(i = 0; i < HASH_SIZE; i++) {
+ for(p = ghash[i]; p; p = p->next)
+ if (p->type & VTADDRESS)
+ p->first_ins = p->last_ins = NULL;
+ }
}
/* utility functions: */
1.1 parrot/languages/imcc/jit.c
Index: jit.c
===================================================================
/* imcc JIT optimizer
*
* This is a totally experimental hack to demonstrate, that we can
* ran faster then -O3 compiled C (primes.pasm).
* But it's incomplete and buggy - albeit it runs all parrot tests.
*
* The main problem is the incomplete CFG, mainly WRT subroutines
* and the effects of saveall/restorall and such.
* Further too many registers are saved/restored: rebuilding the
* bb_list is done to get bb->start/end for jit_info, but then
* life_info maybe out of sync and so all mapped get saved.
*
* NOTE: -Oj should always be used with branch/label optimization
* as -O1j. It needs a correct CFG, without nul blocks:
* e.g. t/op/basic_13.pasm
*
*/
#include <string.h>
#include <assert.h>
#include "imc.h"
#include "pbc.h"
#define JIT_IMCC
#include "parrot/jit.h"
#include "parrot/jit_emit.h"
/* PASM registers are already in most used order, so now:
* - consider the top N registers as processor registers
* - look at the instruction stream and insert register load/store ins
* for e.g. calling out to unJITted functions
* This is of course processor dependend
*
* NOTE: rx_ ops may have a inout INT parameter for position/mark.
* Actually, the either branch or update the inout parameter
* so they are save.
*/
#ifndef EXTCALL
# define EXTCALL(op) op_jit[*(op)].extcall
#endif
#ifndef INT_REGISTERS_TO_MAP
# define INT_REGISTERS_TO_MAP 0
#endif
#ifndef FLOAT_REGISTERS_TO_MAP
# define FLOAT_REGISTERS_TO_MAP 0
#endif
#ifndef PRESERVED_INT_REGS
# define PRESERVED_INT_REGS MAX_MAPPED
#endif
#ifndef PRESERVED_FLOAT_REGS
# define PRESERVED_FLOAT_REGS MAX_MAPPED
#endif
/*
* check life range of all symbols, find the max used mapped
*/
static int
max_used(int bbi, char t, int typ, int mapped[])
{
int max, j, c;
for (j = 0, max = 0; j < n_symbols; j++) {
SymReg * r = reglist[j];
if (r->set != t)
continue;
c = -1 - r->color;
if (c < mapped[typ]) {
Life_range *l = r->life_info[bbi];
if (l->first_ins && c >= max)
max = c + 1;
}
}
return max;
}
/* check life range of all symbols, which have
* colors >= preserved and are mapped
* if none found, don't emit load/store for preserved regs
*/
static int
min_used(int bbi, char t, int typ, int preserved[], int mapped[])
{
int max, j, c;
for (j = 0, max = mapped[typ]; j < n_symbols; j++) {
SymReg * r = reglist[j];
if (r->set != t)
continue;
c = -1 - r->color;
if (c >= preserved[typ] && c < mapped[typ]) {
Life_range *l = r->life_info[bbi];
if (l->first_ins && c < max)
max = c;
}
}
return max;
}
void
allocate_jit(struct Parrot_Interp *interpreter)
{
int c, i, j, k, typ;
int to_map[4] = {0,0,0,0};
#define MAX_MAPPED 32
int preserved[] =
{PRESERVED_INT_REGS, MAX_MAPPED, MAX_MAPPED, PRESERVED_FLOAT_REGS};
const char *types = "IPSN";
Instruction * ins, *tmp, *prev, *last;
SymReg * r;
SymReg * regs[IMCC_MAX_REGS];
static SymReg *cpu[4][MAX_MAPPED];
static SymReg *par[4][MAX_MAPPED];
int reads[4][MAX_MAPPED], writes[4][MAX_MAPPED], nr, nw;
int maxc[4] = {0,0,0,0};
Basic_block *bb;
opcode_t pc;
static int nsubs;
opcode_t * jit_info_ptr;
assert(INT_REGISTERS_TO_MAP < MAX_MAPPED);
assert(FLOAT_REGISTERS_TO_MAP < MAX_MAPPED);
to_map[0] = INT_REGISTERS_TO_MAP;
to_map[3] = FLOAT_REGISTERS_TO_MAP;
/* make a list of mapped cpu regs */
if (cpu[0][0] == NULL) {
for (typ = 0; typ < 4; typ++)
for (k = 0; k < to_map[typ]; k++) {
char name[16];
sprintf(name, "%c%d#c", types[typ], k);
cpu[typ][k] = mk_pasm_reg(str_dup(name));
cpu[typ][k]->color = -1 - k;
sprintf(name, "%c%d#p", types[typ], k);
par[typ][k] = mk_pasm_reg(str_dup(name));
}
}
prev = last = NULL;
nr = nw = 0;
/* change all mappable registers to mapped ones
* do nothing, if a compile was encountered
* TODO not the compile is the problem, but the invoke of
* compiled code - so track PMCs and invokes too
*/
if (!has_compile && !dont_optimize) {
for (j = 0; j < n_symbols; j++) {
r = reglist[j];
if (r->set == 'K')
continue;
typ = strchr(types, r->set) - types;
if (r->color < to_map[typ]) {
if (r->color >= maxc[typ])
maxc[typ] = r->color + 1;
r->color = -1 - r->color;
}
}
}
else {
maxc[0] = maxc[3] = 0;
}
to_map[0] = maxc[0];
to_map[3] = maxc[3];
if (!nsubs++) {
/* clear all used regs at beginning */
last = instructions->type & ITLABEL ? instructions : NULL;
for (typ = 0; typ < 4; typ++)
for (j = 0; j < to_map[typ]; j++) {
regs[0] = cpu[typ][j];
regs[1] = par[typ][j];
tmp = INS(interpreter, "set", "%s, %s\t# init",
regs, 2, 0, 0);
insert_ins(last, tmp);
}
}
/* now run through basic blocks
* and insert register save/load instructions where needed
*/
for (i=0; i < n_basic_blocks; i++) {
bb = bb_list[i];
/* TODO: set minimum register usage for this block */
for (ins = bb->start; ins; ins = ins->next) {
/* clear preserved regs, set rw of non preserved regs */
for (typ = 0; ins != instructions && typ < 4; typ++)
for (k = 0; k < to_map[typ]; k++) {
reads[typ][k] = writes[typ][k] =
k >= min_used(i, types[typ], typ, preserved, to_map);
}
/* if extern, go through regs and check the usage */
if (ins->opnum >= 0 && EXTCALL(&ins->opnum)) {
nr = nw = 1;
/* go through block if extern code, but stop at
* basic block boundary
*/
for (last = ins, prev = ins->prev;
ins && ins->opnum >= 0 && EXTCALL(&ins->opnum);
last = ins, ins = ins->next) {
ins->type |= ITEXT;
/* check register usage of all instructions
* if extern ins reads a reg, we save it to parrot's
* if a reg was writen, we reload it after the
* extern code block
*/
for (j = 0; j < n_symbols; j++) {
r = reglist[j];
if (r->set == 'K')
continue;
if (r->color >= 0)
continue;
typ = strchr(types, r->set) - types;
c = -1 - r->color;
if (0 && !strcmp(ins->op, "bsr") &&
(ins->type & ITSAVES)) {
int bb_sub =
find_sym(ins->r[0]->name)->first_ins->bbindex;
if (max_used(bb_sub, types[typ], typ, to_map))
reads[typ][c] = writes[typ][c] = nr = nw = 1;
}
if (instruction_reads(ins, r) ||
(/* !(ins->type & ITSAVES) && */
ins_reads2(ins, r->set))) {
reads[typ][c] = 1;
nr = 1;
}
if (instruction_writes(ins, r) ||
(/* !(ins->type & ITSAVES) && */
ins_writes2(ins, r->set))) {
writes[typ][c] = 1;
nw = 1;
}
}
/* changed mapped regs to parrot regs */
for (j = 0; (r = ins->r[j]) && j < IMCC_MAX_REGS; j++) {
typ = strchr(types, r->set) - types;
if ((r->type & VTREGISTER) && r->color < 0)
ins->r[j] = par[typ][-1 - r->color];
}
if (ins == bb->end) {
last = ins;
if (!strcmp(ins->op, "ret"))
last = ins->prev;
break;
}
}
}
/* a JITed end opcode, save registers to parrot's */
else if (!ins->opnum) {
for (typ = 0; typ < 4; typ++)
for (j = 0; j < to_map[typ]; j++) {
reads[typ][j] = 1;
nr = 1;
}
}
/* insert load ins after non JIT block */
if (nw) {
for (typ = 0; typ < 4; typ++)
for (j = 0; j < to_map[typ]; j++) {
if (!writes[typ][j])
continue;
regs[0] = cpu[typ][j];
regs[1] = par[typ][j];
tmp = INS(interpreter, "set", "%s, %s\t# load",
regs, 2, 0, 0);
insert_ins(last, tmp);
}
nw = 0;
}
/* insert save ins before extern op */
if (nr) {
for (typ = 0; typ < 4; typ++)
for (j = 0; j < to_map[typ]; j++) {
if (!reads[typ][j])
continue;
regs[0] = par[typ][j];
regs[1] = cpu[typ][j];
tmp = INS(interpreter, "set", "%s, %s\t# save",
regs, 2, 0, 0);
insert_ins(prev, tmp);
}
nr = 0;
}
if (ins == bb->end)
break;
}
}
find_basic_blocks();
/* allocate a jit_info packfile segment holding
* some CFG and register usage info
*/
jit_info_ptr = make_jit_info(interpreter);
/* write out minimal CFG and register_usage */
for (i = 0, pc = 0; i < n_basic_blocks; i++) {
int branch_target = 0;
bb = bb_list[i];
ins = bb->start;
/* mark branch targets with hight bit set */
if (ins->type & ITLABEL)
branch_target = 0x80000000;
*jit_info_ptr++ = (pc | branch_target);
for ( ; ins; ins = ins->next) {
pc += ins->opsize;
if (ins == bb->end)
break;
}
*jit_info_ptr++ = pc - ins->opsize;
/* TODO: dont't write block->end
* put register usage in one op
*/
for (typ = 0; typ < 4; typ++)
*jit_info_ptr++ = to_map[typ];
/* = max_used(i, types[typ], typ, to_map); */
}
}
/*
* Local variables:
* c-indentation-style: bsd
* c-basic-offset: 4
* indent-tabs-mode: nil
* End:
*
* vim: expandtab shiftwidth=4:
*/