PageRenderTime 31ms CodeModel.GetById 27ms app.highlight 2ms RepoModel.GetById 0ms app.codeStats 0ms

/compiler/x86/rgx86.pas

https://github.com/slibre/freepascal
Pascal | 415 lines | 220 code | 47 blank | 148 comment | 16 complexity | 7af374c71919652e977fbf354255fbac MD5 | raw file
Possible License(s): LGPL-2.0, LGPL-2.1, LGPL-3.0
  1{
  2    Copyright (c) 1998-2002 by Florian Klaempfl
  3
  4    This unit implements the x86 specific class for the register
  5    allocator
  6
  7    This program is free software; you can redistribute it and/or modify
  8    it under the terms of the GNU General Public License as published by
  9    the Free Software Foundation; either version 2 of the License, or
 10    (at your option) any later version.
 11
 12    This program is distributed in the hope that it will be useful,
 13    but WITHOUT ANY WARRANTY; without even the implied warranty of
 14    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 15    GNU General Public License for more details.
 16
 17    You should have received a copy of the GNU General Public License
 18    along with this program; if not, write to the Free Software
 19    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 20
 21 ****************************************************************************
 22}
 23
 24unit rgx86;
 25
 26{$i fpcdefs.inc}
 27
 28  interface
 29
 30    uses
 31      cclasses,globtype,
 32      cpubase,cpuinfo,cgbase,cgutils,
 33      aasmbase,aasmtai,aasmdata,aasmcpu,
 34      rgobj;
 35
 36    type
 37       trgx86 = class(trgobj)
 38         function  get_spill_subreg(r : tregister) : tsubregister;override;
 39         function  do_spill_replace(list:TAsmList;instr:taicpu;orgreg:tsuperregister;const spilltemp:treference):boolean;override;
 40       end;
 41
 42       tpushedsavedloc = record
 43         case byte of
 44           0: (pushed: boolean);
 45           1: (ofs: longint);
 46       end;
 47
 48       tpushedsavedfpu = array[tsuperregister] of tpushedsavedloc;
 49
 50       trgx86fpu = class
 51          { The "usableregsxxx" contain all registers of type "xxx" that }
 52          { aren't currently allocated to a regvar. The "unusedregsxxx"  }
 53          { contain all registers of type "xxx" that aren't currently    }
 54          { allocated                                                    }
 55          unusedregsfpu,usableregsfpu : Tsuperregisterset;
 56          { these counters contain the number of elements in the }
 57          { unusedregsxxx/usableregsxxx sets                     }
 58          countunusedregsfpu : byte;
 59
 60          { Contains the registers which are really used by the proc itself.
 61            It doesn't take care of registers used by called procedures
 62          }
 63          used_in_proc : tcpuregisterset;
 64
 65          {reg_pushes_other : regvarother_longintarray;
 66          is_reg_var_other : regvarother_booleanarray;
 67          regvar_loaded_other : regvarother_booleanarray;}
 68
 69          fpuvaroffset : byte;
 70
 71          constructor create;
 72
 73          function getregisterfpu(list: TAsmList) : tregister;
 74          procedure ungetregisterfpu(list: TAsmList; r : tregister);
 75
 76          { pushes and restores registers }
 77          procedure saveusedfpuregisters(list:TAsmList;
 78                                         var saved:Tpushedsavedfpu;
 79                                         const s:Tcpuregisterset);
 80          procedure restoreusedfpuregisters(list:TAsmList;
 81                                            const saved:Tpushedsavedfpu);
 82
 83          { corrects the fpu stack register by ofs }
 84          function correct_fpuregister(r : tregister;ofs : byte) : tregister;
 85       end;
 86
 87
 88implementation
 89
 90    uses
 91       systems,
 92       verbose;
 93
 94    const
 95       { This value is used in tsaved. If the array value is equal
 96         to this, then this means that this register is not used.}
 97       reg_not_saved = $7fffffff;
 98
 99
100{******************************************************************************
101                                    Trgcpu
102******************************************************************************}
103
104    function trgx86.get_spill_subreg(r : tregister) : tsubregister;
105      begin
106        result:=getsubreg(r);
107      end;
108
109
110    function trgx86.do_spill_replace(list:TAsmList;instr:taicpu;orgreg:tsuperregister;const spilltemp:treference):boolean;
111
112    {Decide wether a "replace" spill is possible, i.e. wether we can replace a register
113     in an instruction by a memory reference. For example, in "mov ireg26d,0", the imaginary
114     register ireg26d can be replaced by a memory reference.}
115
116      var
117        n,replaceoper : longint;
118      begin
119        result:=false;
120        with instr do
121          begin
122            replaceoper:=-1;
123            case ops of
124              1 :
125                begin
126                  if (oper[0]^.typ=top_reg) and
127                     (getregtype(oper[0]^.reg)=regtype) then
128                    begin
129                      if get_alias(getsupreg(oper[0]^.reg))<>orgreg then
130                        internalerror(200410101);
131                      replaceoper:=0;
132                    end;
133                end;
134              2,3 :
135                begin
136                  { We can handle opcodes with 2 and 3 operands the same way. The opcodes
137                    with 3 registers are shrd/shld, where the 3rd operand is const or CL,
138                    that doesn't need spilling.
139                    However, due to AT&T order inside the compiler, the 3rd operand is
140                    numbered 0, so look at operand no. 1 and 2 if we have 3 operands by
141                    adding a "n". }
142                  n:=0;
143                  if ops=3 then
144                    n:=1;
145                  if (oper[n+0]^.typ=top_reg) and
146                     (oper[n+1]^.typ=top_reg) and
147                     ((getregtype(oper[n+0]^.reg)<>regtype) or
148                      (getregtype(oper[n+1]^.reg)<>regtype) or
149                      (get_alias(getsupreg(oper[n+0]^.reg))<>get_alias(getsupreg(oper[n+1]^.reg)))) then
150                    begin
151                      if (getregtype(oper[n+0]^.reg)=regtype) and
152                         (get_alias(getsupreg(oper[n+0]^.reg))=orgreg) then
153                        replaceoper:=0+n
154                      else if (getregtype(oper[n+1]^.reg)=regtype) and
155                         (get_alias(getsupreg(oper[n+1]^.reg))=orgreg) then
156                        replaceoper:=1+n;
157                    end
158                  else if (oper[n+0]^.typ=top_reg) and
159                     (oper[n+1]^.typ=top_const) then
160                    begin
161                      if (getregtype(oper[0+n]^.reg)=regtype) and
162                         (get_alias(getsupreg(oper[0+n]^.reg))=orgreg) then
163                        replaceoper:=0+n
164                      else
165                        internalerror(200704282);
166                    end
167                  else if (oper[n+0]^.typ=top_const) and
168                     (oper[n+1]^.typ=top_reg) then
169                    begin
170                      if (getregtype(oper[1+n]^.reg)=regtype) and
171                         (get_alias(getsupreg(oper[1+n]^.reg))=orgreg) then
172                        replaceoper:=1+n
173                      else
174                        internalerror(200704283);
175                    end;
176                  case replaceoper of
177                    0 :
178                      begin
179                        { Some instructions don't allow memory references
180                          for source }
181                        case instr.opcode of
182                          A_BT,
183                          A_BTS,
184                          A_BTC,
185                          A_BTR,
186
187                          { shufp* would require 16 byte alignment for memory locations so we force the source
188                            operand into a register }
189                          A_SHUFPD,
190                          A_SHUFPS :
191                            replaceoper:=-1;
192                        end;
193                      end;
194                    1 :
195                      begin
196                        { Some instructions don't allow memory references
197                          for destination }
198                        case instr.opcode of
199                          A_CMOVcc,
200                          A_MOVZX,
201                          A_MOVSX,
202                          A_MOVSXD,
203                          A_MULSS,
204                          A_MULSD,
205                          A_SUBSS,
206                          A_SUBSD,
207                          A_ADDSD,
208                          A_ADDSS,
209                          A_DIVSD,
210                          A_DIVSS,
211                          A_SHLD,
212                          A_SHRD,
213                          A_COMISD,
214                          A_COMISS,
215                          A_CVTDQ2PD,
216                          A_CVTDQ2PS,
217                          A_CVTPD2DQ,
218                          A_CVTPD2PI,
219                          A_CVTPD2PS,
220                          A_CVTPI2PD,
221                          A_CVTPS2DQ,
222                          A_CVTPS2PD,
223                          A_CVTSD2SI,
224                          A_CVTSD2SS,
225                          A_CVTSI2SD,
226                          A_CVTSS2SD,
227                          A_CVTTPD2PI,
228                          A_CVTTPD2DQ,
229                          A_CVTTPS2DQ,
230                          A_CVTTSD2SI,
231                          A_CVTPI2PS,
232                          A_CVTPS2PI,
233                          A_CVTSI2SS,
234                          A_CVTSS2SI,
235                          A_CVTTPS2PI,
236                          A_CVTTSS2SI,
237                          A_IMUL,
238                          A_XORPD,
239                          A_XORPS,
240                          A_ORPD,
241                          A_ORPS,
242                          A_ANDPD,
243                          A_ANDPS,
244                          A_UNPCKLPS,
245                          A_UNPCKHPS,
246                          A_SHUFPD,
247                          A_SHUFPS:
248
249                            replaceoper:=-1;
250{$ifdef x86_64}
251                          A_MOV:
252                             { 64 bit constants can only be moved into registers }
253                             if (oper[0]^.typ=top_const) and
254                                (oper[1]^.typ=top_reg) and
255                                ((oper[0]^.val<low(longint)) or
256                                 (oper[0]^.val>high(longint))) then
257                               replaceoper:=-1;
258{$endif x86_64}
259                        end;
260                      end;
261                    end;
262                end;
263             end;
264
265            {$ifdef x86_64}
266            { 32 bit operations on 32 bit registers on x86_64 can result in
267              zeroing the upper 32 bits of the register. This does not happen
268              with memory operations, so we have to perform these calculations
269              in registers.  }
270            if (instr.opsize=S_L) then
271              replaceoper:=-1;
272            {$endif x86_64}
273
274            { Replace register with spill reference }
275            if replaceoper<>-1 then
276              begin
277                oper[replaceoper]^.typ:=top_ref;
278                new(oper[replaceoper]^.ref);
279                oper[replaceoper]^.ref^:=spilltemp;
280                { memory locations aren't guaranteed to be aligned }
281                case opcode of
282                  A_MOVAPS:
283                    opcode:=A_MOVSS;
284                  A_MOVAPD:
285                    opcode:=A_MOVSD;
286                end;
287                result:=true;
288              end;
289          end;
290      end;
291
292
293{******************************************************************************
294                                  Trgx86fpu
295******************************************************************************}
296
297    constructor Trgx86fpu.create;
298      begin
299        used_in_proc:=[];
300        unusedregsfpu:=usableregsfpu;
301      end;
302
303
304    function trgx86fpu.getregisterfpu(list: TAsmList) : tregister;
305      begin
306        { note: don't return R_ST0, see comments above implementation of }
307        { a_loadfpu_* methods in cgcpu (JM)                              }
308        result:=NR_ST;
309      end;
310
311
312    procedure trgx86fpu.ungetregisterfpu(list : TAsmList; r : tregister);
313      begin
314        { nothing to do, fpu stack management is handled by the load/ }
315        { store operations in cgcpu (JM)                              }
316      end;
317
318
319
320    function trgx86fpu.correct_fpuregister(r : tregister;ofs : byte) : tregister;
321      begin
322        correct_fpuregister:=r;
323        setsupreg(correct_fpuregister,ofs);
324      end;
325
326
327    procedure trgx86fpu.saveusedfpuregisters(list: TAsmList;
328                                             var saved : tpushedsavedfpu;
329                                             const s: tcpuregisterset);
330     { var
331         r : tregister;
332         hr : treference; }
333      begin
334        used_in_proc:=used_in_proc+s;
335
336{ TODO: firstsavefpureg}
337(*
338        { don't try to save the fpu registers if not desired (e.g. for }
339        { the 80x86)                                                   }
340        if firstsavefpureg <> R_NO then
341          for r.enum:=firstsavefpureg to lastsavefpureg do
342            begin
343              saved[r.enum].ofs:=reg_not_saved;
344              { if the register is used by the calling subroutine and if }
345              { it's not a regvar (those are handled separately)         }
346              if not is_reg_var_other[r.enum] and
347                 (r.enum in s) and
348                 { and is present in use }
349                 not(r.enum in unusedregsfpu) then
350                begin
351                  { then save it }
352                  tg.GetTemp(list,extended_size,tt_persistent,hr);
353                  saved[r.enum].ofs:=hr.offset;
354                  cg.a_loadfpu_reg_ref(list,OS_FLOAT,OS_FLOAT,r,hr);
355                  cg.a_reg_dealloc(list,r);
356                  include(unusedregsfpu,r.enum);
357                  inc(countunusedregsfpu);
358                end;
359            end;
360*)
361      end;
362
363
364    procedure trgx86fpu.restoreusedfpuregisters(list : TAsmList;
365                                                const saved : tpushedsavedfpu);
366{
367      var
368         r,r2 : tregister;
369         hr : treference;
370}
371      begin
372{ TODO: firstsavefpureg}
373(*
374        if firstsavefpureg <> R_NO then
375          for r.enum:=lastsavefpureg downto firstsavefpureg do
376            begin
377              if saved[r.enum].ofs <> reg_not_saved then
378                begin
379                  r2.enum:=R_INTREGISTER;
380                  r2.number:=NR_FRAME_POINTER_REG;
381                  reference_reset_base(hr,r2,saved[r.enum].ofs);
382                  cg.a_reg_alloc(list,r);
383                  cg.a_loadfpu_ref_reg(list,OS_FLOAT,OS_FLOAT,hr,r);
384                  if not (r.enum in unusedregsfpu) then
385                    { internalerror(10)
386                      in n386cal we always save/restore the reg *state*
387                      using save/restoreunusedstate -> the current state
388                      may not be real (JM) }
389                  else
390                    begin
391                      dec(countunusedregsfpu);
392                      exclude(unusedregsfpu,r.enum);
393                    end;
394                  tg.UnGetTemp(list,hr);
395                end;
396            end;
397*)
398      end;
399
400(*
401    procedure Trgx86fpu.saveotherregvars(list: TAsmList; const s: totherregisterset);
402      var
403        r: Tregister;
404      begin
405        if not(cs_opt_regvar in current_settings.optimizerswitches) then
406          exit;
407        if firstsavefpureg <> NR_NO then
408          for r.enum := firstsavefpureg to lastsavefpureg do
409            if is_reg_var_other[r.enum] and
410               (r.enum in s) then
411              store_regvar(list,r);
412      end;
413*)
414
415end.