date and time created 80/08/13 18:55:13 by bill
[unix-history] / usr / src / old / as.vax / asjxxx.c
CommitLineData
d0d638ee
BJ
1/* Copyright (c) 1980 Regents of the University of California */
2static char sccsid[] = "@(#)asjxxx.c 4.1 %G%";
3#include <stdio.h>
4#include <sys/types.h>
5#include "as.h"
6#include "assyms.h"
7
8#define JBR 0x11
9#define BRW 0x31
10
11/*
12 * The number of bytes to add if the jxxx must be "exploded"
13 * into the long form
14 */
15#define JBRFSIZE 1 /*goes to brw*/
16#define JXXXFSIZE 3 /*goes to brb, brw <byte> <byte> */
17
18/*
19 * These variables are filled by asscan.c with the
20 * last name encountered (a pointer buried in the intermediate file),
21 * and the last jxxx symbol table entry encountered.
22 */
23struct symtab *lastnam;
24struct symtab *lastjxxx;
25
26/*
27 * Handle jxxx instructions
28 */
29ijxout(op,ap,nact)
30 struct arg *ap;
31{
32 if (passno == 1){
33 /*
34 * READ THIS BEFORE LOOKING AT jxxxfix()
35 *
36 * Record the jxxx in a special symbol table entry
37 */
38 register struct symtab *jumpfrom;
39
40 /*
41 * We assume the MINIMAL length
42 */
43 putins(op,ap,nact);
44 jumpfrom = lastjxxx;
45 jumpfrom->tag = JXACTIVE;
46 jumpfrom->jxbump = 0;
47 if (op == JBR)
48 jumpfrom->jxfear = JBRFSIZE;
49 else
50 jumpfrom->jxfear = JXXXFSIZE;
51 if (lastnam == 0)
52 yyerror("jxxx destination not a label");
53 jumpfrom->dest = lastnam;
54 jumpfrom->type = dotp->xtype; /*only TEXT or DATA*/
55 jumpfrom->index = dotp-usedot;
56 /*
57 * value ALWAYS (ALWAYS!!!) indexes the next instruction
58 * after the jump, even in the jump must be exploded
59 * (bumped)
60 */
61 jumpfrom->value = dotp->xvalue;
62 njxxx++;
63 } else {/* pass2, resolve */
64 /*
65 * READ THIS AFTER LOOKING AT jxxxfix()
66 */
67 register long oxvalue;
68 register struct exp *xp;
69 register struct symtab *tunnel;
70 register struct arg *aplast;
71
72 aplast = ap + nact - 1;
73 xp = aplast->xp;
74 if (lastjxxx->tag == JXTUNNEL){
75 lastjxxx->tag = JXINACTIVE;
76 tunnel = lastjxxx->dest;
77 xp->xvalue = tunnel->value /*index of instruction following*/
78 - 3 /* size of brw + word*/
79 + ( ( (tunnel->jxfear == JBRFSIZE) &&
80 (tunnel->jxbump == 0))?1:0);
81 /*non bumped branch byteis only 2 back*/
82 }
83 if (lastjxxx->jxbump == 0){ /*wasn't bumped, so is short form*/
84 putins(op, ap, nact);
85 } else {
86 if (op != JBR){ /*branch reverse conditional byte over
87 branch unconditional word*/
88 oxvalue = xp->xvalue;
89 xp->xvalue = lastjxxx->value;
90 putins(op^1, ap, nact);
91 xp->xvalue = oxvalue;
92 }
93 putins(BRW, aplast, 1);
94 }
95 }
96} /*end of ijxout*/
97
98jalign(xp, sp)
99 register struct exp *xp;
100 register struct symtab *sp;
101{
102 register int mask;
103 if (xp->xtype != XABS || xp->xvalue < 0 || xp->xvalue > 16) {
104 yyerror("Illegal `align' argument");
105 return;
106 }
107 flushfield(NBPW/4);
108 if (passno == 1) {
109 sp->tag = JXALIGN;
110 sp->jxfear = (1 << xp->xvalue) - 1;
111 sp->type = dotp->xtype;
112 sp->index = dotp-usedot;
113 /*
114 * We guess that the align will take up at least one
115 * byte in the code output. We will correct for this
116 * initial high guess when we explode (bump) aligns
117 * when we fix the jxxxes. We must do this guess
118 * so that the symbol table is sorted correctly
119 * and labels declared to fall before the align
120 * really get their, instead of guessing zero size
121 * and have the label (incorrectly) fall after the jxxx.
122 * This is a quirk of our requirement that indices into
123 * the code stream point to the next byte following
124 * the logical entry in the symbol table
125 */
126 dotp->xvalue += 1;
127 sp->value = dotp->xvalue;
128 njxxx++;
129 } else {
130 mask = (1 << xp->xvalue) - 1;
131 while (dotp->xvalue & mask){
132#ifdef UNIX
133 outb(0);
134#endif UNIX
135#ifdef VMS
136 *vms_obj_ptr++ = -1;
137 *vms_obj_ptr++ = 0;
138 dotp->xvalue += 1;
139#endif VMS
140 }
141 }
142}
143
144/*
145 * Pass 1.5, resolve jxxx instructions and .align in .text
146 */
147jxxxfix()
148{
149 register struct symtab *jumpfrom;
150 struct symtab **cojumpfrom, *ubjumpfrom;
151 register struct symtab *dest;
152 register struct symtab *intdest; /*intermediate dest*/
153 register struct symtab **cointdest, *ubintdest;
154
155 register struct symtab *tunnel;
156 int displ,nchange;
157 int badjxalign; /*if jump across an align*/
158 int stillactives; /*if still active jxxxes*/
159 int segno; /*current segment number*/
160 int topono; /*which iteration in the topo sort*/
161 register unsigned char tag;
162 /*
163 * consider each segment in turn...
164 */
165 for (segno = 0; segno < NLOC + NLOC; segno++){
166 badjxalign = 0; /*done on a per segment basis*/
167 /*
168 * Do a lazy topological sort.
169 */
170 for (topono = 1, nchange = 1; nchange != 0; topono++){
171#ifdef DEBUG
172 if (debug)
173 printf("\nSegment %d, topo iteration %d\n",
174 segno, topono);
175#endif
176 nchange = 0;
177 stillactives = 0;
178 /*
179 * We keep track of one possible tunnel location.
180 * A tunnel will eventually be an unconditional
181 * branch to the same place that another jxxx
182 * will want to branch to. We will turn a
183 * branch conditional/unconditional (word) that would
184 * have to get bumped because its destination is too
185 * far away, into a branch conditional/unconditional
186 * byte to the tunnel branch conditional/unconditional.
187 * Of course, the tunnel must branch to the same place
188 * as we want to go.
189 */
190 tunnel = 0; /*initially, no tunnel*/
191 SEGITERATE(segno, 0, 0, cojumpfrom, jumpfrom, ubjumpfrom, ++){
192 tag = jumpfrom->tag;
193 if (tag <= IGNOREBOUND)
194 continue; /*just an ordinary symbol*/
195 if (tag == JXALIGN){
196 tunnel = 0; /*avoid tunneling across a flex alocation*/
197 continue; /*we take care of these later*/
198 }
199 if ( jumpfrom->jxfear == JBRFSIZE /*unconditional*/
200 || ( tag == JXINACTIVE /*inactive bumped*/
201 && (jumpfrom->jxbump != 0)
202 )
203 ) tunnel = jumpfrom;
204 if (tag != JXACTIVE)
205 continue;
206 dest = jumpfrom->dest;
207 if (jumpfrom->index != dest->index){
208 yyerror("Intersegment jxxx");
209 continue;
210 }
211 displ = dest->value - jumpfrom->value;
212 if (displ < MINBYTE || displ > MAXBYTE) {
213 /*
214 * This is an immediate lose!
215 *
216 * We first attempt to tunnel
217 * by finding an intervening jump that
218 * has the same destination.
219 * The tunnel is always the first preceeding
220 * jxxx instruction, so the displacement
221 * to the tunnel is less than zero, and
222 * its relative position will be unaffected
223 * by future jxxx expansions.
224 */
225 if ( (jumpfrom->jxfear > JBRFSIZE)
226 && (tunnel)
227 && (tunnel->dest == jumpfrom->dest)
228 && (tunnel->index == jumpfrom->index)
229 && (tunnel->value - jumpfrom->value >=
230 MINBYTE + JXXXFSIZE)
231 ) {
232 /*
233 * tunnelling is OK
234 */
235 jumpfrom->dest = tunnel;
236 /*
237 * no bumping needed, this
238 * is now effectively inactive
239 * but must be remembered
240 */
241 jumpfrom->tag = JXTUNNEL;
242#ifdef DEBUG
243 if(debug)
244 printf("Tunnel from %s from line %d\n",
245 jumpfrom->name, lineno);
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 SEGITERATE(segno, 0, 0, cojumpfrom, jumpfrom,
336 ubjumpfrom, ++){
337 if (jumpfrom->tag == JXACTIVE){
338 jumpfrom->tag =
339 badjxalign?JXNOTYET:JXINACTIVE;
340 }
341 }
342 if (badjxalign){
343 jxxxbump(segno, (struct symtab **)0);
344 }
345 }
346 /*
347 * Handle all of the .align s
348 */
349 SEGITERATE(segno, 0, 0, cojumpfrom, jumpfrom,
350 ubjumpfrom, ++){
351 if (jumpfrom->tag == JXALIGN){
352 /*
353 * Predict the true displacement
354 * needed, irregardless of the
355 * fact that we guessed 1
356 */
357 displ = (jumpfrom->value - 1) & (unsigned)jumpfrom->jxfear;
358 if (displ == 0){ /*no virtual displacement*/
359 jumpfrom->jxfear = -1;
360 } else {
361 jumpfrom->jxfear = (jumpfrom->jxfear + 1) - displ;
362 /*
363 * assert jumpfrom->jxfear > 0
364 */
365 if (jumpfrom->jxfear == 1){
366 /*our prediction was correct*/
367 continue;
368 }
369 /*
370 * assert jumpfrom->jxfear > 1
371 */
372 jumpfrom->jxfear -= 1; /*correct guess*/
373 }
374 /*
375 * assert jumpfrom->jxfear = -1, +1...2**n-1
376 */
377 jumpfrom->tag = JXNOTYET; /*signal*/
378 jxxxbump(segno, cojumpfrom);
379 jumpfrom->tag = JXINACTIVE;
380 /*
381 * Assert jxfrom->jxvalue indexes the first
382 * code byte after the added bytes, and
383 * has n low order zeroes.
384 */
385 }
386 } /*end of walking through each segment*/
387 } /*end of no changes */
388 else { /*changes, and still have to try another pass*/
389 jxxxbump(segno, (struct symtab **)0);
390 }
391 } /*end of doing the topologic sort*/
392 } /*end of iterating through all segments*/
393} /*end of jxxxfix*/
394
395/*
396 * Go through the symbols in a given segment number,
397 * and see which entries are jxxx entries that have
398 * been logically "exploded" (expanded), but for which
399 * the value of textually following symbols has not been
400 * increased
401 */
402
403jxxxbump(segno, starthint)
404 int segno;
405 struct symtab **starthint;
406{
407 register struct symtab **cosp, *sp;
408 register struct symtab *ub;
409 register int cum_bump;
410 register unsigned char tag;
411
412 cum_bump = 0;
413 SEGITERATE(segno, starthint, 0, cosp, sp, ub, ++){
414 tag = sp->tag;
415 if (tag == JXNOTYET){
416#ifdef DEBUG
417 if (debug){
418 if (sp->dest != 0)
419 printf("Explode jump to %s on line %d\n",
420 sp->dest->name, lineno);
421 else
422 printf("Explode an align!\n");
423 }
424#endif
425 sp->tag = JXINACTIVE;
426 sp->jxbump = 1;
427 cum_bump += sp->jxfear;
428 }
429 /*
430 * Only bump labels and jxxxes. Ignored entries can
431 * be incremented, as they are thrown away later on.
432 * Stabds are given their final value in the second
433 * pass.
434 */
435 if (tag >= OKTOBUMP) /*only bump labels and jxxxes and floating stabs*/
436 sp->value += cum_bump;
437 }
438 usedot[segno].xvalue += cum_bump;
439}