Browse Source

+ TSparcmoddivnode.pass_generate_code for SPARC64

git-svn-id: trunk@36637 -
florian 8 years ago
parent
commit
4b30e5ee11
1 changed files with 166 additions and 2 deletions
  1. 166 2
      compiler/sparcgen/ncpumat.pas

+ 166 - 2
compiler/sparcgen/ncpumat.pas

@@ -66,6 +66,170 @@ implementation
                              TSparcMODDIVNODE
                              TSparcMODDIVNODE
 *****************************************************************************}
 *****************************************************************************}
 
 
+{$ifdef sparc64}
+    procedure tSparcmoddivnode.pass_generate_code;
+      const
+                    { 64 bit   signed  overflow }
+        divops: array[boolean, boolean, boolean] of tasmop =
+          (((A_UDIV,A_UDIVcc),(A_SDIV,A_SDIVcc)),
+           ((A_UDIVX,A_NOP),(A_SDIVX,A_NOP))
+          );
+      var
+         power      : longint;
+         op         : tasmop;
+         tmpreg,
+         numerator,
+         divider,
+         resultreg  : tregister;
+         overflowlabel : tasmlabel;
+         ai : taicpu;
+      begin
+         secondpass(left);
+         secondpass(right);
+         location_reset(location,LOC_REGISTER,def_cgsize(resultdef));
+         location.register:=cg.GetIntRegister(current_asmdata.CurrAsmList,OS_INT);
+
+         { put numerator in register }
+         hlcg.location_force_reg(current_asmdata.CurrAsmList,left.location,left.resultdef,left.resultdef,true);
+         numerator := left.location.register;
+         resultreg := location.register;
+
+         if is_64bitint(resultdef) then
+           begin
+             if (nodetype = divn) and
+                (right.nodetype = ordconstn) and
+                ispowerof2(tordconstnode(right).value.svalue,power) and
+                (not (cs_check_overflow in current_settings.localswitches)) then
+               begin
+                 if is_signed(left.resultdef) Then
+                   begin
+                     tmpreg:=cg.GetIntRegister(current_asmdata.CurrAsmList,OS_INT);
+                     cg.a_op_const_reg_reg(current_asmdata.CurrAsmList,OP_SAR,OS_INT,63,numerator,tmpreg);
+                     { if signed, tmpreg=right value-1, otherwise 0 }
+                     cg.a_op_const_reg(current_asmdata.CurrAsmList,OP_AND,OS_INT,tordconstnode(right).value.svalue-1,tmpreg);
+                     { add to the left value }
+                     cg.a_op_reg_reg(current_asmdata.CurrAsmList,OP_ADD,OS_INT,numerator,tmpreg);
+                     cg.a_op_const_reg_reg(current_asmdata.CurrAsmList,OP_SAR,OS_INT,aword(power),tmpreg,resultreg);
+                   end
+                 else
+                   cg.a_op_const_reg_reg(current_asmdata.CurrAsmList,OP_SHR,OS_INT,aword(power),numerator,resultreg);
+               end
+             else
+               begin
+                 { load divider in a register if necessary }
+                 divider:=NR_NO;
+                 if (right.location.loc<>LOC_CONSTANT) or
+                    (right.location.value<simm13lo) or
+                    (right.location.value>simm13hi) then
+                   begin
+                     hlcg.location_force_reg(current_asmdata.CurrAsmList,right.location,
+                       right.resultdef,right.resultdef,true);
+                     divider:=right.location.register;
+                   end;
+
+                 op := divops[true, is_signed(right.resultdef),
+                              cs_check_overflow in current_settings.localswitches];
+                 if (divider<>NR_NO) then
+                   current_asmdata.CurrAsmList.concat(taicpu.op_reg_reg_reg(op,numerator,divider,resultreg))
+                 else
+                   current_asmdata.CurrAsmList.concat(taicpu.op_reg_const_reg(op,numerator,right.location.value,resultreg));
+
+                 if (nodetype = modn) then
+                   begin
+                     current_asmdata.getjumplabel(overflowlabel);
+                     ai:=taicpu.op_cond_sym(A_Bxx,C_VS,overflowlabel);
+                     ai.delayslot_annulled:=true;
+                     current_asmdata.CurrAsmList.concat(ai);
+                     current_asmdata.CurrAsmList.concat(taicpu.op_reg(A_NOT,resultreg));
+                     cg.a_label(current_asmdata.CurrAsmList,overflowlabel);
+                     if (divider<>NR_NO) then
+                       current_asmdata.CurrAsmList.concat(taicpu.op_reg_reg_reg(A_MULX,resultreg,divider,resultreg))
+                     else
+                       current_asmdata.CurrAsmList.concat(taicpu.op_reg_const_reg(A_MULX,resultreg,right.location.value,resultreg));
+                     current_asmdata.CurrAsmList.concat(taicpu.op_reg_reg_reg(A_SUB,numerator,resultreg,resultreg));
+                   end;
+               end;
+           end
+         else
+           begin
+             if (nodetype = divn) and
+                (right.nodetype = ordconstn) and
+                ispowerof2(tordconstnode(right).value.svalue,power) and
+                (not (cs_check_overflow in current_settings.localswitches)) then
+               begin
+                 if is_signed(left.resultdef) Then
+                   begin
+                     tmpreg:=cg.GetIntRegister(current_asmdata.CurrAsmList,OS_INT);
+                     cg.a_op_const_reg_reg(current_asmdata.CurrAsmList,OP_SAR,OS_INT,31,numerator,tmpreg);
+                     { if signed, tmpreg=right value-1, otherwise 0 }
+                     cg.a_op_const_reg(current_asmdata.CurrAsmList,OP_AND,OS_INT,tordconstnode(right).value.svalue-1,tmpreg);
+                     { add to the left value }
+                     cg.a_op_reg_reg(current_asmdata.CurrAsmList,OP_ADD,OS_INT,numerator,tmpreg);
+                     cg.a_op_const_reg_reg(current_asmdata.CurrAsmList,OP_SAR,OS_INT,aword(power),tmpreg,resultreg);
+                   end
+                 else
+                   cg.a_op_const_reg_reg(current_asmdata.CurrAsmList,OP_SHR,OS_INT,aword(power),numerator,resultreg);
+               end
+             else
+               begin
+                 { load divider in a register if necessary }
+                 divider:=NR_NO;
+                 if (right.location.loc<>LOC_CONSTANT) or
+                    (right.location.value<simm13lo) or
+                    (right.location.value>simm13hi) then
+                   begin
+                     hlcg.location_force_reg(current_asmdata.CurrAsmList,right.location,
+                       right.resultdef,right.resultdef,true);
+                     divider:=right.location.register;
+                   end;
+
+                 { needs overflow checking, (-maxlongint-1) div (-1) overflows! }
+                 { And on Sparc, the only way to catch a div-by-0 is by checking  }
+                 { the overflow flag (JM)                                       }
+
+                 { Fill %y with the -1 or 0 depending on the highest bit }
+                 if is_signed(left.resultdef) then
+                   begin
+                     tmpreg:=cg.GetIntRegister(current_asmdata.CurrAsmList,OS_INT);
+                     current_asmdata.CurrAsmList.concat(taicpu.op_reg_const_reg(A_SRA,numerator,31,tmpreg));
+                     current_asmdata.CurrAsmList.concat(taicpu.op_reg_reg(A_MOV,tmpreg,NR_Y));
+                   end
+                 else
+                   current_asmdata.CurrAsmList.concat(taicpu.op_reg_reg(A_MOV,NR_G0,NR_Y));
+                 { wait 3 instructions slots before we can read %y }
+                 current_asmdata.CurrAsmList.concat(taicpu.op_none(A_NOP));
+                 current_asmdata.CurrAsmList.concat(taicpu.op_none(A_NOP));
+                 current_asmdata.CurrAsmList.concat(taicpu.op_none(A_NOP));
+
+                 op := divops[false, is_signed(right.resultdef),
+                              cs_check_overflow in current_settings.localswitches];
+                 if (divider<>NR_NO) then
+                   current_asmdata.CurrAsmList.concat(taicpu.op_reg_reg_reg(op,numerator,divider,resultreg))
+                 else
+                   current_asmdata.CurrAsmList.concat(taicpu.op_reg_const_reg(op,numerator,right.location.value,resultreg));
+
+                 if (nodetype = modn) then
+                   begin
+                     current_asmdata.getjumplabel(overflowlabel);
+                     ai:=taicpu.op_cond_sym(A_Bxx,C_VS,overflowlabel);
+                     ai.delayslot_annulled:=true;
+                     current_asmdata.CurrAsmList.concat(ai);
+                     current_asmdata.CurrAsmList.concat(taicpu.op_reg(A_NOT,resultreg));
+                     cg.a_label(current_asmdata.CurrAsmList,overflowlabel);
+                     if (divider<>NR_NO) then
+                       current_asmdata.CurrAsmList.concat(taicpu.op_reg_reg_reg(A_SMUL,resultreg,divider,resultreg))
+                     else
+                       current_asmdata.CurrAsmList.concat(taicpu.op_reg_const_reg(A_SMUL,resultreg,right.location.value,resultreg));
+                     current_asmdata.CurrAsmList.concat(taicpu.op_reg_reg_reg(A_SUB,numerator,resultreg,resultreg));
+                   end;
+               end;
+           end;
+        { set result location }
+        location.loc:=LOC_REGISTER;
+        location.register:=resultreg;
+        cg.g_overflowcheck(current_asmdata.CurrAsmList,Location,resultdef);
+      end;
+{$else sparc64}
     procedure tSparcmoddivnode.pass_generate_code;
     procedure tSparcmoddivnode.pass_generate_code;
       const
       const
                     { signed   overflow }
                     { signed   overflow }
@@ -167,7 +331,7 @@ implementation
         location.register:=resultreg;
         location.register:=resultreg;
         cg.g_overflowcheck(current_asmdata.CurrAsmList,Location,resultdef);
         cg.g_overflowcheck(current_asmdata.CurrAsmList,Location,resultdef);
       end;
       end;
-
+{$endif sparc64}
 
 
 {*****************************************************************************
 {*****************************************************************************
                              TSparcSHLRSHRNODE
                              TSparcSHLRSHRNODE
@@ -283,7 +447,7 @@ implementation
 {$endif SPARC64}
 {$endif SPARC64}
                     current_asmdata.CurrAsmList.concat(taicpu.op_reg_const_reg(A_SUBcc,left.location.register,0,NR_G0));
                     current_asmdata.CurrAsmList.concat(taicpu.op_reg_const_reg(A_SUBcc,left.location.register,0,NR_G0));
                   location_reset(location,LOC_FLAGS,OS_NO);
                   location_reset(location,LOC_FLAGS,OS_NO);
-                  location.resflags:=F_E;
+                  location.resflags.Init(NR_ICC,F_E);
                end;
                end;
               else
               else
                 internalerror(2003042401);
                 internalerror(2003042401);