ack/tests/plat/long-long/lldivrem_e.c
George Koehler f6a1e08218 Test long long division and remainder; fix i386.
My i386 code from 893df4b gave the wrong sign to some 8-byte
remainders.  Fix by splitting .dvi8 and .rmi8 so each has its own code
to pick the sign.  They and .dvu8 and .rmu8 share a private sub
.divrem8 for unsigned division.

Improve the i386 code by using instructions like _bsr_ and _shrd_.
Change the helpers to yield a quotient in ebx:eax or a remainder in
ecx:edx; this seems more convenient, because _div_ puts its quotient
in eax and remainder in edx.
2019-09-16 20:19:36 -04:00

72 lines
2.2 KiB
C

#include "test.h"
/*
* Test division and remainder. Failure code will look like
* - 0x3d = id 0x3, 'd' for division
* - 0x3e = id 0x3, 'e' for remainder
*/
struct s_divrem {
unsigned int id;
long long a;
long long b;
long long a_div_b; /* a / b */
long long a_rem_b; /* a % b */
} s_cases[] = {
{0x1, 310LL, 100LL, 3LL, 10LL},
{0x2, 310LL, -100LL, -3LL, 10LL},
{0x3, -310LL, 100LL, -3LL, -10LL},
{0x4, -310LL, -100LL, 3LL, -10LL},
{0x5, 3000000000000010LL, 100LL, 30000000000000LL, 10LL},
{0x6, 3000000000000010LL, -100LL, -30000000000000LL, 10LL},
{0x7, -3000000000000010LL, 100LL, -30000000000000LL, -10LL},
{0x8, -3000000000000010LL, -100LL, 30000000000000LL, -10LL},
{0x9, 3000000000000010LL, 1000000000000LL, 3000LL, 10LL},
{0xa, 3000000000000010LL, -1000000000000LL, -3000LL, 10LL},
{0xb, -3000000000000010LL, 1000000000000LL, -3000LL, -10LL},
{0xc, -3000000000000010LL, -1000000000000LL, 3000LL, -10LL},
/*
* In next 3 cases, i386 tries (a / (b >> 13)) >> 13 = 8,
* may need to correct the quotient from 8 to 7.
*/
{0x11, 0x864200000000LL, 0x10c840000000LL, 8LL, 0LL},
{0x12, 0x864200000000LL, 0x10c840000001LL, 7LL, 0x10c83ffffff9LL},
{0x13, 0x864200000000LL, 0x10c840001fffLL, 7LL, 0x10c83fff2007LL},
};
struct u_divrem {
unsigned int id;
unsigned long long a;
unsigned long long b;
unsigned long long a_div_b;
unsigned long long a_rem_b;
} u_cases[] = {
{0x81, 310ULL, 100ULL, 3ULL, 10ULL},
{0x82, 3000000000000010ULL, 100ULL, 30000000000000ULL, 10ULL},
{0x83, 3000000000000010ULL, 1000000000000ULL, 3000ULL, 10ULL},
{0x91, 0x8000000000000000ULL, 3ULL, 0x2aaaaaaaaaaaaaaaULL, 2ULL},
{0x92, 0xffffffffffffffffULL, 3ULL, 0x5555555555555555ULL, 0ULL},
};
#define LEN(ary) (sizeof(ary) / sizeof(ary[0]))
void _m_a_i_n(void) {
int i;
for (i = 0; i < LEN(s_cases); i++) {
struct s_divrem *s = &s_cases[i];
if (s->a / s->b != s->a_div_b)
fail((s->id << 4) | 0xd);
if (s->a % s->b != s->a_rem_b)
fail((s->id << 4) | 0xe);
}
for (i = 0; i < LEN(u_cases); i++) {
struct u_divrem *u = &u_cases[i];
if (u->a / u->b != u->a_div_b)
fail((u->id << 4) | 0xd);
if (u->a % u->b != u->a_rem_b)
fail((u->id << 4) | 0xe);
}
finished();
}