Tried to reorganize the ARM define mess in rtl/arm/arm.inc. Instead of requiring to enumerate all possible ARM variants each time a CPU feature is used, add a define of the format CPUARM_HAS_XXX and use that. Note that a better solution would be to properly implement the compiler cpuinfo infrastructure, however that is much more work.

+ CPUARM_HAS_BX is defined if the CPU supports the BX* instruction
  + CPUARM_HAS_REV is defined if the CPU supports the REV instruction. Note that you still have to check for compiler versions > 2.6.0 since the assembler reader of 2.6.0 does not understand that instruction.
  + CPUARM_HAS_IDIV is defined if the CPU supports the sdiv, udiv instructions. Use of this fixes a bug where previously these instruction were only used for armv7-m, while cortex3m cpus also support it.
  + CPUARM_HAS_LDREX is defined if the CPU supports the ldrex/strex instructions. Use of this fixes a bug with armv7(-a) cpus where this path has not been used.
  + SYSTEM_HAS_KUSER_CMPXCHG is defined if the system (mainly OS) support the kuser_cmpxchg functions. Use of this fixes a bug where ARMHF systems did not use it for synchronization (although ARMHF is armv7+ only, i.e. the LDREX path is used anyway)

git-svn-id: trunk@22081 -
This commit is contained in:
tom_at_work 2012-08-14 19:45:03 +00:00
parent 7b6bcd315f
commit f252fd369e
6 changed files with 110 additions and 71 deletions

1
.gitattributes vendored
View File

@ -7223,6 +7223,7 @@ rtl/android/jvm/java_sys_android.inc svneol=native#text/plain
rtl/android/jvm/java_sysh_android.inc svneol=native#text/plain
rtl/android/jvm/rtl.cfg svneol=native#text/plain
rtl/arm/arm.inc svneol=native#text/plain
rtl/arm/armdefines.inc svneol=native#text/plain
rtl/arm/divide.inc svneol=native#text/plain
rtl/arm/int64p.inc svneol=native#text/plain
rtl/arm/makefile.cpu svneol=native#text/plain

View File

