From fb9f5387b54507108f48f2617b4496e6f018e940 Mon Sep 17 00:00:00 2001 From: George Koehler Date: Sat, 7 Sep 2019 16:20:33 -0400 Subject: [PATCH] Add long long comparisons, shifts for linux386. Add tests for comparisons and shifts. Also add enough integer conversions to compile the shift test (llshift_e.c), and disable some wrong rules for ldc and conversions. --- mach/i386/ncg/table | 162 ++++++++++++++++++++++++++++++- tests/plat/build.lua | 1 + tests/plat/long-long/llcmp_e.c | 124 +++++++++++++++++++++++ tests/plat/long-long/llshift_e.c | 75 ++++++++++++++ 4 files changed, 361 insertions(+), 1 deletion(-) create mode 100644 tests/plat/long-long/llcmp_e.c create mode 100644 tests/plat/long-long/llshift_e.c diff --git a/mach/i386/ncg/table b/mach/i386/ncg/table index 42a39d15b..10fd02809 100644 --- a/mach/i386/ncg/table +++ b/mach/i386/ncg/table @@ -234,8 +234,12 @@ jmp label cost(1,4). proccall "call" label+rm cost(1,8). jxx "syntax error" label cost(1,4). setxx "syntax error" REG1:rw cost(2,4). +seta REG1:rw cost(2,4). +setb REG1:rw cost(2,4). +setl REG1:rw cost(2,4). setle REG1:rw cost(2,4). setg REG1:rw cost(2,4). +setne REG1:rw cost(2,4). lea anyreg:rw, halfindir:ro. lea LOCAL:rw, halfindir:ro. /* only for register variables, UNSAFE!!! */ leave cost(1,4). @@ -255,12 +259,14 @@ movzxb anyreg:wo, REG+rm1:ro. movzx anyreg:wo, REG+rm2:ro. mul rmorconst:ro kills :cc eax edx cost(2,41). neg rmorconst:rw:cc. +negb rm1:rw:cc. not rmorconst:rw. #ifdef REGVARS or LOCAL:rw:cc, rmorconst:ro. /* only for register variables; UNSAFE !!! */ #endif or rm:rw:cc, regorconst:ro. or anyreg:rw:cc, rmorconst:ro. +orb REG1:rw, REG1:ro. pop anyreg:wo cost(1,4). pop rm:wo. push anyreg:ro cost(1,2). @@ -276,7 +282,9 @@ sar rm:rw, ANYCON+SHIFT_CREG:ro kills :cc. sbb rm:rw:cc, regorconst:ro. sbb anyreg:rw:cc, rmorconst:ro. shl rm:rw, ANYCON+SHIFT_CREG:ro kills :cc. +shld rm:rw, anyreg:ro, ANYCON+SHIFT_CREG:ro kills :cc cost(2,3). shr rm:rw, ANYCON+SHIFT_CREG:ro kills :cc. +shrd rm:rw, anyreg:ro, ANYCON+SHIFT_CREG:ro kills :cc cost(2,3). #ifdef REGVARS sub LOCAL:rw:cc, rmorconst:ro. /* only for register variables; UNSAFE !!! */ #endif @@ -506,7 +514,10 @@ PATTERNS pat loc yields {ANYCON,$1} +#if 0 +/* wrong because .Xtrp assumes trap < 16 */ pat ldc leaving loc 18 trp +#endif pat lol yields {LOCAL,$1,4} @@ -1076,6 +1087,27 @@ with ANYCON REG with SHIFT_CREG REG gen sal %2,cl yields %2 +pat sli $1==8 +with SHIFT_CREG REG REG + gen testb cl,{ANYCON,32} + jne {label,1f} + shld %3,%2,cl + sal %2,cl + jmp {label,2f} + 1: + mov %3,%2 + sal %3,cl + xor %2,%2 + 2: yields %3 %2 + +pat loc sli ($1&32)==0 && $2==8 +with REG REG + gen shld %2,%1,{ANYCON,$1&31} + sal %1,{ANYCON,$1&31} yields %2 %1 +pat loc sli ($1&32)!=0 && $2==8 +with REG REG + gen sal %1,{ANYCON,$1&31} yields %1 {ANYCON,0} + /* pat sli !defined($1) with ACC @@ -1089,6 +1121,29 @@ with SHIFT_CREG REG with ANYCON REG gen sar %2,%1 yields %2 +pat sri $1==8 +with SHIFT_CREG REG REG + gen testb cl,{ANYCON,32} + jne {label,1f} + shrd %2,%3,cl + sar %3,cl + jmp {label,2f} + 1: + mov %2,%3 + sar %2,cl + sar %3,{ANYCON,31} + 2: yields %3 %2 + +pat loc sri ($1&32)==0 && $2==8 +with REG REG + gen shrd %1,%2,{ANYCON,$1&31} + sar %2,{ANYCON,$1&31} yields %2 %1 +pat loc sri ($1&32)!=0 && $2==8 +with REG REG + gen mov %1,%2 + sar %1,{ANYCON,$1&31} + sar %2,{ANYCON,31} yields %2 %1 + /* pat sri !defined($1) with ACC @@ -1181,6 +1236,27 @@ gen shr %2,cl yields %2 with ANYCON REG gen shr %2,%1 yields %2 +pat sru $1==8 +with SHIFT_CREG REG REG + gen testb cl,{ANYCON,32} + jne {label,1f} + shrd %2,%3,cl + shr %3,cl + jmp {label,2f} + 1: + mov %2,%3 + shr %2,cl + xor %3,%3 + 2: yields %3 %2 + +pat loc sru ($1&32)==0 && $2==8 +with REG REG + gen shrd %2,%1,{ANYCON,$1&31} + shr %1,{ANYCON,$1&31} yields %2 %1 +pat loc sru ($1&32)!=0 && $2==8 +with REG REG + gen shr %2,{ANYCON,$1&31} yields {ANYCON,0} %2 + /* pat sru !defined($1) with ACC STACK @@ -2085,10 +2161,13 @@ with CXREG DXREG ACC kills ALL gen proccall {label,".cii"} yields %3 +#if 0 +/* wrong when integer size > 4 */ pat ciu leaving cuu pat cui leaving cuu pat cuu +#endif pat loc loc cii zeq $1==1 with GENREG STACK @@ -2123,10 +2202,25 @@ with exact rm2 uses reusing %1,GENREG gen movsx %a,%1 yields %a +pat loc loc cii $1==4 && $2==8 +with ACC + gen cdq. yields edx eax + +pat loc loc cii $1<4 && $2==8 leaving loc $1 loc 4 cii loc 4 loc $2 cii + +pat loc loc cii $1==8 && $2<=4 +with a_word a_word yields %1 + pat loc loc ciu leaving loc $1 loc $2 cuu pat loc loc cui leaving loc $1 loc $2 cuu -pat loc loc cuu $1==$2 +pat loc loc cuu $1==$2 || ($1<=4 && $2<=4) + +pat loc loc cuu $1<=4 && $2==8 +with a_word yields {ANYCON,0} %1 + +pat loc loc cuu $1==8 && $2<=4 +with a_word a_word yields %1 pat loc loc cif $1==4 && $2==4 leaving loc 4 cal ".cif4" asp 4 pat loc loc cif $1==4 && $2==8 leaving loc 4 cal ".cif8" @@ -2432,8 +2526,31 @@ with rmorconst register dec %a 2: yields %a +pat cmi $1==8 +with rmorconst rmorconst GENREG GENREG + /* Let dx = 0x100 or 0x101 if a < b, 0 if a == b, 1 if a > b. + Shift left so 0x100 becomes the sign bit of edx. */ + /* can't use 5th REG */ + gen sub %3,%1 + setne %3.1 + sbb %4,%2 + setl %4.2 + setg %4.1 + orb %4.1,%3.1 + shl %4,{ANYCON,23} yields %4 + pat cmu $1==4 leaving cmp +pat cmu $1==8 +with rmorconst rmorconst GENREG GENREG + gen sub %3,%1 + setne %3.1 + sbb %4,%2 + setb %4.2 + seta %4.1 + orb %4.1,%3.1 + shl %4,{ANYCON,23} yields %4 + pat cms $1==4 with REG rmorconst gen sub %1,%2 yields %1 @@ -2594,6 +2711,49 @@ pat cmp zgt call cmxzxx("ja","jb") pat cms zeq $1==4 call cmxzxx("je","je") pat cms zne $1==4 call cmxzxx("jne","jne") +proc cmx8txxn example cmi tgt +with GENREG REG rmorconst rmorconst + /* can't use 5th REG */ + gen sub %1,%3 + sbb %2,%4 + setxx* %2.1 + movzxb %2,%2.1 yields %2 +proc cmx8txxy example cmi tlt +with rmorconst rmorconst GENREG REG + gen sub %3,%1 + sbb %4,%2 + setxx* %4.1 + movzxb %4,%4.1 yields %4 + +pat cmi tlt $1==8 call cmx8txxy("setl") +pat cmi tle $1==8 call cmx8txxn("setge") +pat cmi tge $1==8 call cmx8txxy("setge") +pat cmi tgt $1==8 call cmx8txxn("setl") +pat cmu tlt $1==8 call cmx8txxy("setb") +pat cmu tle $1==8 call cmx8txxn("setae") +pat cmu tge $1==8 call cmx8txxy("setae") +pat cmu tgt $1==8 call cmx8txxn("setb") + +proc cmx8zxxn example cmi zgt +with REG REG rmorconst rmorconst STACK + gen sub %1,%3 + sbb %2,%4 + jxx* {label,$2} +proc cmx8zxxy example cmi zlt +with rmorconst rmorconst REG REG STACK + gen sub %3,%1 + sbb %4,%2 + jxx* {label,$2} + +pat cmi zlt $1==8 call cmx8zxxy("jl") +pat cmi zle $1==8 call cmx8zxxn("jge") +pat cmi zge $1==8 call cmx8zxxy("jge") +pat cmi zgt $1==8 call cmx8zxxn("jl") +pat cmu zlt $1==8 call cmx8zxxy("jb") +pat cmu zle $1==8 call cmx8zxxn("jae") +pat cmu zge $1==8 call cmx8zxxy("jae") +pat cmu zgt $1==8 call cmx8zxxn("jb") + pat cms zne $1==8 with regorconst regorconst rm rm STACK gen cmp %3,%1 diff --git a/tests/plat/build.lua b/tests/plat/build.lua index 72fd6afad..7adac3134 100644 --- a/tests/plat/build.lua +++ b/tests/plat/build.lua @@ -4,6 +4,7 @@ definerule("plat_testsuite", { plat = { type="string" }, method = { type="string" }, + -- added long-long/llshift_e.c sets = { type="table", default={"core", "b", "bugs", "m2", "floats", "long-long"}}, skipsets = { type="table", default={}}, tests = { type="targets", default={} }, diff --git a/tests/plat/long-long/llcmp_e.c b/tests/plat/long-long/llcmp_e.c new file mode 100644 index 000000000..8edcf727d --- /dev/null +++ b/tests/plat/long-long/llcmp_e.c @@ -0,0 +1,124 @@ +#include "test.h" + +struct s_cmp { + long long a; + long long b; + int a_cmp_b; /* -1 if a < b, 0 if a == b, 1 if a > b */ +} s_cases[] = { + {-1LL, -1LL, 0}, + {-1LL, 0LL, -1}, + {-1LL, 1LL, -1}, + { 0LL, -1LL, 1}, + { 0LL, 0LL, 0}, + { 0LL, 1LL, -1}, + { 1LL, -1LL, 1}, + { 1LL, 0LL, 1}, + { 1LL, 1LL, 0}, +}; + +struct u_cmp { + unsigned long long a; + unsigned long long b; + int a_cmp_b; +} u_cases[] = { + { 0ULL, 0ULL, 0}, + { 0ULL, 1ULL, -1}, + { 1ULL, 0ULL, 1}, + { 1ULL, 1ULL, 0}, +}; + +#define LEN(ary) (sizeof(ary) / sizeof(ary[0])) + +/* Compiler should not optimize !t[a < b] as a > b. */ +int t[] = {0, 1}; + +void _m_a_i_n(void) { + int i; +#define A c->a +#define B c->b + + for (i = 0; i < LEN(s_cases); i++) { + struct s_cmp *c = &s_cases[i]; + switch (c->a_cmp_b) { + case -1: + ASSERT(A < B); + ASSERT(A <= B); + ASSERT(A != B); + ASSERT(t[A < B]); + ASSERT(t[A <= B]); + ASSERT(!t[A == B]); + ASSERT(t[A != B]); + ASSERT(!t[A >= B]); + ASSERT(!t[A > B]); + break; + case 0: + ASSERT(A <= B); + ASSERT(A == B); + ASSERT(A >= B); + ASSERT(!t[A < B]); + ASSERT(t[A <= B]); + ASSERT(t[A == B]); + ASSERT(!t[A != B]); + ASSERT(t[A >= B]); + ASSERT(!t[A > B]); + break; + case 1: + ASSERT(A != B); + ASSERT(A >= B); + ASSERT(A > B); + ASSERT(!t[A < B]); + ASSERT(!t[A <= B]); + ASSERT(!t[A == B]); + ASSERT(t[A != B]); + ASSERT(t[A >= B]); + ASSERT(t[A > B]); + break; + default: + ASSERT(0); + break; + } + } + for (i = 0; i < LEN(u_cases); i++) { + struct u_cmp *c = &u_cases[i]; + switch (c->a_cmp_b) { + case -1: + ASSERT(A < B); + ASSERT(A <= B); + ASSERT(A != B); + ASSERT(t[A < B]); + ASSERT(t[A <= B]); + ASSERT(!t[A == B]); + ASSERT(t[A != B]); + ASSERT(!t[A >= B]); + ASSERT(!t[A > B]); + break; + case 0: + ASSERT(A <= B); + ASSERT(A == B); + ASSERT(A >= B); + ASSERT(!t[A < B]); + ASSERT(t[A <= B]); + ASSERT(t[A == B]); + ASSERT(!t[A != B]); + ASSERT(t[A >= B]); + ASSERT(!t[A > B]); + break; + case 1: + ASSERT(A != B); + ASSERT(A >= B); + ASSERT(A > B); + ASSERT(!t[A < B]); + ASSERT(!t[A <= B]); + ASSERT(!t[A == B]); + ASSERT(t[A != B]); + ASSERT(t[A >= B]); + ASSERT(t[A > B]); + break; + default: + ASSERT(0); + break; + } + } + finished(); +} + diff --git a/tests/plat/long-long/llshift_e.c b/tests/plat/long-long/llshift_e.c new file mode 100644 index 000000000..b5652ebb3 --- /dev/null +++ b/tests/plat/long-long/llshift_e.c @@ -0,0 +1,75 @@ +#include "test.h" + +/* + * i << 1 is a constant shift. i << (1 + zero) is a variable shift, + * and may use a different rule in some code generators. + */ +int zero = 0; + +long long i = 121LL; +long long j = 224690292230LL; +unsigned long long u = 12022195707510591570ULL; + +void _m_a_i_n(void) { + ASSERT(i << 0 == 121LL); + ASSERT(i << (0 + zero) == 121LL); + ASSERT(i << 1 == 242LL); + ASSERT(i << (1 + zero) == 242LL); + ASSERT(i << 26 == 8120172544LL); + ASSERT(i << (26 + zero) == 8120172544LL); + ASSERT(i << 56 == 8718968878589280256LL); + ASSERT(i << (56 + zero) == 8718968878589280256LL); + + ASSERT(i >> 0 == 121LL); + ASSERT(i >> (0 + zero) == 121LL); + ASSERT(i >> 1 == 60LL); + ASSERT(i >> (1 + zero) == 60LL); + ASSERT(i >> 7 == 0LL); + ASSERT(i >> (7 + zero) == 0LL); + ASSERT(i >> 37 == 0LL); + ASSERT(i >> (37 + zero) == 0LL); + + ASSERT(-i >> 0 == -121LL); + ASSERT(-i >> (0 + zero) == -121LL); + ASSERT(-i >> 1 == -61LL); + ASSERT(-i >> (1 + zero) == -61LL); + ASSERT(-i >> 7 == -1LL); + ASSERT(-i >> (7 + zero) == -1LL); + ASSERT(-i >> 37 == -1LL); + ASSERT(-i >> (37 + zero) == -1LL); + + ASSERT(j << 0 == 224690292230LL); + ASSERT(j << (0 + zero) == 224690292230LL); + ASSERT(j << 10 == 230082859243520LL); + ASSERT(j << (10 + zero) == 230082859243520LL); + ASSERT(j << 25 == 7539355131691663360LL); + ASSERT(j << (25 + zero) == 7539355131691663360LL); + + ASSERT(j >> 0 == 224690292230LL); + ASSERT(j >> (0 + zero) == 224690292230LL); + ASSERT(j >> 6 == 3510785816LL); + ASSERT(j >> (6 + zero) == 3510785816LL); + ASSERT(j >> 32 == 52LL); + ASSERT(j >> (32 + zero) == 52LL); + ASSERT(j >> 38 == 0LL); + ASSERT(j >> (38 + zero) == 0LL); + + ASSERT(-j >> 0 == -224690292230LL); + ASSERT(-j >> (0 + zero) == -224690292230LL); + ASSERT(-j >> 6 == -3510785817LL); + ASSERT(-j >> (6 + zero) == -3510785817LL); + ASSERT(-j >> 32 == -53LL); + ASSERT(-j >> (32 + zero) == -53LL); + ASSERT(-j >> 38 == -1LL); + ASSERT(-j >> (38 + zero) == -1LL); + + ASSERT(u >> 0 == 12022195707510591570ULL); + ASSERT(u >> (0 + zero) == 12022195707510591570ULL); + ASSERT(u >> 1 == 6011097853755295785ULL); + ASSERT(u >> (1 + zero) == 6011097853755295785ULL); + ASSERT(u >> 41 == 5467061ULL); + ASSERT(u >> (41 + zero) == 5467061ULL); + + finished(); +} +