From cb99b3778eb77e98ec1465711107147c8422bb48 Mon Sep 17 00:00:00 2001 From: Stephen Heumann Date: Sun, 31 Jan 2021 08:52:50 -0600 Subject: [PATCH 1/3] Flag that conversions may not set CPU flags usable for a subsequent comparison. There are several conversions that do not set the necessary flags, so they must be set separately before doing a comparison. Without this fix, comparisons of a value that was just converted might be mis-evaluated. This led to bugs where the wrong side of an "if" could be followed in some cases, as in the below examples: #include int g(void) {return 50;} signed char h(void) {return 50;} long lf(void) {return 50;} int main(void) { signed char sc = 50; if ((int)(signed char)g()) puts("OK1"); if ((int)h()) puts("OK2"); if ((int)sc) puts("OK3"); if ((int)lf()) puts("OK4"); } --- Gen.pas | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Gen.pas b/Gen.pas index 4d808ef..78a9457 100644 --- a/Gen.pas +++ b/Gen.pas @@ -405,7 +405,7 @@ NeedsCondition := opcode in [pc_and,pc_ior,pc_cui,pc_cup,pc_lor,pc_lnd,pc_ldl,pc_lil,pc_lld, pc_lli,pc_gil,pc_gli,pc_gdl,pc_gld,pc_iil,pc_ili,pc_idl,pc_ild, pc_cop,pc_cpo,pc_cpi,pc_dvi,pc_mpi,pc_adi,pc_sbi,pc_mod,pc_bno, - pc_udi,pc_uim,pc_umi]; + pc_udi,pc_uim,pc_umi,pc_cnv]; end; {NeedsCondition} From 130d3322844884e7a209b0ca29c9f0225b82f249 Mon Sep 17 00:00:00 2001 From: Stephen Heumann Date: Sun, 31 Jan 2021 11:40:07 -0600 Subject: [PATCH 2/3] Fix bugs with several operations on negative values of type signed char. The basic issue with all of these is that they failed to sign-extend the 8-bit signed char value to the full 16-bit A register. This could make certain operations on negative signed char values appear to yield positive values outside the range of signed char. The following example code demonstrates the problems: #include signed char f(void) {return -50;} int main(void) { long l = -123; int i = -99; signed char sc = -47; signed char *scp = ≻ printf("%i\n", (signed char)l); printf("%i\n", (signed char)i); printf("%i\n", f()); printf("%i\n", (*scp)++); printf("%i\n", *scp = -32); } --- Gen.pas | 59 ++++++++++++++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 54 insertions(+), 5 deletions(-) diff --git a/Gen.pas b/Gen.pas index 78a9457..2844285 100644 --- a/Gen.pas +++ b/Gen.pas @@ -1251,15 +1251,23 @@ else if op^.q in [ubyteToLong,ubyteToUlong,uwordToLong,uwordToUlong] then GenImplied(m_pha); end; {else} end {else if} -else if op^.q in [wordToByte,wordToUbyte,uwordToByte,uwordToUbyte] then +else if op^.q in [wordToUbyte,uwordToUbyte] then GenNative(m_and_imm, immediate, $00FF, nil, 0) +else if op^.q in [wordToByte,uwordToByte] then begin + lab1 := GenLabel; + GenNative(m_and_imm, immediate, $00FF, nil, 0); + GenNative(m_bit_imm, immediate, $0080, nil, 0); + GenNative(m_beq, relative, lab1, nil, 0); + GenNative(m_ora_imm, immediate, $FF00, nil, 0); + GenLab(lab1); + end {else if} else if op^.q in [byteToReal,uByteToReal,wordToReal] then GenCall(11) else if op^.q = uwordToReal then begin GenNative(m_ldx_imm, immediate, 0, nil, 0); GenCall(12); end {else if} -else if op^.q in [longToByte,longToUbyte,ulongToByte,ulongToUbyte] then begin +else if op^.q in [longToUbyte,ulongToUbyte] then begin if gLong.where = A_X then GenNative(m_and_imm, immediate, $00FF, nil, 0) else if gLong.where = constant then @@ -1270,6 +1278,22 @@ else if op^.q in [longToByte,longToUbyte,ulongToByte,ulongToUbyte] then begin GenNative(m_and_imm, immediate, $00FF, nil, 0); end; {else if} end {else if} +else if op^.q in [longToByte,ulongToByte] then begin + if gLong.where = A_X then + GenNative(m_and_imm, immediate, $00FF, nil, 0) + else if gLong.where = constant then + GenNative(m_lda_imm, immediate, long(gLong.lval).lsw & $00FF, nil, 0) + else {if gLong.where = onStack then} begin + GenImplied(m_pla); + GenImplied(m_plx); + GenNative(m_and_imm, immediate, $00FF, nil, 0); + end; {else if} + lab1 := GenLabel; + GenNative(m_bit_imm, immediate, $0080, nil, 0); + GenNative(m_beq, relative, lab1, nil, 0); + GenNative(m_ora_imm, immediate, $FF00, nil, 0); + GenLab(lab1); + end {else if} else if op^.q in [longToWord,longToUword,ulongToWord,ulongToUword] then begin {Note: if the result is in A_X, no further action is needed} if gLong.where = constant then @@ -1983,8 +2007,16 @@ case op^.optype of GenNative(m_rep, immediate, 32, nil, 0); end; {else} if not skipLoad then - if short then + if short then begin GenNative(m_and_imm, immediate, $00FF, nil, 0); + if op^.optype = cgByte then begin + GenNative(m_bit_imm, immediate, $0080, nil, 0); + lab1 := GenLabel; + GenNative(m_beq, relative, lab1, nil, 0); + GenNative(m_ora_imm, immediate, $FF00, nil, 0); + GenLab(lab1); + end; {if} + end; {if} end; {case cgByte,cgUByte,cgWord,cgUWord} otherwise: @@ -3225,6 +3257,7 @@ var simple: boolean; {is the load a simple load?} lLong: longType; {address record for left node} zero: boolean; {is the operand a constant zero?} + lab1: integer; {label} procedure LoadLSW; @@ -3538,8 +3571,16 @@ case optype of end; {else} if short then begin GenNative(m_rep, immediate, 32, nil, 0); - if opcode = pc_cpi then + if opcode = pc_cpi then begin GenNative(m_and_imm, immediate, $00FF, nil, 0); + if optype = cgByte then begin + GenNative(m_bit_imm, immediate, $0080, nil, 0); + lab1 := GenLabel; + GenNative(m_beq, relative, lab1, nil, 0); + GenNative(m_ora_imm, immediate, $FF00, nil, 0); + GenLab(lab1); + end; {if} + end; {if} end; {if} end; {case cgByte,cgUByte,cgWord,cgUWord} @@ -5124,6 +5165,7 @@ procedure GenTree {op: icptr}; var size: integer; {localSize + parameterSize} + lab1: integer; {label} begin {GenRet} {pop the name record} @@ -5172,7 +5214,14 @@ procedure GenTree {op: icptr}; cgByte,cgUByte: begin GenNative(m_lda_dir, direct, funLoc, nil, 0); - GenNative(m_and_imm, immediate, $00FF, nil, 0); + GenNative(m_and_imm, immediate, $00FF, nil, 0); + if op^.optype = cgByte then begin + GenNative(m_bit_imm, immediate, $0080, nil, 0); + lab1 := GenLabel; + GenNative(m_beq, relative, lab1, nil, 0); + GenNative(m_ora_imm, immediate, $FF00, nil, 0); + GenLab(lab1); + end; {if} if size <> 2 then GenImplied(m_tay); end; From 393fb8d6351805ddc01af259d0fdc929110b1835 Mon Sep 17 00:00:00 2001 From: Stephen Heumann Date: Sun, 31 Jan 2021 12:00:31 -0600 Subject: [PATCH 3/3] Make floating point to character type conversions yield values within the type's range. This affects cases where the floating value, truncated to an integer, is outside the range of the destination type. Previously, the result value might appear to be an int value outside the range of the character type. These situations are undefined behavior under the C standards, so this was not technically a bug, but the new behavior is less surprising. (Note that it still may not raise the "invalid" floating-point exception in some cases where Annex F would call for that.) --- Gen.pas | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/Gen.pas b/Gen.pas index 2844285..88e1c68 100644 --- a/Gen.pas +++ b/Gen.pas @@ -1317,10 +1317,20 @@ else if op^.q in [longToReal,uLongToReal] then begin else GenCall(13); end {else} -else if op^.q in [realToByte,realToUbyte,realToWord] then begin +else if op^.q =realToWord then + GenCall(14) +else if op^.q = realToUbyte then begin GenCall(14); - if (op^.q & $00FF) in [0,1] then - GenNative(m_and_imm, immediate, $00FF, nil, 0); + GenNative(m_and_imm, immediate, $00FF, nil, 0); + end {else if} +else if op^.q = realToByte then begin + lab1 := GenLabel; + GenCall(14); + GenNative(m_and_imm, immediate, $00FF, nil, 0); + GenNative(m_bit_imm, immediate, $0080, nil, 0); + GenNative(m_beq, relative, lab1, nil, 0); + GenNative(m_ora_imm, immediate, $FF00, nil, 0); + GenLab(lab1); end {else if} else if op^.q = realToUword then GenCall(15)