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