mirror of
https://github.com/jart/cosmopolitan.git
synced 2025-06-27 14:58:30 +00:00
parent
50d8d953ce
commit
06b749ae03
130 changed files with 2 additions and 26665 deletions
|
@ -1,139 +0,0 @@
|
|||
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
|
||||
│vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi│
|
||||
╞══════════════════════════════════════════════════════════════════════════════╡
|
||||
│ Copyright 2020 Justine Alexandra Roberts Tunney │
|
||||
│ │
|
||||
│ Permission to use, copy, modify, and/or distribute this software for │
|
||||
│ any purpose with or without fee is hereby granted, provided that the │
|
||||
│ above copyright notice and this permission notice appear in all copies. │
|
||||
│ │
|
||||
│ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL │
|
||||
│ WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED │
|
||||
│ WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE │
|
||||
│ AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL │
|
||||
│ DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR │
|
||||
│ PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER │
|
||||
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "tool/build/lib/alu.h"
|
||||
#include "libc/assert.h"
|
||||
#include "libc/limits.h"
|
||||
#include "libc/runtime/runtime.h"
|
||||
#include "libc/stdio/stdio.h"
|
||||
#include "libc/testlib/ezbench.h"
|
||||
#include "libc/testlib/testlib.h"
|
||||
#include "test/tool/build/lib/optest.h"
|
||||
#include "tool/build/lib/case.h"
|
||||
#include "tool/build/lib/flags.h"
|
||||
#ifdef __x86_64__
|
||||
|
||||
#define ALU_TEST 8
|
||||
|
||||
#define NATIVE_ALU2(MODE, INSTRUCTION) \
|
||||
do { \
|
||||
intptr_t flags; \
|
||||
asm("pushf\n\t" \
|
||||
"andl\t%3,(%%rsp)\n\t" \
|
||||
"orl\t%4,(%%rsp)\n\t" \
|
||||
"popf\n\t" INSTRUCTION "\t%" MODE "2,%" MODE "0\n\t" \
|
||||
"pushf\n\t" \
|
||||
"pop\t%q1" \
|
||||
: "+r"(x), "=rm"(flags) \
|
||||
: "r"(y), "i"(~FMASK), "r"(*f & FMASK) \
|
||||
: "cc"); \
|
||||
*f = flags; \
|
||||
} while (0)
|
||||
|
||||
#define NATIVE_ALU2_ANYBITS(INSTRUCTION, MUTATING) \
|
||||
switch (w) { \
|
||||
case 0: \
|
||||
NATIVE_ALU2("b", INSTRUCTION); \
|
||||
if (MUTATING) x &= 0xff; \
|
||||
return x; \
|
||||
case 1: \
|
||||
NATIVE_ALU2("w", INSTRUCTION); \
|
||||
if (MUTATING) x &= 0xffff; \
|
||||
return x; \
|
||||
case 2: \
|
||||
NATIVE_ALU2("k", INSTRUCTION); \
|
||||
return x; \
|
||||
case 3: \
|
||||
NATIVE_ALU2("q", INSTRUCTION); \
|
||||
return x; \
|
||||
default: \
|
||||
abort(); \
|
||||
}
|
||||
|
||||
int64_t RunGolden(char w, int h, uint64_t x, uint64_t y, uint32_t *f) {
|
||||
bool rw;
|
||||
rw = !(h & ALU_TEST);
|
||||
switch (h & 7) {
|
||||
case ALU_OR:
|
||||
NATIVE_ALU2_ANYBITS("or", rw);
|
||||
case ALU_AND:
|
||||
if (rw) {
|
||||
NATIVE_ALU2_ANYBITS("and", rw);
|
||||
} else {
|
||||
NATIVE_ALU2_ANYBITS("test", rw);
|
||||
}
|
||||
case ALU_XOR:
|
||||
NATIVE_ALU2_ANYBITS("xor", rw);
|
||||
case ALU_SBB:
|
||||
NATIVE_ALU2_ANYBITS("sbb", rw);
|
||||
case ALU_CMP:
|
||||
rw = false;
|
||||
NATIVE_ALU2_ANYBITS("cmp", rw);
|
||||
case ALU_SUB:
|
||||
NATIVE_ALU2_ANYBITS("sub", rw);
|
||||
case ALU_ADC:
|
||||
NATIVE_ALU2_ANYBITS("adc", rw);
|
||||
case ALU_ADD:
|
||||
NATIVE_ALU2_ANYBITS("add", rw);
|
||||
default:
|
||||
abort();
|
||||
}
|
||||
}
|
||||
|
||||
const uint8_t kAluOps[] = {
|
||||
ALU_ADD, //
|
||||
ALU_OR, //
|
||||
ALU_ADC, //
|
||||
ALU_SBB, //
|
||||
ALU_AND, //
|
||||
ALU_SUB, //
|
||||
ALU_XOR, //
|
||||
ALU_CMP, //
|
||||
ALU_AND | ALU_TEST, //
|
||||
};
|
||||
|
||||
const char *const kAluNames[] = {
|
||||
[ALU_ADD] = "add", //
|
||||
[ALU_OR] = "or", //
|
||||
[ALU_ADC] = "adc", //
|
||||
[ALU_SBB] = "sbb", //
|
||||
[ALU_AND] = "and", //
|
||||
[ALU_SUB] = "sub", //
|
||||
[ALU_XOR] = "xor", //
|
||||
[ALU_CMP] = "cmp", //
|
||||
[ALU_AND | ALU_TEST] = "test", //
|
||||
};
|
||||
|
||||
int64_t Alu(int w, int h, uint64_t x, uint64_t y, uint32_t *flags) {
|
||||
if (h < ALU_CMP) {
|
||||
return kAlu[h][w](x, y, flags);
|
||||
} else {
|
||||
kAlu[h & 7][w](x, y, flags);
|
||||
return x;
|
||||
}
|
||||
}
|
||||
|
||||
int64_t RunOpTest(char w, int h, uint64_t x, uint64_t y, uint32_t *f) {
|
||||
return Alu(w, h, x, y, f);
|
||||
}
|
||||
|
||||
TEST(alu, test) {
|
||||
RunOpTests(kAluOps, ARRAYLEN(kAluOps), kAluNames);
|
||||
}
|
||||
|
||||
#endif /* __x86_64__ */
|
|
@ -1,108 +0,0 @@
|
|||
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
|
||||
│vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi│
|
||||
╞══════════════════════════════════════════════════════════════════════════════╡
|
||||
│ Copyright 2020 Justine Alexandra Roberts Tunney │
|
||||
│ │
|
||||
│ Permission to use, copy, modify, and/or distribute this software for │
|
||||
│ any purpose with or without fee is hereby granted, provided that the │
|
||||
│ above copyright notice and this permission notice appear in all copies. │
|
||||
│ │
|
||||
│ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL │
|
||||
│ WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED │
|
||||
│ WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE │
|
||||
│ AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL │
|
||||
│ DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR │
|
||||
│ PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER │
|
||||
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "tool/build/lib/bitscan.h"
|
||||
#include "libc/macros.internal.h"
|
||||
#include "libc/testlib/testlib.h"
|
||||
#include "test/tool/build/lib/numbers.h"
|
||||
#include "tool/build/lib/flags.h"
|
||||
#ifdef __x86_64__
|
||||
|
||||
#define OSZ 00000000040
|
||||
#define REXW 00000000100
|
||||
|
||||
struct Machine m[1];
|
||||
struct XedDecodedInst xedd[1];
|
||||
|
||||
void SetUp(void) {
|
||||
m->xedd = xedd;
|
||||
}
|
||||
|
||||
TEST(bsr64, test) {
|
||||
bool zf;
|
||||
uint64_t i, w, x, a, b;
|
||||
for (i = 0; i < ARRAYLEN(kNumbers); ++i) {
|
||||
x = kNumbers[i];
|
||||
a = AluBsr(m, REXW, x);
|
||||
asm("bsrq\t%2,%0" : "=r"(b), "=@ccz"(zf) : "r"(x));
|
||||
ASSERT_EQ(zf, GetFlag(m->flags, FLAGS_ZF));
|
||||
if (!zf) ASSERT_EQ(a, b);
|
||||
}
|
||||
}
|
||||
|
||||
TEST(bsr32, test) {
|
||||
bool zf;
|
||||
uint32_t i, w, x, a, b;
|
||||
for (i = 0; i < ARRAYLEN(kNumbers); ++i) {
|
||||
x = kNumbers[i];
|
||||
a = AluBsr(m, 0, x);
|
||||
asm("bsrl\t%2,%0" : "=r"(b), "=@ccz"(zf) : "r"(x));
|
||||
ASSERT_EQ(zf, GetFlag(m->flags, FLAGS_ZF));
|
||||
if (!zf) ASSERT_EQ(a, b);
|
||||
}
|
||||
}
|
||||
|
||||
TEST(bsr16, test) {
|
||||
bool zf;
|
||||
uint16_t i, w, x, a, b;
|
||||
for (i = 0; i < ARRAYLEN(kNumbers); ++i) {
|
||||
x = kNumbers[i];
|
||||
a = AluBsr(m, OSZ, x);
|
||||
asm("bsrw\t%2,%0" : "=r"(b), "=@ccz"(zf) : "r"(x));
|
||||
ASSERT_EQ(zf, GetFlag(m->flags, FLAGS_ZF));
|
||||
if (!zf) ASSERT_EQ(a, b);
|
||||
}
|
||||
}
|
||||
|
||||
TEST(bsf64, test) {
|
||||
bool zf;
|
||||
uint64_t i, w, x, a, b;
|
||||
for (i = 0; i < ARRAYLEN(kNumbers); ++i) {
|
||||
x = kNumbers[i];
|
||||
a = AluBsf(m, REXW, x);
|
||||
asm("bsfq\t%2,%0" : "=r"(b), "=@ccz"(zf) : "r"(x));
|
||||
ASSERT_EQ(zf, GetFlag(m->flags, FLAGS_ZF));
|
||||
if (!zf) ASSERT_EQ(a, b);
|
||||
}
|
||||
}
|
||||
|
||||
TEST(bsf32, test) {
|
||||
bool zf;
|
||||
uint32_t i, w, x, a, b;
|
||||
for (i = 0; i < ARRAYLEN(kNumbers); ++i) {
|
||||
x = kNumbers[i];
|
||||
a = AluBsf(m, 0, x);
|
||||
asm("bsfl\t%2,%0" : "=r"(b), "=@ccz"(zf) : "r"(x));
|
||||
ASSERT_EQ(zf, GetFlag(m->flags, FLAGS_ZF));
|
||||
if (!zf) ASSERT_EQ(a, b);
|
||||
}
|
||||
}
|
||||
|
||||
TEST(bsf16, test) {
|
||||
bool zf;
|
||||
uint16_t i, w, x, a, b;
|
||||
for (i = 0; i < ARRAYLEN(kNumbers); ++i) {
|
||||
x = kNumbers[i];
|
||||
a = AluBsf(m, OSZ, x);
|
||||
asm("bsfw\t%2,%0" : "=r"(b), "=@ccz"(zf) : "r"(x));
|
||||
ASSERT_EQ(zf, GetFlag(m->flags, FLAGS_ZF));
|
||||
if (!zf) ASSERT_EQ(a, b, "%#lx", x);
|
||||
}
|
||||
}
|
||||
|
||||
#endif /* __x86_64__ */
|
|
@ -1,329 +0,0 @@
|
|||
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
|
||||
│vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi│
|
||||
╞══════════════════════════════════════════════════════════════════════════════╡
|
||||
│ Copyright 2020 Justine Alexandra Roberts Tunney │
|
||||
│ │
|
||||
│ Permission to use, copy, modify, and/or distribute this software for │
|
||||
│ any purpose with or without fee is hereby granted, provided that the │
|
||||
│ above copyright notice and this permission notice appear in all copies. │
|
||||
│ │
|
||||
│ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL │
|
||||
│ WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED │
|
||||
│ WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE │
|
||||
│ AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL │
|
||||
│ DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR │
|
||||
│ PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER │
|
||||
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/macros.internal.h"
|
||||
#include "libc/runtime/runtime.h"
|
||||
#include "libc/stdio/stdio.h"
|
||||
#include "libc/testlib/testlib.h"
|
||||
#include "test/tool/build/lib/numbers.h"
|
||||
#include "test/tool/build/lib/optest.h"
|
||||
#include "tool/build/lib/alu.h"
|
||||
#include "tool/build/lib/flags.h"
|
||||
#include "tool/build/lib/machine.h"
|
||||
#ifdef __x86_64__
|
||||
|
||||
#define NATIVE_ALU2(MODE, INSTRUCTION) \
|
||||
asm("pushf\n\t" \
|
||||
"andl\t%3,(%%rsp)\n\t" \
|
||||
"orl\t%4,(%%rsp)\n\t" \
|
||||
"popf\n\t" INSTRUCTION "\t%b2,%" MODE "0\n\t" \
|
||||
"pushf\n\t" \
|
||||
"pop\t%q1" \
|
||||
: "+r"(x), "=r"(*f) \
|
||||
: "c"(y), "i"(~FMASK), "r"(*f & FMASK) \
|
||||
: "cc")
|
||||
|
||||
#define NATIVE_ALU2_ANYBITS(INSTRUCTION, MUTATING) \
|
||||
switch (w) { \
|
||||
case 0: \
|
||||
NATIVE_ALU2("b", INSTRUCTION); \
|
||||
if (MUTATING) x &= 0xff; \
|
||||
return x; \
|
||||
case 1: \
|
||||
NATIVE_ALU2("w", INSTRUCTION); \
|
||||
if (MUTATING) x &= 0xffff; \
|
||||
return x; \
|
||||
case 2: \
|
||||
NATIVE_ALU2("k", INSTRUCTION); \
|
||||
return x; \
|
||||
case 3: \
|
||||
NATIVE_ALU2("q", INSTRUCTION); \
|
||||
return x; \
|
||||
default: \
|
||||
abort(); \
|
||||
}
|
||||
|
||||
int64_t Bsu(int w, int h, uint64_t x, uint64_t y, uint32_t *f) {
|
||||
switch (h & 7) {
|
||||
case BSU_SHR:
|
||||
switch (w) {
|
||||
case 0:
|
||||
return Shr8(x, y, f);
|
||||
case 1:
|
||||
return Shr16(x, y, f);
|
||||
case 2:
|
||||
return Shr32(x, y, f);
|
||||
case 3:
|
||||
return Shr64(x, y, f);
|
||||
default:
|
||||
__builtin_unreachable();
|
||||
}
|
||||
case BSU_SAL:
|
||||
case BSU_SHL:
|
||||
switch (w) {
|
||||
case 0:
|
||||
return Shl8(x, y, f);
|
||||
case 1:
|
||||
return Shl16(x, y, f);
|
||||
case 2:
|
||||
return Shl32(x, y, f);
|
||||
case 3:
|
||||
return Shl64(x, y, f);
|
||||
default:
|
||||
__builtin_unreachable();
|
||||
}
|
||||
case BSU_SAR:
|
||||
switch (w) {
|
||||
case 0:
|
||||
return Sar8(x, y, f);
|
||||
case 1:
|
||||
return Sar16(x, y, f);
|
||||
case 2:
|
||||
return Sar32(x, y, f);
|
||||
case 3:
|
||||
return Sar64(x, y, f);
|
||||
default:
|
||||
__builtin_unreachable();
|
||||
}
|
||||
case BSU_ROL:
|
||||
switch (w) {
|
||||
case 0:
|
||||
return Rol8(x, y, f);
|
||||
case 1:
|
||||
return Rol16(x, y, f);
|
||||
case 2:
|
||||
return Rol32(x, y, f);
|
||||
case 3:
|
||||
return Rol64(x, y, f);
|
||||
default:
|
||||
__builtin_unreachable();
|
||||
}
|
||||
case BSU_ROR:
|
||||
switch (w) {
|
||||
case 0:
|
||||
return Ror8(x, y, f);
|
||||
case 1:
|
||||
return Ror16(x, y, f);
|
||||
case 2:
|
||||
return Ror32(x, y, f);
|
||||
case 3:
|
||||
return Ror64(x, y, f);
|
||||
default:
|
||||
__builtin_unreachable();
|
||||
}
|
||||
case BSU_RCR:
|
||||
switch (w) {
|
||||
case 0:
|
||||
return Rcr8(x, y, f);
|
||||
case 1:
|
||||
return Rcr16(x, y, f);
|
||||
case 2:
|
||||
return Rcr32(x, y, f);
|
||||
case 3:
|
||||
return Rcr64(x, y, f);
|
||||
default:
|
||||
__builtin_unreachable();
|
||||
}
|
||||
case BSU_RCL:
|
||||
switch (w) {
|
||||
case 0:
|
||||
return Rcl8(x, y, f);
|
||||
case 1:
|
||||
return Rcl16(x, y, f);
|
||||
case 2:
|
||||
return Rcl32(x, y, f);
|
||||
case 3:
|
||||
return Rcl64(x, y, f);
|
||||
default:
|
||||
__builtin_unreachable();
|
||||
}
|
||||
default:
|
||||
__builtin_unreachable();
|
||||
}
|
||||
}
|
||||
|
||||
int64_t RunGolden(char w, int h, uint64_t x, uint64_t y, uint32_t *f) {
|
||||
switch (h & 7) {
|
||||
case BSU_ROR:
|
||||
NATIVE_ALU2_ANYBITS("ror", true);
|
||||
case BSU_SHL:
|
||||
NATIVE_ALU2_ANYBITS("shl", true);
|
||||
case BSU_SAL:
|
||||
NATIVE_ALU2_ANYBITS("sal", true);
|
||||
case BSU_RCR:
|
||||
NATIVE_ALU2_ANYBITS("rcr", true);
|
||||
case BSU_SAR:
|
||||
NATIVE_ALU2_ANYBITS("sar", true);
|
||||
case BSU_SHR:
|
||||
NATIVE_ALU2_ANYBITS("shr", true);
|
||||
case BSU_RCL:
|
||||
NATIVE_ALU2_ANYBITS("rcl", true);
|
||||
case BSU_ROL:
|
||||
NATIVE_ALU2_ANYBITS("rol", true);
|
||||
default:
|
||||
abort();
|
||||
}
|
||||
}
|
||||
|
||||
const uint8_t kBsuOps[] = {
|
||||
BSU_SHR, BSU_SHL, BSU_ROL, BSU_ROR, BSU_RCL,
|
||||
BSU_RCR, BSU_SHL, BSU_SAL, BSU_SAR,
|
||||
};
|
||||
|
||||
const char *const kBsuNames[] = {
|
||||
[BSU_ROL] = "rol", [BSU_ROR] = "ror", [BSU_RCL] = "rcl", [BSU_RCR] = "rcr",
|
||||
[BSU_SHL] = "shl", [BSU_SHR] = "shr", [BSU_SAL] = "sal", [BSU_SAR] = "sar",
|
||||
};
|
||||
|
||||
int64_t RunOpTest(char w, int h, uint64_t x, uint64_t y, uint32_t *f) {
|
||||
return Bsu(w, h, x, y, f);
|
||||
}
|
||||
|
||||
void FixupUndefOpTestFlags(char w, int h, uint64_t x, uint64_t y,
|
||||
uint32_t goldenflags, uint32_t *flags) {
|
||||
y &= w == 3 ? 0x3F : 0x1F;
|
||||
if (y != 0 && y != 1) {
|
||||
*flags = SetFlag(*flags, FLAGS_OF, GetFlag(goldenflags, FLAGS_OF));
|
||||
}
|
||||
if (y >= w) {
|
||||
*flags = SetFlag(*flags, FLAGS_CF, GetFlag(goldenflags, FLAGS_CF));
|
||||
}
|
||||
}
|
||||
|
||||
TEST(bsu, test) {
|
||||
RunOpTests(kBsuOps, ARRAYLEN(kBsuOps), kBsuNames);
|
||||
}
|
||||
|
||||
TEST(shrd32, smoke) {
|
||||
int i, j, k;
|
||||
uint8_t b, cf, of;
|
||||
uint32_t x, y, z1, f, z2, unflag;
|
||||
for (i = 0; i < ARRAYLEN(kNumbers); ++i) {
|
||||
x = kNumbers[i];
|
||||
for (j = 0; j < ARRAYLEN(kNumbers); ++j) {
|
||||
y = kNumbers[j];
|
||||
for (k = 0; k < ARRAYLEN(kNumbers); ++k) {
|
||||
f = 0;
|
||||
cf = 0;
|
||||
of = 0;
|
||||
b = kNumbers[k];
|
||||
z1 = BsuDoubleShift(2, x, y, b, true, &f);
|
||||
z2 = x;
|
||||
asm("xor\t%1,%1\n\t"
|
||||
"shrd\t%5,%4,%0"
|
||||
: "+rm"(z2), "=&r"(unflag), "=@ccc"(cf), "=@cco"(of)
|
||||
: "r"(y), "c"(b)
|
||||
: "cc");
|
||||
ASSERT_EQ(z2, z1);
|
||||
ASSERT_EQ(cf, GetFlag(f, FLAGS_CF));
|
||||
if (b <= 1) ASSERT_EQ(of, GetFlag(f, FLAGS_OF));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
TEST(shld16, smoke) {
|
||||
uint32_t f;
|
||||
int i, j, k;
|
||||
uint8_t b, cf, of;
|
||||
uint16_t x, y, z1, z2, unflag;
|
||||
for (i = 0; i < ARRAYLEN(kNumbers); ++i) {
|
||||
x = kNumbers[i];
|
||||
for (j = 0; j < ARRAYLEN(kNumbers); ++j) {
|
||||
y = kNumbers[j];
|
||||
for (k = 0; k < ARRAYLEN(kNumbers); ++k) {
|
||||
f = 0;
|
||||
cf = 0;
|
||||
of = 0;
|
||||
b = kNumbers[k];
|
||||
if (b > 16) continue;
|
||||
z1 = BsuDoubleShift(1, x, y, b, false, &f);
|
||||
z2 = x;
|
||||
asm("xor\t%1,%1\n\t"
|
||||
"shldw\t%5,%4,%0"
|
||||
: "+rm"(z2), "=&r"(unflag), "=@ccc"(cf), "=@cco"(of)
|
||||
: "r"(y), "c"(b)
|
||||
: "cc");
|
||||
ASSERT_EQ(z2, z1);
|
||||
ASSERT_EQ(cf, GetFlag(f, FLAGS_CF));
|
||||
if (b <= 1) ASSERT_EQ(of, GetFlag(f, FLAGS_OF));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
TEST(shld32, smoke) {
|
||||
int i, j, k;
|
||||
uint8_t b, cf, of;
|
||||
uint32_t x, y, z1, f, z2, unflag;
|
||||
for (i = 0; i < ARRAYLEN(kNumbers); ++i) {
|
||||
x = kNumbers[i];
|
||||
for (j = 0; j < ARRAYLEN(kNumbers); ++j) {
|
||||
y = kNumbers[j];
|
||||
for (k = 0; k < ARRAYLEN(kNumbers); ++k) {
|
||||
f = 0;
|
||||
cf = 0;
|
||||
of = 0;
|
||||
b = kNumbers[k];
|
||||
if (b > 32) continue;
|
||||
z1 = BsuDoubleShift(2, x, y, b, false, &f);
|
||||
z2 = x;
|
||||
asm("xor\t%1,%1\n\t"
|
||||
"shld\t%5,%4,%0"
|
||||
: "+rm"(z2), "=&r"(unflag), "=@ccc"(cf), "=@cco"(of)
|
||||
: "r"(y), "c"(b)
|
||||
: "cc");
|
||||
ASSERT_EQ(z2, z1);
|
||||
ASSERT_EQ(cf, GetFlag(f, FLAGS_CF));
|
||||
if (b <= 1) ASSERT_EQ(of, GetFlag(f, FLAGS_OF));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
TEST(shld64, smoke) {
|
||||
uint32_t f;
|
||||
int i, j, k;
|
||||
uint8_t b, cf, of;
|
||||
uint64_t x, y, z1, z2, unflag;
|
||||
for (i = 0; i < ARRAYLEN(kNumbers); ++i) {
|
||||
x = kNumbers[i];
|
||||
for (j = 0; j < ARRAYLEN(kNumbers); ++j) {
|
||||
y = kNumbers[j];
|
||||
for (k = 0; k < ARRAYLEN(kNumbers); ++k) {
|
||||
f = 0;
|
||||
cf = 0;
|
||||
of = 0;
|
||||
b = kNumbers[k];
|
||||
if (b > 64) continue;
|
||||
z1 = BsuDoubleShift(3, x, y, b, false, &f);
|
||||
z2 = x;
|
||||
asm("xor\t%1,%1\n\t"
|
||||
"shldq\t%5,%4,%0"
|
||||
: "+rm"(z2), "=&r"(unflag), "=@ccc"(cf), "=@cco"(of)
|
||||
: "r"(y), "c"(b)
|
||||
: "cc");
|
||||
ASSERT_EQ(z2, z1);
|
||||
ASSERT_EQ(cf, GetFlag(f, FLAGS_CF));
|
||||
if (b <= 1) ASSERT_EQ(of, GetFlag(f, FLAGS_OF));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif /* __x86_64__ */
|
|
@ -1,263 +0,0 @@
|
|||
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
|
||||
│vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi│
|
||||
╞══════════════════════════════════════════════════════════════════════════════╡
|
||||
│ Copyright 2020 Justine Alexandra Roberts Tunney │
|
||||
│ │
|
||||
│ Permission to use, copy, modify, and/or distribute this software for │
|
||||
│ any purpose with or without fee is hereby granted, provided that the │
|
||||
│ above copyright notice and this permission notice appear in all copies. │
|
||||
│ │
|
||||
│ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL │
|
||||
│ WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED │
|
||||
│ WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE │
|
||||
│ AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL │
|
||||
│ DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR │
|
||||
│ PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER │
|
||||
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/stdio/lcg.internal.h"
|
||||
#include "libc/stdio/rand.h"
|
||||
#include "libc/stdio/stdio.h"
|
||||
#include "libc/testlib/ezbench.h"
|
||||
#include "libc/testlib/testlib.h"
|
||||
#include "tool/build/lib/dis.h"
|
||||
#include "tool/build/lib/modrm.h"
|
||||
|
||||
char b1[64];
|
||||
char b2[64];
|
||||
struct Dis d[1];
|
||||
|
||||
#define ILD(OP, MODE) \
|
||||
do { \
|
||||
xed_decoded_inst_zero_set_mode(d->xedd, MODE); \
|
||||
ASSERT_EQ(0, xed_instruction_length_decode(d->xedd, OP, sizeof(OP))); \
|
||||
d->xedd->op.rde = EncodeRde(d->xedd); \
|
||||
} while (0)
|
||||
|
||||
TEST(DisInst, testInt3) {
|
||||
uint8_t op[] = {0xcc};
|
||||
ILD(op, XED_MACHINE_MODE_LONG_64);
|
||||
DisInst(d, b1, DisSpec(d->xedd, b2));
|
||||
EXPECT_STREQ("int3 ", b1);
|
||||
}
|
||||
|
||||
TEST(DisInst, testImmMem_needsSuffix) {
|
||||
uint8_t op[] = {0x80, 0x3c, 0x07, 0x00};
|
||||
ILD(op, XED_MACHINE_MODE_LONG_64);
|
||||
DisInst(d, b1, DisSpec(d->xedd, b2));
|
||||
EXPECT_STREQ("cmpb $0,(%rdi,%rax)", b1);
|
||||
}
|
||||
|
||||
TEST(DisInst, testImmReg_doesntNeedSuffix) {
|
||||
uint8_t op[] = {0xb8, 0x08, 0x70, 0x40, 0x00};
|
||||
ILD(op, XED_MACHINE_MODE_LONG_64);
|
||||
DisInst(d, b1, DisSpec(d->xedd, b2));
|
||||
EXPECT_STREQ("mov $0x407008,%eax", b1);
|
||||
}
|
||||
|
||||
TEST(DisInst, testPuttingOnTheRiz) {
|
||||
static uint8_t ops[][15] = {
|
||||
{0x8d, 0b00110100, 0b00100110},
|
||||
{0x67, 0x8d, 0b00110100, 0b11100110},
|
||||
{0x67, 0x8d, 0b10110100, 0b11100101, 0, 0, 0, 0},
|
||||
{0x8d, 0b00110100, 0b11100101, 0x37, 0x13, 0x03, 0},
|
||||
{0x8d, 0b10110100, 0b11100101, 0, 0, 0, 0},
|
||||
};
|
||||
ILD(ops[0], XED_MACHINE_MODE_LONG_64);
|
||||
DisInst(d, b1, DisSpec(d->xedd, b2));
|
||||
EXPECT_STREQ("lea (%rsi),%esi", b1);
|
||||
ILD(ops[1], XED_MACHINE_MODE_LONG_64);
|
||||
DisInst(d, b1, DisSpec(d->xedd, b2));
|
||||
EXPECT_STREQ("lea (%esi,%eiz,8),%esi", b1);
|
||||
ILD(ops[2], XED_MACHINE_MODE_LONG_64);
|
||||
DisInst(d, b1, DisSpec(d->xedd, b2));
|
||||
EXPECT_STREQ("lea 0(%ebp,%eiz,8),%esi", b1);
|
||||
ILD(ops[3], XED_MACHINE_MODE_LONG_64);
|
||||
DisInst(d, b1, DisSpec(d->xedd, b2));
|
||||
EXPECT_STREQ("lea 0x31337,%esi", b1);
|
||||
ILD(ops[4], XED_MACHINE_MODE_LONG_64);
|
||||
DisInst(d, b1, DisSpec(d->xedd, b2));
|
||||
EXPECT_STREQ("lea 0(%rbp,%riz,8),%esi", b1);
|
||||
}
|
||||
|
||||
TEST(DisInst, testSibIndexOnly) {
|
||||
uint8_t op[] = {76, 141, 4, 141, 0, 0, 0, 0};
|
||||
ILD(op, XED_MACHINE_MODE_LONG_64);
|
||||
DisInst(d, b1, DisSpec(d->xedd, b2));
|
||||
EXPECT_STREQ("lea 0(,%rcx,4),%r8", b1);
|
||||
}
|
||||
|
||||
TEST(DisInst, testRealMode) {
|
||||
uint8_t op[] = {0x89, 0xe5};
|
||||
ILD(op, XED_MACHINE_MODE_REAL);
|
||||
DisInst(d, b1, DisSpec(d->xedd, b2));
|
||||
EXPECT_STREQ("mov %sp,%bp", b1);
|
||||
}
|
||||
|
||||
TEST(DisInst, testNop) {
|
||||
uint8_t op[] = {0x66, 0x2e, 0x0f, 0x1f, 0x84, 0x00, 0x00, 0x00, 0x00, 0x00};
|
||||
ILD(op, XED_MACHINE_MODE_LONG_64);
|
||||
DisInst(d, b1, DisSpec(d->xedd, b2));
|
||||
EXPECT_STREQ("nopw %cs:0(%rax,%rax)", b1);
|
||||
}
|
||||
|
||||
TEST(DisInst, testPush) {
|
||||
uint8_t op[] = {0x41, 0x5c};
|
||||
ILD(op, XED_MACHINE_MODE_LONG_64);
|
||||
EXPECT_EQ(4, ModrmSrm(d->xedd->op.rde));
|
||||
EXPECT_EQ(1, Rexb(d->xedd->op.rde));
|
||||
DisInst(d, b1, DisSpec(d->xedd, b2));
|
||||
EXPECT_STREQ("pop %r12", b1);
|
||||
}
|
||||
|
||||
TEST(DisInst, testMovb) {
|
||||
uint8_t op[] = {0x8a, 0x1e, 0x0c, 0x32};
|
||||
ILD(op, XED_MACHINE_MODE_LONG_64);
|
||||
DisInst(d, b1, DisSpec(d->xedd, b2));
|
||||
EXPECT_STREQ("mov (%rsi),%bl", b1);
|
||||
ILD(op, XED_MACHINE_MODE_REAL);
|
||||
DisInst(d, b1, DisSpec(d->xedd, b2));
|
||||
EXPECT_STREQ("mov 0x320c,%bl", b1);
|
||||
}
|
||||
|
||||
TEST(DisInst, testLes) {
|
||||
uint8_t op[] = {0xc4, 0x3e, 0x16, 0x32};
|
||||
ILD(op, XED_MACHINE_MODE_REAL);
|
||||
DisInst(d, b1, DisSpec(d->xedd, b2));
|
||||
EXPECT_STREQ("les 0x3216,%di", b1);
|
||||
}
|
||||
|
||||
TEST(DisInst, testStosbLong) {
|
||||
uint8_t op[] = {0xAA};
|
||||
ILD(op, XED_MACHINE_MODE_LONG_64);
|
||||
DisInst(d, b1, DisSpec(d->xedd, b2));
|
||||
EXPECT_STREQ("stosb %al,(%rdi)", b1);
|
||||
}
|
||||
|
||||
TEST(DisInst, testStosbReal) {
|
||||
uint8_t op[] = {0xAA};
|
||||
ILD(op, XED_MACHINE_MODE_REAL);
|
||||
DisInst(d, b1, DisSpec(d->xedd, b2));
|
||||
EXPECT_STREQ("stosb %al,(%di)", b1);
|
||||
}
|
||||
|
||||
TEST(DisInst, testStosbLegacy) {
|
||||
uint8_t op[] = {0xAA};
|
||||
ILD(op, XED_MACHINE_MODE_LEGACY_32);
|
||||
DisInst(d, b1, DisSpec(d->xedd, b2));
|
||||
EXPECT_STREQ("stosb %al,(%edi)", b1);
|
||||
}
|
||||
|
||||
TEST(DisInst, testStosbLongAsz) {
|
||||
uint8_t op[] = {0x67, 0xAA};
|
||||
ILD(op, XED_MACHINE_MODE_LONG_64);
|
||||
DisInst(d, b1, DisSpec(d->xedd, b2));
|
||||
EXPECT_STREQ("stosb %al,(%edi)", b1);
|
||||
}
|
||||
|
||||
TEST(DisInst, testAddLong) {
|
||||
uint8_t op[] = {0x01, 0xff};
|
||||
ILD(op, XED_MACHINE_MODE_LONG_64);
|
||||
DisInst(d, b1, DisSpec(d->xedd, b2));
|
||||
EXPECT_STREQ("add %edi,%edi", b1);
|
||||
}
|
||||
|
||||
TEST(DisInst, testAddLegacy) {
|
||||
uint8_t op[] = {0x01, 0xff};
|
||||
ILD(op, XED_MACHINE_MODE_LEGACY_32);
|
||||
DisInst(d, b1, DisSpec(d->xedd, b2));
|
||||
EXPECT_STREQ("add %edi,%edi", b1);
|
||||
}
|
||||
|
||||
TEST(DisInst, testAddReal) {
|
||||
uint8_t op[] = {0x01, 0xff};
|
||||
ILD(op, XED_MACHINE_MODE_REAL);
|
||||
DisInst(d, b1, DisSpec(d->xedd, b2));
|
||||
EXPECT_STREQ("add %di,%di", b1);
|
||||
}
|
||||
|
||||
TEST(DisInst, testAddLongOsz) {
|
||||
uint8_t op[] = {0x66, 0x01, 0xff};
|
||||
ILD(op, XED_MACHINE_MODE_LONG_64);
|
||||
DisInst(d, b1, DisSpec(d->xedd, b2));
|
||||
EXPECT_STREQ("add %di,%di", b1);
|
||||
}
|
||||
|
||||
TEST(DisInst, testAddLegacyOsz) {
|
||||
uint8_t op[] = {0x66, 0x01, 0xff};
|
||||
ILD(op, XED_MACHINE_MODE_LEGACY_32);
|
||||
DisInst(d, b1, DisSpec(d->xedd, b2));
|
||||
EXPECT_STREQ("add %di,%di", b1);
|
||||
}
|
||||
|
||||
TEST(DisInst, testAddRealOsz) {
|
||||
uint8_t op[] = {0x66, 0x01, 0xff};
|
||||
ILD(op, XED_MACHINE_MODE_REAL);
|
||||
DisInst(d, b1, DisSpec(d->xedd, b2));
|
||||
EXPECT_STREQ("add %edi,%edi", b1);
|
||||
}
|
||||
|
||||
TEST(DisInst, testFxam) {
|
||||
uint8_t op[] = {0xd9, 0xe5};
|
||||
ILD(op, XED_MACHINE_MODE_LONG_64);
|
||||
ASSERT_EQ(4, ModrmReg(d->xedd->op.rde));
|
||||
DisInst(d, b1, DisSpec(d->xedd, b2));
|
||||
EXPECT_STREQ("fxam ", b1);
|
||||
}
|
||||
|
||||
TEST(DisInst, testOrImmCode16gcc) {
|
||||
uint8_t op[] = {0x67, 0x81, 0x4c, 0x24, 0x0c, 0x00, 0x0c};
|
||||
ILD(op, XED_MACHINE_MODE_REAL);
|
||||
DisInst(d, b1, DisSpec(d->xedd, b2));
|
||||
EXPECT_STREQ("orw $0xc00,12(%esp)", b1);
|
||||
}
|
||||
|
||||
TEST(DisInst, testPause) {
|
||||
uint8_t op[] = {0xf3, 0x90};
|
||||
ILD(op, XED_MACHINE_MODE_LONG_64);
|
||||
DisInst(d, b1, DisSpec(d->xedd, b2));
|
||||
EXPECT_STREQ("pause ", b1);
|
||||
}
|
||||
|
||||
TEST(DisInst, testJmpEw) {
|
||||
uint8_t op[] = {0xff, 0xe0};
|
||||
ILD(op, XED_MACHINE_MODE_REAL);
|
||||
DisInst(d, b1, DisSpec(d->xedd, b2));
|
||||
EXPECT_STREQ("jmp %ax", b1);
|
||||
}
|
||||
|
||||
TEST(DisInst, testJmpEv16) {
|
||||
uint8_t op[] = {0x66, 0xff, 0xe0};
|
||||
ILD(op, XED_MACHINE_MODE_REAL);
|
||||
DisInst(d, b1, DisSpec(d->xedd, b2));
|
||||
EXPECT_STREQ("jmp %eax", b1);
|
||||
}
|
||||
|
||||
TEST(DisInst, testJmpEv32) {
|
||||
uint8_t op[] = {0xff, 0xe0};
|
||||
ILD(op, XED_MACHINE_MODE_LEGACY_32);
|
||||
DisInst(d, b1, DisSpec(d->xedd, b2));
|
||||
EXPECT_STREQ("jmp %eax", b1);
|
||||
}
|
||||
|
||||
TEST(DisInst, testJmpEq) {
|
||||
uint8_t op[] = {0x66, 0xff, 0xe0};
|
||||
ILD(op, XED_MACHINE_MODE_LONG_64);
|
||||
DisInst(d, b1, DisSpec(d->xedd, b2));
|
||||
EXPECT_STREQ("jmp %rax", b1);
|
||||
}
|
||||
|
||||
TEST(DisInst, testMovswSs) {
|
||||
uint8_t op[] = {0x36, 0xA5};
|
||||
ILD(op, XED_MACHINE_MODE_REAL);
|
||||
DisInst(d, b1, DisSpec(d->xedd, b2));
|
||||
EXPECT_STREQ("movs %ss:(%si),(%di)", b1);
|
||||
}
|
||||
|
||||
TEST(DisInst, testRealModrm_sibOverlap_showsNoDisplacement) {
|
||||
uint8_t op[] = {0x8b, 0b00100101};
|
||||
ILD(op, XED_MACHINE_MODE_REAL);
|
||||
DisInst(d, b1, DisSpec(d->xedd, b2));
|
||||
EXPECT_STREQ("mov (%di),%sp", b1);
|
||||
}
|
|
@ -1,556 +0,0 @@
|
|||
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
|
||||
│vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi│
|
||||
╞══════════════════════════════════════════════════════════════════════════════╡
|
||||
│ Copyright 2020 Justine Alexandra Roberts Tunney │
|
||||
│ │
|
||||
│ Permission to use, copy, modify, and/or distribute this software for │
|
||||
│ any purpose with or without fee is hereby granted, provided that the │
|
||||
│ above copyright notice and this permission notice appear in all copies. │
|
||||
│ │
|
||||
│ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL │
|
||||
│ WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED │
|
||||
│ WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE │
|
||||
│ AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL │
|
||||
│ DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR │
|
||||
│ PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER │
|
||||
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "tool/build/lib/divmul.h"
|
||||
#include "libc/calls/struct/sigaction.h"
|
||||
#include "libc/macros.internal.h"
|
||||
#include "libc/runtime/runtime.h"
|
||||
#include "libc/str/str.h"
|
||||
#include "libc/sysv/consts/sa.h"
|
||||
#include "libc/sysv/consts/sig.h"
|
||||
#include "libc/testlib/testlib.h"
|
||||
#include "libc/x/xsigaction.h"
|
||||
#include "third_party/xed/x86.h"
|
||||
#include "tool/build/lib/endian.h"
|
||||
#include "tool/build/lib/flags.h"
|
||||
#include "tool/build/lib/machine.h"
|
||||
#ifdef __x86_64__
|
||||
|
||||
#define CX 1
|
||||
#define OSZ 00000000040
|
||||
#define REXW 00000000100
|
||||
#define RM(x) (0000001600 & ((x) << 007))
|
||||
#define MOD(x) (0060000000 & ((x) << 026))
|
||||
|
||||
jmp_buf sigfpejmp;
|
||||
struct Machine m[1];
|
||||
struct sigaction oldsigfpe[1];
|
||||
struct XedDecodedInst xedd[1];
|
||||
|
||||
void OnSigFpe(void) {
|
||||
/* ProTip: gdb -ex 'handle SIGFPE nostop noprint pass' */
|
||||
longjmp(sigfpejmp, 1);
|
||||
}
|
||||
|
||||
void SetUp(void) {
|
||||
m->xedd = xedd;
|
||||
ASSERT_NE(-1, xsigaction(SIGFPE, OnSigFpe, SA_NODEFER, 0, oldsigfpe));
|
||||
}
|
||||
|
||||
void TearDown(void) {
|
||||
m->xedd = xedd;
|
||||
ASSERT_NE(-1, sigaction(SIGFPE, oldsigfpe, NULL));
|
||||
}
|
||||
|
||||
TEST(imul8, test) {
|
||||
static const uint8_t A[] = {0x00, 0x01, 0x80, 0x7F, 0x81, 0x7E, 0xFF, 0xBF};
|
||||
int i, j;
|
||||
int16_t ax;
|
||||
bool cf, of;
|
||||
for (i = 0; i < ARRAYLEN(A); ++i) {
|
||||
for (j = 0; j < ARRAYLEN(A); ++j) {
|
||||
Write8(m->ax, A[i]);
|
||||
Write8(m->cx, A[j]);
|
||||
OpMulAxAlEbSigned(m, MOD(3) | RM(CX));
|
||||
asm volatile("imulb\t%3"
|
||||
: "=a"(ax), "=@ccc"(cf), "=@cco"(of)
|
||||
: "q"(A[j]), "0"(A[i])
|
||||
: "cc");
|
||||
EXPECT_EQ(ax, (int16_t)Read16(m->ax));
|
||||
EXPECT_EQ(cf, GetFlag(m->flags, FLAGS_CF));
|
||||
EXPECT_EQ(of, GetFlag(m->flags, FLAGS_OF));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
TEST(imul16, test) {
|
||||
static const uint16_t A[] = {0x0000, 0x0001, 0x8000, 0x7FFF, 0x8001, 0x7FFE,
|
||||
0xFFFF, 0xBeef, 0x00b5, 0x00b6, 0xb504, 0xb505};
|
||||
int i, j;
|
||||
bool cf, of;
|
||||
uint16_t dx, ax;
|
||||
for (i = 0; i < ARRAYLEN(A); ++i) {
|
||||
for (j = 0; j < ARRAYLEN(A); ++j) {
|
||||
Write16(m->ax, A[i]);
|
||||
Write16(m->cx, A[j]);
|
||||
OpMulRdxRaxEvqpSigned(m, OSZ | MOD(3) | RM(CX));
|
||||
asm("imulw\t%4"
|
||||
: "=d"(dx), "=a"(ax), "=@ccc"(cf), "=@cco"(of)
|
||||
: "r"(A[j]), "1"(A[i])
|
||||
: "cc");
|
||||
EXPECT_EQ((int32_t)((uint32_t)dx << 16 | ax),
|
||||
(int32_t)((uint32_t)Read16(m->dx) << 16 | Read16(m->ax)));
|
||||
EXPECT_EQ(cf, GetFlag(m->flags, FLAGS_CF));
|
||||
EXPECT_EQ(of, GetFlag(m->flags, FLAGS_OF));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
TEST(imul32, test) {
|
||||
static const uint32_t A[] = {0x00000000, 0x00000001, 0x80000000, 0x7FFFFFFF,
|
||||
0x80000001, 0x7FFFFFFE, 0xFFFFFFFF, 0xDeadBeef,
|
||||
0x000000b6, 0x0000b504, 0x0000b505, 0xb504f334};
|
||||
int i, j;
|
||||
bool cf, of;
|
||||
uint32_t dx, ax;
|
||||
for (i = 0; i < ARRAYLEN(A); ++i) {
|
||||
for (j = 0; j < ARRAYLEN(A); ++j) {
|
||||
Write32(m->ax, A[i]);
|
||||
Write32(m->cx, A[j]);
|
||||
OpMulRdxRaxEvqpSigned(m, MOD(3) | RM(CX));
|
||||
asm("imull\t%4"
|
||||
: "=d"(dx), "=a"(ax), "=@ccc"(cf), "=@cco"(of)
|
||||
: "r"(A[j]), "1"(A[i])
|
||||
: "cc");
|
||||
EXPECT_EQ((int64_t)((uint64_t)dx << 32 | ax),
|
||||
(int64_t)((uint64_t)Read32(m->dx) << 32 | Read32(m->ax)));
|
||||
EXPECT_EQ(cf, GetFlag(m->flags, FLAGS_CF));
|
||||
EXPECT_EQ(of, GetFlag(m->flags, FLAGS_OF));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
TEST(imul64, test) {
|
||||
static const uint64_t A[] = {0x00000000, 0x00000001, 0x80000000, 0x7FFFFFFF,
|
||||
0x80000001, 0x7FFFFFFE, 0xFFFFFFFF, 0xDeadBeef,
|
||||
0x000000b6, 0x0000b504, 0x0000b505, 0xb504f334};
|
||||
int i, j;
|
||||
bool cf, of;
|
||||
uint64_t dx, ax;
|
||||
for (i = 0; i < ARRAYLEN(A); ++i) {
|
||||
for (j = 0; j < ARRAYLEN(A); ++j) {
|
||||
Write64(m->ax, A[i]);
|
||||
Write64(m->cx, A[j]);
|
||||
OpMulRdxRaxEvqpSigned(m, REXW | MOD(3) | RM(CX));
|
||||
asm("imulq\t%4"
|
||||
: "=d"(dx), "=a"(ax), "=@ccc"(cf), "=@cco"(of)
|
||||
: "r"(A[j]), "1"(A[i])
|
||||
: "cc");
|
||||
EXPECT_EQ((int128_t)((uint128_t)dx << 64 | ax),
|
||||
(int128_t)((uint128_t)Read64(m->dx) << 64 | Read64(m->ax)));
|
||||
EXPECT_EQ(cf, GetFlag(m->flags, FLAGS_CF));
|
||||
EXPECT_EQ(of, GetFlag(m->flags, FLAGS_OF));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
TEST(mul8, test) {
|
||||
static const uint8_t A[] = {0x00, 0x01, 0x80, 0x7F, 0x81, 0x7E, 0xFF, 0xb6};
|
||||
int i, j;
|
||||
uint16_t ax;
|
||||
bool cf, of;
|
||||
for (i = 0; i < ARRAYLEN(A); ++i) {
|
||||
for (j = 0; j < ARRAYLEN(A); ++j) {
|
||||
Write8(m->ax, A[i]);
|
||||
Write8(m->cx, A[j]);
|
||||
OpMulAxAlEbUnsigned(m, MOD(3) | RM(CX));
|
||||
asm volatile("mulb\t%3"
|
||||
: "=a"(ax), "=@ccc"(cf), "=@cco"(of)
|
||||
: "q"(A[j]), "0"(A[i])
|
||||
: "cc");
|
||||
EXPECT_EQ(ax, Read16(m->ax));
|
||||
EXPECT_EQ(cf, GetFlag(m->flags, FLAGS_CF));
|
||||
EXPECT_EQ(of, GetFlag(m->flags, FLAGS_OF));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
TEST(mul16, test) {
|
||||
static const uint16_t A[] = {0x0000, 0x0001, 0x8000, 0x7FFF,
|
||||
0x8001, 0x7FFE, 0xFFFF, 0x00b6};
|
||||
int i, j;
|
||||
bool cf, of;
|
||||
uint16_t dx, ax;
|
||||
for (i = 0; i < ARRAYLEN(A); ++i) {
|
||||
for (j = 0; j < ARRAYLEN(A); ++j) {
|
||||
Write16(m->ax, A[i]);
|
||||
Write16(m->cx, A[j]);
|
||||
OpMulRdxRaxEvqpUnsigned(m, OSZ | MOD(3) | RM(CX));
|
||||
asm("mulw\t%4"
|
||||
: "=d"(dx), "=a"(ax), "=@ccc"(cf), "=@cco"(of)
|
||||
: "r"(A[j]), "1"(A[i])
|
||||
: "cc");
|
||||
EXPECT_EQ((uint32_t)((uint32_t)dx << 16 | ax),
|
||||
(uint32_t)((uint32_t)Read16(m->dx) << 16 | Read16(m->ax)));
|
||||
EXPECT_EQ(cf, GetFlag(m->flags, FLAGS_CF));
|
||||
EXPECT_EQ(of, GetFlag(m->flags, FLAGS_OF));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
TEST(mul32, test) {
|
||||
static const uint32_t A[] = {0x00000000, 0x00000001, 0x80000000, 0x7FFFFFFF,
|
||||
0x80000001, 0x7FFFFFFE, 0xFFFFFFFF, 0x000000b5,
|
||||
0x000000b6, 0x0000b504, 0x0000b505, 0xb504f334};
|
||||
int i, j;
|
||||
bool cf, of;
|
||||
uint32_t dx, ax;
|
||||
for (i = 0; i < ARRAYLEN(A); ++i) {
|
||||
for (j = 0; j < ARRAYLEN(A); ++j) {
|
||||
Write32(m->ax, A[i]);
|
||||
Write32(m->cx, A[j]);
|
||||
OpMulRdxRaxEvqpUnsigned(m, MOD(3) | RM(CX));
|
||||
asm("mull\t%4"
|
||||
: "=d"(dx), "=a"(ax), "=@ccc"(cf), "=@cco"(of)
|
||||
: "r"(A[j]), "1"(A[i])
|
||||
: "cc");
|
||||
EXPECT_EQ((uint64_t)((uint64_t)dx << 32 | ax),
|
||||
(uint64_t)((uint64_t)Read32(m->dx) << 32 | Read32(m->ax)));
|
||||
EXPECT_EQ(cf, GetFlag(m->flags, FLAGS_CF));
|
||||
EXPECT_EQ(of, GetFlag(m->flags, FLAGS_OF));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
TEST(mul64, test) {
|
||||
static const uint64_t A[] = {0x00000000, 0x00000001, 0x80000000, 0x7FFFFFFF,
|
||||
0x80000001, 0x7FFFFFFE, 0xFFFFFFFF, 0x000000b6,
|
||||
0x0000b504, 0x0000b505, 0xb504f333, 0xb504f334};
|
||||
int i, j;
|
||||
bool cf, of;
|
||||
uint64_t dx, ax;
|
||||
for (i = 0; i < ARRAYLEN(A); ++i) {
|
||||
for (j = 0; j < ARRAYLEN(A); ++j) {
|
||||
Write64(m->ax, A[i]);
|
||||
Write64(m->cx, A[j]);
|
||||
OpMulRdxRaxEvqpUnsigned(m, REXW | MOD(3) | RM(CX));
|
||||
asm("mulq\t%4"
|
||||
: "=d"(dx), "=a"(ax), "=@ccc"(cf), "=@cco"(of)
|
||||
: "r"(A[j]), "1"(A[i])
|
||||
: "cc");
|
||||
EXPECT_EQ((uint128_t)((uint128_t)dx << 64 | ax),
|
||||
(uint128_t)((uint128_t)Read64(m->dx) << 64 | Read64(m->ax)));
|
||||
EXPECT_EQ(cf, GetFlag(m->flags, FLAGS_CF));
|
||||
EXPECT_EQ(of, GetFlag(m->flags, FLAGS_OF));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
TEST(idiv8, test) {
|
||||
if (IsWindows()) return; /* TODO */
|
||||
static const uint8_t A[] = {0x00, 0x01, 0x80, 0x7F, 0x81, 0x7E, 0xFF, 0xBF};
|
||||
uint16_t remquo;
|
||||
bool gotthrow, gotsigfpe;
|
||||
int8_t i, j, k, w, x, a, b;
|
||||
int8_t quotient, remainder;
|
||||
for (i = 0; i < ARRAYLEN(A); ++i) {
|
||||
for (j = 0; j < ARRAYLEN(A); ++j) {
|
||||
for (k = 0; k < ARRAYLEN(A); ++k) {
|
||||
m->ax[1] = A[i];
|
||||
m->ax[0] = A[j];
|
||||
m->cx[0] = A[k];
|
||||
gotthrow = false;
|
||||
gotsigfpe = false;
|
||||
if (!setjmp(m->onhalt)) {
|
||||
OpDivAlAhAxEbSigned(m, MOD(3) | RM(CX));
|
||||
} else {
|
||||
gotthrow = true;
|
||||
}
|
||||
if (!setjmp(sigfpejmp)) {
|
||||
asm("idivb\t%1"
|
||||
: "=a"(remquo)
|
||||
: "q"(A[k]), "0"((int16_t)(A[i] << 8 | A[j]))
|
||||
: "cc");
|
||||
} else {
|
||||
gotsigfpe = true;
|
||||
}
|
||||
EXPECT_EQ(gotsigfpe, gotthrow);
|
||||
if (!gotsigfpe && !gotthrow) {
|
||||
quotient = (int8_t)remquo;
|
||||
remainder = (int8_t)(remquo >> 8);
|
||||
EXPECT_EQ(quotient, (int8_t)m->ax[0]);
|
||||
EXPECT_EQ(remainder, (int8_t)m->ax[1]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
TEST(idiv16, test) {
|
||||
if (IsWindows()) return; /* TODO */
|
||||
static const uint16_t A[] = {0x0000, 0x0001, 0x8000, 0x7FFF,
|
||||
0x8001, 0x7FFE, 0xFFFF, 0xBeef};
|
||||
bool gotthrow, gotsigfpe;
|
||||
int16_t i, j, k, w, x, a, b;
|
||||
int16_t quotient, remainder;
|
||||
for (i = 0; i < ARRAYLEN(A); ++i) {
|
||||
for (j = 0; j < ARRAYLEN(A); ++j) {
|
||||
for (k = 0; k < ARRAYLEN(A); ++k) {
|
||||
memcpy(m->dx, &A[i], 2);
|
||||
memcpy(m->ax, &A[j], 2);
|
||||
memcpy(m->cx, &A[k], 2);
|
||||
if (!setjmp(m->onhalt)) {
|
||||
gotthrow = false;
|
||||
OpDivRdxRaxEvqpSigned(m, OSZ | MOD(3) | RM(CX));
|
||||
} else {
|
||||
gotthrow = true;
|
||||
}
|
||||
if (!setjmp(sigfpejmp)) {
|
||||
gotsigfpe = false;
|
||||
asm("idivw\t%2"
|
||||
: "=d"(remainder), "=a"(quotient)
|
||||
: "r"(A[k]), "0"(A[i]), "1"(A[j])
|
||||
: "cc");
|
||||
} else {
|
||||
gotsigfpe = true;
|
||||
}
|
||||
EXPECT_EQ(gotsigfpe, gotthrow);
|
||||
if (!gotsigfpe && !gotthrow) {
|
||||
EXPECT_EQ(quotient, (int16_t)Read16(m->ax));
|
||||
EXPECT_EQ(remainder, (int16_t)Read16(m->dx));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
TEST(idiv32, test) {
|
||||
if (IsWindows()) return; /* TODO */
|
||||
static const uint32_t A[] = {0x00000000, 0x00000001, 0x80000000, 0x7FFFFFFF,
|
||||
0x80000001, 0x7FFFFFFE, 0xFFFFFFFF, 0xDeadBeef};
|
||||
bool gotthrow, gotsigfpe;
|
||||
int32_t i, j, k, w, x, a, b;
|
||||
int32_t quotient, remainder;
|
||||
for (i = 0; i < ARRAYLEN(A); ++i) {
|
||||
for (j = 0; j < ARRAYLEN(A); ++j) {
|
||||
for (k = 0; k < ARRAYLEN(A); ++k) {
|
||||
memcpy(m->dx, &A[i], 4);
|
||||
memcpy(m->ax, &A[j], 4);
|
||||
memcpy(m->cx, &A[k], 4);
|
||||
if (!setjmp(m->onhalt)) {
|
||||
gotthrow = false;
|
||||
OpDivRdxRaxEvqpSigned(m, MOD(3) | RM(CX));
|
||||
} else {
|
||||
gotthrow = true;
|
||||
}
|
||||
if (!setjmp(sigfpejmp)) {
|
||||
gotsigfpe = false;
|
||||
asm("idivl\t%2"
|
||||
: "=d"(remainder), "=a"(quotient)
|
||||
: "r"(A[k]), "0"(A[i]), "1"(A[j])
|
||||
: "cc");
|
||||
} else {
|
||||
gotsigfpe = true;
|
||||
}
|
||||
EXPECT_EQ(gotsigfpe, gotthrow);
|
||||
if (!gotsigfpe && !gotthrow) {
|
||||
EXPECT_EQ(quotient, (int32_t)Read32(m->ax));
|
||||
EXPECT_EQ(remainder, (int32_t)Read32(m->dx));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
TEST(idiv64, test) {
|
||||
if (IsWindows()) return; /* TODO */
|
||||
static const uint64_t A[] = {0x0000000000000000, 0x0000000000000001,
|
||||
0x8000000000000000, 0x7FFFFFFFFFFFFFFF,
|
||||
0x8000000000000001, 0x7FFFFFFFFFFFFFFE,
|
||||
0xFFFFFFFFFFFFFFFF, 0x00DeadBeefCafe00};
|
||||
bool gotthrow, gotsigfpe;
|
||||
int64_t i, j, k, w, x, a, b;
|
||||
int64_t quotient, remainder;
|
||||
for (i = 0; i < ARRAYLEN(A); ++i) {
|
||||
for (j = 0; j < ARRAYLEN(A); ++j) {
|
||||
for (k = 0; k < ARRAYLEN(A); ++k) {
|
||||
memcpy(m->dx, &A[i], 8);
|
||||
memcpy(m->ax, &A[j], 8);
|
||||
memcpy(m->cx, &A[k], 8);
|
||||
if (!setjmp(m->onhalt)) {
|
||||
gotthrow = false;
|
||||
OpDivRdxRaxEvqpSigned(m, REXW | MOD(3) | RM(CX));
|
||||
} else {
|
||||
gotthrow = true;
|
||||
}
|
||||
if (!setjmp(sigfpejmp)) {
|
||||
gotsigfpe = false;
|
||||
asm("idivq\t%2"
|
||||
: "=d"(remainder), "=a"(quotient)
|
||||
: "r"(A[k]), "0"(A[i]), "1"(A[j])
|
||||
: "cc");
|
||||
} else {
|
||||
gotsigfpe = true;
|
||||
}
|
||||
EXPECT_EQ(gotsigfpe, gotthrow);
|
||||
if (!gotsigfpe && !gotthrow) {
|
||||
EXPECT_EQ(quotient, (int64_t)Read64(m->ax));
|
||||
EXPECT_EQ(remainder, (int64_t)Read64(m->dx));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
TEST(div, test) {
|
||||
if (IsWindows()) return; /* TODO */
|
||||
static const uint8_t A[] = {0x00, 0x01, 0x80, 0x7F, 0x81, 0x7E, 0xFF, 0xBF};
|
||||
uint16_t remquo;
|
||||
bool gotthrow, gotsigfpe;
|
||||
uint8_t i, j, k, w, x, a, b;
|
||||
uint8_t quotient, remainder;
|
||||
for (i = 0; i < ARRAYLEN(A); ++i) {
|
||||
for (j = 0; j < ARRAYLEN(A); ++j) {
|
||||
for (k = 0; k < ARRAYLEN(A); ++k) {
|
||||
m->ax[1] = A[i];
|
||||
m->ax[0] = A[j];
|
||||
m->cx[0] = A[k];
|
||||
gotthrow = false;
|
||||
gotsigfpe = false;
|
||||
if (!setjmp(m->onhalt)) {
|
||||
OpDivAlAhAxEbUnsigned(m, MOD(3) | RM(CX));
|
||||
} else {
|
||||
gotthrow = true;
|
||||
}
|
||||
if (!setjmp(sigfpejmp)) {
|
||||
asm("divb\t%1"
|
||||
: "=a"(remquo)
|
||||
: "q"(A[k]), "0"((uint16_t)(A[i] << 8 | A[j]))
|
||||
: "cc");
|
||||
} else {
|
||||
gotsigfpe = true;
|
||||
}
|
||||
EXPECT_EQ(gotsigfpe, gotthrow);
|
||||
if (!gotsigfpe && !gotthrow) {
|
||||
quotient = (uint8_t)remquo;
|
||||
remainder = (uint8_t)(remquo >> 8);
|
||||
EXPECT_EQ(quotient, (uint8_t)m->ax[0]);
|
||||
EXPECT_EQ(remainder, (uint8_t)m->ax[1]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
TEST(div16, test) {
|
||||
if (IsWindows()) return; /* TODO */
|
||||
static const uint16_t A[] = {0x0000, 0x0001, 0x8000, 0x7FFF,
|
||||
0x8001, 0x7FFE, 0xFFFF, 0xBeef};
|
||||
bool gotthrow, gotsigfpe;
|
||||
uint16_t i, j, k, w, x, a, b;
|
||||
uint16_t quotient, remainder;
|
||||
for (i = 0; i < ARRAYLEN(A); ++i) {
|
||||
for (j = 0; j < ARRAYLEN(A); ++j) {
|
||||
for (k = 0; k < ARRAYLEN(A); ++k) {
|
||||
memcpy(m->dx, &A[i], 2);
|
||||
memcpy(m->ax, &A[j], 2);
|
||||
memcpy(m->cx, &A[k], 2);
|
||||
if (!setjmp(m->onhalt)) {
|
||||
gotthrow = false;
|
||||
OpDivRdxRaxEvqpUnsigned(m, OSZ | MOD(3) | RM(CX));
|
||||
} else {
|
||||
gotthrow = true;
|
||||
}
|
||||
if (!setjmp(sigfpejmp)) {
|
||||
gotsigfpe = false;
|
||||
asm("divw\t%2"
|
||||
: "=d"(remainder), "=a"(quotient)
|
||||
: "r"(A[k]), "0"(A[i]), "1"(A[j])
|
||||
: "cc");
|
||||
} else {
|
||||
gotsigfpe = true;
|
||||
}
|
||||
EXPECT_EQ(gotsigfpe, gotthrow);
|
||||
if (!gotsigfpe && !gotthrow) {
|
||||
EXPECT_EQ(quotient, (uint16_t)Read16(m->ax));
|
||||
EXPECT_EQ(remainder, (uint16_t)Read16(m->dx));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
TEST(div32, test) {
|
||||
if (IsWindows()) return; /* TODO */
|
||||
static const uint32_t A[] = {0x00000000, 0x00000001, 0x80000000, 0x7FFFFFFF,
|
||||
0x80000001, 0x7FFFFFFE, 0xFFFFFFFF, 0xDeadBeef};
|
||||
bool gotthrow, gotsigfpe;
|
||||
uint32_t i, j, k, w, x, a, b;
|
||||
uint32_t quotient, remainder;
|
||||
for (i = 0; i < ARRAYLEN(A); ++i) {
|
||||
for (j = 0; j < ARRAYLEN(A); ++j) {
|
||||
for (k = 0; k < ARRAYLEN(A); ++k) {
|
||||
memcpy(m->dx, &A[i], 4);
|
||||
memcpy(m->ax, &A[j], 4);
|
||||
memcpy(m->cx, &A[k], 4);
|
||||
if (!setjmp(m->onhalt)) {
|
||||
gotthrow = false;
|
||||
OpDivRdxRaxEvqpUnsigned(m, MOD(3) | RM(CX));
|
||||
} else {
|
||||
gotthrow = true;
|
||||
}
|
||||
if (!setjmp(sigfpejmp)) {
|
||||
gotsigfpe = false;
|
||||
asm("divl\t%2"
|
||||
: "=d"(remainder), "=a"(quotient)
|
||||
: "r"(A[k]), "0"(A[i]), "1"(A[j])
|
||||
: "cc");
|
||||
} else {
|
||||
gotsigfpe = true;
|
||||
}
|
||||
EXPECT_EQ(gotsigfpe, gotthrow);
|
||||
if (!gotsigfpe && !gotthrow) {
|
||||
EXPECT_EQ(quotient, (uint32_t)Read32(m->ax));
|
||||
EXPECT_EQ(remainder, (uint32_t)Read32(m->dx));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
TEST(div64, test) {
|
||||
if (IsWindows()) return; /* TODO */
|
||||
static const uint64_t A[] = {0x0000000000000000, 0x0000000000000001,
|
||||
0x8000000000000000, 0x7FFFFFFFFFFFFFFF,
|
||||
0x8000000000000001, 0x7FFFFFFFFFFFFFFE,
|
||||
0xFFFFFFFFFFFFFFFF, 0x00DeadBeefCafe00};
|
||||
bool gotthrow, gotsigfpe;
|
||||
uint64_t i, j, k, w, x, a, b;
|
||||
uint64_t quotient, remainder;
|
||||
for (i = 0; i < ARRAYLEN(A); ++i) {
|
||||
for (j = 0; j < ARRAYLEN(A); ++j) {
|
||||
for (k = 0; k < ARRAYLEN(A); ++k) {
|
||||
memcpy(m->dx, &A[i], 8);
|
||||
memcpy(m->ax, &A[j], 8);
|
||||
memcpy(m->cx, &A[k], 8);
|
||||
if (!setjmp(m->onhalt)) {
|
||||
gotthrow = false;
|
||||
OpDivRdxRaxEvqpUnsigned(m, REXW | MOD(3) | RM(CX));
|
||||
} else {
|
||||
gotthrow = true;
|
||||
}
|
||||
if (!setjmp(sigfpejmp)) {
|
||||
gotsigfpe = false;
|
||||
asm("divq\t%2"
|
||||
: "=d"(remainder), "=a"(quotient)
|
||||
: "r"(A[k]), "0"(A[i]), "1"(A[j])
|
||||
: "cc");
|
||||
} else {
|
||||
gotsigfpe = true;
|
||||
}
|
||||
EXPECT_EQ(gotsigfpe, gotthrow);
|
||||
if (!gotsigfpe && !gotthrow) {
|
||||
EXPECT_EQ(quotient, (uint64_t)Read64(m->ax));
|
||||
EXPECT_EQ(remainder, (uint64_t)Read64(m->dx));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif /* __x86_64__ */
|
|
@ -1,84 +0,0 @@
|
|||
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
|
||||
│vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi│
|
||||
╞══════════════════════════════════════════════════════════════════════════════╡
|
||||
│ Copyright 2020 Justine Alexandra Roberts Tunney │
|
||||
│ │
|
||||
│ Permission to use, copy, modify, and/or distribute this software for │
|
||||
│ any purpose with or without fee is hereby granted, provided that the │
|
||||
│ above copyright notice and this permission notice appear in all copies. │
|
||||
│ │
|
||||
│ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL │
|
||||
│ WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED │
|
||||
│ WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE │
|
||||
│ AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL │
|
||||
│ DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR │
|
||||
│ PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER │
|
||||
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/testlib/testlib.h"
|
||||
#include "tool/build/lib/iovs.h"
|
||||
|
||||
TEST(iovs, testEmpty) {
|
||||
struct Iovs iv;
|
||||
InitIovs(&iv);
|
||||
EXPECT_EQ(0, iv.i);
|
||||
EXPECT_GE(iv.n, iv.i);
|
||||
FreeIovs(&iv);
|
||||
}
|
||||
|
||||
TEST(iovs, testAppendEmptyString_wontCreateEmptyEntries) {
|
||||
struct Iovs iv;
|
||||
InitIovs(&iv);
|
||||
EXPECT_NE(-1, AppendIovs(&iv, "", 0));
|
||||
EXPECT_NE(-1, AppendIovs(&iv, NULL, 0));
|
||||
EXPECT_EQ(0, iv.i);
|
||||
EXPECT_GE(iv.n, iv.i);
|
||||
FreeIovs(&iv);
|
||||
}
|
||||
|
||||
TEST(iovs, testAppendContiguousVectors_coalescesAdjacentEntries) {
|
||||
struct Iovs iv;
|
||||
char buf[8], *b = buf;
|
||||
InitIovs(&iv);
|
||||
EXPECT_NE(-1, AppendIovs(&iv, b + 0, 4));
|
||||
EXPECT_NE(-1, AppendIovs(&iv, b + 4, 4));
|
||||
EXPECT_EQ(1, iv.i);
|
||||
EXPECT_GE(iv.n, iv.i);
|
||||
EXPECT_EQ(8, iv.p[0].iov_len);
|
||||
EXPECT_EQ(b, iv.p[0].iov_base);
|
||||
FreeIovs(&iv);
|
||||
}
|
||||
|
||||
TEST(iovs, testAppendNoncontiguousVectors_growsMemoryAndPreservesOrdering) {
|
||||
struct Iovs iv;
|
||||
char buf[8], *b = buf;
|
||||
InitIovs(&iv);
|
||||
EXPECT_NE(-1, AppendIovs(&iv, b + 0, 1));
|
||||
EXPECT_NE(-1, AppendIovs(&iv, b + 2, 1));
|
||||
EXPECT_NE(-1, AppendIovs(&iv, b + 4, 1));
|
||||
EXPECT_NE(-1, AppendIovs(&iv, b + 6, 1));
|
||||
EXPECT_NE(-1, AppendIovs(&iv, b + 1, 1));
|
||||
EXPECT_NE(-1, AppendIovs(&iv, b + 3, 1));
|
||||
EXPECT_NE(-1, AppendIovs(&iv, b + 5, 1));
|
||||
EXPECT_NE(-1, AppendIovs(&iv, b + 7, 1));
|
||||
EXPECT_EQ(8, iv.i);
|
||||
EXPECT_GE(iv.n, iv.i);
|
||||
EXPECT_EQ(b + 0, iv.p[0].iov_base);
|
||||
EXPECT_EQ(1, iv.p[0].iov_len);
|
||||
EXPECT_EQ(b + 2, iv.p[1].iov_base);
|
||||
EXPECT_EQ(1, iv.p[1].iov_len);
|
||||
EXPECT_EQ(b + 4, iv.p[2].iov_base);
|
||||
EXPECT_EQ(1, iv.p[2].iov_len);
|
||||
EXPECT_EQ(b + 6, iv.p[3].iov_base);
|
||||
EXPECT_EQ(1, iv.p[3].iov_len);
|
||||
EXPECT_EQ(b + 1, iv.p[4].iov_base);
|
||||
EXPECT_EQ(1, iv.p[4].iov_len);
|
||||
EXPECT_EQ(b + 3, iv.p[5].iov_base);
|
||||
EXPECT_EQ(1, iv.p[5].iov_len);
|
||||
EXPECT_EQ(b + 5, iv.p[6].iov_base);
|
||||
EXPECT_EQ(1, iv.p[6].iov_len);
|
||||
EXPECT_EQ(b + 7, iv.p[7].iov_base);
|
||||
EXPECT_EQ(1, iv.p[7].iov_len);
|
||||
FreeIovs(&iv);
|
||||
}
|
|
@ -1,348 +0,0 @@
|
|||
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
|
||||
│vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi│
|
||||
╞══════════════════════════════════════════════════════════════════════════════╡
|
||||
│ Copyright 2020 Justine Alexandra Roberts Tunney │
|
||||
│ │
|
||||
│ Permission to use, copy, modify, and/or distribute this software for │
|
||||
│ any purpose with or without fee is hereby granted, provided that the │
|
||||
│ above copyright notice and this permission notice appear in all copies. │
|
||||
│ │
|
||||
│ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL │
|
||||
│ WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED │
|
||||
│ WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE │
|
||||
│ AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL │
|
||||
│ DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR │
|
||||
│ PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER │
|
||||
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/fmt/bing.internal.h"
|
||||
#include "libc/math.h"
|
||||
#include "libc/mem/mem.h"
|
||||
#include "libc/mem/gc.internal.h"
|
||||
#include "libc/stdio/stdio.h"
|
||||
#include "libc/testlib/ezbench.h"
|
||||
#include "libc/testlib/testlib.h"
|
||||
#include "libc/x/x.h"
|
||||
#include "tool/build/lib/endian.h"
|
||||
#include "tool/build/lib/fpu.h"
|
||||
#include "tool/build/lib/machine.h"
|
||||
#include "tool/build/lib/memory.h"
|
||||
|
||||
const uint8_t kPi80[] = {
|
||||
0xd9, 0xe8, // fld1
|
||||
0xb8, 0x0a, 0x00, 0x00, 0x00, // mov $0xa,%eax
|
||||
0x31, 0xd2, // xor %edx,%edx
|
||||
0xd9, 0xee, // fldz
|
||||
0x48, 0x98, // cltq
|
||||
0x48, 0x39, 0xc2, // cmp %rax,%rdx
|
||||
0xd9, 0x05, 0x1a, 0x00, 0x00, 0x00, // flds 0x1a(%rip)
|
||||
0x7d, 0x13, // jge 2b <pi80+0x2b>
|
||||
0xde, 0xc1, // faddp
|
||||
0x48, 0xff, 0xc2, // inc %rdx
|
||||
0xd9, 0xfa, // fsqrt
|
||||
0xd9, 0x05, 0x0f, 0x00, 0x00, 0x00, // flds 15(%rip)
|
||||
0xd8, 0xc9, // fmul %st(1),%st
|
||||
0xde, 0xca, // fmulp %st,%st(2)
|
||||
0xeb, 0xe2, // jmp d <pi80+0xd>
|
||||
0xdd, 0xd9, // fstp %st(1)
|
||||
0xde, 0xf1, // fdivp
|
||||
0xf4, // hlt
|
||||
0x00, 0x00, 0x00, 0x40, // .float 2.0
|
||||
0x00, 0x00, 0x00, 0x3f, // .float 0.5
|
||||
};
|
||||
|
||||
const uint8_t kTenthprime[] = {
|
||||
0x31, 0xd2, // xor %edx,%edx
|
||||
0x45, 0x31, 0xc0, // xor %r8d,%r8d
|
||||
0x31, 0xc9, // xor %ecx,%ecx
|
||||
0xbe, 0x03, 0x00, 0x00, 0x00, // mov $0x3,%esi
|
||||
0x41, 0xff, 0xc0, // inc %r8d
|
||||
0x44, 0x89, 0xc0, // mov %r8d,%eax
|
||||
0x83, 0xf9, 0x0a, // cmp $0xa,%ecx
|
||||
0x74, 0x0b, // je 20
|
||||
0x99, // cltd
|
||||
0xf7, 0xfe, // idiv %esi
|
||||
0x83, 0xfa, 0x01, // cmp $0x1,%edx
|
||||
0x83, 0xd9, 0xff, // sbb $-1,%ecx
|
||||
0xeb, 0xea, // jmp a
|
||||
0xf4, // hlt
|
||||
};
|
||||
|
||||
const uint8_t kTenthprime2[] = {
|
||||
0xE8, 0x11, 0x00, 0x00, 0x00, //
|
||||
0xF4, //
|
||||
0x89, 0xF8, //
|
||||
0xB9, 0x03, 0x00, 0x00, 0x00, //
|
||||
0x99, //
|
||||
0xF7, 0xF9, //
|
||||
0x85, 0xD2, //
|
||||
0x0F, 0x95, 0xC0, //
|
||||
0xC3, //
|
||||
0x55, //
|
||||
0x48, 0x89, 0xE5, //
|
||||
0x31, 0xF6, //
|
||||
0x45, 0x31, 0xC0, //
|
||||
0x44, 0x89, 0xC7, //
|
||||
0xE8, 0xDF, 0xFF, 0xFF, 0xFF, //
|
||||
0x0F, 0xB6, 0xC0, //
|
||||
0x66, 0x83, 0xF8, 0x01, //
|
||||
0x83, 0xDE, 0xFF, //
|
||||
0x41, 0xFF, 0xC0, //
|
||||
0x83, 0xFE, 0x0A, //
|
||||
0x75, 0xE6, //
|
||||
0x44, 0x89, 0xC0, //
|
||||
0x5D, //
|
||||
0xC3, //
|
||||
};
|
||||
|
||||
struct Machine *m;
|
||||
|
||||
void SetUp(void) {
|
||||
m = NewMachine();
|
||||
m->mode = XED_MACHINE_MODE_LONG_64;
|
||||
m->cr3 = AllocateLinearPage(m);
|
||||
ReserveVirtual(m, 0, 4096, 0x0207);
|
||||
ASSERT_EQ(0x1007, Read64(m->real.p + 0x0000)); // PML4T
|
||||
ASSERT_EQ(0x2007, Read64(m->real.p + 0x1000)); // PDPT
|
||||
ASSERT_EQ(0x3007, Read64(m->real.p + 0x2000)); // PDE
|
||||
ASSERT_EQ(0x0207, Read64(m->real.p + 0x3000)); // PT
|
||||
ASSERT_EQ(0x4000, m->real.i);
|
||||
ASSERT_EQ(1, m->memstat.reserved);
|
||||
ASSERT_EQ(4, m->memstat.committed);
|
||||
ASSERT_EQ(4, m->memstat.allocated);
|
||||
ASSERT_EQ(3, m->memstat.pagetables);
|
||||
Write64(m->sp, 4096);
|
||||
}
|
||||
|
||||
void TearDown(void) {
|
||||
FreeVirtual(m, 0, 4096);
|
||||
ASSERT_EQ(0x1007, Read64(m->real.p + 0x0000)); // PML4T
|
||||
ASSERT_EQ(0x2007, Read64(m->real.p + 0x1000)); // PDPT
|
||||
ASSERT_EQ(0x3007, Read64(m->real.p + 0x2000)); // PDE
|
||||
ASSERT_EQ(0x0000, Read64(m->real.p + 0x3000)); // PT
|
||||
FreeMachine(m);
|
||||
}
|
||||
|
||||
int ExecuteUntilHalt(struct Machine *m) {
|
||||
int rc;
|
||||
if (!(rc = setjmp(m->onhalt))) {
|
||||
for (;;) {
|
||||
LoadInstruction(m);
|
||||
ExecuteInstruction(m);
|
||||
}
|
||||
} else {
|
||||
return rc;
|
||||
}
|
||||
}
|
||||
|
||||
TEST(machine, test) {
|
||||
VirtualRecv(m, 0, kTenthprime, sizeof(kTenthprime));
|
||||
ASSERT_EQ(kMachineHalt, ExecuteUntilHalt(m));
|
||||
ASSERT_EQ(15, Read32(m->ax));
|
||||
}
|
||||
|
||||
TEST(machine, testFpu) {
|
||||
VirtualRecv(m, 0, kPi80, sizeof(kPi80));
|
||||
ASSERT_EQ(kMachineHalt, ExecuteUntilHalt(m));
|
||||
ASSERT_TRUE(fabsl(3.14159 - FpuPop(m)) < 0.0001);
|
||||
m->ip = 0;
|
||||
ASSERT_EQ(kMachineHalt, ExecuteUntilHalt(m));
|
||||
ASSERT_TRUE(fabsl(3.14159 - FpuPop(m)) < 0.0001);
|
||||
}
|
||||
|
||||
BENCH(machine, benchPrimeNumberPrograms) {
|
||||
VirtualRecv(m, 0, kTenthprime2, sizeof(kTenthprime2));
|
||||
EZBENCH2("tenthprime2", m->ip = 0, ExecuteUntilHalt(m));
|
||||
ASSERT_EQ(15, Read32(m->ax));
|
||||
VirtualRecv(m, 0, kTenthprime, sizeof(kTenthprime));
|
||||
EZBENCH2("tenthprime", m->ip = 0, ExecuteUntilHalt(m));
|
||||
ASSERT_EQ(15, Read32(m->ax));
|
||||
}
|
||||
|
||||
static void machine_benchFpu_fn(void) {
|
||||
ExecuteUntilHalt(m);
|
||||
FpuPop(m);
|
||||
}
|
||||
|
||||
BENCH(machine, benchFpu) {
|
||||
VirtualRecv(m, 0, kPi80, sizeof(kPi80));
|
||||
EZBENCH2("pi80", m->ip = 0, machine_benchFpu_fn());
|
||||
}
|
||||
|
||||
BENCH(machine, benchLoadExec2) {
|
||||
uint8_t kMovCode[] = {0xbe, 0x03, 0x00, 0x00, 0x00};
|
||||
VirtualRecv(m, 0, kMovCode, sizeof(kMovCode));
|
||||
LoadInstruction(m);
|
||||
EZBENCH2("mov", m->ip = 0, ExecuteInstruction(m));
|
||||
}
|
||||
|
||||
BENCH(machine, benchLoadExec3) {
|
||||
uint8_t kMovdCode[] = {0x66, 0x0f, 0x6e, 0xc0};
|
||||
Write64(m->ax, 0);
|
||||
VirtualRecv(m, 0, kMovdCode, sizeof(kMovdCode));
|
||||
LoadInstruction(m);
|
||||
EZBENCH2("movd", m->ip = 0, ExecuteInstruction(m));
|
||||
}
|
||||
|
||||
BENCH(machine, benchLoadExec4) {
|
||||
uint8_t kAddpsRegregCode[] = {0x0f, 0x58, 0xC0};
|
||||
uint8_t kAddpsMemregCode[] = {0x0f, 0x58, 0x00};
|
||||
Write64(m->ax, 0);
|
||||
VirtualRecv(m, 0, kAddpsRegregCode, sizeof(kAddpsRegregCode));
|
||||
LoadInstruction(m);
|
||||
EZBENCH2("addps reg reg", m->ip = 0, ExecuteInstruction(m));
|
||||
VirtualRecv(m, 0, kAddpsMemregCode, sizeof(kAddpsMemregCode));
|
||||
LoadInstruction(m);
|
||||
EZBENCH2("addps mem reg", m->ip = 0, ExecuteInstruction(m));
|
||||
}
|
||||
|
||||
BENCH(machine, benchLoadExec5) {
|
||||
uint8_t kPaddwRegregCode[] = {0x66, 0x0F, 0xFD, 0xC0};
|
||||
uint8_t kPaddwMemregCode[] = {0x66, 0x0F, 0xFD, 0x00};
|
||||
Write64(m->ax, 0);
|
||||
VirtualRecv(m, 0, kPaddwRegregCode, sizeof(kPaddwRegregCode));
|
||||
LoadInstruction(m);
|
||||
EZBENCH2("paddw", m->ip = 0, ExecuteInstruction(m));
|
||||
VirtualRecv(m, 0, kPaddwMemregCode, sizeof(kPaddwMemregCode));
|
||||
LoadInstruction(m);
|
||||
EZBENCH2("paddw mem", m->ip = 0, ExecuteInstruction(m));
|
||||
}
|
||||
|
||||
BENCH(machine, benchLoadExec6) {
|
||||
uint8_t kPsubqRegregCode[] = {0x66, 0x0F, 0xFB, 0xC0};
|
||||
uint8_t kPsubqMemregCode[] = {0x66, 0x0F, 0xFB, 0x00};
|
||||
Write64(m->ax, 0);
|
||||
VirtualRecv(m, 0, kPsubqRegregCode, sizeof(kPsubqRegregCode));
|
||||
LoadInstruction(m);
|
||||
EZBENCH2("psubq", m->ip = 0, ExecuteInstruction(m));
|
||||
VirtualRecv(m, 0, kPsubqMemregCode, sizeof(kPsubqMemregCode));
|
||||
LoadInstruction(m);
|
||||
EZBENCH2("psubq mem", m->ip = 0, ExecuteInstruction(m));
|
||||
}
|
||||
|
||||
BENCH(machine, benchAddqMem) {
|
||||
uint8_t kAddMemregCode[] = {0x48, 0x03, 0x08};
|
||||
Write64(m->ax, 0);
|
||||
VirtualRecv(m, 0, kAddMemregCode, sizeof(kAddMemregCode));
|
||||
LoadInstruction(m);
|
||||
EZBENCH2("addq mem", m->ip = 0, ExecuteInstruction(m));
|
||||
}
|
||||
|
||||
BENCH(machine, benchAddlMem) {
|
||||
uint8_t kAddMemregCode[] = {0x03, 0x08};
|
||||
Write64(m->ax, 0);
|
||||
VirtualRecv(m, 0, kAddMemregCode, sizeof(kAddMemregCode));
|
||||
LoadInstruction(m);
|
||||
EZBENCH2("addl mem", m->ip = 0, ExecuteInstruction(m));
|
||||
}
|
||||
|
||||
BENCH(machine, benchAddq) {
|
||||
uint8_t kAddqCode[] = {0x48, 0x01, 0xd8};
|
||||
Write64(m->ax, 0);
|
||||
VirtualRecv(m, 0, kAddqCode, sizeof(kAddqCode));
|
||||
LoadInstruction(m);
|
||||
EZBENCH2("addq", m->ip = 0, ExecuteInstruction(m));
|
||||
}
|
||||
|
||||
BENCH(machine, benchAddb) {
|
||||
uint8_t kAddbCode[] = {0x00, 0xd8};
|
||||
Write64(m->ax, 0);
|
||||
VirtualRecv(m, 0, kAddbCode, sizeof(kAddbCode));
|
||||
LoadInstruction(m);
|
||||
EZBENCH2("addb", m->ip = 0, ExecuteInstruction(m));
|
||||
}
|
||||
|
||||
BENCH(machine, benchXorReg) {
|
||||
VirtualRecv(m, 0, kTenthprime, sizeof(kTenthprime));
|
||||
LoadInstruction(m);
|
||||
EZBENCH2("xor", m->ip = 0, ExecuteInstruction(m));
|
||||
}
|
||||
|
||||
BENCH(machine, benchLoadExec8) {
|
||||
uint8_t kFchsCode[] = {0xd9, 0xe0};
|
||||
Write64(m->ax, 0);
|
||||
OpFinit(m);
|
||||
*FpuSt(m, 0) = M_PI;
|
||||
FpuSetTag(m, 0, kFpuTagValid);
|
||||
VirtualRecv(m, 0, kFchsCode, sizeof(kFchsCode));
|
||||
LoadInstruction(m);
|
||||
EZBENCH2("fchs", m->ip = 0, ExecuteInstruction(m));
|
||||
}
|
||||
|
||||
static void machine_benchPushpop_fn(void) {
|
||||
LoadInstruction(m);
|
||||
ExecuteInstruction(m);
|
||||
LoadInstruction(m);
|
||||
ExecuteInstruction(m);
|
||||
}
|
||||
|
||||
BENCH(machine, benchPushpop) {
|
||||
uint8_t kPushpop[] = {0x50, 0x58};
|
||||
Write64(m->ax, 0);
|
||||
VirtualRecv(m, 0, kPushpop, sizeof(kPushpop));
|
||||
EZBENCH2("pushpop", m->ip = 0, machine_benchPushpop_fn());
|
||||
}
|
||||
|
||||
BENCH(machine, benchPause) {
|
||||
uint8_t kPause[] = {0xf3, 0x90};
|
||||
Write64(m->ax, 0);
|
||||
VirtualRecv(m, 0, kPause, sizeof(kPause));
|
||||
LoadInstruction(m);
|
||||
EZBENCH2("pause", m->ip = 0, ExecuteInstruction(m));
|
||||
}
|
||||
|
||||
BENCH(machine, benchClc) {
|
||||
uint8_t kClc[] = {0xf8};
|
||||
Write64(m->ax, 0);
|
||||
VirtualRecv(m, 0, kClc, sizeof(kClc));
|
||||
LoadInstruction(m);
|
||||
EZBENCH2("clc", m->ip = 0, ExecuteInstruction(m));
|
||||
}
|
||||
|
||||
static void machine_benchNop_fn(void) {
|
||||
LoadInstruction(m);
|
||||
ExecuteInstruction(m);
|
||||
}
|
||||
|
||||
BENCH(machine, benchNop) {
|
||||
uint8_t kNop[] = {0x90};
|
||||
Write64(m->ax, 0);
|
||||
VirtualRecv(m, 0, kNop, sizeof(kNop));
|
||||
LoadInstruction(m);
|
||||
EZBENCH2("nop", m->ip = 0, ExecuteInstruction(m));
|
||||
EZBENCH2("nop w/ load", m->ip = 0, machine_benchNop_fn());
|
||||
}
|
||||
|
||||
TEST(x87, fprem1) {
|
||||
// 1 rem -1.5
|
||||
const uint8_t prog[] = {
|
||||
0xd9, 0x05, 0x05, 0x00, 0x00, 0x00, // flds
|
||||
0xd9, 0xe8, // fld1
|
||||
0xd9, 0xf8, // fprem
|
||||
0xf4, // hlt
|
||||
0x00, 0x00, 0xc0, 0xbf, // .float -1.5
|
||||
};
|
||||
VirtualRecv(m, 0, prog, sizeof(prog));
|
||||
ASSERT_EQ(kMachineHalt, ExecuteUntilHalt(m));
|
||||
ASSERT_LDBL_EQ(1, FpuPop(m));
|
||||
}
|
||||
|
||||
TEST(x87, fprem2) {
|
||||
// 12300000000000000. rem .0000000000000123
|
||||
const uint8_t prog[] = {
|
||||
0xdd, 0x05, 0x11, 0x00, 0x00, 0x00, // fldl
|
||||
0xdd, 0x05, 0x03, 0x00, 0x00, 0x00, // fldl
|
||||
0xd9, 0xf8, // fprem
|
||||
0xf4, // hlt
|
||||
0x00, 0x60, 0x5e, 0x75, 0x64, 0xd9, 0x45, 0x43, //
|
||||
0x5b, 0x14, 0xea, 0x9d, 0x77, 0xb2, 0x0b, 0x3d, //
|
||||
};
|
||||
VirtualRecv(m, 0, prog, sizeof(prog));
|
||||
ASSERT_EQ(kMachineHalt, ExecuteUntilHalt(m));
|
||||
ASSERT_LDBL_EQ(1.1766221079117338e-14, FpuPop(m));
|
||||
}
|
||||
|
||||
TEST(machine, sizeIsReasonable) {
|
||||
ASSERT_LE(sizeof(struct Machine), 65536 * 3);
|
||||
}
|
|
@ -1,110 +0,0 @@
|
|||
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
|
||||
│vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi│
|
||||
╞══════════════════════════════════════════════════════════════════════════════╡
|
||||
│ Copyright 2020 Justine Alexandra Roberts Tunney │
|
||||
│ │
|
||||
│ Permission to use, copy, modify, and/or distribute this software for │
|
||||
│ any purpose with or without fee is hereby granted, provided that the │
|
||||
│ above copyright notice and this permission notice appear in all copies. │
|
||||
│ │
|
||||
│ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL │
|
||||
│ WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED │
|
||||
│ WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE │
|
||||
│ AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL │
|
||||
│ DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR │
|
||||
│ PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER │
|
||||
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/mem/mem.h"
|
||||
#include "libc/mem/gc.internal.h"
|
||||
#include "libc/testlib/testlib.h"
|
||||
#include "third_party/xed/x86.h"
|
||||
#include "tool/build/lib/endian.h"
|
||||
#include "tool/build/lib/machine.h"
|
||||
#include "tool/build/lib/modrm.h"
|
||||
|
||||
#define ILD(XEDD, OP, MODE) \
|
||||
do { \
|
||||
xed_decoded_inst_zero_set_mode(XEDD, MODE); \
|
||||
ASSERT_EQ(0, xed_instruction_length_decode(XEDD, OP, sizeof(OP))); \
|
||||
XEDD->op.rde = EncodeRde(XEDD); \
|
||||
} while (0)
|
||||
|
||||
TEST(modrm, testAddressSizeOverride_isNotPresent_keepsWholeExpression) {
|
||||
struct Machine *m = gc(NewMachine());
|
||||
struct XedDecodedInst *xedd = gc(calloc(1, sizeof(struct XedDecodedInst)));
|
||||
uint8_t op[] = {0x8d, 0x04, 0x03}; /* lea (%rbx,%rax,1),%eax */
|
||||
m->xedd = xedd;
|
||||
Write64(m->bx, 0x2);
|
||||
Write64(m->ax, 0xffffffff);
|
||||
ILD(xedd, op, XED_MACHINE_MODE_LONG_64);
|
||||
EXPECT_EQ(0x100000001, ComputeAddress(m, m->xedd->op.rde));
|
||||
}
|
||||
|
||||
TEST(modrm, testAddressSizeOverride_isPresent_modulesWholeExpression) {
|
||||
struct Machine *m = gc(NewMachine());
|
||||
struct XedDecodedInst *xedd = gc(calloc(1, sizeof(struct XedDecodedInst)));
|
||||
uint8_t op[] = {0x67, 0x8d, 0x04, 0x03}; /* lea (%ebx,%eax,1),%eax */
|
||||
m->xedd = xedd;
|
||||
Write64(m->bx, 0x2);
|
||||
Write64(m->ax, 0xffffffff);
|
||||
ILD(xedd, op, XED_MACHINE_MODE_LONG_64);
|
||||
EXPECT_EQ(0x000000001, ComputeAddress(m, m->xedd->op.rde));
|
||||
}
|
||||
|
||||
TEST(modrm, testOverflow_doesntTriggerTooling) {
|
||||
struct Machine *m = gc(NewMachine());
|
||||
struct XedDecodedInst *xedd = gc(calloc(1, sizeof(struct XedDecodedInst)));
|
||||
uint8_t op[] = {0x8d, 0x04, 0x03}; /* lea (%rbx,%rax,1),%eax */
|
||||
m->xedd = xedd;
|
||||
Write64(m->bx, 0x0000000000000001);
|
||||
Write64(m->ax, 0x7fffffffffffffff);
|
||||
ILD(xedd, op, XED_MACHINE_MODE_LONG_64);
|
||||
EXPECT_EQ(0x8000000000000000ull,
|
||||
(uint64_t)ComputeAddress(m, m->xedd->op.rde));
|
||||
}
|
||||
|
||||
TEST(modrm, testPuttingOnTheRiz) {
|
||||
struct Machine *m = gc(NewMachine());
|
||||
static uint8_t ops[][15] = {
|
||||
{0x8d, 0b00110100, 0b00100110}, // lea (%rsi),%esi
|
||||
{0x67, 0x8d, 0b00110100, 0b11100110}, // lea (%esi,%eiz,8),%esi
|
||||
{103, 141, 180, 229, 55, 19, 3, 0}, // lea 0x31337(%ebp,%eiz,8),%esi
|
||||
{141, 52, 229, 55, 19, 3, 0}, // lea 0x31337,%esi
|
||||
};
|
||||
m->xedd = gc(calloc(1, sizeof(struct XedDecodedInst)));
|
||||
Write64(m->si, 0x100000001);
|
||||
Write64(m->bp, 0x200000002);
|
||||
ILD(m->xedd, ops[0], XED_MACHINE_MODE_LONG_64);
|
||||
EXPECT_EQ(0x100000001, ComputeAddress(m, m->xedd->op.rde));
|
||||
ILD(m->xedd, ops[1], XED_MACHINE_MODE_LONG_64);
|
||||
EXPECT_EQ(0x000000001, ComputeAddress(m, m->xedd->op.rde));
|
||||
ILD(m->xedd, ops[2], XED_MACHINE_MODE_LONG_64);
|
||||
EXPECT_EQ(0x31339, ComputeAddress(m, m->xedd->op.rde));
|
||||
ILD(m->xedd, ops[3], XED_MACHINE_MODE_LONG_64);
|
||||
EXPECT_EQ(0x31337, ComputeAddress(m, m->xedd->op.rde));
|
||||
}
|
||||
|
||||
TEST(modrm, testSibIndexOnly) {
|
||||
// lea 0x0(,%rcx,4),%r8
|
||||
// mod = 0b00 (0)
|
||||
// reg = 0b000 (0)
|
||||
// rm = 0b100 (4)
|
||||
// scale = 0b10 (2)
|
||||
// index = 0b001 (1)
|
||||
// base = 0b101 (5)
|
||||
struct Machine *m = gc(NewMachine());
|
||||
struct XedDecodedInst *xedd = gc(calloc(1, sizeof(struct XedDecodedInst)));
|
||||
uint8_t op[] = {0x4c, 0x8d, 0x04, 0x8d, 0, 0, 0, 0};
|
||||
m->xedd = xedd;
|
||||
Write64(m->bp, 0x123);
|
||||
Write64(m->cx, 0x123);
|
||||
ILD(xedd, op, XED_MACHINE_MODE_LONG_64);
|
||||
EXPECT_TRUE(Rexw(m->xedd->op.rde));
|
||||
EXPECT_TRUE(Rexr(m->xedd->op.rde));
|
||||
EXPECT_FALSE(Rexb(m->xedd->op.rde));
|
||||
EXPECT_EQ(0b000, ModrmReg(m->xedd->op.rde));
|
||||
EXPECT_EQ(0b100, ModrmRm(m->xedd->op.rde));
|
||||
EXPECT_EQ(0x123 * 4, (uint64_t)ComputeAddress(m, m->xedd->op.rde));
|
||||
}
|
|
@ -1,56 +0,0 @@
|
|||
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
|
||||
│vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi│
|
||||
╞══════════════════════════════════════════════════════════════════════════════╡
|
||||
│ Copyright 2020 Justine Alexandra Roberts Tunney │
|
||||
│ │
|
||||
│ Permission to use, copy, modify, and/or distribute this software for │
|
||||
│ any purpose with or without fee is hereby granted, provided that the │
|
||||
│ above copyright notice and this permission notice appear in all copies. │
|
||||
│ │
|
||||
│ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL │
|
||||
│ WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED │
|
||||
│ WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE │
|
||||
│ AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL │
|
||||
│ DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR │
|
||||
│ PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER │
|
||||
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "test/tool/build/lib/numbers.h"
|
||||
|
||||
const uint64_t kNumbers[102] = {
|
||||
0x0000000000000000, 0x0000000080000000, 0x0000000000008000,
|
||||
0x0000000000000001, 0x0000000000000002, 0x0000000000000003,
|
||||
0x0000000000000004, 0x0000000000000005, 0x0000000000000006,
|
||||
0x0000000000000007, 0x0000000000000008, 0x0000000000000009,
|
||||
0x000000000000000a, 0x000000000000000b, 0x000000000000000c,
|
||||
0x000000000000000d, 0x000000000000000e, 0x000000000000000f,
|
||||
0x0000000000000010, 0x0000000000000011, 0x0000000000000012,
|
||||
0x0000000000000013, 0x0000000000000014, 0x0000000000000015,
|
||||
0x0000000000000016, 0x0000000000000017, 0x0000000000000018,
|
||||
0x0000000000000019, 0x000000000000001a, 0x000000000000001b,
|
||||
0x000000000000001c, 0x000000000000001d, 0x000000000000001e,
|
||||
0x000000000000001f, 0x0000000000000020, 0x0000000000000040,
|
||||
0x8000000000000000, 0x0000000000000080, 0x0000000000000002,
|
||||
0x0000000000000001, 0x0000000000000004, 0x00000000C0000000,
|
||||
0xC000000000000000, 0x000000000000C000, 0x00000000000000C0,
|
||||
0x0000000000000003, 0x000000000000E000, 0x00000000E0000000,
|
||||
0xE000000000000000, 0x00000000000000E0, 0x000000000000001F,
|
||||
0x00000000000000FC, 0x000000000000003F, 0x000000000000007F,
|
||||
0x00000000000000FB, 0x00000000000000FD, 0x00000000000000FE,
|
||||
0x00000000000000FF, 0x000000000000FF1F, 0x0000000000001FFF,
|
||||
0x000000000000FFFC, 0x0000000000003FFF, 0x000000000000FF3F,
|
||||
0x000000000000FFFD, 0x000000000000FFFE, 0x000000000000FFFB,
|
||||
0x000000000000FF7F, 0x0000000000007FFF, 0x000000000000FFFF,
|
||||
0x00000000FFFF1FFF, 0x00000000FFFFFF1F, 0x000000001FFFFFFF,
|
||||
0x00000000FFFFFF3F, 0x00000000FFFF3FFF, 0x00000000FFFFFFFC,
|
||||
0x000000003FFFFFFF, 0x00000000FFFFFF7F, 0x00000000FFFFFFFD,
|
||||
0x00000000FFFFFFFE, 0x00000000FFFFFFFB, 0x000000007FFFFFFF,
|
||||
0x00000000FFFF7FFF, 0x00000000FFFFFFFF, 0xFFFFFFFF1FFFFFFF,
|
||||
0x1FFFFFFFFFFFFFFF, 0xFFFFFFFFFFFF1FFF, 0xFFFFFFFFFFFFFF1F,
|
||||
0xFFFFFFFFFFFFFFFC, 0xFFFFFFFFFFFF3FFF, 0xFFFFFFFF3FFFFFFF,
|
||||
0xFFFFFFFFFFFFFF3F, 0x3FFFFFFFFFFFFFFF, 0xFFFFFFFFFFFFFFFD,
|
||||
0xFFFFFFFFFFFFFFFE, 0xFFFFFFFFFFFFFFFB, 0xFFFFFFFF7FFFFFFF,
|
||||
0x7FFFFFFFFFFFFFFF, 0xFFFFFFFFFFFFFF7F, 0xFFFFFFFFFFFF7FFF,
|
||||
0xFFFFFFFFFFFFFFFF, 0x00DeadBeefCafe00, 0x0000031337000000,
|
||||
};
|
|
@ -1,10 +0,0 @@
|
|||
#ifndef COSMOPOLITAN_TEST_TOOL_BUILD_LIB_NUMBERS_H_
|
||||
#define COSMOPOLITAN_TEST_TOOL_BUILD_LIB_NUMBERS_H_
|
||||
#if !(__ASSEMBLER__ + __LINKER__ + 0)
|
||||
COSMOPOLITAN_C_START_
|
||||
|
||||
extern const uint64_t kNumbers[102];
|
||||
|
||||
COSMOPOLITAN_C_END_
|
||||
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
|
||||
#endif /* COSMOPOLITAN_TEST_TOOL_BUILD_LIB_NUMBERS_H_ */
|
|
@ -1,96 +0,0 @@
|
|||
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
|
||||
│vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi│
|
||||
╞══════════════════════════════════════════════════════════════════════════════╡
|
||||
│ Copyright 2020 Justine Alexandra Roberts Tunney │
|
||||
│ │
|
||||
│ Permission to use, copy, modify, and/or distribute this software for │
|
||||
│ any purpose with or without fee is hereby granted, provided that the │
|
||||
│ above copyright notice and this permission notice appear in all copies. │
|
||||
│ │
|
||||
│ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL │
|
||||
│ WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED │
|
||||
│ WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE │
|
||||
│ AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL │
|
||||
│ DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR │
|
||||
│ PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER │
|
||||
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "test/tool/build/lib/optest.h"
|
||||
#include "libc/intrin/weaken.h"
|
||||
#include "libc/macros.internal.h"
|
||||
#include "libc/runtime/runtime.h"
|
||||
#include "libc/stdio/stdio.h"
|
||||
#include "test/tool/build/lib/numbers.h"
|
||||
#include "tool/build/lib/flags.h"
|
||||
#ifdef __x86_64__
|
||||
|
||||
const char kOpSuffix[] = {'b', 'w', 'l', 'q'};
|
||||
|
||||
void(RunOpTests)(const uint8_t *ops, size_t n, const char *const *opnames,
|
||||
const char *file, int line, const char *func) {
|
||||
uint64_t x, y;
|
||||
uint64_t xn, xp;
|
||||
uint32_t f0, f1, f2;
|
||||
long failed, succeeded;
|
||||
int w, h, i, j, c, z, s, o, p;
|
||||
failed = 0;
|
||||
succeeded = 0;
|
||||
for (w = 0; w < 4; ++w) {
|
||||
for (h = 0; h < n; ++h) {
|
||||
for (z = 0; z < 2; ++z) {
|
||||
for (o = 0; o < 2; ++o) {
|
||||
for (s = 0; s < 2; ++s) {
|
||||
for (i = 0; i < ARRAYLEN(kNumbers); ++i) {
|
||||
for (j = 0; j < ARRAYLEN(kNumbers); ++j) {
|
||||
for (c = 0; c < 2; ++c) {
|
||||
x = kNumbers[i];
|
||||
y = kNumbers[j];
|
||||
f2 = f1 = f0 = c << FLAGS_CF | z << FLAGS_ZF | s << FLAGS_SF |
|
||||
o << FLAGS_OF;
|
||||
xn = RunGolden(w, ops[h], x, y, &f1);
|
||||
xp = RunOpTest(w, ops[h], x, y, &f2);
|
||||
if (_weaken(FixupUndefOpTestFlags)) {
|
||||
FixupUndefOpTestFlags(w, ops[h], x, y, f1, &f2);
|
||||
}
|
||||
if (xn == xp && (f1 & FMASK) == (f2 & FMASK)) {
|
||||
succeeded++;
|
||||
} else if (failed++ < 10) {
|
||||
fprintf(stderr,
|
||||
"%s:%d:%s: %s%c failed\n\t"
|
||||
"𝑥 %016x\n\t"
|
||||
"𝑦 %016x %c%c%c%c 0NPlODITSZKA1PVC\n\t"
|
||||
"𝑥ₙ %016x %c%c%c%c %016b\n\t"
|
||||
"𝑥ₚ %016x %c%c%c%c %016b\n",
|
||||
file, line, func, opnames[ops[h]], kOpSuffix[w], x,
|
||||
y, ".C"[c], ".Z"[z], ".S"[s], ".O"[o], xn,
|
||||
".C"[!!(f1 & (1 << FLAGS_CF))],
|
||||
".Z"[!!(f1 & (1 << FLAGS_ZF))],
|
||||
".S"[!!(f1 & (1 << FLAGS_SF))],
|
||||
".O"[!!(f1 & (1 << FLAGS_OF))], f1, xp,
|
||||
".C"[!!(f2 & (1 << FLAGS_CF))],
|
||||
".Z"[!!(f2 & (1 << FLAGS_ZF))],
|
||||
".S"[!!(f2 & (1 << FLAGS_SF))],
|
||||
".O"[!!(f2 & (1 << FLAGS_OF))], f2);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (failed) {
|
||||
fprintf(stderr,
|
||||
"\n"
|
||||
"passing: %d%%\n"
|
||||
"succeeded: %,ld\n"
|
||||
"failed: %,ld\n"
|
||||
"\n",
|
||||
(int)((1 - (double)failed / succeeded) * 100), succeeded, failed);
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
#endif /* __x86_64__ */
|
|
@ -1,21 +0,0 @@
|
|||
#ifndef COSMOPOLITAN_TEST_TOOL_BUILD_LIB_OPTEST_H_
|
||||
#define COSMOPOLITAN_TEST_TOOL_BUILD_LIB_OPTEST_H_
|
||||
#include "tool/build/lib/flags.h"
|
||||
#if !(__ASSEMBLER__ + __LINKER__ + 0)
|
||||
COSMOPOLITAN_C_START_
|
||||
|
||||
#define FMASK (1 << FLAGS_CF | 1 << FLAGS_ZF | 1 << FLAGS_SF | 1 << FLAGS_OF)
|
||||
|
||||
void RunOpTests(const uint8_t *, size_t, const char *const *, const char *, int,
|
||||
const char *);
|
||||
|
||||
int64_t RunGolden(char, int, uint64_t, uint64_t, uint32_t *);
|
||||
int64_t RunOpTest(char, int, uint64_t, uint64_t, uint32_t *);
|
||||
void FixupUndefOpTestFlags(char, int, uint64_t, uint64_t, uint32_t, uint32_t *);
|
||||
|
||||
#define RunOpTests(ops, n, names) \
|
||||
RunOpTests(ops, n, names, __FILE__, __LINE__, __func__)
|
||||
|
||||
COSMOPOLITAN_C_END_
|
||||
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
|
||||
#endif /* COSMOPOLITAN_TEST_TOOL_BUILD_LIB_OPTEST_H_ */
|
|
@ -1,235 +0,0 @@
|
|||
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
|
||||
│vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi│
|
||||
╞══════════════════════════════════════════════════════════════════════════════╡
|
||||
│ Copyright 2020 Justine Alexandra Roberts Tunney │
|
||||
│ │
|
||||
│ Permission to use, copy, modify, and/or distribute this software for │
|
||||
│ any purpose with or without fee is hereby granted, provided that the │
|
||||
│ above copyright notice and this permission notice appear in all copies. │
|
||||
│ │
|
||||
│ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL │
|
||||
│ WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED │
|
||||
│ WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE │
|
||||
│ AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL │
|
||||
│ DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR │
|
||||
│ PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER │
|
||||
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "tool/build/lib/pty.h"
|
||||
#include "libc/log/log.h"
|
||||
#include "libc/mem/gc.internal.h"
|
||||
#include "libc/mem/mem.h"
|
||||
#include "libc/stdio/stdio.h"
|
||||
#include "libc/str/str.h"
|
||||
#include "libc/str/unicode.h"
|
||||
#include "libc/testlib/ezbench.h"
|
||||
#include "libc/testlib/testlib.h"
|
||||
|
||||
char *render(struct Pty *pty) {
|
||||
static struct Buffer b;
|
||||
int y;
|
||||
b.i = 0;
|
||||
for (y = 0; y < pty->yn; ++y) {
|
||||
PtyAppendLine(pty, &b, y);
|
||||
}
|
||||
b.p[b.i] = 0;
|
||||
return b.p;
|
||||
}
|
||||
|
||||
const char widelatin[] forcealign(16) = "\
|
||||
A-BCDEFGHIJKLMNOPQRSTUVWXYZ\r\n\
|
||||
ab-cdefghijklmnopqrstuvwxyz\r\n\
|
||||
012-3456789\r\n\
|
||||
ABCD-EFGHIJKLMNOPQRSTUVWXYZ\r\n\
|
||||
abcde-fghijklmnopqrstuvwxyz\r\n\
|
||||
012345-6789\r\n\
|
||||
ABCDEFG-HIJKLMNOPQRSTUVWXYZ\r\n\
|
||||
abcdefgh-ijklmnopqrstuvwxyz\r\n\
|
||||
012345678-9";
|
||||
|
||||
static const char widelatin_golden[] = "\
|
||||
A-BCDEFGHIJKLMNOPQRSTUVWXYZ \
|
||||
ab-cdefghijklmnopqrstuvwxyz \
|
||||
012-3456789 \
|
||||
ABCD-EFGHIJKLMNOPQRSTUVWXYZ \
|
||||
abcde-fghijklmnopqrstuvwxyz \
|
||||
012345-6789 \
|
||||
ABCDEFG-HIJKLMNOPQRSTUVWXYZ \
|
||||
abcdefgh-ijklmnopqrstuvwxyz \
|
||||
012345678-9▂ \
|
||||
\
|
||||
\
|
||||
\
|
||||
\
|
||||
\
|
||||
\
|
||||
\
|
||||
\
|
||||
\
|
||||
\
|
||||
\
|
||||
\
|
||||
\
|
||||
\
|
||||
\
|
||||
";
|
||||
|
||||
TEST(pty, testFunWidth) {
|
||||
struct Pty *pty = NewPty();
|
||||
PtyWrite(pty, widelatin, ARRAYLEN(widelatin) - 1);
|
||||
EXPECT_STREQ(widelatin_golden, gc(render(pty)));
|
||||
FreePty(pty);
|
||||
}
|
||||
|
||||
const char hyperion[] forcealign(16) = "\
|
||||
Fanatics have their dreams, wherewith they weave \
|
||||
A paradise for a sect; the savage too \
|
||||
From forth the loftiest fashion of his sleep \
|
||||
Guesses at Heaven; pity these have not \
|
||||
Trac'd upon vellum or wild Indian leaf \
|
||||
The shadows of melodious utterance. \
|
||||
But bare of laurel they live, dream, and die; \
|
||||
For Poesy alone can tell her dreams, \
|
||||
With the fine spell of words alone can save \
|
||||
Imagination from the sable charm \
|
||||
And dumb enchantment. Who alive can say, \
|
||||
'Thou art no Poet may'st not tell thy dreams?' \
|
||||
Since every man whose soul is not a clod \
|
||||
Hath visions, and would speak, if he had loved \
|
||||
And been well nurtured in his mother tongue. \
|
||||
Whether the dream now purpos'd to rehearse \
|
||||
Be poet's or fanatic's will be known \
|
||||
When this warm scribe my hand is in the grave.";
|
||||
|
||||
static const wchar_t hyperion_golden[] = L"\
|
||||
Fanatics have their dreams, wherewith they weave A paradise for a sect; the sava\
|
||||
ge too From forth the loftiest fashion of his sleep Guesses at Heaven; pity thes\
|
||||
e have not Trac'd upon vellum or wild Indian leaf The shadows of melodious utter\
|
||||
ance. But bare of laurel they live, dream, and die; For Poesy alone can tell her\
|
||||
dreams, With the fine spell of words alone can save Imagination from the sable \
|
||||
charm And dumb enchantment. Who alive can say, 'Thou art no Poet may'st not tell\
|
||||
thy dreams?' Since every man whose soul is not a clod Hath visions, and would s\
|
||||
peak, if he had loved And been well nurtured in his mother tongue. Whether the d\
|
||||
ream now purpos'd to rehearse Be poet's or fanatic's will be known When this war\
|
||||
m scribe my hand is in the grave. \
|
||||
\
|
||||
\
|
||||
\
|
||||
\
|
||||
\
|
||||
\
|
||||
\
|
||||
\
|
||||
\
|
||||
\
|
||||
\
|
||||
\
|
||||
\
|
||||
\
|
||||
";
|
||||
|
||||
TEST(pty, testPureAscii_benefitsFromVectorization) {
|
||||
struct Pty *pty = NewPty();
|
||||
PtyWrite(pty, hyperion, ARRAYLEN(hyperion) - 1);
|
||||
EXPECT_STREQN(pty->wcs, hyperion_golden, ARRAYLEN(hyperion_golden) - 1);
|
||||
FreePty(pty);
|
||||
}
|
||||
|
||||
static const char kKiloAnsi[] = "\
|
||||
\e[?25l\e[H\
|
||||
#-*-mode:makefile-gmake;indent-tabs-mode:t;tab-width:8;coding:utf-8-*-┐\e[39m\e[0K\r\n\
|
||||
#───vi: set et ft=make ts=8 tw=8 fenc=utf-8 :vi─────────\e[39m\e[0K\r\n\
|
||||
#\e[39m\e[0K\r\n\
|
||||
# SYNOPSIS\e[39m\e[0K\r\n\
|
||||
#\e[39m\e[0K\r\n\
|
||||
# Freestanding Hermetically-Sealed Monolithic Repository\e[39m\e[0K\r\n\
|
||||
#\e[39m\e[0K\r\n\
|
||||
# REQUIREMENTS\e[39m\e[0K\r\n\
|
||||
#\e[39m\e[0K\r\n\
|
||||
# You can run your programs on any operating system, but you have\e[39m\e[0K\r\n\
|
||||
# to build them on Linux 2.6+ (or WSL) using GNU Make. A modern C\e[39m\e[0K\r\n\
|
||||
# compiler that\'s statically-linked comes included as a courtesy.\e[39m\e[0K\r\n\
|
||||
#\e[39m\e[0K\r\n\
|
||||
# EXAMPLES\e[39m\e[0K\r\n\
|
||||
#\e[39m\e[0K\r\n\
|
||||
# # build and run everything\e[39m\e[0K\r\n\
|
||||
# make -j8 -O\e[39m\e[0K\r\n\
|
||||
# make -j8 -O MODE=dbg\e[39m\e[0K\r\n\
|
||||
# make -j8 -O MODE=opt\e[39m\e[0K\r\n\
|
||||
# make -j8 -O MODE=rel\e[39m\e[0K\r\n\
|
||||
# make -j8 -O MODE=tiny\e[39m\e[0K\r\n\
|
||||
#\e[39m\e[0K\r\n\
|
||||
# # build individual target\e[39m\e[0K\r\n\
|
||||
\e[0K\e[7mMakefile - 340 lines 1/340\e[0m\r\n\
|
||||
\e[0KHELP: Ctrl-S = save | Ctrl-Q = quit | Ctrl-F = find\e[1;1H\e[?25h";
|
||||
|
||||
static const wchar_t kKiloGolden[] = L"\
|
||||
#-*-mode:makefile-gmake;indent-tabs-mode:t;tab-width:8;coding:utf-8-*-┐ \
|
||||
#───vi: set et ft=make ts=8 tw=8 fenc=utf-8 :vi───────── \
|
||||
# \
|
||||
# SYNOPSIS \
|
||||
# \
|
||||
# Freestanding Hermetically-Sealed Monolithic Repository \
|
||||
# \
|
||||
# REQUIREMENTS \
|
||||
# \
|
||||
# You can run your programs on any operating system, but you have \
|
||||
# to build them on Linux 2.6+ (or WSL) using GNU Make. A modern C \
|
||||
# compiler that's statically-linked comes included as a courtesy. \
|
||||
# \
|
||||
# EXAMPLES \
|
||||
# \
|
||||
# # build and run everything \
|
||||
# make -j8 -O \
|
||||
# make -j8 -O MODE=dbg \
|
||||
# make -j8 -O MODE=opt \
|
||||
# make -j8 -O MODE=rel \
|
||||
# make -j8 -O MODE=tiny \
|
||||
# \
|
||||
# # build individual target \
|
||||
Makefile - 340 lines 1/340\
|
||||
HELP: Ctrl-S = save | Ctrl-Q = quit | Ctrl-F = find \
|
||||
";
|
||||
|
||||
TEST(pty, testLongestPossibleCharacter) {
|
||||
EXPECT_EQ(60, strlen("\e[21;22;27;24;25;29;38;2;255;255;255;48;2;255;255;"
|
||||
"255m\377\277\277\277\277\277"));
|
||||
struct Buffer b = {0};
|
||||
struct Pty *pty = NewPty();
|
||||
const char *s = "\e[1;2;3;4;5;6;7;9m"
|
||||
"h"
|
||||
"\e[0;"
|
||||
"38;2;255;255;255;"
|
||||
"48;2;255;255;255m"
|
||||
"\377\277\277\277\277\277"
|
||||
"\e[0m";
|
||||
PtyWrite(pty, s, strlen(s));
|
||||
PtyAppendLine(pty, &b, 0);
|
||||
AppendChar(&b, '\0');
|
||||
EXPECT_STREQ("\e[1;2;4;7;5;9m"
|
||||
"𝒉"
|
||||
"\e[22;24;27;25;29;38;2;255;255;255;48;2;255;255;255m"
|
||||
" "
|
||||
"\e[0m▂ "
|
||||
" ",
|
||||
b.p);
|
||||
FreePty(pty);
|
||||
free(b.p);
|
||||
}
|
||||
|
||||
TEST(pty, test) {
|
||||
struct Pty *pty = NewPty();
|
||||
PtyWrite(pty, kKiloAnsi, strlen(kKiloAnsi));
|
||||
EXPECT_STREQN(kKiloGolden, pty->wcs, wcslen(kKiloGolden));
|
||||
FreePty(pty);
|
||||
}
|
||||
|
||||
BENCH(pty, bench) {
|
||||
struct Pty *pty = NewPty();
|
||||
EZBENCH2("pty write ascii", donothing,
|
||||
PtyWrite(pty, hyperion, sizeof(hyperion) - 1));
|
||||
EZBENCH2("pty write kilo", donothing,
|
||||
PtyWrite(pty, kKiloAnsi, sizeof(kKiloAnsi) - 1));
|
||||
FreePty(pty);
|
||||
}
|
|
@ -1,26 +0,0 @@
|
|||
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
|
||||
│vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi│
|
||||
╞══════════════════════════════════════════════════════════════════════════════╡
|
||||
│ Copyright 2020 Justine Alexandra Roberts Tunney │
|
||||
│ │
|
||||
│ Permission to use, copy, modify, and/or distribute this software for │
|
||||
│ any purpose with or without fee is hereby granted, provided that the │
|
||||
│ above copyright notice and this permission notice appear in all copies. │
|
||||
│ │
|
||||
│ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL │
|
||||
│ WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED │
|
||||
│ WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE │
|
||||
│ AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL │
|
||||
│ DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR │
|
||||
│ PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER │
|
||||
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/errno.h"
|
||||
#include "libc/testlib/testlib.h"
|
||||
#include "tool/build/lib/xlat.h"
|
||||
|
||||
TEST(xlaterrno, test) {
|
||||
EXPECT_EQ(95, XlatErrno(EOPNOTSUPP));
|
||||
EXPECT_EQ(90, XlatErrno(EMSGSIZE));
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue