{
    Copyright (c) 2002 by Florian Klaempfl

    This unit contains the CPU specific part of tprocinfo

    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.

 ****************************************************************************
}

{ This unit contains the CPU specific part of tprocinfo. }
unit cpupi;

{$I fpcdefs.inc}

interface

uses
  cutils,aasmdata,
  procinfo, cpuinfo, psub;

type
  tppcprocinfo = class(tcgprocinfo)
    needstackframe: boolean;

    { offset where the frame pointer from the outer procedure is stored. }
    parent_framepointer_offset: longint;

    needs_frame_pointer : boolean;

    constructor create(aparent: tprocinfo); override;
    procedure set_first_temp_offset; override;
    function calc_stackframe_size: longint; override;
    function calc_stackframe_size(numgpr, numfpr : longint): longint;

    procedure allocate_got_register(list: TAsmList); override;
  end;

implementation

uses
  globtype, globals, systems,
  cpubase, cgbase,
  aasmtai,
  tgobj,cgobj,
  symconst, symsym, paramgr, symutil, symtable,
  verbose;

constructor tppcprocinfo.create(aparent: tprocinfo);

begin
  inherited create(aparent);
  maxpushedparasize := 0;
  needs_frame_pointer := false;
end;

procedure tppcprocinfo.set_first_temp_offset;
var
  ofs: aword;
begin
  if not (po_assembler in procdef.procoptions) then begin
    { align the stack properly }
    ofs := align(maxpushedparasize + LinkageAreaSizeELF, ELF_STACK_ALIGN);

    { the ABI specification says that it is required to always allocate space for 8 * 8 bytes
      for registers R3-R10 and stack header if there's a stack frame, but GCC doesn't do that,
      so we don't that too. Uncomment the next three lines if this is required }
    if (cs_profile in init_settings.moduleswitches) and (ofs < MINIMUM_STACKFRAME_SIZE) then begin
      ofs := MINIMUM_STACKFRAME_SIZE;
    end;
    tg.setfirsttemp(ofs);
  end else begin
    if (current_procinfo.procdef.localst.symtabletype=localsymtable) and
       (tabstractlocalsymtable(current_procinfo.procdef.localst).count_locals <> 0) then
      { at 0(r1), the previous value of r1 will be stored }
      tg.setfirsttemp(8);
  end;
end;

function tppcprocinfo.calc_stackframe_size: longint;
begin
  result := calc_stackframe_size(18, 18);
end;

function tppcprocinfo.calc_stackframe_size(numgpr, numfpr : longint) : longint;
begin
  { more or less copied from cgcpu.pas/g_stackframe_entry }
  if not (po_assembler in procdef.procoptions) then begin
    // no VMX support
    result := align(numgpr * sizeof(pint) +
        numfpr * tcgsize2size[OS_FLOAT], ELF_STACK_ALIGN);

    if (pi_do_call in flags) or (tg.lasttemp <> tg.firsttemp) or
      (result > RED_ZONE_SIZE) {or (cs_profile in init_settings.moduleswitches)} then begin
      result := align(result + tg.lasttemp, ELF_STACK_ALIGN);
      needstackframe:=true;
    end else
      needstackframe:=false;
  end else begin
    result := align(tg.lasttemp, ELF_STACK_ALIGN);
    needstackframe:=result<>0;
  end;
end;


procedure tppcprocinfo.allocate_got_register(list: TAsmList);
  begin
    if (target_info.system = system_powerpc64_darwin) and
       (cs_create_pic in current_settings.moduleswitches) then
      begin
        got := cg.getaddressregister(list);
      end;
  end;

begin
  cprocinfo := tppcprocinfo;
end.

