Browse Source

* parameter passing is now more ABI compliant
* stack frame size optimization
* optimized (64 bit) constant loading
* some code generator code cleanup

git-svn-id: trunk@1539 -

tom_at_work 20 years ago
parent
commit
5fcb64f350

+ 103 - 128
compiler/powerpc64/cgcpu.pas

@@ -139,6 +139,13 @@ type
     { of asmcondflags and destination addressing mode                }
     { of asmcondflags and destination addressing mode                }
     procedure a_jmp(list: taasmoutput; op: tasmop;
     procedure a_jmp(list: taasmoutput; op: tasmop;
       c: tasmcondflag; crval: longint; l: tasmlabel);
       c: tasmcondflag; crval: longint; l: tasmlabel);
+
+    { returns the lowest numbered FP register in use, and the number of used FP registers 
+      for the current procedure }
+    procedure calcFirstUsedFPR(out firstfpr : TSuperRegister; out fprcount : aint);
+    { returns the lowest numbered GP register in use, and the number of used GP registers
+      for the current procedure }
+    procedure calcFirstUsedGPR(out firstgpr : TSuperRegister; out gprcount : aint);
   end;
   end;
 
 
 const
 const
@@ -350,26 +357,34 @@ end;
 procedure tcgppc.a_load_const_reg(list: taasmoutput; size: TCGSize; a: aint;
 procedure tcgppc.a_load_const_reg(list: taasmoutput; size: TCGSize; a: aint;
   reg: TRegister);
   reg: TRegister);
 
 
-var
-  scratchreg : TRegister;
-
-  procedure load32bitconstant(list : taasmoutput; size : TCGSize; a : longint;
-    reg : TRegister);
-  var is_half_signed : boolean;
+  { loads a 32 bit constant into the given register, using an optimal instruction sequence.
+    This is either LIS, LI or LI+ADDIS.
+    Returns true if during these operations the upper 32 bits were filled with 1 bits (e.g.
+    sign extension was performed) }
+  function load32bitconstant(list : taasmoutput; size : TCGSize; a : longint;
+    reg : TRegister) : boolean;
+  var 
+    is_half_signed : byte;
   begin
   begin
