mirror of
https://github.com/dschmenk/PLASMA.git
synced 2025-08-08 09:25:19 +00:00
Modular optimizer
This commit is contained in:
@@ -53,6 +53,7 @@ FIBER = FIBER\#FE1000
|
|||||||
LONGJMP = LONGJMP\#FE1000
|
LONGJMP = LONGJMP\#FE1000
|
||||||
PLASM = plasm
|
PLASM = plasm
|
||||||
PLASMAPLASM = PLASM\#FE1000
|
PLASMAPLASM = PLASM\#FE1000
|
||||||
|
CODEOPT = CODEOPT\#FE1000
|
||||||
INCS = toolsrc/plasm.h toolsrc/tokens.h toolsrc/symbols.h toolsrc/lex.h toolsrc/parse.h toolsrc/codegen.h
|
INCS = toolsrc/plasm.h toolsrc/tokens.h toolsrc/symbols.h toolsrc/lex.h toolsrc/parse.h toolsrc/codegen.h
|
||||||
OBJS = toolsrc/plasm.c toolsrc/parse.c toolsrc/lex.c toolsrc/codegen.c
|
OBJS = toolsrc/plasm.c toolsrc/parse.c toolsrc/lex.c toolsrc/codegen.c
|
||||||
#
|
#
|
||||||
@@ -71,7 +72,7 @@ TXTTYPE = .TXT
|
|||||||
#SYSTYPE = \#FF2000
|
#SYSTYPE = \#FF2000
|
||||||
#TXTTYPE = \#040000
|
#TXTTYPE = \#040000
|
||||||
|
|
||||||
all: $(PLASM) $(PLVM) $(PLVM01) $(PLVM02) $(PLVM802) $(PLVM03) $(CMD) $(PLASMAPLASM) $(ARGS) $(MEMMGR) $(MEMTEST) $(FIBER) $(LONGJMP) $(ED) $(MON) $(ROD) $(SIEVE) $(UTHERNET2) $(UTHERNET) $(ETHERIP) $(INET) $(DHCP) $(HTTPD) $(ROGUE) $(ROGUEMAP) $(ROGUECOMBAT) $(ROGUEIO) $(HGR1) $(TONE) $(DGR) $(DGRTEST) $(FILEIO) $(CONIO) $(PORTIO) $(SPIPORT) $(SDFAT) $(FATCAT) $(FATGET) $(FATPUT) $(FATWDSK) $(FATRDSK) $(SANE) $(FPSTR) $(FPU) $(SANITY) $(RPNCALC)
|
all: $(PLASM) $(PLVM) $(PLVM01) $(PLVM02) $(PLVM802) $(PLVM03) $(CMD) $(PLASMAPLASM) $(CODEOPT) $(ARGS) $(MEMMGR) $(MEMTEST) $(FIBER) $(LONGJMP) $(ED) $(MON) $(ROD) $(SIEVE) $(UTHERNET2) $(UTHERNET) $(ETHERIP) $(INET) $(DHCP) $(HTTPD) $(ROGUE) $(ROGUEMAP) $(ROGUECOMBAT) $(ROGUEIO) $(HGR1) $(TONE) $(DGR) $(DGRTEST) $(FILEIO) $(CONIO) $(PORTIO) $(SPIPORT) $(SDFAT) $(FATCAT) $(FATGET) $(FATPUT) $(FATWDSK) $(FATRDSK) $(SANE) $(FPSTR) $(FPU) $(SANITY) $(RPNCALC)
|
||||||
|
|
||||||
clean:
|
clean:
|
||||||
-rm *FE1000 *FF2000 $(PLASM) $(PLVM) $(PLVM01) $(PLVM02) $(PLVM03)
|
-rm *FE1000 *FF2000 $(PLASM) $(PLVM) $(PLVM01) $(PLVM02) $(PLVM03)
|
||||||
@@ -85,10 +86,14 @@ clean:
|
|||||||
$(PLASM): $(OBJS) $(INCS)
|
$(PLASM): $(OBJS) $(INCS)
|
||||||
cc $(OBJS) -o $(PLASM)
|
cc $(OBJS) -o $(PLASM)
|
||||||
|
|
||||||
$(PLASMAPLASM): toolsrc/plasm.pla toolsrc/lex.pla toolsrc/parse.pla toolsrc/codegen.pla
|
$(PLASMAPLASM): toolsrc/plasm.pla toolsrc/lex.pla toolsrc/parse.pla toolsrc/codegen.pla toolsrc/codeseq.plh
|
||||||
./$(PLASM) -AMOW < toolsrc/plasm.pla > toolsrc/plasm.a
|
./$(PLASM) -AMOW < toolsrc/plasm.pla > toolsrc/plasm.a
|
||||||
acme --setpc 4094 -o $(PLASMAPLASM) toolsrc/plasm.a
|
acme --setpc 4094 -o $(PLASMAPLASM) toolsrc/plasm.a
|
||||||
|
|
||||||
|
$(CODEOPT): toolsrc/codeopt.pla toolsrc/codeseq.plh
|
||||||
|
./$(PLASM) -AMOW < toolsrc/codeopt.pla > toolsrc/codeopt.a
|
||||||
|
acme --setpc 4094 -o $(CODEOPT) toolsrc/codeopt.a
|
||||||
|
|
||||||
#
|
#
|
||||||
# PLASMA VMs
|
# PLASMA VMs
|
||||||
#
|
#
|
||||||
|
@@ -24,6 +24,51 @@
|
|||||||
// loop
|
// loop
|
||||||
//end
|
//end
|
||||||
//
|
//
|
||||||
|
// New/release sequence ops
|
||||||
|
//
|
||||||
|
def new_op
|
||||||
|
word op
|
||||||
|
op = freeop_lst
|
||||||
|
if not op
|
||||||
|
puts("Compiler out of sequence ops!")
|
||||||
|
return NULL
|
||||||
|
fin
|
||||||
|
freeop_lst = freeop_lst=>opnext
|
||||||
|
op=>opnext = NULL
|
||||||
|
return op
|
||||||
|
end
|
||||||
|
def release_op(op)#0
|
||||||
|
if op
|
||||||
|
op=>opnext = freeop_lst
|
||||||
|
freeop_lst = op
|
||||||
|
fin
|
||||||
|
end
|
||||||
|
def release_seq(seq)#0
|
||||||
|
word op
|
||||||
|
|
||||||
|
while seq
|
||||||
|
op = seq
|
||||||
|
seq = seq=>opnext
|
||||||
|
//
|
||||||
|
//Free this op
|
||||||
|
//
|
||||||
|
op=>opnext = freeop_lst
|
||||||
|
freeop_lst = op
|
||||||
|
loop
|
||||||
|
end
|
||||||
|
//
|
||||||
|
// Append one sequence to the end of another
|
||||||
|
//
|
||||||
|
def cat_seq(seq1, seq2)
|
||||||
|
word op
|
||||||
|
|
||||||
|
if not seq1; return seq2; fin
|
||||||
|
op = seq1
|
||||||
|
while op=>opnext; op = op=>opnext; loop
|
||||||
|
op=>opnext = seq2
|
||||||
|
return seq1
|
||||||
|
end
|
||||||
|
//
|
||||||
// Emit data/bytecode
|
// Emit data/bytecode
|
||||||
//
|
//
|
||||||
def emit_byte(bval)#0
|
def emit_byte(bval)#0
|
||||||
@@ -212,6 +257,141 @@ def emit_ctag(ctag)#0
|
|||||||
ctag_tbl=>[ctag] = (codeptr - codebuff) | IS_RESOLVED
|
ctag_tbl=>[ctag] = (codeptr - codebuff) | IS_RESOLVED
|
||||||
end
|
end
|
||||||
//
|
//
|
||||||
|
// Emit the pending sequence
|
||||||
|
//
|
||||||
|
def emit_pending_seq#0
|
||||||
|
word lcl_pending, op
|
||||||
|
//
|
||||||
|
// This is called by some of the emit_*() functions to ensure that any
|
||||||
|
// pending ops are emitted before they emit their own op when they are
|
||||||
|
// called from the parser. However, this function itself calls some of those
|
||||||
|
// emit_*() functions to emit instructions from the pending sequence, which
|
||||||
|
// would cause an infinite loop if we weren't careful. We therefore set
|
||||||
|
// pending_seq to null on entry and work with a local copy, so if this
|
||||||
|
// function calls back into itself it is a no-op.
|
||||||
|
//
|
||||||
|
if not pending_seq; return; fin
|
||||||
|
lcl_pending = pending_seq
|
||||||
|
pending_seq = NULL
|
||||||
|
if outflags & OPTIMIZE
|
||||||
|
while optimize_seq(@lcl_pending, 0); loop
|
||||||
|
if outflags & OPTIMIZE2
|
||||||
|
while optimize_seq(@lcl_pending, 1); loop
|
||||||
|
fin
|
||||||
|
fin
|
||||||
|
while lcl_pending
|
||||||
|
op = lcl_pending
|
||||||
|
when op->opgroup
|
||||||
|
//
|
||||||
|
// Constant value
|
||||||
|
//
|
||||||
|
is CONST_GROUP
|
||||||
|
if op=>opval == $0000 // ZERO
|
||||||
|
emit_byte($00)
|
||||||
|
elsif op=>opval & $FF00 == $0000 // Constant BYTE
|
||||||
|
emit_byte($2A)
|
||||||
|
emit_byte(op->opval)
|
||||||
|
elsif op=>opval & $FF00 == $FF00 // Constant $FF00 | BYTE
|
||||||
|
emit_byte($5E)
|
||||||
|
emit_byte(op->opval)
|
||||||
|
else // Constant WORD
|
||||||
|
emit_byte($2C)
|
||||||
|
emit_word(op=>opval)
|
||||||
|
fin
|
||||||
|
break
|
||||||
|
//
|
||||||
|
// Constant string
|
||||||
|
//
|
||||||
|
is CONSTR_GROUP
|
||||||
|
emit_byte($2E)
|
||||||
|
emit_data(0, STR_TYPE, op=>opval, 0)
|
||||||
|
break
|
||||||
|
//
|
||||||
|
// Single op codes
|
||||||
|
//
|
||||||
|
is STACK_GROUP
|
||||||
|
emit_byte(op->opcode)
|
||||||
|
break
|
||||||
|
//
|
||||||
|
// Local address codes
|
||||||
|
//
|
||||||
|
is LOCAL_GROUP
|
||||||
|
emit_byte(op->opcode)
|
||||||
|
emit_byte(op->opoffset)
|
||||||
|
break
|
||||||
|
//
|
||||||
|
// Global address codes
|
||||||
|
//
|
||||||
|
is GLOBAL_GROUP
|
||||||
|
if op=>optag & IS_CTAG and op=>opoffset
|
||||||
|
exit_err(ERR_INVAL|ERR_CODE|ERR_CONST)
|
||||||
|
else
|
||||||
|
emit_byte(op->opcode)
|
||||||
|
emit_addr(op=>optag+op=>opoffset)
|
||||||
|
fin
|
||||||
|
break
|
||||||
|
//
|
||||||
|
// Relative address codes
|
||||||
|
//
|
||||||
|
is RELATIVE_GROUP
|
||||||
|
emit_byte(op->opcode)
|
||||||
|
emit_reladdr(op=>optag)
|
||||||
|
break
|
||||||
|
//
|
||||||
|
// Code tags
|
||||||
|
//
|
||||||
|
is CODETAG_GROUP
|
||||||
|
emit_ctag(op=>optag)
|
||||||
|
break
|
||||||
|
otherwise
|
||||||
|
return
|
||||||
|
wend
|
||||||
|
lcl_pending = lcl_pending=>opnext;
|
||||||
|
//
|
||||||
|
// Free this op
|
||||||
|
//
|
||||||
|
op=>opnext = freeop_lst
|
||||||
|
freeop_lst = op
|
||||||
|
loop
|
||||||
|
end
|
||||||
|
//
|
||||||
|
// Emit a sequence of ops (into the pending sequence)
|
||||||
|
//
|
||||||
|
def emit_seq(seq)#0
|
||||||
|
word op
|
||||||
|
byte string
|
||||||
|
string = FALSE
|
||||||
|
op = seq
|
||||||
|
while op
|
||||||
|
if op->opgroup == CONSTR_GROUP; string = TRUE; break; fin
|
||||||
|
op = op=>opnext
|
||||||
|
loop
|
||||||
|
pending_seq = cat_seq(pending_seq, seq)
|
||||||
|
//
|
||||||
|
// The source code comments in the output are much more logical if we don't
|
||||||
|
// merge multiple sequences together. There's no value in doing this merging
|
||||||
|
// if we're not optimizing, and we optionally allow it to be prevented even
|
||||||
|
// when we are optimizing by specifing the -N (NO_COMBINE) flag.
|
||||||
|
//
|
||||||
|
// We must also force output if the sequence includes a CS opcode, as the
|
||||||
|
// associated 'constant' is only temporarily valid.
|
||||||
|
//
|
||||||
|
if not (outflags & (OPTIMIZE|OPTIMIZE2)) or (outflags & NO_COMBINE) or string
|
||||||
|
emit_pending_seq
|
||||||
|
fin
|
||||||
|
end
|
||||||
|
//
|
||||||
|
// Emit lambda function
|
||||||
|
//
|
||||||
|
def emit_lambdafunc(tag, namestr, cparms, lambda_seq)#0
|
||||||
|
emit_ctag(tag)
|
||||||
|
framesize = cparms * 2
|
||||||
|
emit_enter(cparms)
|
||||||
|
emit_seq(lambda_seq)
|
||||||
|
emit_pending_seq
|
||||||
|
emit_leave
|
||||||
|
end
|
||||||
|
//
|
||||||
// ID manager
|
// ID manager
|
||||||
//
|
//
|
||||||
def idmatch(nameptr, len, idptr, idcnt)
|
def idmatch(nameptr, len, idptr, idcnt)
|
||||||
@@ -367,503 +547,6 @@ def ctag_new
|
|||||||
return codetag | IS_CTAG
|
return codetag | IS_CTAG
|
||||||
end
|
end
|
||||||
//
|
//
|
||||||
// New/release sequence ops
|
|
||||||
//
|
|
||||||
def new_op
|
|
||||||
word op
|
|
||||||
op = freeop_lst
|
|
||||||
if not op
|
|
||||||
puts("Compiler out of sequence ops!")
|
|
||||||
return NULL
|
|
||||||
fin
|
|
||||||
freeop_lst = freeop_lst=>opnext
|
|
||||||
op=>opnext = NULL
|
|
||||||
return op
|
|
||||||
end
|
|
||||||
def release_op(op)#0
|
|
||||||
if op
|
|
||||||
op=>opnext = freeop_lst
|
|
||||||
freeop_lst = op
|
|
||||||
fin
|
|
||||||
end
|
|
||||||
def release_seq(seq)#0
|
|
||||||
word op
|
|
||||||
|
|
||||||
while seq
|
|
||||||
op = seq
|
|
||||||
seq = seq=>opnext
|
|
||||||
//
|
|
||||||
//Free this op
|
|
||||||
//
|
|
||||||
op=>opnext = freeop_lst
|
|
||||||
freeop_lst = op
|
|
||||||
loop
|
|
||||||
end
|
|
||||||
//
|
|
||||||
// Replace all but the first of a series of identical load opcodes by DUP. This
|
|
||||||
// doesn't reduce the number of opcodes but does reduce their size in bytes.
|
|
||||||
// This is only called on the second optimisation pass because the DUP opcodes
|
|
||||||
// may inhibit other peephole optimisations which are more valuable.
|
|
||||||
//
|
|
||||||
def try_dupify(op)
|
|
||||||
byte crunched
|
|
||||||
word nextop
|
|
||||||
|
|
||||||
crunched = FALSE
|
|
||||||
nextop = op=>opnext
|
|
||||||
while nextop
|
|
||||||
if op->opcode <> nextop->opcode; return crunched; fin
|
|
||||||
when op->opcode
|
|
||||||
is CONST_CODE
|
|
||||||
if op=>opval <> nextop=>opval; return crunched; fin
|
|
||||||
break
|
|
||||||
is LADDR_CODE
|
|
||||||
is LLB_CODE
|
|
||||||
is LLW_CODE
|
|
||||||
if op=>opoffset <> nextop=>opoffset; return crunched; fin
|
|
||||||
break
|
|
||||||
is GADDR_CODE
|
|
||||||
is LAB_CODE
|
|
||||||
is LAW_CODE
|
|
||||||
if (op=>optag <> nextop=>optag) or (op=>opoffset <> nextop=>opoffset); return crunched; fin
|
|
||||||
break
|
|
||||||
otherwise
|
|
||||||
return crunched
|
|
||||||
wend
|
|
||||||
nextop->opcode = DUP_CODE
|
|
||||||
nextop->opgroup = STACK_GROUP
|
|
||||||
nextop = nextop=>opnext
|
|
||||||
crunched = TRUE
|
|
||||||
loop
|
|
||||||
return crunched
|
|
||||||
end
|
|
||||||
def is_hardware_address(addr)
|
|
||||||
return isuge(addr, $C000) and isult(addr, $D000)
|
|
||||||
end
|
|
||||||
//
|
|
||||||
// Crunch sequence (peephole optimize)
|
|
||||||
//
|
|
||||||
def crunch_seq(seq, pass)
|
|
||||||
word nextop, nextopnext, opprev, op
|
|
||||||
byte crunched, freeops, shiftcnt
|
|
||||||
|
|
||||||
opprev = NULL
|
|
||||||
op = *seq
|
|
||||||
nextop = op=>opnext
|
|
||||||
crunched = FALSE
|
|
||||||
freeops = 0
|
|
||||||
while op and nextop
|
|
||||||
when op->opcode
|
|
||||||
is CONST_CODE
|
|
||||||
if op=>opval == 1
|
|
||||||
if nextop>opcode == ADD_CODE
|
|
||||||
op->opcode = INC_CODE
|
|
||||||
freeops = 1
|
|
||||||
break
|
|
||||||
fin
|
|
||||||
if nextop->opcode == SUB_CODE
|
|
||||||
op->opcode = DEC_CODE
|
|
||||||
freeops = 1
|
|
||||||
break
|
|
||||||
fin
|
|
||||||
if nextop->opcode == SHL_CODE
|
|
||||||
op->opcode = DUP_CODE
|
|
||||||
nextop->opcode = ADD_CODE
|
|
||||||
crunched = 1
|
|
||||||
break
|
|
||||||
fin
|
|
||||||
fin
|
|
||||||
when nextop->opcode
|
|
||||||
is NEG_CODE
|
|
||||||
op=>opval = -(op=>opval)
|
|
||||||
freeops = 1
|
|
||||||
break
|
|
||||||
is COMP_CODE
|
|
||||||
op=>opval = ~(op=>opval)
|
|
||||||
freeops = 1
|
|
||||||
break
|
|
||||||
is LOGIC_NOT_CODE
|
|
||||||
op=>opval = op=>opval ?? FALSE :: TRUE
|
|
||||||
freeops = 1
|
|
||||||
break
|
|
||||||
is LB_CODE // BPTR_CODE
|
|
||||||
op=>opoffset = op=>opval
|
|
||||||
op->opcode = LAB_CODE
|
|
||||||
op->opgroup = GLOBAL_GROUP
|
|
||||||
freeops = 1
|
|
||||||
break
|
|
||||||
is LW_CODE // WPTR_CODE
|
|
||||||
op=>opoffset = op=>opval
|
|
||||||
op->opcode = LAW_CODE
|
|
||||||
op->opgroup = LOCAL_GROUP
|
|
||||||
freeops = 1
|
|
||||||
break
|
|
||||||
is SB_CODE
|
|
||||||
op=>opoffset = op=>opval
|
|
||||||
op->opcode = SAB_CODE
|
|
||||||
op->opgroup = GLOBAL_GROUP
|
|
||||||
freeops = 1
|
|
||||||
break
|
|
||||||
is SW_CODE
|
|
||||||
op=>opoffset = op=>opval
|
|
||||||
op->opcode = SAW_CODE
|
|
||||||
op->opgroup = GLOBAL_GROUP
|
|
||||||
freeops = 1
|
|
||||||
break
|
|
||||||
is BRFALSE_CODE
|
|
||||||
if op=>opval
|
|
||||||
freeops = -2 // Remove constant and never taken branch
|
|
||||||
else
|
|
||||||
op->opcode = BRNCH_CODE // Always taken branch
|
|
||||||
op->opgroup = RELATIVE_GROUP
|
|
||||||
op=>optag = nextop=>optag
|
|
||||||
freeops = 1
|
|
||||||
fin
|
|
||||||
break
|
|
||||||
is BRTRUE_CODE
|
|
||||||
if not op=>opval
|
|
||||||
freeops = -2 // Remove constant never taken branch
|
|
||||||
else
|
|
||||||
op->opcode = BRNCH_CODE // Always taken branch
|
|
||||||
op->opgroup = RELATIVE_GROUP
|
|
||||||
op=>optag = nextop=>optag
|
|
||||||
freeops = 1
|
|
||||||
fin
|
|
||||||
break
|
|
||||||
is NE_CODE
|
|
||||||
if not op=>opval
|
|
||||||
freeops = -2 // Remove ZERO:ISNE
|
|
||||||
fin
|
|
||||||
break
|
|
||||||
is EQ_CODE
|
|
||||||
if not op=>opval
|
|
||||||
op->opcode = LOGIC_NOT_CODE
|
|
||||||
freeops = 1
|
|
||||||
fin
|
|
||||||
break
|
|
||||||
is CONST_CODE // Collapse constant operation
|
|
||||||
nextopnext = nextop->nextop
|
|
||||||
if nextopnext
|
|
||||||
when nextopnext->opcode
|
|
||||||
is MUL_CODE
|
|
||||||
op=>opval = op=>opval * nextop=>opval
|
|
||||||
freeops = 2
|
|
||||||
break
|
|
||||||
is DIV_CODE
|
|
||||||
op=>opval = op=>opval / nextop=>opval
|
|
||||||
freeops = 2
|
|
||||||
break
|
|
||||||
is MOD_CODE
|
|
||||||
op=>opval = op=>opval % nextop=>opval
|
|
||||||
freeops = 2
|
|
||||||
break
|
|
||||||
is ADD_CODE
|
|
||||||
op=>opval = op=>opval + nextop=>opval
|
|
||||||
freeops = 2
|
|
||||||
break
|
|
||||||
is SUB_CODE
|
|
||||||
op=>opval = op=>opval - nextop=>opval
|
|
||||||
freeops = 2
|
|
||||||
break
|
|
||||||
is SHL_CODE
|
|
||||||
op=>opval = op=>opval << nextop=>opval
|
|
||||||
freeops = 2
|
|
||||||
break
|
|
||||||
is SHR_CODE
|
|
||||||
op=>opval = op=>opval >> nextop=>opval
|
|
||||||
freeops = 2
|
|
||||||
break
|
|
||||||
is AND_CODE
|
|
||||||
op=>opval = op=>opval & nextop=>opval
|
|
||||||
freeops = 2
|
|
||||||
break
|
|
||||||
is OR_CODE
|
|
||||||
op=>opval = op=>opval | nextop=>opval
|
|
||||||
freeops = 2
|
|
||||||
break
|
|
||||||
is EOR_CODE
|
|
||||||
op=>opval = op=>opval ^ nextop=>opval
|
|
||||||
freeops = 2
|
|
||||||
break
|
|
||||||
is EQ_CODE
|
|
||||||
op=>opval = op=>opval == nextop=>opval
|
|
||||||
freeops = 2
|
|
||||||
break
|
|
||||||
is NE_CODE
|
|
||||||
op=>opval = op=>opval <> nextop=>opval
|
|
||||||
freeops = 2
|
|
||||||
break
|
|
||||||
is GE_CODE
|
|
||||||
op=>opval = op=>opval >= nextop=>opval
|
|
||||||
freeops = 2
|
|
||||||
break
|
|
||||||
is LT_CODE
|
|
||||||
op=>opval = op=>opval < nextop=>opval
|
|
||||||
freeops = 2
|
|
||||||
break
|
|
||||||
is GT_CODE
|
|
||||||
op=>opval = op=>opval > nextop=>opval
|
|
||||||
freeops = 2
|
|
||||||
break
|
|
||||||
is LE_CODE
|
|
||||||
op=>opval = op=>opval <= nextop=>opval
|
|
||||||
freeops = 2
|
|
||||||
break
|
|
||||||
is LOGIC_OR_CODE
|
|
||||||
op=>opval = op=>opval or nextop=>opval
|
|
||||||
freeops = 2
|
|
||||||
break
|
|
||||||
is LOGIC_AND_CODE
|
|
||||||
op=>opval = op=>opval and nextop=>opval
|
|
||||||
freeops = 2
|
|
||||||
break
|
|
||||||
wend // End of collapse constant operation
|
|
||||||
fin
|
|
||||||
if pass > 0 and freeops == 0 and op=>opval
|
|
||||||
crunched = try_dupify(op)
|
|
||||||
fin
|
|
||||||
break // CONST_CODE
|
|
||||||
is MUL_CODE
|
|
||||||
for shiftcnt = 0 to 15
|
|
||||||
if op=>opval == 1 << shiftcnt
|
|
||||||
op=>opval = shiftcnt
|
|
||||||
nextop->opcode = SHL_CODE
|
|
||||||
nextop->opgroup = STACK_GROUP
|
|
||||||
break
|
|
||||||
fin
|
|
||||||
next
|
|
||||||
break
|
|
||||||
is DIV_CODE
|
|
||||||
for shiftcnt = 0 to 15
|
|
||||||
if op=>opval == 1 << shiftcnt
|
|
||||||
op=>opval = shiftcnt
|
|
||||||
nextop->opcode = SHR_CODE
|
|
||||||
nextop->opcode = STACK_GROUP
|
|
||||||
break
|
|
||||||
fin
|
|
||||||
next
|
|
||||||
break
|
|
||||||
wend
|
|
||||||
break // CONST_CODE
|
|
||||||
is LADDR_CODE
|
|
||||||
when nextop->opcode
|
|
||||||
is CONST_CODE
|
|
||||||
if nextop=>opnext
|
|
||||||
nextopnext = nextop=>opnext
|
|
||||||
when nextopnext->opcode
|
|
||||||
is ADD_CODE
|
|
||||||
is INDEXB_CODE
|
|
||||||
op=>opoffset = op=>opoffset + nextop=>opval
|
|
||||||
freeops = 2
|
|
||||||
break
|
|
||||||
is INDEXW_CODE
|
|
||||||
op=>opoffset = op=>opoffset + nextop=>opval * 2
|
|
||||||
freeops = 2
|
|
||||||
break
|
|
||||||
wend
|
|
||||||
fin
|
|
||||||
break
|
|
||||||
is LB_CODE
|
|
||||||
op->opcode = LLB_CODE
|
|
||||||
op->opgroup = LOCAL_GROUP
|
|
||||||
freeops = 1
|
|
||||||
break
|
|
||||||
is LW_CODE
|
|
||||||
op->opcode = LLW_CODE
|
|
||||||
op->opgroup = LOCAL_GROUP
|
|
||||||
freeops = 1
|
|
||||||
break
|
|
||||||
is SB_CODE
|
|
||||||
op->opcode = SLB_CODE
|
|
||||||
op->opgroup = LOCAL_GROUP
|
|
||||||
freeops = 1
|
|
||||||
break
|
|
||||||
is SW_CODE
|
|
||||||
op->opcode = SLW_CODE
|
|
||||||
op->opgroup = LOCAL_GROUP
|
|
||||||
freeops = 1
|
|
||||||
break
|
|
||||||
wend
|
|
||||||
if pass > 0 and not freeops
|
|
||||||
crunched = try_dupify(op)
|
|
||||||
fin
|
|
||||||
break // LADDR_CODE
|
|
||||||
is GADDR_CODE
|
|
||||||
when nextop->opcode
|
|
||||||
is CONST_CODE
|
|
||||||
if nextop=>opnext
|
|
||||||
nextopnext = nextop=>opnext
|
|
||||||
when nextopnext->opcode
|
|
||||||
is ADD_CODE
|
|
||||||
is INDEXB_CODE
|
|
||||||
op=>opoffset = op=>opoffset + nextop=>opval
|
|
||||||
freeops = 2
|
|
||||||
break
|
|
||||||
is INDEXW_CODE
|
|
||||||
op=>opoffset = op=>opoffset + nextop=>opval * 2
|
|
||||||
freeops = 2
|
|
||||||
break
|
|
||||||
wend
|
|
||||||
fin
|
|
||||||
break
|
|
||||||
is LB_CODE
|
|
||||||
op->opcode = LAB_CODE
|
|
||||||
op->opgroup = GLOBAL_GROUP
|
|
||||||
freeops = 1
|
|
||||||
break
|
|
||||||
is LW_CODE
|
|
||||||
op->opcode = LAW_CODE
|
|
||||||
op->opgroup = GLOBAL_GROUP
|
|
||||||
freeops = 1
|
|
||||||
break
|
|
||||||
is SB_CODE
|
|
||||||
op->opcode = SAB_CODE
|
|
||||||
op->opgroup = GLOBAL_GROUP
|
|
||||||
freeops = 1
|
|
||||||
break
|
|
||||||
is SW_CODE
|
|
||||||
op->opcode = SAW_CODE
|
|
||||||
op->opgroup = GLOBAL_GROUP
|
|
||||||
freeops = 1
|
|
||||||
break
|
|
||||||
is ICAL_CODE
|
|
||||||
op->opcode = CALL_CODE
|
|
||||||
op->opgroup = GLOBAL_GROUP
|
|
||||||
freeops = 1
|
|
||||||
break
|
|
||||||
wend
|
|
||||||
if pass > 0 and not freeops
|
|
||||||
crunched = try_dupify(op)
|
|
||||||
fin
|
|
||||||
break // GADDR_CODE
|
|
||||||
is LLB_CODE
|
|
||||||
if pass > 0
|
|
||||||
crunched = try_dupify(op)
|
|
||||||
fin
|
|
||||||
break // LLB_CODE
|
|
||||||
is LLW_CODE
|
|
||||||
// LLW [n]:CB 8:SHR -> LLB [n+1]
|
|
||||||
if nextop->opcode == CONST_CODE and nextop=>opval == 8
|
|
||||||
if nextop=>opnext
|
|
||||||
nextopnext = nextop=>opnext
|
|
||||||
if nextopnext->opcode == SHR_CODE
|
|
||||||
op->opcode = LLB_CODE
|
|
||||||
op=>opoffset++
|
|
||||||
freeops = 2
|
|
||||||
break
|
|
||||||
fin
|
|
||||||
fin
|
|
||||||
fin
|
|
||||||
if pass and not freeops
|
|
||||||
crunched = try_dupify(op)
|
|
||||||
fin
|
|
||||||
break // LLW_CODE
|
|
||||||
is LAB_CODE
|
|
||||||
if pass and not is_hardware_address(op=>opoffset)
|
|
||||||
crunched = try_dupify(op)
|
|
||||||
fin
|
|
||||||
break // LAB_CODE
|
|
||||||
is LAW_CODE
|
|
||||||
// LAW x:CB 8:SHR -> LAB x+1
|
|
||||||
if nextop->opcode == CONST_CODE and nextop=>opval == 8
|
|
||||||
if nextop=>opnext
|
|
||||||
nextopnext = nextop=>opnext
|
|
||||||
if nextopnext->opcode == SHR_CODE
|
|
||||||
op->opcode = LAB_CODE
|
|
||||||
op=>opoffset++
|
|
||||||
freeops = 2
|
|
||||||
break
|
|
||||||
fin
|
|
||||||
fin
|
|
||||||
fin
|
|
||||||
if pass and not freeops and not is_hardware_address(op=>opoffset)
|
|
||||||
crunched = try_dupify(op)
|
|
||||||
fin
|
|
||||||
break // LAW_CODE
|
|
||||||
is LOGIC_NOT_CODE
|
|
||||||
when nextop->opcode
|
|
||||||
is BRFALSE_CODE
|
|
||||||
op->opcode = BRTRUE_CODE
|
|
||||||
op->opgroup = RELATIVE_GROUP
|
|
||||||
op=>optag = nextop=>optag
|
|
||||||
freeops = 1
|
|
||||||
break
|
|
||||||
is BRTRUE_CODE
|
|
||||||
op->opcode = BRFALSE_CODE
|
|
||||||
op->opgroup = RELATIVE_GROUP
|
|
||||||
op=>optag = nextop=>optag
|
|
||||||
freeops = 1
|
|
||||||
break
|
|
||||||
wend
|
|
||||||
break // LOGIC_NOT_CODE
|
|
||||||
is SLB_CODE
|
|
||||||
if nextop->opcode == LLB_CODE and op=>opoffset == nextop=>opoffset
|
|
||||||
op->opcode = DLB_CODE
|
|
||||||
freeops = 1
|
|
||||||
fin
|
|
||||||
break // SLB_CODE
|
|
||||||
is SLW_CODE
|
|
||||||
if nextop->opcode == LLW_CODE and op=>opoffset == nextop=>opoffset
|
|
||||||
op->opcode = DLW_CODE
|
|
||||||
freeops = 1
|
|
||||||
fin
|
|
||||||
break // SLW_CODE
|
|
||||||
is SAB_CODE
|
|
||||||
if nextop->opcode == LAB_CODE and op=>optag == nextop=>optag and op=>opoffset == nextop=>opoffset
|
|
||||||
op->opcode = DAB_CODE
|
|
||||||
freeops = 1
|
|
||||||
fin
|
|
||||||
break // SAB_CODE
|
|
||||||
is SAW_CODE
|
|
||||||
if nextop->opcode == LAW_CODE and op=>optag == nextop=>optag and op=>opoffset == nextop=>opoffset
|
|
||||||
op->opcode = DAW_CODE
|
|
||||||
freeops = 1
|
|
||||||
fin
|
|
||||||
break // SAW_CODE
|
|
||||||
wend
|
|
||||||
//
|
|
||||||
// Free up crunched ops. If freeops is positive we free up that many ops
|
|
||||||
// *after* op; if it's negative, we free up abs(freeops) ops *starting
|
|
||||||
// with* op.
|
|
||||||
//
|
|
||||||
if freeops < 0
|
|
||||||
freeops = -freeops
|
|
||||||
if op == *seq
|
|
||||||
//
|
|
||||||
// If op is at the start of the sequence, we treat this as a special case.
|
|
||||||
//
|
|
||||||
while freeops > 0
|
|
||||||
nextop = op=>opnext
|
|
||||||
release_op(op)
|
|
||||||
*seq = nextop
|
|
||||||
op = nextop
|
|
||||||
freeops--
|
|
||||||
loop
|
|
||||||
crunched = TRUE
|
|
||||||
else
|
|
||||||
//
|
|
||||||
// Otherwise we just move op back to point to the previous op and
|
|
||||||
// let the following loop remove the required number of ops.
|
|
||||||
//
|
|
||||||
op = opprev
|
|
||||||
nextop = op=>opnext
|
|
||||||
fin
|
|
||||||
fin
|
|
||||||
while freeops
|
|
||||||
op=>opnext = nextop=>opnext
|
|
||||||
nextop=>opnext = freeop_lst
|
|
||||||
freeop_lst = nextop
|
|
||||||
nextop = op=>opnext
|
|
||||||
crunched = TRUE
|
|
||||||
freeops--
|
|
||||||
loop
|
|
||||||
opprev = op
|
|
||||||
op = nextop
|
|
||||||
nextop = op=>opnext
|
|
||||||
loop
|
|
||||||
return crunched
|
|
||||||
end
|
|
||||||
//
|
|
||||||
// Generate/add to a sequence of code
|
// Generate/add to a sequence of code
|
||||||
//
|
//
|
||||||
def gen_op(seq, code)
|
def gen_op(seq, code)
|
||||||
@@ -1076,150 +759,3 @@ def gen_bop(tkn, seq)
|
|||||||
op->opgroup = STACK_GROUP
|
op->opgroup = STACK_GROUP
|
||||||
return seq
|
return seq
|
||||||
end
|
end
|
||||||
//
|
|
||||||
// Append one sequence to the end of another
|
|
||||||
//
|
|
||||||
def cat_seq(seq1, seq2)
|
|
||||||
word op
|
|
||||||
|
|
||||||
if not seq1; return seq2; fin
|
|
||||||
op = seq1
|
|
||||||
while op=>opnext; op = op=>opnext; loop
|
|
||||||
op=>opnext = seq2
|
|
||||||
return seq1
|
|
||||||
end
|
|
||||||
//
|
|
||||||
// Emit the pending sequence
|
|
||||||
//
|
|
||||||
def emit_pending_seq#0
|
|
||||||
word lcl_pending, op
|
|
||||||
//
|
|
||||||
// This is called by some of the emit_*() functions to ensure that any
|
|
||||||
// pending ops are emitted before they emit their own op when they are
|
|
||||||
// called from the parser. However, this function itself calls some of those
|
|
||||||
// emit_*() functions to emit instructions from the pending sequence, which
|
|
||||||
// would cause an infinite loop if we weren't careful. We therefore set
|
|
||||||
// pending_seq to null on entry and work with a local copy, so if this
|
|
||||||
// function calls back into itself it is a no-op.
|
|
||||||
//
|
|
||||||
if not pending_seq; return; fin
|
|
||||||
lcl_pending = pending_seq
|
|
||||||
pending_seq = NULL
|
|
||||||
if outflags & OPTIMIZE
|
|
||||||
while crunch_seq(@lcl_pending, 0); loop
|
|
||||||
if outflags & OPTIMIZE2
|
|
||||||
while crunch_seq(@lcl_pending, 1); loop
|
|
||||||
fin
|
|
||||||
fin
|
|
||||||
while lcl_pending
|
|
||||||
op = lcl_pending
|
|
||||||
when op->opgroup
|
|
||||||
//
|
|
||||||
// Constant value
|
|
||||||
//
|
|
||||||
is CONST_GROUP
|
|
||||||
if op=>opval == $0000 // ZERO
|
|
||||||
emit_byte($00)
|
|
||||||
elsif op=>opval & $FF00 == $0000 // Constant BYTE
|
|
||||||
emit_byte($2A)
|
|
||||||
emit_byte(op->opval)
|
|
||||||
elsif op=>opval & $FF00 == $FF00 // Constant $FF00 | BYTE
|
|
||||||
emit_byte($5E)
|
|
||||||
emit_byte(op->opval)
|
|
||||||
else // Constant WORD
|
|
||||||
emit_byte($2C)
|
|
||||||
emit_word(op=>opval)
|
|
||||||
fin
|
|
||||||
break
|
|
||||||
//
|
|
||||||
// Constant string
|
|
||||||
//
|
|
||||||
is CONSTR_GROUP
|
|
||||||
emit_byte($2E)
|
|
||||||
emit_data(0, STR_TYPE, op=>opval, 0)
|
|
||||||
break
|
|
||||||
//
|
|
||||||
// Single op codes
|
|
||||||
//
|
|
||||||
is STACK_GROUP
|
|
||||||
emit_byte(op->opcode)
|
|
||||||
break
|
|
||||||
//
|
|
||||||
// Local address codes
|
|
||||||
//
|
|
||||||
is LOCAL_GROUP
|
|
||||||
emit_byte(op->opcode)
|
|
||||||
emit_byte(op->opoffset)
|
|
||||||
break
|
|
||||||
//
|
|
||||||
// Global address codes
|
|
||||||
//
|
|
||||||
is GLOBAL_GROUP
|
|
||||||
if op=>optag & IS_CTAG and op=>opoffset
|
|
||||||
exit_err(ERR_INVAL|ERR_CODE|ERR_CONST)
|
|
||||||
else
|
|
||||||
emit_byte(op->opcode)
|
|
||||||
emit_addr(op=>optag+op=>opoffset)
|
|
||||||
fin
|
|
||||||
break
|
|
||||||
//
|
|
||||||
// Relative address codes
|
|
||||||
//
|
|
||||||
is RELATIVE_GROUP
|
|
||||||
emit_byte(op->opcode)
|
|
||||||
emit_reladdr(op=>optag)
|
|
||||||
break
|
|
||||||
//
|
|
||||||
// Code tags
|
|
||||||
//
|
|
||||||
is CODETAG_GROUP
|
|
||||||
emit_ctag(op=>optag)
|
|
||||||
break
|
|
||||||
otherwise
|
|
||||||
return
|
|
||||||
wend
|
|
||||||
lcl_pending = lcl_pending=>opnext;
|
|
||||||
//
|
|
||||||
// Free this op
|
|
||||||
//
|
|
||||||
op=>opnext = freeop_lst
|
|
||||||
freeop_lst = op
|
|
||||||
loop
|
|
||||||
end
|
|
||||||
//
|
|
||||||
// Emit a sequence of ops (into the pending sequence)
|
|
||||||
//
|
|
||||||
def emit_seq(seq)#0
|
|
||||||
word op
|
|
||||||
byte string
|
|
||||||
string = FALSE
|
|
||||||
op = seq
|
|
||||||
while op
|
|
||||||
if op->opgroup == CONSTR_GROUP; string = TRUE; break; fin
|
|
||||||
op = op=>opnext
|
|
||||||
loop
|
|
||||||
pending_seq = cat_seq(pending_seq, seq)
|
|
||||||
//
|
|
||||||
// The source code comments in the output are much more logical if we don't
|
|
||||||
// merge multiple sequences together. There's no value in doing this merging
|
|
||||||
// if we're not optimizing, and we optionally allow it to be prevented even
|
|
||||||
// when we are optimizing by specifing the -N (NO_COMBINE) flag.
|
|
||||||
//
|
|
||||||
// We must also force output if the sequence includes a CS opcode, as the
|
|
||||||
// associated 'constant' is only temporarily valid.
|
|
||||||
//
|
|
||||||
if not (outflags & (OPTIMIZE|OPTIMIZE2)) or (outflags & NO_COMBINE) or string
|
|
||||||
emit_pending_seq
|
|
||||||
fin
|
|
||||||
end
|
|
||||||
//
|
|
||||||
// Emit lambda function
|
|
||||||
//
|
|
||||||
def emit_lambdafunc(tag, namestr, cparms, lambda_seq)#0
|
|
||||||
emit_ctag(tag)
|
|
||||||
framesize = cparms * 2
|
|
||||||
emit_enter(cparms)
|
|
||||||
emit_seq(lambda_seq)
|
|
||||||
emit_pending_seq
|
|
||||||
emit_leave
|
|
||||||
end
|
|
||||||
|
486
src/toolsrc/codeopt.pla
Normal file
486
src/toolsrc/codeopt.pla
Normal file
@@ -0,0 +1,486 @@
|
|||||||
|
include "inc/cmdsys.plh"
|
||||||
|
//
|
||||||
|
// Imports from main compiler
|
||||||
|
//
|
||||||
|
import plasm
|
||||||
|
word freeop_lst
|
||||||
|
word optimize_seq
|
||||||
|
end
|
||||||
|
//
|
||||||
|
// Code sequence values shares with main compiler
|
||||||
|
//
|
||||||
|
include "toolsrc/codeseq.plh"
|
||||||
|
//
|
||||||
|
// Replace all but the first of a series of identical load opcodes by DUP. This
|
||||||
|
// doesn't reduce the number of opcodes but does reduce their size in bytes.
|
||||||
|
// This is only called on the second optimisation pass because the DUP opcodes
|
||||||
|
// may inhibit other peephole optimisations which are more valuable.
|
||||||
|
//
|
||||||
|
def try_dupify(op)
|
||||||
|
byte crunched
|
||||||
|
word nextop
|
||||||
|
|
||||||
|
crunched = FALSE
|
||||||
|
nextop = op=>opnext
|
||||||
|
while nextop
|
||||||
|
if op->opcode <> nextop->opcode; return crunched; fin
|
||||||
|
when op->opcode
|
||||||
|
is CONST_CODE
|
||||||
|
if op=>opval <> nextop=>opval; return crunched; fin
|
||||||
|
break
|
||||||
|
is LADDR_CODE
|
||||||
|
is LLB_CODE
|
||||||
|
is LLW_CODE
|
||||||
|
if op=>opoffset <> nextop=>opoffset; return crunched; fin
|
||||||
|
break
|
||||||
|
is GADDR_CODE
|
||||||
|
is LAB_CODE
|
||||||
|
is LAW_CODE
|
||||||
|
if (op=>optag <> nextop=>optag) or (op=>opoffset <> nextop=>opoffset); return crunched; fin
|
||||||
|
break
|
||||||
|
otherwise
|
||||||
|
return crunched
|
||||||
|
wend
|
||||||
|
nextop->opcode = DUP_CODE
|
||||||
|
nextop->opgroup = STACK_GROUP
|
||||||
|
nextop = nextop=>opnext
|
||||||
|
crunched = TRUE
|
||||||
|
loop
|
||||||
|
return crunched
|
||||||
|
end
|
||||||
|
def is_hardware_address(addr)
|
||||||
|
return isuge(addr, $C000) and isult(addr, $D000)
|
||||||
|
end
|
||||||
|
//
|
||||||
|
// Crunch sequence (peephole optimize)
|
||||||
|
//
|
||||||
|
def crunch_seq(seq, pass)
|
||||||
|
word nextop, nextopnext, opprev, op
|
||||||
|
byte crunched, freeops, shiftcnt
|
||||||
|
|
||||||
|
opprev = NULL
|
||||||
|
op = *seq
|
||||||
|
nextop = op=>opnext
|
||||||
|
crunched = FALSE
|
||||||
|
freeops = 0
|
||||||
|
while op and nextop
|
||||||
|
when op->opcode
|
||||||
|
is CONST_CODE
|
||||||
|
if op=>opval == 1
|
||||||
|
if nextop>opcode == ADD_CODE
|
||||||
|
op->opcode = INC_CODE
|
||||||
|
freeops = 1
|
||||||
|
break
|
||||||
|
fin
|
||||||
|
if nextop->opcode == SUB_CODE
|
||||||
|
op->opcode = DEC_CODE
|
||||||
|
freeops = 1
|
||||||
|
break
|
||||||
|
fin
|
||||||
|
if nextop->opcode == SHL_CODE
|
||||||
|
op->opcode = DUP_CODE
|
||||||
|
nextop->opcode = ADD_CODE
|
||||||
|
crunched = 1
|
||||||
|
break
|
||||||
|
fin
|
||||||
|
fin
|
||||||
|
when nextop->opcode
|
||||||
|
is NEG_CODE
|
||||||
|
op=>opval = -(op=>opval)
|
||||||
|
freeops = 1
|
||||||
|
break
|
||||||
|
is COMP_CODE
|
||||||
|
op=>opval = ~(op=>opval)
|
||||||
|
freeops = 1
|
||||||
|
break
|
||||||
|
is LOGIC_NOT_CODE
|
||||||
|
op=>opval = op=>opval ?? FALSE :: TRUE
|
||||||
|
freeops = 1
|
||||||
|
break
|
||||||
|
is LB_CODE // BPTR_CODE
|
||||||
|
op=>opoffset = op=>opval
|
||||||
|
op->opcode = LAB_CODE
|
||||||
|
op->opgroup = GLOBAL_GROUP
|
||||||
|
freeops = 1
|
||||||
|
break
|
||||||
|
is LW_CODE // WPTR_CODE
|
||||||
|
op=>opoffset = op=>opval
|
||||||
|
op->opcode = LAW_CODE
|
||||||
|
op->opgroup = LOCAL_GROUP
|
||||||
|
freeops = 1
|
||||||
|
break
|
||||||
|
is SB_CODE
|
||||||
|
op=>opoffset = op=>opval
|
||||||
|
op->opcode = SAB_CODE
|
||||||
|
op->opgroup = GLOBAL_GROUP
|
||||||
|
freeops = 1
|
||||||
|
break
|
||||||
|
is SW_CODE
|
||||||
|
op=>opoffset = op=>opval
|
||||||
|
op->opcode = SAW_CODE
|
||||||
|
op->opgroup = GLOBAL_GROUP
|
||||||
|
freeops = 1
|
||||||
|
break
|
||||||
|
is BRFALSE_CODE
|
||||||
|
if op=>opval
|
||||||
|
freeops = -2 // Remove constant and never taken branch
|
||||||
|
else
|
||||||
|
op->opcode = BRNCH_CODE // Always taken branch
|
||||||
|
op->opgroup = RELATIVE_GROUP
|
||||||
|
op=>optag = nextop=>optag
|
||||||
|
freeops = 1
|
||||||
|
fin
|
||||||
|
break
|
||||||
|
is BRTRUE_CODE
|
||||||
|
if not op=>opval
|
||||||
|
freeops = -2 // Remove constant never taken branch
|
||||||
|
else
|
||||||
|
op->opcode = BRNCH_CODE // Always taken branch
|
||||||
|
op->opgroup = RELATIVE_GROUP
|
||||||
|
op=>optag = nextop=>optag
|
||||||
|
freeops = 1
|
||||||
|
fin
|
||||||
|
break
|
||||||
|
is NE_CODE
|
||||||
|
if not op=>opval
|
||||||
|
freeops = -2 // Remove ZERO:ISNE
|
||||||
|
fin
|
||||||
|
break
|
||||||
|
is EQ_CODE
|
||||||
|
if not op=>opval
|
||||||
|
op->opcode = LOGIC_NOT_CODE
|
||||||
|
freeops = 1
|
||||||
|
fin
|
||||||
|
break
|
||||||
|
is CONST_CODE // Collapse constant operation
|
||||||
|
nextopnext = nextop->nextop
|
||||||
|
if nextopnext
|
||||||
|
when nextopnext->opcode
|
||||||
|
is MUL_CODE
|
||||||
|
op=>opval = op=>opval * nextop=>opval
|
||||||
|
freeops = 2
|
||||||
|
break
|
||||||
|
is DIV_CODE
|
||||||
|
op=>opval = op=>opval / nextop=>opval
|
||||||
|
freeops = 2
|
||||||
|
break
|
||||||
|
is MOD_CODE
|
||||||
|
op=>opval = op=>opval % nextop=>opval
|
||||||
|
freeops = 2
|
||||||
|
break
|
||||||
|
is ADD_CODE
|
||||||
|
op=>opval = op=>opval + nextop=>opval
|
||||||
|
freeops = 2
|
||||||
|
break
|
||||||
|
is SUB_CODE
|
||||||
|
op=>opval = op=>opval - nextop=>opval
|
||||||
|
freeops = 2
|
||||||
|
break
|
||||||
|
is SHL_CODE
|
||||||
|
op=>opval = op=>opval << nextop=>opval
|
||||||
|
freeops = 2
|
||||||
|
break
|
||||||
|
is SHR_CODE
|
||||||
|
op=>opval = op=>opval >> nextop=>opval
|
||||||
|
freeops = 2
|
||||||
|
break
|
||||||
|
is AND_CODE
|
||||||
|
op=>opval = op=>opval & nextop=>opval
|
||||||
|
freeops = 2
|
||||||
|
break
|
||||||
|
is OR_CODE
|
||||||
|
op=>opval = op=>opval | nextop=>opval
|
||||||
|
freeops = 2
|
||||||
|
break
|
||||||
|
is EOR_CODE
|
||||||
|
op=>opval = op=>opval ^ nextop=>opval
|
||||||
|
freeops = 2
|
||||||
|
break
|
||||||
|
is EQ_CODE
|
||||||
|
op=>opval = op=>opval == nextop=>opval
|
||||||
|
freeops = 2
|
||||||
|
break
|
||||||
|
is NE_CODE
|
||||||
|
op=>opval = op=>opval <> nextop=>opval
|
||||||
|
freeops = 2
|
||||||
|
break
|
||||||
|
is GE_CODE
|
||||||
|
op=>opval = op=>opval >= nextop=>opval
|
||||||
|
freeops = 2
|
||||||
|
break
|
||||||
|
is LT_CODE
|
||||||
|
op=>opval = op=>opval < nextop=>opval
|
||||||
|
freeops = 2
|
||||||
|
break
|
||||||
|
is GT_CODE
|
||||||
|
op=>opval = op=>opval > nextop=>opval
|
||||||
|
freeops = 2
|
||||||
|
break
|
||||||
|
is LE_CODE
|
||||||
|
op=>opval = op=>opval <= nextop=>opval
|
||||||
|
freeops = 2
|
||||||
|
break
|
||||||
|
is LOGIC_OR_CODE
|
||||||
|
op=>opval = op=>opval or nextop=>opval
|
||||||
|
freeops = 2
|
||||||
|
break
|
||||||
|
is LOGIC_AND_CODE
|
||||||
|
op=>opval = op=>opval and nextop=>opval
|
||||||
|
freeops = 2
|
||||||
|
break
|
||||||
|
wend // End of collapse constant operation
|
||||||
|
fin
|
||||||
|
if pass > 0 and freeops == 0 and op=>opval
|
||||||
|
crunched = try_dupify(op)
|
||||||
|
fin
|
||||||
|
break // CONST_CODE
|
||||||
|
is MUL_CODE
|
||||||
|
for shiftcnt = 0 to 15
|
||||||
|
if op=>opval == 1 << shiftcnt
|
||||||
|
op=>opval = shiftcnt
|
||||||
|
nextop->opcode = SHL_CODE
|
||||||
|
nextop->opgroup = STACK_GROUP
|
||||||
|
break
|
||||||
|
fin
|
||||||
|
next
|
||||||
|
break
|
||||||
|
is DIV_CODE
|
||||||
|
for shiftcnt = 0 to 15
|
||||||
|
if op=>opval == 1 << shiftcnt
|
||||||
|
op=>opval = shiftcnt
|
||||||
|
nextop->opcode = SHR_CODE
|
||||||
|
nextop->opcode = STACK_GROUP
|
||||||
|
break
|
||||||
|
fin
|
||||||
|
next
|
||||||
|
break
|
||||||
|
wend
|
||||||
|
break // CONST_CODE
|
||||||
|
is LADDR_CODE
|
||||||
|
when nextop->opcode
|
||||||
|
is CONST_CODE
|
||||||
|
if nextop=>opnext
|
||||||
|
nextopnext = nextop=>opnext
|
||||||
|
when nextopnext->opcode
|
||||||
|
is ADD_CODE
|
||||||
|
is INDEXB_CODE
|
||||||
|
op=>opoffset = op=>opoffset + nextop=>opval
|
||||||
|
freeops = 2
|
||||||
|
break
|
||||||
|
is INDEXW_CODE
|
||||||
|
op=>opoffset = op=>opoffset + nextop=>opval * 2
|
||||||
|
freeops = 2
|
||||||
|
break
|
||||||
|
wend
|
||||||
|
fin
|
||||||
|
break
|
||||||
|
is LB_CODE
|
||||||
|
op->opcode = LLB_CODE
|
||||||
|
op->opgroup = LOCAL_GROUP
|
||||||
|
freeops = 1
|
||||||
|
break
|
||||||
|
is LW_CODE
|
||||||
|
op->opcode = LLW_CODE
|
||||||
|
op->opgroup = LOCAL_GROUP
|
||||||
|
freeops = 1
|
||||||
|
break
|
||||||
|
is SB_CODE
|
||||||
|
op->opcode = SLB_CODE
|
||||||
|
op->opgroup = LOCAL_GROUP
|
||||||
|
freeops = 1
|
||||||
|
break
|
||||||
|
is SW_CODE
|
||||||
|
op->opcode = SLW_CODE
|
||||||
|
op->opgroup = LOCAL_GROUP
|
||||||
|
freeops = 1
|
||||||
|
break
|
||||||
|
wend
|
||||||
|
if pass > 0 and not freeops
|
||||||
|
crunched = try_dupify(op)
|
||||||
|
fin
|
||||||
|
break // LADDR_CODE
|
||||||
|
is GADDR_CODE
|
||||||
|
when nextop->opcode
|
||||||
|
is CONST_CODE
|
||||||
|
if nextop=>opnext
|
||||||
|
nextopnext = nextop=>opnext
|
||||||
|
when nextopnext->opcode
|
||||||
|
is ADD_CODE
|
||||||
|
is INDEXB_CODE
|
||||||
|
op=>opoffset = op=>opoffset + nextop=>opval
|
||||||
|
freeops = 2
|
||||||
|
break
|
||||||
|
is INDEXW_CODE
|
||||||
|
op=>opoffset = op=>opoffset + nextop=>opval * 2
|
||||||
|
freeops = 2
|
||||||
|
break
|
||||||
|
wend
|
||||||
|
fin
|
||||||
|
break
|
||||||
|
is LB_CODE
|
||||||
|
op->opcode = LAB_CODE
|
||||||
|
op->opgroup = GLOBAL_GROUP
|
||||||
|
freeops = 1
|
||||||
|
break
|
||||||
|
is LW_CODE
|
||||||
|
op->opcode = LAW_CODE
|
||||||
|
op->opgroup = GLOBAL_GROUP
|
||||||
|
freeops = 1
|
||||||
|
break
|
||||||
|
is SB_CODE
|
||||||
|
op->opcode = SAB_CODE
|
||||||
|
op->opgroup = GLOBAL_GROUP
|
||||||
|
freeops = 1
|
||||||
|
break
|
||||||
|
is SW_CODE
|
||||||
|
op->opcode = SAW_CODE
|
||||||
|
op->opgroup = GLOBAL_GROUP
|
||||||
|
freeops = 1
|
||||||
|
break
|
||||||
|
is ICAL_CODE
|
||||||
|
op->opcode = CALL_CODE
|
||||||
|
op->opgroup = GLOBAL_GROUP
|
||||||
|
freeops = 1
|
||||||
|
break
|
||||||
|
wend
|
||||||
|
if pass > 0 and not freeops
|
||||||
|
crunched = try_dupify(op)
|
||||||
|
fin
|
||||||
|
break // GADDR_CODE
|
||||||
|
is LLB_CODE
|
||||||
|
if pass > 0
|
||||||
|
crunched = try_dupify(op)
|
||||||
|
fin
|
||||||
|
break // LLB_CODE
|
||||||
|
is LLW_CODE
|
||||||
|
// LLW [n]:CB 8:SHR -> LLB [n+1]
|
||||||
|
if nextop->opcode == CONST_CODE and nextop=>opval == 8
|
||||||
|
if nextop=>opnext
|
||||||
|
nextopnext = nextop=>opnext
|
||||||
|
if nextopnext->opcode == SHR_CODE
|
||||||
|
op->opcode = LLB_CODE
|
||||||
|
op=>opoffset++
|
||||||
|
freeops = 2
|
||||||
|
break
|
||||||
|
fin
|
||||||
|
fin
|
||||||
|
fin
|
||||||
|
if pass and not freeops
|
||||||
|
crunched = try_dupify(op)
|
||||||
|
fin
|
||||||
|
break // LLW_CODE
|
||||||
|
is LAB_CODE
|
||||||
|
if pass and not is_hardware_address(op=>opoffset)
|
||||||
|
crunched = try_dupify(op)
|
||||||
|
fin
|
||||||
|
break // LAB_CODE
|
||||||
|
is LAW_CODE
|
||||||
|
// LAW x:CB 8:SHR -> LAB x+1
|
||||||
|
if nextop->opcode == CONST_CODE and nextop=>opval == 8
|
||||||
|
if nextop=>opnext
|
||||||
|
nextopnext = nextop=>opnext
|
||||||
|
if nextopnext->opcode == SHR_CODE
|
||||||
|
op->opcode = LAB_CODE
|
||||||
|
op=>opoffset++
|
||||||
|
freeops = 2
|
||||||
|
break
|
||||||
|
fin
|
||||||
|
fin
|
||||||
|
fin
|
||||||
|
if pass and not freeops and not is_hardware_address(op=>opoffset)
|
||||||
|
crunched = try_dupify(op)
|
||||||
|
fin
|
||||||
|
break // LAW_CODE
|
||||||
|
is LOGIC_NOT_CODE
|
||||||
|
when nextop->opcode
|
||||||
|
is BRFALSE_CODE
|
||||||
|
op->opcode = BRTRUE_CODE
|
||||||
|
op->opgroup = RELATIVE_GROUP
|
||||||
|
op=>optag = nextop=>optag
|
||||||
|
freeops = 1
|
||||||
|
break
|
||||||
|
is BRTRUE_CODE
|
||||||
|
op->opcode = BRFALSE_CODE
|
||||||
|
op->opgroup = RELATIVE_GROUP
|
||||||
|
op=>optag = nextop=>optag
|
||||||
|
freeops = 1
|
||||||
|
break
|
||||||
|
wend
|
||||||
|
break // LOGIC_NOT_CODE
|
||||||
|
is SLB_CODE
|
||||||
|
if nextop->opcode == LLB_CODE and op=>opoffset == nextop=>opoffset
|
||||||
|
op->opcode = DLB_CODE
|
||||||
|
freeops = 1
|
||||||
|
fin
|
||||||
|
break // SLB_CODE
|
||||||
|
is SLW_CODE
|
||||||
|
if nextop->opcode == LLW_CODE and op=>opoffset == nextop=>opoffset
|
||||||
|
op->opcode = DLW_CODE
|
||||||
|
freeops = 1
|
||||||
|
fin
|
||||||
|
break // SLW_CODE
|
||||||
|
is SAB_CODE
|
||||||
|
if nextop->opcode == LAB_CODE and op=>optag == nextop=>optag and op=>opoffset == nextop=>opoffset
|
||||||
|
op->opcode = DAB_CODE
|
||||||
|
freeops = 1
|
||||||
|
fin
|
||||||
|
break // SAB_CODE
|
||||||
|
is SAW_CODE
|
||||||
|
if nextop->opcode == LAW_CODE and op=>optag == nextop=>optag and op=>opoffset == nextop=>opoffset
|
||||||
|
op->opcode = DAW_CODE
|
||||||
|
freeops = 1
|
||||||
|
fin
|
||||||
|
break // SAW_CODE
|
||||||
|
wend
|
||||||
|
//
|
||||||
|
// Free up crunched ops. If freeops is positive we free up that many ops
|
||||||
|
// *after* op; if it's negative, we free up abs(freeops) ops *starting
|
||||||
|
// with* op.
|
||||||
|
//
|
||||||
|
if freeops < 0
|
||||||
|
freeops = -freeops
|
||||||
|
if op == *seq
|
||||||
|
//
|
||||||
|
// If op is at the start of the sequence, we treat this as a special case.
|
||||||
|
//
|
||||||
|
while freeops > 0
|
||||||
|
nextop = op=>opnext
|
||||||
|
op=>opnext = freeop_lst
|
||||||
|
freeop_lst = op
|
||||||
|
*seq = nextop
|
||||||
|
op = nextop
|
||||||
|
freeops--
|
||||||
|
loop
|
||||||
|
crunched = TRUE
|
||||||
|
else
|
||||||
|
//
|
||||||
|
// Otherwise we just move op back to point to the previous op and
|
||||||
|
// let the following loop remove the required number of ops.
|
||||||
|
//
|
||||||
|
op = opprev
|
||||||
|
nextop = op=>opnext
|
||||||
|
fin
|
||||||
|
fin
|
||||||
|
while freeops
|
||||||
|
op=>opnext = nextop=>opnext
|
||||||
|
nextop=>opnext = freeop_lst
|
||||||
|
freeop_lst = nextop
|
||||||
|
nextop = op=>opnext
|
||||||
|
crunched = TRUE
|
||||||
|
freeops--
|
||||||
|
loop
|
||||||
|
opprev = op
|
||||||
|
op = nextop
|
||||||
|
nextop = op=>opnext
|
||||||
|
loop
|
||||||
|
return crunched
|
||||||
|
end
|
||||||
|
//
|
||||||
|
// Point to crunch function
|
||||||
|
//
|
||||||
|
optimize_seq = @crunch_seq
|
||||||
|
//
|
||||||
|
// Keep this module in memory
|
||||||
|
//
|
||||||
|
return modkeep
|
||||||
|
done
|
91
src/toolsrc/codeseq.plh
Normal file
91
src/toolsrc/codeseq.plh
Normal file
@@ -0,0 +1,91 @@
|
|||||||
|
//
|
||||||
|
// Constant code group
|
||||||
|
//
|
||||||
|
const CONST_GROUP = $00
|
||||||
|
const CONST_CODE = $2C
|
||||||
|
const CONSTR_GROUP = $01
|
||||||
|
const CONSTR_CODE = $2E
|
||||||
|
//
|
||||||
|
// Stack code group
|
||||||
|
//
|
||||||
|
const STACK_GROUP = $02
|
||||||
|
const INDEXB_CODE = $02
|
||||||
|
const ADD_CODE = $02
|
||||||
|
const SUB_CODE = $04
|
||||||
|
const MUL_CODE = $06
|
||||||
|
const DIV_CODE = $08
|
||||||
|
const MOD_CODE = $0A
|
||||||
|
const INC_CODE = $0C
|
||||||
|
const DEC_CODE = $0E
|
||||||
|
const NEG_CODE = $10
|
||||||
|
const COMP_CODE = $12
|
||||||
|
const AND_CODE = $14
|
||||||
|
const OR_CODE = $16
|
||||||
|
const EOR_CODE = $18
|
||||||
|
const SHL_CODE = $1A
|
||||||
|
const SHR_CODE = $1C
|
||||||
|
const INDEXW_CODE = $1E
|
||||||
|
const LOGIC_NOT_CODE = $20
|
||||||
|
const LOGIC_OR_CODE = $22
|
||||||
|
const LOGIC_AND_CODE = $24
|
||||||
|
const DROP_CODE = $30
|
||||||
|
const DUP_CODE = $32
|
||||||
|
const EQ_CODE = $40
|
||||||
|
const NE_CODE = $42
|
||||||
|
const GT_CODE = $44
|
||||||
|
const LT_CODE = $46
|
||||||
|
const GE_CODE = $48
|
||||||
|
const LE_CODE = $4A
|
||||||
|
const ICAL_CODE = $56
|
||||||
|
const RET_CODE = $5C
|
||||||
|
const LB_CODE = $60
|
||||||
|
const BPTR_CODE = $60
|
||||||
|
const LW_CODE = $62
|
||||||
|
const WPTR_CODE = $62
|
||||||
|
const SB_CODE = $70
|
||||||
|
const SW_CODE = $72
|
||||||
|
//
|
||||||
|
// Local address code group
|
||||||
|
//
|
||||||
|
const LOCAL_GROUP = $03
|
||||||
|
const LADDR_CODE = $28
|
||||||
|
const LLB_CODE = $64
|
||||||
|
const LLW_CODE = $66
|
||||||
|
const DLB_CODE = $6C
|
||||||
|
const DLW_CODE = $6E
|
||||||
|
const SLB_CODE = $74
|
||||||
|
const SLW_CODE = $76
|
||||||
|
//
|
||||||
|
// Global address code group
|
||||||
|
//
|
||||||
|
const GLOBAL_GROUP = $04
|
||||||
|
const GADDR_CODE = $26
|
||||||
|
const LAB_CODE = $68
|
||||||
|
const LAW_CODE = $6A
|
||||||
|
const SAB_CODE = $78
|
||||||
|
const SAW_CODE = $7A
|
||||||
|
const DAB_CODE = $7C
|
||||||
|
const DAW_CODE = $7E
|
||||||
|
const CALL_CODE = $54
|
||||||
|
//
|
||||||
|
// Relative address code group
|
||||||
|
//
|
||||||
|
const RELATIVE_GROUP = $05
|
||||||
|
const BRFALSE_CODE = $4C
|
||||||
|
const BRTRUE_CODE = $4E
|
||||||
|
const BRNCH_CODE = $50
|
||||||
|
//
|
||||||
|
// Code tag address group
|
||||||
|
//
|
||||||
|
const CODETAG_GROUP = $06
|
||||||
|
//
|
||||||
|
// Code sequence op
|
||||||
|
//
|
||||||
|
struc t_opseq
|
||||||
|
byte opcode
|
||||||
|
byte opgroup
|
||||||
|
word opval[]
|
||||||
|
word optag
|
||||||
|
word opoffset
|
||||||
|
word opnext
|
||||||
|
end
|
@@ -202,96 +202,13 @@ byte[16] sizestack
|
|||||||
byte[16] typestack
|
byte[16] typestack
|
||||||
word valsp
|
word valsp
|
||||||
//
|
//
|
||||||
// Constant code group
|
// Code sequence shared with optimizer
|
||||||
//
|
//
|
||||||
const CONST_GROUP = $00
|
include "toolsrc/codeseq.plh"
|
||||||
const CONST_CODE = $2C
|
|
||||||
const CONSTR_GROUP = $01
|
|
||||||
const CONSTR_CODE = $2E
|
|
||||||
//
|
//
|
||||||
// Stack code group
|
|
||||||
//
|
|
||||||
const STACK_GROUP = $02
|
|
||||||
const INDEXB_CODE = $02
|
|
||||||
const ADD_CODE = $02
|
|
||||||
const SUB_CODE = $04
|
|
||||||
const MUL_CODE = $06
|
|
||||||
const DIV_CODE = $08
|
|
||||||
const MOD_CODE = $0A
|
|
||||||
const INC_CODE = $0C
|
|
||||||
const DEC_CODE = $0E
|
|
||||||
const NEG_CODE = $10
|
|
||||||
const COMP_CODE = $12
|
|
||||||
const AND_CODE = $14
|
|
||||||
const OR_CODE = $16
|
|
||||||
const EOR_CODE = $18
|
|
||||||
const SHL_CODE = $1A
|
|
||||||
const SHR_CODE = $1C
|
|
||||||
const INDEXW_CODE = $1E
|
|
||||||
const LOGIC_NOT_CODE = $20
|
|
||||||
const LOGIC_OR_CODE = $22
|
|
||||||
const LOGIC_AND_CODE = $24
|
|
||||||
const DROP_CODE = $30
|
|
||||||
const DUP_CODE = $32
|
|
||||||
const EQ_CODE = $40
|
|
||||||
const NE_CODE = $42
|
|
||||||
const GT_CODE = $44
|
|
||||||
const LT_CODE = $46
|
|
||||||
const GE_CODE = $48
|
|
||||||
const LE_CODE = $4A
|
|
||||||
const ICAL_CODE = $56
|
|
||||||
const RET_CODE = $5C
|
|
||||||
const LB_CODE = $60
|
|
||||||
const BPTR_CODE = $60
|
|
||||||
const LW_CODE = $62
|
|
||||||
const WPTR_CODE = $62
|
|
||||||
const SB_CODE = $70
|
|
||||||
const SW_CODE = $72
|
|
||||||
//
|
|
||||||
// Local address code group
|
|
||||||
//
|
|
||||||
const LOCAL_GROUP = $03
|
|
||||||
const LADDR_CODE = $28
|
|
||||||
const LLB_CODE = $64
|
|
||||||
const LLW_CODE = $66
|
|
||||||
const DLB_CODE = $6C
|
|
||||||
const DLW_CODE = $6E
|
|
||||||
const SLB_CODE = $74
|
|
||||||
const SLW_CODE = $76
|
|
||||||
//
|
|
||||||
// Global address code group
|
|
||||||
//
|
|
||||||
const GLOBAL_GROUP = $04
|
|
||||||
const GADDR_CODE = $26
|
|
||||||
const LAB_CODE = $68
|
|
||||||
const LAW_CODE = $6A
|
|
||||||
const SAB_CODE = $78
|
|
||||||
const SAW_CODE = $7A
|
|
||||||
const DAB_CODE = $7C
|
|
||||||
const DAW_CODE = $7E
|
|
||||||
const CALL_CODE = $54
|
|
||||||
//
|
|
||||||
// Relative address code group
|
|
||||||
//
|
|
||||||
const RELATIVE_GROUP = $05
|
|
||||||
const BRFALSE_CODE = $4C
|
|
||||||
const BRTRUE_CODE = $4E
|
|
||||||
const BRNCH_CODE = $50
|
|
||||||
//
|
|
||||||
// Code tag address group
|
|
||||||
//
|
|
||||||
const CODETAG_GROUP = $06
|
|
||||||
//
|
//
|
||||||
// Symbol table variables
|
// Symbol table variables
|
||||||
//
|
//
|
||||||
struc t_opseq
|
|
||||||
byte opcode
|
|
||||||
byte opgroup
|
|
||||||
word opval[]
|
|
||||||
word optag
|
|
||||||
word opoffset
|
|
||||||
word opnext
|
|
||||||
end
|
|
||||||
struc t_id
|
struc t_id
|
||||||
word idval
|
word idval
|
||||||
word idtype
|
word idtype
|
||||||
@@ -312,7 +229,7 @@ const IDGLOBALSZ = 2048
|
|||||||
const IDLOCALSZ = 512
|
const IDLOCALSZ = 512
|
||||||
word codetag = -1
|
word codetag = -1
|
||||||
word idglobal_tbl, idlocal_tbl, ctag_tbl
|
word idglobal_tbl, idlocal_tbl, ctag_tbl
|
||||||
word freeop_lst, pending_seq
|
word pending_seq
|
||||||
word globals, lastglobal, lastlocal, savelast
|
word globals, lastglobal, lastlocal, savelast
|
||||||
word codebufsz, datasize, framesize, savesize
|
word codebufsz, datasize, framesize, savesize
|
||||||
byte locals, savelocals
|
byte locals, savelocals
|
||||||
@@ -322,6 +239,11 @@ byte[16] moddep_tbl[8]
|
|||||||
byte moddep_cnt
|
byte moddep_cnt
|
||||||
predef emit_pending_seq#0
|
predef emit_pending_seq#0
|
||||||
//
|
//
|
||||||
|
// Exports for optimizer module
|
||||||
|
//
|
||||||
|
export word freeop_lst
|
||||||
|
export word optimize_seq
|
||||||
|
//
|
||||||
// Compiler flags
|
// Compiler flags
|
||||||
//
|
//
|
||||||
const OPTIMIZE = 1
|
const OPTIMIZE = 1
|
||||||
@@ -467,6 +389,8 @@ end
|
|||||||
// Include code to reduce size of this file
|
// Include code to reduce size of this file
|
||||||
//
|
//
|
||||||
include "toolsrc/codegen.pla"
|
include "toolsrc/codegen.pla"
|
||||||
|
//include "toolsrc/codeopt.pla"
|
||||||
|
//include "toolsrc/writerel.pla"
|
||||||
include "toolsrc/lex.pla"
|
include "toolsrc/lex.pla"
|
||||||
include "toolsrc/parse.pla"
|
include "toolsrc/parse.pla"
|
||||||
//
|
//
|
||||||
@@ -474,10 +398,17 @@ include "toolsrc/parse.pla"
|
|||||||
//
|
//
|
||||||
arg = argNext(argFirst)
|
arg = argNext(argFirst)
|
||||||
if ^arg and ^(arg + 1) == '-'
|
if ^arg and ^(arg + 1) == '-'
|
||||||
opt = arg + 2
|
opt = arg + 2
|
||||||
while TRUE
|
while TRUE
|
||||||
if toupper(^opt) == 'O'
|
if toupper(^opt) == 'O'
|
||||||
outflags = outflags | OPTIMIZE
|
//
|
||||||
|
// Load optimizer module here
|
||||||
|
//
|
||||||
|
if modexec("CODEOPT") >= 0
|
||||||
|
outflags = outflags | OPTIMIZE
|
||||||
|
else
|
||||||
|
puts("\nOptimizer disabled\n")
|
||||||
|
fin
|
||||||
opt++
|
opt++
|
||||||
if ^opt == '2'
|
if ^opt == '2'
|
||||||
outflags = outflags | OPTIMIZE2
|
outflags = outflags | OPTIMIZE2
|
||||||
@@ -519,7 +450,7 @@ if srcfile and relfile
|
|||||||
//
|
//
|
||||||
parse_module
|
parse_module
|
||||||
fileio:close(srcref)
|
fileio:close(srcref)
|
||||||
puts("Bytes compiled: "); puti(codeptr - codebuff); putln
|
puts("\nBytes compiled: "); puti(codeptr - codebuff); putln
|
||||||
//
|
//
|
||||||
// Write REL file
|
// Write REL file
|
||||||
//
|
//
|
||||||
@@ -530,13 +461,13 @@ if srcfile and relfile
|
|||||||
//writerel(srcref)
|
//writerel(srcref)
|
||||||
fileio:close(srcref)
|
fileio:close(srcref)
|
||||||
else
|
else
|
||||||
puts("Error opening: "); puts(@relfile); putln
|
puts("\nError opening: "); puts(@relfile); putln
|
||||||
fin
|
fin
|
||||||
fin
|
fin
|
||||||
else
|
else
|
||||||
puts("Error opening: "); puts(@srcfile); putln
|
puts("\nError opening: "); puts(@srcfile); putln
|
||||||
fin
|
fin
|
||||||
else
|
else
|
||||||
puts("Usage: +PLASM [-[W][O[2]][N]] <src> <rel>\n")
|
puts("Usage:+PLASM [-[W][O[2]][N]] <src> <rel>\n")
|
||||||
fin
|
fin
|
||||||
done
|
done
|
||||||
|
Reference in New Issue
Block a user