diff options
Diffstat (limited to 'compiler/m68k/rgcpu.pas')
-rw-r--r-- | compiler/m68k/rgcpu.pas | 140 |
1 files changed, 138 insertions, 2 deletions
diff --git a/compiler/m68k/rgcpu.pas b/compiler/m68k/rgcpu.pas index a981d73a75..0c0ab7957c 100644 --- a/compiler/m68k/rgcpu.pas +++ b/compiler/m68k/rgcpu.pas @@ -27,14 +27,150 @@ unit rgcpu; interface uses - aasmbase,aasmtai,aasmdata, - cpubase, + aasmbase,aasmtai,aasmdata,aasmcpu, + cgbase,cgutils,cpubase, rgobj; type trgcpu = class(trgobj) + procedure do_spill_read(list:tasmlist;pos:tai;const spilltemp:treference;tempreg:tregister);override; + procedure do_spill_written(list:tasmlist;pos:tai;const spilltemp:treference;tempreg:tregister);override; + function do_spill_replace(list:TAsmList;instr:taicpu;orgreg:tsuperregister;const spilltemp:treference):boolean;override; end; implementation + uses + cutils,cgobj,verbose,globtype,globals,cpuinfo; + + { returns True if source operand of MOVE can be replaced with spilltemp when its destination is ref^. } + function isvalidmovedest(ref: preference): boolean; inline; + begin + { The following is for Coldfire, for other CPUs it maybe can be relaxed. } + result:=(ref^.symbol=nil) and (ref^.scalefactor<=1) and + (ref^.index=NR_NO) and (ref^.base<>NR_NO) and (ref^.offset>=low(smallint)) and + (ref^.offset<=high(smallint)); + end; + + + procedure trgcpu.do_spill_read(list:tasmlist;pos:tai;const spilltemp:treference;tempreg:tregister); + var + helpins : tai; + tmpref : treference; + helplist : tasmlist; + hreg : tregister; + begin + if (abs(spilltemp.offset)>32767) and (current_settings.cputype in (cpu_coldfire + [cpu_mc68000])) then + begin + helplist:=tasmlist.create; + + if getregtype(tempreg)=R_INTREGISTER then + hreg:=tempreg + else + hreg:=cg.getintregister(helplist,OS_ADDR); +{$ifdef DEBUG_SPILLING} + helplist.concat(tai_comment.Create(strpnew('Spilling: Read, large offset'))); +{$endif} + + helplist.concat(taicpu.op_const_reg(A_MOVE,S_L,spilltemp.offset,hreg)); + reference_reset_base(tmpref,spilltemp.base,0,sizeof(aint)); + tmpref.index:=hreg; + + helpins:=spilling_create_load(tmpref,tempreg); + helplist.concat(helpins); + list.insertlistafter(pos,helplist); + helplist.free; + end + else + inherited do_spill_read(list,pos,spilltemp,tempreg); + end; + + + procedure trgcpu.do_spill_written(list:tasmlist;pos:tai;const spilltemp:treference;tempreg:tregister); + var + tmpref : treference; + helplist : tasmlist; + hreg : tregister; + begin + if (abs(spilltemp.offset)>32767) and (current_settings.cputype in (cpu_coldfire + [cpu_mc68000])) then + begin + helplist:=tasmlist.create; + + if getregtype(tempreg)=R_INTREGISTER then + hreg:=getregisterinline(helplist,[R_SUBWHOLE]) + else + hreg:=cg.getintregister(helplist,OS_ADDR); +{$ifdef DEBUG_SPILLING} + helplist.concat(tai_comment.Create(strpnew('Spilling: Write, large offset'))); +{$endif} + + helplist.concat(taicpu.op_const_reg(A_MOVE,S_L,spilltemp.offset,hreg)); + reference_reset_base(tmpref,spilltemp.base,0,sizeof(aint)); + tmpref.index:=hreg; + + helplist.concat(spilling_create_store(tempreg,tmpref)); + if getregtype(tempreg)=R_INTREGISTER then + ungetregisterinline(helplist,hreg); + + list.insertlistafter(pos,helplist); + helplist.free; + end + else + inherited do_spill_written(list,pos,spilltemp,tempreg); + end; + + + function trgcpu.do_spill_replace(list:TAsmList;instr:taicpu;orgreg:tsuperregister;const spilltemp:treference):boolean; + var + opidx: longint; + begin + result:=false; + opidx:=-1; + if (abs(spilltemp.offset)>32767) and (current_settings.cputype in cpu_coldfire) then + exit; + case instr.ops of + 1: + begin + if (instr.oper[0]^.typ=top_reg) and (getregtype(instr.oper[0]^.reg)=regtype) and + ((instr.opcode=A_TST) or (instr.opcode=A_CLR)) then + begin + if get_alias(getsupreg(instr.oper[0]^.reg))<>orgreg then + InternalError(2014080101); + opidx:=0; + end; + end; + 2: + begin + if (instr.oper[0]^.typ=top_reg) and (getregtype(instr.oper[0]^.reg)=regtype) and + (get_alias(getsupreg(instr.oper[0]^.reg))=orgreg) then + begin + { source can be replaced if dest is register... } + if ((instr.oper[1]^.typ=top_reg) and (instr.opcode in [A_MOVE,A_ADD,A_SUB,A_AND,A_OR,A_CMP])) or + {... or a "simple" reference in case of MOVE } + ((instr.opcode=A_MOVE) and (instr.oper[1]^.typ=top_ref) and isvalidmovedest(instr.oper[1]^.ref)) then + opidx:=0; + end + else if (instr.oper[1]^.typ=top_reg) and (getregtype(instr.oper[1]^.reg)=regtype) and + (get_alias(getsupreg(instr.oper[1]^.reg))=orgreg) and + ( + (instr.opcode in [A_MOVE,A_ADD,A_SUB,A_AND,A_OR]) and + (instr.oper[0]^.typ=top_reg) + ) or + (instr.opcode in [A_ADDQ,A_SUBQ,A_MOV3Q]) then + opidx:=1; + end; + end; + + if (opidx<0) then + exit; + instr.oper[opidx]^.typ:=top_ref; + new(instr.oper[opidx]^.ref); + instr.oper[opidx]^.ref^:=spilltemp; + case instr.opsize of + S_B: inc(instr.oper[opidx]^.ref^.offset,3); + S_W: inc(instr.oper[opidx]^.ref^.offset,2); + end; + result:=true; + end; + end. |