Browse Source

* i386: switch the div/mod node to shared code, leaving in place the specific optimization for division by power of 2.

git-svn-id: trunk@27975 -
sergei 11 years ago
parent
commit
5356f17fa5
1 changed files with 27 additions and 161 deletions
  1. 27 161
      compiler/i386/n386mat.pas

+ 27 - 161
compiler/i386/n386mat.pas

@@ -29,7 +29,7 @@ interface
       node,nmat,ncgmat,nx86mat;
       node,nmat,ncgmat,nx86mat;
 
 
     type
     type
-      ti386moddivnode = class(tmoddivnode)
+      ti386moddivnode = class(tx86moddivnode)
          procedure pass_generate_code;override;
          procedure pass_generate_code;override;
       end;
       end;
 
 
@@ -65,177 +65,43 @@ implementation
 
 
    procedure ti386moddivnode.pass_generate_code;
    procedure ti386moddivnode.pass_generate_code;
       var
       var
-        hreg1,hreg2:Tregister;
+        hreg1:Tregister;
         power:longint;
         power:longint;
         hl:Tasmlabel;
         hl:Tasmlabel;
-        op:Tasmop;
-        e : longint;
-        d,m: dword;
-        s: byte;
-        sm: aint;
-        m_add: boolean;
       begin
       begin
-        secondpass(left);
-        if codegenerror then
-          exit;
-        secondpass(right);
-        if codegenerror then
-          exit;
-
         if is_64bitint(resultdef) then
         if is_64bitint(resultdef) then
           { should be handled in pass_1 (JM) }
           { should be handled in pass_1 (JM) }
           internalerror(200109052);
           internalerror(200109052);
-        { put numerator in register }
-        location_reset(location,LOC_REGISTER,def_cgsize(resultdef));
-        hlcg.location_force_reg(current_asmdata.CurrAsmList,left.location,left.resultdef,resultdef,false);
-        hreg1:=left.location.register;
 
 
-        if (nodetype=divn) and (right.nodetype=ordconstn) then
+        if (nodetype=divn) and (right.nodetype=ordconstn) and
+          is_signed(left.resultdef) and
+          ispowerof2(tordconstnode(right).value.svalue,power) and
+          ((current_settings.optimizecputype = cpu_386) or
+           (cs_opt_size in current_settings.optimizerswitches)) then
           begin
           begin
-            if ispowerof2(tordconstnode(right).value.svalue,power) then
-              begin
-                { for signed numbers, the numerator must be adjusted before the
-                  shift instruction, but not wih unsigned numbers! Otherwise,
-                  "Cardinal($ffffffff) div 16" overflows! (JM) }
-                if is_signed(left.resultdef) Then
-                  begin
-                    if (current_settings.optimizecputype <> cpu_386) and
-                       not(cs_opt_size in current_settings.optimizerswitches) then
-                      { use a sequence without jumps, saw this in
-                        comp.compilers (JM) }
-                      begin
-                        { no jumps, but more operations }
-                        hreg2:=cg.getintregister(current_asmdata.CurrAsmList,OS_INT);
-                        emit_reg_reg(A_MOV,S_L,hreg1,hreg2);
-                        {If the left value is signed, hreg2=$ffffffff, otherwise 0.}
-                        emit_const_reg(A_SAR,S_L,31,hreg2);
-                        {If signed, hreg2=right value-1, otherwise 0.}
-                        emit_const_reg(A_AND,S_L,tordconstnode(right).value.svalue-1,hreg2);
-                        { add to the left value }
-                        emit_reg_reg(A_ADD,S_L,hreg2,hreg1);
-                        { do the shift }
-                        emit_const_reg(A_SAR,S_L,power,hreg1);
-                      end
-                    else
-                      begin
-                        { a jump, but less operations }
-                        emit_reg_reg(A_TEST,S_L,hreg1,hreg1);
-                        current_asmdata.getjumplabel(hl);
-                        cg.a_jmp_flags(current_asmdata.CurrAsmList,F_NS,hl);
-                        if power=1 then
-                          emit_reg(A_INC,S_L,hreg1)
-                        else
-                          emit_const_reg(A_ADD,S_L,tordconstnode(right).value.svalue-1,hreg1);
-                        cg.a_label(current_asmdata.CurrAsmList,hl);
-                        emit_const_reg(A_SAR,S_L,power,hreg1);
-                      end
-                  end
-                else
-                  emit_const_reg(A_SHR,S_L,power,hreg1);
-                location.register:=hreg1;
-              end
+            { signed divide-by-power-of-two optimized for size }
+            secondpass(left);
+            if codegenerror then
+              exit;
+            secondpass(right);
+            if codegenerror then
+              exit;
+            hlcg.location_force_reg(current_asmdata.CurrAsmList,left.location,left.resultdef,resultdef,false);
+            hreg1:=left.location.register;
+            emit_reg_reg(A_TEST,S_L,hreg1,hreg1);
+            current_asmdata.getjumplabel(hl);
+            cg.a_jmp_flags(current_asmdata.CurrAsmList,F_NS,hl);
+            if power=1 then
+              emit_reg(A_INC,S_L,hreg1)
             else
             else
