xref: /netbsd-src/external/bsd/pcc/dist/pcc/arch/mips/local2.c (revision daf6c4152fcddc27c445489775ed1f66ab4ea9a9)
1 /*	Id: local2.c,v 1.25 2008/12/03 22:23:38 gmcgarry Exp 	 */
2 /*	$NetBSD: local2.c,v 1.1.1.3 2010/06/03 18:57:19 plunky Exp $	 */
3 /*
4  * Copyright (c) 2003 Anders Magnusson (ragge@ludd.luth.se).
5  * All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  * 1. Redistributions of source code must retain the above copyright
11  *    notice, this list of conditions and the following disclaimer.
12  * 2. Redistributions in binary form must reproduce the above copyright
13  *    notice, this list of conditions and the following disclaimer in the
14  *    documentation and/or other materials provided with the distribution.
15  * 3. The name of the author may not be used to endorse or promote products
16  *    derived from this software without specific prior written permission
17  *
18  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
19  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
20  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
21  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
22  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
23  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
24  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
25  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
27  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28  */
29 
30 /*
31  * MIPS port by Jan Enoksson (janeno-1@student.ltu.se) and
32  * Simon Olsson (simols-1@student.ltu.se) 2005.
33  */
34 
35 #include <ctype.h>
36 #include <string.h>
37 #include <stdlib.h>
38 #include <assert.h>
39 
40 #include "pass1.h"
41 #include "pass2.h"
42 
43 #ifdef TARGET_BIG_ENDIAN
44 int bigendian = 1;
45 #else
46 int bigendian = 0;
47 #endif
48 
49 int nargregs = MIPS_O32_NARGREGS;
50 
51 static int argsiz(NODE *p);
52 
53 void
54 deflab(int label)
55 {
56 	printf(LABFMT ":\n", label);
57 }
58 
59 static int regoff[32];
60 static TWORD ftype;
61 
62 /*
63  * calculate stack size and offsets
64  */
65 static int
66 offcalc(struct interpass_prolog * ipp)
67 {
68 	int i, j, addto;
69 
70 	addto = p2maxautooff;
71 
72 	for (i = ipp->ipp_regs[0], j = 0; i; i >>= 1, j++) {
73 		if (i & 1) {
74 			addto += SZINT / SZCHAR;
75 			regoff[j] = addto;
76 		}
77 	}
78 
79         /* round to 8-byte boundary */
80         addto += 7;
81         addto &= ~7;
82 
83 	return addto;
84 }
85 
86 /*
87  * Print out the prolog assembler.
88  */
89 void
90 prologue(struct interpass_prolog * ipp)
91 {
92 	int addto;
93 	int i, j;
94 
95 	ftype = ipp->ipp_type;
96 	printf("\t.align 2\n");
97 	if (ipp->ipp_vis)
98 		printf("\t.globl %s\n", ipp->ipp_name);
99 	printf("\t.ent %s\n", ipp->ipp_name);
100 	printf("%s:\n", ipp->ipp_name);
101 
102 	addto = offcalc(ipp);
103 
104 	/* for the moment, just emit this PIC stuff - NetBSD does it */
105 	printf("\t.frame %s,%d,%s\n", rnames[FP], ARGINIT/SZCHAR, rnames[RA]);
106 	printf("\t.set noreorder\n");
107 	printf("\t.cpload $25\t# pseudo-op to load GOT ptr into $25\n");
108 	printf("\t.set reorder\n");
109 
110 	printf("\tsubu %s,%s,%d\n", rnames[SP], rnames[SP], ARGINIT/SZCHAR);
111 	/* for the moment, just emit PIC stuff - NetBSD does it */
112 	printf("\t.cprestore 8\t# pseudo-op to store GOT ptr at 8(sp)\n");
113 
114 	printf("\tsw %s,4(%s)\n", rnames[RA], rnames[SP]);
115 	printf("\tsw %s,(%s)\n", rnames[FP], rnames[SP]);
116 	printf("\tmove %s,%s\n", rnames[FP], rnames[SP]);
117 
118 #ifdef notyet
119 	/* profiling */
120 	if (pflag) {
121 		printf("\t.set noat\n");
122 		printf("\tmove %s,%s\t# save current return address\n",
123 		    rnames[AT], rnames[RA]);
124 		printf("\tsubu %s,%s,8\t# _mcount pops 2 words from stack\n",
125 		    rnames[SP], rnames[SP]);
126 		printf("\tjal %s\n", exname("_mcount"));
127 		printf("\tnop\n");
128 		printf("\t.set at\n");
129 	}
130 #endif
131 
132 	if (addto)
133 		printf("\tsubu %s,%s,%d\n", rnames[SP], rnames[SP], addto);
134 
135 	for (i = ipp->ipp_regs[0], j = 0; i; i >>= 1, j++)
136 		if (i & 1)
137 			fprintf(stdout, "\tsw %s,-%d(%s) # save permanent\n",
138 				rnames[j], regoff[j], rnames[FP]);
139 
140 }
141 
142 void
143 eoftn(struct interpass_prolog * ipp)
144 {
145 	int i, j;
146 	int addto;
147 
148 	addto = offcalc(ipp);
149 
150 	if (ipp->ipp_ip.ip_lbl == 0)
151 		return;		/* no code needs to be generated */
152 
153 	/* return from function code */
154 	for (i = ipp->ipp_regs[0], j = 0; i; i >>= 1, j++) {
155 		if (i & 1)
156 			fprintf(stdout, "\tlw %s,-%d(%s)\n\tnop\n",
157 				rnames[j], regoff[j], rnames[FP]);
158 	}
159 
160 	printf("\taddiu %s,%s,%d\n", rnames[SP], rnames[FP], ARGINIT/SZCHAR);
161 	printf("\tlw %s,%d(%s)\n", rnames[RA], 4-ARGINIT/SZCHAR,  rnames[SP]);
162 	printf("\tlw %s,%d(%s)\n", rnames[FP], 0-ARGINIT/SZCHAR,  rnames[SP]);
163 
164 	printf("\tjr %s\n", rnames[RA]);
165 	printf("\tnop\n");
166 
167 #ifdef USE_GAS
168 	printf("\t.end %s\n", ipp->ipp_name);
169 	printf("\t.size %s,.-%s\n", ipp->ipp_name, ipp->ipp_name);
170 #endif
171 }
172 
173 /*
174  * add/sub/...
175  *
176  * Param given:
177  */
178 void
179 hopcode(int f, int o)
180 {
181 	char *str;
182 
183 	switch (o) {
184 	case EQ:
185 		str = "beqz";	/* pseudo-op */
186 		break;
187 	case NE:
188 		str = "bnez";	/* pseudo-op */
189 		break;
190 	case ULE:
191 	case LE:
192 		str = "blez";
193 		break;
194 	case ULT:
195 	case LT:
196 		str = "bltz";
197 		break;
198 	case UGE:
199 	case GE:
200 		str = "bgez";
201 		break;
202 	case UGT:
203 	case GT:
204 		str = "bgtz";
205 		break;
206 	case PLUS:
207 		str = "add";
208 		break;
209 	case MINUS:
210 		str = "sub";
211 		break;
212 	case AND:
213 		str = "and";
214 		break;
215 	case OR:
216 		str = "or";
217 		break;
218 	case ER:
219 		str = "xor";
220 		break;
221 	default:
222 		comperr("hopcode2: %d", o);
223 		str = 0;	/* XXX gcc */
224 	}
225 
226 	printf("%s%c", str, f);
227 }
228 
229 char *
230 rnames[] = {
231 #ifdef USE_GAS
232 	/* gnu assembler */
233 	"$zero", "$at", "$2", "$3", "$4", "$5", "$6", "$7",
234 	"$8", "$9", "$10", "$11", "$12", "$13", "$14", "$15",
235 	"$16", "$17", "$18", "$19", "$20", "$21", "$22", "$23",
236 	"$24", "$25",
237 	"$kt0", "$kt1", "$gp", "$sp", "$fp", "$ra",
238 	"$2!!$3!!",
239 	"$4!!$5!!", "$5!!$6!!", "$6!!$7!!", "$7!!$8!!",
240 	"$8!!$9!!", "$9!!$10!", "$10!$11!", "$11!$12!",
241 	"$12!$13!", "$13!$14!", "$14!$15!", "$15!$24!", "$24!$25!",
242 	"$16!$17!", "$17!$18!", "$18!$19!", "$19!$20!",
243 	"$20!$21!", "$21!$22!", "$22!$23!",
244 #else
245 	/* mips assembler */
246 	 "$zero", "$at", "$v0", "$v1", "$a0", "$a1", "$a2", "$a3",
247 	"$t0", "$t1", "$t2", "$t3", "$t4", "$t5", "$t6", "$t7",
248 	"$s0", "$s1", "$s2", "$s3", "$s4", "$s5", "$s6", "$s7",
249 	"$t8", "$t9",
250 	"$k0", "$k1", "$gp", "$sp", "$fp", "$ra",
251 	"$v0!$v1!",
252 	"$a0!$a1!", "$a1!$a2!", "$a2!$a3!", "$a3!$t0!",
253 	"$t0!$t1!", "$t1!$t2!", "$t2!$t3!", "$t3!$t4!",
254 	"$t4!$t5!", "$t5!$t6!", "$t6!$t7!", "$t7!$t8!", "$t8!$t9!",
255 	"$s0!$s1!", "$s1!$s2!", "$s2!$s3!", "$s3!$s4!",
256 	"$s4!$s5!", "$s5!$s6!", "$s6!$s7!",
257 #endif
258 	"$f0!$f1!", "$f2!$f3!", "$f4!$f5!", "$f6!$f7!",
259 	"$f8!$f9!", "$f10$f11", "$f12$f13", "$f14$f15",
260 	"$f16$f17", "$f18$f19", "$f20$f21", "$f22$f23",
261 	"$f24$f25", "$f26$f27", "$f28$f29", "$f30$f31",
262 };
263 
264 char *
265 rnames_n32[] = {
266 	/* mips assembler */
267 	"$zero", "$at", "$v0", "$v1", "$a0", "$a1", "$a2", "$a3",
268 	"$a4", "$a5", "$a6", "$a7", "$t0", "$t1", "$t2", "$t3",
269 	"$s0", "$s1", "$s2", "$s3", "$s4", "$s5", "$s6", "$s7",
270 	"$t8", "$t9",
271 	"$k0", "$k1", "$gp", "$sp", "$fp", "$ra",
272 	"$v0!$v1!",
273 	"$a0!$a1!", "$a1!$a2!", "$a2!$a3!", "$a3!$a4!",
274 	"$a4!$a5!", "$a5!$a6!", "$a6!$a7!", "$a7!$t0!",
275 	"$t0!$t1!", "$t1!$t2!", "$t2!$t3!", "$t3!$t8!", "$t8!$t9!",
276 	"$s0!$s1!", "$s1!$s2!", "$s2!$s3!", "$s3!$s4!",
277 	"$s4!$s5!", "$s5!$s6!", "$s6!$s7!",
278 	"$f0!$f1!", "$f2!$f3!", "$f4!$f5!", "$f6!$f7!",
279 	"$f8!$f9!", "$f10$f11", "$f12$f13", "$f14$f15",
280 	"$f16$f17", "$f18$f19", "$f20$f21", "$f22$f23",
281 	"$f24$f25", "$f26$f27", "$f28$f29", "$f30$f31",
282 };
283 
284 int
285 tlen(NODE *p)
286 {
287 	switch (p->n_type) {
288 	case CHAR:
289 	case UCHAR:
290 		return (1);
291 
292 	case SHORT:
293 	case USHORT:
294 		return (SZSHORT / SZCHAR);
295 
296 	case DOUBLE:
297 		return (SZDOUBLE / SZCHAR);
298 
299 	case INT:
300 	case UNSIGNED:
301 	case LONG:
302 	case ULONG:
303 		return (SZINT / SZCHAR);
304 
305 	case LONGLONG:
306 	case ULONGLONG:
307 		return SZLONGLONG / SZCHAR;
308 
309 	default:
310 		if (!ISPTR(p->n_type))
311 			comperr("tlen type %d not pointer");
312 		return SZPOINT(p->n_type) / SZCHAR;
313 	}
314 }
315 
316 
317 /*
318  * Push a structure on stack as argument.
319  */
320 static void
321 starg(NODE *p)
322 {
323 	//assert(p->n_rval == A1);
324 	printf("\tsubu %s,%s,%d\n", rnames[SP], rnames[SP], p->n_stsize);
325 	/* A0 = dest, A1 = src, A2 = len */
326 	printf("\tmove %s,%s\n", rnames[A0], rnames[SP]);
327 	printf("\tli %s,%d\t# structure size\n", rnames[A2], p->n_stsize);
328 	printf("\tsubu %s,%s,16\n", rnames[SP], rnames[SP]);
329 	printf("\tjal %s\t# structure copy\n", exname("memcpy"));
330 	printf("\tnop\n");
331 	printf("\taddiu %s,%s,16\n", rnames[SP], rnames[SP]);
332 }
333 
334 /*
335  * Structure assignment.
336  */
337 static void
338 stasg(NODE *p)
339 {
340 	assert(p->n_right->n_rval == A1);
341 	/* A0 = dest, A1 = src, A2 = len */
342 	printf("\tli %s,%d\t# structure size\n", rnames[A2], p->n_stsize);
343 	if (p->n_left->n_op == OREG) {
344 		printf("\taddiu %s,%s," CONFMT "\t# dest address\n",
345 		    rnames[A0], rnames[p->n_left->n_rval],
346 		    p->n_left->n_lval);
347 	} else if (p->n_left->n_op == NAME) {
348 		printf("\tla %s,", rnames[A0]);
349 		adrput(stdout, p->n_left);
350 		printf("\n");
351 	}
352 	printf("\tsubu %s,%s,16\n", rnames[SP], rnames[SP]);
353 	printf("\tjal %s\t# structure copy\n", exname("memcpy"));
354 	printf("\tnop\n");
355 	printf("\taddiu %s,%s,16\n", rnames[SP], rnames[SP]);
356 }
357 
358 static void
359 shiftop(NODE *p)
360 {
361 	NODE *r = p->n_right;
362 	TWORD ty = p->n_type;
363 
364 	if (p->n_op == LS && r->n_op == ICON && r->n_lval < 32) {
365 		expand(p, INBREG, "\tsrl A1,AL,");
366 		printf(CONFMT "\t# 64-bit left-shift\n", 32 - r->n_lval);
367 		expand(p, INBREG, "\tsll U1,UL,AR\n");
368 		expand(p, INBREG, "\tor U1,U1,A1\n");
369 		expand(p, INBREG, "\tsll A1,AL,AR\n");
370 	} else if (p->n_op == LS && r->n_op == ICON && r->n_lval < 64) {
371 		expand(p, INBREG, "\tli A1,0\t# 64-bit left-shift\n");
372 		expand(p, INBREG, "\tsll U1,AL,");
373 		printf(CONFMT "\n", r->n_lval - 32);
374 	} else if (p->n_op == LS && r->n_op == ICON) {
375 		expand(p, INBREG, "\tli A1,0\t# 64-bit left-shift\n");
376 		expand(p, INBREG, "\tli U1,0\n");
377 	} else if (p->n_op == RS && r->n_op == ICON && r->n_lval < 32) {
378 		expand(p, INBREG, "\tsll U1,UL,");
379 		printf(CONFMT "\t# 64-bit right-shift\n", 32 - r->n_lval);
380 		expand(p, INBREG, "\tsrl A1,AL,AR\n");
381 		expand(p, INBREG, "\tor A1,A1,U1\n");
382 		if (ty == LONGLONG)
383 			expand(p, INBREG, "\tsra U1,UL,AR\n");
384 		else
385 			expand(p, INBREG, "\tsrl U1,UL,AR\n");
386 	} else if (p->n_op == RS && r->n_op == ICON && r->n_lval < 64) {
387 		if (ty == LONGLONG) {
388 			expand(p, INBREG, "\tsra U1,UL,31\t# 64-bit right-shift\n");
389 			expand(p, INBREG, "\tsra A1,UL,");
390 		}else {
391 			expand(p, INBREG, "\tli U1,0\t# 64-bit right-shift\n");
392 			expand(p, INBREG, "\tsrl A1,UL,");
393 		}
394 		printf(CONFMT "\n", r->n_lval - 32);
395 	} else if (p->n_op == LS && r->n_op == ICON) {
396 		expand(p, INBREG, "\tli A1,0\t# 64-bit right-shift\n");
397 		expand(p, INBREG, "\tli U1,0\n");
398 	} else {
399 		comperr("shiftop");
400 	}
401 }
402 
403 /*
404  * http://gcc.gnu.org/onlinedocs/gccint/Soft-float-library-routines.html#Soft-float-library-routines
405  */
406 static void
407 fpemulop(NODE *p)
408 {
409 	NODE *l = p->n_left;
410 	char *ch = NULL;
411 
412 	if (p->n_op == PLUS && p->n_type == FLOAT) ch = "addsf3";
413 	else if (p->n_op == PLUS && p->n_type == DOUBLE) ch = "adddf3";
414 	else if (p->n_op == PLUS && p->n_type == LDOUBLE) ch = "addtf3";
415 
416 	else if (p->n_op == MINUS && p->n_type == FLOAT) ch = "subsf3";
417 	else if (p->n_op == MINUS && p->n_type == DOUBLE) ch = "subdf3";
418 	else if (p->n_op == MINUS && p->n_type == LDOUBLE) ch = "subtf3";
419 
420 	else if (p->n_op == MUL && p->n_type == FLOAT) ch = "mulsf3";
421 	else if (p->n_op == MUL && p->n_type == DOUBLE) ch = "muldf3";
422 	else if (p->n_op == MUL && p->n_type == LDOUBLE) ch = "multf3";
423 
424 	else if (p->n_op == DIV && p->n_type == FLOAT) ch = "divsf3";
425 	else if (p->n_op == DIV && p->n_type == DOUBLE) ch = "divdf3";
426 	else if (p->n_op == DIV && p->n_type == LDOUBLE) ch = "divtf3";
427 
428 	else if (p->n_op == UMINUS && p->n_type == FLOAT) ch = "negsf2";
429 	else if (p->n_op == UMINUS && p->n_type == DOUBLE) ch = "negdf2";
430 	else if (p->n_op == UMINUS && p->n_type == LDOUBLE) ch = "negtf2";
431 
432 	else if (p->n_op == EQ && l->n_type == FLOAT) ch = "eqsf2";
433 	else if (p->n_op == EQ && l->n_type == DOUBLE) ch = "eqdf2";
434 	else if (p->n_op == EQ && l->n_type == LDOUBLE) ch = "eqtf2";
435 
436 	else if (p->n_op == NE && l->n_type == FLOAT) ch = "nesf2";
437 	else if (p->n_op == NE && l->n_type == DOUBLE) ch = "nedf2";
438 	else if (p->n_op == NE && l->n_type == LDOUBLE) ch = "netf2";
439 
440 	else if (p->n_op == GE && l->n_type == FLOAT) ch = "gesf2";
441 	else if (p->n_op == GE && l->n_type == DOUBLE) ch = "gedf2";
442 	else if (p->n_op == GE && l->n_type == LDOUBLE) ch = "getf2";
443 
444 	else if (p->n_op == LE && l->n_type == FLOAT) ch = "lesf2";
445 	else if (p->n_op == LE && l->n_type == DOUBLE) ch = "ledf2";
446 	else if (p->n_op == LE && l->n_type == LDOUBLE) ch = "letf2";
447 
448 	else if (p->n_op == GT && l->n_type == FLOAT) ch = "gtsf2";
449 	else if (p->n_op == GT && l->n_type == DOUBLE) ch = "gtdf2";
450 	else if (p->n_op == GT && l->n_type == LDOUBLE) ch = "gttf2";
451 
452 	else if (p->n_op == LT && l->n_type == FLOAT) ch = "ltsf2";
453 	else if (p->n_op == LT && l->n_type == DOUBLE) ch = "ltdf2";
454 	else if (p->n_op == LT && l->n_type == LDOUBLE) ch = "lttf2";
455 
456 	else if (p->n_op == SCONV && p->n_type == FLOAT) {
457 		if (l->n_type == DOUBLE) ch = "truncdfsf2";
458 		else if (l->n_type == LDOUBLE) ch = "trunctfsf2";
459 		else if (l->n_type == ULONGLONG) ch = "floatdisf"; /**/
460 		else if (l->n_type == LONGLONG) ch = "floatdisf";
461 		else if (l->n_type == LONG) ch = "floatsisf";
462 		else if (l->n_type == ULONG) ch = "floatunsisf";
463 		else if (l->n_type == INT) ch = "floatsisf";
464 		else if (l->n_type == UNSIGNED) ch = "floatunsisf";
465 	} else if (p->n_op == SCONV && p->n_type == DOUBLE) {
466 		if (l->n_type == FLOAT) ch = "extendsfdf2";
467 		else if (l->n_type == LDOUBLE) ch = "trunctfdf2";
468 		else if (l->n_type == ULONGLONG) ch = "floatunsdidf";
469 		else if (l->n_type == LONGLONG) ch = "floatdidf";
470 		else if (l->n_type == LONG) ch = "floatsidf";
471 		else if (l->n_type == ULONG) ch = "floatunsidf";
472 		else if (l->n_type == INT) ch = "floatsidf";
473 		else if (l->n_type == UNSIGNED) ch = "floatunsidf";
474 	} else if (p->n_op == SCONV && p->n_type == LDOUBLE) {
475 		if (l->n_type == FLOAT) ch = "extendsftf2";
476 		else if (l->n_type == DOUBLE) ch = "extenddfdf2";
477 		else if (l->n_type == ULONGLONG) ch = "floatunsdidf";
478 		else if (l->n_type == LONGLONG) ch = "floatdidf";
479 		else if (l->n_type == LONG) ch = "floatsidf";
480 		else if (l->n_type == ULONG) ch = "floatunssidf";
481 		else if (l->n_type == INT) ch = "floatsidf";
482 		else if (l->n_type == UNSIGNED) ch = "floatunsidf";
483 	} else if (p->n_op == SCONV && p->n_type == ULONGLONG) {
484 		if (l->n_type == FLOAT) ch = "fixunssfdi";
485 		else if (l->n_type == DOUBLE) ch = "fixunsdfdi";
486 		else if (l->n_type == LDOUBLE) ch = "fixunsdfdi";
487 	} else if (p->n_op == SCONV && p->n_type == LONGLONG) {
488 		if (l->n_type == FLOAT) ch = "fixsfdi";
489 		else if (l->n_type == DOUBLE) ch = "fixdfdi";
490 		else if (l->n_type == LDOUBLE) ch = "fixdfdi";
491 	} else if (p->n_op == SCONV && p->n_type == LONG) {
492 		if (l->n_type == FLOAT) ch = "fixsfsi";
493 		else if (l->n_type == DOUBLE) ch = "fixdfsi";
494 		else if (l->n_type == LDOUBLE) ch = "fixdfsi";
495 	} else if (p->n_op == SCONV && p->n_type == ULONG) {
496 		if (l->n_type == FLOAT) ch = "fixunssfsi";
497 		else if (l->n_type == DOUBLE) ch = "fixunsdfsi";
498 		else if (l->n_type == LDOUBLE) ch = "fixunsdfsi";
499 	} else if (p->n_op == SCONV && p->n_type == INT) {
500 		if (l->n_type == FLOAT) ch = "fixsfsi";
501 		else if (l->n_type == DOUBLE) ch = "fixdfsi";
502 		else if (l->n_type == LDOUBLE) ch = "fixdfsi";
503 	} else if (p->n_op == SCONV && p->n_type == UNSIGNED) {
504 		if (l->n_type == FLOAT) ch = "fixunssfsi";
505 		else if (l->n_type == DOUBLE) ch = "fixunsdfsi";
506 		else if (l->n_type == LDOUBLE) ch = "fixunsdfsi";
507 	}
508 
509 	if (ch == NULL) comperr("ZF: op=0x%x (%d)\n", p->n_op, p->n_op);
510 
511 	if (p->n_op == SCONV) {
512 		if (l->n_type == FLOAT) {
513 			printf("\tmfc1 %s,", rnames[A0]);
514 			adrput(stdout, l);
515 			printf("\n\tnop\n");
516 		}  else if (l->n_type == DOUBLE || l->n_type == LDOUBLE) {
517 			printf("\tmfc1 %s,", rnames[A1]);
518 			upput(l, 0);
519 			printf("\n\tnop\n");
520 			printf("\tmfc1 %s,", rnames[A0]);
521 			adrput(stdout, l);
522 			printf("\n\tnop\n");
523 		}
524 	} else {
525 		comperr("ZF: incomplete softfloat - put args in registers");
526 	}
527 
528 	printf("\tjal __%s\t# softfloat operation\n", exname(ch));
529 	printf("\tnop\n");
530 
531 	if (p->n_op >= EQ && p->n_op <= GT)
532 		printf("\tcmp %s,0\n", rnames[V0]);
533 }
534 
535 /*
536  * http://gcc.gnu.org/onlinedocs/gccint/Integer-library-routines.html#Integer-library-routines
537  */
538 static void
539 emulop(NODE *p)
540 {
541 	char *ch = NULL;
542 
543 	if (p->n_op == LS && DEUNSIGN(p->n_type) == LONGLONG) ch = "ashldi3";
544 	else if (p->n_op == LS && (DEUNSIGN(p->n_type) == LONG ||
545 	    DEUNSIGN(p->n_type) == INT))
546 		ch = "ashlsi3";
547 
548 	else if (p->n_op == RS && p->n_type == ULONGLONG) ch = "lshrdi3";
549 	else if (p->n_op == RS && (p->n_type == ULONG || p->n_type == INT))
550 		ch = "lshrsi3";
551 
552 	else if (p->n_op == RS && p->n_type == LONGLONG) ch = "ashrdi3";
553 	else if (p->n_op == RS && (p->n_type == LONG || p->n_type == INT))
554 		ch = "ashrsi3";
555 
556 	else if (p->n_op == DIV && p->n_type == LONGLONG) ch = "divdi3";
557 	else if (p->n_op == DIV && (p->n_type == LONG || p->n_type == INT))
558 		ch = "divsi3";
559 
560 	else if (p->n_op == DIV && p->n_type == ULONGLONG) ch = "udivdi3";
561 	else if (p->n_op == DIV && (p->n_type == ULONG ||
562 	    p->n_type == UNSIGNED))
563 		ch = "udivsi3";
564 
565 	else if (p->n_op == MOD && p->n_type == LONGLONG) ch = "moddi3";
566 	else if (p->n_op == MOD && (p->n_type == LONG || p->n_type == INT))
567 		ch = "modsi3";
568 
569 	else if (p->n_op == MOD && p->n_type == ULONGLONG) ch = "umoddi3";
570 	else if (p->n_op == MOD && (p->n_type == ULONG ||
571 	    p->n_type == UNSIGNED))
572 		ch = "umodsi3";
573 
574 	else if (p->n_op == MUL && p->n_type == LONGLONG) ch = "muldi3";
575 	else if (p->n_op == MUL && (p->n_type == LONG || p->n_type == INT))
576 		ch = "mulsi3";
577 
578 	else if (p->n_op == UMINUS && p->n_type == LONGLONG) ch = "negdi2";
579 	else if (p->n_op == UMINUS && p->n_type == LONG) ch = "negsi2";
580 
581 	else ch = 0, comperr("ZE");
582 	printf("\tsubu %s,%s,16\n", rnames[SP], rnames[SP]);
583 	printf("\tjal __%s\t# emulated operation\n", exname(ch));
584 	printf("\tnop\n");
585 	printf("\taddiu %s,%s,16\n", rnames[SP], rnames[SP]);
586 }
587 
588 /*
589  * Emit code to compare two longlong numbers.
590  */
591 static void
592 twollcomp(NODE *p)
593 {
594 	int o = p->n_op;
595 	int s = getlab2();
596 	int e = p->n_label;
597 	int cb1, cb2;
598 
599 	if (o >= ULE)
600 		o -= (ULE-LE);
601 	switch (o) {
602 	case NE:
603 		cb1 = 0;
604 		cb2 = NE;
605 		break;
606 	case EQ:
607 		cb1 = NE;
608 		cb2 = 0;
609 		break;
610 	case LE:
611 	case LT:
612 		cb1 = GT;
613 		cb2 = LT;
614 		break;
615 	case GE:
616 	case GT:
617 		cb1 = LT;
618 		cb2 = GT;
619 		break;
620 
621 	default:
622 		cb1 = cb2 = 0; /* XXX gcc */
623 	}
624 	if (p->n_op >= ULE)
625 		cb1 += 4, cb2 += 4;
626 	expand(p, 0, "\tsub A1,UL,UR\t# compare 64-bit values (upper)\n");
627 	if (cb1) {
628 		printf("\t");
629 		hopcode(' ', cb1);
630 		expand(p, 0, "A1");
631 		printf("," LABFMT "\n", s);
632 		printf("\tnop\n");
633 	}
634 	if (cb2) {
635 		printf("\t");
636 		hopcode(' ', cb2);
637 		expand(p, 0, "A1");
638 		printf("," LABFMT "\n", e);
639 		printf("\tnop\n");
640 	}
641 	expand(p, 0, "\tsub A1,AL,AR\t# (and lower)\n");
642 	printf("\t");
643 	hopcode(' ', o);
644 	expand(p, 0, "A1");
645 	printf("," LABFMT "\n", e);
646 	printf("\tnop\n");
647 	deflab(s);
648 }
649 
650 static void
651 fpcmpops(NODE *p)
652 {
653 	NODE *l = p->n_left;
654 
655 	switch (p->n_op) {
656 	case EQ:
657 		if (l->n_type == FLOAT)
658 			expand(p, 0, "\tc.eq.s AL,AR\n");
659 		else
660 			expand(p, 0, "\tc.eq.d AL,AR\n");
661 		expand(p, 0, "\tnop\n\tbc1t LC\n");
662 		break;
663 	case NE:
664 		if (l->n_type == FLOAT)
665 			expand(p, 0, "\tc.eq.s AL,AR\n");
666 		else
667 			expand(p, 0, "\tc.eq.d AL,AR\n");
668 		expand(p, 0, "\tnop\n\tbc1f LC\n");
669 		break;
670 	case LT:
671 		if (l->n_type == FLOAT)
672 			expand(p, 0, "\tc.lt.s AL,AR\n");
673 		else
674 			expand(p, 0, "\tc.lt.d AL,AR\n");
675 		expand(p, 0, "\tnop\n\tbc1t LC\n");
676 		break;
677 	case GE:
678 		if (l->n_type == FLOAT)
679 			expand(p, 0, "\tc.lt.s AL,AR\n");
680 		else
681 			expand(p, 0, "\tc.lt.d AL,AR\n");
682 		expand(p, 0, "\tnop\n\tbc1f LC\n");
683 		break;
684 	case LE:
685 		if (l->n_type == FLOAT)
686 			expand(p, 0, "\tc.le.s AL,AR\n");
687 		else
688 			expand(p, 0, "\tc.le.d AL,AR\n");
689 		expand(p, 0, "\tnop\n\tbc1t LC\n");
690 		break;
691 	case GT:
692 		if (l->n_type == FLOAT)
693 			expand(p, 0, "\tc.le.s AL,AR\n");
694 		else
695 			expand(p, 0, "\tc.le.d AL,AR\n");
696 		expand(p, 0, "\tnop\n\tbc1f LC\n");
697 		break;
698 	}
699 	printf("\tnop\n\tnop\n");
700 }
701 
702 void
703 zzzcode(NODE * p, int c)
704 {
705 	int sz;
706 
707 	switch (c) {
708 
709 	case 'C':	/* remove arguments from stack after subroutine call */
710 		sz = p->n_qual > 16 ? p->n_qual : 16;
711 		printf("\taddiu %s,%s,%d\n", rnames[SP], rnames[SP], sz);
712 		break;
713 
714 	case 'D':	/* long long comparison */
715 		twollcomp(p);
716 		break;
717 
718 	case 'E':	/* emit emulated ops */
719 		emulop(p);
720 		break;
721 
722 	case 'F':	/* emit emulate floating point ops */
723 		fpemulop(p);
724 		break;
725 
726 	case 'G':	/* emit hardware floating-point compare op */
727 		fpcmpops(p);
728 		break;
729 
730 	case 'H':	/* structure argument */
731 		starg(p);
732 		break;
733 
734 	case 'I':		/* high part of init constant */
735 		if (p->n_name[0] != '\0')
736 			comperr("named highword");
737 		fprintf(stdout, CONFMT, (p->n_lval >> 32) & 0xffffffff);
738 		break;
739 
740         case 'O': /* 64-bit left and right shift operators */
741 		shiftop(p);
742 		break;
743 
744 	case 'Q':		/* emit struct assign */
745 		stasg(p);
746 		break;
747 
748 	default:
749 		comperr("zzzcode %c", c);
750 	}
751 }
752 
753 /* ARGSUSED */
754 int
755 rewfld(NODE * p)
756 {
757 	return (1);
758 }
759 
760 int
761 fldexpand(NODE *p, int cookie, char **cp)
762 {
763         CONSZ val;
764 
765         if (p->n_op == ASSIGN)
766                 p = p->n_left;
767         switch (**cp) {
768         case 'S':
769                 printf("%d", UPKFSZ(p->n_rval));
770                 break;
771         case 'H':
772                 printf("%d", UPKFOFF(p->n_rval));
773                 break;
774         case 'M':
775         case 'N':
776                 val = (CONSZ)1 << UPKFSZ(p->n_rval);
777                 --val;
778                 val <<= UPKFOFF(p->n_rval);
779                 printf("0x%llx", (**cp == 'M' ? val : ~val)  & 0xffffffff);
780                 break;
781         default:
782                 comperr("fldexpand");
783         }
784         return 1;
785 }
786 
787 /*
788  * Does the bitfield shape match?
789  */
790 int
791 flshape(NODE * p)
792 {
793 	int o = p->n_op;
794 
795 	if (o == OREG || o == REG || o == NAME)
796 		return SRDIR;	/* Direct match */
797 	if (o == UMUL && shumul(p->n_left, SOREG))
798 		return SROREG;	/* Convert into oreg */
799 	return SRREG;		/* put it into a register */
800 }
801 
802 /* INTEMP shapes must not contain any temporary registers */
803 /* XXX should this go away now? */
804 int
805 shtemp(NODE * p)
806 {
807 	return 0;
808 #if 0
809 	int r;
810 
811 	if (p->n_op == STARG)
812 		p = p->n_left;
813 
814 	switch (p->n_op) {
815 	case REG:
816 		return (!istreg(p->n_rval));
817 
818 	case OREG:
819 		r = p->n_rval;
820 		if (R2TEST(r)) {
821 			if (istreg(R2UPK1(r)))
822 				return (0);
823 			r = R2UPK2(r);
824 		}
825 		return (!istreg(r));
826 
827 	case UMUL:
828 		p = p->n_left;
829 		return (p->n_op != UMUL && shtemp(p));
830 	}
831 
832 	if (optype(p->n_op) != LTYPE)
833 		return (0);
834 	return (1);
835 #endif
836 }
837 
838 void
839 adrcon(CONSZ val)
840 {
841 	printf(CONFMT, val);
842 }
843 
844 void
845 conput(FILE *fp, NODE *p)
846 {
847 	int val = p->n_lval;
848 
849 	switch (p->n_op) {
850 	case ICON:
851 		if (p->n_name[0] != '\0') {
852 			fprintf(fp, "%s", p->n_name);
853 			if (p->n_lval)
854 				fprintf(fp, "+%d", val);
855 		} else
856 			fprintf(fp, "%d", val);
857 		return;
858 
859 	default:
860 		comperr("illegal conput");
861 	}
862 }
863 
864 /* ARGSUSED */
865 void
866 insput(NODE * p)
867 {
868 	comperr("insput");
869 }
870 
871 /*
872  * Print lower or upper name of 64-bit register.
873  */
874 static void
875 print_reg64name(FILE *fp, int rval, int hi)
876 {
877         int off = 4 * (hi != 0);
878 	char *regname = rnames[rval];
879 
880         fprintf(fp, "%c%c",
881                  regname[off],
882                  regname[off + 1]);
883         if (regname[off + 2] != '!')
884                 fputc(regname[off + 2], fp);
885         if (regname[off + 3] != '!')
886                 fputc(regname[off + 3], fp);
887 }
888 
889 /*
890  * Write out the upper address, like the upper register of a 2-register
891  * reference, or the next memory location.
892  */
893 void
894 upput(NODE * p, int size)
895 {
896 
897 	size /= SZCHAR;
898 	switch (p->n_op) {
899 	case REG:
900 		if (GCLASS(p->n_rval) == CLASSB || GCLASS(p->n_rval) == CLASSC)
901 			print_reg64name(stdout, p->n_rval, 1);
902 		else
903 			fputs(rnames[p->n_rval], stdout);
904 		break;
905 
906 	case NAME:
907 	case OREG:
908 		p->n_lval += size;
909 		adrput(stdout, p);
910 		p->n_lval -= size;
911 		break;
912 	case ICON:
913 		fprintf(stdout, CONFMT, p->n_lval >> 32);
914 		break;
915 	default:
916 		comperr("upput bad op %d size %d", p->n_op, size);
917 	}
918 }
919 
920 void
921 adrput(FILE * io, NODE * p)
922 {
923 	int r;
924 	/* output an address, with offsets, from p */
925 
926 	if (p->n_op == FLD)
927 		p = p->n_left;
928 
929 	switch (p->n_op) {
930 
931 	case NAME:
932 		if (p->n_name[0] != '\0')
933 			fputs(p->n_name, io);
934 		if (p->n_lval != 0)
935 			fprintf(io, "+" CONFMT, p->n_lval);
936 		return;
937 
938 	case OREG:
939 		r = p->n_rval;
940 
941 		if (p->n_lval)
942 			fprintf(io, "%d", (int) p->n_lval);
943 
944 		fprintf(io, "(%s)", rnames[p->n_rval]);
945 		return;
946 	case ICON:
947 		/* addressable value of the constant */
948 		conput(io, p);
949 		return;
950 
951 	case REG:
952 		if (GCLASS(p->n_rval) == CLASSB || GCLASS(p->n_rval) == CLASSC)
953 			print_reg64name(io, p->n_rval, 0);
954 		else
955 			fputs(rnames[p->n_rval], io);
956 		return;
957 
958 	default:
959 		comperr("illegal address, op %d, node %p", p->n_op, p);
960 		return;
961 
962 	}
963 }
964 
965 /* printf conditional and unconditional branches */
966 void
967 cbgen(int o, int lab)
968 {
969 }
970 
971 void
972 myreader(struct interpass * ipole)
973 {
974 }
975 
976 #if 0
977 /*
978  *  Calculate the stack size for arguments
979  */
980 static int stacksize;
981 
982 static void
983 calcstacksize(NODE *p, void *arg)
984 {
985 	int sz;
986 
987 	printf("op=%d\n", p->n_op);
988 
989 	if (p->n_op != CALL && p->n_op != STCALL)
990 		return;
991 
992 	sz = argsiz(p->n_right);
993 	if (sz > stacksize)
994 		stacksize = sz;
995 
996 #ifdef PCC_DEBUG
997 	if (x2debug)
998 		printf("stacksize: %d\n", stacksize);
999 #endif
1000 }
1001 #endif
1002 
1003 /*
1004  * If we're big endian, then all OREG loads of a type
1005  * larger than the destination, must have the
1006  * offset changed to point to the correct bytes in memory.
1007  */
1008 static void
1009 offchg(NODE *p, void *arg)
1010 {
1011 	NODE *l;
1012 
1013 	if (p->n_op != SCONV)
1014 		return;
1015 
1016 	l = p->n_left;
1017 
1018 	if (l->n_op != OREG)
1019 		return;
1020 
1021 	switch (l->n_type) {
1022 	case SHORT:
1023 	case USHORT:
1024 		if (DEUNSIGN(p->n_type) == CHAR)
1025 			l->n_lval += 1;
1026 		break;
1027 	case LONG:
1028 	case ULONG:
1029 	case INT:
1030 	case UNSIGNED:
1031 		if (DEUNSIGN(p->n_type) == CHAR)
1032 			l->n_lval += 3;
1033 		else if (DEUNSIGN(p->n_type) == SHORT)
1034 			l->n_lval += 2;
1035 		break;
1036 	case LONGLONG:
1037 	case ULONGLONG:
1038 		if (DEUNSIGN(p->n_type) == CHAR)
1039 			l->n_lval += 7;
1040 		else if (DEUNSIGN(p->n_type) == SHORT)
1041 			l->n_lval += 6;
1042 		else if (DEUNSIGN(p->n_type) == INT ||
1043 		    DEUNSIGN(p->n_type) == LONG)
1044 			l->n_lval += 4;
1045 		break;
1046 	default:
1047 		comperr("offchg: unknown type");
1048 		break;
1049 	}
1050 }
1051 
1052 /*
1053  * Remove some PCONVs after OREGs are created.
1054  */
1055 static void
1056 pconv2(NODE * p, void *arg)
1057 {
1058 	NODE *q;
1059 
1060 	if (p->n_op == PLUS) {
1061 		if (p->n_type == (PTR | SHORT) || p->n_type == (PTR | USHORT)) {
1062 			if (p->n_right->n_op != ICON)
1063 				return;
1064 			if (p->n_left->n_op != PCONV)
1065 				return;
1066 			if (p->n_left->n_left->n_op != OREG)
1067 				return;
1068 			q = p->n_left->n_left;
1069 			nfree(p->n_left);
1070 			p->n_left = q;
1071 			/*
1072 		         * This will be converted to another OREG later.
1073 		         */
1074 		}
1075 	}
1076 }
1077 
1078 void
1079 mycanon(NODE * p)
1080 {
1081 	walkf(p, pconv2, 0);
1082 }
1083 
1084 void
1085 myoptim(struct interpass * ipole)
1086 {
1087 	struct interpass *ip;
1088 
1089 #ifdef PCC_DEBUG
1090 	if (x2debug)
1091 		printf("myoptim:\n");
1092 #endif
1093 
1094 #if 0
1095 	stacksize = 0;
1096 #endif
1097 
1098 	DLIST_FOREACH(ip, ipole, qelem) {
1099 		if (ip->type != IP_NODE)
1100 			continue;
1101 		if (bigendian)
1102 			walkf(ip->ip_node, offchg, 0);
1103 #if 0
1104 		walkf(ip->ip_node, calcstacksize, 0);
1105 #endif
1106 	}
1107 }
1108 
1109 /*
1110  * Move data between registers.  While basic registers aren't a problem,
1111  * we have to handle the special case of overlapping composite registers.
1112  */
1113 void
1114 rmove(int s, int d, TWORD t)
1115 {
1116         switch (t) {
1117         case LONGLONG:
1118         case ULONGLONG:
1119                 if (s == d+1) {
1120                         /* dh = sl, copy low word first */
1121                         printf("\tmove ");
1122 			print_reg64name(stdout, d, 0);
1123 			printf(",");
1124 			print_reg64name(stdout, s, 0);
1125 			printf("\t# 64-bit rmove\n");
1126                         printf("\tmove ");
1127 			print_reg64name(stdout, d, 1);
1128 			printf(",");
1129 			print_reg64name(stdout, s, 1);
1130 			printf("\n");
1131                 } else {
1132                         /* copy high word first */
1133                         printf("\tmove ");
1134 			print_reg64name(stdout, d, 1);
1135 			printf(",");
1136 			print_reg64name(stdout, s, 1);
1137 			printf(" # 64-bit rmove\n");
1138                         printf("\tmove ");
1139 			print_reg64name(stdout, d, 0);
1140 			printf(",");
1141 			print_reg64name(stdout, s, 0);
1142 			printf("\n");
1143                 }
1144                 break;
1145 	case FLOAT:
1146 	case DOUBLE:
1147         case LDOUBLE:
1148 		if (t == FLOAT)
1149 			printf("\tmov.s ");
1150 		else
1151 			printf("\tmov.d ");
1152 		print_reg64name(stdout, d, 0);
1153 		printf(",");
1154 		print_reg64name(stdout, s, 0);
1155 		printf("\t# float/double rmove\n");
1156                 break;
1157         default:
1158                 printf("\tmove %s,%s\t# default rmove\n", rnames[d], rnames[s]);
1159         }
1160 }
1161 
1162 
1163 /*
1164  * For class c, find worst-case displacement of the number of
1165  * registers in the array r[] indexed by class.
1166  *
1167  * On MIPS, we have:
1168  *
1169  * 32 32-bit registers (8 reserved)
1170  * 26 64-bit pseudo registers (1 unavailable)
1171  * 16 floating-point register pairs
1172  */
1173 int
1174 COLORMAP(int c, int *r)
1175 {
1176 	int num = 0;
1177 
1178         switch (c) {
1179         case CLASSA:
1180                 num += r[CLASSA];
1181                 num += 2*r[CLASSB];
1182                 return num < 24;
1183         case CLASSB:
1184                 num += 2*r[CLASSB];
1185                 num += r[CLASSA];
1186                 return num < 25;
1187 	case CLASSC:
1188 		num += r[CLASSC];
1189 		return num < 6;
1190         }
1191 	comperr("COLORMAP");
1192         return 0; /* XXX gcc */
1193 }
1194 
1195 /*
1196  * Return a class suitable for a specific type.
1197  */
1198 int
1199 gclass(TWORD t)
1200 {
1201 	if (t == LONGLONG || t == ULONGLONG)
1202 		return CLASSB;
1203 	if (t >= FLOAT && t <= LDOUBLE)
1204 		return CLASSC;
1205 	return CLASSA;
1206 }
1207 
1208 /*
1209  * Calculate argument sizes.
1210  */
1211 void
1212 lastcall(NODE *p)
1213 {
1214 	int sz;
1215 
1216 #ifdef PCC_DEBUG
1217 	if (x2debug)
1218 		printf("lastcall:\n");
1219 #endif
1220 
1221 	p->n_qual = 0;
1222 	if (p->n_op != CALL && p->n_op != FORTCALL && p->n_op != STCALL)
1223 		return;
1224 
1225 	sz = argsiz(p->n_right);
1226 
1227 	if ((sz > 4*nargregs) && (sz & 7) != 0) {
1228 		printf("\tsubu %s,%s,4\t# align stack\n",
1229 		    rnames[SP], rnames[SP]);
1230 		sz += 4;
1231 		assert((sz & 7) == 0);
1232 	}
1233 
1234 	p->n_qual = sz; /* XXX */
1235 }
1236 
1237 static int
1238 argsiz(NODE *p)
1239 {
1240 	TWORD t;
1241 	int size = 0;
1242 	int sz = 0;
1243 
1244 	if (p->n_op == CM) {
1245 		size = argsiz(p->n_left);
1246 		p = p->n_right;
1247 	}
1248 
1249 	t = p->n_type;
1250 	if (t < LONGLONG || t > BTMASK)
1251 		sz = 4;
1252 	else if (DEUNSIGN(t) == LONGLONG)
1253 		sz = 8;
1254 	else if (t == DOUBLE || t == LDOUBLE)
1255 		sz = 8;
1256 	else if (t == FLOAT)
1257 		sz = 4;
1258 	else if (t == STRTY || t == UNIONTY)
1259 		sz = p->n_stsize;
1260 
1261 	if (p->n_type == STRTY || p->n_type == UNIONTY) {
1262 		return (size + sz);
1263 	}
1264 
1265 	/* alignment */
1266 	if (sz == 8 && (size & 7) != 0)
1267 		sz += 4;
1268 
1269 //	printf("size=%d, sz=%d -> %d\n", size, sz, size + sz);
1270 	return (size + sz);
1271 }
1272 
1273 /*
1274  * Special shapes.
1275  */
1276 int
1277 special(NODE *p, int shape)
1278 {
1279 	int o = p->n_op;
1280 	switch(shape) {
1281 	case SPCON:
1282 		if (o == ICON && p->n_name[0] == 0 &&
1283 		    (p->n_lval & ~0xffff) == 0)
1284 			return SRDIR;
1285 		break;
1286 	}
1287 
1288 	return SRNOPE;
1289 }
1290 
1291 /*
1292  * Target-dependent command-line options.
1293  */
1294 void
1295 mflags(char *str)
1296 {
1297 	if (strcasecmp(str, "big-endian") == 0) {
1298 		bigendian = 1;
1299 	} else if (strcasecmp(str, "little-endian") == 0) {
1300 		bigendian = 0;
1301 	} else {
1302 		fprintf(stderr, "unknown m option '%s'\n", str);
1303 		exit(1);
1304 	}
1305 
1306 #if 0
1307 	 else if (strcasecmp(str, "ips2")) {
1308 	} else if (strcasecmp(str, "ips2")) {
1309 	} else if (strcasecmp(str, "ips3")) {
1310 	} else if (strcasecmp(str, "ips4")) {
1311 	} else if (strcasecmp(str, "hard-float")) {
1312 	} else if (strcasecmp(str, "soft-float")) {
1313 	} else if (strcasecmp(str, "abi=32")) {
1314 		nargregs = MIPS_O32_NARGREGS;
1315 	} else if (strcasecmp(str, "abi=n32")) {
1316 		nargregs = MIPS_N32_NARGREGS;
1317 	} else if (strcasecmp(str, "abi=64")) {
1318 		nargregs = MIPS_N32_NARGREGS;
1319 	}
1320 #endif
1321 }
1322 /*
1323  * Do something target-dependent for xasm arguments.
1324  * Supposed to find target-specific constraints and rewrite them.
1325  */
1326 int
1327 myxasm(struct interpass *ip, NODE *p)
1328 {
1329 	return 0;
1330 }
1331