! File: CODE.BLI
!
! This work was supported by the Advanced Research
! Projects Agency of the Office of the Secretary of
! Defense (F44620-73-C-0074) and is monitored by the
! Air Force Office of Scientific Research.
!
Module CODE=
Begin
!
! CODE MODULE
! ------------
!
! SEPT. 1972
! WULF,JOHNSSON,WEINSTOCK
! LATER ADDITIONS:
! LEVERETT,KNUEVEN
!
! THIS MODULE PRODUCES THE ACTUAL PDP-11 MACHINE CODE. IT IS
! EXECUTED AFTER DELAYING AND TEMP-NAME BINDING. THEREFORE ESSENTIALLY
! ALL RELEVANT INFORMATION IS KNOWN. THE PRIMARY FUNCTION OF 'CODE',
! IN ADDITION TO GENERATING THE CODE, IS TO DO THE (RATHER EXTENSIVE)
! SPECIAL CASE ANALYSIS TO PRODUCE LOCALLY OPTIMAL CODE. THUS, FOR
! EXAMPLE, IT IS CODE THAT DETERMINES THE OPTIMAL SEQUENCE OF MASKING,
! ROTATE AND/OR SHIFT, AND 'SWAB' INSTRUCTIONS TO ISOLATE A SUBFIELD
! AND TO ALIGN IT AT A SPECIFIED LOCATION IN A WORD.
!
! THE MAJOR PORTIONS OF CODE ARE:
!
! 1. CODE/LABEL PLACEMENT
! THESE ROUTINES ACTUALLY EMIT THE CODE AND/OR
! LABELS IN A FORM SUITABLE FOR PROCESSING
! BY THE 'FINAL' MODULE. THE CODE REPRESENTATION
! CREATED BY THE ROUTINES IS A DOUBLY LINKED
! LIST -- ITS PRECISE FORM IS IRRELEVANT TO
! THIS MODULE, HOWEVER.
!
! 2. 'VERY-TEMP' ALLOCATION
! IN A FEW CASES THE FACT THAT AN ADDITIONAL
! TEMPORARY IS NEEDED IS NOT KNOWN UNTIL CODE-GENERATION
! TIME, THUS THE TEMPORARIES WILL NOT HAVE
! BEEN ALLOCATED BY 'TNBIND'. THE NECESSARY
! ROUTINES ARE DUPLICATED FROM TNBIND IN ORDER
! ALLOCATE THESE TEMPS 'ON THE FLY' DURING
! CODE-GENERATION. THE SAME PHILOSOPHY FOR
! ALLOCATION IS USED IN CODE AS IN TNBIND,
! ESPECIALLY WRT. LON'S AND FON'S,AS IN
! TNBIND. THEREFORE THEY WILL NOT BE DISCUSSED
! HERE.
!
! 3. ADDRESS GENERATION
! THIS SET OF ROUTINES, OF WHICH 'GMA' AND
! 'GMA8' ARE THE PRINCIPAL ONES, ARE SERVICE
! ROUTINES WHICH GENERATE THE ADDRESS FORMAT
! NEEDED BY 'FINAL'. THE PARAMETER
! TO EACH OF THESE ROUTINES IS A LEXEME --
! IT MAY BE A LITERAL LEXEME, ST-LEXEME, OR
! GT-LEXEME. IN EACH CASE THE APPROPRIATE ADDRESS
! IS GENERATED.
! THE DIFFERENCE BETWEEN GMA AND GMA8 IS ONLY
! THAT GMA8 GENERATES THE ADDRESS OF THE HIGH
! BYTE OF THE WORD.
!
! 4. MOVE GENERATION
! THESE ROUTINES, PRIMARILY 'SIMPLEMOVE' AND
! 'GENMOVE', ARE SERVICE ROUTINE WHICH WILL
! GENERATE A DATA MOVE -- IF (AND ONLY IF)
! ONE IS ACTUALLY REQUIRED. SIMPLEMOVE ALWAYS
! MOVES AN ENTIRE WORD. GENMOVE WILL MOVE AN
! ARBITRARY FIELD OF ONE WORD TO AN ARBITRARY
! FIELD OF ANOTHER WORD. GENMOVE MAKES EXTENSIVE
! USE OF THE FIELD-ISOLATION AND ALIGNMENT
! ROUTINES -- SEE BELOW.
!
! 5. FIELD ISOLATION AND ALIGNMENT
! THIS SET OF ROUTINES PROVIDES THE PRIMITIVES
! FOR ISOLATING AN ARBITRARY SUBFIELD OF A
! WORD AND ALIGNING THE FIELD TO AN ARBITRARY
! POSITION IN THE WORD.
!
! 6. COMPARISON GENERATION
! THIS SET OF SERVICE ROUTINES GENERATES
! COMPARISONS BETWEEN ARBITRARY OPERANDS, WHICH
! IN PARTICULAR MAY BE SUBFIELDS OF A WORD, AND
! GENERATES BRANCHES TO SPECIFIED LABELS. THIS
! IS IN GENERAL A SIMPLE TASK, BUT THE SPECIAL
! CASE ANALYSIS IS ESPECIALLY EXTENSIVE HERE.
!
! 7. NODE-SPECIFIC ROUTINES
! CODE GENERATION IS EFFECTED BY AN EXECUTION-ORDER
! TREE WALK AND CALLING NODE-SPECIFIC ROUTINES
! AT EACH NODE. THESE ROUTINES ACTUALLY CONTROL
! THE CODE TO BE GENERATED FOR EACH NODE. THIS
! SECTION CONTAINS THESE ROUTINES. A GOOD EXAMPLE
! OF THE SPECIAL CASE ANALYSIS DONE BY THESE
! ROUTINES MAY BE FOUND BY LOOKING AT 'GID' WHICH
! GENERATES THE CODE FOR INCR/DECR STATEMENTS.
!
! 8. CODE & FREEUNDER
! THE SWITCHING TO THE NODE-SPECIFIC ROUTINES
! IS DONE HERE, AS ELSEWHERE IN THE COMPILER,
! BY SWITCHING THROUGH A 'PLIT'. THE ROUTINE
! 'CODE' ACTS AS THE CENTRAL SWITCHING AGENT.
! AS EACH NODE IS COMPLETED BY CODE THE ROUTINE
! 'FREEUNDER' IS CALLED BY IT TO RELEASE THE
! SPACE FOR THAT PORTION OF THE TREE WHICH IS
! NO LONGER NEEDED. THUS THE SPACE CONSUMED BY
! THE EMITTED CODE IS LARGELY THAT
! RELEASED FROM THE TREE.
!
! 9. CODEDRIVER
! THIS ROUTINE IS CALLED FROM 'GENIT' IN
! DRIVER TO INITIATE THE CODE GENERATION PROCESS.
! IT DOES THE NECESSARY INITIALIZATION AND
! CLEAN-UP.
!
Require 'Bliss';
External Routine
OUTINST : Novalue;
External
DYTEMPS;
Own
REGSCHNGD : Integer,
NODVT : Integer,
NOVTCNT : Integer,
PLSTCNT : Integer,
SIGLAB : Ref CELL,
SAMETOG : Integer;
! MISC. EXTERNALS FOR CODE ONLY
Structure ADRWD[P,S,E] = [8]ADRWD
;
External
ALTERSRCDST : Vector[,Byte],
OPBYTES : Vector[,Byte],
OPERTYPE : Vector[,Byte];
! LABEL HANDLING
! --------------
! allocate a new label cell
Routine GENLABEL =
Begin
Return NEWLABCELL(LAB_COMP,GETLABEL())
End;
! place a place at the current location
Routine PLACELABEL(LAB : Ref CELL) : Novalue =
Begin
NCELL = AFTER(.NCELL,.LAB);
NCELL[cel_min_loc] = .LOC
End;
! generate a label reference operand
Routine REFLABEL(LAB : Ref CELL,FRM : Ref CELL,OTYPE) =
Begin
Local
C : Ref CELL;
C = GETCELL(CELL_REF,SZ_CELL_REF);
C[cel_ref_ef] = .LAB;
C[cel_ref_rf] = .FRM;
C[cel_class] = .OTYPE;
PUSHBOT(.C[cel_ref_ef],.C);
Return BUILDOPD(OPND_LABEL,RELATIVE,PC,.C)
End;
! generate a label address reference operand (used only by GCASE)
Routine IMMLAB(LAB : Ref CELL,FRM : Ref CELL,OTYPE) =
Begin
Local
C : Ref CELL;
C = GETCELL(CELL_REF,SZ_CELL_REF);
C[cel_ref_ef] = .LAB;
C[cel_ref_rf] = .FRM;
C[cel_class] = .OTYPE;
PUSHBOT(.C[cel_ref_ef],.C);
Return BUILDOPD(OPND_LABEL,IMMEDIATE,PC,.C)
End;
Routine NODELABEL(NODE : Ref GT) =
Begin
If .NODE[gt_label] Eql 0 Then
NODE[gt_label] = NEWLABCELL(LAB_COMP,GETLABEL());
Return .NODE[gt_label]
End;
Routine USERLABEL(LABST : Ref ST) =
Begin
If .LABST[st_lab_cell] Eql 0 Then
LABST[st_lab_cell] = NEWLABCELL(LAB_USER,.LABST);
Return .LABST[st_lab_cell]
End;
! LIST-OF-NAME-DESCRIPTORS HANDLING
! -----------------------------------
Routine SEARCHLL(HEAD : Ref CELL,LABS,LABN) =
Begin
Local
PTR : Ref CELL;
PTR = .HEAD[cel_prev];
While TRUE Do
Begin
If .LABS Gtr .PTR[cel_sym_name] Then
Exitloop;
If .LABS Eql .PTR[cel_sym_name] And .LABN Geq .PTR[cel_sym_disp] Then
Exitloop;
PTR = .PTR[cel_prev]
End;
If .LABS Eql .PTR[cel_sym_name] And .LABN Eql .PTR[cel_sym_disp] Then
Return .PTR
Else
Return AFTER(.PTR,NEWLABCELL(.LABS,.LABN))
End;
! EMIT CODE INTO INSTRUCTION STREAM
! ---------------------------------
Routine PUTADR(ADR : Ref ADRVARSTR,A : ADRWD,BYTES) : Novalue =
Begin
Bind
IMMEDZERO = ADRPLIT(2,PC,ADDR_IMMED,NAME_NORMAL,0) : ADRVARSTR;
Bind
ADRTYPE = Uplit Byte(
ADDR_REG, ! R
ADDR_MEMORY, ! @R
ADDR_MEMORY, ! (R)+
ADDR_INDIRECT, ! @(R)+
ADDR_MEMORY, ! -(R)
ADDR_INDIRECT, ! @-(R)
ADDR_MEMORY, ! n(R)
ADDR_INDIRECT, ! @n(R)
UNUSED, ! PC
UNUSED, ! @PC
ADDR_IMMED, ! #
ADDR_MEMORY, ! @#
UNUSED, !
UNUSED, !
ADDR_MEMORY, ! n(PC)
ADDR_INDIRECT) ! @n(PC)
: Vector[,Byte];
COPYADR(.ADR,IMMEDZERO);
If (.A Eql SP) Or .A Then
BYTES = 2;
ADR[adr_mode] = .A;
ADR[adr_reg] = .A;
If (.ADR[adr_mode] And 6) Eql INDEXED Or .ADR[adr_reg] Eql PC Then
Case .A From LO_OPND_TYPE To HI_OPND_TYPE Of Set
[Inrange]:
0;
[OPND_NORMAL]:
Begin
ADR[adr_disp] = .A;
If .A<31,1> Then
ADR[adr_name_type] = NAME_FORMAL
End;
[OPND_NAME]:
Begin
ADR[adr_disp] = .ST[.A,cel_sym_disp];
ADR[adr_name] = .ST[.A,cel_sym_name]
End;
[OPND_LABEL]:
Begin
ADR[adr_name_type] = NAME_LABEL;
ADR[adr_name] = .A
End;
[OPND_ERROR]:
Begin
ADR[adr_name_type] = NAME_ERROR;
ADR[adr_disp] = .A
End
Tes;
If .ADR[adr_reg] Eql SP And .ADR[adr_name] Eql 0 And .ADR[adr_mode] Neq GENREG Then
ADR[adr_name] = 1;
If (.ADR[adr_mode] And 6) Eql AUTOINCR And .ADR[adr_reg] Neq PC Then
Begin
ADR[adr_disp] = -.BYTES;
ADR[adr_delta] = .BYTES;
End
Else If (.ADR[adr_mode] And 6) Eql AUTODECR Then
ADR[adr_delta] = -.BYTES;
ADR[adr_type] = .ADRTYPE[.ADR[adr_mode]+ (If .ADR[adr_reg] Eql PC Then 8 Else 0)]
End;
Routine CKREGSCHNGD(OP : Integer,S : ADRWD,D : ADRWD) : Novalue =
Begin
Macro
NOTER(X)=REGSCHNGD<.X,1> = TRUE %,
NOTEZ=REGSCHNGD<0,1> = TRUE %,
RS(X)= If .X Eql GENREG Then NOTER(X) %,
CR(X)= If ONEOF(.X,AUTOINCR,AUTOINCR+DEFERRED,
AUTODECR,AUTODECR+DEFERRED)
Then NOTER(X) %;
Case .OPERTYPE[.OP] From LO_OPTYPE To HI_OPTYPE Of Set
[OPTYPE_NOP]:
If .OP Eql PIOT Then
NOTEZ;
[OPTYPE_ONE]:
Begin
If .ALTERSRCDST[.OP] Then
RS(S);
CR(S)
End;
[OPTYPE_TWO]:
Begin
CR(D);
If .ALTERSRCDST[.OP] Then
RS(D);
CR(S)
End;
[OPTYPE_BR]:
CR(S);
[OPTYPE_JSR]:
Begin
CR(D);
NOTEZ;
RS(S)
End;
[OPTYPE_RTS]:
RS(S);
[OPTYPE_TRAP]:
NOTEZ;
[OPTYPE_WORD,OPTYPE_CASE]:
0
Tes
End;
Routine PUTCODE(WHERE : Ref CELL,OPT : Integer,OP : Integer,S : ADRWD,D : ADRWD) =
Begin
Local
BYTES : Integer;
CKREGSCHNGD(.OP,.S,.D);
NCELL = AFTER(.NCELL,.WHERE);
NCELL[cel_min_loc] = LOC = .LOC+1;
NCELL[cel_class] = .OPT;
NCELL[cel_code] = .OP;
BYTES = .OPBYTES[.OP];
If HASSOURCE(.OP) Then
PUTADR(NCELL[cel_src],.S,.BYTES);
If HASDEST(.OP) Then
PUTADR(NCELL[cel_dst],.D,.BYTES);
Case .OPERTYPE[.OP] From LO_OPTYPE To HI_OPTYPE Of Set
[Inrange]:
0;
[OPTYPE_NOP]:
If .OP Eql PINLINE Then
NCELL[cel_inl_arg] = .S;
[OPTYPE_JSR,OPTYPE_RTS]:
NCELL[cel_src_reg] = .S;
[OPTYPE_TRAP]:
NCELL[cel_src_disp] = .S;
[OPTYPE_WORD]:
If .D Then NCELL[cel_hydra_word] = TRUE
Tes;
Return .NCELL
End;
Bind
OPTYPLIT = UPlit Byte (
INST_INLINE, ! INLINE
UNUSED, ! PMOV=1,
UNUSED, ! PMOVB=2,
UNUSED, ! PCMP=3,
UNUSED, ! PCMPB=4,
UNUSED, ! PBIT=5,
UNUSED, ! PBITB=6,
UNUSED, ! PBIC=7,
UNUSED, ! PBICB=8,
UNUSED, ! PBIS=9,
UNUSED, ! PBISB=10,
INST_ADD_IMMED, ! PADD=11,
INST_ADD_IMMED, ! PSUB=12,
UNUSED, ! PCLR=13,
UNUSED, ! PCLRB=14,
UNUSED, ! PCOM=15,
UNUSED, ! PCOMB=16,
UNUSED, ! PINC=17,
UNUSED, ! PINCB=18,
UNUSED, ! PDEC=19,
UNUSED, ! PDECB=20,
UNUSED, ! PNEG=21,
UNUSED, ! PNEGB=22,
UNUSED, ! PADC=23,
UNUSED, ! PADCB=24,
UNUSED, ! PSBC=25,
UNUSED, ! PSBCB=26,
UNUSED, ! PTST=27,
UNUSED, ! PTSTB=28,
UNUSED, ! PROR=29,
UNUSED, ! PRORB=30,
UNUSED, ! PROL=31,
UNUSED, ! PROLB=32,
UNUSED, ! PASR=33,
UNUSED, ! PASRB=34,
UNUSED, ! PASL=35,
UNUSED, ! PASLB=36,
UNUSED, ! PJMP=37,
UNUSED, ! PSWAB=38,
UNUSED, ! PJSR=39,
UNUSED, ! PRTS=40,
UNUSED, ! PHALT=41,
UNUSED, ! PWAIT=42,
UNUSED, ! PRTI=43,
UNUSED, ! PIOT=44,
UNUSED, ! PRESET=45,
UNUSED, ! PEMT=46,
UNUSED, ! PTRAP=47,
INST_UNCOND_JUMP,! PBR=48,
INST_UNCOND_JUMP,! PNBR=49,
INST_COND_JUMP, ! PBNE=50,
INST_COND_JUMP, ! PBEQ=51,
INST_COND_JUMP, ! PBGE=52,
INST_COND_JUMP, ! PBLT=53,
INST_COND_JUMP, ! PBLE=54,
INST_COND_JUMP, ! PBGT=55,
INST_COND_JUMP, ! PBPL=56,
INST_COND_JUMP, ! PBMI=57,
INST_COND_JUMP, ! PBHI=58,
INST_COND_JUMP, ! PBLOS=59,
INST_COND_JUMP, ! PBVC=60,
INST_COND_JUMP, ! PBVS=61,
INST_COND_JUMP, ! PBHIS=62,
INST_COND_JUMP, ! PBLO=63,
UNUSED, ! PNOP=64,
UNUSED, ! PCLC=65,
UNUSED, ! PCLVC=66,
UNUSED, ! PWORD=67,
INST_CASE_PARAM,! PCASE=68,
UNUSED, ! PMFPI=69,
UNUSED, ! PMFPD=70,
UNUSED, ! PMTPI=71,
UNUSED, ! PMTPD=72,
0,0
) : Vector[,Byte];
Routine ISLIT(L : Ref GT) =
Begin
If .L Eql T_LITERAL Then
Return .L
Else If .L[gt_type] Neq S_NODE Then
Return 0
Else If .L Then
Return .L
Else
Return 0
End;
Routine CLITVALUE(L : Ref GT) =
Begin
If .L Eql T_LITERAL Then
Return .L
Else
Return .L[gt_disp_16]
End;
Macro
ISZERO(L)= (ISLIT(L) And CLITVALUE(L) Eql 0) %;
Routine ISIMMEDIATE(ADR)=
Begin
Bind
X=(BUILDOPD(OPND_NORMAL,IMMEDIATE,PC,0)^(-32));
Return .ADR<32,32> Eql X
End;
Routine EMIT(OP : Integer,S : ADRWD,D : ADRWD) : Novalue =
Begin
Local
PCELL : Ref CELL,
TYPE : Integer;
PCELL = NEWCODECELL();
TYPE = .OPTYPLIT[.OP];
Case .TYPE From LO_INST_TYPE To HI_INST_TYPE Of Set
[INST_NORMAL]:
If .OP Eql PJMP Then
TYPE = INST_UNCOND_JUMP;
[INST_CASE_PARAM]:
Begin
D = REFLABEL(.D,.PCELL,.TYPE);
S = REFLABEL(.S,.PCELL,.TYPE)
End;
[INST_INLINE]:
0;
[INST_UNCOND_JUMP]:
S = REFLABEL(.S,.PCELL,.TYPE);
[INST_ADD_IMMED]:
If Not ISIMMEDIATE(.S) Then
TYPE = UNUSED;
[INST_COND_JUMP]:
S = REFLABEL(.S,.PCELL,.TYPE)
Tes;
PUTCODE(.PCELL,.TYPE,.OP,.S,.D)
End;
! GET HIGHLY TEMPORARY CELLS WITHIN A NODE LIFE
! ---------------------------------------------
Macro
ISOKPUSHVT=(.NOVTCNT Eql 0) %,
OKTOPDYTEMP=(.NODVT Eql 0 And .DYTEMPS Geq 2) %,
OKALLDYTMPS=(.NODVT Eql 0 And .DYTEMPS Geq 4) %;
Macro
SETNOPUSHVT=NOVTCNT = .NOVTCNT+1 %,
RESETPUSHVT=NOVTCNT = .NOVTCNT-1 %,
SETNODYNVT=NODVT = .NODVT+1 %,
RESETDYNVT=NODVT = .NODVT-1 %;
! TRY THE OPEN VERY TEMPS
Routine TRYOPVTEMPS(T : Ref GT) =
Begin
Incr I From 0 To .VTEMPS[stk_idx] Do
If TRYFIT(.T,VTEMPS[stk_item(.I)]) Then
SUCCESS;
FAIL
End;
! OPEN A NEW VERY TEMP
Routine TRYCLVTEMPS(T : Ref GT) =
Begin
Local
TX : Ref GT,
TR : Ref TNREPR,
R : Ref ITEM;
PUSHSTK(VTEMPS);
R = VTEMPS[stk_item(.VTEMPS[stk_idx])];
OPENLIST(.R);
TRYFIT(.T,.R); ! NOTE THIS WILL (SHOULD) ALWAYS WORK
TR = .R;
Until (TR = .TR[itm_rlink]) Eqla .R Do
Begin
TX = .TR[tnr_ptr];
TX[tn_type] = BNDLOCAL;
TX[gt_reg] = SP;
TX[gt_mode] = INDEXED;
TX[gt_disp] = .VTEMPS[stk_idx] * 2
End
End;
Routine COPYTNDATA(TN : Ref GT) : Novalue =
Begin
Local
L : Ref TNREPR,
P : Ref GT;
L = .TN[tn_bind_list];
! 'L' points to a list header. move to the first element of the list
L = .L[itm_rlink];
P = .L[tnr_ptr];
TN[tn_type] = .P[tn_type];
TN[gt_reg] = .P[gt_reg];
TN[gt_mode] = .P[gt_mode];
TN[gt_disp] = .P[gt_disp]
End;
Routine MARKANDCOPY(TN : Ref GT) : Novalue =
Begin
Local
LST : Ref TNREPR,
L : Ref TNREPR,
N : Integer,
P : Ref GT;
LST = .TN[tn_bind_list];
N = (.LST-REGS[0]) / 8;
L = .LST[itm_rlink];
P = .L[tnr_ptr];
P[tn_type] = BNDREG;
P[gt_reg] = .N;
COPYTNDATA(.TN)
End;
Routine MAKEPUSHVT(T : Ref GT) : Novalue =
Begin
If .VTN[gt_dtdelete] Eql DTDONTCARE Then
VTN[gt_dtdelete] = .DYTEMPS;
T[tn_type] = BNDPUSH;
T[gt_reg] = SP;
T[gt_mode] = INDEXED;
T[gt_disp] = -(.MAXLOCALS+.STATICSIZE+.DYTEMPS+2)
End;
Routine VERYTEMP(X : Ref GT) =
Begin
Local
T : Ref GT;
T = GETTN();
T[tn_lon_fu] = .LON;
T[tn_lon_lu] = .LON;
T[tn_fon_fu] = .FON;
T[tn_fon_lu] = .FON;
If .X Gequ 8 And .X[tn_bind_list] Neqa 0 And TRYFIT(.T,.X[tn_bind_list]) Then
COPYTNDATA(.T)
Else If TRYOPREG(.T) Then
COPYTNDATA(.T)
Else If OKTOPDYTEMP And TRYSPDYTEMP(.T,(.DYTEMPS-2)/2) Then
COPYTNDATA(.T)
Else If ISOKPUSHVT Then
MAKEPUSHVT(.T)
Else If OKALLDYTMPS And TRYDYTEMPS(.T) Then
COPYTNDATA(.T)
Else If TRYOPSTEMPS(.T) Then
COPYTNDATA(.T)
Else If TRYCLREG(.T) Then
MARKANDCOPY(.T)
Else If TRYOPVTEMPS(.T) Then
COPYTNDATA(.T)
Else
TRYCLVTEMPS(.T);
Return .T
End;
Routine VERYTMPREG=
Begin
Local
T : Ref GT;
T = GETTN();
T[tn_lon_fu] = .LON;
T[tn_lon_lu] = .LON;
T[tn_fon_fu] = .FON;
T[tn_fon_lu] = .FON;
If TRYOPREG(.T) Then
COPYTNDATA(.T)
Else If OKTOPDYTEMP And TRYSPDYTEMP(.T,(.DYTEMPS-2)/2) Then
COPYTNDATA(.T)
Else If ISOKPUSHVT Then
MAKEPUSHVT(.T)
Else
T = 0;
Return .T
End;
! ROUTINES TO HANDLE GENERATION OF MACHINE ADDRESSING FORMATS
! ------------------------------------------------------------
Macro
ALOCAL(X) = BUILDOPD(OPND_NORMAL,INDEXED,SP,XLO(X)) %,
DEFER(Z) = ((Z) Or ((DEFERRED)^_POS(gma_mode))) %,
INDEXEDBY(R,X,T)= BUILDOPD(T,INDEXED,REGNUM(R),X) %,
LOCALOFFSET(ZZZ)= (((.MAXLOCALS+.STATICSIZE+.DYTEMPS)
+.ZZZ[gt_disp_16])And %x'ffff') %,
MAKLIT(L) = (LITLEXEME((L) And %x'ffff')+FLD_K_LIT+FLD_K_IMM) %,
MAKNAM(N) = (LEXOUT(0,N)+FLD_K_LIT+FLD_K_IMM) %,
NODEFER(Z) = ((Z) And (Not((DEFERRED)^_POS(gma_mode)))) %,
NXTBYTEADR(A) = BUMPBYTEADR(A,1) %,
PROGCTR = BUILDOPD(OPND_NORMAL,GENREG,PC,UNUSED) %,
PUSHED = BUILDOPD(OPND_NORMAL,AUTODECR,SP,UNUSED) %,
POPPED = BUILDOPD(OPND_NORMAL,AUTOINCR,SP,UNUSED) %,
STACKPTR = BUILDOPD(OPND_NORMAL,GENREG,SP,UNUSED) %,
XLO(X) = (((.MAXLOCALS+.STATICSIZE+.DYTEMPS)+X) And %x'ffff') %,
XREG(X) = BUILDOPD(OPND_NORMAL,GENREG,X,UNUSED) %,
XTOS = BUILDOPD(OPND_NORMAL,DEFERRED,SP,UNUSED) %,
ZPOPPED = BUILDOPD(OPND_NORMAL,AUTOINCR,0,UNUSED) %;
Forward Routine
GMA,
ISREG,
NOMOVREQD,
REGNUM;
Macro
FLD_K_FORMAL = 1^31 %;
Routine NAMEDESC(N : Ref ST) =
Begin
Local
L : Integer,
B : Ref ST;
B = BASESYM(.N);
L = .N[gt_disp]-.B[gt_disp];
Return SEARCHLL(.NLHEAD,.B,.L)
End;
Routine BUMPNAMEDESC(D : Ref CELL,N)=
Begin
Return SEARCHLL(.NLHEAD,.D[cel_sym_name],.D[cel_sym_disp]+.N)
End;
Routine BUMPBYTEADR(ADR : ADRWD,N : Integer) =
Begin
Case .ADR From 0 To 7 Of Set
[GENREG,AUTODECR,AUTODECR+DEFERRED]:
PUNT(581);
[GENREG+DEFERRED]:
Begin
ADR = INDEXED;
ADR = .N
End;
! auto-increment in this situation may only be PC mode
[AUTOINCR,AUTOINCR+DEFERRED,INDEXED]:
If .ADR Eql OPND_NORMAL Then
ADR = .ADR+.N
Else
ADR = BUMPNAMEDESC(.ADR,.N);
[INDEXED+DEFERRED]:
! this can't be right?
If .ADR Neq OPND_NORMAL Then
ADR = BUMPNAMEDESC(.ADR,.N)
Else
Begin
Local T : Ref GT;
T = VERYTEMP(0);
EMIT(PMOV,NODEFER(.ADR),GMA(.T));
If ISREG(.T) Then
Return BUILDOPD(OPND_NORMAL,INDEXED,REGNUM(.T),.N);
EMIT(PADD,GMA(MAKLIT(.N)),GMA(.T));
Return DEFER(GMA(.T))
End
Tes;
Return .ADR
End;
Routine ISIDT(N : Ref GT) =
Begin
If .N Eql S_NODE Then
Return .N[rw_destroyable]
Else
Return 0
End;
Routine FORGOTTEN(NODE : Ref GT,OP1 : Ref GT) =
Begin
Local
TN : Ref GT;
TN = .NODE[gt_reg];
If .TN Lss 8 Then
Return FALSE;
If .TN[tn_type] Eql BNDNCSE Then
Return TRUE;
If .TN[tn_request] Neq MEMREQDB Then
Return FALSE;
If .TN[gt_reg] Eql .OP1 Then
Return TRUE;
If .OP1 Neq T_NODE Then
Return FALSE;
Return FORGOTTEN(.OP1,.OP1[gt_arg1])
End;
Routine ISDESTROYABLE(N : Ref GT) =
Begin
If .N Eql T_NODE Then
Return .N[rw_destroyable] And .N[gt_mode] Eql GENREG
Else If .N Eql T_LITERAL Then
Return FALSE
Else If .N[gt_type] Eql S_TEMPNAME Then
Return (.N[tn_lon_lu] Lequ .LON And .N[tn_fon_lu] Lequ .FON)
Else
Return FALSE
End;
Routine ISREG(R : Ref GT) =
Begin
If .R Lss 8 THEN
Return TRUE;
If .R Eql T_LITERAL THEN
Return FALSE;
Selectone .R[gt_type] Of Set
[S_REGISTER]:
Return TRUE;
[S_LOCAL]:
If .R[gt_reg] Lss 8 Then
Return FALSE
Else
Return ISREG(.R[gt_reg]);
[S_TEMPNAME]:
Begin
If .R[tn_type] Eql BNDREG Then
Return TRUE;
If .R[tn_request] Eql MEMREQDB Then
If .R[tn_type] Eql 0 Or .R[tn_type] Eql BNDPREF Then
If Not .R[tn_v_lit] Then
Return ISREG(.R[gt_reg]);
Return FALSE
End;
[S_NODE]:
If .R[gt_mode] Eql GENREG Then
Return ISREG(.R[gt_reg])
Else
Return FALSE;
[Otherwise]:
Return FALSE
Tes
End;
Routine REGNUM(R : Ref GT) =
Begin
While .R Geqa 8 Do
R = .R[gt_reg];
Return .R
End;
Routine LOCDEF(NODE : Ref GT) =
Begin
While .NODE[gt_reg] Gtra 8 Do
NODE = .NODE[gt_reg];
Return .NODE
End;
Routine LOCDF1(NODE : Ref GT) =
Begin
While TRUE Do
Begin
If .NODE[gt_type] Eql S_TEMPNAME Then
If .NODE[tn_v_lit] Then
Return .NODE[tn_literal];
If .NODE[gt_reg] Lssa 8 Then
Exitloop;
NODE = .NODE[gt_reg]
End;
Return .NODE
End;
Routine GETOFFSET(NODE : Ref GT) =
Begin
Local
S : Ref ST;
! if the displacement is not a symbol
If Not .NODE[gt_v_symoff] Then
Return .NODE[gt_disp_16];
! get the dispacement symbol
S = .NODE[gt_disp];
If .S[gt_type] Eql S_LOCAL Then
Return LOCALOFFSET(S)
Else If .S[gt_type] Eql S_FORMAL Then
Return LOCALOFFSET(S)+FLD_K_FORMAL
Else
Return NAMEDESC(.NODE[gt_disp])
End;
Routine ISCHEAP(NODE : Ref GT) =
Begin
If ISREG(.NODE) Then
Return TRUE;
NODE = LOCDF1(.NODE);
If .NODE Eql T_LITERAL Then
Return FALSE;
If ISSTVAR(NODE) Then
If .NODE[gt_mode] Neq GENREG Then
Return FALSE;
NODE = LOCALOFFSET(NODE);
Return .NODE Eql 0 Or .NODE Eql 1^16-2
End;
Routine GMOFF(NODE : Ref GT) =
Begin
If .NODE[gt_v_symoff] Then
Return GMA(MAKNAM(.NODE[gt_disp]))
Else
Return BUILDOPD(OPND_NORMAL,IMMEDIATE,PC,.NODE[gt_disp_16])
End;
!
! generate a memory address
!
! input
! 'NODE' is a lexeme for which an address is to be
! generated. It may be a literal, node, symbol, or
! a tempname. 'NODE' includes any state bits.
! The state bits of interest are
! and .
! note: the field is only checked for T_LITERAL.
! for all other types, the [gt_type] field is used.
! several routines take advantage of this.
Routine GMA(NODE : Ref GT)=
Begin
Local
S : Ref GT,
L : Integer,
TN : Ref GT,
T : ADRWD,
NMODE : Integer,
O : Ref GT,
TY : Integer;
! IF NAMING A REGISTER
If .NODE Lssu 8 Then
Return BUILDOPD(OPND_NORMAL,GENREG,.NODE,0);
! NOW HANDLE LITERAL LEXEMES
If .NODE Eql T_LITERAL Then
If .NODE Then
Return BUILDOPD(OPND_NORMAL,IMMEDIATE,PC,CLITVALUE(.NODE))
Else
Return BUILDOPD(OPND_NORMAL,ABSOLUTE,PC,CLITVALUE(.NODE));
! IN ALL REMAINING CASES WE USE THE TYPE FIELD IN THE NODE
If .NODE[gt_type] Eql S_TEMPNAME Then
Begin
! if a stack reference, generate either -(SP) or n(SP)
If .NODE[tn_type] Eql BNDPUSH Then
If LOCALOFFSET(NODE) Gtr 1^15 Then
Begin
DYTEMPS = .DYTEMPS+2;
Return BUILDOPD(OPND_NORMAL,AUTODECR,SP,UNUSED)
End
Else
Return BUILDOPD(OPND_NORMAL,INDEXED,SP,LOCALOFFSET(NODE));
! this tempname is bound to another lexeme or another tempname.
If .NODE[tn_request] Eql MEMREQDB Then
If .NODE[tn_type] Eql 0 Or .NODE[tn_type] Eql BNDPREF Then
If .NODE[tn_v_lit] Then
Return GMA(.NODE[tn_literal])
Else
! note: the high 32 bits contains the state flags. the field
! is irrevalent as long as it is not T_LITERAL
Return GMA(LEXOUT(.NODE<32,32,0>,.NODE[gt_reg]));
! if this tempname is bound to a register
If .NODE[tn_type] Eql BNDREG Then
Return BUILDOPD(OPND_NORMAL,GENREG,.NODE[gt_reg],0);
! use the regsiter and mode in the tempname
Return BUILDOPD(OPND_NORMAL,.NODE[gt_mode],.NODE[gt_reg],LOCALOFFSET(NODE))
End;
! GRAPH TABLE CASES
If .NODE[gt_type] Eql S_NODE Then
Begin
! if delay folded this node to a constant
If .NODE Then
! if a literal used as a value
If .NODE Then
Return BUILDOPD(If .NODE[gt_v_symoff]
Then OPND_NAME
Else OPND_NORMAL,
IMMEDIATE,PC,GETOFFSET(.NODE))
Else
! if a literal used as an address (can it not be a symbol offset also?)
Return BUILDOPD(OPND_NORMAL,ABSOLUTE,PC,.NODE[gt_disp_16]);
! get the mode and handle the normal cases
NMODE = .NODE[gt_mode];
If .NMODE Eql GENREG Then
Return GMA(.NODE[gt_reg]);
If .NMODE Eql GENREG+DEFERRED Then
Return DEFER(GMA(.NODE[gt_reg]));
! get the offset and determine whether it is absolute or relocatable
O = GETOFFSET(.NODE);
If Not .NODE[gt_v_symoff] Then
TY = OPND_NORMAL
Else
Begin
S = .NODE[gt_disp];
If ONEOF(.S[gt_type],S_LOCAL,S_FORMAL) Then
TY = OPND_NORMAL
Else
TY = OPND_NAME
End;
! handle '(R)+' and '@(R)+'
If (.NMODE And 6) Eql AUTOINCR Then
Return BUILDOPD(.TY,If .NODE[rw_immediate]
Then IMMEDIATE
Else .NMODE,
REGNUM(.NODE[gt_reg]),.O);
! at this point, the mode may only be AUTODECR or INDEXED. Since
! only FINAL may generate AUTODECR it is an error if we see it here.
If (.NMODE And 6) Neq INDEXED Then
PUNT(580);
! for indexed modes, there is always a tempname.
TN = .NODE[gt_reg];
! if the tempname is used as a value
If .NODE Then
Return GMA(.TN);
! the tempname is being used as an address.
! if a named-cse usage then reference the symbol and defer as necessary
If .TN Gtru 7 And .TN[tn_type] Eql BNDNCSE Then
Begin
T = GMA(LEXOUT(T_SYMBOL,.TN[gt_reg]));
If .NMODE Then
T = DEFER(.T);
Return .T
End;
! if a register reference
If ISREG(.TN) Then
Return BUILDOPD(.TY,.NMODE,REGNUM(.TN),.O);
! at this point we want an address and what we have is an index register
! and an offset. we need to return the sum of the two and not the
! contents of what they point to.
! if called from SAMEADDR and friends, just return a unique descriptor
If .SAMETOG Neq 0 Then
Return -(.TN^32+(3 And .NMODE)^16+.O);
T = VERYTEMP(0);
EMIT(PMOV,GMA(.TN),GMA(.T));
If ISREG(.T) Then
Return BUILDOPD(.TY,.NMODE,REGNUM(.T),.O);
EMIT(PADD,GMOFF(.NODE),GMA(.T));
If .NMODE Eql INDEXED+DEFERRED Then
EMIT(PMOV,DEFER(GMA(.T)),GMA(.T));
Return DEFER(GMA(.T))
End;
! SYMBOL TABLE CASES
Selectone .NODE[gt_type] Of Set
[S_REGISTER]:
Return GMA(.NODE[gt_reg]);
[S_LOCAL]:
! if bound to a register or a stack location
If .NODE[gt_reg] Gequ 8 Then
Return GMA(.NODE[gt_reg])
Else
Return BUILDOPD(OPND_NORMAL,INDEXED,SP,LOCALOFFSET(NODE));
[S_FORMAL]:
! if bound to a register or a stack location
If .NODE[gt_reg] Gequ 8 Then
Return GMA(.NODE[gt_reg])
Else
Return BUILDOPD(OPND_NORMAL,INDEXED,SP,FLD_K_FORMAL+LOCALOFFSET(NODE));
[S_GLOBAL,S_EXTERNAL]:
! PIC seems to mean that the code may float but variables are fixed.
! this means that absolute addresses must be used for PIC code at
! all times but relative addressing may be used for non-PIC code.
Begin
L = (If .NODE
Then IMMEDIATE
Else If .swit_pic
Then ABSOLUTE
Else RELATIVE);
Return BUILDOPD(OPND_NAME,.L,PC,NAMEDESC(.NODE))
End;
[S_OWN,S_ROUTINE,S_GBL_ROUTINE,S_FORWARD]:
Return BUILDOPD(OPND_NAME,
If .NODE Then IMMEDIATE Else RELATIVE,
PC, NAMEDESC(.NODE))
Tes;
PUNT(580);
Return 0
End; ! OF GMA
Routine GMA8(OPND : Ref GT) =
Begin
Local
X : ADRWD;
X = GMA(.OPND);
If Not ISLIT(.OPND) Then
If .OPND[gt_pos] Eql 8 Then
X = NXTBYTEADR(.X);
Return .X
End;
! ROUTINES TO HANDLE GENERAL DATA MOVES
! -------------------------------------
Forward Routine
CLEARFIELD : Novalue,
MAKEDESTROYABLE,
DIAL,
ISMOVSELF,
SHIFT : Novalue,
ISOLATE : Novalue,
MASK,
GENBITTEST : Novalue,
POSITIONIT;
Macro
PICK8(INSTR,POS,SIZ)=
Begin
If (POS)+(SIZ) Leq 8 Then
%Name(INSTR,B)
Else
INSTR
End %;
Routine CK08(NODE : Ref GT) =
Begin
If .NODE Eql T_SYMBOL Then
Begin
If .NODE[gt_pos] Eql 0 And .NODE[gt_len] Eql 8 Then
Return TRUE;
Return FALSE
End;
If .NODE Neq T_NODE Then
Return FALSE;
If .NODE[gt_pos] Lss 8 Then
If .NODE[gt_pos]+.NODE[gt_len] Leq 8 Then
Return TRUE;
Return FALSE
End;
Macro
CHECK08(NX)=CK08(NX) %;
Routine SIMPLEMOVE(O1 : Ref GT,O2 : Ref GT) : Novalue =
Begin
Local
A1 : ADRWD,
A2 : ADRWD;
If .O1 Neq .O2 Then
Begin
A1 = GMA(.O1);
A2 = GMA(.O2);
If .A1 Neq .A2 Then
If Not ISMOVSELF(.A1,.A2) Then
If CHECK08(.O1) Then
EMIT(PMOVB,.A1,.A2)
Else If CHECK08(.O2) Then
EMIT(PMOVB,.A1,.A2)
Else
EMIT(PMOV,.A1,.A2)
End
End;
Routine ISMOVSELF(S : Ref GT,D : Ref GT)=
Begin
Macro
PCRETURN=Return .S Eql PC %,
COMBINE(MODE1,MODE2)=(MODE1*8 + MODE2) %;
If .S Eql .D Then
Return TRUE;
If .S Neq .D Then
Return FALSE;
If .S Neq .D Then
Return FALSE;
Selectone COMBINE(.S,.D) Of Set
[COMBINE(0,0)]: Return TRUE;
[COMBINE(1,1)]: Return TRUE;
[COMBINE(6,6)]: Return TRUE;
[COMBINE(7,7)]: Return TRUE;
[COMBINE(3,3)]: PCRETURN;
[COMBINE(6,3)]: PCRETURN;
[COMBINE(3,6)]: PCRETURN;
[Otherwise]: Return FALSE
Tes
End;
Routine SAMEADDR(O1 : Ref GT,O2 : Ref GT) =
Begin
Local
SDTD : Integer,
A1 : ADRWD,
A2 : ADRWD;
SDTD = .DYTEMPS;
SAMETOG = .SAMETOG+1;
A1 = GMA(.O1);
A2 = GMA(.O2);
DYTEMPS = .SDTD;
SAMETOG = .SAMETOG-1;
Return ISMOVSELF(.A1,.A2)
End;
Routine SAMEWORD(O1 : Ref GT,O2 : Ref GT) =
Begin
Local
SDTD : Integer,
A1 : ADRWD,
A2 : ADRWD;
SDTD = .DYTEMPS;
SAMETOG = .SAMETOG+1;
A1 = GMA(.O1) And (-2);
A2 = GMA(.O2) And (-2);
DYTEMPS = .SDTD;
SAMETOG = .SAMETOG-1;
Return ISMOVSELF(.A1,.A2)
End;
Routine OVERLAP(P1 : Integer,S1 : Integer,P2 : Integer,S2 : Integer)=
Begin
S1 = .S1+.P1;
S2 = .S2+.P2;
Return .S2 Geq .P1 And .P2 Leq .S1
End;
Routine REG8(R : Ref GT)=
Begin
If .R[gt_pos] Neq 8 Then
Return GMA(.R);
R = MAKEDESTROYABLE(.R);
If ISREG(.R) Then
Begin
EMIT(PSWAB,GMA(.R),0);
Return GMA(.R)
End
Else
Return NXTBYTEADR(GMA(.R))
End;
Routine NOMOVREQD(O1 : Ref GT,O2 : Ref GT)=
Begin
If .O1 Eql T_LITERAL Or .O2 Eql T_LITERAL Then
Return .O1 Eql .O2;
If .O1 Neq .O2 Then
If .O1+.O2 Gtr PFNONE+PF016 Then
Return FALSE;
Return SAMEADDR(.O1,.O2)
End;
Routine DEPENDON(S : Ref GT,D : Ref GT) =
Begin
Local
RESULT : Boolean,
T : ADRWD,
E : ADRWD,
SDTD : Integer;
If ISREG(.D) Then
Return REGNUM(.S) Eql REGNUM(.D)
Else
Begin
SDTD = .DYTEMPS;
SAMETOG = .SAMETOG+1;
T = GMA(.S);
If .T Lss 0 Then
T = GMA(.S[gt_reg]);
E = GMA(.D);
If .E Lss 0 Then
E = GMA(.D[gt_reg]);
RESULT = (NODEFER(.T) And (-2)) Eql (.E And (-2));
DYTEMPS = .SDTD;
SAMETOG = .SAMETOG-1;
Return .RESULT
End
End;
Routine GENMOVE(O1 : Ref GT,O2 : Ref GT) : Novalue =
Begin
Local
P1 : Integer,
P2 : Integer,
T : ADRWD,
SPC : Boolean,
C,
X,
BS,
L,
LAB : Ref CELL,
POS1 : Integer,
POS2 : Integer,
SIZE1 : Integer,
SIZE2 : Integer,
S,
CHP : Boolean,
XBIT,
OP;
Bind
GMOVPLIT = UPlit Byte(
0,0,1,8,5,1,
0,0,1,8,5,1,
2,2,1,8,5,1,
7,7,6,8,8,6,
3,3,4,8,5,4,
2,2,1,8,5,1) : Vector[,Byte];
If .O1 Eql .O2 Then
Return;
P1 = .O1;
P2 = .O2;
If Not .swit_quick Then
If NOMOVREQD(.O1,.O2) Then
Return;
Case .GMOVPLIT[.P1*6+.P2] From 0 To 8 Of Set
[0]: ! 0 - FULL WORD TO FULL WORD
If ISZERO(.O1) Then
EMIT(PCLR,GMA(.O2),0)
Else
EMIT(PMOV,GMA(.O1),GMA(.O2));
[1]: ! 1 - MOVE TO <0,8> OR <8,8> FROM <0,16>, <0,8> OR <8,8>
If ISREG(.O2) Then
Begin
POS2 = .O2[gt_pos];
If ISLIT(.O1) Then
Begin
T = CLITVALUE(.O1);
If (.T And 255) Neq 255 Then
CLEARFIELD(.O2,.POS2,8);
If .T Neq 0 Then
EMIT(PICK8(PBIS,.POS2,8),
GMA(MAKLIT(.T^.POS2)),
GMA(.O2));
Return
End;
T = .O1;
If DEPENDON(.O1,.O2) Then
Begin
T = VERYTEMP(0);
SIMPLEMOVE(.O1,.T)
End;
If .POS2 Eql 8 Or (ISREG(.T) And .P1 Eql PF88) Then
T = DIAL(.T,.O1[gt_pos],.O1[gt_len],.POS2,8);
CLEARFIELD(.O2,.POS2,8);
If .POS2 Eql 0 And Not ISREG(.T) Then
Begin
EMIT(PBISB,GMA8(.T),GMA(.O2));
Return
End;
EMIT(PICK8(PBIS,.POS2,8),GMA(.T),GMA(.O2))
End
Else If ISLIT(.O1) Then
If CLITVALUE(.O1) Eql 0 Then
EMIT(PCLRB,GMA8(.O2),0)
Else
EMIT(PMOVB,GMA(.O1),GMA8(.O2))
Else If ISREG(.O1) And .O1[gt_pos] Neq 0 Then
Begin
If Not DEPENDON(.O2,.O1) Then
Begin
T = GMA(.O1);
EMIT(PSWAB,.T,0);
EMIT(PMOVB,.T,GMA8(.O2));
EMIT(PSWAB,.T,0)
End
Else
Begin
T = VERYTEMP(0);
SIMPLEMOVE(.O1,.T);
T = REG8(.T);
EMIT(PMOVB,.T,GMA8(.O2))
End
End
Else
EMIT(PMOVB,GMA8(.O1),GMA8(.O2));
[2]: ! 2 - MOVE TO 0,16 FROM 0,8 OR 8,8
Begin
If SAMEWORD(.O1,.O2) Then
Begin
SHIFT(.O1,.O1[gt_pos],0,8);
ISOLATE(.O2,0,.O1[gt_len]);
Return
End;
If DEPENDON(.O1,.O2) Then
Begin
EMIT(PMOVB,GMA8(.O1),GMA(.O2));
CLEARFIELD(.O2,8,8);
Return
End;
If ISREG(.O1) And .O1[gt_pos] Eql 8 Then
Begin
SIMPLEMOVE(.O1,.O2);
EMIT(PCLRB,GMA(.O2),0);
EMIT(PSWAB,GMA(.O2),0)
End
Else
Begin
EMIT(PCLR,GMA(.O2),0);
EMIT(PBISB,GMA8(.O1),GMA(.O2))
End
End;
[3]: ! 3 - MOVE TO 0,16 FROM ARBITRARY FIELD
Begin
T = .O2;
If Not SAMEWORD(.O1,.O2) Then
If Not ISCHEAP(.O2) Then
If .O1[gt_pos] Neq 0 Then
Begin
O2 = VERYTMPREG();
If .O2 Eql 0 Then
O2 = .T
End;
SIMPLEMOVE(.O1,.O2);
SHIFT(.O2,.O1[gt_pos],0,.O1[gt_len]);
ISOLATE(.O2,0,.O1[gt_len]);
SIMPLEMOVE(.O2,.T)
End;
[4]: ! 4 - MOVE TO 0,8 OR 8,8 FROM ARBITRARY FIELD
Begin
T = .O1;
If DEPENDON(.O1,.O2) Then
Begin
T = VERYTEMP(0);
SIMPLEMOVE(.O1,.T)
End;
SPC = ISREG(.O2) And .O2[gt_pos] Eql 8;
If .SPC Or .O1[gt_len] Lss 8 Then
T = DIAL(.T,.O1[gt_pos],.O1[gt_len],8*.SPC,8)
Else
T = POSITIONIT(.T,.O1[gt_pos],0,8);
If .SPC Then
Begin
CLEARFIELD(.O2,8,8);
EMIT(PBIS,GMA(.T),GMA(.O2))
End
Else
EMIT(PMOVB,GMA(.T),GMA8(.O2))
End;
[5]: ! 5 - ARBITRARY FIELD TO ARBITRARY FIELD
Begin
BS = -1;
C = -1;
POS2 = .O2[gt_pos];
SIZE2 = .O2[gt_len];
If ISLIT(.O1) Then
Begin
L = CLITVALUE(.O1);
X = MASK(0,.SIZE2,0);
L = .L And .X;
If .L Eql .X Then
C = 0;
If .L Eql 0 Then
BS = 0;
T = MAKLIT(.L^.POS2)
End
Else
Begin
If .O1[gt_type] Eql S_TEMPNAME Then
Begin
POS1 = 0;
SIZE1 = 16
End
Else
Begin
POS1 = .O1[gt_pos];
SIZE1 = .O1[gt_len]
End;
T = DIAL(.O1,.POS1,.SIZE1,.POS2,.SIZE2)
End;
If .C Neq 0 Then
CLEARFIELD(.O2,.POS2,.SIZE2);
If .BS Neq 0 Then
EMIT(PICK8(PBIS,.POS2,.SIZE2),GMA(.T),GMA(.O2))
End;
[6]: ! 6 - MOVE TO 0,8 OR 8,8 FROM E,1
Begin
CHP = 0;
P1 = .O1[gt_pos];
SPC = (ISREG(.O2) And .O2[gt_pos] Eql 8);
If DEPENDON(.O1,.O2) Or
(SAMEWORD(.O1,.O2) And
OVERLAP(.P1,.O1[gt_len],.O2[gt_pos],.O2[gt_len])) Then
Begin
T = VERYTEMP(0);
If ISCHEAP(.T) And Not .SPC Then
Begin
CHP = -1;
S = .O2;
O2 = .T
End
Else
Begin
SIMPLEMOVE(.O1,.T);
O1 = .T
End
End;
CLEARFIELD(.O2,.O2[gt_pos],.O2[gt_len]);
LAB = GENLABEL();
GENBITTEST(.O1,.P1,.LAB);
If Not .SPC Then
EMIT(PINCB,GMA8(.O2),0)
Else
EMIT(PBIS,GMA(MAKLIT(1^8)),GMA(.O2));
PLACELABEL(.LAB);
If .CHP Then
EMIT(PMOVB,GMA(.O2),GMA8(.S))
End;
[7]: ! 7 - MOVE TO 0,16 FROM E,1
Begin
CHP = FALSE;
P1 = .O1[gt_pos];
If SAMEWORD(.O1,.O2) Then
Begin
If (.P1 Mod 8) Leq 2 Then
Begin
SHIFT(.O1,.P1,0,1);
ISOLATE(.O2,0,1);
Return
End;
CHP = TRUE
End
Else If DEPENDON(.O1,.O2) Then
CHP = TRUE;
If .CHP Then
Begin
T = VERYTEMP(0);
If ISCHEAP(.T) Then
Begin
S = .O2;
O2 = .T
End
Else
Begin
CHP = 0;
SIMPLEMOVE(.O1,.T);
O1 = .T
End
End;
EMIT(PCLR,GMA(.O2),0);
LAB = GENLABEL();
GENBITTEST(.O1,.P1,.LAB);
EMIT(PINC,GMA(.O2),0);
PLACELABEL(.LAB);
If .CHP Then
EMIT(PMOV,GMA(.O2),GMA(.S))
End;
[8]: ! 8 - MOVE TO/FROM ARBITRARY ONE BIT FIELD
Begin
If ISLIT(.O1) Then
Begin
T = CLITVALUE(.O1);
XBIT = GMA(MAKLIT(MASK(.O2[gt_pos],1,0)));
If .O2[gt_pos]+.O2[gt_len] Leq 8 Then
OP = (If .T Then PBISB Else PBICB)
Else
OP = (If .T Then PBIS Else PBIC);
EMIT(.OP,.XBIT,GMA(.O2));
Return
End;
P1 = (If .O1[gt_type] Eql S_TEMPNAME
Then 0
Else .O1[gt_pos]);
If DEPENDON(.O1,.O2) Or
(SAMEWORD(.O1,.O2) And
OVERLAP(.P1,.O1[gt_len],.O2[gt_pos],.O2[gt_len])) Then
Begin
T = VERYTEMP(0);
SIMPLEMOVE(.O1,.T);
O1 = .T
End;
CLEARFIELD(.O2,.O2[gt_pos],.O2[gt_len]);
LAB = GENLABEL();
GENBITTEST(.O1,.P1,.LAB);
POS2 = .O2[gt_pos];
If .POS2 Eql 0 Then
EMIT(PINCB,GMA(.O2),0)
Else If .POS2 Eql 8 And Not(ISREG(.O2)) Then
EMIT(PINCB,GMA8(.O2),0)
Else
EMIT(PICK8(PBIS,.POS2,1),GMA(MAKLIT(1^.POS2)),GMA(.O2));
PLACELABEL(.LAB);
End
Tes
End; ! OF GENMOVE
Macro
TTN(Z)=(1^(Z)) %,
TTM(Z)=(TTN(Z)-1) %;
Routine MAKEDESTROYABLE(XOPND : Ref GT) =
Begin
Local
T : Ref GT;
If Not ISDESTROYABLE(.XOPND) Then
Begin
T = VERYTEMP(.XOPND[gt_reg]);
SIMPLEMOVE(.XOPND,.T)
End
Else If .XOPND[gt_type] Eql S_TEMPNAME Then
Return .XOPND
Else
Begin
T = .XOPND[gt_reg];
If .XOPND[gt_mode] Neq GENREG Then
SIMPLEMOVE(.XOPND,.T)
End;
Return .T
End;
Bind
MASKS = Uplit Word(
0,
TTM(1),
TTM(2),
TTM(3),
TTM(4),
TTM(5),
TTM(6),
TTM(7),
TTM(8),
TTM(9),
TTM(10),
TTM(11),
TTM(12),
TTM(13),
TTM(14),
TTM(15),
TTM(16)) : Vector[,Word];
Routine MASK(POS : Integer,SIZ : Integer,COMP : Boolean)=
Begin
Local
X : Integer;
X = (.MASKS[.SIZ])^.POS;
If .COMP Then
X = Not(.X);
Return .X And %x'7fffffff'
End;
Routine CLEARMASK(XOPND : Ref GT,MSK : Integer) : Novalue =
Begin
Local
LOCN : ADRWD;
MSK = .MSK And %x'ffff';
If .MSK Eql 0 Then
Return;
If CHECK08(.XOPND) Then
MSK = .MSK And 255;
LOCN = GMA(.XOPND);
Selectone .MSK Of Set
[%x'ffff']:
EMIT(PCLR,.LOCN,0);
[%x'00ff']:
EMIT(PCLRB,.LOCN,0);
[%x'ff00']:
If Not ISREG(.XOPND) Then
EMIT(PCLRB,NXTBYTEADR(.LOCN),0)
Else
EMIT(If .MSK Leq 255 Then PBICB Else PBIC,
GMA(MAKLIT(.MSK)),.LOCN);
[Otherwise]:
EMIT(If .MSK Leq 255 Then PBICB Else PBIC,GMA(MAKLIT(.MSK)),.LOCN)
Tes
End;
Routine CLEARFIELD(XOPND : Ref GT,P : Integer,S : Integer) : Novalue =
Begin
CLEARMASK(.XOPND,MASK(.P,.S,0))
End;
Routine ISOLATE(XOPND : Ref GT,P : Integer,S : Integer) : Novalue =
Begin
CLEARMASK(.XOPND,MASK(.P,.S,1))
End;
Routine SHIFT(XOPND : Ref GT,XFP : Integer,XTP : Integer,SZ : Integer) : Novalue =
Begin
Local
DIST : Integer,
RL : Boolean,
SB : Boolean,
RB : Boolean,
SA : Boolean,
SHIFTROT : Boolean,
OP : Integer,
LAB : Ref CELL,
ADR : ADRWD,
ADR1 : ADRWD;
! compute the shift distance and return if no shift required
DIST = .XTP - .XFP;
If .DIST Eql 0 Then
Return FALSE;
ADR = GMA(.XOPND);
! if shifting the sign bit to 2,3,10, or 11 then generate:
!
! BIC #m,X ; this tests the sign bit!
! BPL 1$
! COM X l flip all bits
! 1$:
If .SZ Eql 1 And .XFP Eql 15 And .ADR Neq 0 Then
If ONEOF(.XTP,2,3,4,10,11) Then
Begin
LAB = GENLABEL();
EMIT(PBIC,GMA(MAKLIT(1^.XTP)),.ADR);
EMIT(PBPL,.LAB,0);
EMIT(PCOM,.ADR,0);
PLACELABEL(.LAB);
Return FALSE
End;
RL = FALSE;
SB = FALSE;
RB = FALSE;
SA = FALSE;
SHIFTROT = FALSE;
! if a right shift
If .DIST Lss 0 Then
Begin
RL = TRUE;
DIST = -.DIST
End;
! for a shift of 13,14, or 15 bits, rotate around the top
If .DIST Gtr 12 Then
Begin
RL = Not .RL;
DIST = 17 - .DIST;
SHIFTROT = TRUE
End;
! if more than 7 bits then use a SWAB
If .DIST Gtr 7 Then
Begin
SB = TRUE;
DIST = .DIST-8
End;
If .DIST Gtr 4 Then
Begin
Local A;
If .SZ Gtr 8 Then
Begin
If Not .RL Or .DIST Neq 5 Then
Begin
RB = TRUE;
SHIFTROT = TRUE;
If .RL Then
SA = 8-.DIST
Else
SB = TRUE;
DIST = 8-.DIST;
RL = Not .RL
End
End
Else
Begin
A = (If .RL Then 16-(.XFP+.SZ) Else .XFP);
SA = Min(.A,8-.DIST);
If .SA Eql 0 Then
SB = TRUE;
DIST = 8-.DIST;
RL = Not .RL
End
End;
ADR1 = .ADR;
If .SB+(.SA Neq 0)+.DIST+.RB Gtr 1 Then
If .ADR Neq 0 Then
Begin
ADR = VERYTMPREG();
If .ADR Eql 0 Then
ADR = .ADR1
Else
Begin
GENMOVE(.XOPND,.ADR);
ADR = GMA(.ADR)
End
End;
! generate a SWAB if necessary
If .SB Then
EMIT(PSWAB,.ADR,0);
! generate an RORB
If .RB And .RL Then
EMIT(PRORB,.ADR,0);
OP = (If .RL Then PASR Else PASL);
If .SHIFTROT Then
OP = .OP + (PROR - PASR); ! ASR TO ROR, ASL TO ROL
While (DIST = .DIST-1) Geq 0 Do
Begin
EMIT(.OP,.ADR,0);
If .DIST Eql 0 And .RB And Not .RL Then
EMIT(PROLB,.ADR,0);
SA = .SA - 1;
If .SA Eql 0 Then
EMIT(PSWAB,.ADR,0)
End;
If .ADR Neq .ADR1 Then
EMIT(PMOV,.ADR,.ADR1);
!TRUE IFF OLD CARRY BIT HAS BEEN ROTATED INTO WORD
Return .SHIFTROT And Not .SB
End;
Routine POSITIONIT(X : Ref GT,XFP : Integer,XTP : Integer,SZ : Integer)=
Begin
Local
T : Ref GT;
If .SZ Leq 8 And .XFP Eql 8 And .XTP Eql 0 Then
If Not ISIDT(.X) Then
If Not ISREG(.X) Then
Begin
T = VERYTEMP(.X[gt_reg]);
EMIT(PMOVB,GMA8(.X),GMA(.T));
Return .T
End;
T = MAKEDESTROYABLE(.X);
SHIFT(.T,.XFP,.XTP,.SZ);
Return .T
End;
Routine DIAL(XOPND : Ref GT,XFP,XFS,XTP,XTS) =
Begin
Local
S : Integer,
T : Ref GT;
S = Min(.XFS,.XTS);
T = POSITIONIT(.XOPND,.XFP,.XTP,.S);
ISOLATE(.T,.XTP,.S);
Return .T
End;
Routine ALIGNX(O1 : Ref Vector,O2 : Ref Vector) : Novalue =
Begin
Local
N1 : Ref GT,
N2 : Ref GT,
X1 : Ref GT,
X2 : Ref GT,
T1 : Ref GT,
T2 : Ref GT,
T : Boolean;
N1 = .O1[0];
N2 = .O2[0];
If .N1[gt_pos] Gtr .N2[gt_pos] Then
(X1 = .N2; X2 = .N1; T = 0)
Else
(X1 = .N1; X2 = .N2; T = 1);
T1 = MAKEDESTROYABLE(.X1);
ISOLATE(.T1,.X1[gt_pos],.X1[gt_len]);
T2 = DIAL(.X2,.X2[gt_pos],.X2[gt_len],.X1[gt_pos],16);
If .T Then
(O1[0] = .T1; O2[0] = .T2)
Else
(O1[0] = .T2; O2[0] = .T1)
End;
! TEST-BRANCH SPECIAL CASE ROUTINES
! ---------------------------------------
Routine GENBITTEST(OPND : Ref GT,IBIT,FLAB) : Novalue =
Begin
Local
OPC1 : Integer,
OPC2 : Integer,
ADR : ADRWD,
SPC : Boolean;
If ISLIT(.OPND) Then
Begin
If (CLITVALUE(.OPND) And (1^.IBIT)) Eql 0 Then
EMIT(PBR,.FLAB,0);
Return
End;
SPC = TRUE;
ADR = GMA(.OPND);
If .IBIT Eql 15 Then
Begin
OPC1 = PTST;
OPC2 = PBPL
End
Else If .IBIT Eql 7 Then
Begin
OPC1 = PTSTB;
OPC2 = PBPL
End
Else If Not ISDESTROYABLE(.OPND) Then
SPC = FALSE
Else
Selectone .IBIT Of Set
[0]:
Begin
OPC1 = PROR;
OPC2 = PBHIS
End;
[14]:
Begin
OPC1 = PASL;
OPC2 = PBPL
End;
[6]:
Begin
OPC1 = PASLB;
OPC2 = PBPL
End;
[Otherwise]:
SPC = FALSE
Tes;
If Not .SPC Then
Begin
OPC1 = PICK8(PBIT,.IBIT,1);
EMIT(.OPC1,GMA(MAKLIT(MASK(.IBIT,1,0))),.ADR);
OPC2 = PBEQ
End
Else
EMIT(.OPC1,.ADR,0);
EMIT(.OPC2,.FLAB,0)
End;
Bind
RELOPTAB = Uplit Byte(
PBGT,
PBLE,
PBLT,
PBGE,
PBEQ,
PBNE,
0,0,0,0,0, ! not,eqv,and,or,xor
PBHI,
PBLOS,
PBLO,
PBHIS,
PBEQ,
PBNE) : Vector[,Byte];
Bind
CRELOP = Uplit Byte(
PBNE,PBEQ,PBLE,PBGT,PBGE,PBLT,0,0,PBLO,PBHIS,0,0,PBLOS,PBHI)
: Vector[,Byte];
Routine MAPTOUNSIGNED(OP : Integer)=
Begin
Selectone .OP Of Set
[PBGT]:
Return PBHI;
[PBGE]:
Return PBHIS;
[PBLT]:
Return PBLO;
[PBLE]:
Return PBLOS;
[Otherwise]:
Return OP
Tes
End;
Macro
CONVERSERELATIONAL(OP)=(.CRELOP[OP - PBNE]) %;
Macro
REVERSERELATIONAL(OP)=((OP) Xor 1) %;
Routine COMPARE(OP1 : Ref GT,OP2 : Ref GT,RELOP : Integer,LAB : Ref GT) : Novalue =
Begin
EMIT(PCMP,GMA(.OP1),GMA(.OP2));
EMIT(.RELOP,.LAB,0)
End;
Routine COMPAREBYTE(OP1 : Ref GT,OP2 : Ref GT,RELOP : Integer,LAB : Ref GT) : Novalue =
Begin
EMIT(PCMPB,GMA8(.OP1),GMA8(.OP2));
EMIT(MAPTOUNSIGNED(.RELOP),.LAB,0)
End;
Routine REALCOMPARE(OP1 : Ref GT,OP2 : Ref GT,RELOP : Integer,LAB : Ref GT) : Novalue =
Begin
Local
T : Ref GT;
Bind
SSPLIT = UPlit Byte(
0,0,2,2,2,2,
0,0,2,2,2,2,
3,3,1,4,4,1,
3,3,4,4,4,4,
3,3,4,4,4,4,
3,3,1,4,4,1) : Vector[,Byte];
Case .SSPLIT[.OP1*6+.OP2] From 0 To 4 Of Set
[0]: !0 -- FULL WORD COMPARISON
COMPARE(.OP1,.OP2,.RELOP,.LAB);
[1]: !1 -- BYTE-BYTE COMPARISON
If (ISREG(.OP1) And .OP1 Neq PF08) Or
(ISREG(.OP2) And .OP2 Neq PF08) Then
Begin
ALIGNX(OP1,OP2);
COMPARE(.OP1,.OP2,MAPTOUNSIGNED(.RELOP),.LAB)
End
Else
COMPAREBYTE(.OP1,.OP2,.RELOP,.LAB);
[2]: !2 -- FULL WORD WITH SOMETHING SMALLER
Begin
T = DIAL(.OP2,.OP2[gt_pos],.OP2[gt_len],0,16);
COMPARE(.OP1,.T,.RELOP,.LAB)
End;
[3]: !3 -- SOMETHING SMALLER WITH FULL WORD
Begin
T = DIAL(.OP1,.OP1[gt_pos],.OP1[gt_len],0,16);
COMPARE(.T,.OP2,.RELOP,.LAB)
End;
[4]: !4 -- BOTH ARE FUNNY FIELDS
Begin
ALIGNX(OP1,OP2);
COMPARE(.OP1,.OP2,MAPTOUNSIGNED(.RELOP),.LAB)
End
Tes
End;
Routine LITCOMPARE(OP1 : Ref GT,L : Ref GT,RELOP : Integer,LAB : Ref GT) : Novalue =
Begin
Local
T : Integer,
T1 : Ref GT,
L1 : Ref CELL,
CASINDEX : Integer,
N : Integer;
Bind
O1SS = Uplit Byte(0,0,1,2,3,1) : Vector[,Byte];
CASINDEX = .O1SS[.OP1];
If .OP1 Eql PF88 Then
If ISREG(.OP1) Then
CASINDEX = 3;
Case .CASINDEX From 0 To 3 Of Set
[0]: !0 -- FULL WORD CASES
Begin
N = (If ISLIT(.L) Then CLITVALUE(.L) Else 999);
If .N Eql 0 Then
Begin
EMIT(PTST,GMA(.OP1),0);
EMIT(.RELOP,.LAB,0)
End
Else If Abs(.N) Eql 1 And ISDESTROYABLE(.OP1) Then
Begin
If .N Eql 1 Then
EMIT(PDEC,GMA(.OP1),0)
Else
EMIT(PINC,GMA(.OP1),0);
EMIT(.RELOP,.LAB,0)
End
Else
COMPARE(.OP1,.L,.RELOP,.LAB)
End;
[1]: !1 -- BYTE CASES
Begin
N = (If ISLIT(.L) Then CLITVALUE(.L) Else 999);
RELOP = MAPTOUNSIGNED(.RELOP);
If .N Eql 0 Then
Begin
EMIT(PTSTB,GMA8(.OP1),0);
EMIT(.RELOP,.LAB,0)
End
Else If Abs(.N) Eql 1 And ISDESTROYABLE(.OP1) Then
Begin
If .N Eql 1 Then
EMIT(PDECB,GMA8(.OP1),0)
Else
EMIT(PINCB,GMA8(.OP1),0);
EMIT(.RELOP,.LAB,0)
End
Else
COMPAREBYTE(.OP1,.L,.RELOP,.LAB)
End;
[2]: !2 -- ONE BIT CASES
Begin
T = CLITVALUE(.L);
If .T Eql 0 Or .T Eql 1 Then
If .RELOP Eql PBEQ Or .RELOP Eql PBNE Then
Begin
If (.T Eql 0) Eqv (.RELOP Eql PBEQ) Then
GENBITTEST(.OP1,.OP1[gt_pos],.LAB)
Else
Begin
L1 = GENLABEL();
GENBITTEST(.OP1,.OP1[gt_pos],.L1);
EMIT(PBR,.L1,0);
PLACELABEL(.L1)
End;
Return
End;
If .T Lss 0 Then
If .RELOP Eql PBGT Or .RELOP Eql PBGE Then
EMIT(PBR,.LAB,0);
If .T Gtr 1 Then
If .RELOP Eql PBLT Or .RELOP Eql PBLE Then
EMIT(PBR,.LAB,0)
End;
[3]: !3 -- GENERAL SUBFIELD CASES
Begin
T = CLITVALUE(.L);
If .T Eql 0 Then
Begin
RELOP = MAPTOUNSIGNED(.RELOP);
Selectone .RELOP Of Set
[PBHI]:
RELOP = PBNE;
[PBHIS]:
RELOP = PBR;
[PBLOS]:
RELOP = PBEQ;
[PBLO]:
Return;
Tes;
If .RELOP Neq PBR Then
EMIT(PICK8(PBIT,.OP1[gt_pos],.OP1[gt_len]),
GMA(.OP1),
GMA(MAKLIT(MASK(.OP1[gt_pos],.OP1[gt_len],0))));
EMIT(.RELOP,.LAB,0);
Return
End;
If .T Gtr 0 Then
Begin
If (.T^(.OP1[gt_pos]) Eql ((.T^(.OP1[gt_pos])) And %x'ffff')) Then
Begin
T1 = MAKEDESTROYABLE(.OP1);
ISOLATE(.T1,.OP1[gt_pos],.OP1[gt_len]);
COMPARE(.T1,MAKLIT(.T^(.OP1[gt_pos])),
MAPTOUNSIGNED(.RELOP),.LAB);
Return
End
End;
T1 = DIAL(.OP1,.OP1[gt_pos],.OP1[gt_len],0,16);
COMPARE(.T1,.L,.RELOP,.LAB)
End
Tes
End;
Routine GENCOMPARE(OP1 : Ref GT,OP2 : Ref GT,OPX : Integer,
LABT : Ref GT,LABF : Ref GT,SENSE : Boolean) : Novalue =
Begin
Local
RELOP : Integer;
RELOP = .RELOPTAB[.OPX - RELOPBASE];
If .SENSE Then
RELOP = CONVERSERELATIONAL(.RELOP);
If .LABT Eql 0 Then
Begin
RELOP = REVERSERELATIONAL(.RELOP);
LABT = .LABF;
LABF = 0
End;
If .OP2 Eql T_LITERAL Then
LITCOMPARE(.OP1,.OP2,.RELOP,.LABT)
Else If .OP1 Eql T_LITERAL Then
Begin
RELOP = CONVERSERELATIONAL(.RELOP);
LITCOMPARE(.OP2,.OP1,.RELOP,.LABT)
End
Else
REALCOMPARE(.OP1,.OP2,.RELOP,.LABT);
If .LABF Neq 0 Then
EMIT(PBR,.LABF,0);
End;
Macro COMPAREFALSE(X1,X2,NX,XL)=
GENCOMPARE(X1,X2,NX,XL,0,0) %;
Routine BITLIT(O1 : Ref GT,O2 : Ref GT) : Novalue =
Begin
Local
L : ADRWD,
P : Integer,
S : Integer;
P = .O1[gt_pos];
S = .O1[gt_len];
L = GMA(MAKLIT(CLITVALUE(.O2)^.P And .MASKS[.P+.S]));
EMIT(PICK8(PBIT,.P,.S),.L,GMA(.O1))
End;
Routine BITX(O1 : Ref GT,O2 : Ref GT,ENE : Boolean,LAB : Ref GT) : Novalue =
Begin
Local
P : Integer,
S : Integer;
Bind
BITPLIT = Uplit Byte(
0,0,1,2,2,1,
0,0,1,2,2,1,
1,1,1,2,2,1,
2,2,2,2,2,2,
2,2,2,2,2,2,
1,1,1,2,2,1) : Vector[,Byte];
If ISLIT(.O1) Then
BITLIT(.O2,.O1)
Else If ISLIT(.O2) Then
BITLIT(.O1,.O2)
Else
Case .BITPLIT[.O1*6+.O2] From 0 To 2 Of Set
[0]: ! 0 - BIT
EMIT(PBIT,GMA(.O1),GMA(.O2));
[1]: ! 1 - BITB
Begin
If .O1 Eql PF88 Then
If ISREG(.O1) Then
O1 = POSITIONIT(.O1,8,0,8);
If .O2 Eql PF88 Then
If ISREG(.O2) Then
O2 = POSITIONIT(.O2,8,0,8);
EMIT(PBITB,GMA8(.O1),GMA8(.O2))
End;
[2]: ! 2 - SUBFIELD CASES
Begin
S = Min(.O1[gt_len],.O2[gt_len]);
If .O1[gt_pos] Leq .O2[gt_pos] Then
(P = .O1[gt_pos]; O2 = DIAL(.O2,.O2[gt_pos],.O2[gt_len],.P,.S))
Else
(P = .O2[gt_pos]; O1 = DIAL(.O1,.O1[gt_pos],.O1[gt_len],.P,.S));
EMIT(PICK8(PBIT,.P,.S),GMA(.O1),GMA(.O2));
End
Tes;
EMIT(If .ENE Then PBNE Else PBEQ,.LAB,0)
End;
!!! THE FOLLOWING ROUTINES ARE THE NODE-SPECIFIC CODE GENERATORS
!!! --------------------------------------------------------------
Forward Routine
CODE : Novalue;
Macro
ADJUSTSTACK=
If .NODE[gt_dtdelete] Neq DTDONTCARE And
.NODE[gt_dtdelete] Neq .DYTEMPS Then
Begin
EMIT(PADD,GMA(MAKLIT(.DYTEMPS-.NODE[gt_dtdelete])),STACKPTR);
DYTEMPS = .NODE[gt_dtdelete]
End %,
CHECKFORFLOW=
(If .NODE[rw_flow] Then GFLOW(.NODE)) %,
CODELST(LST)=
PULSELIST(PULSECODE,LST,0) %,
LASTOPERAND=
gt_argv(.NODE[gt_argc]-1) %,
PICKTARGET(T,N)=
If .NODE[gt_v_tpath]
Then (T = .NODE[gt_arg2]; N = .NODE[gt_arg1])
Else (T = .NODE[gt_arg1]; N = .NODE[gt_arg2]) %,
STARTFREE(L1,L2)=
Begin
If Not EMPTY(L1) Or Not EMPTY(L2) Then
PLSTCNT = .PLSTCNT-1
End %,
STOPFREE(L1,L2)=
Begin
If Not EMPTY(L1) Or Not EMPTY(L2) Then
PLSTCNT = .PLSTCNT+1
End %;
Structure GOALWD[P,S,E]=[8]GOALWD;
Macro
GSIZEF = 0,32,0 %,
GPOSF = 32,32,0 %;
Macro
GOALS(P,S) = ((P)^32 Or (S)) %,
FULLWD = GOALS(0,16) %;
Routine SETNEWPS(NODE : Ref GT,P : Integer,S : Integer) =
Begin
NODE[gt_pos] = .P;
NODE[gt_len] = .S;
If .S Eql 1 Then
NODE[rw_ptr_state] = PFE1
Else If .P Eql 0 Then
If .S Eql 8 Then
NODE[rw_ptr_state] = PF08
Else If .S Eql 16 Then
NODE[rw_ptr_state] = PF016
Else
NODE[rw_ptr_state] = PFOTHER
Else If .P Eql 8 And .S Eql 8 Then
NODE[rw_ptr_state] = PF88
Else
NODE[rw_ptr_state] = PFOTHER;
NODE = .NODE[rw_ptr_state];
Return .NODE
End;
Routine GFLOW(NODE : Ref GT) : Novalue =
Begin
ADJUSTSTACK;
GENBITTEST(.NODE,.NODE[gt_pos],NODELABEL(.NODE[gt_lab_f]));
EMIT(PBR,NODELABEL(.NODE[gt_lab_t]),0)
End;
Routine PULSECODE(NODE : Ref GT,P) : Novalue =
Begin
Local
L : Ref GT,
LR : Boolean,
RFF : Integer,
LDT : Integer;
RFF = .NODE[rw_real_flow];
If .RFF Eql RFFLOW Then
Return;
L = .NODE[gt_label];
LR = .NODE[gt_v_lab_req];
LDT = .NODE[gt_dtdelete];
NODE[rw_flow] = FALSE;
NODE[gt_label] = 0;
NODE[gt_v_lab_req] = FALSE;
NODE[gt_dtdelete] = DTDONTCARE;
NODE[gt_v_mustgencode] = TRUE;
PLSTCNT = .PLSTCNT+1;
CODE(NODE,FULLWD);
PLSTCNT = .PLSTCNT-1;
NODE[gt_v_lab_req] = .LR;
NODE[gt_label] = .L;
NODE[rw_real_flow] = .RFF;
NODE[gt_dtdelete] = .LDT
End;
Routine GAS(NODE : Ref GT,GOAL : GOALWD,OP) =
Begin
Local
TAR : Ref GT,
NTAR : Ref GT,
TMP : Ref GT,
L : Ref GT,
INCORDEC : Boolean;
INCORDEC = FALSE;
TMP = .NODE[gt_reg];
CODE(NODE[gt_arg1],FULLWD);
CODE(NODE[gt_arg2],FULLWD);
If .NODE[rw_real_flow] Eql RFNONE Then
Return .NODE;
PICKTARGET(TAR,NTAR);
If .NODE[rc_mov_offset] Then
EMIT(PMOV,GMOFF(.NODE),GMA(.TMP));
If .NODE[rc_mov_target] Then
GENMOVE(.TAR,.TMP);
If .NODE[rc_negate] Then
EMIT(PNEG,GMA(.TMP),0);
If .NODE[rc_operate] Then
Begin
If .NTAR[rw_ptr_state] Gtr PF016 Then
Begin
L = VERYTEMP(.NTAR[gt_reg]);
GENMOVE(.NTAR,.L);
NTAR = .L
End;
EMIT(.OP,GMA(.NTAR),GMA(.TMP))
End;
! IF OFFSET IS LITERAL, GET ITS ABSOLUTE VALUE, TO
! TRY TO GET AS MANY INCB'S AND DECB'S AS POSSIBLE.
If .NODE[rc_add_offset] Xor .NODE[rc_sub_offset] Then
If Not .NODE[gt_v_symoff] And .NODE[gt_disp_16] Lss 0 Then
Begin
NODE[gt_disp] = -.NODE[gt_disp_16];
NODE[rc_add_offset] = Not .NODE[rc_add_offset];
NODE[rc_sub_offset] = Not .NODE[rc_sub_offset]
End;
! NO NEED TO TEST [SYMOFFF] IF THE ABOVE IS TRUE!
If .NODE[rc_add_offset] Then
If .NODE[gt_disp_16] Eql 1 Then
Begin
EMIT(PICK8(PINC,.GOAL,.GOAL),GMA(.TMP),0);
INCORDEC = TRUE
End
Else
EMIT(PADD,GMOFF(.NODE),GMA(.TMP));
If .NODE[rc_sub_offset] Then
If .NODE[gt_disp_16] Eql 1 Then
Begin
EMIT(PICK8(PDEC,.GOAL,.GOAL),GMA(.TMP),0);
INCORDEC = TRUE
End
Else
EMIT(PSUB,GMOFF(.NODE),GMA(.TMP));
CHECKFORFLOW;
If .INCORDEC Then
If .GOAL Eql GOALS(0,8) Then
Return SETNEWPS(.NODE,0,8);
Return .NODE
End;
Routine GADD(NODE : Ref GT,GOAL : GOALWD) =
Begin
Return GAS(.NODE,.GOAL,PADD)
End;
Routine GSUB(NODE : Ref GT,GOAL : GOALWD) =
Begin
Return GAS(.NODE,.GOAL,PSUB)
End;
Routine GSTORE(NODE : Ref GT,GOAL : GOALWD) =
Begin
Local
TAR : Ref GT,
NTAR : Ref GT,
TGOAL : GOALWD;
TAR = (If .NODE[gt_v_tpath] Then .NODE[gt_arg2] Else .NODE[gt_arg1]);
TGOAL = (If .TAR Eql T_LITERAL
Then FULLWD
Else GOALS(.TAR[gt_pos],.TAR[gt_len]));
CODE(NODE[gt_arg1],If .NODE[gt_v_tpath] Then .TGOAL Else FULLWD);
CODE(NODE[gt_arg2],If .NODE[gt_v_tpath] Then FULLWD Else .TGOAL);
PICKTARGET(TAR,NTAR);
If .TGOAL Neq GOALS(0,16) Then
If .NTAR Eql T_LITERAL Or
.TGOAL Eql GOALS(.NTAR[gt_pos],.NTAR[gt_len]) Then
NODE = SETNEWPS(.NODE,.TGOAL,.TGOAL);
If .NODE[rw_real] Then
Begin
GENMOVE(.NTAR,.NODE[gt_reg]);
GENMOVE(.NODE[gt_reg],.TAR)
End
Else
GENMOVE(.NTAR,.TAR);
CHECKFORFLOW;
Return .NODE
End;
Routine GDOT(NODE : Ref GT,GOAL : GOALWD) =
Begin
CODE(NODE[gt_arg1],FULLWD);
CHECKFORFLOW;
Return .NODE
End;
Routine GXNULL(NODE : Ref GT,GOAL : GOALWD) =
Begin
CHECKFORFLOW;
Return .NODE
End;
Routine GNULL(NODE : Ref GT,GOAL : GOALWD) =
Begin
CODE(NODE[gt_arg1],FULLWD);
If .NODE[rw_real_flow] Neq RFNONE Then
GENMOVE(.NODE[gt_arg1],.NODE[gt_reg]);
CHECKFORFLOW;
Return .NODE
End;
Routine GBNULL(NODE : Ref GT,GOAL : GOALWD) =
Begin
CODE(NODE[gt_arg1],FULLWD);
CODE(NODE[gt_arg2],FULLWD);
CHECKFORFLOW;
Return .NODE
End;
Routine GLOADNODE(NODE : Ref GT,GOAL : GOALWD) =
Begin
Macro
OFFSETLIT=GMA(MAKLIT(LOCALOFFSET(OPR))) %;
Local
X : ADRWD,
OPR : Ref GT;
CODE(NODE[gt_arg1],FULLWD);
OPR = .NODE[gt_arg1];
If .NODE[rw_real_flow] Eql RFNONE Then
Return .NODE;
If .NODE[rc_mov_target] Then
If .OPR Eql T_LITERAL Then
GENMOVE(.NODE[gt_arg1],.NODE[gt_reg])
Else If .OPR[gt_type] Eql S_NODE Then
GENMOVE(.NODE[gt_arg1],.NODE[gt_reg])
Else If Not(.OPR) Then
GENMOVE(.NODE[gt_arg1],.NODE[gt_reg])
Else If Not FORGOTTEN(.NODE,.NODE[gt_arg1]) Then
Begin
! WE HAVE AN ST ENTRY WITH THE IMMF BIT ON
X = GMA(.NODE[gt_reg]);
Select .OPR[gt_type] Of Set
[S_LOCAL]:
Begin
OPR = LOCDEF(.OPR);
flg_stack_addr = TRUE;
If LOCALOFFSET(OPR) Eql 0 And .X Neq PUSHED Then
EMIT(PMOV,STACKPTR,.X)
Else
Begin
EMIT(PMOV,OFFSETLIT,.X);
EMIT(PADD,STACKPTR,GMA(.NODE[gt_reg]))
End
End;
[S_FORMAL]:
Begin
EMIT(PMOV,(OFFSETLIT)+FLD_K_FORMAL,.X);
EMIT(PADD,STACKPTR,GMA(.NODE[gt_reg]))
End;
[Otherwise]:
EMIT(PMOV,GMA(.OPR),.X)
Tes
End;
If .NODE[rc_add_offset] Then
EMIT(PADD,GMOFF(.NODE),GMA(.NODE[gt_reg]));
If .NODE[rc_negate] Then
EMIT(PICK8(PNEG,.GOAL,.GOAL),GMA(.NODE[gt_reg]),0);
If .NODE[rc_complement] Then
EMIT(PICK8(PCOM,.GOAL,.GOAL),GMA(.NODE[gt_reg]),0);
CHECKFORFLOW;
If .GOAL Eql GOALS(0,8) Then
If .NODE[rc_negate] Or .NODE[rc_complement] Then
Return SETNEWPS(.NODE,0,8);
Return .NODE
End;
Routine GREL(NODE : Ref GT,GOAL : GOALWD) =
Begin
Local
L : Ref CELL;
CODE(NODE[gt_arg1],FULLWD);
CODE(NODE[gt_arg2],FULLWD);
If .NODE[rw_flow] Then
Begin
SETNOPUSHVT;
ADJUSTSTACK
End;
Case .NODE[rw_real_flow] From 0 To 3 Of Set
[RFNONE]:
0;
[RFREAL]:
Begin
EMIT(PCLR,GMA(.NODE[gt_reg]),0);
L = GENLABEL();
GENCOMPARE(.NODE[gt_arg1],.NODE[gt_arg2],.NODE[gt_code],0,.L,.NODE[gt_v_tpath]);
EMIT(PINC,GMA(.NODE[gt_reg]),0);
PLACELABEL(.L)
End;
[RFFLOW]:
GENCOMPARE(.NODE[gt_arg1], .NODE[gt_arg2], .NODE[gt_code],
NODELABEL(.NODE[gt_lab_t]), NODELABEL(.NODE[gt_lab_f]),
.NODE[gt_v_tpath]);
[RFBOTH]:
Begin
EMIT(PCLR,GMA(.NODE[gt_reg]),0);
GENCOMPARE(.NODE[gt_arg1],.NODE[gt_arg2],.NODE[gt_code],0,
NODELABEL(.NODE[gt_lab_f]),.NODE[gt_v_tpath]);
EMIT(PINC,GMA(.NODE[gt_reg]),0);
EMIT(PBR,NODELABEL(.NODE[gt_lab_t]),0)
End
Tes;
If .NODE[rw_flow] Then
RESETPUSHVT;
Return .NODE
End;
Routine GBIT(NODE : Ref GT,GOAL : GOALWD) =
Begin
Local
L : Ref CELL;
CODE(NODE[gt_arg1],FULLWD);
CODE(NODE[gt_arg2],FULLWD);
If .NODE[rw_flow] Then
Begin
SETNOPUSHVT;
ADJUSTSTACK
End;
Case .NODE[rw_real_flow] From 0 To 3 Of Set
[RFNONE]:
0;
[RFREAL]:
Begin
EMIT(PCLR,GMA(.NODE[gt_reg]),0);
L = GENLABEL();
BITX(.NODE[gt_arg1],.NODE[gt_arg2],Not .NODE[rw_complemented],.L);
EMIT(PINC,GMA(.NODE[gt_reg]),0);
PLACELABEL(.L)
End;
[RFFLOW]:
Begin
BITX(.NODE[gt_arg1],.NODE[gt_arg2],.NODE[rw_complemented],NODELABEL(.NODE[gt_lab_t]));
EMIT(PBR,NODELABEL(.NODE[gt_lab_f]),0)
End;
[RFBOTH]:
Begin
EMIT(PCLR,GMA(.NODE[gt_reg]),0);
BITX(.NODE[gt_arg1],.NODE[gt_arg2],Not .NODE[rw_complemented],
NODELABEL(.NODE[gt_lab_f]));
EMIT(PINC,GMA(.NODE[gt_reg]),0);
EMIT(PBR,NODELABEL(.NODE[gt_lab_t]),0)
End
Tes;
If .NODE[rw_flow] Then
RESETPUSHVT;
Return .NODE
End;
Literal
XNT = 0, ! MOVE NON-TARGET TO DISTINCT TEMPORARY
CN = 1, ! COMPLEMENT NON-TARGET
CT = 2, ! COMPLEMENT TEMP
CX = 3, ! COMPLEMENT X (COPY OF NON-TARGET)
BISNT = 4, ! BIS NON-TARGET TO TARGET
BISXT = 5, ! BIS X TO TARGET
BISTX = 6, ! BIS TARGET TO X
BICNT = 7, ! BIC NON-TARGET TO TARGET
BICXT = 8, ! BIC X TO TARGET
BICTX = 9; ! BIC TARGET TO X
Routine GBOOL(NODE : Ref GT,GOAL : GOALWD,OPS : Ref Vector,FILL : Boolean) =
Begin
Local
NT : Ref GT,
XNT2 : Ref GT,
T : Ref GT,
X : Ref GT,
RPOS : Integer,
RSIZ : Integer,
TPOS : Integer,
TSIZ : Integer;
CODE(NODE[gt_arg1],.GOAL);
CODE(NODE[gt_arg2],.GOAL);
If Not(.NODE[rw_real]) Then
Return .NODE;
PICKTARGET(T,NT);
XNT2 = .NT;
If .NODE[rc_mov_target] Then
SIMPLEMOVE(.T,.NODE[gt_reg]);
! YES, THIS CAN HAPPEN, E.G. ' #340 AND Not .X '
! IN WHICH THE TARGET SUBNODE WILL BE THE ' #340 '.
If ISLIT(.T) Then
Begin
TPOS = 0;
TSIZ = 16
End
Else
Begin
TPOS = .T[gt_pos];
TSIZ = .T[gt_len]
End;
If ISLIT(.NT) Then
Begin
RPOS = Min(.GOAL,.TPOS);
RSIZ = .GOAL;
If .RPOS Lss .TPOS Then
SHIFT(.NODE[gt_reg],.TPOS,.RPOS,Min(.TSIZ,.RSIZ));
If .TSIZ Lss .RSIZ Then
ISOLATE(.NODE[gt_reg],.RPOS,.TSIZ);
XNT2 = MAKLIT(CLITVALUE(.NT)^.RPOS)
End
Else
Begin
If (.TPOS-.GOAL)*(.NT[gt_pos]-.GOAL) Lss 0 Then
RPOS = .GOAL
Else If Abs(.TPOS-.GOAL) Lss Abs(.NT[gt_pos]-.GOAL) Then
RPOS = .TPOS
Else
RPOS = .NT[gt_pos];
RSIZ = Min(.GOAL,Max(.TSIZ,.NT[gt_len]));
If .TPOS Neq .RPOS Then
SHIFT(.NODE[gt_reg],.TPOS,.RPOS,Min(.TSIZ,.RSIZ));
If .TSIZ Lss .RSIZ Then
ISOLATE(.NODE[gt_reg],.RPOS,.TSIZ);
If .NT[gt_pos] Neq .RPOS Then
Begin
XNT2 = MAKEDESTROYABLE(.XNT2);
SHIFT(.XNT2,.NT[gt_pos],.RPOS,Min(.NT[gt_len],.RSIZ))
End;
If Not .NODE[rc_mov_target] Then
If (.RPOS Or (.RSIZ Mod 8)) Neq 0 Then
Begin
XNT2 = MAKEDESTROYABLE(.XNT2);
ISOLATE(.XNT2,.RPOS,.RSIZ)
End;
If .NT[gt_len] Lss .RSIZ Then
Begin
XNT2 = MAKEDESTROYABLE(.XNT2);
ISOLATE(.XNT2,.RPOS,.NT[gt_len])
End
End;
X = 0;
Incr I From 0 To .OPS[-1]-1 Do
Case .OPS[.I] From 0 To 9 Of Set
[XNT]:
Begin
X = VERYTEMP(0);
GENMOVE(.XNT2,.X)
End;
[CN]:
If ISLIT(.XNT2) Then
XNT2 = MAKLIT(Not CLITVALUE(.XNT2))
Else
Begin
XNT2 = MAKEDESTROYABLE(.XNT2);
EMIT(PCOM,GMA(.XNT2),0)
End;
[CT]:
EMIT(PICK8(PCOM,.RPOS,.RSIZ),GMA(.NODE[gt_reg]),0);
[CX]:
EMIT(PCOM,GMA(.X),0);
[BISNT]:
EMIT(PICK8(PBIS,.RPOS,.RSIZ),GMA(.XNT2),GMA(.NODE[gt_reg]));
[BISXT]:
EMIT(PBIS,GMA(.X),GMA(.NODE[gt_reg]));
[BISTX]:
EMIT(PBIS,GMA(.NODE[gt_reg]),GMA(.X));
[BICNT]:
EMIT(PICK8(PBIC,.RPOS,.RSIZ),GMA(.XNT2),GMA(.NODE[gt_reg]));
[BICXT]:
EMIT(PBIC,GMA(.X),GMA(.NODE[gt_reg]));
[BICTX]:
EMIT(PBIC,GMA(.NODE[gt_reg]),GMA(.X))
Tes;
SHIFT(.NODE[gt_reg],.RPOS,.GOAL,.RSIZ);
If .GOAL Gtr .RSIZ Then
Begin
RPOS = .GOAL+.RSIZ;
RSIZ = .GOAL-.RSIZ;
If .FILL Then
EMIT(PICK8(PBIS,.RPOS,.RSIZ),
GMA(MAKLIT(MASK(.RPOS,.RSIZ,0))),
GMA(.NODE[gt_reg]))
Else
CLEARFIELD(.NODE[gt_reg],.RPOS,.RSIZ)
End;
CHECKFORFLOW;
Return SETNEWPS(.NODE,.GOAL,.GOAL)
End;
Macro PICKCASE=
(If .NODE[gt_v_tpath]
Then .O1*2+.O2
Else .O2*2+.O1) %;
Routine GAND(NODE : Ref GT,GOAL : GOALWD) =
Begin
Bind
O1=NODE[gt_arg1] : Ref GT,
O2=NODE[gt_arg2] : Ref GT;
Bind
OPS = Plit(
Plit(CN,BICNT),
Plit(CN,BISNT,CT),
Plit(BICNT),
Plit(BISNT,CT)) : Vector;
Return GBOOL(.NODE,.GOAL,.OPS[PICKCASE],0)
End;
Routine GOR(NODE : Ref GT,GOAL : GOALWD) =
Begin
Bind
O1=NODE[gt_arg1] : Ref GT,
O2=NODE[gt_arg2] : Ref GT;
Bind
OPS=Plit(
Plit(BISNT),
Plit(CT,BISNT),
Plit(CN,BISNT),
Plit(CN,BICNT,CT) ) : Vector;
Return GBOOL(.NODE,.GOAL,.OPS[PICKCASE],0)
End;
Routine XEFLOW(LOP : Ref GT,ROP : Ref GT,TLAB,FLAB) : Novalue =
Begin
Local
VT : Ref GT,
RPOS : Integer;
SETNOPUSHVT;
RPOS = .ROP[gt_pos];
If (.RPOS+.ROP[gt_len] Leq 8) And (Not ISREG(.ROP)) Then
Begin
VT = VERYTEMP(.ROP[gt_reg]);
SIMPLEMOVE(.ROP,.VT);
ROP = .VT
End;
VT = POSITIONIT(.LOP,.LOP[gt_pos],.RPOS,1);
CLEARFIELD(.VT,0,.RPOS);
EMIT(PADD,GMA(.ROP),GMA(.VT));
GENBITTEST(.VT,.RPOS,NODELABEL(.FLAB));
EMIT(PBR,NODELABEL(.TLAB),0);
RESETPUSHVT
End;
Routine GXOR(NODE : Ref GT,GOAL : GOALWD) =
Begin
Bind
O1=NODE[gt_arg1] : Ref GT,
O2=NODE[gt_arg2] : Ref GT;
Bind
OPS=Plit(
Plit(XNT,BICTX,BICNT,BISXT),
Plit(XNT,BICTX,BICNT,BISXT,CT),
Plit(XNT,BICTX,BICNT,BISXT,CT),
Plit(XNT,BICTX,BICNT,BISXT) ) : Vector;
If .NODE[rw_real_flow] Neq RFFLOW Then
Return GBOOL(.NODE,.GOAL,.OPS[PICKCASE],0)
Else
Begin
CODE(O1,FULLWD);
CODE(O2,FULLWD);
ADJUSTSTACK;
XEFLOW(.O1,.O2,.NODE[gt_lab_t],.NODE[gt_lab_f]);
Return .NODE
End
End;
Routine GEQV(NODE : Ref GT,GOAL : GOALWD) =
Begin
Bind
O1=NODE[gt_arg1] : Ref GT,
O2=NODE[gt_arg2] : Ref GT;
Bind
OPS=Plit(
Plit(XNT,BICTX,BICNT,BISXT,CT),
Plit(XNT,BICTX,BICNT,BISXT),
Plit(XNT,BICTX,BICNT,BISXT),
Plit(XNT,BICTX,BICNT,BISXT,CT)) : Vector;
If .NODE[rw_real_flow] Neq RFFLOW Then
Return GBOOL(.NODE,.GOAL,.OPS[PICKCASE],1)
Else
Begin
CODE(O1,FULLWD);
CODE(O2,FULLWD);
ADJUSTSTACK;
XEFLOW(.O1,.O2,.NODE[gt_lab_f],.NODE[gt_lab_t]);
Return .NODE
End
End;
Routine GSHIFT(NODE : Ref GT,GOAL : GOALWD) =
Begin
Local
T : Ref ST,
LAB : Ref CELL,
NT : Ref GT,
S : Integer,
AS : Integer,
OP : Integer,
T1 : Ref GT,
GT1 : ADRWD,
CHP : Boolean,
GMD : Boolean,
MSK : Integer;
CODE(NODE[gt_arg1],FULLWD);
CODE(NODE[gt_arg2],FULLWD);
If .NODE[rw_real_flow] Eql RFNONE Then
Return .NODE;
PICKTARGET(T,NT);
If Not ISLIT(.NT) Then
PUNT(777);
GMD = FALSE;
S = CLITVALUE(.NT);
If .T Leq PF016 Then
MSK = 0
Else
Begin
S = Min(16,.S-.T[gt_pos]);
MSK = (Not MASK(.T[gt_pos],.T[gt_len],0)) ^ .S
End;
OP = (If .S Lss 0 Then PASR Else PASL);
AS = Abs(.S);
CHP = FALSE;
If .AS Leq 2 Or ISCHEAP(.NODE[gt_reg]) Then
Begin
T1 = .NODE[gt_reg];
CHP = TRUE
End
Else
Begin
T1 = VERYTMPREG();
If .T1 Eql 0 Then
T1 = .NODE[gt_reg]
Else
CHP = TRUE
End;
If .S Geq 13 Then
Begin
AS = 17-.S;
SIMPLEMOVE(.T,.T1);
GT1 = GMA(.T1);
While (AS = .AS-1) Geq 0 Do
EMIT(PROR,.GT1,0);
CLEARMASK(.T1,.MASKS[.S] Or .MSK);
GENMOVE(.T1,.NODE[gt_reg]);
CHECKFORFLOW;
Return .NODE
End;
If .S Eql 7 Then
Begin
SIMPLEMOVE(.T,.T1);
GT1 = GMA(.T1);
EMIT(PSWAB,.GT1,0);
EMIT(PRORB,.GT1,0);
EMIT(PROR,.GT1,0);
CLEARMASK(.T1,127 Or .MSK);
GENMOVE(.T1,.NODE[gt_reg]);
CHECKFORFLOW;
Return .NODE
End;
If .S Geq 8 Then
Begin
SIMPLEMOVE(.T,.T1);
GT1 = GMA(.T1);
GMD = TRUE;
EMIT(PSWAB,.GT1,0);
AS = .AS-8;
If (.MSK And Not (255^.AS)) Eql 0 Then
EMIT(PCLRB,.GT1,0)
Else
MSK = .MSK Or 255^.AS
End;
If (.S Leq -7) Or (Not .CHP) Then
If ISREG(.T1) And .S Leq -8 Then
Begin
SIMPLEMOVE(.T,.T1);
GT1 = GMA(.T1);
GMD = TRUE;
EMIT(PSWAB,.GT1,0);
If .MSK Eql 0 Then
EMIT(PMOVB,.GT1,.GT1);
AS = .AS-8
End
Else If .AS Geq 4 Then
Begin
If .T1 Eql .NODE[gt_reg] Then
T1 = VERYTEMP(0);
SIMPLEMOVE(.T,.NODE[gt_reg]);
EMIT(PMOV,GMA(MAKLIT(.AS)),GMA(.T1));
LAB = GENLABEL();
PLACELABEL(.LAB);
EMIT(.OP,GMA(.NODE[gt_reg]),0);
EMIT(PDEC,GMA(.T1),0);
EMIT(PBNE,.LAB,0);
CLEARMASK(.NODE[gt_reg],.MSK);
CHECKFORFLOW;
Return .NODE
End;
If Not .GMD Then
Begin
SIMPLEMOVE(.T,.T1);
GT1 = GMA(.T1)
End;
While (AS = .AS-1) Geq 0 Do
EMIT(.OP,.GT1,0);
CLEARMASK(.T1,.MSK);
! FOR DISTRIBUTED MULTIPLICATION THAT DIDN'T MAKE IT.
If .NODE[rc_add_offset] Then
EMIT(PADD,GMOFF(.NODE),GMA(.T1));
GENMOVE(.T1,.NODE[gt_reg]);
CHECKFORFLOW;
Return .NODE
End;
Routine GROT(NODE : Ref GT,GOAL : GOALWD) =
Begin
Local
S : Integer,
NT : Ref GT,
T : Ref GT,
OP : Integer;
CODE(NODE[gt_arg1],FULLWD);
PICKTARGET(T,NT);
GENMOVE(.T,.NODE[gt_reg]);
If ISLIT(.NT) Then
Begin
S = CLITVALUE(.NT);
If .S<15,1> Then
S = (.S+17) And %x'ffff';
If .S Leq 8 Then
OP = PROL
Else
Begin
OP = PROR;
S = 17-.S
End;
While (S = .S-1) Geq 0 Do
EMIT(.OP,GMA(.NODE[gt_reg]),0);
CHECKFORFLOW
End
Else
PUNT(777);
Return .NODE
End;
Routine GMAXMIN(NODE : Ref GT,GOAL : GOALWD) =
Begin
Local
T : Ref GT,
N : Ref GT,
L : Ref CELL,
RELOP : Integer;
CODE(NODE[gt_arg1],FULLWD);
CODE(NODE[gt_arg2],FULLWD);
If .NODE[rw_real_flow] Eql RFNONE Then
Return .NODE;
PICKTARGET(T,N);
RELOP = (If .NODE[gt_code] Eql OP_MIN Then OP_GTR Else OP_LSS);
GENMOVE(.T,.NODE[gt_reg]);
L = GENLABEL();
GENCOMPARE(.NODE[gt_reg],.N,.RELOP,0,.L,0);
GENMOVE(.N,.NODE[gt_reg]);
PLACELABEL(.L);
CHECKFORFLOW;
Return .NODE
End;
Routine GSWAB(NODE : Ref GT,GOAL : GOALWD) =
Begin
CODE(NODE[gt_arg1],FULLWD);
GENMOVE(.NODE[gt_arg1],.NODE[gt_reg]);
EMIT(PSWAB,GMA(.NODE[gt_reg]),0);
CHECKFORFLOW;
Return .NODE
End;
Routine GCASE(NODE : Ref GT,GOAL : GOALWD) =
Begin
Local
SDTD : Integer,
T : Ref GT,
L : Ref Vector,
LX : Ref CELL,
LE : Ref CELL,
LSG : Ref CELL,
CC : Ref CELL;
STOPFREE(.NODE[gt_arg1],.NODE[LASTOPERAND]);
CODELST(.NODE[gt_arg1]);
CODE(NODE[gt_arg2],FULLWD);
SDTD = .DYTEMPS;
T = .NODE[gt_arg2];
LE = GENLABEL();
LX = GENLABEL();
If .swit_i_d Then
LSG = GENLABEL();
CC = NEWCODECELL();
If ISREG(.T) Then
PUTCODE(.CC,UNUSED,PADD,
INDEXEDBY(.T,REFLABEL(.LE,.CC,UNUSED),OPND_LABEL),PROGCTR)
Else
Begin
PUTCODE(.CC,UNUSED,PADD,IMMLAB(.LE,.CC,UNUSED),GMA(.T));
EMIT(PADD,DEFER(GMA(.T)),PROGCTR)
End;
If .swit_i_d Then
Begin
PLACELABEL(.LSG);
EMIT(PWORD,GMA(MAKLIT(0)),0)
End;
PLACELABEL(.LE);
If .swit_i_d Then
LE = .LSG;
L = GETSPACE(.NODE[gt_argc]);
Incr I From 2 To .NODE[gt_argc]-2 Do
Begin
L[.I] = GENLABEL();
EMIT(PCASE,.L[.I],.LE)
End;
Incr I From 2 To .NODE[gt_argc]-2 Do
Begin
PLACELABEL(.L[.I]);
DYTEMPS = .SDTD;
CODE(NODE[gt_argv(.I)],FULLWD);
If .NODE[rw_real] Then
Begin
SETNOPUSHVT;
GENMOVE(.NODE[gt_argv(.I)],.NODE[gt_reg]);
RESETPUSHVT
End;
EMIT(PBR,.LX,0)
End;
PLACELABEL(.LX);
CODELST(.NODE[LASTOPERAND]);
RELEASESPACE(.L,.NODE[gt_argc]);
STARTFREE(.NODE[gt_arg1],.NODE[LASTOPERAND]);
CHECKFORFLOW;
Return .NODE
End;
Macro POPENABLE=(If Not .swit_hydra
Then EMIT(PMOV,ALOCAL(.K),GMA(.LXSIGR))
Else EMIT(PMOV,ALOCAL(.K+2),GMA(.LXSIGR))) %;
! GET RID OF ELSE PART AFTER HYDRA PEOPLE RECOMPILE
Routine GCOMPOUND(NODE : Ref GT,GOAL : GOALWD) =
Begin
Incr I From 0 To .NODE[gt_argc]-1 Do
CODE(NODE[gt_argv(.I)],FULLWD);
If .NODE[gt_v_enable] Then
If Not .swit_hydra Then
EMIT(PMOV,DEFER(GMA(.LXSIGR)),GMA(.LXSIGR))
Else
Begin ! TEMPORARY UNTIL HYDRA PEOPLE RECOMPILE
Local V;
V = VERYTEMP(0);
GENMOVE(.LXSIGR,.V);
If ISREG(.V) Then
EMIT(PMOV,INDEXEDBY(.V,2,OPND_NORMAL),GMA(.LXSIGR))
Else
Begin
EMIT(PADD,GMA(MAKLIT(2)),GMA(.V));
EMIT(PMOV,DEFER(GMA(.V)),GMA(.LXSIGR))
End
End;
CHECKFORFLOW;
Return .NODE
End;
Routine GCALL(NODE : Ref GT,GOAL : GOALWD) =
Begin
Local
LNK : Ref GT,
S : Ref GT;
SETNODYNVT;
SETNOPUSHVT;
Incr I From 1 To .NODE[gt_argc]-1 Do
CODE(NODE[gt_argv(.I)],FULLWD);
LNK = .NODE[gt_arg1];
Case .LNK[st_lnk_type] From LO_LNK_TYPE To HI_LNK_TYPE Of Set
[LNK_SPECIAL]:
Begin
S = .NODE[gt_arg2];
Selectone .S Of Set
[.LXHALT]:
EMIT(PHALT,0,0);
[.LXRESET]:
EMIT(PRESETX,0,0);
[.LXWAIT]:
EMIT(PWAIT,0,0);
[.LXNOP]:
EMIT(PNOP,0,0);
[.LEXEXCHJ]:
Begin
LEXEXCHJ[st_v_listed_external] = TRUE;
EMIT(PJSR,PROGCTR,GMA(.LEXEXCHJ))
End
Tes
End;
[LNK_BLISS]:
Begin
EMIT(PJSR,PROGCTR,GMA(.NODE[gt_arg2]));
If .NODE[gt_disp_16] Neq 0 Then ! FOR DIST MULTIPLICATION.
EMIT(PADD,GMOFF(.NODE),GMA(.NODE))
End;
[LNK_EMT]:
EMIT(PEMT,BUILDOPD(OPND_TRAP,UNUSED,UNUSED,CLITVALUE(.NODE[gt_arg2])),0);
[LNK_FORTRAN]:
0; ! Not CODED YET
[LNK_INTERRUPT]:
0;
[LNK_TRAP]:
EMIT(PTRAP,BUILDOPD(OPND_TRAP,UNUSED,UNUSED,CLITVALUE(.NODE[gt_arg2])),0);
[LNK_IOT]:
EMIT(PIOT,0,0);
[LNK_HYDRA]:
Begin
LXHLNK[st_v_listed_external] = TRUE;
LXHLTB[st_v_listed_external] = TRUE;
EMIT(PJSR,XREG(5),GMA(.LXHLNK));
EMIT(PWORD,GMA(.NODE[gt_arg2]),1);
EMIT(PWORD,GMA(.LXHLTB),1)
End;
[LNK_IHYDRA]:
Begin
LXIHLNK[st_v_listed_external] = TRUE;
GENMOVE(.NODE[gt_arg2],.RR0);
EMIT(PJSR,PROGCTR,GMA(.LXIHLNK))
End
Tes;
CHECKFORFLOW;
RESETPUSHVT;
RESETDYNVT;
Return .NODE
End;
Routine GIF(NODE : Ref GT,GOAL : GOALWD) =
Begin
Macro
GENTHEN=.T<0,1> %,
GENELSE=.T<1,1> %;
Local
SDTD : Integer,
L : Ref CELL,
T : Integer;
Bind
THENPART=NODE[gt_arg3] : Ref GT,
ELSEPART=NODE[gt_arg4] : Ref GT;
STOPFREE(.NODE[gt_arg1],.NODE[gt_arg5]);
CODELST(.NODE[gt_arg1]);
CODE(NODE[gt_arg2],FULLWD);
If ISLIT(.NODE[gt_arg2]) Then
If CLITVALUE(.NODE[gt_arg2]) Then
T = 1
Else
T = 2
Else
T = 3;
If GENTHEN Then
Begin
SDTD = .DYTEMPS;
CODE(THENPART,FULLWD);
If .NODE[rw_real] Then
Begin
SETNOPUSHVT;
GENMOVE(.THENPART,.NODE[gt_reg]);
RESETPUSHVT
End;
L = GENLABEL();
EMIT(PBR,.L,0);
DYTEMPS = .SDTD;
End
Else
PLACELABEL(NODELABEL(.THENPART));
If GENELSE Then
Begin
CODE(ELSEPART,FULLWD);
If .NODE[rw_real] Then
Begin
SETNOPUSHVT;
GENMOVE(.ELSEPART,.NODE[gt_reg]);
RESETPUSHVT
End;
End
Else
PLACELABEL(NODELABEL(.ELSEPART));
If GENTHEN Then
PLACELABEL(.L);
CODELST(.NODE[gt_arg5]);
STARTFREE(.NODE[gt_arg1],.NODE[gt_arg5]);
CHECKFORFLOW;
Return .NODE
End;
Routine GSELECT(NODE : Ref GT,GOAL : GOALWD) =
Begin
Local
TN : Ref GT,
FO : Integer,
L : Ref CELL,
SVLON : Integer,
SVFON : Integer;
Label
aaa;
Macro
THISOP=NODE[gt_argv(.I)] %;
TN = .NODE[gt_argv(.NODE[gt_argc]-2)] And %x'7fffffff';
FO = CLITVALUE(.NODE[LASTOPERAND]);
CODE(NODE[gt_arg1],FULLWD);
If .NODE[rw_real_flow] Neq RFNONE Then
If Not .NODE[rc_otherwise] Then
EMIT(PMOV,GMA(MAKLIT(-1)),GMA(.NODE[gt_reg]));
If .FO Neq 0 Then
EMIT(PCLR,GMA(.TN),0);
Incr I From 1 To .NODE[gt_argc]-4 By 2 Do
aaa: Begin
L = GENLABEL();
If .THISOP Eql LEXOTHERWISE Then
Begin
If .I Gtr .FO Then
Leave aaa;
EMIT(PTST,GMA(.TN),0);
EMIT(PBGT,.L,0);
End
Else If .THISOP Neq LEXALWAYS Then
Begin
CODE(THISOP,FULLWD);
SVLON = .LON;
SVFON = .FON;
If .(THISOP) Eql T_NODE Then
Begin
LON = .GT[.THISOP,gt_lon];
FON = .GT[.THISOP,gt_fon]
End;
GENCOMPARE(.NODE[gt_arg1],.THISOP,OP_EQL,0,.L,0);
LON = .SVLON;
FON = .SVFON
End;
CODE(NODE[gt_argv(.I+1)],FULLWD);
If .NODE[rw_real_flow] Neq RFNONE Then
Begin
SETNOPUSHVT;
GENMOVE(.NODE[gt_argv(.I+1)],.NODE[gt_reg]);
RESETPUSHVT
End;
If .I Lss .FO Then
EMIT(PADD,GMA(MAKLIT(1)),GMA(.TN));
PLACELABEL(.L)
End;
CHECKFORFLOW;
Return .NODE
End;
Routine GMOVP(NODE : Ref GT,GOAL : GOALWD) =
Begin
Local
L : Ref GT;
CODE(NODE[gt_arg1],FULLWD);
L = .NODE[gt_arg2];
EMIT(PMFPI+.L,GMA(.NODE[gt_arg1]),0);
CHECKFORFLOW;
Return .NODE
End;
Routine GSIGNAL(NODE : Ref GT,GOAL : GOALWD ) =
Begin
CODE(NODE[gt_arg1],FULLWD);
GENMOVE(.NODE[gt_arg1],.NODE[gt_reg]);
If .SIGLAB Eql 0 Then
Begin
SIGLAB = GENLABEL();
PLACELABEL(.SIGLAB);
EMIT(PJMP,GMA(.LXSIGL),0)
End
Else
EMIT(PBR,.SIGLAB,0);
Return .NODE
End;
Routine GENABLE(NODE : Ref GT,GOAL : GOALWD) =
Begin
Local
N : Ref GT,
K : Ref GT,
L : Ref CELL,
CC : Ref CELL,
LEXIT : Ref CELL;
Label
aaa;
N = .NODE[gt_arg1];
K = .NODE[gt_arg2];
EMIT(PMOV,GMA(MAKLIT(XLO(.K)+6)),.NODE[gt_reg]);
EMIT(PJSR,PROGCTR,GMA(.LXENAB));
L = GENLABEL();
LEXIT = GENLABEL();
If Not .swit_i_d Then
EMIT(PCASE,.LEXIT,.L)
Else
Begin
CC = NEWCODECELL();
PUTCODE(.CC,UNUSED,PJMP,REFLABEL(.LEXIT,.CC,UNUSED),0);
REFLABEL(.L,.BRAK1,UNUSED)
End;
PLACELABEL(.L);
If .swit_debug Then
Begin
LXY612[st_v_listed_external] = TRUE;
EMIT(PJSR,PROGCTR,GMA(.LXY612))
End;
aaa: Begin
Incr I From 1 To .N[gt_argc]-4 By 2 Do
Begin
If .N[gt_argv(.I)] Eql LEXALWAYS Then
Begin
CODE(N[gt_argv(.I+1)],FULLWD);
Leave aaa
End;
CODE(N[gt_argv(.I)],FULLWD);
L = GENLABEL();
GENCOMPARE(.N[gt_argv(.I)],.LXSIGV,OP_EQL,0,.L,0);
CODE(N[gt_argv(.I+1)],FULLWD);
PLACELABEL(.L)
End;
EMIT(PJMP,GMA(.LXSIG1),0)
End;
PLACELABEL(.LEXIT);
Return .NODE
End;
Routine GLABEL(NODE : Ref GT,GOAL : GOALWD) =
Begin
Local
LAB : Ref ST;
LAB = .NODE[gt_arg2];
LAB[st_lab_cell] = 0;
CODE(NODE[gt_arg1],FULLWD);
If .NODE[rw_real_flow] Neq RFNONE Then
GENMOVE(.NODE[gt_arg1],.NODE[gt_reg]);
ADJUSTSTACK;
PLACELABEL(USERLABEL(.LAB));
CHECKFORFLOW;
Return .NODE
End;
Routine GLOOP(NODE : Ref GT,XBR : Integer) =
Begin
Local
L : Ref CELL;
Bind
tbl = Uplit Byte (4,7,7,7,4,7,6,7,6,7,6,6) : Vector[,Byte];
STOPFREE(.NODE[gt_arg1],.NODE[gt_arg2]);
XBR = .tbl[.XBR];
CODELST(.NODE[gt_arg1]);
CODELST(.NODE[gt_arg2]);
If .XBR<0,1> Then
Begin
L = GENLABEL();
PLACELABEL(.L)
End;
If .XBR<2,1> Then
CODE(NODE[gt_arg3],FULLWD);
If .XBR<1,1> Then
CODE(NODE[gt_arg4],FULLWD);
If .XBR<0,1> Then
EMIT(PBR,.L,0);
CODE(NODE[gt_arg5],FULLWD);
If .NODE[rw_real_flow] Neq RFNONE Then
EMIT(PMOV,GMA(MAKLIT(-1)),GMA(.NODE[gt_reg]));
STARTFREE(.NODE[gt_arg1],.NODE[gt_arg2]);
CHECKFORFLOW;
Return .NODE
End;
Macro
DLC(X)= (If ISLIT(X) Then (CLITVALUE(X) And 1) Else 2) %;
Routine GWD(NODE : Ref GT,GOAL : GOALWD) =
Begin
Return GLOOP(.NODE,0+DLC(.NODE[gt_arg3]))
End;
Routine GUD(NODE : Ref GT,GOAL : GOALWD) =
Begin
Return GLOOP(.NODE,3+DLC(.NODE[gt_arg3]))
End;
Routine GDW(NODE : Ref GT,GOAL : GOALWD) =
Begin
Return GLOOP(.NODE,6+DLC(.NODE[gt_arg4]))
End;
Routine GDU(NODE : Ref GT,GOAL : GOALWD) =
Begin
Return GLOOP(.NODE,9+DLC(.NODE[gt_arg4]))
End;
Routine GID(NODE : Ref GT,WHICH : Boolean) =
Begin
Macro
STDTST=
Begin
EMIT(PCMP,GMA(.NODE[gt_arg1]),GMA(.NODE[gt_arg3]));
EMIT(If .WHICH Then PBGE Else PBLE,.L1,0);
End %;
Local
L : Integer,
L1 : Ref CELL,
L2 : Ref CELL,
T : Boolean,
T2 : Integer,
T3 : Integer;
STOPFREE(.NODE[gt_arg5],.NODE[gt_arg6]);
L1 = GENLABEL();
L2 = GENLABEL();
T = 1;
CODE(NODE[gt_arg2],FULLWD);
CODE(NODE[gt_arg3],FULLWD);
CODE(NODE[gt_arg4],FULLWD);
CODELST(.NODE[gt_arg5]);
CODELST(.NODE[gt_arg6]);
GENMOVE(.NODE[gt_arg2],.NODE[gt_arg1]);
If CLITVALUE(.NODE[gt_arg3]) Eql 0 Then
EMIT(PTST,GMA(.NODE[gt_arg1]),0);
If ISLIT(.NODE[gt_arg2]) Then
If ISLIT(.NODE[gt_arg3]) Then
Begin
T2 = CLITVALUE(.NODE[gt_arg2]);
T3 = CLITVALUE(.NODE[gt_arg3]);
If .WHICH Then
(If .T2 Geq .T3 Then T = 0)
Else
(If .T2 Leq .T3 Then T = 0)
End;
If .T Then
EMIT(PBR,.L2,0);
PLACELABEL(.L1);
CODE(NODE[gt_arg7],FULLWD);
EMIT(If .WHICH Then PSUB Else PADD,GMA(.NODE[gt_arg4]),GMA(.NODE[gt_arg1]));
PLACELABEL(.L2);
If ISLIT(.NODE[gt_arg3]) Then
Begin
L = CLITVALUE(.NODE[gt_arg3]);
If Abs(.L)-.WHICH Eql %x'7fff' Then
EMIT(PBR,.L1,0)
Else If .L Eql 0 Then
EMIT(If .WHICH Then PBPL Else PBLE,.L1,0)
Else If .WHICH And .L Eql 1 Then
EMIT(PBGT,.L1,0)
Else If Not .WHICH And .L Eql -1 Then
EMIT(PBMI,.L1,0)
Else
STDTST
End
Else
STDTST;
If .NODE[rw_real_flow] Neq RFNONE Then
EMIT(PMOV,GMA(MAKLIT(-1)),GMA(.NODE[gt_reg]));
STARTFREE(.NODE[gt_arg5],.NODE[gt_arg6]);
CHECKFORFLOW;
Return .NODE
End;
Routine GINCR(NODE : Ref GT,GOAL : GOALWD) =
Begin
Return GID(.NODE,FALSE)
End;
Routine GDECR(NODE : Ref GT,GOAL : GOALWD) =
Begin
Return GID(.NODE,TRUE)
End;
Routine NOTEREGS(RNAME : Ref GT) : Novalue =
Begin
RNAME[st_var_reg_save] = (.REGSCHNGD And Not .RESERVED) And ((1^6)-1)
End;
Routine FIXFORMALS(N : Integer,CURS : Ref CELL,E : Ref CELL) =
Begin
Routine FF(A : Ref ST,N : Integer) : Novalue =
Begin
If .A[adr_name_type] Eql NAME_FORMAL Then
Begin
A[adr_name_type] = NAME_NORMAL;
A[adr_disp] = .A[adr_disp]+.N
End
End;
While (CURS = NXTCC(.CURS)) Neq .E Do
Case .OPERTYPE[.CURS[cel_code]] From LO_OPTYPE To HI_OPTYPE Of Set
[Inrange]:
0;
[OPTYPE_ONE]:
FF(CURS[cel_src],.N);
[OPTYPE_TWO]:
Begin
FF(CURS[cel_src],.N);
FF(CURS[cel_dst],.N)
End;
[OPTYPE_BR]:
FF(CURS[cel_src],.N);
[OPTYPE_JSR]:
FF(CURS[cel_dst],.N)
Tes
End;
Routine GBODY(NODE : Ref GT,GOAL : GOALWD) =
Begin
Local
RNAME : Ref GT,
LNKAGE : Ref GT,
BNCELL : Ref CELL,
ENCELL : Ref CELL,
BLOC : Integer,
ELOC : Integer,
LB : Integer,
NR : Integer,
LX : Ref CELL,
L : Ref LSTHDR,
I : Ref ITEM,
A : ADRWD,
B : ADRWD,
LNKTYPE : Integer,
HR : Integer,
LEX : Ref GT;
Own
INLINSAVPLIT : Vector[9] Initial(0,0,1,1,1,1,1,0,0),
SAVN : Vector[4] Initial(LXSAV2,LXSAV3,LXSAV4,LXSAV5);
Macro
POF2(X) =(((X) And -(X)) Eql (X)) %,
INLINSAV =(.swit_debug Or .swit_zip Or POF2(.RNAME[st_var_reg_save])) %;
LOC = 100;
BNCELL = .NCELL;
NR = 0;
RNAME = .NODE[gt_arg2];
LNKAGE = .RNAME[st_var_linkage];
LNKTYPE = .LNKAGE[st_lnk_type];
NODE[gt_label] = LX = GENLABEL();
If .RNAME[st_v_unique] Then
Begin
CODENAME[3] = .RNAME[st_unique];
CODENAME[2] = (If .RNAME[gt_type] Eql S_ROUTINE
Then .CODENAME[3]
Else -.CODENAME[3])
End;
CODENAME[0] = NT[.RNAME[st_name],nt_data];
CODENAME[4] = .RNAME;
! load up register parameters
I = L = .RNAME[st_var_reg_list];
Until (I = .I[itm_rlink]) Eqla .L Do
Begin
A = XREG(.I[itm_ldata(1)]);
B = GMA(.I[itm_rdata(1)]);
If .A Neq .B Then
EMIT(PMOV,.A,.B)
End;
! code the body of the routine
CODE(NODE[gt_arg1],FULLWD);
LB = .MAXLOCALS+.STATICSIZE+(.VTEMPS[stk_max]+1)*2;
NOTEREGS(.RNAME);
! if this routine produces a result
If .LNKTYPE Neq LNK_INTERRUPT Then
Begin
RNAME[st_var_reg_save] = .RNAME[st_var_reg_save] And (Not(1));
GENMOVE(.NODE[gt_arg1],.NODE[gt_reg])
End;
! place the label
If .DYTEMPS Neq 0 Then
EMIT(PADD,GMA(MAKLIT(.DYTEMPS)),STACKPTR);
PLACELABEL(.LX);
! release locals
If .LB Neq 0 Then
EMIT(PADD,GMA(MAKLIT(.LB)),STACKPTR);
NODE[gt_dtdelete] = .DYTEMPS;
! pop registers
If .INLINSAVPLIT[.LNKTYPE] Or INLINSAV Then
Begin
Decr I From 5 To 0 Do
If (.RNAME[st_var_reg_save] And 1^(.I)) Neq 0 Then
EMIT(PMOV,POPPED,XREG(.I))
End;
! generate return
Case .LNKTYPE From LO_LNK_TYPE To HI_LNK_TYPE Of Set
[LNK_SPECIAL]:
0;
[LNK_BLISS,LNK_HYDRA,LNK_IHYDRA]:
If Not .swit_debug Then
EMIT(PRTS,PROGCTR,0)
Else
Begin
LXX612[st_v_listed_external] = TRUE;
EMIT(PJMP,GMA(.LXX612),0)
End;
[LNK_EMT,LNK_INTERRUPT,LNK_TRAP,LNK_IOT]:
Begin
If .swit_debug Then
EMIT(PJSR,PROGCTR,GMA(.LXX612));
EMIT(PRTI,0,0)
End;
[LNK_FORTRAN]:
EMIT(PRTS,XREG(5),0)
Tes;
ENCELL = .NCELL;
ELOC = .LOC;
NCELL = .BNCELL;
LOC = 0;
! if debug, generate a call to the debugger
If .swit_debug Then
Begin
LXE612[st_v_listed_external] = TRUE;
EMIT(PJSR,PROGCTR,GMA(.LXE612))
End;
! if registers saved in-line, generate pushes of the registers
If .INLINSAVPLIT[.LNKTYPE] Or INLINSAV Then
Begin
Incr I From 0 To 5 Do
If (.RNAME[st_var_reg_save] And 1^(.I)) Neq 0 Then
Begin
NR = .NR+1;
EMIT(PMOV,XREG(.I),PUSHED)
End
End
Else
! not saved in-line. generate a call to the register save routine
Begin
HR = FIRSTONE(.RNAME[st_var_reg_save]);
NR = .HR+1;
LEX = .SAVN[.HR-2];
LEX[st_v_listed_external] = TRUE;
EMIT(PJSR,XREG(1),GMA(.LEX));
End;
! allocate locals
If .LB Neq 0 Then
EMIT(PSUB,GMA(MAKLIT(.LB)),STACKPTR);
NODE[gt_label] = 0;
NCELL = .ENCELL;
LOC = .ELOC;
NR = (.NR+.VTEMPS[stk_max]+1)*2;
FIXFORMALS(.NR,.BRAK1,.NCELL);
Return .NODE
End;
Routine GLEAVE(NODE : Ref GT,GOAL : GOALWD) =
Begin
Local
LAB : Ref GT,
LABNODE : Ref GT,
K : Integer,
L : Ref GT;
LAB = .NODE[gt_arg2];
LABNODE = .LAB[st_lab_node];
CODE(NODE[gt_arg1],FULLWD);
If .LABNODE[rw_real_flow] Neq RFNONE Then
GENMOVE(.NODE[gt_arg1],.LABNODE[gt_reg]);
If .DYTEMPS Neq .LABNODE[gt_dtdelete] Then
EMIT(PADD,GMA(MAKLIT(.DYTEMPS-.LABNODE[gt_dtdelete])),STACKPTR);
L = .NODE[gt_arg3];
K = .L;
If .K Neq 0 Then
POPENABLE;
EMIT(PBR,USERLABEL(.LAB),0);
Return .NODE
End;
Routine GRETURN(NODE : Ref GT,GOAL : GOALWD) =
Begin
Local
R : Ref GT,
K : Integer,
L : Ref GT;
R = .NODE[gt_arg2];
R = .R[st_retlab];
CODE(NODE[gt_arg1],FULLWD);
If .R[gt_reg] Neq 0 Then
GENMOVE(.NODE[gt_arg1],.R[gt_reg]);
If .DYTEMPS Neq 0 Then
EMIT(PADD,GMA(MAKLIT(.DYTEMPS)),STACKPTR);
L = .NODE[gt_arg3];
K = .L;
If .K Neq 0 Then
POPENABLE;
EMIT(PBR,.R[gt_label],0);
Return .NODE
End;
Routine GINLINE(NODE : Ref GT,GOAL : GOALWD) =
Begin
Bind
ILO=BUILDOPD(OPND_INLINE,0,0,0);
PUTCODE(NEWCODECELL(),INST_INLINE,0,.NODE[gt_arg1],ILO);
NCELL[cel_inl_comment] = .NODE[gt_v_inlinecom];
Return .NODE
End;
!!! THE FOLLOWING ARE THE DRIVERS FOR THE NODE-SPECIFIC GENERATORS
!!! ----------------------------------------------------------------
Bind
GENPLIT = Uplit Long (
GADD, ! +
GSWAB, ! SWAB
GBNULL, ! /
GDOT, ! .
GSUB, ! - (BINARY)
GBNULL, ! MOD
GBNULL, ! *
GDOT, ! - (UNARY)
GLOADNODE, ! + (UNARY)
GSHIFT, ! ^
GBIT, ! BIT
GREL, ! GTR
GREL, ! LEQ
GREL, ! LSS
GREL, ! GEQ
GREL, ! EQL
GREL, ! NEQ
GDOT, ! NOT,
GEQV, ! EQV
GAND, ! AND
GOR, ! OR
GXOR, ! XOR
GREL, ! GTRU
GREL, ! LEQU
GREL, ! LSSU
GREL, ! GEQU
GREL, ! EQLU
GREL, ! NEQU
GROT, ! ROT
GMAXMIN, ! MAX
GMAXMIN, ! MIN
PUNT, ! CARRY
PUNT, ! OVERFLOW
GSTORE, ! =
0, ! ERROR OPERATOR
GCASE, ! CASE
GNULL, ! CALL-STORE
GNULL, ! CALL-PARM
GWD, ! WHILE-DO
GUD, ! UNTIL-DO
GBODY, ! ROUTINE DEFN
GCOMPOUND, ! COMPOUND
GINCR, ! INCR
GDECR, ! DECR
GIF, ! IF
GDW, ! DO-WHILE
GDU, ! DO-UNTIL
0, ! CREATE
0, ! EXCHJ
GSELECT, ! SELECT
0, ! EXITLOOP
GLABEL, ! LABEL PLACEMENT
0, ! MODULE
0, ! PLIT
GCALL, ! CALL
GDOT, ! POINTER
0, ! [
GLEAVE, ! LEAVE
GRETURN, ! RETURN
GXNULL, ! NULL
GINLINE, ! INLINE
GENABLE, ! ENABLE
GSIGNAL, ! SIGNAL
GMOVP, ! MFPI, ETC.
0,0,0,0,0,0) : Vector[,Long];
Routine FREEUNDER(NODE : Ref GT,XLON) =
Begin
Local
L : Ref GT,
B : Boolean,
A : Ref GT;
Label
aaa;
If .PLSTCNT Gtr 0 Then
Return 0;
If .NODE Neq T_NODE Then
Return 0;
Decr I From .NODE[gt_argc]-1 To 0 Do
aaa: Begin
L = .NODE[gt_argv(.I)];
If .L Neq 0 Then
If .L Eql T_NODE Then
Begin
A = 0;
B = 0;
If .L[gt_code] Eql OP_STORE Then
Begin
A = .L[gt_reg];
B = (.A Neq 0)
End;
If .L[gt_code] Eql OP_LOAD_NODE Then
Begin
A = .L[gt_reg];
If .A Geq 8 Then
If .A[tn_request] Eql MEMREQDB And Not .A[tn_v_lit] Then
If .A[gt_reg] Geq 8 Then
B = (.GT[.A[gt_reg],gt_type] Eql S_NODE)
End;
If .B And .A[tn_lon_lu] Gequ .XLON Then
Return 0;
If FREEUNDER(.L,.XLON) Eql 0 Then
Leave aaa
Else
RELEASESPACE(.L,.L[gt_argc]+SZ_NODE)
End
Else If .L Geq LOWFLOLSTTYPE Then
RELLST(.L);
NODE[gt_argv(.I)] = 0
End
End;
Routine CODEWALK(NODE : Ref GT) : Novalue =
Begin
Local
N : Ref GT;
If Not .NODE[gt_v_coded] Then
Begin
N = FASTLEXOUT(T_NODE,.NODE[gt_csparent]);
If .N Eql .NODE Then
Return;
If .N[gt_v_coded] Then
Return;
If Not .N[gt_v_delayed] Then ! N IS A BOGUS NODE
UNBOGUS(N);
PULSECODE(.N,0)
End
End;
Routine CODE(PNODE : Ref Vector,GOAL : GOALWD) : Novalue =
Begin
Local
NODE : Ref GT,
SLON : Integer,
SFON : Integer,
SVTN : Ref GT,
NODE1 : Ref GT;
Label
aaa;
NODE = .PNODE[0];
If .NODE Neq T_NODE Then
Return;
If .NODE[gt_label] Neqa 0 Then
PLACELABEL(.NODE[gt_label])
Else If .NODE[gt_v_lab_req] Then
PLACELABEL(NODELABEL(.NODE));
If .NODE[gt_v_mustgencode] Then
If Not .NODE[gt_v_coded] Then
Begin
SLON = .LON;
SFON = .FON;
SVTN = .VTN;
LON = .NODE[gt_lon];
FON = .NODE[gt_fon];
VTN = .NODE;
PNODE[0] = NODE = Bliss(.GENPLIT[.NODE[gt_code]],.NODE,.GOAL);
ADJUSTSTACK;
LON = .SLON;
FON = .SFON;
VTN = .SVTN;
aaa: Begin
! if we are not the parent and the parent has been coded...
NODE1 = .NODE[gt_csparent];
If .NODE1 Neqa .NODE And .NODE1[gt_v_coded] Then
Leave aaa;
If Not ISCSECREATION(NODE1) Then
Leave aaa;
! mark all CSE uses as coded
Do
Begin
If Not (.NODE1[gt_v_delayed] And .NODE1[gt_v_mustgencode]) Then
NODE1[gt_v_coded] = TRUE
End
Until (NODE1 = .NODE1[gt_csthread]) Eqla 0
End;
NODE[gt_v_coded] = TRUE
End
Else
CHECKFORFLOW
Else
Begin
CODEWALK(.NODE);
CHECKFORFLOW
End;
Selectone .NODE[gt_code] Of Set
[OP_STORE]:
If .NODE[gt_reg] Eqla 0 Then
FREEUNDER(.NODE,.NODE[gt_lon]);
[OP_LOAD_NODE,OP_DOT,OP_COMPOUND]:
0;
[Otherwise]:
FREEUNDER(.NODE,.NODE[gt_lon])
Tes
End;
Global Routine CODEDRIVER(LEX : Ref GT) : Novalue =
Begin
Local
ENCELL : Ref CELL,
T : Integer;
CODENAME[0] = .MODNAME;
CODENAME[2] = 0;
CODENAME[3] = 0;
CODENAME[4] = 0;
DYTEMPS = 0;
LOC = 0;
SAMETOG = FALSE;
SIGLAB = 0;
flg_stack_addr = FALSE;
VTEMPS = GETSPACE(10);
VTEMPS[stk_idx] = -1;
VTEMPS[stk_max] = -1;
BRAK1 = NEWCODECELL();
BRAK1[cel_class] = INST_INLINE;
NCELL = .BRAK1;
NLHEAD = NEWLABCELL(0,0);
PLSTCNT = 0;
NODVT = 0;
NOVTCNT = 0;
REGSCHNGD = (If .flg_enable Then %o'77' Else 0);
CODE(LEX,FULLWD);
PLSTCNT = 0;
If .LEX Eql T_NODE Then
FREEUNDER(.LEX,.LEX[gt_lon]);
VTN = .VTEMPS[stk_max]+1;
If .LEX Eql T_NODE Then
RELEASESPACE(.LEX,.LEX[gt_argc]+SZ_NODE);
If .swit_debug Then
LXHLTB[st_v_listed_external] = TRUE;
If .MODDONE Then
Begin
ENCELL = .NCELL;
NCELL = .BRAK1;
T = .MAXLOCALS+.STATICSIZE+.VTN*2;
If .T Neq 0 Then
EMIT(PSUB,GMA(MAKLIT(.T)),STACKPTR);
If .MAINDECL And .swit_debug Then
Begin
LXINT612[st_v_listed_external] = TRUE;
EMIT(PJSR,PROGCTR,GMA(.LXINT612))
End;
NCELL = .ENCELL
End;
RELEASESPACE(.VTEMPS,10);
If .MODDONE And (.BRAK1 Neqa .NCELL Or .MAINDECL) Then
EMIT(PHALT,0,0);
BRAK2 = PUTCODE(NEWCODECELL(),INST_INLINE,0,0,0);
RELALLTNS() ! RELEASE ALL TNS
End;
End
Eludom