1
0
Fork 0
mirror of https://github.com/ruby/ruby.git synced 2022-11-09 12:17:21 -05:00
ruby--ruby/yjit_asm_tests.c
Alan Wu f6da559d5b Put YJIT into a single compilation unit
For upstreaming, we want functions we export either prefixed with "rb_"
or made static. Historically we haven't been following this rule, so we
were "leaking" a lot of symbols as `make leak-globals` would tell us.

This change unifies everything YJIT into a single compilation unit,
yjit.o, and makes everything unprefixed static to pass `make leak-globals`.
This manual "unified build" setup is similar to that of vm.o.

Having everything in one compilation unit allows static functions to
be visible across YJIT files and removes the need for declarations in
headers in some cases. Unnecessary declarations were removed.

Other changes of note:
  - switched to MJIT_SYMBOL_EXPORT_BEGIN which indicates stuff as being
    off limits for native extensions
  - the first include of each YJIT file is change to be "internal.h"
  - undefined MAP_STACK before explicitly redefining it since it
    collide's with a definition in system headers. Consider renaming?
2021-10-20 18:19:42 -04:00

420 lines
16 KiB
C

// For MAP_ANONYMOUS on GNU/Linux
#define _GNU_SOURCE 1
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <assert.h>
#include "yjit_asm.c"
// Print the bytes in a code block
void print_bytes(codeblock_t* cb)
{
for (uint32_t i = 0; i < cb->write_pos; ++i)
{
printf("%02X", (int)cb->mem_block[i]);
}
printf("\n");
}
// Check that the code block contains the given sequence of bytes
void check_bytes(codeblock_t* cb, const char* bytes)
{
printf("checking encoding: %s\n", bytes);
size_t len = strlen(bytes);
assert (len % 2 == 0);
size_t num_bytes = len / 2;
if (cb->write_pos != num_bytes)
{
fprintf(stderr, "incorrect encoding length, expected %ld, got %d\n",
num_bytes,
cb->write_pos
);
printf("%s\n", bytes);
print_bytes(cb);
exit(-1);
}
for (uint32_t i = 0; i < num_bytes; ++i)
{
char byte_str[] = {0, 0, 0, 0};
strncpy(byte_str, bytes + (2 * i), 2);
char* endptr;
long int byte = strtol(byte_str, &endptr, 16);
uint8_t cb_byte = cb->mem_block[i];
if (cb_byte != byte)
{
fprintf(stderr, "incorrect encoding at position %d, expected %02X, got %02X\n",
i,
(int)byte,
(int)cb_byte
);
printf("%s\n", bytes);
print_bytes(cb);
exit(-1);
}
}
}
void run_assembler_tests()
{
printf("Running assembler tests\n");
codeblock_t cb_obj;
codeblock_t* cb = &cb_obj;
uint8_t* mem_block = alloc_exec_mem(4096);
cb_init(cb, mem_block, 4096);
// add
cb_set_pos(cb, 0); add(cb, CL, imm_opnd(3)); check_bytes(cb, "80C103");
cb_set_pos(cb, 0); add(cb, CL, BL); check_bytes(cb, "00D9");
cb_set_pos(cb, 0); add(cb, CL, SPL); check_bytes(cb, "4000E1");
cb_set_pos(cb, 0); add(cb, CX, BX); check_bytes(cb, "6601D9");
cb_set_pos(cb, 0); add(cb, RAX, RBX); check_bytes(cb, "4801D8");
cb_set_pos(cb, 0); add(cb, ECX, EDX); check_bytes(cb, "01D1");
cb_set_pos(cb, 0); add(cb, RDX, R14); check_bytes(cb, "4C01F2");
cb_set_pos(cb, 0); add(cb, mem_opnd(64, RAX, 0), RDX); check_bytes(cb, "480110");
cb_set_pos(cb, 0); add(cb, RDX, mem_opnd(64, RAX, 0)); check_bytes(cb, "480310");
cb_set_pos(cb, 0); add(cb, RDX, mem_opnd(64, RAX, 8)); check_bytes(cb, "48035008");
cb_set_pos(cb, 0); add(cb, RDX, mem_opnd(64, RAX, 255)); check_bytes(cb, "480390FF000000");
cb_set_pos(cb, 0); add(cb, mem_opnd(64, RAX, 127), imm_opnd(255)); check_bytes(cb, "4881407FFF000000");
cb_set_pos(cb, 0); add(cb, mem_opnd(32, RAX, 0), EDX); check_bytes(cb, "0110");
cb_set_pos(cb, 0); add(cb, RSP, imm_opnd(8)); check_bytes(cb, "4883C408");
cb_set_pos(cb, 0); add(cb, ECX, imm_opnd(8)); check_bytes(cb, "83C108");
cb_set_pos(cb, 0); add(cb, ECX, imm_opnd(255)); check_bytes(cb, "81C1FF000000");
// and
cb_set_pos(cb, 0); and(cb, EBP, R12D); check_bytes(cb, "4421E5");
cb_set_pos(cb, 0); and(cb, mem_opnd(64, RAX, 0), imm_opnd(0x08)); check_bytes(cb, "48832008");
// call
{
cb_set_pos(cb, 0);
uint32_t fn_label = cb_new_label(cb, "foo");
call_label(cb, fn_label);
cb_link_labels(cb);
check_bytes(cb, "E8FBFFFFFF");
}
cb_set_pos(cb, 0); call(cb, RAX); check_bytes(cb, "FFD0");
cb_set_pos(cb, 0); call(cb, mem_opnd(64, RSP, 8)); check_bytes(cb, "FF542408");
// cmovcc
cb_set_pos(cb, 0); cmovg(cb, ESI, EDI); check_bytes(cb, "0F4FF7");
cb_set_pos(cb, 0); cmovg(cb, ESI, mem_opnd(32, RBP, 12)); check_bytes(cb, "0F4F750C");
cb_set_pos(cb, 0); cmovl(cb, EAX, ECX); check_bytes(cb, "0F4CC1");
cb_set_pos(cb, 0); cmovl(cb, RBX, RBP); check_bytes(cb, "480F4CDD");
cb_set_pos(cb, 0); cmovle(cb, ESI, mem_opnd(32, RSP, 4)); check_bytes(cb, "0F4E742404");
// cmp
cb_set_pos(cb, 0); cmp(cb, CL, DL); check_bytes(cb, "38D1");
cb_set_pos(cb, 0); cmp(cb, ECX, EDI); check_bytes(cb, "39F9");
cb_set_pos(cb, 0); cmp(cb, RDX, mem_opnd(64, R12, 0)); check_bytes(cb, "493B1424");
cb_set_pos(cb, 0); cmp(cb, RAX, imm_opnd(2)); check_bytes(cb, "4883F802");
// cqo
cb_set_pos(cb, 0); cqo(cb); check_bytes(cb, "4899");
// div
/*
test(
delegate void (CodeBlock cb) { cb.div(X86Opnd(EDX)); },
"F7F2"
);
test(
delegate void (CodeBlock cb) { cb.div(X86Opnd(32, RSP, -12)); },
"F77424F4"
);
*/
// jcc to label
{
cb_set_pos(cb, 0);
uint32_t loop_label = cb_new_label(cb, "loop");
jge_label(cb, loop_label);
cb_link_labels(cb);
check_bytes(cb, "0F8DFAFFFFFF");
}
{
cb_set_pos(cb, 0);
uint32_t loop_label = cb_new_label(cb, "loop");
jo_label(cb, loop_label);
cb_link_labels(cb);
check_bytes(cb, "0F80FAFFFFFF");
}
// jmp to label
{
cb_set_pos(cb, 0);
uint32_t loop_label = cb_new_label(cb, "loop");
jmp_label(cb, loop_label);
cb_link_labels(cb);
check_bytes(cb, "E9FBFFFFFF");
}
// jmp with RM operand
cb_set_pos(cb, 0); jmp_rm(cb, R12); check_bytes(cb, "41FFE4");
// lea
cb_set_pos(cb, 0); lea(cb, RDX, mem_opnd(64, RCX, 8)); check_bytes(cb, "488D5108");
cb_set_pos(cb, 0); lea(cb, RAX, mem_opnd(8, RIP, 0)); check_bytes(cb, "488D0500000000");
cb_set_pos(cb, 0); lea(cb, RAX, mem_opnd(8, RIP, 5)); check_bytes(cb, "488D0505000000");
cb_set_pos(cb, 0); lea(cb, RDI, mem_opnd(8, RIP, 5)); check_bytes(cb, "488D3D05000000");
// mov
cb_set_pos(cb, 0); mov(cb, EAX, imm_opnd(7)); check_bytes(cb, "B807000000");
cb_set_pos(cb, 0); mov(cb, EAX, imm_opnd(-3)); check_bytes(cb, "B8FDFFFFFF");
cb_set_pos(cb, 0); mov(cb, R15, imm_opnd(3)); check_bytes(cb, "49BF0300000000000000");
cb_set_pos(cb, 0); mov(cb, EAX, EBX); check_bytes(cb, "89D8");
cb_set_pos(cb, 0); mov(cb, EAX, ECX); check_bytes(cb, "89C8");
cb_set_pos(cb, 0); mov(cb, EDX, mem_opnd(32, RBX, 128)); check_bytes(cb, "8B9380000000");
/*
test(
delegate void (CodeBlock cb) { cb.mov(X86Opnd(AL), X86Opnd(8, RCX, 0, 1, RDX)); },
"8A0411"
);
*/
cb_set_pos(cb, 0); mov(cb, CL, R9B); check_bytes(cb, "4488C9");
cb_set_pos(cb, 0); mov(cb, RBX, RAX); check_bytes(cb, "4889C3");
cb_set_pos(cb, 0); mov(cb, RDI, RBX); check_bytes(cb, "4889DF");
cb_set_pos(cb, 0); mov(cb, SIL, imm_opnd(11)); check_bytes(cb, "40B60B");
cb_set_pos(cb, 0); mov(cb, mem_opnd(8, RSP, 0), imm_opnd(-3)); check_bytes(cb, "C60424FD");
cb_set_pos(cb, 0); mov(cb, mem_opnd(64, RDI, 8), imm_opnd(1)); check_bytes(cb, "48C7470801000000");
// movsx
cb_set_pos(cb, 0); movsx(cb, AX, AL); check_bytes(cb, "660FBEC0");
cb_set_pos(cb, 0); movsx(cb, EDX, AL); check_bytes(cb, "0FBED0");
cb_set_pos(cb, 0); movsx(cb, RAX, BL); check_bytes(cb, "480FBEC3");
cb_set_pos(cb, 0); movsx(cb, ECX, AX); check_bytes(cb, "0FBFC8");
cb_set_pos(cb, 0); movsx(cb, R11, CL); check_bytes(cb, "4C0FBED9");
cb_set_pos(cb, 0); movsx(cb, R10, mem_opnd(32, RSP, 12)); check_bytes(cb, "4C6354240C");
cb_set_pos(cb, 0); movsx(cb, RAX, mem_opnd(8, RSP, 0)); check_bytes(cb, "480FBE0424");
// neg
cb_set_pos(cb, 0); neg(cb, RAX); check_bytes(cb, "48F7D8");
// nop
cb_set_pos(cb, 0); nop(cb, 1); check_bytes(cb, "90");
// not
cb_set_pos(cb, 0); not(cb, AX); check_bytes(cb, "66F7D0");
cb_set_pos(cb, 0); not(cb, EAX); check_bytes(cb, "F7D0");
cb_set_pos(cb, 0); not(cb, mem_opnd(64, R12, 0)); check_bytes(cb, "49F71424");
cb_set_pos(cb, 0); not(cb, mem_opnd(32, RSP, 301)); check_bytes(cb, "F794242D010000");
cb_set_pos(cb, 0); not(cb, mem_opnd(32, RSP, 0)); check_bytes(cb, "F71424");
cb_set_pos(cb, 0); not(cb, mem_opnd(32, RSP, 3)); check_bytes(cb, "F7542403");
cb_set_pos(cb, 0); not(cb, mem_opnd(32, RBP, 0)); check_bytes(cb, "F75500");
cb_set_pos(cb, 0); not(cb, mem_opnd(32, RBP, 13)); check_bytes(cb, "F7550D");
cb_set_pos(cb, 0); not(cb, RAX); check_bytes(cb, "48F7D0");
cb_set_pos(cb, 0); not(cb, R11); check_bytes(cb, "49F7D3");
cb_set_pos(cb, 0); not(cb, mem_opnd(32, RAX, 0)); check_bytes(cb, "F710");
cb_set_pos(cb, 0); not(cb, mem_opnd(32, RSI, 0)); check_bytes(cb, "F716");
cb_set_pos(cb, 0); not(cb, mem_opnd(32, RDI, 0)); check_bytes(cb, "F717");
cb_set_pos(cb, 0); not(cb, mem_opnd(32, RDX, 55)); check_bytes(cb, "F75237");
cb_set_pos(cb, 0); not(cb, mem_opnd(32, RDX, 1337)); check_bytes(cb, "F79239050000");
cb_set_pos(cb, 0); not(cb, mem_opnd(32, RDX, -55)); check_bytes(cb, "F752C9");
cb_set_pos(cb, 0); not(cb, mem_opnd(32, RDX, -555)); check_bytes(cb, "F792D5FDFFFF");
/*
test(
delegate void (CodeBlock cb) { cb.not(X86Opnd(32, RAX, 0, 1, RBX)); },
"F71418"
);
test(
delegate void (CodeBlock cb) { cb.not(X86Opnd(32, RAX, 0, 1, R12)); },
"42F71420"
);
test(
delegate void (CodeBlock cb) { cb.not(X86Opnd(32, R15, 0, 1, R12)); },
"43F71427"
);
test(
delegate void (CodeBlock cb) { cb.not(X86Opnd(32, R15, 5, 1, R12)); },
"43F7542705"
);
test(
delegate void (CodeBlock cb) { cb.not(X86Opnd(32, R15, 5, 8, R12)); },
"43F754E705"
);
test(
delegate void (CodeBlock cb) { cb.not(X86Opnd(32, R15, 5, 8, R13)); },
"43F754EF05"
);
test(
delegate void (CodeBlock cb) { cb.not(X86Opnd(32, R12, 5, 4, R9)); },
"43F7548C05"
);
test(
delegate void (CodeBlock cb) { cb.not(X86Opnd(32, R12, 301, 4, R9)); },
"43F7948C2D010000"
);
test(
delegate void (CodeBlock cb) { cb.not(X86Opnd(32, RAX, 5, 4, RDX)); },
"F7549005"
);
test(
delegate void (CodeBlock cb) { cb.not(X86Opnd(64, RAX, 0, 2, RDX)); },
"48F71450"
);
test(
delegate void (CodeBlock cb) { cb.not(X86Opnd(32, RSP, 0, 1, RBX)); },
"F7141C"
);
test(
delegate void (CodeBlock cb) { cb.not(X86Opnd(32, RSP, 3, 1, RBX)); },
"F7541C03"
);
test(
delegate void (CodeBlock cb) { cb.not(X86Opnd(32, RBP, 13, 1, RDX)); },
"F754150D"
);
*/
// or
cb_set_pos(cb, 0); or(cb, EDX, ESI); check_bytes(cb, "09F2");
// pop
cb_set_pos(cb, 0); pop(cb, RAX); check_bytes(cb, "58");
cb_set_pos(cb, 0); pop(cb, RBX); check_bytes(cb, "5B");
cb_set_pos(cb, 0); pop(cb, RSP); check_bytes(cb, "5C");
cb_set_pos(cb, 0); pop(cb, RBP); check_bytes(cb, "5D");
cb_set_pos(cb, 0); pop(cb, R12); check_bytes(cb, "415C");
cb_set_pos(cb, 0); pop(cb, mem_opnd(64, RAX, 0)); check_bytes(cb, "8F00");
cb_set_pos(cb, 0); pop(cb, mem_opnd(64, R8, 0)); check_bytes(cb, "418F00");
cb_set_pos(cb, 0); pop(cb, mem_opnd(64, R8, 3)); check_bytes(cb, "418F4003");
cb_set_pos(cb, 0); pop(cb, mem_opnd_sib(64, RAX, RCX, 8, 3)); check_bytes(cb, "8F44C803");
cb_set_pos(cb, 0); pop(cb, mem_opnd_sib(64, R8, RCX, 8, 3)); check_bytes(cb, "418F44C803");
// push
cb_set_pos(cb, 0); push(cb, RAX); check_bytes(cb, "50");
cb_set_pos(cb, 0); push(cb, RBX); check_bytes(cb, "53");
cb_set_pos(cb, 0); push(cb, R12); check_bytes(cb, "4154");
cb_set_pos(cb, 0); push(cb, mem_opnd(64, RAX, 0)); check_bytes(cb, "FF30");
cb_set_pos(cb, 0); push(cb, mem_opnd(64, R8, 0)); check_bytes(cb, "41FF30");
cb_set_pos(cb, 0); push(cb, mem_opnd(64, R8, 3)); check_bytes(cb, "41FF7003");
cb_set_pos(cb, 0); push(cb, mem_opnd_sib(64, RAX, RCX, 8, 3)); check_bytes(cb, "FF74C803");
cb_set_pos(cb, 0); push(cb, mem_opnd_sib(64, R8, RCX, 8, 3)); check_bytes(cb, "41FF74C803");
// ret
cb_set_pos(cb, 0); ret(cb); check_bytes(cb, "C3");
// sal
cb_set_pos(cb, 0); sal(cb, CX, imm_opnd(1)); check_bytes(cb, "66D1E1");
cb_set_pos(cb, 0); sal(cb, ECX, imm_opnd(1)); check_bytes(cb, "D1E1");
cb_set_pos(cb, 0); sal(cb, EBP, imm_opnd(5)); check_bytes(cb, "C1E505");
cb_set_pos(cb, 0); sal(cb, mem_opnd(32, RSP, 68), imm_opnd(1)); check_bytes(cb, "D1642444");
// sar
cb_set_pos(cb, 0); sar(cb, EDX, imm_opnd(1)); check_bytes(cb, "D1FA");
// shr
cb_set_pos(cb, 0); shr(cb, R14, imm_opnd(7)); check_bytes(cb, "49C1EE07");
/*
// sqrtsd
test(
delegate void (CodeBlock cb) { cb.sqrtsd(X86Opnd(XMM2), X86Opnd(XMM6)); },
"F20F51D6"
);
*/
// sub
cb_set_pos(cb, 0); sub(cb, EAX, imm_opnd(1)); check_bytes(cb, "83E801");
cb_set_pos(cb, 0); sub(cb, RAX, imm_opnd(2)); check_bytes(cb, "4883E802");
// test
cb_set_pos(cb, 0); test(cb, AL, AL); check_bytes(cb, "84C0");
cb_set_pos(cb, 0); test(cb, AX, AX); check_bytes(cb, "6685C0");
cb_set_pos(cb, 0); test(cb, CL, imm_opnd(8)); check_bytes(cb, "F6C108");
cb_set_pos(cb, 0); test(cb, DL, imm_opnd(7)); check_bytes(cb, "F6C207");
cb_set_pos(cb, 0); test(cb, RCX, imm_opnd(8)); check_bytes(cb, "F6C108");
cb_set_pos(cb, 0); test(cb, mem_opnd(8, RDX, 8), imm_opnd(8)); check_bytes(cb, "F6420808");
cb_set_pos(cb, 0); test(cb, mem_opnd(8, RDX, 8), imm_opnd(255)); check_bytes(cb, "F64208FF");
cb_set_pos(cb, 0); test(cb, DX, imm_opnd(0xFFFF)); check_bytes(cb, "66F7C2FFFF");
cb_set_pos(cb, 0); test(cb, mem_opnd(16, RDX, 8), imm_opnd(0xFFFF)); check_bytes(cb, "66F74208FFFF");
cb_set_pos(cb, 0); test(cb, mem_opnd(8, RSI, 0), imm_opnd(1)); check_bytes(cb, "F60601");
cb_set_pos(cb, 0); test(cb, mem_opnd(8, RSI, 16), imm_opnd(1)); check_bytes(cb, "F6461001");
cb_set_pos(cb, 0); test(cb, mem_opnd(8, RSI, -16), imm_opnd(1)); check_bytes(cb, "F646F001");
cb_set_pos(cb, 0); test(cb, mem_opnd(32, RSI, 64), EAX); check_bytes(cb, "854640");
cb_set_pos(cb, 0); test(cb, mem_opnd(64, RDI, 42), RAX); check_bytes(cb, "4885472A");
cb_set_pos(cb, 0); test(cb, RAX, RAX); check_bytes(cb, "4885C0");
cb_set_pos(cb, 0); test(cb, RAX, RSI); check_bytes(cb, "4885F0");
cb_set_pos(cb, 0); test(cb, mem_opnd(64, RSI, 64), imm_opnd(~0x08)); check_bytes(cb, "48F74640F7FFFFFF");
// xchg
cb_set_pos(cb, 0); xchg(cb, RAX, RCX); check_bytes(cb, "4891");
cb_set_pos(cb, 0); xchg(cb, RAX, R13); check_bytes(cb, "4995");
cb_set_pos(cb, 0); xchg(cb, RCX, RBX); check_bytes(cb, "4887D9");
cb_set_pos(cb, 0); xchg(cb, R9, R15); check_bytes(cb, "4D87F9");
// xor
cb_set_pos(cb, 0); xor(cb, EAX, EAX); check_bytes(cb, "31C0");
printf("Assembler tests done\n");
}
void assert_equal(expected, actual)
{
if (expected != actual) {
fprintf(stderr, "expected %d, got %d\n", expected, actual);
exit(-1);
}
}
void run_runtime_tests()
{
printf("Running runtime tests\n");
codeblock_t codeblock;
codeblock_t* cb = &codeblock;
uint8_t* mem_block = alloc_exec_mem(4096);
cb_init(cb, mem_block, 4096);
int (*function)(void);
function = (int (*)(void))mem_block;
#define TEST(BODY) cb_set_pos(cb, 0); BODY ret(cb); assert_equal(7, function());
// add
TEST({ mov(cb, RAX, imm_opnd(0)); add(cb, RAX, imm_opnd(7)); })
TEST({ mov(cb, RAX, imm_opnd(0)); mov(cb, RCX, imm_opnd(7)); add(cb, RAX, RCX); })
// and
TEST({ mov(cb, RAX, imm_opnd(31)); and(cb, RAX, imm_opnd(7)); })
TEST({ mov(cb, RAX, imm_opnd(31)); mov(cb, RCX, imm_opnd(7)); and(cb, RAX, RCX); })
// or
TEST({ mov(cb, RAX, imm_opnd(3)); or(cb, RAX, imm_opnd(4)); })
TEST({ mov(cb, RAX, imm_opnd(3)); mov(cb, RCX, imm_opnd(4)); or(cb, RAX, RCX); })
// push/pop
TEST({ mov(cb, RCX, imm_opnd(7)); push(cb, RCX); pop(cb, RAX); })
// shr
TEST({ mov(cb, RAX, imm_opnd(31)); shr(cb, RAX, imm_opnd(2)); })
// sub
TEST({ mov(cb, RAX, imm_opnd(12)); sub(cb, RAX, imm_opnd(5)); })
TEST({ mov(cb, RAX, imm_opnd(12)); mov(cb, RCX, imm_opnd(5)); sub(cb, RAX, RCX); })
// xor
TEST({ mov(cb, RAX, imm_opnd(13)); xor(cb, RAX, imm_opnd(10)); })
TEST({ mov(cb, RAX, imm_opnd(13)); mov(cb, RCX, imm_opnd(10)); xor(cb, RAX, RCX); })
#undef TEST
printf("Runtime tests done\n");
}
int main(int argc, char** argv)
{
run_assembler_tests();
run_runtime_tests();
return 0;
}