diff --git a/lang/cem/cemcom.ansi/ch3mon.c b/lang/cem/cemcom.ansi/ch3mon.c index 87969c6a6..e502599dd 100644 --- a/lang/cem/cemcom.ansi/ch3mon.c +++ b/lang/cem/cemcom.ansi/ch3mon.c @@ -127,11 +127,10 @@ void ch3mon(int oper, struct expr** expp) { writh o1 = (*expp)->VL_VALUE; - (*expp)->VL_VALUE = (oper == '-') - ? -o1 - : ((*expp)->ex_type->tp_unsigned - ? (~o1) & full_mask[(int)(*expp)->ex_type->tp_size] - : ~o1); + o1 = (oper == '-') ? -o1 : ~o1; + if ((*expp)->ex_type->tp_unsigned) + o1 &= full_mask[(int)(*expp)->ex_type->tp_size]; + (*expp)->VL_VALUE = o1; } else if (is_fp_cst(*expp)) switch_sign_fp(*expp); diff --git a/mach/m68020/ncg/table b/mach/m68020/ncg/table index 311b05b62..27ff792b7 100644 --- a/mach/m68020/ncg/table +++ b/mach/m68020/ncg/table @@ -1210,7 +1210,8 @@ from memory2 from memory1 uses DD_REG = {zero_const, 0} - gen move_b %1, %a yields %a + gen move_b %1, %a + killcc. yields %a from memory2 uses DD_REG @@ -6400,18 +6401,20 @@ pat lil loc sru sil $1==$4 && $2==1 && $3==4 call rlil1shsil("lsr #1,") proc txxand with test_set_int DD_REG - gen test %1 + gen and_i {const,1}, %2 + test %1 bxx[1] {slabel, 1f} - bclr {const,0}, %2 + clr_i %2 1: yields %2 #if WORD_SIZE==2 with test_set1 DD_REG #else with test_set1 + test_set2 DD_REG #endif - gen test %1 + gen and_i {const,1}, %2 + test %1 bxx[2] {slabel, 1f} - bclr {const,0}, %2 + clr_i %2 1: yields %2 proc txxior @@ -6432,19 +6435,21 @@ with test_set1 + test_set2 DD_REG proc txxand_ouch with test_set_int DD_REG - gen killcc. + gen and_i {const,1}, %2 + killcc. test %1 bxx[1] {slabel, 1f} - bclr {const,0}, %2 + clr_i %2 1: yields %2 #if WORD_SIZE==2 with test_set1 DD_REG #else with test_set1 + test_set2 DD_REG #endif - gen test %1 + gen and_i {const,1}, %2 + test %1 bxx[2] {slabel, 1f} - bclr {const,0}, %2 + clr_i %2 1: yields %2 proc txxior_ouch @@ -6480,46 +6485,54 @@ pat tgt ior $2==WORD_SIZE call txxior_ouch("ble", "bls") proc cmxtxxand with exact extend1 extend1 DD_REG - gen cmp_b %2, %1 + gen and_i {const,1}, %3 + cmp_b %2, %1 bxx[2] {llabel,1f} - bclr {const,0}, %3 + clr_i %3 1: yields %3 with exact extend2 extend2 DD_REG - gen cmp_w %2, %1 + gen and_i {const,1}, %3 + cmp_w %2, %1 bxx[2] {llabel,1f} - bclr {const,0}, %3 + clr_i %3 1: yields %3 with exact sconsts any_int DD_REG uses DD_REG=%1 - gen cmp_i %2, %a + gen and_i {const,1}, %3 + cmp_i %2, %a bxx[2] {slabel, 1f} - bclr {const,0}, %3 + clr_i %3 1: yields %3 with exact any_int sconsts DD_REG uses DD_REG=%2 - gen cmp_i %1, %a + gen and_i {const,1}, %3 + cmp_i %1, %a bxx[1] {slabel, 1f} - bclr {const,0}, %3 + clr_i %3 1: yields %3 with any_int-sconsts genreg DD_REG - gen cmp_i %1, %2 + gen and_i {const,1}, %3 + cmp_i %1, %2 bxx[1] {slabel, 1f} - bclr {const,0}, %3 + clr_i %3 1: yields %3 with genreg any_int-sconsts DD_REG - gen cmp_i %2, %1 + gen and_i {const,1}, %3 + cmp_i %2, %1 bxx[2] {slabel, 1f} - bclr {const,0}, %3 + clr_i %3 1: yields %3 with exact immediate_int-sconsts imm_cmp_int DD_REG - gen cmp_i %1, %2 + gen and_i {const,1}, %3 + cmp_i %1, %2 bxx[1] {slabel, 1f} - bclr {const,0}, %3 + clr_i %3 1: yields %3 with exact imm_cmp_int immediate_int-sconsts DD_REG - gen cmp_i %2, %1 + gen and_i {const,1}, %3 + cmp_i %2, %1 bxx[2] {slabel, 1f} - bclr {const,0}, %3 + clr_i %3 1: yields %3 proc cmxtxxior diff --git a/tests/plat/build.py b/tests/plat/build.py index 30bdb962b..5344a96c0 100644 --- a/tests/plat/build.py +++ b/tests/plat/build.py @@ -16,9 +16,11 @@ "core": [ "tests/plat/core/aar,e,.e", "tests/plat/core/and,e,.e", + "tests/plat/core/andbool,e,.c", "tests/plat/core/andv,e,.e", "tests/plat/core/brk,c,.c", "tests/plat/core/bss,e,.c", + "tests/plat/core/bytediv,e,.c", "tests/plat/core/calloc,c,.c", "tests/plat/core/cii,e,.e", "tests/plat/core/cmi,e,.e", @@ -29,6 +31,8 @@ "tests/plat/core/_dummy,e,.c", "tests/plat/core/dup,e,.e", "tests/plat/core/exg,e,.e", + "tests/plat/core/foldcii,e,-O3,.c", + "tests/plat/core/foldoverflow,e,-O3,.c", "tests/plat/core/inn,e,.e", "tests/plat/core/intadd,e,.c", "tests/plat/core/intcmp,e,.c", @@ -39,6 +43,8 @@ "tests/plat/core/ior,e,.e", "tests/plat/core/iorv,e,.e", "tests/plat/core/lar,e,.e", + "tests/plat/core/mulminus1,e,.c", + "tests/plat/core/negunsigned,e,.c", "tests/plat/core/newdispose,p,.p", "tests/plat/core/pascalsets,p,.p", "tests/plat/core/rck,e,.e", diff --git a/tests/plat/core/andbool,e,.c b/tests/plat/core/andbool,e,.c new file mode 100644 index 000000000..35a17b81c --- /dev/null +++ b/tests/plat/core/andbool,e,.c @@ -0,0 +1,65 @@ +#include "test.h" + +/* x & (a op b) is x & 0 or x & 1, not "x with bit 0 cleared if false". */ + +int16_t one = 1; +int16_t two = 2; +int8_t g = 0x40; +int32_t sh = 0; +int ione = 1, itwo = 2, ish = 0; +long lone = 1, ltwo = 2, lsh = 0; + +static int16_t f(void) +{ + return (int16_t)((int32_t)-8017 >> ((uint8_t)sh & 31)) + & (int16_t)((int32_t)-1L && (int16_t)g); +} + +static int16_t h(int16_t x) +{ + return (int16_t)((int32_t)x >> ((uint8_t)sh & 31)) & (int16_t)(one < two); +} + +static int16_t k(int16_t x) +{ + return (int16_t)((int32_t)x >> ((uint8_t)sh & 31)) & (int16_t)(one == two); +} + +/* The same with int and long operands, for every word size. */ + +static int ih(int x) +{ + return (x >> ish) & (ione < itwo); +} + +static int ik(int x) +{ + return (x >> ish) & (ione == itwo); +} + +static int ic(int x, int a, int b) +{ + return (x >> ish) & (a < b); +} + +static long lh(long x) +{ + return (x >> lsh) & (lone < ltwo); +} + +/* Bypasses the CRT, so there's no stdio. */ +void _m_a_i_n(void) +{ + ASSERT(f() == 1); + ASSERT(h(-8017) == 1); + ASSERT(h(-8018) == 0); + ASSERT(k(-8017) == 0); + ASSERT(ih(-8017) == 1); + ASSERT(ih(-8018) == 0); + ASSERT(ik(-8017) == 0); + ASSERT(ic(-8017, 1, 2) == 1); + ASSERT(ic(-8017, 2, 1) == 0); + ASSERT(lh(-8017L) == 1); + + finished(); +} diff --git a/tests/plat/core/bytediv,e,.c b/tests/plat/core/bytediv,e,.c new file mode 100644 index 000000000..e4730711e --- /dev/null +++ b/tests/plat/core/bytediv,e,.c @@ -0,0 +1,23 @@ +#include "test.h" + +/* A byte moved into a cleared register sets the condition codes for the + * byte, not the register: dividing by a power of two must not take the + * byte's sign as the register's. */ + +int16_t l = -300; +int8_t s = -100; + +/* Bypasses the CRT, so there's no stdio. */ +void _m_a_i_n(void) +{ + uint8_t u = (uint8_t)l; + + ASSERT((uint8_t)l == 212); + ASSERT((uint8_t)l / 16 == 13); + ASSERT(u / 16 == 13); + ASSERT(u / 4 == 53); + ASSERT((uint8_t)s / 2 == 78); + ASSERT(s / 2 == -50); + + finished(); +} diff --git a/tests/plat/core/foldcii,e,-O3,.c b/tests/plat/core/foldcii,e,-O3,.c new file mode 100644 index 000000000..3c9c93b1e --- /dev/null +++ b/tests/plat/core/foldcii,e,-O3,.c @@ -0,0 +1,79 @@ +#include "test.h" + +/* Narrowing conversions of constants that ego propagates: (int8_t)16384 + * is 0. */ + +int16_t a = 1, b = 2; +int16_t sh = 0; +int16_t fe = 29988; +int32_t fb = -1021131558L; +int8_t arr[8]; + +static void f(void) +{ + uint16_t l = 16384; + + arr[((uint8_t)((int32_t)((uint8_t)((uint16_t)((uint8_t)l) << (sh & 7))) + | (int32_t)(((int8_t)l) ? ((uint8_t)fe) : ((uint8_t)fb)))) & 7] = 1; +} + +static int16_t g(void) +{ + uint16_t l = 16384; + + return (int8_t)l ? a : b; +} + +static int32_t h(void) +{ + uint16_t l = 45219; + + return (int32_t)(int16_t)l; +} + +/* The same with int, for every word size. */ + +static int fi(void) +{ + int l = 16384; + + return (int8_t)l ? a : b; +} + +static int ki(void) +{ + int l = 384; + + return (int8_t)l + 0; +} + +static long hi(void) +{ + int l = 384; + + return (long)(int8_t)l; +} + +static void si(void) +{ + int l = 16384; + + arr[(int8_t)l ? 4 : 2] = 2; +} + +/* Bypasses the CRT, so there's no stdio. */ +void _m_a_i_n(void) +{ + f(); + ASSERT(arr[2] == 1); + ASSERT(arr[4] == 0); + ASSERT(g() == 2); + ASSERT(h() == 45219L - 65536L); + ASSERT(fi() == 2); + ASSERT(ki() == -128); + ASSERT(hi() == -128L); + si(); + ASSERT(arr[2] == 2); + + finished(); +} diff --git a/tests/plat/core/foldoverflow,e,-O3,.c b/tests/plat/core/foldoverflow,e,-O3,.c new file mode 100644 index 000000000..77d81a9ef --- /dev/null +++ b/tests/plat/core/foldoverflow,e,-O3,.c @@ -0,0 +1,36 @@ +#include "test.h" + +/* Unsigned arithmetic on constants that ego propagates into one + * instruction wraps around in the word instead of growing. */ + +uint16_t r16 = 0; + +/* Bypasses the CRT, so there's no stdio. */ +void _m_a_i_n(void) +{ + unsigned int m = (unsigned int)-1; + unsigned int three = 3; + unsigned int two = 2; + uint16_t a = 12933; + uint16_t b = 20802; + uint32_t big = 0x10000UL; + unsigned int ua = 12933; + unsigned int ub = 20802; + + ASSERT(m * three == (unsigned int)-3); + ASSERT(m + two == 1); + ASSERT(three - m == 4); + ASSERT((m << three) == (unsigned int)-8); + ASSERT((uint16_t)(a * b) == 6986); + r16 = 100 / (uint16_t)(a * b); + ASSERT(r16 == 0); + ASSERT(big * big == 0); + ASSERT((big << 16) == 0); + /* Shifting the result of a fold must not see bits beyond the word. */ + ASSERT((uint16_t)((uint16_t)(ua * ub) >> 8) == 27); + ASSERT((uint32_t)(big * big) >> 16 == 0); + ASSERT((uint32_t)(big << 16) >> 8 == 0); + ASSERT((m * three) >> 1 == (unsigned int)-3 >> 1); + + finished(); +} diff --git a/tests/plat/core/mulminus1,e,.c b/tests/plat/core/mulminus1,e,.c new file mode 100644 index 000000000..467a9f3ed --- /dev/null +++ b/tests/plat/core/mulminus1,e,.c @@ -0,0 +1,16 @@ +#include "test.h" + +/* Multiplication by a constant with all bits set is not a shift. */ + +uint32_t x = 3; +uint16_t y = 3; + +/* Bypasses the CRT, so there's no stdio. */ +void _m_a_i_n(void) +{ + ASSERT((uint32_t)(x * 0xFFFFFFFFUL) == 0xFFFFFFFDUL); + ASSERT((uint32_t)(x * 0x80000000UL) == 0x80000000UL); + ASSERT((uint16_t)(y * 0xFFFFU) == 0xFFFDU); + + finished(); +} diff --git a/tests/plat/core/negunsigned,e,.c b/tests/plat/core/negunsigned,e,.c new file mode 100644 index 000000000..ebfde3d9b --- /dev/null +++ b/tests/plat/core/negunsigned,e,.c @@ -0,0 +1,16 @@ +#include "test.h" + +/* Unary - and ~ of an unsigned constant are folded modulo the type's + * size, also when the compiler's own arithmetic is wider. */ + +/* Bypasses the CRT, so there's no stdio. */ +void _m_a_i_n(void) +{ + ASSERT(-(uint32_t)1371337135UL / 193754694UL == 15); + ASSERT(-(uint32_t)1 == 0xFFFFFFFFUL); + ASSERT((-(uint32_t)1 >> 31) == 1); + ASSERT(~(uint32_t)0 / 0x10000UL == 0xFFFFUL); + ASSERT(-(unsigned int)1 / 2 == (unsigned int)-1 / 2); + + finished(); +} diff --git a/util/opt/patterns b/util/opt/patterns index 58f5204f9..07dfca7d2 100644 --- a/util/opt/patterns +++ b/util/opt/patterns @@ -220,10 +220,10 @@ ldc mli $1==1 && $2==2*w: loc mlu $1==1 && $2==w: ldc mlu $1==1 && $2==2*w: loc sbi $1==1 && $2==w: dec -loc loc sli $3==w: loc ($1 << $2) -loc loc slu $3==w: loc ($1 << $2) -ldc loc sli $3==2*w: ldc ($1 << $2) -ldc loc slu $3==2*w: ldc ($1 << $2) +loc loc sli $3==w && (sfit($1<<$2,8*w) || ufit($1<<$2,8*w)): loc ($1 << $2) +loc loc slu $3==w && (sfit($1<<$2,8*w) || ufit($1<<$2,8*w)): loc ($1 << $2) +ldc loc sli $3==2*w && (sfit($1<<$2,16*w) || ufit($1<<$2,16*w)): ldc ($1 << $2) +ldc loc slu $3==2*w && (sfit($1<<$2,16*w) || ufit($1<<$2,16*w)): ldc ($1 << $2) loc loc sri $3==w: loc ($1 >> $2) loc loc sru $1 >= 0 && $3==w: loc ($1 >> $2) ldc loc sri $3==2*w: ldc ($1 >> $2) @@ -558,12 +558,12 @@ dup SLP sti $1==p && $3==w: SLP $2 sil $2 loc cms $1==0 && $2==w: tne zer $1==w: loc 0 loc loc adi $3==w && sfit($1+$2,8*w) : loc $1+$2 -loc loc adu $3==w : loc $1+$2 +loc loc adu $3==w && (sfit($1+$2,8*w) || ufit($1+$2,8*w)) : loc $1+$2 loc loc sbi $3==w && sfit($1-$2,8*w) : loc $1-$2 -loc loc sbu $3==w : loc $1-$2 +loc loc sbu $3==w && (sfit($1-$2,8*w) || ufit($1-$2,8*w)) : loc $1-$2 loc loc sbs $3==w && w==p && sfit($1-$2,8*w) : loc $1-$2 loc loc mli $3==w && sfit($1*$2,8*w) : loc $1*$2 -loc loc mlu $3==w : loc $1*$2 +loc loc mlu $3==w && (sfit($1*$2,8*w) || ufit($1*$2,8*w)) : loc $1*$2 loc loc dvi $3==w && $2!=0 : loc $1/$2 loc loc and $3==w : loc $1&$2 loc loc ior $3==w : loc $1|$2 @@ -620,9 +620,9 @@ lal loi lal sti $2==$4 && $2>8 && ( $3<=$1-$2 || $3>=$1+$2 ) : lae loi lae sti $2==$4 && $2>8 && ( !defined($1==$3) || $3<=$1-$2 || $3>=$1+$2 ) : lae $1 lae $3 blm $2 loc loc loc cif $1==0 && $2==w : zrf $3 -loc loc loc ciu $1>=0 && $2==w && $3==2*w : ldc $1 -loc loc loc cii $2==w && $3==2*w : ldc $1 -loc loc loc cii $2=0 && sfit($1,8*w) && $2==w && $3==2*w : ldc $1 +loc loc loc cii $2==w && $3==2*w && sfit($1,8*w) : ldc $1 +loc loc loc cii $2=0 && $2<$1*8 : lof ($2/(8*w))*w loc $2&(8*w-1) inn w ldl loc inn $3==2*w && $2>=0 && $2<16*w : diff --git a/util/opt/peephole.c b/util/opt/peephole.c index 9cbef0ade..10c31283a 100644 --- a/util/opt/peephole.c +++ b/util/opt/peephole.c @@ -814,6 +814,10 @@ static int repl_mul(line_p lp, line_p *b, line_p *e) break; } + /* Only the sz bytes of the operand count: n is wider on 64-bit hosts. */ + if (sz < (int) sizeof(n)) + n &= (1UL << (8 * sz)) - 1; + #define newinstr(res, opcode, val) (*(res) = newline((short)(val)+Z_OPMINI), (*(res))->l_instr = (opcode)) while (n)