mirror of
https://gitlab.com/freepascal.org/fpc/source.git
synced 2025-10-16 15:46:14 +02:00
392 lines
9.0 KiB
PHP
392 lines
9.0 KiB
PHP
{
|
|
$Id$
|
|
This file is part of the Free Pascal run time library.
|
|
Copyright (c) 2002 by Florian Klaempfl.
|
|
Member of the Free Pascal development team
|
|
|
|
Parts of this code are derived from the x86-64 linux port
|
|
Copyright 2002 Andi Kleen
|
|
|
|
Processor dependent implementation for the system unit for
|
|
the x86-64 architecture
|
|
|
|
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.
|
|
|
|
**********************************************************************}
|
|
|
|
{$asmmode GAS}
|
|
|
|
{****************************************************************************
|
|
Primitives
|
|
****************************************************************************}
|
|
|
|
procedure fpc_cpuinit;
|
|
begin
|
|
end;
|
|
|
|
|
|
{$define FPC_SYSTEM_HAS_SPTR}
|
|
Function Sptr : Pointer;assembler;{$ifdef SYSTEMINLINE}inline;{$endif}
|
|
asm
|
|
movq %rsp,%rax
|
|
end ['RAX'];
|
|
|
|
|
|
{$define FPC_SYSTEM_HAS_GET_FRAME}
|
|
function get_frame:pointer;assembler;{$ifdef SYSTEMINLINE}inline;{$endif}
|
|
asm
|
|
movq %rbp,%rax
|
|
end ['RAX'];
|
|
|
|
|
|
{$define FPC_SYSTEM_HAS_GET_CALLER_ADDR}
|
|
function get_caller_addr(framebp:pointer):pointer;assembler;{$ifdef SYSTEMINLINE}inline;{$endif}
|
|
asm
|
|
{ %rdi = framebp }
|
|
orq %rdi,%rdi
|
|
jz .Lg_a_null
|
|
movq 8(%rdi),%rax
|
|
.Lg_a_null:
|
|
end ['RAX'];
|
|
|
|
|
|
{$define FPC_SYSTEM_HAS_GET_CALLER_FRAME}
|
|
function get_caller_frame(framebp:pointer):pointer;assembler;{$ifdef SYSTEMINLINE}inline;{$endif}
|
|
asm
|
|
{ %rdi = framebp }
|
|
orq %rdi,%rdi
|
|
jz .Lg_a_null
|
|
movq (%rdi),%rax
|
|
.Lg_a_null:
|
|
end ['RAX'];
|
|
|
|
(*
|
|
{$define FPC_SYSTEM_HAS_MOVE}
|
|
procedure Move(const source;var dest;count:longint);[public, alias: 'FPC_MOVE'];assembler;
|
|
asm
|
|
{ rdi destination
|
|
rsi source
|
|
rdx count
|
|
}
|
|
pushq %rbx
|
|
prefetcht0 (%rsi) // for more hopefully the hw prefetch will kick in
|
|
movq %rdi,%rax
|
|
|
|
movl %edi,%ecx
|
|
andl $7,%ecx
|
|
jnz .Lbad_alignment
|
|
.Lafter_bad_alignment:
|
|
movq %rdx,%rcx
|
|
movl $64,%ebx
|
|
shrq $6,%rcx
|
|
jz .Lhandle_tail
|
|
|
|
.Lloop_64:
|
|
{ no prefetch because we assume the hw prefetcher does it already
|
|
and we have no specific temporal hint to give. XXX or give a nta
|
|
hint for the source? }
|
|
movq (%rsi),%r11
|
|
movq 8(%rsi),%r8
|
|
movq 2*8(%rsi),%r9
|
|
movq 3*8(%rsi),%r10
|
|
movnti %r11,(%rdi)
|
|
movnti %r8,1*8(%rdi)
|
|
movnti %r9,2*8(%rdi)
|
|
movnti %r10,3*8(%rdi)
|
|
|
|
movq 4*8(%rsi),%r11
|
|
movq 5*8(%rsi),%r8
|
|
movq 6*8(%rsi),%r9
|
|
movq 7*8(%rsi),%r10
|
|
movnti %r11,4*8(%rdi)
|
|
movnti %r8,5*8(%rdi)
|
|
movnti %r9,6*8(%rdi)
|
|
movnti %r10,7*8(%rdi)
|
|
|
|
addq %rbx,%rsi
|
|
addq %rbx,%rdi
|
|
loop .Lloop_64
|
|
|
|
.Lhandle_tail:
|
|
movl %edx,%ecx
|
|
andl $63,%ecx
|
|
shrl $3,%ecx
|
|
jz .Lhandle_7
|
|
movl $8,%ebx
|
|
.Lloop_8:
|
|
movq (%rsi),%r8
|
|
movnti %r8,(%rdi)
|
|
addq %rbx,%rdi
|
|
addq %rbx,%rsi
|
|
loop .Lloop_8
|
|
|
|
.Lhandle_7:
|
|
movl %edx,%ecx
|
|
andl $7,%ecx
|
|
jz .Lende
|
|
.Lloop_1:
|
|
movb (%rsi),%r8b
|
|
movb %r8b,(%rdi)
|
|
incq %rdi
|
|
incq %rsi
|
|
loop .Lloop_1
|
|
|
|
jmp .Lende
|
|
|
|
{ align destination }
|
|
{ This is simpleminded. For bigger blocks it may make sense to align
|
|
src and dst to their aligned subset and handle the rest separately }
|
|
.Lbad_alignment:
|
|
movl $8,%r9d
|
|
subl %ecx,%r9d
|
|
movl %r9d,%ecx
|
|
subq %r9,%rdx
|
|
js .Lsmall_alignment
|
|
jz .Lsmall_alignment
|
|
.Lalign_1:
|
|
movb (%rsi),%r8b
|
|
movb %r8b,(%rdi)
|
|
incq %rdi
|
|
incq %rsi
|
|
loop .Lalign_1
|
|
jmp .Lafter_bad_alignment
|
|
.Lsmall_alignment:
|
|
addq %r9,%rdx
|
|
jmp .Lhandle_7
|
|
|
|
.Lende:
|
|
sfence
|
|
popq %rbx
|
|
end;
|
|
*)
|
|
|
|
(*
|
|
{$define FPC_SYSTEM_HAS_FILLCHAR}
|
|
Procedure FillChar(var x;count:longint;value:byte);assembler;
|
|
asm
|
|
{ rdi destination
|
|
rsi value (char)
|
|
rdx count (bytes)
|
|
}
|
|
movq %rdi,%r10
|
|
movq %rdx,%r11
|
|
|
|
{ expand byte value }
|
|
movzbl %sil,%ecx
|
|
movabs $0x0101010101010101,%rax
|
|
mul %rcx { with rax, clobbers rdx }
|
|
|
|
{ align dst }
|
|
movl %edi,%r9d
|
|
andl $7,%r9d
|
|
jnz .Lbad_alignment
|
|
.Lafter_bad_alignment:
|
|
|
|
movq %r11,%rcx
|
|
movl $64,%r8d
|
|
shrq $6,%rcx
|
|
jz .Lhandle_tail
|
|
|
|
.Lloop_64:
|
|
movnti %rax,(%rdi)
|
|
movnti %rax,8(%rdi)
|
|
movnti %rax,16(%rdi)
|
|
movnti %rax,24(%rdi)
|
|
movnti %rax,32(%rdi)
|
|
movnti %rax,40(%rdi)
|
|
movnti %rax,48(%rdi)
|
|
movnti %rax,56(%rdi)
|
|
addq %r8,%rdi
|
|
loop .Lloop_64
|
|
|
|
{ Handle tail in loops. The loops should be faster than hard
|
|
to predict jump tables. }
|
|
.Lhandle_tail:
|
|
movl %r11d,%ecx
|
|
andl $56,%ecx
|
|
jz .Lhandle_7
|
|
shrl $3,%ecx
|
|
.Lloop_8:
|
|
movnti %rax,(%rdi)
|
|
addq $8,%rdi
|
|
loop .Lloop_8
|
|
.Lhandle_7:
|
|
movl %r11d,%ecx
|
|
andl $7,%ecx
|
|
jz .Lende
|
|
.Lloop_1:
|
|
movb %al,(%rdi)
|
|
addq $1,%rdi
|
|
loop .Lloop_1
|
|
|
|
jmp .Lende
|
|
|
|
.Lbad_alignment:
|
|
cmpq $7,%r11
|
|
jbe .Lhandle_7
|
|
movnti %rax,(%rdi) (* unaligned store *)
|
|
movq $8,%r8
|
|
subq %r9,%r8
|
|
addq %r8,%rdi
|
|
subq %r8,%r11
|
|
jmp .Lafter_bad_alignment
|
|
|
|
.Lende:
|
|
movq %r10,%rax
|
|
end;
|
|
*)
|
|
|
|
|
|
{$define FPC_SYSTEM_HAS_DECLOCKED_LONGINT}
|
|
{ does a thread save inc/dec }
|
|
function declocked(var l : longint) : boolean;assembler;
|
|
asm
|
|
{
|
|
l: %rdi
|
|
}
|
|
{ this check should be done because a lock takes a lot }
|
|
{ of time! }
|
|
cmpb $0,IsMultithread
|
|
jz .Ldeclockednolock
|
|
lock
|
|
decl (%rdi)
|
|
jmp .Ldeclockedend
|
|
.Ldeclockednolock:
|
|
decl (%rdi)
|
|
.Ldeclockedend:
|
|
setzb %al
|
|
end;
|
|
|
|
|
|
{$define FPC_SYSTEM_HAS_DECLOCKED_INT64}
|
|
function declocked(var l : int64) : boolean;assembler;
|
|
asm
|
|
{
|
|
l: %rdi
|
|
}
|
|
{ this check should be done because a lock takes a lot }
|
|
{ of time! }
|
|
cmpb $0,IsMultithread
|
|
jz .Ldeclockednolock
|
|
lock
|
|
decq (%rdi)
|
|
jmp .Ldeclockedend
|
|
.Ldeclockednolock:
|
|
decq (%rdi)
|
|
.Ldeclockedend:
|
|
setzb %al
|
|
end;
|
|
|
|
|
|
{$define FPC_SYSTEM_HAS_INCLOCKED_LONGINT}
|
|
procedure inclocked(var l : longint);assembler;
|
|
|
|
asm
|
|
{
|
|
l: %rdi
|
|
}
|
|
{ this check should be done because a lock takes a lot }
|
|
{ of time! }
|
|
cmpb $0,IsMultithread
|
|
jz .Linclockednolock
|
|
lock
|
|
incl (%rdi)
|
|
jmp .Linclockedend
|
|
.Linclockednolock:
|
|
incl (%rdi)
|
|
.Linclockedend:
|
|
end;
|
|
|
|
|
|
{$define FPC_SYSTEM_HAS_INCLOCKED_INT64}
|
|
procedure inclocked(var l : int64);assembler;
|
|
|
|
asm
|
|
{
|
|
l: %rdi
|
|
}
|
|
{ this check should be done because a lock takes a lot }
|
|
{ of time! }
|
|
cmpb $0,IsMultithread
|
|
jz .Linclockednolock
|
|
lock
|
|
incq (%rdi)
|
|
jmp .Linclockedend
|
|
.Linclockednolock:
|
|
incq (%rdi)
|
|
.Linclockedend:
|
|
end;
|
|
|
|
|
|
{****************************************************************************
|
|
FPU
|
|
****************************************************************************}
|
|
|
|
const
|
|
fpucw : word = $1332;
|
|
{ Internal constants for use in system unit }
|
|
FPU_Invalid = 1;
|
|
FPU_Denormal = 2;
|
|
FPU_DivisionByZero = 4;
|
|
FPU_Overflow = 8;
|
|
FPU_Underflow = $10;
|
|
FPU_StackUnderflow = $20;
|
|
FPU_StackOverflow = $40;
|
|
FPU_ExceptionMask = $ff;
|
|
|
|
{$define FPC_SYSTEM_HAS_SYSRESETFPU}
|
|
Procedure SysResetFPU;assembler;{$ifdef SYSTEMINLINE}inline;{$endif}
|
|
asm
|
|
fninit
|
|
fldcw fpucw
|
|
end;
|
|
|
|
{
|
|
$Log$
|
|
Revision 1.14 2004-11-01 20:31:35 florian
|
|
* another fix for locked reference counting
|
|
|
|
Revision 1.13 2004/06/05 07:55:22 peter
|
|
* fixed parameters of get_caller_*()
|
|
|
|
Revision 1.12 2004/05/01 15:59:17 florian
|
|
* x86_64 exception handling fixed
|
|
|
|
Revision 1.11 2004/04/29 19:50:13 peter
|
|
* x86-64 fixes
|
|
|
|
Revision 1.10 2004/04/26 15:55:01 peter
|
|
* FPC_MOVE alias
|
|
|
|
Revision 1.9 2004/04/22 20:20:16 peter
|
|
* get_caller_addr fixed
|
|
|
|
Revision 1.8 2004/04/21 21:26:51 florian
|
|
* commented out broken fillchar and move
|
|
|
|
Revision 1.7 2004/02/23 15:52:15 peter
|
|
* don't use ret
|
|
|
|
Revision 1.6 2004/02/06 15:58:21 florian
|
|
* fixed x86-64 assembler problems
|
|
|
|
Revision 1.5 2004/02/05 01:16:12 florian
|
|
+ completed x86-64/linux system unit
|
|
|
|
Revision 1.4 2004/01/20 12:52:18 florian
|
|
* some problems with x86-64 inline assembler fixed
|
|
|
|
Revision 1.3 2003/05/01 08:05:23 florian
|
|
* started to make the rtl 64 bit save by introducing SizeInt and SizeUInt (similar to size_t of C)
|
|
|
|
Revision 1.2 2003/04/30 22:11:06 florian
|
|
+ for a lot of x86-64 dependend files mostly dummies added
|
|
|
|
Revision 1.1 2003/01/06 19:40:18 florian
|
|
+ initial revision
|
|
} |