Browse Source

- Fix bug in software overflow checking for longint's.
- AVR: Fix overflow checking for HW multiplications

git-svn-id: trunk@42531 -

Jeppe Johansen 6 năm trước cách đây
mục cha
commit
1b698d319f
2 tập tin đã thay đổi với 81 bổ sung46 xóa
  1. 80 45
      compiler/avr/cgcpu.pas
  2. 1 1
      rtl/inc/generic.inc

+ 80 - 45
compiler/avr/cgcpu.pas

@@ -1848,44 +1848,31 @@ unit cgcpu;
 
     procedure tcgavr.gen_multiply(list: TAsmList; op: topcg; size: TCgSize; src2, src1, dst: tregister; check_overflow: boolean; var ovloc: tlocation);
 
-      procedure perform_r1_check;
+      procedure perform_r1_check(overflow_label: TAsmLabel; other_reg: TRegister=NR_R1);
         var
-          hl: TAsmLabel;
           ai: taicpu;
         begin
           if check_overflow then
             begin
-              current_asmdata.getjumplabel(hl);
-              list.concat(taicpu.op_reg_reg(A_AND,NR_R1,NR_R1));
+              list.concat(taicpu.op_reg_reg(A_OR,NR_R1,other_reg));
 
-              ai:=Taicpu.Op_Sym(A_BRxx,hl);
-              ai.SetCondition(C_EQ);
+              ai:=Taicpu.Op_Sym(A_BRxx,overflow_label);
+              ai.SetCondition(C_NE);
               ai.is_jmp:=true;
               list.concat(ai);
-
-              list.concat(taicpu.op_none(A_SET));
-
-              a_label(list,hl);
             end;
         end;
 
-      procedure perform_ovf_check;
+      procedure perform_ovf_check(overflow_label: TAsmLabel);
         var
           ai: taicpu;
-          hl: TAsmLabel;
         begin
           if check_overflow then
             begin
-              current_asmdata.getjumplabel(hl);
-
-              ai:=Taicpu.Op_Sym(A_BRxx,hl);
-              ai.SetCondition(C_CC);
+              ai:=Taicpu.Op_Sym(A_BRxx,overflow_label);
+              ai.SetCondition(C_CS);
               ai.is_jmp:=true;
               list.concat(ai);
-
-              list.concat(taicpu.op_none(A_SET));
-
-              a_label(list,hl);
             end;
         end;
 
@@ -1893,15 +1880,14 @@ unit cgcpu;
         pd: tprocdef;
         paraloc1, paraloc2: tcgpara;
         ai: taicpu;
-        hl: TAsmLabel;
+        hl, no_overflow: TAsmLabel;
         name: String;
       begin
         ovloc.loc:=LOC_VOID;
         if size in [OS_8,OS_S8] then
           begin
             if (CPUAVR_HAS_MUL in cpu_capabilities[current_settings.cputype]) and
-               ((not check_overflow) or
-                (size=OS_8)) then
+               (op=OP_MUL) then
               begin
                 cg.a_reg_alloc(list,NR_R0);
                 cg.a_reg_alloc(list,NR_R1);
@@ -1912,16 +1898,16 @@ unit cgcpu;
                     current_asmdata.getjumplabel(hl);
                     list.concat(taicpu.op_reg_reg(A_AND,NR_R1,NR_R1));
 
+                     { Clear carry as it's not affected by any of the instructions }
+                    list.concat(taicpu.op_none(A_CLC));
+
                     ai:=Taicpu.Op_Sym(A_BRxx,hl);
                     ai.SetCondition(C_EQ);
                     ai.is_jmp:=true;
                     list.concat(ai);
 
                     list.concat(taicpu.op_reg(A_CLR,NR_R1));
-                    if op=OP_MUL then
-                      list.concat(taicpu.op_none(A_SEC))
-                    else
-                      list.concat(taicpu.op_none(A_SEV));
+                    list.concat(taicpu.op_none(A_SEC));
 
                     a_label(list,hl);
 
@@ -1934,6 +1920,41 @@ unit cgcpu;
                 list.concat(taicpu.op_reg_reg(A_MOV,dst,NR_R0));
                 cg.a_reg_dealloc(list,NR_R0);
               end
+            else if (CPUAVR_HAS_MUL in cpu_capabilities[current_settings.cputype]) and
+               (op=OP_IMUL) then
+              begin
+                cg.a_reg_alloc(list,NR_R0);
+                cg.a_reg_alloc(list,NR_R1);
+                list.concat(taicpu.op_reg_reg(A_MULS,src1,src2));
+                list.concat(taicpu.op_reg_reg(A_MOV,dst,NR_R0));
+
+                // Check overflow
+                if check_overflow then
+                  begin
+                    current_asmdata.getjumplabel(no_overflow);
+
+                    list.concat(taicpu.op_reg_const(A_SBRC,NR_R0,7));
+                    list.concat(taicpu.op_reg(A_INC,NR_R1));
+                    list.concat(taicpu.op_reg(A_TST,NR_R1));
+
+                    ai:=Taicpu.Op_Sym(A_BRxx,no_overflow);
+                    ai.SetCondition(C_EQ);
+                    ai.is_jmp:=true;
+                    list.concat(ai);
+
+                    list.concat(taicpu.op_reg(A_CLR,NR_R1));
+
+                    a_call_name(list,'FPC_OVERFLOW',false);
+
+                    a_label(list,no_overflow);
+
+                    ovloc.loc:=LOC_VOID;
+                  end
+                else
+                  list.concat(taicpu.op_reg(A_CLR,NR_R1));
+                cg.a_reg_dealloc(list,NR_R1);
+                cg.a_reg_dealloc(list,NR_R0);
+              end
             else
               begin
                 if size=OS_8 then
@@ -1970,52 +1991,66 @@ unit cgcpu;
                 (size=OS_16)) then
               begin
                 if check_overflow then
