mirror of
https://gitlab.com/freepascal.org/fpc/source.git
synced 2025-04-15 23:59:30 +02:00
* 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:
parent
cc44a19af5
commit
651f34e27c
compiler/powerpc64
rtl
@ -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;
|
||||
|
||||
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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 }
|
||||
|
Loading…
Reference in New Issue
Block a user