-(*
-    // ts: test optimized code using LI/ADDIS
-
+    { if the lower 16 bits are zero, do a single LIS }
     if (smallint(a) = 0) and ((a shr 16) <> 0) then begin
     if (smallint(a) = 0) and ((a shr 16) <> 0) then begin
-      list.concat(taicpu.op_reg_const(A_LIS, reg, smallint(a shr 16)));
+      list.concat(taicpu.op_reg_const(A_LIS, reg, smallint(hi(a))));
+      load32bitconstant := longint(a) < 0;
     end else begin
     end else begin
-      is_half_signed := smallint(a) < 0;
-      list.concat(taicpu.op_reg_const(A_LI, reg, smallint(a)));
-      if smallint((a shr 16) + ord(is_half_signed)) <> 0 then begin
-        list.concat(taicpu.op_reg_reg_const(A_ADDIS, reg, reg, smallint((a shr 16) + ord(is_half_signed))));
+      is_half_signed := ord(smallint(lo(a)) < 0);
+      list.concat(taicpu.op_reg_const(A_LI, reg, smallint(a and $ffff)));
+      if smallint(hi(a) + is_half_signed) <> 0 then begin
+        list.concat(taicpu.op_reg_reg_const(A_ADDIS, reg, reg, smallint(hi(a) + is_half_signed)));
       end;
       end;
+      load32bitconstant := (smallint(a) < 0) or (a < 0);
     end;
     end;
-*)
+  end;
+
+  { R0-safe version of the above (ADDIS doesn't work the same way with R0 as base), without
+    the return value }
+  procedure load32bitconstantR0(list : taasmoutput; size : TCGSize; a : longint;
+    reg : TRegister);
+  begin
     // only 16 bit constant? (-2^15 <= a <= +2^15-1)
     // only 16 bit constant? (-2^15 <= a <= +2^15-1)
     if (a >= low(smallint)) and (a <= high(smallint)) then begin
     if (a >= low(smallint)) and (a <= high(smallint)) then begin
       list.concat(taicpu.op_reg_const(A_LI, reg, smallint(a)));
       list.concat(taicpu.op_reg_const(A_LI, reg, smallint(a)));
@@ -378,56 +393,52 @@ var
       if ((a and $FFFF) <> 0) then begin
       if ((a and $FFFF) <> 0) then begin
         list.concat(taicpu.op_reg_const(A_LIS, reg, smallint(a shr 16)));
         list.concat(taicpu.op_reg_const(A_LIS, reg, smallint(a shr 16)));
         list.concat(taicpu.op_reg_reg_const(A_ORI, reg, reg, word(a)));
         list.concat(taicpu.op_reg_reg_const(A_ORI, reg, reg, word(a)));
-
       end else begin
       end else begin
         list.concat(taicpu.op_reg_const(A_LIS, reg, smallint(a shr 16)));
         list.concat(taicpu.op_reg_const(A_LIS, reg, smallint(a shr 16)));
       end;
       end;
     end;
     end;
-
   end;
   end;
+
 var
 var
+  extendssign : boolean;
+  {$IFDEF EXTDEBUG}
   astring : string;
   astring : string;
+  {$ENDIF EXTDEBUG}
 
 
 begin
 begin
-  astring := 'a_load_const reg ' + inttostr(a) + ' ' + inttostr(tcgsize2size[size]);
+  {$IFDEF EXTDEBUG}
+  astring := 'a_load_const reg ' + inttostr(hi(a)) + ' ' + inttostr(lo(a)) + ' ' + inttostr(ord(size)) + ' ' + inttostr(tcgsize2size[size]);
   list.concat(tai_comment.create(strpnew(astring)));
   list.concat(tai_comment.create(strpnew(astring)));
+  {$ENDIF EXTDEBUG}
+
   if not (size in [OS_8, OS_S8, OS_16, OS_S16, OS_32, OS_S32, OS_64, OS_S64]) then
   if not (size in [OS_8, OS_S8, OS_16, OS_S16, OS_32, OS_S32, OS_64, OS_S64]) then
     internalerror(2002090902);
     internalerror(2002090902);
-  // load low 32 bit (as signed number)
-  load32bitconstant(list, size, lo(a), reg);
-
-  // load high 32 bit if needed :( (the second expression is optimization, to be enabled and tested later!)
-  if (size in [OS_64, OS_S64]) {and (hi(a) <> 0)} then begin
-    // allocate scratch reg (=R0 because it might be called at places where register
-    // allocation has already happened - either procedure entry/exit, and stack check
-    // code generation)
-    // Note: I hope this restriction can be lifted at some time
-
-    //scratchreg := rg[R_INTREGISTER].getregister(list, R_SUBWHOLE);
-    // load high 32 bit
-    load32bitconstant(list, size, hi(a), NR_R0);
-    // combine both registers
-    list.concat(taicpu.op_reg_reg_const_const(A_RLDIMI, reg, NR_R0, 32, 0));
-  end;
-(*
-  // for 16/32 bit unsigned constants we need to make sure that the difference from this size to
-  // 32 bits is cleared (since we optimize loading them as signed 16 bit parts, but 32 bit ops are
-  // used for them.
-  // e.g. for 16 bit there's a problem if the (unsigned) constant is of the form
-  //   xx..xx xx..xx 00..00 1x..xx
-  // same problem as above for 32 bit: unsigned constants of the form
-  //   xx..xx xx..xx 00..00 1x..xx
-  // cause troubles. Signed are ok.
-  // for now, just clear the upper 48/32 bits (also because full 32 bit op usage isn't done yet)
-  if (size in [OS_16, OS_32]) {and (lo(a) < 0)} then begin
-    a_load_reg_reg(list, size, size, reg, reg);
-  end; *)
-  // need to clear MSB for unsigned 64 bit int because we did not load the upper
-  // 32 bit at all (second expression is optimization: enable and test later!)
-  // e.g. constants of the form 00..00 00..00 1x..xx xx..xx
-  if (size in [OS_64]) and (hi(a) = 0) then begin
-        list.concat(taicpu.op_reg_reg_const_const(A_RLDICL, reg, reg, 0, 32));
-  end;
+  if (lo(a) = 0) and (hi(a) <> 0) then begin
+    { load only upper 32 bits, and shift }
+    load32bitconstant(list, size, hi(a), reg);
+    list.concat(taicpu.op_reg_reg_const(A_SLDI, reg, reg, 32));    
+  end else begin
+    { load lower 32 bits }
+    extendssign := load32bitconstant(list, size, lo(a), reg);
+    if (extendssign) and (hi(a) = 0) then
+      { if upper 32 bits are zero, but loading the lower 32 bit resulted in automatic 
+        sign extension, clear those bits }
+      a_load_reg_reg(list, OS_32, OS_64, reg, reg)
+    else if (not 
+      ((extendssign and (longint(hi(a)) = -1)) or 
+       ((not extendssign) and (hi(a)=0)))
+      ) then begin
+      { only load the upper 32 bits, if the automatic sign extension is not okay,
+        that is, _not_ if 
+        - loading the lower 32 bits resulted in -1 in the upper 32 bits, and the upper 
+         32 bits should contain -1
+        - loading the lower 32 bits resulted in 0 in the upper 32 bits, and the upper
+         32 bits should contain 0 }
+      load32bitconstantR0(list, size, hi(a), NR_R0);
+      { combine both registers }
+      list.concat(taicpu.op_reg_reg_const_const(A_RLDIMI, reg, NR_R0, 32, 0));
+    end;
+  end;  
 end;
 end;
 
 
 procedure tcgppc.a_load_reg_ref(list: taasmoutput; fromsize, tosize: TCGSize;
 procedure tcgppc.a_load_reg_ref(list: taasmoutput; fromsize, tosize: TCGSize;
@@ -794,6 +805,7 @@ var
   signed: boolean;
   signed: boolean;
 
 
 begin
 begin
+  { todo: use 32 bit compares? }
   signed := cmp_op in [OC_GT, OC_LT, OC_GTE, OC_LTE];
   signed := cmp_op in [OC_GT, OC_LT, OC_GTE, OC_LTE];
   { in the following case, we generate more efficient code when }
   { in the following case, we generate more efficient code when }
   { signed is true                                              }
   { signed is true                                              }
@@ -803,16 +815,14 @@ begin
   if signed then
   if signed then
     if (a >= low(smallint)) and (a <= high(smallint)) then
     if (a >= low(smallint)) and (a <= high(smallint)) then
       list.concat(taicpu.op_reg_reg_const(A_CMPDI, NR_CR0, reg, a))
       list.concat(taicpu.op_reg_reg_const(A_CMPDI, NR_CR0, reg, a))
-    else
-    begin
+    else begin
       scratch_register := rg[R_INTREGISTER].getregister(list, R_SUBWHOLE);
       scratch_register := rg[R_INTREGISTER].getregister(list, R_SUBWHOLE);
       a_load_const_reg(list, OS_64, a, scratch_register);
       a_load_const_reg(list, OS_64, a, scratch_register);
       list.concat(taicpu.op_reg_reg_reg(A_CMPD, NR_CR0, reg, scratch_register));
       list.concat(taicpu.op_reg_reg_reg(A_CMPD, NR_CR0, reg, scratch_register));
     end
     end
   else if (aword(a) <= $FFFF) then
   else if (aword(a) <= $FFFF) then
     list.concat(taicpu.op_reg_reg_const(A_CMPLDI, NR_CR0, reg, aword(a)))
     list.concat(taicpu.op_reg_reg_const(A_CMPLDI, NR_CR0, reg, aword(a)))
-  else
-  begin
+  else begin
     scratch_register := rg[R_INTREGISTER].getregister(list, R_SUBWHOLE);
     scratch_register := rg[R_INTREGISTER].getregister(list, R_SUBWHOLE);
     a_load_const_reg(list, OS_64, a, scratch_register);
     a_load_const_reg(list, OS_64, a, scratch_register);
     list.concat(taicpu.op_reg_reg_reg(A_CMPLD, NR_CR0, reg,
     list.concat(taicpu.op_reg_reg_reg(A_CMPLD, NR_CR0, reg,
@@ -930,6 +940,40 @@ begin
   { this work is done in g_proc_exit }
   { this work is done in g_proc_exit }
 end;
 end;
 
 
+procedure tcgppc.calcFirstUsedFPR(out firstfpr : TSuperRegister; out fprcount : aint);
+var
+  reg : TSuperRegister;
+begin
+  fprcount := 0;
+  firstfpr := RS_F31;
+  if not (po_assembler in current_procinfo.procdef.procoptions) then begin
+    for reg := RS_F14 to RS_F31 do begin
+      if reg in rg[R_FPUREGISTER].used_in_proc then begin
+        fprcount := ord(RS_F31)-ord(reg)+1;
+        firstfpr := reg;
+        break;
+      end;
+    end;
+  end;
+end;
+
+procedure tcgppc.calcFirstUsedGPR(out firstgpr : TSuperRegister; out gprcount : aint);
+var
+  reg : TSuperRegister;
+begin
+  gprcount := 0;
+  firstgpr := RS_R31;
+  if not (po_assembler in current_procinfo.procdef.procoptions) then begin
+    for reg := RS_R14 to RS_R31 do begin
+      if reg in rg[R_INTREGISTER].used_in_proc then begin
+        gprcount := ord(RS_R31)-ord(reg)+1;
+        firstgpr := reg;
+        break;
+      end;
+    end;
+  end;
+end;
+
 procedure tcgppc.g_proc_entry(list: taasmoutput; localsize: longint;
 procedure tcgppc.g_proc_entry(list: taasmoutput; localsize: longint;
   nostackframe: boolean);
   nostackframe: boolean);
 { generated the entry code of a procedure/function. Note: localsize is the }
 { generated the entry code of a procedure/function. Note: localsize is the }
@@ -939,40 +983,6 @@ procedure tcgppc.g_proc_entry(list: taasmoutput; localsize: longint;
 { This procedure may be called before, as well as after g_return_from_proc }
 { This procedure may be called before, as well as after g_return_from_proc }
 { is called. NOTE registers are not to be allocated through the register   }
 { is called. NOTE registers are not to be allocated through the register   }
 { allocator here, because the register colouring has already occured !!    }
 { allocator here, because the register colouring has already occured !!    }
-  procedure calcFirstUsedFPR(out firstfpr : TSuperRegister; out fprcount : aint);
-  var
-    reg : TSuperRegister;
-  begin
-    fprcount := 0;
-    firstfpr := RS_F31;
-    if not (po_assembler in current_procinfo.procdef.procoptions) then begin
-      for reg := RS_F14 to RS_F31 do begin
-        if reg in rg[R_FPUREGISTER].used_in_proc then begin
-          fprcount := ord(RS_F31)-ord(reg)+1;
-          firstfpr := reg;
-          break;
-        end;
-      end;
-    end;
-  end;
-
-  procedure calcFirstUsedGPR(out firstgpr : TSuperRegister; out gprcount : aint);
-  var
-    reg : TSuperRegister;
-  begin
-    gprcount := 0;
-    firstgpr := RS_R31;
-    if not (po_assembler in current_procinfo.procdef.procoptions) then begin
-      for reg := RS_R14 to RS_R31 do begin
-        if reg in rg[R_INTREGISTER].used_in_proc then begin
-          gprcount := ord(RS_R31)-ord(reg)+1;
-          firstgpr := reg;
-          break;
-        end;
-      end;
-    end;
-  end;
-
 var
 var
   firstregfpu, firstreggpr: TSuperRegister;
   firstregfpu, firstreggpr: TSuperRegister;
   href: treference;
   href: treference;
@@ -1009,7 +1019,6 @@ begin
     a_reg_alloc(list, NR_R12);
     a_reg_alloc(list, NR_R12);
     list.concat(taicpu.op_reg_reg(A_MR, NR_R12, NR_STACK_POINTER_REG));
     list.concat(taicpu.op_reg_reg(A_MR, NR_R12, NR_STACK_POINTER_REG));
   end;
   end;
-
   // save registers, FPU first, then GPR
   // save registers, FPU first, then GPR
   reference_reset_base(href, NR_STACK_POINTER_REG, -8);
   reference_reset_base(href, NR_STACK_POINTER_REG, -8);
   if (fprcount > 0) then begin
   if (fprcount > 0) then begin
@@ -1072,45 +1081,11 @@ end;
 
 
 procedure tcgppc.g_proc_exit(list: taasmoutput; parasize: longint; nostackframe:
 procedure tcgppc.g_proc_exit(list: taasmoutput; parasize: longint; nostackframe:
   boolean);
   boolean);
-
-  procedure calcFirstUsedFPR(out firstfpr : TSuperRegister; out fprcount : aint);
-  var
-    reg : TSuperRegister;
-  begin
-    fprcount := 0;
-    firstfpr := RS_F31;
-    if not (po_assembler in current_procinfo.procdef.procoptions) then begin
-      for reg := RS_F14 to RS_F31 do begin
-        if reg in rg[R_FPUREGISTER].used_in_proc then begin
-          fprcount := ord(RS_F31)-ord(reg)+1;
-          firstfpr := reg;
-          break;
-        end;
-      end;
-    end;
-  end;
-
-  procedure calcFirstUsedGPR(out firstgpr : TSuperRegister; out gprcount : aint);
-  var
-    reg : TSuperRegister;
-  begin
-    gprcount := 0;
-    firstgpr := RS_R31;
-    if not (po_assembler in current_procinfo.procdef.procoptions) then begin
-      for reg := RS_R14 to RS_R31 do begin
-        if reg in rg[R_INTREGISTER].used_in_proc then begin
-          gprcount := ord(RS_R31)-ord(reg)+1;
-          firstgpr := reg;
-          break;
-        end;
-      end;
-    end;
-  end;
-
 { This procedure may be called before, as well as after g_stackframe_entry }
 { This procedure may be called before, as well as after g_stackframe_entry }
 { is called. NOTE registers are not to be allocated through the register   }
 { is called. NOTE registers are not to be allocated through the register   }
 { allocator here, because the register colouring has already occured !!    }
 { allocator here, because the register colouring has already occured !!    }
 
 
+
 var
 var
   regcount, firstregfpu, firstreggpr: TSuperRegister;
   regcount, firstregfpu, firstreggpr: TSuperRegister;
   href: treference;
   href: treference;
@@ -1443,7 +1418,7 @@ procedure tcgppc.g_intf_wrapper(list: TAAsmoutput; procdef: tprocdef; const
       procdef._class.vmtmethodoffset(procdef.extnumber));
       procdef._class.vmtmethodoffset(procdef.extnumber));
     if not ((aint(href.offset) >= low(smallint)) and
     if not ((aint(href.offset) >= low(smallint)) and
       (aint(href.offset) <= high(smallint))) then begin
       (aint(href.offset) <= high(smallint))) then begin
-      {$warning ts:adapt me}
+      {$warning ts:adapt me for offsets > 16 bit }
       list.concat(taicpu.op_reg_reg_const(A_ADDIS, NR_R11, NR_R11,
       list.concat(taicpu.op_reg_reg_const(A_ADDIS, NR_R11, NR_R11,
         smallint((href.offset shr 16) + ord(smallint(href.offset and $FFFF) <
         smallint((href.offset shr 16) + ord(smallint(href.offset and $FFFF) <
         0))));
         0))));

+ 1 - 1
compiler/powerpc64/cpubase.pas

@@ -19,7 +19,7 @@
 
 
  ****************************************************************************
  ****************************************************************************
 }
 }
-{ This Unit contains the base types for the PowerPC
+{ This Unit contains the base types for the PowerPC64
 }
 }
 unit cpubase;
 unit cpubase;
 
 

+ 58 - 155
compiler/powerpc64/cpupara.pas

@@ -87,18 +87,14 @@ begin
   cgpara.intsize := tcgsize2size[OS_INT];
   cgpara.intsize := tcgsize2size[OS_INT];
   cgpara.alignment := get_para_align(calloption);
   cgpara.alignment := get_para_align(calloption);
   paraloc := cgpara.add_location;
   paraloc := cgpara.add_location;
-  with paraloc^ do
-  begin
+  with paraloc^ do begin
     size := OS_INT;
     size := OS_INT;
-    if (nr <= 8) then
-    begin
+    if (nr <= 8) then begin
       if nr = 0 then
       if nr = 0 then
         internalerror(200309271);
         internalerror(200309271);
       loc := LOC_REGISTER;
       loc := LOC_REGISTER;
       register := newreg(R_INTREGISTER, RS_R2 + nr, R_SUBWHOLE);
       register := newreg(R_INTREGISTER, RS_R2 + nr, R_SUBWHOLE);
-    end
-    else
-    begin
+    end else begin
       loc := LOC_REFERENCE;
       loc := LOC_REFERENCE;
       paraloc^.reference.index := NR_STACK_POINTER_REG;
       paraloc^.reference.index := NR_STACK_POINTER_REG;
       if (target_info.abi <> abi_powerpc_aix) then
       if (target_info.abi <> abi_powerpc_aix) then
@@ -129,10 +125,7 @@ begin
     classrefdef:
     classrefdef:
       result := LOC_REGISTER;
       result := LOC_REGISTER;
     recorddef:
     recorddef:
-      if (target_info.abi <> abi_powerpc_aix) then
-        result := LOC_REFERENCE
-      else
-        result := LOC_REGISTER;
+      result := LOC_REGISTER;
     objectdef:
     objectdef:
       if is_object(p) then
       if is_object(p) then
         result := LOC_REFERENCE
         result := LOC_REFERENCE
@@ -183,7 +176,6 @@ begin
       result := true;
       result := true;
     recorddef:
     recorddef:
       result :=
       result :=
-        (target_info.abi <> abi_powerpc_aix) or
         ((varspez = vs_const) and
         ((varspez = vs_const) and
         ((calloption = pocall_mwpascal) or
         ((calloption = pocall_mwpascal) or
         (not (calloption in [pocall_cdecl, pocall_cppdecl]) and
         (not (calloption in [pocall_cdecl, pocall_cppdecl]) and
@@ -210,10 +202,11 @@ end;
 procedure tppcparamanager.init_values(var curintreg, curfloatreg, curmmreg:
 procedure tppcparamanager.init_values(var curintreg, curfloatreg, curmmreg:
   tsuperregister; var cur_stack_offset: aword);
   tsuperregister; var cur_stack_offset: aword);
 begin
 begin
+  { register parameter save area begins at 48(r2) }
   cur_stack_offset := 48;
   cur_stack_offset := 48;
   curintreg := RS_R3;
   curintreg := RS_R3;
   curfloatreg := RS_F1;
   curfloatreg := RS_F1;
-  curmmreg := RS_M1;
+  curmmreg := RS_M2;
 end;
 end;
 
 
 procedure tppcparamanager.create_funcretloc_info(p: tabstractprocdef; side:
 procedure tppcparamanager.create_funcretloc_info(p: tabstractprocdef; side:
@@ -230,36 +223,28 @@ begin
   location_reset(p.funcretloc[side], LOC_INVALID, OS_NO);
   location_reset(p.funcretloc[side], LOC_INVALID, OS_NO);
   p.funcretloc[side].size := retcgsize;
   p.funcretloc[side].size := retcgsize;
   { void has no location }
   { void has no location }
-  if is_void(p.rettype.def) then
-  begin
+  if is_void(p.rettype.def) then begin
     p.funcretloc[side].loc := LOC_VOID;
     p.funcretloc[side].loc := LOC_VOID;
     exit;
     exit;
   end;
   end;
 
 
   { Return in FPU register? }
   { Return in FPU register? }
-  if p.rettype.def.deftype = floatdef then
-  begin
+  if p.rettype.def.deftype = floatdef then begin
     p.funcretloc[side].loc := LOC_FPUREGISTER;
     p.funcretloc[side].loc := LOC_FPUREGISTER;
     p.funcretloc[side].register := NR_FPU_RESULT_REG;
     p.funcretloc[side].register := NR_FPU_RESULT_REG;
     p.funcretloc[side].size := retcgsize;
     p.funcretloc[side].size := retcgsize;
-  end
-  else
-    { Return in register? } if not ret_in_param(p.rettype.def, p.proccalloption)
-      then
-    begin
-      begin
-        p.funcretloc[side].loc := LOC_REGISTER;
-        p.funcretloc[side].size := retcgsize;
-        if side = callerside then
-          p.funcretloc[side].register := newreg(R_INTREGISTER,
-            RS_FUNCTION_RESULT_REG, cgsize2subreg(retcgsize))
-        else
-          p.funcretloc[side].register := newreg(R_INTREGISTER,
-            RS_FUNCTION_RETURN_REG, cgsize2subreg(retcgsize));
-      end;
-    end
-    else
-    begin
+  end else
+    { Return in register? } 
+    if not ret_in_param(p.rettype.def, p.proccalloption) then begin
+      p.funcretloc[side].loc := LOC_REGISTER;
+      p.funcretloc[side].size := retcgsize;
+      if side = callerside then
+        p.funcretloc[side].register := newreg(R_INTREGISTER,
+          RS_FUNCTION_RESULT_REG, cgsize2subreg(retcgsize))
+      else
+        p.funcretloc[side].register := newreg(R_INTREGISTER,
+          RS_FUNCTION_RETURN_REG, cgsize2subreg(retcgsize));
+    end else begin
       p.funcretloc[side].loc := LOC_REFERENCE;
       p.funcretloc[side].loc := LOC_REFERENCE;
       p.funcretloc[side].size := retcgsize;
       p.funcretloc[side].size := retcgsize;
     end;
     end;
@@ -282,8 +267,8 @@ end;
 
 
 function tppcparamanager.create_paraloc_info_intern(p: tabstractprocdef; side:
 function tppcparamanager.create_paraloc_info_intern(p: tabstractprocdef; side:
   tcallercallee; paras: tparalist;
   tcallercallee; paras: tparalist;
-  var curintreg, curfloatreg, curmmreg: tsuperregister; var cur_stack_offset:
-    aword): longint;
+var curintreg, curfloatreg, curmmreg: tsuperregister; var cur_stack_offset:
+  aword): longint;
 var
 var
   stack_offset: longint;
   stack_offset: longint;
   paralen: aint;
   paralen: aint;
@@ -309,13 +294,11 @@ begin
 
 
   maxfpureg := RS_F13;
   maxfpureg := RS_F13;
 
 
-  for i := 0 to paras.count - 1 do
-  begin
+  for i := 0 to paras.count - 1 do begin
     hp := tparavarsym(paras[i]);
     hp := tparavarsym(paras[i]);
     paradef := hp.vartype.def;
     paradef := hp.vartype.def;
     { Syscall for Morphos can have already a paraloc set }
     { Syscall for Morphos can have already a paraloc set }
-    if (vo_has_explicit_paraloc in hp.varoptions) then
-    begin
+    if (vo_has_explicit_paraloc in hp.varoptions) then begin
       if not (vo_is_syscall_lib in hp.varoptions) then
       if not (vo_is_syscall_lib in hp.varoptions) then
         internalerror(200412153);
         internalerror(200412153);
       continue;
       continue;
@@ -323,8 +306,7 @@ begin
     hp.paraloc[side].reset;
     hp.paraloc[side].reset;
     { currently only support C-style array of const }
     { currently only support C-style array of const }
     if (p.proccalloption in [pocall_cdecl, pocall_cppdecl]) and
     if (p.proccalloption in [pocall_cdecl, pocall_cppdecl]) and
-      is_array_of_const(paradef) then
-    begin
+      is_array_of_const(paradef) then begin
       paraloc := hp.paraloc[side].add_location;
       paraloc := hp.paraloc[side].add_location;
       { hack: the paraloc must be valid, but is not actually used }
       { hack: the paraloc must be valid, but is not actually used }
       paraloc^.loc := LOC_REGISTER;
       paraloc^.loc := LOC_REGISTER;
@@ -336,50 +318,37 @@ begin
     if (hp.varspez in [vs_var, vs_out]) or
     if (hp.varspez in [vs_var, vs_out]) or
       push_addr_param(hp.varspez, paradef, p.proccalloption) or
       push_addr_param(hp.varspez, paradef, p.proccalloption) or
       is_open_array(paradef) or
       is_open_array(paradef) or
-      is_array_of_const(paradef) then
-    begin
+      is_array_of_const(paradef) then begin
       paradef := voidpointertype.def;
       paradef := voidpointertype.def;
       loc := LOC_REGISTER;
       loc := LOC_REGISTER;
       paracgsize := OS_ADDR;
       paracgsize := OS_ADDR;
       paralen := tcgsize2size[OS_ADDR];
       paralen := tcgsize2size[OS_ADDR];
-    end
-    else
-    begin
+    end else begin
       if not is_special_array(paradef) then
       if not is_special_array(paradef) then
         paralen := paradef.size
         paralen := paradef.size
       else
       else
         paralen := tcgsize2size[def_cgsize(paradef)];
         paralen := tcgsize2size[def_cgsize(paradef)];
-      if (target_info.abi = abi_powerpc_aix) and
-        (paradef.deftype = recorddef) and
-        (hp.varspez in [vs_value, vs_const]) then
-      begin
+      if (paradef.deftype = recorddef) and
+        (hp.varspez in [vs_value, vs_const]) then begin
         { if a record has only one field and that field is }
         { if a record has only one field and that field is }
         { non-composite (not array or record), it must be  }
         { non-composite (not array or record), it must be  }
         { passed according to the rules of that type.       }
         { passed according to the rules of that type.       }
         if (trecorddef(hp.vartype.def).symtable.symindex.count = 1) and
         if (trecorddef(hp.vartype.def).symtable.symindex.count = 1) and
           (not trecorddef(hp.vartype.def).isunion) and
           (not trecorddef(hp.vartype.def).isunion) and
-          ((tabstractvarsym(trecorddef(hp.vartype.def).symtable.symindex.search(1)).vartype.def.deftype = floatdef) or
-          ((target_info.system = system_powerpc_darwin) and
-          (tabstractvarsym(trecorddef(hp.vartype.def).symtable.symindex.search(1)).vartype.def.deftype in [orddef, enumdef]))) then
-        begin
+          (tabstractvarsym(trecorddef(hp.vartype.def).symtable.symindex.search(1)).vartype.def.deftype = floatdef) then begin
           paradef :=
           paradef :=
             tabstractvarsym(trecorddef(hp.vartype.def).symtable.symindex.search(1)).vartype.def;
             tabstractvarsym(trecorddef(hp.vartype.def).symtable.symindex.search(1)).vartype.def;
           loc := getparaloc(paradef);
           loc := getparaloc(paradef);
           paracgsize := def_cgsize(paradef);
           paracgsize := def_cgsize(paradef);
-        end
-        else
-        begin
+        end else begin
           loc := LOC_REGISTER;
           loc := LOC_REGISTER;
           paracgsize := int_cgsize(paralen);
           paracgsize := int_cgsize(paralen);
         end;
         end;
-      end
-      else
-      begin
+      end else begin
         loc := getparaloc(paradef);
         loc := getparaloc(paradef);
         paracgsize := def_cgsize(paradef);
         paracgsize := def_cgsize(paradef);
         { for things like formaldef }
         { for things like formaldef }
-        if (paracgsize = OS_NO) then
-        begin
+        if (paracgsize = OS_NO) then begin
           paracgsize := OS_ADDR;
           paracgsize := OS_ADDR;
           paralen := tcgsize2size[OS_ADDR];
           paralen := tcgsize2size[OS_ADDR];
         end;
         end;
@@ -389,20 +358,16 @@ begin
     hp.paraloc[side].size := paracgsize;
     hp.paraloc[side].size := paracgsize;
     hp.paraloc[side].intsize := paralen;
     hp.paraloc[side].intsize := paralen;
     if (paralen = 0) then
     if (paralen = 0) then
-      if (paradef.deftype = recorddef) then
-      begin
+      if (paradef.deftype = recorddef) then begin
         paraloc := hp.paraloc[side].add_location;
         paraloc := hp.paraloc[side].add_location;
         paraloc^.loc := LOC_VOID;
         paraloc^.loc := LOC_VOID;
-      end
-      else
+      end else
         internalerror(2005011310);
         internalerror(2005011310);
     { can become < 0 for e.g. 3-byte records }
     { can become < 0 for e.g. 3-byte records }
-    while (paralen > 0) do
-    begin
+    while (paralen > 0) do begin
       paraloc := hp.paraloc[side].add_location;
       paraloc := hp.paraloc[side].add_location;
       if (loc = LOC_REGISTER) and
       if (loc = LOC_REGISTER) and
-        (nextintreg <= RS_R10) then
-      begin
+        (nextintreg <= RS_R10) then begin
         paraloc^.loc := loc;
         paraloc^.loc := loc;
         { make sure we don't lose whether or not the type is signed }
         { make sure we don't lose whether or not the type is signed }
         if (paradef.deftype <> orddef) then
         if (paradef.deftype <> orddef) then
@@ -414,29 +379,36 @@ begin
         paraloc^.register := newreg(R_INTREGISTER, nextintreg, R_SUBNONE);
         paraloc^.register := newreg(R_INTREGISTER, nextintreg, R_SUBNONE);
         inc(nextintreg);
         inc(nextintreg);
         dec(paralen, tcgsize2size[paraloc^.size]);
         dec(paralen, tcgsize2size[paraloc^.size]);
-        if target_info.abi = abi_powerpc_aix then
-          inc(stack_offset, tcgsize2size[paraloc^.size]);
-      end
-      else if (loc = LOC_FPUREGISTER) and
-        (nextfloatreg <= maxfpureg) then
-      begin
+
+        inc(stack_offset, tcgsize2size[paraloc^.size]);
+      end else if (loc = LOC_FPUREGISTER) and
+        (nextfloatreg <= maxfpureg) then begin
         paraloc^.loc := loc;
         paraloc^.loc := loc;
         paraloc^.size := paracgsize;
         paraloc^.size := paracgsize;
         paraloc^.register := newreg(R_FPUREGISTER, nextfloatreg, R_SUBWHOLE);
         paraloc^.register := newreg(R_FPUREGISTER, nextfloatreg, R_SUBWHOLE);
+        { the PPC64 ABI says that the GPR index is increased for every parameter, no matter
+        which type it is stored in }
+        inc(nextintreg);
         inc(nextfloatreg);
         inc(nextfloatreg);
         dec(paralen, tcgsize2size[paraloc^.size]);
         dec(paralen, tcgsize2size[paraloc^.size]);
-        { if nextfpureg > maxfpureg, all intregs are already used, since there }
-        { are less of those available for parameter passing in the AIX abi     }
-      end
-      else { LOC_REFERENCE }
-      begin
+
+        inc(stack_offset, tcgsize2size[paraloc^.size]);
+      end else if (loc = LOC_MMREGISTER) then begin
+        { Altivec not supported }
+        internalerror(200510192);
+      end else begin 
+        { either LOC_REFERENCE, or one of the above which must be passed on the
+        stack because of insufficient registers }
         paraloc^.loc := LOC_REFERENCE;
         paraloc^.loc := LOC_REFERENCE;
         paraloc^.size := int_cgsize(paralen);
         paraloc^.size := int_cgsize(paralen);
         if (side = callerside) then
         if (side = callerside) then
           paraloc^.reference.index := NR_STACK_POINTER_REG
           paraloc^.reference.index := NR_STACK_POINTER_REG
         else
         else
+          { during procedure entry, R12 contains the old stack pointer }
           paraloc^.reference.index := NR_R12;
           paraloc^.reference.index := NR_R12;
         paraloc^.reference.offset := stack_offset;
         paraloc^.reference.offset := stack_offset;
+
+        { TODO: change this to the next power of two (natural alignment) }
         inc(stack_offset, align(paralen, 8));
         inc(stack_offset, align(paralen, 8));
         paralen := 0;
         paralen := 0;
       end;
       end;
@@ -470,9 +442,7 @@ begin
     result := create_paraloc_info_intern(p, callerside, varargspara, curintreg,
     result := create_paraloc_info_intern(p, callerside, varargspara, curintreg,
       curfloatreg, curmmreg, cur_stack_offset);
       curfloatreg, curmmreg, cur_stack_offset);
     { varargs routines have to reserve at least 64 bytes for the AIX abi }
     { varargs routines have to reserve at least 64 bytes for the AIX abi }
-    { ts: dunno??? }
-    if (target_info.abi = abi_powerpc_aix) and
-      (result < 64) then
+    if (result < 64) then
       result := 64;
       result := 64;
   end
   end
   else
   else
@@ -497,76 +467,9 @@ begin
 end;
 end;
 
 
 function tppcparamanager.parseparaloc(p: tparavarsym; const s: string): boolean;
 function tppcparamanager.parseparaloc(p: tparavarsym; const s: string): boolean;
-var
-  paraloc: pcgparalocation;
-  paracgsize: tcgsize;
 begin
 begin
-  result := false;
-  case target_info.system of
-    system_powerpc_morphos:
-      begin
-        paracgsize := def_cgsize(p.vartype.def);
-        p.paraloc[callerside].alignment := 8;
-        p.paraloc[callerside].size := paracgsize;
-        p.paraloc[callerside].intsize := tcgsize2size[paracgsize];
-        paraloc := p.paraloc[callerside].add_location;
-        paraloc^.loc := LOC_REFERENCE;
-        paraloc^.size := paracgsize;
-        paraloc^.reference.index := newreg(R_INTREGISTER, RS_R2, R_SUBWHOLE);
-        { pattern is always uppercase'd }
-        if s = 'D0' then
-          paraloc^.reference.offset := 0
-        else if s = 'D1' then
-          paraloc^.reference.offset := 8
-        else if s = 'D2' then
-          paraloc^.reference.offset := 16
-        else if s = 'D3' then
-          paraloc^.reference.offset := 24
-        else if s = 'D4' then
-          paraloc^.reference.offset := 32
-        else if s = 'D5' then
-          paraloc^.reference.offset := 40
-        else if s = 'D6' then
-          paraloc^.reference.offset := 48
-        else if s = 'D7' then
-          paraloc^.reference.offset := 56
-        else if s = 'A0' then
-          paraloc^.reference.offset := 64
-        else if s = 'A1' then
-          paraloc^.reference.offset := 72
-        else if s = 'A2' then
-          paraloc^.reference.offset := 80
-        else if s = 'A3' then
-          paraloc^.reference.offset := 88
-        else if s = 'A4' then
-          paraloc^.reference.offset := 96
-        else if s = 'A5' then
-          paraloc^.reference.offset := 104
-            { 'A6' (offset 56) is used by mossyscall as libbase, so API
-            never passes parameters in it,
-            Indeed, but this allows to declare libbase either explicitly
-            or let the compiler insert it }
-        else if s = 'A6' then
-          paraloc^.reference.offset := 112
-            { 'A7' is the stack pointer on 68k, can't be overwritten
-            by API calls, so it has no offset }
-          { 'R12' is special, used internally to support r12base sysv
-            calling convention }
-        else if s = 'R12' then
-        begin
-          paraloc^.loc := LOC_REGISTER;
-          paraloc^.size := OS_ADDR;
-          paraloc^.register := NR_R12;
-        end
-        else
-          exit;
-
-        { copy to callee side }
-        p.paraloc[calleeside].add_location^ := paraloc^;
-      end;
-  else
-    internalerror(200404182);
-  end;
+  { not supported/required for PowerPC64-linux target }
+  internalerror(200404182);
   result := true;
   result := true;
 end;
 end;
 
 

+ 7 - 5
compiler/powerpc64/cpupi.pas

@@ -65,11 +65,13 @@ var
   locals: longint;
   locals: longint;
 begin
 begin
   if not (po_assembler in procdef.procoptions) then begin
   if not (po_assembler in procdef.procoptions) then begin
-    { always allocate space for 8 * 8 bytes for registers R3-R10 and stack header if
-      there's a stack frame }
-    if (maxpushedparasize < 64) then begin
-      maxpushedparasize := 64;
-    end;
+    { 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 (maxpushedparasize < 64) then begin
+    //  maxpushedparasize := 64;
+    // end;
+    { align the stack properly }
     ofs := align(maxpushedparasize + LinkageAreaSizeELF, ELF_STACK_ALIGN);
     ofs := align(maxpushedparasize + LinkageAreaSizeELF, ELF_STACK_ALIGN);
     tg.setfirsttemp(ofs);
     tg.setfirsttemp(ofs);
   end else begin
   end else begin