{ $Id$ Copyright (c) 1993,98 by Florian Klaempfl, Carl Eric Codere This unit generates 68000 (or better) assembler from the parse tree This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. ****************************************************************************} {$ifdef tp} {$E+,F+,N+,D+,L+,Y+} {$endif} {---------------------------------------------------------------------------} { LEFT TO DO IN CG68k AND CG68k2 } {---------------------------------------------------------------------------} { o Test and correct problems with extended support. } { o Optimize secondmoddiv when doing a constant modulo. } { o Add emulation support for Cardinal under MC68000. } {---------------------------------------------------------------------------} unit cg68k; {***************************************************************************} interface {***************************************************************************} uses objects,verbose,cobjects,systems,globals,tree, symtable,types,strings,pass_1,hcodegen, aasm,m68k,tgen68k,files,cga68k,cg68k2,gdb,link; { produces assembler for the expression in variable p } { and produces an assembler node at the end } procedure generatecode(var p : ptree); { produces the actual code } function do_secondpass(var p : ptree) : boolean; procedure secondpass(var p : ptree); {$ifdef test_dest_loc} const { used to avoid temporary assignments } dest_loc_known : boolean = false; in_dest_loc : boolean = false; dest_loc_tree : ptree = nil; var dest_loc : tlocation; procedure mov_reg_to_dest(p : ptree; s : topsize; reg : tregister); {$endif test_dest_loc} {***************************************************************************} implementation {***************************************************************************} const never_copy_const_param : boolean = false; bytes2Sxx:array[1..4] of Topsize=(S_B,S_W,S_NO,S_L); { used to avoid temporary assignments } dest_loc_known : boolean = false; in_dest_loc : boolean = false; dest_loc_tree : ptree = nil; var { this is for open arrays and strings } { but be careful, this data is in the } { generated code destroyed quick, and also } { the next call of secondload destroys this } { data } { So be careful using the informations } { provided by this variables } highframepointer : tregister; highoffset : longint; dest_loc : tlocation; procedure mov_reg_to_dest(p : ptree; s : topsize; reg : tregister); begin if (dest_loc.loc=LOC_CREGISTER) or (dest_loc.loc=LOC_REGISTER) then begin emit_reg_reg(A_MOVE,s,reg,dest_loc.register); p^.location:=dest_loc; in_dest_loc:=true; end else if (dest_loc.loc=LOC_REFERENCE) or (dest_loc.loc=LOC_MEM) then begin exprasmlist^.concat(new(pai68k,op_reg_ref(A_MOVE,s,reg,newreference(dest_loc.reference)))); p^.location:=dest_loc; in_dest_loc:=true; end else internalerror(20080); end; procedure error(const t : tmsgconst); begin if not(codegenerror) then verbose.Message(t); codegenerror:=true; end; type secondpassproc = procedure(var p : ptree); procedure seconderror(var p : ptree); begin p^.error:=true; codegenerror:=true; end; procedure secondload(var p : ptree); var hregister : tregister; i : longint; symtabletype: tsymtabletype; hp : preference; begin simple_loadn:=true; reset_reference(p^.location.reference); case p^.symtableentry^.typ of { this is only for toasm and toaddr } absolutesym : begin stringdispose(p^.location.reference.symbol); p^.location.reference.symbol:=stringdup(p^.symtableentry^.mangledname); if p^.symtableentry^.owner^.symtabletype=unitsymtable then concat_external(p^.symtableentry^.mangledname,EXT_NEAR); end; varsym : begin hregister:=R_NO; symtabletype:=p^.symtable^.symtabletype; { in case it is a register variable: } { we simply set the location to the } { correct register. } if pvarsym(p^.symtableentry)^.reg<>R_NO then begin p^.location.loc:=LOC_CREGISTER; p^.location.register:=pvarsym(p^.symtableentry)^.reg; unused:=unused-[pvarsym(p^.symtableentry)^.reg]; end else begin { --------------------- LOCAL AND TEMP VARIABLES ------------- } if (symtabletype=parasymtable) or (symtabletype=localsymtable) then begin p^.location.reference.base:=procinfo.framepointer; p^.location.reference.offset:=pvarsym(p^.symtableentry)^.address; if (symtabletype=localsymtable) then p^.location.reference.offset:=-p^.location.reference.offset; if (symtabletype=parasymtable) then inc(p^.location.reference.offset,p^.symtable^.call_offset); if (lexlevel>(p^.symtable^.symtablelevel)) then begin hregister:=getaddressreg; { make a reference } new(hp); reset_reference(hp^); hp^.offset:=procinfo.framepointer_offset; hp^.base:=procinfo.framepointer; exprasmlist^.concat(new(pai68k,op_ref_reg(A_MOVE,S_L,hp,hregister))); simple_loadn:=false; i:=lexlevel-1; while i>(p^.symtable^.symtablelevel) do begin { make a reference } new(hp); reset_reference(hp^); hp^.offset:=8; hp^.base:=hregister; exprasmlist^.concat(new(pai68k,op_ref_reg(A_MOVE,S_L,hp,hregister))); dec(i); end; p^.location.reference.base:=hregister; end; end { --------------------- END OF LOCAL AND TEMP VARS ---------------- } else case symtabletype of unitsymtable,globalsymtable, staticsymtable : begin stringdispose(p^.location.reference.symbol); p^.location.reference.symbol:=stringdup(p^.symtableentry^.mangledname); if symtabletype=unitsymtable then concat_external(p^.symtableentry^.mangledname,EXT_NEAR); end; objectsymtable : begin if (pvarsym(p^.symtableentry)^.properties and sp_static)<>0 then begin stringdispose(p^.location.reference.symbol); p^.location.reference.symbol:=stringdup(p^.symtableentry^.mangledname); if p^.symtable^.defowner^.owner^.symtabletype=unitsymtable then concat_external(p^.symtableentry^.mangledname,EXT_NEAR); end else begin p^.location.reference.base:=R_A5; p^.location.reference.offset:=pvarsym(p^.symtableentry)^.address; end; end; withsymtable : begin hregister:=getaddressreg; p^.location.reference.base:=hregister; { make a reference } new(hp); reset_reference(hp^); hp^.offset:=p^.symtable^.datasize; hp^.base:=procinfo.framepointer; exprasmlist^.concat(new(pai68k,op_ref_reg(A_MOVE,S_L,hp,hregister))); p^.location.reference.offset:= pvarsym(p^.symtableentry)^.address; end; end; { in case call by reference, then calculate: } if (pvarsym(p^.symtableentry)^.varspez=vs_var) or ((pvarsym(p^.symtableentry)^.varspez=vs_const) and dont_copy_const_param(pvarsym(p^.symtableentry)^.definition)) then begin simple_loadn:=false; if hregister=R_NO then hregister:=getaddressreg; { ADDED FOR OPEN ARRAY SUPPORT. } if (p^.location.reference.base=procinfo.framepointer) then begin highframepointer:=p^.location.reference.base; highoffset:=p^.location.reference.offset; end else begin highframepointer:=R_A1; highoffset:=p^.location.reference.offset; exprasmlist^.concat(new(pai68k,op_reg_reg(A_MOVE,S_L, p^.location.reference.base,R_A1))); end; exprasmlist^.concat(new(pai68k,op_ref_reg(A_MOVE,S_L,newreference(p^.location.reference), hregister))); { END ADDITION } clear_reference(p^.location.reference); p^.location.reference.base:=hregister; end; { should be dereferenced later (FK) if (pvarsym(p^.symtableentry)^.definition^.deftype=objectdef) and ((pobjectdef(pvarsym(p^.symtableentry)^.definition)^.options and oois_class)<>0) then begin simple_loadn:=false; if hregister=R_NO then hregister:=getaddressreg; exprasmlist^.concat(new(pai68k,op_ref_reg(A_MOVE,S_L,newreference(p^.location.reference), hregister))); clear_reference(p^.location.reference); p^.location.reference.base:=hregister; end; } end; end; procsym: begin {!!!!! Be aware, work on virtual methods too } stringdispose(p^.location.reference.symbol); p^.location.reference.symbol:= stringdup(pprocsym(p^.symtableentry)^.definition^.mangledname); if p^.symtable^.symtabletype=unitsymtable then concat_external(p^.symtableentry^.mangledname,EXT_NEAR); end; typedconstsym : begin stringdispose(p^.location.reference.symbol); p^.location.reference.symbol:=stringdup(p^.symtableentry^.mangledname); if p^.symtable^.symtabletype=unitsymtable then concat_external(p^.symtableentry^.mangledname,EXT_NEAR); end; else internalerror(4); end; end; { D0 and D1 used as temp (ok) } procedure secondmoddiv(var p : ptree); var hreg1 : tregister; power : longint; hl : plabel; reg: tregister; pushed: boolean; begin secondpass(p^.left); set_location(p^.location,p^.left^.location); pushed:=maybe_push(p^.right^.registers32,p); secondpass(p^.right); if pushed then restore(p); { put numerator in register } if p^.left^.location.loc<>LOC_REGISTER then begin if p^.left^.location.loc=LOC_CREGISTER then begin hreg1:=getregister32; emit_reg_reg(A_MOVE,S_L,p^.left^.location.register,hreg1); end else begin del_reference(p^.left^.location.reference); hreg1:=getregister32; exprasmlist^.concat(new(pai68k,op_ref_reg(A_MOVE,S_L,newreference(p^.left^.location.reference), hreg1))); end; p^.left^.location.loc:=LOC_REGISTER; p^.left^.location.register:=hreg1; end else hreg1:=p^.left^.location.register; if (p^.treetype=divn) and (p^.right^.treetype=ordconstn) and ispowerof2(p^.right^.value,power) then begin exprasmlist^.concat(new(pai68k, op_reg(A_TST, S_L, hreg1))); getlabel(hl); emitl(A_BPL,hl); if (power = 1) then exprasmlist^.concat(new(pai68k, op_const_reg(A_ADDQ, S_L,1, hreg1))); if (p^.right^.value-1) < 9 then exprasmlist^.concat(new(pai68k, op_const_reg(A_ADDQ, S_L,p^.right^.value-1, hreg1))) else exprasmlist^.concat(new(pai68k, op_const_reg(A_ADD, S_L,p^.right^.value-1, hreg1))); emitl(A_LABEL, hl); if (power > 0) and (power < 9) then exprasmlist^.concat(new(pai68k, op_const_reg(A_ASR, S_L,power, hreg1))) else begin exprasmlist^.concat(new(pai68k, op_const_reg(A_MOVE,S_L,power, R_D0))); exprasmlist^.concat(new(pai68k, op_reg_reg(A_ASR,S_L,R_D0, hreg1))); end; end else begin { bring denominator to D1 } { D1 is always free, it's } { only used for temporary } { purposes } if (p^.right^.location.loc<>LOC_REGISTER) and (p^.right^.location.loc<>LOC_CREGISTER) then begin del_reference(p^.right^.location.reference); p^.left^.location.loc:=LOC_REGISTER; exprasmlist^.concat(new(pai68k,op_ref_reg(A_MOVE,S_L,newreference(p^.right^.location.reference),R_D1))); end else begin ungetregister32(p^.right^.location.register); emit_reg_reg(A_MOVE,S_L,p^.right^.location.register,R_D1); end; { on entering this section D1 should contain the divisor } if (opt_processors = MC68020) then begin if (p^.treetype = modn) then Begin reg := getregister32; exprasmlist^.concat(new(pai68k,op_reg(A_CLR,S_L,reg))); getlabel(hl); { here what we do is prepare the high register with the } { correct sign. i.e we clear it, check if the low dword reg } { which will participate in the division is signed, if so we} { we extend the sign to the high doword register by inverting } { all the bits. } exprasmlist^.concat(new(pai68k,op_reg(A_TST,S_L,hreg1))); emitl(A_BPL,hl); exprasmlist^.concat(new(pai68k,op_reg(A_NOT,S_L,reg))); emitl(A_LABEL,hl); { reg:hreg1 / d1 } exprasmlist^.concat(new(pai68k,op_reg_reg_reg(A_DIVSL,S_L,R_D1,reg,hreg1))); { hreg1 already contains quotient } { looking for remainder } exprasmlist^.concat(new(pai68k,op_reg_reg(A_MOVE,S_L,reg,hreg1))); ungetregister32(reg); end else { simple division... } Begin { reg:hreg1 / d1 } exprasmlist^.concat(new(pai68k,op_reg_reg(A_DIVS,S_L,R_D1,hreg1))); end; end else { MC68000 operations } begin { put numerator in d0 } emit_reg_reg(A_MOVE,S_L,hreg1,R_D0); { operation to perform on entry to both } { routines... d0/d1 } { return result in d0 } if p^.treetype = divn then emitcall('LONGDIV',true) else emitcall('LONGMOD',true); emit_reg_reg(A_MOVE,S_L,R_D0,hreg1); end; { endif } end; { this registers are always used when div/mod are present } usedinproc:=usedinproc or ($800 shr word(R_D1)); usedinproc:=usedinproc or ($800 shr word(R_D0)); p^.location.loc:=LOC_REGISTER; p^.location.register:=hreg1; end; { D6 used as scratch (ok) } procedure secondshlshr(var p : ptree); var hregister1,hregister2,hregister3 : tregister; op : tasmop; pushed : boolean; begin secondpass(p^.left); pushed:=maybe_push(p^.right^.registers32,p); secondpass(p^.right); if pushed then restore(p); { load left operators in a register } if p^.left^.location.loc<>LOC_REGISTER then begin if p^.left^.location.loc=LOC_CREGISTER then begin hregister1:=getregister32; emit_reg_reg(A_MOVE,S_L,p^.left^.location.register, hregister1); end else begin del_reference(p^.left^.location.reference); hregister1:=getregister32; exprasmlist^.concat(new(pai68k,op_ref_reg(A_MOVE,S_L,newreference(p^.left^.location.reference), hregister1))); end; end else hregister1:=p^.left^.location.register; { determine operator } if p^.treetype=shln then op:=A_LSL else op:=A_LSR; { shifting by a constant directly decode: } if (p^.right^.treetype=ordconstn) then begin if (p^.right^.location.reference.offset and 31 > 0) and (p^.right^.location.reference.offset and 31 < 9) then exprasmlist^.concat(new(pai68k,op_const_reg(op,S_L,p^.right^.location.reference.offset and 31, hregister1))) else begin exprasmlist^.concat(new(pai68k,op_const_reg(A_MOVE,S_L,p^.right^.location.reference.offset and 31, R_D6))); exprasmlist^.concat(new(pai68k,op_reg_reg(op,S_L,R_D6,hregister1))); end; p^.location.loc:=LOC_REGISTER; p^.location.register:=hregister1; end else begin { load right operators in a register } if p^.right^.location.loc<>LOC_REGISTER then begin if p^.right^.location.loc=LOC_CREGISTER then begin hregister2:=getregister32; emit_reg_reg(A_MOVE,S_L,p^.right^.location.register, hregister2); end else begin del_reference(p^.right^.location.reference); hregister2:=getregister32; exprasmlist^.concat(new(pai68k,op_ref_reg(A_MOVE,S_L,newreference(p^.right^.location.reference), hregister2))); end; end else hregister2:=p^.right^.location.register; emit_reg_reg(op,S_L,hregister2,hregister1); p^.location.register:=hregister1; end; { this register is always used when shl/shr are present } usedinproc:=usedinproc or ($800 shr byte(R_D6)); end; procedure secondrealconst(var p : ptree); var hp1 : pai; lastlabel : plabel; found : boolean; begin clear_reference(p^.location.reference); lastlabel:=nil; found:=false; { const already used ? } if p^.labnumber=-1 then begin { tries to found an old entry } hp1:=pai(consts^.first); while assigned(hp1) do begin if hp1^.typ=ait_label then lastlabel:=pai_label(hp1)^.l else begin if (hp1^.typ=p^.realtyp) and (lastlabel<>nil) then begin { Florian this caused a internalerror(10)=> no free reg !! } {if ((p^.realtyp=ait_real_64bit) and (pai_double(hp1)^.value=p^.valued)) or ((p^.realtyp=ait_real_80bit) and (pai_extended(hp1)^.value=p^.valued)) or ((p^.realtyp=ait_real_32bit) and (pai_single(hp1)^.value=p^.valued)) then } if ((p^.realtyp=ait_real_64bit) and (pai_double(hp1)^.value=p^.valued)) then found:=true; if ((p^.realtyp=ait_real_32bit) and (pai_single(hp1)^.value=p^.valued)) then found:=true; if ((p^.realtyp=ait_real_extended) and (pai_extended(hp1)^.value=p^.valued)) then found:=true; if found then begin { found! } p^.labnumber:=lastlabel^.nb; break; end; end; lastlabel:=nil; end; hp1:=pai(hp1^.next); end; { :-(, we must generate a new entry } if p^.labnumber=-1 then begin getlabel(lastlabel); p^.labnumber:=lastlabel^.nb; case p^.realtyp of ait_real_64bit : consts^.insert(new(pai_double,init(p^.valued))); ait_real_32bit : consts^.insert(new(pai_single,init(p^.valued))); ait_real_extended : consts^.insert(new(pai_extended,init(p^.valued))); else internalerror(10120); end; consts^.insert(new(pai_label,init(lastlabel))); end; end; stringdispose(p^.location.reference.symbol); p^.location.reference.symbol:=stringdup(lab2str(lastlabel)); end; procedure secondfixconst(var p : ptree); begin { an fix comma const. behaves as a memory reference } p^.location.loc:=LOC_MEM; p^.location.reference.isintvalue:=true; p^.location.reference.offset:=p^.valuef; end; procedure secondordconst(var p : ptree); begin { an integer const. behaves as a memory reference } p^.location.loc:=LOC_MEM; p^.location.reference.isintvalue:=true; p^.location.reference.offset:=p^.value; end; procedure secondniln(var p : ptree); begin p^.location.loc:=LOC_MEM; p^.location.reference.isintvalue:=true; p^.location.reference.offset:=0; end; procedure secondstringconst(var p : ptree); var hp1 : pai; lastlabel : plabel; pc : pchar; same_string : boolean; i : word; begin clear_reference(p^.location.reference); lastlabel:=nil; { const already used ? } if p^.labstrnumber=-1 then begin { tries to found an old entry } hp1:=pai(consts^.first); while assigned(hp1) do begin if hp1^.typ=ait_label then lastlabel:=pai_label(hp1)^.l else begin if (hp1^.typ=ait_string) and (lastlabel<>nil) and (pai_string(hp1)^.len=length(p^.values^)+2) then begin same_string:=true; for i:=1 to length(p^.values^) do if pai_string(hp1)^.str[i]<>p^.values^[i] then begin same_string:=false; break; end; if same_string then begin { found! } p^.labstrnumber:=lastlabel^.nb; break; end; end; lastlabel:=nil; end; hp1:=pai(hp1^.next); end; { :-(, we must generate a new entry } if p^.labstrnumber=-1 then begin getlabel(lastlabel); p^.labstrnumber:=lastlabel^.nb; getmem(pc,length(p^.values^)+3); move(p^.values^,pc^,length(p^.values^)+1); pc[length(p^.values^)+1]:=#0; { we still will have a problem if there is a #0 inside the pchar } consts^.insert(new(pai_string,init_pchar(pc))); { to overcome this problem we set the length explicitly } { with the ending null char } pai_string(consts^.first)^.len:=length(p^.values^)+2; consts^.insert(new(pai_label,init(lastlabel))); end; end; stringdispose(p^.location.reference.symbol); p^.location.reference.symbol:=stringdup(lab2str(lastlabel)); p^.location.loc := LOC_MEM; end; procedure secondumminus(var p : ptree); begin secondpass(p^.left); p^.location.loc:=LOC_REGISTER; case p^.left^.location.loc of LOC_REGISTER : begin p^.location.register:=p^.left^.location.register; exprasmlist^.concat(new(pai68k,op_reg(A_NEG,S_L,p^.location.register))); end; LOC_CREGISTER : begin p^.location.register:=getregister32; emit_reg_reg(A_MOVE,S_L,p^.location.register, p^.location.register); exprasmlist^.concat(new(pai68k,op_reg(A_NEG,S_L,p^.location.register))); end; LOC_REFERENCE,LOC_MEM : begin del_reference(p^.left^.location.reference); { change sign of a floating point } { in the case of emulation, get } { a free register, and change sign } { manually. } { otherwise simply load into an FPU} { register. } if (p^.left^.resulttype^.deftype=floatdef) and (pfloatdef(p^.left^.resulttype)^.typ<>f32bit) then begin { move to FPU } floatload(pfloatdef(p^.left^.resulttype)^.typ, p^.left^.location.reference,p^.location); if (cs_fp_emulation) in aktswitches then { if in emulation mode change sign manually } exprasmlist^.concat(new(pai68k,op_const_reg(A_BCHG,S_L,31, p^.location.fpureg))) else exprasmlist^.concat(new(pai68k,op_reg(A_FNEG,S_X, p^.location.fpureg))); end else begin p^.location.register:=getregister32; exprasmlist^.concat(new(pai68k,op_ref_reg(A_MOVE,S_L, newreference(p^.left^.location.reference), p^.location.register))); exprasmlist^.concat(new(pai68k,op_reg(A_NEG,S_L,p^.location.register))); end; end; LOC_FPU : begin p^.location.loc:=LOC_FPU; p^.location.fpureg := p^.left^.location.fpureg; if (cs_fp_emulation) in aktswitches then exprasmlist^.concat(new(pai68k,op_const_reg(A_BCHG,S_L,31,p^.location.fpureg))) else exprasmlist^.concat(new(pai68k,op_reg(A_FNEG,S_X,p^.location.fpureg))); end; end; { emitoverflowcheck;} end; { use of A6 is required only temp (ok) } procedure secondaddr(var p : ptree); begin secondpass(p^.left); p^.location.loc:=LOC_REGISTER; p^.location.register:=getregister32; {@ on a procvar means returning an address to the procedure that is stored in it.} { yes but p^.left^.symtableentry can be nil for example on @self !! } { symtableentry can be also invalid, if left is no tree node } if (p^.left^.treetype=loadn) and assigned(p^.left^.symtableentry) and (p^.left^.symtableentry^.typ=varsym) and (Pvarsym(p^.left^.symtableentry)^.definition^.deftype= procvardef) then exprasmlist^.concat(new(pai68k,op_ref_reg(A_MOVE,S_L, newreference(p^.left^.location.reference), p^.location.register))) else begin exprasmlist^.concat(new(pai68k,op_ref_reg(A_LEA,S_L, newreference(p^.left^.location.reference),R_A0))); exprasmlist^.concat(new(pai68k,op_reg_reg(A_MOVE,S_L, R_A0,p^.location.register))); end; { for use of other segments } { if p^.left^.location.reference.segment<>R_DEFAULT_SEG then p^.location.segment:=p^.left^.location.reference.segment; } del_reference(p^.left^.location.reference); end; { register a6 used as scratch } procedure seconddoubleaddr(var p : ptree); begin secondpass(p^.left); p^.location.loc:=LOC_REGISTER; del_reference(p^.left^.location.reference); p^.location.register:=getregister32; exprasmlist^.concat(new(pai68k,op_ref_reg(A_LEA,S_L, newreference(p^.left^.location.reference),R_A0))); exprasmlist^.concat(new(pai68k,op_reg_reg(A_MOVE,S_L, R_A0,p^.location.register))); end; procedure secondnot(var p : ptree); const flagsinvers : array[F_E..F_BE] of tresflags = (F_NE,F_E,F_LE,F_GE,F_L,F_G,F_NC,F_C, F_A,F_AE,F_B,F_BE); var hl : plabel; begin if (p^.resulttype^.deftype=orddef) and (porddef(p^.resulttype)^.typ=bool8bit) then begin case p^.location.loc of LOC_JUMP : begin hl:=truelabel; truelabel:=falselabel; falselabel:=hl; secondpass(p^.left); maketojumpbool(p^.left); hl:=truelabel; truelabel:=falselabel; falselabel:=hl; end; LOC_FLAGS : begin secondpass(p^.left); p^.location.resflags:=flagsinvers[p^.left^.location.resflags]; end; LOC_REGISTER : begin secondpass(p^.left); p^.location.register:=p^.left^.location.register; exprasmlist^.concat(new(pai68k,op_const_reg(A_EOR,S_B,1,p^.location.register))); end; LOC_CREGISTER : begin secondpass(p^.left); p^.location.loc:=LOC_REGISTER; p^.location.register:=getregister32; emit_reg_reg(A_MOVE,S_B,p^.left^.location.register, p^.location.register); exprasmlist^.concat(new(pai68k,op_const_reg(A_EOR,S_B,1,p^.location.register))); end; LOC_REFERENCE,LOC_MEM : begin secondpass(p^.left); del_reference(p^.left^.location.reference); p^.location.loc:=LOC_REGISTER; p^.location.register:=getregister32; if p^.left^.location.loc=LOC_CREGISTER then emit_reg_reg(A_MOVE,S_B,p^.left^.location.register, p^.location.register) else exprasmlist^.concat(new(pai68k,op_ref_reg(A_MOVE,S_B, newreference(p^.left^.location.reference), p^.location.register))); exprasmlist^.concat(new(pai68k,op_const_reg(A_EOR,S_B,1,p^.location.register))); end; end; end else begin secondpass(p^.left); p^.location.loc:=LOC_REGISTER; case p^.left^.location.loc of LOC_REGISTER : begin p^.location.register:=p^.left^.location.register; exprasmlist^.concat(new(pai68k,op_reg(A_NOT,S_L,p^.location.register))); end; LOC_CREGISTER : begin p^.location.register:=getregister32; emit_reg_reg(A_MOVE,S_L,p^.left^.location.register, p^.location.register); exprasmlist^.concat(new(pai68k,op_reg(A_NOT,S_L,p^.location.register))); end; LOC_REFERENCE,LOC_MEM : begin del_reference(p^.left^.location.reference); p^.location.register:=getregister32; exprasmlist^.concat(new(pai68k,op_ref_reg(A_MOVE,S_L, newreference(p^.left^.location.reference), p^.location.register))); exprasmlist^.concat(new(pai68k,op_reg(A_NOT,S_L,p^.location.register))); end; end; {if p^.left^.location.loc=loc_register then p^.location.register:=p^.left^.location.register else begin del_locref(p^.left^.location); p^.location.register:=getregister32; exprasmlist^.concat(new(pai68k,op_loc_reg(A_MOV,S_L, p^.left^.location, p^.location.register))); end; exprasmlist^.concat(new(pai68k,op_reg(A_NOT,S_L,p^.location.register)));} end; end; procedure secondnothing(var p : ptree); begin end; procedure secondassignment(var p : ptree); var opsize : topsize; withresult : boolean; otlabel,hlabel,oflabel : plabel; hregister : tregister; loc : tloc; begin otlabel:=truelabel; oflabel:=falselabel; getlabel(truelabel); getlabel(falselabel); withresult:=false; { calculate left sides } secondpass(p^.left); case p^.left^.location.loc of LOC_REFERENCE : begin { in case left operator uses too many registers } { but to few are free then LEA } if (p^.left^.location.reference.base<>R_NO) and (p^.left^.location.reference.index<>R_NO) and (usablereg32
LOC_REFERENCE then
internalerror(10010)
else
floatstore(pfloatdef(p^.left^.resulttype)^.typ,
p^.right^.location,p^.left^.location.reference);
end;
LOC_JUMP : begin
getlabel(hlabel);
emitl(A_LABEL,truelabel);
if loc=LOC_CREGISTER then
exprasmlist^.concat(new(pai68k,op_const_reg(A_MOVE,S_B,
1,p^.left^.location.register)))
else
exprasmlist^.concat(new(pai68k,op_const_ref(A_MOVE,S_B,
1,newreference(p^.left^.location.reference))));
{exprasmlist^.concat(new(pai68k,op_const_loc(A_MOV,S_B,
1,p^.left^.location)));}
emitl(A_JMP,hlabel);
emitl(A_LABEL,falselabel);
if loc=LOC_CREGISTER then
exprasmlist^.concat(new(pai68k,op_reg(A_CLR,S_B,
p^.left^.location.register)))
else
exprasmlist^.concat(new(pai68k,op_const_ref(A_MOVE,S_B,
0,newreference(p^.left^.location.reference))));
emitl(A_LABEL,hlabel);
end;
LOC_FLAGS : begin
if loc=LOC_CREGISTER then
begin
exprasmlist^.concat(new(pai68k,op_reg(flag_2_set[p^.right^.location.resflags],S_B,
p^.left^.location.register)));
exprasmlist^.concat(new(pai68k,op_reg(A_NEG,S_B,p^.left^.location.register)));
end
else
begin
exprasmlist^.concat(new(pai68k,op_ref(flag_2_set[p^.right^.location.resflags],S_B,
newreference(p^.left^.location.reference))));
exprasmlist^.concat(new(pai68k,op_ref(A_NEG,S_B,newreference(p^.left^.location.reference))));
end;
end;
end;
truelabel:=otlabel;
falselabel:=oflabel;
end;
procedure secondderef(var p : ptree);
var
hr : tregister;
begin
secondpass(p^.left);
clear_reference(p^.location.reference);
case p^.left^.location.loc of
LOC_REGISTER : Begin
hr := getaddressreg;
emit_reg_reg(A_MOVE,S_L,p^.left^.location.register,hr);
p^.location.reference.base:=hr;
ungetregister(p^.left^.location.register);
end;
LOC_CREGISTER : begin
{ ... and reserve one for the pointer }
hr:=getaddressreg;
emit_reg_reg(A_MOVE,S_L,p^.left^.location.register,hr);
p^.location.reference.base:=hr;
{ LOC_REGISTER indicates that this is a
variable register which should not be freed. }
{ ungetregister(p^.left^.location.register); }
end;
else
begin
{ free register }
del_reference(p^.left^.location.reference);
{ ...and reserve one for the pointer }
hr:=getaddressreg;
exprasmlist^.concat(new(pai68k,op_ref_reg(
A_MOVE,S_L,newreference(p^.left^.location.reference),
hr)));
p^.location.reference.base:=hr;
end;
end;
end;
{ used D0, D1 as scratch (ok) }
{ arrays ... }
{ Sets up the array and string }
{ references . }
procedure secondvecn(var p : ptree);
var
pushed : boolean;
ind : tregister;
_p : ptree;
procedure calc_emit_mul;
var
l1,l2 : longint;
begin
l1:=p^.resulttype^.size;
case l1 of
1 : p^.location.reference.scalefactor:=l1;
2 : exprasmlist^.concat(new(pai68k,op_const_reg(A_LSL,S_L,1,ind)));
4 : exprasmlist^.concat(new(pai68k,op_const_reg(A_LSL,S_L,2,ind)));
8 : exprasmlist^.concat(new(pai68k,op_const_reg(A_LSL,S_L,3,ind)));
else
begin
if ispowerof2(l1,l2) then
exprasmlist^.concat(new(pai68k,op_const_reg(A_LSL,S_L,l2,ind)))
else
begin
{ use normal MC68000 signed multiply }
if (l1 >= -32768) and (l1 <= 32767) then
exprasmlist^.concat(new(pai68k,op_const_reg(A_MULS,S_W,l1,ind)))
else
{ use long MC68020 long multiply }
if (opt_processors = MC68020) then
exprasmlist^.concat(new(pai68k,op_const_reg(A_MULS,S_L,l1,ind)))
else
{ MC68000 long multiply }
begin
exprasmlist^.concat(new(pai68k,op_const_reg(A_MOVE,S_L,l1,R_D0)));
exprasmlist^.concat(new(pai68k,op_reg_reg(A_MOVE,S_L,ind,R_D1)));
emitcall('LONGMUL',true);
exprasmlist^.concat(new(pai68k,op_reg_reg(A_MOVE,S_L,R_D0,ind)));
end;
end;
end; { else case }
end; { end case }
end; { calc_emit_mul }
var
extraoffset : longint;
t : ptree;
hp : preference;
tai:pai68k;
reg: tregister;
begin
secondpass(p^.left);
{ RESULT IS IN p^.location.reference }
set_location(p^.location,p^.left^.location);
{ offset can only differ from 0 if arraydef }
if p^.left^.resulttype^.deftype=arraydef then
dec(p^.location.reference.offset,
p^.resulttype^.size*
parraydef(p^.left^.resulttype)^.lowrange);
if p^.right^.treetype=ordconstn then
begin
{ offset can only differ from 0 if arraydef }
if (p^.left^.resulttype^.deftype=arraydef) then
begin
if not(is_open_array(p^.left^.resulttype)) then
begin
if (p^.right^.value>parraydef(p^.left^.resulttype)^.highrange) or
(p^.right^.value