Browse Source

+ internal bsr/bsf support for ppc32 and ppc64

git-svn-id: trunk@30152 -
Jonas Maebe 10 years ago
parent
commit
6a70c84258
3 changed files with 55 additions and 5 deletions
  1. 1 1
      compiler/options.pas
  2. 50 0
      compiler/ppcgen/cgppc.pas
  3. 4 4
      rtl/inc/systemh.inc

+ 1 - 1
compiler/options.pas

@@ -3850,7 +3850,7 @@ if (target_info.abi = abi_eabihf) then
 {$endif ARM}
 
 { inline bsf/bsr implementation }
-{$if defined(i386) or defined(x86_64) or defined(aarch64)}
+{$if defined(i386) or defined(x86_64) or defined(aarch64) or defined(powerpc) or defined(powerpc64)}
   def_system_macro('FPC_HAS_INTERNAL_BSF');
   def_system_macro('FPC_HAS_INTERNAL_BSR');
 {$endif}

+ 50 - 0
compiler/ppcgen/cgppc.pas

@@ -35,6 +35,8 @@ unit cgppc;
       tcgppcgen = class(tcg)
         procedure a_loadaddr_ref_cgpara(list : TAsmList;const r : treference;const paraloc : tcgpara); override;
 
+        procedure a_bit_scan_reg_reg(list: TAsmList; reverse: boolean; srcsize, dstsize: tcgsize; src, dst: TRegister); override;
+
         procedure a_call_reg(list : TAsmList;reg: tregister); override;
 
         { stores the contents of register reg to the memory location described by
@@ -216,6 +218,54 @@ unit cgppc;
       end;
 
 
+    procedure tcgppcgen.a_bit_scan_reg_reg(list: TAsmList; reverse: boolean; srcsize, dstsize: tcgsize; src, dst: TRegister);
+      var
+        tmpreg: tregister;
+        cntlzop: tasmop;
+        bitsizem1: longint;
+      begin
+        { we only have a cntlz(w|d) instruction, which corresponds to bsr(x)
+         (well, regsize_in_bits - bsr(x), as x86 numbers bits in reverse).
+          Fortunately, bsf(x) can be calculated easily based on that, see
+          "Figure 5-13. Number of Powers of 2 Code Sequence" in the PowerPC
+          Compiler Writer's Guide
+        }
+        if srcsize in [OS_64,OS_S64] then
+          begin
+{$ifdef powerpc64}
+            cntlzop:=A_CNTLZD;
+{$else}
+            internalerror(2015022601);
+{$endif}
+            bitsizem1:=63;
+          end
+        else
+          begin
+            cntlzop:=A_CNTLZW;
+            bitsizem1:=31;
+          end;
+        if not reverse then
+          begin
+            { cntlzw(src and -src) }
+            tmpreg:=getintregister(list,srcsize);
+            { don't use a_op_reg_reg, as this will adjust the result
+              after the neg in case of a non-32/64 bit operation, which
+              is not necessary since we're only using it as an
+              AND-mask }
+            list.concat(taicpu.op_reg_reg(A_NEG,tmpreg,src));
+            a_op_reg_reg(list,OP_AND,srcsize,src,tmpreg);
+          end
+        else
+          tmpreg:=src;
+        { count leading zeroes }
+        list.concat(taicpu.op_reg_reg(cntlzop,dst,tmpreg));
+        { (bitsize-1) - cntlz (which is 32/64 in case src was 0) }
+        list.concat(taicpu.op_reg_reg_const(A_SUBFIC,dst,dst,bitsizem1));
+        { set to 255 is source was 0 }
+        a_op_const_reg(list,OP_AND,dstsize,255,dst);
+      end;
+
+
     procedure tcgppcgen.g_maybe_got_init(list: TAsmList);
       var
          instr: taicpu;

+ 4 - 4
rtl/inc/systemh.inc

@@ -987,23 +987,23 @@ function fpc_SarInt64(Const AValue : Int64;const Shift : Byte): Int64;compilerpr
 {$endif FPC_HAS_INTERNAL_SAR_QWORD}
 
 {$ifdef FPC_HAS_INTERNAL_BSF}
-{$if defined(cpui386) or defined(cpux86_64) or defined(cpuarm) or defined(cpuaarch64)}
+{$if defined(cpui386) or defined(cpux86_64) or defined(cpuarm) or defined(cpuaarch64) or defined(cpupowerpc32) or defined(cpupowerpc64)}
 {$define FPC_HAS_INTERNAL_BSF_BYTE}
 {$define FPC_HAS_INTERNAL_BSF_WORD}
 {$define FPC_HAS_INTERNAL_BSF_DWORD}
 {$endif}
-{$if defined(cpux86_64) or defined(cpuaarch64)}
+{$if defined(cpux86_64) or defined(cpuaarch64) or defined(cpupowerpc64)}
 {$define FPC_HAS_INTERNAL_BSF_QWORD}
 {$endif}
 {$endif}
 
 {$ifdef FPC_HAS_INTERNAL_BSR}
-{$if defined(cpui386) or defined(cpux86_64) or defined(cpuarm) or defined(cpuaarch64)}
+{$if defined(cpui386) or defined(cpux86_64) or defined(cpuarm) or defined(cpuaarch64) or defined(cpupowerpc32) or defined(cpupowerpc64)}
 {$define FPC_HAS_INTERNAL_BSR_BYTE}
 {$define FPC_HAS_INTERNAL_BSR_WORD}
 {$define FPC_HAS_INTERNAL_BSR_DWORD}
 {$endif}
-{$if defined(cpux86_64) or defined(cpuaarch64)}
+{$if defined(cpux86_64) or defined(cpuaarch64) or defined(cpupowerpc64)}
 {$define FPC_HAS_INTERNAL_BSR_QWORD}
 {$endif}
 {$endif}