mirror of
				https://github.com/jart/cosmopolitan.git
				synced 2025-10-28 03:44:33 +00:00 
			
		
		
		
	Make improvements
- Emulator can now test the αcτµαlly pδrταblε εxεcµταblε bootloader - Whipped up a webserver named redbean. It services 150k requests per second on a single core. Bundling assets inside zip enables extremely fast serving for two reasons. The first is that zip central directory lookups go faster than stat() system calls. The second is that both zip and gzip content-encoding use DEFLATE, therefore, compressed responses can be served via the sendfile() system call which does an in-kernel copy directly from the zip executable structure. Also note that red bean zip executables can be deployed easily to all platforms, since these native executables work on Linux, Mac, BSD, and Windows. - Address sanitizer now works very well
This commit is contained in:
		
							parent
							
								
									7327c345f9
								
							
						
					
					
						commit
						416fd86676
					
				
					 230 changed files with 9835 additions and 5682 deletions
				
			
		|  | @ -1,25 +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                              │ | ||||
| │                                                                              │ | ||||
| │ This program is free software; you can redistribute it and/or modify         │ | ||||
| │ it under the terms of the GNU General Public License as published by         │ | ||||
| │ the Free Software Foundation; version 2 of the License.                      │ | ||||
| │                                                                              │ | ||||
| │ This program is distributed in the hope that it will be useful, but          │ | ||||
| │ WITHOUT ANY WARRANTY; without even the implied warranty of                   │ | ||||
| │ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU             │ | ||||
| │ General Public License for more details.                                     │ | ||||
| │                                                                              │ | ||||
| │ You should have received a copy of the GNU General Public License            │ | ||||
| │ along with this program; if not, write to the Free Software                  │ | ||||
| │ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA                │ | ||||
| │ 02110-1301 USA                                                               │ | ||||
| ╚─────────────────────────────────────────────────────────────────────────────*/ | ||||
| #include "libc/testlib/testlib.h" | ||||
| 
 | ||||
| TEST(flattenhighmemory, test) { | ||||
|   /* EXPECT_EQ(0, flattenhighmemory()); */ | ||||
|   /* EXPECT_STREQ("", flattenhighmemory()); */ | ||||
| } | ||||
|  | @ -29,6 +29,7 @@ TEST_APE_LIB_DIRECTDEPS =				\ | |||
| 	LIBC_NEXGEN32E					\
 | ||||
| 	LIBC_RUNTIME					\
 | ||||
| 	LIBC_STR					\
 | ||||
| 	LIBC_LOG					\
 | ||||
| 	LIBC_STUBS					\
 | ||||
| 	LIBC_TESTLIB					\
 | ||||
| 	LIBC_X | ||||
|  | @ -49,6 +50,10 @@ o/$(MODE)/test/ape/lib/%.com.dbg:			\ | |||
| 		$(APE) | ||||
| 	@$(APELINK) | ||||
| 
 | ||||
| $(TEST_APE_LIB_OBJS):					\ | ||||
| 		OVERRIDE_CFLAGS +=			\
 | ||||
| 			-fsanitize=address | ||||
| 
 | ||||
| .PHONY: o/$(MODE)/test/ape/lib | ||||
| o/$(MODE)/test/ape/lib:	$(TEST_APE_LIB_BINS)		\ | ||||
| 		$(TEST_APE_LIB_CHECKS) | ||||
|  |  | |||
|  | @ -19,6 +19,7 @@ | |||
| ╚─────────────────────────────────────────────────────────────────────────────*/ | ||||
| #include "dsp/core/core.h" | ||||
| #include "dsp/core/q.h" | ||||
| #include "libc/stdio/stdio.h" | ||||
| #include "libc/str/str.h" | ||||
| #include "libc/testlib/ezbench.h" | ||||
| #include "libc/testlib/testlib.h" | ||||
|  | @ -49,7 +50,8 @@ TEST(GetIntegerCoefficients8, testBt601Vectors) { | |||
|   for (i = 0; i < ARRAYLEN(V); ++i) { | ||||
|     GetIntegerCoefficients8(got, V[i].r, V[i].m, V[i].L, V[i].H); | ||||
|     EXPECT_EQ(0, memcmp(V[i].n, got, sizeof(got)), | ||||
|               "got={%ld,%ld,%ld,%ld,%ld,%ld}, want={%ld,%ld,%ld,%ld,%ld,%ld}", | ||||
|               "got={%ld,%ld,%ld,%ld,%ld,%ld}, want = { % ld, % ld, % ld, % ld, " | ||||
|               "% ld, % ld } ", | ||||
|               got[0], got[1], got[2], got[3], got[4], got[5], V[i].n[0], | ||||
|               V[i].n[1], V[i].n[2], V[i].n[3], V[i].n[4], V[i].n[5]); | ||||
|   } | ||||
|  |  | |||
|  | @ -47,6 +47,14 @@ o/$(MODE)/test/dsp/core/%.com.dbg:				\ | |||
| 		$(APE) | ||||
| 	@$(APELINK) | ||||
| 
 | ||||
| $(TEST_DSP_CORE_OBJS):						\ | ||||
| 		OVERRIDE_CFLAGS +=				\
 | ||||
| 			-fsanitize=address | ||||
| 
 | ||||
| o/$(MODE)/test/dsp/core/getintegercoefficients8_test-gcc.asm:	\ | ||||
| 		OVERRIDE_CFLAGS +=				\
 | ||||
| 			-fsanitize=address | ||||
| 
 | ||||
| .PHONY: o/$(MODE)/test/dsp/core | ||||
| o/$(MODE)/test/dsp/core:					\ | ||||
| 		$(TEST_DSP_CORE_BINS)				\
 | ||||
|  |  | |||
|  | @ -347,7 +347,7 @@ TEST(magikarp_vs_gyarados, testHalf) { | |||
|              61. / 31., 0, 0); | ||||
|   Magikarp2xY(32, 61, M[0], 32, 61); | ||||
|   Magikarp2xX(32, 61, M[0], 16, 61); | ||||
|   AbsoluteDifference(16, 31, D, 16, 32, G[0], 32, 61, M[0]); | ||||
|   AbsoluteDifference(16, 31, D, 16, 31, G[0], 32, 61, M[0]); | ||||
|   EXPECT_STREQ(u"\n\
 | ||||
| oppppppppooooooooooooopppppppqp\n\ | ||||
| pppppooonnmmmmmmmmmmmnnoopppppp\n\ | ||||
|  | @ -386,21 +386,21 @@ pppppppppoooooooooooooppppppppq", | |||
|                gc(bingblit(16, 31, G[0], 16, 31))); | ||||
|   EXPECT_STREQ(u"\n\
 | ||||
| ☺       ☺             ☺      ☺ \n\ | ||||
|     ☺ ☺☺ ☺          ☺          \n\ | ||||
|  ☺☺☺ ☺                ☺☺☺☺☻   ☺\n\ | ||||
| ☻☻☺☻      ☺☺☺  ☺☺☺     ☺☺☻☺☺ ☺☻\n\ | ||||
| ♥☺☺☺ ☺☺☻♥☻♥☻☺ ☺☻☻☻☻☺☺☺ ☺☺☻☻☺ ☺♥\n\ | ||||
| ☻☺ ☺☻♦♣♠♣♦♥☻☺☺☻♥♣♠♣♣♦♥☺☺☺☻☻ ☺☻☻\n\ | ||||
| ☺ ☻♦♠••○•♠♥☻☺♥♦♠•○••♠♥☻ ☻☻☺ ☺☺☻\n\ | ||||
|  ☻♣•◘◙◙◙◙♠♦☺☻♦•○◙◙◙◘•♣☺☺☻☺   ☺☺\n\ | ||||
| ☺♦♠◘◙♂♂◙○♣♦☺♦♠○◙♂♂◙•♠♦ ☺☺    ☺☺\n\ | ||||
| ☻♦•◘○◙◙◘•♦☺☻♦•○◙◙○◘♠♦☺  ☺   ☺☻☺\n\ | ||||
| ☺☻♣♠♠♠♠♠♦☻ ☻♦♠♠♠♠♠♥♥☺ ☻☺☺   ☺☻☻\n\ | ||||
| ☻ ☺♥♥♥☻☻☺☺☺☺☻☻♥♥☻☺ ☺☻♥☻☻☺  ☺☻☻♥\n\ | ||||
| ♥♥☻☻☺         ☺☻☻♥♥♥♥♥☻☻☺☺☻☺♥♥♥\n\ | ||||
| ♥♥♥♥☺☻☺    ☺☺☻☻♥♥♥♥♥♥♥♥☻  ☺☻☻♥♥\n\ | ||||
| ♥♥♥♥♥♥☺☺☺☺☺☻♥♥♥♥♥♥♥♥☻☻☺☺☺ ☺☺☺☺☺\n\ | ||||
| ☻☺☺☺☺☺☺   ☺☺☺☺☺☻oooooppppppppqp", | ||||
|        ☺               ☺ ☺     \n\ | ||||
|     ☺ ☺                   ☺☺   \n\ | ||||
|  ☺☺☺☺                      ☺ ☺ \n\ | ||||
| ☺☺              ☺ ☺☺          ☺\n\ | ||||
|        ☺☺☺           ☺ ☺   ☺ ☺ \n\ | ||||
|   ☺       ☺☺☺        ☺☺ ☺   ☺  \n\ | ||||
|          ☺ ☺   ☺      ☺☺☺      \n\ | ||||
|          ☺ ☺       ☺  ☺☺☺      \n\ | ||||
|        ☺  ☺        ☺ ☺      ☺☺ \n\ | ||||
|  ☺☺               ☺   ☺      ☺ \n\ | ||||
| ☺  ☺                        ☺ ☺\n\ | ||||
|                           ☺☺☺  \n\ | ||||
|    ☺☺☺                  ☺☺ ☺   \n\ | ||||
|      ☺  ☺             ☺  ☺     \n\ | ||||
| ☺        ☺           ☺       ☺☺", | ||||
|                gc(bingblit(16, 31, D, 16, 31))); | ||||
| } | ||||
| 
 | ||||
