/* ** This file has been pre-processed with DynASM. ** http://luajit.org/dynasm.html ** DynASM version 1.3.0, DynASM x64 version 1.3.0 ** DO NOT EDIT! The original file is in "src/jit/x64/emit.dasc". */ #line 1 "src/jit/x64/emit.dasc" /* -*-C-*- */ #include "moar.h" #include "jit/internal.h" #ifndef _MSC_VER #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wimplicit-fallthrough" #endif #include "dasm_x86.h" #ifndef _MSC_VER #pragma GCC diagnostic pop #pragma GCC diagnostic ignored "-Wunused-variable" #endif #ifdef _MSC_VER #pragma warning( disable : 4129 ) #endif /** * CONVENTIONS * Much of this file contains snippets of assembly code, which are concatenated * at runtime in order to form a single executable routine. It is essential for * the correctness of the result that each of the snippets behaves * nicely. Because you can't be expected to know what that is, it is documented * here. * REGISTERS: * Register and calling conventions differ between POSIX and windows * systems. The registers rax, rcx, rdx, r8, r9, r10 and r11 are caller-saved, * meaning that you are free to overwrrite them, and functions you may call are * free to do thesame. Hence you should save their values on stack, if you wish * to keep them after calling. In contrast, rbx, rsp, rbp, and r12-r15 are * callee-saved, meaning that their values before entering and after returning * from a function must be the same. POSIX also makes rdi and rsi caller-saved, * windows makes them callee-saved. For this reason we avoid using them. The * first 4 (windows) or 6 (POSIX) function call arguments are placed in * registers. These registers sets are not the same between windows and POSIX, * but they're always caller-saved. * To deal with the ambiguity, register names have been aliased. * + RV stands for 'return value', and is aliased to rax * + TMP1-6 are the 6 shared caller-saved registers * + ARG1-4 are (different) aliases for argument registers * + TC, CU, WORK are registers that hold interpreter variables; these are callee- * saved registers set up at entry and restored at exit * + TMP5 (r10) is also aliased as FUNCTION; it never conflicts with an argument * register, and neither does TMP6. * + The suffixes d, w, and b stand for the 4, 2, and 1 byte-width value of the * registers. * Note that the current convention for function calls is to load the function * pointer as a 64 bit value in a register from the machine code, and call on * that register. This is not ideal, but call doesn't natively take 64 bit * values, and it is neccesary to ensure that the function lives within 32 bits * distance from the function otherwise. Other methods are being considered. * LABELS: * Don't use dynamic labels in this code, unless they have been passed to you * from outside. Dynamic labels need to be allocated and not conflict, hence * just picking one is typically unsafe. Local labels are usually safe. * WRITE BARRIERS: * Use of write barriers is tricky, because they may involve a function call, and * that may or may not mean you have to store your temporaries on the stack. * Hence, a write barrier (MVM_ASSIGN_REF) is split into two parts: * + check_wb (root, value, label) * + hit_wb (root, value) * You should have the label parameter point somewhere after hit_wb, and save * and restore your temporaries around the hit_wb. **/ //|.arch x64 #if DASM_VERSION != 10300 #error "Version mismatch between DynASM and included encoding engine" #endif #line 80 "src/jit/x64/emit.dasc" //|.actionlist actions static const unsigned char actions[6309] = { 254,0,85,72,137,229,255,72,129,250,236,0,1,0,0,255,76,137,117,250,248,76, 137,109,250,240,72,137,93,250,232,255,73,137,250,254,73,137,250,245,77,139, 158,231,73,139,155,231,255,72,141,68,36,250,248,73,137,134,231,255,250,255, 226,255,246,10,255,73,199,134,231,0,0,0,0,255,76,139,117,250,248,76,139,109, 250,240,72,139,93,250,232,255,72,137,250,236,93,195,255,72,185,235,235,72, 137,139,231,255,76,137,250,247,72,199,198,235,254,1,246,5,235,235,254,0,250, 255,21,242,5,73,139,142,231,72,139,137,231,72,139,137,231,72,137,136,231, 102,199,128,231,234,65,139,142,231,137,136,231,255,72,199,131,231,235,255, 73,139,141,231,72,139,137,231,72,137,139,231,255,73,139,142,231,72,139,137, 231,72,137,139,231,255,72,139,139,231,72,139,137,231,255,72,139,137,231,73, 139,150,231,72,139,146,231,72,133,201,72,15,68,202,255,77,139,158,231,255, 77,139,155,231,255,77,139,147,231,255,77,139,146,231,255,77,133,210,15,133, 242,247,255,76,137,250,247,76,137,222,72,199,194,235,254,1,250,255,21,242, 5,255,73,137,194,246,1,255,76,137,147,231,255,76,139,155,231,77,139,155,231, 255,72,139,145,231,255,76,139,131,231,76,137,130,231,255,102,250,247,129, 231,234,15,132,242,248,77,133,192,15,132,242,248,102,65,250,247,128,231,234, 15,133,242,248,76,137,194,72,137,206,76,137,250,247,254,1,250,255,21,242, 5,246,2,255,76,139,147,231,77,139,154,231,77,139,155,231,65,129,187,231,237, 15,132,242,247,102,65,250,247,130,231,234,15,132,242,247,76,137,250,247,72, 190,235,235,254,1,250,255,21,242,5,246,1,76,137,250,247,76,137,214,72,139, 147,231,254,1,250,255,21,242,5,72,137,131,231,255,250,255,21,242,5,246,1, 76,137,250,247,76,137,214,72,139,147,231,72,141,139,231,254,1,76,137,250, 247,255,73,139,181,231,72,139,182,231,72,199,194,235,72,141,139,231,254,1, 250,255,21,242,5,72,133,192,15,133,242,247,77,139,134,231,77,139,128,231, 76,137,131,231,246,1,255,73,139,142,231,255,72,139,145,231,76,139,131,231, 76,137,130,231,255,72,139,139,231,72,139,145,231,72,139,146,231,129,186,231, 237,15,133,242,247,102,250,247,129,231,234,15,132,242,248,246,1,76,137,250, 247,72,190,235,235,254,1,250,255,21,242,5,246,2,72,139,177,231,72,139,147, 231,76,137,250,247,254,1,73,139,142,231,72,139,145,231,102,139,146,231,72, 15,183,210,72,139,137,231,72,139,12,209,72,137,139,231,255,72,139,139,231, 255,72,141,145,231,255,72,141,145,231,76,139,137,231,77,141,145,231,77,133, 201,73,15,69,210,255,76,139,2,77,133,192,255,15,133,242,249,255,77,139,134, 231,77,139,128,231,246,3,255,76,139,2,255,77,133,192,15,133,242,250,255,77, 139,134,231,77,139,128,231,77,139,128,231,255,102,250,247,129,231,234,15, 132,242,249,77,133,192,15,132,242,249,102,65,250,247,128,231,234,15,133,242, 249,72,137,85,216,76,137,69,208,76,137,194,72,139,179,231,76,137,250,247, 254,1,250,255,21,242,5,76,139,69,208,72,139,85,216,246,3,255,76,137,2,246, 4,255,76,139,2,77,133,192,15,133,242,250,255,76,137,250,247,73,139,182,231, 72,139,182,231,72,139,182,231,254,1,250,255,21,242,5,73,137,192,255,72,139, 139,231,72,141,145,231,76,139,137,231,77,141,145,231,77,133,201,73,15,69, 210,255,250,255,21,242,5,76,139,69,208,72,139,85,216,246,3,76,137,2,255,68, 139,138,231,65,129,250,249,237,15,133,242,251,76,99,130,231,250,233,242,252, 246,5,76,137,250,247,72,137,214,254,1,250,255,21,242,5,73,137,192,246,6,255, 76,99,2,255,76,137,131,231,255,72,139,139,231,72,139,147,231,255,102,250, 247,129,231,234,15,132,242,248,72,133,210,15,132,242,248,102,250,247,130, 231,234,15,133,242,248,255,72,139,147,231,72,139,179,231,76,137,250,247,254, 1,250,255,21,242,5,72,139,139,231,72,139,147,231,246,2,255,137,145,231,255, 72,137,145,231,255,72,139,139,231,72,139,145,231,72,137,147,231,255,72,139, 139,231,72,139,145,231,72,133,210,15,133,242,247,73,139,150,231,72,139,146, 231,246,1,72,137,147,231,255,72,139,139,231,72,139,129,231,72,152,72,137, 131,231,255,72,139,139,231,72,139,147,231,72,139,137,231,72,137,17,255,72, 139,139,231,76,139,129,231,73,139,16,72,137,147,231,255,72,139,139,231,72, 139,147,231,76,141,129,231,73,131,184,231,0,15,132,242,247,77,139,128,231, 246,1,255,102,250,247,129,231,234,15,132,242,248,72,133,210,15,132,242,248, 102,250,247,130,231,234,15,133,242,248,72,137,85,216,76,137,69,208,72,139, 147,231,72,139,179,231,76,137,250,247,254,1,250,255,21,242,5,76,139,69,208, 72,139,85,216,246,2,255,65,137,144,231,255,73,137,144,231,255,72,139,139, 231,72,137,139,231,255,73,139,142,231,72,139,137,231,72,139,137,231,72,137, 139,231,255,76,137,250,247,73,139,182,231,254,1,72,139,139,231,102,250,247, 129,231,234,15,133,242,247,72,139,145,231,72,139,146,231,129,186,231,237, 15,132,242,248,246,1,76,137,250,247,72,190,235,235,254,1,250,255,21,242,5, 246,2,72,137,139,231,255,72,49,192,76,139,147,231,255,102,65,250,247,130, 231,234,15,133,242,247,77,139,154,231,77,139,155,231,65,129,187,231,237,15, 133,242,247,255,76,137,250,247,76,137,214,72,199,194,235,254,1,250,255,21, 242,5,72,137,131,231,250,233,242,248,246,1,76,137,250,247,72,190,235,235, 254,1,73,139,141,231,255,72,199,131,231,0,0,0,0,255,72,139,139,231,72,133, 201,15,148,210,72,15,182,210,72,137,147,231,255,72,129,131,231,237,255,72, 129,171,231,237,255,72,129,139,231,237,255,72,129,163,231,237,255,72,129, 179,231,237,255,72,139,131,231,255,72,1,131,231,255,72,41,131,231,255,72, 9,131,231,255,72,33,131,231,255,72,49,131,231,255,72,129,192,237,255,72,129, 250,232,237,255,72,129,200,237,255,72,129,224,237,255,72,129,250,240,237, 255,72,3,131,231,255,72,43,131,231,255,72,11,131,231,255,72,35,131,231,255, 72,51,131,231,255,72,15,175,131,231,255,138,139,231,72,211,224,255,138,139, 231,72,211,250,248,255,72,49,192,72,139,139,231,72,57,193,15,140,242,249, 72,250,255,192,76,139,131,231,246,1,72,250,247,193,1,0,0,0,15,132,242,248, 73,250,247,250,232,246,2,77,15,175,192,72,209,250,233,15,133,242,1,246,3, 72,137,131,231,255,72,139,131,231,72,139,139,231,72,131,250,249,0,15,133, 242,247,76,137,250,247,72,190,235,235,254,1,250,255,21,242,5,246,1,255,15, 156,214,72,131,250,248,0,15,156,210,48,250,242,68,15,182,194,72,153,72,250, 247,250,249,72,133,210,15,149,209,65,32,200,255,76,41,192,72,137,131,231, 255,250,255,21,242,5,246,1,72,153,72,250,247,250,249,72,137,147,231,255,72, 131,131,231,1,255,72,131,171,231,1,255,72,139,139,231,72,250,247,209,72,137, 139,231,255,72,139,139,231,72,250,247,217,72,137,139,231,255,72,139,139,231, 72,250,247,217,72,15,76,139,231,72,137,139,231,255,72,139,131,231,102,152, 152,72,152,72,137,131,231,255,72,139,139,231,72,49,210,136,202,72,137,147, 231,255,72,139,131,231,152,72,152,72,137,131,231,255,72,139,139,231,72,49, 210,102,137,202,72,137,147,231,255,72,139,131,231,72,152,72,137,131,231,255, 72,139,139,231,137,202,72,137,139,231,255,250,242,15,16,131,231,15,87,201, 250,242,15,194,193,4,102,72,15,126,193,72,131,225,1,72,137,139,231,255,250, 242,15,16,131,231,255,250,242,15,88,131,231,255,250,242,15,92,131,231,255, 250,242,15,89,131,231,255,250,242,15,94,131,231,255,250,242,15,17,131,231, 255,250,242,72,15,42,131,231,250,242,15,17,131,231,255,250,242,72,15,44,131, 231,72,137,131,231,255,72,199,193,1,0,0,0,72,193,225,63,72,139,147,231,72, 49,202,72,137,147,231,255,72,59,131,231,255,15,148,208,255,15,149,208,255, 15,156,208,255,15,146,208,255,15,158,208,255,15,150,208,255,15,159,208,255, 15,151,208,255,15,157,208,255,15,147,208,255,72,15,182,192,72,137,131,231, 255,72,59,139,231,255,15,159,210,255,15,151,210,255,72,15,182,210,255,65, 15,156,208,255,65,15,146,208,255,77,15,182,192,76,41,194,72,137,147,231,255, 72,199,194,1,0,0,0,255,72,199,194,250,255,250,255,250,255,250,255,255,72, 199,194,0,0,0,0,255,72,59,147,231,255,72,199,193,0,0,0,0,255,72,199,193,1, 0,0,0,255,250,242,15,16,131,231,102,15,46,131,231,255,15,147,209,255,15,155, 210,72,15,68,202,255,15,154,210,72,15,68,202,255,15,151,209,255,72,15,182, 201,72,137,139,231,255,250,242,15,16,131,231,250,242,15,16,139,231,102,15, 46,193,15,151,209,72,15,182,193,102,15,46,200,15,151,209,72,15,182,201,72, 41,200,72,137,131,231,255,76,137,250,247,72,139,179,231,72,139,147,231,254, 1,72,129,250,248,237,15,148,208,255,72,129,250,248,237,15,149,208,255,72, 139,139,231,72,133,201,15,132,242,247,72,139,137,231,72,139,137,231,72,129, 185,231,237,15,133,242,247,72,199,131,231,1,0,0,0,250,233,242,248,246,1,72, 199,131,231,0,0,0,0,246,2,255,72,139,139,231,72,139,145,231,72,131,194,1, 76,139,129,231,255,76,57,194,15,156,209,72,15,182,201,72,137,139,231,255, 76,139,155,231,77,133,219,15,132,242,247,76,137,250,247,73,139,179,231,76, 139,150,231,77,139,146,231,65,250,255,210,76,15,183,152,231,246,1,76,137, 155,231,255,76,139,155,231,77,133,219,15,132,242,247,73,139,179,231,76,139, 150,231,77,139,146,231,76,137,250,247,65,250,255,210,76,15,183,152,231,77, 133,219,15,132,242,247,76,15,183,152,231,246,1,76,137,155,231,255,76,139, 147,231,77,133,210,15,132,242,247,76,137,250,247,73,139,178,231,76,139,150, 231,77,139,146,231,65,250,255,210,76,15,183,152,231,77,133,219,15,132,242, 247,76,15,182,152,231,76,137,155,231,250,233,242,248,246,1,72,199,131,231, 0,0,0,0,246,2,255,72,139,139,231,72,133,201,15,149,210,77,139,134,231,77, 139,128,231,76,57,193,65,15,149,208,68,32,194,72,15,182,210,72,137,147,231, 255,76,139,147,231,77,139,154,231,77,139,155,231,65,129,187,231,237,15,132, 242,247,76,137,250,247,72,190,235,235,254,1,250,255,21,242,5,246,1,76,137, 250,247,76,137,214,254,1,250,255,21,242,5,246,1,76,137,250,247,72,139,179, 231,76,137,210,254,1,72,139,139,231,72,133,201,15,148,210,77,139,134,231, 77,139,128,231,76,57,193,65,15,148,208,68,8,194,72,15,182,210,72,137,147, 231,255,76,139,147,231,102,65,250,247,130,231,234,255,15,133,242,247,77,139, 154,231,77,139,155,231,77,133,219,255,15,132,242,247,76,137,250,247,76,137, 214,72,141,147,231,77,139,147,231,65,250,255,210,250,233,242,248,246,1,255, 76,137,147,231,246,2,255,72,139,139,231,72,133,201,15,132,242,247,72,139, 137,231,72,139,137,231,72,133,201,246,1,15,149,209,72,15,182,201,72,137,139, 231,255,72,139,139,231,72,133,201,15,132,242,247,102,250,247,129,231,234, 15,133,242,247,72,199,131,231,1,0,0,0,250,233,242,248,246,1,72,199,131,231, 0,0,0,0,246,2,255,102,250,247,129,231,234,15,133,242,247,72,139,145,231,72, 139,146,231,129,186,231,237,15,132,242,248,246,1,255,199,129,231,1,0,0,0, 255,73,139,142,231,72,133,201,15,133,242,247,73,139,142,231,72,139,137,231, 246,1,72,137,139,231,73,199,134,231,0,0,0,0,255,73,139,142,231,72,133,201, 15,132,242,247,72,139,137,231,72,137,139,231,250,233,242,248,246,1,73,139, 142,231,72,139,137,231,72,137,139,231,246,2,255,65,139,142,231,131,193,1, 65,137,142,231,72,137,139,231,255,65,139,142,231,131,250,233,1,65,137,142, 231,72,137,139,231,255,72,139,179,231,76,139,150,231,77,139,146,231,77,133, 210,15,133,242,247,76,137,250,247,72,190,235,235,254,1,250,255,21,242,5,246, 1,76,137,250,247,72,139,147,231,255,65,250,255,210,255,76,137,250,247,73, 139,182,231,72,139,182,231,72,139,182,231,72,141,182,231,72,139,182,231,72, 141,182,231,72,139,147,231,72,141,139,231,76,139,22,77,139,146,231,65,250, 255,210,72,133,192,15,133,242,247,77,139,134,231,77,139,128,231,76,137,131, 231,246,1,255,76,137,250,247,72,139,179,231,72,199,194,235,72,141,139,231, 254,1,73,139,182,231,72,141,182,231,72,139,150,231,102,68,139,146,231,102, 68,59,146,231,15,132,242,247,76,137,250,247,254,1,72,139,139,231,72,133,201, 15,133,242,247,76,137,250,247,73,139,182,231,72,139,182,231,72,139,182,231, 72,141,182,231,72,139,182,231,72,141,182,231,254,1,76,137,250,247,73,139, 182,231,72,139,182,231,72,199,194,235,254,1,76,137,250,247,73,139,182,231, 72,139,182,231,72,139,182,231,72,199,194,235,254,1,72,139,139,231,139,145, 231,77,49,192,131,250,250,0,15,142,242,247,77,139,134,231,77,139,128,231, 77,139,4,208,77,139,128,231,246,1,76,137,131,231,255,77,139,134,231,255,76, 137,250,247,72,139,179,231,255,250,255,21,242,5,246,2,72,139,145,231,72,137, 147,231,255,72,139,145,231,72,139,146,231,129,186,231,237,15,132,242,247, 255,250,255,21,242,5,246,1,72,139,147,231,72,137,145,231,102,250,247,129, 231,234,15,132,242,248,72,133,210,15,132,242,248,102,250,247,130,231,234, 15,133,242,248,72,137,210,72,137,206,76,137,250,247,254,1,77,139,134,231, 76,137,131,231,255,76,137,250,247,72,49,250,246,72,199,194,235,254,1,76,137, 250,247,72,139,183,231,72,49,250,246,254,1,76,137,250,247,72,139,179,231, 72,139,147,231,72,139,139,231,76,141,131,231,76,139,150,231,77,139,146,231, 77,139,146,231,65,250,255,210,255,76,137,250,247,72,139,179,231,76,139,150, 231,77,139,146,231,77,139,146,231,65,250,255,210,72,137,131,231,255,76,137, 250,247,72,139,179,231,72,139,147,231,76,139,150,231,77,139,146,231,77,139, 146,231,65,250,255,210,255,72,139,139,231,72,133,201,15,133,242,247,72,185, 235,235,250,233,242,248,246,1,72,185,235,235,246,2,72,137,139,231,255,76, 137,250,247,72,139,179,231,254,1,250,255,21,242,5,76,139,144,231,76,137,250, 247,72,139,179,231,65,250,255,210,72,137,131,231,255,250,255,21,242,5,76, 139,144,231,76,137,250,247,72,139,179,231,65,250,255,210,72,139,136,231,199, 129,231,1,0,0,0,72,137,131,231,255,76,139,155,231,77,139,147,231,77,139,146, 231,77,139,146,231,76,137,250,247,73,139,179,231,72,139,147,231,65,250,255, 210,72,139,139,231,72,137,139,231,255,72,139,139,231,72,131,250,249,14,15, 143,242,247,72,131,250,249,250,255,15,140,242,247,72,250,255,193,72,186,235, 235,72,139,20,202,72,137,147,231,250,233,242,248,246,1,255,72,137,131,231, 76,139,131,231,255,76,137,128,231,255,73,129,250,248,237,15,143,242,249,73, 129,250,248,237,15,140,242,249,199,128,231,235,68,137,128,231,250,233,242, 250,246,3,76,137,250,247,72,137,198,72,129,198,237,76,137,194,254,1,250,255, 21,242,5,246,4,255,72,139,139,231,72,139,147,231,68,139,137,231,65,129,250, 249,237,15,133,242,247,68,139,138,231,65,129,250,249,237,15,133,242,247,255, 68,139,137,231,255,68,3,138,231,255,68,43,138,231,255,68,15,175,138,231,255, 15,128,242,247,255,65,131,250,249,14,15,143,242,248,65,131,250,249,250,255, 15,140,242,248,65,250,255,193,72,186,235,235,74,139,20,202,72,137,147,231, 250,233,242,249,246,2,68,137,77,208,255,72,137,131,231,68,139,77,208,199, 128,231,235,68,137,136,231,72,137,131,231,250,233,242,249,255,76,137,250, 247,72,139,179,231,72,129,198,237,72,139,147,231,72,129,194,237,72,137,131, 231,72,137,193,72,129,193,237,255,72,139,139,231,68,139,137,231,65,129,250, 249,237,15,133,242,247,255,68,139,137,231,69,133,201,65,15,149,208,77,15, 182,192,76,137,131,231,250,233,242,248,246,1,255,76,139,137,231,69,139,129, 231,69,133,192,65,15,149,208,77,15,182,192,76,137,131,231,246,2,255,73,139, 190,231,72,141,191,231,254,1,250,255,21,242,5,76,137,250,247,73,139,182,231, 72,139,182,231,72,139,147,231,254,1,250,255,21,242,5,72,137,131,231,73,139, 190,231,72,141,191,231,254,1,77,137,250,243,255,77,137,250,235,255,77,139, 158,231,77,141,155,231,255,77,139,158,231,77,139,155,231,255,76,139,155,231, 255,76,141,155,231,255,77,139,157,231,77,139,155,231,255,73,199,195,235,255, 73,187,235,235,255,76,139,155,231,77,141,155,231,255,77,139,150,231,77,139, 18,77,49,219,102,69,139,154,231,78,139,28,219,255,76,141,29,243,255,77,139, 158,231,77,139,155,231,77,139,155,231,255,76,139,157,231,255,76,137,223,255, 76,137,222,255,76,137,218,255,76,137,217,255,77,137,216,255,77,137,217,255, 102,73,15,110,195,255,102,73,15,110,203,255,102,73,15,110,211,255,102,73, 15,110,219,255,102,73,15,110,227,255,102,73,15,110,250,235,255,102,73,15, 110,250,243,255,102,73,15,110,250,251,255,68,136,156,251,36,231,255,102,68, 137,156,251,36,231,255,76,137,156,251,36,231,255,72,133,192,15,148,210,72, 15,182,210,72,137,147,231,255,72,139,8,72,137,139,231,255,72,139,139,231, 72,137,8,255,73,139,142,231,72,139,9,72,49,210,102,139,145,231,72,137,4,211, 255,72,133,192,15,132,242,250,72,139,8,250,233,242,251,246,4,73,139,142,231, 72,139,137,231,246,5,72,137,139,231,255,102,152,255,72,152,255,72,37,250, 255,0,0,0,255,72,37,250,255,250,255,0,0,255,72,131,224,250,255,255,72,137, 133,231,255,73,131,190,231,0,15,132,242,247,76,137,250,247,254,1,250,233, 242,10,255,250,233,243,255,72,139,131,231,72,133,192,15,133,243,255,72,139, 131,231,72,133,192,15,132,243,255,102,72,15,110,131,231,102,15,87,201,102, 15,46,193,15,138,243,15,133,243,255,102,72,15,110,131,231,102,15,87,201,102, 15,46,193,15,138,242,247,15,133,242,247,250,233,243,246,1,255,250,255,21, 242,5,72,133,192,255,72,139,139,231,72,133,201,15,132,242,247,73,139,150, 231,72,139,146,231,72,57,209,15,132,242,247,250,233,243,246,1,255,72,139, 139,231,72,133,201,15,132,242,247,131,185,231,0,15,132,242,247,250,233,243, 246,1,255,72,139,139,231,72,133,201,15,132,243,131,185,231,0,15,132,243,246, 1,255,76,137,250,247,72,139,179,231,72,139,147,231,255,73,139,141,231,72, 139,137,231,254,1,72,131,250,248,250,255,255,15,142,243,255,15,138,242,247, 15,130,243,246,1,255,15,140,243,255,15,138,242,247,15,134,243,246,1,255,15, 138,242,247,15,132,243,246,1,255,15,138,243,255,15,131,243,255,15,141,243, 255,15,135,243,255,15,143,243,255,73,139,150,231,72,139,146,231,72,139,146, 231,255,72,133,201,15,132,242,247,255,72,59,145,231,15,133,242,247,255,102, 250,247,129,231,234,255,102,250,247,129,231,234,15,133,242,247,255,72,186, 235,235,76,139,129,231,73,59,144,231,15,133,242,247,255,72,57,202,15,133, 242,247,255,72,57,202,15,132,242,247,255,102,250,247,129,231,234,15,132,242, 247,255,76,139,145,231,77,139,146,231,77,139,146,231,77,133,210,15,132,242, 249,72,137,206,76,137,250,247,72,139,147,231,65,250,255,210,76,137,250,247, 72,139,179,231,72,137,179,231,254,1,250,255,21,242,5,76,137,250,247,254,1, 250,255,21,242,5,250,233,242,247,246,3,76,137,250,247,72,190,235,235,254, 1,250,233,242,10,246,2,255,246,5,255,73,139,150,231,72,139,18,77,139,150, 231,73,137,146,231,255,65,198,130,231,233,255,73,199,130,231,235,255,72,141, 147,231,73,137,146,231,255,76,137,250,247,72,139,179,231,72,199,194,235,73, 187,235,235,76,137,28,36,77,139,158,231,77,139,27,76,137,92,36,8,76,141,29, 242,5,76,137,92,36,16,254,1,76,137,250,247,73,187,235,235,76,137,28,36,77, 139,158,231,77,139,27,76,137,92,36,8,76,141,29,242,5,76,137,92,36,16,76,139, 147,231,77,139,146,231,65,250,255,210,255,73,186,235,235,65,250,255,210,255, 76,137,250,247,77,139,158,231,77,139,155,231,77,139,155,231,73,141,179,231, 72,139,182,231,72,141,182,231,72,139,22,255,73,139,141,231,72,139,137,231, 255,73,184,235,235,76,141,13,242,5,72,137,156,251,36,231,76,137,156,251,36, 231,73,199,195,250,255,250,255,250,255,250,255,76,137,156,251,36,231,255, 76,139,146,231,65,250,255,210,255,76,137,250,247,72,139,179,231,72,139,147, 231,72,141,139,231,254,1,246,5,234,234,254,0,73,139,150,231,72,139,18,77, 139,150,231,73,137,146,231,65,198,130,231,233,72,141,147,231,73,137,146,231, 255,72,185,235,235,72,139,9,255,72,139,139,231,72,131,250,249,0,15,140,242, 248,72,129,250,249,237,15,141,242,248,72,107,201,8,72,141,21,242,247,72,1, 202,250,255,226,248,7,246,1,255,247,250,233,243,248,7,255,205,3,255,64,252, 138,128,251,238,10,238,8,231,255,102,253,139,128,251,238,10,238,8,231,255, 72,252,139,128,251,238,10,238,8,231,255,250,242,253,15,16,128,251,238,10, 238,8,231,255,64,252,136,128,251,238,10,238,8,231,255,102,253,137,128,251, 238,10,238,8,231,255,72,252,137,128,251,238,10,238,8,231,255,250,242,253, 15,17,128,251,238,10,238,8,231,255,72,252,137,192,238,14,238,12,255,102,72, 252,15,126,192,238,14,238,12,255,250,243,253,15,126,192,238,14,238,12,255, 102,72,252,15,110,192,238,14,238,12,255,144,255,77,139,158,231,77,139,155, 231,77,133,219,15,133,242,247,250,233,242,10,246,1,255,72,252,141,128,251, 238,10,238,8,231,255,72,252,141,132,251,238,10,64,238,7,238,5,231,255,72, 252,141,132,251,238,10,192,238,15,238,13,231,255,72,252,199,192,238,12,235, 255,72,252,184,238,0,235,235,255,250,242,253,15,16,5,238,2,242,5,255,253, 138,128,251,238,10,238,8,231,255,64,252,138,132,251,238,10,192,238,15,238, 13,231,255,102,253,139,132,251,238,10,64,238,7,238,5,231,255,102,253,139, 132,251,238,10,192,238,15,238,13,231,255,72,252,139,132,251,238,10,192,238, 15,238,13,231,255,64,252,136,132,251,238,10,192,238,15,238,13,231,255,102, 253,137,132,251,238,10,192,238,15,238,13,231,255,72,252,137,132,251,238,10, 192,238,15,238,13,231,255,102,64,252,15,190,192,238,14,238,12,255,253,15, 191,192,238,14,238,12,255,72,252,15,190,192,238,14,238,12,255,72,252,15,191, 192,238,14,238,12,255,253,137,192,238,14,72,152,72,252,137,192,238,12,255, 64,252,15,182,192,238,14,238,12,255,102,64,252,15,182,192,238,14,238,12,255, 253,15,183,192,238,14,238,12,255,253,137,192,238,14,238,12,255,72,252,15, 182,192,238,14,238,12,255,72,252,15,183,192,238,14,238,12,255,102,64,252, 15,190,128,251,238,10,238,8,231,255,253,15,191,128,251,238,10,238,8,231,255, 72,252,15,190,128,251,238,10,238,8,231,255,72,252,15,191,128,251,238,10,238, 8,231,255,253,139,128,251,238,8,231,72,152,72,252,137,192,238,12,255,64,252, 15,182,128,251,238,10,238,8,231,255,102,64,252,15,182,128,251,238,10,238, 8,231,255,253,15,183,128,251,238,10,238,8,231,255,72,252,15,182,128,251,238, 10,238,8,231,255,72,252,15,183,128,251,238,10,238,8,231,255,72,252,1,192, 238,14,238,12,255,72,252,129,192,238,12,237,255,64,252,2,128,251,238,10,238, 8,231,255,102,253,3,128,251,238,10,238,8,231,255,72,252,3,128,251,238,10, 238,8,231,255,64,252,2,132,251,238,10,192,238,15,238,13,231,255,102,253,3, 132,251,238,10,192,238,15,238,13,231,255,72,252,3,132,251,238,10,192,238, 15,238,13,231,255,250,242,253,15,88,192,238,14,238,12,255,250,242,253,15, 92,192,238,14,238,12,255,250,242,253,15,89,192,238,14,238,12,255,72,252,33, 192,238,14,238,12,255,72,252,129,224,238,12,237,255,64,252,34,128,251,238, 10,238,8,231,255,102,253,35,128,251,238,10,238,8,231,255,72,252,35,128,251, 238,10,238,8,231,255,64,252,34,132,251,238,10,192,238,15,238,13,231,255,102, 253,35,132,251,238,10,192,238,15,238,13,231,255,72,252,35,132,251,238,10, 192,238,15,238,13,231,255,72,252,15,175,192,238,14,238,12,255,72,252,9,192, 238,14,238,12,255,72,252,49,192,238,14,238,12,255,72,252,250,247,208,238, 12,255,72,252,41,192,238,14,238,12,255,72,252,129,250,232,238,12,237,255, 64,252,42,128,251,238,10,238,8,231,255,102,253,43,128,251,238,10,238,8,231, 255,72,252,43,128,251,238,10,238,8,231,255,64,252,42,132,251,238,10,192,238, 15,238,13,231,255,102,253,43,132,251,238,10,192,238,15,238,13,231,255,72, 252,43,132,251,238,10,192,238,15,238,13,231,255,64,252,132,192,238,14,238, 12,255,102,253,133,192,238,14,238,12,255,72,252,133,192,238,14,238,12,255, 64,252,128,184,251,238,8,231,0,255,102,253,131,184,251,238,8,231,0,255,72, 252,131,184,251,238,8,231,0,255,64,252,128,188,251,192,238,15,238,13,231, 0,255,102,253,131,188,251,192,238,15,238,13,231,0,255,72,252,131,188,251, 192,238,15,238,13,231,0,255,64,252,250,246,192,238,12,233,255,102,253,250, 247,192,238,12,234,255,253,250,247,192,238,12,235,255,64,252,250,246,128, 251,238,8,231,233,255,102,253,250,247,128,251,238,8,231,234,255,253,250,247, 128,251,238,8,231,235,255,102,15,87,192,102,253,15,46,192,238,14,255,64,252, 56,192,238,14,238,12,255,102,253,57,192,238,14,238,12,255,72,252,57,192,238, 14,238,12,255,102,253,15,46,192,238,14,238,12,255,15,155,208,64,252,15,146, 208,238,12,64,252,32,192,238,12,255,15,155,208,64,252,15,150,208,238,12,64, 252,32,192,238,12,255,15,155,208,64,252,15,148,208,238,12,64,252,32,192,238, 12,255,15,154,208,64,252,15,149,208,238,12,64,252,8,192,238,12,255,64,252, 15,147,208,238,12,255,64,252,15,151,208,238,12,255,64,252,15,156,208,238, 12,255,64,252,15,158,208,238,12,255,64,252,15,148,208,238,12,255,64,252,15, 149,208,238,12,255,64,252,15,157,208,238,12,255,64,252,15,159,208,238,12, 255,72,252,141,5,238,2,243,255,250,242,253,15,16,192,238,14,255,253,250,255, 208,238,12,255,253,250,255,144,251,238,8,231,255 }; #line 81 "src/jit/x64/emit.dasc" //|.section code, data #define DASM_SECTION_CODE 0 #define DASM_SECTION_DATA 1 #define DASM_MAXSECTION 2 #line 82 "src/jit/x64/emit.dasc" //|.globals MVM_JIT_LABEL_ enum { MVM_JIT_LABEL_exit, MVM_JIT_LABEL__MAX }; #line 83 "src/jit/x64/emit.dasc" #if MVM_JIT_LABEL__MAX > MVM_JIT_MAX_GLOBALS #error "Not enough space for labels" #endif /* type declarations */ //|.type REGISTER, MVMRegister #define Dt1(_V) (int)(ptrdiff_t)&(((MVMRegister *)0)_V) #line 90 "src/jit/x64/emit.dasc" //|.type FRAME, MVMFrame #define Dt2(_V) (int)(ptrdiff_t)&(((MVMFrame *)0)_V) #line 91 "src/jit/x64/emit.dasc" //|.type ARGCTX, MVMArgProcContext #define Dt3(_V) (int)(ptrdiff_t)&(((MVMArgProcContext *)0)_V) #line 92 "src/jit/x64/emit.dasc" //|.type CALLSITE, MVMCallsite #define Dt4(_V) (int)(ptrdiff_t)&(((MVMCallsite *)0)_V) #line 93 "src/jit/x64/emit.dasc" //|.type CALLSITEPTR, MVMCallsite* #define Dt5(_V) (int)(ptrdiff_t)&(((MVMCallsite* *)0)_V) #line 94 "src/jit/x64/emit.dasc" //|.type ARGPROCCONTEXT, MVMArgProcContext #define Dt6(_V) (int)(ptrdiff_t)&(((MVMArgProcContext *)0)_V) #line 95 "src/jit/x64/emit.dasc" //|.type STATICFRAME, MVMStaticFrame #define Dt7(_V) (int)(ptrdiff_t)&(((MVMStaticFrame *)0)_V) #line 96 "src/jit/x64/emit.dasc" //|.type P6OPAQUE, MVMP6opaque #define Dt8(_V) (int)(ptrdiff_t)&(((MVMP6opaque *)0)_V) #line 97 "src/jit/x64/emit.dasc" //|.type P6OBODY, MVMP6opaqueBody #define Dt9(_V) (int)(ptrdiff_t)&(((MVMP6opaqueBody *)0)_V) #line 98 "src/jit/x64/emit.dasc" //|.type MVMITER, MVMIter #define DtA(_V) (int)(ptrdiff_t)&(((MVMIter *)0)_V) #line 99 "src/jit/x64/emit.dasc" //|.type MVMINSTANCE, MVMInstance #define DtB(_V) (int)(ptrdiff_t)&(((MVMInstance *)0)_V) #line 100 "src/jit/x64/emit.dasc" //|.type MVMACTIVEHANDLERS, MVMActiveHandler #define DtC(_V) (int)(ptrdiff_t)&(((MVMActiveHandler *)0)_V) #line 101 "src/jit/x64/emit.dasc" //|.type OBJECT, MVMObject #define DtD(_V) (int)(ptrdiff_t)&(((MVMObject *)0)_V) #line 102 "src/jit/x64/emit.dasc" //|.type STOOGE, MVMObjectStooge #define DtE(_V) (int)(ptrdiff_t)&(((MVMObjectStooge *)0)_V) #line 103 "src/jit/x64/emit.dasc" //|.type VMARRAY, MVMArray #define DtF(_V) (int)(ptrdiff_t)&(((MVMArray *)0)_V) #line 104 "src/jit/x64/emit.dasc" //|.type CARRAY, MVMCArray #define Dt10(_V) (int)(ptrdiff_t)&(((MVMCArray *)0)_V) #line 105 "src/jit/x64/emit.dasc" //|.type COLLECTABLE, MVMCollectable #define Dt11(_V) (int)(ptrdiff_t)&(((MVMCollectable *)0)_V) #line 106 "src/jit/x64/emit.dasc" //|.type STABLE, MVMSTable #define Dt12(_V) (int)(ptrdiff_t)&(((MVMSTable *)0)_V) #line 107 "src/jit/x64/emit.dasc" //|.type REPR, MVMREPROps #define Dt13(_V) (int)(ptrdiff_t)&(((MVMREPROps *)0)_V) #line 108 "src/jit/x64/emit.dasc" //|.type STRING, MVMString #define Dt14(_V) (int)(ptrdiff_t)&(((MVMString *)0)_V) #line 109 "src/jit/x64/emit.dasc" //|.type OBJECTPTR, MVMObject* #define Dt15(_V) (int)(ptrdiff_t)&(((MVMObject* *)0)_V) #line 110 "src/jit/x64/emit.dasc" //|.type CONTEXT, MVMContext #define Dt16(_V) (int)(ptrdiff_t)&(((MVMContext *)0)_V) #line 111 "src/jit/x64/emit.dasc" //|.type CONTAINERSPEC, MVMContainerSpec #define Dt17(_V) (int)(ptrdiff_t)&(((MVMContainerSpec *)0)_V) #line 112 "src/jit/x64/emit.dasc" //|.type STORAGESPEC, MVMStorageSpec #define Dt18(_V) (int)(ptrdiff_t)&(((MVMStorageSpec *)0)_V) #line 113 "src/jit/x64/emit.dasc" //|.type HLLCONFIG, MVMHLLConfig; #define Dt19(_V) (int)(ptrdiff_t)&(((MVMHLLConfig *)0)_V) #line 114 "src/jit/x64/emit.dasc" //|.type SCREF, MVMSerializationContext #define Dt1A(_V) (int)(ptrdiff_t)&(((MVMSerializationContext *)0)_V) #line 115 "src/jit/x64/emit.dasc" //|.type SCREFBODY, MVMSerializationContextBody #define Dt1B(_V) (int)(ptrdiff_t)&(((MVMSerializationContextBody *)0)_V) #line 116 "src/jit/x64/emit.dasc" //|.type NFGSYNTH, MVMNFGSynthetic #define Dt1C(_V) (int)(ptrdiff_t)&(((MVMNFGSynthetic *)0)_V) #line 117 "src/jit/x64/emit.dasc" //|.type CODE, MVMCode #define Dt1D(_V) (int)(ptrdiff_t)&(((MVMCode *)0)_V) #line 118 "src/jit/x64/emit.dasc" //|.type BIGINTBODY, MVMP6bigintBody #define Dt1E(_V) (int)(ptrdiff_t)&(((MVMP6bigintBody *)0)_V) #line 119 "src/jit/x64/emit.dasc" //|.type U8, MVMuint8 #define Dt1F(_V) (int)(ptrdiff_t)&(((MVMuint8 *)0)_V) #line 120 "src/jit/x64/emit.dasc" //|.type U16, MVMuint16 #define Dt20(_V) (int)(ptrdiff_t)&(((MVMuint16 *)0)_V) #line 121 "src/jit/x64/emit.dasc" //|.type U32, MVMuint32 #define Dt21(_V) (int)(ptrdiff_t)&(((MVMuint32 *)0)_V) #line 122 "src/jit/x64/emit.dasc" //|.type U64, MVMuint64 #define Dt22(_V) (int)(ptrdiff_t)&(((MVMuint64 *)0)_V) #line 123 "src/jit/x64/emit.dasc" //|.type MPINT, mp_int #define Dt23(_V) (int)(ptrdiff_t)&(((mp_int *)0)_V) #line 124 "src/jit/x64/emit.dasc" //|.type MVMDISPINLINECACHEENTRY, MVMDispInlineCacheEntry #define Dt24(_V) (int)(ptrdiff_t)&(((MVMDispInlineCacheEntry *)0)_V) #line 125 "src/jit/x64/emit.dasc" //|.type MVMDISPINLINECACHE, MVMDispInlineCache #define Dt25(_V) (int)(ptrdiff_t)&(((MVMDispInlineCache *)0)_V) #line 126 "src/jit/x64/emit.dasc" //|.type CFUNCTION, MVMCFunction #define Dt26(_V) (int)(ptrdiff_t)&(((MVMCFunction *)0)_V) #line 127 "src/jit/x64/emit.dasc" /* Static allocation of relevant types to registers. I pick * callee-save registers for efficiency. It is likely we'll be calling * quite a C functions, and this saves us the trouble of storing * them. Moreover, C compilers preferentially do not use callee-saved * registers, and so in most cases, these won't be touched at all. */ //|.type TC, MVMThreadContext, r14 #define Dt27(_V) (int)(ptrdiff_t)&(((MVMThreadContext *)0)_V) #line 134 "src/jit/x64/emit.dasc" /* Alternative base pointer. I'll be using this often, so picking rbx * here rather than the extended registers will lead to smaller * bytecode */ //|.type WORK, MVMRegister, rbx #define Dt28(_V) (int)(ptrdiff_t)&(((MVMRegister *)0)_V) #line 138 "src/jit/x64/emit.dasc" //|.type CU, MVMCompUnit, r13 #define Dt29(_V) (int)(ptrdiff_t)&(((MVMCompUnit *)0)_V) #line 139 "src/jit/x64/emit.dasc" MVMint32 MVM_jit_support(void) { #ifdef __i386__ /* Usually, this file should only be compiled only on a amd64 platform; but when compiling 'fat' or 'universal' binaries, we may compile it for other platform. In this case we use the runtime check to disable the JIT */ return 0; #else return 1; #endif } const unsigned char * MVM_jit_actions(void) { return actions; } /* C Call argument registers */ //|.if WIN32 //|.define ARG1, rcx //|.define ARG2, rdx //|.define ARG3, r8 //|.define ARG4, r9 //|.define ARG5, qword [rsp+0x20] //|.define ARG6, qword [rsp+0x28] //|.else //|.define ARG1, rdi //|.define ARG2, rsi //|.define ARG3, rdx //|.define ARG4, rcx //|.define ARG5, r8 //|.define ARG6, r9 //|.endif /* C call argument registers for floating point */ //|.if WIN32 //|.define ARG1F, xmm0 //|.define ARG2F, xmm1 //|.define ARG3F, xmm2 //|.define ARG4F, xmm3 //|.else //|.define ARG1F, xmm0 //|.define ARG2F, xmm1 //|.define ARG3F, xmm2 //|.define ARG4F, xmm3 //|.define ARG5F, xmm4 //|.define ARG6F, xmm5 //|.define ARG7F, xmm6 //|.define ARG8F, xmm7 //|.endif /* Special register for the function to be invoked * (chosen because it isn't involved in argument passing * and volatile) */ //|.define FUNCTION, r10 /* all-purpose temporary registers */ //|.define TMP1, rcx //|.define TMP2, rdx //|.define TMP3, r8 //|.define TMP4, r9 //|.define TMP5, r10 //|.define TMP6, r11 /* same, but 32 bits wide */ //|.define TMP1d, ecx //|.define TMP2d, edx //|.define TMP3d, r8d //|.define TMP4d, r9d //|.define TMP5d, r10d //|.define TMP6d, r11d /* and 16 bits wide */ //|.define TMP1w, cx //|.define TMP2w, dx //|.define TMP3w, r8w //|.define TMP4w, r9w //|.define TMP5w, r10w //|.define TMP6w, r11w /* and 8 bits for good measure */ //|.define TMP1b, cl //|.define TMP2b, dl //|.define TMP3b, r8b //|.define TMP4b, r9b //|.define TMP5b, r10b //|.define TMP6b, r11b /* return value */ //|.define RV, rax //|.define RVd, eax //|.define RVw, ax //|.define RVb, al //|.define RVF, xmm0 //|.macro callp, funcptr //|.data //|5: //|.dword (MVMuint32)((uintptr_t)(funcptr)), (MVMuint32)((uintptr_t)(funcptr) >> 32); //|.code //| call qword [<5]; //|.endmacro //|.macro check_wb, root, ref, lbl; //| test word COLLECTABLE:root->flags2, MVM_CF_SECOND_GEN; //| jz lbl; //| test ref, ref; //| jz lbl; //| test word COLLECTABLE:ref->flags2, MVM_CF_SECOND_GEN; //| jnz lbl; //|.endmacro; //|.macro hit_wb, obj, value //| mov ARG3, value //| mov ARG2, obj; //| mov ARG1, TC; //| callp &MVM_gc_write_barrier_hit_by; //|.endmacro //|.macro get_spesh_slot, reg, idx; //| mov reg, TC->cur_frame; //| mov reg, FRAME:reg->effective_spesh_slots; //| mov reg, OBJECTPTR:reg[idx]; //|.endmacro //|.macro get_vmnull, reg //| mov reg, TC->instance; //| mov reg, MVMINSTANCE:reg->VMNull; //|.endmacro //|.macro get_cur_op, reg //| mov reg, TC->interp_cur_op //| mov reg, [reg] //|.endmacro //|.macro get_string, reg, idx //|| MVM_cu_ensure_string_decoded(tc, jg->sg->sf->body.cu, idx); //| mov reg, CU->body.strings; //| mov reg, OBJECTPTR:reg[idx]; //|.endmacro //|.macro test_type_object, reg //| test word OBJECT:reg->header.flags1, MVM_CF_TYPE_OBJECT //|.endmacro //|.macro gc_sync_point //| cmp qword TC->gc_status, 0; //| je >1; //| mov ARG1, TC; //| callp &MVM_gc_enter_from_interrupt; //|1: //|.endmacro //|.macro throw_adhoc, msg //| mov ARG1, TC; //| mov64 ARG2, (uintptr_t)(msg); //| callp &MVM_exception_throw_adhoc; //|.endmacro //|.macro get_stable, out, in //| mov out, aword OBJECT:in->st; //|.endmacro //|.macro get_repr, out, in //| get_stable out, in; //| mov out, aword STABLE:out->REPR; //|.endmacro //|.macro cmp_repr_id, obj, tmp, id //| get_repr tmp, obj; //| cmp dword REPR:tmp->ID, id; //|.endmacro //|.define FRAME_NR, dword [rbp-0x20] /* A function prologue is always the same in x86 / x64, because * we do not provide variable arguments, instead arguments are provided * via a frame. All JIT entry points receive a prologue. */ void MVM_jit_emit_prologue(MVMThreadContext *tc, MVMJitCompiler *compiler, MVMJitGraph *jg) { //|.code dasm_put(Dst, 0); #line 323 "src/jit/x64/emit.dasc" /* Setup stack */ //| push rbp; //| mov rbp, rsp; dasm_put(Dst, 2); #line 326 "src/jit/x64/emit.dasc" /* allocate stack space: 0x100 bytes = 256 bytes * * layout: [ a: 0x20 | b: 0x40 | c: 0xa0 | d: 0x20 ] * a: space for 4 callee-save registers * b: small scratch space * c: space for stack arguments to c calls * d: reserve space for GPR registers to c calls (win64) or more space for * stack arguments (posix) */ //| sub rsp, 0x100; dasm_put(Dst, 7); #line 335 "src/jit/x64/emit.dasc" /* save callee-save registers */ //| mov [rbp-0x8], TC; //| mov [rbp-0x10], CU; //| mov [rbp-0x18], WORK; dasm_put(Dst, 16); #line 339 "src/jit/x64/emit.dasc" /* setup special frame variables */ //| mov TC, ARG1; //| mov CU, ARG2; //| mov TMP6, TC->cur_frame; //| mov WORK, FRAME:TMP6->work; dasm_put(Dst, 32, Dt27(->cur_frame), Dt2(->work)); #line 344 "src/jit/x64/emit.dasc" /* If in the future we call a function, the return address into the JIT * frame will be stored in this position. */ if (!jg->no_trampoline) { //| lea rax, [rsp-0x8]; //| mov aword TC->jit_return_address, rax; dasm_put(Dst, 49, Dt27(->jit_return_address)); #line 349 "src/jit/x64/emit.dasc" } /* ARG3 contains our 'entry label' */ //| jmp ARG3 dasm_put(Dst, 60); #line 352 "src/jit/x64/emit.dasc" } /* And a function epilogue is also always the same */ void MVM_jit_emit_epilogue(MVMThreadContext *tc, MVMJitCompiler *compiler, MVMJitGraph *jg) { //| ->exit: dasm_put(Dst, 64); #line 357 "src/jit/x64/emit.dasc" /* clear the return address, so that we know there's no longer a JIT frame * on the stack */ if (!jg->no_trampoline) { //| mov aword TC->jit_return_address, 0; dasm_put(Dst, 67, Dt27(->jit_return_address)); #line 361 "src/jit/x64/emit.dasc" } /* restore callee-save registers */ //| mov TC, [rbp-0x8]; //| mov CU, [rbp-0x10]; //| mov WORK, [rbp-0x18]; dasm_put(Dst, 76); #line 366 "src/jit/x64/emit.dasc" /* Restore stack */ //| mov rsp, rbp; //| pop rbp; //| ret; dasm_put(Dst, 92); #line 370 "src/jit/x64/emit.dasc" } static MVMuint64 try_emit_gen2_ref(MVMThreadContext *tc, MVMJitCompiler *compiler, MVMJitGraph *jg, MVMObject *obj, MVMint16 reg) { if (!(obj->header.flags2 & MVM_CF_SECOND_GEN)) return 0; //| mov64 TMP1, (uintptr_t)obj; //| mov WORK[reg], TMP1; dasm_put(Dst, 99, (unsigned int)((uintptr_t)obj), (unsigned int)(((uintptr_t)obj)>>32), Dt28([reg])); #line 378 "src/jit/x64/emit.dasc" return 1; } static MVMint64 fits_in_32_bit(MVMint64 number) { /* Used to determine if a 64 bit integer can be safely used as a * 32 bit constant for immediate mode access */ return (number >= INT32_MIN) && (number <= INT32_MAX); } static void emit_fastcreate(MVMThreadContext *tc, MVMJitCompiler *compiler, MVMJitGraph *jg, MVMSpeshIns *ins) { MVMuint16 size = ins->operands[1].lit_i16; MVMint16 spesh_idx = ins->operands[2].lit_i16; //| mov ARG1, TC; //| mov ARG2, size; //| callp &MVM_gc_allocate_nursery; dasm_put(Dst, 108, size); dasm_put(Dst, 118, (MVMuint32)((uintptr_t)(&MVM_gc_allocate_nursery)), (MVMuint32)((uintptr_t)(&MVM_gc_allocate_nursery) >> 32)); #line 394 "src/jit/x64/emit.dasc" //| get_spesh_slot TMP1, spesh_idx; //| mov aword OBJECT:RV->st, TMP1; // st is 64 bit (pointer) //| mov word OBJECT:RV->header.size, size; // object size is 16 bit //| mov TMP1d, dword TC->thread_id; // thread id is 32 bit //| mov dword OBJECT:RV->header.owner, TMP1d; // does this even work? dasm_put(Dst, 124, Dt27(->cur_frame), Dt2(->effective_spesh_slots), Dt15([spesh_idx]), DtD(->st), DtD(->header.size), size, Dt27(->thread_id), DtD(->header.owner)); #line 399 "src/jit/x64/emit.dasc" } /* compile per instruction, can't really do any better yet */ void MVM_jit_emit_primitive(MVMThreadContext *tc, MVMJitCompiler *compiler, MVMJitGraph *jg, MVMJitPrimitive * prim) { MVMSpeshIns *ins = prim->ins; MVMuint16 op = ins->info->opcode; /* Quite a few of these opcodes are copies. Ultimately, I want to * move copies to their own node (MVMJitCopy or such), and reduce * the number of copies (and thereby increase the efficiency), but * currently that isn't really feasible. */ switch (op) { case MVM_OP_const_i64_16: case MVM_OP_const_i64_32: { MVMint32 reg = ins->operands[0].reg.orig; /* Upgrade to 64 bit */ MVMint64 val = (op == MVM_OP_const_i64_16 ? (MVMint64)ins->operands[1].lit_i16 : (MVMint64)ins->operands[1].lit_i32); //| mov qword WORK[reg], val; dasm_put(Dst, 158, Dt28([reg]), val); #line 418 "src/jit/x64/emit.dasc" break; } case MVM_OP_const_i64: { MVMint32 reg = ins->operands[0].reg.orig; MVMint64 val = ins->operands[1].lit_i64; //| mov64 TMP1, val; //| mov WORK[reg], TMP1; dasm_put(Dst, 99, (unsigned int)(val), (unsigned int)((val)>>32), Dt28([reg])); #line 425 "src/jit/x64/emit.dasc" break; } case MVM_OP_const_n64: { MVMint16 reg = ins->operands[0].reg.orig; MVMint64 valbytes = ins->operands[1].lit_i64; //| mov64 TMP1, valbytes; //| mov WORK[reg], TMP1; dasm_put(Dst, 99, (unsigned int)(valbytes), (unsigned int)((valbytes)>>32), Dt28([reg])); #line 432 "src/jit/x64/emit.dasc" break; } case MVM_OP_inf: case MVM_OP_neginf: case MVM_OP_nan: { MVMint16 reg = ins->operands[0].reg.orig; MVMRegister tmp; if (op == MVM_OP_nan) tmp.n64 = MVM_num_nan(tc); else if (op == MVM_OP_inf) tmp.n64 = MVM_num_posinf(tc); else if (op == MVM_OP_neginf) tmp.n64 = MVM_num_neginf(tc); //| mov64 TMP1, tmp.i64; //| mov WORK[reg], TMP1; dasm_put(Dst, 99, (unsigned int)(tmp.i64), (unsigned int)((tmp.i64)>>32), Dt28([reg])); #line 447 "src/jit/x64/emit.dasc" break; } case MVM_OP_const_s: { MVMint16 reg = ins->operands[0].reg.orig; MVMuint32 idx = ins->operands[1].lit_str_idx; MVMStaticFrame *sf = jg->sg->sf; MVMString * s = MVM_cu_string(tc, sf->body.cu, idx); if (!try_emit_gen2_ref(tc, compiler, jg, (MVMObject*)s, reg)) { //| get_string TMP1, idx; MVM_cu_ensure_string_decoded(tc, jg->sg->sf->body.cu, idx); #line 456 "src/jit/x64/emit.dasc" //| mov WORK[reg], TMP1; dasm_put(Dst, 164, Dt29(->body.strings), Dt15([idx]), Dt28([reg])); #line 457 "src/jit/x64/emit.dasc" } break; } case MVM_OP_null: /* Runtime semantics of resumption setup are to null out a register to be * used for dispatch state, thus we compile it just like null. */ case MVM_OP_sp_resumption: { MVMint16 reg = ins->operands[0].reg.orig; //| get_vmnull TMP1; //| mov WORK[reg], TMP1; dasm_put(Dst, 177, Dt27(->instance), DtB(->VMNull), Dt28([reg])); #line 467 "src/jit/x64/emit.dasc" break; } case MVM_OP_getwhat: case MVM_OP_getwho: { MVMint16 dst = ins->operands[0].reg.orig; MVMint16 obj = ins->operands[1].reg.orig; //| mov TMP1, WORK[obj]; //| mov TMP1, OBJECT:TMP1->st; dasm_put(Dst, 190, Dt28([obj]), DtD(->st)); #line 475 "src/jit/x64/emit.dasc" if (op == MVM_OP_getwho) { //| mov TMP1, STABLE:TMP1->WHO; //| get_vmnull TMP2; //| test TMP1, TMP1; //| cmovz TMP1, TMP2; dasm_put(Dst, 199, Dt12(->WHO), Dt27(->instance), DtB(->VMNull)); #line 480 "src/jit/x64/emit.dasc" } else { //| mov TMP1, STABLE:TMP1->WHAT; dasm_put(Dst, 194, Dt12(->WHAT)); #line 482 "src/jit/x64/emit.dasc" } //| mov WORK[dst], TMP1; dasm_put(Dst, 103, Dt28([dst])); #line 484 "src/jit/x64/emit.dasc" break; } case MVM_OP_getlex: case MVM_OP_sp_getlex_o: case MVM_OP_sp_getlex_ins: { MVMuint16 *lexical_types; MVMStaticFrame * sf = jg->sg->sf; MVMint16 dst = ins->operands[0].reg.orig; MVMint16 idx = ins->operands[1].lex.idx; MVMint16 out = ins->operands[1].lex.outers; MVMint16 i; //| mov TMP6, TC->cur_frame; dasm_put(Dst, 219, Dt27(->cur_frame)); #line 496 "src/jit/x64/emit.dasc" for (i = 0; i < out; i++) { /* I'm going to skip compiling the check whether the outer * node really exists, because if the code has run N times * correctly, then the outer frame must have existed then, * and since this chain is static, it should still exist * now. If it doesn't exist, that means we crash. * * NB: inlining /might/ make this all wrong! But, if that * happens, the interpreter will panic even without JIT */ //| mov TMP6, FRAME:TMP6->outer; dasm_put(Dst, 224, Dt2(->outer)); #line 506 "src/jit/x64/emit.dasc" sf = sf->body.outer; } /* get array of lexicals */ //| mov TMP5, FRAME:TMP6->env; dasm_put(Dst, 229, Dt2(->env)); #line 510 "src/jit/x64/emit.dasc" /* read value */ //| mov TMP5, REGISTER:TMP5[idx]; dasm_put(Dst, 234, Dt1([idx])); #line 512 "src/jit/x64/emit.dasc" /* it seems that if at runtime, if the outer frame has been inlined, * this /could/ be wrong. But if that is so, the interpreted instruction * would also be wrong, because it'd refer to the wrong lexical. */ lexical_types = (!out && jg->sg->lexical_types ? jg->sg->lexical_types : sf->body.lexical_types); if (lexical_types[idx] == MVM_reg_obj) { /* if it is zero, check if we need to auto-vivify */ //| test TMP5, TMP5; //| jnz >1; dasm_put(Dst, 239); #line 522 "src/jit/x64/emit.dasc" /* setup args */ //| mov ARG1, TC; //| mov ARG2, TMP6; //| mov ARG3, idx; //| callp &MVM_frame_vivify_lexical; dasm_put(Dst, 247, idx); dasm_put(Dst, 118, (MVMuint32)((uintptr_t)(&MVM_frame_vivify_lexical)), (MVMuint32)((uintptr_t)(&MVM_frame_vivify_lexical) >> 32)); dasm_put(Dst, 260); #line 527 "src/jit/x64/emit.dasc" /* use return value for the result */ //| mov TMP5, RV; //|1: dasm_put(Dst, 266); #line 530 "src/jit/x64/emit.dasc" } /* store the value */ //| mov WORK[dst], TMP5; dasm_put(Dst, 272, Dt28([dst])); #line 533 "src/jit/x64/emit.dasc" break; } case MVM_OP_sp_getlexvia_o: case MVM_OP_sp_getlexvia_ins: { MVMint16 dst = ins->operands[0].reg.orig; MVMint16 idx = ins->operands[1].lit_ui16; MVMint16 out = ins->operands[2].lit_ui16; MVMint16 via = ins->operands[3].reg.orig; MVMint16 i; /* Resolve the frame. */ //| mov TMP6, WORK[via]; //| mov TMP6, CODE:TMP6->body.outer; dasm_put(Dst, 277, Dt28([via]), Dt1D(->body.outer)); #line 545 "src/jit/x64/emit.dasc" for (i = 1; i < out; i++) /* From 1 as we are already at outer */ //| mov TMP6, FRAME:TMP6->outer; dasm_put(Dst, 224, Dt2(->outer)); #line 547 "src/jit/x64/emit.dasc" /* get array of lexicals */ //| mov TMP5, FRAME:TMP6->env; dasm_put(Dst, 229, Dt2(->env)); #line 549 "src/jit/x64/emit.dasc" /* read value */ //| mov TMP5, REGISTER:TMP5[idx]; dasm_put(Dst, 234, Dt1([idx])); #line 551 "src/jit/x64/emit.dasc" if (op == MVM_OP_sp_getlexvia_o) { /* if it is zero, check if we need to auto-vivify */ //| test TMP5, TMP5; //| jnz >1; dasm_put(Dst, 239); #line 555 "src/jit/x64/emit.dasc" /* setup args */ //| mov ARG1, TC; //| mov ARG2, TMP6; //| mov ARG3, idx; //| callp &MVM_frame_vivify_lexical; dasm_put(Dst, 247, idx); dasm_put(Dst, 118, (MVMuint32)((uintptr_t)(&MVM_frame_vivify_lexical)), (MVMuint32)((uintptr_t)(&MVM_frame_vivify_lexical) >> 32)); dasm_put(Dst, 260); #line 560 "src/jit/x64/emit.dasc" /* use return value for the result */ //| mov TMP5, RV; //|1: dasm_put(Dst, 266); #line 563 "src/jit/x64/emit.dasc" } /* store the value */ //| mov WORK[dst], TMP5; dasm_put(Dst, 272, Dt28([dst])); #line 566 "src/jit/x64/emit.dasc" break; } case MVM_OP_sp_bindlexvia_os: case MVM_OP_sp_bindlexvia_in: { MVMint16 idx = ins->operands[0].lit_ui16; MVMint16 out = ins->operands[1].lit_ui16; MVMint16 via = ins->operands[2].reg.orig; MVMint16 src = ins->operands[3].reg.orig; MVMint16 i; /* Resolve the frame. */ //| mov TMP1, WORK[via]; //| mov TMP1, CODE:TMP1->body.outer; dasm_put(Dst, 190, Dt28([via]), Dt1D(->body.outer)); #line 578 "src/jit/x64/emit.dasc" for (i = 1; i < out; i++) /* From 1 as we are already at outer */ //| mov TMP1, FRAME:TMP1->outer; dasm_put(Dst, 194, Dt2(->outer)); #line 580 "src/jit/x64/emit.dasc" /* get array of lexicals */ //| mov TMP2, FRAME:TMP1->env; dasm_put(Dst, 286, Dt2(->env)); #line 582 "src/jit/x64/emit.dasc" /* bind the lexical, and write barrier if needed */ //| mov TMP3, WORK[src] //| mov REGISTER:TMP2[idx], TMP3; dasm_put(Dst, 291, Dt28([src]), Dt1([idx])); #line 585 "src/jit/x64/emit.dasc" if (op == MVM_OP_sp_bindlexvia_os) { //| check_wb TMP1, TMP3, >2; //| hit_wb TMP1, TMP3; dasm_put(Dst, 300, Dt11(->flags2), MVM_CF_SECOND_GEN, Dt11(->flags2), MVM_CF_SECOND_GEN); dasm_put(Dst, 118, (MVMuint32)((uintptr_t)(&MVM_gc_write_barrier_hit_by)), (MVMuint32)((uintptr_t)(&MVM_gc_write_barrier_hit_by) >> 32)); #line 588 "src/jit/x64/emit.dasc" //|2: dasm_put(Dst, 340); #line 589 "src/jit/x64/emit.dasc" } break; } case MVM_OP_getlexrel: { MVMint16 dst = ins->operands[0].reg.orig; MVMint16 ctx = ins->operands[1].reg.orig; MVMint16 name = ins->operands[2].reg.orig; //| mov TMP5, aword WORK[ctx]; //| cmp_repr_id TMP5, TMP6, MVM_REPR_ID_MVMContext; //| je >1; //| test_type_object TMP5; //| jz >1; //| throw_adhoc "getlexrel needs a context"; dasm_put(Dst, 348, Dt28([ctx]), DtD(->st), Dt12(->REPR), Dt13(->ID), MVM_REPR_ID_MVMContext, DtD(->header.flags1), MVM_CF_TYPE_OBJECT, (unsigned int)((uintptr_t)("getlexrel needs a context")), (unsigned int)(((uintptr_t)("getlexrel needs a context"))>>32)); dasm_put(Dst, 118, (MVMuint32)((uintptr_t)(&MVM_exception_throw_adhoc)), (MVMuint32)((uintptr_t)(&MVM_exception_throw_adhoc) >> 32)); #line 602 "src/jit/x64/emit.dasc" //|1: //| mov ARG1, TC; //| mov ARG2, TMP5; //| mov ARG3, aword WORK[name]; //| callp &MVM_context_lexical_lookup; dasm_put(Dst, 390, Dt28([name])); dasm_put(Dst, 118, (MVMuint32)((uintptr_t)(&MVM_context_lexical_lookup)), (MVMuint32)((uintptr_t)(&MVM_context_lexical_lookup) >> 32)); #line 607 "src/jit/x64/emit.dasc" //| mov WORK[dst], RV; dasm_put(Dst, 410, Dt28([dst])); #line 608 "src/jit/x64/emit.dasc" break; } case MVM_OP_getlexreldyn: { MVMint16 dst = ins->operands[0].reg.orig; MVMint16 ctx = ins->operands[1].reg.orig; MVMint16 name = ins->operands[2].reg.orig; //| mov TMP5, aword WORK[ctx]; //| cmp_repr_id TMP5, TMP6, MVM_REPR_ID_MVMContext; //| je >1; //| test_type_object TMP5; //| jz >1; //| throw_adhoc "getlexreldyn needs a context"; dasm_put(Dst, 348, Dt28([ctx]), DtD(->st), Dt12(->REPR), Dt13(->ID), MVM_REPR_ID_MVMContext, DtD(->header.flags1), MVM_CF_TYPE_OBJECT, (unsigned int)((uintptr_t)("getlexreldyn needs a context")), (unsigned int)(((uintptr_t)("getlexreldyn needs a context"))>>32)); dasm_put(Dst, 118, (MVMuint32)((uintptr_t)(&MVM_exception_throw_adhoc)), (MVMuint32)((uintptr_t)(&MVM_exception_throw_adhoc) >> 32)); #line 620 "src/jit/x64/emit.dasc" //|1: //| mov ARG1, TC; //| mov ARG2, TMP5; //| mov ARG3, aword WORK[name]; //| lea ARG4, WORK[dst]; //| callp &MVM_context_dynamic_lookup; dasm_put(Dst, 420, Dt28([name]), Dt28([dst])); dasm_put(Dst, 118, (MVMuint32)((uintptr_t)(&MVM_context_dynamic_lookup)), (MVMuint32)((uintptr_t)(&MVM_context_dynamic_lookup) >> 32)); dasm_put(Dst, 260); #line 626 "src/jit/x64/emit.dasc" break; } case MVM_OP_getlexrelcaller: { MVMint16 dst = ins->operands[0].reg.orig; MVMint16 ctx = ins->operands[1].reg.orig; MVMint16 name = ins->operands[2].reg.orig; //| mov TMP5, aword WORK[ctx]; //| cmp_repr_id TMP5, TMP6, MVM_REPR_ID_MVMContext; //| je >1; //| test_type_object TMP5; //| jz >1; //| throw_adhoc "getlexrelcaller needs a context"; dasm_put(Dst, 348, Dt28([ctx]), DtD(->st), Dt12(->REPR), Dt13(->ID), MVM_REPR_ID_MVMContext, DtD(->header.flags1), MVM_CF_TYPE_OBJECT, (unsigned int)((uintptr_t)("getlexrelcaller needs a context")), (unsigned int)(((uintptr_t)("getlexrelcaller needs a context"))>>32)); dasm_put(Dst, 118, (MVMuint32)((uintptr_t)(&MVM_exception_throw_adhoc)), (MVMuint32)((uintptr_t)(&MVM_exception_throw_adhoc) >> 32)); #line 638 "src/jit/x64/emit.dasc" //|1: //| mov ARG1, TC; //| mov ARG2, TMP5; //| mov ARG3, aword WORK[name]; //| callp &MVM_context_caller_lookup; dasm_put(Dst, 390, Dt28([name])); dasm_put(Dst, 118, (MVMuint32)((uintptr_t)(&MVM_context_caller_lookup)), (MVMuint32)((uintptr_t)(&MVM_context_caller_lookup) >> 32)); #line 643 "src/jit/x64/emit.dasc" //| mov WORK[dst], RV; dasm_put(Dst, 410, Dt28([dst])); #line 644 "src/jit/x64/emit.dasc" break; } case MVM_OP_getlex_no: case MVM_OP_sp_getlex_no: { MVMint16 dst = ins->operands[0].reg.orig; MVMuint32 idx = ins->operands[1].lit_str_idx; //| mov ARG1, TC; //| get_string ARG2, idx; dasm_put(Dst, 444); MVM_cu_ensure_string_decoded(tc, jg->sg->sf->body.cu, idx); #line 652 "src/jit/x64/emit.dasc" //| mov ARG3, MVM_reg_obj; //| lea ARG4, WORK[dst] //| callp &MVM_frame_find_lexical_by_name; dasm_put(Dst, 449, Dt29(->body.strings), Dt15([idx]), MVM_reg_obj, Dt28([dst])); dasm_put(Dst, 118, (MVMuint32)((uintptr_t)(&MVM_frame_find_lexical_by_name)), (MVMuint32)((uintptr_t)(&MVM_frame_find_lexical_by_name) >> 32)); #line 655 "src/jit/x64/emit.dasc" //| test RV, RV; //| jnz >1; //| get_vmnull TMP3; //| mov WORK[dst], TMP3; //|1: dasm_put(Dst, 467, Dt27(->instance), DtB(->VMNull), Dt28([dst])); #line 660 "src/jit/x64/emit.dasc" break; } case MVM_OP_bindlex: case MVM_OP_sp_bindlex_os: case MVM_OP_sp_bindlex_in: { MVMuint16 *lexical_types; MVMStaticFrame *sf = jg->sg->sf; MVMint16 idx = ins->operands[0].lex.idx; MVMint16 out = ins->operands[0].lex.outers; MVMint16 src = ins->operands[1].reg.orig; MVMint16 i; //| mov TMP1, TC->cur_frame; dasm_put(Dst, 494, Dt27(->cur_frame)); #line 672 "src/jit/x64/emit.dasc" for (i = 0; i < out; i++) { //| mov TMP1, FRAME:TMP1->outer; dasm_put(Dst, 194, Dt2(->outer)); #line 674 "src/jit/x64/emit.dasc" sf = sf->body.outer; } lexical_types = (!out && jg->sg->lexical_types ? jg->sg->lexical_types : sf->body.lexical_types); //| mov TMP2, FRAME:TMP1->env; //| mov TMP3, WORK[src]; //| mov REGISTER:TMP2[idx], TMP3; dasm_put(Dst, 499, Dt2(->env), Dt28([src]), Dt1([idx])); #line 682 "src/jit/x64/emit.dasc" if (lexical_types[idx] == MVM_reg_obj || lexical_types[idx] == MVM_reg_str) { //| check_wb TMP1, TMP3, >2; //| hit_wb TMP1, TMP3; dasm_put(Dst, 300, Dt11(->flags2), MVM_CF_SECOND_GEN, Dt11(->flags2), MVM_CF_SECOND_GEN); dasm_put(Dst, 118, (MVMuint32)((uintptr_t)(&MVM_gc_write_barrier_hit_by)), (MVMuint32)((uintptr_t)(&MVM_gc_write_barrier_hit_by) >> 32)); #line 686 "src/jit/x64/emit.dasc" //|2: dasm_put(Dst, 340); #line 687 "src/jit/x64/emit.dasc" } break; } case MVM_OP_lexprimspec: { MVMint16 dst = ins->operands[0].reg.orig; MVMint16 ctx = ins->operands[1].reg.orig; MVMint16 name = ins->operands[2].reg.orig; //| mov TMP1, WORK[ctx]; //| cmp_repr_id, TMP1, TMP2, MVM_REPR_ID_MVMContext; //| jne >1; //| test_type_object TMP1; //| jz >2; //|1: //| throw_adhoc "lexprimspec needs a context"; dasm_put(Dst, 512, Dt28([ctx]), DtD(->st), Dt12(->REPR), Dt13(->ID), MVM_REPR_ID_MVMContext, DtD(->header.flags1), MVM_CF_TYPE_OBJECT, (unsigned int)((uintptr_t)("lexprimspec needs a context")), (unsigned int)(((uintptr_t)("lexprimspec needs a context"))>>32)); dasm_put(Dst, 118, (MVMuint32)((uintptr_t)(&MVM_exception_throw_adhoc)), (MVMuint32)((uintptr_t)(&MVM_exception_throw_adhoc) >> 32)); #line 701 "src/jit/x64/emit.dasc" //|2: //| mov ARG2, CONTEXT:TMP1->body.context; //| mov ARG3, WORK[name]; //| mov ARG1, TC; //| callp &MVM_frame_lexical_primspec; dasm_put(Dst, 554, Dt16(->body.context), Dt28([name])); dasm_put(Dst, 118, (MVMuint32)((uintptr_t)(&MVM_frame_lexical_primspec)), (MVMuint32)((uintptr_t)(&MVM_frame_lexical_primspec) >> 32)); #line 706 "src/jit/x64/emit.dasc" //| mov WORK[dst], RV; dasm_put(Dst, 410, Dt28([dst])); #line 707 "src/jit/x64/emit.dasc" break; } case MVM_OP_sp_getarg_o: case MVM_OP_sp_getarg_n: case MVM_OP_sp_getarg_s: case MVM_OP_sp_getarg_i: { MVMint32 reg = ins->operands[0].reg.orig; MVMuint16 idx = ins->operands[1].callsite_idx; //| mov TMP1, TC->cur_frame; //| mov TMP2, FRAME:TMP1->params.arg_info.map; //| mov TMP2w, U16:TMP2[idx]; //| movzx TMP2, TMP2w //| mov TMP1, FRAME:TMP1->params.arg_info.source; //| mov TMP1, qword [TMP1 + TMP2 * 8]; //| mov WORK[reg], TMP1; dasm_put(Dst, 575, Dt27(->cur_frame), Dt2(->params.arg_info.map), Dt20([idx]), Dt2(->params.arg_info.source), Dt28([reg])); #line 722 "src/jit/x64/emit.dasc" break; } case MVM_OP_sp_p6oget_i: case MVM_OP_sp_p6oget_i32: case MVM_OP_sp_p6oget_n: case MVM_OP_sp_p6oget_s: case MVM_OP_sp_p6oget_bi: case MVM_OP_sp_p6oget_o: case MVM_OP_sp_p6ogetvc_o: case MVM_OP_sp_p6ogetvt_o: case MVM_OP_sp_getvc_o: case MVM_OP_sp_getvt_o: { MVMint16 dst = ins->operands[0].reg.orig; MVMint16 obj = ins->operands[1].reg.orig; MVMint16 body = offsetof(MVMP6opaque, body); MVMint16 offset = ins->operands[2].lit_i16; /* load address and object */ //| mov TMP1, WORK[obj]; dasm_put(Dst, 604, Dt28([obj])); #line 740 "src/jit/x64/emit.dasc" if (op == MVM_OP_sp_getvc_o || op == MVM_OP_sp_getvt_o) { //| lea TMP2, [TMP1 + offset]; dasm_put(Dst, 609, offset); #line 742 "src/jit/x64/emit.dasc" body = 0; /* Offset is already from the start of the object */ } else { //| lea TMP2, [TMP1 + (offset + body)]; //| mov TMP4, P6OPAQUE:TMP1->body.replaced; //| lea TMP5, [TMP4 + offset]; //| test TMP4, TMP4; //| cmovnz TMP2, TMP5; dasm_put(Dst, 614, (offset + body), Dt8(->body.replaced), offset); #line 750 "src/jit/x64/emit.dasc" } /* TMP2 now contains address of item */ if (op == MVM_OP_sp_p6oget_o) { //| mov TMP3, [TMP2]; //| test TMP3, TMP3; dasm_put(Dst, 634); #line 755 "src/jit/x64/emit.dasc" /* Check if object doesn't point to NULL */ //| jnz >3; dasm_put(Dst, 641); #line 757 "src/jit/x64/emit.dasc" /* Otherwise load VMNull */ //| get_vmnull TMP3; //|3: dasm_put(Dst, 646, Dt27(->instance), DtB(->VMNull)); #line 760 "src/jit/x64/emit.dasc" } else if (op == MVM_OP_sp_p6ogetvt_o || op == MVM_OP_sp_getvt_o) { /* vivify as type object */ MVMint16 spesh_idx = ins->operands[3].lit_i16; MVMCollectable *spesh_value = jg->sg->spesh_slots[spesh_idx]; //| mov TMP3, [TMP2]; dasm_put(Dst, 657); #line 765 "src/jit/x64/emit.dasc" /* check for null */ //| test TMP3, TMP3; //| jnz >4; dasm_put(Dst, 661); #line 768 "src/jit/x64/emit.dasc" /* if null, vivify as type object from spesh slot */ //| get_spesh_slot TMP3, spesh_idx; dasm_put(Dst, 669, Dt27(->cur_frame), Dt2(->effective_spesh_slots), Dt15([spesh_idx])); #line 770 "src/jit/x64/emit.dasc" if (!(spesh_value->flags2 & MVM_CF_SECOND_GEN)) { /* need to hit write barrier? */ //| check_wb TMP1, TMP3, >3; //| mov qword [rbp-0x28], TMP2; // address //| mov qword [rbp-0x30], TMP3; // value //| hit_wb WORK[obj], TMP3; // write barrier for header dasm_put(Dst, 682, Dt11(->flags2), MVM_CF_SECOND_GEN, Dt11(->flags2), MVM_CF_SECOND_GEN, Dt28([obj])); dasm_put(Dst, 118, (MVMuint32)((uintptr_t)(&MVM_gc_write_barrier_hit_by)), (MVMuint32)((uintptr_t)(&MVM_gc_write_barrier_hit_by) >> 32)); #line 776 "src/jit/x64/emit.dasc" //| mov TMP3, qword [rbp-0x30]; //| mov TMP2, qword [rbp-0x28]; //|3: dasm_put(Dst, 731); #line 779 "src/jit/x64/emit.dasc" } /* store vivified type value in memory location */ //| mov qword [TMP2], TMP3; //|4: dasm_put(Dst, 747); #line 783 "src/jit/x64/emit.dasc" } else if (op == MVM_OP_sp_p6ogetvc_o || op == MVM_OP_sp_getvc_o) { MVMint16 spesh_idx = ins->operands[3].lit_i16; //| mov TMP3, [TMP2]; //| test TMP3, TMP3; //| jnz >4; dasm_put(Dst, 753); #line 788 "src/jit/x64/emit.dasc" /* vivify as clone */ //| mov ARG1, TC; //| get_spesh_slot ARG2, spesh_idx; //| callp &MVM_repr_clone; dasm_put(Dst, 764, Dt27(->cur_frame), Dt2(->effective_spesh_slots), Dt15([spesh_idx])); dasm_put(Dst, 118, (MVMuint32)((uintptr_t)(&MVM_repr_clone)), (MVMuint32)((uintptr_t)(&MVM_repr_clone) >> 32)); #line 792 "src/jit/x64/emit.dasc" //| mov TMP3, RV; dasm_put(Dst, 782); #line 793 "src/jit/x64/emit.dasc" /* reload object and address */ //| mov TMP1, WORK[obj]; //| lea TMP2, [TMP1 + (offset + body)]; //| mov TMP4, P6OPAQUE:TMP1->body.replaced; //| lea TMP5, [TMP4 + offset]; //| test TMP4, TMP4; //| cmovnz TMP2, TMP5; dasm_put(Dst, 791, Dt28([obj]), (offset + body), Dt8(->body.replaced), offset); #line 800 "src/jit/x64/emit.dasc" /* assign with write barrier */ //| check_wb TMP1, TMP3, >3; //| mov qword [rbp-0x28], TMP2; // address //| mov qword [rbp-0x30], TMP3; // value //| hit_wb WORK[obj], TMP3; // write barrier for header dasm_put(Dst, 682, Dt11(->flags2), MVM_CF_SECOND_GEN, Dt11(->flags2), MVM_CF_SECOND_GEN, Dt28([obj])); dasm_put(Dst, 118, (MVMuint32)((uintptr_t)(&MVM_gc_write_barrier_hit_by)), (MVMuint32)((uintptr_t)(&MVM_gc_write_barrier_hit_by) >> 32)); #line 805 "src/jit/x64/emit.dasc" //| mov TMP3, qword [rbp-0x30]; //| mov TMP2, qword [rbp-0x28]; //|3: //| mov qword [TMP2], TMP3; dasm_put(Dst, 815); #line 809 "src/jit/x64/emit.dasc" /* done */ //|4: dasm_put(Dst, 750); #line 811 "src/jit/x64/emit.dasc" } else if (op == MVM_OP_sp_p6oget_bi) { /* Big integer case */ //| mov TMP4d, BIGINTBODY:TMP2->u.smallint.flag; //| cmp TMP4d, dword MVM_BIGINT_32_FLAG; //| jne >5; //| movsxd TMP3, dword BIGINTBODY:TMP2->u.smallint.value; //| jmp >6; //| 5: //| mov ARG1, TC; //| mov ARG2, TMP2; //| callp &MVM_p6bigint_get_int64; dasm_put(Dst, 834, Dt1E(->u.smallint.flag), MVM_BIGINT_32_FLAG, Dt1E(->u.smallint.value)); dasm_put(Dst, 118, (MVMuint32)((uintptr_t)(&MVM_p6bigint_get_int64)), (MVMuint32)((uintptr_t)(&MVM_p6bigint_get_int64) >> 32)); #line 822 "src/jit/x64/emit.dasc" //| mov TMP3, RV; //| 6: dasm_put(Dst, 866); #line 824 "src/jit/x64/emit.dasc" } else if (op == MVM_OP_sp_p6oget_i32) { //| movsxd TMP3, dword [TMP2]; dasm_put(Dst, 877); #line 826 "src/jit/x64/emit.dasc" } else { /* the regular case */ //| mov TMP3, [TMP2]; dasm_put(Dst, 657); #line 830 "src/jit/x64/emit.dasc" } /* store in local register */ //| mov WORK[dst], TMP3; dasm_put(Dst, 881, Dt28([dst])); #line 833 "src/jit/x64/emit.dasc" break; } case MVM_OP_sp_bind_i64: case MVM_OP_sp_bind_i32: case MVM_OP_sp_bind_n: case MVM_OP_sp_bind_s: case MVM_OP_sp_bind_s_nowb: case MVM_OP_sp_bind_o: { MVMint16 obj = ins->operands[0].reg.orig; MVMint16 offset = ins->operands[1].lit_i16; MVMint16 val = ins->operands[2].reg.orig; //| mov TMP1, WORK[obj]; // object //| mov TMP2, WORK[val]; // value dasm_put(Dst, 886, Dt28([obj]), Dt28([val])); #line 846 "src/jit/x64/emit.dasc" if (op == MVM_OP_sp_bind_o || op == MVM_OP_sp_bind_s) { /* check if we should hit write barrier */ //| check_wb TMP1, TMP2, >2; dasm_put(Dst, 895, Dt11(->flags2), MVM_CF_SECOND_GEN, Dt11(->flags2), MVM_CF_SECOND_GEN); #line 849 "src/jit/x64/emit.dasc" /* note: it is uneccesary to store pointers, because they can just be loaded from memory */ //| hit_wb WORK[obj], WORK[val]; dasm_put(Dst, 923, Dt28([val]), Dt28([obj])); dasm_put(Dst, 118, (MVMuint32)((uintptr_t)(&MVM_gc_write_barrier_hit_by)), (MVMuint32)((uintptr_t)(&MVM_gc_write_barrier_hit_by) >> 32)); #line 852 "src/jit/x64/emit.dasc" //| mov TMP1, aword WORK[obj]; // reload object //| mov TMP2, aword WORK[val]; // reload value //|2: // done dasm_put(Dst, 937, Dt28([obj]), Dt28([val])); #line 855 "src/jit/x64/emit.dasc" } if (op == MVM_OP_sp_bind_i32) { //| mov dword [TMP1+offset], TMP2d; // store value into body dasm_put(Dst, 953, offset); #line 858 "src/jit/x64/emit.dasc" } else { //| mov qword [TMP1+offset], TMP2; // store value into body dasm_put(Dst, 957, offset); #line 861 "src/jit/x64/emit.dasc" } break; } case MVM_OP_sp_get_i64: case MVM_OP_sp_get_n: case MVM_OP_sp_get_s: { MVMint16 dst = ins->operands[0].reg.orig; MVMint16 obj = ins->operands[1].reg.orig; MVMint16 offset = ins->operands[2].lit_i16; //| mov TMP1, WORK[obj]; // object //| mov TMP2, qword [TMP1+offset]; // get value from body //| mov WORK[dst], TMP2; dasm_put(Dst, 962, Dt28([obj]), offset, Dt28([dst])); #line 873 "src/jit/x64/emit.dasc" break; } case MVM_OP_sp_get_o: { MVMint16 dst = ins->operands[0].reg.orig; MVMint16 obj = ins->operands[1].reg.orig; MVMint16 offset = ins->operands[2].lit_i16; //| mov TMP1, WORK[obj]; // object //| mov TMP2, qword [TMP1+offset]; // get value from body //| test TMP2, TMP2; //| jnz >1; //| get_vmnull TMP2; //|1: //| mov WORK[dst], TMP2; dasm_put(Dst, 975, Dt28([obj]), offset, Dt27(->instance), DtB(->VMNull), Dt28([dst])); #line 886 "src/jit/x64/emit.dasc" break; } case MVM_OP_sp_get_i32: { MVMint16 dst = ins->operands[0].reg.orig; MVMint16 obj = ins->operands[1].reg.orig; MVMint16 offset = ins->operands[2].lit_i16; //| mov TMP1, WORK[obj]; // object //| mov RV, [TMP1+offset]; // get value from body //| cdqe; //| mov WORK[dst], RV; dasm_put(Dst, 1005, Dt28([obj]), offset, Dt28([dst])); #line 896 "src/jit/x64/emit.dasc" break; } case MVM_OP_sp_deref_bind_i64: case MVM_OP_sp_deref_bind_n: { MVMint16 obj = ins->operands[0].reg.orig; MVMint16 val = ins->operands[1].reg.orig; MVMint16 offset = ins->operands[2].lit_i16; //| mov TMP1, WORK[obj]; // object //| mov TMP2, WORK[val]; // value //| mov TMP1, qword [TMP1+offset]; // find address of target //| mov qword [TMP1], TMP2; dasm_put(Dst, 1020, Dt28([obj]), Dt28([val]), offset); #line 907 "src/jit/x64/emit.dasc" break; } case MVM_OP_sp_deref_get_i64: case MVM_OP_sp_deref_get_n: { MVMint16 dst = ins->operands[0].reg.orig; MVMint16 obj = ins->operands[1].reg.orig; MVMint16 offset = ins->operands[2].lit_i16; //| mov TMP1, WORK[obj]; // object //| mov TMP3, qword [TMP1+offset]; // get value pointer from body //| mov TMP2, qword [TMP3]; // deref the pointer //| mov WORK[dst], TMP2; dasm_put(Dst, 1036, Dt28([obj]), offset, Dt28([dst])); #line 918 "src/jit/x64/emit.dasc" break; } case MVM_OP_sp_p6obind_i: case MVM_OP_sp_p6obind_i32: case MVM_OP_sp_p6obind_n: case MVM_OP_sp_p6obind_s: case MVM_OP_sp_p6obind_o: { MVMint16 obj = ins->operands[0].reg.orig; MVMint16 offset = ins->operands[1].lit_i16; MVMint16 val = ins->operands[2].reg.orig; //| mov TMP1, WORK[obj]; // object //| mov TMP2, WORK[val]; // value //| lea TMP3, P6OPAQUE:TMP1->body; // body //| cmp qword P6OBODY:TMP3->replaced, 0; //| je >1; //| mov TMP3, P6OBODY:TMP3->replaced; // replaced object body //|1: dasm_put(Dst, 1052, Dt28([obj]), Dt28([val]), Dt8(->body), Dt9(->replaced), Dt9(->replaced)); #line 935 "src/jit/x64/emit.dasc" if (op == MVM_OP_sp_p6obind_o || op == MVM_OP_sp_p6obind_s) { /* check if we should hit write barrier */ //| check_wb TMP1, TMP2, >2; //| mov qword [rbp-0x28], TMP2; // store value //| mov qword [rbp-0x30], TMP3; // store body pointer //| hit_wb WORK[obj], WORK[val]; dasm_put(Dst, 1080, Dt11(->flags2), MVM_CF_SECOND_GEN, Dt11(->flags2), MVM_CF_SECOND_GEN, Dt28([val]), Dt28([obj])); dasm_put(Dst, 118, (MVMuint32)((uintptr_t)(&MVM_gc_write_barrier_hit_by)), (MVMuint32)((uintptr_t)(&MVM_gc_write_barrier_hit_by) >> 32)); #line 941 "src/jit/x64/emit.dasc" //| mov TMP3, qword [rbp-0x30]; // restore body pointer //| mov TMP2, qword [rbp-0x28]; // restore value //|2: // done dasm_put(Dst, 1129); #line 944 "src/jit/x64/emit.dasc" } if (op == MVM_OP_sp_p6obind_i32) { //| mov dword [TMP3+offset], TMP2d; // store value into body dasm_put(Dst, 1145, offset); #line 947 "src/jit/x64/emit.dasc" } else { //| mov [TMP3+offset], TMP2; // store value into body dasm_put(Dst, 1150, offset); #line 950 "src/jit/x64/emit.dasc" } break; } case MVM_OP_getwhere: case MVM_OP_set: { MVMint32 reg1 = ins->operands[0].reg.orig; MVMint32 reg2 = ins->operands[1].reg.orig; //| mov TMP1, WORK[reg2]; //| mov WORK[reg1], TMP1; dasm_put(Dst, 1155, Dt28([reg2]), Dt28([reg1])); #line 959 "src/jit/x64/emit.dasc" break; } case MVM_OP_sp_getspeshslot: { MVMint16 dst = ins->operands[0].reg.orig; MVMint16 spesh_idx = ins->operands[1].lit_i16; //| get_spesh_slot TMP1, spesh_idx; //| mov WORK[dst], TMP1; dasm_put(Dst, 1164, Dt27(->cur_frame), Dt2(->effective_spesh_slots), Dt15([spesh_idx]), Dt28([dst])); #line 966 "src/jit/x64/emit.dasc" break; } case MVM_OP_ctx: { MVMint16 dst = ins->operands[0].reg.orig; //| mov ARG1, TC; //| mov ARG2, TC->cur_frame; //| callp &MVM_context_from_frame; dasm_put(Dst, 1181, Dt27(->cur_frame)); dasm_put(Dst, 118, (MVMuint32)((uintptr_t)(&MVM_context_from_frame)), (MVMuint32)((uintptr_t)(&MVM_context_from_frame) >> 32)); #line 973 "src/jit/x64/emit.dasc" //| mov WORK[dst], RV; dasm_put(Dst, 410, Dt28([dst])); #line 974 "src/jit/x64/emit.dasc" break; } case MVM_OP_ctxlexpad: { MVMint16 src = ins->operands[1].reg.orig; MVMint16 dst = ins->operands[0].reg.orig; //| mov TMP1, WORK[src]; //| test_type_object TMP1; //| jnz >1; //| cmp_repr_id TMP1, TMP2, MVM_REPR_ID_MVMContext; //| je >2; //|1: //| throw_adhoc "ctxlexpad needs an MVMContext"; dasm_put(Dst, 1191, Dt28([src]), DtD(->header.flags1), MVM_CF_TYPE_OBJECT, DtD(->st), Dt12(->REPR), Dt13(->ID), MVM_REPR_ID_MVMContext, (unsigned int)((uintptr_t)("ctxlexpad needs an MVMContext")), (unsigned int)(((uintptr_t)("ctxlexpad needs an MVMContext"))>>32)); dasm_put(Dst, 118, (MVMuint32)((uintptr_t)(&MVM_exception_throw_adhoc)), (MVMuint32)((uintptr_t)(&MVM_exception_throw_adhoc) >> 32)); #line 986 "src/jit/x64/emit.dasc" //|2: //| mov WORK[dst], TMP1; dasm_put(Dst, 1233, Dt28([dst])); #line 988 "src/jit/x64/emit.dasc" break; } case MVM_OP_ctxcallerskipthunks: { MVMint16 dst = ins->operands[0].reg.orig; MVMint16 ctx = ins->operands[1].reg.orig; /* ctx = NULL */ //| xor RV, RV; //| mov TMP5, aword WORK[ctx]; dasm_put(Dst, 1245, Dt28([ctx])); #line 996 "src/jit/x64/emit.dasc" /* check concrete instance of type or throw */ //| test_type_object TMP5; //| jnz >1; //| cmp_repr_id TMP5, TMP6, MVM_REPR_ID_MVMContext; //| jne >1; dasm_put(Dst, 1253, DtD(->header.flags1), MVM_CF_TYPE_OBJECT, DtD(->st), Dt12(->REPR), Dt13(->ID), MVM_REPR_ID_MVMContext); #line 1001 "src/jit/x64/emit.dasc" /* Call function to create context. */ //| mov ARG1, TC //| mov ARG2, TMP5 //| mov ARG3, MVM_CTX_TRAV_CALLER_SKIP_THUNKS //| callp &MVM_context_apply_traversal; dasm_put(Dst, 1282, MVM_CTX_TRAV_CALLER_SKIP_THUNKS); dasm_put(Dst, 118, (MVMuint32)((uintptr_t)(&MVM_context_apply_traversal)), (MVMuint32)((uintptr_t)(&MVM_context_apply_traversal) >> 32)); #line 1006 "src/jit/x64/emit.dasc" //| mov WORK[dst], RV; //| jmp >2; //|1: //| throw_adhoc "ctxcallerskipthunks needs an MVMContext"; dasm_put(Dst, 1295, Dt28([dst]), (unsigned int)((uintptr_t)("ctxcallerskipthunks needs an MVMContext")), (unsigned int)(((uintptr_t)("ctxcallerskipthunks needs an MVMContext"))>>32)); dasm_put(Dst, 118, (MVMuint32)((uintptr_t)(&MVM_exception_throw_adhoc)), (MVMuint32)((uintptr_t)(&MVM_exception_throw_adhoc) >> 32)); #line 1010 "src/jit/x64/emit.dasc" //|2: dasm_put(Dst, 340); #line 1011 "src/jit/x64/emit.dasc" break; } case MVM_OP_curcode: { MVMint16 dst = ins->operands[0].reg.orig; //| mov TMP1, TC->cur_frame; //| mov TMP1, aword FRAME:TMP1->code_ref; //| mov aword WORK[dst], TMP1; dasm_put(Dst, 177, Dt27(->cur_frame), Dt2(->code_ref), Dt28([dst])); #line 1018 "src/jit/x64/emit.dasc" break; } case MVM_OP_getcode: { MVMint16 dst = ins->operands[0].reg.orig; MVMuint16 idx = ins->operands[1].coderef_idx; //| mov TMP1, aword CU->body.coderefs; //| mov TMP1, aword OBJECTPTR:TMP1[idx]; //| mov aword WORK[dst], TMP1; dasm_put(Dst, 164, Dt29(->body.coderefs), Dt15([idx]), Dt28([dst])); #line 1026 "src/jit/x64/emit.dasc" break; } case MVM_OP_hllboxtype_n: case MVM_OP_hllboxtype_s: case MVM_OP_hllboxtype_i: { MVMint16 dst = ins->operands[0].reg.orig; //| mov TMP1, CU->body.hll_config; dasm_put(Dst, 1320, Dt29(->body.hll_config)); #line 1033 "src/jit/x64/emit.dasc" if (op == MVM_OP_hllboxtype_n) { //| mov TMP1, aword HLLCONFIG:TMP1->num_box_type; dasm_put(Dst, 194, Dt19(->num_box_type)); #line 1035 "src/jit/x64/emit.dasc" } else if (op == MVM_OP_hllboxtype_s) { //| mov TMP1, aword HLLCONFIG:TMP1->str_box_type; dasm_put(Dst, 194, Dt19(->str_box_type)); #line 1037 "src/jit/x64/emit.dasc" } else { //| mov TMP1, aword HLLCONFIG:TMP1->int_box_type; dasm_put(Dst, 194, Dt19(->int_box_type)); #line 1039 "src/jit/x64/emit.dasc" } //| mov aword WORK[dst], TMP1; dasm_put(Dst, 103, Dt28([dst])); #line 1041 "src/jit/x64/emit.dasc" break; } case MVM_OP_null_s: { MVMint16 dst = ins->operands[0].reg.orig; //| mov qword WORK[dst], 0; dasm_put(Dst, 1325, Dt28([dst])); #line 1046 "src/jit/x64/emit.dasc" break; } case MVM_OP_isnull_s: { MVMint16 dst = ins->operands[0].reg.orig; MVMint16 src = ins->operands[1].reg.orig; //| mov TMP1, WORK[src]; //| test TMP1, TMP1; //| setz TMP2b; //| movzx TMP2, TMP2b; //| mov qword WORK[dst], TMP2; dasm_put(Dst, 1334, Dt28([src]), Dt28([dst])); #line 1056 "src/jit/x64/emit.dasc" break; } case MVM_OP_add_i: case MVM_OP_sub_i: case MVM_OP_bor_i: case MVM_OP_band_i: case MVM_OP_bxor_i: { MVMint32 reg_a = ins->operands[0].reg.orig; MVMint32 reg_b = ins->operands[1].reg.orig; MVMint32 reg_c = ins->operands[2].reg.orig; MVMSpeshFacts *operand_facts = MVM_spesh_get_facts(tc, jg->sg, ins->operands[2]); if (reg_a == reg_b) { if (operand_facts->flags & MVM_SPESH_FACT_KNOWN_VALUE && fits_in_32_bit(operand_facts->value.i)) { MVMint64 value = operand_facts->value.i; MVM_spesh_graph_add_comment(tc, jg->sg, ins, "JIT optimized to memory/constant operation"); switch(ins->info->opcode) { case MVM_OP_add_i: //| add qword WORK[reg_a], qword value; dasm_put(Dst, 1353, Dt28([reg_a]), value); #line 1077 "src/jit/x64/emit.dasc" break; case MVM_OP_sub_i: //| sub qword WORK[reg_a], qword value; dasm_put(Dst, 1359, Dt28([reg_a]), value); #line 1080 "src/jit/x64/emit.dasc" break; case MVM_OP_bor_i: //| or qword WORK[reg_a], qword value; dasm_put(Dst, 1365, Dt28([reg_a]), value); #line 1083 "src/jit/x64/emit.dasc" break; case MVM_OP_band_i: //| and qword WORK[reg_a], qword value; dasm_put(Dst, 1371, Dt28([reg_a]), value); #line 1086 "src/jit/x64/emit.dasc" break; case MVM_OP_bxor_i: //| xor qword WORK[reg_a], qword value; dasm_put(Dst, 1377, Dt28([reg_a]), value); #line 1089 "src/jit/x64/emit.dasc" break; } } else { MVM_spesh_graph_add_comment(tc, jg->sg, ins, "JIT optimized to memory/register operation"); //| mov rax, WORK[reg_c]; dasm_put(Dst, 1383, Dt28([reg_c])); #line 1094 "src/jit/x64/emit.dasc" switch(ins->info->opcode) { case MVM_OP_add_i: //| add WORK[reg_a], rax; dasm_put(Dst, 1388, Dt28([reg_a])); #line 1097 "src/jit/x64/emit.dasc" break; case MVM_OP_sub_i: //| sub WORK[reg_a], rax; dasm_put(Dst, 1393, Dt28([reg_a])); #line 1100 "src/jit/x64/emit.dasc" break; case MVM_OP_bor_i: //| or WORK[reg_a], rax; dasm_put(Dst, 1398, Dt28([reg_a])); #line 1103 "src/jit/x64/emit.dasc" break; case MVM_OP_band_i: //| and WORK[reg_a], rax; dasm_put(Dst, 1403, Dt28([reg_a])); #line 1106 "src/jit/x64/emit.dasc" break; case MVM_OP_bxor_i: //| xor WORK[reg_a], rax; dasm_put(Dst, 1408, Dt28([reg_a])); #line 1109 "src/jit/x64/emit.dasc" break; } } } else { if (operand_facts->flags & MVM_SPESH_FACT_KNOWN_VALUE && fits_in_32_bit(operand_facts->value.i)) { MVMint64 value = operand_facts->value.i; MVM_spesh_graph_add_comment(tc, jg->sg, ins, "JIT optimized to register/constant operation"); //| mov rax, WORK[reg_b]; dasm_put(Dst, 1383, Dt28([reg_b])); #line 1118 "src/jit/x64/emit.dasc" switch(ins->info->opcode) { case MVM_OP_add_i: //| add rax, qword value; dasm_put(Dst, 1413, value); #line 1121 "src/jit/x64/emit.dasc" break; case MVM_OP_sub_i: //| sub rax, qword value; dasm_put(Dst, 1418, value); #line 1124 "src/jit/x64/emit.dasc" break; case MVM_OP_bor_i: //| or rax, qword value; dasm_put(Dst, 1424, value); #line 1127 "src/jit/x64/emit.dasc" break; case MVM_OP_band_i: //| and rax, qword value; dasm_put(Dst, 1429, value); #line 1130 "src/jit/x64/emit.dasc" break; case MVM_OP_bxor_i: //| xor rax, qword value; dasm_put(Dst, 1434, value); #line 1133 "src/jit/x64/emit.dasc" break; } //| mov WORK[reg_a], rax; dasm_put(Dst, 415, Dt28([reg_a])); #line 1136 "src/jit/x64/emit.dasc" } else { //| mov rax, WORK[reg_b]; dasm_put(Dst, 1383, Dt28([reg_b])); #line 1138 "src/jit/x64/emit.dasc" switch(ins->info->opcode) { case MVM_OP_add_i: //| add rax, WORK[reg_c]; dasm_put(Dst, 1440, Dt28([reg_c])); #line 1141 "src/jit/x64/emit.dasc" break; case MVM_OP_sub_i: //| sub rax, WORK[reg_c]; dasm_put(Dst, 1445, Dt28([reg_c])); #line 1144 "src/jit/x64/emit.dasc" break; case MVM_OP_bor_i: //| or rax, WORK[reg_c]; dasm_put(Dst, 1450, Dt28([reg_c])); #line 1147 "src/jit/x64/emit.dasc" break; case MVM_OP_band_i: //| and rax, WORK[reg_c]; dasm_put(Dst, 1455, Dt28([reg_c])); #line 1150 "src/jit/x64/emit.dasc" break; case MVM_OP_bxor_i: //| xor rax, WORK[reg_c]; dasm_put(Dst, 1460, Dt28([reg_c])); #line 1153 "src/jit/x64/emit.dasc" break; } //| mov WORK[reg_a], rax; dasm_put(Dst, 415, Dt28([reg_a])); #line 1156 "src/jit/x64/emit.dasc" } } break; } case MVM_OP_mul_i: case MVM_OP_blshift_i: case MVM_OP_brshift_i: { MVMint32 reg_a = ins->operands[0].reg.orig; MVMint32 reg_b = ins->operands[1].reg.orig; MVMint32 reg_c = ins->operands[2].reg.orig; //| mov rax, WORK[reg_b]; dasm_put(Dst, 1383, Dt28([reg_b])); #line 1167 "src/jit/x64/emit.dasc" switch(ins->info->opcode) { case MVM_OP_mul_i: //| imul rax, WORK[reg_c]; dasm_put(Dst, 1465, Dt28([reg_c])); #line 1170 "src/jit/x64/emit.dasc" break; case MVM_OP_blshift_i: //| mov cl, byte WORK[reg_c]; //| shl rax, cl; dasm_put(Dst, 1471, Dt28([reg_c])); #line 1174 "src/jit/x64/emit.dasc" break; case MVM_OP_brshift_i: //| mov cl, byte WORK[reg_c]; //| sar rax, cl; dasm_put(Dst, 1478, Dt28([reg_c])); #line 1178 "src/jit/x64/emit.dasc" break; } //| mov WORK[reg_a], rax; dasm_put(Dst, 415, Dt28([reg_a])); #line 1181 "src/jit/x64/emit.dasc" break; } case MVM_OP_pow_i: { MVMint16 dst = ins->operands[0].reg.orig; MVMint16 base = ins->operands[1].reg.orig; MVMint16 exp = ins->operands[2].reg.orig; //| xor rax, rax; //| mov rcx, WORK[exp]; //| cmp rcx, rax; //| jl >3; //| inc rax; //| mov r8, WORK[base]; //|1: //| test rcx, 1; //| jz >2; //| imul r8; //|2: //| imul r8, r8; //| shr rcx, 1; //| jnz <1; //|3: //| mov WORK[dst], rax; dasm_put(Dst, 1486, Dt28([exp]), Dt28([base]), Dt28([dst])); #line 1203 "src/jit/x64/emit.dasc" break; } case MVM_OP_div_i: { MVMint16 dst = ins->operands[0].reg.orig; MVMint16 a = ins->operands[1].reg.orig; MVMint16 b = ins->operands[2].reg.orig; //| mov rax, WORK[a]; //| mov rcx, WORK[b]; //| cmp rcx, 0; //| jnz >1; //| throw_adhoc "Division by zero"; dasm_put(Dst, 1548, Dt28([a]), Dt28([b]), (unsigned int)((uintptr_t)("Division by zero")), (unsigned int)(((uintptr_t)("Division by zero"))>>32)); dasm_put(Dst, 118, (MVMuint32)((uintptr_t)(&MVM_exception_throw_adhoc)), (MVMuint32)((uintptr_t)(&MVM_exception_throw_adhoc) >> 32)); #line 1214 "src/jit/x64/emit.dasc" //|1: dasm_put(Dst, 1575); #line 1215 "src/jit/x64/emit.dasc" /* either num < 0, or denom < 0, but not both */ //| setl dh; //| cmp rax, 0; //| setl dl; //| xor dl, dh; //| movzx r8d, dl; //| cqo; //| idiv rcx; //| test rdx, rdx; //| setnz cl; //| and r8b, cl; dasm_put(Dst, 1583); #line 1226 "src/jit/x64/emit.dasc" /* r8 = bias = (modulo != 0) & ((num < 0) ^ (denom < 0)) */ //| sub rax, r8; //| mov WORK[dst], rax; dasm_put(Dst, 1618, Dt28([dst])); #line 1229 "src/jit/x64/emit.dasc" break; } case MVM_OP_mod_i: { MVMint16 dst = ins->operands[0].reg.orig; MVMint16 a = ins->operands[1].reg.orig; MVMint16 b = ins->operands[2].reg.orig; //| mov rax, WORK[a]; //| mov rcx, WORK[b]; //| cmp rcx, 0; //| jnz >1; //| throw_adhoc "Division by zero"; dasm_put(Dst, 1548, Dt28([a]), Dt28([b]), (unsigned int)((uintptr_t)("Division by zero")), (unsigned int)(((uintptr_t)("Division by zero"))>>32)); dasm_put(Dst, 118, (MVMuint32)((uintptr_t)(&MVM_exception_throw_adhoc)), (MVMuint32)((uintptr_t)(&MVM_exception_throw_adhoc) >> 32)); #line 1240 "src/jit/x64/emit.dasc" //|1: //| cqo; //| idiv rcx; //| mov WORK[dst], rdx; dasm_put(Dst, 1626, Dt28([dst])); #line 1244 "src/jit/x64/emit.dasc" break; } case MVM_OP_inc_i: { MVMint32 reg = ins->operands[0].reg.orig; //| add qword WORK[reg], 1; dasm_put(Dst, 1645, Dt28([reg])); #line 1249 "src/jit/x64/emit.dasc" break; } case MVM_OP_dec_i: { MVMint32 reg = ins->operands[0].reg.orig; //| sub qword WORK[reg], 1; dasm_put(Dst, 1651, Dt28([reg])); #line 1254 "src/jit/x64/emit.dasc" break; } case MVM_OP_bnot_i: { MVMint16 dst = ins->operands[0].reg.orig; MVMint16 src = ins->operands[1].reg.orig; //| mov TMP1, WORK[src]; //| not TMP1; //| mov WORK[dst], TMP1; dasm_put(Dst, 1657, Dt28([src]), Dt28([dst])); #line 1262 "src/jit/x64/emit.dasc" break; } case MVM_OP_neg_i: { MVMint16 dst = ins->operands[0].reg.orig; MVMint16 src = ins->operands[1].reg.orig; //| mov TMP1, WORK[src]; //| neg TMP1; //| mov WORK[dst], TMP1; dasm_put(Dst, 1670, Dt28([src]), Dt28([dst])); #line 1270 "src/jit/x64/emit.dasc" break; } case MVM_OP_abs_i: { MVMint16 dst = ins->operands[0].reg.orig; MVMint16 src = ins->operands[1].reg.orig; //| mov TMP1, WORK[src]; //| neg TMP1; //| cmovl TMP1, WORK[src]; //| mov WORK[dst], TMP1; dasm_put(Dst, 1683, Dt28([src]), Dt28([src]), Dt28([dst])); #line 1279 "src/jit/x64/emit.dasc" break; } case MVM_OP_extend_i8: { MVMint16 dst = ins->operands[0].reg.orig; MVMint16 src = ins->operands[1].reg.orig; //| mov RV, WORK[src]; //| cbw; //| cwde; //| cdqe; //| mov WORK[dst], RV; dasm_put(Dst, 1701, Dt28([src]), Dt28([dst])); #line 1289 "src/jit/x64/emit.dasc" break; } case MVM_OP_extend_u8: { MVMint16 dst = ins->operands[0].reg.orig; MVMint16 src = ins->operands[1].reg.orig; //| mov TMP1, WORK[src]; //| xor TMP2, TMP2; //| mov TMP2b, TMP1b; //| mov WORK[dst], TMP2; dasm_put(Dst, 1715, Dt28([src]), Dt28([dst])); #line 1298 "src/jit/x64/emit.dasc" break; } case MVM_OP_extend_i16: { MVMint16 dst = ins->operands[0].reg.orig; MVMint16 src = ins->operands[1].reg.orig; //| mov RV, WORK[src]; //| cwde; //| cdqe; //| mov WORK[dst], RV; dasm_put(Dst, 1729, Dt28([src]), Dt28([dst])); #line 1307 "src/jit/x64/emit.dasc" break; } case MVM_OP_extend_u16: { MVMint16 dst = ins->operands[0].reg.orig; MVMint16 src = ins->operands[1].reg.orig; //| mov TMP1, WORK[src]; //| xor TMP2, TMP2; //| mov TMP2w, TMP1w; //| mov WORK[dst], TMP2; dasm_put(Dst, 1741, Dt28([src]), Dt28([dst])); #line 1316 "src/jit/x64/emit.dasc" break; } case MVM_OP_extend_i32: { MVMint16 dst = ins->operands[0].reg.orig; MVMint16 src = ins->operands[1].reg.orig; //| mov RV, WORK[src]; //| cdqe; //| mov WORK[dst], RV; dasm_put(Dst, 1756, Dt28([src]), Dt28([dst])); #line 1324 "src/jit/x64/emit.dasc" break; } case MVM_OP_extend_u32: { MVMint16 dst = ins->operands[0].reg.orig; MVMint16 src = ins->operands[1].reg.orig; //| mov TMP1, WORK[src]; //| mov TMP2d, TMP1d; //| mov WORK[dst], TMP1; dasm_put(Dst, 1767, Dt28([src]), Dt28([dst])); #line 1332 "src/jit/x64/emit.dasc" break; } case MVM_OP_trunc_u8: case MVM_OP_trunc_i8: { MVMint16 dst = ins->operands[0].reg.orig; MVMint16 src = ins->operands[1].reg.orig; //| mov TMP1, WORK[src]; //| xor TMP2, TMP2; //| mov TMP2b, TMP1b; //| mov WORK[dst], TMP2; dasm_put(Dst, 1715, Dt28([src]), Dt28([dst])); #line 1342 "src/jit/x64/emit.dasc" break; } case MVM_OP_trunc_u16: case MVM_OP_trunc_i16: { MVMint16 dst = ins->operands[0].reg.orig; MVMint16 src = ins->operands[1].reg.orig; //| mov TMP1, WORK[src]; //| xor TMP2, TMP2; //| mov TMP2w, TMP1w; //| mov WORK[dst], TMP2; dasm_put(Dst, 1741, Dt28([src]), Dt28([dst])); #line 1352 "src/jit/x64/emit.dasc" break; } case MVM_OP_trunc_u32: case MVM_OP_trunc_i32: { MVMint16 dst = ins->operands[0].reg.orig; MVMint16 src = ins->operands[1].reg.orig; //| mov TMP1, WORK[src]; dasm_put(Dst, 604, Dt28([src])); #line 1359 "src/jit/x64/emit.dasc" /* x86-64 auto-truncates the upper 32 bits when using registers in 32 * bit mode */ //| mov TMP2d, TMP1d; //| mov WORK[dst], TMP2; dasm_put(Dst, 1749, Dt28([dst])); #line 1363 "src/jit/x64/emit.dasc" break; } case MVM_OP_sp_istrue_n: { MVMint16 dst = ins->operands[0].reg.orig; MVMint16 src = ins->operands[1].reg.orig; //| movsd xmm0, qword WORK[src]; //| xorps xmm1, xmm1; //| cmpsd xmm0, xmm1, 4; //| movd TMP1, xmm0; //| and TMP1, 1; //| mov WORK[dst], TMP1; dasm_put(Dst, 1778, Dt28([src]), Dt28([dst])); #line 1374 "src/jit/x64/emit.dasc" break; } case MVM_OP_add_n: case MVM_OP_sub_n: case MVM_OP_mul_n: case MVM_OP_div_n: { MVMint16 reg_a = ins->operands[0].reg.orig; MVMint16 reg_b = ins->operands[1].reg.orig; MVMint16 reg_c = ins->operands[2].reg.orig; /* Copying data to xmm (floating point) registers requires * a special move instruction */ //| movsd xmm0, qword WORK[reg_b]; dasm_put(Dst, 1807, Dt28([reg_b])); #line 1386 "src/jit/x64/emit.dasc" switch(ins->info->opcode) { case MVM_OP_add_n: //| addsd xmm0, qword WORK[reg_c]; dasm_put(Dst, 1814, Dt28([reg_c])); #line 1389 "src/jit/x64/emit.dasc" break; case MVM_OP_sub_n: //| subsd xmm0, qword WORK[reg_c]; dasm_put(Dst, 1821, Dt28([reg_c])); #line 1392 "src/jit/x64/emit.dasc" break; case MVM_OP_mul_n: //| mulsd xmm0, qword WORK[reg_c]; dasm_put(Dst, 1828, Dt28([reg_c])); #line 1395 "src/jit/x64/emit.dasc" break; case MVM_OP_div_n: //| divsd xmm0, qword WORK[reg_c]; dasm_put(Dst, 1835, Dt28([reg_c])); #line 1398 "src/jit/x64/emit.dasc" break; } //| movsd qword WORK[reg_a], xmm0; dasm_put(Dst, 1842, Dt28([reg_a])); #line 1401 "src/jit/x64/emit.dasc" break; } case MVM_OP_coerce_iu: case MVM_OP_coerce_ui: { MVMint16 dst = ins->operands[0].reg.orig; MVMint16 src = ins->operands[1].reg.orig; //| mov TMP1, WORK[src]; //| mov WORK[dst], TMP1; dasm_put(Dst, 1155, Dt28([src]), Dt28([dst])); #line 1409 "src/jit/x64/emit.dasc" break; } case MVM_OP_coerce_in: { MVMint16 dst = ins->operands[0].reg.orig; MVMint16 src = ins->operands[1].reg.orig; /* convert simple integer to double precision */ //| cvtsi2sd xmm0, qword WORK[src]; //| movsd qword WORK[dst], xmm0; dasm_put(Dst, 1849, Dt28([src]), Dt28([dst])); #line 1417 "src/jit/x64/emit.dasc" break; } case MVM_OP_coerce_ni: { MVMint16 dst = ins->operands[0].reg.orig; MVMint16 src = ins->operands[1].reg.orig; /* convert double precision to simple intege */ //| cvttsd2si rax, qword WORK[src]; //| mov WORK[dst], rax; dasm_put(Dst, 1863, Dt28([src]), Dt28([dst])); #line 1425 "src/jit/x64/emit.dasc" break; } case MVM_OP_neg_n: { /* Negation is xor-ing the highest byte. Pretty simple right */ MVMint16 dst = ins->operands[0].reg.orig; MVMint16 src = ins->operands[1].reg.orig; //| mov TMP1, 1; //| sal TMP1, 63; //| mov TMP2, qword WORK[src]; //| xor TMP2, TMP1; //| mov qword WORK[dst], TMP2; dasm_put(Dst, 1875, Dt28([src]), Dt28([dst])); #line 1436 "src/jit/x64/emit.dasc" break; } case MVM_OP_eq_u: case MVM_OP_eq_i: case MVM_OP_eqaddr: case MVM_OP_ne_u: case MVM_OP_ne_i: case MVM_OP_lt_u: case MVM_OP_lt_i: case MVM_OP_le_u: case MVM_OP_le_i: case MVM_OP_gt_u: case MVM_OP_gt_i: case MVM_OP_ge_u: case MVM_OP_ge_i: { MVMint32 reg_a = ins->operands[0].reg.orig; MVMint32 reg_b = ins->operands[1].reg.orig; MVMint32 reg_c = ins->operands[2].reg.orig; //| mov rax, WORK[reg_b]; dasm_put(Dst, 1383, Dt28([reg_b])); #line 1455 "src/jit/x64/emit.dasc" /* comparison result in the setting bits in the rflags register */ //| cmp rax, WORK[reg_c]; dasm_put(Dst, 1898, Dt28([reg_c])); #line 1457 "src/jit/x64/emit.dasc" /* copy the right comparison bit to the lower byte of the rax register */ switch(ins->info->opcode) { case MVM_OP_eqaddr: case MVM_OP_eq_u: case MVM_OP_eq_i: //| sete RVb; dasm_put(Dst, 1903); #line 1464 "src/jit/x64/emit.dasc" break; case MVM_OP_ne_u: case MVM_OP_ne_i: //| setne RVb; dasm_put(Dst, 1907); #line 1468 "src/jit/x64/emit.dasc" break; case MVM_OP_lt_i: //| setl RVb; dasm_put(Dst, 1911); #line 1471 "src/jit/x64/emit.dasc" break; case MVM_OP_lt_u: //| setb RVb; dasm_put(Dst, 1915); #line 1474 "src/jit/x64/emit.dasc" break; case MVM_OP_le_i: //| setle RVb; dasm_put(Dst, 1919); #line 1477 "src/jit/x64/emit.dasc" break; case MVM_OP_le_u: //| setbe RVb; dasm_put(Dst, 1923); #line 1480 "src/jit/x64/emit.dasc" break; case MVM_OP_gt_i: //| setg RVb; dasm_put(Dst, 1927); #line 1483 "src/jit/x64/emit.dasc" break; case MVM_OP_gt_u: //| seta RVb; dasm_put(Dst, 1931); #line 1486 "src/jit/x64/emit.dasc" break; case MVM_OP_ge_i: //| setge RVb; dasm_put(Dst, 1935); #line 1489 "src/jit/x64/emit.dasc" break; case MVM_OP_ge_u: //| setae RVb; dasm_put(Dst, 1939); #line 1492 "src/jit/x64/emit.dasc" break; } /* zero extend al (lower byte) to rax (whole register) */ //| movzx RV, RVb; //| mov WORK[reg_a], RV; dasm_put(Dst, 1943, Dt28([reg_a])); #line 1497 "src/jit/x64/emit.dasc" break; } case MVM_OP_cmp_u : case MVM_OP_cmp_i : { MVMint32 reg_a = ins->operands[0].reg.orig; MVMint32 reg_b = ins->operands[1].reg.orig; MVMint32 reg_c = ins->operands[2].reg.orig; //| mov TMP1, WORK[reg_b]; dasm_put(Dst, 604, Dt28([reg_b])); #line 1505 "src/jit/x64/emit.dasc" /* comparison result in the setting bits in the rflags register */ //| cmp TMP1, WORK[reg_c]; dasm_put(Dst, 1952, Dt28([reg_c])); #line 1507 "src/jit/x64/emit.dasc" /* copy the right comparison bit to the lower byte of the rax register */ /* The braces are needed on the below if/else pairs. If they are omitted then * for some reason cmp_i returns the right operand (unless run under valgrind). * I don't understand it, but since it works with the braces... */ if (ins->info->opcode == MVM_OP_cmp_i) { //| setg TMP2b; dasm_put(Dst, 1957); #line 1514 "src/jit/x64/emit.dasc" } else { //| seta TMP2b; dasm_put(Dst, 1961); #line 1517 "src/jit/x64/emit.dasc" } //| movzx TMP2, TMP2b; dasm_put(Dst, 1965); #line 1519 "src/jit/x64/emit.dasc" if (ins->info->opcode == MVM_OP_cmp_i) { //| setl TMP3b; dasm_put(Dst, 1970); #line 1521 "src/jit/x64/emit.dasc" } else { //| setb TMP3b; dasm_put(Dst, 1975); #line 1524 "src/jit/x64/emit.dasc" } //| movzx TMP3, TMP3b; //| sub TMP2, TMP3; //| mov WORK[reg_a], TMP2; dasm_put(Dst, 1980, Dt28([reg_a])); #line 1528 "src/jit/x64/emit.dasc" break; } case MVM_OP_gt_s: case MVM_OP_ge_s: case MVM_OP_lt_s: case MVM_OP_le_s: { /* src/jit/graph.c already put a call to the MVM_string_compare function into the graph, so here we just have to deal with the returned integers. */ MVMint32 reg = ins->operands[0].reg.orig; switch(ins->info->opcode) { case MVM_OP_gt_s: //| mov TMP2, 1; dasm_put(Dst, 1992); #line 1541 "src/jit/x64/emit.dasc" break; case MVM_OP_lt_s: //| mov TMP2, -1; dasm_put(Dst, 2000); #line 1544 "src/jit/x64/emit.dasc" break; case MVM_OP_ge_s: case MVM_OP_le_s: //| mov TMP2, 0; dasm_put(Dst, 2012); #line 1547 "src/jit/x64/emit.dasc" break; } //| cmp TMP2, WORK[reg]; dasm_put(Dst, 2020, Dt28([reg])); #line 1550 "src/jit/x64/emit.dasc" /* Mind the reversedness of the constant and the value as compared to * interp.c */ switch(ins->info->opcode) { case MVM_OP_gt_s: //| sete RVb; dasm_put(Dst, 1903); #line 1555 "src/jit/x64/emit.dasc" break; case MVM_OP_ge_s: //| setle RVb; dasm_put(Dst, 1919); #line 1558 "src/jit/x64/emit.dasc" break; case MVM_OP_lt_s: //| sete RVb; dasm_put(Dst, 1903); #line 1561 "src/jit/x64/emit.dasc" break; case MVM_OP_le_s: //| setge RVb; dasm_put(Dst, 1935); #line 1564 "src/jit/x64/emit.dasc" break; } //| movzx RV, RVb; //| mov WORK[reg], RV; dasm_put(Dst, 1943, Dt28([reg])); #line 1568 "src/jit/x64/emit.dasc" break; } case MVM_OP_not_i: { MVMint16 dst = ins->operands[0].reg.orig; MVMint16 src = ins->operands[1].reg.orig; //| mov TMP1, WORK[src]; //| test TMP1, TMP1; //| setz TMP2b; //| movzx TMP2, TMP2b; //| mov WORK[dst], TMP2; dasm_put(Dst, 1334, Dt28([src]), Dt28([dst])); #line 1578 "src/jit/x64/emit.dasc" break; } case MVM_OP_eq_n: case MVM_OP_ne_n: case MVM_OP_le_n: case MVM_OP_lt_n: case MVM_OP_ge_n: case MVM_OP_gt_n: { MVMint16 dst = ins->operands[0].reg.orig; MVMint16 a = ins->operands[1].reg.orig; MVMint16 b = ins->operands[2].reg.orig; if (op == MVM_OP_eq_n) { //| mov TMP1, 0; dasm_put(Dst, 2025); #line 1591 "src/jit/x64/emit.dasc" } else if (op == MVM_OP_ne_n) { //| mov TMP1, 1; dasm_put(Dst, 2033); #line 1593 "src/jit/x64/emit.dasc" } if (op == MVM_OP_lt_n || op == MVM_OP_le_n) { //| movsd xmm0, qword WORK[b]; //| ucomisd xmm0, qword WORK[a]; dasm_put(Dst, 2041, Dt28([b]), Dt28([a])); #line 1597 "src/jit/x64/emit.dasc" } else { //| movsd xmm0, qword WORK[a]; //| ucomisd xmm0, qword WORK[b]; dasm_put(Dst, 2041, Dt28([a]), Dt28([b])); #line 1600 "src/jit/x64/emit.dasc" } if (op == MVM_OP_le_n || op == MVM_OP_ge_n) { //| setae TMP1b; dasm_put(Dst, 2053); #line 1604 "src/jit/x64/emit.dasc" } else if (op == MVM_OP_eq_n) { //| setnp TMP2b; // zero if either is NaN, 1 otherwise //| cmove TMP1, TMP2; // if equal, overwrite 0 with 1 dasm_put(Dst, 2057); #line 1607 "src/jit/x64/emit.dasc" } else if (op == MVM_OP_ne_n) { //| setp TMP2b; // 1 if either is NaN (in which case they can't be equal) //| cmove TMP1, TMP2; // if equal, overwrite 1 with IsNan(a) | IsNaN(b) dasm_put(Dst, 2065); #line 1610 "src/jit/x64/emit.dasc" } else { //| seta TMP1b; dasm_put(Dst, 2073); #line 1612 "src/jit/x64/emit.dasc" } //| movzx TMP1, TMP1b; //| mov WORK[dst], TMP1; dasm_put(Dst, 2077, Dt28([dst])); #line 1615 "src/jit/x64/emit.dasc" break; } case MVM_OP_cmp_n: { MVMint16 dst = ins->operands[0].reg.orig; MVMint16 a = ins->operands[1].reg.orig; MVMint16 b = ins->operands[2].reg.orig; //| movsd xmm0, qword WORK[a]; //| movsd xmm1, qword WORK[b]; //| ucomisd xmm0, xmm1 //| seta TMP1b; //| movzx rax, TMP1b; //| ucomisd xmm1, xmm0 //| seta TMP1b; //| movzx TMP1, TMP1b; //| sub rax, TMP1; //| mov WORK[dst], rax; dasm_put(Dst, 2086, Dt28([a]), Dt28([b]), Dt28([dst])); #line 1631 "src/jit/x64/emit.dasc" break; } case MVM_OP_eq_I: case MVM_OP_ne_I: case MVM_OP_lt_I: case MVM_OP_le_I: case MVM_OP_gt_I: case MVM_OP_ge_I: { MVMint32 reg_a = ins->operands[0].reg.orig; MVMint32 reg_b = ins->operands[1].reg.orig; MVMint32 reg_c = ins->operands[2].reg.orig; /* Call the bigint comparison function. */ //| mov ARG1, TC; //| mov ARG2, WORK[reg_b]; //| mov ARG3, WORK[reg_c]; //| callp &MVM_bigint_cmp; dasm_put(Dst, 2128, Dt28([reg_b]), Dt28([reg_c])); dasm_put(Dst, 118, (MVMuint32)((uintptr_t)(&MVM_bigint_cmp)), (MVMuint32)((uintptr_t)(&MVM_bigint_cmp) >> 32)); dasm_put(Dst, 260); #line 1647 "src/jit/x64/emit.dasc" /* Handle result by opcode. */ switch(ins->info->opcode) { case MVM_OP_eq_I: //| cmp RV, MP_EQ //| sete RVb; dasm_put(Dst, 2142, MP_EQ); #line 1652 "src/jit/x64/emit.dasc" break; case MVM_OP_ne_I: //| cmp RV, MP_EQ //| setne RVb; dasm_put(Dst, 2151, MP_EQ); #line 1656 "src/jit/x64/emit.dasc" break; case MVM_OP_lt_I: //| cmp RV, MP_LT //| sete RVb; dasm_put(Dst, 2142, MP_LT); #line 1660 "src/jit/x64/emit.dasc" break; case MVM_OP_le_I: //| cmp RV, MP_GT //| setne RVb; dasm_put(Dst, 2151, MP_GT); #line 1664 "src/jit/x64/emit.dasc" break; case MVM_OP_gt_I: //| cmp RV, MP_GT //| sete RVb; dasm_put(Dst, 2142, MP_GT); #line 1668 "src/jit/x64/emit.dasc" break; case MVM_OP_ge_I: //| cmp RV, MP_LT //| setne RVb; dasm_put(Dst, 2151, MP_LT); #line 1672 "src/jit/x64/emit.dasc" break; } /* zero extend al (lower byte) to rax (whole register) */ //| movzx RV, RVb; //| mov WORK[reg_a], RV; dasm_put(Dst, 1943, Dt28([reg_a])); #line 1677 "src/jit/x64/emit.dasc" break; } case MVM_OP_isint: case MVM_OP_isnum: case MVM_OP_isstr: case MVM_OP_islist: case MVM_OP_ishash: { MVMint16 dst = ins->operands[0].reg.orig; MVMint16 obj = ins->operands[1].reg.orig; MVMint32 reprid = op == MVM_OP_isint ? MVM_REPR_ID_P6int : op == MVM_OP_isnum ? MVM_REPR_ID_P6num : op == MVM_OP_isstr ? MVM_REPR_ID_P6str : op == MVM_OP_islist ? MVM_REPR_ID_VMArray : /* op == MVM_OP_ishash */ MVM_REPR_ID_MVMHash; //| mov TMP1, aword WORK[obj]; //| test TMP1, TMP1; //| jz >1; //| mov TMP1, OBJECT:TMP1->st; //| mov TMP1, STABLE:TMP1->REPR; //| cmp qword REPR:TMP1->ID, reprid; //| jne >1; //| mov qword WORK[dst], 1; //| jmp >2; //|1: //| mov qword WORK[dst], 0; //|2: dasm_put(Dst, 2160, Dt28([obj]), DtD(->st), Dt12(->REPR), Dt13(->ID), reprid, Dt28([dst]), Dt28([dst])); #line 1703 "src/jit/x64/emit.dasc" break; } case MVM_OP_sp_boolify_iter_arr: { MVMint16 dst = ins->operands[0].reg.orig; MVMint16 obj = ins->operands[1].reg.orig; //| mov TMP1, aword WORK[obj]; //| mov TMP2, MVMITER:TMP1->body.array_state.index; //| add TMP2, 1; //| mov TMP3, MVMITER:TMP1->body.array_state.limit; dasm_put(Dst, 2213, Dt28([obj]), DtA(->body.array_state.index), DtA(->body.array_state.limit)); #line 1712 "src/jit/x64/emit.dasc" /* index - limit will give a carry flag when index < limit */ //| cmp TMP2, TMP3; //| setl TMP1b; //| movzx TMP1, TMP1b; //| mov aword WORK[dst], TMP1; dasm_put(Dst, 2230, Dt28([dst])); #line 1717 "src/jit/x64/emit.dasc" break; } case MVM_OP_objprimspec: { MVMint16 dst = ins->operands[0].reg.orig; MVMint16 type = ins->operands[1].reg.orig; //| mov TMP6, aword WORK[type]; //| test TMP6, TMP6; //| jz >1; //| mov ARG1, TC; //| mov ARG2, OBJECT:TMP6->st; //| mov FUNCTION, STABLE:ARG2->REPR; //| mov FUNCTION, REPR:FUNCTION->get_storage_spec; //| call FUNCTION; //| movzx TMP6, word STORAGESPEC:RV->boxed_primitive; //|1: //| mov aword WORK[dst], TMP6; dasm_put(Dst, 2245, Dt28([type]), DtD(->st), Dt12(->REPR), Dt13(->get_storage_spec), Dt18(->boxed_primitive), Dt28([dst])); #line 1733 "src/jit/x64/emit.dasc" break; } case MVM_OP_objprimbits: { MVMint16 dst = ins->operands[0].reg.orig; MVMint16 type = ins->operands[1].reg.orig; //| mov TMP6, aword WORK[type]; //| test TMP6, TMP6; //| jz >1; //| mov ARG2, OBJECT:TMP6->st; //| mov FUNCTION, STABLE:ARG2->REPR; //| mov FUNCTION, REPR:FUNCTION->get_storage_spec; //| mov ARG1, TC; //| call FUNCTION; //| movzx TMP6, word STORAGESPEC:RV->boxed_primitive; //| test TMP6, TMP6; //| jz >1; //| movzx TMP6, word STORAGESPEC:RV->bits; //|1: //| mov aword WORK[dst], TMP6; dasm_put(Dst, 2288, Dt28([type]), DtD(->st), Dt12(->REPR), Dt13(->get_storage_spec), Dt18(->boxed_primitive), Dt18(->bits), Dt28([dst])); #line 1752 "src/jit/x64/emit.dasc" break; } case MVM_OP_objprimunsigned: { MVMint16 dst = ins->operands[0].reg.orig; MVMint16 type = ins->operands[1].reg.orig; //| mov TMP5, aword WORK[type]; //| test TMP5, TMP5; //| jz >1; //| mov ARG1, TC; //| mov ARG2, OBJECT:TMP5->st; //| mov FUNCTION, STABLE:ARG2->REPR; //| mov FUNCTION, REPR:FUNCTION->get_storage_spec; //| call FUNCTION; //| movzx TMP6, word STORAGESPEC:RV->boxed_primitive; //| test TMP6, TMP6; //| jz >1; //| movzx TMP6, byte STORAGESPEC:RV->is_unsigned; //| mov WORK[dst], TMP6; //| jmp >2; //|1: //| mov aword WORK[dst], 0; //|2: dasm_put(Dst, 2343, Dt28([type]), DtD(->st), Dt12(->REPR), Dt13(->get_storage_spec), Dt18(->boxed_primitive), Dt18(->is_unsigned), Dt28([dst]), Dt28([dst])); #line 1774 "src/jit/x64/emit.dasc" break; } case MVM_OP_isnonnull: { MVMint16 dst = ins->operands[0].reg.orig; MVMint16 obj = ins->operands[1].reg.orig; //| mov TMP1, WORK[obj]; //| test TMP1, TMP1; //| setnz TMP2b; //| get_vmnull TMP3; //| cmp TMP1, TMP3; //| setne TMP3b; //| and TMP2b, TMP3b; //| movzx TMP2, TMP2b; //| mov WORK[dst], TMP2; dasm_put(Dst, 2412, Dt28([obj]), Dt27(->instance), DtB(->VMNull), Dt28([dst])); #line 1788 "src/jit/x64/emit.dasc" break; } case MVM_OP_scgethandle: { MVMint16 dst = ins->operands[0].reg.orig; MVMint16 sc = ins->operands[1].reg.orig; //| mov TMP5, aword WORK[sc]; //| cmp_repr_id TMP5, TMP6, MVM_REPR_ID_SCRef; //| je >1; //| throw_adhoc "Must provide an SCRef operand to scgethandle" dasm_put(Dst, 2449, Dt28([sc]), DtD(->st), Dt12(->REPR), Dt13(->ID), MVM_REPR_ID_SCRef, (unsigned int)((uintptr_t)("Must provide an SCRef operand to scgethandle")), (unsigned int)(((uintptr_t)("Must provide an SCRef operand to scgethandle"))>>32)); dasm_put(Dst, 118, (MVMuint32)((uintptr_t)(&MVM_exception_throw_adhoc)), (MVMuint32)((uintptr_t)(&MVM_exception_throw_adhoc) >> 32)); #line 1797 "src/jit/x64/emit.dasc" //|1: //| mov ARG1, TC; //| mov ARG2, SCREF:TMP5; //| callp &MVM_sc_get_handle; dasm_put(Dst, 2480); dasm_put(Dst, 118, (MVMuint32)((uintptr_t)(&MVM_sc_get_handle)), (MVMuint32)((uintptr_t)(&MVM_sc_get_handle) >> 32)); #line 1801 "src/jit/x64/emit.dasc" //| mov WORK[dst], RV; dasm_put(Dst, 410, Dt28([dst])); #line 1802 "src/jit/x64/emit.dasc" break; } case MVM_OP_scobjcount: { MVMint16 dst = ins->operands[0].reg.orig; MVMint16 sc = ins->operands[1].reg.orig; //| mov TMP5, aword WORK[sc]; //| cmp_repr_id TMP5, TMP6, MVM_REPR_ID_SCRef; //| je >1; //| throw_adhoc "Must provide an SCRef operand to scobjcount" dasm_put(Dst, 2449, Dt28([sc]), DtD(->st), Dt12(->REPR), Dt13(->ID), MVM_REPR_ID_SCRef, (unsigned int)((uintptr_t)("Must provide an SCRef operand to scobjcount")), (unsigned int)(((uintptr_t)("Must provide an SCRef operand to scobjcount"))>>32)); dasm_put(Dst, 118, (MVMuint32)((uintptr_t)(&MVM_exception_throw_adhoc)), (MVMuint32)((uintptr_t)(&MVM_exception_throw_adhoc) >> 32)); #line 1811 "src/jit/x64/emit.dasc" //|1: //| mov ARG1, TC; //| mov ARG2, SCREF:TMP5; //| callp &MVM_sc_get_object_count; dasm_put(Dst, 2480); dasm_put(Dst, 118, (MVMuint32)((uintptr_t)(&MVM_sc_get_object_count)), (MVMuint32)((uintptr_t)(&MVM_sc_get_object_count) >> 32)); #line 1815 "src/jit/x64/emit.dasc" //| mov WORK[dst], RV; dasm_put(Dst, 410, Dt28([dst])); #line 1816 "src/jit/x64/emit.dasc" break; } case MVM_OP_setobjsc: { MVMint16 dst = ins->operands[0].reg.orig; MVMint16 sc = ins->operands[1].reg.orig; //| mov TMP5, WORK[sc]; //| cmp_repr_id TMP5, TMP6, MVM_REPR_ID_SCRef; //| je >1; //| throw_adhoc "Must provide an SCRef operand to setobjsc" dasm_put(Dst, 2449, Dt28([sc]), DtD(->st), Dt12(->REPR), Dt13(->ID), MVM_REPR_ID_SCRef, (unsigned int)((uintptr_t)("Must provide an SCRef operand to setobjsc")), (unsigned int)(((uintptr_t)("Must provide an SCRef operand to setobjsc"))>>32)); dasm_put(Dst, 118, (MVMuint32)((uintptr_t)(&MVM_exception_throw_adhoc)), (MVMuint32)((uintptr_t)(&MVM_exception_throw_adhoc) >> 32)); #line 1825 "src/jit/x64/emit.dasc" //|1: //| mov ARG1, TC; //| mov ARG2, aword WORK[dst]; //| mov ARG3, SCREF:TMP5; //| callp &MVM_sc_set_obj_sc; dasm_put(Dst, 2496, Dt28([dst])); dasm_put(Dst, 118, (MVMuint32)((uintptr_t)(&MVM_sc_set_obj_sc)), (MVMuint32)((uintptr_t)(&MVM_sc_set_obj_sc) >> 32)); dasm_put(Dst, 260); #line 1830 "src/jit/x64/emit.dasc" break; } case MVM_OP_isnull: { MVMint16 dst = ins->operands[0].reg.orig; MVMint16 obj = ins->operands[1].reg.orig; //| mov TMP1, WORK[obj]; //| test TMP1, TMP1; //| setz TMP2b; //| get_vmnull TMP3; //| cmp TMP1, TMP3; //| sete TMP3b; //| or TMP2b, TMP3b; //| movzx TMP2, TMP2b; //| mov WORK[dst], TMP2; dasm_put(Dst, 2516, Dt28([obj]), Dt27(->instance), DtB(->VMNull), Dt28([dst])); #line 1844 "src/jit/x64/emit.dasc" break; } case MVM_OP_sp_fastcreate: { MVMint16 dst = ins->operands[0].reg.orig; emit_fastcreate(tc, compiler, jg, ins); //| mov aword WORK[dst], RV; dasm_put(Dst, 415, Dt28([dst])); #line 1850 "src/jit/x64/emit.dasc" break; } case MVM_OP_decont: case MVM_OP_sp_decont: { MVMint16 dst = ins->operands[0].reg.orig; MVMint16 src = ins->operands[1].reg.orig; //| mov TMP5, WORK[src]; //| test_type_object TMP5; dasm_put(Dst, 2553, Dt28([src]), DtD(->header.flags1), MVM_CF_TYPE_OBJECT); #line 1858 "src/jit/x64/emit.dasc" // object is type object (not concrete) //| jnz >1; //| mov TMP6, OBJECT:TMP5->st; //| mov TMP6, STABLE:TMP6->container_spec; //| test TMP6, TMP6; dasm_put(Dst, 2565, DtD(->st), Dt12(->container_spec)); #line 1863 "src/jit/x64/emit.dasc" // container spec is zero //| jz >1; //| mov ARG1, TC; //| mov ARG2, TMP5; // object //| lea ARG3, WORK[dst]; // destination register //| mov FUNCTION, CONTAINERSPEC:TMP6->fetch; // get function pointer //| call FUNCTION; //| jmp >2; //|1: dasm_put(Dst, 2581, Dt28([dst]), Dt17(->fetch)); #line 1872 "src/jit/x64/emit.dasc" // otherwise just move the object into the register //| mov WORK[dst], TMP5; //|2: dasm_put(Dst, 2611, Dt28([dst])); #line 1875 "src/jit/x64/emit.dasc" break; } case MVM_OP_iscont: { MVMint16 dst = ins->operands[0].reg.orig; MVMint16 obj = ins->operands[1].reg.orig; //| mov TMP1, aword WORK[obj]; //| test TMP1, TMP1; //| jz >1; //| mov TMP1, OBJECT:TMP1->st; //| mov TMP1, STABLE:TMP1->container_spec; //| test TMP1, TMP1; //|1: //| setnz TMP1b; //| movzx TMP1, TMP1b; //| mov qword WORK[dst], TMP1; dasm_put(Dst, 2618, Dt28([obj]), DtD(->st), Dt12(->container_spec), Dt28([dst])); #line 1890 "src/jit/x64/emit.dasc" break; } case MVM_OP_isconcrete: { MVMint16 dst = ins->operands[0].reg.orig; MVMint16 obj = ins->operands[1].reg.orig; //| mov TMP1, WORK[obj]; //| test TMP1, TMP1; //| jz >1; //| test_type_object TMP1; //| jnz >1; //| mov qword WORK[dst], 1; //| jmp >2; //|1: //| mov qword WORK[dst], 0; //|2: dasm_put(Dst, 2654, Dt28([obj]), DtD(->header.flags1), MVM_CF_TYPE_OBJECT, Dt28([dst]), Dt28([dst])); #line 1905 "src/jit/x64/emit.dasc" break; } case MVM_OP_markcodestatic: { MVMint16 cr = ins->operands[0].reg.orig; //| mov TMP1, aword WORK[cr]; dasm_put(Dst, 604, Dt28([cr])); #line 1910 "src/jit/x64/emit.dasc" /* if (IS_CONCRETE(cr) && REPR(cr)->ID == MVM_REPR_ID_MVMCode) */ //| test_type_object TMP1; //| jnz >1; //| cmp_repr_id TMP1, TMP2, MVM_REPR_ID_MVMCode; //| je >2; //|1: dasm_put(Dst, 2700, DtD(->header.flags1), MVM_CF_TYPE_OBJECT, DtD(->st), Dt12(->REPR), Dt13(->ID), MVM_REPR_ID_MVMCode); #line 1916 "src/jit/x64/emit.dasc" /* else throw */ //| throw_adhoc "markcodestatic requires a concrete coderef"; dasm_put(Dst, 380, (unsigned int)((uintptr_t)("markcodestatic requires a concrete coderef")), (unsigned int)(((uintptr_t)("markcodestatic requires a concrete coderef"))>>32)); dasm_put(Dst, 118, (MVMuint32)((uintptr_t)(&MVM_exception_throw_adhoc)), (MVMuint32)((uintptr_t)(&MVM_exception_throw_adhoc) >> 32)); #line 1918 "src/jit/x64/emit.dasc" //|2: dasm_put(Dst, 340); #line 1919 "src/jit/x64/emit.dasc" /* ((MVMCode *)cr)->body.is_static = 1; */ //| mov dword CODE:TMP1->body.is_static, 1; dasm_put(Dst, 2729, Dt1D(->body.is_static)); #line 1921 "src/jit/x64/emit.dasc" break; } case MVM_OP_markcodestub: { MVMint16 cr = ins->operands[0].reg.orig; //| mov TMP1, aword WORK[cr]; dasm_put(Dst, 604, Dt28([cr])); #line 1926 "src/jit/x64/emit.dasc" /* if (IS_CONCRETE(cr) && REPR(cr)->ID == MVM_REPR_ID_MVMCode) */ //| test_type_object TMP1; //| jnz >1; //| cmp_repr_id TMP1, TMP2, MVM_REPR_ID_MVMCode; //| je >2; //|1: dasm_put(Dst, 2700, DtD(->header.flags1), MVM_CF_TYPE_OBJECT, DtD(->st), Dt12(->REPR), Dt13(->ID), MVM_REPR_ID_MVMCode); #line 1932 "src/jit/x64/emit.dasc" /* else throw */ //| throw_adhoc "markcodestub requires a concrete coderef"; dasm_put(Dst, 380, (unsigned int)((uintptr_t)("markcodestub requires a concrete coderef")), (unsigned int)(((uintptr_t)("markcodestub requires a concrete coderef"))>>32)); dasm_put(Dst, 118, (MVMuint32)((uintptr_t)(&MVM_exception_throw_adhoc)), (MVMuint32)((uintptr_t)(&MVM_exception_throw_adhoc) >> 32)); #line 1934 "src/jit/x64/emit.dasc" //|2: dasm_put(Dst, 340); #line 1935 "src/jit/x64/emit.dasc" /* ((MVMCode *)cr)->body.is_compiler_stub = 1; */ //| mov dword CODE:TMP1->body.is_compiler_stub, 1; dasm_put(Dst, 2729, Dt1D(->body.is_compiler_stub)); #line 1937 "src/jit/x64/emit.dasc" break; } case MVM_OP_takehandlerresult: { MVMint16 dst = ins->operands[0].reg.orig; //| mov TMP1, aword TC->last_handler_result; //| test TMP1, TMP1; //| jnz >1; //| get_vmnull TMP1; //|1: //| mov aword WORK[dst], TMP1; //| mov aword TC->last_handler_result, 0; dasm_put(Dst, 2737, Dt27(->last_handler_result), Dt27(->instance), DtB(->VMNull), Dt28([dst]), Dt27(->last_handler_result)); #line 1948 "src/jit/x64/emit.dasc" break; } case MVM_OP_exception: { MVMint16 dst = ins->operands[0].reg.orig; //| mov TMP1, TC->active_handlers; //| test TMP1, TMP1; //| jz >1; //| mov TMP1, MVMACTIVEHANDLERS:TMP1->ex_obj; //| mov WORK[dst], TMP1; //| jmp >2; //|1: //| get_vmnull TMP1; //| mov WORK[dst], TMP1; //|2: dasm_put(Dst, 2771, Dt27(->active_handlers), DtC(->ex_obj), Dt28([dst]), Dt27(->instance), DtB(->VMNull), Dt28([dst])); #line 1962 "src/jit/x64/emit.dasc" break; } case MVM_OP_scwbdisable: { MVMint16 dst = ins->operands[0].reg.orig; //| mov TMP1d, dword TC->sc_wb_disable_depth; //| add TMP1d, 1; //| mov dword TC->sc_wb_disable_depth, TMP1d; //| mov qword WORK[dst], TMP1; dasm_put(Dst, 2811, Dt27(->sc_wb_disable_depth), Dt27(->sc_wb_disable_depth), Dt28([dst])); #line 1970 "src/jit/x64/emit.dasc" break; } case MVM_OP_scwbenable: { MVMint16 dst = ins->operands[0].reg.orig; //| mov TMP1d, dword TC->sc_wb_disable_depth; // should do zero-extension //| sub TMP1d, 1; //| mov dword TC->sc_wb_disable_depth, TMP1d; //| mov qword WORK[dst], TMP1; dasm_put(Dst, 2827, Dt27(->sc_wb_disable_depth), Dt27(->sc_wb_disable_depth), Dt28([dst])); #line 1978 "src/jit/x64/emit.dasc" break; } case MVM_OP_assign: case MVM_OP_assignunchecked: { MVMint16 cont = ins->operands[0].reg.orig; MVMint16 obj = ins->operands[1].reg.orig; //| mov ARG2, aword WORK[cont]; //| mov FUNCTION, OBJECT:ARG2->st; //| mov FUNCTION, STABLE:FUNCTION->container_spec; //| test FUNCTION, FUNCTION; //| jnz >1; //| throw_adhoc "Cannot assign to an immutable value"; dasm_put(Dst, 2844, Dt28([cont]), DtD(->st), Dt12(->container_spec), (unsigned int)((uintptr_t)("Cannot assign to an immutable value")), (unsigned int)(((uintptr_t)("Cannot assign to an immutable value"))>>32)); dasm_put(Dst, 118, (MVMuint32)((uintptr_t)(&MVM_exception_throw_adhoc)), (MVMuint32)((uintptr_t)(&MVM_exception_throw_adhoc) >> 32)); #line 1990 "src/jit/x64/emit.dasc" //|1: //| mov ARG1, TC; //| mov ARG3, aword WORK[obj]; dasm_put(Dst, 2873, Dt28([obj])); #line 1993 "src/jit/x64/emit.dasc" if (op == MVM_OP_assign) { //| mov FUNCTION, CONTAINERSPEC:FUNCTION->store; dasm_put(Dst, 234, Dt17(->store)); #line 1995 "src/jit/x64/emit.dasc" } else { //| mov FUNCTION, CONTAINERSPEC:FUNCTION->store_unchecked; dasm_put(Dst, 234, Dt17(->store_unchecked)); #line 1997 "src/jit/x64/emit.dasc" } //| call FUNCTION; dasm_put(Dst, 2889); #line 1999 "src/jit/x64/emit.dasc" break; } case MVM_OP_sp_getlexstatic_o: { MVMint16 dst = ins->operands[0].reg.orig; MVMint16 name = ins->operands[1].reg.orig; MVMint16 spesh_idx = ins->operands[2].lit_i16; MVMuint32 slot = ins->operands[3].lit_ui32; //| mov ARG1, TC; //| get_spesh_slot ARG2, spesh_idx; //| lea ARG2, STATICFRAME:ARG2->body.inline_cache; //| mov ARG2, MVMDISPINLINECACHE:ARG2->entries; //| lea ARG2, MVMDISPINLINECACHEENTRY:ARG2[slot]; //| mov ARG3, aword WORK[name]; //| lea ARG4, WORK[dst]; //| mov FUNCTION, [ARG2]; //| mov FUNCTION, MVMDISPINLINECACHEENTRY:FUNCTION->run_getlexstatic; //| call FUNCTION; //| test RV, RV; //| jnz >1; //| get_vmnull TMP3; //| mov WORK[dst], TMP3; //|1: dasm_put(Dst, 2894, Dt27(->cur_frame), Dt2(->effective_spesh_slots), Dt15([spesh_idx]), Dt7(->body.inline_cache), Dt25(->entries), Dt24([slot]), Dt28([name]), Dt28([dst]), Dt24(->run_getlexstatic), Dt27(->instance), DtB(->VMNull), Dt28([dst])); #line 2021 "src/jit/x64/emit.dasc" break; } case MVM_OP_getlexperinvtype_o: { MVMint16 dst = ins->operands[0].reg.orig; MVMint16 name = ins->operands[1].reg.orig; //| mov ARG1, TC; //| mov ARG2, aword WORK[name]; //| mov ARG3, MVM_reg_obj; //| lea ARG4, WORK[dst]; //| callp &MVM_frame_find_lexical_by_name; dasm_put(Dst, 2963, Dt28([name]), MVM_reg_obj, Dt28([dst])); dasm_put(Dst, 118, (MVMuint32)((uintptr_t)(&MVM_frame_find_lexical_by_name)), (MVMuint32)((uintptr_t)(&MVM_frame_find_lexical_by_name) >> 32)); #line 2031 "src/jit/x64/emit.dasc" //| test RV, RV; //| jnz >1; //| get_vmnull TMP3; //| mov WORK[dst], TMP3; //|1: dasm_put(Dst, 467, Dt27(->instance), DtB(->VMNull), Dt28([dst])); #line 2036 "src/jit/x64/emit.dasc" break; } case MVM_OP_paramnamesused: //| mov ARG2, TC->cur_frame; //| lea ARG2, FRAME:ARG2->params; //| mov ARG3, ARGCTX:ARG2->arg_info.callsite //| mov TMP5w, word CALLSITE:ARG3->num_pos; //| cmp TMP5w, word CALLSITE:ARG3->flag_count; //| je >1; //| mov ARG1, TC; //| callp &MVM_args_assert_nameds_used; dasm_put(Dst, 2981, Dt27(->cur_frame), Dt2(->params), Dt3(->arg_info.callsite), Dt4(->num_pos), Dt4(->flag_count)); dasm_put(Dst, 118, (MVMuint32)((uintptr_t)(&MVM_args_assert_nameds_used)), (MVMuint32)((uintptr_t)(&MVM_args_assert_nameds_used) >> 32)); #line 2047 "src/jit/x64/emit.dasc" //|1: dasm_put(Dst, 1575); #line 2048 "src/jit/x64/emit.dasc" break; case MVM_OP_sp_assertparamcheck: { MVMint16 ok = ins->operands[0].reg.orig; MVMint16 spesh_idx = ins->operands[1].lit_i16; MVMuint32 slot = ins->operands[2].lit_ui32; //| mov TMP1, qword WORK[ok]; //| test TMP1, TMP1; //| jnz >1; //| mov ARG1, TC; //| get_spesh_slot ARG2, spesh_idx; //| lea ARG2, STATICFRAME:ARG2->body.inline_cache; //| mov ARG2, MVMDISPINLINECACHE:ARG2->entries; //| lea ARG2, MVMDISPINLINECACHEENTRY:ARG2[slot]; //| callp &MVM_args_bind_failed; dasm_put(Dst, 3013, Dt28([ok]), Dt27(->cur_frame), Dt2(->effective_spesh_slots), Dt15([spesh_idx]), Dt7(->body.inline_cache), Dt25(->entries), Dt24([slot])); dasm_put(Dst, 118, (MVMuint32)((uintptr_t)(&MVM_args_bind_failed)), (MVMuint32)((uintptr_t)(&MVM_args_bind_failed) >> 32)); #line 2062 "src/jit/x64/emit.dasc" //|1: dasm_put(Dst, 1575); #line 2063 "src/jit/x64/emit.dasc" break; } case MVM_OP_prof_enterspesh: //| mov ARG1, TC; //| mov ARG2, TC->cur_frame; //| mov ARG2, aword FRAME:ARG2->static_info; //| mov ARG3, aword MVM_PROFILE_ENTER_JIT; //| callp &MVM_profile_log_enter; dasm_put(Dst, 3054, Dt27(->cur_frame), Dt2(->static_info), MVM_PROFILE_ENTER_JIT); dasm_put(Dst, 118, (MVMuint32)((uintptr_t)(&MVM_profile_log_enter)), (MVMuint32)((uintptr_t)(&MVM_profile_log_enter) >> 32)); dasm_put(Dst, 260); #line 2071 "src/jit/x64/emit.dasc" break; case MVM_OP_prof_enterinline: { MVMint16 spesh_idx = ins->operands[0].lit_i16; //| mov ARG1, TC; //| get_spesh_slot ARG2, spesh_idx; //| mov ARG3, aword MVM_PROFILE_ENTER_JIT_INLINE; //| callp &MVM_profile_log_enter; dasm_put(Dst, 3072, Dt27(->cur_frame), Dt2(->effective_spesh_slots), Dt15([spesh_idx]), MVM_PROFILE_ENTER_JIT_INLINE); dasm_put(Dst, 118, (MVMuint32)((uintptr_t)(&MVM_profile_log_enter)), (MVMuint32)((uintptr_t)(&MVM_profile_log_enter) >> 32)); dasm_put(Dst, 260); #line 2078 "src/jit/x64/emit.dasc" break; } case MVM_OP_prof_replaced: { MVMint16 spesh_idx = ins->operands[0].lit_i16; //| mov ARG1, TC; //| get_spesh_slot ARG2, spesh_idx; //| callp &MVM_profile_log_scalar_replaced; dasm_put(Dst, 764, Dt27(->cur_frame), Dt2(->effective_spesh_slots), Dt15([spesh_idx])); dasm_put(Dst, 118, (MVMuint32)((uintptr_t)(&MVM_profile_log_scalar_replaced)), (MVMuint32)((uintptr_t)(&MVM_profile_log_scalar_replaced) >> 32)); dasm_put(Dst, 260); #line 2085 "src/jit/x64/emit.dasc" break; } case MVM_OP_getobjsc: { MVMint16 dst = ins->operands[0].reg.orig; MVMint16 obj = ins->operands[1].reg.orig; //| mov TMP1, aword WORK[obj]; //| mov TMP2d, dword COLLECTABLE:TMP1->sc_forward_u.sc.sc_idx; //| xor TMP3, TMP3; //| cmp TMP2d, 0; //| jle >1; //| mov TMP3, aword TC->instance; //| mov TMP3, aword MVMINSTANCE:TMP3->all_scs; //| mov TMP3, aword [TMP3 + TMP2d * 8]; //| mov TMP3, SCREFBODY:TMP3->sc; //|1: //| mov aword WORK[dst], TMP3; dasm_put(Dst, 3094, Dt28([obj]), Dt11(->sc_forward_u.sc.sc_idx), Dt27(->instance), DtB(->all_scs), Dt1B(->sc), Dt28([dst])); #line 2101 "src/jit/x64/emit.dasc" break; } case MVM_OP_getstdin: case MVM_OP_getstdout: case MVM_OP_getstderr: { MVMint16 dst = ins->operands[0].reg.orig; //| mov TMP3, aword TC->instance; dasm_put(Dst, 3135, Dt27(->instance)); #line 2108 "src/jit/x64/emit.dasc" if (ins->info->opcode == MVM_OP_getstdin) { //| mov TMP3, aword MVMINSTANCE:TMP3->stdin_handle; dasm_put(Dst, 677, DtB(->stdin_handle)); #line 2110 "src/jit/x64/emit.dasc" } else if (ins->info->opcode == MVM_OP_getstdout) { //| mov TMP3, aword MVMINSTANCE:TMP3->stdout_handle; dasm_put(Dst, 677, DtB(->stdout_handle)); #line 2112 "src/jit/x64/emit.dasc" } else if (ins->info->opcode == MVM_OP_getstderr) { //| mov TMP3, aword MVMINSTANCE:TMP3->stderr_handle; dasm_put(Dst, 677, DtB(->stderr_handle)); #line 2114 "src/jit/x64/emit.dasc" } //| mov aword WORK[dst], TMP3; dasm_put(Dst, 881, Dt28([dst])); #line 2116 "src/jit/x64/emit.dasc" break; } case MVM_OP_ordat: case MVM_OP_ordbaseat: case MVM_OP_ordfirst: { MVMint16 dst = ins->operands[0].reg.orig; MVMint16 str = ins->operands[1].reg.orig; //| mov ARG1, TC; //| mov ARG2, aword WORK[str]; dasm_put(Dst, 3140, Dt28([str])); #line 2125 "src/jit/x64/emit.dasc" if (op == MVM_OP_ordat || op == MVM_OP_ordbaseat) { MVMint16 idx = ins->operands[2].reg.orig; //| mov ARG3, qword WORK[idx]; dasm_put(Dst, 890, Dt28([idx])); #line 2128 "src/jit/x64/emit.dasc" } else { //| mov ARG3, 0; dasm_put(Dst, 2012); #line 2130 "src/jit/x64/emit.dasc" } if (op == MVM_OP_ordbaseat) { //| callp &MVM_string_ord_basechar_at; dasm_put(Dst, 116); dasm_put(Dst, 118, (MVMuint32)((uintptr_t)(&MVM_string_ord_basechar_at)), (MVMuint32)((uintptr_t)(&MVM_string_ord_basechar_at) >> 32)); dasm_put(Dst, 260); #line 2133 "src/jit/x64/emit.dasc" } else { //| callp &MVM_string_ord_at; dasm_put(Dst, 116); dasm_put(Dst, 118, (MVMuint32)((uintptr_t)(&MVM_string_ord_at)), (MVMuint32)((uintptr_t)(&MVM_string_ord_at) >> 32)); dasm_put(Dst, 260); #line 2135 "src/jit/x64/emit.dasc" } //| cdqe; //| mov qword WORK[dst], RV; dasm_put(Dst, 1013, Dt28([dst])); #line 2138 "src/jit/x64/emit.dasc" break; } case MVM_OP_getcodename: { MVMint16 obj = ins->operands[0].reg.orig; MVMint16 code = ins->operands[1].reg.orig; //| mov TMP1, aword WORK[code]; //| cmp_repr_id TMP1, TMP2, MVM_REPR_ID_MVMCode; //| jne >1; //| test_type_object TMP1; //| jz >2; //|1: //| throw_adhoc "getcodename requires a concrete object"; dasm_put(Dst, 512, Dt28([code]), DtD(->st), Dt12(->REPR), Dt13(->ID), MVM_REPR_ID_MVMCode, DtD(->header.flags1), MVM_CF_TYPE_OBJECT, (unsigned int)((uintptr_t)("getcodename requires a concrete object")), (unsigned int)(((uintptr_t)("getcodename requires a concrete object"))>>32)); dasm_put(Dst, 118, (MVMuint32)((uintptr_t)(&MVM_exception_throw_adhoc)), (MVMuint32)((uintptr_t)(&MVM_exception_throw_adhoc) >> 32)); #line 2150 "src/jit/x64/emit.dasc" //|2: //| mov TMP2, CODE:TMP1->body.name; //| mov WORK[obj], TMP2; dasm_put(Dst, 3149, Dt1D(->body.name), Dt28([obj])); #line 2153 "src/jit/x64/emit.dasc" break; } case MVM_OP_setcodeobj: { MVMint16 obj = ins->operands[0].reg.orig; MVMint16 code = ins->operands[1].reg.orig; //| mov TMP1, aword WORK[obj]; dasm_put(Dst, 604, Dt28([obj])); #line 2159 "src/jit/x64/emit.dasc" /* if (REPR(obj)->ID == MVM_REPR_ID_MVMCode) */ //| cmp_repr_id TMP1, TMP2, MVM_REPR_ID_MVMCode; //| je >1; dasm_put(Dst, 3165, DtD(->st), Dt12(->REPR), Dt13(->ID), MVM_REPR_ID_MVMCode); #line 2162 "src/jit/x64/emit.dasc" /* else throw */ //| throw_adhoc "setcodeobj needs a code ref"; dasm_put(Dst, 380, (unsigned int)((uintptr_t)("setcodeobj needs a code ref")), (unsigned int)(((uintptr_t)("setcodeobj needs a code ref"))>>32)); dasm_put(Dst, 118, (MVMuint32)((uintptr_t)(&MVM_exception_throw_adhoc)), (MVMuint32)((uintptr_t)(&MVM_exception_throw_adhoc) >> 32)); #line 2164 "src/jit/x64/emit.dasc" //|1: //| mov TMP2, aword WORK[code]; //| mov aword CODE:TMP1->body.code_object, TMP2; //| check_wb TMP1, TMP2, >2; //| hit_wb TMP1, TMP2 dasm_put(Dst, 3182, Dt28([code]), Dt1D(->body.code_object), Dt11(->flags2), MVM_CF_SECOND_GEN, Dt11(->flags2), MVM_CF_SECOND_GEN); dasm_put(Dst, 118, (MVMuint32)((uintptr_t)(&MVM_gc_write_barrier_hit_by)), (MVMuint32)((uintptr_t)(&MVM_gc_write_barrier_hit_by) >> 32)); #line 2169 "src/jit/x64/emit.dasc" //|2: //| dasm_put(Dst, 340); #line 2171 "src/jit/x64/emit.dasc" break; } case MVM_OP_setcodename: { MVMint16 obj = ins->operands[0].reg.orig; MVMint16 code = ins->operands[1].reg.orig; //| mov TMP1, aword WORK[obj]; dasm_put(Dst, 604, Dt28([obj])); #line 2177 "src/jit/x64/emit.dasc" /* if (REPR(obj)->ID == MVM_REPR_ID_MVMCode) */ //| cmp_repr_id TMP1, TMP2, MVM_REPR_ID_MVMCode; //| je >1; dasm_put(Dst, 3165, DtD(->st), Dt12(->REPR), Dt13(->ID), MVM_REPR_ID_MVMCode); #line 2180 "src/jit/x64/emit.dasc" /* else throw */ //| throw_adhoc "setcodename needs a code ref"; dasm_put(Dst, 380, (unsigned int)((uintptr_t)("setcodename needs a code ref")), (unsigned int)(((uintptr_t)("setcodename needs a code ref"))>>32)); dasm_put(Dst, 118, (MVMuint32)((uintptr_t)(&MVM_exception_throw_adhoc)), (MVMuint32)((uintptr_t)(&MVM_exception_throw_adhoc) >> 32)); #line 2182 "src/jit/x64/emit.dasc" //|1: //| mov TMP2, aword WORK[code]; //| mov aword CODE:TMP1->body.name, TMP2; //| check_wb TMP1, TMP2, >2; //| hit_wb TMP1, TMP2 dasm_put(Dst, 3182, Dt28([code]), Dt1D(->body.name), Dt11(->flags2), MVM_CF_SECOND_GEN, Dt11(->flags2), MVM_CF_SECOND_GEN); dasm_put(Dst, 118, (MVMuint32)((uintptr_t)(&MVM_gc_write_barrier_hit_by)), (MVMuint32)((uintptr_t)(&MVM_gc_write_barrier_hit_by) >> 32)); #line 2187 "src/jit/x64/emit.dasc" //|2: //| dasm_put(Dst, 340); #line 2189 "src/jit/x64/emit.dasc" break; } case MVM_OP_lastexpayload: { MVMint16 dst = ins->operands[0].reg.orig; //| mov TMP3, aword TC->last_payload; //| mov aword WORK[dst], TMP3; dasm_put(Dst, 3236, Dt27(->last_payload), Dt28([dst])); #line 2195 "src/jit/x64/emit.dasc" break; } case MVM_OP_param_sp: { MVMuint16 dst = ins->operands[0].reg.orig; MVMuint16 off = ins->operands[1].lit_ui16; //| mov ARG1, TC //| xor ARG2, ARG2 //| mov ARG3, off //| callp &MVM_args_slurpy_positional; dasm_put(Dst, 3245, off); dasm_put(Dst, 118, (MVMuint32)((uintptr_t)(&MVM_args_slurpy_positional)), (MVMuint32)((uintptr_t)(&MVM_args_slurpy_positional) >> 32)); #line 2204 "src/jit/x64/emit.dasc" //| mov qword WORK[dst], RV; dasm_put(Dst, 410, Dt28([dst])); #line 2205 "src/jit/x64/emit.dasc" break; } case MVM_OP_param_sn: { MVMuint16 dst = ins->operands[0].reg.orig; //| mov ARG1, TC //| mov ARG2, TC:ARG1->cur_frame //| xor ARG2, ARG2 //| callp &MVM_args_slurpy_named; dasm_put(Dst, 3259, Dt27(->cur_frame)); dasm_put(Dst, 118, (MVMuint32)((uintptr_t)(&MVM_args_slurpy_named)), (MVMuint32)((uintptr_t)(&MVM_args_slurpy_named) >> 32)); #line 2213 "src/jit/x64/emit.dasc" //| mov qword WORK[dst], RV; dasm_put(Dst, 410, Dt28([dst])); #line 2214 "src/jit/x64/emit.dasc" break; } case MVM_OP_sp_bindcomplete: { MVMint16 spesh_idx = ins->operands[0].lit_i16; MVMuint32 slot = ins->operands[1].lit_ui32; //| mov ARG1, TC; //| get_spesh_slot ARG2, spesh_idx; //| lea ARG2, STATICFRAME:ARG2->body.inline_cache; //| mov ARG2, MVMDISPINLINECACHE:ARG2->entries; //| lea ARG2, MVMDISPINLINECACHEENTRY:ARG2[slot]; //| callp &MVM_args_bind_succeeded; dasm_put(Dst, 3024, Dt27(->cur_frame), Dt2(->effective_spesh_slots), Dt15([spesh_idx]), Dt7(->body.inline_cache), Dt25(->entries), Dt24([slot])); dasm_put(Dst, 118, (MVMuint32)((uintptr_t)(&MVM_args_bind_succeeded)), (MVMuint32)((uintptr_t)(&MVM_args_bind_succeeded) >> 32)); dasm_put(Dst, 260); #line 2225 "src/jit/x64/emit.dasc" break; } case MVM_OP_sp_cas_o: { MVMint16 target = ins->operands[1].reg.orig; MVMint16 expected = ins->operands[2].reg.orig; MVMint16 value = ins->operands[3].reg.orig; MVMint16 result = ins->operands[0].reg.orig; //| mov ARG1, TC; //| mov ARG2, aword WORK[target]; //| mov ARG3, aword WORK[expected]; //| mov ARG4, aword WORK[value]; //|.if WIN32; //| lea TMP6, WORK[result] //| mov ARG5, TMP6 //|.else; //| lea ARG5, WORK[result] //|.endif //| mov FUNCTION, OBJECT:ARG2->st; //| mov FUNCTION, STABLE:FUNCTION->container_spec; //| mov FUNCTION, CONTAINERSPEC:FUNCTION->cas; //| call FUNCTION; dasm_put(Dst, 3273, Dt28([target]), Dt28([expected]), Dt28([value]), Dt28([result]), DtD(->st), Dt12(->container_spec), Dt17(->cas)); #line 2246 "src/jit/x64/emit.dasc" break; } case MVM_OP_sp_atomicload_o: { MVMint16 target = ins->operands[1].reg.orig; MVMint16 result = ins->operands[0].reg.orig; //| mov ARG1, TC; //| mov ARG2, aword WORK[target]; //| mov FUNCTION, OBJECT:ARG2->st; //| mov FUNCTION, STABLE:FUNCTION->container_spec; //| mov FUNCTION, CONTAINERSPEC:FUNCTION->load_atomic; //| call FUNCTION; //| mov WORK[result], RV dasm_put(Dst, 3310, Dt28([target]), DtD(->st), Dt12(->container_spec), Dt17(->load_atomic), Dt28([result])); #line 2258 "src/jit/x64/emit.dasc" break; } case MVM_OP_sp_atomicstore_o: { MVMint16 target = ins->operands[0].reg.orig; MVMint16 value = ins->operands[1].reg.orig; //| mov ARG1, TC; //| mov ARG2, aword WORK[target]; //| mov ARG3, aword WORK[value]; //| mov FUNCTION, OBJECT:ARG2->st; //| mov FUNCTION, STABLE:FUNCTION->container_spec; //| mov FUNCTION, CONTAINERSPEC:FUNCTION->store_atomic; //| call FUNCTION; dasm_put(Dst, 3339, Dt28([target]), Dt28([value]), DtD(->st), Dt12(->container_spec), Dt17(->store_atomic)); #line 2270 "src/jit/x64/emit.dasc" break; } case MVM_OP_hllbool: { MVMint16 target = ins->operands[0].reg.orig; MVMint16 value = ins->operands[1].reg.orig; MVMHLLConfig *hll_config = (MVMHLLConfig*)jg->sg->sf->body.cu->body.hll_config; uintptr_t true_value = (uintptr_t)hll_config->true_value; uintptr_t false_value = (uintptr_t)hll_config->false_value; //| mov TMP1, WORK[value]; //| test TMP1, TMP1; //| jnz >1; //| mov64 TMP1, false_value; //| jmp >2; //|1: //| mov64 TMP1, true_value; //|2: //| mov WORK[target], TMP1; dasm_put(Dst, 3368, Dt28([value]), (unsigned int)(false_value), (unsigned int)((false_value)>>32), (unsigned int)(true_value), (unsigned int)((true_value)>>32), Dt28([target])); #line 2287 "src/jit/x64/emit.dasc" break; } case MVM_OP_hllboolfor: { MVMint16 target = ins->operands[0].reg.orig; MVMint16 value = ins->operands[1].reg.orig; MVMHLLConfig *hll_config = (MVMHLLConfig*)ins->operands[2].lit_i64; uintptr_t true_value = (uintptr_t)hll_config->true_value; uintptr_t false_value = (uintptr_t)hll_config->false_value; //| mov TMP1, WORK[value]; //| test TMP1, TMP1; //| jnz >1; //| mov64 TMP1, false_value; //| jmp >2; //|1: //| mov64 TMP1, true_value; //|2: //| mov WORK[target], TMP1; dasm_put(Dst, 3368, Dt28([value]), (unsigned int)(false_value), (unsigned int)((false_value)>>32), (unsigned int)(true_value), (unsigned int)((true_value)>>32), Dt28([target])); #line 2304 "src/jit/x64/emit.dasc" break; } case MVM_OP_newtype: { MVMint16 dst = ins->operands[0].reg.orig; MVMint16 how = ins->operands[1].reg.orig; MVMint16 name = ins->operands[2].reg.orig; //| mov ARG1, TC; //| mov ARG2, aword WORK[name]; //| callp &MVM_repr_get_by_name; dasm_put(Dst, 3400, Dt28([name])); dasm_put(Dst, 118, (MVMuint32)((uintptr_t)(&MVM_repr_get_by_name)), (MVMuint32)((uintptr_t)(&MVM_repr_get_by_name) >> 32)); #line 2313 "src/jit/x64/emit.dasc" //| mov FUNCTION, REPR:RV->type_object_for; //| mov ARG1, TC; //| mov ARG2, aword WORK[how]; //| call FUNCTION; //| mov WORK[dst], RV; dasm_put(Dst, 3410, Dt13(->type_object_for), Dt28([how]), Dt28([dst])); #line 2318 "src/jit/x64/emit.dasc" break; } case MVM_OP_newmixintype: { MVMint16 dst = ins->operands[0].reg.orig; MVMint16 how = ins->operands[1].reg.orig; MVMint16 name = ins->operands[2].reg.orig; //| mov ARG1, TC; //| mov ARG2, aword WORK[name]; //| callp &MVM_repr_get_by_name; dasm_put(Dst, 3400, Dt28([name])); dasm_put(Dst, 118, (MVMuint32)((uintptr_t)(&MVM_repr_get_by_name)), (MVMuint32)((uintptr_t)(&MVM_repr_get_by_name) >> 32)); #line 2327 "src/jit/x64/emit.dasc" //| mov FUNCTION, REPR:RV->type_object_for; //| mov ARG1, TC; //| mov ARG2, aword WORK[how]; //| call FUNCTION; //| mov TMP1, OBJECT:RV->st; //| mov dword STABLE:TMP1->is_mixin_type, 1; //| mov WORK[dst], RV; dasm_put(Dst, 3436, Dt13(->type_object_for), Dt28([how]), DtD(->st), Dt12(->is_mixin_type), Dt28([dst])); #line 2334 "src/jit/x64/emit.dasc" break; } case MVM_OP_composetype:{ MVMint16 dst = ins->operands[0].reg.orig; MVMint16 obj = ins->operands[1].reg.orig; MVMint16 type = ins->operands[2].reg.orig; //| mov TMP6, aword WORK[obj]; //| mov FUNCTION, OBJECT:TMP6->st; //| mov FUNCTION, STABLE:FUNCTION->REPR; //| mov FUNCTION, REPR:FUNCTION->compose; //| mov ARG1, TC; //| get_stable, ARG2, TMP6; //| mov ARG3, aword WORK[type]; //| call FUNCTION; //| mov TMP1, aword WORK[obj]; //| mov WORK[dst], TMP1; dasm_put(Dst, 3473, Dt28([obj]), DtD(->st), Dt12(->REPR), Dt13(->compose), DtD(->st), Dt28([type]), Dt28([obj]), Dt28([dst])); #line 2350 "src/jit/x64/emit.dasc" break; } case MVM_OP_sp_fastbox_i: case MVM_OP_sp_fastbox_i_ic: case MVM_OP_sp_fastbox_bi: case MVM_OP_sp_fastbox_bi_ic: { MVMint32 use_cache = op == MVM_OP_sp_fastbox_i_ic || op == MVM_OP_sp_fastbox_bi_ic; MVMint16 dst = ins->operands[0].reg.orig; MVMint16 offset = ins->operands[3].lit_i16; MVMint16 val = ins->operands[4].reg.orig; if (use_cache) { MVMObject **cache = tc->instance->int_const_cache->cache[ins->operands[5].lit_i16]; MVMint16 dst = ins->operands[0].reg.orig; //| mov TMP1, WORK[val] //| cmp TMP1, 14 //| jg >1 //| cmp TMP1, -1 //| jl >1 //| inc TMP1 //| mov64 TMP2, (MVMuint64)cache //| mov TMP2, [TMP2 + TMP1 * 8] //| mov WORK[dst], TMP2 //| jmp >2 //|1: dasm_put(Dst, 3514, Dt28([val]), (unsigned int)((MVMuint64)cache), (unsigned int)(((MVMuint64)cache)>>32), Dt28([dst])); #line 2374 "src/jit/x64/emit.dasc" } emit_fastcreate(tc, compiler, jg, ins); //| mov aword WORK[dst], RV; //| mov TMP3, WORK[val]; dasm_put(Dst, 3560, Dt28([dst]), Dt28([val])); #line 2378 "src/jit/x64/emit.dasc" if (op == MVM_OP_sp_fastbox_i || op == MVM_OP_sp_fastbox_i_ic) { /* Normal integer */ //| mov qword [RV+offset], TMP3; dasm_put(Dst, 3569, offset); #line 2381 "src/jit/x64/emit.dasc" } else { /* Big integer; if it's in smallint range we poke it in directly, * and if not we do a function call to create a bigint. */ MVMuint16 val_offset = offset + 4; //| cmp TMP3, qword 2147483647LL //| jg >3 //| cmp TMP3, qword -2147483648LL //| jl >3 //| mov dword [RV+offset], MVM_BIGINT_32_FLAG //| mov dword [RV+val_offset], TMP3d //| jmp >4 //|3: //| mov ARG1, TC //| mov ARG2, RV //| add ARG2, offset //| mov ARG3, TMP3 //| callp &MVM_p6bigint_store_as_mp_int; dasm_put(Dst, 3574, 2147483647LL, -2147483648LL, offset, MVM_BIGINT_32_FLAG, val_offset, offset); dasm_put(Dst, 118, (MVMuint32)((uintptr_t)(&MVM_p6bigint_store_as_mp_int)), (MVMuint32)((uintptr_t)(&MVM_p6bigint_store_as_mp_int) >> 32)); #line 2399 "src/jit/x64/emit.dasc" //|4: dasm_put(Dst, 3622); #line 2400 "src/jit/x64/emit.dasc" } if (use_cache) { //|2: dasm_put(Dst, 345); #line 2403 "src/jit/x64/emit.dasc" } break; } case MVM_OP_sp_add_I: case MVM_OP_sp_sub_I: case MVM_OP_sp_mul_I: { MVMint16 a = ins->operands[3].reg.orig; MVMint16 b = ins->operands[4].reg.orig; MVMint16 c = ins->operands[0].reg.orig; MVMint16 offset = ins->operands[5].lit_i16; MVMint16 val_offset = offset + 4; MVMObject **cache = tc->instance->int_const_cache->cache[ins->operands[6].lit_i16]; /* See if they're both smallint. */ //| mov TMP1, WORK[a]; //| mov TMP2, WORK[b]; //| mov TMP4d, dword [TMP1 + offset]; //| cmp TMP4d, MVM_BIGINT_32_FLAG; //| jne >1; //| mov TMP4d, dword [TMP2 + offset]; //| cmp TMP4d, MVM_BIGINT_32_FLAG; //| jne >1; dasm_put(Dst, 3630, Dt28([a]), Dt28([b]), offset, MVM_BIGINT_32_FLAG, offset, MVM_BIGINT_32_FLAG); #line 2425 "src/jit/x64/emit.dasc" /* Both smallint, so try to do the addition. If it overflows, fall * back to the slow path. */ //| mov TMP4d, dword [TMP1 + val_offset] dasm_put(Dst, 3665, val_offset); #line 2429 "src/jit/x64/emit.dasc" switch (op) { case MVM_OP_sp_add_I: //| add TMP4d, dword [TMP2 + val_offset] dasm_put(Dst, 3670, val_offset); #line 2432 "src/jit/x64/emit.dasc" break; case MVM_OP_sp_sub_I: //| sub TMP4d, dword [TMP2 + val_offset] dasm_put(Dst, 3675, val_offset); #line 2435 "src/jit/x64/emit.dasc" break; case MVM_OP_sp_mul_I: //| imul TMP4d, dword [TMP2 + val_offset] dasm_put(Dst, 3680, val_offset); #line 2438 "src/jit/x64/emit.dasc" break; } //| jo >1 dasm_put(Dst, 3686); #line 2441 "src/jit/x64/emit.dasc" /* No overflow. See if it's in integer cache range. */ //| cmp TMP4d, 14 //| jg >2 //| cmp TMP4d, -1 //| jl >2 //| inc TMP4d //| mov64 TMP2, (MVMuint64)cache //| mov TMP2, [TMP2 + TMP4d * 8] //| mov WORK[c], TMP2 //| jmp >3 //|2: //| mov dword [rbp-0x30], TMP4d; dasm_put(Dst, 3691, (unsigned int)((MVMuint64)cache), (unsigned int)(((MVMuint64)cache)>>32), Dt28([c])); #line 2454 "src/jit/x64/emit.dasc" emit_fastcreate(tc, compiler, jg, ins); //| mov aword WORK[c], RV; //| mov TMP4d, dword [rbp-0x30]; //| mov dword [RV + offset], MVM_BIGINT_32_FLAG //| mov dword [RV + val_offset], TMP4d //| mov WORK[c], RV //| jmp >3 dasm_put(Dst, 3737, Dt28([c]), offset, MVM_BIGINT_32_FLAG, val_offset, Dt28([c])); #line 2461 "src/jit/x64/emit.dasc" /* The slow path does a function call. Make sure to read the args * before storing the result value, in case they're aimed at the * same register. */ //|1: dasm_put(Dst, 269); #line 2466 "src/jit/x64/emit.dasc" emit_fastcreate(tc, compiler, jg, ins); //| mov ARG1, TC; //| mov ARG2, WORK[a]; //| add ARG2, offset //| mov ARG3, WORK[b]; //| add ARG3, offset //| mov aword WORK[c], RV; //| mov ARG4, RV; //| add ARG4, offset dasm_put(Dst, 3762, Dt28([a]), offset, Dt28([b]), offset, Dt28([c]), offset); #line 2475 "src/jit/x64/emit.dasc" switch (op) { case MVM_OP_sp_add_I: //| callp &MVM_bigint_fallback_add; dasm_put(Dst, 116); dasm_put(Dst, 118, (MVMuint32)((uintptr_t)(&MVM_bigint_fallback_add)), (MVMuint32)((uintptr_t)(&MVM_bigint_fallback_add) >> 32)); dasm_put(Dst, 260); #line 2478 "src/jit/x64/emit.dasc" break; case MVM_OP_sp_sub_I: //| callp &MVM_bigint_fallback_sub; dasm_put(Dst, 116); dasm_put(Dst, 118, (MVMuint32)((uintptr_t)(&MVM_bigint_fallback_sub)), (MVMuint32)((uintptr_t)(&MVM_bigint_fallback_sub) >> 32)); dasm_put(Dst, 260); #line 2481 "src/jit/x64/emit.dasc" break; case MVM_OP_sp_mul_I: //| callp &MVM_bigint_fallback_mul; dasm_put(Dst, 116); dasm_put(Dst, 118, (MVMuint32)((uintptr_t)(&MVM_bigint_fallback_mul)), (MVMuint32)((uintptr_t)(&MVM_bigint_fallback_mul) >> 32)); dasm_put(Dst, 260); #line 2484 "src/jit/x64/emit.dasc" break; } //|3: dasm_put(Dst, 654); #line 2487 "src/jit/x64/emit.dasc" break; } case MVM_OP_sp_bool_I: { MVMint16 dst = ins->operands[0].reg.orig; MVMint16 a = ins->operands[1].reg.orig; MVMint16 offset = ins->operands[2].lit_i16; MVMint16 val_offset = offset + 4; /* Is this a smallint? */ //| mov TMP1, WORK[a]; //| mov TMP4d, dword [TMP1 + offset]; //| cmp TMP4d, MVM_BIGINT_32_FLAG; //| jne >1; dasm_put(Dst, 3794, Dt28([a]), offset, MVM_BIGINT_32_FLAG); #line 2499 "src/jit/x64/emit.dasc" /* Smallbigint. Test the 32bit value for nonzero. */ //| mov TMP4d, dword [TMP1 + val_offset] //| test TMP4d, TMP4d; //| setnz TMP3b; //| movzx TMP3, TMP3b; //| mov WORK[dst], TMP3; //| jmp >2 //|1: dasm_put(Dst, 3812, val_offset, Dt28([dst])); #line 2507 "src/jit/x64/emit.dasc" /* Bigint; check a->used for nonzero. */ //| mov TMP4, [TMP1 + offset] //| mov TMP3d, dword MPINT:TMP4->used; //| test TMP3d, TMP3d; //| setnz TMP3b; //| movzx TMP3, TMP3b; //| mov WORK[dst], TMP3; //|2: dasm_put(Dst, 3838, offset, Dt23(->used), Dt28([dst])); #line 2515 "src/jit/x64/emit.dasc" break; } case MVM_OP_getcomp: { MVMint16 dst = ins->operands[0].reg.orig; MVMint16 comp = ins->operands[1].reg.orig; //| mov ARG1, TC->instance; //| lea ARG1, MVMINSTANCE:ARG1->mutex_compiler_registry; //| callp &uv_mutex_lock; dasm_put(Dst, 3864, Dt27(->instance), DtB(->mutex_compiler_registry)); dasm_put(Dst, 118, (MVMuint32)((uintptr_t)(&uv_mutex_lock)), (MVMuint32)((uintptr_t)(&uv_mutex_lock) >> 32)); #line 2523 "src/jit/x64/emit.dasc" //| mov ARG1, TC; //| mov ARG2, TC->instance; //| mov ARG2, MVMINSTANCE:ARG2->compiler_registry; //| mov ARG3, aword WORK[comp]; //| callp &MVM_repr_at_key_o; dasm_put(Dst, 3874, Dt27(->instance), DtB(->compiler_registry), Dt28([comp])); dasm_put(Dst, 118, (MVMuint32)((uintptr_t)(&MVM_repr_at_key_o)), (MVMuint32)((uintptr_t)(&MVM_repr_at_key_o) >> 32)); #line 2528 "src/jit/x64/emit.dasc" //| mov WORK[dst], RV; //| mov ARG1, TC->instance; //| lea ARG1, MVMINSTANCE:ARG1->mutex_compiler_registry; //| callp &uv_mutex_unlock; dasm_put(Dst, 3897, Dt28([dst]), Dt27(->instance), DtB(->mutex_compiler_registry)); dasm_put(Dst, 118, (MVMuint32)((uintptr_t)(&uv_mutex_unlock)), (MVMuint32)((uintptr_t)(&uv_mutex_unlock) >> 32)); dasm_put(Dst, 260); #line 2532 "src/jit/x64/emit.dasc" break; } default: MVM_panic(1, "Can't JIT opcode <%s>", ins->info->name); } } /* Call argument decoder */ static void load_call_arg(MVMThreadContext *tc, MVMJitCompiler *compiler, MVMJitGraph *jg, MVMJitCallArg arg) { switch(arg.type) { case MVM_JIT_INTERP_VAR: switch (arg.v.ivar) { case MVM_JIT_INTERP_TC: //| mov TMP6, TC; dasm_put(Dst, 3916); #line 2549 "src/jit/x64/emit.dasc" break; case MVM_JIT_INTERP_CU: //| mov TMP6, CU; dasm_put(Dst, 3921); #line 2552 "src/jit/x64/emit.dasc" break; case MVM_JIT_INTERP_FRAME: //| mov TMP6, TC->cur_frame; dasm_put(Dst, 219, Dt27(->cur_frame)); #line 2555 "src/jit/x64/emit.dasc" break; case MVM_JIT_INTERP_PARAMS: //| mov TMP6, TC->cur_frame; //| lea TMP6, FRAME:TMP6->params; dasm_put(Dst, 3926, Dt27(->cur_frame), Dt2(->params)); #line 2559 "src/jit/x64/emit.dasc" break; case MVM_JIT_INTERP_CALLER: //| mov TMP6, TC->cur_frame; //| mov TMP6, aword FRAME:TMP6->caller; dasm_put(Dst, 3935, Dt27(->cur_frame), Dt2(->caller)); #line 2563 "src/jit/x64/emit.dasc" break; } break; case MVM_JIT_REG_VAL: //| mov TMP6, qword WORK[arg.v.reg]; dasm_put(Dst, 3944, Dt28([arg.v.reg])); #line 2568 "src/jit/x64/emit.dasc" break; case MVM_JIT_REG_VAL_F: //| mov TMP6, qword WORK[arg.v.reg]; dasm_put(Dst, 3944, Dt28([arg.v.reg])); #line 2571 "src/jit/x64/emit.dasc" break; case MVM_JIT_REG_ADDR: //| lea TMP6, WORK[arg.v.reg]; dasm_put(Dst, 3949, Dt28([arg.v.reg])); #line 2574 "src/jit/x64/emit.dasc" break; case MVM_JIT_STR_IDX: //| get_string TMP6, arg.v.lit_i64; MVM_cu_ensure_string_decoded(tc, jg->sg->sf->body.cu, arg.v.lit_i64); dasm_put(Dst, 3954, Dt29(->body.strings), Dt15([arg.v.lit_i64])); #line 2577 "src/jit/x64/emit.dasc" break; case MVM_JIT_LITERAL: //| mov TMP6, arg.v.lit_i64; dasm_put(Dst, 3963, arg.v.lit_i64); #line 2580 "src/jit/x64/emit.dasc" break; case MVM_JIT_LITERAL_64: case MVM_JIT_LITERAL_PTR: case MVM_JIT_LITERAL_F: //| mov64 TMP6, arg.v.lit_i64; dasm_put(Dst, 3968, (unsigned int)(arg.v.lit_i64), (unsigned int)((arg.v.lit_i64)>>32)); #line 2585 "src/jit/x64/emit.dasc" break; case MVM_JIT_REG_STABLE: //| mov TMP6, qword WORK[arg.v.reg]; //| mov TMP6, OBJECT:TMP6->st; dasm_put(Dst, 277, Dt28([arg.v.reg]), DtD(->st)); #line 2589 "src/jit/x64/emit.dasc" break; case MVM_JIT_REG_OBJBODY: //| mov TMP6, qword WORK[arg.v.reg]; //| lea TMP6, STOOGE:TMP6->data; dasm_put(Dst, 3973, Dt28([arg.v.reg]), DtE(->data)); #line 2593 "src/jit/x64/emit.dasc" break; case MVM_JIT_REG_DYNIDX: //| get_cur_op TMP5; //| xor TMP6, TMP6; //| mov TMP6w, U16:TMP5[arg.v.reg]; //| mov TMP6, qword [WORK + TMP6*8]; dasm_put(Dst, 3982, Dt27(->interp_cur_op), Dt20([arg.v.reg])); #line 2599 "src/jit/x64/emit.dasc" break; case MVM_JIT_DATA_LABEL: //| lea TMP6, [=>(arg.v.lit_i64)]; dasm_put(Dst, 4002, (arg.v.lit_i64)); #line 2602 "src/jit/x64/emit.dasc" break; case MVM_JIT_PARAM_I64: //| mov TMP6, qword WORK[arg.v.lit_i64]; dasm_put(Dst, 3944, Dt28([arg.v.lit_i64])); #line 2605 "src/jit/x64/emit.dasc" break; case MVM_JIT_PARAM_I64_RW: //| lea TMP6, qword WORK[arg.v.lit_i64]; dasm_put(Dst, 3949, Dt28([arg.v.lit_i64])); #line 2608 "src/jit/x64/emit.dasc" break; case MVM_JIT_PARAM_DOUBLE: //| mov TMP6, qword WORK[arg.v.lit_i64]; dasm_put(Dst, 3944, Dt28([arg.v.lit_i64])); #line 2611 "src/jit/x64/emit.dasc" break; case MVM_JIT_PARAM_PTR: //| mov TMP6, aword WORK[arg.v.lit_i64]; //| mov TMP6, aword STOOGE:TMP6->data; dasm_put(Dst, 277, Dt28([arg.v.lit_i64]), DtE(->data)); #line 2615 "src/jit/x64/emit.dasc" break; case MVM_JIT_PARAM_VMARRAY: //| mov TMP6, aword WORK[arg.v.lit_i64]; //| mov TMP6, aword VMARRAY:TMP6->body.slots; dasm_put(Dst, 277, Dt28([arg.v.lit_i64]), DtF(->body.slots)); #line 2619 "src/jit/x64/emit.dasc" break; case MVM_JIT_PARAM_CARRAY: //| mov TMP6, aword WORK[arg.v.lit_i64]; //| mov TMP6, aword CARRAY:TMP6->body.storage; dasm_put(Dst, 277, Dt28([arg.v.lit_i64]), Dt10(->body.storage)); #line 2623 "src/jit/x64/emit.dasc" break; case MVM_JIT_SPESH_SLOT_VALUE: //| get_spesh_slot TMP6, arg.v.lit_i64; dasm_put(Dst, 4007, Dt27(->cur_frame), Dt2(->effective_spesh_slots), Dt15([arg.v.lit_i64])); #line 2626 "src/jit/x64/emit.dasc" break; case MVM_JIT_STACK_VALUE: //| mov TMP6, [rbp-(0x28+arg.v.lit_i64*8)]; dasm_put(Dst, 4020, -(0x28+arg.v.lit_i64*8)); #line 2629 "src/jit/x64/emit.dasc" break; default: MVM_oops(tc, "JIT: Unknown JIT argument type %d", arg.type); } } static void emit_gpr_arg(MVMThreadContext *tc, MVMJitCompiler *compiler, MVMJitGraph *jg, MVMint32 i) { switch (i) { case 0: //| mov ARG1, TMP6; dasm_put(Dst, 4025); #line 2640 "src/jit/x64/emit.dasc" break; case 1: //| mov ARG2, TMP6; dasm_put(Dst, 4029); #line 2643 "src/jit/x64/emit.dasc" break; case 2: //| mov ARG3, TMP6; dasm_put(Dst, 4033); #line 2646 "src/jit/x64/emit.dasc" break; case 3: //| mov ARG4, TMP6; dasm_put(Dst, 4037); #line 2649 "src/jit/x64/emit.dasc" break; //|.if POSIX case 4: //| mov ARG5, TMP6; dasm_put(Dst, 4041); break; #line 2654 "src/jit/x64/emit.dasc" case 5: //| mov ARG6, TMP6; dasm_put(Dst, 4045); break; #line 2657 "src/jit/x64/emit.dasc" //|.endif default: MVM_oops(tc, "JIT: can't store %d arguments in GPR", i); } } static void emit_sse_arg(MVMThreadContext *tc, MVMJitCompiler *compiler, MVMJitGraph *jg, MVMint32 i) { switch (i) { case 0: //| movd ARG1F, TMP6; dasm_put(Dst, 4049); #line 2668 "src/jit/x64/emit.dasc" break; case 1: //| movd ARG2F, TMP6; dasm_put(Dst, 4055); #line 2671 "src/jit/x64/emit.dasc" break; case 2: //| movd ARG3F, TMP6; dasm_put(Dst, 4061); #line 2674 "src/jit/x64/emit.dasc" break; case 3: //| movd ARG4F, TMP6; dasm_put(Dst, 4067); #line 2677 "src/jit/x64/emit.dasc" break; //|.if POSIX case 4: //| movd ARG5F, TMP6; dasm_put(Dst, 4073); break; #line 2682 "src/jit/x64/emit.dasc" case 5: //| movd ARG6F, TMP6; dasm_put(Dst, 4079); break; #line 2685 "src/jit/x64/emit.dasc" case 6: //| movd ARG7F, TMP6; dasm_put(Dst, 4086); break; #line 2688 "src/jit/x64/emit.dasc" case 7: //| movd ARG8F, TMP6; dasm_put(Dst, 4093); break; #line 2691 "src/jit/x64/emit.dasc" //|.endif default: MVM_oops(tc, "JIT: can't put %d arguments in SSE", i); } } static void emit_stack_arg(MVMThreadContext *tc, MVMJitCompiler *compiler, MVMJitGraph *jg, MVMint32 arg_size, MVMint32 pos) { /* basically, stack arguments are passed in right-to-left order on both POSIX and W64 backends, it seems. Thus the most logical thing to do is to count from the stack top upwards. */ if (pos + arg_size > 160) { MVM_oops(tc, "JIT: trying to pass arguments " " in local space (stack top offset:" " %d, size: %d)", pos, arg_size); } switch(arg_size) { case 1: //| mov byte [rsp+pos], TMP6b; dasm_put(Dst, 4100, pos); #line 2710 "src/jit/x64/emit.dasc" break; case 2: //| mov word [rsp+pos], TMP6w; dasm_put(Dst, 4107, pos); #line 2713 "src/jit/x64/emit.dasc" break; case 4: //| mov dword [rsp+pos], TMP6d; dasm_put(Dst, 4108, pos); #line 2716 "src/jit/x64/emit.dasc" break; case 8: //| mov qword [rsp+pos], TMP6; dasm_put(Dst, 4115, pos); #line 2719 "src/jit/x64/emit.dasc" break; default: MVM_oops(tc, "JIT: can't pass arguments size %d bytes", arg_size); } } static void emit_posix_callargs(MVMThreadContext *tc, MVMJitCompiler *compiler, MVMJitGraph *jg, MVMJitCallArg args[], MVMint32 num_args) { MVMint32 num_gpr = 0, num_fpr = 0, num_stack = 0, i; MVMJitCallArg in_gpr[6], in_fpr[8], *on_stack = NULL; if (num_args > 6) on_stack = MVM_malloc(sizeof(MVMJitCallArg) * (num_args - 6)); /* divide in gpr, fpr, stack values */ for (i = 0; i < num_args; i++) { switch (args[i].type) { case MVM_JIT_INTERP_VAR: case MVM_JIT_REG_VAL: case MVM_JIT_REG_ADDR: case MVM_JIT_REG_OBJBODY: case MVM_JIT_REG_STABLE: case MVM_JIT_REG_DYNIDX: case MVM_JIT_STR_IDX: case MVM_JIT_LITERAL: case MVM_JIT_LITERAL_64: case MVM_JIT_LITERAL_PTR: case MVM_JIT_DATA_LABEL: case MVM_JIT_ARG_I64: case MVM_JIT_ARG_I64_RW: case MVM_JIT_ARG_PTR: case MVM_JIT_ARG_VMARRAY: case MVM_JIT_PARAM_I64: case MVM_JIT_PARAM_I64_RW: case MVM_JIT_PARAM_PTR: case MVM_JIT_PARAM_VMARRAY: case MVM_JIT_PARAM_CARRAY: case MVM_JIT_SPESH_SLOT_VALUE: case MVM_JIT_STACK_VALUE: if (num_gpr < 6) { in_gpr[num_gpr++] = args[i]; } else { on_stack[num_stack++] = args[i]; } break; case MVM_JIT_ARG_DOUBLE: case MVM_JIT_PARAM_DOUBLE: case MVM_JIT_REG_VAL_F: case MVM_JIT_LITERAL_F: if (num_fpr < 8) { in_fpr[num_fpr++] = args[i]; } else { on_stack[num_stack++] = args[i]; } break; default: MVM_oops(tc, "JIT: Unknown JIT argument type %d for emit_posix_callargs", args[i].type); } } for (i = 0; i < num_gpr; i++) { load_call_arg(tc, compiler, jg, in_gpr[i]); emit_gpr_arg(tc, compiler, jg, i); } for (i = 0; i < num_fpr; i++) { load_call_arg(tc, compiler, jg, in_fpr[i]); emit_sse_arg(tc, compiler, jg, i); } /* push right-to-left */ for (i = 0; i < num_stack; i++) { load_call_arg(tc, compiler, jg, on_stack[i]); // I'm not sure this is correct, btw emit_stack_arg(tc, compiler, jg, 8, i*8); } if (on_stack) MVM_free(on_stack); } static void emit_win64_callargs(MVMThreadContext *tc, MVMJitCompiler *compiler, MVMJitGraph *jg, MVMJitCallArg args[], MVMint32 num_args) { MVMint32 i; MVMint32 num_reg_args = (num_args > 4 ? 4 : num_args); for (i = 0; i < num_reg_args; i++) { load_call_arg(tc, compiler, jg, args[i]); if (args[i].type == MVM_JIT_REG_VAL_F || args[i].type == MVM_JIT_LITERAL_F || args[i].type == MVM_JIT_ARG_DOUBLE || args[i].type == MVM_JIT_PARAM_DOUBLE) { emit_sse_arg(tc, compiler, jg, i); } else { emit_gpr_arg(tc, compiler, jg, i); } } for (; i < num_args; i++) { load_call_arg(tc, compiler, jg, args[i]); emit_stack_arg(tc, compiler, jg, 8, i * 8); } } void MVM_jit_emit_call_c(MVMThreadContext *tc, MVMJitCompiler *compiler, MVMJitGraph *jg, MVMJitCallC * call_spec) { //|.if WIN32; #line 2821 "src/jit/x64/emit.dasc" //|.else; emit_posix_callargs(tc, compiler, jg, call_spec->args, call_spec->num_args); //|.endif /* Emit the call. I think we should be able to do something smarter than * store the constant into the bytecode, like a data segment. But I'm * not sure. */ //| callp call_spec->func_ptr; dasm_put(Dst, 116); dasm_put(Dst, 118, (MVMuint32)((uintptr_t)(call_spec->func_ptr)), (MVMuint32)((uintptr_t)(call_spec->func_ptr) >> 32)); dasm_put(Dst, 260); #line 2828 "src/jit/x64/emit.dasc" /* right, now determine what to do with the return value */ switch(call_spec->rv_mode) { case MVM_JIT_RV_VOID: break; case MVM_JIT_RV_INT: case MVM_JIT_RV_PTR: //| mov WORK[call_spec->rv_idx], RV; dasm_put(Dst, 415, Dt28([call_spec->rv_idx])); #line 2835 "src/jit/x64/emit.dasc" break; case MVM_JIT_RV_INT_NEGATED: //| test RV, RV; //| setz TMP2b; //| movzx TMP2, TMP2b; //| mov WORK[call_spec->rv_idx], TMP2; dasm_put(Dst, 4122, Dt28([call_spec->rv_idx])); #line 2841 "src/jit/x64/emit.dasc" break; case MVM_JIT_RV_NUM: //| movsd qword WORK[call_spec->rv_idx], RVF; dasm_put(Dst, 1842, Dt28([call_spec->rv_idx])); #line 2844 "src/jit/x64/emit.dasc" break; case MVM_JIT_RV_DEREF: //| mov TMP1, [RV]; //| mov WORK[call_spec->rv_idx], TMP1; dasm_put(Dst, 4137, Dt28([call_spec->rv_idx])); #line 2848 "src/jit/x64/emit.dasc" break; case MVM_JIT_RV_ADDR: /* store local at address */ //| mov TMP1, WORK[call_spec->rv_idx]; //| mov [RV], TMP1; dasm_put(Dst, 4145, Dt28([call_spec->rv_idx])); #line 2853 "src/jit/x64/emit.dasc" break; case MVM_JIT_RV_DYNIDX: /* store in register relative to cur_op */ //| get_cur_op TMP1; //| xor TMP2, TMP2; //| mov TMP2w, word [TMP1 + call_spec->rv_idx*2]; //| mov aword [WORK + TMP2*8], RV; dasm_put(Dst, 4153, Dt27(->interp_cur_op), call_spec->rv_idx*2); #line 2860 "src/jit/x64/emit.dasc" break; case MVM_JIT_RV_DEREF_OR_VMNULL: //| test RV, RV; //| jz >4; //| mov TMP1, [RV]; //| jmp >5; //|4: //| get_vmnull TMP1; //|5: //| mov WORK[call_spec->rv_idx], TMP1; dasm_put(Dst, 4172, Dt27(->instance), DtB(->VMNull), Dt28([call_spec->rv_idx])); #line 2870 "src/jit/x64/emit.dasc" break; case MVM_JIT_RV_TO_STACK: if (call_spec->rv_type == MVM_NATIVECALL_ARG_CHAR) { //| cbw; dasm_put(Dst, 4203); #line 2874 "src/jit/x64/emit.dasc" } if (call_spec->rv_type == MVM_NATIVECALL_ARG_CHAR || call_spec->rv_type == MVM_NATIVECALL_ARG_SHORT) { //| cwde; dasm_put(Dst, 4204); #line 2877 "src/jit/x64/emit.dasc" } if (call_spec->rv_type == MVM_NATIVECALL_ARG_CHAR || call_spec->rv_type == MVM_NATIVECALL_ARG_SHORT || call_spec->rv_type == MVM_NATIVECALL_ARG_INT) { //| cdqe; dasm_put(Dst, 4206); #line 2880 "src/jit/x64/emit.dasc" } if (call_spec->rv_type == MVM_NATIVECALL_ARG_UCHAR) { //| and RV, 0xFF dasm_put(Dst, 4209); #line 2883 "src/jit/x64/emit.dasc" } else if (call_spec->rv_type == MVM_NATIVECALL_ARG_USHORT) { //| and RV, 0xFFFF dasm_put(Dst, 4217); #line 2886 "src/jit/x64/emit.dasc" } else if (call_spec->rv_type == MVM_NATIVECALL_ARG_UINT) { //| and RV, 0xFFFFFFFF dasm_put(Dst, 4226); #line 2889 "src/jit/x64/emit.dasc" } else if (call_spec->rv_type == MVM_NATIVECALL_ARG_ULONG && sizeof(long) == 4) { //| and RV, 0xFFFFFFFF dasm_put(Dst, 4226); #line 2892 "src/jit/x64/emit.dasc" } //| mov [rbp-(0x28+call_spec->rv_idx*8)], RV; dasm_put(Dst, 4232, -(0x28+call_spec->rv_idx*8)); #line 2894 "src/jit/x64/emit.dasc" break; } } void MVM_jit_emit_block_branch(MVMThreadContext *tc, MVMJitCompiler *compiler, MVMJitGraph *jg, MVMJitBranch * branch) { MVMSpeshIns *ins = branch->ins; MVMint32 name = branch->dest; /* move gc sync point to the front so as to not have * awkward dispatching issues */ //| gc_sync_point; dasm_put(Dst, 4237, Dt27(->gc_status)); dasm_put(Dst, 118, (MVMuint32)((uintptr_t)(&MVM_gc_enter_from_interrupt)), (MVMuint32)((uintptr_t)(&MVM_gc_enter_from_interrupt) >> 32)); dasm_put(Dst, 1575); #line 2905 "src/jit/x64/emit.dasc" if (ins == NULL || ins->info->opcode == MVM_OP_goto) { if (name == MVM_JIT_BRANCH_EXIT) { //| jmp ->exit dasm_put(Dst, 4252); #line 2908 "src/jit/x64/emit.dasc" } else { //| jmp =>(name) dasm_put(Dst, 4257, (name)); #line 2910 "src/jit/x64/emit.dasc" } } else { MVMint16 val = ins->operands[0].reg.orig; switch(ins->info->opcode) { case MVM_OP_if_i: //| mov rax, WORK[val]; //| test rax, rax; //| jnz =>(name); // jump to dynamic label dasm_put(Dst, 4261, Dt28([val]), (name)); #line 2918 "src/jit/x64/emit.dasc" break; case MVM_OP_unless_i: //| mov rax, WORK[val]; //| test rax, rax; //| jz =>(name); dasm_put(Dst, 4272, Dt28([val]), (name)); #line 2923 "src/jit/x64/emit.dasc" break; case MVM_OP_if_n: //| movd xmm0, qword WORK[val]; //| xorpd xmm1, xmm1; // make it zero //| ucomisd xmm0, xmm1; //| jp =>(name); // is NaN? //| jne =>(name); // not equal to zero? we're golden dasm_put(Dst, 4283, Dt28([val]), (name), (name)); #line 2930 "src/jit/x64/emit.dasc" break; case MVM_OP_unless_n: //| movd xmm0, qword WORK[val]; //| xorpd xmm1, xmm1; // make it zero //| ucomisd xmm0, xmm1; //| jp >1; // is NaN //| jne >1; // is not zero //| jmp =>(name); // it is zero yay! //|1: dasm_put(Dst, 4304, Dt28([val]), (name)); #line 2939 "src/jit/x64/emit.dasc" break; case MVM_OP_if_s0: case MVM_OP_unless_s0: //| mov ARG1, TC; //| mov ARG2, WORK[val]; //| callp &MVM_coerce_istrue_s; dasm_put(Dst, 3400, Dt28([val])); dasm_put(Dst, 118, (MVMuint32)((uintptr_t)(&MVM_coerce_istrue_s)), (MVMuint32)((uintptr_t)(&MVM_coerce_istrue_s) >> 32)); #line 2945 "src/jit/x64/emit.dasc" //| test RV, RV; dasm_put(Dst, 4332); #line 2946 "src/jit/x64/emit.dasc" if (ins->info->opcode == MVM_OP_unless_s0) //| jz =>(name); dasm_put(Dst, 4279, (name)); #line 2948 "src/jit/x64/emit.dasc" else //| jnz =>(name); dasm_put(Dst, 4268, (name)); #line 2950 "src/jit/x64/emit.dasc" break; case MVM_OP_ifnonnull: //| mov TMP1, WORK[val]; //| test TMP1, TMP1; //| jz >1; //| get_vmnull TMP2; //| cmp TMP1, TMP2; //| je >1; //| jmp =>(name); //|1: dasm_put(Dst, 4341, Dt28([val]), Dt27(->instance), DtB(->VMNull), (name)); #line 2960 "src/jit/x64/emit.dasc" break; case MVM_OP_if_s: //| mov TMP1, WORK[val]; //| test TMP1, TMP1; //| jz >1; //| cmp dword STRING:TMP1->body.num_graphs, 0; //| je >1; //| jmp =>(name); //|1: dasm_put(Dst, 4373, Dt28([val]), Dt14(->body.num_graphs), (name)); #line 2969 "src/jit/x64/emit.dasc" break; case MVM_OP_unless_s: //| mov TMP1, WORK[val]; //| test TMP1, TMP1; //| jz =>(name); //| cmp dword STRING:TMP1->body.num_graphs, 0; //| je =>(name); //|1: dasm_put(Dst, 4398, Dt28([val]), (name), Dt14(->body.num_graphs), (name)); #line 2977 "src/jit/x64/emit.dasc" break; case MVM_OP_indexat: case MVM_OP_indexnat: { MVMint16 offset = ins->operands[1].reg.orig; MVMuint32 str_idx = ins->operands[2].lit_str_idx; //| mov ARG1, TC; //| mov ARG2, WORK[val]; //| mov ARG3, WORK[offset]; //| get_string ARG4, str_idx; dasm_put(Dst, 4418, Dt28([val]), Dt28([offset])); MVM_cu_ensure_string_decoded(tc, jg->sg->sf->body.cu, str_idx); #line 2986 "src/jit/x64/emit.dasc" //| callp &MVM_string_char_at_in_string; dasm_put(Dst, 4431, Dt29(->body.strings), Dt15([str_idx])); dasm_put(Dst, 118, (MVMuint32)((uintptr_t)(&MVM_string_char_at_in_string)), (MVMuint32)((uintptr_t)(&MVM_string_char_at_in_string) >> 32)); dasm_put(Dst, 260); #line 2987 "src/jit/x64/emit.dasc" /* This subtlety is due to the value being overloaded to * -2 if it is out of bounds. Note that -1 is passed as a * 32 bit integer, but this magically works in a 64 bit * comparison because 32 bit values are sign-extended */ //| cmp RV, -1; dasm_put(Dst, 4441); #line 2992 "src/jit/x64/emit.dasc" if (ins->info->opcode == MVM_OP_indexat) //| jle =>(name); dasm_put(Dst, 4448, (name)); #line 2994 "src/jit/x64/emit.dasc" else { //| jne =>(name); dasm_put(Dst, 4268, (name)); #line 2997 "src/jit/x64/emit.dasc" } break; } default: MVM_panic(1, "JIT: Can't handle conditional <%s>", ins->info->name); } } } void MVM_jit_emit_label(MVMThreadContext *tc, MVMJitCompiler *compiler, MVMJitGraph *jg, MVMint32 label) { //| =>(label): dasm_put(Dst, 245, (label)); #line 3009 "src/jit/x64/emit.dasc" } void MVM_jit_emit_branch(MVMThreadContext *tc, MVMJitCompiler *compiler, MVMint32 label) { //| jmp =>(label); dasm_put(Dst, 4257, (label)); #line 3013 "src/jit/x64/emit.dasc" } void MVM_jit_emit_conditional_branch(MVMThreadContext *tc, MVMJitCompiler *compiler, MVMint32 cond, MVMint32 label, MVMuint8 test_type) { MVMint32 is_float = (test_type == MVM_reg_num32 || test_type == MVM_reg_num64); /* Intel Manual Vol 1 ch7 Table 7-4 'Conditional Jump Instructions', * also Table 8-7 'Setting of EFLAG Status Flags for Floating Point Number Comparisons' */ switch (cond) { case MVM_JIT_LT: if (is_float) { /* CF & !PF */ //| jp >1; //| jb =>(label); //|1: dasm_put(Dst, 4452, (label)); #line 3027 "src/jit/x64/emit.dasc" } else { /* SF ^ OF */ //| jl =>(label); dasm_put(Dst, 4462, (label)); #line 3030 "src/jit/x64/emit.dasc" } break; case MVM_JIT_LE: if (is_float) { /* (CF | ZF) & !PF */ //| jp >1; //| jbe =>(label); //|1: dasm_put(Dst, 4466, (label)); #line 3038 "src/jit/x64/emit.dasc" } else { /* (SF ^ OF) | ZF */ //| jle =>(label); dasm_put(Dst, 4448, (label)); #line 3041 "src/jit/x64/emit.dasc" } break; case MVM_JIT_EQ: if (is_float) { /* ZF & !PF */ //| jp >1; //| je =>(label); //|1: dasm_put(Dst, 4476, (label)); #line 3049 "src/jit/x64/emit.dasc" } else { /* ZF */ //| je =>(label); dasm_put(Dst, 4279, (label)); #line 3052 "src/jit/x64/emit.dasc" } break; case MVM_JIT_NE: if (is_float) { /* PF | !ZF */ //| jp =>(label); dasm_put(Dst, 4486, (label)); #line 3058 "src/jit/x64/emit.dasc" } /* !ZF */ //| jne =>(label); dasm_put(Dst, 4268, (label)); #line 3061 "src/jit/x64/emit.dasc" break; case MVM_JIT_GE: if (is_float) { /* !CF */ //| jae =>(label); dasm_put(Dst, 4490, (label)); #line 3066 "src/jit/x64/emit.dasc" } else { /* !(SF ^ OF) */ //| jge =>(label); dasm_put(Dst, 4494, (label)); #line 3069 "src/jit/x64/emit.dasc" } break; case MVM_JIT_GT: if (is_float) { /* !(CF | ZF) */ //| ja =>(label); dasm_put(Dst, 4498, (label)); #line 3075 "src/jit/x64/emit.dasc" } else { /* !((SF ^ OF) | ZF) */ //| jg =>(label); dasm_put(Dst, 4502, (label)); #line 3078 "src/jit/x64/emit.dasc" } break; case MVM_JIT_NZ: if (is_float) { /* PF set, Unordered to zero is nonzero */ //| jp =>(label); dasm_put(Dst, 4486, (label)); #line 3084 "src/jit/x64/emit.dasc" } //| jnz =>(label); dasm_put(Dst, 4268, (label)); #line 3086 "src/jit/x64/emit.dasc" break; case MVM_JIT_ZR: if (is_float) { //| jp >1; //| jz =>(label); //|1: dasm_put(Dst, 4476, (label)); #line 3092 "src/jit/x64/emit.dasc" } else { //| jz =>(label); dasm_put(Dst, 4279, (label)); #line 3094 "src/jit/x64/emit.dasc" } break; default: abort(); } } void MVM_jit_emit_guard(MVMThreadContext *tc, MVMJitCompiler *compiler, MVMJitGraph *jg, MVMJitGuard *guard) { MVMint16 op = guard->ins->info->opcode; MVMint16 obj = guard->ins->operands[op == MVM_OP_sp_guardsf ? 0 : 1].reg.orig; /* load object and spesh slot value, except for those that don't need it */ //| mov TMP1, WORK[obj]; dasm_put(Dst, 604, Dt28([obj])); #line 3108 "src/jit/x64/emit.dasc" if (op != MVM_OP_sp_guardjustconc && op != MVM_OP_sp_guardjusttype && op != MVM_OP_sp_guardnonzero && op != MVM_OP_sp_guardhll && op != MVM_OP_sp_rebless) { MVMint16 spesh_idx = guard->ins->operands[op == MVM_OP_sp_guardsf ? 1 : 2].lit_i16; //| get_spesh_slot TMP2, spesh_idx; dasm_put(Dst, 4506, Dt27(->cur_frame), Dt2(->effective_spesh_slots), Dt15([spesh_idx])); #line 3113 "src/jit/x64/emit.dasc" } if (op == MVM_OP_sp_guard) { /* object in question should just match the type, so it shouldn't * be zero, and the STABLE should be equal to the value in the spesh * slot */ /* check for null */ //| test TMP1, TMP1; //| jz >1; dasm_put(Dst, 4519); #line 3121 "src/jit/x64/emit.dasc" /* get stable and compare */ //| cmp TMP2, OBJECT:TMP1->st; //| jne >1; dasm_put(Dst, 4527, DtD(->st)); #line 3124 "src/jit/x64/emit.dasc" /* we're good, no need to deopt */ } else if (op == MVM_OP_sp_guardtype) { /* object in question should be a type object, so it shouldn't * be zero, should not be concrete, and the STABLE should be * equal to the value in the spesh slot */ /* check for null */ //| test TMP1, TMP1; //| jz >1; dasm_put(Dst, 4519); #line 3132 "src/jit/x64/emit.dasc" /* check if type object (not concrete) */ //| test_type_object TMP1; dasm_put(Dst, 4536, DtD(->header.flags1), MVM_CF_TYPE_OBJECT); #line 3134 "src/jit/x64/emit.dasc" /* if zero, this is a concrete object, and we should deopt */ //| jz >1; dasm_put(Dst, 3177); #line 3136 "src/jit/x64/emit.dasc" /* get stable and compare */ //| cmp TMP2, OBJECT:TMP1->st; //| jne >1; dasm_put(Dst, 4527, DtD(->st)); #line 3139 "src/jit/x64/emit.dasc" /* we're good, no need to deopt */ } else if (op == MVM_OP_sp_guardconc) { /* object should be a non-null concrete (non-type) object */ //| test TMP1, TMP1; //| jz >1; dasm_put(Dst, 4519); #line 3144 "src/jit/x64/emit.dasc" /* shouldn't be type object */ //| test_type_object TMP1; //| jnz >1; dasm_put(Dst, 4543, DtD(->header.flags1), MVM_CF_TYPE_OBJECT); #line 3147 "src/jit/x64/emit.dasc" /* should have our stable */ //| cmp TMP2, OBJECT:TMP1->st; //| jne >1; dasm_put(Dst, 4527, DtD(->st)); #line 3150 "src/jit/x64/emit.dasc" } else if (op == MVM_OP_sp_guardhll) { /* get HLL owner and compare */ //| mov64 TMP2, guard->ins->operands[2].lit_ui64; //| mov TMP3, OBJECT:TMP1->st; //| cmp TMP2, STABLE:TMP3->hll_owner; //| jne >1; dasm_put(Dst, 4554, (unsigned int)(guard->ins->operands[2].lit_ui64), (unsigned int)((guard->ins->operands[2].lit_ui64)>>32), DtD(->st), Dt12(->hll_owner)); #line 3156 "src/jit/x64/emit.dasc" } else if (op == MVM_OP_sp_guardsf) { /* Should be an MVMCode */ //| cmp TMP2, CODE:TMP1->body.sf; //| jne >1; dasm_put(Dst, 4527, Dt1D(->body.sf)); #line 3160 "src/jit/x64/emit.dasc" } else if (op == MVM_OP_sp_guardobj) { /* object should match that from the spesh slot */ //| cmp TMP2, TMP1; //| jne >1; dasm_put(Dst, 4571); #line 3164 "src/jit/x64/emit.dasc" } else if (op == MVM_OP_sp_guardnonzero) { /* integer value should not be zero */ //| test TMP1, TMP1; //| jz >1; dasm_put(Dst, 4519); #line 3168 "src/jit/x64/emit.dasc" } else if (op == MVM_OP_sp_guardnotobj) { /* object should not match that from the spesh slot */ //| cmp TMP2, TMP1; //| je >1; dasm_put(Dst, 4579); #line 3172 "src/jit/x64/emit.dasc" } else if (op == MVM_OP_sp_guardjustconc) { /* object should be a non-null concrete (non-type) object; * exact type doesn't matter */ //| test TMP1, TMP1; //| jz >1; dasm_put(Dst, 4519); #line 3177 "src/jit/x64/emit.dasc" /* shouldn't be type object */ //| test_type_object TMP1; //| jnz >1; dasm_put(Dst, 4543, DtD(->header.flags1), MVM_CF_TYPE_OBJECT); #line 3180 "src/jit/x64/emit.dasc" } else if (op == MVM_OP_sp_guardjusttype) { /* object in question should be a type object, so it shouldn't * be zero, and should not be concrete */ /* check for null */ //| test TMP1, TMP1; //| jz >1; dasm_put(Dst, 4519); #line 3186 "src/jit/x64/emit.dasc" /* should be type object */ //| test_type_object TMP1; //| jz >1; dasm_put(Dst, 4587, DtD(->header.flags1), MVM_CF_TYPE_OBJECT); #line 3189 "src/jit/x64/emit.dasc" } else if (op == MVM_OP_sp_rebless) { MVMint16 dst = guard->ins->operands[0].reg.orig; MVMint16 new_type = guard->ins->operands[2].reg.orig; //| get_repr TMP5, TMP1; //| mov FUNCTION, REPR:TMP5->change_type; //| test FUNCTION, FUNCTION; //| jz >3; //| mov ARG2, TMP1; //| mov ARG1, TC; //| mov ARG3, WORK[new_type]; //| call FUNCTION; //| mov ARG1, TC; //| mov ARG2, WORK[obj]; //| mov WORK[dst], ARG2; //| callp &MVM_SC_WB_OBJ; dasm_put(Dst, 4598, DtD(->st), Dt12(->REPR), Dt13(->change_type), Dt28([new_type]), Dt28([obj]), Dt28([dst])); dasm_put(Dst, 118, (MVMuint32)((uintptr_t)(&MVM_SC_WB_OBJ)), (MVMuint32)((uintptr_t)(&MVM_SC_WB_OBJ) >> 32)); #line 3204 "src/jit/x64/emit.dasc" //| mov ARG1, TC; //| callp &MVM_spesh_deopt_all; dasm_put(Dst, 4646); dasm_put(Dst, 118, (MVMuint32)((uintptr_t)(&MVM_spesh_deopt_all)), (MVMuint32)((uintptr_t)(&MVM_spesh_deopt_all) >> 32)); #line 3206 "src/jit/x64/emit.dasc" //| jmp >1; //|3: //| throw_adhoc "REPR cannot change type"; dasm_put(Dst, 4657, (unsigned int)((uintptr_t)("REPR cannot change type")), (unsigned int)(((uintptr_t)("REPR cannot change type"))>>32)); dasm_put(Dst, 118, (MVMuint32)((uintptr_t)(&MVM_exception_throw_adhoc)), (MVMuint32)((uintptr_t)(&MVM_exception_throw_adhoc) >> 32)); dasm_put(Dst, 260); #line 3209 "src/jit/x64/emit.dasc" } /* If we're here, we didn't jump to deopt. Most of the time a guard * destination is the same real register, but if not then emit a store * here before jumping over the deopt code. */ if (op != MVM_OP_sp_guardsf) { MVMint16 dest = guard->ins->operands[0].reg.orig; if (dest != obj) //| mov WORK[dest], TMP1 dasm_put(Dst, 103, Dt28([dest])); #line 3217 "src/jit/x64/emit.dasc" } //| jmp >2; //|1: dasm_put(Dst, 2604); #line 3220 "src/jit/x64/emit.dasc" /* emit deopt */ //| mov ARG1, TC; //| mov ARG2, guard->deopt_idx; //| callp &MVM_spesh_deopt_one; dasm_put(Dst, 108, guard->deopt_idx); dasm_put(Dst, 118, (MVMuint32)((uintptr_t)(&MVM_spesh_deopt_one)), (MVMuint32)((uintptr_t)(&MVM_spesh_deopt_one) >> 32)); dasm_put(Dst, 260); #line 3224 "src/jit/x64/emit.dasc" /* jump out */ //| jmp ->exit; //|2: dasm_put(Dst, 4678); #line 3227 "src/jit/x64/emit.dasc" } void MVM_jit_emit_runbytecode(MVMThreadContext *tc, MVMJitCompiler *compiler, MVMJitGraph *jg, MVMJitRunByteCode *runcode) { MVMint16 i; MVMuint64 callsite = (MVMuint64)runcode->callsite; /* Store the argument map in a data section so we can get a pointer to it */ //|.data dasm_put(Dst, 116); #line 3235 "src/jit/x64/emit.dasc" //|5: dasm_put(Dst, 4685); #line 3236 "src/jit/x64/emit.dasc" for (i = 0; i < runcode->callsite->flag_count; i++) { //|.word (MVMuint16)runcode->map[i].reg.orig; dasm_put(Dst, 2563, (MVMuint16)runcode->map[i].reg.orig); #line 3238 "src/jit/x64/emit.dasc" } //|.code dasm_put(Dst, 0); #line 3240 "src/jit/x64/emit.dasc" /* The return address for the interpreter */ //| get_cur_op TMP2; //| mov TMP5, TC->cur_frame; //| mov aword FRAME:TMP5->return_address, TMP2; dasm_put(Dst, 4688, Dt27(->interp_cur_op), Dt27(->cur_frame), Dt2(->return_address)); #line 3245 "src/jit/x64/emit.dasc" /* Setup the frame for returning to our current position */ if (sizeof(MVMReturnType) == 1) { //| mov byte FRAME:TMP5->return_type, runcode->return_type; dasm_put(Dst, 4704, Dt2(->return_type), runcode->return_type); #line 3249 "src/jit/x64/emit.dasc" } else { MVM_panic(1, "JIT: MVMReturnType has unexpected size"); } /* The register for our return value */ if (runcode->return_type == MVM_RETURN_VOID) { //| mov aword FRAME:TMP5->return_value, NULL; dasm_put(Dst, 4710, Dt2(->return_value), NULL); #line 3256 "src/jit/x64/emit.dasc" } else { //| lea TMP2, WORK[runcode->return_register]; //| mov aword FRAME:TMP5->return_value, TMP2; dasm_put(Dst, 4716, Dt28([runcode->return_register]), Dt2(->return_value)); #line 3259 "src/jit/x64/emit.dasc" } //| mov ARG1, TC; //| mov ARG2, aword WORK[runcode->code_register] //|.if WIN32 //| mov64 TMP6, callsite; //| mov aword [rsp+0x20], TMP6; //| mov TMP6, TC->interp_reg_base; //| mov TMP6, [TMP6]; //| mov aword [rsp+0x28], TMP6; //| lea TMP6, [<5]; //| mov aword [rsp+0x30], TMP6; //| lea ARG3, [rsp+0x20]; //| mov ARG4, runcode->spesh_cand //|.else //| mov ARG3, runcode->spesh_cand //| mov64 TMP6, callsite; //| mov aword [rsp], TMP6; //| mov TMP6, TC->interp_reg_base; //| mov TMP6, [TMP6]; //| mov aword [rsp+0x08], TMP6; //| lea TMP6, [<5]; //| mov aword [rsp+0x10], TMP6; //|.endif //| callp &MVM_frame_dispatch dasm_put(Dst, 4725, Dt28([runcode->code_register]), runcode->spesh_cand, (unsigned int)(callsite), (unsigned int)((callsite)>>32), Dt27(->interp_reg_base)); dasm_put(Dst, 118, (MVMuint32)((uintptr_t)(&MVM_frame_dispatch)), (MVMuint32)((uintptr_t)(&MVM_frame_dispatch) >> 32)); dasm_put(Dst, 260); #line 3284 "src/jit/x64/emit.dasc" } void MVM_jit_emit_runccode(MVMThreadContext *tc, MVMJitCompiler *compiler, MVMJitGraph *jg, MVMJitRunCCode *runcode) { MVMint16 i; MVMuint64 callsite = (MVMuint64)runcode->callsite; /* Store the argument map in a data section so we can get a pointer to it */ //|.data dasm_put(Dst, 116); #line 3292 "src/jit/x64/emit.dasc" //|5: dasm_put(Dst, 4685); #line 3293 "src/jit/x64/emit.dasc" for (i = 0; i < runcode->callsite->flag_count; i++) { //|.word (MVMuint16)runcode->map[i].reg.orig; dasm_put(Dst, 2563, (MVMuint16)runcode->map[i].reg.orig); #line 3295 "src/jit/x64/emit.dasc" } //|.code dasm_put(Dst, 0); #line 3297 "src/jit/x64/emit.dasc" /* The return address for the interpreter */ //| get_cur_op TMP2; //| mov TMP5, TC->cur_frame; //| mov aword FRAME:TMP5->return_address, TMP2; dasm_put(Dst, 4688, Dt27(->interp_cur_op), Dt27(->cur_frame), Dt2(->return_address)); #line 3302 "src/jit/x64/emit.dasc" /* Setup the frame for returning to our current position */ if (sizeof(MVMReturnType) == 1) { //| mov byte FRAME:TMP5->return_type, runcode->return_type; dasm_put(Dst, 4704, Dt2(->return_type), runcode->return_type); #line 3306 "src/jit/x64/emit.dasc" } else { MVM_panic(1, "JIT: MVMReturnType has unexpected size"); } /* The register for our return value */ if (runcode->return_type == MVM_RETURN_VOID) { //| mov aword FRAME:TMP5->return_value, NULL; dasm_put(Dst, 4710, Dt2(->return_value), NULL); #line 3313 "src/jit/x64/emit.dasc" } else { //| lea TMP2, WORK[runcode->return_register]; //| mov aword FRAME:TMP5->return_value, TMP2; dasm_put(Dst, 4716, Dt28([runcode->return_register]), Dt2(->return_value)); #line 3316 "src/jit/x64/emit.dasc" } //| mov ARG1, TC; //| mov64 TMP6, callsite; //|.if WIN32 //| mov aword [rsp+0x20], TMP6; //| mov TMP6, TC->interp_reg_base; //| mov TMP6, [TMP6]; //| mov aword [rsp+0x28], TMP6; //| lea TMP6, [<5]; //| mov aword [rsp+0x30], TMP6; //| lea ARG2, [rsp+0x20]; //|.else //| mov aword [rsp], TMP6; //| mov TMP6, TC->interp_reg_base; //| mov TMP6, [TMP6]; //| mov aword [rsp+0x08], TMP6; //| lea TMP6, [<5]; //| mov aword [rsp+0x10], TMP6; //|.endif //| mov FUNCTION, aword WORK[runcode->code_register]; //| mov FUNCTION, CFUNCTION:FUNCTION->body.func; //| call FUNCTION dasm_put(Dst, 4769, (unsigned int)(callsite), (unsigned int)((callsite)>>32), Dt27(->interp_reg_base), Dt28([runcode->code_register]), Dt26(->body.func)); #line 3339 "src/jit/x64/emit.dasc" } void MVM_jit_emit_runnativecall(MVMThreadContext *tc, MVMJitCompiler *compiler, MVMJitGraph *jg, MVMJitRunNativeCall *runcode) { MVMint16 i; /* The return address for the interpreter */ //| get_cur_op TMP2; //| mov TMP5, TC->cur_frame; //| mov aword FRAME:TMP5->return_address, TMP2; dasm_put(Dst, 4688, Dt27(->interp_cur_op), Dt27(->cur_frame), Dt2(->return_address)); #line 3348 "src/jit/x64/emit.dasc" /* Setup the frame for returning to our current position */ if (sizeof(MVMReturnType) == 1) { //| mov byte FRAME:TMP5->return_type, runcode->return_type; dasm_put(Dst, 4704, Dt2(->return_type), runcode->return_type); #line 3352 "src/jit/x64/emit.dasc" } else { MVM_panic(1, "JIT: MVMReturnType has unexpected size"); } /* The register for our return value */ if (runcode->return_type == MVM_RETURN_VOID) { //| mov aword FRAME:TMP5->return_value, NULL; dasm_put(Dst, 4710, Dt2(->return_value), NULL); #line 3359 "src/jit/x64/emit.dasc" } else { //| lea TMP2, WORK[runcode->return_register]; //| mov aword FRAME:TMP5->return_value, TMP2; dasm_put(Dst, 4716, Dt28([runcode->return_register]), Dt2(->return_value)); #line 3362 "src/jit/x64/emit.dasc" } //|.if WIN32; #line 3366 "src/jit/x64/emit.dasc" //|.else; emit_posix_callargs(tc, compiler, jg, runcode->args, runcode->num_args); //|.endif MVMuint64 entry_point = (MVMuint64)runcode->entry_point; //| mov64 FUNCTION, entry_point; //| call FUNCTION dasm_put(Dst, 4816, (unsigned int)(entry_point), (unsigned int)((entry_point)>>32)); #line 3373 "src/jit/x64/emit.dasc" if (runcode->return_type != MVM_RETURN_VOID) { if (runcode->rv_type == MVM_NATIVECALL_ARG_CHAR) { //| cbw; dasm_put(Dst, 4203); #line 3376 "src/jit/x64/emit.dasc" } if (runcode->rv_type == MVM_NATIVECALL_ARG_CHAR || runcode->rv_type == MVM_NATIVECALL_ARG_SHORT) { //| cwde; dasm_put(Dst, 4204); #line 3379 "src/jit/x64/emit.dasc" } if (runcode->rv_type == MVM_NATIVECALL_ARG_CHAR || runcode->rv_type == MVM_NATIVECALL_ARG_SHORT || runcode->rv_type == MVM_NATIVECALL_ARG_INT) { //| cdqe; dasm_put(Dst, 4206); #line 3382 "src/jit/x64/emit.dasc" } if (runcode->rv_type == MVM_NATIVECALL_ARG_UCHAR) { //| and RV, 0xFF dasm_put(Dst, 4209); #line 3385 "src/jit/x64/emit.dasc" } else if (runcode->rv_type == MVM_NATIVECALL_ARG_USHORT) { //| and RV, 0xFFFF dasm_put(Dst, 4217); #line 3388 "src/jit/x64/emit.dasc" } else if (runcode->rv_type == MVM_NATIVECALL_ARG_UINT) { //| and RV, 0xFFFFFFFF dasm_put(Dst, 4226); #line 3391 "src/jit/x64/emit.dasc" } else if (runcode->rv_type == MVM_NATIVECALL_ARG_ULONG && sizeof(long) == 4) { //| and RV, 0xFFFFFFFF dasm_put(Dst, 4226); #line 3394 "src/jit/x64/emit.dasc" } //| mov WORK[runcode->return_register], RV dasm_put(Dst, 415, Dt28([runcode->return_register])); #line 3396 "src/jit/x64/emit.dasc" } } void MVM_jit_emit_dispatch(MVMThreadContext *tc, MVMJitCompiler *compiler, MVMJitGraph *jg, MVMJitDispatch *dispatch) { MVMint16 i; MVMuint64 callsite = (MVMuint64)dispatch->callsite; /* Store the argument map in a data section so we can get a pointer to it */ //|.data dasm_put(Dst, 116); #line 3405 "src/jit/x64/emit.dasc" //|5: dasm_put(Dst, 4685); #line 3406 "src/jit/x64/emit.dasc" for (i = 0; i < dispatch->callsite->flag_count; i++) { //|.word (MVMuint16)dispatch->map[i].reg.orig; dasm_put(Dst, 2563, (MVMuint16)dispatch->map[i].reg.orig); #line 3408 "src/jit/x64/emit.dasc" } //|.code dasm_put(Dst, 0); #line 3410 "src/jit/x64/emit.dasc" /* The return address for the interpreter */ //| get_cur_op TMP2; //| mov TMP5, TC->cur_frame; //| mov aword FRAME:TMP5->return_address, TMP2; dasm_put(Dst, 4688, Dt27(->interp_cur_op), Dt27(->cur_frame), Dt2(->return_address)); #line 3415 "src/jit/x64/emit.dasc" /* Setup the frame for returning to our current position */ if (sizeof(MVMReturnType) == 1) { //| mov byte FRAME:TMP5->return_type, dispatch->return_type; dasm_put(Dst, 4704, Dt2(->return_type), dispatch->return_type); #line 3419 "src/jit/x64/emit.dasc" } else { MVM_panic(1, "JIT: MVMReturnType has unexpected size"); } /* The register for our return value */ if (dispatch->return_type == MVM_RETURN_VOID) { //| mov aword FRAME:TMP5->return_value, NULL; dasm_put(Dst, 4710, Dt2(->return_value), NULL); #line 3426 "src/jit/x64/emit.dasc" } else { //| lea TMP2, WORK[dispatch->return_register]; //| mov aword FRAME:TMP5->return_value, TMP2; dasm_put(Dst, 4716, Dt28([dispatch->return_register]), Dt2(->return_value)); #line 3429 "src/jit/x64/emit.dasc" } //| mov ARG1, TC; //| get_spesh_slot TMP6, dispatch->sf_slot; //| lea ARG2, STATICFRAME:TMP6->body.inline_cache; //| mov ARG2, MVMDISPINLINECACHE:ARG2->entries; //| lea ARG2, MVMDISPINLINECACHEENTRY:ARG2[dispatch->ice_slot]; //| mov ARG3, [ARG2] //| get_string ARG4, dispatch->id; dasm_put(Dst, 4825, Dt27(->cur_frame), Dt2(->effective_spesh_slots), Dt15([dispatch->sf_slot]), Dt7(->body.inline_cache), Dt25(->entries), Dt24([dispatch->ice_slot])); MVM_cu_ensure_string_decoded(tc, jg->sg->sf->body.cu, dispatch->id); dasm_put(Dst, 4857, Dt29(->body.strings), Dt15([dispatch->id])); #line 3438 "src/jit/x64/emit.dasc" //|.if WIN32 //| mov64 TMP5, callsite; //| mov ARG5, TMP5; //| lea TMP5, [<5]; //| mov ARG6, TMP5; //| mov qword [rsp+6*8], WORK; //| mov qword [rsp+7*8], TMP6; //| mov TMP6, -1; //| mov qword [rsp+8*8], TMP6; //|.else //| mov64 ARG5, callsite; //| lea ARG6, [<5]; //| mov qword [rsp+0*8], WORK; //| mov qword [rsp+1*8], TMP6; //| mov TMP6, -1; //| mov qword [rsp+2*8], TMP6; //|.endif dasm_put(Dst, 4866, (unsigned int)(callsite), (unsigned int)((callsite)>>32), 0*8, 1*8, 2*8); #line 3456 "src/jit/x64/emit.dasc" //| mov FUNCTION, MVMDISPINLINECACHEENTRY:ARG3->run_dispatch; //| call FUNCTION; dasm_put(Dst, 4905, Dt24(->run_dispatch)); #line 3459 "src/jit/x64/emit.dasc" } void MVM_jit_emit_istype(MVMThreadContext *tc, MVMJitCompiler *compiler, MVMJitGraph *jg, MVMJitIsType *istype) { /* Emit the call to MVM_6model_try_cache_type_check, in order to try and * resolve it via the cache. */ //| mov ARG1, TC //| mov ARG2, aword WORK[istype->obj_register]; //| mov ARG3, aword WORK[istype->type_register]; //| lea ARG4, WORK[istype->return_register]; //| callp &MVM_6model_try_cache_type_check; dasm_put(Dst, 4914, Dt28([istype->obj_register]), Dt28([istype->type_register]), Dt28([istype->return_register])); dasm_put(Dst, 118, (MVMuint32)((uintptr_t)(&MVM_6model_try_cache_type_check)), (MVMuint32)((uintptr_t)(&MVM_6model_try_cache_type_check) >> 32)); dasm_put(Dst, 260); #line 3470 "src/jit/x64/emit.dasc" /* If it worked out with the cache, we're done. */ //| test RV, RV; //| jnz =>(istype->reentry_label); dasm_put(Dst, 4265, (istype->reentry_label)); #line 3474 "src/jit/x64/emit.dasc" /* Get HLL and ensure it has an istype dispatcher. If not, nothing * more to do. */ MVMStaticFrame *sf = (MVMStaticFrame *)jg->sg->spesh_slots[istype->sf_slot]; MVMHLLConfig *hll = sf->body.cu->body.hll_config; if (hll->istype_dispatcher) { /* Otherwise, it's a dispatch. Emit argument map in the data section. */ //|.data dasm_put(Dst, 116); #line 3482 "src/jit/x64/emit.dasc" //|5: //|.word istype->obj_register; //|.word istype->type_register; //|.code dasm_put(Dst, 4932, istype->obj_register, istype->type_register); #line 3486 "src/jit/x64/emit.dasc" /* Set up return address and value location. */ //| get_cur_op TMP2; //| mov TMP5, TC->cur_frame; //| mov aword FRAME:TMP5->return_address, TMP2; //| mov byte FRAME:TMP5->return_type, MVM_RETURN_INT; //| lea TMP2, WORK[istype->return_register]; //| mov aword FRAME:TMP5->return_value, TMP2; dasm_put(Dst, 4938, Dt27(->interp_cur_op), Dt27(->cur_frame), Dt2(->return_address), Dt2(->return_type), MVM_RETURN_INT, Dt28([istype->return_register]), Dt2(->return_value)); #line 3494 "src/jit/x64/emit.dasc" /* Perform the dispatch. */ //| mov ARG1, TC; //| get_spesh_slot TMP6, istype->sf_slot; //| lea ARG2, STATICFRAME:TMP6->body.inline_cache; //| mov ARG2, MVMDISPINLINECACHE:ARG2->entries; //| lea ARG2, MVMDISPINLINECACHEENTRY:ARG2[istype->ice_slot]; //| mov ARG3, [ARG2] dasm_put(Dst, 4825, Dt27(->cur_frame), Dt2(->effective_spesh_slots), Dt15([istype->sf_slot]), Dt7(->body.inline_cache), Dt25(->entries), Dt24([istype->ice_slot])); #line 3502 "src/jit/x64/emit.dasc" MVMString **id_addr = &(hll->istype_dispatcher); //| mov64 ARG4, (uintptr_t)id_addr; //| mov ARG4, [ARG4] dasm_put(Dst, 4967, (unsigned int)((uintptr_t)id_addr), (unsigned int)(((uintptr_t)id_addr)>>32)); #line 3505 "src/jit/x64/emit.dasc" MVMCallsite *callsite = MVM_callsite_get_common(tc, MVM_CALLSITE_ID_OBJ_OBJ); //|.if WIN32 //| mov64 TMP5, (uintptr_t)callsite; //| mov ARG5, TMP5; //| lea TMP5, [<5]; //| mov ARG6, TMP5; //| mov qword [rsp+6*8], WORK; //| mov qword [rsp+7*8], TMP6; //| mov TMP6, -1; //| mov qword [rsp+8*8], TMP6; //|.else //| mov64 ARG5, (uintptr_t)callsite; //| lea ARG6, [<5]; //| mov qword [rsp+0*8], WORK; //| mov qword [rsp+1*8], TMP6; //| mov TMP6, -1; //| mov qword [rsp+2*8], TMP6; //|.endif dasm_put(Dst, 4866, (unsigned int)((uintptr_t)callsite), (unsigned int)(((uintptr_t)callsite)>>32), 0*8, 1*8, 2*8); #line 3524 "src/jit/x64/emit.dasc" //| mov FUNCTION, MVMDISPINLINECACHEENTRY:ARG3->run_dispatch; //| call FUNCTION; dasm_put(Dst, 4905, Dt24(->run_dispatch)); #line 3527 "src/jit/x64/emit.dasc" } } void MVM_jit_emit_jumplist(MVMThreadContext *tc, MVMJitCompiler *compiler, MVMJitGraph *jg, MVMJitJumpList *jumplist) { MVMint32 i; //| mov TMP1, WORK[jumplist->reg]; //| cmp TMP1, 0; //| jl >2; //| cmp TMP1, jumplist->num_labels; //| jge >2; //| imul TMP1, 0x8; // 8 bytes per goto //| lea TMP2, [>1]; //| add TMP2, TMP1; //| jmp TMP2; //|.align 8; //|1: dasm_put(Dst, 4975, Dt28([jumplist->reg]), jumplist->num_labels); #line 3544 "src/jit/x64/emit.dasc" for (i = 0; i < jumplist->num_labels; i++) { //|=>(jumplist->in_labels[i]): //| jmp =>(jumplist->out_labels[i]); //|.align 8; dasm_put(Dst, 5017, (jumplist->in_labels[i]), (jumplist->out_labels[i])); #line 3548 "src/jit/x64/emit.dasc" } //|2: dasm_put(Dst, 345); #line 3550 "src/jit/x64/emit.dasc" } void MVM_jit_emit_control(MVMThreadContext *tc, MVMJitCompiler *compiler, MVMJitControl *ctrl, MVMJitTile *tile) { MVMJitControlType type = (tile != NULL ? (MVMJitControlType)tile->args[0] : ctrl->type); if (type == MVM_JIT_CONTROL_BREAKPOINT) { /* Debug breakpoint */ //| int 3; dasm_put(Dst, 5024); #line 3558 "src/jit/x64/emit.dasc" } else { MVM_panic(1, "Unknown control code: <%s>", ctrl->ins->info->name); } } /* Convenience macros for testing the register class of a register id */ #define IS_GPR(x) ((x) >= MVM_JIT_REG(RAX) && (x) <= MVM_JIT_REG(R15)) #define IS_FPR(x) ((x) >= MVM_JIT_REG(XMM0) && (x) <= MVM_JIT_REG(XMM15)) #define REG_NUM(x) ((x) & 0xf) void MVM_jit_emit_load(MVMThreadContext *tc, MVMJitCompiler *compiler, MVMint8 reg_dst, MVMJitStorageClass mem_cls, MVMint32 mem_src, MVMint32 size) { MVMint8 mem_base; if (mem_cls == MVM_JIT_STORAGE_LOCAL) { mem_base = MVM_JIT_REG(RBX); } else if (mem_cls == MVM_JIT_STORAGE_STACK) { mem_base = MVM_JIT_REG(RSP); } else { abort(); } if (IS_GPR(reg_dst)) { switch(size) { case 1: //| mov Rb(reg_dst), byte [Rq(mem_base)+mem_src]; dasm_put(Dst, 5027, (reg_dst), (mem_base), mem_src); #line 3583 "src/jit/x64/emit.dasc" return; case 2: //| mov Rw(reg_dst), word [Rq(mem_base)+mem_src]; dasm_put(Dst, 5038, (reg_dst), (mem_base), mem_src); #line 3586 "src/jit/x64/emit.dasc" return; case 4: //| mov Rd(reg_dst), dword [Rq(mem_base)+mem_src]; dasm_put(Dst, 5039, (reg_dst), (mem_base), mem_src); #line 3589 "src/jit/x64/emit.dasc" return; case 8: //| mov Rq(reg_dst), qword [Rq(mem_base)+mem_src]; dasm_put(Dst, 5049, (reg_dst), (mem_base), mem_src); #line 3592 "src/jit/x64/emit.dasc" return; } } else if (IS_FPR(reg_dst)) { MVMint8 reg_num = REG_NUM(reg_dst); switch(size) { case 8: //| movsd xmm(reg_num), qword [Rq(mem_base)+mem_src]; dasm_put(Dst, 5060, (reg_num), (mem_base), mem_src); #line 3599 "src/jit/x64/emit.dasc" return; } } abort(); } void MVM_jit_emit_store(MVMThreadContext *tc, MVMJitCompiler *compiler, MVMJitStorageClass mem_cls, MVMint32 mem_dst, MVMint8 reg_src, MVMint32 size) { MVMint8 mem_base; if (mem_cls == MVM_JIT_STORAGE_LOCAL) { mem_base = MVM_JIT_REG(RBX); } else if (mem_cls == MVM_JIT_STORAGE_STACK) { mem_base = MVM_JIT_REG(RSP); } else { abort(); } if (IS_GPR(reg_src)) { switch (size) { case 1: //| mov byte [Rq(mem_base)+mem_dst], Rb(reg_src); dasm_put(Dst, 5073, (reg_src), (mem_base), mem_dst); #line 3621 "src/jit/x64/emit.dasc" return; case 2: //| mov word [Rq(mem_base)+mem_dst], Rw(reg_src); dasm_put(Dst, 5084, (reg_src), (mem_base), mem_dst); #line 3624 "src/jit/x64/emit.dasc" return; case 4: //| mov dword [Rq(mem_base)+mem_dst], Rd(reg_src); dasm_put(Dst, 5085, (reg_src), (mem_base), mem_dst); #line 3627 "src/jit/x64/emit.dasc" return; case 8: //| mov qword [Rq(mem_base)+mem_dst], Rq(reg_src); dasm_put(Dst, 5095, (reg_src), (mem_base), mem_dst); #line 3630 "src/jit/x64/emit.dasc" return; } } else if (IS_FPR(reg_src)) { reg_src = reg_src & 0xf; switch (size) { case 8: //| movsd qword [Rq(mem_base)+mem_dst], xmm(reg_src); dasm_put(Dst, 5106, (reg_src), (mem_base), mem_dst); #line 3637 "src/jit/x64/emit.dasc" return; } } abort(); } void MVM_jit_emit_copy(MVMThreadContext *tc, MVMJitCompiler *compiler, MVMint8 dst_reg, MVMint8 src_reg) { if (IS_GPR(dst_reg)) { if (IS_GPR(src_reg)) { //| mov Rq(dst_reg), Rq(src_reg); dasm_put(Dst, 5119, (src_reg), (dst_reg)); #line 3649 "src/jit/x64/emit.dasc" } else { // src_cls == MVM_JIT_STORAGE_FPR //| movd Rq(dst_reg), xmm(REG_NUM(src_reg)); dasm_put(Dst, 5128, (REG_NUM(src_reg)), (dst_reg)); #line 3651 "src/jit/x64/emit.dasc" } } else if (IS_FPR(src_reg)) { // dst_cls == MVM_JIT_STORAGE_FPR //| movq xmm(REG_NUM(dst_reg)), xmm(REG_NUM(src_reg)); dasm_put(Dst, 5139, (REG_NUM(dst_reg)), (REG_NUM(src_reg))); #line 3654 "src/jit/x64/emit.dasc" } else { // src_cls == MVM_JIT_STORAGE_GPR //| movd xmm(REG_NUM(dst_reg)), Rq(src_reg); dasm_put(Dst, 5150, (REG_NUM(dst_reg)), (src_reg)); #line 3656 "src/jit/x64/emit.dasc" } } void MVM_jit_emit_marker(MVMThreadContext *tc, MVMJitCompiler *compiler, MVMint32 num) { MVMint32 i; for (i = 0; i < num; i++) { //| nop; dasm_put(Dst, 5161); #line 3664 "src/jit/x64/emit.dasc" } } void MVM_jit_emit_data(MVMThreadContext *tc, MVMJitCompiler *compiler, MVMJitData *data) { MVMuint8 *bytes = data->data; size_t i; //|.data; dasm_put(Dst, 116); #line 3672 "src/jit/x64/emit.dasc" //|=>(data->label): dasm_put(Dst, 245, (data->label)); #line 3673 "src/jit/x64/emit.dasc" for (i = 0; i < data->size; i++) { //|.byte bytes[i]; dasm_put(Dst, 4708, bytes[i]); #line 3675 "src/jit/x64/emit.dasc" } //|.code dasm_put(Dst, 0); #line 3677 "src/jit/x64/emit.dasc" } void MVM_jit_emit_deopt_check(MVMThreadContext *tc, MVMJitCompiler *compiler) { //| mov TMP6, TC->cur_frame; //| mov TMP6, FRAME:TMP6->spesh_cand //| test TMP6, TMP6 //| jnz >1 //| jmp ->exit //|1: dasm_put(Dst, 5163, Dt27(->cur_frame), Dt2(->spesh_cand)); #line 3686 "src/jit/x64/emit.dasc" } /* import tiles */ //|.include src/jit/x64/tiles.dasc #line 1 "src/jit/x64/tiles.dasc" /* -*-C-*- */ #ifndef _MSC_VER #pragma GCC diagnostic ignored "-Wunused-variable" #endif #define DIE(...) do { MVM_oops(tc, __VA_ARGS__); } while (0) /* NB: The rax/eax/ax/al/ah register is *reserved* for internal use in tiles by * the register allocator. Using rax will never overwrite an allocated value */ /* basic memory traffic tiles */ MVM_JIT_TILE_DECL(addr) { MVMint8 out = tile->values[0]; MVMint8 base = tile->values[1]; MVMint32 ofs = tile->args[0]; //| lea Rq(out), [Rq(base)+ofs]; dasm_put(Dst, 5185, (out), (base), ofs); #line 16 "src/jit/x64/tiles.dasc" } MVM_JIT_TILE_DECL(idx) { MVMint8 out = tile->values[0]; MVMint8 base = tile->values[1]; MVMint8 idx = tile->values[2]; MVMint8 scl = tile->args[0]; switch(scl) { case 2: //| lea Rq(out), [Rq(base)+Rq(idx)*2]; dasm_put(Dst, 5196, (out), (idx), (base), 0); #line 27 "src/jit/x64/tiles.dasc" break; case 8: //| lea Rq(out), [Rq(base)+Rq(idx)*8]; dasm_put(Dst, 5210, (out), (idx), (base), 0); #line 30 "src/jit/x64/tiles.dasc" break; default: DIE("Unsupported scale: %d", scl); } } MVM_JIT_TILE_DECL(const_reg) { MVMint8 out = tile->values[0]; MVMint32 val = tile->args[0]; MVMint32 size = tile->args[1]; //| mov Rq(out), val; dasm_put(Dst, 5224, (out), val); #line 42 "src/jit/x64/tiles.dasc" } MVM_JIT_TILE_DECL(const_large) { MVMint8 out = tile->values[0]; MVMint64 val = tree->constants[tile->args[0]].i; //| mov64 Rq(out), val; dasm_put(Dst, 5232, (out), (unsigned int)(val), (unsigned int)((val)>>32)); #line 48 "src/jit/x64/tiles.dasc" } MVM_JIT_TILE_DECL(const_num) { MVMuint8 out = tile->values[0] - MVM_JIT_REG(XMM0); MVMnum64 val = tree->constants[tile->args[0]].n; unsigned char bytes[sizeof(val)]; size_t i; memcpy(bytes, &val, sizeof(val)); //|.data; dasm_put(Dst, 116); #line 57 "src/jit/x64/tiles.dasc" //|5: dasm_put(Dst, 4685); #line 58 "src/jit/x64/tiles.dasc" for (i = 0; i < sizeof(bytes); i++) { //|.byte bytes[i]; dasm_put(Dst, 4708, bytes[i]); #line 60 "src/jit/x64/tiles.dasc" } //|.code; dasm_put(Dst, 0); #line 62 "src/jit/x64/tiles.dasc" //| movsd xmm(out), qword [<5]; dasm_put(Dst, 5240, (out)); #line 63 "src/jit/x64/tiles.dasc" } MVM_JIT_TILE_DECL(load_reg) { MVMint8 out = tile->values[0]; MVMint8 base = tile->values[1]; MVMint32 size = tile->args[0]; switch (size) { case 1: //| mov Rb(out), [Rq(base)]; dasm_put(Dst, 5251, (out), (base), 0); #line 72 "src/jit/x64/tiles.dasc" break; case 2: //| mov Rw(out), [Rq(base)]; dasm_put(Dst, 5038, (out), (base), 0); #line 75 "src/jit/x64/tiles.dasc" break; case 4: //| mov Rd(out), [Rq(base)]; dasm_put(Dst, 5039, (out), (base), 0); #line 78 "src/jit/x64/tiles.dasc" break; case 8: //| mov Rq(out), [Rq(base)]; dasm_put(Dst, 5049, (out), (base), 0); #line 81 "src/jit/x64/tiles.dasc" break; default: DIE("Unsupported load size: %d\n", size); } } MVM_JIT_TILE_DECL(load_addr) { MVMint8 out = tile->values[0]; MVMint8 base = tile->values[1]; MVMint32 ofs = tile->args[0]; MVMint32 size = tile->args[1]; switch (tile->args[1]) { case 1: //| mov Rb(out), byte [Rq(base)+ofs]; dasm_put(Dst, 5027, (out), (base), ofs); #line 95 "src/jit/x64/tiles.dasc" break; case 2: //| mov Rw(out), word [Rq(base)+ofs]; dasm_put(Dst, 5038, (out), (base), ofs); #line 98 "src/jit/x64/tiles.dasc" break; case 4: //| mov Rd(out), dword [Rq(base)+ofs]; dasm_put(Dst, 5039, (out), (base), ofs); #line 101 "src/jit/x64/tiles.dasc" break; case 8: //| mov Rq(out), qword [Rq(base)+ofs]; dasm_put(Dst, 5049, (out), (base), ofs); #line 104 "src/jit/x64/tiles.dasc" break; default: DIE("Unsupported load size: %d\n", size); } } MVM_JIT_TILE_DECL(load_idx) { MVMint8 out = tile->values[0]; MVMint8 base = tile->values[1]; MVMint8 idx = tile->values[2]; MVMint8 scl = tile->args[0]; MVMint32 size = tile->args[1]; if (scl != 8 && size != 2) { DIE("Unsupported scale size: %d\n", scl); } switch (size) { case 1: //| mov Rb(out), byte [Rq(base)+Rq(idx)*8]; dasm_put(Dst, 5261, (out), (idx), (base), 0); #line 122 "src/jit/x64/tiles.dasc" break; case 2: switch(scl) { case 2: //| mov Rw(out), word [Rq(base)+Rq(idx)*2]; dasm_put(Dst, 5275, (out), (idx), (base), 0); #line 127 "src/jit/x64/tiles.dasc" break; case 8: //| mov Rw(out), word [Rq(base)+Rq(idx)*8]; dasm_put(Dst, 5289, (out), (idx), (base), 0); #line 130 "src/jit/x64/tiles.dasc" break; } break; case 4: //| mov Rd(out), dword [Rq(base)+Rq(idx)*8]; dasm_put(Dst, 5290, (out), (idx), (base), 0); #line 135 "src/jit/x64/tiles.dasc" break; case 8: //| mov Rq(out), qword [Rq(base)+Rq(idx)*8]; dasm_put(Dst, 5303, (out), (idx), (base), 0); #line 138 "src/jit/x64/tiles.dasc" break; default: DIE("Unsupported load size: %d\n", size); } } MVM_JIT_TILE_DECL(load_num) { MVMint8 out = REG_NUM(tile->values[0]); MVMint8 addr = tile->values[1]; //| movsd xmm(out), qword [Rq(addr)]; dasm_put(Dst, 5060, (out), (addr), 0); #line 148 "src/jit/x64/tiles.dasc" } MVM_JIT_TILE_DECL(load_num_addr) { MVMint8 out = REG_NUM(tile->values[0]); MVMint8 addr = tile->values[1]; MVMint32 ofs = tile->args[0]; //| movsd xmm(out), qword [Rq(addr)+ofs]; dasm_put(Dst, 5060, (out), (addr), ofs); #line 155 "src/jit/x64/tiles.dasc" } MVM_JIT_TILE_DECL(store) { MVMint8 base = tile->values[1]; MVMint8 value = tile->values[2]; MVMint32 size = tile->args[0]; switch (size) { case 1: //| mov byte [Rq(base)], Rb(value); dasm_put(Dst, 5073, (value), (base), 0); #line 165 "src/jit/x64/tiles.dasc" break; case 2: //| mov word [Rq(base)], Rw(value); dasm_put(Dst, 5084, (value), (base), 0); #line 168 "src/jit/x64/tiles.dasc" break; case 4: //| mov dword [Rq(base)], Rd(value); dasm_put(Dst, 5085, (value), (base), 0); #line 171 "src/jit/x64/tiles.dasc" break; case 8: //| mov qword [Rq(base)], Rq(value); dasm_put(Dst, 5095, (value), (base), 0); #line 174 "src/jit/x64/tiles.dasc" break; default: DIE("Unsupported store size: %d\n", size); } } MVM_JIT_TILE_DECL(store_addr) { MVMint8 base = tile->values[1]; MVMint8 value = tile->values[2]; MVMint32 ofs = tile->args[0]; MVMint32 size = tile->args[1]; switch (size) { case 1: //| mov byte [Rq(base)+ofs], Rb(value); dasm_put(Dst, 5073, (value), (base), ofs); #line 188 "src/jit/x64/tiles.dasc" break; case 2: //| mov word [Rq(base)+ofs], Rw(value); dasm_put(Dst, 5084, (value), (base), ofs); #line 191 "src/jit/x64/tiles.dasc" break; case 4: //| mov dword [Rq(base)+ofs], Rd(value); dasm_put(Dst, 5085, (value), (base), ofs); #line 194 "src/jit/x64/tiles.dasc" break; case 8: //| mov qword [Rq(base)+ofs], Rq(value); dasm_put(Dst, 5095, (value), (base), ofs); #line 197 "src/jit/x64/tiles.dasc" break; default: DIE("Unsupported store size: %d\n", size); } } MVM_JIT_TILE_DECL(store_idx) { MVMint8 base = tile->values[1]; MVMint8 idx = tile->values[2]; MVMint8 scl = tile->args[0]; MVMint32 size = tile->args[1]; MVMint8 value = tile->values[3]; if (scl != 8) DIE("Scale %d NYI\n", scl); switch (size) { case 1: //| mov byte [Rq(base)+Rq(idx)*8], Rb(value); dasm_put(Dst, 5317, (value), (idx), (base), 0); #line 214 "src/jit/x64/tiles.dasc" break; case 2: //| mov word [Rq(base)+Rq(idx)*8], Rw(value); dasm_put(Dst, 5331, (value), (idx), (base), 0); #line 217 "src/jit/x64/tiles.dasc" break; case 4: //| mov dword [Rq(base)+Rq(idx)*8], Rd(value); dasm_put(Dst, 5332, (value), (idx), (base), 0); #line 220 "src/jit/x64/tiles.dasc" break; case 8: //| mov qword [Rq(base)+Rq(idx)*8], Rq(value); dasm_put(Dst, 5345, (value), (idx), (base), 0); #line 223 "src/jit/x64/tiles.dasc" break; default: DIE("Unsupported store size: %d\n", size); } } MVM_JIT_TILE_DECL(store_num) { MVMint8 addr = tile->values[1]; MVMint8 val = tile->values[2] - MVM_JIT_REG(XMM0); //| movsd qword [Rq(addr)], xmm(val); dasm_put(Dst, 5106, (val), (addr), 0); #line 233 "src/jit/x64/tiles.dasc" } MVM_JIT_TILE_DECL(store_num_addr) { MVMint8 addr = tile->values[1]; MVMint8 value = REG_NUM(tile->values[2]); MVMint32 ofs = tile->args[0]; //| movsd qword [Rq(addr)+ofs], xmm(value); dasm_put(Dst, 5106, (value), (addr), ofs); #line 240 "src/jit/x64/tiles.dasc" } MVM_JIT_TILE_DECL(cast_signed) { MVMint32 to_size = tile->args[0]; MVMint32 from_size = tile->args[1]; MVMint8 to_reg = tile->values[0]; MVMint8 from_reg = tile->values[1]; /* possible combinations: 1 -> 2, 4, 8; 2 -> 4, 8; 4 -> 8 * Hence we can combine from_size | (to_size << 3) to get * the following options: * 1 + 2<<3 == 17 * 1 + 4<<3 == 33 * 1 + 8<<3 == 65 * 2 + 4<<3 == 34 * 2 + 8<<3 == 66 * 4 + 8<<3 == 68 */ MVMint32 size_conv = (from_size) | (to_size << 3); switch (size_conv) { case 17: //| movsx Rw(to_reg), Rb(from_reg); dasm_put(Dst, 5359, (to_reg), (from_reg)); #line 264 "src/jit/x64/tiles.dasc" break; case 33: //| movsx Rd(to_reg), Rb(from_reg); dasm_put(Dst, 5360, (to_reg), (from_reg)); #line 267 "src/jit/x64/tiles.dasc" break; case 34: //| movsx Rd(to_reg), Rw(from_reg); dasm_put(Dst, 5370, (to_reg), (from_reg)); #line 270 "src/jit/x64/tiles.dasc" break; case 65: //| movsx Rq(to_reg), Rb(from_reg); dasm_put(Dst, 5379, (to_reg), (from_reg)); #line 273 "src/jit/x64/tiles.dasc" break; case 66: //| movsx Rq(to_reg), Rw(from_reg); dasm_put(Dst, 5389, (to_reg), (from_reg)); #line 276 "src/jit/x64/tiles.dasc" break; case 68: /* movsx is apparantly not defined for double-to-quadword conversions, * which forces us to use the rax register like it's 1978. It might be easier * to bithack the sign-extension manually, but I'm not sure how.. */ //| mov eax, Rd(from_reg); //| cdqe; //| mov Rq(to_reg), rax; dasm_put(Dst, 5399, (from_reg), (to_reg)); #line 284 "src/jit/x64/tiles.dasc" break; default: DIE("Unsupported signed cast %d -> %d\n", from_size, to_size); } } MVM_JIT_TILE_DECL(cast_unsigned) { MVMint32 to_size = tile->args[0]; MVMint32 from_size = tile->args[1]; MVMint8 to_reg = tile->values[0]; MVMint8 from_reg = tile->values[1]; /* Same combination set as above, but we also support casting down: * 8 -> 1 = 8 (1<<3 = 8, 8 | 8 = 8) * 4 -> 1 = 12 * 2 -> 1 = 10 * 8 -> 2 = 24 * 4 -> 2 = 20 * 8 -> 4 = 40 */ MVMint32 size_conv = (from_size) | (to_size << 3); switch (size_conv) { case 8: /* 8 -> 1 */ case 10: /* 2 -> 1 */ case 12: /* 4 -> 1 */ //| movzx Rd(to_reg), Rb(from_reg); dasm_put(Dst, 5413, (to_reg), (from_reg)); #line 311 "src/jit/x64/tiles.dasc" break; case 17: /* 1 -> 2 */ //| movzx Rw(to_reg), Rb(from_reg); dasm_put(Dst, 5423, (to_reg), (from_reg)); #line 314 "src/jit/x64/tiles.dasc" break; case 20: /* 4 -> 2 */ case 24: /* 8 -> 2 */ //| movzx Rd(to_reg), Rw(to_reg); dasm_put(Dst, 5434, (to_reg), (to_reg)); #line 318 "src/jit/x64/tiles.dasc" break; case 33: /* 1 -> 4 */ //| movzx Rd(to_reg), Rb(from_reg); dasm_put(Dst, 5413, (to_reg), (from_reg)); #line 321 "src/jit/x64/tiles.dasc" break; case 34: /* 2 -> 4 */ //| movzx Rd(to_reg), Rw(from_reg); dasm_put(Dst, 5434, (to_reg), (from_reg)); #line 324 "src/jit/x64/tiles.dasc" break; case 40: /* 8 -> 4 */ //| mov Rd(to_reg), Rd(from_reg); dasm_put(Dst, 5443, (from_reg), (to_reg)); #line 327 "src/jit/x64/tiles.dasc" break; case 65: /* 1 -> 8 */ //| movzx Rq(to_reg), Rb(from_reg); dasm_put(Dst, 5451, (to_reg), (from_reg)); #line 330 "src/jit/x64/tiles.dasc" break; case 66: /* 2 -> 8 */ //| movzx Rq(to_reg), Rw(from_reg); dasm_put(Dst, 5461, (to_reg), (from_reg)); #line 333 "src/jit/x64/tiles.dasc" break; case 68: /* 4 -> 8 */ /* In contrast to signed cast, nothing special is necessary to cast * unsigned doublewords to quadwords, because using the lower 4 bytes * automatically clears the upper 4 */ //| mov Rd(to_reg), Rd(from_reg); dasm_put(Dst, 5443, (from_reg), (to_reg)); #line 339 "src/jit/x64/tiles.dasc" break; default: DIE("Unsupported unsigned cast %d -> %d (%d)\n", from_size, to_size, size_conv); } } /* Logic is the same as cast above except loading from memory instead of reg */ /* See comments in cast above for more detail */ MVM_JIT_TILE_DECL(cast_signed_load_addr) { MVMint32 ofs = tile->args[0]; MVMint32 load_size = tile->args[1]; MVMint32 to_size = tile->args[2]; MVMint32 from_size = tile->args[3]; MVMint8 to_reg = tile->values[0]; MVMint8 base = tile->values[1]; MVMint32 size_conv = (from_size) | (to_size << 3); switch (size_conv) { case 17: //| movsx Rw(to_reg), byte [Rq(base)+ofs]; dasm_put(Dst, 5471, (to_reg), (base), ofs); #line 362 "src/jit/x64/tiles.dasc" break; case 33: //| movsx Rd(to_reg), byte [Rq(base)+ofs]; dasm_put(Dst, 5472, (to_reg), (base), ofs); #line 365 "src/jit/x64/tiles.dasc" break; case 34: //| movsx Rd(to_reg), word [Rq(base)+ofs]; dasm_put(Dst, 5484, (to_reg), (base), ofs); #line 368 "src/jit/x64/tiles.dasc" break; case 65: //| movsx Rq(to_reg), byte [Rq(base)+ofs]; dasm_put(Dst, 5495, (to_reg), (base), ofs); #line 371 "src/jit/x64/tiles.dasc" break; case 66: //| movsx Rq(to_reg), word [Rq(base)+ofs]; dasm_put(Dst, 5507, (to_reg), (base), ofs); #line 374 "src/jit/x64/tiles.dasc" break; case 68: //| mov eax, dword [Rq(base)+ofs]; //| cdqe; //| mov Rq(to_reg), rax; dasm_put(Dst, 5519, (base), ofs, (to_reg)); #line 379 "src/jit/x64/tiles.dasc" break; default: DIE("Unsupported signed cast with load %d -> %d\n", from_size, to_size); } } /* Logic is the same as cast above except loading from memory instead of reg */ /* See comments in cast above for more detail */ MVM_JIT_TILE_DECL(cast_unsigned_load_addr) { MVMint32 ofs = tile->args[0]; MVMint32 load_size = tile->args[1]; MVMint32 to_size = tile->args[2]; MVMint32 from_size = tile->args[3]; MVMint8 to_reg = tile->values[0]; MVMint8 base = tile->values[1]; MVMint32 size_conv = (from_size) | (to_size << 3); switch (size_conv) { case 8: /* 8 -> 1 */ case 10: /* 2 -> 1 */ case 12: /* 4 -> 1 */ //| movzx Rd(to_reg), byte [Rq(base)+ofs]; dasm_put(Dst, 5535, (to_reg), (base), ofs); #line 402 "src/jit/x64/tiles.dasc" break; case 17: /* 1 -> 2 */ //| movzx Rw(to_reg), byte [Rq(base)+ofs]; dasm_put(Dst, 5547, (to_reg), (base), ofs); #line 405 "src/jit/x64/tiles.dasc" break; case 20: /* 4 -> 2 */ case 24: /* 8 -> 2 */ //| movzx Rd(to_reg), word [Rq(base)+ofs]; dasm_put(Dst, 5560, (to_reg), (base), ofs); #line 409 "src/jit/x64/tiles.dasc" break; case 33: /* 1 -> 4 */ //| movzx Rd(to_reg), byte [Rq(base)+ofs]; dasm_put(Dst, 5535, (to_reg), (base), ofs); #line 412 "src/jit/x64/tiles.dasc" break; case 34: /* 2 -> 4 */ //| movzx Rd(to_reg), word [Rq(base)+ofs]; dasm_put(Dst, 5560, (to_reg), (base), ofs); #line 415 "src/jit/x64/tiles.dasc" break; case 40: /* 8 -> 4 */ //| mov Rd(to_reg), dword [Rq(base)+ofs]; dasm_put(Dst, 5039, (to_reg), (base), ofs); #line 418 "src/jit/x64/tiles.dasc" break; case 65: /* 1 -> 8 */ //| movzx Rq(to_reg), byte [Rq(base)+ofs]; dasm_put(Dst, 5571, (to_reg), (base), ofs); #line 421 "src/jit/x64/tiles.dasc" break; case 66: /* 2 -> 8 */ //| movzx Rq(to_reg), word [Rq(base)+ofs]; dasm_put(Dst, 5583, (to_reg), (base), ofs); #line 424 "src/jit/x64/tiles.dasc" break; case 68: /* 4 -> 8 */ //| mov Rd(to_reg), dword [Rq(base)+ofs]; dasm_put(Dst, 5039, (to_reg), (base), ofs); #line 427 "src/jit/x64/tiles.dasc" break; default: DIE("Unsupported unsigned cast with load %d -> %d (size_conv=%d)\n", from_size, to_size, size_conv); } } /* binary operations have special requirements because x86 is two-operand form, e.g: * r0 = r0 r1 * whereas the JIT uses a three-operand model: * r0 = r1 r2 */ static void ensure_two_operand_pre(MVMThreadContext *tc, MVMJitCompiler *compiler, MVMJitTile *tile, MVMint8 reg[2]) { MVMint8 out = tile->values[0], in1 = tile->values[1], in2 = tile->values[2]; assert(out == in1); reg[0] = REG_NUM(out); reg[1] = REG_NUM(in2); } static void ensure_two_operand_post(MVMThreadContext *tc, MVMJitCompiler *compiler, MVMJitTile *tile, MVMint8 reg[2]) { } MVM_JIT_TILE_DECL(add_reg) { MVMint8 reg[2]; ensure_two_operand_pre(tc, compiler, tile, reg); //| add Rq(reg[0]), Rq(reg[1]); dasm_put(Dst, 5595, (reg[1]), (reg[0])); #line 454 "src/jit/x64/tiles.dasc" ensure_two_operand_post(tc, compiler, tile, reg); } MVM_JIT_TILE_DECL(add_const) { MVMint8 out = tile->values[0]; MVMint8 in1 = tile->values[1]; MVMint32 val = tile->args[0]; MVMint32 sz = tile->args[1]; if (out != in1) { //| mov Rq(out), Rq(in1); dasm_put(Dst, 5119, (in1), (out)); #line 464 "src/jit/x64/tiles.dasc" } //| add Rq(out), val; dasm_put(Dst, 5604, (out), val); #line 466 "src/jit/x64/tiles.dasc" } MVM_JIT_TILE_DECL(add_load_addr) { MVMint8 out = tile->values[0]; MVMint8 in1 = tile->values[1]; MVMint8 base = tile->values[2]; MVMint32 ofs = tile->args[0]; MVMint32 size = tile->args[1]; assert(out == in1); switch (size) { case 1: //| add Rb(out), byte [Rq(base)+ofs]; dasm_put(Dst, 5612, (out), (base), ofs); #line 478 "src/jit/x64/tiles.dasc" break; case 2: //| add Rw(out), word [Rq(base)+ofs]; dasm_put(Dst, 5623, (out), (base), ofs); #line 481 "src/jit/x64/tiles.dasc" break; case 4: //| add Rd(out), dword [Rq(base)+ofs]; dasm_put(Dst, 5624, (out), (base), ofs); #line 484 "src/jit/x64/tiles.dasc" break; case 8: //| add Rq(out), qword [Rq(base)+ofs]; dasm_put(Dst, 5634, (out), (base), ofs); #line 487 "src/jit/x64/tiles.dasc" break; default: DIE("Unsupported load size: %d\n", size); } } MVM_JIT_TILE_DECL(add_load_idx) { MVMint8 out = tile->values[0]; MVMint8 in1 = tile->values[1]; MVMint8 base = tile->values[2]; MVMint8 idx = tile->values[3]; MVMint32 scl = tile->args[0]; MVMint32 size = tile->args[1]; assert(out == in1); if (scl != 8) DIE("IDX Scale %d NYI\n", scl); switch (size) { case 1: //| add Rb(out), byte [Rq(base)+Rq(idx)*8]; dasm_put(Dst, 5645, (out), (idx), (base), 0); #line 506 "src/jit/x64/tiles.dasc" break; case 2: //| add Rw(out), word [Rq(base)+Rq(idx)*8]; dasm_put(Dst, 5659, (out), (idx), (base), 0); #line 509 "src/jit/x64/tiles.dasc" break; case 4: //| add Rd(out), dword [Rq(base)+Rq(idx)*8]; dasm_put(Dst, 5660, (out), (idx), (base), 0); #line 512 "src/jit/x64/tiles.dasc" break; case 8: //| add Rq(out), qword [Rq(base)+Rq(idx)*8]; dasm_put(Dst, 5673, (out), (idx), (base), 0); #line 515 "src/jit/x64/tiles.dasc" break; default: DIE("Unsupported load size: %d\n", size); } } MVM_JIT_TILE_DECL(add_num) { MVMint8 reg[2]; ensure_two_operand_pre(tc, compiler, tile, reg); //| addsd xmm(reg[0]), xmm(reg[1]); dasm_put(Dst, 5687, (reg[0]), (reg[1])); #line 525 "src/jit/x64/tiles.dasc" ensure_two_operand_post(tc, compiler, tile, reg); } MVM_JIT_TILE_DECL(sub_num) { MVMint8 reg[2]; ensure_two_operand_pre(tc, compiler, tile, reg); //| subsd xmm(reg[0]), xmm(reg[1]); dasm_put(Dst, 5698, (reg[0]), (reg[1])); #line 532 "src/jit/x64/tiles.dasc" ensure_two_operand_post(tc, compiler, tile, reg); } MVM_JIT_TILE_DECL(mul_num) { MVMint8 reg[2]; ensure_two_operand_pre(tc, compiler, tile, reg); //| mulsd xmm(reg[0]), xmm(reg[1]); dasm_put(Dst, 5709, (reg[0]), (reg[1])); #line 539 "src/jit/x64/tiles.dasc" ensure_two_operand_post(tc, compiler, tile, reg); } MVM_JIT_TILE_DECL(and_reg) { MVMint8 reg[2]; ensure_two_operand_pre(tc, compiler, tile, reg); //| and Rq(reg[0]), Rq(reg[1]); dasm_put(Dst, 5720, (reg[1]), (reg[0])); #line 548 "src/jit/x64/tiles.dasc" ensure_two_operand_post(tc, compiler, tile, reg); } MVM_JIT_TILE_DECL(and_const) { MVMint8 out = tile->values[0]; MVMint8 in1 = tile->values[1]; MVMint32 val = tile->args[0]; MVMint32 sz = tile->args[1]; assert(out == in1); //| and Rq(out), val; dasm_put(Dst, 5729, (out), val); #line 558 "src/jit/x64/tiles.dasc" } MVM_JIT_TILE_DECL(and_load_addr) { MVMint8 out = tile->values[0]; MVMint8 in1 = tile->values[1]; MVMint8 base = tile->values[2]; MVMint32 ofs = tile->args[0]; MVMint32 size = tile->args[1]; assert(out == in1); switch (size) { case 1: //| and Rb(out), byte [Rq(base)+ofs]; dasm_put(Dst, 5737, (out), (base), ofs); #line 570 "src/jit/x64/tiles.dasc" break; case 2: //| and Rw(out), word [Rq(base)+ofs]; dasm_put(Dst, 5748, (out), (base), ofs); #line 573 "src/jit/x64/tiles.dasc" break; case 4: //| and Rd(out), dword [Rq(base)+ofs]; dasm_put(Dst, 5749, (out), (base), ofs); #line 576 "src/jit/x64/tiles.dasc" break; case 8: //| and Rq(out), qword [Rq(base)+ofs]; dasm_put(Dst, 5759, (out), (base), ofs); #line 579 "src/jit/x64/tiles.dasc" break; default: DIE("Unsupported load size: %d\n", size); } } MVM_JIT_TILE_DECL(and_load_idx) { MVMint8 out = tile->values[0]; MVMint8 in1 = tile->values[1]; MVMint8 base = tile->values[2]; MVMint8 idx = tile->values[3]; MVMint32 scl = tile->args[0]; MVMint32 size = tile->args[1]; assert(out == in1); if (scl != 8) DIE("IDX Scale %d NYI\n", scl); switch (size) { case 1: //| and Rb(out), byte [Rq(base)+Rq(idx)*8]; dasm_put(Dst, 5770, (out), (idx), (base), 0); #line 598 "src/jit/x64/tiles.dasc" break; case 2: //| and Rw(out), word [Rq(base)+Rq(idx)*8]; dasm_put(Dst, 5784, (out), (idx), (base), 0); #line 601 "src/jit/x64/tiles.dasc" break; case 4: //| and Rd(out), dword [Rq(base)+Rq(idx)*8]; dasm_put(Dst, 5785, (out), (idx), (base), 0); #line 604 "src/jit/x64/tiles.dasc" break; case 8: //| and Rq(out), qword [Rq(base)+Rq(idx)*8]; dasm_put(Dst, 5798, (out), (idx), (base), 0); #line 607 "src/jit/x64/tiles.dasc" break; default: DIE("Unsupported load size: %d\n", size); } } MVM_JIT_TILE_DECL(mul_reg) { MVMint8 reg[2]; ensure_two_operand_pre(tc, compiler, tile, reg); //| imul Rq(reg[0]), Rq(reg[1]); dasm_put(Dst, 5812, (reg[0]), (reg[1])); #line 617 "src/jit/x64/tiles.dasc" ensure_two_operand_post(tc, compiler, tile, reg); } MVM_JIT_TILE_DECL(or_reg) { MVMint8 reg[2]; ensure_two_operand_pre(tc, compiler, tile, reg); //| or Rq(reg[0]), Rq(reg[1]); dasm_put(Dst, 5822, (reg[1]), (reg[0])); #line 624 "src/jit/x64/tiles.dasc" ensure_two_operand_post(tc, compiler, tile, reg); } MVM_JIT_TILE_DECL(xor_reg) { MVMint8 reg[2]; ensure_two_operand_pre(tc, compiler, tile, reg); //| xor Rq(reg[0]), Rq(reg[1]); dasm_put(Dst, 5831, (reg[1]), (reg[0])); #line 631 "src/jit/x64/tiles.dasc" ensure_two_operand_post(tc, compiler, tile, reg); } MVM_JIT_TILE_DECL(not_reg) { MVMint8 out = tile->values[0]; MVMint8 in = tile->values[1]; assert(out == in); //| not Rq(out); dasm_put(Dst, 5840, (out)); #line 639 "src/jit/x64/tiles.dasc" } MVM_JIT_TILE_DECL(sub_reg) { MVMint8 reg[2]; ensure_two_operand_pre(tc, compiler, tile, reg); //| sub Rq(reg[0]), Rq(reg[1]); dasm_put(Dst, 5848, (reg[1]), (reg[0])); #line 645 "src/jit/x64/tiles.dasc" ensure_two_operand_post(tc, compiler, tile, reg); } MVM_JIT_TILE_DECL(sub_const) { MVMint8 out = tile->values[0]; MVMint8 in1 = tile->values[1]; MVMint32 val = tile->args[0]; MVMint32 sz = tile->args[1]; assert(out == in1); //| sub Rq(out), val; dasm_put(Dst, 5857, (out), val); #line 655 "src/jit/x64/tiles.dasc" } MVM_JIT_TILE_DECL(sub_load_addr) { MVMint8 out = tile->values[0]; MVMint8 in1 = tile->values[1]; MVMint8 base = tile->values[2]; MVMint32 ofs = tile->args[0]; MVMint32 size = tile->args[1]; assert(out == in1); switch (size) { case 1: //| sub Rb(out), byte [Rq(base)+ofs]; dasm_put(Dst, 5866, (out), (base), ofs); #line 667 "src/jit/x64/tiles.dasc" break; case 2: //| sub Rw(out), word [Rq(base)+ofs]; dasm_put(Dst, 5877, (out), (base), ofs); #line 670 "src/jit/x64/tiles.dasc" break; case 4: //| sub Rd(out), dword [Rq(base)+ofs]; dasm_put(Dst, 5878, (out), (base), ofs); #line 673 "src/jit/x64/tiles.dasc" break; case 8: //| sub Rq(out), qword [Rq(base)+ofs]; dasm_put(Dst, 5888, (out), (base), ofs); #line 676 "src/jit/x64/tiles.dasc" break; default: DIE("Unsupported load size: %d\n", size); } } MVM_JIT_TILE_DECL(sub_load_idx) { MVMint8 out = tile->values[0]; MVMint8 in1 = tile->values[1]; MVMint8 base = tile->values[2]; MVMint8 idx = tile->values[3]; MVMint32 scl = tile->args[0]; MVMint32 size = tile->args[1]; assert(out != in1); if (scl != 8) DIE("IDX Scale %d NYI\n", scl); switch (size) { case 1: //| sub Rb(out), byte [Rq(base)+Rq(idx)*8]; dasm_put(Dst, 5899, (out), (idx), (base), 0); #line 695 "src/jit/x64/tiles.dasc" break; case 2: //| sub Rw(out), word [Rq(base)+Rq(idx)*8]; dasm_put(Dst, 5913, (out), (idx), (base), 0); #line 698 "src/jit/x64/tiles.dasc" break; case 4: //| sub Rd(out), dword [Rq(base)+Rq(idx)*8]; dasm_put(Dst, 5914, (out), (idx), (base), 0); #line 701 "src/jit/x64/tiles.dasc" break; case 8: //| sub Rq(out), qword [Rq(base)+Rq(idx)*8]; dasm_put(Dst, 5927, (out), (idx), (base), 0); #line 704 "src/jit/x64/tiles.dasc" break; default: DIE("Unsupported load size: %d\n", size); } } MVM_JIT_TILE_DECL(test) { MVMint8 reg = tile->values[1]; switch (tile->size) { case 1: //| test Rb(reg), Rb(reg); dasm_put(Dst, 5941, (reg), (reg)); #line 718 "src/jit/x64/tiles.dasc" break; case 2: //| test Rw(reg), Rw(reg); dasm_put(Dst, 5950, (reg), (reg)); #line 721 "src/jit/x64/tiles.dasc" break; case 4: //| test Rd(reg), Rd(reg); dasm_put(Dst, 5951, (reg), (reg)); #line 724 "src/jit/x64/tiles.dasc" break; case 8: default: /* NB - this is a hack, because we don't assign a size to the result of * CALL, its size would be 0, and we'd have nothing compiled. Better fix * would be to assign a result size to CALL. */ //| test Rq(reg), Rq(reg); dasm_put(Dst, 5959, (reg), (reg)); #line 731 "src/jit/x64/tiles.dasc" break; } } MVM_JIT_TILE_DECL(test_addr) { MVMint8 base = tile->values[1]; MVMint32 ofs = tile->args[0]; MVMint32 size = tile->args[1]; /* TODO - I now suspect that this can be OR [addr], 0, without loss of generality */ switch (size) { case 1: //| cmp byte [Rq(base)+ofs], 0; dasm_put(Dst, 5968, (base), ofs); #line 745 "src/jit/x64/tiles.dasc" break; case 2: //| cmp word [Rq(base)+ofs], 0; dasm_put(Dst, 5978, (base), ofs); #line 748 "src/jit/x64/tiles.dasc" break; case 4: //| cmp dword [Rq(base)+ofs], 0; dasm_put(Dst, 5979, (base), ofs); #line 751 "src/jit/x64/tiles.dasc" break; case 8: //| cmp qword [Rq(base)+ofs], 0; dasm_put(Dst, 5988, (base), ofs); #line 754 "src/jit/x64/tiles.dasc" break; default: DIE("Unsupported size %d for load\n", size); } } MVM_JIT_TILE_DECL(test_idx) { MVMint8 base = tile->values[1]; MVMint8 idx = tile->values[2]; MVMint32 scl = tile->args[0]; MVMint32 size = tile->args[1]; if (scl != 8) DIE("Scale %d NYI\n", scl); switch(size) { case 1: //| cmp byte [Rq(base)+Rq(idx)*8], 0; dasm_put(Dst, 5998, (idx), (base), 0); #line 771 "src/jit/x64/tiles.dasc" break; case 2: //| cmp word [Rq(base)+Rq(idx)*8], 0; dasm_put(Dst, 6011, (idx), (base), 0); #line 774 "src/jit/x64/tiles.dasc" break; case 4: //| cmp dword [Rq(base)+Rq(idx)*8], 0; dasm_put(Dst, 6012, (idx), (base), 0); #line 777 "src/jit/x64/tiles.dasc" break; case 8: //| cmp qword [Rq(base)+Rq(idx)*8], 0; dasm_put(Dst, 6024, (idx), (base), 0); #line 780 "src/jit/x64/tiles.dasc" break; default: DIE("Unsupported size %d for load\n", tile->size); } } MVM_JIT_TILE_DECL(test_and) { MVMint8 rega = tile->values[1]; MVMint8 regb = tile->values[2]; switch(tile->size) { case 1: //| test Rb(regb), Rb(rega); dasm_put(Dst, 5941, (rega), (regb)); #line 792 "src/jit/x64/tiles.dasc" break; case 2: //| test Rw(regb), Rw(rega); dasm_put(Dst, 5950, (rega), (regb)); #line 795 "src/jit/x64/tiles.dasc" break; case 4: //| test Rd(regb), Rd(rega); dasm_put(Dst, 5951, (rega), (regb)); #line 798 "src/jit/x64/tiles.dasc" break; case 8: //| test Rq(regb), Rq(rega); dasm_put(Dst, 5959, (rega), (regb)); #line 801 "src/jit/x64/tiles.dasc" break; } } MVM_JIT_TILE_DECL(test_const) { MVMint8 reg = tile->values[1]; MVMint32 val = tile->args[0]; switch(tile->size) { case 1: //| test Rb(reg), val; dasm_put(Dst, 6037, (reg), val); #line 811 "src/jit/x64/tiles.dasc" break; case 2: //| test Rw(reg), val; dasm_put(Dst, 6046, (reg), val); #line 814 "src/jit/x64/tiles.dasc" break; case 4: //| test Rd(reg), val; dasm_put(Dst, 6055, (reg), val); #line 817 "src/jit/x64/tiles.dasc" break; default: DIE("Unsupported size of constant"); break; } } MVM_JIT_TILE_DECL(test_addr_const) { MVMint8 reg = tile->values[1]; /* args: $ofs $lsize $val $csize */ MVMint32 ofs = tile->args[0]; MVMint32 val = tile->args[2]; switch(tile->size) { case 1: //| test byte [Rq(reg)+ofs], val; dasm_put(Dst, 6063, (reg), ofs, val); #line 832 "src/jit/x64/tiles.dasc" break; case 2: //| test word [Rq(reg)+ofs], val; dasm_put(Dst, 6074, (reg), ofs, val); #line 835 "src/jit/x64/tiles.dasc" break; case 4: //| test dword [Rq(reg)+ofs], val; dasm_put(Dst, 6085, (reg), ofs, val); #line 838 "src/jit/x64/tiles.dasc" break; default: DIE("Unsupported size of constant"); break; } } MVM_JIT_TILE_DECL(test_num) { MVMint8 reg = REG_NUM(tile->values[1]); //| xorpd xmm0, xmm0; //| ucomisd xmm(reg), xmm0; dasm_put(Dst, 6095, (reg)); #line 849 "src/jit/x64/tiles.dasc" } MVM_JIT_TILE_DECL(cmp) { MVMint8 regl = tile->values[1]; MVMint8 regr = tile->values[2]; switch (tile->size) { case 1: //| cmp Rb(regl), Rb(regr); dasm_put(Dst, 6107, (regr), (regl)); #line 858 "src/jit/x64/tiles.dasc" break; case 2: //| cmp Rw(regl), Rw(regr); dasm_put(Dst, 6116, (regr), (regl)); #line 861 "src/jit/x64/tiles.dasc" break; case 4: //| cmp Rd(regl), Rd(regr); dasm_put(Dst, 6117, (regr), (regl)); #line 864 "src/jit/x64/tiles.dasc" break; case 8: //| cmp Rq(regl), Rq(regr); dasm_put(Dst, 6125, (regr), (regl)); #line 867 "src/jit/x64/tiles.dasc" break; } } MVM_JIT_TILE_DECL(cmp_num) { MVMint8 left = REG_NUM(tile->values[1]); MVMint8 right = REG_NUM(tile->values[2]); //| ucomisd xmm(left), xmm(right); dasm_put(Dst, 6134, (left), (right)); #line 875 "src/jit/x64/tiles.dasc" } MVM_JIT_TILE_DECL(flagval) { /* Intel SDM Volume 1, ch5.1.6 - Bit and Byte Instructions */ MVMint8 out = tile->values[0]; MVMint32 child = MVM_JIT_EXPR_LINKS(tree, tile->node)[0]; enum MVMJitExprOperator flag = tree->nodes[child]; /* This isn't exactly elegant, better mechanism wanted */ MVMuint8 test_type = MVM_JIT_EXPR_INFO(tree, child)->type; if (test_type == MVM_reg_num32 || test_type == MVM_reg_num64) { switch (flag) { case MVM_JIT_LT: //| setnp al; //| setb Rb(out); //| and Rb(out), al; dasm_put(Dst, 6144, (out), (out)); #line 891 "src/jit/x64/tiles.dasc" break; case MVM_JIT_LE: //| setnp al; //| setbe Rb(out); //| and Rb(out), al; dasm_put(Dst, 6161, (out), (out)); #line 896 "src/jit/x64/tiles.dasc" break; case MVM_JIT_ZR: case MVM_JIT_EQ: //| setnp al; //| setz Rb(out); //| and Rb(out), al; dasm_put(Dst, 6178, (out), (out)); #line 902 "src/jit/x64/tiles.dasc" break; case MVM_JIT_NZ: case MVM_JIT_NE: //| setp al; //| setnz Rb(out); //| or Rb(out), al; dasm_put(Dst, 6195, (out), (out)); #line 908 "src/jit/x64/tiles.dasc" break; case MVM_JIT_GE: //| setae Rb(out); dasm_put(Dst, 6212, (out)); #line 911 "src/jit/x64/tiles.dasc" break; case MVM_JIT_GT: //| seta Rb(out); dasm_put(Dst, 6220, (out)); #line 914 "src/jit/x64/tiles.dasc" break; default: abort(); } } else { switch (flag) { case MVM_JIT_LT: //| setl Rb(out); dasm_put(Dst, 6228, (out)); #line 922 "src/jit/x64/tiles.dasc" break; case MVM_JIT_LE: //| setle Rb(out); dasm_put(Dst, 6236, (out)); #line 925 "src/jit/x64/tiles.dasc" break; case MVM_JIT_ZR: case MVM_JIT_EQ: //| setz Rb(out); dasm_put(Dst, 6244, (out)); #line 929 "src/jit/x64/tiles.dasc" break; case MVM_JIT_NZ: case MVM_JIT_NE: //| setnz Rb(out); dasm_put(Dst, 6252, (out)); #line 933 "src/jit/x64/tiles.dasc" break; case MVM_JIT_GE: //| setge Rb(out); dasm_put(Dst, 6260, (out)); #line 936 "src/jit/x64/tiles.dasc" break; case MVM_JIT_GT: //| setg Rb(out); dasm_put(Dst, 6268, (out)); #line 939 "src/jit/x64/tiles.dasc" break; default: abort(); } } /* XXX THIS IS A HACK * The size cast is supposed to be applied by the expression template * builder, but that subtly doesn't work (it's not applied for STORE * operands, and when it is, it causes even subtler errors with CONST * arguments. (const_i64_16 returns a 64 bit signed integer as a 16 bit * signed integer argument, and currently CONST doesn't have a sign, and the * tile yielding the value (fortunately) doesn't respect the size. */ //| movzx Rq(out), Rb(out); dasm_put(Dst, 5451, (out), (out)); #line 954 "src/jit/x64/tiles.dasc" } MVM_JIT_TILE_DECL(mark) { MVMint32 label = tile->args[0]; //|=>(label): dasm_put(Dst, 245, (label)); #line 960 "src/jit/x64/tiles.dasc" } MVM_JIT_TILE_DECL(label) { MVMint8 reg = tile->values[0]; MVMint32 label = tile->args[0]; //| lea Rq(reg), [=>label]; dasm_put(Dst, 6276, (reg), label); #line 966 "src/jit/x64/tiles.dasc" } MVM_JIT_TILE_DECL(branch_label) { MVMint32 label = tile->args[0]; if (label >= 0) { //| jmp =>(label); dasm_put(Dst, 4257, (label)); #line 972 "src/jit/x64/tiles.dasc" } else { //| jmp ->exit; dasm_put(Dst, 4252); #line 974 "src/jit/x64/tiles.dasc" } } static void move_call_value(MVMThreadContext *tc, MVMJitCompiler *compiler, MVMJitTile *tile) { if (MVM_JIT_TILE_YIELDS_VALUE(tile)) { MVMint8 out = tile->values[0]; if (IS_GPR(out)) { //| mov Rq(out), rax; dasm_put(Dst, 5406, (out)); #line 984 "src/jit/x64/tiles.dasc" } else { //| movsd xmm(REG_NUM(out)), xmm0; dasm_put(Dst, 6284, (REG_NUM(out))); #line 986 "src/jit/x64/tiles.dasc" } } } MVM_JIT_TILE_DECL(call) { MVMint8 reg = tile->values[1]; //| call Rq(reg); dasm_put(Dst, 6293, (reg)); #line 993 "src/jit/x64/tiles.dasc" move_call_value(tc, compiler, tile); } MVM_JIT_TILE_DECL(call_func) { uintptr_t ptr = tree->constants[tile->args[0]].u; //| callp ptr; dasm_put(Dst, 116); dasm_put(Dst, 118, (MVMuint32)((uintptr_t)(ptr)), (MVMuint32)((uintptr_t)(ptr) >> 32)); dasm_put(Dst, 260); #line 999 "src/jit/x64/tiles.dasc" move_call_value(tc, compiler, tile); } MVM_JIT_TILE_DECL(call_addr) { MVMint8 reg = tile->values[1]; MVMint32 ofs = tile->args[0]; //| call qword [Rq(reg)+ofs]; dasm_put(Dst, 6300, (reg), ofs); #line 1007 "src/jit/x64/tiles.dasc" move_call_value(tc, compiler, tile); }