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 4000 2005-12-22 14:05:01Z twisti $
45 #include "mm/memory.h"
46 #include "vm/options.h"
47 #include "vm/statistics.h"
48 #include "vm/jit/schedule/schedule.h"
54 scheduledata *schedule_init(methodinfo *m, registerdata *rd)
58 sd = DNEW(scheduledata);
61 (rd->savintregcnt - rd->maxsavintreguse) +
62 (rd->savfltregcnt - rd->maxsavfltreguse) +
65 1; /* index 0 are all other memory accesses */
67 /* XXX quick hack: just use a fixed number of instructions */
68 sd->mi = DMNEW(minstruction, 20000);
70 sd->intregs_define_dep = DMNEW(edgenode*, rd->intregsnum);
71 sd->fltregs_define_dep = DMNEW(edgenode*, rd->fltregsnum);
73 sd->intregs_use_dep = DMNEW(edgenode*, rd->intregsnum);
74 sd->fltregs_use_dep = DMNEW(edgenode*, rd->fltregsnum);
76 sd->memory_define_dep = DMNEW(edgenode*, stackrange);
77 sd->memory_use_dep = DMNEW(edgenode*, stackrange);
80 /* open graphviz file */
85 file = fopen("cacao.dot", "w+");
86 fprintf(file, "digraph G {\n");
95 void schedule_reset(scheduledata *sd, registerdata *rd)
100 /* set define array to -1, because 0 is a valid node number */
102 MSET(sd->intregs_define_dep, 0, edgenode*, rd->intregsnum);
103 MSET(sd->fltregs_define_dep, 0, edgenode*, rd->fltregsnum);
105 /* clear all use pointers */
107 MSET(sd->intregs_use_dep, 0, edgenode*, rd->intregsnum);
108 MSET(sd->fltregs_use_dep, 0, edgenode*, rd->fltregsnum);
110 MSET(sd->memory_define_dep, 0, edgenode*, stackrange);
111 MSET(sd->memory_use_dep, 0, edgenode*, stackrange);
115 void schedule_close(scheduledata *sd)
122 fprintf(file, "}\n");
129 /* schedule_add_define_dep *****************************************************
133 *******************************************************************************/
135 void schedule_add_define_dep(scheduledata *sd, s1 opnum, edgenode **define_dep, edgenode **use_dep)
146 /* get current machine instruction */
148 minum = sd->micount - 1;
151 /* get current use dependency nodes, if non-null use them... */
153 if ((useen = *use_dep)) {
155 /* Save next pointer so we can link the current node to the */
156 /* machine instructions' dependency list. */
160 /* don't add the current machine instruction (e.g. add A0,A0,A0) */
162 if (useen->minum != minum) {
163 /* some edges to current machine instruction -> no leader */
165 mi->flags &= ~SCHEDULE_LEADER;
167 /* get use machine instruction */
169 usemi = &sd->mi[useen->minum];
171 /* link current use node into dependency list */
173 useen->minum = minum;
174 useen->opnum2 = opnum;
176 /* calculate latency, for define add 1 cycle */
177 useen->latency = (usemi->op[useen->opnum].lastcycle -
178 mi->op[opnum].firstcycle) + 1;
180 useen->next = usemi->deps;
187 /* ...otherwise use last define dependency, if non-null */
188 } else if ((defen = *define_dep)) {
189 /* some edges to current machine instruction -> no leader */
191 mi->flags &= ~SCHEDULE_LEADER;
193 /* get last define machine instruction */
195 defmi = &sd->mi[defen->minum];
197 /* link current define node into dependency list */
199 defen->minum = minum;
200 defen->opnum2 = opnum;
202 /* calculate latency, for define add 1 cycle */
203 defen->latency = (defmi->op[defen->opnum].lastcycle -
204 mi->op[opnum].firstcycle) + 1;
206 defen->next = defmi->deps;
210 /* Set current instruction as new define dependency and clear use */
222 /* schedule_add_use_dep ********************************************************
226 *******************************************************************************/
228 void schedule_add_use_dep(scheduledata *sd, s1 opnum, edgenode **define_dep, edgenode **use_dep)
236 /* get current machine instruction */
238 minum = sd->micount - 1;
241 /* get current define dependency instruction */
243 if ((defen = *define_dep)) {
244 /* some edges to current machine instruction -> no leader */
246 mi->flags &= ~SCHEDULE_LEADER;
248 /* add node to dependency list of current define node */
250 defmi = &sd->mi[defen->minum];
254 en->opnum = defen->opnum;
257 /* calculate latency */
258 en->latency = (defmi->op[defen->opnum].lastcycle -
259 mi->op[opnum].firstcycle);
261 en->next = defmi->deps;
265 /* add node to list of current use nodes */
275 /* schedule_calc_priorities ****************************************************
277 Calculates the current node's priority by getting highest priority
278 of the dependency nodes, adding this nodes latency plus 1 (for the
281 *******************************************************************************/
283 void schedule_calc_priorities(scheduledata *sd)
286 minstruction *lastmi;
296 /* last node MUST always be the last instruction scheduled */
298 lastnode = sd->micount - 1;
300 /* if last instruction is the first instruction, skip everything */
303 lastmi = &sd->mi[lastnode];
305 /* last instruction is no leader */
307 lastmi->flags &= ~SCHEDULE_LEADER;
309 /* last instruction has no dependencies, use virtual sink node */
313 for (j = 0; j < 4; j++) {
314 if (lastmi->op[j].lastcycle > lastcycle)
315 lastcycle = lastmi->op[j].lastcycle;
318 #define EARLIEST_USE_CYCLE 3
319 lastmi->priority = (lastcycle - EARLIEST_USE_CYCLE) + 1;
322 /* walk through all remaining machine instructions backwards */
324 for (i = lastnode - 1, mi = &sd->mi[lastnode - 1]; i >= 0; i--, mi--) {
332 /* walk through depedencies and calculate highest latency */
335 priority = sd->mi[en->minum].priority;
337 currentpath = en->latency + priority;
339 if (currentpath > criticalpath)
340 criticalpath = currentpath;
345 /* set priority to critical path */
347 mi->priority = criticalpath;
350 /* no dependencies, use virtual sink node */
354 for (j = 0; j < 4; j++) {
355 if (mi->op[j].lastcycle > lastcycle)
356 lastcycle = mi->op[j].lastcycle;
359 mi->priority = (lastcycle - EARLIEST_USE_CYCLE);
362 /* add current machine instruction to leader list, if one */
364 if (mi->flags & SCHEDULE_LEADER) {
367 en->next = sd->leaders;
373 /* last node is first instruction, add to leader list */
376 en->minum = lastnode;
377 en->next = sd->leaders;
383 static void schedule_create_graph(scheduledata *sd, s4 criticalpath)
394 fprintf(file, "subgraph cluster_%d {\n", bb);
395 fprintf(file, "label = \"BB%d (nodes: %d, critical path: %d)\"\n", bb, sd->micount, criticalpath);
397 for (i = 0, mi = sd->mi; i < sd->micount; i++, mi++) {
403 fprintf(file, "\"#%d.%d ", bb, i);
404 disassinstr(file, &mi->instr);
405 fprintf(file, "\\np=%d\"", mi->priority);
407 fprintf(file, " -> ");
409 fprintf(file, "\"#%d.%d ", bb, en->minum);
410 disassinstr(file, &sd->mi[en->minum].instr);
411 fprintf(file, "\\np=%d\"", sd->mi[en->minum].priority);
413 fprintf(file, " [ label = \"%d\" ]\n", en->latency);
418 fprintf(file, "\"#%d.%d ", bb, i);
419 disassinstr(file, &mi->instr);
420 fprintf(file, "\\np=%d\"", mi->priority);
422 fprintf(file, " -> ");
424 fprintf(file, "\"end %d\"", bb);
426 fprintf(file, " [ label = \"%d\" ]\n", mi->priority);
432 fprintf(file, "}\n");
438 /* schedule_add_deps_to_leaders ************************************************
440 Walk through all dependencies, change the starttime and add the
441 node to the leaders list.
443 *******************************************************************************/
445 static void schedule_add_deps_to_leaders(scheduledata *sd, edgenode *deps, s4 time)
450 if ((depen = deps)) {
452 /* set starttime of instruction */
454 sd->mi[depen->minum].starttime = time + depen->latency;
456 /* save last entry */
463 /* add dependencies to front of the list */
465 preven->next = sd->leaders;
471 /* schedule_do_schedule ********************************************************
475 *******************************************************************************/
477 void schedule_do_schedule(scheduledata *sd)
499 /* It may be possible that no instructions are in the current basic block */
500 /* because after an branch instruction the instructions are scheduled. */
502 if (sd->micount > 0) {
503 /* calculate priorities and critical path */
505 schedule_calc_priorities(sd);
508 printf("bb start ---\n");
509 printf("nodes: %d\n", sd->micount);
519 printf("#%d ", en->minum);
523 if (sd->mi[en->minum].priority > criticalpath)
524 criticalpath = sd->mi[en->minum].priority;
528 /* check last node for critical path (e.g. ret) */
530 if (sd->mi[sd->micount - 1].priority > criticalpath)
531 criticalpath = sd->mi[sd->micount - 1].priority;
535 printf("critical path: %d\n", criticalpath);
537 for (i = 0, mi = sd->mi; i < sd->micount; i++, mi++) {
538 disassinstr(stdout, &mi->instr);
540 printf("\t--> #%d, prio=%d", i, mi->priority);
542 printf(", mem=%d:%d", mi->op[0].firstcycle, mi->op[0].lastcycle);
544 for (j = 1; j <= 3; j++) {
545 printf(", op%d=%d:%d", j, mi->op[j].firstcycle, mi->op[j].lastcycle);
551 printf("#%d (op%d->op%d: %d) ", en->minum, en->opnum, en->opnum2, en->latency);
556 printf("bb end ---\n\n");
558 schedule_create_graph(sd, criticalpath);
562 /* set start time to zero */
564 printf("\n\nschedule start ---\n");
568 while (sd->leaders) {
569 /* XXX argh! how to make this portable? */
570 for (j = 0; j < 2; j++ ) {
582 printf("\n\nleaders: ");
584 /* get current machine instruction from leader list */
586 mi = &sd->mi[en->minum];
587 disassinstr(stdout, &mi->instr);
590 /* starttime reached */
592 if (mi->starttime <= time) {
594 /* check for a suitable ALU instruction */
596 if ((mi->flags & SCHEDULE_UNIT_ALU) &&
597 (!alumi || (mi->priority > alumi->priority))) {
598 /* remove/replace current node from leaders list */
602 preven->next = aluen;
603 aluen->next = en->next;
605 preven->next = en->next;
610 aluen->next = en->next;
612 sd->leaders = en->next;
615 /* set current ALU instruction and node */
620 /* check for a suitable MEM instruction */
622 } else if ((mi->flags & SCHEDULE_UNIT_MEM) &&
623 (!memmi || (mi->priority > memmi->priority))) {
626 preven->next = memen;
627 memen->next = en->next;
629 preven->next = en->next;
634 memen->next = en->next;
636 sd->leaders = en->next;
642 /* check for a suitable BRANCH instruction */
644 } else if ((mi->flags & SCHEDULE_UNIT_BRANCH) &&
645 (!brmi || (mi->priority > brmi->priority))) {
647 preven->next = en->next;
649 sd->leaders = en->next;
658 /* not leader removed, save next previous node */
667 /* schedule ALU instruction, if one was found */
670 mi = &sd->mi[aluen->minum];
672 disassinstr(stdout, &mi->instr);
676 schedule_add_deps_to_leaders(sd, mi->deps, time);
679 /* schedule MEM instruction, if one was found */
682 mi = &sd->mi[memen->minum];
684 disassinstr(stdout, &mi->instr);
688 schedule_add_deps_to_leaders(sd, mi->deps, time);
691 /* schedule BRANCH instruction, if one was found */
694 mi = &sd->mi[bren->minum];
696 disassinstr(stdout, &brmi->instr);
700 schedule_add_deps_to_leaders(sd, mi->deps, time);
703 if (!aluen && !memen && !bren) {
710 /* bundle finished, increase execution time */
714 printf("schedule end ---\n\n");
716 #if defined(ENABLE_STATISTICS)
718 count_schedule_basic_blocks++;
719 count_schedule_nodes += sd->micount;
720 count_schedule_leaders += leaders;
722 if (leaders > count_schedule_max_leaders)
723 count_schedule_max_leaders = leaders;
725 count_schedule_critical_path += criticalpath;
733 * These are local overrides for various environment variables in Emacs.
734 * Please do not remove this and leave it at the end of the file, where
735 * Emacs will automagically detect them.
736 * ---------------------------------------------------------------------
739 * indent-tabs-mode: t