|  |  | |||
|  | @ -24,6 +24,10 @@ TEST(itoa64radix16, test) { | |||
|   char buf[21]; | ||||
|   EXPECT_EQ(5, uint64toarray_radix16(0x31337, buf)); | ||||
|   EXPECT_STREQ("31337", buf); | ||||
|   EXPECT_EQ(2, uint64toarray_radix16(0x13, buf)); | ||||
|   EXPECT_STREQ("13", buf); | ||||
|   EXPECT_EQ(3, uint64toarray_radix16(0x113, buf)); | ||||
|   EXPECT_STREQ("113", buf); | ||||
| } | ||||
| 
 | ||||
| TEST(itoa64fixed16, test) { | ||||
|  |  | |||
|  | @ -416,12 +416,8 @@ TEST(sprintf, test_float) { | |||
|   EXPECT_STREQ("42.90", Format("%.2f", 42.8952)); | ||||
|   EXPECT_STREQ("42.895200000", Format("%.9f", 42.8952)); | ||||
|   EXPECT_STREQ("42.8952230000", Format("%.10f", 42.895223)); | ||||
|   /* this testcase checks, that the precision is truncated to 9 digits. */ | ||||
|   /* a perfect working float should return the whole number */ | ||||
|   EXPECT_STREQ("42.895223123000", Format("%.12f", 42.89522312345678)); | ||||
|   /* this testcase checks, that the precision is truncated AND rounded to 9 */ | ||||
|   /* digits. a perfect working float should return the whole number */ | ||||
|   EXPECT_STREQ("42.895223877000", Format("%.12f", 42.89522387654321)); | ||||
|   EXPECT_STREQ("42.89522312345678", Format("%.14f", 42.89522312345678)); | ||||
|   EXPECT_STREQ("42.89522387654321", Format("%.14f", 42.89522387654321)); | ||||
|   EXPECT_STREQ(" 42.90", Format("%6.2f", 42.8952)); | ||||
|   EXPECT_STREQ("+42.90", Format("%+6.2f", 42.8952)); | ||||
|   EXPECT_STREQ("+42.9", Format("%+5.1f", 42.9252)); | ||||
|  |  | |||
|  | @ -18,6 +18,7 @@ | |||
| │ 02110-1301 USA                                                               │ | ||||
| ╚─────────────────────────────────────────────────────────────────────────────*/ | ||||
| #include "libc/bits/progn.h" | ||||
| #include "libc/intrin/mpsadbw.h" | ||||
| #include "libc/intrin/pabsb.h" | ||||
| #include "libc/intrin/pabsd.h" | ||||
| #include "libc/intrin/pabsw.h" | ||||
|  | @ -1422,7 +1423,8 @@ TEST(pabsb, fuzz) { | |||
|     RngSet(x, sizeof(x)); | ||||
|     pabsb(a, x); | ||||
|     (pabsb)(b, x); | ||||
|     ASSERT_EQ(0, memcmp(a, b, 16)); | ||||
|     ASSERT_EQ(0, memcmp(a, b, 16), "%d\n\t%`#.16s\n\t%`#.16s\n\t%`#.16s", i, x, | ||||
|               a, b); | ||||
|   } | ||||
| } | ||||
| 
 | ||||
|  | @ -1975,6 +1977,21 @@ TEST(pmulhrsw, fuzz) { | |||
|   } | ||||
| } | ||||
| 
 | ||||
| TEST(mpsadbw, fuzz) { | ||||
|   int i, j; | ||||
|   uint16_t a[8], b[8]; | ||||
|   uint8_t x[16], y[16]; | ||||
|   for (i = 0; i < 100; ++i) { | ||||
|     RngSet(x, sizeof(x)); | ||||
|     RngSet(y, sizeof(y)); | ||||
|     for (j = 0; j < 8; ++j) { | ||||
|       mpsadbw(a, x, y, j); | ||||
|       (mpsadbw)(b, x, y, j); | ||||
|       ASSERT_EQ(0, memcmp(a, b, 16), "%d %d", i, j); | ||||
|     } | ||||
|   } | ||||
| } | ||||
| 
 | ||||
