ASM: Code generation phase, specific to a particular target machine.
ASM: Code generation phase, specific to a particular target machine. This version is for the Digital Equipment Corporation DECsystem-10. By Richard Kenner and David Shields, based on the LITTLE code generator for the IBM System/370 by Kenner.
1 .=member intro 2 .=list noauto,nodir 3 .=title 'dec-10 little code generator.' 4 .=title 'macros.' 5 .=list resume,nodir 6 $ !$&'()*+,-./0123456789:;<=>abcdefghijklmnopqrstuvwxyz^_ 7 $ the above line contains, in order of ascii codes, the 56 8 $ characters of the little language, starting in column 7. 9 /* 10 11 12 13 $$ $$$$$$$$$$ $$$$$$$$$$ $$$$$$$$$$ $$ $$$$$$$$$$ 14 $$ $$$$$$$$$$ $$$$$$$$$$ $$$$$$$$$$ $$ $$$$$$$$$$ 15 $$ $$ $$ $$ $$ $$ 16 $$ $$ $$ $$ $$ $$ 17 $$ $$ $$ $$ $$ $$$$$$ 18 $$ $$ $$ $$ $$ $$$$$$ 19 $$ $$ $$ $$ $$ $$ 20 $$ $$ $$ $$ $$ $$ 21 $$$$$$$$$$ $$$$$$$$$$ $$ $$ $$$$$$$$$$ $$$$$$$$$$ 22 $$$$$$$$$$ $$$$$$$$$$ $$ $$ $$$$$$$$$$ $$$$$$$$$$ 23 24 25 26 27 $$$$$$$$ $$$$$$$$ $$ $$ $$$$$$$$ $$ $$$$ 28 $$$$$$$$$$ $$$$$$$$$$ $$$$ $$$$ $$$$$$$$$$ $$$$ $$$$$$ 29 $$ $$ $$ $ $$ $$$$ $$ $$ $ $ $$ $$ $$ 30 $$ $$ $$ $$ $$ $$ $$ $$ $$ $$ 31 $$ $$ $$$$$$$$$ $$ $$ $$ $$$$$$$$$ $$ $$ $$ 32 $$$$$$$$$$ $$$$$$$$$ $$ $$ $$$$$$$$$ $$ $$ $$ 33 $$$$$$$$$$ $$ $$ $$ $$ $$ $$ $$ 34 $$ $$ $ $$ $$ $$ $ $$ $$ $$ $$ 35 $$ $$ $$$$$$$$$$ $$ $$ $$$$$$$$$$ $$$$$$$$$$ $$$$$$ 36 $$ $$ $$$$$$$$ $$ $$ $$$$$$$$ $$$$$$$$$$ $$$$ 37 38 39 40 this software is part of the little programming system. 41 address queries and comments to 42 43 little project 44 department of computer science 45 new york university 46 courant institute of mathematical sciences 47 251 mercer street 48 new york, ny 10012 49 50 this program is the code generation (asm) phase for the 51 digital equipment corporation decsystem-10 (dec-10). 52 it was written by richard kenner and david shields of 53 the courant institute, and is based on the little code 54 generator for the ibm system/370 written by kenner. 55 56 dr. anthony p. mccann and nigel chapman of the university 57 of leeds have agreed to attempt to produce a resident little 58 compiler for the dec-10 based on this asm. 59 60 61 the program source contains two documentation sections 62 delimited by conditional symbols doct10 and docnote. 63 doct10 text contains specification of t10 target language. 64 docnote contains example little programs and the 65 generated t10 code; it also contains a preliminary version 66 of the macro-10 macros to translate t10 to macro-10. 67 the documentation sections are included here to make this 68 work more accessible to those interested in studying the 69 bootstrap t10 compiler. 70 71 72 */ 1 .=member chars 2 /* little character set and ascii representation 3 4 !$&'()*+,-./0123456789:;<=>abcdefghijklmnopqrstuvwxyz^_ 5 the above line contains, in order of ascii codes, the 56 6 characters of the little language, starting in column 7. 7 8 the little language requires 56 distinct characters. 9 these include the 26 upper case letters, the 10 digits, 10 and the following special characters: 11 12 blank 13 = equal sign, assignment symbol 14 + plus 15 - minus 16 * times, asterisk 17 / divide, slash 18 ( left parenthesis 19 ) right parenthesis 20 , comma 21 . period, point 22 ; semicolon 23 : colon 24 $ dollar sign, comment character 25 ^ not 26 & and 27 ! or 28 < less than 29 > greater than 30 ' apostrophe, string delimiter 31 _ underline, break character 32 33 the following table gives the standard ascii encoding 34 for the little character set. 35 36 little character ascii ascii ascii ascii character 37 (hex) (oct) (dec) 38 39 space 20 40 32 space 40 ! or 21 41 33 exclamation mark 41 $ dollar sign 24 44 36 dollar sign 42 & and 26 46 38 ampersand 43 ' apostrophe 27 47 39 apostrophe 44 ( left parenthesis 28 50 40 left parenthesis 45 ) right parenthesis 29 51 41 right parenthesis 46 * asterisk 2a 52 42 asterisk 47 + plus 2b 53 43 plus 48 , comma 2c 54 44 comma 49 - minus 2d 55 45 minus 50 . period 2e 56 46 period 51 / slash 2f 57 47 slant 52 0 digit 0 30 60 48 digit 0 53 1 digit 1 31 61 49 digit 1 54 2 digit 2 32 62 50 digit 2 55 3 digit 3 33 63 51 digit 3 56 4 digit 4 34 64 52 digit 4 57 5 digit 5 35 65 53 digit 5 58 6 digit 6 36 66 54 digit 6 59 7 digit 7 37 67 55 digit 7 60 8 digit 8 38 70 56 digit 8 61 9 digit 9 39 71 57 digit 9 62 : colon 3a 72 58 colon 63 ; semicolon 3b 73 59 semicolon 64 < less than 3c 74 60 less than 65 = equals 3d 75 61 equals 66 > greater than 3e 76 62 greater than 67 a letter a 41 101 65 letter a 68 b letter b 42 102 66 letter b 69 c letter c 43 103 67 letter c 70 d letter d 44 104 68 letter d 71 e letter e 45 105 69 letter e 72 f letter f 46 106 70 letter f 73 g letter g 47 107 71 letter g 74 h letter h 48 110 72 letter h 75 i letter i 49 111 73 letter i 76 j letter j 4a 112 74 letter j 77 k letter k 4b 113 75 letter k 78 l letter l 4c 114 76 letter l 79 m letter m 4d 115 77 letter m 80 n letter n 4e 116 78 letter n 81 o letter o 4f 117 79 letter o 82 p letter p 50 120 80 letter p 83 q letter q 51 121 81 letter q 84 r letter r 52 122 82 letter r 85 s letter s 53 123 83 letter s 86 t letter t 54 124 84 letter t 87 u letter u 55 125 85 letter u 88 v letter v 56 126 86 letter v 89 w letter w 57 127 87 letter w 90 x letter x 58 130 88 letter x 91 y letter y 59 131 89 letter y 92 z letter z 5a 132 90 letter z 93 ^ not 5e 136 94 circumflex 94 _ underline 5f 137 95 underline 95 96 97 the bootstrap dec-10 asm requires additional characters. 98 the at and quotation mark appear in the generated code. 99 100 @ at 40 100 64 at 101 " quotation mark 22 42 34 quotation mark 102 103 brackets are used to delimit meta-comments within the program 104 source. the meta-comments contain queries, comments and 105 suggestions about the code; they are to be examined and 106 dealt with as soon as possible. 107 108 109 [ left bracket 5b 133 91 left bracket 110 ] right bracket 5d 135 93 right bracket 111 */ 112 1 .=member desc 2 .+doct10. 3 /* t 1 0 s p e c i f i c a t i o n s 4 5 t10 language level: 1.0 6 date of last language change: 07 jun 78 7 date of last t10 documentation change: 07 jun 78 8 9 this section defines the target language t10 of the bootstrap 10 little code generator for the dec-10. 11 12 13 statement format 14 ---------------- 15 16 each line contains either a t10 operation or comment. a comment 17 instruction begins with a semicolon in column one, and the 18 rest of the line contains text. an operation has an opcode 19 beginning in column 9 and an operand field beginning in column 17. 20 the operands may be followed by a comment field, which begins with 21 a semicolon. 22 23 operand formats 24 --------------- 25 26 fnam an fnam is the name of an external file whose 27 extension 'unv' contains the macros for translating 28 t10 operations to valid dec-10 macro-10 assembler 29 code. the default for fnam is 't10mac'; other values 30 can be selected using the 'unv' compiler parameter. 31 32 enam an enam is the external name of a nameset or procedure 33 truncated to six characters if necessary. 34 35 bnam a bnam is the internal three-character blockname used 36 to reference the first word of a block of memory. 37 references to words in the block have the form 38 'bnam+n' where n is nonnegative integer constant. 39 40 bnam's in generated t10 code include the following: 41 42 bas this block contains parameter lists, label lists, 43 constants and other values generated by bootstrap 44 code generator. 45 46 con constant block which contains initial values 47 of program constants. this block can be placed 48 in read-only memory if possible (see dbr). 49 50 g-- global data areas (namesets) are referenced within 51 the code by a block name consisting of the letter 52 g followed by two digits. numeric codes begin with 53 10; first nameset is g10, etc. 54 55 lcl this block contains local variables. 56 57 tmp this block contains temporaries. 58 59 r a register name consists of the letter r followed by 60 a decimal number from zero to 15, and indicates the 61 corresponding word of memory. when register addressed 62 as memory, an attempt is made to use reg and not 63 just memory location value, i.e., 'r3' instead of '3'. 64 65 n indicates a nonnegative integer constant with size 66 at most 18 bits 67 68 acon address constant for dwa operation, has the form 69 bnam+n. 70 71 ccon character code constant for dwc operation, in the 72 form of a sixbit character string delimited by 73 apostrophes. apostrophes within the string are 74 doubled. the string is to be assembled right- 75 justified with zero fill on the left. 76 77 icon signed integer constant for dwi operation. 78 79 ocon octal constant for dwo operation. 80 81 rcon floating point constant for dwr operation. in same 82 form as in little source, except that internal blanks 83 are eliminated. 84 85 scon character string constant for dws operation. in 86 the form of a sixbit character string delimited by 87 quotation marks. quotation marks within the string 88 are doubled. the string is to be assembled left- 89 justified with blank fill. 90 91 plbl a program label consists of the letter l followed 92 by three decimal digits. a lab instruction indicates 93 the definition point of a plbl. plbl's may occur only 94 in branching operations. 95 96 ea an effective address which specifies the memory location 97 of an operand. the ea consists of four parts, as follows: 98 99 indirection indicated by letter at (@) 100 block name a bnam 101 block offset signed integer constant 102 index register register name enclosed in parentheses 103 104 all parts are optional, but specified parts must be given 105 in the order above. if no parts given, value of zero 106 is implied, although bootstrap asm will never produce 107 such a null ea. 108 109 the bnam is optional, but if it is given then the 110 offset must be nonnegative. if the offset is not given, an 111 offset of zero is implied, although bootstrap asm will 112 never produce such an ea. 113 114 the address is formed by first taking block name and 115 offset to determine address. if nonzero index 116 register specified, then contents of the index register 117 are added to address. the resulting value is the location 118 of the word containing the operand, unless indirection 119 is specified, in which case the word addressed contains 120 the location of the operand. 121 122 eai an eai is similar to an ea except that it admits the 123 possibility of specifying a short (up to 18 bit) value 124 using the ea field directly, without requiring a memory 125 access. the operand value is that of the ea itself, and 126 not the word addressed by ea. an instance of such an 127 operand, called 'immediate', is denoted by appending 128 i to the t10 opcode. 129 130 note that certain instructions have four letter opcodes 131 ending in i. such instructions have ea which is always 132 immediate value. 133 134 the following table lists the t10 opcodes in alphabetical order. 135 there follows a description of the opcodes according to their 136 function. 137 138 139 3.1 ban r,eai set (r) to (r) .and. (eai) 140 3.4 bfb r,ea set (r) to .fb. (ea) 141 3.5 bnb r,ea set (r) to .nb. (ea) 142 3.6 bno r,ea set (r) to .not.(ea) 143 3.2 bor r,eai set (r) to (r) .or. (eai) 144 3.3 bxo r,eai set (r) to (r) .exor. (eai) 145 7.3 cal enam,n1,bnam+n2 call procedure enam, n1 args at bnam+n2 146 6.2 ceq r,eai skip next instruction if (r) eq (eai) 147 6.5 cge r,eai skip next instruction if (r) ge (eai) 148 6.4 cgt r,eai skip next instruction if (r) gt (eai) 149 6.7 cle r,eai skip next instruction if (r) le (eai) 150 6.6 clt r,eai skip next instruction if (r) lt (eai) 151 6.3 cne r,eai skip next instruction if (r) ne (eai) 152 1.8 dbr bnam,n define read-only block bnam of n words 153 1.9 dbw bnam,n define writeable block bnam of n words 154 1.5 dec enam define end of code for procedure enam 155 1.3 dep enam define end of procedure enam 156 1.6 dna enam,bnam,n define access of nameset enam 157 1.7 dnd enam,bnam,n define nameset enam 158 1.4 dsc enam define start of code for procedure enam 159 1.2 dsp enam,n1,n2 define start of procedure enam 160 1.10 dwa bnam+n,acon define word with address 161 1.11 dwc bnam+n,ccon define word with character code 162 1.12 dwi bnam+n,icon define word with integer 163 1.13 dwo bnam+n,ocon define word with octal 164 1.14 dwr bnam+n,rcon define word with real 165 1.15 dws bnam+n,scon define word with character string 166 1.16 dwz bnam+n1,n2 define initial block of zeros 167 7.1 ent enam enter procedure enam 168 4.7 iab r,ea set (r) to iabs((ea)) 169 4.1 iad r,eai integer add (eai) to (r) 170 4.9 iao r,ea integer add one: set (r) to (ea)+1 171 4.8 ico r,ea integer complement of (ea) to (r) 172 4.4 idi r,eai integer divide (r) by (eai) 173 4.12 idti r,n divide (r) by n-th power of two 174 4.13 ieq r,eai set (r) to 1 if (r) eq (eai), else 0 dsj 1 4.19 ifr r,ea set (r) to ifix((ea)) 175 4.16 ige r,eai set (r) to 1 if (r) ge (eai), else 0 176 4.15 igt r,eai set (r) to 1 if (r) gt (eai), else 0 177 4.18 ile r,eai set (r) to 1 if (r) le (eai), else 0 178 4.17 ilt r,eai set (r) to 1 if (r) lt (eai), else 0 179 4.5 imo r,eai set (r) to mod((r),(eai)) 180 4.11 imti r,n multiply (r) by n-th power of two 181 4.3 imu r,eai integer multiply (eai) by (r) 182 4.14 ine r,eai set (r) to 1 if (r) ne (eai), else 0 183 4.6 isi r,eai set (r) to isign((r),(eai)) 184 4.10 iso r,ea integer subtract one: set (r) to (ea)-1 185 4.2 isu r,eai integer subtract (eai) from (r) 186 6.8 jeq r,plbl jump to plbl if (r) eq 0 187 6.11 jge r,plbl jump to plbl if (r) ge 0 188 6.10 jgt r,plbl jump to plbl if (r) gt 0 189 6.13 jle r,plbl jump to plbl if (r) le 0 190 6.12 jlt r,plbl jump to plbl if (r) lt 0 191 6.15 jmn r,plbl jump never to plbl 192 6.14 jmp r,plbl jump always to plbl 193 6.9 jne r,plbl jump to plbl if (r) ne 0 194 6.1 lab plbl define label plbl 195 2.2 lda r,ea set (r) to ea 196 2.6 ldf r,ea load (r) from byte pointer in (ea) 197 2.8 ldl r,ea set (r) to .f. 19,18,(ea) 198 2.9 ldr r,ea set (r) to .f. 1,18,(ea) 199 2.1 ldw r,eai set (r) to (eai) eaa 1 .+t20. eaa 2 3.14 lla r,ea set (r) to rh(ea) - for local address eaa 3 (extended addressing only) eaa 4 ..t20 200 2.4 lpr r,ea,n1,n2 set (r) to .f. n1+1,n2,(ea) dsa 1 2.12 mvw r,ea,n move n words from ea to (r) dsu 1 2.12 mvx r,ea,n move n words from (r) to ea 202 5.7 rab r,ea set (r) to abs((ea)) 203 5.1 rad r,eai real add (eai) to (r) 204 5.8 rco r,eai real complement of (eai) to (r) 205 5.4 rdi r,eai real divide (r) by (eai) 206 5.9 req r,eai set (r) to 1 if (r)-(eai) eq 0.0, else 0 207 7.2 ret enam return from procedure enam dsj 2 5.15 rfi r,eai set (r) to float((eai)) 208 5.12 rge r,eai set (r) to 1 if (r)-(eai) ge 0.0, else 0 209 5.11 rgt r,eai set (r) to 1 if (r)-(eai) gt 0.0, else 0 210 5.14 rle r,eai set (r) to 1 if (r)-(eai) le 0.0, else 0 211 5.13 rlt r,eai set (r) to 1 if (r)-(eai) lt 0.0, else 0 212 5.5 rmo r,eai set (r) to amod((r),(eai)) 213 5.3 rmu r,eai real multiply (r) by (eai) 214 5.10 rne r,eai set (r) to 1 if (r)-(eai) ne 0.0, else 0 215 5.6 rsi r,eai set (r) to sign((r),(eai)) 216 5.2 rsu r,eai real subtract (eai) from (r) dsj 3 5.16 rtr r,ea set (r) to aint((ea)) 217 1.1 search fnam specify universal file for search 218 2.5 spr r,ea,n1,n2 set .f. n1+1,n2,(ea) to .f. 1,n2,(r) 219 2.7 stf r,ea store (r) to byte pointer in (ea) 220 2.10 stl r,ea set .f.19,18,(ea) to .f. 1,18,(r) 221 2.11 str r,ea set .f.1,18,(ea) to .f. 1,18,(r) 222 2.3 stw r,ea set (ea) to (r) 223 2.14 zebi r,n zeroize n words starting at (r) 224 2.13 zew r,ea set (ea) to zero 225 226 227 description of t10 operations 228 ----------------------------- 229 230 -1- declaration and definition operations 231 232 these operations define the structure of a program and specify 233 the initial value of memory locations. 234 they are not executable. 235 236 1.1 search fnam specify universal file for search 237 238 the search operation specifies the file to be searched 239 for macro definitions to translate the t10 code into valid 240 dec-10 macro-10 instructions. if present, the search 241 instruction is the first t10 instruction in a procedure. 242 243 1.2 dsp enam,n1,n2 define start of procedure enam 244 1.3 dep enam define end of procedure enam 245 246 the dsp and dep instructions begin and end a procedure 247 definition, respectively. dsp and dep are required. dsp 248 is the first instruction in a procedure, unless a search 249 instruction is present, in which case the dsp immediately 250 follows the search instruction. the dep instruction is 251 the last instruction in a procedure. 252 253 the first argument of both dsp and dep is the external 254 name of the procedure. the second argument of a dsp gives 255 the number of arguments; the third argument gives the type 256 of the procedure, as follows: 257 258 0 subroutine (subr) 259 1 function (fnct) 260 2 program (prog) 261 262 1.4 dsc enam define start of code for procedure enam 263 1.5 dec enam define end of code for procedure enam 264 265 the dsc instruction indicates the start of the executable code 266 section for a procedure, the dec instruction indicates the end 267 of the code section. both are required, and all executable 268 instructions must occur in the code section. for the dec-10, 269 the dsc effects relocation to high segment, the dec returns 270 relocation to low segment. 271 272 1.6 dna enam,bnam,n define access of nameset enam 273 1.7 dnd enam,bnam,n define nameset enam 274 275 the dna and dnd instructions effect access and definition of 276 global data areas. enam is the external name of the block, 277 bnam is the internal name of the block used in t10 instructions, 278 and n is the length of the block in words. the dnd instruction 279 specifies that this procedure define the data area, and so may 280 contain data definition (dw-) instructions for words in the 281 data area. 282 283 1.8 dbr bnam,n define read-only block bnam of n words 284 1.9 dbw bnam,n define writeable block bnam of n words 285 286 the dbr and dbw instructions reserve blocks of working storage. 287 the words in a dbr block are never written, so that a dbr block 288 should be allocated in read-only memory if this is possible. 289 290 1.10 dwa bnam+n,acon define word with address 291 1.11 dwc bnam+n,ccon define word with character code 292 1.12 dwi bnam+n,icon define word with integer 293 1.13 dwo bnam+n,ocon define word with octal 294 1.14 dwr bnam+n,rcon define word with real 295 1.15 dws bnam+n,scon define word with character string 296 297 the dw operations define the initial value of a memory word. 298 the first operand specfies the location of the word to be 299 initialized and has the form bnam+n where bnam is a block 300 defined by dbr, dbw or dnd instruction, and n is the offset 301 within the block. the second operand specifies the value to 302 which the word is to be initialized, according to the 303 operation code. 304 305 1.16 dwz bnam+n1,n2 define initial block of zeros 306 307 a dwz instruction indicates that the n2 words beginning at 308 location bnam+n1 are to be initialized to zero. 309 310 -2- data transmission instructions 311 312 these instructions transmit data without operating upon it, and 313 are used to move parts of words, single words 314 and blocks of words. 315 316 2.1 ldw r,eai set (r) to (eai) 317 2.2 lda r,ea set (r) to ea eaa 5 .+t20. eaa 6 3.14 lla r,ea set (r) to rh(ea) (extended addressing) eaa 7 ..t20 318 2.3 stw r,ea set (ea) to (r) 319 320 the ldw instruction moves the operand value to a register. 321 the lda instruction moves the operand location to a register, 322 and is equivalent to ldwi. eaa 8 .+t20. eaa 9 for extended addressing, this is an xmovei. eaa 10 the lla instruction moves the right half of the operand eaa 11 location to a register, and should be used whenever this will eaa 12 be used in a local context. it is equivalent to ldri. eaa 13 ..t20 323 the stw instruction stores the register contents at the 324 operand location. 325 326 2.4 lpr r,ea,n1,n2 set (r) to .f. n1+1,n2,(ea) 327 2.5 spr r,ea,n1,n2 set .f. n1+1,n2,(ea) to .f. 1,n2,(r) 328 329 the lpr and spr instructions operate on part of a word. the 330 constants n1 and n2 specify the starting point of the field and 331 the length of the field in bits, respectively. n1 is the little 332 field origin minus one. n2 is the field size. 333 334 2.6 ldf r,ea load (r) from byte pointer in (ea) 335 2.7 stf r,ea store (r) to byte pointer in (ea) 336 337 the ldf and stf instructions operate on part of a word, using a 338 byte pointer explicitly constructed using lpr and spr 339 operations. 340 such a byte pointer is always constructed in a register, and the 341 ea of the ldf and stf will usually, although not necessarily, be 342 a register. 343 the generated byte pointer has same format and interpretation 344 as a dec-10 byte pointer: 345 346 .f. 01, 24, - ea of word containing byte 347 .f. 25, 06, - byte length in bits 348 .f. 31, 06, - number of bits to right of rightmost bit in byte. 349 350 2.8 ldl r,ea set (r) to .f. 19,18,(ea) 351 2.9 ldr r,ea set (r) to .f. 1,18,(ea) 352 2.10 stl r,ea set .f.19,18,(ea) to .f. 1,18,(r) 353 2.11 str r,ea set .f.1,18,(ea) to .f. 1,18,(r) 354 355 356 the halfword ops transmit halfword values using the dec-10 357 halfword operations. they can be considered to be defined 358 by lpr and spr operations, as follows: 359 360 ldl r,ea <-> lpr r,ea,18,18 361 ldr r,ea <-> lpr r,ea,0,18 362 stl r,ea <-> spr r,ea,18,18 363 str r,ea <-> spr,r,ea,0,18 364 dsa 2 2.12 mvw r,ea,n move n words from ea to (r) 366 dsa 3 the mvw instruction moves a block of memory. ea specifies dsa 4 the address of the first word to be moved, (r) contains the 369 address of the first word to which data is to be moved, and 370 n specifies the number of words to be moved. dsu 2 dsu 3 mvx is like mvw, but moves from (r) to ea. 371 372 2.13 zew r,ea set (ea) to zero 373 2.14 zebi r,n zeroize n words starting at (r) 374 375 the zew instruction clears a memory location. the zebi 376 instruction clears the n words beginning at the 377 specified memory location. 378 379 380 381 -3- the boolean operations operate on full word values. 382 383 3.1 ban r,eai set (r) to (r) .and. (eai) 384 3.2 bor r,eai set (r) to (r) .or. (eai) 385 3.3 bxo r,eai set (r) to (r) .exor. (eai) 386 387 the binary operations combine the operand value and the register 388 contents, and store the result in the register. 389 390 3.4 bfb r,ea set (r) to .fb. (ea) 391 3.5 bnb r,ea set (r) to .nb. (ea) 392 3.6 bno r,ea set (r) to .not.(ea) 393 394 the bno instruction inverts a full word, so that correct 395 translation of the little not is effected by using lpr to 396 extract desired part of full-word value computed by bno. 397 398 -4- integer arithmetic operations 399 400 4.1 iad r,eai integer add (eai) to (r) 401 4.2 isu r,eai integer subtract (eai) from (r) 402 4.3 imu r,eai integer multiply (eai) by (r) 403 4.4 idi r,eai integer divide (r) by (eai) 404 4.5 imo r,eai set (r) to mod((r),(eai)) 405 4.6 isi r,eai set (r) to isign((r),(eai)) 406 407 the binary operations combine the operand value and the register 408 contents, and store the result in the register. 409 410 4.7 iab r,ea set (r) to iabs((ea)) 411 4.8 ico r,ea integer complement of (ea) to (r) dsj 4 4.19 ifr r,ea set (r) to ifix((ea)) 412 413 the integer complement is the result of subtracting the operand 414 value from zero. 415 416 4.9 iao r,ea integer add one: set (r) to (ea)+1 417 4.10 iso r,ea integer subtract one: set (r) to (ea)-1 418 419 the operations iao and iso effect integer addition and 420 subtraction of the value one, respectively. 421 422 4.11 imti r,n multiply (r) by n-th power of two 423 4.12 idti r,n divide (r) by n-th power of two 424 425 the imti and idti instructions are special cases of the imu and 426 idi instructions where the divisor is a power of two. such 427 operations can be effected by appropriate arithmetic shift. 428 to avoid incorrect results for division of a negative number, 429 the idti instruction is never emitted if the dividend 430 has size ws. 431 432 4.13 ieq r,eai set (r) to 1 if (r) eq (eai), else 0 433 4.14 ine r,eai set (r) to 1 if (r) ne (eai), else 0 434 4.15 igt r,eai set (r) to 1 if (r) gt (eai), else 0 435 4.16 ige r,eai set (r) to 1 if (r) ge (eai), else 0 436 4.17 ilt r,eai set (r) to 1 if (r) lt (eai), else 0 437 4.18 ile r,eai set (r) to 1 if (r) le (eai), else 0 438 439 the integer comparison operations compare the register contents 440 and the operand value, setting the register to one if the 441 relation is true, or to zero if it is not. 442 443 -5- real (floating point) operations 444 445 5.1 rad r,eai real add (eai) to (r) 446 5.2 rsu r,eai real subtract (eai) from (r) 447 5.3 rmu r,eai real multiply (r) by (eai) 448 5.4 rdi r,eai real divide (r) by (eai) 449 5.5 rmo r,eai set (r) to amod((r),(eai)) 450 5.6 rsi r,eai set (r) to sign((r),(eai)) 451 452 the binary operations combine the operand value and the register 453 contents, and store the result in the register. 454 the memory operand may be immediate mode, although this should 455 not occur. the eai case results from the method in which these 456 operations are processed by the bootstrap asm. 457 458 5.7 rab r,ea set (r) to abs((ea)) 459 5.8 rco r,eai real complement of (eai) to (r) dsj 5 5.15 rfi r,eai set (r) to float((eai)) dsj 6 5.16 rtr r,ea set (r) to aint((ea)) 460 461 5.9 req r,eai set (r) to 1 if (r)-(eai) eq 0.0, else 0 462 5.10 rne r,eai set (r) to 1 if (r)-(eai) ne 0.0, else 0 463 5.11 rgt r,eai set (r) to 1 if (r)-(eai) gt 0.0, else 0 464 5.12 rge r,eai set (r) to 1 if (r)-(eai) ge 0.0, else 0 465 5.13 rlt r,eai set (r) to 1 if (r)-(eai) lt 0.0, else 0 466 5.14 rle r,eai set (r) to 1 if (r)-(eai) le 0.0, else 0 467 468 the real comparison operations compare the register contents 469 and the operand value, setting the register to (integer) one if 470 the relation is true, or to (integer) zero if it is not. 471 472 473 -6- branching instructions 474 475 the branching instructions control program execution. a 476 program label is always defined in the code section by a 477 lab instruction. 478 479 6.1 lab plbl define label plbl 480 481 6.2 ceq r,eai skip next instruction if (r) eq (eai) 482 6.3 cne r,eai skip next instruction if (r) ne (eai) 483 6.4 cgt r,eai skip next instruction if (r) gt (eai) 484 6.5 cge r,eai skip next instruction if (r) ge (eai) 485 6.6 clt r,eai skip next instruction if (r) lt (eai) 486 6.7 cle r,eai skip next instruction if (r) le (eai) 487 488 the branch comparison instructions compare the register contents 489 and the operand value, and cause the next instruction to be 490 skipped if the relation is true. 491 these instructions do not alter the register contents. 492 493 6.8 jeq r,plbl jump to plbl if (r) eq 0 494 6.9 jne r,plbl jump to plbl if (r) ne 0 495 6.10 jgt r,plbl jump to plbl if (r) gt 0 496 6.11 jge r,plbl jump to plbl if (r) ge 0 497 6.12 jlt r,plbl jump to plbl if (r) lt 0 498 6.13 jle r,plbl jump to plbl if (r) le 0 499 6.14 jmp r,plbl jump always to plbl 500 6.15 jmn r,plbl jump never to plbl 501 502 the jump operations compare the register contents with zero 503 and cause a branch to the plbl if the relation is true. 504 the jmp instruction always causes a jump. the jmn instruction 505 never causes a jump, and is thus a no-op. the jmp and jmn 506 instructions always specify a register, usually r0, although the 507 contents of the register do not determine if the branch is 508 or is not taken. 509 these instructions do not alter the register contents. 510 511 -7- procedure linkage 512 513 ent is the first instruction executed on procedure invocation, 514 cal is used to invoke other procedures and ret is used to return 515 from a procedure invocation. 516 517 the bootstrap asm makes specific assumptions about register 518 usage but otherwise permits some freedom in implementation 519 of linkage. 520 521 the bootstrap asm allocates registers r0 through r11. r0 is 522 used to return the result of a function invocation. within a 523 procedure that has arguments r11 is used to address the 524 paramater list. a parameter list is a list of words containing 525 the addresses of the corresponding procedure arguments. 526 the bootstrap asm allocates parameter lists within 527 the base block (bnam 'bas'). 528 529 the bootstrap asm requires that register contents be preserved 530 over a cal instruction. this requires that the called procedure 531 save the registers before beginning execution and restore them 532 before returning. 533 534 7.1 ent enam enter procedure enam 535 536 the ent is the first instruction executed in a procedure and 537 must occur within the code section. it immediately follows the 538 dsc instruction. the required register save action depends on 539 procedure type (which is given by third argument of dsp 540 instruction) as follows: 541 follows 542 543 0 (subr) registers r0 through r11 must be saved 544 1 (fnct) registers r1 through r11 must be saved. r0 need 545 not be saved, as it will be set to contain 546 function value 547 2 (prog) registers need not be saved, as a program never 548 returns to caller. 549 550 if the procedure has arguments, indicated by the second argument 551 of the dsp instruction having a value greater than zero, then 552 the third argument of the cal instruction contains the address 553 of the parameter list. after saving the registers, this 554 address is to be copied to r11. 555 556 on entry, the procedure can compare the number of arguments 557 given in the dsp instruction with the number actually supplied, 558 as indicated by the second argument of the cal instruction which 559 invoked the procedure. 560 561 7.2 ret enam return from procedure enam 562 563 a return instruction restores the registers and returns to 564 point of invocation. register restore done as follows, 565 according to procedure type indicated by third argument of 566 dsp instruction. 567 568 0 (subr) restore registers r0 through r11 569 1 (fnct) restore registers r1 through r11 570 2 (prog) a return within a prog is invalid and should be 571 treated as an error. the compiler should map 572 return's in a prog into calls to the standard 573 library termination routine ltlfin. 574 575 7.3 cal enam,n1,bnam+n2 call procedure enam, n1 args at bnam+n2 576 577 a cal instruction calls the named procedure. the second 578 argument gives the number of arguments. if it is zero, 579 indicating no arguments, the third argument of cal will be zero. 580 otherwise third argument of cal instruction will be address in 581 address in base block (bnam 'bas') of the start of the 582 parameter list. 583 584 585 586 */ 587 ..doct10 1 .=member mods 2 $ ---all corrections are to insert self-description after mods.2--- pic 1 pic 2 $ pic d. shields 01-sep-82 level 82244 pic 3 $ r. kenner pic 4 $ pic 5 $ 1. fix bug in asmlong re comparison of multi-word items. pic 6 $ 2. generate position independent code for vax vms. pic 7 $ dsw 1 dsw 2 $ dsw d. shields 15-jan-82 level 82015 dsw 3 $ dsw 4 $ avoid generating 'g--' symbols for s32u, as they are too much for dsw 5 $ 'as' to deal with; generate full global block name instead. dsw 6 $ decks affected - eminit, outdata, outcon. dsw 7 dsv 1 dsv 2 $ dsv d. shields 20-nov-81 level 81324 dsv 3 $ dsv 4 $ 1. support t32h for unix (s32) also. dsv 5 $ 2. for s32 nsheap, address the first word in nsheap (heap_addr) dsv 6 $ directly, except within parameter lists. dsv 7 $ decks affected - emitea, macros dsv 8 dsu 4 dsu 5 $ dsu d. shields 02-oct-81 level 81278 dsu 6 $ dsu 7 $ 1. generate opcode mvx where needed. mwx is like mvw, except dsu 8 $ operands in other order. dsu 9 $ this affects all implementations. dsu 10 $ 2. for s32, support program option 'nsheap=/nsheap', so that if dsu 11 $ a nameset given, then that specified nameset will be addressed dsu 12 $ indirectly. this permits dynamic allocation dsu 13 $ of the setl heap, for example. the generated code asssumes the dsu 14 $ first word in the nameset contains the dynamic address. this dsu 15 $ value is loaded at the start of each procedure referencing the dsu 16 $ nameset; thereafter, references are made using the dynamic dsu 17 $ address which is kept in a register, together with the vax dsu 18 $ 'indexed' addressing mode of the form '[r..]'. dsu 19 $ code is conditioned by symbol t32h, and is currently enabled dsu 20 $ for s32v (vax vms). new t32 ops include the following dsu 21 $ lha rb,rw,loc load loc to rb dsu 22 $ rb is register to get byte address, rw to get word address dsu 23 $ sha var,ea store heap address of var in ea dsu 24 $ decks affected - macros, start, asmini, setup, eminit, emitsub dsu 25 $ storer, endsubr, emopr, emitea, emiteh (new) dsu 26 eaa 14 eaa 15 $ eaa c. hedrick 29-aug-81 level 81243 eaa 16 $ d. shields eaa 17 $ eaa 18 $ add support for t20, extended addressing extension of t10. eaa 19 $ adds two parameters eaa 20 $ nsheap=/nsheap name of nameset to be 'relocated' eaa 21 $ nshorg=^o2000001/ extended address of nsheap nameset. eaa 22 $ (section two) eaa 23 $ if nsheap selected, all references to variables in the specified eaa 24 $ nameset are done indirectly with efiw macro. eaa 25 $ this nameset must contain only single-word variables and eaa 26 $ variables in it cannot be initialized with data statements. eaa 27 $ the new (t20) opcodes are hba, hbb, hbc, lla, and dha. eaa 28 $ build this asm by compiling with 'iset=t20'. eaa 29 $ decks affected - macros, start, asmini, eminit, asmfld, getword, eaa 30 $ endsubr, emitea, emitex (new) eaa 31 dst 1 dst 2 $ dst d. shields 17-jun-81 level 81168 dst 3 $ dst 4 $ 1. add option nspage=0/1 such that nspage=1 causes pnd and pna dst 5 $ ops to be emitted instead of dnd and dna, respectively. this dst 6 $ is principally for variant setl lib on vax where want in some dst 7 $ cases to align namesets on page boundaries. dst 8 $ 2. add measurement feature 'enp' consisting of two new dst 9 $ options, enp=0/t.rep and enporg=0/0. if enp specified, the dst 10 $ specified file must have been created using rep=p gen option dst 11 $ the generated code will contain (new) opcode 'enp' with dst 12 $ argument determined by the position of the procedure in the dst 13 $ enp file, dst 14 $ incremented by value of enporg parameter. this makes it dst 15 $ possible at run-time to determine the active procedure. dst 16 $ enp instructions are emitted at start of each procedure and dst 17 $ after each call instruction within the generated code. dst 18 $ this feature conditioned by symbol 'enp', which is set for s32 dst 19 $ decks affected - start, asmini, eminit, endsubr, eminit, asmexit. dst 20 rke 1 rke 2 $ rke r. kenner 12-nov-80 level 80317 rke 3 $ d. shields rke 4 $ rke 5 $ 1. fix problem (fr156) in handling of multi-word temporaries. rke 6 $ 2. avoid sending abnormal termination dumps to terminal. rke 7 $ decks affected - assign, aermey. rke 8 rkd 1 rkd 2 $ rkd r. kenner 02-sep-80 level 80246 rkd 3 $ rkd 4 $ fix bug (fr150) that caused stores of live quantities to not be rkd 5 $ done when same variable used in arithmetic operation where another rkd 6 $ variable is both output and input, and where the live variable is rkd 7 $ second argument. for example, in 'i=i+j', j was not stored. rkd 8 $ deck affected - emitdop. rkd 9 dss 1 dss 2 $ dss d. shields 08-aug-80 level 80217 dss 3 $ dss 4 $ modify t32u to cater to unix assembler (as) as follows: dss 5 $ 1. generate unique names for local blocks (base, label, const, dss 6 $ temp) by generating new name for each procedure. for example, dss 7 $ base block identified as baa in first procedure, bab in second dss 8 $ and so forth. the second and third characters of these names dss 9 $ are generated in upper case. dss 10 $ 2. also make label names unique, use five digit label. dss 11 $ decks affected - setup, eminit, branchr, labdef, endsubr. dss 12 dsr 1 dsr 2 $ dsr d. shields 30-jul-80 level 80212 dsr 3 $ dsr 4 $ 1. fix problem in listing ats option value. dsr 5 $ 2. fix problem in representation of grave accent for t32u, as dsr 6 $ this character not in s66 character set. dsr 7 $ decks affected - macros, asmini, emitea. dsr 8 dsq 1 dsq 2 $ dsq d. shields 21-jul-80 level 80203 dsq 3 $ dsq 4 $ 1. for t32, add option iv=0/1 such that iv=1 causes dsq 5 $ integer overflow bit to be set in procedure entry dsq 6 $ mask of all procedures compiled, so that integer dsq 7 $ overflows can be trapped. dsq 8 $ 2. if hmeqtm, generate tabs in generated code. this not dsq 9 $ fully machine-independent, but all current machines dsq 10 $ s10, s32 (both vms and unix) are dec and use same tab dsq 11 $ conventions. this reduces size of generated code files, dsq 12 $ by at least a third for most programs based on initial dsq 13 $ test. dsq 14 $ 3. delete 'no errors detected message'. dsq 15 $ 4. add program parameter ats=1/0 such that ats=1 causes dsq 16 $ generated code to include date of compilation. ats=0 meant dsq 17 $ for use during replication to compare generated code files. dsq 18 $ 5. begin work on bootstrapping to s32 unix. this requires dsq 19 $ possibility of producing two t32 variants: dsq 20 $ t32v - vms dsq 21 $ t32u - unix. dsq 22 $ nyu currently using vms, hence iset=unix required to dsq 23 $ configure for unix. note that unix assembler (as) dsq 24 $ does not support macros, so that a separate c processor dsq 25 $ is required. hence, changes for t32u are initially as dsq 26 $ small as possibile, and mainly reflect different unix dsq 27 $ conventions for specifying indirection and literals. dsq 28 $ no provision has been made for differing default file dsq 29 $ names, etc.; this distinction can be introduced by dsq 30 $ adding s32u/s32v conditional symbols later. dsq 31 $ dsq 32 $ decks affected - macros, start, asmini, eminit, dsq 33 $ endsubr, emitea, emopr, ocsput. dsq 34 dsp 1 dsp 2 $ dsp d. shields 26-feb-80 level 80057 dsp 3 $ dsp 4 $ fix errors reported by chuck hedrick at rutgers relating dsp 5 $ to s10/t10. dsp 6 $ 1. missing comment character after mcs definition dsp 7 $ 2. missing semicolon. dsp 8 $ also fix error (fr2.3.131) in labfix that caused errors dsp 9 $ in compiling some until loops. dsp 10 $ also add new t10 option 'end=prg/seg' such if value other dsp 11 $ than '0' specified, code file ended as follows dsp 12 $ 1. end=prg places dsp 13 $ extern z$strt dsp 14 $ end z$strt dsp 15 $ at end of code file. dsp 16 $ 2. end=seg places dsp 17 $ end dsp 18 $ at end of code file. dsp 19 $ 3. end=nam, where nam not prg or seg, places dsp 20 $ endnam dsp 21 $ at end of code file. dsp 22 $ decks affected - macros, start, asmini, sdsnam, sdlnam, dsp 23 $ labfix, asmexit. dsp 24 dso 1 dso 2 $ dso d. shields 04-feb-80 level 80035 dso 3 $ dso 4 $ 1. increase ha dimension to 937. dso 5 $ 2. fix error that caused looping in some cases dso 6 $ while printing tables on abnormal termination. dso 7 $ decks affected - macros, aermey dso 8 dsn 1 dsn 2 $ dsn d. shields 14-dec-79 level 79348 dsn 3 $ dsn 4 $ 1. rewind voa file only for s66. dsn 5 $ 2. support long filenames for s32. dsn 6 $ 3. list actual parameter string. dsn 7 $ 4. extend maximum permitted dimension for s10, s32 and s37 up dsn 8 $ to 2**n-1 with n=17, 30 and 22, respectively. this involves dsn 9 $ change to voa, nl, mba and xha, so that voa file format change dsn 10 $ remaining changes apply to s10 version. dsn 11 $ 5. change extent for code file from .t10 to .mac. dsn 12 $ 6. correct miscellaneous bugs found in porting to dsn 13 $ rutgers. dsn 14 $ 7. change _ to $ in external names. dsn 15 $ 8. change code file extent from .t10 to .mac for t10. dsn 16 $ decks affected - macros, start, asmini, sdlnam, sdsnam, outcon. dsn 17 vaxa 1 vaxa 2 $ vaxa r. kenner 11-sep-79 level 79254 vaxa 3 $ vaxa 4 $ extend to support generation of code for dec vax-11/780 (s32). vaxa 5 $ source configured according to conditional assembly options. vaxa 6 $ t10 - set to produce t10 code for s10. vaxa 7 $ t32 - set to produce t32 code for s32. vaxa 8 $ hmeqtm - set if host and target machine are the same. vaxa 9 $ decks affected - most. vaxa 10 rkc 1 rkc 2 $ rkc r. kenner 10-sep-79 level 79253 rkc 3 $ rkc 4 $ fix bug (fr2.3.122) that caused miscompilation of some expressions rkc 5 $ involving .seq. and .sne. operators. rkc 6 $ deck affected - emitdop. rkc 7 rkb 1 rkb 2 $ rkb r. kenner 18-may-79 level 79138 rkb 3 $ rkb 4 $ fix bug (fr2.3.108) that was due to constants of size larger rkb 5 $ than cval field in ditems being considered short. resolve this rkb 6 $ by adding new parameter -scs- corresponding to size of cval field. rkb 7 $ also do not consider arguments to be eligible for permanent rkb 8 $ register allocation (this fixes fr2.3.109). rkb 9 rkb 10 $ decks affected - setup, assign. rkb 11 dsm 1 dsm 2 $ dsm d. shields 29 mar 79 level 79088 dsm 3 $ dsm 4 $ fix errors in s10, s37 field definitions (fr2.3.64, fr2.3.100). dsm 5 $ these involve mb_chain for s10, vv_vbeg for s10 and s37. dsm 6 $ deck affected - start. dsm 7 rka 1 rka 2 $ rka r. kenner 21 feb 79 level 79052 rka 3 $ rka 4 $ fix bug (fr2.3.97) in dsk code in emitsub which assumes that rka 5 $ all registers contain data. rka 6 $ fix bug (fr2.3.98) that had error count wrong in -aermey-. rka 7 $ decks affected - emitsub, aermey. rka 8 dsl 1 dsl 2 $ dsl d. shields 01 feb 79 level 79032 dsl 3 $ r. kenner dsl 4 $ dsl 5 $ 1. fix typo introduced by correction dsk. dsl 6 $ 2. fix error (fr2.3.89) caused by wrongly removing 'if' dsl 7 $ and 'ifnot' voa operations which branched to next operation. dsl 8 $ decks affected - labfix, emitdop. dsl 9 dsk 1 $ dsk d. shields 30 jan 79 level 79030 dsk 2 $ r. kenner dsk 3 $ dsk 4 $ 1. fix bug in setting drop status of temporaries (fr2.3.80). dsk 5 $ 2. add code to support .sne. op (fr2.3.82). dsk 6 $ 3. add option 'fag=0/1' which needs be set nonzero if dsk 7 $ functions may alter globals (this required for setl cod, lib dsk 8 $ phases). dsk 9 $ 4. fix error (fr2.3.87) that resulted in bad code if multi-word dsk 10 $ items compared in if statement. dsk 11 $ 5. increase table dimensions so can digest setl. dsk 12 $ 6. add field definitions for s32. dsk 13 $ decks affected - macros, start, asmini, setup, asmprog, emitdop, dsk 14 $ asmif, emitsub. dsk 15 dsj 7 dsj 8 $ dsj d. shields 27 dec 78 level 78361 dsj 9 $ dsj 10 $ 1. fix error (fr2.3.73) in emitsf that caused miscompilation dsj 11 $ of lex. dsj 12 $ 2. fix error (fr2.3.75) in sizing of last argument in dsj 13 $ calls to getvar in some cases. dsj 14 $ 3. expand operations aint, float, ifix, int (alias for ifix) dsj 15 $ in-line. this involves adding t10 opcodes ifr, rfi and rtr. dsj 16 $ 4. provide code to translate little -amod- to opcode rmo, as dsj 17 $ existing code was incomplete. dsj 18 $ decks affected - macros, start, asmprog, emitdop, emitun, emitsf. dsj 19 dsi 1 dsi 2 $ dsi d. shields 20 dec 78 level 78354 dsi 3 $ dsi 4 $ 1. supply missing argument in -baseprober- call (fr2.3.69). dsi 5 $ 2. supply missing argument in -ltlterm- call (fr2.3.70). dsi 6 $ decks affected - macros, asmexit. dsi 7 dsh 1 dsh 2 $ dsh d. shields 19 dec 78 level 78353 dsh 3 $ dsh 4 $ 1. fix error (fr2.3.67) in that too many args were dsh 5 $ passed to -cextmw-. dsh 6 $ 2. fix error (fr2.3.68) in specification of attributes dsh 7 $ of .e. assignment that caused fatal error in some cases. dsh 8 $ decks affected - asmprog, emitdop. dsh 9 dsg 1 dsg 2 $ dsg d. shields 14 dec 78 level 78349 dsg 3 $ r. kenner dsg 4 $ dsg 5 $ correct error (fr2.3.65) in translating assignment where dsg 6 $ neither lastdrop set due to bug in -mover-. dsg 7 $ deck affected - mover. dsg 8 dsf 1 dsf 2 $ dsf d. shields 12 dec 78 level 78346 dsf 3 $ dsf 4 $ fix error (fr2.3.63) that incorrectly declared -imo- to dsf 5 $ be commutative. dsf 6 $ deck affected - emitbin. dsf 7 dse 1 dse 2 $ dse d. shields 11 dec 78 level 78345 dse 3 $ r. kenner dse 4 $ dse 5 $ 1. improve allocation of dead registers. dse 6 $ 2. try once again to generate correct code for imt/idt (fr2.3.48) dse 7 $ 3. fix bad code for some binary i/o (fr2.3.47) dse 8 $ by moving -kill(dopir)- to correct place in asmprog. dse 9 $ 4. correct error (fr2.3.61) in compiling .e. 1+e,3,mw(i) = 0, dse 10 $ ie, .e. assign to indexed multiword where postion is expr. dse 11 $ decks affected - asmprog, emitdop, emitbin, aermey. dse 12 dsd 1 dsd 2 $ dsd d. shields 08 dec 78 level 78342 dsd 3 $ dsd 4 $ 1. respond to fr 2.3.53 (mistranslation of easimw in lib) by dsd 5 $ correcting code in -mover-. dsd 6 $ 2. provide field definitions for asmif -it- table for s10, s66. dsd 7 $ 3. correct conval test in asmfld (fr 2.3.60). dsd 8 $ decks affected - asmif, asmfld, mover. dsd 9 dsc 1 dsc 2 $ dsc d. shields 27 nov 78 level 78331 dsc 3 $ dsc 4 $ 1. fix incorrect generation of imt to correct op imti. dsc 5 $ 2. fix bug in emitbin which caused r-1 to be generated. dsc 6 $ 3. fix bug in b$num call due to bad data statement. dsc 7 $ decks affected - start, emitbin. dsc 8 dsb 1 dsb 2 $ dsb d. shields 25 sep 78 level 78268 dsb 3 $ dsb 4 $ 1. fix error which gave extra zero in label in dwa op. dsb 5 $ 2. correct wrong name 'nbit$m' to be 'bnum$m'. dsb 6 $ 3. change so dimltl not set by default, and so obtain dsb 7 $ full length arrays for production use. dsb 8 $ 4. add s10 fields for -mba-. dsb 9 $ decks affected - start, endsubr. dsb 10 dsa 5 dsa 6 $ dsa d. shields 23 jun 78 level 78174 dsa 7 $ dsa 8 $ 1. correct error in documentation of -mvw- op. dsa 9 $ 2. correct error in indexed multiword assignment that dsa 10 $ caused bad translation of ltldoc. dsa 11 $ decks affected - macros, asmxasi. dsa 12 3 4 $ (none) r. kenner 07 jun 78 level 78158 5 $ d. shields 6 $ 7 $ release initial version of dec-10 bootstrap compiler for 8 $ checkout at university of leeds. 9 $ little language level is 2.3; t10 target language level is 1.0. 10 $ decks affected - all. 11 12 1 .=member macros 2 3 .+set trace 4 .+set labopt 5 .+set ifopt 6 .+set defer 7 8 +* assemblerlevel = $ define level of code generator. pic 8 'asm(82244)' $ 01-sep-82 10 ** 11 dsvb 1 .+s32. dsvb 2 .+set s32v $ assume vms. dsvb 3 ..s32 dsvb 4 dsvb 5 .+s32u. dsvb 6 .+s32. dsvb 7 .-set s32v $ do not want vms. dsvb 8 .+set s32u $ want unix os. dsvb 9 ..s32 dsvb 10 .+set mcl $ want primary case to be lower. dsvb 11 ..s32u vaxa 12 .+s32. vaxa 13 .+set t32 dst 22 .+set enp $ support enp for s32 dsv 10 .+set t32h vaxa 14 ..s32 vaxa 15 vaxa 16 eaa 33 eaa 34 .+t20. $ if t20 initially set, select t10 (as t20 is extension of t10) eaa 35 .+set t10 eaa 36 ..t20 eaa 37 vaxa 17 .+s10. vaxa 18 .+set t10 vaxa 19 ..s10 vaxa 20 vaxa 21 vaxa 22 .-t32. vaxa 23 .+set t10 vaxa 24 ..t32 vaxa 25 vaxa 26 vaxa 27 .+t10. vaxa 28 .+s10. vaxa 29 .+set hmeqtm $ host machine = target machine vaxa 30 ..s10 vaxa 31 ..t10 vaxa 32 vaxa 33 vaxa 34 .+t32. vaxa 35 .+s32. vaxa 36 .+set hmeqtm dsq 36 .+set t32v $ get vms format by default vaxa 37 ..s32 vaxa 38 ..t32 vaxa 39 dsvb 12 .+s32u. dsq 38 .-set t32v $ disable vms format dsq 39 .+set t32u $ generate unix format t32 dsvb 13 ..s32u dsq 41 dsu 28 dsu 29 .+t32v. dsu 31 ..t32v dsu 32 vaxa 40 12 $ general macros. 13 14 +* ws = .ws. ** $ machine word size. 15 +* ps = .ps. ** $ machine pointer size. 16 +* cs = .cs. ** $ machine character size. 17 18 19 $ target machine parameters. vaxa 41 .+t10. 20 +* mws = 36 ** 21 +* mps = 18 ** dsp 26 +* mcs = 09 ** $ 9 bit version vaxa 42 +* msl = 18 ** vaxa 43 +* mso = 18 ** vaxa 44 ..t10 vaxa 45 eaa 38 .+t20 +* mps = 30 ** $ increase mps for extended addressing eaa 39 eaa 40 vaxa 46 vaxa 47 .+t32. vaxa 48 +* mws = 32 ** vaxa 49 +* mps = 30 ** vaxa 50 +* mcs = 8 ** vaxa 51 +* msl = 16 ** vaxa 52 +* mso = 16 ** vaxa 53 ..t32 vaxa 54 vaxa 55 23 +* mcpw = (mws/mcs) ** $ characters per word. 24 25 +* no = 0 ** $ logical false value. 26 +* yes = 1 ** $ logical true value. 27 28 +* namelen = 20 ** $ significant length of name. dsn 20 dsn 21 +* filenamelen = 20 ** $ lengt of file name. dsn 22 .+s32 +* filenamelen = 64 ** 29 dsn 23 $ getapp_len is length of actual parameter string (cf. lexini). dsn 24 +* getapp_len = 128 ** dsn 25 .+s32 +* getapp_len = 240 ** dsn 26 30 +* lstimelen = 30 ** $ length of lstime result. 31 32 +* slen = .len. ** $ length of self-defined string. 33 +* sorg = .f. .sl.+1, .so., ** $ origin of sds. 34 35 +* cpw = (.ws./.cs.) ** $ number of characters/word. 36 37 $ meta macros. 38 +* q3(a, b, c) = a b c ** 39 +* macdef(a) = q3(+, *a*, *) ** 40 +* macdrop(a) = macdef(a=) ** 41 +* defc(a) = macdef(a=zzya) ** 42 $ macros for -lcp- print package. 43 +* textl(s) = call textlr(s); ** $ print string. 44 +* charl(c) = call charlr(c); ** $ print character. 45 +* intl(i) = call intlr(i); ** $ print integer. 46 +* intlp(i, n) = call intlpr(i, n); ** $ print -i- in -n- cols. 47 +* hexlp(w, n) = call hexlpr(w, n); ** $ print -w- hex -n- cols. 48 +* tintl(s, i) = call tintlr(s, i); ** $ print string and int. 49 +* endl = call endlr; ** $ end current print line. 50 +* getlpos(n) = call contlpr(1, n); ** $ get current line pos. 51 +* setlpos(n) = call contlpr(2, n); ** $ set current line pos. 52 +* tabl(n) = call contlpr(4, n); ** $ tab to column -n-. 53 +* ejectl = call contlpr(5, 0); ** $ skip to new page. 54 +* ejectlp(n) = call contlpr(5, n); ** $ conditional eject. 55 +* listl(f) = call contlpr(26,f); ** $ set list file control. 56 +* terml(f) = call contlpr(27,f); ** $ set terminal file cntrl. 57 +* octl(i) = call octlr(i); ** $ print octal. 58 +* octlp(i, n) = call octlpr(i, n); ** $ print -i- in -n- cols. 59 60 $ values for io access codes. 61 +* access_get = 1 ** 62 +* access_put = 3 ** 63 +* access_read = 4 ** 64 +* access_write = 6 ** 65 $ file numbers. 66 +* voafile = 3 ** 67 +* codefile = 4 ** $ generated source code file (macro 10) 68 +* ocsfile = 5 ** $ string file for output code. dst 23 .+enp +* enpfile = 6 ** dst 24 .+enp +* enpmax = 500 ** $ max. num. of procedures 69 70 $ tmc-del macros give delimiters for output constants. dsn 27 .+t10 +* tmccdel = 1r" ** vaxa 57 .+t32 +* tmccdel = 1r" ** 72 +* tmcsdel = 1r" ** dsq 42 .+hmeqtm. dsq 43 +* tmcctab = 9 ** $ tab character (assuming ascii). dsq 44 ..hmeqtm dsq 45 $ tmcscom is string giving comment character. dsq 46 $ tmcsind is string giving 'indirection' character. dsq 47 $ tmcslit is string giving 'constant literal character'. dsq 48 dsq 49 +* tmcscom = ';' ** $ default comment character. dsq 50 +* tmcsind = '@' ** $ default indirection character. dsq 51 +* tmcslit = '#' ** $ default constant literal character. dsq 52 dsq 53 .+t32u. dsq 54 $ redefine codes for t32u assembler. dsq 55 +* tmcscom = '#' ** $ comment character dsq 56 +* tmcsind = '*' ** $ indirection character. dsq 57 +* tmcslit = '$' ** $ constant literal character. dsr 10 $ the s66 used to maintain source does not have grave dsr 11 $ accent, so use ascii code. dsr 12 +* tmccgra = 3b'140' ** $ grave accent (ascii octal 140) dsq 58 ..t32u 73 74 $ mneg computes two complement value of negative offset. vaxa 58 +* mneg(x) = vaxa 59 .+t10 (3b'1000000' - (x)) vaxa 60 .+t32. vaxa 61 .+hmeqtm (-(x)) vaxa 62 .-hmeqtm (4b'100000000' - (x)) vaxa 63 ..t32 vaxa 64 ** 76 77 $ dimensions of tables. 78 79 $ select dimltl for small, test dimensions. 81 .-dimltl. dso 10 +* hadim = 937 ** 83 +* mbadim = 63 ** 84 +* namesdim = 800 ** 85 +* valdim = 1100 ** 86 +* voadim = 1850 ** 87 +* xargdim = 511 ** 88 89 +* dopsdim = 32 ** dsk 17 +* ditemdim = 90 ** dsk 18 +* dworddim = 220 ** dsk 19 +* dregdim = 220 ** 93 +* lablistdim = 400 ** dsk 20 +* pdlistdim = 500 ** 95 +* pcaradim = 6 ** 96 ..dimltl 97 98 .+dimltl. dso 11 +* hadim = 937 ** 100 +* mbadim = 63 ** 101 +* namesdim = 300 ** 102 +* valdim = 400 ** 103 +* voadim = 500 ** 104 +* xargdim = 200 ** 105 106 +* dopsdim = 32 ** 107 +* ditemdim = 40 ** 108 +* dworddim = 50 ** 109 +* dregdim = 50 ** 110 +* lablistdim = 100 ** 111 +* pdlistdim = 200 ** 112 +* pcaradim = 6 ** 113 ..dimltl 114 115 116 $ register numbers. 117 118 $ the following macros encode register numbers. the dec-10 119 $ contains 16 accumulators. this asm only uses some of the 120 $ registers, in the range r0 to rhi. the asm also requires 121 $ a 'spare' register, assumed to be rhi+1. the spare register 122 $ is used to construct parameter lists and to store values in 123 $ some situations. 124 vaxa 65 .+t10. 125 +* r0 = 1 ** $ first register, used for function value. 126 +* r1 = 2 ** $ first assignable register. 127 +* rlo = r1 ** $ first assignable register (ac 1). 128 +* rhi = 12 ** $ last assignable register (ac 11). 129 +* parmreg = rhi ** $ contains parameter list address. 130 +* sparereg = (rhi+1) ** $ spare register. 131 +* rhihi = 16 ** $ last machine register (ac 15). vaxa 66 ..t10 vaxa 67 vaxa 68 vaxa 69 .+t32. vaxa 70 +* r0 = 1 ** $ first register, used for function value. vaxa 71 +* r2 = 3 ** $ first assignable register. vaxa 72 +* rlo = r2 ** $ first assignable register vaxa 73 +* rhi = 12 ** $ last assignable register vaxa 74 +* parmreg = 13 ** $ contains parameter list address. vaxa 75 +* sparereg = 2 ** $ spare register. vaxa 76 +* rhihi = 16 ** $ last machine register vaxa 77 ..t32 132 133 $ machine block types. 134 135 +* bl_abs = 0 ** $ absolute block. 136 +* bl_imm = 1 ** $ immediate constant block. 137 +* bl_base = 2 ** $ base block. 138 +* bl_const = 3 ** $ constant block. 139 +* bl_temp = 4 ** $ temporary block. 140 +* bl_local = 8 ** $ local variable blokck. 141 +* bl_global = 10 ** $ first global block. 142 143 +* num_bl = 4 ** $ number of special blocks. 144 145 $ -voa- operations. 146 147 +* vo_add = 1 ** +* vo_xload = 31 ** 148 +* vo_sub = 2 ** +* vo_xasin = 32 ** 149 +* vo_gt = 3 ** +* vo_xfasin = 33 ** 150 +* vo_lt = 4 ** +* vo_ifnot = 34 ** 151 +* vo_ge = 5 ** +* vo_ccat = 35 ** 152 +* vo_le = 6 ** +* vo_in = 36 ** 153 +* vo_eq = 7 ** +* vo_eext = 37 ** 154 +* vo_ne = 8 ** +* vo_sext = 38 ** 155 +* vo_mul = 9 ** +* vo_easin = 39 ** 156 +* vo_div = 10 ** +* vo_sasin = 40 ** 157 +* vo_or = 11 ** +* vo_xeasin = 41 ** 158 +* vo_seq = 12 ** +* vo_xsasin = 42 ** 159 +* vo_and = 13 ** +* vo_radd = 43 ** 160 +* vo_exor = 14 ** +* vo_rsub = 44 ** 161 +* vo_sne = 15 ** +* vo_rgt = 45 ** 162 +* vo_nb = 16 ** +* vo_rlt = 46 ** 163 +* vo_fb = 17 ** +* vo_rge = 47 ** 164 +* vo_not = 18 ** +* vo_rle = 48 ** 165 +* vo_fcall = 19 ** +* vo_req = 49 ** 166 +* vo_scall = 20 ** +* vo_rne = 50 ** 167 +* vo_asin = 21 ** +* vo_rmul = 51 ** 168 +* vo_data = 22 ** +* vo_rdiv = 52 ** 169 +* vo_fasin = 23 ** +* vo_rusub = 53 ** dsj 21 +* vo_float = 54 ** dsj 22 +* vo_ifix = 55 ** 170 +* vo_io = 24 ** +* vo_abs = 56 ** 171 +* vo_return = 25 ** +* vo_iabs = 57 ** dsj 23 +* vo_aint = 58 ** dsj 24 +* vo_int = 59 ** dsj 25 +* vo_amod = 60 ** 172 +* vo_fext = 26 ** +* vo_mod = 61 ** 173 +* vo_if = 27 ** +* vo_sign = 62 ** 174 +* vo_lab = 28 ** +* vo_isign = 63 ** 175 +* vo_goto = 29 ** +* vo_dim = 64 ** 176 +* vo_goby = 30 ** +* vo_idim = 65 ** 177 178 +* num_vo = 65 ** $ number of operations. 179 180 $ deferred operation codes. 181 182 .=zzyorg a 183 $ deferred operation codes 184 185 .=zzyorg a 186 defc(do_add) 187 defc(do_sub) 188 defc(do_lt) 189 defc(do_ge) 190 defc(do_eq) 191 defc(do_ne) 192 defc(do_mul) 193 defc(do_div) 194 defc(do_and) 195 defc(do_or) 196 defc(do_exor) 197 defc(do_fcall) 198 defc(do_nb) 199 defc(do_not) 200 defc(do_fb) 201 defc(do_scall) 202 defc(do_asin) 203 defc(do_fasin) 204 defc(do_return) 205 defc(do_fext) 206 defc(do_if) 207 defc(do_goto) 208 defc(do_xload) 209 defc(do_xasin) 210 defc(do_xfasin) 211 defc(do_ifnot) 212 defc(do_eext) 213 defc(do_easin) 214 defc(do_xeasin) 215 defc(do_xsasin) 216 defc(do_radd) 217 defc(do_rsub) 218 defc(do_rlt) 219 defc(do_rge) 220 defc(do_req) 221 defc(do_rne) 222 defc(do_rmul) 223 defc(do_rdiv) 224 defc(do_rusub) 225 defc(do_abs) dsj 26 defc(do_float) dsj 27 defc(do_ifix) dsj 28 defc(do_aint) dsj 29 defc(do_amod) 226 defc(do_iabs) 227 defc(do_mod) 228 defc(do_sign) 229 defc(do_isign) 230 defc(do_dim) 231 defc(do_idim) 232 defc(do_seq) 233 defc(do_sne) 234 defc(do_goby) 235 236 +* num_do = do_goby ** $ number of dops. 237 238 $ assembler operations. 239 240 .=zzyorg a 241 242 defc(ao_ban) 243 defc(ao_bor) 244 defc(ao_bxo) 245 defc(ao_idi) 246 defc(ao_idt) 247 defc(ao_ieq) 248 defc(ao_ige) 249 defc(ao_igt) 250 defc(ao_ile) 251 defc(ao_ilt) 252 defc(ao_imu) 253 defc(ao_imt) 254 defc(ao_isi) 255 defc(ao_ine) 256 defc(ao_isu) 257 defc(ao_iad) 258 defc(ao_imo) 259 defc(ao_rmo) 260 defc(ao_rad) 261 defc(ao_rdi) 262 defc(ao_req) 263 defc(ao_rge) 264 defc(ao_rgt) 265 defc(ao_rle) 266 defc(ao_rlt) 267 defc(ao_rmu) 268 defc(ao_rne) 269 defc(ao_rsi) 270 defc(ao_rsu) 271 defc(ao_bfb) 272 defc(ao_bnb) 273 defc(ao_bno) 274 defc(ao_iab) 275 defc(ao_iao) 276 defc(ao_ico) dsj 30 defc(ao_ifr) 277 defc(ao_iso) 278 defc(ao_rab) 279 defc(ao_rco) dsj 31 defc(ao_rfi) dsj 32 defc(ao_rtr) 280 defc(ao_ldf) 281 defc(ao_lpr) 282 defc(ao_cal) 283 defc(ao_mvw) 284 defc(ao_zeb) 285 defc(ao_stf) 286 defc(ao_spr) 287 288 +* ao_fbo = ao_ban ** $ first binary op 289 +* ao_lbo = ao_rsu ** $ last binary op 290 +* ao_fuo = ao_bfb ** $ first unary op 291 +* ao_luo = ao_lpr ** $ last unary op vaxa 78 +* num_ao = ao_spr ** $ number of ao operators 293 294 295 $ machine operation codes (listed in alphabetical order) 296 297 .=zzyorg a 298 299 defc(mo_ban) 300 defc(mo_bfb) 301 defc(mo_bnb) 302 defc(mo_bno) 303 defc(mo_bor) 304 defc(mo_bxo) 305 defc(mo_cal) 306 defc(mo_ceq) 307 defc(mo_cge) 308 defc(mo_cgt) 309 defc(mo_cle) 310 defc(mo_clt) 311 defc(mo_cne) 312 defc(mo_iab) 313 defc(mo_iad) 314 defc(mo_iao) 315 defc(mo_ico) 316 defc(mo_idi) 317 defc(mo_idt) 318 defc(mo_ieq) dsj 33 defc(mo_ifr) 319 defc(mo_ige) 320 defc(mo_igt) 321 defc(mo_ile) 322 defc(mo_ilt) 323 defc(mo_imo) 324 defc(mo_imt) 325 defc(mo_imu) 326 defc(mo_ine) 327 defc(mo_isi) 328 defc(mo_iso) 329 defc(mo_isu) 330 defc(mo_jeq) 331 defc(mo_jge) 332 defc(mo_jgt) 333 defc(mo_jle) 334 defc(mo_jlt) 335 defc(mo_jmn) 336 defc(mo_jmp) 337 defc(mo_jne) 338 defc(mo_lda) 339 defc(mo_ldf) 340 defc(mo_ldl) 341 defc(mo_ldr) 342 defc(mo_ldw) eaa 41 .+t20 defc(mo_lla) 343 defc(mo_lpr) 344 defc(mo_mvw) dsu 33 defc(mo_mvx) 345 defc(mo_rab) 346 defc(mo_rad) 347 defc(mo_rco) 348 defc(mo_rdi) 349 defc(mo_req) 350 defc(mo_ret) dsj 34 defc(mo_rfi) 351 defc(mo_rge) 352 defc(mo_rgt) 353 defc(mo_rle) 354 defc(mo_rlt) 355 defc(mo_rmo) 356 defc(mo_rmu) 357 defc(mo_rne) 358 defc(mo_rsi) 359 defc(mo_rsu) dsj 35 defc(mo_rtr) 360 defc(mo_spr) 361 defc(mo_stf) 362 defc(mo_stl) vaxa 79 .+t32 +* mo_xjm = mo_str ** $ add new opcode for t32. 363 defc(mo_str) 364 defc(mo_stw) 365 defc(mo_zeb) eaa 42 .+t20 defc(mo_hba) eaa 43 .+t20 defc(mo_hbb) eaa 44 .+t20 defc(mo_hbc) 366 defc(mo_zew) 367 368 +* num_mo = mo_zew ** $ number of mo ops 369 370 371 372 $ mop attributes are given by following macros and fields. 373 +* moaimm(mop) = moa_imm moatab(mop) ** $ is immediate ok. 374 +* moaicb(mop) = mob_icb moatab(mop) ** $ basic instruction cod 375 +* moaici(mop) = moa_ici moatab(mop) ** $ immediate instr. code. 376 +* moaiwc(mop) = moa_iwc moatab(mop) ** $ instr. word count. 377 378 +* moa_imm = .f. 01, 1, ** $ on if immediate mode allowed. 379 +* moa_ici = .f. 04, 9, ** $ opcode if moa_imm set. 380 +* moa_icb = .f. 13, 9, ** $ basic instruction code. 381 +* moa_iwc = .f. 22, 3, ** $ instruction word count. 382 383 384 $ the following branch masks are used to select various types 385 $ of conditional branches. they are three bits long. each 386 $ bit means branch on <0, =0, or >0. therefore, all bits being 387 $ set is an unconditional branch. therefore, to negate a branch 388 $ mask, it must just be exclusive or'ed with the unconditional 389 $ mask. an extra branch mask is used to indicate the mask for 390 $ the 'testchar' test when the bits are on. 391 $ [these codes used in asmif, branchr.] 392 393 +* bm_zer = 1b'100' ** $ branch on zero. 394 +* bm_neg = 1b'010' ** $ branch on less than zero. 395 +* bm_pos = 1b'001' ** $ branch on greater than zero. 396 +* bm_all = 1b'111' ** $ unconditional branch. 397 398 +* binv(bm) = (bm .ex. bm_all) ** $ inverse branch mask. 399 400 +* bmswap(bm, t) = $ swap branch mask. 401 $ this is used when one wants to reverse the operands of 402 $ a comparison. it changes the positive and negative bits. 403 $ -bm- is the output and input mask and -t- is a temporary. 404 t = bm; .f. 1, 1, t = .f. 2, 1, bm; 405 .f. 2, 1, t = .f. 1, 1, bm; bm = t; 406 ** 407 408 409 $ these macros are used to emit -asm- instructions to be 410 $ converted into dec-10 machine code. they are split up into 411 $ various types and each has its own macro. the operations 412 $ of that type all call that macro. note that not all 413 $ operations have macros because only those that are issue 414 $ explicitly (i.e., not from a table) have macros defined. 415 416 417 $ these macros are for the conditional operations. the first 418 $ parameter after the op-code is the dummy register to be tested 419 $ and the second parameter is the label to branch to if the 420 $ test is true. 421 422 +* if_op(op, in, lab) = call emitif(op, in, lab); ** 423 424 +* ifspos_op(in, lab) = $ branch to -lab- if -in- is >0. 425 if_op(bm_pos, in, lab) ** 426 427 +* ifpos_op(in, lab) = $ branch to -lab- if -in- is >=0. 428 if_op(binv(bm_neg), in, lab) ** 429 430 +* goto_op(lab) = $ unconditional branch to -lab-. 431 branchop(bm_all, r0, lab) ** $ unconditional branch. 432 433 434 $ these next macros are for the long operations. these 435 $ operations are storage-storage operations. the first 436 $ parameter after the op-code is the address of the destination, 437 $ the second is the address of the target, and the last is the 438 $ length in words. the addresses are obtained via the -getaddr- 439 $ macro. 440 441 +* long_op(op, or, ir, l) = 442 call emitlong(op, or, ir, l); ** 443 444 +* smove_op(or, ir, l) = $ move from input to output. 445 long_op(ao_mvw, or, ir, l); ** 446 447 +* clear_op(r, l) = $ clear to zero. 448 long_op(ao_zeb, r, r, l); ** 449 450 $ the clear op clears nw words of memory. 451 452 453 $ these macros are for unary operators. the first parameter 454 $ after the op-code is the output and the last parameter is the 455 $ input operand. 456 457 +* un_op(op, or, ir) = call emitun(op, or, ir); ** 458 459 +* not_op(or, ir) = $ negate (not complement) register. 460 un_op(ao_bno, or, ir) ** 461 462 +* neg_op(or, ir) = $ complement register (0-r). 463 un_op(ao_ico, or, ir) ** 464 465 +* add1_op(or, ir) = $ add one to a register. 466 un_op(ao_iao, or, ir) ** 467 468 +* sub1_op(or, ir) = $ subtract one from a register. 469 un_op(ao_iso, or, ir) ** 470 471 $ the lpr and spr ops retrieve/store parts of registers. 472 $ lpr loads from ir to or, spr stores from or to ir, ie 473 $ lpr_op(r1,r2,c1,c2) <-> r1 = .f. c1+1, c2, r1 474 $ spr_op(r1,r2,c1,c2) <-> .f. c1+1, c2, r2 = r1 475 476 +* lpr_op(or, ir, fo, fl) = $ load part of word. 477 emopparm1 = fo; emopparm2 = fl; $ set extra parms. 478 un_op(ao_lpr, or, ir) ** $ do as unary op. 479 480 +* ldf_op(or, ir) = $ load -or- as pointed to by byte -ir-. 481 un_op(ao_ldf, or, ir) ** $ do as unary op. 482 483 $ macros for part word store operations. 484 485 +* sfld_op(op, ir, tr) = $ store -ir- into -tr- 486 call emitsfld(op, ir, tr); ** 487 488 +* spr_op(ir, tr, fo, fl) = $ store part of word. 489 emopparm1 = fo; emopparm2 = fl; $ set extra parms. 490 sfld_op(ao_spr, ir, tr) ** $ do operation 491 492 +* stf_op(ir, tr) = $ store -ir- in byte pointed to by -tr-. 493 sfld_op(ao_stf, ir, tr) ** $ do operation 494 495 496 $ these macros are for the subroutine handling operations 497 $ such as call. 498 499 +* call_op = call emitsub; ** 500 501 502 $ these macros are used to emit binary operations. the first 503 $ parameter after the op-code is the output and the last two 504 $ parameters are the inputs. 505 506 +* bin_op(op, out, in1, in2) = call emitbin(op, out, in1, in2);** 507 508 +* and_op(out, in1, in2) = $ logical -and- 509 bin_op(ao_ban, out, in1, in2) ** 510 511 +* or_op(out, in1, in2) = $ logical -or- 512 bin_op(ao_bor, out, in1, in2) ** 513 514 +* exor_op(out, in1, in2) = $ logical exclusive -or-. 515 bin_op(ao_bxo, out, in1, in2) ** 516 517 +* add_op(out, in1, in2) = $ addition. 518 bin_op(ao_iad, out, in1, in2) ** 519 520 +* sub_op(out, in1, in2) = $ subtraction. 521 bin_op(ao_isu, out, in1, in2) ** 522 523 +* mul_op(out, in1, in2) = $ multiplication 524 bin_op(ao_imu, out, in1, in2) ** 525 526 +* div_op(out, in1, in2) = $ division 527 bin_op(ao_idi, out, in1, in2) ** 528 529 +* mul2_op(out, in1, in2) = $ multiplication by power of two 530 bin_op(ao_imt, out, in1, in2) ** 531 532 +* div2_op(out, in1, in2) = $ division by power of two 533 bin_op(ao_idt, out, in1, in2) ** 534 535 +* mod_op(out, in1, in2) = $ mod 536 bin_op(ao_imo, out, in1, in2) ** 537 538 539 $ the next operation compares two inputs and branches 540 $ with a specified condition to a label. 541 +* cmp_op(bm, in1, in2, lab) = 542 call emitcmp(bm, in1, in2, lab); ** 543 544 545 $ macro to assign dummy resister to -voa- operand 546 547 $ the -assign- macro has two operands. the first rs the 548 $ variable to receive the dummy register number and the 549 $ second is the encoded -voa- operand to obtain. the 550 $ encodings follow. 551 552 +* va_spec = 1 ** $ special value. use -voaep- as pointer. 553 +* va_fnct = 2 ** $ function return (voap=1) 554 +* va_inp1 = 3 ** $ input one of current operation 555 +* va_inp2 = 4 ** $ input two 556 +* va_inp3 = 5 ** $ input three 557 +* va_inp4 = 6 ** $ input four 558 +* va_oup = 7 ** $ output 559 +* va_xarg = 8 ** $ values above this indicate that arguments 560 $ come from the -xarg- entries pointed to by 561 $ the current operation. the difference 562 $ between the value and -va_xarg- is the 563 $ number of the desired parameter. 564 565 566 +* assign(reg, type) = 567 call assignr(type); $ call routine to get register. 568 reg = assignreg; ** $ copy assigned value. 569 570 571 572 $ macro to assign dummy register to constant. 573 574 $ the -assignconst- macro has two operands. the first is set 575 $ to the number of the dummy register assigned. the second 576 $ operand is the constant to be assigned to the register. 577 $ the flag -asconstspc- is used internally to alter the meaning 578 $ of the second operand. see routines -assignr- and -asconst- 579 $ for meaning of this usage. 580 581 +* assignconst(reg, const) = $ assign register to constant. 582 call asconst(const); $ pass constant to routine. 583 reg = asconstreg; ** $ get return value. 584 585 586 $ macro to get free dummy register. 587 588 $ the -getdreg- macro gets a dummy register to use as a 589 $ temporary result. it is set up as a one word variable 590 $ with standard form, offset, etc. this variable is set to 591 $ temporary type and, when actually used as core reference, 592 $ will be allocated to an actual temporary location, if needed. 593 594 +* getdreg(reg) = $ get dummy register. 595 call getdregr(reg); ** $ call routine. 596 597 598 $ macro to clear dummy register. 599 600 $ the -clear- macro resets the status of a dummy register so 601 $ that it can be assigned to. this involves dropping any 602 $ alternate forms and/or deferred operations from the previous 603 $ value of the register. 604 605 +* clear(reg) = call clearr(reg); ** $ call routine. 606 607 608 609 $ -getdesc- macro. 610 611 $ the -getdesc- macro gets a description of the variable 612 $ given to it. the description is given by three items. the 613 614 +* getdesc(dr, typ, ind, reg, off) = 615 call getdescr(dr, typ, ind, reg, off); ** $ call routine. 616 617 618 619 $ -getvar- macro 620 621 $ the -getvar- macro is similar to the -getdesc- macro in its 622 $ parameters. the difference is that -getvar- can be used oto 623 $ put the variable into the desired type of register. it 624 $ should be called when the type is anything other than 625 $ -gd_addr-. 626 627 +* getvar(dr, typ, mode, reg, off) = 628 call getvarr(dr, typ, mode, reg, off); ** 629 630 631 $ types for -getdesc- and -getvar- 632 633 +* gd_addr = 1 ** $ just get address pointer. 634 +* gd_use = 2 ** $ want to use variable as general. 635 +* gd_reg = 3 ** $ force into register. 636 +* gd_intoreg = 4 ** $ want to load into specific register. 637 +* gd_inregnu = 5 ** $ want to load specific register, no upd. 638 639 +* num_gd = 5 ** $ number of types. 640 641 $ macro -countup-. 642 643 $ increment a pointer to an array and 644 $ to test for array overflow. 645 646 +* countup(p, max, name) = 647 p = p+1; $ increment pointer. 648 if (p > max) call countupr(name); $ error. 649 ** 650 651 $ macro -lastuse-. 652 653 $ this macro is used to indicate that the next action done 654 $ by a generator on a dummy register will be its last. 655 656 +* lastuse(reg) = 657 di_luse ditem(dr_item dreg(reg)) = $ increment. 658 di_luse ditem(dr_item dreg(reg)) + 1; 659 ** 660 661 662 663 $ macro -sdsname-. 664 665 $ this macro returns an sds containing the name of the item 666 $ whose -ha- pointer is given. (it must be a variable or 667 $ routine name.) 668 $ sdsname is used for names to appear in generated code file, 669 $ so that long names are truncated to six characters. 670 671 +* sdsname(str, ptr) = 672 call sdsnamr(str, ptr); $ call routine. 673 ** 674 675 $ macro -sdlname-. 676 677 $ this macro returns an sds containing the name of the item 678 $ whose -ha- pointer is given. (it must be a variable or 679 $ routine name.) 680 681 +* sdlname(str, ptr) = 682 call sdlnamr(str, ptr); $ call routine. 683 ** 684 685 686 .+defer. 687 $ -using- macro. 688 689 $ the -using- macro is used to indicate that an operand of 690 $ a previous deferred operation is going to be used even 691 $ though the operation may be freed. this is needed to 692 $ keep track of the count fields. 693 694 +* using(dr) = $ will use this register. 695 di_count ditem(dr_item dreg(dr)) = $ increment count. 696 di_count ditem(dr_item dreg(dr)) + 1; 697 ** 698 ..defer 699 700 701 702 $ thdse are access macros for various fields in -ditem-. 703 $ they enable them to be accessed from the -dreg- pointer. 704 705 +* accss(fld, dr) = fld ditem(dr_item dreg(dr)) ** 706 707 +* nwords(dr) = accss(di_nwords, dr) ** 708 709 +* syze(dr) = accss(di_syze, dr) ** 710 711 +* conval(dr) = accss(di_cval, dr) ** 712 713 .+defer +* dout(dr) = accss(di_out, dr) ** 714 715 +* isreal(dr) = accss(di_real, dr) ** 716 717 +* ismw(dr) = accss(di_mw, dr) ** 718 719 +* isvar(dr) = accss(di_var, dr) ** 720 721 +* istemp(dr) = accss(di_temp, dr) ** 722 723 +* isconst(dr) = accss(di_const, dr) ** 724 725 +* isscon(dr) = accss(di_scon, dr) ** 726 727 +* isind(dr) = (accss(di_anum, dr) ^= 0) ** 728 729 730 731 $ macro -getwordc-. 732 733 $ this macro is called by a set of macros to address words or 734 $ parts of words. the first parameter of these macros is 735 $ the 'output' register, the second is the 'input' register, 736 $ the third is the word of character offst of the word or 737 $ character desired, and the fourth is the -dreg- number of an 738 $ optional index register. 739 740 $ ****** important note ****** 741 $ [ds 11 apr ds will see kenner about this important note 742 $ and report back to mccann.] 743 $ the -getaddr- and -getword- calls return a form of 744 $ the input when there is no index. thus if the argument 745 $ is slated to be dropped, things will blow up. the solution 746 $ is not to drop the argument unless there is an index. 747 $ if ind is zero, then dritem(out) is same as dritem(in); 748 $ otherwise, a 'special' temporary is built. hennce can 749 $ cannot do lastuse(out) unless you mean lastuse(in) also. 750 +* getwordc(type, out, in, off, ind) = $ first parm. is type. 751 call getwordr(out, in, type, off, ind); ** $ call routine. 752 753 754 $ types for -getwordc-. 755 756 +* gw_word = 01 ** $ get word value. 757 +* gw_addr = 02 ** $ get word address. 758 +* gw_sword = 03 ** $ store word. 759 760 +* num_gw = 3 ** 761 762 +* getword(out, in, off, ind) = 763 getwordc(gw_word, out, in, off, ind) ** 764 +* getaddr(out, in, off, ind) = 765 getwordc(gw_addr, out, in, off, ind) ** 766 +* storeword(out, in, off, ind) = 767 getwordc(gw_sword, out, in, off, ind) ** 768 769 770 $ macro -branchop-. 771 772 $ this macro is used to generate a branch to a desired label. 773 $ the first parameter is the hardware condition code mask to 774 $ use for the branch and the second parameter is the label 775 $ number. 776 777 +* branchop(m, reg, lab) = call branchr(m, reg, lab); ** 778 779 780 $ macros for emitting machine operations. 781 782 +* emop(op, oreg, imode, ireg, ioff) = $ emit basic machine op. 783 call emopr(op, oreg, imode, ireg, ioff); ** 784 785 786 $ -move_op- macro. 787 788 $ this macro is used to move the contents of one dummy register 789 $ to another. the first operand is the output register and the 790 $ second is the input rwegister. 791 792 +* move_op(out, in) = call mover(out, in); ** 793 794 795 796 $ -inzero- macro. 797 798 $ the macro is called to indicate that a value is present in 799 $ machine register zero. if the second operand is yes, the 800 $ address of the operand (assumed multi-word) is in reg zero. 801 802 +* inzero(dr, fl) = call inzeror(dr, fl); ** 803 804 805 $ the mrcopy macros is used to copy one register to another. 806 +* mrcopy(a,b) = $ copy reg b to reg a. 807 if a^=b then $ copy only if regs differ. 808 emop(mo_ldw, a, am_reg, b, 0); 809 end if; ** 810 811 $ the mrclear macro clears a register. 812 +* mrclear(a) = emop(mo_zew, a, am_reg, a, 0); ** 813 814 $ -forcezero- macro. 815 816 $ this macro is used to force a variable into register zero,. 817 $ it is used in some function returns and for some special 818 $ calling sequences. the first parameter is the variable and 819 $ the second is a flag which is set if the address of the 820 $ variable is what is wanted in register zero. 821 822 +* forcezero(dr, fl) = call forcer(dr, fl); ** 823 824 dss 14 +* labcol = 3 ** $ columns for label dss 15 .+t32u +* labcol = 5 ** 825 826 $ -labfree- macro. 827 828 $ this macro is used to release a label that was used 829 $ temporarily in a local fashion. 830 831 +* labfree(l) = $ free a label. 832 ; ** 833 834 835 836 $ -labget- macro. 837 838 $ this macro gets a temporary label for local use. 839 840 +* labget(l) = $ get a temporary label. 841 842 countup(labluse, lablistdim, 'lablist'); 843 l = labluse; $ set to gotten label. 844 lablist(l) = 0; $ clear label list entry. 845 ** 846 847 848 849 $ -labdef- macro. 850 851 $ this macro is used to define the position of a label. the 852 $ first operand is the label number and the second operand is a 853 $ flag which is off when the label is only being used for 854 $ internal local purposes. 855 856 +* labdef(l, f) = call labdefr(l, f); ** 857 858 859 $ -store- macro. 860 861 $ this macro is used to store the live data in the machine 862 $ register given by its first parameter into the dummy register 863 $ location indicated by its second parameter. status values 864 $ are reset appropriately. 865 $ see dropr, getwordr, storall, emitlong, emitsub, getdregr, 866 $ endsubr 867 868 +* store(mr, dr) = call storer(mr, dr); ** 869 870 871 872 $ -getreg- macro. 873 874 $ this macro is used to obtain a register of a desired type. 875 $ the first parameter will contain the register obtained and 876 $ the second parameter is the type. 877 $ if no registers of 878 $ that type or lower are available, a value of zero will be 879 $ given for the register. specifying the type as a 'live' 880 $ type will ensure that a register will always be obtained. 881 882 +* getreg(mr, typ) = call getregr(typ); mr = gotreg;** 883 884 885 886 $ -lastdrop- macro. 887 888 $ this macro sees if this is last use of dummy register. 889 890 +* lastdrop(dr) = 891 ( (di_count ditem(dr_item dreg(dr))=1 892 & di_ldrop ditem(dr_item dreg(dr)) 893 & di_luse ditem(dr_item dreg(dr)) ^= 0) 894 ! ismw(dr) ! isscon(dr) ) ** 895 896 897 $ -dropform- macro. 898 899 $ this macro is used to drop a dummy register. 900 901 +* dropform(dr) = 902 if (dr_reg dreg(dr)) reglis(dr_reg dreg(dr)) = 0; 903 904 $ put this dummy register onto free list. 905 dreg(dr) = 0; $ clear out all status info. 906 dr_next dreg(dr) = dregfree; $ chain to rest of free list. 907 dregfree = dr; $ put onto free list. 908 ** 909 910 911 912 $ -drop- macro. 913 914 $ this macro is used to drop an entire dummy register. it 915 $ drops all the forms in the chain and also, if there is one, 916 $ any deferred operations that this is the output of. 917 918 +* drop(dr) = 919 if (di_luse ditem(dr_item dreg(dr)) ^= 0) $ can drop. 920 call dropr(dr); $ call routine to drop. 921 ** 922 923 924 925 $ -kill- macro. 926 927 $ this macro is the same as -drop- except that it does not 928 $ require that the generator have dropped the register. it 929 $ is used in place of -lastuse-, -drop- sequences. 930 931 +* kill(dr) = call dropr(dr); ** 932 933 934 935 .+defer. 936 $ -dropdop- macro. 937 938 $ this macro drops a deferred operation. it will also drop any 939 $ registers that are inputs to that operation. 940 941 +* dropdop(dop) = dropdopflg = yes; call dropr(dop); ** 942 ..defer 943 944 945 946 .+eab. $ put off until after bootstrap, no need for pairs now. 947 $ -getregpair- macro. 948 949 $ this macro is used to return a free even/odd pair of 950 $ registers. the even register is returned in the first 951 $ parameter. the other two parameters are registers that can 952 $ be used in the pair. both registers are freed and on hold 953 $ when returned and if either of the two registers matched one 954 $ of the registers that it was indicated can be used, that 955 $ register is dropped. note that no check is made for live 956 $ variable. this check is assumed to have been made previously. 957 958 +* getregpair(r, u1, u2) = $ get register pair. 959 call getrpair(u1, u2); 960 r = gotrpair; ** 961 ..eab 962 963 964 $ -error- macro. 965 966 $ this macro is used by -outdata- to print error messages. 967 $ the first parameter is the error text and the second is the 968 $ -voa- pointer of the item referred to. 969 970 $ first, define error headings. 971 +* error_notice = ' ****error**** ' ** 972 +* system_notice = '*system error* ' ** 973 974 +* error(msg, ptr) = 975 terml(yes) textl(error_notice) textl(msg) 976 textl('. item = ') sdsname(dopsname, vv_naym voa(ptr)) 977 textl(dopsname) endl terml(no) 978 errno = errno+1; 979 ** 980 981 $ macro -baseprobe-. 982 983 $ these macros manipulate the base block. they will search 984 $ for an item in the base block and will put it there if it 985 $ is not already. 986 987 $ types for -baseprober-. 988 989 +* rp_normal = 1 ** $ normal search. 990 +* rp_addlab = 2 ** $ add to table with no search. 991 +* rp_nocomp = 3 ** $ no compare 992 +* rp_addbas = rp_addlab ** 993 $ [ds 3 may addbas renamed addlab from s37 to s11.] 994 995 $ define codes for arrays to use for comparisons so that 996 $ the array need not be passed as a parameter. 997 +* ar_val = 1 ** $ constant value array. 998 +* ar_plist = 2 ** $ parameter array. 1000 1001 +* baseprobe(ptr, hcode, len, type, arrayp, array, arrmx) = 1002 rparrmx = arrmx; $ set global. 1003 call baseprober(rp_normal, ptr, hcode, len, type, arrayp, 1004 array); arrmx = rparrmx; ** $ call and reset global. 1005 1006 +* baseprobelab(ptr, addr) = 1007 call baseprober(rp_addlab, ptr, 0, 0, addr, 0, 0); ** 1008 1009 +* baseprobenc(ptr, len, type, arrayp) = $ probe no compare dsi 9 call baseprober(rp_nocomp, ptr, 0, len, type, arrayp ,0); ** 1011 1012 1013 1014 +* rztok = 12 ** 1015 +* qstok = 6 ** 1016 +* sstok = 5 ** 1017 +* dectok = 4 ** $ integer 1018 +* bittok = 8 ** $ bit 1019 +* realtok = 14 ** $ real 1020 +* strtok = 6 ** 1021 1022 +* num_lt = 14 ** $ number of lexical types. 1023 1024 +* szmax = 2048 ** $ maximum size. 1025 1026 $ addressing modes 1027 +* am_reg = 0 ** $ ea is register number. 1028 +* am_rel = 1 ** $ ea is offset from index register 1029 +* am_mem = 2 ** $ ea is memory address. 1030 +* am_reli = 3 ** $ ea is indirect from offset in register 1031 +* num_am = 3 ** $ number of am modes. 1032 1033 $ fields of machine offste vaxa 80 .+t10. 1034 +* mosize = 36 ** 1035 +* mbo_off = .f. 01, 18, ** $ offset from block 1036 +* mbo_blk = .f. 19, 18, ** $ machine block. vaxa 81 ..t10 vaxa 82 .+t32. vaxa 83 +* mosize = 38 ** vaxa 84 +* mbo_off = .f. 1, 32, ** vaxa 85 +* mbo_blk = .f. 33, 6, ** vaxa 86 ..t32 1037 1038 /* t10 and dec10 addressing. 1039 1040 the am_ codes indicate addressing mode within this asm. 1041 address designated by triple 1042 where mode is one of the am_ modes, mreg is machine register, 1043 and moff is block and offset. 1044 mreg must always be specificed, to permit register tracking, 1045 even if actual register not needed to form address; this pseudo- 1046 register is the 'spare' register. 1047 moff consists of two fields, mbo_blk and mbo_blk, where mbo_blk 1048 is a 'machine block', and mbo_off specifies word offset in block. 1049 the am modes, and the ea obtained, are as follows: 1050 1051 am_reg ea is register mreg, moff ignored. 1052 am_rel ea is offset from index register - blk+off(mreg) 1053 am_mem ea is memory address: blk+off 1054 am_reli ea is indirect from offset of register: @blk+off(mreg) 1055 1056 short (1 to 18 bit) constants have am_mem, with mbo_blk of bl_imm 1057 and bl_off gives constant value. 1058 1059 the offset for multiword and array accesses may be negative, so 1060 that mbo_off and dw_madr may be negative. 1061 $ [ds 10 may need to elaborate this] 1062 */ 1063 $ tmclt maps lexical types to desired conversion action 1064 +* tmc_i = 01 ** $ integer 1065 +* tmc_b = 02 ** $ bit 1066 +* tmc_c = 03 ** $ character (-r- type) 1067 +* tmc_r = 04 ** $ real token (not supported in bootstrap). 1068 +* tmc_s = 05 ** $ character string (-q- type) 1069 1070 +* num_tmc = 05 ** $ number of tmc codes. 1071 1072 1073 +* mblkname(i) = mblknames(i) ** 1 .=member start dsb 12 .+s10 prog start; dsk 21 .+s32 prog start; dsb 13 .+s66 subr start; eaa 45 eaa 46 .+t20. eaa 47 $ variables for extended addressing (t20). eaa 48 size nsheap_opt(ws); $ nonzero if dynamic heap. eaa 49 size nsheap_prm(.sds. filenamelen); eaa 50 $ nsheap_this is nonzero if current procedure contains eaa 51 $ to dynamic nameset. in this case nsheap_blk is mba index of the eaa 52 $ dynamic nameset. eaa 53 size nsheap_blk(ws); eaa 54 size nsheap_this(1); eaa 55 size nsheap_org(.sds. namelen); $ origin for nsheap (extended add eaa 56 $ we need to consult 'getword' as an oracle to sort out indexed eaa 57 $ dynamic heap assignments for extended addressing. eaa 58 $ this is done using the following variables. eaa 59 size asmflh_gwi(ps); $ input flag to getword eaa 60 data asmflh_gwi = no; eaa 61 size asmflh_gwo(ps); $ output from getword eaa 62 size asmflh_mreg(ps); $ mreg from getword eaa 63 size asmflh_moff(mosize); $ moff from getword eaa 64 size asmflh_mode(ws); $ mode from getword eaa 65 size asmflh_varext(ps); $ set if field assignment eaa 66 ..t20 3 size asconstdb(1); $ drop bit for -asconst-. 4 size asconstreal(1); $ flags real constants for -asconst-. 5 size asconstreg(ps); $ output value from -asconst-. 6 size asconstspc(1); $ 'internal special case in -asconst-' 7 data asconstspc = no; 8 size asconstsz(ps); $ size of constant for -asconst-. 9 size assignreg(ps); $ output register from -assignr-. dsq 59 size ats_opt(1); $ on to time stamp generated code 10 size baseblockfree(ps); $ last block in -baseblock- to be free. 11 size basefirst(ps); $ first block in -baseblock- chain. 12 size baselast(ps); $ last block in -baseblock- chain. 13 size baselastaddr(mps); $ highest address in -baseblock-. 14 size calldropgl(1); $ '-emitsub- should drop globals' 15 data calldropgl = no; 16 size callnodrop(1); $ '-emitsub- should not drop parms' 17 data callnodrop = no; 18 size codethis(ps); $ estimated code length. 19 size comptime(.sds. lstimelen); $ time of compilation. 20 data comptime = '' .pad. lstimelen; 21 size currsubname(.sds. namelen); $ current subroutine name 22 size ddblk(ps); $ data definition block. 23 size ddoff(mps); $ data definition offset. 24 $ dd variables used for declaration output. 25 size ddlt(ps); $ lexical type. 26 size ddnc(ps); $ length if character constant. 27 size ddnwds(ps); $ word count. 28 size ditemfree(ps); $ free list for -ditem-. 29 size doff(ps); $ offset for -asmxload- and others. 30 size dopcode(ps); $ operation code at deferring level. 31 size dopfbconst(1); $ 'first bit of extraction constant' 32 size dopfbm1(ps); $ -dreg- for first bit-1. 33 size dopfbm1val(ps); $ value of first bit - 1. 34 size dopfree(ps); $ free head for -dops-. 35 size dophasout(1); $ 'operation has output' 36 size dophold(ps); $ operation to re-issue is deferring. 37 size dopindx(ps); $ index register for .f. 38 size dopir(ps); $ first operand to -dop-. 39 size dopjr(ps); $ second operand to -dop-. 40 size dopkr(ps); $ third operand to -dop-. 41 size doplr(ps); $ fourth operand to -dop-. 42 size doplenconst(1); $ 'length operand of .f. is constant' 43 size doplenval(ps); $ value of length. 44 size dopnargs(ps); $ number of args for -dop-. 45 size dopnx(ps); $ number of extra arguments for -dop-. 46 size dopor(ps); $ output for -dop-. 47 size dopname(.sds. 6); dims dopname(num_do); 48 data 49 dopname(do_add) = 'add': 50 dopname(do_sub) = 'sub': 51 dopname(do_lt) = 'lt': 52 dopname(do_ge) = 'ge': 53 dopname(do_eq) = 'eq': 54 dopname(do_ne) = 'ne': 55 dopname(do_mul) = 'mul': 56 dopname(do_div) = 'div': 57 dopname(do_and) = 'and': 58 dopname(do_or) = 'or': 59 dopname(do_exor) = 'exor': 60 dopname(do_fcall) = 'fcall': 61 dopname(do_nb) = 'nb': 62 dopname(do_not) = 'not': 63 dopname(do_fb) = 'fb': 64 dopname(do_scall) = 'scall': 65 dopname(do_asin) = 'asin': 66 dopname(do_fasin) = 'fasin': 67 dopname(do_return) = 'return': 68 dopname(do_fext) = 'fext': 69 dopname(do_if) = 'if': 70 dopname(do_goto) = 'goto': 71 dopname(do_xload) = 'xload': 72 dopname(do_xasin) = 'xasin': 73 dopname(do_xfasin) = 'xfasin': 74 dopname(do_ifnot) = 'ifnot': 75 dopname(do_eext) = 'eext': 76 dopname(do_easin) = 'easin': 77 dopname(do_xeasin) = 'xeasin': 78 dopname(do_xsasin) = 'xsasin': 79 dopname(do_radd) = 'radd': 80 dopname(do_rsub) = 'rsub': 81 dopname(do_rlt) = 'rlt': 82 dopname(do_rge) = 'rge': 83 dopname(do_req) = 'req': 84 dopname(do_rne) = 'rne': 85 dopname(do_rmul) = 'rmul': 86 dopname(do_rdiv) = 'rdiv': 87 dopname(do_rusub) = 'rusub': 88 dopname(do_abs) = 'abs': dsj 36 dopname(do_float) = 'rfi': dsj 37 dopname(do_ifix) = 'ifr': dsj 38 dopname(do_aint) = 'rtr': dsj 39 dopname(do_amod) = 'rmo': 89 dopname(do_iabs) = 'iabs': 90 dopname(do_mod) = 'mod': 91 dopname(do_sign) = 'sign': 92 dopname(do_isign) = 'isign': 93 dopname(do_dim) = 'dim': 94 dopname(do_idim) = 'idim': 95 dopname(do_seq) = 'seq': 96 dopname(do_sne) = 'sne': 97 dopname(do_goby) = 'goby'; 98 size dopsname(.sds. namelen); $ name of routine to call. 99 size doptr(ps); $ pointer to -dops-. 100 size dopvar(ps); $ extractor variable for .f. 101 size dopwork(ps); $ work register for -dop- level. 102 size dopxr(ps); $ extra arguments for -dop-. 103 dims dopxr(511); $ maximum number possible. 104 size dregfree(ps); $ head of -dreg- free list. 105 size dropdopflg(1); $ set for -dropr- to drop -dop-. 106 data dropdopflg = no; 107 size dwordfree(ps); $ free list for -dword-. 108 size emopparm1(ps), emopparm2(ps); $ extra parms. to -emopr-. dst 25 .+enp. dst 26 nameset nsenp; dst 27 size enpara(.sds. 30); dims enpara(enpmax); dst 28 size enptot(ws); data enptot = 0; $ total # of procs dst 29 size enpopt(1); data enpopt=0; dst 30 size enpfilename(.sds. filenamelen); dst 31 size enpnotfound(ws); data enpnotfound = 0; dst 32 size enpnum(ws); $ number of current procedure dst 33 size enporg(ws); $ origin for assigned procedure numbers dst 34 end nameset; dst 35 ..enp dsp 27 .+t10 size end_opt(.sds. namelen); $ end option 109 size errno(ps); $ number of detected errors. 110 data errno = 0; 111 size exitcode(ps); $ completion code for -asmexit-. dsk 22 size fag_opt(ps); $ 'functions alter globals' 112 size gfoutr(ps); $ output from -getformr-. 113 size gotdreg(ps); $ return value from -getdregr-. 114 size gotreg(ps); $ return value from -getregr-. 115 size gotrpair(ps); $ return value from -getrpair-. 116 size iorc(ws); $ io return code. 117 size isinif(1); data isinif = no; $ -if- statement flag. 118 size isspecial(1); $ special case flag for -dop- level. dsq 60 .+t32. dsq 61 size iv_opt(ps); $ option for integer overflow trap. dsq 62 ..t32 dss 16 .-t32u +* lablorg = 0 ** dss 17 .+t32u size lablorg(ps); data lablorg=0; 119 size labluse(ps); $ last used entry of -lablist-. 120 size lcs_opt(1); $ statistics listing option. 121 size loadlab(ps); $ maximum usage of -lablist- array. 122 data loadlab = 0; 123 size loadpd(ps); $ maximum usage of -pdlist- array. 124 data loadpd = 0; 125 size loadrlab(.sds. namelen); $ largest user of -lablist-. 126 data loadrlab = ''; 127 size loadrpd(.sds. namelen); $ largest user of -pdlist-. 128 data loadrpd = ''; 129 size loadrsub(.sds. namelen); $ largest user of -subname-. 130 data loadrsub = ''; 131 size loadrval(.sds. namelen); $ routine which used most -val-. 132 data loadrval = ''; 133 size loadsub(ps); $ maximum usage of -subname- array. 134 data loadsub = 0; 135 size loadval(ps); $ maximum usage of -val- array. 136 data loadval = 0; 137 size nextgfree(ps); $ next general register free. dsu 34 dsu 35 $ nsheap_prm gives name of nameset to reference indirectly. dsu 36 $ if null there is no dynamic indirection. dsu 37 $ if indirection, nsheap_this is set if the current procedure dsu 38 $ references the indirect nameset, and nsheap_blk is mba index dsu 39 $ of the indirect nameset. nsheapreg_b is register reserved dsu 40 $ to contain byte address of nameset, nsheapreg_w is register dsu 41 $ reserved to contain word address. dsu 42 $ generated code will generally use nsheapreg_w to address the dsu 43 $ nameset since most instructions have longword context. dsu 44 $ nsheap_byte is flag set when nsheapreg_b must be used. dsu 45 dsu 46 .+t32h. dsu 47 size nsheap_prm(.sds. filenamelen); dsu 48 size nsheap_opt(ws); dsu 49 size heapthis(ws); $ nonzero if heap references possible dsu 50 size nsheap_blk(ws); $ nonzero if nsheap referenced in curr. dsu 51 size nsheap_this(1); $ nonzero if dynamic refs possible dsu 52 data nsheap_this = no; dsu 53 size nsheap_byte(1); $ nonzero for byte addressing dsu 54 data nsheap_byte = no; dsu 55 size nsheapreg_w(ps); $ register with head address (word) dsu 56 size nsheapreg_b(ps); $ register with heap address (byte address) dsu 57 ..t32h dst 36 size nspage_opt(ps); 138 size numcalls(ps); $ number of routine calls. 139 size ocs(.sds. 80); data ocs=''.pad.80; 140 size opt_d(1); $ 'do deferring optimization' 141 data opt_d = no; $ initially don't. 142 size opt_f(1); $ '-if- optimization in effect' 143 data opt_f = no; $ initially not. 144 size opt_l(1); $ 'label optimization in effect' 145 data opt_l = no; $ initially not. 146 size putcodei(ps); $ index for code output. vaxa 87 .+t32 size regmask(rhihi); $ mask of registers used. 147 size reguseval(ps); $ for lru allocation of registers. 148 size reissuedop(1); $ 'issue current -dop- again' 149 size returnlab(ps); $ label for return operation. 150 size rparrsz(ws); $ size for base probe. 151 size rparrmx(ws); $ array maximum for base probe. 152 size spcdrop(1); $ 'special case in -dropr-' 153 data spcdrop = no; $ default is normal. 154 size strname(.sds. namelen); $ for temporary strings. 155 data strname = ''; 156 size subrtype(ps); $ routine type (subr, fnct, or prog). 157 $ tmcval is used for constants in target machine form. 158 size tmctab(ps); dims tmctab(num_lt); 159 data tmctab(dectok) = tmc_i: 160 tmctab(bittok) = tmc_b: 161 tmctab(strtok) = tmc_s: 162 tmctab(rztok) = tmc_c: 163 tmctab(realtok)= tmc_r; 164 165 size tmcval(mws); dims tmcval(szmax/mws+1); 166 size tmcvalptr(ps); $ tmcval index. 167 size totglobs(ws); $ total length of globals. 168 size totlength(ws); $ total length of code. 169 size totns(ws); $ total number of namesets. 170 size totprocs(ws); $ total number of proceedures. 171 data totglobs = 0: totlength = 0: 172 totns = 0: totprocs = 0; 173 size trace_a(1); $ 'trace assembler ops' 174 size trace_any(1); $ set if some trace option is on. 175 size trace_c(1); $ 'trace generated code' 176 size trace_d(1); $ 'trace -dreg-s' 177 size trace_l(1); $ 'trace load cards' 178 size trace_o(1); $ 'trace -dop-s' 179 size trace_r(1); $ 'trace machine registers' 180 size trace_v(1); $ 'trace -voa-' dsn 28 .+t10 size univfilename(.sds.filenamelen); $ universal file name. dsn 29 .+t10 data univfilename = '' .pad.filenamelen; 183 size voaep(ps); $ current -voa- pointer. 184 size voahead(ps); $ list of -voa- operations. 185 size voalast(ps); $ last operation in chain. 186 size vopcode(ps); $ -voa- operation code. 187 188 $ definitions of tables defined passed by parser. 189 190 $ h a . hashed array. 191 192 $ all symbols 193 $ names, constants and expressions are entered in the ha, and 194 $ the ha index is main way item is referenced. the arglist 195 $ consists largely of ha indices. 196 197 $ the fields of the ha are as follows. 198 $ ep. the index of voa for this item. 199 $ var. 'is this a variable (ie. not operation) entry'. 200 $ hainuse. 'is this entry in use' 201 $ nayme. index in names array if variable name. 202 $ nchars. number of characters in name or constant. 203 $ labno. (for names only) lablist index if used as label. 204 $ namintern. 'is this a compiler generated name' 205 $ hascon. (for constants only) 'is this safe (short) constant'. 206 $ zerents. number of preceding empty ha entries (used to 207 $ pack ha when writing voa file). 208 $ varluse. last use in block of variable. (-voa- pointer) 209 $ tracef. 'is store trace in effect.' 210 $ chinxf. 'is check index option in effect.' 211 212 +* hasz = $ size of ha in bits 213 .+s66 60 dsk 23 .+s32 64 214 .+s37 64 215 .+s10 72 216 ** 218 .+s66 nameset blank; $ keep in blank common on s66. dso 12 size ha(hasz); dims ha(hadim); 220 .+s66 end nameset; 221 222 .+s66. 223 +* ha_ep = .f. 01, 12, ** 224 +* ha_hascon = .f. 13, 01, ** 225 +* ha_var = .f. 14, 01, ** 226 +* ha_hainuse = .f. 15, 01, ** 227 +* ha_nayme = .f. 16, 13, ** 228 +* ha_labno = .f. 29, 10, ** 229 +* ha_tracef = .f. 39, 01, ** 230 +* ha_chinxf = .f. 40, 01, ** 231 +* ha_namintern = .f. 41, 01, ** 232 +* ha_zerents = .f. 42, 11, ** 233 +* ha_varluse = .f. 42, 11, ** $ overlays -zerents- 234 +* ha_nchars = .f. 53, 08, ** 235 ..s66 dsk 24 .+s32. dsk 25 +* ha_hascon = .f. 1, 1, ** dsk 26 +* ha_var = .f. 2, 1, ** dsk 27 +* ha_tracef = .f. 3, 1, ** dsk 28 +* ha_chinxf = .f. 4, 1, ** dsk 29 +* ha_ep = .f. 5, 11, ** dsk 30 +* ha_namintern = .f. 16, 1, ** dsk 31 +* ha_zerents = .f. 17, 16, ** dsk 32 +* ha_varluse = .f. 17, 16, ** dsk 33 +* ha_nchars = .f. 33, 8, ** dsk 34 +* ha_labno = .f. 41, 9, ** dsk 35 +* ha_hainuse = .f. 50, 1, ** dsk 36 +* ha_nayme = .f. 54, 11, ** dsk 37 ..s32 236 .+s37. 237 +* ha_hascon = .f. 1, 1, ** 238 +* ha_var = .f. 2, 1, ** 239 +* ha_tracef = .f. 3, 1, ** 240 +* ha_chinxf = .f. 4, 1, ** 241 +* ha_ep = .f. 5, 11, ** 242 +* ha_namintern = .f. 16, 1, ** 243 +* ha_zerents = .f. 17, 16, ** 244 +* ha_varluse = .f. 17, 16, ** 245 +* ha_nchars = .f. 33, 8, ** 246 +* ha_labno = .f. 41, 9, ** 247 +* ha_hainuse = .f. 50, 1, ** 248 +* ha_nayme = .f. 54, 11, ** 249 ..s37 250 .+s10. 251 +* ha_ep = .f. 1, 18, ** 252 +* ha_zerents = .f. 19, 18, ** 253 +* ha_varluse = .f. 19, 18, ** 254 +* ha_nayme = .f. 37, 11, ** 255 +* ha_labno = .f. 48, 9, ** 256 +* ha_nchars = .f. 57, 8, ** 257 +* ha_hascon = .f. 65, 1, ** 258 +* ha_var = .f. 66, 1, ** 259 +* ha_tracef = .f. 67, 1, ** 260 +* ha_chinxf = .f. 68, 1, ** 261 +* ha_namintern = .f. 69, 1, ** 262 +* ha_hainuse = .f. 70, 1, ** 263 ..s10 264 265 size ha_0(ps); $ ha index of constant zero. 266 size ha_1(ps); $ ha index of constant one. 267 268 269 $ m b a . machine block array 270 size mbaptr(ps); data mbaptr=0; $ most recent entry in mba 271 272 +* mbasz = $ size of mba (m-achine b-lock a-rray) 273 .+s66 60 dsn 30 .+s32 96 dsn 31 .+s37 96 275 .+s10 72 276 ** 277 278 size mba(mbasz); dims mba(mbadim); $ m-achine b-lock a-rray 279 data mba = 0(mbadim); 280 dsb 14 .+s10. dsb 15 +* mb_len = .f. 1, 18, ** dsb 16 +* mb_org = .f. 19, 18, ** dsb 17 +* mb_ha = .f. 37, 18, ** dsm 9 +* mb_chain = .f. 55, 11, ** dsm 10 +* mb_used = .f. 66, 1, ** dsm 11 +* mb_def = .f. 67, 1, ** dsb 21 ..s10 dsk 39 .+s32. dsk 40 +* mb_used = .f. 1, 1, ** $ 'block used in current routine' dsk 41 +* mb_def = .f. 2, 1, ** $ 'block defined in this routine' dsk 42 +* mb_ha = .f. 4, 11, ** $ -ha- index of block name. dsn 32 +* mb_len = .f. 65, 32, ** $ length of block. dsk 44 +* mb_org = .f. 33, 13, ** $ origin address of block. dsk 45 +* mb_chain = .f. 46, 11, ** $ -voa- pointer to first var. dsk 46 ..s32 dsk 47 .+s37. dsk 48 +* mb_used = .f. 1, 1, ** $ 'block used in current routine' dsk 49 +* mb_def = .f. 2, 1, ** $ 'block defined in this routine' dsk 50 +* mb_ha = .f. 4, 11, ** $ -ha- index of block name. dsn 33 +* mb_len = .f. 65, 32, ** $ length of block. dsk 52 +* mb_org = .f. 33, 13, ** $ origin address of block. dsk 53 +* mb_chain = .f. 46, 11, ** $ -voa- pointer to first var. dsk 54 ..s37 281 .+s66. 282 +* mb_len = .f. 01, 20, ** 283 +* mb_ha = .f. 21, 11, ** 284 +* mb_used = .f. 32, 01, ** 285 +* mb_org = .f. 33, 13, ** 286 +* mb_def = .f. 46, 01, ** 287 +* mb_chain = .f. 47, 11, ** 288 ..s66 289 290 size mbanames(.sds. namelen); 291 dims mbanames(mbadim); 292 data mbanames(bl_base) = 'bas': 293 mbanames(bl_const)= 'con': 294 mbanames(bl_temp) = 'tmp': dsq 63 .+t32u mbanames(bl_imm) = '$': dsq 64 .+t32v mbanames(bl_imm) = '#': 295 mbanames(bl_local)= 'lcl'; 296 297 size mblknames(.sds. namelen); 298 dims mblknames(mbadim); 299 data mblknames(bl_base) = 'bas': 300 mblknames(bl_const)= 'con': 301 mblknames(bl_temp) = 'tmp': dsq 65 .+t32u mblknames(bl_imm) = '$': dsq 66 .+t32v mblknames(bl_imm) = '#': 302 mblknames(bl_local)= 'lcl'; 303 304 305 size moatab(ws); dims moatab(num_mo); $ mop attributes. 306 data 307 $ iw icb ici i 308 moatab(mo_ban) = 3b' 1 404 405 1': 309 moatab(mo_bfb) = 3b' 5 000 000 1': 310 moatab(mo_bnb) = 3b' 5 000 000 0': 311 moatab(mo_bno) = 3b' 1 000 000 0': 312 moatab(mo_bor) = 3b' 1 434 435 1': 313 moatab(mo_bxo) = 3b' 1 430 431 1': 314 moatab(mo_cal) = 3b' 3 000 000 0': 315 moatab(mo_ceq) = 3b' 1 000 000 1': 316 moatab(mo_cge) = 3b' 1 000 000 1': 317 moatab(mo_cgt) = 3b' 1 000 000 1': 318 moatab(mo_cle) = 3b' 1 000 000 1': 319 moatab(mo_clt) = 3b' 1 000 000 1': 320 moatab(mo_cne) = 3b' 1 000 000 1': 321 moatab(mo_iab) = 3b' 1 000 000 0': 322 moatab(mo_iad) = 3b' 1 270 271 1': 323 moatab(mo_iao) = 3b' 1 240 000 0': 324 moatab(mo_ico) = 3b' 1 210 000 0': 325 moatab(mo_idi) = 3b' 3 230 231 1': 326 moatab(mo_idt) = 3b' 1 000 000 1': 327 moatab(mo_ieq) = 3b' 4 000 000 1': dsj 40 moatab(mo_ifr) = 3b' 1 000 000 0': 328 moatab(mo_ige) = 3b' 4 000 000 1': 329 moatab(mo_igt) = 3b' 4 000 000 1': 330 moatab(mo_ile) = 3b' 4 000 000 1': 331 moatab(mo_ilt) = 3b' 4 000 000 1': 332 moatab(mo_imo) = 3b' 3 000 000 1': 333 moatab(mo_imt) = 3b' 1 000 000 1': 334 moatab(mo_imu) = 3b' 1 220 221 1': 335 moatab(mo_ine) = 3b' 4 000 000 1': 336 moatab(mo_isi) = 3b' 4 000 000 1': 337 moatab(mo_iso) = 3b' 1 370 000 0': 338 moatab(mo_isu) = 3b' 1 274 275 1': 339 moatab(mo_jeq) = 3b' 1 000 000 0': 340 moatab(mo_jge) = 3b' 1 325 000 0': 341 moatab(mo_jgt) = 3b' 1 327 000 0': 342 moatab(mo_jle) = 3b' 1 323 000 0': 343 moatab(mo_jlt) = 3b' 1 321 000 0': 344 moatab(mo_jmn) = 3b' 1 320 000 0': 345 moatab(mo_jmp) = 3b' 1 324 000 0': 346 moatab(mo_jne) = 3b' 1 326 000 0': 347 moatab(mo_lda) = 3b' 1 000 000 0': 348 moatab(mo_ldf) = 3b' 1 000 000 0': 349 moatab(mo_ldl) = 3b' 1 534 555 0': 350 moatab(mo_ldr) = 3b' 2 550 551 0': 351 moatab(mo_ldw) = 3b' 1 200 201 1': eaa 67 .+t20. eaa 68 moatab(mo_lla) = 3b' 1 000 000 0': eaa 69 ..t20 352 moatab(mo_lpr) = 3b' 2 000 000 0': 353 moatab(mo_mvw) = 3b' 5 000 000 0': dsu 58 .+t32h. dsu 59 moatab(mo_mvx) = 3b' 5 000 000 0': dsu 60 ..t32h 354 moatab(mo_rab) = 3b' 1 000 000 0': 355 moatab(mo_rad) = 3b' 1 140 000 1': 356 moatab(mo_rco) = 3b' 1 210 000 0': 357 moatab(mo_rdi) = 3b' 2 170 000 1': 358 moatab(mo_req) = 3b' 4 000 000 1': 359 moatab(mo_ret) = 3b' 3 000 000 0': dsj 41 moatab(mo_rfi) = 3b' 1 000 000 1': 360 moatab(mo_rge) = 3b' 4 000 000 1': 361 moatab(mo_rgt) = 3b' 4 000 000 1': 362 moatab(mo_rle) = 3b' 4 000 000 1': 363 moatab(mo_rlt) = 3b' 4 000 000 1': 364 moatab(mo_rmo) = 3b' 3 000 000 1': 365 moatab(mo_rmu) = 3b' 1 160 000 1': 366 moatab(mo_rne) = 3b' 4 000 000 1': 367 moatab(mo_rsi) = 3b' 1 000 000 1': 368 moatab(mo_rsu) = 3b' 1 150 000 1': dsj 42 moatab(mo_rtr) = 3b' 1 000 000 0': 369 moatab(mo_spr) = 3b' 2 000 000 0': 370 moatab(mo_stf) = 3b' 1 000 000 0': 371 moatab(mo_stl) = 3b' 1 506 000 0': 372 moatab(mo_str) = 3b' 1 542 000 0': 373 moatab(mo_stw) = 3b' 1 202 000 0': 374 moatab(mo_zeb) = 3b' 4 251 000 1': eaa 70 .+t20. eaa 71 moatab(mo_hba) = 3b' 1 000 000 1': eaa 72 moatab(mo_hbb) = 3b' 1 000 000 1': eaa 73 moatab(mo_hbc) = 3b' 1 000 000 1': eaa 74 ..t20 375 moatab(mo_zew) = 3b' 1 400 000 0'; 376 377 size names(ws); dims names(namesdim); $ -names- array space. 378 379 380 381 size val(ws); dims val(valdim); $ -val- array space. 382 size valptr(ps); $ last index in -val-. 383 384 +* voafnct = 1 ** 385 size voaptr(ps); $ pointer to last used item in -voa-. 386 387 +* voasz = $ size of voa entry. 388 .+s10 144 dsn 34 .+s32 192 dsn 35 .+s37 192 390 .+s66 120 391 ** 392 .+s66 nameset blank; 393 size voa(voasz); dims voa(voadim); 394 .+s66 end nameset; 395 396 size voawrt(1); $ on if writing voa file 397 $ v o a f i e l d s 398 399 $ fields common to both -operation- and -quantity- operations 400 401 .+s66. 402 +* vv_deflev = .f. 1, 6, ** $ definition level 403 +* vv_keeb = .f. 7, 1, ** $ keep bit for holding till blkend 404 +* vv_naym = .f. 8, 10, ** $ ha ptr 405 +* vv_opb = .f. 18, 1, ** $ 'is this an operation' 406 +* vv_syze = .f. 19, 11, ** $ entry size in bits 407 +* vv_amode = .f. 118, 1, ** $ real or integer mode 408 409 $ voa field for -variable' or non-operation entries (opb = no) 410 411 +* vv_arb = .f. 30, 1, ** $ argument bit 412 +* vv_argno = .f. 31, 5, ** $ argument no of parameter 413 +* vv_const = .f. 36, 1, ** $ on if 'constant' 414 +* vv_dimn = .f. 37, 16, ** $ dimension of array (or 0 if no di 415 +* vv_vlen = .f. 55, 5, ** $ no of words in constant value 416 +* vv_temb = .f. 60, 1, ** $ on if 'temporary' 417 +* vv_voanl = .f. 61, 9, ** $ pointer to -nl- for global 418 +* vv_madr = .f. 70, 16, ** $ machine address of item 419 +* vv_mblk = .f. 86, 6, ** $ machine block of item 420 +* vv_type = .f. 92, 2, ** $ quantity type 421 +* vv_vbeg = .f. 94, 12, ** $ start of const val in -val- array 422 +* vv_signbit = .f.106,1, ** $ sign of constant (0=+, 1=-) 423 +* vv_lextype = .f. 107,5, ** $ lexical type of constant 424 +* vv_isafnct = .f. 113,1, ** $ set when name used as function n 425 +* vv_varnuse = .f. 114, 4, ** $ number of uses of var. 426 +* vv_varnusemax = 1b'1111' ** $ max of -varnuse- field 427 +* vv_isavar = .f. 119, 1, ** $ 'used as variable' 428 +* vv_frsdata = .f. 121, 11, ** $ pointer to first data op. 429 +* vv_ppdata = .f. 53, 1, ** $ possible permanent value 430 +* vv_inreg = .f. 61, 8, ** $ -dreg- containing item. 431 432 $ fields for operation type entries 433 434 435 +* vv_argbeg = .f. 30, 9, ** $ beginning of extra arguments 436 +* vv_arglen = .f. 39, 9, ** $ number of extra arguments 437 +* vv_db1 = .f. 49, 1, ** $ drop bit for input 1 438 +* vv_db2 = .f. 50, 1, ** $ drop bit for input 2 439 +* vv_db3 = .f. 51, 1, ** $ drop bit for input 3 440 +* vv_opcode = .f. 52, 7, ** 441 +* vv_seblk = .f. 59, 1, ** $ indicates if scall ends block 442 +* vv_bytaln = .f. 60, 1, ** $ indicates char. extract or assign 443 +* vv_inp1 = .f. 61, 12, ** $ voa index of first input 444 +* vv_inp2 = .f. 73, 12, ** $ voa index of second input 445 +* vv_inp3 = .f. 85, 12, ** $ voa index of third input 446 +* vv_oup = .f. 97, 12, ** $ voa index of output 447 +* vv_lastuse = .f. 109, 9, **$ voa index of last use of op 448 +* vv_dboup = .e. 119, 01, ** $ drop bit if oup used as input. 449 ..s66 450 dsk 56 .+s32. dsk 57 +* vv_amode = .f. 1, 1, ** $ arithmetic mode. dsk 58 +* vv_keeb = .f. 2, 1, ** $ '-deflev- overflow' dsk 59 +* vv_opb = .f. 3, 1, ** $ 'operation entry' dsk 60 +* vv_naym = .f. 4, 10, ** $ -ha- index. dsk 61 +* vv_syze = .f. 17, 16, ** $ size of item in bits. dsk 62 +* vv_deflev = .f. 33, 6, ** $ definition level. dsk 63 dsk 64 $ fields for variable operand entries. dsk 65 dsk 66 +* vv_const = .f. 14, 1, ** $ 'operand is constant' dsk 67 +* vv_temb = .f. 15, 1, ** $ 'operand is temporary' dsk 68 +* vv_signbit = .f. 16, 1, ** $ sign bit. dsk 69 +* vv_isafnct = .f. 39, 1, ** $ 'operand used as function' dsk 70 +* vv_inreg = .f. 40, 8, ** $ -dreg- containing item. dsk 71 +* vv_ppdata = .f. 48, 1, ** $ 'possible permanent value' dsn 36 +* vv_dimn = .f. 129, 32, ** $ dimension of array. dsk 73 +* vv_varnuse = .f. 65, 8, ** $ number of uses. dsk 74 +* vv_mblk = .f. 73, 7, ** $ machine block number. dsn 37 +* vv_madr = .f. 161, 32, ** $ machine address. dsk 76 +* vv_frsdata = .f. 97, 12, ** $ pointer to first -data- op. dsk 77 +* vv_vlen = .f. 97, 8, ** $ length in -val- array. dsk 78 +* vv_lextype = .f. 105, 4, ** $ lexical type. dsk 79 +* vv_argno = .f. 109, 5, ** $ argument number. dsk 80 +* vv_arb = .f. 114, 1, ** $ 'operand is routine argument' dsk 81 +* vv_type = .f. 115, 2, ** $ operand type. dsk 82 +* vv_vbeg = .f. 117, 12, ** $ -val- pointer for constannts. dsk 83 dsk 84 $ fields for operation entries. dsk 85 dsk 86 +* vv_db1 = .f. 14, 1, ** $ 'last use of first operand' dsk 87 +* vv_db2 = .f. 15, 1, ** $ 'last use of second operand' dsk 88 +* vv_db3 = .f. 16, 1, ** $ 'last use of third operand' dsk 89 +* vv_chain = .f. 17, 16, ** $ operation chain. dsk 90 +* vv_arglen = .f. 39, 9, ** $ length of -xarg- entries. dsk 91 +* vv_dboup = .f. 48, 1, ** $ 'last use of output' dsk 92 +* vv_inp1 = .f. 49, 16, ** $ first input. dsk 93 +* vv_inp2 = .f. 65, 11, ** $ second input. dsk 94 +* vv_lastuse = .f. 76, 10, ** $ last use pointer. dsk 95 +* vv_inp3 = .f. 86, 11, ** $ third input. dsk 96 +* vv_opcode = .f. 97, 8, ** $ operation code. dsk 97 +* vv_seblk = .f. 105, 1, ** $ 'call ends block' dsk 98 +* vv_bytaln = .f. 106, 1, ** $ 'byte aligned' dsk 99 +* vv_argbeg = .f. 107, 10, ** $ -xarg- pointer. dsk 100 +* vv_oup = .f. 118, 11, ** $ output. dsk 101 ..s32 dsk 102 .+s37. dsk 103 +* vv_amode = .f. 1, 1, ** $ arithmetic mode. dsk 104 +* vv_keeb = .f. 2, 1, ** $ '-deflev- overflow' dsk 105 +* vv_opb = .f. 3, 1, ** $ 'operation entry' dsk 106 +* vv_naym = .f. 4, 10, ** $ -ha- index. dsk 107 +* vv_syze = .f. 17, 16, ** $ size of item in bits. dsk 108 +* vv_deflev = .f. 33, 6, ** $ definition level. dsk 109 dsk 110 $ fields for variable operand entries. dsk 111 dsk 112 +* vv_const = .f. 14, 1, ** $ 'operand is constant' dsk 113 +* vv_temb = .f. 15, 1, ** $ 'operand is temporary' dsk 114 +* vv_signbit = .f. 16, 1, ** $ sign bit. dsk 115 +* vv_isafnct = .f. 39, 1, ** $ 'operand used as function' dsk 116 +* vv_inreg = .f. 40, 8, ** $ -dreg- containing item. dsk 117 +* vv_ppdata = .f. 48, 1, ** $ 'possible permanent value' dsn 38 +* vv_dimn = .f. 129, 32, ** $ dimension of array. dsm 12 +* vv_varnuse = .f. 65, 8, ** $ number of uses. dsm 13 +* vv_mblk = .f. 73, 7, ** $ machine block number. dsn 39 +* vv_madr = .f. 161, 32, ** $ machine address. dsm 15 +* vv_frsdata = .f. 97, 12, ** $ pointer to first -data- op. dsm 16 +* vv_vlen = .f. 97, 8, ** $ length in -val- array. dsm 17 +* vv_lextype = .f. 105, 4, ** $ lexical type. dsm 18 +* vv_argno = .f. 109, 5, ** $ argument number. dsm 19 +* vv_arb = .f. 114, 1, ** $ 'operand is routine argument' dsm 20 +* vv_type = .f. 115, 2, ** $ operand type. dsm 21 +* vv_vbeg = .f. 117, 12, ** $ -val- pointer for constannts. dsk 129 dsk 130 $ fields for operation entries. dsk 131 dsk 132 +* vv_db1 = .f. 14, 1, ** $ 'last use of first operand' dsk 133 +* vv_db2 = .f. 15, 1, ** $ 'last use of second operand' dsk 134 +* vv_db3 = .f. 16, 1, ** $ 'last use of third operand' dsk 135 +* vv_chain = .f. 17, 16, ** $ operation chain. dsk 136 +* vv_arglen = .f. 39, 9, ** $ length of -xarg- entries. dsk 137 +* vv_dboup = .f. 48, 1, ** $ 'last use of output' dsk 138 +* vv_inp1 = .f. 49, 16, ** $ first input. dsk 139 +* vv_inp2 = .f. 65, 11, ** $ second input. dsk 140 +* vv_lastuse = .f. 76, 10, ** $ last use pointer. dsk 141 +* vv_inp3 = .f. 86, 11, ** $ third input. dsk 142 +* vv_opcode = .f. 97, 8, ** $ operation code. dsk 143 +* vv_seblk = .f. 105, 1, ** $ 'call ends block' dsk 144 +* vv_bytaln = .f. 106, 1, ** $ 'byte aligned' dsk 145 +* vv_argbeg = .f. 107, 10, ** $ -xarg- pointer. dsk 146 +* vv_oup = .f. 118, 11, ** $ output. dsk 147 ..s37 451 .+s37. 452 +* vv_amode = .f. 1, 1, ** 453 +* vv_keeb = .f. 2, 1, ** 454 +* vv_opb = .f. 3, 1, ** 455 +* vv_naym = .f. 4, 10, ** 456 +* vv_syze = .f. 17, 16, ** 457 +* vv_deflev = .f. 33, 6, ** 458 459 +* vv_const = .f. 14, 1, ** 460 +* vv_temb = .f. 15, 1, ** 461 +* vv_signbit = .f. 16, 1, ** 462 +* vv_isafnct = .f. 39, 1, ** 463 +* vv_voanl = .f. 40, 9, ** 464 +* vv_dimn = .f. 49, 16, ** 465 +* vv_type = .f. 65, 2, ** 466 +* vv_vbeg = .f. 67, 12, ** 467 +* vv_lextype = .f. 79, 5, ** 468 +* vv_arb = .f. 84, 1, ** 469 +* vv_isavar = .f. 85, 1, ** 470 +* vv_vlen = .f. 89, 8, ** 471 +* vv_madr = .f. 97, 16, ** 472 +* vv_mblk = .f. 113, 8, ** 473 +* vv_varnuse = .f. 121, 8, ** 474 +* vv_varnusemax = 4b'ff' ** 475 476 +* vv_db1 = .f. 14, 1, ** 477 +* vv_db2 = .f. 15, 1, ** 478 +* vv_db3 = .f. 16, 1, ** 479 +* vv_arglen = .f. 39, 9, ** 480 +* vv_dboup = .f. 48, 1, ** 481 +* vv_inp1 = .f. 49, 16, ** 482 +* vv_inp2 = .f. 65, 11, ** 483 +* vv_lastuse = .f. 76, 10, ** 484 +* vv_inp3 = .f. 86, 11, ** 485 +* vv_opcode = .f. 97, 8, ** 486 +* vv_seblk = .f. 105, 1, ** 487 +* vv_bytaln = .f. 106, 1, ** 488 +* vv_argbeg = .f. 107, 10, ** 489 +* vv_oup = .f. 118, 11, ** 490 ..s37 dsb 22 .+s10. dsb 23 +* vv_amode = .f. 1, 1, ** dsb 24 +* vv_keeb = .f. 2, 1, ** dsb 25 +* vv_opb = .f. 3, 1, ** dsb 26 +* vv_naym = .f. 4, 10, ** dsb 27 +* vv_syze = .f. 17, 11, ** dsb 28 +* vv_deflev = .f. 28, 6, ** dsb 29 dsb 30 +* vv_const = .f. 14, 1, ** dsb 31 +* vv_temb = .f. 15, 1, ** dsb 32 +* vv_signbit = .f. 16, 1, ** dsb 33 +* vv_isafnct = .f. 37, 1, ** dsb 34 +* vv_inreg = .f. 38, 8, ** dsb 35 +* vv_ppdata = .f. 46, 1, ** dsb 36 +* vv_voanl = .f. 38, 9, ** dsb 37 +* vv_vlen = .f. 47, 8, ** dsb 38 +* vv_lextype = .f. 55, 4, ** dsb 39 +* vv_frsdata = .f. 47, 12, ** dsb 40 +* vv_argno = .f. 59, 5, ** dsb 41 +* vv_mblk = .f. 64, 6, ** dsb 42 +* vv_arb = .f. 70, 1, ** dsb 43 +* vv_isavar = .f. 71, 1, ** dsb 44 +* vv_type = .f. 73, 2, ** dsn 40 +* vv_dimn = .f. 75, 17, ** dsn 41 +* vv_madr = .f. 92, 17, ** dsm 22 +* vv_vbeg = .f. 109, 12, ** dsm 23 +* vv_varnuse = .f. 121, 8, ** dsb 49 +* varnusemax = 4b'ff' ** dsb 50 dsb 51 +* vv_db1 = .f. 14, 1, ** dsb 52 +* vv_db2 = .f. 15, 1, ** dsb 53 +* vv_db3 = .f. 16, 1, ** dsb 54 +* vv_arglen = .f. 37, 9, ** dsb 55 +* vv_dboup = .f. 46, 1, ** dsb 56 +* vv_inp1 = .f. 47, 11, ** dsb 57 +* vv_inp2 = .f. 58, 11, ** dsb 58 +* vv_seblk = .f. 69, 1, ** dsb 59 +* vv_bytaln = .f. 70, 1, ** dsb 60 +* vv_inp3 = .f. 73, 11, ** dsb 61 +* vv_lastuse = .f. 84, 10, ** dsb 62 +* vv_oup = .f. 94, 11, ** dsb 63 +* vv_opcode = .f. 109, 7, ** dsb 64 +* vv_argbeg = .f. 116, 10, ** dsb 65 ..s10 532 533 +* vv_chain = vv_syze ** $ used for operations. 534 535 $ to keep voa at two words for s66 bootstrap, the vv field 536 $ vv_frsdata is kept in separate array. 537 $ the conditional symbol vvfrs is on for separate frsdata. 538 .+s10. 539 .-set vvfrs 540 ..s10 541 .+s66. 542 .+set vvfrs 543 ..s66 544 .+vvfrs. 545 +* vv_frsdata = ** $ drop prior definition 546 +* vvfrsdata(i) = 547 .f. 1 + 16*((i) - 4*((i)/4)), 12, frsdataara(1+(i)/4) ** 548 size frsdataara(ws); dims frsdataara((voadim)/4+2); 549 ..vvfrs 550 size voafilename(ws); $ name of voa file 551 $ v o a f i l e m a c r o s 552 553 +* vf_level = .e. 17, 16, ** $ julian date of last change 554 $ relative to 1 jan 1976 (ie, juliandate - 76000). 555 $ *** when change array size or fields, update version no. *** 556 557 $ codes for items in voa-file 558 +* vh_eof = 0 ** $ marks end of file 559 +* vh_hdr = 1 ** $ file header code 560 +* vh_asm = 2 ** $ routine header code 561 +* vh_voa = 3 ** $ voa 562 +* vh_ha = 4** $ ha 563 +* vh_names = 5 ** $ names array 564 +* vh_xarg = 6 ** $ xarg array 565 +* vh_val = 7 ** $ val array 566 +* vh_mba = 8 ** $ m-achine b-lock a-rray (mba) 567 +* vh_eos = 9 ** $ code for end of subprogram 568 569 +* num_vh = 9 ** 570 dsk 148 .+s32. dsk 149 $ first, fields common to all header entries dsk 150 +* vf_code = .e. 1,16, ** $ code of item dsk 151 +* vf_lo = .e.49,16, ** $ lo entry of array dsk 152 $ for debugging dsk 153 +* vf_hi = .e.65,16, ** $ high entry of array dsk 154 +* vf_listcode = .e. 81, 01, ** $ on to list generated code. dsk 155 $ to format of any item written to voa. dsk 156 +* vf_hamax = .e. 97,16, ** $ hamax in gen dsk 157 $ bits 113...128 reserved for future expansion dsk 158 dsk 159 $ fields used to pass non/array args to assembler dsk 160 +* vf_asmarg = .e. 129, 16,** $ assemblarg dsk 161 +* vf_init = .e. 145, 16,** $ init dsk 162 +* vf_lablistptr = .e. 161, 16, ** $ lablistptr dsk 163 +* vf_sub1 = .e. 177, 16, ** $ subinfo(1), a name dsk 164 +* vf_sub2 = .e. 193, 16, ** $ subinfo(2) dsk 165 +* vf_sub3 = .e. 209, 16, ** $ subinfo(3) dsk 166 +* vf_subrargs = .e. 225, 16, ** $ no. of arguments of current dsk 167 $ routine dsk 168 +* vf_ha0 = .e. 241, 16, ** $ ha index of constant 0. dsk 169 +* vf_ha1 = .e. 257, 16, ** $ ha index of constant 1. dsk 170 ..s32 571 .+s37. 572 $ first, fields common to all header entries 573 +* vf_code = .e. 1,16, ** $ code of item 574 +* vf_lo = .e.49,16, ** $ lo entry of array 575 $ for debugging 576 +* vf_hi = .e.65,16, ** $ high entry of array 577 +* vf_listcode = .e. 81, 01, ** $ on to list generated code. 578 $ to format of any item written to voa. 579 +* vf_hamax = .e. 97,16, ** $ hamax in gen 580 $ bits 113...128 reserved for future expansion 581 582 $ fields used to pass non/array args to assembler 583 +* vf_asmarg = .e. 129, 16,** $ assemblarg 584 +* vf_init = .e. 145, 16,** $ init 585 +* vf_lablistptr = .e. 161, 16, ** $ lablistptr 586 +* vf_sub1 = .e. 177, 16, ** $ subinfo(1), a name 587 +* vf_sub2 = .e. 193, 16, ** $ subinfo(2) 588 +* vf_sub3 = .e. 209, 16, ** $ subinfo(3) 589 +* vf_subrargs = .e. 225, 16, ** $ no. of arguments of current 590 $ routine 591 +* vf_ha0 = .e. 241, 16, ** $ ha index of constant 0. 592 +* vf_ha1 = .e. 257, 16, ** $ ha index of constant 1. 593 ..s37 594 .+s66. 595 +* vf_code = .e. 01, 06, ** $ code of item 596 +* vf_hdrseq = .e. 07, 18, ** $ header sequence number. 597 +* vf_es = .e. 25, 12, ** $ entry size in bits 598 +* vf_lo = .e. 37, 12, ** $ lo entry of array 599 +* vf_hi = .e. 49, 12, ** $ high entry of array 600 +* vf_listcode = .e. 61, 01, ** $ on to list generated code. 601 +* vf_hamax = .e. 62, 11, ** $ hamax in gen 602 +* vf_asmarg = .e. 73, 12,** $ assemblarg 603 +* vf_init = .e. 85, 12,** $ init 604 +* vf_lablistptr = .e. 97, 12, ** $ lablistptr 605 +* vf_sub1 = .e. 109, 12, ** $ subinfo(1), a name 606 +* vf_sub2 = .e. 121, 12, ** $ subinfo(2) 607 +* vf_sub3 = .e. 133, 12, ** $ subinfo(3) 608 +* vf_subrargs = .e. 145, 12, ** $ no. of arguments of current 609 $ routine 610 +* vf_ha0 = .e. 157, 12, ** $ ha index of constant 0. 611 +* vf_ha1 = .e. 169, 12, ** $ ha index of constant 1. 612 ..s66 613 .+s10. 614 +* vf_code = .f. 1, 18, ** 615 +* vf_hdrseq = .f. 19, 18, ** 616 +* vf_es = .f. 37, 18, ** 617 +* vf_lo = .f. 55, 18, ** 618 +* vf_hi = .f. 73, 18, ** 619 +* vf_listcode = .f. 91, 1, ** 620 +* vf_hamax = .f. 109, 18, ** 621 +* vf_asmarg = .f. 127, 18, ** 622 +* vf_init = .f. 145, 18, ** 623 +* vf_lablistptr = .f. 163, 18, ** 624 +* vf_sub1 = .f. 181, 18, ** 625 +* vf_sub2 = .f. 199, 18, ** 626 +* vf_sub3 = .f. 217, 18, ** 627 +* vf_subrargs = .f. 235, 18, ** 628 +* vf_ha0 = .f. 253, 18, ** 629 +* vf_ha1 = .f. 271, 18, ** 630 ..s10 631 632 +* vf_lablistp = vf_lablistptr ** $ rename with edit later. 633 634 $ values for routine type. 635 636 +* st_subr = 0 ** $ subroutine. 637 +* st_fnct = 1 ** $ function. 638 +* st_prog = 2 ** $ main program. 639 640 +* vofsz = $ size of voa header frame 641 .+s10 288 dsk 171 .+s32 256 dsk 172 .+s37 256 642 .+s66 240 643 ** 644 645 size vof(vofsz); $ -voa- header frame. 646 647 648 649 $ x a r g. extra arguments array dsn 42 +* xargsz = $ size of xarg array. dsn 43 .+s10 ws dsn 44 .+s32 64 dsn 45 .+s37 64 dsn 46 .+s66 ws dsn 47 ** 651 +* xargmax = 511 ** $ xarg dims 652 .+s66 nameset blank; $ keep in blank common on s66. 653 size xarg(xargsz); dims xarg(xargmax); $ extra arguments array 654 .+s66 end nameset; 655 size xargptr(ps); data xargptr = 1; $ ptr to xarg 656 $ fields of xarg array 657 $ xa_dbf is called xa_db. 658 .+s66. 659 +* xa_voa = .f. 16, 15, ** $ ptr to voa entry 660 +* xa_db= .f. 31, 1, ** 661 +* xa_rep = .f. 1, 15, ** 662 ..s66 dsk 173 .+s32. dsk 174 +* xa_voa = .f. 1, 16, ** dsk 175 +* xa_db = .f. 17, 1, ** dsn 48 +* xa_rep = .f. 33, 32, ** dsk 177 ..s32 663 .+s37. 664 +* xa_voa = .f. 1, 16, ** 665 +* xa_db = .f. 17, 1, ** dsn 49 +* xa_rep = .f. 33, 32, ** 667 ..s37 668 .+s10. dsn 50 +* xa_voa = .f. 1, 15, ** dsn 51 +* xa_rep = .f. 19, 18, ** dsn 52 +* xa_db = .f. 16, 1, ** 672 ..s10 673 674 +* xa_arf = xa_voa ** $ rename with edit later. 675 .+defer. 676 $ -dops- 677 678 $ the -dops- array is used if deferring is set to hold 679 $ operations that have been deferred until a later time. these 680 $ operations are linked via the -dr_out- field of the dummy 681 $ register which is the output of an operation. 682 683 $ fields in -dops-. 684 685 +* dp_inp1 = .f. 01, 8, ** $ first input. 686 +* dp_inp2 = .f. 09, 8, ** $ second input. 687 +* dp_inp3 = .f. 17, 8, ** $ third input. 688 +* dp_oup = .f. 25, 8, ** $ output. 689 .+s10 +* dp_op = .f. 57, 8, ** $ operation code dsk 178 .+s32 +* dp_op = .f. 33, 8, ** $ operation code dsk 179 .+s37 +* dp_op = .f. 33, 8, ** $ operation code 690 .+s66 +* dp_op = .f. 33, 8, ** $ operation code 691 +* dp_chain = .f. 41, 8, ** $ points to next free entry. 692 +* dp_nargs = .f. 49, 8, ** $ number of arguments (0,1,2, or 3) 693 694 +* dopssz = $ size of dops 695 .+s10 72 dsk 180 .+s32 64 dsk 181 .+s37 64 696 .+s66 60 697 ** 698 699 size dops(dopssz); dims dops(dopsdim); 700 701 ..defer 702 703 $ operands in the code generator are passed as dummy registers. 704 $ these dummy registers point to dummy words and dummy items. 705 $ a dummy item is, in a sense, a local copy of the -voa- entry 706 $ for that variable (if it is a variable). there is one dummy 707 $ word for each word of an item that has been used and there 708 $ may be many dummy registers for each word. one dummy register 709 $ for each word. 710 711 $ the dummy items, words, and, registers and chained and link 712 $ to and from each other. the information contained in each 713 $ block is that information which is common for all blocks 714 $ under it. 715 716 $ fields of -ditem-. 717 718 /* 719 di_chain is pointer to voa if di_baseblk is zero, or to voa 720 if di_baseblk is nonzer. 721 di_syze is item size. 722 di_scon is on if item is short constant (1 to 18 bits), in which 723 case di_cval is constant value. 724 di_nwords is number of machine words in item. 725 di_count is number of users of item. 726 di_addrreg is nonzero if address of item is in machine reg addrreg 727 di_out is deferred output ptr for dop. 728 di_luse is number of drops. 729 di_lword is start of -dword- chain. 730 di_mblk is machine block for item. 731 di_scon is nonzero if item is short constant, in which case 732 di_cval contains constant value. 733 di_mw is nonzero for multi-word item. 734 di_real is nonzero for real, or floating point, item. 735 di_baseblk is nonzero if di_chain points to baseblock, not voa. 736 di_array is nonzero if item is array. 737 di_temp is nonzero if item is temporary. 738 di_const is nonzero if item is constant. 739 di_var is nonzero if item is variable. 740 di_ldrop is nonzero if last use in voa. 741 di_anum is nonzero if item if procedure argument, and value gives 742 argument number. 743 */ 744 745 +* di_luseminus1val = 4b'ff' ** $ to avoid overflow problem. dsb 66 .+s10. rkb 13 +* scs = 18 ** $ short constant size. dsb 67 +* di_chain = .f. 01, 12, ** dsb 68 +* di_syze = .f. 13, 11, ** dsb 69 +* di_cval = .f. 127, 18, ** dsb 70 +* di_nwords = .f. 42, 08, ** dsb 71 +* di_count = .f. 50, 08, ** dsb 72 +* di_addrreg = .f. 61, 05, ** dsb 73 +* di_out = .f. 118, 08, ** dsb 74 +* di_luse = .f. 76, 08, ** dsb 75 +* di_lword = .f. 84, 08, ** dsb 76 +* di_mblk = .f. 92, 08, ** dsb 77 +* di_scon = .f. 100, 01, ** dsb 78 +* di_mw = .f. 101, 01, ** dsb 79 +* di_real = .f. 102, 01, ** dsb 80 +* di_baseblk = .f. 103, 01, ** dsb 81 +* di_array = .f. 104, 01, ** dsb 82 +* di_temp = .f. 105, 01, ** dsb 83 +* di_const = .f. 106, 01, ** dsb 84 +* di_var = .f. 107, 01, ** dsb 85 +* di_ldrop = .f. 109, 01, ** dsb 86 +* di_anum = .f. 110, 08, ** dsb 87 ..s10 dsk 182 .+s32. rkb 14 +* scs = 16 ** $ short constant size. dsk 183 +* di_chain = .f. 1, 16, ** $ ptr to -voa- or -baseblock-. dsk 184 +* di_syze = .f. 17, 16, ** $ length in bits of item. dsk 185 +* di_cval = .f. 33, 16, ** $ short constant value. dsk 186 +* di_nwords = .f. 49, 8, ** $ number of words in item. dsk 187 +* di_count = .f. 57, 8, ** $ number of users of item. dsk 188 +* di_addrreg = .f. 65, 8, ** $ address register for item. dsk 189 +* di_out = .f. 73, 8, ** $ deferred output of -dop-. dsk 190 +* di_luse = .f. 81, 8, ** $ number of drops. dsk 191 +* di_lword = .f. 89, 8, ** $ head of -dword- chain. dsk 192 +* di_mblk = .f. 97, 8, ** $ machine block of item. dsk 193 +* di_scon = .f. 105, 1, ** $ 'item is short constant' dsk 194 +* di_mw = .f. 106, 1, ** $ 'item is multi-word' dsk 195 +* di_real = .f. 107, 1, ** $ 'item is floating-point' dsk 196 +* di_baseblk = .f. 108, 1, ** $ 'item is in base block' dsk 197 +* di_array = .f. 109, 1, ** $ 'item is array' dsk 198 +* di_temp = .f. 111, 1, ** $ 'item is temporary' dsk 199 +* di_const = .f. 112, 1, ** $ 'item is constant' dsk 200 +* di_var = .f. 113, 1, ** $ 'item is variable' dsk 201 +* di_ldrop = .f. 115, 1, ** $ 'last use in -voa-' dsk 202 +* di_anum = .f. 121, 8, ** $ argument number. dsk 203 ..s32 dsk 204 .+s37. rkb 15 +* scs = 16 ** $ short constant size. dsk 205 +* di_chain = .f. 1, 16, ** $ ptr to -voa- or -baseblock-. dsk 206 +* di_syze = .f. 17, 16, ** $ length in bits of item. dsk 207 +* di_cval = .f. 33, 16, ** $ short constant value. dsk 208 +* di_nwords = .f. 49, 8, ** $ number of words in item. dsk 209 +* di_count = .f. 57, 8, ** $ number of users of item. dsk 210 +* di_addrreg = .f. 65, 8, ** $ address register for item. dsk 211 +* di_out = .f. 73, 8, ** $ deferred output of -dop-. dsk 212 +* di_luse = .f. 81, 8, ** $ number of drops. dsk 213 +* di_lword = .f. 89, 8, ** $ head of -dword- chain. dsk 214 +* di_mblk = .f. 97, 8, ** $ machine block of item. dsk 215 +* di_scon = .f. 105, 1, ** $ 'item is short constant' dsk 216 +* di_mw = .f. 106, 1, ** $ 'item is multi-word' dsk 217 +* di_real = .f. 107, 1, ** $ 'item is floating-point' dsk 218 +* di_baseblk = .f. 108, 1, ** $ 'item is in base block' dsk 219 +* di_array = .f. 109, 1, ** $ 'item is array' dsk 220 +* di_temp = .f. 111, 1, ** $ 'item is temporary' dsk 221 +* di_const = .f. 112, 1, ** $ 'item is constant' dsk 222 +* di_var = .f. 113, 1, ** $ 'item is variable' dsk 223 +* di_ldrop = .f. 115, 1, ** $ 'last use in -voa-' dsk 224 +* di_anum = .f. 121, 8, ** $ argument number. dsk 225 ..s37 746 .+s66. rkb 16 +* scs = 18 ** $ short constant size. 747 +* di_chain = .f. 01, 12, ** 748 +* di_syze = .f. 13, 11, ** 749 +* di_cval = .f. 24, 18, ** 750 +* di_nwords = .f. 42, 08, ** 751 +* di_count = .f. 50, 08, ** 752 +* di_addrreg = .f. 61, 05, ** 753 +* di_out = .f. 66, 08, ** 754 +* di_luse = .f. 76, 08, ** 755 +* di_lword = .f. 84, 08, ** 756 +* di_mblk = .f. 92, 08, ** 757 +* di_scon = .f. 100, 01, ** 758 +* di_mw = .f. 101, 01, ** 759 +* di_real = .f. 102, 01, ** 760 +* di_baseblk = .f. 103, 01, ** 761 +* di_array = .f. 104, 01, ** 762 +* di_temp = .f. 105, 01, ** 763 +* di_const = .f. 106, 01, ** 764 +* di_var = .f. 107, 01, ** 765 +* di_ldrop = .f. 109, 01, ** 766 +* di_anum = .f. 110, 08, ** 767 ..s66 768 769 +* ditemsz = $ size of -ditem- 770 .+s10 144 dsk 226 .+s32 128 dsk 227 .+s37 128 771 .+s66 120 772 ** 773 774 size ditem(ditemsz); dims ditem(ditemdim); 775 776 777 $ fields in -dword-. 778 vaxa 92 .+s66. vaxa 93 .+t10. 779 +* dw_word = .f. 1, 18, ** $ word number in item (from left). 780 +* dw_madr = .f. 19, 18, ** $ machine addr or register offset. 781 +* dw_next = .f. 37, 8, ** $ index of next -dword- in chain. 782 +* dw_freg = .f. 45, 8, ** $ index of first -dreg- in chain. vaxa 94 ..t10 vaxa 95 .+t32. vaxa 96 +* dw_madr = .f. 1, 32, ** vaxa 97 +* dw_word = .f. 33, 18, ** vaxa 98 +* dw_next = .f. 61, 8, ** vaxa 99 +* dw_freg = .f. 69, 8, ** vaxa 100 ..t32 vaxa 101 ..s66 dsn 53 .+s10. dsn 54 .+t10. dsn 55 +* dw_word = .f. 1, 18, ** $ word number in item (from left). dsn 56 +* dw_madr = .f. 19, 18, ** $ machine addr or register offset. dsn 57 +* dw_next = .f. 37, 8, ** $ index of next -dword- in chain. dsn 58 +* dw_freg = .f. 45, 8, ** $ index of first -dreg- in chain. dsn 59 ..t10 dsn 60 .+t32. dsn 61 +* dw_madr = .f. 1, 32, ** dsn 62 +* dw_word = .f. 33, 18, ** dsn 63 +* dw_next = .f. 61, 8, ** dsn 64 +* dw_freg = .f. 69, 8, ** dsn 65 ..t32 dsn 66 ..s10 dsk 228 .+s32. dsk 229 +* dw_word = .f. 1, 16, ** $ word number in item (from left) dsk 230 +* dw_next = .f. 17, 8, ** $ pointer to next -dword- in chain. dsk 231 +* dw_freg = .f. 25, 8, ** $ pointer to -dreg-. dsk 232 +* dw_madr = .f. 33, 32, ** $ machine addr or register offset. dsk 233 ..s32 dsk 234 .+s37. dsk 235 +* dw_word = .f. 1, 16, ** $ word number in item (from left) dsk 236 +* dw_next = .f. 17, 8, ** $ pointer to next -dword- in chain. dsk 237 +* dw_freg = .f. 25, 8, ** $ pointer to -dreg-. dsk 238 +* dw_madr = .f. 33, 32, ** $ machine addr or register offset. dsk 239 ..s37 784 +* dwordsz = $ size of -dword- 785 .+s10 72 dsk 240 .+s32 64 dsk 241 .+s37 64 vaxa 102 .+s66. vaxa 103 .+t10 60 vaxa 104 .+t32 120 vaxa 105 ..s66 787 ** 788 789 size dword(dwordsz); dims dword(dworddim); 790 791 792 $ fields in -dreg-. 793 794 $ dr_item - pointer to -ditem- 795 $ dr_word - pointer to -dword-. 796 $ dr next - next -dreg- in chain. 797 $ dr_reg - machine register containing form. 798 .+s10. 799 +* dr_item = .f. 01, 08, ** 800 +* dr_word = .f. 09, 08, ** 801 +* dr_next = .f. 17, 08, ** 802 +* dr_reg = .f. 25, 08, ** 803 ..s10 dsk 242 .+s32. dsk 243 +* dr_item = .f. 1, 8, ** $ pointer to -ditem-. dsk 244 +* dr_reg = .f. 9, 8, ** $ machine register containing form. dsk 245 +* dr_word = .f. 17, 8, ** $ pointer to -dword-. dsk 246 +* dr_next = .f. 25, 8, ** $ next -dreg- in chain. dsk 247 ..s32 dsk 248 .+s37. dsk 249 +* dr_item = .f. 5, 8, ** $ pointer to -ditem-. dsk 250 +* dr_word = .f. 17, 8, ** $ pointer to -dword-. dsk 251 +* dr_next = .f. 25, 8, ** $ next -dreg- in chain. dsk 252 +* dr_reg = .f. 33, 8, ** $ machine register containing form. dsk 253 ..s37 804 .+s66. 805 +* dr_item = .f. 01, 08, ** 806 +* dr_word = .f. 09, 08, ** 807 +* dr_next = .f. 17, 08, ** 808 +* dr_reg = .f. 25, 08, ** 809 ..s66 810 dsk 254 +* dregsz = dsk 255 .+s66 60 dsk 256 .+s10 36 dsk 257 .+s32 32 dsk 258 .+s37 64 dsk 259 ** 812 813 size dreg(dregsz); dims dreg(dregdim); 814 815 $ -reglis- 816 817 $ the entries is this table correspond to the real machine 818 $ register. they contain information used to allocate the 819 $ real machine registers to the dummy registers. 820 821 +* rl_content = .f. 01, 09, ** $ pointer to -dreg- that is 822 $ 'in' this register or, for 823 $ base types, the -madr/1024-. 824 +* rl_type = .f. 16, 04, ** $ type of item in register. 825 +* rl_subtype = .f. 16, 03, ** $ sub-type of item 826 +* rl_perm = .f. 19, 01, ** $ 'value is permanently in reg' 827 +* rl_hold = .f. 20, 01, ** $ hold bit. 828 +* rl_addrhold = .f. 21, 01, ** $ address hold bit. 829 +* rl_usevalue = .f. 22, 11, ** $ value for lru allocation 830 831 +* reglissz = 32 ** $ size of -reglis- array. 832 833 size reglis(reglissz); dims reglis(rhihi); $ machine reg. list 834 835 836 $ values of -rl_type- field. 837 $ note that the order of these types corresponds to increasing 838 $ priority of the register. 839 840 +* rt_dead = 00 ** $ register is empty 841 +* rt_address = 01 ** $ register contains address of variable 842 +* rt_need = 02 ** $ register contains needed value 843 +* rt_live = 03 ** $ register contains only copy of data 844 +* rt_liveaddr = 04 ** $ register contains only copy of address 845 846 $ the rest of the types are the same as above but are 847 $ permanently assigned. 848 849 +* rt_permresv = 8 ** $ permanent reserved value. (r13, etc.) 850 +* rt_perm = 8 + rt_need ** 851 +* rt_permlive = 8 + rt_live ** 852 853 854 855 $ -lablist-. 856 857 $ the -lablist- array is used to hold information about 858 $ labels in the routine being compiled. 859 860 .+labopt. $ used only if this option is on. 861 +* ll_count = .f. 1, 16, ** $ number of times label used. 862 +* ll_def = .f. 17, 16, ** $ -voa- operation defining label. 863 ..labopt 864 865 +* lablistsz = 32 ** $ size of -lablist- 866 867 size lablist(lablistsz); dims lablist(lablistdim); 868 size lablistptr(ps); $ pointer into -lablist-. 869 870 $ -pdlist-. 871 872 $ the -pdlist- array is used to hold the parameter lists 873 $ for all calls generated by the program. 874 dsk 260 .-s32. 875 +* pd_madr = .f. 1, 18, ** $ machine address of parameter. 876 +* pd_block = .f. 19, 8, ** $ machine block of parameter. dsk 261 .+s32. dsn 67 +* pd_madr = .f. 1, 32, ** dsn 68 +* pd_block = .f. 33, 32, ** dsk 264 ..s32 877 878+* pdlistsz = $ size of pdlist. 879 .+s10 ws dsn 69 .+s32 64 881 .+s66 ws 882** 883 size pdlist(pdlistsz); dims pdlist(pdlistdim); 884 size pdlistp(ps); $ pointer to pdlist. 885 vaxa 106 .+t10 size longname(.sds. 6); $ long routine names. vaxa 107 .+t32 size longname(.sds. namelen); $ long routine names. 887 dims longname(vo_sasin); $ highest entry used. 888 889 data $ initialize -longname- array. 890 +* long(en, n) = longname(en) = n ** 891 $ since only standard form on s10, need full set of multi-word 892 $ comparison procedures. 893 vaxa 108 .+t10. 894 long(do_add, 'iadd$m'): 895 long(do_sub, 'isub$m'): 896 long(do_mul, 'imul$m'): 897 long(do_div, 'idiv$m'): 898 long(do_and, 'band$m'): 899 long(do_eq, 'bequ$m'): 900 long(do_ne, 'bneq$m'): 901 long(do_lt, 'bles$m'): 902 long(do_ge, 'bgeq$m'): 903 long(do_or, 'bior$m'): 904 long(do_exor, 'bxor$m'): 905 long(do_not, 'bnot$m'): 906 long(do_fb, 'bfir$m'): dsc 10 long(do_nb, 'bnum$m'): 908 909 long(vo_sasin, 'casi$m'): 910 long(vo_ccat, 'ccat$m'): 911 long(vo_in, 'cind$m'): 912 long(vo_seq, 'cequ$m'): 913 long(vo_sext, 'cext$m'): 914 long(vo_easin, 'easi$m'): 915 long(vo_eext, 'eext$m'); vaxa 109 ..t10 vaxa 110 .+t32. vaxa 111 long(do_add, 'iadd$mw'): vaxa 112 long(do_sub, 'isub$mw'): vaxa 113 long(do_mul, 'imul$mw'): vaxa 114 long(do_div, 'idiv$mw'): vaxa 115 long(do_and, 'band$mw'): vaxa 116 long(do_eq, 'bequ$mw'): vaxa 117 long(do_ne, 'bneq$mw'): vaxa 118 long(do_lt, 'bles$mw'): vaxa 119 long(do_ge, 'bgeq$mw'): vaxa 120 long(do_or, 'bior$mw'): vaxa 121 long(do_exor, 'bxor$mw'): vaxa 122 long(do_not, 'bnot$mw'): vaxa 123 long(do_fb, 'bfir$mw'): vaxa 124 long(do_nb, 'bnum$mw'): vaxa 125 vaxa 126 vaxa 127 long(vo_sasin, 'casi$mw'): vaxa 128 long(vo_ccat, 'ccat$mw'): vaxa 129 long(vo_in, 'cind$mw'): vaxa 130 long(vo_seq, 'cequ$mw'): vaxa 131 long(vo_sext, 'cext$mw'): vaxa 132 long(vo_easin, 'easi$mw'): vaxa 133 long(vo_eext, 'eext$mw'); vaxa 134 ..t32 916 917 918 size moptab(.sds. 3); dims moptab(num_mo); 919 data 920 moptab(mo_ban) = 'ban': 921 moptab(mo_bfb) = 'bfb': 922 moptab(mo_bnb) = 'bnb': 923 moptab(mo_bno) = 'bno': 924 moptab(mo_bor) = 'bor': 925 moptab(mo_bxo) = 'bxo': 926 moptab(mo_cal) = 'cal': 927 moptab(mo_ceq) = 'ceq': 928 moptab(mo_cge) = 'cge': 929 moptab(mo_cgt) = 'cgt': 930 moptab(mo_cle) = 'cle': 931 moptab(mo_clt) = 'clt': 932 moptab(mo_cne) = 'cne': 933 moptab(mo_iab) = 'iab': 934 moptab(mo_iad) = 'iad': 935 moptab(mo_iao) = 'iao': 936 moptab(mo_ico) = 'ico': 937 moptab(mo_idi) = 'idi': 938 moptab(mo_idt) = 'idt': 939 moptab(mo_ieq) = 'ieq': dsj 43 moptab(mo_ifr) = 'ifr': 940 moptab(mo_ige) = 'ige': 941 moptab(mo_igt) = 'igt': 942 moptab(mo_ile) = 'ile': 943 moptab(mo_ilt) = 'ilt': 944 moptab(mo_imo) = 'imo': 945 moptab(mo_imt) = 'imt': 946 moptab(mo_imu) = 'imu': 947 moptab(mo_ine) = 'ine': 948 moptab(mo_isi) = 'isi': 949 moptab(mo_iso) = 'iso': 950 moptab(mo_isu) = 'isu': 951 moptab(mo_jeq) = 'jeq': 952 moptab(mo_jge) = 'jge': 953 moptab(mo_jgt) = 'jgt': 954 moptab(mo_jle) = 'jle': 955 moptab(mo_jlt) = 'jlt': 956 moptab(mo_jmn) = 'jmn': vaxa 135 .+t10 moptab(mo_jmp) = 'jmp': vaxa 136 .+t32 moptab(mo_jmp) = 'jma': 958 moptab(mo_jne) = 'jne': 959 moptab(mo_lda) = 'lda': 960 moptab(mo_ldf) = 'ldf': 961 moptab(mo_ldl) = 'ldl': 962 moptab(mo_ldr) = 'ldr': 963 moptab(mo_ldw) = 'ldw': eaa 75 .+t20. eaa 76 moptab(mo_lla) = 'lla': eaa 77 ..t20 964 moptab(mo_lpr) = 'lpr': 965 moptab(mo_mvw) = 'mvw': dsu 61 moptab(mo_mvx) = 'mvx': 966 moptab(mo_rab) = 'rab': 967 moptab(mo_rad) = 'rad': 968 moptab(mo_rco) = 'rco': 969 moptab(mo_rdi) = 'rdi': 970 moptab(mo_req) = 'req': 971 moptab(mo_ret) = 'ret': dsj 44 moptab(mo_rfi) = 'rfi': 972 moptab(mo_rge) = 'rge': 973 moptab(mo_rgt) = 'rgt': 974 moptab(mo_rle) = 'rle': 975 moptab(mo_rlt) = 'rlt': 976 moptab(mo_rmo) = 'rmo': 977 moptab(mo_rmu) = 'rmu': 978 moptab(mo_rne) = 'rne': 979 moptab(mo_rsi) = 'rsi': 980 moptab(mo_rsu) = 'rsu': dsj 45 moptab(mo_rtr) = 'rtr': 981 moptab(mo_spr) = 'spr': 982 moptab(mo_stf) = 'stf': 983 moptab(mo_stl) = 'stl': vaxa 137 .+t10 moptab(mo_str) = 'str': vaxa 138 .+t32 moptab(mo_xjm) = 'xjm': 985 moptab(mo_stw) = 'stw': 986 moptab(mo_zeb) = 'zeb': eaa 78 .+t20. eaa 79 moptab(mo_hba) = 'hba': eaa 80 moptab(mo_hbb) = 'hbb': eaa 81 moptab(mo_hbc) = 'hbc': eaa 82 ..t20 987 moptab(mo_zew) = 'zew'; 988 989 $ -baseblock- 990 991 $ this table is used to create a map of the base block 992 $ addressed by base. it is a hashed table containing addresses, 993 $ some local variables, some temporaries, parameter lists, 994 $ and single-word constants. it uses a link for hash clashes 995 $ and is threaded by order of address in block. (note that this 996 $ corresponds to the order in which entries are inserted into 997 $ this table.) 998 999 1000 $ fields of -baseblock-. 1001 1002 .+s10. 1003 +* bb_chain = .f. 01, 09, ** $ next entry in block by address 1004 +* bb_link = .f. 10, 09, ** $ link for hash clashes. 1005 +* bb_type = .f. 19, 03, ** $ type of item in block. 1006 +* bb_nwords = .f. 22, 05, ** $ length (in words) of item. 1007 +* bb_bptr = .f. 37, 11, ** $ back pointer. (-dreg- or -voa-) 1008 +* bb_pointer = .f. 48, 11, ** $ pointer depending on type. 1009 +* bb_addr = .f. 59, 10, ** $ offset of item in base block. 1010 ..s10 dsk 266 .+s32. dsk 267 +* bb_chain = .f. 01, 09, ** $ next entry in block by address dsk 268 +* bb_link = .f. 10, 09, ** $ link for hash clashes. dsk 269 +* bb_type = .f. 19, 03, ** $ type of item in block. dsk 270 +* bb_nwords = .f. 22, 05, ** $ length (in words) of item. dsk 271 +* bb_bptr = .f. 33, 11, ** $ back pointer. (-dreg- or -voa-) dsk 272 +* bb_pointer = .f. 44, 11, ** $ pointer depending on type. dsk 273 +* bb_addr = .f. 55, 10, ** $ offset of item in base block. dsk 274 ..s32 1011 .+s66. 1012 +* bb_chain = .f. 01, 09, ** $ next entry in block by address 1013 +* bb_link = .f. 10, 09, ** $ link for hash clashes. 1014 +* bb_type = .f. 19, 03, ** $ type of item in block. 1015 +* bb_nwords = .f. 22, 05, ** $ length (in words) of item. 1016 +* bb_bptr = .f. 27, 11, ** $ back pointer. (-dreg- or -voa-) 1017 +* bb_pointer = .f. 38, 11, ** $ pointer depending on type. 1018 +* bb_addr = .f. 49, 10, ** $ offset of item in base block. 1019 ..s66 1020 1021 +* baseblocksz = $ size of entry in bits. 1022 .+s10 72 dsk 275 .+s32 64 dsk 276 .+s37 64 1023 .+s66 60 1024 ** 1025 1026 +* baseblockdim = 511 ** 1027 +* baseblockprime = 499 ** 1028 size baseblock(baseblocksz); dims baseblock(baseblockdim); 1029 1030 $ types used in -bb_type- 1031 +* bt_label = 1 ** $ label address. -bb_pointer- is -lablist- 1032 $ index. 1033 +* bt_const = 2 ** $ entry is single-word constant. 1034 $ -bb_pointer- is -val- index. 1035 +* bt_plist = 3 ** $ parameter list. -bb_pointer- points 1036 $ into -pdlist-. 1037 1038 +* bt_temp = 4 ** $ temporary. 1039 +* num_bt = 4 ** 1040 1041 pic 9 .+s32. pic 10 size pic_case(ps); data pic_case=no; pic 11 size pic_char(cs); pic 12 ..s32 1042 1043 1044 1045 size xx(1); data xx=yes; $ to force correct s37 load order. 1046 $ this required since otherwise dead code that sould be 1047 $ retained for correct load is eliminated. 1048 call asmini; $ initialize everything. 1049 while xx; $ loop until stopped. 1050 call setup; $ initialize for generation. 1051 call asmprog; $ generate code. 1052 call endsubr; $ terminate code for routine. 1053 end while; 1054 1055 $ ***** no exit to here expected. **** 1056 1057 exitcode = 0; call asmexit; $ for lked. 1058 dsb 89 .+s10 end prog start; dsk 277 .+s32 end prog start; dsb 90 .+s66 end subr start; 1 .=member asmini 2 subr asmini; $ code generator initialization. 3 $ this is the initialization routine for the code generator 4 $ which is entered first. it reads parameters, initializes 5 $ some tables, and opens files. 6 size i(ps), j(ps), flg(1); $ temporaries. 7 size cval(ws); $ constant value for 'pc' option. 8 size lnta(ps); dims lnta(8); $ array for -lntime-. 9 size lcp_opt(1); $ compiler parameter listing option. 11 size optval(.sds. namelen); $ options desired. dsn 70 size voafilename(.sds.filenamelen); $ -voa- file name. dsn 71 size codefilename(.sds.filenamelen); $ loader input file name. dsn 72 size appstr(.sds. getapp_len); $ actual parameter string. 14 15 call lstime(comptime); 16 dsq 67 call getipp(ats_opt, 'ats=1/0'); $ get time stamp option. dsq 68 17 $ generate local names for global blocks. 18 file ocsfile title=ocs, access=string, linesize=80; 19 do i = bl_global to mbadim; 20 put ocsfile ,column(1) ,'g' :i,i(2,2); 21 mblknames(i) = .s. 1, 3, ocs; 22 end do; 23 call ocsput(0, 2); $ clear code string. 24 25 $ read parameters. dsn 73 .+s10 call getspp(voafilename, 'voa=*.voa/'); dsk 278 .+s32 call getspp(voafilename, 'voa=voa.tmp/,'); dsb 92 .+s66 call getspp(voafilename, 'voa=voa/'); 28 dsn 74 .+s10 call getspp(codefilename, 'code=*.mac/'); dsk 280 .+s32 call getspp(codefilename, 'code=little.cod/'); dsb 95 .+s66 call getspp(codefilename, 'code=code/'); 30 call getspp(optval, 'opt=dfl/'); 31 $ [ds 2 jun 78 optimizations on by default, as they 32 $ were enabled for nyu checkout.] 33 .+defer. 34 .+ifopt opt_f = ('f' .in. optval) ^= 0; 35 ..defer opt_d = ('d' .in. optval) ^= 0 ! opt_f; 36 .+labopt opt_l = ('l' .in. optval) ^= 0; 37 38 .+trace. $ process trace parameter. 39 call getspp(optval, 'trace=/acdorv'); 40 trace_a = ('a' .in. optval) ^= 0; 41 trace_c = ('c' .in. optval) ^= 0; 42 trace_d = ('d' .in. optval) ^= 0; 43 trace_l = ('l' .in. optval) ^= 0; 44 trace_o = ('o' .in. optval) ^= 0; 45 trace_r = ('r' .in. optval) ^= 0; 46 trace_v = ('v' .in. optval) ^= 0; 47 48 trace_any = (trace_a ! trace_c ! trace_d ! trace_l ! trace_o ! 49 trace_r ! trace_v); 50 ..trace 51 vaxa 139 .+t10. 52 $ parameter unv names universal file. if not null, then 53 $ each t10 procedure will begin with search ufn 54 $ command where ufn is universal file name. 55 56 call getspp(univfilename, 'unv=t10mac/'); dsp 28 dsp 29 $ parameter end permits generation of end directive at end dsp 30 $ of code file, for example end=prg yields endprg as last line dsp 31 $ if end=0 specified, no special last line is generated. dsp 32 call getspp(end_opt,'end=prg/seg'); dsp 33 vaxa 140 ..t10 57 dsq 69 .+t32 call getipp(iv_opt, 'iv=0/1'); $ integer overflow enable 58 call getipp(lcs_opt, 'lcs=1/0'); 59 call getipp(lcp_opt, 'lcp=1/0'); dsvb 14 .+s32u. dsq 71 $ quiet listing by default. dsq 72 call getipp(lcs_opt, 'lcs=0/1'); dsq 73 call getipp(lcp_opt, 'lcp=0/1'); dsvb 15 ..s32u 60 eaa 83 .+t20. eaa 84 call getspp(nsheap_prm,'nsheap=/nsheap'); eaa 85 if .len. nsheap_prm then $ if want dynamic heap eaa 86 nsheap_opt = 1; eaa 87 call stuc(nsheap_prm); $ fold name to primary case eaa 88 call getspp(nsheap_org,'nshorg=^o2000001/'); eaa 89 else eaa 90 nsheap_opt = 0; eaa 91 end if; eaa 92 ..t20 dsu 62 .+t32h. dsu 63 call getspp(nsheap_prm,'nsheap=/nsheap'); dsu 64 if .len. nsheap_prm then $ if want dynamic heap dsu 65 nsheap_opt = 1; dsu 66 else dsu 67 nsheap_opt = 0; dsu 68 end if; dsu 69 ..t32h dsk 281 call getipp(fag_opt, 'fag=0/1'); dst 37 call getipp(nspage_opt,'nspage=0/1'); $ page alignment opt. dsn 75 dsn 76 $ get actual parameters specified. dsn 77 call getapp(appstr, getapp_len); dsn 78 61 $ open files. 63 file voafile access=read, title=voafilename; dsk 282 call dropsio(voafile, i); $ set to delete voa file. eaa 93 .+s66 rewind voafile; 65 if codefile ^= 2 then $ if separate code file. 66 file codefile access=put, title=codefilename,linesize=80; 67 end if; dst 38 .+enp. dst 39 call getspp(enpfilename, 'enp=0/t.rep'); dsta 1 call getipp(enporg, 'enporg=0/0'); dst 41 if enpfilename .sne. '0' then $ if enp file wanted dst 42 enpopt = yes; dst 43 file enpfile access= get, title=enpfilename; dst 44 while 1; dst 45 size enpent(.sds. 20); dst 46 size enptyp(.sds. 16); dst 47 get enpfile ,skip :enptyp,a(16) :enpent,a(20); dst 48 if filestat(enpfile,end) then quit; end if; dst 49 if enptyp .sne. ' p ' then cont; end if; dst 50 countup(enptot, enpmax, 'enp readin'); dst 51 size enpl(ps),brkc(ws); dst 52 enpl = brkc(enpent,1, 1r,); dst 53 if enpl>0 then .len. enpent = enpl; end if; dst 54 enpara(enptot) = enpent; dst 55 end while; dst 56 end if; dst 57 ..enp dst 58 68 $ set up titling. 69 call ltitlr(assemblerlevel); 70 call stitlr(0, 'little compilation - code generation phase.'); 71 72 $ list parameters, if desired. 73 if lcp_opt then $ parameter list wanted. 74 call stitlr(1, 'parameters for this code generation.'); dsn 80 dsn 81 if .len. appstr then $ if any explicitly specified. dsn 82 textl(appstr) endl endl dsn 83 end if; dsn 84 75 textl('voa file name: voa = ') textl(voafilename) 76 textl('. code file name: code = ') textl(codefilename) 81 charl(1r.) endl 82 vaxa 141 .+t10. dsp 34 textl('end line: end = ') dsp 35 textl(end_opt) dsp 36 textl('.' ) 83 if (.len. univfilename) then $ if universal file. 84 textl('universal file: unv = ') dsp 37 textl(univfilename) textl('.') 86 end if; dsp 38 endl eaa 94 eaa 95 .+t20. eaa 96 textl('nsheap: nsheap = ') textl(nsheap_prm) eaa 97 textl('. nsheap origin: nshorg = ') eaa 98 textl(nsheap_org) textl('.') endl eaa 99 ..t20 dsu 70 .+t32h. dsu 71 textl('nsheap: nsheap = ') textl(nsheap_prm) dsu 72 textl('.') endl dsu 73 ..t32h eaa 100 vaxa 142 ..t10 87 textl('optimizations to be performed: opt = ') 88 .+defer. if (opt_d) charl(1rd) 89 .+ifopt if (opt_f) charl(1rf) 90 ..defer 91 .+labopt if (opt_l) charl(1rl) 92 if (opt_d+opt_l = 0) charl(1r0) 93 94 .+trace. 95 if trace_any then $ print trace options. 96 textl('. tracing options: trace = ') 97 if (trace_a) charl(1ra) 98 if (trace_c) charl(1rc) 99 if (trace_d) charl(1rd) 100 if (trace_l) charl(1rl) 101 if (trace_o) charl(1ro) 102 if (trace_r) charl(1rr) 103 if (trace_v) charl(1rv) 104 end if; 105 ..trace 106 dsk 283 charl(1r.) endl dsq 75 textl('time stamp: ats = ') dst 59 intlp(ats_opt, 1) textl('. nspage: nspage = ') dst 60 intlp(nspage_opt,1) charl(1r.) dst 61 endl dsk 284 dsk 285 textl('functions alter globals: fag = ') intlp(fag_opt, 1) dsq 77 .+t32 textl('. iv: iv = ') intlp(iv_opt,1) dsk 286 charl(1r.) endl endl 108 end if; 109 110 111 112 $ if statistics are desired, write headers. 113 if lcs_opt then $ write header. 114 call stitlr(1, 'statistics and error messages.'); 115 endl textl('procedure') 116 tabl(30) textl('const') 117 tabl(40) textl(' base') 118 tabl(50) textl(' code') 119 tabl(60) textl('local') 120 tabl(70) textl('temps') 121 tabl(90) textl('module') 122 tabl(100) textl('global') 123 endl endl 124 else $ write different subtitle. 125 call stitlr(1, 'error messages.'); 126 end if; 127 128 129 130 131 end subr asmini; 1 .=member setup 2 subr setup; $ initialize to process a new subroutine. 3 $ this routine is called to begin processing a new routine. 4 $ it initializes tables, reads data from the -voa- file, and 5 $ emits the initial routine starting code. in addition, this 6 $ routine decides which variables or base addresses should be 7 $ permanently assigned to a register and assigns them if any 8 $ are to be assigned. 9 size i(ps), j(ps), k(ps); $ temporaries. 10 size namep(ps); $ pointer to routine name. 11 size numargs(ps); $ number of arguments to routine. 12 size hap(ps); $ -ha- pointer. 13 size haent(hasz); $ -ha- entry. 14 size reg(ps); $ -dreg- used for peramanent value. 15 size flg(1); $ flag array for permanent assignment. 16 size addr(mps); $ machine address. 17 size mblk(ps); $ machine block. 18 size tempaddr(mps); $ address in temporary block. 19 size numglobs(ps); $ number of globals. 20 size totcnt(ps); $ total count for modes. 21 size lastcnst(ps); $ last constant entry so far. dsj 46 size moff(mosize); $ address offset. 22 23 24 $ the first thing to do is to initialize the tables used for 25 $ generating code for a routine. 26 27 $ first, clear the -dreg- table by putting all entries on the 28 $ free chain. 29 do i = 1 to dregdim-1; $ scan over all but last. 30 dr_next dreg(i) = i+1; $ chain to next. 31 end do; 32 dr_next dreg(dregdim) = 0; $ show end of chain. 33 dregfree = 1; $ show first is free. 34 35 $ clear the -dword- table. 36 do i = 1 to dworddim-1; $ scan all but last. 37 dw_next dword(i) = i+1; $ build free chain. 38 end do; 39 dw_next dword(dworddim) = 0; $ show last in chain. 40 dwordfree = 1; $ show first is free. 41 42 $ do the same for -ditem-. 43 do i = 1 to ditemdim-1; $ scan all but last. 44 di_out ditem(i) = i+1; $ chain to next. 45 end do; 46 di_out ditem(ditemdim) = 0; $ show last in chain. 47 ditemfree = 1; $ show first is free. 48 49 do i = 1 to baseblockdim; baseblock(i) = 0; end do; 50 51 baseblockfree = baseblockdim; 52 basefirst = 0; baselast = 0; baselastaddr = 1; 53 54 codethis = 0; $ clear estimated length of code. 55 56 .+defer. $ clear -dops-. 57 if opt_d then $ if optimization is in effect. 58 do i = 1 to dopsdim-1; $ chain all to next. 59 dp_chain dops(i) = i+1; $ chain one to next. 60 end do; 61 dp_chain dops(dopsdim) = 0; $ chain last to nothing. 62 dopfree = 1; $ show first is on free chain. 63 end if; 64 ..defer 65 66 67 $ clear machine register table. 68 do i = r0 to rhihi; 69 reglis(i) = 0; $ show register dead. 70 end do; 71 72 reguseval = 0; $ reset register usage count. vaxa 143 vaxa 144 vaxa 145 .+t32 regmask = 0; $ show no registers used yet. 73 74 +* checkvof(ptr, lim) = $ check file dimensions. 75 ptr = vf_hi vof; $ get dimension 76 if (vf_hi vof > lim) call aermey(3); $ if data too big. 77 ** 78 79 80 $ read the -voa- file. loop until a routine trailer 81 $ frame is read. 82 while yes; $ loop until 'quit'ed. 83 read voafile, vof; $ get header frame. 84 if filestat(voafile,end) then $ if premature end 85 textl('error - premature end of voa file') endl 86 call aermey(37); $ need new error number. 87 end if; 88 go to l(vf_code vof) in 0 to num_vh; $ select frame type. 89 90 /l(vh_eof)/ $ end-of-file frame. 91 exitcode = 0; call asmexit; $ call termination routine. 92 93 /l(vh_hdr)/ $ file header frame. 94 cont while; $ ignore this frame. 95 96 /l(vh_asm)/ $ routine header frame. 97 lablistptr = vf_lablistp vof; $ get highest lablist value. 98 if (lablistptr>lablistdim) call aermey(39); $ if overflow. 99 do i = 1 to lablistptr; lablist(i) = 0; end do; $ clear. 100 namep = vf_sub1 vof; $ -ha- pointer of routine name. 101 subrtype = vf_sub2 vof; $ get routine type. 102 numargs = vf_subrargs vof; $ get number of arguments. 103 ha_0 = vf_ha0 vof; $ ha index of constant zero. 104 ha_1 = vf_ha1 vof; $ ha index of constant one. 105 .+trace trace_c = vf_listcode vof; $ set code trace option. 106 .+trace trace_any = (trace_c ! trace_d ! trace_o ! trace_r ! 107 .+trace trace_a ! trace_l ! trace_v); 108 cont while; $ got all needed info. 109 110 /l(vh_voa)/ $ -voa- frame. 111 checkvof(voaptr, voadim); $ check and set dimension. 112 read voafile, voa(1) to voa(voaptr); 113 voaptr = voaptr-1; $ adjust pointer to last used. 114 cont while; 115 116 /l(vh_ha)/ $ -ha- frame. 117 $ the -ha- is transmitted packed. must read it in 118 $ packed format into the top of the -ha- and then unpack 119 $ it into the bottom of the array. 120 i = hadim - (vf_hi vof) + 1; $ set to place to start. 121 read voafile, ha(i) to ha(hadim); 122 hap = 0; $ initially, start to fill at bottom. 123 do i = i to hadim; $ scan received packed info. 124 haent = ha(i); $ get first packed entry. 125 do j = 1 to ha_zerents haent; $ insert zero entries. 126 hap = hap+1; ha(hap) = 0; 127 end do; 128 hap = hap+1; ha(hap) = haent; $ insert entry. 129 end do; 130 do i = hap+1 to hadim; $ clear rest of -ha-. 131 ha(i) = 0; 132 end do; 133 cont while; 134 135 /l(vh_names)/ $ -names- array frame. 136 checkvof(i, namesdim); $ check and set dimension. 137 read voafile, names(1) to names(i); 138 cont while; 139 140 /l(vh_xarg)/ $ -xarg- frame. 141 checkvof(i, xargdim); $ check and set dimension. 142 read voafile, xarg(1) to xarg(i); 143 cont while; 144 145 /l(vh_val)/ $ -val- array frame. 146 checkvof(valptr, valdim); 147 read voafile, val(1) to val(valptr); 148 cont while; 149 150 /l(vh_mba)/ $ -mba- frame. 151 checkvof(mbaptr, mbadim); 152 read voafile, mba(1) to mba(mbaptr); 153 do i = 1 to num_bl; mba(i) = 0; end do; $ clear special. 154 cont while; 155 156 /l(vh_eos)/ $ end-of-routine frame. 157 quit while; $ exit from loop to continue with initialization. 158 end while; 159 160 161 sdsname(currsubname, namep); $ get current routine name. 162 163 $ reserve parmreg is procedure has parameters. 164 165 if (numargs) rl_type reglis(parmreg) = rt_permresv; 166 167 call eminit(1, numargs, subrtype); $ emit initialization code. 168 dss 18 .+t32u lablorg = lablorg + labluse; 169 $ get a new label and use it for the label for returns. 170 countup(lablistptr, lablistdim, 'lablist'); $ new label. 171 returnlab = lablistptr; $ use this as the return label. 172 lablist(returnlab) = 0; $ clear -lablist- entry. 173 labluse = lablistptr; $ set last use pointer. 174 175 $ must make a pass over the -voa- to do the following: 176 $ 1) allocate all multi-word constants to the constant block. 177 $ 2) allocate all multi-word temporaries to the temp block. 178 $ 3) set flags indicating whether or not an operand can be 179 $ permanently assigned to a register. 180 $ 4) clear -inreg- fields of operands. 181 $ 5) count subroutine calls. 182 $ 6) decrease usage count for a variable for each time it 183 $ appears in subroutine or function calls. 184 $ 7) chain -voa- operations for faster access. 185 $ 8) if label optimization is wanted, indicate where label 186 $ is defined and also count uses of labels. 187 $ 9) change return operations into a goto to the return label. 188 numglobs = 0; 189 numcalls = 0; $ initially no calls. 190 addr = 1; $ set current address in constant block to start. 191 lastcnst = 0; $ show no nulti-word constants yet. 192 tempaddr = 1; $ set current address in temporary block. 193 voahead = 0; $ show nothing in -voa- op chain yet. 194 totcnt = 0; $ no counts. 195 do i = 1 to voaptr; $ scan -voa-. 196 if vv_opb voa(i) then $ this is operation. 197 $ chain in operation. 198 if voahead then $ chain this to last. 199 vv_chain voa(voalast) = i; $ chain this in. 200 else $ this is head of chain. 201 voahead = i; $ put on top of chain. 202 end if; 203 204 voalast = i; $ show this is last one. 205 206 $ check for operation which is subroutine 207 $ or function call. in this case global 208 $ variables must be stored so the number of such calls 209 $ is recorded for computing which variables should 210 $ permanently reside in a register. 211 if vv_opcode voa(i) = vo_scall ! $ if subroutine call. 212 vv_opcode voa(i) = vo_fcall then $ or function call. 213 numcalls = numcalls + 1; $ count the call. dsk 287 if (vv_opcode voa = vo_fcall & fag_opt = no) dsk 288 cont do; $ skip functions if globals not altered. 215 $ loop over all arguments. 216 if (vv_arglen voa(i) = 0) cont do; $ if no args. 217 do j = vv_argbeg voa(i) to vv_argbeg voa(i) 218 + vv_arglen voa(i) - 1; 219 k = xa_voa xarg(j); 220 $ if not constant or temporary and has a usage 221 $ count, then decrement by two to allow for 222 $ work needed for saving and restoring. 223 if (vv_temb voa(k)) cont do; $ skip temps. 224 if (vv_const voa(k)) cont do; $ and consts. 225 if (vv_mblk voa(k) >= bl_global) cont do; 226 if (vv_varnuse voa(k) < 2) cont do; 227 228 $ else, decrement. 229 vv_varnuse voa(k) = vv_varnuse voa(k) - 2; 230 end do; 231 232 233 $ change returns to gotos. 234 elseif vv_opcode voa(i) = vo_return then $ this is one. 235 vv_opcode voa(i) = vo_goto; $ set new operation. 236 vv_inp1 voa(i) = returnlab; $ set target label. 237 .+labopt. 238 if (opt_l) $ count uses of label. 239 ll_count lablist(returnlab) = 240 ll_count lablist(returnlab) + 1; 241 elseif vv_opcode voa(i) = vo_lab then $ this defines. 242 if (opt_l) ll_def lablist(vv_inp1 voa(i)) = i; 243 else $ this may use a label so call routine. 244 if (opt_l) call labcount(i, 1); $ count upwards. 245 ..labopt 246 end if; 247 cont do; $ done with this entry. 248 end if; 249 250 vv_ppdata voa(i) = no; $ initially. 251 vv_inreg voa(i) = 0; $ show not in a register. 252 if (vv_type voa(i) = 0) cont do; $ skip routine entries. 253 if vv_const voa(i) then $ if constant. 254 $ if this is single word constant that can 255 $ be represented safely in octal. rkb 17 if vv_syze voa(i) <= scs $ if short, 257 & tmctab(vv_lextype voa(i)) <= tmc_b then 258 if (vv_signbit voa(i)) vv_syze voa(i) = mws; 259 $ can have in register if not short constant. 260 vv_ppdata voa(i) = vv_syze voa(i) > mps; 261 else $ multi-word constant. 262 vv_mblk voa(i) = bl_const; $ in constant block. 263 k = vv_syze voa(i); $ copy in case overflow. 264 addr = addr + (k + (mws-1))/mws; 265 vv_madr voa(i) = addr-1; $ set offset. 266 $ chain constants via -dimn-. 267 if lastcnst then $ if not first in chain. 268 vv_dimn voa(lastcnst) = i; $ chain last to this. 269 else $ first in chain. 270 mb_chain mba(bl_const) = i; $ put in head. 271 end if; 272 lastcnst = i; $ set last to this. 273 end if; 274 elseif vv_temb voa(i) then $ this is temporary. 275 if vv_syze voa(i) > mws then $ is multi-word temp. 276 vv_mblk voa(i) = bl_temp; $ set block. 277 k = vv_syze voa(i); $ copy in case overflow. 278 tempaddr = tempaddr + (k + (mws-1))/mws; 279 vv_madr voa(i) = tempaddr-1; $ set address. 280 end if; 281 else $ not constant or temporary. 282 .-vvfrs vv_frsdata voa(i) = 0; $ clear head of data chain 283 .+vvfrs vvfrsdata(i) = 0; $ clear head of data chain 284 if vv_isafnct voa(i) = no then $ ok. 285 if vv_syze voa(i) <= mws & vv_dimn voa(i) = 0 then rkb 18 if (vv_argno voa(i)=0) vv_ppdata voa(i) = yes; 287 if (vv_mblk voa(i) >= bl_global) 288 numglobs = numglobs + 1; 289 end if; 290 $ list address in generated code. 291 if (i^=1) call eminit(2, i, i); 292 293 end if; 294 295 end if; 296 297 $ if can address as data, increment the total count for 298 $ that arithmetic mode. 299 if (vv_ppdata voa(i)) $ do increment. 300 totcnt = totcnt + 301 vv_varnuse voa(i); $ add to count. 302 303 end do; 304 305 $ if the total count for any mode is too small, set it to 306 $ a higher value to avoid trivial variables in registers. 307 $ also decrease counts by number of globals*number of calls. 308 totcnt = idim(totcnt, numglobs*numcalls); 309 if (totcnt < 20) totcnt = 20; 310 311 if (voahead) vv_chain voa(voalast) = 0; $ end the chain. 312 313 314 $ next, end the constant chain, if it exists, and then 315 $ allocate space in the base block for the addresses of the 316 $ parameters to the current routine. 317 mb_len mba(bl_const) = addr-1; $ set length of const block. 318 mb_len mba(bl_temp) = tempaddr-1; $ set length of temp block. 319 if (lastcnst) vv_dimn voa(lastcnst) = 0; $ end last chain. 320 321 $ see if the current routine is a function. if so, then 322 $ allocate space for the return value in the base block. 323 if subrtype = st_fnct then $ this is a function. 324 vv_mblk voa(1) = bl_base; $ show in base block. 325 i = (vv_syze voa(1) + mws-1) / mws; 326 vv_madr voa(1) = i; 327 baselastaddr = baselastaddr + i; 328 call eminit(2, 1, 1); 329 end if; 330 dsu 74 .+t32h. dsu 75 $ see if nsheap option on. if so, see if nsheap nameset dsu 76 $ referenced in current procedure, in which case indicate dsu 77 $ references to the nameset are to be made dynamic. dsu 78 nsheap_this = no; $ assume no refrences possible dsu 79 ..t32h 331 do i = bl_global to mbaptr; 332 if (mb_used mba(i) = no) cont do; 333 sdsname(dopsname, mb_ha mba(i)); 334 mbanames(i) = dopsname; dsu 80 .+t32h. dsu 81 if nsheap_opt then dsu 82 if dopsname .seq. nsheap_prm then $ if heap block dsu 83 nsheap_blk = i; dsu 84 nsheap_this = yes; dsu 85 end if; dsu 86 end if; dsu 87 ..t32h 335 end do; 336 337 $ check to see if variables should be permanently assigned 338 $ to registers. 339 340 $ see if any data can be permanently assigned. 341 $ will try to get at most 5 items permanently assigned to 342 $ registers. 343 i = 0; dsu 88 .+t32h. dsu 89 $ if heap block, reserve two registers which will contain the dsu 90 $ byte and word address of the start of the nameset during dsu 91 $ execution of the procedure. dsu 92 if nsheap_this then $ if need to reserve registers. dsu 93 nsheapreg_w = rhi; dsu 94 nsheapreg_b = rhi-1; dsu 95 i = 2; $ indicate registers reserved. dsu 96 end if; dsu 97 ..t32h 344 until i >= 5 ; $ loop until no more. 345 346 $ see if there is something that can be permanent. 347 call getperm(totcnt/20+1); $ get variable. 348 349 $ if none, set flag and exit. 350 if (voaep = 0) quit until; $ if none. 351 352 $ otherwise, assign to next register. 353 assign(reg, va_spec); $ assign to a dummy register. 354 vaxa 146 .+t10. 355 rl_content reglis(rlo+i) = reg; $ show owner. 356 rl_type reglis(rlo+i) = rt_perm; $ set type. vaxa 147 ..t10 vaxa 148 .+t32. vaxa 149 rl_content reglis(rhi-i) = reg; $ show owner. vaxa 150 rl_type reglis(rhi-i) = rt_perm; $ set type. vaxa 151 ..t32 vaxa 152 vaxa 153 357 vv_ppdata voa(voaep) = no; $ show cannot be perm again. 358 i = i+1; $ count register used. 359 end until; 360 vaxa 154 .+t10 nextgfree = rlo+i; $ show next available register. vaxa 155 .+t32 nextgfree = rhi-i; $ show next available register. 362 363 $ if label optimization wanted, call routine. 364 .+labopt if (opt_l) call labfixup; 365 366 367 pdlistp = 0; $ no parameter lists yet. 368 369 $ emit the code to initialize a routine. 370 371 372 call eminit(3, 1, 2); 373 374 $ finally, load permanent data values. 375 do i = rlo to rhi; $ scan registers. 376 if rl_type reglis(i) = rt_perm then $ should load data. dsj 47 getvar(rl_content reglis(i), gd_intoreg, j, i, moff); 378 rl_perm reglis(i) = yes; $ show to be permanent. 379 end if; 380 end do; 381 382 .+trace. $ generate trace code. 383 if (trace_d) call dumpdregs; 384 if (trace_r) call dumpmregs; 385 ..trace 386 387 end subr setup; 1 .=member eminit 2 subr eminit(case, nargs, ptype); $ emit initial code for proc. 3 $ emit initial t10 code for procedure. 4 size case(ps); $ case. 5 size nargs(ps); $ number of arguments 6 size ptype(ps); $ procedure type. 7 size i(ps); $ loop index. dsw 9 size p(ps); $ position 8 size d(cs); $ access/definition code character. 9 size dops(mcs); $ t10 op to put out. 10 size blk(ps); $ machine block. 11 size dop(ps); dsw 10 size blkname(.sds. namelen); $ block name 12 13 go to l(case) in 1 to 3; 14 /l(1)/ $ to start procedure. 15 16 .s. 1, 80, ocs = ''; $ clear ocs. vaxa 156 .+t10. 17 $ if universal file specified, put out search directive. 18 if .len. univfilename then 19 put ocsfile ,column(9) ,'search' 20 ,column(17) :univfilename,a; 21 call ocsput(0,0); 22 end if; vaxa 157 ..t10 23 24 .s. 9, 3, ocs = 'dsp'; 25 put ocsfile ,column(17) 26 :currsubname,a , 27 ',' :nargs,i ,',' :ptype,i ,x(30) dsq 78 ,column(33) dsq 79 ,tmcscom $ comment dsq 80 ,' * * ' :currsubname,a(0,1) 29 ,' * *'; 30 call ocsput(0, 0); $ put code line. 31 vaxa 158 .+t10 put ocsfile ,column(1) ,'; compiled by t10.' dsq 81 .+t32. dsq 82 put ocsfile ,column(1) ,tmcscom ,' compiled ' dsq 83 .+t32u ,'t32u by ' dsq 84 .+t32v ,'t32v by ' dsq 85 ..t32 dsq 86 ; dsq 87 if ats_opt then $ if want time stamp dsq 88 put ocsfile ,assemblerlevel ,' on ' dsq 89 :comptime,a; dsq 90 end if; 35 call ocsput(0,0); $ put line. 36 .s. 1, 80, ocs = ''; $ clear ocs. dss 19 .+t32u. dss 20 call renblk(bl_base); dss 21 call renblk(bl_const); dss 22 call renblk(bl_temp); dss 23 call renblk(bl_local); dsw 11 $ avoid 'g--' symbols for unix; they are too much for 'as'. dsw 12 do i = bl_global to mbaptr; dsw 13 sdsname(blkname, mb_ha mba(i)); $ get name dsw 14 while 1; $ map $ in name to _ dsw 15 p = '$' .in. blkname; dsw 16 if (p=0) quit; $ if no more $'s in name. dsw 17 .ch. p, blkname = 1r_; $ map $ to _. dsw 18 end while; dsw 19 mblkname(i) = blkname; $ substitute expanded name. dsw 20 end do; dss 24 ..t32u 37 return; 38 /l(2)/ $ put out address of variable as comment. 39 i = nargs; 40 sdlname(dopsname, vv_naym voa(i)); $ get (long) name. dsq 91 put ocsfile ,column(1) dsq 92 ,tmcscom dsq 93 ,'=' dsq 94 ,column(9) 42 :dopsname,a(12) ,x; $ put name 43 if vv_argno voa(i) then $ if argument. vaxa 160 .+t10 put ocsfile ,'@+' :vv_argno voa(i)-1,i vaxa 161 .+t10 ,'(r' :parmreg-1,i ,')'; dsq 95 .+t32. dsq 96 put ocsfile dsq 97 ,tmcsind dsq 98 ,'+' dsq 99 :vv_argno voa(i) * mcpw,i ,'(ap)'; dsq 100 ..t32 46 else $ otherwise, write block, offset. 47 put ocsfile :mblkname(vv_mblk voa(i)),a ,'+' vaxa 163 .+t10 :vv_madr voa(i)-1,i; $ put offset. vaxa 164 .+t32 :(vv_madr voa(i)-1) * mcpw,i; $ put offset. 49 end if; 50 call ocsput(0,0); 51 return; 52 /l(3)/ $ put out nameset declarations. vaxa 165 .+t10. 53 $ put out nameset declarations, dnd for defined namesets, 54 $ dna for accessed namesets. eaa 102 eaa 103 .+t20. eaa 104 $ see if nsheap option on. if so, see if nsheap nameset eaa 105 $ referenced in current procedure, in which case indicate eaa 106 $ references to the nameset are to be extended. eaa 107 nsheap_this = no; $ assume no references possible. eaa 108 nsheap_blk = 0; $ assume no references. eaa 109 if nsheap_opt then eaa 110 do i = bl_global to mbaptr; eaa 111 sdsname(blkname, mb_ha mba(i)); $ get name. eaa 112 call stuc(blkname); $ make upper case. eaa 113 if blkname .sne. nsheap_prm then cont do; end if; eaa 114 $ here if found eaa 115 nsheap_blk = i; eaa 116 nsheap_this = yes; eaa 117 quit do; eaa 118 end do; eaa 119 eaa 120 if nsheap_this then $ if references eaa 121 $ add extra descriptive line if extended addressing eaa 122 put ocsfile ,column(1) , '; extended addressing for ' eaa 123 :nsheap_prm,a eaa 124 ,' (g' :nsheap_blk,i ,')' eaa 125 ,' with origin ' :nsheap_org,a ,skip; eaa 126 call ocsput(0,0); $ put line. eaa 127 .s. 1,80, ocs = ''; eaa 128 end if; eaa 129 end if; eaa 130 ..t20 55 do i = bl_global to mbaptr; $ loop over global namesets dsu 98 .+t20 if nsheap_this & (i=nsheap_blk) then cont do; end if; 56 if mb_def mba(i) then d = 1rd; $ if defined. 57 elseif mb_used mba(i) then d = 1ra; $ if access. 58 else cont do; $ skip if neither. 59 end if; 60 sdsname(dopsname, (mb_ha mba(i))); $ get block name. 61 .s. 9, 2, ocs = 'dn'; 62 put ocsfile ,column(11) :d,r(1) 63 ,column(17) :dopsname,a ,',' 64 :mblkname(i),a ,',' :mb_len mba(i),i ; 65 call ocsput(0, 0); 66 end do; 67 $ reserve internal blocks. 68 do i = 1 to 3; 69 if i=1 then blk = bl_const; dop = 1rr; 70 elseif i=2 then blk=bl_temp; dop = 1rw; 71 elseif i=3 then blk=bl_local; dop = 1rw; end if; 72 if (mb_len mba(blk)=0) cont do; 73 .s. 9, 2, ocs = 'db'; 74 .ch. 11, ocs = dop; 75 put ocsfile, column(17) 76 :mblkname(blk),a ,',' $ internal block name. 77 :mb_len mba(blk),i; 78 call ocsput(0, 0); $ put code line. 79 end do; vaxa 166 ..t10 80 $ indicate start of code phase. 81 put ocsfile ,column(9), 'dsc' 82 ,column(17) :currsubname,a; $ indicate start of code. 83 call ocsput(0, 0); $ put code. 84 put ocsfile ,column(9) ,'ent' 85 ,column(17) :currsubname,a; 86 call ocsput(0,0); $ put line. dst 62 .+enp. dst 63 if enpopt then $ if enp op wanted dst 64 enpnum = 0; dst 65 do i = 1 to enptot; dst 66 if enpara(i) .seq. currsubname then $ if match dst 67 enpnum = i; dst 68 quit do; dst 69 end if; dst 70 end do; dst 71 if enpnum=0 then enpnotfound = enpnotfound + 1;end if; dst 72 put ocsfile ,column(9) ,'enp' ,column(17) dst 73 :currsubname,a ,',#' :(enpnum+enporg),i; dst 74 call ocsput(0,0); dst 75 end if; dst 76 ..enp dsu 99 .+t32h. dsu 100 if nsheap_this then $ if references to heap. dsu 101 put ocsfile ,column(9) ,'lha' ,column(17) dsu 102 ,'r' :nsheapreg_b-1,i ,',r' :nsheapreg_w-1,i dsu 103 ,',' :mblkname(nsheap_blk),a; dsu 104 call ocsput(0,0); $ emit line dsu 105 end if; dsu 106 ..t32h 87 .s. 1, 80, ocs = ''; 88 end subr eminit; dssa 1 .+t32u. dss 26 subr renblk(bl); dss 27 dss 28 $ for unix only, generate unique name for 'local' blocks. dss 29 $ the second and third characters are put in upper case to reduce dss 30 $ probability of name clash with user names. dss 31 dss 32 size bl(ps); dss 33 size s(.sds. 2); dss 34 s = .s. 2, 2, mblknames(bl); dss 35 .s. 1, 1, s = .s. (totprocs/26)+1, 1, dss 36 'abcdefghijklmnopqrstuvwxyz'; dss 37 .s. 2, 1, s = .s. 1 + totprocs - 26*(totprocs/26), 1, dss 38 'abcdefghijklmnopqrstuvwxyz'; dss 39 call stuc(s); dss 40 .s. 2, 2, mblknames(bl) = s; dss 41 .s. 2, 2, mbanames(bl) = s; dss 42 end subr renblk; dss 43 ..t32u 1 .=member labfix 2 .+labopt. $ routine used for label optimization. 3 subr labfixup; $ clean up branch structure. 4 $ this routine is called when label optimization is 5 $ desired. it will make as many passes over the operations 6 $ in the -voa- as needed. it does the following things: 7 $ 1) deletes unreferenced labels. 8 $ 2) deletes dead code. 9 $ 3) deletes branches to the next statements. 10 $ 4) changes destinations of branches to -goto-s. 11 $ 5) fixes up things like if x,3; goto,4;lab,3 12 $ by changing it to ifnot x,4 13 size voap(ps); $ current index into -voa-. 14 size modfl(1); $ flag indicating if any modifications 15 $ were made in the last pass over -voa-. 16 size lab(ps); $ label being referenced. 17 size i(ps), j(ps); $ temporaries. 18 size targsp(ps); $ pointer to targets array. 19 size targs(ps); dims targs(10); 20 21 $ will loop over the -voa- until the last pass made 22 $ no changes. 23 until modfl = no; 24 modfl = no; $ show no changes in this pass. 25 $ start at top of -voa-. 26 voap = voahead; $ set to first in chain. 27 while voap; $ while more operations. 28 29 $ first check for the case of an if/ifnot followed 30 $ by a goto followed by the target label being defined. 31 until yes; $ quit if not this case. 32 if (vv_opcode voa(voap) ^= vo_if & 33 vv_opcode voa(voap) ^= vo_ifnot) quit until; 34 i = vv_chain voa(voap); $ point to next. 35 if (i = 0) quit until; $ must not be last op. 36 if (vv_opcode voa(i) ^= vo_goto) quit until; 37 38 $ scan and see if any labels following are 39 $ the target of the if/ifnot. 40 j = vv_chain voa(i); $ start at next operation. 41 while j ^= 0 & vv_opcode voa(j) = vo_lab; 42 $ check destination against this label. 43 if vv_inp2 voa(voap) = vv_inp1 voa(j) then 44 $ reduce count of original label. 45 ll_count lablist(vv_inp2 voa(voap)) = 46 ll_count lablist(vv_inp2 voa(voap)) - 1; 47 $ next, switch opcode to inverse operation. 48 vv_opcode voa(voap) = (vo_if+vo_ifnot) - 49 vv_opcode voa(voap); 50 $ change target label. 51 vv_inp2 voa(voap) = vv_inp1 voa(i); 52 $ finally, rechain around -goto-. 53 vv_chain voa(voap) = vv_chain voa(i); 54 modfl = yes; $ show a change was made. 55 quit until; 56 end if; 57 58 j = vv_chain voa(j); $ get next in chain. 59 end while; 60 end until; 61 62 63 $ see what the target of an -if-, -ifnot-, or 64 $ -goto- is pointing to and update if possible. 65 $ note that do not bother to update -goby- 66 $ operations because the payoff would be small. 67 until yes; $ exit if updated or cannot update. 68 $ see if this is an eligable op-code. 69 if vv_opcode voa(voap) = vo_goto ! 70 vv_opcode voa(voap) = vo_if ! 71 vv_opcode voa(voap) = vo_ifnot then $ this is ok. 72 73 $ first, get target label. 74 if vv_opcode voa(voap) = vo_goto 75 then lab = vv_inp1 voa(voap); 76 else lab = vv_inp2 voa(voap); end if; 77 78 $ get defining point of label. 79 i = ll_def lablist(lab); 80 if (i = 0) quit until; $ undefined or return. 81 targsp = 0; $ show no branch targets yet. 82 83 /labloop/ $ follow target. 84 85 $ first see if target is simply the next 86 $ statement. 87 j = vv_chain voa(voap); $ point to next. 88 while j ^= 0 & vv_opcode voa(j) = vo_lab; 89 if j = i then $ it is null branch. dsl 11 if (vv_opcode voa(voap) ^= vo_goto) dsl 12 quit while; 90 $ first, decrease label count. 91 ll_count lablist(lab) = 92 ll_count lablist(lab) - 1; 93 $ unchain the -goto-. 94 if voap = voahead then $ see if top. 95 voahead = vv_chain voa(voap); 96 else $ not start of chain. 97 vv_chain voa(voalast) = $ rechain. 98 vv_chain voa(voap); 99 end if; 100 101 modfl = yes; $ show change made. 102 voap = vv_chain voa(voap); $ next. 103 cont while voap; $ around again. 104 end if; 105 106 j = vv_chain voa(j); $ get next. 107 end while; 108 109 $ check for the case where a -goto- is the 110 $ destination. first skip any labels at the 111 $ branch point. 112 while i ^= 0 & vv_opcode voa(i) = vo_lab; 113 j = i; $ save last value. 114 i = vv_chain voa(i); $ point to next. 115 end while; 116 117 if i = 0 then $ must process this -goto-. 118 i = j; $ back to last label. 119 go to labproc; $ go and process. 120 end if; 121 122 $ do check of destination. 123 if vv_opcode voa(i) = vo_goto then $ special. 124 $ will want to change this to a 125 $ branch to the target so see what the 126 $ target is. 127 j = ll_def lablist(vv_inp1 voa(i)); 128 129 $ if this is undefined, go process 130 $ by getting label from -goto-. 131 if (j = 0) go to labproc; 132 133 i = j; $ point to destination. 134 135 $ must verify that never branched 136 $ to this label in this search. this 137 $ could be caused by an infinite loop. 138 do j = 1 to targsp; $ scan targets. 139 if targs(j) = i then $ duplicate. 140 error('infinite loop found near ' 141 !! 'label', j); 142 quit until; $ skip this. 143 end if; 144 end do; 145 146 $ insert into target array. 147 countup(targsp, 20, 'targs'); $ increment. 148 targs(targsp) = i; $ insert label into array. 149 go to labloop; $ take 'branch'. 150 end if; 151 152 $ look backwards for the next label in the 153 $ chain to use as a destination. 154 j = i; $ point to an operation in the chain. 155 do i = i to 1 by -1; $ scan backwards. 156 if (vv_opb voa(i) = no) cont do; $ not op. 157 if (vv_chain voa(i) ^= j) cont do; 158 j = i; $ show this is in chain. 159 if (vv_opcode voa(i) = vo_lab) quit do; 160 end do; 161 162 /labproc/ $ update the target to point to here. 163 if (i = 0) call aermey(2); $ this is error. 164 165 $ check if target changed. if so, update. 166 if vv_inp1 voa(i) ^= lab then $ it did. 167 modfl = yes; $ show an update done. 168 ll_count lablist(lab)=ll_count lablist(lab)-1; 169 ll_count lablist(vv_inp1 voa(i)) = 170 ll_count lablist(vv_inp1 voa(i)) + 1; 171 172 $ do update of target. 173 if vv_opcode voa(voap) = vo_goto 174 then vv_inp1 voa(voap) = vv_inp1 voa(i); 175 else vv_inp2 voa(voap) = vv_inp1 voa(i); 176 end if; 177 end if; 178 end if; 179 end until; 180 181 182 $ see if the current operation is an unreferenced 183 $ label. delete it if so. 184 if vv_opcode voa(voap) = vo_lab then $ it is a label. 185 if ll_count lablist(vv_inp1 voa(voap)) = 0 then 186 $ this label is unreferenced. so unchain it. 187 modfl = yes; $ show a change made. 188 $ unchain. 189 if voap = voahead then $ this is top. 190 voahead = vv_chain voa(voap); $ set new top. 191 else $ this is not top. 192 vv_chain voa(voalast) = vv_chain voa(voap); 193 end if; 194 dsp 39 i = voap; $ keep pointer to label being deleted. 195 voap = vv_chain voa(voap); $ point to next. dsp 40 $ clear chain so won't be pickup up as valid dsp 41 $ label later. dsp 42 vv_chain voa(i) = 0; $ clear chain. 196 cont while; $ go around again. 197 end if; 198 end if; 199 200 $ see if this is an unconditional -goto- (or -goby-) 201 $ which is followed by something other than a label. 202 $ if so, delete text in between. 203 if vv_opcode voa(voap) = vo_goto ! $ if -goto-. 204 vv_opcode voa(voap) = vo_goby then $ or -goby-. 205 i = vv_chain voa(voap); $ point to next. 206 while i; $ loop until hit end. 207 if (vv_opcode voa(i) = vo_lab) quit while; 208 209 $ -i- points to unreferenced operation. 210 $ will delete it by rechaining so decrement 211 $ any label references of the deleted operation. 212 call labcount(i, -1); $ decrement counts. 213 i = vv_chain voa(i); $ point to next. 214 modfl = yes; $ show a modification was made. 215 end while; 216 217 $ rechain. 218 vv_chain voa(voap) = i; $ this may be same as before. 219 end if; 220 221 222 223 $ finally, go to next operation in -voa-. 224 voalast = voap; $ save pointer to last. 225 voap = vv_chain voa(voap); $ point to next. 226 end while voap; 227 end until modfl; 228 229 230 $ just do a final check on the -return-. see if the last 231 $ operation is a -goto- to the return label. if it is, then 232 $ can just remove it from the chain. 233 if vv_opcode voa(voalast) = vo_goto & $ it is -goto-. 234 vv_inp1 voa(voalast) = returnlab then $ it is this case. 235 236 $ scan backwards for the last operation before this one. 237 do i = voalast to 1 by -1; $ go back. 238 if (vv_opb voa(i) = no) cont do; $ skip data. 239 if vv_chain voa(i) = voalast then $ this is the one. 240 voalast = i; $ show this is last. 241 vv_chain voa(i) = 0; $ show in -voa-. 242 quit do; 243 end if; 244 end do; 245 end if; 246 247 $ if count of return label is zero, no return is done 248 $ from the routine so can clear -returnlab- to suppress 249 $ unneeded code. 250 if (ll_count lablist(returnlab) = 0) returnlab = 0; 251 252 $ finally, clear -lablist- again. 253 do i = 1 to lablistptr; lablist(i) = 0; end do; 254 255 end subr labfixup; 1 .=member labcnt 2 ..labopt 3 .+labopt. $ used only for label optimizations. 4 subr labcount(voap, inc); $ count usage of label. 5 $ this routine is passed a -voa- pointer and an increment. 6 $ it sees if there are any labels referenced (not defined) 7 $ in the operation and increments their counts by the increment 8 $ that it is passed (usually +1 or -1). 9 size voap(ps); $ pointer to operation. 10 size inc(ws); $ increment. 11 size i(ps); $ loop variable. 12 size lab(ps); $ label to decrement. 13 14 lab = 0; $ show no label found yet. 15 16 $ see what type of operation this is. 17 if vv_opcode voa(voap) = vo_goto then $ this references label. 18 lab = vv_inp1 voa(voap); $ get the label. 19 elseif vv_opcode voa(voap) = vo_if ! $ if -if-. 20 vv_opcode voa(voap) = vo_ifnot then $ or -ifnot-. 21 lab = vv_inp2 voa(voap); $ label is here. 22 elseif vv_opcode voa(voap) = vo_goby then $ indexed -goto-. 23 $ this is handled via a loop. 24 do i = vv_argbeg voa(voap) to $ loop over -xarg- entries. 25 vv_argbeg voa(voap) + vv_arglen voa(voap) - 1; 26 ll_count lablist(xa_voa xarg(i)) = $ change count. 27 ll_count lablist(xa_voa xarg(i)) + inc; 28 end do; 29 end if; 30 31 $ if a label was found, change its count. 32 if (lab) ll_count lablist(lab) = ll_count lablist(lab) + inc; 33 34 end subr labcount; 1 .=member getprm 2 ..labopt 3 subr getperm(min); $ assign permanent register. 4 $ this routine scans the -voa- to find the best value 5 $ to permanently assign to a register. 6 size min(ps); $ minimum count needed to assign. 7 size musage(ps); $ highest usage so far. 8 size i(ps); $ index. 9 size usage(ws); $ usage of scanned variable. 10 11 musage = min; $ show 'best' so far. 12 voaep = 0; $ show none assigned. 13 do i = 1 to voaptr; $ scan -voa-. 14 if (vv_opb voa(i)) cont do; $ skip operations. 15 if (vv_ppdata voa(i) = no) cont do; $ skip if not eligible. 16 usage = vv_varnuse voa(i); $ get usage count. 17 if (vv_mblk voa(i) >= bl_global) $ must decrement. 18 usage = usage - numcalls*2; $ allow for number of calls. 19 20 $ see if this is best so far. 21 if (usage < musage) cont do; $ worse. 22 $ else, show this variable is 'better'. 23 voaep = i; musage = usage; 24 end do; 25 26 .+trace. 27 if trace_d then $ print last action. 28 tintl('getperm, voaep', voaep) endl 29 end if; 30 ..trace 31 32 end subr getperm; 1 .=member asmprog 2 subr asmprog; $ scan -voa- operations. 3 $ this is the highest-level routine in -asm- for 4 $ generating the code for a routine. it is responsible 5 $ for looping over the -voa- and calling -emitdop-, the 6 $ next lower-level routine, to issue each -voa- operation 7 $ to be processed. this routine is largely table-driven 8 $ and machine-independent. 9 10 size voptab(ws); $ -voa- operation table. 11 dims voptab(num_vo); $ number of operations. 12 13 $ fields in -voptab-. 14 15 +* vt_ign = .f. 01, 1, ** $ new setting for -ignorevoa- 16 +* vt_storall = .f. 02, 1, ** $ 'must do -storall-' 17 +* vt_xargs = .f. 03, 1, ** $ 'operation has extra args' 18 +* vt_isout = .f. 04, 1, ** $ 'operation has output' 19 +* vt_inv = .f. 05, 1, ** $ 'invert operands' 20 +* vt_nargs = .f. 06, 3, ** $ number of arguments 21 +* vt_dop = .f. 09, 8, ** $ operation to issue 22 +* vt_kind = .f. 17, 5, ** $ operation types 23 24 $ types for -voa- opcodes. 25 +* vk_data = 01 ** +* vk_lab = 09 ** 26 +* vk_ext = 02 ** +* vk_mwbin = 10 ** 27 +* vk_fasin = 03 ** +* vk_sasin = 11 ** 28 +* vk_fcall = 04 ** +* vk_scall = 12 ** 29 +* vk_goby = 05 ** +* vk_sext = 13 ** 30 +* vk_goto = 06 ** +* vk_simp = 14 ** 31 +* vk_if = 07 ** +* vk_xfasin = 15 ** 32 +* vk_io = 08 ** 33 34 +* num_vk = 15 ** $ number of -voa- operation types 35 36 $ macro to initialize -voptab-. 37 38 +* vop(num, typ, dop, nargs, inv, out, xarg, stor, ign) = 39 voptab(num) = typ*4b'10000'+dop*4b'100'+nargs*4b'20'+ 40 inv*1b'10000'+out*1b'1000'+xarg*1b'100'+stor*1b'10'+ign ** 41 42 data $ initialize table. 43 44 $ vop kind dop args inv out xarg stor ign 45 $ --- ---- --- ---- --- --- ---- ---- --- 46 47 vop(vo_add, vk_simp, do_add, 2, no, yes, no, no, no): 48 vop(vo_sub, vk_simp, do_sub, 2, no, yes, no, no, no): 49 vop(vo_gt, vk_simp, do_lt, 2, yes, yes, no, no, no): 50 vop(vo_lt, vk_simp, do_lt, 2, no, yes, no, no, no): 51 vop(vo_ge, vk_simp, do_ge, 2, no, yes, no, no, no): 52 vop(vo_le, vk_simp, do_ge, 2, yes, yes, no, no, no): 53 vop(vo_eq, vk_simp, do_eq, 2, no, yes, no, no, no): 54 vop(vo_ne, vk_simp, do_ne, 2, no, yes, no, no, no): 55 vop(vo_mul, vk_simp, do_mul, 2, no, yes, no, no, no): 56 vop(vo_div, vk_simp, do_div, 2, no, yes, no, no, no): 57 vop(vo_or, vk_simp, do_or, 2, no, yes, no, no, no): 58 vop(vo_and, vk_simp, do_and, 2, no, yes, no, no, no): 59 vop(vo_exor, vk_simp, do_exor, 2, no, yes, no, no, no): 60 vop(vo_nb, vk_simp, do_nb, 1, no, yes, no, no, no): 61 vop(vo_fb, vk_simp, do_fb, 1, no, yes, no, no, no): 62 vop(vo_not, vk_simp, do_not, 1, no, yes, no, no, no): 63 vop(vo_fcall, vk_fcall, do_fcall, 0, no, yes, yes, no, no): 64 vop(vo_scall, vk_scall, do_scall, 0, no, no, yes, yes, no): 65 vop(vo_asin, vk_simp, do_asin, 2, no, no, no, no, no): 66 vop(vo_data, vk_data, 0, 0, no, no, no, no, no): 67 vop(vo_fasin, vk_fasin, do_fasin, 4, no, no, no, no, no): 68 vop(vo_io, vk_io, do_scall, 2, no, no, no, yes, no): 69 vop(vo_return, vk_simp, do_return, 0, no, no, no, yes, yes): 70 vop(vo_fext, vk_ext, do_fext, 3, no, yes, no, no, no): 71 vop(vo_if, vk_if, do_if, 1, no, no, no, yes, no): 72 vop(vo_lab, vk_lab, 0, 0, no, no, no, yes, no): 73 vop(vo_goto, vk_goto, do_goto, 0, no, no, no, yes, yes): 74 vop(vo_goby, vk_goby, do_goby, 1, no, no, no, yes, yes): 75 vop(vo_xload, vk_simp, do_xload, 2, no, yes, no, no, no): 76 vop(vo_xasin, vk_simp, do_xasin, 3, no, no, no, no, no): 77 vop(vo_xfasin, vk_xfasin, do_xfasin, 4, no, no, yes, no, no): 78 vop(vo_ifnot, vk_if, do_ifnot, 1, no, no, no, yes, no): 79 vop(vo_ccat, vk_mwbin, do_scall, 2, no, yes, no, no, no): 80 vop(vo_in, vk_mwbin, do_fcall, 2, no, yes, no, no, no): 81 vop(vo_eext, vk_ext, do_eext, 3, no, yes, no, no, no): 82 vop(vo_sext, vk_sext, do_scall, 3, no, yes, no, no, no): 83 vop(vo_easin, vk_fasin, do_easin, 4, no, no, no, no, no): 84 vop(vo_sasin, vk_sasin, do_scall, 4, no, no, no, no, no): 85 vop(vo_xeasin, vk_xfasin, do_xeasin, 4, no, no, yes, no, no): 86 vop(vo_xsasin, vk_simp, do_xsasin, 4, no, no, yes, no, no): 87 vop(vo_radd, vk_simp, do_radd, 2, no, yes, no, no, no): 88 vop(vo_rsub, vk_simp, do_rsub, 2, no, yes, no, no, no): 89 vop(vo_rgt, vk_simp, do_rlt, 2, yes, yes, no, no, no): 90 vop(vo_rlt, vk_simp, do_rlt, 2, no, yes, no, no, no): 91 vop(vo_rge, vk_simp, do_rge, 2, no, yes, no, no, no): 92 vop(vo_rle, vk_simp, do_rge, 2, yes, yes, no, no, no): 93 vop(vo_req, vk_simp, do_req, 2, no, yes, no, no, no): 94 vop(vo_rne, vk_simp, do_rne, 2, no, yes, no, no, no): 95 vop(vo_rmul, vk_simp, do_rmul, 2, no, yes, no, no, no): 96 vop(vo_rdiv, vk_simp, do_rdiv, 2, no, yes, no, no, no): 97 vop(vo_rusub, vk_simp, do_rusub, 1, no, yes, no, no, no): 98 vop(vo_abs, vk_simp, do_abs, 1, no, yes, no, no, no): dsj 48 vop(vo_float, vk_simp, do_float, 1, no, yes, no, no, no): dsj 49 vop(vo_ifix, vk_simp, do_ifix, 1, no, yes, no, no, no): dsj 50 vop(vo_int, vk_simp, do_ifix, 1, no, yes, no, no, no): dsj 51 vop(vo_aint, vk_simp, do_aint, 1, no, yes, no, no, no): dsj 52 vop(vo_amod, vk_simp, do_amod, 2, no, yes, no, no, no): 99 vop(vo_iabs, vk_simp, do_iabs, 1, no, yes, no, no, no): 100 vop(vo_mod, vk_simp, do_mod, 2, no, yes, no, no, no): 101 vop(vo_sign, vk_simp, do_sign, 2, no, yes, no, no, no): 102 vop(vo_isign, vk_simp, do_isign, 2, no, yes, no, no, no): 103 vop(vo_dim, vk_simp, do_dim, 2, no, yes, no, no, no): 104 vop(vo_idim, vk_simp, do_idim, 2, no, yes, no, no, no): 105 vop(vo_seq, vk_simp, do_seq, 2, no, yes, no, no, no): 106 vop(vo_sne, vk_simp, do_sne, 2, no, yes, no, no, no); 107 108 macdrop(vop) 109 110 size inv(1); $ on if operands should be inverted 111 size xargs(1); $ on if operation has values in -xarg- 112 size storflag(1); $ on if must do 'storall' for op 113 size opkind(ps); $ operation type 114 size ignorevoa(1); $ flag to ignore dead -voa- ops 115 size t1(ps), t2(ps); $ temporaries 116 size i(ps), j(ps); $ loop variables. 117 118 size uio_routs(.sds. 7); $ routine names for unformatted i/o. 119 dims uio_routs(4); $ var/array and input/output vaxa 167 .+t10 data uio_routs = 'rdlv$i', 'rdla$i', vaxa 168 .+t10 'wtlv$i', 'wtla$i'; vaxa 169 .+t32 data uio_routs = 'rdlv$io', 'rdla$io', vaxa 170 .+t32 'wtlv$io', 'wtla$io'; 122 123 124 ignorevoa = no; $ initially don't ignore -voa- ops. 125 126 $ begin loop over -voa-. 127 voaep = voahead; reissuedop = yes; $ set initial status. 128 while yes; $ loop while more in chain. 129 130 $ see if should reissue last operation or if should 131 $ get a new one. 132 if reissuedop then $ must re-issue. 133 reissuedop = no; $ clear flag. 134 vopcode = vv_opcode voa(voaep); $ get -voa- op. code. 135 else $ get new operation. 136 voaep = vv_chain voa(voaep); $ step to next. 137 if (voaep = 0) quit while; $ exit at end of chain. 138 vopcode = vv_opcode voa(voaep); $ get -voa- op. code. 139 $ see if dead operation. 140 if (vopcode ^= vo_lab & ignorevoa) cont while; $ skip. 141 end if; 142 143 $ have a -voa- entry must process. extract 144 $ parameters for this opcode from -voptab-. 145 dopnargs = vt_nargs voptab(vopcode); $ number of args. 146 inv = vt_inv voptab(vopcode); $ 'invert arguments' 147 dophasout = vt_isout voptab(vopcode); $ 'has output' 148 dopcode = vt_dop voptab(vopcode); $ operation to issue 149 xargs = vt_xargs voptab(vopcode); $ 'uses -xarg-' 150 storflag = vt_storall voptab(vopcode); $ 'do -storall-' 151 opkind = vt_kind voptab(vopcode); $ operation type 152 ignorevoa = vt_ign voptab(vopcode); $ new setting 153 154 .+trace. $ generate trace code. 155 if trace_any then $ if any trace, give -voa- pointer. 156 tintl('voaep', voaep) 157 if trace_v then $ print operations. 158 tintl('op', vopcode) tintl('ign', ignorevoa) 159 tintl('kind', opkind) tintl('inv', inv) 160 end if; 161 endl 162 end if; 163 ..trace 164 $ if this is an operation with an output, but the lastuse 165 $ field of the operatin is zero, it means that the output 166 $ will never be used. thus there is no need to issue the 167 $ operation. operations of this type occur mostly in the 168 $ 'a(i) to a(j)' construct in the formatted and unformatted 169 $ io statements. 170 if (dophasout & vv_lastuse voa(voaep) = 0) cont while; 171 172 $ start processing. first, see if must store regs. 173 if (storflag) call storall; $ if need to store regs. 174 175 $ get arguments. 176 go to n(dopnargs) in 0 to 4; $ select number to get. 177 178 /n(4)/ $ four arguments. 179 assign(doplr, va_inp4); $ get fourth argument. 180 /n(3)/ $ three arguments 181 assign(dopkr, va_inp3); $ get third argument. 182 /n(2)/ $ two arguments 183 assign(dopjr, va_inp2); $ get second argument. 184 /n(1)/ $ one argument 185 assign(dopir, va_inp1); $ get first argument. 186 /n(0)/ $ no arguments - fall through to next step. 187 188 $ invert first & second args, if needed. 189 if inv then t1 = dopjr; dopjr = dopir; dopir = t1; end if; 190 $ get output, if it exists. 191 if dophasout then assign(dopor, va_oup); end if; 192 $ get extra arguments (-xarg-), if they exist. 193 if xargs then $ they do exist. 194 dopnx = vv_arglen voa(voaep); $ get number of arguments. 195 do t1 = 1 to dopnx; $ process each argument. 196 assign(dopxr(t1), va_xarg+t1) 197 end do; 198 else 199 dopnx = 0; $ no arguments present. 200 end if; 201 202 $ branch on opcode type. 203 go to l(opkind) in 1 to num_vk; 204 205 /l(vk_simp)/ 206 $ simple operation - issue it. 207 call emitdop; 208 cont while; 209 210 /l(vk_scall)/ 211 $ subroutine call. vaxa 171 .+t10 sdlname(dopsname, vv_naym voa(voaep)); $ get (long) name to c vaxa 172 .+t32 sdsname(dopsname, vv_naym voa(voaep)); $ get name to call. 213 214 $ subroutine call ends basic block if -vv_seblk- flag set. 215 if vv_seblk voa(voaep) then $ want to end block. 216 calldropgl = yes; $ indicate call should drop globals. 217 else $ indicate it shouldn't drop parameters. 218 callnodrop = yes; $ set special case flag. 219 end if; 220 221 call emitdop; $ issue call. 222 223 if (vv_seblk voa(voaep)) call endblock; $ end block. 224 225 cont while; 226 227 /l(vk_fcall)/ 228 $ function call. 229 sdsname(dopsname, vv_naym voa(voaep)) $ get name to call. 230 callnodrop = yes; $ function cant change parameters. dsk 289 calldropgl = fag_opt; $ set whether or not to drop globals. 231 call emitdop; $ issue call 232 cont while; 233 234 /l(vk_data)/ 235 $ -data- statement. in this case call a special 236 $ routine, -asmdata-, to process this -voa- entry. 237 call asmdata; 238 cont while; 239 240 /l(vk_fasin)/ 241 $ .f. field assignment. 242 call emitdop; $ issue it, or old code. 243 cont while; 244 245 /l(vk_io)/ 246 $ unformatted io. this is to be assembled as a subroutine 247 $ call. generate the parameter list and issue a 248 $ subroutine call operation. 249 dopxr(1) = dopjr; $ first is i/o item. 250 assignconst(dopxr(2), syze(dopjr)) $ second is size. 251 if vv_inp3 voa(voaep) then $ if array slice. 252 dopnx = 4; $ show four parameters. 253 assign(dopxr(3), va_inp3) $ third is from inp3. 254 if vv_arglen voa(voaep) then $ get hi value. 255 assign(dopxr(4), va_xarg+1) $ get fourth value. 256 else $ if hi = lo. 257 dopxr(4) = dopxr(3); $ copy value. 258 using(dopxr(3)); $ show additional use. 259 end if; 260 else $ this is simple variable case. 261 dopnx = 2; $ set short parameter list length. 262 end if; 263 $ select routine to call depending on whether this is 264 $ input or output and whether this is slice or not. 265 dopsname = uio_routs(2*(vv_oup voa(voaep)) + (dopnx>2) + 1); 266 dopnargs = 0; dophasout = (dopcode = do_fcall); $ reset. 267 callnodrop = (vv_oup voa(voaep) > 0); dse 14 kill(dopir); 268 call emitdop; $ issue call to i/o routine. 270 $ if input call, this ends block. 271 if (vv_oup voa(voaep) = 0) call endblock; 272 cont while; 273 274 /l(vk_ext)/ 275 $ .f. extract. 276 call emitdop; $ issue operation. 277 cont while; 278 279 /l(vk_if)/ 280 $ -if- or -ifnot- operation. get label number and issue. 281 dopjr = vv_inp2 voa(voaep); $ label is in -vv_inp2-. 282 call emitdop; 283 cont while; 284 285 /l(vk_lab)/ 286 $ label. end basic block and define label. 287 call endblock; 288 labdef(vv_inp1 voa(voaep), yes) $ label is in -vv_inp1-. 289 cont while; 290 291 /l(vk_goto)/ 292 $ goto operation. get label number and issue. 293 dopir = vv_inp1 voa(voaep); $ label is in -vv_inp1-. 294 call emitdop; $ issue operation. 295 cont while; 296 297 /l(vk_goby)/ 298 $ indexed -goto-. copy labels and issue. 299 dopnx = vv_arglen voa(voaep); $ get no. of labels. 300 t1 = vv_argbeg voa(voaep)-1; $ save time in loop. 301 do t2 = 1 to dopnx; $ move in each label. 302 dopxr(t2) = xa_voa xarg(t1+t2); $ copy from -xarg-. 303 end do; 304 call emitdop; $ issue operation. 305 cont while; 306 307 /l(vk_xfasin)/ 308 $ .f. x, y, a(i) op, indexed extract. 309 call emitdop; $ issue operation. 310 cont while; 311 312 /l(vk_mwbin)/ 313 $ .cc. or .in. operation. process as subroutine call. 314 dopsname = longname(vopcode); $ get routine name. 315 dopnx = 3; $ this call has three parameters. 316 dopxr(1) = dopir; dopxr(2) = dopjr; $ first two are inputs. 317 dopxr(3) = dopor; $ third parameter is output. 318 if (vopcode = vo_in) dopnx = 2; $ .in. is function. 319 dopnargs = 0; dophasout = (dopcode = do_fcall); $ reset. 320 call emitdop; $ issue op. 321 cont while; 322 323 /l(vk_sasin)/ 324 $ .s. assignment operation. process as subroutine call. 325 dopsname = longname(vo_sasin); $ get routine name. 326 dopnx = 4; $ set to four parameters. 327 dopxr(1) = dopkr; $ first argument is position. 328 dopxr(2) = doplr; $ second is length. 329 dopxr(3) = dopjr; $ third is source. 330 dopxr(4) = dopir; $ and fourth is target. 331 dopnargs = 0; dophasout = (dopcode = do_fcall); $ reset. 332 call emitdop; $ issue call. 333 cont while; 334 335 /l(vk_sext)/ 336 $ .s. extraction. process as subroutine call. 337 dopsname = longname(vo_sext); $ get routine name. dsh 11 dopnx = 4; $ call has four parameters. 339 dopxr(1) = dopir; $ first is character position. 340 dopxr(2) = dopjr; $ second is length. 341 dopxr(3) = dopkr; $ third is source. 342 dopxr(4) = dopor; $ and fourth is output. 344 dopnargs = 0; dophasout = (dopcode = do_fcall); $ reset. 345 call emitdop; $ issue operation. 346 cont while; 347 348 end while; $ end of main -voa- loop. 349 350 351 macdrop(vt_ign) macdrop(vt_storall) 352 macdrop(vt_xarg) macdrop(vt_isout) 353 macdrop(vt_inv) macdrop(vt_nargs) 354 macdrop(vt_dop) macdrop(vt_kind) 355 356 macdrop(vk_data) macdrop(vk_easin) 357 macdrop(vk_simp) macdrop(vk_ext) 358 macdrop(vk_fasin) macdrop(vk_fcall) 359 macdrop(vk_goby) macdrop(vk_goto) 360 macdrop(vk_if) macdrop(vk_io) 361 macdrop(vk_lab) macdrop(vk_mwbin) 362 macdrop(vk_sasin) macdrop(vk_scall) 363 macdrop(vk_sext) macdrop(vk_xeasin) 364 macdrop(vk_sasin) macdrop(num_vk) 365 366 end subr asmprog; 1 .=member emitdop 2 subr emitdop; $ process deferred-level operations. 3 $ this routine processes each 'deferred' operation sent 4 $ by -asmprog-. the attributes of each operation are 5 $ kept in the table -doptab-. -emitdop- checks to see 6 $ if deferring mode is enabled (compilation option) and 7 $ whether the operation being processed can be deferred. 8 $ if so, the operation will be deferred until its operands 9 $ are needed. next, unless it is flagged as permissable 10 $ for an operand of the current operation to be deferred, 11 $ the current operation is reissueed until the operand at 12 $ fault is evaluated. 13 $ 14 $ if the processor for any operation find that an operand 15 $ has been deferred and the operation that yields the operand 16 $ is not one the enables a special case, that processor will 17 $ branch to label -reissue- to indicate that the current 18 $ operation must be reissueed until the operand can be 19 $ evaluated. the operation to execute is passed in the 20 $ variable -dophold-. note that the processor must 21 $ determine if it must force evaluation of any operands 22 $ before it does 'anything else' that affects status 23 $ of the compilation. 24 25 size doptab(ws); $ deferred operation table. 26 dims doptab(num_do); $ length of table. 27 28 $ fields in -doptab-. 29 30 +* dt_dx = .f. 01, 1, ** $ '-xargs- can be deferred' 31 +* dt_do = .f. 02, 1, ** $ 'output can be deferred' 32 +* dt_d4 = .f. 03, 1, ** $ 'input four can be deferred' 33 +* dt_d3 = .f. 04, 1, ** $ 'input three can be deferred' 34 +* dt_d2 = .f. 05, 1, ** $ 'input 2 can be deferred' 35 +* dt_d1 = .f. 06, 1, ** $ 'input 1 can be deferred' 36 +* dt_defer = .f. 07, 1, ** $ 'operation should be deferrred' 37 +* dt_spcasin = .f. 08, 1, ** $ 'operation is special cased' 38 +* dt_type = .f. 09, 8, ** $ operation type 39 +* dt_aop = .f. 17, 8, ** $ operation to issue 40 41 $ deferred operation types. 42 43 .+eab. 44 +* dk_asin = 01 ** +* dk_simp0 = 14 ** 45 +* dk_bool = 02 ** +* dk_simp1 = 15 ** 46 +* dk_casin = 03 ** +* dk_simp2 = 16 ** 47 +* dk_cext = 04 ** +* dk_xasin = 17 ** 48 $ casin and cext should never occur for s10, but keep codes now. 49 +* dk_easin = 05 ** +* dk_xeasin = 18 ** 50 +* dk_eext = 06 ** +* dk_xload = 19 ** 51 +* dk_fasin = 07 ** +* dk_xsasin = 20 ** 52 +* dk_fcall = 08 ** +* dk_mod = 21 ** 53 +* dk_fext = 09 ** +* dk_dim = 22 ** 54 +* dk_fnb = 10 ** +* dk_return = 23 ** 55 +* dk_goto = 11 ** +* dk_seq = 24 ** 56 +* dk_if = 12 ** +* dk_goby = 25 ** 57 +* dk_not = 13 ** +* dk_comp = 26 ** 58 59 +* num_dk = 26 ** $ number of types. 60 .-eab. 61 .=zzyorg a 62 63 defc(dk_asin) 64 defc(dk_bool) 65 defc(dk_easin) 66 defc(dk_eext) 67 defc(dk_fasin) 68 defc(dk_fcall) 69 defc(dk_fext) 70 defc(dk_goto) 71 defc(dk_if) 72 defc(dk_not) 73 defc(dk_simp0) 74 defc(dk_simp1) 75 defc(dk_simp2) 76 defc(dk_mod) 77 defc(dk_xasin) 78 defc(dk_xeasin) 79 defc(dk_xload) 80 defc(dk_xsasin) 81 defc(dk_return) 82 defc(dk_seq) 83 defc(dk_dim) 84 defc(dk_goby) 85 defc(dk_comp) 86 87 +* num_dk = dk_comp ** 88 ..eab 89 90 $ macro to initialize -doptab-. 91 +* dop(num, df, of, as, typ, aop) = 92 doptab(num) = aop*4b'10000'+typ*4b'100'+ 93 as*4b'80' + df*1b'1000000' + of ** 94 95 data $ build table. 96 97 98 $ dop def 1234ox as type aop 99 $ --- --- ------ -- ---- --- 100 101 dop(do_add, yes, 1b'001100', yes, dk_simp2, ao_iad): 102 dop(do_sub, yes, 1b'001100', yes, dk_simp2, ao_isu): 103 dop(do_lt, yes, 1b'111100', no, dk_comp, ao_ilt): 104 dop(do_ge, yes, 1b'111100', no, dk_comp, ao_ige): 105 dop(do_eq, yes, 1b'111100', no, dk_comp, ao_ieq): 106 dop(do_ne, yes, 1b'111100', no, dk_comp, ao_ine): 107 dop(do_mul, yes, 1b'001100', yes, dk_simp2, ao_imu): 108 dop(do_div, yes, 1b'001100', no, dk_simp2, ao_idi): 109 dop(do_and, yes, 1b'111100', no, dk_bool, ao_ban): 110 dop(do_or, yes, 1b'111100', no, dk_bool, ao_bor): 111 dop(do_exor, yes, 1b'001100', yes, dk_bool, ao_bxo): 112 dop(do_fb, yes, 1b'011100', yes, dk_simp1, ao_bfb): 113 dop(do_nb, yes, 1b'011100', yes, dk_simp1, ao_bnb): 114 dop(do_not, yes, 1b'111100', yes, dk_not, ao_bno): 115 dop(do_fcall, no, 1b'111100', no, dk_fcall, 0): 116 dop(do_scall, no, 1b'111110', no, dk_simp0, 0): 117 dop(do_asin, no, 1b'011110', no, dk_asin, 0): 118 dop(do_fasin, no, 1b'001010', no, dk_fasin, 0): 119 dop(do_return, no, 1b'111110', no, dk_return, 0): 120 dop(do_fext, yes, 1b'101100', no, dk_fext, 0): 121 dop(do_if, no, 1b'111110', no, dk_if, 0): 122 dop(do_goto, no, 1b'111110', no, dk_goto, 0): 123 dop(do_xload, yes, 1b'011100', no, dk_xload, 0): 124 dop(do_xasin, no, 1b'001110', no, dk_xasin, 0): 125 dop(do_xfasin, no, 1b'001011', no, dk_fasin, 0): 126 dop(do_ifnot, no, 1b'111110', no, dk_if, 0): 127 dop(do_eext, no, 1b'000100', no, dk_eext, 0): dsh 12 dop(do_easin, no, 1b'000010', no, dk_easin, 0): dse 15 dop(do_xeasin, no, 1b'001010', no, dk_xeasin, 0): 130 dop(do_xsasin, no, 1b'001010', no, dk_xsasin, 0): 131 dop(do_radd, yes, 1b'001100', yes, dk_simp2, ao_rad): 132 dop(do_rsub, yes, 1b'001100', no, dk_simp2, ao_rsu): 133 dop(do_rlt, yes, 1b'001100', no, dk_simp2, ao_rlt): 134 dop(do_rge, yes, 1b'001100', no, dk_simp2, ao_rge): 135 dop(do_req, yes, 1b'001100', yes, dk_simp2, ao_req): 136 dop(do_rne, yes, 1b'001100', yes, dk_simp2, ao_rne): 137 dop(do_rmul, yes, 1b'001100', yes, dk_simp2, ao_rmu): 138 dop(do_rdiv, yes, 1b'001100', no, dk_simp2, ao_rdi): 139 dop(do_rusub, yes, 1b'011100', yes, dk_simp1, ao_rco): 140 dop(do_abs, yes, 1b'011100', yes, dk_simp1, ao_rab): dsj 53 dop(do_ifix, yes, 1b'011100', yes, dk_simp1, ao_ifr): dsj 54 dop(do_float, yes, 1b'011100', yes, dk_simp1, ao_rfi): dsj 55 dop(do_aint, yes, 1b'011100', yes, dk_simp1, ao_rtr): dsj 56 dop(do_amod, yes, 1b'001100', no, dk_simp2, ao_rmo): 141 dop(do_iabs, yes, 1b'011100', yes, dk_simp1, ao_iab): 142 dop(do_mod, yes, 1b'001100', no, dk_mod , ao_imo): 143 dop(do_sign, yes, 1b'001100', no, dk_simp2, ao_rsi): 144 dop(do_isign, yes, 1b'001100', no, dk_simp2, ao_isi): 145 dop(do_dim, yes, 1b'001100', no, dk_dim , ao_rsu): 146 dop(do_idim, yes, 1b'001100', no, dk_dim , ao_isu): 147 dop(do_seq, no, 1b'001100', no, dk_seq, 0): 148 dop(do_sne, no, 1b'001100', no, dk_seq, 0): 149 dop(do_goby, no, 1b'011111', no, dk_goby, 0); 150 151 $ the deferring entry is one if entry can be deferred and 152 $ zero if it cannot be deferred. if no input, the entry 153 $ is one indicating it can be deferred, but later code 154 $ detects that actually no input. 155 macdrop(dop) 156 157 158 size work(ps), work1(ps); $ temporary operands. 159 size i(ps), j(ps); $ temporary variables 160 size lab(ps); $ temporary label. 161 size type(ps); $ type of operation. 162 size aop(ps); $ operation to issue. 163 size resform(ps); $ result form. 164 size invform(ps); $ inverse forms. 165 size mask(ws); $ mask used for -not-. 166 167 .+trace. $ assembler trace code 168 if trace_o then $ trace is wanted. 169 tintl('dop', dopcode) 170 if dopcode>0 & dopcode<=num_do then 171 textl(' ') textl(dopname(dopcode)) textl(' ') 172 end if; 173 174 tintl('i', dopir) 175 tintl('j', dopjr) tintl('k', dopkr) 176 tintl('l', doplr) tintl('o', dopor) endl 177 end if; 178 ..trace 179 180 .+defer. $ code used only if defering ops. 181 if (opt_d = no) go to issue; $ skip if not defering. 182 183 $ check if any inputs to this operation are unevaluated 184 $ operations and the corresponding input is not allowed 185 $ to be such operations. if so, branch to -reissue- to process 186 $ and evaluate that operation. 187 188 if dt_d1 doptab(dopcode) = no then $ check first operand. 189 dophold = dout(dopir); $ get result op. 190 if (dophold) go to reissue; $ branch if there is one. 191 end if; 192 193 if dt_d2 doptab(dopcode) = no then $ second operand 194 dophold = dout(dopjr); 195 if (dophold) go to reissue; 196 end if; 197 198 if dt_d3 doptab(dopcode) = no then $ third operand 199 dophold = dout(dopkr); 200 if (dophold) go to reissue; 201 end if; 202 203 if dt_d4 doptab(dopcode) = no then $ fourth operand. 204 dophold = dout(doplr); 205 if (dophold) go to reissue; 206 end if; 207 208 if dt_do doptab(dopcode) = no then $ output 209 dophold = dout(dopor); 210 if (dophold) call aermey(31); 211 end if; 212 213 if dopnx then $ check arguments. 214 if dt_dx doptab(dopcode) = no then $ must not be deferred. 215 do i = 1 to dopnx; $ test each one. 216 dophold = dout(dopxr(i)); 217 if (dophold) go to reissue; 218 end do; 219 end if; 220 end if; 221 222 223 $ check if this operation itself is to be deferred. 224 if dt_defer doptab(dopcode) then $ it is to be deferred. 225 if (dopfree = 0) go to issue; $ table is full. 226 227 $ after having verified that a table entry exists, build 228 $ one for this operation. 229 doptr = dopfree; dopfree = dp_chain dops(dopfree); 230 dops(doptr) = 0; $ clear entry. 231 dp_inp1 dops(doptr) = dopir; $ set first input. 232 dp_inp2 dops(doptr) = dopjr; $ set second input. 233 dp_inp3 dops(doptr) = dopkr; $ set third input. 234 dp_oup dops(doptr) = dopor; $ set output. 235 dp_op dops(doptr) = dopcode; $ set operation code. 236 dp_nargs dops(doptr) = dopnargs; $ set number of inputs. 237 .+trace if trace_o then tintl(' *defer*', doptr) endl end if; 238 dout(dopor) = doptr; $ point back to this operation. 239 di_count ditem(dr_item dreg(dopor)) = $ decrement count. 240 di_count ditem(dr_item dreg(dopor)) - 1; 241 242 return; $ done with this case 243 end if; 244 245 /issue/ $ issue operation 246 ..defer 247 248 $ extract fields from descriptive table to determine type 249 $ of processing needed for each operation. 250 type = dt_type doptab(dopcode); $ -goto- index. 251 aop = dt_aop doptab(dopcode); $ operation code for lower-level. 252 253 $ branch on operation type. 254 go to l(type) in 1 to num_dk; 255 256 /l(dk_comp)/ 257 $ comparison operators. merely check for deferred inputs. 258 .+defer. 259 dophold = dout(dopir); $ get first input operation. 260 if (dophold) go to reissue; $ this is not ok. 261 dophold = dout(dopjr); $ check second operand. 262 if (dophold) go to reissue; 263 ..defer 264 go to l(dk_simp2); 265 266 267 /l(dk_simp2)/ 268 $ simple two-operand operations. in this case call 269 $ a routine to check for special cases and just issue 270 $ the operation. 271 272 $ check for multi-word. 273 if (ismw(dopir) ! ismw(dopjr)) go to multi; 274 275 $ see if special case. 276 call special; 277 if (isspecial) go to endop; $ done if so. 278 279 $ set status flags. 280 lastuse(dopir); lastuse(dopjr); lastuse(dopor); $ set status. 281 bin_op(aop, dopor, dopir, dopjr); $ issue operation. 282 go to endop; $ done. 283 284 /l(dk_simp1)/ 285 $ simple unary operation. 286 if (ismw(dopir)) go to multi; $ check for multi-word. 287 lastuse(dopir); lastuse(dopor); $ set status. 288 un_op(aop, dopor, dopir); $ issue operation. 289 go to endop; 290 291 /l(dk_simp0)/ 292 $ operations without arguments. 293 call_op; $ this can only be a call. 294 go to endop; 295 296 /l(dk_bool)/ 297 $ boolean operation (.or., .and., .exor.). 298 $ in this case call a routine to check for special cases. 299 $ otherwise, process as simple operation. 300 301 .+defer. 302 $ since these operands can be deferred must check that they 303 $ are not in this case. this arises in the case of an assignment 304 $ to a variable of a logical expression. i.e., in the 305 $ statement x = (i>j ! a = b); 306 $ in this case, the two comparisons and the -or- will be 307 $ deferred in the hope that this is part of an -if- statement. 308 $ when it is discovered that it is not, the comparisons must 309 $ be performed prior to performing the -or- operation. 310 dophold = dout(dopir); $ check first input. 311 if (dophold) go to reissue; $ force evaluation. 312 dophold = dout(dopjr); $ check second input. 313 if (dophold) go to reissue; $ force evaluation. 314 ..defer 315 316 go to l(dk_simp2); $ else, process as simple operation. 317 318 .+eab. 319 /l(dk_fnb)/ 320 $ .fb. or .nb. operation. 321 $ in this case, a check is made to see if the operand is 322 $ not in standard form. in this (unlikely) case, the operation 323 $ is a no-op and will merely cause a copy, if needed. 324 325 if (ismw(dopir)) go to multi; $ check for multi-word. 326 327 $ this is the normal case. put into register 0 and call 328 $ offline routine. upon return from this routine, the 329 $ result will be in register 0. 330 lastuse(dopir); $ indicate last use in processor. 331 forcezero(dopir, no); $ force value into r0. 332 if dopcode = do_nb then $ set routine name. 333 dopsname = 'nbop$sw'; $ single-word .nb. 334 else $ must be .fb. 335 dopsname = 'fbop$sw'; $ single-word .fb. 336 end if; 337 callnodrop = yes; call_op; $ issue call 338 lastuse(dopor); $ set status. 339 inzero(dopor, no); $ show value in r0. 340 go to endop; $ done. 341 ..eab 342 343 /l(dk_not)/ 344 $ .not. operation. 345 346 .+defer. 347 $ check if input is a deferred operation. this can occur for 348 $ similar reasons as for booleans. 349 dophold = dout(dopir); $ see if deferred result. 350 if (dophold) go to reissue; 351 ..defer 352 353 if (ismw(dopir)) go to multi; $ handle multi-word. 354 355 $ see if this is a full word .not. 356 if syze(dopir) = mws then $ it is full word. 357 lastuse(dopir); lastuse(dopor); $ set status. 358 not_op(dopor, dopir); $ negate. 359 else $need longer code. 360 getdreg(work); $ get a temporary. 361 lastuse(dopir); $ set status. 362 not_op(work, dopir); $ negate input. 363 lastuse(work); lastuse(dopor); $ set status. vaxa 173 .+t10 lpr_op(dopor, work, 0, syze(dopor)); $ extract significant pa vaxa 174 .+t32 assignconst(i, 0); lastuse(i); $ get first bit. vaxa 175 .+t32 assignconst(j, syze(dopor)); lastuse(j); $ get length. vaxa 176 .+t32 lpr_op(dopor, work, i, j); $ extract significant pa 365 end if; 366 367 go to endop; $ done. 368 369 /l(dk_fcall)/ 370 $ function call. issue call and retrieve result from r0. dsk 290 forcezero(0, no); call_op; 372 lastuse(dopor); inzero(dopor, ismw(dopor)); $ get result. 373 go to endop; $ done. 374 375 /l(dk_asin)/ 376 $ simple assignment. 377 $ first, check for multi-word case. in multi-word case, move 378 $ and clear, as appropriate. 379 if ismw(dopir) then $ multi-word output. 380 381 .+defer. 382 $ first, check if input is a deferred operation and force 383 $ evaluation if so. 384 dophold = dout(dopjr); $ check input. 385 if (dophold) go to reissue; 386 ..defer 387 388 if ismw(dopjr) then $ multi-word input too. 389 if nwords(dopjr) < nwords(dopir) then $ must clear 390 getaddr(work, dopir, 1, 0); $ get address. 391 i = nwords(dopir)-nwords(dopjr); $ get no. of words. 392 clear_op(work, i); $ clear first part. 393 else $ will fit. need not clear. 394 i = 0; $ set start offset to zero. 395 end if; 396 getaddr(work, dopir, i+1, 0); $ get proper word. 397 getaddr(work1, dopjr, 1 + idim(nwords(dopjr), $ source. 398 nwords(dopir)), 0); $ place to start move from. 399 lastuse(work1); lastuse(work); $ set status. 400 smove_op(work, work1, nwords(work)-i); $ move source. 401 else $ source is single-word. 402 i = nwords(dopir); $ save for later. 403 getaddr(work, dopir, 1, 0); $ first word. 404 405 $ check for special case of assignment to zero. 406 if isscon(dopjr) & conval(dopjr) = 0 then 407 lastuse(work); $ set status. 408 clear_op(work, i); $ clear. 409 lastuse(dopjr); drop(dopjr); 410 else $ store in word. 411 clear_op(work, i-1); $ clear all but last word. 412 lastuse(dopir); lastuse(dopjr); $ set status. 413 storeword(dopjr, dopir, i, 0); $ store into last word 414 $ clear all but last word. 415 end if; 416 end if; 417 else $ simple, single-word assignment. 418 419 .+defer. 420 $ check for the case where the operation of the input 421 $ is of a very simple type. in this case, the operation 422 $ can be issued with the assignment target as its output 423 $ provided that this is last use of input. this will 424 $ generate more efficient code in many cases. 425 dophold = dout(dopjr); $ get input op. 426 if dophold then $ check if this is special. 427 if (di_ldrop ditem(dr_item dreg(dopjr)) = no ! 428 di_count ditem(dr_item dreg(dopjr)) ^= 1) 429 go to reissue; $ cannot modify output yet. 430 if (dt_spcasin doptab(dp_op dops(dophold)) = no) 431 go to reissue; $ not special operation. 432 433 $ get inputs of this operation and check for 434 $ multi-word. 435 work = dp_inp1 dops(dophold); $ set new first input. 436 work1 = dp_inp2 dops(dophold); $ set new second input. 437 i = dp_nargs dops(dophold); $ save argument count. 438 if (ismw(work)) go to reissue; 439 dsk 291 if dout(work) then $ input is a deferred op. dsk 292 dophold = dout(work); go to reissue; $ reissue it. dsk 293 end if; dsk 294 440 $ check for 1 or 2 operand operation and process. 441 if i=2 then $ 2-operand. 442 if (ismw(work1)) go to reissue; $ not special. dsk 295 if dout(work1) then $ input is a deferred operation dsk 296 dophold = dout(work1); go to reissue; dsk 297 end if; dsk 298 443 using(work1); $ show using this operand. 444 end if; 445 446 $ kill the input operation and reset to issue 447 $ this operation again differently. 448 using(work); $ show using this input. 449 kill(dopjr); $ drop old operation. 450 dopor = dopir; dopir = work; 451 dopjr = work1; dopnargs = i; 452 dopcode = dp_op dops(dophold); dophasout = yes; 453 454 $ if the output is the same as an input, can reset 455 $ live status. 456 if dopor = dopir ! (dopor = dopjr & dopnargs = 2 ) then 457 if dr_reg dreg(dw_freg dword(dr_word dreg(dopir))) rkd 11 ^=0 & (dopor=dopir) then rkd 12 rl_subtype reglis(dr_reg dreg(dopir)) 459 = rt_need; 460 end if; rkd 13 if dopnargs=2 then rkd 14 if dr_reg dreg(dw_freg dword(dr_word dreg(dopjr))) rkd 15 ^=0 & (dopor=dopjr) then rkd 16 rl_subtype reglis(dr_reg dreg(dopjr)) rkd 17 = rt_need; rkd 18 end if; rkd 19 end if; 461 spcdrop = yes; $ set special -clear- operation. 462 463 $ since the usage count of the input should 464 $ be one less then it is, must decrement usage 465 $ count. however, must also pre-decrement the 466 $ lastuse count so that this ihem is not dropped 467 $ too early. 468 di_count ditem(dr_item dreg(dopor)) = 469 di_count ditem(dr_item dreg(dopor)) - 1; 470 di_luse ditem(dr_item dreg(dopor)) = 471 di_luse ditem(dr_item dreg(dopor)) 472 + di_luseminus1val; 473 end if; 474 475 clear(dopor); $ clear output. 476 spcdrop = no; $ clear in case special was set. 477 go to issue; $ re-issue. 478 end if; 479 ..defer 480 481 clear(dopir); $ clear output 482 getword(dopjr, dopjr, nwords(dopjr), 0); $ get proper word. 483 lastuse(dopir); lastuse(dopjr); $ set status 484 move_op(dopir, dopjr); $ move (copy if needed) 485 end if; 486 487 go to endop; $ done. 488 489 /l(dk_fasin)/ 490 $ .f. assignment. 491 $ set register containing first bit and ensure that opcode 492 $ is for a field and not a character assignment. 493 work = dopkr; $ this is case for non-indexed. 494 if (dopcode = do_xfasin) work = dopxr(1); 495 496 call asmfld(work, doplr, dopir, dopjr); $ do .f. assignment. 497 .+defer if (dophold) go to reissue; 498 499 go to endop; $ done. 500 501 /l(dk_return)/ 502 call aermey(4); $ this should not occur. 503 504 /l(dk_fext)/ 505 $ .f. field extraction. 506 call asmfld(dopir, dopjr, dopkr, 0); $ do .f. extract 507 .+defer if (dophold) go to reissue; 508 509 go to endop; $ done. 510 511 /l(dk_xload)/ 512 $ indexed load operation. calculate storage offset and 513 $ either shift or multiply index over. then get desired 514 $ address or value. 515 .+defer. 516 call asmdxchk(dopjr); $ check index. 517 if (dophold) go to reissue; 518 ..defer 519 520 doff = nwords(dopir); call asmxload(dopir, dopjr); 521 522 $ in multi-word case, get address of first (left-most) word. 523 $ in single-word case, get the word. 524 if ismw(dopir) then $ multi-word. 525 if dopjr then lastuse(dopir); lastuse(dopjr); end if; 526 getaddr(work, dopir, doff, dopjr); $ get addr. 527 lastuse(work); lastuse(dopor); $ set status. 528 call moveaddr(dopor, work); $ move address to -dopor-. 529 else $ single-word case. 530 if dopjr then lastuse(dopir); lastuse(dopjr); end if; 531 getword(work, dopir, doff, dopjr); $ get word. 532 $ move to output value. 533 lastuse(dopor); lastuse(work); $ set status. 534 move_op(dopor, work); $ issue move. 535 end if; 536 go to endop; $ done. 537 538 /l(dk_xasin)/ 539 $ indexed assignment. 540 call asmxasin; $ call routine to generate indexed assignment. 541 .+defer if (dophold) go to reissue; $ must reissue prior op. 542 go to endop; $ done. 543 544 /l(dk_eext)/ 545 $ .e. extraction. handle as routine call. 546 dopxr(1) = dopir; $ first parameter is first bit. 547 dopxr(2) = dopjr; $ second parameter is length. 548 dopxr(3) = dopkr; $ third is source. 549 assignconst(dopxr(4), syze(dopkr)) $ length of source. 550 dopxr(5) = dopor; $ target. 551 assignconst(dopxr(6), syze(dopor)) $ length of target. 552 dopsname = longname(vo_eext); $ get routine name. 553 callnodrop = yes; dopnx = 6; call_op; $ call with six parameters. 554 go to endop; $ done. 555 556 /l(dk_easin)/ 557 $ .e. assignment. call off-line routine. 558 dopxr(1) = dopkr; $ first parameter is first bit. 559 dopxr(2) = doplr; $ second is length. 560 dopxr(3) = dopjr; $ third is source. 561 assignconst(dopxr(4), syze(dopjr)) $ length of source. 562 dopxr(5) = dopir; $ target. 563 assignconst(dopxr(6), syze(dopir)) $ length of target. 564 dopsname = longname(vo_easin); $ get routine name. 565 callnodrop = yes; dopnx = 6; call_op; $ call with six parameters. 566 go to endop; $ done. 567 568 /l(dk_xeasin)/ 569 $ .e. indexed assignment. calculate address of target and 570 $ call off-line routine. 571 .+defer. 572 call asmdxchk(dopkr); $ check index. 573 if (dophold) go to reissue; 574 ..defer 575 doff = nwords(dopir); call asmxload(dopir, dopkr); 576 577 $ set up parameters for call. 578 $ (first parameter already set - first bit position) 579 dopxr(2) = doplr; $ second parameter is length. 580 dopxr(3) = dopjr; $ third parameter is source. 581 assignconst(dopxr(4), syze(dopjr)) $ length of source. 582 assignconst(dopxr(6), syze(dopir)) $ length of target. 583 if dopkr then lastuse(dopkr); lastuse(dopir); end if; 584 getaddr(work, dopir, doff, dopkr); dopxr(5) = work; 585 dopsname = longname(vo_easin); $ get routine name. 586 callnodrop = yes; dopnx = 6; call_op; $ call with six parameters. 587 go to endop; $ done. 588 589 /l(dk_xsasin)/ 590 $ indexed .s. assignment. get address of target and call 591 $ off-line routine. 592 .+defer. 593 call asmdxchk(dopkr); $ check index. 594 if (dophold) go to reissue; 595 ..defer 596 doff = nwords(dopir); call asmxload(dopir, dopkr); 597 598 $ set up parameters. (parameter one is already set up) 599 dopxr(2) = doplr; $ length. 600 dopxr(3) = dopjr; $ source. 601 if dopkr then lastuse(dopir); lastuse(dopkr); end if; 602 getaddr(work, dopir, doff, dopkr); dopxr(4) = work; 603 dopsname = longname(vo_sasin); $ get name. 604 callnodrop = yes; dopnx = 4; call_op; $ call with four parms. 605 go to endop; $ done. 606 607 /l(dk_goto)/ 608 $ go to operation. just issue. 609 goto_op(dopir); $ branch to label. 610 go to endop; $ done. 611 612 /l(dk_if)/ 613 $ -if- operation. in complicated case, call a routine to 614 $ generate code. otherwise, just issue the appropriate branch. 615 616 .+defer. 617 dophold = dout(dopir); $ get deferred op for input, if any. 618 .+ifopt. 619 if dophold then $ must do something. 620 if (opt_f) call asmif; $ if optimization, call routine. 621 if (dophold) go to reissue; $ if must reissue something. 622 go to endop; $ otherwise done with operation. 623 end if; 624 .-ifopt if (dophold) go to reissue; $ if no optimzation, evaluate. 625 ..defer 626 627 $ simple case - select branch instruction from form of input. 628 629 aop = bm_zer; 630 if (dopcode = do_if) aop = binv(bm_zer); $ invert aop. 631 lastuse(dopir); $ set status. 632 if_op(aop, dopir, dopjr); $ issue branch. 633 go to endop; $ done. 634 635 /l(dk_seq)/ 636 $ .seq. or .sne. comparison. handle as function call. 637 dopxr(1) = dopir; $ first parameter is input 1. 638 dopxr(2) = dopjr; $ second parameter is input 2. 639 dopsname = longname(vo_seq); $ get routine name. rkc 9 forcezero(0, no); $ free up r0. 640 callnodrop = yes; dopnx = 2; call_op; $ call routine. dsk 299 inzero(dopor, no); $ show function result. dsk 300 if dopcode = do_sne then $ see if this was .sne. dsk 301 lastuse(dopor); $ set lastuse status. dsk 302 assignconst(work, 1); $ set to a one. dsk 303 exor_op(dopor, dopor, work); $ negate value. dsk 304 else $ this was a .seq. dsl 13 kill(dopor); $ simply drop output. dsk 306 end if; dsk 307 643 go to endop; $ done. 644 645 /l(dk_mod)/ 646 $ -mod- function. check for a power of two. 647 if .nb. conval(dopjr) = 1 then $ it is. 648 assignconst(work, conval(dopjr)-1); $ get mask. 649 kill(dopjr); $ drop unused constant. 650 lastuse(dopor); lastuse(dopir); lastuse(work); 651 and_op(dopor, dopir, work); $ do as -and- with mask. 652 go to endop; $ done in this special case. 653 end if; 654 655 $ otherwise process as normal operation. 656 go to l(dk_simp2); 657 658 /l(dk_dim)/ 659 $ -idim- or -dim- function. generate as subtraction and test. 660 lastuse(dopir); lastuse(dopjr); $ set status. 661 bin_op(aop, dopor, dopir, dopjr); $ do subtraction. 662 663 $ get label and generate test. 664 labget(lab); $ get a label. 665 ifpos_op(dopor, lab); $ done if positive. 666 sub_op(dopor, dopor, dopor); $ else set to zero. 667 labdef(lab, no); $ define label. 668 labfree(lab); $ and free it. 669 kill(dopor); $ free output. note that this could not have 670 $ been done on the subtract because of the label. 671 go to endop; 672 673 /l(dk_goby)/ $ indexed -goto- operation. 674 call asmgoby; $ call routine to process. 675 go to endop; $ done with this operation. 676 677 /multi/ 678 $ multi-word operation found. call routine to generate 679 $ call (or maybe inline code for some). 680 call asmlong; 681 go to endop; $ done with this operation. 682 683 684 /endop/ 685 686 $ must do the housekeeping for the end of an operation. 687 688 do i = r0 to rhi; $ first clear all hold bits. 689 rl_hold reglis(i) = no; $ clear normal hold. 690 rl_addrhold reglis(i) = no; $ clear address hold. dse 16 if (rl_type reglis(i) = rt_dead) reglis(i) = 0; 691 end do; 692 693 694 .+trace. $ write out desired traces. 695 if (trace_d) call dumpdregs; 696 if (trace_r) call dumpmregs; 697 ..trace 698 699 700 return; $ done with operation. 701 702 703 .+defer. 704 /reissue/ $ reissue current operation and process operation pointed 705 $ to by -dophold-. 706 707 $ must check to see if this is an intermediate 708 $ operation being passed over. in that case, this 709 $ operation must be deferred again. 710 if reissuedop then $ this is intermediate operation. 711 if (dopfree = 0) call aermey(29); $ table is full. 712 713 $ after having verified that a table entry exists, build 714 $ one for this operation. 715 doptr = dopfree; dopfree = dp_chain dops(dopfree); 716 dops(doptr) = 0; $ clear entry. 717 dp_inp1 dops(doptr) = dopir; $ set first input. 718 dp_inp2 dops(doptr) = dopjr; $ set second input. 719 dp_inp3 dops(doptr) = dopkr; $ set third input. 720 dp_oup dops(doptr) = dopor; $ set output. 721 dp_op dops(doptr) = dopcode; $ set operation code. 722 dp_nargs dops(doptr) = dopnargs; $ set number of inputs. 723 .+trace if trace_o then tintl(' *defer*', doptr) endl end if; 724 dout(dopor) = doptr; $ point back to this operation. 725 di_count ditem(dr_item dreg(dopor)) = $ decrement usage count. 726 di_count ditem(dr_item dreg(dopor)) - 1; 727 else $ this is not intermediate operation. 728 $ must drop all inputs of current operation to make it 729 $ look as though the operation was never issued. 730 spcdrop = yes; $ set for special handling in -dropr-. 731 go to n1(dopnargs) in 0 to 4; $ drop arguments. 732 733 /n1(4)/ kill(doplr); 734 /n1(3)/ kill(dopkr); 735 /n1(2)/ kill(dopjr); 736 /n1(1)/ kill(dopir); 737 /n1(0)/ 738 739 if dophasout then kill(dopor); end if; 740 741 if dopnx ^= 0 & dopcode ^= do_goby then $ free extra args. 742 do i = 1 to dopnx; 743 kill(dopxr(i)); 744 end do; 745 end if; 746 747 spcdrop = no; $ reset flag. 748 749 reissuedop = yes; $ flag for -asmprog- to re-issue. 750 end if; 751 752 $ clear output pointer of output of this operation. 753 dout(dp_oup dops(dophold)) = 0; $ because will do now. 754 755 $ reset variables to point to operation. 756 .+trace if trace_o then tintl(' *reset*', dophold) endl end if; 757 dopcode = dp_op dops(dophold); $ get operation code. 758 dopor = dp_oup dops(dophold); $ ... output. 759 dopir = dp_inp1 dops(dophold); $ ... input 1. 760 dopjr = dp_inp2 dops(dophold); $ ... input 2. 761 dopkr = dp_inp3 dops(dophold); $ ... input 3. 762 dopnargs = dp_nargs dops(dophold); $ ... number of inputs. 763 $ count use of the output again. 764 using(dopor); $ because dropped when deferred. 765 766 767 $ insert on free queue. 768 dp_chain dops(dophold) = dopfree; dopfree = dophold; 769 770 go to issue; $ issue operation. 771 ..defer 772 773 macdrop(dt_dx) macdrop(dt_do) 774 macdrop(dt_d4) 775 macdrop(dt_d3) macdrop(dt_d2) 776 macdrop(dt_d1) macdrop(dt_defer) 777 macdrop(dt_spcasin) macdrop(dt_type) 778 macdrop(dt_aop) macdrop(dt_resform) 779 780 macdrop(dk_asin) macdrop(dk_bool) 781 macdrop(dk_casin) macdrop(dk_cext) 782 macdrop(dk_easin) macdrop(dk_eext) 783 macdrop(dk_fasin) macdrop(dk_fcall) 784 macdrop(dk_fext) macdrop(dk_fnb) 785 macdrop(dk_goto) macdrop(dk_if) 786 macdrop(dk_not) macdrop(dk_simp0) 787 macdrop(dk_simp1) macdrop(dk_simp2) 788 macdrop(dk_xasin) macdrop(dk_xeasin) 789 macdrop(dk_xfasin) macdrop(dk_xload) 790 macdrop(dk_xsasin) macdrop(dk_mod) 791 macdrop(dk_dim) macdrop(dk_goby) 792 macdrop(num_dk) 793 794 end subr emitdop; 1 .=member asmxasi 2 subr asmxasin; $ process indexed assignment. 3 size work(ps), work1(ps); $ work registers. 4 size i(ps), j(ps); $ temporaries. 5 6 .+defer. 7 call asmdxchk(dopkr); $ check index. 8 if (dophold) return; 9 ..defer 10 11 doff = 1; call asmxload(dopir, dopkr); $ process index. 12 13 $ check for multi-word cases. 14 if ismw(dopir) then $ target multi-word. 15 j = nwords(dopir); $ get no. of words for later. 16 if ismw(dopjr) then $ source multi-word. 17 $ have two cases depending on the sizes of source 18 $ and target. 19 if nwords(dopjr) < nwords(dopir) then $ must zero-fill. 20 getaddr(work, dopir, doff, dopkr); $ get address. 21 i = nwords(dopir)-nwords(dopjr); $ length to clear. 22 if dopkr then lastuse(work); end if; 23 clear_op(work, i); $ clear to zero. 24 else $ need not zero-fill. 25 i = 0; $ difference is zero. 26 end if; 27 if dopkr then lastuse(dopir); lastuse(dopkr); end if; 28 getaddr(work, dopir, doff+i, dopkr); dsa 14 getaddr(work1, dopjr, 1+idim(nwords(dopjr),j), 0); 30 $ move in source. 31 lastuse(work1); lastuse(work); $ set status. 32 smove_op(work, work1, (j-i)); 33 return; $ done. 34 else $ source is single-word. 35 $ check for special case of assigning zero. 36 if isscon(dopjr) & conval(dopjr) = 0 then 37 kill(dopjr); $ free the zero. 38 $ point to first word in variable. 39 if dopkr then lastuse(dopkr);lastuse(dopir); end if; 40 getaddr(work, dopir, doff, dopkr); 41 lastuse(work); $ set status. 42 clear_op(work, j); $ clear to zero. 43 return; $ done. 44 else $ must clear high-order. 45 getaddr(work, dopir, doff, dopkr); 46 lastuse(work); $ set status $ check with s37 chngs 47 clear_op(work, (nwords(dopir)-1)); $ clear to zero. 48 $ fall through to single-word case. 49 end if; 50 end if; 51 end if; 52 53 $ in single-word case, merely store source into target array. 54 lastuse(dopir); lastuse(dopjr); $ set status. 55 if dopkr then lastuse(dopkr); end if; 56 storeword(dopjr, dopir, doff+nwords(dopir)-1, dopkr); $ store. 57 58 end subr asmxasin; 1 .=member asmdata 2 subr asmdata; $ process -data- statement. 3 $ -data- statements are processed by chaining them in order of 4 $ increasing subcript value, to the variable that it being 5 $ initialized. 6 size i(ps), j(ps); $ pointers. 7 size ind(ps); $ index value. 8 9 $ first get index value. if this is not for subscripted 10 $ variable or if the subscript is left out, set the index 11 $ to 1. 12 i = vv_inp3 voa(voaep); $ -voa- pointer to index. 13 if i then $ if index given. 14 ind = val(vv_vbeg voa(i)); $ load value. 15 else $ not given. 16 ind = 1; $ set to one. 17 end if; 18 19 $ index will be stored in -vv_inp1- of -data- operation for 20 $ later use. 21 vv_inp1 voa(voaep) = ind; 22 23 $ get pointers to variable to be initialized and to the 24 $ start of the data chain for it. 25 i = ha_ep ha(vv_naym voa(voaep)); $ point to -voa- entry. 26 .-vvfrs j = vv_frsdata voa(i); $ point to head of chain 27 .+vvfrs j = vvfrsdata(i); $ point to head of chain. 28 29 $ check if a chain is present. 30 if j then $ a chain is present. 31 $ see if this index is lower than the first entry in chain. 32 $ if so, then this becomes the first index in the chain. 33 if ind < vv_inp1 voa(j) then $ this becomes first in chain. 34 vv_inp2 voa(voaep) = j; $ maintain chain. 35 .-vvfrs vv_frsdata voa(i) = voaep; 36 .+vvfrs vvfrsdata(i) = voaep; 37 else $ not below first in chain. 38 $ search for the place at which this new entry 39 $ should be inserted in the chain. the 'maybe' loop 40 $ is exited when the entry has been added to the chain. 41 until yes; $ exit when added to chain/ 42 while vv_inp2 voa(j); $ loop while more in chain. 43 i = vv_inp2 voa(j); $ set to next in chain. 44 if ind < vv_inp1 voa(i) then $ insert here. 45 vv_inp2 voa(voaep) = i; 46 vv_inp2 voa(j) = voaep; $ put into chain. 47 quit until; $ show in chain. 48 end if; 49 j = i; $ step to next in chain next time around. 50 end while; 51 52 $ if reach here, the entry is higher than any in 53 $ the chain so add to end. 54 vv_inp2 voa(voaep) = 0; $ set to end of chain. 55 vv_inp2 voa(j) = voaep; $ point to new entry. 56 end until; 57 end if; 58 59 else $ chain is empty -- put as first entry. 60 vv_inp2 voa(voaep) = 0; $ show last in chain. 61 .-vvfrs vv_frsdata voa(i) = voaep; $ show first also. 62 .+vvfrs vvfrsdata(i) = voaep; $ show first also. 63 end if; 64 65 end subr asmdata; 1 .=member asmgoby 2 subr asmgoby; $ generate code for indexed goto. 3 $ this routine generates code for the indexed goto operation. 4 size i(ps); $ loop variable. 5 size lab(ps); $ temporary label. 6 size lab1(ps); $ second label. 7 size reg(ps); $ temporary dummy register. 8 size mreg(ps); $ machine register. 9 size mode(ps); $ machine mode for label table. 10 size moff(mosize); $ machine offset for label table. 11 size t(ws); $ temporary. vaxa 177 size work(ps); $ temporary dreg. vaxa 178 .+t32 size work2(ps); $ temporary dreg. 12 13 $ define a label to indicate that the index is acceptable 14 $ so far and branch to it if the index is strictly positive. 15 labget(lab); $ get a temporary label. 16 ifspos_op(dopir, lab); $ branch if greater than zero. 17 18 $ define an error point at this location. 19 labget(lab1); $ get a label. 20 labdef(lab1, no); $ define it locally. 21 22 $ call an error routine. put the bad index () into 23 $ r0 and call the routine with no parameters. 24 forcezero(dopir, no); $ force into r0. 25 i = dopnx; $ save no. arguments for later. 26 dopnx = 0; dopsname = 'goto$er'; call_op; $ call with no args. 27 dopnx = i; $ restore number of arguments. 28 29 $ define the 'good-so-far' label and check if the index 30 $ is too high. 31 labdef(lab, no); $ define the label locally. 32 labfree(lab); $ this is last use of that label. 33 assignconst(reg, dopnx); $ get no. to compare with. 34 lastuse(reg); $ set status. 35 cmp_op(bm_pos, dopir, reg, lab1); $ do compare. 36 labfree(lab1); $ done with this label. 37 vaxa 179 .+t10 work = dopir; $ copy to variable to use later. vaxa 180 .+t32 assignconst(work2, 2); $ get amount to shift. vaxa 181 .+t32 getdreg(work); $ get dummy register. vaxa 182 .+t32 lastuse(work2); lastuse(dopir); $ set status. vaxa 183 .+t32 mul2_op(work, dopir, work2); $ shift over. vaxa 184 vaxa 185 vaxa 186 getvar(work, gd_reg, mode, mreg, moff); $ get index into reg vaxa 187 vaxa 188 vaxa 189 .+t10. 39 if mreg = r0 then $ check if it is in r0. 40 $ in this case it must be moved somewhere because r0 41 $ cannot be used as an index register. 42 getreg(mreg, rt_live); $ must get a register. vaxa 190 dr_reg dreg(work) = mreg; $ set to new register. 44 reglis(mreg) = reglis(r0); $ copy status. 45 reglis(r0) = 0; $ free register zero. 46 end if; vaxa 191 ..t10 vaxa 192 vaxa 193 vaxa 194 kill(work); $ free index. 48 $ emit an indexed branch into the label table to be built in 49 $ the base block. 50 moff = 0; mbo_blk moff = bl_base; $ set to base block 51 $ if base block address would go negative, increment it. 52 if (baselastaddr=1) baselastaddr=2; 53 t = baselastaddr - 2; 54 if (t<0) t = mneg(iabs(t)); $ if negative. 55 mbo_off moff = t; vaxa 195 .+t10 emop(mo_jmp, r0, am_reli, mreg, moff); $ do the branch. vaxa 196 .+t32 emop(mo_xjm, mreg, am_mem, sparereg, moff); $ do branch. 57 58 $ now insert the labels into the base block. 59 do i = 1 to dopnx; $ loop over each label. 60 baseprobelab(t, dopxr(i)); $ insert a label. 61 end do; 62 63 end subr asmgoby; 1 .=member asmif 2 .+ifopt. 3 subr asmif; 4 $ this routine processes the expression of an -if- statement. 5 $ it is used to generate the appropriate compare instructions 6 $ rather than subtracts, exclusive-ors, etc. 7 $ 8 $ it receives as input the tree for the expression in the -dops- 9 $ array. it then copies and processes the tree. its first 10 $ pass is to copy the tree into an internal structure. this 11 $ structure indicates exactly what comparisons are to be done, 12 $ what branch mask is to be used to the true case, and what 13 $ variables, offsets, and masks are involved. this first pass 14 $ also checks that everything is validly deferred and will 15 $ return to force evaluation if not. 16 $ 17 $ the second pass then scans the tree to actually generate the 18 $ comparisons and branches. 19 20 $ the main table used by this routine is the i-f t-able (it). 21 $ it contains the nodes of the tree built from the expression. 22 $ the format of each node is given below. 23 +* it_op = .f. 1, 8, ** $ operation type. 24 +* it_tlab = .f. 9, 8, ** $ true branch label index. 25 +* it_flab = .f. 17, 8, ** $ false branch label index. 26 +* it_dop = .f. 25, 8, ** $ pointer to deferred operation. 27 +* it_llink = .f. 33, 8, ** $ left tree link pointer. 28 +* it_rlink = .f. 41, 8, ** $ right tree link pointer. 29 +* it_blink = .f. 49, 8, ** $ back pointer. 30 +* it_count = .f. 57, 8, ** $ number of nodes below this. 31 +* it_bmask = .f. 65, 8, ** $ true branch mask. 32 +* it_inp1 = .f. 73, 8, ** $ input one to operation. 33 +* it_inp2 = .f. 81, 8, ** $ second input to operation. 34 +* it_len = .f. 89, 8, ** $ byte offset or mask. 35 +* it_rlf = .f. 97, 1, ** $ right/left flag. 36 +* it_tdef = .f. 98, 1, ** $ 'defines new true label' 37 +* it_fdef = .f. 99, 1, ** $ 'defines new false label' 38 +* it_negfl = .f. 100, 1, ** $ 'changes status of -negfl-' 39 40 +* itsz = 128 ** $ size of table. dsd 11 $ define it fields using 32 bit (s37) as default, correct dsd 12 $ as needed for other machines. this not standard practice, dsd 13 $ but acceptable as fields referenced only in this procedure. dsd 14 dsd 15 .+s10 +* itsz = 144 ** +* it_llink = .f. 137, 8, ** dsd 16 .+s66 +* itsz = 120 ** +* it_count = .f. 113, 8, ** 41 42 43 $ the other tables that are used are the -iv- and the -il- 44 $ tables. -iv- contains a list of variables which will be used 45 $ in generating the expression. this is done so usage counts 46 $ can be correctly maintained. the -il- table contains a list 47 $ of generated labels. if an entry is zero, it means that no 48 $ label has been assigned for that index. if it is nonzero, 49 $ then it is the label number. 50 51 $ define maximum table dimensions. 52 +* itmax = 32 ** 53 +* ivmax = 30 ** 54 +* ilmax = 20 ** 55 56 $ define tables and pointers. 57 size it(itsz), itptr(ps); 58 dims it(itmax); 59 60 size iv(ps), ivptr(ps); 61 dims iv(ivmax); 62 63 size il(ps), ilptr(ps); 64 dims il(ilmax); 65 66 67 $ operation types used. 68 +* ip_or = 1 ** $ logical -or-. 69 +* ip_and = 2 ** $ logical -and-. 70 +* ip_cmp = 3 ** $ do simple comparison. 71 72 $ flag values for tree. 73 +* left = 0 ** $ at left subtree. 74 +* right = 1 ** $ at right subtree. 75 76 77 $ table for conversion of op --> branch mask. 78 size bmasks(ps); dims bmasks(do_ne - (do_lt-1)); 79 80 +* bmi(op, bm) = bmasks(op - (do_lt-1)) = bm ** 81 82 data $ initialize table. 83 84 $ table bmi bewow is machine-independent. 85 bmi(do_lt, bm_neg): 86 bmi(do_ge, binv(bm_neg)): 87 bmi(do_eq, bm_zer): 88 bmi(do_ne, binv(bm_zer)); 89 90 macdrop(bmi) 91 92 93 size in1(ps), in2(ps), in3(ps); $ inputs to operation. 94 size optr(ps); $ pointer to -dop-. 95 size negfl(1); $ negate flag. 96 size opc(ps); $ operation code. 97 size lptr(ps); $ last tree entry pointer. 98 size one(ps); $ register containing one. 99 size zero(ps); $ register containing zero. 100 size nextop(ps); $ pointer to next operation. 101 size bmask(ps); $ branch mask for node. 102 size t(ps); $ temporary. 103 size itval(itsz); $ temporary copy of node. 104 size i(ps); $ loop index. 105 size lab(ps); $ temporary label and index. 106 107 108 $ first, initialize variables for pass one. 109 itptr = 0; ivptr = 0; $ show empty tables. 110 ilptr = 2; il(1) = dopjr; il(2) = 0; $ initialize -il- table. 111 optr = dophold; $ set initial -dop- index. 112 negfl = no; $ set initial negation flag. 113 lptr = 0; $ set initial tree status. 114 115 assignconst(one, 1); assignconst(zero, 0); 116 117 118 $ start pass one. 119 while yes; $ exit from this ends pass one. 120 $ first, extract op-code and operands. 121 opc = dp_op dops(dophold); $ get operation. 122 in1 = dp_inp1 dops(dophold); in2 = dp_inp2 dops(dophold); 123 124 $ process the operation depending on type. 125 if opc = do_or then $ logical or case. 126 $ in this case, simply add an -or- operation 127 $ to the tree (or an -and- operation if the negate 128 $ flag is set) and set the next operation to the first 129 $ input. 130 $ first make sure that if any input is not deferred, 131 $ that it is an operand of size 1. 132 if dout(in1) = 0 then $ first input not deferred. 133 if (syze(in1) ^= 1) go to force; 134 end if; 135 136 if dout(in2) = 0 then $ second input not deferred. 137 if (syze(in2) ^= 1) go to force; 138 end if; 139 140 nextop = in1; $ set next operation. 141 in1 = 0; in2 = 0; $ show no operands. 142 opc = ip_or; if (negfl) opc = ip_and; 143 $ go to build; $ add operation to tree. 144 145 146 elseif opc = do_and then $ logical and case. 147 $ this is similar to the -or- case above. 148 if dout(in1) = 0 then $ first input not deferred. 149 if (syze(in1) ^= 1) go to force; 150 end if; 151 152 if dout(in2) = 0 then $ second input not deferred. 153 if (syze(in2) ^= 1) go to force; 154 end if; 155 156 nextop = in1; $ set next operation. 157 in1 = 0; in2 = 0; $ show no operands. 158 opc = ip_and; if (negfl) opc = ip_or; 159 $ go to build; $ add operation to tree. 160 161 162 elseif opc = do_not then $ logical not operation. 163 $ in the case of a -not- opertation, simply set the 164 $ negate flag and apply de morgan's laws. also set 165 $ a flag in the last operation added to the tree so that 166 $ when back up past it on the way up, the negate flag 167 $ can be toggled to its previous status. 168 if dout(in1) = 0 then $ first input not deferred. 169 if (syze(in1) ^= 1) go to force; 170 end if; 171 172 negfl = .not. negfl; $ negate 'negate' flag. 173 if (lptr) it_negfl it(lptr) = .not. it_negfl it(lptr); 174 nextop = in1; go to next; $ continue but dont add op. 175 176 177 elseif opc >= do_lt & opc <= do_ne then $ is comparison. 178 $ this is the most common, complex, and important case. 179 $ want to check the operands of the comparison. 180 $ first, though, will test to see if this is a 181 $ comparison of a one-bit item with either zero or one 182 $ or any item with zero. 183 $ if it is, then it is either a -not- or a noop and 184 $ can be processed accordingly. 185 until yes; $ exit if not special. 186 if (opc ^= do_eq & opc ^= do_ne) quit until; 187 188 $ for simplicity, want to set the constant 189 $ operand to the second operand so swap if not 190 $ that way already. 191 if in1 = one ! in1 = zero then $ swap. 192 t = in1; in1 = in2; in2 = t; 193 elseif in2 ^= zero & in2 ^= one then 194 quit until; $ this is not special. 195 end if; 196 197 if ((syze(in1) ^= 1 & in2 = one) ! ismw(in1)) 198 quit until; $ this is not special. 199 200 nextop = in1; $ get next operation. 201 202 $ see if this is a -not-. if so, do the negation. 203 if (opc = do_eq) .ex. (in2 ^= zero) then 204 negfl = .not. negfl; $ negate the negate flag. 205 if (lptr) it_negfl it(lptr) = ^it_negfl it(lptr); 206 end if; 207 go to next; $ go down chain. 208 end until; 209 210 $ check for none of the following special cases. 211 $ 1 convert a<1 to 0 >= a 212 $ 2 convett a>= 1 to 0 < a 213 if in2 = one & (opc = do_lt! opc = do_ge) then 214 in2 = in1; in1 = zero; $ change operands. 215 opc = (do_lt + do_ge) - opc; $ switch operation 216 end if; 217 $ otherwise have a normal comparison. first, compute 218 $ the branch mask. 219 bmask = bmasks(opc - (do_lt-1)); $ get normal mask. 220 if (negfl) bmask = binv(bmask); $ invert if negated. 221 222 $ check operands of the comparison. 223 if (dout(in1) ! dout(in2)) go to force; $ normal. dsk 308 if (ismw(in1) ! ismw(in2)) go to force; $ if multi-word. 224 $ this is a normal comparison. all must do 225 $ is check for a comparison against zero and, if so, 226 $ ensure it is the second operand. then the 227 $ comparison operation can be built. 228 if in1 = zero then $ first input is zero. 229 in1 = in2; $ set to nonzero input. 230 in2 = 0; $ show this is zero. 231 bmswap(bmask, t); $ swap the branch mask. 232 elseif in2 = zero then $ second input is zero. 233 in2 = 0; $ flag as such. 234 end if; 235 236 nextop = 0; $ show to go back. 237 opc = ip_cmp; $ add operation. 238 else $ not special operation. 239 go to force; $ so force evaluation. 240 end if; 241 242 /build/ 243 244 245 $ first, add variables to -iv- table. 246 if (ivptr > ivmax-2) go to force; $ overflow. 247 iv(ivptr+1) = in1; iv(ivptr+2) = in2; $ insert. 248 ivptr = ivptr + (in1^=0) + (in2^=0); $ increment. 249 250 if (itptr > itmax-1) go to force; $ tree is full. 251 252 itval = 0; $ clear entry. 253 254 $ build the node for the tree. 255 it_op itval = opc; $ set opcode. 256 it_dop itval = optr; $ set operation pointer. 257 it_blink itval = lptr; $ set back link. 258 it_bmask itval = bmask; $ set branch mask. 259 it_inp1 itval = in1; $ set first input. 260 it_inp2 itval = in2; $ set second input. 261 262 itptr = itptr+1; it(itptr) = itval; $ insert into tree. 263 264 265 $ see about updating pointer to this node. 266 if lptr then $ if this is not root. 267 if it_rlf it(lptr) = left $ see which to update. 268 then it_llink it(lptr) = itptr; $ left. 269 else it_rlink it(lptr) = itptr; end if; $ right. 270 end if; 271 272 lptr = itptr; $ set last node pointer. 273 274 /next/ $ merge here to advance to next operation. 275 if nextop = 0 then $ this means back up the tree. 276 lptr = it_blink it(lptr); $ step back the tree. 277 while lptr; $ loop while someplace to go. 278 negfl = negfl .ex. it_negfl it(lptr); $ flip switch. 279 280 it_negfl it(lptr) = no; $ clear switch. 281 $ see whether are in left or right subtree 282 $ of the ancestor node. 283 if it_rlf it(lptr) = left then $ are in left. 284 $ in this case, merely move to the right 285 $ subtree. 286 it_rlf it(lptr) = right; $ set to right subtree. 287 nextop = dp_inp2 dops(it_dop it(lptr)); $ next. 288 go to next; $ go process that op or variable. 289 290 else $ are in the right subtree. 291 $ in this case must back up to the ancestor 292 $ of this node. but first must do two 293 $ things. the first is to set the status back 294 $ to left for the second pass. 295 it_rlf it(lptr) = left; 296 297 $ the second thing is to update the count of 298 $ the number of nodes below this one. in 299 $ addition, if the left subtree has more nodes 300 $ than the right subtree, they are swapped. 301 it_count it(lptr) = 302 it_count it(it_llink it(lptr)) + 303 it_count it(it_rlink it(lptr)); 304 305 if it_count it(it_llink it(lptr)) > 306 it_count it(it_rlink it(lptr)) then $ swap. 307 t = it_llink it(lptr); 308 it_llink it(lptr) = it_rlink it(lptr); 309 it_rlink it(lptr) = t; 310 end if; 311 312 lptr = it_blink it(lptr); $ back up to try again. 313 end if; 314 end while; 315 316 $ if reach here, then are done with the first 317 $ pass. 318 quit while; $ exit from first pass. 319 320 321 elseif dout(nextop) = 0 then 322 $ in this case the next 'operation' is actually 323 $ a variable. so must build an operation which 324 $ compares it against zero. 325 dophold = 0; $ this is zero also. 326 opc = ip_cmp; in1 = nextop; in2 = 0; $ set parms. 327 bmask = binv(bm_zer); if (negfl) bmask = bm_zer; 328 nextop = 0; go to build; $ add to tree. 329 330 else 331 $ this is the case where the next operation is 332 $ really an operation. 333 dophold = dout(nextop); optr = dophold; $ set index. 334 end if; 335 end while; 336 337 338 339 340 $ this is the end of the first pass. 341 342 $ before the second pass is started, must go through 343 $ the variable table and indicate the using status. then the 344 $ initial input and the dummy zero and one can be dropped so 345 $ that only the variables that will actually be used are shown 346 $ as being used. 347 do i = 1 to ivptr; $ loop over the whole table. 348 using(iv(i)); $ increment the count. 349 end do; 350 351 kill(zero); kill(one); kill(dopir); $ drop junk. 352 353 354 355 $ are ready to begin the second pass. first must 356 $ assign the labels for the root of the tree depending on the 357 $ original operation code. 358 if dopcode = do_if then 359 it_tlab it(1) = 1; 360 it_flab it(1) = 2; 361 else $ must be -ifnot- so invert. 362 it_tlab it(1) = 2; 363 it_flab it(1) = 1; 364 end if; 365 366 367 itptr = 1; $ start traverse at root of tree. 368 while itptr; $ while not done with tree. 369 $ first extract values from node. 370 itval = it(itptr); $ get copy of node. 371 opc = it_op itval; $ get operation code. 372 in1 = it_inp1 itval; in2 = it_inp2 itval; $ inputs. 373 bmask = it_bmask itval; 374 375 $ get target label. will use the lower of the two 376 $ label indices. 377 lab = it_tlab itval; $ assume true is lower. 378 if lab > it_flab itval then $ it is in fact higher. 379 lab = it_flab itval; $ set to false label. 380 bmask = binv(bmask); $ invert branch mask. 381 end if; 382 383 $ if this is neither and -and- nor an -or- and a label 384 $ has not been assigned to the index, must assign one 385 $ now. 386 if opc ^= ip_and & opc ^= ip_or & il(lab) = 0 then 387 labget(t); $ get a label; 388 il(lab) = t; $ put it into the table. 389 end if; 390 391 lab = il(lab); $ get the actual label number. 392 393 394 $ must process the node depending on operation. 395 if opc = ip_and ! opc = ip_or then $ logical ops. 396 $ in this case all must do is to update the true 397 $ and false labels of the sons of the node. in all 398 $ cases the right son gets the same labels. however, 399 $ the left son gets a new label for either true or false 400 $ depending on the operation. 401 it_tlab it(it_rlink itval) = it_tlab itval; 402 it_flab it(it_rlink itval) = it_flab itval; 403 404 $ initially copy both labels to left son also. 405 it_tlab it(it_llink itval) = it_tlab itval; 406 it_flab it(it_llink itval) = it_flab itval; 407 408 countup(ilptr, ilmax, 'il'); $ get a label index. 409 il(ilptr) = 0; $ clear entry to show unassigned. 410 411 if opc = ip_and then $ assign to true label. 412 it_tlab it(it_llink itval) = ilptr; 413 it_tdef it(it_llink itval) = yes; $ show definer. 414 else $ must be -or-. 415 it_flab it(it_llink itval) = ilptr; 416 it_fdef it(it_llink itval) = yes; 417 end if; 418 419 420 elseif opc = ip_cmp then 421 $ this is either a simple comparison or a test. 422 if in2 then $ this is comparison. 423 lastuse(in1); lastuse(in2); $ set status. 424 cmp_op(bmask, in1, in2, lab); 425 else $ this is just test. 426 lastuse(in1); $ set status. 427 if_op(bmask, in1, lab); 428 end if; 429 430 431 end if; 432 433 434 $ if have just done a forward branch must set a flag 435 $ to indicate that can no longer put items into registers 436 if lab .ne. 0 & lab .ne. il(1) then $ if must set 437 isinif = yes; $ set flag for emitbin and emitcmp. 438 end if; 439 $ go down the left branch until hit end. 440 lptr = it_llink itval; $ get left pointer. 441 if lptr then $ will continue down. 442 itptr = lptr; $ set to son. 443 cont while; $ continue. 444 end if; 445 446 447 /loop/ $ merge here to back up tree. 448 449 $ go back up the tree. 450 itptr = it_blink it(itptr); $ go back up. 451 if (itptr = 0) quit while; $ done when hit top. 452 453 $ see if are in the left or right subtree of that 454 $ node. 455 if it_rlf it(itptr) = left then $ were in left subtree. 456 $ in this case set to right subtree. 457 it_rlf it(itptr) = right; $ set for next time. 458 itptr = it_rlink it(itptr); $ go to the right. 459 cont while; $ process it. 460 461 else $ were in right subtree. 462 $ in this case must actually define any labels 463 $ that were flagged as being defined in this node and 464 $ that were used. then back up the tree again. 465 lab = 0; $ assume no label to define. 466 if (it_tdef it(itptr)) lab = it_tlab it(itptr); 467 if (it_fdef it(itptr)) lab = it_flab it(itptr); 468 469 $ see if there was a label to define and if it 470 $ was used. 471 if lab then $ a label was defined. 472 if il(lab) then $ it was also used. 473 labdef(il(lab), no); $ define at this point. 474 labfree(il(lab)); $ free the label. 475 il(lab) = 0; $ clear just to be sure. 476 end if; 477 end if; 478 479 go to loop; $ back up again. 480 end if; 481 end while; 482 483 484 485 isinif = no; $ reset flag for emit level routines. 486 $ are done with both passes. all that remains is to 487 $ define the initial 'true' label if it has been used. 488 if il(2) then $ it has been used. 489 labdef(il(2), no); $ define the label. 490 labfree(il(2)); $ free the label. 491 end if; 492 493 494 dophold = 0; $ show nothing to evaluate. 495 return; 496 497 /force/ 498 $ this is branched to in order to force evaluation of 499 $ something. this will pick the best thing to force 500 $ evaluation of (as far down the tree as possible.) 501 502 kill(one); kill(zero); $ first, drop constants. 503 504 if (dophold) return; $ if something here, done. 505 506 dophold = optr; $ else set to last operation. 507 if (dophold) return; $ if something here, done. 508 509 dophold = dout(dopir); $ else set to initial operation. 510 return; 511 512 macdrop(it_op) macdrop(it_tlab) 513 macdrop(it_flab) macdrop(it_dop) 514 macdrop(it_llink) macdrop(it_rlink) 515 macdrop(it_bink) macdrop(it_count) 516 macdrop(it_bmask) macdrop(it_inp1) 517 macdrop(it_inp2) macdrop(it_off1) 518 macdrop(it_off2) macdrop(it_len) 519 macdrop(it_tdef) macdrop(it_fdef) 520 macdrop(it_negfl) macdrop(itsz) 521 macdrop(itmax) macdrop(ivmax) 522 macdrop(ilmax) macdrop(ip_or) 523 macdrop(ip_and) macdrop(ip_cmp) 524 macdrop(left) 525 macdrop(right) 526 527 end subr asmif; 528 ..ifopt 1 .=member asmlong 2 subr asmlong; $ call off-line multi-word routine. 3 $ this routine processes multi-word simple operations by 4 $ generating calls to off-line routines. 5 size aop(ps); $ operation to issue. 6 size dop_comparison(do_not); $ flags comparison ops. 7 data dop_comparison = 1b'00000 00011 1100'; 8 9 dopsname = longname(dopcode); $ get routine name. 10 callnodrop = yes; $ dont drop parameters. 11 12 if dopnargs = 1 then $ unary operation. 13 dopxr(1) = dopir; $ first is input. 14 if dopcode = do_not then $ this is subroutine call. 15 assignconst(dopxr(2), syze(dopir)) $ length. 16 dopnx = 3; $ three parameters. 17 dopxr(3) = dopor; $ third is output. 18 call_op; $ call routine. 19 else $ this is a call to library function. 20 assignconst(dopxr(2), nwords(dopir)) $ length of input. 21 forcezero(0, no); $ clear register zero. 22 dopnx = 2; call_op; $ call with two parameters. 23 inzero(dopor, no); $ indicate output in r0. 24 end if; 25 26 else $ must be binary operation. 27 28 $ insert first four operands for call. 29 dopxr(1) = dopir; assignconst(dopxr(2), nwords(dopir)) 30 dopxr(3) = dopjr; assignconst(dopxr(4), nwords(dopjr)) 31 $ comparison operation are functions, so check if this 32 $ is a comparison operation. 33 if .f. dopcode, 1, dop_comparison then $ if comparison. 34 dopnx = 4; $ only four arguments. pic 13 forcezero(0,no); $ clear register zero 35 call_op; $ call routine. 36 inzero(dopor, no); $ show in r0. 37 else $ normal binary operation. output is last argument. 38 dopnx = 5; $ has five arguments. 39 dopxr(5) = dopor; $ fifth is output. 40 call_op; $ call routine. 41 end if; 42 end if; 43 44 end subr asmlong; 1 .=member asmfld 2 subr asmfld(fb, len, var, source); $ prepare for .f. op. 3 $ this routine emits the code for all the .f. 4 $ operations. it first checks that all inputs are validly 5 $ deferred. then it processes constant length and position 6 $ and sets up index and position registers where aplicable. 7 size fb(ps); $ register containing bit position. 8 size len(ps); $ register containing field length. 9 size var(ps); $ register containing .f. variable. 10 size source(ps); $ register containing source of assignment 11 size t1(ps), t2(ps); $ temporaries. 12 size i(ps); $ temporary 13 size isaop(1); $ 'this is assignment operation' 14 size isxop(1); $ 'this is indexed operation' 15 size ismwop(1); $ 'this is multi-word operation' 16 size work(ps), work1(ps), work2(ps); $ work registers. 17 size mode(ps); $ machine mode for target word. 18 size mreg(ps); $ machine register for target word. 19 size moff(mosize); $ machine offset for target word. 20 size mreg1(ps); $ temporary machine register. 21 22 $ first, set flags for operation type. 23 24 isxop = (dopcode = do_xfasin); 25 26 isaop = isxop ! (dopcode = do_fasin); 27 28 ismwop = ismw(var); $ set multi-word attribute. 29 30 31 $ set flags and value for constant length and position. 32 doplenconst = isscon(len); $ constant length flag. 33 doplenval = conval(len); $ value of constant length. 34 35 dopfbconst = isscon(fb); $ constant position flag. 36 dopfbm1val = conval(fb) - (conval(fb)^=0); 37 38 39 .+defer. 40 $ ensure that all inputs are validly deferred. 41 dophold = dout(fb); $ first check bit position. 42 if dophold then $ it is deferred. 43 if (dp_op dops(dophold) ^= do_add) go to ret; $ must be add. 44 t1 = dp_inp1 dops(dophold); t2 = dp_inp2 dops(dophold); 45 until yes; $ ensure that at least one is constant. 46 dopfbm1 = t2; $ assume inp1 is constant. 47 if (conval(t1) = 1) quit until; $ exit if it is. 48 dopfbm1 = t1; $ assume inp2 is constant. dsd 17 if (conval(t2) = 1) quit until; $ exit if it is. 50 go to ret; $ else cannot defer this input. 51 end until; 52 53 dopfbconst = isscon(dopfbm1); $ reset constant and 54 dopfbm1val = conval(dopfbm1); $ value flags. 55 end if; 56 57 $ if this is an indexed operation, check the index. 58 if isxop then $ this is indexed. 59 call asmdxchk(dopkr); $ index is kept there. 60 if (dophold) go to ret; $ force evaluation if needed. 61 end if; 62 63 dophold = dout(var); $ check variable (always zero or asin). 64 if dophold then $ this is deferred. 65 if di_ldrop ditem(dr_item dreg(var)) = no ! 66 di_count ditem(dr_item dreg(var)) ^= 1 then 67 if (ismwop) go to ret; 68 end if; 69 70 if (dp_op dops(dophold) ^= do_xload) go to ret; $ not valid. 71 $ call routine to check if the operands to this indexed 72 $ load are validly deferred. 73 call asmdxchk(dp_inp2 dops(dophold)); $ check index. 74 if (dophold) go to ret; $ not validly deferred. 75 end if; 76 77 78 .+eab. 79 $ [the desired code here is, for s37, to emit ni, tm, and oi 80 $ which clear target bit, skip if source bit off, and if 81 $ source bit on, then -or- constant one in to effect move 20 apr] 82 $ do special check for the case of a field move of one bit. 83 if source then $ this may be a special case. 84 dophold = dout(source); $ see if source is deferred. 85 if dophold then $ it is. 86 if (doplenval ^= 1) go to ret; $ not one bit asign. 87 if (dopfbconst = no) go to ret; $ not constant position. 88 if (dp_op dops(dophold) ^= do_fext) go to ret; 89 if (conval(dp_inp2 dops(dophold)) ^= 1) go to ret; 90 if (isscon(dp_inp1 dops(dophold)) = no) go to ret; 91 $ must be carefull that this is never a field 92 $ move from a field to the same field because in that 93 $ case the clear of the bit would be done before the 94 $ test of the bit. since it is not simple to compare 95 $ both arrays, will compare the bit positions. 96 if (dopfbm1val = conval(dp_inp1 dops(dophold)) - 1) 97 go to ret; $ cannot have this as special case. 98 dophold = dout(dp_inp3 dops(dophold)); 99 if (dophold) go to ret; $ cannot have index. 100 isspecial = yes; $ show this is a special case. 101 end if; 102 end if; 103 ..eab 104 105 $ if reach here, the operands were validly deferred, so 106 $ clear -dophold-. 107 dophold = 0; 108 ..defer 109 110 $ process position to do subtraction if needed. 111 if dopfbconst then $ this is constant. 112 kill(fb); $ can drop constant register. 113 assignconst(dopfbm1, dopfbm1val); $ set new constant. 114 .+defer. 115 elseif dout(fb) then $ this was an addition of one. 116 using(dopfbm1); kill(fb); $ reset status. 117 ..defer 118 else $ must subtract one. 119 getdreg(dopfbm1); $ get result register. 120 lastuse(fb); $ set status. 121 sub1_op(dopfbm1, fb); $ do the subtraction. 122 end if; 123 124 $ process the variable and index. first, initialize. 125 dopvar = var; dopindx = 0; $ original variable, no index. 126 .+defer. 127 if dout(var) then $ this is indexed load so set new items. 128 dopvar = dp_inp1 dops(dout(var)); $ get base. 129 dopindx = dp_inp2 dops(dout(var)); $ get index. 130 using(dopvar); using(dopindx); kill(var); $ set status. 131 end if; 132 ..defer 133 134 doff = nwords(dopvar); $ set initial word offset. 135 $ if this is an indexed operation, set index. 136 if isxop then $ this is indexed operation. 137 dopindx = dopkr; $ this is where index is kept. 138 .+defer. 139 end if; 140 141 $ if there is an index register, position it and 142 $ compute possible new offset. 143 if dopindx then $ there is an index register. 144 ..defer 145 call asmxload(dopvar, dopindx); $ position index. 146 end if; 147 148 149 ismwop = ismw(dopvar); $ reset multi-word flag. 150 151 $ are ready to use the bit position to build the 152 $ correct index value to access the desired word. 153 $ this is only done if the variable is multi-word. 154 if ismwop then $ get new index. 155 $ if constant position, just compute new word index. 156 if dopfbconst then $ this is constant position. 157 doff = doff - dopfbm1val/mws; 158 dopfbm1val = mod(dopfbm1val, mws); $ to place in word. vaxa 197 kill(dopfbm1); $ drop old value. vaxa 198 assignconst(dopfbm1, dopfbm1val); $ get new one. 159 else $ must compute index register. vaxa 199 .+t10 assignconst(work2, mws); $ get constant. vaxa 200 .+t10 getdreg(work); lastuse(work2); vaxa 201 .+t32 getdreg(work); 162 if doplenval = mws then $ need not keep values. 163 lastuse(dopfbm1); $ set status. 164 end if; 165 vaxa 202 .+t10 div_op(work, dopfbm1, work2); vaxa 203 .+t32 assignconst(work2, 5); lastuse(work2); vaxa 204 .+t32 div2_op(work, dopfbm1, work2); vaxa 205 .+t32 assignconst(work2, 2); $ set to log2 (mcpw). vaxa 206 .+t32 mul2_op(work, work, work2); $ shift over again. 167 168 if doplenval ^= mws then $ must compute new fb 169 $ compute bit position mod ws. 170 getdreg(work1); $ get a result register. vaxa 207 .+t10 assignconst(work2, mws); $ get word size. vaxa 208 .+t32 assignconst(work2, mws-1); $ get word size. 172 lastuse(dopfbm1); lastuse(work2); $ set status. vaxa 209 .+t10 mod_op(work1, dopfbm1, work2); $ get offset. vaxa 210 .+t32 and_op(work1, dopfbm1, work2); $ get offset. 174 dopfbm1 = work1; $ set new position. 175 end if; 176 177 $ must compute final offset. must get a new 178 $ register and either negate or subtract. 179 180 getdreg(work1); lastuse(work); 181 182 if dopindx then $ must subtract two registers. 183 lastuse(dopindx); $ set status. 184 sub_op(work1, dopindx, work); $ do subtract. 185 else $ just negate offset. 186 neg_op(work1, work); $ do negation. 187 end if; 188 189 dopindx = work1; $ set to new index register. 190 end if; 191 end if; 192 193 vaxa 211 .+t10. 194 /* 195 the following is the code skeletons for field ops. 196 the code sequences for field extraction and insertion 197 are very similar, as shown below by parenthesized comments 198 indicating code for field insertion. 199 r = .f. c1+1, c2, ea (or .f. c1+1, c2, ea = r) 200 lpr r,ea,c1,c2 (or spr r,ea,c1,c2) 201 202 r = .f. c, e, ea (or .f. c, e, ea = r) eaa 132 lda* ra,ea 204 ldwi rb,c-1 205 spr rb,ra,30,6 set p 206 ldw rb,e 207 spr rb,ra,24,6 set s 208 ldf r,ra (or stf r,ra) 209 210 r = .f. e, c, ea (or .f. e, c, ea = r) eaa 133 lda* ra,ea 212 ldwi rb,c 213 spr rb,ra,24,6 set s 214 iso rb,e 215 spr rb,ra,30,6 set p 216 ldf r,ra (or stf r,ra) 217 218 r = .f. e1, e2, ea (or .f. e1, e2, ea = r) eaa 134 lda* ra,ea 220 iso rb,e1 221 spr rb,ra,30,6 set p 222 ldw rb,e2 223 spr rb,ra,24,6 set s 224 ldf r,ra (or stf r,ra) 225 eaa 135 instances of lda* denote lda except for extended addressing (t20), eaa 136 where lla op is implied. 226 */ vaxa 212 ..t10 vaxa 213 vaxa 214 227 if dopindx then $ must set lastuse flags. 228 lastuse(dopvar); lastuse(dopindx); 229 end if; 230 231 i = gw_word; if (isaop) i = gw_addr; eaa 137 .+t20. $ if possible dynamic heap reference. eaa 138 if nsheap_this then eaa 139 $ need special getword call to defer address load if eaa 140 $ reference to heap. we are adding an oracle so getword eaa 141 $ can tell us if doing assignment to indexed heap variable. eaa 142 asmflh_gwi = 1; $ indicate special call eaa 143 $ set if not constant field length and origin. eaa 144 asmflh_varext = (1 -dopfbconst & doplenconst); eaa 145 end if; eaa 146 ..t20 232 getwordc(i, dopkr, dopvar, doff, dopindx); $ get needed word. 233 eaa 147 .+t20. $ see if need special code for dynamic heap reference. eaa 148 if nsheap_this then eaa 149 asmflh_gwi = 0; $ indicate endof special call eaa 150 else eaa 151 asmflh_gwo = 0; eaa 152 end if; eaa 153 ..t20 234 $ see if this is a full word operation. if so 235 $ just move in the word. 236 if doplenval = mws then $ it is. 237 kill(len); $ kill constant length. 238 lastuse(dopkr); $ set last use of target word. 239 if isaop then $ this is an assignment. 240 lastuse(source); $ set status. 241 move_op(dopkr, source); $ move the word. 242 else $ this is an extraction. 243 lastuse(dopor); $ set status. 244 move_op(dopor, dopkr); $ move into output. 245 end if; 246 247 go to ret; $ done in this case. 248 end if; 249 vaxa 215 .+t10. 250 if doplenconst & dopfbconst then $ if both constant. 251 kill(len); kill(dopfbm1); $ kill constants. 252 lastuse(dopkr); $ show last use on target word. 253 if isaop then $ if is assignment. 254 lastuse(source); $ set status. 255 spr_op(source, dopkr, dopfbm1val, doplenval); 256 else $ this is field extract. 257 lastuse(dopor); $ set status. 258 lpr_op(dopor, dopkr, dopfbm1val, doplenval); 259 end if; 260 261 go to ret; $ done 262 end if; 263 264 265 $ in this case we have the more general field extract or assign 266 $ when either the offset or length is an expression. in this 267 $ case, we must build a byte pointer and then issue an -ldf- or 268 $ -stf- operation to do the extract or assign. 269 270 $ first, load the address of the desired target word into a 271 $ machine register to use as a byte pointer. 272 getdreg(work); $ get dummy register for byte pointer. 273 274 $ if wanted word is a short constant which is not in a register, 275 $ must get its address in the base block. 276 i = gd_use; $ default type is gd_use. 277 if (isscon(dopkr) & dr_reg dreg(dopkr) = 0) i = gd_addr; 278 mreg = dr_reg dreg(dopkr); 279 if lastdrop(dopkr) then $ if last use. 280 if mreg then 281 if rl_type reglis(mreg) = rt_need then 282 reglis(mreg) = 0; $ free register. 283 dr_reg dreg(dopkr) = 0; 284 mreg = 0; 285 end if; 286 end if; 287 end if; 288 if mreg & isaop then 289 rl_subtype reglis(mreg) = rt_live; 290 end if; 291 getdesc(dopkr, i, mode, mreg, moff); $ get address. 292 293 getreg(mreg1, rt_live); $ get register for byte pointer. eaa 154 .-t20. 294 emop(mo_lda, mreg1, mode, mreg, moff); $ get address into reg. eaa 155 .+t20. eaa 156 if asmflh_gwo>0 & isaop then eaa 157 emop(mo_hbc, mreg1, mode, mreg,moff); eaa 158 else eaa 159 emop(mo_lla, mreg1,mode, mreg,moff); eaa 160 end if; eaa 161 asmflh_gwo = 0; eaa 162 ..t20 295 if (mode=am_reg & isaop) rl_hold reglis(mreg) = yes; 296 rl_content reglis(mreg1) = work; $ show owner of data. 297 dr_reg dreg(work) = mreg1; $ show in machine register. 298 299 $ now insert position and length into byte pointer. 300 if dopfbconst & dopfbm1val = 0 then $ special case. 301 kill(dopfbm1); $ get rid of constant of zero. 302 else $ normal case. 303 lastuse(dopfbm1); $ show last use of position. 304 spr_op(dopfbm1, work, 30, 6); $ set p field. 305 end if; 306 307 if doplenconst & doplenval = 0 then $ special case. 308 kill(len); $ done with constant length. 309 else $ normal case. 310 lastuse(len); $ show last use of length. 311 spr_op(len, work, 24, 6); $ set s field. 312 end if; 313 314 315 $ now do the actual extract or assign. 316 lastuse(work); $ show next is last use of byte pointer. 317 if isaop then $ if is assignment. 318 lastuse(source); $ set status. 319 stf_op(source, work); $ do the assignment. 320 else $ this is an extraction. 321 lastuse(dopor); $ set status. 322 ldf_op(dopor, work); $ do the extraction. 323 end if; 324 325 kill(dopkr); $ kill the desired word. vaxa 216 ..t10 vaxa 217 .+t32. vaxa 218 lastuse(len); lastuse(dopfbm1); lastuse(dopkr); $ set status. vaxa 219 if isaop then $ is field assignment. vaxa 220 lastuse(source); $ set status. vaxa 221 spr_op(source, dopkr, dopfbm1, len); $ do assign. vaxa 222 else $ is field extract. vaxa 223 lastuse(dopor); $ set status. vaxa 224 lpr_op(dopor, dopkr, dopfbm1, len); $ do extract. vaxa 225 end if; vaxa 226 ..t32 326 327 /ret/ 328 end subr asmfld; 329 .+defer. 1 .=member asmdxch 2 subr asmdxchk(index); $ check for valid index deferral. 3 size index(ps); $ index to check. 4 size in1(ps), in2(ps); $ inputs to operation. 5 6 dophold = dout(index); $ see if index is deferred. 7 if dophold then $ if so, process. 8 $ the index can only be deferred if it is an addition 9 $ of a constant. 10 until yes; $ quit if ok. 11 in1 = dp_inp1 dops(dophold); in2 = dp_inp2 dops(dophold); 12 if dp_op dops(dophold) = do_add then $ may be ok. 13 if (isscon(in1)) quit until; $ this is ok. 14 if isscon(in2) then $ this is ok too. 15 dp_inp1 dops(dophold) = in2; $ switch to simplify 16 dp_inp2 dops(dophold) = in1; $ job of -asmxload-. 17 quit until; $ show is ok. 18 end if; 19 end if; 20 21 return; $ else must evaluate. 22 end until; 23 24 dophold = 0; $ otherwise, show ok. 25 end if; 26 27 end subr asmdxchk; 28 ..defer 1 .=member asmxld 2 subr asmxload(base, index); $ process index for array. 3 $ this routine processes the index for an array. it sets up 4 $ the index to be a machine index into the array. it will 5 $ either multiply the index by the appropriate amount or will 6 $ do a shift of the appropriate amount. in addition, if the 7 $ index is a constant or an index plus a constant, the constant 8 $ will be added to the global variable -doff-. 9 size base(ps); $ base variable (array) 10 size index(ps); $ index. 11 size off(ps); $ temporary offset value. 12 size work(ps), work1(ps); $ temporary registers. 13 size t(ps); $ temporary. 14 15 off = 0; $ initialize offset. 16 17 .+defer. 18 $ if the index is deferred, the it must be constant+new index. 19 $ so get the constant and the new index. 20 if dout(index) then $ it is. 21 work = index; $ save old index. 22 off = conval(dp_inp1 dops(dout(index))); $ get offset. 23 index = dp_inp2 dops(dout(index)); $ get new index. 24 using(index); kill(work); $ set status. 25 end if; 26 ..defer 27 28 $ if index is a constant, just add in constant. 29 if isscon(index) then $ it is a constant. 30 off = off + conval(index); $ add it in. 31 kill(index); index = 0; $ drop index. 32 else $ must multiply or shift. 33 t = nwords(base); $ get amount to multiply by. 34 if (t & (t-1)) = 0 then $ is a power of two. vaxa 227 .+t10 if t^=1 then $ if not identity. 36 getdreg(work); $ get dummy register. vaxa 228 .+t10 assignconst(work1, ((.fb.t)-1)); vaxa 229 .+t32 assignconst(work1, ((.fb.t)+1)); 38 lastuse(work1); lastuse(index); 39 mul2_op(work, index, work1); 40 index = work; vaxa 230 .+t10 end if; 42 43 else $ must multiply. vaxa 231 .+t10 getdreg(work); assignconst(work1, t); vaxa 232 .+t32 getdreg(work); assignconst(work1, t * mcpw); 45 lastuse(work1); lastuse(index); $ set status. 46 mul_op(work, index, work1); $ do multiply. 47 index = work; $ set new index. 48 end if; 49 end if; 50 51 doff = doff + off*nwords(base); $ set new word offset. 52 53 end subr asmxload; 1 .=member assign 2 subr assignr(type); $ assign a dummy register 3 size type(ps); $ encoding of desired argument 4 size db(1); $ holds drop bit 5 size var(ps); $ holds -voa- pointer. 6 size i(ps); $ temporary. 7 size di(ps); $ pointer to dummy item. 8 size dw(ps); $ pointer to dummy word. 9 size ditemval(ditemsz), dwordval(dwordsz); $ temporaries. 10 11 $ first, must determine which -voa- entry is wanted. 12 $ then, the -voa- index and the drop bit are set and the 13 $ main section of this routine is executed. 14 15 $ [ds 11 apr, for efficiency replace else...elseif by goby] 16 if type > va_xarg then $ this is reference to -xarg-. 17 db = xa_db xarg(vv_argbeg voa(voaep)+type-(va_xarg+1)); 18 var = xa_voa xarg(vv_argbeg voa(voaep)+type-(va_xarg+1)); 19 elseif type = va_oup then $ request for output of operation. 20 db = no; var = vv_oup voa(voaep); 21 elseif type = va_inp1 then $ request for input one. 22 db = vv_db1 voa(voaep); var = vv_inp1 voa(voaep); 23 elseif type = va_inp2 then $ request for input two. 24 db = vv_db2 voa(voaep); var = vv_inp2 voa(voaep); 25 elseif type = va_inp3 then $ request for input three. 26 db = vv_db3 voa(voaep); var = vv_inp3 voa(voaep); 27 elseif type = va_inp4 then $ fourth input (in vv_oup) 28 db = vv_dboup voa(voaep); var = vv_oup voa(voaep); 29 elseif type = va_fnct then $ request for function result. 30 db = yes; var = 1; $ set to function return. 31 elseif type = va_spec then $ special call. 32 db = yes; var = voaep; $ specific variable. 33 else $ invalid -assign- call. 34 call aermey(5); $ write error message and terminate. 35 end if; 36 37 $ can begin processing the operand. first, check to 38 $ see if the operand is already in a dummy register. 39 40 if vv_inreg voa(var) then $ it is. 41 $ in this case merely set drop bit status, assign to return 42 $ variable, and increment count. 43 di = vv_inreg voa(var); $ copy register number. 44 if (di_lword ditem(di) = 0) call aermey(6); $ error. 45 46 .+defer. $ check if this is re-use of a deferred temporary. 47 if type=va_oup & di_temp ditem(di) & di_ldrop ditem(di) then 48 vv_inreg voa(var) = 0; $ clear this entry. rke 10 if (di_baseblk ditem(di)) rke 11 bb_bptr baseblock(di_chain ditem(di)) = 0; 50 go to skip; $ must get a new value. 51 end if; 52 ..defer 53 54 $ update status. 55 di_count ditem(di) = di_count ditem(di)+1; $ increment count. 56 di_ldrop ditem(di) = db; $ set new drop value. 57 di_luse ditem(di) = 0; $ show no drop flags yet. 58 59 assignreg = dw_freg dword(di_lword ditem(di)); $ get reg. 60 go to ret; $ return this value. 61 end if; 62 63 /skip/ $ entered here to get new -dreg-. 64 $ handle case where the -voa- operand is a constant. in 65 $ this case the -assignconst- routine is called to process 66 $ the constant. if it is a multi-word constant, then it is 67 $ processed as a normal variable. 68 rkb 19 if vv_const voa(var) & vv_syze voa(var) <= scs 70 & tmctab(vv_lextype voa(var)) <= tmc_b then $ if safe. rkb 20 $ have a short constant. must set special rkb 21 72 $ flags for -assignconst- to indicate that the size of 73 $ the constant is known and also that is already in -val- 74 $ array. then pass the -val- index rather than the 75 $ constant itself to -assignconst-. 76 asconstspc = yes; $ show special case. 77 asconstdb = db; $ copy over drop bit. 78 asconstsz = vv_syze voa(var); $ get size. 79 asconstreal = vv_amode voa(var); $ set mode. 80 assignconst(assignreg, vv_vbeg voa(var)); $ assign constant. 81 go to ret; $ return value. 82 end if; 83 84 $ have a normal case which will be handled in this 85 $ routine. first must obtain dummy values from the free 86 $ list and then fill in the appropriate fields. 87 88 di = ditemfree; $ get off free list. 89 if (di = 0) call aermey(7); $ error if full. 90 ditemfree = di_out ditem(di); $ restore chain. 91 92 dw = dwordfree; $ get off free word list. 93 if (dw = 0) call aermey(8); $ error if full. 94 dwordfree = dw_next dword(dw); $ restore chain. 95 96 assignreg = dregfree; $ get off register list. 97 if (assignreg = 0) call aermey(9); $ error if full. 98 dregfree = dr_next dreg(assignreg); $ restore free chain. 99 100 ditemval = 0; dwordval = 0; $ clear values. 101 102 vv_inreg voa(var) = di; $ point -voa- to item. 103 104 $ fill in common fields in -ditem-. 105 di_syze ditemval = vv_syze voa(var); $ get size. 106 di_mw ditemval = (vv_syze voa(var) > mws); $ multi-word flag. 107 di_nwords ditemval = (vv_syze voa(var) + (mws-1))/mws; 108 di_real ditemval = vv_amode voa(var); $ arithmetic mode. 109 di_temp ditemval = vv_temb voa(var); $ temporary bit. 110 di_var ditemval = (vv_temb voa(var) = no); $ since not constant. 111 di_array ditemval = (vv_dimn voa(var)^=0)&(vv_const voa(var)=no); 112 di_ldrop ditemval = db; $ set drop bit. 113 di_count ditemval = 1; $ show just this one use. 114 di_anum ditemval = vv_argno voa(var); $ get argument number. 115 di_lword ditemval = dw; $ point to -dword-. 116 117 $ set fields in -dword-. 118 dw_freg dwordval = assignreg; $ set first register. 119 dw_word dwordval = di_nwords ditemval; $ set word position. 120 if (di_array ditemval) $ must update word position. 121 dw_word dwordval = (di_nwords ditemval)*2; 122 123 $ process single-word temporaries. 124 if di_temp ditemval & di_mw ditemval = no then $ this case. 125 $ if not output is error. 126 if (type ^= va_oup) call aermey(31); $ terminal error. 127 128 $ otherwise, allocate space in temporary block. 129 baseprobenc(i, 1, bt_temp, yes); $ i --> temporary. 130 bb_pointer baseblock(i) = no; $ show no longer free. 131 bb_bptr baseblock(i) = var; $ point back to -voa-. 132 di_chain ditemval = i; $ point to base block. 133 di_baseblk ditemval = yes; $ show in vase block. 134 di_mblk ditemval = bl_base; $ set machine block. 135 dw_madr dwordval = bb_addr baseblock(i); $ set address. 136 137 else $ multi-word temporary or variable. 138 di_chain ditemval = var; $ point to -voa-. 139 di_mblk ditemval = vv_mblk voa(var); $ get machine block. 140 dw_madr dwordval = vv_madr voa(var); $ get machine address. 141 if (di_anum ditemval) dw_madr dwordval = 1; 142 end if; 143 144 $ finally, plant all values in table. 145 ditem(di) = ditemval; dword(dw) = dwordval; 146 147 dreg(assignreg) = 0; $ clear dummy reg. 148 dr_word dreg(assignreg) = dw; $ point to dummy word. 149 dr_item dreg(assignreg) = di; $ point to dummy item. 150 151 /ret/ $ return register. 152 .+trace. $ generate trace code. 153 if trace_d then $ if tracing enabled. 154 tintl('assign var', var) tintl('to', assignreg) endl 155 end if; 156 ..trace 157 158 end subr assignr; 1 .=member asconst 2 subr asconst(value); $ assign register to constant. 3 size value(ws); $ value to assign to register. 4 size valp(ps); $ pointer to -val- array. 5 size hcode(mws/2);$ hash code in -baseblock-. 6 size i(ps); $ index. 7 size ditemval(ditemsz), dwordval(dwordsz); $ temporaries. 8 size di(ps); $ pointer to dummy item. 9 size dw(ps); $ pointer to dummy word. 10 11 $ the first thing that must be done is to set various parameters 12 $ these are size of constant, index into -val- of constant, 13 $ and drop bit value for constant. normally, these are 14 $ calculated from the constant itself. however, when the 15 $ flag -asconstspc- is set, it indicates that this call is 16 $ from -assignr- and thus these parameters have already been 17 $ set. in the latter case, the flag is reset. 18 19 if asconstspc then $ this is internal call. 20 valp = value; $ value passed is index into -val-. 21 asconstspc = no; $ clear special case flag. 22 else $ normal call. 23 asconstsz = (.fb. value) + (value=0); $ compute size. 24 countup(valptr, valdim, 'val'); $ get space in -val-. 25 valp = valptr; val(valp) = value; $ set into -val- array. 26 asconstdb = yes; $ assume last use. 27 asconstreal = no; $ assume integer value. 28 end if; 29 30 $ must place constant into -baseblock-. the hash code 31 $ is computed by exclusive-or'ing the two half-words of the 32 $ constant. 33 34 hcode = .f. 1,mws/2, val(valp) .exor. .f.mws/2+1,mws/2, val(valp); 35 36 $ insert into table, if not already present, by use of 37 $ -baseprobe- macro to search hashed table. 38 baseprobe(i, hcode, 1, bt_const, valp, ar_val, valptr); 39 40 $ handle case where constant is already in dummy register. 41 if bb_bptr baseblock(i) then $ it is. 42 di = bb_bptr baseblock(i); $ get item pointer. 43 di_count ditem(di) = di_count ditem(di)+1; $ increment count. 44 di_ldrop ditem(di) = asconstdb; $ set drop flag. 45 di_luse ditem(di) = 0; $ show no drop flags yet. 46 asconstreg = dw_freg dword(di_lword ditem(di)); $ get -dreg-. 47 go to ret; $ go return register. 48 end if; 49 50 $ in the other case, get a dummy item, word, and register 51 $ from the free lists and initialize them. 52 53 di = ditemfree; $ get a dummy item. 54 if (di = 0) call aermey(7); $ error if none. 55 ditemfree = di_out ditem(di); $ restore free chain. 56 57 dw = dwordfree; $ get word from free chain. 58 if (dw = 0) call aermey(8); $ error if all being used. 59 dwordfree = dw_next dword(dw); $ restore free chain. 60 61 dwordval = 0; ditemval = 0; $ clear values. 62 63 $ if the address is assigned, copy it. 64 if bb_addr baseblock(i) then $ it is assigned. 65 di_mblk ditemval = bl_base; $ show in base block. 66 dw_madr dwordval = bb_addr baseblock(i); $ set machine addr. 67 end if; 68 69 $ initialize common fields in dummy values. 70 di_chain ditemval = i; $ point to base block. 71 di_baseblk ditemval = yes; $ show in base block. 72 di_syze ditemval = asconstsz; $ set size. 73 di_const ditemval = yes; $ show is constant. 74 di_nwords ditemval = 1; $ this routine only handles 1-word. 75 di_real ditemval = asconstreal; $ set mode. 76 di_lword ditemval = dw; $ point to last word item. 77 di_count ditemval = 1; $ show just this one user. 78 di_ldrop ditemval = asconstdb; $ set drop bit. 79 80 $ check for short constants. 81 if asconstsz <= mps then $ this is short. 82 di_scon ditemval = yes; $ show is short constant. 83 di_cval ditemval = val(valp); $ set short value. 84 end if; 85 86 $ initialize some fields in word value. 87 dw_word dwordval = 1; $ show which word is being referenced. 88 89 90 $ grab a dummy register. 91 asconstreg = dregfree; $ get from free list. 92 if (asconstreg = 0) call aermey(9); $ error if none. 93 dregfree = dr_next dreg(asconstreg); $ restore list. 94 95 $ can point dummy word to dummy register. 96 dw_freg dwordval = asconstreg; $ point first in chain. 97 98 $ plant all values in tables. 99 dword(dw) = dwordval; ditem(di) = ditemval; 100 dreg(asconstreg) = 0; $ clear dummy register. 101 102 $ set up chains from dummy register. 103 dr_word dreg(asconstreg) = dw; $ point to dummy word. 104 dr_item dreg(asconstreg) = di; $ point to dummy item. 105 106 bb_bptr baseblock(i) = di; $ finally, point base block to item. 107 108 /ret/ $ have register to return. 109 .+trace. $ trace code. 110 if trace_d then $ request trace code. 111 tintl('asconst val', val(valp)) tintl('to', asconstreg) endl 112 end if; 113 ..trace 114 115 return; 116 end subr asconst; 1 .=member clearr 2 subr clearr(reg); $ clear a dummy register. 3 size reg(ps); $ register to clear. 4 size i(ps), j(ps); $ temporary indexes. 5 6 $ do a check to ensure that things haven't gotten messed up. 7 if (istemp(reg)) call aermey(12); 8 9 10 $ must drop any registers that contain data for other 11 $ words of the item if multi-word. 12 if ismw(reg) then $ must check other words. 13 i = di_lword ditem(dr_item dreg(reg)); $ get first in chain. 14 while i; $ while more words to loop over. 15 if i ^= dr_word dreg(reg) then $ skip original word. 16 j = dw_freg dword(i); $ point to first register. 17 if dr_reg dreg(j) then $ must drop register. 18 reglis(dr_reg dreg(j)) = 0; $ drop. 19 dr_reg dreg(j) = 0; $ show not in register. 20 end if; 21 end if; 22 23 i = dw_next dword(i); $ get next word in chain. 24 end while; 25 end if; 26 27 28 29 .+defer. $ only needed if deferring. 30 $ if register is output of deferred operation, that operation 31 $ was never used so flush it. 32 if dout(reg) then $ must flush operation. 33 dropdop(dout(reg)); $ flush operation. 34 dout(reg) = 0; $ clear field. 35 end if; 36 ..defer 37 38 $ if a register has been assigned to the register, free it 39 $ unless it has been permanently assigned. 40 if dr_reg dreg(reg) then $ must drop machine register. 41 if rl_perm reglis(dr_reg dreg(reg)) = no & spcdrop = no then 42 reglis(dr_reg dreg(reg)) = 0; $ drop machine register. 43 dr_reg dreg(reg) = no; $ show not in register. 44 end if; 45 end if; 46 47 .+trace if trace_d then tintl('*clear', reg) endl end if; 48 49 end subr clearr; 1 .=member dropr 2 subr dropr(arg); $ drop a -dreg- or -dop-. 3 $ this routine is called by the -drop- or -dropdop- macros. 4 $ if it is called to drop a register, the -drop- macro does 5 $ nothing unless the last use bit is set. this routine then 6 $ checks if the value is dead (count=1 & last drop set). if so, 7 $ it frees the item. otherwise, it merely decrements the usage 8 $ count. 9 10 $ when this routine is called by the -dropdop- macro, it will 11 $ add the -dop- to the free chain and recursively free the 12 $ operands of the operation. 13 size arg(ps); $ argument (-dreg- or -dop-) 14 size i(ps), j(ps), k(ps); $ temporaries. 15 size reg(ps); $ -dreg- pointer. 16 size di(ps); $ -ditem- pointer. 17 18 .+defer. $ additional code for dererring. 19 $ if deferring is being used, this routine is recursive. t 20 $ therefore, a stack is used to list all the -dreg-'s that must 21 $ be dropped. a loop is then entered until the stack is empty. 22 size stack(ps); dims stack(20); $ the stack. 23 size stackp(ps); $ pointer into -stack-. 24 size dop(ps); $ index into -dops-. 25 26 +* push(d) = $ push onto stack. 27 stackp = stackp+1; $ up pointer. 28 stack(stackp) = d; ** $ add onto stack. 29 30 +* pop(d) = $ pop from stack. 31 d = stack(stackp); $ read data. 32 stackp = stackp-1; ** $ decrement pointer. 33 34 +* exit = cont while stackp; ** $ recursive exit. 35 36 $ initialize stack and contents. 37 stackp = 0; $ initially empty stack. 38 if dropdopflg then $ this is -dop-. 39 dropdopflg = no; $ reset flag. 40 dop = arg; $ set index. 41 go to procdop; $ go process -dop-. 42 end if; 43 44 push(arg); $ push first -dreg- onto stack. 45 46 $ loop until the stack is empty. 47 while stackp; $ done when nothing more to drop. 48 pop(reg); $ get first thing to do from stack. 49 .-defer. $ generate code for non-deferrings. 50 +* exit = return; ** $ process exit code. 51 52 reg = arg; $ set thing to drop. 53 ..defer 54 55 $ can just return if this was a freed dummy register. 56 if (dr_item dreg(reg) = 0) exit; $ done in this case. 57 58 .+trace. $ generate trace code. 59 if trace_d then $ print trace info. 60 tintl(' drop, reg', reg) endl 61 end if; 62 ..trace 63 64 $ see if must drop or just decrement count. 65 if di_count ditem(dr_item dreg(reg)) ^= 1 ! 66 di_ldrop ditem(dr_item dreg(reg)) = no ! spcdrop then 67 $ must decrement count and last usage. 68 di = dr_item dreg(reg); $ get item number. 69 if (di_luse ditem(di)) di_luse ditem(di) = 70 di_luse ditem(di) - 1; 71 di_count ditem(di) = di_count ditem(di) - 1; 72 if (spcdrop) di_ldrop ditem(di) = no; 73 exit; $ done with this case. 74 end if; 75 76 $ otherwise, must actually drop register. 77 78 79 $ drop all forms. 80 di = dr_item dreg(reg); $ point to dummy item. 81 i = di_lword ditem(di); $ get last dummy word. 82 while i; $ loop over each word. 83 j = dw_freg dword(i); $ get first form in word. 84 $ see if must store any live. 85 if di_var ditem(di) then $ is variable. 86 if dr_reg dreg(j) then $ it is in a register. 87 if (rl_perm reglis(dr_reg dreg(j))) 88 call aermey(32); $ this is an error. 89 if (rl_type reglis(dr_reg dreg(j)) = rt_live) 90 store(dr_reg dreg(j), j); $ store it. 91 end if; 92 end if; 93 dropform(j); $ drop this form. 94 95 j = dw_next dword(i); $ get next word in chain. 96 97 $ drop that current word. 98 dword(i) = 0; $ clear it. 99 dw_next dword(i) = dwordfree; dwordfree = i; $ free it. 100 i = j; $ set to next word. 101 end while; 102 103 $ drop any live address for this item. 104 if (di_addrreg ditem(di)) reglis(di_addrreg ditem(di)) = 0; 105 106 $ if this is not a constant or temporary and it is 107 $ chained to the -voa-, clear the -voa- pointer to this 108 $ dummy item. 109 if di_chain ditem(di) then $ there is a chain. 110 i = di_chain ditem(di); $ get pointer. 111 if di_baseblk ditem(di) then $ in base block. 112 if di_temp ditem(di) then $ free temporary. 113 bb_pointer baseblock(i) = yes; 114 if bb_bptr baseblock(i) then $ if points to voa 115 $ check that this pointer in fact points 116 $ to the dummy item that are freeing. 117 if (vv_inreg voa(bb_bptr baseblock(i)) = di) 118 vv_inreg voa(bb_bptr baseblock(i)) = 0; 119 end if; 120 end if; 121 bb_bptr baseblock(i) = 0; $ clear base block pointer 122 else $ in -voa-. 123 $ check that clear the correct pointer 124 if (vv_inreg voa(i) = di) vv_inreg voa(i) = 0; 125 end if; 126 end if; 127 128 .+defer dop = di_out ditem(di); $ set if this is output. 129 130 $ finally free dummy item. 131 ditem(di) = 0; $ clear all status info. 132 di_out ditem(di) = ditemfree; $ point this to free chain. 133 ditemfree = di; $ put this on free chain. 134 135 .+defer if (dop = 0) $ only quit if no deferred output. 136 exit; $ quit this drop call. 137 138 139 $ process the dropping of a deferred operation.. first 140 $ push any registers that this used onto the stack of work 141 $ to be done. then free this operation. 142 /procdop/ 143 .+trace. 144 if trace_o then $ print output. 145 tintl('drop, dop', dop) endl 146 end if; 147 ..trace 148 149 go to n(dp_nargs dops(dop)) in 1 to 3; $ get number to drop. 150 151 /n(3)/ push(dp_inp3 dops(dop)); 152 /n(2)/ push(dp_inp2 dops(dop)); 153 /n(1)/ push(dp_inp1 dops(dop)); 154 155 $ actually free this deferred operation. 156 dp_chain dops(dop) = dopfree; $ set this to free chain. 157 dopfree = dop; $ put this onto free chain. 158 end while; $ loop around again. 159 160 macdrop(push) macdrop(pop) 161 ..defer 162 163 macdrop(exit) 164 165 end subr dropr; 1 .=member dmpdreg 2 .+trace. 3 subr dumpdregs; $ dump dummy registers. 4 $ this routine is used for tracing purposes to print out 5 $ the contents of the dummy items, words, and registers. 6 size i(ps); $ index. 7 size ditemmap(ditemdim), dwordmap(dworddim), dregmap(dregdim); 8 size ditemval(ditemsz), dwordval(dwordsz), dregval(dregsz); 9 10 11 $ first print dummy items. see which are on free chain. 12 i = ditemfree; $ point to free chain. 13 ditemmap = 0; $ show none initially free. 14 while i; $ while more on free chain. 15 if (.f. i, 1, ditemmap) call aermey(13); $ dup -ditem-. 16 .f. i, 1, ditemmap = yes; $ else set bit to show free. 17 i = di_out ditem(i); $ get next in chain. 18 end while; 19 20 $ complement map to show which items are in use. 21 ditemmap = .not. ditemmap; 22 23 if ditemmap then 24 $ print title. 25 endl textl(' dummy items') endl endl 26 textl(' n b chain s m r a t c v l syze count nwrds luse ' 27 !! 'lwrd mblk') endl 28 29 $ print each dummy item. 30 while ditemmap; $ while more to print. 31 i = .fb. ditemmap; $ get index to print. 32 intlp(i, 2) $ print index. 33 ditemval = ditem(i); $ get values. 34 35 $ print header information. 36 intlp(di_baseblk ditemval,2) 37 intlp(di_chain ditemval, 6) intlp(di_scon ditemval, 2) 38 intlp(di_mw ditemval, 2) intlp(di_real ditemval, 2) 39 intlp(di_array ditemval, 2) 40 intlp(di_temp ditemval, 2) intlp(di_const ditemval, 2) 41 intlp(di_var ditemval, 2) 42 intlp(di_ldrop ditemval, 2) 43 intlp(di_syze ditemval, 5) 44 intlp(di_count ditemval, 6) intlp(di_nwords ditemval, 6) 45 intlp(di_luse ditemval, 5) intlp(di_lword ditemval, 5) 46 intlp(di_mblk ditemval, 5) 47 48 $ print out any special values. 49 if (di_scon ditemval) then 50 textl(' cval ') octl(di_cval ditemval) 51 end if; 52 if (di_addrreg ditemval) tintl('addrreg',di_addrreg ditemval) 53 .+defer if (di_out ditemval) tintl('out', di_out ditemval) 54 if (di_anum ditemval) tintl('anum', di_anum ditemval) 55 56 .f. i, 1, ditemmap = no; $ show done with register. 57 endl 58 end while; 59 else textl('no dummy items') endl end if; 60 61 $ print dummy words. 62 dwordmap = 0; $ show none in use yet. 63 i = dwordfree; $ start at head of free chain. 64 65 while i; $ while some in free chain. 66 if (.f. i, 1, dwordmap) call aermey(14); $ dup -dword-. 67 .f. i, 1, dwordmap = yes; $ else show free. 68 i = dw_next dword(i); $ point to next in chain. 69 end while; 70 71 $ complement map to get words in use. 72 dwordmap = .not. dwordmap; 73 74 if dwordmap then 75 $ print title. 76 endl endl textl(' dummy words') endl endl 77 textl(' n next madr freg word') endl 78 79 while dwordmap; $ while more in use. 80 i = .fb. dwordmap; $ get first in list. 81 intlp(i, 3) $ print out index. 82 dwordval = dword(i); $ get value. 83 84 $ print out values. 85 intlp(dw_next dwordval, 5) intlp(dw_madr dwordval, 5) 86 intlp(dw_freg dwordval, 5) 87 intlp(dw_word dwordval, 5) 88 89 .f. i, 1, dwordmap = no; $ show this not in use. 90 endl 91 end while; 92 else textl('no dummy words') endl end if; 93 94 95 $ process dummy registers. 96 dregmap = 0; $ show none free yet. 97 i = dregfree; $ point to head of free chain. 98 99 while i; $ loop over free chain. 100 if (.f. i, 1, dregmap) call aermey(15); $ dup -dreg-. 101 .f. i, 1, dregmap = yes; $ show on free chain. 102 i = dr_next dreg(i); $ get next on chain. 103 end while; 104 105 $ invert map to get registers in use. 106 dregmap = .not. dregmap; 107 108 if dregmap then 109 $ print titles. 110 endl endl textl(' dummy registers') endl endl 111 textl(' n next item word reg') endl 112 113 $ process each register. 114 while dregmap; $ while more in use. 115 i = .fb. dregmap; $ get first to process. 116 intlp(i, 3); $ print index. 117 dregval = dreg(i); $ get register value. 118 119 $ print information. 120 intlp(dr_next dregval, 5) intlp(dr_item dregval, 5) 121 intlp(dr_word dregval, 5) 122 intlp(dr_reg dregval, 4) 123 if (dr_next dregval) call aermey(21); 124 125 .f. i, 1, dregmap = no; $ show done this one. 126 endl 127 end while; 128 else textl('no registers in use') endl end if; 129 130 endl $ leave a blank line at the end. 131 132 end subr dumpdregs; 133 ..trace 1 .=member dmpmreg 2 .+trace. $ only used if tracing. 3 subr dumpmregs; $ dump machine registers. 4 $ this routine prints a dump of the machine register status 5 $ for use in debugging. 6 size i(ps); $ loop index. 7 size nact(ps); $ number of active registers. 8 size rname(.sds. 4); $ register names. 9 dims rname(rhihi); $ number of registers. 10 data rname = ' r0 ', ' r1 ', ' r2 ', ' r3 ', ' r4 ', 11 ' r5 ', ' r6 ', ' r7 ', ' r8 ', ' r9 ', vaxa 233 .+t10 'r10 ', 'r11 ', 'r12 ', 'r13 ', 'r14 ', vaxa 234 .+t32 'r10 ', 'r11 ', 'ap ', 'fp ', 'sp ', vaxa 235 .+t10 'r15 '; vaxa 236 .+t32 'pc '; 14 15 size rtype(.sds. 5); $ register types. 16 dims rtype(rt_permlive+1); $ number of types +1. 17 data rtype(rt_dead+1) = ' dead': 18 rtype(rt_need+1) = ' need': 19 rtype(rt_address+1) = ' addr': 20 rtype(rt_live+1) = ' live': 21 rtype(rt_liveaddr+1) = ' ladr': 22 rtype(rt_permresv+1) = ' resv': 23 rtype(rt_perm+1) = ' perm': 24 rtype(rt_permlive+1) = ' prml'; 25 26 27 28 nact = 0; 29 do i = r0 to rhi; $ loop over all registers. vaxa 237 if (reglis(i) = 0) cont do; $ dont list dead. 31 nact = nact + 1; 32 if nact = 1 then $ if need title. 33 endl textl(' machine registers') endl 34 textl('nam content type h ah useval') endl 35 end if; 36 37 $ list attributes. 38 textl(rname(i)) intlp(rl_content reglis(i), 8) 39 textl(rtype(rl_type reglis(i)+1)) 40 intlp(rl_hold reglis(i), 2) intlp(rl_addrhold reglis(i), 3) 41 intlp(rl_usevalue reglis(i), 7) endl 42 end do; 43 44 45 endl $ leave a blank line. 46 end subr dumpmregs; 1 .=member endblk 2 ..trace 3 subr endblock; $ end a basic block. 4 $ this routine is called by -asmprog- when a basic block is to 5 $ be ended. this routine drops all registers except those 6 $ which only need be dropped when a label is encountered. 7 size i(ps); $ do loop index. 8 size reg(ps); $ -dreg- pointer. 9 10 $ if the -reissuedop- flag is on, this routine just returns 11 $ because it will be called again. 12 .+defer if (reissuedop) return; 13 14 .+trace if trace_a then textl(' *endblock') endl end if; 15 16 do i = r0 to rhi; 17 if (rl_perm reglis(i)) cont do; $ skip permanent. 18 if (rl_type reglis(i) = rt_dead) cont do; $ ignore dead. 19 if (rl_type reglis(i) = rt_address) cont do; $ leave addr. 20 21 $ know that have a register which either contains 22 $ data or a live address. drop the appropriate 23 $ type. 24 if rl_type reglis(i) = rt_liveaddr then $ error. 25 call aermey(30); $ cannot have this at block end. 26 else $ must be a data type. 27 dr_reg dreg(rl_content reglis(i)) = 0; $ clear pointer. 28 end if; 29 30 reglis(i) = 0; $ drop register. 31 end do; 32 33 end subr endblock; 1 .=member forcer 2 subr forcer(reg, flg); $ force a variable to register zero. 3 $ this routine is called by the macro -forcezero-. it puts 4 $ either a variable or the address of a variable into register 5 $ zero. 6 size reg(ps); $ variable to force into register zero. 7 size flg(1); $ set if address wanted in r0. 8 size t(ps); $ temporary. 9 size mode(ps); $ mode. 10 size mreg(ps); $ machine register. 11 size moff(mosize); $ machine offset. 12 size mnam(ps); 13 .+trace. 14 if trace_a then $ trace output wanted. 15 tintl('force, reg', reg) tintl('fl', flg) endl 16 end if; 17 ..trace 18 19 $ clear register zero before putting anything into it. 20 if rl_type reglis(r0) ^= rt_dead then $ must do it. 21 getreg(t, rl_type reglis(r0)); $ get new register. 22 if t then $ register available. 23 reglis(t) = reglis(r0); $ copy status. 24 mrcopy(t, r0); $ copy regs. 25 end if; 26 dr_reg dreg(rl_content reglis(r0)) = t; $ set new owner. 27 reglis(r0) = 0; $ free register zero. 28 end if; 29 30 $ if -reg- is given as zero, this was a call just to clear 31 $ register zero. 32 33 if (reg = 0) return; 34 35 $ first, check to see whether the address or data is wanted 36 $ in register zero. 37 if flg then $ address wanted in register zero. 38 $ get the descriptor for the last word. 39 getdesc(dw_freg dword(di_lword ditem(dr_item dreg(reg))), 40 gd_addr, mode, mreg, moff); $ get machine values. 41 emop(mo_lda, r0, mode, mreg, moff); 42 43 else $ want variable itself in register. 44 mreg = r0; $ set to get into r0. 45 getvar(reg, gd_inregnu, mode, mreg, moff); $ load to register 46 end if; 47 48 drop(reg); $ free if last use. 49 50 end subr forcer; 1 .=member getdreg 2 subr getdregr(dr); $ get a new dummy register. 3 size dr(ps); $ register obtained. 4 size dw(ps); $ pointer to dummy word. 5 size di(ps); $ pointer to dummy item. 6 size bbp(ps); $ base block pointer. 7 size ditemval(ditemsz), dwordval(dwordsz); $ temporaries. 8 9 $ first get a new dummy item, word, and register. 10 di = ditemfree; $ get from free list. 11 if (di = 0) call aermey(7); $ none left. 12 ditemfree = di_out ditem(di); $ rechain. 13 14 dw = dwordfree; $ get free word. 15 if (dw = 0) call aermey(8); $ none left. 16 dwordfree = dw_next dword(dw); $ rechain. 17 18 dr = dregfree; $ get free register. 19 if (dr = 0) call aermey(9); $ none left. 20 dregfree = dr_next dreg(dr); $ rechain. 21 22 $ initialize values. 23 ditemval = 0; dwordval = 0; 24 25 $ find an available temporary. 26 baseprobenc(bbp, 1, bt_temp, yes); $ scan base block. 27 bb_pointer baseblock(bbp) = no; $ show no longer free. 28 29 $ fill in fields for -ditem-. 30 di_chain ditemval = bbp; $ point to base block. 31 di_baseblk ditemval = yes; $ show is in base block. 32 di_syze ditemval = mps; $ set to one word. 33 di_nwords ditemval = 1; $ show one word long. 34 di_temp ditemval = yes; $ show is temporary. 35 di_ldrop ditemval = yes; $ show this is last use. 36 di_count ditemval = 1; $ show just one user. 37 di_mblk ditemval = bl_base; $ set machine block. 38 di_lword ditemval = dw; $ point to dummy word. 39 40 $ set fields for -dword-. 41 dw_madr dwordval = bb_addr baseblock(bbp); $ machine address. 42 dw_word dwordval = 1; $ show is first word. 43 dw_freg dwordval = dr; $ point to first in register chain. 44 45 $ replace fields and do final chaining. 46 ditem(di) = ditemval; dword(dw) = dwordval; 47 48 dreg(dr) = 0; dr_item dreg(dr) = di; dr_word dreg(dr) = dw; 49 50 .+trace if trace_d then tintl('gotdreg', dr) endl end if; 51 52 end subr getdregr; 1 .=member getword 2 subr getwordr(out, in, type, offset, index); $ word/character. 3 $ this routine is used to address, store, or retrieve a word 4 $ or character of a multi-word item. 5 size out(ps); $ output dummy register. 6 size in(ps); $ input dummy register. 7 size type(ps); $ type of call. 8 size offset(ps); $ word or character offset. 9 size index(ps); $ register for index. 10 11 $ this routine uses a table to define the operations to be 12 $ performed on the operands. 13 14 $ the fields in this table are defined below. 15 16 +* gt_inddr = .f. 1, 1, ** $ 'drop forms if indexed' 17 +* gt_kind = .f. 3, 2, ** $ kinds of 'output's. 18 +* mop_gt = .f. 9, 8, ** $ machine instruction to issue. 19 20 $ kind values for output. 21 22 +* gk_output = 0 ** $ it is a real output. 23 +* gk_input = 1 ** $ it is really an input operand. 24 25 +* num_gk = 1 ** 26 27 +* gwt(typ, mop, drp, outk) = $ build table. 28 gwtab(typ) = mop*4b'100'+outk*1b'100'+drp ** 29 30 size gwtab(ws); dims gwtab(num_gw); $ define table. 31 data $ initialize table. 32 $ type mop drp kind 33 $ ---- --- --- ---- 34 35 gwt(gw_word, mo_ldw, no, gk_output): 36 gwt(gw_addr, mo_lda, yes, gk_output): 37 gwt(gw_sword, mo_stw, yes, gk_input); 38 39 macdrop(gwt) 40 41 size woff(ps); $ word offset. 42 size nmadr(ws); $ new machine address. 43 size reg(ps), reg1(ps); $ temporary -dreg-'s. 44 size mreg(ps), mreg1(ps), mreg2(ps); $ temporary -mreg-'s. 45 size moff(mosize); $ machine offset. dsj 57 size moff1(mosize); $ temporary. 46 size mode(ps); $ machine address type. 47 size t(ws), t1(ps);$ dummy variables and temporaries. 48 size mop(ps); $ machine operation to issue. 49 size hcode(mws/2); $ hash code for -baseblock-. 50 size di(ps); $ dummy item index. 51 size dw(ps); $ dummy word index. 52 eaa 163 .+t20. $ special code for nsheap (extended addressing) eaa 164 if asmflh_gwi then $ if called from asmfld eaa 165 $ asmflh_gwi nonzero indicates we are being called from asmfld eaa 166 $ and caller wants to know if assignment target is in dynamic eaa 167 $ heap. eaa 168 asmflh_gwo = 0; $ assume not heap reference eaa 169 end if; eaa 170 ..t20 53 woff = offset; $ copy offset to local variable. 54 55 $ now check for the normal case and exit immediately if so. 56 if (type = gw_addr ! type = gw_word) & nwords(in) = 1 & index = no 57 & di_array ditem(dr_item dreg(in)) = no then $ do nothing. 58 out = in; $ just copy the word to the output. 59 go to ret; $ done. 60 end if; 61 62 $ first, get pointers to dummy item and word. 63 di = dr_item dreg(in); dw = dr_word dreg(in); 64 65 if di_anum ditem(di) ^= 0 & di_addrreg ditem(di) = 0 then 66 $ must obtain machine reg with address of rightmost word. 67 getreg(mreg, rt_liveaddr); $ get register. vaxa 238 .+t10 emop(mo_ldw, mreg, am_rel, parmreg, di_anum ditem(di)-1); vaxa 239 .+t32 moff1 = 0; mbo_off moff1 = di_anum ditem(di); vaxa 240 .+t32 emop(mo_ldw, mreg, am_rel, parmreg, moff1); 69 rl_type reglis(mreg) = rt_address; 70 rl_content reglis(mreg) = di; 71 rl_hold reglis(mreg) = yes; 72 di_addrreg ditem(di) = mreg; 73 end if; 74 75 getdesc(in, gd_addr, mode, mreg, moff); 76 nmadr = mbo_off moff - (dw_word dword(dw) - woff) + 1; 77 if (nmadr<0) nmadr = mneg(iabs(nmadr)); 78 t = nmadr - 1; 79 if (t<0) t = mneg(iabs(t)); 80 mbo_off moff = t; 81 82 $ build a new dummy word for the desired word. 83 $ first see if it already exists. 84 t1 = di_lword ditem(di); $ set to start of chain. 85 while t1; $ while more in chain. 86 if dw_word dword(t1) = woff then $ found what want. 87 dw = t1; reg = dw_freg dword(dw); $ set to this one. 88 quit while; $ show found. 89 end if; 90 91 t = t1; $ save last position in chain. 92 t1 = dw_next dword(t1); $ point to next. 93 end while; 94 95 $ if hit end of chain, must build new word. 96 if t1 = 0 then $ at end of chain. 97 dw = dwordfree; $ get from free chain. 98 if (dw = 0) call aermey(7); $ none left. 99 dwordfree = dw_next dword(dw); $ rechain. 100 101 $ build new word. 102 dword(dw) = dword(t); $ copy most from old. 103 dw_madr dword(dw) = nmadr; $ set new address. 104 dw_word dword(dw) = woff; $ set to wanted word. 105 dw_next dword(t) = dw; $ put into chain. 106 107 $ get new dummy register. 108 reg = dregfree; $ get from free list. 109 if (reg = 0) call aermey(9); $ none left. 110 dregfree = dr_next dreg(reg); $ rechain. 111 112 $ chain in new register. 113 dreg(reg) = 0; $ set initial values. 114 dr_item dreg(reg) = di; dr_word dreg(reg) = dw; 115 dw_freg dword(dw) = reg; 116 end if; 117 118 $ split up into two cases depending on whether or not 119 $ an index register is specified. 120 if index then $ have an index register. 121 $ first, save all 'live' forms. 122 t = di_lword ditem(di); $ point to first word in chain. 123 while t; $ while more word. 124 $ the only form which can be live is the 'primary' 125 $ form so just check it. 126 if dr_reg dreg(dw_freg dword(t)) then $ in a register. 127 $ see if live. 128 if rl_type reglis(dr_reg dreg(dw_freg dword(t))) = 129 rt_live then $ must do the store. 130 store(dr_reg dreg(dw_freg dword(t)), 131 dw_freg dword(t)); $ store live variable. 132 end if; 133 end if; 134 t = dw_next dword(t); $ get next in chain. 135 end while; 136 137 $ get index value into a machine register. dsj 58 getvar(index, gd_reg, t, mreg1, moff1); 139 vaxa 241 .+t10. 140 $ check if the index register is in r0. if so, 141 $ must move it somewhere else. 142 if mreg1 = r0 then $ it is. 143 getreg(mreg1, rt_live); $ get a register. 144 dr_reg dreg(index) = mreg1; $ set new register. 145 reglis(mreg1) = reglis(r0); $ copy status. 146 reglis(r0) = 0; $ clear r0. 147 mrcopy(mreg1, r0); 148 end if; vaxa 242 ..t10 149 150 $ [rk 24 may code below can be optimized to do only iad, 151 $ based on lastuse information.] 152 if mode = am_rel then $ if relative 153 getreg(mreg2, rt_liveaddr); 154 emop(mo_ldw, mreg2, am_reg, mreg1, 0); 155 emop(mo_iad, mreg2, am_reg, mreg, 0); 156 reglis(mreg2) = 0; 157 rl_hold reglis(mreg2) = yes; 158 mreg = mreg2; 159 elseif mode = am_mem then $ if in memory. 160 mreg = mreg1; 161 mode = am_rel; 162 else $ fatal if here 163 call aermey(35); $ need correct aermey message. 164 end if; 165 $ finally, select operation type by output type. 166 go to iopk(gt_kind gwtab(type)) in 0 to num_gk; 167 168 /iopk(gk_output)/ $ indexed -getword- or -getaddr-. 169 $ in these cases, the word or address of the desired 170 $ item will be loaded into a new dummy register. the 171 $ result form will have minimal information set because 172 $ it is only used in a few cases. 173 getdreg(out); $ get a dummy register for the output. 174 isreal(out) = di_real ditem(di); $ set arithmetic mode. 175 dw = dr_word dreg(out); di = dr_item dreg(out); $ get ptrs. 176 mop = mop_gt gwtab(type); $ get machine operation to issue. 177 178 $ get appropriate register. 179 getreg(mreg2, rt_live); $ get general register. 180 eaa 171 .+t20. eaa 172 $ note only load address for indexed field assignment eaa 173 if mop=mo_lda & nsheap_this & (mbo_blk moff = nsheap_blk) then eaa 174 $ if assignment to dynamic heap, emit special opcode. eaa 175 mop = mo_hba; eaa 176 if (asmflh_varext) mop = mo_hbb; eaa 177 asmflh_gwo = 1; $ indicate heap reference. eaa 178 asmflh_mreg = mreg; $ save register. eaa 179 asmflh_moff = moff; $ save offset. eaa 180 asmflh_mode = mode; $ save mode. eaa 181 end if; eaa 182 ..t20 181 $ do the operation. 182 emop(mop, mreg2, mode, mreg, moff); $ do load or load addr. 183 184 $ update the status depending on type. 185 if type = gw_addr then $ update address values. 186 di_addrreg ditem(di) = mreg2; $ show register. 187 di_mw ditem(di) = yes; $ show multi-word. vaxa 243 rl_type reglis(mreg2) = rt_liveaddr; $ set reg. type. 189 rl_content reglis(mreg2) = di; $ show owner. 190 dw_madr dword(dw) = 1; $ show offset of zero. 191 else $ this is a value load. 192 dr_reg dreg(out) = mreg2; $ show in register. 193 rl_content reglis(mreg2) = out; $ show owner. 194 end if; 195 go to reti; $ process common indexed return actions. 196 197 198 /iopk(gk_input)/ $ input operand storeword 199 $ load input into register. dsj 59 getvar(out, gd_reg, t, mreg2, moff1); 201 mop = mop_gt gwtab(type); $ set op. to issue. 202 $ do operation. 203 emop(mop, mreg2, mode, mreg, moff); $ do store. 204 go to reti; $ go do common return. 205 206 207 /reti/ $ common return from indexed operations. 208 $ if -inddr- flag is set in type table for this operation 209 $ type, must drop all forms in registers. 210 if gt_inddr gwtab(type) then $ must do drops. 211 t = di_lword ditem(dr_item dreg(in)); $ start of words. 212 while t; $ while more in chain. 213 t1 = dw_freg dword(t); $ first in register chain. 214 if dr_reg dreg(t1) then $ is in register. 215 reglis(dr_reg dreg(t1)) = 0; $ free register. 216 dr_reg dreg(t1) = 0; $ show freed. 217 end if; 218 t = dw_next dword(t); $ next in word chain. 219 end while; 220 end if; 221 go to ret; $ go do common return. 222 223 else $ non-indexed case. 224 225 $ go process each operation type. 226 go to opk(gt_kind gwtab(type)) in 0 to num_gk; 227 228 /opk(gk_output)/ $ case where output is a alternate form. 229 out = reg; $ just point to the new form. 230 go to ret; $ go to common return processing. 231 232 233 234 /opk(gk_input)/ $ input -- storeword, 235 236 $ this is a simple store operation, can just do 237 $ move to see if should store or keep in register. 238 move_op(dw_freg dword(dw), out); $ do store. 239 return; $ done -- already dropped. 240 241 end if; 242 243 244 /ret/ $ common return processing. 245 $ at this point, merely issue drop calls for each input 246 $ or output used. 247 if index then drop(index); end if; 248 drop(in); $ drop input. 249 250 $ drop output unless -output- type. 251 if gt_kind gwtab(type) ^= gk_output then $ can drop output. 252 drop(out); $ go drop it. 253 end if; 254 255 .+trace. 256 if trace_d then $ print trace info. 257 if type = gw_word ! type = gw_addr then 258 tintl('gotwordr', out) tintl('offset', offset) 259 tintl('index', index) endl 260 end if; 261 end if; 262 ..trace 263 264 macdrop(gk_output) macdrop(gk_oper) macdrop(gk_input) 265 macdrop(gk_mask) macdrop(num_gk) 266 267 end subr getwordr; 1 .=member inzero 2 subr inzeror(reg, flg); $ indicate value in register zero. 3 $ the routine is called by the macro -inzero- to indicate 4 $ that a value is currenly in register zero. this is normally 5 $ called after a function call. the first parameter is the 6 $ dummy register describing the operand. the second parameter 7 $ is a flag indicating whether or not it is actually the address 8 $ of the operand. 9 size reg(ps); $ operand contained in register zero. 10 size flg(1); $ set if address is in register zero. 11 size mreg(ps); $ machine register for operand. 12 size t(ps); $ temporary and dummy variable. 13 14 $ see if quantity or address of quantity is in register zero. 15 if flg then $ this is case where address is in register. 16 $ in this case, allocate a register to contain the address 17 $ and move it from r0. vaxa 244 .+t10 getreg(mreg, rt_liveaddr); $ must get a register. vaxa 245 .+t32 mreg = r0; $ fake to use this register. 19 rl_content reglis(mreg) = dr_item dreg(reg); $ show owner. 20 di_addrreg ditem(dr_item dreg(reg)) = mreg; $ point to reg. 21 t = di_lword ditem(dr_item dreg(reg)); $ point to last word. 22 if (t^=dr_word dreg(reg) ! dw_next dword(t)) call aermey(17); 23 dw_madr dword(t) = 1; $ reset machine address. vaxa 246 .+t10 mrcopy(mreg, r0); $ copy it over. 25 else $ data item is in r0. 26 $ in this case, set the status of the variable to 27 $ indicate that it is in register zero. 28 rl_content reglis(r0) = reg; $ set contents of register. 29 rl_type reglis(r0) = rt_live; $ set status. 30 dr_reg dreg(reg) = r0; $ point varible to register. 31 end if; 32 33 drop(reg); $ drop if last use. 34 end subr inzeror; 1 .=member labdef 2 subr labdefr(label, flag); $ define a label. 3 $ this routine is called by the -labdef- macro to define the 4 $ position of a label in code. if desired, it performs some 5 $ clearing actions corresponding to the occurance of a label. 6 $ if branch optimization is enabled, and there are fixup 7 $ requests pending on the label, they will be emitted. 8 size label(ps); $ label to define. 9 size flag(1); $ set to indicate clearing action wanted. 10 size i(ps), j(ps); $ work variables. 11 size reg(ps); $ temporary -dreg- pointer. 12 13 .+trace. $ generate trace code. 14 if trace_a then $ trace wanted. 15 tintl('labdef, label', label) tintl('f', flag) endl 16 end if; 17 ..trace 18 19 $ if flag is set, drop all base registers and register with 20 $ addresses in them. in addition, set all permenantly assigned 21 $ registers to live status. 22 if flag then $ clearing actions wanted. 23 do i = r0 to rhi; $ scan all registers. 24 if rl_type reglis(i) = rt_perm then $ set to live. 25 if (isconst(rl_content reglis(i))) cont do; 26 rl_type reglis(i) = rt_permlive; $ set to live. 27 elseif rl_type reglis(i) = rt_address then $ drop addr. 28 di_addrreg ditem(rl_content reglis(i)) = 0; 29 reglis(i) = 0; $ free register. 30 end if; 31 end do; 32 33 $ clear register useage counter since all not-permanent 34 $ register should be empty. 35 reguseval = 0; $ clear value for lru allocation. 36 37 end if; 38 39 put ocsfile ,column(9) ,'lab' dss 44 ,column(17) dss 45 ,'l' dss 46 :(label+lablorg),i(labcol, labcol) dss 47 ,x(17-labcol) dss 48 ,column(33) ,tmcscom dss 49 ,' / l ' dss 50 :(label+lablorg),i(2*labcol-1, labcol, 1) dss 51 ,' /'; 42 call ocsput(0, 0); $ put code. 43 .s. 33, 20, ocs = ''; $ clead ocs. 44 45 end subr labdefr; 1 .=member movadr 2 subr moveaddr(outr, inr); $ move an address. 3 $ this routine is called by -emitdop- to process a multi-word 4 $ indexed load. it is used to take the output -dreg- from a 5 $ -getaddr- and move the address pointed to by it into a 6 $ register so that it can be set as the output of the load. 7 size outr(ps); $ output register. 8 size inr(ps); $ input register. 9 size ildr(1); $ 'last usage of input' 10 size reg(ps); $ temporary register. 11 size mreg(ps); $ machine register. 12 size mreg1(ps); $ second machine register. 13 size moff1(mosize); $ machine offset. 14 size di(ps); $ pointer to dummy item. 15 size mode1(ps); $ dummy parameter. 16 17 .+trace. $ emit trace code. 18 if trace_a then $ trace wanted 19 tintl('moveaddr, out', outr) tintl('in', inr) endl 20 end if; 21 ..trace 22 23 $ [output of getaddr is 'funny temporary' when there is index. 24 $ [to use it, must get through moveaddr 20 apr] 25 di = dr_item dreg(inr); $ get dummy item pointer. 26 27 $ first, see if input dummy register has an address in a machine 28 $ register. if it does, that address can be moved into a new 29 $ register. 30 if di_addrreg ditem(di) then $ it is in a machine register. 31 $ if this is last use of the input and the register is 32 $ not permanent, then it can be used. 33 ildr = (di_count ditem(di) = 1 & di_ldrop ditem(di) & 34 di_luse ditem(di) ^= 0); $ get last usage status. 35 if ildr & rl_perm reglis(di_addrreg ditem(di)) = no then 36 $ can use this register. note that need 37 $ not check if a store is necessary because cannot 38 $ have a live address for a variable. 39 mreg = di_addrreg ditem(di); $ get machine register. 40 di_addrreg ditem(di) = 0; $ show not in register. 41 else $ must get a new register. 42 getreg(mreg, rt_liveaddr); $ go get register. 43 mrcopy(mreg, (di_addrreg ditem(di))); 44 end if; 45 46 elseif di_anum ditem(di) then $ must load address. 47 call aermey(18); 48 else $ must do load address. 49 getreg(mreg, rt_liveaddr); $ get register. 50 51 $ get base, displacement for value. 52 getdesc(inr, gd_addr, mode1, mreg1, moff1); 53 54 emop(mo_lda, mreg, mode1, mreg1, moff1); 55 end if; 56 57 $ set offset of dummy word. 58 dw_madr dword(dr_word dreg(outr)) = 1; $ set machine offset. 59 60 $ set output register status. 61 rl_subtype reglis(mreg) = rt_liveaddr; $ set to live address. 62 rl_content reglis(mreg) = dr_item dreg(outr); $ set to owner. 63 di_addrreg ditem(dr_item dreg(outr)) = mreg; $ show in register. 64 65 drop(outr); drop(inr); $ drop operands. 66 67 end subr moveaddr; 1 .=member sdsnam 2 subr sdsnamr(string, ptr); $ convert -ha- pointer to sds. 3 $ this routine is used to convert an -ha- pointer into an 4 $ sds containing the first -namelen- characters of the 5 $ name given in the little program. 6 size string(.sds. namelen); $ output string. 7 size ptr(ps); $ -ha- pointer of name to convert. 8 size namesp(ps); $ pointer to -names- array. 9 size i(ps); $ loop variable. 10 size j(ps); $ temporary. vaxa 247 .+t32 size c(ps); $ character. 11 12 $ first, set length to max(nchars(ha), namelen) 13 j = ha_nchars ha(ptr); $ get length of name. vaxa 248 .+t10 if (j>6) j = 6; $ at most six chars. vaxa 249 .+t32 if (j>15) j = 15; $ at most 15 chars. 15 16 $ initialize string descriptor. 17 string = 0; $ clear unused parts. 18 sorg string = .sds. namelen + 1; $ set origin. 19 namesp = ha_nayme ha(ptr); $ get -names- pointer 20 if (namesp=0) j = 0; $ null string if no name. 21 slen string = j; 22 23 do i = 1 to j; $ copy all characters. 24 .ch. i, string = .f. ws+1-cs - mod(i-1, cpw)*cs, cs, 25 names(namesp + (i-1)/cpw); $ move character. dsp 43 .+t10 if (.ch. i, string = 1r_) .ch. i, string = 1r$; 26 end do; 27 28 end subr sdsnamr; 1 .=member sdlnam 2 subr sdlnamr(string, ptr); $ convert -ha- pointer to sds. 3 $ this routine is used to convert an -ha- pointer into an 4 $ sds containing the first -namelen- characters of the 5 $ name given in the little program. 6 size string(.sds. namelen); $ output string. 7 size ptr(ps); $ -ha- pointer of name to convert. 8 size namesp(ps); $ pointer to -names- array. 9 size i(ps); $ loop variable. 10 size j(ps); $ temporary. 11 12 $ first, set length to max(nchars(ha), namelen) 13 j = ha_nchars ha(ptr); $ get length of name. 14 if (j>namelen) j = namelen; $ at most six chars. 15 16 $ initialize string descriptor. 17 string = 0; $ clear unused parts. 18 sorg string = .sds. namelen + 1; $ set origin. 19 namesp = ha_nayme ha(ptr); $ get -names- pointer 20 if (namesp=0) j = 0; $ null string if no name. 21 slen string = j; 22 23 do i = 1 to j; $ copy all characters. 24 .ch. i, string = .f. ws+1-cs - mod(i-1, cpw)*cs, cs, 25 names(namesp + (i-1)/cpw); $ move character. dsp 44 .+t10 if (.ch. i, string = 1r_) .ch. i, string = 1r$; 26 end do; 27 28 end subr sdlnamr; 1 .=member special 2 subr special; $ special case binary operations. 3 $ this routine check for and processes special cases for 4 $ simple binary operators. it sets the global flag -isspecial- 5 $ to indicate whether or not a special case was found. 6 $ 7 $ possible special cases are, at present, only those in which 8 $ one or more of the two operands is a short constant so only 9 $ these need be processed further. each operation that can 10 $ be special cased has two routines. one is for the case where 11 $ the right-hand variable is a short constant and the other is 12 $ for the case where the left-hand variable is a short constant. 13 $ note that for commutative operations only one of these is 14 $ necessary and the right-hand one is used. 15 size dop_commutes(do_div); $ flags which operations commute. 16 data dop_commutes = 1b'01110001'; $ add, eq, ne, mul commute. 17 size aop(ws); $ a op 18 size constv(ws); $ constant value 19 size work(ps); $ operand pointer 20 size t(ps); $ temporary. 21 22 $ initially, not a special case. 23 isspecial = no; 24 25 $ only operations below -do_div- are special cased by this 26 $ subroutine. 27 if (dopcode > do_div) return; 28 29 $ if right operand is short constant, process. 30 if (isscon(dopjr)) go to right; 31 32 $ check left operand. 33 if isscon(dopir) then 34 $ if operation commutes, reverse operands so that right 35 $ operand will be the constant. else process left operand. 36 if .f. dopcode, 1, dop_commutes then $ operation commutes. 37 t = dopir; dopir = dopjr; dopjr = t; $ swap 38 go to right; $ process right operand. 39 else $ operation does not commute. 40 go to left; $ process left operand. 41 end if; 42 end if; 43 44 $ since neither operand is a short constant, this is not a 45 $ special case. 46 return; 47 48 /right/ 49 $ process operand on right-hand side. 50 constv = conval(dopjr); $ get constant value. 51 52 go to r(dopcode) in do_add to do_div; $ select routine. 53 54 /left/ 55 $ process operand on left-hand side. 56 constv = conval(dopir); $ get constant value. 57 go to l(dopcode) in do_add to do_div; $ select routine. 58 59 60 61 /r(do_add)/ 62 $ special case routine for addition. 63 64 if (constv ^= 1) return; 65 isspecial = yes; $ is special case. 66 kill(dopjr); $ kill constant. 67 68 lastuse(dopir); lastuse(dopor); $ set status. 69 add1_op(dopor, dopir); $ add one. 70 return; 71 72 /r(do_sub)/ 73 $ special case routine for right-hand constant in subtraction. 74 $ if constant is not 1, not special. if it is 1, then use 75 $ shorter subtraction by 1. 76 if (constv ^= 1) return; 77 isspecial = yes; $ show special. 78 79 80 kill(dopjr); $ kill constant input. 81 82 lastuse(dopir); lastuse(dopor); $ set status. 83 sub1_op(dopor, dopir); $ subtract. 84 return; 85 86 87 /r(do_mul)/ /r(do_div)/ $ multiplication, division. 88 $ if constant is power of two generate appropriate arithmetic 89 $ shift operation. 90 91 if (.nb. constv ^=1) return; 92 if (dopcode = do_div & syze(dopir) = mws) return; 93 isspecial = yes; $ is special case. 94 assignconst(work, ((.fb. constv)-1)); 95 aop = ao_imt; $ assume multiplication. 96 if (dopcode = do_div) aop = ao_idt; $ if division. 97 lastuse(dopor); lastuse(dopir); lastuse(work); $ set status. 98 bin_op(aop, dopor, dopir, work); $ emit op. 99 return; 100 101 $ define unused processors. these can occur either 102 $ because a short constant on a given side of an operation 103 $ does not allow any special case and for the left-hand side 104 $ of commutative operators. 105 /l(do_add)/ /l(do_eq)/ /l(do_ne)/ /l(do_mul)/ /l(do_div)/ 106 /l(do_sub)/ /r(do_lt)/ /l(do_lt)/ /r(do_ge)/ /l(do_ge)/ 107 /r(do_eq)/ /r(do_ne)/ 108 109 end subr special; 1 .=member storall 2 subr storall; $ store all machine registers. 3 $ this routine stores all live, non-permanent machine registers. 4 size i(ps); $ register index. 5 6 .+trace if trace_a then textl(' *storall') endl end if; 7 8 do i = r0 to rhi; $ loop over all registers. 9 if rl_type reglis(i) = rt_live then $ check if live data. 10 if (isvar(rl_content reglis(i)) = no) cont do; 11 store(i, rl_content reglis(i)); $ store register. 12 end if; 13 end do; 14 15 end subr storall; 1 .=member emitbin 2 subr emitbin(iop, iout, iin1, iin2); $ emit binary operation. 3 $ this routine emits binary operations. it handles much of 4 $ the lowest-level optimizations done in this code generator. 5 $ it decides what machine instruction types should be issued 6 $ for various cases of register status. it is driven by an 7 $ internal table which contains information needed for the 8 $ various sub-routines in this routine. 9 size iop(ps); $ operation. 10 size t(mosize); $ temporary for offset copy. 11 size iout(ps); $ output register. 12 size iin1(ps); $ first input. 13 size iin2(ps); $ second input. 14 15 $ operation types used in table. 16 +* ek_norm = 1 ** $ normal binary operation. 17 .+eab. 18 +* ek_mul = 2 ** $ multiplication. 19 +* ek_div = 3 ** $ division or -mod- function. 20 +* ek_sign = 4 ** $ -sign- or -isign- operation. 21 +* ek_shift = 5 ** $ shift right or left. 22 23 +* num_ek = 5 ** 24 .-eab. 25 +* num_ek = 1 ** $ only norm for 26 ..eab 27 28 size ebtab(ws); $ operation table. 29 dims ebtab(ao_lbo-ao_fbo+1); 30 31 $ define fields in -ebtab-. 32 33 +* eb_mop = .f. 1, 8, ** $ machine operation to use. 34 +* eb_type = .f. 9, 4, ** $ operation type. 35 +* eb_comm = .f. 13, 1, ** $ 'operation commutes' 36 37 +* ebset(op, rm, ty, cm) = $ build table. 38 ebtab(op - (ao_fbo-1)) = 39 cm*4b'1000'+ty*4b'100'+rm ** 40 41 data $ initialize binary operation table. 42 43 $ aop r-mop type comm 44 $ --- ----- ---- ---- 45 46 ebset(ao_ban, mo_ban, ek_norm, yes): 47 ebset(ao_bor, mo_bor, ek_norm, yes): 48 ebset(ao_bxo, mo_bxo, ek_norm, yes): 49 ebset(ao_idi, mo_idi, ek_norm, no): 50 ebset(ao_idt, mo_idt, ek_norm, no): 51 ebset(ao_ieq, mo_ieq, ek_norm, yes): 52 ebset(ao_ige, mo_ige, ek_norm, no): 53 ebset(ao_igt, mo_igt, ek_norm, no): 54 ebset(ao_ile, mo_ile, ek_norm, no): 55 ebset(ao_ilt, mo_ilt, ek_norm, no): dsf 9 ebset(ao_imo, mo_imo, ek_norm, no): 57 ebset(ao_imu, mo_imu, ek_norm, yes): dsc 11 ebset(ao_imt, mo_imt, ek_norm, no): 59 ebset(ao_ine, mo_ine, ek_norm, yes): 60 ebset(ao_isi, mo_isi, ek_norm, no): 61 ebset(ao_isu, mo_isu, ek_norm, no): 62 ebset(ao_iad, mo_iad, ek_norm, yes): 63 ebset(ao_rad, mo_rad, ek_norm, yes): 64 ebset(ao_rdi, mo_rdi, ek_norm, no): 65 ebset(ao_req, mo_req, ek_norm, yes): 66 ebset(ao_rge, mo_rge, ek_norm, no): 67 ebset(ao_rgt, mo_rgt, ek_norm, no): 68 ebset(ao_rle, mo_rle, ek_norm, no): 69 ebset(ao_rlt, mo_rlt, ek_norm, no): 70 ebset(ao_rmo, mo_rmo, ek_norm, no): 71 ebset(ao_rmu, mo_rmu, ek_norm, yes): 72 ebset(ao_rne, mo_rne, ek_norm, yes): 73 ebset(ao_rsi, mo_rsi, ek_norm, no): 74 ebset(ao_rsu, mo_rsu, ek_norm, no); 75 76 macdrop(ebset) 77 78 size op(ps); $ local copy of operation. 79 size out(ps); $ local copy of output. 80 size in1(ps); $ local copy of first input. 81 size in2(ps); $ local copy of second input. 82 size i1ldr(1); $ 'last usage of input 1' 83 size i2ldr(1); $ 'last usage of input 2' 84 size oldr(1); $ 'last usage of output' 85 size omreg(ps); $ machine register for output. 86 size omode(ps); $ machine indicator for output. 87 size omoff(mosize); $ machine offset for output. 88 size i1mreg(ps); $ machine register for first input. 89 size i1mode(ps); $ machine indicator for first input. 90 size i1moff(mosize); $ machine offset for first input. 91 size i2mreg(ps); $ machine register for second input. 92 size i2mode(ps); $ machine indicator for second input. 93 size i2moff(mosize); $ machine offset for second input. 94 size mreg(ps); $ temporary machine register. 95 size mop(ps); $ temporary operation. 96 size lab(ps); $ label to use. 97 size mreg1(ps); $ second temporary machine register. 98 size mreg2(ps); $ third temporary machine register. 99 size i(ps); $ temporary. 100 101 .+trace. $ print trace info. 102 if trace_a then $ trace info. wanted. 103 tintl('binop, op', iop) tintl('out', iout) 104 tintl('in1', iin1) tintl('in2', iin2) endl 105 end if; 106 ..trace 107 108 $ initialize variable for emission. 109 op = iop - (ao_fbo-1); $ get local op code. 110 out = iout; in1 = iin1; in2 = iin2; $ get local copy of operands. 111 112 113 $ set last usage indicator for inputs and get machine 114 $ parameters for them. 115 i1ldr = lastdrop(in1); $ get last usage counts. 116 117 i2ldr = lastdrop(in2); $ get last usage counts. 118 119 oldr = lastdrop(out); $ get last usage counts. 120 121 getdesc(in1, gd_use, i1mode, i1mreg, i1moff); dse 17 if iop = ao_imt ! iop = ao_idt then $ if mul/div by power of two dse 18 if dr_reg dreg(in2) then $ if input in register. dse 19 if (isscon(in2) = no) call aermey(41); $ need constant. dse 20 reglis(dr_reg dreg(in2)) = 0; $ clear register status. dse 21 dr_reg dreg(in2) = 0; $ show no longer in register. dse 22 end if; dse 23 end if; dse 24 dse 25 getdesc(in2, gd_use, i2mode, i2mreg, i2moff); 123 getdesc(out, gd_use, omode, omreg, omoff); 124 125 $ branch to proper operation type. 126 .+eab go to l(eb_type ebtab(op)) in 1 to num_ek; 127 .-eab $ for bootstrap, all ops are ek_norm type. 128 129 130 /l(ek_norm)/ $ processor for normal binary operation. 131 132 $ first check for the case where an operand is used for 133 $ both inputs and the output and the operation is either 134 $ a subtraction or exclusive-or. in this case, get a 135 $ register and assign it to all of the operands. 136 if out = in1 & in1 = in2 & omode^=am_reg then $ have this case. 137 if iop = ao_isu ! iop = ao_bxo ! iop = ao_rsu then 138 omreg = dr_reg dreg(out); $ see if output register. 139 if omreg = 0 then $ third is not. 140 getreg(omreg, rt_live); $ get register. 141 end if; 142 143 emop(eb_mop ebtab(op), omreg, am_reg, omreg, 0); $ issue. 144 go to ret; $ done. 145 end if; 146 end if; 147 148 $ the next step is to see if either of the inputs are 149 $ not in a register but it is not their last use. in this 150 $ case, they are loaded into a register, if one is available. 151 152 if i1ldr = no & i1mode^=am_reg & isinif=no then $ see if can get 153 $ first, get a register of the appropriate type. 154 getreg(mreg, rt_need); $ get real or general. 155 156 if mreg then $ one is available. 157 i1mreg = mreg; $ show register that input will be in. 158 getvar(in1, gd_intoreg, i1mode, i1mreg, i1moff); $ load. 159 160 if out = in1 then $ must update -out- status too. 161 omreg = mreg; omode = am_reg; omoff = 0; 162 end if; 163 if in2 = in1 then $ must update -in2- status too. 164 i2mreg = mreg; i2mode = am_reg; i2moff = 0; 165 end if; 166 end if; 167 end if; 168 169 if i2ldr = no & i2mode^=am_reg & isinif=no then $ see if can get 170 getreg(mreg, rt_need); $ get register. 171 172 if mreg then $ one is available. 173 i2mreg = mreg; $ show operand is in a register. 174 getvar(in2, gd_intoreg, i2mode, i2mreg, i2moff); $ load. 175 176 if out = in2 then $ must update -out- status too. 177 omreg = mreg; omode = am_reg; omoff = 0; 178 end if; 179 end if; 180 end if; 181 182 183 i = rt_need; $ set to try to find first time. 184 while omode^=am_reg; $ when exited, register will be in -omreg-. dsc 15 omoff = 0; 186 187 $ if input 1 is in non-permanent register and this is 188 $ the last use, can use for output. 189 if i1ldr & i1mode=am_reg & rl_perm reglis(i1mreg) = no then 190 omreg = i1mreg; $ set output register. dsc 16 omode = am_reg; 191 $ must store if live. 192 if rl_type reglis(i1mreg)=rt_live & isvar(in1) then 193 store(i1mreg, in1); 194 end if; 195 dr_reg dreg(in1) = 0; $ not in here any more. 196 quit while; 197 end if; 198 199 $ if operation is commutative, can check for same thing 200 $ on second input. 201 if eb_comm ebtab(op) then $ it is commutative. 202 if i2ldr & i2mode=am_reg & rl_perm reglis(i2mreg)=no then 203 omreg = i2mreg; $ set output register. dsc 17 omode = am_reg; 204 $ must store if live. dsc 18 if rl_type reglis(i2mreg)=rt_live & isvar(in2) then dsc 19 store(i2mreg, in2); dsc 20 end if; 208 dr_reg dreg(in2) = 0; $ not in here any more. 209 $ swap fields. 210 t = i1moff; i1moff = i2moff; i2moff = t; 211 t = i1mode; i1mode = i2mode; i2mode = t; 212 t = i1mreg; i1mreg = i2mreg; i2mreg = t; 213 t = in1; in1 = in2; in2 = t; 214 quit while; 215 end if; 216 end if; 217 218 $ otherwise, hold the input register (just to be sure) 219 $ and see if output register is available. 220 rl_hold reglis(i1mreg) = yes; 221 rl_hold reglis(i2mreg) = yes; 222 getreg(omreg, i); $ try to get a register. 223 $ if got one, can exit loop. dsc 21 if omreg then dsc 22 omode = am_reg; dsc 23 quit while; dsc 24 end if; 225 226 $ at this point there are no registers available. in this 227 $ case, fake as if the inputs had last use and loop again. 228 i = rt_live; $ set next time to try all. 229 230 $ if a register does not have live status, show that 231 $ it can be used. 232 i1ldr = (rl_type reglis(i1mreg) ^= rt_live); 233 i2ldr = (rl_type reglis(i2mreg) ^= rt_live); 234 end while; 235 236 $ next, must get an input (for non-commutative -- first input) 237 $ into the output register. 238 until yes; $ quit when in register. 239 if (i1mreg = omreg) quit until; $ have it. 240 241 if i2mreg = omreg then $ second arg. is in output register. 242 if eb_comm ebtab(op) = no then $ not commutative op. 243 $ must check the operation. if this is a 244 $ subtraction, complement input, set operation to 245 $ addition, and swap. otherwise error. 246 if op = ao_isu - (ao_fbo-1) then $ normal sub. 247 emop(mo_ico, omreg, am_reg, omreg, 0); $ complemen 248 op = ao_iad - (ao_fbo-1); $ set for add. 249 elseif op = ao_rsu - (ao_fbo-1) then $ if real. 250 emop(mo_rco, omreg, am_reg, omreg, 0); $ complemen 251 op = ao_rsu - (ao_fbo-1); $ set for add. 252 else $ error. 253 call aermey(19); $ this is fatal error. 254 end if; 255 end if; 256 257 i2mreg = i1mreg; i2moff = i1moff; i2mode = i1mode; 258 quit until; $ have in register. 259 end if; 260 261 262 if i1mode = am_reg then $ this is in register. copy it. 263 mrcopy(omreg, i1mreg); $ copy reg. 264 quit until; $ have in register. 265 end if; 266 267 $ if operation is commutative, see if input 2 is in reg. 268 if i2mode = am_reg & eb_comm ebtab(op) then $ ok. 269 mrcopy(omreg, i2mreg); $ move into reg. 270 i2mreg = i1mreg; i2mode = i1mode; i2moff = i1moff; $ swap. 271 quit until; 272 end if; 273 274 $ otherwise, do load into output. 275 $ if this is commutative operation with the first 276 $ operand a short constant, swap operands. 277 if eb_comm ebtab(op) & isscon(in1) then $ it is. 278 i2moff=i1moff; i2mreg=i1mreg; i2mode=i1mode; in1=in2; 279 end if; 280 281 $ get first operand into register. 282 getvar(in1, gd_inregnu, t, omreg, t); 283 end until; 284 285 $ finally, do operation. 286 emop(eb_mop ebtab(op), omreg, i2mode, i2mreg, i2moff); 287 288 go to ret; 289 290 291 .+eab. $ defer sign, isign code until after bootstrap 292 $ and do off-line for bootstrap. 293 /l(ek_sign)/ $ -sign- or -isign- function. 294 295 $ first, get first input into a register if it is not already. 296 if i1mode ^= am_reg then $ it is not in a register. 297 getvar(in1, grtype, i1mode, i1mreg, i1moff); 298 end if; 299 300 $ get register to use for output. 301 i = rt_need; $ initially, just see if one available. 302 while omode ^= am_reg; $ exit when register in -omreg-. 303 304 $ see if can use input register. 305 if i1ldr & i1mode=am_reg & rl_perm reglis(i1mreg)=no then 306 omreg = i1mreg; $ set to proper register. 307 dr_reg dreg(in1) = 0; $ not in here any more. 308 quit while; 309 end if; 310 311 $ try to get an appropriate register. 312 rl_hold reglis(i1mreg) = yes; $ hold this input. 313 rl_hold reglis(i2mreg) = no; $ but release other one. 314 getreg(omreg, i); $ try to get a register. 315 $ if a register was obtained, use it. 316 if (omreg) quit while; 317 318 $ otherwise, must reset to use input. 319 i1ldr = (rl_type reglis(i1mreg) ^= rt_live); $ fake last use. 320 i = rt_live; $ set to force a register. 321 end while; 322 323 $ do operation. first, get absolute value. 324 rrop(eb_mop ebtab(op), omreg, i1mreg); $ -lper- or -lpr- 325 326 $ get a label and emit branch to it if second operand is 327 $ positive. 328 labget(lab); ifpos_op(in2, lab); $ branch on second operand. 329 330 $ if was not positive, then do complement. 331 rrop(eb_xmop ebtab(op), omreg, omreg); $ -lcer- or -lcr-. 332 333 $ define ending label and free it. 334 labdef(lab, no); labfree(lab); 335 336 go to ret; 337 ..eab 338 339 340 .+eab. $ defer mul/div special casing 341 /l(ek_mul)/ $ multiplication. 342 343 344 $ the first thing to do is to see which, if any, of the input 345 $ registers can be pre-empted. then call the -getregpair- 346 $ routine to get a register pair. 347 348 mreg1 = 0; mreg2 = 0; $ initially none can. 349 if (i1ldr & i1mode = am_reg & rl_perm reglis(i1mreg) = no) 350 mreg1 = i1mreg; $ can use first register. 351 if (i2ldr & i2mode = am_reg & rl_perm reglis(i2mreg) = no) 352 mreg2 = i2mreg; $ can use second register. 353 354 getregpair(mreg, mreg1, mreg2); $ get pair into -mreg-. 355 356 $ next, get an input into the second register of the pair. 357 until yes; $ exit when gotten. 358 if (mreg+1 = i1mreg) quit until; $ got 1st. 359 if mreg+1 = i2mreg then $ got 2nd -- exchange. 360 t = in2; in2 = in1; in1 = t; 361 t = i2mreg; i2mreg = i1mreg; i1mreg = t; 362 t = i2moff; i2moff = i1moff; i1moff = t; 363 t = i2mode; i2mode = i1mode; i1mode = t; 364 quit until; 365 end if; 366 367 $ else must load into register. 368 getvar(in1, gd_inregnu, t, mreg+1, t); $ force to -mreg+1-. 369 end until; 370 371 $ set -mreg1- to the register to contain the output. 372 mreg1 = mreg+1; $ set for common code. 373 374 /muldiv/ $ this code is common for multiplication and division. 375 $ if the second operand is not in a register and this is not 376 $ the last usage of that operand, then load it into a 377 $ register if one if available. 378 if i2ldr = no & i2mode^=am_reg then $ try to get a register. 379 rl_hold reglis(mreg) = yes; rl_hold reglis(mreg+1) = yes; 380 getreg(mreg2, rt_need); $ see if one is available. 381 if mreg2 then $ there is one available. 382 i2mreg = mreg2; $ show which register is in. 383 getvar(in2, gd_intoreg, i2mode, i2mreg, i2moff); 384 end if; 385 end if; 386 387 $ do operation. 388 if i2mode^=am_reg then $ do -rx- operation. 389 rxop(eb_xmop ebtab(op), mreg, i2moff, r0, i2mreg); 390 else $ do -rr- operation. 391 rrop(eb_mop ebtab(op), mreg, i2mreg); 392 end if; 393 394 rl_hold reglis(mreg+1) = no; $ this is unheld. 395 396 $ must see if either register in the pair was 397 $ holding one of the inputs to the operation. if so, must 398 $ show that the input is no longer in that register. 399 if i1mreg = mreg ! i1mreg = mreg+1 then $ hit input one. 400 dr_reg dreg(in1) = 0; $ show not assigned. 401 end if; 402 403 if i2mreg = mreg ! i2mreg = mreg+1 then $ hit input two. 404 dr_reg dreg(in2) = 0; $ show not assigned. 405 end if; 406 407 $ must move the result to the output. if the output 408 $ is a permanently assigned register or if the register pair 409 $ allocated is non-standard, must move the data. otherwise, 410 $ can just indicate that it resides in the pair. 411 if mreg1 = r1 ! mreg1 >= r14 then $ bad place. 412 reglis(r1) = 0; rl_type reglis(r1) = rt_permresv; $ reset. 413 if omode^=am_reg then $ must get output register. 414 getreg(omreg, rt_live); $ get one. 415 end if; 416 417 $ just move to output. 418 mcropy(omreg, mreg1); 419 go to ret; $ done. 420 end if; 421 422 $ check if the output is a permanently assigned register. 423 if omode = am_reg then $ it is a register. 424 mrcopy(omreg, mreg1); $ copy reg. 425 reglis(mreg1) = 0; $ clear register. 426 go to ret; 427 end if; 428 429 $ otherwise, can assign to output. 430 omreg = mreg1; $ show output is here. 431 $ the regster which does not contain the output is 432 $ to be concidered dead. 433 if omreg = mreg 434 then reglis(mreg+1) = 0; 435 else reglis(mreg) = 0; end if; 436 437 go to ret; 438 439 /l(ek_div)/ $ division or -mod- function. 440 441 $ in this case, must see if can pre-empt the first input 442 $ register and, if so, so indicate. then a register pair is 443 $ obtained. 444 mreg1 = 0; $ assume cannot pre-empt. 445 if (i1ldr & i1mode = am_reg & rl_perm reglis(i1mreg) = no) 446 mreg1 = i1mreg; $ can use. 447 448 $ [ds 11 apr should issue aop for t10, and hence no need 449 $ for reg pair here.] 450 getregpair(mreg, mreg1, 0); $ get register pair. 451 452 $ must load first input into high register of pair. note 453 $ that do not bother to check for the case where this is not 454 $ last use of the input because division is not that common 455 $ an operation. 456 if mreg ^= i1mreg then $ must put it in. 457 getvar(in1, gd_inregnu, t, mreg, t); $ move it. 458 end if; 459 460 $ do shift down to high register. 461 rxop(mop_srda, mreg, ws, r0, r0); $ propagate sign through high. 462 463 $ prepare to branch to common code to emit operation. 464 $ set -mreg1- to that register that will contain the output 465 $ of the operation. 466 mreg1 = mreg+1; $ assume division. 467 if (iop = ao_mod) mreg1 = mreg; $ set for -mod- function. 468 go to muldiv; $ enter common code. 469 470 ..eab 471 472 473 /ret/ $ common return point. 474 $ first, update status of output register. 475 dr_reg dreg(out) = omreg; $ show in this register. 476 rl_subtype reglis(omreg) = rt_live; $ show changed. 477 rl_content reglis(omreg) = out; $ show owner. 478 479 /noupdate/ $ branch here to skip status update. 480 $ drop inputs. 481 drop(iin1); drop(iin2); drop(iout); 482 483 return; 484 485 .+eab macdrop(ek_norm) macdrop(ek_mul) 486 .+eab macdrop(ek_div) macdrop(ek_sign) 487 macdrop(ek_shift) macdrop(eb_mop) 488 macdrop(eb_type) macdrop(eb_comm) 489 macdrop(eb_fp) 490 491 end subr emitbin; 1 .=member emitcmp 2 subr emitcmp(imask, iin1, iin2, lab); $ emit comparison. 3 $ this routine emits a compare and a branch. it compares 4 $ two inputs and will conditionally branch to a given label. 5 size imask(3); $ conditional branch mask. 6 size iin1(ps); $ first input. 7 size iin2(ps); $ second input. 8 size lab(ps); $ label to branch to. 9 size mask(ps); $ copy of branch mask. 10 size in1(ps); $ copy of first input. 11 size in2(ps); $ copy of second input. 12 size i1ldr(1); $ drop bit for first input. 13 size i2ldr(1); $ drop bit for second input. 14 size i1mode(ps); $ indirect bit for first input. 15 size i2mode(ps); $ indirect bit for second input. 16 size i1mreg(ps); $ machine register for first input. 17 size i2mreg(ps); $ machine register for second input. 18 size i1moff(mosize); $ machine offset for first input. 19 size i2moff(mosize); $ machine offset for second input. 20 size mreg(ps); $ register obtained. 21 size t(ps); $ temporary. 22 size gtype(ps); $ desired address type. dsb 96 size moctb(ps); dims moctb(9); dsb 97 +* mo_cmptab(i) = moctb((i)+1) ** $ array is zero-origin 24 data mo_cmptab(bm_all) = mo_jmp: 25 mo_cmptab(bm_neg) = mo_clt: 26 mo_cmptab(bm_pos) = mo_cgt: 27 mo_cmptab(bm_zer) = mo_ceq: 28 mo_cmptab(binv(bm_all)) = mo_jmn: 29 mo_cmptab(binv(bm_neg)) = mo_cge: 30 mo_cmptab(binv(bm_pos)) = mo_cle: 31 mo_cmptab(binv(bm_zer)) = mo_cne; 32 33 $ first, make copy of inputs and set some initial defaults. 34 in1 = iin1; in2 = iin2; mask = imask; 35 $ get last usage bits. 36 i1ldr = lastdrop(in1); $ get last usage counts. 37 38 i2ldr = lastdrop(in2); $ get last usage counts. 39 40 41 $ get machine descriptors for inputs. 42 getdesc(in1, gd_use, i1mode, i1mreg, i1moff); 43 getdesc(in2, gd_use, i2mode, i2mreg, i2moff); 44 45 $ see if this is not the last use of the first input and 46 $ it is in storage. load it into an available register if so. 47 if i1ldr = no & i1mode^=am_reg & isinif=no then $ can get to re 48 getreg(mreg, rt_need); $ see if reg available. 49 if mreg then $ if reg available. 50 i1mreg = mreg; $ copy to result register. 51 getvar(in1, gd_intoreg, i1mode, i1mreg, i1moff); 52 $ must check for the cases where both inputs same. 53 if in2 = in1 then $ update in2 status also 54 i2mreg = mreg; i2mode = am_reg; i2moff = 0; 55 end if; 56 end if; 57 end if; 58 $ do the same for the second input. 59 60 if i2ldr = no & i2mode^=am_reg & isinif=no then $ can get in2. 61 getreg(mreg, rt_need); $ see if reg available. 62 if mreg then $ if reg. available. 63 i2mreg = mreg; $ set result reg. 64 getvar(in2, gd_intoreg, i2mode, i2mreg, i2moff); 65 end if; 66 end if; 67 68 $ get one of the inputs into a register. 69 until yes; $ quit when one is loaded. 70 mreg = i1mreg; $ assume first input in a register. 71 if (i1mode = am_reg) quit until; $ quit if it is. 72 if i2mode = am_reg then $ second input is in a register. 73 $ copy descriptors. 74 mreg=i2mreg; i2mreg=i1mreg; i2mode=i1mode; i2moff=i1moff; 75 bmswap(mask, t); $ reverse branch mask. 76 quit until; $ indicate in register. 77 end if; 78 79 $ must get a register. 80 getreg(mreg, rt_live); $ get register. 81 82 $ if the first input is a short constant, then 83 $ will want to load second into the register. 84 if isscon(in1) then $ it is. 85 in1 = in2; $ set to this input. 86 i2mode = i1mode; i2mreg = i1mreg; i2moff = i1moff; 87 bmswap(mask, t); $ reverse branch mask. 88 end if; 89 90 gtype = gd_intoreg; if (isinif) gtype = gd_inregnu; 91 getvar(in1, gtype, i1mode, mreg, i1moff); 92 if (isinif) reglis(mreg) = 0; $ clear status of gotten regis 93 end until; 94 95 $ do the comparison. 96 emop(mo_cmptab(binv(mask)), mreg, i2mode, i2mreg, i2moff); 97 goto_op(lab); 98 99 drop(iin1); drop(iin2); $ drop the inputs. dsb 98 macdrop(mo_cmptab) 100 101 end subr emitcmp; 1 .=member emitif 2 subr emitif(iop, inr, label); $ emit an -if- operation. 3 $ this routine is called to proces conditional branch 4 $ operations. it decides whether to do the operation as 5 $ a storage operation or to load it into a register and test 6 $ it in the register. 7 size iop(ps); $ branch mask to use. 8 size inr(ps); $ dummy register to test. 9 size label(ps); $ label to branch to if condition true. 10 size mreg(ps); $ machine register for operand. 11 size moff(mosize); $ machine address. 12 size mode(ps); $ machine mode. 13 14 15 .+trace. 16 if trace_a then $ trace output wanted. 17 tintl('ifop, mask', iop) tintl('in', inr) 18 tintl('l', label) endl 19 end if; 20 ..trace 21 22 $ first set flag to indicate whether this is last use of 23 $ operation. this will be used later. 24 25 26 $ get description of variable. 27 getdesc(inr, gd_use, mode, mreg, moff); 28 if mode ^= am_reg then $ if not in register. 29 getvar(inr, gd_reg, mode, mreg, moff); $ bring to reg. 30 if isinif then $ if in if. 31 reglis(mreg) = 0; dr_reg dreg(inr) = 0; 32 end if; 33 end if; 34 35 $ finally, emit branch instruction. 36 branchop(iop, mreg, label); 37 38 /ret/ $ common return code. 39 40 drop(inr); $ free if last use. 41 end subr emitif; 42 subr emitlong(op, outr, inr, length); $ emit long op. 1 .=member emitlon 2 $ the routine emits code for the storage-storage operations. 3 $ it uses a table to determine which machine operation to 4 $ issue. in addition, it handles the storing and freeing of 5 $ words near the operand locations. 6 size op(ps); $ internal operati!n code. 7 size outr(ps); $ output dummy register. 8 size inr(ps); $ input dummy register. 9 size length(ps); $ length, in words, of operation to perform. 10 size imode(ps); $ input address mode. 11 size omode(ps); $ output address mode. 12 size imreg(ps); $ machine register for input. 13 size imoff(mosize); $ machine offset for input. 14 size omreg(ps); $ machine register for output. 15 size omoff(mosize); $ machine offset for output. 16 size mreg(ps); $ machine register. 17 size i(ps), j(ps), k(ps); $ temporaries. 18 size dw(ps); $ pointer to dummy word. 19 20 .+trace. $ generate trace code. 21 if trace_a then $ if tracing these ops. 22 tintl('longop, op', op) tintl('out', outr) 23 tintl('in', inr) tintl('l', length) endl 24 end if; 25 ..trace 26 $ must store any live forms of the input that fall 27 $ into the range to be moved. 28 if op = ao_mvw then $ only store if move operation. 29 i = dw_word dword(dr_word dreg(inr)); j = i+length-1; 30 dw = di_lword ditem(dr_item dreg(inr)); $ point to first wor 31 while dw; $ while more in chain. 32 $ see if in specified range. 33 if dw_word dword(dw) >= i & dw_word dword(dw) <= j then 34 $ it is. see if primary register is live. 35 if dr_reg dreg(dw_freg dword(dw)) then $ there is on 36 if rl_subtype reglis(dr_reg dreg(dw_freg 37 dword(dw))) = rt_live then $ it is live. 38 store(dr_reg dreg(dw_freg dword(dw)), $ stor 39 dw_freg dword(dw)); $ primary form. 40 end if; 41 end if; 42 end if; 43 44 dw = dw_next dword(dw); $ get next in chain. 45 end while; 46 end if; 47 48 $ get descriptors for output and input and go do operation. 49 getdesc(inr, gd_addr, imode, imreg, imoff); $ get input. 50 getdesc(outr, gd_addr, omode, omreg, omoff); $ get output. 51 52 $ now emit the long operation. first move the output address in 53 $ to a register. 54 $ if the start of the output is at offset zero from a register, 55 $ then can use that register. 56 if omoff = 0 & omode = am_rel then $ can use register. 57 mreg = omreg; $ set register to use. 58 else $ must get a register. 59 getreg(mreg, rt_live); $ get a register. 60 emop(mo_lda, mreg, omode, omreg, omoff); $ load address. 61 reglis(mreg) = 0; $ nothing usefull in register. 62 end if; 63 64 $ now actually emit the move or clear. 65 if op = ao_mvw then $ emit move. 66 emopparm1 = length; $ set length to move. 67 emop(mo_mvw, mreg, imode, imreg, imoff); $ emit the move. 68 else $ this must be a clear. 69 imoff = 0; mbo_blk imoff = bl_imm; $ set for immediate. 70 mbo_off imoff = length; $ put length out as ea. 71 emop(mo_zeb, mreg, am_mem, sparereg, imoff); $ clear storage. 72 end if; 73 74 $ must drop any output words that are in range modified. 75 i = dw_word dword(dr_word dreg(outr));j = i+length-1; 76 dw = di_lword ditem(dr_item dreg(outr)); $ get first word. 77 while dw; $ loop until end of chain. 78 $ see if in range. 79 if dw_word dword(dw) >= i & dw_word dword(dw) <= j then 80 $ it is. drop all assigned registers. 81 k = dw_freg dword(dw); $ point to first. 82 if dr_reg dreg(k) then $ must free this one. 83 if rl_perm reglis(dr_reg dreg(k)) then 84 omreg = dr_reg dreg(k); $ get reg number 85 dr_reg dreg(k) = 0; $ temporarily free. 86 getvar(k, gd_intoreg, omode, omreg, omoff); 87 rl_perm reglis(omreg) = yes; $ show perm 88 else $ not permanent, actually free. 89 reglis(dr_reg dreg(k)) = 0; $ free reg. 90 dr_reg dreg(k) = 0; $ show not in reg. 91 end if; 92 end if; 93 end if; 94 95 dw = dw_next dword(dw); $ get next word. 96 end while; 97 98 $ drop input and output. 99 drop(outr); $ drop output. 100 if op = ao_mvw then drop(inr); end if; $ drop input. 101 102 end subr emitlong; 1 .=member emitsub 2 subr emitsub; $ emit subroutine/function call. 3 $ this routine emits the operations needed to call a subroutine 4 $ or function. the routine name is located and any needed 5 $ housekeeping is done. then the parameter list is generated. 6 size reg(ps); $ dummy register. 7 size i(ps), j(ws), k(ps); $ temporaries. 8 size hcode(ws/2); $ hash code for base block. 9 size mreg(ps); $ machine register. 10 size moff(mosize); $ machine offset. 11 size mop(ps); $ machine operation. 12 size mode(ps); $ address mode. 13 size t(ws); $ temporary if address goes negative. vaxa 250 size moff1(mosize); $ temporary machine offset. dsu 107 .+t32h size moff2(mosize); 14 15 .+trace. $ handle special trace actions. 16 if trace_any then $ if tracing. 17 textl(' * call ') textl(dopsname) 18 if trace_a then tintl(' np', dopnx) end if; 19 endl 20 end if; 21 22 $ see if this 'routine' to be called is actually a 23 $ special flag to turn on traces. 24 if .ch. 3, dopsname = 1r= then $ it is special. 25 if .ch. 1, dopsname = 1rt & .ch. 2, dopsname = 1rr then 26 dopsname = .s. 4, .len. dopsname-3, dopsname; 27 $ set new trace values. 28 trace_d = ('d' .in. dopsname) > 0; 29 trace_o = ('o' .in. dopsname) > 0; 30 trace_a = ('a' .in. dopsname) > 0; 31 trace_r = ('r' .in. dopsname) > 0; 32 trace_c = ('c' .in. dopsname) > 0; 33 trace_l = ('l' .in. dopsname) > 0; 34 trace_v = ('v' .in. dopsname) > 0; 35 36 trace_any = trace_d!trace_o!trace_a!trace_r!trace_c! 37 trace_l!trace_v; $ set any trace info. 38 39 return; $ end of dummy call. 40 end if; 41 end if; 42 ..trace 43 44 $ if name longer than six characters, truncate to length six 45 $ for possible output in generated code file. vaxa 251 .+t10 if (.len. dopsname > 6) .len. dopsname = 6; 47 48 $ must scan the contents of all permanently-assigned dsk 309 $ registers. if the register has live data in it and the 50 $ data is a global variable, then it must be saved across 51 $ the call because the called routine may modify it. 52 $ the -hold- flag is set to those those registers that 53 $ contain such global information so that they can be 54 $ reloaded at the completion of the call. 55 56 $ this is only done when the -calldropgl- flag is set. dsk 310 do i = rlo to rhi; $ search all registers. rka 10 if (rl_subtype reglis(i) ^= rt_need & rka 11 rl_subtype reglis(i) ^= rt_live) cont do; dsk 311 if di_mblk ditem(dr_item dreg(rl_content reglis(i))) >= dsk 312 bl_global then $ this is a special case. dsk 313 if calldropgl then $ go ahead. dsk 314 if rl_subtype reglis(i) = rt_live then dsk 315 store(i, rl_content reglis(i)) dsk 316 end if; dsk 317 dsk 318 if rl_perm reglis(i) then $ if permanent. dsk 319 rl_hold reglis(i) = yes; $ show special. dsk 320 else $ not permanent. dsk 321 dr_reg dreg(rl_content reglis(i)) = 0; $ show not. dsk 322 reglis(i) = 0; $ free register. dsk 323 end if; dsk 324 dsk 325 else $ dont hold. dsk 326 rl_hold reglis(i) = no; $ show not special. dsk 327 end if; dsk 328 else $ not a global. dsk 329 rl_hold reglis(i) = no; $ show not special. dsk 330 end if; dsk 331 end do; 74 75 $ process arguments to calls, if any. dsk 332 hcode = 0; 76 if dopnx then $ arguments exist. 77 78 $ make a pass over the arguments to build the parameter 79 $ list. in addition, if any arguments are live in registers 80 $ those registers must be stored. also, if the item is 81 $ in a permanent register, it must be flagged to be reloaded 82 $ after the call is complete. 84 do i = 1 to dopnx; $ scan all parameters. 85 reg = dopxr(i); $ get parameter -dreg- value. 86 countup(pdlistp, pdlistdim, 'pdlist'); $ get space. 87 pdlist(pdlistp) = 0; $ clear parameter list entry. 88 89 $ if this parametet does not have a fixed address, 90 $ will have to move it into the parm. list at run-time. 91 $ in this pass over the parameters it is ignored 92 $ because only known addresses are compiled into the 93 $ parameter list. 94 if di_addrreg ditem(dr_item dreg(reg)) = 0 & 95 isind(reg) = no then $ normal address. 96 $ can put this address into the parm list. 97 $ check for the case where an address has not been 98 $ assigned and assign an address to it. 99 if di_mblk ditem(dr_item dreg(reg)) = 0 then 100 getdesc(reg, gd_addr, j, mreg, moff); $ get value 101 rl_hold reglis(mreg) = no; $ release. 102 end if; 103 104 pd_block pdlist(pdlistp) = $ set machine block. 105 di_mblk ditem(dr_item dreg(reg)); 106 pd_madr pdlist(pdlistp) = $ machine address. 107 dw_madr dword(dr_word dreg(reg)); 108 hcode = hcode .ex. $ hash in machine address. 109 dw_madr dword(dr_word dreg(reg)); 110 end if; 111 112 $ check for the case where the parameter is in a 113 $ register. 114 if dr_reg dreg(reg).ne. 0 & isscon(reg)=no then $ it is 115 $ if live, must store. 116 if rl_subtype reglis(dr_reg dreg(reg)) = rt_live then 117 store(dr_reg dreg(reg), reg); $ do the store. 118 end if; 119 120 $ if -callnodrop- is set, this is end of 121 $ processing for this variable. 122 if (callnodrop) cont do; 123 124 $ see how to drop. 125 if rl_perm reglis(dr_reg dreg(reg)) then $ perm. 126 rl_hold reglis(dr_reg dreg(reg)) = isvar(reg); 127 else $ must do normal clear if variable. 128 if isvar(reg) then $ do normal clear. 129 clear(reg); $ clear all fields. 130 end if; 131 end if; 132 end if; 133 end do; vaxa 252 .+t32 end if; 134 135 136 $ allocate space in base block for the parameter list. 137 $ if base block address would go negative, increment it. 138 if (baselastaddr=1) baselastaddr=2; 139 baseprobe(j, hcode, dopnx, bt_plist, $ get space for p-list. 140 pdlistp - (dopnx-1), ar_plist, pdlistp); 141 moff = 0; vaxa 253 .+t10 t = bb_addr baseblock(j) - 2; vaxa 254 .+t32 t = bb_addr baseblock(j) - 1; 143 if (t<0) t = mneg(iabs(t)); 144 mbo_off moff = t; $ set offset. 145 mbo_blk moff = bl_base; vaxa 255 vaxa 256 vaxa 257 .+t32 if dopnx then $ if parameters. 146 147 $ make a pass over the parameters to move any needed 148 $ values into the parameter list at run-time. 149 do i = 1 to dopnx; $ loop over all parameters. 150 reg = dopxr(i); $ get -dreg- number. 151 if di_addrreg ditem(dr_item dreg(reg)) then $ else live. 152 $ see if last word is in register. else must 153 $ get last word into a register. 154 if (dw_word dword(dr_word dreg(reg))^=nwords(reg)) 155 call aermey(20); $ this is a fatal error. 156 if dw_madr dword(dr_word dreg(reg)) = 1 then $ last. vaxa 258 moff1 = moff; mbo_off moff1 = mbo_off moff1 + i; 157 emop(mo_stw, di_addrreg ditem(dr_item dreg(reg)), vaxa 259 am_mem, sparereg, moff1); 159 else $ use as temporary. 160 j = dw_madr dword(dr_word dreg(reg))-1; 161 if (j<0) j = mneg(-j); vaxa 260 moff1 = 0; mbo_off moff1 = j; vaxa 261 emop(mo_lda, sparereg, am_rel, vaxa 262 di_addrreg ditem(dr_item dreg(reg)), moff1); vaxa 263 moff1 = moff; mbo_off moff1 = mbo_off moff1 + i; 164 emop(mo_stw, sparereg, am_mem, vaxa 264 sparereg, moff1); 166 end if; 167 elseif isind(reg) then $ move in address. vaxa 265 .+t10 emop(mo_ldw, sparereg, am_rel, parmreg, vaxa 266 .+t10 di_anum ditem(dr_item dreg(reg)) - 1); vaxa 267 .+t32 moff1 = 0; mbo_off moff1 = vaxa 268 .+t32 di_anum ditem(dr_item dreg(reg)); vaxa 269 .+t32 emop(mo_ldw, sparereg, am_rel, parmreg, moff1); vaxa 270 moff1 = moff; mbo_off moff1 = mbo_off moff1 + i; vaxa 271 emop(mo_stw, sparereg, am_mem, sparereg, moff1); dsu 108 .+t32h. dsu 109 elseif nsheap_this & dsu 110 (nsheap_blk = di_mblk ditem(dr_item dreg(reg))) then dsu 111 .s. 9, 3, ocs = 'sha'; dsu 112 put ocsfile ,column(17); dsu 113 getdesc(reg, gd_addr, j, mreg, moff2); dsu 114 call emitea(am_mem, sparereg, moff2); dsu 115 put ocsfile ,','; dsu 116 moff1 = moff; dsu 117 mbo_off moff1 = mbo_off moff1 + i; dsu 118 call emitea(am_mem, sparereg, moff1); $ emit base blk dsu 119 call ocsput(0,0); dsu 120 ..t32h 171 end if; 172 kill(reg); $ last usage of parameter. 173 end do; 174 175 $ load parameter list address into r1. 176 $ emop(mo_lda, r1, am_mem, sparereg, moff+1); 177 end if; 178 179 $ emit call. vaxa 272 .+t10 if (.len. dopsname > 6) .len. dopsname = 6; vaxa 273 .+t32 if (.len. dopsname > 15) .len. dopsname = 15; 181 .s. 9, 3, ocs = 'cal'; 182 put ocsfile ,column(17) 183 :dopsname,a 184 ,',' :dopnx,i ,',' ; 185 $ if arguments, put out ea of param list, else put zero. vaxa 274 .+t10 if dopnx then $ if arguments. vaxa 275 .+t10 call emitea(am_mem, sparereg, moff+1); vaxa 276 .+t32 call emitea(am_mem, sparereg, moff); vaxa 277 .+t10 else put ocsfile ,'0'; end if; 189 call ocsput(0, 0); $ put code line. 190 dst 77 .+enp. dst 78 if enpopt then $ if tracking active procs, indicate dst 79 $ back in 'current' procedure. dst 80 put ocsfile ,column(9) ,'enp' ,column(17) dst 81 :currsubname,a ,',#' :(enpnum+enporg),i; dst 82 call ocsput(0,0); dst 83 end if; dst 84 ..enp 191 $ reload any permanent registers marked for reload. 192 do i = rlo to rhi; $ search all registers. 193 if rl_perm reglis(i) & rl_hold reglis(i) then $ got one. 194 if rl_type reglis(i) = rt_permlive ! $ check for data. 195 rl_type reglis(i) = rt_perm then $ this is data. 196 getdesc(rl_content reglis(i), gd_addr, mode, mreg, moff); 197 $ get operation to use for load. 198 emop(mo_ldw, i, mode, mreg, moff); 199 clear(rl_content reglis(i)); $ clear -dreg-. 200 rl_subtype reglis(i) = rt_need; $ not live. 201 end if; 202 end if; 203 end do; 204 205 206 callnodrop = no; calldropgl = no; $ set default state of flags. 207 208 end subr emitsub; 1 .=member emitsf 2 subr emitsfld(op, inr, target); $ emit field store operation. 3 $ this routine emits code for field store operations. 4 size op(ps); $ operation code. 5 size inr(ps); $ input register to store. 6 size target(ps); $ target register. 7 size mode(ps); $ machine mode of target. 8 size mreg(ps); $ machine register of target. 9 size moff(mosize); $ machine offset of target. 10 size mreg1(ps); $ machine register for input. 11 size mop(ps); $ machine operation to emit. 12 13 $ get input to a register. 14 getvar(inr, gd_reg, mode, mreg1, moff); 15 16 mreg = dr_reg dreg(target); dsj 60 if op = ao_spr then $ if spr. 18 if lastdrop(target) then $ if last use of target. 19 if mreg then 20 if rl_type reglis(mreg) = rt_need then 21 reglis(mreg) = 0; 22 dr_reg dreg(target) = 0; 23 mreg = 0; 24 end if; 25 end if; 26 end if; 27 if (mreg) rl_subtype reglis(mreg) = rt_live; 28 end if; 29 30 $ now get ea for target. 31 getdesc(target, gd_use, mode, mreg, moff); 32 33 $ now get machine operation to issue. handle special case 34 $ of halfword ops for spr. 35 mop = mo_stf; $ assume was stf_op. 36 if op = ao_spr then $ it was not. 37 mop = mo_spr; $ set for normal case. vaxa 278 .+t10. 38 if emopparm2 = mws/2 then $ could be halfword. 39 if emopparm1 = 0 then $ is right half. 40 mop = mo_str; $ set to store right. 41 elseif emopparm1 = mws/2 then $ is left half. 42 mop = mo_stl; $ store left half. 43 end if; 44 end if; vaxa 279 ..t10 45 end if; 46 47 $ now emit operation. 48 emop(mop, mreg1, mode, mreg, moff); 49 50 drop(inr); drop(target); $ drop register. 51 52 end subr emitsfld; 1 .=member emitun 2 subr emitun(iop, outr, inr); $ emit unary operation. 3 $ this routine emits unary operations. it is highly table- 4 $ driven and handles special cases depending on mahchine 5 $ register status. 6 size iop(ps); $ internal operation code. 7 size outr(ps); $ output operand. 8 size inr(ps); $ input operand. 9 size imode(ps); $ input one addressing mode 10 size imoff(mosize); $ input addressing mode 11 size imreg(ps); $ input machine register 12 size omreg(ps); $ output machine register 13 size omode(ps); $ output mode. 14 size omoff(mosize); $ output offset. 15 size mop(ps); $ machine operation. 16 size i(ps); $ index. 17 18 size eutab(ps); $ table to drive routine. 19 size euotab(ps); dims euotab(ao_luo-ao_fuo+1); 20 +* eutab(i) = euotab(i-(ao_fuo-1)) ** 21 data 22 eutab(ao_bfb) = mo_bfb: 23 eutab(ao_bnb) = mo_bnb: 24 eutab(ao_bno) = mo_bno: 25 eutab(ao_iab) = mo_iab: 26 eutab(ao_iao) = mo_iao: 27 eutab(ao_ico) = mo_ico: dsj 61 eutab(ao_ifr) = mo_ifr: 28 eutab(ao_iso) = mo_iso: 29 eutab(ao_rab) = mo_rab: 30 eutab(ao_rco) = mo_rco: dsj 62 eutab(ao_rfi) = mo_rfi: dsj 63 eutab(ao_rtr) = mo_rtr: 31 eutab(ao_ldf) = mo_ldf: 32 eutab(ao_lpr) = mo_lpr; 33 34 macdrop(eutab) 35 36 size mreg(ps); $ machine register. 37 size ildr(1); $ 'last usage of input' 38 size op(ps); $ operation code within routine. 39 size t(ps); $ dummy variable. 40 41 .+trace. $ generate trace info. 42 if trace_a then $ this trace wanted. 43 tintl('unop, op',iop) tintl('out',outr) tintl('in',inr) endl 44 end if; 45 ..trace 46 47 $ initialize for emission. 48 op = iop - (ao_fuo-1); $ get operation code for local use. 49 i = gd_use; 50 if (isscon(inr) & dr_reg dreg(inr)=0) i = gd_addr; 51 getdesc(inr, i, imode, imreg, imoff); $ get input. 52 getdesc(outr, gd_use, omode, omreg, omoff); $ get input into reg 53 54 $ get last usage value for variable. 55 ildr = lastdrop(inr); $ get last usage counts. 56 57 $ the next step is to see if the input is not in a register 58 $ but this is not the last use. in this case, bring into 59 $ register, if one is available. 60 61 if ildr = no & imode^=am_reg & isinif = no then $ check for -i 62 $ first, get a register of the appropriate type. 63 getreg(mreg, rt_need); $ get real or general. 64 65 if mreg then $ one is available. 66 imreg = mreg; $ show register that input will be in. 67 getvar(inr, gd_intoreg, imode, imreg, imoff); $ load. 68 69 if outr = inr then $ must update -out- status too. 70 omreg = mreg; omode = am_reg; 71 end if; 72 end if; 73 end if; 74 75 $ must get a register to use as the output of the 76 $ operation. this can come from either a register permanently 77 $ assigned to the output, from the input if register status 78 $ indicates such, or from a new register. upon exit from 79 $ the following 'maybe' loop, -omreg- contains the output 80 $ register to use. 81 until yes; $ get a register. 82 if (omode=am_reg) quit until; $ if have it, quit. 83 omreg = imreg; $ see if safe to use input register. 84 if (imode=am_reg & ildr & rl_perm reglis(imreg)=no) 85 quit until; 86 87 $ otherwise, get register if available. 88 89 $ see if must get a new register. 90 i = rt_need; $ assume dont have to. 91 if (rl_type reglis(imreg) > rt_need) i = rt_live; $ do. 92 if (imode^=am_reg) i = rt_live; $ cannot use if not in reg. 93 getreg(omreg, i); $ get register for output. 94 if (omreg) quit until; $ if got one, exit. 95 omreg = imreg; $ else use input after all. 96 end until; 97 98 $ see if input register used was input register. 99 if omreg = imreg then $ it was. must drop and/or store. 100 if rl_type reglis(imreg)=rt_live & isvar(inr) then 101 store(imreg, inr); 102 end if; 103 dr_reg dreg(inr) = 0; $ show no longer in register. 104 end if; 105 106 $ get machine operation and check for halfword case in lpr. 107 mop = euotab(op); $ get default operation. vaxa 280 .+t10. 108 if mop = mo_lpr & emopparm2 = mws/2 then $ could be special. 109 if emopparm1 = 0 then $ is right half. 110 mop = mo_ldr; $ load right half. 111 elseif emopparm1 = mws/2 then $ is left half. 112 mop = mo_ldl; $ load left half. 113 end if; 114 end if; vaxa 281 ..t10 115 116 emop(mop, omreg, imode, imreg, imoff); $ emit op. 117 118 $ set status of output register. 119 rl_content reglis(omreg) = outr; $ show it contains output. 120 rl_subtype reglis(omreg) = rt_live; $ show live. 121 dr_reg dreg(outr) = omreg; $ point -dreg- to -mreg-. 122 123 drop(inr); drop(outr); $ drop operands. 124 125 126 end subr emitun; 1 .=member branchr 2 subr branchr(bmask, mreg, label); $ handle branches. 3 $ process branch operations. 4 size bmask(4); $ input branch mask. 5 size label(ps); $ label number to branch to. 6 size fixptr(ps); $ pointer to fixup table. 7 size mreg(ps); $ machine register. 8 size labent(lablistsz); $ temporary 9 size bops(.sds.3); dims bops(8); 10 +* bop(bm, op) = bops(bm+1) = op ** 11 12 data vaxa 282 .+t10 bop(bm_all , 'jmp'): vaxa 283 .+t32 bop(bm_all , 'jma'): 14 bop(bm_neg , 'jlt'): 15 bop(bm_pos , 'jgt'): 16 bop(bm_zer , 'jeq'): 17 bop(binv(bm_all) , 'jmn'): 18 bop(binv(bm_neg) , 'jge'): 19 bop(binv(bm_pos) , 'jle'): 20 bop(binv(bm_zer) , 'jne'); 21 macdrop(bop) 22 23 .+trace. $ generate trace code. 24 if trace_a then $ print trace info. 25 tintl('branchop, mask', bmask) tintl('label', label) endl 26 end if; 27 ..trace 28 29 put ocsfile ,column(9) 30 :bops(bmask+1),a(3), column(17) dss 52 ,'r' :mreg-1,i dss 53 ,',l' dss 54 :(label+lablorg),i(labcol, labcol); 32 call ocsput(0, 0); 33 end subr branchr; 1 .=member getdesc 2 subr getdescr(var, type, mode, reg, off); $ get register descr. 3 $ this routine is passed a dummy register pointer in 4 $ variable -var- and a type in -type-. 5 size var(ps); $ variable to process. 6 size type(ps); $ type of call. 7 size mode(ps); $ indirect reference flag. 8 size reg(ps); $ machine register. 9 size off(mosize); $ machine offset. 10 size hcode(mws); $ hash code for temporary allocation. 11 size i(ps), j(ps); $ temporary pointers. 12 size blk(ps), adr(ws); $ block and address. 13 14 $ first, unless the type is -gd_addr-, in which case a value 15 $ in a register is not wanted, if a register contains the value, 16 $ return it. 17 18 if dr_reg dreg(var) then $ check for special type. 19 if type ^= gd_addr then $ return value in reg. 20 reg = dr_reg dreg(var); $ set register. 21 mode = am_reg; $ show not indirect. 22 adr = 0; blk = 0; 23 go to ret; $ return value. 24 end if; 25 end if; 26 27 $ if address of value is in register, use it as indirect. 28 if di_addrreg ditem(dr_item dreg(var)) then $ have this case. 29 reg = di_addrreg ditem(dr_item dreg(var)); $ set register. 30 adr = (dw_madr dword(dr_word dreg(var)))-1; $ set offset. 31 blk = 0; 32 mode = am_rel; $ set to use indirectly. 33 go to ret; 34 end if; 35 36 $ handle case where variable is parameter to routine. 37 if isind(var) then $ is an argument. 38 if (dr_word dreg(var) ^= di_lword ditem(dr_item dreg(var))) 39 call aermey(23); $ this is a fatal error. 40 $ get a base register for the address. vaxa 284 .+t10 adr = di_anum ditem(dr_item dreg(var))-1; blk = 0; vaxa 285 .+t32 adr = di_anum ditem(dr_item dreg(var)); blk = 0; 42 reg = parmreg; mode = am_reli; blk = 0; 43 go to ret; 44 end if; 45 46 if isscon(var) & type^=gd_addr then $ if short constant 47 off = 0; adr = conval(var); blk = bl_imm; 48 reg = sparereg; 49 mode = am_mem; 50 go to ret; 51 end if; 52 53 $ if address has not been assigned, this must be a 54 $ constant that resides in the base block. 55 if di_mblk ditem(dr_item dreg(var)) = 0 then $ not assigned. 56 if (di_baseblk ditem(dr_item dreg(var)) = no ! ismw(var)) 57 call aermey(24); $ this is a fatal error. 58 i = di_chain ditem(dr_item dreg(var)); $ baseblock pointer. 59 if (bb_type baseblock(i) ^= bt_const) call aermey(24); 60 61 $ must allocate an address to the constant. 62 bb_addr baseblock(i) = baselastaddr; $ set address. 63 di_mblk ditem(dr_item dreg(var)) = bl_base; $ set block. 64 dw_madr dword(dr_word dreg(var)) = baselastaddr; $ address. 65 baselastaddr = baselastaddr + 1; $ step up adddess. 66 67 $ put entry on chain. 68 if baselast then $ is not first. 69 bb_chain baseblock(baselast) = i; $ set onto chain. 70 else $ this is first entry. 71 basefirst = i; $ set to chain head. 72 end if; 73 74 baselast = i; $ show this is last in chain. 75 end if; 76 77 mode = am_mem; $ in memory. 78 reg = sparereg; $ constant pseudo-reg. 79 blk = di_mblk ditem(dr_item dreg(var)); 80 adr = dw_madr dword(dr_word dreg(var)) - 1; 81 82 /ret/ 83 if (adr<0) adr = mneg(iabs(adr)); 84 off = 0; mbo_blk off = blk; mbo_off off = adr; 85 .+trace. $ compile trace code. 86 if trace_r then $ if tracing machine registers 87 tintl('getdesc var', var) tintl('type', type) 88 textl(' --> ') tintl('reg', reg) 89 tintl('mode',mode) tintl('blk', blk) 90 textl('off ') 91 if .f. mps, 1, adr then $ if negative offset 92 textl('-') intl(mneg(adr)) 93 else 94 intl(adr) 95 end if; 96 endl end if; 97 ..trace 98 99 rl_hold reglis(reg) = yes; $ indicate register needed soon. 100 end subr getdescr; 101 subr getvarr(var, type, mode, mreg, moff); $ get variable. 1 .=member getvar 2 $ this routine is called to reference a dummy register. it 3 $ can be used to load a dummy register into a machine register, 4 $ to get the address of a dummy register's variable, or to 5 $ get a dummy register into any addressable mode. the type is 6 $ used to determine parameters to use to determine what 7 $ operations to issue. -mode-, -mreg-, and -moff- are set as 8 $ in -getdescr-. 9 size var(ps); $ dummy register. 10 size type(ps); $ type of call. 11 size mode(ps); $ indirect flag. 12 size mreg(ps); $ machine register to return. 13 size moff(mosize); $ machine offset. 14 size i(ps), j(ps); $ temporaries. 15 size mreg1(ps); $ temporary machine register. 16 size mode1(ps); $ temporary machine indirect flag. 17 size moff1(mosize); $ temporary machine offset. 18 size mop(ps); $ machine operation to issue. 19 20 $ table for actions depending on type. 21 size gvtab(2); $ define table. 22 dims gvtab(num_gd); $ number of types. 23 24 $ macros for bits in table. 25 +* gt_forcr = .f. 1, 1, ** $ force into any register. 26 +* gt_forci = .f. 2, 1, ** $ force into specific register. 27 28 +* gvt(i, fr, fi) = $ macro to define table. 29 gvtab(i) = fi*2+fr ** 30 31 data $ initialize type table. 32 $ type fr fi 33 $ ---- -- -- 34 gvt(gd_addr, no, no): 35 gvt(gd_use, no, no): 36 gvt(gd_reg, yes, no): 37 gvt(gd_intoreg, yes, yes): 38 gvt(gd_inregnu, yes, yes); 39 40 macdrop(gvt) 41 42 $ first, get descriptor for variable. 43 getdesc(var, type, mode1, mreg1, moff1); 44 mode = mode1; moff = moff1; $ set user return values. 45 46 $ see if the variable is in a register. 47 if mode1 = am_reg then $ it is in a register. 48 $ if must force into a 49 $ specific register. 50 if gt_forci gvtab(type) then 51 52 $ if in the desired register, return. 53 if (mreg1 = mreg) return; 54 55 mrcopy(mreg, mreg1); $ copy reg. 56 57 $ unless type is not to update status, do the 58 $ status update. 59 if type ^= gd_inregnu then $ must do update. 60 $ if old was permanent, build new form. 61 if rl_perm reglis(mreg1) then $ it is. 62$ call gfdreg(mreg, var); $ get new -dreg-. 63 call aermey(34); 64 else $ can do simple update. 65 reglis(mreg) = reglis(mreg1); $ copy status. 66 reglis(mreg1) = 0; $ clear old status. 67 dr_reg dreg(var) = mreg; $ show in register. 68 end if; 69 end if; 70 71 else $ it is ok as is. 72 mreg = mreg1; $ copy register given. 73 end if; 74 75 76 else $ dummy register is not in a machine register. 77 $ see if must load to a register. 78 if gt_forcr gvtab(type) then $ must get into register. 79 mode = am_reg; $ show will be in register. 80 81 $ unless are going to force into a particular 82 $ register, must get a register. 83 if gt_forci gvtab(type) = no then $ must get a register. 84 getreg(mreg, rt_live); $ get register. 85 end if; 86 87 $ if the output register is not real and the input 88 $ is a short constant, can bring it in without a 89 $ storage reference. 90 if isscon(var) & conval(var)=0 then 91 mrclear(mreg); $ zeroize reg. 92 93 else $ not constant. 94 emop(mo_ldw, mreg, mode1, mreg1, moff1); 95 end if; 96 97 $ unless this was a no-update call, update status. 98 if type ^= gd_inregnu then $ must update. 99 rl_content reglis(mreg) = var; $ show owner. 100 dr_reg dreg(var) = mreg; $ show which register. 101 rl_type reglis(mreg) = rt_need; $ reduce type. 102 end if; 103 104 else $ it is ok as is. 105 mreg = mreg1; $ copy register given. 106 end if; 107 end if; 108 109 .+trace. $ emit trace code. 110 if trace_r then $ print trace info. 111 tintl('getvar', var) tintl('mreg', mreg) endl 112 end if; 113 ..trace 114 115 rl_hold reglis(mreg) = yes; $ hold gotten register. 116 117 end subr getvarr; 1 .=member getreg 2 subr getregr(type); $ get a register. 3 $ thus routine is the register allocator for the general 4 $ purpose registers. it returns the register number via the 5 $ global variable -gotreg-. 6 size type(ps); $ register type. 7 size lo(ps), hi(ps); $ search limits. 8 size i(ps); $ loop variable. 9 size blru(ps); $ best lru value so far. 10 size btype(ps); $ best type so far. 11 size reg(ps); $ dummy register pointer. 12 13 $ select the register bounds to search. 14 lo = nextgfree; hi = rhi; $ set high bounds for general. 15 16 gotreg = 0; $ initially dont have a register. 17 blru = 4b'1000'; $ set to worst lru value. 18 btype = type; $ set to worst allowable type. 19 if (btype = rt_live) btype = rt_liveaddr; $ ensure -live- gets. 20 21 $ scan for best register to use. vaxa 286 .+t10 do i = nextgfree to rhi; $ scan all registers. vaxa 287 .+t32 do i = rlo to nextgfree; $ scan all registers. 23 if (rl_hold reglis(i)) cont do; $ skip if held. 24 if (rl_addrhold reglis(i)) cont do; $ skip if held. 25 if (rl_type reglis(i) > btype) cont do; $ worse type. 26 if (rl_type reglis(i) = btype & rl_usevalue reglis(i) > blru) 27 cont do; $ worse lru for same type. 28 29 $ else, this is best so far. 30 gotreg = i; $ set to use this register. 31 btype = rl_type reglis(i); $ set best type so far. 32 blru = rl_usevalue reglis(i); $ set best lru value so far. 33 end do; 34 35 36 if gotreg then $ found a register. 37 $ select method of dropping this register by its prior type. 38 go to dtyp(btype) in rt_dead to rt_liveaddr; 39 40 /dtyp(rt_live)/ $ drop live register. 41 store(gotreg, rl_content reglis(gotreg)); $ store it. 42 $ status is -need- so fall through. 43 44 /dtyp(rt_need)/ $ value in register. 45 dr_reg dreg(rl_content reglis(gotreg)) = 0; $ not in reg. 46 go to dtyp(rt_dead); $ register is dead. 47 48 /dtyp(rt_address)/ $ address is in register. 49 di_addrreg ditem(rl_content reglis(gotreg)) = 0; 50 go to dtyp(rt_dead); $ type is dead. 51 52 /dtyp(rt_liveaddr)/ $ live address in register. 53 store(gotreg, dw_freg dword(di_lword ditem(rl_content 54 reglis(gotreg)))); $ store into primary register. 55 $ status is -dead- so fall through. 56 57 /dtyp(rt_dead)/ $ register can be used. 58 reglis(gotreg) = 0; $ clear register status. 59 rl_type reglis(gotreg) = type; $ set to desired type. 60 rl_hold reglis(gotreg) = yes; $ hold gotten register. 61 62 63 end if; 64 65 66 .+trace. 67 if trace_r then $ print register info. 68 tintl('gotreg', gotreg) tintl('type', type) endl 69 end if; 70 ..trace 71 72 end subr getregr; 1 .=member getpair 2 .+eab. 3 subr getrpair(use1, use2); $ get a register pair. 4 $ this routine is called by the -getregpair- macro to get a 5 $ pair of registers. it first checks to see if a pair exists 6 $ of which neither register is on hold. the best such pair is 7 $ picked and a pair containing one of the 'ok-to-use' registers 8 $ is weigthed more heavily. if no normal registers are a 9 $ available, r0-r1 and r14-r15 are tried, in that order. 10 $ the lowest register of the gotten pair is returned via 11 $ global variable -gotrpair-. 12 size use1(ps), use2(ps); $ registers that can be used. 13 size i(ps), j(ps); $ temporaries. 14 size btype(ws); $ best type so far. 15 size blru(ws); $ best lru value so far. 16 size type(ws); $ type of this pair. 17 size lru(ws); $ lru value of this pair. 18 size reg(ps); $ temporary register. 19 20 $ first, scan all registers to find the best available 21 $ pair. note that can use a register which has -addrhold- 22 $ set as long as it does not also have -hold- set because 23 $ it can be moved to another register. 24 btype = rt_liveaddr*2; $ set to worst type. 25 blru = 4b'1000'*2; $ set to worst lru. 26 gotrpair = 0; $ show didn't find any yet. 27 $ rhi was r10, not r12 (check). 28 do i = rlo to rhi by 2; $ scan all pairs. 29 $ set combined values for both registers. 30 type = 0; lru = 0; $ set counters to zero. 31 do j = i to i+1; $ scan both registers in pair. 32 if (rl_addrhold reglis(j)) cont do i; $ if perm. 33 if (rl_perm reglis(j)) cont do i; $ or if perm. 34 if j = use1 ! j = use2 then $ can use this one. 35 type = type-1; lru = lru-1; $ make this seem better. 36 else $ just add types and lru value. 37 if (rl_hold reglis(j)) cont do i; $ skip if held. 38 type = type+rl_type reglis(j); $ add type. 39 lru = lru+rl_usevalue reglis(j); $ add lru. 40 end if; 41 end do j; 42 43 $ that have the combined type and useage value of 44 $ the pair, if this is worse than the best so far, skip. 45 if (type > btype) cont do; $ worse type. 46 if (lru > blru) cont do; $ worse lru value. 47 gotrpair = i; $ show register obtained. 48 btype = type; blru = lru; $ set new 'best' values. 49 end do i; 50 51 $ see if got a register. 52 if gotrpair = 0 then $ didn't.. try r0 and r14. 53 call aermey(25); 54 end if; 55 $ [ds 11 apr what does end if below close...] 56 end if; 57 58 59 $ scan both registers and drop them as needed. 60 do j = gotrpair to gotrpair+1; $ scan over both in pair. 61 $ hold both registers. 62 rl_hold reglis(gotrpair)=yes; rl_hold reglis(gotrpair+1)=yes; 63 if j ^= use1 & j ^= use2 & j ^= r1 then $ must drop. 64 go to drp(rl_type reglis(j)) in rt_dead to rt_liveaddr; 65 else $ cannot drop register. 66 cont do; $ go around loop again. 67 end if; 68 69 /drp(rt_need)/ /drp(rt_address)/ /drp(rt_live)/ 70 /drp(rt_liveaddr)/ $ most needed types. 71 $ in this case try to get a another register of the desired 72 $ type and do a move. 73 getreg(gotreg, rl_type reglis(j)); $ try to get one. 74 if gotreg then $ got one. 75 mrcopy(gotreg, j); $ copy reg. 76 reglis(gotreg) = reglis(j); $ move status. 77 rl_hold reglis(gotreg) = no; $ but clear hold. 78 end if; 79 80 $ if type is address update all forms or otherwise 81 $ just one. 82 if rl_type reglis(j) = rt_address ! $ update all forms. 83 rl_type reglis(j) = rt_liveaddr then $ go ahead. 84 di_addrreg ditem(rl_content reglis(j)) = gotreg; 85 else $ data -- just clear one form. 86 dr_reg dreg(rl_content reglis(j)) = gotreg; $ update. 87 end if; 88 89 /drp(rt_dead)/ $ need not drop anything. 90 reglis(j) = 0; $ so just clear status. 91 cont do; 92 93 end do j; 94 95 $ just clear to set final status. 96 rl_hold reglis(gotrpair) = yes; $ hold first register. 97 rl_hold reglis(gotrpair+1) = yes; $ hold second. 98 99 .+trace. 100 if trace_r then $ print trace info. 101 tintl('getregpair, reg', gotrpair) tintl('u1', use1) 102 tintl('u2', use2) endl 103 end if; 104 ..trace 105 106 end subr getrpair; 107 ..eab 1 .=member storer 2 subr storer(mreg, reg); $ store a machine register. 3 $ this routine is called to store the contents of a 4 $ machine register in order to free the register. it 5 $ is called for two classes of contents. in the case 6 $ where the register is a live address, it is called to 7 $ move the data pointed to by the register into a 8 $ temporary. in the other cases, the register contains 9 $ data that is simply stored. note that this routine 10 $ may be called by the register allocator and this must 11 $ be carefull which routines it calls. 12 size mreg(ps); $ machine register to store. 13 size reg(ps); $ dummy register to store into. 14 size mreg1(ps); $ machine register for item. 15 size moff1(mosize); $ machine offset for item. 16 size mode1(ps); $ machine mode for item. 17 size t(ws); $ temporary. 18 size i(ps); $ loop variable. 19 20 .+trace. $ print trace code if wanted. 21 if trace_r then $ trace code is wanted. 22 tintl('storer, mreg', mreg) tintl('reg', reg) endl 23 end if; 24 ..trace 25 26 $ check if this is the case of data in a register. 27 if rl_subtype reglis(mreg) ^= rt_liveaddr then $ it is. 28 $ must get the address of the item for which 29 $ this register corresponds. the only time that 30 $ have trouble and cannot do this directly is when 31 $ have a word other than the last of an argument. 32 $ so first handle the simple case. 33 if isind(reg) = no ! dr_word dreg(reg) = $ test for simple. 34 di_lword ditem(dr_item dreg(reg)) ! 35 di_addrreg ditem(dr_item dreg(reg)) then $ it is. 36 getdesc(reg, gd_addr, mode1, mreg1, moff1); $ get item. 37 else $ this is the less simple case. in this case, 38 $ will get the address of the last word and then 39 $ subtract enough to point to the desired position. vaxa 288 .+t10 emop(mo_ldw, sparereg, am_reg, parmreg, vaxa 289 .+t10 di_anum ditem(dr_item dreg(reg))-1); vaxa 290 .+t32 moff1=0; mbo_off moff1=di_anum ditem(dr_item dreg(reg)); vaxa 291 .+t32 emop(mo_ldw, sparereg, am_reg, parmreg, moff1); 42 mreg1 = sparereg; 43 mode1 = am_rel; 44 t = dw_madr dword(dr_word dreg(reg)) - 1; $ get desired addre 45 if (t<0) t = mneg(iabs(t)); $ set to valid machine address. 46 moff1 = 0; mbo_off moff1 = t; $ set offset. 47 end if; 48 49 $ get operation to issue. 50 $ do the actual store. 51 emop(mo_stw, mreg, mode1, mreg1, moff1); 52 53 $ set the status of the register to only needed if it 54 $ was live before. 55 if (rl_subtype reglis(mreg) = rt_live) $ update. 56 rl_subtype reglis(mreg) = rt_need; 57 58 59 60 else $ this is a live address in a register. 61 $ first check to see if this is a valid call. 62 if (rl_content reglis(mreg) ^= dr_item dreg(reg)) 63 call aermey(27); $ this is an error. 64 65 if (istemp(reg) = no ! ismw(reg) = no) call aermey(28); 66 67 $ get the word offset (-1) that the register is 68 $ pointing to. dsu 121 t = (dw_word dword(dr_word dreg(reg)) - dsu 122 dw_madr dword(dr_word dreg(reg))) * mcpw; 71 72 $ if it is not pointing to the first word, must 73 $ adjust it so it does. 74 if t then $ must adjust. 75 if (t<0) t = mneg(iabs(t)); $ set machine address. 76 moff1 = 0; mbo_blk moff1 = bl_imm; $ show immediate. 77 mbo_off moff1 = t; $ set constant to subtract. 78 emop(mo_isu, mreg, am_mem, sparereg, moff1); $ do subtrac 79 end if; 80 81 $ must get the address of the item back. 82 $ first, do another validity check. 83 if (di_baseblk ditem(dr_item dreg(reg))) call aermey(28); 84 85 t = vv_madr voa(di_chain ditem(dr_item dreg(reg))) - 86 nwords(reg); $ get low address -1. 87 88 $ update ditem status to show no longer floating 89 $ address in register. 90 di_addrreg ditem(dr_item dreg(reg)) = 0; $ no register. 91 92 $ update the address fields in each word to reflect 93 $ the core address. 94 i = di_lword ditem(dr_item dreg(reg)); $ point to head. 95 while i; $ while more words in chain. 96 dw_madr dword(i) = t + dw_word dword(i); 97 i = dw_next dword(i); $ step to next. 98 end while; 99 100 $ get address to store into and emit the move. 101 moff1 = 0; mbo_blk moff1 = di_mblk ditem(dr_item dreg(reg)); 102 mbo_off moff1 = t; $ set offset of start (left end) of item. 103 emopparm1 = nwords(reg); $ set length to move. dsu 123 emop(mo_mvx, mreg, am_mem, sparereg, moff1); $ move to storag 105 106 reglis(mreg) = 0; $ show register is dead. 107 end if; 108 109 end subr storer; 1 .=member mover 2 subr mover(outr, inr); $ move from out -dreg- to another. 3 $ this routine is called by the -move_op- macro to move 4 $ data from one -dreg- to another. it handles various 5 $ cases depending on the lastuse status of the output and 6 $ input and whether the output and input are already assigned 7 $ to registers. 8 size outr(ps); $ output dummy register. 9 size inr(ps); $ input dummy register. 10 size omode(ps); $ set if output is indirect (in core) 11 size imode(ps); $ set if input is in core. 12 size ooff(mosize); $ core offset of output if in core. 13 size ioff(mosize); $ core offset of input. 14 size omreg(ps); $ output register (or base if in core). 15 size imreg(ps); $ input register. 16 size oldr(1); $ set if last usage of output. 17 size ildr(1); $ set if last usage of input. 18 size treg(ps); $ temporary machine register. 19 size mop(ps); $ machine operation to issue. 20 size t(ps); $ temporary. dsj 64 size moff(mosize); $ temporary. 21 22 .+trace. 23 if trace_a then $ print trace code. 24 tintl('move, out', outr) tintl('in', inr) endl 25 end if; 26 ..trace 27 28 if (inr = outr) go to ret; $ this is a no-op. 29 30 $ first, get information about the input. 31 ildr = lastdrop(inr); 32 33 $ get location descriptor for input. 34 getdesc(inr, gd_use, imode, imreg, ioff); 35 36 $ get info. for output. 37 oldr = lastdrop(outr); 38 getdesc(outr, gd_use, omode, omreg, ooff); $ get locator. 39 40 $ check for the case where the output will be used again 41 $ and is not assigned to a register and where the input is 42 $ in a register and this is it's last use. in this case, 43 $ re-assign the register to the output. 44 if omode^=am_reg & oldr = no & ildr & imode=am_reg then $ have t 45 $ if the input register is permanently assigned, it cannot 46 $ be re-assigned to the output. so in that case, this 47 $ proceedure will not be used. 48 if rl_perm reglis(imreg) = no then $ ok to re-assign. 49 if rl_type reglis(imreg)=rt_live & isvar(inr) then 50 store(imreg, inr); 51 end if; 52 rl_content reglis(imreg) = outr; $ set to output. 53 rl_type reglis(imreg) = rt_live; $ set to live. 54 dr_reg dreg(inr) = 0; $ set to null in this case. 55 dr_reg dreg(outr) = imreg; $ set output to old reg. 56 go to ret; $ done in this case. 57 end if; 58 end if; 59 60 if oldr & isscon(inr) & conval(inr)=0 then $ if zero. 61 emop(mo_zew, r0, omode, omreg, ooff); $ issue zew. 62 go to ret; 63 end if; 64 65 $ if input is in storage, then it must be loaded 66 $ into a register. 67 if imode^=am_reg then $ input is in storage. 68 $ must determine whether this register will be 69 $ to the input or the output because the register should 70 $ be of the same mode as the value to which it is being 71 $ assigned. if this is the last usage of the input, then 72 $ the register is assigned to the output and vice versa. 73 if ildr & omode=am_reg then $ last use of input -- assign to 74 $ if output is already assigned to a register, can use 75 $ it. (occurs when output is permanently in register). 76 treg = omreg; $ get output register. 77 else $ last usage of output -- assigned to input. 78 $ note that need not check for output permanently in 79 $ register because know that it is storage. 80 getreg(treg, rt_live); $ get register. 81 end if; 82 83 84 $ do load of input into -treg-. dsj 65 getvar(inr, gd_inregnu, t, treg, moff); $ load no update. 86 87 $ update register tracking status. if last usage of 88 $ input, assign new register to output. dsg 10 if ildr then $ assign to output. 90 dr_reg dreg(outr) = treg; $ set in -dreg- info. 91 rl_content reglis(treg) = outr; $ point -mreg- to -dreg-. 92 rl_subtype reglis(treg) = rt_live; $ show live. 93 omreg = treg; omode = am_reg; $ show output in regist dsg 11 if (oldr) store(omreg, outr); 94 else $ assign to input. 95 dr_reg dreg(inr) = treg; $ set in -dreg- info. 96 rl_content reglis(treg) = inr; $ point -mreg- to -dreg-. 97 rl_subtype reglis(treg) = rt_need; 98 imreg = treg; imode = am_reg; $ show input in registe 99 end if; 100 end if; 101 102 103 $ if this is last usage of output and output is not 104 $ assigned to a register, store into output. 105 if oldr & omode^=am_reg then $ have this case. 106 /storecase/ $ branched to from below. 107 t = rl_type reglis(imreg); $ save old status. 108 store(imreg, outr); $ store into output. 109 rl_subtype reglis(imreg) = t; $ restore register status. 110 go to ret; $ done. 111 end if; 112 113 $ if input is not in a register and this is last usage of 114 $ input, all work has been done so exit. 115 if (ildr & imode^=am_reg) go to ret; 116 117 $ otherwise, must copy input register into output register. 118 rl_hold reglis(imreg) = yes; $ just in case. 119 120 $ must get a register of the correct mode. first 121 $ check if the output is permanently assigned to a register. 122 if omode=am_reg then $ it is -- use that register. 123 treg = omreg; $ set to output register. 124 else $ output not in register. 125 getreg(treg, rt_need); $ get register. 126 end if; 127 128 $ if no register was assigned, go do store case. 129 if (treg = 0) go to storecase; $ go store. 130 131 $ must check which load register operation to issue. 132 $ note that if the assigned input register and the permanently 133 $ assigned output register are of different modes, a load/store 134 $ must be done to do the operation. 135 mrcopy(treg, imreg); $ copy reg. 136 137 $ finally, update register status. 138 rl_subtype reglis(treg) = rt_live; $ set to live. 139 rl_content reglis(treg) = outr; $ point -mreg- to -dreg-. 140 dr_reg dreg(outr) = treg; $ set to register number. 141 142 /ret/ $ common exit point. 143 drop(outr); drop(inr); $ drop operands if last usage. 144 end subr mover; 1 .=member endsubr 2 subr endsubr; $ terminate processing of a routine. 3 $ this routine is called after all code for a routine has been 4 $ emitted. -endsubr- then computes the location of each 5 $ internal machine block in the program csect. it then emits 6 $ data, esd, and rld entries to initialize the base block and 7 $ any other blocks such as the constant block. in addition, 8 $ it calls -outdata- to process data statements for any 9 $ variables encountered. 10 $ routine has been emitted. it then emits 11 $ data entries to initialize the base block and 12 $ any other blocks such as the constant block. in addition, 13 $ it calls -outdata- to process data statements for any 14 $ variables encountered. 15 size i(ps), j(ps), k(ps), t(ps); $ temporaries. 16 size reg(ps); $ dummy register. 17 size len(ps); $ length. 18 size moff(mosize); $ temporary. 19 20 21 $ must put in code for return if return label is 22 $ set. 23 if returnlab then $ need code for return. 24 labdef(returnlab, yes); $ define label. 25 26 $ first, store all live permanent registers. 27 do i = r0 to rhi; $ scan all possible. 28 if rl_type reglis(i) = rt_permlive then $ must store. 29 store(i, rl_content reglis(i)); $ store back. 30 end if; 31 end do; 32 33 $ if function, must load r0 . 34 if subrtype = st_fnct then $ is function. 35 assign(reg, va_fnct); $ get register. 36 lastuse(reg); $ set status. 37 forcezero(reg, ismw(reg)); $ force into r0. 38 end if; 39 40 $ emit return operation. 41 put ocsfile ,column(9) ,'ret' ,column(17) vaxa 292 .+t10 :currsubname,a; vaxa 293 .+t32 ; 43 call ocsput(0, 0); $ put code 44 end if; 45 dsq 102 .+t32. dsq 103 $ output entry mask shifted right by two. dsq 104 $ set overflow bit if want integer overflow traps. dsq 105 size maskword(ws); dsq 106 maskword = .f. r2, rhi-r2+1, regmask; dsq 107 if iv_opt then $ if want overflow trap dsq 108 .f. 15-2, 1, maskword = 1; $ raise overflow traps. dsq 109 end if; dsu 124 .+t32h. dsu 125 if nsheap_this then dsu 126 .f. nsheapreg_w-2, 1, maskword = 1; $ using heap reg dsu 127 .f. nsheapreg_b-2, 1, maskword = 1; $ using heap reg dsu 128 end if; dsu 129 ..t32h dsq 110 ..t32 46 put ocsfile ,column(9) ,'dec' $ indicate end of code vaxa 294 .+t10 ,column(17) :currsubname,a; vaxa 295 .+t32 ,column(17) :currsubname,a ,',' dsq 111 .+t32 :maskword,b(0,4); 48 call ocsput(0, 0); $ put code. 49 trace_c = no; $ do not trace declarations. 50 51 mb_len mba(bl_base) = baselastaddr-1; $ length of base block. 52 vaxa 297 .+t10. 53 $ allocate base block. 54 if baselastaddr>1 then $ if base block. 55 put ocsfile ,column(9) ,'dbw' ,column(17) 56 :mblkname(bl_base),a ,',' $ put block name. 57 :baselastaddr-1,i; 58 call ocsput(0, 0); $ put code. 59 end if; vaxa 298 ..t10 vaxa 299 vaxa 300 vaxa 301 .+t32. vaxa 302 $ allocate constant block. vaxa 303 if mb_len mba(bl_const) then $ there is a constant block. vaxa 304 put ocsfile ,column(9) ,'dbr' ,column(17) vaxa 305 :mblknames(bl_const),a ,',' vaxa 306 :(mb_len mba(bl_const))*mcpw,i; vaxa 307 call ocsput(0, 0); $ write out line. vaxa 308 end if; vaxa 309 ..t32 60 61 $ emit constants in constant block. 62 i = mb_chain mba(bl_const); $ get start of constant block. 63 ddblk = bl_const; dss 55 .s. 17, 3, ocs = mblkname(bl_const); $ indicate constant block. dss 56 .s. 20, 1, ocs = '+'; 65 while i; 66 ddoff = vv_madr voa(i) - (vv_syze voa(i) + (mws-1))/mws; vaxa 310 .+t32 ddoff = ddoff * mcpw; $ set to byte address. dsw 21 call outcon(i,3); $ put out value. 68 i = vv_dimn voa(i); $ link to next. 69 end while; 70 71 vaxa 311 .+t32. vaxa 312 $ allocate base block. vaxa 313 if mb_len mba(bl_base) then $ if there is a base block. vaxa 314 put ocsfile ,column(9) ,'dbw' ,column(17) vaxa 315 :mblknames(bl_base),a ,',' vaxa 316 :(mb_len mba(bl_base)) * mcpw,i; vaxa 317 call ocsput(0, 0); $ write out line. vaxa 318 end if; vaxa 319 ..t32 dss 57 .s. 17, 3, ocs = mblkname(bl_base); $ indicate base block. dss 58 .s. 20, 1, ocs = '+'; 73 $ process entries in base block. 74 i = basefirst; $ point to first entry in block. 75 while i; $ while more entries remain. 76 j = bb_pointer baseblock(i); $ get pointer from entry. 77 ddoff = bb_addr baseblock(i) - 1; $ dd offset. vaxa 320 .+t32 ddoff = ddoff * mcpw; $ set to byte pointer. 78 go to bt(bb_type baseblock(i)) in 1 to num_bt; $ select type. 79 /bt(bt_label)/ $ label entry. 80 .s. 9, 3, ocs = 'dwa'; $ set code op. 81 put ocsfile ,column(21) 82 :ddoff,i ,',' $ put offset dss 59 ,'l' dss 60 :(lablorg + bb_pointer baseblock(i)) ,i(labcol,labcol); 84 call ocsput(0, 1); $ put line. 85 go to contbase; $ continue. 86 87 /bt(bt_plist)/ $ parameter lists. vaxa 321 .+t32. $ write out number of entries. vaxa 322 .s. 9, 3, ocs = 'dwi'; vaxa 323 put ocsfile ,column(21) :ddoff,i ,',' vaxa 324 :bb_nwords baseblock(i),i; vaxa 325 call ocsput(0, 1); $ write the line. vaxa 326 ddoff = ddoff + mcpw; $ count the word. vaxa 327 ..t32 vaxa 328 vaxa 329 88 .s. 9, 3, ocs = 'dwa'; eaa 183 .-t20. 89 do k = j to bb_nwords baseblock(i) + j-1; 90 if pd_block pdlist(k) then $ if entry. dsu 130 .+t32h. dsu 131 if (nsheap_this=no) ! dsu 132 (nsheap_this & (pd_block pdlist(k) ^= nsheap_blk)) then dsu 133 ..t32h 91 put ocsfile ,column(21) 92 :ddoff,i ,',' 93 :mblkname(pd_block pdlist(k)),a ,'+' vaxa 330 .+t10 :pd_madr pdlist(k)-1,i; vaxa 331 .+t32 :(pd_madr pdlist(k)-1) * mcpw, i; 95 call ocsput(0, 1); $ put line. dsu 134 .+t32h end if; 96 end if; vaxa 332 .+t10 ddoff = ddoff + 1; $ step to next address. vaxa 333 .+t32 ddoff = ddoff + mcpw; $ step to next address. 98 end do; eaa 184 eaa 185 .+t20. eaa 186 do k = j to bb_nwords baseblock(i) + j - 1; eaa 187 if pd_block pdlist(k) then $ if entry eaa 188 if nsheap_this & (pd_block pdlist(k) = nsheap_blk) then eaa 189 .s. 9, 3, ocs = 'dha'; $ indicate heap address. eaa 190 put ocsfile ,column(21) eaa 191 :ddoff,i ,',efiw (' eaa 192 :nsheap_org,a ,'+' eaa 193 :pd_madr pdlist(k)-1,i ,',0)'; eaa 194 else $ if not heap block eaa 195 put ocsfile ,column(21) eaa 196 :ddoff,i ,',' eaa 197 :mblkname(pd_block pdlist(k)),a ,'+' eaa 198 :pd_madr pdlist(k)-1,i; eaa 199 end if; eaa 200 call ocsput(0, 1); $ put line. eaa 201 .s. 9, 3, ocs = 'dwa'; $ restore dwa op (in case was dha) eaa 202 end if; eaa 203 ddoff = ddoff + 1; $ step to next address. eaa 204 end do; eaa 205 ..t20 eaa 206 99 100 go to contbase; $ continue. 101 102 /bt(bt_const)/ $ single word constants. vaxa 334 .+t10 .s. 9, 3, ocs = 'dwo'; $ set op. vaxa 335 .+t32 .s. 9, 3, ocs = 'dwh'; $ set op. 104 put ocsfile ,column(21) 105 :ddoff,i ,',' vaxa 336 .+t10 :val(bb_pointer baseblock(i)),b(0,3); vaxa 337 .+t32 :val(bb_pointer baseblock(i)),b(0,4); 107 call ocsput(0, 1); $ put line. 108 109 /bt(bt_temp)/ 110 /contbase/ $ continue. 111 i = bb_chain baseblock(i); $ chain to next entry; 112 end while; 113 114 call ocsput(0, 2); $ clear code line. vaxa 338 vaxa 339 vaxa 340 .+t32. vaxa 341 $ allocate temporary block. vaxa 342 if mb_len mba(bl_temp) then $ nonempty. vaxa 343 put ocsfile ,column(9) ,'dbw' ,column(17) vaxa 344 :mblknames(bl_temp),a ,',' vaxa 345 :(mb_len mba(bl_temp)) * mcpw,i; vaxa 346 call ocsput(0, 0); $ write out line. vaxa 347 end if; vaxa 348 ..t32 vaxa 349 vaxa 350 115 $ generate initial values for variables in namesets 116 $ defined in this procedure. 117 do i = bl_local to mbaptr; $ loop over nameset entries. vaxa 351 vaxa 352 vaxa 353 .+t32. vaxa 354 if (mb_used mba(i) = no) cont do; vaxa 355 vaxa 356 vaxa 357 if i = bl_local then $ this is local block. vaxa 358 put ocsfile ,column(9) ,'dbw' ,column(17); vaxa 359 elseif mb_def mba(i) then vaxa 360 sdsname(dopsname, (mb_ha mba(i))); $ get block name. dst 85$ emit dnd, unless nspage_opt selected, in which case emit pnd dst 86 put ocsfile, column(9); dst 87 if nspage_opt then put ocsfile,'pnd'; dst 88 else put ocsfile,'dnd'; dst 89 end if; dst 90 put ocsfile ,column(17) vaxa 362 :dopsname,a ,','; vaxa 363 else $ not local, not defined. vaxa 364 sdsname(dopsname, (mb_ha mba(i))); $ get name. dst 91$ emit dna, unless nspage_opt selected, in which case emit pna dst 92 put ocsfile, column(9); dst 93 if nspage_opt then put ocsfile,'pna'; dst 94 else put ocsfile,'dna'; dst 95 end if; dst 96 put ocsfile ,column(17) vaxa 366 :dopsname,a ,','; vaxa 367 end if; vaxa 368 vaxa 369 vaxa 370 put ocsfile :mblknames(i),a ,',' $ write internal name. vaxa 371 :(mb_len mba(i)) * mcpw,i; vaxa 372 call ocsput(0,0); vaxa 374 ..t32 vaxa 375 vaxa 376 118 if (mb_def mba(i)=no) cont do; dsu 135 .+t20 if nsheap_this & (i=nsheap_blk) then cont do; end if; 119 ddblk = i; 120 121 j = mb_chain mba(i); $ point to first entry. 122 while j; $ while more remain in chain. 123 len = ((vv_syze voa(j)+mws-1)/mws)* 124 (vv_dimn voa(j) + (vv_dimn voa(j)=0)); 125 k = vv_madr voa(j) - ((vv_syze voa(j)+mws-1)/mws); 126 127 .-vvfrs if vv_frsdata voa(j) then $ must initialize. 128 .+vvfrs if vvfrsdata(j) then $ must initialize. 129 call outdata(j); $ call data routine. 130 end if; 131 132 j = vv_vbeg voa(j); $ chain to next entry. 133 end while; 134 end do; 135 136 call ocsput(0, 2); $ put line. 137 138 .s. 9, 3, ocs = 'dep'; $ indicate end of procedure 139 put ocsfile, column(17) :currsubname,a; 140 call ocsput(0, 0); vaxa 377 vaxa 378 vaxa 379 .+t32. $ must write out real '.end' statement. dsq 112 put ocsfile ,column(9) dsq 113 .+t32u $ 'end' probably not required for unix bootstrap,but dsq 114 .+t32u $ include for compatibility. dsq 115 .+t32u ,'end'; dsq 116 .+t32v ,'.end'; vaxa 381 if (subrtype = st_prog) put ocsfile ,column(17) vaxa 382 :currsubname,a; $ write out entry name if prog. vaxa 383 call ocsput(0, 0); $ write the line. vaxa 384 ..t32 141 142 dss 61 totprocs = totprocs + 1; 143 $ the rest of this processing is accumulation of statistics, 144 $ so if they are not wanted, return. 145 if (lcs_opt = no) return; 146 147 $ else, start statistics by writing out lengths of blocks 148 $ for this routine. 149 textl(currsubname) $ write routine name. 151 152 len = 0; $ clear acumulation. 153 tabl(30) intl(mb_len mba(bl_const)) 154 len = len + mb_len mba(bl_const); 155 tabl(40) intl(mb_len mba(bl_base)); 156 len = len + mb_len mba(bl_base); 157 tabl(50) intl(codethis); 158 len = len + codethis; 159 tabl(60) intl(mb_len mba(bl_local)); 160 len = len + mb_len mba(bl_local); 161 tabl(70) intl(mb_len mba(bl_temp)) 162 len = len + mb_len mba(bl_temp); 163 164 $ write out total module length. 165 tabl(90) intl(len) 166 totlength = totlength + len; $ add to total length. 167 168 len = 0; $ clear cumulative global length. 169 do i = bl_global to mbaptr; 170 if mb_def mba(i) then $ if defined here, add in length. 171 len = len + mb_len mba(i); $ add to total. 172 totglobs = totglobs + mb_len mba(i); 173 totns = totns + 1; $ count number of namesets. 174 end if; 175 end do; 176 177 tabl(100) intl(len) endl 178 179 $ reset variables to indicate which routine so far has 180 $ used the most table space. 181 if pdlistp > loadpd then $ this routine used most in -pdlist- 182 loadpd = pdlistp; loadrpd = currsubname; 183 end if; 184 185 186 187 188 189 if labluse > loadlab then 190 loadlab = labluse; loadrlab = currsubname; 191 end if; 192 193 if valptr > loadval then 194 loadval = valptr; loadrval = currsubname; 195 end if; 196 197 end subr endsubr; 1 .=member outdata 2 subr outdata(var); $ this routine process data statements. 3 $ this routine is called by -endsubr- to process any data 4 $ statements on the chain of -var-. 5 size var(ps); $ variable to process. 6 size dim(ps); $ dimension of variable. 7 size curind(ps); $ current index of variable. 8 size datvoa(ps); $ -voa- pointer to data statement. 9 size wlen(ps); $ word length of variable. 10 size i(ps), j(ps), k(ps); $ temporaries. 11 size len(ps); $ length of data item. dsw 22 size nlen(ps); $ name length 12 size rep(ps); $ repetition factor. 13 size vp(ps); $ -voa- pointer to data value. 14 size vmadr(mps); $ variable address. 15 16 $ first, set values for this variable. 17 curind = 1; $ initially at first element. 18 dim = vv_dimn voa(var); $ set dimension. 19 if (dim = 0) dim = 1; $ reset if not array. 20 wlen = (vv_syze voa(var) + (mws-1))/mws; $ set word length. 21 vmadr = vv_madr voa(var) - wlen; 22 ddblk = vv_mblk voa(var); 23 24 $ process all data statements on chain for this variable. 25 .-vvfrs datvoa = vv_frsdata voa(var); $ get first entry index. 26 .+vvfrs datvoa = vvfrsdata(var); $ get first entry index. 27 28 .s. 9, 2, ocs = 'dw'; $ set declaritive op. dsw 23 nlen = .len. mblkname(ddblk); dsw 24 put ocsfile, column(17) :mblkname(ddblk),a ,'+'; 30 31 while datvoa; $ loop while more remain. 32 $ check if this is an overlapping index. 33 if vv_inp1 voa(datvoa) < curind then $ it is. 34 error('data indices overlap', var) 35 quit while; 36 end if; 37 38 curind = vv_inp1 voa(datvoa); $ set current index. 39 do i = 1 to vv_arglen voa(datvoa); $ process all elements. 40 vp = xa_voa xarg(vv_argbeg voa(datvoa)+i-1); 41 len = (vv_syze voa(vp)+(mws-1))/mws; 42 rep = xa_rep xarg(vv_argbeg voa(datvoa)+i-1); 43 44 $ check if value too long. 45 if len > wlen then $ too long. 46 error('data value too long', var) 47 quit while; 48 end if; 49 50 $ get repetition value. 51 if rep then $ repetition is used. 52 rep = val(vv_vbeg voa(rep)); $ get constant value. 53 else $ will just do once. 54 rep = 1; 55 end if; 56 57 if curind+rep>(dim+1) then $ if out of range. 58 error('data index exceeds dimension', var); 59 quit while; 60 end if; 61 62 ddoff = vmadr +(curind-1) * wlen; vaxa 385 .+t32 ddoff = ddoff * mcpw; $ set to byte address. 63 if vv_naym voa(vp) = ha_0 then $ if zeroizing. 64 put ocsfile ,column(11) ,'z' $ change op dsw 25 ,column(18+nlen) :ddoff,i, ',' $ put offset 66 :rep*wlen,i; 67 call ocsput(0, 1); $ put line, retain text. 68 curind = curind + rep; 69 cont do; 70 end if; 71 72 do j = 1 to rep; $ do once/repetition. 73 74 if wlen-len > 0 then $ if must zero initial part. 75 put ocsfile ,column(11) ,'z' $ change opcode. dsw 26 ,column(18+nlen) 77 :ddoff,i ,',' $ put offset. 78 :wlen-len,i; 79 call ocsput(0, 1); $ put line, retain text. 80 end if; 81 vaxa 386 .+t10 ddoff = ddoff + (wlen-len); vaxa 387 .+t32 ddoff = ddoff + (wlen-len) * mcpw; dsw 27 call outcon(vp, nlen); $ put constant value. 84 curind = curind + 1; vaxa 388 .+t10 ddoff = ddoff + len; vaxa 389 .+t32 ddoff = ddoff + len*mcpw; 86 end do; 87 end do; 88 89 k = datvoa; $ save one entry back. 90 datvoa = vv_inp2 voa(datvoa); $ get next data entry. 91 end while; 92 93 end subr outdata; 1 .=member outcon dsw 28 subr outcon(voaptr, bl); $ output constant initialization. 3 size voaptr(ps); $ voa item to put out. 4 size tmi(ps); $ index. 5 size tmwd(mws); $ working copy of tmcval entry. 6 size c(mcs); $ character. 7 size n(ps); $ character count. vaxa 390 .+t32 size i(ps); $ loop index. 8 size tmpos(ps); $ position in word. 9 size ddtab(mcs); dims ddtab(num_tmc); $ type table dsw 29 size bl(ps); $ length of block name vaxa 391 .+t10 data ddtab(tmc_b) = 1ro; vaxa 392 .+t32 data ddtab(tmc_b) = 1rh; 11 data ddtab(tmc_i) = 1ri; 12 data ddtab(tmc_c) = 1rc; 13 data ddtab(tmc_r) = 1rr; dsn 87 .+t32 data ddtab(tmc_s) = 1rs; dsn 88 .+t10 data ddtab(tmc_s) = 1rc; 15 16 ddlt = tmctab(vv_lextype voa(voaptr)); 17 18 call tmcons(voaptr); $ put into target machine form. 19 vaxa 393 .-hmeqtm. 20 .s. 9, 2, ocs = 'dw'; 21 .ch. 11, ocs = ddtab(ddlt); vaxa 394 .+hmeqtm. vaxa 395 .+t10 .s. 9, 3, ocs = 'dwo'; vaxa 396 .+t32 .s. 9, 3, ocs = 'dwh'; vaxa 397 ..hmeqtm 22 23 do tmi = 1 to tmcvalptr; 24 tmwd = tmcval(tmi); $ copy entry. dsw 30 put ocsfile ,column(18+bl) vaxa 398 .+t10 :ddoff+tmi-1,i ,','; vaxa 399 .+t32 :ddoff + (tmi-1)*mcpw,i ,','; vaxa 400 vaxa 401 vaxa 402 .-hmeqtm. 27 go to l(ddlt) in 1 to num_tmc; $ branch on lexical type. vaxa 403 ..hmeqtm 28 29 /l(tmc_b)/ $ bit string, put out in octal vaxa 404 .+t10 put ocsfile :tmwd,b(0,3); vaxa 405 .+t32 put ocsfile :tmwd,b(0,4); 31 go to ddcont; 32 vaxa 406 .-hmeqtm. 33 /l(tmc_i)/ $ integer 34 put ocsfile :tmwd,i; 35 go to ddcont; 36 37 /l(tmc_r)/ $ real 38 $ put out characters which are in same form 39 $ as character constant (cf. tmc_c codein tmcons). 40 vaxa 407 n = mcpw; if (tmi=1) n = mod(ddnc-1, mcpw)+1; vaxa 408 put ocsfile :tmwd,r(n); 43 go to ddcont; 44 45 /l(tmc_c)/ $ character code (r) constant. 46 n = mcpw; if (tmi=1) n = mod(ddnc-1, mcpw) + 1; vaxa 409 .+t10 tmpos = n*mcs+1; $ position at left. vaxa 410 .+t32 tmpos = 1; $ position at right. vaxa 411 .+t32 put ocsfile ,'<'; $ write out macro arg. starter. 48 put ocsfile :tmccdel,r(1); $ put delimiter. vaxa 412 .+t10. dsn 89 tmpos = mws + 1 ; dsn 90 do n = 1 to mcpw ; dsn 91 tmpos = tmpos - mcs ; dsn 92 c = .f. tmpos, mcs, tmwd ; dsn 93 if c ^= 0 dsn 94 then dsn 95 if ( c = tmccdel ) put ocsfile :tmccdel,r(1) ; dsn 96 put ocsfile :tmccdel,r(1) :c,r(1) :tmccdel,r(1) ; dsn 97 end if ; dsn 98 if ( n ^= mcpw ) put ocsfile ,',' ; dsn 99 end do ; vaxa 413 ..t10 vaxa 414 .+t32. vaxa 415 i = n; $ save number of characters in word. vaxa 416 until n = 0; $ until hit left end. vaxa 417 n = n - 1; $ decrement count. vaxa 418 c = .f. tmpos, mcs, tmwd; $ get a character. vaxa 419 if c = tmccdel then $ this is delimiter. vaxa 420 put ocsfile :c,r(1) ,'/' :c,r(1) ,'/' :c,r(1); vaxa 421 elseif c = 1r< then $ handle special character. vaxa 422 put ocsfile :tmccdel,r(1) ,'<60>' :tmccdel,r(1); vaxa 423 elseif c = 1r> then $ handle special character. vaxa 424 put ocsfile :tmccdel,r(1) ,'<62>' :tmccdel,r(1); vaxa 425 else $ normal character. vaxa 426 put ocsfile :c,r(1); vaxa 427 end if; vaxa 428 vaxa 429 vaxa 430 tmpos = tmpos + mcs; $ step to next character. vaxa 431 end until; vaxa 432 vaxa 433 vaxa 434 if i ^= mcpw then $ must insert zeros. vaxa 435 do n = 1 to mcpw-i; $ mcpw-i times. vaxa 436 put ocsfile :tmccdel,r(1) ,'<0>' vaxa 437 :tmccdel,r(1); vaxa 438 end do; vaxa 439 end if; vaxa 440 vaxa 441 vaxa 442 put ocsfile ,'>'; $ close macro delimiter. vaxa 443 vaxa 444 vaxa 445 ..t32 vaxa 446 vaxa 447 55 put ocsfile :tmccdel,r(1); $ put delimiter. 56 go to ddcont; 57 58 /l(tmc_s)/ $ character string. 59 if tmi=tmcvalptr then $ put last word as octal. vaxa 448 .+t10 .ch. 11, ocs = 1ro; go to l(tmc_b); vaxa 449 .+t32 .ch. 11, ocs = 1rh; go to l(tmc_b); 61 end if; 62 n = mcpw; if (tmi=tmcvalptr-1) n=mod(ddnc,mcpw); 63 if (n=0) n = mcpw; vaxa 450 .+t32 put ocsfile ,'<'; $ write out argument start. 64 put ocsfile :tmcsdel,r(1); $ put delimiter. vaxa 451 .+t10. 65 tmpos = mws+1; $ start at leftmost position. 66 until n = 0; $ until all characters are processed. 67 n = n - 1; $ count the character. 68 tmpos = tmpos - mcs; $ allow for the character. 69 c = .f. tmpos, mcs, tmwd; $ get character. 70 put ocsfile :c,r(1); $ put character. 71 if (c=tmcsdel) put ocsfile :c,r(1); $ if delimiter. 72 end until; vaxa 452 ..t10 vaxa 453 .+t32. vaxa 454 if (n ^= mcpw) put ocsfile :4r ,r(mcpw-n); $ fill. vaxa 455 tmpos = 1 + (mcpw-n) * mcs; $ start at right. vaxa 456 until tmpos = mws+1; $ until at end of word. vaxa 457 c = .f. tmpos, mcs, tmwd; $ get character. vaxa 458 if c = 1r< then $ special case. vaxa 459 put ocsfile :tmcsdel,r(1) ,'<60>' :tmcsdel,r(1); vaxa 460 elseif c = 1r> then $ another special case. vaxa 461 put ocsfile :tmcsdel,r(1) ,'<62>' :tmcsdel,r(1); vaxa 462 else $ normal character. vaxa 463 if (c = tmcsdel) $ if delimiter. vaxa 464 put ocsfile :c,r(1) ,'/' :c,r(1) ,'/'; vaxa 465 put ocsfile :c,r(1); $ write out character. vaxa 466 end if; vaxa 467 vaxa 468 vaxa 469 tmpos = tmpos + mcs; $ step to next position. vaxa 470 end until; vaxa 471 vaxa 472 vaxa 473 put ocsfile :tmccdel,r(1); vaxa 474 put ocsfile ,'>'; $ write argument terminator. vaxa 475 vaxa 476 vaxa 477 $ now write out cleanly. vaxa 478 i = filestat(ocsfile,column); vaxa 479 put ocsfile ,x(57-i) ,'; ' :tmccdel,r(1); vaxa 480 do i = 1 to n; $ for each character. vaxa 481 put ocsfile :(.f. mws+1 - i*mcs, mcs, tmwd),r(1); vaxa 482 end do; vaxa 483 ..t32 vaxa 484 vaxa 485 73 put ocsfile :tmcsdel,r(1); $ put delimiter. 74 go to ddcont; vaxa 486 ..hmeqtm 75 76 /ddcont/ $ write out line 77 call ocsput(0, 1); $ retain 1-16. 78 end do; 79 80 end subr outcon; 1 .=member tmcons 2 subr tmcons(voaptr); $ convert target machine constant. 3 $ given voa index -voaptr- of constant, convert as needed 4 $ so that tmcval(1) to tmcval(tmcvalptr) contains constant 5 $ in correct form for target machine. 6 $ for resident compiler, this requires just copying over 7 $ the contents of val array. for bootstrap, conversion 8 $ depends on host machine structure, as val entries passed 9 $ in form appropriate to host machine. 10 size c(cs); $ character temporary 11 size hmpos(ps); $ host machine word position. 12 size hmptr(ps); $ host machine word pointer 13 size hmwd(ws); $ temporary word value. 14 size i(ps); $ loop index. 15 size nc(ps); $ number of characters. 16 size nrem(ps); $ remaining characters. 17 size mbs(szmax-1); $ bit string to build target form. 18 size sz(ps); $ result size. 19 size vl(ps); $ vv_vlen value. 20 size vb(ps); $ vv_vbeg value. 21 size vp(ps); $ val pointer 22 size voaptr(ps); $ voa index 23 24 vp = vv_vbeg voa(voaptr); $ get starting point in val. 25 vl = vv_vlen voa(voaptr); $ get number of words in val. 26 sz = vv_syze voa(voaptr); $ get size. 27 tmcvalptr = (sz+mws-1) / mws; $ get target machine words. 28 ddlt = tmctab(vv_lextype voa(voaptr)); $ save lexical type. 29 ddnc = ha_nchars ha(vv_naym voa(voaptr)); vaxa 487 .+hmeqtm. $ if host = target, just copy into tmcval. 31 do i = 1 to vl; tmcval(i) = val(vp+i-1); end do; 32 if (vl ^= tmcvalptr) call aermey(38); $ error. 33 return; vaxa 488 ..hmeqtm 35 .+s66. $ on different host machine, reconvert. 36 $ if result multiword on target, clear required 37 $ part of mbs. 38 do i = 1 to (sz+ws-1)/ws+1; 39 .f. (i-1)*ws+1, ws, mbs = 0; 40 end do; 41 go to l(ddlt) in 1 to num_tmc; 42 43 /l(tmc_i)/ $ integer, single word, so no conversion. 44 tmcval(tmcvalptr) = val(vp); $ no conversion 45 if (sz > mws) call aermey(38); $ if too long. 46 go to ret; 47 48 /l(tmc_b)/ $ bit, must format appropriate number to word. 49 if sz <= mws then $ if conversion not needed. 50 tmcval(tmcvalptr) = val(vp); 51 go to ret; 52 end if; 53 $ here to convert val packed hws bits to entry to 54 $ target form. 55 do i = 1 to vl; 56 .f. (vl-i)*ws+1, ws, mbs = val(vp+i-1); 57 end do; 58 go to retlong; 59 /l(tmc_c)/ $ character code constant. 60 $ host has passed characters left aligned, with blank 61 $ fill. 62 nc = ha_nchars ha(vv_naym voa(voaptr)); 63 if (nc=0) call aermey(39); 64 hmpos = ws+1; hmptr = vp; hmwd = val(hmptr); 65 do i = 1 to nc; 66 hmpos = hmpos - cs; 67 c = .f. hmpos, cs, hmwd; vaxa 489 .e. (nc-i)*mcs + 1, mcs, mbs = c; 69 if hmpos = 1 then $ if need new word. 70 hmpos = ws+1; 71 hmptr = hmptr + 1; 72 hmwd = val(hmptr); 73 end if; 74 end do; 75 go to retlong; 76 77 /l(tmc_r)/ $ real constant. 78 $ convert in same way as for character constants. 79 $ since real constants not 'safe' for bootstrap, 80 $ val will just contain characters of constant. 81 82 go to l(tmc_c); 83 84 /l(tmc_s)/ $ character string. 85 nc = ha_nchars ha(vv_naym voa(voaptr)); 86 if nc = 0 then $ if null string 87 tmcval(1) = 0; go to ret; $ null string is zero. 88 go to ret; 89 end if; 90 $ characters are packed in val, left aligned with 91 $ blank fill. 92 nc = ha_nchars ha(vv_naym voa(voaptr)); vaxa 490 vaxa 491 vaxa 492 hmpos = ws+1; hmptr = vp; hmwd = val(hmptr); $ set up for start. vaxa 493 do i = 1 to nc; $ process each character. vaxa 494 hmpos = hmpos - cs; $ step to next character. vaxa 495 c = .f. hmpos, cs, hmwd; $ get a character. vaxa 496 .e. sz+1 - i*mcs, mcs, mbs = c; $ insert character. vaxa 497 if hmpos = 1 then $ if need new word. vaxa 498 hmpos = ws+1; $ reset. vaxa 499 hmptr = hmptr + 1; hmwd = val(hmptr); $ get next word. vaxa 500 end if; vaxa 501 end do; vaxa 502 vaxa 503 102 $ fill in string origin, length field. vaxa 504 .f. 1, msl, mbs = nc; $ set length. vaxa 505 .f. msl+1, mso, mbs = sz+1; $ origin. 105 go to retlong; 106 107 /retlong/ $ here to pack mbs to tmcval. 108 do i = 1 to tmcvalptr; 109 tmcval(i) = .e. (tmcvalptr-i)*mws+1, mws, mbs; 110 end do; 111 ..s66 112 /ret/ 113 end subr tmcons; 1 .=member emopr 2 subr emopr(op, oreg, imode, ireg, ioff); $ emit machine instr. 3 $ emit machine instruction for m op -op-. oreg is accumulator 4 $ and imode, ireg and ioff represent effect address. 5 6 size op(ps); $ mop 7 size oreg(ps); $ result accumulator 8 size imode(ps); $ input address mode. 9 size ireg(ps); $ input machine register. 10 size ioff(mosize); $ input block, offset. 11 size regname(.sds. 3); dims regname(16); 12 size blk(ps); $ block of address. 13 size off(mps); $ offset of address. 14 size ic(cs); $ immediate code. 15 size ostr(.sds. namelen); $ for output description. 16 size nx(ps); $ space count. dsu 136 size mvop(1); $ set if mvw or mvx op 17 18 codethis = codethis + moaiwc(op); $ add length of instr. 19 .s. 9, 3, ocs = moptab(op); pic 14 .+t32v pic 15 pic_case=no; pic 16 if (op=mo_lda ! op=mo_ldw ! op=mo_stw ) pic 17 & (imode=am_rel ! imode=am_reli) & pic 18 (mbo_blk ioff > bl_imm) then pic 19 pic_case=yes; pic 20 pic_char = .ch. 10, ocs; pic 21 .ch. 10, ocs = 1rx; pic 22 end if; pic 23 ..t32v 20 dsu 137 mvop = (op=mo_mvw) ! (op=mo_mvx); vaxa 506 .+t10. 21 $ if op admits immediate mode and operand is immediate, 22 $ append i to opcode. 23 if mbo_blk ioff = bl_imm then $ if immediate block. 24 if (moaimm(op) = no) call aermey(40); $ ***assign number*** 25 put ocsfile ,column(12) ,'i'; 26 end if; vaxa 507 ..t10 27 28 put ocsfile ,column(17); 29 call emitea(am_reg, oreg, 0); 30 put ocsfile ,','; 31 ostr = strname; dsu 138 .+t32h. dsu 139 if mvop ! op=mo_lpr ! op=mo_spr ! op=mo_bnb dsu 140 ! op=mo_bfb then dsu 141 if nsheap_this then dsu 142 nsheap_byte = yes; dsu 143 end if; dsu 144 end if; dsu 145 ..t32h 32 call emitea(imode, ireg, ioff); dsu 146 .+t32h nsheap_byte = no; 33 34 $ now put out any additional operands needed for specific ops. vaxa 508 .+t10. dsu 147 if op = mo_lpr ! op = mo_spr ! mvop then 36 put ocsfile ,',' :emopparm1,i; $ write parm. 1. 37 dsu 148 if mvop=0 then $ there is a second parm. 39 put ocsfile ,',' :emopparm2,i; $ write second. 40 end if; 41 end if; vaxa 509 ..t10 vaxa 510 .+t32. vaxa 511 size mode(ps), reg(ps), moff(mosize); dsu 149 if mvop then $ if word move. dsq 117 put ocsfile ,',' ,tmcslit dsq 118 :emopparm1,i; $ write out extra operand. vaxa 514 vaxa 515 vaxa 516 elseif op = mo_lpr ! op = mo_spr then $ field operation. vaxa 517 put ocsfile ,','; $ write a comma. vaxa 518 getdesc(emopparm1, gd_use, mode, reg, moff); $ get first bit dsu 150 .+t32h nsheap_byte = yes; vaxa 519 call emitea(mode, reg, moff); $ write the ea. dsu 151 .+t32h nsheap_byte = no; vaxa 520 getdesc(emopparm2, gd_use, mode, reg, moff); $ get length. vaxa 521 put ocsfile ,','; $ write a comma. dsu 152 .+t32h nsheap_byte = yes; vaxa 522 call emitea(mode, reg, moff); $ write the ea. dsu 153 .+t32h nsheap_byte = no; vaxa 523 end if; vaxa 524 ..t32 42 43 if slen strname ^= 0 ! slen ostr ^= 0 then 44 nx = 17 - mod(filestat(ocsfile,column), 8); 45 $ [ds 31 may separate nx reflects gen bug in nested 46 $ filestat handling.] dsq 119 put ocsfile ,x(nx) ,tmcscom; 48 if (slen ostr) put ocsfile :ostr,a; 49 if slen strname then 50 if (slen ostr) put ocsfile ,','; 51 put ocsfile :strname,a; 52 end if; 53 end if; 54 pic 24 .+t32v pic_case=no; 55 call ocsput(0, 0); $ put line. vaxa 525 vaxa 526 vaxa 527 .+t32. vaxa 528 if op = mo_lpr ! op = mo_spr then $ field operations. vaxa 529 drop(emopparm1); drop(emopparm2); $ drop parameters. vaxa 530 end if; vaxa 531 ..t32 vaxa 532 vaxa 533 56 end subr emopr; 1 .=member emitea 2 subr emitea(mode, reg, ioff); $ put out ea. 3 $ emit t10 code for operand. 4 size mode(ps); $ operand mode. 5 size reg(ps); $ machine register 6 size ioff(mosize); $ operand block, offset 7 size blk(ps), off(mps); $ block, offset. 8 size i(ps); $ temporary. vaxa 534 size sign(cs); $ sign character (1r+ or 1r-). 9 10 $ free output register. 11 rl_hold reglis(reg) = no; $ no longer on hold. 12 reguseval = reguseval + 1; $ increment usage count. 13 rl_usevalue reglis(reg) = reguseval; $ save lru value. vaxa 535 .+t32 .f. reg, 1, regmask = yes; $ show register used. 14 15 .len. strname = 0; $ clear name string. 16 i = rl_content reglis(reg); $ assume data. 17 if (rl_subtype reglis(reg) = rt_address 18 ! rl_subtype reglis(reg) = rt_liveaddr) 19 & (i^=0) then 20 i = dw_freg dword(di_lword ditem(i)); 21 end if; 22 23 if reg ^= sparereg & i^=0 then $ if not empty. 24 if isvar(i) then $ if variable. 25 sdlname(strname, (vv_naym voa(di_chain 26 ditem(dr_item dreg(i))))); $ get name. 27 end if; 28 end if; 29 30 blk = mbo_blk ioff; off = mbo_off ioff; $ get block, offset. eaa 208 .+t20. eaa 209 if nsheap_this & (blk=nsheap_blk) then $ if need to redirect. eaa 210 call emitex(mode, reg, off, blk); eaa 211 return; eaa 212 end if; eaa 213 ..t20 dsu 154 .+t32h. dsv 11$ only redirect if offset>0, i.e., keep refs to heap_adr as is dsva 1 if nsheap_this & (blk=nsheap_blk) & .not.(mode=am_mem & off=0) dsva 2 then call emiteh(mode, reg, off, blk); dsu 157 return; dsu 158 end if; dsu 159 ..t32h 31 $ dispose of am_reg case. 32 if mode=am_reg then 33 put ocsfile ,'r' :reg-1,i; 34 return; end if; 35 if mode=am_reli then $ if indirect. dsq 120 put ocsfile ,tmcsind; end if; 37 $ identify block unless immediate or absolute. vaxa 536 .+t10 if blk>bl_imm then $ if need to identify. vaxa 537 .+t32 if blk>=bl_imm then $ if need to identify. dsq 121 .+t32. pic 25 .+t32u. pic 26 if (mode=am_rel & blk>bl_imm) put ocsfile ,'l' :tmccgra,r(1); pic 27 ..t32u pic 28 .+t32v. pic 29 $ pic form pic 30 if blk>bl_imm then put ocsfile ,'g^'; end if; pic 31 ..t32v dsq 125 ; dsq 126 ..t32 39 put ocsfile :mblkname(blk),a; 40 end if; 41 $ indicate offset, as negative if sign bit set. vaxa 539 vaxa 540 vaxa 541 if .f. mps, 1, off then $ if negative. vaxa 542 off = mneg(off); sign = 1r-; $ set negative. vaxa 543 else $ positive. vaxa 544 sign = 1r+; $ show positive. vaxa 545 end if; vaxa 546 vaxa 547 vaxa 548 .+t32. vaxa 549 if (blk ^= bl_imm) off = off * mcpw; $ set to byte value. vaxa 550 if mode = am_mem ! off ^= 0 then vaxa 551 ..t32 vaxa 552 put ocsfile :sign,r(1) :off,i; $ write out offset. vaxa 553 .+t32 end if; 45 $ write index register if appropriate. 46 if mode=am_rel ! mode=am_reli then vxaa 1 .+t10 put ocsfile ,'(r' :reg-1,i ,')'; vaxa 555 .+t32. pic 32 .+t32u. vaxa 556 if reg = parmreg vaxa 557 then put ocsfile ,'(ap)'; vaxa 558 else put ocsfile ,'(r' :reg-1,i ,')'; end if; pic 33 ..t32u pic 34 .+t32v. pic 35 if reg=parmreg then put ocsfile ,'(ap)'; pic 36 elseif blk>bl_imm then $ if need pic form then pic 37 put ocsfile ,'[r' :reg-1,i ,']'; pic 38 else put ocsfile ,'(r' :reg-1,i ,')'; pic 39 end if; pic 40 ..t32v vaxa 559 ..t32 48 end if; 49 if mode=am_mem then 50 if (reg^=sparereg) call aermey(33); end if; 51 end subr emitea; dsu 160 .+t32h. dsu 161 subr emiteh(mode, reg, off, blk); $ put out ea. dsu 162 $ emit t10 code for operand. dsu 163 size mode(ps); $ operand mode. dsu 164 size hreg(ws); $ reg if dynamic address dsu 165 size reg(ps); $ machine register dsu 166 size blk(ps), off(mps); $ block, offset. dsu 167 size i(ps); $ temporary. dsu 168 size sign(cs); $ sign character (1r+ or 1r-). dsu 169 pic 41 .+t32v. pic 42 if pic_case then $ no need pic fix for heap refs pic 43 .ch. 10, ocs = pic_char; pic 44 end if; pic 45 ..t32v dsu 170 $ dispose of am_reg case. dsu 171 if mode=am_reg then dsu 172 put ocsfile ,'r' :reg-1,i; dsu 173 return; end if; dsu 174 if mode=am_reli then $ if indirect. dsu 175 put ocsfile ,tmcsind; dsu 176 end if; dsu 177 $ indicate offset, as negative if sign bit set. dsu 178 dsu 179 dsu 180 if .f. mps, 1, off then $ if negative. dsu 181 off = mneg(off); sign = 1r-; $ set negative. dsu 182 else $ positive. dsu 183 sign = 1r+; $ show positive. dsu 184 end if; dsu 185 dsu 186 if (blk ^= bl_imm) off = off * mcpw; $ convert to bytes dsu 187 dsu 188 $ write index register if appropriate. dsu 189 if mode=am_rel ! mode=am_reli then dsu 190 if off ^= 0 then dsu 191 put ocsfile :sign,r(1) :off,i; $ write out offset. dsu 192 end if; dsu 193 if reg = parmreg dsu 194 then put ocsfile ,'(ap)'; dsu 195 else put ocsfile ,'(r' :reg-1,i ,')'; end if; dsu 196 else $ put out @#off[rh] dsv 13 put ocsfile ,tmcsind ,tmcslit :off,i; dsu 198 if sign^=1r+ then call aermey(99); end if; dsu 199 end if; dsu 200 dsu 201 if nsheap_byte then hreg = nsheapreg_b; dsu 202 else hreg = nsheapreg_w; end if; dsu 203 put ocsfile ,'[r' :hreg-1,i ,']'; $ add indexing dsu 204 if mode=am_mem then dsu 205 if (reg^=sparereg) call aermey(33); dsu 206 end if; dsu 207 dsu 208 end subr emiteh; dsu 209 ..t32h eaa 214 .+t20. eaa 215 subr emitex(mode, reg, off, blk); $ put out ea. eaa 216 $ emit t20 code for operand. eaa 217 size mode(ps); $ operand mode. eaa 218 size hreg(ws); $ reg if dynamic address eaa 219 size reg(ps); $ machine register eaa 220 size blk(ps), off(mps); $ block, offset. eaa 221 size i(ps); $ temporary. eaa 222 size sign(cs); $ sign character (1r+ or 1r-). eaa 223 eaa 224 $ dispose of am_reg case. eaa 225 if mode=am_reg then eaa 226 put ocsfile ,'r' :reg-1,i; eaa 227 return; end if; eaa 228 if mode=am_reli then $ if indirect. eaa 229 call aermey(1); $ cannot have indirection here!!! eaa 230 put ocsfile ,tmcsind; eaa 231 end if; eaa 232 $ write operand as @[heaporg + offset +register_specification] eaa 233 put ocsfile ,'@[efiw ' :nsheap_org,a; eaa 234 $ indicate offset, as negative if sign bit set. eaa 235 eaa 236 eaa 237 if .f. mps, 1, off then $ if negative. eaa 238 off = mneg(off); sign = 1r-; $ set negative. eaa 239 else $ positive. eaa 240 sign = 1r+; $ show positive. eaa 241 end if; eaa 242 eaa 243 eaa 244 put ocsfile :sign,r(1) :off,i; $ write out offset. eaa 245 $ write index register if appropriate. eaa 246 if mode=am_rel ! mode=am_reli then eaa 247 put ocsfile ,',' :reg-1,i ,']'; eaa 248 else put ocsfile ,',0]'; eaa 249 end if; eaa 250 eaa 251 if mode=am_mem then eaa 252 if (reg^=sparereg) call aermey(33); eaa 253 end if; eaa 254 end subr emitex; eaa 255 ..t20 1 .=member ocsput 2 subr ocsput(la, c); $ put code line. 3 size la(ps); $ length argument. 4 size l(ps); $ length. 5 size c(ps); $ action code. dsq 128 .+hmeqtm. dsq 129 size s(.sds. 80); $ copy of code string dsq 130 ..hmeqtm 6 $ c=0 to clear 1-16 after write. 7 $ c=1 to retain 1-16 after write. 8 $ c=2 to clear 1-16, no write. 9 10 if c = 2 then $ if clear only wanted. 11 .s. 1, 16, ocs = ''; 12 return; 13 end if; 14 l = la; if (l=0) l = filestat(ocsfile,column)-1; dsq 131 .-hmeqtm. 15 put codefile :ocs,a(l) ,skip; $ put to codefile. dsr 15 ..hmeqtm 16 if (trace_c) put :ocs,a(l) ,skip; $ put trace to print file. dsq 133 .+hmeqtm. dsq 134 $ here to try to generate tabs. dsq 135 $ cannot alter ocs, so work with copy in s. dsq 136 dsq 137 s = ocs; .len. s = l; dsq 138 if l>8 then $ try to map initial blanks to tabs dsq 139 if .s. 1, 8, s .seq. (''.pad.8) then dsq 140 .ch. 1, s = tmcctab; $ insert tab dsq 141 .s. 2, l-8, s = .s. 9, l-8, s; dsq 142 l = l - 7; dsq 143 .len. s = l; dsq 144 $ now try to put tab in operator field dsq 145 if l > 9 then dsq 146 if .s. 5, 5, s .seq. (''.pad.5) then dsq 147 .ch. 5, s = tmcctab; dsq 148 .s. 6, l-9, s = .s. 10, l-9, s; dsq 149 l = l - 4; $ adjust length. dsq 150 .len. s = l; dsq 151 end if; dsq 152 end if; dsq 153 end if; dsq 154 end if; dsq 155 put codefile :s,a(l) ,skip; $ put to codefile. dsq 156 ..hmeqtm 17 if (c = 0) .s. 1, 16, ocs = ''; 18 end subr ocsput; 1 .=member basprb 2 subr baseprober(ctyp, optr, ihcode, p1, p2, arrayp, array); 3 $ this routine is called by the various -baseprobe- macros 4 $ to insert items into the hased base block. -ctyp- is the 5 $ call type and determines some of the actions. 6 size ctyp(ps); $ calling type. 7 size optr(ps); $ the output pointer. 8 size ihcode(mws/2+7); $ the given hash code. 9 size p1(ps); $ one descriptive parameter. 10 size p2(ps); $ the second parameter. 11 size arrayp(ps); $ array pointer to data. 12 size array(ps); $ index value representing array. 13 size hcode(23); $ computed hash code to use. 14 size ptr(ps); $ base block pointer. 15 size type(ps); $ entry type. 16 size len(ps); $ entry length. 17 size i(ps), j(ps); $ temporaries. 18 size vptr(ps); $ desired data pointer. 19 size baseent(baseblocksz); $ temporary entry. 20 21 $ first must set the values for this probe based on 22 $ the calling type. 23 if ctyp = rp_addlab then $ label call. 24 type = bt_label; $ set type. 25 len = 1; $ labels are one word long. 26 vptr = p2; $ data pointer is label index. 27 hcode = p2; $ hashcode is initially label index. 28 elseif ctyp=rp_nocomp then 29 len = p1; type = p2; 30 vptr = arrayp; $ data pointer is array pointer. 31 hcode = vptr; $ initial hash code is pointer. 32 else $ this is normal call. 33 len = p1; type = p2; $ get length, type. 34 vptr = arrayp; $ set data pointer to array pointer. 35 hcode = ihcode; $ use caller's hash code. 36 end if; 37 38 $ complete hash code with type and length. 39 .f. mws/2+1, 3, hcode = type; $ insert type. 40 .f. mws/2+4, 3, hcode = len; $ insert length. 41 42 $ compute initial place to try in base block. 43 ptr = mod(hcode, baseblockprime); $ compute initial probe. 44 if (ptr = 0) ptr = baseblockprime - 2; $ set for bad value. 45 46 $ enter a loop which will be exited when a free entry 47 $ is found. 48 until yes; $ will exit when found entry. 49 $ if the first one is free, quit now. 50 if (bb_type baseblock(ptr) = 0) quit until; 51 52 $ scan and see if the desired entry is already in the 53 $ base block. 54 while yes; $ will quit when end of chain found. 55 $ must compare each entry. quit this next 56 $ loop if the entries do not match. 57 until yes; $ quit if no match. 58 $ in the case of the -addlab- call, will 59 $ just say that they dont compare. 60 if (ctyp = rp_addlab) quit until; 61 62 $ check types. 63 if (bb_type baseblock(ptr) ^= type) quit until; 64 65 $ next check lengths. vaxa 560 .+t10 if (bb_nwords baseblock(ptr) < len) quit until; vaxa 561 .+t32 if (bb_nwords baseblock(ptr) ^= len) quit until; 67 68 $ if the pointers compare, the items are the 69 $ same. so return this pointer. 70 if bb_pointer baseblock(ptr) = vptr then $ found. 71 optr = ptr; return; $ set return value. 72 end if; vaxa 562 vaxa 563 73 if (ctyp ^= rp_normal) quit until; 74 75 $ finally, check every word in the data. vaxa 564 .+t32 if len then $ if there is a list. 76 do i = 0 to len-1; $ check every entry. 77 $ do the array comparison that is needed. 78 j = bb_pointer baseblock(ptr)+i; $ get one value. 79 if array = ar_val then $ compare const array. 80 if (val(vptr+i) ^= val(j)) quit until; 81 else $ parm. lists. 82 if (pdlist(vptr+i) ^= pdlist(j)) quit until; 83 end if; 84 end do; vaxa 565 .+t32 end if; 85 86 $ found a matching entry at a different 87 $ location. therefore, the entry in the array 88 $ that is pointed to is redundant. so if the 89 $ pointer is set to the last used value, can 90 $ update the last used value. 91 if (vptr = rparrmx - (len-1)) rparrmx = vptr - 1; 92 93 $ return pointer. 94 optr = ptr; return; 95 end until; 96 97 $ this entry is not the one wanted. see if more in 98 $ clash chain. 99 if (bb_link baseblock(ptr) = 0) quit while; $ no more. 100 ptr = bb_link baseblock(ptr); $ else get pointer. 101 end while; 102 103 $ must look for a free entry from the top of the array. 104 do i = baseblockfree to 1 by -1; $ scan down. 105 if (bb_type baseblock(i)) cont do; $ not free. 106 baseblockfree = i-1; $ update free pointer. 107 bb_link baseblock(ptr) = i; $ add to clash chain. 108 ptr = i; $ point to entry. 109 quit until; $ show found entry. 110 end do; 111 112 $ else, base block is full. 113 call aermey(26); $ this is a fatal error. 114 end until; 115 116 $ finally, build entry. 117 optr = ptr; $ set return value. 118 119 baseent = 0; $ set entry to null. 120 bb_type baseent = type; $ set type. 121 bb_nwords baseent = len; $ set length. 122 bb_pointer baseent = vptr; $ set data pointer. 123 124 baseblock(ptr) = baseent; $ place in block. 125 126 $ if type is constant, will not assign address now. 127 if (type = bt_const) return; $ so just return. 128 129 $ assign address and chain to entries whose address have 130 $ been assigned. 131 bb_addr baseblock(ptr) = baselastaddr; $ set address. 132 if baselast then $ this is not first in chain. 133 bb_chain baseblock(baselast) = ptr; $ chain last to this. 134 else $ this is first in chain. 135 basefirst = ptr; $ show is first. 136 end if; 137 138 baselast = ptr; $ show last in chain. 139 baselastaddr = baselastaddr + len; $ increment base block address vaxa 566 .+t32 if (array = ar_plist) baselastaddr = baselastaddr + 1; 140 141 142 end subr baseprober; 1 .=member countup 2 subr countupr(name); $ process array overflow. 3 $ this routine informs the user of an array overflow 4 $ and terminates the compilation. 5 size name(.sds. namelen); $ name of array. 6 7 terml(yes) textl(error_notice) textl('array ') textl(name) 8 textl(' overflowed. compilation aborted.') endl 9 textl('assembling ') textl(currsubname) endl 10 errno = errno+1; 11 12 exitcode = 1; call asmexit; $ terminate compilation. 13 end subr countupr; 1 .=member aermey 2 subr aermey(n); $ print fatal error message. 3 $ this routine is called to print fatal error messages 4 $ and abort the compilation. 5 size n(ps); $ error message number. 6 size i(ps); $ temporary. 7 8 +* ender = go to ret; ** $ abbreviation. 9 10 terml(yes) textl(system_notice) $ write header. dse 26 if n <= 0 ! n >= 42 then $ bad number. 12 tintl('bad message number', n) ender 13 end if; 14 rka 12 go to e(n) in 1 to 41; $ print error message. 16 17 /e(1)/ tintl('invalid error number', n) ender 18 /e(2)/ textl('chaining error in label fixup') ender 19 /e(3)/ textl('format error on voa file') ender 20 /e(4)/ textl('unconverted return found') ender 21 /e(5)/ textl('invalid call to -assignr-') ender 22 /e(6)/ textl('inreg points to free item') ender 23 /e(7)/ textl('dummy item table is full') ender 24 /e(8)/ textl('dummy word table is full') ender 25 /e(9)/ textl('dummy register table is full') ender 26 /e(10)/ textl('bad temporary drop status') ender 27 /e(11)/ textl('attempt to clear address-float item') ender 28 /e(12)/ textl('attempt to clear temporary') ender 29 /e(13)/ textl('-ditem- on free chain twice') ender 30 /e(14)/ textl('-dword- on free chain twice') ender 31 /e(15)/ textl('-dreg- on free chain twice') ender 32 /e(16)/ textl('bad address value with no register') ender 33 /e(17)/ textl('bad call to -inzeror-') ender 34 /e(18)/ textl('bad call to -moveaddr-') ender 35 /e(19)/ textl('bad non-commutative operation') ender 36 /e(20)/ textl('not last word received in -emitsub-') ender 37 /e(21)/ textl('more than one word on chain') ender 38 /e(22)/ textl('no base register available') ender 39 /e(23)/ textl('not last word of arg. in -getdescr-') ender 40 /e(24)/ textl('bad unassigned address') ender 41 /e(25)/ textl('cannot get register pair') ender 42 /e(26)/ textl('base block is full') ender 43 /e(27)/ textl('disagreeing values in store of addrlive') ender 44 /e(28)/ textl('bad input to store addrlive') ender 45 /e(29)/ textl('cannot obtain space in -dops-') ender 46 /e(30)/ textl('live address present at block end') ender 47 /e(31)/ textl('improper drop status of temporaries') ender 48 /e(32)/ textl('attempt to drop permanent value') ender 49 /e(33)/ textl('reg should be sparereg') ender 50 /e(34)/ textl('unexpected gdfdreg call') ender 51 /e(35)/ textl('invalid address mode') ender 52 /e(36)/ textl('bad dopcode') ender 53 /e(37)/ textl('premature end on voa file') ender 54 /e(38)/ textl('constant conversion problem') ender 55 /e(39)/ textl('lablist overflow') ender 56 /e(40)/ textl('expect immediate mode') ender dse 27 /e(41)/ textl('-in2- not constant for idt/imt') ender 57 58 /ret/ $ common termination code. 59 endl endl $ leave some space. rke 12 terml(no); 60 61 .+trace. $ print info. describing error. dso 13 if n ^= 13 & n ^= 14 & n ^= 15 & n ^= 21 then 62 tintl(' at error dopcode', dopcode) 63 tintl('voaep', voaep) tintl('vopcode', vopcode) 64 endl tintl(' dopir', dopir) tintl('dopjr', dopjr) 65 tintl('dopkr', dopkr) tintl('dopor', dopor) 66 tintl('dopnargs', dopnargs) tintl('dopnx', dopnx) endl 67 call dumpdregs; call dumpmregs; dso 14 end if; 68 ..trace 69 70 exitcode = 1; call asmexit; $ terminate. 71 72 end subr aermey; 1 .=member asmexit 2 subr asmexit; $ code generator termination routine. 3 $ this routine terminates the code generation. it prints 4 $ statistics, closes files, and writes messages to the user. 5 size totwaste(ps); $ total wasted space. 6 7 $ first, write statistics if user wants them. 8 if lcs_opt then $ statistics wanted. 9 terml(no) $ just in case. 10 call stitlr(1, 'statistics for this code generation.'); 11 ejectlp(13) endl $ start at new page if near end. 12 13 $ write out length statistics. 14 15 if totprocs>1 then $ if several procs, give total length. 16 intl(totprocs) textl(' procedures, estimate ') 17 intlp(totlength, 6) textl(' words.') endl 18 end if; 19 20 if totns>1 then $ if several namesets, give total length. 21 intl(totns) textl(' namesets with ') 22 intlp(totglobs, 6) textl(' words.') endl 23 end if; 24 25 endl 26 27 textl('compiler array usage') endl 28 textl('array name') tabl(19) 29 textl('length') tabl(30) 30 textl(' used ') tabl(39) 31 textl('unused') tabl(50) 32 textl('procedure') endl 33 34 +* arastat(lib, max, tot, rout, sz) = $ print line. 35 textl(lib) tabl(20) 36 intl(max) tabl(30) 37 intl(tot) tabl(40) 38 intl(max-tot) tabl(50) 39 textl(rout) endl 40 totwaste = totwaste + (max-tot); 41 ** 42 43 totwaste = 0; $ show nothing wasted yet. 44 arastat('pdlist', pdlistdim, loadpd, loadrpd, 1); 45 46 arastat('lablist',lablistdim,loadlab,loadrlab,lablistsz/ws); 47 arastat('val', valdim, loadval, loadrval, 1); 48 tabl(20) textl('unused array words') 49 tabl(40) intl(totwaste) 50 endl dst 97 .+enp. dst 98 if enpopt then $ report if unmatched procedures dst 99 tintl('enptot',enptot) tintl(' enporg',enporg) endl dst 100 if enpnotfound then dst 101 textl('enp procs not found ') intl(enpnotfound) dst 102 endl dst 103 end if; dst 104 end if; dst 105 ..enp 51 endl endl macdrop(arastat) 52 end if; 53 54 $ write out number of errors. 55 terml(yes) $ want this on terminal file. 56 if errno then $ there were errors. 57 intl(errno) textl(' detected errors.') endl 58 $ s37 setcc code to set condition code dropped. 59 $ check if s10 has any equivalent of s37 cnndition code. 62 end if; 63 64 $ close any open files. 65 file voafile access=release; 66 dsp 45 .+t10. dsp 46 $ if -end- option selected, see if want special last line dsp 47 if end_opt .seq. 'prg' then $ if want end of program. dsp 48 put ocsfile ,column(9) ,'extern z$strt'; dsp 49 call ocsput(0, 0); dsp 50 put ocsfile ,column(9) ,'end z$strt'; dsp 51 call ocsput(0, 0); dsp 52 elseif end_opt .seq. 'seg' then $ if want end of segment. dsp 53 put ocsfile ,column(9) ,'end'; dsp 54 call ocsput(0, 0); dsp 55 elseif end_opt .sne. '0' then $ if want endnam dsp 56 put ocsfile ,column(9), 'end' :end_opt,a; dsp 57 call ocsput(0, 0); dsp 58 end if; dsp 59 ..t10 dsp 60 67 $ process possible abnormal termination. 68 if exitcode then $ this is abnormal. 69 textl(error_notice) textl('abnormal termination.') endl 70 call ltlxtr; terml(no); call clsterm; call ltlfin(1,1); 71 end if; 72 73 terml(no); call clsterm; $ else just close terminal file. dsi 10 call ltlterm(3, 0); $ terminate normally. 75 76 end subr asmexit; 1 .=member note 2 .+docnote. 3 report on initial work on little compiler for dec-10 4 5 richard kenner 6 david shields 7 8 2 june 1978 9 10 the goal of this project is to produce a resident little compiler 11 for the digital equipment corporation decsystem-10 (dec-10). 12 work began last summer during a visit to nyu by anthony p. mccann 13 of the university of leeds. it was decided to base the code 14 generator on that written by kenner for the ibm system/370 (s37). 15 initial work consisted largely of taking the 370-dependent parts 16 of the asm code out of the s37 asm, while retaining underlying 17 machine-independent code genertion machinery. 18 19 shields visited mccann at leeds in early april 1978. the design 20 was reviewed, as well as structure of operating system interface. 21 nigel chapman, a graduate student at leeds, also joined the 22 project at that time. 23 24 it was agreed that the bootstrap compiler would produce source code 25 for a made-up machine called t10 (t stands for target) in order to 26 simplify bootstrap onto the dec-10. t10 admits a straightforward 27 translation to dec-10 assembler (which is called macro-10). 28 29 the bootstrap asm has been used to translate the little library, 30 as well as the utility programs ltldoc and ltlpad (a copy of 31 ltldoc may be found in the guide to the little language). a 32 correct assembly of ltldoc was obtained at the dec-10 at bbn in 33 boston, although it was not possible to run the code as the 34 operating system interface for dec-10 is not yet available. 35 36 kenner and shields are now shipping the compiler for mccann and 37 chapman for further checkout. they will write operating system 38 interface, check system out, and then hopefully be in position 39 to request translation of the little compiler itself. once 40 bootstrap to dec-10 effected, it is planned to convert compiler 41 to produce binary object (rel) files directly, as well as to 42 further refine the code generator. 43 44 a goal in writing the 370 code generator was to produce a base 45 for constructing other code generators. the work on the dec-10 46 has gone quite smoothly. as the dec-10 architecture is much cleaner 47 than the 370, the asm is correspondingly simpler. 48 49 the rest of this note contains the following 50 51 1. description of dec-10 52 2. a comment separating program in little 53 3. the t10 code produced for separating program 54 4. the dec-10 macro code for separating program 55 5. a small test program used in asm checkout 56 6. the t10 code produced by test program 57 7. the macro-10 macros for t10 opcodes used for 58 assembly at bbn. 59 60 section 1. brief introduction to the dec-10 61 -------------------------------------------- 62 63 this section contains a brief description of the dec-10 64 hardware. basic machine characters are as follows: 65 66 1. word size of 36. 67 2. memory up to 256k. 68 3. address size of 18 bits. 69 4. character size varies, but will be six for first 70 little implementation. 71 5. halfword, byte and stack instructions. 72 6. no condition codes. 73 7. first sixteen memory locations are 'fast' and correspond 74 to registers, which may be addressed as memory, accumulators 75 or index registers. 76 8. arithmetic is two's complement. 77 9. memory protection and relocation. memory may be divided 78 into 'pure' (high) and 'impure' (low) segments, typically 79 done so pure segment can contain sharable, reentrant code. 80 81 the basic instruction word layout is as follows: 82 83 ic = .f. 28, 09, instruction code 84 ra .f. 24, 04, result accumulator (register) number 85 ia .f. 23, 01, set for indirect addressing 86 ir .f. 19, 04, index register (if nonzero) 87 ma .f. 01, 18, memory address 88 89 the rightmost three fields ia, ir and ma determine the 90 effective address e in the same way in all instructions, 91 as follows: 92 93 $ is is current instruction word. 94 aw = .f. 01, 24, iw; 95 while 1; $ while possible indirection. 96 e = .f. 01, 18, aw; $ get memory address. 97 if .f. 19, 04, aw then $ if indexing 98 e = e + memory(.f. 19, 04, aw); $ do indexing. 99 end if; 100 if (.f. 23, 1, aw = 0) quit while; $ if not indirect. 101 aw = .f. 1, 24, memory(e); $ indirect, load next word. 102 end while; 103 104 here, memory(x) indicates contents of memory location x. 105 106 the assembler is called macro-10. basic assembler conventins 107 are as follows: 108 1. symbols up to six characters, may use period, dollar sign 109 and percent characters in symbols 110 2. labels indicated by initial name followed by colon. 111 3. first operand generally result register, second generally 112 specifies effective address. 113 4. symbol '.' indicates current location. 114 5. comments begin with semicolon. 115 6. literals enclosed in square brackets. literals may 116 be multi-line, i.e., contain several instructions. 117 118 for example, the instruction 119 move r1,@ara(r2) ; load ara(i) into r1. 120 (where @ is that 'at' character) 121 moves a value into register r1. the value is obtained by 122 adding the contents of register r2 (here used as an index 123 register) to ara to obtain address e and, since @ indicates 124 indirect addressing, the contents of location e contain the 125 address of the operand. 126 127 the dec-10 ops are straightforward. the common form specifies 128 result register and memory address, and indicates the contents 129 of register and memory operand are to be combined in some way. 130 there are four basic modes for most of the instructions: 131 132 (basic) put result in register 133 (memory) put result in memory 134 (immediate) put result in register, ea is value to operate 135 on, not address of operand 136 (both) put result in both register and memory 137 138 the default mode is basic; other modes are indicated by adding 139 letter m, i or b to opcode to obtain memory, immediate, or 140 both, respectively. 141 142 the dec-10 supports the field extract as a hardware operation, 143 sothat code generation for extractions is very straightforward 144 the machine operation uses a byte pointer where the i, x and 145 y fields address the word containing the byte. the leftmost 146 six bits of the byte pointer define the byte position p, the 147 next six bits define the byte size s. s is the number of bits 148 in the byte, and p is the number of bits in the word to the 149 right of the rightmost bit in the byte. thus 150 151 little .f. f1, f2, v corresponds to s=f2 p=f1-1 152 153 macro supports a pseudo-op 'point' to construct byte pointers 154 which has the form 155 156 point s1,a,b1 157 158 where a is the address of the word containing the byte, s1 is 159 the length of byte, and b1 is the dec-10 index of the rightmost 160 bit of the byte. thus 161 162 point s1,a,b1 corresponds to s=s1, p=35-b1 163 164 so that 165 166 little .f. f1, f2, v corresponds to s1=f2, b1=36-f1 167 168 example of field extract 169 170 r2 = .f. 2, 10, r1 --> ldb r2,[point 10,r1,34] 171 172 173 174 section 2. little program to separate comments 175 ------------------------------------------------------ 176 177 this a simple little program that filters the input 178 file to align dec-10 format assembler comments. 179 --------------------------------------------------- 180 181 $ program to align semicolon comments in dec-10 code. 182 $ semicolons in input text are assumed to begin 183 $ comments. comments not beginning in column one are 184 $ aligned so that comments begin in a tab column (1,9,17,...). 185 $ author: d. shields (cims) 1 jun 78 186 +* ws = .ws. ** +* ps=.ps.** +* cs=.cs.** 187 +* ofile = 3 ** $ output file. 188 prog main; 189 size istr(.sds. 80); $ input string. 190 size sp(ps); $ semicolon position 191 size nsp(ps); $ new semicolon position. 192 193 file ofile access=put, title='out',linesize=80; 194 .+s66 rewind ofile; 195 196 while 1; $ filter std. input to ofile. 197 get ,skip :istr,a(80); 198 if (filestat(1,end)) quit while; 199 sp = ';' .in. istr; 200 $ just copy if no semicolon, or semicolon is aligned. 201 if sp=0 ! mod(sp,8)=1 then 202 put ofile :istr,a ,skip; 203 else $ if semicolon to align. 204 nsp = sp+8-mod(sp-1,8); 205 put ofile 206 :(.s. 1,sp-1,istr),a $ text. 207 ,column(nsp) ,';' $ semicolon 208 :(.s. sp+1,(80-nsp),istr),a $ comment text. 209 ,skip; 210 end if; 211 end while; 212 end prog; 213 214 215 216 section 3. t10 code for semicolon program 217 ------------------------------------------ 218 219 search t10mac 220 dsp main,0,2 ; * * * m a i n *** 221 ;= istr g10+16 222 ;= sp g10+0 223 ;= nsp g10+1 224 dnd $ain,g10,17 225 dbr con,4 226 dbw tmp,15 227 dsc main 228 cal ltlini,1,bas+1 229 cal makf$i,6,bas+5 230 lab l0001 231 cal vali$i,2,bas+12 232 cal gcfp$i,2,bas+15 233 cal ifma$i,2,bas+18 234 cal ioqu$i,2,bas+15 235 jne r0,l0002 236 cal cind$m,2,bas+21 237 stw r0,g10+0 ;sp 238 ldw r11,r0 ;sp 239 bani r11,+7 240 jeq r0,l0006 241 ceqi r11,+1 242 jmp r0,l0003 243 lab l0006 244 cal vali$i,2,bas+26 245 cal ofma$i,2,bas+29 246 cal gcfp$i,2,bas+15 247 jmp r0,l0001 248 lab l0003 249 ldw r11,g10+0 250 iso r10,r11 ;sp 251 ldw r9,r11 ;sp 252 iadi r9,+8 253 ldw r8,r10 254 bani r8,+7 255 isu r9,r8 256 stw r9,g10+1 ;nsp 257 cal vali$i,2,bas+26 258 stw r10,bas+23 259 cal cext$m,5,bas+32 260 cal ofma$i,2,bas+37 261 cal gcfp$i,2,bas+39 262 cal ofma$i,2,bas+42 263 iao r11,r11 ;sp,sp 264 ldwi r10,+80 265 isu r10,g10+1 266 stw r11,bas+20 267 stw r10,bas+23 268 cal cext$m,5,bas+44 269 cal ofma$i,2,bas+37 270 cal gcfp$i,2,bas+15 271 jmp r0,l0001 272 lab l0002 273 cal ltlfin,2,bas+49 274 dec main 275 dbw bas,51 276 dws con+0,"out" 277 dwo con+1,111000003 278 dws con+2,";" 279 dwo con+3,111000001 280 dwo bas+0,0 281 dwa bas+1,bas+0 282 dwo bas+2,3 283 dwo bas+3,7 284 dwo bas+4,120 285 dwa bas+5,bas+2 286 dwa bas+6,bas+3 287 dwa bas+7,con+1 288 dwa bas+8,bas+2 289 dwa bas+9,bas+4 290 dwa bas+10,bas+0 291 dwo bas+11,1 292 dwa bas+12,bas+11 293 dwa bas+13,bas+0 294 dwo bas+14,2 295 dwa bas+15,bas+11 296 dwa bas+16,bas+14 297 dwo bas+17,207000240 298 dwa bas+18,g10+16 299 dwa bas+19,bas+17 300 dwa bas+21,con+3 301 dwa bas+22,g10+16 302 dwa bas+26,bas+2 303 dwa bas+27,bas+11 304 dwo bas+28,207000000 305 dwa bas+29,g10+16 306 dwa bas+30,bas+28 307 dwo bas+31,17 308 dwa bas+32,bas+11 309 dwa bas+33,bas+23 310 dwa bas+34,g10+16 311 dwa bas+35,tmp+14 312 dwa bas+36,bas+31 313 dwa bas+37,tmp+14 314 dwa bas+38,bas+28 315 dwa bas+39,g10+1 316 dwa bas+40,bas+11 317 dwo bas+41,22000000 318 dwa bas+42,con+3 319 dwa bas+43,bas+41 320 dwa bas+44,bas+20 321 dwa bas+45,bas+23 322 dwa bas+46,g10+16 323 dwa bas+47,tmp+14 324 dwa bas+48,bas+31 325 dwa bas+49,bas+0 326 dwa bas+50,bas+0 327 dep main 328 329 330 section 4. hand translation of t10 code for semicolon 331 ------------------------------------------------------- 332 333 search t10mac 334 title main 335 twoseg 336 entry main 337 reloc 0 338 z$sa: block 13 ;register save area. 339 ;= istr g10+16 340 ;= sp g10+0 341 ;= nsp g10+1 342 intern $ain 343 $ain: block 17 344 g10==$ain 345 con: block 4 346 tmp: block 15 347 reloc ^o400000 ;code in high segment 348 main: movei r13,z$sa 349 blt r13,z$sa+r11-1 ;save registers 350 movei r12,bas+1 351 pushj r15,ltlini 352 movei r12,bas+5 353 pushj r15,makf$i 354 l0001: movei r12,bas+12 355 pushj r15,vali$i 356 movei r12,bas+15 357 pushj r15,gcfp$i 358 movei r12,bas+18 359 pushj r15,ifma$i 360 movei r12,bas+15 361 pushj r15,ioqu$i 362 jumpn r0,l0002 363 movei r12,bas+21 364 pushj r15,cind$m 365 movem r0,g10+0 ;sp 366 move r11,r0 ;sp 367 andi r11,+7 368 jumpe r0,l0006 369 move r12,r11 370 movei r11,+1 371 caie r12,+1 372 setz ,r11 373 jumpa r0,l0003 374 l0006: movei r12,bas+26 375 pushj r15,vali$i 376 movei r12,bas+29 377 pushj r15,ofma$i 378 movei r12,bas+15 379 pushj r15,gcfp$i 380 jumpa r0,l0001 381 l0003: move r11,g10+0 382 move r10,r11 383 sos r10, 384 move r9,r11 ;sp 385 addi r9,+8 386 move r8,r10 387 andi r8,+7 388 sub r9,r8 389 movem r9,g10+1 ;nsp 390 movei r12,bas+26 391 pushj r15,vali$i 392 movem r10,bas+23 393 movei r12,bas+32 394 pushj r15,cext$m 395 movei r12,bas+37 396 pushj r15,ofma$i 397 movei r12,bas+39 398 pushj r15,gcfp$i 399 movei r12,bas+42 400 pushj r15,ofma$i 401 aos ,r11 ;sp 402 movei r10,+80 403 sub r10,g10+1 404 movem r11,bas+20 405 movem r10,bas+23 406 movei r12,bas+44 407 pushj r15,cext$m 408 movei r12,bas+37 409 pushj r15,ofma$i 410 movei r12,bas+15 411 pushj r15,gcfp$i 412 jumpa r0,l0001 413 l0002: movei r12,bas+49 414 pushj r15,ltlfin 415 dec main 416 lit 417 reloc ;return to lo segment. 418 bas block 51 419 .org con+0 420 sixbit "out" 421 oct 111000003 422 sixbit ";" 423 oct 111000001 424 .org 425 .org bas+0 426 oct 0 427 exp bas+0 428 oct 3 429 oct 7 430 oct 120 431 exp bas+2 432 exp bas+3 433 exp con+1 434 exp bas+2 435 exp bas+4 436 exp bas+0 437 oct 1 438 exp bas+11 439 exp bas+0 440 oct 2 441 exp bas+11 442 exp bas+14 443 oct 207000240 444 exp g10+16 445 exp bas+17 446 exp con+3 447 exp g10+16 448 exp bas+2 449 exp bas+11 450 oct 207000000 451 exp g10+16 452 exp bas+28 453 oct 17 454 exp bas+11 455 exp bas+23 456 exp g10+16 457 exp tmp+14 458 exp bas+31 459 exp tmp+14 460 exp bas+28 461 exp g10+1 462 exp bas+11 463 oct 22000000 464 exp con+3 465 exp bas+41 466 exp bas+20 467 exp bas+23 468 exp g10+16 469 exp tmp+14 470 exp bas+31 471 exp bas+0 472 exp bas+0 473 .org 474 lit 475 var 476 prgend main 477 478 479 480 section 5. tst10 - asm test program 481 ------------------------------------ 482 483 484 485 prog start; 486 call sub1; 487 end prog; 488 subr sub1; 489 size mw1(.ws.*3), mw2(.ws.*2); 490 size mwfcn(.ws.*2), f(.ps.); 491 size i(.ps.), j(.ps.); 492 493 i = .f. 1, 1,j; i = .f. 1, 1, mw1; 494 495 mw1 = 0; mw2 = mwfcn(i); 496 497 j = .f. i+1, 3, f(j); 498 499 j = .f. 1, i, mw2; 500 501 .f. 1, 1,i = 1; 502 503 .f. 1, 4, i = j; 504 505 .f. i, j, mw2 = 567; 506 507 i = .f. 1, 2, 67; 508 509 end subr sub1; 510 fnct mwfcn(x); 511 size mwfcn(2*.ws.), x(.ws.); 512 513 mwfcn = x; 514 515 end fnct; 516 fnct f(i); 517 size f(.ps.), i(.ps.); 518 519 f = .f. 19, 18, i; 520 521 end fnct; 522 subr sub2; 523 size mwarr(.ws.*2), swarr(.ws.); 524 dims mwarr(100), swarr(100); 525 526 size i(.ps.); 527 528 mwarr(i) = i; 529 530 swarr(i) = i + 3; 531 532 mwarr(i) = mwarr(i+4); 533 534 call sub3(mwarr, swarr); 535 536 end subr sub2; 537 subr sub3(mwarr, swarr); 538 size mwarr(.ws.*2), swarr(.ws.); 539 540 dims mwarr(2), swarr(2); 541 size i(.ps.); 542 543 swarr(1) = 20; 544 545 .f. 1, 3, mwarr(i) = 5; 546 547 .f. i+1, 5, swarr(i) = 20; 548 549 end subr sub3; 550 551 552 553 $ little dec10 code generator test. 554 +* ws = .ws. ** +* ps=.ps. ** +* cs = .cs.** 555 subr main; 556 size gw1(ws), gw2(ws), gw3(ws), gw4(ws); 557 size i(ps), ara(ws); dims ara(100); 558 data gw1=1; 559 gw1 = gw2 + gw3; 560 do i = 1 to .nb. gw1; ara(i) = ara(i) / 4; end do; 561 if gw1>gw2 & gw3>=1 then i = 10; else i= gw1*gw2; end if; 562 if gw1 .ne. gw2 ! i<0 then 563 call sub(gw1, ara(i+2), 4); 564 end if; 565 size mw1(ws*3), mwa(ws*3); dims mwa(5); 566 call sub1(mw1, mwa, mwa(4)); 567 end subr; 568 569 570 571 572 section 6. generated t10 code for tst10 program 573 ------------------------------------------------ 574 search t10mac 575 dsp start,0,2 ; * * * s t a r t * * * 576 dsc start 577 cal ltlini,1,bas+1 578 cal sub1,0,0 579 cal ltlfin,2,bas+2 580 dec start 581 dbw bas,4 582 dwo bas+0,0 583 dwa bas+1,bas+0 584 dwa bas+2,bas+0 585 dwa bas+3,bas+0 586 dep start 587 search t10mac 588 dsp sub1,0,0 ; * * * s u b 1 * * * 589 ;= mw1 lcl+9 590 ;= mw2 lcl+4 591 ;= i lcl+1 592 ;= j lcl+2 593 dbw tmp,2 594 dbw lcl,10 595 dsc sub1 596 ldw r1,lcl+1 ;i 597 ldw r2,lcl+2 ;j 598 lpr r11,r2,0,1 ;j 599 ldw r1,r11 ;i 600 lpr r11,lcl+9,0,1 601 ldw r1,r11 ;i 602 lda r11,lcl+7 603 zebi r11,+3 604 stw r1,lcl+1 ;i 605 cal mwfcn,1,bas+1 606 ldw r10,r0 607 lda r9,lcl+3 608 mvw r9,-1(r10),2 609 cal f,1,bas+3 610 lda r10,r0 611 spr r1,r10,30,6 ;i 612 ldwi r8,+3 613 spr r8,r10,24,6 614 ldf r10,r10 615 ldw r2,r10 ;j 616 lda r10,lcl+4 617 spr r1,r10,24,6 ;i 618 ldf r10,r10 619 ldw r2,r10 ;j 620 ldwi r10,+1 621 spr r10,r1,0,1 ;i 622 spr r2,r1,0,4 ;j,i 623 iso r8,r1 ;i 624 ldw r7,r8 625 idii r7,+36 626 imoi r8,+36 627 ico r7,r7 628 lda r6,lcl+4(r7) 629 lda r7,+0(r6) 630 spr r8,r7,30,6 631 spr r2,r7,24,6 ;j 632 ldwi r8,+567 633 stf r8,r7 634 lpr r10,bas+5,0,2 635 ldw r1,r10 ;i 636 lab l0002 637 stw r1,lcl+1 ;i 638 stw r2,lcl+2 ;j 639 ret sub1 640 dec sub1 641 dbw bas,6 642 dwa bas+1,lcl+1 643 dwa bas+3,lcl+2 644 dwo bas+5,103 645 dep sub1 646 search t10mac 647 dsp mwfcn,1,1 ; * * * m w f c n * * * 648;= x @+0(r11) 649;= mwfcn bas+1 650 dsc mwfcn 651 lda r10,bas+0 652 zebi r10,+1 653 ldw r9,@+0(r11) 654 stw r9,bas+1 ;mwfcn 655 lab l0003 656 lda r0,bas+1 657 ret mwfcn 658 dec mwfcn 659 dbw bas,2 660 dep mwfcn 661 search t10mac 662 dsp f,1,1 ; * * * f * * * 663;= i @+0(r11) 664;= f bas+0 665 dsc f 666 ldl r10,@+0(r11) 667 stw r10,bas+0 668 lab l0004 669 ldw r0,bas+0 670 ret f 671 dec f 672 dbw bas,2 673 dep f 674 search t10mac 675 dsp sub2,0,0 ; * * * s u b 2 * * * 676;= mwarr lcl+102 677;= swarr lcl+1 678;= i lcl+0 679 dbw tmp,2 680 dbw lcl,301 681 dsc sub2 682 ldw r1,lcl+0 ;i 683 ldw r11,r1 ;i 684 imti r11,+1 685 lda r10,lcl+99(r11) 686 zebi r10,+1 687 stw r1,lcl+100(r11) ;i 688 ldw r11,r1 ;i 689 iadi r11,+3 690 stw r11,lcl+0(r1) ;i 691 ldw r11,r1 ;i 692 imti r11,+1 693 lda r10,lcl+108(r11) 694 ldw r11,r1 ;i 695 imti r11,+1 696 lda r9,lcl+99(r11) 697 mvw r9,-1(r10),2 698 cal sub3,2,bas+2 699 lab l0005 700 stw r1,lcl+0 ;i 701 ret sub2 702 dec sub2 703 dbw bas,4 704 dwa bas+2,lcl+102 705 dwa bas+3,lcl+1 706 dep sub2 707 search t10mac 708 dsp sub3,2,0 ; * * * s u b 3 * * * 709;= mwarr @+0(r11) 710;= swarr @+1(r11) 711;= i lcl+0 712 dbw lcl,1 713 dsc sub3 714 ldw r1,lcl+0 ;i 715 ldw r10,+1(r11) 716 ldwi r9,+20 717 ldw r8,r1 ;i 718 imti r8,+1 719 ldw r7,+0(r11) 720 ldw r6,r8 721 iad r6,r7 ;mwarr 722 lda r5,-2(r6) 723 ldwi r8,+5 724 spr r8,+0(r5),0,3 725 stw r9,+0(r10) ;swarr,swarr 726 ldw r7,r1 ;i 727 iad r7,r10 ;swarr 728 lda r5,-1(r7) 729 lda r10,+0(r5) 730 spr r1,r10,30,6 ;i 731 spr r8,r10,24,6 732 ldwi r9,+20 733 stf r9,r10 734 lab l0006 735 stw r1,lcl+0 ;i 736 ret sub3 737 dec sub3 738 dbw bas,2 739 dep sub3 740 741 742 743 section 7. macro-10 macros for t10 operations 744 ---------------------------------------------- 745 746 this section contains a preliminary definition 747 of the dec-10 macro-10 macros to expand t10 748 code to valid macro-10 code. this version 749 is based in part on a version written by nigel 750 chapman of leeds in april 78. this version was 751 used to assemble the little program ltldoc. 752 there were no assembly errors. as the system 753 interface for dec-10 little was not available, it 754 was not possible to run the program. 755 756 universal t10mac 757 ; t10 macros for assembling t10 code. 758 ; these macros expand the t10 source code generated 759 ; by little dec-10 bootstrap compiler into macro-10 760 ; 761 ; author d. shields cims 1-jun-78 762 ; 763 ; the macros should be assembled as a universal file 764 pass2 ; no data, so need only pass2. 765 radix 10 766 ; symbols used within macros all begin with z$ . 767 ; symbolic names for registers. 768 r0==0 769 r1==1 770 r2==2 771 r3==3 772 r4==4 773 r5==5 774 r6==6 775 r7==7 776 r8==8 777 r9==9 778 r10==10 779 r11==11 780 rhi==r11 781 w1==rhi+1 782 w2==rhi+2 783 z$sp==15 784 ; r0 is used to hold function value. 785 ; t10 code uses registers ro through rhi. 786 ; w1 and w2 are work registers used in some 787 ; macro expansions. w1 is volatile in that 788 ; t10 code may contain uses of w1 to store 789 ; values into parameter lists. 790 ; z$sp is stack pointer used for procedure 791 ; linkage. 792 ; 793 ; z$pt. codes give procedure type: subr, fnct 794 ; or prog. this is same encoding used 795 ; by gen, and is passed as last arg 796 ; in dsp t10 opcode. 797 z$pt.s==0 798 z$pt.f==1 799 z$pt.p==2 800 define dbr(bn,l) 801 802 define dbw(bn,l) 803 804 define dec(pn) 805 < lit ; hi seg literals 806 reloc> ; return to low segment 807 define dep(pn) 808 < lit 809 var 810 ife z$pt-z$pt.p, 811 ifn z$pt-z$pt.p,> 812 define dsc(pn) 813 < reloc ^o400000 ;; code in high segment 814 pn: movei w2,z$sa 815 blt w2,z$sa+rhi-1 816 ifg z$na,> ; if args 817 define dsp(pn,na,ty) 818 < title pn 819 radix 10 820 twoseg 821 entry pn 822 reloc 0 823 z$na==na ; save argument count 824 z$pt==ty ; save procedure type 825 z$sa: block rhi+1> ; allocate register save area 826 ; dna and dnd indicate access and definition of global 827 ; data areas. en is external name, in is internal 828 ; name used in t10 code, and l is block length in 829 ; words. 830 define dna(en,in,l) 831 < extern en 832 in==en> 833 define dnd(en,in,l) 834 < intern en 835 en: block l 836 in==en> 837 ; the dw- ops define the initial value of a word 838 ; of memory. the first arg is address of word, 839 ; the second is value. 840 ; types are a-address, c-character (right-justified 841 ; sixbit with zero fill), i-integer, o-octal, r-real 842 ; and s-string (left justified sixbit with blank fill). 843 ; the second arg of dwz op is number of words to be 844 ; initialized to zero, beginning at data address. 845 define dwa(da,v) 846 < .org da 847 exp v 848 .org> 849 define dwc(da,v) 850 < .org da 851 exp v 852 .org> 853 define dwi(da,v) 854 < .org da 855 dec v 856 .org> 857 define dwo(da,v) 858 < .org da 859 oct v 860 .org> 861 define dwr(da,v) 862 < .org da 863 exp v 864 .org> 865 define dws(da,v) 866 < .org da 867 sixbit v 868 .org> 869 define dwz(da,n) 870 < .org da 871 repeat n, 872 .org> 873 syn and,ban 874 syn andi,bani 875 define bfb(ra,ea) 876 < move w1,ea 877 jffo w1,.+2 878 movei w2,36 879 subi w2,36 880 movn ra,w2> 881 define bnb(ra,ea) 882 < move w1,ea 883 setz ra 884 movn w2,w1 885 tdze w1,w2 886 aoja ra,.-2> 887 syn setcm,bno 888 syn ior,bor 889 syn iori,bori 890 syn xor,bxo 891 syn xori,bxoi 892 define cal(pn,na,pl) 893 < movei w1,pl 894 movei w2,na 895 ifndef pn, 896 pushj z$sp,pn> 897 syn came,ceq 898 syn caie,ceqi 899 syn camge,cge 900 syn caige,cgei 901 syn camg,cgt 902 syn caig,cgti 903 syn camle,cle 904 syn caile,clei 905 syn caml,clt 906 syn cail,clti 907 syn camn,cne 908 syn cain,cnei 909 syn movm,iab 910 syn add,iad 911 syn addi,iadi 912 define iao(ra,ea) 913 < ifidn , 914 ifdif ,< 915 move ra,ea 916 aos ra,>> 917 syn movn,ico 918 define idi(ra,ea) 919 < move w1,ra 920 idiv w1,ea 921 move ra,w1> 922 define idii(ra,ea) 923 < move w1,ra 924 idivi w1,ea 925 move ra,w1> 926 define idti(ra,ea) 927 define ieq(ra,ea) 928 < move w1,ra 929 movei ra,1 930 came w1,ea 931 setz ra> 932 define ieqi(ra,ea) 933 < move w1,ra 934 movei ra,1 935 caie w1,ea 936 setz ra> 937 define ige(ra,ea) 938 < move w1,ra 939 movei ra,1 940 camge w1,ea 941 setz ra> 942 define igei(ra,ea) 943 < move w1,ra 944 movei ra,1 945 caige w1,ea 946 setz ra> 947 define igt(ra,ea) 948 < move w1,ra 949 movei ra,1 950 camg w1,ea 951 setz ra> 952 define igti(ra,ea) 953 < move w1,ra 954 movei ra,1 955 caig w1,ea 956 setz ra> 957 define ile(ra,ea) 958 < move w1,ra 959 movei ra,1 960 camle w1,ea 961 setz ra> 962 define ilei(ra,ea) 963 < move w1,ra 964 movei ra,1 965 caile w1,ea 966 setz ra> 967 define ilt(ra,ea) 968 < move w1,ra 969 movei ra,1 970 caml w1,ea 971 setz ra> 972 define ilti(ra,ea) 973 < move w1,ra 974 movei ra,1 975 cail w1,ea 976 setz ra> 977 define imo(ra,ea) 978 < move w1,ra 979 idiv w1,ea 980 move ra,w2> 981 define imoi(ra,ea) 982 < move w1,ra 983 idivi w1,ea 984 move ra,w2> 985 define imti(ra,ea) 986 syn imul,imu 987 syn imuli,imui 988 define ine(ra,ea) 989 < move w1,ra 990 movei ra,1 991 camn w1,ea 992 setz ra> 993 define inei(ra,ea) 994 < move w1,ra 995 movei ra,1 996 cain w1,ea 997 setz ra> 998 define isi(ra,ea) 999 < move w1,ea 1000 movem ra,ra 1001 jumpe w1,.+2 1002 moven ra,ea> 1003 define iso(ra,ea) 1004 < ifidn , 1005 ifdif ,< 1006 move ra,ea 1007 sos ra,>> 1008 syn sub,isu 1009 syn subi,isui 1010 syn jumpe,jeq 1011 syn jumpge,jge 1012 syn jumpg,jgt 1013 syn jumple,jle 1014 syn jumpl,jlt 1015 syn jump,jmn 1016 syn jumpa,jmp 1017 syn jumpn,jne 1018 define lab(l) 1019 syn movei,lda 1020 define ldf(ra,ea) 1021 syn hlrz,ldl 1022 syn hlrzi,ldli 1023 syn hrrz,ldr 1024 syn hrrzi,ldri 1025 syn move,ldw 1026 syn movei,ldwi 1027 define lpr(ra,ea,c1,c2) 1028 define mvw(ra,ea,n) 1029 < hrl w1,ra 1030 hrri w1,ea 1031 movei w2,ea 1032 addi w2,n-1 1033 blt w1,w2> 1034 syn movm,rab 1035 syn fad,rad 1036 syn movn,rco 1037 syn fdvr,rdi 1038 syn ieq,req 1039 define ret(pn) 1040 < ife z$pt-z$pt.f,< 1041 hrr z$sp,r1 1042 hrlzi z$sp,z$sa 1043 blt z$sp,rhi> 1044 ifn z$pt-z$pt.f,< 1045 hrlzi z$sp,z$sa 1046 blt z$sp,rhi> 1047 popj z$sp,> 1048 syn ige,rge 1049 syn igt,rgt 1050 syn ile,rle 1051 syn ilt,rlt 1052 define rmo(ra,ea) 1053 ; rmo code is (incorrect) copy of imo code 1054 < move w1,ra 1055 idiv w1,ea 1056 move ra,w2> 1057 syn fmp,rmu 1058 syn ine,rne 1059 syn isi,rsi 1060 syn fsb,rsu 1061 define spr(ra,ea,c1,c2) 1062 define stf(ra,ea) 1063 syn hrlm,stl 1064 syn hrrm,str 1065 syn movem,stw 1066 define zebi(ra,n) 1067 < movei w1,1(ra) 1068 hrl w1,ra 1069 setzm ,0(ra) 1070 blt w1,n(ra)> 1071 syn setzm,zew 1072 end 1073 */ 1074 ..docnote