summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--compiler/compinnr.inc1
-rw-r--r--compiler/ncginl.pas11
-rw-r--r--compiler/ninl.pas11
-rw-r--r--compiler/options.pas5
-rw-r--r--compiler/x86/nx86inl.pas24
-rw-r--r--rtl/inc/generic.inc10
-rw-r--r--rtl/inc/innr.inc1
-rw-r--r--rtl/inc/systemh.inc36
-rw-r--r--tests/test/tpopcnt1.pp28
9 files changed, 120 insertions, 7 deletions
diff --git a/compiler/compinnr.inc b/compiler/compinnr.inc
index 4c899dce03..d1cdc124aa 100644
--- a/compiler/compinnr.inc
+++ b/compiler/compinnr.inc
@@ -86,6 +86,7 @@ const
in_default_x = 76;
in_box_x = 77; { managed platforms: wrap in class instance }
in_unbox_x_y = 78; { manage platforms: extract from class instance }
+ in_popcnt_x = 79;
{ Internal constant functions }
in_const_sqr = 100;
diff --git a/compiler/ncginl.pas b/compiler/ncginl.pas
index c233ef7780..06899d684f 100644
--- a/compiler/ncginl.pas
+++ b/compiler/ncginl.pas
@@ -58,6 +58,7 @@ interface
procedure second_new; virtual;
procedure second_setlength; virtual; abstract;
procedure second_box; virtual; abstract;
+ procedure second_popcnt; virtual;
end;
implementation
@@ -177,6 +178,8 @@ implementation
second_setlength;
in_box_x:
second_box;
+ in_popcnt_x:
+ second_popcnt;
else internalerror(9);
end;
end;
@@ -734,6 +737,12 @@ implementation
end;
+ procedure tcginlinenode.second_popcnt;
+ begin
+ internalerror(2012082601);
+ end;
+
+
begin
cinlinenode:=tcginlinenode;
-end.
+end. s
diff --git a/compiler/ninl.pas b/compiler/ninl.pas
index fabf6806f2..fa2d881fd8 100644
--- a/compiler/ninl.pas
+++ b/compiler/ninl.pas
@@ -3046,6 +3046,14 @@ implementation
resultdef:=u32inttype
end;
+ in_popcnt_x:
+ begin
+ set_varstate(left,vs_read,[vsf_must_be_valid]);
+ if not is_integer(left.resultdef) then
+ CGMessage1(type_e_integer_expr_expected,left.resultdef.typename);
+ resultdef:=left.resultdef;
+ end;
+
in_objc_selector_x:
begin
result:=cobjcselectornode.create(left);
@@ -3467,7 +3475,8 @@ implementation
in_sar_x,
in_sar_x_y,
in_bsf_x,
- in_bsr_x:
+ in_bsr_x,
+ in_popcnt_x:
expectloc:=LOC_REGISTER;
in_new_x:
result:=first_new;
diff --git a/compiler/options.pas b/compiler/options.pas
index f7f29f2dec..b7563961ad 100644
--- a/compiler/options.pas
+++ b/compiler/options.pas
@@ -2781,6 +2781,11 @@ begin
def_system_macro('FPC_HAS_INTERNAL_BSX');
{$endif}
+{ inline bsf/bsr implementation }
+{$if defined(x86) or defined(x86_64)}
+ def_system_macro('FPC_HAS_INTERNAL_POPCNT');
+{$endif}
+
{$ifdef powerpc64}
def_system_macro('FPC_HAS_LWSYNC');
{$endif}
diff --git a/compiler/x86/nx86inl.pas b/compiler/x86/nx86inl.pas
index b08ca6d007..8bc07edbf5 100644
--- a/compiler/x86/nx86inl.pas
+++ b/compiler/x86/nx86inl.pas
@@ -60,6 +60,7 @@ interface
procedure second_prefetch;override;
procedure second_abs_long;override;
+ procedure second_popcnt;override;
private
procedure load_fpu_location;
end;
@@ -542,4 +543,27 @@ implementation
end;
+ procedure tx86inlinenode.second_popcnt;
+ var
+ opsize: tcgsize;
+ begin
+ secondpass(left);
+
+ opsize:=tcgsize2unsigned[left.location.size];
+
+ { no 8 Bit popcont }
+ if opsize=OS_8 then
+ opsize:=OS_16;
+
+ if not(left.location.loc in [LOC_REGISTER,LOC_CREGISTER,LOC_REFERENCE,LOC_CREFERENCE]) or
+ (left.location.size<>opsize) then
+ hlcg.location_force_reg(current_asmdata.CurrAsmList,left.location,left.resultdef,hlcg.tcgsize2orddef(opsize),true);
+
+ location_reset(location,LOC_REGISTER,opsize);
+ location.register:=cg.getintregister(current_asmdata.CurrAsmList,opsize);
+ if left.location.loc in [LOC_REGISTER,LOC_CREGISTER] then
+ current_asmdata.CurrAsmList.concat(taicpu.op_reg_reg(A_POPCNT,TCGSize2OpSize[opsize],left.location.register,location.register))
+ else
+ current_asmdata.CurrAsmList.concat(taicpu.op_ref_reg(A_POPCNT,TCGSize2OpSize[opsize],left.location.reference,location.register));
+ end;
end.
diff --git a/rtl/inc/generic.inc b/rtl/inc/generic.inc
index 856ad35899..b0d194d75e 100644
--- a/rtl/inc/generic.inc
+++ b/rtl/inc/generic.inc
@@ -2444,3 +2444,13 @@ function BsrQWord(Const AValue : QWord): cardinal;
end;
{$endif}
{$endif}
+
+{$ifndef FPC_HAS_INTERNAL_POPCNT_QWORD}
+{$ifndef FPC_SYSTEM_HAS_POPCNT_QWORD}
+function PopCnt(Const AValue : QWord): QWord;
+ begin
+ Result:=PopCnt(lo(AValue))+PopCnt(hi(AValue))
+ end;
+{$endif}
+{$endif}
+
diff --git a/rtl/inc/innr.inc b/rtl/inc/innr.inc
index c9324dcc57..dd655b4d6f 100644
--- a/rtl/inc/innr.inc
+++ b/rtl/inc/innr.inc
@@ -87,6 +87,7 @@ const
fpc_in_default_x = 76;
fpc_in_box_x = 77; { managed platforms: wrap in class instance }
fpc_in_unbox_x_y = 78; { manage platforms: extract from class instance }
+ fpc_in_popcnt_x = 79;
{ Internal constant functions }
fpc_in_const_sqr = 100;
diff --git a/rtl/inc/systemh.inc b/rtl/inc/systemh.inc
index a4715dd2a9..0ba1e9124f 100644
--- a/rtl/inc/systemh.inc
+++ b/rtl/inc/systemh.inc
@@ -860,6 +860,42 @@ function BsfQWord(Const AValue : QWord): cardinal;{$ifdef SYSTEMINLINE}inline;{$
function BsrQWord(Const AValue : QWord): cardinal;{$ifdef SYSTEMINLINE}inline;{$endif}
{$endif FPC_HAS_INTERNAL_BSF_QWORD}
+{$ifdef FPC_HAS_INTERNAL_POPCNT}
+{$if defined(cpui386) or defined(cpux86_64)}
+{$define FPC_HAS_INTERNAL_POPCNT_BYTE}
+{$define FPC_HAS_INTERNAL_POPCNT_WORD}
+{$define FPC_HAS_INTERNAL_POPCNT_DWORD}
+{$endif}
+{$if defined(cpux86_64)}
+{$define FPC_HAS_INTERNAL_POPCNT_QWORD}
+{$endif}
+{$endif}
+
+
+{$ifdef FPC_HAS_INTERNAL_POPCNT_BYTE}
+function PopCnt(Const AValue: Byte): Byte;[internproc:fpc_in_popcnt_x];
+{$else}
+function PopCnt(Const AValue: Byte): Byte;{$ifdef SYSTEMINLINE}inline;{$endif}
+{$endif FPC_HAS_INTERNAL_POPCNT_BYTE}
+
+{$ifdef FPC_HAS_INTERNAL_POPCNT_WORD}
+function PopCnt(Const AValue: Word): Word;[internproc:fpc_in_popcnt_x];
+{$else}
+function PopCnt(Const AValue: Word): Word;{$ifdef SYSTEMINLINE}inline;{$endif}
+{$endif FPC_HAS_INTERNAL_POPCNT_WORD}
+
+{$ifdef FPC_HAS_INTERNAL_POPCNT_DWORD}
+function PopCnt(Const AValue : DWord): DWord;[internproc:fpc_in_popcnt_x];
+{$else}
+function PopCnt(Const AValue : DWord): DWord;
+{$endif FPC_HAS_INTERNAL_POPCNT_DWORD}
+
+{$ifdef FPC_HAS_INTERNAL_POPCNT_QWORD}
+function PopCnt(Const AValue : QWord): QWord;[internproc:fpc_in_popcnt_x];
+{$else}
+function PopCnt(Const AValue : QWord): QWord;
+{$endif FPC_HAS_INTERNAL_POPCNT_QWORD}
+
{$ifndef FPUNONE}
{ float math routines }
{$I mathh.inc}
diff --git a/tests/test/tpopcnt1.pp b/tests/test/tpopcnt1.pp
index 993847865d..ad3a8aa333 100644
--- a/tests/test/tpopcnt1.pp
+++ b/tests/test/tpopcnt1.pp
@@ -5,7 +5,7 @@ var
i : integer;
d : dword;
li : longint;
- q : qword
+ q : qword;
i64 : int64;
begin
@@ -23,6 +23,9 @@ begin
if popcnt(b)<>1 then
halt(1);
+ writeln('popcnt(<byte>); passed');
+
+{
si:=$54;
if popcnt(si)<>3 then
halt(1);
@@ -34,6 +37,7 @@ begin
si:=$20;
if popcnt(si)<>1 then
halt(1);
+}
{ 16 Bit }
@@ -49,6 +53,9 @@ begin
if popcnt(w)<>2 then
halt(1);
+ writeln('popcnt(<word>); passed');
+
+{
i:=$5454;
if popcnt(i)<>6 then
halt(1);
@@ -60,11 +67,12 @@ begin
i:=$2020;
if popcnt(i)<>2 then
halt(1);
+}
{ 32 Bit }
d:=$a4a4a4a4;
- if popcnt(w)<>12 then
+ if popcnt(d)<>12 then
halt(1);
d:=$0;
@@ -75,6 +83,9 @@ begin
if popcnt(d)<>4 then
halt(1);
+ writeln('popcnt(<dword>); passed');
+
+{
li:=$54545454;
if popcnt(li)<>12 then
halt(1);
@@ -86,11 +97,11 @@ begin
li:=$20402080;
if popcnt(li)<>4 then
halt(1);
-
+}
{ 64 Bit }
- q:=$a4a4a4a4a4a4a4a4;
+ q:=qword($a4a4a4a4a4a4a4a4);
if popcnt(q)<>24 then
halt(1);
@@ -102,6 +113,13 @@ begin
if popcnt(q)<>8 then
halt(1);
+ q:=qword($a4a4a4a400000000);
+ if popcnt(q)<>12 then
+ halt(1);
+
+ writeln('popcnt(<qword>); passed');
+
+{
i64:=$5454545454545454;
if popcnt(i64)<>24 then
halt(1);
@@ -113,7 +131,7 @@ begin
i64:=$2040208020402080;
if popcnt(li)<>8 then
halt(1);
-
+}
writeln('ok');
end.