xref: /inferno-os/utils/tl/noop.c (revision e45fa0eb0763b57d6fb0649c064bc3b95ccdea6c)
1 #include	"l.h"
2 
3 static	Sym*	sym_div;
4 static	Sym*	sym_divu;
5 static	Sym*	sym_mod;
6 static	Sym*	sym_modu;
7 
8 static void setdiv(int);
9 
10 static Prog *
11 movrr(Prog *q, int rs, int rd, Prog *p)
12 {
13 	if(q == nil)
14 		q = prg();
15 	q->as = AMOVW;
16 	q->line = p->line;
17 	q->from.type = D_REG;
18 	q->from.reg = rs;
19 	q->to.type = D_REG;
20 	q->to.reg = rd;
21 	q->link = p->link;
22 	return q;
23 }
24 
25 static Prog *
26 fnret(Prog *q, int rs, int foreign, Prog *p)
27 {
28 	q = movrr(q, rs, REGPC, p);
29 	if(foreign){	// BX rs
30 		q->as = ABXRET;
31 		q->from.type = D_NONE;
32 		q->from.reg = NREG;
33 		q->to.reg = rs;
34 	}
35 	return q;
36 }
37 
38 static Prog *
39 aword(long w, Prog *p)
40 {
41 	Prog *q;
42 
43 	q = prg();
44 	q->as = AWORD;
45 	q->line = p->line;
46 	q->from.type = D_NONE;
47 	q->reg = NREG;
48 	q->to.type = D_CONST;
49 	q->to.offset = w;
50 	q->link = p->link;
51 	p->link = q;
52 	return q;
53 }
54 
55 static Prog *
56 adword(long w1, long w2, Prog *p)
57 {
58 	Prog *q;
59 
60 	q = prg();
61 	q->as = ADWORD;
62 	q->line = p->line;
63 	q->from.type = D_CONST;
64 	q->from.offset = w1;
65 	q->reg = NREG;
66 	q->to.type = D_CONST;
67 	q->to.offset = w2;
68 	q->link = p->link;
69 	p->link = q;
70 	return q;
71 }
72 
73 void
74 noops(void)
75 {
76 	Prog *p, *q, *q1, *q2;
77 	int o, curframe, curbecome, maxbecome, foreign;
78 
79 	/*
80 	 * find leaf subroutines
81 	 * become sizes
82 	 * frame sizes
83 	 * strip NOPs
84 	 * expand RET
85 	 * expand BECOME pseudo
86 	 */
87 
88 	if(debug['v'])
89 		Bprint(&bso, "%5.2f noops\n", cputime());
90 	Bflush(&bso);
91 
92 	curframe = 0;
93 	curbecome = 0;
94 	maxbecome = 0;
95 	curtext = 0;
96 
97 	q = P;
98 	for(p = firstp; p != P; p = p->link) {
99 		setarch(p);
100 
101 		/* find out how much arg space is used in this TEXT */
102 		if(p->to.type == D_OREG && p->to.reg == REGSP)
103 			if(p->to.offset > curframe)
104 				curframe = p->to.offset;
105 
106 		switch(p->as) {
107 		case ATEXT:
108 			if(curtext && curtext->from.sym) {
109 				curtext->from.sym->frame = curframe;
110 				curtext->from.sym->become = curbecome;
111 				if(curbecome > maxbecome)
112 					maxbecome = curbecome;
113 			}
114 			curframe = 0;
115 			curbecome = 0;
116 
117 			p->mark |= LEAF;
118 			curtext = p;
119 			break;
120 
121 		case ARET:
122 			/* special form of RET is BECOME */
123 			if(p->from.type == D_CONST)
124 				if(p->from.offset > curbecome)
125 					curbecome = p->from.offset;
126 			break;
127 
128 		case ADIV:
129 		case ADIVU:
130 		case AMOD:
131 		case AMODU:
132 			q = p;
133 			if(prog_div == P)
134 				initdiv();
135 			if(curtext != P)
136 				curtext->mark &= ~LEAF;
137 			setdiv(p->as);
138 			continue;
139 
140 		case ANOP:
141 			q1 = p->link;
142 			q->link = q1;		/* q is non-nop */
143 			q1->mark |= p->mark;
144 			continue;
145 
146 		case ABL:
147 		case ABX:
148 			if(curtext != P)
149 				curtext->mark &= ~LEAF;
150 
151 		case ABCASE:
152 		case AB:
153 
154 		case ABEQ:
155 		case ABNE:
156 		case ABCS:
157 		case ABHS:
158 		case ABCC:
159 		case ABLO:
160 		case ABMI:
161 		case ABPL:
162 		case ABVS:
163 		case ABVC:
164 		case ABHI:
165 		case ABLS:
166 		case ABGE:
167 		case ABLT:
168 		case ABGT:
169 		case ABLE:
170 
171 			q1 = p->cond;
172 			if(q1 != P) {
173 				while(q1->as == ANOP) {
174 					q1 = q1->link;
175 					p->cond = q1;
176 				}
177 			}
178 			break;
179 		}
180 		q = p;
181 	}
182 
183 	if(curtext && curtext->from.sym) {
184 		curtext->from.sym->frame = curframe;
185 		curtext->from.sym->become = curbecome;
186 		if(curbecome > maxbecome)
187 			maxbecome = curbecome;
188 	}
189 
190 	if(debug['b'])
191 		print("max become = %d\n", maxbecome);
192 	xdefine("ALEFbecome", STEXT, maxbecome);
193 
194 	curtext = 0;
195 	for(p = firstp; p != P; p = p->link) {
196 		setarch(p);
197 		switch(p->as) {
198 		case ATEXT:
199 			curtext = p;
200 			break;
201 		case ABL:
202 		// case ABX:
203 			if(curtext != P && curtext->from.sym != S && curtext->to.offset >= 0) {
204 				o = maxbecome - curtext->from.sym->frame;
205 				if(o <= 0)
206 					break;
207 				/* calling a become or calling a variable */
208 				if(p->to.sym == S || p->to.sym->become) {
209 					curtext->to.offset += o;
210 					if(debug['b']) {
211 						curp = p;
212 						print("%D calling %D increase %d\n",
213 							&curtext->from, &p->to, o);
214 					}
215 				}
216 			}
217 			break;
218 		}
219 	}
220 
221 	for(p = firstp; p != P; p = p->link) {
222 		setarch(p);
223 		o = p->as;
224 		switch(o) {
225 		case ATEXT:
226 			curtext = p;
227 			autosize = p->to.offset + 4;
228 			if(autosize <= 4)
229 			if(curtext->mark & LEAF) {
230 				p->to.offset = -4;
231 				autosize = 0;
232 			}
233 
234 			if(!autosize && !(curtext->mark & LEAF)) {
235 				if(debug['v'])
236 					Bprint(&bso, "save suppressed in: %s\n",
237 						curtext->from.sym->name);
238 				Bflush(&bso);
239 				curtext->mark |= LEAF;
240 			}
241 #ifdef CALLEEBX
242 			if(p->from.sym->foreign){
243 				if(thumb)
244 					// don't allow literal pool to seperate these
245 					p = adword(0xe28f7001, 0xe12fff17, p); // arm add 1, pc, r7 and bx r7
246 					// p = aword(0xe12fff17, aword(0xe28f7001, p)); // arm add 1, pc, r7 and bx r7
247 				else
248 					p = aword(0x4778, p);	// thumb bx pc and 2 bytes padding
249 			}
250 #endif
251 			if(curtext->mark & LEAF) {
252 				if(curtext->from.sym)
253 					curtext->from.sym->type = SLEAF;
254 #ifdef optimise_time
255 				if(autosize) {
256 					q = prg();
257 					q->as = ASUB;
258 					q->line = p->line;
259 					q->from.type = D_CONST;
260 					q->from.offset = autosize;
261 					q->to.type = D_REG;
262 					q->to.reg = REGSP;
263 
264 					q->link = p->link;
265 					p->link = q;
266 				}
267 				break;
268 #else
269 				if(!autosize)
270 					break;
271 #endif
272 			}
273 
274 			if(thumb){
275 				if(!(curtext->mark & LEAF)){
276 					q = movrr(nil, REGLINK, REGTMPT-1, p);
277 					p->link = q;
278 					q1 = prg();
279 					q1->as = AMOVW;
280 					q1->line = p->line;
281 					q1->from.type = D_REG;
282 					q1->from.reg = REGTMPT-1;
283 					q1->to.type = D_OREG;
284 					q1->to.name = D_NONE;
285 					q1->to.reg = REGSP;
286 					q1->to.offset = 0;
287 					q1->link = q->link;
288 					q->link = q1;
289 				}
290 				if(autosize){
291 					q2 = prg();
292 					q2->as = ASUB;
293 					q2->line = p->line;
294 					q2->from.type = D_CONST;
295 					q2->from.offset = autosize;
296 					q2->to.type = D_REG;
297 					q2->to.reg = REGSP;
298 					q2->link = p->link;
299 					p->link = q2;
300 				}
301 				break;
302 			}
303 
304 			q1 = prg();
305 			q1->as = AMOVW;
306 			q1->scond |= C_WBIT;
307 			q1->line = p->line;
308 			q1->from.type = D_REG;
309 			q1->from.reg = REGLINK;
310 			q1->to.type = D_OREG;
311 			q1->to.offset = -autosize;
312 			q1->to.reg = REGSP;
313 			q1->link = p->link;
314 			p->link = q1;
315 			break;
316 
317 		case ARET:
318 			nocache(p);
319 			foreign = seenthumb && curtext->from.sym != S && (curtext->from.sym->foreign || curtext->from.sym->fnptr);
320 // print("%s %d %d\n", curtext->from.sym->name, curtext->from.sym->foreign, curtext->from.sym->fnptr);
321 			if(p->from.type == D_CONST)
322 				goto become;
323 			if(curtext->mark & LEAF) {
324 				if(!autosize) {
325 					if(thumb){
326 						p = fnret(p, REGLINK, foreign, p);
327 						break;
328 					}
329 // if(foreign) print("ABXRET 1 %s\n", curtext->from.sym->name);
330 					p->as = foreign ? ABXRET : AB;
331 					p->from = zprg.from;
332 					p->to.type = D_OREG;
333 					p->to.offset = 0;
334 					p->to.reg = REGLINK;
335 					break;
336 				}
337 
338 #ifdef optimise_time
339 				p->as = AADD;
340 				p->from.type = D_CONST;
341 				p->from.offset = autosize;
342 				p->to.type = D_REG;
343 				p->to.reg = REGSP;
344 				if(thumb){
345 					p->link = fnret(nil, REGLINK, foreign, p);
346 					break;
347 				}
348 				q = prg();
349 // if(foreign) print("ABXRET 2 %s\n", curtext->from.sym->name);
350 				q->as = foreign ? ABXRET : AB;
351 				q->scond = p->scond;
352 				q->line = p->line;
353 				q->to.type = D_OREG;
354 				q->to.offset = 0;
355 				q->to.reg = REGLINK;
356 
357 				q->link = p->link;
358 				p->link = q;
359 
360 				break;
361 #endif
362 			}
363 			if(thumb){
364 				if(curtext->mark & LEAF){
365 					if(autosize){
366 						p->as = AADD;
367 						p->from.type = D_CONST;
368 						p->from.offset = autosize;
369 						p->to.type = D_REG;
370 						p->to.reg = REGSP;
371 						q = nil;
372 					}
373 					else
374 						q = p;
375 					q = fnret(q, REGLINK, foreign, p);
376 					if(q != p)
377 						p->link = q;
378 				}
379 				else{
380 					p->as = AMOVW;
381 					p->from.type = D_OREG;
382 					p->from.name = D_NONE;
383 					p->from.reg = REGSP;
384 					p->from.offset = 0;
385 					p->to.type = D_REG;
386 					p->to.reg = REGTMPT-1;
387 					if(autosize){
388 						q = prg();
389 						q->as = AADD;
390 						q->from.type = D_CONST;
391 						q->from.offset = autosize;
392 						q->to.type = D_REG;
393 						q->to.reg = REGSP;
394 						q->link = p->link;
395 						p->link = 	q;
396 					}
397 					else
398 						q = p;
399 					q1 = fnret(nil, REGTMPT-1, foreign, p);
400 					q1->link = q->link;
401 					q->link = q1;
402 				}
403 				break;
404 			}
405 			if(foreign) {
406 // if(foreign) print("ABXRET 3 %s\n", curtext->from.sym->name);
407 #define	R	1
408 				p->as = AMOVW;
409 				p->from.type = D_OREG;
410 				p->from.name = D_NONE;
411 				p->from.reg = REGSP;
412 				p->from.offset = 0;
413 				p->to.type = D_REG;
414 				p->to.reg = R;
415 				q = prg();
416 				q->as = AADD;
417 				q->scond = p->scond;
418 				q->line = p->line;
419 				q->from.type = D_CONST;
420 				q->from.offset = autosize;
421 				q->to.type = D_REG;
422 				q->to.reg = REGSP;
423 				q->link = p->link;
424 				p->link = q;
425 				q1 = prg();
426 				q1->as = ABXRET;
427 				q1->scond = p->scond;
428 				q1->line = p->line;
429 				q1->to.type = D_OREG;
430 				q1->to.offset = 0;
431 				q1->to.reg = R;
432 				q1->link = q->link;
433 				q->link = q1;
434 #undef	R
435 			}
436 			else {
437 				p->as = AMOVW;
438 				p->scond |= C_PBIT;
439 				p->from.type = D_OREG;
440 				p->from.offset = autosize;
441 				p->from.reg = REGSP;
442 				p->to.type = D_REG;
443 				p->to.reg = REGPC;
444 			}
445 			break;
446 
447 		become:
448 			if(foreign){
449 				diag("foreign become - help");
450 				break;
451 			}
452 			if(thumb){
453 				diag("thumb become - help");
454 				break;
455 			}
456 			print("arm become\n");
457 			if(curtext->mark & LEAF) {
458 
459 				if(!autosize) {
460 					p->as = AB;
461 					p->from = zprg.from;
462 					break;
463 				}
464 
465 #ifdef optimise_time
466 				q = prg();
467 				q->scond = p->scond;
468 				q->line = p->line;
469 				q->as = AB;
470 				q->from = zprg.from;
471 				q->to = p->to;
472 				q->cond = p->cond;
473 				q->link = p->link;
474 				p->link = q;
475 
476 				p->as = AADD;
477 				p->from = zprg.from;
478 				p->from.type = D_CONST;
479 				p->from.offset = autosize;
480 				p->to = zprg.to;
481 				p->to.type = D_REG;
482 				p->to.reg = REGSP;
483 
484 				break;
485 #endif
486 			}
487 			q = prg();
488 			q->scond = p->scond;
489 			q->line = p->line;
490 			q->as = AB;
491 			q->from = zprg.from;
492 			q->to = p->to;
493 			q->cond = p->cond;
494 			q->link = p->link;
495 			p->link = q;
496 			if(thumb){
497 				q1 = prg();
498 				q1->line = p->line;
499 				q1->as = AADD;
500 				q1->from.type = D_CONST;
501 				q1->from.offset = autosize;
502 				q1->to.type = D_REG;
503 				q1->to.reg = REGSP;
504 				p->as = AMOVW;
505 				p->line = p->line;
506 				p->from.type = D_OREG;
507 				p->from.name = D_NONE;
508 				p->from.reg = REGSP;
509 				p->from.offset = 0;
510 				p->to.type = D_REG;
511 				p->to.reg = REGTMPT-1;
512 				q1->link = q;
513 				p->link = q1;
514 				q2 = movrr(nil, REGTMPT-1, REGLINK, p);
515 				q2->link = q;
516 				q1->link = q2;
517 				break;
518 			}
519 			p->as = AMOVW;
520 			p->scond |= C_PBIT;
521 			p->from = zprg.from;
522 			p->from.type = D_OREG;
523 			p->from.offset = autosize;
524 			p->from.reg = REGSP;
525 			p->to = zprg.to;
526 			p->to.type = D_REG;
527 			p->to.reg = REGLINK;
528 
529 			break;
530 
531 		case ADIV:
532 		case ADIVU:
533 		case AMOD:
534 		case AMODU:
535 			if(debug['M'])
536 				break;
537 			if(p->from.type != D_REG)
538 				break;
539 			if(p->to.type != D_REG)
540 				break;
541 			q1 = p;
542 
543 			/* MOV a,4(SP) */
544 			q = prg();
545 			q->link = p->link;
546 			p->link = q;
547 			p = q;
548 
549 			p->as = AMOVW;
550 			p->line = q1->line;
551 			p->from.type = D_REG;
552 			p->from.reg = q1->from.reg;
553 			p->to.type = D_OREG;
554 			p->to.reg = REGSP;
555 			p->to.offset = 4;
556 
557 			/* MOV b,REGTMP */
558 			q = prg();
559 			q->link = p->link;
560 			p->link = q;
561 			p = q;
562 
563 			p->as = AMOVW;
564 			p->line = q1->line;
565 			p->from.type = D_REG;
566 			p->from.reg = q1->reg;
567 			if(q1->reg == NREG)
568 				p->from.reg = q1->to.reg;
569 			p->to.type = D_REG;
570 			p->to.reg = prog_div != UP && prog_div->from.sym->thumb ? REGTMPT : REGTMP;
571 			p->to.offset = 0;
572 
573 			/* CALL appropriate */
574 			q = prg();
575 			q->link = p->link;
576 			p->link = q;
577 			p = q;
578 
579 #ifdef CALLEEBX
580 			p->as = ABL;
581 #else
582 			if(prog_div != UP && prog_div->from.sym->thumb)
583 				p->as = thumb ? ABL : ABX;
584 			else
585 				p->as = thumb ? ABX : ABL;
586 #endif
587 			p->line = q1->line;
588 			p->to.type = D_BRANCH;
589 			p->cond = p;
590 			switch(o) {
591 			case ADIV:
592 				p->cond = prog_div;
593 				p->to.sym = sym_div;
594 				break;
595 			case ADIVU:
596 				p->cond = prog_divu;
597 				p->to.sym = sym_divu;
598 				break;
599 			case AMOD:
600 				p->cond = prog_mod;
601 				p->to.sym = sym_mod;
602 				break;
603 			case AMODU:
604 				p->cond = prog_modu;
605 				p->to.sym = sym_modu;
606 				break;
607 			}
608 
609 			/* MOV REGTMP, b */
610 			q = prg();
611 			q->link = p->link;
612 			p->link = q;
613 			p = q;
614 
615 			p->as = AMOVW;
616 			p->line = q1->line;
617 			p->from.type = D_REG;
618 			p->from.reg = prog_div != UP && prog_div->from.sym->thumb ? REGTMPT : REGTMP;
619 			p->from.offset = 0;
620 			p->to.type = D_REG;
621 			p->to.reg = q1->to.reg;
622 
623 			/* ADD $8,SP */
624 			q = prg();
625 			q->link = p->link;
626 			p->link = q;
627 			p = q;
628 
629 			p->as = AADD;
630 			p->from.type = D_CONST;
631 			p->from.reg = NREG;
632 			p->from.offset = 8;
633 			p->reg = NREG;
634 			p->to.type = D_REG;
635 			p->to.reg = REGSP;
636 
637 			/* SUB $8,SP */
638 			q1->as = ASUB;
639 			q1->from.type = D_CONST;
640 			q1->from.offset = 8;
641 			q1->from.reg = NREG;
642 			q1->reg = NREG;
643 			q1->to.type = D_REG;
644 			q1->to.reg = REGSP;
645 
646 			break;
647 		case AMOVW:
648 			if(thumb){
649 				Adr *a = &p->from;
650 
651 				if(a->type == D_CONST && ((a->name == D_NONE && a->reg == REGSP) || a->name == D_AUTO || a->name == D_PARAM) && (a->offset & 3))
652 					diag("SP offset not multiple of 4");
653 			}
654 			break;
655 		case AMOVB:
656 		case AMOVBU:
657 		case AMOVH:
658 		case AMOVHU:
659 			if(thumb){
660 				if(p->from.type == D_OREG && (p->from.name == D_AUTO || p->from.name == D_PARAM || (p->from.name == D_CONST && p->from.reg == REGSP))){
661 					q = prg();
662 					*q = *p;
663 					if(p->from.name == D_AUTO)
664 						q->from.offset += autosize;
665 					else if(p->from.name == D_PARAM)
666 						q->from.offset += autosize+4;
667 					q->from.name = D_NONE;
668 					q->from.reg = REGTMPT;
669 					p = movrr(p, REGSP, REGTMPT, p);
670 					q->link = p->link;
671 					p->link = q;
672 				}
673 				if(p->to.type == D_OREG && (p->to.name == D_AUTO || p->to.name == D_PARAM || (p->to.name == D_CONST && p->to.reg == REGSP))){
674 					q = prg();
675 					*q = *p;
676 					if(p->to.name == D_AUTO)
677 						q->to.offset += autosize;
678 					else if(p->to.name == D_PARAM)
679 						q->to.offset += autosize+4;
680 					q->to.name = D_NONE;
681 					q->to.reg = REGTMPT;
682 					p = movrr(p, REGSP, REGTMPT, p);
683 					q->link = p->link;
684 					p->link = q;
685 					if(q->to.offset < 0 || q->to.offset > 255){	// complicated
686 						p->to.reg = REGTMPT+1;			// mov sp, r8
687 						q1 = prg();
688 						q1->line = p->line;
689 						q1->as = AMOVW;
690 						q1->from.type = D_CONST;
691 						q1->from.offset = q->to.offset;
692 						q1->to.type = D_REG;
693 						q1->to.reg = REGTMPT;			// mov $o, r7
694 						p->link = q1;
695 						q1->link = q;
696 						q1 = prg();
697 						q1->line = p->line;
698 						q1->as = AADD;
699 						q1->from.type = D_REG;
700 						q1->from.reg = REGTMPT+1;
701 						q1->to.type = D_REG;
702 						q1->to.reg = REGTMPT;			// add r8, r7
703 						p->link->link = q1;
704 						q1->link = q;
705 						q->to.offset = 0;				// mov* r, 0(r7)
706 						/* phew */
707 					}
708 				}
709 			}
710 			break;
711 		case AMOVM:
712 			if(thumb){
713 				if(p->from.type == D_OREG){
714 					if(p->from.offset == 0)
715 						p->from.type = D_REG;
716 					else
717 						diag("non-zero AMOVM offset");
718 				}
719 				else if(p->to.type == D_OREG){
720 					if(p->to.offset == 0)
721 						p->to.type = D_REG;
722 					else
723 						diag("non-zero AMOVM offset");
724 				}
725 			}
726 			break;
727 		case AB:
728 			if(thumb && p->to.type == D_OREG){
729 				if(p->to.offset == 0){
730 					p->as = AMOVW;
731 					p->from.type = D_REG;
732 					p->from.reg = p->to.reg;
733 					p->to.type = D_REG;
734 					p->to.reg = REGPC;
735 				}
736 				else{
737 					p->as = AADD;
738 					p->from.type = D_CONST;
739 					p->from.offset = p->to.offset;
740 					p->reg = p->to.reg;
741 					p->to.type = D_REG;
742 					p->to.reg = REGTMPT-1;
743 					q = prg();
744 					q->as = AMOVW;
745 					q->line = p->line;
746 					q->from.type = D_REG;
747 					q->from.reg = REGTMPT-1;
748 					q->to.type = D_REG;
749 					q->to.reg = REGPC;
750 					q->link = p->link;
751 					p->link = q;
752 				}
753 			}
754 			if(seenthumb && !thumb && p->to.type == D_OREG && p->to.reg == REGLINK){
755 				// print("warn %s:	b	(R%d)	assuming a return\n", curtext->from.sym->name, p->to.reg);
756 				p->as = ABXRET;
757 			}
758 			break;
759 		case ABL:
760 		case ABX:
761 			if(thumb && p->to.type == D_OREG){
762 				if(p->to.offset == 0){
763 					p->as = o;
764 					p->from.type = D_NONE;
765 					p->to.type = D_REG;
766 				}
767 				else{
768 					p->as = AADD;
769 					p->from.type = D_CONST;
770 					p->from.offset = p->to.offset;
771 					p->reg = p->to.reg;
772 					p->to.type = D_REG;
773 					p->to.reg = REGTMPT-1;
774 					q = prg();
775 					q->as = o;
776 					q->line = p->line;
777 					q->from.type = D_NONE;
778 					q->to.type = D_REG;
779 					q->to.reg = REGTMPT-1;
780 					q->link = p->link;
781 					p->link = q;
782 				}
783 			}
784 			break;
785 		}
786 	}
787 }
788 
789 static void
790 sigdiv(char *n)
791 {
792 	Sym *s;
793 
794 	s = lookup(n, 0);
795 	if(s->type == STEXT){
796 		if(s->sig == 0)
797 			s->sig = SIGNINTERN;
798 	}
799 	else if(s->type == 0 || s->type == SXREF)
800 		s->type = SUNDEF;
801 }
802 
803 void
804 divsig(void)
805 {
806 	sigdiv("_div");
807 	sigdiv("_divu");
808 	sigdiv("_mod");
809 	sigdiv("_modu");
810 }
811 
812 static void
813 sdiv(Sym *s)
814 {
815 	if(s->type == 0 || s->type == SXREF){
816 		/* undefsym(s); */
817 		s->type = SXREF;
818 		if(s->sig == 0)
819 			s->sig = SIGNINTERN;
820 		s->subtype = SIMPORT;
821 	}
822 	else if(s->type != STEXT)
823 		diag("undefined: %s", s->name);
824 }
825 
826 void
827 initdiv(void)
828 {
829 	Sym *s2, *s3, *s4, *s5;
830 	Prog *p;
831 
832 	if(prog_div != P)
833 		return;
834 	sym_div = s2 = lookup("_div", 0);
835 	sym_divu = s3 = lookup("_divu", 0);
836 	sym_mod = s4 = lookup("_mod", 0);
837 	sym_modu = s5 = lookup("_modu", 0);
838 	if(dlm) {
839 		sdiv(s2); if(s2->type == SXREF) prog_div = UP;
840 		sdiv(s3); if(s3->type == SXREF) prog_divu = UP;
841 		sdiv(s4); if(s4->type == SXREF) prog_mod = UP;
842 		sdiv(s5); if(s5->type == SXREF) prog_modu = UP;
843 	}
844 	for(p = firstp; p != P; p = p->link)
845 		if(p->as == ATEXT) {
846 			if(p->from.sym == s2)
847 				prog_div = p;
848 			if(p->from.sym == s3)
849 				prog_divu = p;
850 			if(p->from.sym == s4)
851 				prog_mod = p;
852 			if(p->from.sym == s5)
853 				prog_modu = p;
854 		}
855 	if(prog_div == P) {
856 		diag("undefined: %s", s2->name);
857 		prog_div = curtext;
858 	}
859 	if(prog_divu == P) {
860 		diag("undefined: %s", s3->name);
861 		prog_divu = curtext;
862 	}
863 	if(prog_mod == P) {
864 		diag("undefined: %s", s4->name);
865 		prog_mod = curtext;
866 	}
867 	if(prog_modu == P) {
868 		diag("undefined: %s", s5->name);
869 		prog_modu = curtext;
870 	}
871 }
872 
873 static void
874 setdiv(int as)
875 {
876 	Prog *p = nil;
877 
878 	switch(as){
879 	case ADIV: p = prog_div; break;
880 	case ADIVU: p = prog_divu; break;
881 	case AMOD: p = prog_mod; break;
882 	case AMODU: p = prog_modu; break;
883 	}
884 	if(p != UP && thumb != p->from.sym->thumb)
885 		p->from.sym->foreign = 1;
886 }
887 
888 void
889 nocache(Prog *p)
890 {
891 	p->optab = 0;
892 	p->from.class = 0;
893 	p->to.class = 0;
894 }
895