* ppc64: with -Or the compiler now also generates calls to helper functions in the function prolog/epilog instead of multiple stores/loads

* ppc64: moved function prolog/epilog helper code into startup code
* ppc64: added FPU configuration code in math unit (fixes tw3161)

git-svn-id: trunk@1786 -
This commit is contained in:
tom_at_work 2005-11-20 01:20:55 +00:00
parent cc44a19af5
commit 651f34e27c
6 changed files with 865 additions and 493 deletions
compiler/powerpc64
rtl

View File

@ -546,7 +546,7 @@ begin
{ call ptrgl helper routine which expects the pointer to the function descriptor
in R11 }
a_load_reg_reg(list, OS_ADDR, OS_ADDR, reg, NR_R11);
a_call_name_direct(list, 'ptrgl', true, false);
a_call_name_direct(list, '.ptrgl', false, false);
end;
{ we need to load the old RTOC from stackframe because we changed it}
@ -1185,12 +1185,14 @@ end;
procedure tcgppc.g_save_standard_registers(list: Taasmoutput);
begin
{ this work is done in g_proc_entry }
{ this work is done in g_proc_entry; additionally it is not safe
to use it because it is called at some weird time }
end;
procedure tcgppc.g_restore_standard_registers(list: Taasmoutput);
begin
{ this work is done in g_proc_exit }
{ this work is done in g_proc_exit; mainly because it is not safe to
put the register restore code here because it is called at some weird time }
end;
procedure tcgppc.calcFirstUsedFPR(out firstfpr : TSuperRegister; out fprcount : aint);
@ -1199,15 +1201,13 @@ var
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 not (po_assembler in current_procinfo.procdef.procoptions) then
for reg := RS_F14 to RS_F31 do
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);
@ -1216,42 +1216,87 @@ var
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 not (po_assembler in current_procinfo.procdef.procoptions) then
for reg := RS_R14 to RS_R31 do
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;
{ Generates the entry code of a procedure/function.
This procedure may be called before, as well as after g_return_from_proc
is called. localsize is the sum of the size necessary for local variables
and the maximum possible combined size of ALL the parameters of a procedure
called by the current one
IMPORTANT: registers are not to be allocated through the register
allocator here, because the register colouring has already occured !!
}
procedure tcgppc.g_proc_entry(list: taasmoutput; localsize: longint;
nostackframe: boolean);
{ generated the entry code of a procedure/function. Note: localsize is the
sum of the size necessary for local variables and the maximum possible
combined size of ALL the parameters of a procedure called by the current
one.
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
allocator here, because the register colouring has already occured !! }
var
firstregfpu, firstreggpr: TSuperRegister;
href: treference;
needslinkreg: boolean;
regcount : TSuperRegister;
fprcount, gprcount : aint;
begin
{ CR and LR only have to be saved in case they are modified by the current
procedure, but currently this isn't checked, so save them always
following is the entry code as described in "Altivec Programming
Interface Manual", bar the saving of AltiVec registers }
a_reg_alloc(list, NR_STACK_POINTER_REG);
a_reg_alloc(list, NR_R0);
{ Save standard registers, both FPR and GPR; does not support VMX/Altivec }
procedure save_standard_registers;
var
regcount : TSuperRegister;
href : TReference;
mayNeedLRStore : boolean;
begin
{ there are two ways to do this: manually, by generating a few "std" instructions,
or via the restore helper functions. The latter are selected by the -Og switch,
i.e. "optimize for size" }
if (cs_littlesize in aktglobalswitches) then begin
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);
end else if (gprcount > 0) then
a_call_name_direct(list, '_savegpr0_' + intToStr(32-gprcount), false, false)
else if (fprcount > 0) then
a_call_name_direct(list, '_savefpr_' + intToStr(32-fprcount), false, false)
else
mayNeedLRStore := true;
end else begin
{ save registers, FPU first, then GPR }
reference_reset_base(href, NR_STACK_POINTER_REG, -8);
if (fprcount > 0) then
for regcount := RS_F31 downto firstregfpu do begin
a_loadfpu_reg_ref(list, OS_FLOAT, newreg(R_FPUREGISTER, regcount,
R_SUBNONE), href);
dec(href.offset, tcgsize2size[OS_FLOAT]);
end;
if (gprcount > 0) then
for regcount := RS_R31 downto firstreggpr do begin
a_load_reg_ref(list, OS_INT, OS_INT, newreg(R_INTREGISTER, regcount,
R_SUBNONE), href);
dec(href.offset, tcgsize2size[OS_INT]);
end;
{ VMX registers not supported by FPC atm }
{ in this branch we may always need to store LR ourselves}
mayNeedLRStore := true;
end;
{ we may need to store R0 (=LR) ourselves }
if (mayNeedLRStore) and (needslinkreg) then begin
reference_reset_base(href, NR_STACK_POINTER_REG, LA_LR_ELF);
list.concat(taicpu.op_reg_ref(A_STD, NR_R0, href));
end;
end;
var
href: treference;
begin
calcFirstUsedFPR(firstregfpu, fprcount);
calcFirstUsedGPR(firstreggpr, gprcount);
@ -1260,42 +1305,24 @@ begin
gprcount, fprcount);
{ determine whether we need to save the link register }
needslinkreg := ((not (po_assembler in current_procinfo.procdef.procoptions)) and
(pi_do_call in current_procinfo.flags));
needslinkreg :=
((not (po_assembler in current_procinfo.procdef.procoptions)) and (pi_do_call in current_procinfo.flags)) or
((cs_littlesize in aktglobalswitches) and ((fprcount > 0) or (gprcount > 0)));
a_reg_alloc(list, NR_STACK_POINTER_REG);
a_reg_alloc(list, NR_R0);
{ move link register to r0 }
if (needslinkreg) then begin
if (needslinkreg) then
list.concat(taicpu.op_reg(A_MFLR, NR_R0));
end;
save_standard_registers;
{ save old stack frame pointer }
if (localsize > 0) then begin
a_reg_alloc(list, NR_OLD_STACK_POINTER_REG);
list.concat(taicpu.op_reg_reg(A_MR, NR_OLD_STACK_POINTER_REG, NR_STACK_POINTER_REG));
end;
{ save registers, FPU first, then GPR }
reference_reset_base(href, NR_STACK_POINTER_REG, -8);
if (fprcount > 0) then begin
for regcount := RS_F31 downto firstregfpu do begin
a_loadfpu_reg_ref(list, OS_FLOAT, newreg(R_FPUREGISTER, regcount,
R_SUBNONE), href);
dec(href.offset, tcgsize2size[OS_FLOAT]);
end;
end;
if (gprcount > 0) then begin
for regcount := RS_R31 downto firstreggpr do begin
a_load_reg_ref(list, OS_INT, OS_INT, newreg(R_INTREGISTER, regcount,
R_SUBNONE), href);
dec(href.offset, tcgsize2size[OS_INT]);
end;
end;
{ VMX registers not supported by FPC atm }
{ we may need to store R0 (=LR) ourselves }
if (needslinkreg) then begin
reference_reset_base(href, NR_STACK_POINTER_REG, LA_LR_ELF);
list.concat(taicpu.op_reg_ref(A_STD, NR_R0, href));
end;
{ create stack frame }
if (not nostackframe) and (localsize > 0) then begin
@ -1305,10 +1332,11 @@ begin
end else begin
reference_reset_base(href, NR_NO, -localsize);
{ use R0 for loading the constant (which is definitely > 32k when entering
this branch)
{ Use R0 for loading the constant (which is definitely > 32k when entering
this branch).
Inlined at this position because it must not use temp registers because
register allocations have already been done :( }
register allocations have already been done }
{ Code template:
lis r0,ofs@highest
ori r0,r0,ofs@higher
@ -1325,30 +1353,99 @@ begin
list.concat(taicpu.op_reg_reg_reg(A_STDUX, NR_R1, NR_R1, NR_R0));
end;
end;
{ CR register not used by FPC atm }
{ keep R1 allocated??? }
a_reg_dealloc(list, NR_R0);
end;
{ Generates the exit code for a method.
This procedure may be called before, as well as after g_stackframe_entry
is called.
IMPORTANT: registers are not to be allocated through the register
allocator here, because the register colouring has already occured !!
}
procedure tcgppc.g_proc_exit(list: taasmoutput; parasize: longint; nostackframe:
boolean);
{ 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 }
{ allocator here, because the register colouring has already occured !! }
var
regcount, firstregfpu, firstreggpr: TSuperRegister;
href: treference;
firstregfpu, firstreggpr: TSuperRegister;
needslinkreg : boolean;
localsize,
fprcount, gprcount: aint;
{ Restore standard registers, both FPR and GPR; does not support VMX/Altivec }
procedure restore_standard_registers;
var
{ flag indicating whether we need to manually add the exit code (e.g. blr instruction)
or not }
needsExitCode : Boolean;
href : treference;
regcount : TSuperRegister;
begin
{ there are two ways to do this: manually, by generating a few "ld" instructions,
or via the restore helper functions. The latter are selected by the -Og switch,
i.e. "optimize for size" }
if (cs_littlesize in aktglobalswitches) then begin
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_jmp_name(list, '_restfpr_' + intToStr(32-fprcount));
end else if (gprcount > 0) then
a_jmp_name(list, '_restgpr0_' + intToStr(32-gprcount))
else if (fprcount > 0) then
a_jmp_name(list, '_restfpr_' + intToStr(32-fprcount))
else
needsExitCode := true;
end else begin
needsExitCode := true;
{ restore registers, FPU first, GPR next }
reference_reset_base(href, NR_STACK_POINTER_REG, -tcgsize2size[OS_FLOAT]);
if (fprcount > 0) then
for regcount := RS_F31 downto firstregfpu do begin
a_loadfpu_ref_reg(list, OS_FLOAT, href, newreg(R_FPUREGISTER, regcount,
R_SUBNONE));
dec(href.offset, tcgsize2size[OS_FLOAT]);
end;
if (gprcount > 0) then
for regcount := RS_R31 downto firstreggpr do begin
a_load_ref_reg(list, OS_INT, OS_INT, href, newreg(R_INTREGISTER, regcount,
R_SUBNONE));
dec(href.offset, tcgsize2size[OS_INT]);
end;
{ VMX not supported by FPC atm }
end;
if (needsExitCode) then begin
{ restore LR (if needed) }
if (needslinkreg) then begin
reference_reset_base(href, NR_STACK_POINTER_REG, LA_LR_ELF);
list.concat(taicpu.op_reg_ref(A_LD, NR_R0, href));
list.concat(taicpu.op_reg(A_MTLR, NR_R0));
end;
{ generate return instruction }
list.concat(taicpu.op_none(A_BLR));
end;
end;
var
href: treference;
localsize : aint;
begin
calcFirstUsedFPR(firstregfpu, fprcount);
calcFirstUsedGPR(firstreggpr, gprcount);
{ determine whether we need to restore the link register }
needslinkreg := ((not (po_assembler in current_procinfo.procdef.procoptions)) and
(pi_do_call in current_procinfo.flags));
needslinkreg :=
((not (po_assembler in current_procinfo.procdef.procoptions)) and (pi_do_call in current_procinfo.flags)) or
((cs_littlesize in aktglobalswitches) and ((fprcount > 0) or (gprcount > 0)));
{ calculate stack frame }
localsize := tppcprocinfo(current_procinfo).calc_stackframe_size(
gprcount, fprcount);
@ -1365,13 +1462,14 @@ begin
{ use R0 for loading the constant (which is definitely > 32k when entering
this branch)
Inlined because it must not use temp registers because register allocations
have already been done :( }
have already been done
}
{ Code template:
lis r0,ofs@highest
ori r0,ofs@higher
sldi r0,r0,32
oris r0,r0,ofs@h
ori r0,r0,ofs@l
lis r0,ofs@highest
ori r0,ofs@higher
sldi r0,r0,32
oris r0,r0,ofs@h
ori r0,r0,ofs@l
}
list.concat(taicpu.op_reg_const(A_LIS, NR_R0, word(href.offset shr 48)));
list.concat(taicpu.op_reg_reg_const(A_ORI, NR_R0, NR_R0, word(href.offset shr 32)));
@ -1383,35 +1481,7 @@ begin
end;
end;
{ load registers, FPR first, then GPR }
{$note ts:todo change order of loading}
reference_reset_base(href, NR_STACK_POINTER_REG, -tcgsize2size[OS_FLOAT]);
if (fprcount > 0) then begin
for regcount := RS_F31 downto firstregfpu do begin
a_loadfpu_ref_reg(list, OS_FLOAT, href, newreg(R_FPUREGISTER, regcount,
R_SUBNONE));
dec(href.offset, tcgsize2size[OS_FLOAT]);
end;
end;
if (gprcount > 0) then begin
for regcount := RS_R31 downto firstreggpr do begin
a_load_ref_reg(list, OS_INT, OS_INT, href, newreg(R_INTREGISTER, regcount,
R_SUBNONE));
dec(href.offset, tcgsize2size[OS_INT]);
end;
end;
{ VMX not supported... }
{ restore LR (if needed) }
if (needslinkreg) then begin
reference_reset_base(href, NR_STACK_POINTER_REG, LA_LR_ELF);
list.concat(taicpu.op_reg_ref(A_LD, NR_R0, href));
list.concat(taicpu.op_reg(A_MTLR, NR_R0));
end;
{ generate return instruction }
list.concat(taicpu.op_none(A_BLR));
restore_standard_registers;
end;

View File

@ -54,8 +54,18 @@
.globl .\fn
.\fn:
.endm
/* "ptrgl" glue code */
/*
* "ptrgl" glue code for calls via pointer. This function
* sequence loads the data from the function descriptor
* referenced by R11 into the CTR register (function address),
* R2 (GOT/TOC pointer), and R11 (the outer frame pointer).
*
* On entry, R11 must be set to point to the function descriptor.
*
* See also the 64-bit PowerPC ABI specification for more
* information, chapter 3.5.11 (in v1.7).
*/
.section ".text"
.align 3
.globl .ptrgl
@ -67,10 +77,267 @@
ld 11, 8(11)
bctr
.long 0
.byte 0, 12, 0, 0, 0, 0, 0, 0
.byte 0, 12, 128, 0, 0, 0, 0, 0
.type .ptrgl, @function
.size .ptrgl, . - .ptrgl
/*
* Function prolog/epilog helpers, which are part of the 64-bit
* PowerPC ABI.
*
* See also the 64-bit PowerPC ABI specification for more
* information, chapter 3.5.5, "Register saving and restoring
* function" (in v1.7).
*/
/* Each _savegpr0_N routine saves the general registers from rN to r31,
* inclusive. When the routine is called, r1 must point to the start
* of the general register save area. R0 must contain the old LR on
* entry.
*/
_savegpr0_14: std 14,-144(1)
_savegpr0_15: std 15,-136(1)
_savegpr0_16: std 16,-128(1)
_savegpr0_17: std 17,-120(1)
_savegpr0_18: std 18,-112(1)
_savegpr0_19: std 19,-104(1)
_savegpr0_20: std 20,-96(1)
_savegpr0_21: std 21,-88(1)
_savegpr0_22: std 22,-80(1)
_savegpr0_23: std 23,-72(1)
_savegpr0_24: std 24,-64(1)
_savegpr0_25: std 25,-56(1)
_savegpr0_26: std 26,-48(1)
_savegpr0_27: std 27,-40(1)
_savegpr0_28: std 28,-32(1)
_savegpr0_29: std 29,-24(1)
_savegpr0_30: std 30,-16(1)
_savegpr0_31:
std 31,-8(1)
std 0, 16(1)
blr
.long 0
.byte 0, 12, 64, 0, 0, 0, 0, 0
/* Each _restgpr0_N routine restores the general registers from rN to r31,
* inclusive. When the routine is called, r1 must point to the start
* of the general register save area.
*/
_restgpr0_14: ld 14,-144(1)
_restgpr0_15: ld 15,-136(1)
_restgpr0_16: ld 16,-128(1)
_restgpr0_17: ld 17,-120(1)
_restgpr0_18: ld 18,-112(1)
_restgpr0_19: ld 19,-104(1)
_restgpr0_20: ld 20,-96(1)
_restgpr0_21: ld 21,-88(1)
_restgpr0_22: ld 22,-80(1)
_restgpr0_23: ld 23,-72(1)
_restgpr0_24: ld 24,-64(1)
_restgpr0_25: ld 25,-56(1)
_restgpr0_26: ld 26,-48(1)
_restgpr0_27: ld 27,-40(1)
_restgpr0_28: ld 28,-32(1)
_restgpr0_29:
ld 0, 16(1)
ld 29,-24(1)
mtlr 0
ld 30,-16(1)
ld 31,-8(1)
blr
.long 0
.byte 0, 12, 64, 0, 0, 0, 0, 0
_restgpr0_30: ld 30,-16(1)
_restgpr0_31: ld 0, 16(1)
ld 31,-8(1)
mtlr 0
blr
.long 0
.byte 0, 12, 64, 0, 0, 0, 0, 0
/* Each _savegpr1_N routine saves the general registers from rN to r31,
* inclusive. When the routine is called, r12
* must point to the start of the general register save area.
*/
_savegpr1_14: std 14,-144(12)
_savegpr1_15: std 15,-136(12)
_savegpr1_16: std 16,-128(12)
_savegpr1_17: std 17,-120(12)
_savegpr1_18: std 18,-112(12)
_savegpr1_19: std 19,-104(12)
_savegpr1_20: std 20,-96(12)
_savegpr1_21: std 21,-88(12)
_savegpr1_22: std 22,-80(12)
_savegpr1_23: std 23,-72(12)
_savegpr1_24: std 24,-64(12)
_savegpr1_25: std 25,-56(12)
_savegpr1_26: std 26,-48(12)
_savegpr1_27: std 27,-40(12)
_savegpr1_28: std 28,-32(12)
_savegpr1_29: std 29,-24(12)
_savegpr1_30: std 30,-16(12)
_savegpr1_31: std 31,-8(12)
blr
.long 0
.byte 0, 12, 64, 0, 0, 0, 0, 0
/* The _restgpr1_N routines restore the general registers from rN to r31.
* When the routine is called, r12 must point to the start of the general
* register save area.
*/
_restgpr1_14: ld 14,-144(12)
_restgpr1_15: ld 15,-136(12)
_restgpr1_16: ld 16,-128(12)
_restgpr1_17: ld 17,-120(12)
_restgpr1_18: ld 18,-112(12)
_restgpr1_19: ld 19,-104(12)
_restgpr1_20: ld 20,-96(12)
_restgpr1_21: ld 21,-88(12)
_restgpr1_22: ld 22,-80(12)
_restgpr1_23: ld 23,-72(12)
_restgpr1_24: ld 24,-64(12)
_restgpr1_25: ld 25,-56(12)
_restgpr1_26: ld 26,-48(12)
_restgpr1_27: ld 27,-40(12)
_restgpr1_28: ld 28,-32(12)
_restgpr1_29: ld 29,-24(12)
_restgpr1_30: ld 30,-16(12)
_restgpr1_31: ld 31,-8(12)
blr
.long 0
.byte 0, 12, 64, 0, 0, 0, 0, 0
/* Each _savefpr_M routine saves the floating point registers from fM to f31,
* inclusive. When the routine is called, r1 must point to the start of the
* floating point register save area, and r0 must contain the value of LR on
* function entry.
*/
_savefpr_14: stfd 14,-144(1)
_savefpr_15: stfd 15,-136(1)
_savefpr_16: stfd 16,-128(1)
_savefpr_17: stfd 17,-120(1)
_savefpr_18: stfd 18,-112(1)
_savefpr_19: stfd 19,-104(1)
_savefpr_20: stfd 20,-96(1)
_savefpr_21: stfd 21,-88(1)
_savefpr_22: stfd 22,-80(1)
_savefpr_23: stfd 23,-72(1)
_savefpr_24: stfd 24,-64(1)
_savefpr_25: stfd 25,-56(1)
_savefpr_26: stfd 26,-48(1)
_savefpr_27: stfd 27,-40(1)
_savefpr_28: stfd 28,-32(1)
_savefpr_29: stfd 29,-24(1)
_savefpr_30: stfd 30,-16(1)
_savefpr_31: stfd 31,-8(1)
std 0, 16(1)
blr
.long 0
.byte 0, 12, 64, 0, 0, 0, 0, 0
/* The _restfpr_M routines restore the floating point registers from fM to f31.
* When the routine is called, r1 must point to the start of the floating point
* register save area.
*/
_restfpr_14: lfd 14,-144(1)
_restfpr_15: lfd 15,-136(1)
_restfpr_16: lfd 16,-128(1)
_restfpr_17: lfd 17,-120(1)
_restfpr_18: lfd 18,-112(1)
_restfpr_19: lfd 19,-104(1)
_restfpr_20: lfd 20,-96(1)
_restfpr_21: lfd 21,-88(1)
_restfpr_22: lfd 22,-80(1)
_restfpr_23: lfd 23,-72(1)
_restfpr_24: lfd 24,-64(1)
_restfpr_25: lfd 25,-56(1)
_restfpr_26: lfd 26,-48(1)
_restfpr_27: lfd 27,-40(1)
_restfpr_28: lfd 28,-32(1)
_restfpr_29:
ld 0, 16(1)
lfd 29,-24(1)
mtlr 0
lfd 30,-16(1)
lfd 31,-8(1)
blr
.long 0
.byte 0, 12, 64, 0, 0, 0, 0, 0
_restfpr_30: lfd 30,-16(1)
_restfpr_31:
ld 0, 16(1)
lfd 31,-8(1)
mtlr 0
blr
.long 0
.byte 0, 12, 64, 0, 0, 0, 0, 0
/* Each _savevr_M routine saves the vector registers from vM to v31, inclusive.
* When the routine is called, r0 must point to the word just beyound the end
* of the vector register save area. On return the value of r0 is unchanged
* while r12 may be modified.
*/
/* commented out for now, unused
_savevr_20: addi r12,r0,-192
stvx v20,r12,r0
_savevr_21: addi r12,r0,-176
stvx v21,r12,r0
_savevr_22: addi r12,r0,-160
stvx v22,r12,r0
_savevr_23: addi r12,r0,-144
stvx v23,r12,r0
_savevr_24: addi r12,r0,-128
stvx v24,r12,r0
_savevr_25: addi r12,r0,-112
stvx v25,r12,r0
_savevr_26: addi r12,r0,-96
stvx v26,r12,r0
_savevr_27: addi r12,r0,-80
stvx v27,r12,r0
_savevr_28: addi r12,r0,-64
stvx v28,r12,r0
_savevr_29: addi r12,r0,-48
stvx v29,r12,r0
_savevr_30: addi r12,r0,-32
stvx v30,r12,r0
_savevr_31: addi r12,r0,-16
stvx v31,r12,r0
blr
*/
/* The _restvr_M routines restore the vector registers from vM to v31. When the
* routine is called, r0 must point to the word just beyound the end of the
* vector register save area. On return the value of r0 is unchanged while r12
* may be modified.
*/
/* commented out for now, unused
_restvr_20: addi r12,r0,-192
lvx v20,r12,r0
_restvr_21: addi r12,r0,-176
lvx v21,r12,r0
_restvr_22: addi r12,r0,-160
lvx v22,r12,r0
_restvr_23: addi r12,r0,-144
lvx v23,r12,r0
_restvr_24: addi r12,r0,-128
lvx v24,r12,r0
_restvr_25: addi r12,r0,-112
lvx v25,r12,r0
_restvr_26: addi r12,r0,-96
lvx v26,r12,r0
_restvr_27: addi r12,r0,-80
lvx v27,r12,r0
_restvr_28: addi r12,r0,-64
lvx v28,r12,r0
_restvr_29: addi r12,r0,-48
lvx v29,r12,r0
_restvr_30: addi r12,r0,-32
lvx v30,r12,r0
_restvr_31: addi r12,r0,-16
lvx v31,r12,r0
blr
*/
/*
* start_addresses is a structure containing the real
* entry point (next to other things not interesting to

View File

@ -1,6 +1,16 @@
/*
* This file is part of the Free Pascal run time library.
* Copyright (c) 2005 by Thomas Schatzl,
* member of the Free Pascal development team.
*
* Startup code for normal programs, PowerPC64 version.
*
* See the file COPYING.FPC, included in this distribution,
* for details about the copyright.
*
* 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.
*/
.macro LOAD_64BIT_VAL ra, value
@ -27,7 +37,17 @@
.\fn:
.endm
/* "ptrgl" glue code */
/*
* "ptrgl" glue code for calls via pointer. This function
* sequence loads the data from the function descriptor
* referenced by R11 into the CTR register (function address),
* R2 (GOT/TOC pointer), and R11 (the outer frame pointer).
*
* On entry, R11 must be set to point to the function descriptor.
*
* See also the 64-bit PowerPC ABI specification for more
* information, chapter 3.5.11 (in v1.7).
*/
.section ".text"
.align 3
.globl .ptrgl
@ -39,12 +59,269 @@
ld 11, 8(11)
bctr
.long 0
.byte 0, 12, 0, 0, 0, 0, 0, 0
.byte 0, 12, 128, 0, 0, 0, 0, 0
.type .ptrgl, @function
.size .ptrgl, . - .ptrgl
/*
* Function prolog/epilog helpers, which are part of the 64-bit
* PowerPC ABI.
*
* See also the 64-bit PowerPC ABI specification for more
* information, chapter 3.5.5, "Register saving and restoring
* function" (in v1.7).
*/
/* Each _savegpr0_N routine saves the general registers from rN to r31,
* inclusive. When the routine is called, r1 must point to the start
* of the general register save area. R0 must contain the old LR on
* entry.
*/
_savegpr0_14: std 14,-144(1)
_savegpr0_15: std 15,-136(1)
_savegpr0_16: std 16,-128(1)
_savegpr0_17: std 17,-120(1)
_savegpr0_18: std 18,-112(1)
_savegpr0_19: std 19,-104(1)
_savegpr0_20: std 20,-96(1)
_savegpr0_21: std 21,-88(1)
_savegpr0_22: std 22,-80(1)
_savegpr0_23: std 23,-72(1)
_savegpr0_24: std 24,-64(1)
_savegpr0_25: std 25,-56(1)
_savegpr0_26: std 26,-48(1)
_savegpr0_27: std 27,-40(1)
_savegpr0_28: std 28,-32(1)
_savegpr0_29: std 29,-24(1)
_savegpr0_30: std 30,-16(1)
_savegpr0_31:
std 31,-8(1)
std 0, 16(1)
blr
.long 0
.byte 0, 12, 64, 0, 0, 0, 0, 0
/* Each _restgpr0_N routine restores the general registers from rN to r31,
* inclusive. When the routine is called, r1 must point to the start
* of the general register save area.
*/
_restgpr0_14: ld 14,-144(1)
_restgpr0_15: ld 15,-136(1)
_restgpr0_16: ld 16,-128(1)
_restgpr0_17: ld 17,-120(1)
_restgpr0_18: ld 18,-112(1)
_restgpr0_19: ld 19,-104(1)
_restgpr0_20: ld 20,-96(1)
_restgpr0_21: ld 21,-88(1)
_restgpr0_22: ld 22,-80(1)
_restgpr0_23: ld 23,-72(1)
_restgpr0_24: ld 24,-64(1)
_restgpr0_25: ld 25,-56(1)
_restgpr0_26: ld 26,-48(1)
_restgpr0_27: ld 27,-40(1)
_restgpr0_28: ld 28,-32(1)
_restgpr0_29:
ld 0, 16(1)
ld 29,-24(1)
mtlr 0
ld 30,-16(1)
ld 31,-8(1)
blr
.long 0
.byte 0, 12, 64, 0, 0, 0, 0, 0
_restgpr0_30: ld 30,-16(1)
_restgpr0_31: ld 0, 16(1)
ld 31,-8(1)
mtlr 0
blr
.long 0
.byte 0, 12, 64, 0, 0, 0, 0, 0
/* Each _savegpr1_N routine saves the general registers from rN to r31,
* inclusive. When the routine is called, r12
* must point to the start of the general register save area.
*/
_savegpr1_14: std 14,-144(12)
_savegpr1_15: std 15,-136(12)
_savegpr1_16: std 16,-128(12)
_savegpr1_17: std 17,-120(12)
_savegpr1_18: std 18,-112(12)
_savegpr1_19: std 19,-104(12)
_savegpr1_20: std 20,-96(12)
_savegpr1_21: std 21,-88(12)
_savegpr1_22: std 22,-80(12)
_savegpr1_23: std 23,-72(12)
_savegpr1_24: std 24,-64(12)
_savegpr1_25: std 25,-56(12)
_savegpr1_26: std 26,-48(12)
_savegpr1_27: std 27,-40(12)
_savegpr1_28: std 28,-32(12)
_savegpr1_29: std 29,-24(12)
_savegpr1_30: std 30,-16(12)
_savegpr1_31: std 31,-8(12)
blr
.long 0
.byte 0, 12, 64, 0, 0, 0, 0, 0
/* The _restgpr1_N routines restore the general registers from rN to r31.
* When the routine is called, r12 must point to the start of the general
* register save area.
*/
_restgpr1_14: ld 14,-144(12)
_restgpr1_15: ld 15,-136(12)
_restgpr1_16: ld 16,-128(12)
_restgpr1_17: ld 17,-120(12)
_restgpr1_18: ld 18,-112(12)
_restgpr1_19: ld 19,-104(12)
_restgpr1_20: ld 20,-96(12)
_restgpr1_21: ld 21,-88(12)
_restgpr1_22: ld 22,-80(12)
_restgpr1_23: ld 23,-72(12)
_restgpr1_24: ld 24,-64(12)
_restgpr1_25: ld 25,-56(12)
_restgpr1_26: ld 26,-48(12)
_restgpr1_27: ld 27,-40(12)
_restgpr1_28: ld 28,-32(12)
_restgpr1_29: ld 29,-24(12)
_restgpr1_30: ld 30,-16(12)
_restgpr1_31: ld 31,-8(12)
blr
.long 0
.byte 0, 12, 64, 0, 0, 0, 0, 0
/* Each _savefpr_M routine saves the floating point registers from fM to f31,
* inclusive. When the routine is called, r1 must point to the start of the
* floating point register save area, and r0 must contain the value of LR on
* function entry.
*/
_savefpr_14: stfd 14,-144(1)
_savefpr_15: stfd 15,-136(1)
_savefpr_16: stfd 16,-128(1)
_savefpr_17: stfd 17,-120(1)
_savefpr_18: stfd 18,-112(1)
_savefpr_19: stfd 19,-104(1)
_savefpr_20: stfd 20,-96(1)
_savefpr_21: stfd 21,-88(1)
_savefpr_22: stfd 22,-80(1)
_savefpr_23: stfd 23,-72(1)
_savefpr_24: stfd 24,-64(1)
_savefpr_25: stfd 25,-56(1)
_savefpr_26: stfd 26,-48(1)
_savefpr_27: stfd 27,-40(1)
_savefpr_28: stfd 28,-32(1)
_savefpr_29: stfd 29,-24(1)
_savefpr_30: stfd 30,-16(1)
_savefpr_31: stfd 31,-8(1)
std 0, 16(1)
blr
.long 0
.byte 0, 12, 64, 0, 0, 0, 0, 0
/* The _restfpr_M routines restore the floating point registers from fM to f31.
* When the routine is called, r1 must point to the start of the floating point
* register save area.
*/
_restfpr_14: lfd 14,-144(1)
_restfpr_15: lfd 15,-136(1)
_restfpr_16: lfd 16,-128(1)
_restfpr_17: lfd 17,-120(1)
_restfpr_18: lfd 18,-112(1)
_restfpr_19: lfd 19,-104(1)
_restfpr_20: lfd 20,-96(1)
_restfpr_21: lfd 21,-88(1)
_restfpr_22: lfd 22,-80(1)
_restfpr_23: lfd 23,-72(1)
_restfpr_24: lfd 24,-64(1)
_restfpr_25: lfd 25,-56(1)
_restfpr_26: lfd 26,-48(1)
_restfpr_27: lfd 27,-40(1)
_restfpr_28: lfd 28,-32(1)
_restfpr_29:
ld 0, 16(1)
lfd 29,-24(1)
mtlr 0
lfd 30,-16(1)
lfd 31,-8(1)
blr
.long 0
.byte 0, 12, 64, 0, 0, 0, 0, 0
_restfpr_30: lfd 30,-16(1)
_restfpr_31:
ld 0, 16(1)
lfd 31,-8(1)
mtlr 0
blr
.long 0
.byte 0, 12, 64, 0, 0, 0, 0, 0
/* Each _savevr_M routine saves the vector registers from vM to v31, inclusive.
* When the routine is called, r0 must point to the word just beyound the end
* of the vector register save area. On return the value of r0 is unchanged
* while r12 may be modified.
*/
/* commented out for now, unused
_savevr_20: addi r12,r0,-192
stvx v20,r12,r0
_savevr_21: addi r12,r0,-176
stvx v21,r12,r0
_savevr_22: addi r12,r0,-160
stvx v22,r12,r0
_savevr_23: addi r12,r0,-144
stvx v23,r12,r0
_savevr_24: addi r12,r0,-128
stvx v24,r12,r0
_savevr_25: addi r12,r0,-112
stvx v25,r12,r0
_savevr_26: addi r12,r0,-96
stvx v26,r12,r0
_savevr_27: addi r12,r0,-80
stvx v27,r12,r0
_savevr_28: addi r12,r0,-64
stvx v28,r12,r0
_savevr_29: addi r12,r0,-48
stvx v29,r12,r0
_savevr_30: addi r12,r0,-32
stvx v30,r12,r0
_savevr_31: addi r12,r0,-16
stvx v31,r12,r0
blr
*/
/* The _restvr_M routines restore the vector registers from vM to v31. When the
* routine is called, r0 must point to the word just beyound the end of the
* vector register save area. On return the value of r0 is unchanged while r12
* may be modified.
*/
/* commented out for now, unused
_restvr_20: addi r12,r0,-192
lvx v20,r12,r0
_restvr_21: addi r12,r0,-176
lvx v21,r12,r0
_restvr_22: addi r12,r0,-160
lvx v22,r12,r0
_restvr_23: addi r12,r0,-144
lvx v23,r12,r0
_restvr_24: addi r12,r0,-128
lvx v24,r12,r0
_restvr_25: addi r12,r0,-112
lvx v25,r12,r0
_restvr_26: addi r12,r0,-96
lvx v26,r12,r0
_restvr_27: addi r12,r0,-80
lvx v27,r12,r0
_restvr_28: addi r12,r0,-64
lvx v28,r12,r0
_restvr_29: addi r12,r0,-48
lvx v29,r12,r0
_restvr_30: addi r12,r0,-32
lvx v30,r12,r0
_restvr_31: addi r12,r0,-16
lvx v31,r12,r0
blr
*/
/*
* Main Pascal entry point label (function)
* Main program entry point label (function), called by the loader
*/
FUNCTION_PROLOG _start

View File

@ -1,6 +1,6 @@
{
This file is part of the Free Pascal run time library.
Copyright (c) 1999-2000 by Florian Klaempfl
Copyright (c) 2005 by Thomas Schatzl
member of the Free Pascal development team
See the file COPYING.FPC, included in this distribution,
@ -11,3 +11,110 @@
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
**********************************************************************}
const
RoundModeMask = %00000011;
NonIEEEModeMask = %00000100;
InvalidOperationMask = %10000000;
OverflowMask = %01000000;
UnderflowMask = %00100000;
ZeroDivideMask = %00010000;
InexactMask = %00001000;
ExceptionMask = InvalidOperationMask or OverflowMask or UnderflowMask or ZeroDivideMask or InexactMask;
AllConfigBits = ExceptionMask or NonIEEEModeMask or RoundModeMask;
function getFPSCR : DWord; assembler; nostackframe;
asm
mffs f0
stfd f0, -8(r1)
ld r3, -8(r1)
end;
procedure setFPSCR(newFPSCR : DWord); assembler; nostackframe;
asm
std r3, -8(r1)
lfd f0, -8(r1)
mtfsf 255, f0
end;
function GetRoundMode: TFPURoundingMode;
begin
case (getFPSCR and RoundModeMask) of
0 : result := rmNearest;
1 : result := rmTruncate;
2 : result := rmUp;
3 : result := rmDown;
end;
end;
function SetRoundMode(const RoundMode: TFPURoundingMode): TFPURoundingMode;
var
mode : DWord;
begin
case (RoundMode) of
rmNearest : mode := 0;
rmTruncate : mode := 1;
rmUp : mode := 2;
rmDown : mode := 3;
end;
setFPSCR((getFPSCR and (not RoundModeMask)) or mode);
result := RoundMode;
end;
function GetPrecisionMode: TFPUPrecisionMode;
begin
result := pmDouble;
end;
function SetPrecisionMode(const Precision: TFPUPrecisionMode): TFPUPrecisionMode;
begin
{ nothing to do, not supported }
end;
function GetExceptionMask: TFPUExceptionMask;
begin
result := [];
if ((getFPSCR and InvalidOperationMask) <> 0) then
result := result + [exInvalidOp];
if ((getFPSCR and OverflowMask) <> 0) then
result := result + [exOverflow];
if ((getFPSCR and UnderflowMask) <> 0) then
result := result + [exUnderflow];
if ((getFPSCR and ZeroDivideMask) <> 0) then
result := result + [exZeroDivide];
if ((getFPSCR and InexactMask) <> 0) then
result := result + [exPrecision];
end;
function SetExceptionMask(const Mask: TFPUExceptionMask): TFPUExceptionMask;
var
mode : DWord;
begin
mode := 0;
if (exInvalidOp in Mask) then
mode := mode or InvalidOperationMask;
if (exOverflow in Mask) then
mode := mode or OverflowMask;
if (exUnderflow in Mask) then
mode := mode or UnderflowMask;
if (exZeroDivide in Mask) then
mode := mode or ZeroDivideMask;
if (exPrecision in Mask) then
mode := mode or InexactMask;
setFPSCR((getFPSCR and (not ExceptionMask)) or mode);
result := Mask - [exDenormalized];
end;
procedure ClearExceptions(RaisePending: Boolean = true);
begin
{ RaisePending has no effect on PPC, always raises them at the correct location }
setFPSCR(getFPSCR and (not AllConfigBits));
end;

View File

@ -1,6 +1,6 @@
{
This file is part of the Free Pascal run time library.
Copyright (c) 1999-2000 by Florian Klaempfl
Copyright (c) 1999-2005 by Florian Klaempfl
member of the Free Pascal development team
See the file COPYING.FPC, included in this distribution,
@ -12,3 +12,22 @@
**********************************************************************}
type
TFPURoundingMode = (rmNearest, rmDown, rmUp, rmTruncate);
TFPUPrecisionMode = (pmSingle, pmReserved, pmDouble, pmExtended);
TFPUException = (
exInvalidOp, exDenormalized, exZeroDivide,
exOverflow, exUnderflow, exPrecision);
TFPUExceptionMask = set of TFPUException;
function GetRoundMode: TFPURoundingMode;
function SetRoundMode(const RoundMode: TFPURoundingMode): TFPURoundingMode;
function GetPrecisionMode: TFPUPrecisionMode;
function SetPrecisionMode(const Precision: TFPUPrecisionMode): TFPUPrecisionMode;
function GetExceptionMask: TFPUExceptionMask;
function SetExceptionMask(const Mask: TFPUExceptionMask): TFPUExceptionMask;
procedure ClearExceptions(RaisePending: Boolean = true);

View File

@ -1,9 +1,8 @@
{
This file is part of the Free Pascal run time library.
Copyright (c) 2000-2001 by the Free Pascal development team.
Portions Copyright (c) 2000 by Casey Duncan (casey.duncan@state.co.us)
Portions Copyright (c) 2000 by Casey Duncan (casey.duncan@state.co.us)
Processor dependent implementation for the system unit for
PowerPC64
@ -22,16 +21,7 @@
PowerPC specific stuff
****************************************************************************}
const
ppc_fpu_overflow = (1 shl (32-3));
ppc_fpu_underflow = (1 shl (32-4));
ppc_fpu_divbyzero = (1 shl (32-5));
ppc_fpu_inexact = (1 shl (32-6));
ppc_fpu_invalid_snan = (1 shl (32-7));
procedure fpc_enable_ppc_fpu_exceptions;
assembler; nostackframe;
procedure fpc_enable_ppc_fpu_exceptions; assembler; nostackframe;
asm
{ clear all "exception happened" flags we care about}
mtfsfi 0,0
@ -42,7 +32,6 @@ asm
mtfsb0 21
mtfsb0 22
mtfsb0 23
{$endif fpc_mtfsb0_corrected}
{ enable invalid operations and division by zero exceptions. }
@ -57,358 +46,6 @@ begin
fpc_enable_ppc_fpu_exceptions;
end;
function fpc_get_ppc_fpscr: cardinal;
assembler;
var
temp: record a,b:longint; end;
asm
mffs f0
stfd f0,temp
lwz r3,temp.b
{ clear all exception flags }
{ TODO
rlwinm r4,r3,0,16,31
stw r4,temp.b
lfd f0,temp
mtfsf f0
}
end;
{ note: unused; to be moved into startup code }
{ The following code is never called directly, it's a dummy which holds the
entry points and code to the register save/load subroutines; it is part of the
PPC ABI and used in procedure entry and exit methods.
See the comments in the code for "calling conventions". Directly taken from
the ABI specification. The labels right below are required to shut up the
compiler. }
label
// _savegpr0_x
_savegpr0_14, _savegpr0_15, _savegpr0_16, _savegpr0_17, _savegpr0_18, _savegpr0_19,
_savegpr0_20, _savegpr0_21, _savegpr0_22, _savegpr0_23, _savegpr0_24, _savegpr0_25,
_savegpr0_26, _savegpr0_27, _savegpr0_28, _savegpr0_29, _savegpr0_30, _savegpr0_31,
// _restgpr0_x
_restgpr0_14, _restgpr0_15, _restgpr0_16, _restgpr0_17, _restgpr0_18, _restgpr0_19,
_restgpr0_20, _restgpr0_21, _restgpr0_22, _restgpr0_23, _restgpr0_24, _restgpr0_25,
_restgpr0_26, _restgpr0_27, _restgpr0_28, _restgpr0_29, _restgpr0_30, _restgpr0_31,
// _savegpr1_x
_savegpr1_14, _savegpr1_15, _savegpr1_16, _savegpr1_17, _savegpr1_18, _savegpr1_19,
_savegpr1_20, _savegpr1_21, _savegpr1_22, _savegpr1_23, _savegpr1_24, _savegpr1_25,
_savegpr1_26, _savegpr1_27, _savegpr1_28, _savegpr1_29, _savegpr1_30, _savegpr1_31,
// _restgpr1_x
_restgpr1_14, _restgpr1_15, _restgpr1_16, _restgpr1_17, _restgpr1_18, _restgpr1_19,
_restgpr1_20, _restgpr1_21, _restgpr1_22, _restgpr1_23, _restgpr1_24, _restgpr1_25,
_restgpr1_26, _restgpr1_27, _restgpr1_28, _restgpr1_29, _restgpr1_30, _restgpr1_31,
// _savefpr_x
_savefpr_14, _savefpr_15, _savefpr_16, _savefpr_17, _savefpr_18, _savefpr_19,
_savefpr_20, _savefpr_21, _savefpr_22, _savefpr_23, _savefpr_24, _savefpr_25,
_savefpr_26, _savefpr_27, _savefpr_28, _savefpr_29, _savefpr_30, _savefpr_31,
// _restfpr_x
_restfpr_14, _restfpr_15, _restfpr_16, _restfpr_17, _restfpr_18, _restfpr_19,
_restfpr_20, _restfpr_21, _restfpr_22, _restfpr_23, _restfpr_24, _restfpr_25,
_restfpr_26, _restfpr_27, _restfpr_28, _restfpr_29, _restfpr_30, _restfpr_31,
// _savevr_x
_savevr_20, _savevr_21, _savevr_22, _savevr_23, _savevr_24, _savevr_25,
_savevr_26, _savevr_27, _savevr_28, _savevr_29, _savevr_30, _savevr_31,
// _restvr_x
_restvr_20, _restvr_21, _restvr_22, _restvr_23, _restvr_24, _restvr_25,
_restvr_26, _restvr_27, _restvr_28, _restvr_29, _restvr_30, _restvr_31;
procedure __save_restore_services; assembler; nostackframe;
assembler;
asm
// Each _savegpr0_N routine saves the general registers from rN to r31, inclusive.
// Each routine also saves the LR. When the routine is called, r1 must point to
// the start of the general register save area, and r0 must contain the
// value of LR on function entry.
.globl _savegpr0_14
_savegpr0_14: std r14,-144(r1)
.globl _savegpr0_15
_savegpr0_15: std r15,-136(r1)
.globl _savegpr0_16
_savegpr0_16: std r16,-128(r1)
.globl _savegpr0_17
_savegpr0_17: std r17,-120(r1)
.globl _savegpr0_18
_savegpr0_18: std r18,-112(r1)
.globl _savegpr0_19
_savegpr0_19: std r19,-104(r1)
.globl _savegpr0_20
_savegpr0_20: std r20,-96(r1)
.globl _savegpr0_21
_savegpr0_21: std r21,-88(r1)
.globl _savegpr0_22
_savegpr0_22: std r22,-80(r1)
.globl _savegpr0_23
_savegpr0_23: std r23,-72(r1)
.globl _savegpr0_24
_savegpr0_24: std r24,-64(r1)
.globl _savegpr0_25
_savegpr0_25: std r25,-56(r1)
.globl _savegpr0_26
_savegpr0_26: std r26,-48(r1)
.globl _savegpr0_27
_savegpr0_27: std r27,-40(r1)
.globl _savegpr0_28
_savegpr0_28: std r28,-32(r1)
.globl _savegpr0_29
_savegpr0_29: std r29,-24(r1)
.globl _savegpr0_30
_savegpr0_30: std r30,-16(r1)
.globl _savegpr0_31
_savegpr0_31: std r31,-8(r1)
std r0, 16(r1)
blr
// The _restgpr0_N routines restore the general registers from rN to r31, and then
// return to the caller. When the routine is called, r1 must point to the start of
// the general register save area.
.globl _restgpr0_14
_restgpr0_14: ld r14,-144(r1)
.globl _restgpr0_15
_restgpr0_15: ld r15,-136(r1)
.globl _restgpr0_16
_restgpr0_16: ld r16,-128(r1)
.globl _restgpr0_17
_restgpr0_17: ld r17,-120(r1)
.globl _restgpr0_18
_restgpr0_18: ld r18,-112(r1)
.globl _restgpr0_19
_restgpr0_19: ld r19,-104(r1)
.globl _restgpr0_20
_restgpr0_20: ld r20,-96(r1)
.globl _restgpr0_21
_restgpr0_21: ld r21,-88(r1)
.globl _restgpr0_22
_restgpr0_22: ld r22,-80(r1)
.globl _restgpr0_23
_restgpr0_23: ld r23,-72(r1)
.globl _restgpr0_24
_restgpr0_24: ld r24,-64(r1)
.globl _restgpr0_25
_restgpr0_25: ld r25,-56(r1)
.globl _restgpr0_26
_restgpr0_26: ld r26,-48(r1)
.globl _restgpr0_27
_restgpr0_27: ld r27,-40(r1)
.globl _restgpr0_28
_restgpr0_28: ld r28,-32(r1)
.globl _restgpr0_29
_restgpr0_29: ld r0, 16(r1)
ld r29,-24(r1)
mtlr r0
ld r30,-16(r1)
ld r31,-8(r1)
blr
.globl _restgpr0_30
_restgpr0_30: ld r30,-16(r1)
.globl _restgpr0_31
_restgpr0_31: ld r0, 16(r1)
ld r31,-8(r1)
mtlr r0
blr
// Each _savegpr1_N routine saves the general registers from rN to r31,
// inclusive. When the routine is called, r12
// must point to the start of the general register save area.
.globl _savegpr1_14
_savegpr1_14: std r14,-144(r12)
.globl _savegpr1_15
_savegpr1_15: std r15,-136(r12)
.globl _savegpr1_16
_savegpr1_16: std r16,-128(r12)
.globl _savegpr1_17
_savegpr1_17: std r17,-120(r12)
.globl _savegpr1_18
_savegpr1_18: std r18,-112(r12)
.globl _savegpr1_19
_savegpr1_19: std r19,-104(r12)
.globl _savegpr1_20
_savegpr1_20: std r20,-96(r12)
.globl _savegpr1_21
_savegpr1_21: std r21,-88(r12)
.globl _savegpr1_22
_savegpr1_22: std r22,-80(r12)
.globl _savegpr1_23
_savegpr1_23: std r23,-72(r12)
.globl _savegpr1_24
_savegpr1_24: std r24,-64(r12)
.globl _savegpr1_25
_savegpr1_25: std r25,-56(r12)
.globl _savegpr1_26
_savegpr1_26: std r26,-48(r12)
.globl _savegpr1_27
_savegpr1_27: std r27,-40(r12)
.globl _savegpr1_28
_savegpr1_28: std r28,-32(r12)
.globl _savegpr1_29
_savegpr1_29: std r29,-24(r12)
.globl _savegpr1_30
_savegpr1_30: std r30,-16(r12)
.globl _savegpr1_31
_savegpr1_31: std r31,-8(r12)
blr
// The _restgpr1_N routines restore the general registers from rN to r31.
// When the routine is called, r12 must point to the start of the general
// register save area.
.globl _restgpr1_14
_restgpr1_14: ld r14,-144(r12)
.globl _restgpr1_15
_restgpr1_15: ld r15,-136(r12)
.globl _restgpr1_16
_restgpr1_16: ld r16,-128(r12)
.globl _restgpr1_17
_restgpr1_17: ld r17,-120(r12)
.globl _restgpr1_18
_restgpr1_18: ld r18,-112(r12)
.globl _restgpr1_19
_restgpr1_19: ld r19,-104(r12)
.globl _restgpr1_20
_restgpr1_20: ld r20,-96(r12)
.globl _restgpr1_21
_restgpr1_21: ld r21,-88(r12)
.globl _restgpr1_22
_restgpr1_22: ld r22,-80(r12)
.globl _restgpr1_23
_restgpr1_23: ld r23,-72(r12)
.globl _restgpr1_24
_restgpr1_24: ld r24,-64(r12)
.globl _restgpr1_25
_restgpr1_25: ld r25,-56(r12)
.globl _restgpr1_26
_restgpr1_26: ld r26,-48(r12)
.globl _restgpr1_27
_restgpr1_27: ld r27,-40(r12)
.globl _restgpr1_28
_restgpr1_28: ld r28,-32(r12)
.globl _restgpr1_29
_restgpr1_29: ld r29,-24(r12)
.globl _restgpr1_30
_restgpr1_30: ld r30,-16(r12)
.globl _restgpr1_31
_restgpr1_31: ld r31,-8(r12)
blr
// Each _savefpr_M routine saves the floating point registers from fM to f31,
// inclusive. When the routine is called, r1 must point to the start of the
// floating point register save area, and r0 must contain the value of LR on
// function entry.
_savefpr_14: stfd f14,-144(r1)
_savefpr_15: stfd f15,-136(r1)
_savefpr_16: stfd f16,-128(r1)
_savefpr_17: stfd f17,-120(r1)
_savefpr_18: stfd f18,-112(r1)
_savefpr_19: stfd f19,-104(r1)
_savefpr_20: stfd f20,-96(r1)
_savefpr_21: stfd f21,-88(r1)
_savefpr_22: stfd f22,-80(r1)
_savefpr_23: stfd f23,-72(r1)
_savefpr_24: stfd f24,-64(r1)
_savefpr_25: stfd f25,-56(r1)
_savefpr_26: stfd f26,-48(r1)
_savefpr_27: stfd f27,-40(r1)
_savefpr_28: stfd f28,-32(r1)
_savefpr_29: stfd f29,-24(r1)
_savefpr_30: stfd f30,-16(r1)
_savefpr_31: stfd f31,-8(r1)
std r0, 16(r1)
blr
// The _restfpr_M routines restore the floating point registers from fM to f31.
// When the routine is called, r1 must point to the start of the floating point
// register save area.
_restfpr_14: lfd f14,-144(r1)
_restfpr_15: lfd f15,-136(r1)
_restfpr_16: lfd f16,-128(r1)
_restfpr_17: lfd f17,-120(r1)
_restfpr_18: lfd f18,-112(r1)
_restfpr_19: lfd f19,-104(r1)
_restfpr_20: lfd f20,-96(r1)
_restfpr_21: lfd f21,-88(r1)
_restfpr_22: lfd f22,-80(r1)
_restfpr_23: lfd f23,-72(r1)
_restfpr_24: lfd f24,-64(r1)
_restfpr_25: lfd f25,-56(r1)
_restfpr_26: lfd f26,-48(r1)
_restfpr_27: lfd f27,-40(r1)
_restfpr_28: lfd f28,-32(r1)
_restfpr_29: lfd f29,-24(r1)
_restfpr_29: ld r0, 16(r1)
lfd f29,-24(r1)
mtlr r0
lfd f30,-16(r1)
lfd f31,-8(r1)
blr
_restfpr_30: lfd f30,-16(r1)
_restfpr_31: ld r0, 16(r1)
lfd f31,-8(r1)
mtlr r0
blr
// Each _savevr_M routine saves the vector registers from vM to v31, inclusive.
// When the routine is called, r0 must point to the word just beyound the end
// of the vector register save area. On return the value of r0 is unchanged
// while r12 may be modified.
(* commented out: GAS does not understand VMX opcodes?
_savevr_20: addi r12,r0,-192
stvx v20,r12,r0
_savevr_21: addi r12,r0,-176
stvx v21,r12,r0
_savevr_22: addi r12,r0,-160
stvx v22,r12,r0
_savevr_23: addi r12,r0,-144
stvx v23,r12,r0
_savevr_24: addi r12,r0,-128
stvx v24,r12,r0
_savevr_25: addi r12,r0,-112
stvx v25,r12,r0
_savevr_26: addi r12,r0,-96
stvx v26,r12,r0
_savevr_27: addi r12,r0,-80
stvx v27,r12,r0
_savevr_28: addi r12,r0,-64
stvx v28,r12,r0
_savevr_29: addi r12,r0,-48
stvx v29,r12,r0
_savevr_30: addi r12,r0,-32
stvx v30,r12,r0
_savevr_31: addi r12,r0,-16
stvx v31,r12,r0
blr
*)
// The _restvr_M routines restore the vector registers from vM to v31. When the
// routine is called, r0 must point to the word just beyound the end of the
// vector register save area. On return the value of r0 is unchanged while r12
// may be modified.
(* commented out: GAS does not understand VMX opcodes?
_restvr_20: addi r12,r0,-192
lvx v20,r12,r0
_restvr_21: addi r12,r0,-176
lvx v21,r12,r0
_restvr_22: addi r12,r0,-160
lvx v22,r12,r0
_restvr_23: addi r12,r0,-144
lvx v23,r12,r0
_restvr_24: addi r12,r0,-128
lvx v24,r12,r0
_restvr_25: addi r12,r0,-112
lvx v25,r12,r0
_restvr_26: addi r12,r0,-96
lvx v26,r12,r0
_restvr_27: addi r12,r0,-80
lvx v27,r12,r0
_restvr_28: addi r12,r0,-64
lvx v28,r12,r0
_restvr_29: addi r12,r0,-48
lvx v29,r12,r0
_restvr_30: addi r12,r0,-32
lvx v30,r12,r0
_restvr_31: addi r12,r0,-16
lvx v31,r12,r0
blr
*)
end;
{****************************************************************************
Move / Fill
****************************************************************************}
@ -451,27 +88,22 @@ begin
v := 0;
{ aligned? }
if (PtrUInt(@x) mod sizeof(PtrUInt))<>0 then
begin
for i:=0 to count-1 do
bytearray(x)[i]:=value;
end
else
begin
v:=(value shl 8) or (value and $FF);
v:=(v shl 16) or (v and $ffff);
for i:=0 to (count div 4)-1 do
longintarray(x)[i]:=v;
for i:=(count div 4)*4 to count-1 do
bytearray(x)[i]:=value;
end;
bytearray(x)[i]:=value
else begin
v:=(value shl 8) or (value and $FF);
v:=(v shl 16) or (v and $ffff);
for i:=0 to (count div 4)-1 do
longintarray(x)[i]:=v;
for i:=(count div 4)*4 to count-1 do
bytearray(x)[i]:=value;
end;
end;
{$endif FPC_SYSTEM_HAS_FILLCHAR}
{$ifndef FPC_SYSTEM_HAS_FILLDWORD}
{$define FPC_SYSTEM_HAS_FILLDWORD}
procedure filldword(var x;count : SizeInt;value : dword);
assembler; nostackframe;
procedure filldword(var x;count : SizeInt;value : dword); assembler; nostackframe;
asm
cmpdi cr0,r4,0
mtctr r4
@ -787,7 +419,7 @@ asm
.Lcopys2loop:
lbzu r0,1(r5)
stbu r0,1(r9)
bdnz .Lcopys2loop
bdnz .Lcopys2loop
.LconcatDone:
end;
{$endif FPC_SYSTEM_HAS_FPC_SHORTSTR_CONCAT}
@ -840,8 +472,8 @@ end;
(*
{$define FPC_SYSTEM_HAS_FPC_SHORTSTR_COMPARE}
function fpc_shortstr_compare(const dstr, sstr:shortstring): SizeInt; [public,alias:'FPC_SHORTSTR_COMPARE']; compilerproc;
assembler;
{ TODO: improve, because the main compare loop does an unaligned access everytime.. :(
assembler;
{ TODO: improve, because the main compare loop does an unaligned access everytime.. :(
TODO: needs some additional opcodes not yet known to the compiler :( }
asm
{ load length sstr }
@ -857,7 +489,7 @@ asm
{ first compare qwords (length/4) }
srdi. r5,r9,3
{ keep length mod 8 for the ends; note that the value in r9 <= 255
{ keep length mod 8 for the ends; note that the value in r9 <= 255
so we can use rlwinm safely }
rlwinm r9,r9,0,29,31
{ already check whether length mod 8 = 0 }