summaryrefslogtreecommitdiff
path: root/compiler/m68k/rgcpu.pas
diff options
context:
space:
mode:
Diffstat (limited to 'compiler/m68k/rgcpu.pas')
-rw-r--r--compiler/m68k/rgcpu.pas140
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.