| TEST(pmaddubsw, fuzz) { | ||||
|   int i, j; | ||||
|   int8_t y[16]; | ||||
|  |  | |||
|  | @ -52,6 +52,10 @@ o/$(MODE)/test/libc/intrin/%.com.dbg:			\ | |||
| 		$(APE) | ||||
| 	@$(APELINK) | ||||
| 
 | ||||
| $(TEST_LIBC_INTRIN_OBJS):				\ | ||||
| 		OVERRIDE_CFLAGS +=			\
 | ||||
| 			-fsanitize=address | ||||
| 
 | ||||
| .PHONY: o/$(MODE)/test/libc/intrin | ||||
| o/$(MODE)/test/libc/intrin:				\ | ||||
| 		$(TEST_LIBC_INTRIN_BINS)		\
 | ||||
|  |  | |||
|  | @ -57,3 +57,37 @@ TEST(memmove, overlappingDirect) { | |||
|     } | ||||
|   } | ||||
| } | ||||
| 
 | ||||
| char *MoveMemory(char *dst, const char *src, size_t n) { | ||||
|   size_t i; | ||||
|   for (i = 0; i < n; ++i) { | ||||
|     dst[i] = src[i]; | ||||
|   } | ||||
|   return dst; | ||||
| } | ||||
| 
 | ||||
| TEST(memmove, overlappingBackwards_isGenerallySafe) { | ||||
|   char buf[32]; | ||||
|   strcpy(buf, "abcdefghijklmnopqrstuvwxyz"); | ||||
|   ASSERT_STREQ("cdefghijklmnopqrstuvwxyzyz", MoveMemory(buf, buf + 2, 24)); | ||||
|   strcpy(buf, "abcdefghijklmnopqrstuvwxyz"); | ||||
|   ASSERT_STREQ("cdefghijklmnopqrstuvwxyzyz", memmove(buf, buf + 2, 24)); | ||||
|   strcpy(buf, "abcdefghijklmnopqrstuvwxyz"); | ||||
|   ASSERT_STREQ("cdefghijklmnopqrstuvwxyzyz", memcpy(buf, buf + 2, 24)); | ||||
| } | ||||
| 
 | ||||
| TEST(memmove, overlappingForwards_avoidsRunLengthDecodeBehavior) { | ||||
|   volatile char buf[32]; | ||||
|   strcpy(buf, "abc"); | ||||
|   MoveMemory(buf + 1, buf, 2); | ||||
|   ASSERT_STREQ("aaa", buf); | ||||
|   strcpy(buf, "abc"); | ||||
|   (memmove)(buf + 1, buf, 2); | ||||
|   ASSERT_STREQ("aab", buf); | ||||
|   strcpy(buf, "abcdefghijklmnopqrstuvwxyz"); | ||||
|   MoveMemory(buf + 2, buf, 24); | ||||
|   ASSERT_STREQ("ababababababababababababab", buf); | ||||
|   strcpy(buf, "abcdefghijklmnopqrstuvwxyz"); | ||||
|   memmove(buf + 2, buf, 24); | ||||
|   ASSERT_STREQ("ababcdefghijklmnopqrstuvwx", buf); | ||||
| } | ||||
|  |  | |||
|  | @ -81,3 +81,17 @@ TEST(memcpy, overlapping_isFineIfCopyingBackwards) { | |||
|     tfree(b1); | ||||
|   } | ||||
| } | ||||
| 
 | ||||
| TEST(stpcpy, test) { | ||||
|   volatile char *p; | ||||
|   volatile char b[16]; | ||||
|   volatile const char *s1 = "hello"; | ||||
|   volatile const char *s2 = "there"; | ||||
|   p = b; | ||||
|   p = stpcpy(p, s1); | ||||
|   EXPECT_EQ((intptr_t)b + 5, (intptr_t)p); | ||||
|   EXPECT_STREQ("hello", b); | ||||
|   p = stpcpy(p, s2); | ||||
|   EXPECT_EQ((intptr_t)b + 10, (intptr_t)p); | ||||
|   EXPECT_STREQ("hellothere", b); | ||||
| } | ||||
|  |  | |||
|  | @ -21,22 +21,26 @@ | |||
| #include "libc/str/str.h" | ||||
| #include "libc/testlib/testlib.h" | ||||
| 
 | ||||
| TEST(strlen16, testEmpty) { EXPECT_EQ(0, strlen(u"")); } | ||||
| TEST(strlen16, testAscii) { EXPECT_EQ(5, strlen(u"hello")); } | ||||
| TEST(strlen16, testEmpty) { | ||||
|   EXPECT_EQ(0, strlen16(u"")); | ||||
| } | ||||
| TEST(strlen16, testAscii) { | ||||
|   EXPECT_EQ(5, strlen16(u"hello")); | ||||
| } | ||||
| 
 | ||||
| TEST(strlen16, testUnicode) { | ||||
|   EXPECT_EQ(28, strlen(u"αcτµαlly pδrταblε εxεcµταblε")); | ||||
|   EXPECT_EQ(28, strlen16(u"αcτµαlly pδrταblε εxεcµταblε")); | ||||
| } | ||||
| 
 | ||||
| TEST(strclen, testAegeanNumberSupplementaryPlane) { | ||||
|   EXPECT_EQ(36, strlen("𐄷𐄸𐄹𐄺𐄻𐄼𐄽𐄾𐄿")); | ||||
|   EXPECT_EQ(18, strlen(u"𐄷𐄸𐄹𐄺𐄻𐄼𐄽𐄾𐄿")); | ||||
|   EXPECT_EQ(9, strlen(L"𐄷𐄸𐄹𐄺𐄻𐄼𐄽𐄾𐄿")); | ||||
|   EXPECT_EQ(18, strlen16(u"𐄷𐄸𐄹𐄺𐄻𐄼𐄽𐄾𐄿")); | ||||
|   EXPECT_EQ(9, wcslen(L"𐄷𐄸𐄹𐄺𐄻𐄼𐄽𐄾𐄿")); | ||||
|   EXPECT_EQ(9, strclen("𐄷𐄸𐄹𐄺𐄻𐄼𐄽𐄾𐄿")); | ||||
|   EXPECT_EQ(9, strclen(u"𐄷𐄸𐄹𐄺𐄻𐄼𐄽𐄾𐄿")); | ||||
|   EXPECT_EQ(9, strclen(L"𐄷𐄸𐄹𐄺𐄻𐄼𐄽𐄾𐄿")); | ||||
| } | ||||
| 
 | ||||
| TEST(strlen16, testCoolKidNulTerminator) { | ||||
|   EXPECT_EQ(2, strlen((const char16_t *)"\x00\xd8\x00\xdc\x00")); | ||||
|   EXPECT_EQ(2, strlen16((const char16_t *)"\x00\xd8\x00\xdc\x00")); | ||||
| } | ||||
|  |  | |||
|  | @ -29,8 +29,8 @@ wchar_t u32[] = L"utf32 ☻"; | |||
| 
 | ||||
| TEST(strlen, usageExample_c11) { | ||||
|   EXPECT_EQ(6 + 3, strlen(u8)); | ||||
|   EXPECT_EQ(7, strlen(u16)); | ||||
|   EXPECT_EQ(7, strlen(u32)); | ||||
|   EXPECT_EQ(7, strlen16(u16)); | ||||
|   EXPECT_EQ(7, wcslen(u32)); | ||||
| } | ||||
| 
 | ||||
