include "Sysinc:com.inc" ! ************************************************************** ! * * ! * PERKIN-ELMER 32-bit series IMP compiler * ! * Intermediate-code Assembler * ! * * ! * (General Service Version) * ! * * ! * Interactive Datasystems (Edinburgh) Ltd. * ! * 32, Upper Gilmore Place, * ! * Edinburgh EH3 9NJ * ! * * ! * Copyright (c) MAY 1st. 1980 * ! * All Rights Reserved * ! * * ! ************************************************************** ! Known faults: ! Outstanding: ! %longreal is currently treated as %real ! statically sized arrays within stack frame ! ! Optimisations: (intended complete list) ! integer constant folding *done* ! real folding: integer/integer, integer^integer *done* ! literals in shareable code segment *done* ! special treatment of null string *done* ! special treatment of simple append (S = S.T) *done* ! special treatment of S=S.tostring(x) *done* ! suppression of redundant capacity checks *done* ! suppression of redundant unassigned checks *done* ! register usage *done* ! register environments *done* ! k*2 -> k+k, k^2 -> k*k, k^^2 -> k*k *done* ! Pass last param = string or record %value as %name then ! copy within routine *done* (for strings only) ! Detect and omit redundant array bound checks ! ABORT CODES ! =========== ! code routine reason ! ! ?? x: assemble: faulty intermediate code operation 'x' ! ADMP: adump: constant record ? ! AM00: assemble: static block nesting > 5 levels ! AM01: assemble: ('A') unknown constant type ! AM05: assemble: ('u', 'q') unspecified length in ++, -- ! AM10: assemble: ('_') switch label outwith declared vector ! AM15: assemble: ('B') intermediate code faulty at %repeat tag ! AM25: assemble: ('F') user label out of range ! AM30: assemble: (':') user label out of range ! AM35: assemble: ('d') wrong no. of dimensions specified ! AM40: assemble: ('d') %const/%own array inside out ! AM45: assemble: ('~') faulty intermediate code in alternate record format ! AM50: assemble: ('}') symbol table overflow (inserting formal parameter specs) ! AM55: assemble: ('}') (OUT:) %record format > 64k bytes ! AMAP: amap: impossible form ! ARF1: array ref: no. of subscripts doesn't match declaration ! ASS1: assign: not at least two items on operand stack ! ASS2: assign: general %name not a %name ! ASS3: assign: record length undefined in 'record = record' ! CLM1: claim: reg > fr14 ! CLMD: assemble: ('O') registers still claimed at line flag ! COP1: cop: exponent overflow in folding integer^integer ! COP2: cop: inappropriate operator ! DMP1: select literal area: literal area already selected ! DMP2: select code area: code area already selected ! DMP3: lit byte: literal area not selected ! DMP4: claim literal: literal area currently selected ! DMP5: external link: non-existent reference type ! DROP: drop: descriptor not in use ! DSC1: descriptor: operand stack overflow ! DSC2: descriptor: descriptor free-list empty ! DSC3: descriptor: link-block ('using') free-list empty ! DFV1: define var: symbol table overflow (inserting record element name) ! DFV2: define var: symbol table overflow (inserting non-format item) ! FOR1: compile for: too many nested %for...%cycle .....%repeat pairs ! HAZ1: hazard: attempt to hazard a constant ! HAZ2: hazard: a use is still outstanding ! HDR1: header: %string parameter in %begin ? ! LD1: load: ADDRESS failed to simplify non-trivial address mode ! LD2: load: real variable/integer register ! LD3: load: inappropriate type ! LD4: load: not/neg implemented in operate ! LD5: load: load floating variable into 'any' ? ! LD6: load: real operand with and/or/xor ! LD7: load: real 'neg' implemented in operate ! LD8: load: not a floating register ! LD9: load: real exponent ? ! LIT?: assemble: ('O') literal area still selected at line flag ! NLBL: new label: no free labels ! PICK: pickup (in LOAD) incompatible uses of a register ! POPL: pop lhs: operand stack is already empty ! REL1: release: reg > fr14 ! REL2: release: reg not claimed ! RXD1: rxd: no immediate form of instruction ! RXD2: rxd: faulty register specification ! RXD3: rxd: faulty register specification ! RXD4: rxd: non-elementary operand type supplied to 'RXD' ! RXD5: rxd: displacement not aligned on 'type' boundary ! SETB: set both: not at least two items on operand stack ! STK?: assemble: ('O') operand stack not empty at line flag. ! TAG?: block mark: more than 32767 third pass tags generated. See c('_'): ! USNG: assemble: ('O') 'using' list not empty at line flag. ! VMAP: vmap: impossible form ! VSTK: vstack: variable no (symbol table index) out of bounds ! == == == == == == == == == == == == == == == == == == ! Known Faults: ! READ SYMBOL is not implemented properly ! external linkage dumping is too indiscriminate ! general name parameter types don't match old subsystem ! == == == == == == == == == == == == == == == == == == !***************************************************************************** ! ! Options: (enabled when control bit = 1) ! ! 1: Capacity check on all store operations ! Overflow check on integer multiply ! 2: Unassigned check on %string, %integer, %real & %longreal operands ! 4: Array bound checking ! Checks for integrity of %for construction ! 16: Assorted extra checks: ! complete arithmetic overflow checking (*not yet*) ! 32: Permit removal of ALL diagnostic code and optimisations which are ! not 100% safe. ! Diagnostic code removed: ! Unassigned check on P in R string parameter ! Stack limit check ! Risky optimisations: ! Remembering pointers over an assignment via ! another pointer. Aliasing might JUST occur. ! 64: Enable trace option ! 128: No register optimisation: primarily for suppressing compiler faults ! ! NOTE: ! Switch references are always checked ! Stack overflow is checked unless 'TRUSTED' is specified. ! !****************************************************************************** ! N.B. The bit positions in CONTROL corresponding to 256 and 512 ! are reserved to control the dumping of diagnostic tables ! by PASS 3. ! ! OPT is set (implicitly) by disabling all explicitly settable ! checks (bits 1,2,4,8,16) ! ! TRUSTED disables all checks and also sets the '32' bit. !****************************************************************************** begin ; ! 7/32 DIAGNOSTIC ASSEMBLER !SIZE CONSTANTS constinteger max vars = 800 constinteger max labels = 80 constinteger max depth = 16 constinteger max stack = 25 constinteger max labdef = 7999 constinteger max refs = 2000 constinteger SetLen = 32 {bytes per set} constinteger max prim = 23 constinteger max cycle = 30 constinteger max temps = 60 constinteger max use = 20; !limit for klist constinteger max envirs = 5; !Environments constinteger max knowledge = max use*(max envirs+1) conststring (3) program ep = "%GO"; ! Main program external name conststring (1) system prefix = "$"; ! prefixed to %system routine idents conststring (6) trace routine = "$TRACE"; ! external called by trace option conststring (10) read sym fn = "#READSYMFN"; ! linkage name of "read symbol" perm constinteger ident len = 19; ! Significant chars in internal idents constinteger extern len = 12; ! Max. length of names in diags/link !Input/output streams constinteger in=1 constinteger report=0, direct=1, object=2 ! Language mask bits (generally =0 for 'obvious' or IMP interpretation) ! Note that each bit controls compilation of a particular source level ! abstraction and each first pass can select any convenient combination ! of options. constinteger UNUSED = 1, {currently not used - IMP pass1!!} non IMP for = 2 {exit on >= final value (zero trip)} !CONTROL BITS constinteger check capacity=1 constinteger check unass=2 constinteger check array=4, check for = 4 constinteger check extra=16 constinteger trusted=32 constinteger trace=64 constinteger suppress=128 constinteger check bits = check capacity+check unass+check array+check extra constinteger bit15 = -32768; ! halfword sign-bit !SPECIAL ADDRESSES constinteger unass = 12; ! unassigned pattern at unass(code) constinteger init gla = 12; ! first usable displacement into gla constinteger init lit = 8; ! first literal ends at -INITLIT(CODE) ! Derived constants constinteger for lab base = 8000; ! = MAX LABDEF+1 !REGISTERS constinteger R0 = 1 constinteger R1 = 2; ! Fn/map result, @final string result constinteger p3 = R1; ! SPECIAL STRING PARAMETER constinteger R2 = 3 constinteger R3 = 4 constinteger R4 = 5 constinteger R5 = 6, p2 = R5 constinteger R6 = 7, p1 = R6 constinteger R7 = 8, wsp = R7 constinteger R8 = 9, base1 = R8 constinteger R9 = 10, base2 = R9 constinteger R10 = 11, base3 = R10 constinteger R11 = 12, base4 = R11 constinteger R12 = 13, base5 = R12; ! (unassigned pattern for levels 1:4) constinteger R13 = 14, gla = R13 constinteger R14 = 15, code = R14 constinteger R15 = 16, link = R15 constinteger FR0 = 17; ! FN RESULT constinteger FR2 = 18 constinteger FR4 = 19 constinteger FR6 = 20 constinteger FR8 = 21 constinteger FR10 = 22 constinteger FR12 = 23 constinteger FR14 = 24 !PSEUDO REGISTERS constinteger any = 25 constinteger anyf = 26 constbyteintegerarray actual(0:fr14) = 0, 0, 1, 2, 3, 4, 5, 6, 7, ! R0 R1 R2 R3 R4 P2 P1 WSP 8, 9, 10, 11, 12, 13, 14, 15, ! R8 R9 R10 R11 R12 GLA CODE LINK 0, 2, 4, 6, 8, 10, 12, 14 ! FR0 FR2 FR4 FR6 FR8 FR10 FR12 FR14 constbyteintegerarray breg(-1:5) = 0, 0, base1, base2, base3, base4, base5 !DATA FORMS ! EXTERNAL constinteger recordformat = 4 constinteger switch = 6 constinteger array = 11 constinteger arrayname = 12 constinteger namearray = 13 constinteger namearrayname = 14 ! INTERNAL constinteger constant = 0 constinteger v in r = 1 constinteger av in r = 2 constinteger a in r = 3 constinteger v in s = 4 constinteger av in s = 5 constinteger a in s = 6 constinteger v in rec = 7 constinteger av in rec = 8 constinteger a in rec = 9 constinteger pgm label = 14 !!N.B. FORM=15 denotes %record format ! Flag bits used in conjunction with form: constinteger quick conc = 1, {optimise: S = S.tostring(symbol) } P in R = 2, {parameter-in-register} prim bit = 4, {primitive known to compiler} assigned = 8, {assigned and known to be} proc bit = 16, {routine/fn/map/predicate} abit = 32, {array by value} anbit = 64, {array by name} label bit = 128 {data is an address} constinteger array bits = abit ! anbit; ! for convenience ! All arrays are in fact treated as by name (i.e. with a dope vector) and ! the ABIT bit is misused to indicate that an array is a candidate for ! subscript scaling by the use of 'multiply halfword' constinteger cheap array bit = abit ! 'FLAG' byte of 'xform': !=======================================================================! ! label AN A proc assigned prim P in R ------ ! ! bit bit bit bit bit ! ! - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ! ! 128 64 32 16 8 4 2 1 ! !=======================================================================! ! : ! ! : D I M E N S I O N S ! ! : (if %array) ! ! :______________________________! ! N.B. ! In 'varfm' the 4,2,1 bits are used to hold the number of dimensions ! when the table entry represents an array object. This field is ! unpacked into the 'DIM' field of 'stackfm' by 'VSTACK' !LABEL CONSTANTS constinteger define new = 0 constinteger redefine old = 1 constinteger internal tag = -1; ! N.B. This must be <0 and others >=0 !DATA TYPES constinteger integers = 1 constinteger short = 2 constinteger byte = 3 constinteger general = 4 constinteger strings = 5 constinteger records = 6 constinteger reals = 7 constinteger reall = 7; ! (SET TO 8 FOR LONG REALS) !Figurative data types used internally (reduce to INTEGERS) !! %constinteger pointer = -1 !! %constinteger in store const = -2 !LENGTHS constinteger single=4; ! bytes in single precision %real constinteger double = single*(reall-reals+1) constinteger align = 3; ! Basic alignment mask constinteger reglen=4; ! no. of bytes in GP register constinteger basic frame = (link-p2+1)*reglen !OWN INFO constinteger own = 1 constinteger con = 2 constinteger external = 3 constinteger system = 4 constinteger dynamic = 5 constinteger primrt = 6 constinteger permrt = 7 ! Constants used to define sizes of various objects known to pass 3 constinteger short ident = 6; ! characters: related to 'extern len' !! constinteger basic vdiag = 4; ! halfwords: no. req'd for 'short ident' constinteger extra vdiag = 2; ! halfwords: basic+extra == extern len ! Define type codes known externally (to pass 3 and user): constbyteintegerarray gen map(integers:reals+1) = 1, 6, 5, 0, 3, 4, 2, 8 ! integer short byte general string record reals reall !PERM ROUTINES ! ** UNASSIGNED CHECK as a special at 0(code) ** constinteger asschk=1 constinteger iexp=2 constinteger fexp=3; ! floating exponent constinteger smove=4 constinteger sjam=5 constinteger sconc=6 constinteger sresln=7; ! conditional resolution constinteger sresv=8; ! check SRESLN succeeded constinteger scomp=9 constinteger frac part = 10; ! IMP 'frac pt' function constinteger sfcap=11; ! string capacity exceeded constinteger substr = 12; ! substring constinteger aref1=13; ! 1-D with checks constinteger aref2=14; ! 2-D with checks constinteger aref3=15; ! n-D with checks constinteger aref4=16; ! 2-D without checks constinteger set dv=17; ! set dope vector constinteger alloc=18; ! claim array space constinteger swjump=19 constinteger signal=20 constinteger mulchk=21; ! check for 32-bit result from integer multiply constinteger cap16=22; ! check for 16-bit signed overflow constinteger cap8=23; ! . . . 8-bit unsigned . . constinteger fchk1=24; ! %for loop parameter check constinteger fchk2=25; ! check for %for loop counter fiddling constinteger pentc=26; ! checked procedure entry constinteger rcopy=27; ! record copy constinteger rzero=28; ! clear record constinteger vschk=29; ! variable shift parameter check constinteger smovopt=30; ! fast unchecked string move (also see P in R string) constinteger chmap=31; ! IMP 'charno' %map constinteger freesp=32; ! IMP 'free space' function constinteger int fn=33; ! IMP 'int' function constinteger rcomp = 34 {record compare} constinteger set comp = 35, set union = 36, set difference = 37, set intersection = 38 constbytearray Set ops(1:3) = Set union, Set Difference, Set intersection constinteger iocp = 49 constinteger enter trace = 50 !OPERATIONS ! logical => both <= code generator constinteger not = 1, lw = 1 constinteger neg = 2, st = 2 constinteger add = 3 constinteger sub = 4 constinteger mul = 5 constinteger div = 6 constinteger conc = 7, cmp = 7 constinteger and = 8 constinteger or = 9 constinteger xor = 10 constinteger lsh = 11 constinteger rsh = 12 constinteger mult16 = 13 constinteger rem = 14 constinteger exp = 15 constinteger rexp = 16 constinteger rdiv = 17 !CODE GENERATOR TABLES ! mask bits in 'op index' array constinteger fw imm=2048, hw imm=4096, sf imm=8192, inv imm=16384 constinteger fw rr=256, fw rx=512, short rx=1024, byte rx=32768 constinteger fp base = rem-1 constshortintegerarray op index(1:40) = x'FF01',; ! LW: load - 1 + all formats x'8609',; ! ST: store - 9 + full/half word + byte x'7F11',; ! ADD: add - 17 + all but byte x'7F18',; ! SUB: subtract - 24 + all but byte x'031F',; ! MUL: multiply - 31 + full word formats x'0321',; ! DIV: divide - 33 + full word formats x'1F23',; ! CMP: compare - 35 + all but byte and short immediate x'1F28',; ! AND: and - 40 + ..... x'1F2D',; ! OR: or - 45 + ...... x'1F32',; ! XOR: xor - 52 + ........ x'3037',; ! LSH: left shift - 55 + halfword and shortform x'303D',; ! RSH: right shift - 61 + halfword and shortform x'0775',; ! MULT16: 117 + rr + rx + short rx ! ** floating point formats ** x'0F43',; ! LW: load - single and double x'0A47',; ! ST: store - store reference formats only x'0F4B',; ! ADD: add - 75 + all formats x'0F4F',; ! SUB: subtract - 79 + ... x'0F53',; ! MUL: multiply - 83 + ... x'0F57',; ! DIV: divide - 87 + ... x'0F5B',; ! CMP: compare - 91 + ... ! ** specials ** x'0364', ; ! JMP x'0366', ; ! BAL x'0267', ; ! LA x'0268', ; ! LM x'0269', ; ! STM x'016B', ; ! FLR x'016C', ; ! FXR x'1F5F', ; ! CLW x'1069', ; ! SRA x'016E', ; ! CHVR x'016F', ; ! LBR x'040A', ; ! STH x'026F', ; ! SVC x'0270', ; ! LME x'0271', ; ! STME x'1870', ; ! TEST (TI/THI) x'0476', ; ! LHL (short rx only) x'0678', ; ! AM (fullword and short rx only) x'027A', ; ! TBT x'027B' ; ! SBT ! Each halfword below is treated as 4 groups of 4 bits [a:b:c:d] with the ! following significance. ! a,b: 8-bit machine op-code ! c: special function bits ! 1: this operation sets condition code other than relative ! to zero. ! 2: invert order of operands to provide for example ! STR x,y => LR y,x ! 4: this operation doesn't affect condition code ! d: mask to check alignment of displacement required by this instruction. constshortintegerarray op code(1:124) = x'0800', x'5803', x'4801', x'F800', x'C800', x'2400', x'2500', x'D350', ! LR L LH LI LHI LIS LCS LB x'0820', x'5053', x'4051', 0, 0, 0, 0, x'D250', ! STR ST STH -- -- -- -- STB x'0A00', x'5A03', x'4A01', x'FA00', x'CA00', x'2600', x'2700', ! AR A AH AI AHI AIS SIS x'0B00', x'5B03', x'4B01', x'FB00', x'CB00', x'2700', x'2600', ! SR S SH SI SHI SIS AIS x'1C50', x'5C53', ! MR M x'1D50', x'5D53', ! DR D x'0910', x'5913', x'4911', x'F910', x'C910', ! CR C CH CI CHI x'0400', x'5403', x'4401', x'F400', x'C400', ! NR N NH NI NHI x'0600', x'5603', x'4601', x'F600', x'C600', ! OR O OH OI OHI x'0700', x'5703', x'4701', x'F700', x'C700', ! XR X XH XI XHI 0, 0, 0, 0, x'ED00', x'1100', ! -- -- -- -- SLL SLLS 0, 0, 0, 0, x'EC00', x'1000', ! -- -- -- -- SRL SRLS x'2800', x'6803', x'3800', x'7803', ! LER LE LDR LD x'2820', x'6053', 0, x'7053', ! STER STE -- STD x'2A00', x'6A03', x'3A00', x'7A03', ! AER AE ADR AD x'2B00', x'6B03', x'3B00', x'7B03', ! SER SE SDR SD x'2C00', x'6C03', x'3C00', x'7C03', ! MER ME MDR MD x'2D00', x'6D03', x'3D00', x'7D03', ! DER DE DDR DD x'2910', x'6913', x'3910', x'7913', ! CER CE CDR CD ! Special purpose entries. x'0510', x'5513', x'4511', x'F510', x'C510', ! CLR CL CLH CLI CLHI x'0300', x'4300', ! BFCR BFC x'0100', x'4100', ! BALR BAL x'E650', ! LA x'D150', ! LM x'D050', ! STM x'2F00', ! FLR x'2E00', ! FXR x'EE10', ! SRA x'1200', ! CHVR x'9350', ! LBR x'E110', ! SVC x'7250', ! LME x'7150', ! STME x'F310', x'C310', ! TI THI x'0C50', x'4C51', x'4C51', ! MHR M(H) MH x'7301', ! LHL x'5113', x'6111', ! AM AHM x'7401', x'7501' ! TBT SBT !Non-uniform operations for special situations constinteger jmp=21, always=r0; ! RR(JMP,always,LINK) constinteger bal=22; ! Branch-and-link constinteger la =23; ! Load Address (RX format) constinteger lm=24, stm=25; ! Load/Store Multiple ! ** FLR below is really 25-fpbase ** constinteger flr=26-fpbase, fxr=27; ! Float/Fix (RR format only) constinteger clw=28; ! Compare Logical (same formats as AND) constinteger sra=29; ! Shift Right Arithmetic (HW IMM only) constinteger chvr=30; ! Convert to halfword value (RR only) constinteger lbr=31; ! Load Byte Register (RR only) constinteger sth=32; ! Store half-word (Short RX only) constinteger svc=33; ! Supervisor call (RX format) constinteger lme=34-fpbase; ! Used in conjunction with SVC constinteger stme=35-fpbase; ! .... ditto .... constinteger test=36; ! test halfword? immediate constinteger LHL=37; ! load unsigned halfword (for switch) constinteger AM=38; ! add-to-memory (see ASSIGN) constinteger TBT = 39, SBT = 40 constbytearray Inverted(16:21) = 0, 1, 3, 2, 5, 4 { = # < > <= >= } !ASSORTED FUNNY CONSTANTS constinteger jump=12; ! logical condition code == unconditional jump constinteger not equal=1; ! . . . branch not equal constinteger less than=2, greater than=3 constinteger less or equal=4, greater or equal=5 !CODES USED IN OUTPUT FOR 3RD. PASS constinteger tag def = 1 constinteger r ref = 2; ! Routine/fn/map/predicate reference constinteger p ref = 3; ! Prim reference constinteger sw ref = 4; ! Switch reference constinteger j ref = 5; ! Jump reference constinteger c ref = 6; ! Conditional (jump) reference constinteger code item = 7 constinteger gla item = 8 constinteger line flag = 9 constinteger line reset = 10 constinteger var diag = 11 constinteger code area = 12 constinteger lit area = 13 constinteger lit org = 14 constinteger frame patch = 15 constinteger block start = 16 constinteger block end = 17 constinteger prog end = 18 constinteger c rel = 19 constinteger g rel = 20 constinteger extern = 21 ! (external references) constinteger data ref = 4, data defn = 5 constinteger ep ref = 6, ep defn = 7 recordformat varfm(integer disp, c shortinteger format,extra,length,header, c (shortinteger xform or byteinteger flag,form), byteinteger base,type) record (varfm)array var(0:max vars) record (varfm)name decvar record (varfm)name fp, ap ownrecord (varfm) begin = 0 recordformat stackfm(integer disp, shortinteger format, extra, length, header, rt, shortinteger var no, type, (shortinteger xform or byteinteger flag,form), (short xbase or byte index, base), byte dim, oper, record (stackfm)name link) record (stackfm)array stak(0:max stack) record (stackfm)name desc asl recordformat sptfm(record (stackfm)name v) record (sptfm)array stacked(1:max depth) ! elements of USING list recordformat dfm(record (stackfm)name d, record (dfm)name link) record (dfm)array dlist(0:max stack) record (dfm)name dasl record (dfm) using ! for compiling %for/%repeat pairs recordformat cyclefm(integer cv disp, fv disp, c shortinteger lab, shadow, initial, cv form, c byteinteger reg, cv type, cv base, c fv base, temp base) record (cyclefm)array for stk(0:max cycle) record (cyclefm)name for; ! points to currently active level owninteger for stp=0 ! mechanism to minimise no of temporaries allocated shortintegerarray temps(1:max temps) owninteger temp base = 0, next temp = 0, new temp = 0 ! list terminator constrecord (*)name null == (0) recordformat labelfm(shortinteger id, tag) record (labelfm)array labels(1:max labels) ownintegerarray activity(0:fr14) = 0(*) owninteger claimed = 0 ownshortinteger control = check bits & (¬check extra) ownshortinteger diagnose = 0 ! 1: trace calls on descriptor stack handling primitives ! 2: . . . . . . . . . LOAD ! 4: . . . . . . . . . ASSIGN ! 8: . . . . . . . optimisation routines and display generated code ! 16: dump 'knowledge' list every time CHEAPEN is called with '8' bit on owninteger level = -1 owninteger main ep = 0; ! non-zero if compiling main program owninteger unassigned rtn = 0; ! non-zero if unassigned check routine pr in integer j,k,len,n,val,aparm,opr owninteger ca = 0; ! CODE ADDRESS owninteger ga = init gla; ! GLA ADDRESS owninteger lita = 0; ! Literal address: current address owninteger litmax=0; ! : limit of area claimed so far owninteger diag1 = 0; ! DIAG TABLES 1 owninteger diag2 = 0; ! DIAG TABLES 2 owninteger cc ca=0, cc reg=0; ! to remember condition code integer sym, next; ! CODE SYMBOL, NEXT SYMBOL integer vlb,vub; ! VECTOR LOWER/UPPER BOUND integer Allocate; ! Flag for array(#0) or arrayformat (=0) integer Falign {alignment of internal formats} owninteger current line = 0; ! SOURCE LINE NUMBER owninteger last line = 0 owninteger stp = 0; ! STACK POINTER integer data size; ! CURRENT DATA ITEM SIZE owninteger frame = 0; ! LOCAL STACK FRAME EXTENT owninteger extra frame = 0; ! ALLOW EXTRA FRAME FOR STATIC ARRAYS integer parms; ! START OF PARAMETER STACK integer local; ! LOCAL BASE REGISTER owninteger invert = 0, swopped = 0; ! CONDITION INVERSION FLAGS owninteger uncond jump = 0; ! ADDRESS OF CODE HOLE owninteger gtype = 0; ! 0=RECORDS, 1=PROCEDURE owninteger gmode = 0; ! NON-ZERO INSIDE PARAMETER LISTS integer decl; ! LAST-DEFINED DESCRIPTOR ownshortinteger language mask = 0; ! selects language specific options integer cheap reg; !Preferred register after ADDRESS integer otype, owntype, ownform, spec, frozen, potype integer diag type=0, diag form=0, diag size=0; ! external form/type/size longreal rvalue !! Initialised to suppress critical unassigned check when compiling itself owninteger ownval = 0, mantissa = 0; ! *order critical* integer oarea integer dim,dv integer wdisp, pdisp, gdisp owninteger block no = 0; ! Ordered by block head owninteger defns=0, specs=0, relocations=0, var diags=0 owninteger total ca = 0 owninteger last ca = -1; ! Used by 'set line' owninteger trace flag = 0; ! controls calling of DUMP TRACE routine integer jtag; ! Set by 'JUMP TO' ownstring (ident len) external id = "", alias = "", block name = "" ownstring (ident len) internal id = "" owninteger faulty=0 owninteger null string = 0 byteintegername cslen byteintegerarray current string(0:255) ! Register optimisation scratch pad owninteger Last Gpr = 1, Last Fpr = Fr0, Last EO = 1 recordformat kfm(record (kfm)name link, array, integer disp, shortinteger reg, byteinteger type, form, base, ktype) record (kfm)array knowledge(1:max knowledge) ownrecord (kfm)name klist == (0), kasl == (0) integer known regs = 0; ! bit mask: must contain at least ANYF+1 bits integer in use = 0; !counter to limit active uses !Environment control recordformat envfm(integer label, in use, known, record (kfm)name link) record (envfm)array envir(1:max envirs) owninteger envp = 0 ! Code generation routine specs routinespec rr(integer op,r1,r2) routinespec rx(integer op,r1,base,disp) routinespec rxi(integer op,r1,base,disp) routinespec rxd(integer op,r1,record (stackfm)name v) routinespec set line ! >> SHOW << routine show(record (stackfm)name v) write(v_varno,2); print symbol(':') write(v_type,3); write(v_form,2); write(v_flag,2) write(v_base,3); write(v_disp,5) write(v_length,3) write(v_extra,3); write(v_format,3) write(v_header,3); write(v_dim,3) if v_oper # 0 start write(v_oper,2); newline print string(" +") show(v_link) else newline finish end ! >> ABORT << routine abort(integer code) record (dfm)name dd integer j select output(report) print string("*Compiler error '") print symbol( (code>>j)&255 ) for j = 24,-8,0 print string("' at line"); write(current line,1) newline print string("Please seek assistance!!"); newline if stp # 0 start print string("STACK:"); newline show(stacked(j)_v) for j = 1,1,stp finish unless using_link == null start print string("USING:"); newline dd == using_link cycle show(dd_d) dd == dd_link; exit if dd == null repeat finish select output(object) signal 15,15; ! %IF diagnose < 0 end ; ! abort ! >> WARN << routine warn(integer n) switch w(1:8) select output(report) print string("*WARNING: line") write(current line, 1); print string(": ") -> w(n) w(1): print string("division by zero"); -> at w(2): print string("Illegal FOR"); -> at w(3): print string("Non-local control variable?"); -> at w(4): print string("Invalid parameter for READ SYMBOL"); -> at w(5): print string("String constant too long"); -> at w(6): print string("No. of shifts outwith 0..31"); -> at w(7): print string("Illegal constant exponent"); -> at w(8): print string("Numerical constant too big"); -> at at: newline select output(object) end ! >> MONITOR << routine monitor(record (stackfm)name v, string (15) text) select output(report) print string(text); print symbol(':') spaces(9-length(text)) show(v) select output(object) end ! >> FLOATING << predicate floating(record (stackfm)name v) ! check descriptor for floating point quantity true if (v_type >= reals and v_type # 255) or (v_oper # 0 c and v_link_type >= reals) true if v_oper >= rexp false end ! >> ZERO << predicate zero(record (stackfm)name v) ! CHECK DESCRIPTOR FOR (INTEGER) ZERO false if v_disp # 0 or v_base # 0 or constant # v_form # AV in S false if v_oper # 0 true end ! >> CONST << predicate const(record (stackfm)name v) ! CHECK DESCRIPTOR FOR CONSTANT (INTEGER) VALUE false unless v_form = constant and v_oper = 0 false if v_type > byte true end integerfn Min Record Size(record (stackfm)name A, B) integer N, M N = A_Format; N = Var(N)_Length&x'FFFF' if N # 0 M = B_Format; M = Var(M)_Length&x'FFFF' if M # 0 N = M if N = 0 or (M # 0 and M < N) result = N if N > 0 Abort(m'Rec0') end ! >> SAME << integerfn POWER(integer n) integer j, ref ref = 1 for j = 1, 1, 14 cycle ref = ref<<1 if ref >= n start if ref = n then result = j else result = -1 finish repeat result = -1 end predicate same(record (stackfm)name v,w) ! Test whether or not V and W describe the same object. true if v_disp = w_disp and v_base = w_base c and v_type = w_type and v_form = w_form and v_extra = w_extra false end ! >> IN FREE REG << predicate in free reg(record (stackfm)name v) ! TRUE if v is in a useable register false unless v_form = v in r and activity(v_base) <= 1 true end ! >> TEMP << integerfn temp ! Allocate a temporary 4 bytes long integer t if next temp = new temp start ; ! no spare temps outstanding t = (frame+3)&(¬3) frame = t+4 result = t if new temp = max temps; ! temp buffer overflow new temp = new temp + 1 temps(new temp) = t finish next temp = next temp + 1 result = temps(next temp)&x'FFFF' end ! >> TAG << integerfn tag integer s1, s2 s1 = next readsymbol(s2) readsymbol(next) result = s1<<8!s2 end ! >> GET D << routine get d longreal p integer i, n real ten,one n = 10 ; rvalue = n {initial base} n = 1; one = n n = tag; read symbol(next); ! Skip comma BASE: ten = rvalue rvalue = 0 cycle sym = next; read symbol(next) exit if sym = '.' n = n-1 -> power if sym = '@' -> base if sym = '_' sym = sym-'A'+'0'+10 if sym >= 'A' rvalue = rvalue*ten+(sym-'0') -> SIGN if n = 0 repeat p = one cycle n = n-1; -> SIGN if n = 0 sym = next; read symbol(next) -> POWER if sym = '@' sym = sym-'A'+'0'+10 if sym >= 'A' p = p/ten rvalue = rvalue + (sym-'0')*p repeat POWER: n = tag n = n ! 16_FFFF0000 if n&16_8000 # 0 rvalue = rvalue * (ten^n) SIGN: ! sign of whole value if next = 'U' start read symbol(next) rvalue = -rvalue finish end ! >> RELEASE << routine release(integer reg) ! Hazard the value in a register abort(m'REL1') if reg > fr14 return if reg = 0 or activity(reg) < 0; ! LOCKED activity(reg) = activity(reg)-1 abort(m'REL2') if activity(reg) < 0 claimed = claimed - 1 end ! >> CLAIM << routine claim(integer reg) ! Cherish the value in a register abort(m'CLM1') if reg > fr14 return if reg = 0 or activity(reg) < 0 activity(reg) = activity(reg)+1 claimed = claimed+1 end routinespec forget reg(integer mask) routinespec forget all routinespec forget var(record (stackfm)name v) ! >> HAZARD << routine hazard(integer reg) ! Protect the value in register REG by storing in a temporary. integer n, t, tot record (dfm)name p record (stackfm) u routine mod(record (stackfm)name v) switch sw(0:a in rec) v_base = local n = n-1 -> sw(v_form) sw(a in rec): sw(av in rec): sw(v in rec): if tot = 1 start claim(reg); rx(lw,reg,reg,v_extra) u_type = integers v_extra = t -> OUT2 finish sw(constant): abort(m'HAZ1') sw(v in s): if v_disp = 0 start v_disp = t; v_form = a in s; ->out1 finish sw(a in s): sw(av in s): ! change (X in S) to (X in REC) v_form = v_form + 3; v_extra = t; -> OUT1 sw(v in r): v_form = v in s; v_disp = t v_type = u_type OUT1: v_flag = v_flag ! assigned OUT2: end n = activity(reg); return if n <= 0; ! NOT IN USE OR CLAIMED tot = n claimed = claimed - n activity(reg) = 0 t = temp; ! ** needs a parameter to deal with 8-byte reals ** u_type = integers u_type = reals if FR0 <= reg <= FR14 p == using_link cycle exit if p == null mod(p_d) if p_d_base = reg p == p_link repeat u_xbase = local; u_disp = t u_xform = V in S ! (assigned << 8) rxd(st,reg,u) forget var(u) abort(m'HAZ2') if n # 0; ! USE STILL OUTSTANDING end ! >> HAZARD ALL << routine hazard all integer j forget reg(-1) if claimed # 0 start ; ! at least one register claimed hazard(j) for j = r0,1,fr14 finish end ! REGISTER OPTIMISATION ROUTINES constinteger register contents = 1 routine Reset Optimisation Data integer J Last Gpr = 1 Last Fpr = Fr0 Last EO = 1 Envp = 0 Known Regs = -1 In Use = 0 Kasl == Null Klist == Null for j = 1,1,max knowledge cycle knowledge(j)_Link == Kasl Kasl == knowledge(j) repeat for j = 1,1,max envirs cycle Envir(j)_Label = 0 Envir(j)_Link == Null repeat end ! >> DUMP OPT LIST << routine dump opt list record (kfm)name p select output(report) p == klist if p == null start print string("*opt list empty") newline else cycle write(p_type,1); write(p_form,1) write(p_disp,3); print symbol('(') write(p_base,-1); print string(") =") write(p_reg,1); newline p == p_link repeat until p == null finish select output(object) end ; ! dump opt list ! >> K ENTRY << record (kfm)map k entry(record (stackfm)name v, integer fuzz) record (kfm)name p,q fuzz = ¬fuzz p == k list q == null while not p == null cycle -> FOUND if (p_disp!!v_disp)&fuzz = 0 and p_base = v_base q == p p == p_link repeat result == null; ! failure FOUND: if not q == null start ; ! promote if not first item already q_link == p_link p_link == klist klist == p finish result == klist end ; ! k entry ! >> NEW KCELL << record (kfm)map new kcell record (kfm)name p, q integer n if kasl == null or in use >= max use start ; ! no free cells left ! In extremis so reclaim last item from KLIST. p == klist; q == null n = max use cycle n = n-1 exit if p_link == null q == p p == p_link repeat abort(m'OPT1') if n # 0 q_link == null; ! truncate KLIST p_link == kasl; kasl == p; !give on back in use = in use-1 finish p == kasl; kasl == kasl_link in use = in use+1; abort(m'Opt3') if in use > max use p = 0 result == p end ; ! new kcell ! >> ASSOCIATE << routine associate(record (stackfm)name v, integer reg) record (kfm)name p return if reg = R0 or V_Base = Reg p == k entry(v,0) if p == null start ; ! new entry p == new kcell p_link == klist klist == p else ; ! re-use this cell forget reg(1<<p_reg) finish p_reg = reg p_base = v_base p_disp = v_disp p_type = v_type p_form = v_form p_ktype = register contents known regs = known regs ! (1<<reg) known regs = known regs ! (1<<p_base) if activity(p_base) >= 0; ! unlocked ? end ; ! associate ! >> CHEAPEN << routine cheapen(record (stackfm)name v, integer mode) !! modes: >= 0: looking for value ! < 1: looking for address record (kfm)name p integer reg, form, type form = v_form; type = v_type p == k entry(v,0) return if p == null v_flag = v_flag ! assigned if p_form = V in S; ! it's at least assigned return if p_reg = 0; !*psr* Nothing known cheap reg = p_reg if form # AinS and p_type = Type return if mode < 0 and form = V in S; ! V in S on left-hand side reg = p_reg if form = A in S and p_type = integers and p_form = V in S start release(v_base); claim(reg) v_base = reg; v_disp = 0; v_Xform = V in S {changed to Xform - PSR} cheapen(v,mode) else return if p_type # type or p_form # form release(v_base); claim(reg) v_base = reg; v_disp = 0; v_Xform = V in R {changed to Xform - PSR} finish if diagnose < 0 start monitor(v, "CHEAPENED") dump opt list if diagnose & 16 # 0 finish end ; ! cheapen !!! * * * * * This needs to be a bit brighter * * * * * ! >> FORGET VAR << routine forget var(record (stackfm)name v) record (kfm)name p !!!!! p == k entry(v, align) !!!!! forget reg(1<<p_reg) %unless p == null cycle p == k entry(V, align) return if p == null p_base = anyf+1 {invalid entry} repeat end ; ! forget var ! >> FORGET REG << routine forget reg(integer reg mask) record (kfm)name p return if known regs & reg mask = 0; ! for speed: nothing to do reg mask = reg mask & (¬1); ! R0 = 1 not 0 known regs = known regs & (¬reg mask) p == klist if reg mask < 0 start ; ! forget the lot while not p == null cycle p_base = anyf+1 if regmask & (1<<p_base) # 0; ! invalidate entry p_reg = 0 p == p_link repeat else ; ! selective forget while not p == null cycle p_base = anyf+1 if reg mask & (1<<p_base) # 0; ! invalidate entry p_reg = 0 if reg mask & (1<<p_reg) # 0; ! forget reg association p == p_link repeat finish ! Clean up any old kcells which can be recovered easily while klist ## null and klist_base = anyf+1 cycle p == klist; klist == klist_link p_link == kasl kasl == p in use = in use-1 repeat abort(m'Use?') if in use < 0 end ; ! forget reg ! >> FORGET ALL << routine forget all record (kfm)name p if not klist == null start p == klist cycle in use = in use-1 exit if p_link == null p == p_link repeat p_link == kasl kasl == klist klist == null finish abort(m'Fall') unless in use = 0 known regs = 0 end ; ! forget all !environment control record (envfm)map environment(integer label) record (envfm)name E integer j if label > 0 start for j = 1,1,max envirs cycle E == envir(j) result == E if E_label = label repeat finish result == null end record (envfm)map new env(record (envfm)name E) record (kfm)name K if E == null start envp = envp+1; envp = 1 if envp > max envirs e == envir(envp) finish k == E_link unless k == null start k == k_link while k_link ## null k_link == kasl kasl == E_link finish E_in use = 0 E_label = 0 E_link == null result == E end record (kfm)map Ecopy(record (kfm)name L) record (kfm)name K result == null if l == null abort(m'Ecop') if kasl == null k == kasl; kasl == k_link k = l k_link == Ecopy(l_link) result == k end routine restore environment(integer label) record (envfm)name E record (envfm) temp temp_link == klist e == new env(temp) {release current environment} E == environment(label) if E == null start klist == null known regs = 0 in use = 0 else klist == Ecopy(E_link) known regs = E_known in use = E_in use finish end routine remember environment(integer label) record (envfm)name E return if label <= 0 E == environment(label) E == new env(E) E_label = label E_known = known regs E_in use = in use E_link == Ecopy(klist) end routine merge environment(integer label) record (ENVFM)name e record (kfm)name K, end, X record (kfm) khead routine MERGE(record (kfm)name K) record (kfm)name p p == klist while p ## null cycle if p_disp = k_disp and p_reg = k_reg and p_base = k_base and p_form = k_form and p_type = k_type and p_ktype= k_ktype start {*****Beware when array opt is put in***} end_link == k end == k E_known = E_known ! (1<<p_reg) ! (1<<p_base) E_in use = E_in use+1 return finish p == p_link repeat k_link == kasl; kasl == k end E == environment(label) if E ## null start k == E_link e_link == null e_in use = 0 e_known = 0 khead_link == null; end == khead while k ## null cycle x == k_link merge(k) k == x repeat end_link == null e_link == khead_link finish end ! >> GPR << integerfn gpr ! Get a general (integer) register constinteger nregs=8 constbyteintegerarray pref(1:nregs) = P1, P2, R4, R9, R10, R11, R3, R12 integer r,j,mask mask = known regs cycle for j = 1,1,nregs cycle Last Gpr = Last Gpr-1; Last Gpr = nregs if Last Gpr = 0 r = pref(Last Gpr) result = r if activity(r) = 0 and mask & (1<<r) = 0 repeat exit if mask = 0 mask = 0 repeat hazard(R4) result = R4 end ! >> EVEN/ODD PAIR << integerfn even odd pair ! Get an even/odd (integer) register pair ! the odd register is returned ! registers are hazarded here constinteger regs = 3 constbyteintegerarray even(1:regs) = r2, r10, r4 integer j,r,mask mask = known regs cycle for j = 1,1,regs cycle Last EO = Last EO-1; Last EO = regs if Last EO = 0 r = even(Last EO) result = r+1 if activity(r) = 0 and activity(r+1) = 0 c and mask & (3<<r) = 0 repeat exit if mask = 0 mask = 0 repeat hazard(r2); hazard(r3); result = r3 end ! >> FPR << integerfn fpr ! get a floating point register integer j,mask mask = known regs cycle for j = fr0,1,fr14 cycle Last Fpr = Last Fpr-1; Last Fpr = fr14 if Last Fpr = fr0-1 result = Last Fpr if activity(Last Fpr) = 0 repeat exit if mask = 0 mask = 0 repeat hazard(fr0) result = fr0 end !OBJECT FILE HANDLING ROUTINES ! >> PUT << routine put(integer n) print symbol(n>>8); print symbol(n&255) end ! >> SELECT LITERAL AREA << routine select literal area integer k print symbol(lit area) abort(m'DMP1') if ca < 0 k = lita; lita = ca; ca = k end ! >> SELECT CODE AREA << routine select code area integer k abort(m'DMP2') if ca > 0 k = lita; lita = ca; ca = k print symbol(code area) end routine phex(integer n) integer j,k spaces(2) for j = 12,-4,0 cycle k = (n>>j)&15 if k <= 9 then k = k+'0' else k = k-10+'A' print symbol(k) repeat end ! >> DUMP TAG << routine dump tag(integer tag, type) conststring (7)array s(tag def:c ref) = " defn", " r ref", " p ref", " sw ref", " j ref", " c ref" select output(report) print symbol('*'); write(ca,-3) print string(s(type)) write(tag,1) newline select output(object) end ; ! dump tag ! >> DUMP << routine dump(integer p,val) integer k select output(report) if p = m'CA' start print string("CA "); k = ca else print string("GA "); k = ga finish write(k-2,-3); print symbol(':') phex(val) newline select output(object) end ; ! dump ! >> CPUT << routine cput(integer n) ! Output one halfword to code area print symbol(code item) print symbol(n>>8); print symbol(n&255) ca = ca+2 dump(m'CA',n) if diagnose < 0 end ! >> GPUT << routine gput(integer n) ! Output one halfword to gla area print symbol(gla item) print symbol(n>>8); print symbol(n&255) ga = ga+2 dump(m'GA',n) if diagnose < 0 end ! >> CWORD << routine cword(integer n) cput(n>>16); cput(n) end ! >> LIT BYTE << routine lit byte(integer n) owninteger v=0,f=0 f = ¬f if f=0 start ca = ca+1; cput(v<<8 + n&255) else v = n; ca = ca-1 finish abort(m'DMP3') unless ca <= 0 end ! >> GWORD << routine gword(integer n) gput(n>>16); gput(n&x'FFFF') end ! >> GWORD REL << routine gword rel(integer n) ! Word in GLA modified at load-time by gla base address - used to relocate ! %ownarray headers. gput(n>>16); gput(n&x'FFFF') print symbol(g rel); relocations = relocations + 1 end ; ! gword rel ! >> GWORD CREL << routine gword crel(integer n) ! Word in GLA modified at load-time by code base address - used to relocate ! %constarray headers gput(n>>16); gput(n&x'FFFF') print symbol(c rel); relocations = relocations+1 end ; ! GWORD CREL ! >> GBYTE << routine gbyte(integer n) owninteger v=0, f=0 f = ¬f if f = 0 start ga = ga-1; gput(v<<8 + n&255) else v = n; ga = ga+1 finish end ! >> GFIX << routine gfix(integer align) gbyte(0) while ga&align # 0 end ! >> DEFINE TAG << routine define tag(integer ref) integer k select output(direct) print symbol(tag def) print symbol(ref>>8); print symbol(ref&255) k = ca>>1; ! ******* Halfword units print symbol(k>>8); print symbol(k&255) select output(object) dump tag(ref,tag def) if diagnose < 0 end ; ! define tag ! >> DEFINE REFERENCE << routine define reference(integer ref, type) integer k set line if current line # last line select output(direct) print symbol(type) print symbol(ref>>8); print symbol(ref&255) k = ca>>1; ! ******** Halfword units print symbol(k>>8); print symbol(k&255) select output(object) dump tag(ref,type) if diagnose < 0 print symbol(type) if type = r ref start print symbol(ref>>8); print symbol(ref&255) finish end ; ! define reference ! >> CLAIM LITERAL << routine claim literal(integer size,align) integer k abort(m'DMP4') if ca < 0 or litmax > 0 if lita&1 # 0 start ; ! odd no. of bytes select literal area lit byte(0) select code area finish litmax = -((-litmax+size+align)&(¬align)) lita = litmax k = (-lita)>>1 print symbol(lit org); put(k); ! Tell pass 3 end ; ! claim literal ! >> SET LINE << routine set line integer flag return if ca < 0; !in literal area if current line-last line # 1 then flag = line reset c else flag = line flag select output(direct) print symbol(flag); put(current line) if flag = line reset if diagnose < 0 start select output(report) print string("-->line"); write(current line,1) newline finish select output(object) print symbol(flag); put(current line) if flag = line reset last line = current line; last ca = ca end ; ! set line ! >> DESCRIBE << routine describe(integer base,disp, string (ident len)name xsym) ! Generate a full description of the variable specified by (base,disp) ! Assumes that DIAG SIZE, DIAG TYPE, DIAG FORM, OTYPE are appropriately set. integer size,type integer j,k constbyteintegerarray compressed type(0:13) = 1, 2, 3, 4, 5, 0(3), 6, 0(4), 7 ! integer real string record byte short long real length(xsym) = extern len if length(xsym) > extern len print symbol(length(xsym)) print symbol(charno(xsym,j)) for j = 1,1,length(xsym); ! name return if base < 0 size = diag size; type = diag type size = 1 if diag type >= 3 or diag form > 2 or size = 0 type = 1 if diag type <= 0 k = (size-1) << 2 + (type-1) j = 0 j = x'80' if Otype # 0 and Spec # 0 {external data spec} print symbol(otype) print symbol( compressed type(k) << 4 ! DIAG FORM ! J) j = actual(base)<<20 + disp&x'000FFFFF' print symbol(j>>16); print symbol(j>>8); print symbol(j) end ; ! describe ! >> SET DIAG << routine set diag(integer base,disp) ! Implicit parameters: DIAG TYPE DIAG FORM DIAG SIZE OTYPE var diags = var diags + basic vdiag var diags = var diags + extra vdiag if length(internal id) > short ident print symbol(var diag); describe(base,disp,internal id) end ! >> EXTERNAL LINK << routine external link(integer ref type,data size,addr) !Note that ADDR is ignored when defining procedure entry points ! it is assumed that the link is set IMMEDIATELY before the entry point. integer k abort(m'DMP5') unless data ref <= ref type <= ep defn if ref type&1 # 0 then defns = defns+1 else specs = specs+1 print symbol(extern) print symbol(ref type) put(data size//2); ! Halfwords for pass3 k = gla; k = code if ref type = ep defn describe(k,addr//2,external id) if ref type&1 = 0 start ; !a spec gword(0); gword(0) if ref type = ep ref then gword(0) else gword(-1) finish end ! >> CLOSE FILES << routine close files select output(direct) print symbol(prog end) put(total ca>>1); put((-litmax)>>1); put(ga>>1); ! Halfword units put(defns); put(specs); put(relocations) print symbol(0); ! to prevent potential trouble with binary 4 = EOF close output select output(object); print symbol(prog end) close output end ; ! close files ! code generation routines ! >> RXD << ! = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = ! B a s i c C o d e G e n e r a t o r ! routine RXD(integer op, r1, record (stackfm)name v) integer index, mask, code, format integer type, form, base, disp, x integer k, old ca record (stackfm) u constbyteintegerarray type index(integers:reals+1) = 1, 2, 7, 0(3), 1, 0 ! integer short byte reals reall old ca = ca type = v_type; form = v_form base = v_base; disp = v_disp; x = v_index op = op + fp base if r1 >= FR0 mask = op index(op); index = mask&255 set line if last line # current line if form = constant or form = AV in S start ; ! RXI abort(m'RXDx') if x # 0 if disp = 0 and base # 0 and LSH # op # RSH and op # SRA start ! optimise: LHI x,0(y) => LR x,y ! remove: LHI x,0(x) if r1 # base or op # LW start u_xbase = base; u_disp = 0; ! **** u_disp otherwise unassigned **** u_form = V in R; rxd(op,r1,u) return finish code = x'10'; !(psr) preserve CC at end - see later else if op = LW and r1 = base and 15 >= disp >= -15 ! LHI x, 15(x) => AIS x,15 ! LHI x,-15(x) => SIS x,15 op = add if disp < 0 start op = sub; disp = -disp finish u_form = constant; u_xbase = 0; u_disp = disp; rxd(op,r1,u) release(base) return else if op = LSH and disp = 1 and base = 0 ! SLLS x,1 => AR x,x claim(r1) u_xbase = r1; u_disp = 0 u_form = V in R; rxd(add,r1,u); return else ; ! general case (RXI) abort(m'RXD1') if mask&FWIMM = 0 and LSH # op # RSH and op # SRA index = index + 3; ! fullword immediate format = 0 if 15>=disp>=-15 and base=0 and (SF IMM+INV IMM)&mask # 0 start if disp >= 0 start format = 2 else format = 3; disp = -disp finish else if 32767 >= disp >= -32768 format = 1 finish code = op code(index + format) if format >= 2 start cput(code&x'FF00' + actual(r1)<<4 + disp) else cput(code&x'FF00' + actual(r1)<<4 + actual(base)) cput(disp>>16) if format = 0; ! fullword immediate ? cput(disp) finish finish else if form = V in R; ! register-register operation abort(m'RXD2') if r1 = 0 or base = 0 or x # 0 code = op code(index); ! ** N.B. op code(index + 0) really ...... if code&x'20' # 0 start ; ! STR => LR etc. k = r1; r1 = base; base = k finish cput(code&x'FF00' + actual(r1)<<4 + actual(base)) else ; ! RX (integer,real,short,byte) abort(m'RXD3') if r1 = 0 or base = R0 format = type index(type); abort(m'RXD4') if format = 0 code = op code(index + format) abort(m'RXD5') if (code&15)&disp # 0 cput(code&x'FF00' + actual(r1)<<4 + actual(base)) unless 0 <= disp <= 16383 and x = 0 start cput(x'4000' + actual(x)<<8 + (disp>>16)&255) finish cput(disp) finish release(base) if base > 0; !(PSR) release(x) if x # 0 if code&x'40' # 0 start ; ! leaves cond code completely unchanged cc ca = cc ca + ca - old ca else if code&x'10' = 0; ! cond code relative to zero ? cc ca = ca; cc reg = r1 finish end ; ! of 'RXD' ! = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = ! >> RR << routine rr(integer op,r1,r2) record (stackfm) v v_xbase = r2; v_disp = 0 v_type = integers; v_type = reals if r1 >= FR0 v_form = V in R; rxd(op, r1, v) end ! >> RXI << routine rxi(integer op, r1, base, disp) record (stackfm) v v_xbase = base; v_disp = disp v_type = integers v_form = constant; rxd(op, r1, v) end ! >> RX << routine rx(integer op, r1, base, disp) record (stackfm) v v_xbase = base; v_disp = disp v_type = integers; v_type = reals if r1 >= FR0 v_form = V in S; rxd(op, r1, v) end ! >> SKIP << routine skip(integer half words, condition) ! Plant a short forward jump to skip over unwanted code sequence: ! skips forward the number of halfwords specified NOT COUNTING the ! code dumped to effect the skip ! Must be used with care as it doesn't account automatically for register ! contents. constshortintegerarray jump(0:5) = x'2330', x'2130', x'2110', x'2120', x'2320', x'2310' ! BES BNES BMS BPS BNPS BNMS Condition = Inverted(Condition) if Condition&16 # 0 abort(m'SKP1') unless 0 < halfwords <= 14 and 0 <= condition <= 5 cput( jump(condition) ! (halfwords + 1) ) end ! >> MACHINE CODE << routine machine code constinteger branch = 1 constinteger rr = 2 constinteger indexed = 4 constinteger ri1 = 8 constinteger ri2 = 16 !*delete* constinteger mc entries = 204 constintegerarray mcop(1:mc entries) = x'00000041', x'00000042', x'00000043', x'00000044', x'0000004C', ! A B C D L x'0000004D', x'0000004E', x'0000004F', x'00000053', x'00000058', ! M N O S X x'00001004', x'00001005', x'00001008', x'00001009', x'0000100C', ! AD AE AH AI AL x'0000100D', x'00001012', x'00001084', x'00001085', x'00001088', ! AM AR CD CE CH x'00001089', x'0000108C', x'00001092', x'000010C3', x'000010C5', ! CI CL CR BC BE x'000010C7', x'000010CC', x'000010CD', x'000010CF', x'000010D0', ! BG BL BM BO BP x'000010D2', x'000010DA', x'00001144', x'00001145', x'00001148', ! BR BZ DD DE DH x'00001152', x'00001304', x'00001305', x'00001308', x'00001312', ! DR MD ME MH MR x'00001341', x'00001342', x'00001344', x'00001345', x'00001348', ! LA LB LD LE LH x'00001349', x'0000134D', x'00001352', x'00001383', x'00001388', ! LI LM LR OC OH x'00001389', x'00001392', x'000013C8', x'000013C9', x'000013D2', ! OI OR NH NI NR x'00001484', x'00001485', x'00001488', x'00001489', x'00001492', ! SD SE SH SI SR x'00001493', x'00001494', x'000014C2', x'000014C4', x'000014C8', ! SS ST RB RD RH x'00001549', x'00001553', x'00001582', x'00001584', x'00001588', ! TI TS WB WD WH x'00001648', x'00001649', x'00001652', x'000400CC', x'00040112', ! XH XI XR ABL AER x'00040152', x'00040213', x'00040249', x'0004024D', x'0004054C', ! ADR AIS AHI AHM ATL x'000420D4', x'00042112', x'00042152', x'00042249', x'00042342', ! CBT CER CDR CHI CLB x'00042348', x'00042349', x'00042352', x'0004300C', x'00043092', ! CLH CLI CLR BAL BCR x'00043112', x'00043185', x'00043192', x'000431C3', x'00043312', ! BER BGE BGR BFC BMR x'00043345', x'00043352', x'00043392', x'000433C3', x'000433C5', ! BLE BLR BOR BNC BNE x'000433CC', x'000433CD', x'000433CF', x'000433D0', x'000433DA', ! BNL BNM BNO BNP BNZ x'00043452', x'00043543', x'00043648', x'000436D2', x'00045112', ! BPR BTC BXH BZR DER x'00045152', x'00045252', x'00047352', x'00047652', x'0004C112', ! DDR DHR FLR FXR MER x'0004C152', x'0004C252', x'0004D093', x'0004D0D2', x'0004D112', ! MDR MHR LCS LBR LER x'0004D152', x'0004D213', x'0004D249', x'0004D24C', x'0004D304', ! LDR LIS LHI LHL LMD x'0004D305', x'0004E092', x'0004E249', x'0004F249', x'0004F390', ! LME OCR OHI NHI NOP x'00052090', x'000520D4', x'00052112', x'00052152', x'00052213', ! SCP SBT SER SDR SIS x'00052249', x'00052341', x'00052492', x'000524C1', x'000524CC', ! SHI SLA SSR SRA SRL x'000524D2', x'00052542', x'00052544', x'00052545', x'00052548', ! SRR STB STD STE STH x'0005254D', x'000525C3', x'000530CC', x'000530D2', x'000530D4', ! STM SVC RBL RBR RBT x'00053152', x'00053252', x'0005334C', x'000534CC', x'0005354C', ! RDR RHR RLL RRL RTL x'000550D4', x'00055249', x'000560D2', x'00056152', x'00056252', ! TBT THI WBR WDR WHR x'00059249', x'010895D2', x'0108D249', x'010C0352', x'010C6112', ! XHI CHVR CLHI BALR BGER x'010C7092', x'010C7092', x'010C70D3', x'010C71D3', x'010CD112', ! BFCR BFCR BFBS BFFS BLER x'010CF092', x'010CF112', x'010CF312', x'010CF352', x'010CF392', ! BNCR BNER BNMR BNLR BNOR x'010CF452', x'010CF6D2', x'010D5092', x'010D50D3', x'010D51D3', ! BNPR BNZR BTCR BTBS BTFS x'010D9345', x'01111492', x'011190D2', x'01119252', x'011CD152', ! BXLE EPSR EXBR EXHR FLDR x'011D9152', x'01351497', x'013CE452', x'014883D4', x'0148D241', ! FXDR LPSW NOPR SINT SLHA x'0148D24C', x'0148D353', x'01493241', x'0149324C', x'01493353', ! SLHL SLLS SRHA SRHL SRLS x'014950D2', x'01495304', x'01495305', x'424C3C72', x'424C3C76', ! STBR STMD STME CRC12 CRC16 x'4D452592', x'52349353', x'524C9353', x'55340545' ! LPSWR SLHLS SRHLS TLATE constshortintegerarray opflags(1:mc entries) = x'5A04', x'4305', x'5904', x'5D04', x'5804', x'5C04', x'5404', x'5604', ! A B C D L M N O x'5B04', x'5704', x'7A04', x'6A04', x'4A04', x'FA10', x'D501', x'5104', ! S X AD AE AH AI AL AM x'0A02', x'7904', x'6904', x'4904', x'F910', x'5504', x'0902', x'4285', ! AR CD CE CH CI CL CR BC x'4335', x'4225', x'4285', x'4215', x'4245', x'4225', x'0303', x'4335', ! BE BG BL BM BO BP BR BZ x'7D04', x'6D04', x'4D04', x'1D02', x'7C04', x'6C04', x'4C04', x'1C02', ! DD DE DH DR MD ME MH MR x'E604', x'D304', x'7804', x'6804', x'4804', x'F810', x'D104', x'0802', ! LA LB LD LE LH LI LM LR x'DE04', x'4604', x'F610', x'0602', x'4404', x'F410', x'0402', x'7B04', ! OC OH OI OR NH NI NR SD x'6B04', x'4B04', x'FB10', x'0B02', x'DD04', x'5004', x'D704', x'DB04', ! SE SH SI SR SS ST RB RD x'D904', x'F310', x'E004', x'D604', x'DA04', x'D804', x'4704', x'F710', ! RH TI TS WB WD WH XH XI x'0702', x'6504', x'2A02', x'3A02', x'2602', x'CA08', x'6104', x'6404', ! XR ABL AER ADR AIS AHI AHM ATL x'7704', x'2902', x'3902', x'C908', x'D404', x'4504', x'F510', x'0502', ! CBT CER CDR CHI CLB CLH CLI CLR x'4104', x'0281', x'0333', x'4315', x'0223', x'4304', x'0213', x'4325', ! BAL BCR BER BGE BGR BFC BMR BLE x'0283', x'0243', x'4385', x'4235', x'4385', x'4315', x'4345', x'4325', ! BLR BOR BNC BNE BNL BNM BNO BNP x'4235', x'0223', x'4204', x'C004', x'0333', x'2D02', x'3D02', x'0D02', ! BNZ BPR BTC BXH BZR DER DDR DHR x'2F02', x'2E02', x'2C02', x'3C02', x'0C02', x'2502', x'9302', x'2802', ! FLR FXR MER MDR MHR LCS LBR LER x'3802', x'2402', x'C808', x'7304', x'7F04', x'7204', x'9E02', x'C608', ! LDR LIS LHI LHL LMD LME OCR OHI x'C408', x'4205', x'E304', x'7504', x'2B02', x'3B02', x'2702', x'CB08', ! NHI NOP SCP SBT SER SDR SIS SHI x'EF00', x'9D02', x'EE00', x'EC00', x'ED00', x'D204', x'7004', x'6004', ! SLA SSR SRA SRL SRR STB STD STE x'4004', x'D004', x'E104', x'6704', x'9702', x'7604', x'9B02', x'9902', ! STH STM SVC RBL RBR RBT RDR RHR x'EB00', x'EA00', x'6604', x'7404', x'C308', x'9602', x'9A02', x'9802', ! RLL RRL RTL TBT THI WBR WDR WHR x'C708', x'1202', x'C508', x'0102', x'0313', x'0302', x'1302', x'2202', ! XHI CHVR CLHI BALR BGER BFCR BFCR BFBS x'2302', x'0323', x'0383', x'0233', x'0313', x'0383', x'0343', x'0323', ! BFFS BLER BNCR BNER BNMR BNLR BNOR BNPR x'0233', x'0202', x'2002', x'2102', x'C104', x'9502', x'9402', x'3402', ! BNZR BTCR BTBS BTFS BXLE EPSR EXBR EXHR x'3F02', x'3E02', x'C205', x'0203', x'E201', x'CF08', x'CD08', x'1102', ! FLDR FXDR LPSW NOPR SINT SLHA SLHL SLLS x'CE08', x'CC08', x'1002', x'9202', x'7E04', x'7104', x'5E04', x'5F04', ! SRHA SRHL SRLS STBR STMD STME CRC12 CRC16 x'1801', x'9102', x'9002', x'E704' ! LPSWR SLHLS SRHLS TLATE !*end* string (7) opcode record (varfm)name v integer op, base, disp, index, flags, p, n, reg routine mc error(string (255) s) selectoutput(0) printsymbol('*') write(current line, 3) space printstring(opcode) printstring(": ") printstring(s) newline selectoutput(object) while sym # ';' cycle sym = next; readsymbol(next) repeat end routine get opcode opcode = ""; op = 0 cycle sym = next; readsymbol(next) exit if sym = '_' if length(opcode) # 6 start op = op<<6!!sym opcode = opcode.tostring(sym) finish repeat sym = next; readsymbol(next) end integerfn find opcode integer high, low, p high = mc entries; low = 1 while high >= low cycle p = (high+low)>>1 result = p if mcop(p) = op if mcop(p) > op then high = p-1 else low = p+1 repeat mc error("unknown operation") result = 0 end predicate value(integername n) n = 0 false unless '0' <= sym <= '7' cycle n = n<<3!(sym-'0') sym = next; readsymbol(next) true unless '0' <= sym <= '7' repeat end predicate register(integername r) false unless value(r) false unless 0 <= r <= 15 true end predicate deal with plus minus integer sign, n true unless sym = '+' or sym = '-' sign = sym; sym = next; readsymbol(next) unless value(n) start mc error("invalid offset") false finish n = -n if sign = '-' disp = disp+n true end base = -1; index = -1; disp = 0 get opcode p = find opcode; return if p = 0 flags = opflags(p) if flags&branch # 0 start reg = flags>>4&15; !cond-code else unless register(reg) mc error("register 1?"); return else if sym # ',' mc error("comma missing"); return else sym = next; readsymbol(next) finish if flags&rr # 0 start unless register(base) start mc error("register 2?"); return finish else if sym = ' '; !named operand n = tag sym = next; readsymbol(next) v == var(n) disp = v_disp if v_form = pgm label start ; !%label define reference(disp&X'FFF', r ref); !make it look like a routine disp = 0; Base = Code return unless deal with plus minus else base = actual(v_base) unless v_base = 0 return unless deal with plus minus if sym = '(' start ->ix if base > 0 ->ib finish finish else if sym = '-' and deal with plus minus start !only needs the side-effect of deal with .. else unless value(disp) mc error("displacement?"); return finish return unless deal with plus minus if sym = '(' start ib: sym = next; readsymbol(next) unless register(base) start mc error("base register?"); return finish if sym = ',' start ix: sym = next; readsymbol(next) if flags&indexed = 0 start mc error("no double indexed form"); return finish unless register(index) start mc error("index register?"); return finish finish if sym # ')' start mc error(") missing"); return finish sym = next; readsymbol(next) finish finish if sym # ';' start mc error("form?"); return finish base = 0 if base < 0 index = 0 if index < 0 base = index and index = 0 if base = 0 and index # 0 cput(flags&x'FF00'+reg<<4+base) if flags&ri1 # 0 start cput(disp&x'FFFF') else if flags&ri2 # 0 and flags&branch = 0 cput(disp>>16); cput(disp&x'FFFF') else if flags&rr = 0 if disp>>14 # 0 or index > 0 start mc error("no RX3 form") and return if flags&indexed = 0 cput(x'4000'+index<<8+disp>>16&x'FF') finish cput(disp&x'FFFF') finish end ! >> SET DOPE VECTOR << routine set dope vector integer t t = vub-vlb+1 claim literal(4*reglen,3) select literal area dv = ca cword(1) cword(vlb); cword(vub) cword(data size) select code area vub = t*data size; vlb = vlb*data size end ! >> PERM << routine perm(integer n) constinteger g0=1, g1=2, g2=4, g3=8, g4=16, g5=32, g6=64; ! General Registers constinteger f0=128, f2=256; ! Floating Registers constinteger prot = (-1)<<15; ! protect stack around call constshortintegerarray rmap(0:8) = R0, R1, R2, R3, R4, P2, P1, FR0, FR2 integer k,r,h ! ! **** N.B. The following table must match the properties of the perm ! routines in use. constinteger perm routines = 50 constshortintegerarray hazard reg(1:perm routines) = 0, ; ! 1: ASSCHK G0+G3, ; ! 2: IEXP G0+F0+F2, ; ! 3: REXP G0+G3+G4, ; ! 4: SMOVE G0+G3+G5, ; ! 4: SJAM G0+G1+G2+G3+G4+G5, ; ! 6: SCONC G0+G5+G6, ; ! 7: SRESLN 0, ; ! 8: SRESV G0+G3+G4+G5, ; ! 9: SCOMP F0+F2, ; ! 10: FRAC PT 0, ; ! 11: SFCAP G0+G1+G2+G3+prot, ; ! 12: SUBSTR G0+G1+G2, ; ! 13: AREF1 G0+G1+G4, ; ! 14: AREF2 G0+G1+G4+G5, ; ! 15: AREF3 G0+G1+G4, ; ! 16: AREF4 G0+G1+G2+G3, ; ! 17: SETDV G0+G5, ; ! 18: ALLOC 0, ; ! 19: SWJMP 0, ; ! 20: SIGNAL 0, ; ! 21: MULCHK 0, ; ! 22: CAP16 0, ; ! 23: CAP8 G0+G1, ; ! 24: FCHK1 0, ; ! 25: FCHK2 G2+G3+G4, ; ! 26: PENTC G0+G3, ; ! 27: RCOPY G0+G3, ; ! 28: RZERO 0, ; ! 29: VSCHK G0+G3+G4, ; ! 30: SMOVOPT G0+G1, ; ! 31: CHMAP G1, ; ! 32: FREESP G1+F2, ; ! 33: INT G0+G3+G4+G5, ; ! 34: RECORD COMPARE G0+G1+G2+G3+G4+G5+G6, ; ! 35: SET COMPARE G0+G3, ; ! 36: SET UNION G0+G3, ; ! 37: SET DIFFERENCE G0+G3, ; ! 38: SET INTERSECTION 0, ; ! 39: 0, ; ! 40: 0, ; ! 41: 0, ; ! 42: 0, ; ! 43: 0, ; ! 44: 0, ; ! 45: 0, ; ! 46: 0, ; ! 47: 0, ; ! 48: G0+G1+G2+G3+G4+G5+G6+F0+F2, ; ! 49: IOCP G0+G1+G2+G3+G4+G5+G6+F0+F2 ; ! 50: ENTER TRACE h = hazard reg(n); ! property mask for nth. perm routine if claimed # 0 start ; ! maybe something to do .. perhaps k = h&x'7FFF'; ! register mask r = 0 while k # 0 cycle hazard(rmap(r)) if k&1 # 0 k = k>>1 r = r+1 repeat finish ! forget all registers which are at risk r = ( ((h&(F0+F2)) << (FR0-P1)) ! (h&127) ) << 1; ! ** N.B. P1 == G6 forget reg(r) rxi(ADD,wsp,0,wdisp) if h < 0 and wdisp # 0 define reference(n&255,p ref) rx(bal,link,code,n&255) if h < 0 start rxi(SUB,wsp,0,wdisp) if wdisp # 0 wdisp = wdisp + basic frame + 256; ! protect it finish end ! >> DUMP TRACE << routine DUMP TRACE if current line # last line start trace flag = 0 perm(enter trace); cput(current line) finish end ! >> ASSEMBLE << ! AMODE: ! -2: alternate record format ! -1: record format ! 0: procedure ! 1: %spec ! 2: initial call routine Assemble(integer amode, labs, names) switch c(33:127), Pc('A':'Z') recordformat evfm(integer low, high, events, label) record (evfm) event = 0 record (varfm)name v record (varfm)name gvar {procedure var} record (stackfm)name lhs, rhs, x integer old frame, old extra frame, old jump integer old temp base, old next temp integer true frame base, putative frame base, max frame, alt first, alt align=0 integer old var diags integer gstart {first descriptor at this level} integer label start {first label for this level} owninteger free tag = 0 integer max local = 0 integer max parm = 0 integer min parm = 0 {P1, P2 parameter registers used ?} integer mark assigned = 1 {mark VAR table entries as 'assigned' if # 0} integer Closed = Assigned {assume it can't return} integer Return Label = 0 {label on return code} integer px = 0 integer proc ca = ca integer sw list = 0 integer last a = -1 integer line size = 0 integer block index integer j, k, t routinespec compile to string(record (stackfm)name v) routinespec pop lhs routinespec lrd(record (stackfm)name v, integer reg) routinespec load(record (stackfm)name v, integer reg) routinespec assign(integer assop) routinespec array ref(integer mode) routinespec operate(integer n) routinespec compare(record (stackfm)name l,r, integer next) routinespec test zero(record (stackfm)name v) routinespec header(record (varfm)name v) routinespec block mark(integer mark) integerfnspec new tag old jump = uncond jump; uncond jump = -1 old var diags = var diags; var diags = 0 label start = labs old frame = frame; old extra frame = extra frame; extra frame = 0 old temp base = temp base; old next temp = next temp temp base = new temp; Next Temp = New Temp forget the lot: pdisp = 0; wdisp = 0; gdisp = -1; event_events = 0 abort(m'-1 ?') unless gdisp = -1; !************???????????? gvar == decvar; gstart = names if amode >= 0 start ; ! NOT A RECORDFORMAT frame = basic frame; ca = 0 level = level+1; abort(m'AM00') if level > 5 and spec = 0 local = breg(level) activity(local) = -1 gdisp = (p1-p2)*reglen Reset Optimisation Data if Spec = 0 if amode = 0 start ; ! procedure, proc. parameter, %begin block block no = block no + 1; block index = block no block mark(block start) if sym = 'H' start ; ! %BEGIN block gdisp = -1 if level = 1 start ; ! Initial %begin ? external id = program ep; ! linkage to program entry otype = external; potype = otype finish header(gvar) finish finish else if amode = -1 start ; ! record format gvar_extra = parms frame = 0 finish true frame base = frame putative frame base = (frame+align)&(¬align) frame = putative frame base max frame = frame alt first = parms-1; ! note start of this alternative list finish ! >> BLOCK MARK << routine block mark(integer mark) integer k, limit k = direct cycle select output(k) print symbol(mark) if mark = block start start print symbol(block index) if k = object start ; ! procedure head diagnostics put(current line); last line = -15; !force a reset describe(-1,0,block name); ! internal name for procedure finish else if k = direct; ! %and mark = block end (by implication) abort(m'TAG?') if free tag > 32767; ! too many pass3 tags put(ca>>1); ! code size for this block (half words) put(var diags); ! var. diags local to this block frame = (frame+align)&(¬align) k = frame + extra frame; ! include in-frame array space if control & trusted = 0 start ! using checked (perm) entry sequence k = k>>2; ! to full word units limit = 65535; ! treated as unsigned 16 bits by perm else ! in-line entry sequence limit = 32767; ! must be positive 2's complement (byte units) finish abort(m'FRM?') unless 0 < k <= limit put(k) print symbol(actual(local)); ! current display register put(event_events); ! events-trapped mask put(event_label); ! Event block ep put(event_low); ! Event block %finish total ca = total ca + ca finish exit if k = object k = object repeat last ca = -1 end ; ! block mark ! >> SET FRAME PATCH << routine set frame patch if diagnose < 0 start select output(report) print string(" Block index"); write(block index,1) newline select output(object) finish print symbol(frame patch) end ; ! set frame patch ! >> DEFINE VAR << routine define var integer type, form, tf, size, format, s, new, round, dimension integer ignore; ! ** used to control dumping of diags ** record (stackfm) temp integer k !!!*** N.B. On machines with the PDP-11/VAX perversion relating to the order ! of register bytes in store, the following table will have to ! be changed as will a few constants in this routine. ! The relevant piece of record format to consider is: ! (%shortinteger xform %or %byteinteger flag,form) ! which must have the effect of mapping 'flag' onto the ! more significant byte of 'xform'. constshortintegerarray fmap(0:18) = 0, V in S, {simple variable} A in S, {name: pointer variable} pgm label, {label ** SPECIAL **} 15, {record format **SPECIAL**} 0, {unused} 0, {switch} proc bit<<8 + 0, {routine} proc bit<<8 + V in R, {function} proc bit<<8 + V in S, {map} proc bit<<8 + 5, {predicate} abit<<8 + V in S, {array} anbit<<8 + V in S, {array name} (abit+label bit)<<8 + V in S, {name array} (anbit+label bit)<<8 + V in S, {name array name} ! external manifestations of array forms abit<<8 + V in REC, {external array} anbit<<8 + V in REC, {external array name} (abit+label bit)<<8 + V in REC, {external name array} (anbit+label bit)<<8 + V in REC {external name array name} constbyteintegerarray vsize(0:8) = 0,4,2,1,8,0,0,4,8 owninteger prim no = 0 ignore = 0 ignore = 1 if amode < 0 or amode = 1; ! no diags for specs of any kind!! internal id = ""; new = 0; round = align decl = tag if decl = 0 start ; ! RECORD FORMAT ELEMENT NAME parms = parms-1; abort(m'DFV1') if parms <= names decvar == var(parms) decvar = 0; !(psr) else abort(m'DFV2') if decl >= parms decvar == var(decl) if decl > names start names = decl; new = 1 decvar = 0 finish finish cycle sym = next; read symbol(next); exit if sym = ',' if length(internal id) # extern len start internal id = internal id.to string(sym) finish repeat ignore = 1 if internal id = "" tf = tag; read symbol(next) type = tf>>4; form = tf&15 size = tag; read symbol(next) diag type = type; diag form = form; diag size = size if type = integers and size # 1 start ; ! INTEGER type = byte and round = 0 if size = 2 type = short and round = 1 if size = 3 size = vsize(type) else if type = 2; ! REAL type = reals ! *** for 8/32, 'round = 3' below should be changed to 'round = 7' !????????????? type = reall %and round = 3 %if size = 4; ! LONG REAL size = vsize(type) else if type = 4; ! record type = records format = size decvar_format = format; size = var(format)_length&x'FFFF' if format <= names else if type = 3; ! string type = strings round = 0 decvar_length = size size = size + 1 else size = vsize(type) finish decvar_length = size if type # strings decvar_type = type; decvar_xform = fmap(form) otype = tag spec = (otype>>3)&1; dimension = otype>>8&255; otype = otype&7 if otype # 0 start ; ! Set external linkage name if appropriate if otype >= external start if alias # "" start external id = alias else if otype = system external id <- system prefix.internal id else external id = internal id finish otype = external if otype <= dynamic {external, system, dynamic} finish finish alias = "" if 7 <= form <= 10 start ; ! PROCEDURE gtype = spec if otype # 0 and spec # 0 start ; ! external spec if otype = primrt start primno = primno + 1 decvar_flag = decvar_flag ! prim bit decvar_header = prim no; ! *** THIS NEEDS FIXING *** return if prim no # 2; ! not READ SYMBOL otype = external; external id = read sym fn; ! see "CALL" finish gfix(align) decvar_disp = ga; decvar_base = gla external link(ep ref, 0, ga) return finish if gmode = 0 start ; ! NOT A PARAMETER potype = otype if new # 0 start ; ! NEW NAME decvar_disp = new tag; ! Procedure ID finish block name = internal id if spec = 0 return finish ignore = 1 otype = 0; size = 4; data size = 4; ! procedure parameter else data size = size if form # 1 start Round = Align if type = 0 start ; ! General %name ignore = 1 decvar_extra = gmode; ! FOR LABELS type = general; size = 8 decvar_type = general else if form = array or form = name array ignore = 1 size = 0 data size = reglen if form = name array else if form = array name or form = name array name ignore = 1 size = 2*reglen; round = align; ! array header decvar_header = -1 abort(m'DFV3') unless 0 < dimension <= 7 decvar_flag = decvar_flag ! dimension; ! 'dim' in low order 3 bits else size = 4; ! integer (etc) %name finish finish finish if otype # 0 start ; ! OWN DATA if otype = con start ; ! CONST INTEGER ETC. data size = 0 if type=strings and form=1; ! use actual size if form = 2 or form = arrayname or form = namearrayname start otype = 0; ! Treat as special later else ignore = 1; ! no diags for named constants finish else gfix(round) set diag(gla,ga) if ignore # 1 finish own type = type; own form = form own type = integers and data size = 4 if form = 2 decvar_header = -1 if spec = 0 start if form = array or form = name array start own form = array; ! to simplify subsequent test at 'A' decvar_flag = decvar_flag&(¬array bits)!(anbit!1); ! 1-D %name ! mark as candidate for MHR subscript scaling if bounds do not ! exceed -32768 <= x <= 32767 and data size <= 32767 decvar_flag = decvar_flag ! cheap array bit if c 0 < decvar_length <= 32767 and c -32768 <= vlb {<= 32767} and c {-32768 <=} vub <= 32767 {Note: vlb <= vub-1} gfix(align) set dope vector; ! N.B. changes vlb, vub if otype # con start decvar_disp = ga; decvar_base = gla gword rel(ga+8-vlb); ! @A(0) (in gla area) gword crel(dv); ! @dope vector (in code area) else ; ! %const ...... %array claim literal(vub,align); ! no header this time (it's in GLA) select literal area decvar_disp = ga; decvar_base = gla gword crel(ca-vlb) gword crel(dv) select code area finish external link(data defn,0,ga-8) if otype = external finish else {to RECORD variant with 1-dim bit set, if nesc} decvar_xform = (decvar_xform+3) ! (assigned<<8) decvar_xform = decvar_Xform!1<<8 if Form >= Array decvar_base = gla; decvar_disp = 0; decvar_extra = ga+8 external link(data ref,0,ga) finish return finish if form = 3 start ; !%label decvar_disp = new tag return finish if form = switch start decvar_extra = vlb; decvar_length = vub-vlb+1 decvar_format = free tag + 1; ! base tag claim literal((vub-vlb+1+2)*2,1) decvar_base = code; decvar_disp = litmax select literal area cput(vlb); cput(vub); ! switch bounds for s = vlb,1,vub cycle free tag = free tag + 1 define reference(free tag,sw ref) cput(free tag) repeat select code area return finish if form = record format start if gmode # 0 start frame = decvar_length if decvar_length > frame else gtype = -1; spec = -1 finish return finish decvar_base = local if gdisp >= 0 and decvar_flag & array bits = 0 c and ( (decvar_form = a in s and decvar_type # general) c or (decvar_form = v in s and decvar_type <= byte) ) start decvar_disp = gdisp; gdisp = gdisp - reglen decvar_disp = decvar_disp + decvar_type if c decvar_form = v in s and short <= decvar_type <= byte decvar_flag = decvar_flag ! P in R; ! Parameter in Register min parm = min parm + 1; ! for use by 'HEADER' if control & suppress = 0 start temp_form = decvar_form; temp_type = decvar_type temp_xbase = decvar_base; temp_disp = decvar_disp if temp_form = A in S start temp_form = V in S; temp_type = integers finish associate(temp, p1 - (min parm-1)) finish else frame = (frame+round)&(¬round) max local = frame decvar_disp = frame frame = frame + size alt align = alt align ! round finish set diag(local,decvar_disp) if ignore = 0 end ; ! define var ! >> CHECKABLE << predicate checkable(record (stackfm)name v) ! Presumes test on 'CONTROL&CHECK UNASS' in line for speed ! Note that a string temporary (v_type = 0) yields FALSE false if v_form = constant or v_form = AV in S false if v_flag & assigned # 0 true if v_type = integers or v_type = strings or v_type >= reals false end ; ! checkable ! >> DESCRIPTOR << ! N.B. Note that the record zero operation is used, among ! other things, to set the link field to NULL. This ! equivalence between binary zero and NULL links must ! be maintained. record (stackfm)map descriptor record (dfm)name d record (stackfm)name v stp = stp+1; abort(m'DSC1') if stp > max depth v == desc asl; abort(m'DSC2') if v == null d == dasl; abort(m'DSC3') if d == null desc asl == v_link; v = 0 dasl == d_link; d_link == using_link; using_link == d d_d == v result == v end ! >> DROP << routine drop(record (stackfm)name descriptor) record (dfm)name p,q p == using cycle q == p_link abort(m'DROP') if q == null exit if q_d == descriptor p == q repeat p_link == q_link q_link == dasl; dasl == q descriptor_link == desc asl; desc asl == descriptor end ! >> VSTACK << routine vstack(integer var no) record (varfm)name w abort(m'VSTK') unless 0 <= var no <= max vars w == var(varno) lhs == descriptor stacked(stp)_v == lhs lhs_base = w_base lhs_disp = w_disp lhs_format = w_format lhs_extra = w_extra lhs_type = w_type lhs_length = w_length lhs_header = w_header lhs_link == null lhs_type = w_type; lhs_xform = w_xform lhs_dim = w_flag&7; ! in case it's an array lhs_varno = varno monitor(lhs, "V stack") if diagnose&1 # 0 end ! >> SSTACK << routine sstack(record (stackfm)name v) record (stackfm)name t t == descriptor; t = v stacked(stp)_v == t monitor(t, "S STACK") if diagnose&1 # 0 end ! >> C STACK << routine c stack(integer n) rhs == descriptor rhs_base = 0 rhs_disp = n rhs_type = integers rhs_form = constant stacked(stp)_v == rhs monitor(rhs, "C stack") if diagnose&1 # 0 end ! >> C LOAD << routine cload(integer value, reg) c stack(value) pop lhs lrd(lhs,reg) end ! >> SSET << routine sset(integer base, disp, xform, extra) rhs == descriptor rhs_base = base rhs_disp = disp rhs_type = integers rhs_xform = xform rhs_extra = extra rhs_link == null stacked(stp)_v == rhs monitor(rhs, "SSET") if diagnose&1 # 0 end ! >> SET LHS << routine set lhs lhs == stacked(stp)_v monitor(lhs, "SET LHS") if diagnose&1 # 0 end ! >> SET BOTH << routine set both abort(m'SETB') if stp <= 1 lhs == stacked(stp-1)_v rhs == stacked(stp)_v if diagnose&1 # 0 start monitor(lhs, "BOTH LHS") monitor(rhs, "BOTH RHS") finish end ! >> POP LHS << routine pop lhs abort(m'POPL') if stp <= 0 lhs == stacked(stp)_v stp = stp-1 monitor(lhs, "POP LHS") if diagnose&1 # 0 end ! >> POP DROP << routine pop drop pop lhs monitor(lhs, "POP DROP") if diagnose&1 # 0 drop(lhs) end !STRING PROCESSING ! >> DUMP STRING << routine dump string(integer max) integer j if max = 0 start ; ! DUMP AS MUCH AS NEEDED max = cslen+1 else ; ! DUMP NO MORE THAN MAX if cslen+1 > max start ! String constant too long - warn and truncate if cslen # x'80' or current string(1) # x'80' start warn(5); current string(0) = max-1 finish finish finish if otype = con start select literal area lit byte(current string(j)) for j = 0,1,max-1 select code area else ; ! %own gbyte(current string(j)) for j = 0,1,max-1 finish end ! >> GET STRING << routine get string integer l l = next; !length cslen = 0 while l > 0 cycle l = l-1 read symbol(next) cslen = (cslen+1)&255; current string(cslen) = next repeat readsymbol(next) if next # 'A' and next # '$' start if next = '.' and cslen = 1 and control&(check capacity!check unass) = 0 start cstack(current string(1)) Rhs_Flag = Rhs_Flag!Quick Conc return finish cstack(0); rhs_type = strings otype = con; ! anonymous %const rhs_base = code; rhs_xform = VinS!(assigned<<8); rhs_format = cslen+1 if cslen # 0 or null string = 0 start claim literal(cslen+1,1); ! Alignment req'd for buffer flushing rhs_disp = lita; dump string(0) null string = rhs_disp if null string = 0 = cslen else rhs_disp = null string finish else cstack(0); ! explicit string initialisation finish end ! >> REAL CONSTANT << integerfn real constant(integer force) owninteger last = 0, next = 0 integer j,k ownintegerarray val(0:31) = 0(32) ownshortintegerarray index(0:31) = 0(32) k = integer(addr(rvalue)) if otype # con start gfix(3); gword(k) result = ga-4 finish ! deal with %const anonymous or not if force = 0 start j = last cycle -> FOUND if val(last) = k last = (last+1)&31 exit if last = j repeat claim literal(single,single-1); ! anonymous value not in cache finish next = (next+1)&31; last = next select literal area val(last) = k; index(last) = ca cword(k) select code area FOUND: result = index(last) end ; ! real constant !LABEL PROCESSING ! >> NEW TAG << integerfn new tag free tag = free tag + 1 result = free tag end ! >> NEW LABEL << record (labelfm)map new label labs = labs+1; abort(m'NLBL') if labs > max labels result == labels(labs) end ! >> FIND << record (labelfm)map find(integer label) integer lp record (labelfm)name l lp = labs while lp # label start cycle l == labels(lp) result == l if l_id = label lp = lp-1 repeat result == null end ! >> DEFINE LABEL << routine define label(integer label) integer ltag, new record (labelfm)name l record (envfm)name E cc ca = 0 {must forget condition code} new = 0 return if label = 0; ! JUMP AROUND PROCEDURE if label < 0 start ltag = -label new = 1 else l == find(label) if l == null start l == new label l_id = label; l_tag = new tag new = 1 else if l_tag < 0 and label >= 0 start l_tag = new tag new = 1 finish finish l_tag = l_tag ! bit15 ltag = l_tag finish if new # 0 start e == environment(label) e_label = 0 if e ## null finish define tag(ltag & x'7FFF') merge environment(label) if uncond jump # ca restore environment(label) if trace flag # 0 start dump trace if next # ':' and next # 'L' finish uncond jump = 0; ! YOU CAN GET HERE ! mark assigned = 0; ! can't be sure any more end ; ! define label ! >> JUMP TO << routine jump to(integer label, cond, def) record (labelfm)name lab integer ref invert = 0 Cond = Inverted(Cond) if Cond&16 # 0 if def >= 0 start ; ! Compiler defined label return if label = 0; ! jump round routine if label < 0 start j tag = -label else lab == find(label) if lab == null start lab == new label lab_id = label; lab_tag = new tag remember environment(label) else if lab_tag < 0 and def = redefine old lab_tag = new tag remember environment(label) else merge environment(label) if lab_tag > 0 finish j tag = lab_tag&x'7FFF' finish else ; ! Tag internal to pass 2 jtag = label; ! *** N.B. This is %not a pass1-visible label *** finish if cond = jump then ref = j ref else ref = c ref define reference(j tag,ref) cput(jtag<<4 + cond&15); cc ca = cc ca + 2; ! these two bytes can't change CC if cond = jump start uncond jump = ca; ! no way past here trace flag = control&trace if next = ':'; ! to catch 'else', 'repeat' etc else trace flag = control&trace; ! maybe trace flow on next line finish mark assigned = 0 end ; ! jump to ! >> FLOAT << routine float(record (stackfm)name v, integer r) ! Convert 'v' into floating point form integer k !!!!!%longreal x r = fpr if r = anyf if const(v) start if v_disp = 0 start hazard(r); claim(r) rr(sub,r,r); claim(r) v_type = reall; v_form = v in r; v_base = r else rvalue = v_disp; ! ** IMPLICIT FLOATING ** otype = con; k = real constant(0) v_xform = (assigned<<8) ! V in S; v_type = reals v_base = code; v_disp = k finish else load(v,any) rr(flr,r,v_base); claim(r) v_form = v in r; v_type = reall v_base = r finish end ! >> LRD << routine lrd(record (stackfm)name v, integer reg) ! load, release and drop load(v,reg) release(v_base) drop(v) end ! >> QUICK LOAD << routine QUICK LOAD(integer reg, form, base, disp) record (stackfm) v v = 0 v_type = integers; v_form = form v_base = base; v_disp = disp load(v, reg) end ! >> REDUCE << routine reduce(record (stackfm)name v) integer type, xform, disp, base xform = v_xform - 3; ! X in REC => X in S type = v_type disp = v_disp; base = v_base v_disp = v_extra; v_type = integers; v_form = v in s load(v,any) v_type = type; v_xform = xform & (¬(assigned<<8)) v_disp = disp end ! >> AMAP << routine amap(record (stackfm)name v) ! convert V into a descriptor for the address of V integer f constshortintegerarray map(0:15) = -1, -2, -3, -4, av in s, -5, v in s, av in rec, -6, v in rec, -7, -8, -9, -10, -11 {PGM LABEL}, -12 {record format} f = map(v_form) if f < 0 start abort(m'AMAP') unless v_form = pgm label ! Deal with ADDR(pgm label) f = gpr; forget reg(1<<f) define reference(v_disp&x'FFF',r ref) rx(LA,f,code,0) v_type = integers; v_xform = VinR v_base = f; v_disp = 0 claim(f) return finish if (f = VinREC or f = AVinREC) and v_disp = 0 start {eliminate redundant LOAD} if f = VinREC then f = AinS else f = VinS v_disp = v_extra finish v_type = integers; v_form = f end ! >> AMAPS << routine amaps(record (stackfm)name v) integer t,l t = v_type; l = v_length amap(v) return if t # strings; ! put length in top byte reduce(v) if v_form >= V in REC load(v,any) if v_form = V in S or v_Form = AinS !! It must be: const, V in R or AV in S v_disp = v_disp + l<<24 v_form = AV in S end ! >> VMAP << routine vmap(record (stackfm)name v) ! The inverse of AMAP: i.e. vmap(amap(x)) => x integer mod, f, t constshortintegerarray map(0:8) = v in s, v in s, -1, -2, a in s, v in s, -3, a in rec, v in rec mod = 0 if v_oper # 0 start if (v_oper=add or v_oper=sub) and const(v_link) start mod = v_link_disp mod = -mod if v_oper = sub v_oper = 0; drop(v_link) finish load(v,any) else if v_form = a in s or v_form = a in rec T = V_Type Amap(V) load(v,any) V_Type = T; V_Form = VinS finish f = map(v_form); abort(m'VMAP') if f < 0 v_form = f v_disp = v_disp + mod end ; ! v map ! >> ADDRESS << routine address(record (stackfm)name v, integer mode) ! convert V into a form in which it is directly addressable ! MODE parameter specifies what type of result is required. ! >= 0 : a value (RHS) ! < 0 : a name (LHS) ! Further, if MODE > 0, the value is taken to specify the target register ! for any LOAD which may be generated. integer type, form, reg, d, cr ownrecord (stackfm)name last == (0); ! ***** null actually ****** UGH monitor(v, "ADDRESS") if diagnose&2 # 0 reg = mode if reg <= 0 start reg = any reg = anyf if v_type >= reals or (v_oper # 0 and floating(v)) finish cr = reg; !*psr* if v_oper # 0 start ; ! compound object if v_oper = ADD and const(v_link) and v_type <= BYTE start d = v_link_disp; drop(v_link) v_oper = 0 load(v,reg) v_disp = d; v_form = AV in S else load(v,reg) finish ->SET CR finish form = v_form; type = v_type if form >= V in REC start reduce(v); form = v_form finish if control & suppress = 0 start cheap reg = cr cheapen(v,mode) cr = cheap reg form = v_form finish ->SET CR if form = V in R or form = constant if form = AV in S start if v_base = 0 start v_form = constant else if v_disp = 0 v_form = V in R finish ->SET CR finish if form = A in S start v_form = V in S; v_type = integers load(v,any) v_type = type; v_xform = (v_flag&(¬assigned))<<8 ! V in S; v_disp = 0 form = V in S finish if not last == v start ; ! *** FRIG: to prevent mutually recursive loop last == v if mode >= 0 and ((control&check unass#0 and v_type#strings c and checkable(v)) or v_type = byte) start load(v,reg) finish last == null finish SET CR: cheap reg = cr end ; ! address ! >> LOAD << routine load(record (stackfm)name v, integer r) ! load the entity described by V into register R record (stackfm)name w switch f(constant:a in rec), iop(not:rdiv), rop(not:rdiv) record (stackfm) z record (stackfm)name temp rhs integer op, d, type, temp, n, uflag constbyteintegerarray twin(R0:R15) = R1,R0, R3,R2, R5,R4, R7,R6, R9,R8, R11,R10, R13,R12, R15,R14 routine PICKUP(record (stackfm)name V) integer old load(v, r) if R = Any or R = AnyF start old = R; R = V_Base return if Activity(R) = 1 or (Activity(R)=2 and W_Base = R) if old = Any then R = Gpr else R = Fpr Load(V, R) else abort(m'Pick') if activity(r) # 1 finish end monitor(v, "LOAD") if diagnose&2 # 0 -> realv if floating(v) or fr0 <= r <= fr14 or r = anyf op = v_oper; v_oper = 0 if op # 0 start w == v_link; {address(w,0)}; ! records reduced here load(w,any) if w_base = r # v_base; ! *** FRIG: to avoid problem ! with HAZARD and e.g. -> sw( -A(j) ) -> iop(op) finish amap(v) if v_type = 0 or v_type = strings or v_type = records address(v,r) if r = any start return if v_form = VinR if v_form = AV in S and activity(v_base) = 1 and -15 <= v_disp <= 15 start r = v_base else r = gpr finish else if v_base = r start if activity(r) > 1 start {protect other uses} release(r); v_base = 0 hazard(r) claim(r); v_base = r finish else hazard(r) finish finish -> f(v_form) f(av in rec): f(a in rec): f(v in rec): f(A in S): abort(m'LD1'); ! These forms should have been simplified by ADDRESS f(av in s): f(constant): abort(m'LD2') if v_type >= reals rxi(lw,r,v_base,v_disp) forget reg(1<<r); associate(v,r) if r # v_base; ! e.g.LHI 12,1(12) CSETI: v_type = integers CSET: v_form = v in r v_base = r; v_disp = 0 claim(r) return f(v in r): return if v_base = r rr(lw,r,v_base); forget reg(1<<r) v_base = r claim(r) return f(v in s): uflag = control & check unass if integers < v_type < reals start abort(m'LD3') if short # v_type # byte uflag = 0 else uflag = 0 if v_Flag&assigned # 0 or not checkable(v) or v_Type = 255 finish if V_Type = 255 start V_Type = Short Rxd(LHL, r, v) Forget reg(1<<r) else rxd(lw,r,v) forget reg(1<<r); associate(v,r) finish if uflag # 0 start if v_type < reals start v_type = integers if level # 5 start rr(clw,r,r12) else rx(clw,r,code,unass) finish else v_type = reall rx(cmp,r,code,unass) finish rr(bal,link,code) v_flag = v_flag & (¬assigned); ! only one level remembered (1 bit !!) finish -> CSET ! integer operations iop(and): if control&check unass = 0 and w_form = constant start address(v, r) if w_disp = x'FFFF' start if v_form = VinS and (v_type = integers or v_type = short) start v_disp = v_disp+2 if v_type = integers LOADL: v_type = 255 drop(w) Load(V, R) return finish else if w_disp = 255 drop(w) if v_form = VinR start r = gpr if r = any rr(LBR, r, v_base) ->CSETI finish if v_type = integers start v_disp = v_disp+3 else if v_type = short v_disp = v_disp+1 finish v_type = byte load(v, r) return finish finish {** Drops through **} iop(add): iop(sub): iop(or): iop(xor): pickup(v) {sets R} address(w, 0) {**Moved down one line**} rxd(op,r,w) -> end op iop(rsh): if control&check unass = 0 and w_form = constant and w_disp = 16 start address(v, r) ->LOADL if v_form = VinS and v_type = integers finish iop(lsh): if w_form # constant and control&check capacity # 0 start load(w,r2); perm(vschk) finish pickup(v) {sets R} if w_form = constant start warn(6) unless 0 <= w_disp <= 8*reglen-1 else ; ! variable shift load(w,any) if w_form # V in R w_disp = 0 finish rxi(op,v_base,w_base,w_disp) -> end op ! these operations are changed immediately into binary subtracts ! and should themselves never appear in LOAD ! -x => 0 - x ! ¬x => -1 - x (assumes 2's complement) iop(not): iop(neg): abort(m'LD4') iop(div): if w_form = constant start n = power(w_disp) if n > 0 start Pickup(V) {make sure it's in the correct register} Test Zero(v); r = v_base claim(r) d = 1; d = 2 if n > 4; ! 1 or 2 halfwords skip(d, greater or equal) rxi(ADD, v_base, 0, ¬((-1)<<n)) rxi(SRA, v_base, 0, n) ->END OP finish finish {** Drops through **} ! *** N.B. *** ! The multiply routine below is not intended for use in array subscript ! calculation as it will include an overflow check. Currently all in-line ! subscript scaling uses shift or 'multiply halfword' instructions. iop(mul): iop(rem): if r = any start n = 0; n = 1 if op = MUL if in free reg(v) and actual(v_base)&1 = n c and activity(twin(v_base)) = 0 start temp = v_base temp = twin(temp) if op # MUL else temp = even odd pair finish else if actual(r)&1 # 0 and activity(twin(r)) = 0 start temp = r else temp = even odd pair finish finish n = twin(temp) claim(n); load(v,temp) release(n); hazard(n); claim(n) d = op if op # MUL start rr(lw,n,temp); claim(temp) rxi(sra,n,0,31); ! propagate sign d = div finish forget reg( (2+1)<<n ); ! forget N,TEMP (adjacent) address(w, 0) ! Note complication below because machine op-code only caters ! for the cases INTEGER*INTEGER, INTEGER//INTEGER, rem(INTEGER,INTEGER) ! Short, byte and constant multipliers must therefore be preloaded ! into a register load(w,any) if w_form = constant or w_form = AV in S or w_type # integers rxd(d,n,w) release(n) if op = MUL start if control & check capacity # 0 start ; ! overflow check if n # R0 start claim(n); rr(LW,r0,n) finish perm(mulchk) finish else if op = rem ! Interested in remainder not dividend claim(n); release(temp) d = temp; temp = n; n = d finish v_base = temp; v_disp = 0; v_form = v in r load(v,r) if temp # r -> end op ! Special multiply routine used for array subscript scaling where all values ! involved are in range: -32768 <= x <= +32767 iop(mult16): if r = v_base or v_type = byte start load(v,any) else address(v,0) load(v,any) if v_form # V in S and v_form # V in R and v_form # constant finish v_disp = v_disp+reglen//2 if v_type = integers; ! ** halfword instruction!! ** pickup(w); ! scale factor (data size) - & sets R rxd(mult16,r,v) v_base = r; v_disp = 0; v_xform = V in R -> end op iop(exp): load(v,r3); load(w,r2) release(r3); release(r2) perm(iexp) claim(r1); v_base = r1 -> end op iop(conc): address(v, r) if v_type # 0 start pdisp = basic frame if pdisp = 0 ! N.B. Must %not corrupt LHS/RHS in LOAD temp rhs == rhs sset(wsp,pdisp,V in S,0); rhs_type = strings; rhs_length = 255 rhs == temp rhs sstack(v); v_Base = 0 assign(1) claim(r2) v_type = strings; v_form = VinS v_base = r2; v_disp = 0 v_length = 255; ! it's a temporary now pdisp = pdisp + 256; ! ... so protect it finish if w_flag & quick conc # 0 start ; ! S = S.tostring(sym) z = v; claim(z_base); z_type = byte load(z, any) rxi(LW, z_base, z_base, 1); claim(z_base) {length+1} load(w, any) {character} v_index = z_base; v_type = byte; v_form = VinS rxd(ST, w_base, v); release(w_base) claim(v_base); v_index = 0 rxd(ST, z_base, v) else load(v, r2) load(w,r1); release(r1); release(r2) n = v_length; n = 255 if n = 0 perm(sconc); cput(n) v_form = VinS finish claim(v_base) v_type = 0 if r # any and r # 0 start ; ! not from OPERATE load(v,r); v_type = 0; v_form = v in s finish drop(w) return {Note: nothing to forget} ! floating operations REALV: abort(m'LD5') if r = any; ! should be floating register op = v_oper; v_oper = 0 if op # 0 start w == v_link -> rop(op) rop(not): rop(lsh): rop(rsh): rop(and): rop(or): rop(xor): rop(conc): rop(mult16): abort(m'LD6'); ! inappropriate operator rop(rdiv): op = div rop(div): rop(add): rop(sub): rop(mul): if w_type < reals start float(w, anyf) if w_form = V in R # v_form and v_type >= reals c and (op = add or op = mul) start z = v; v = w; w = z; ! interchange finish finish Pickup(v); r = v_base Address(W, 0) rxd(op,r,w) -> end op rop(neg): abort(m'LD7'); ! should have been modified by OPERATE finish float(v, r) if v_type < reals address(v, r) {AFTER float to prevent optimising constants} {e.g. I=0; R=0} if v_form = v in r start return if r = anyf or v_base = r hazard(r); rr(lw,r,v_base) v_base = r; claim(r) return finish if r = anyf start r = fpr else hazard(r) unless r = v_base finish abort(m'LD8') unless fr0 <= r <= fr14 -> f(v_form) rop(rexp): abort(m'LD9') if w_type >= reals load(v,fr2); load(w,r1) release(fr2); release(r1) perm(fexp); ! floating exponent claim(fr0); v_base = fr0 END OP: V_Type = Integers if V_Type <= Byte forget reg(1<<v_base) drop(w) end ; ! load ! >> COP << routine cop(integer op, record (stackfm)name lh,rh) ! perform a compile-time operation constinteger fp tens=70; ! max powers of ten available in floating point integer l,r switch s(1:rdiv) integerfn p10(integer n); ! approximate powers of ten in 'n' integer value, power value = 1; power = 0 cycle result = power if value >= n value = value*10 power = power+1 abort(m'COP1') if power > 100 repeat end l = lh_disp; r = rh_disp -> s(op) s(NEG): s(NOT): s(CONC): abort(m'COP2') s(ADD): l = l+r; -> EXIT s(SUB): l = l-r; -> EXIT s(OR): l = l!R; -> EXIT s(AND): l = l&r; -> EXIT s(XOR): l = l!!R; -> EXIT s(LSH): l = l<<r; -> EXIT s(MUL): l = l*r; -> EXIT s(MULT16): l = l*r; -> EXIT s(RSH): l = l>>r; -> EXIT s(EXP): l = l^^r; -> EXIT s(DIV): warn(1) and r = 1 if r = 0 l = l//r; -> EXIT s(REM): warn(1) and r = 1 if r = 0 l = l-l//r*r; -> EXIT s(REXP): warn(7) and r = 0 if p10(|l|) * r > fp tens rvalue = l^r; ! **** implicit floating **** -> REAL s(RDIV): warn(1) and r = 1 if r = 0 rvalue = l/r; ! **** implicit floating **** REAL: otype = con; l = real constant(0) lh_base = code lh_type = reall; lh_form = V in S EXIT: lh_disp = l end ! >> OPERATE << routine operate(integer oper) ! perform the operation OPER on the top two elements of the stack. ! (single element for unary operators) record (stackfm)name lh,rh,with integer key,lcon,rcon,wcon,lop constbyteintegerarray transitive(add:rdiv) = 0,0,1,15(2),1(3),15(2),1,15(4) constbyteintegerarray commutative(add:rdiv) = 1,0,1,0,0,1(3),0(2),1,0(4) constshortintegerarray nop value(add:rdiv) = 0,0,1(2),0,-1,0(4),1,1(4) routine pickup(record (stackfm)name v) if floating(v) then load(v,anyf) else load(v,any) end stp = stp-1 lcon = 0; rcon = 0; wcon = 0 lh == stacked(stp)_v if const(lh) start lcon = 1 else if lh_type # strings and lh_type # 0 address(lh, 0) if lh_oper = 0 finish rh == stacked(stp+1)_v if const(rh) start rcon = 1 if oper = sub start oper = add; rh_disp = -rh_disp finish finish if lh_oper # 0 start lop = lh_oper with == lh_link wcon = 1 if const(with) if wcon&rcon # 0 start ; !! fold key = transitive(oper)!transitive(lop) if key = 0 or (key = 1 and oper = lop) start with_disp = -with_disp and lop = add if lop = sub cop(oper,rh,with); drop(with) lh_link == rh lh_oper = lop -> STRIP NOP finish finish pickup(lh) finish if rcon # 0 start if lcon#0 or (oper=ADD and lh_type=INTEGERS and (lh_form=VinR or lh_form=AVinS)) start lh_form = AV in S if lh_form = VinR cop(oper,lh,rh); drop(rh) return finish finish if rh_oper # 0 start pickup(rh) else if rcon # 0 and rh_disp = 2 ! treat *2 (real & integer) and ^2, ^^2 specially if oper = mul or oper = exp or oper = rexp start if oper = mul then oper = add else oper = mul rh = lh; rcon = 0; claim(rh_base) finish finish if commutative(oper) # 0 and ( lcon # 0 c or ( lh_form # VinR and rh_form = VinR and activity(rh_base) >= 0 ) ) start rh_link == lh stacked(stp)_v == rh rh_oper = oper ! keep various items valid for use at STRIP NOP: with == rh; rh == lh; lh == with rcon = lcon else lh_oper = oper; lh_link == rh finish STRIP NOP: if rcon # 0 start if rh_disp = nop value(oper) start lh_oper = 0; drop(rh) else if oper = MUL and control&check capacity = 0 key = power(rh_disp) if key > 0 start lh_oper = lsh; rh_disp = key finish finish finish end ; ! operate ! >> ASSIGN << routine assign(integer assop) ! ASSOP = -1: parameter assignment ! 0: == assignment ! 1: = assignment ! 2: <- assignment ! 3: Unchecked string move - either for speed or P in R constbyteintegerarray string move(-1:3) = SMOVE, 0, SMOVE, SJAM, SMOVOPT record (stackfm)name lh,rh,x record (stackfm) temp integer n,p,t,op,insert,form,lhdisp insert = 0 abort(m'ASS1') if stp < 2 rh == stacked(stp)_v lh == stacked(stp-1)_v form = lh_form; ! to avoid the ravages of amap, load etc if diagnose&4 # 0 start monitor(lh, "ASS LH") monitor(rh, "ASS RH") finish if assop < 0 start ; ! Parameter if lh_flag & prim bit # 0 start ; ! Special - prim routine temp = lh; lh = rh; rh = temp p disp = 0 return finish lh_extra = lh_extra - 1 vstack(lh_extra); lh == stacked(stp)_v form = lh_form; lh disp = lh_disp; ! preserve original values assop = 0 if lh_form # v in s if lh_flag & p in r = 0 start ; ! not an in-register parameter p disp = lh_disp + lh_length p disp = p disp+1 if lh_type = strings and Form = VinS lh_disp = lh_disp + wdisp; ! adjust for nested calls finish if lh_flag & proc bit # 0 start ; ! Procedure parameter assop = 1 lh_type = integers; lh_form = v in s rh_type = integers; rh_form = av in s if rh_base # 0 and rh_base # gla start ; ! param already rh_form = v in s else if rh_base = gla; ! non-local external rh_disp = rh_disp-5*reglen; !dummy environment else ; ! local routine p = (frame+3)&(¬3) frame = p+8*reglen t = rh_disp; !proc tag rh_disp = p; rh_base = local define reference(t, r ref) rx(la, link, code, 0) rx(stm, r8, local, p) finish finish finish stp = stp-2 if rh_flag & array bits # 0 start ; ! Arrayname p disp = lh_disp + 2*reglen hazard(r0) address(lh,-1); address(rh,-1) if rh_header = -1 start ; ! Simple case rx(lw,r0,rh_base,rh_disp); ! @A(0) else ; ! Array-in-record rxi(lw,r0,rh_base,rh_disp) rx(add,r0,gla,rh_header) rh_disp = rh_header; rh_base = GLA finish if lh_type = strings and lh_length = 0 start ; ! %string(*)%arrayname RXI(ADD,r0,0,rh_length<<24); ! length in top byte finish forget reg(1<<r0) rx(st,r0,lh_base,lh_disp) claim(rh_base); rx(lw,r0,rh_base,rh_disp+reglen) claim(lh_base); rx(st,r0,lh_base,lh_disp+reglen) drop(lh); drop(rh) return finish if lh_type = general start ; ! general %name parameter abort(m'ASS2') unless assop = 0 if rh_type = general start amap(lh); address(lh,-1) amap(rh); address(rh,-1) hazard(r0) rx(lw,r0,rh_base,rh_disp) rx(st,r0,lh_base,lh_disp) claim(lh_base); claim(rh_base) rx(lw,r0,rh_base,rh_disp+reglen) rx(st,r0,lh_base,lh_disp+reglen) drop(lh); drop(rh) return finish t = rh_type rh_flag = rh_flag ! assigned; ! pointer proper may never be used !!!!! n = rh_length; n = n+1 if t = strings; ! logical => physical length amaps(rh); lrd(rh,any); p = rh_base rx(st,p,lh_base,lh_disp) claim(lh_base) cload((n<<4) + genmap(t),p) rx(st,p,lh_base,lh_disp+reglen) drop(lh) return finish if assop = 0 start ; ! == amap(lh); ! destination if lh_length = 0 then amaps(rh) else amap(rh); ! %string(*)%name ? finish if Lh_Type = Records start n = Min Record Size(Lh, Rh) if rh_Form # Constant start lrd(rh,r1); ! source area op = rcopy; ! copy record else drop(rh) op = rzero; ! clear record finish lrd(lh,r2); ! destination area cload(n>>2,R3); ! R3 = no. of WORDS to copy/zero perm(op) return finish if lh_type = strings and lh_flag & p in r = 0 start if assop > 0 and rh_format = 1 start ; ! null string as zero byte ? drop(rh) lh_type = byte; sstack(lh); drop(lh) cstack(0); assign(assop) return finish p = lh_length if assop # 2 and same(lh,rh) start ; ! S = S or S = S.T if rh_oper = 0 start drop(lh); drop(rh); ! S = S else rh_length = p release(lh_base); drop(lh) rh_type = 0{; address(rh,-1)}; lrd(rh,0) {0 = special for CONC} finish else if Control&Trusted # 0 and assop # 2 and Rh_Oper # 0 and not Same(Lh, Rh) and not Same(Lh, Rh_Link) x == Rh_Link; Rh_Oper = 0 Load(Lh, R2); Lrd(Rh, R1) Perm(String Move(3)) Lh_Form = VinS; Lh_Type = 0 Lh_Oper = Conc; Lh_Link == X Lrd(Lh, 0) else ; ! general case rh_flag = rh_flag&(¬quick conc); ! quicky not possible after all. ! use fast string move if 'trusted' or capacity exceeded is impossible ! and unassigned is not requested or impossible. if assop # 2 start ; ! not jam transfer assop = 3 if control & trusted # 0 c or ( p >= rh_length c and (control&check unass = 0 or not checkable(rh)) ) finish if rh_oper = 0 start ; !simple, so protect lhs first: s(j)=t lrd(lh, r2); lrd(rh, r1) else ; !simplify rh first: s = t.u lrd(rh, r1); lrd(lh, r2) finish perm( string move(assop) ) cput(p) if assop # 3; ! max. length of destination for check ? finish return finish if lh_flag & p in r # 0 start p = p1; p = p2 if lh disp < reglen; p = p3 if lh_type = strings load(rh,p) if rh_oper # 0 drop(lh) lh == stacked(stp)_v rh_oper = p; ! target register rh_link == lh_link; lh_link == rh address(lh, -1) else ! Test for case where add-to-memory can profitably be used. ! Note that the effective no-op of self-assignment can be detected easily address(lh, -1) if control & check bits = 0 and rh_type <= short C and (rh_oper = 0 or rh_oper = ADD) and same(lh,rh) start if rh_oper = 0 start ; ! assignment-to-self release(rh_base); drop(rh) release(lh_base); drop(lh) return finish ! General case: add-to-memory x == rh; rh == rh_link release(x_base); drop(x) load(rh,any) address(lh,-1); rxd(AM,rh_base,lh) forget var(lh) release(rh_base); drop(rh); drop(lh) return finish ! test for assignment of small constants to %short and %byte t = rh_type if rh_base = 0 and rh_form = constant and rh_Oper = 0 start if -32768 <= rh_disp <= 32767 start if rh_disp&(¬255) = 0 start t = byte else t = short finish finish finish ! . . . then suppress capacity check if LH is real or length RH is ! not greater than length LH. n = assop assop = 2 if lh_type > byte or lh_type <= t if Lh_Form = VinR start {special by PSR - is it safe????} Load(Rh, Lh_Base) Assop = 2 else p = cheap reg {preferred register} float(rh, p) if lh_type >= reals and not floating(rh) {Float here to prevent optimising the integer value} address(rh, p) {see where it is} load(rh, p) unless rh_form = VinR p = rh_base address(lh, -1) unless lh_form = VinS rxd(ST, p, lh) if control & suppress = 0 start t = activity(lh_base) if t < 0 or control&trusted # 0 start forget var(lh) if mark assigned # 0 and lh_base = local start ; ! set 'assigned' ? var(lh_varno)_flag = var(lh_varno)_flag ! assigned finish else forget all finish lh_flag = lh_flag ! (rh_flag & assigned) associate(lh,p) if n # 2; ! not jam transfer finish release(p) finish drop(lh); drop(rh) finish if assop = 1 and control&check capacity # 0 start if lh_type = short start claim(p); rr(chvr,p,p) perm(cap16); ! Test for 16-bit overflow else rxi(TEST,p,0,¬255); ! should give zero result perm(cap8); ! Test for 8-bit overflow finish finish end ; ! assign ! >> LOAD PARAMS << routine load params(record (stackfm)name v) ! called at c('E') to load in-register parameters set by ASSIGN above integer reg record (stackfm)name next return if v == null reg = v_oper v_oper = 0 next == v_link load(v,reg) load params(next) release(reg) drop(v) end ; ! load params ! >> ARRAY REF << routine array ref(integer mode) ! Array references are by perm call except in the case of unchecked 1-D arrays ! which either: ! (i) have a data size which is an integral power of 2, not greater than 16384. ! or: ! (ii) have data size <= 32768 and constant bounds -32768 <= x <= 32767. integer flags, p, type, base, assbit integer mult, shift; ! ** PRESUMED SET BY 'UNCHECKED REF' record (stackfm)name temp predicate special case shift = power(mult) true if shift >= 0 or flags & cheap array bit # 0 or Base = 0 false end ; ! special case routine unchecked ref integer header, length, format, extra header = lhs_header; length = lhs_length; format = lhs_format extra = 0 if rhs_oper = ADD or (rhs_oper = 0 and (rhs_form = AV in S or rhs_form = Constant)) start if rhs_oper = ADD start if rhs_link_form = constant or rhs_link_form = AV in S start extra = rhs_link_disp if rhs_link_form = AV in S start ; ! => VinR + const (see below) rhs_link_form = VinR rhs_link_disp = 0 else ; ! simple constant rhs_oper = 0 drop(rhs_link) finish finish else ; ! AV in S (treat as VinR + constant) extra = rhs_disp; rhs_disp = 0 rhs_form = VinR if rhs_form = AVinS finish extra = extra * mult finish if shift >= 0 start cstack(shift); operate(lsh) else cstack(mult); operate(mult16) finish lhs_type = integers; ! address calculation if lhs_header >= 0 start ; ! array-in-record amap(lhs); ! address of record containing array sset(gla,lhs_header,v in s,0) operate(add) finish operate(add) set lhs ! ! ***** F R I G ***** ! load(lhs,any) %if lhs_oper = 0; ! Force load: zero subscript folded out ! ! ***** F R I G ***** ! vmap(lhs) ! lhs_disp = lhs_disp + extra ! lhs_type = type ! lhs_format = format; lhs_length = length ! lhs_xform = assbit ! V in S ! lhs_form = A in S %if flags & label bit # 0 if Extra # 0 start Cstack(Extra); Operate(Add) Set Lhs finish Vmap(Lhs) Vmap(Lhs) if Flags&Label Bit # 0 {namearray} Lhs_Type = Type Lhs_Format = Format Lhs_Length = Length Lhs_Xform = Lhs_Form!Assbit end if mode # 0 start ; ! multi-dimensional: ingest non-terminal subscripts set both; stp = stp-1 load(rhs,any) if rhs_oper # 0 rhs_link == lhs_link lhs_link == rhs lhs_oper = lhs_oper+1 return finish set both abort(m'ARF1') if lhs_oper+1 # lhs_dim; ! No. of subscripts ? flags = lhs_flag; ! protect from ravages of AMAP lhs_flag = lhs_flag & (¬(label bit + array bits)) base = lhs_base; type = lhs_type; assbit = lhs_xform & (assigned<<8) if (control & check array = 0 and lhs_oper = 0) or Base = 0 start ; ! unchecked 1-D mult = lhs_length mult = mult+1 if lhs_type = strings mult = 4 if Flags&Label Bit # 0; !namearray if special case start ; ! sets 'shift' as a side-effect unchecked ref; return finish finish stp = stp-1 if lhs_oper = 0 start ; ! 1-D load(rhs,r1); drop(rhs) p = aref1 else if lhs_oper = 1; ! 2-D load(lhs_link,r1); drop(lhs_link) load(rhs,r2); drop(rhs) p = aref2 p = aref4 if control & check array = 0 else ; ! 3-D or more load(rhs, any) if rhs_oper # 0 {**psr**} rhs_link == lhs_link; ! tack on last subscript for p = pdisp,reglen,pdisp+(lhs_oper-1)*reglen cycle temp == rhs_link lrd(rhs,any) {**psr**} rx(ST,rhs_base,wsp,p) {**psr**} rhs == temp repeat load(rhs,r1); ! r1 = first subscript rhs_form = AV in S; rhs_base = wsp; rhs_disp = pdisp load(rhs,r2); ! r2 = addr(subscript list) drop(rhs) p = aref3 finish lhs_oper = 0 amap(lhs) if lhs_header >= 0 start ; ! array-within-record sset(gla,lhs_header,av in s,0) load(rhs,r3); drop(rhs); stp = stp-1 else load(lhs,r3) finish release(r1); release(r3) release(r2) unless p = aref1 perm(p) claim(r1) if lhs_header >= 0 start ; ! array-in-record sset(lhs_base,lhs_disp,lhs_form,lhs_extra); ! address of record lhs_base = r1; lhs_disp = 0; lhs_form = VinR; ! array component lhs_type = integers; ! an address to be amapped operate(add); ! record address + array component else lhs_base = r1; lhs_disp = 0 finish vmap(lhs) lhs_type = type lhs_xform = assbit ! V in S lhs_form = A in S if flags & label bit # 0 end ; ! array ref ! >> TEST ZERO << routine test zero(record (stackfm)name v) record (stackfm)name w integer cr cr = any cr = anyf if floating(v) if v_oper = AND and sym = '?' and const(v_link) start ! if x & const = 0 . . . . . . . w == v_link; v_oper = 0 load(v,cr) rxd(TEST,v_base,w) drop(w); release(v_base) else load(v,cr) if ca # cc ca or cc reg # v_base start rr(lw,v_base,v_base) else release(v_base) finish finish end ; ! test zero routine Compare Records(record (stackfm)name L, R, integer N) Amap(l); Load(l, R1) Amap(r); Load(r, R2) Cload(n, R3); Set Both {***beware of CLOAD and Lhs} Release(R1); Release(R2) Perm(Rcomp) end ! >> COMPARE REALS << routine compare reals(record (stackfm)name l,r) load(l,anyf) address(r,0) float(r, anyf) unless floating(r) rxd(cmp,l_base,r) release(l_base) end ; ! compare reals ! >> COMPARE STRINGS << routine compare strings(record (stackfm)name l,r) record (stackfm)name temp if l_base = code and l_disp = null string start temp == r; r == l; l == temp invert = invert !! 16 finish if r_base = code and r_disp = null string start load(l,any) if l_oper # 0 l_type = byte test zero(l) else load(r,r2) if r_oper # 0 load(l,r1); load(r,r2) release(r1); release(r2) perm(scomp) finish l_type = strings; l_form = v in s p disp = 0 end ; ! compare strings ! >> COMPARE << routine compare(record (stackfm)name l,r, integer next) swopped = 0 if l_type = 0 or l_type = strings start compare strings(l,r); return finish if zero(r) start test zero(l); return finish if zero(l) start test zero(r); invert = invert !! 16 return finish if floating(l) or floating(r) start compare reals(l,r); return finish if L_Type = Records start Compare Records(L, R, Min Record Size(L, R)) return finish address(l,0); load(l,any) address(r,0) if '=' # next # '#' start rxd(cmp,l_base,r) else rxd(clw,l_base,r) finish release(l_base) end ; ! compare ! >> RESOLVE << routine resolve(integer flag) !S -> A.(B).C record (stackfm)name s,a,b,c integer p,q cstack(0) if flag&1 = 0; ! C missing pop lhs; c == lhs pop lhs; b == lhs cstack(0) if flag&2 = 0; ! A missing pop lhs; a == lhs pop lhs; s == lhs load(s,r3); load(a,r2); load(b,r1); load(c,r4) p = a_length; !!!!! p = 255 %if p = 0 q = c_length; !!!!! q = 255 %if q = 0 release(r3); drop(s) release(r2); drop(a) release(r1); drop(b) release(r4); drop(c) perm(sresln); cput( (p<<8) + (q&255) ); ! conditional resolution if flag&4 = 0 start ; ! unconditional perm(sresv); ! verify it succeeded finish end ; ! resolve ! >> HEADER << routine header(record (varfm)name v) frame = basic frame if frame < basic frame define tag(v_disp&x'FFF') rx(stm, p2+2-minparm, wsp, (2-minparm)*reglen) if potype >= external start !===== the order of the next two statements is critical ===== external link(ep defn,0,0) rx(st,link,wsp,(link-p2)*reglen) if control&unass # 0 and unassigned rtn = 0 start ! Force inclusion of unassigned check routine if not already present unassigned rtn = 1 select output(direct) print symbol(p ref); put(asschk); put(0) select output(object) finish finish rr(lw,local,wsp) if v_header # 0 start ; ! special string parameter (P in R) abort(m'HDR1') if v == begin sset(local,v_header,V in S,0); rhs_type = strings sset(p3,0,VinR,0) claim(P3); ! parameter nominally at 0(P3) assign(3); ! SMOVOPT if control&trusted # 0 start ; ! suppress check if 'TRUSTED' v_header = 0 else Cput(x'0812') {preserve R2 for later} finish finish frame = (frame+align)&(¬align); ! ensure non-parameter locals are aligned if control & trusted = 0 start ; ! stack overflow check perm(pentc); ! checked procedure entry *** mustn't corrupt R2 *** cput(frame); ! parameter size cput(0); ! padding:- gets overwritten else rxi(add,wsp,0,basic frame); ! 2nd. halfword gets overwritten finish set frame patch; ! Total size ! Use base reg(5) to hold unassigned pattern ( except at level 5 !! ) if level # 5 and control & check unass # 0 start rx(lw,base5,code,unass) activity(base5) = -1; ! lock it finish if v_header # 0 start ; ! check P in R string Cput(x'0821') {*LR_2,1} perm(smove) cput(ap_length); ! 'AP' set at '}' v_header = 0 finish if control&trace # 0 start ; ! trace option enabled if v == begin and potype >= external start ; ! main program %begin external id = trace routine external link(ep ref,0,ga) perm(enter trace); cput(0); ! initialise user-supplied routine finish trace flag = control&trace finish event = 0 end ; ! header ! >> RETURN << routine return return if uncond jump = ca; ! can't get here ? if Return Label # 0 start Jump To(Return Label, Jump, Define New) else Return Label = x'7001' {something positive and unique} Define Label(Return Label) rx(lm,wsp,local,(wsp-p2)*reglen) rr(jmp,always,link) finish uncond jump = ca Closed = 0 {can get back now} end ; ! return routine compile to string(record (stackfm)name v) {Delay if possible so S = S.tostring(k) can be optimised in LOAD} if next = '.' and control&(check capacity!check unass) = 0 start v_flag = v_flag ! quick conc return else if const(v) current string(0) = 1; current string(1) = v_disp&255 claim literal(2,0); otype = con; dump string(0) v_base = code; v_disp = litmax else load(v,any) frame = (frame+1)&(¬1) rr(lbr,R0,v_base) rxi(add,R0,0,1<<8) rx(sth,R0,local,frame) v_base = local; v_disp = frame; frame = frame+2 finish v_type = strings; v_xform = VinS ! (assigned<<8); v_length = 1 end ! >> CALL << routine call(record (stackfm)name v) switch b(1:max prim) ! 1 = rem ! 2 = read symbol ! 3 = float ! 4 = to string ! 5 = substring ! 6 = free space ! 7 = SVC; ! *** MOUSES specific *** ! 8 = addr ! 9 = integer ! 10 = short integer ! 11 = byte integer ! 12 = string ! 13 = record ! 14 = real ! 15 = long real ! 16 = length ! 17 = charno ! 18 = int ! 19 = int pt ! 20 = IOCP; ! *** temporary *** ! 21 = type of; ( type of general name parameter ) ! 22 = size of; ( physical length in bytes ) ! 23 = frac pt; ! *** replaces IOCP above in the fullness of time *** constbyteintegerarray new type(9:17) = integers, short, byte, strings, records, reals, reall, byte, byte constbytearray New Size(integers:reall) = 4,2,1,8,255,0,4 integer t,l,p if v_flag & prim bit # 0 start ; ! built-in primitive l = 0; t = v_header; sym = 0; ! 'sym=0' used as flag elsewhere if t = 2 start ; ! 'read symbol' v_flag = v_flag & (¬prim bit) v_header = 0; ! otherwise looks like "P in R" in "HEADER" q.v. else drop(v) finish set lhs -> b(t) b(1): ! REM operate(rem); return b(2): ! READ SYMBOL call(v) sset(r1,0,VinR,0) if lhs_type = records or lhs_type = general start warn(4) ! *** subsequently, force a call on external routine form of ! read symbol and leave it to generate the error ! *** FRIG *** cload(5,r0); cload(5,r1); perm(signal) set lhs; lhs_type = byte; ! to prevent compiler failing ! *** FRIG *** finish claim(rhs_base) compile to string(rhs) if lhs_type = strings assign(1) return b(3): ! FLOAT float(lhs, anyf); return b(4): ! TO STRING compile to string(lhs) return b(8): ! ADDR t = Lhs_Type amap(lhs) if T = Strings and Lhs_Form # AVinS and Lhs_Form # AVinRec start Load(Lhs, Any) Lhs_Form = VinS Forget Reg(1<<Lhs_Base) Rxd(LA, Lhs_Base, Lhs); Claim(Lhs_Base) Lhs_Form = VinR finish return b(16): ! LENGTH cstack(0) b(17): ! CHARNO set both amap(lhs) if control&check array = 0 c or (const(rhs) and t-16 <= rhs_disp <= lhs_length) start operate(add); set lhs; !LHS&RHS reversed in operate?? else load(lhs,r1); load(rhs,r2) drop(rhs); stp = stp-1 release(r1); release(r2) !!**** charno(s,j) where S is %String(*)%name won't work: change perm as well perm(chmap); cput(lhs_length & 255) claim(r1) set lhs; lhs_base = r1; lhs_disp = 0; lhs_xform = VinR finish -> map it b(12): ! STRING !!!!! l = 255 b(9):b(10):b(11): ! INTEGER, SHORT, BYTE b(13): ! RECORD b(14):b(15): ! REAL, LONG REAL map it: vmap(lhs); lhs_type = new type(t) lhs_length = new size(Lhs_Type) return b(19): ! INT PT load(lhs,anyf) p = gpr; hazard(p) rr(fxr,p,lhs_base); claim(p) lhs_base = p; lhs_type = integers; lhs_xform = VinR return b(18): ! INT p = intfn; ! perm routine t = integers; ! resulting type l = R1; ! result register -> PERM1823 b(23): ! FRAC PT p = frac part t = reall l = FR2 PERM1823: load(lhs,fr2); release(fr2) perm(p) claim(l); ! result register set lhs lhs_base = l; lhs_xform = VinR; lhs_type = t return b(5): ! substring(S,from,to) load(lhs,r3); drop(lhs); stp = stp-1 set both; stp = stp-2 load(lhs,r1); load(rhs,r2); drop(lhs); drop(rhs) release(r1); release(r2); release(r3) perm(substr); claim(r1) sset(r1,0,v in s,0); rhs_type = strings return b(21): ! type of(..) b(22): ! size of(..) if lhs_type # general start ; ! type explicitly specified if t = 21 start ; ! type of p = gen map(lhs_type) else p = lhs_length; p = p+1 if lhs_type = strings finish release(lhs_base) lhs_type = integers; lhs_form = constant lhs_base = 0; lhs_disp = p else lhs_disp = lhs_disp + reglen; ! reference property-word lhs_xform = (assigned<<8) ! V in S; lhs_type = integers if t = 21 start ; ! type of cstack(15); operate(and) else ; ! size of cstack(4); operate(rsh) finish finish return b(6): ! free space perm(freesp); claim(r1) sset(r1,0,VinR,0) return b(7): ! SVC (MOUSES SPECIFIC) hazard(p) for p = fr0,1,fr14 set both; stp = stp-2 load(lhs,any) unless const(lhs); address(rhs,-1) rx(lme,fr0,rhs_base,rhs_disp); claim(rhs_base) rx(svc,r0,lhs_base,lhs_disp) rx(stme,fr0,rhs_base,rhs_disp) drop(lhs); drop(rhs) forget reg(-1) return b(20): ! IOCP *** temporary *** load(lhs,r4); ! required function release(r4); drop(lhs); stp = stp-1 perm(iocp) return finish ! -- normal routine calls -- wdisp = (wdisp+align)&(¬align); !keep WSP aligned hazard all if V_Flag&Assigned = 0 {beware - it returns} if v_base # 0 start ; ! non-local if v_base # gla start t = new tag; define reference(t, r ref) rx(la, link, code, 0) finish rx(STM,p2,wsp,wdisp) rxi(ADD,wsp,0,wdisp) if wdisp # 0 if v_base = gla start ; ! external rx(lm,gla,gla,v_disp) rr(bal, link, link) else ; ! procedure-as-parameter quick load(r2, VinS, v_base, v_disp); forget reg(1<<R2) rx(lm,r8,r2,0) rx(bal, link, link, 4); !skip initial STM define tag(t) finish else ; ! local routine rxi(ADD,wsp,0,wdisp) if wdisp # 0; ! protect stacked parameters ? define reference(v_disp&x'FFF',r ref) rx(bal,link,code,0) rxi(SUB,wsp,0,wdisp) if wdisp # 0; ! reset protection Uncond Jump = Ca if V_Flag&Assigned # 0 {it doesn't return} finish wdisp = v_header; p disp = v_rt drop(v) if v_type = 0; ! not function or map end ; ! call ! >> COMPILER OP << !***** RE=ORGANISE 'call', 'prim' and this routine ***** routine compiler op(integer n) record (stackfm)name p p == descriptor; stp = stp-1 {DESCRIPTOR increments it!!} p_flag= prim bit; p_header = n abort(m'CMOP') unless 0 < n <= max prim call(p) end ! >> COMPILE FOR << routine compile for record (stackfm)name cv, iv, inc, fv integer lab, safe, n, reg, shadow routine stab(record (stackfm)name v, integer type) integer t,r return if const(v) load(v,any); r = v_base t = temp v_base = local; v_disp = t v_type = type; v_xform = (assigned<<8) ! V in S rx(ST,r,local,t); release(r) associate(v,r) if control & suppress = 0 end routine set(record (stackfm)name v,integer reg) record (stackfm)name r sstack(v); r == stacked(stp)_v lrd(r,reg) stp = stp-1 end cv == stacked(stp-3)_v inc == stacked(stp-2)_v fv == stacked(stp-1)_v lab = tag abort(m'FOR1') if for stp = max cycle for stp = for stp + 1; for == for stk(for stp) n = next temp; ! remember current point in temp stack shadow = -1; shadow = temp if control & check for # 0 stab(fv,integers); stab(inc,integers) for_temp base = temp base if n # next temp start ; ! protect shadow, FV, INC ? temp base = new temp finish safe = 0 sstack(inc); operate(sub) iv == stacked(stp)_v; ! iv = iv - inc if cv_form # v in s or activity(cv_base) >= 0 start n = cv_type amap(cv) stab(cv, n) cv_form = a in s finish stp = stp-4 if const(fv) and const(iv) and const(inc) start if inc_disp # 0 start n = fv_disp-iv_disp if n !! inc_disp >= 0 and (n//inc_disp)*inc_disp = n start safe = 1 finish finish if safe = 0 start warn(2); ! constant faulty %for parameters else safe = fv_disp - iv_disp; ! null cycle ? finish finish reg = iv_base if reg <= r2 start reg = gpr {**cannot return r0,r1,r2} else reg = any finish load(iv,reg); reg = iv_base if safe = 0 and control & check for # 0 start set(iv,r0); claim(reg) set(fv,r1); set(inc,r2) perm(fchk1); ! Check %for parameters before entry finish if safe = 0 start ; ! non-constant or null cycle sstack(cv); sstack(iv); assign(1); claim(reg) for_initial = for lab base + for stp jump to(for_initial,jump,redefine old) finish define label(lab); trace flag = control&trace sstack(cv) sstack(iv); sstack(inc); operate(add); ! CV + INC drop(iv); drop(inc) set lhs; load(lhs,reg); ! to make sure ASSIGN doesn't use wrong register assign(1) rx(st,reg,local,shadow) if shadow >= 0 for_lab = lab; for_reg = reg; for_shadow = shadow for_cvbase = cv_base; for_cvdisp = cv_disp for_cvtype = cv_type; for_cvform = cv_xform for_fvbase = fv_base; for_fvdisp = fv_disp drop(cv); drop(fv) end ; ! for cycle ; ! --- main loop --- sym = next; read symbol(next) -> c(sym) c('l'): language mask = tag; continue ; ! Select language dependent options c('O'): abort(m'STK?') if stp # 0 abort(m'USNG') unless using_link == null abort(m'CLMD') if claimed # 0 abort(m'LIT?') if ca < 0; ! 'select code/literal area' misused wdisp = 0; p disp = 0 next temp = temp base current line = tag if control&trace # 0 start if next = ':' or next = 'L' start trace flag = 1 else if trace flag # 0 dump trace finish finish continue c('$'): define var; continue c('b'): pop drop; vub = lhs_disp pop drop; vlb = lhs_disp continue routine adump switch c(integers:8),g(integers:8); ! 8 =REALS+1 !!!!! constintegerarray low(integers:8) = 0,-32768, 0, 0(*) constintegerarray high(integers:8) = 0, 65535, 255, 0(*) integer j if high(owntype) # 0 and control & check capacity # 0 start warn(8) unless low(owntype) <= ownval <= high(owntype) finish -> g(owntype) if otype # con select literal area if strings # owntype < reals -> c(owntype) g(integers): gword(ownval); return c(integers): cword(ownval); -> exit c(reals):c(8): g(reals):g(8): j = real constant(1); return g(byte): gbyte(ownval); return c(byte): lit byte(ownval); -> exit g(short): gput(ownval); return c(short): cput(ownval); -> exit c(strings): g(strings): dump string(data size); return g(records): gput(0) for j = 1,1,data size>>1 return c(records): abort(m'ADMP') exit: select code area end ; ! adump c('A'): aparm = tag if stp # 0 start decvar_flag = decvar_flag ! assigned; ! explicit initialisation pop drop if own type >= reals start rvalue = lhs_disp if lhs_type < reals ownval = integer(addr(rvalue)) mantissa = integer(addr(rvalue)+4) else ownval = lhs_disp; ! a string finish else ; ! initialise to UNASSIGNED pattern if own type = byte start own val = x'80' else if own type = short own val = x'FFFF8080' else if owntype # strings ownval = x'80808080'; mantissa = x'80808080' else cslen = x'80'; current string(1) = x'80' finish finish if own form = array or own form = name array start adump for j = 1,1,aparm else if otype = 0 start decvar_flag = decvar_flag & (¬assigned); ! %const .... %name decvar_disp = ownval; decvar_base = 0 ! %CONSTINTEGERNAME -> INTEGER ! A in S -> V in S, A in REC -> VinREC if Decvar_Form = VinS start Decvar_Form = Constant else Set Diag(0, Ownval) if Decvar_Form = AinS decvar_form = decvar_form + (v in s - a in s) finish else decvar_base = gla; decvar_disp = ga if otype >= external start decvar_flag = decvar_flag & (¬assigned) external link(data defn,data size,ga) else if otype = con ; ! %const if decvar_type = strings start claim literal(cslen+1,1) j = litmax; dump string(0) else if decvar_type >= reals j = real constant(0); ! ** N.B. %fn + side-effect ** else abort(m'AM01') finish decvar_base = code; decvar_disp = j continue finish adump finish finish continue c(''''): get string; continue c('G'): get string alias = "" for j = 1, 1, cslen cycle alias = alias.tostring(current string(j)) repeat pop drop continue c('N'): cstack(tag<<16!tag); continue c('D'): get d cstack(0) and continue if rvalue = 0 continue if next = 'A' otype = con; ! anonymous %const j = real constant(0); ! N.B. ** %fn + side-effect ** sset(code,j,v in s,0); rhs_type = reals continue c('n'): j = tag; set lhs vstack( var(lhs_format)_extra - j ) set both; stp = stp-1 if rhs_form # 15 start ; ! not record format if lhs_form = v in s or lhs_form = VinRec start rhs_disp = lhs_disp + rhs_disp lhs_xform = lhs_form - v in s + rhs_xform else if lhs_form = a in rec start lhs_form = VinRec; lhs_type = integers load(lhs,any) lhs_xform = rhs_xform else if lhs_form <= VinR start lhs_xform = rhs_xform; ! ???? else lhs_extra = lhs_disp lhs_xform = rhs_xform+3 finish finish finish lhs_disp = rhs_disp lhs_type = rhs_type lhs_rt = rhs_rt lhs_header = rhs_header finish lhs_length = rhs_length; lhs_format = rhs_format lhs_dim = rhs_dim drop(rhs) continue c('@'): vstack(tag) if lhs_flag & proc bit # 0 and next # 'p' c and lhs_flag&prim bit = 0 start lhs_rt = p disp lhs_header = wdisp w disp = (p disp+align)&(¬align) p disp = 0 finish continue c('E'): pop lhs; x == lhs load params(x_link) call(x) if x_type # 0 and sym # 0 start ; ! fn/map - SYM=0: see 'CALL'!?!?!?!? sstack(x); drop(x); set lhs if lhs_type >= reals then opr = fr0 else opr = r1 lhs_base = opr; lhs_disp = 0 claim(opr) if lhs_form = VinR c and (lhs_type = strings or lhs_type = records) start lhs_base = R1; lhs_form = V in S if next # 'S' and next # 'p' and next # '?' start if lhs_type = strings start n = 256; lhs_length = 255 else n = var(lhs_format)_length finish pdisp = basic frame if pdisp = 0 lhs_base = wsp; lhs_disp = pdisp sstack(lhs); ! a copy for 'ASSIGN' below sset(r1,0,V in S,0); ! N.B. sets RHS implicitly if lhs_type = strings start rhs_type = strings else rhs_type = records; rhs_format = lhs_format finish assign(1) pdisp = pdisp + n; ! protect stacked temporary lhs_type = 0 if lhs_type = strings finish finish finish continue c('M'): c('V'): set lhs opr = r1 if sym = 'V' start if gvar_type >= reals start opr = FR0 else if gvar_type = records and zero(lhs); ! recordfn result = 0 lhs_type = records; lhs_form = V in S lhs_base = wsp; lhs_disp = 0 lhs_format = gvar_format sstack(lhs); ! duplicate cstack(0) assign(1); ! construct zero record set lhs finish else amaps(lhs) finish lrd(lhs,opr); stp = stp-1 if sym = 'V' start if gvar_type = strings and gvar_length > 0 start cload(gvar_length,r0) perm(sfcap); ! string function capacity else if control & check capacity # 0 if gvar_type = short start claim(opr); rr(CHVR,opr,opr) perm(cap16) else if gvar_type = byte rxi(TEST,opr,0,¬255) perm(cap8) finish finish finish c('R'): return continue c('K'): ! %false k = 0; -> true false c('T'): ! %true k = -1 true false: cload(k,r1) return continue c('a'): array ref(0); continue c('i'): array ref(1); continue c('.'): operate(conc); continue c('+'): operate(add); continue c('¬'): k = -1; -> not neg; ! NOT c('U'): k = 0; ! NEG not neg: pop lhs; cstack(k); sstack(lhs); drop(lhs) c('-'): operate(sub); continue c('!'): operate(or); continue c('%'): operate(xor); continue c('&'): operate(and); continue c('['): operate(lsh); continue c(']'): operate(rsh); continue c('*'): operate(mul); continue c('/'): operate(div); continue c('Q'): operate(rdiv); continue c('X'): operate(exp); continue c('x'): operate(rexp); continue c('v'): set lhs if floating(lhs) start load(lhs,anyf); opr = fpr else load(lhs,any); opr = gpr finish pop lhs k = lhs_base load(lhs,opr) n = new tag jump to(n,greater or equal,internal tag) cstack(0); sstack(lhs); drop(lhs) operate(sub) set lhs; load(lhs,k) define tag(n) continue c('j'): assign(2); continue c('S'): assign(1); continue c('Z'): assign(0); continue c('p'): assign(-1); continue c('u'): !++ c('q'): !-- if sym = 'u' then k = add else k = sub set both t = lhs_type; j = lhs_length j = j+1 if t = strings amap(lhs) abort(m'AM05') if j = 0 if j = 2 start cstack(1); j = lsh else if j = 4 cstack(2); j = lsh else cstack(j); j = mul finish operate(j) operate(k) set lhs vmap(lhs); lhs_type = t continue c('='): c('k'): opr = 0; -> cond c('#'): c('t'): opr = 1; -> cond c('<'): opr = 2; -> cond c('>'): opr = 3; -> cond c('('): opr = 4; -> cond c(')'): opr = 5; -> cond cond: val = tag jump to(val,opr+invert,redefine old); invert = 0 continue c('C'): set both t = lhs_type amap(lhs); amap(rhs) if t = strings and (lhs_form = V in S or lhs_form = VinREC c or rhs_form = V in S or rhs_form = VinREC) start operate(xor) cstack(8); operate(lsh) cstack(0) finish c('?'): set both compare(lhs,rhs, next); stp = stp-2 drop(lhs); drop(rhs) continue c('"'): set both; invert = 16 compare(rhs,lhs, next) stp = stp-1; lhs = rhs; drop(rhs) claim(lhs_base) continue c('r'): resolve(tag); continue c('_'): uncond jump = 0; mark assigned = 0 forget all v == var(tag); pop drop j = lhs_disp - v_extra; ! this label - lower bound abort(m'AM10') unless 0 <= j < v_length; ! within vector ? define tag((v_format + j)!x'8000'); ! N.B. marked as a switch defn. continue c('W'): v == var(tag) if control & trusted = 0 start ; ! checked switch via PERM pop lhs lrd(lhs,r1) rxi(lw,r2,code,v_disp) perm(swjump) else cstack(1); operate(lsh); ! subscript X 2 pop lhs k = v_disp+2*2-v_extra*2 if const(lhs) start k = k+lhs_disp j = 0 else load(lhs, Any) j = Lhs_Base finish lhs_base = code; lhs_index = j; lhs_disp = k lhs_type = short; lhs_form = V in S rxd(LHL,r1,lhs); claim(r1) drop(lhs) rr(ADD,r1,r1); claim(r1) rr(ADD,r1,code) rr(JMP,always,r1) finish uncond jump = ca continue c('B'): val = tag if val # for_lab start ; ! not %for .... %repeat jump to(val,jump,define new) else sset(for_cvbase,for_cvdisp,for_cvform,0) hazard(for_reg) pop lhs lhs_type = for_cvtype; lhs_flag = lhs_flag ! assigned lrd(lhs,for_reg) if for_shadow >= 0 start rx(clw,for_reg,local,for_shadow) perm(fchk2) finish if for_initial # 0 start define label(for_initial); for_initial = 0 finish if for_fvbase = 0 start ; ! constant if for_fvdisp = 0 start ; ! zero claim(for_reg); rr(lw,for_reg,for_reg) else rxi(clw,for_reg,for_fvbase,for_fvdisp) finish else rx(clw,for_reg,for_fvbase,for_fvdisp) finish jump to(val,not equal,define new) abort(m'AM15') if next # ':' read symbol(next); define label(tag) if for_shadow >= 0 start if level # 5 start rx(st,r12,local,for_shadow) else rx(lw,for_reg,code,unass) rx(st,for_reg,local,for_shadow) forget reg(1<<for_reg) finish finish temp base = for_temp base; ! unprotect shadow, FV, INC for stp = for stp-1; abort(m'AM20') if for stp < 0 for == for stk(for stp) finish continue c('F'): val = tag; abort(m'AM25') if val >= for lab base jump to(val,jump,redefine old) continue integerfn user label(integer lab) record (varfm)name v if lab > names start names = lab v == var(lab) v = 0 v_form = pgm label v_disp = new tag result = -v_disp finish result = -var(lab)_disp end c('J'): jump to(user label(tag),jump,define new) continue c('L'): define label(user label(tag)) continue c(':'): j = tag; abort(m'AM30') if j >= for lab base define label(j); continue c('f'): compile for; continue c('w'): mark assigned = 0; machine code; forget reg(-1); continue c('P'): pop drop; cput(lhs_disp); forget reg(-1) continue c('y'): ! %diagnose n j = tag diagnose = 0 if (j>>14)&3 = 2 start ; ! it's for pass 2 diagnose = j&x'3FFF' diagnose = diagnose ! ((-1)<<15) if diagnose&4 # 0; ! only for speed else !***** should pass onto next pass ****** finish continue c('z'): control = tag; continue c('m'): j = -1; -> SIGNAL EVENT c('s'): if control&trace # 0 start perm(enter trace); cput(0); ! close off user-supplied routine finish j = 0; -> SIGNAL EVENT c('e'): j = tag SIGNAL EVENT: cstack(0) while stp < 2 pop lhs; lrd(lhs,r2) pop lhs; lrd(lhs,r1) cload(j,R0) perm(signal) uncond jump = ca continue c('o'): event_events = tag; ! events trapped read symbol(next); k = tag j = (frame+align)&(¬align); frame = j+reglen rx(ST,wsp,local,j); ! for use below jump to(k,jump,redefine old); event_low = j tag; ! skip event body forget all event_label = new tag define tag(event_label); ! entry point rx(LW,wsp,local,j) continue c('h'): ! compiler op(n) compiler op(tag) continue c('g'): !array formats c('d'): ! array allocation and dope vector dumping. Allocate = Sym-'g' {0=format} ! GMODE: =0 -> simple array, # 0 -> array-in-record ! When OPT is specified, in-line code is dumped to ! allocate 1-D constant-bounded arrays dim = tag; abort(m'AM35') unless 0 < dim <= 7 read symbol(next); n = tag if gmode = 0 then names = names-n else parms = parms+n set both dv = 0; ! used as a flag subsequently t = -1 ! **** The test for OPT must come out once this optimisation is ! implemented correctly **** if control&checkbits=0 and dim = 1 and lhs_disp <= rhs_disp+1 start if const(rhs) and const(lhs) start t = 0; ! candidate for cheap allocation at least if 0 < data size <= 32767 c and -32768 <= lhs_disp <= 32767 c and -32768 <= rhs_disp <= 32767 start dim = dim ! cheap array bit; ! stuffed in below finish finish finish if gmode # 0 or t >= 0 start vlb = lhs_disp; vub = rhs_disp abort(m'AM40') if vlb > vub+1; ! null array, A(1:0) allowed set dope vector stp = stp-2; drop(lhs); drop(rhs) if gmode = 0 start ; ! constant-bounded 1-D simple array quick load(R4, AVinS, code, dv); release(R4) vub = (vub+align) & (¬align); ! to preserve stack-front alignment finish else frame = (frame+align)&(¬align); k = frame; Frame = Frame+Reglen quick load(R4, AVinS, local, K); release(R4) stp = 0 for j = 1,1,dim<<1 cycle ; ! N.B. not changed above on this path stp = stp+1; set lhs claim(r4); lrd(lhs,any) rx(st,lhs_base,r4,frame-k); frame = frame+reglen frame = frame+reglen if j&1 = 0; ! LEAVE HOLE FOR MULTIPLIER repeat perm(set dv) cput(dim); cput(data size) stp = 0 finish if dv = 0 start quick load(R2, AVinS, local, frame) release(R2) forget reg(1<<r2) finish for j = 1,1,n cycle if gmode = 0 start names = names+1; decvar == var(names) else parms = parms-1; decvar == var(parms) finish decvar_disp = frame decvar_flag = decvar_flag ! dim; ! may also set 'cheap array bit' if gmode = 0 start ; ! array not in record decvar_header = -1; decvar_base = local decvar_flag = decvar_flag ! anbit; ! force arrayname if dv = 0 start if Allocate # 0 start perm(alloc); ! general method of allocation else RX(ST, R4, Local, Frame+Reglen) RX(ST, R1, Local, Frame+0) finish else ! dope-vector was dumped statically above ! Note that the data area for each array is allocated within ! the high address end of the static frame startingat the top ! and working downwards. Pass3 patches in the displacement req'd ! from 'local' rx(ST,r4,local,frame+reglen); ! @DV if Allocate # 0 start rxi(LW,r0,wsp,-vlb); ! @A(0) for Jth array rxi(ADD,wsp,0,vub); !****temp fix**** else rxi(LW,R0,0,-vlb) finish rx(ST,r0,local,frame+0); ! plug into header finish frame = frame + 2*reglen; ! 2-word header else ; ! array-in-record gfix(align); !*****psr***** decvar_header = ga; decvar_base = 0 gword(-vlb); ! relative to start of array gword crel(dv); ! relative to code base frame = frame+vub if Allocate # 0 finish repeat continue c('^'): {Set Format} Set Lhs Lhs_Type = Records Lhs_Format = Tag continue routine Temp Set Frame = (Frame+Align)&(¬Align) Sset(Local, Frame, VinS, 0) Rhs_Type = Records Rhs_Format = Max Vars Frame = Frame+SetLen end c('I'): {ESCAPE for Pascal etc.} sym = next; readsymbol(next) ->Pc(Sym) if 'A' <= Sym <= 'Z' Abort(M'I ?' - ' '<<8 +Sym<<8) Pc('A'): {Compare} Pc('D'): {Compare records} Pc('K'): {Test set membership} cload(0, R6); claim(R6) set both j = next; readsymbol(next) if Sym = 'A' start if j <= 1 then k = '=' else k = '<' compare(lhs, rhs, k) else if Sym = 'K' Load(Lhs, Any); Address(Rhs, -1) Rhs_Type = Integers Rxd(Tbt, Lhs_Base, Rhs) Release(Lhs_Base) else k = next; readsymbol(next) Compare Records(Lhs, Rhs, K) finish stp = stp-2; drop(lhs); drop(rhs) skip(1, j+invert); ! short forward jump Invert = 0 rxi(ADD, R6, 0, 1); ! reduces to halfword: AIS R6,1 forget reg(1<<r6); CC CA = 0 sset(R6, 0, VinR, 0) continue Pc('B'): {Create space} sym = next; readsymbol(next) ownform = array; Owntype = byte Claim Literal(Sym, Align) Select Literal Area Decvar_Disp = Ca; Decvar_Base = Code Select Code Area continue Pc('C'): ! 'refer to' FORTRAN parameter in CALL ! If parameter is not a simple variable, then store into a ! temporary to make it so. Either way, convert to descriptor for ! address of simple variable for final parameter set lhs unless lhs_form = VinS and lhs_oper = 0 start t = any; t = anyf if floating(lhs) load(lhs,t) hazard(lhs_base); ! force into store temporary finish continue Pc('I'): {Add to set} Set Both Lrd(Rhs, Any) Address(Lhs, -1) Lhs_Type = Integers Rxd(Sbt, Rhs_base, Lhs); Claim(Lhs_Base) Lhs_Type = Records Stp = Stp-1 continue Pc('G'): {Make set null} Pc('H'): {assign set} k = Tag if Sym = 'H' if Next # 'S' start Temp Set Sstack(Rhs) Rhs_Type = 0 {show it's a temporary} else Readsymbol(Next) finish if Sym = 'G' then Cstack(0) else Vstack(k) Assign(1) continue Pc('J'): {Compare sets} Set Both Lrd(Lhs, R1) Lrd(Rhs, R2) Perm(Set Comp) if Next <= 1 start {#, =} cput(0) else if Next = 3 {<=} cput(2) else {Next = 2} {>=} cput(1) finish Stp = Stp-2 Sset(R6, 0, VinR, 0); Claim(R6) Rxi(Xor, R6, 0, 1) if Next = 0 {#} Readsymbol(Next) continue Pc('L'): {Set operation} Pop Lhs; X == Lhs Set Lhs if Lhs_Type # 0 start {needs to be made temporary} Pop Lhs Temp Set Sstack(Lhs); Drop(Lhs) Assign(1) Sset(Local, Frame-SetLen, VinS, 0) Rhs_Type = 0 Set Lhs finish Load(Lhs, R1) Lrd(X, R2) Perm(Set Ops(next)); Readsymbol(Next) continue Pc('S'): {Swop top of stack elements} Set Both Stacked(Stp-1)_V == RHS Stacked(Stp)_V == LHS continue Pc('N'): {check not NIL} if Control&Check Unass # 0 start Set Lhs; Test Zero(Lhs); Claim(Lhs_Base) RR(Bal, Link, Code) finish continue Pc('W'): {Stack WSP} Cstack(0) Rhs_Form = VinR Rhs_Base = Wsp continue c('~'): ! alternate record format sym = next; read symbol(next) if sym = 'A' start ; ! alt start decvar == gvar assemble(-2,labs,names) Alt Align = Alt Align!Falign else if sym = 'B'; ! alt end -> OUT else abort(m'AM45') if sym # 'C'; ! faulty intermediate code max frame = frame if frame > max frame frame = putative frame base finish continue c('{'): gmode = -1 assemble(gtype,labs,names) continue c('}'): gmode = 0 -> OUT if amode < 0; ! end of %record %format defn. -> OUT if gvar_flag & primbit # 0; ! prim routine reference if names > gstart start gvar_extra = parms for j = gstart+1,1,names cycle ap == var(j) parms = parms-1; fp == var(parms) fp = ap; fp_base = wsp ap_flag = ap_flag & (¬p in r) ! assigned if ap_flag&array bits = 0 repeat abort(m'AM50') if parms < names if ap_type = strings and ap_xform & (array bits<<8 + 255) = V in S c and ap_base # 0 start gvar_header = ap_disp fp_flag = fp_flag ! P in R; ! mark as 'in-register' param finish finish gdisp = -1; ! so locals are properly placed max parm = frame; !start of local space -> OUT if amode # 0 header(gvar) continue c('H'): decvar == begin; decvar_disp = new tag otype = 0; spec = 0; potype = 0 if level # 0 start ; ! not outermost %begin cstack(decvar_disp) pop lhs; lhs_type = 0; call(lhs) finish block name = "BLOCK"; ! Fix up diagnostic name for "%begin" block assemble(0,labs,names) continue repeat ; ! --- end of main loop --- ! To catch the sinners!! C(*): abort(m'?? '<<8 ! sym) routine ALIGN ALTERNATIVES ! Routine to fix up alternate record definitions - implicit parameters in: ! true frame base, putative frame base, max frame, alt first, alt align integer n, mod, j record (varfm)name v Falign = Alt Align n = putative frame base - true frame base return if n = 0 or alt align = align; ! no padding or fullword req'd if alt align = 0 start ; ! byte alignment possible mod = n else ; ! at least %short req'd return if n = 1; ! can't move it back mod = 2; ! n = 2,3 finish ! now strip out extra unnecessary alignment for j = parms,1,alt first cycle v == var(j) v_disp = v_disp - mod repeat max frame = max frame - mod end ; ! align alternatives c(';'): if level # 0 start if uncond jump # ca or (gvar_type = 0 and control&trusted = 0) start if control&trace # 0 and level = 1 start perm(enter trace); cput(0); ! close down user-supplied routine finish return finish else ; ! level 0: flush literals and gla gbyte(0) if ga&1 # 0 claim literal(0,0) if lita&1 # 0 finish Gvar_Flag = Gvar_Flag!Closed block mark(block end) Reset Optimisation Data OUT: if amode >= 0 start ; ! end of declarative block activity(local) = 0 unless local = base5; ! release old base register level = level-1; local = breg(level) else ; ! end of record format defn align alternatives frame = max frame if max frame > frame if amode = -2 start ; ! end of alternative only old frame = frame else frame = (frame+align)&(¬align); ! **** temporary **** abort(m'AM55') unless frame>>16 = 0 {only 16 bits worth} gvar_length <- frame finish finish frame = old frame; extra frame = old extra frame uncond jump = old jump; ca = proc ca var diags = old var diags new temp = temp base next temp = old next temp temp base = old temp base last line = -15 end ; ! assemble ! -------- it all starts here --------- control = IMPCOM_flags & 255; ! set compilation options control = control & (¬check bits) if control & trusted # 0; ! force OPT select input(in) select output(object) print symbol(init gla>>1); ! Initial GLA allocation print symbol(init lit>>1); ! specify literal area available to pass 3 claim literal(init lit,align); ! set literal base and initialise pass 3 var(0) = 0; ! for %RECORD(*) . . . . . var(max vars)_Length = SetLen {for sets} parms = max vars cslen == current string(0) activity(wsp) = -1; activity(code) = -1; activity(0) = -1 activity(gla) = -1; activity(link) = -1 for j = 0,1,max stack-1 cycle stak(j)_link == stak(j+1) dlist(j)_link == dlist(j+1) repeat stak(max stack)_link == null dlist(max stack)_link == null desc asl == stak(0); dasl == dlist(0) using_link == null for stk(j) = 0 for j = 0,1,max cycle for stp = 0; for == for stk(0) read symbol(next); ! Prime SYM/NEXT pair Spec = 0 decvar == begin assemble(2,0,0) close files signal 15,3 if faulty # 0 endofprogram