xref: /original-bsd/old/as.vax/asjxxx.c (revision 30ae0772)
1 /*
2  * Copyright (c) 1982 Regents of the University of California.
3  * All rights reserved.  The Berkeley software License Agreement
4  * specifies the terms and conditions for redistribution.
5  */
6 
7 #ifndef lint
8 static char sccsid[] = "@(#)asjxxx.c	5.1 (Berkeley) 04/30/85";
9 #endif not lint
10 
11 #include	<stdio.h>
12 #include	"as.h"
13 #include	"assyms.h"
14 
15 #define	JBR	0x11
16 #define	BRW	0x31
17 #define	JMP	0x17
18 
19 /*
20  *	The number of bytes to add if the jxxx must be "exploded"
21  *	into the long form
22  */
23 #define	JBRDELTA	1	/* brb <byte> ==> brw <byte> <byte> */
24 #define	JXXXDELTA	3	/* brb <byte> ==> brb <byte> brw <byte> <byte> */
25 #define	JBRJDELTA	d124	/* brb <byte> ==> jmp L^(pc) <byte>*d124 */
26 #define	JXXXJDELTA	d124+2	/* brb <byte> ==> brb <byte> jmp L^(pc) <byte>*d124 */
27 
28 int	jbrfsize = JBRDELTA;
29 int	jxxxfsize = JXXXDELTA;
30 
31 /*
32  *	These variables are filled by asscan.c with the
33  *	last name encountered (a pointer buried in the intermediate file),
34  *	and the last jxxx symbol table entry encountered.
35  */
36 struct 	symtab	*lastnam;
37 struct	symtab	*lastjxxx;
38 
39 initijxxx()
40 {
41 	jbrfsize = jxxxJUMP ? JBRJDELTA : JBRDELTA;
42 	jxxxfsize = jxxxJUMP ? JXXXJDELTA : JXXXDELTA;
43 	/*
44 	 *	Note: ifjxxxJUMP is set, then we do NOT do any tunnelling;
45 	 *	this was too complicated to figure out, and in the first
46 	 *	version of the assembler, tunnelling proved to be the hardest
47 	 *	to get to work!
48 	 */
49 }
50 /*
51  *	Handle jxxx instructions
52  */
53 ijxout(opcode, ap, nact)
54 	struct	Opcode	opcode;
55 	struct	arg	*ap;
56 	int	nact;
57 {
58 	if (passno == 1){
59 		/*
60 		 *	READ THIS BEFORE LOOKING AT jxxxfix()
61 		 *
62 		 *	Record the jxxx in a special symbol table entry
63 		 */
64 		register struct symtab *jumpfrom;
65 
66 		/*
67 		 *	We assume the MINIMAL length
68 		 */
69 		putins(opcode, ap, nact);
70 		jumpfrom = lastjxxx;
71 		jumpfrom->s_tag = JXACTIVE;
72 		jumpfrom->s_jxbump = 0;
73 		if (opcode.Op_popcode == JBR)
74 			jumpfrom->s_jxfear = jbrfsize;
75 		else
76 			jumpfrom->s_jxfear = jxxxfsize;
77 		if (lastnam == 0)
78 			yyerror("jxxx destination not a label");
79 		jumpfrom->s_dest = lastnam;
80 		jumpfrom->s_type = dotp->e_xtype;	/*only TEXT or DATA*/
81 		jumpfrom->s_index = dotp-usedot;
82 #ifdef DEBUG
83 		jumpfrom->s_name = ITABFETCH(opcode)->i_name;
84 		jumpfrom->s_jxline = lineno;
85 #endif
86 		/*
87 		 *	value ALWAYS (ALWAYS!!!) indexes the next instruction
88 		 *	after the jump, even if the jump must be exploded
89 		 *	(bumped)
90 		 */
91 		jumpfrom->s_value = dotp->e_xvalue;
92 		njxxx++;
93 	} else {/* pass2, resolve */
94 		/*
95 		 *	READ THIS AFTER LOOKING AT jxxxfix()
96 		 */
97 		reg	long		oxvalue;
98 		reg	struct	exp 	*xp;
99 		reg	struct	symtab	*tunnel;
100 		reg	struct	arg	*aplast;
101 			struct	Opcode	nopcode;
102 
103 		aplast = ap + nact - 1;
104 		xp = aplast->a_xp;
105 		if (lastjxxx->s_tag == JXTUNNEL){
106 			lastjxxx->s_tag = JXINACTIVE;
107 			tunnel = lastjxxx->s_dest;
108 			xp->e_xvalue = tunnel->s_value	/*index of instruction following*/
109 				    - 3			/* size of brw + word*/
110 				    + ( ( (tunnel->s_jxfear == jbrfsize) &&
111 					  (tunnel->s_jxbump == 0))?1:0);
112 							/*non bumped branch byteis only 2 back*/
113 		}
114 		if (lastjxxx->s_jxbump == 0){	/*wasn't bumped, so is short form*/
115 			putins(opcode, ap, nact);
116 		} else {
117 			if (opcode.Op_popcode != JBR){
118 				/*
119 				 *	branch reverse conditional byte over
120 				 *	branch unconditional word
121 				 */
122 				oxvalue = xp->e_xvalue;
123 				xp->e_xvalue = lastjxxx->s_value;
124 				nopcode = opcode;
125 				nopcode.Op_popcode ^= 1;
126 				putins(nopcode, ap, nact);
127 				xp->e_xvalue = oxvalue;
128 			}
129 			nopcode.Op_eopcode = CORE;
130 			nopcode.Op_popcode = jxxxJUMP ? JMP : BRW;
131 			putins(nopcode, aplast, 1);
132 		}
133 	}
134 }
135 
136 jalign(xp, sp)
137 	register struct exp *xp;
138 	register struct symtab *sp;
139 {
140 	register	int	mask;
141 #ifdef DEBUG
142 	static struct strdesc noname;
143 #endif
144 	/*
145 	 *	Problem with .align
146 	 *
147 	 *	When the loader constructs an executable file from
148 	 *	a number of objects, it effectively concatnates
149 	 *	together all of the text segments from all objects,
150 	 *	and then all of the data segments.
151 	 *
152 	 *	If we do an align by a large value, we can align
153 	 *	within the a.out this assembly produces, but
154 	 *	after the loader concatnates, the alignment can't
155 	 *	be guaranteed if the objects preceding this one
156 	 *	in the load are also aligned to the same size.
157 	 *
158 	 *	Currently, the loader guarantees full word alignment.
159 	 *	So, ridiculous aligns are caught here and converted
160 	 *	to a .align (maxalign), if possible, where maxalign
161 	 *	is set in the command line, and defaults to 2.
162 	 */
163 	if (   ( (xp->e_xtype & XTYPE) != XABS)
164 	    || (xp->e_xvalue < 0)
165 	    || (xp->e_xvalue > 16)
166 	    ) {
167 		yyerror("Illegal `align' argument");
168 		return;
169 	}
170 	if (xp->e_xvalue > maxalign){
171 		if (passno == 1){
172 			yywarning(".align %d is NOT preserved by the loader",
173 				xp->e_xvalue);
174 			yywarning(".align %d converted to .align %d",
175 				xp->e_xvalue, maxalign);
176 		}
177 		xp->e_xvalue = maxalign;
178 	}
179 	flushfield(NBPW/4);
180 	if (passno == 1) {
181 		sp->s_tag = JXALIGN;
182 		sp->s_jxfear = (1 << xp->e_xvalue) - 1;
183 		sp->s_type = dotp->e_xtype;
184 		sp->s_index = dotp-usedot;
185 #ifdef DEBUG
186 		sp->s_name = (char *)&noname;
187 		sp->s_jxline = lineno;
188 #endif
189 		/*
190 		 *	We guess that the align will take up at least one
191 		 *	byte in the code output.  We will correct for this
192 		 *	initial high guess when we explode (bump) aligns
193 		 *	when we fix the jxxxes.  We must do this guess
194 		 *	so that the symbol table is sorted correctly
195 		 *	and labels declared to fall before the align
196 		 *	really get their, instead of guessing zero size
197 		 *	and have the label (incorrectly) fall after the jxxx.
198 		 *	This is a quirk of our requirement that indices into
199 		 *	the code stream point to the next byte following
200 		 *	the logical entry in the symbol table
201 		 */
202 		dotp->e_xvalue += 1;
203 		sp->s_value = dotp->e_xvalue;
204 		njxxx++;
205 	} else {
206 		mask = (1 << xp->e_xvalue) - 1;
207 		while (dotp->e_xvalue & mask)
208 			Outb(0);
209 	}
210 }
211 
212 /*
213  *	Pass 1.5, resolve jxxx instructions and .align in .text
214  */
215 jxxxfix()
216 {
217 	register struct symtab 	*jumpfrom;
218 		 struct symtab	**cojumpfrom, *ubjumpfrom;
219 	register struct symtab 	*dest;
220 	register struct symtab	*intdest;	/*intermediate dest*/
221 	register struct symtab	**cointdest, *ubintdest;
222 
223 	register struct symtab 	*tunnel;
224 	 	 int 		displ,nchange;
225 		 int		badjxalign;	/*if jump across an align*/
226 		 int		stillactives;	/*if still active jxxxes*/
227 		 int		segno;		/*current segment number*/
228 		 int		topono;		/*which iteration in the topo sort*/
229 	register unsigned char	tag;
230 	/*
231 	 *	consider each segment in turn...
232 	 */
233 	for (segno = 0; segno < NLOC + NLOC; segno++){
234 	    badjxalign = 0;		/*done on a per segment basis*/
235 	    /*
236 	     *	Do a lazy topological sort.
237 	     */
238 	    for (topono = 1, nchange = 1; nchange != 0; topono++){
239 #ifdef lint
240 		topno = topno;
241 #endif lint
242 #ifdef DEBUG
243 		if (debug)
244 			printf("\nSegment %d, topo iteration %d\n",
245 				segno, topono);
246 #endif
247 		nchange = 0;
248 		stillactives = 0;
249 		/*
250 		 *	We keep track of one possible tunnel location.
251 		 *	A tunnel will eventually be an unconditional
252 		 *	branch to the same place that another jxxx
253 		 *	will want to branch to.  We will turn a
254 		 *	branch conditional/unconditional (word) that would
255 		 *	have to get bumped because its destination is too
256 		 *	far away, into a branch conditional/unconditional
257 		 *	byte to the tunnel branch conditional/unconditional.
258 		 *	Of course, the tunnel must branch to the same place
259 		 *	as we want to go.
260 		 */
261 		tunnel = 0;	/*initially, no tunnel*/
262 		SEGITERATE(segno, 0, 0, cojumpfrom, jumpfrom, ubjumpfrom, ++){
263 			tag = jumpfrom->s_tag;
264 			if (tag <= IGNOREBOUND)
265 				continue;	/*just an ordinary symbol*/
266 			if (tag == JXALIGN){
267 				tunnel = 0;	/*avoid tunneling across a flex alocation*/
268 				continue;	/*we take care of these later*/
269 			}
270 			if (   jumpfrom->s_jxfear == jbrfsize	/*unconditional*/
271 			    || (   tag == JXINACTIVE		/*inactive bumped*/
272 				&& (jumpfrom->s_jxbump != 0)
273 			       )
274 			   ) tunnel = jumpfrom;
275 			if (tag != JXACTIVE)
276 				continue;
277 			dest = jumpfrom->s_dest;
278 			if (jumpfrom->s_index != dest->s_index){
279 				yyerror("Intersegment jxxx");
280 				continue;
281 			}
282 			displ = dest->s_value - jumpfrom->s_value;
283 			if (displ < MINBYTE || displ > MAXBYTE) {
284 				/*
285 				 *	This is an immediate lose!
286 				 *
287 				 *	We first attempt to tunnel
288 				 *	by finding an intervening jump that
289 				 *	has  the same destination.
290 				 *	The tunnel is always the first preceeding
291 				 *	jxxx instruction, so the displacement
292 				 *	to the tunnel is less than zero, and
293 				 *	its relative position will be unaffected
294 				 *	by future jxxx expansions.
295 				 *
296 				 *	No tunnels if doing jumps...
297 				 */
298 				if (    (!jxxxJUMP)
299 				     && (jumpfrom->s_jxfear > jbrfsize)
300 				     && (tunnel)
301 				     && (tunnel->s_dest == jumpfrom->s_dest)
302 				     && (tunnel->s_index == jumpfrom->s_index)
303 				     && (tunnel->s_value - jumpfrom->s_value >=
304 						MINBYTE + jxxxfsize)
305 				   ) {
306 						/*
307 						 *	tunnelling is OK
308 						 */
309 						jumpfrom->s_dest = tunnel;
310 						/*
311 						 * no bumping needed, this
312 						 * is now effectively inactive
313 						 * but must be remembered
314 						 */
315 						jumpfrom->s_tag = JXTUNNEL;
316 #ifdef DEBUG
317 						if(debug)
318 						printf("Tunnel from %s from line %d\n",
319 							FETCHNAME(jumpfrom),
320 							jumpfrom->s_jxline);
321 #endif
322 						continue;
323 				} else {	/*tunneling not possible*/
324 					/*
325 					 *	since this will be turned
326 					 *	into a bumped jump, we can
327 					 *	use the unconditional jump
328 					 *	as a tunnel
329 					 */
330 					tunnel = jumpfrom;
331 					jumpfrom->s_tag = JXNOTYET;
332 					++nchange;
333 					continue;
334 				}
335 			}	/*end of immediate lose*/
336 			/*
337 			 *	Do a forward search for an intervening jxxx
338 			 */
339 			if (displ >= 0) {
340 				SEGITERATE(segno, cojumpfrom + 1,0,cointdest,
341 						intdest, ubintdest, ++){
342 					if (intdest->s_value > dest->s_value)
343 						break; /* beyond destination */
344 					if (intdest->s_tag <= JXQUESTIONABLE)
345 						continue;	/*frozen solid*/
346 					if (intdest->s_tag == JXALIGN){
347 						jumpfrom->s_jxoveralign = 1;
348 						badjxalign++;
349 					}
350 					/*
351 					 *	we assume the worst case
352 					 *	for unfrozen jxxxxes
353 					 */
354 					displ += intdest->s_jxfear;
355 				}
356 				if (displ <= MAXBYTE){
357 					/*
358 					 *	the worst possible conditions
359 					 *	can't hurt us, so forget about
360 					 *	this jump
361 					 */
362 					jumpfrom->s_tag = JXINACTIVE;
363 				} else {
364 					stillactives++;
365 				}
366 			} else {
367 			/*
368 			 *	backward search for intervening jxxx
369 			 */
370 				SEGITERATE(segno, cojumpfrom - 1,1,cointdest,
371 				  intdest, ubintdest, --){
372 					if (intdest->s_value <= dest->s_value)
373 						break; /* beyond destination */
374 					if (intdest->s_tag <= JXQUESTIONABLE)
375 						continue;	/*frozen solid*/
376 					if (intdest->s_tag == JXALIGN){
377 						jumpfrom->s_jxoveralign = 1;
378 						badjxalign++;
379 					}
380 					displ -= intdest->s_jxfear;
381 				}
382 				if (displ >= MINBYTE) {
383 					jumpfrom->s_tag = JXINACTIVE;
384 				} else {
385 					stillactives++;
386 				}
387 			}	/*end of backwards search*/
388 		}	/*end of iterating through all symbols in this seg*/
389 
390 		if (nchange == 0) {
391 			/*
392 			 *	Now, if there are still active jxxx entries,
393 			 *	we are partially deadlocked.  We can leave
394 			 *	these jxxx entries in their assumed short jump
395 			 *	form, as all initial displacement calcualtions
396 			 *	are hanging on unresolved jxxx instructions
397 			 *	that might explode into a long form, causing
398 			 *	other jxxxes jumping across the first set of
399 			 *	jxxxes to explode, etc.
400 			 *	However, if a jxxx jumps across a .align,
401 			 *	we assume the worst for the deadlock cycle,
402 			 *	and resolve all of them towards the long
403 			 *	jump.
404 			 *	Currently, the C compiler does not produce
405 			 *	jumps across aligns, as aligns are only used
406 			 *	in data segments, or in text segments to align
407 			 *	functions.
408 			 */
409 			if (stillactives){
410 				SEGITERATE(segno, 0, 0, cojumpfrom, jumpfrom,
411 				    ubjumpfrom, ++){
412 					if (jumpfrom->s_tag == JXACTIVE){
413 						jumpfrom->s_tag =
414 						  badjxalign?JXNOTYET:JXINACTIVE;
415 					}
416 				}
417 				if (badjxalign){
418 					jxxxbump(segno, (struct symtab **)0);
419 				}
420 			}
421 			/*
422 			 *	Handle  all of the .align s
423 			 */
424 			SEGITERATE(segno, 0, 0, cojumpfrom, jumpfrom,
425 			   ubjumpfrom, ++){
426 			    if (jumpfrom->s_tag == JXALIGN){
427 				/*
428 				 *	Predict the true displacement
429 				 *	needed, irregardless of the
430 				 *	fact that we guessed 1
431 				 */
432 				displ = (jumpfrom->s_value - 1) & (unsigned)jumpfrom->s_jxfear;
433 				if (displ == 0){	/*no virtual displacement*/
434 					jumpfrom->s_jxfear = -1;
435 				} else {
436 					jumpfrom->s_jxfear = (jumpfrom->s_jxfear + 1) - displ;
437 					/*
438 					 *	assert jumpfrom->s_jxfear > 0
439 					 */
440 					if (jumpfrom->s_jxfear == 1){
441 						/*our prediction was correct*/
442 						continue;
443 					}
444 					/*
445 					 *	assert jumpfrom->s_jxfear > 1
446 					 */
447 					jumpfrom->s_jxfear -= 1;	/*correct guess*/
448 				}
449 				/*
450 				 *	assert jumpfrom->s_jxfear = -1, +1...2**n-1
451 				 */
452 				jumpfrom->s_tag = JXNOTYET;	/*signal*/
453 				jxxxbump(segno, cojumpfrom);
454 				jumpfrom->s_tag = JXINACTIVE;
455 				/*
456 				 *	Assert jxfrom->jxvalue indexes the first
457 				 *	code byte after the added bytes, and
458 				 *	has n low order zeroes.
459 				 */
460 			  }
461 			}	/*end of walking through each segment*/
462 	    	}	/*end of no changes */
463 		else {	/*changes, and still have to try another pass*/
464 			jxxxbump(segno, (struct symtab **)0);
465 		}
466 	   }	/*end of doing the topologic sort*/
467 	}	/*end of iterating through all segments*/
468 }	/*end of jxxxfix*/
469 
470 /*
471  *	Go through the symbols in a given segment number,
472  *	and see which entries are jxxx entries that have
473  *	been logically "exploded" (expanded), but for which
474  *	the value of textually following symbols has not been
475  *	increased
476  */
477 
478 jxxxbump(segno, starthint)
479 	int	segno;
480 	struct	symtab **starthint;
481 {
482 	register	struct	symtab	**cosp, *sp;
483 	register	struct	symtab		*ub;
484 	register	int	cum_bump;
485 	register	unsigned	char	tag;
486 
487 	cum_bump = 0;
488 	SEGITERATE(segno, starthint, 0, cosp, sp, ub, ++){
489 		tag = sp->s_tag;
490 		if (tag == JXNOTYET){
491 #ifdef DEBUG
492 			if (debug){
493 			if (sp->s_dest != 0)
494 				printf("Explode jump to %s on line %d\n",
495 					FETCHNAME(sp->s_dest), sp->s_jxline);
496 			else
497 				printf("Explode an align! on line %d\n",
498 					sp->s_jxline);
499 			}
500 #endif
501 			sp->s_tag = JXINACTIVE;
502 			sp->s_jxbump = 1;
503 			cum_bump += sp->s_jxfear;
504 		}
505 		/*
506 		 *	Only bump labels and jxxxes. Ignored entries can
507 		 *	be incremented, as they are thrown away later on.
508 		 *	Stabds are given their final value in the second
509 		 *	pass.
510 		 */
511 		if (tag >= OKTOBUMP)	/*only bump labels and jxxxes and floating stabs*/
512 			sp->s_value += cum_bump;
513 	}
514 	usedot[segno].e_xvalue += cum_bump;
515 }
516