| TEST(strlen, usageExample_c99) { | ||||
|  |  | |||
|  | @ -39,3 +39,8 @@ TEST(ldexp, test) { | |||
|   ASSERT_STREQ("100.48", gc(xasprintf("%.2f", scalblnf(pi, twopow)))); | ||||
|   ASSERT_STREQ("100.48", gc(xasprintf("%.2Lf", scalblnl(pi, twopow)))); | ||||
| } | ||||
| 
 | ||||
| TEST(exp10, test) { | ||||
|   ASSERT_EQ(100, (int)exp10(2)); | ||||
|   ASSERT_STREQ("100.000000", gc(xasprintf("%Lf", exp10l(2)))); | ||||
| } | ||||
|  |  | |||
|  | @ -20,6 +20,7 @@ | |||
| #include "libc/math.h" | ||||
| #include "libc/nexgen32e/x86feature.h" | ||||
| #include "libc/runtime/gc.h" | ||||
| #include "libc/str/str.h" | ||||
| #include "libc/testlib/testlib.h" | ||||
| #include "libc/tinymath/tinymath.h" | ||||
| #include "libc/x/x.h" | ||||
|  | @ -27,6 +28,10 @@ | |||
| float tinymath_roundf$k8(float); | ||||
| double tinymath_round$k8(double); | ||||
| 
 | ||||
| FIXTURE(intrin, disableHardwareExtensions) { | ||||
|   memset((/*unconst*/ void *)kCpuids, 0, sizeof(kCpuids)); | ||||
| } | ||||
| 
 | ||||
| TEST(round, testCornerCases) { | ||||
|   EXPECT_STREQ("-0", gc(xdtoa(tinymath_round(-0.0)))); | ||||
|   EXPECT_STREQ("nan", gc(xdtoa(tinymath_round(NAN)))); | ||||
|  | @ -35,6 +40,14 @@ TEST(round, testCornerCases) { | |||
|   EXPECT_STREQ("-inf", gc(xdtoa(tinymath_round(-INFINITY)))); | ||||
| } | ||||
| 
 | ||||
| TEST(roundl, testCornerCases) { | ||||
|   EXPECT_STREQ("-0", gc(xdtoa(tinymath_roundl(-0.0)))); | ||||
|   EXPECT_STREQ("nan", gc(xdtoa(tinymath_roundl(NAN)))); | ||||
|   EXPECT_STREQ("-nan", gc(xdtoa(tinymath_roundl(-NAN)))); | ||||
|   EXPECT_STREQ("inf", gc(xdtoa(tinymath_roundl(INFINITY)))); | ||||
|   EXPECT_STREQ("-inf", gc(xdtoa(tinymath_roundl(-INFINITY)))); | ||||
| } | ||||
| 
 | ||||
| TEST(round, test) { | ||||
|   EXPECT_STREQ("-3", gc(xdtoa(tinymath_round(-2.5)))); | ||||
|   EXPECT_STREQ("-2", gc(xdtoa(tinymath_round(-1.5)))); | ||||
|  | @ -134,16 +147,6 @@ TEST(rintl, test) { | |||
|   EXPECT_STREQ("2", gc(xdtoa(tinymath_rintl(2.5)))); | ||||
| } | ||||
| 
 | ||||
| TEST(lround, test) { | ||||
|   EXPECT_EQ(-3, tinymath_lround(-2.5)); | ||||
|   EXPECT_EQ(-2, tinymath_lround(-1.5)); | ||||
|   EXPECT_EQ(-1, tinymath_lround(-.5)); | ||||
|   EXPECT_EQ(0, tinymath_lround(-.0)); | ||||
|   EXPECT_EQ(1, tinymath_lround(.5)); | ||||
|   EXPECT_EQ(2, tinymath_lround(1.5)); | ||||
|   EXPECT_EQ(3, tinymath_lround(2.5)); | ||||
| } | ||||
| 
 | ||||
| TEST(roundf, testCornerCases) { | ||||
|   EXPECT_STREQ("-0", gc(xdtoa(tinymath_roundf(-0.0)))); | ||||
|   EXPECT_STREQ("nan", gc(xdtoa(tinymath_roundf(NAN)))); | ||||
|  | @ -162,40 +165,24 @@ TEST(lroundf, test) { | |||
|   EXPECT_EQ(3, tinymath_lroundf(2.5)); | ||||
| } | ||||
| 
 | ||||
| #if !X86_NEED(SSE4_2) | ||||
| 
 | ||||
| TEST(round$k8, test) { | ||||
|   EXPECT_STREQ("-3", gc(xdtoa(tinymath_round$k8(-2.5)))); | ||||
|   EXPECT_STREQ("-2", gc(xdtoa(tinymath_round$k8(-1.5)))); | ||||
|   EXPECT_STREQ("-1", gc(xdtoa(tinymath_round$k8(-.5)))); | ||||
|   EXPECT_STREQ("1", gc(xdtoa(tinymath_round$k8(.5)))); | ||||
|   EXPECT_STREQ("2", gc(xdtoa(tinymath_round$k8(1.5)))); | ||||
|   EXPECT_STREQ("3", gc(xdtoa(tinymath_round$k8(2.5)))); | ||||
| TEST(lround, test) { | ||||
|   EXPECT_EQ(-3, tinymath_lround(-2.5)); | ||||
|   EXPECT_EQ(-2, tinymath_lround(-1.5)); | ||||
|   EXPECT_EQ(-1, tinymath_lround(-.5)); | ||||
|   EXPECT_EQ(-0, tinymath_lround(-.4)); | ||||
|   EXPECT_EQ(0, tinymath_lround(.4)); | ||||
|   EXPECT_EQ(1, tinymath_lround(.5)); | ||||
|   EXPECT_EQ(2, tinymath_lround(1.5)); | ||||
|   EXPECT_EQ(3, tinymath_lround(2.5)); | ||||
| } | ||||
| 
 | ||||
| TEST(roundf$k8, test) { | ||||
|   EXPECT_STREQ("-3", gc(xdtoa(tinymath_roundf$k8(-2.5)))); | ||||
|   EXPECT_STREQ("-2", gc(xdtoa(tinymath_roundf$k8(-1.5)))); | ||||
|   EXPECT_STREQ("-1", gc(xdtoa(tinymath_roundf$k8(-.5)))); | ||||
|   EXPECT_STREQ("1", gc(xdtoa(tinymath_roundf$k8(.5)))); | ||||
|   EXPECT_STREQ("2", gc(xdtoa(tinymath_roundf$k8(1.5)))); | ||||
|   EXPECT_STREQ("3", gc(xdtoa(tinymath_roundf$k8(2.5)))); | ||||
| TEST(lroundl, test) { | ||||
|   EXPECT_EQ(-3, tinymath_lroundl(-2.5)); | ||||
|   EXPECT_EQ(-2, tinymath_lroundl(-1.5)); | ||||
|   EXPECT_EQ(-1, tinymath_lroundl(-.5)); | ||||
|   EXPECT_EQ(-0, tinymath_lroundl(-.4)); | ||||
|   EXPECT_EQ(0, tinymath_lroundl(.4)); | ||||
|   EXPECT_EQ(1, tinymath_lroundl(.5)); | ||||
|   EXPECT_EQ(2, tinymath_lroundl(1.5)); | ||||
|   EXPECT_EQ(3, tinymath_lroundl(2.5)); | ||||
| } | ||||
| 
 | ||||
| TEST(round$k8, testCornerCases) { | ||||
|   EXPECT_STREQ("-0", gc(xdtoa(tinymath_round$k8(-0.0)))); | ||||
|   EXPECT_STREQ("nan", gc(xdtoa(tinymath_round$k8(NAN)))); | ||||
|   EXPECT_STREQ("-nan", gc(xdtoa(tinymath_round$k8(-NAN)))); | ||||
|   EXPECT_STREQ("inf", gc(xdtoa(tinymath_round$k8(INFINITY)))); | ||||
|   EXPECT_STREQ("-inf", gc(xdtoa(tinymath_round$k8(-INFINITY)))); | ||||
| } | ||||
| 
 | ||||
| TEST(roundf$k8, testCornerCases) { | ||||
|   EXPECT_STREQ("-0", gc(xdtoa(tinymath_roundf$k8(-0.0)))); | ||||
|   EXPECT_STREQ("nan", gc(xdtoa(tinymath_roundf$k8(NAN)))); | ||||
|   EXPECT_STREQ("-nan", gc(xdtoa(tinymath_roundf$k8(-NAN)))); | ||||
|   EXPECT_STREQ("inf", gc(xdtoa(tinymath_roundf$k8(INFINITY)))); | ||||
|   EXPECT_STREQ("-inf", gc(xdtoa(tinymath_roundf$k8(-INFINITY)))); | ||||
| } | ||||
| 
 | ||||
| #endif | ||||
|  |  | |||
|  | @ -29,6 +29,7 @@ TEST_LIBC_TINYMATH_DIRECTDEPS =					\ | |||
| 	LIBC_TINYMATH						\
 | ||||
| 	LIBC_MEM						\
 | ||||
| 	LIBC_RUNTIME						\
 | ||||
| 	LIBC_NEXGEN32E						\
 | ||||
| 	LIBC_STUBS						\
 | ||||
| 	LIBC_TESTLIB						\
 | ||||
| 	LIBC_X							\
 | ||||
|  |  | |||
|  | @ -28,7 +28,7 @@ | |||
| 
 | ||||
| testonly nodiscard uint8_t *unbingx86op(const char16_t *codez) { | ||||
|   size_t len; | ||||
|   len = strlen(codez); | ||||
|   len = strlen16(codez); | ||||
|   return unbingbuf(xmalloc(ROUNDUP(len, 16)), len, codez, 0x90); | ||||
| } | ||||
| 
 | ||||
|  |  | |||
|  | @ -19,52 +19,42 @@ | |||
| ╚─────────────────────────────────────────────────────────────────────────────*/ | ||||
| #include "libc/bits/bits.h" | ||||
| #include "libc/mem/mem.h" | ||||
| #include "libc/runtime/gc.h" | ||||
| #include "libc/stdio/stdio.h" | ||||
| #include "libc/str/str.h" | ||||
| #include "libc/testlib/testlib.h" | ||||
| #include "libc/x/x.h" | ||||
| #include "net/http/http.h" | ||||
| 
 | ||||
| TEST(parsehttprequest, testEmpty) { | ||||
|   FILE *f = fmemopen(NULL, BUFSIZ, "r+"); | ||||
|   struct HttpRequest *req = calloc(1, sizeof(struct HttpRequest)); | ||||
|   EXPECT_EQ(-1, parsehttprequest(req, f)); | ||||
|   EXPECT_TRUE(feof(f)); | ||||
|   freehttprequest(&req); | ||||
|   fclose(f); | ||||
| struct HttpRequest req[1]; | ||||
| 
 | ||||
| static char *slice(const char *m, struct HttpRequestSlice s) { | ||||
|   return memcpy(xmalloc(s.b - s.a), m + s.a, s.b - s.a); | ||||
| } | ||||
| 
 | ||||
| TEST(parsehttprequest, testNoHeaders) { | ||||
|   const char kMessage[] = "GET /foo HTTP/1.0\r\n" | ||||
|                           "\r\n"; | ||||
|   FILE *f = fmemopen(NULL, BUFSIZ, "r+"); | ||||
|   ASSERT_EQ(1, fwrite(kMessage, strlen(kMessage), 1, f)); | ||||
|   struct HttpRequest *req = calloc(1, sizeof(struct HttpRequest)); | ||||
|   EXPECT_EQ(0, parsehttprequest(req, f)); | ||||
|   EXPECT_STREQN("GET", req->method.p, req->method.i); | ||||
|   EXPECT_STREQN("/foo", req->uri.p, req->uri.i); | ||||
|   EXPECT_STREQN("HTTP/1.0", req->version.p, req->version.i); | ||||
|   EXPECT_EQ(0, req->headers.count); | ||||
|   freehttprequest(&req); | ||||
|   fclose(f); | ||||
| TEST(ParseHttpRequest, testEmpty) { | ||||
|   EXPECT_EQ(-1, ParseHttpRequest(req, "", 0)); | ||||
| } | ||||
| 
 | ||||
| TEST(parsehttprequest, testSomeHeaders) { | ||||
|   const char kMessage[] = "GET /foo?bar%20hi HTTP/1.0\r\n" | ||||
|                           "Host: foo.example\r\n" | ||||
|                           "Content-Length: 0\r\n" | ||||
|                           "\r\n"; | ||||
|   FILE *f = fmemopen(NULL, BUFSIZ, "r+"); | ||||
|   ASSERT_EQ(1, fwrite(kMessage, strlen(kMessage), 1, f)); | ||||
|   struct HttpRequest *req = calloc(1, sizeof(struct HttpRequest)); | ||||
|   EXPECT_EQ(0, parsehttprequest(req, f)); | ||||
|   EXPECT_STREQN("GET", req->method.p, req->method.i); | ||||
|   EXPECT_STREQN("/foo?bar%20hi", req->uri.p, req->uri.i); | ||||
|   EXPECT_STREQN("HTTP/1.0", req->version.p, req->version.i); | ||||
|   EXPECT_EQ(2, req->headers.count); | ||||
|   EXPECT_STREQ("host:foo.example", critbit0_get(&req->headers, "host:")); | ||||
|   EXPECT_STREQ("content-length:0", | ||||
|                critbit0_get(&req->headers, "content-length:")); | ||||
|   EXPECT_EQ(NULL, critbit0_get(&req->headers, "content:")); | ||||
|   freehttprequest(&req); | ||||
|   fclose(f); | ||||
| TEST(ParseHttpRequest, testNoHeaders) { | ||||
|   static const char m[] = "GET /foo HTTP/1.0\r\n\r\n"; | ||||
|   EXPECT_EQ(0, ParseHttpRequest(req, m, strlen(m))); | ||||
|   EXPECT_EQ(kHttpGet, req->method); | ||||
|   EXPECT_STREQ("/foo", gc(slice(m, req->uri))); | ||||
|   EXPECT_STREQ("HTTP/1.0", gc(slice(m, req->version))); | ||||
| } | ||||
| 
 | ||||
| TEST(ParseHttpRequest, testSomeHeaders) { | ||||
|   static const char m[] = "\
 | ||||
| POST /foo?bar%20hi HTTP/1.0\r\n\ | ||||
| Host: foo.example\r\n\ | ||||
| Content-Length: 0\r\n\ | ||||
| \r\n"; | ||||
|   EXPECT_EQ(0, ParseHttpRequest(req, m, strlen(m))); | ||||
|   EXPECT_EQ(kHttpPost, req->method); | ||||
|   EXPECT_STREQ("/foo?bar%20hi", gc(slice(m, req->uri))); | ||||
|   EXPECT_STREQ("HTTP/1.0", gc(slice(m, req->version))); | ||||
|   EXPECT_STREQ("foo.example", gc(slice(m, req->headers[kHttpHost]))); | ||||
|   EXPECT_STREQ("0", gc(slice(m, req->headers[kHttpContentLength]))); | ||||
|   EXPECT_STREQ("", gc(slice(m, req->headers[kHttpEtag]))); | ||||
| } | ||||
|  |  | |||
|  | @ -39,6 +39,10 @@ o/$(MODE)/test/net/http/%.com.dbg:				\ | |||
| 		$(APE) | ||||
| 	@$(APELINK) | ||||
| 
 | ||||
| $(TEST_NET_HTTP_OBJS):						\ | ||||
| 		OVERRIDE_CFLAGS +=				\
 | ||||
| 			-fsanitize=address | ||||
| 
 | ||||
| .PHONY: o/$(MODE)/test/net/http | ||||
| o/$(MODE)/test/net/http:					\ | ||||
| 		$(TEST_NET_HTTP_BINS)				\
 | ||||
|  |  | |||
|  | @ -18,14 +18,19 @@ | |||
| │ 02110-1301 USA                                                               │ | ||||
| ╚─────────────────────────────────────────────────────────────────────────────*/ | ||||
| #include "libc/assert.h" | ||||
| #include "libc/bits/progn.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/alu.h" | ||||
| #include "tool/build/lib/case.h" | ||||
| #include "tool/build/lib/flags.h" | ||||
| 
 | ||||
| #define ALU_TEST 8 | ||||
| 
 | ||||
| #define NATIVE_ALU2(MODE, INSTRUCTION)                     \ | ||||
|   asm("pushf\n\t"                                          \ | ||||
|       "andl\t%3,(%%rsp)\n\t"                               \ | ||||
|  | @ -97,6 +102,15 @@ const char *const kAluNames[] = { | |||
|     [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); | ||||
| } | ||||
|  |  | |||
|  | @ -24,7 +24,7 @@ | |||
| #include "tool/build/lib/flags.h" | ||||
| 
 | ||||
| #define OSZ  00000000040 | ||||
| #define REXW 00000004000 | ||||
| #define REXW 00000000100 | ||||
| 
 | ||||
| struct Machine m[1]; | ||||
| struct XedDecodedInst xedd[1]; | ||||
|  | @ -38,7 +38,7 @@ TEST(bsr64, test) { | |||
|   uint64_t i, w, x, a, b; | ||||
|   for (i = 0; i < ARRAYLEN(kNumbers); ++i) { | ||||
|     x = kNumbers[i]; | ||||
|     a = AluBsr(m, REXW, 0, x); | ||||
|     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); | ||||
|  | @ -50,7 +50,7 @@ TEST(bsr32, test) { | |||
|   uint32_t i, w, x, a, b; | ||||
|   for (i = 0; i < ARRAYLEN(kNumbers); ++i) { | ||||
|     x = kNumbers[i]; | ||||
|     a = AluBsr(m, 0, 0, x); | ||||
|     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); | ||||
|  | @ -62,7 +62,7 @@ TEST(bsr16, test) { | |||
|   uint16_t i, w, x, a, b; | ||||
|   for (i = 0; i < ARRAYLEN(kNumbers); ++i) { | ||||
|     x = kNumbers[i]; | ||||
|     a = AluBsr(m, OSZ, 0, x); | ||||
|     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); | ||||
|  | @ -74,7 +74,7 @@ TEST(bsf64, test) { | |||
|   uint64_t i, w, x, a, b; | ||||
|   for (i = 0; i < ARRAYLEN(kNumbers); ++i) { | ||||
|     x = kNumbers[i]; | ||||
|     a = AluBsf(m, REXW, 0, x); | ||||
|     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); | ||||
|  | @ -86,7 +86,7 @@ TEST(bsf32, test) { | |||
|   uint32_t i, w, x, a, b; | ||||
|   for (i = 0; i < ARRAYLEN(kNumbers); ++i) { | ||||
|     x = kNumbers[i]; | ||||
|     a = AluBsf(m, 0, 0, x); | ||||
|     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); | ||||
|  | @ -98,7 +98,7 @@ TEST(bsf16, test) { | |||
|   uint16_t i, w, x, a, b; | ||||
|   for (i = 0; i < ARRAYLEN(kNumbers); ++i) { | ||||
|     x = kNumbers[i]; | ||||
|     a = AluBsf(m, OSZ, 0, x); | ||||
|     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); | ||||
|  |  | |||
|  | @ -58,6 +58,105 @@ | |||
|       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: | ||||
|           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: | ||||
|           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: | ||||
|           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: | ||||
|           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: | ||||
|           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: | ||||
|           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: | ||||
|           unreachable; | ||||
|       } | ||||
|     default: | ||||
|       unreachable; | ||||
|   } | ||||
| } | ||||
| 
 | ||||
| int64_t RunGolden(char w, int h, uint64_t x, uint64_t y, uint32_t *f) { | ||||
|   switch (h & 7) { | ||||
|     case BSU_ROR: | ||||
|  |  | |||
|  | @ -19,6 +19,7 @@ | |||
| ╚─────────────────────────────────────────────────────────────────────────────*/ | ||||
| #include "libc/testlib/testlib.h" | ||||
| #include "tool/build/lib/dis.h" | ||||
| #include "tool/build/lib/modrm.h" | ||||
| 
 | ||||
| char b1[64]; | ||||
| char b2[64]; | ||||
|  | @ -80,9 +81,144 @@ TEST(DisInst, testPuttingOnTheRiz) { | |||
| } | ||||
| 
 | ||||
| TEST(DisInst, testSibIndexOnly) { | ||||
|   uint8_t op[] = {76, 141, 4, 141, 0, 0, 0, 0}; /* lea 0x0(,%rcx,4),%r8 */ | ||||
|   uint8_t op[] = {76, 141, 4, 141, 0, 0, 0, 0}; | ||||
|   xed_decoded_inst_zero_set_mode(d->xedd, XED_MACHINE_MODE_LONG_64); | ||||
|   ASSERT_EQ(0, xed_instruction_length_decode(d->xedd, op, sizeof(op))); | ||||
|   DisInst(b, b1, DisSpec(d->xedd, b2)); | ||||
|   EXPECT_STREQ("lea     0(,%rcx,4),%r8", b1); | ||||
| } | ||||
| 
 | ||||
| TEST(DisInst, testRealMode) { | ||||
|   uint8_t op[] = {0x89, 0xe5}; | ||||
|   xed_decoded_inst_zero_set_mode(d->xedd, XED_MACHINE_MODE_REAL); | ||||
|   ASSERT_EQ(0, xed_instruction_length_decode(d->xedd, op, sizeof(op))); | ||||
|   DisInst(b, 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}; | ||||
|   xed_decoded_inst_zero_set_mode(d->xedd, XED_MACHINE_MODE_LONG_64); | ||||
|   ASSERT_EQ(0, xed_instruction_length_decode(d->xedd, op, sizeof(op))); | ||||
|   DisInst(b, b1, DisSpec(d->xedd, b2)); | ||||
|   EXPECT_STREQ("nopw    %cs:0(%rax,%rax)", b1); | ||||
| } | ||||
| 
 | ||||
| TEST(DisInst, testPush) { | ||||
|   uint8_t op[] = {0x41, 0x5c}; | ||||
|   xed_decoded_inst_zero_set_mode(d->xedd, XED_MACHINE_MODE_LONG_64); | ||||
|   ASSERT_EQ(0, xed_instruction_length_decode(d->xedd, op, sizeof(op))); | ||||
|   EXPECT_EQ(4, ModrmSrm(d->xedd->op.rde)); | ||||
|   EXPECT_EQ(1, Rexb(d->xedd->op.rde)); | ||||
|   DisInst(b, b1, DisSpec(d->xedd, b2)); | ||||
|   EXPECT_STREQ("pop     %r12", b1); | ||||
| } | ||||
| 
 | ||||
| TEST(DisInst, testMovb) { | ||||
|   uint8_t op[] = {0x8a, 0x1e, 0x0c, 0x32}; | ||||
|   xed_decoded_inst_zero_set_mode(d->xedd, XED_MACHINE_MODE_LONG_64); | ||||
|   ASSERT_EQ(0, xed_instruction_length_decode(d->xedd, op, sizeof(op))); | ||||
|   DisInst(b, b1, DisSpec(d->xedd, b2)); | ||||
|   EXPECT_STREQ("mov     (%rsi),%bl", b1); | ||||
|   xed_decoded_inst_zero_set_mode(d->xedd, XED_MACHINE_MODE_REAL); | ||||
|   ASSERT_EQ(0, xed_instruction_length_decode(d->xedd, op, sizeof(op))); | ||||
|   DisInst(b, b1, DisSpec(d->xedd, b2)); | ||||
|   EXPECT_STREQ("mov     0x320c,%bl", b1); | ||||
| } | ||||
| 
 | ||||
| TEST(DisInst, testLes) { | ||||
|   uint8_t op[] = {0xc4, 0x3e, 0x16, 0x32}; | ||||
|   xed_decoded_inst_zero_set_mode(d->xedd, XED_MACHINE_MODE_REAL); | ||||
|   ASSERT_EQ(0, xed_instruction_length_decode(d->xedd, op, sizeof(op))); | ||||
|   DisInst(b, b1, DisSpec(d->xedd, b2)); | ||||
|   EXPECT_STREQ("les     0x3216,%di", b1); | ||||
| } | ||||
| 
 | ||||
| TEST(DisInst, testStosbLong) { | ||||
|   uint8_t op[] = {0xAA}; | ||||
|   xed_decoded_inst_zero_set_mode(d->xedd, XED_MACHINE_MODE_LONG_64); | ||||
|   ASSERT_EQ(0, xed_instruction_length_decode(d->xedd, op, sizeof(op))); | ||||
|   DisInst(b, b1, DisSpec(d->xedd, b2)); | ||||
|   EXPECT_STREQ("stosb   %al,(%rdi)", b1); | ||||
| } | ||||
| 
 | ||||
| TEST(DisInst, testStosbReal) { | ||||
|   uint8_t op[] = {0xAA}; | ||||
|   xed_decoded_inst_zero_set_mode(d->xedd, XED_MACHINE_MODE_REAL); | ||||
|   ASSERT_EQ(0, xed_instruction_length_decode(d->xedd, op, sizeof(op))); | ||||
|   DisInst(b, b1, DisSpec(d->xedd, b2)); | ||||
|   EXPECT_STREQ("stosb   %al,(%di)", b1); | ||||
| } | ||||
| 
 | ||||
| TEST(DisInst, testStosbLegacy) { | ||||
|   uint8_t op[] = {0xAA}; | ||||
|   xed_decoded_inst_zero_set_mode(d->xedd, XED_MACHINE_MODE_LEGACY_32); | ||||
|   ASSERT_EQ(0, xed_instruction_length_decode(d->xedd, op, sizeof(op))); | ||||
|   DisInst(b, b1, DisSpec(d->xedd, b2)); | ||||
|   EXPECT_STREQ("stosb   %al,(%edi)", b1); | ||||
| } | ||||
| 
 | ||||
| TEST(DisInst, testStosbLongAsz) { | ||||
|   uint8_t op[] = {0x67, 0xAA}; | ||||
|   xed_decoded_inst_zero_set_mode(d->xedd, XED_MACHINE_MODE_LONG_64); | ||||
|   ASSERT_EQ(0, xed_instruction_length_decode(d->xedd, op, sizeof(op))); | ||||
|   DisInst(b, b1, DisSpec(d->xedd, b2)); | ||||
|   EXPECT_STREQ("stosb   %al,(%edi)", b1); | ||||
| } | ||||
| 
 | ||||
| TEST(DisInst, testAddLong) { | ||||
|   uint8_t op[] = {0x01, 0xff}; | ||||
|   xed_decoded_inst_zero_set_mode(d->xedd, XED_MACHINE_MODE_LONG_64); | ||||
|   ASSERT_EQ(0, xed_instruction_length_decode(d->xedd, op, sizeof(op))); | ||||
|   DisInst(b, b1, DisSpec(d->xedd, b2)); | ||||
|   EXPECT_STREQ("add     %edi,%edi", b1); | ||||
| } | ||||
| 
 | ||||
| TEST(DisInst, testAddLegacy) { | ||||
|   uint8_t op[] = {0x01, 0xff}; | ||||
|   xed_decoded_inst_zero_set_mode(d->xedd, XED_MACHINE_MODE_LEGACY_32); | ||||
|   ASSERT_EQ(0, xed_instruction_length_decode(d->xedd, op, sizeof(op))); | ||||
|   DisInst(b, b1, DisSpec(d->xedd, b2)); | ||||
|   EXPECT_STREQ("add     %edi,%edi", b1); | ||||
| } | ||||
| 
 | ||||
| TEST(DisInst, testAddReal) { | ||||
|   uint8_t op[] = {0x01, 0xff}; | ||||
|   xed_decoded_inst_zero_set_mode(d->xedd, XED_MACHINE_MODE_REAL); | ||||
|   ASSERT_EQ(0, xed_instruction_length_decode(d->xedd, op, sizeof(op))); | ||||
|   DisInst(b, b1, DisSpec(d->xedd, b2)); | ||||
|   EXPECT_STREQ("add     %di,%di", b1); | ||||
| } | ||||
| 
 | ||||
| TEST(DisInst, testAddLongOsz) { | ||||
|   uint8_t op[] = {0x66, 0x01, 0xff}; | ||||
|   xed_decoded_inst_zero_set_mode(d->xedd, XED_MACHINE_MODE_LONG_64); | ||||
|   ASSERT_EQ(0, xed_instruction_length_decode(d->xedd, op, sizeof(op))); | ||||
|   DisInst(b, b1, DisSpec(d->xedd, b2)); | ||||
|   EXPECT_STREQ("add     %di,%di", b1); | ||||
| } | ||||
| 
 | ||||
| TEST(DisInst, testAddLegacyOsz) { | ||||
|   uint8_t op[] = {0x66, 0x01, 0xff}; | ||||
|   xed_decoded_inst_zero_set_mode(d->xedd, XED_MACHINE_MODE_LEGACY_32); | ||||
|   ASSERT_EQ(0, xed_instruction_length_decode(d->xedd, op, sizeof(op))); | ||||
|   DisInst(b, b1, DisSpec(d->xedd, b2)); | ||||
|   EXPECT_STREQ("add     %di,%di", b1); | ||||
| } | ||||
| 
 | ||||
| TEST(DisInst, testAddRealOsz) { | ||||
|   uint8_t op[] = {0x66, 0x01, 0xff}; | ||||
|   xed_decoded_inst_zero_set_mode(d->xedd, XED_MACHINE_MODE_REAL); | ||||
|   ASSERT_EQ(0, xed_instruction_length_decode(d->xedd, op, sizeof(op))); | ||||
|   DisInst(b, b1, DisSpec(d->xedd, b2)); | ||||
|   EXPECT_STREQ("add     %edi,%edi", b1); | ||||
| } | ||||
| 
 | ||||
| TEST(DisInst, testFxam) { | ||||
|   uint8_t op[] = {0xd9, 0xe5}; | ||||
|   xed_decoded_inst_zero_set_mode(d->xedd, XED_MACHINE_MODE_LONG_64); | ||||
|   ASSERT_EQ(0, xed_instruction_length_decode(d->xedd, op, sizeof(op))); | ||||
|   ASSERT_EQ(4, ModrmReg(d->xedd->op.rde)); | ||||
|   DisInst(b, b1, DisSpec(d->xedd, b2)); | ||||
|   EXPECT_STREQ("fxam    ", b1); | ||||
| } | ||||
|  |  | |||
|  | @ -32,8 +32,8 @@ | |||
| 
 | ||||
| #define CX     1 | ||||
| #define OSZ    00000000040 | ||||
| #define REXW   00000004000 | ||||
| #define RM(x)  (0000000700 & ((x) << 006)) | ||||
| #define REXW   00000000100 | ||||
| #define RM(x)  (0000001600 & ((x) << 007)) | ||||
| #define MOD(x) (0060000000 & ((x) << 026)) | ||||
| 
 | ||||
| jmp_buf sigfpejmp; | ||||
|  |  | |||
|  | @ -106,6 +106,7 @@ struct Machine *m; | |||
| void SetUp(void) { | ||||
|   base = 0; | ||||
|   m = NewMachine(); | ||||
|   m->cr3 = MallocPage(); | ||||
|   realsize = 0x10000; | ||||
|   real = tmemalign(PAGESIZE, ROUNDUP(realsize, PAGESIZE)); | ||||
|   RegisterMemory(m, base, real, realsize); | ||||
|  | @ -115,6 +116,7 @@ void SetUp(void) { | |||
| 
 | ||||
| void TearDown(void) { | ||||
|   ResetRam(m); | ||||
|   free(m->cr3); | ||||
|   tfree(real); | ||||
|   free(m); | ||||
| } | ||||
|  | @ -294,5 +296,34 @@ BENCH(machine, benchNop) { | |||
| } | ||||
| 
 | ||||
| TEST(machine, sizeIsReasonable) { | ||||
|   ASSERT_LE(sizeof(struct Machine), 65536 * 2); | ||||
|   ASSERT_LE(sizeof(struct Machine), 65536 * 3); | ||||
| } | ||||
| 
 | ||||
| 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
 | ||||
|   }; | ||||
|   memcpy(real, 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,  //
 | ||||
|   }; | ||||
|   memcpy(real, prog, sizeof(prog)); | ||||
|   ASSERT_EQ(kMachineHalt, ExecuteUntilHalt(m)); | ||||
|   ASSERT_LDBL_EQ(1.1766221079117338e-14, FpuPop(m)); | ||||
| } | ||||
|  |  | |||
|  | @ -88,6 +88,7 @@ TEST(modrm, testPuttingOnTheRiz) { | |||
| } | ||||
| 
 | ||||
| TEST(modrm, testSibIndexOnly) { | ||||
|   // lea 0x0(,%rcx,4),%r8
 | ||||
|   //       mod                  = 0b00  (0)
 | ||||
|   //       reg                  = 0b000 (0)
 | ||||
|   //       rm                   = 0b100 (4)
 | ||||
|  | @ -96,11 +97,16 @@ TEST(modrm, testSibIndexOnly) { | |||
|   //       base                 = 0b101 (5)
 | ||||
|   struct Machine *m = gc(NewMachine()); | ||||
|   struct XedDecodedInst *xedd = gc(calloc(1, sizeof(struct XedDecodedInst))); | ||||
|   uint8_t op[] = {76, 141, 4, 141, 0, 0, 0, 0}; /* lea 0x0(,%rcx,4),%r8 */ | ||||
|   uint8_t op[] = {0x4c, 0x8d, 0x04, 0x8d, 0, 0, 0, 0}; | ||||
|   m->xedd = xedd; | ||||
|   Write64(m->bp, 0x123); | ||||
|   Write64(m->cx, 0x123); | ||||
|   xed_decoded_inst_zero_set_mode(xedd, XED_MACHINE_MODE_LONG_64); | ||||
|   ASSERT_EQ(0, xed_instruction_length_decode(xedd, op, sizeof(op))); | ||||
|   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,39 +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                              │ | ||||
| │                                                                              │ | ||||
| │ This program is free software; you can redistribute it and/or modify         │ | ||||
| │ it under the terms of the GNU General Public License as published by         │ | ||||
| │ the Free Software Foundation; version 2 of the License.                      │ | ||||
| │                                                                              │ | ||||
| │ This program is distributed in the hope that it will be useful, but          │ | ||||
| │ WITHOUT ANY WARRANTY; without even the implied warranty of                   │ | ||||
| │ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU             │ | ||||
| │ General Public License for more details.                                     │ | ||||
| │                                                                              │ | ||||
| │ You should have received a copy of the GNU General Public License            │ | ||||
| │ along with this program; if not, write to the Free Software                  │ | ||||
| │ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA                │ | ||||
| │ 02110-1301 USA                                                               │ | ||||
| ╚─────────────────────────────────────────────────────────────────────────────*/ | ||||
| #include "libc/testlib/testlib.h" | ||||
| #include "tool/build/lib/x87.h" | ||||
| 
 | ||||
| TEST(x87, fprem) { | ||||
|   ASSERT_LDBL_EQ(1, fprem(1, -1.5, NULL)); | ||||
|   ASSERT_LDBL_EQ(1.1766221079117338e-14L, | ||||
|                  fprem(12300000000000000.L, .0000000000000123L, NULL)); | ||||
| } | ||||
| 
 | ||||
| TEST(x87, fprem1) { | ||||
|   ASSERT_LDBL_EQ(-.5, fprem1(1, -1.5, NULL)); | ||||
|   ASSERT_LDBL_EQ(-5.337789208826618e-16, | ||||
|                  fprem1(12300000000000000.L, .0000000000000123L, NULL)); | ||||
| } | ||||
| 
 | ||||
| TEST(x87, fpremFlags) { | ||||
|   uint32_t sw = 0xffff; | ||||
|   ASSERT_LDBL_EQ(1, fprem(1, -1.5, &sw)); | ||||
|   ASSERT_EQ(0b1011100011111111, sw); | ||||
| } | ||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue