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, &reg);
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