-                  list.concat(taicpu.op_none(A_CLT));
+                  begin
+                    current_asmdata.getjumplabel(hl);
+                    current_asmdata.getjumplabel(no_overflow);
+                  end;
                 cg.a_reg_alloc(list,NR_R0);
                 cg.a_reg_alloc(list,NR_R1);
                 list.concat(taicpu.op_reg_reg(A_MUL,src2,src1));
                 emit_mov(list,dst,NR_R0);
                 emit_mov(list,GetNextReg(dst),NR_R1);
                 list.concat(taicpu.op_reg_reg(A_MUL,GetNextReg(src1),src2));
-                perform_r1_check();
+                perform_r1_check(hl);
                 list.concat(taicpu.op_reg_reg(A_ADD,GetNextReg(dst),NR_R0));
-                perform_ovf_check();
+                perform_ovf_check(hl);
                 list.concat(taicpu.op_reg_reg(A_MUL,src1,GetNextReg(src2)));
-                perform_r1_check();
+                perform_r1_check(hl);
                 list.concat(taicpu.op_reg_reg(A_ADD,GetNextReg(dst),NR_R0));
-                perform_ovf_check();
+                perform_ovf_check(hl);
+
+                if check_overflow then
+                  begin
+                    list.concat(taicpu.op_reg_reg(A_MUL,GetNextReg(src1),GetNextReg(src2)));
+                    perform_r1_check(hl,NR_R0);
+                  end;
+
                 cg.a_reg_dealloc(list,NR_R0);
                 list.concat(taicpu.op_reg(A_CLR,NR_R1));
-                cg.a_reg_dealloc(list,NR_R1);
 
                 if check_overflow then
                   begin
                     {
-                      CLC
-                      CLV
-                      BRTC .L1
+                      CLV/CLC
+                      JMP no_overflow
+                    .hl:
+                      CLR R1
                       SEV/SEC
-                    .L1:
+                    .no_overflow:
                     }
-                    list.concat(taicpu.op_none(A_CLC));
-                    list.concat(taicpu.op_none(A_CLV));
 
-                    current_asmdata.getjumplabel(hl);
+                    if op=OP_MUL then
+                      list.concat(taicpu.op_none(A_CLC))
+                    else
+                      list.concat(taicpu.op_none(A_CLV));
 
-                    ai:=Taicpu.Op_Sym(A_BRxx,hl);
-                    ai.SetCondition(C_TC);
-                    ai.is_jmp:=true;
-                    list.concat(ai);
+                    a_jmp_always(list,no_overflow);
+
+                    a_label(list,hl);
+
+                    list.concat(taicpu.op_reg(A_CLR,NR_R1));
 
                     if op=OP_MUL then
                       list.concat(taicpu.op_none(A_SEC))
                     else
                       list.concat(taicpu.op_none(A_SEV));
 
-                    a_label(list,hl);
+                    a_label(list,no_overflow);
 
                     ovloc.loc:=LOC_FLAGS;
                   end;
+
+                cg.a_reg_dealloc(list,NR_R1);
               end
             else
               begin

+ 1 - 1
rtl/inc/generic.inc

@@ -1767,7 +1767,7 @@ end;
           ((q1>q3) or (q2>q3) or
           { the bit 31 can be only set if we have $8000 0000 }
           { and sign is true                                 }
-          (q3 shr 15<>0) and
+          (q3 shr 31<>0) and
            ((q3<>dword(dword(1) shl 31)) or not(sign))
           ) then
           FPC_Overflow();