diff --git a/compiler/powerpc64/cgcpu.pas b/compiler/powerpc64/cgcpu.pas index fc5e534fb0..40632a2867 100644 --- a/compiler/powerpc64/cgcpu.pas +++ b/compiler/powerpc64/cgcpu.pas @@ -154,7 +154,14 @@ type immediate as required by some PowerPC instructions } function hasLargeOffset(const ref : TReference) : Boolean; inline; - procedure a_call_name_direct(list: taasmoutput; s: string; prependDot : boolean; addNOP : boolean); + { generates code to call a method with the given string name. The boolean options + control code generation. If prependDot is true, a single dot character is prepended to + the string, if addNOP is true a single NOP instruction is added after the call, and + if includeCall is true, the method is marked as having a call, not if false. This + option is particularly useful to prevent generation of a larger stack frame for the + register save and restore helper functions. } + procedure a_call_name_direct(list: taasmoutput; s: string; prependDot : boolean; + addNOP : boolean; includeCall : boolean = true); { emits code to store the given value a into the TOC (if not already in there), and load it from there as well } @@ -552,7 +559,7 @@ begin a_call_name_direct(list, s, true, true); end; -procedure tcgppc.a_call_name_direct(list: taasmoutput; s: string; prependDot : boolean; addNOP : boolean); +procedure tcgppc.a_call_name_direct(list: taasmoutput; s: string; prependDot : boolean; addNOP : boolean; includeCall : boolean); begin if (prependDot) then s := '.' + s; @@ -560,9 +567,9 @@ begin AT_FUNCTION))); if (addNOP) then list.concat(taicpu.op_none(A_NOP)); - { the compiler does not properly set this flag anymore in pass 1, and - for now we only need it after pass 2 (I hope) (JM) } - include(current_procinfo.flags, pi_do_call); + + if (includeCall) then + include(current_procinfo.flags, pi_do_call); end; @@ -1326,12 +1333,12 @@ var mayNeedLRStore := false; if ((fprcount > 0) and (gprcount > 0)) then begin a_op_const_reg_reg(list, OP_SUB, OS_INT, 8 * fprcount, NR_R1, NR_R12); - a_call_name_direct(list, '_savegpr1_' + intToStr(32-gprcount), false, false); - a_call_name_direct(list, '_savefpr_' + intToStr(32-fprcount), false, false); + a_call_name_direct(list, '_savegpr1_' + intToStr(32-gprcount), false, false, false); + a_call_name_direct(list, '_savefpr_' + intToStr(32-fprcount), false, false, false); end else if (gprcount > 0) then - a_call_name_direct(list, '_savegpr0_' + intToStr(32-gprcount), false, false) + a_call_name_direct(list, '_savegpr0_' + intToStr(32-gprcount), false, false, false) else if (fprcount > 0) then - a_call_name_direct(list, '_savefpr_' + intToStr(32-fprcount), false, false) + a_call_name_direct(list, '_savefpr_' + intToStr(32-fprcount), false, false, false) else mayNeedLRStore := true; end else begin @@ -1461,7 +1468,7 @@ var needsExitCode := false; if ((fprcount > 0) and (gprcount > 0)) then begin a_op_const_reg_reg(list, OP_SUB, OS_INT, 8 * fprcount, NR_R1, NR_R12); - a_call_name_direct(list, '_restgpr1_' + intToStr(32-gprcount), false, false); + a_call_name_direct(list, '_restgpr1_' + intToStr(32-gprcount), false, false, false); a_jmp_name(list, '_restfpr_' + intToStr(32-fprcount)); end else if (gprcount > 0) then a_jmp_name(list, '_restgpr0_' + intToStr(32-gprcount)) @@ -1520,7 +1527,6 @@ begin { calculate stack frame } localsize := tppcprocinfo(current_procinfo).calc_stackframe_size( gprcount, fprcount); - { CR register not supported } { restore stack pointer } @@ -1656,15 +1662,21 @@ begin internalerror(2002072704); list.concat(tai_comment.create(strpnew('g_concatcopy1 ' + inttostr(len) + ' bytes left '))); {$ENDIF extdebug} + { if the references are equal, exit, there is no need to copy anything } + if (references_equal(source, dest)) then + exit; + { make sure short loads are handled as optimally as possible; note that the data here never overlaps, so we can do a forward copy at all times. NOTE: maybe use some scratch registers to pair load/store instructions } - + if (len <= maxmoveunit) then begin src := source; dst := dest; + {$IFDEF extdebug} list.concat(tai_comment.create(strpnew('g_concatcopy3 ' + inttostr(src.offset) + ' ' + inttostr(dst.offset)))); + {$ENDIF extdebug} while (len <> 0) do begin if (len = 8) then begin a_load_ref_ref(list, OS_64, OS_64, src, dst); @@ -2167,7 +2179,7 @@ begin ref.refaddr := addr_pic; {$IFDEF EXTDEBUG} - list.concat(tai_comment.create(strpnew('loading value from TOC reference for ' + symbol))); + list.concat(tai_comment.create(strpnew('loading value from TOC reference for ' + symname))); {$ENDIF EXTDEBUG} cg.a_load_ref_reg(list, OS_INT, OS_INT, ref, reg); end; diff --git a/compiler/powerpc64/cpupara.pas b/compiler/powerpc64/cpupara.pas index 2ce3d168b9..25b3257921 100644 --- a/compiler/powerpc64/cpupara.pas +++ b/compiler/powerpc64/cpupara.pas @@ -47,6 +47,7 @@ type tvarargsparalist): longint; override; procedure create_funcretloc_info(p: tabstractprocdef; side: tcallercallee); + procedure createtempparaloc(list: taasmoutput;calloption : tproccalloption;parasym : tparavarsym;var cgpara:TCGPara); private procedure init_values(var curintreg, curfloatreg, curmmreg: tsuperregister; var cur_stack_offset: aword); @@ -487,6 +488,20 @@ begin result := true; end; +procedure tppcparamanager.createtempparaloc(list: taasmoutput;calloption : tproccalloption;parasym : tparavarsym;var cgpara:TCGPara); +var + paraloc : pcgparalocation; +begin + paraloc:=parasym.paraloc[callerside].location; + { Do not create a temporary if the value is pushed } + if assigned(paraloc) and + (paraloc^.loc=LOC_REFERENCE) and + (paraloc^.reference.index=NR_STACK_POINTER_REG) then + duplicateparaloc(list,calloption,parasym,cgpara) + else + inherited createtempparaloc(list,calloption,parasym,cgpara); +end; + begin paramanager := tppcparamanager.create; end. diff --git a/compiler/powerpc64/cpupi.pas b/compiler/powerpc64/cpupi.pas index 5161bd312e..ab1c8eacd7 100644 --- a/compiler/powerpc64/cpupi.pas +++ b/compiler/powerpc64/cpupi.pas @@ -106,9 +106,10 @@ begin result := align(numgpr * tcgsize2size[OS_INT] + numfpr * tcgsize2size[OS_FLOAT], ELF_STACK_ALIGN); - if not ((not (pi_do_call in flags)) and (tg.lasttemp = tg.firsttemp) and - (result <= RED_ZONE_SIZE)) then + if (pi_do_call in flags) or (tg.lasttemp <> tg.firsttemp) or + (result > RED_ZONE_SIZE) then begin result := align(result + tg.lasttemp, ELF_STACK_ALIGN); + end; end else result := align(tg.lasttemp, ELF_STACK_ALIGN); end;