1 #include "dill.h"
2 #include "dill_internal.h"
3 #include "sparc.h"
4 #include "config.h"
5 #include <stdio.h>
6 #ifdef HAVE_MALLOC_H
7 #include <malloc.h>
8 #endif
9 #undef NDEBUG
10 #include <assert.h>
11 #include <stdlib.h>
12 #include <string.h>
13
14 #define sparc_save(s, r) sparc_FORM3_arith(s, 0x3c, 0x2, _sp, _sp, r)
15 #define sparc_savei(s, imm) sparc_FORM3imm_arith(s, 0x3c, 0x2, _sp, _sp, imm)
16 #define sparc_sethi(s, r, imm) INSN_OUT(s, HDR(0)|RD(r)|OP2(0x4)|imm)
17 #define sparc_ori(s, dest, src, imm) INSN_OUT(s, HDR(0x2)|OP3(0x2)|IM|RD(dest)|RS1(src)|imm)
18 #define sparc_xori(s, dest, src, imm) INSN_OUT(s, HDR(0x2)|OP3(0x3)|IM|RD(dest)|RS1(src)|imm)
19 #define sparc_andi(s, dest, src, imm) sparc_FORM3imm_arith(s, 0x1, 0, dest, src, imm)
20 #define sparc_or(s, dest, src1, src2) INSN_OUT(s, HDR(0x2)|OP3(0x2)|RD(dest)|RS1(src1)|RS2(src2))
21 #define sparc_movi(s, dest, src) sparc_or(s, dest, src, _g0)
22 #define sparc_int_mov(s, dest, src) sparc_or(s, dest, _g0, src)
23 #define sparc_movf(s, dest, src) INSN_OUT(s, HDR(0x2)|RD(dest)|OP3(0x34)|OPF(1)|RS2(src))
24 #define sparc_movd(s, dest, src) INSN_OUT(s, HDR(0x2)|RD(dest)|OP3(0x34)|OPF(2)|RS2(src))
25 #define sparc_simple_ret(c) INSN_OUT(s, HDR(0x2)|OP3(0x38)|RD(_g0)|RS1(_i7)|IM|SIMM13(0x8))
26 #define sparc_restore(c) INSN_OUT(s, HDR(0x2)|OP3(0x3d)|RD(_g0)|RS1(_g0)|RS2(_g0));
27 #define sparc_lshi(s, dest, src1,imm) INSN_OUT(s, HDR(0x2)|OP3(0x25)|RD(dest)|RS1(src1)|IM|SIMM13(imm));
28 #define sparc_xlshi(s, dest, src1,imm) INSN_OUT(s, HDR(0x2)|OP3(0x25)|RD(dest)|RS1(src1)|IM|SIMM13(imm)|(1<<12) );
29 #define sparc_rshi(s, dest, src1,imm) INSN_OUT(s, HDR(0x2)|OP3(0x26)|RD(dest)|RS1(src1)|IM|SIMM13(imm));
30 #define sparc_xrshi(s, dest, src1,imm) INSN_OUT(s, HDR(0x2)|OP3(0x26)|RD(dest)|RS1(src1)|IM|SIMM13(imm)|(1<<12) );
31 #define sparc_rshai(s, dest, src1,imm) INSN_OUT(s, HDR(0x2)|OP3(0x27)|RD(dest)|RS1(src1)|IM|SIMM13(imm));
32 #define sparc_xrshai(s, dest, src1,imm) INSN_OUT(s, HDR(0x2)|OP3(0x27)|RD(dest)|RS1(src1)|IM|SIMM13(imm)|(1<<12) );
33 #define sparc_rsh(s, dest, src1, src2) INSN_OUT(s, HDR(0x2)|OP3(0x27)|RD(dest)|RS1(src1)|RS2(src2));
34
35 #define sparc_nop(c) INSN_OUT(s, OP2(0x4));
36
37 #define IREG 0
38 #define FREG 1
39
40 #define roundup(a,b) ((a + (b-1)) & (-b))
41
42 static
43 struct basic_type_info
44 { char size;
45 char align;
46 char reg_type;
47 } type_info[] = {
48 { 1, 1, IREG}, /* C */
49 { 1, 1, IREG}, /* UC */
50 { 2, 2, IREG}, /* S */
51 { 2, 2, IREG}, /* US */
52 { 4, 4, IREG}, /* I */
53 { 4, 4, IREG}, /* U */
54 { sizeof(long), sizeof(long), IREG}, /* UL */
55 { sizeof(long), sizeof(long), IREG}, /* L */
56 { sizeof(char*), sizeof(char*), IREG}, /* P */
57 { sizeof(float), sizeof(float), FREG}, /* F */
58 { sizeof(double), sizeof(double), FREG}, /* D */
59 { 0, 8, IREG}, /* V */
60 { -1, 8, IREG}, /* B */
61 { sizeof(long), sizeof(long), IREG}, /* EC */
62 };
63
64 int sparc_type_align[] = {
65 1, /* C */
66 1, /* UC */
67 2, /* S */
68 2, /* US */
69 4, /* I */
70 4, /* U */
71 sizeof(unsigned long), /* UL */
72 sizeof(long), /* L */
73 sizeof(char*), /* P */
74 4, /* F */
75 8, /* D */
76 1, /* V */
77 8, /* B */
78 sizeof(long), /* EC */
79 };
80
81 int sparc_type_size[] = {
82 1, /* C */
83 1, /* UC */
84 2, /* S */
85 2, /* US */
86 4, /* I */
87 4, /* U */
88 sizeof(unsigned long), /* UL */
89 sizeof(long), /* L */
90 sizeof(char*), /* P */
91 4, /* F */
92 8, /* D */
93 1, /* V */
94 8, /* B */
95 sizeof(long), /* EC */
96 };
97
98 extern int
sparc_local(dill_stream s,int type)99 sparc_local(dill_stream s, int type)
100 {
101 sparc_mach_info smi = (sparc_mach_info) s->p->mach_info;
102
103 smi->act_rec_size += roundup(type_info[type].size, smi->stack_align);
104 return (-smi->act_rec_size) + smi->stack_constant_offset;
105 }
106
107 extern int
sparc_localb(dill_stream s,int size)108 sparc_localb(dill_stream s, int size)
109 {
110 sparc_mach_info smi = (sparc_mach_info) s->p->mach_info;
111 if (size < 0) size = 0;
112 smi->act_rec_size = roundup(smi->act_rec_size, size);
113
114 smi->act_rec_size += roundup(size, smi->stack_align);
115 return (-smi->act_rec_size) - 8 + smi->stack_constant_offset;
116 }
117
sparc_local_op(dill_stream s,int flag,int val)118 extern int sparc_local_op(dill_stream s, int flag, int val)
119 {
120 int size = val;
121 if (flag == 0) {
122 size = type_info[val].size;
123 }
124 if (size < 0) size = 0;
125 return sparc_localb(s, size);
126 }
127
128 static int
is_temp(int ireg)129 is_temp(int ireg)
130 {
131 return ((ireg <= _g7) && (ireg >= _g0));
132 }
133
134 extern void
sparc_save_restore_op(dill_stream s,int save_restore,int type,int reg)135 sparc_save_restore_op(dill_stream s, int save_restore, int type, int reg)
136 {
137 sparc_mach_info smi = (sparc_mach_info) s->p->mach_info;
138 if (save_restore == 0) { /* save */
139 switch (type) {
140 case DILL_D: case DILL_F:
141 sparc_pstorei(s, type, 0, reg, _sp, smi->fp_save_offset + reg * smi->stack_align + smi->stack_constant_offset);
142 break;
143 default:
144 if (is_temp(reg)) {
145 sparc_pstorei(s, type, 0, reg, _sp, smi->gp_save_offset + (reg - _g0) * smi->stack_align + smi->stack_constant_offset);
146 }
147 break;
148 }
149 } else { /* restore */
150 switch (type) {
151 case DILL_D: case DILL_F:
152 sparc_ploadi(s, type, 0, reg, _sp, smi->fp_save_offset + reg * smi->stack_align + smi->stack_constant_offset);
153 break;
154 default:
155 if (is_temp(reg)) {
156 sparc_ploadi(s, type, 0, reg, _sp, smi->gp_save_offset + (reg - _g0) * smi->stack_align + smi->stack_constant_offset);
157 }
158 break;
159 }
160 }
161 }
162
163 static void
sparc_movi2f(dill_stream s,int dest,int src)164 sparc_movi2f(dill_stream s, int dest, int src)
165 {
166 sparc_mach_info smi = (sparc_mach_info) s->p->mach_info;
167 sparc_pstorei(s, DILL_I, 0, src, _fp, smi->conversion_word);
168 sparc_ploadi(s, DILL_F, 0, dest, _fp, smi->conversion_word);
169 }
170
171 static void
sparc_movf2i(dill_stream s,int dest,int src)172 sparc_movf2i(dill_stream s, int dest, int src)
173 {
174 sparc_mach_info smi = (sparc_mach_info) s->p->mach_info;
175 sparc_pstorei(s, DILL_F, 0, src, _fp, smi->conversion_word);
176 sparc_ploadi(s, DILL_I, 0, dest, _fp, smi->conversion_word);
177 }
178
179 static void
sparc_movd2i(dill_stream s,int dest,int src)180 sparc_movd2i(dill_stream s, int dest, int src)
181 {
182 sparc_mach_info smi = (sparc_mach_info) s->p->mach_info;
183 sparc_pstorei(s, DILL_D, 0, src, _fp, smi->conversion_word);
184 if (smi->stack_align == 8) {
185 sparc_ploadi(s, DILL_L, 0, dest, _fp, smi->conversion_word);
186 } else {
187 sparc_ploadi(s, DILL_I, 0, dest, _fp, smi->conversion_word);
188 sparc_ploadi(s, DILL_I, 0, dest+1, _fp, smi->conversion_word+4);
189 }
190 }
191
192 static void
sparc_movi2d(dill_stream s,int dest,int src)193 sparc_movi2d(dill_stream s, int dest, int src)
194 {
195 sparc_mach_info smi = (sparc_mach_info) s->p->mach_info;
196 if (smi->stack_align == 8) {
197 sparc_pstorei(s, DILL_L, 0, src, _fp, smi->conversion_word);
198 } else {
199 sparc_pstorei(s, DILL_I, 0, src, _fp, smi->conversion_word);
200 sparc_pstorei(s, DILL_I, 0, src+1, _fp, smi->conversion_word+4);
201 }
202 sparc_ploadi(s, DILL_D, 0, dest, _fp, smi->conversion_word);
203 }
204
205 /*
206 * sparc stack frame organization
207 * HIGH MEMORY
208 *
209 * %fp (old sp) -> -------------------------
210 * %fp -offset automatic arrays, aggregates
211 * and scalar automatic (local vars)
212 * -------------------------
213 * alloca space (if any)
214 * -------------------------
215 * %sp + offset compiler temps + saved float regs
216 * -------------------------
217 * %sp + offset outgoing parameters past the 6th (if any)
218 * -------------------------
219 * %sp + offset 6 words into which callee may store reg args
220 * -------------------------
221 * %sp + offset one word hidden parameter
222 * -------------------------
223 * %sp + offset 16 words in which to save register window
224 * %sp -> -------------------------
225 * |
226 * V stack growth
227 * LOW MEMORY
228 */
229
230
231 extern void sparc_FORM3_arith(s, sparc_op3, use_ext_form, dest, src1, src2)
232 dill_stream s;
233 int sparc_op3;
234 int use_ext_form;
235 int dest;
236 int src1;
237 int src2;
238 {
239 sparc_mach_info smi = (sparc_mach_info) s->p->mach_info;
240 /* format 3 */
241 if ((smi->stack_align == 8) && use_ext_form) {
242 INSN_OUT(s, HDR(0x2)|OP3(sparc_op3)|1<<12|RD(dest)|RS1(src1)|RS2(src2));
243 } else {
244 INSN_OUT(s, HDR(0x2)|OP3(sparc_op3)|RD(dest)|RS1(src1)|RS2(src2));
245 }
246 }
247
248 extern void sparc_FORM3imm_arith(s, op3, use_ext_form, dest, src1, imm)
249 dill_stream s;
250 int op3;
251 int use_ext_form;
252 int dest;
253 int src1;
254 long imm;
255 {
256 sparc_mach_info smi = (sparc_mach_info) s->p->mach_info;
257 int sparcv9 = 0;
258 if ((smi->stack_align == 8) && use_ext_form) {
259 sparcv9 = 0x1;
260 }
261 if (((op3 >= 0x25) && (op3 <= 0x27)) && !use_ext_form) {
262 imm &= 0x1f; /* 32-bit reg shift. limit imm to 31 or less */
263 }
264 if (((long)imm) < 4096 && ((long)imm) >= -4096) {
265 /* format 3 */
266 INSN_OUT(s, HDR(0x2)|OP3(op3)|RD(dest)|RS1(src1)|IM|SIMM13(imm)|sparcv9<<12);
267 } else {
268 sparc_set(s, _g1, imm);
269 /* format 3 */
270 INSN_OUT(s, HDR(0x2)|OP3(op3)|RD(dest)|RS1(src1)|RS2(_g1)|sparcv9<<12);
271 }
272 }
273
274 extern void
sparc_proc_start(dill_stream s,char * subr_name,int arg_count,arg_info_list args,dill_reg * arglist)275 sparc_proc_start(dill_stream s, char *subr_name, int arg_count, arg_info_list args,
276 dill_reg *arglist)
277 {
278 int i;
279 int max_in_reg = _i0;
280 sparc_mach_info smi = (sparc_mach_info) s->p->mach_info;
281 int cur_arg_offset = 0;
282 /* emit start insns */
283 INSN_OUT(s, 0x10000);
284 INSN_OUT(s, 0x10000);
285 INSN_OUT(s, 0x10000);
286 INSN_OUT(s, 0x10000);
287 smi->save_insn_offset = (long)s->p->cur_ip - (long)s->p->code_base;
288 sparc_savei(s, 0);
289
290 smi->conversion_word = sparc_local(s, DILL_D);
291 smi->conversion_word = sparc_local(s, DILL_D);
292
293 /* load params from regs */
294 for (i = 0; i < arg_count; i++) {
295 switch (args[i].type) {
296 case DILL_F: case DILL_D:
297 if (smi->stack_align == 8) {
298 /* How about the limit on FP registers? Fix this. */
299 int reg;
300 args[i].is_register = 1;
301 if (args[i].type == DILL_F) {
302 reg = _f0 + cur_arg_offset / 4 + 1;
303 } else {
304 reg = _f0 + cur_arg_offset / 4;
305 }
306 dill_dealloc_specific(s, _f0 +cur_arg_offset / 4, args[i].type, DILL_TEMP);
307 args[i].in_reg = args[i].out_reg = reg;
308 break;
309 }
310 /* falling through */
311 default:
312 if (cur_arg_offset < 6 * smi->stack_align) {
313 args[i].is_register = 1;
314 args[i].in_reg = _i0 + cur_arg_offset/smi->stack_align;
315 args[i].out_reg = _o0 + cur_arg_offset/smi->stack_align;
316 max_in_reg = args[i].in_reg;
317 } else {
318 args[i].is_register = 0;
319 }
320 break;
321 }
322 args[i].offset = cur_arg_offset;
323 cur_arg_offset += roundup(type_info[(int)args[i].type].size, smi->stack_align);
324 }
325
326 for (i=_i0 ; i < _i6; i++) {
327 if (i <= max_in_reg) {
328 dill_dealloc_specific(s, i, DILL_I, DILL_VAR);
329 } else {
330 dill_alloc_specific(s, i, DILL_I, DILL_VAR);
331 }
332 }
333 for (i = 0; i < arg_count; i++) {
334 int tmp_reg;
335 if (smi->stack_align != 8) {
336 /* 32-bit sparc */
337 /* only do nothing for int params in registers */
338 if (args[i].is_register && ((args[i].type != DILL_F) &&
339 (args[i].type != DILL_D))) {
340 if (arglist != NULL) arglist[i] = args[i].in_reg;
341 continue;
342 }
343 } else {
344 /* 64-bit sparc do nothing for anything in a register */
345 if (args[i].is_register) {
346 if (arglist != NULL) arglist[i] = args[i].in_reg;
347 continue;
348 }
349 }
350 if (!dill_raw_getreg(s, &tmp_reg, args[i].type, DILL_VAR)) {
351 fprintf(stderr, "not enough registers for parameter %d\n", i);
352 exit(1);
353 }
354 if (arglist != NULL) arglist[i] = tmp_reg;
355 if (args[i].is_register) {
356 /* must be float */
357 if (args[i].type == DILL_F) {
358 sparc_movi2f(s, tmp_reg, args[i].in_reg);
359 dill_alloc_specific(s, args[i].in_reg, DILL_I, DILL_VAR);
360 } else {
361 /* sparcv8 boundary condition, half in register */
362 if (args[i].offset == 5*4) {
363 int real_offset = args[i].offset + 68;
364 sparc_pstorei(s, DILL_I, 0, args[i].in_reg, _fp,
365 real_offset);
366 sparc_ploadi(s, DILL_F, 0, tmp_reg, _fp, real_offset);
367 sparc_ploadi(s, DILL_F, 0, tmp_reg+1, _fp, real_offset+4);
368 } else {
369 sparc_movi2d(s, tmp_reg, args[i].in_reg);
370 dill_alloc_specific(s, args[i].in_reg, DILL_I, DILL_VAR);
371 if (smi->stack_align == 4) {
372 dill_alloc_specific(s, args[i].in_reg, DILL_I, DILL_VAR);
373
374 }
375 }
376 }
377 } else {
378 /* general offset from fp*/
379 int real_offset = args[i].offset + 8 +15*smi->stack_align;
380 if (type_info[(int)args[i].type].size < smi->stack_align) {
381 real_offset += smi->stack_align - type_info[(int)args[i].type].size;
382 }
383 real_offset += smi->stack_constant_offset;
384 if (args[i].type != DILL_D) {
385 sparc_ploadi(s, args[i].type, 0, tmp_reg, _fp,
386 real_offset);
387 } else {
388 sparc_ploadi(s, DILL_I, 0, _g1, _fp, real_offset);
389 sparc_pstorei(s, DILL_I, 0, _g1, _fp, smi->conversion_word);
390 sparc_ploadi(s, DILL_I, 0, _g1, _fp, real_offset+4);
391 sparc_pstorei(s, DILL_I, 0, _g1, _fp, smi->conversion_word+4);
392 sparc_ploadi(s, DILL_D, 0, tmp_reg, _fp, smi->conversion_word);
393 }
394 }
395 args[i].in_reg = tmp_reg;
396 args[i].is_register = 1;
397 }
398 }
399
400 static char ld_opcodes[] = {
401 0x09, /* DILL_C */
402 0x01, /* DILL_UC */
403 0x0a, /* DILL_S */
404 0x02, /* DILL_US */
405 0x08, /* DILL_I */
406 0x00, /* DILL_U */
407 0x0b, /* DILL_L */
408 0x0b, /* DILL_UL */
409 0x0b, /* DILL_P */
410 0x0, /* DILL_F */
411 0x0, /* DILL_D */
412 0x00, /* DILL_V */
413 0x00, /* DILL_B */
414 0x0b, /* DILL_EC */
415 };
416 extern void
sparc_ploadi(dill_stream s,int type,int junk,int dest,int src,long offset)417 sparc_ploadi(dill_stream s, int type, int junk, int dest, int src, long offset)
418 {
419 if (((long)offset) >= 4096 || ((long)offset) < -4096) {
420 sparc_set(s, _g1, offset);
421 sparc_pload(s, type, junk, dest, src, _g1);
422 return;
423 }
424
425 switch (type) {
426 case DILL_F:
427 INSN_OUT(s, HDR(0x3)|RD(dest)|OP3(0x20)|RS1(src)|IM|SIMM13(offset));
428 break;
429 case DILL_D:
430 INSN_OUT(s, HDR(0x3)|RD(dest)|OP3(0x23)|RS1(src)|IM|SIMM13(offset));
431 break;
432 case DILL_L: case DILL_UL: case DILL_P:{
433 sparc_mach_info smi = (sparc_mach_info) s->p->mach_info;
434 if (smi->stack_align == 4) {
435 type = DILL_I;
436 }
437 }
438 /* fall through */
439 default:
440 INSN_OUT(s, HDR(0x3)|RD(dest)|OP3(ld_opcodes[type])|RS1(src)|IM|SIMM13(offset));
441 break;
442 }
443 }
444
445 extern void
sparc_pload(dill_stream s,int type,int junk,int dest,int src1,int src2)446 sparc_pload(dill_stream s, int type, int junk, int dest, int src1, int src2)
447 {
448 switch (type) {
449 case DILL_F:
450 INSN_OUT(s, HDR(0x3)|RD(dest)|OP3(0x20)|RS1(src1)|RS2(src2));
451 break;
452 case DILL_D:
453 INSN_OUT(s, HDR(0x3)|RD(dest)|OP3(0x23)|RS1(src1)|RS2(src2));
454 break;
455 case DILL_L: case DILL_UL: case DILL_P:
456 {
457 sparc_mach_info smi = (sparc_mach_info) s->p->mach_info;
458 if (smi->stack_align == 4) {
459 type = DILL_I;
460 }
461 /* fall through */
462 }
463 default:
464 INSN_OUT(s, HDR(0x3)|RD(dest)|OP3(ld_opcodes[type])|RS1(src1)|RS2(src2));
465 break;
466 }
467 }
468
469 static char ld_bs_opcodes[] = { /* load from alternate space */
470 0x19, /* DILL_C */
471 0x11, /* DILL_UC */
472 0x1a, /* DILL_S */
473 0x12, /* DILL_US */
474 0x18, /* DILL_I */
475 0x10, /* DILL_U */
476 0x1b, /* DILL_L */
477 0x1b, /* DILL_UL */
478 0x1b, /* DILL_P */
479 0x30, /* DILL_F */
480 0x33, /* DILL_D */
481 };
482 extern void
sparc_pbsloadi(dill_stream s,int type,int junk,int dest,int src,long offset)483 sparc_pbsloadi(dill_stream s, int type, int junk, int dest, int src, long offset)
484 {
485 if (offset == 0) {
486 sparc_pbsload(s, type, junk, dest, src, _g0);
487 } else {
488 sparc_set(s, _g1, offset);
489 sparc_pbsload(s, type, junk, dest, src, _g1);
490 }
491 }
492
493
494 extern void
sparc_pbsload(dill_stream s,int type,int junk,int dest,int src1,int src2)495 sparc_pbsload(dill_stream s, int type, int junk, int dest, int src1, int src2)
496 {
497 switch (type) {
498 case DILL_L: case DILL_UL: case DILL_P:
499 {
500 sparc_mach_info smi = (sparc_mach_info) s->p->mach_info;
501 if (smi->stack_align == 4) {
502 type = DILL_I;
503 }
504 /* fall through */
505 }
506 default:
507 INSN_OUT(s, HDR(0x3)|RD(dest)|OP3(ld_bs_opcodes[type])|RS1(src1)|RS2(src2)|ASI(0x88));
508 break;
509 }
510 }
511
512 static char st_opcodes[] = {
513 0x05, /* DILL_C */
514 0x05, /* DILL_UC */
515 0x06, /* DILL_S */
516 0x06, /* DILL_US */
517 0x04, /* DILL_I */
518 0x04, /* DILL_U */
519 0x0e, /* DILL_L */
520 0x0e, /* DILL_UL */
521 0x0e, /* DILL_P */
522 0x0, /* DILL_F */
523 0x0, /* DILL_D */
524 0x00, /* DILL_V */
525 0x00, /* DILL_B */
526 0x0e, /* DILL_EC */
527 };
528 extern void
sparc_pstorei(dill_stream s,int type,int junk,int dest,int src,long offset)529 sparc_pstorei(dill_stream s, int type, int junk, int dest, int src, long offset)
530 {
531 if (((long)offset) >= 4096 || ((long)offset) < -4096) {
532 sparc_set(s, _g1, offset);
533 sparc_pstore(s, type, junk, dest, src, _g1);
534 return;
535 }
536
537 switch (type) {
538 case DILL_F:
539 INSN_OUT(s, HDR(0x3)|RD(dest)|OP3(0x24)|RS1(src)|IM|SIMM13(offset));
540 break;
541 case DILL_D:
542 INSN_OUT(s, HDR(0x3)|RD(dest)|OP3(0x27)|RS1(src)|IM|SIMM13(offset));
543 break;
544 case DILL_L: case DILL_UL: case DILL_P:{
545 sparc_mach_info smi = (sparc_mach_info) s->p->mach_info;
546 if (smi->stack_align == 4) {
547 type = DILL_I;
548 }
549 }
550 /* fall through */
551 default:
552 INSN_OUT(s, HDR(0x3)|RD(dest)|OP3(st_opcodes[type])|RS1(src)|IM|SIMM13(offset));
553 break;
554 }
555 }
556
557 extern void
sparc_pstore(dill_stream s,int type,int junk,int dest,int src1,int src2)558 sparc_pstore(dill_stream s, int type, int junk, int dest, int src1, int src2)
559 {
560 switch (type) {
561 case DILL_F:
562 INSN_OUT(s, HDR(0x3)|RD(dest)|OP3(0x24)|RS1(src1)|RS2(src2));
563 break;
564 case DILL_D:
565 INSN_OUT(s, HDR(0x3)|RD(dest)|OP3(0x27)|RS1(src1)|RS2(src2));
566 break;
567 case DILL_L: case DILL_UL: case DILL_P:
568 {
569 sparc_mach_info smi = (sparc_mach_info) s->p->mach_info;
570 if (smi->stack_align == 4) {
571 type = DILL_I;
572 }
573 /* fall through */
574 }
575 default:
576 INSN_OUT(s, HDR(0x3)|RD(dest)|OP3(st_opcodes[type])|RS1(src1)|RS2(src2));
577 break;
578 }
579 }
580
581 extern long dill_sparc_hidden_modi(int a, int b);
582 extern long dill_sparc_hidden_mod(long a, long b);
583 extern unsigned long dill_sparc_hidden_umod(unsigned long a, unsigned long b);
584 extern unsigned int dill_sparc_hidden_umodi(unsigned int a, unsigned int b);
585 extern double dill_sparc_hidden_ultod(unsigned long a);
586 extern float dill_sparc_hidden_ultof(unsigned long a);
587 extern unsigned long dill_sparc_hidden_dtoul(double a);
588 extern unsigned int dill_sparc_hidden_dtou(double a);
589 extern unsigned long dill_sparc_hidden_ftoul(float a);
590 extern unsigned int dill_sparc_hidden_ftou(float a);
591 extern long dill_sparc_hidden_udiv(unsigned long a, unsigned long b);
592
593
sparc_mod(dill_stream s,int data1,int type_long,int dest,int src1,int src2)594 extern void sparc_mod(dill_stream s, int data1, int type_long, int dest,
595 int src1, int src2)
596 {
597 int return_reg;
598 if (data1 == 1) {
599 /* signed case */
600 if (type_long) {
601 return_reg = dill_scalll(s, (void*)dill_sparc_hidden_mod, "dill_sparc_hidden_mod", "%l%l", src1, src2);
602 dill_movl(s, dest, return_reg);
603 } else {
604 return_reg = dill_scalli(s, (void*)dill_sparc_hidden_modi, "dill_sparc_hidden_modi", "%i%i", src1, src2);
605 dill_movi(s, dest, return_reg);
606 }
607 } else {
608 /* unsigned case */
609 if (type_long) {
610 return_reg = dill_scalll(s, (void*)dill_sparc_hidden_umod, "dill_sparc_hidden_umod", "%l%l", src1, src2);
611 dill_movul(s, dest, return_reg);
612 } else {
613 return_reg = dill_scallu(s, (void*)dill_sparc_hidden_umodi, "dill_sparc_hidden_umodi", "%u%u", src1, src2);
614 dill_movu(s, dest, return_reg);
615 }
616 }
617 }
618
sparc_modi(dill_stream s,int data1,int data2,int dest,int src1,long imm)619 extern void sparc_modi(dill_stream s, int data1, int data2, int dest, int src1,
620 long imm)
621 {
622 sparc_set(s, _g1, imm);
623 sparc_mod(s, data1, data2, dest, src1, _g1);
624 }
625
sparc_div(dill_stream s,int op3,int type_long,int dest,int src1,int src2)626 extern void sparc_div(dill_stream s, int op3, int type_long, int dest, int src1,
627 int src2)
628 {
629 sparc_mach_info smi = (sparc_mach_info) s->p->mach_info;
630 if ((op3 == 0x0d /* udiv */) && (type_long == 1)) {
631 int return_reg;
632 return_reg = dill_scalll(s, (void*)&dill_sparc_hidden_udiv, "dill_sparc_hidden_udiv", "%l%l", src1, src2);
633 dill_movl(s, dest, return_reg);
634 return;
635
636 }
637 if (op3 == 0x0d) {
638 INSN_OUT(s, HDR(0x2)|RD(0)|OP3(0x30)|RS1(_g0)|RS2(_g0));/*wry(_g0, _g0);*/
639 } else {
640 sparc_rshai(s, _g1, src1, 31);
641 INSN_OUT(s, HDR(0x2)|RD(0)|OP3(0x30)|RS1(_g0)|RS2(_g1));/*wry(_g0, _g1);*/
642 }
643 if ((type_long == 0) || (smi->stack_align != 8)) {
644 if (op3 == 0x0d) {
645 op3 = 0x0e;
646 } else {
647 op3 = 0x1f;
648 }
649 }
650 sparc_nop(c);
651 sparc_nop(c);
652 sparc_nop(c);
653 INSN_OUT(s, HDR(2)|OP3(op3)|RD(dest)|RS1(src1)|RS2(src2));
654 if (op3 == 0x1f) {
655 INSN_OUT(s, HDR(0)|1<<29|COND(0x7)|2<<22|2);
656 sparc_sethi(s, dest, 1<<21);
657 }
658 }
659
sparc_divi(dill_stream s,int sparc_op3,int type_long,int dest,int src,long imm)660 extern void sparc_divi(dill_stream s, int sparc_op3, int type_long,
661 int dest, int src, long imm)
662 {
663 sparc_mach_info smi = (sparc_mach_info) s->p->mach_info;
664 if ((sparc_op3 == 0x0d /* udiv */) && (type_long == 1)) {
665 sparc_set(s, _g1, imm);
666 sparc_div(s, sparc_op3, type_long, dest, src, _g1);
667 return;
668 }
669 if (sparc_op3 == 0x0d) {
670 INSN_OUT(s, HDR(0x2)|RD(0)|OP3(0x30)|RS1(_g0)|RS2(_g0));/*wry(_g0, _g0);*/
671 } else {
672 sparc_rshai(s, _g1, src, 31);
673 INSN_OUT(s, HDR(0x2)|RD(0)|OP3(0x30)|RS1(_g0)|RS2(_g1));/*wry(_g0, _g1);*/
674 }
675 if ((type_long == 0) || (smi->stack_align != 8)) {
676 if (sparc_op3 == 0x0d) {
677 sparc_op3 = 0x0e;
678 } else {
679 sparc_op3 = 0x1f;
680 }
681 }
682 sparc_set(s, _g1, imm);
683 sparc_nop(c);
684 sparc_nop(c);
685 INSN_OUT(s, HDR(2)|OP3(sparc_op3)|RD(dest)|RS1(src)|RS2(_g1));
686 if (sparc_op3 == 0x1f) {
687 INSN_OUT(s, HDR(0)|1<<29|COND(0x7)|2<<22|2);
688 sparc_sethi(s, dest, 1<<21);
689 }
690 }
691
692 extern void
sparc_mov(dill_stream s,int type,int junk,int dest,int src)693 sparc_mov(dill_stream s, int type, int junk, int dest, int src)
694 {
695 if (src == dest) return;
696 switch(type) {
697 case DILL_D:
698 sparc_movd(s, dest, src);
699 break;
700 case DILL_F:
701 sparc_movf(s, dest, src);
702 break;
703 default:
704 sparc_ori(s, dest, src, 0x0);
705 }
706 }
707
708 extern void
sparc_lea(dill_stream s,int j1,int j2,int dest,int src,long imm)709 sparc_lea(dill_stream s, int j1, int j2, int dest, int src, long imm)
710 {
711 sparc_mach_info smi = (sparc_mach_info) s->p->mach_info;
712 if (src != _fp) {
713 /* sparc_add */
714 sparc_FORM3imm_arith(s, 0, 0, dest, src, imm);
715 } else {
716 sparc_FORM3imm_arith(s, 0, 0, dest, src,
717 imm + smi->stack_constant_offset);
718 }
719 }
720
721 static void
sparc_saverestore_floats(dill_stream s,int saverestore)722 sparc_saverestore_floats(dill_stream s, int saverestore)
723 {
724 int i;
725 for (i=2; i <32 ; i+=2) {
726 if (dill_mustsave(&s->p->tmp_f, i)) {
727 sparc_save_restore_op(s, saverestore, DILL_D, i);
728 }
729 }
730 }
731
732 #define CONV(x,y) ((x*100)+y)
733 extern void
sparc_convert(dill_stream s,int from_type,int to_type,int dest,int src)734 sparc_convert(dill_stream s, int from_type, int to_type,
735 int dest, int src)
736 {
737 sparc_mach_info smi = (sparc_mach_info) s->p->mach_info;
738 int word_size = smi->stack_align << 3;
739
740 from_type &= 0xf;
741 to_type &= 0xf;
742 switch(CONV(from_type, to_type)) {
743 case CONV(DILL_I,DILL_L):
744 if (word_size == 64) {
745 /* sign extend */
746 sparc_xlshi(s, dest, src, 32);
747 sparc_xrshai(s, dest, dest, 32);
748 return;
749 }
750 /* fall through to mov */
751 case CONV(DILL_US,DILL_S):
752 case CONV(DILL_UC,DILL_US):
753 case CONV(DILL_C,DILL_US):
754 case CONV(DILL_C,DILL_UC):
755 case CONV(DILL_I,DILL_U):
756 case CONV(DILL_I,DILL_UL):
757 case CONV(DILL_UL,DILL_I):
758 case CONV(DILL_UL,DILL_U):
759 case CONV(DILL_L,DILL_U):
760 case CONV(DILL_U,DILL_UL):
761 case CONV(DILL_U,DILL_L):
762 case CONV(DILL_L,DILL_I):
763 case CONV(DILL_UL,DILL_L):
764 case CONV(DILL_L,DILL_UL):
765 case CONV(DILL_P,DILL_UL):
766 case CONV(DILL_UL,DILL_P):
767 case CONV(DILL_U,DILL_I):
768 if(src == dest) return;
769 sparc_movi(s, dest,src);
770 break;
771 case CONV(DILL_F,DILL_D):
772 INSN_OUT(s, HDR(0x2)|RD(dest)|OP3(0x34)|OPF(0xc9)|RS2(src)); /*fstod*/
773 break;
774 case CONV(DILL_F,DILL_L):
775 if (smi->stack_align == 8) {
776 INSN_OUT(s, HDR(0x2)|RD(src)|OP3(0x34)|OPF(0x81)|RS2(src));/*fstox*/
777 sparc_pstorei(s, DILL_D, 0, src, _fp, smi->conversion_word);
778 sparc_ploadi(s, DILL_L, 0, dest, _fp, smi->conversion_word);
779 break;
780 }
781 /* falling through */
782 case CONV(DILL_F,DILL_I):
783 INSN_OUT(s, HDR(0x2)|RD(src)|OP3(0x34)|OPF(0xd1)|RS2(src));/*fstoi*/
784 sparc_movf2i(s, dest, src);
785 break;
786 case CONV(DILL_F,DILL_C):
787 INSN_OUT(s, HDR(0x2)|RD(src)|OP3(0x34)|OPF(0xd1)|RS2(src));/*fstoi*/
788 sparc_movf2i(s, dest, src);
789 sparc_lshi(s, dest, src, 24);
790 sparc_rshai(s, dest, dest, 24);
791 break;
792 case CONV(DILL_F,DILL_S):
793 INSN_OUT(s, HDR(0x2)|RD(src)|OP3(0x34)|OPF(0xd1)|RS2(src));/*fstoi*/
794 sparc_movf2i(s, dest, src);
795 sparc_lshi(s, dest, src, 16);
796 sparc_rshai(s, dest, dest, 16);
797 break;
798 case CONV(DILL_F,DILL_UC):
799 INSN_OUT(s, HDR(0x2)|RD(src)|OP3(0x34)|OPF(0xd1)|RS2(src));/*fstoi*/
800 sparc_movf2i(s, dest, src);
801 sparc_lshi(s, dest, src, 24);
802 sparc_rshi(s, dest, dest, 24);
803 break;
804 case CONV(DILL_F,DILL_US):
805 INSN_OUT(s, HDR(0x2)|RD(src)|OP3(0x34)|OPF(0xd1)|RS2(src));/*fstoi*/
806 sparc_movf2i(s, dest, src);
807 sparc_lshi(s, dest, src, 16);
808 sparc_rshi(s, dest, dest, 16);
809 break;
810 case CONV(DILL_F,DILL_U):
811 {
812 int ret;
813 sparc_saverestore_floats(s, 0);
814 ret = dill_scallu(s, (void*)dill_sparc_hidden_ftou, "dill_sparc_hidden_ftou", "%f", src);
815 sparc_saverestore_floats(s, 1);
816 sparc_mov(s, DILL_UL, 0, dest, ret);
817 }
818 break;
819 /* fallthrough */
820 case CONV(DILL_F,DILL_UL):
821 {
822 int ret;
823 sparc_saverestore_floats(s, 0);
824 ret = dill_scallul(s, (void*)dill_sparc_hidden_ftoul, "dill_sparc_hidden_ftoul", "%f", src);
825 sparc_saverestore_floats(s, 1);
826 sparc_mov(s, DILL_UL, 0, dest, ret);
827 }
828 break;
829 case CONV(DILL_D,DILL_F):
830 INSN_OUT(s, HDR(0x2)|RD(dest)|OP3(0x34)|OPF(0xc6)|RS2(src)); /*fdtos*/
831 break;
832 case CONV(DILL_D,DILL_L):
833 if (smi->stack_align == 8) {
834 INSN_OUT(s, HDR(0x2)|RD(src)|OP3(0x34)|OPF(0x82)|RS2(src));/*fdtox*/
835 sparc_pstorei(s, DILL_D, 0, src, _fp, smi->conversion_word);
836 sparc_ploadi(s, DILL_L, 0, dest, _fp, smi->conversion_word);
837 break;
838 }
839 /* falling through */
840 case CONV(DILL_D,DILL_I):
841 INSN_OUT(s, HDR(0x2)|RD(src)|OP3(0x34)|OPF(0xd2)|RS2(src));/*fdtoi*/
842 sparc_movf2i(s, dest, src);
843 break;
844 case CONV(DILL_D,DILL_C):
845 case CONV(DILL_D,DILL_UC):
846 INSN_OUT(s, HDR(0x2)|RD(src)|OP3(0x34)|OPF(0xd2)|RS2(src));/*fdtoi*/
847 sparc_movf2i(s, dest, src);
848 sparc_andi(s, dest, dest, 0xff);
849 break;
850 case CONV(DILL_D,DILL_S):
851 case CONV(DILL_D,DILL_US):
852 INSN_OUT(s, HDR(0x2)|RD(src)|OP3(0x34)|OPF(0xd2)|RS2(src));/*fdtoi*/
853 sparc_movf2i(s, dest, src);
854 sparc_andi(s, dest, dest, 0xffff);
855 break;
856 case CONV(DILL_D,DILL_U):
857 {
858 int ret;
859 sparc_saverestore_floats(s, 0);
860 ret = dill_scallu(s, (void*)dill_sparc_hidden_dtou, "dill_sparc_hidden_dtou", "%d", src);
861 sparc_saverestore_floats(s, 1);
862 sparc_mov(s, DILL_U, 0, dest, ret);
863 }
864 break;
865 case CONV(DILL_D,DILL_UL):
866 {
867 int ret;
868 sparc_saverestore_floats(s, 0);
869 ret = dill_scallul(s, (void*)dill_sparc_hidden_dtoul, "dill_sparc_hidden_dtoul", "%d", src);
870 sparc_saverestore_floats(s, 1);
871 sparc_mov(s, DILL_UL, 0, dest, ret);
872 }
873 break;
874 case CONV(DILL_C,DILL_D):
875 case CONV(DILL_S,DILL_D):
876 case CONV(DILL_I,DILL_D):
877 sparc_rshi(s, _g1, src, 0);
878 src = _g1;
879 /* fall through */
880 case CONV(DILL_L,DILL_D):
881 sparc_movi2f(s, dest, src);
882 INSN_OUT(s, HDR(0x2)|RD(dest)|OP3(0x34)|OPF(0xc8)|RS2(dest));/*fitod*/
883 break;
884 case CONV(DILL_UC,DILL_D):
885 case CONV(DILL_US,DILL_D):
886 case CONV(DILL_U,DILL_D):
887 if (smi->stack_align == 8) {
888 sparc_rshi(s, _g1, src, 0);
889 src = _g1;
890 /* fall through */
891 sparc_pstorei(s, DILL_UL, 0, src, _fp, smi->conversion_word);
892 sparc_ploadi(s, DILL_D, 0, dest, _fp, smi->conversion_word);
893 INSN_OUT(s, HDR(0x2)|RD(dest)|OP3(0x34)|OPF(0x88)|RS2(dest));/*fxtod*/
894 break;
895 }
896 /* fallthrough */
897 case CONV(DILL_UL,DILL_D):
898 {
899 int ret;
900 sparc_saverestore_floats(s, 0);
901 ret = dill_scalld(s, (void*)dill_sparc_hidden_ultod, "dill_sparc_hidden_ultod", "%l", src);
902 sparc_saverestore_floats(s, 1);
903 sparc_mov(s, DILL_D, 0, dest, ret);
904 }
905 break;
906 case CONV(DILL_C,DILL_F):
907 case CONV(DILL_S,DILL_F):
908 case CONV(DILL_I,DILL_F):
909 case CONV(DILL_L,DILL_F):
910 sparc_movi2f(s, dest, src);
911 INSN_OUT(s, HDR(0x2)|RD(dest)|OP3(0x34)|OPF(0xc4)|RS2(dest));/*fitos*/
912 break;
913 case CONV(DILL_UC,DILL_F):
914 case CONV(DILL_US,DILL_F):
915 case CONV(DILL_U,DILL_F):
916 if (smi->stack_align == 8) {
917 sparc_rshi(s, _g1, src, 0);
918 src = _g1;
919 sparc_pstorei(s, DILL_UL, 0, src, _fp, smi->conversion_word);
920 sparc_ploadi(s, DILL_D, 0, dest, _fp, smi->conversion_word);
921 INSN_OUT(s, HDR(0x2)|RD(dest)|OP3(0x34)|OPF(0x84)|RS2(dest));/*fxtos*/
922 break;
923 }
924 /* fallthrough */
925 case CONV(DILL_UL,DILL_F):
926 {
927 int ret;
928 sparc_saverestore_floats(s, 0);
929 ret = dill_scalld(s, (void*)dill_sparc_hidden_ultof, "dill_sparc_hidden_ultof", "%l", src);
930 sparc_saverestore_floats(s, 1);
931 sparc_mov(s, DILL_D, 0, dest, ret);
932 }
933 break;
934 case CONV(DILL_C,DILL_UL):
935 case CONV(DILL_C,DILL_S):
936 case CONV(DILL_C,DILL_L):
937 case CONV(DILL_C,DILL_I):
938 case CONV(DILL_C,DILL_U):
939 sparc_lshi(s, dest, src, 24);
940 sparc_rshai(s, dest, dest, 24);
941 break;
942 case CONV(DILL_S,DILL_C):
943 case CONV(DILL_US,DILL_C):
944 case CONV(DILL_I,DILL_C):
945 case CONV(DILL_U,DILL_C):
946 case CONV(DILL_L,DILL_C):
947 case CONV(DILL_UL,DILL_C):
948 case CONV(DILL_L,DILL_UC):
949 case CONV(DILL_US,DILL_UC):
950 case CONV(DILL_UL,DILL_UC):
951 case CONV(DILL_I,DILL_UC):
952 case CONV(DILL_U,DILL_UC):
953 case CONV(DILL_S,DILL_UC):
954 sparc_andi(s, dest, src, 0xff);
955 break;
956 case CONV(DILL_S,DILL_US):
957 sparc_andi(s, dest, src, 0xffff);
958 break;
959 case CONV(DILL_S,DILL_L):
960 case CONV(DILL_S,DILL_UL):
961 case CONV(DILL_S,DILL_I):
962 case CONV(DILL_S,DILL_U):
963 sparc_lshi(s, dest, src, 16);
964 sparc_rshai(s, dest, dest, 16);
965 break;
966 case CONV(DILL_US,DILL_I):
967 case CONV(DILL_US,DILL_L):
968 case CONV(DILL_US,DILL_U):
969 case CONV(DILL_US,DILL_UL):
970 case CONV(DILL_I,DILL_S):
971 case CONV(DILL_U,DILL_S):
972 case CONV(DILL_L,DILL_S):
973 case CONV(DILL_UL,DILL_S):
974 case CONV(DILL_I,DILL_US):
975 case CONV(DILL_U,DILL_US):
976 case CONV(DILL_L,DILL_US):
977 case CONV(DILL_UL,DILL_US):
978 sparc_lshi(s, dest, src, 16);
979 sparc_rshi(s, dest, dest, 16);
980 break;
981 default:
982 printf("Unknown case in sparc convert %d\n", CONV(from_type,to_type));
983 }
984 }
985
986 static signed char op_conds[] = {
987 0x01, /* dill_eq_code */ /* signed */
988 0x0b, /* dill_ge_code */
989 0x0a, /* dill_gt_code */
990 0x02, /* dill_le_code */
991 0x03, /* dill_lt_code */
992 0x09, /* dill_ne_code */
993
994 0x01, /* dill_eq_code */ /* unsigned */
995 0x00, /* dill_ge_code */ /* no unsigned version */
996 0x0c, /* dill_gt_code */
997 0x04, /* dill_le_code */
998 0x00, /* dill_lt_code */ /* no unsigned version */
999 0x09, /* dill_ne_code */
1000 };
1001
1002 static char fop_conds[] = {
1003 0x09, /* dill_eq_code */
1004 0x0b, /* dill_ge_code */
1005 0x06, /* dill_gt_code */
1006 0x0d, /* dill_le_code */
1007 0x04, /* dill_lt_code */
1008 0x01, /* dill_ne_code */
1009 };
1010
1011 extern void
sparc_compare(dill_stream s,int op,int type,int dest,int src1,int src2)1012 sparc_compare(dill_stream s, int op, int type, int dest, int src1, int src2)
1013 {
1014 int label = dill_alloc_label(s, "compare end");
1015 sparc_set(s, dest, 1);
1016 sparc_branch(s, op, type, src1, src2, label);
1017 sparc_set(s, dest, 0);
1018 dill_mark_label(s, label);
1019 }
1020
1021 extern void
sparc_comparei(dill_stream s,int op,int type,int dest,int src,long imm)1022 sparc_comparei(dill_stream s, int op, int type, int dest, int src, long imm)
1023 {
1024 int label = dill_alloc_label(s, "compare end");
1025 sparc_set(s, dest, 1);
1026 sparc_branchi(s, op, type, src, imm, label);
1027 sparc_set(s, dest, 0);
1028 dill_mark_label(s, label);
1029 }
1030
1031 extern void
sparc_branch(dill_stream s,int op,int type,int src1,int src2,int label)1032 sparc_branch(dill_stream s, int op, int type, int src1, int src2, int label)
1033 {
1034 switch(type) {
1035 case DILL_F:
1036 INSN_OUT(s, HDR(0x2)|OP3(0x35)|RS1(src1)|OPF(0x51)|RS2(src2));/*fcmps*/
1037 dill_mark_branch_location(s, label);
1038 INSN_OUT(s, HDR(0)|COND(fop_conds[op])|(0x5<<22)|CC(0x0)|P(1)|/*disp */0);/* fbp*/
1039 break;
1040 case DILL_D:
1041 INSN_OUT(s, HDR(0x2)|OP3(0x35)|RS1(src1)|OPF(0x52)|RS2(src2));
1042 dill_mark_branch_location(s, label);
1043 INSN_OUT(s, HDR(0)|COND(fop_conds[op])|(0x5<<22)|CC(0x0)|P(1)|/*disp */0);/* fbp*/
1044 break;
1045 case DILL_U:
1046 case DILL_UL:
1047 switch(op) {
1048 case dill_ge_code: {
1049 int tmp = src1; src1 = src2; src2 = tmp; /* swap operands */
1050 op = dill_le_code;
1051 break;
1052 }
1053 case dill_lt_code: {
1054 int tmp = src1; src1 = src2; src2 = tmp; /* swap operands */
1055 op = dill_gt_code;
1056 break;
1057 }
1058 }
1059 op += 6; /* second set of codes */
1060 /* fall through */
1061 default:
1062 INSN_OUT(s, HDR(0x2)|RD(_g0)|OP3(0x14)|RS1(src1)|RS2(src2)); /* subcc */
1063 dill_mark_branch_location(s, label);
1064 INSN_OUT(s, HDR(0)|COND(op_conds[op])|(2<<22)|/*disp */0);/* bp*/
1065 }
1066 sparc_nop(c);
1067 }
1068
1069 extern void
sparc_jump_to_label(dill_stream s,unsigned long label)1070 sparc_jump_to_label(dill_stream s, unsigned long label)
1071 {
1072 dill_mark_branch_location(s, label);
1073 INSN_OUT(s, HDR(0)|COND(8)|(2<<22)|/*disp */0);/* bp always*/
1074 sparc_nop(c);
1075 }
1076
sparc_jump_to_reg(dill_stream s,unsigned long reg)1077 extern void sparc_jump_to_reg(dill_stream s, unsigned long reg)
1078 {
1079 INSN_OUT(s, HDR(0x2)|OP3(0x38)|RD(_g0)|RS1(reg)|IM|SIMM13(0x0));
1080 sparc_nop(c);
1081 }
1082
sparc_jump_to_imm(dill_stream s,unsigned long imm)1083 extern void sparc_jump_to_imm(dill_stream s, unsigned long imm)
1084 {
1085 INSN_OUT(s, HDR(0x2)|OP3(0x38)|RD(_g0)|RS1(_i7)|IM|SIMM13(imm));
1086 sparc_nop(c);
1087 }
1088
1089 extern void
sparc_jal(dill_stream s,int return_addr_reg,int target)1090 sparc_jal(dill_stream s, int return_addr_reg, int target)
1091 {
1092 INSN_OUT(s, HDR(0x2)|OP3(0x38)|RD(return_addr_reg)|RS1(target)|IM|SIMM13(0x0));
1093 }
1094
internal_push(dill_stream s,int type,int immediate,void * value_ptr)1095 static void internal_push(dill_stream s, int type, int immediate,
1096 void *value_ptr)
1097 {
1098 sparc_mach_info smi = (sparc_mach_info) s->p->mach_info;
1099 struct arg_info arg;
1100 int real_offset;
1101
1102 arg.is_immediate = immediate;
1103 switch(type) {
1104 case DILL_C: case DILL_S: case DILL_I: case DILL_L:
1105 arg.type = DILL_L;
1106 break;
1107 case DILL_UC: case DILL_US: case DILL_U: case DILL_UL:
1108 arg.type = DILL_UL;
1109 break;
1110 default:
1111 arg.type = type;
1112 }
1113
1114 if (smi->cur_arg_offset < 6 * smi->stack_align) {
1115 arg.is_register = 1;
1116 if ((smi->stack_align == 8) && ((type == DILL_F) || (type == DILL_D))) {
1117 arg.out_reg = _f0 + smi->cur_arg_offset/4;
1118 if (type == DILL_F) arg.out_reg++;
1119 arg.in_reg = _o0 + smi->cur_arg_offset/8;
1120 } else {
1121 /* sparcv8 */
1122 arg.in_reg = _i0 + smi->cur_arg_offset/smi->stack_align;
1123 arg.out_reg = _o0 + smi->cur_arg_offset/smi->stack_align;
1124 }
1125 } else {
1126 if ((smi->stack_align == 8) && ((type == DILL_F) || (type == DILL_D)) &&
1127 (smi->cur_arg_offset <= 10 * smi->stack_align)) {
1128 /* floating arg can go in a float reg, but not int reg */
1129 arg.is_register = 1;
1130 arg.out_reg = _f0 + smi->cur_arg_offset/4;
1131 arg.in_reg = -1;
1132 } else {
1133 arg.is_register = 0;
1134 }
1135 }
1136
1137 arg.offset = smi->cur_arg_offset;
1138 smi->cur_arg_offset +=
1139 roundup(type_info[(int)arg.type].size, smi->stack_align);
1140 real_offset = arg.offset + 8 + 15*smi->stack_align +
1141 smi->stack_constant_offset;
1142 if (smi->stack_align == 4) {
1143 /* sparcv8 */
1144 if (arg.is_register == 0) {
1145 /* store it on the stack only */
1146 if (arg.is_immediate) {
1147 if (type != DILL_D) {
1148 if (type == DILL_F) {
1149 float f = (float) *(double*)value_ptr;
1150 sparc_set(s, _g1, *(int*)&f);
1151 } else {
1152 sparc_set(s, _g1, *(long*)value_ptr);
1153 }
1154 sparc_pstorei(s, arg.type, 0, _g1, _sp, real_offset);
1155 } else {
1156 sparc_set(s, _g1, *(int*)value_ptr);
1157 sparc_pstorei(s, DILL_I, 0, _g1, _sp, real_offset);
1158 sparc_set(s, _g1, *(((int*)value_ptr)+1));
1159 sparc_pstorei(s, DILL_I, 0, _g1, _sp, real_offset+4);
1160 }
1161 } else {
1162 if (type != DILL_D) {
1163 sparc_pstorei(s, arg.type, 0, *(int*)value_ptr, _sp, real_offset);
1164 } else {
1165 sparc_pstorei(s, DILL_F, 0, *(int*)value_ptr, _sp, real_offset);
1166 sparc_pstorei(s, DILL_F, 0, (*(int*)value_ptr)+1, _sp,
1167 real_offset + 4);
1168 }
1169 }
1170 } else {
1171 if ((type != DILL_F) && (type != DILL_D)) {
1172 if (arg.is_immediate) {
1173 sparc_set(s, arg.out_reg, *(long*)value_ptr);
1174 } else {
1175 sparc_mov(s, type, 0, arg.out_reg, *(int*) value_ptr);
1176 }
1177 } else {
1178 if (arg.is_immediate) {
1179 if (type == DILL_F) {
1180 float f = (float) *(double*)value_ptr;
1181 sparc_set(s, arg.out_reg, *(int*)&f);
1182 } else {
1183 sparc_set(s, arg.out_reg, *(int*)value_ptr);
1184 if (arg.out_reg != _o5) {
1185 sparc_set(s, arg.out_reg+1, *(((int*)value_ptr)+1));
1186 } else {
1187 /* sparcv8 boundary condition */
1188 sparc_set(s, _g1, *(((int*)value_ptr)+1));
1189 sparc_pstorei(s, DILL_I, 0, _g1, _sp, real_offset + 4);
1190 }
1191 }
1192 } else {
1193 if (type == DILL_F) {
1194 sparc_movf2i(s, arg.out_reg, *(int*)value_ptr);
1195 } else {
1196 if (arg.out_reg != _o5) {
1197 sparc_movd2i(s, arg.out_reg, *(int*)value_ptr);
1198 } else {
1199 /* sparcv8 boundary condition */
1200 sparc_movf2i(s, arg.out_reg, *(int*)value_ptr);
1201 sparc_pstorei(s, DILL_F, 0, (*(int*)value_ptr)+1, _sp,
1202 real_offset + 4);
1203 }
1204 }
1205 }
1206
1207 }
1208 }
1209 } else {
1210 /* sparcv9 */
1211 if (arg.is_register == 0) {
1212 /* store it on the stack only */
1213 if (arg.is_immediate) {
1214 if (type == DILL_F) {
1215 float f = (float) *(double*)value_ptr;
1216 sparc_set(s, _g1, *(int*)&f);
1217 } else {
1218 sparc_set(s, _g1, *(long*)value_ptr);
1219 }
1220 sparc_pstorei(s, arg.type, 0, _g1, _sp, real_offset);
1221 } else {
1222 sparc_pstorei(s, arg.type, 0, *(int*)value_ptr, _sp,
1223 real_offset);
1224 }
1225 } else {
1226 if ((type != DILL_F) && (type != DILL_D)) {
1227 if (arg.is_immediate) {
1228 sparc_set(s, arg.out_reg, *(long*)value_ptr);
1229 } else {
1230 sparc_mov(s, type, 0, arg.out_reg, *(int*) value_ptr);
1231 }
1232 } else {
1233 if (arg.is_immediate) {
1234 if ((type == DILL_F) || (type == DILL_D)) {
1235 /* set appropriate register */
1236 sparc_setf(s, type, 0, arg.out_reg,
1237 *(double*)value_ptr);
1238 } else {
1239 sparc_set(s, arg.out_reg, *(int*)value_ptr);
1240 }
1241 } else {
1242 /* move to the appropriate float reg */
1243 sparc_mov(s, type, 0, arg.out_reg, *(int*)value_ptr);
1244 }
1245 if (arg.in_reg != -1) {
1246 /* put value in int regs too */
1247 if (type == DILL_D) {
1248 sparc_movd2i(s, arg.in_reg, arg.out_reg);
1249 } else {
1250 sparc_movf2i(s, arg.in_reg, arg.out_reg);
1251 }
1252 } else {
1253 /* put it on the stack as well */
1254 sparc_pstorei(s, arg.type, 0, arg.out_reg, _sp,
1255 real_offset);
1256 }
1257 }
1258 }
1259 }
1260 }
1261
push_init(dill_stream s)1262 static void push_init(dill_stream s)
1263 {
1264 sparc_mach_info smi = (sparc_mach_info) s->p->mach_info;
1265 smi->cur_arg_offset = 0;
1266 }
1267
sparc_push(dill_stream s,int type,int reg)1268 extern void sparc_push(dill_stream s, int type, int reg)
1269 {
1270 if ((type == DILL_V) && (reg <= -1)) {
1271 push_init(s);
1272 } else {
1273 internal_push(s, type, 0, ®);
1274 }
1275 }
1276
sparc_pushi(dill_stream s,int type,long value)1277 extern void sparc_pushi(dill_stream s, int type, long value)
1278 {
1279 internal_push(s, type, 1, &value);
1280 }
1281
sparc_pushpi(dill_stream s,int type,void * value)1282 extern void sparc_pushpi(dill_stream s, int type, void *value)
1283 {
1284 internal_push(s, type, 1, &value);
1285 }
1286
sparc_pushfi(dill_stream s,int type,double value)1287 extern void sparc_pushfi(dill_stream s, int type, double value)
1288 {
1289 internal_push(s, type, 1, &value);
1290 }
1291
sparc_calli(dill_stream s,int type,void * xfer_address,char * name)1292 extern int sparc_calli(dill_stream s, int type, void *xfer_address, char *name)
1293 {
1294 int caller_side_ret_reg = _o0;
1295
1296 /* save temporary registers */
1297 dill_mark_call_location(s, name, xfer_address);
1298 INSN_OUT(s, HDR(0x1)|0);
1299 sparc_nop(s);
1300 /* restore temporary registers */
1301 if ((type == DILL_D) || (type == DILL_F)) {
1302 caller_side_ret_reg = _f0;
1303 }
1304 push_init(s);
1305 return caller_side_ret_reg;
1306 }
1307
sparc_callr(dill_stream s,int type,int src)1308 extern int sparc_callr(dill_stream s, int type, int src)
1309 {
1310 int caller_side_ret_reg = _o0;
1311
1312 /* save temporary registers */
1313 sparc_jal(s, _o7, src);
1314 sparc_nop(s);
1315 /* restore temporary registers */
1316 if ((type == DILL_D) || (type == DILL_F)) {
1317 caller_side_ret_reg = _f0;
1318 }
1319 push_init(s);
1320 return caller_side_ret_reg;
1321 }
1322
1323 extern void
sparc_branchi(dill_stream s,int op,int type,int src,long imm,int label)1324 sparc_branchi(dill_stream s, int op, int type, int src, long imm, int label)
1325 {
1326 switch(type) {
1327 case DILL_F:
1328 case DILL_D:
1329 fprintf(stderr, "Shouldn't happen\n");
1330 break;
1331 case DILL_U:
1332 case DILL_UL:
1333 switch(op) {
1334 case dill_ge_code: {
1335 imm = imm-1;
1336 op = dill_gt_code;
1337 break;
1338 }
1339 case dill_lt_code: {
1340 imm = imm-1;
1341 op = dill_le_code;
1342 break;
1343 }
1344 }
1345 op += 6; /* second set of codes */
1346 /* fall through */
1347 default:
1348 sparc_FORM3imm_arith(s, 0x14, 0, _g0, src, imm); /* subcc */
1349 dill_mark_branch_location(s, label);
1350 INSN_OUT(s, HDR(0)|COND(op_conds[op])|(2<<22)|/*disp */0);/* bp*/
1351 sparc_nop(s);
1352 }
1353 }
1354
sparc_ret(dill_stream s,int data1,int data2,int src)1355 extern void sparc_ret(dill_stream s, int data1, int data2, int src)
1356 {
1357 switch (data1) {
1358 case DILL_C:
1359 case DILL_UC:
1360 case DILL_S:
1361 case DILL_US:
1362 case DILL_I:
1363 case DILL_U:
1364 case DILL_L:
1365 case DILL_UL:
1366 case DILL_P:
1367 if (src != _i0) sparc_int_mov(s, _i0, src);
1368 break;
1369 case DILL_F:
1370 if (src != _f0) sparc_movf(s, _f0, src);
1371 break;
1372 case DILL_D:
1373 if (src != _f0) sparc_movd(s, _f0, src);
1374 break;
1375 }
1376 sparc_simple_ret(s);
1377 sparc_restore(s);
1378 }
1379
sparc_reti(dill_stream s,int data1,int data2,long imm)1380 extern void sparc_reti(dill_stream s, int data1, int data2, long imm)
1381 {
1382 switch (data1) {
1383 case DILL_C:
1384 case DILL_UC:
1385 case DILL_S:
1386 case DILL_US:
1387 case DILL_I:
1388 case DILL_U:
1389 case DILL_L:
1390 case DILL_UL:
1391 case DILL_P:
1392 sparc_set(s, _i0, imm);
1393 break;
1394 case DILL_F:
1395 case DILL_D:
1396 break;/* no return immediate of floats */
1397 }
1398 sparc_simple_ret(s);
1399 sparc_restore(s);
1400 }
1401
1402 static void
sparc_data_link(dill_stream s)1403 sparc_data_link(dill_stream s)
1404 {
1405 /* struct branch_table *t = &s->p->branch_table;
1406 int i;
1407 for (i=0; i < t->data_mark_count; i++) {
1408 int label = t->data_marks[i].label;
1409 void *label_addr = t->label_locs[label] + (char*)s->p->code_base;
1410 *t->data_marks[i].addr = label_addr;
1411 }*/
1412 }
1413
1414 static void
sparc_branch_link(dill_stream s)1415 sparc_branch_link(dill_stream s)
1416 {
1417 struct branch_table *t = &s->p->branch_table;
1418 int i;
1419
1420 for(i=0; i< t->branch_count; i++) {
1421 int label = t->branch_locs[i].label;
1422 int label_offset = t->label_locs[label] - t->branch_locs[i].loc;
1423 int *branch_addr = (int*)((char *)s->p->code_base +
1424 t->branch_locs[i].loc);
1425 /* div addr diff by 4 for sparc offset value */
1426 label_offset = label_offset >> 2;
1427 *branch_addr &= 0xffc00000;
1428 *branch_addr |= (label_offset & 0x3fffff);
1429 }
1430 }
1431
1432 /*
1433 * on 64-bit solaris 8, we need a procedure linkage table to manage
1434 * calls to DLLs in an address range that is typically more than 32 bits
1435 * away from malloc'd memory. We emit a PLT that is basically a set_reg,
1436 * then jump_through_reg for each routine. Later, during call linkage,
1437 * we'll call to the PLT entry rather than directly to the routine.
1438 */
1439 static void
sparc_PLT_emit(dill_stream s,int force_PLT)1440 sparc_PLT_emit(dill_stream s, int force_PLT)
1441 {
1442 call_t *t = &s->p->call_table;
1443 int i;
1444
1445 for(i=0; i< t->call_count; i++) {
1446 int *call_addr = (int*) ((unsigned long)s->p->code_base +
1447 t->call_locs[i].loc);
1448 long call_offset = (unsigned long)t->call_locs[i].xfer_addr -
1449 (unsigned long)call_addr;
1450 int jump_value;
1451
1452 /* div addr diff by 4 for sparc offset value */
1453 call_offset = call_offset >> 2;
1454 jump_value = (char*)s->p->cur_ip - (char*)call_addr;
1455 call_offset = call_offset >> 30;
1456 t->call_locs[i].mach_info = (void*)0;
1457 if (((call_offset != 0) && (call_offset != -1)) || force_PLT) {
1458
1459 int plt_offset = (char*)s->p->cur_ip - (char*)s->p->code_base;
1460 t->call_locs[i].mach_info = (void*)1;
1461
1462 sparc_nop(s);
1463 sparc_nop(s);
1464 sparc_nop(s);
1465 sparc_nop(s);
1466 sparc_nop(s);
1467 sparc_nop(s);
1468
1469 /* sparc_set(s, _g1, (unsigned long)t->call_locs[i].xfer_addr);*/
1470 sparc_jump_to_reg(s, _g1);
1471 sparc_nop(s);
1472
1473 /* fixup call to reference just-generated PLT code*/
1474 call_addr = (int*) ((unsigned long)s->p->code_base +
1475 t->call_locs[i].loc);
1476 t->call_locs[i].loc = plt_offset;
1477 jump_value = jump_value >> 2;
1478 *call_addr &= 0xc0000000;
1479 *call_addr |= (jump_value & 0x3fffffff);
1480 }
1481 }
1482 }
1483
1484 extern void sparc_rt_call_link(char *code, call_t *t, int force_plt);
1485
1486 static void
sparc_call_link(dill_stream s)1487 sparc_call_link(dill_stream s)
1488 {
1489 call_t *t = &s->p->call_table;
1490
1491 sparc_rt_call_link(s->p->code_base, t, /* don't force plt */ 0);
1492 }
1493
1494 static void
sparc_flush(void * base,void * limit)1495 sparc_flush(void *base, void *limit)
1496 {
1497 #if defined(HOST_SPARC) || defined(HOST_SPARCV9)
1498 {
1499 volatile void *ptr = base;
1500
1501 #ifdef __GNUC__
1502 /* flush every 8 bytes of preallocated insn stream. */
1503 while((char*)ptr < (char*) limit) {
1504 asm volatile ("iflush %0" : /* */ : "r" (ptr));
1505 ptr = (char *)ptr + 8;
1506 }
1507 asm volatile("nop");
1508 asm volatile("nop");
1509 asm volatile("nop");
1510 asm volatile("nop");
1511 asm volatile("nop");
1512 #else
1513 int nbytes = (char*)limit - (char*)base;
1514 for(; nbytes > 0;nbytes -= 8) {
1515 asm("add %i0, 8, %i0");
1516 asm ("iflush %i0");
1517 }
1518
1519 asm ("nop");
1520 asm ("nop");
1521 asm ("nop");
1522 asm ("nop");
1523 asm ("nop");
1524 #endif
1525 #ifdef USE_MEMBAR
1526 asm("membar #Sync");
1527 #endif
1528 }
1529 #endif
1530 }
1531
1532 static void
sparc_emit_save(dill_stream s)1533 sparc_emit_save(dill_stream s)
1534 {
1535 sparc_mach_info smi = (sparc_mach_info) s->p->mach_info;
1536 void *save_ip = s->p->cur_ip;
1537 int ar_size = smi->fp_save_end + smi->act_rec_size;
1538 ar_size = roundup(ar_size, 16) + 16;
1539
1540 s->p->cur_ip = (char*)s->p->code_base + smi->save_insn_offset;
1541 sparc_savei(s, -ar_size);
1542 s->p->fp = (char*)s->p->code_base + smi->save_insn_offset;
1543 s->p->cur_ip = save_ip;
1544 }
1545
1546 extern void
1547 sparc_end(s)
1548 dill_stream s;
1549 {
1550 sparc_simple_ret(s);
1551 sparc_restore(s);
1552 sparc_PLT_emit(s, 0); /* must be done before linking */
1553 sparc_branch_link(s);
1554 sparc_call_link(s);
1555 sparc_data_link(s);
1556 sparc_emit_save(s);
1557 sparc_flush(s->p->code_base, s->p->code_limit);
1558 }
1559
1560 extern void
1561 sparc_package_end(s)
1562 dill_stream s;
1563 {
1564 int force_plt = 0;
1565 sparc_simple_ret(s);
1566 sparc_restore(s);
1567 #if defined(HOST_SPARCV9)
1568 force_plt = 1;
1569 #endif
1570 sparc_PLT_emit(s, force_plt); /* must be done before linking */
1571 sparc_branch_link(s);
1572 sparc_emit_save(s);
1573 }
1574
1575 extern void *
1576 sparc_clone_code(s, new_base, available_size)
1577 dill_stream s;
1578 void *new_base;
1579 int available_size;
1580 {
1581 int size = dill_code_size(s);
1582 if (available_size < size) {
1583 return NULL;
1584 }
1585 void *old_base = s->p->code_base;
1586 void *native_base = s->p->code_base;
1587 if (native_base == NULL) native_base = s->p->native.code_base;
1588 memcpy(new_base, native_base, size);
1589 s->p->code_base = new_base;
1590 s->p->cur_ip = (void*)((long)new_base + size);
1591 s->p->fp = new_base;
1592 sparc_branch_link(s);
1593 sparc_call_link(s);
1594 sparc_data_link(s);
1595 sparc_flush(s->p->code_base, s->p->code_limit);
1596 s->p->code_base = old_base;
1597 s->p->cur_ip = (void*)((long) old_base + size);
1598 s->p->fp = old_base;
1599 while (*(int*)new_base == 0x10000) {
1600 /* skip UNIMPs */
1601 new_base = (void*) ((long) new_base + 4);
1602 }
1603 return new_base;
1604 }
1605
1606 extern void
sparc_pset(dill_stream s,int type,int junk,int dest,long imm)1607 sparc_pset(dill_stream s, int type, int junk, int dest, long imm)
1608 {
1609 sparc_set(s, dest, imm);
1610 }
1611
1612 extern void
sparc_setp(dill_stream s,int type,int junk,int dest,void * imm)1613 sparc_setp(dill_stream s, int type, int junk, int dest, void *imm)
1614 {
1615 sparc_mach_info smi = (sparc_mach_info) s->p->mach_info;
1616 union {
1617 void *a;
1618 int i;
1619 long l;
1620 } a;
1621 a.a = imm;
1622 if (smi->stack_align == 4) {
1623 sparc_set(s, dest, a.i);
1624 } else {
1625 sparc_set(s, dest, a.l);
1626 }
1627 }
1628
1629 extern void
sparc_setf(dill_stream s,int type,int junk,int dest,double imm)1630 sparc_setf(dill_stream s, int type, int junk, int dest, double imm)
1631 {
1632 union {
1633 float f;
1634 int i;
1635 } a;
1636 union {
1637 double d;
1638 long l;
1639 int i[2];
1640 } b;
1641 sparc_mach_info smi = (sparc_mach_info) s->p->mach_info;
1642 if (type == DILL_F) {
1643 a.f = (float) imm;
1644 sparc_set(s, _g1, a.i);
1645 sparc_movi2f(s, dest, _g1);
1646 } else if (smi->stack_align == 4) {
1647 b.d = imm;
1648 sparc_set(s, _g1, b.i[0]);
1649 sparc_movi2f(s, dest, _g1);
1650 sparc_set(s, _g1, b.i[1]);
1651 sparc_movi2f(s, dest+1, _g1);
1652 } else {
1653 /* double sparcv9 */
1654 b.d = imm;
1655 sparc_set(s, _g1, b.l);
1656 sparc_movi2d(s, dest, _g1);
1657 }
1658 }
1659
1660 #define SIMM34_P(im) (((long)im) < (long)1<<33 ) && (((long)im) >= -((long)1<<33) )
1661
1662 extern void
1663 sparc_set(s, r, val)
1664 dill_stream s;
1665 int r;
1666 long val;
1667 {
1668 if (((long)val) < 4096 && ((long)val) >= -4096) {
1669 sparc_ori(s, r, _g0, (val&0x1fff));
1670 #if SIZEOF_LONG == 8
1671 } else if ((val >> 34) == 0) {
1672 /* fits in 34 positive bits */
1673 sparc_sethi(s, r, val>>12);
1674 sparc_lshi(s, r,r,2);
1675 sparc_ori(s, r,r,val & 0xfff);
1676 } else if ((val >> 34) == -1) {
1677 /* fits in 34 negative bits */
1678 sparc_sethi(s, r, ~(val>>12));
1679 sparc_lshi(s, r,r,2);
1680 sparc_xori(s, r,r,(val & 0xfff)|0x1000);
1681 } else {
1682 if (r != _g1) {
1683 /* case where we can use g1 as a temporary */
1684 sparc_sethi(s, r,hh(val));
1685 sparc_sethi(s, _g1,lm(val));
1686 /* printf("lm (%lx) = %lx\n", val, lm(val));*/
1687 sparc_ori(s, r,r,hm(val));
1688 sparc_ori(s, _g1,_g1,lo(val));
1689 sparc_xlshi(s, r,r,32);
1690 sparc_or(s, r,r,_g1);
1691 /* can't use g1! */
1692 } else {
1693 /* set hi, set low */
1694 sparc_sethi(s, r, hh(val));
1695 sparc_ori(s, r, r, hm(val));
1696 if ((val & 0xFF000000) != 0) {
1697 /* top 8 of low 32 are non-zero */
1698 sparc_lshi(s, r,r,8);
1699 sparc_ori(s, r, r, (val & 0xFF000000) >> 24);
1700 sparc_lshi(s, r,r,12);
1701 } else {
1702 sparc_lshi(s, r,r, 20);
1703 }
1704 sparc_ori(s, r, r, (val & 0x00fff000) >> 12);
1705 sparc_lshi(s, r,r,12);
1706 sparc_ori(s, r, r, val & 0xfff);
1707 }
1708 }
1709 #else
1710 } else if (! (val & 0x3ff)) {
1711 /* no low bits */
1712 sparc_sethi(s, r, ((val >> 10) & 0x3fffff));
1713 } else {
1714 sparc_sethi(s, r, ((val >> 10) & 0x3fffff));
1715 sparc_ori(s, r, r, (val & 0x3ff));
1716 }
1717 #endif
1718 }
1719
1720 extern void sparc_bswap(s, junk, typ, dest, src)
1721 dill_stream s;
1722 int junk;
1723 int typ;
1724 int dest;
1725 int src;
1726 {
1727 sparc_mach_info smi = (sparc_mach_info) s->p->mach_info;
1728 sparc_pstorei(s, typ, 0, src, _fp, smi->conversion_word);
1729 sparc_pbsloadi(s, typ, 0, dest, _fp, smi->conversion_word);
1730 }
1731
1732 #define bit_R(x) ((unsigned long)1<<x)
1733
1734 extern void
sparc_reg_init(dill_stream s)1735 sparc_reg_init(dill_stream s)
1736 {
1737 s->p->var_i.init_avail[0] = (bit_R(_l0)|bit_R(_l1)|bit_R(_l2)|bit_R(_l3)|
1738 bit_R(_l4)|bit_R(_l5)|bit_R(_l6)|bit_R(_l7));
1739 s->p->var_i.members[0] = s->p->var_i.init_avail[0] |
1740 (bit_R(_i0)|bit_R(_i1)|bit_R(_i2)|bit_R(_i3)|
1741 bit_R(_i4)|bit_R(_i5)|bit_R(_i6)|bit_R(_i7));
1742 s->p->tmp_i.init_avail[0] = (bit_R(_g2)|bit_R(_g3));
1743 s->p->tmp_i.members[0] = s->p->tmp_i.init_avail[0] | bit_R(_g1);
1744 s->p->var_f.init_avail[0] = 0;
1745 s->p->var_f.members[0] = s->p->var_f.init_avail[0];
1746 s->p->tmp_f.init_avail[0] = (bit_R(_f2)|bit_R(_f4)|bit_R(_f6)|
1747 bit_R(_f8)|bit_R(_f10)|bit_R(_f12)|bit_R(_f14)|
1748 bit_R(_f16)|bit_R(_f18)|bit_R(_f20)|bit_R(_f22)|
1749 bit_R(_f24)|bit_R(_f26)|bit_R(_f28)|bit_R(_f30));
1750 s->p->tmp_f.members[0] = s->p->tmp_f.init_avail[0];
1751 }
1752
1753 extern void*
1754 gen_sparc_mach_info(s, v9)
1755 dill_stream s;
1756 int v9;
1757 {
1758 sparc_mach_info smi = malloc(sizeof(*smi));
1759 if (s->p->mach_info != NULL) {
1760 free(s->p->mach_info);
1761 s->p->mach_info = NULL;
1762 s->p->native.mach_info = NULL;
1763 }
1764 sparc_reg_init(s);
1765 smi->act_rec_size = 0;
1766 smi->conversion_word = 0;
1767 smi->cur_arg_offset = 0;
1768 if (v9) {
1769 smi->stack_align = 8; /* 8 for sparcv9 */
1770 smi->stack_constant_offset = 2047;
1771 } else {
1772 smi->stack_align = 4; /* 8 for sparcv9 */
1773 smi->stack_constant_offset = 0; /* 2047 for sparcv9 */
1774 }
1775 smi->gp_save_offset = (16 + 1 + 6 + 19 /* args */) * smi->stack_align; /*184;*/
1776 smi->fp_save_offset = smi->gp_save_offset + 8 * smi->stack_align;
1777 smi->fp_save_end = smi->fp_save_offset + 32 * smi->stack_align + 16;
1778 return smi;
1779 }
1780
1781 #if defined(HAVE_DIS_ASM_H) && !defined(NO_DISASSEMBLER)
1782 /* GENERIC BINUTILS DISASSEMBLER */
1783 #include "dis-asm.h"
1784
1785 #define MAXLENGTH (1<<23) /* Max length of function that can be disassembled */
1786
1787 extern int
sparc_init_disassembly_info(dill_stream s,void * ptr)1788 sparc_init_disassembly_info(dill_stream s, void * ptr)
1789 {
1790 struct disassemble_info *i = ptr;
1791 #ifdef INIT_DISASSEMBLE_INFO_THREE_ARG
1792 INIT_DISASSEMBLE_INFO(*i, stdout,fprintf);
1793 i->endian = BFD_ENDIAN_BIG;
1794 #else
1795 INIT_DISASSEMBLE_INFO(*i, stdout);
1796 #endif
1797 i->mach = bfd_mach_sparc_v9;
1798 if (s->p->code_base != NULL) {
1799 i->buffer = (bfd_byte *)s->p->code_base;
1800 i->buffer_vma = (bfd_vma)(long)s->p->code_base;
1801 } else {
1802 i->buffer = (bfd_byte *)s->p->native.code_base;
1803 i->buffer_vma = (bfd_vma)(long)s->p->native.code_base;
1804 }
1805 i->buffer_length = MAXLENGTH;
1806 #ifdef HAVE_PRINT_INSN_SPARC
1807 return 1;
1808 #else
1809 return 0;
1810 #endif
1811 }
1812
1813 extern int
sparc_print_insn(dill_stream s,void * info_ptr,void * insn)1814 sparc_print_insn(dill_stream s, void *info_ptr, void *insn)
1815 {
1816 #ifdef HAVE_PRINT_INSN_SPARC
1817 return print_insn_sparc((unsigned long) insn, (disassemble_info*)info_ptr);
1818 #else
1819 return 0;
1820 #endif
1821 }
1822 #else
1823 extern int
sparc_init_disassembly_info(dill_stream s,void * ptr)1824 sparc_init_disassembly_info(dill_stream s, void * ptr){return 0;}
sparc_print_insn(dill_stream s,void * info_ptr,void * insn)1825 extern int sparc_print_insn(dill_stream s, void *info_ptr, void *insn){return 0;}
1826 #endif
1827
1828 extern void
sparc_print_reg(dill_stream s,int typ,int reg)1829 sparc_print_reg(dill_stream s, int typ, int reg)
1830 {
1831 switch(typ) {
1832 case DILL_C: case DILL_UC:
1833 case DILL_S: case DILL_US:
1834 case DILL_I: case DILL_U: case DILL_L: case DILL_UL:
1835 if (reg == _fp) {
1836 printf("fp");
1837 return;
1838 } else if (reg == _ra) {
1839 printf("ra");
1840 return;
1841 } else if (reg == _sp) {
1842 printf("sp");
1843 return;
1844 } else if (reg <= _g7) {
1845 printf("g%d\n", reg - _g0);
1846 return;
1847 } else if (reg <= _o7) {
1848 printf("o%d\n", reg - _o0);
1849 return;
1850 } else if (reg <= _l7) {
1851 printf("l%d\n", reg - _l0);
1852 return;
1853 } else if (reg <= _i7) {
1854 printf("i%d\n", reg - _i0);
1855 return;
1856 }
1857 break;
1858 case DILL_F: case DILL_D:
1859 printf("F%d", reg);
1860 return;
1861 }
1862 printf("NoReg(%d)", reg);
1863 }
1864
1865 extern int
sparc_count_insn(dill_stream s,int start,int end)1866 sparc_count_insn(dill_stream s, int start, int end)
1867 {
1868 return (end - start)>>2;
1869 }
1870