-              begin
-                if is_signed(left.resultdef) then
-                  begin
-                    e:=tordconstnode(right).value.svalue;
-                    calc_divconst_magic_signed(32,e,sm,s);
-                    cg.getcpuregister(current_asmdata.CurrAsmList,NR_EAX);
-                    emit_const_reg(A_MOV,S_L,sm,NR_EAX);
-                    cg.getcpuregister(current_asmdata.CurrAsmList,NR_EDX);
-                    emit_reg(A_IMUL,S_L,hreg1);
-                    { only the high half of result is used }
-                    cg.ungetcpuregister(current_asmdata.CurrAsmList,NR_EAX);
-                    { add or subtract dividend }
-                    if (e>0) and (sm<0) then
-                      emit_reg_reg(A_ADD,S_L,hreg1,NR_EDX)
-                    else if (e<0) and (sm>0) then
-                      emit_reg_reg(A_SUB,S_L,hreg1,NR_EDX);
-                    { shift if necessary }
-                    if (s<>0) then
-                      emit_const_reg(A_SAR,S_L,s,NR_EDX);
-                    { extract and add the sign bit }
-                    if (e<0) then
-                      emit_reg_reg(A_MOV,S_L,NR_EDX,hreg1);
-                    { if e>=0, hreg1 still contains dividend }
-                    emit_const_reg(A_SHR,S_L,31,hreg1);
-                    emit_reg_reg(A_ADD,S_L,hreg1,NR_EDX);
-                    cg.ungetcpuregister(current_asmdata.CurrAsmList,NR_EDX);
-                    location.register:=cg.getintregister(current_asmdata.CurrAsmList,OS_INT);
-                    cg.a_load_reg_reg(current_asmdata.CurrAsmList,OS_INT,OS_INT,NR_EDX,location.register)
-                  end
-                else
-                  begin
-                    d:=tordconstnode(right).value.svalue;
-                    if d>=$80000000 then
-                      begin
-                        emit_const_reg(A_CMP,S_L,aint(d),hreg1);
-                        location.register:=cg.getintregister(current_asmdata.CurrAsmList,OS_INT);
-                        emit_const_reg(A_MOV,S_L,0,location.register);
-                        emit_const_reg(A_SBB,S_L,-1,location.register);
-                      end
-                    else
-                      begin
-                        calc_divconst_magic_unsigned(32,d,m,m_add,s);
-                        cg.getcpuregister(current_asmdata.CurrAsmList,NR_EAX);
-                        emit_const_reg(A_MOV,S_L,aint(m),NR_EAX);
-                        cg.getcpuregister(current_asmdata.CurrAsmList,NR_EDX);
-                        emit_reg(A_MUL,S_L,hreg1);
-                        cg.ungetcpuregister(current_asmdata.CurrAsmList,NR_EAX);
-                        if m_add then
-                          begin
-                            { addition can overflow, shift first bit considering carry,
-                              then shift remaining bits in regular way. }
-                            emit_reg_reg(A_ADD,S_L,hreg1,NR_EDX);
-                            emit_const_reg(A_RCR,S_L,1,NR_EDX);
-                            dec(s);
-                          end;
-                        if s<>0 then
-                          emit_const_reg(A_SHR,S_L,aint(s),NR_EDX);
-                        cg.ungetcpuregister(current_asmdata.CurrAsmList,NR_EDX);
-                        location.register:=cg.getintregister(current_asmdata.CurrAsmList,OS_INT);
-                        cg.a_load_reg_reg(current_asmdata.CurrAsmList,OS_INT,OS_INT,NR_EDX,location.register)
-                      end;
-                  end
-              end
+              emit_const_reg(A_ADD,S_L,tordconstnode(right).value.svalue-1,hreg1);
+            cg.a_label(current_asmdata.CurrAsmList,hl);
+            emit_const_reg(A_SAR,S_L,power,hreg1);
+            location_reset(location,LOC_REGISTER,def_cgsize(resultdef));
+            location.register:=hreg1;
           end
           end
         else
         else
-          begin
-            cg.getcpuregister(current_asmdata.CurrAsmList,NR_EAX);
-            emit_reg_reg(A_MOV,S_L,hreg1,NR_EAX);
-            cg.getcpuregister(current_asmdata.CurrAsmList,NR_EDX);
-            {Sign extension depends on the left type.}
-            if torddef(left.resultdef).ordtype=u32bit then
-              emit_reg_reg(A_XOR,S_L,NR_EDX,NR_EDX)
-            else
-              emit_none(A_CDQ,S_NO);
-
-            {Division depends on the right type.}
-            if Torddef(right.resultdef).ordtype=u32bit then
-              op:=A_DIV
-            else
-              op:=A_IDIV;
-
-            if right.location.loc in [LOC_REFERENCE,LOC_CREFERENCE] then
-              emit_ref(op,S_L,right.location.reference)
-            else if right.location.loc in [LOC_REGISTER,LOC_CREGISTER] then
-              emit_reg(op,S_L,right.location.register)
-            else
-              begin
-                hreg1:=cg.getintregister(current_asmdata.CurrAsmList,right.location.size);
-                hlcg.a_load_loc_reg(current_asmdata.CurrAsmList,right.resultdef,u32inttype,right.location,hreg1);
-                emit_reg(op,S_L,hreg1);
-              end;
-
-            {Copy the result into a new register. Release EAX & EDX.}
-            cg.ungetcpuregister(current_asmdata.CurrAsmList,NR_EDX);
-            cg.ungetcpuregister(current_asmdata.CurrAsmList,NR_EAX);
-            location.register:=cg.getintregister(current_asmdata.CurrAsmList,OS_INT);
-            if nodetype=divn then
-              cg.a_load_reg_reg(current_asmdata.CurrAsmList,OS_INT,OS_INT,NR_EAX,location.register)
-            else
-              cg.a_load_reg_reg(current_asmdata.CurrAsmList,OS_INT,OS_INT,NR_EDX,location.register);
-          end;
+          inherited pass_generate_code;
       end;
       end;