; ; ;COPYRIGHT (C) 1975,1981,1982 BY ;DIGITAL EQUIPMENT CORPORATION, MAYNARD, MASS. ; ; ;THIS SOFTWARE IS FURNISHED UNDER A LICENSE AND MAY BE USED AND COPIED ;ONLY IN ACCORDANCE WITH THE TERMS OF SUCH LICENSE AND WITH THE ;INCLUSION OF THE ABOVE COPYRIGHT NOTICE. THIS SOFTWARE OR ANY OTHER ;COPIES THEREOF MAY NOT BE PROVIDED OR OTHERWISE MADE AVAILABLE TO ANY ;OTHER PERSON. NO TITLE TO AND OWNERSHIP OF THE SOFTWARE IS HEREBY ;TRANSFERRED. ; ;THE INFORMATION IN THIS SOFTWARE IS SUBJECT TO CHANGE WITHOUT NOTICE ;AND SHOULD NOT BE CONSTRUED AS A COMMITMENT BY DIGITAL EQUIPMENT ;CORPORATION. ; ;DIGITAL ASSUMES NO RESPONSIBILITY FOR THE USE OR RELIABILITY OF ITS ;SOFTWARE ON EQUIPMENT WHICH IS NOT SUPPLIED BY DIGITAL. ; ; ;SUBTTL CODE GENERATION ROUTINES PART 1 ; WRITTEN BY H. VAN ZOEREN, C.M.U. ; EDITED BY R. M. DE MORGAN AND Andrew J. Skinner HISEG SEARCH ALGPRM,ALGMAC ; SEARCH PARAMETER FILES MODULE MCOD; $PLEVEL=2; BEGIN EXPROC CHECKARITH EXPROC CLOSE EXPROC COMBASSIGN EXPROC COMBLEX EXPROC CONVERT EXPROC EMITCODE EXPROC ERRLEX EXPROC FAIL EXPROC GLOAD EXPROC IPLUNK EXPROC LOAD EXPROC MARRY EXPROC MERGEPORTIONS EXPROC PLUNK EXPROC REOPEN EXPROC REVORDER EXPROC SETUP EXPROC STOCON EXPROC TOCT1 EXPROC TOCT2 EXTERN CTILR,CTLRI,CTLRR ;COMPILE-TIME CONVERSION SR'S; EXTERN POWC1,POWC2,POWC3 ;COMPILE-TIME POWER SR'S; INTERN OPUMIN,OPABS,OPENT1,OPENT2,OPENT3,OPJSPX,OPMVMS ; OPS USED IN CGFUN INTERN OPPSJP,OPSGN1,OPSGN2,OPSGN3,OPSETO INTERN OPADDB,OPAOS,OPSOS,OPMVSM INTERN OPJMPE,OPJMPG,OPJRST,OPMVLP INTERN OPCONC,OPCONV,OPMOVE,OPABS1,OPLNEG INTERN OPENT4,OPENT5,KIOPS ; * * * * TABLE OF INSTRUCTIONS (ACTUAL AND PSEUDO) ; TO BE GENERATED IN CGEN AND CGFUN OPCODE: OPPOW: POWR1 0,$R !7 ; 3 BY 4 TABLE OF "^" SUBROUTINES POWR4 0,$R !0 ; POWR5 0,$LR!0 ; OPTDZA: TDZA ; USED IN RELATIONS POWR2 0,$R !7 ; POWR4 0,$R !1 ; POWR5 0,$LR!1 ; OPSETO: SETO ; USED IN RELATIONS POWR3 0,$LR!7 ; POWR5 0,$LR!2 ; POWR5 0,$LR!3 ; OPTIMES:IMUL ; INTEGER "*" FMPR ; REAL "*" LFMP ; LONG REAL "*" (PSEUDO OPN) DFMP A0,A3 OPDIV: IDIV ; INTEGER "DIV" OPSLASH:NOOP OPREM: FDVR ; REAL "/" LFDV ; LONG REAL "/" (PSEUDO OPN) DFDV A0,A3 RLFDV ; REVERSED LONG REAL "/" (PSEUDO OPN) OPUMIN: MOVN ; INTEGER NEGATE OPUPLUS:MOVN ; REAL NEGATE OPLNEG: LMOVN 0,0 ; LONG REAL NEGATE PSEUDO-OP OPPLUS: ADD ; INTEGER "+" FADR ; REAL "+" LFAD ; LONG REAL "+" (PSEUDO OPN) DFAD A0,A3 ; LFADC OPMINUS:SUB ; INTEGER "-" OPFSBR: FSBR ; REAL "-" OPLFSB: LFSB ; LONG REAL "-" (PSEUDO OPN) DFSB A0,A3 RLFSB ; REVERSED LONG REAL "-" (PSEUDO OPN) OPLSS: CAML ; INTEGER OR REAL "<" CAIL ; LONG REAL "<" OPGTR: CAMG ; ">" (AND REVERSED "<") CAIG OPRGTR: CAML ; REVERSED ">" CAIL OPLEQ: CAMLE ; INTEGER OR REAL "<=" CAILE ; LONG REAL "<=" OPGTE: CAMGE ; ">=" (AND REVERSED "<=") CAIGE OPRGTE: CAMLE ; REVERSED ">=" CAILE OPEQ: CAME ; INTEGER OR REAL "=" CAIE ; LONG REAL "=" OPNE: CAMN ; INTEGER OR REAL "#" CAIN ; LONG REAL "#" OPNOT: SETCM ; BOOLEAN "NOT" OPAND: AND ; BOOLEAN "AND" OPOR: OR ; BOOLEAN "OR" OPIMP: ORCA ; BOOLEAN "IMP" OPEQV: EQV ; BOOLEAN "EQV" OPRIMP: ORCM ; REVERSED "IMP" OPASS: MOVEM ; INTEGER ":=" MOVEM ; REAL ":=" LMOVEM ; LONG REAL ":=" (PSEUDO OPN) LMOVEM ; STRING ":=" (PSEUDO OPN) OPTCSF: TCSF ; FORMAL ":=" (PSEUDO OPN) OPCONV: CIR ; 3 BY 4 TABLE OF CONVERSION CALLS CIL ; OPPUSH: PUSH ; USED IN "^"CALL CRI ; OPMVI1: MOVEI 1,0 ; USED IN "^" CALL CRL ; OPLPSH: LPUSH ; LONG REAL PUSH PSEUDO (USED IN "^" CALL) CLI ; CLR ; OPJSPX: ELI ; LONG ENTIER OPMOVE: MOVE ; INTEGER MOVE MOVE ; REAL MOVE LMOVE ; LONG REAL MOVE (PSEUDO OPN) OPCONC: FLTR A0,A0 ; 3 BY 4 TABLE OF COMPILE-TIME PUSHJ SP,CTILR ; CONVERSIONS FOR CONSTANTS OPPSJP: PUSHJ SP,0 ; USED TO CALL LIBRARY FUNCTIONS FIXR A0,A0 ; OPABS: MOVM ; IN-LINE "ABS" SETZ A1, ; OPMVMS: MOVM 0,(SYM) ; CONSTANT TO LOAD ABS(SYM) PUSHJ SP,CTLRI ; PUSHJ SP,CTLRR ; OPABS1: ;..AND IN .CGFTEST (ALGFUN) EXP !$RA_22 ;USED IN IN-LINE LONG "ABS" OPPOWC: PUSHJ SP,POWC1 ; COMPILE-TIME INTEGER "^" INTEGER PUSHJ SP,POWC2 ; COMPILE-TIME REAL "^" INTEGER PUSHJ SP,POWC3 ; COMPILE-TIME LONG REAL "^" INTEGER OPMVLP: MOVE 0,(LOP) ; CONSTANT FOR GLOAD OF LOP OPMVSM: MOVE 0,(SYM) ; CONSTANT FOR GLOAD OF SYM OPENT1: MULI 0,400 ; IN-LINE REAL "ENTIER" OPENT2: TSC OPENT3: EXP !$NEXT_22 OPSGN1: EXP !$RA_22 ; IN-LINE "SIGN" OPSGN2: ASH 0,-43 OPSGN3: IORI 0,1 OPADDB: ADDB ; USED IN "FOR" INCREMENT FADRB OPAOS: AOS OPSOS: SOS OPJMPE: JUMPE ; USED IN "FOR" TEST OPJMPG: JUMPG OPJRST: JRST OPBYT3: EXP !$ACC_22 OPSTRA: TCADDF STRASS ; CALL ON STRING ASSIGNMENT OPCMPR: TCADDF COMPAR ; CALL ON STRING COMPARE SR OPSTZB: SETZB 0,(LOP) ; ASSIGN A ZERO OPSTOB: SETOB 0,(LOP) ; ASSIGN ALL ONES OPASHL: ASH 0,21 ; MULTIPLY BY POWER OF 2 OPASHR: ASH 0,-21 ; DIVIDE BY POWER OF 2 OPENT4: FSBRI 0,(0.5) ; IN LINE ENTIER FOR KI10 OPENT5: FIXR 0,0 ; REAL KI10 OPERATORS KIOPS: DMOVE ; 700 DPUSH DMOVEM TCTHEN TCELSE TCFI TCTO TCOT DMOVN ; 710 TCTYDES DMOVNM TCSF DMOVEM 715 DFAD DFSB DFMP ; 720 DFDV SUBTTL CODE GENERATION ROUTINES * CGASS * PROCEDURE CGASS ;..GENERATE CODE TO PERFORM AN ASSIGNMENT; ; ON ENTRY, LEXEME FOR RIGHT HAND SIDE IS IN SYM ; LEXEME FOR LEFT PART IS IN LOP ; IF TYPES ARE ARITHMETIC AND DO NOT MATCH, SYM WILL BE ; CONVERTED TO THE TYPE OF LOP. ; SPECIAL CASES FOR NON-FORMAL ASSIGNMENTS: ; LOP _ 0 ("SETZB" GENERATED) ; LOP _ -1 ("SETOB" GENERATED) ; RESULT IS A CLOSED PORTION WHOSE LEXEME IS IN SYM; BEGIN OWN CGATMP; ;..TEMPORARY TO HOLD LOP FOR FORMALS; IF LOP IS AN ERROR LEXEME JUMPGE LOP,FALSE;$ THEN;..SET RESULT LEXEME AND LEAVE; ERRLEX; ELSE;..NO ERRORS YET ..... GO ON; BEGIN ;..SET REV OFF; MOVNI REV,SYM;$ ;..INITIALIZE OP TO "_" (NEEDED IN REVORDER); MOVE T,ZASS;$ MOVEM T,OP;$ IF LOP NEQ SYM F.TYPE (T3,LOP); F.TYPE (T4,SYM); CAMN T3,T4;$ GOTO FALSE;$ THEN;..TYPES DO NOT MATCH; BEGIN IF LOP = ARITH AND SYM = ARITH TLNN LOP,$ARC;$ T.ARITH (SYM); THEN;..UNMATCHED ARITHMETIC TYPES; ;..CONVERT SYM TO THE TYPE OF LOP; MOVE T,T3;$ CONVERT; ELSE;..TYPES ARE NOT BOTH ARITHMETIC; IF LOP=STRING!REGULAR T.S (LOP); T.REG (LOP); THEN;..BYTE ASSIGNMENT; BEGIN IF SYM = ARITHMETIC T.ARITH (SYM); THEN;..BYTE IS ARITHMETIC; BEGIN IF SYM NEQ INTEGER TN.I (SYM); THEN;..BYTE OPERAND MUST BE CONVERTED TO INTEGER; ;..CONVERT SYM TO INTEGER TYPE; MOVEI T,$I;$ CONVERT; FI ENDD ELSE;..ERROR -- MISMATCHED TYPES; ;GO TO WRITE FAIL MESSAGE AND DIE; GOTO LCGAS3;$ FI ENDD ELSE;..TYPES CANNOT BE MATCHED; BEGIN LCGAS3: FAIL(65,FRIED,SYM,UNMATCHED TYPE CLASSES FOR AN ASSIGNMENT); ;GO TO LAST "ENDD"; GOTO LCGAS1;$ ENDD FI FI ENDD ELSE IF LOP=STRING!REGULAR T.S (LOP); T.REG (LOP); THEN ;..STRING ASSIGNED TO A BYTE POINTER, GO TO WRITE ;..FAIL MESSAGE AND DIE; GOTO LCGAS3;$ FI FI; EDIT(044); Dont force constants to D.P. unnecessarily IF SYM = PSEUDO-LONG REAL CONSTANT ; [E044] TLNN SYM,$TYPE-$LR ; [E044] T.CONST (SYM) ; [E044] TLNE SYM,$CT-$IMM ; [E044] TLNN SYM,$DEC ; [E044] GOTO FALSE ; [E044] F.LOCN (T2,SYM) ; [E044] ADD T2,CONTAB ; [E044] SKIPL T4,3(T2) ; [E044] GOTO FALSE ; [E044] THEN;..CONVERT SYM TO A GENUINE LONG REAL CONSTANT ; [E044] MOVE T3,2(T2) ; [E044] TLZ T4,(1B0) ; [E044] TOCT (2,SYM) ; [E044] FI ; [E044] IF LOP = FORMAL BY NAME T.FON (LOP); THEN;..ASSIGNMENT TO A FORMAL; BEGIN ;..THE THUNK FOR STORING INTO A FORMAL NEEDS THE RIGHT-HAND ; VALUE IN A0 AND THE FORMAL IN A2; IF SYM IS A POINTER T.PTR (SYM); THEN;..PUT ITS VALUE INTO AC0; GOTO LCGAS2;$ FI IF VALUE OF SYM NOT IN AC0 TN.AC0 (SYM); THEN;..PUT IT IN; LCGAS2: LOAD(SYM,A0); FI ;..SAVE LOP (LEXEME FOR FORMAL SYMBOL); MOVEM LOP,CGATMP;$ ;..FOOL MERGEPORTIONS. TELL IT THAT LOP IS AN INT. EXP. (IN A2); TLZ LOP,$KIND!$TYPE!$STATUS!$AM;$ TLO LOP,$EXP!$I!$SIM!$ACC;$ HRRI LOP,A2;$ MERGEPORTIONS; IF LOP IS IN THE STACK OR LOP#A2 TLNN LOP,$STACK;$ GOTO TRUE;$ MOVEI LOP,(LOP);$ CAIN LOP,A2;$ GOTO FALSE;$ THEN;..MERGEPORTIONS DID IT BECAUSE OF ACC CONFLICT; ;..GET LOP BACK INTO A2 (NO CONFLICT POSSIBLE NOW); ;PLUNK(MOVE,A2,LOP); MOVE T,OPMOVE;$ MOVEI T1,A2;$ PLUNK (LOP); FI ;..RESTORE ORIGINAL LOP LEXEME; MOVE LOP,CGATMP;$ ;..EXECUTE THUNK (F[1]); ;PLUNK(TCSF,LOP); ;..TCSF IS A PSEUDO TO GENERATE THE XCT TO STORE INTO A FORMAL; MOVE T,OPTCSF;$ PLUNKI (LOP); ENDD ELSE;..NON-FORMAL ASSIGNMENT; BEGIN IF SYM IS A POINTER T.PTR (SYM); THEN;..LOAD VALUE OF SYM INTO SAME ACC USED BY PTR; F.LOCN (T2,SYM); LOAD(SYM,@T2); ELSE;..SYM IS NOT A POINTER; IF SYM = SINGLE T.SINGLE(SYM); THEN;..THE VALUE OF SYM IS NOT YET IN AN ACC; BEGIN IF LOP NEQ STRING TLNN LOP,$TYPE-$S;$ GOTO FALSE;$ THEN;..CHECK FOR SPECIAL CASES (SYM = 0 OR -1); BEGIN IF SYM = IMMEDIATE AND SYM = 0 TRNN SYM,777777;$ T.IMM (SYM); THEN;..STORE A ZERO; BEGIN ;..GENERATE SETZB TO STORE ZERO IN LOP AND INTO A FREE ACC; MOVE T1,OPSTZB;$ ;..GO AND GENERATE THE STORE INSTRUCTION; GOTO LCGAS5;$ ENDD FI IF SYM IS A ONE WORD CONSTANT = -1 (ALL ONES) TLNE SYM,$CT-$IMM;$ TLNE SYM,$VAR1!$CONST;$ GOTO FALSE;$ F.LOCN (T,SYM); ADD T,CONTAB;$ SETCM T,1(T);$ JUMPN T,FALSE;$ THEN;..STORE ALL ONES; BEGIN ;..GENERATE SETOB TO STORE ONES IN LOP AND AN ACC; MOVE T1,OPSTOB;$ LCGAS5: ;..EMIT SETB COMMAND; HRRI T1,ANYAC;$ PUSHJ SP,.LOAD;$ ;LEX(SYM) _ (EXPR,SAME,SIMPLE,LOP); TLZ SYM,$KIND!$STATUS!$AM;$ TLO SYM,$EXP!$SIM!$ACC;$ HRR SYM,LOP;$ REOPEN(LOP); ;..GO OUT TO COMBINE LEXEMES; GOTO LCGAS4;$ ENDD FI ENDD FI ;..GET THE VALUE OF SYM INTO A FREE ACC; LOAD(SYM,ANYAC); ENDD FI FI IF LOP = BYTE POINTER HLRZ T,LOP;$ CAIE T,$VAR!$S!$REG!$DECL!$PTR;$ GOTO FALSE;$ THEN;..SET SWITCH ON; SETOM 0,CGATMP;$ ELSE;..SET SWITCH OFF; SETZM 0,CGATMP;$ FI IF LOP = SINGLE T.SINGLE(LOP); THEN;..NO PORTION NECESSARY FOR LOP; REOPEN(SYM); ELSE;..BOTH LOP AND SYM ARE PORTIONS; BEGIN REVORDER; MERGEPORTIONS; IF REV T.REV; THEN;..PORTIONS WERE REVERSED; BEGIN ;..RE-EXCHANGE LEXEMES; EXCH LOP,SYM;$ ;..SET REV OFF; MOVNI REV,SYM;$ ENDD FI IF SYM IS IN THE STACK T.STK (SYM); THEN;..VALUE WAS PUSHED DUE TO ACC CONFLICT; ;..PUT IT BACK IN AN ACC; MOVE T,OPMVSM;$ MOVEI T1,ANYAC;$ GLOAD; ELSE;..MAYBE LOP WAS PUSHED; IF LOP IS IN THE STACK T.STK (LOP); THEN;..PTR WAS PUSHED DUE TO ACC CONFLICT. OK UNLESS 2 WORD OPD; BEGIN IF LOP = LONG REAL OR STRING T.TWO (LOP); THEN;..WE MUST RETRIEVE THE POINTER FROM THE STACK; BEGIN ;[220] DON'T ASSUME ANY FREE REGISTER, ALLOCATE ONE USING GLOAD PUSH SP,LOP ;[220] SAVE LOP ;LEX(LOP) _ (SAME,INTEGER,SAME,STACKED) ;[220] TLZ LOP,$TYPE!$AM ;[220] TLO LOP,$I!$SP ;[220] ;[220] LOAD LOP INTO NEXT FREE AC MOVE T,LAC ;[276] GET LAST AC USED BY GLOAD SUBI T,(SYM) ;[276] CALCULATE AC DISTANCE JUMPLE T,EDT276 ;[276] DISTANCE IS NEG., OK CAILE T,2 ;[276] IS AC > 2 AWAY FROM SYM? JRST EDT276 ;[276] YES, OK - USE AS IS MOVE T1,LAC ;[276] NO, GET LAC AGAIN SUB T1,T ;[276] USE NEXT FREE AC CAIG T1,1 ;[276] IS AC NUMBER OK? MOVEI T1,14 ;[276] NO, TOO LOW - WRAP AROUND MOVEM T1,LAC ;[276] YES, STORE NEW LAC VALUE EDT276: MOVE T,OPMVLP ;[276][220] AND FOOL GLOAD MOVEI T1,ANYAC ;[276][262] GLOAD ;[220] ;[220] LEX(LOP) _ (OLD,OLD,OLD,POINTER) TLZ LOP,$TYPE!$AM ;[220] POP SP,T4 ;[220] HLRZ T4,T4 ;[220] ANDI T4,$TYPE ;[220] TLO LOP,$PTR(T4) ;[220] ENDD ;..ELSE LOP IS NOT A 2 WORD OPERAND; FI ENDD ;..ELSE LOP WAS NOT STACKED; FI FI ENDD FI ;..ALL IS READY AND WE CAN PERFORM THE ASSIGNMENT; IF LOP IS A BYTE POINTER SKIPN 0,CGATMP;$ GOTO FALSE;$ THEN;..GENERATE CODE FOR BYTE ASSIGNMENT; BEGIN ;PLUNK(DPB,SYM,LOP); MOVE T,OPBYT3;$ F.LOCN (T1,SYM); HRR T,LOP;$ PLUNK; ;LEX(SYM) _ (EXPR,INTEGER,SIMPLE,ACC); TLZ SYM,$KIND!$TYPE!$STATUS!$AM;$ TLO SYM,$EXP!$I!$SIM!$ACC;$ ENDD ELSE;..DO A NORMAL MOVE TO MEMORY; IF SYM = STRING T.S (SYM);$ THEN;..PLANT CALL TO STRASS BEGIN MOVE T,OPLPSH;$ MOVEI T1,SP;$ ; PUSH SYM PLUNK(SYM);$ EDIT(032) ; ALLOW FOR THE CASE OF LOP IN AC 0 OR 1 IF LOP IN AC 0 OR 1 ; [E032] HRLEI T,-1(LOP) ; [E032] TLNN LOP,$AMAC ; [E032] JUMPLE T,TRUE ; [E032] GOTO FALSE ; [E032] THEN ; [E032] ; WE HAVE NOW PUSHED SYM FROM SOME ACCS ONTO THE STACK. WE WILL NOT ;USE THESE ACCS ANY MORE, AS WE ARE ABOUT TO ELABORATE THE RESULT OF ;STRASS (WHICH WILL BE IN AC 0 & 1) INTO SYM. THEREFORE WE CAN USE ONE ;OF THE ACCS THAT SYM WAS IN WITHOUT ANY FEAR OF LATER ACC CONFLICT !!. MOVSI T,() ; [E032] HRRI T,(LOP) ; [E032] HRRI LOP,1(SYM) ; [E032] F.LOCN(T1,LOP) ; [E032] PLUNK; [E032] FI ; [E032] ; PUSH LOP MOVE T,OPLPSH;$ MOVEI T1,SP;$ PLUNK(LOP);$ MOVE T,OPSTRA;$ PLUNKI; ;..SYM _ (EXPR,SIM,AC0) TLZ SYM,$KIND!$STATUS!$AM;$ TLO SYM,$EXP!$SIM!$ACC;$ TRZ SYM,777777;$ EDIT(200); REMEMBER THAT CALL TO STRASS WILL USE AC0 AND AC1 ;HANDLE := HANDLE OR ;[200] MOVSI T,3 ;[200] MARK REGISTERS 0 AND 1 AS USED IORM T,HANDLE ;[200] IN HANDLE ENDD; FI; ;PLUNK(ASSIGN,LOP,SYM); F.TRANK (T,SYM); MOVE T,OPASS(T);$ F.LOCN (T1,SYM); PLUNK (LOP); FI ENDD; FI LCGAS4: CLOSE(SYM); ;..COMBINE LEXEXES AND COMPOSITE NAMES; COMBASSIGN; ENDD FI LCGAS1: ENDD ; CGASS SUBTTL CODE GENERATION ROUTINES * CGBIN * PROCEDURE CGBIN ;..GENERATE CODE TO PERFORM A BINARY OPERATION; ; ON ENTRY, OPERATION LEXEME IS IN OP; ; OPERAND LEXEMES ARE IN LOP AND SYM; ; IF BOTH OPERANDS ARE CONSTANTS, THE OPERATION IS USUALLY ; DONE AT COMPILE TIME, A NEW CONSTANT IS GENERATED, ; AND NO CODE IS PRODUCED. ; OPERANDS WILL BE REVERSED IF POSSIBLE, AND OPERATIONS ; MAY ALSO BE REVERSED (E.G., "<" BECOMES ">"). ; ARITHMETIC TYPES WILL BE MATCHED BY CONVERTING ONE ; OPERAND TO THE TYPE OF THE OTHER ; (IN THE ORDERING INTEGER => REAL => LONG REAL). ; SPECIAL CASES FOR BINARY OPERATIONS: ; LOP ^ 2 (GENERATES "MULTIPLY LOP,LOP") ; LOP DIV (2^N) (GENERATES "ASH -N") ; LOP * (2^N) (GENERATES "ASH N") ; LOP + (-CONST) (CHANGED TO (LOP - CONST)) ; RESULT IS A CLOSED PORTION WHOSE LEXEME IS IN SYM; BEGIN LOCAL LACSAV; IF LOP IS AN ERROR LEXEME JUMPGE LOP,FALSE;$ THEN;..SET RESULT LEXEME AND LEAVE; ERRLEX; ELSE;..NO ERRORS YET ..... GO ON; BEGIN ;..SET REV OFF; MOVNI REV,SYM;$ IF OP IS ARITHMETIC F.DISC (T); CAILE T,OPMINUS-OPCODE;$ GOTO FALSE;$ THEN;..ARITHMETIC OPERATION; BEGIN IF LOP = ARITH AND SYM = ARITH TLNN LOP,$ARC;$ T.ARITH (SYM); THEN;..OPERANDS ARE ARITHMETIC; BEGIN IF OP = "REM" OR "DIV" MOVE T,OP;$ CAMN T,ZREM;$ GOTO TRUE;$ CAME T,ZDIV;$ GOTO FALSE;$ THEN;..MUST DO AN INTEGER DIVIDE; BEGIN IF LOP = INTEGER AND SYM = INTEGER TLNN LOP,$TYPE-$I;$ T.I (SYM); THEN;..OPERANDS ARE INTEGERS; BEGIN IF NOT TREATCONST TREATCONST; JUMPN T,FALSE;$ THEN;..OPERANDS ARE NOT BOTH CONSTANTS; BEGIN ;..GIVE LOP SPECIAL TYPE SO LOAD WILL USE 2 AC'S; TLZ LOP,$TYPE;$ TLO LOP,$IDI;$ IF VALUE OF LOP IN LAST AC OR NOT IN AC TLNE LOP,$AM-$ACC;$ GOTO TRUE;$ F.LOCN (T,LOP); CAIE T,A13;$ GOTO FALSE;$ THEN;..MUST MOVE LOP TO AN AC PAIR; BEGIN LOAD(LOP,ANYAC); ENDD FI SETUP; ;..RESET TYPE TO INTEGER; TLZ LOP,$TYPE;$ TLO LOP,$I;$ ;EMITCODE(IDIV,LOP,SYM,2); MOVE T,OPDIV;$ F.LOCN (T1,LOP); HRLI T1,2;$ EMITCODE(SYM); ;LEX(SYM) _ (EXPR,INTEGER,SIMPLE,LOP); TLZ SYM,$KIND!$TYPE!$STATUS!$AM;$ TLO SYM,$EXP!$I!$SIM!$ACC;$ HRR SYM,LOP;$ IF OP = "REM" T.OPER (ZREM); THEN;..RESULT WILL BE IN AC+1; ;SYM _ SYM + 1; HRRZ T,SYM;$ ADDI T,1;$ HRR SYM,T;$ FI CLOSE(SYM); COMBLEX; ENDD FI ENDD ELSE;..OPERANDS ARE NOT INTEGERS; FAIL(67,FRIED,SYM,NON-INTEGER OPERAND FOR "REM" OR "DIV"); FI ENDD ELSE;..OP NEQ "REM" AND OP NEQ "DIV"; IF OP = "^" T.OPER (ZPOW); THEN;..POWER OPERATION; BEGIN IF NOT TREATCONST TREATCONST; JUMPN T,FALSE;$ THEN;..OPERANDS ARE NOT BOTH CONSTANTS; BEGIN IF SYM = IMMEDIATE AND SYM = 2 F.LOCN (T,SYM); CAIN T,2;$ T.IMM (SYM); THEN;..WE CAN USE MULTIPLY INSTEAD OF POWER; ;..( LOP ^ 2 = LOP * LOP ); BEGIN IF LOP IS A POINTER T.PTR (LOP); THEN;..LOAD VALUE INTO SAME ACC USED BY PTR; F.LOCN (T2,LOP); LOAD(LOP,@T2); ELSE;..NOT A POINTER; IF LOP IS SINGLE T.SINGLE(LOP); THEN;..MAKE A PORTION TO LOAD LOP INTO AN ACC; LOAD(LOP,ANYAC); FI FI REOPEN(LOP); ;..GENERATE (MULTIPLY,LOP,LOP); ;SYM _ LOP; MOVE SYM,LOP;$ ;OP _ "*"; MOVE T,ZTIMES;$ MOVEM T,OP;$ ;GO AND EMIT THE "*" OPERATION; GOTO LCGBI3;$ ENDD FI ;..COMBINE PORTIONS; MARRY; IF REV T.REV; THEN;..PORTIONS WERE REVERSED; BEGIN ;..EXCHANGE THE LEXEMES AGAIN; EXCH LOP,SYM;$ ;..SET REV OFF; MOVNI REV,SYM;$ ENDD FI ;..WE MUST NOW STACK BOTH OPERANDS FOR THE POWER SR; EDIT(044);Don't force all constants to D.P. IF SYM = LONG REAL ; [E044] T.LR (SYM) ; [E044] THEN; ; [E044] BEGIN; ; [E044] IF SYM = PSEUDO-LONG CONSTANT ; [E044] T.CONST (SYM) ; [E044] TLNE SYM,$CT-$IMM ; [E044] TLNN SYM,$DEC ; [E044] GOTO FALSE ; [E044] F.LOCN (T2,SYM) ; [E044] ADD T2,CONTAB ; [E044] SKIPL A1,3(T2) ; [E044] GOTO FALSE ; [E044] THEN; ; [E044] BEGIN; ; [E044] IF LOP # GENUINE LONG REAL ; [E044] TLNE LOP,$TYPE-$LR ; [E044] GOTO TRUE ; [E044] T.CONST (LOP) ; [E044] TLNE LOP,$CT-$IMM ; [E044] TLNN LOP,$DEC ; [E044] GOTO FALSE ; [E044] F.LOCN (T1,LOP) ; [E044] ADD T1,CONTAB ; [E044] SKIPL 3(T1) ; [E044] GOTO FALSE ; [E044] THEN;SYM SHOULD BE REAL ; [E044] MOVE T3,A0 ; [E044] MOVE A0,2(T2) ; [E044] TLZ A1,(1B0) ; [E044] PUSHJ SP,CTLRR ; [E044] EXCH T3,A0 ; [E044] TOCT (1,SYM) ; [E044] TLZ SYM,$TYPE ; [E044] TLO SYM,$R ; [E044] GOTO LCPOW1 ; [E044] ELSE;SYM SHOULD BE LONG ; [E044] MOVE T3,2(T2) ; [E044] MOVE T4,3(T2) ; [E044] TLZ T4,(1B0) ; [E044] TOCT (2,SYM) ; [E044] FI; ; [E044] ENDD; ; [E044] ELSE; SYM IS GENUINE LONG REAL ; [E044] IF LOP = PSEUDO-LONG REAL ; [E044] TLNN LOP,$TYPE-$LR ; [E044] T.CONST (LOP) ; [E044] TLNE LOP,$CT-$IMM ; [E044] TLNN LOP,$DEC ; [E044] GOTO FALSE ; [E044] F.LOCN (T2,LOP) ; [E044] ADD T2,CONTAB ; [E044] SKIPL T4,3(T2) ; [E044] GOTO FALSE ; [E044] THEN;MAKE LOP GENUINE LONG ; [E044] MOVE T3,2(T2) ; [E044] TLZ T4,(1B0) ; [E044] TOCT (2,LOP) ; [E044] FI; ; [E044] FI; ; [E044] ENDD; ; [E044] ELSE;SYM IS NOT LONG REAL ; [E044] LCPOW1: ; [E044] IF LOP = PSEUDO-LONG REAL ; [E044] TLNN LOP,$TYPE-$LR ; [E044] T.CONST (LOP) ; [E044] TLNE LOP,$CT-$IMM ; [E044] TLNN LOP,$DEC ; [E044] GOTO FALSE ; [E044] F.LOCN (T2,LOP) ; [E044] ADD T2,CONTAB ; [E044] SKIPL A1,3(T2) ; [E044] GOTO FALSE ; [E044] THEN;CONVERT LOP TO REAL ; [E044] MOVE T3,A0 ; [E044] MOVE A0,2(T2) ; [E044] TLZ A1,(1B0) ; [E044] PUSHJ SP,CTLRR ; [E044] EXCH T3,A0 ; [E044] TOCT (1,LOP) ; [E044] TLZ LOP,$TYPE ; [E044] TLO LOP,$R ; [E044] FI; ; [E044] FI; ; [E044] EDIT(110); Check for variables already on the stack IF SYM IS IN THE STACK ; [E110] T.STK (SYM) ; [E110] THEN; PUT IT BACK IN AN ACC ; [E110] MOVE T,OPMVSM ; [E110] MOVEI T1,ANYAC ; [E110] GLOAD; ; [E110] FI; ; [E110] IF LOP = LONG REAL T.LR (LOP); THEN ;OPN IS LPUSH; MOVE T,OPLPSH;$ ELSE;..SHORT OPERAND; BEGIN IF LOP IS IMMEDIATE T.IMM (LOP); THEN;..PUT CONSTANT IN TABLE SO IT CAN BE PUSHED; BEGIN IF LOP = INTEGER T.I (LOP); THEN;..IMMED. CONST. GOES TO RIGHT HALF OF T3; HRRZ T3,LOP;$ ELSE;..IMMED. CONST. GOES TO LEFT HALF OF T3; HRLZ T3,LOP;$ FI ;..PUT CONSTANT INTO TABLE; TOCT(1,LOP); ENDD FI ;..OPN IS "PUSH"; MOVE T,OPPUSH;$ ENDD FI ;..PUSH LOP; ;PLUNK(OPN,SP,LOP); MOVEI T1,SP;$ PLUNK (LOP); IF SYM = LONG REAL T.LR (SYM); THEN ;OPN IS LPUSH; MOVE T,OPLPSH;$ ELSE;..SHORT OPERAND; BEGIN IF SYM IS IMMEDIATE T.IMM (SYM); THEN;..PUT CONSTANT IN TABLE SO IT CAN BE PUSHED; BEGIN IF SYM = INTEGER T.I (SYM); THEN;..IMMED. CONST. GOES TO RIGHT HALF OF T3; HRRZ T3,SYM;$ ELSE;..REAL IMM. CONST. GOES TO LEFT OF T3; HRLZ T3,SYM;$ FI ;..PUT CONSTANT INTO TABLE; TOCT(1,SYM); ENDD FI ;..OPN IS "PUSH"; MOVE T,OPPUSH;$ ENDD FI ;..PUSH SYM; ;PLUNK(OPN,SP,SYM); MOVEI T1,SP;$ PLUNK (SYM); ;..GET POWER INFORMATION WORD; F.TRANK (T3,LOP); LSH T3,2;$ F.TRANK (T,SYM); OR T3,T;$ MOVE T3,OPPOW(T3);$ IF SYM NEQ INTEGER TN.I (SYM); THEN;..PUT CODE VALUE IN AC1; BEGIN ;PLUNK(MOVEI,AC1,POWER CODE); MOVE T,T3;$ ANDI T,3;$ HLL T,OPMVI1;$ PLUNKI; ;..BOOK AC1 USED; MOVSI T,2;$ IORM T,HANDLE;$ ENDD ELSE;..EXPONENT IS AN INTEGER; BEGIN IF LOP = INTEGER T.I (LOP); THEN;..INTEGER ^ INTEGER. RESULT MAY BE INT. OR REAL; BEGIN IF SYM = CONSTANT GEQ ZERO T.CONST (SYM); F.LOCN (T,SYM); ADD T,CONTAB;$ SKIPGE 0,1(T);$ GOTO FALSE;$ THEN;..CODE _ 0 AND RESULT WILL BE INTEGER; BEGIN ;POWER CODE _ 0; MOVEI T,0;$ ;RESULT.TYPE _ INTEGER; TRZ T3,$TYPE;$ TRO T3,$I;$ ENDD ELSE;..CODE _ 1 AND RESULT WILL BE REAL; ;POWER CODE _ 1; MOVEI T,1;$ FI ;..PUT CODE VALUE IN AC1; ;PLUNK(MOVEI,AC1,POWER CODE); HLL T,OPMVI1;$ PLUNKI; ;..BOOK AC0-AC5 USED; MOVSI T,77;$ IORM T,HANDLE;$ ENDD FI ENDD FI ;..CALL POWER SUBROUTINE; ;PLUNK(POWER NAME); HLLZ T,T3;$ PLUNKI; IF RESULT.TYPE = LONG REAL ANDI T3,$TYPE;$ CAIE T3,$LR;$ GOTO FALSE;$ THEN;..BOOK AC0-AC13 USED; MOVSI T,7777;$ ELSE;..BOOK AC0-4 USED; MOVSI T,37;$ FI IORM T,HANDLE;$ ;LEX(SYM) _ (EXPR,RESULT.TYPE,SIMPLE,AC0); TLZ SYM,$KIND!$TYPE!$STATUS!$AM;$ TLO SYM,$EXP!$SIM!$ACC;$ TSO SYM,T3;$ HRRI SYM,0;$ CLOSE(SYM); COMBLEX; ENDD ;..ELSE BOTH OPDS WERE CONSTS AND A NEW CONST WAS GENERATED; FI ENDD ELSE;..OP NEQ "^" OR "REM" OR "DIV"; BEGIN IF OP = SLASH AND LOP = INTEGER AND SYM = INTEGER T.OPER (ZSLASH); TLNN LOP,$TYPE-$I;$ T.I (SYM); THEN;..SLASH OPERATION REQUIRES REAL OPERANDS; ;CONVERT(REAL,SYM); MOVEI T,$R;$ CONVERT; FI IF NOT CHECKARITH CHECKARITH; JUMPN T,FALSE;$ THEN;..OPERANDS NOW HAVE MATCHING ARITHMETIC TYPES; BEGIN IF NOT TREATCONST TREATCONST; JUMPN T,FALSE;$ THEN;..OPERANDS ARE NOT BOTH CONSTANTS; BEGIN SETUP; IF OP = "*" AND SYM = IMMED. INT. = 2^N (0 LEQ N LSS 18) MOVE T,OP;$ CAMN T,ZTIMES;$ TLNE SYM,$AM-$IMM+$TYPE-$I;$ GOTO FALSE;$ HRLZ T,SYM;$ JFFO T,.+2;$ GOTO FALSE;$ LSH T,1(T1);$ JUMPN T,FALSE;$ THEN;..WE CAN SHIFT RATHER THAN MULTIPLY; BEGIN ;PLUNK(ASH,LOP,N); MOVE T,OPASHL;$ SUB T,T1;$ F.LOCN (T1,LOP); PLUNK; ;GO AND SET UP THE LEXEME; GOTO LCGBI4;$ ENDD FI IF OP = "+" AND SYM = NEGATED IMM. INT. CONSTANT T.OPER (ZPLUS); TLNN SYM,$CONST+$TYPE-$I;$ TLNN SYM,$CT-$IMM;$ GOTO FALSE;$ F.LOCN (T,SYM); ADD T,CONTAB;$ MOVN T1,1(T);$ JUMPL T1,FALSE;$ CAILE T1,-1;$ GOTO FALSE;$ THEN;..CHANGE "A + (- CONSTANT)" TO "A - CONSTANT"; BEGIN ;OP _ "-"; MOVE T,ZMINUS;$ MOVEM T,OP;$ ;LEX(SYM) _ (IMMED.,SAME,SAME,-(VALUE(SYM))); TLZ SYM,$AM;$ TLO SYM,$IMM;$ HRR SYM,T1;$ ENDD FI LCGBI3: ;..GENERATE THE INSTRUCTION TO PERFORM "OP"; ;EMITCODE(OPN,LOP,SYM,LENGTH); F.TRANK (T,SYM); F.DISC (T1); ADD T,T1;$ MOVE T,OPCODE(T);$ F.LOCN (T1,LOP); IF LOP IS LONG REAL T.LR (LOP); THEN BEGIN HLRZ T1,T LSH T1,-11 TRZ T1,700 CAIGE T1,22 MOVE T,KIOPS(T1) ; LENGTH _ 2; HRLI T1,2 ENDD ELSE ; LENGTH _ 1 (TYPE # LONG REAL) HRLI T1,1;$ FI EDIT(026); DONT DESTROY LENGTH CODE CAREFULLY SET UP IN L.H. OF T1 HRR T1,LOP ; [E026] EMITCODE(SYM); LCGBI4: ;LEX(SYM) _ (EXPR,SAME,SIMPLE,LOP); TLZ SYM,$KIND!$STATUS!$AM;$ TLO SYM,$EXP!$SIM!$ACC;$ HRR SYM,LOP;$ CLOSE(SYM); COMBLEX; ENDD ;..ELSE BOTH OPDS WERE CONSTS AND A NEW CONST WAS GENERATED; FI ENDD ELSE;..TYPE OF AN OPERAND IS NOT INTEGER, REAL, OR LONG REAL; FAIL(68,FRIED,SYM,COMPLEX OPERAND FOR ARITH OPERATOR); FI ENDD FI FI ENDD ELSE;..AN OPERAND IS NOT ARITHMETIC; FAIL(69,FRIED,SYM,NON-ARITH OPERAND FOR ARITH OPERATOR); FI ENDD ELSE;..OP IS NOT ARITHMETIC; IF OP = RELATIONAL T.RELATION(T); THEN;..WE HAVE A RELATION; BEGIN IF NOT CHECKARITH CHECKARITH; JUMPN T,FALSE;$ THEN;..OPERANDS NOW HAVE MATCHING ARITHMETIC TYPES; BEGIN IF NOT TREATCONST TREATCONST; JUMPN T,FALSE;$ THEN;..OPERANDS ARE NOT BOTH CONSTANTS; BEGIN SETUP; IF SYM = LONG REAL T.LR (SYM); THEN;..OPERANDS ARE BOTH LONG REAL; BEGIN ;..SUBTRACT SYM FROM LOP; ;EMITCODE(LFSB,LOP,SYM,3); MOVE T,OPLFSB;$ F.LOCN (T1,LOP); HRLI T1,3;$ EMITCODE(SYM); ;..TEST RESULT VS. ZERO; ;PLUNK(OPN+1,LOP,ZERO); F.DISC (T); MOVE T,OPCODE+1(T);$ F.LOCN (T1,LOP); PLUNK; ENDD ELSE;..OPERANDS ARE INTEGER OR REAL; ;..COMPARE THE OPERANDS; IF SYM = IMMEDIATE T.IMM (SYM); THEN;..IMMEDIATE CONSTANT; BEGIN IF SYM = REAL T.R (SYM); THEN;..REAL IMMEDIATE CONSTANT; BEGIN ;..SUBTRACT SYM FROM LOP; ;EMITCODE(FSBR,LOP,SYM,1); MOVE T,OPFSBR;$ F.LOCN (T1,LOP); HRLI T1,1;$ EMITCODE(SYM); ;..TEST RESULT VS. ZERO; ;PLUNK(OPN+1,LOP,0); F.DISC (T); MOVE T,OPCODE+1(T);$ F.LOCN (T1,LOP); PLUNK; ENDD ELSE;..INTEGER IMMEDIATE CONSTANT; ;EMITCODE(OPN+1,LOP,SYM,1); F.DISC (T); MOVE T,OPCODE+1(T);$ F.LOCN (T1,LOP); HRLI T1,1;$ EMITCODE(SYM); FI ENDD ELSE;..NON-IMMEDIATE OPERAND; ;EMITCODE(OPN,LOP,SYM,1); F.DISC (T); MOVE T,OPCODE(T);$ F.LOCN (T1,LOP); HRLI T1,1;$ EMITCODE(SYM); FI FI LCGBI2: ;..RESULT MUST BE "TRUE" OR "FALSE". GENERATE IT; ;PLUNK(TDZA,LOP,LOP); MOVE T,OPTDZA;$ F.LOCN (T1,LOP); PLUNK (LOP); ;PLUNK(SETO,LOP,0); MOVE T,OPSETO;$ F.LOCN (T1,LOP); PLUNK; ;LEX(SYM) _ (EXPR,BOOLEAN,SIMPLE,LOP); TLZ SYM,$KIND!$TYPE!$STATUS!$AM;$ TLO SYM,$EXP!$B!$SIM!$ACC;$ HRR SYM,LOP;$ CLOSE(SYM); COMBLEX; ENDD ;..ELSE BOTH OPDS WERE CONSTS AND A NEW CONST WAS GENERATED; FI ENDD ELSE;..A RELATIONAL OPERAND IS NOT INTEGER OR REAL OR LONG REAL; IF LOP = STRING AND SYM = STRING TLNN LOP,$TYPE-$S;$ T.S (SYM); THEN;..RELATION BETWEEN STRINGS; BEGIN ;..PUT OPERANDS IN A0-1 AND A2-3 FOR THE COMPARE SR; IF VALUE OF LOP IS NOT IN AC0 TN.AC0 (LOP); THEN;..MUST PUT IT INTO AC0 AND AC1; LOAD(LOP,A0); FI IF VALUE OF SYM IS NOT IN AC2 TLNE SYM,$AM-$ACC;$ GOTO TRUE;$ F.LOCN (T,SYM); CAIN T,A2;$ GOTO FALSE;$ THEN;..MUST PUT IT INTO AC2 AND AC3; ;..FUDGE LAC=A4 TO MAKE LOAD WORK; MOVEI T,A4;$ EXCH T,LAC;$ MOVEM T,LACSAV;$ LOAD(SYM,A2); ;..RESTORE LAC; MOVE T,LACSAV;$ MOVEM T,LAC;$ FI MERGEPORTIONS; IF LOP NOT IN AC0 TN.AC0 (LOP); THEN;..IT WAS MOVED DUE TO ACC CONFLICT. PUT IT BACK IN AC0; MOVE T,OPMVLP;$ MOVEI T1,A0;$ GLOAD; FI ;..GENERATE CALL ON COMPARE SUBROUTINE; MOVE T,OPCMPR;$ PLUNKI; ;..RESULT IS -1, 0, OR +1 IN REGISTER AC0; HRRI LOP,A0;$ ;..GENERATE THE INST. TO TEST RESULT OF COMPAR VS. ZERO; ;EMITCODE(OPN+1,AC0,0,1); F.DISC (T); MOVE T,OPCODE+1(T);$ HRLZI T1,1;$ EMITCODE; ;..NOW GO GENERATE THE BOOLEAN RESULT; GOTO LCGBI2;$ ENDD ELSE;..TYPES CANNOT BE CORRECT; FAIL(70,HARD,NSYM,NON-ARITH OPERAND FOR RELATIONAL OPERATOR); FI FI ENDD ELSE;..OP IS NOT ARITHMETIC OR RELATIONAL. IT MUST BE BOOLEAN; BEGIN IF LOP = BOOLEAN AND SYM = BOOLEAN TLNN LOP,$TYPE-$B;$ T.B (SYM); THEN;..OPERANDS ARE BOTH BOOLEAN; BEGIN IF NOT TREATCONST TREATCONST; JUMPN T,FALSE;$ THEN;..OPERANDS ARE NOT BOTH CONSTANTS; BEGIN SETUP; ;..GENERATE THE INSTRUCTION TO PERFORM "OP"; ;EMITCODE(OPN,LOP,SYM,1); F.DISC (T); MOVE T,OPCODE(T);$ F.LOCN (T1,LOP); HRLI T1,1;$ EMITCODE(SYM); ;LEX(SYM) _ (EXPR,SAME,SIMPLE,LOP); TLZ SYM,$KIND!$STATUS!$AM;$ TLO SYM,$EXP!$SIM!$ACC;$ HRR SYM,LOP;$ CLOSE(SYM); COMBLEX; ENDD ;..ELSE BOTH OPDS WERE CONSTS AND A NEW CONST WAS GENERATED; FI ENDD ELSE;..AN OPERAND IS NOT BOOLEAN; FAIL(71,FRIED,SYM,NON-BOOLEAN OPERAND FOR BOOLEAN OPERATOR); FI ENDD FI FI ENDD FI ENDD ; CGBIN SUBTTL CODE GENERATION ROUTINES * CGUNA * PROCEDURE CGUNA ;..PROCESS UNARY OPERATORS; ; GENERATE CODE TO PERFORM UNARY "+", "-", AND "NOT". ; ON ENTRY, OPERATION LEXEME IS IN OP; ; OPERAND IS IN SYM; ; RESULT IS A CLOSED PORTION WHOSE LEXEME IS IN SYM; BEGIN ;..SET REV OFF; MOVNI REV,SYM;$ IF OP = "NOT" T.OPER (ZNOT); THEN;..LOGICAL COMPLEMENT; BEGIN IF SYM NEQ BOOLEAN TN.B (SYM); THEN FAIL(72,FRIED,SYM,NON-BOOLEAN OPERAND FOR "NOT"); ELSE;..OPERAND IS BOOLEAN; BEGIN IF NOT TRUNACONST TRUNACONST; JUMPN T,FALSE;$ THEN;..OPERAND IS NOT CONSTANT; BEGIN IF SYM IS AN EXPR OR A POINTER IN AN ACC T.ACC (SYM); THEN;..OPERAND OR ITS POINTER IS ALREADY IN AN AC; BEGIN REOPEN(SYM); ;..COMPLEMENT THE OPERAND; ;PLUNK(NOT,SYM,SYM); MOVE T,OPNOT;$ F.LOCN (T1,SYM); PLUNK (SYM); ;LEX(SYM) _ (EXPR,SAME,SIMPLE,ACC); TLZ SYM,$KIND!$STATUS!$AM;$ TLO SYM,$EXP!$SIM!$ACC;$ CLOSE(SYM); ENDD ELSE;..OPERAND IS NOT IN AN AC. LOAD ITS COMPLEMENT; LOADC(SYM,ANYAC); FI ENDD ;..ELSE OPERAND WAS CONSTANT AND A NEW CONST WAS GENERATED; FI ENDD FI ENDD ELSE;..OP NEQ "NOT". IT MUST BE "+" OR "-"; BEGIN IF SYM NEQ ARITH TN.ARITH(SYM); THEN FAIL(73,FRIED,SYM,NON-ARITH OPERAND FOR UNARY "+" OR "-"); ELSE;..OPERAND IS ARITHMETIC; BEGIN IF OP = UNARY "-" T.OPER (ZUMINUS); THEN;..OP = NEGATE; BEGIN IF NOT TRUNACONST TRUNACONST; JUMPN T,FALSE;$ THEN;..OPERAND IS NOT CONSTANT; BEGIN IF SYM IS A LONG REAL POINTER IN AN ACC TLNN SYM,$AMAC+$TYPE-$LR;$ TLNN SYM,$INDC;$ GOTO FALSE;$ THEN;..VALUE OF OPERAND NOT IN ACC. LOAD ITS NEGATIVE; GOTO LCGUN1;$ FI IF SYM IS AN EXPR IN ACC T.ACC (SYM); THEN;..OPERAND OR ITS POINTER IS ALREADY IN AN ACC; BEGIN REOPEN(SYM); ;..NEGATE THE OPERAND; ;PLUNK(MOVN,SYM,SYM) OR PLUNK(DFN,SYM,SYM+1); F.TRANK (T,SYM); MOVE T,OPUMIN(T); F.LOCN (T1,SYM); MOVE T2,SYM;$ TLZ T2,777777-$AM;$ ADD T,T2;$ PLUNK; ;LEX(SYM) _ (EXPR,SAME,SIMPLE,ACC); TLZ SYM,$KIND!$STATUS!$AM;$ TLO SYM,$EXP!$SIM!$ACC;$ CLOSE(SYM); ENDD ELSE;..OPERAND IS NOT IN AN AC. LOAD ITS NEGATIVE; LCGUN1: LOADN(SYM,ANYAC); FI ENDD ;..ELSE OPD WAS CONST AND NEGATED CONST WAS GENERATED; FI ENDD ;..ELSE OPERATION IS UNARY "+". NO ACTION NEEDED; FI ENDD FI ENDD FI ENDD ; CGUNA SUBTTL CODE GENERATION ROUTINES * TREATCONST * PROCEDURE TREATCONST ;..PERFORM BINARY OP AT COMPILE-TIME WHEN BOTH OPDS ARE CONSTANTS. ; IF AT LEAST ONE OPERAND IS NON-CONSTANT, ; FLAG (T) IS SET TO "FALSE" (ALL ZEROS); ; IF BOTH ARE CONSTANT, NEW CONSTANT IS PRODUCED ; AND FLAG IS SET TO "TRUE" (ALL ONES). ; ON ENTRY, OPERAND LEXEMES ARE IN LOP AND SYM, ; OPERATION LEXEME IS IN OP. ; IF OPERATION = "^", NEW CONSTANT IS PRODUCED ONLY IF ; EXPONENT IS AN INTEGER. ; RESULT LEXEME GOES TO SYM. ; NEW CONSTANT IS PUT INTO LEXEME IF IT IS IMMEDIATE, ; OTHERWISE IT IS PUT INTO THE CONSTANT TABLE. BEGIN OWN TA0,DPFLAG; TA0 = TEMPORARY TO HOLD A0 (GBREG) ; [E044] ;DPFLAG SET IF EXPLICIT DOUBLE PRECISION; [E044] IF LOP = CONSTANT AND SYM = CONSTANT TLNN LOP,$CONST;$ T.CONST (SYM); THEN;..WE MUST PRODUCE A NEW CONSTANT; BEGIN ;..MAKE SURE OVERFLOW FLAGS ARE OFF; JFCL 11,LTC2;$ LTC2: IF OP NEQ "^" TN.OPER (ZPOW); THEN;..OP IS NOT POWER AND TYPES OF LOP AND SYM MATCH; BEGIN IF SYM NEQ LONG REAL TN.LR (SYM); THEN;..TYPES OF LOP AND SYM ARE NOT LONG REAL; BEGIN ;T2 _ LOP; F.LOCN (T2,LOP); ;..PUT VALUE OF LOP INTO T3; IF LOP = IMMEDIATE T.IMM (LOP); THEN;..IMMEDIATE LEFT OPERAND; IF SYM = REAL T.R (SYM); THEN ;FETCH IMMEDIATE REAL CONSTANT; HRLZ T3,T2;$ ELSE ;FETCH IMMEDIATE INTEGER OR BOOLEAN CONSTANT; HRRZ T3,T2;$ FI ELSE;..LEFT OPERAND IS IN CONSTANT TABLE; ;FETCH CONSTANT FROM TABLE; ADD T2,CONTAB;$ MOVE T3,1(T2);$ FI ;..NOW GENERATE INSTRUCTION ; ;..FIRST COMPUTE INCREMENT FOR OPCODE TABLE INDEX; IF OP = RELATIONAL T.RELATION(T); THEN ;T1 _ 0; SETZ T1,0;$ ELSE IF SYM = BOOLEAN T.B (SYM); THEN ;T1 _ 0; SETZ T1,0;$ ELSE IF OP="REM" T.OPER (ZREM); THEN; FUDGE INDEX TO GET AN IDIV; ;T1_-2; MOVNI T1,2;$ ELSE; USE THE RANK AS AN INDEX; ;T1 _ SYM; F.TRANK (T1,SYM); FI FI FI ;T1 _ ; F.DISC (T); ADD T,T1;$ MOVE T1,OPCODE(T);$ TLO T1,T3_5;$ ;..T2 _ SYM; F.LOCN (T2,SYM); IF SYM = IMMEDIATE T.IMM (SYM); THEN;..IMMEDIATE RIGHT OPERAND; BEGIN IF OP = RELATIONAL T.RELATION(T); THEN;..IMMEDIATE RIGHT OPERAND IN A RELATION; BEGIN IF SYM = REAL T.R (SYM); THEN;..REAL IMMEDIATE CONSTANT IN A RELATION; BEGIN ;..LOAD CONSTANT INTO T2; HRLZ T2,T2;$ ;..ADDRESS OF OPERAND IS T2; HRRI T1,T2;$ ENDD ELSE;..INTEGER IMMED. CONST. IN A RELATION; BEGIN ;..SUBTRACT 10 FROM INST. CODE TO GET IMMED. (I) VARIANT; ;T1 _ T1 - 10; TLZ T1,010000;$ ;..LOAD IMMEDIATE CONSTANT; HRR T1,T2;$ ENDD FI ENDD ELSE;..OP IS NOT A RELATION; BEGIN ;..ADD 1 TO PDP-10 INST. CODE TO GET IMMEDIATE (I) VARIANT; ;T1 _ T1 + 1; TLO T1,001000;$ ;..LOAD IMMEDIATE CONSTANT; HRR T1,T2;$ ENDD FI ENDD ELSE;..RIGHT OPERAND IS IN CONSTANT TABLE; ;LOAD ADDRESS OF CONSTANT; ADD T2,CONTAB;$ HRRI T1,1(T2);$ FI ;..INSTRUCTION IS NOW READY; IF OP = RELATIONAL T.RELATION(T); THEN;..WE HAVE A RELATION; BEGIN ;..EXECUTE THE INSTRUCTION IN T1; XCT T1;$ ;..GENERATE "FALSE" OR "TRUE" CONSTANT; TDZA T3,T3;$ SETO T3,0;$ ;SYM _ BOOLEAN; TLZ SYM,$TYPE;$ TLO SYM,$B;$ ENDD ELSE;..OP IS NOT A RELATION; BEGIN ;..EXECUTE THE INSTRUCTION IN T1; XCT T1;$ IF OP = "REM" T.OPER (ZREM); THEN;..QUOTIENT IS IN T3, REMAINDER IS IN T4; ;RESULT CONSTANT IS REMAINDER(IDIV); MOVE T3,T4;$ FI ENDD FI IF NO OVERFLOW FLAGS SET JFCL 11,FALSE;$ THEN;..NO OVERFLOW. VALID RESULT WAS PRODUCED; STOCON; ELSE;..OVERFLOW IN OPERATION ON CONSTANTS. RESULT IS INVALID; BEGIN FAIL(74,FRIED,SYM,OVERFLOW WHILE COMBINING CONSTANTS); ERRLEX; ENDD FI ENDD ELSE;..OPERANDS ARE LONG REAL; BEGIN ;..SAVE A0 (GBREG); MOVEM A0,TA0;$ ;..ASSUME SINGLE PRECISION FOR NOW ; [E044] SETOM DPFLAG ; [E044] ;..PUT LEFT VALUE INTO (A0,A1); ;.. * * * NOTE THAT A1 IS THE SAME REGISTER AS T; F.LOCN (T4,LOP); ADD T4,CONTAB;$ MOVE A0,2(T4);$ MOVE A1,3(T4);$ TLZN A1,(1B0) ; [E044] SETZM DPFLAG ; [E044] ;..PUT RIGHT VALUE INTO (A3,A4); F.LOCN (T4,SYM); ADD T4,CONTAB;$ MOVE A3,2(T4);$ MOVE A4,3(T4);$ TLZN A4,(1B0) ; [E044] SETZM DPFLAG ; [E044] IF OP = RELATIONAL T.RELATION(T4); THEN;..WE HAVE A RELATION. RESULT WILL BE A BOOLEAN CONSTANT; BEGIN ;..SUBTRACT (LONG REAL) SYM FROM LOP; ;..NOTE THAT A2 (T1) WILL BE CLOBBERED; ;EXECUTE ; DFSB A0,A3;$ ;..COMPARE RESULT WITH ZERO; ;EXECUTE +1] A0,0>; F.DISC (T4); HLLZ T4,OPCODE+1(T4);$ XCT T4;$ ;GENERATE "FALSE" OR "TRUE" CONSTANT IN T3; TDZA T3,T3;$ SETO T3,0;$ ;SYM _ BOOLEAN; TLZ SYM,$TYPE;$ TLO SYM,$B;$ ;..RESTORE A0; MOVE A0,TA0;$ ;..PUT BOOLEAN CONSTANT AWAY; STOCON; ENDD ELSE;..NOT A RELATION. RESULT IS A LONG REAL CONSTANT; BEGIN ;..PERFORM THE OPERATION; ;.. * * * NOTE THAT A2 (T1) WILL BE CLOBBERED; ;EXECUTE +3]>; F.DISC (T4); XCT OPCODE+3(T4);$ ;..MOVE RESULT TO (T3,T4); MOVE T3,A0;$ MOVE T4,A1;$ ;..RESTORE A0; MOVE A0,TA0;$ IF NO OVERFLOW IN LONG REAL MULTIPLY OR DIVIDE JUMPL SYM,FALSE;$ EDIT (221); INSERT IN CONSTANT FOLDING ROUTINE IN .CGBIN JFOV FALSE; ;[221] THEN;..STORE LONG REAL CONSTANT RESULT; ;..IF NEITHER OPERAND WAS EXPLICIT DOUBLE PRECISION, ;..THEN NEITHER IS THE RESULTING CONSTANT. SKIPE DPFLAG ; [E044] TLOA T4,(1B0) ; [E044] TLZ T4,(1B0) ; [E044] TOCT(2,SYM); ELSE;..WE HAD AN OVERFLOW IN LONG REAL "*" OR "/"; ;..SET UP ERROR LEXEME; FAIL(74,FRIED,SYM,OVERFLOW WHILE COMBINGING CONSTANTS); ;[221] ERRLEX; FI ENDD FI ENDD FI ENDD ELSE;..OP IS "^"; BEGIN IF SYM NEQ INTEGER TN.I (SYM); THEN;..COMPUTE POWER AT RUN-TIME; ;SET T TO "FALSE" AND EXIT; GOTO LTC1;$ FI ;..LOAD BASE (LOP) INTO A0 (AND A1); ;T2 _ LOP; F.LOCN (T2,LOP); ;..SAVE GBREG (A0); MOVEM A0,TA0;$ IF LOP = LONG REAL T.LR (LOP); THEN;..BASE IS LONG REAL; BEGIN; ; [E044] ;..PUT LONG CONSTANT INTO REGISTERS A0 AND A1; ADD T2,CONTAB;$ MOVE A0,2(T2);$ IF PSEUDO-LONG REAL CONVERT IT TO A REAL ; [E044] SKIPL A1,3(T2) ; [E044] GOTO FALSE ; [E044] THEN; ; [E044] TLZ A1,(1B0) ; [E044] PUSHJ SP,CTLRR ; [E044] TLZ LOP,$TYPE ; [E044] TLO LOP,$R ; [E044] FI; ; [E044] ENDD; ; [E044] ELSE;..BASE IS INTEGER OR REAL; BEGIN IF LOP = IMMEDIATE T.IMM (LOP); THEN;..IMMEDIATE VALUE MUST BE LOADED INTO A0; BEGIN IF LOP = INTEGER T.I (LOP); THEN ;LOAD IMMEDIATE INTEGER CONSTANT; HRRZ A0,T2;$ ELSE ;LOAD IMMEDIATE REAL CONSTANT; HRLZ A0,T2;$ FI ENDD ELSE;..LOP HAS A FULLWORD VALUE; ;;..LOAD CONSTANT FROM TABLE; ADD T2,CONTAB;$ MOVE A0,1(T2);$ FI ENDD FI ;..PUT EXPONENT (SYM) INTO A2; ;T2 _ SYM; F.LOCN (T2,SYM); IF SYM = IMMEDIATE T.IMM (SYM); THEN;..IMMEDIATE VALUE MUST BE LOADED INTO A2; ;..LOAD IMMEDIATE INTEGER CONSTANT; HRRZ A2,T2;$ ELSE;..SYM HAS A FULLWORD VALUE; ;..LOAD CONSTANT FROM TABLE; ADD T2,CONTAB;$ MOVE A2,1(T2);$ FI ;..COPY EXPONENT FOR SIGN CHECK; MOVE T4,A2;$ ;..EXECUTE THE CALL. RESULT IN A0 (AND A1); F.TRANK (T2,LOP); XCT OPPOWC(T2);$ ;..MOVE FIRST WORD OF RESULT TO T3; MOVE T3,A0;$ ;..RESTORE GBREG (A0); MOVE A0,TA0;$ IF SYM IS AN ERROR LEXEME JUMPGE SYM,FALSE;$ THEN;..SET RESULT LEXEME; ERRLEX; ELSE;..RESULT IS VALID. PUT IT AWAY; BEGIN IF LOP = LONG REAL T.LR (LOP); THEN;..RESULT IS LONG REAL; BEGIN ;..MOVE SECOND WORD OF RESULT TO T4; MOVE T4,A1;$ ;..PUT LONG CONSTANT IN TABLE; TOCT(2,SYM); ;LEX(SYM) _ (SAME,LONG REAL,SAME,SAME); TLZ SYM,$TYPE;$ TLO SYM,$LR;$ ENDD ELSE;..PUT SHORT CONSTANT AWAY; BEGIN IF LOP = INTEGER AND EXPONENT GTE 0 JUMPL T4,FALSE;$ T.I (LOP); THEN;..TYPE OF SYM SHOULD BE INTEGER (IT ALREADY IS); ELSE;..TYPE OF RESULT SHOULD BE REAL; ;LEX(SYM) _ (SAME,REAL,SAME,SAME); TLZ SYM,$TYPE;$ TLO SYM,$R;$ FI STOCON; ENDD FI ENDD FI ENDD FI ;..RESULT HAS BEEN COMPUTED. SET FLAG TO TRUE; ;T _ "TRUE"; SETO T,0;$ ENDD ELSE;..OPERANDS ARE NOT BOTH CONSTANTS AND RESULT CANNOT BE COMPUTED NOW; LTC1: ;..SET FLAG TO FALSE; ;T _ "FALSE"; SETZ T,0;$ FI ENDD ; TREATCONST SUBTTL CODE GENERATION ROUTINES * TRUNACONST * PROCEDURE TRUNACONST; ;..PERFORM UNARY OP AT COMPILE-TIME IF OPERAND IS A CONSTANT. ; IF OPERAND IS NOT A CONSTANT, FLAG (T) IS SET TO ; "FALSE" (ALL ZEROS); ; IF IT IS A CONSTANT, NEW CONSTANT IS PRODUCED ; AND FLAG IS SET TO "TRUE" (ALL ONES); ; ON ENTRY, OPD LEXEME IS IN SYM AND OPN LEXEME IS IN OP; ; RESULT LEXEME GOES TO SYM. ; NEW CONSTANT IS PUT INTO LEXEME IF IT IS IMMEDIATE, ; OTHERWISE IT IS PUT INTO THE CONSTANT TABLE; BEGIN IF SYM = CONSTANT T.CONST (SYM); THEN;..WE MUST DO SOMETHING; BEGIN ;T2 _ SYM; F.LOCN (T2,SYM); IF SYM = LONG REAL T.LR (SYM); THEN;..LONG REAL OPERAND POSSIBLE ONLY FOR UNARY "-"; BEGIN ;NEGATE LONG CONSTANT INTO T3 AND T4; ADD T2,CONTAB;$ DMOVN T3,2(T2) TLZ T4,(1B0) ; [E044] SKIPL 3(T2) ; [E044] TLZA T4,(1B0) ; [E044] TLO T4,(1B0) ; [E044] ;..PUT NEW CONSTANT IN TABLE; TOCT(2,SYM); ENDD ELSE;..SHORT CONSTANT; BEGIN IF OP = "NOT" T.OPER (ZNOT); THEN;..COMPLEMENT THE CONSTANT; BEGIN IF SYM = IMMEDIATE T.IMM (SYM); THEN;..PUT COMPLEMENT OF IMMED. CONSTANT INTO T3; SETCM T3,T2;$ ELSE;..GET COMPLEMENT OF TABLED CONST. INTO T3; ADD T2,CONTAB;$ SETCM T3,1(T2);$ FI ENDD ELSE;..OP MUST BE UNARY "-"; BEGIN IF SYM = IMMEDIATE T.IMM (SYM); THEN;..CONSTANT IS IN A HALFWORD; BEGIN IF SYM = INTEGER T.I (SYM); THEN;..NEGATE IMMED. INTEGER CONST. INTO T3; MOVN T3,T2;$ ELSE;..NEGATE IMMED. REAL CONSTANT INTO T3; HRLZ T3,T2;$ MOVN T3,T3;$ FI ENDD ELSE;..CONSTANT TAKES A FULL WORD; ;NEGATE CONSTANT FROM TABLE INTO T3; ADD T2,CONTAB;$ MOVN T3,1(T2);$ FI ENDD FI ;..SET UP LEXEME AND STORE IN CONSTANT TABLE; STOCON; ENDD FI ;..UNARY OPERATION IS COMPLETE; ;T _ TRUE; SETO T,0;$ ENDD ELSE;..OPERAND IS NOT A CONSTANT. UNARY OP MUST BE GENERATED; ;T _ FALSE; SETZ T,0;$ FI ENDD ; TRUNACONST ENDD; OF MODULE MCOD LIT END