@ -146,10 +146,10 @@ Procedure FillChar(var x;count:longint;value:byte);assembler;nostackframe;
asm
// less than 0?
cmp r1,#0
{$if defined(cpuarmv3) or defined(cpuarmv4)}
movle pc,lr
{$else}
{$ifdef CPUARM_HAS_BX}
bxle lr
{$else}
movle pc,lr
{$endif}
mov r3,r0
@ -177,10 +177,10 @@ asm
// Do the rest
adds r1, r1, #8
{$if defined(cpuarmv3) or defined(cpuarmv4)}
moveq pc,lr
{$else}
{$ifdef CPUARM_HAS_BX}
bxeq lr
{$else}
moveq pc,lr
{$endif}
tst r1, #4
@ -189,10 +189,10 @@ asm
strneh r2,[r3],#2
tst r1, #1
strneb r2,[r3],#1
{$if defined(cpuarmv3) or defined(cpuarmv4)}
mov pc,lr
{$else}
{$ifdef CPUARM_HAS_BX}
bx lr
{$else}
mov pc,lr
{$endif}
// Special case for unaligned start
@ -200,10 +200,10 @@ asm
.LFillchar_do_align:
strb r2,[r3],#1
subs r1, r1, #1
{$if defined(cpuarmv3) or defined(cpuarmv4)}
moveq pc,lr
{$else}
{$ifdef CPUARM_HAS_BX}
bxeq lr
{$else}
moveq pc,lr
{$endif}
tst r3,#3
bne .LFillchar_do_align
@ -218,10 +218,10 @@ asm
pld [r0]
// count <=0 ?
cmp r2,#0
{$if defined(cpuarmv3) or defined(cpuarmv4)}
movle pc,lr
{$else}
{$ifdef CPUARM_HAS_BX}
bxle lr
{$else}
movle pc,lr
{$endif}
// overlap?
subs r3, r1, r0 // if (dest > source) and
@ -245,20 +245,20 @@ asm
stmia r1!, {r3, ip}
bge .Ldwordloop
cmp r2,#0
{$if defined(cpuarmv3) or defined(cpuarmv4)}
moveq pc,lr
{$else}
{$ifdef CPUARM_HAS_BX}
bxeq lr
{$else}
moveq pc,lr
{$endif}
.Lbyteloop:
subs r2,r2,#1
ldrb r3,[r0],#1
strb r3,[r1],#1
bne .Lbyteloop
{$if defined(cpuarmv3) or defined(cpuarmv4)}
mov pc,lr
{$else}
{$ifdef CPUARM_HAS_BX}
bx lr
{$else}
mov pc,lr
{$endif}
.Loverlapped:
subs r2,r2,#1
@ -271,10 +271,10 @@ procedure Move_blended(const source;var dest;count:longint);assembler;nostackfra
asm
// count <=0 ?
cmp r2,#0
{$if defined(cpuarmv3) or defined(cpuarmv4)}
movle pc,lr
{$else}
{$ifdef CPUARM_HAS_BX}
bxle lr
{$else}
movle pc,lr
{$endif}
// overlap?
subs r3, r1, r0 // if (dest > source) and
@ -295,20 +295,20 @@ asm
stmia r1!, {r3, ip}
bge .Ldwordloop
cmp r2,#0
{$if defined(cpuarmv3) or defined(cpuarmv4)}
moveq pc,lr
{$else}
{$ifdef CPUARM_HAS_BX}
bxeq lr
{$else}
moveq pc,lr
{$endif}
.Lbyteloop:
subs r2,r2,#1
ldrb r3,[r0],#1
strb r3,[r1],#1
bne .Lbyteloop
{$if defined(cpuarmv3) or defined(cpuarmv4)}
mov pc,lr
{$else}
{$ifdef CPUARM_HAS_BX}
bx lr
{$else}
mov pc,lr
{$endif}
.Loverlapped:
subs r2,r2,#1
@ -488,10 +488,10 @@ asm
terminating 0, due to the known carry flag sbc can do this.*)
sbc r0,r1,r0
.Ldone:
{$if defined(cpuarmv3) or defined(cpuarmv4)}
mov pc,lr
{$else}
{$ifdef CPUARM_HAS_BX}
bx lr
{$else}
mov pc,lr
{$endif}
.L01010101:
.long 0x01010101
@ -513,17 +513,17 @@ asm
cmp r1, #0
// Load reference counter
ldrne r2, [r1, #-8]
{$if defined(cpuarmv3) or defined(cpuarmv4)}
moveq pc,lr
{$else}
{$ifdef CPUARM_HAS_BX}
bxeq lr
{$else}
moveq pc,lr
{$endif}
// Check for a constant string
cmp r2, #0
{$if defined(cpuarmv3) or defined(cpuarmv4)}
movlt pc,lr
{$else}
{$ifdef CPUARM_HAS_BX}
bxlt lr
{$else}
movlt pc,lr
{$endif}
stmfd sp!, {r1, lr}
sub r0, r1, #8
@ -544,7 +544,7 @@ var
function InterLockedDecrement (var Target: longint) : longint; assembler; nostackframe;
asm
{$if defined(cpuarmv6) or defined(cpuarmv7m) or defined(cpucortexm3)}
{$ifdef CPUARM_HAS_LDREX}
.Lloop:
ldrex r1, [r0]
sub r1, r1, #1
@ -554,7 +554,7 @@ asm
movs r0, r1
bx lr
{$else}
{$if defined(LINUX) and defined(CPUARMEL)}
{$ifdef SYSTEM_HAS_KUSER_CMPXCHG}
stmfd r13!, {lr}
mov r2, r0 // kuser_cmpxchg does not clobber r2 by definition
.Latomic_dec_loop:
@ -613,10 +613,10 @@ asm
ldrne r1, [r0, #-8]
// pointer to counter, calculate here for delay slot utilization
subne r0, r0, #8
{$if defined(cpuarmv3) or defined(cpuarmv4)}
moveq pc,lr
{$else}
{$ifdef CPUARM_HAS_BX}
bxeq lr
{$else}
moveq pc,lr
{$endif}
// Check for a constant string
cmp r1, #0
@ -628,7 +628,7 @@ end;
function InterLockedIncrement (var Target: longint) : longint; assembler; nostackframe;
asm
{$if defined(cpuarmv6) or defined(cpuarmv7m) or defined(cpucortexm3)}
{$ifdef CPUARM_HAS_LDREX}
.Lloop:
ldrex r1, [r0]
add r1, r1, #1
@ -638,7 +638,7 @@ asm
mov r0, r1
bx lr
{$else}
{$if defined(LINUX) and defined(CPUARMEL)}
{$ifdef SYSTEM_HAS_KUSER_CMPXCHG}
stmfd r13!, {lr}
mov r2, r0 // kuser_cmpxchg does not clobber r2 by definition
.Latomic_inc_loop:
@ -688,7 +688,7 @@ end;
function InterLockedExchange (var Target: longint;Source : longint) : longint; assembler; nostackframe;
asm
{$if defined(cpuarmv6) or defined(cpuarmv7m) or defined(cpucortexm3)}
{$ifdef CPUARM_HAS_LDREX}
// swp is deprecated on ARMv6 and above
.Lloop:
ldrex r2, [r0]
@ -698,7 +698,7 @@ asm
mov r0, r2
bx lr
{$else}
{$if defined(LINUX) and defined(CPUARMEL)}
{$ifdef SYSTEM_HAS_KUSER_CMPXCHG}
stmfd r13!, {r4, lr}
mov r2, r0 // kuser_cmpxchg does not clobber r2 (and r1) by definition
.Latomic_add_loop:
@ -747,7 +747,7 @@ end;
function InterLockedExchangeAdd (var Target: longint;Source : longint) : longint; assembler; nostackframe;
asm
{$if defined(cpuarmv6) or defined(cpuarmv7m) or defined(cpucortexm3)}
{$ifdef CPUARM_HAS_LDREX}
.Lloop:
ldrex r2, [r0]
add r12, r1, r2
@ -757,7 +757,7 @@ asm
mov r0, r2
bx lr
{$else}
{$if defined(LINUX) and defined(CPUARMEL)}
{$ifdef SYSTEM_HAS_KUSER_CMPXCHG}
stmfd r13!, {r4, lr}
mov r2, r0 // kuser_cmpxchg does not clobber r2 by definition
mov r4, r1 // Save addend
@ -812,7 +812,7 @@ end;
function InterlockedCompareExchange(var Target: longint; NewValue: longint; Comperand: longint): longint; assembler; nostackframe;
asm
{$if defined(cpuarmv6) or defined(cpuarmv7m) or defined(cpucortexm3)}
{$ifdef CPUARM_HAS_LDREX}
.Lloop:
ldrex r3, [r0]
mov r12, #0
@ -823,7 +823,7 @@ asm
mov r0, r3
bx lr
{$else}
{$if defined(LINUX) and defined(CPUARMEL)}
{$ifdef SYSTEM_HAS_KUSER_CMPXCHG}
stmfd r13!, {r4, lr}
mvn r3, #0x0000f000
sub r3, r3, #0x3F
@ -928,13 +928,13 @@ is bigger than the gain of the optimized function.
function AsmSwapEndian(const AValue: SmallInt): SmallInt;{$ifdef SYSTEMINLINE}inline;{$endif};assembler;nostackframe;
asm
// We're starting with 4321
{$if defined(cpuarmv3) or defined(cpuarmv4) or defined(cpuarmv5) or defined(VER2_6)}
{$if defined(CPUARM_HAS_REV) and (FPC_FULLVERSION > 20600)}
rev r0, r0 // Reverse byteorder r0 = 1234
mov r0, r0, shr #16 // Shift down to 16bits r0 = 0012
{$else}
mov r0, r0, shl #16 // Shift to make that 2100
mov r0, r0, ror #24 // Rotate to 1002
orr r0, r0, r0 shr #16 // Shift and combine into 0012
{$else}
rev r0, r0 // Reverse byteorder r0 = 1234
mov r0, r0, shr #16 // Shift down to 16bits r0 = 0012
{$endif}
end;
@ -966,7 +966,12 @@ end;
function SwapEndian(const AValue: Int64): Int64; assembler; nostackframe;
asm
{$if defined(cpuarmv3) or defined(cpuarmv4) or defined(cpuarmv5) or defined(VER2_6)}
// fpc >2.6.0 adds the "rev" instruction in the internal assembler
{$if defined(CPUARM_HAS_REV) and (FPC_FULLVERSION > 20600)}
rev r2, r0
rev r0, r1
mov r1, r2
{$else}
mov ip, r1
// We're starting with r0 = $87654321
@ -980,10 +985,6 @@ asm
mov ip, ip, ror #8
eor r0, ip, r0, lsr #8
{$else}
rev r2, r0
rev r0, r1
mov r1, r2
{$endif}
end;

35
rtl/arm/armdefines.inc Normal file
View File

@ -0,0 +1,35 @@
{
This file is part of the Free Pascal run time library.
Copyright (c) 2012 by the Free Pascal development team.
Processor dependent defines for the ARM runtime library.
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.
**********************************************************************}
{$if not defined(cpuarmv3) and not defined(cpuarmv4)}
{$define CPUARM_HAS_BX} // cpu has BX instruction
{$endif}
{$if not defined(CPUARMV3) and not defined(CPUARMV4) and not defined(CPUARMV5)}
{$define CPUARM_HAS_REV} // cpu has REV instruction
{$endif}
{$if defined(CPUARMV7M) or defined(CPUARMCORTEXM3)}
{$define CPUARM_HAS_IDIV} // cpu has SDIV/UDIV instructions
{$endif}
{$if defined(CPUARMV6) or defined(CPUARMV7) or defined(CPUARMV7M) or defined(CPUARMCORTEXM3)}
{$define CPUARM_HAS_LDREX} // cpu has LDREX/STREX instructions
{$endif}
{$if defined(LINUX) and (defined(CPUARMEL) or defined(CPUARMHF))}
{$define SYSTEM_HAS_KUSER_CMPXCHG} // system has kuser_cmpxchg method
{$endif}

View File

@ -41,7 +41,7 @@
function fpc_div_dword(n,z:dword):dword;[public,alias: 'FPC_DIV_DWORD'];assembler;nostackframe;
asm
{$if defined(CPUARMV7M)}
{$ifdef CPUARM_HAS_IDIV}
udiv r0, r0, r1
{$else}
mov r3, #0
@ -96,19 +96,19 @@ asm
.Ldiv_next:
bcs .Ldiv_loop
mov r0, r3
{$if defined(cpuarmv3) or defined(cpuarmv4)}
mov pc, lr
{$else}
{$ifdef CPUARM_HAS_BX}
bx lr
{$else}
mov pc, lr
{$endif}
.Ldiv_by_0:
mov r0, #200
mov r1, r11
bl handleerrorframe
{$if defined(cpuarmv3) or defined(cpuarmv4)}
mov pc, lr
{$else}
{$ifdef CPUARM_HAS_BX}
bx lr
{$else}
mov pc, lr
{$endif}
{$endif}
end;
@ -122,7 +122,7 @@ function fpc_div_dword(n,z:dword):dword;external name 'FPC_DIV_DWORD';
function fpc_div_longint(n,z:longint):longint;[public,alias: 'FPC_DIV_LONGINT'];assembler;nostackframe;
asm
{$if defined(CPUARMV7M)}
{$ifdef CPUARM_HAS_IDIV}
sdiv r0, r0, r1
{$else}
stmfd sp!, {lr}
@ -147,7 +147,7 @@ function fpc_div_longint(n,z:longint):longint;external name 'FPC_DIV_LONGINT';
function fpc_mod_dword(n,z:dword):dword;[public,alias: 'FPC_MOD_DWORD'];assembler;nostackframe;
asm
{$if defined(CPUARMV7M)}
{$ifdef CPUARM_HAS_IDIV}
udiv r2, r0, r1
mul r2,r1,r2
sub r0,r0,r2
@ -168,7 +168,7 @@ function fpc_mod_dword(n,z:dword):dword;external name 'FPC_MOD_DWORD';
function fpc_mod_longint(n,z:longint):longint;[public,alias: 'FPC_MOD_LONGINT'];assembler;nostackframe;
asm
{$if defined(CPUARMV7M)}
{$ifdef CPUARM_HAS_IDIV}
sdiv r2, r0, r1
smull r2,r3,r1,r2
sub r0,r0,r2

View File

@ -217,6 +217,7 @@ function do_isdevice(handle:thandle):boolean;forward;
{$ifdef SYSPROCDEFINED}
{$Error Can't determine processor type !}
{$endif}
{$i armdefines.inc}
{$if defined(CPUCORTEXM3) or defined(CPUARMV7M)}
{$i thumb2.inc} { Case dependent, don't change }
{$else}

View File

@ -223,6 +223,7 @@ function do_isdevice(handle:thandle):boolean;forward;
{$ifdef SYSPROCDEFINED}
{$Error Can't determine processor type !}
{$endif}
{$i armdefines.inc}
{$if defined(CPUCORTEXM3) or defined(CPUARMV7M)}
{$i thumb2.inc} { Case dependent, don't change }
{$else}