From 1b698d319fd2f30ea9314b18063f9f64c1cf23c5 Mon Sep 17 00:00:00 2001 From: Jeppe Johansen Date: Tue, 30 Jul 2019 13:42:26 +0000 Subject: [PATCH] - Fix bug in software overflow checking for longint's. - AVR: Fix overflow checking for HW multiplications git-svn-id: trunk@42531 - --- compiler/avr/cgcpu.pas | 125 ++++++++++++++++++++++++++--------------- rtl/inc/generic.inc | 2 +- 2 files changed, 81 insertions(+), 46 deletions(-) diff --git a/compiler/avr/cgcpu.pas b/compiler/avr/cgcpu.pas index 9fe8e1a65f..4be4f4823e 100644 --- a/compiler/avr/cgcpu.pas +++ b/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 diff --git a/rtl/inc/generic.inc b/rtl/inc/generic.inc index 138c436fe1..53cec7753a 100644 --- a/rtl/inc/generic.inc +++ b/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();