Changes for Windows NT port; added flags for loading libdyninst dynamically
[dyninst.git] / dyninstAPI / src / ast.C
1 /*
2  * Copyright (c) 1996 Barton P. Miller
3  * 
4  * We provide the Paradyn Parallel Performance Tools (below
5  * described as Paradyn") on an AS IS basis, and do not warrant its
6  * validity or performance.  We reserve the right to update, modify,
7  * or discontinue this software at any time.  We shall have no
8  * obligation to supply such updates or modifications or any other
9  * form of support to you.
10  * 
11  * This license is for research uses.  For such uses, there is no
12  * charge. We define "research use" to mean you may freely use it
13  * inside your organization for whatever purposes you see fit. But you
14  * may not re-distribute Paradyn or parts of Paradyn, in any form
15  * source or binary (including derivatives), electronic or otherwise,
16  * to any other organization or entity without our permission.
17  * 
18  * (for other uses, please contact us at paradyn@cs.wisc.edu)
19  * 
20  * All warranties, including without limitation, any warranty of
21  * merchantability or fitness for a particular purpose, are hereby
22  * excluded.
23  * 
24  * By your use of Paradyn, you understand and agree that we (or any
25  * other person or entity with proprietary rights in Paradyn) are
26  * under no obligation to provide either maintenance services,
27  * update services, notices of latent defects, or correction of
28  * defects for Paradyn.
29  * 
30  * Even if advised of the possibility of such damages, under no
31  * circumstances shall we (or any other person or entity with
32  * proprietary rights in the software licensed hereunder) be liable
33  * to you or any third party for direct, indirect, or consequential
34  * damages of any character regardless of type of action, including,
35  * without limitation, loss of profits, loss of use, loss of good
36  * will, or computer failure or malfunction.  You agree to indemnify
37  * us (and any other person or entity with proprietary rights in the
38  * software licensed hereunder) for any and all liability it may
39  * incur to third parties resulting from your use of Paradyn.
40  */
41
42 /* 
43  * $Log: ast.C,v $
44  * Revision 1.43  1997/05/08 00:38:47  mjrg
45  * Changes for Windows NT port; added flags for loading libdyninst dynamically
46  *
47  * Revision 1.42  1997/05/07 19:02:53  naim
48  * Getting rid of old support for threads and turning it off until the new
49  * version is finished. Additionally, new superTable, baseTable and superVector
50  * classes for future support of multiple threads. The fastInferiorHeap class has
51  * also changed - naim
52  *
53  * Revision 1.41  1997/04/29 16:58:50  buck
54  * Added features to dyninstAPI library, including the ability to delete
55  * inserted snippets and the start of type checking.
56  *
57  * Revision 1.1.1.1  1997/04/01 20:24:59  buck
58  * Update Maryland repository with latest from Wisconsin.
59  *
60  * Revision 1.40  1997/03/18 19:44:07  buck
61  * first commit of dyninst library.  Also includes:
62  *      moving templates from paradynd to dyninstAPI
63  *      converting showError into a function (in showerror.C)
64  *      many ifdefs for BPATCH_LIBRARY in dyinstAPI/src.
65  *
66  * Revision 1.39  1997/03/14 15:58:59  lzheng
67  * Dealing with complier optimization related to the return value
68  *
69  * Revision 1.38  1997/02/26 23:42:48  mjrg
70  * First part on WindowsNT port: changes for compiling with Visual C++;
71  * moved unix specific code to unix.C
72  *
73  * Revision 1.37  1997/02/21 20:13:16  naim
74  * Moving files from paradynd to dyninstAPI + moving references to dataReqNode
75  * out of the ast class. The is the first pre-dyninstAPI commit! - naim
76  *
77  * Revision 1.36  1997/01/27 19:40:36  naim
78  * Part of the base instrumentation for supporting multithreaded applications
79  * (vectors of counter/timers) implemented for all current platforms +
80  * different bug fixes - naim
81  *
82  * Revision 1.35  1996/11/14 14:42:52  naim
83  * Minor fix to my previous commit - naim
84  *
85  * Revision 1.34  1996/11/14 14:26:57  naim
86  * Changing AstNodes back to pointers to improve performance - naim
87  *
88  * Revision 1.33  1996/11/12 17:48:34  mjrg
89  * Moved the computation of cost to the basetramp in the x86 platform,
90  * and changed other platform to keep code consistent.
91  * Removed warnings, and made changes for compiling with Visual C++
92  *
93  * Revision 1.32  1996/11/11 01:45:30  lzheng
94  * Moved the instructions which is used to caculate the observed cost
95  * from the miniTramps to baseTramp
96  *
97  * Revision 1.31  1996/10/31 08:36:58  tamches
98  * the shm-sampling commit; added noCost param to some fns
99  *
100  * Revision 1.30  1996/10/04 16:12:38  naim
101  * Optimization for code generation (use of immediate operations whenever
102  * possible). This first commit is only for the sparc platform. Other platforms
103  * should follow soon - naim
104  *
105  * Revision 1.29  1996/09/13 21:41:57  mjrg
106  * Implemented opcode ReturnVal for ast's to get the return value of functions.
107  * Added missing calls to free registers in Ast.generateCode and emitFuncCall.
108  * Removed architecture dependencies from inst.C.
109  * Changed code to allow base tramps of variable size.
110  *
111  * Revision 1.28  1996/08/21 18:02:35  mjrg
112  * Changed the ast nodes generated for timers. This just affects the ast
113  * nodes, not the code generated.
114  *
115  * Revision 1.27  1996/08/20 19:07:30  lzheng
116  * Implementation of moving multiple instructions sequence and
117  * splitting the instrumentations into two phases.
118  *
119  * Revision 1.26  1996/08/16 21:18:14  tamches
120  * updated copyright for release 1.1
121  *
122  * Revision 1.25  1996/05/12 05:15:56  tamches
123  * aix 4.1 commit
124  *
125  * Revision 1.24  1996/04/26 20:16:16  lzheng
126  * Move part of code in AstNode::generateCode to machine dependent file.
127  * (Those code are put into the procedure emitFuncCall)
128  *
129  * Revision 1.23  1996/04/10 18:00:11  lzheng
130  * Added multiple arguments to calls for HPUX by using stack instead of extra
131  * registers.
132  *
133  * Revision 1.22  1996/04/08 21:21:11  lzheng
134  * changes for HP generateCode and emitFuncCall
135  *
136  * Revision 1.21  1996/03/25 20:20:39  tamches
137  * the reduce-mem-leaks-in-paradynd commit
138  *
139  * Revision 1.20  1996/03/20 17:02:36  mjrg
140  * Added multiple arguments to calls.
141  * Instrument pvm_send instead of pvm_recv to get tags.
142  *
143  * Revision 1.19  1995/12/19 01:04:44  hollings
144  * Moved the implementation of registerSpace::readOnlyRegister to processor
145  *   specific files (since it is).
146  * Fixed a bug in Power relOps cases.
147  *
148  */
149
150 #include "dyninstAPI/src/symtab.h"
151 #include "dyninstAPI/src/pdThread.h"
152 #include "dyninstAPI/src/process.h"
153 #include "dyninstAPI/src/inst.h"
154 #include "dyninstAPI/src/instP.h"
155 #include "dyninstAPI/src/dyninstP.h"
156 #include "dyninstAPI/src/ast.h"
157 #include "dyninstAPI/src/util.h"
158 #include "paradynd/src/showerror.h"
159 #if defined(BPATCH_LIBRARY)
160 #include "dyninstAPI/h/BPatch.h"
161 #include "dyninstAPI/src/BPatch_type.h"
162 #endif
163
164 #ifndef BPATCH_LIBRARY
165 #include "rtinst/h/rtinst.h"
166 #include "paradynd/src/metric.h"
167 #endif
168
169 #if defined(sparc_sun_sunos4_1_3) || defined(sparc_sun_solaris2_4)
170 #include "dyninstAPI/src/inst-sparc.h"
171 #elif defined(hppa1_1_hp_hpux)
172 #include "dyninstAPI/src/inst-hppa.h"
173 #elif defined(rs6000_ibm_aix3_2) || defined(rs6000_ibm_aix4_1)
174 #include "dyninstAPI/src/inst-power.h"
175 #elif defined(i386_unknown_solaris2_5) || defined(i386_unknown_nt4_0)
176 #include "dyninstAPI/src/inst-x86.h"
177 #else
178 #endif
179
180 extern registerSpace *regSpace;
181 extern bool doNotOverflow(int value);
182
183 registerSpace::registerSpace(int deadCount, int *dead, int liveCount, int *live)
184 {
185     int i;
186
187     numRegisters = deadCount + liveCount;
188     registers = new registerSlot[numRegisters];
189
190     // load dead ones
191     for (i=0; i < deadCount; i++) {
192         registers[i].number = dead[i];
193         registers[i].inUse = false;
194         registers[i].mustRestore = false;
195         registers[i].needsSaving = false;
196         registers[i].startsLive = false;
197     }
198
199     // load live ones;
200     for (i=0; i < liveCount; i++) {
201         registers[i+deadCount].number = live[i];
202         registers[i+deadCount].inUse = false;
203         registers[i+deadCount].mustRestore = false;
204         registers[i+deadCount].needsSaving = true;
205         registers[i+deadCount].startsLive = true;
206 #if defined(SHM_SAMPLING) && defined(MT_THREAD)
207         if (registers[i+deadCount].number == REG_MT) {
208           registers[i+deadCount].inUse = true;
209           registers[i+deadCount].needsSaving = true;
210         }
211 #endif
212     }
213
214 }
215
216 reg registerSpace::allocateRegister(char *insn, unsigned &base, bool noCost) 
217 {
218     int i;
219     for (i=0; i < numRegisters; i++) {
220         if (!registers[i].inUse && !registers[i].needsSaving) {
221             registers[i].inUse = true;
222             highWaterRegister = (highWaterRegister > i) ? 
223                  highWaterRegister : i;
224             return(registers[i].number);
225         }
226     }
227
228     // now consider ones that need saving
229     for (i=0; i < numRegisters; i++) {
230         if (!registers[i].inUse) {
231 #if !defined(rs6000_ibm_aix4_1)
232             // MT_AIX: we are not saving registers on demand on the power
233             // architecture. Instead, we save/restore registers in the base
234             // trampoline - naim
235             emit(saveRegOp, registers[i].number, 0, 0, insn, base, noCost);
236 #endif
237             registers[i].inUse = true;
238 #if !defined(rs6000_ibm_aix4_1)
239             // MT_AIX
240             registers[i].mustRestore = true;
241 #endif
242             // prevent general spill (func call) from saving this register.
243             registers[i].needsSaving = false;
244             highWaterRegister = (highWaterRegister > i) ? 
245                  highWaterRegister : i;
246             return(registers[i].number);
247         }
248     }
249
250     logLine("==> WARNING! run out of registers...\n");
251     abort();
252     return(-1);
253 }
254
255 bool registerSpace::is_keep_register(reg k)
256 {
257   for (unsigned i=0;i<keep_list.size();i++) {
258     if (keep_list[i]==k) return(true);
259   }
260   return(false);
261 }
262
263 void registerSpace::keep_register(reg k)
264 {
265   if (!is_keep_register(k)) {
266     keep_list += k;
267 #if defined(ASTDEBUG)
268     sprintf(errorLine,"==> keeping register %d, size is %d <==\n",k,keep_list.size());
269     logLine(errorLine);
270 #endif
271   }
272 }
273
274 void registerSpace::unkeep_register(reg k) {
275   unsigned ksize = keep_list.size();
276   for (unsigned i=0;i<ksize;i++) {
277     if (keep_list[i]==k) {
278       keep_list[i]=keep_list[ksize-1];
279       ksize--;
280       keep_list.resize(ksize);
281       freeRegister(k);
282 #if defined(ASTDEBUG)
283       sprintf(errorLine,"==> un-keeping register %d, size is %d <==\n",k,keep_list.size());
284       logLine(errorLine);
285 #endif
286       break;
287     }
288   }
289 }
290
291 void registerSpace::freeRegister(int reg) {
292     int i;
293     if (is_keep_register(reg)) return;
294     for (i=0; i < numRegisters; i++) {
295         if (registers[i].number == reg) {
296             registers[i].inUse = false;
297             return;
298         }
299     }
300 }
301
302 bool registerSpace::isFreeRegister(int reg) {
303     int i;
304     for (i=0; i < numRegisters; i++) {
305         if ((registers[i].number == reg) &&
306             (registers[i].inUse == true)) {
307             return false;
308         }
309     }
310     return true;
311 }
312
313 void registerSpace::resetSpace() {
314     int i;
315     for (i=0; i < numRegisters; i++) {
316         if (registers[i].inUse && (registers[i].number != REG_MT)) {
317           sprintf(errorLine,"WARNING: register %d is still in use\n",registers[i].number);
318           logLine(errorLine);
319         }
320         registers[i].inUse = false;
321         registers[i].mustRestore = false;
322         registers[i].needsSaving = registers[i].startsLive;
323 #if defined(SHM_SAMPLING) && defined(MT_THREAD)
324         if (registers[i].number == REG_MT) {
325           registers[i].inUse = true;
326           registers[i].needsSaving = true;
327         }
328 #endif
329     }
330     highWaterRegister = 0;
331 }
332
333 //
334 // How to use AstNodes:
335 //
336 // In order to avoid memory leaks, it is important to define and delete
337 // AstNodes properly. The general rules are the following:
338 //
339 // 1.- Any AstNode defined locally, should be destroyed at the end of that
340 //     procedure. The only exception occurs when we are returning a pointer
341 //     to the AstNode as a result of the function (i.e. we need to keep the
342 //     value alive).
343 // 2.- Every time we assign an AstNode to another, we have to use the
344 //     "assignAst" function. This function will update the reference count
345 //     of the AstNode being assigned and it will return a pointer to it. If
346 //     we are creating a new AstNode (e.g. AstNode *t1 = new AstNode(...))
347 //     then it is not necessary to use assign, because the constructor will
348 //     automatically increment the reference count for us.
349 // 3.- "removeAst" is the procedure to be used everytime we want to delete
350 //     an AstNode. In general, if an AstNode is re-used several times, it
351 //     should be enough to delete the root of the DAG to delete all nodes.
352 //     However, there are exceptions like this one:
353 //     AstNode *t1, *t2, *t3;
354 //     t1 = AstNode(...);   rc-t1=1
355 //     t2 = AstNode(...);   rc-t2=1
356 //     t3 = AstNode(t1,t2); rc-t1=2, rc-t2=2, rc-t3=1
357 //     if we say:
358 //     removeAst(t3);
359 //     it will delete t3, but not t1 or t2 (because the rc will be 1 for both
360 //     of them). Therefore, we need to add the following:
361 //     removeAst(t1); removeAst(t2);
362 //     We only delete AstNodes when the reference count is 0.
363 //
364
365 AstNode &AstNode::operator=(const AstNode &src) {
366    logLine("Calling AstNode COPY constructor\n");
367    if (&src == this)
368       return *this; // the usual check for x=x
369
370    // clean up self before overwriting self; i.e., release memory
371    // currently in use so it doesn't become leaked.
372    if (loperand) {
373       if (src.loperand) {
374         if (loperand!=src.loperand) {
375           removeAst(loperand);
376         }
377       } else {
378         removeAst(loperand);
379       }
380    }
381    if (roperand) {
382       if (src.roperand) {
383         if (roperand!=src.roperand) {
384           removeAst(roperand);
385         }
386       } else {
387         removeAst(roperand);
388       }
389    }
390    if (type == operandNode && oType == ConstantString)
391        free((char *)oValue);
392    referenceCount = src.referenceCount;
393    referenceCount++;
394
395    type = src.type;
396    if (type == opCodeNode)
397       op = src.op; // defined only for operand nodes
398
399    if (type == callNode) {
400       callee = src.callee; // defined only for call nodes
401       for (unsigned i=0;i<src.operands.size();i++) 
402         operands += assignAst(src.operands[i]);
403    }
404
405    if (type == operandNode) {
406       oType = src.oType;
407       // XXX This is for the string type.  If/when we fix the string type to
408       // make it less of a hack, we'll need to change this.
409       if (oType == ConstantString)
410           oValue = P_strdup((char *)src.oValue);
411       else
412           oValue = src.oValue;
413    }
414
415    loperand = assignAst(src.loperand);
416    roperand = assignAst(src.roperand);
417
418    firstInsn = src.firstInsn;
419    lastInsn = src.lastInsn;
420
421 #if defined(sparc_sun_sunos4_1_3) || defined(sparc_sun_solaris2_4)
422    astFlag = src.astFlag;
423 #endif
424
425    bptype = src.bptype;
426    doTypeCheck = src.doTypeCheck;
427
428    return *this;
429 }
430
431 #if defined(ASTDEBUG)
432 static int ASTcount=0;
433
434 void ASTcounter()
435 {
436   ASTcount++;
437   sprintf(errorLine,"AstNode CONSTRUCTOR - ASTcount is %d\n",ASTcount);
438   logLine(errorLine);
439 }
440
441 void ASTcounterNP()
442 {
443   ASTcount++;
444 }
445 #endif
446
447 AstNode::AstNode() {
448 #if defined(ASTDEBUG)
449    ASTcounter();
450 #endif
451 #if defined(sparc_sun_sunos4_1_3) || defined(sparc_sun_solaris2_4)  
452     astFlag = false;
453 #endif
454    // used in mdl.C
455    type = opCodeNode;
456    op = noOp;
457    loperand = roperand = NULL;
458    referenceCount = 1;
459    useCount = 0;
460    kept_register = -1;
461    // "operands" is left as an empty vector
462    bptype = NULL;
463    doTypeCheck = true;
464 }
465
466 AstNode::AstNode(const string &func, AstNode *l, AstNode *r) {
467 #if defined(ASTDEBUG)
468     ASTcounter();
469 #endif
470 #if defined(sparc_sun_sunos4_1_3) || defined(sparc_sun_solaris2_4)  
471     astFlag = false;
472 #endif
473     referenceCount = 1;
474     useCount = 0;
475     kept_register = -1;
476     type = callNode;
477     callee = func;
478     if (l) operands += assignAst(l);
479     if (r) operands += assignAst(r);
480     bptype = NULL;
481     doTypeCheck = true;
482 }
483
484 AstNode::AstNode(const string &func, AstNode *l) {
485 #if defined(ASTDEBUG)
486     ASTcounter();
487 #endif
488 #if defined(sparc_sun_sunos4_1_3) || defined(sparc_sun_solaris2_4)  
489     astFlag = false;
490 #endif
491     referenceCount = 1;
492     useCount = 0;
493     kept_register = -1;
494     loperand = assignAst(l);
495     roperand = NULL;
496     type = callNode;
497     callee = func;
498     if (l) operands += assignAst(l);
499     bptype = NULL;
500     doTypeCheck = true;
501 }
502
503 AstNode::AstNode(const string &func, vector<AstNode *> &ast_args) {
504 #if defined(ASTDEBUG)
505    ASTcounter();
506 #endif
507 #if defined(sparc_sun_sunos4_1_3) || defined(sparc_sun_solaris2_4)  
508     astFlag = false;
509 #endif
510    referenceCount = 1;
511    useCount = 0;
512    kept_register = -1;
513    for (unsigned i=0;i<ast_args.size();i++) 
514      if (ast_args[i]) operands += assignAst(ast_args[i]);
515    loperand = roperand = NULL;
516    type = callNode;
517    callee = func;
518    bptype = NULL;
519    doTypeCheck = true;
520 }
521
522 AstNode::AstNode(operandType ot, void *arg) {
523 #if defined(ASTDEBUG)
524     ASTcounterNP();
525 #endif
526 #if defined(sparc_sun_sunos4_1_3) || defined(sparc_sun_solaris2_4)  
527     astFlag = false;
528 #endif
529     referenceCount = 1;
530     useCount = 0;
531     kept_register = -1;
532     type = operandNode;
533     oType = ot;
534     if (ot == ConstantString)
535         oValue = (void *)P_strdup((char *)arg);
536     else
537         oValue = (void *) arg;
538     loperand = roperand = NULL;
539     bptype = NULL;
540     doTypeCheck = true;
541 };
542
543 AstNode::AstNode(operandType ot, AstNode *l) {
544 #if defined(ASTDEBUG)
545     ASTcounter();
546 #endif
547 #if defined(sparc_sun_sunos4_1_3) || defined(sparc_sun_solaris2_4)  
548     astFlag = false;
549 #endif
550     referenceCount = 1;
551     useCount = 0;
552     kept_register = -1;
553     type = operandNode;
554     oType = ot;
555     oValue = NULL;
556     roperand = NULL;
557     loperand = assignAst(l);
558     bptype = NULL;
559     doTypeCheck = true;
560 };
561
562 AstNode::AstNode(AstNode *l, AstNode *r) {
563 #if defined(ASTDEBUG)
564    ASTcounter();
565 #endif
566 #if defined(sparc_sun_sunos4_1_3) || defined(sparc_sun_solaris2_4)  
567     astFlag = false;
568 #endif
569    referenceCount = 1;
570    useCount = 0;
571    kept_register = -1;
572    type = sequenceNode;
573    loperand = assignAst(l);
574    roperand = assignAst(r);
575    bptype = NULL;
576    doTypeCheck = true;
577 };
578
579 AstNode::AstNode(opCode ot) {
580 #if defined(ASTDEBUG)
581    ASTcounter();
582 #endif
583 #if defined(sparc_sun_sunos4_1_3) || defined(sparc_sun_solaris2_4)  
584     astFlag = false;
585 #endif
586    // a private constructor
587    referenceCount = 1;
588    useCount = 0;
589    kept_register = -1;
590    type = opCodeNode;
591    op = ot;
592    loperand = roperand = NULL;
593    bptype = NULL;
594    doTypeCheck = true;
595 }
596
597 AstNode::AstNode(opCode ot, AstNode *l) {
598 #if defined(ASTDEBUG)
599    ASTcounter();
600 #endif
601 #if defined(sparc_sun_sunos4_1_3) || defined(sparc_sun_solaris2_4)  
602     astFlag = false;
603 #endif
604    // a private constructor
605    referenceCount = 1;
606    useCount = 0;
607    kept_register = -1;
608    type = opCodeNode;
609    op = ot;
610    loperand = assignAst(l);
611    roperand = NULL;
612    bptype = NULL;
613    doTypeCheck = true;
614 }
615
616 AstNode::AstNode(opCode ot, AstNode *l, AstNode *r) {
617 #if defined(ASTDEBUG)
618    ASTcounter();
619 #endif
620 #if defined(sparc_sun_sunos4_1_3) || defined(sparc_sun_solaris2_4)  
621     astFlag = false;
622 #endif
623    referenceCount = 1;
624    useCount = 0;
625    kept_register = -1;
626    type = opCodeNode;
627    op = ot;
628    loperand = assignAst(l);
629    roperand = assignAst(r);
630    bptype = NULL;
631    doTypeCheck = true;
632 };
633
634 AstNode::AstNode(AstNode *src) {
635 #if defined(ASTDEBUG)
636    ASTcounter();
637 #endif
638 #if defined(sparc_sun_sunos4_1_3) || defined(sparc_sun_solaris2_4)  
639     astFlag = false;
640 #endif
641    referenceCount = 1;
642    useCount = 0;
643    kept_register = -1;
644
645    type = src->type;   
646    if (type == opCodeNode)
647       op = src->op;             // defined only for operand nodes
648
649    if (type == callNode) {
650       callee = src->callee;     // defined only for call nodes
651       for (unsigned i=0;i<src->operands.size();i++) {
652         if (src->operands[i]) operands += assignAst(src->operands[i]);
653       }
654    }
655
656    if (type == operandNode) {
657       oType = src->oType;
658       // XXX This is for the string type.  If/when we fix the string type to
659       // make it less of a hack, we'll need to change this.
660       if (oType == ConstantString)
661           oValue = P_strdup((char *)src->oValue);
662       else
663           oValue = src->oValue;
664    }
665
666    loperand = assignAst(src->loperand);
667    roperand = assignAst(src->roperand);
668    firstInsn = src->firstInsn;
669    lastInsn = src->lastInsn;
670    bptype = src->bptype;
671    doTypeCheck = src->doTypeCheck;
672 }
673
674 #if defined(ASTDEBUG)
675 void AstNode::printRC()
676 {
677     sprintf(errorLine,"RC referenceCount=%d\n",referenceCount);
678     logLine(errorLine);
679     if (loperand) {
680       logLine("RC loperand\n");
681       loperand->printRC();
682     }
683     if (roperand) {
684       logLine("RC roperand\n");
685       roperand->printRC();
686     }
687 }
688 #endif
689
690 AstNode::~AstNode() {
691 #if defined(ASTDEBUG)
692   ASTcount--;
693   sprintf(errorLine,"AstNode DESTRUCTOR - ASTcount is %d\n",ASTcount);
694   logLine(errorLine);
695 #endif
696   if (loperand) {
697     removeAst(loperand);
698   }
699   if (roperand) {
700     removeAst(roperand);
701   }
702   if (type==callNode) {
703     for (unsigned i=0;i<operands.size();i++) {
704       removeAst(operands[i]);
705     }
706   } else if (type == operandNode && oType == ConstantString) {
707       free(oValue);
708   }
709 }
710
711 //
712 // Increments/decrements the reference counter for the operands of a call 
713 // node. If "flag" is true, it increments the counter. Otherwise, it 
714 // decrements it.
715 //
716 void AstNode::updateOperandsRC(bool flag)
717 {
718   if (type==callNode) {
719     for (unsigned i=0;i<operands.size();i++) {
720       if (operands[i]) {
721         if (flag) operands[i]->referenceCount++;
722         else operands[i]->referenceCount--;
723       }
724     }
725   }
726 }
727
728 //
729 // This procedure should be use every time we assign an AstNode pointer,
730 // because it increments the reference counter.
731 //
732 AstNode *assignAst(AstNode *src) {
733   if (src) {
734     src->referenceCount++;
735     src->updateOperandsRC(true);
736   }
737   return(src);
738 }
739
740 //
741 // Decrements the reference count for "ast". If it is "0", it calls the 
742 // AstNode destructor.
743 //
744 void removeAst(AstNode *&ast) {
745   if (ast) {
746     assert(ast->referenceCount>0);
747     ast->referenceCount--;
748     if (ast->referenceCount==0) {
749       delete ast;
750       ast=NULL;
751     } else {
752       ast->updateOperandsRC(false);
753     }
754   }
755 }
756
757 //
758 // This procedure decrements the reference count for "ast" until it is 0.
759 //
760 void terminateAst(AstNode *&ast) {
761   while (ast) {
762     removeAst(ast);
763   }
764 }
765
766 int AstNode::generateTramp(process *proc, char *i, 
767                            unsigned &count, 
768                            int &trampCost, bool noCost) {
769     static AstNode *trailer=NULL;
770     if (!trailer) trailer = new AstNode(trampTrailer); // private constructor
771                                                        // used to estimate cost
772     static AstNode *preambleTemplate=NULL;
773     if (!preambleTemplate) {
774       AstNode *tmp1 = new AstNode(Constant, (void *) 0);
775       preambleTemplate = new AstNode(trampPreamble, tmp1);
776       removeAst(tmp1);
777     }
778     // private constructor; assumes NULL for right child
779     
780     trampCost = preambleTemplate->cost() + cost() + trailer->cost();
781     int cycles = trampCost;
782
783     AstNode *preamble, *tmp2;
784     tmp2 = new AstNode(Constant, (void *) cycles);
785     preamble = new AstNode(trampPreamble, tmp2); 
786     removeAst(tmp2);
787     // private constructor; assumes NULL for right child
788
789     initTramps(); // needed to initialize regSpace below
790                   // shouldn't we do a "delete regSpace" first to avoid
791                   // leaking memory?
792
793     regSpace->resetSpace();
794     reg return_reg;
795     if (type != opCodeNode || op != noOp) {
796         reg tmp;
797         preamble->generateCode(proc, regSpace, i, count, noCost);
798         removeAst(preamble);
799         tmp = generateCode(proc, regSpace, i, count, noCost);
800         regSpace->freeRegister(tmp);
801         return_reg = trailer->generateCode(proc, regSpace, i, count, noCost);
802     } else {
803         removeAst(preamble);
804         return_reg = (unsigned) emit(op, 1, 0, 0, i, count, noCost);
805     }
806     regSpace->resetSpace();
807     return(return_reg);
808 }
809
810 bool isPowerOf2(int value, int &result)
811 {
812   if (value<=0) return(false);
813   if (value==1) {
814     result=0;
815     return(true);
816   }
817   if ((value%2)!=0) return(false);
818   if (isPowerOf2(value/2,result)) {
819     result++;
820     return(true);
821   }
822   else return(false);
823 }
824
825 void AstNode::setUseCount(void)
826 {
827   useCount++;
828   if (useCount>1) return;
829   kept_register=-1;
830   if (loperand) loperand->setUseCount();
831   if (roperand) roperand->setUseCount();
832 }
833
834 void AstNode::cleanUseCount(void)
835 {
836   useCount=0;
837   kept_register=-1;
838   if (loperand) loperand->cleanUseCount();
839   if (roperand) roperand->cleanUseCount();
840 }
841
842 #if defined(ASTDEBUG)
843 void AstNode::printUseCount(void)
844 {
845   static int i=0;
846   i++;
847   sprintf(errorLine,"(%d)=>useCount is %d\n",i,useCount);
848   logLine(errorLine);
849   if (loperand) {
850     sprintf(errorLine,"(%d)=>loperand\n",i);
851     logLine(errorLine);
852     loperand->printUseCount();
853   }
854   if (roperand) {
855     sprintf(errorLine,"(%d)=>roperand\n",i);
856     logLine(errorLine);
857     roperand->printUseCount();  
858   }
859 }
860 #endif
861
862 //
863 // This procedure generates code for an AST DAG. If there is a sub-graph
864 // being shared between more than 1 node, then the code is generated only
865 // once for this sub-graph and the register where the return value of the
866 // sub-graph is stored, is kept allocated until the last node sharing the
867 // sub-graph has used it (freeing it afterwards). A count called "useCount"
868 // is used to determine whether a particular node or sub-graph is being
869 // shared. At the end of the call to generate code, this count must be 0
870 // for every node. Another important issue to notice is that we have to make
871 // sure that if a node is not calling generate code recursively for either
872 // its left or right operands, we then need to make sure that we update the
873 // "useCount" for these nodes (otherwise we might be keeping registers
874 // allocated without reason). 
875 //
876 // This code was modified in order to set the proper "useCount" for every
877 // node in the DAG before calling the original generateCode procedure (now
878 // generateCode_phase2). This means that we are traversing the DAG twice,
879 // but with the advantage of potencially generating more efficient code.
880 //
881 // Note: a complex Ast DAG might require more registers than the ones 
882 // currently available. In order to fix this problem, we will need to 
883 // implement a "virtual" register allocator - naim 11/06/96
884 //
885 reg AstNode::generateCode(process *proc,
886                           registerSpace *rs,
887                           char *insn, 
888                           unsigned &base, bool noCost) {
889   cleanUseCount();
890   setUseCount();
891   reg tmp=generateCode_phase2(proc,rs,insn,base,noCost);
892   return(tmp);
893 }
894
895 reg AstNode::generateCode_phase2(process *proc,
896                                  registerSpace *rs,
897                                  char *insn, 
898                                  unsigned &base, bool noCost) {
899     unsigned addr;
900     unsigned fromAddr;
901     unsigned startInsn;
902     reg src1, src2;
903     reg src = -1;
904     reg dest = -1;
905     reg right_dest = -1;
906
907     useCount--;
908     if (kept_register>=0) {
909 #if defined(ASTDEBUG)
910       sprintf(errorLine,"==> Returning register %d <==\n",kept_register);
911       logLine(errorLine);
912 #endif
913       if (useCount==0) {
914         rs->unkeep_register(kept_register);
915         reg tmp=kept_register;
916         kept_register=-1;
917         return(tmp);
918       }
919       return(kept_register);
920     }
921
922     if (type == opCodeNode) {
923         if (op == ifOp) {
924             // This ast cannot be shared because it doesn't return a register
925             src = loperand->generateCode_phase2(proc, rs, insn, base, noCost);
926             startInsn = base;
927             fromAddr = emit(op, src, (reg) 0, (reg) 0, insn, base, noCost);
928             rs->freeRegister(src);
929             reg tmp = roperand->generateCode_phase2(proc, rs, insn, base, noCost);
930             rs->freeRegister(tmp);
931
932             // call emit again now with correct offset.
933             (void) emit(op, src, (reg) 0, (reg) ((int)base - (int)fromAddr), 
934                         insn, startInsn, noCost);
935             // sprintf(errorLine,branch forward %d\n", base - fromAddr);
936         } else if (op == storeOp) {
937             // This ast cannot be shared because it doesn't return a register
938             // Check loperand because we are not generating code for it on
939             // this node.
940             loperand->useCount--;
941             if (loperand->useCount==0 && loperand->kept_register>=0) {
942               rs->unkeep_register(loperand->kept_register);
943               loperand->kept_register=-1;
944             }
945             src1 = roperand->generateCode_phase2(proc, rs, insn, base, noCost);
946             src2 = rs->allocateRegister(insn, base, noCost);
947             addr = (unsigned) loperand->oValue;
948             assert(addr != 0); // check for NULL
949             (void) emit(op, src1, src2, (reg) addr, insn, base, noCost);
950             rs->freeRegister(src1);
951             rs->freeRegister(src2);
952         } else if (op == storeIndirOp) {
953             src1 = roperand->generateCode_phase2(proc, rs, insn, base, noCost);
954             dest = loperand->generateCode_phase2(proc, rs, insn, base, noCost);
955             (void) emit(op, src1, 0, dest, insn, base, noCost);          
956             rs->freeRegister(src1);
957             rs->freeRegister(dest);
958         } else if (op == trampTrailer) {
959             // This ast cannot be shared because it doesn't return a register
960             return((unsigned) emit(op, 0, 0, 0, insn, base, noCost));
961         } else if (op == trampPreamble) {
962             // This ast cannot be shared because it doesn't return a register
963 #ifdef i386_unknown_solaris2_5
964             // loperand is a constant AST node with the cost, in cycles.
965             int cost = noCost ? 0 : (int) loperand->oValue;
966             int costAddr = 0; // for now... (won't change if noCost is set)
967             loperand->useCount--;
968
969 #ifndef SHM_SAMPLING
970             bool err;
971             costAddr = proc->findInternalAddress("DYNINSTobsCostLow", true, err);
972             if (err) {
973 //              logLine("Internal error: unable to find addr of DYNINSTobsCostLow\n");
974                 showErrorCallback(79, "");
975                 P_abort();
976             }
977 #else
978             if (!noCost)
979                costAddr = (int)proc->getObsCostLowAddrInApplicSpace();
980 #endif
981             return (unsigned) emit(op, 0, 0, 0, insn, base, noCost);
982 #endif
983         } else {
984             AstNode *left = assignAst(loperand);
985             AstNode *right = assignAst(roperand);
986
987             if (left && right) {
988               if (left->type == operandNode && left->oType == Constant) {
989                 if (type == opCodeNode) {
990                   if (op == plusOp) {
991                     AstNode *temp = assignAst(right);
992                     right = assignAst(left);
993                     left = assignAst(temp);
994                     removeAst(temp);
995                   } else if (op == timesOp) {
996                     if (right->type == operandNode) {
997                       if (right->oType != Constant) {
998                         AstNode *temp = assignAst(right);
999                         right = assignAst(left);
1000                         left = assignAst(temp);
1001                         removeAst(temp);
1002                       }
1003                       else {
1004                         int result;
1005                         if (!isPowerOf2((int)right->oValue,result) &&
1006                              isPowerOf2((int)left->oValue,result))
1007                         {
1008                           AstNode *temp = assignAst(right);
1009                           right = assignAst(left);
1010                           left = assignAst(temp);
1011                           removeAst(temp);
1012                         }
1013                       }
1014                     }
1015                   }
1016                 }
1017               }
1018             }
1019
1020             if (left)
1021               src = left->generateCode_phase2(proc, rs, insn, base, noCost);
1022
1023             rs->freeRegister(src);
1024             dest = rs->allocateRegister(insn, base, noCost);
1025             if (useCount>0) {
1026               kept_register=dest;
1027               rs->keep_register(dest);
1028             }
1029
1030             if (right && (right->type == operandNode) &&
1031                 (right->oType == Constant) &&
1032                 doNotOverflow((int)right->oValue) &&
1033                 (type == opCodeNode))
1034             {
1035               emitImm(op, src, (reg)right->oValue, dest, insn, base, noCost);
1036               right->useCount--;
1037               if (right->useCount==0 && right->kept_register>=0) {
1038                 rs->unkeep_register(right->kept_register);
1039                 right->kept_register=-1;
1040               }
1041             }
1042             else {
1043               if (right)
1044                 right_dest = right->generateCode_phase2(proc, rs, insn, base, noCost);
1045               rs->freeRegister(right_dest);
1046               (void) emit(op, src, right_dest, dest, insn, base, noCost);
1047             }
1048             removeAst(left);
1049             removeAst(right);
1050         }
1051     } else if (type == operandNode) {
1052         dest = rs->allocateRegister(insn, base, noCost);
1053         if (useCount>0) {
1054           kept_register=dest;
1055           rs->keep_register(dest);
1056         }
1057         if (oType == Constant) {
1058             (void) emit(loadConstOp, (reg) oValue, dest, dest, insn, base, noCost);
1059         } else if (oType == ConstantPtr) {
1060             (void) emit(loadConstOp, (reg) (*(unsigned int *) oValue),
1061                 dest, dest, insn, base, noCost);
1062         } else if (oType == DataPtr) {
1063             addr = (unsigned) oValue;
1064             assert(addr != 0); // check for NULL
1065             (void) emit(loadConstOp, (reg) addr, dest, dest, insn, base, noCost);
1066         } else if (oType == DataIndir) {
1067             src = loperand->generateCode_phase2(proc, rs, insn, base, noCost);
1068             (void) emit(loadIndirOp, src, 0, dest, insn, base, noCost); 
1069             rs->freeRegister(src);
1070         } else if (oType == DataReg) {
1071             rs->unkeep_register(dest);
1072             rs->freeRegister(dest);
1073             dest = (reg)oValue;
1074             if (useCount>0) {
1075               kept_register=dest;
1076               rs->keep_register(dest);
1077             }
1078         } else if (oType == DataId) {
1079             (void) emit(loadConstOp, (reg) oValue, dest, dest, insn, base, noCost);
1080         } else if (oType == DataValue) {
1081             addr = (unsigned) oValue;
1082
1083             assert(addr != 0); // check for NULL
1084             (void) emit(loadOp, (reg) addr, dest, dest, insn, base, noCost);
1085         } else if (oType == ReturnVal) {
1086             rs->unkeep_register(dest);
1087             rs->freeRegister(dest);
1088             src = rs->allocateRegister(insn, base, noCost);
1089 #if defined(sparc_sun_sunos4_1_3) || defined(sparc_sun_solaris2_4)  
1090             if (loperand) {
1091                 unsigned emitOptReturn(unsigned, reg, char *, unsigned &, bool);
1092                 dest = emitOptReturn(loperand -> oValue, src, insn, base, noCost);
1093             }
1094             else if (astFlag)
1095                 dest = emit(getSysRetValOp, 0, 0, src, insn, base, noCost);
1096             else 
1097 #endif
1098                 dest = emit(getRetValOp, 0, 0, src, insn, base, noCost);
1099             if (useCount>0) {
1100               kept_register=dest;
1101               rs->keep_register(dest);
1102             }
1103             if (src != dest) {
1104                 rs->freeRegister(src);
1105             }
1106         } else if (oType == Param) {
1107             rs->unkeep_register(dest);
1108             rs->freeRegister(dest);
1109             src = rs->allocateRegister(insn, base, noCost);
1110             // return the actual reg it is in.
1111 #if defined(sparc_sun_sunos4_1_3) || defined(sparc_sun_solaris2_4)  
1112             if (astFlag)
1113                 dest = emit(getSysParamOp, (reg)oValue, 0, src, insn, base, noCost);
1114             else 
1115 #endif
1116                 dest = emit(getParamOp, (reg)oValue, 0, src, insn, base, noCost);
1117             if (useCount>0) {
1118               kept_register=dest;
1119               rs->keep_register(dest);
1120             }
1121             if (src != dest) {
1122                 rs->freeRegister(src);
1123             }
1124         } else if (oType == DataAddr) {
1125           addr = (unsigned) oValue;
1126           emit(loadOp, (reg) addr, dest, dest, insn, base, noCost);
1127         } else if (oType == ConstantString) {
1128           // XXX This is for the string type.  If/when we fix the string type
1129           // to make it less of a hack, we'll need to change this.
1130           int len = strlen((char *)oValue) + 1;
1131           addr = (unsigned) inferiorMalloc(proc, len, dataHeap);
1132           proc->writeDataSpace((char *)addr, len, (char *)oValue);
1133           emit(loadConstOp, (reg) addr, dest, dest, insn, base, noCost);
1134         }
1135     } else if (type == callNode) {
1136         dest = emitFuncCall(callOp, rs, insn, base, operands, callee, proc, noCost);
1137         if (useCount>0) {
1138           kept_register=dest;
1139           rs->keep_register(dest);
1140         }
1141     } else if (type == sequenceNode) {
1142         (void) loperand->generateCode_phase2(proc, rs, insn, base, noCost);
1143         return(roperand->generateCode_phase2(proc, rs, insn, base, noCost));
1144     }
1145
1146     return(dest);
1147 }
1148
1149
1150 #if defined(ASTDEBUG)
1151 string getOpString(opCode op)
1152 {
1153     switch (op) {
1154         case plusOp: return("+");
1155         case minusOp: return("-");
1156         case timesOp: return("*");
1157         case divOp: return("/");
1158         case lessOp: return("<");
1159         case leOp: return("<=");
1160         case greaterOp: return(">");
1161         case geOp: return(">=");
1162         case eqOp: return("==");
1163         case neOp: return("!=");
1164         case loadOp: return("lda");
1165         case loadConstOp: return("load");
1166         case storeOp: return("=");
1167         case ifOp: return("if");
1168         case trampPreamble: return("preTramp");
1169         case trampTrailer: return("goto");
1170         case noOp: return("nop");
1171         case andOp: return("and");
1172         case orOp: return("or");
1173         case loadIndirOp: return("load&");
1174         case storeIndirOp: return("=&");
1175         default: return("ERROR");
1176     }
1177 }
1178 #endif
1179
1180 int AstNode::cost() const {
1181     int total = 0;
1182     int getInsnCost(opCode t);
1183
1184     if (type == opCodeNode) {
1185         if (op == ifOp) {
1186             if (loperand) total += loperand->cost();
1187             total += getInsnCost(op);
1188             if (roperand) total += roperand->cost();
1189         } else if (op == storeOp) {
1190             if (roperand) total += roperand->cost();
1191             total += getInsnCost(op);
1192         } else if (op == storeIndirOp) {
1193             if (loperand) total += loperand->cost();
1194             if (roperand) total += roperand->cost();
1195             total += getInsnCost(op);
1196         } else if (op == trampTrailer) {
1197             total = getInsnCost(op);
1198         } else if (op == trampPreamble) {
1199             total = getInsnCost(op);
1200         } else {
1201             if (loperand) 
1202                 total += loperand->cost();
1203             if (roperand) 
1204                 total += roperand->cost();
1205             total += getInsnCost(op);
1206         }
1207     } else if (type == operandNode) {
1208         if (oType == Constant) {
1209             total = getInsnCost(loadConstOp);
1210         } else if (oType == DataPtr) {
1211             total = getInsnCost(loadConstOp);
1212         } else if (oType == DataValue) {
1213             total = getInsnCost(loadOp);
1214         } else if (oType == DataId) {
1215             total = getInsnCost(loadConstOp);
1216         } else if (oType == DataIndir) {
1217             total = getInsnCost(loadIndirOp);
1218             total += loperand->cost();
1219         } else if (oType == DataReg) {
1220             total = getInsnCost(loadIndirOp);
1221         } else if (oType == Param) {
1222             total = getInsnCost(getParamOp);
1223         }
1224     } else if (type == callNode) {
1225         total = getPrimitiveCost(callee);
1226         for (unsigned u = 0; u < operands.size(); u++)
1227           if (operands[u]) total += operands[u]->cost();
1228     } else if (type == sequenceNode) {
1229         if (loperand) total += loperand->cost();
1230         if (roperand) total += roperand->cost();
1231     }
1232     return(total);
1233 }
1234
1235 #if defined(ASTDEBUG)
1236 void AstNode::print() const {
1237     if (type == operandNode) {
1238         if (oType == Constant) {
1239             sprintf(errorLine, " %d", (int) oValue);
1240             logLine(errorLine);
1241         } else if (oType == DataPtr) {
1242             sprintf(errorLine, " %d", (int) oValue);
1243             logLine(errorLine);
1244         } else if (oType == DataValue) {
1245             sprintf(errorLine, "@%d", (int) oValue);
1246             logLine(errorLine);
1247         } else if (oType == DataIndir) {
1248             logLine("@[");
1249             loperand->print();
1250             logLine("]");
1251         } else if (oType == DataReg) {
1252             sprintf(errorLine," reg%d ",(int)oValue);
1253             logLine(errorLine);
1254             loperand->print();
1255         } else if (oType == Param) {
1256             sprintf(errorLine, "param[%d]", (int) oValue);
1257             logLine(errorLine);
1258         }
1259     } else if (type == opCodeNode) {
1260         ostrstream os(errorLine, 1024, ios::out);
1261         os << "(" << getOpString(op) << ends;
1262         logLine(errorLine);
1263         if (loperand) loperand->print();
1264         if (roperand) roperand->print();
1265         logLine(")");
1266     } else if (type == callNode) {
1267         ostrstream os(errorLine, 1024, ios::out);
1268         os << "(" << callee << ends;
1269         logLine(errorLine);
1270         for (unsigned u = 0; u < operands.size(); u++)
1271           operands[u]->print();
1272         logLine(")");
1273     } else if (type == sequenceNode) {
1274         if (loperand) loperand->print();
1275         logLine(",");
1276         if (roperand) roperand->print();
1277     }
1278 }
1279 #endif
1280
1281 AstNode *createIf(AstNode *expression, AstNode *action) 
1282 {
1283   AstNode *t;
1284   t = new AstNode(ifOp, expression, action);
1285   return(t);
1286 }
1287
1288 #ifndef BPATCH_LIBRARY
1289
1290 // Multithreaded case with shared memory sampling
1291
1292 #if defined(SHM_SAMPLING) && defined(MT_THREAD)
1293
1294 AstNode *computeAddress(void *level, void *index, int type)
1295 {
1296   AstNode *t0=NULL,*t1=NULL,*t2=NULL,*t3=NULL;
1297   AstNode *t4=NULL,*t5=NULL,*t6=NULL,*t7=NULL;
1298   AstNode *t8=NULL,*t9=NULL,*t10=NULL,*t11=NULL;
1299   int tSize;
1300
1301   /* DYNINSTthreadTable[0][thr_self()] */
1302   t0 = new AstNode(AstNode::DataReg, (void *)REG_MT);
1303
1304   /* Now we compute the offset for the corresponding level. We assume */
1305   /* that the DYNINSTthreadTable is stored by rows - naim 4/18/97 */
1306   if ((int)level != 0) {
1307     tSize = sizeof(unsigned);
1308     t1 = new AstNode(AstNode::Constant, (void *)MAX_NUMBER_OF_THREADS);
1309     t2 = new AstNode(AstNode::Constant, level);
1310     t3 = new AstNode(timesOp, t1, t2);
1311     t4 = new AstNode(AstNode::Constant, (void *)tSize);
1312     t5 = new AstNode(timesOp, t3, t4); /* offset including just level */
1313
1314     /* Given the level and tid, we compute the position in the thread */
1315     /* table. */
1316     t6 = new AstNode(plusOp, t0, t5);
1317
1318     /* We then read the address, which is really the base address of the */
1319     /* vector of counters and timers in the shared memory segment. */
1320     t7 = new AstNode(AstNode::DataIndir, t6); 
1321   } else {
1322     /* if level is 0, we don't need to compute the offset */
1323     t7 = new AstNode(AstNode::DataIndir, t0);
1324   }
1325
1326   /* Finally, using the index as an offset, we compute the address of the */
1327   /* counter/timer. */
1328   if (type==0) {
1329     /* intCounter */
1330     tSize = sizeof(intCounter);
1331   } else {
1332     /* Timer */
1333     tSize = sizeof(tTimer);
1334   }
1335   t8 = new AstNode(AstNode::Constant, (void *)index);
1336   t9 = new AstNode(AstNode::Constant, (void *)tSize);
1337   t10 = new AstNode(timesOp, t8, t9);
1338   t11 = new AstNode(plusOp, t7, t10); /* address of counter/timer */
1339
1340   removeAst(t0);
1341   removeAst(t1);
1342   removeAst(t2);
1343   removeAst(t3);
1344   removeAst(t4);
1345   removeAst(t5);
1346   removeAst(t6);
1347   removeAst(t7);
1348   removeAst(t8);
1349   removeAst(t9);
1350   removeAst(t10);
1351   return(t11);
1352 }
1353
1354 AstNode *createTimer(const string &func, void *level, void *index,
1355                      vector<AstNode *> &ast_args)
1356 {
1357   AstNode *t0=NULL,*t1=NULL;
1358
1359   t0 = computeAddress(level,index,1); /* 1 means tTimer */
1360   ast_args += assignAst(t0);
1361   removeAst(t0);
1362   t1 = new AstNode(func, ast_args);
1363   for (unsigned i=0;i<ast_args.size();i++) removeAst(ast_args[i]);  
1364
1365   return(t1);
1366 }
1367
1368 AstNode *createCounter(const string &func, void *level, void *index, 
1369                        AstNode *ast) 
1370
1371   AstNode *t0=NULL,*t1=NULL,*t2=NULL,*t3=NULL;
1372
1373   t0 = computeAddress(level,index,0); /* 0 means intCounter */
1374
1375   if (func == "addCounter") {
1376     t1 = new AstNode(AstNode::DataIndir, t0);
1377     t2 = new AstNode(plusOp, t1, ast);
1378     t3 = new AstNode(storeIndirOp, t0, t2);
1379   } else if (func == "subCounter") {
1380     t1 = new AstNode(AstNode::DataIndir, t0);
1381     t2 = new AstNode(minusOp, t1, ast);
1382     t3 = new AstNode(storeIndirOp, t0, t2);
1383   } else if (func == "setCounter") {
1384     t3 = new AstNode(storeIndirOp, t0, ast);
1385   }
1386
1387   removeAst(t0);
1388   removeAst(t1);
1389   removeAst(t2);
1390
1391   return(t3);
1392 }
1393
1394 #else
1395
1396 // Single threaded case
1397
1398 AstNode *createTimer(const string &func, void *dataPtr, 
1399                      vector<AstNode *> &ast_args)
1400 {
1401   AstNode *t0=NULL,*t1=NULL;
1402
1403   t0 = new AstNode(AstNode::DataPtr, (void *) dataPtr);
1404   ast_args += assignAst(t0);
1405   removeAst(t0);
1406   t1 = new AstNode(func, ast_args);
1407   for (unsigned i=0;i<ast_args.size();i++) removeAst(ast_args[i]);  
1408   return(t1);
1409 }
1410
1411 AstNode *createCounter(const string &func, void *dataPtr, 
1412                        AstNode *ast) 
1413 {
1414    AstNode *t0=NULL, *t1=NULL, *t2=NULL;
1415
1416    t0 = new AstNode(AstNode::DataValue, (void *)dataPtr);
1417    if (func=="addCounter") {
1418      t1 = new AstNode(plusOp,t0,ast);
1419      t2 = new AstNode(storeOp,t0,t1);
1420    } else if (func=="subCounter") {
1421      t1 = new AstNode(minusOp,t0,ast);
1422      t2 = new AstNode(storeOp,t0,t1);
1423    } else if (func=="setCounter") {
1424      t2 = new AstNode(storeOp,t0,ast);
1425    } else abort();
1426    removeAst(t0);
1427    removeAst(t1);
1428    return(t2);
1429 }
1430
1431 #endif
1432 #endif
1433
1434 #ifdef BPATCH_LIBRARY
1435 BPatch_type *AstNode::checkType()
1436 {
1437     BPatch_type *ret = NULL;
1438     BPatch_type *lType = NULL, *rType = NULL;
1439     bool errorFlag = false;
1440
1441     assert(BPatch::bpatch != NULL);     /* We'll use this later. */
1442
1443     assert( (!loperand && !roperand) || getType() == NULL );
1444
1445     if (loperand)
1446         lType = loperand->checkType();
1447
1448     if (roperand)
1449         rType = roperand->checkType();
1450
1451     if (lType == BPatch::bpatch->type_Error ||
1452         rType == BPatch::bpatch->type_Error)
1453         errorFlag = true;
1454
1455     
1456     switch (type) { // Type here is nodeType, not BPatch library type
1457         case sequenceNode:
1458             ret = rType;
1459             break;
1460         case opCodeNode:
1461             if (lType != NULL && rType != NULL) {
1462                 if (!lType->isCompatible(*rType)) {
1463                     errorFlag = true;
1464                 }
1465             }
1466             // XXX The following line must change to decide based on the types
1467             // and operation involved what the return type of the expression
1468             // will be.
1469             ret = lType;
1470             break;
1471         case operandNode:
1472             assert(loperand == NULL && roperand == NULL);
1473             if (oType == Param)
1474                 ret = BPatch::bpatch->type_Untyped; //XXX Params untyped for now
1475             else
1476                 ret = getType();
1477             assert(ret != NULL);
1478             break;
1479         case callNode:
1480             for (int i = 0; i < operands.size(); i++) {
1481                 BPatch_type *operandType = operands[i]->checkType();
1482                 /* XXX Check operands for compatibility */
1483                 if (operandType == BPatch::bpatch->type_Error)
1484                     errorFlag = true;
1485             }
1486             /* XXX Should set to return type of function. */
1487             ret = BPatch::bpatch->type_Untyped;
1488             break;
1489       default:
1490         assert(0);
1491     }
1492
1493     assert(ret != NULL);
1494
1495     if (errorFlag && doTypeCheck) {
1496         ret = BPatch::bpatch->type_Error;
1497     }
1498
1499     return ret;
1500 }
1501 #endif