1 /* src/vm/jit/schedule/schedule.c - architecture independent instruction
4 Copyright (C) 1996-2005 R. Grafl, A. Krall, C. Kruegel, C. Oates,
5 R. Obermaisser, M. Platter, M. Probst, S. Ring, E. Steiner,
6 C. Thalinger, D. Thuernbeck, P. Tomsich, C. Ullrich, J. Wenninger,
7 Institut f. Computersprachen - TU Wien
9 This file is part of CACAO.
11 This program is free software; you can redistribute it and/or
12 modify it under the terms of the GNU General Public License as
13 published by the Free Software Foundation; either version 2, or (at
14 your option) any later version.
16 This program is distributed in the hope that it will be useful, but
17 WITHOUT ANY WARRANTY; without even the implied warranty of
18 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
19 General Public License for more details.
21 You should have received a copy of the GNU General Public License
22 along with this program; if not, write to the Free Software
23 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
26 Contact: cacao@complang.tuwien.ac.at
28 Authors: Christian Thalinger
32 $Id: schedule.c 2056 2005-03-22 11:21:32Z twisti $
42 #include "mm/memory.h"
43 #include "vm/options.h"
44 #include "vm/statistics.h"
45 #include "vm/jit/schedule/schedule.h"
51 scheduledata *schedule_init(methodinfo *m, registerdata *rd)
55 sd = DNEW(scheduledata);
58 (rd->savintregcnt - rd->maxsavintreguse) +
59 (rd->savfltregcnt - rd->maxsavfltreguse) +
62 1; /* index 0 are all other memory accesses */
64 /* XXX quick hack: just use a fixed number of instructions */
65 sd->mi = DMNEW(minstruction, 20000);
67 sd->intregs_define_dep = DMNEW(edgenode*, rd->intregsnum);
68 sd->fltregs_define_dep = DMNEW(edgenode*, rd->fltregsnum);
70 sd->intregs_use_dep = DMNEW(edgenode*, rd->intregsnum);
71 sd->fltregs_use_dep = DMNEW(edgenode*, rd->fltregsnum);
73 sd->memory_define_dep = DMNEW(edgenode*, stackrange);
74 sd->memory_use_dep = DMNEW(edgenode*, stackrange);
77 /* open graphviz file */
82 file = fopen("cacao.dot", "w+");
83 fprintf(file, "digraph G {\n");
92 void schedule_reset(scheduledata *sd, registerdata *rd)
97 /* set define array to -1, because 0 is a valid node number */
99 MSET(sd->intregs_define_dep, 0, edgenode*, rd->intregsnum);
100 MSET(sd->fltregs_define_dep, 0, edgenode*, rd->fltregsnum);
102 /* clear all use pointers */
104 MSET(sd->intregs_use_dep, 0, edgenode*, rd->intregsnum);
105 MSET(sd->fltregs_use_dep, 0, edgenode*, rd->fltregsnum);
107 MSET(sd->memory_define_dep, 0, edgenode*, stackrange);
108 MSET(sd->memory_use_dep, 0, edgenode*, stackrange);
112 void schedule_close(scheduledata *sd)
119 fprintf(file, "}\n");
126 /* schedule_add_define_dep *****************************************************
130 *******************************************************************************/
132 void schedule_add_define_dep(scheduledata *sd, s1 opnum, edgenode **define_dep, edgenode **use_dep)
143 /* get current machine instruction */
145 minum = sd->micount - 1;
148 /* get current use dependency nodes, if non-null use them... */
150 if ((useen = *use_dep)) {
152 /* Save next pointer so we can link the current node to the */
153 /* machine instructions' dependency list. */
157 /* don't add the current machine instruction (e.g. add A0,A0,A0) */
159 if (useen->minum != minum) {
160 /* some edges to current machine instruction -> no leader */
162 mi->flags &= ~SCHEDULE_LEADER;
164 /* get use machine instruction */
166 usemi = &sd->mi[useen->minum];
168 /* link current use node into dependency list */
170 useen->minum = minum;
171 useen->opnum2 = opnum;
173 /* calculate latency, for define add 1 cycle */
174 useen->latency = (usemi->op[useen->opnum].lastcycle -
175 mi->op[opnum].firstcycle) + 1;
177 useen->next = usemi->deps;
184 /* ...otherwise use last define dependency, if non-null */
185 } else if ((defen = *define_dep)) {
186 /* some edges to current machine instruction -> no leader */
188 mi->flags &= ~SCHEDULE_LEADER;
190 /* get last define machine instruction */
192 defmi = &sd->mi[defen->minum];
194 /* link current define node into dependency list */
196 defen->minum = minum;
197 defen->opnum2 = opnum;
199 /* calculate latency, for define add 1 cycle */
200 defen->latency = (defmi->op[defen->opnum].lastcycle -
201 mi->op[opnum].firstcycle) + 1;
203 defen->next = defmi->deps;
207 /* Set current instruction as new define dependency and clear use */
219 /* schedule_add_use_dep ********************************************************
223 *******************************************************************************/
225 void schedule_add_use_dep(scheduledata *sd, s1 opnum, edgenode **define_dep, edgenode **use_dep)
233 /* get current machine instruction */
235 minum = sd->micount - 1;
238 /* get current define dependency instruction */
240 if ((defen = *define_dep)) {
241 /* some edges to current machine instruction -> no leader */
243 mi->flags &= ~SCHEDULE_LEADER;
245 /* add node to dependency list of current define node */
247 defmi = &sd->mi[defen->minum];
251 en->opnum = defen->opnum;
254 /* calculate latency */
255 en->latency = (defmi->op[defen->opnum].lastcycle -
256 mi->op[opnum].firstcycle);
258 en->next = defmi->deps;
262 /* add node to list of current use nodes */
272 /* schedule_calc_priorities ****************************************************
274 Calculates the current node's priority by getting highest priority
275 of the dependency nodes, adding this nodes latency plus 1 (for the
278 *******************************************************************************/
280 void schedule_calc_priorities(scheduledata *sd)
283 minstruction *lastmi;
293 /* last node MUST always be the last instruction scheduled */
295 lastnode = sd->micount - 1;
297 /* if last instruction is the first instruction, skip everything */
300 lastmi = &sd->mi[lastnode];
302 /* last instruction is no leader */
304 lastmi->flags &= ~SCHEDULE_LEADER;
306 /* last instruction has no dependencies, use virtual sink node */
310 for (j = 0; j < 4; j++) {
311 if (lastmi->op[j].lastcycle > lastcycle)
312 lastcycle = lastmi->op[j].lastcycle;
315 #define EARLIEST_USE_CYCLE 3
316 lastmi->priority = (lastcycle - EARLIEST_USE_CYCLE) + 1;
319 /* walk through all remaining machine instructions backwards */
321 for (i = lastnode - 1, mi = &sd->mi[lastnode - 1]; i >= 0; i--, mi--) {
329 /* walk through depedencies and calculate highest latency */
332 priority = sd->mi[en->minum].priority;
334 currentpath = en->latency + priority;
336 if (currentpath > criticalpath)
337 criticalpath = currentpath;
342 /* set priority to critical path */
344 mi->priority = criticalpath;
347 /* no dependencies, use virtual sink node */
351 for (j = 0; j < 4; j++) {
352 if (mi->op[j].lastcycle > lastcycle)
353 lastcycle = mi->op[j].lastcycle;
356 mi->priority = (lastcycle - EARLIEST_USE_CYCLE);
359 /* add current machine instruction to leader list, if one */
361 if (mi->flags & SCHEDULE_LEADER) {
364 en->next = sd->leaders;
370 /* last node is first instruction, add to leader list */
373 en->minum = lastnode;
374 en->next = sd->leaders;
380 static void schedule_create_graph(scheduledata *sd, s4 criticalpath)
391 fprintf(file, "subgraph cluster_%d {\n", bb);
392 fprintf(file, "label = \"BB%d (nodes: %d, critical path: %d)\"\n", bb, sd->micount, criticalpath);
394 for (i = 0, mi = sd->mi; i < sd->micount; i++, mi++) {
400 fprintf(file, "\"#%d.%d ", bb, i);
401 disassinstr(file, &mi->instr);
402 fprintf(file, "\\np=%d\"", mi->priority);
404 fprintf(file, " -> ");
406 fprintf(file, "\"#%d.%d ", bb, en->minum);
407 disassinstr(file, &sd->mi[en->minum].instr);
408 fprintf(file, "\\np=%d\"", sd->mi[en->minum].priority);
410 fprintf(file, " [ label = \"%d\" ]\n", en->latency);
415 fprintf(file, "\"#%d.%d ", bb, i);
416 disassinstr(file, &mi->instr);
417 fprintf(file, "\\np=%d\"", mi->priority);
419 fprintf(file, " -> ");
421 fprintf(file, "\"end %d\"", bb);
423 fprintf(file, " [ label = \"%d\" ]\n", mi->priority);
429 fprintf(file, "}\n");
435 /* schedule_add_deps_to_leaders ************************************************
437 Walk through all dependencies, change the starttime and add the
438 node to the leaders list.
440 *******************************************************************************/
442 static void schedule_add_deps_to_leaders(scheduledata *sd, edgenode *deps, s4 time)
447 if ((depen = deps)) {
449 /* set starttime of instruction */
451 sd->mi[depen->minum].starttime = time + depen->latency;
453 /* save last entry */
460 /* add dependencies to front of the list */
462 preven->next = sd->leaders;
468 /* schedule_do_schedule ********************************************************
472 *******************************************************************************/
474 void schedule_do_schedule(scheduledata *sd)
496 /* It may be possible that no instructions are in the current basic block */
497 /* because after an branch instruction the instructions are scheduled. */
499 if (sd->micount > 0) {
500 /* calculate priorities and critical path */
502 schedule_calc_priorities(sd);
505 printf("bb start ---\n");
506 printf("nodes: %d\n", sd->micount);
516 printf("#%d ", en->minum);
520 if (sd->mi[en->minum].priority > criticalpath)
521 criticalpath = sd->mi[en->minum].priority;
525 /* check last node for critical path (e.g. ret) */
527 if (sd->mi[sd->micount - 1].priority > criticalpath)
528 criticalpath = sd->mi[sd->micount - 1].priority;
532 printf("critical path: %d\n", criticalpath);
534 for (i = 0, mi = sd->mi; i < sd->micount; i++, mi++) {
535 disassinstr(stdout, &mi->instr);
537 printf("\t--> #%d, prio=%d", i, mi->priority);
539 printf(", mem=%d:%d", mi->op[0].firstcycle, mi->op[0].lastcycle);
541 for (j = 1; j <= 3; j++) {
542 printf(", op%d=%d:%d", j, mi->op[j].firstcycle, mi->op[j].lastcycle);
548 printf("#%d (op%d->op%d: %d) ", en->minum, en->opnum, en->opnum2, en->latency);
553 printf("bb end ---\n\n");
555 schedule_create_graph(sd, criticalpath);
559 /* set start time to zero */
561 printf("\n\nschedule start ---\n");
565 while (sd->leaders) {
566 /* XXX argh! how to make this portable? */
567 for (j = 0; j < 2; j++ ) {
579 printf("\n\nleaders: ");
581 /* get current machine instruction from leader list */
583 mi = &sd->mi[en->minum];
584 disassinstr(stdout, &mi->instr);
587 /* starttime reached */
589 if (mi->starttime <= time) {
591 /* check for a suitable ALU instruction */
593 if ((mi->flags & SCHEDULE_UNIT_ALU) &&
594 (!alumi || (mi->priority > alumi->priority))) {
595 /* remove/replace current node from leaders list */
599 preven->next = aluen;
600 aluen->next = en->next;
602 preven->next = en->next;
607 aluen->next = en->next;
609 sd->leaders = en->next;
612 /* set current ALU instruction and node */
617 /* check for a suitable MEM instruction */
619 } else if ((mi->flags & SCHEDULE_UNIT_MEM) &&
620 (!memmi || (mi->priority > memmi->priority))) {
623 preven->next = memen;
624 memen->next = en->next;
626 preven->next = en->next;
631 memen->next = en->next;
633 sd->leaders = en->next;
639 /* check for a suitable BRANCH instruction */
641 } else if ((mi->flags & SCHEDULE_UNIT_BRANCH) &&
642 (!brmi || (mi->priority > brmi->priority))) {
644 preven->next = en->next;
646 sd->leaders = en->next;
655 /* not leader removed, save next previous node */
664 /* schedule ALU instruction, if one was found */
667 mi = &sd->mi[aluen->minum];
669 disassinstr(stdout, &mi->instr);
673 schedule_add_deps_to_leaders(sd, mi->deps, time);
676 /* schedule MEM instruction, if one was found */
679 mi = &sd->mi[memen->minum];
681 disassinstr(stdout, &mi->instr);
685 schedule_add_deps_to_leaders(sd, mi->deps, time);
688 /* schedule BRANCH instruction, if one was found */
691 mi = &sd->mi[bren->minum];
693 disassinstr(stdout, &brmi->instr);
697 schedule_add_deps_to_leaders(sd, mi->deps, time);
700 if (!aluen && !memen && !bren) {
707 /* bundle finished, increase execution time */
711 printf("schedule end ---\n\n");
713 #if defined(STATISTICS)
715 count_schedule_basic_blocks++;
716 count_schedule_nodes += sd->micount;
717 count_schedule_leaders += leaders;
719 if (leaders > count_schedule_max_leaders)
720 count_schedule_max_leaders = leaders;
722 count_schedule_critical_path += criticalpath;
730 * These are local overrides for various environment variables in Emacs.
731 * Please do not remove this and leave it at the end of the file, where
732 * Emacs will automagically detect them.
733 * ---------------------------------------------------------------------
736 * indent-tabs-mode: t