0,0 → 1,985 |
/* |
** Small-C Compiler -- Part 4 -- Back End. |
** Copyright 1982, 1983, 1985, 1988 J. E. Hendrix |
** Copyright 1998 H T Walheim |
** All rights reserved. |
*/ |
#include <stdio.h> |
#include "cc.h" |
|
/* #define DISOPT */ /* display optimizations values */ |
|
/*************************** externals ****************************/ |
|
extern char |
*cptr, *macn, *litq, *symtab, optimize, ssname[NAMESIZE]; |
|
extern int |
*stage, litlab, litptr, csp, output, oldseg, usexpr, |
*snext, *stail, *slast; |
|
|
/***************** optimizer command definitions ******************/ |
|
/* -- p-codes must not overlap these */ |
#define any 0x00FF /* matches any p-code */ |
#define _pop 0x00FE /* matches if corresponding POP2 exists */ |
#define pfree 0x00FD /* matches if pri register free */ |
#define sfree 0x00FC /* matches if sec register free */ |
#define comm 0x00FB /* matches if registers are commutative */ |
|
/* -- these digits are reserved for n */ |
#define go 0x0100 /* go n entries */ |
#define gc 0x0200 /* get code from n entries away */ |
#define gv 0x0300 /* get value from n entries away */ |
#define sum 0x0400 /* add value from nth entry away */ |
#define neg 0x0500 /* negate the value */ |
#define ife 0x0600 /* if value == n do commands to next 0 */ |
#define ifl 0x0700 /* if value < n do commands to next 0 */ |
#define swv 0x0800 /* swap value with value n entries away */ |
#define topop 0x0900 /* moves |code and current value to POP2 */ |
|
#define p1 0x0001 /* plus 1 */ |
#define p2 0x0002 /* plus 2 */ |
#define p3 0x0003 /* plus 3 */ |
#define p4 0x0004 /* plus 4 */ |
#define m1 0x00FF /* minus 1 */ |
#define m2 0x00FE /* minus 2 */ |
#define m3 0x00FD /* minus 3 */ |
#define m4 0x00FC /* minus 4 */ |
|
#define PRI 0030 /* primary register bits */ |
#define SEC 0003 /* secondary register bits */ |
#define USES 0011 /* use register contents */ |
#define ZAPS 0022 /* zap register contents */ |
#define PUSHES 0100 /* pushes onto the stack */ |
#define COMMUTES 0200 /* commutative p-code */ |
|
/******************** optimizer command lists *********************/ |
|
int |
seq00[] = {0,ADD12,MOVE21,0, /* ADD21 */ |
go|p1,ADD21,0}, |
|
seq01[] = {0,ADD1n,0, /* rINC1 or rDEC1 ? */ |
ifl|m2,0,ifl|0,rDEC1,neg,0,ifl|p3,rINC1,0,0}, |
|
seq02[] = {0,ADD2n,0, /* rINC2 or rDEC2 ? */ |
ifl|m2,0,ifl|0,rDEC2,neg,0,ifl|p3,rINC2,0,0}, |
|
seq03[] = {0,rDEC1,PUTbp1,rINC1,0, /* SUBbpn or DECbp */ |
go|p2,ife|p1,DECbp,0,SUBbpn,0}, |
|
seq04[] = {0,rDEC1,PUTwp1,rINC1,0, /* SUBwpn or DECwp */ |
go|p2,ife|p1,DECwp,0,SUBwpn,0}, |
|
seq05[] = {0,rDEC1,PUTbm1,rINC1,0, /* SUB_m_ COMMAn */ |
go|p1,SUB_m_,go|p1,COMMAn,go|m1,0}, |
|
seq06[] = {0,rDEC1,PUTwm1,rINC1,0, /* SUB_m_ COMMAn */ |
go|p1,SUB_m_,go|p1,COMMAn,go|m1,0}, |
|
seq07[] = {0,GETw1m,GETw2n,ADD12,MOVE21,GETb1p,0, /* GETw2m GETb1p */ |
go|p4,gv|m3,go|m1,GETw2m,gv|m3,0}, |
|
seq08[] = {0,GETw1m,GETw2n,ADD12,MOVE21,GETb1pu,0, /* GETw2m GETb1pu */ |
go|p4,gv|m3,go|m1,GETw2m,gv|m3,0}, |
|
seq09[] = {0,GETw1m,GETw2n,ADD12,MOVE21,GETw1p,0, /* GETw2m GETw1p */ |
go|p4,gv|m3,go|m1,GETw2m,gv|m3,0}, |
|
seq10[] = {0,GETw1m,GETw2m,SWAP12,0, /* GETw2m GETw1m */ |
go|p2,GETw1m,gv|m1,go|m1,gv|m1,0}, |
|
seq11[] = {0,GETw1m,MOVE21,0, /* GETw2m */ |
go|p1,GETw2m,gv|m1,0}, |
|
seq12[] = {0,GETw1m,PUSH1,pfree,0, /* PUSHm */ |
go|p1,PUSHm,gv|m1,0}, |
|
seq13[] = {0,GETw1n,PUTbm1,pfree,0, /* PUT_m_ COMMAn */ |
PUT_m_,go|p1,COMMAn,go|m1,swv|p1,0}, |
|
seq14[] = {0,GETw1n,PUTwm1,pfree,0, /* PUT_m_ COMMAn */ |
PUT_m_,go|p1,COMMAn,go|m1,swv|p1,0}, |
|
seq15[] = {0,GETw1p,PUSH1,pfree,0, /* PUSHp */ |
go|p1,PUSHp,gv|m1,0}, |
|
seq16[] = {0,GETw1s,GETw2n,ADD12,MOVE21,0, /* GETw2s ADD2n */ |
go|p3,ADD2n,gv|m2,go|m1,GETw2s,gv|m2,0}, |
|
seq17[] = {0,GETw1s,GETw2s,SWAP12,0, /* GETw2s GETw1s */ |
go|p2,GETw1s,gv|m1,go|m1,GETw2s,gv|m1,0}, |
|
seq18[] = {0,GETw1s,MOVE21,0, /* GETw2s */ |
go|p1,GETw2s,gv|m1,0}, |
|
seq19[] = {0,GETw2m,GETw1n,SWAP12,SUB12,0, /* GETw1m SUB1n */ |
go|p3,SUB1n,gv|m2,go|m1,GETw1m,gv|m2,0}, |
|
seq20[] = {0,GETw2n,ADD12,0, /* ADD1n */ |
go|p1,ADD1n,gv|m1,0}, |
|
seq21[] = {0,GETw2s,GETw1n,SWAP12,SUB12,0, /* GETw1s SUB1n */ |
go|p3,SUB1n,gv|m2,go|m1,GETw1s,gv|m2,0}, |
|
seq22[] = {0,rINC1,PUTbm1,rDEC1,0, /* ADDm_ COMMAn */ |
go|p1,ADDm_,go|p1,COMMAn,go|m1,0}, |
|
seq23[] = {0,rINC1,PUTwm1,rDEC1,0, /* ADDm_ COMMAn */ |
go|p1,ADDm_,go|p1,COMMAn,go|m1,0}, |
|
seq24[] = {0,rINC1,PUTbp1,rDEC1,0, /* ADDbpn or INCbp */ |
go|p2,ife|p1,INCbp,0,ADDbpn,0}, |
|
seq25[] = {0,rINC1,PUTwp1,rDEC1,0, /* ADDwpn or INCwp */ |
go|p2,ife|p1,INCwp,0,ADDwpn,0}, |
|
seq26[] = {0,MOVE21,GETw1n,SWAP12,SUB12,0, /* SUB1n */ |
go|p3,SUB1n,gv|m2,0}, |
|
seq27[] = {0,MOVE21,GETw1n,comm,0, /* GETw2n comm */ |
go|p1,GETw2n,0}, |
|
seq28[] = {0,POINT1m,GETw2n,ADD12,MOVE21,0, /* POINT2m_ PLUSn */ |
go|p3,PLUSn,gv|m2,go|m1,POINT2m_,gv|m2,0}, |
|
seq29[] = {0,POINT1m,MOVE21,pfree,0, /* POINT2m */ |
go|p1,POINT2m,gv|m1,0}, |
|
seq30[] = {0,POINT1m,PUSH1,pfree,_pop,0, /* ... POINT2m */ |
topop|POINT2m,go|p2,0}, |
|
seq31[] = {0,POINT1s,GETw2n,ADD12,MOVE21,0, /* POINT2s */ |
sum|p1,go|p3,POINT2s,gv|m3,0}, |
|
seq32[] = {0,POINT1s,PUSH1,MOVE21,0, /* POINT2s PUSH2 */ |
go|p1,POINT2s,gv|m1,go|p1,PUSH2,go|m1,0}, |
|
seq33[] = {0,POINT1s,PUSH1,pfree,_pop,0, /* ... POINT2s */ |
topop|POINT2s,go|p2,0}, |
|
seq34[] = {0,POINT1s,MOVE21,0, /* POINT2s */ |
go|p1,POINT2s,gv|m1,0}, |
|
seq35[] = {0,POINT2m,GETb1p,sfree,0, /* GETb1m */ |
go|p1,GETb1m,gv|m1,0}, |
|
seq36[] = {0,POINT2m,GETb1pu,sfree,0, /* GETb1mu */ |
go|p1,GETb1mu,gv|m1,0}, |
|
seq37[] = {0,POINT2m,GETw1p,sfree,0, /* GETw1m */ |
go|p1,GETw1m,gv|m1,0}, |
|
seq38[] = {0,POINT2m_,PLUSn,GETw1p,sfree,0, /* GETw1m_ PLUSn */ |
go|p2,gc|m1,gv|m1,go|m1,GETw1m_,gv|m1,0}, |
|
seq39[] = {0,POINT2s,GETb1p,sfree,0, /* GETb1s */ |
sum|p1,go|p1,GETb1s,gv|m1,0}, |
|
seq40[] = {0,POINT2s,GETb1pu,sfree,0, /* GETb1su */ |
sum|p1,go|p1,GETb1su,gv|m1,0}, |
|
seq41[] = {0,POINT2s,GETw1p,PUSH1,pfree,0, /* PUSHs */ |
sum|p1,go|p2,PUSHs,gv|m2,0}, |
|
seq42[] = {0,POINT2s,GETw1p,sfree,0, /* GETw1s */ |
sum|p1,go|p1,GETw1s,gv|m1,0}, |
|
seq43[] = {0,PUSH1,any,POP2,0, /* MOVE21 any */ |
go|p2,gc|m1,gv|m1,go|m1,MOVE21,0}, |
|
seq44[] = {0,PUSHm,_pop,0, /* ... GETw2m */ |
topop|GETw2m,go|p1,0}, |
|
seq45[] = {0,PUSHp,any,POP2,0, /* GETw2p ... */ |
go|p2,gc|m1,gv|m1,go|m1,GETw2p,gv|m1,0}, |
|
seq46[] = {0,PUSHs,_pop,0, /* ... GETw2s */ |
topop|GETw2s,go|p1,0}, |
|
seq47[] = {0,SUB1n,0, /* rDEC1 or rINC1 ? */ |
ifl|m2,0,ifl|0,rINC1,neg,0,ifl|p3,rDEC1,0,0}; |
|
#define HIGH_SEQ 47 |
int seq[HIGH_SEQ + 1]; |
setseq() { |
seq[ 0] = seq00; seq[ 1] = seq01; seq[ 2] = seq02; seq[ 3] = seq03; |
seq[ 4] = seq04; seq[ 5] = seq05; seq[ 6] = seq06; seq[ 7] = seq07; |
seq[ 8] = seq08; seq[ 9] = seq09; seq[10] = seq10; seq[11] = seq11; |
seq[12] = seq12; seq[13] = seq13; seq[14] = seq14; seq[15] = seq15; |
seq[16] = seq16; seq[17] = seq17; seq[18] = seq18; seq[19] = seq19; |
seq[20] = seq20; seq[21] = seq21; seq[22] = seq22; seq[23] = seq23; |
seq[24] = seq24; seq[25] = seq25; seq[26] = seq26; seq[27] = seq27; |
seq[28] = seq28; seq[29] = seq29; seq[30] = seq30; seq[31] = seq31; |
seq[32] = seq32; seq[33] = seq33; seq[34] = seq34; seq[35] = seq35; |
seq[36] = seq36; seq[37] = seq37; seq[38] = seq38; seq[39] = seq39; |
seq[40] = seq40; seq[41] = seq41; seq[42] = seq42; seq[43] = seq43; |
seq[44] = seq44; seq[45] = seq45; seq[46] = seq46; seq[47] = seq47; |
} |
|
/***************** assembly-code strings ******************/ |
|
int code[PCODES]; |
|
/* |
** First byte contains flag bits indicating: |
** the value in ax is needed (010) or zapped (020) |
** the value in bx is needed (001) or zapped (002) |
*/ |
setcodes() { |
setseq(); |
code[ADD12] = "\211ADD EAX,EBX\15\n"; |
code[ADD1n] = "\010?ADD EAX,<n>\15\n??"; |
code[ADD21] = "\211ADD EBX,EAX\15\n"; |
code[ADD2n] = "\010?ADD EBX,<n>\15\n??"; |
code[ADDbpn] = "\001ADD BYTE [EBX],<n>\15\n"; |
code[ADDwpn] = "\001ADD WORD [EBX],<n>\15\n"; |
code[ADDm_] = "\000ADD <m>"; |
code[ADDSP] = "\000?ADD ESP,<n>\15\n??"; |
code[AND12] = "\211AND EAX,EBX\15\n"; |
code[ANEG1] = "\010NEG EAX\15\n"; |
code[ARGCNTn] = "\000?MOV CL,<n>?XOR CL,CL?\15\n"; |
code[ASL12] = "\011MOV ECX,EAX\15\nMOV EAX,EBX\15\nSAL EAX,CL\15\n"; |
code[ASR12] = "\011MOV ECX,EAX\15\nMOV EAX,EBX\15\nSAR EAX,CL\15\n"; |
code[CALL1] = "\010CALL EAX\15\n"; |
code[CALLm] = "\020CALL <m>\15\n"; |
code[BYTE_] = "\000 DB "; |
code[BYTEn] = "\000 RESB <n>\15\n"; |
code[BYTEr0] = "\000 TIMES <n> DB 0\15\n"; |
code[COM1] = "\010NOT EAX\15\n"; |
code[COMMAn] = "\000,<n>\15\n"; |
code[DBL1] = "\010SHL EAX,1\15\n"; |
code[DBL2] = "\001SHL EBX,1\15\n"; |
code[DECbp] = "\001DEC BYTE [EBX]\15\n"; |
code[DECwp] = "\001DEC WORD [EBX]\15\n"; |
code[DIV12] = "\011CDQ\15\nIDIV EBX\15\n"; /* see gen() */ |
code[DIV12u] = "\011XOR EDX,EDX\15\nDIV EBX\15\n"; /* see gen() */ |
|
code[DWORD_] = "\000 DD "; |
code[DWORDn] = "\000 DD <n>\15\n"; |
code[DWORDr0] = "\000 TIMES <n> DD 0\15\n"; |
|
code[ENTER] = "\100PUSH EBP\15\nMOV EBP,ESP\15\n"; |
code[EQ10f] = "\010<g>OR EAX,EAX\15\nJE _<d>\15\nJMP _<n>\15\n_<d>:\15\n"; |
code[EQ12] = "\211CALL __eq\15\n"; |
code[GE10f] = "\010<g>OR EAX,EAX\15\nJGE _<d>\15\nJMP _<n>\15\n_<d>:\15\n"; |
code[GE12] = "\011CALL __ge\15\n"; |
code[GE12u] = "\011CALL __uge\15\n"; |
code[GETb1m] = "\020MOVSX EAX,BYTE [<m>]\15\n"; |
code[GETb1mu] = "\020MOVZX EAX,BYTE [<m>]\15\n"; |
code[GETb1p] = "\021MOVSX EAX,BYTE [EBX?<o>??]\15\n"; /* see gen() */ |
code[GETb1pu] = "\021MOVZX EAX,BYTE [EBX?<o>??]\15\n"; /* see gen() */ |
code[GETb1s] = "\020MOVSX EAX,BYTE [EBP<o>]\15\n"; |
code[GETb1su] = "\020MOVZX EAX,BYTE [EBP<o>]\15\n"; |
|
code[GETd1m] = "\020MOV EAX,[<m>]\15\n"; |
code[GETd1n] = "\020?MOV EAX,<n>?XOR EAX,EAX?\15\n"; |
code[GETd1p] = "\021MOV EAX, [EBX?<o>??]\15\n"; /* see gen() */ |
code[GETd2n] = "\002?MOV EBX,<n>?XOR EBX,EBX?\15\n"; |
|
code[GETw1m] = "\020MOVSX EAX,WORD [<m>]\15\n"; |
code[GETw1m_] = "\020MOVSX EAX,WORD [<m>]"; |
code[GETw1n] = "\020?MOV EAX,<n>?XOR EAX,EAX?\15\n"; |
code[GETw1p] = "\021MOVSX EAX, WORD [EBX?<o>??]\15\n"; /* see gen() */ |
code[GETw1s] = "\020MOVSX EAX, WORD [EBP<o>]\15\n"; |
code[GETw2m] = "\002MOVSX EBX,WORD <m>\15\n"; |
code[GETw2n] = "\002?MOV EBX,<n>?XOR EBX,EBX?\15\n"; |
code[GETw2p] = "\021MOVSX EBX,WORD [EBX?<o>??]\15\n"; |
code[GETw2s] = "\002MOVSX EBX,WORD [EBP<o>]\15\n"; |
code[GT10f] = "\010<g>OR EAX,EAX\15\nJG _<d>\15\nJMP _<n>\15\n_<d>:\15\n"; |
code[GT12] = "\010CALL __gt\15\n"; |
code[GT12u] = "\011CALL __ugt\15\n"; |
code[INCbp] = "\001INC BYTE [EBX]\15\n"; |
code[INCwp] = "\001INC WORD [EBX]\15\n"; |
code[WORD_] = "\000 DW "; |
code[WORDn] = "\000 RESW <n>\15\n"; |
code[WORDr0] = "\000 TIMES <n> DW 0\15\n"; |
code[JMPm] = "\000JMP _<n>\15\n"; |
code[LABm] = "\000_<n>:\15\n"; |
code[LE10f] = "\010<g>OR EAX,EAX\15\nJLE _<d>\15\nJMP _<n>\15\n_<d>:\15\n"; |
code[LE12] = "\011CALL __le\15\n"; |
code[LE12u] = "\011CALL __ule\15\n"; |
code[LNEG1] = "\010CALL __lneg\15\n"; |
code[LT10f] = "\010<g>OR EAX,EAX\15\nJL _<d>\15\nJMP _<n>\15\n_<d>:\15\n"; |
code[LT12] = "\011CALL __lt\15\n"; |
code[LT12u] = "\011CALL __ult\15\n"; |
code[MOD12] = "\011CDQ\15\nIDIV EBX\15\nMOV EAX,EDX\15\n"; /* see gen() */ |
code[MOD12u] = "\011XOR EDX,EDX\15\nDIV EBX\15\nMOV EAX,EDX\15\n"; /* see gen() */ |
code[MOVE21] = "\012MOV EBX,EAX\15\n"; |
code[MUL12] = "\211IMUL EBX\15\n"; |
code[MUL12u] = "\211MUL EBX\15\n"; |
code[NE10f] = "\010<g>OR EAX,EAX\15\nJNE _<d>\15\nJMP _<n>\15\n_<d>:\15\n"; |
code[NE12] = "\211CALL __ne\15\n"; |
code[NEARm] = "\000 DD _<n>\15\n"; |
code[OR12] = "\211OR EAX,EBX\15\n"; |
code[PLUSn] = "\000?+<n>??\15\n"; |
code[POINT1l] = "\020MOV EAX,_<l>+<n>\15\n"; |
code[POINT1m] = "\020MOV EAX,<m>\15\n"; |
code[POINT1s] = "\020LEA EAX,[EBP<o>]\15\n"; |
code[POINT2m] = "\002MOV EBX,<m>\15\n"; |
code[POINT2m_]= "\002MOV EBX,<m>"; |
code[POINT2s] = "\002LEA EBX,[EBP<o>]\15\n"; |
code[POP2] = "\002POP EBX\15\n"; |
code[PUSH1] = "\110PUSH EAX\15\n"; |
code[PUSH2] = "\101PUSH EBX\15\n"; |
code[PUSHm] = "\100PUSH <m>\15\n"; |
code[PUSHp] = "\100PUSH [EBX?<o>??]\15\n"; |
code[PUSHs] = "\100PUSH [EBP?<o>??]\15\n"; |
code[PUT_m_] = "\000MOV <m>"; |
code[PUTbm1] = "\010MOV BYTE [<m>],AL\15\n"; |
code[PUTbp1] = "\011MOV [EBX],AL\15\n"; |
code[PUTdm1] = "\010MOV DWORD [<m>],EAX\15\n"; |
code[PUTdp1] = "\011MOV [EBX],EAX\15\n"; |
code[PUTwm1] = "\010MOV WORD [<m>],AX\15\n"; |
code[PUTwp1] = "\011MOV [EBX],AX\15\n"; |
code[rDEC1] = "\010#DEC EAX\15\n#"; |
code[rDEC2] = "\010#DEC EBX\15\n#"; |
code[REFm] = "\000_<n>"; |
code[RETURN] = "\000?MOV ESP,EBP\15\n??POP EBP\15\nRET\15\n"; |
code[rINC1] = "\010#INC EAX\15\n#"; |
code[rINC2] = "\010#INC EBX\15\n#"; |
code[SUB_m_] = "\000SUB <m>"; |
code[SUB12] = "\011SUB EAX,EBX\15\n"; /* see gen() */ |
code[SUB1n] = "\010?SUB EAX,<n>\15\n??"; |
code[SUBbpn] = "\001SUB [EBX],<n>\15\n"; |
code[SUBwpn] = "\001SUB [EBX],<n>\15\n"; |
code[SWAP12] = "\011XCHG EAX,EBX\15\n"; |
code[SWAP1s] = "\012POP EBX\15\nXCHG EAX,EBX\15\nPUSH EBX\15\n"; |
code[SWITCH] = "\012CALL __switch\15\n"; |
code[XOR12] = "\211XOR EAX,EBX\15\n"; |
} |
|
/***************** code generation functions *****************/ |
|
/* |
** print all assembler info before any code is generated |
** and ensure that the segments appear in the correct order. |
*/ |
header() { |
/* outline(" .386"); |
outline(" .MODEL FLAT"); |
*/ toseg(CODESEG); |
|
/* - FASM |
outline("EXTERN __eq"); |
outline("EXTERN __ne"); |
outline("EXTERN __le"); |
outline("EXTERN __lt"); |
outline("EXTERN __ge"); |
outline("EXTERN __gt"); |
outline("EXTERN __ule"); |
outline("EXTERN __ult"); |
outline("EXTERN __uge"); |
outline("EXTERN __ugt"); |
outline("EXTERN __lneg"); |
outline("EXTERN __switch"); |
*/ |
|
/* outline("dw 0"); *//* force non-zero code pointers, word alignment */ |
toseg(DATASEG); |
/* outline("dw 0"); *//* force non-zero data pointers, word alignment */ |
} |
|
/* |
** print any assembler stuff needed at the end |
*/ |
trailer() { |
char *cp; |
cptr = STARTGLB; |
while(cptr < ENDGLB) { |
if(cptr[IDENT] == FUNCTION && cptr[CLASS] == AUTOEXT) |
external(cptr + NAME, 0, FUNCTION); |
cptr += SYMMAX; |
} |
/* |
if((cp = findglb("main")) && cp[CLASS]==STATIC) |
external("_main", 0, FUNCTION); |
*/ |
toseg(NULL); |
/* outline("END"); */ |
#ifdef DISOPT |
{ |
int i, *count; |
printf(";opt count\n"); |
for(i = -1; ++i <= HIGH_SEQ; ) { |
count = seq[i]; |
printf("; %2u %5u\n", i, *count); |
} |
} |
#endif |
} |
|
/* |
** remember where we are in the queue in case we have to back up. |
*/ |
setstage(before, start) int *before, *start; { |
if((*before = snext) == 0) |
snext = stage; |
*start = snext; |
} |
|
/* |
** generate code in staging buffer. |
*/ |
gen(pcode, value) |
int pcode, value; |
{ |
int newcsp; |
switch(pcode) |
{ |
case GETb1pu: |
case GETb1p: |
case GETw1p: |
case GETd1p: |
gen(MOVE21, 0); |
break; |
case SUB12: |
case MOD12: |
case MOD12u: |
case DIV12: |
case DIV12u: |
gen(SWAP12, 0); |
break; |
case PUSH1: |
#ifdef INT32 |
csp -= BPD; |
#else |
csp -= BPW; |
#endif |
break; |
case POP2: |
#ifdef INT32 |
csp += BPD; |
#else |
csp += BPW; |
#endif |
break; |
case ADDSP: |
case RETURN: |
newcsp = value; |
value -= csp; |
csp = newcsp; |
} |
if(snext == 0) |
{ |
outcode(pcode, value); |
return; |
} |
if(snext >= slast) |
{ |
error("staging buffer overflow"); |
return; |
} |
snext[0] = pcode; |
snext[1] = value; |
snext += 2; |
} |
|
/* |
** dump the contents of the queue. |
** If start = 0, throw away contents. |
** If before != 0, don't dump queue yet. |
*/ |
clearstage(before, start) |
int *before, *start; |
{ |
if(before) |
{ |
snext = before; |
return; |
} |
if(start) |
dumpstage(); |
snext = 0; |
} |
|
/* |
** dump the staging buffer |
*/ |
dumpstage() |
{ |
int i; |
stail = snext; |
snext = stage; |
while(snext < stail) |
{ |
if(optimize) |
{ |
restart: |
i = -1; |
while(++i <= HIGH_SEQ) |
if(peep(seq[i])) |
{ |
#ifdef DISOPT |
if(isatty(output)) |
fprintf(stderr, " optimized %2u\n", i); |
#endif |
goto restart; |
} |
} |
outcode(snext[0], snext[1]); |
snext += 2; |
} |
} |
|
/* |
** change to a new segment |
** may be called with NULL, CODESEG, or DATASEG |
** With NASM the section names are case-sensitive |
*/ |
toseg(newseg) |
int newseg; |
{ |
if(oldseg == newseg) |
return; |
/* if(oldseg == CODESEG) |
outline("_TEXT ENDS"); |
else if(oldseg == DATASEG) |
outline("_DATA ENDS"); <-- */ |
|
/* - FASM |
if(newseg == CODESEG) |
{ |
outline("SECTION .text"); |
} |
else if(newseg == DATASEG) |
outline("SECTION .data"); |
*/ |
oldseg = newseg; |
} |
|
/* |
** declare entry point |
*/ |
public(ident) int ident;{ |
if(ident == FUNCTION) |
toseg(CODESEG); |
else toseg(DATASEG); |
/* - FASM |
outstr("GLOBAL "); |
outname(ssname); |
*/ |
newline(); |
outname(ssname); |
if(ident == FUNCTION) { |
colon(); |
newline(); |
} |
} |
|
/* |
** declare external reference |
*/ |
external(name, size, ident) char *name; int size, ident; { |
if(ident == FUNCTION) |
toseg(CODESEG); |
else toseg(DATASEG); |
/* - FASM |
outstr("EXTERN "); |
outname(name); |
/# colon(); |
outsize(size, ident); <-- #/ |
newline(); |
*/ |
} |
|
/* |
** output the size of the object pointed to. |
*/ |
outsize(size, ident) int size, ident; |
{ |
/* why not size on FUNCTION and POINTER ? */ |
if (ident == FUNCTION) |
outstr("NEAR"); |
else if (ident == POINTER) |
outstr("DWORD"); |
else if(size == 1) |
outstr("BYTE"); |
else if(size == 2) |
outstr("WORD"); |
else |
outstr("DWORD"); |
} |
|
/* |
** point to following object(s) |
*/ |
point() { |
outline(" DW $+2"); |
} |
|
/* |
** dump the literal pool |
*/ |
dumplits(size) int size; |
{ |
int j, k; |
k = 0; |
while (k < litptr) |
{ |
if(size == 1) |
{ |
gen(BYTE_, NULL); |
} |
else if (size == 2) |
{ |
gen(WORD_, NULL); |
} |
else |
{ |
gen(DWORD_,NULL); |
} |
j = 10; |
while(j--) |
{ |
outdec(getint(litq + k, size)); |
k += size; |
if(j == 0 || k >= litptr) |
{ |
newline(); |
break; |
} |
fputc(',', output); |
} |
} |
} |
|
/* |
** dump zeroes for default initial values |
*/ |
dumpzero(size, count) |
int size, count; |
{ |
if(count > 0) |
{ |
if(size == 1) |
gen(BYTEr0, count); |
else if (size == 2) |
gen(WORDr0, count); |
else |
gen(DWORDr0, count); |
} |
} |
|
/******************** optimizer functions ***********************/ |
|
/* |
** Try to optimize sequence at snext in the staging buffer. |
*/ |
peep(seq) int *seq; { |
int *next, *count, *pop, n, skip, tmp, reply; |
char c; |
next = snext; |
count = seq++; |
while(*seq) { |
switch(*seq) { |
case any: if(next < stail) break; return (NO); |
case pfree: if(isfree(PRI, next)) break; return (NO); |
case sfree: if(isfree(SEC, next)) break; return (NO); |
case comm: if(*next & COMMUTES) break; return (NO); |
case _pop: if(pop = getpop(next)) break; return (NO); |
default: if(next >= stail || *next != *seq) return (NO); |
} |
next += 2; ++seq; |
} |
|
/****** have a match, now optimize it ******/ |
|
*count += 1; |
reply = skip = NO; |
while(*(++seq) || skip) { |
if(skip) { |
if(*seq == 0) skip = NO; |
continue; |
} |
if(*seq >= PCODES) { |
c = *seq & 0xFF; /* get low byte of command */ |
n = c; /* and sign extend into n */ |
switch(*seq & 0xFF00) { |
case ife: if(snext[1] != n) skip = YES; break; |
case ifl: if(snext[1] >= n) skip = YES; break; |
case go: snext += (n<<1); break; |
case gc: snext[0] = snext[(n<<1)]; goto done; |
case gv: snext[1] = snext[(n<<1)+1]; goto done; |
case sum: snext[1] += snext[(n<<1)+1]; goto done; |
case neg: snext[1] = -snext[1]; goto done; |
case topop: pop[0] = n; pop[1] = snext[1]; goto done; |
case swv: tmp = snext[1]; |
snext[1] = snext[(n<<1)+1]; |
snext[(n<<1)+1] = tmp; |
done: reply = YES; |
break; |
} |
} |
else snext[0] = *seq; /* set p-code */ |
} |
return (reply); |
} |
|
/* |
** Is the primary or secondary register free? |
** Is it zapped or unused by the p-code at pp |
** or a successor? If the primary register is |
** unused by it still may not be free if the |
** context uses the value of the expression. |
*/ |
isfree(reg, pp) int reg, *pp; { |
char *cp; |
while(pp < stail) { |
cp = code[*pp]; |
if(*cp & USES & reg) return (NO); |
if(*cp & ZAPS & reg) return (YES); |
pp += 2; |
} |
if(usexpr) return (reg & 001); /* PRI => NO, SEC => YES at end */ |
else return (YES); |
} |
|
/* |
** Get place where the currently pushed value is popped? |
** NOTE: Function arguments are not popped, they are |
** wasted with an ADDSP. |
*/ |
getpop(next) int *next; { |
char *cp; |
int level; level = 0; |
while(YES) { |
if(next >= stail) /* compiler error */ |
return 0; |
if(*next == POP2) |
if(level) --level; |
else return next; /* have a matching POP2 */ |
else if(*next == ADDSP) { /* after func call */ |
if((level -= (next[1]>>LBPW)) < 0) |
return 0; |
} |
else { |
cp = code[*next]; /* code string ptr */ |
if(*cp & PUSHES) ++level; /* must be a push */ |
} |
next += 2; |
} |
} |
|
/******************* output functions *********************/ |
|
colon() { |
fputc(':', output); |
} |
|
newline() { |
fputc('\15', output); |
fputc(NEWLINE, output); |
} |
|
/* |
** output assembly code. |
** |
*/ |
outcode(pcode, value) |
int pcode, value; |
{ |
int part, skip, count; |
int byte_opt; |
char *cp, *back; |
int loc_label; |
part = back = 0; |
skip = NO; |
byte_opt = 0; |
|
cp = code[pcode] + 1; /* skip 1st byte of code string */ |
|
#ifdef _MSC_VER |
|
switch (pcode) |
{ |
case BYTE_: |
case BYTEn: |
case BYTEr0: |
case WORD_: |
case WORDn: |
case WORDr0: |
case DWORD_: |
case DWORDn: |
case DWORDr0: |
case REFm: |
case COMMAn: |
case PLUSn: |
break; |
|
default: |
|
dump_debug (pcode, value); |
outtab (); |
} |
#endif |
|
if (pcode == ADD1n) |
{ |
if (value < 0) |
{ |
pcode = SUB1n; |
value = -value; |
} |
if (value < 128) |
{ |
byte_opt = 1; |
} |
} |
|
while(*cp) |
{ |
if(*cp == '<') |
{ |
++cp; /* skip to action code */ |
if(skip == NO) |
switch(*cp) |
{ |
case 'm': |
outname(value+NAME); |
break; /* mem ref by label */ |
case 'n': |
if (byte_opt) |
{ |
outstr ("BYTE "); |
} |
outdec(value); |
break; /* numeric constant */ |
case 'o': |
offset(value); |
break; /* numeric constant */ |
case 'l': |
outdec(litlab); |
break; /* current literal label */ |
case 'g': /* generate local label */ |
loc_label = getlabel (); |
break; |
case 'd': /* dump local label */ |
outdec(loc_label); |
break; |
} |
cp += 2; /* skip past > */ |
} |
else if(*cp == '?') /* ?..if value...?...if not value...? */ |
{ |
switch(++part) |
{ |
case 1: |
if(value == 0) |
skip = YES; |
break; |
case 2: |
skip = !skip; |
break; |
case 3: |
part = 0; |
skip = NO; |
break; |
} |
++cp; /* skip past ? */ |
} |
else if(*cp == '#') |
{ /* repeat #...# value times */ |
++cp; |
if(back == 0) |
{ |
if((count = value) < 1) |
{ |
while(*cp && *cp++ != '#') |
; |
continue; |
} |
back = cp; |
continue; |
} |
if(--count > 0) |
cp = back; |
else |
back = 0; |
} |
else if(skip == NO) |
fputc(*cp++, output); |
else |
++cp; |
} |
} |
|
outdec(number) int number; { |
int k, zs; |
char c, *q, *r; |
zs = 0; |
k = 1000000000; |
|
#ifdef _MSC_VER |
// fprintf(output, "/* %d */", number); |
#endif |
|
if(number < 0) { |
number = -number; |
fputc('-', output); |
} |
|
while (k >= 1) { |
q = 0; |
r = number; |
while(r >= k) {++q; r = r - k;} |
c = q + '0'; |
if(c != '0' || k == 1 || zs) { |
zs = 1; |
fputc(c, output); |
} |
number = r; |
k /= 10; |
} |
} |
|
offset(number) |
int number; |
{ |
int k, zs; |
char c, *q, *r; |
zs = 0; |
k = 1000000000; |
if(number < 0) { |
number = -number; |
fputc('-', output); |
} |
else |
{ |
fputc('+',output); |
} |
|
while (k >= 1) { |
q = 0; |
r = number; |
while(r >= k) {++q; r = r - k;} |
c = q + '0'; |
if(c != '0' || k == 1 || zs) { |
zs = 1; |
fputc(c, output); |
} |
number = r; |
k /= 10; |
} |
} |
|
outline(ptr) char ptr[]; { |
outstr(ptr); |
newline(); |
} |
|
outname(ptr) char ptr[]; { |
outstr("_"); |
while(*ptr >= ' ') fputc(*ptr++, output); |
} |
|
outstr(ptr) char ptr[]; { |
while(*ptr == '\t' || *ptr >= ' ') fputc(*ptr++, output); |
} |
|
outtab () |
{ |
fputc ('\t', output); |
} |