diff options
Diffstat (limited to 'compiler/x86/rgx86.pas')
| -rw-r--r-- | compiler/x86/rgx86.pas | 346 |
1 files changed, 346 insertions, 0 deletions
diff --git a/compiler/x86/rgx86.pas b/compiler/x86/rgx86.pas new file mode 100644 index 0000000000..725ba50022 --- /dev/null +++ b/compiler/x86/rgx86.pas @@ -0,0 +1,346 @@ +{ + Copyright (c) 1998-2002 by Florian Klaempfl + + This unit implements the x86 specific class for the register + allocator + + 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. + + **************************************************************************** +} + +unit rgx86; + +{$i fpcdefs.inc} + + interface + + uses + cclasses,globtype, + cpubase,cpuinfo,cgbase,cgutils, + aasmbase,aasmtai,aasmcpu, + rgobj; + + type + trgx86 = class(trgobj) + function get_spill_subreg(r : tregister) : tsubregister;override; + function do_spill_replace(list:Taasmoutput;instr:taicpu;orgreg:tsuperregister;const spilltemp:treference):boolean;override; + end; + + tpushedsavedloc = record + case byte of + 0: (pushed: boolean); + 1: (ofs: longint); + end; + + tpushedsavedfpu = array[tsuperregister] of tpushedsavedloc; + + trgx86fpu = class + { The "usableregsxxx" contain all registers of type "xxx" that } + { aren't currently allocated to a regvar. The "unusedregsxxx" } + { contain all registers of type "xxx" that aren't currently } + { allocated } + unusedregsfpu,usableregsfpu : Tsuperregisterset; + { these counters contain the number of elements in the } + { unusedregsxxx/usableregsxxx sets } + countunusedregsfpu : byte; + + { Contains the registers which are really used by the proc itself. + It doesn't take care of registers used by called procedures + } + used_in_proc : tcpuregisterset; + + {reg_pushes_other : regvarother_longintarray; + is_reg_var_other : regvarother_booleanarray; + regvar_loaded_other : regvarother_booleanarray;} + + { tries to hold the amount of times which the current tree is processed } + t_times: longint; + + fpuvaroffset : byte; + + constructor create; + + function getregisterfpu(list: taasmoutput) : tregister; + procedure ungetregisterfpu(list: taasmoutput; r : tregister); + + { pushes and restores registers } + procedure saveusedfpuregisters(list:Taasmoutput; + var saved:Tpushedsavedfpu; + const s:Tcpuregisterset); + procedure restoreusedfpuregisters(list:Taasmoutput; + const saved:Tpushedsavedfpu); + + { corrects the fpu stack register by ofs } + function correct_fpuregister(r : tregister;ofs : byte) : tregister; + end; + + +implementation + + uses + systems, + verbose; + + const + { This value is used in tsaved. If the array value is equal + to this, then this means that this register is not used.} + reg_not_saved = $7fffffff; + + +{****************************************************************************** + Trgcpu +******************************************************************************} + + function trgx86.get_spill_subreg(r : tregister) : tsubregister; + begin + result:=getsubreg(r); + end; + + + function trgx86.do_spill_replace(list:Taasmoutput;instr:taicpu;orgreg:tsuperregister;const spilltemp:treference):boolean; + var + replaceoper : longint; + begin + result:=false; + with instr do + begin + replaceoper:=-1; + case ops of + 1 : + begin + if (oper[0]^.typ=top_reg) then + begin + if getsupreg(oper[0]^.reg)<>orgreg then + internalerror(200410101); + replaceoper:=0; + end; + end; + 2,3 : + begin + { We can handle opcodes with 2 and 3 operands the same way. The opcodes + with 3 registers are shrd/shld, where the 3rd operand is const or CL, + that doesn't need spilling } + if (oper[0]^.typ=top_reg) and + (oper[1]^.typ=top_reg) and + (getsupreg(oper[0]^.reg)<>getsupreg(oper[1]^.reg)) then + begin + { One of the arguments shall be able to be replaced } + if (getregtype(oper[0]^.reg)=regtype) and + (getsupreg(oper[0]^.reg)=orgreg) then + replaceoper:=0 + else + if (getregtype(oper[1]^.reg)=regtype) and + (getsupreg(oper[1]^.reg)=orgreg) then + replaceoper:=1 + else + internalerror(200410106); + case replaceoper of + 0 : + begin + { Some instructions don't allow memory references + for source } + case instr.opcode of + A_BT, + A_BTS, + A_BTC, + A_BTR : + replaceoper:=-1; + end; + end; + 1 : + begin + { Some instructions don't allow memory references + for destination } + case instr.opcode of + A_MOVZX, + A_MOVSX, + A_MULSS, + A_MULSD, + A_SUBSS, + A_SUBSD, + A_ADDSD, + A_ADDSS, + A_DIVSD, + A_DIVSS, + A_SHLD, + A_SHRD, + A_CVTDQ2PD, + A_CVTDQ2PS, + A_CVTPD2DQ, + A_CVTPD2PI, + A_CVTPD2PS, + A_CVTPI2PD, + A_CVTPS2DQ, + A_CVTPS2PD, + A_CVTSD2SI, + A_CVTSD2SS, + A_CVTSI2SD, + A_CVTSS2SD, + A_CVTTPD2PI, + A_CVTTPD2DQ, + A_CVTTPS2DQ, + A_CVTTSD2SI, + A_CVTPI2PS, + A_CVTPS2PI, + A_CVTSI2SS, + A_CVTSS2SI, + A_CVTTPS2PI, + A_CVTTSS2SI, + A_IMUL : + replaceoper:=-1; + end; + end; + end; + end; + end; + end; + + { Replace register with spill reference } + if replaceoper<>-1 then + begin + oper[replaceoper]^.typ:=top_ref; + new(oper[replaceoper]^.ref); + oper[replaceoper]^.ref^:=spilltemp; + result:=true; + end; + end; + end; + + +{****************************************************************************** + Trgx86fpu +******************************************************************************} + + constructor Trgx86fpu.create; + begin + used_in_proc:=[]; + t_times := 0; + unusedregsfpu:=usableregsfpu; + end; + + + function trgx86fpu.getregisterfpu(list: taasmoutput) : tregister; + begin + { note: don't return R_ST0, see comments above implementation of } + { a_loadfpu_* methods in cgcpu (JM) } + result:=NR_ST; + end; + + + procedure trgx86fpu.ungetregisterfpu(list : taasmoutput; r : tregister); + begin + { nothing to do, fpu stack management is handled by the load/ } + { store operations in cgcpu (JM) } + end; + + + + function trgx86fpu.correct_fpuregister(r : tregister;ofs : byte) : tregister; + begin + correct_fpuregister:=r; + setsupreg(correct_fpuregister,ofs); + end; + + + procedure trgx86fpu.saveusedfpuregisters(list: taasmoutput; + var saved : tpushedsavedfpu; + const s: tcpuregisterset); + var + r : tregister; + hr : treference; + begin + used_in_proc:=used_in_proc+s; + +{$warning TODO firstsavefpureg} +(* + { don't try to save the fpu registers if not desired (e.g. for } + { the 80x86) } + if firstsavefpureg <> R_NO then + for r.enum:=firstsavefpureg to lastsavefpureg do + begin + saved[r.enum].ofs:=reg_not_saved; + { if the register is used by the calling subroutine and if } + { it's not a regvar (those are handled separately) } + if not is_reg_var_other[r.enum] and + (r.enum in s) and + { and is present in use } + not(r.enum in unusedregsfpu) then + begin + { then save it } + tg.GetTemp(list,extended_size,tt_persistent,hr); + saved[r.enum].ofs:=hr.offset; + cg.a_loadfpu_reg_ref(list,OS_FLOAT,r,hr); + cg.a_reg_dealloc(list,r); + include(unusedregsfpu,r.enum); + inc(countunusedregsfpu); + end; + end; +*) + end; + + + procedure trgx86fpu.restoreusedfpuregisters(list : taasmoutput; + const saved : tpushedsavedfpu); + + var + r,r2 : tregister; + hr : treference; + + begin +{$warning TODO firstsavefpureg} +(* + if firstsavefpureg <> R_NO then + for r.enum:=lastsavefpureg downto firstsavefpureg do + begin + if saved[r.enum].ofs <> reg_not_saved then + begin + r2.enum:=R_INTREGISTER; + r2.number:=NR_FRAME_POINTER_REG; + reference_reset_base(hr,r2,saved[r.enum].ofs); + cg.a_reg_alloc(list,r); + cg.a_loadfpu_ref_reg(list,OS_FLOAT,hr,r); + if not (r.enum in unusedregsfpu) then + { internalerror(10) + in n386cal we always save/restore the reg *state* + using save/restoreunusedstate -> the current state + may not be real (JM) } + else + begin + dec(countunusedregsfpu); + exclude(unusedregsfpu,r.enum); + end; + tg.UnGetTemp(list,hr); + end; + end; +*) + end; + +(* + procedure Trgx86fpu.saveotherregvars(list: taasmoutput; const s: totherregisterset); + var + r: Tregister; + begin + if not(cs_regvars in aktglobalswitches) then + exit; + if firstsavefpureg <> NR_NO then + for r.enum := firstsavefpureg to lastsavefpureg do + if is_reg_var_other[r.enum] and + (r.enum in s) then + store_regvar(list,r); + end; +*) + +end. |
