*** empty log message ***
[dyninst.git] / dyninstAPI / src / inst-sparc.h
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 #if !defined(sparc_sun_sunos4_1_3) && !defined(sparc_sun_solaris2_4)
43 #error "invalid architecture-os inclusion"
44 #endif
45
46 #ifndef INST_SPARC_H
47 #define INST_SPARC_H
48
49 #include "util/h/headers.h"
50 #ifndef BPATCH_LIBRARY
51 #include "rtinst/h/rtinst.h"
52 #endif
53 #include "dyninstAPI/src/symtab.h"
54 #include "dyninstAPI/src/process.h"
55 #include "dyninstAPI/src/inst.h"
56 #include "dyninstAPI/src/ast.h"
57 //#include "dyninstAPI/src/inst-sparc.h"
58 #include "dyninstAPI/src/arch-sparc.h"
59 #include "dyninstAPI/src/util.h"
60 #include "dyninstAPI/src/stats.h"
61 #include "dyninstAPI/src/os.h"
62 #include "paradynd/src/showerror.h"
63 #include "dyninstAPI/src/as-sparc.h"
64 #include "dyninstAPI/src/instP.h"
65
66 #define REG_MT               23   /* register saved to keep the address of */
67                                   /* the current vector of counter/timers  */
68                                   /* for each thread.                      */
69 #define NUM_INSN_MT_PREAMBLE  9   /* number of instructions required for   */
70                                   /* the MT preamble.                      */ 
71
72 // NOTE: LOW() and HIGH() can return ugly values if x is negative, because in
73 // that case, 2's complement has really changed the bitwise representation!
74 // Perhaps an assert should be done!
75 #define LOW10(x) ((x) & 0x3ff)
76 #define LOW13(x) ((x) & 0x1fff)
77 #define HIGH22(x) ((x) >> 10)
78
79 inline unsigned ABS(int x) {
80    if (x < 0) return -x;
81    return x;
82 }
83 //#define ABS(x)                ((x) > 0 ? x : -x)
84
85 //#define MAX_BRANCH    (0x1<<23)
86
87 #define MAX_IMM13       (4095)
88 #define MIN_IMM13       (-4096)
89
90
91 #define REG_G0          0
92 #define REG_G5          5
93 #define REG_G6          6
94 #define REG_G7          7
95
96 #define REG_O7          15
97
98 #define REG_L0          16
99 #define REG_L1          17
100 #define REG_L2          18
101
102 #define REG_SP          14
103 #define REG_FP          30
104
105 extern "C" void baseTramp();
106 extern trampTemplate baseTemplate;
107 extern registerSpace *regSpace;
108 extern int deadList[];
109
110 #define NEW_INSTR_ARRAY_LEN 1024
111 extern instruction newInstr[NEW_INSTR_ARRAY_LEN];
112
113 // amount of expansion for relocated functions....
114 #define RELOCATED_FUNC_EXTRA_SPACE 36
115
116 class instPoint;
117
118 inline unsigned getMaxBranch3Insn() {
119    // The length we can branch using 3 instructions
120    // isn't limited.
121    unsigned result = 1;
122    result <<= 31;
123    return result;
124
125    // probably returning ~0 would be better, since there's no limit
126 }
127
128 //inline unsigned getMaxBranch1Insn() {
129 //   // The length we can branch using just 1 instruction is dictated by the
130 //   // sparc instruction set.
131 //   return (0x1 << 23);
132 //}
133
134 inline bool offsetWithinRangeOfBranchInsn(int offset) {
135    // The pc-relative offset range which we can branch to with a single sparc
136    // branch instruction is dictated by the sparc instruction set.
137    // There are 22 bits available...however, you really get 2 extra bits
138    // because the CPU multiplies the 22-bit signed offset by 4.
139    // The only downside is that the offset must be a multiple of 4, which we check.
140    unsigned abs_offset = ABS(offset);
141    assert(abs_offset % 4 == 0);
142
143    // divide by 4.  After the divide, the result must fit in 22 bits.
144    offset /= 4;
145
146    const int INT22_MAX = 0x1FFFFF; // low 21 bits all 1's, the high bit (#22) is 0
147    const int INT22_MIN = -(INT22_MAX+1); // in 2's comp, negative numbers get 1 extra value
148    assert(INT22_MAX > 0);
149    assert(INT22_MIN < 0);
150
151    if (offset < INT22_MIN)
152       return false;
153    else if (offset > INT22_MAX)
154       return false;
155    else
156       return true;
157 }
158
159 inline bool in1BranchInsnRange(unsigned adr1, unsigned adr2) 
160 {
161     return (abs(adr1-adr2) < (0x1 << 23));
162 }
163
164 inline void generateNOOP(instruction *insn)
165 {
166     insn->raw = 0;
167     insn->branch.op = 0;
168     insn->branch.op2 = NOOPop2;
169
170     // logLine("nop\n");
171 }
172
173 inline void generateBranchInsn(instruction *insn, int offset)
174 {
175     if (!offsetWithinRangeOfBranchInsn(offset)) {
176         char buffer[100];
177         sprintf(buffer, "a Branch too far; offset=%d\n", offset);
178         logLine(buffer);
179         //showErrorCallback(52, "");
180         assert(false && "a Branch too far");
181         return;
182     }
183
184     insn->raw = 0;
185     insn->branch.op = 0;
186     insn->branch.cond = BAcond;
187     insn->branch.op2 = BICCop2;
188     insn->branch.anneal = true;
189     insn->branch.disp22 = offset >> 2;
190
191     // logLine("ba,a %x\n", offset);
192 }
193
194 inline void generateCallInsn(instruction *insn, int fromAddr, int toAddr)
195 {
196     int offset = toAddr - fromAddr;
197     insn->call.op = 01;
198     insn->call.disp30 = offset >> 2;
199 }
200
201 inline void generateJmplInsn(instruction *insn, int rs1, int offset, int rd)
202 {
203     insn->resti.op = 10;
204     insn->resti.rd = rd;
205     insn->resti.op3 = JMPLop3;
206     insn->resti.rs1 = rs1;
207     insn->resti.i = 1;
208     assert(offset >= MIN_IMM13 && offset <= MAX_IMM13);
209     insn->resti.simm13 = offset;
210 }    
211
212 inline void genBranch(instruction *insn, int offset, unsigned condition, bool annul)
213 {
214 //    if (ABS(offset) > getMaxBranch1Insn()) {
215     if (!offsetWithinRangeOfBranchInsn(offset)) {
216         char buffer[80];
217         sprintf(buffer, "a branch too far, offset=%d\n", offset);
218         logLine(buffer);
219         showErrorCallback(52, "");
220         abort();
221     }
222
223     insn->raw = 0;
224     insn->branch.op = 0;
225     insn->branch.cond = condition;
226     insn->branch.op2 = BICCop2;
227     insn->branch.anneal = annul;
228     insn->branch.disp22 = offset >> 2;
229 }
230
231 inline void generateAnnulledBranchInsn(instruction *insn, int offset)
232 {
233     genBranch(insn, offset, BAcond, true);
234 }
235
236
237 inline void genSimpleInsn(instruction *insn, int op, reg rs1, reg rs2, reg rd)
238 {
239     insn->raw = 0;
240     insn->rest.op = RESTop;
241     insn->rest.rd = rd;
242     insn->rest.op3 = op;
243     insn->rest.rs1 = rs1;
244     insn->rest.rs2 = rs2;
245 }
246
247 inline void genBreakpointTrap(instruction *insn) {
248    insn->raw = BREAK_POINT_INSN; // ta (trap always) 1
249 }
250
251 inline void genUnimplementedInsn(instruction *insn) {
252    insn->raw = 0; // UNIMP 0
253 }
254
255 inline void genImmInsn(instruction *insn, int op, reg rs1, int immd, reg rd)
256 {
257     insn->raw = 0;
258     insn->resti.op = RESTop;
259     insn->resti.rd = rd;
260     insn->resti.op3 = op;
261     insn->resti.rs1 = rs1;
262     insn->resti.i = 1;
263     assert(immd >= MIN_IMM13 && immd <= MAX_IMM13);
264     insn->resti.simm13 = immd;
265 }
266
267 inline void genImmRelOp(instruction *insn, int cond, reg rs1,
268                         int immd, reg rd, unsigned &base)
269 {
270     // cmp rs1, rs2
271     genImmInsn(insn, SUBop3cc, rs1, immd, 0); insn++;
272     // mov 1, rd
273     genImmInsn(insn, ORop3, 0, 1, rd); insn++;
274
275     // b??,a +2
276     insn->branch.op = 0;
277     insn->branch.cond = cond;
278     insn->branch.op2 = BICCop2;
279     insn->branch.anneal = true;
280     insn->branch.disp22 = 2;
281     insn++;
282
283     // clr rd
284     genImmInsn(insn, ORop3, 0, 0, rd); insn++; 
285     //genSimpleInsn(insn, ORop3, 0, 0, rd); insn++;
286     base += 4 * sizeof(instruction);
287 }
288
289 inline void genRelOp(instruction *insn, int cond, reg rs1,
290                      reg rs2, reg rd, unsigned &base)
291 {
292     // cmp rs1, rs2
293     genSimpleInsn(insn, SUBop3cc, rs1, rs2, 0); insn++;
294     // mov 1, rd
295     genImmInsn(insn, ORop3, 0, 1, rd); insn++;
296
297     // b??,a +2
298     insn->branch.op = 0;
299     insn->branch.cond = cond;
300     insn->branch.op2 = BICCop2;
301     insn->branch.anneal = true;
302     insn->branch.disp22 = 2;
303     insn++;
304
305     // clr rd
306     genImmInsn(insn, ORop3, 0, 0, rd); insn++;
307     //genSimpleInsn(insn, ORop3, 0, 0, rd); insn++;
308     base += 4 * sizeof(instruction);
309 }
310
311 inline void generateSetHi(instruction *insn, int src1, int dest)
312 {
313     insn->raw = 0;
314     insn->sethi.op = FMT2op;
315     insn->sethi.rd = dest;
316     insn->sethi.op2 = SETHIop2;
317     insn->sethi.imm22 = HIGH22(src1);
318 }
319
320 // st rd, [rs1 + offset]
321 inline void generateStore(instruction *insn, int rd, int rs1, int offset)
322 {
323     insn->resti.op = STop;
324     insn->resti.rd = rd;
325     insn->resti.op3 = STop3;
326     insn->resti.rs1 = rs1;
327     insn->resti.i = 1;
328     assert(offset >= MIN_IMM13 && offset <= MAX_IMM13);
329     insn->resti.simm13 = offset;
330 }
331
332 // sll rs1,rs2,rd
333 inline void generateLShift(instruction *insn, int rs1, int offset, int rd)
334 {
335     insn->restix.op = SLLop;
336     insn->restix.op3 = SLLop3;
337     insn->restix.rd = rd;
338     insn->restix.rs1 = rs1;
339     insn->restix.i = 1;
340     insn->restix.x = 0;
341     insn->restix.rs2 = offset;
342 }
343
344 // sll rs1,rs2,rd
345 inline void generateRShift(instruction *insn, int rs1, int offset, int rd)
346 {
347     insn->restix.op = SRLop;
348     insn->restix.op3 = SRLop3;
349     insn->restix.rd = rd;
350     insn->restix.rs1 = rs1;
351     insn->restix.i = 1;
352     insn->restix.x = 0;
353     insn->restix.rs2 = offset;
354 }
355
356 // load [rs1 + offset], rd
357 inline void generateLoad(instruction *insn, int rs1, int offset, int rd)
358 {
359     insn->resti.op = LOADop;
360     insn->resti.op3 = LDop3;
361     insn->resti.rd = rd;
362     insn->resti.rs1 = rs1;
363     insn->resti.i = 1;
364     assert(offset >= MIN_IMM13 && offset <= MAX_IMM13);
365     insn->resti.simm13 = offset;
366 }
367
368 // swap [rs1 + offset], rd
369 inline void generateSwap(instruction *insn, int rs1, int offset, int rd)
370 {
371     insn->resti.op = SWAPop;
372     insn->resti.rd = rd;
373     insn->resti.op3 = SWAPop3;
374     insn->resti.rs1 = rs1;
375     insn->resti.i = 0;
376     assert(offset >= MIN_IMM13 && offset <= MAX_IMM13);
377     insn->resti.simm13 = offset;
378 }    
379
380 // std rd, [rs1 + offset]
381 inline void genStoreD(instruction *insn, int rd, int rs1, int offset)
382 {
383     insn->resti.op = STop;
384     insn->resti.rd = rd;
385     insn->resti.op3 = STDop3;
386     insn->resti.rs1 = rs1;
387     insn->resti.i = 1;
388     assert(offset >= MIN_IMM13 && offset <= MAX_IMM13);
389     insn->resti.simm13 = offset;
390 }
391
392 // ldd [rs1 + offset], rd
393 inline void genLoadD(instruction *insn, int rs1, int offset, int rd)
394 {
395     insn->resti.op = LOADop;
396     insn->resti.op3 = LDDop3;
397     insn->resti.rd = rd;
398     insn->resti.rs1 = rs1;
399     insn->resti.i = 1;
400     assert(offset >= MIN_IMM13 && offset <= MAX_IMM13);
401     insn->resti.simm13 = offset;
402 }
403
404 bool processOptimaRet(instPoint *location, AstNode *&ast);
405
406 extern bool isPowerOf2(int value, int &result);
407 extern void generateNoOp(process *proc, int addr);
408 extern void changeBranch(process *proc, unsigned fromAddr, unsigned newAddr,
409                   instruction originalBranch);
410 extern trampTemplate *findAndInstallBaseTramp(process *proc,
411                                  instPoint *&location, 
412                                  returnInstance *&retInstance, bool noCost);
413
414 extern void  generateBranch(process *proc, unsigned fromAddr, unsigned newAddr);
415 extern void generateCall(process *proc, unsigned fromAddr,unsigned newAddr);
416 extern void genImm(process *proc, Address fromAddr,int op, reg rs1, 
417                    int immd, reg rd);
418 extern int callsTrackedFuncP(instPoint *point);
419 extern pd_Function *getFunction(instPoint *point);
420 extern unsigned emitFuncCall(opCode op, registerSpace *rs, char *i, 
421                              unsigned &base, const vector<AstNode *> &operands,
422                              const string &callee, process *proc, bool noCost);
423
424 extern unsigned emitImm(opCode op, reg src1, reg src2, reg dest, char *i,
425                         unsigned &base, bool noCost);
426
427 extern unsigned emitOptReturn(unsigned, reg, char *, unsigned &, bool);
428
429 extern int getInsnCost(opCode op);
430 extern bool isReturnInsn(const image *owner, Address adr, bool &lastOne);
431 extern void generateMTpreamble(char *insn, unsigned &base, process *proc);
432
433 #endif