Assembly version of fpc_ansistr_decr_ref for ARM

As fpc_ansistr_decr_ref is a very often called procedure in typical
pascal programs this optimized version will shave off some cycles
compared to the generic one.

It tries to avoid load latencies as much as possible and also uses the
new Z-flag functionality of the InterlockedDecrement from the previous
patch. Also FreeMem is called as a tail-function.

git-svn-id: trunk@22034 -
This commit is contained in:
masta 2012-08-08 06:44:31 +00:00
parent 25e2f5f3fa
commit b9770519f8

View File

@ -499,6 +499,50 @@ end;
{$endif}
{$define FPC_SYSTEM_HAS_ANSISTR_DECR_REF}
function fpc_freemem_x(p:pointer):ptrint; [external name 'FPC_FREEMEM_X'];
Procedure fpc_ansistr_decr_ref (Var S : Pointer); [Public,Alias:'FPC_ANSISTR_DECR_REF'];assembler;nostackframe; compilerproc;
asm
ldr r1, [r0]
// On return the pointer will always be set to zero, so utilize the delay slots
mov r2, #0
str r2, [r0]
// Check for a zero string
cmp r1, #0
// Load reference counter
ldrne r2, [r1, #-8]
{$if defined(cpuarmv3) or defined(cpuarmv4)}
moveq pc,lr
{$else}
bxeq lr
{$endif}
// Check for a constant string
cmp r2, #0
{$if defined(cpuarmv3) or defined(cpuarmv4)}
movlt pc,lr
{$else}
bxlt lr
{$endif}
stmfd sp!, {r1, lr}
sub r0, r1, #8
blx InterLockedDecrement
// InterLockedDecrement is a nice guy and sets the z flag for us
// if the reference count dropped to 0
ldmnefd sp!, {r1, pc}
ldmfd sp!, {r0, lr}
// We currently can not use constant symbols in ARM-Assembly
// but we need to stay backward compatible with 2.6
{$if defined(VER2_6)}
sub r0, r0, #8 //AnsiFirstOff in 2.6
{$else}
sub r0, r0, #12 //AnsiFirstOff in 2.7 with codepage support
{$endif}
// Jump without a link, so freemem directly returns to our caller
b FPC_FREEMEM_X
end;
var
fpc_system_lock: longint; export name 'fpc_system_lock';