diff options
Diffstat (limited to 'Src/ns-eel2')
-rw-r--r-- | Src/ns-eel2/asm-nseel-ppc-gcc.c | 1511 | ||||
-rw-r--r-- | Src/ns-eel2/asm-nseel-x64-macho.o | bin | 0 -> 10264 bytes | |||
-rw-r--r-- | Src/ns-eel2/asm-nseel-x86-gcc.c | 2153 | ||||
-rw-r--r-- | Src/ns-eel2/asm-nseel-x86-msvc.c | 4101 | ||||
-rw-r--r-- | Src/ns-eel2/denormal.h | 260 | ||||
-rw-r--r-- | Src/ns-eel2/glue_x86.h | 524 | ||||
-rw-r--r-- | Src/ns-eel2/glue_x86_64.h | 261 | ||||
-rw-r--r-- | Src/ns-eel2/ns-eel-addfuncs.h | 81 | ||||
-rw-r--r-- | Src/ns-eel2/ns-eel-func-ref.h | 62 | ||||
-rw-r--r-- | Src/ns-eel2/ns-eel-int.h | 331 | ||||
-rw-r--r-- | Src/ns-eel2/ns-eel.h | 275 | ||||
-rw-r--r-- | Src/ns-eel2/nseel-caltab.c | 1 | ||||
-rw-r--r-- | Src/ns-eel2/nseel-cfunc.c | 188 | ||||
-rw-r--r-- | Src/ns-eel2/nseel-compiler.c | 5700 | ||||
-rw-r--r-- | Src/ns-eel2/nseel-eval.c | 447 | ||||
-rw-r--r-- | Src/ns-eel2/nseel-lextab.c | 1 | ||||
-rw-r--r-- | Src/ns-eel2/nseel-ram.c | 463 | ||||
-rw-r--r-- | Src/ns-eel2/nseel-yylex.c | 40 | ||||
-rw-r--r-- | Src/ns-eel2/wdlcstring.h | 316 | ||||
-rw-r--r-- | Src/ns-eel2/wdltypes.h | 160 | ||||
-rw-r--r-- | Src/ns-eel2/y.tab.c | 2191 | ||||
-rw-r--r-- | Src/ns-eel2/y.tab.h | 117 |
22 files changed, 19183 insertions, 0 deletions
diff --git a/Src/ns-eel2/asm-nseel-ppc-gcc.c b/Src/ns-eel2/asm-nseel-ppc-gcc.c new file mode 100644 index 00000000..db5b4f6b --- /dev/null +++ b/Src/ns-eel2/asm-nseel-ppc-gcc.c @@ -0,0 +1,1511 @@ +#define FUNCTION_MARKER "mr r0, r0\n" \ + "mr r1, r1\n" \ + "mr r2, r2\n" + +#if EEL_F_SIZE == 8 + +void nseel_asm_1pdd(void) +{ + + __asm__( + FUNCTION_MARKER + "addis r5, 0, 0xdead\n" + "ori r5, r5, 0xbeef\n" + "mtctr r5\n" + "subi r1, r1, 64\n" + "bctrl\n" + "addi r1, r1, 64\n" + FUNCTION_MARKER + :: ); +} +void nseel_asm_1pdd_end(void){} + +void nseel_asm_2pdd(void) +{ + + __asm__( + FUNCTION_MARKER + "addis r7, 0, 0xdead\n" + "ori r7, r7, 0xbeef\n" + "fmr f2, f1\n" + "lfd f1, 0(r14)\n" + "mtctr r7\n" + "subi r1, r1, 64\n" + "bctrl\n" + "addi r1, r1, 64\n" + FUNCTION_MARKER + :: ); +}; +void nseel_asm_2pdd_end(void){} + +void nseel_asm_2pdds(void) +{ + __asm__( + FUNCTION_MARKER + "addis r5, 0, 0xdead\n" + "ori r5, r5, 0xbeef\n" + "fmr f2, f1\n" + "lfd f1, 0(r14)\n" + "mtctr r5\n" + "subi r1, r1, 64\n" + "bctrl\n" + "addi r1, r1, 64\n" + "stfd f1, 0(r14)\n" + "mr r3, r14\n" + FUNCTION_MARKER + :: ); +} +void nseel_asm_2pdds_end(void){} + +#else // 32 bit floating point calls + +#error no 32 bit float support + +#endif + +//--------------------------------------------------------------------------------------------------------------- + + + +// do nothing, eh +void nseel_asm_exec2(void) +{ + __asm__( + FUNCTION_MARKER + FUNCTION_MARKER + ); +} +void nseel_asm_exec2_end(void) { } + + + +void nseel_asm_invsqrt(void) +{ + __asm__( + FUNCTION_MARKER + "frsqrte f1, f1\n" // less accurate than our x86 equivilent, but invsqrt() is inherently inaccurate anyway + FUNCTION_MARKER + ); +} +void nseel_asm_invsqrt_end(void) {} + +void nseel_asm_dbg_getstackptr(void) +{ + __asm__( + FUNCTION_MARKER + "addis r11, 0, 0x4330\n" + "xoris r10, r1, 0x8000\n" + "stw r11, -8(r1)\n" // 0x43300000 + "stw r10, -4(r1)\n" // our integer sign flipped + "lfd f1, -8(r1)\n" + "fsub f1, f1, f30\n" + FUNCTION_MARKER + ); +} +void nseel_asm_dbg_getstackptr_end(void) {} + + +//--------------------------------------------------------------------------------------------------------------- +void nseel_asm_sqr(void) +{ + __asm__( + FUNCTION_MARKER + "fmul f1, f1, f1\n" + FUNCTION_MARKER + ); +} +void nseel_asm_sqr_end(void) {} + + +//--------------------------------------------------------------------------------------------------------------- +void nseel_asm_abs(void) +{ + __asm__( + FUNCTION_MARKER + "fabs f1, f1\n" + FUNCTION_MARKER + ); +} +void nseel_asm_abs_end(void) {} + + +//--------------------------------------------------------------------------------------------------------------- +void nseel_asm_assign(void) +{ + __asm__( + FUNCTION_MARKER + "lfd f1, 0(r3)\n" + "mr r3, r14\n" + "stfd f1, 0(r14)\n" + FUNCTION_MARKER + ); +} +void nseel_asm_assign_end(void) {} +// +//--------------------------------------------------------------------------------------------------------------- +void nseel_asm_assign_fromfp(void) +{ + __asm__( + FUNCTION_MARKER + "mr r3, r14\n" + "stfd f1, 0(r14)\n" + FUNCTION_MARKER + ); +} +void nseel_asm_assign_fromfp_end(void) {} + +//--------------------------------------------------------------------------------------------------------------- +void nseel_asm_assign_fast(void) +{ + __asm__( + FUNCTION_MARKER + "lfd f1, 0(r3)\n" + "mr r3, r14\n" + "stfd f1, 0(r14)\n" + FUNCTION_MARKER + ); +} +void nseel_asm_assign_fast_end(void) {} +// +//--------------------------------------------------------------------------------------------------------------- +void nseel_asm_assign_fast_fromfp(void) +{ + __asm__( + FUNCTION_MARKER + "mr r3, r14\n" + "stfd f1, 0(r14)\n" + FUNCTION_MARKER + ); +} +void nseel_asm_assign_fast_fromfp_end(void) {} + + + +//--------------------------------------------------------------------------------------------------------------- +void nseel_asm_add(void) +{ + __asm__( + FUNCTION_MARKER + "lfd f2, 0(r14)\n" + "fadd f1, f1, f2\n" + FUNCTION_MARKER + ); +} +void nseel_asm_add_end(void) {} + +void nseel_asm_add_op(void) +{ + __asm__( + FUNCTION_MARKER + "lfd f2, 0(r14)\n" + "fadd f1, f1, f2\n" + "mr r3, r14\n" + "stfd f1, 0(r14)\n" + FUNCTION_MARKER + ); +} +void nseel_asm_add_op_end(void) {} + +void nseel_asm_add_op_fast(void) +{ + __asm__( + FUNCTION_MARKER + "lfd f2, 0(r14)\n" + "fadd f1, f1, f2\n" + "mr r3, r14\n" + "stfd f1, 0(r14)\n" + FUNCTION_MARKER + ); +} +void nseel_asm_add_op_fast_end(void) {} + + +//--------------------------------------------------------------------------------------------------------------- +void nseel_asm_sub(void) +{ + __asm__( + FUNCTION_MARKER + "lfd f2, 0(r14)\n" + "fsub f1, f2, f1\n" + FUNCTION_MARKER + ); +} +void nseel_asm_sub_end(void) {} + +void nseel_asm_sub_op(void) +{ + __asm__( + FUNCTION_MARKER + "lfd f2, 0(r14)\n" + "fsub f1, f2, f1\n" + "mr r3, r14\n" + "stfd f1, 0(r14)\n" + FUNCTION_MARKER + ); +} +void nseel_asm_sub_op_end(void) {} + +void nseel_asm_sub_op_fast(void) +{ + __asm__( + FUNCTION_MARKER + "lfd f2, 0(r14)\n" + "fsub f1, f2, f1\n" + "mr r3, r14\n" + "stfd f1, 0(r14)\n" + FUNCTION_MARKER + ); +} +void nseel_asm_sub_op_fast_end(void) {} + +//--------------------------------------------------------------------------------------------------------------- +void nseel_asm_mul(void) +{ + __asm__( + FUNCTION_MARKER + "lfd f2, 0(r14)\n" + "fmul f1, f2, f1\n" + FUNCTION_MARKER + ); +} +void nseel_asm_mul_end(void) {} + +void nseel_asm_mul_op(void) +{ + __asm__( + FUNCTION_MARKER + "lfd f2, 0(r14)\n" + "fmul f1, f2, f1\n" + "mr r3, r14\n" + "stfd f1, 0(r14)\n" + FUNCTION_MARKER + ); +} +void nseel_asm_mul_op_end(void) {} + +void nseel_asm_mul_op_fast(void) +{ + __asm__( + FUNCTION_MARKER + "lfd f2, 0(r14)\n" + "fmul f1, f2, f1\n" + "mr r3, r14\n" + "stfd f1, 0(r14)\n" + FUNCTION_MARKER + ); +} +void nseel_asm_mul_op_fast_end(void) {} + +//--------------------------------------------------------------------------------------------------------------- +void nseel_asm_div(void) +{ + __asm__( + FUNCTION_MARKER + "lfd f2, 0(r14)\n" + "fdiv f1, f2, f1\n" + FUNCTION_MARKER + ); +} +void nseel_asm_div_end(void) {} + +void nseel_asm_div_op(void) +{ + __asm__( + FUNCTION_MARKER + "lfd f2, 0(r14)\n" + "fdiv f1, f2, f1\n" + "mr r3, r14\n" + "stfd f1, 0(r14)\n" + FUNCTION_MARKER + ); +} +void nseel_asm_div_op_end(void) {} + +void nseel_asm_div_op_fast(void) +{ + __asm__( + FUNCTION_MARKER + "lfd f2, 0(r14)\n" + "fdiv f1, f2, f1\n" + "mr r3, r14\n" + "stfd f1, 0(r14)\n" + FUNCTION_MARKER + ); +} +void nseel_asm_div_op_fast_end(void) {} + +//--------------------------------------------------------------------------------------------------------------- +void nseel_asm_mod(void) +{ + __asm__( + FUNCTION_MARKER + "lfd f2, 0(r14)\n" + "fabs f1, f1\n" + "fabs f2, f2\n" + "fctiwz f1, f1\n" + "fctiwz f2, f2\n" + "stfd f1, -8(r1)\n" + "stfd f2, -16(r1)\n" + "lwz r10, -4(r1)\n" + "lwz r11, -12(r1)\n" //r11 and r12 have the integers + + "divw r12, r11, r10\n" + "mullw r12, r12, r10\n" + "subf r10, r12, r11\n" + + "addis r11, 0, 0x4330\n" + "xoris r10, r10, 0x8000\n" + "stw r11, -8(r1)\n" // 0x43300000 + "stw r10, -4(r1)\n" // our integer sign flipped + "lfd f1, -8(r1)\n" + "fsub f1, f1, f30\n" + FUNCTION_MARKER + ); +} +void nseel_asm_mod_end(void) {} + +void nseel_asm_shl(void) +{ + __asm__( + FUNCTION_MARKER + "lfd f2, 0(r14)\n" + "fctiwz f1, f1\n" + "fctiwz f2, f2\n" + "stfd f1, -8(r1)\n" + "stfd f2, -16(r1)\n" + "lwz r10, -4(r1)\n" + "lwz r11, -12(r1)\n" //r11 and r12 have the integers + "slw r10, r11, r10\n" // r10 has the result + "addis r11, 0, 0x4330\n" + "xoris r10, r10, 0x8000\n" + "stw r11, -8(r1)\n" // 0x43300000 + "stw r10, -4(r1)\n" // our integer sign flipped + "lfd f1, -8(r1)\n" + "fsub f1, f1, f30\n" + FUNCTION_MARKER + ); +} +void nseel_asm_shl_end(void) {} + +void nseel_asm_shr(void) +{ + __asm__( + FUNCTION_MARKER + "lfd f2, 0(r14)\n" + "fctiwz f1, f1\n" + "fctiwz f2, f2\n" + "stfd f1, -8(r1)\n" + "stfd f2, -16(r1)\n" + "lwz r10, -4(r1)\n" + "lwz r11, -12(r1)\n" //r11 and r12 have the integers + "sraw r10, r11, r10\n" // r10 has the result + "addis r11, 0, 0x4330\n" + "xoris r10, r10, 0x8000\n" + "stw r11, -8(r1)\n" // 0x43300000 + "stw r10, -4(r1)\n" // our integer sign flipped + "lfd f1, -8(r1)\n" + "fsub f1, f1, f30\n" + FUNCTION_MARKER + ); +} +void nseel_asm_shr_end(void) {} + +void nseel_asm_mod_op(void) +{ + + __asm__( + FUNCTION_MARKER + "lfd f2, 0(r14)\n" + "fabs f1, f1\n" + "fabs f2, f2\n" + "fctiwz f1, f1\n" + "fctiwz f2, f2\n" + "stfd f1, -8(r1)\n" + "stfd f2, -16(r1)\n" + "lwz r10, -4(r1)\n" + "lwz r11, -12(r1)\n" //r11 and r12 have the integers + + "divw r12, r11, r10\n" + "mullw r12, r12, r10\n" + "subf r10, r12, r11\n" + + "addis r11, 0, 0x4330\n" + "xoris r10, r10, 0x8000\n" + "stw r11, -8(r1)\n" // 0x43300000 + "stw r10, -4(r1)\n" // our integer sign flipped + "lfd f1, -8(r1)\n" + "fsub f1, f1, f30\n" + "mr r3, r14\n" + "stfd f1, 0(r14)\n" + FUNCTION_MARKER + ); + +} +void nseel_asm_mod_op_end(void) {} + +//--------------------------------------------------------------------------------------------------------------- +void nseel_asm_or(void) +{ + __asm__( + FUNCTION_MARKER + "lfd f2, 0(r14)\n" + "fctiwz f1, f1\n" + "fctiwz f2, f2\n" + "stfd f1, -8(r1)\n" + "stfd f2, -16(r1)\n" + "lwz r10, -4(r1)\n" + "lwz r11, -12(r1)\n" //r11 and r12 have the integers + "or r10, r10, r11\n" // r10 has the result + "addis r11, 0, 0x4330\n" + "xoris r10, r10, 0x8000\n" + "stw r11, -8(r1)\n" // 0x43300000 + "stw r10, -4(r1)\n" // our integer sign flipped + "lfd f1, -8(r1)\n" + "fsub f1, f1, f30\n" + FUNCTION_MARKER + ); +} +void nseel_asm_or_end(void) {} + +void nseel_asm_or0(void) +{ + __asm__( + FUNCTION_MARKER + "fctiwz f1, f1\n" + "addis r11, 0, 0x4330\n" + "stfd f1, -8(r1)\n" + "lwz r10, -4(r1)\n" + "xoris r10, r10, 0x8000\n" + "stw r11, -8(r1)\n" // 0x43300000 + "stw r10, -4(r1)\n" // our integer sign flipped + "lfd f1, -8(r1)\n" + "fsub f1, f1, f30\n" + FUNCTION_MARKER + ); +} +void nseel_asm_or0_end(void) {} + +void nseel_asm_or_op(void) +{ + __asm__( + FUNCTION_MARKER + "lfd f2, 0(r14)\n" + "fctiwz f1, f1\n" + "fctiwz f2, f2\n" + "stfd f1, -8(r1)\n" + "stfd f2, -16(r1)\n" + "lwz r10, -4(r1)\n" + "lwz r11, -12(r1)\n" //r11 and r12 have the integers + "or r10, r10, r11\n" // r10 has the result + "addis r11, 0, 0x4330\n" + "xoris r10, r10, 0x8000\n" + "stw r11, -8(r1)\n" // 0x43300000 + "stw r10, -4(r1)\n" // our integer sign flipped + "lfd f1, -8(r1)\n" + "fsub f1, f1, f30\n" + "mr r3, r14\n" + "stfd f1, 0(r14)\n" + FUNCTION_MARKER + ); +} +void nseel_asm_or_op_end(void) {} + +//--------------------------------------------------------------------------------------------------------------- +void nseel_asm_xor(void) +{ + __asm__( + FUNCTION_MARKER + "lfd f2, 0(r14)\n" + "fctiwz f1, f1\n" + "fctiwz f2, f2\n" + "stfd f1, -8(r1)\n" + "stfd f2, -16(r1)\n" + "lwz r10, -4(r1)\n" + "lwz r11, -12(r1)\n" //r11 and r12 have the integers + "xor r10, r10, r11\n" // r10 has the result + "addis r11, 0, 0x4330\n" + "xoris r10, r10, 0x8000\n" + "stw r11, -8(r1)\n" // 0x43300000 + "stw r10, -4(r1)\n" // our integer sign flipped + "lfd f1, -8(r1)\n" + "fsub f1, f1, f30\n" + FUNCTION_MARKER + ); +} +void nseel_asm_xor_end(void) {} + +void nseel_asm_xor_op(void) +{ + __asm__( + FUNCTION_MARKER + "lfd f2, 0(r14)\n" + "fctiwz f1, f1\n" + "fctiwz f2, f2\n" + "stfd f1, -8(r1)\n" + "stfd f2, -16(r1)\n" + "lwz r10, -4(r1)\n" + "lwz r11, -12(r1)\n" //r11 and r12 have the integers + "xor r10, r10, r11\n" // r10 has the result + "addis r11, 0, 0x4330\n" + "xoris r10, r10, 0x8000\n" + "stw r11, -8(r1)\n" // 0x43300000 + "stw r10, -4(r1)\n" // our integer sign flipped + "lfd f1, -8(r1)\n" + "fsub f1, f1, f30\n" + "mr r3, r14\n" + "stfd f1, 0(r14)\n" + FUNCTION_MARKER + ); +} +void nseel_asm_xor_op_end(void) {} + +//--------------------------------------------------------------------------------------------------------------- +void nseel_asm_and(void) +{ + __asm__( + FUNCTION_MARKER + "lfd f2, 0(r14)\n" + "fctiwz f1, f1\n" + "fctiwz f2, f2\n" + "stfd f1, -8(r1)\n" + "stfd f2, -16(r1)\n" + "lwz r10, -4(r1)\n" + "lwz r11, -12(r1)\n" //r11 and r12 have the integers + "and r10, r10, r11\n" // r10 has the result + "addis r11, 0, 0x4330\n" + "xoris r10, r10, 0x8000\n" + "stw r11, -8(r1)\n" // 0x43300000 + "stw r10, -4(r1)\n" // our integer sign flipped + "lfd f1, -8(r1)\n" + "fsub f1, f1, f30\n" + FUNCTION_MARKER + );} +void nseel_asm_and_end(void) {} + +void nseel_asm_and_op(void) +{ + __asm__( + FUNCTION_MARKER + "lfd f2, 0(r14)\n" + "fctiwz f1, f1\n" + "fctiwz f2, f2\n" + "stfd f1, -8(r1)\n" + "stfd f2, -16(r1)\n" + "lwz r10, -4(r1)\n" + "lwz r11, -12(r1)\n" //r11 and r12 have the integers + "and r10, r10, r11\n" // r10 has the result + "addis r11, 0, 0x4330\n" + "xoris r10, r10, 0x8000\n" + "stw r11, -8(r1)\n" // 0x43300000 + "stw r10, -4(r1)\n" // our integer sign flipped + "lfd f1, -8(r1)\n" + "fsub f1, f1, f30\n" + "mr r3, r14\n" + "stfd f1, 0(r14)\n" + FUNCTION_MARKER + ); +} +void nseel_asm_and_op_end(void) {} + + +//--------------------------------------------------------------------------------------------------------------- +void nseel_asm_uplus(void) // this is the same as doing nothing, it seems +{ + __asm__( + FUNCTION_MARKER + FUNCTION_MARKER + ); +} +void nseel_asm_uplus_end(void) {} + +//--------------------------------------------------------------------------------------------------------------- +void nseel_asm_uminus(void) +{ + __asm__( + FUNCTION_MARKER + "fneg f1, f1\n" + FUNCTION_MARKER + ); +} +void nseel_asm_uminus_end(void) {} + + +//--------------------------------------------------------------------------------------------------------------- +void nseel_asm_sign(void) +{ + __asm__( + FUNCTION_MARKER + "li r9, 0\n" + "stw r9, -4(r1)\n" + "lis r9, 0xbf80\n" // -1 in float + "lfs f2, -4(r1)\n" + + "fcmpu cr7, f1, f2\n" + "blt- cr7, 0f\n" + "ble- cr7, 1f\n" + " lis r9, 0x3f80\n" // 1 in float + "0:\n" + " stw r9, -4(r1)\n" + " lfs f1, -4(r1)\n" + "1:\n" + FUNCTION_MARKER + :: + ); +} +void nseel_asm_sign_end(void) {} + + + +//--------------------------------------------------------------------------------------------------------------- +void nseel_asm_bnot(void) +{ + __asm__( + FUNCTION_MARKER + "cmpwi cr0, r3, 0\n" + "addis r3, 0, 0\n" + "bne cr0, 0f\n" + "addis r3, 0, 1\n" + "0:\n" + FUNCTION_MARKER + ); +} +void nseel_asm_bnot_end(void) {} + +//--------------------------------------------------------------------------------------------------------------- +void nseel_asm_if(void) +{ + __asm__( + FUNCTION_MARKER + "cmpwi cr0, r3, 0\n" + "beq cr0, 0f\n" + " addis r6, 0, 0xdead\n" + " ori r6, r6, 0xbeef\n" + " mtctr r6\n" + " bctrl\n" + "b 1f\n" + "0:\n" + " addis r6, 0, 0xdead\n" + " ori r6, r6, 0xbeef\n" + " mtctr r6\n" + " bctrl\n" + "1:\n" + FUNCTION_MARKER + :: ); +} +void nseel_asm_if_end(void) {} + +//--------------------------------------------------------------------------------------------------------------- +void nseel_asm_repeat(void) +{ +#if NSEEL_LOOPFUNC_SUPPORT_MAXLEN > 0 + __asm__( + FUNCTION_MARKER + "fctiwz f1, f1\n" + "stfd f1, -8(r1)\n" + "lwz r5, -4(r1)\n" // r5 has count now + "cmpwi cr0, r5, 0\n" + "ble cr0, 1f\n" // skip the loop + + "addis r7, 0, ha16(%0)\n" + "addi r7, r7, lo16(%0)\n" + + "stwu r16, -16(r1)\n" // set up the stack for the loop, save r16 + + "cmpw cr0, r7, r5\n" + "bge cr0, 0f\n" + "mr r5, r7\n" // set r5 to max if we have to +"0:\n" + "addis r6, 0, 0xdead\n" + "ori r6, r6, 0xbeef\n" + + "addi r5, r5, -1\n" + "stw r5, 4(r1)\n" + + "mtctr r6\n" + "bctrl\n" + + "lwz r16, 0(r1)\n" + "lwz r5, 4(r1)\n" + + "cmpwi cr0, r5, 0\n" + "bgt cr0, 0b\n" + + "addi r1, r1, 16\n" // restore old stack + + "1:\n" + FUNCTION_MARKER + ::"g" (NSEEL_LOOPFUNC_SUPPORT_MAXLEN) + ); +#else + __asm__( + FUNCTION_MARKER + "fctiwz f1, f1\n" + "stfd f1, -8(r1)\n" + "lwz r5, -4(r1)\n" // r5 has count now + "cmpwi cr0, r5, 0\n" + "ble cr0, 1f\n" // skip the loop + + "stwu r16, -16(r1)\n" // set up the stack for the loop, save r16 + +"0:\n" + "addis r6, 0, 0xdead\n" + "ori r6, r6, 0xbeef\n" + + "addi r5, r5, -1\n" + "stw r5, 4(r1)\n" + + "mtctr r6\n" + "bctrl\n" + + "lwz r16, 0(r1)\n" + "lwz r5, 4(r1)\n" + + "cmpwi cr0, r5, 0\n" + "bgt cr0, 0b\n" + + "addi r1, r1, 16\n" // restore old stack + + "1:\n" + FUNCTION_MARKER + :: + ); +#endif +} +void nseel_asm_repeat_end(void) {} + +void nseel_asm_repeatwhile(void) +{ +#if NSEEL_LOOPFUNC_SUPPORT_MAXLEN > 0 + __asm__( + FUNCTION_MARKER + "stwu r16, -16(r1)\n" // save r16 to stack, update stack + "addis r5, 0, ha16(%0)\n" + "addi r5, r5, lo16(%0)\n" +"0:\n" + + "addis r6, 0, 0xdead\n" + "ori r6, r6, 0xbeef\n" + "stw r5, 4(r1)\n" // save maxcnt + + "mtctr r6\n" + "bctrl\n" + + "lwz r16, 0(r1)\n" // restore r16 + "lwz r5, 4(r1)\n" // restore, check maxcnt + + "cmpwi cr7, r3, 0\n" // check return value + "addi r5, r5, -1\n" + + "beq cr7, 1f\n" + + "cmpwi cr0, r5, 0\n" + "bgt cr0, 0b\n" + "1:\n" + "addi r1, r1, 16\n" // restore stack + FUNCTION_MARKER + ::"g" (NSEEL_LOOPFUNC_SUPPORT_MAXLEN) + ); +#else + __asm__( + FUNCTION_MARKER + "stwu r16, -16(r1)\n" // save r16 to stack, update stack +"0:\n" + "addis r6, 0, 0xdead\n" + "ori r6, r6, 0xbeef\n" + + "mtctr r6\n" + "bctrl\n" + + "lwz r16, 0(r1)\n" // restore r16 + + "cmpwi cr7, r3, 0\n" // check return value + "bne cr7, 0b\n" + "addi r1, r1, 16\n" // restore stack + FUNCTION_MARKER + :: + ); + +#endif +} +void nseel_asm_repeatwhile_end(void) {} + + +void nseel_asm_band(void) +{ + __asm__( + FUNCTION_MARKER + "cmpwi cr7, r3, 0\n" + "beq cr7, 0f\n" + " addis r6, 0, 0xdead\n" + " ori r6, r6, 0xbeef\n" + " mtctr r6\n" + " bctrl\n" + "0:\n" + FUNCTION_MARKER + :: ); +} +void nseel_asm_band_end(void) {} + +void nseel_asm_bor(void) +{ + __asm__( + FUNCTION_MARKER + "cmpwi cr7, r3, 0\n" + "bne cr7, 0f\n" + " addis r6, 0, 0xdead\n" + " ori r6, r6, 0xbeef\n" + " mtctr r6\n" + " bctrl\n" + "0:\n" + FUNCTION_MARKER + :: ); +} +void nseel_asm_bor_end(void) {} + +//--------------------------------------------------------------------------------------------------------------- +void nseel_asm_equal(void) +{ + __asm__( + FUNCTION_MARKER + "lfd f2, 0(r14)\n" + "fsub f1, f1, f2\n" + "fabs f1, f1\n" + "fcmpu cr7, f1, f31\n" + "addis r3, 0, 0\n" + "bge cr7, 0f\n" + "addis r3, 0, 1\n" + "0:\n" + FUNCTION_MARKER + :: + ); +} +void nseel_asm_equal_end(void) {} +//--------------------------------------------------------------------------------------------------------------- +void nseel_asm_equal_exact(void) +{ + __asm__( + FUNCTION_MARKER + "lfd f2, 0(r14)\n" + "fcmpu cr7, f1, f2\n" + "addis r3, 0, 0\n" + "bne cr7, 0f\n" + "addis r3, 0, 1\n" + "0:\n" + FUNCTION_MARKER + :: + ); +} +void nseel_asm_equal_exact_end(void) {} +// +//--------------------------------------------------------------------------------------------------------------- +void nseel_asm_notequal_exact(void) +{ + __asm__( + FUNCTION_MARKER + "lfd f2, 0(r14)\n" + "fcmpu cr7, f1, f2\n" + "addis r3, 0, 0\n" + "beq cr7, 0f\n" + "addis r3, 0, 1\n" + "0:\n" + FUNCTION_MARKER + :: + ); +} +void nseel_asm_notequal_exact_end(void) {} +// +// +// +//--------------------------------------------------------------------------------------------------------------- +void nseel_asm_notequal(void) +{ + __asm__( + FUNCTION_MARKER + "lfd f2, 0(r14)\n" + "fsub f1, f1, f2\n" + "fabs f1, f1\n" + "fcmpu cr7, f1, f31\n" + "addis r3, 0, 0\n" + "blt cr7, 0f\n" + " addis r3, 0, 1\n" + "0:\n" + FUNCTION_MARKER + :: + ); +} +void nseel_asm_notequal_end(void) {} + + +//--------------------------------------------------------------------------------------------------------------- +void nseel_asm_below(void) +{ + __asm__( + FUNCTION_MARKER + "lfd f2, 0(r14)\n" + "fcmpu cr7, f1, f2\n" + "addis r3, 0, 0\n" + "ble cr7, 0f\n" + "addis r3, 0, 1\n" + "0:\n" + FUNCTION_MARKER + :: + ); +} +void nseel_asm_below_end(void) {} + +//--------------------------------------------------------------------------------------------------------------- +void nseel_asm_beloweq(void) +{ + __asm__( + FUNCTION_MARKER + "lfd f2, 0(r14)\n" + "fcmpu cr7, f1, f2\n" + "addis r3, 0, 0\n" + "blt cr7, 0f\n" + " addis r3, 0, 1\n" + "0:\n" + FUNCTION_MARKER + :: + ); +} +void nseel_asm_beloweq_end(void) {} + + +//--------------------------------------------------------------------------------------------------------------- +void nseel_asm_above(void) +{ + __asm__( + FUNCTION_MARKER + "lfd f2, 0(r14)\n" + "fcmpu cr7, f1, f2\n" + "addis r3, 0, 0\n" + "bge cr7, 0f\n" + "addis r3, 0, 1\n" + "0:\n" + FUNCTION_MARKER + :: + ); +} +void nseel_asm_above_end(void) {} + +void nseel_asm_aboveeq(void) +{ + __asm__( + FUNCTION_MARKER + "lfd f2, 0(r14)\n" + "fcmpu cr7, f1, f2\n" + "addis r3, 0, 0\n" + "bgt cr7, 0f\n" + "addis r3, 0, 1\n" + "0:\n" + FUNCTION_MARKER + :: + ); +} +void nseel_asm_aboveeq_end(void) {} + + + +void nseel_asm_min(void) +{ + __asm__( + FUNCTION_MARKER + "lfd f1, 0(r3)\n" + "lfd f2, 0(r14)\n" + "fcmpu cr7, f2, f1\n" + "bgt cr7, 0f\n" + "mr r3, r14\n" + "0:\n" + FUNCTION_MARKER + ); +} +void nseel_asm_min_end(void) {} + +void nseel_asm_max(void) +{ + __asm__( + FUNCTION_MARKER + "lfd f1, 0(r3)\n" + "lfd f2, 0(r14)\n" + "fcmpu cr7, f2, f1\n" + "blt cr7, 0f\n" + "mr r3, r14\n" + "0:\n" + FUNCTION_MARKER + ); +} + +void nseel_asm_max_end(void) {} + + +void nseel_asm_min_fp(void) +{ + __asm__( + FUNCTION_MARKER + "lfd f2, 0(r14)\n" + "fcmpu cr7, f2, f1\n" + "bgt cr7, 0f\n" + "fmr f1, f2\n" + "0:\n" + FUNCTION_MARKER + ); +} +void nseel_asm_min_fp_end(void) {} + +void nseel_asm_max_fp(void) +{ + __asm__( + FUNCTION_MARKER + "lfd f2, 0(r14)\n" + "fcmpu cr7, f2, f1\n" + "blt cr7, 0f\n" + "fmr f1, f2\n" + "0:\n" + FUNCTION_MARKER + ); +} + +void nseel_asm_max_fp_end(void) {} + + + + + + +void _asm_generic3parm(void) +{ + __asm__( + FUNCTION_MARKER + "mr r6, r3\n" + "addis r3, 0, 0xdead\n" + "ori r3, r3, 0xbeef\n" + "addis r7, 0, 0xdead\n" + "ori r7, r7, 0xbeef\n" + "mr r4, r15\n" + "mr r5, r14\n" + "mtctr r7\n" + "subi r1, r1, 64\n" + "bctrl\n" + "addi r1, r1, 64\n" + FUNCTION_MARKER + :: + ); +} +void _asm_generic3parm_end(void) {} + +void _asm_generic3parm_retd(void) +{ + __asm__( + FUNCTION_MARKER + "mr r6, r3\n" + "addis r3, 0, 0xdead\n" + "ori r3, r3, 0xbeef\n" + "addis r7, 0, 0xdead\n" + "ori r7, r7, 0xbeef\n" + "mr r4, r15\n" + "mr r5, r14\n" + "mtctr r7\n" + "subi r1, r1, 64\n" + "bctrl\n" + "addi r1, r1, 64\n" + FUNCTION_MARKER + :: + ); +} +void _asm_generic3parm_retd_end(void) {} + + +void _asm_generic2parm(void) // this prob neds to be fixed for ppc +{ + __asm__( + FUNCTION_MARKER + "mr r5, r3\n" + "addis r3, 0, 0xdead\n" + "ori r3, r3, 0xbeef\n" + "addis r7, 0, 0xdead\n" + "ori r7, r7, 0xbeef\n" + "mr r4, r14\n" + "mtctr r7\n" + "subi r1, r1, 64\n" + "bctrl\n" + "addi r1, r1, 64\n" + FUNCTION_MARKER + :: + ); +} +void _asm_generic2parm_end(void) {} + + +void _asm_generic2parm_retd(void) +{ + __asm__( + FUNCTION_MARKER + "mr r5, r3\n" + "addis r3, 0, 0xdead\n" + "ori r3, r3, 0xbeef\n" + "addis r7, 0, 0xdead\n" + "ori r7, r7, 0xbeef\n" + "mr r4, r14\n" + "mtctr r7\n" + "subi r1, r1, 64\n" + "bctrl\n" + "addi r1, r1, 64\n" + FUNCTION_MARKER + :: + ); +} +void _asm_generic2parm_retd_end(void) {} + +void _asm_generic1parm(void) // this prob neds to be fixed for ppc +{ + __asm__( + FUNCTION_MARKER + "mr r4, r3\n" + "addis r3, 0, 0xdead\n" + "ori r3, r3, 0xbeef\n" + "addis r7, 0, 0xdead\n" + "ori r7, r7, 0xbeef\n" + "mtctr r7\n" + "subi r1, r1, 64\n" + "bctrl\n" + "addi r1, r1, 64\n" + FUNCTION_MARKER + :: + ); +} +void _asm_generic1parm_end(void) {} + + + +void _asm_generic1parm_retd(void) +{ + __asm__( + FUNCTION_MARKER + "mr r4, r3\n" + "addis r3, 0, 0xdead\n" + "ori r3, r3, 0xbeef\n" + "addis r7, 0, 0xdead\n" + "ori r7, r7, 0xbeef\n" + "mtctr r7\n" + "subi r1, r1, 64\n" + "bctrl\n" + "addi r1, r1, 64\n" + FUNCTION_MARKER + :: + ); +} +void _asm_generic1parm_retd_end(void) {} + + + + +void _asm_megabuf(void) +{ + __asm__( + FUNCTION_MARKER + "lfd f2, -8(r13)\n" + "mr r3, r13\n" + + "fadd f1, f2, f1\n" + + // f1 has (float) index of array, r3 has EEL_F ** + "fctiwz f1, f1\n" + "stfd f1, -8(r1)\n" + "lwz r4, -4(r1)\n" // r4 is index of array + + "andis. r15, r4, %0\n" // check to see if it has any bits in 0xFF800000, which is 0xFFFFFFFF - (NSEEL_RAM_BLOCKS*NSEEL_RAM_ITEMSPERBLOCK - 1) + "bne cr0, 0f\n" // out of range, jump to error + + // shr 14 (16 for NSEEL_RAM_ITEMSPERBLOCK, minus two for pointer size), which is rotate 18 + // mask 7 bits (NSEEL_RAM_BLOCKS), but leave two empty bits (pointer size) + "rlwinm r15, r4, %1, %2, 29\n" + "lwzx r15, r3, r15\n" // r15 = (r3+r15) + "cmpi cr0, r15, 0\n" + "bne cr0, 1f\n" // if nonzero, jump to final calculation + + "0:\n" + // set up function call + "addis r7, 0, 0xdead\n" + "ori r7, r7, 0xbeef\n" + "mtctr r7\n" + "subi r1, r1, 64\n" + "bctrl\n" + "addi r1, r1, 64\n" + "b 2f\n" + "1:\n" + // good news: we can do a direct addr return + // bad news: more rlwinm ugliness! + // shift left by 3 (sizeof(EEL_F)), mask off lower 3 bits, only allow 16 bits (NSEEL_RAM_ITEMSPERBLOCK) through + "rlwinm r3, r4, 3, %3, 28\n" + + // add offset of loaded block + "add r3, r3, r15\n" + + "2:\n" + FUNCTION_MARKER + :: + "i" ((0xFFFFFFFF - (NSEEL_RAM_BLOCKS*NSEEL_RAM_ITEMSPERBLOCK - 1))>>16), + "i" (32 - NSEEL_RAM_ITEMSPERBLOCK_LOG2 + 2), + "i" (30 - NSEEL_RAM_BLOCKS_LOG2), + "i" (28 - NSEEL_RAM_ITEMSPERBLOCK_LOG2 + 1) + ); +} + +void _asm_megabuf_end(void) {} + +void _asm_gmegabuf(void) +{ + __asm__( + FUNCTION_MARKER + "fadd f1, f31, f1\n" + "addis r3, 0, 0xdead\n" // set up context pointer + "ori r3, r3, 0xbeef\n" + + "fctiwz f1, f1\n" + "subi r1, r1, 64\n" + + "addis r7, 0, 0xdead\n" + "ori r7, r7, 0xbeef\n" + + "stfd f1, 8(r1)\n" + "mtctr r7\n" + + "lwz r4, 12(r1)\n" + + "bctrl\n" + "addi r1, r1, 64\n" + FUNCTION_MARKER + :: + ); +} + +void _asm_gmegabuf_end(void) {} + +void nseel_asm_fcall(void) +{ + __asm__( + FUNCTION_MARKER + "addis r6, 0, 0xdead\n" + "ori r6, r6, 0xbeef\n" + "mtctr r6\n" + "bctrl\n" + FUNCTION_MARKER + ); +} +void nseel_asm_fcall_end(void) {} + + + +void nseel_asm_stack_push(void) +{ + __asm__( + FUNCTION_MARKER + + "addis r6, 0, 0xdead\n" + "ori r6, r6, 0xbeef\n" // r6 is stack + + "lfd f1, 0(r3)\n" // f1 is value to copy to stack + "lwz r3, 0(r6)\n" + + "addis r14, 0, 0xdead\n" + "ori r14, r14, 0xbeef\n" + "addi r3, r3, 0x8\n" + + "and r3, r3, r14\n" + + "addis r14, 0, 0xdead\n" + "ori r14, r14, 0xbeef\n" + "or r3, r3, r14\n" + + "stfd f1, 0(r3)\n" // copy parameter to stack + + "stw r3, 0(r6)\n" // update stack state + FUNCTION_MARKER + ); +} +void nseel_asm_stack_push_end(void) {} + +void nseel_asm_stack_pop(void) +{ + __asm__( + FUNCTION_MARKER + "addis r6, 0, 0xdead\n" + "ori r6, r6, 0xbeef\n" // r6 is stack + "lwz r15, 0(r6)\n" // return the old stack pointer + + "lfd f1, 0(r15)\n" + "subi r15, r15, 0x8\n" + + "addis r14, 0, 0xdead\n" + "ori r14, r14, 0xbeef\n" + "and r15, r15, r14\n" + + "addis r14, 0, 0xdead\n" + "ori r14, r14, 0xbeef\n" + "or r15, r15, r14\n" + "stw r15, 0(r6)\n" + + "stfd f1, 0(r3)\n" + FUNCTION_MARKER + ); +} +void nseel_asm_stack_pop_end(void) {} + + + +void nseel_asm_stack_pop_fast(void) +{ + __asm__( + FUNCTION_MARKER + "addis r6, 0, 0xdead\n" + "ori r6, r6, 0xbeef\n" // r6 is stack + "lwz r3, 0(r6)\n" // return the old stack pointer + + "mr r15, r3\n" // update stack pointer + "subi r15, r15, 0x8\n" + + "addis r14, 0, 0xdead\n" + "ori r14, r14, 0xbeef\n" + "and r15, r15, r14\n" + + "addis r14, 0, 0xdead\n" + "ori r14, r14, 0xbeef\n" + "or r15, r15, r14\n" + "stw r15, 0(r6)\n" + FUNCTION_MARKER + ); +} +void nseel_asm_stack_pop_fast_end(void) {} + +void nseel_asm_stack_peek(void) +{ + __asm__( + FUNCTION_MARKER + "fctiwz f1, f1\n" + "stfd f1, -8(r1)\n" + + "addis r6, 0, 0xdead\n" + "ori r6, r6, 0xbeef\n" // r6 is stack + + "lwz r14, -4(r1)\n" + "rlwinm r14, r14, 3, 0, 28\n" // slwi r14, r14, 3 -- 3 is log2(sizeof(EEL_F)) -- 28 represents 31-3 + "lwz r3, 0(r6)\n" // return the old stack pointer + + "sub r3, r3, r14\n" + + "addis r14, 0, 0xdead\n" + "ori r14, r14, 0xbeef\n" + "and r3, r3, r14\n" + + "addis r14, 0, 0xdead\n" + "ori r14, r14, 0xbeef\n" + "or r3, r3, r14\n" + FUNCTION_MARKER + ); +} +void nseel_asm_stack_peek_end(void) {} + + +void nseel_asm_stack_peek_top(void) +{ + __asm__( + FUNCTION_MARKER + "addis r6, 0, 0xdead\n" + "ori r6, r6, 0xbeef\n" // r6 is stack + "lwz r3, 0(r6)\n" // return the old stack pointer + FUNCTION_MARKER + ); +} +void nseel_asm_stack_peek_top_end(void) {} + + +void nseel_asm_stack_peek_int(void) +{ + __asm__( + FUNCTION_MARKER + "addis r6, 0, 0xdead\n" + "ori r6, r6, 0xbeef\n" // r6 is stack + "lwz r3, 0(r6)\n" // return the old stack pointer + + "addis r14, 0, 0xdead\n" // add manual offset + "ori r14, r14, 0xbeef\n" + "sub r3, r3, r14\n" + + "addis r14, 0, 0xdead\n" + "ori r14, r14, 0xbeef\n" + "and r3, r3, r14\n" + + "addis r14, 0, 0xdead\n" + "ori r14, r14, 0xbeef\n" + "or r3, r3, r14\n" + FUNCTION_MARKER + ); +} +void nseel_asm_stack_peek_int_end(void) {} + +void nseel_asm_stack_exch(void) +{ + __asm__( + FUNCTION_MARKER + "addis r6, 0, 0xdead\n" + "ori r6, r6, 0xbeef\n" // r6 is stack + "lfd f1, 0(r3)\n" + "lwz r14, 0(r6)\n" + "lfd f2, 0(r14)\n" + + "stfd f1, 0(r14)\n" + "stfd f2, 0(r3)\n" + FUNCTION_MARKER + ); +} +void nseel_asm_stack_exch_end(void) {} + + +void nseel_asm_booltofp(void) +{ + __asm__( + FUNCTION_MARKER + "cmpwi cr7, r3, 0\n" + "li r14, 0\n" + "beq cr7, 0f\n" + "addis r14, 0, 0x3f80\n" + "0:\n" + "stw r14, -8(r1)\n" + "lfs f1, -8(r1)\n" + FUNCTION_MARKER + ); +} +void nseel_asm_booltofp_end(void){ } + +void nseel_asm_fptobool(void) +{ + __asm__( + FUNCTION_MARKER + "fabs f1, f1\n" + "fcmpu cr7, f1, f31\n" + "addis r3, 0, 1\n" + "bge cr7, 0f\n" + " addis r3, 0, 0\n" + "0:\n" + FUNCTION_MARKER + :: + ); +} +void nseel_asm_fptobool_end(void){ } + +void nseel_asm_fptobool_rev(void) +{ + __asm__( + FUNCTION_MARKER + "fabs f1, f1\n" + "fcmpu cr7, f1, f31\n" + "addis r3, 0, 0\n" + "bge cr7, 0f\n" + " addis r3, 0, 1\n" + "0:\n" + FUNCTION_MARKER + :: + ); +} +void nseel_asm_fptobool_rev_end(void){ } + diff --git a/Src/ns-eel2/asm-nseel-x64-macho.o b/Src/ns-eel2/asm-nseel-x64-macho.o Binary files differnew file mode 100644 index 00000000..7a871393 --- /dev/null +++ b/Src/ns-eel2/asm-nseel-x64-macho.o diff --git a/Src/ns-eel2/asm-nseel-x86-gcc.c b/Src/ns-eel2/asm-nseel-x86-gcc.c new file mode 100644 index 00000000..5c3d747e --- /dev/null +++ b/Src/ns-eel2/asm-nseel-x86-gcc.c @@ -0,0 +1,2153 @@ +/* note: only EEL_F_SIZE=8 is now supported (no float EEL_F's) */ + +#ifndef AMD64ABI +#define X64_EXTRA_STACK_SPACE 32 // win32 requires allocating space for 4 parameters at 8 bytes each, even though we pass via register +#endif + +void nseel_asm_1pdd(void) +{ + __asm__( + + FUNCTION_MARKER + + "movl $0xfefefefe, %edi\n" +#ifdef TARGET_X64 + "fstpl (%rsi)\n" + "movq (%rsi), %xmm0\n" + #ifdef AMD64ABI + "movl %rsi, %r15\n" + "call *%edi\n" + "movl %r15, %rsi\n" + #else + "subl X64_EXTRA_STACK_SPACE, %rsp\n" + "call *%edi\n" + "addl X64_EXTRA_STACK_SPACE, %rsp\n" + #endif + "movq xmm0, (%rsi)\n" + "fldl (%rsi)\n" +#else + "subl $16, %esp\n" + "fstpl (%esp)\n" + "call *%edi\n" + "addl $16, %esp\n" +#endif + + FUNCTION_MARKER + + ); +} +void nseel_asm_1pdd_end(void){} + +void nseel_asm_2pdd(void) +{ + __asm__( + FUNCTION_MARKER + + "movl $0xfefefefe, %edi\n" +#ifdef TARGET_X64 + "fstpl 8(%rsi)\n" + "fstpl (%rsi)\n" + "movq 8(%rsi), %xmm1\n" + "movq (%rsi), %xmm0\n" + #ifdef AMD64ABI + "movl %rsi, %r15\n" + "call *%edi\n" + "movl %r15, %rsi\n" + #else + "subl X64_EXTRA_STACK_SPACE, %rsp\n" + "call *%edi\n" + "addl X64_EXTRA_STACK_SPACE, %rsp\n" + #endif + "movq xmm0, (%rsi)\n" + "fldl (%rsi)\n" +#else + "subl $16, %esp\n" + "fstpl 8(%esp)\n" + "fstpl (%esp)\n" + "call *%edi\n" + "addl $16, %esp\n" +#endif + + FUNCTION_MARKER + ); +} +void nseel_asm_2pdd_end(void){} + +void nseel_asm_2pdds(void) +{ + __asm__( + FUNCTION_MARKER + + "movl $0xfefefefe, %eax\n" +#ifdef TARGET_X64 + "fstpl (%rsi)\n" + "movq (%rdi), %xmm0\n" + "movq (%rsi), %xmm1\n" + #ifdef AMD64ABI + "movl %rsi, %r15\n" + "movl %rdi, %r14\n" + "call *%eax\n" + "movl %r14, %rdi\n" /* restore thrashed rdi */ + "movl %r15, %rsi\n" + "movl %r14, %rax\n" /* set return value */ + "movq xmm0, (%r14)\n" + #else + "subl X64_EXTRA_STACK_SPACE, %rsp\n" + "call *%eax\n" + "movq xmm0, (%edi)\n" + "movl %edi, %eax\n" /* set return value */ + "addl X64_EXTRA_STACK_SPACE, %rsp\n" + #endif +#else + "subl $8, %esp\n" + "fstpl (%esp)\n" + "pushl 4(%edi)\n" /* push parameter */ + "pushl (%edi)\n" /* push the rest of the parameter */ + "call *%eax\n" + "addl $16, %esp\n" + "fstpl (%edi)\n" /* store result */ + "movl %edi, %eax\n" /* set return value */ +#endif + + // denormal-fix result (this is only currently used for pow_op, so we want this!) + "movl 4(%edi), %edx\n" + "addl $0x00100000, %edx\n" + "andl $0x7FF00000, %edx\n" + "cmpl $0x00200000, %edx\n" + "jg 0f\n" + "subl %edx, %edx\n" +#ifdef TARGET_X64 + "movll %rdx, (%rdi)\n" +#else + "movl %edx, (%edi)\n" + "movl %edx, 4(%edi)\n" +#endif + "0:\n" + + FUNCTION_MARKER + + ); +} +void nseel_asm_2pdds_end(void){} + + + +//--------------------------------------------------------------------------------------------------------------- + + +// do nothing, eh +void nseel_asm_exec2(void) +{ + __asm__( + FUNCTION_MARKER + "" + FUNCTION_MARKER + ); +} +void nseel_asm_exec2_end(void) { } + + + +void nseel_asm_invsqrt(void) +{ + __asm__( + FUNCTION_MARKER + "movl $0x5f3759df, %edx\n" + "fsts (%esi)\n" +#ifdef TARGET_X64 + "movl 0xfefefefe, %rax\n" + "fmul" EEL_F_SUFFIX " (%rax)\n" + "movsxl (%esi), %rcx\n" +#else + "fmul" EEL_F_SUFFIX " (0xfefefefe)\n" + "movl (%esi), %ecx\n" +#endif + "sarl $1, %ecx\n" + "subl %ecx, %edx\n" + "movl %edx, (%esi)\n" + "fmuls (%esi)\n" + "fmuls (%esi)\n" +#ifdef TARGET_X64 + "movl 0xfefefefe, %rax\n" + "fadd" EEL_F_SUFFIX " (%rax)\n" +#else + "fadd" EEL_F_SUFFIX " (0xfefefefe)\n" +#endif + "fmuls (%esi)\n" + + FUNCTION_MARKER + ); +} +void nseel_asm_invsqrt_end(void) {} + + +void nseel_asm_dbg_getstackptr(void) +{ + __asm__( + FUNCTION_MARKER +#ifdef __clang__ + "ffree %st(0)\n" +#else + "fstpl %st(0)\n" +#endif + "movl %esp, (%esi)\n" + "fildl (%esi)\n" + + FUNCTION_MARKER + ); +} +void nseel_asm_dbg_getstackptr_end(void) {} + +//--------------------------------------------------------------------------------------------------------------- +void nseel_asm_sin(void) +{ + __asm__( + FUNCTION_MARKER + "fsin\n" + FUNCTION_MARKER + ); +} +void nseel_asm_sin_end(void) {} + +//--------------------------------------------------------------------------------------------------------------- +void nseel_asm_cos(void) +{ + __asm__( + FUNCTION_MARKER + "fcos\n" + FUNCTION_MARKER + ); +} +void nseel_asm_cos_end(void) {} + +//--------------------------------------------------------------------------------------------------------------- +void nseel_asm_tan(void) +{ + __asm__( + FUNCTION_MARKER + "fptan\n" + "fstp %st(0)\n" + FUNCTION_MARKER + ); +} +void nseel_asm_tan_end(void) {} + +//--------------------------------------------------------------------------------------------------------------- +void nseel_asm_sqr(void) +{ + __asm__( + FUNCTION_MARKER + "fmul %st(0), %st(0)\n" + FUNCTION_MARKER + ); +} +void nseel_asm_sqr_end(void) {} + +//--------------------------------------------------------------------------------------------------------------- +void nseel_asm_sqrt(void) +{ + __asm__( + FUNCTION_MARKER + "fabs\n" + "fsqrt\n" + FUNCTION_MARKER + ); +} +void nseel_asm_sqrt_end(void) {} + + +//--------------------------------------------------------------------------------------------------------------- +void nseel_asm_log(void) +{ + __asm__( + FUNCTION_MARKER + "fldln2\n" + "fxch\n" + "fyl2x\n" + FUNCTION_MARKER + ); +} +void nseel_asm_log_end(void) {} + +//--------------------------------------------------------------------------------------------------------------- +void nseel_asm_log10(void) +{ + __asm__( + FUNCTION_MARKER + "fldlg2\n" + "fxch\n" + "fyl2x\n" + + FUNCTION_MARKER + ); +} +void nseel_asm_log10_end(void) {} + +//--------------------------------------------------------------------------------------------------------------- +void nseel_asm_abs(void) +{ + __asm__( + FUNCTION_MARKER + "fabs\n" + FUNCTION_MARKER + ); +} +void nseel_asm_abs_end(void) {} + + +//--------------------------------------------------------------------------------------------------------------- +void nseel_asm_assign(void) +{ +#ifdef TARGET_X64 + + __asm__( + FUNCTION_MARKER + "movll (%rax), %rdx\n" + "movll %rdx, %rcx\n" + "shrl $32, %rdx\n" + "addl $0x00100000, %edx\n" + "andl $0x7FF00000, %edx\n" + "cmpl $0x00200000, %edx\n" + "movll %rdi, %rax\n" + "jg 0f\n" + "subl %ecx, %ecx\n" + "0:\n" + "movll %rcx, (%edi)\n" + + FUNCTION_MARKER + ); + +#else + + __asm__( + FUNCTION_MARKER + "movl (%eax), %ecx\n" + "movl 4(%eax), %edx\n" + "movl %edx, %eax\n" + "addl $0x00100000, %eax\n" // if exponent is zero, make exponent 0x7ff, if 7ff, make 7fe + "andl $0x7ff00000, %eax\n" + "cmpl $0x00200000, %eax\n" + "jg 0f\n" + "subl %ecx, %ecx\n" + "subl %edx, %edx\n" + "0:\n" + "movl %edi, %eax\n" + "movl %ecx, (%edi)\n" + "movl %edx, 4(%edi)\n" + + FUNCTION_MARKER + ); + +#endif +} +void nseel_asm_assign_end(void) {} + +//--------------------------------------------------------------------------------------------------------------- +void nseel_asm_assign_fromfp(void) +{ + __asm__( + FUNCTION_MARKER + "fstpl (%edi)\n" + "movl 4(%edi), %edx\n" + "addl $0x00100000, %edx\n" + "andl $0x7FF00000, %edx\n" + "cmpl $0x00200000, %edx\n" + "movl %edi, %eax\n" + "jg 0f\n" + "subl %edx, %edx\n" +#ifdef TARGET_X64 + "movll %rdx, (%rdi)\n" +#else + "movl %edx, (%edi)\n" + "movl %edx, 4(%edi)\n" +#endif + "0:\n" + + FUNCTION_MARKER + ); +} +void nseel_asm_assign_fromfp_end(void) {} + + +//--------------------------------------------------------------------------------------------------------------- +void nseel_asm_assign_fast_fromfp(void) +{ + __asm__( + FUNCTION_MARKER + "movl %edi, %eax\n" + "fstpl (%edi)\n" + FUNCTION_MARKER + ); +} +void nseel_asm_assign_fast_fromfp_end(void) {} + + + +//--------------------------------------------------------------------------------------------------------------- +void nseel_asm_assign_fast(void) +{ +#ifdef TARGET_X64 + + __asm__( + FUNCTION_MARKER + "movll (%rax), %rdx\n" + "movll %rdx, (%edi)\n" + "movll %rdi, %rax\n" + FUNCTION_MARKER + ); + +#else + + __asm__( + FUNCTION_MARKER + "movl (%eax), %ecx\n" + "movl %ecx, (%edi)\n" + "movl 4(%eax), %ecx\n" + + "movl %edi, %eax\n" + "movl %ecx, 4(%edi)\n" + FUNCTION_MARKER + ); + +#endif +} +void nseel_asm_assign_fast_end(void) {} + +//--------------------------------------------------------------------------------------------------------------- +void nseel_asm_add(void) +{ + __asm__( + FUNCTION_MARKER +#ifdef __clang__ + "faddp %st(1)\n" +#else + "fadd\n" +#endif + FUNCTION_MARKER + ); +} +void nseel_asm_add_end(void) {} + +void nseel_asm_add_op(void) +{ + __asm__( + FUNCTION_MARKER + "fadd" EEL_F_SUFFIX " (%edi)\n" + "movl %edi, %eax\n" + "fstp" EEL_F_SUFFIX " (%edi)\n" + + "movl 4(%edi), %edx\n" + "addl $0x00100000, %edx\n" + "andl $0x7FF00000, %edx\n" + "cmpl $0x00200000, %edx\n" + "jg 0f\n" + "subl %edx, %edx\n" +#ifdef TARGET_X64 + "movll %rdx, (%rdi)\n" +#else + "movl %edx, (%edi)\n" + "movl %edx, 4(%edi)\n" +#endif + "0:\n" + FUNCTION_MARKER + ); +} +void nseel_asm_add_op_end(void) {} + +void nseel_asm_add_op_fast(void) +{ + __asm__( + FUNCTION_MARKER + "fadd" EEL_F_SUFFIX " (%edi)\n" + "movl %edi, %eax\n" + "fstp" EEL_F_SUFFIX " (%edi)\n" + FUNCTION_MARKER + ); +} +void nseel_asm_add_op_fast_end(void) {} + + +//--------------------------------------------------------------------------------------------------------------- +void nseel_asm_sub(void) +{ + __asm__( + FUNCTION_MARKER +#ifdef __clang__ + "fsubrp %st(0), %st(1)\n" +#else + #ifdef __GNUC__ + #ifdef __INTEL_COMPILER + "fsub\n" + #else + "fsubr\n" // gnuc has fsub/fsubr backwards, ack + #endif + #else + "fsub\n" + #endif +#endif + FUNCTION_MARKER + ); +} +void nseel_asm_sub_end(void) {} + +void nseel_asm_sub_op(void) +{ + __asm__( + FUNCTION_MARKER + "fsubr" EEL_F_SUFFIX " (%edi)\n" + "movl %edi, %eax\n" + "fstp" EEL_F_SUFFIX " (%edi)\n" + + "movl 4(%edi), %edx\n" + "addl $0x00100000, %edx\n" + "andl $0x7FF00000, %edx\n" + "cmpl $0x00200000, %edx\n" + "jg 0f\n" + "subl %edx, %edx\n" +#ifdef TARGET_X64 + "movll %rdx, (%rdi)\n" +#else + "movl %edx, (%edi)\n" + "movl %edx, 4(%edi)\n" +#endif + "0:\n" + FUNCTION_MARKER + ); +} +void nseel_asm_sub_op_end(void) {} + +void nseel_asm_sub_op_fast(void) +{ + __asm__( + FUNCTION_MARKER + "fsubr" EEL_F_SUFFIX " (%edi)\n" + "movl %edi, %eax\n" + "fstp" EEL_F_SUFFIX " (%edi)\n" + FUNCTION_MARKER + ); +} +void nseel_asm_sub_op_fast_end(void) {} + +//--------------------------------------------------------------------------------------------------------------- +void nseel_asm_mul(void) +{ + __asm__( + FUNCTION_MARKER +#ifdef __clang__ + "fmulp %st(0), %st(1)\n" +#else + "fmul\n" +#endif + FUNCTION_MARKER + ); +} +void nseel_asm_mul_end(void) {} + +void nseel_asm_mul_op(void) +{ + __asm__( + FUNCTION_MARKER + "fmul" EEL_F_SUFFIX " (%edi)\n" + "movl %edi, %eax\n" + "fstp" EEL_F_SUFFIX " (%edi)\n" + + "movl 4(%edi), %edx\n" + "addl $0x00100000, %edx\n" + "andl $0x7FF00000, %edx\n" + "cmpl $0x00200000, %edx\n" + "jg 0f\n" + "subl %edx, %edx\n" +#ifdef TARGET_X64 + "movll %rdx, (%rdi)\n" +#else + "movl %edx, (%edi)\n" + "movl %edx, 4(%edi)\n" +#endif + "0:\n" + FUNCTION_MARKER + ); +} +void nseel_asm_mul_op_end(void) {} + +void nseel_asm_mul_op_fast(void) +{ + __asm__( + FUNCTION_MARKER + "fmul" EEL_F_SUFFIX " (%edi)\n" + "movl %edi, %eax\n" + "fstp" EEL_F_SUFFIX " (%edi)\n" + FUNCTION_MARKER + ); +} +void nseel_asm_mul_op_fast_end(void) {} + +//--------------------------------------------------------------------------------------------------------------- +void nseel_asm_div(void) +{ + __asm__( + FUNCTION_MARKER +#ifdef __clang__ + "fdivrp %st(1)\n" +#else + #ifdef __GNUC__ + #ifdef __INTEL_COMPILER + "fdiv\n" + #else + "fdivr\n" // gcc inline asm seems to have fdiv/fdivr backwards + #endif + #else + "fdiv\n" + #endif +#endif + FUNCTION_MARKER + ); +} +void nseel_asm_div_end(void) {} + +void nseel_asm_div_op(void) +{ + __asm__( + FUNCTION_MARKER + "fld" EEL_F_SUFFIX " (%edi)\n" +#ifdef __clang__ + "fdivp %st(1)\n" +#else + #ifndef __GNUC__ + "fdivr\n" + #else + #ifdef __INTEL_COMPILER + "fdivp %st(1)\n" + #else + "fdiv\n" + #endif + #endif +#endif + "movl %edi, %eax\n" + "fstp" EEL_F_SUFFIX " (%edi)\n" + + "movl 4(%edi), %edx\n" + "addl $0x00100000, %edx\n" + "andl $0x7FF00000, %edx\n" + "cmpl $0x00200000, %edx\n" + "jg 0f\n" + "subl %edx, %edx\n" +#ifdef TARGET_X64 + "movll %rdx, (%rdi)\n" +#else + "movl %edx, (%edi)\n" + "movl %edx, 4(%edi)\n" +#endif + "0:\n" + + FUNCTION_MARKER + ); +} +void nseel_asm_div_op_end(void) {} + +void nseel_asm_div_op_fast(void) +{ + __asm__( + FUNCTION_MARKER + "fld" EEL_F_SUFFIX " (%edi)\n" +#ifdef __clang__ + "fdivp %st(1)\n" +#else + #ifndef __GNUC__ + "fdivr\n" + #else + #ifdef __INTEL_COMPILER + "fdivp %st(1)\n" + #else + "fdiv\n" + #endif + #endif +#endif + "movl %edi, %eax\n" + "fstp" EEL_F_SUFFIX " (%edi)\n" + + FUNCTION_MARKER + ); +} +void nseel_asm_div_op_fast_end(void) {} + +//--------------------------------------------------------------------------------------------------------------- +void nseel_asm_mod(void) +{ + __asm__( + FUNCTION_MARKER + "fabs\n" + "fistpl (%esi)\n" + "fabs\n" + "fistpl 4(%esi)\n" + "xorl %edx, %edx\n" + "cmpl $0, (%esi)\n" + "je 0f\n" // skip devide, set return to 0 + "movl 4(%esi), %eax\n" + "divl (%esi)\n" + "0:\n" + "movl %edx, (%esi)\n" + "fildl (%esi)\n" + + FUNCTION_MARKER + ); +} +void nseel_asm_mod_end(void) {} + +void nseel_asm_shl(void) +{ + __asm__( + FUNCTION_MARKER + "fistpl (%esi)\n" + "fistpl 4(%esi)\n" + "movl (%esi), %ecx\n" + "movl 4(%esi), %eax\n" + "shll %cl, %eax\n" + "movl %eax, (%esi)\n" + "fildl (%esi)\n" + FUNCTION_MARKER + ); +} +void nseel_asm_shl_end(void) {} + +void nseel_asm_shr(void) +{ + __asm__( + FUNCTION_MARKER + "fistpl (%esi)\n" + "fistpl 4(%esi)\n" + "movl (%esi), %ecx\n" + "movl 4(%esi), %eax\n" + "sarl %cl, %eax\n" + "movl %eax, (%esi)\n" + "fildl (%esi)\n" + FUNCTION_MARKER + ); +} +void nseel_asm_shr_end(void) {} + + +void nseel_asm_mod_op(void) +{ + __asm__( + FUNCTION_MARKER + "fld" EEL_F_SUFFIX " (%edi)\n" + "fxch\n" + "fabs\n" + "fistpl (%edi)\n" + "fabs\n" + "fistpl (%esi)\n" + "xorl %edx, %edx\n" + "cmpl $0, (%edi)\n" + "je 0f\n" // skip devide, set return to 0 + "movl (%esi), %eax\n" + "divl (%edi)\n" + "0:\n" + "movl %edx, (%edi)\n" + "fildl (%edi)\n" + "movl %edi, %eax\n" + "fstp" EEL_F_SUFFIX " (%edi)\n" + + FUNCTION_MARKER + ); +} +void nseel_asm_mod_op_end(void) {} + +//--------------------------------------------------------------------------------------------------------------- +void nseel_asm_or(void) +{ + __asm__( + FUNCTION_MARKER + "fistpll (%esi)\n" + "fistpll 8(%esi)\n" +#ifdef TARGET_X64 + "movll 8(%rsi), %rdi\n" + "orll %rdi, (%rsi)\n" +#else + "movl 8(%esi), %edi\n" + "movl 12(%esi), %ecx\n" + "orl %edi, (%esi)\n" + "orl %ecx, 4(%esi)\n" +#endif + "fildll (%esi)\n" + + FUNCTION_MARKER + ); +} +void nseel_asm_or_end(void) {} + +void nseel_asm_or0(void) +{ + __asm__( + FUNCTION_MARKER + "fistpll (%esi)\n" + "fildll (%esi)\n" + FUNCTION_MARKER + ); +} +void nseel_asm_or0_end(void) {} + +void nseel_asm_or_op(void) +{ + __asm__( + FUNCTION_MARKER + "fld" EEL_F_SUFFIX " (%edi)\n" + "fxch\n" + "fistpll (%edi)\n" + "fistpll (%esi)\n" +#ifdef TARGET_X64 + "movll (%rsi), %rax\n" + "orll %rax, (%rdi)\n" +#else + "movl (%esi), %eax\n" + "movl 4(%esi), %ecx\n" + "orl %eax, (%edi)\n" + "orl %ecx, 4(%edi)\n" +#endif + "fildll (%edi)\n" + "movl %edi, %eax\n" + "fstp" EEL_F_SUFFIX " (%edi)\n" + + FUNCTION_MARKER + ); +} +void nseel_asm_or_op_end(void) {} + + +void nseel_asm_xor(void) +{ + __asm__( + FUNCTION_MARKER + "fistpll (%esi)\n" + "fistpll 8(%esi)\n" +#ifdef TARGET_X64 + "movll 8(%rsi), %rdi\n" + "xorll %rdi, (%rsi)\n" +#else + "movl 8(%esi), %edi\n" + "movl 12(%esi), %ecx\n" + "xorl %edi, (%esi)\n" + "xorl %ecx, 4(%esi)\n" +#endif + "fildll (%esi)\n" + + FUNCTION_MARKER + ); +} +void nseel_asm_xor_end(void) {} + +void nseel_asm_xor_op(void) +{ + __asm__( + FUNCTION_MARKER + "fld" EEL_F_SUFFIX " (%edi)\n" + "fxch\n" + "fistpll (%edi)\n" + "fistpll (%esi)\n" +#ifdef TARGET_X64 + "movll (%rsi), %rax\n" + "xorll %rax, (%rdi)\n" +#else + "movl (%esi), %eax\n" + "movl 4(%esi), %ecx\n" + "xorl %eax, (%edi)\n" + "xorl %ecx, 4(%edi)\n" +#endif + "fildll (%edi)\n" + "movl %edi, %eax\n" + "fstp" EEL_F_SUFFIX " (%edi)\n" + + FUNCTION_MARKER + ); +} +void nseel_asm_xor_op_end(void) {} + + +//--------------------------------------------------------------------------------------------------------------- +void nseel_asm_and(void) +{ + __asm__( + FUNCTION_MARKER + "fistpll (%esi)\n" + "fistpll 8(%esi)\n" +#ifdef TARGET_X64 + "movll 8(%rsi), %rdi\n" + "andll %rdi, (%rsi)\n" +#else + "movl 8(%esi), %edi\n" + "movl 12(%esi), %ecx\n" + "andl %edi, (%esi)\n" + "andl %ecx, 4(%esi)\n" +#endif + "fildll (%esi)\n" + + FUNCTION_MARKER + ); +} +void nseel_asm_and_end(void) {} + +void nseel_asm_and_op(void) +{ + __asm__( + FUNCTION_MARKER + "fld" EEL_F_SUFFIX " (%edi)\n" + "fxch\n" + "fistpll (%edi)\n" + "fistpll (%esi)\n" +#ifdef TARGET_X64 + "movll (%rsi), %rax\n" + "andll %rax, (%rdi)\n" +#else + "movl (%esi), %eax\n" + "movl 4(%esi), %ecx\n" + "andl %eax, (%edi)\n" + "andl %ecx, 4(%edi)\n" +#endif + "fildll (%edi)\n" + "movl %edi, %eax\n" + "fstp" EEL_F_SUFFIX " (%edi)\n" + + FUNCTION_MARKER + ); +} +void nseel_asm_and_op_end(void) {} + + +//--------------------------------------------------------------------------------------------------------------- +void nseel_asm_uplus(void) // this is the same as doing nothing, it seems +{ + __asm__( + FUNCTION_MARKER + "" + FUNCTION_MARKER + ); +} +void nseel_asm_uplus_end(void) {} + +//--------------------------------------------------------------------------------------------------------------- +void nseel_asm_uminus(void) +{ + __asm__( + FUNCTION_MARKER + "fchs\n" + FUNCTION_MARKER + ); +} +void nseel_asm_uminus_end(void) {} + + + +//--------------------------------------------------------------------------------------------------------------- +void nseel_asm_sign(void) +{ + __asm__( + FUNCTION_MARKER + +#ifdef TARGET_X64 + + + "fst" EEL_F_SUFFIX " (%rsi)\n" + "mov" EEL_F_SUFFIX " (%rsi), %rdx\n" + "movll $0x7FFFFFFFFFFFFFFF, %rcx\n" + "testll %rcx, %rdx\n" + "jz 0f\n" // zero zero, return the value passed directly + // calculate sign + "incll %rcx\n" // rcx becomes 0x80000... + "fstp %st(0)\n" + "fld1\n" + "testl %rcx, %rdx\n" + "jz 0f\n" + "fchs\n" + "0:\n" + +#else + + "fsts (%esi)\n" + "movl (%esi), %ecx\n" + "movl $0x7FFFFFFF, %edx\n" + "testl %edx, %ecx\n" + "jz 0f\n" // zero zero, return the value passed directly + // calculate sign + "incl %edx\n" // edx becomes 0x8000... + "fstp %st(0)\n" + "fld1\n" + "testl %edx, %ecx\n" + "jz 0f\n" + "fchs\n" + "0:\n" + +#endif + FUNCTION_MARKER +); +} +void nseel_asm_sign_end(void) {} + + + +//--------------------------------------------------------------------------------------------------------------- +void nseel_asm_bnot(void) +{ + __asm__( + FUNCTION_MARKER + "testl %eax, %eax\n" + "setz %al\n" + "andl $0xff, %eax\n" + FUNCTION_MARKER + ); +} +void nseel_asm_bnot_end(void) {} + +//--------------------------------------------------------------------------------------------------------------- +void nseel_asm_fcall(void) +{ + __asm__( + FUNCTION_MARKER + "movl $0xfefefefe, %edx\n" +#ifdef TARGET_X64 + "subl $8, %esp\n" + "call *%edx\n" + "addl $8, %esp\n" +#else + "subl $12, %esp\n" /* keep stack 16 byte aligned, 4 bytes for return address */ + "call *%edx\n" + "addl $12, %esp\n" +#endif + FUNCTION_MARKER + ); +} +void nseel_asm_fcall_end(void) {} + +void nseel_asm_band(void) +{ + __asm__( + FUNCTION_MARKER + "testl %eax, %eax\n" + "jz 0f\n" + + "movl $0xfefefefe, %ecx\n" +#ifdef TARGET_X64 + "subl $8, %rsp\n" +#else + "subl $12, %esp\n" +#endif + "call *%ecx\n" +#ifdef TARGET_X64 + "addl $8, %rsp\n" +#else + "addl $12, %esp\n" +#endif + "0:\n" + FUNCTION_MARKER + ); +} +void nseel_asm_band_end(void) {} + +void nseel_asm_bor(void) +{ + __asm__( + FUNCTION_MARKER + "testl %eax, %eax\n" + "jnz 0f\n" + + "movl $0xfefefefe, %ecx\n" +#ifdef TARGET_X64 + "subl $8, %rsp\n" +#else + "subl $12, %esp\n" +#endif + "call *%ecx\n" +#ifdef TARGET_X64 + "addl $8, %rsp\n" +#else + "addl $12, %esp\n" +#endif + "0:\n" + FUNCTION_MARKER + ); +} +void nseel_asm_bor_end(void) {} + +//--------------------------------------------------------------------------------------------------------------- +void nseel_asm_equal(void) +{ + __asm__( + FUNCTION_MARKER +#ifdef __clang__ + "fsubp %st(1)\n" +#else + "fsub\n" +#endif + + "fabs\n" +#ifdef TARGET_X64 + "fcomp" EEL_F_SUFFIX " -8(%r12)\n" //[g_closefact] +#else + "fcomp" EEL_F_SUFFIX " -8(%ebx)\n" //[g_closefact] +#endif + "fstsw %ax\n" + "andl $256, %eax\n" // old behavior: if 256 set, true (NaN means true) + + FUNCTION_MARKER + ); +} +void nseel_asm_equal_end(void) {} +// +//--------------------------------------------------------------------------------------------------------------- +void nseel_asm_equal_exact(void) +{ + __asm__( + FUNCTION_MARKER + "fcompp\n" + "fstsw %ax\n" // for equal 256 and 1024 should be clear, 16384 should be set + "andl $17664, %eax\n" // mask C4/C3/C1, bits 8/10/14, 16384|256|1024 -- if equals 16384, then equality + "cmp $16384, %eax\n" + "je 0f\n" + "subl %eax, %eax\n" + "0:\n" + FUNCTION_MARKER + ); +} +void nseel_asm_equal_exact_end(void) {} + +void nseel_asm_notequal_exact(void) +{ + __asm__( + FUNCTION_MARKER + "fcompp\n" + "fstsw %ax\n" // for equal 256 and 1024 should be clear, 16384 should be set + "andl $17664, %eax\n" // mask C4/C3/C1, bits 8/10/14, 16384|256|1024 -- if equals 16384, then equality + "cmp $16384, %eax\n" + "je 0f\n" + "subl %eax, %eax\n" + "0:\n" + "xorl $16384, %eax\n" // flip the result + FUNCTION_MARKER + ); +} +void nseel_asm_notequal_exact_end(void) {} +// +//--------------------------------------------------------------------------------------------------------------- +void nseel_asm_notequal(void) +{ + __asm__( + FUNCTION_MARKER +#ifdef __clang__ + "fsubp %st(1)\n" +#else + "fsub\n" +#endif + + "fabs\n" +#ifdef TARGET_X64 + "fcomp" EEL_F_SUFFIX " -8(%r12)\n" //[g_closefact] +#else + "fcomp" EEL_F_SUFFIX " -8(%ebx)\n" //[g_closefact] +#endif + "fstsw %ax\n" + "andl $256, %eax\n" + "xorl $256, %eax\n" // old behavior: if 256 set, FALSE (NaN makes for false) + FUNCTION_MARKER + ); +} +void nseel_asm_notequal_end(void) {} + + +//--------------------------------------------------------------------------------------------------------------- +void nseel_asm_above(void) +{ + __asm__( + FUNCTION_MARKER + "fcompp\n" + "fstsw %ax\n" + "andl $1280, %eax\n" // (1024+256) old behavior: NaN would mean 1, preserve that + FUNCTION_MARKER + ); +} +void nseel_asm_above_end(void) {} + +//--------------------------------------------------------------------------------------------------------------- +void nseel_asm_beloweq(void) +{ + __asm__( + FUNCTION_MARKER + "fcompp\n" + "fstsw %ax\n" + "andl $256, %eax\n" // old behavior: NaN would be 0 (ugh) + "xorl $256, %eax\n" + FUNCTION_MARKER + ); +} +void nseel_asm_beloweq_end(void) {} + + +void nseel_asm_booltofp(void) +{ + __asm__( + FUNCTION_MARKER + "testl %eax, %eax\n" + "jz 0f\n" + "fld1\n" + "jmp 1f\n" + "0:\n" + "fldz\n" + "1:\n" + FUNCTION_MARKER + ); +} +void nseel_asm_booltofp_end(void) {} + +void nseel_asm_fptobool(void) +{ + __asm__( + FUNCTION_MARKER + "fabs\n" +#ifdef TARGET_X64 + "fcomp" EEL_F_SUFFIX " -8(%r12)\n" //[g_closefact] +#else + "fcomp" EEL_F_SUFFIX " -8(%ebx)\n" //[g_closefact] +#endif + "fstsw %ax\n" + "andl $256, %eax\n" + "xorl $256, %eax\n" + FUNCTION_MARKER + ); +} +void nseel_asm_fptobool_end(void) {} + +void nseel_asm_fptobool_rev(void) +{ + __asm__( + FUNCTION_MARKER + "fabs\n" +#ifdef TARGET_X64 + "fcomp" EEL_F_SUFFIX " -8(%r12)\n" //[g_closefact] +#else + "fcomp" EEL_F_SUFFIX " -8(%ebx)\n" //[g_closefact] +#endif + "fstsw %ax\n" + "andl $256, %eax\n" + FUNCTION_MARKER + ); +} +void nseel_asm_fptobool_rev_end(void) {} + +void nseel_asm_min(void) +{ + __asm__( + FUNCTION_MARKER + "fld" EEL_F_SUFFIX " (%edi)\n" + "fcomp" EEL_F_SUFFIX " (%eax)\n" + "movl %eax, %ecx\n" + "fstsw %ax\n" + "testl $256, %eax\n" + "movl %ecx, %eax\n" + "jz 0f\n" + "movl %edi, %eax\n" + "0:\n" + FUNCTION_MARKER + ); + +} +void nseel_asm_min_end(void) {} + +void nseel_asm_max(void) +{ + __asm__( + FUNCTION_MARKER + "fld" EEL_F_SUFFIX " (%edi)\n" + "fcomp" EEL_F_SUFFIX " (%eax)\n" + "movl %eax, %ecx\n" + "fstsw %ax\n" + "testl $256, %eax\n" + "movl %ecx, %eax\n" + "jnz 0f\n" + "movl %edi, %eax\n" + "0:\n" + FUNCTION_MARKER + ); +} +void nseel_asm_max_end(void) {} + + + +void nseel_asm_min_fp(void) +{ + __asm__( + FUNCTION_MARKER + "fcom\n" + "fstsw %ax\n" + "testl $256, %eax\n" + "jz 0f\n" + "fxch\n" + "0:\n" + "fstp %st(0)\n" + FUNCTION_MARKER + ); + +} +void nseel_asm_min_fp_end(void) {} + +void nseel_asm_max_fp(void) +{ + __asm__( + FUNCTION_MARKER + "fcom\n" + "fstsw %ax\n" + "testl $256, %eax\n" + "jnz 0f\n" + "fxch\n" + "0:\n" + "fstp %st(0)\n" + FUNCTION_MARKER + ); +} +void nseel_asm_max_fp_end(void) {} + + + +// just generic functions left, yay + + + + +void _asm_generic3parm(void) +{ + __asm__( + FUNCTION_MARKER +#ifdef TARGET_X64 + +#ifdef AMD64ABI + + "movl %rsi, %r15\n" + "movl %rdi, %rdx\n" // third parameter = parm + "movl $0xfefefefe, %rdi\n" // first parameter= context + + "movl %ecx, %rsi\n" // second parameter = parm + "movl %rax, %rcx\n" // fourth parameter = parm + "movl $0xfefefefe, %rax\n" // call function + "call *%rax\n" + + "movl %r15, %rsi\n" +#else + "movl %ecx, %edx\n" // second parameter = parm + "movl $0xfefefefe, %ecx\n" // first parameter= context + "movl %rdi, %r8\n" // third parameter = parm + "movl %rax, %r9\n" // fourth parameter = parm + "movl $0xfefefefe, %edi\n" // call function + "subl X64_EXTRA_STACK_SPACE, %rsp\n" + "call *%edi\n" + "addl X64_EXTRA_STACK_SPACE, %rsp\n" +#endif + +#else + + "movl $0xfefefefe, %edx\n" + "pushl %eax\n" // push parameter + "pushl %edi\n" // push parameter + "movl $0xfefefefe, %edi\n" + "pushl %ecx\n" // push parameter + "pushl %edx\n" // push context pointer + "call *%edi\n" + "addl $16, %esp\n" + +#endif + FUNCTION_MARKER + ); +} +void _asm_generic3parm_end(void) {} + + +void _asm_generic3parm_retd(void) +{ + __asm__( + FUNCTION_MARKER +#ifdef TARGET_X64 +#ifdef AMD64ABI + "movl %rsi, %r15\n" + "movl %rdi, %rdx\n" // third parameter = parm + "movl $0xfefefefe, %rdi\n" // first parameter= context + "movl %ecx, %rsi\n" // second parameter = parm + "movl %rax, %rcx\n" // fourth parameter = parm + "movl $0xfefefefe, %rax\n" // call function + "call *%rax\n" + "movl %r15, %rsi\n" + "movq xmm0, (%r15)\n" + "fldl (%r15)\n" +#else + "movl %ecx, %edx\n" // second parameter = parm + "movl $0xfefefefe, %ecx\n" // first parameter= context + "movl %rdi, %r8\n" // third parameter = parm + "movl %rax, %r9\n" // fourth parameter = parm + "movl $0xfefefefe, %edi\n" // call function + "subl X64_EXTRA_STACK_SPACE, %rsp\n" + "call *%edi\n" + "addl X64_EXTRA_STACK_SPACE, %rsp\n" + "movq xmm0, (%rsi)\n" + "fldl (%rsi)\n" +#endif +#else + + "subl $16, %esp\n" + "movl $0xfefefefe, %edx\n" + "movl %edi, 8(%esp)\n" + "movl $0xfefefefe, %edi\n" + "movl %eax, 12(%esp)\n" + "movl %ecx, 4(%esp)\n" + "movl %edx, (%esp)\n" + "call *%edi\n" + "addl $16, %esp\n" + +#endif + FUNCTION_MARKER + ); +} +void _asm_generic3parm_retd_end(void) {} + + +void _asm_generic2parm(void) // this prob neds to be fixed for ppc +{ + __asm__( + FUNCTION_MARKER +#ifdef TARGET_X64 + +#ifdef AMD64ABI + "movl %rsi, %r15\n" + "movl %edi, %esi\n" // second parameter = parm + "movl $0xfefefefe, %edi\n" // first parameter= context + "movl %rax, %rdx\n" // third parameter = parm + "movl $0xfefefefe, %rcx\n" // call function + "call *%rcx\n" + "movl %r15, %rsi\n" +#else + "movl $0xfefefefe, %ecx\n" // first parameter= context + "movl %edi, %edx\n" // second parameter = parm + "movl %rax, %r8\n" // third parameter = parm + "movl $0xfefefefe, %edi\n" // call function + "subl X64_EXTRA_STACK_SPACE, %rsp\n" + "call *%edi\n" + "addl X64_EXTRA_STACK_SPACE, %rsp\n" +#endif +#else + + "movl $0xfefefefe, %edx\n" + "movl $0xfefefefe, %ecx\n" + "subl $4, %esp\n" // keep stack aligned + "pushl %eax\n" // push parameter + "pushl %edi\n" // push parameter + "pushl %edx\n" // push context pointer + "call *%ecx\n" + "addl $16, %esp\n" + +#endif + FUNCTION_MARKER + ); +} +void _asm_generic2parm_end(void) {} + + +void _asm_generic2parm_retd(void) +{ + __asm__( + FUNCTION_MARKER +#ifdef TARGET_X64 +#ifdef AMD64ABI + "movl %rsi, %r15\n" + "movl %rdi, %rsi\n" // second parameter = parm + "movl $0xfefefefe, %rdi\n" // first parameter= context + "movl $0xfefefefe, %rcx\n" // call function + "movl %rax, %rdx\n" // third parameter = parm + "call *%rcx\n" + "movl %r15, %rsi\n" + "movq xmm0, (%r15)\n" + "fldl (%r15)\n" +#else + "movl %rdi, %rdx\n" // second parameter = parm + "movl $0xfefefefe, %rcx\n" // first parameter= context + "movl $0xfefefefe, %rdi\n" // call function + "movl %rax, %r8\n" // third parameter = parm + "subl X64_EXTRA_STACK_SPACE, %rsp\n" + "call *%edi\n" + "addl X64_EXTRA_STACK_SPACE, %rsp\n" + "movq xmm0, (%rsi)\n" + "fldl (%rsi)\n" +#endif +#else + + "subl $16, %esp\n" + "movl $0xfefefefe, %edx\n" + "movl $0xfefefefe, %ecx\n" + "movl %edx, (%esp)\n" + "movl %edi, 4(%esp)\n" + "movl %eax, 8(%esp)\n" + "call *%ecx\n" + "addl $16, %esp\n" + +#endif + FUNCTION_MARKER + ); +} +void _asm_generic2parm_retd_end(void) {} + + + + + +void _asm_generic1parm(void) +{ + __asm__( + FUNCTION_MARKER +#ifdef TARGET_X64 +#ifdef AMD64ABI + "movl $0xfefefefe, %rdi\n" // first parameter= context + "movl %rsi, %r15\n" + "movl %eax, %rsi\n" // second parameter = parm + "movl $0xfefefefe, %rcx\n" // call function + "call *%rcx\n" + "movl %r15, %rsi\n" +#else + "movl $0xfefefefe, %ecx\n" // first parameter= context + "movl %eax, %edx\n" // second parameter = parm + "movl $0xfefefefe, %edi\n" // call function + "subl X64_EXTRA_STACK_SPACE, %rsp\n" + "call *%edi\n" + "addl X64_EXTRA_STACK_SPACE, %rsp\n" +#endif +#else + + "movl $0xfefefefe, %edx\n" + "subl $8, %esp\n" // keep stack aligned + "movl $0xfefefefe, %ecx\n" + "pushl %eax\n" // push parameter + "pushl %edx\n" // push context pointer + "call *%ecx\n" + "addl $16, %esp\n" + +#endif + + FUNCTION_MARKER + ); +} +void _asm_generic1parm_end(void) {} + + +void _asm_generic1parm_retd(void) // 1 parameter returning double +{ + __asm__( + FUNCTION_MARKER +#ifdef TARGET_X64 +#ifdef AMD64ABI + "movl $0xfefefefe, %rdi\n" // first parameter = context pointer + "movl $0xfefefefe, %rcx\n" // function address + "movl %rsi, %r15\n" // save rsi + "movl %rax, %rsi\n" // second parameter = parameter + + "call *%rcx\n" + + "movl %r15, %rsi\n" + "movq xmm0, (%r15)\n" + "fldl (%r15)\n" +#else + "movl $0xfefefefe, %ecx\n" // first parameter= context + "movl $0xfefefefe, %edi\n" // call function + + "movl %rax, %rdx\n" // second parameter = parm + + "subl X64_EXTRA_STACK_SPACE, %rsp\n" + "call *%edi\n" + "addl X64_EXTRA_STACK_SPACE, %rsp\n" + "movq xmm0, (%rsi)\n" + "fldl (%rsi)\n" +#endif +#else + + "movl $0xfefefefe, %edx\n" // context pointer + "movl $0xfefefefe, %ecx\n" // func-addr + "subl $16, %esp\n" + "movl %eax, 4(%esp)\n" // push parameter + "movl %edx, (%esp)\n" // push context pointer + "call *%ecx\n" + "addl $16, %esp\n" + +#endif + FUNCTION_MARKER + ); +} +void _asm_generic1parm_retd_end(void) {} + + + + + +// this gets its own stub because it's pretty crucial for performance :/ + +void _asm_megabuf(void) +{ + __asm__( + + FUNCTION_MARKER + +#ifdef TARGET_X64 + + +#ifdef AMD64ABI + + "fadd" EEL_F_SUFFIX " -8(%r12)\n" + + "fistpl (%rsi)\n" + + // check if (%rsi) is in range, and buffer available, otherwise call function + "movl (%rsi), %edx\n" + "cmpl %1, %rdx\n" //REPLACE=((NSEEL_RAM_BLOCKS*NSEEL_RAM_ITEMSPERBLOCK)) + "jae 0f\n" + "movll %rdx, %rax\n" + "shrll %2, %rax\n" //REPLACE=(NSEEL_RAM_ITEMSPERBLOCK_LOG2 - 3/*log2(sizeof(void *))*/ ) + "andll %3, %rax\n" //REPLACE=((NSEEL_RAM_BLOCKS-1)*8 /*sizeof(void*)*/ ) + "movll (%r12, %rax), %rax\n" + "testl %rax, %rax\n" + "jnz 1f\n" + "0:\n" + "movl $0xfefefefe, %rax\n" + "movl %r12, %rdi\n" // set first parm to ctx + "movl %rsi, %r15\n" // save rsi + "movl %rdx, %esi\n" // esi becomes second parameter (edi is first, context pointer) + "call *%rax\n" + "movl %r15, %rsi\n" // restore rsi + "jmp 2f\n" + "1:\n" + "andll %4, %rdx\n" //REPLACE=(NSEEL_RAM_ITEMSPERBLOCK-1) + "shlll $3, %rdx\n" // 3 is log2(sizeof(EEL_F)) + "addll %rdx, %rax\n" + "2:\n" + +#else + + "fadd" EEL_F_SUFFIX " -8(%r12)\n" + + "fistpl (%rsi)\n" + + // check if (%rsi) is in range... + "movl (%rsi), %edi\n" + "cmpl %1, %edi\n" //REPLACE=((NSEEL_RAM_BLOCKS*NSEEL_RAM_ITEMSPERBLOCK)) + "jae 0f\n" + "movll %rdi, %rax\n" + "shrll %2, %rax\n" //REPLACE=(NSEEL_RAM_ITEMSPERBLOCK_LOG2 - 3/*log2(sizeof(void *))*/ ) + "andll %3, %rax\n" //REPLACE=((NSEEL_RAM_BLOCKS-1)*8 /*sizeof(void*)*/ ) + "movll (%r12, %rax), %rax\n" + "testl %rax, %rax\n" + "jnz 1f\n" + "0:\n" + "movl $0xfefefefe, %rax\n" // function ptr + "movl %r12, %rcx\n" // set first parm to ctx + "movl %rdi, %rdx\n" // rdx is second parameter (rcx is first) + "subl X64_EXTRA_STACK_SPACE, %rsp\n" + "call *%rax\n" + "addl X64_EXTRA_STACK_SPACE, %rsp\n" + "jmp 2f\n" + "1:\n" + "andll %4, %rdi\n" //REPLACE=(NSEEL_RAM_ITEMSPERBLOCK-1) + "shlll $3, %rdi\n" // 3 is log2(sizeof(EEL_F)) + "addll %rdi, %rax\n" + "2:\n" +#endif + + + FUNCTION_MARKER +#else + "fadd" EEL_F_SUFFIX " -8(%%ebx)\n" + "fistpl (%%esi)\n" + + // check if (%esi) is in range, and buffer available, otherwise call function + "movl (%%esi), %%edi\n" + "cmpl %0, %%edi\n" //REPLACE=((NSEEL_RAM_BLOCKS*NSEEL_RAM_ITEMSPERBLOCK)) + "jae 0f\n" + + "movl %%edi, %%eax\n" + "shrl %1, %%eax\n" //REPLACE=(NSEEL_RAM_ITEMSPERBLOCK_LOG2 - 2/*log2(sizeof(void *))*/ ) + "andl %2, %%eax\n" //REPLACE=((NSEEL_RAM_BLOCKS-1)*4 /*sizeof(void*)*/ ) + "movl (%%ebx, %%eax), %%eax\n" + "testl %%eax, %%eax\n" + "jnz 1f\n" + "0:\n" + "subl $8, %%esp\n" // keep stack aligned + "movl $0xfefefefe, %%ecx\n" + "pushl %%edi\n" // parameter + "pushl %%ebx\n" // push context pointer + "call *%%ecx\n" + "addl $16, %%esp\n" + "jmp 2f\n" + "1:\n" + "andl %3, %%edi\n" //REPLACE=(NSEEL_RAM_ITEMSPERBLOCK-1) + "shll $3, %%edi\n" // 3 is log2(sizeof(EEL_F)) + "addl %%edi, %%eax\n" + "2:" + FUNCTION_MARKER + + #ifndef _MSC_VER + :: "i" (((NSEEL_RAM_BLOCKS*NSEEL_RAM_ITEMSPERBLOCK))), + "i" ((NSEEL_RAM_ITEMSPERBLOCK_LOG2 - 2/*log2(sizeof(void *))*/ )), + "i" (((NSEEL_RAM_BLOCKS-1)*4 /*sizeof(void*)*/ )), + "i" ((NSEEL_RAM_ITEMSPERBLOCK-1 )) + #endif + + + +#endif + + ); +} + +void _asm_megabuf_end(void) {} + + +void _asm_gmegabuf(void) +{ + __asm__( + + FUNCTION_MARKER + +#ifdef TARGET_X64 + + +#ifdef AMD64ABI + + "movl %rsi, %r15\n" + "fadd" EEL_F_SUFFIX " -8(%r12)\n" + "movl $0xfefefefe, %rdi\n" // first parameter = context pointer + "fistpl (%rsi)\n" + "movl $0xfefefefe, %edx\n" + "movl (%rsi), %esi\n" + "call *%rdx\n" + "movl %r15, %rsi\n" + +#else + "fadd" EEL_F_SUFFIX " -8(%r12)\n" + "movl $0xfefefefe, %rcx\n" // first parameter = context pointer + "fistpl (%rsi)\n" + "movl $0xfefefefe, %rdi\n" + "movl (%rsi), %edx\n" + "subl X64_EXTRA_STACK_SPACE, %rsp\n" + "call *%rdi\n" + "addl X64_EXTRA_STACK_SPACE, %rsp\n" +#endif + + +#else + "subl $16, %esp\n" // keep stack aligned + "movl $0xfefefefe, (%esp)\n" + "fadd" EEL_F_SUFFIX " -8(%ebx)\n" + "movl $0xfefefefe, %edi\n" + "fistpl 4(%esp)\n" + "call *%edi\n" + "addl $16, %esp\n" + +#endif + + + + FUNCTION_MARKER + ); +} + +void _asm_gmegabuf_end(void) {} + +void nseel_asm_stack_push(void) +{ +#ifdef TARGET_X64 + __asm__( + FUNCTION_MARKER + "movl $0xfefefefe, %rdi\n" + "movll (%rax), %rcx\n" + "movll (%rdi), %rax\n" + "addll $8, %rax\n" + "movl $0xFEFEFEFE, %rdx\n" + "andll %rdx, %rax\n" + "movl $0xFEFEFEFE, %rdx\n" + "orll %rdx, %rax\n" + "movll %rcx, (%rax)\n" + "movll %rax, (%rdi)\n" + FUNCTION_MARKER + ); +#else + + __asm__( + FUNCTION_MARKER + "movl $0xfefefefe, %edi\n" + + "movl (%eax), %ecx\n" + "movl 4(%eax), %edx\n" + + "movl (%edi), %eax\n" + + "addl $8, %eax\n" + "andl $0xfefefefe, %eax\n" + "orl $0xfefefefe, %eax\n" + + "movl %ecx, (%eax)\n" + "movl %edx, 4(%eax)\n" + + "movl %eax, (%edi)\n" + FUNCTION_MARKER + ); + +#endif + +} +void nseel_asm_stack_push_end(void) {} + + + +void nseel_asm_stack_pop(void) +{ +#ifdef TARGET_X64 + + __asm__( + FUNCTION_MARKER + "movl $0xfefefefe, %rdi\n" + "movll (%rdi), %rcx\n" + "movq (%rcx), %xmm0\n" + "subll $8, %rcx\n" + "movl $0xFEFEFEFE, %rdx\n" + "andll %rdx, %rcx\n" + "movl $0xFEFEFEFE, %rdx\n" + "orll %rdx, %rcx\n" + "movll %rcx, (%rdi)\n" + "movq %xmm0, (%eax)\n" + FUNCTION_MARKER + ); + +#else + + __asm__( + FUNCTION_MARKER + "movl $0xfefefefe, %edi\n" + "movl (%edi), %ecx\n" + "fld" EEL_F_SUFFIX " (%ecx)\n" + "subl $8, %ecx\n" + "andl $0xfefefefe, %ecx\n" + "orl $0xfefefefe, %ecx\n" + "movl %ecx, (%edi)\n" + "fstp" EEL_F_SUFFIX " (%eax)\n" + FUNCTION_MARKER + ); + +#endif +} +void nseel_asm_stack_pop_end(void) {} + + +void nseel_asm_stack_pop_fast(void) +{ +#ifdef TARGET_X64 + + __asm__( + FUNCTION_MARKER + "movl $0xfefefefe, %rdi\n" + "movll (%rdi), %rcx\n" + "movll %rcx, %rax\n" + "subll $8, %rcx\n" + "movl $0xFEFEFEFE, %rdx\n" + "andll %rdx, %rcx\n" + "movl $0xFEFEFEFE, %rdx\n" + "orll %rdx, %rcx\n" + "movll %rcx, (%rdi)\n" + FUNCTION_MARKER + ); + +#else + + __asm__( + FUNCTION_MARKER + "movl $0xfefefefe, %edi\n" + "movl (%edi), %ecx\n" + "movl %ecx, %eax\n" + "subl $8, %ecx\n" + "andl $0xfefefefe, %ecx\n" + "orl $0xfefefefe, %ecx\n" + "movl %ecx, (%edi)\n" + FUNCTION_MARKER + ); + +#endif +} +void nseel_asm_stack_pop_fast_end(void) {} + +void nseel_asm_stack_peek_int(void) +{ +#ifdef TARGET_X64 + + __asm__( + FUNCTION_MARKER + "movll $0xfefefefe, %rdi\n" + "movll (%rdi), %rax\n" + "movl $0xfefefefe, %rdx\n" + "subll %rdx, %rax\n" + "movl $0xFEFEFEFE, %rdx\n" + "andll %rdx, %rax\n" + "movl $0xFEFEFEFE, %rdx\n" + "orll %rdx, %rax\n" + FUNCTION_MARKER + ); + +#else + + __asm__( + FUNCTION_MARKER + "movl $0xfefefefe, %edi\n" + "movl (%edi), %eax\n" + "movl $0xfefefefe, %edx\n" + "subl %edx, %eax\n" + "andl $0xfefefefe, %eax\n" + "orl $0xfefefefe, %eax\n" + FUNCTION_MARKER + ); + +#endif + +} +void nseel_asm_stack_peek_int_end(void) {} + + + +void nseel_asm_stack_peek(void) +{ +#ifdef TARGET_X64 + + __asm__( + FUNCTION_MARKER + "movll $0xfefefefe, %rdi\n" + "fistpl (%rsi)\n" + "movll (%rdi), %rax\n" + "movll (%rsi), %rdx\n" + "shll $3, %rdx\n" // log2(sizeof(EEL_F)) + "subl %rdx, %rax\n" + "movl $0xFEFEFEFE, %rdx\n" + "andll %rdx, %rax\n" + "movl $0xFEFEFEFE, %rdx\n" + "orll %rdx, %rax\n" + FUNCTION_MARKER + ); + +#else + + __asm__( + FUNCTION_MARKER + "movl $0xfefefefe, %edi\n" + "fistpl (%esi)\n" + "movl (%edi), %eax\n" + "movl (%esi), %edx\n" + "shll $3, %edx\n" // log2(sizeof(EEL_F)) + "subl %edx, %eax\n" + "andl $0xfefefefe, %eax\n" + "orl $0xfefefefe, %eax\n" + FUNCTION_MARKER + ); + +#endif + +} +void nseel_asm_stack_peek_end(void) {} + + +void nseel_asm_stack_peek_top(void) +{ +#ifdef TARGET_X64 + + __asm__( + FUNCTION_MARKER + "movll $0xfefefefe, %rdi\n" + "movll (%rdi), %rax\n" + FUNCTION_MARKER + ); + +#else + + __asm__( + FUNCTION_MARKER + "movl $0xfefefefe, %edi\n" + "movl (%edi), %eax\n" + FUNCTION_MARKER + ); + +#endif + +} +void nseel_asm_stack_peek_top_end(void) {} + +void nseel_asm_stack_exch(void) +{ +#ifdef TARGET_X64 + + __asm__( + FUNCTION_MARKER + "movll $0xfefefefe, %rdi\n" + "movll (%rdi), %rcx\n" + "movq (%rcx), %xmm0\n" + "movq (%rax), %xmm1\n" + "movq %xmm0, (%rax)\n" + "movq %xmm1, (%rcx)\n" + FUNCTION_MARKER + ); + +#else + + __asm__( + FUNCTION_MARKER + "movl $0xfefefefe, %edi\n" + "movl (%edi), %ecx\n" + "fld" EEL_F_SUFFIX " (%ecx)\n" + "fld" EEL_F_SUFFIX " (%eax)\n" + "fstp" EEL_F_SUFFIX " (%ecx)\n" + "fstp" EEL_F_SUFFIX " (%eax)\n" + FUNCTION_MARKER + ); + +#endif + +} +void nseel_asm_stack_exch_end(void) {} + +#ifdef TARGET_X64 +void eel_callcode64() +{ + __asm__( +#ifndef EEL_X64_NO_CHANGE_FPFLAGS + "subl $16, %rsp\n" + "fnstcw (%rsp)\n" + "mov (%rsp), %ax\n" + "or $0xE3F, %ax\n" // 53 or 64 bit precision, trunc, and masking all exceptions + "mov %ax, 4(%rsp)\n" + "fldcw 4(%rsp)\n" +#endif + "push %rbx\n" + "push %rbp\n" + "push %r12\n" + "push %r13\n" + "push %r14\n" + "push %r15\n" + +#ifdef AMD64ABI + "movll %rsi, %r12\n" // second parameter is ram-blocks pointer + "call %rdi\n" +#else + "push %rdi\n" + "push %rsi\n" + "movll %rdx, %r12\n" // second parameter is ram-blocks pointer + "call %rcx\n" + "pop %rsi\n" + "pop %rdi\n" +#endif + + "fclex\n" + + "pop %r15\n" + "pop %r14\n" + "pop %r13\n" + "pop %r12\n" + "pop %rbp\n" + "pop %rbx\n" + +#ifndef EEL_X64_NO_CHANGE_FPFLAGS + "fldcw (%rsp)\n" + "addl $16, %rsp\n" +#endif + + "ret\n" + ); +} + +void eel_callcode64_fast() +{ + __asm__( + "push %rbx\n" + "push %rbp\n" + "push %r12\n" + "push %r13\n" + "push %r14\n" + "push %r15\n" + +#ifdef AMD64ABI + "movll %rsi, %r12\n" // second parameter is ram-blocks pointer + "call %rdi\n" +#else + "push %rdi\n" + "push %rsi\n" + "movll %rdx, %r12\n" // second parameter is ram-blocks pointer + "call %rcx\n" + "pop %rsi\n" + "pop %rdi\n" +#endif + + "pop %r15\n" + "pop %r14\n" + "pop %r13\n" + "pop %r12\n" + "pop %rbp\n" + "pop %rbx\n" + + "ret\n" + ); +} + +void eel_setfp_round() +{ + __asm__( +#ifndef EEL_X64_NO_CHANGE_FPFLAGS + "subl $16, %rsp\n" + "fnstcw (%rsp)\n" + "mov (%rsp), %ax\n" + "and $0xF3FF, %ax\n" // set round to nearest + "mov %ax, 4(%rsp)\n" + "fldcw 4(%rsp)\n" + "addl $16, %rsp\n" +#endif + "ret\n" + ); +} + +void eel_setfp_trunc() +{ + __asm__( +#ifndef EEL_X64_NO_CHANGE_FPFLAGS + "subl $16, %rsp\n" + "fnstcw (%rsp)\n" + "mov (%rsp), %ax\n" + "or $0xC00, %ax\n" // set to truncate + "mov %ax, 4(%rsp)\n" + "fldcw 4(%rsp)\n" + "addl $16, %rsp\n" +#endif + "ret\n" + ); +} + +void eel_enterfp(int s[2]) +{ + __asm__( +#ifdef AMD64ABI + "fnstcw (%rdi)\n" + "mov (%rdi), %ax\n" + "or $0xE3F, %ax\n" // 53 or 64 bit precision, trunc, and masking all exceptions + "mov %ax, 4(%rdi)\n" + "fldcw 4(%rdi)\n" +#else + "fnstcw (%rcx)\n" + "mov (%rcx), %ax\n" + "or $0xE3F, %ax\n" // 53 or 64 bit precision, trunc, and masking all exceptions + "mov %ax, 4(%rcx)\n" + "fldcw 4(%rcx)\n" +#endif + "ret\n" + ); +} +void eel_leavefp(int s[2]) +{ + __asm__( +#ifdef AMD64ABI + "fldcw (%rdi)\n" +#else + "fldcw (%rcx)\n" +#endif + "ret\n"; + ); +} + +#endif diff --git a/Src/ns-eel2/asm-nseel-x86-msvc.c b/Src/ns-eel2/asm-nseel-x86-msvc.c new file mode 100644 index 00000000..02476f48 --- /dev/null +++ b/Src/ns-eel2/asm-nseel-x86-msvc.c @@ -0,0 +1,4101 @@ +// THIS FILE AUTOGENERATED FROM asm-nseel-x86-gcc.c by a2i.php + +#if EEL_F_SIZE == 8 + #define EEL_ASM_TYPE qword ptr +#else + #define EEL_ASM_TYPE dword ptr +#endif + +/* note: only EEL_F_SIZE=8 is now supported (no float EEL_F's) */ + +#ifndef AMD64ABI +#define X64_EXTRA_STACK_SPACE 32 // win32 requires allocating space for 4 parameters at 8 bytes each, even though we pass via register +#endif + +__declspec(naked) void nseel_asm_1pdd(void) +{ + __asm { + +_emit 0x89; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; + + mov edi, 0xfefefefe; +#ifdef TARGET_X64 + fstp qword ptr [rsi]; + movq xmm0, [rsi]; + #ifdef AMD64ABI + mov r15, rsi; + call edi; + mov rsi, r15; + #else + sub rsp, X64_EXTRA_STACK_SPACE; + call edi; + add rsp, X64_EXTRA_STACK_SPACE; + #endif + movq [rsi], xmm0; + fld qword ptr [rsi]; +#else + sub esp, 16; + fstp qword ptr [esp]; + call edi; + add esp, 16; +#endif + +_emit 0x89; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; + + } +} +__declspec(naked) void nseel_asm_1pdd_end(void){} + +__declspec(naked) void nseel_asm_2pdd(void) +{ + __asm { +_emit 0x89; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; + + mov edi, 0xfefefefe; +#ifdef TARGET_X64 + fstp qword ptr [rsi+8]; + fstp qword ptr [rsi]; + movq xmm1, [rsi+8]; + movq xmm0, [rsi]; + #ifdef AMD64ABI + mov r15, rsi; + call edi; + mov rsi, r15; + #else + sub rsp, X64_EXTRA_STACK_SPACE; + call edi; + add rsp, X64_EXTRA_STACK_SPACE; + #endif + movq [rsi], xmm0; + fld qword ptr [rsi]; +#else + sub esp, 16; + fstp qword ptr [esp+8]; + fstp qword ptr [esp]; + call edi; + add esp, 16; +#endif + +_emit 0x89; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; + } +} +__declspec(naked) void nseel_asm_2pdd_end(void){} + +__declspec(naked) void nseel_asm_2pdds(void) +{ + __asm { +_emit 0x89; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; + + mov eax, 0xfefefefe; +#ifdef TARGET_X64 + fstp qword ptr [rsi]; + movq xmm0, [rdi]; + movq xmm1, [rsi]; + #ifdef AMD64ABI + mov r15, rsi; + mov r14, rdi; + call eax; + mov rdi, r14; /* restore thrashed rdi */ + mov rsi, r15; + mov rax, r14; /* set return value */ + movq [r14], xmm0; + #else + sub rsp, X64_EXTRA_STACK_SPACE; + call eax; + movq [edi], xmm0; + mov eax, edi; /* set return value */ + add rsp, X64_EXTRA_STACK_SPACE; + #endif +#else + sub esp, 8; + fstp qword ptr [esp]; + push dword ptr [edi+4]; /* push parameter */ + push dword ptr [edi]; /* push the rest of the parameter */ + call eax; + add esp, 16; + fstp qword ptr [edi]; /* store result */ + mov eax, edi; /* set return value */ +#endif + + // denormal-fix result (this is only currently used for pow_op, so we want this!) + mov edx, dword ptr [edi+4]; + add edx, 0x00100000; + and edx, 0x7FF00000; + cmp edx, 0x00100000; + jg label_0; + sub edx, edx; +#ifdef TARGET_X64 + mov qword ptr [rdi], rdx; +#else + mov dword ptr [edi], edx; + mov dword ptr [edi+4], edx; +#endif +label_0: + + +_emit 0x89; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; + + } +} +__declspec(naked) void nseel_asm_2pdds_end(void){} + + + +//--------------------------------------------------------------------------------------------------------------- + + +// do nothing, eh +__declspec(naked) void nseel_asm_exec2(void) +{ + __asm { +_emit 0x89; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; + +_emit 0x89; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; + } +} +__declspec(naked) void nseel_asm_exec2_end(void) { } + + + +__declspec(naked) void nseel_asm_invsqrt(void) +{ + __asm { +_emit 0x89; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; + mov edx, 0x5f3759df; + fst dword ptr [esi]; +#ifdef TARGET_X64 + mov rax, 0xfefefefe; + fmul EEL_ASM_TYPE [rax]; + movsx rcx, dword ptr [esi]; +#else +#if EEL_F_SIZE == 8 +_emit 0xDC; // fmul qword ptr [0xfefefefe] +_emit 0x0D; +_emit 0xFE; +_emit 0xFE; +_emit 0xFE; +_emit 0xFE; +#else +_emit 0xD8; // fmul dword ptr [0xfefefefe] +_emit 0x0D; +_emit 0xFE; +_emit 0xFE; +_emit 0xFE; +_emit 0xFE; +#endif + mov ecx, dword ptr [esi]; +#endif + sar ecx, 1; + sub edx, ecx; + mov dword ptr [esi], edx; + fmul dword ptr [esi]; + fmul dword ptr [esi]; +#ifdef TARGET_X64 + mov rax, 0xfefefefe; + fadd EEL_ASM_TYPE [rax]; +#else +#if EEL_F_SIZE == 8 +_emit 0xDC; // fadd qword ptr [0xfefefefe] +_emit 0x05; +_emit 0xFE; +_emit 0xFE; +_emit 0xFE; +_emit 0xFE; +#else +_emit 0xD8; // fadd dword ptr [0xfefefefe] +_emit 0x05; +_emit 0xFE; +_emit 0xFE; +_emit 0xFE; +_emit 0xFE; +#endif +#endif + fmul dword ptr [esi]; + +_emit 0x89; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; + } +} +__declspec(naked) void nseel_asm_invsqrt_end(void) {} + + +__declspec(naked) void nseel_asm_dbg_getstackptr(void) +{ + __asm { +_emit 0x89; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +#ifdef __clang__ + ffree st(0); +#else + fstp st(0); +#endif + mov dword ptr [esi], esp; + fild dword ptr [esi]; + +_emit 0x89; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; + } +} +__declspec(naked) void nseel_asm_dbg_getstackptr_end(void) {} + +//--------------------------------------------------------------------------------------------------------------- +__declspec(naked) void nseel_asm_sin(void) +{ + __asm { +_emit 0x89; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; + fsin; +_emit 0x89; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; + } +} +__declspec(naked) void nseel_asm_sin_end(void) {} + +//--------------------------------------------------------------------------------------------------------------- +__declspec(naked) void nseel_asm_cos(void) +{ + __asm { +_emit 0x89; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; + fcos; +_emit 0x89; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; + } +} +__declspec(naked) void nseel_asm_cos_end(void) {} + +//--------------------------------------------------------------------------------------------------------------- +__declspec(naked) void nseel_asm_tan(void) +{ + __asm { +_emit 0x89; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; + fptan; + fstp st(0); +_emit 0x89; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; + } +} +__declspec(naked) void nseel_asm_tan_end(void) {} + +//--------------------------------------------------------------------------------------------------------------- +__declspec(naked) void nseel_asm_sqr(void) +{ + __asm { +_emit 0x89; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; + fmul st(0), st(0); +_emit 0x89; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; + } +} +__declspec(naked) void nseel_asm_sqr_end(void) {} + +//--------------------------------------------------------------------------------------------------------------- +__declspec(naked) void nseel_asm_sqrt(void) +{ + __asm { +_emit 0x89; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; + fabs; + fsqrt; +_emit 0x89; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; + } +} +__declspec(naked) void nseel_asm_sqrt_end(void) {} + + +//--------------------------------------------------------------------------------------------------------------- +__declspec(naked) void nseel_asm_log(void) +{ + __asm { +_emit 0x89; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; + fldln2; + fxch; + fyl2x; +_emit 0x89; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; + } +} +__declspec(naked) void nseel_asm_log_end(void) {} + +//--------------------------------------------------------------------------------------------------------------- +__declspec(naked) void nseel_asm_log10(void) +{ + __asm { +_emit 0x89; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; + fldlg2; + fxch; + fyl2x; + +_emit 0x89; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; + } +} +__declspec(naked) void nseel_asm_log10_end(void) {} + +//--------------------------------------------------------------------------------------------------------------- +__declspec(naked) void nseel_asm_abs(void) +{ + __asm { +_emit 0x89; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; + fabs; +_emit 0x89; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; + } +} +__declspec(naked) void nseel_asm_abs_end(void) {} + + +//--------------------------------------------------------------------------------------------------------------- +__declspec(naked) void nseel_asm_assign(void) +{ +#ifdef TARGET_X64 + + __asm { +_emit 0x89; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; + mov rdx, qword ptr [rax]; + mov rcx, rdx; + shr rdx, 32; + add edx, 0x00100000; + and edx, 0x7FF00000; + cmp edx, 0x00100000; + mov rax, rdi; + jg label_1; + sub ecx, ecx; +label_1: + + mov qword ptr [edi], rcx; + +_emit 0x89; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; + } + +#else + + __asm { +_emit 0x89; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; + mov ecx, dword ptr [eax]; + mov edx, dword ptr [eax+4]; + mov eax, edx; + add eax, 0x00100000; // if exponent is zero, make exponent 0x7ff, if 7ff, make 7fe + and eax, 0x7ff00000; + cmp eax, 0x00100000; + jg label_2; + sub ecx, ecx; + sub edx, edx; +label_2: + + mov eax, edi; + mov dword ptr [edi], ecx; + mov dword ptr [edi+4], edx; + +_emit 0x89; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; + } + +#endif +} +__declspec(naked) void nseel_asm_assign_end(void) {} + +//--------------------------------------------------------------------------------------------------------------- +__declspec(naked) void nseel_asm_assign_fromfp(void) +{ + __asm { +_emit 0x89; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; + fstp qword ptr [edi]; + mov edx, dword ptr [edi+4]; + add edx, 0x00100000; + and edx, 0x7FF00000; + cmp edx, 0x00100000; + mov eax, edi; + jg label_3; + sub edx, edx; +#ifdef TARGET_X64 + mov qword ptr [rdi], rdx; +#else + mov dword ptr [edi], edx; + mov dword ptr [edi+4], edx; +#endif +label_3: + + +_emit 0x89; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; + } +} +__declspec(naked) void nseel_asm_assign_fromfp_end(void) {} + + +//--------------------------------------------------------------------------------------------------------------- +__declspec(naked) void nseel_asm_assign_fast_fromfp(void) +{ + __asm { +_emit 0x89; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; + mov eax, edi; + fstp qword ptr [edi]; +_emit 0x89; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; + } +} +__declspec(naked) void nseel_asm_assign_fast_fromfp_end(void) {} + + + +//--------------------------------------------------------------------------------------------------------------- +__declspec(naked) void nseel_asm_assign_fast(void) +{ +#ifdef TARGET_X64 + + __asm { +_emit 0x89; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; + mov rdx, qword ptr [rax]; + mov qword ptr [edi], rdx; + mov rax, rdi; +_emit 0x89; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; + } + +#else + + __asm { +_emit 0x89; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; + mov ecx, dword ptr [eax]; + mov dword ptr [edi], ecx; + mov ecx, dword ptr [eax+4]; + + mov eax, edi; + mov dword ptr [edi+4], ecx; +_emit 0x89; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; + } + +#endif +} +__declspec(naked) void nseel_asm_assign_fast_end(void) {} + +//--------------------------------------------------------------------------------------------------------------- +__declspec(naked) void nseel_asm_add(void) +{ + __asm { +_emit 0x89; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +#ifdef __clang__ + faddp st(1); +#else + fadd; +#endif +_emit 0x89; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; + } +} +__declspec(naked) void nseel_asm_add_end(void) {} + +__declspec(naked) void nseel_asm_add_op(void) +{ + __asm { +_emit 0x89; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; + fadd EEL_ASM_TYPE [edi]; + mov eax, edi; + fstp EEL_ASM_TYPE [edi]; + + mov edx, dword ptr [edi+4]; + add edx, 0x00100000; + and edx, 0x7FF00000; + cmp edx, 0x00100000; + jg label_4; + sub edx, edx; +#ifdef TARGET_X64 + mov qword ptr [rdi], rdx; +#else + mov dword ptr [edi], edx; + mov dword ptr [edi+4], edx; +#endif +label_4: + +_emit 0x89; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; + } +} +__declspec(naked) void nseel_asm_add_op_end(void) {} + +__declspec(naked) void nseel_asm_add_op_fast(void) +{ + __asm { +_emit 0x89; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; + fadd EEL_ASM_TYPE [edi]; + mov eax, edi; + fstp EEL_ASM_TYPE [edi]; +_emit 0x89; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; + } +} +__declspec(naked) void nseel_asm_add_op_fast_end(void) {} + + +//--------------------------------------------------------------------------------------------------------------- +__declspec(naked) void nseel_asm_sub(void) +{ + __asm { +_emit 0x89; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +#ifdef __clang__ + fsubrp st(1), st(0); +#else + #ifdef __GNUC__ + #ifdef __INTEL_COMPILER + fsub; + #else + fsubr; // gnuc has fsub/fsubr backwards, ack + #endif + #else + fsub; + #endif +#endif +_emit 0x89; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; + } +} +__declspec(naked) void nseel_asm_sub_end(void) {} + +__declspec(naked) void nseel_asm_sub_op(void) +{ + __asm { +_emit 0x89; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; + fsubr EEL_ASM_TYPE [edi]; + mov eax, edi; + fstp EEL_ASM_TYPE [edi]; + + mov edx, dword ptr [edi+4]; + add edx, 0x00100000; + and edx, 0x7FF00000; + cmp edx, 0x00100000; + jg label_5; + sub edx, edx; +#ifdef TARGET_X64 + mov qword ptr [rdi], rdx; +#else + mov dword ptr [edi], edx; + mov dword ptr [edi+4], edx; +#endif +label_5: + +_emit 0x89; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; + } +} +__declspec(naked) void nseel_asm_sub_op_end(void) {} + +__declspec(naked) void nseel_asm_sub_op_fast(void) +{ + __asm { +_emit 0x89; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; + fsubr EEL_ASM_TYPE [edi]; + mov eax, edi; + fstp EEL_ASM_TYPE [edi]; +_emit 0x89; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; + } +} +__declspec(naked) void nseel_asm_sub_op_fast_end(void) {} + +//--------------------------------------------------------------------------------------------------------------- +__declspec(naked) void nseel_asm_mul(void) +{ + __asm { +_emit 0x89; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +#ifdef __clang__ + fmulp st(1), st(0); +#else + fmul; +#endif +_emit 0x89; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; + } +} +__declspec(naked) void nseel_asm_mul_end(void) {} + +__declspec(naked) void nseel_asm_mul_op(void) +{ + __asm { +_emit 0x89; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; + fmul EEL_ASM_TYPE [edi]; + mov eax, edi; + fstp EEL_ASM_TYPE [edi]; + + mov edx, dword ptr [edi+4]; + add edx, 0x00100000; + and edx, 0x7FF00000; + cmp edx, 0x00100000; + jg label_6; + sub edx, edx; +#ifdef TARGET_X64 + mov qword ptr [rdi], rdx; +#else + mov dword ptr [edi], edx; + mov dword ptr [edi+4], edx; +#endif +label_6: + +_emit 0x89; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; + } +} +__declspec(naked) void nseel_asm_mul_op_end(void) {} + +__declspec(naked) void nseel_asm_mul_op_fast(void) +{ + __asm { +_emit 0x89; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; + fmul EEL_ASM_TYPE [edi]; + mov eax, edi; + fstp EEL_ASM_TYPE [edi]; +_emit 0x89; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; + } +} +__declspec(naked) void nseel_asm_mul_op_fast_end(void) {} + +//--------------------------------------------------------------------------------------------------------------- +__declspec(naked) void nseel_asm_div(void) +{ + __asm { +_emit 0x89; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +#ifdef __clang__ + fdivrp st(1); +#else + #ifdef __GNUC__ + #ifdef __INTEL_COMPILER + fdiv; + #else + fdivr; // gcc inline asm seems to have fdiv/fdivr backwards + #endif + #else + fdiv; + #endif +#endif +_emit 0x89; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; + } +} +__declspec(naked) void nseel_asm_div_end(void) {} + +__declspec(naked) void nseel_asm_div_op(void) +{ + __asm { +_emit 0x89; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; + fld EEL_ASM_TYPE [edi]; +#ifdef __clang__ + fdivp st(1); +#else + #ifndef __GNUC__ + fdivr; + #else + #ifdef __INTEL_COMPILER + fdivp st(1); + #else + fdiv; + #endif + #endif +#endif + mov eax, edi; + fstp EEL_ASM_TYPE [edi]; + + mov edx, dword ptr [edi+4]; + add edx, 0x00100000; + and edx, 0x7FF00000; + cmp edx, 0x00100000; + jg label_7; + sub edx, edx; +#ifdef TARGET_X64 + mov qword ptr [rdi], rdx; +#else + mov dword ptr [edi], edx; + mov dword ptr [edi+4], edx; +#endif +label_7: + + +_emit 0x89; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; + } +} +__declspec(naked) void nseel_asm_div_op_end(void) {} + +__declspec(naked) void nseel_asm_div_op_fast(void) +{ + __asm { +_emit 0x89; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; + fld EEL_ASM_TYPE [edi]; +#ifdef __clang__ + fdivp st(1); +#else + #ifndef __GNUC__ + fdivr; + #else + #ifdef __INTEL_COMPILER + fdivp st(1); + #else + fdiv; + #endif + #endif +#endif + mov eax, edi; + fstp EEL_ASM_TYPE [edi]; + +_emit 0x89; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; + } +} +__declspec(naked) void nseel_asm_div_op_fast_end(void) {} + +//--------------------------------------------------------------------------------------------------------------- +__declspec(naked) void nseel_asm_mod(void) +{ + __asm { +_emit 0x89; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; + fabs; + fistp dword ptr [esi]; + fabs; + fistp dword ptr [esi+4]; + xor edx, edx; + cmp dword ptr [esi], 0; + je label_8; // skip devide, set return to 0 + mov eax, dword ptr [esi+4]; + div dword ptr [esi]; +label_8: + + mov dword ptr [esi], edx; + fild dword ptr [esi]; + +_emit 0x89; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; + } +} +__declspec(naked) void nseel_asm_mod_end(void) {} + +__declspec(naked) void nseel_asm_shl(void) +{ + __asm { +_emit 0x89; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; + fistp dword ptr [esi]; + fistp dword ptr [esi+4]; + mov ecx, dword ptr [esi]; + mov eax, dword ptr [esi+4]; + shl eax, cl; + mov dword ptr [esi], eax; + fild dword ptr [esi]; +_emit 0x89; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; + } +} +__declspec(naked) void nseel_asm_shl_end(void) {} + +__declspec(naked) void nseel_asm_shr(void) +{ + __asm { +_emit 0x89; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; + fistp dword ptr [esi]; + fistp dword ptr [esi+4]; + mov ecx, dword ptr [esi]; + mov eax, dword ptr [esi+4]; + sar eax, cl; + mov dword ptr [esi], eax; + fild dword ptr [esi]; +_emit 0x89; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; + } +} +__declspec(naked) void nseel_asm_shr_end(void) {} + + +__declspec(naked) void nseel_asm_mod_op(void) +{ + __asm { +_emit 0x89; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; + fld EEL_ASM_TYPE [edi]; + fxch; + fabs; + fistp dword ptr [edi]; + fabs; + fistp dword ptr [esi]; + xor edx, edx; + cmp dword ptr [edi], 0; + je label_9; // skip devide, set return to 0 + mov eax, dword ptr [esi]; + div dword ptr [edi]; +label_9: + + mov dword ptr [edi], edx; + fild dword ptr [edi]; + mov eax, edi; + fstp EEL_ASM_TYPE [edi]; + +_emit 0x89; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; + } +} +__declspec(naked) void nseel_asm_mod_op_end(void) {} + +//--------------------------------------------------------------------------------------------------------------- +__declspec(naked) void nseel_asm_or(void) +{ + __asm { +_emit 0x89; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; + fistp qword ptr [esi]; + fistp qword ptr [esi+8]; +#ifdef TARGET_X64 + mov rdi, qword ptr [rsi+8]; + or qword ptr [rsi], rdi; +#else + mov edi, dword ptr [esi+8]; + mov ecx, dword ptr [esi+12]; + or dword ptr [esi], edi; + or dword ptr [esi+4], ecx; +#endif + fild qword ptr [esi]; + +_emit 0x89; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; + } +} +__declspec(naked) void nseel_asm_or_end(void) {} + +__declspec(naked) void nseel_asm_or0(void) +{ + __asm { +_emit 0x89; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; + fistp qword ptr [esi]; + fild qword ptr [esi]; +_emit 0x89; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; + } +} +__declspec(naked) void nseel_asm_or0_end(void) {} + +__declspec(naked) void nseel_asm_or_op(void) +{ + __asm { +_emit 0x89; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; + fld EEL_ASM_TYPE [edi]; + fxch; + fistp qword ptr [edi]; + fistp qword ptr [esi]; +#ifdef TARGET_X64 + mov rax, qword ptr [rsi]; + or qword ptr [rdi], rax; +#else + mov eax, dword ptr [esi]; + mov ecx, dword ptr [esi+4]; + or dword ptr [edi], eax; + or dword ptr [edi+4], ecx; +#endif + fild qword ptr [edi]; + mov eax, edi; + fstp EEL_ASM_TYPE [edi]; + +_emit 0x89; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; + } +} +__declspec(naked) void nseel_asm_or_op_end(void) {} + + +__declspec(naked) void nseel_asm_xor(void) +{ + __asm { +_emit 0x89; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; + fistp qword ptr [esi]; + fistp qword ptr [esi+8]; +#ifdef TARGET_X64 + mov rdi, qword ptr [rsi+8]; + xor qword ptr [rsi], rdi; +#else + mov edi, dword ptr [esi+8]; + mov ecx, dword ptr [esi+12]; + xor dword ptr [esi], edi; + xor dword ptr [esi+4], ecx; +#endif + fild qword ptr [esi]; + +_emit 0x89; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; + } +} +__declspec(naked) void nseel_asm_xor_end(void) {} + +__declspec(naked) void nseel_asm_xor_op(void) +{ + __asm { +_emit 0x89; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; + fld EEL_ASM_TYPE [edi]; + fxch; + fistp qword ptr [edi]; + fistp qword ptr [esi]; +#ifdef TARGET_X64 + mov rax, qword ptr [rsi]; + xor qword ptr [rdi], rax; +#else + mov eax, dword ptr [esi]; + mov ecx, dword ptr [esi+4]; + xor dword ptr [edi], eax; + xor dword ptr [edi+4], ecx; +#endif + fild qword ptr [edi]; + mov eax, edi; + fstp EEL_ASM_TYPE [edi]; + +_emit 0x89; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; + } +} +__declspec(naked) void nseel_asm_xor_op_end(void) {} + + +//--------------------------------------------------------------------------------------------------------------- +__declspec(naked) void nseel_asm_and(void) +{ + __asm { +_emit 0x89; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; + fistp qword ptr [esi]; + fistp qword ptr [esi+8]; +#ifdef TARGET_X64 + mov rdi, qword ptr [rsi+8]; + and qword ptr [rsi], rdi; +#else + mov edi, dword ptr [esi+8]; + mov ecx, dword ptr [esi+12]; + and dword ptr [esi], edi; + and dword ptr [esi+4], ecx; +#endif + fild qword ptr [esi]; + +_emit 0x89; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; + } +} +__declspec(naked) void nseel_asm_and_end(void) {} + +__declspec(naked) void nseel_asm_and_op(void) +{ + __asm { +_emit 0x89; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; + fld EEL_ASM_TYPE [edi]; + fxch; + fistp qword ptr [edi]; + fistp qword ptr [esi]; +#ifdef TARGET_X64 + mov rax, qword ptr [rsi]; + and qword ptr [rdi], rax; +#else + mov eax, dword ptr [esi]; + mov ecx, dword ptr [esi+4]; + and dword ptr [edi], eax; + and dword ptr [edi+4], ecx; +#endif + fild qword ptr [edi]; + mov eax, edi; + fstp EEL_ASM_TYPE [edi]; + +_emit 0x89; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; + } +} +__declspec(naked) void nseel_asm_and_op_end(void) {} + + +//--------------------------------------------------------------------------------------------------------------- +__declspec(naked) void nseel_asm_uplus(void) // this is the same as doing nothing, it seems +{ + __asm { +_emit 0x89; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; + +_emit 0x89; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; + } +} +__declspec(naked) void nseel_asm_uplus_end(void) {} + +//--------------------------------------------------------------------------------------------------------------- +__declspec(naked) void nseel_asm_uminus(void) +{ + __asm { +_emit 0x89; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; + fchs; +_emit 0x89; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; + } +} +__declspec(naked) void nseel_asm_uminus_end(void) {} + + + +//--------------------------------------------------------------------------------------------------------------- +__declspec(naked) void nseel_asm_sign(void) +{ + __asm { +_emit 0x89; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; + +#ifdef TARGET_X64 + + + fst EEL_ASM_TYPE [rsi]; + mov rdx, EEL_ASM_TYPE [rsi]; + mov rcx, 0x7FFFFFFFFFFFFFFF; + test rdx, rcx; + jz label_10; // zero zero, return the value passed directly + // calculate sign + inc rcx; // rcx becomes 0x80000... + fstp st(0); + fld1; + test rdx, rcx; + jz label_10; + fchs; +label_10: + + +#else + + fst dword ptr [esi]; + mov ecx, dword ptr [esi]; + mov edx, 0x7FFFFFFF; + test ecx, edx; + jz label_11; // zero zero, return the value passed directly + // calculate sign + inc edx; // edx becomes 0x8000... + fstp st(0); + fld1; + test ecx, edx; + jz label_11; + fchs; +label_11: + + +#endif +_emit 0x89; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +} +} +__declspec(naked) void nseel_asm_sign_end(void) {} + + + +//--------------------------------------------------------------------------------------------------------------- +__declspec(naked) void nseel_asm_bnot(void) +{ + __asm { +_emit 0x89; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; + test eax, eax; + setz al; + and eax, 0xff; +_emit 0x89; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; + } +} +__declspec(naked) void nseel_asm_bnot_end(void) {} + +//--------------------------------------------------------------------------------------------------------------- +__declspec(naked) void nseel_asm_fcall(void) +{ + __asm { +_emit 0x89; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; + mov edx, 0xfefefefe; +#ifdef TARGET_X64 + sub esp, 8; + call edx; + add esp, 8; +#else + sub esp, 12; /* keep stack 16 byte aligned, 4 bytes for return address */ + call edx; + add esp, 12; +#endif +_emit 0x89; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; + } +} +__declspec(naked) void nseel_asm_fcall_end(void) {} + +__declspec(naked) void nseel_asm_band(void) +{ + __asm { +_emit 0x89; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; + test eax, eax; + jz label_12; + + mov ecx, 0xfefefefe; +#ifdef TARGET_X64 + sub rsp, 8; +#else + sub esp, 12; +#endif + call ecx; +#ifdef TARGET_X64 + add rsp, 8; +#else + add esp, 12; +#endif +label_12: + +_emit 0x89; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; + } +} +__declspec(naked) void nseel_asm_band_end(void) {} + +__declspec(naked) void nseel_asm_bor(void) +{ + __asm { +_emit 0x89; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; + test eax, eax; + jnz label_13; + + mov ecx, 0xfefefefe; +#ifdef TARGET_X64 + sub rsp, 8; +#else + sub esp, 12; +#endif + call ecx; +#ifdef TARGET_X64 + add rsp, 8; +#else + add esp, 12; +#endif +label_13: + +_emit 0x89; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; + } +} +__declspec(naked) void nseel_asm_bor_end(void) {} + +//--------------------------------------------------------------------------------------------------------------- +__declspec(naked) void nseel_asm_equal(void) +{ + __asm { +_emit 0x89; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +#ifdef __clang__ + fsubp st(1); +#else + fsub; +#endif + + fabs; +#ifdef TARGET_X64 + fcomp EEL_ASM_TYPE [r12+-8]; //[g_closefact] +#else + fcomp EEL_ASM_TYPE [ebx+-8]; //[g_closefact] +#endif + fstsw ax; + and eax, 256; // old behavior: if 256 set, true (NaN means true) + +_emit 0x89; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; + } +} +__declspec(naked) void nseel_asm_equal_end(void) {} +// +//--------------------------------------------------------------------------------------------------------------- +__declspec(naked) void nseel_asm_equal_exact(void) +{ + __asm { +_emit 0x89; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; + fcompp; + fstsw ax; // for equal 256 and 1024 should be clear, 16384 should be set + and eax, 17664; // mask C4/C3/C1, bits 8/10/14, 16384|256|1024 -- if equals 16384, then equality + cmp eax, 16384; + je label_14; + sub eax, eax; +label_14: + +_emit 0x89; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; + } +} +__declspec(naked) void nseel_asm_equal_exact_end(void) {} + +__declspec(naked) void nseel_asm_notequal_exact(void) +{ + __asm { +_emit 0x89; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; + fcompp; + fstsw ax; // for equal 256 and 1024 should be clear, 16384 should be set + and eax, 17664; // mask C4/C3/C1, bits 8/10/14, 16384|256|1024 -- if equals 16384, then equality + cmp eax, 16384; + je label_15; + sub eax, eax; +label_15: + + xor eax, 16384; // flip the result +_emit 0x89; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; + } +} +__declspec(naked) void nseel_asm_notequal_exact_end(void) {} +// +//--------------------------------------------------------------------------------------------------------------- +__declspec(naked) void nseel_asm_notequal(void) +{ + __asm { +_emit 0x89; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +#ifdef __clang__ + fsubp st(1); +#else + fsub; +#endif + + fabs; +#ifdef TARGET_X64 + fcomp EEL_ASM_TYPE [r12+-8]; //[g_closefact] +#else + fcomp EEL_ASM_TYPE [ebx+-8]; //[g_closefact] +#endif + fstsw ax; + and eax, 256; + xor eax, 256; // old behavior: if 256 set, FALSE (NaN makes for false) +_emit 0x89; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; + } +} +__declspec(naked) void nseel_asm_notequal_end(void) {} + + +//--------------------------------------------------------------------------------------------------------------- +__declspec(naked) void nseel_asm_above(void) +{ + __asm { +_emit 0x89; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; + fcompp; + fstsw ax; + and eax, 1280; // (1024+256) old behavior: NaN would mean 1, preserve that +_emit 0x89; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; + } +} +__declspec(naked) void nseel_asm_above_end(void) {} + +//--------------------------------------------------------------------------------------------------------------- +__declspec(naked) void nseel_asm_beloweq(void) +{ + __asm { +_emit 0x89; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; + fcompp; + fstsw ax; + and eax, 256; // old behavior: NaN would be 0 (ugh) + xor eax, 256; +_emit 0x89; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; + } +} +__declspec(naked) void nseel_asm_beloweq_end(void) {} + + +__declspec(naked) void nseel_asm_booltofp(void) +{ + __asm { +_emit 0x89; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; + test eax, eax; + jz label_16; + fld1; + jmp label_17; +label_16: + + fldz; +label_17: + +_emit 0x89; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; + } +} +__declspec(naked) void nseel_asm_booltofp_end(void) {} + +__declspec(naked) void nseel_asm_fptobool(void) +{ + __asm { +_emit 0x89; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; + fabs; +#ifdef TARGET_X64 + fcomp EEL_ASM_TYPE [r12+-8]; //[g_closefact] +#else + fcomp EEL_ASM_TYPE [ebx+-8]; //[g_closefact] +#endif + fstsw ax; + and eax, 256; + xor eax, 256; +_emit 0x89; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; + } +} +__declspec(naked) void nseel_asm_fptobool_end(void) {} + +__declspec(naked) void nseel_asm_fptobool_rev(void) +{ + __asm { +_emit 0x89; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; + fabs; +#ifdef TARGET_X64 + fcomp EEL_ASM_TYPE [r12+-8]; //[g_closefact] +#else + fcomp EEL_ASM_TYPE [ebx+-8]; //[g_closefact] +#endif + fstsw ax; + and eax, 256; +_emit 0x89; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; + } +} +__declspec(naked) void nseel_asm_fptobool_rev_end(void) {} + +__declspec(naked) void nseel_asm_min(void) +{ + __asm { +_emit 0x89; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; + fld EEL_ASM_TYPE [edi]; + fcomp EEL_ASM_TYPE [eax]; + mov ecx, eax; + fstsw ax; + test eax, 256; + mov eax, ecx; + jz label_18; + mov eax, edi; +label_18: + +_emit 0x89; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; + } + +} +__declspec(naked) void nseel_asm_min_end(void) {} + +__declspec(naked) void nseel_asm_max(void) +{ + __asm { +_emit 0x89; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; + fld EEL_ASM_TYPE [edi]; + fcomp EEL_ASM_TYPE [eax]; + mov ecx, eax; + fstsw ax; + test eax, 256; + mov eax, ecx; + jnz label_19; + mov eax, edi; +label_19: + +_emit 0x89; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; + } +} +__declspec(naked) void nseel_asm_max_end(void) {} + + + +__declspec(naked) void nseel_asm_min_fp(void) +{ + __asm { +_emit 0x89; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; + fcom; + fstsw ax; + test eax, 256; + jz label_20; + fxch; +label_20: + + fstp st(0); +_emit 0x89; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; + } + +} +__declspec(naked) void nseel_asm_min_fp_end(void) {} + +__declspec(naked) void nseel_asm_max_fp(void) +{ + __asm { +_emit 0x89; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; + fcom; + fstsw ax; + test eax, 256; + jnz label_21; + fxch; +label_21: + + fstp st(0); +_emit 0x89; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; + } +} +__declspec(naked) void nseel_asm_max_fp_end(void) {} + + + +// just generic functions left, yay + + + + +__declspec(naked) void _asm_generic3parm(void) +{ + __asm { +_emit 0x89; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +#ifdef TARGET_X64 + +#ifdef AMD64ABI + + mov r15, rsi; + mov rdx, rdi; // third parameter = parm + mov rdi, 0xfefefefe; // first parameter= context + + mov rsi, ecx; // second parameter = parm + mov rcx, rax; // fourth parameter = parm + mov rax, 0xfefefefe; // call function + call rax; + + mov rsi, r15; +#else + mov edx, ecx; // second parameter = parm + mov ecx, 0xfefefefe; // first parameter= context + mov r8, rdi; // third parameter = parm + mov r9, rax; // fourth parameter = parm + mov edi, 0xfefefefe; // call function + sub rsp, X64_EXTRA_STACK_SPACE; + call edi; + add rsp, X64_EXTRA_STACK_SPACE; +#endif + +#else + + mov edx, 0xfefefefe; + push eax; // push parameter + push edi; // push parameter + mov edi, 0xfefefefe; + push ecx; // push parameter + push edx; // push context pointer + call edi; + add esp, 16; + +#endif +_emit 0x89; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; + } +} +__declspec(naked) void _asm_generic3parm_end(void) {} + + +__declspec(naked) void _asm_generic3parm_retd(void) +{ + __asm { +_emit 0x89; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +#ifdef TARGET_X64 +#ifdef AMD64ABI + mov r15, rsi; + mov rdx, rdi; // third parameter = parm + mov rdi, 0xfefefefe; // first parameter= context + mov rsi, ecx; // second parameter = parm + mov rcx, rax; // fourth parameter = parm + mov rax, 0xfefefefe; // call function + call rax; + mov rsi, r15; + movq [r15], xmm0; + fld qword ptr [r15]; +#else + mov edx, ecx; // second parameter = parm + mov ecx, 0xfefefefe; // first parameter= context + mov r8, rdi; // third parameter = parm + mov r9, rax; // fourth parameter = parm + mov edi, 0xfefefefe; // call function + sub rsp, X64_EXTRA_STACK_SPACE; + call edi; + add rsp, X64_EXTRA_STACK_SPACE; + movq [rsi], xmm0; + fld qword ptr [rsi]; +#endif +#else + + sub esp, 16; + mov edx, 0xfefefefe; + mov dword ptr [esp+8], edi; + mov edi, 0xfefefefe; + mov dword ptr [esp+12], eax; + mov dword ptr [esp+4], ecx; + mov dword ptr [esp], edx; + call edi; + add esp, 16; + +#endif +_emit 0x89; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; + } +} +__declspec(naked) void _asm_generic3parm_retd_end(void) {} + + +__declspec(naked) void _asm_generic2parm(void) // this prob neds to be fixed for ppc +{ + __asm { +_emit 0x89; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +#ifdef TARGET_X64 + +#ifdef AMD64ABI + mov r15, rsi; + mov esi, edi; // second parameter = parm + mov edi, 0xfefefefe; // first parameter= context + mov rdx, rax; // third parameter = parm + mov rcx, 0xfefefefe; // call function + call rcx; + mov rsi, r15; +#else + mov ecx, 0xfefefefe; // first parameter= context + mov edx, edi; // second parameter = parm + mov r8, rax; // third parameter = parm + mov edi, 0xfefefefe; // call function + sub rsp, X64_EXTRA_STACK_SPACE; + call edi; + add rsp, X64_EXTRA_STACK_SPACE; +#endif +#else + + mov edx, 0xfefefefe; + mov ecx, 0xfefefefe; + sub esp, 4; // keep stack aligned + push eax; // push parameter + push edi; // push parameter + push edx; // push context pointer + call ecx; + add esp, 16; + +#endif +_emit 0x89; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; + } +} +__declspec(naked) void _asm_generic2parm_end(void) {} + + +__declspec(naked) void _asm_generic2parm_retd(void) +{ + __asm { +_emit 0x89; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +#ifdef TARGET_X64 +#ifdef AMD64ABI + mov r15, rsi; + mov rsi, rdi; // second parameter = parm + mov rdi, 0xfefefefe; // first parameter= context + mov rcx, 0xfefefefe; // call function + mov rdx, rax; // third parameter = parm + call rcx; + mov rsi, r15; + movq [r15], xmm0; + fld qword ptr [r15]; +#else + mov rdx, rdi; // second parameter = parm + mov rcx, 0xfefefefe; // first parameter= context + mov rdi, 0xfefefefe; // call function + mov r8, rax; // third parameter = parm + sub rsp, X64_EXTRA_STACK_SPACE; + call edi; + add rsp, X64_EXTRA_STACK_SPACE; + movq [rsi], xmm0; + fld qword ptr [rsi]; +#endif +#else + + sub esp, 16; + mov edx, 0xfefefefe; + mov ecx, 0xfefefefe; + mov dword ptr [esp], edx; + mov dword ptr [esp+4], edi; + mov dword ptr [esp+8], eax; + call ecx; + add esp, 16; + +#endif +_emit 0x89; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; + } +} +__declspec(naked) void _asm_generic2parm_retd_end(void) {} + + + + + +__declspec(naked) void _asm_generic1parm(void) +{ + __asm { +_emit 0x89; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +#ifdef TARGET_X64 +#ifdef AMD64ABI + mov rdi, 0xfefefefe; // first parameter= context + mov r15, rsi; + mov rsi, eax; // second parameter = parm + mov rcx, 0xfefefefe; // call function + call rcx; + mov rsi, r15; +#else + mov ecx, 0xfefefefe; // first parameter= context + mov edx, eax; // second parameter = parm + mov edi, 0xfefefefe; // call function + sub rsp, X64_EXTRA_STACK_SPACE; + call edi; + add rsp, X64_EXTRA_STACK_SPACE; +#endif +#else + + mov edx, 0xfefefefe; + sub esp, 8; // keep stack aligned + mov ecx, 0xfefefefe; + push eax; // push parameter + push edx; // push context pointer + call ecx; + add esp, 16; + +#endif + +_emit 0x89; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; + } +} +__declspec(naked) void _asm_generic1parm_end(void) {} + + +__declspec(naked) void _asm_generic1parm_retd(void) // 1 parameter returning double +{ + __asm { +_emit 0x89; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +#ifdef TARGET_X64 +#ifdef AMD64ABI + mov rdi, 0xfefefefe; // first parameter = context pointer + mov rcx, 0xfefefefe; // function address + mov r15, rsi; // save rsi + mov rsi, rax; // second parameter = parameter + + call rcx; + + mov rsi, r15; + movq [r15], xmm0; + fld qword ptr [r15]; +#else + mov ecx, 0xfefefefe; // first parameter= context + mov edi, 0xfefefefe; // call function + + mov rdx, rax; // second parameter = parm + + sub rsp, X64_EXTRA_STACK_SPACE; + call edi; + add rsp, X64_EXTRA_STACK_SPACE; + movq [rsi], xmm0; + fld qword ptr [rsi]; +#endif +#else + + mov edx, 0xfefefefe; // context pointer + mov ecx, 0xfefefefe; // func-addr + sub esp, 16; + mov dword ptr [esp+4], eax; // push parameter + mov dword ptr [esp], edx; // push context pointer + call ecx; + add esp, 16; + +#endif +_emit 0x89; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; + } +} +__declspec(naked) void _asm_generic1parm_retd_end(void) {} + + + + + +// this gets its own stub because it's pretty crucial for performance :/ + +__declspec(naked) void _asm_megabuf(void) +{ + __asm { + +_emit 0x89; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; + +#ifdef TARGET_X64 + + +#ifdef AMD64ABI + + fadd EEL_ASM_TYPE [r12+-8]; + + fistp dword ptr [rsi]; + + // check if (%rsi) is in range, and buffer available, otherwise call function + mov edx, dword ptr [rsi]; + cmp rdx, ((NSEEL_RAM_BLOCKS*NSEEL_RAM_ITEMSPERBLOCK)); //REPLACE=((NSEEL_RAM_BLOCKS*NSEEL_RAM_ITEMSPERBLOCK)) + jae label_22; + mov rax, rdx; + shr rax, (NSEEL_RAM_ITEMSPERBLOCK_LOG2 - 3/*log2(sizeof(void *))*/ ); //REPLACE=(NSEEL_RAM_ITEMSPERBLOCK_LOG2 - 3/*log2(sizeof(void *))*/ ) + and rax, ((NSEEL_RAM_BLOCKS-1)*8 /*sizeof(void*)*/ ); //REPLACE=((NSEEL_RAM_BLOCKS-1)*8 /*sizeof(void*)*/ ) + mov rax, qword ptr [r12+rax]; + test rax, rax; + jnz label_23; +label_22: + + mov rax, 0xfefefefe; + mov rdi, r12; // set first parm to ctx + mov r15, rsi; // save rsi + mov esi, rdx; // esi becomes second parameter (edi is first, context pointer) + call rax; + mov rsi, r15; // restore rsi + jmp label_24; +label_23: + + and rdx, (NSEEL_RAM_ITEMSPERBLOCK-1); //REPLACE=(NSEEL_RAM_ITEMSPERBLOCK-1) + shl rdx, 3; // 3 is log2(sizeof(EEL_F)) + add rax, rdx; +label_24: + + +#else + + fadd EEL_ASM_TYPE [r12+-8]; + + fistp dword ptr [rsi]; + + // check if (%rsi) is in range... + mov edi, dword ptr [rsi]; + cmp edi, ((NSEEL_RAM_BLOCKS*NSEEL_RAM_ITEMSPERBLOCK)); //REPLACE=((NSEEL_RAM_BLOCKS*NSEEL_RAM_ITEMSPERBLOCK)) + jae label_25; + mov rax, rdi; + shr rax, (NSEEL_RAM_ITEMSPERBLOCK_LOG2 - 3/*log2(sizeof(void *))*/ ); //REPLACE=(NSEEL_RAM_ITEMSPERBLOCK_LOG2 - 3/*log2(sizeof(void *))*/ ) + and rax, ((NSEEL_RAM_BLOCKS-1)*8 /*sizeof(void*)*/ ); //REPLACE=((NSEEL_RAM_BLOCKS-1)*8 /*sizeof(void*)*/ ) + mov rax, qword ptr [r12+rax]; + test rax, rax; + jnz label_26; +label_25: + + mov rax, 0xfefefefe; // function ptr + mov rcx, r12; // set first parm to ctx + mov rdx, rdi; // rdx is second parameter (rcx is first) + sub rsp, X64_EXTRA_STACK_SPACE; + call rax; + add rsp, X64_EXTRA_STACK_SPACE; + jmp label_27; +label_26: + + and rdi, (NSEEL_RAM_ITEMSPERBLOCK-1); //REPLACE=(NSEEL_RAM_ITEMSPERBLOCK-1) + shl rdi, 3; // 3 is log2(sizeof(EEL_F)) + add rax, rdi; +label_27: + +#endif + + +_emit 0x89; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +#else + fadd EEL_ASM_TYPE [ebx+-8]; + fistp dword ptr [esi]; + + // check if (%esi) is in range, and buffer available, otherwise call function + mov edi, dword ptr [esi]; + cmp edi, ((NSEEL_RAM_BLOCKS*NSEEL_RAM_ITEMSPERBLOCK)); //REPLACE=((NSEEL_RAM_BLOCKS*NSEEL_RAM_ITEMSPERBLOCK)) + jae label_28; + + mov eax, edi; + shr eax, (NSEEL_RAM_ITEMSPERBLOCK_LOG2 - 2/*log2(sizeof(void *))*/ ); //REPLACE=(NSEEL_RAM_ITEMSPERBLOCK_LOG2 - 2/*log2(sizeof(void *))*/ ) + and eax, ((NSEEL_RAM_BLOCKS-1)*4 /*sizeof(void*)*/ ); //REPLACE=((NSEEL_RAM_BLOCKS-1)*4 /*sizeof(void*)*/ ) + mov eax, dword ptr [ebx+eax]; + test eax, eax; + jnz label_29; +label_28: + + sub esp, 8; // keep stack aligned + mov ecx, 0xfefefefe; + push edi; // parameter + push ebx; // push context pointer + call ecx; + add esp, 16; + jmp label_30; +label_29: + + and edi, (NSEEL_RAM_ITEMSPERBLOCK-1); //REPLACE=(NSEEL_RAM_ITEMSPERBLOCK-1) + shl edi, 3; // 3 is log2(sizeof(EEL_F)) + add eax, edi; +label_30: + +_emit 0x89; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; + + #ifndef _MSC_VER + :: i; (((NSEEL_RAM_BLOCKS*NSEEL_RAM_ITEMSPERBLOCK))), + i; ((NSEEL_RAM_ITEMSPERBLOCK_LOG2 - 2/*log2(sizeof(void *))*/ )), + i; (((NSEEL_RAM_BLOCKS-1)*4 /*sizeof(void*)*/ )), + i; ((NSEEL_RAM_ITEMSPERBLOCK-1 )) + #endif + + + +#endif + + } +} + +__declspec(naked) void _asm_megabuf_end(void) {} + + +__declspec(naked) void _asm_gmegabuf(void) +{ + __asm { + +_emit 0x89; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; + +#ifdef TARGET_X64 + + +#ifdef AMD64ABI + + mov r15, rsi; + fadd EEL_ASM_TYPE [r12+-8]; + mov rdi, 0xfefefefe; // first parameter = context pointer + fistp dword ptr [rsi]; + mov edx, 0xfefefefe; + mov esi, dword ptr [rsi]; + call rdx; + mov rsi, r15; + +#else + fadd EEL_ASM_TYPE [r12+-8]; + mov rcx, 0xfefefefe; // first parameter = context pointer + fistp dword ptr [rsi]; + mov rdi, 0xfefefefe; + mov edx, dword ptr [rsi]; + sub rsp, X64_EXTRA_STACK_SPACE; + call rdi; + add rsp, X64_EXTRA_STACK_SPACE; +#endif + + +#else + sub esp, 16; // keep stack aligned + mov dword ptr [esp], 0xfefefefe; + fadd EEL_ASM_TYPE [ebx+-8]; + mov edi, 0xfefefefe; + fistp dword ptr [esp+4]; + call edi; + add esp, 16; + +#endif + + + +_emit 0x89; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; + } +} + +__declspec(naked) void _asm_gmegabuf_end(void) {} + +__declspec(naked) void nseel_asm_stack_push(void) +{ +#ifdef TARGET_X64 + __asm { +_emit 0x89; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; + mov rdi, 0xfefefefe; + mov rcx, qword ptr [rax]; + mov rax, qword ptr [rdi]; + add rax, 8; + mov rdx, 0xFEFEFEFE; + and rax, rdx; + mov rdx, 0xFEFEFEFE; + or rax, rdx; + mov qword ptr [rax], rcx; + mov qword ptr [rdi], rax; +_emit 0x89; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; + } +#else + + __asm { +_emit 0x89; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; + mov edi, 0xfefefefe; + + mov ecx, dword ptr [eax]; + mov edx, dword ptr [eax+4]; + + mov eax, dword ptr [edi]; + + add eax, 8; + and eax, 0xfefefefe; + or eax, 0xfefefefe; + + mov dword ptr [eax], ecx; + mov dword ptr [eax+4], edx; + + mov dword ptr [edi], eax; +_emit 0x89; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; + } + +#endif + +} +__declspec(naked) void nseel_asm_stack_push_end(void) {} + + + +__declspec(naked) void nseel_asm_stack_pop(void) +{ +#ifdef TARGET_X64 + + __asm { +_emit 0x89; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; + mov rdi, 0xfefefefe; + mov rcx, qword ptr [rdi]; + movq xmm0, [rcx]; + sub rcx, 8; + mov rdx, 0xFEFEFEFE; + and rcx, rdx; + mov rdx, 0xFEFEFEFE; + or rcx, rdx; + mov qword ptr [rdi], rcx; + movq [eax], xmm0; +_emit 0x89; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; + } + +#else + + __asm { +_emit 0x89; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; + mov edi, 0xfefefefe; + mov ecx, dword ptr [edi]; + fld EEL_ASM_TYPE [ecx]; + sub ecx, 8; + and ecx, 0xfefefefe; + or ecx, 0xfefefefe; + mov dword ptr [edi], ecx; + fstp EEL_ASM_TYPE [eax]; +_emit 0x89; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; + } + +#endif +} +__declspec(naked) void nseel_asm_stack_pop_end(void) {} + + +__declspec(naked) void nseel_asm_stack_pop_fast(void) +{ +#ifdef TARGET_X64 + + __asm { +_emit 0x89; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; + mov rdi, 0xfefefefe; + mov rcx, qword ptr [rdi]; + mov rax, rcx; + sub rcx, 8; + mov rdx, 0xFEFEFEFE; + and rcx, rdx; + mov rdx, 0xFEFEFEFE; + or rcx, rdx; + mov qword ptr [rdi], rcx; +_emit 0x89; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; + } + +#else + + __asm { +_emit 0x89; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; + mov edi, 0xfefefefe; + mov ecx, dword ptr [edi]; + mov eax, ecx; + sub ecx, 8; + and ecx, 0xfefefefe; + or ecx, 0xfefefefe; + mov dword ptr [edi], ecx; +_emit 0x89; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; + } + +#endif +} +__declspec(naked) void nseel_asm_stack_pop_fast_end(void) {} + +__declspec(naked) void nseel_asm_stack_peek_int(void) +{ +#ifdef TARGET_X64 + + __asm { +_emit 0x89; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; + mov rdi, 0xfefefefe; + mov rax, qword ptr [rdi]; + mov rdx, 0xfefefefe; + sub rax, rdx; + mov rdx, 0xFEFEFEFE; + and rax, rdx; + mov rdx, 0xFEFEFEFE; + or rax, rdx; +_emit 0x89; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; + } + +#else + + __asm { +_emit 0x89; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; + mov edi, 0xfefefefe; + mov eax, dword ptr [edi]; + mov edx, 0xfefefefe; + sub eax, edx; + and eax, 0xfefefefe; + or eax, 0xfefefefe; +_emit 0x89; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; + } + +#endif + +} +__declspec(naked) void nseel_asm_stack_peek_int_end(void) {} + + + +__declspec(naked) void nseel_asm_stack_peek(void) +{ +#ifdef TARGET_X64 + + __asm { +_emit 0x89; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; + mov rdi, 0xfefefefe; + fistp dword ptr [rsi]; + mov rax, qword ptr [rdi]; + mov rdx, qword ptr [rsi]; + shl rdx, 3; // log2(sizeof(EEL_F)) + sub rax, rdx; + mov rdx, 0xFEFEFEFE; + and rax, rdx; + mov rdx, 0xFEFEFEFE; + or rax, rdx; +_emit 0x89; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; + } + +#else + + __asm { +_emit 0x89; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; + mov edi, 0xfefefefe; + fistp dword ptr [esi]; + mov eax, dword ptr [edi]; + mov edx, dword ptr [esi]; + shl edx, 3; // log2(sizeof(EEL_F)) + sub eax, edx; + and eax, 0xfefefefe; + or eax, 0xfefefefe; +_emit 0x89; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; + } + +#endif + +} +__declspec(naked) void nseel_asm_stack_peek_end(void) {} + + +__declspec(naked) void nseel_asm_stack_peek_top(void) +{ +#ifdef TARGET_X64 + + __asm { +_emit 0x89; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; + mov rdi, 0xfefefefe; + mov rax, qword ptr [rdi]; +_emit 0x89; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; + } + +#else + + __asm { +_emit 0x89; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; + mov edi, 0xfefefefe; + mov eax, dword ptr [edi]; +_emit 0x89; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; + } + +#endif + +} +__declspec(naked) void nseel_asm_stack_peek_top_end(void) {} + +__declspec(naked) void nseel_asm_stack_exch(void) +{ +#ifdef TARGET_X64 + + __asm { +_emit 0x89; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; + mov rdi, 0xfefefefe; + mov rcx, qword ptr [rdi]; + movq xmm0, [rcx]; + movq xmm1, [rax]; + movq [rax], xmm0; + movq [rcx], xmm1; +_emit 0x89; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; + } + +#else + + __asm { +_emit 0x89; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; + mov edi, 0xfefefefe; + mov ecx, dword ptr [edi]; + fld EEL_ASM_TYPE [ecx]; + fld EEL_ASM_TYPE [eax]; + fstp EEL_ASM_TYPE [ecx]; + fstp EEL_ASM_TYPE [eax]; +_emit 0x89; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; +_emit 0x90; + } + +#endif + +} +__declspec(naked) void nseel_asm_stack_exch_end(void) {} + +#ifdef TARGET_X64 +__declspec(naked) void eel_callcode64() +{ + __asm { +#ifndef EEL_X64_NO_CHANGE_FPFLAGS + sub rsp, 16; + fnstcw [rsp]; + mov ax, [rsp]; + or ax, 0xE3F; // 53 or 64 bit precision, trunc, and masking all exceptions + mov [rsp+4], ax; + fldcw [rsp+4]; +#endif + push rbx; + push rbp; + push r12; + push r13; + push r14; + push r15; + +#ifdef AMD64ABI + mov r12, rsi; // second parameter is ram-blocks pointer + call rdi; +#else + push rdi; + push rsi; + mov r12, rdx; // second parameter is ram-blocks pointer + call rcx; + pop rsi; + pop rdi; +#endif + + fclex; + + pop r15; + pop r14; + pop r13; + pop r12; + pop rbp; + pop rbx; + +#ifndef EEL_X64_NO_CHANGE_FPFLAGS + fldcw [rsp]; + add rsp, 16; +#endif + + ret; + } +} + +__declspec(naked) void eel_callcode64_fast() +{ + __asm { + push rbx; + push rbp; + push r12; + push r13; + push r14; + push r15; + +#ifdef AMD64ABI + mov r12, rsi; // second parameter is ram-blocks pointer + call rdi; +#else + push rdi; + push rsi; + mov r12, rdx; // second parameter is ram-blocks pointer + call rcx; + pop rsi; + pop rdi; +#endif + + pop r15; + pop r14; + pop r13; + pop r12; + pop rbp; + pop rbx; + + ret; + } +} + +__declspec(naked) void eel_setfp_round() +{ + __asm { +#ifndef EEL_X64_NO_CHANGE_FPFLAGS + sub rsp, 16; + fnstcw [rsp]; + mov ax, [rsp]; + and ax, 0xF3FF; // set round to nearest + mov [rsp+4], ax; + fldcw [rsp+4]; + add rsp, 16; +#endif + ret; + } +} + +__declspec(naked) void eel_setfp_trunc() +{ + __asm { +#ifndef EEL_X64_NO_CHANGE_FPFLAGS + sub rsp, 16; + fnstcw [rsp]; + mov ax, [rsp]; + or ax, 0xC00; // set to truncate + mov [rsp+4], ax; + fldcw [rsp+4]; + add rsp, 16; +#endif + ret; + } +} + +__declspec(naked) void eel_enterfp(int s[2]) +{ + __asm { +#ifdef AMD64ABI + fnstcw [rdi]; + mov ax, [rdi]; + or ax, 0xE3F; // 53 or 64 bit precision, trunc, and masking all exceptions + mov [rdi+4], ax; + fldcw [rdi+4]; +#else + fnstcw [rcx]; + mov ax, [rcx]; + or ax, 0xE3F; // 53 or 64 bit precision, trunc, and masking all exceptions + mov [rcx+4], ax; + fldcw [rcx+4]; +#endif + ret; + } +} +__declspec(naked) void eel_leavefp(int s[2]) +{ + __asm { +#ifdef AMD64ABI + fldcw [rdi]; +#else + fldcw [rcx]; +#endif + ret;; + } +} + +#endif diff --git a/Src/ns-eel2/denormal.h b/Src/ns-eel2/denormal.h new file mode 100644 index 00000000..c06a855e --- /dev/null +++ b/Src/ns-eel2/denormal.h @@ -0,0 +1,260 @@ +#ifndef _WDL_DENORMAL_H_ +#define _WDL_DENORMAL_H_ + +typedef struct +{ + #ifdef __ppc__ // todo: other big endian platforms... + unsigned int hw; + unsigned int lw; + #else + unsigned int lw; + unsigned int hw; + #endif +} WDL_DenormalTwoInts; + +typedef union { double fl; WDL_DenormalTwoInts w; } WDL_DenormalDoubleAccess; +typedef union { float fl; unsigned int w; } WDL_DenormalFloatAccess; + + +// note: the _aggressive versions filter out anything less than around 1.0e-16 or so (approximately) to 0.0, including -0.0 (becomes 0.0) +// note: new! the _aggressive versions also filter inf and NaN to 0.0 + +#ifdef __cplusplus +#define WDL_DENORMAL_INLINE inline +#elif defined(_MSC_VER) +#define WDL_DENORMAL_INLINE __inline +#else +#define WDL_DENORMAL_INLINE +#endif + +#define WDL_DENORMAL_DOUBLE_HW(a) (((const WDL_DenormalDoubleAccess*)(a))->w.hw) +#define WDL_DENORMAL_DOUBLE_LW(a) (((const WDL_DenormalDoubleAccess*)(a))->w.lw) +#define WDL_DENORMAL_FLOAT_W(a) (((const WDL_DenormalFloatAccess*)(a))->w) + +#define WDL_DENORMAL_DOUBLE_HW_NC(a) (((WDL_DenormalDoubleAccess*)(a))->w.hw) +#define WDL_DENORMAL_DOUBLE_LW_NC(a) (((WDL_DenormalDoubleAccess*)(a))->w.lw) +#define WDL_DENORMAL_FLOAT_W_NC(a) (((WDL_DenormalFloatAccess*)(a))->w) + +#define WDL_DENORMAL_DOUBLE_AGGRESSIVE_CUTOFF 0x3cA00000 // 0x3B8000000 maybe instead? that's 10^-5 smaller or so +#define WDL_DENORMAL_FLOAT_AGGRESSIVE_CUTOFF 0x25000000 + + +// define WDL_DENORMAL_WANTS_SCOPED_FTZ, and then use a WDL_denormal_ftz_scope in addition to denormal_*(), then +// if FTZ is available it will be used instead... +// +#ifdef WDL_DENORMAL_WANTS_SCOPED_FTZ + +#if defined(__SSE2__) || _M_IX86_FP >= 2 || defined(_WIN64) + #define WDL_DENORMAL_FTZMODE + #define WDL_DENORMAL_FTZSTATE_TYPE unsigned int + #ifdef _MSC_VER + #include <intrin.h> + #else + #include <xmmintrin.h> + #endif + #define wdl_denorm_mm_getcsr() _mm_getcsr() + #define wdl_denorm_mm_setcsr(x) _mm_setcsr(x) + #if defined(__SSE3__) + #define wdl_denorm_mm_csr_mask ((1<<15)|(1<<11) | (1<<8) | (1<<6)) // FTZ, underflow, denormal mask, DAZ + #else + #define wdl_denorm_mm_csr_mask ((1<<15)|(1<<11)) // FTZ and underflow only (target SSE2) + #endif +#elif defined(__arm__) || defined(__aarch64__) + #define WDL_DENORMAL_FTZMODE + #define WDL_DENORMAL_FTZSTATE_TYPE unsigned long + static unsigned long __attribute__((unused)) wdl_denorm_mm_getcsr() + { + unsigned long rv; +#ifdef __aarch64__ + asm volatile ( "mrs %0, fpcr" : "=r" (rv)); +#else + asm volatile ( "fmrx %0, fpscr" : "=r" (rv)); +#endif + return rv; + } + static void __attribute__((unused)) wdl_denorm_mm_setcsr(unsigned long v) + { +#ifdef __aarch64__ + asm volatile ( "msr fpcr, %0" :: "r"(v)); +#else + asm volatile ( "fmxr fpscr, %0" :: "r"(v)); +#endif + } + #define wdl_denorm_mm_csr_mask (1<<24) +#endif + +class WDL_denormal_ftz_scope +{ + public: + WDL_denormal_ftz_scope() + { +#ifdef WDL_DENORMAL_FTZMODE + const WDL_DENORMAL_FTZSTATE_TYPE b = wdl_denorm_mm_csr_mask; + old_state = wdl_denorm_mm_getcsr(); + if ((need_restore = (old_state & b) != b)) + wdl_denorm_mm_setcsr(old_state|b); +#endif + } + ~WDL_denormal_ftz_scope() + { +#ifdef WDL_DENORMAL_FTZMODE + if (need_restore) wdl_denorm_mm_setcsr(old_state); +#endif + } + +#ifdef WDL_DENORMAL_FTZMODE + WDL_DENORMAL_FTZSTATE_TYPE old_state; + bool need_restore; +#endif + +}; + + +#endif + + +#if !defined(WDL_DENORMAL_FTZMODE) && !defined(WDL_DENORMAL_DO_NOT_FILTER) + +static double WDL_DENORMAL_INLINE denormal_filter_double(double a) +{ + return (WDL_DENORMAL_DOUBLE_HW(&a)&0x7ff00000) ? a : 0.0; +} + +static double WDL_DENORMAL_INLINE denormal_filter_double2(double a) +{ + return ((WDL_DENORMAL_DOUBLE_HW(&a)+0x100000)&0x7ff00000) > 0x100000 ? a : 0.0; +} + +static double WDL_DENORMAL_INLINE denormal_filter_double_aggressive(double a) +{ + return ((WDL_DENORMAL_DOUBLE_HW(&a)+0x100000)&0x7ff00000) >= WDL_DENORMAL_DOUBLE_AGGRESSIVE_CUTOFF ? a : 0.0; +} + +static float WDL_DENORMAL_INLINE denormal_filter_float(float a) +{ + return (WDL_DENORMAL_FLOAT_W(&a)&0x7f800000) ? a : 0.0f; +} + +static float WDL_DENORMAL_INLINE denormal_filter_float2(float a) +{ + return ((WDL_DENORMAL_FLOAT_W(&a)+0x800000)&0x7f800000) > 0x800000 ? a : 0.0f; +} + + +static float WDL_DENORMAL_INLINE denormal_filter_float_aggressive(float a) +{ + return ((WDL_DENORMAL_FLOAT_W(&a)+0x800000)&0x7f800000) >= WDL_DENORMAL_FLOAT_AGGRESSIVE_CUTOFF ? a : 0.0f; +} +static void WDL_DENORMAL_INLINE denormal_fix_double(double *a) +{ + if (!(WDL_DENORMAL_DOUBLE_HW(a)&0x7ff00000)) *a=0.0; +} + +static void WDL_DENORMAL_INLINE denormal_fix_double_aggressive(double *a) +{ + if (((WDL_DENORMAL_DOUBLE_HW(a)+0x100000)&0x7ff00000) < WDL_DENORMAL_DOUBLE_AGGRESSIVE_CUTOFF) *a=0.0; +} + +static void WDL_DENORMAL_INLINE denormal_fix_float(float *a) +{ + if (!(WDL_DENORMAL_FLOAT_W(a)&0x7f800000)) *a=0.0f; +} +static void WDL_DENORMAL_INLINE denormal_fix_float_aggressive(float *a) +{ + if (((WDL_DENORMAL_FLOAT_W(a)+0x800000)&0x7f800000) < WDL_DENORMAL_FLOAT_AGGRESSIVE_CUTOFF) *a=0.0f; +} + + + +#ifdef __cplusplus // automatic typed versions (though one should probably use the explicit versions... + + +static double WDL_DENORMAL_INLINE denormal_filter(double a) +{ + return (WDL_DENORMAL_DOUBLE_HW(&a)&0x7ff00000) ? a : 0.0; +} +static double WDL_DENORMAL_INLINE denormal_filter_aggressive(double a) +{ + return ((WDL_DENORMAL_DOUBLE_HW(&a)+0x100000)&0x7ff00000) >= WDL_DENORMAL_DOUBLE_AGGRESSIVE_CUTOFF ? a : 0.0; +} + +static float WDL_DENORMAL_INLINE denormal_filter(float a) +{ + return (WDL_DENORMAL_FLOAT_W(&a)&0x7f800000) ? a : 0.0f; +} + +static float WDL_DENORMAL_INLINE denormal_filter_aggressive(float a) +{ + return ((WDL_DENORMAL_FLOAT_W(&a)+0x800000)&0x7f800000) >= WDL_DENORMAL_FLOAT_AGGRESSIVE_CUTOFF ? a : 0.0f; +} + +static void WDL_DENORMAL_INLINE denormal_fix(double *a) +{ + if (!(WDL_DENORMAL_DOUBLE_HW(a)&0x7ff00000)) *a=0.0; +} +static void WDL_DENORMAL_INLINE denormal_fix_aggressive(double *a) +{ + if (((WDL_DENORMAL_DOUBLE_HW(a)+0x100000)&0x7ff00000) < WDL_DENORMAL_DOUBLE_AGGRESSIVE_CUTOFF) *a=0.0; +} +static void WDL_DENORMAL_INLINE denormal_fix(float *a) +{ + if (!(WDL_DENORMAL_FLOAT_W(a)&0x7f800000)) *a=0.0f; +} +static void WDL_DENORMAL_INLINE denormal_fix_aggressive(float *a) +{ + if (((WDL_DENORMAL_FLOAT_W(a)+0x800000)&0x7f800000) < WDL_DENORMAL_FLOAT_AGGRESSIVE_CUTOFF) *a=0.0f; +} + + + +#endif // cplusplus versions + +#else // end of !WDL_DENORMAL_DO_NOT_FILTER (and other platform-specific checks) + +#define denormal_filter(x) (x) +#define denormal_filter2(x) (x) +#define denormal_filter_double(x) (x) +#define denormal_filter_double2(x) (x) +#define denormal_filter_double_aggressive(x) (x) +#define denormal_filter_float(x) (x) +#define denormal_filter_float2(x) (x) +#define denormal_filter_float_aggressive(x) (x) +#define denormal_filter_aggressive(x) (x) +#define denormal_fix(x) do { } while(0) +#define denormal_fix_aggressive(x) do { } while(0) +#define denormal_fix_double(x) do { } while(0) +#define denormal_fix_double_aggressive(x) do { } while(0) +#define denormal_fix_float(x) do { } while(0) +#define denormal_fix_float_aggressive(x) do { } while(0) + +#endif + + +//////////////////// +// this isnt a denormal function but it is similar, so we'll put it here as a bonus + +static void WDL_DENORMAL_INLINE GetDoubleMaxAbsValue(double *out, const double *in) // note: the value pointed to by "out" must be >=0.0, __NOT__ <= -0.0 +{ + unsigned int hw = WDL_DENORMAL_DOUBLE_HW(in)&0x7fffffff; + if (hw >= WDL_DENORMAL_DOUBLE_HW(out) && (hw>WDL_DENORMAL_DOUBLE_HW(out) || WDL_DENORMAL_DOUBLE_LW(in) > WDL_DENORMAL_DOUBLE_LW(out))) + { + WDL_DENORMAL_DOUBLE_LW_NC(out) = WDL_DENORMAL_DOUBLE_LW(in); + WDL_DENORMAL_DOUBLE_HW_NC(out) = hw; + } +} + +static void WDL_DENORMAL_INLINE GetFloatMaxAbsValue(float *out, const float *in) // note: the value pointed to by "out" must be >=0.0, __NOT__ <= -0.0 +{ + unsigned int hw = WDL_DENORMAL_FLOAT_W(in)&0x7fffffff; + if (hw > WDL_DENORMAL_FLOAT_W(out)) WDL_DENORMAL_FLOAT_W_NC(out)=hw; +} + + +#ifdef __cplusplus +static void WDL_DENORMAL_INLINE GetFloatMaxAbsValue(double *out, const double *in) // note: the value pointed to by "out" must be >=0.0, __NOT__ <= -0.0 +{ + GetDoubleMaxAbsValue(out,in); +} +#endif + +#endif diff --git a/Src/ns-eel2/glue_x86.h b/Src/ns-eel2/glue_x86.h new file mode 100644 index 00000000..dd1a101b --- /dev/null +++ b/Src/ns-eel2/glue_x86.h @@ -0,0 +1,524 @@ +#ifndef _NSEEL_GLUE_X86_H_ +#define _NSEEL_GLUE_X86_H_ + +#include <intrin.h> + +#define GLUE_MAX_FPSTACK_SIZE 8 + +// endOfInstruction is end of jump with relative offset, offset is offset from end of instruction to jump to +#define GLUE_JMP_SET_OFFSET(endOfInstruction,offset) (((int *)(endOfInstruction))[-1] = (offset)) + +static const unsigned char GLUE_JMP_NC[] = { 0xE9, 0,0,0,0, }; // jmp<offset> +static const unsigned char GLUE_JMP_IF_P1_Z[] = {0x85, 0xC0, 0x0F, 0x84, 0,0,0,0 }; // test eax, eax, jz +static const unsigned char GLUE_JMP_IF_P1_NZ[] = {0x85, 0xC0, 0x0F, 0x85, 0,0,0,0 }; // test eax, eax, jnz + +#define GLUE_FUNC_ENTER_SIZE 0 +#define GLUE_FUNC_LEAVE_SIZE 0 +const static unsigned int GLUE_FUNC_ENTER[1]; +const static unsigned int GLUE_FUNC_LEAVE[1]; + + // x86 + // stack is 16 byte aligned + // when pushing values to stack, alignment pushed first, then value (value is at the lower address) + // when pushing pointers to stack, alignment pushed first, then pointer (pointer is at the lower address) + + static const unsigned char GLUE_PUSH_P1PTR_AS_VALUE[] = + { + 0x83, 0xEC, 8, /* sub esp, 8 */ + 0xff, 0x70, 0x4, /* push dword [eax+4] */ + 0xff, 0x30, /* push dword [eax] */ + }; + + static int GLUE_POP_VALUE_TO_ADDR(unsigned char *buf, void *destptr) + { + if (buf) + { + *buf++ = 0xB8; *(void **) buf = destptr; buf+=4; // mov eax, directvalue + + *buf++ = 0x8f; *buf++ = 0x00; // pop dword [eax] + *buf++ = 0x8f; *buf++ = 0x40; *buf++ = 4; // pop dword [eax+4] + + *buf++ = 0x59; // pop ecx (alignment) + *buf++ = 0x59; // pop ecx (alignment) + } + + return 12; + } + + static int GLUE_COPY_VALUE_AT_P1_TO_PTR(unsigned char *buf, void *destptr) + { + if (buf) + { + *buf++ = 0x8B; *buf++ = 0x38; // mov edi, [eax] + *buf++ = 0x8B; *buf++ = 0x48; *buf++ = 0x04; // mov ecx, [eax+4] + + + *buf++ = 0xB8; *(void **) buf = destptr; buf+=4; // mov eax, directvalue + *buf++ = 0x89; *buf++ = 0x38; // mov [eax], edi + *buf++ = 0x89; *buf++ = 0x48; *buf++ = 0x04; // mov [eax+4], ecx + } + + return 2 + 3 + 5 + 2 + 3; + } + + static int GLUE_POP_FPSTACK_TO_PTR(unsigned char *buf, void *destptr) + { + if (buf) + { + *buf++ = 0xB8; *(void **) buf = destptr; buf+=4; // mov eax, directvalue + *buf++ = 0xDD; *buf++ = 0x18; // fstp qword [eax] + } + return 1+4+2; + } + + + #define GLUE_MOV_PX_DIRECTVALUE_SIZE 5 + #define GLUE_MOV_PX_DIRECTVALUE_TOSTACK_SIZE 6 // length when wv == -1 + + static void GLUE_MOV_PX_DIRECTVALUE_GEN(void *b, INT_PTR v, int wv) + { + if (wv==-1) + { + const static unsigned char t[2] = {0xDD, 0x05}; + memcpy(b,t,2); + b= ((unsigned char *)b)+2; + } + else + { + const static unsigned char tab[3] = { + 0xB8 /* mov eax, dv*/, + 0xBF /* mov edi, dv */ , + 0xB9 /* mov ecx, dv */ + }; + *((unsigned char *)b) = tab[wv]; // mov eax, dv + b= ((unsigned char *)b)+1; + } + *(INT_PTR *)b = v; + } + const static unsigned char GLUE_PUSH_P1[4]={0x83, 0xEC, 12, 0x50}; // sub esp, 12, push eax + + #define GLUE_STORE_P1_TO_STACK_AT_OFFS_SIZE(x) 7 + static void GLUE_STORE_P1_TO_STACK_AT_OFFS(void *b, int offs) + { + ((unsigned char *)b)[0] = 0x89; // mov [esp+offs], eax + ((unsigned char *)b)[1] = 0x84; + ((unsigned char *)b)[2] = 0x24; + *(int *)((unsigned char *)b+3) = offs; + } + + #define GLUE_MOVE_PX_STACKPTR_SIZE 2 + static void GLUE_MOVE_PX_STACKPTR_GEN(void *b, int wv) + { + static const unsigned char tab[3][GLUE_MOVE_PX_STACKPTR_SIZE]= + { + { 0x89, 0xe0 }, // mov eax, esp + { 0x89, 0xe7 }, // mov edi, esp + { 0x89, 0xe1 }, // mov ecx, esp + }; + memcpy(b,tab[wv],GLUE_MOVE_PX_STACKPTR_SIZE); + } + + #define GLUE_MOVE_STACK_SIZE 6 + static void GLUE_MOVE_STACK(void *b, int amt) + { + ((unsigned char *)b)[0] = 0x81; + if (amt <0) + { + ((unsigned char *)b)[1] = 0xEC; + *(int *)((char*)b+2) = -amt; // sub esp, -amt + } + else + { + ((unsigned char *)b)[1] = 0xc4; + *(int *)((char*)b+2) = amt; // add esp, amt + } + } + + + #define GLUE_POP_PX_SIZE 4 + static void GLUE_POP_PX(void *b, int wv) + { + static const unsigned char tab[3][GLUE_POP_PX_SIZE]= + { + {0x58,/*pop eax*/ 0x83, 0xC4, 12 /* add esp, 12*/}, + {0x5F,/*pop edi*/ 0x83, 0xC4, 12}, + {0x59,/*pop ecx*/ 0x83, 0xC4, 12}, + }; + memcpy(b,tab[wv],GLUE_POP_PX_SIZE); + } + + #define GLUE_SET_PX_FROM_P1_SIZE 2 + static void GLUE_SET_PX_FROM_P1(void *b, int wv) + { + static const unsigned char tab[3][GLUE_SET_PX_FROM_P1_SIZE]={ + {0x90,0x90}, // should never be used! (nopnop) + {0x89,0xC7}, // mov edi, eax + {0x89,0xC1}, // mov ecx, eax + }; + memcpy(b,tab[wv],GLUE_SET_PX_FROM_P1_SIZE); + } + + #define GLUE_POP_FPSTACK_SIZE 2 + static const unsigned char GLUE_POP_FPSTACK[2] = { 0xDD, 0xD8 }; // fstp st0 + + static const unsigned char GLUE_POP_FPSTACK_TOSTACK[] = { + 0x83, 0xEC, 16, // sub esp, 16 + 0xDD, 0x1C, 0x24 // fstp qword (%esp) + }; + + static const unsigned char GLUE_POP_STACK_TO_FPSTACK[] = { + 0xDD, 0x04, 0x24, // fld qword (%esp) + 0x83, 0xC4, 16 // add esp, 16 + }; + + static const unsigned char GLUE_POP_FPSTACK_TO_WTP[] = { + 0xDD, 0x1E, /* fstp qword [esi] */ + 0x83, 0xC6, 8, /* add esi, 8 */ + }; + + #define GLUE_SET_PX_FROM_WTP_SIZE 2 + static void GLUE_SET_PX_FROM_WTP(void *b, int wv) + { + static const unsigned char tab[3][GLUE_SET_PX_FROM_WTP_SIZE]={ + {0x89,0xF0}, // mov eax, esi + {0x89,0xF7}, // mov edi, esi + {0x89,0xF1}, // mov ecx, esi + }; + memcpy(b,tab[wv],GLUE_SET_PX_FROM_WTP_SIZE); + } + + #define GLUE_PUSH_VAL_AT_PX_TO_FPSTACK_SIZE 2 + static void GLUE_PUSH_VAL_AT_PX_TO_FPSTACK(void *b, int wv) + { + static const unsigned char tab[3][GLUE_PUSH_VAL_AT_PX_TO_FPSTACK_SIZE]={ + {0xDD,0x00}, // fld qword [eax] + {0xDD,0x07}, // fld qword [edi] + {0xDD,0x01}, // fld qword [ecx] + }; + memcpy(b,tab[wv],GLUE_PUSH_VAL_AT_PX_TO_FPSTACK_SIZE); + } + +#define GLUE_POP_FPSTACK_TO_WTP_TO_PX_SIZE (GLUE_SET_PX_FROM_WTP_SIZE + sizeof(GLUE_POP_FPSTACK_TO_WTP)) +static void GLUE_POP_FPSTACK_TO_WTP_TO_PX(unsigned char *buf, int wv) +{ + GLUE_SET_PX_FROM_WTP(buf,wv); + memcpy(buf + GLUE_SET_PX_FROM_WTP_SIZE,GLUE_POP_FPSTACK_TO_WTP,sizeof(GLUE_POP_FPSTACK_TO_WTP)); +}; + + +const static unsigned char GLUE_RET=0xC3; + +static int GLUE_RESET_WTP(unsigned char *out, void *ptr) +{ + if (out) + { + *out++ = 0xBE; // mov esi, constant + memcpy(out,&ptr,sizeof(void *)); + out+=sizeof(void *); + } + return 1+sizeof(void *); +} + + +#ifdef _MSC_VER +#pragma warning(push) +#pragma warning(disable: 4731) +#endif + +#define GLUE_TABPTR_IGNORED +#define GLUE_CALL_CODE(bp, cp, rt) do { \ + if (h->compile_flags&NSEEL_CODE_COMPILE_FLAG_NOFPSTATE) eel_callcode32_fast(cp, rt); \ + else eel_callcode32(cp, rt);\ + } while(0) + +static void eel_callcode32(INT_PTR cp, INT_PTR ramptr) +{ + #ifndef NSEEL_EEL1_COMPAT_MODE + short oldsw, newsw; + #endif + #ifdef _MSC_VER + + __asm + { +#ifndef NSEEL_EEL1_COMPAT_MODE + fnstcw [oldsw] + mov ax, [oldsw] + or ax, 0xE3F // 53 or 64 bit precision (depending on whether 0x100 is set), trunc, and masking all exceptions + mov [newsw], ax + fldcw [newsw] +#endif + + mov eax, cp + mov ebx, ramptr + + pushad + mov ebp, esp + and esp, -16 + + // on win32, which _MSC_VER implies, we keep things aligned to 16 bytes, and if we call a win32 function, + // the stack is 16 byte aligned before the call, meaning that if calling a function with no frame pointer, + // the stack would be aligned to a 16 byte boundary +4, which isn't good for performance. Having said that, + // normally we compile with frame pointers (which brings that to 16 byte + 8, which is fine), or ICC, which + // for nontrivial functions will align the stack itself (for very short functions, it appears to weigh the + // cost of aligning the stack vs that of the slower misaligned double accesses). + + // it may be worthwhile (at some point) to put some logic in the code that calls out to functions + // (generic1parm etc) to detect which alignment would be most optimal. + sub esp, 12 + call eax + mov esp, ebp + popad +#ifndef NSEEL_EEL1_COMPAT_MODE + fldcw [oldsw] +#endif + }; + + #else // gcc x86 + __asm__( +#ifndef NSEEL_EEL1_COMPAT_MODE + "fnstcw %2\n" + "movw %2, %%ax\n" + "orw $0xE3F, %%ax\n" // 53 or 64 bit precision (depending on whether 0x100 is set), trunc, and masking all exceptions + "movw %%ax, %3\n" + "fldcw %3\n" +#endif + "pushl %%ebx\n" + "movl %%ecx, %%ebx\n" + "pushl %%ebp\n" + "movl %%esp, %%ebp\n" + "andl $-16, %%esp\n" // align stack to 16 bytes + "subl $12, %%esp\n" // call will push 4 bytes on stack, align for that + "call *%%edx\n" + "leave\n" + "popl %%ebx\n" +#ifndef NSEEL_EEL1_COMPAT_MODE + "fldcw %2\n" +#endif + :: + "d" (cp), "c" (ramptr) +#ifndef NSEEL_EEL1_COMPAT_MODE + , "m" (oldsw), "m" (newsw) +#endif + : "%eax","%esi","%edi"); + #endif //gcc x86 +} + +void eel_enterfp(int s[2]) +{ + #ifdef _MSC_VER + __asm + { + mov ecx, s + fnstcw [ecx] + mov ax, [ecx] + or ax, 0xE3F // 53 or 64 bit precision (depending on whether 0x100 is set), trunc, and masking all exceptions + mov [ecx+4], ax + fldcw [ecx+4] + }; + #else + __asm__( + "fnstcw (%%ecx)\n" + "movw (%%ecx), %%ax\n" + "orw $0xE3F, %%ax\n" // 53 or 64 bit precision (depending on whether 0x100 is set), trunc, and masking all exceptions + "movw %%ax, 4(%%ecx)\n" + "fldcw 4(%%ecx)\n" + :: "c" (s) : "%eax"); + #endif +} +void eel_leavefp(int s[2]) +{ + #ifdef _MSC_VER + __asm + { + mov ecx, s + fldcw [ecx] + }; + #else + __asm__( + "fldcw (%%ecx)\n" + :: "c" (s) : "%eax"); + #endif +} + +static void eel_callcode32_fast(INT_PTR cp, INT_PTR ramptr) +{ + #ifdef _MSC_VER + + __asm + { + mov eax, cp + mov ebx, ramptr + + pushad + mov ebp, esp + and esp, -16 + + // on win32, which _MSC_VER implies, we keep things aligned to 16 bytes, and if we call a win32 function, + // the stack is 16 byte aligned before the call, meaning that if calling a function with no frame pointer, + // the stack would be aligned to a 16 byte boundary +4, which isn't good for performance. Having said that, + // normally we compile with frame pointers (which brings that to 16 byte + 8, which is fine), or ICC, which + // for nontrivial functions will align the stack itself (for very short functions, it appears to weigh the + // cost of aligning the stack vs that of the slower misaligned double accesses). + + // it may be worthwhile (at some point) to put some logic in the code that calls out to functions + // (generic1parm etc) to detect which alignment would be most optimal. + sub esp, 12 + call eax + mov esp, ebp + popad + }; + + #else // gcc x86 + __asm__( + "pushl %%ebx\n" + "movl %%ecx, %%ebx\n" + "pushl %%ebp\n" + "movl %%esp, %%ebp\n" + "andl $-16, %%esp\n" // align stack to 16 bytes + "subl $12, %%esp\n" // call will push 4 bytes on stack, align for that + "call *%%edx\n" + "leave\n" + "popl %%ebx\n" + :: + "d" (cp), "c" (ramptr) + : "%eax","%esi","%edi"); + #endif //gcc x86 +} + +#ifdef _MSC_VER +#pragma warning(pop) +#endif + + +static unsigned char *EEL_GLUE_set_immediate(void *_p, INT_PTR newv) +{ + char *p=(char*)_p; + INT_PTR scan = 0xFEFEFEFE; + while (*(INT_PTR *)p != scan) p++; + *(INT_PTR *)p = newv; + return (unsigned char *) (((INT_PTR*)p)+1); +} + +#define INT_TO_LECHARS(x) ((x)&0xff),(((x)>>8)&0xff), (((x)>>16)&0xff), (((x)>>24)&0xff) + + +#define GLUE_INLINE_LOOPS + +static const unsigned char GLUE_LOOP_LOADCNT[]={ + 0xDB, 0x1E, //fistp dword [esi] + 0x8B, 0x0E, // mov ecx, [esi] + 0x81, 0xf9, 1,0,0,0, // cmp ecx, 1 + 0x0F, 0x8C, 0,0,0,0, // JL <skipptr> +}; + +#if NSEEL_LOOPFUNC_SUPPORT_MAXLEN > 0 +#define GLUE_LOOP_CLAMPCNT_SIZE sizeof(GLUE_LOOP_CLAMPCNT) +static const unsigned char GLUE_LOOP_CLAMPCNT[]={ + 0x81, 0xf9, INT_TO_LECHARS(NSEEL_LOOPFUNC_SUPPORT_MAXLEN), // cmp ecx, NSEEL_LOOPFUNC_SUPPORT_MAXLEN + 0x0F, 0x8C, 5,0,0,0, // JL over-the-mov + 0xB9, INT_TO_LECHARS(NSEEL_LOOPFUNC_SUPPORT_MAXLEN), // mov ecx, NSEEL_LOOPFUNC_SUPPORT_MAXLEN +}; +#else + +#define GLUE_LOOP_CLAMPCNT_SIZE 0 +#define GLUE_LOOP_CLAMPCNT "" + +#endif + +#define GLUE_LOOP_BEGIN_SIZE sizeof(GLUE_LOOP_BEGIN) +static const unsigned char GLUE_LOOP_BEGIN[]={ + 0x56, //push esi + 0x51, // push ecx + 0x81, 0xEC, 0x08, 0,0,0, // sub esp, 8 +}; +static const unsigned char GLUE_LOOP_END[]={ + 0x81, 0xC4, 0x08, 0,0,0, // add esp, 8 + 0x59, //pop ecx + 0x5E, // pop esi + 0x49, // dec ecx + 0x0f, 0x85, 0,0,0,0, // jnz ... +}; + + +#if NSEEL_LOOPFUNC_SUPPORT_MAXLEN > 0 +#define GLUE_WHILE_SETUP_SIZE sizeof(GLUE_WHILE_SETUP) +static const unsigned char GLUE_WHILE_SETUP[]={ + 0xB9, INT_TO_LECHARS(NSEEL_LOOPFUNC_SUPPORT_MAXLEN), // mov ecx, NSEEL_LOOPFUNC_SUPPORT_MAXLEN +}; +static const unsigned char GLUE_WHILE_BEGIN[]={ + 0x56, //push esi + 0x51, // push ecx + 0x81, 0xEC, 0x08, 0,0,0, // sub esp, 8 +}; +static const unsigned char GLUE_WHILE_END[]={ + 0x81, 0xC4, 0x08, 0,0,0, // add esp, 8 + 0x59, //pop ecx + 0x5E, // pop esi + + + 0x49, // dec ecx + 0x0f, 0x84, 0,0,0,0, // jz endpt +}; + + +#else + +#define GLUE_WHILE_SETUP_SIZE 0 +#define GLUE_WHILE_SETUP "" +#define GLUE_WHILE_END_NOJUMP +static const unsigned char GLUE_WHILE_BEGIN[]={ + 0x56, //push esi + 0x81, 0xEC, 12, 0,0,0, // sub esp, 12 +}; +static const unsigned char GLUE_WHILE_END[]={ + 0x81, 0xC4, 12, 0,0,0, // add esp, 12 + 0x5E, // pop esi +}; + +#endif + +static const unsigned char GLUE_WHILE_CHECK_RV[] = { + 0x85, 0xC0, // test eax, eax + 0x0F, 0x85, 0,0,0,0 // jnz looppt +}; + +static const unsigned char GLUE_SET_P1_Z[] = { 0x29, 0xC0 }; // sub eax, eax +static const unsigned char GLUE_SET_P1_NZ[] = { 0xb0, 0x01 }; // mov al, 1 + +#define GLUE_HAS_FXCH +static const unsigned char GLUE_FXCH[] = {0xd9, 0xc9}; + +#define GLUE_HAS_FLDZ +static const unsigned char GLUE_FLDZ[] = {0xd9, 0xee}; +#define GLUE_HAS_FLD1 +static const unsigned char GLUE_FLD1[] = {0xd9, 0xe8}; + +static EEL_F negativezeropointfive=-0.5f; +static EEL_F onepointfive=1.5f; +#define GLUE_INVSQRT_NEEDREPL &negativezeropointfive, &onepointfive, + + +#define GLUE_HAS_NATIVE_TRIGSQRTLOG + +static void *GLUE_realAddress(void *fn, void *fn_e, int *size) +{ + static const unsigned char sig[12] = { 0x89, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90 }; + unsigned char *p = (unsigned char *)fn; + + #if defined(_DEBUG) && defined(_MSC_VER) + if (*p == 0xE9) // this means jump to the following address (debug stub) + { + p += 5 + *(int *)(p+1); + } + #endif + + while (memcmp(p,sig,sizeof(sig))) p++; + p+=sizeof(sig); + fn = p; + + while (memcmp(p,sig,sizeof(sig))) p++; + *size = p - (unsigned char *)fn; + return fn; +} + +#endif diff --git a/Src/ns-eel2/glue_x86_64.h b/Src/ns-eel2/glue_x86_64.h new file mode 100644 index 00000000..addaa882 --- /dev/null +++ b/Src/ns-eel2/glue_x86_64.h @@ -0,0 +1,261 @@ +#ifndef _NSEEL_GLUE_X86_64_H_ +#define _NSEEL_GLUE_X86_64_H_ + +#define GLUE_MAX_FPSTACK_SIZE 8 +#define GLUE_JMP_SET_OFFSET(endOfInstruction,offset) (((int *)(endOfInstruction))[-1] = (offset)) + +#define GLUE_PREFER_NONFP_DV_ASSIGNS + +static const unsigned char GLUE_JMP_NC[] = { 0xE9, 0,0,0,0, }; // jmp<offset> +static const unsigned char GLUE_JMP_IF_P1_Z[] = {0x85, 0xC0, 0x0F, 0x84, 0,0,0,0 }; // test eax, eax, jz +static const unsigned char GLUE_JMP_IF_P1_NZ[] = {0x85, 0xC0, 0x0F, 0x85, 0,0,0,0 }; // test eax, eax, jnz + + +#define GLUE_FUNC_ENTER_SIZE 0 +#define GLUE_FUNC_LEAVE_SIZE 0 +const static unsigned int GLUE_FUNC_ENTER[1]; +const static unsigned int GLUE_FUNC_LEAVE[1]; + + // on x86-64: + // stack is always 16 byte aligned + // pushing values to the stack (for eel functions) has alignment pushed first, then value (value is at the lower address) + // pushing pointers to the stack has the pointer pushed first, then the alignment (pointer is at the higher address) + #define GLUE_MOV_PX_DIRECTVALUE_SIZE 10 + static void GLUE_MOV_PX_DIRECTVALUE_GEN(void *b, INT_PTR v, int wr) { + const static unsigned short tab[3] = + { + 0xB848 /* mov rax, dv*/, + 0xBF48 /* mov rdi, dv */ , + 0xB948 /* mov rcx, dv */ + }; + unsigned short *bb = (unsigned short *)b; + *bb++ = tab[wr]; // mov rax, directvalue + *(INT_PTR *)bb = v; + } + + const static unsigned char GLUE_PUSH_P1[2]={ 0x50,0x50}; // push rax (pointer); push rax (alignment) + + #define GLUE_POP_PX_SIZE 2 + static void GLUE_POP_PX(void *b, int wv) + { + static const unsigned char tab[3][GLUE_POP_PX_SIZE]= + { + {0x58,/*pop eax*/ 0x58}, // pop alignment, then pop pointer + {0x5F,/*pop edi*/ 0x5F}, + {0x59,/*pop ecx*/ 0x59}, + }; + memcpy(b,tab[wv],GLUE_POP_PX_SIZE); + } + + static const unsigned char GLUE_PUSH_P1PTR_AS_VALUE[] = + { + 0x50, /*push rax - for alignment */ + 0xff, 0x30, /* push qword [rax] */ + }; + + static int GLUE_POP_VALUE_TO_ADDR(unsigned char *buf, void *destptr) // trashes P2 (rdi) and P3 (rcx) + { + if (buf) + { + *buf++ = 0x48; *buf++ = 0xB9; *(void **) buf = destptr; buf+=8; // mov rcx, directvalue + *buf++ = 0x8f; *buf++ = 0x01; // pop qword [rcx] + *buf++ = 0x5F ; // pop rdi (alignment, safe to trash rdi though) + } + return 1+10+2; + } + + static int GLUE_COPY_VALUE_AT_P1_TO_PTR(unsigned char *buf, void *destptr) // trashes P2/P3 + { + if (buf) + { + *buf++ = 0x48; *buf++ = 0xB9; *(void **) buf = destptr; buf+=8; // mov rcx, directvalue + *buf++ = 0x48; *buf++ = 0x8B; *buf++ = 0x38; // mov rdi, [rax] + *buf++ = 0x48; *buf++ = 0x89; *buf++ = 0x39; // mov [rcx], rdi + } + + return 3 + 10 + 3; + } + + static int GLUE_POP_FPSTACK_TO_PTR(unsigned char *buf, void *destptr) + { + if (buf) + { + *buf++ = 0x48; + *buf++ = 0xB8; + *(void **) buf = destptr; buf+=8; // mov rax, directvalue + *buf++ = 0xDD; *buf++ = 0x18; // fstp qword [rax] + } + return 2+8+2; + } + + + #define GLUE_SET_PX_FROM_P1_SIZE 3 + static void GLUE_SET_PX_FROM_P1(void *b, int wv) + { + static const unsigned char tab[3][GLUE_SET_PX_FROM_P1_SIZE]={ + {0x90,0x90,0x90}, // should never be used! (nopnop) + {0x48,0x89,0xC7}, // mov rdi, rax + {0x48,0x89,0xC1}, // mov rcx, rax + }; + memcpy(b,tab[wv],GLUE_SET_PX_FROM_P1_SIZE); + } + + + #define GLUE_POP_FPSTACK_SIZE 2 + static const unsigned char GLUE_POP_FPSTACK[2] = { 0xDD, 0xD8 }; // fstp st0 + + static const unsigned char GLUE_POP_FPSTACK_TOSTACK[] = { + 0x48, 0x81, 0xEC, 16, 0,0,0, // sub rsp, 16 + 0xDD, 0x1C, 0x24 // fstp qword (%rsp) + }; + + static const unsigned char GLUE_POP_FPSTACK_TO_WTP[] = { + 0xDD, 0x1E, /* fstp qword [rsi] */ + 0x48, 0x81, 0xC6, 8, 0,0,0,/* add rsi, 8 */ + }; + + #define GLUE_SET_PX_FROM_WTP_SIZE 3 + static void GLUE_SET_PX_FROM_WTP(void *b, int wv) + { + static const unsigned char tab[3][GLUE_SET_PX_FROM_WTP_SIZE]={ + {0x48, 0x89,0xF0}, // mov rax, rsi + {0x48, 0x89,0xF7}, // mov rdi, rsi + {0x48, 0x89,0xF1}, // mov rcx, rsi + }; + memcpy(b,tab[wv],GLUE_SET_PX_FROM_WTP_SIZE); + } + + #define GLUE_PUSH_VAL_AT_PX_TO_FPSTACK_SIZE 2 + static void GLUE_PUSH_VAL_AT_PX_TO_FPSTACK(void *b, int wv) + { + static const unsigned char tab[3][GLUE_PUSH_VAL_AT_PX_TO_FPSTACK_SIZE]={ + {0xDD,0x00}, // fld qword [rax] + {0xDD,0x07}, // fld qword [rdi] + {0xDD,0x01}, // fld qword [rcx] + }; + memcpy(b,tab[wv],GLUE_PUSH_VAL_AT_PX_TO_FPSTACK_SIZE); + } + static unsigned char GLUE_POP_STACK_TO_FPSTACK[] = { + 0xDD, 0x04, 0x24, // fld qword (%rsp) + 0x48, 0x81, 0xC4, 16, 0,0,0, // add rsp, 16 + }; + + +#define GLUE_POP_FPSTACK_TO_WTP_TO_PX_SIZE (GLUE_SET_PX_FROM_WTP_SIZE + sizeof(GLUE_POP_FPSTACK_TO_WTP)) +static void GLUE_POP_FPSTACK_TO_WTP_TO_PX(unsigned char *buf, int wv) +{ + GLUE_SET_PX_FROM_WTP(buf,wv); + memcpy(buf + GLUE_SET_PX_FROM_WTP_SIZE,GLUE_POP_FPSTACK_TO_WTP,sizeof(GLUE_POP_FPSTACK_TO_WTP)); +}; + + +const static unsigned char GLUE_RET=0xC3; + +static int GLUE_RESET_WTP(unsigned char *out, void *ptr) +{ + if (out) + { + *out++ = 0x48; + *out++ = 0xBE; // mov rsi, constant64 + *(void **)out = ptr; + out+=sizeof(void *); + } + return 2+sizeof(void *); +} + +extern void win64_callcode(INT_PTR code, INT_PTR ram_tab); +#define GLUE_CALL_CODE(bp, cp, rt) win64_callcode(cp, rt) + +static unsigned char *EEL_GLUE_set_immediate(void *_p, INT_PTR newv) +{ + char *p=(char*)_p; + INT_PTR scan = 0xFEFEFEFEFEFEFEFE; + while (*(INT_PTR *)p != scan) p++; + *(INT_PTR *)p = newv; + return (unsigned char *) (((INT_PTR*)p)+1); +} + +#define INT_TO_LECHARS(x) ((x)&0xff),(((x)>>8)&0xff), (((x)>>16)&0xff), (((x)>>24)&0xff) + +#define GLUE_INLINE_LOOPS + +static const unsigned char GLUE_LOOP_LOADCNT[]={ + 0xDD, 0x0E, //fistTp qword [rsi] + 0x48, 0x8B, 0x0E, // mov rcx, [rsi] + 0x48, 0x81, 0xf9, 1,0,0,0, // cmp rcx, 1 + 0x0F, 0x8C, 0,0,0,0, // JL <skipptr> +}; +static const unsigned char GLUE_LOOP_CLAMPCNT[]={ + 0x48, 0x81, 0xf9, INT_TO_LECHARS(NSEEL_LOOPFUNC_SUPPORT_MAXLEN), // cmp rcx, NSEEL_LOOPFUNC_SUPPORT_MAXLEN + 0x0F, 0x8C, 10,0,0,0, // JL over-the-mov + 0x48, 0xB9, INT_TO_LECHARS(NSEEL_LOOPFUNC_SUPPORT_MAXLEN), 0,0,0,0, // mov rcx, NSEEL_LOOPFUNC_SUPPORT_MAXLEN +}; +static const unsigned char GLUE_LOOP_BEGIN[]={ + 0x56, //push rsi + 0x51, // push rcx +}; +static const unsigned char GLUE_LOOP_END[]={ + 0x59, //pop rcx + 0x5E, // pop rsi + 0xff, 0xc9, // dec rcx + 0x0f, 0x85, 0,0,0,0, // jnz ... +}; + + + +static const unsigned char GLUE_WHILE_SETUP[]={ + 0x48, 0xB9, INT_TO_LECHARS(NSEEL_LOOPFUNC_SUPPORT_MAXLEN), 0,0,0,0, // mov rcx, NSEEL_LOOPFUNC_SUPPORT_MAXLEN +}; +static const unsigned char GLUE_WHILE_BEGIN[]={ + 0x56, //push rsi + 0x51, // push rcx +}; +static const unsigned char GLUE_WHILE_END[]={ + 0x59, //pop rcx + 0x5E, // pop rsi + + 0xff, 0xc9, // dec rcx + 0x0f, 0x84, 0,0,0,0, // jz endpt +}; +static const unsigned char GLUE_WHILE_CHECK_RV[] = { + 0x85, 0xC0, // test eax, eax + 0x0F, 0x85, 0,0,0,0 // jnz looppt +}; + +static const unsigned char GLUE_SET_P1_Z[] = { 0x48, 0x29, 0xC0 }; // sub rax, rax +static const unsigned char GLUE_SET_P1_NZ[] = { 0xb0, 0x01 }; // mov al, 1 + + +#define GLUE_HAS_FXCH +static const unsigned char GLUE_FXCH[] = {0xd9, 0xc9}; + +#define GLUE_HAS_FLDZ +static const unsigned char GLUE_FLDZ[] = {0xd9, 0xee}; +#define GLUE_HAS_FLD1 +static const unsigned char GLUE_FLD1[] = {0xd9, 0xe8}; + + +static EEL_F negativezeropointfive=-0.5f; +static EEL_F onepointfive=1.5f; +#define GLUE_INVSQRT_NEEDREPL &negativezeropointfive, &onepointfive, + +#define GLUE_HAS_NATIVE_TRIGSQRTLOG + + +static void *GLUE_realAddress(void *fn, void *fn_e, int *size) +{ + static const unsigned char sig[12] = { 0x89, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90 }; + unsigned char *p = (unsigned char *)fn; + + while (memcmp(p,sig,sizeof(sig))) p++; + p+=sizeof(sig); + fn = p; + + while (memcmp(p,sig,sizeof(sig))) p++; + *size = p - (unsigned char *)fn; + return fn; +} + +// end of x86-64 + +#endif diff --git a/Src/ns-eel2/ns-eel-addfuncs.h b/Src/ns-eel2/ns-eel-addfuncs.h new file mode 100644 index 00000000..2f88d144 --- /dev/null +++ b/Src/ns-eel2/ns-eel-addfuncs.h @@ -0,0 +1,81 @@ +/* + Nullsoft Expression Evaluator Library (NS-EEL) + Copyright (C) 1999-2003 Nullsoft, Inc. + + ns-eel-addfuncs.h: defines macros useful for adding functions to the compiler + + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any damages + arising from the use of this software. + + Permission is granted to anyone to use this software for any purpose, + including commercial applications, and to alter it and redistribute it + freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. + 2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. + 3. This notice may not be removed or altered from any source distribution. +*/ + +#ifndef __NS_EEL_ADDFUNCS_H__ +#define __NS_EEL_ADDFUNCS_H__ + +#ifdef __cplusplus +extern "C" { +#endif + +struct _compileContext; + +void *NSEEL_PProc_RAM(void *data, int data_size, struct _compileContext *ctx); +void *NSEEL_PProc_THIS(void *data, int data_size, struct _compileContext *ctx); + + +#ifdef EEL_TARGET_PORTABLE + +extern EEL_BC_TYPE _asm_generic3parm[]; // 3 double * parms, returning double * +extern EEL_BC_TYPE _asm_generic3parm_retd[]; // 3 double * parms, returning double +extern EEL_BC_TYPE _asm_generic2parm[]; // 2 double * parms, returning double * +extern EEL_BC_TYPE _asm_generic2parm_retd[]; // 2 double * parms, returning double +extern EEL_BC_TYPE _asm_generic1parm[]; // 1 double * parms, returning double * +extern EEL_BC_TYPE _asm_generic1parm_retd[]; // 1 double * parms, returning double + +extern const void *const _asm_generic1parm_retd_end; +extern const void *const _asm_generic1parm_end; +extern const void *const _asm_generic2parm_retd_end; +extern const void *const _asm_generic2parm_end; +extern const void *const _asm_generic3parm_retd_end; +extern const void *const _asm_generic3parm_end; +#else + +void _asm_generic3parm(void); // 3 double * parms, returning double * +void _asm_generic3parm_end(void); +void _asm_generic3parm_retd(void); // 3 double * parms, returning double +void _asm_generic3parm_retd_end(void); +void _asm_generic2parm(void); // 2 double * parms, returning double * +void _asm_generic2parm_end(void); +void _asm_generic2parm_retd(void); // 2 double * parms, returning double +void _asm_generic2parm_retd_end(void); +void _asm_generic1parm(void); // 1 double * parms, returning double * +void _asm_generic1parm_end(void); +void _asm_generic1parm_retd(void); // 1 double * parms, returning double +void _asm_generic1parm_retd_end(void); + +#endif + +#if EEL_F_SIZE == 4 +#define EEL_F_SSTR "4" +#define EEL_F_SUFFIX "s" +#else +#define EEL_F_SSTR "8" +#define EEL_F_SUFFIX "l" +#endif + +#ifdef __cplusplus +}; + +#endif +#endif//__NS_EEL_ADDFUNCS_H__ diff --git a/Src/ns-eel2/ns-eel-func-ref.h b/Src/ns-eel2/ns-eel-func-ref.h new file mode 100644 index 00000000..9c2833e3 --- /dev/null +++ b/Src/ns-eel2/ns-eel-func-ref.h @@ -0,0 +1,62 @@ +#ifndef _NSEEL_FUNC_REF_H_ +#define _NSEEL_FUNC_REF_H_ + +#include "ns-eel.h" +#define TMP_MKSTR2(x) #x +#define TMP_MKSTR(x) TMP_MKSTR2(x) + +const char *nseel_builtin_function_reference= + "while\texpression\tExecutes expression until expression evaluates to zero" +#if NSEEL_LOOPFUNC_SUPPORT_MAXLEN + ", or until " TMP_MKSTR(NSEEL_LOOPFUNC_SUPPORT_MAXLEN) "iterations occur" +#endif + ". An alternate and more useful syntax is while (expression) ( statements ), which evaluates statements after " + "every non-zero evaluation of expression.\0" + "loop\tcount,expression\tEvaluates count once, and then executes expression count" +#if NSEEL_LOOPFUNC_SUPPORT_MAXLEN + ", but not more than " TMP_MKSTR(NSEEL_LOOPFUNC_SUPPORT_MAXLEN) "," +#endif + " times.\0" + "sin\tangle\tReturns the sine of the angle specified (specified in radians -- to convert from degrees to radians, multiply by $pi/180, or 0.017453).\0" + "cos\tangle\tReturns the cosine of the angle specified (specified in radians).\0" + "tan\tangle\tReturns the tangent of the angle specified (specified in radians).\0" + "sqrt\tvalue\tReturns the square root of the parameter. If the parameter is negative, the return value is undefined.\0" + "log\tvalue\tReturns the natural logarithm (base e) of the parameter. If the value is not greater than 0, the return value is undefined.\0" + "log10\tvalue\tReturns the base-10 logarithm of the parameter. If the value is not greater than 0, the return value is undefined.\0" + "asin\tvalue\tReturns the arc sine of the value specified (return value is in radians). If the parameter is not between -1.0 and 1.0 inclusive, the return value is undefined.\0" + "acos\tvalue\tReturns the arc cosine of the value specified (return value is in radians). If the parameter is not between -1.0 and 1.0 inclusive, the return value is undefined.\0" + "atan\tvalue\tReturns the arc tangent of the value specified (return value is in radians). If the parameter is not between -1.0 and 1.0 inclusive, the return value is undefined.\0" + "atan2\tnumerator,denominator\tReturns the arc tangent of the numerator divided by the denominator, allowing the denominator to be 0, and using their signs to produce a more meaningful result.\0" + "exp\texponent\tReturns the number e ($e, approximately 2.718) raised to the parameter-th power. This function is significantly faster than pow() or the ^ operator.\0" + "abs\tvalue\tReturns the absolute value of the parameter.\0" + "sqr\tvalue\tReturns the square of the parameter (similar to value*value, but only evaluating value once).\0" + "min\t&value,&value\tReturns (by reference) the minimum value of the two parameters. Since min() returns by reference, expressions such as min(x,y) = 5 are possible.\0" + "max\t&value,&value\tReturns (by reference) the maximum value of the two parameters. Since max() returns by reference, expressions such as max(x,y) = 5 are possible.\0" + "sign\tvalue\tReturns 1.0 if the parameter is greater than 0, -1.0 if the parameter is less than 0, or 0 if the parameter is 0.\0" + "floor\tvalue\tReturns the value rounded to the next lowest integer (floor(3.9)==3, floor(-3.1)==-4).\0" + "ceil\tvalue\tReturns the value rounded to the next highest integer (ceil(3.1)==4, ceil(-3.9)==-3).\0" + "invsqrt\tvalue\tReturns a fast inverse square root (1/sqrt(x)) approximation of the parameter.\0" + "freembuf\taddress\tHints the runtime that memory above the address specified may no longer be used. The runtime may, at its leisure, choose to lose the contents of memory above the address specified.\0" + "memcpy\tdest,src,length\tCopies length items of memory from src to dest. Regions are permitted to overlap.\0" + "memset\toffset,value,length\tSets length items of memory at offset to value.\0" + "mem_get_values\toffset, ...\tReads values from memory starting at offset into variables specified. Slower than regular memory reads for less than a few variables, faster for more than a few. Undefined behavior if used with more than 32767 variables.\0" + "mem_set_values\toffset, ...\tWrites values to memory starting at offset from variables specified. Slower than regular memory writes for less than a few variables, faster for more than a few. Undefined behavior if used with more than 32767 variables.\0" + "stack_push\t&value\tPushes value onto the user stack, returns a reference to the parameter.\0" + "stack_pop\t&value\tPops a value from the user stack into value, or into a temporary buffer if value is not specified, and returns a reference to where the stack was popped. Note that no checking is done to determine if the stack is empty, and as such stack_pop() will never fail.\0" + "stack_peek\tindex\tReturns a reference to the item on the top of the stack (if index is 0), or to the Nth item on the stack if index is greater than 0. \0" + "stack_exch\t&value\tExchanges a value with the top of the stack, and returns a reference to the parameter (with the new value).\0" +#ifdef NSEEL_EEL1_COMPAT_MODE + "rand\tmax\tReturns a psuedorandom non-negative integer number less than the parameter.\0" + "sigmoid\tvalue,constraint\tReturns 1.0/(1+exp(-x * (constraint))), or 0 if a divide by 0 would occur.\0" + "band\tx,y\tReturns 1 if both x and y evaluate to nonzero, 0 if otherwise. Both parameters are always evaluated.\0" + "bor\tx,y\tReturns 1 if either x or y evaluate to nonzero, 0 if otherwise. Both parameters are always evaluated.\0" + "exec2\tx,y\tEvaluates x, then evaluates and returns y.\0" + "exec3\tx,y,z\tEvaluates x, evaluates y, then evaluates and returns z.\0" +#else + "rand\t[max]\tReturns a psuedorandom real number between 0 and the parameter, inclusive. If the parameter is omitted or less than 1.0, 1.0 is used as a maximum instead.\0" + +#endif +; +#undef TMP_MKSTR + +#endif diff --git a/Src/ns-eel2/ns-eel-int.h b/Src/ns-eel2/ns-eel-int.h new file mode 100644 index 00000000..a13478e0 --- /dev/null +++ b/Src/ns-eel2/ns-eel-int.h @@ -0,0 +1,331 @@ +/* + Nullsoft Expression Evaluator Library (NS-EEL) + Copyright (C) 1999-2003 Nullsoft, Inc. + + ns-eel-int.h: internal code definition header. + + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any damages + arising from the use of this software. + + Permission is granted to anyone to use this software for any purpose, + including commercial applications, and to alter it and redistribute it + freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. + 2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. + 3. This notice may not be removed or altered from any source distribution. +*/ + +#ifndef __NS_EELINT_H__ +#define __NS_EELINT_H__ + +#ifdef _WIN32 +#include <windows.h> +#else +#include "../wdltypes.h" +#endif + +#include "ns-eel.h" +#include "ns-eel-addfuncs.h" + +#ifdef __cplusplus +extern "C" { +#endif + + +enum { + + // these ignore fn in opcodes, just use fntype to determine function + FN_MULTIPLY=0, + FN_DIVIDE, + FN_JOIN_STATEMENTS, + FN_DENORMAL_LIKELY, + FN_DENORMAL_UNLIKELY, + FN_ADD, + FN_SUB, + FN_AND, + FN_OR, + FN_UMINUS, + FN_NOT, + FN_NOTNOT, + FN_XOR, + FN_SHL, + FN_SHR, + FN_MOD, + FN_POW, + FN_LT, + FN_GT, + FN_LTE, + FN_GTE, + FN_EQ, + FN_EQ_EXACT, + FN_NE, + FN_NE_EXACT, + FN_LOGICAL_AND, + FN_LOGICAL_OR, + FN_IF_ELSE, + FN_MEMORY, + FN_GMEMORY, + FN_NONCONST_BEGIN, + FN_ASSIGN=FN_NONCONST_BEGIN, + + FN_ADD_OP, + FN_SUB_OP, + FN_MOD_OP, + FN_OR_OP, + FN_AND_OP, + FN_XOR_OP, + FN_DIV_OP, + FN_MUL_OP, + FN_POW_OP, + + FN_WHILE, + FN_LOOP, + + FUNCTYPE_SIMPLEMAX, + + + FUNCTYPE_FUNCTIONTYPEREC=1000, // fn is a functionType * + FUNCTYPE_EELFUNC, // fn is a _codeHandleFunctionRec * +}; + + + +#define YYSTYPE opcodeRec * + +#define NSEEL_CLOSEFACTOR 0.00001 + + +typedef struct opcodeRec opcodeRec; + +typedef struct _codeHandleFunctionRec +{ + struct _codeHandleFunctionRec *next; // main linked list (only used for high level functions) + struct _codeHandleFunctionRec *derivedCopies; // separate linked list, _head being the main function, other copies being derived versions + + void *startptr; // compiled code (may be cleared + recompiled when shared) + opcodeRec *opcodes; + + int startptr_size; // 0=no code. -1 = needs calculation. >0 = size. + int tmpspace_req; + + int num_params; + + int rvMode; // RETURNVALUE_* + int fpStackUsage; // 0-8, usually + int canHaveDenormalOutput; + + // local storage's first items are the parameters, then locals. Note that the opcodes will reference localstorage[] via VARPTRPTR, but + // the values localstorage[x] points are reallocated from context-to-context, if it is a common function. + + // separately allocated list of pointers, the contents of the list should be zeroed on context changes if a common function + // note that when making variations on a function (context), it is shared, but since it is zeroed on context changes, it is context-local + int localstorage_size; + EEL_F **localstorage; + + int isCommonFunction; + int usesNamespaces; + unsigned int parameterAsNamespaceMask; + + char fname[NSEEL_MAX_FUNCSIG_NAME+1]; +} _codeHandleFunctionRec; + +#define LLB_DSIZE (65536-64) +typedef struct _llBlock { + struct _llBlock *next; + int sizeused; + char block[LLB_DSIZE]; +} llBlock; + +typedef struct { + llBlock *blocks, + *blocks_data; + void *workTable; // references a chunk in blocks_data + + void *code; + int code_size; // in case the caller wants to write it out + int code_stats[4]; + + int want_stack; + void *stack; // references a chunk in blocks_data, somewhere within the complete NSEEL_STACK_SIZE aligned at NSEEL_STACK_SIZE + + void *ramPtr; + + int workTable_size; // size (minus padding/extra space) of workTable -- only used if EEL_VALIDATE_WORKTABLE_USE set, but might be handy to have around too + int compile_flags; +} codeHandleType; + +typedef struct +{ + EEL_F *value; + int refcnt; + char isreg; + char str[1]; +} varNameRec; + +typedef struct +{ + void *ptr; + int size, alloc; +} eel_growbuf; +#define EEL_GROWBUF(type) union { eel_growbuf _growbuf; type *_tval; } +#define EEL_GROWBUF_RESIZE(gb, newsz) __growbuf_resize(&(gb)->_growbuf, (newsz)*(int)sizeof((gb)->_tval[0])) // <0 to free, does not realloc down otherwise +#define EEL_GROWBUF_GET(gb) ((gb)->_tval) +#define EEL_GROWBUF_GET_SIZE(gb) ((gb)->_growbuf.size/(int)sizeof((gb)->_tval[0])) + +typedef struct _compileContext +{ + eel_function_table *registered_func_tab; + const char *(*func_check)(const char *fn_name, void *user); // return error message if not permitted + void *func_check_user; + + EEL_GROWBUF(varNameRec *) varNameList; + EEL_F *varValueStore; + int varValueStore_left; + + int errVar,gotEndOfInput; + opcodeRec *result; + char last_error_string[256]; + + void *scanner; + const char *rdbuf_start, *rdbuf, *rdbuf_end; + + llBlock *tmpblocks_head, // used while compiling, and freed after compiling + + *blocks_head, // used while compiling, transferred to code context (these are pages marked as executable) + *blocks_head_data, // used while compiling, transferred to code context + + *pblocks; // persistent blocks, stores data used by varTable_Names, varTable_Values, etc. + + int l_stats[4]; // source bytes, static code bytes, call code bytes, data bytes + int has_used_global_vars; + + _codeHandleFunctionRec *functions_local, *functions_common; + + // state used while generating functions + int optimizeDisableFlags; + int current_compile_flags; + struct opcodeRec *directValueCache; // linked list using fn as next + + int isSharedFunctions; + int isGeneratingCommonFunction; + int function_usesNamespaces; + int function_globalFlag; // set if restrict globals to function_localTable_Names[2] + // [0] is parameter+local symbols (combined space) + // [1] is symbols which get implied "this." if used + // [2] is globals permitted + int function_localTable_Size[3]; // for parameters only + char **function_localTable_Names[3]; // lists of pointers + EEL_F **function_localTable_ValuePtrs; + const char *function_curName; // name of current function + + EEL_F (*onString)(void *caller_this, struct eelStringSegmentRec *list); + EEL_F (*onNamedString)(void *caller_this, const char *name); + + EEL_F *(*getVariable)(void *userctx, const char *name); + void *getVariable_userctx; + + codeHandleType *tmpCodeHandle; + + struct + { + int needfree; + int maxblocks; + double closefact; + EEL_F *blocks[NSEEL_RAM_BLOCKS]; + } ram_state +#ifdef __GNUC__ + __attribute__ ((aligned (8))) +#endif + ; + + void *gram_blocks; + + void *caller_this; +} +compileContext; + +#define NSEEL_NPARAMS_FLAG_CONST 0x80000 +typedef struct functionType { + const char *name; + void *afunc; + void *func_e; + int nParams; + void *replptrs[4]; + NSEEL_PPPROC pProc; +} functionType; + +functionType *nseel_getFunctionByName(compileContext *ctx, const char *name, int *mchk); // sets mchk (if non-NULL) to how far allowed to scan forward for duplicate names + +opcodeRec *nseel_createCompiledValue(compileContext *ctx, EEL_F value); +opcodeRec *nseel_createCompiledValuePtr(compileContext *ctx, EEL_F *addrValue, const char *namestr); + +opcodeRec *nseel_createMoreParametersOpcode(compileContext *ctx, opcodeRec *code1, opcodeRec *code2); +opcodeRec *nseel_createSimpleCompiledFunction(compileContext *ctx, int fn, int np, opcodeRec *code1, opcodeRec *code2); +opcodeRec *nseel_createMemoryAccess(compileContext *ctx, opcodeRec *code1, opcodeRec *code2); +opcodeRec *nseel_createIfElse(compileContext *ctx, opcodeRec *code1, opcodeRec *code2, opcodeRec *code3); +opcodeRec *nseel_createFunctionByName(compileContext *ctx, const char *name, int np, opcodeRec *code1, opcodeRec *code2, opcodeRec *code3); + +// converts a generic identifier (VARPTR) opcode into either an actual variable reference (parmcnt = -1), +// or if parmcnt >= 0, to a function call (see nseel_setCompiledFunctionCallParameters()) +opcodeRec *nseel_resolve_named_symbol(compileContext *ctx, opcodeRec *rec, int parmcnt, int *errOut); + +// sets parameters and calculates parameter count for opcode, and calls nseel_resolve_named_symbol() with the right +// parameter count +opcodeRec *nseel_setCompiledFunctionCallParameters(compileContext *ctx, opcodeRec *fn, opcodeRec *code1, opcodeRec *code2, opcodeRec *code3, opcodeRec *postCode, int *errOut); +// errOut will be set if return NULL: +// -1 if postCode set when not wanted (i.e. not while()) +// 0 if func not found, +// 1 if function requires 2+ parameters but was given more +// 2 if function needs more parameters +// 4 if function requires 1 parameter but was given more + + + +struct eelStringSegmentRec *nseel_createStringSegmentRec(compileContext *ctx, const char *str, int len); +opcodeRec *nseel_eelMakeOpcodeFromStringSegments(compileContext *ctx, struct eelStringSegmentRec *rec); + +EEL_F *nseel_int_register_var(compileContext *ctx, const char *name, int isReg, const char **namePtrOut); +_codeHandleFunctionRec *eel_createFunctionNamespacedInstance(compileContext *ctx, _codeHandleFunctionRec *fr, const char *nameptr); + +typedef struct nseel_globalVarItem +{ + EEL_F data; + struct nseel_globalVarItem *_next; + char name[1]; // varlen, does not include _global. prefix +} nseel_globalVarItem; + +extern nseel_globalVarItem *nseel_globalreg_list; // if NSEEL_EEL1_COMPAT_MODE, must use NSEEL_getglobalregs() for regxx values + +#include "y.tab.h" + +// nseel_simple_tokenizer will return comments as tokens if state is non-NULL +const char *nseel_simple_tokenizer(const char **ptr, const char *endptr, int *lenOut, int *state); +int nseel_filter_escaped_string(char *outbuf, int outbuf_sz, const char *rdptr, size_t rdptr_size, char delim_char); // returns length used, minus NUL char + +opcodeRec *nseel_translate(compileContext *ctx, const char *tmp, size_t tmplen); // tmplen=0 for nul-term +int nseel_lookup(compileContext *ctx, opcodeRec **opOut, const char *sname); + +EEL_F * NSEEL_CGEN_CALL __NSEEL_RAMAlloc(EEL_F **blocks, unsigned int w); +EEL_F * NSEEL_CGEN_CALL __NSEEL_RAMAllocGMEM(EEL_F ***blocks, unsigned int w); +EEL_F * NSEEL_CGEN_CALL __NSEEL_RAM_MemSet(EEL_F **blocks,EEL_F *dest, EEL_F *v, EEL_F *lenptr); +EEL_F * NSEEL_CGEN_CALL __NSEEL_RAM_MemFree(void *blocks, EEL_F *which); +EEL_F * NSEEL_CGEN_CALL __NSEEL_RAM_MemTop(void *blocks, EEL_F *which); +EEL_F * NSEEL_CGEN_CALL __NSEEL_RAM_MemCpy(EEL_F **blocks,EEL_F *dest, EEL_F *src, EEL_F *lenptr); +EEL_F NSEEL_CGEN_CALL __NSEEL_RAM_Mem_SetValues(EEL_F **blocks, INT_PTR np, EEL_F **parms); +EEL_F NSEEL_CGEN_CALL __NSEEL_RAM_Mem_GetValues(EEL_F **blocks, INT_PTR np, EEL_F **parms); + +extern EEL_F nseel_ramalloc_onfail; // address returned by __NSEEL_RAMAlloc et al on failure +extern EEL_F * volatile nseel_gmembuf_default; // can free/zero this on DLL unload if needed + +#ifdef __cplusplus +} +#endif + + +#endif//__NS_EELINT_H__ diff --git a/Src/ns-eel2/ns-eel.h b/Src/ns-eel2/ns-eel.h new file mode 100644 index 00000000..fabac878 --- /dev/null +++ b/Src/ns-eel2/ns-eel.h @@ -0,0 +1,275 @@ +/* + Nullsoft Expression Evaluator Library (NS-EEL) + Copyright (C) 1999-2003 Nullsoft, Inc. + + ns-eel.h: main application interface header + + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any damages + arising from the use of this software. + + Permission is granted to anyone to use this software for any purpose, + including commercial applications, and to alter it and redistribute it + freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. + 2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. + 3. This notice may not be removed or altered from any source distribution. +*/ + + +#ifndef __NS_EEL_H__ +#define __NS_EEL_H__ + +// put standard includes here +#include <stdlib.h> +#include <stdio.h> + +#ifndef EEL_F_SIZE +#define EEL_F_SIZE 8 +#endif + +#define NSEEL_EEL1_COMPAT_MODE + +#include "wdltypes.h" + +#if EEL_F_SIZE == 4 +typedef float EEL_F; +typedef float *EEL_F_PTR; +#else +typedef double EEL_F WDL_FIXALIGN; +typedef double *EEL_F_PTR; +#endif + +#ifdef _MSC_VER +#define NSEEL_CGEN_CALL __cdecl +#else +#define NSEEL_CGEN_CALL +#endif + + +#ifdef __cplusplus +extern "C" { +#endif + +// host should implement these (can be empty stub functions if no VM will execute code in multiple threads at once) + + // implement if you will be running the code in same VM from multiple threads, + // or VMs that have the same GRAM pointer from different threads, or multiple + // VMs that have a NULL GRAM pointer from multiple threads. + // if you give each VM it's own unique GRAM and only run each VM in one thread, then you can leave it blank. + + // or if you're daring.... + +void NSEEL_HOSTSTUB_EnterMutex(); +void NSEEL_HOSTSTUB_LeaveMutex(); + + +int NSEEL_init(); // returns nonzero on failure (only if EEL_VALIDATE_FSTUBS defined), otherwise the same as NSEEL_quit(), and completely optional +void NSEEL_quit(); // clears any added functions + + +// adds a function that returns a value (EEL_F) +#define NSEEL_addfunc_retval(name,np,pproc,fptr) \ + NSEEL_addfunc_ret_type(name,np,1,pproc,(void *)(fptr),NSEEL_ADDFUNC_DESTINATION) + +// adds a function that returns a pointer (EEL_F*) +#define NSEEL_addfunc_retptr(name,np,pproc,fptr) \ + NSEEL_addfunc_ret_type(name,np,0,pproc,(void *)(fptr),NSEEL_ADDFUNC_DESTINATION) + +// adds a void or bool function +#define NSEEL_addfunc_retbool(name,np,pproc,fptr) \ + NSEEL_addfunc_ret_type(name,np,-1,pproc,(void *)(fptr),NSEEL_ADDFUNC_DESTINATION) + +// adds a function that takes min_np or more parameters (func sig needs to be EEL_F func(void *ctx, INT_PTR np, EEL_F **parms) +#define NSEEL_addfunc_varparm(name, min_np, pproc, fptr) \ + NSEEL_addfunc_varparm_ex(name,min_np,0,pproc,fptr,NSEEL_ADDFUNC_DESTINATION) + +// adds a function that takes np parameters via func: sig needs to be EEL_F func(void *ctx, INT_PTR np, EEL_F **parms) +#define NSEEL_addfunc_exparms(name, np, pproc, fptr) \ + NSEEL_addfunc_varparm_ex(name,np,1,pproc,fptr,NSEEL_ADDFUNC_DESTINATION) + + +// deprecated +#define NSEEL_addfunction(name,nparms,code,len) NSEEL_addfunctionex((name),(nparms),(code),(len),0,0) +#define NSEEL_addfunctionex(name,nparms,code,len,pproc,fptr) NSEEL_addfunctionex2((name),(nparms),(code),(len),(pproc),(fptr),0, NSEEL_ADDFUNC_DESTINATION) + +#ifndef NSEEL_ADDFUNC_DESTINATION +#define NSEEL_ADDFUNC_DESTINATION (NULL) +#endif + +struct functionType; + +typedef struct +{ + struct functionType *list; + int list_size; +} eel_function_table; + +struct _compileContext; +typedef void *(*NSEEL_PPPROC)(void *data, int data_size, struct _compileContext *userfunc_data); +void NSEEL_addfunctionex2(const char *name, int nparms, char *code_startaddr, int code_len, NSEEL_PPPROC pproc, void *fptr, void *fptr2, eel_function_table *destination); + +void NSEEL_addfunc_ret_type(const char *name, int np, int ret_type, NSEEL_PPPROC pproc, void *fptr, eel_function_table *destination); // ret_type=-1 for bool, 1 for value, 0 for ptr +void NSEEL_addfunc_varparm_ex(const char *name, int min_np, int want_exact, NSEEL_PPPROC pproc, EEL_F (NSEEL_CGEN_CALL *fptr)(void *, INT_PTR, EEL_F **), eel_function_table *destination); + +int *NSEEL_getstats(); // returns a pointer to 5 ints... source bytes, static code bytes, call code bytes, data bytes, number of code handles + +typedef void *NSEEL_VMCTX; +typedef void *NSEEL_CODEHANDLE; + +NSEEL_VMCTX NSEEL_VM_alloc(); // return a handle +void NSEEL_VM_free(NSEEL_VMCTX ctx); // free when done with a VM and ALL of its code have been freed, as well + +void NSEEL_VM_SetFunctionTable(NSEEL_VMCTX, eel_function_table *tab); // use NULL to use default (global) table + +// validateFunc can return error message if not permitted +void NSEEL_VM_SetFunctionValidator(NSEEL_VMCTX, const char * (*validateFunc)(const char *fn_name, void *user), void *user); + +void NSEEL_VM_remove_unused_vars(NSEEL_VMCTX _ctx); +void NSEEL_VM_clear_var_refcnts(NSEEL_VMCTX _ctx); +void NSEEL_VM_remove_all_nonreg_vars(NSEEL_VMCTX _ctx); +void NSEEL_VM_enumallvars(NSEEL_VMCTX ctx, int (*func)(const char *name, EEL_F *val, void *ctx), void *userctx); // return false from func to stop + +EEL_F *NSEEL_VM_regvar(NSEEL_VMCTX ctx, const char *name); // register a variable (before compilation) +EEL_F *NSEEL_VM_getvar(NSEEL_VMCTX ctx, const char *name); // get a variable (if registered or created by code) +int NSEEL_VM_get_var_refcnt(NSEEL_VMCTX _ctx, const char *name); // returns -1 if not registered, or >=0 +void NSEEL_VM_set_var_resolver(NSEEL_VMCTX ctx, EEL_F *(*res)(void *userctx, const char *name), void *userctx); + +void NSEEL_VM_freeRAM(NSEEL_VMCTX ctx); // clears and frees all (VM) RAM used +void NSEEL_VM_freeRAMIfCodeRequested(NSEEL_VMCTX); // call after code to free the script-requested memory +int NSEEL_VM_wantfreeRAM(NSEEL_VMCTX ctx); // want NSEEL_VM_freeRAMIfCodeRequested? + +// if you set this, it uses a local GMEM context. +// Must be set before compilation. +// void *p=NULL; +// NSEEL_VM_SetGRAM(ctx,&p); +// .. do stuff +// NSEEL_VM_FreeGRAM(&p); +void NSEEL_VM_SetGRAM(NSEEL_VMCTX ctx, void **gram); +void NSEEL_VM_FreeGRAM(void **ufd); // frees a gmem context. +void NSEEL_VM_SetCustomFuncThis(NSEEL_VMCTX ctx, void *thisptr); + +EEL_F *NSEEL_VM_getramptr(NSEEL_VMCTX ctx, unsigned int offs, int *validCount); +EEL_F *NSEEL_VM_getramptr_noalloc(NSEEL_VMCTX ctx, unsigned int offs, int *validCount); + + +// set 0 to query. returns actual value used (limits, granularity apply -- see NSEEL_RAM_BLOCKS) +int NSEEL_VM_setramsize(NSEEL_VMCTX ctx, int maxent); + + +struct eelStringSegmentRec { + struct eelStringSegmentRec *_next; + const char *str_start; // escaped characters, including opening/trailing characters + int str_len; +}; +void NSEEL_VM_SetStringFunc(NSEEL_VMCTX ctx, + EEL_F (*onString)(void *caller_this, struct eelStringSegmentRec *list), + EEL_F (*onNamedString)(void *caller_this, const char *name)); + +// call with NULL to calculate size, or non-null to generate to buffer (returning size used -- will not null terminate, caller responsibility) +int nseel_stringsegments_tobuf(char *bufOut, int bufout_sz, struct eelStringSegmentRec *list); + + +NSEEL_CODEHANDLE NSEEL_code_compile(NSEEL_VMCTX ctx, const char *code, int lineoffs); +#define NSEEL_CODE_COMPILE_FLAG_COMMONFUNCS 1 // allows that code's functions to be used in other code (note you shouldn't destroy that codehandle without destroying others first if used) +#define NSEEL_CODE_COMPILE_FLAG_COMMONFUNCS_RESET 2 // resets common code functions +#define NSEEL_CODE_COMPILE_FLAG_NOFPSTATE 4 // hint that the FPU/SSE state should be good-to-go +#define NSEEL_CODE_COMPILE_FLAG_ONLY_BUILTIN_FUNCTIONS 8 // very restrictive mode (only math functions really) + +NSEEL_CODEHANDLE NSEEL_code_compile_ex(NSEEL_VMCTX ctx, const char *code, int lineoffs, int flags); + +char *NSEEL_code_getcodeerror(NSEEL_VMCTX ctx); +int NSEEL_code_geterror_flag(NSEEL_VMCTX ctx); +void NSEEL_code_execute(NSEEL_CODEHANDLE code); +void NSEEL_code_free(NSEEL_CODEHANDLE code); +int *NSEEL_code_getstats(NSEEL_CODEHANDLE code); // 4 ints...source bytes, static code bytes, call code bytes, data bytes + + +// global memory control/view +extern unsigned int NSEEL_RAM_limitmem; // if nonzero, memory limit for user data, in bytes +extern unsigned int NSEEL_RAM_memused; +extern int NSEEL_RAM_memused_errors; + + + +// configuration: + +// use the handwritten lexer -- the flex (eel2.l generated) lexer mostly works, but doesn't support string parsing at the moment +// this mode is faster and uses less ram than eel2.l anyway, so leave it on +#define NSEEL_SUPER_MINIMAL_LEXER + + // #define NSEEL_EEL1_COMPAT_MODE // supports old behaviors (continue after failed compile), old functions _bnot etc. disables string support (strings were used as comments in eel1 etc) + +#define NSEEL_MAX_VARIABLE_NAMELEN 128 // define this to override the max variable length +#define NSEEL_MAX_EELFUNC_PARAMETERS 40 +#define NSEEL_MAX_FUNCSIG_NAME 2048 // longer than variable maxlen, due to multiple namespaces + +// maximum loop length (0 for unlimited) +#ifndef NSEEL_LOOPFUNC_SUPPORT_MAXLEN +#define NSEEL_LOOPFUNC_SUPPORT_MAXLEN 1048576 +#endif + +#define NSEEL_MAX_FUNCTION_SIZE_FOR_INLINE 2048 + +// when a VM ctx doesn't have a GRAM context set, make the global one this big +#define NSEEL_SHARED_GRAM_SIZE (1<<20) + +//#define EEL_DUMP_OPS // used for testing frontend parser/logic changes + +// note: if you wish to change NSEEL_RAM_*, and your target is x86-64, you will need to regenerate things. + +// on osx: +// php a2x64.php win64x +// php a2x64.php macho64 + +// or on win32: +// php a2x64.php +// php a2x64.php macho64x +// this will regenerate the .asm files and object files + +// 512 * 65536 = 32 million entries maximum (256MB RAM) +// default is limited to 128 * 65536 = 8 million entries (64MB RAM) + +// default to 8 million entries, use NSEEL_VM_setramsize() to change at runtime +#define NSEEL_RAM_BLOCKS_DEFAULTMAX 128 + +// 512 entry block table maximum (2k/4k per VM) +#define NSEEL_RAM_BLOCKS_LOG2 9 + + // 65536 items per block (512KB) +#define NSEEL_RAM_ITEMSPERBLOCK_LOG2 16 + +#define NSEEL_RAM_BLOCKS (1 << NSEEL_RAM_BLOCKS_LOG2) +#define NSEEL_RAM_ITEMSPERBLOCK (1<<NSEEL_RAM_ITEMSPERBLOCK_LOG2) + +#define NSEEL_STACK_SIZE 4096 // about 64k overhead if the stack functions are used in a given code handle + +// arch neutral mode, runs about 1/8th speed or so +//#define EEL_TARGET_PORTABLE + +#ifdef EEL_TARGET_PORTABLE +#define EEL_BC_TYPE int +#endif + +#ifdef NSEEL_EEL1_COMPAT_MODE +double *NSEEL_getglobalregs(); +#endif + +void eel_setfp_round(); // use to set fp to rounding mode (normal) -- only really use this when being called from EEL +void eel_setfp_trunc(); // use to restore fp to trunc mode -- only really use this when being called from EEL + +void eel_enterfp(int s[2]); +void eel_leavefp(int s[2]); + +extern void *(*nseel_gmem_calloc)(size_t,size_t); // set this to the calloc() implementation used by the context that will call NSEEL_VM_FreeGRAM() + +#ifdef __cplusplus +} +#endif + +#endif//__NS_EEL_H__ diff --git a/Src/ns-eel2/nseel-caltab.c b/Src/ns-eel2/nseel-caltab.c new file mode 100644 index 00000000..6138b65d --- /dev/null +++ b/Src/ns-eel2/nseel-caltab.c @@ -0,0 +1 @@ +// no longer used
\ No newline at end of file diff --git a/Src/ns-eel2/nseel-cfunc.c b/Src/ns-eel2/nseel-cfunc.c new file mode 100644 index 00000000..fba63e0b --- /dev/null +++ b/Src/ns-eel2/nseel-cfunc.c @@ -0,0 +1,188 @@ +/* + Expression Evaluator Library (NS-EEL) v2 + Copyright (C) 2004-2013 Cockos Incorporated + Copyright (C) 1999-2003 Nullsoft, Inc. + + nseel-cfunc.c: assembly/C implementation of operator/function templates + This file should be ideally compiled with optimizations towards "minimize size" + + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any damages + arising from the use of this software. + + Permission is granted to anyone to use this software for any purpose, + including commercial applications, and to alter it and redistribute it + freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. + 2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. + 3. This notice may not be removed or altered from any source distribution. +*/ + + +#include "ns-eel-int.h" +#include <math.h> +#include <stdio.h> + + + +// these are used by our assembly code + + +#define N 624 +#define M 397 +#define MATRIX_A 0x9908b0dfUL /* constant vector a */ +#define UPPER_MASK 0x80000000UL /* most significant w-r bits */ +#define LOWER_MASK 0x7fffffffUL /* least significant r bits */ + +static unsigned int genrand_int32(void) +{ + + unsigned int y; + static unsigned int mag01[2]={0x0UL, MATRIX_A}; + /* mag01[x] = x * MATRIX_A for x=0,1 */ + + static unsigned int mt[N]; /* the array for the state vector */ + static int mti; /* mti==N+1 means mt[N] is not initialized */ + + + if (!mti) + { + unsigned int s=0x4141f00d; + mt[0]= s & 0xffffffffUL; + for (mti=1; mti<N; mti++) + { + mt[mti] = + (1812433253UL * (mt[mti-1] ^ (mt[mti-1] >> 30)) + mti); + /* See Knuth TAOCP Vol2. 3rd Ed. P.106 for multiplier. */ + /* In the previous versions, MSBs of the seed affect */ + /* only MSBs of the array mt[]. */ + /* 2002/01/09 modified by Makoto Matsumoto */ + mt[mti] &= 0xffffffffUL; + /* for >32 bit machines */ + } + } + + if (mti >= N) { /* generate N words at one time */ + int kk; + + for (kk=0;kk<N-M;kk++) { + y = (mt[kk]&UPPER_MASK)|(mt[kk+1]&LOWER_MASK); + mt[kk] = mt[kk+M] ^ (y >> 1) ^ mag01[y & 0x1UL]; + } + for (;kk<N-1;kk++) { + y = (mt[kk]&UPPER_MASK)|(mt[kk+1]&LOWER_MASK); + mt[kk] = mt[kk+(M-N)] ^ (y >> 1) ^ mag01[y & 0x1UL]; + } + y = (mt[N-1]&UPPER_MASK)|(mt[0]&LOWER_MASK); + mt[N-1] = mt[M-1] ^ (y >> 1) ^ mag01[y & 0x1UL]; + + mti = 0; + } + + y = mt[mti++]; + + /* Tempering */ + y ^= (y >> 11); + y ^= (y << 7) & 0x9d2c5680UL; + y ^= (y << 15) & 0xefc60000UL; + y ^= (y >> 18); + + return y; +} + + + +//--------------------------------------------------------------------------------------------------------------- +EEL_F NSEEL_CGEN_CALL nseel_int_rand(EEL_F f) +{ + EEL_F x=floor(f); + if (x < 1.0) x=1.0; + +#ifdef NSEEL_EEL1_COMPAT_MODE + return (EEL_F)(genrand_int32()%(int)x); +#else + return (EEL_F) (genrand_int32()*(1.0/(double)0xFFFFFFFF)*x); +#endif +} + +//--------------------------------------------------------------------------------------------------------------- + + +#ifndef EEL_TARGET_PORTABLE + +#ifdef __ppc__ +#include "asm-nseel-ppc-gcc.c" +#elif defined(__aarch64__) +#include "asm-nseel-aarch64-gcc.c" +#elif defined(__arm__) +#include "asm-nseel-arm-gcc.c" +#elif defined (_M_ARM) && _M_ARM == 7 + // vc on ARM, tbd +#else + #ifdef _MSC_VER + #ifdef _WIN64 + //nasm + #else + #include "asm-nseel-x86-msvc.c" + + void eel_setfp_round() + { + short oldsw; + __asm + { + fnstcw [oldsw] + mov ax, [oldsw] + and ax, 0xF3FF // round to nearest + mov [oldsw], ax + fldcw [oldsw] + } + } + void eel_setfp_trunc() + { + short oldsw; + __asm + { + fnstcw [oldsw] + mov ax, [oldsw] + or ax, 0xC00 // truncate + mov [oldsw], ax + fldcw [oldsw] + } + } + #endif + #elif !defined(__LP64__) + #define FUNCTION_MARKER "\n.byte 0x89,0x90,0x90,0x90,0x90,0x90,0x90,0x90,0x90,0x90,0x90,0x90\n" + #include "asm-nseel-x86-gcc.c" + void eel_setfp_round() + { + __asm__( + "subl $16, %esp\n" + "fnstcw (%esp)\n" + "mov (%esp), %ax\n" + "and $0xF3FF, %ax\n" // set round to nearest + "mov %ax, 4(%esp)\n" + "fldcw 4(%esp)\n" + "addl $16, %esp\n" + ); + } + void eel_setfp_trunc() + { + __asm__( + "subl $16, %esp\n" + "fnstcw (%esp)\n" + "mov (%esp), %ax\n" + "or $0xC00, %ax\n" // set to truncate + "mov %ax, 4(%esp)\n" + "fldcw 4(%esp)\n" + "addl $16, %esp\n" + ); + } + #endif +#endif + +#endif diff --git a/Src/ns-eel2/nseel-compiler.c b/Src/ns-eel2/nseel-compiler.c new file mode 100644 index 00000000..69b08ae6 --- /dev/null +++ b/Src/ns-eel2/nseel-compiler.c @@ -0,0 +1,5700 @@ +/* + Expression Evaluator Library (NS-EEL) v2 + Copyright (C) 2004-2013 Cockos Incorporated + Copyright (C) 1999-2003 Nullsoft, Inc. + + nseel-compiler.c + + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any damages + arising from the use of this software. + + Permission is granted to anyone to use this software for any purpose, + including commercial applications, and to alter it and redistribute it + freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. + 2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. + 3. This notice may not be removed or altered from any source distribution. +*/ + +#include "ns-eel-int.h" + +#include "denormal.h" +#include "wdlcstring.h" + +#include <string.h> +#include <math.h> +#include <stdio.h> +#include <ctype.h> + +#if !defined(EEL_TARGET_PORTABLE) && !defined(_WIN32) +#include <sys/mman.h> +#include <stdint.h> +#include <unistd.h> +#endif + +#include "glue_x86.h" + +#ifdef _WIN64 +#include "glue_x86_64.h" +#endif // _WIN64 + + +#define NSEEL_VARS_MALLOC_CHUNKSIZE 8 + +//#define LOG_OPT +//#define EEL_PRINT_FAILS +//#define EEL_VALIDATE_WORKTABLE_USE +//#define EEL_VALIDATE_FSTUBS + + +#ifdef EEL_PRINT_FAILS + #ifdef _WIN32 + #define RET_MINUS1_FAIL(x) { OutputDebugString(x); return -1; } + #else + #define RET_MINUS1_FAIL(x) { printf("%s\n",x); return -1; } + #endif +#else +#define RET_MINUS1_FAIL(x) return -1; +#endif + +#ifdef EEL_DUMP_OPS +FILE *g_eel_dump_fp, *g_eel_dump_fp2; +#endif + +#ifdef EEL_VALIDATE_WORKTABLE_USE + #define MIN_COMPUTABLE_SIZE 0 + #define COMPUTABLE_EXTRA_SPACE 64 // safety buffer, if EEL_VALIDATE_WORKTABLE_USE set, used for magic-value-checking +#else + #define MIN_COMPUTABLE_SIZE 32 // always use at least this big of a temp storage table (and reset the temp ptr when it goes past this boundary) + #define COMPUTABLE_EXTRA_SPACE 16 // safety buffer, if EEL_VALIDATE_WORKTABLE_USE set, used for magic-value-checking +#endif + + +/* + P1 is rightmost parameter + P2 is second rightmost, if any + P3 is third rightmost, if any + registers on x86 are (RAX etc on x86-64) + P1(ret) EAX + P2 EDI + P3 ECX + WTP RSI + x86_64: r12 is a pointer to ram_state.blocks + x86_64: r13 is a pointer to closenessfactor + + registers on PPC are: + P1(ret) r3 + P2 r14 + P3 r15 + WTP r16 (r17 has the original value) + r13 is a pointer to ram_state.blocks + + ppc uses f31 and f30 and others for certain constants + + */ + + +#ifdef EEL_TARGET_PORTABLE + +#define EEL_DOESNT_NEED_EXEC_PERMS +#include "glue_port.h" + +#elif defined(__ppc__) + +#include "glue_ppc.h" + +#elif defined(__aarch64__) + +#include "glue_aarch64.h" + +#elif defined(__arm__) || (defined (_M_ARM) && _M_ARM == 7) + +#include "glue_arm.h" + +#elif defined(_WIN64) || defined(__LP64__) + +#include "glue_x86_64.h" + +#else + +#include "glue_x86.h" + +#endif + +#ifndef GLUE_INVSQRT_NEEDREPL +#define GLUE_INVSQRT_NEEDREPL 0 +#endif + + +// used by //#eel-no-optimize:xxx, in ctx->optimizeDisableFlags +#define OPTFLAG_NO_OPTIMIZE 1 +#define OPTFLAG_NO_FPSTACK 2 +#define OPTFLAG_NO_INLINEFUNC 4 +#define OPTFLAG_FULL_DENORMAL_CHECKS 8 // if set, denormals/NaN are always filtered on assign +#define OPTFLAG_NO_DENORMAL_CHECKS 16 // if set and FULL not set, denormals/NaN are never filtered on assign + + +#define DENORMAL_CLEARING_THRESHOLD 1.0e-50 // when adding/subtracting a constant, assume if it's greater than this, it will clear denormal (the actual value is probably 10^-290...) + + +#define MAX_SUB_NAMESPACES 32 +typedef struct +{ + const char *namespacePathToThis; + const char *subParmInfo[MAX_SUB_NAMESPACES]; +} namespaceInformation; + + + + +static int nseel_evallib_stats[5]; // source bytes, static code bytes, call code bytes, data bytes, segments +int *NSEEL_getstats() +{ + return nseel_evallib_stats; +} + +static int findLineNumber(const char *exp, int byteoffs) +{ + int lc=0; + while (byteoffs-->0 && *exp) if (*exp++ =='\n') lc++; + return lc; +} + + +static int nseel_vms_referencing_globallist_cnt; +nseel_globalVarItem *nseel_globalreg_list; +static EEL_F *get_global_var(compileContext *ctx, const char *gv, int addIfNotPresent); + +static void *__newBlock(llBlock **start,int size, int wantMprotect); + +#define OPCODE_IS_TRIVIAL(x) ((x)->opcodeType <= OPCODETYPE_VARPTRPTR) +enum { + OPCODETYPE_DIRECTVALUE=0, + OPCODETYPE_DIRECTVALUE_TEMPSTRING, // like directvalue, but will generate a new tempstring value on generate + OPCODETYPE_VALUE_FROM_NAMESPACENAME, // this.* or namespace.* are encoded this way + OPCODETYPE_VARPTR, + OPCODETYPE_VARPTRPTR, + OPCODETYPE_FUNC1, + OPCODETYPE_FUNC2, + OPCODETYPE_FUNC3, + OPCODETYPE_FUNCX, + + OPCODETYPE_MOREPARAMS, + + OPCODETYPE_INVALID, +}; + +struct opcodeRec +{ + int opcodeType; + int fntype; + void *fn; + + union { + struct opcodeRec *parms[3]; + struct { + double directValue; + EEL_F *valuePtr; // if direct value, valuePtr can be cached + } dv; + } parms; + + int namespaceidx; + + // OPCODETYPE_VALUE_FROM_NAMESPACENAME (relname is either empty or blah) + // OPCODETYPE_VARPTR if it represents a global variable, will be nonempty + // OPCODETYPE_FUNC* with fntype=FUNCTYPE_EELFUNC + const char *relname; +}; + + + + +static void *newTmpBlock(compileContext *ctx, int size) +{ + const int align = 8; + const int a1=align-1; + char *p=(char*)__newBlock(&ctx->tmpblocks_head,size+a1, 0); + return p+((align-(((INT_PTR)p)&a1))&a1); +} + +static void *__newBlock_align(compileContext *ctx, int size, int align, int isForCode) +{ + const int a1=align-1; + char *p=(char*)__newBlock( + ( + isForCode < 0 ? (isForCode == -2 ? &ctx->pblocks : &ctx->tmpblocks_head) : + isForCode > 0 ? &ctx->blocks_head : + &ctx->blocks_head_data) ,size+a1, isForCode>0); + return p+((align-(((INT_PTR)p)&a1))&a1); +} + +static opcodeRec *newOpCode(compileContext *ctx, const char *str, int opType) +{ + const size_t strszfull = str ? strlen(str) : 0; + const size_t str_sz = wdl_min(NSEEL_MAX_VARIABLE_NAMELEN, strszfull); + + opcodeRec *rec = (opcodeRec*)__newBlock_align(ctx, + (int) (sizeof(opcodeRec) + (str_sz>0 ? str_sz+1 : 0)), + 8, ctx->isSharedFunctions ? 0 : -1); + if (rec) + { + memset(rec,0,sizeof(*rec)); + rec->opcodeType = opType; + + if (str_sz > 0) + { + char *p = (char *)(rec+1); + memcpy(p,str,str_sz); + p[str_sz]=0; + + rec->relname = p; + } + else + { + rec->relname = ""; + } + } + + return rec; +} + +#define newCodeBlock(x,a) __newBlock_align(ctx,x,a,1) +#define newDataBlock(x,a) __newBlock_align(ctx,x,a,0) +#define newCtxDataBlock(x,a) __newBlock_align(ctx,x,a,-2) + +static void freeBlocks(llBlock **start); + +static int __growbuf_resize(eel_growbuf *buf, int newsize) +{ + if (newsize<0) + { + free(buf->ptr); + buf->ptr=NULL; + buf->alloc=buf->size=0; + return 0; + } + + if (newsize > buf->alloc) + { + const int newalloc = newsize + 4096 + newsize/2; + void *newptr = realloc(buf->ptr,newalloc); + if (!newptr) + { + newptr = malloc(newalloc); + if (!newptr) return 1; + if (buf->ptr && buf->size) memcpy(newptr,buf->ptr,buf->size); + free(buf->ptr); + buf->ptr=newptr; + } + else + buf->ptr = newptr; + + buf->alloc=newalloc; + } + buf->size = newsize; + return 0; +} + + +#ifndef DECL_ASMFUNC +#define DECL_ASMFUNC(x) \ + void nseel_asm_##x(void); \ + void nseel_asm_##x##_end(void); + + +void _asm_megabuf(void); +void _asm_megabuf_end(void); +void _asm_gmegabuf(void); +void _asm_gmegabuf_end(void); + +#endif + + + DECL_ASMFUNC(booltofp) + DECL_ASMFUNC(fptobool) + DECL_ASMFUNC(fptobool_rev) + DECL_ASMFUNC(sin) + DECL_ASMFUNC(cos) + DECL_ASMFUNC(tan) + DECL_ASMFUNC(1pdd) + DECL_ASMFUNC(2pdd) + DECL_ASMFUNC(2pdds) + DECL_ASMFUNC(1pp) + DECL_ASMFUNC(2pp) + DECL_ASMFUNC(sqr) + DECL_ASMFUNC(sqrt) + DECL_ASMFUNC(log) + DECL_ASMFUNC(log10) + DECL_ASMFUNC(abs) + DECL_ASMFUNC(min) + DECL_ASMFUNC(max) + DECL_ASMFUNC(min_fp) + DECL_ASMFUNC(max_fp) + DECL_ASMFUNC(sig) + DECL_ASMFUNC(sign) + DECL_ASMFUNC(band) + DECL_ASMFUNC(bor) + DECL_ASMFUNC(bnot) + DECL_ASMFUNC(bnotnot) + DECL_ASMFUNC(if) + DECL_ASMFUNC(fcall) + DECL_ASMFUNC(repeat) + DECL_ASMFUNC(repeatwhile) + DECL_ASMFUNC(equal) + DECL_ASMFUNC(equal_exact) + DECL_ASMFUNC(notequal_exact) + DECL_ASMFUNC(notequal) + DECL_ASMFUNC(below) + DECL_ASMFUNC(above) + DECL_ASMFUNC(beloweq) + DECL_ASMFUNC(aboveeq) + DECL_ASMFUNC(assign) + DECL_ASMFUNC(assign_fromfp) + DECL_ASMFUNC(assign_fast) + DECL_ASMFUNC(assign_fast_fromfp) + DECL_ASMFUNC(add) + DECL_ASMFUNC(sub) + DECL_ASMFUNC(add_op) + DECL_ASMFUNC(sub_op) + DECL_ASMFUNC(add_op_fast) + DECL_ASMFUNC(sub_op_fast) + DECL_ASMFUNC(mul) + DECL_ASMFUNC(div) + DECL_ASMFUNC(mul_op) + DECL_ASMFUNC(div_op) + DECL_ASMFUNC(mul_op_fast) + DECL_ASMFUNC(div_op_fast) + DECL_ASMFUNC(mod) + DECL_ASMFUNC(shl) + DECL_ASMFUNC(shr) + DECL_ASMFUNC(mod_op) + DECL_ASMFUNC(or) + DECL_ASMFUNC(or0) + DECL_ASMFUNC(xor) + DECL_ASMFUNC(xor_op) + DECL_ASMFUNC(and) + DECL_ASMFUNC(or_op) + DECL_ASMFUNC(and_op) + DECL_ASMFUNC(uplus) + DECL_ASMFUNC(uminus) + DECL_ASMFUNC(invsqrt) + DECL_ASMFUNC(dbg_getstackptr) +#ifdef NSEEL_EEL1_COMPAT_MODE + DECL_ASMFUNC(exec2) +#endif + + DECL_ASMFUNC(stack_push) + DECL_ASMFUNC(stack_pop) + DECL_ASMFUNC(stack_pop_fast) // just returns value, doesn't mod param + DECL_ASMFUNC(stack_peek) + DECL_ASMFUNC(stack_peek_int) + DECL_ASMFUNC(stack_peek_top) + DECL_ASMFUNC(stack_exch) + +static void *NSEEL_PProc_GRAM(void *data, int data_size, compileContext *ctx) +{ + if (data_size>0) data=EEL_GLUE_set_immediate(data, (INT_PTR)ctx->gram_blocks); + return data; +} + +static void *NSEEL_PProc_Stack(void *data, int data_size, compileContext *ctx) +{ + codeHandleType *ch=ctx->tmpCodeHandle; + + if (data_size>0) + { + UINT_PTR m1=(UINT_PTR)(NSEEL_STACK_SIZE * sizeof(EEL_F) - 1); + UINT_PTR stackptr = ((UINT_PTR) (&ch->stack)); + + ch->want_stack=1; + if (!ch->stack) ch->stack = newDataBlock(NSEEL_STACK_SIZE*sizeof(EEL_F),NSEEL_STACK_SIZE*sizeof(EEL_F)); + + data=EEL_GLUE_set_immediate(data, stackptr); + data=EEL_GLUE_set_immediate(data, m1); // and + data=EEL_GLUE_set_immediate(data, ((UINT_PTR)ch->stack&~m1)); //or + } + return data; +} + +static void *NSEEL_PProc_Stack_PeekInt(void *data, int data_size, compileContext *ctx, INT_PTR offs) +{ + codeHandleType *ch=ctx->tmpCodeHandle; + + if (data_size>0) + { + UINT_PTR m1=(UINT_PTR)(NSEEL_STACK_SIZE * sizeof(EEL_F) - 1); + UINT_PTR stackptr = ((UINT_PTR) (&ch->stack)); + + ch->want_stack=1; + if (!ch->stack) ch->stack = newDataBlock(NSEEL_STACK_SIZE*sizeof(EEL_F),NSEEL_STACK_SIZE*sizeof(EEL_F)); + + data=EEL_GLUE_set_immediate(data, stackptr); + data=EEL_GLUE_set_immediate(data, offs); + data=EEL_GLUE_set_immediate(data, m1); // and + data=EEL_GLUE_set_immediate(data, ((UINT_PTR)ch->stack&~m1)); //or + } + return data; +} +static void *NSEEL_PProc_Stack_PeekTop(void *data, int data_size, compileContext *ctx) +{ + codeHandleType *ch=ctx->tmpCodeHandle; + + if (data_size>0) + { + UINT_PTR stackptr = ((UINT_PTR) (&ch->stack)); + + ch->want_stack=1; + if (!ch->stack) ch->stack = newDataBlock(NSEEL_STACK_SIZE*sizeof(EEL_F),NSEEL_STACK_SIZE*sizeof(EEL_F)); + + data=EEL_GLUE_set_immediate(data, stackptr); + } + return data; +} + +#if defined(_MSC_VER) && _MSC_VER >= 1400 +//static double __floor(double a) { return floor(a); } +//static double __ceil(double a) { return ceil(a); } +#define floor __floor +#define ceil __ceil +#endif + + +#ifdef NSEEL_EEL1_COMPAT_MODE +static double eel1band(double a, double b) +{ + return (fabs(a)>NSEEL_CLOSEFACTOR && fabs(b) > NSEEL_CLOSEFACTOR) ? 1.0 : 0.0; +} +static double eel1bor(double a, double b) +{ + return (fabs(a)>NSEEL_CLOSEFACTOR || fabs(b) > NSEEL_CLOSEFACTOR) ? 1.0 : 0.0; +} + +static double eel1sigmoid(double x, double constraint) +{ + double t = (1+exp(-x * (constraint))); + return fabs(t)>NSEEL_CLOSEFACTOR ? 1.0/t : 0; +} + +#endif + + + +#define FUNCTIONTYPE_PARAMETERCOUNTMASK 0xff + +#define BIF_NPARAMS_MASK 0x7ffff00 +#define BIF_RETURNSONSTACK 0x0000100 +#define BIF_LASTPARMONSTACK 0x0000200 +#define BIF_RETURNSBOOL 0x0000400 +#define BIF_LASTPARM_ASBOOL 0x0000800 +// 0x00?0000 -- taken by FP stack flags +#define BIF_TAKES_VARPARM 0x0400000 +#define BIF_TAKES_VARPARM_EX 0x0C00000 // this is like varparm but check count exactly +#define BIF_WONTMAKEDENORMAL 0x0100000 +#define BIF_CLEARDENORMAL 0x0200000 + +#if defined(GLUE_HAS_FXCH) && GLUE_MAX_FPSTACK_SIZE > 0 + #define BIF_SECONDLASTPARMST 0x0001000 // use with BIF_LASTPARMONSTACK only (last two parameters get passed on fp stack) + #define BIF_LAZYPARMORDERING 0x0002000 // allow optimizer to avoid fxch when using BIF_TWOPARMSONFPSTACK_LAZY etc + #define BIF_REVERSEFPORDER 0x0004000 // force a fxch (reverse order of last two parameters on fp stack, used by comparison functions) + + #ifndef BIF_FPSTACKUSE + #define BIF_FPSTACKUSE(x) (((x)>=0&&(x)<8) ? ((7-(x))<<16):0) + #endif + #ifndef BIF_GETFPSTACKUSE + #define BIF_GETFPSTACKUSE(x) (7 - (((x)>>16)&7)) + #endif +#else + // do not support fp stack use unless GLUE_HAS_FXCH and GLUE_MAX_FPSTACK_SIZE>0 + #define BIF_SECONDLASTPARMST 0 + #define BIF_LAZYPARMORDERING 0 + #define BIF_REVERSEFPORDER 0 + #define BIF_FPSTACKUSE(x) 0 + #define BIF_GETFPSTACKUSE(x) 0 +#endif + +#define BIF_TWOPARMSONFPSTACK (BIF_SECONDLASTPARMST|BIF_LASTPARMONSTACK) +#define BIF_TWOPARMSONFPSTACK_LAZY (BIF_LAZYPARMORDERING|BIF_SECONDLASTPARMST|BIF_LASTPARMONSTACK) + + +#ifndef GLUE_HAS_NATIVE_TRIGSQRTLOG +static double sqrt_fabs(double a) { return sqrt(fabs(a)); } +#endif + + +EEL_F NSEEL_CGEN_CALL nseel_int_rand(EEL_F f); + +#define FNPTR_HAS_CONDITIONAL_EXEC(op) \ + (op->fntype == FN_LOGICAL_AND || \ + op->fntype == FN_LOGICAL_OR || \ + op->fntype == FN_IF_ELSE || \ + op->fntype == FN_WHILE || \ + op->fntype == FN_LOOP) + +static functionType fnTable1[] = { +#ifndef GLUE_HAS_NATIVE_TRIGSQRTLOG + { "sin", nseel_asm_1pdd,nseel_asm_1pdd_end, 1|NSEEL_NPARAMS_FLAG_CONST|BIF_RETURNSONSTACK|BIF_LASTPARMONSTACK|BIF_WONTMAKEDENORMAL, {&sin} }, + { "cos", nseel_asm_1pdd,nseel_asm_1pdd_end, 1|NSEEL_NPARAMS_FLAG_CONST|BIF_RETURNSONSTACK|BIF_LASTPARMONSTACK|BIF_CLEARDENORMAL, {&cos} }, + { "tan", nseel_asm_1pdd,nseel_asm_1pdd_end, 1|NSEEL_NPARAMS_FLAG_CONST|BIF_RETURNSONSTACK|BIF_LASTPARMONSTACK, {&tan} }, + { "sqrt", nseel_asm_1pdd,nseel_asm_1pdd_end, 1|NSEEL_NPARAMS_FLAG_CONST|BIF_RETURNSONSTACK|BIF_LASTPARMONSTACK|BIF_WONTMAKEDENORMAL, {&sqrt_fabs}, }, + { "log", nseel_asm_1pdd,nseel_asm_1pdd_end, 1|NSEEL_NPARAMS_FLAG_CONST|BIF_RETURNSONSTACK|BIF_LASTPARMONSTACK, {&log} }, + { "log10", nseel_asm_1pdd,nseel_asm_1pdd_end, 1|NSEEL_NPARAMS_FLAG_CONST|BIF_RETURNSONSTACK|BIF_LASTPARMONSTACK, {&log10} }, +#else + { "sin", nseel_asm_sin,nseel_asm_sin_end, 1|NSEEL_NPARAMS_FLAG_CONST|BIF_RETURNSONSTACK|BIF_LASTPARMONSTACK|BIF_WONTMAKEDENORMAL|BIF_FPSTACKUSE(1) }, + { "cos", nseel_asm_cos,nseel_asm_cos_end, 1|NSEEL_NPARAMS_FLAG_CONST|BIF_RETURNSONSTACK|BIF_LASTPARMONSTACK|BIF_CLEARDENORMAL|BIF_FPSTACKUSE(1) }, + { "tan", nseel_asm_tan,nseel_asm_tan_end, 1|NSEEL_NPARAMS_FLAG_CONST|BIF_RETURNSONSTACK|BIF_LASTPARMONSTACK|BIF_FPSTACKUSE(1) }, + { "sqrt", nseel_asm_sqrt,nseel_asm_sqrt_end, 1|NSEEL_NPARAMS_FLAG_CONST|BIF_RETURNSONSTACK|BIF_LASTPARMONSTACK|BIF_FPSTACKUSE(1)|BIF_WONTMAKEDENORMAL }, + { "log", nseel_asm_log,nseel_asm_log_end, 1|NSEEL_NPARAMS_FLAG_CONST|BIF_RETURNSONSTACK|BIF_LASTPARMONSTACK|BIF_FPSTACKUSE(3), }, + { "log10", nseel_asm_log10,nseel_asm_log10_end, 1|NSEEL_NPARAMS_FLAG_CONST|BIF_RETURNSONSTACK|BIF_LASTPARMONSTACK|BIF_FPSTACKUSE(3), }, +#endif + + + { "asin", nseel_asm_1pdd,nseel_asm_1pdd_end, 1|NSEEL_NPARAMS_FLAG_CONST|BIF_RETURNSONSTACK|BIF_LASTPARMONSTACK, {&asin}, }, + { "acos", nseel_asm_1pdd,nseel_asm_1pdd_end, 1|NSEEL_NPARAMS_FLAG_CONST|BIF_RETURNSONSTACK|BIF_LASTPARMONSTACK, {&acos}, }, + { "atan", nseel_asm_1pdd,nseel_asm_1pdd_end, 1|NSEEL_NPARAMS_FLAG_CONST|BIF_RETURNSONSTACK|BIF_LASTPARMONSTACK, {&atan}, }, + { "atan2", nseel_asm_2pdd,nseel_asm_2pdd_end, 2|NSEEL_NPARAMS_FLAG_CONST|BIF_RETURNSONSTACK|BIF_TWOPARMSONFPSTACK, {&atan2}, }, + { "exp", nseel_asm_1pdd,nseel_asm_1pdd_end, 1|NSEEL_NPARAMS_FLAG_CONST|BIF_RETURNSONSTACK|BIF_LASTPARMONSTACK, {&exp}, }, + { "abs", nseel_asm_abs,nseel_asm_abs_end, 1|NSEEL_NPARAMS_FLAG_CONST|BIF_RETURNSONSTACK|BIF_LASTPARMONSTACK|BIF_FPSTACKUSE(0)|BIF_WONTMAKEDENORMAL }, + { "sqr", nseel_asm_sqr,nseel_asm_sqr_end, 1|NSEEL_NPARAMS_FLAG_CONST|BIF_RETURNSONSTACK|BIF_LASTPARMONSTACK|BIF_FPSTACKUSE(1) }, + { "min", nseel_asm_min,nseel_asm_min_end, 2|NSEEL_NPARAMS_FLAG_CONST|BIF_FPSTACKUSE(3)|BIF_WONTMAKEDENORMAL }, + { "max", nseel_asm_max,nseel_asm_max_end, 2|NSEEL_NPARAMS_FLAG_CONST|BIF_FPSTACKUSE(3)|BIF_WONTMAKEDENORMAL }, + { "sign", nseel_asm_sign,nseel_asm_sign_end, 1|NSEEL_NPARAMS_FLAG_CONST|BIF_RETURNSONSTACK|BIF_LASTPARMONSTACK|BIF_FPSTACKUSE(2)|BIF_CLEARDENORMAL, }, + { "rand", nseel_asm_1pdd,nseel_asm_1pdd_end, 1|BIF_RETURNSONSTACK|BIF_LASTPARMONSTACK|BIF_CLEARDENORMAL, {&nseel_int_rand}, }, + + //{ "floor", nseel_asm_1pdd,nseel_asm_1pdd_end, 1|NSEEL_NPARAMS_FLAG_CONST|BIF_RETURNSONSTACK|BIF_LASTPARMONSTACK|BIF_CLEARDENORMAL, {&floor} }, + //{ "ceil", nseel_asm_1pdd,nseel_asm_1pdd_end, 1|NSEEL_NPARAMS_FLAG_CONST|BIF_RETURNSONSTACK|BIF_LASTPARMONSTACK|BIF_CLEARDENORMAL, {&ceil} }, + + { "invsqrt", nseel_asm_invsqrt,nseel_asm_invsqrt_end, 1|NSEEL_NPARAMS_FLAG_CONST|BIF_RETURNSONSTACK|BIF_LASTPARMONSTACK|BIF_FPSTACKUSE(3), {GLUE_INVSQRT_NEEDREPL} }, + + { "__dbg_getstackptr", nseel_asm_dbg_getstackptr,nseel_asm_dbg_getstackptr_end, 1|NSEEL_NPARAMS_FLAG_CONST|BIF_RETURNSONSTACK|BIF_LASTPARMONSTACK|BIF_FPSTACKUSE(1), }, + +#ifdef NSEEL_EEL1_COMPAT_MODE + { "sigmoid", nseel_asm_2pdd,nseel_asm_2pdd_end, 2|NSEEL_NPARAMS_FLAG_CONST|BIF_RETURNSONSTACK|BIF_TWOPARMSONFPSTACK, {&eel1sigmoid}, }, + + // these differ from _and/_or, they always evaluate both... + { "band", nseel_asm_2pdd,nseel_asm_2pdd_end, 2|NSEEL_NPARAMS_FLAG_CONST|BIF_RETURNSONSTACK|BIF_TWOPARMSONFPSTACK|BIF_CLEARDENORMAL , {&eel1band}, }, + { "bor", nseel_asm_2pdd,nseel_asm_2pdd_end, 2|NSEEL_NPARAMS_FLAG_CONST|BIF_RETURNSONSTACK|BIF_TWOPARMSONFPSTACK|BIF_CLEARDENORMAL , {&eel1bor}, }, + + {"exec2",nseel_asm_exec2,nseel_asm_exec2_end,2|NSEEL_NPARAMS_FLAG_CONST|BIF_WONTMAKEDENORMAL}, + {"exec3",nseel_asm_exec2,nseel_asm_exec2_end,3|NSEEL_NPARAMS_FLAG_CONST|BIF_WONTMAKEDENORMAL}, +#endif // end EEL1 compat + + + {"freembuf",_asm_generic1parm,_asm_generic1parm_end,1,{&__NSEEL_RAM_MemFree},NSEEL_PProc_RAM}, + {"memcpy",_asm_generic3parm,_asm_generic3parm_end,3,{&__NSEEL_RAM_MemCpy},NSEEL_PProc_RAM}, + {"memset",_asm_generic3parm,_asm_generic3parm_end,3,{&__NSEEL_RAM_MemSet},NSEEL_PProc_RAM}, + {"__memtop",_asm_generic1parm,_asm_generic1parm_end,1,{&__NSEEL_RAM_MemTop},NSEEL_PProc_RAM}, + {"mem_set_values",_asm_generic2parm_retd,_asm_generic2parm_retd_end,2|BIF_TAKES_VARPARM|BIF_RETURNSONSTACK,{&__NSEEL_RAM_Mem_SetValues},NSEEL_PProc_RAM}, + {"mem_get_values",_asm_generic2parm_retd,_asm_generic2parm_retd_end,2|BIF_TAKES_VARPARM|BIF_RETURNSONSTACK,{&__NSEEL_RAM_Mem_GetValues},NSEEL_PProc_RAM}, + + {"stack_push",nseel_asm_stack_push,nseel_asm_stack_push_end,1|BIF_FPSTACKUSE(0),{0,},NSEEL_PProc_Stack}, + {"stack_pop",nseel_asm_stack_pop,nseel_asm_stack_pop_end,1|BIF_FPSTACKUSE(1),{0,},NSEEL_PProc_Stack}, + {"stack_peek",nseel_asm_stack_peek,nseel_asm_stack_peek_end,1|NSEEL_NPARAMS_FLAG_CONST|BIF_LASTPARMONSTACK|BIF_FPSTACKUSE(0),{0,},NSEEL_PProc_Stack}, + {"stack_exch",nseel_asm_stack_exch,nseel_asm_stack_exch_end,1|BIF_FPSTACKUSE(1), {0,},NSEEL_PProc_Stack_PeekTop}, +}; + +static eel_function_table default_user_funcs; + +static int functable_lowerbound(functionType *list, int list_sz, const char *name, int *ismatch) +{ + int a = 0, c = list_sz; + while (a != c) + { + const int b = (a+c)/2; + const int cmp = stricmp(name,list[b].name); + if (cmp > 0) a = b+1; + else if (cmp < 0) c = b; + else + { + *ismatch = 1; + return b; + } + } + *ismatch = 0; + return a; +} + +static int funcTypeCmp(const void *a, const void *b) { return stricmp(((functionType*)a)->name,((functionType*)b)->name); } +functionType *nseel_getFunctionByName(compileContext *ctx, const char *name, int *mchk) +{ + eel_function_table *tab = ctx && ctx->registered_func_tab ? ctx->registered_func_tab : &default_user_funcs; + static char sorted; + const int fn1size = (int) (sizeof(fnTable1)/sizeof(fnTable1[0])); + int idx,match; + if (!sorted) + { + NSEEL_HOSTSTUB_EnterMutex(); + if (!sorted) qsort(fnTable1,fn1size,sizeof(fnTable1[0]),funcTypeCmp); + sorted=1; + NSEEL_HOSTSTUB_LeaveMutex(); + } + idx=functable_lowerbound(fnTable1,fn1size,name,&match); + if (match) return fnTable1+idx; + + if ((!ctx || !(ctx->current_compile_flags&NSEEL_CODE_COMPILE_FLAG_ONLY_BUILTIN_FUNCTIONS)) && tab->list) + { + idx=functable_lowerbound(tab->list,tab->list_size,name,&match); + if (match) + { + if (mchk) + { + while (idx>0 && !stricmp(tab->list[idx-1].name,name)) idx--; + *mchk = tab->list_size - 1 - idx; + } + return tab->list + idx; + } + } + + return NULL; +} + +int NSEEL_init() // returns 0 on success +{ + +#ifdef EEL_VALIDATE_FSTUBS + int a; + for (a=0;a < sizeof(fnTable1)/sizeof(fnTable1[0]);a++) + { + char *code_startaddr = (char*)fnTable1[a].afunc; + char *endp = (char *)fnTable1[a].func_e; + // validate + int sz=0; + char *f=(char *)GLUE_realAddress(code_startaddr,endp,&sz); + + if (f+sz > endp) + { +#ifdef _WIN32 + OutputDebugString("bad eel function stub\n"); +#else + printf("bad eel function stub\n"); +#endif + *(char *)NULL = 0; + } + } +#ifdef _WIN32 + OutputDebugString("eel function stub (builtin) validation complete\n"); +#else + printf("eel function stub (builtin) validation complete\n"); +#endif +#endif + + NSEEL_quit(); + return 0; +} + +void NSEEL_quit() +{ + free(default_user_funcs.list); + default_user_funcs.list = NULL; + default_user_funcs.list_size = 0; +} + +void NSEEL_addfunc_varparm_ex(const char *name, int min_np, int want_exact, NSEEL_PPPROC pproc, EEL_F (NSEEL_CGEN_CALL *fptr)(void *, INT_PTR, EEL_F **), eel_function_table *destination) +{ + const int sz = (int) ((char *)_asm_generic2parm_retd_end-(char *)_asm_generic2parm_retd); + NSEEL_addfunctionex2(name,min_np|(want_exact?BIF_TAKES_VARPARM_EX:BIF_TAKES_VARPARM),(char *)_asm_generic2parm_retd,sz,pproc,fptr,NULL,destination); +} +void NSEEL_addfunc_ret_type(const char *name, int np, int ret_type, NSEEL_PPPROC pproc, void *fptr, eel_function_table *destination) // ret_type=-1 for bool, 1 for value, 0 for ptr +{ + char *stub=NULL; + int stubsz=0; +#define DOSTUB(np) { \ + stub = (ret_type == 1 ? (char*)_asm_generic##np##parm_retd : (char*)_asm_generic##np##parm); \ + stubsz = (int) ((ret_type == 1 ? (char*)_asm_generic##np##parm_retd_end : (char *)_asm_generic##np##parm_end) - stub); \ + } + + if (np == 1) DOSTUB(1) + else if (np == 2) DOSTUB(2) + else if (np == 3) DOSTUB(3) +#undef DOSTUB + + if (stub) NSEEL_addfunctionex2(name,np|(ret_type == -1 ? BIF_RETURNSBOOL:0), stub, stubsz, pproc,fptr,NULL,destination); +} + +void NSEEL_addfunctionex2(const char *name, int nparms, char *code_startaddr, int code_len, NSEEL_PPPROC pproc, void *fptr, void *fptr2, eel_function_table *destination) +{ + const int list_size_chunk = 128; + functionType *r; + if (!destination) destination = &default_user_funcs; + + if (!destination->list || !(destination->list_size & (list_size_chunk-1))) + { + void *nv = realloc(destination->list, (destination->list_size + list_size_chunk)*sizeof(functionType)); + if (!nv) return; + destination->list = (functionType *)nv; + } + if (destination->list) + { + int match,idx; + + idx=functable_lowerbound(destination->list,destination->list_size,name,&match); + +#ifdef EEL_VALIDATE_FSTUBS + { + char *endp = code_startaddr+code_len; + // validate + int sz=0; + char *f=(char *)GLUE_realAddress(code_startaddr,endp,&sz); + + if (f+sz > endp) + { +#ifdef _WIN32 + OutputDebugString("bad eel function stub\n"); +#else + printf("bad eel function stub\n"); +#endif + *(char *)NULL = 0; + } +#ifdef _WIN32 + OutputDebugString(name); + OutputDebugString(" - validated eel function stub\n"); +#else + printf("eel function stub validation complete for %s\n",name); +#endif + } +#endif + + r = destination->list + idx; + if (idx < destination->list_size) + memmove(r + 1, r, (destination->list_size - idx) * sizeof(functionType)); + destination->list_size++; + + memset(r, 0, sizeof(functionType)); + + if (!(nparms & BIF_RETURNSBOOL)) + { + if (code_startaddr == (void *)&_asm_generic1parm_retd || + code_startaddr == (void *)&_asm_generic2parm_retd || + code_startaddr == (void *)&_asm_generic3parm_retd) + { + nparms |= BIF_RETURNSONSTACK; + } + } + r->nParams = nparms; + r->name = name; + r->afunc = code_startaddr; + r->func_e = code_startaddr + code_len; + r->pProc = pproc; + r->replptrs[0] = fptr; + r->replptrs[1] = fptr2; + } +} + + +//--------------------------------------------------------------------------------------------------------------- +static void freeBlocks(llBlock **start) +{ + llBlock *s=*start; + *start=0; + while (s) + { + llBlock *llB = s->next; + free(s); + s=llB; + } +} + +//--------------------------------------------------------------------------------------------------------------- +static void *__newBlock(llBlock **start, int size, int wantMprotect) +{ +#if !defined(EEL_DOESNT_NEED_EXEC_PERMS) && defined(_WIN32) + DWORD ov; + UINT_PTR offs,eoffs; +#endif + llBlock *llb; + int alloc_size; + if (*start && (LLB_DSIZE - (*start)->sizeused) >= size) + { + void *t=(*start)->block+(*start)->sizeused; + (*start)->sizeused+=(size+7)&~7; + return t; + } + + alloc_size=sizeof(llBlock); + if ((int)size > LLB_DSIZE) alloc_size += size - LLB_DSIZE; + llb = (llBlock *)malloc(alloc_size); // grab bigger block if absolutely necessary (heh) + if (!llb) return NULL; + +#ifndef EEL_DOESNT_NEED_EXEC_PERMS + if (wantMprotect) + { + #ifdef _WIN32 + offs=((UINT_PTR)llb)&~4095; + eoffs=((UINT_PTR)llb + alloc_size + 4095)&~4095; + VirtualProtect((LPVOID)offs,eoffs-offs,PAGE_EXECUTE_READWRITE,&ov); + // MessageBox(NULL,"vprotecting, yay\n","a",0); + #else + { + static int pagesize = 0; + if (!pagesize) + { + pagesize=sysconf(_SC_PAGESIZE); + if (!pagesize) pagesize=4096; + } + uintptr_t offs,eoffs; + offs=((uintptr_t)llb)&~(pagesize-1); + eoffs=((uintptr_t)llb + alloc_size + pagesize-1)&~(pagesize-1); + mprotect((void*)offs,eoffs-offs,PROT_WRITE|PROT_READ|PROT_EXEC); + } + #endif + } +#endif + llb->sizeused=(size+7)&~7; + llb->next = *start; + *start = llb; + return llb->block; +} + + +//--------------------------------------------------------------------------------------------------------------- +opcodeRec *nseel_createCompiledValue(compileContext *ctx, EEL_F value) +{ + opcodeRec *r=newOpCode(ctx,NULL,OPCODETYPE_DIRECTVALUE); + if (r) + { + r->parms.dv.directValue = value; + } + return r; +} + +opcodeRec *nseel_createCompiledValuePtr(compileContext *ctx, EEL_F *addrValue, const char *namestr) +{ + opcodeRec *r=newOpCode(ctx,namestr,OPCODETYPE_VARPTR); + if (!r) return 0; + + r->parms.dv.valuePtr=addrValue; + + return r; +} + +static int validate_varname_for_function(compileContext *ctx, const char *name) +{ + if (!ctx->function_curName || !ctx->function_globalFlag) return 1; + + if (ctx->function_localTable_Size[2] > 0 && ctx->function_localTable_Names[2]) + { + char * const * const namelist = ctx->function_localTable_Names[2]; + const int namelist_sz = ctx->function_localTable_Size[2]; + int i; + const size_t name_len = strlen(name); + + for (i=0;i<namelist_sz;i++) + { + const char *nmchk=namelist[i]; + const size_t l = strlen(nmchk); + if (l > 1 && nmchk[l-1] == '*') + { + if (name_len >= l && !strnicmp(nmchk,name,l-1) && name[l-1]=='.') return 1; + } + else + { + if (name_len == l && !stricmp(nmchk,name)) return 1; + } + } + } + + return 0; +} + +opcodeRec *nseel_resolve_named_symbol(compileContext *ctx, opcodeRec *rec, int parmcnt, int *errOut) +{ + const int isFunctionMode = parmcnt >= 0; + int rel_prefix_len=0; + int rel_prefix_idx=-2; + int i; + char match_parmcnt[4]={-1,-1,-1,-1}; // [3] is guess + unsigned char match_parmcnt_pos=0; + char *sname = (char *)rec->relname; + int is_string_prefix = parmcnt < 0 && sname[0] == '#'; + const char *prevent_function_calls = NULL; + + if (errOut) *errOut = 0; + + if (sname) sname += is_string_prefix; + + if (rec->opcodeType != OPCODETYPE_VARPTR || !sname || !sname[0]) return NULL; + + if (!isFunctionMode && !is_string_prefix && !strnicmp(sname,"reg",3) && isdigit(sname[3]) && isdigit(sname[4]) && !sname[5]) + { + EEL_F *a=get_global_var(ctx,sname,1); + if (a) + { + rec->parms.dv.valuePtr = a; + sname[0]=0; // for dump_ops compat really, but this shouldn't be needed anyway + } + return rec; + } + + if (ctx->function_curName) + { + if (!strnicmp(sname,"this.",5)) + { + rel_prefix_len=5; + rel_prefix_idx=-1; + } + else if (!stricmp(sname,"this")) + { + rel_prefix_len=4; + rel_prefix_idx=-1; + } + + // scan for parameters/local variables before user functions + if (rel_prefix_idx < -1 && + ctx->function_localTable_Size[0] > 0 && + ctx->function_localTable_Names[0] && + ctx->function_localTable_ValuePtrs) + { + char * const * const namelist = ctx->function_localTable_Names[0]; + const int namelist_sz = ctx->function_localTable_Size[0]; + for (i=0; i < namelist_sz; i++) + { + const char *p = namelist[i]; + if (p) + { + if (!isFunctionMode && !is_string_prefix && !strnicmp(p,sname,NSEEL_MAX_VARIABLE_NAMELEN)) + { + rec->opcodeType = OPCODETYPE_VARPTRPTR; + rec->parms.dv.valuePtr=(EEL_F *)(ctx->function_localTable_ValuePtrs+i); + rec->parms.dv.directValue=0.0; + return rec; + } + else + { + const size_t plen = strlen(p); + if (plen > 1 && p[plen-1] == '*' && !strnicmp(p,sname,plen-1) && ((sname[plen-1] == '.'&&sname[plen]) || !sname[plen-1])) + { + rel_prefix_len=(int) (sname[plen-1] ? plen : plen-1); + rel_prefix_idx=i; + break; + } + } + } + } + } + // if instance name set, translate sname or sname.* into "this.sname.*" + if (rel_prefix_idx < -1 && + ctx->function_localTable_Size[1] > 0 && + ctx->function_localTable_Names[1]) + { + char * const * const namelist = ctx->function_localTable_Names[1]; + const int namelist_sz = ctx->function_localTable_Size[1]; + const char *full_sname = rec->relname; // include # in checks + for (i=0; i < namelist_sz; i++) + { + const char *p = namelist[i]; + if (p && *p) + { + const size_t tl = strlen(p); + if (!strnicmp(p,full_sname,tl) && (full_sname[tl] == 0 || full_sname[tl] == '.')) + { + rel_prefix_len=0; // treat as though this. prefixes is present + rel_prefix_idx=-1; + break; + } + } + } + } + if (rel_prefix_idx >= -1) + { + ctx->function_usesNamespaces=1; + } + } // ctx->function_curName + + if (!isFunctionMode) + { + // instance variables + if (rel_prefix_idx >= -1) + { + rec->opcodeType = OPCODETYPE_VALUE_FROM_NAMESPACENAME; + rec->namespaceidx = rel_prefix_idx; + if (rel_prefix_len > 0) + { + if (is_string_prefix) sname[-1] = '#'; + memmove(sname, sname+rel_prefix_len, strlen(sname + rel_prefix_len) + 1); + } + } + else + { + // no namespace index, so it must be a global + if (!validate_varname_for_function(ctx,rec->relname)) + { + if (errOut) *errOut = 1; + if (ctx->last_error_string[0]) lstrcatn(ctx->last_error_string, ", ", sizeof(ctx->last_error_string)); + snprintf_append(ctx->last_error_string,sizeof(ctx->last_error_string),"global '%s' inaccessible",rec->relname); + return NULL; + } + } + + return rec; + } + + if (ctx->func_check) + prevent_function_calls = ctx->func_check(sname,ctx->func_check_user); + + ////////// function mode + // first off, while() and loop() are special and can't be overridden + // + if (parmcnt == 1 && !stricmp("while",sname) && !prevent_function_calls) + { + rec->opcodeType = OPCODETYPE_FUNC1; + rec->fntype = FN_WHILE; + return rec; + } + if (parmcnt == 2 && !stricmp("loop",sname) && !prevent_function_calls) + { + rec->opcodeType = OPCODETYPE_FUNC2; + rec->fntype = FN_LOOP; + return rec; + } + + // + // resolve user function names before builtin functions -- this allows the user to override default functions + if (!(ctx->current_compile_flags & NSEEL_CODE_COMPILE_FLAG_ONLY_BUILTIN_FUNCTIONS)) + { + _codeHandleFunctionRec *best=NULL; + size_t bestlen=0; + const char * const ourcall = sname+rel_prefix_len; + const size_t ourcall_len = strlen(ourcall); + int pass; + for (pass=0;pass<2;pass++) + { + _codeHandleFunctionRec *fr = pass ? ctx->functions_common : ctx->functions_local; + // sname is [namespace.[ns.]]function, find best match of function that matches the right end + while (fr) + { + int this_np = fr->num_params; + const char *thisfunc = fr->fname; + const size_t thisfunc_len = strlen(thisfunc); + if (this_np < 1) this_np=1; + if (thisfunc_len == ourcall_len && !stricmp(thisfunc,ourcall)) + { + if (this_np == parmcnt) + { + bestlen = thisfunc_len; + best = fr; + break; // found exact match, finished + } + else + { + if (match_parmcnt_pos < 3) match_parmcnt[match_parmcnt_pos++] = fr->num_params; + } + } + + if (thisfunc_len > bestlen && thisfunc_len < ourcall_len && ourcall[ourcall_len - thisfunc_len - 1] == '.' && !stricmp(thisfunc,ourcall + ourcall_len - thisfunc_len)) + { + if (this_np == parmcnt) + { + bestlen = thisfunc_len; + best = fr; + } + else + if (match_parmcnt[3]<0) match_parmcnt[3]=fr->num_params; + } + fr=fr->next; + } + if (fr) break; // found exact match, finished + } + + if (best) + { + switch (parmcnt) + { + case 0: + case 1: rec->opcodeType = OPCODETYPE_FUNC1; break; + case 2: rec->opcodeType = OPCODETYPE_FUNC2; break; + case 3: rec->opcodeType = OPCODETYPE_FUNC3; break; + default: rec->opcodeType = OPCODETYPE_FUNCX; break; + } + if (ourcall != rec->relname) memmove((char *)rec->relname, ourcall, strlen(ourcall)+1); + + if (ctx->function_curName && rel_prefix_idx<0) + { + // if no namespace specified, and this.commonprefix.func() called, remove common prefixes and set prefixidx to be this + const char *p=ctx->function_curName; + if (*p) p++; + while (*p && *p != '.') p++; + if (*p && p[1]) // we have a dot! + { + while (p[1]) p++; // go to last char of string, which doesn't allow possible trailing dot to be checked + + while (--p > ctx->function_curName) // do not check possible leading dot + { + if (*p == '.') + { + const size_t cmplen = p+1-ctx->function_curName; + if (!strnicmp(rec->relname,ctx->function_curName,cmplen) && rec->relname[cmplen]) + { + const char *src=rec->relname + cmplen; + memmove((char *)rec->relname, src, strlen(src)+1); + rel_prefix_idx=-1; + ctx->function_usesNamespaces=1; + break; + } + } + } + } + } + + if (ctx->function_curName && rel_prefix_idx < -1 && + strchr(rec->relname,'.') && !validate_varname_for_function(ctx,rec->relname)) + { + if (errOut) *errOut = 1; + if (ctx->last_error_string[0]) lstrcatn(ctx->last_error_string, ", ", sizeof(ctx->last_error_string)); + snprintf_append(ctx->last_error_string,sizeof(ctx->last_error_string),"namespaced function '%s' inaccessible",rec->relname); + return NULL; + } + + rec->namespaceidx = rel_prefix_idx; + rec->fntype = FUNCTYPE_EELFUNC; + rec->fn = best; + return rec; + } + } + + if (prevent_function_calls) + { + if (ctx->last_error_string[0]) lstrcatn(ctx->last_error_string, ", ", sizeof(ctx->last_error_string)); + snprintf_append(ctx->last_error_string,sizeof(ctx->last_error_string),"'%.30s': %s",sname, prevent_function_calls); + if (errOut) *errOut = 0; + return NULL; + } + +#ifdef NSEEL_EEL1_COMPAT_MODE + if (!stricmp(sname,"assign")) + { + if (parmcnt == 2) + { + rec->opcodeType = OPCODETYPE_FUNC2; + rec->fntype = FN_ASSIGN; + return rec; + } + if (match_parmcnt_pos < 3) match_parmcnt[match_parmcnt_pos++] = 2; + } + else if (!stricmp(sname,"if")) + { + if (parmcnt == 3) + { + rec->opcodeType = OPCODETYPE_FUNC3; + rec->fntype = FN_IF_ELSE; + return rec; + } + if (match_parmcnt_pos < 3) match_parmcnt[match_parmcnt_pos++] = 3; + } + else if (!stricmp(sname,"equal")) + { + if (parmcnt == 2) + { + rec->opcodeType = OPCODETYPE_FUNC2; + rec->fntype = FN_EQ; + return rec; + } + if (match_parmcnt_pos < 3) match_parmcnt[match_parmcnt_pos++] = 2; + } + else if (!stricmp(sname,"below")) + { + if (parmcnt == 2) + { + rec->opcodeType = OPCODETYPE_FUNC2; + rec->fntype = FN_LT; + return rec; + } + if (match_parmcnt_pos < 3) match_parmcnt[match_parmcnt_pos++] = 2; + } + else if (!stricmp(sname,"above")) + { + if (parmcnt == 2) + { + rec->opcodeType = OPCODETYPE_FUNC2; + rec->fntype = FN_GT; + return rec; + } + if (match_parmcnt_pos < 3) match_parmcnt[match_parmcnt_pos++] = 2; + } + else if (!stricmp(sname,"bnot")) + { + if (parmcnt == 1) + { + rec->opcodeType = OPCODETYPE_FUNC1; + rec->fntype = FN_NOT; + return rec; + } + if (match_parmcnt_pos < 3) match_parmcnt[match_parmcnt_pos++] = 1; + } + else if (!stricmp(sname,"megabuf")) + { + if (parmcnt == 1) + { + rec->opcodeType = OPCODETYPE_FUNC1; + rec->fntype = FN_MEMORY; + return rec; + } + if (match_parmcnt_pos < 3) match_parmcnt[match_parmcnt_pos++] = 1; + } + else if (!stricmp(sname,"gmegabuf")) + { + if (parmcnt == 1) + { + rec->opcodeType = OPCODETYPE_FUNC1; + rec->fntype = FN_GMEMORY; + return rec; + } + if (match_parmcnt_pos < 3) match_parmcnt[match_parmcnt_pos++] = 1; + } + else +#endif + // convert legacy pow() to FN_POW + if (!stricmp("pow",sname)) + { + if (parmcnt == 2) + { + rec->opcodeType = OPCODETYPE_FUNC2; + rec->fntype = FN_POW; + return rec; + } + if (match_parmcnt_pos < 3) match_parmcnt[match_parmcnt_pos++] = 2; + } + else if (!stricmp("__denormal_likely",sname) || !stricmp("__denormal_unlikely",sname)) + { + if (parmcnt == 1) + { + rec->opcodeType = OPCODETYPE_FUNC1; + rec->fntype = !stricmp("__denormal_likely",sname) ? FN_DENORMAL_LIKELY : FN_DENORMAL_UNLIKELY; + return rec; + } + } + + { + int chkamt=0; + functionType *f=nseel_getFunctionByName(ctx,sname,&chkamt); + if (f) while (chkamt-->=0) + { + const int pc_needed=(f->nParams&FUNCTIONTYPE_PARAMETERCOUNTMASK); + if ((f->nParams&BIF_TAKES_VARPARM_EX)==BIF_TAKES_VARPARM ? (parmcnt >= pc_needed) : (parmcnt == pc_needed)) + { + rec->fntype = FUNCTYPE_FUNCTIONTYPEREC; + rec->fn = (void *)f; + switch (parmcnt) + { + case 0: + case 1: rec->opcodeType = OPCODETYPE_FUNC1; break; + case 2: rec->opcodeType = OPCODETYPE_FUNC2; break; + case 3: rec->opcodeType = OPCODETYPE_FUNC3; break; + default: rec->opcodeType = OPCODETYPE_FUNCX; break; + } + return rec; + } + if (match_parmcnt_pos < 3) match_parmcnt[match_parmcnt_pos++] = (f->nParams&FUNCTIONTYPE_PARAMETERCOUNTMASK); + f++; + if (stricmp(f->name,sname)) break; + } + } + if (ctx->last_error_string[0]) lstrcatn(ctx->last_error_string, ", ", sizeof(ctx->last_error_string)); + if (match_parmcnt[3] >= 0) + { + if (match_parmcnt_pos<3) match_parmcnt[match_parmcnt_pos] = match_parmcnt[3]; + match_parmcnt_pos++; + } + + if (!match_parmcnt_pos) + snprintf_append(ctx->last_error_string,sizeof(ctx->last_error_string),"'%.30s' undefined",sname); + else + { + int x; + snprintf_append(ctx->last_error_string,sizeof(ctx->last_error_string),"'%.30s' needs ",sname); + for (x = 0; x < match_parmcnt_pos; x++) + snprintf_append(ctx->last_error_string,sizeof(ctx->last_error_string),"%s%d",x==0?"" : x == match_parmcnt_pos-1?" or ":",",match_parmcnt[x]); + lstrcatn(ctx->last_error_string," parms",sizeof(ctx->last_error_string)); + } + if (errOut) *errOut = match_parmcnt_pos > 0 ? parmcnt<match_parmcnt[0]?2:(match_parmcnt[0] < 2 ? 4:1) : 0; + return NULL; +} + +opcodeRec *nseel_setCompiledFunctionCallParameters(compileContext *ctx, opcodeRec *fn, opcodeRec *code1, opcodeRec *code2, opcodeRec *code3, opcodeRec *postCode, int *errOut) +{ + opcodeRec *r; + int np=0,x; + if (!fn || fn->opcodeType != OPCODETYPE_VARPTR || !fn->relname || !fn->relname[0]) + { + return NULL; + } + fn->parms.parms[0] = code1; + fn->parms.parms[1] = code2; + fn->parms.parms[2] = code3; + + for (x=0;x<3;x++) + { + opcodeRec *prni=fn->parms.parms[x]; + while (prni && np < NSEEL_MAX_EELFUNC_PARAMETERS) + { + const int isMP = prni->opcodeType == OPCODETYPE_MOREPARAMS; + np++; + if (!isMP) break; + prni = prni->parms.parms[1]; + } + } + r = nseel_resolve_named_symbol(ctx, fn, np<1 ? 1 : np ,errOut); + if (postCode && r) + { + if (code1 && r->opcodeType == OPCODETYPE_FUNC1 && r->fntype == FN_WHILE) + { + // change while(x) (postcode) to be + // while ((x) ? (postcode;1) : 0); + + r->parms.parms[0] = + nseel_createIfElse(ctx,r->parms.parms[0], + nseel_createSimpleCompiledFunction(ctx,FN_JOIN_STATEMENTS,2,postCode,nseel_createCompiledValue(ctx,1.0f)), + NULL); // NULL defaults to 0.0 + + } + else + { + snprintf_append(ctx->last_error_string,sizeof(ctx->last_error_string),"syntax error following function"); + *errOut = -1; + return NULL; + } + } + return r; +} + + +struct eelStringSegmentRec *nseel_createStringSegmentRec(compileContext *ctx, const char *str, int len) +{ + struct eelStringSegmentRec *r = newTmpBlock(ctx,sizeof(struct eelStringSegmentRec)); + if (r) + { + r->_next=0; + r->str_start=str; + r->str_len = len; + } + return r; +} + +opcodeRec *nseel_eelMakeOpcodeFromStringSegments(compileContext *ctx, struct eelStringSegmentRec *rec) +{ + if (ctx && ctx->onString) + { + return nseel_createCompiledValue(ctx, ctx->onString(ctx->caller_this,rec)); + } + + return NULL; +} + +opcodeRec *nseel_createMoreParametersOpcode(compileContext *ctx, opcodeRec *code1, opcodeRec *code2) +{ + opcodeRec *r=code1 && code2 ? newOpCode(ctx,NULL,OPCODETYPE_MOREPARAMS) : NULL; + if (r) + { + r->parms.parms[0] = code1; + r->parms.parms[1] = code2; + } + return r; +} + + +opcodeRec *nseel_createIfElse(compileContext *ctx, opcodeRec *code1, opcodeRec *code2, opcodeRec *code3) +{ + opcodeRec *r=code1 ? newOpCode(ctx,NULL,OPCODETYPE_FUNC3) : NULL; + if (r) + { + if (!code2) code2 = nseel_createCompiledValue(ctx,0.0); + if (!code3) code3 = nseel_createCompiledValue(ctx,0.0); + if (!code2||!code3) return NULL; + + r->fntype = FN_IF_ELSE; + r->parms.parms[0] = code1; + r->parms.parms[1] = code2; + r->parms.parms[2] = code3; + } + return r; +} + + +opcodeRec *nseel_createMemoryAccess(compileContext *ctx, opcodeRec *code1, opcodeRec *code2) +{ + if (code1 && code1->opcodeType == OPCODETYPE_VARPTR && !stricmp(code1->relname,"gmem")) + { + return nseel_createSimpleCompiledFunction(ctx, FN_GMEMORY,1,code2?code2:nseel_createCompiledValue(ctx,0.0),0); + } + if (code2 && (code2->opcodeType != OPCODETYPE_DIRECTVALUE || code2->parms.dv.directValue != 0.0)) + { + code1 = nseel_createSimpleCompiledFunction(ctx,FN_ADD,2,code1,code2); + } + return nseel_createSimpleCompiledFunction(ctx, FN_MEMORY,1,code1,0); +} + +opcodeRec *nseel_createSimpleCompiledFunction(compileContext *ctx, int fn, int np, opcodeRec *code1, opcodeRec *code2) +{ + opcodeRec *r=code1 && (np<2 || code2) ? newOpCode(ctx,NULL,np>=2 ? OPCODETYPE_FUNC2:OPCODETYPE_FUNC1) : NULL; + if (r) + { + r->fntype = fn; + r->parms.parms[0] = code1; + r->parms.parms[1] = code2; + if (fn == FN_JOIN_STATEMENTS) + { + r->fn = r; // for joins, fn is temporarily used for _tail pointers + if (code1 && code1->opcodeType == OPCODETYPE_FUNC2 && code1->fntype == fn) + { + opcodeRec *t = (opcodeRec *)code1->fn; + // keep joins in the form of dosomething->morestuff. + // in this instance, code1 is previous stuff to do, code2 is new stuff to do + r->parms.parms[0] = t->parms.parms[1]; + + code1->fn = (t->parms.parms[1] = r); + return code1; + } + } + } + return r; +} + + +// these are bitmasks; on request you can tell what is supported, and compileOpcodes will return one of them +#define RETURNVALUE_IGNORE 0 // ignore return value +#define RETURNVALUE_NORMAL 1 // pointer +#define RETURNVALUE_FPSTACK 2 +#define RETURNVALUE_BOOL 4 // P1 is nonzero if true +#define RETURNVALUE_BOOL_REVERSED 8 // P1 is zero if true +#define RETURNVALUE_CACHEABLE 16 // only to be used when (at least) RETURNVALUE_NORMAL is set + + + +static int compileOpcodes(compileContext *ctx, opcodeRec *op, unsigned char *bufOut, int bufOut_len, int *computTable, const namespaceInformation *namespacePathToThis, + int supportedReturnValues, int *rvType, int *fpStackUsage, int *canHaveDenormalOutput); + + +static unsigned char *compileCodeBlockWithRet(compileContext *ctx, opcodeRec *rec, int *computTableSize, const namespaceInformation *namespacePathToThis, + int supportedReturnValues, int *rvType, int *fpStackUse, int *canHaveDenormalOutput); + +_codeHandleFunctionRec *eel_createFunctionNamespacedInstance(compileContext *ctx, _codeHandleFunctionRec *fr, const char *nameptr) +{ + size_t n; + _codeHandleFunctionRec *subfr = + fr->isCommonFunction ? + ctx->isSharedFunctions ? newDataBlock(sizeof(_codeHandleFunctionRec),8) : + newCtxDataBlock(sizeof(_codeHandleFunctionRec),8) : // if common function, but derived version is in non-common context, set ownership to VM rather than us + newTmpBlock(ctx,sizeof(_codeHandleFunctionRec)); + + if (!subfr) return 0; + // fr points to functionname()'s rec, nameptr to blah.functionname() + + *subfr = *fr; + n = strlen(nameptr); + if (n > sizeof(subfr->fname)-1) n=sizeof(subfr->fname)-1; + memcpy(subfr->fname,nameptr,n); + subfr->fname[n]=0; + + subfr->next = NULL; + subfr->startptr=0; // make sure this code gets recompiled (with correct member ptrs) for this instance! + subfr->startptr_size=-1; + + // subfr->derivedCopies already points to the right place + fr->derivedCopies = subfr; + + return subfr; + +} +static void combineNamespaceFields(char *nm, const namespaceInformation *namespaceInfo, const char *relname, int thisctx) // nm must be NSEEL_MAX_VARIABLE_NAMELEN+1 bytes +{ + const char *prefix = namespaceInfo ? + thisctx<0 ? (thisctx == -1 ? namespaceInfo->namespacePathToThis : NULL) : (thisctx < MAX_SUB_NAMESPACES ? namespaceInfo->subParmInfo[thisctx] : NULL) + : NULL; + int lfp = 0, lrn=relname ? (int)strlen(relname) : 0; + if (prefix) while (prefix[lfp] && prefix[lfp] != ':' && lfp < NSEEL_MAX_VARIABLE_NAMELEN) lfp++; + if (!relname) relname = ""; + + while (*relname == '.') // if relname begins with ., then remove a chunk of context from prefix + { + relname++; + while (lfp>0 && prefix[lfp-1] != '.') lfp--; + if (lfp>0) lfp--; + } + + if (lfp > NSEEL_MAX_VARIABLE_NAMELEN-3) lfp=NSEEL_MAX_VARIABLE_NAMELEN-3; + if (lfp>0) memcpy(nm,prefix,lfp); + + if (lrn > NSEEL_MAX_VARIABLE_NAMELEN - lfp - (lfp>0)) lrn=NSEEL_MAX_VARIABLE_NAMELEN - lfp - (lfp>0); + if (lrn > 0) + { + if (lfp>0) nm[lfp++] = '.'; + memcpy(nm+lfp,relname,lrn); + lfp+=lrn; + } + nm[lfp++]=0; +} + + +//--------------------------------------------------------------------------------------------------------------- +static void *nseel_getBuiltinFunctionAddress(compileContext *ctx, + int fntype, void *fn, + NSEEL_PPPROC *pProc, void ***replList, + void **endP, int *abiInfo, int preferredReturnValues, const EEL_F *hasConstParm1, const EEL_F *hasConstParm2) +{ + const EEL_F *firstConstParm = hasConstParm1 ? hasConstParm1 : hasConstParm2; + static void *pow_replptrs[4]={&pow,}; + + switch (fntype) + { +#define RF(x) *endP = nseel_asm_##x##_end; return (void*)nseel_asm_##x + + + case FN_MUL_OP: + *abiInfo=BIF_LASTPARMONSTACK|BIF_FPSTACKUSE(2)|BIF_CLEARDENORMAL; + RF(mul_op); + case FN_DIV_OP: + *abiInfo=BIF_LASTPARMONSTACK|BIF_FPSTACKUSE(2)|BIF_CLEARDENORMAL; + RF(div_op); + case FN_OR_OP: + *abiInfo=BIF_LASTPARMONSTACK|BIF_FPSTACKUSE(2)|BIF_CLEARDENORMAL; + RF(or_op); + case FN_XOR_OP: + *abiInfo=BIF_LASTPARMONSTACK|BIF_FPSTACKUSE(2)|BIF_CLEARDENORMAL; + RF(xor_op); + case FN_AND_OP: + *abiInfo=BIF_LASTPARMONSTACK|BIF_FPSTACKUSE(2)|BIF_CLEARDENORMAL; + RF(and_op); + case FN_MOD_OP: + *abiInfo=BIF_LASTPARMONSTACK|BIF_FPSTACKUSE(2)|BIF_CLEARDENORMAL; + RF(mod_op); + case FN_ADD_OP: + *abiInfo=BIF_LASTPARMONSTACK|BIF_FPSTACKUSE(2)|BIF_CLEARDENORMAL; + RF(add_op); + case FN_SUB_OP: + *abiInfo=BIF_LASTPARMONSTACK|BIF_FPSTACKUSE(2)|BIF_CLEARDENORMAL; + RF(sub_op); + case FN_POW_OP: + *abiInfo=BIF_LASTPARMONSTACK|BIF_CLEARDENORMAL; + *replList = pow_replptrs; + RF(2pdds); + case FN_POW: + *abiInfo = BIF_RETURNSONSTACK|BIF_TWOPARMSONFPSTACK;//BIF_FPSTACKUSE(2) might be safe, need to look at pow()'s implementation, but safer bet is to disallow fp stack caching for this expression + *replList = pow_replptrs; + RF(2pdd); + case FN_ADD: + *abiInfo = BIF_RETURNSONSTACK|BIF_TWOPARMSONFPSTACK_LAZY|BIF_FPSTACKUSE(2); + // for x +- non-denormal-constant, we can set BIF_CLEARDENORMAL + if (firstConstParm && fabs(*firstConstParm) > DENORMAL_CLEARING_THRESHOLD) *abiInfo |= BIF_CLEARDENORMAL; + RF(add); + case FN_SUB: + *abiInfo = BIF_RETURNSONSTACK|BIF_TWOPARMSONFPSTACK|BIF_FPSTACKUSE(2); + // for x +- non-denormal-constant, we can set BIF_CLEARDENORMAL + if (firstConstParm && fabs(*firstConstParm) > DENORMAL_CLEARING_THRESHOLD) *abiInfo |= BIF_CLEARDENORMAL; + RF(sub); + case FN_MULTIPLY: + *abiInfo = BIF_RETURNSONSTACK|BIF_TWOPARMSONFPSTACK_LAZY|BIF_FPSTACKUSE(2); + // for x*constant-greater-than-eq-1, we can set BIF_WONTMAKEDENORMAL + if (firstConstParm && fabs(*firstConstParm) >= 1.0) *abiInfo |= BIF_WONTMAKEDENORMAL; + RF(mul); + case FN_DIVIDE: + *abiInfo = BIF_RETURNSONSTACK|BIF_TWOPARMSONFPSTACK|BIF_FPSTACKUSE(2); + // for x/constant-less-than-eq-1, we can set BIF_WONTMAKEDENORMAL + if (firstConstParm && fabs(*firstConstParm) <= 1.0) *abiInfo |= BIF_WONTMAKEDENORMAL; + RF(div); + case FN_MOD: + *abiInfo = BIF_RETURNSONSTACK|BIF_TWOPARMSONFPSTACK|BIF_FPSTACKUSE(1)|BIF_CLEARDENORMAL; + RF(mod); + case FN_ASSIGN: + *abiInfo = BIF_FPSTACKUSE(1)|BIF_CLEARDENORMAL; + RF(assign); + case FN_AND: *abiInfo = BIF_RETURNSONSTACK|BIF_TWOPARMSONFPSTACK_LAZY|BIF_FPSTACKUSE(2)|BIF_CLEARDENORMAL; RF(and); + case FN_OR: *abiInfo = BIF_RETURNSONSTACK|BIF_TWOPARMSONFPSTACK_LAZY|BIF_FPSTACKUSE(2)|BIF_CLEARDENORMAL; RF(or); + case FN_XOR: + *abiInfo = BIF_RETURNSONSTACK|BIF_TWOPARMSONFPSTACK_LAZY|BIF_FPSTACKUSE(2)|BIF_CLEARDENORMAL; + RF(xor); + case FN_SHR: + *abiInfo = BIF_RETURNSONSTACK|BIF_TWOPARMSONFPSTACK|BIF_FPSTACKUSE(2)|BIF_CLEARDENORMAL; + RF(shr); + case FN_SHL: + *abiInfo = BIF_RETURNSONSTACK|BIF_TWOPARMSONFPSTACK|BIF_FPSTACKUSE(2)|BIF_CLEARDENORMAL; + RF(shl); +#ifndef EEL_TARGET_PORTABLE + case FN_NOTNOT: *abiInfo = BIF_LASTPARM_ASBOOL|BIF_RETURNSBOOL|BIF_FPSTACKUSE(1); RF(uplus); +#else + case FN_NOTNOT: *abiInfo = BIF_LASTPARM_ASBOOL|BIF_RETURNSBOOL|BIF_FPSTACKUSE(1); RF(bnotnot); +#endif + case FN_UMINUS: *abiInfo = BIF_RETURNSONSTACK|BIF_LASTPARMONSTACK|BIF_WONTMAKEDENORMAL; RF(uminus); + case FN_NOT: *abiInfo = BIF_LASTPARM_ASBOOL|BIF_RETURNSBOOL|BIF_FPSTACKUSE(1); RF(bnot); + + case FN_EQ: + *abiInfo = BIF_TWOPARMSONFPSTACK_LAZY|BIF_RETURNSBOOL|BIF_FPSTACKUSE(2); + RF(equal); + case FN_EQ_EXACT: + *abiInfo=BIF_TWOPARMSONFPSTACK_LAZY|BIF_RETURNSBOOL|BIF_FPSTACKUSE(2); + RF(equal_exact); + case FN_NE: + *abiInfo=BIF_TWOPARMSONFPSTACK_LAZY|BIF_RETURNSBOOL|BIF_FPSTACKUSE(2); + RF(notequal); + case FN_NE_EXACT: + *abiInfo=BIF_TWOPARMSONFPSTACK_LAZY|BIF_RETURNSBOOL|BIF_FPSTACKUSE(2); + RF(notequal_exact); + case FN_LOGICAL_AND: + *abiInfo = BIF_RETURNSBOOL; + RF(band); + case FN_LOGICAL_OR: + *abiInfo = BIF_RETURNSBOOL; + RF(bor); + +#ifdef GLUE_HAS_FXCH + case FN_GT: + *abiInfo = BIF_TWOPARMSONFPSTACK|BIF_RETURNSBOOL|BIF_FPSTACKUSE(2); + RF(above); + case FN_GTE: + *abiInfo = BIF_TWOPARMSONFPSTACK|BIF_RETURNSBOOL|BIF_REVERSEFPORDER|BIF_FPSTACKUSE(2); + RF(beloweq); + case FN_LT: + *abiInfo = BIF_TWOPARMSONFPSTACK|BIF_RETURNSBOOL|BIF_REVERSEFPORDER|BIF_FPSTACKUSE(2); + RF(above); + case FN_LTE: + *abiInfo = BIF_TWOPARMSONFPSTACK|BIF_RETURNSBOOL|BIF_FPSTACKUSE(2); + RF(beloweq); +#else + case FN_GT: + *abiInfo = BIF_RETURNSBOOL|BIF_LASTPARMONSTACK; + RF(above); + case FN_GTE: + *abiInfo = BIF_RETURNSBOOL|BIF_LASTPARMONSTACK; + RF(aboveeq); + case FN_LT: + *abiInfo = BIF_RETURNSBOOL|BIF_LASTPARMONSTACK; + RF(below); + case FN_LTE: + *abiInfo = BIF_RETURNSBOOL|BIF_LASTPARMONSTACK; + RF(beloweq); +#endif + + +#undef RF +#define RF(x) *endP = _asm_##x##_end; return (void*)_asm_##x + + case FN_MEMORY: + { + static void *replptrs[4]={&__NSEEL_RAMAlloc,}; + *replList = replptrs; + *abiInfo = BIF_LASTPARMONSTACK|BIF_FPSTACKUSE(1)|BIF_CLEARDENORMAL; + #ifdef GLUE_MEM_NEEDS_PPROC + *pProc = NSEEL_PProc_RAM; + #endif + RF(megabuf); + } + break; + case FN_GMEMORY: + { + static void *replptrs[4]={&__NSEEL_RAMAllocGMEM,}; + *replList = replptrs; + *abiInfo=BIF_LASTPARMONSTACK|BIF_FPSTACKUSE(1)|BIF_CLEARDENORMAL; + *pProc=NSEEL_PProc_GRAM; + RF(gmegabuf); + } + break; +#undef RF + + case FUNCTYPE_FUNCTIONTYPEREC: + if (fn) + { + functionType *p=(functionType *)fn; + + // if prefers fpstack or bool, or ignoring value, then use fp-stack versions + if ((preferredReturnValues&(RETURNVALUE_BOOL|RETURNVALUE_FPSTACK)) || !preferredReturnValues) + { + static functionType min2={ "min", nseel_asm_min_fp,nseel_asm_min_fp_end, 2|NSEEL_NPARAMS_FLAG_CONST|BIF_RETURNSONSTACK|BIF_TWOPARMSONFPSTACK_LAZY|BIF_FPSTACKUSE(2)|BIF_WONTMAKEDENORMAL }; + static functionType max2={ "max", nseel_asm_max_fp,nseel_asm_max_fp_end, 2|NSEEL_NPARAMS_FLAG_CONST|BIF_RETURNSONSTACK|BIF_TWOPARMSONFPSTACK_LAZY|BIF_FPSTACKUSE(2)|BIF_WONTMAKEDENORMAL }; + + if (p->afunc == (void*)nseel_asm_min) p = &min2; + else if (p->afunc == (void*)nseel_asm_max) p = &max2; + } + + *replList=p->replptrs; + *pProc=p->pProc; + *endP = p->func_e; + *abiInfo = p->nParams & BIF_NPARAMS_MASK; + if (firstConstParm) + { + const char *name=p->name; + if (!strcmp(name,"min") && *firstConstParm < -1.0e-10) *abiInfo |= BIF_CLEARDENORMAL; + else if (!strcmp(name,"max") && *firstConstParm > 1.0e-10) *abiInfo |= BIF_CLEARDENORMAL; + } + return p->afunc; + } + break; + } + + return 0; +} + + + +static void *nseel_getEELFunctionAddress(compileContext *ctx, + opcodeRec *op, + int *customFuncParmSize, int *customFuncLocalStorageSize, + EEL_F ***customFuncLocalStorage, int *computTableTop, + void **endP, int *isRaw, int wantCodeGenerated, + const namespaceInformation *namespacePathToThis, int *rvMode, int *fpStackUse, int *canHaveDenormalOutput, + opcodeRec **ordered_parmptrs, int num_ordered_parmptrs + ) // if wantCodeGenerated is false, can return bogus pointers in raw mode +{ + _codeHandleFunctionRec *fn = (_codeHandleFunctionRec*)op->fn; + + namespaceInformation local_namespace={NULL}; + char prefix_buf[NSEEL_MAX_VARIABLE_NAMELEN+1], nm[NSEEL_MAX_FUNCSIG_NAME+1]; + if (!fn) return NULL; + + // op->relname ptr is [whatever.]funcname + if (fn->parameterAsNamespaceMask || fn->usesNamespaces) + { + if (wantCodeGenerated) + { + char *p = prefix_buf; + combineNamespaceFields(nm,namespacePathToThis,op->relname,op->namespaceidx); + lstrcpyn_safe(prefix_buf,nm,sizeof(prefix_buf)); + local_namespace.namespacePathToThis = prefix_buf; + // nm is full path of function, prefix_buf will be the path not including function name (unless function name only) + while (*p) p++; + while (p >= prefix_buf && *p != '.') p--; + if (p > prefix_buf) *p=0; + } + if (fn->parameterAsNamespaceMask) + { + int x; + for(x=0;x<MAX_SUB_NAMESPACES && x < fn->num_params;x++) + { + if (fn->parameterAsNamespaceMask & (((unsigned int)1)<<x)) + { + if (wantCodeGenerated) + { + const char *rn=NULL; + char tmp[NSEEL_MAX_VARIABLE_NAMELEN+1]; + if (x < num_ordered_parmptrs && ordered_parmptrs[x]) + { + if (ordered_parmptrs[x]->opcodeType == OPCODETYPE_VARPTR) + { + rn=ordered_parmptrs[x]->relname; + } + else if (ordered_parmptrs[x]->opcodeType == OPCODETYPE_VALUE_FROM_NAMESPACENAME) + { + const char *p=ordered_parmptrs[x]->relname; + if (*p == '#') p++; + combineNamespaceFields(tmp,namespacePathToThis,p,ordered_parmptrs[x]->namespaceidx); + rn = tmp; + } + } + + if (!rn) + { + // todo: figure out how to give correct line number/offset (ugh) + snprintf(ctx->last_error_string,sizeof(ctx->last_error_string),"parameter %d to %.120s() must be namespace",x+1,fn->fname); + return NULL; + } + + lstrcatn(nm,":",sizeof(nm)); + + local_namespace.subParmInfo[x] = nm+strlen(nm); + lstrcatn(nm,rn,sizeof(nm)); + } + ordered_parmptrs[x] = NULL; // prevent caller from bothering generating parameters + } + } + } + if (wantCodeGenerated) + { + _codeHandleFunctionRec *fr = fn; + // find namespace-adjusted function (if generating code, otherwise assume size is the same) + fn = 0; // if this gets re-set, it will be the new function + while (fr && !fn) + { + if (!stricmp(fr->fname,nm)) fn = fr; + fr=fr->derivedCopies; + } + if (!fn) // generate copy of function + { + fn = eel_createFunctionNamespacedInstance(ctx,(_codeHandleFunctionRec*)op->fn,nm); + } + } + } + if (!fn) return NULL; + + if (!fn->startptr && fn->opcodes && fn->startptr_size != 0) + { + int sz = fn->startptr_size; + + if (sz < 0) + { + fn->tmpspace_req=0; + fn->rvMode = RETURNVALUE_IGNORE; + fn->canHaveDenormalOutput=0; + + sz = compileOpcodes(ctx,fn->opcodes,NULL,128*1024*1024,&fn->tmpspace_req, + wantCodeGenerated ? &local_namespace : NULL,RETURNVALUE_NORMAL|RETURNVALUE_FPSTACK, + &fn->rvMode,&fn->fpStackUsage,&fn->canHaveDenormalOutput); + if (sz<0) return NULL; + + fn->startptr_size = sz; + } + + if (!wantCodeGenerated) + { + // don't compile anything for now, just give stats + if (computTableTop) *computTableTop += fn->tmpspace_req; + *customFuncParmSize = fn->num_params; + *customFuncLocalStorage = fn->localstorage; + *customFuncLocalStorageSize = fn->localstorage_size; + *rvMode = fn->rvMode; + *fpStackUse = fn->fpStackUsage; + if (canHaveDenormalOutput) *canHaveDenormalOutput=fn->canHaveDenormalOutput; + + if (sz <= NSEEL_MAX_FUNCTION_SIZE_FOR_INLINE && !(ctx->optimizeDisableFlags&OPTFLAG_NO_INLINEFUNC)) + { + *isRaw = 1; + *endP = ((char *)1) + sz; + return (char *)1; + } + *endP = (void*)nseel_asm_fcall_end; + return (void*)nseel_asm_fcall; + } + + if (sz <= NSEEL_MAX_FUNCTION_SIZE_FOR_INLINE && !(ctx->optimizeDisableFlags&OPTFLAG_NO_INLINEFUNC)) + { + void *p=newTmpBlock(ctx,sz); + fn->tmpspace_req=0; + if (p) + { + fn->canHaveDenormalOutput=0; + if (fn->isCommonFunction) ctx->isGeneratingCommonFunction++; + sz=compileOpcodes(ctx,fn->opcodes,(unsigned char*)p,sz,&fn->tmpspace_req,&local_namespace,RETURNVALUE_NORMAL|RETURNVALUE_FPSTACK,&fn->rvMode,&fn->fpStackUsage,&fn->canHaveDenormalOutput); + if (fn->isCommonFunction) ctx->isGeneratingCommonFunction--; + // recompile function with native context pointers + if (sz>0) + { + fn->startptr_size=sz; + fn->startptr=p; + } + } + } + else + { + unsigned char *codeCall; + fn->tmpspace_req=0; + fn->fpStackUsage=0; + fn->canHaveDenormalOutput=0; + if (fn->isCommonFunction) ctx->isGeneratingCommonFunction++; + codeCall=compileCodeBlockWithRet(ctx,fn->opcodes,&fn->tmpspace_req,&local_namespace,RETURNVALUE_NORMAL|RETURNVALUE_FPSTACK,&fn->rvMode,&fn->fpStackUsage,&fn->canHaveDenormalOutput); + if (fn->isCommonFunction) ctx->isGeneratingCommonFunction--; + if (codeCall) + { + void *f=GLUE_realAddress(nseel_asm_fcall,nseel_asm_fcall_end,&sz); + fn->startptr = newTmpBlock(ctx,sz); + if (fn->startptr) + { + memcpy(fn->startptr,f,sz); + EEL_GLUE_set_immediate(fn->startptr,(INT_PTR)codeCall); + fn->startptr_size = sz; + } + } + } + } + + if (fn->startptr) + { + if (computTableTop) *computTableTop += fn->tmpspace_req; + *customFuncParmSize = fn->num_params; + *customFuncLocalStorage = fn->localstorage; + *customFuncLocalStorageSize = fn->localstorage_size; + *rvMode = fn->rvMode; + *fpStackUse = fn->fpStackUsage; + if (canHaveDenormalOutput) *canHaveDenormalOutput= fn->canHaveDenormalOutput; + *endP = (char*)fn->startptr + fn->startptr_size; + *isRaw=1; + return fn->startptr; + } + + return 0; +} + + + +// returns true if does something (other than calculating and throwing away a value) +static char optimizeOpcodes(compileContext *ctx, opcodeRec *op, int needsResult) +{ + opcodeRec *lastJoinOp=NULL; + char retv, retv_parm[3], joined_retv=0; + while (op && op->opcodeType == OPCODETYPE_FUNC2 && op->fntype == FN_JOIN_STATEMENTS) + { + if (!optimizeOpcodes(ctx,op->parms.parms[0], 0) || OPCODE_IS_TRIVIAL(op->parms.parms[0])) + { + // direct value, can skip ourselves + memcpy(op,op->parms.parms[1],sizeof(*op)); + } + else + { + joined_retv |= 1; + lastJoinOp = op; + op = op->parms.parms[1]; + } + } +goto start_over; + +#define RESTART_DIRECTVALUE(X) { op->parms.dv.directValue = (X); goto start_over_directvalue; } +start_over_directvalue: + op->opcodeType = OPCODETYPE_DIRECTVALUE; + op->parms.dv.valuePtr=NULL; + +start_over: // when an opcode changed substantially in optimization, goto here to reprocess it + + retv = retv_parm[0]=retv_parm[1]=retv_parm[2]=0; + + if (!op || // should never really happen + OPCODE_IS_TRIVIAL(op) || // should happen often (vars) + op->opcodeType < 0 || op->opcodeType >= OPCODETYPE_INVALID // should never happen (assert would be appropriate heh) + ) return joined_retv; + + if (!needsResult) + { + if (op->fntype == FUNCTYPE_EELFUNC) + { + needsResult=1; // assume eel functions are non-const for now + } + else if (op->fntype == FUNCTYPE_FUNCTIONTYPEREC) + { + functionType *pfn = (functionType *)op->fn; + if (!pfn || !(pfn->nParams&NSEEL_NPARAMS_FLAG_CONST)) needsResult=1; + } + else if (op->fntype >= FN_NONCONST_BEGIN && op->fntype < FUNCTYPE_SIMPLEMAX) + { + needsResult=1; + } + } + + if (op->opcodeType>=OPCODETYPE_FUNC2) retv_parm[1] = optimizeOpcodes(ctx,op->parms.parms[1], needsResult); + if (op->opcodeType>=OPCODETYPE_FUNC3) retv_parm[2] = optimizeOpcodes(ctx,op->parms.parms[2], needsResult); + + retv_parm[0] = optimizeOpcodes(ctx,op->parms.parms[0], needsResult || + (FNPTR_HAS_CONDITIONAL_EXEC(op) && (retv_parm[1] || retv_parm[2] || op->opcodeType <= OPCODETYPE_FUNC1)) ); + + if (op->opcodeType != OPCODETYPE_MOREPARAMS) + { + if (op->fntype >= 0 && op->fntype < FUNCTYPE_SIMPLEMAX) + { + if (op->opcodeType == OPCODETYPE_FUNC1) // within FUNCTYPE_SIMPLE + { + if (op->parms.parms[0]->opcodeType == OPCODETYPE_DIRECTVALUE) + { + switch (op->fntype) + { + case FN_NOTNOT: RESTART_DIRECTVALUE(fabs(op->parms.parms[0]->parms.dv.directValue)>=NSEEL_CLOSEFACTOR ? 1.0 : 0.0); + case FN_NOT: RESTART_DIRECTVALUE(fabs(op->parms.parms[0]->parms.dv.directValue)>=NSEEL_CLOSEFACTOR ? 0.0 : 1.0); + case FN_UMINUS: RESTART_DIRECTVALUE(- op->parms.parms[0]->parms.dv.directValue); + } + } + else if (op->fntype == FN_NOT || op->fntype == FN_NOTNOT) + { + if (op->parms.parms[0]->opcodeType == OPCODETYPE_FUNC1) + { + switch (op->parms.parms[0]->fntype) + { + case FN_UMINUS: + case FN_NOTNOT: // ignore any NOTNOTs UMINUS or UPLUS, they would have no effect anyway + op->parms.parms[0] = op->parms.parms[0]->parms.parms[0]; + goto start_over; + + case FN_NOT: + op->fntype = op->fntype==FN_NOT ? FN_NOTNOT : FN_NOT; // switch between FN_NOT and FN_NOTNOT + op->parms.parms[0] = op->parms.parms[0]->parms.parms[0]; + goto start_over; + } + } + else if (op->parms.parms[0]->opcodeType == OPCODETYPE_FUNC2) + { + int repl_type = -1; + switch (op->parms.parms[0]->fntype) + { + case FN_EQ: repl_type = FN_NE; break; + case FN_NE: repl_type = FN_EQ; break; + case FN_EQ_EXACT: repl_type = FN_NE_EXACT; break; + case FN_NE_EXACT: repl_type = FN_EQ_EXACT; break; + case FN_LT: repl_type = FN_GTE; break; + case FN_LTE: repl_type = FN_GT; break; + case FN_GT: repl_type = FN_LTE; break; + case FN_GTE: repl_type = FN_LT; break; + } + if (repl_type != -1) + { + const int oldtype = op->fntype; + memcpy(op,op->parms.parms[0],sizeof(*op)); + if (oldtype == FN_NOT) op->fntype = repl_type; + goto start_over; + } + } + } + } + else if (op->opcodeType == OPCODETYPE_FUNC2) // within FUNCTYPE_SIMPLE + { + const int dv0 = op->parms.parms[0]->opcodeType == OPCODETYPE_DIRECTVALUE; + const int dv1 = op->parms.parms[1]->opcodeType == OPCODETYPE_DIRECTVALUE; + if (dv0 && dv1) + { + int reval = -1; + switch (op->fntype) + { + case FN_MOD: + { + int a = (int) op->parms.parms[1]->parms.dv.directValue; + if (a) + { + a = (int) op->parms.parms[0]->parms.dv.directValue % a; + if (a<0) a=-a; + } + RESTART_DIRECTVALUE((EEL_F)a); + } + break; + case FN_SHL: RESTART_DIRECTVALUE(((int)op->parms.parms[0]->parms.dv.directValue) << ((int)op->parms.parms[1]->parms.dv.directValue)); + case FN_SHR: RESTART_DIRECTVALUE(((int)op->parms.parms[0]->parms.dv.directValue) >> ((int)op->parms.parms[1]->parms.dv.directValue)); + case FN_POW: RESTART_DIRECTVALUE(pow(op->parms.parms[0]->parms.dv.directValue, op->parms.parms[1]->parms.dv.directValue)); + case FN_DIVIDE: RESTART_DIRECTVALUE(op->parms.parms[0]->parms.dv.directValue / op->parms.parms[1]->parms.dv.directValue); + case FN_MULTIPLY: RESTART_DIRECTVALUE(op->parms.parms[0]->parms.dv.directValue * op->parms.parms[1]->parms.dv.directValue); + + case FN_ADD: RESTART_DIRECTVALUE(op->parms.parms[0]->parms.dv.directValue + op->parms.parms[1]->parms.dv.directValue); + case FN_SUB: RESTART_DIRECTVALUE(op->parms.parms[0]->parms.dv.directValue - op->parms.parms[1]->parms.dv.directValue); + case FN_AND: RESTART_DIRECTVALUE((double) (((WDL_INT64)op->parms.parms[0]->parms.dv.directValue) & ((WDL_INT64)op->parms.parms[1]->parms.dv.directValue))); + case FN_OR: RESTART_DIRECTVALUE((double) (((WDL_INT64)op->parms.parms[0]->parms.dv.directValue) | ((WDL_INT64)op->parms.parms[1]->parms.dv.directValue))); + case FN_XOR: RESTART_DIRECTVALUE((double) (((WDL_INT64)op->parms.parms[0]->parms.dv.directValue) ^ ((WDL_INT64)op->parms.parms[1]->parms.dv.directValue))); + + case FN_EQ: reval = fabs(op->parms.parms[0]->parms.dv.directValue - op->parms.parms[1]->parms.dv.directValue) < NSEEL_CLOSEFACTOR; break; + case FN_NE: reval = fabs(op->parms.parms[0]->parms.dv.directValue - op->parms.parms[1]->parms.dv.directValue) >= NSEEL_CLOSEFACTOR; break; + case FN_EQ_EXACT: reval = op->parms.parms[0]->parms.dv.directValue == op->parms.parms[1]->parms.dv.directValue; break; + case FN_NE_EXACT: reval = op->parms.parms[0]->parms.dv.directValue != op->parms.parms[1]->parms.dv.directValue; break; + case FN_LT: reval = op->parms.parms[0]->parms.dv.directValue < op->parms.parms[1]->parms.dv.directValue; break; + case FN_LTE: reval = op->parms.parms[0]->parms.dv.directValue <= op->parms.parms[1]->parms.dv.directValue; break; + case FN_GT: reval = op->parms.parms[0]->parms.dv.directValue > op->parms.parms[1]->parms.dv.directValue; break; + case FN_GTE: reval = op->parms.parms[0]->parms.dv.directValue >= op->parms.parms[1]->parms.dv.directValue; break; + case FN_LOGICAL_AND: reval = fabs(op->parms.parms[0]->parms.dv.directValue) >= NSEEL_CLOSEFACTOR && fabs(op->parms.parms[1]->parms.dv.directValue) >= NSEEL_CLOSEFACTOR; break; + case FN_LOGICAL_OR: reval = fabs(op->parms.parms[0]->parms.dv.directValue) >= NSEEL_CLOSEFACTOR || fabs(op->parms.parms[1]->parms.dv.directValue) >= NSEEL_CLOSEFACTOR; break; + } + + if (reval >= 0) RESTART_DIRECTVALUE((EEL_F) reval); + } + else if (dv0 || dv1) + { + double dvalue = op->parms.parms[!dv0]->parms.dv.directValue; + switch (op->fntype) + { + case FN_OR: + case FN_XOR: + if (!(WDL_INT64)dvalue) + { + // replace with or0 + static functionType fr={"or0",nseel_asm_or0, nseel_asm_or0_end, 1|NSEEL_NPARAMS_FLAG_CONST|BIF_LASTPARMONSTACK|BIF_RETURNSONSTACK|BIF_CLEARDENORMAL, {0}, NULL}; + + op->opcodeType = OPCODETYPE_FUNC1; + op->fntype = FUNCTYPE_FUNCTIONTYPEREC; + op->fn = &fr; + if (dv0) op->parms.parms[0] = op->parms.parms[1]; + goto start_over; + } + break; + case FN_SUB: + if (dv0) + { + if (dvalue == 0.0) + { + op->opcodeType = OPCODETYPE_FUNC1; + op->fntype = FN_UMINUS; + op->parms.parms[0] = op->parms.parms[1]; + goto start_over; + } + break; + } + // fall through, if dv1 we can remove +0.0 + + case FN_ADD: + if (dvalue == 0.0) + { + memcpy(op,op->parms.parms[!!dv0],sizeof(*op)); + goto start_over; + } + break; + case FN_AND: + if ((WDL_INT64)dvalue) break; + dvalue = 0.0; // treat x&0 as x*0, which optimizes to 0 + + // fall through + case FN_MULTIPLY: + if (dvalue == 0.0) // remove multiply by 0.0 (using 0.0 direct value as replacement), unless the nonzero side did something + { + if (!retv_parm[!!dv0]) + { + memcpy(op,op->parms.parms[!dv0],sizeof(*op)); // set to 0 if other action wouldn't do anything + goto start_over; + } + else + { + // this is 0.0 * oldexpressionthatmustbeprocessed or oldexpressionthatmustbeprocessed*0.0 + op->fntype = FN_JOIN_STATEMENTS; + + if (dv0) // 0.0*oldexpression, reverse the order so that 0 is returned + { + // set to (oldexpression;0) + opcodeRec *tmp = op->parms.parms[1]; + op->parms.parms[1] = op->parms.parms[0]; + op->parms.parms[0] = tmp; + } + goto start_over; + } + } + else if (dvalue == 1.0) // remove multiply by 1.0 (using non-1.0 value as replacement) + { + memcpy(op,op->parms.parms[!!dv0],sizeof(*op)); + goto start_over; + } + break; + case FN_POW: + if (dv1) + { + // x^0 = 1 + if (fabs(dvalue) < 1e-30) + { + RESTART_DIRECTVALUE(1.0); + } + // x^1 = x + if (fabs(dvalue-1.0) < 1e-30) + { + memcpy(op,op->parms.parms[0],sizeof(*op)); + goto start_over; + } + } + else if (dv0) + { + // pow(constant, x) = exp((x) * ln(constant)), if constant>0 + // opcodeRec *parm0 = op->parms.parms[0]; + if (dvalue > 0.0) + { + static functionType expcpy={ "exp", nseel_asm_1pdd,nseel_asm_1pdd_end, 1|NSEEL_NPARAMS_FLAG_CONST|BIF_RETURNSONSTACK|BIF_LASTPARMONSTACK, {&exp}, }; + + // 1^x = 1 + if (fabs(dvalue-1.0) < 1e-30) + { + RESTART_DIRECTVALUE(1.0); + } + + dvalue=log(dvalue); + + if (fabs(dvalue-1.0) < 1e-9) + { + // caller wanted e^x + op->parms.parms[0]=op->parms.parms[1]; + } + else + { + // it would be nice to replace 10^x with exp(log(10)*x) or 2^x with exp(log(2),x), but + // doing so breaks rounding. we could maybe only allow 10^x, which is used for dB conversion, + // but for now we should just force the programmer do it exp(log(10)*x) themselves. + break; + + /* + parm0->opcodeType = OPCODETYPE_FUNC2; + parm0->fntype = FN_MULTIPLY; + parm0->parms.parms[0] = nseel_createCompiledValue(ctx,dvalue); + parm0->parms.parms[1] = op->parms.parms[1]; + */ + } + + op->opcodeType = OPCODETYPE_FUNC1; + op->fntype = FUNCTYPE_FUNCTIONTYPEREC; + op->fn = &expcpy; + goto start_over; + } + } + break; + case FN_MOD: + if (dv1) + { + const int a = (int) dvalue; + if (!a) + { + RESTART_DIRECTVALUE(0.0); + } + } + break; + case FN_DIVIDE: + if (dv1) + { + if (dvalue == 1.0) // remove divide by 1.0 (using non-1.0 value as replacement) + { + memcpy(op,op->parms.parms[!!dv0],sizeof(*op)); + goto start_over; + } + else + { + // change to a multiply + if (dvalue == 0.0) + { + op->fntype = FN_MULTIPLY; + goto start_over; + } + else + { + double d = 1.0/dvalue; + + WDL_DenormalDoubleAccess *p = (WDL_DenormalDoubleAccess*)&d; + // allow conversion to multiply if reciprocal is exact + // we could also just look to see if the last few digits of the mantissa were 0, which would probably be good + // enough, but if the user really wants it they should do * (1/x) instead to force precalculation of reciprocal. + if (!p->w.lw && !(p->w.hw & 0xfffff)) + { + op->fntype = FN_MULTIPLY; + op->parms.parms[1]->parms.dv.directValue = d; + op->parms.parms[1]->parms.dv.valuePtr=NULL; + goto start_over; + } + } + } + } + else if (dvalue == 0.0) + { + if (!retv_parm[!!dv0]) + { + // if 0/x set to always 0. + // this is 0.0 / (oldexpression that can be eliminated) + memcpy(op,op->parms.parms[!dv0],sizeof(*op)); // set to 0 if other action wouldn't do anything + } + else + { + opcodeRec *tmp; + // this is 0.0 / oldexpressionthatmustbeprocessed + op->fntype = FN_JOIN_STATEMENTS; + tmp = op->parms.parms[1]; + op->parms.parms[1] = op->parms.parms[0]; + op->parms.parms[0] = tmp; + // set to (oldexpression;0) + } + goto start_over; + } + break; + case FN_EQ: + if (dvalue == 0.0) + { + // convert x == 0.0 to !x + op->opcodeType=OPCODETYPE_FUNC1; + op->fntype = FN_NOT; + if (dv0) op->parms.parms[0]=op->parms.parms[1]; + goto start_over; + } + break; + case FN_NE: + if (dvalue == 0.0) + { + // convert x != 0.0 to !! + op->opcodeType=OPCODETYPE_FUNC1; + op->fntype = FN_NOTNOT; + if (dv0) op->parms.parms[0]=op->parms.parms[1]; + goto start_over; + } + break; + case FN_LOGICAL_AND: + if (dv0) + { + // dvalue && expr + if (fabs(dvalue) < NSEEL_CLOSEFACTOR) + { + // 0 && expr, replace with 0 + RESTART_DIRECTVALUE(0.0); + } + else + { + // 1 && expr, replace with 0 != expr + op->fntype = FN_NE; + op->parms.parms[0]->parms.dv.valuePtr=NULL; + op->parms.parms[0]->parms.dv.directValue = 0.0; + } + } + else + { + // expr && dvalue + if (fabs(dvalue) < NSEEL_CLOSEFACTOR) + { + // expr && 0 + if (!retv_parm[0]) + { + // expr has no consequence, drop it + RESTART_DIRECTVALUE(0.0); + } + else + { + // replace with (expr; 0) + op->fntype = FN_JOIN_STATEMENTS; + op->parms.parms[1]->parms.dv.valuePtr=NULL; + op->parms.parms[1]->parms.dv.directValue = 0.0; + } + } + else + { + // expr && 1, replace with expr != 0 + op->fntype = FN_NE; + op->parms.parms[1]->parms.dv.valuePtr=NULL; + op->parms.parms[1]->parms.dv.directValue = 0.0; + } + } + goto start_over; + case FN_LOGICAL_OR: + if (dv0) + { + // dvalue || expr + if (fabs(dvalue) >= NSEEL_CLOSEFACTOR) + { + // 1 || expr, replace with 1 + RESTART_DIRECTVALUE(1.0); + } + else + { + // 0 || expr, replace with 0 != expr + op->fntype = FN_NE; + op->parms.parms[0]->parms.dv.valuePtr=NULL; + op->parms.parms[0]->parms.dv.directValue = 0.0; + } + } + else + { + // expr || dvalue + if (fabs(dvalue) >= NSEEL_CLOSEFACTOR) + { + // expr || 1 + if (!retv_parm[0]) + { + // expr has no consequence, drop it and return 1 + RESTART_DIRECTVALUE(1.0); + } + else + { + // replace with (expr; 1) + op->fntype = FN_JOIN_STATEMENTS; + op->parms.parms[1]->parms.dv.valuePtr=NULL; + op->parms.parms[1]->parms.dv.directValue = 1.0; + } + } + else + { + // expr || 0, replace with expr != 0 + op->fntype = FN_NE; + op->parms.parms[1]->parms.dv.valuePtr=NULL; + op->parms.parms[1]->parms.dv.directValue = 0.0; + } + } + goto start_over; + } + } // dv0 || dv1 + + // general optimization of two parameters + switch (op->fntype) + { + case FN_MULTIPLY: + { + opcodeRec *first_parm = op->parms.parms[0],*second_parm = op->parms.parms[1]; + + if (second_parm->opcodeType == first_parm->opcodeType) + { + switch(first_parm->opcodeType) + { + case OPCODETYPE_VALUE_FROM_NAMESPACENAME: + if (first_parm->namespaceidx != second_parm->namespaceidx) break; + // fall through + case OPCODETYPE_VARPTR: + if (first_parm->relname && second_parm->relname && !stricmp(second_parm->relname,first_parm->relname)) second_parm=NULL; + break; + case OPCODETYPE_VARPTRPTR: + if (first_parm->parms.dv.valuePtr && first_parm->parms.dv.valuePtr==second_parm->parms.dv.valuePtr) second_parm=NULL; + break; + + } + if (!second_parm) // switch from x*x to sqr(x) + { + static functionType sqrcpy={ "sqr", nseel_asm_sqr,nseel_asm_sqr_end, 1|NSEEL_NPARAMS_FLAG_CONST|BIF_RETURNSONSTACK|BIF_LASTPARMONSTACK|BIF_FPSTACKUSE(1) }; + op->opcodeType = OPCODETYPE_FUNC1; + op->fntype = FUNCTYPE_FUNCTIONTYPEREC; + op->fn = &sqrcpy; + goto start_over; + } + } + } + break; + case FN_POW: + { + opcodeRec *first_parm = op->parms.parms[0]; + if (first_parm->opcodeType == op->opcodeType && first_parm->fntype == FN_POW) + { + // since first_parm is a pow too, we can multiply the exponents. + + // set our base to be the base of the inner pow + op->parms.parms[0] = first_parm->parms.parms[0]; + + // make the old extra pow be a multiply of the exponents + first_parm->fntype = FN_MULTIPLY; + first_parm->parms.parms[0] = op->parms.parms[1]; + + // put that as the exponent + op->parms.parms[1] = first_parm; + + goto start_over; + } + } + break; + case FN_LOGICAL_AND: + case FN_LOGICAL_OR: + if (op->parms.parms[0]->fntype == FN_NOTNOT) + { + // remove notnot, unnecessary for input to &&/|| operators + op->parms.parms[0] = op->parms.parms[0]->parms.parms[0]; + goto start_over; + } + if (op->parms.parms[1]->fntype == FN_NOTNOT) + { + // remove notnot, unnecessary for input to &&/|| operators + op->parms.parms[1] = op->parms.parms[1]->parms.parms[0]; + goto start_over; + } + break; + } + } + else if (op->opcodeType==OPCODETYPE_FUNC3) // within FUNCTYPE_SIMPLE + { + if (op->fntype == FN_IF_ELSE) + { + if (op->parms.parms[0]->opcodeType == OPCODETYPE_DIRECTVALUE) + { + int s = fabs(op->parms.parms[0]->parms.dv.directValue) >= NSEEL_CLOSEFACTOR; + memcpy(op,op->parms.parms[s ? 1 : 2],sizeof(opcodeRec)); + goto start_over; + } + if (op->parms.parms[0]->opcodeType == OPCODETYPE_FUNC1) + { + if (op->parms.parms[0]->fntype == FN_NOTNOT) + { + // remove notnot, unnecessary for input to ? operator + op->parms.parms[0] = op->parms.parms[0]->parms.parms[0]; + goto start_over; + } + } + } + } + if (op->fntype >= FN_NONCONST_BEGIN && op->fntype < FUNCTYPE_SIMPLEMAX) retv|=1; + + // FUNCTYPE_SIMPLE + } + else if (op->fntype == FUNCTYPE_FUNCTIONTYPEREC && op->fn) + { + + /* + probably worth doing reduction on: + _divop (constant change to multiply) + _and + _or + abs + + maybe: + min + max + + + also, optimize should (recursively or maybe iteratively?) search transitive functions (mul/div) for more constant reduction possibilities + + + */ + + + functionType *pfn = (functionType *)op->fn; + + if (!(pfn->nParams&NSEEL_NPARAMS_FLAG_CONST)) retv|=1; + + if (op->opcodeType==OPCODETYPE_FUNC1) // within FUNCTYPE_FUNCTIONTYPEREC + { + if (op->parms.parms[0]->opcodeType == OPCODETYPE_DIRECTVALUE) + { + int suc=1; + EEL_F v = op->parms.parms[0]->parms.dv.directValue; + #define DOF(x) if (!strcmp(pfn->name,#x)) v = x(v); else + #define DOF2(x,y) if (!strcmp(pfn->name,#x)) v = x(y); else + DOF(sin) + DOF(cos) + DOF(tan) + DOF(asin) + DOF(acos) + DOF(atan) + DOF2(sqrt, fabs(v)) + DOF(exp) + DOF(log) + DOF(log10) + /* else */ suc=0; + #undef DOF + #undef DOF2 + if (suc) + { + RESTART_DIRECTVALUE(v); + } + + + } + } + else if (op->opcodeType==OPCODETYPE_FUNC2) // within FUNCTYPE_FUNCTIONTYPEREC + { + const int dv0=op->parms.parms[0]->opcodeType == OPCODETYPE_DIRECTVALUE; + const int dv1=op->parms.parms[1]->opcodeType == OPCODETYPE_DIRECTVALUE; + if (dv0 && dv1) + { + if (!strcmp(pfn->name,"atan2")) + { + RESTART_DIRECTVALUE(atan2(op->parms.parms[0]->parms.dv.directValue, op->parms.parms[1]->parms.dv.directValue)); + } + } + } + // FUNCTYPE_FUNCTIONTYPEREC + } + else + { + // unknown or eel func, assume non-const + retv |= 1; + } + } + + // if we need results, or our function has effects itself, then finish + if (retv || needsResult) + { + return retv || joined_retv || retv_parm[0] || retv_parm[1] || retv_parm[2]; + } + + // we don't need results here, and our function is const, which means we can remove it + { + int cnt=0, idx1=0, idx2=0, x; + for (x=0;x<3;x++) if (retv_parm[x]) { if (!cnt++) idx1=x; else idx2=x; } + + if (!cnt) // none of the parameters do anything, remove this opcode + { + if (lastJoinOp) + { + // replace previous join with its first linked opcode, removing this opcode completely + memcpy(lastJoinOp,lastJoinOp->parms.parms[0],sizeof(*lastJoinOp)); + } + else if (op->opcodeType != OPCODETYPE_DIRECTVALUE) + { + // allow caller to easily detect this as trivial and remove it + op->opcodeType = OPCODETYPE_DIRECTVALUE; + op->parms.dv.valuePtr=NULL; + op->parms.dv.directValue=0.0; + } + // return joined_retv below + } + else + { + // if parameters are non-const, and we're a conditional, preserve our function + if (FNPTR_HAS_CONDITIONAL_EXEC(op)) return 1; + + // otherwise, condense into either the non-const statement, or a join + if (cnt==1) + { + memcpy(op,op->parms.parms[idx1],sizeof(*op)); + } + else if (cnt == 2) + { + op->opcodeType = OPCODETYPE_FUNC2; + op->fntype = FN_JOIN_STATEMENTS; + op->fn = op; + op->parms.parms[0] = op->parms.parms[idx1]; + op->parms.parms[1] = op->parms.parms[idx2]; + op->parms.parms[2] = NULL; + } + else + { + // todo need to create a new opcodeRec here, for now just leave as is + // (non-conditional const 3 parameter functions are rare anyway) + } + return 1; + } + } + return joined_retv; +} + + +static int generateValueToReg(compileContext *ctx, opcodeRec *op, unsigned char *bufOut, int whichReg, const namespaceInformation *functionPrefix, int allowCache) +{ + EEL_F *b=NULL; + if (op->opcodeType==OPCODETYPE_VALUE_FROM_NAMESPACENAME) + { + char nm[NSEEL_MAX_VARIABLE_NAMELEN+1]; + const char *p = op->relname; + combineNamespaceFields(nm,functionPrefix,p+(*p == '#'),op->namespaceidx); + if (!nm[0]) return -1; + if (*p == '#') + { + if (ctx->isGeneratingCommonFunction) + b = newCtxDataBlock(sizeof(EEL_F),sizeof(EEL_F)); + else + b = newDataBlock(sizeof(EEL_F),sizeof(EEL_F)); + + if (!b) RET_MINUS1_FAIL("error creating storage for str") + + if (!ctx->onNamedString) return -1; // should never happen, will not generate OPCODETYPE_VALUE_FROM_NAMESPACENAME with # prefix if !onNamedString + + *b = ctx->onNamedString(ctx->caller_this,nm); + } + else + { + b = nseel_int_register_var(ctx,nm,0,NULL); + if (!b) RET_MINUS1_FAIL("error registering var") + } + } + else + { + if (op->opcodeType != OPCODETYPE_DIRECTVALUE) allowCache=0; + + if (op->opcodeType==OPCODETYPE_DIRECTVALUE_TEMPSTRING && ctx->onNamedString) + { + op->parms.dv.directValue = ctx->onNamedString(ctx->caller_this,""); + op->parms.dv.valuePtr = NULL; + } + + b=op->parms.dv.valuePtr; + if (!b && op->opcodeType == OPCODETYPE_VARPTR && op->relname && op->relname[0]) + { + op->parms.dv.valuePtr = b = nseel_int_register_var(ctx,op->relname,0,NULL); + } + + if (b && op->opcodeType == OPCODETYPE_VARPTRPTR) b = *(EEL_F **)b; + if (!b && allowCache) + { + int n=50; // only scan last X items + opcodeRec *r = ctx->directValueCache; + while (r && n--) + { + if (r->parms.dv.directValue == op->parms.dv.directValue && (b=r->parms.dv.valuePtr)) break; + r=(opcodeRec*)r->fn; + } + } + if (!b) + { + ctx->l_stats[3]++; + if (ctx->isGeneratingCommonFunction) + b = newCtxDataBlock(sizeof(EEL_F),sizeof(EEL_F)); + else + b = newDataBlock(sizeof(EEL_F),sizeof(EEL_F)); + + if (!b) RET_MINUS1_FAIL("error allocating data block") + + if (op->opcodeType != OPCODETYPE_VARPTRPTR) op->parms.dv.valuePtr = b; + #if EEL_F_SIZE == 8 + *b = denormal_filter_double2(op->parms.dv.directValue); + #else + *b = denormal_filter_float2(op->parms.dv.directValue); + #endif + + if (allowCache) + { + op->fn = ctx->directValueCache; + ctx->directValueCache = op; + } + } + } + + GLUE_MOV_PX_DIRECTVALUE_GEN(bufOut,(INT_PTR)b,whichReg); + return GLUE_MOV_PX_DIRECTVALUE_SIZE; +} + + +unsigned char *compileCodeBlockWithRet(compileContext *ctx, opcodeRec *rec, int *computTableSize, const namespaceInformation *namespacePathToThis, + int supportedReturnValues, int *rvType, int *fpStackUsage, int *canHaveDenormalOutput) +{ + unsigned char *p, *newblock2; + // generate code call + int funcsz=compileOpcodes(ctx,rec,NULL,1024*1024*128,NULL,namespacePathToThis,supportedReturnValues, rvType,fpStackUsage, NULL); + if (funcsz<0) return NULL; + + p = newblock2 = newCodeBlock(funcsz+ sizeof(GLUE_RET)+GLUE_FUNC_ENTER_SIZE+GLUE_FUNC_LEAVE_SIZE,32); + if (!newblock2) return NULL; + #if GLUE_FUNC_ENTER_SIZE > 0 + memcpy(p,&GLUE_FUNC_ENTER,GLUE_FUNC_ENTER_SIZE); + p += GLUE_FUNC_ENTER_SIZE; + #endif + *fpStackUsage=0; + funcsz=compileOpcodes(ctx,rec,p, funcsz, computTableSize,namespacePathToThis,supportedReturnValues, rvType,fpStackUsage, canHaveDenormalOutput); + if (funcsz<0) return NULL; + p+=funcsz; + + #if GLUE_FUNC_LEAVE_SIZE > 0 + memcpy(p,&GLUE_FUNC_LEAVE,GLUE_FUNC_LEAVE_SIZE); + p+=GLUE_FUNC_LEAVE_SIZE; + #endif + memcpy(p,&GLUE_RET,sizeof(GLUE_RET)); p+=sizeof(GLUE_RET); +#if defined(__arm__) || defined(__aarch64__) + __clear_cache(newblock2,p); +#endif + + ctx->l_stats[2]+=funcsz+2; + return newblock2; +} + +static int compileNativeFunctionCall(compileContext *ctx, opcodeRec *op, unsigned char *bufOut, int bufOut_len, int *computTableSize, const namespaceInformation *namespacePathToThis, + int *rvMode, int *fpStackUsage, int preferredReturnValues, int *canHaveDenormalOutput) +{ + // builtin function generation + int func_size=0; + int cfunc_abiinfo=0; + int local_fpstack_use=0; // how many items we have pushed onto the fp stack + int parm_size=0; + int restore_stack_amt=0; + + void *func_e=NULL; + NSEEL_PPPROC preProc=0; + void **repl=NULL; + + int n_params= 1 + op->opcodeType - OPCODETYPE_FUNC1; + + const int parm0_dv = op->parms.parms[0]->opcodeType == OPCODETYPE_DIRECTVALUE; + const int parm1_dv = n_params > 1 && op->parms.parms[1]->opcodeType == OPCODETYPE_DIRECTVALUE; + + void *func = nseel_getBuiltinFunctionAddress(ctx, op->fntype, op->fn, &preProc,&repl,&func_e,&cfunc_abiinfo,preferredReturnValues, + parm0_dv ? &op->parms.parms[0]->parms.dv.directValue : NULL, + parm1_dv ? &op->parms.parms[1]->parms.dv.directValue : NULL + ); + + if (!func) RET_MINUS1_FAIL("error getting funcaddr") + + *fpStackUsage=BIF_GETFPSTACKUSE(cfunc_abiinfo); + *rvMode = RETURNVALUE_NORMAL; + + if (cfunc_abiinfo & BIF_TAKES_VARPARM) + { +#if defined(__arm__) || (defined (_M_ARM) && _M_ARM == 7) + const int max_params=16384; // arm uses up to two instructions, should be good for at leaast 64k (16384*4) +#elif defined(__ppc__) + const int max_params=4096; // 32kb max offset addressing for stack, so 4096*4 = 16384, should be safe +#elif defined(__aarch64__) + const int max_params=32768; +#else + const int max_params=32768; // sanity check, the stack is free to grow on x86/x86-64 +#endif + int x; + // this mode is less efficient in that it creates a list of pointers on the stack to pass to the function + // but it is more flexible and works for >3 parameters. + if (op->opcodeType == OPCODETYPE_FUNCX) + { + n_params=0; + for (x=0;x<3;x++) + { + opcodeRec *prni=op->parms.parms[x]; + while (prni) + { + const int isMP = prni->opcodeType == OPCODETYPE_MOREPARAMS; + n_params++; + if (!isMP||n_params>=max_params) break; + prni = prni->parms.parms[1]; + } + } + } + + restore_stack_amt = (sizeof(void *) * n_params + 15)&~15; + + if (restore_stack_amt) + { + int offs = restore_stack_amt; + while (offs > 0) + { + int amt = offs; + if (amt > 4096) amt=4096; + + if (bufOut_len < parm_size+GLUE_MOVE_STACK_SIZE) RET_MINUS1_FAIL("insufficient size for varparm") + if (bufOut) GLUE_MOVE_STACK(bufOut+parm_size, - amt); + parm_size += GLUE_MOVE_STACK_SIZE; + offs -= amt; + + if (offs>0) // make sure this page is in memory + { + if (bufOut_len < parm_size+GLUE_STORE_P1_TO_STACK_AT_OFFS_SIZE(0)) + RET_MINUS1_FAIL("insufficient size for varparm stackchk") + if (bufOut) GLUE_STORE_P1_TO_STACK_AT_OFFS(bufOut+parm_size,0); + parm_size += GLUE_STORE_P1_TO_STACK_AT_OFFS_SIZE(0); + } + } + } + + if (op->opcodeType == OPCODETYPE_FUNCX) + { + n_params=0; + for (x=0;x<3;x++) + { + opcodeRec *prni=op->parms.parms[x]; + while (prni) + { + const int isMP = prni->opcodeType == OPCODETYPE_MOREPARAMS; + opcodeRec *r = isMP ? prni->parms.parms[0] : prni; + if (r) + { + int canHaveDenorm=0; + int rvt=RETURNVALUE_NORMAL; + int subfpstackuse=0, use_offs; + + int lsz = compileOpcodes(ctx,r,bufOut ? bufOut + parm_size : NULL,bufOut_len - parm_size, computTableSize, namespacePathToThis, rvt,&rvt, &subfpstackuse, &canHaveDenorm); + if (canHaveDenorm && canHaveDenormalOutput) *canHaveDenormalOutput = 1; + + if (lsz<0) RET_MINUS1_FAIL("call coc for varparmX failed") + if (rvt != RETURNVALUE_NORMAL) RET_MINUS1_FAIL("call coc for varparmX gave bad type back"); + + parm_size += lsz; + use_offs = n_params*(int) sizeof(void *); + + if (bufOut_len < parm_size+GLUE_STORE_P1_TO_STACK_AT_OFFS_SIZE(use_offs)) + RET_MINUS1_FAIL("call coc for varparmX size"); + if (bufOut) GLUE_STORE_P1_TO_STACK_AT_OFFS(bufOut + parm_size, use_offs); + parm_size+=GLUE_STORE_P1_TO_STACK_AT_OFFS_SIZE(use_offs); + + if (subfpstackuse+local_fpstack_use > *fpStackUsage) *fpStackUsage = subfpstackuse+local_fpstack_use; + } + else RET_MINUS1_FAIL("zero parameter varparmX") + + n_params++; + + if (!isMP||n_params>=max_params) break; + prni = prni->parms.parms[1]; + } + } + } + else for (x=0;x<n_params;x++) + { + opcodeRec *r = op->parms.parms[x]; + if (r) + { + int canHaveDenorm=0; + int subfpstackuse=0; + int rvt=RETURNVALUE_NORMAL; + int use_offs; + + int lsz = compileOpcodes(ctx,r,bufOut ? bufOut + parm_size : NULL,bufOut_len - parm_size, computTableSize, namespacePathToThis, rvt,&rvt, &subfpstackuse, &canHaveDenorm); + if (canHaveDenorm && canHaveDenormalOutput) *canHaveDenormalOutput = 1; + + if (lsz<0) RET_MINUS1_FAIL("call coc for varparm123 failed") + if (rvt != RETURNVALUE_NORMAL) RET_MINUS1_FAIL("call coc for varparm123 gave bad type back"); + + parm_size += lsz; + + use_offs = x*(int)sizeof(void *); + if (bufOut_len < parm_size+GLUE_STORE_P1_TO_STACK_AT_OFFS_SIZE(use_offs)) + RET_MINUS1_FAIL("call coc for varparm123 size"); + if (bufOut) GLUE_STORE_P1_TO_STACK_AT_OFFS(bufOut + parm_size, use_offs); + parm_size+=GLUE_STORE_P1_TO_STACK_AT_OFFS_SIZE(use_offs); + + if (subfpstackuse+local_fpstack_use > *fpStackUsage) *fpStackUsage = subfpstackuse+local_fpstack_use; + } + else RET_MINUS1_FAIL("zero parameter for varparm123"); + } + + if (bufOut_len < parm_size+GLUE_MOV_PX_DIRECTVALUE_SIZE+GLUE_MOVE_PX_STACKPTR_SIZE) RET_MINUS1_FAIL("insufficient size for varparm p1") + if (bufOut) GLUE_MOV_PX_DIRECTVALUE_GEN(bufOut+parm_size, (INT_PTR)n_params,1); + parm_size+=GLUE_MOV_PX_DIRECTVALUE_SIZE; + if (bufOut) GLUE_MOVE_PX_STACKPTR_GEN(bufOut+parm_size, 0); + parm_size+=GLUE_MOVE_PX_STACKPTR_SIZE; + + } + else // not varparm + { + int pn; + #ifdef GLUE_HAS_FXCH + int need_fxch=0; + #endif + int last_nt_parm=-1, last_nt_parm_type=-1; + + if (op->opcodeType == OPCODETYPE_FUNCX) + { + // this is not yet supported (calling conventions will need to be sorted, among other things) + RET_MINUS1_FAIL("funcx for native functions requires BIF_TAKES_VARPARM or BIF_TAKES_VARPARM_EX") + } + + if (parm0_dv) + { + if (func == nseel_asm_stack_pop) + { + func = GLUE_realAddress(nseel_asm_stack_pop_fast,nseel_asm_stack_pop_fast_end,&func_size); + if (!func || bufOut_len < func_size) RET_MINUS1_FAIL(func?"failed on popfast size":"failed on popfast addr") + + if (bufOut) + { + memcpy(bufOut,func,func_size); + NSEEL_PProc_Stack(bufOut,func_size,ctx); + } + return func_size; + } + else if (func == nseel_asm_stack_peek) + { + int f = (int) op->parms.parms[0]->parms.dv.directValue; + if (!f) + { + func = GLUE_realAddress(nseel_asm_stack_peek_top,nseel_asm_stack_peek_top_end,&func_size); + if (!func || bufOut_len < func_size) RET_MINUS1_FAIL(func?"failed on peek size":"failed on peek addr") + + if (bufOut) + { + memcpy(bufOut,func,func_size); + NSEEL_PProc_Stack_PeekTop(bufOut,func_size,ctx); + } + return func_size; + } + else + { + func = GLUE_realAddress(nseel_asm_stack_peek_int,nseel_asm_stack_peek_int_end,&func_size); + if (!func || bufOut_len < func_size) RET_MINUS1_FAIL(func?"failed on peekint size":"failed on peekint addr") + + if (bufOut) + { + memcpy(bufOut,func,func_size); + NSEEL_PProc_Stack_PeekInt(bufOut,func_size,ctx,f*sizeof(EEL_F)); + } + return func_size; + } + } + } + // end of built-in function specific special casing + + + // first pass, calculate any non-trivial parameters + for (pn=0; pn < n_params; pn++) + { + if (!OPCODE_IS_TRIVIAL(op->parms.parms[pn])) + { + int canHaveDenorm=0; + int subfpstackuse=0; + int lsz=0; + int rvt=RETURNVALUE_NORMAL; + int may_need_fppush=-1; + if (last_nt_parm>=0) + { + if (last_nt_parm_type==RETURNVALUE_FPSTACK) + { + may_need_fppush= parm_size; + } + else + { + // push last result + if (bufOut_len < parm_size + (int)sizeof(GLUE_PUSH_P1)) RET_MINUS1_FAIL("failed on size, pushp1") + if (bufOut) memcpy(bufOut + parm_size, &GLUE_PUSH_P1, sizeof(GLUE_PUSH_P1)); + parm_size += sizeof(GLUE_PUSH_P1); + } + } + + if (func == nseel_asm_bnot) rvt=RETURNVALUE_BOOL_REVERSED|RETURNVALUE_BOOL; + else if (pn == n_params - 1) + { + if (cfunc_abiinfo&BIF_LASTPARMONSTACK) rvt=RETURNVALUE_FPSTACK; + else if (cfunc_abiinfo&BIF_LASTPARM_ASBOOL) rvt=RETURNVALUE_BOOL; + else if (func == nseel_asm_assign) rvt=RETURNVALUE_FPSTACK|RETURNVALUE_NORMAL; + } + else if (pn == n_params -2 && (cfunc_abiinfo&BIF_SECONDLASTPARMST)) + { + rvt=RETURNVALUE_FPSTACK; + } + + lsz = compileOpcodes(ctx,op->parms.parms[pn],bufOut ? bufOut + parm_size : NULL,bufOut_len - parm_size, computTableSize, namespacePathToThis, rvt,&rvt, &subfpstackuse, &canHaveDenorm); + + if (lsz<0) RET_MINUS1_FAIL("call coc failed") + + if (func == nseel_asm_bnot && rvt==RETURNVALUE_BOOL_REVERSED) + { + // remove bnot, compileOpcodes() used fptobool_rev +#ifndef EEL_TARGET_PORTABLE + func = nseel_asm_uplus; + func_e = nseel_asm_uplus_end; +#else + func = nseel_asm_bnotnot; + func_e = nseel_asm_bnotnot_end; +#endif + rvt = RETURNVALUE_BOOL; + } + + if (canHaveDenorm && canHaveDenormalOutput) *canHaveDenormalOutput = 1; + + parm_size += lsz; + + if (may_need_fppush>=0) + { + if (local_fpstack_use+subfpstackuse >= (GLUE_MAX_FPSTACK_SIZE-1) || (ctx->optimizeDisableFlags&OPTFLAG_NO_FPSTACK)) + { + if (bufOut_len < parm_size + (int)sizeof(GLUE_POP_FPSTACK_TOSTACK)) + RET_MINUS1_FAIL("failed on size, popfpstacktostack") + + if (bufOut) + { + memmove(bufOut + may_need_fppush + sizeof(GLUE_POP_FPSTACK_TOSTACK), bufOut + may_need_fppush, parm_size - may_need_fppush); + memcpy(bufOut + may_need_fppush, &GLUE_POP_FPSTACK_TOSTACK, sizeof(GLUE_POP_FPSTACK_TOSTACK)); + + } + parm_size += sizeof(GLUE_POP_FPSTACK_TOSTACK); + } + else + { + local_fpstack_use++; + } + } + + if (subfpstackuse+local_fpstack_use > *fpStackUsage) *fpStackUsage = subfpstackuse+local_fpstack_use; + + last_nt_parm = pn; + last_nt_parm_type = rvt; + + if (pn == n_params - 1 && func == nseel_asm_assign) + { + if (!(ctx->optimizeDisableFlags & OPTFLAG_FULL_DENORMAL_CHECKS) && + (!canHaveDenorm || (ctx->optimizeDisableFlags & OPTFLAG_NO_DENORMAL_CHECKS))) + { + if (rvt == RETURNVALUE_FPSTACK) + { + cfunc_abiinfo |= BIF_LASTPARMONSTACK; + func = nseel_asm_assign_fast_fromfp; + func_e = nseel_asm_assign_fast_fromfp_end; + } + else + { + func = nseel_asm_assign_fast; + func_e = nseel_asm_assign_fast_end; + } + } + else + { + if (rvt == RETURNVALUE_FPSTACK) + { + cfunc_abiinfo |= BIF_LASTPARMONSTACK; + func = nseel_asm_assign_fromfp; + func_e = nseel_asm_assign_fromfp_end; + } + } + + } + } + } + + pn = last_nt_parm; + + if (pn >= 0) // if the last thing executed doesn't go to the last parameter, move it there + { + if ((cfunc_abiinfo&BIF_SECONDLASTPARMST) && pn == n_params-2) + { + // do nothing, things are in the right place + } + else if (pn != n_params-1) + { + // generate mov p1->pX + if (bufOut_len < parm_size + GLUE_SET_PX_FROM_P1_SIZE) RET_MINUS1_FAIL("size, pxfromp1") + if (bufOut) GLUE_SET_PX_FROM_P1(bufOut + parm_size,n_params - 1 - pn); + parm_size += GLUE_SET_PX_FROM_P1_SIZE; + } + } + + // pop any pushed parameters + while (--pn >= 0) + { + if (!OPCODE_IS_TRIVIAL(op->parms.parms[pn])) + { + if ((cfunc_abiinfo&BIF_SECONDLASTPARMST) && pn == n_params-2) + { + if (!local_fpstack_use) + { + if (bufOut_len < parm_size + (int)sizeof(GLUE_POP_STACK_TO_FPSTACK)) RET_MINUS1_FAIL("size, popstacktofpstack 2") + if (bufOut) memcpy(bufOut+parm_size,GLUE_POP_STACK_TO_FPSTACK,sizeof(GLUE_POP_STACK_TO_FPSTACK)); + parm_size += sizeof(GLUE_POP_STACK_TO_FPSTACK); + #ifdef GLUE_HAS_FXCH + need_fxch = 1; + #endif + } + else + { + local_fpstack_use--; + } + } + else + { + if (bufOut_len < parm_size + GLUE_POP_PX_SIZE) RET_MINUS1_FAIL("size, poppx") + if (bufOut) GLUE_POP_PX(bufOut + parm_size,n_params - 1 - pn); + parm_size += GLUE_POP_PX_SIZE; + } + } + } + + // finally, set trivial pointers + for (pn=0; pn < n_params; pn++) + { + if (OPCODE_IS_TRIVIAL(op->parms.parms[pn])) + { + if (pn == n_params-2 && (cfunc_abiinfo&(BIF_SECONDLASTPARMST))) // second to last parameter + { + int a = compileOpcodes(ctx,op->parms.parms[pn],bufOut ? bufOut+parm_size : NULL,bufOut_len - parm_size,computTableSize,namespacePathToThis, + RETURNVALUE_FPSTACK,NULL,NULL,canHaveDenormalOutput); + if (a<0) RET_MINUS1_FAIL("coc call here 2") + parm_size+=a; + #ifdef GLUE_HAS_FXCH + need_fxch = 1; + #endif + } + else if (pn == n_params-1) // last parameter, but we should call compileOpcodes to get it in the right format (compileOpcodes can optimize that process if it needs to) + { + int rvt=0, a; + int wantFpStack = func == nseel_asm_assign; + #ifdef GLUE_PREFER_NONFP_DV_ASSIGNS // x86-64, and maybe others, prefer to avoid the fp stack for a simple copy + if (wantFpStack && + (op->parms.parms[pn]->opcodeType != OPCODETYPE_DIRECTVALUE || + (op->parms.parms[pn]->parms.dv.directValue != 1.0 && op->parms.parms[pn]->parms.dv.directValue != 0.0))) + { + wantFpStack=-1; // cacheable but non-FP stack + } + #endif + a = compileOpcodes(ctx,op->parms.parms[pn],bufOut ? bufOut+parm_size : NULL,bufOut_len - parm_size,computTableSize,namespacePathToThis, + func == nseel_asm_bnot ? (RETURNVALUE_BOOL_REVERSED|RETURNVALUE_BOOL) : + (cfunc_abiinfo & BIF_LASTPARMONSTACK) ? RETURNVALUE_FPSTACK : + (cfunc_abiinfo & BIF_LASTPARM_ASBOOL) ? RETURNVALUE_BOOL : + wantFpStack < 0 ? (RETURNVALUE_CACHEABLE|RETURNVALUE_NORMAL) : + wantFpStack ? (RETURNVALUE_FPSTACK|RETURNVALUE_NORMAL) : + RETURNVALUE_NORMAL, + &rvt, NULL,canHaveDenormalOutput); + + if (a<0) RET_MINUS1_FAIL("coc call here 3") + + if (func == nseel_asm_bnot && rvt == RETURNVALUE_BOOL_REVERSED) + { + // remove bnot, compileOpcodes() used fptobool_rev +#ifndef EEL_TARGET_PORTABLE + func = nseel_asm_uplus; + func_e = nseel_asm_uplus_end; +#else + func = nseel_asm_bnotnot; + func_e = nseel_asm_bnotnot_end; +#endif + rvt = RETURNVALUE_BOOL; + } + + parm_size+=a; + #ifdef GLUE_HAS_FXCH + need_fxch = 0; + #endif + + if (func == nseel_asm_assign) + { + if (rvt == RETURNVALUE_FPSTACK) + { + if (!(ctx->optimizeDisableFlags & OPTFLAG_FULL_DENORMAL_CHECKS)) + { + func = nseel_asm_assign_fast_fromfp; + func_e = nseel_asm_assign_fast_fromfp_end; + } + else + { + func = nseel_asm_assign_fromfp; + func_e = nseel_asm_assign_fromfp_end; + } + } + else if (!(ctx->optimizeDisableFlags & OPTFLAG_FULL_DENORMAL_CHECKS)) + { + // assigning a value (from a variable or other non-computer), can use a fast assign (no denormal/result checking) + func = nseel_asm_assign_fast; + func_e = nseel_asm_assign_fast_end; + } + } + } + else + { + if (bufOut_len < parm_size + GLUE_MOV_PX_DIRECTVALUE_SIZE) RET_MINUS1_FAIL("size, pxdvsz") + if (bufOut) + { + if (generateValueToReg(ctx,op->parms.parms[pn],bufOut + parm_size,n_params - 1 - pn,namespacePathToThis, 0/*nocaching, function gets pointer*/)<0) RET_MINUS1_FAIL("gvtr") + } + parm_size += GLUE_MOV_PX_DIRECTVALUE_SIZE; + } + } + } + + #ifdef GLUE_HAS_FXCH + if ((cfunc_abiinfo&(BIF_SECONDLASTPARMST)) && !(cfunc_abiinfo&(BIF_LAZYPARMORDERING))&& + ((!!need_fxch)^!!(cfunc_abiinfo&BIF_REVERSEFPORDER)) + ) + { + // emit fxch + if (bufOut_len < sizeof(GLUE_FXCH)) RET_MINUS1_FAIL("len,fxch") + if (bufOut) + { + memcpy(bufOut+parm_size,GLUE_FXCH,sizeof(GLUE_FXCH)); + } + parm_size+=sizeof(GLUE_FXCH); + } + #endif + + if (!*canHaveDenormalOutput) + { + // if add_op or sub_op, and constant non-denormal input, safe to omit denormal checks + if (func == (void*)nseel_asm_add_op && parm1_dv && fabs(op->parms.parms[1]->parms.dv.directValue) >= DENORMAL_CLEARING_THRESHOLD) + { + func = nseel_asm_add_op_fast; + func_e = nseel_asm_add_op_fast_end; + } + else if (func == (void*)nseel_asm_sub_op && parm1_dv && fabs(op->parms.parms[1]->parms.dv.directValue) >= DENORMAL_CLEARING_THRESHOLD) + { + func = nseel_asm_sub_op_fast; + func_e = nseel_asm_sub_op_fast_end; + } + // or if mul/div by a fixed value of >= or <= 1.0 + else if (func == (void *)nseel_asm_mul_op && parm1_dv && fabs(op->parms.parms[1]->parms.dv.directValue) >= 1.0) + { + func = nseel_asm_mul_op_fast; + func_e = nseel_asm_mul_op_fast_end; + } + else if (func == (void *)nseel_asm_div_op && parm1_dv && fabs(op->parms.parms[1]->parms.dv.directValue) <= 1.0) + { + func = nseel_asm_div_op_fast; + func_e = nseel_asm_div_op_fast_end; + } + } + } // not varparm + + if (cfunc_abiinfo & (BIF_CLEARDENORMAL | BIF_RETURNSBOOL) ) *canHaveDenormalOutput=0; + else if (!(cfunc_abiinfo & BIF_WONTMAKEDENORMAL)) *canHaveDenormalOutput=1; + + func = GLUE_realAddress(func,func_e,&func_size); + if (!func) RET_MINUS1_FAIL("failrealladdrfunc") + + if (bufOut_len < parm_size + func_size) RET_MINUS1_FAIL("funcsz") + + if (bufOut) + { + unsigned char *p=bufOut + parm_size; + memcpy(p, func, func_size); + if (preProc) p=preProc(p,func_size,ctx); + if (repl) + { + if (repl[0]) p=EEL_GLUE_set_immediate(p,(INT_PTR)repl[0]); + if (repl[1]) p=EEL_GLUE_set_immediate(p,(INT_PTR)repl[1]); + if (repl[2]) p=EEL_GLUE_set_immediate(p,(INT_PTR)repl[2]); + if (repl[3]) p=EEL_GLUE_set_immediate(p,(INT_PTR)repl[3]); + } + } + + if (restore_stack_amt) + { + int rem = restore_stack_amt; + while (rem > 0) + { + int amt = rem; + if (amt > 4096) amt=4096; + rem -= amt; + + if (bufOut_len < parm_size + func_size + GLUE_MOVE_STACK_SIZE) RET_MINUS1_FAIL("insufficient size for varparm") + if (bufOut) GLUE_MOVE_STACK(bufOut + parm_size + func_size, amt); + parm_size += GLUE_MOVE_STACK_SIZE; + } + } + + if (cfunc_abiinfo&BIF_RETURNSONSTACK) *rvMode = RETURNVALUE_FPSTACK; + else if (cfunc_abiinfo&BIF_RETURNSBOOL) *rvMode=RETURNVALUE_BOOL; + + return parm_size + func_size; +} + +static int compileEelFunctionCall(compileContext *ctx, opcodeRec *op, unsigned char *bufOut, int bufOut_len, int *computTableSize, const namespaceInformation *namespacePathToThis, + int *rvMode, int *fpStackUse, int *canHaveDenormalOutput) +{ + int func_size=0, parm_size=0; + int pn; + int last_nt_parm=-1,last_nt_parm_mode=0; + void *func_e=NULL; + int n_params; + opcodeRec *parmptrs[NSEEL_MAX_EELFUNC_PARAMETERS]; + int cfp_numparams=-1; + int cfp_statesize=0; + EEL_F **cfp_ptrs=NULL; + int func_raw=0; + int do_parms; + int x; + + void *func; + + for (x=0; x < 3; x ++) parmptrs[x] = op->parms.parms[x]; + + if (op->opcodeType == OPCODETYPE_FUNCX) + { + n_params=0; + for (x=0;x<3;x++) + { + opcodeRec *prni=op->parms.parms[x]; + while (prni && n_params < NSEEL_MAX_EELFUNC_PARAMETERS) + { + const int isMP = prni->opcodeType == OPCODETYPE_MOREPARAMS; + parmptrs[n_params++] = isMP ? prni->parms.parms[0] : prni; + if (!isMP) break; + prni = prni->parms.parms[1]; + } + } + } + else + { + n_params = 1 + op->opcodeType - OPCODETYPE_FUNC1; + } + + *fpStackUse = 0; + func = nseel_getEELFunctionAddress(ctx, op, + &cfp_numparams,&cfp_statesize,&cfp_ptrs, + computTableSize, + &func_e, &func_raw, + !!bufOut,namespacePathToThis,rvMode,fpStackUse,canHaveDenormalOutput, parmptrs, n_params); + + if (func_raw) func_size = (int) ((char*)func_e - (char*)func); + else if (func) func = GLUE_realAddress(func,func_e,&func_size); + + if (!func) RET_MINUS1_FAIL("eelfuncaddr") + + *fpStackUse += 1; + + + if (cfp_numparams>0 && n_params != cfp_numparams) + { + RET_MINUS1_FAIL("eelfuncnp") + } + + // user defined function + do_parms = cfp_numparams>0 && cfp_ptrs && cfp_statesize>0; + + // if function local/parameter state is zero, we need to allocate storage for it + if (cfp_statesize>0 && cfp_ptrs && !cfp_ptrs[0]) + { + EEL_F *pstate = newDataBlock(sizeof(EEL_F)*cfp_statesize,8); + if (!pstate) RET_MINUS1_FAIL("eelfuncdb") + + for (pn=0;pn<cfp_statesize;pn++) + { + pstate[pn]=0; + cfp_ptrs[pn] = pstate + pn; + } + } + + + // first process parameters that are non-trivial + for (pn=0; pn < n_params; pn++) + { + int needDenorm=0; + int lsz,sUse=0; + + if (!parmptrs[pn] || OPCODE_IS_TRIVIAL(parmptrs[pn])) continue; // skip and process after + + if (last_nt_parm >= 0 && do_parms) + { + if (last_nt_parm_mode == RETURNVALUE_FPSTACK) + { + if (bufOut_len < parm_size + (int)sizeof(GLUE_POP_FPSTACK_TOSTACK)) RET_MINUS1_FAIL("eelfunc_size popfpstacktostack") + if (bufOut) memcpy(bufOut + parm_size,GLUE_POP_FPSTACK_TOSTACK,sizeof(GLUE_POP_FPSTACK_TOSTACK)); + parm_size+=sizeof(GLUE_POP_FPSTACK_TOSTACK); + } + else + { + if (bufOut_len < parm_size + (int)sizeof(GLUE_PUSH_P1PTR_AS_VALUE)) RET_MINUS1_FAIL("eelfunc_size pushp1ptrasval") + + // push + if (bufOut) memcpy(bufOut + parm_size,&GLUE_PUSH_P1PTR_AS_VALUE,sizeof(GLUE_PUSH_P1PTR_AS_VALUE)); + parm_size+=sizeof(GLUE_PUSH_P1PTR_AS_VALUE); + } + } + + last_nt_parm_mode=0; + lsz = compileOpcodes(ctx,parmptrs[pn],bufOut ? bufOut + parm_size : NULL,bufOut_len - parm_size, computTableSize, namespacePathToThis, + do_parms ? (RETURNVALUE_FPSTACK|RETURNVALUE_NORMAL) : RETURNVALUE_IGNORE,&last_nt_parm_mode,&sUse, &needDenorm); + + // todo: if needDenorm, denorm convert when copying parameter + + if (lsz<0) RET_MINUS1_FAIL("eelfunc, coc fail") + + if (last_nt_parm_mode == RETURNVALUE_FPSTACK) sUse++; + if (sUse > *fpStackUse) *fpStackUse=sUse; + parm_size += lsz; + + last_nt_parm = pn; + } + // pop non-trivial results into place + if (last_nt_parm >=0 && do_parms) + { + while (--pn >= 0) + { + if (!parmptrs[pn] || OPCODE_IS_TRIVIAL(parmptrs[pn])) continue; // skip and process after + if (pn == last_nt_parm) + { + if (last_nt_parm_mode == RETURNVALUE_FPSTACK) + { + // pop to memory directly + const int cpsize = GLUE_POP_FPSTACK_TO_PTR(NULL,NULL); + if (bufOut_len < parm_size + cpsize) RET_MINUS1_FAIL("eelfunc size popfpstacktoptr") + + if (bufOut) GLUE_POP_FPSTACK_TO_PTR((unsigned char *)bufOut + parm_size,cfp_ptrs[pn]); + parm_size += cpsize; + } + else + { + // copy direct p1ptr to mem + const int cpsize = GLUE_COPY_VALUE_AT_P1_TO_PTR(NULL,NULL); + if (bufOut_len < parm_size + cpsize) RET_MINUS1_FAIL("eelfunc size copyvalueatp1toptr") + + if (bufOut) GLUE_COPY_VALUE_AT_P1_TO_PTR((unsigned char *)bufOut + parm_size,cfp_ptrs[pn]); + parm_size += cpsize; + } + } + else + { + const int popsize = GLUE_POP_VALUE_TO_ADDR(NULL,NULL); + if (bufOut_len < parm_size + popsize) RET_MINUS1_FAIL("eelfunc size pop value to addr") + + if (bufOut) GLUE_POP_VALUE_TO_ADDR((unsigned char *)bufOut + parm_size,cfp_ptrs[pn]); + parm_size+=popsize; + + } + } + } + + // finally, set any trivial parameters + if (do_parms) + { + const int cpsize = GLUE_MOV_PX_DIRECTVALUE_SIZE + GLUE_COPY_VALUE_AT_P1_TO_PTR(NULL,NULL); + for (pn=0; pn < n_params; pn++) + { + if (!parmptrs[pn] || !OPCODE_IS_TRIVIAL(parmptrs[pn])) continue; // set trivial values, we already set nontrivials + + if (bufOut_len < parm_size + cpsize) RET_MINUS1_FAIL("eelfunc size trivial set") + + if (bufOut) + { + if (generateValueToReg(ctx,parmptrs[pn],bufOut + parm_size,0,namespacePathToThis, 1)<0) RET_MINUS1_FAIL("eelfunc gvr fail") + GLUE_COPY_VALUE_AT_P1_TO_PTR(bufOut + parm_size + GLUE_MOV_PX_DIRECTVALUE_SIZE,cfp_ptrs[pn]); + } + parm_size += cpsize; + + } + } + + if (bufOut_len < parm_size + func_size) RET_MINUS1_FAIL("eelfunc size combined") + + if (bufOut) memcpy(bufOut + parm_size, func, func_size); + + return parm_size + func_size; + // end of EEL function generation +} + +#ifdef DUMP_OPS_DURING_COMPILE +void dumpOp(compileContext *ctx, opcodeRec *op, int start); +#endif + +#ifdef EEL_DUMP_OPS +void dumpOpcodeTree(compileContext *ctx, FILE *fp, opcodeRec *op, int indent_amt) +{ + const char *fname=""; + fprintf(fp,"%*sOP TYPE %d", indent_amt, "", + op->opcodeType==OPCODETYPE_DIRECTVALUE_TEMPSTRING ? 10000 : // remap around OPCODETYPE_DIRECTVALUE_TEMPSTRING + op->opcodeType > OPCODETYPE_DIRECTVALUE_TEMPSTRING ? op->opcodeType - 1 : + op->opcodeType); + + if ((op->opcodeType == OPCODETYPE_FUNC1 || + op->opcodeType == OPCODETYPE_FUNC2 || + op->opcodeType == OPCODETYPE_FUNC3 || + op->opcodeType == OPCODETYPE_FUNCX)) + { + if (op->fntype == FUNCTYPE_FUNCTIONTYPEREC) + { + functionType *fn_ptr = (functionType *)op->fn; + fname = fn_ptr->name; + } + else if (op->fntype == FUNCTYPE_EELFUNC) + { + fname = op->relname; + } + if (!fname) fname =""; + } + + switch (op->opcodeType) + { + case OPCODETYPE_DIRECTVALUE: + fprintf(fp," DV=%f\r\n",op->parms.dv.directValue); + break; + case OPCODETYPE_VALUE_FROM_NAMESPACENAME: // this.* or namespace.* are encoded this way + fprintf(fp," NSN=%s(%d)\r\n",op->relname?op->relname : "(null)",op->namespaceidx); + break; + case OPCODETYPE_VARPTR: + { + const char *nm = op->relname; + if (!nm || !*nm) + { + int wb; + for (wb = 0; wb < ctx->varTable_numBlocks; wb ++) + { + char **plist=ctx->varTable_Names[wb]; + if (!plist) break; + + if (op->parms.dv.valuePtr >= ctx->varTable_Values[wb] && op->parms.dv.valuePtr < ctx->varTable_Values[wb] + NSEEL_VARS_PER_BLOCK) + { + nm = plist[op->parms.dv.valuePtr - ctx->varTable_Values[wb]]; + break; + } + } + } + fprintf(fp," VP=%s\r\n", nm?nm : "(null)"); + } + break; + case OPCODETYPE_VARPTRPTR: + fprintf(fp, " VPP?\r\n"); + break; + case OPCODETYPE_FUNC1: + if (op->fntype == FN_NOT) + fprintf(fp," FUNC1 %d %s {\r\n",FUNCTYPE_FUNCTIONTYPEREC, "_not"); + else if (op->fntype == FN_NOTNOT) + fprintf(fp," FUNC1 %d %s {\r\n",FUNCTYPE_FUNCTIONTYPEREC, "_notnot"); + else if (op->fntype == FN_MEMORY) + fprintf(fp," FUNC1 %d %s {\r\n",FUNCTYPE_FUNCTIONTYPEREC, "_mem"); + else if (op->fntype == FN_GMEMORY) + fprintf(fp," FUNC1 %d %s {\r\n",FUNCTYPE_FUNCTIONTYPEREC, "_gmem"); + else if (op->fntype == FN_WHILE) + fprintf(fp," FUNC1 %d %s {\r\n",FUNCTYPE_FUNCTIONTYPEREC, "while"); + else + fprintf(fp," FUNC1 %d %s {\r\n",op->fntype, fname); + + if (op->parms.parms[0]) + dumpOpcodeTree(ctx,fp,op->parms.parms[0],indent_amt+2); + else + fprintf(fp,"%*sINVALID PARM\r\n",indent_amt+2,""); + fprintf(fp,"%*s}\r\n", indent_amt, ""); + break; + case OPCODETYPE_MOREPARAMS: + case OPCODETYPE_FUNC2: + if (op->opcodeType == OPCODETYPE_MOREPARAMS) + fprintf(fp," MOREPARAMS {\r\n"); + else + { + if (op->fntype == FN_POW) + fprintf(fp," FUNC2 %d %s {\r\n",FUNCTYPE_FUNCTIONTYPEREC, "pow"); + else if (op->fntype == FN_MOD) + fprintf(fp," FUNC2 %d %s {\r\n",FUNCTYPE_FUNCTIONTYPEREC, "_mod"); + else if (op->fntype == FN_XOR) + fprintf(fp," FUNC2 %d %s {\r\n",FUNCTYPE_FUNCTIONTYPEREC, "_xor"); + else if (op->fntype == FN_SHL) + fprintf(fp," FUNC2 %d %s {\r\n",FUNCTYPE_FUNCTIONTYPEREC, "_shl"); + else if (op->fntype == FN_SHR) + fprintf(fp," FUNC2 %d %s {\r\n",FUNCTYPE_FUNCTIONTYPEREC, "_shr"); + else if (op->fntype == FN_LT) + fprintf(fp," FUNC2 %d %s {\r\n",FUNCTYPE_FUNCTIONTYPEREC, "_below"); + else if (op->fntype == FN_GT) + fprintf(fp," FUNC2 %d %s {\r\n",FUNCTYPE_FUNCTIONTYPEREC, "_above"); + else if (op->fntype == FN_LTE) + fprintf(fp," FUNC2 %d %s {\r\n",FUNCTYPE_FUNCTIONTYPEREC, "_beleq"); + else if (op->fntype == FN_GTE) + fprintf(fp," FUNC2 %d %s {\r\n",FUNCTYPE_FUNCTIONTYPEREC, "_aboeq"); + else if (op->fntype == FN_EQ) + fprintf(fp," FUNC2 %d %s {\r\n",FUNCTYPE_FUNCTIONTYPEREC, "_equal"); + else if (op->fntype == FN_NE) + fprintf(fp," FUNC2 %d %s {\r\n",FUNCTYPE_FUNCTIONTYPEREC, "_noteq"); + else if (op->fntype == FN_EQ_EXACT) + fprintf(fp," FUNC2 %d %s {\r\n",FUNCTYPE_FUNCTIONTYPEREC, "_equal_exact"); + else if (op->fntype == FN_NE_EXACT) + fprintf(fp," FUNC2 %d %s {\r\n",FUNCTYPE_FUNCTIONTYPEREC, "_noteq_exact"); + else if (op->fntype == FN_LOGICAL_AND) + fprintf(fp," FUNC2 %d %s {\r\n",FUNCTYPE_FUNCTIONTYPEREC, "_and"); + else if (op->fntype == FN_LOGICAL_OR) + fprintf(fp," FUNC2 %d %s {\r\n",FUNCTYPE_FUNCTIONTYPEREC, "_or"); + else if (op->fntype == FN_ASSIGN) + fprintf(fp," FUNC2 %d %s {\r\n",FUNCTYPE_FUNCTIONTYPEREC, "_set"); + else if (op->fntype == FN_ADD_OP) + fprintf(fp," FUNC2 %d %s {\r\n",FUNCTYPE_FUNCTIONTYPEREC, "_addop"); + else if (op->fntype == FN_SUB_OP) + fprintf(fp," FUNC2 %d %s {\r\n",FUNCTYPE_FUNCTIONTYPEREC, "_subop"); + else if (op->fntype == FN_MUL_OP) + fprintf(fp," FUNC2 %d %s {\r\n",FUNCTYPE_FUNCTIONTYPEREC, "_mulop"); + else if (op->fntype == FN_DIV_OP) + fprintf(fp," FUNC2 %d %s {\r\n",FUNCTYPE_FUNCTIONTYPEREC, "_divop"); + else if (op->fntype == FN_OR_OP) + fprintf(fp," FUNC2 %d %s {\r\n",FUNCTYPE_FUNCTIONTYPEREC, "_orop"); + else if (op->fntype == FN_AND_OP) + fprintf(fp," FUNC2 %d %s {\r\n",FUNCTYPE_FUNCTIONTYPEREC, "_andop"); + else if (op->fntype == FN_XOR_OP) + fprintf(fp," FUNC2 %d %s {\r\n",FUNCTYPE_FUNCTIONTYPEREC, "_xorop"); + else if (op->fntype == FN_MOD_OP) + fprintf(fp," FUNC2 %d %s {\r\n",FUNCTYPE_FUNCTIONTYPEREC, "_modop"); + else if (op->fntype == FN_POW_OP) + fprintf(fp," FUNC2 %d %s {\r\n",FUNCTYPE_FUNCTIONTYPEREC, "_powop"); + else if (op->fntype == FN_LOOP) + fprintf(fp," FUNC2 %d %s {\r\n",FUNCTYPE_FUNCTIONTYPEREC, "loop"); + else + fprintf(fp," FUNC2 %d %s {\r\n",op->fntype, fname); + } + if (op->parms.parms[0]) + dumpOpcodeTree(ctx,fp,op->parms.parms[0],indent_amt+2); + else + fprintf(fp,"%*sINVALID PARM\r\n",indent_amt+2,""); + + if (op->parms.parms[1]) + dumpOpcodeTree(ctx,fp,op->parms.parms[1],indent_amt+2); + else + fprintf(fp,"%*sINVALID PARM\r\n",indent_amt+2,""); + fprintf(fp,"%*s}\r\n", indent_amt, ""); + break; + case OPCODETYPE_FUNCX: + case OPCODETYPE_FUNC3: + if (op->opcodeType == OPCODETYPE_FUNCX) + fprintf(fp," FUNCX %d %s {\r\n",op->fntype, fname); + else if (op->fntype == FN_IF_ELSE) + fprintf(fp," FUNC3 %d %s {\r\n",FUNCTYPE_FUNCTIONTYPEREC, "_if"); + else + fprintf(fp," FUNC3 %d %s {\r\n",op->fntype, fname); + if (op->parms.parms[0]) + dumpOpcodeTree(ctx,fp,op->parms.parms[0],indent_amt+2); + else + fprintf(fp,"%*sINVALID PARM\r\n",indent_amt+2,""); + + if (op->parms.parms[1]) + dumpOpcodeTree(ctx,fp,op->parms.parms[1],indent_amt+2); + else + fprintf(fp,"%*sINVALID PARM\r\n",indent_amt+2,""); + + if (op->parms.parms[2]) + dumpOpcodeTree(ctx,fp,op->parms.parms[2],indent_amt+2); + else + fprintf(fp,"%*sINVALID PARM\r\n",indent_amt+2,""); + fprintf(fp,"%*s}\r\n", indent_amt, ""); + + break; + } +} + +#endif + +#ifdef GLUE_MAX_JMPSIZE +#define CHECK_SIZE_FORJMP(x,y) if ((x)<0 || (x)>=GLUE_MAX_JMPSIZE) goto y; +#define RET_MINUS1_FAIL_FALLBACK(err,j) goto j; +#else +#define CHECK_SIZE_FORJMP(x,y) +#define RET_MINUS1_FAIL_FALLBACK(err,j) RET_MINUS1_FAIL(err) +#endif +static int compileOpcodesInternal(compileContext *ctx, opcodeRec *op, unsigned char *bufOut, int bufOut_len, int *computTableSize, const namespaceInformation *namespacePathToThis, int *calledRvType, int preferredReturnValues, int *fpStackUse, int *canHaveDenormalOutput) +{ + int rv_offset=0, denormal_force=-1; + if (!op) RET_MINUS1_FAIL("coi !op") + + *fpStackUse=0; + for (;;) + { + // special case: statement delimiting means we can process the left side into place, and iteratively do the second parameter without recursing + // also we don't need to save/restore anything to the stack (which the normal 2 parameter function processing does) + if (op->opcodeType == OPCODETYPE_FUNC2 && op->fntype == FN_JOIN_STATEMENTS) + { + int fUse1; + int parm_size = compileOpcodes(ctx,op->parms.parms[0],bufOut,bufOut_len, computTableSize, namespacePathToThis, RETURNVALUE_IGNORE, NULL,&fUse1,NULL); + if (parm_size < 0) RET_MINUS1_FAIL("coc join fail") + op = op->parms.parms[1]; + if (!op) RET_MINUS1_FAIL("join got to null") + + if (fUse1>*fpStackUse) *fpStackUse=fUse1; + if (bufOut) bufOut += parm_size; + bufOut_len -= parm_size; + rv_offset += parm_size; +#ifdef DUMP_OPS_DURING_COMPILE + if (op->opcodeType != OPCODETYPE_FUNC2 || op->fntype != FN_JOIN_STATEMENTS) dumpOp(ctx,op,0); +#endif + denormal_force=-1; + } + // special case: __denormal_likely(), __denormal_unlikely() + else if (op->opcodeType == OPCODETYPE_FUNC1 && (op->fntype == FN_DENORMAL_LIKELY || op->fntype == FN_DENORMAL_UNLIKELY)) + { + denormal_force = op->fntype == FN_DENORMAL_LIKELY; + op = op->parms.parms[0]; + } + else + { + break; + } + } + if (denormal_force >= 0 && canHaveDenormalOutput) + { + *canHaveDenormalOutput = denormal_force; + canHaveDenormalOutput = &denormal_force; // prevent it from being changed by functions below + } + + // special case: BAND/BOR + if (op->opcodeType == OPCODETYPE_FUNC2 && (op->fntype == FN_LOGICAL_AND || op->fntype == FN_LOGICAL_OR)) + { + int fUse1=0; + int parm_size; +#ifdef GLUE_MAX_JMPSIZE + int parm_size_pre; +#endif + int retType=RETURNVALUE_IGNORE; + if (preferredReturnValues != RETURNVALUE_IGNORE) retType = RETURNVALUE_BOOL; + + *calledRvType = retType; + + parm_size = compileOpcodes(ctx,op->parms.parms[0],bufOut,bufOut_len, computTableSize, namespacePathToThis, RETURNVALUE_BOOL, NULL, &fUse1, NULL); + if (parm_size < 0) RET_MINUS1_FAIL("loop band/bor coc fail") + + if (fUse1 > *fpStackUse) *fpStackUse=fUse1; + + +#ifdef GLUE_MAX_JMPSIZE + parm_size_pre=parm_size; +#endif + + { + int sz2, fUse2=0; + unsigned char *destbuf; + const int testsz=op->fntype == FN_LOGICAL_OR ? sizeof(GLUE_JMP_IF_P1_NZ) : sizeof(GLUE_JMP_IF_P1_Z); + if (bufOut_len < parm_size+testsz) RET_MINUS1_FAIL_FALLBACK("band/bor size fail",doNonInlinedAndOr_) + + if (bufOut) memcpy(bufOut+parm_size,op->fntype == FN_LOGICAL_OR ? GLUE_JMP_IF_P1_NZ : GLUE_JMP_IF_P1_Z,testsz); + parm_size += testsz; + destbuf = bufOut + parm_size; + + sz2= compileOpcodes(ctx,op->parms.parms[1],bufOut?bufOut+parm_size:NULL,bufOut_len-parm_size, computTableSize, namespacePathToThis, retType, NULL,&fUse2, NULL); + + CHECK_SIZE_FORJMP(sz2,doNonInlinedAndOr_) + if (sz2<0) RET_MINUS1_FAIL("band/bor coc fail") + + parm_size+=sz2; + if (bufOut) GLUE_JMP_SET_OFFSET(destbuf, (bufOut + parm_size) - destbuf); + + if (fUse2 > *fpStackUse) *fpStackUse=fUse2; + return rv_offset + parm_size; + } +#ifdef GLUE_MAX_JMPSIZE + if (0) + { + void *stub; + int stubsize; + unsigned char *newblock2, *p; + + // encode as function call +doNonInlinedAndOr_: + parm_size = parm_size_pre; + + if (op->fntype == FN_LOGICAL_AND) + { + stub = GLUE_realAddress(nseel_asm_band,nseel_asm_band_end,&stubsize); + } + else + { + stub = GLUE_realAddress(nseel_asm_bor,nseel_asm_bor_end,&stubsize); + } + + if (bufOut_len < parm_size + stubsize) RET_MINUS1_FAIL("band/bor len fail") + + if (bufOut) + { + int fUse2=0; + newblock2 = compileCodeBlockWithRet(ctx,op->parms.parms[1],computTableSize,namespacePathToThis, retType, NULL, &fUse2, NULL); + if (!newblock2) RET_MINUS1_FAIL("band/bor ccbwr fail") + + if (fUse2 > *fpStackUse) *fpStackUse=fUse2; + + p = bufOut + parm_size; + memcpy(p, stub, stubsize); + + p=EEL_GLUE_set_immediate(p,(INT_PTR)newblock2); + } + return rv_offset + parm_size + stubsize; + } +#endif + } + + if (op->opcodeType == OPCODETYPE_FUNC3 && op->fntype == FN_IF_ELSE) // special case: IF + { + int fUse1=0; +#ifdef GLUE_MAX_JMPSIZE + int parm_size_pre; +#endif + int use_rv = RETURNVALUE_IGNORE; + int rvMode=0; + int parm_size = compileOpcodes(ctx,op->parms.parms[0],bufOut,bufOut_len, computTableSize, namespacePathToThis, RETURNVALUE_BOOL|RETURNVALUE_BOOL_REVERSED, &rvMode,&fUse1, NULL); + if (parm_size < 0) RET_MINUS1_FAIL("if coc fail") + if (fUse1 > *fpStackUse) *fpStackUse=fUse1; + + if (preferredReturnValues & RETURNVALUE_NORMAL) use_rv=RETURNVALUE_NORMAL; + else if (preferredReturnValues & RETURNVALUE_FPSTACK) use_rv=RETURNVALUE_FPSTACK; + else if (preferredReturnValues & RETURNVALUE_BOOL) use_rv=RETURNVALUE_BOOL; + + *calledRvType = use_rv; +#ifdef GLUE_MAX_JMPSIZE + parm_size_pre = parm_size; +#endif + + { + int csz,hasSecondHalf; + if (rvMode & RETURNVALUE_BOOL_REVERSED) + { + if (bufOut_len < parm_size + (int)sizeof(GLUE_JMP_IF_P1_NZ)) RET_MINUS1_FAIL_FALLBACK("if size fail",doNonInlineIf_) + if (bufOut) memcpy(bufOut+parm_size,GLUE_JMP_IF_P1_NZ,sizeof(GLUE_JMP_IF_P1_NZ)); + parm_size += sizeof(GLUE_JMP_IF_P1_NZ); + } + else + { + if (bufOut_len < parm_size + (int)sizeof(GLUE_JMP_IF_P1_Z)) RET_MINUS1_FAIL_FALLBACK("if size fail",doNonInlineIf_) + if (bufOut) memcpy(bufOut+parm_size,GLUE_JMP_IF_P1_Z,sizeof(GLUE_JMP_IF_P1_Z)); + parm_size += sizeof(GLUE_JMP_IF_P1_Z); + } + csz=compileOpcodes(ctx,op->parms.parms[1],bufOut ? bufOut+parm_size : NULL,bufOut_len - parm_size, computTableSize, namespacePathToThis, use_rv, NULL,&fUse1, canHaveDenormalOutput); + if (fUse1 > *fpStackUse) *fpStackUse=fUse1; + hasSecondHalf = preferredReturnValues || !OPCODE_IS_TRIVIAL(op->parms.parms[2]); + + CHECK_SIZE_FORJMP(csz,doNonInlineIf_) + if (csz<0) RET_MINUS1_FAIL("if coc fial") + + if (bufOut) GLUE_JMP_SET_OFFSET(bufOut + parm_size, csz + (hasSecondHalf?sizeof(GLUE_JMP_NC):0)); + parm_size+=csz; + + if (hasSecondHalf) + { + if (bufOut_len < parm_size + (int)sizeof(GLUE_JMP_NC)) RET_MINUS1_FAIL_FALLBACK("if len fail",doNonInlineIf_) + if (bufOut) memcpy(bufOut+parm_size,GLUE_JMP_NC,sizeof(GLUE_JMP_NC)); + parm_size+=sizeof(GLUE_JMP_NC); + + csz=compileOpcodes(ctx,op->parms.parms[2],bufOut ? bufOut+parm_size : NULL,bufOut_len - parm_size, computTableSize, namespacePathToThis, use_rv, NULL, &fUse1, canHaveDenormalOutput); + + CHECK_SIZE_FORJMP(csz,doNonInlineIf_) + if (csz<0) RET_MINUS1_FAIL("if coc 2 fail") + + // update jump address + if (bufOut) GLUE_JMP_SET_OFFSET(bufOut + parm_size,csz); + parm_size+=csz; + if (fUse1 > *fpStackUse) *fpStackUse=fUse1; + } + return rv_offset + parm_size; + } +#ifdef GLUE_MAX_JMPSIZE + if (0) + { + unsigned char *newblock2,*newblock3,*ptr; + void *stub; + int stubsize; +doNonInlineIf_: + parm_size = parm_size_pre; + stub = GLUE_realAddress(nseel_asm_if,nseel_asm_if_end,&stubsize); + + if (!stub || bufOut_len < parm_size + stubsize) RET_MINUS1_FAIL(stub ? "if sz fail" : "if addr fail") + + if (bufOut) + { + int fUse2=0; + newblock2 = compileCodeBlockWithRet(ctx,op->parms.parms[1],computTableSize,namespacePathToThis, use_rv, NULL,&fUse2, canHaveDenormalOutput); + if (fUse2 > *fpStackUse) *fpStackUse=fUse2; + newblock3 = compileCodeBlockWithRet(ctx,op->parms.parms[2],computTableSize,namespacePathToThis, use_rv, NULL,&fUse2, canHaveDenormalOutput); + if (fUse2 > *fpStackUse) *fpStackUse=fUse2; + if (!newblock2 || !newblock3) RET_MINUS1_FAIL("if subblock gen fail") + + ptr = bufOut + parm_size; + memcpy(ptr, stub, stubsize); + + ptr=EEL_GLUE_set_immediate(ptr,(INT_PTR)newblock2); + EEL_GLUE_set_immediate(ptr,(INT_PTR)newblock3); + } + return rv_offset + parm_size + stubsize; + } +#endif + } + + { + // special case: while + if (op->opcodeType == OPCODETYPE_FUNC1 && op->fntype == FN_WHILE) + { + *calledRvType = RETURNVALUE_BOOL; + +#ifndef GLUE_INLINE_LOOPS + // todo: PPC looping support when loop length is small enough + { + unsigned char *pwr=bufOut; + unsigned char *newblock2; + int stubsz; + void *stubfunc = GLUE_realAddress(nseel_asm_repeatwhile,nseel_asm_repeatwhile_end,&stubsz); + if (!stubfunc || bufOut_len < stubsz) RET_MINUS1_FAIL(stubfunc ? "repeatwhile size fail" :"repeatwhile addr fail") + + if (bufOut) + { + newblock2=compileCodeBlockWithRet(ctx,op->parms.parms[0],computTableSize,namespacePathToThis, RETURNVALUE_BOOL, NULL, fpStackUse, NULL); + if (!newblock2) RET_MINUS1_FAIL("repeatwhile ccbwr fail") + + memcpy(pwr,stubfunc,stubsz); + pwr=EEL_GLUE_set_immediate(pwr,(INT_PTR)newblock2); + } + + return rv_offset+stubsz; + } +#else + { +#ifndef GLUE_WHILE_END_NOJUMP + unsigned char *jzoutpt; +#endif + unsigned char *looppt; + int parm_size=0,subsz; + if (bufOut_len < parm_size + (int)(GLUE_WHILE_SETUP_SIZE + sizeof(GLUE_WHILE_BEGIN))) RET_MINUS1_FAIL("while size fail 1") + + if (bufOut) memcpy(bufOut + parm_size,GLUE_WHILE_SETUP,GLUE_WHILE_SETUP_SIZE); + parm_size+=GLUE_WHILE_SETUP_SIZE; + + looppt = bufOut + parm_size; + if (bufOut) memcpy(bufOut + parm_size,GLUE_WHILE_BEGIN,sizeof(GLUE_WHILE_BEGIN)); + parm_size+=sizeof(GLUE_WHILE_BEGIN); + + subsz = compileOpcodes(ctx,op->parms.parms[0],bufOut ? (bufOut + parm_size) : NULL,bufOut_len - parm_size, computTableSize, namespacePathToThis, RETURNVALUE_BOOL, NULL,fpStackUse, NULL); + if (subsz<0) RET_MINUS1_FAIL("while coc fail") + + if (bufOut_len < parm_size + (int)(sizeof(GLUE_WHILE_END) + sizeof(GLUE_WHILE_CHECK_RV))) RET_MINUS1_FAIL("which size fial 2") + + parm_size+=subsz; + if (bufOut) memcpy(bufOut + parm_size, GLUE_WHILE_END, sizeof(GLUE_WHILE_END)); + parm_size+=sizeof(GLUE_WHILE_END); +#ifndef GLUE_WHILE_END_NOJUMP + jzoutpt = bufOut + parm_size; +#endif + + if (bufOut) memcpy(bufOut + parm_size, GLUE_WHILE_CHECK_RV, sizeof(GLUE_WHILE_CHECK_RV)); + parm_size+=sizeof(GLUE_WHILE_CHECK_RV); + if (bufOut) + { + GLUE_JMP_SET_OFFSET(bufOut + parm_size,(looppt - (bufOut+parm_size)) ); +#ifndef GLUE_WHILE_END_NOJUMP + GLUE_JMP_SET_OFFSET(jzoutpt, (bufOut + parm_size) - jzoutpt); +#endif + } + return rv_offset+parm_size; + } + +#endif + } + + // special case: loop + if (op->opcodeType == OPCODETYPE_FUNC2 && op->fntype == FN_LOOP) + { + int fUse1; + int parm_size = compileOpcodes(ctx,op->parms.parms[0],bufOut,bufOut_len, computTableSize, namespacePathToThis, RETURNVALUE_FPSTACK, NULL,&fUse1, NULL); + if (parm_size < 0) RET_MINUS1_FAIL("loop coc fail") + + *calledRvType = RETURNVALUE_BOOL; + if (fUse1 > *fpStackUse) *fpStackUse=fUse1; + +#ifndef GLUE_INLINE_LOOPS + // todo: PPC looping support when loop length is small enough + { + void *stub; + int stubsize; + unsigned char *newblock2, *p; + stub = GLUE_realAddress(nseel_asm_repeat,nseel_asm_repeat_end,&stubsize); + if (bufOut_len < parm_size + stubsize) RET_MINUS1_FAIL("loop size fail") + if (bufOut) + { + newblock2 = compileCodeBlockWithRet(ctx,op->parms.parms[1],computTableSize,namespacePathToThis, RETURNVALUE_IGNORE, NULL,fpStackUse, NULL); + + p = bufOut + parm_size; + memcpy(p, stub, stubsize); + + p=EEL_GLUE_set_immediate(p,(INT_PTR)newblock2); + } + return rv_offset + parm_size + stubsize; + } +#else + { + int subsz; + int fUse2=0; + unsigned char *skipptr1,*loopdest; + + if (bufOut_len < parm_size + (int)(sizeof(GLUE_LOOP_LOADCNT) + GLUE_LOOP_CLAMPCNT_SIZE + GLUE_LOOP_BEGIN_SIZE)) RET_MINUS1_FAIL("loop size fail") + + // store, convert to int, compare against 1, if less than, skip to end + if (bufOut) memcpy(bufOut+parm_size,GLUE_LOOP_LOADCNT,sizeof(GLUE_LOOP_LOADCNT)); + parm_size += sizeof(GLUE_LOOP_LOADCNT); + skipptr1 = bufOut+parm_size; + + // compare aginst max loop length, jump to loop start if not above it + if (bufOut) memcpy(bufOut+parm_size,GLUE_LOOP_CLAMPCNT,GLUE_LOOP_CLAMPCNT_SIZE); + parm_size += GLUE_LOOP_CLAMPCNT_SIZE; + + // loop code: + loopdest = bufOut + parm_size; + + if (bufOut) memcpy(bufOut+parm_size,GLUE_LOOP_BEGIN,GLUE_LOOP_BEGIN_SIZE); + parm_size += GLUE_LOOP_BEGIN_SIZE; + + subsz = compileOpcodes(ctx,op->parms.parms[1],bufOut ? (bufOut + parm_size) : NULL,bufOut_len - parm_size, computTableSize, namespacePathToThis, RETURNVALUE_IGNORE, NULL, &fUse2, NULL); + if (subsz<0) RET_MINUS1_FAIL("loop coc fail") + if (fUse2 > *fpStackUse) *fpStackUse=fUse2; + + parm_size += subsz; + + if (bufOut_len < parm_size + (int)sizeof(GLUE_LOOP_END)) RET_MINUS1_FAIL("loop size fail 2") + + if (bufOut) memcpy(bufOut+parm_size,GLUE_LOOP_END,sizeof(GLUE_LOOP_END)); + parm_size += sizeof(GLUE_LOOP_END); + + if (bufOut) + { + GLUE_JMP_SET_OFFSET(bufOut + parm_size,loopdest - (bufOut+parm_size)); + GLUE_JMP_SET_OFFSET(skipptr1, (bufOut+parm_size) - skipptr1); + } + + return rv_offset + parm_size; + + } +#endif + } + } + + switch (op->opcodeType) + { + case OPCODETYPE_DIRECTVALUE: + if (preferredReturnValues == RETURNVALUE_BOOL) + { + int w = fabs(op->parms.dv.directValue) >= NSEEL_CLOSEFACTOR; + int wsz=(w?sizeof(GLUE_SET_P1_NZ):sizeof(GLUE_SET_P1_Z)); + + *calledRvType = RETURNVALUE_BOOL; + if (bufOut_len < wsz) RET_MINUS1_FAIL("direct bool size fail3") + if (bufOut) memcpy(bufOut,w?GLUE_SET_P1_NZ:GLUE_SET_P1_Z,wsz); + return rv_offset+wsz; + } + else if (preferredReturnValues & RETURNVALUE_FPSTACK) + { +#ifdef GLUE_HAS_FLDZ + if (op->parms.dv.directValue == 0.0) + { + *fpStackUse = 1; + *calledRvType = RETURNVALUE_FPSTACK; + if (bufOut_len < sizeof(GLUE_FLDZ)) RET_MINUS1_FAIL("direct fp fail 1") + if (bufOut) memcpy(bufOut,GLUE_FLDZ,sizeof(GLUE_FLDZ)); + return rv_offset+sizeof(GLUE_FLDZ); + } +#endif +#ifdef GLUE_HAS_FLD1 + if (op->parms.dv.directValue == 1.0) + { + *fpStackUse = 1; + *calledRvType = RETURNVALUE_FPSTACK; + if (bufOut_len < sizeof(GLUE_FLD1)) RET_MINUS1_FAIL("direct fp fail 1") + if (bufOut) memcpy(bufOut,GLUE_FLD1,sizeof(GLUE_FLD1)); + return rv_offset+sizeof(GLUE_FLD1); + } +#endif + } + // fall through + case OPCODETYPE_DIRECTVALUE_TEMPSTRING: + case OPCODETYPE_VALUE_FROM_NAMESPACENAME: + case OPCODETYPE_VARPTR: + case OPCODETYPE_VARPTRPTR: + + + #ifdef GLUE_MOV_PX_DIRECTVALUE_TOSTACK_SIZE + if (OPCODE_IS_TRIVIAL(op)) + { + if (preferredReturnValues & RETURNVALUE_FPSTACK) + { + *fpStackUse = 1; + if (bufOut_len < GLUE_MOV_PX_DIRECTVALUE_TOSTACK_SIZE) RET_MINUS1_FAIL("direct fp fail 2") + if (bufOut) + { + if (generateValueToReg(ctx,op,bufOut,-1,namespacePathToThis, 1 /*allow caching*/)<0) RET_MINUS1_FAIL("direct fp fail gvr") + } + *calledRvType = RETURNVALUE_FPSTACK; + return rv_offset+GLUE_MOV_PX_DIRECTVALUE_TOSTACK_SIZE; + } + } + #endif + + if (bufOut_len < GLUE_MOV_PX_DIRECTVALUE_SIZE) + { + RET_MINUS1_FAIL("direct value fail 1") + } + if (bufOut) + { + if (generateValueToReg(ctx,op,bufOut,0,namespacePathToThis, + (preferredReturnValues&(RETURNVALUE_FPSTACK|RETURNVALUE_CACHEABLE))!=0)<0) + { + RET_MINUS1_FAIL("direct value gvr fail3") + } + } + return rv_offset + GLUE_MOV_PX_DIRECTVALUE_SIZE; + + case OPCODETYPE_FUNCX: + case OPCODETYPE_FUNC1: + case OPCODETYPE_FUNC2: + case OPCODETYPE_FUNC3: + + if (op->fntype == FUNCTYPE_EELFUNC) + { + int a; + + a = compileEelFunctionCall(ctx,op,bufOut,bufOut_len,computTableSize,namespacePathToThis, calledRvType,fpStackUse,canHaveDenormalOutput); + if (a<0) return a; + rv_offset += a; + } + else + { + int a; + a = compileNativeFunctionCall(ctx,op,bufOut,bufOut_len,computTableSize,namespacePathToThis, calledRvType,fpStackUse,preferredReturnValues,canHaveDenormalOutput); + if (a<0)return a; + rv_offset += a; + } + return rv_offset; + } + + RET_MINUS1_FAIL("default opcode fail") +} + +#ifdef DUMP_OPS_DURING_COMPILE +FILE *g_debugfp; +int g_debugfp_indent; +int g_debugfp_histsz=0; + +void dumpOp(compileContext *ctx, opcodeRec *op, int start) +{ + if (start>=0) + { + if (g_debugfp) + { + static opcodeRec **hist; + + int x; + int hit=0; + if (!hist) hist = (opcodeRec**) calloc(1024,1024*sizeof(opcodeRec*)); + for(x=0;x<g_debugfp_histsz;x++) + { + if (hist[x] == op) { hit=1; break; } + } + if (x ==g_debugfp_histsz && g_debugfp_histsz<1024*1024) hist[g_debugfp_histsz++] = op; + + if (!start) + { + g_debugfp_indent-=2; + fprintf(g_debugfp,"%*s}(join)\n",g_debugfp_indent," "); + } + if (g_debugfp_indent>=100) *(char *)1=0; + fprintf(g_debugfp,"%*s{ %p : %d%s: ",g_debugfp_indent," ",op,op->opcodeType, hit ? " -- DUPLICATE" : ""); + switch (op->opcodeType) + { + case OPCODETYPE_DIRECTVALUE: + fprintf(g_debugfp,"dv %f",op->parms.dv.directValue); + break; + case OPCODETYPE_VARPTR: + if (op->relname && op->relname[0]) + { + fprintf(g_debugfp,"var %s",op->relname); + } + else + { + int wb; + for (wb = 0; wb < ctx->varTable_numBlocks; wb ++) + { + char **plist=ctx->varTable_Names[wb]; + if (!plist) break; + + if (op->parms.dv.valuePtr >= ctx->varTable_Values[wb] && op->parms.dv.valuePtr < ctx->varTable_Values[wb] + NSEEL_VARS_PER_BLOCK) + { + fprintf(g_debugfp,"var %s",plist[op->parms.dv.valuePtr - ctx->varTable_Values[wb]]); + break; + } + } + } + break; + case OPCODETYPE_FUNC1: + case OPCODETYPE_FUNC2: + case OPCODETYPE_FUNC3: + case OPCODETYPE_FUNCX: + if (op->fntype == FUNCTYPE_FUNCTIONTYPEREC) + { + functionType *p=(functionType*)op->fn; + fprintf(g_debugfp,"func %d: %s",p->nParams&0xff,p->name); + } + else + fprintf(g_debugfp,"sf %d",op->fntype); + break; + + } + fprintf(g_debugfp,"\n"); + g_debugfp_indent+=2; + } + } + else + { + if (g_debugfp) + { + g_debugfp_indent-=2; + fprintf(g_debugfp,"%*s}%p\n",g_debugfp_indent," ",op); + } + } +} +#endif + +int compileOpcodes(compileContext *ctx, opcodeRec *op, unsigned char *bufOut, int bufOut_len, int *computTableSize, const namespaceInformation *namespacePathToThis, + int supportedReturnValues, int *rvType, int *fpStackUse, int *canHaveDenormalOutput) +{ + int code_returns=RETURNVALUE_NORMAL; + int fpsu=0; + int codesz; + int denorm=0; + +#ifdef DUMP_OPS_DURING_COMPILE + dumpOp(ctx,op,1); +#endif + + codesz = compileOpcodesInternal(ctx,op,bufOut,bufOut_len,computTableSize,namespacePathToThis,&code_returns, supportedReturnValues,&fpsu,&denorm); + if (denorm && canHaveDenormalOutput) *canHaveDenormalOutput=1; + +#ifdef DUMP_OPS_DURING_COMPILE + dumpOp(ctx,op,-1); +#endif +#ifdef EEL_DUMP_OPS + // dump opcode trees for verification, after optimizing + if (g_eel_dump_fp2) + { + fprintf(g_eel_dump_fp2,"-- compileOpcodes generated %d bytes of code!\r\n",codesz); + } +#endif + if (codesz < 0) return codesz; + + + /* + { + char buf[512]; + sprintf(buf,"opcode %d %d (%s): fpu use: %d\n",op->opcodeType,op->fntype, + op->opcodeType >= OPCODETYPE_FUNC1 && op->fntype == FUNCTYPE_FUNCTIONTYPEREC ? ( + ((functionType *)op->fn)->name + ) : "", + fpsu); + OutputDebugString(buf); + } + */ + + if (fpStackUse) *fpStackUse=fpsu; + + if (bufOut) bufOut += codesz; + bufOut_len -= codesz; + + + if (code_returns == RETURNVALUE_BOOL && !(supportedReturnValues & RETURNVALUE_BOOL) && supportedReturnValues) + { + int stubsize; + void *stub = GLUE_realAddress(nseel_asm_booltofp,nseel_asm_booltofp_end,&stubsize); + if (!stub || bufOut_len < stubsize) RET_MINUS1_FAIL(stub?"booltofp size":"booltfp addr") + if (bufOut) + { + memcpy(bufOut,stub,stubsize); + bufOut += stubsize; + } + codesz+=stubsize; + bufOut_len -= stubsize; + + code_returns = RETURNVALUE_FPSTACK; + } + + + // default processing of code_returns to meet return value requirements + if (supportedReturnValues & code_returns) + { + if (rvType) *rvType = code_returns; + return codesz; + } + + + if (rvType) *rvType = RETURNVALUE_IGNORE; + + + if (code_returns == RETURNVALUE_NORMAL) + { + if (supportedReturnValues & (RETURNVALUE_FPSTACK|RETURNVALUE_BOOL)) + { + if (bufOut_len < GLUE_PUSH_VAL_AT_PX_TO_FPSTACK_SIZE) RET_MINUS1_FAIL("pushvalatpxtofpstack,size") + if (bufOut) + { + GLUE_PUSH_VAL_AT_PX_TO_FPSTACK(bufOut,0); // always fld qword [eax] but we might change that later + bufOut += GLUE_PUSH_VAL_AT_PX_TO_FPSTACK_SIZE; + } + codesz += GLUE_PUSH_VAL_AT_PX_TO_FPSTACK_SIZE; + bufOut_len -= GLUE_PUSH_VAL_AT_PX_TO_FPSTACK_SIZE; + + if (supportedReturnValues & RETURNVALUE_BOOL) + { + code_returns = RETURNVALUE_FPSTACK; + } + else + { + if (rvType) *rvType = RETURNVALUE_FPSTACK; + } + } + } + + if (code_returns == RETURNVALUE_FPSTACK) + { + if (supportedReturnValues & (RETURNVALUE_BOOL|RETURNVALUE_BOOL_REVERSED)) + { + int stubsize; + void *stub; + + if (supportedReturnValues & RETURNVALUE_BOOL_REVERSED) + { + if (rvType) *rvType = RETURNVALUE_BOOL_REVERSED; + stub = GLUE_realAddress(nseel_asm_fptobool_rev,nseel_asm_fptobool_rev_end,&stubsize); + } + else + { + if (rvType) *rvType = RETURNVALUE_BOOL; + stub = GLUE_realAddress(nseel_asm_fptobool,nseel_asm_fptobool_end,&stubsize); + } + + + if (!stub || bufOut_len < stubsize) RET_MINUS1_FAIL(stub?"fptobool size":"fptobool addr") + if (bufOut) + { + memcpy(bufOut,stub,stubsize); + bufOut += stubsize; + } + codesz+=stubsize; + bufOut_len -= stubsize; + } + else if (supportedReturnValues & RETURNVALUE_NORMAL) + { + if (computTableSize) (*computTableSize) ++; + + if (bufOut_len < GLUE_POP_FPSTACK_TO_WTP_TO_PX_SIZE) RET_MINUS1_FAIL("popfpstacktowtptopxsize") + + // generate fp-pop to temp space + if (bufOut) GLUE_POP_FPSTACK_TO_WTP_TO_PX(bufOut,0); + codesz+=GLUE_POP_FPSTACK_TO_WTP_TO_PX_SIZE; + if (rvType) *rvType = RETURNVALUE_NORMAL; + } + else + { + // toss return value that will be ignored + if (bufOut_len < GLUE_POP_FPSTACK_SIZE) RET_MINUS1_FAIL("popfpstack size") + if (bufOut) memcpy(bufOut,GLUE_POP_FPSTACK,GLUE_POP_FPSTACK_SIZE); + codesz+=GLUE_POP_FPSTACK_SIZE; + } + } + + return codesz; +} + + +#if 0 +static void movestringover(char *str, int amount) +{ + char tmp[1024+8]; + + int l=(int)strlen(str); + l=wdl_min(1024-amount-1,l); + + memcpy(tmp,str,l+1); + + while (l >= 0 && tmp[l]!='\n') l--; + l++; + + tmp[l]=0;//ensure we null terminate + + memcpy(str+amount,tmp,l+1); +} +#endif + +//------------------------------------------------------------------------------ +NSEEL_CODEHANDLE NSEEL_code_compile(NSEEL_VMCTX _ctx, const char *_expression, int lineoffs) +{ + return NSEEL_code_compile_ex(_ctx,_expression,lineoffs,0); +} + +typedef struct topLevelCodeSegmentRec { + struct topLevelCodeSegmentRec *_next; + void *code; + int codesz; + int tmptable_use; +} topLevelCodeSegmentRec; + + +NSEEL_CODEHANDLE NSEEL_code_compile_ex(NSEEL_VMCTX _ctx, const char *_expression, int lineoffs, int compile_flags) +{ + compileContext *ctx = (compileContext *)_ctx; + const char *endptr; + const char *_expression_end; + codeHandleType *handle; + topLevelCodeSegmentRec *startpts_tail=NULL; + topLevelCodeSegmentRec *startpts=NULL; + _codeHandleFunctionRec *oldCommonFunctionList; + int curtabptr_sz=0; + void *curtabptr=NULL; + int had_err=0; + + if (!ctx) return 0; + + ctx->directValueCache=0; + ctx->optimizeDisableFlags=0; + ctx->gotEndOfInput=0; + ctx->current_compile_flags = compile_flags; + + if (compile_flags & NSEEL_CODE_COMPILE_FLAG_COMMONFUNCS_RESET) + { + ctx->functions_common=NULL; // reset common function list + } + else + { + // reset common compiled function code, forcing a recompile if shared + _codeHandleFunctionRec *a = ctx->functions_common; + while (a) + { + _codeHandleFunctionRec *b = a->derivedCopies; + + if (a->localstorage) + { + // force local storage actual values to be reallocated if used again + memset(a->localstorage,0,sizeof(EEL_F *) * a->localstorage_size); + } + + a->startptr = NULL; // force this copy to be recompiled + a->startptr_size = -1; + + while (b) + { + b->startptr = NULL; // force derived copies to get recompiled + b->startptr_size = -1; + // no need to reset b->localstorage, since it points to a->localstorage + b=b->derivedCopies; + } + + a=a->next; + } + } + + ctx->last_error_string[0]=0; + + if (!_expression || !*_expression) return 0; + + _expression_end = _expression + strlen(_expression); + + oldCommonFunctionList = ctx->functions_common; + + ctx->isGeneratingCommonFunction=0; + ctx->isSharedFunctions = !!(compile_flags & NSEEL_CODE_COMPILE_FLAG_COMMONFUNCS); + ctx->functions_local = NULL; + + freeBlocks(&ctx->tmpblocks_head); // free blocks + freeBlocks(&ctx->blocks_head); // free blocks + freeBlocks(&ctx->blocks_head_data); // free blocks + memset(ctx->l_stats,0,sizeof(ctx->l_stats)); + + handle = (codeHandleType*)newDataBlock(sizeof(codeHandleType),8); + + if (!handle) + { + return 0; + } + + + memset(handle,0,sizeof(codeHandleType)); + + ctx->l_stats[0] += (int)(_expression_end - _expression); + ctx->tmpCodeHandle = handle; + endptr=_expression; + + while (*endptr) + { + int computTableTop = 0; + int startptr_size=0; + void *startptr=NULL; + opcodeRec *start_opcode=NULL; + const char *expr=endptr; + + int function_numparms=0; + char is_fname[NSEEL_MAX_VARIABLE_NAMELEN+1]; + is_fname[0]=0; + + memset(ctx->function_localTable_Size,0,sizeof(ctx->function_localTable_Size)); + memset(ctx->function_localTable_Names,0,sizeof(ctx->function_localTable_Names)); + ctx->function_localTable_ValuePtrs=0; + ctx->function_usesNamespaces=0; + ctx->function_curName=NULL; + ctx->function_globalFlag=0; + + ctx->errVar=0; + + // single out top level segment + { + int had_something = 0, pcnt=0, pcnt2=0; + int state=0; + for (;;) + { + int l; + const char *p=nseel_simple_tokenizer(&endptr,_expression_end,&l,&state); + if (!p) + { + if (pcnt || pcnt2) ctx->gotEndOfInput|=4; + break; + } + + if (*p == ';') + { + if (had_something && !pcnt && !pcnt2) break; + } + else if (*p == '/' && l > 1 && (p[1] == '/' || p[1] == '*')) + { + if (l > 19 && !strnicmp(p,"//#eel-no-optimize:",19)) + ctx->optimizeDisableFlags = atoi(p+19); + } + else + { + if (!had_something) + { + expr = p; + had_something = 1; + } + + if (*p == '(') pcnt++; + else if (*p == ')') { if (--pcnt<0) pcnt=0; } + else if (*p == '[') pcnt2++; + else if (*p == ']') { if (--pcnt2<0) pcnt2=0; } + } + } + if (!*expr || !had_something) break; + } + + // parse + + { + int tmplen,funcname_len; + const char *p = expr; + const char *tok1 = nseel_simple_tokenizer(&p,endptr,&tmplen,NULL); + const char *funcname = nseel_simple_tokenizer(&p,endptr,&funcname_len,NULL); + if (tok1 && funcname && tmplen == 8 && !strnicmp(tok1,"function",8) && (isalpha(funcname[0]) || funcname[0] == '_')) + { + int had_parms_locals=0; + if (funcname_len > sizeof(is_fname)-1) funcname_len=sizeof(is_fname)-1; + memcpy(is_fname, funcname, funcname_len); + is_fname[funcname_len]=0; + ctx->function_curName = is_fname; // only assigned for the duration of the loop, cleared later //-V507 + + while (NULL != (tok1 = nseel_simple_tokenizer(&p,endptr,&tmplen,NULL))) + { + int is_parms = 0, localTableContext = 0; + int maxcnt=0; + const char *sp_save; + + if (tok1[0] == '(') + { + if (had_parms_locals) + { + expr = p-1; // begin compilation at this code! + break; + } + is_parms = 1; + } + else + { + if (tmplen == 5 && !strnicmp(tok1,"local",tmplen)) localTableContext=0; + else if (tmplen == 6 && !strnicmp(tok1,"static",tmplen)) localTableContext=0; + else if (tmplen == 8 && !strnicmp(tok1,"instance",tmplen)) localTableContext=1; + else if ((tmplen == 7 && !strnicmp(tok1,"globals",tmplen)) || + (tmplen == 6 && !strnicmp(tok1,"global",tmplen))) + { + ctx->function_globalFlag = 1; + localTableContext=2; + } + else break; // unknown token! + + tok1 = nseel_simple_tokenizer(&p,endptr,&tmplen,NULL); + if (!tok1 || tok1[0] != '(') break; + } + had_parms_locals = 1; + + + sp_save=p; + + while (NULL != (tok1 = nseel_simple_tokenizer(&p,endptr,&tmplen,NULL))) + { + if (tok1[0] == ')') break; + if (*tok1 == '#' && localTableContext!=1 && localTableContext!=2) + { + ctx->errVar = (int) (tok1 - _expression); + lstrcpyn_safe(ctx->last_error_string,"#string can only be in instance() or globals()",sizeof(ctx->last_error_string)); + goto had_error; + } + + if (isalpha(*tok1) || *tok1 == '_' || *tok1 == '#') + { + maxcnt++; + if (p < endptr && *p == '*') + { + if (!is_parms && localTableContext!=2) + { + ctx->errVar = (int) (p - _expression); + lstrcpyn_safe(ctx->last_error_string,"namespace* can only be used in parameters or globals()",sizeof(ctx->last_error_string)); + goto had_error; + } + p++; + } + } + else if (*tok1 != ',') + { + ctx->errVar = (int)(tok1 - _expression); + lstrcpyn_safe(ctx->last_error_string,"unknown character in function parameters",sizeof(ctx->last_error_string)); + goto had_error; + } + } + + if (tok1 && maxcnt > 0) + { + char **ot = ctx->function_localTable_Names[localTableContext]; + const int osz = ctx->function_localTable_Size[localTableContext]; + + maxcnt += osz; + + ctx->function_localTable_Names[localTableContext] = (char **)newTmpBlock(ctx,sizeof(char *) * maxcnt); + + if (ctx->function_localTable_Names[localTableContext]) + { + int i=osz; + if (osz && ot) memcpy(ctx->function_localTable_Names[localTableContext],ot,sizeof(char *) * osz); + p=sp_save; + + while (NULL != (tok1 = nseel_simple_tokenizer(&p,endptr,&tmplen,NULL))) + { + if (tok1[0] == ')') break; + if (isalpha(*tok1) || *tok1 == '_' || *tok1 == '#') + { + char *newstr; + int l = tmplen; + if (*p == '*') // xyz* for namespace + { + p++; + l++; + } + if (l > NSEEL_MAX_VARIABLE_NAMELEN) l = NSEEL_MAX_VARIABLE_NAMELEN; + newstr = newTmpBlock(ctx,l+1); + if (newstr) + { + memcpy(newstr,tok1,l); + newstr[l]=0; + ctx->function_localTable_Names[localTableContext][i++] = newstr; + } + } + } + ctx->function_localTable_Size[localTableContext]=i; + if (is_parms) function_numparms = i; + } + } + } + } + } + if (ctx->function_localTable_Size[0]>0) + { + ctx->function_localTable_ValuePtrs = + ctx->isSharedFunctions ? newDataBlock(ctx->function_localTable_Size[0] * sizeof(EEL_F *),8) : + newTmpBlock(ctx,ctx->function_localTable_Size[0] * sizeof(EEL_F *)); + if (!ctx->function_localTable_ValuePtrs) + { + ctx->function_localTable_Size[0]=0; + function_numparms=0; + } + else + { + memset(ctx->function_localTable_ValuePtrs,0,sizeof(EEL_F *) * ctx->function_localTable_Size[0]); // force values to be allocated + } + } + + { + int nseelparse(compileContext* context); + void nseelrestart (void *input_file ,void *yyscanner ); + + ctx->rdbuf_start = _expression; + +#ifdef NSEEL_SUPER_MINIMAL_LEXER + + ctx->rdbuf = expr; + ctx->rdbuf_end = endptr; + if (!nseelparse(ctx) && !ctx->errVar) + { + start_opcode = ctx->result; + } +#else + + nseelrestart(NULL,ctx->scanner); + + ctx->rdbuf = expr; + ctx->rdbuf_end = endptr; + + if (!nseelparse(ctx) && !ctx->errVar) + { + start_opcode = ctx->result; + } + if (ctx->errVar) + { + const char *p=expr; + ctx->errVar += expr-_expression; + } +#endif + ctx->rdbuf = NULL; + } + + if (start_opcode) + { + int rvMode=0, fUse=0; + +#ifdef LOG_OPT + char buf[512]; + int sd=0; + sprintf(buf,"pre opt sz=%d (tsackDepth=%d)\n",compileOpcodes(ctx,start_opcode,NULL,1024*1024*256,NULL, NULL,RETURNVALUE_IGNORE,NULL,&sd,NULL),sd); +#ifdef _WIN32 + OutputDebugString(buf); +#else + printf("%s\n",buf); +#endif +#endif + +#ifdef EEL_DUMP_OPS + // dump opcode trees for verification, before optimizing + if (g_eel_dump_fp) + { + fprintf(g_eel_dump_fp,"-- opcode chunk --\r\n"); + dumpOpcodeTree(ctx,g_eel_dump_fp,start_opcode,2); + } +#endif + + if (!(ctx->optimizeDisableFlags&OPTFLAG_NO_OPTIMIZE)) optimizeOpcodes(ctx,start_opcode,is_fname[0] ? 1 : 0); +#ifdef LOG_OPT + sprintf(buf,"post opt sz=%d, stack depth=%d\n",compileOpcodes(ctx,start_opcode,NULL,1024*1024*256,NULL,NULL, RETURNVALUE_IGNORE,NULL,&sd,NULL),sd); +#ifdef _WIN32 + OutputDebugString(buf); +#else + printf("%s\n",buf); +#endif +#endif + +#ifdef EEL_DUMP_OPS + // dump opcode trees for verification, after optimizing + if (g_eel_dump_fp2) + { + fprintf(g_eel_dump_fp2,"-- POST-OPTIMIZED opcode chunk --\r\n"); + dumpOpcodeTree(ctx,g_eel_dump_fp2,start_opcode,2); + } +#endif + + if (is_fname[0]) + { + _codeHandleFunctionRec *fr = ctx->isSharedFunctions ? newDataBlock(sizeof(_codeHandleFunctionRec),8) : + newTmpBlock(ctx,sizeof(_codeHandleFunctionRec)); + if (fr) + { + memset(fr,0,sizeof(_codeHandleFunctionRec)); + fr->startptr_size = -1; + fr->opcodes = start_opcode; + + if (ctx->function_localTable_Size[0] > 0 && ctx->function_localTable_ValuePtrs) + { + if (ctx->function_localTable_Names[0]) + { + int i; + for(i=0;i<function_numparms;i++) + { + const char *nptr = ctx->function_localTable_Names[0][i]; + if (nptr && *nptr && nptr[strlen(nptr)-1] == '*') + { + fr->parameterAsNamespaceMask |= ((unsigned int)1)<<i; + } + } + } + fr->num_params=function_numparms; + fr->localstorage = ctx->function_localTable_ValuePtrs; + fr->localstorage_size = ctx->function_localTable_Size[0]; + } + + fr->usesNamespaces = ctx->function_usesNamespaces; + fr->isCommonFunction = ctx->isSharedFunctions; + + lstrcpyn_safe(fr->fname,is_fname,sizeof(fr->fname)); + + if (ctx->isSharedFunctions) + { + fr->next = ctx->functions_common; + ctx->functions_common = fr; + } + else + { + fr->next = ctx->functions_local; + ctx->functions_local = fr; + } + } + continue; + } + +#ifdef DUMP_OPS_DURING_COMPILE + g_debugfp_indent=0; + g_debugfp_histsz=0; + g_debugfp = fopen("C:/temp/foo.txt","w"); +#endif + startptr_size = compileOpcodes(ctx,start_opcode,NULL,1024*1024*256,NULL, NULL, + is_fname[0] ? (RETURNVALUE_NORMAL|RETURNVALUE_FPSTACK) : RETURNVALUE_IGNORE, &rvMode, &fUse, NULL); // if not a function, force return value as address (avoid having to pop it ourselves + // if a function, allow the code to decide how return values are generated + +#ifdef DUMP_OPS_DURING_COMPILE + if (g_debugfp) fclose(g_debugfp); + g_debugfp=0; +#endif + + + if (!startptr_size) continue; // optimized away + if (startptr_size>0) + { + startptr = newTmpBlock(ctx,startptr_size); + if (startptr) + { + startptr_size=compileOpcodes(ctx,start_opcode,(unsigned char*)startptr,startptr_size,&computTableTop, NULL, RETURNVALUE_IGNORE, NULL,NULL, NULL); + if (startptr_size<=0) startptr = NULL; + + } + } + } + + if (!startptr) + { +had_error: +#ifdef NSEEL_EEL1_COMPAT_MODE + continue; + +#else + //if (!ctx->last_error_string[0]) + { + int byteoffs = ctx->errVar; + int linenumber; + char cur_err[sizeof(ctx->last_error_string)]; + lstrcpyn_safe(cur_err,ctx->last_error_string,sizeof(cur_err)); + if (cur_err[0]) lstrcatn(cur_err,": ",sizeof(cur_err)); + else lstrcpyn_safe(cur_err,"syntax error: ",sizeof(cur_err)); + + if (_expression + byteoffs >= _expression_end) + { + if (ctx->gotEndOfInput&4) byteoffs = (int)(expr-_expression); + else byteoffs=(int)(_expression_end-_expression); + } + + if (byteoffs < 0) byteoffs=0; + + linenumber=findLineNumber(_expression,byteoffs)+1; + + if (ctx->gotEndOfInput&4) + { + snprintf(ctx->last_error_string,sizeof(ctx->last_error_string),"%d: %smissing ) or ]",linenumber+lineoffs,cur_err); + } + else + { + const char *p = _expression + byteoffs; + int x=0, right_amt_nospace=0, left_amt_nospace=0; + while (x < 32 && p-x > _expression && p[-x] != '\r' && p[-x] != '\n') + { + if (!isspace(p[-x])) left_amt_nospace=x; + x++; + } + x=0; + while (x < 60 && p[x] && p[x] != '\r' && p[x] != '\n') + { + if (!isspace(p[x])) right_amt_nospace=x; + x++; + } + + if (right_amt_nospace<1) right_amt_nospace=1; + + // display left_amt >>>> right_amt_nospace + if (left_amt_nospace > 0) + snprintf(ctx->last_error_string,sizeof(ctx->last_error_string),"%d: %s'%.*s <!> %.*s'",linenumber+lineoffs,cur_err, + left_amt_nospace,p-left_amt_nospace, + right_amt_nospace,p); + else + snprintf(ctx->last_error_string,sizeof(ctx->last_error_string),"%d: %s'%.*s'",linenumber+lineoffs,cur_err,right_amt_nospace,p); + } + } + + startpts=NULL; + startpts_tail=NULL; + had_err=1; + break; +#endif + } + + if (!is_fname[0]) // redundant check (if is_fname[0] is set and we succeeded, it should continue) + // but we'll be on the safe side + { + topLevelCodeSegmentRec *p = newTmpBlock(ctx,sizeof(topLevelCodeSegmentRec)); + p->_next=0; + p->code = startptr; + p->codesz = startptr_size; + p->tmptable_use = computTableTop; + + if (!startpts_tail) startpts_tail=startpts=p; + else + { + startpts_tail->_next=p; + startpts_tail=p; + } + + if (curtabptr_sz < computTableTop) + { + curtabptr_sz=computTableTop; + } + } + } + + memset(ctx->function_localTable_Size,0,sizeof(ctx->function_localTable_Size)); + memset(ctx->function_localTable_Names,0,sizeof(ctx->function_localTable_Names)); + ctx->function_localTable_ValuePtrs=0; + ctx->function_usesNamespaces=0; + ctx->function_curName=NULL; + ctx->function_globalFlag=0; + + ctx->tmpCodeHandle = NULL; + + if (handle->want_stack) + { + if (!handle->stack) startpts=NULL; + } + + if (startpts) + { + curtabptr_sz += 2; // many functions use the worktable for temporary storage of up to 2 EEL_F's + + handle->workTable_size = curtabptr_sz; + handle->workTable = curtabptr = newDataBlock((curtabptr_sz+MIN_COMPUTABLE_SIZE + COMPUTABLE_EXTRA_SPACE) * sizeof(EEL_F),32); + +#ifdef EEL_VALIDATE_WORKTABLE_USE + if (curtabptr) memset(curtabptr,0x3a,(curtabptr_sz+MIN_COMPUTABLE_SIZE + COMPUTABLE_EXTRA_SPACE) * sizeof(EEL_F)); +#endif + if (!curtabptr) startpts=NULL; + } + + + if (startpts || (!had_err && (compile_flags & NSEEL_CODE_COMPILE_FLAG_COMMONFUNCS))) + { + unsigned char *writeptr; + topLevelCodeSegmentRec *p=startpts; + int size=sizeof(GLUE_RET)+GLUE_FUNC_ENTER_SIZE+GLUE_FUNC_LEAVE_SIZE; // for ret at end :) + int wtpos=0; + + // now we build one big code segment out of our list of them, inserting a mov esi, computable before each item as necessary + while (p) + { + if (wtpos <= 0) + { + wtpos=MIN_COMPUTABLE_SIZE; + size += GLUE_RESET_WTP(NULL,0); + } + size+=p->codesz; + wtpos -= p->tmptable_use; + p=p->_next; + } + handle->code = newCodeBlock(size,32); + if (handle->code) + { + writeptr=(unsigned char *)handle->code; + #if GLUE_FUNC_ENTER_SIZE > 0 + memcpy(writeptr,&GLUE_FUNC_ENTER,GLUE_FUNC_ENTER_SIZE); + writeptr += GLUE_FUNC_ENTER_SIZE; + #endif + p=startpts; + wtpos=0; + while (p) + { + if (wtpos <= 0) + { + wtpos=MIN_COMPUTABLE_SIZE; + writeptr+=GLUE_RESET_WTP(writeptr,curtabptr); + } + memcpy(writeptr,(char*)p->code,p->codesz); + writeptr += p->codesz; + wtpos -= p->tmptable_use; + + p=p->_next; + } + #if GLUE_FUNC_LEAVE_SIZE > 0 + memcpy(writeptr,&GLUE_FUNC_LEAVE,GLUE_FUNC_LEAVE_SIZE); + writeptr += GLUE_FUNC_LEAVE_SIZE; + #endif + memcpy(writeptr,&GLUE_RET,sizeof(GLUE_RET)); writeptr += sizeof(GLUE_RET); + ctx->l_stats[1]=size; + handle->code_size = (int) (writeptr - (unsigned char *)handle->code); +#if defined(__arm__) || defined(__aarch64__) + __clear_cache(handle->code,writeptr); +#endif + } + + handle->blocks = ctx->blocks_head; + handle->blocks_data = ctx->blocks_head_data; + ctx->blocks_head=0; + ctx->blocks_head_data=0; + } + else + { + // failed compiling, or failed calloc() + handle=NULL; // return NULL (after resetting blocks_head) + } + + + ctx->directValueCache=0; + ctx->functions_local = NULL; + + ctx->isGeneratingCommonFunction=0; + ctx->isSharedFunctions=0; + + freeBlocks(&ctx->tmpblocks_head); // free blocks + freeBlocks(&ctx->blocks_head); // free blocks of code (will be nonzero only on error) + freeBlocks(&ctx->blocks_head_data); // free blocks of data (will be nonzero only on error) + + if (handle) + { + handle->compile_flags = compile_flags; + handle->ramPtr = ctx->ram_state.blocks; + memcpy(handle->code_stats,ctx->l_stats,sizeof(ctx->l_stats)); + nseel_evallib_stats[0]+=ctx->l_stats[0]; + nseel_evallib_stats[1]+=ctx->l_stats[1]; + nseel_evallib_stats[2]+=ctx->l_stats[2]; + nseel_evallib_stats[3]+=ctx->l_stats[3]; + nseel_evallib_stats[4]++; + } + else + { + ctx->functions_common = oldCommonFunctionList; // failed compiling, remove any added common functions from the list + + // remove any derived copies of functions due to error, since we may have added some that have been freed + while (oldCommonFunctionList) + { + oldCommonFunctionList->derivedCopies=NULL; + oldCommonFunctionList=oldCommonFunctionList->next; + } + } + memset(ctx->l_stats,0,sizeof(ctx->l_stats)); + + return (NSEEL_CODEHANDLE)handle; +} + +//------------------------------------------------------------------------------ +void NSEEL_code_execute(NSEEL_CODEHANDLE code) +{ +#ifndef GLUE_TABPTR_IGNORED + INT_PTR tabptr; +#endif + INT_PTR codeptr; + codeHandleType *h = (codeHandleType *)code; + if (!h || !h->code) return; + + codeptr = (INT_PTR) h->code; +#if 0 + { + unsigned int *p=(unsigned int *)codeptr; + while (*p != GLUE_RET[0]) + { + printf("instr:%04X:%04X\n",*p>>16,*p&0xffff); + p++; + } + } +#endif + +#ifndef GLUE_TABPTR_IGNORED + tabptr=(INT_PTR)h->workTable; +#endif + //printf("calling code!\n"); + GLUE_CALL_CODE(tabptr,codeptr,(INT_PTR)h->ramPtr); + +} + +int NSEEL_code_geterror_flag(NSEEL_VMCTX ctx) +{ + compileContext *c=(compileContext *)ctx; + if (c) return (c->gotEndOfInput ? 1 : 0); + return 0; +} + +char *NSEEL_code_getcodeerror(NSEEL_VMCTX ctx) +{ + compileContext *c=(compileContext *)ctx; + if (ctx && c->last_error_string[0]) return c->last_error_string; + return 0; +} + +//------------------------------------------------------------------------------ +void NSEEL_code_free(NSEEL_CODEHANDLE code) +{ + codeHandleType *h = (codeHandleType *)code; + if (h != NULL) + { +#ifdef EEL_VALIDATE_WORKTABLE_USE + if (h->workTable) + { + char *p = ((char*)h->workTable) + h->workTable_size*sizeof(EEL_F); + int x; + for(x=COMPUTABLE_EXTRA_SPACE*sizeof(EEL_F) - 1;x >= 0; x --) + if (p[x] != 0x3a) + { + char buf[512]; + snprintf(buf,sizeof(buf),"worktable overrun at byte %d (wts=%d), value = %f\n",x,h->workTable_size, *(EEL_F*)(p+(x&~(sizeof(EEL_F)-1)))); +#ifdef _WIN32 + OutputDebugString(buf); +#else + printf("%s",buf); +#endif + break; + } + } +#endif + + nseel_evallib_stats[0]-=h->code_stats[0]; + nseel_evallib_stats[1]-=h->code_stats[1]; + nseel_evallib_stats[2]-=h->code_stats[2]; + nseel_evallib_stats[3]-=h->code_stats[3]; + nseel_evallib_stats[4]--; + +#if defined(__ppc__) && defined(__APPLE__) + { + FILE *fp = fopen("/var/db/receipts/com.apple.pkg.Rosetta.plist","r"); + if (fp) + { + fclose(fp); + // on PPC, but rosetta installed, do not free h->blocks, as rosetta won't detect changes to these pages + } + else + { + freeBlocks(&h->blocks); + } + } +#else + freeBlocks(&h->blocks); +#endif + + freeBlocks(&h->blocks_data); + } + +} + +//------------------------------------------------------------------------------ + +NSEEL_VMCTX NSEEL_VM_alloc() // return a handle +{ + compileContext *ctx=calloc(1,sizeof(compileContext)); + + #ifdef NSEEL_SUPER_MINIMAL_LEXER + if (ctx) ctx->scanner = ctx; + #else + if (ctx) + { + int nseellex_init(void ** ptr_yy_globals); + void nseelset_extra(void *user_defined , void *yyscanner); + if (nseellex_init(&ctx->scanner)) + { + free(ctx); + return NULL; + } + nseelset_extra(ctx,ctx->scanner); + } + #endif + + if (ctx) + { + ctx->ram_state.maxblocks = NSEEL_RAM_BLOCKS_DEFAULTMAX; + ctx->ram_state.closefact = NSEEL_CLOSEFACTOR; + } + return ctx; +} + +int NSEEL_VM_setramsize(NSEEL_VMCTX _ctx, int maxent) +{ + compileContext *ctx = (compileContext *)_ctx; + if (!ctx) return 0; + if (maxent > 0) + { + maxent = (maxent + NSEEL_RAM_ITEMSPERBLOCK - 1)/NSEEL_RAM_ITEMSPERBLOCK; + if (maxent > NSEEL_RAM_BLOCKS) maxent = NSEEL_RAM_BLOCKS; + ctx->ram_state.maxblocks = maxent; + } + + return ctx->ram_state.maxblocks * NSEEL_RAM_ITEMSPERBLOCK; +} + +void NSEEL_VM_SetFunctionValidator(NSEEL_VMCTX _ctx, const char * (*validateFunc)(const char *fn_name, void *user), void *user) +{ + if (_ctx) + { + compileContext *ctx = (compileContext *)_ctx; + ctx->func_check = validateFunc; + ctx->func_check_user = user; + } +} + +void NSEEL_VM_SetFunctionTable(NSEEL_VMCTX _ctx, eel_function_table *tab) +{ + if (_ctx) + { + compileContext *ctx = (compileContext *)_ctx; + ctx->registered_func_tab = tab; + } +} +void NSEEL_VM_free(NSEEL_VMCTX _ctx) // free when done with a VM and ALL of its code have been freed, as well +{ + + if (_ctx) + { + compileContext *ctx=(compileContext *)_ctx; + EEL_GROWBUF_RESIZE(&ctx->varNameList,-1); + NSEEL_VM_freeRAM(_ctx); + + freeBlocks(&ctx->pblocks); + + // these should be 0 normally but just in case + freeBlocks(&ctx->tmpblocks_head); // free blocks + freeBlocks(&ctx->blocks_head); // free blocks + freeBlocks(&ctx->blocks_head_data); // free blocks + + + #ifndef NSEEL_SUPER_MINIMAL_LEXER + if (ctx->scanner) + { + int nseellex_destroy(void *yyscanner); + nseellex_destroy(ctx->scanner); + } + #endif + ctx->scanner=0; + if (ctx->has_used_global_vars) + { + nseel_globalVarItem *p = NULL; + NSEEL_HOSTSTUB_EnterMutex(); + if (--nseel_vms_referencing_globallist_cnt == 0) + { + // clear and free globals + p = nseel_globalreg_list; + nseel_globalreg_list=0; + } + NSEEL_HOSTSTUB_LeaveMutex(); + + while (p) + { + nseel_globalVarItem *op = p; + p=p->_next; + free(op); + } + } + free(ctx); + } + +} + +int *NSEEL_code_getstats(NSEEL_CODEHANDLE code) +{ + codeHandleType *h = (codeHandleType *)code; + if (h) + { + return h->code_stats; + } + return 0; +} + +void NSEEL_VM_SetStringFunc(NSEEL_VMCTX ctx, + EEL_F (*onString)(void *caller_this, struct eelStringSegmentRec *list), + EEL_F (*onNamedString)(void *caller_this, const char *name)) +{ + if (ctx) + { + compileContext *c=(compileContext*)ctx; + c->onString = onString; + c->onNamedString = onNamedString; + } +} + +void NSEEL_VM_SetCustomFuncThis(NSEEL_VMCTX ctx, void *thisptr) +{ + if (ctx) + { + compileContext *c=(compileContext*)ctx; + c->caller_this=thisptr; + } +} + + + + + +void *NSEEL_PProc_RAM(void *data, int data_size, compileContext *ctx) +{ + if (data_size>0) data=EEL_GLUE_set_immediate(data, (INT_PTR)ctx->ram_state.blocks); + return data; +} + +void *NSEEL_PProc_THIS(void *data, int data_size, compileContext *ctx) +{ + if (data_size>0) data=EEL_GLUE_set_immediate(data, (INT_PTR)ctx->caller_this); + return data; +} + +static int vartable_lowerbound(compileContext *ctx, const char *name, int *ismatch) +{ + int a = 0, c = EEL_GROWBUF_GET_SIZE(&ctx->varNameList); + varNameRec **list = EEL_GROWBUF_GET(&ctx->varNameList); + while (a != c) + { + const int b = (a+c)/2; + const int cmp = strnicmp(name,list[b]->str,NSEEL_MAX_VARIABLE_NAMELEN); + if (cmp > 0) a = b+1; + else if (cmp < 0) c = b; + else + { + *ismatch = 1; + return b; + } + } + *ismatch = 0; + return a; +} + +static void vartable_cull_list(compileContext *ctx, int refcnt_chk) +{ + const int ni = EEL_GROWBUF_GET_SIZE(&ctx->varNameList); + int i = ni, ndel = 0; + varNameRec **rd = EEL_GROWBUF_GET(&ctx->varNameList), **wr=rd; + while (i--) + { + varNameRec *v = rd[0]; + if ((!refcnt_chk || !v->refcnt) && !v->isreg) + { + ndel++; + } + else + { + if (wr != rd) *wr = *rd; + wr++; + } + rd++; + } + if (ndel) EEL_GROWBUF_RESIZE(&ctx->varNameList,ni - ndel); +} + +void NSEEL_VM_remove_unused_vars(NSEEL_VMCTX _ctx) +{ + compileContext *ctx = (compileContext *)_ctx; + if (ctx) vartable_cull_list(ctx,1); +} + +void NSEEL_VM_remove_all_nonreg_vars(NSEEL_VMCTX _ctx) +{ + compileContext *ctx = (compileContext *)_ctx; + if (ctx) vartable_cull_list(ctx,0); +} + +void NSEEL_VM_clear_var_refcnts(NSEEL_VMCTX _ctx) +{ + compileContext *ctx = (compileContext *)_ctx; + if (ctx) + { + int i = EEL_GROWBUF_GET_SIZE(&ctx->varNameList); + varNameRec **rd = EEL_GROWBUF_GET(&ctx->varNameList); + while (i--) + { + rd[0]->refcnt=0; + rd++; + } + } +} + + +#ifdef NSEEL_EEL1_COMPAT_MODE +static EEL_F __nseel_global_regs[100]; +double *NSEEL_getglobalregs() { return __nseel_global_regs; } +#endif + +EEL_F *get_global_var(compileContext *ctx, const char *gv, int addIfNotPresent) +{ + nseel_globalVarItem *p; +#ifdef NSEEL_EEL1_COMPAT_MODE + if (!strnicmp(gv,"reg",3) && gv[3]>='0' && gv[3] <= '9' && gv[4] >= '0' && gv[4] <= '9' && !gv[5]) + { + return __nseel_global_regs + atoi(gv+3); + } +#endif + + NSEEL_HOSTSTUB_EnterMutex(); + if (!ctx->has_used_global_vars) + { + ctx->has_used_global_vars++; + nseel_vms_referencing_globallist_cnt++; + } + + p = nseel_globalreg_list; + while (p) + { + if (!stricmp(p->name,gv)) break; + p=p->_next; + } + + if (!p && addIfNotPresent) + { + size_t gvl = strlen(gv); + p = (nseel_globalVarItem*)malloc(sizeof(nseel_globalVarItem) + gvl); + if (p) + { + p->data=0.0; + strcpy(p->name,gv); + p->_next = nseel_globalreg_list; + nseel_globalreg_list=p; + } + } + NSEEL_HOSTSTUB_LeaveMutex(); + return p ? &p->data : NULL; +} + + + +EEL_F *nseel_int_register_var(compileContext *ctx, const char *name, int isReg, const char **namePtrOut) +{ + int slot, match; + + if (isReg == 0 && ctx->getVariable) + { + EEL_F *ret = ctx->getVariable(ctx->getVariable_userctx, name); + if (ret) return ret; + } + + if (!strnicmp(name,"_global.",8) && name[8]) + { + EEL_F *a=get_global_var(ctx,name+8,isReg >= 0); + if (a) return a; + } + + slot = vartable_lowerbound(ctx,name, &match); + if (match) + { + varNameRec *v = EEL_GROWBUF_GET(&ctx->varNameList)[slot]; + if (isReg >= 0) + { + v->refcnt++; + if (isReg) v->isreg=isReg; + if (namePtrOut) *namePtrOut = v->str; + } + return v->value; + } + if (isReg < 0) return NULL; + + if (ctx->varValueStore_left<1) + { + const int sz=500; + ctx->varValueStore_left = sz; + ctx->varValueStore = (EEL_F *)newCtxDataBlock((int)sizeof(EEL_F)*sz,8); + } + if (ctx->varValueStore) + { + int listsz = EEL_GROWBUF_GET_SIZE(&ctx->varNameList); + size_t l = strlen(name); + varNameRec *vh; + if (l > NSEEL_MAX_VARIABLE_NAMELEN) l = NSEEL_MAX_VARIABLE_NAMELEN; + vh = (varNameRec*) newCtxDataBlock( (int) (sizeof(varNameRec) + l),8); + if (!vh || EEL_GROWBUF_RESIZE(&ctx->varNameList, (listsz+1))) return NULL; // alloc fail + + (vh->value = ctx->varValueStore++)[0]=0.0; + ctx->varValueStore_left--; + + vh->refcnt=1; + vh->isreg=isReg; + memcpy(vh->str,name,l); + vh->str[l] = 0; + if (namePtrOut) *namePtrOut = vh->str; + + if (slot < listsz) + { + memmove(EEL_GROWBUF_GET(&ctx->varNameList) + slot+1, + EEL_GROWBUF_GET(&ctx->varNameList) + slot, (listsz - slot) * sizeof(EEL_GROWBUF_GET(&ctx->varNameList)[0])); + } + EEL_GROWBUF_GET(&ctx->varNameList)[slot] = vh; + + return vh->value; + } + return NULL; +} + + +//------------------------------------------------------------------------------ + +void NSEEL_VM_enumallvars(NSEEL_VMCTX ctx, int (*func)(const char *name, EEL_F *val, void *ctx), void *userctx) +{ + compileContext *tctx = (compileContext *) ctx; + int ni; + varNameRec **rd; + if (!tctx) return; + + ni = EEL_GROWBUF_GET_SIZE(&tctx->varNameList); + rd = EEL_GROWBUF_GET(&tctx->varNameList); + while (ni--) + { + if (!func(rd[0]->str,rd[0]->value,userctx)) break; + rd++; + } +} + + +//------------------------------------------------------------------------------ +EEL_F *NSEEL_VM_regvar(NSEEL_VMCTX _ctx, const char *var) +{ + compileContext *ctx = (compileContext *)_ctx; + if (!ctx) return 0; + + if (!strnicmp(var,"reg",3) && strlen(var) == 5 && isdigit(var[3]) && isdigit(var[4])) + { + EEL_F *a=get_global_var(ctx,var,1); + if (a) return a; + } + + return nseel_int_register_var(ctx,var,1,NULL); +} + +EEL_F *NSEEL_VM_getvar(NSEEL_VMCTX _ctx, const char *var) +{ + compileContext *ctx = (compileContext *)_ctx; + if (!ctx) return 0; + + if (!strnicmp(var,"reg",3) && strlen(var) == 5 && isdigit(var[3]) && isdigit(var[4])) + { + EEL_F *a=get_global_var(ctx,var,0); + if (a) return a; + } + + return nseel_int_register_var(ctx,var,-1,NULL); +} + +int NSEEL_VM_get_var_refcnt(NSEEL_VMCTX _ctx, const char *name) +{ + compileContext *ctx = (compileContext *)_ctx; + int slot,match; + if (!ctx) return -1; + slot = vartable_lowerbound(ctx,name, &match); + return match ? EEL_GROWBUF_GET(&ctx->varNameList)[slot]->refcnt : -1; +} + + + + +opcodeRec *nseel_createFunctionByName(compileContext *ctx, const char *name, int np, opcodeRec *code1, opcodeRec *code2, opcodeRec *code3) +{ + int chkamt=0; + functionType *f=nseel_getFunctionByName(ctx,name,&chkamt); + if (f) while (chkamt-->=0) + { + if ((f->nParams&FUNCTIONTYPE_PARAMETERCOUNTMASK) == np) + { + opcodeRec *o=newOpCode(ctx,NULL, np==3?OPCODETYPE_FUNC3:np==2?OPCODETYPE_FUNC2:OPCODETYPE_FUNC1); + if (o) + { + o->fntype = FUNCTYPE_FUNCTIONTYPEREC; + o->fn = f; + o->parms.parms[0]=code1; + o->parms.parms[1]=code2; + o->parms.parms[2]=code3; + } + return o; + } + f++; + if (stricmp(f->name,name)) break; + } + return NULL; +} + + + + +//------------------------------------------------------------------------------ +opcodeRec *nseel_translate(compileContext *ctx, const char *tmp, size_t tmplen) // tmplen 0 = null term +{ + // this depends on the string being nul terminated eventually, tmplen is used more as a hint than anything else + if ((tmp[0] == '0' || tmp[0] == '$') && toupper(tmp[1])=='X') + { + char *p; + return nseel_createCompiledValue(ctx,(EEL_F)strtoul(tmp+2,&p,16)); + } + else if (tmp[0] == '$') + { + if (tmp[1] == '~') + { + char *p=(char*)tmp+2; + unsigned int v=strtoul(tmp+2,&p,10); + if (v>53) v=53; + return nseel_createCompiledValue(ctx,(EEL_F)((((WDL_INT64)1) << v) - 1)); + } + else if (!tmplen ? !stricmp(tmp,"$E") : (tmplen == 2 && !strnicmp(tmp,"$E",2))) + return nseel_createCompiledValue(ctx,(EEL_F)2.71828183); + else if (!tmplen ? !stricmp(tmp, "$PI") : (tmplen == 3 && !strnicmp(tmp, "$PI", 3))) + return nseel_createCompiledValue(ctx,(EEL_F)3.141592653589793); + else if (!tmplen ? !stricmp(tmp, "$PHI") : (tmplen == 4 && !strnicmp(tmp, "$PHI", 4))) + return nseel_createCompiledValue(ctx,(EEL_F)1.61803399); + else if ((!tmplen || tmplen == 4) && tmp[1] == '\'' && tmp[2] && tmp[3] == '\'') + return nseel_createCompiledValue(ctx,(EEL_F)tmp[2]); + else return NULL; + } + else if (tmp[0] == '\'') + { + char b[64]; + int x,sz; + unsigned int rv=0; + + if (!tmplen) // nul terminated tmplen, calculate a workable length + { + // faster than strlen(tmp) if tmp is large, we'll never need more than ~18 chars anyway + while (tmplen < 32 && tmp[tmplen]) tmplen++; + } + + sz = tmplen > 0 ? nseel_filter_escaped_string(b,sizeof(b),tmp+1, tmplen - 1, '\'') : 0; + + if (sz > 4) + { + if (ctx->last_error_string[0]) lstrcatn(ctx->last_error_string, ", ", sizeof(ctx->last_error_string)); + snprintf_append(ctx->last_error_string,sizeof(ctx->last_error_string),"multi-byte character '%.5s...' too long",b); + return NULL; // do not allow 'xyzxy', limit to 4 bytes + } + + for (x=0;x<sz;x++) rv = (rv<<8) + ((unsigned char*)b)[x]; + return nseel_createCompiledValue(ctx,(EEL_F)rv); + } + else if (tmp[0] == '#') + { + char buf[2048]; + if (!tmplen) while (tmplen < sizeof(buf)-1 && tmp[tmplen]) tmplen++; + else if (tmplen > sizeof(buf)-1) tmplen = sizeof(buf)-1; + memcpy(buf,tmp,tmplen); + buf[tmplen]=0; + if (ctx->onNamedString) + { + if (tmplen>0 && buf[1]&&ctx->function_curName) + { + int err=0; + opcodeRec *r = nseel_resolve_named_symbol(ctx,nseel_createCompiledValuePtr(ctx,NULL,buf),-1, &err); + if (r) + { + if (r->opcodeType!=OPCODETYPE_VALUE_FROM_NAMESPACENAME) + { + r->opcodeType = OPCODETYPE_DIRECTVALUE; + r->parms.dv.directValue = ctx->onNamedString(ctx->caller_this,buf+1); + r->parms.dv.valuePtr=NULL; + } + return r; + } + if (err) return NULL; + } + + // if not namespaced symbol, return directly + if (!buf[1]) + { + opcodeRec *r=newOpCode(ctx,NULL,OPCODETYPE_DIRECTVALUE_TEMPSTRING); + if (r) r->parms.dv.directValue = -10000.0; + return r; + } + return nseel_createCompiledValue(ctx,ctx->onNamedString(ctx->caller_this,buf+1)); + } + } + return nseel_createCompiledValue(ctx,(EEL_F)atof(tmp)); +} + +void NSEEL_VM_set_var_resolver(NSEEL_VMCTX _ctx, EEL_F *(*res)(void *userctx, const char *name), void *userctx) +{ + compileContext *ctx = (compileContext *)_ctx; + if (ctx) + { + ctx->getVariable = res; + ctx->getVariable_userctx = userctx; + } +} + + +#if defined(__ppc__) || defined(EEL_TARGET_PORTABLE) + // blank stubs + void eel_setfp_round() { } + void eel_setfp_trunc() { } + void eel_enterfp(int s[2]) {} + void eel_leavefp(int s[2]) {} +#endif diff --git a/Src/ns-eel2/nseel-eval.c b/Src/ns-eel2/nseel-eval.c new file mode 100644 index 00000000..f4f6136c --- /dev/null +++ b/Src/ns-eel2/nseel-eval.c @@ -0,0 +1,447 @@ +/* + Expression Evaluator Library (NS-EEL) v2 + Copyright (C) 2004-2013 Cockos Incorporated + Copyright (C) 1999-2003 Nullsoft, Inc. + + nseel-eval.c + + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any damages + arising from the use of this software. + + Permission is granted to anyone to use this software for any purpose, + including commercial applications, and to alter it and redistribute it + freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. + 2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. + 3. This notice may not be removed or altered from any source distribution. +*/ + +#include <string.h> +#include <ctype.h> +#include "ns-eel-int.h" +#include "wdlcstring.h" + + +static const char *nseel_skip_space_and_comments(const char *p, const char *endptr) +{ + for (;;) + { + while (p < endptr && isspace(p[0])) p++; + if (p >= endptr-1 || *p != '/') return p; + + if (p[1]=='/') + { + while (p < endptr && *p != '\r' && *p != '\n') p++; + } + else if (p[1] == '*') + { + p+=2; + while (p < endptr-1 && (p[0] != '*' || p[1] != '/')) p++; + p+=2; + if (p>=endptr) return endptr; + } + else return p; + } +} + +// removes any escaped characters, also will convert pairs delim_char into single delim_chars +int nseel_filter_escaped_string(char *outbuf, int outbuf_sz, const char *rdptr, size_t rdptr_size, char delim_char) +{ + int outpos = 0; + const char *rdptr_end = rdptr + rdptr_size; + while (rdptr < rdptr_end && outpos < outbuf_sz-1) + { + char thisc=*rdptr; + if (thisc == '\\' && rdptr < rdptr_end-1) + { + const char nc = rdptr[1]; + if (nc == 'r' || nc == 'R') { thisc = '\r'; } + else if (nc == 'n' || nc == 'N') { thisc = '\n'; } + else if (nc == 't' || nc == 'T') { thisc = '\t'; } + else if (nc == 'b' || nc == 'B') { thisc = '\b'; } + else if ((nc >= '0' && nc <= '9') || nc == 'x' || nc == 'X') + { + unsigned char c=0; + char base_shift = 3; + char num_top = '7'; + + rdptr++; // skip backslash + if (nc > '9') // implies xX + { + base_shift = 4; + num_top = '9'; + rdptr ++; // skip x + } + + while (rdptr < rdptr_end) + { + char tc=*rdptr; + if (tc >= '0' && tc <= num_top) + { + c = (c<<base_shift) + tc - '0'; + } + else if (base_shift==4) + { + if (tc >= 'a' && tc <= 'f') + { + c = (c<<base_shift) + (tc - 'a' + 10); + } + else if (tc >= 'A' && tc <= 'F') + { + c = (c<<base_shift) + (tc - 'A' + 10); + } + else break; + } + else break; + + rdptr++; + } + outbuf[outpos++] = (char)c; + continue; + } + else // \c where c is an unknown character drops the backslash -- works for \, ', ", etc + { + thisc = nc; + } + rdptr+=2; + } + else + { + if (thisc == delim_char) break; + rdptr++; + } + outbuf[outpos++] = thisc; + } + outbuf[outpos]=0; + return outpos; +} + +int nseel_stringsegments_tobuf(char *bufOut, int bufout_sz, struct eelStringSegmentRec *list) // call with NULL to calculate size, or non-null to generate to buffer (returning size used) +{ + int pos=0; + while (list) + { + if (!bufOut) + { + pos += list->str_len; + } + else if (list->str_len > 1) + { + if (pos >= bufout_sz) break; + pos += nseel_filter_escaped_string(bufOut + pos, bufout_sz-pos, list->str_start+1, list->str_len-1, list->str_start[0]); + } + list = list->_next; + } + return pos; +} + + + +// state can be NULL, it will be set if finished with unterminated thing: 1 for multiline comment, ' or " for string +const char *nseel_simple_tokenizer(const char **ptr, const char *endptr, int *lenOut, int *state) +{ + const char *p = *ptr; + const char *rv = p; + + if (state) // if state set, returns comments as tokens + { + if (*state == 1) goto in_comment; + + #ifndef NSEEL_EEL1_COMPAT_MODE + if (*state == '\'' || *state == '\"') + { + delim = (char)*state; + goto in_string; + } + #endif + + // skip any whitespace + while (p < endptr && isspace(p[0])) p++; + } + else + { + // state not passed, skip comments (do not return them as tokens) + p = nseel_skip_space_and_comments(p,endptr); + } + + if (p >= endptr) + { + *ptr = endptr; + *lenOut = 0; + return NULL; + } + + rv=p; + + if (*p == '$' && p+3 < endptr && p[1] == '\'' && p[3] == '\'') + { + p+=4; + } + else if (state && *p == '/' && p < endptr-1 && (p[1] == '/' || p[1] == '*')) + { + if (p[1] == '/') + { + while (p < endptr && *p != '\r' && *p != '\n') p++; // advance to end of line + } + else + { + if (state) *state=1; + p+=2; +in_comment: + while (p < endptr) + { + const char c = *p++; + if (c == '*' && p < endptr && *p == '/') + { + p++; + if (state) *state=0; + break; + } + } + + } + } + else if (isalnum(*p) || *p == '_' || *p == '#' || *p == '$') + { + if (*p == '$' && p < endptr-1 && p[1] == '~') p++; + p++; + while (p < endptr && (isalnum(*p) || *p == '_' || *p == '.')) p++; + } +#ifndef NSEEL_EEL1_COMPAT_MODE + else if (*p == '\'' || *p == '\"') + { + delim = *p++; + if (state) *state=delim; +in_string: + + while (p < endptr) + { + const char c = *p++; + if (p < endptr && c == '\\') p++; // skip escaped characters + else if (c == delim) + { + if (state) *state=0; + break; + } + } + } +#endif + else + { + p++; + } + *ptr = p; + *lenOut = (int) (p - rv); + return p>rv ? rv : NULL; +} + + + +#ifdef NSEEL_SUPER_MINIMAL_LEXER + + int nseellex(opcodeRec **output, YYLTYPE * yylloc_param, compileContext *scctx) + { + int rv=0,toklen=0; + const char *rdptr = scctx->rdbuf; + const char *endptr = scctx->rdbuf_end; + const char *tok = nseel_simple_tokenizer(&rdptr,endptr,&toklen,NULL); + *output = 0; + if (tok) + { + rv = tok[0]; + if (rv == '$') + { + if (rdptr != tok+1) + { + *output = nseel_translate(scctx,tok,rdptr-tok); + if (*output) rv=VALUE; + } + } +#ifndef NSEEL_EEL1_COMPAT_MODE + else if (rv == '#' && scctx->onNamedString) + { + *output = nseel_translate(scctx,tok,rdptr-tok); + if (*output) rv=STRING_IDENTIFIER; + } + else if (rv == '\'') + { + if (toklen > 1 && tok[toklen-1] == '\'') + { + *output = nseel_translate(scctx, tok, toklen); + if (*output) rv = VALUE; + } + else scctx->gotEndOfInput|=8; + } + else if (rv == '\"' && scctx->onString) + { + if (toklen > 1 && tok[toklen-1] == '\"') + { + *output = (opcodeRec *)nseel_createStringSegmentRec(scctx,tok,toklen); + if (*output) rv = STRING_LITERAL; + } + else scctx->gotEndOfInput|=16; + } +#endif + else if (isalpha(rv) || rv == '_') + { + // toklen already valid + char buf[NSEEL_MAX_VARIABLE_NAMELEN*2]; + if (toklen > sizeof(buf) - 1) toklen=sizeof(buf) - 1; + memcpy(buf,tok,toklen); + buf[toklen]=0; + *output = nseel_createCompiledValuePtr(scctx, NULL, buf); + if (*output) rv = IDENTIFIER; + } + else if ((rv >= '0' && rv <= '9') || (rv == '.' && (rdptr < endptr && rdptr[0] >= '0' && rdptr[0] <= '9'))) + { + if (rv == '0' && rdptr < endptr && (rdptr[0] == 'x' || rdptr[0] == 'X')) + { + rdptr++; + while (rdptr < endptr && (rv=rdptr[0]) && ((rv>='0' && rv<='9') || (rv>='a' && rv<='f') || (rv>='A' && rv<='F'))) rdptr++; + } + else + { + int pcnt=rv == '.'; + while (rdptr < endptr && (rv=rdptr[0]) && ((rv>='0' && rv<='9') || (rv == '.' && !pcnt++))) rdptr++; + } + *output = nseel_translate(scctx,tok,rdptr-tok); + if (*output) rv=VALUE; + } + else if (rv == '<') + { + const char nc=*rdptr; + if (nc == '<') + { + rdptr++; + rv=TOKEN_SHL; + } + else if (nc == '=') + { + rdptr++; + rv=TOKEN_LTE; + } + } + else if (rv == '>') + { + const char nc=*rdptr; + if (nc == '>') + { + rdptr++; + rv=TOKEN_SHR; + } + else if (nc == '=') + { + rdptr++; + rv=TOKEN_GTE; + } + } + else if (rv == '&' && *rdptr == '&') + { + rdptr++; + rv = TOKEN_LOGICAL_AND; + } + else if (rv == '|' && *rdptr == '|') + { + rdptr++; + rv = TOKEN_LOGICAL_OR; + } + else if (*rdptr == '=') + { + switch (rv) + { + case '+': rv=TOKEN_ADD_OP; rdptr++; break; + case '-': rv=TOKEN_SUB_OP; rdptr++; break; + case '%': rv=TOKEN_MOD_OP; rdptr++; break; + case '|': rv=TOKEN_OR_OP; rdptr++; break; + case '&': rv=TOKEN_AND_OP; rdptr++; break; + case '~': rv=TOKEN_XOR_OP; rdptr++; break; + case '/': rv=TOKEN_DIV_OP; rdptr++; break; + case '*': rv=TOKEN_MUL_OP; rdptr++; break; + case '^': rv=TOKEN_POW_OP; rdptr++; break; + case '!': + rdptr++; + if (rdptr < endptr && *rdptr == '=') + { + rdptr++; + rv=TOKEN_NE_EXACT; + } + else + rv=TOKEN_NE; + break; + case '=': + rdptr++; + if (rdptr < endptr && *rdptr == '=') + { + rdptr++; + rv=TOKEN_EQ_EXACT; + } + else + rv=TOKEN_EQ; + break; + } + } + } + + scctx->rdbuf = rdptr; + yylloc_param->first_column = (int)(tok - scctx->rdbuf_start); + return rv; + } + + + void nseelerror(YYLTYPE *pos,compileContext *ctx, const char *str) + { + ctx->errVar=pos->first_column>0?pos->first_column:(int)(ctx->rdbuf_end - ctx->rdbuf_start); + } + + +#else + + int nseel_gets(compileContext *ctx, char *buf, size_t sz) + { + int n=0; + const char *endptr = ctx->rdbuf_end; + const char *rdptr = ctx->rdbuf; + if (!rdptr) return 0; + + while (n < sz && rdptr < endptr) buf[n++] = *rdptr++; + ctx->rdbuf=rdptr; + return n; + + } + + + //#define EEL_TRACE_LEX + + #ifdef EEL_TRACE_LEX + #define nseellex nseellex2 + + #endif + #include "lex.nseel.c" + + #ifdef EEL_TRACE_LEX + + #undef nseellex + + int nseellex(YYSTYPE * yylval_param, YYLTYPE * yylloc_param , yyscan_t yyscanner) + { + int a=nseellex2(yylval_param,yylloc_param,yyscanner); + + char buf[512]; + sprintf(buf,"tok: %c (%d)\n",a,a); + OutputDebugString(buf); + return a; + } + #endif//EEL_TRACE_LEX + + + void nseelerror(YYLTYPE *pos,compileContext *ctx, const char *str) + { + ctx->errVar=pos->first_column>0?pos->first_column:(int)(ctx->rdbuf_end - ctx->rdbuf_start); + } +#endif // !NSEEL_SUPER_MINIMAL_LEXER diff --git a/Src/ns-eel2/nseel-lextab.c b/Src/ns-eel2/nseel-lextab.c new file mode 100644 index 00000000..6138b65d --- /dev/null +++ b/Src/ns-eel2/nseel-lextab.c @@ -0,0 +1 @@ +// no longer used
\ No newline at end of file diff --git a/Src/ns-eel2/nseel-ram.c b/Src/ns-eel2/nseel-ram.c new file mode 100644 index 00000000..2062fed4 --- /dev/null +++ b/Src/ns-eel2/nseel-ram.c @@ -0,0 +1,463 @@ +/* + Expression Evaluator Library (NS-EEL) v2 + Copyright (C) 2004-2013 Cockos Incorporated + Copyright (C) 1999-2003 Nullsoft, Inc. + + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any damages + arising from the use of this software. + + Permission is granted to anyone to use this software for any purpose, + including commercial applications, and to alter it and redistribute it + freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. + 2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. + 3. This notice may not be removed or altered from any source distribution. +*/ + +#include "ns-eel.h" +#include "ns-eel-int.h" +#include <math.h> +#include <stdio.h> +#include <string.h> +#include <stdlib.h> + + +#ifdef _WIN32 +#include <malloc.h> +#ifdef _MSC_VER +#define inline __inline +#endif + +#endif + +unsigned int NSEEL_RAM_limitmem=0; +unsigned int NSEEL_RAM_memused=0; +int NSEEL_RAM_memused_errors=0; + + + +int NSEEL_VM_wantfreeRAM(NSEEL_VMCTX ctx) +{ + if (ctx) + { + compileContext *c=(compileContext*)ctx; + if (c->ram_state.needfree) + return 1; + } + return 0; +} + +void NSEEL_VM_freeRAMIfCodeRequested(NSEEL_VMCTX ctx) // check to see if our free flag was set +{ + if (ctx) + { + compileContext *c=(compileContext*)ctx; + if (c->ram_state.needfree) + { + NSEEL_HOSTSTUB_EnterMutex(); + { + INT_PTR startpos=((INT_PTR)c->ram_state.needfree)-1; + EEL_F **blocks = c->ram_state.blocks; + INT_PTR pos=0; + int x; + for (x = 0; x < NSEEL_RAM_BLOCKS; x ++) + { + if (pos >= startpos) + { + if (blocks[x]) + { + if (NSEEL_RAM_memused >= sizeof(EEL_F) * NSEEL_RAM_ITEMSPERBLOCK) + NSEEL_RAM_memused -= sizeof(EEL_F) * NSEEL_RAM_ITEMSPERBLOCK; + else NSEEL_RAM_memused_errors++; + free(blocks[x]); + blocks[x]=0; + } + } + pos+=NSEEL_RAM_ITEMSPERBLOCK; + } + c->ram_state.needfree=0; + } + NSEEL_HOSTSTUB_LeaveMutex(); + } + + } +} + +EEL_F nseel_ramalloc_onfail; +EEL_F * volatile nseel_gmembuf_default; + + +void *(*nseel_gmem_calloc)(size_t a, size_t b); + +EEL_F * NSEEL_CGEN_CALL __NSEEL_RAMAllocGMEM(EEL_F ***blocks, unsigned int w) +{ + if (blocks) + { + EEL_F **pblocks=*blocks; + + if (w < NSEEL_RAM_BLOCKS*NSEEL_RAM_ITEMSPERBLOCK) + { + const unsigned int whichblock = w/NSEEL_RAM_ITEMSPERBLOCK; + EEL_F *p=NULL; + if (!pblocks || !(p=pblocks[whichblock])) + { + NSEEL_HOSTSTUB_EnterMutex(); + if (!nseel_gmem_calloc) nseel_gmem_calloc=calloc; + + if (!(pblocks=*blocks)) pblocks = *blocks = (EEL_F **)nseel_gmem_calloc(sizeof(EEL_F *),NSEEL_RAM_BLOCKS); + else p = pblocks[whichblock]; + + if (!p && pblocks) + { + p=pblocks[whichblock]=(EEL_F *)nseel_gmem_calloc(sizeof(EEL_F),NSEEL_RAM_ITEMSPERBLOCK); + } + NSEEL_HOSTSTUB_LeaveMutex(); + } + if (p) return p + (w&(NSEEL_RAM_ITEMSPERBLOCK-1)); + } + return &nseel_ramalloc_onfail; + } + + if (!nseel_gmembuf_default) + { + NSEEL_HOSTSTUB_EnterMutex(); + if (!nseel_gmembuf_default) nseel_gmembuf_default=(EEL_F*)calloc(sizeof(EEL_F),NSEEL_SHARED_GRAM_SIZE); + NSEEL_HOSTSTUB_LeaveMutex(); + if (!nseel_gmembuf_default) return &nseel_ramalloc_onfail; + } + + return nseel_gmembuf_default+(((unsigned int)w)&((NSEEL_SHARED_GRAM_SIZE)-1)); +} + + +EEL_F * NSEEL_CGEN_CALL __NSEEL_RAMAlloc(EEL_F **pblocks, unsigned int w) +{ +// fprintf(stderr,"got request at %d, %d\n",w/NSEEL_RAM_ITEMSPERBLOCK, w&(NSEEL_RAM_ITEMSPERBLOCK-1)); + if (w < NSEEL_RAM_BLOCKS*NSEEL_RAM_ITEMSPERBLOCK) + { + unsigned int whichblock = w/NSEEL_RAM_ITEMSPERBLOCK; + EEL_F *p=pblocks[whichblock]; + if (!p && whichblock < ((unsigned int *)pblocks)[-3]) // pblocks -1/-2 are closefact, -3 is maxblocks + { + NSEEL_HOSTSTUB_EnterMutex(); + + if (!(p=pblocks[whichblock])) + { + + const int msize=sizeof(EEL_F) * NSEEL_RAM_ITEMSPERBLOCK; + if (!NSEEL_RAM_limitmem || NSEEL_RAM_memused+msize < NSEEL_RAM_limitmem) + { + p=pblocks[whichblock]=(EEL_F *)calloc(sizeof(EEL_F),NSEEL_RAM_ITEMSPERBLOCK); + if (p) NSEEL_RAM_memused+=msize; + } + } + NSEEL_HOSTSTUB_LeaveMutex(); + } + if (p) return p + (w&(NSEEL_RAM_ITEMSPERBLOCK-1)); + } +// fprintf(stderr,"ret 0\n"); + return &nseel_ramalloc_onfail; +} + + +EEL_F * NSEEL_CGEN_CALL __NSEEL_RAM_MemFree(void *blocks, EEL_F *which) +{ + // blocks points to ram_state.blocks, so back it up past closefact and maxblocks to needfree + int *flag = (int *)((char *)blocks - sizeof(double) - 2*sizeof(int)); + int d=(int)(*which); + if (d < 0) d=0; + if (d < flag[1]*NSEEL_RAM_ITEMSPERBLOCK) flag[0]=1+d; + return which; +} + +EEL_F * NSEEL_CGEN_CALL __NSEEL_RAM_MemTop(void *blocks, EEL_F *which) +{ + // blocks points to ram_state.blocks, so back it up past closefact to maxblocks + const int *flag = (int *)((char *)blocks - sizeof(double) - sizeof(int)); + *which = flag[0]*NSEEL_RAM_ITEMSPERBLOCK; + return which; +} + + + + + + +EEL_F * NSEEL_CGEN_CALL __NSEEL_RAM_MemCpy(EEL_F **blocks,EEL_F *dest, EEL_F *src, EEL_F *lenptr) +{ + const int mem_size=NSEEL_RAM_BLOCKS*NSEEL_RAM_ITEMSPERBLOCK; + int dest_offs = (int)(*dest + 0.0001); + int src_offs = (int)(*src + 0.0001); + int len = (int)(*lenptr + 0.0001); + int want_mmove=0; + + // trim to front + if (src_offs<0) + { + len += src_offs; + dest_offs -= src_offs; + src_offs=0; + } + if (dest_offs<0) + { + len += dest_offs; + src_offs -= dest_offs; + dest_offs=0; + } + if (src_offs + len > mem_size) len = mem_size-src_offs; + if (dest_offs + len > mem_size) len = mem_size-dest_offs; + + if (src_offs == dest_offs || len < 1) return dest; + + if (src_offs < dest_offs && src_offs+len > dest_offs) + { + // if src_offs < dest_offs and overlapping, must copy right to left + if ((dest_offs - src_offs) < NSEEL_RAM_ITEMSPERBLOCK) want_mmove = 1; + src_offs += len; + dest_offs += len; + while (len > 0) + { + const int maxdlen=((dest_offs-1)&(NSEEL_RAM_ITEMSPERBLOCK-1)) + 1; + const int maxslen=((src_offs-1)&(NSEEL_RAM_ITEMSPERBLOCK-1)) + 1; + int copy_len = len; + EEL_F *srcptr,*destptr; + + if (copy_len > maxdlen) copy_len=maxdlen; + if (copy_len > maxslen) copy_len=maxslen; + + srcptr = __NSEEL_RAMAlloc(blocks,src_offs - copy_len); + destptr = __NSEEL_RAMAlloc(blocks,dest_offs - copy_len); + if (srcptr==&nseel_ramalloc_onfail || destptr==&nseel_ramalloc_onfail) break; + + if (want_mmove) memmove(destptr,srcptr,sizeof(EEL_F)*copy_len); + else memcpy(destptr,srcptr,sizeof(EEL_F)*copy_len); + src_offs-=copy_len; + dest_offs-=copy_len; + len-=copy_len; + } + return dest; + } + + if (dest_offs < src_offs && dest_offs+len > src_offs) + { + // if dest_offs < src_offs and overlapping, and less than NSEEL_RAM_ITEMSPERBLOCK apart, use memmove() + if ((src_offs-dest_offs) < NSEEL_RAM_ITEMSPERBLOCK) want_mmove = 1; + } + + while (len > 0) + { + const int maxdlen=NSEEL_RAM_ITEMSPERBLOCK - (dest_offs&(NSEEL_RAM_ITEMSPERBLOCK-1)); + const int maxslen=NSEEL_RAM_ITEMSPERBLOCK - (src_offs&(NSEEL_RAM_ITEMSPERBLOCK-1)); + int copy_len = len; + EEL_F *srcptr,*destptr; + + if (copy_len > maxdlen) copy_len=maxdlen; + if (copy_len > maxslen) copy_len=maxslen; + + srcptr = __NSEEL_RAMAlloc(blocks,src_offs); + destptr = __NSEEL_RAMAlloc(blocks,dest_offs); + if (srcptr==&nseel_ramalloc_onfail || destptr==&nseel_ramalloc_onfail) break; + + if (want_mmove) memmove(destptr,srcptr,sizeof(EEL_F)*copy_len); + else memcpy(destptr,srcptr,sizeof(EEL_F)*copy_len); + src_offs+=copy_len; + dest_offs+=copy_len; + len-=copy_len; + } + return dest; +} + +EEL_F * NSEEL_CGEN_CALL __NSEEL_RAM_MemSet(EEL_F **blocks,EEL_F *dest, EEL_F *v, EEL_F *lenptr) +{ + int offs = (int)(*dest + 0.0001); + int len = (int)(*lenptr + 0.0001); + EEL_F t; + if (offs<0) + { + len += offs; + offs=0; + } + if (offs >= NSEEL_RAM_BLOCKS*NSEEL_RAM_ITEMSPERBLOCK) return dest; + + if (offs+len > NSEEL_RAM_BLOCKS*NSEEL_RAM_ITEMSPERBLOCK) len = NSEEL_RAM_BLOCKS*NSEEL_RAM_ITEMSPERBLOCK - offs; + + if (len < 1) return dest; + + + t=*v; // set value + +// int lastBlock=-1; + while (len > 0) + { + int lcnt; + EEL_F *ptr=__NSEEL_RAMAlloc(blocks,offs); + if (ptr==&nseel_ramalloc_onfail) break; + + lcnt=NSEEL_RAM_ITEMSPERBLOCK-(offs&(NSEEL_RAM_ITEMSPERBLOCK-1)); + if (lcnt > len) lcnt=len; + + len -= lcnt; + offs += lcnt; + + while (lcnt--) + { + *ptr++=t; + } + } + return dest; +} + + +static inline int __getset_values(EEL_F **blocks, int isset, int len, EEL_F **parms) +{ + int offs, lout=0; + unsigned int pageidx, sub_offs; + if (--len < 1) return 0; + offs = (int)(parms++[0][0] + 0.0001); + + if (offs<=0) + { + len += offs; + parms -= offs; + offs=0; + pageidx=sub_offs=0; + if (len<1) return 0; + } + else + { + sub_offs = ((unsigned int)offs) & (NSEEL_RAM_ITEMSPERBLOCK-1); + pageidx = ((unsigned int)offs)>>NSEEL_RAM_ITEMSPERBLOCK_LOG2; + if (pageidx>=NSEEL_RAM_BLOCKS) return 0; + } + + for (;;) + { + int lcnt=NSEEL_RAM_ITEMSPERBLOCK-sub_offs; + EEL_F *ptr=blocks[pageidx]; + if (!ptr) + { + ptr = __NSEEL_RAMAlloc(blocks,offs + lout); + if (ptr==&nseel_ramalloc_onfail) return lout; + } + else + { + ptr += sub_offs; + } + + if (lcnt >= len) + { + // this page satisfies the request (normal behavior) + lout += len; + if (isset) while (len--) *ptr++=parms++[0][0]; + else while (len--) parms++[0][0] = *ptr++; + return lout; + } + + // crossing a page boundary + len -= lcnt; + lout += lcnt; + if (isset) while (lcnt--) *ptr++=parms++[0][0]; + else while (lcnt--) parms++[0][0] = *ptr++; + + if (len <= 0 || ++pageidx >= NSEEL_RAM_BLOCKS) return lout; + sub_offs=0; + } +} + +EEL_F NSEEL_CGEN_CALL __NSEEL_RAM_Mem_SetValues(EEL_F **blocks, INT_PTR np, EEL_F **parms) +{ + return __getset_values(blocks,1,(int)np,parms); +} + +EEL_F NSEEL_CGEN_CALL __NSEEL_RAM_Mem_GetValues(EEL_F **blocks, INT_PTR np, EEL_F **parms) +{ + return __getset_values(blocks,0,(int)np,parms); +} + +void NSEEL_VM_SetGRAM(NSEEL_VMCTX ctx, void **gram) +{ + if (ctx) + { + compileContext *c=(compileContext*)ctx; + c->gram_blocks = gram; + } +} + + +void NSEEL_VM_freeRAM(NSEEL_VMCTX ctx) +{ + if (ctx) + { + int x; + compileContext *c=(compileContext*)ctx; + EEL_F **blocks = c->ram_state.blocks; + for (x = 0; x < NSEEL_RAM_BLOCKS; x ++) + { + if (blocks[x]) + { + if (NSEEL_RAM_memused >= sizeof(EEL_F) * NSEEL_RAM_ITEMSPERBLOCK) + NSEEL_RAM_memused -= sizeof(EEL_F) * NSEEL_RAM_ITEMSPERBLOCK; + else NSEEL_RAM_memused_errors++; + free(blocks[x]); + blocks[x]=0; + } + } + c->ram_state.needfree=0; // no need to free anymore + } +} + +void NSEEL_VM_FreeGRAM(void **ufd) +{ + if (ufd[0]) + { + EEL_F **blocks = (EEL_F **)ufd[0]; + int x; + for (x = 0; x < NSEEL_RAM_BLOCKS; x ++) + { + if (blocks[x]) + { + if (NSEEL_RAM_memused >= sizeof(EEL_F) * NSEEL_RAM_ITEMSPERBLOCK) + NSEEL_RAM_memused -= sizeof(EEL_F) * NSEEL_RAM_ITEMSPERBLOCK; + else NSEEL_RAM_memused_errors++; + } + free(blocks[x]); + blocks[x]=0; + } + free(blocks); + ufd[0]=0; + } +} + +EEL_F *NSEEL_VM_getramptr(NSEEL_VMCTX ctx, unsigned int offs, int *validCount) +{ + EEL_F *d=__NSEEL_RAMAlloc(ctx ? ((compileContext*)ctx)->ram_state.blocks : 0,offs); + if (!d || d == &nseel_ramalloc_onfail) return NULL; + if (validCount) *validCount = NSEEL_RAM_ITEMSPERBLOCK - (offs%NSEEL_RAM_ITEMSPERBLOCK); + + return d; +} + +EEL_F *NSEEL_VM_getramptr_noalloc(NSEEL_VMCTX ctx, unsigned int offs, int *validCount) +{ + EEL_F *d; + compileContext *cc = (compileContext *)ctx; + + if (!cc || + offs >= NSEEL_RAM_ITEMSPERBLOCK*NSEEL_RAM_BLOCKS || + NULL == (d = cc->ram_state.blocks[offs/NSEEL_RAM_ITEMSPERBLOCK]) + ) + { + if (validCount) *validCount = 0; + return NULL; + } + + offs %= NSEEL_RAM_ITEMSPERBLOCK; + if (validCount) *validCount = NSEEL_RAM_ITEMSPERBLOCK - offs; + return d + offs; +} diff --git a/Src/ns-eel2/nseel-yylex.c b/Src/ns-eel2/nseel-yylex.c new file mode 100644 index 00000000..986b75af --- /dev/null +++ b/Src/ns-eel2/nseel-yylex.c @@ -0,0 +1,40 @@ +/* + Expression Evaluator Library (NS-EEL) + Copyright (C) 2004-2013 Cockos Incorporated + Copyright (C) 1999-2003 Nullsoft, Inc. + + nseel-yylex.c + + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any damages + arising from the use of this software. + + Permission is granted to anyone to use this software for any purpose, + including commercial applications, and to alter it and redistribute it + freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. + 2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. + 3. This notice may not be removed or altered from any source distribution. +*/ + + +#include "ns-eel-int.h" + + + +# define YYMALLOC malloc +# define YYFREE free + +int nseellex(void * yylval_param,void * yylloc_param ,void *yyscanner); +void nseelerror(void *pos,compileContext *ctx, const char *str); + +#include <stdlib.h> +#include <string.h> + +#include "y.tab.c" + diff --git a/Src/ns-eel2/wdlcstring.h b/Src/ns-eel2/wdlcstring.h new file mode 100644 index 00000000..71a248e6 --- /dev/null +++ b/Src/ns-eel2/wdlcstring.h @@ -0,0 +1,316 @@ +/* + WDL - wdlcstring.h + Copyright (C) 2005 and later, Cockos Incorporated + + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any damages + arising from the use of this software. + + Permission is granted to anyone to use this software for any purpose, + including commercial applications, and to alter it and redistribute it + freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. + 2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. + 3. This notice may not be removed or altered from any source distribution. + +*/ + +/* +C string manipulation utilities -- [v]snprintf for Win32, also snprintf_append, lstrcatn, etc + */ +#ifndef _WDL_CSTRING_H_ +#define _WDL_CSTRING_H_ + +#include <stdarg.h> +#include <stdio.h> +#include <ctype.h> + +#include "wdltypes.h" + +#ifdef _WDL_CSTRING_IMPL_ONLY_ + #ifdef _WDL_CSTRING_IF_ONLY_ + #undef _WDL_CSTRING_IF_ONLY_ + #endif + #define _WDL_CSTRING_PREFIX +#else + #define _WDL_CSTRING_PREFIX static WDL_STATICFUNC_UNUSED +#endif + + + +#if defined(_WIN32) && defined(_MSC_VER) + // provide snprintf()/vsnprintf() for win32 -- note that these have no way of knowing + // what the amount written was, code should(must) be written to not depend on this. + #ifdef snprintf + #undef snprintf + #endif + #define snprintf WDL_snprintf + + #ifdef vsnprintf + #undef vsnprintf + #endif + #define vsnprintf WDL_vsnprintf + +#endif // win32 snprintf/vsnprintf + +// use wdlcstring.h's lstrcpyn_safe rather than the real lstrcpyn. +#ifdef _WIN32 + #ifdef lstrcpyn + #undef lstrcpyn + #endif + #define lstrcpyn lstrcpyn_safe +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +#ifdef _WDL_CSTRING_IF_ONLY_ + + void lstrcpyn_safe(char *o, const char *in, INT_PTR count); + void lstrcatn(char *o, const char *in, INT_PTR count); + void WDL_VARARG_WARN(printf,3,4) snprintf_append(char *o, INT_PTR count, const char *format, ...); + void vsnprintf_append(char *o, INT_PTR count, const char *format, va_list va); + + const char *WDL_get_filepart(const char *str); // returns whole string if no dir chars + const char *WDL_get_fileext(const char *str); // returns ".ext" or end of string "" if no extension + char *WDL_remove_fileext(char *str); // returns pointer to "ext" if ".ext" was removed (zero-d dot), or NULL + char WDL_remove_filepart(char *str); // returns dir character that was zeroed, or 0 if new string is empty + int WDL_remove_trailing_dirchars(char *str); // returns trailing dirchar count removed, will not convert "/" into "" + size_t WDL_remove_trailing_crlf(char *str); // returns new length + + + #if defined(_WIN32) && defined(_MSC_VER) + void WDL_vsnprintf(char *o, size_t count, const char *format, va_list args); + void WDL_VARARG_WARN(printf,3,4) WDL_snprintf(char *o, size_t count, const char *format, ...); + #endif + + int WDL_strcmp_logical(const char *s1, const char *s2, int case_sensitive); +#else + + + #if defined(_WIN32) && defined(_MSC_VER) + + _WDL_CSTRING_PREFIX void WDL_vsnprintf(char *o, size_t count, const char *format, va_list args) + { + if (count>0) + { + int rv; + o[0]=0; + rv=_vsnprintf(o,count,format,args); // returns -1 if over, and does not null terminate, ugh + if (rv < 0 || rv>=(int)count-1) o[count-1]=0; + } + } + _WDL_CSTRING_PREFIX void WDL_VARARG_WARN(printf,3,4) WDL_snprintf(char *o, size_t count, const char *format, ...) + { + if (count>0) + { + int rv; + va_list va; + va_start(va,format); + o[0]=0; + rv=_vsnprintf(o,count,format,va); // returns -1 if over, and does not null terminate, ugh + va_end(va); + + if (rv < 0 || rv>=(int)count-1) o[count-1]=0; + } + } + #endif + + _WDL_CSTRING_PREFIX void lstrcpyn_safe(char *o, const char *in, INT_PTR count) + { + if (count>0) + { + while (--count>0 && *in) *o++ = *in++; + *o=0; + } + } + + _WDL_CSTRING_PREFIX void lstrcatn(char *o, const char *in, INT_PTR count) + { + if (count>0) + { + while (*o) { if (--count < 1) return; o++; } + while (--count>0 && *in) *o++ = *in++; + *o=0; + } + } + + _WDL_CSTRING_PREFIX const char *WDL_get_filepart(const char *str) // returns whole string if no dir chars + { + const char *p = str; + while (*p) p++; + while (p >= str && !WDL_IS_DIRCHAR(*p)) --p; + return p + 1; + } + _WDL_CSTRING_PREFIX const char *WDL_get_fileext(const char *str) // returns ".ext" or end of string "" if no extension + { + const char *p=str, *ep; + while (*p) p++; + ep = p; + while (p >= str && !WDL_IS_DIRCHAR(*p)) + { + if (*p == '.') return p; + --p; + } + return ep; + } + + _WDL_CSTRING_PREFIX char *WDL_remove_fileext(char *str) // returns pointer to "ext" if ".ext" was removed (zero-d dot), or NULL + { + char *p=str; + while (*p) p++; + while (p >= str && !WDL_IS_DIRCHAR(*p)) + { + if (*p == '.') + { + *p = 0; + return p+1; + } + --p; + } + return NULL; + } + + _WDL_CSTRING_PREFIX char WDL_remove_filepart(char *str) // returns dir character that was zeroed, or 0 if new string is empty + { + char *p=str; + while (*p) p++; + while (p >= str) + { + char c = *p; + if (WDL_IS_DIRCHAR(c)) + { + *p = 0; + return c; + } + --p; + } + str[0] = 0; + return 0; + } + + _WDL_CSTRING_PREFIX int WDL_remove_trailing_dirchars(char *str) // returns trailing dirchar count removed + { + int cnt = 0; + char *p=str; + while (*p) p++; + while (p > str+1 && WDL_IS_DIRCHAR(p[-1])) + { + cnt++; + p--; + } + *p = 0; + return cnt; + } + + _WDL_CSTRING_PREFIX size_t WDL_remove_trailing_crlf(char *str) // returns new length + { + char *p=str; + while (*p) p++; + while (p > str && (p[-1] == '\r' || p[-1] == '\n')) p--; + *p = 0; + return p-str; + } + + _WDL_CSTRING_PREFIX void WDL_VARARG_WARN(printf,3,4) snprintf_append(char *o, INT_PTR count, const char *format, ...) + { + if (count>0) + { + va_list va; + while (*o) { if (--count < 1) return; o++; } + va_start(va,format); + vsnprintf(o,count,format,va); + va_end(va); + } + } + + _WDL_CSTRING_PREFIX void vsnprintf_append(char *o, INT_PTR count, const char *format, va_list va) + { + if (count>0) + { + while (*o) { if (--count < 1) return; o++; } + vsnprintf(o,count,format,va); + } + } + + _WDL_CSTRING_PREFIX int WDL_strcmp_logical(const char *s1, const char *s2, int case_sensitive) + { + // also exists as WDL_LogicalSortStringKeyedArray::_cmpstr() + + char lastNonZeroChar=0; + // last matching character, updated if not 0. this allows us to track whether + // we are inside of a number with the same leading digits + + for (;;) + { + char c1=*s1++, c2=*s2++; + if (!c1) return c1-c2; + + if (c1!=c2) + { + if (c1 >= '0' && c1 <= '9' && c2 >= '0' && c2 <= '9') + { + int lzdiff=0, cnt=0; + if (lastNonZeroChar < '1' || lastNonZeroChar > '9') + { + while (c1 == '0') { c1=*s1++; lzdiff--; } + while (c2 == '0') { c2=*s2++; lzdiff++; } // lzdiff = lz2-lz1, more leading 0s = earlier in list + } + + for (;;) + { + if (c1 >= '0' && c1 <= '9') + { + if (c2 < '0' || c2 > '9') return 1; + + c1=s1[cnt]; + c2=s2[cnt++]; + } + else + { + if (c2 >= '0' && c2 <= '9') return -1; + break; + } + } + + s1--; + s2--; + + while (cnt--) + { + const int d = *s1++ - *s2++; + if (d) return d; + } + + if (lzdiff) return lzdiff; + } + else + { + if (!case_sensitive) + { + if (c1>='a' && c1<='z') c1+='A'-'a'; + if (c2>='a' && c2<='z') c2+='A'-'a'; + } + if (c1 != c2) return c1-c2; + } + } + else if (c1 != '0') lastNonZeroChar=c1; + } + } + +#endif + + +#ifdef __cplusplus +}; +#endif + +#undef _WDL_CSTRING_PREFIX + +#endif diff --git a/Src/ns-eel2/wdltypes.h b/Src/ns-eel2/wdltypes.h new file mode 100644 index 00000000..b839094d --- /dev/null +++ b/Src/ns-eel2/wdltypes.h @@ -0,0 +1,160 @@ +#ifndef _WDLTYPES_ +#define _WDLTYPES_ + +#ifdef _MSC_VER + +typedef __int64 WDL_INT64; +typedef unsigned __int64 WDL_UINT64; + +#else + +typedef long long WDL_INT64; +typedef unsigned long long WDL_UINT64; + +#endif + +#ifdef _MSC_VER + #define WDL_UINT64_CONST(x) (x##ui64) + #define WDL_INT64_CONST(x) (x##i64) +#else + #define WDL_UINT64_CONST(x) (x##ULL) + #define WDL_INT64_CONST(x) (x##LL) +#endif + + +#if !defined(_MSC_VER) || _MSC_VER > 1200 +#define WDL_DLGRET INT_PTR CALLBACK +#else +#define WDL_DLGRET BOOL CALLBACK +#endif + + +#ifdef _WIN32 +#include <windows.h> +#else +#include <stdint.h> +typedef intptr_t INT_PTR; +typedef uintptr_t UINT_PTR; +#endif + +#if defined(__ppc__) || !defined(__cplusplus) +typedef char WDL_bool; +#else +typedef bool WDL_bool; +#endif + +#ifndef GWLP_USERDATA +#define GWLP_USERDATA GWL_USERDATA +#define GWLP_WNDPROC GWL_WNDPROC +#define GWLP_HINSTANCE GWL_HINSTANCE +#define GWLP_HWNDPARENT GWL_HWNDPARENT +#define DWLP_USER DWL_USER +#define DWLP_DLGPROC DWL_DLGPROC +#define DWLP_MSGRESULT DWL_MSGRESULT +#define SetWindowLongPtr(a,b,c) SetWindowLong(a,b,c) +#define GetWindowLongPtr(a,b) GetWindowLong(a,b) +#define SetWindowLongPtrW(a,b,c) SetWindowLongW(a,b,c) +#define GetWindowLongPtrW(a,b) GetWindowLongW(a,b) +#define SetWindowLongPtrA(a,b,c) SetWindowLongA(a,b,c) +#define GetWindowLongPtrA(a,b) GetWindowLongA(a,b) + +#define GCLP_WNDPROC GCL_WNDPROC +#define GCLP_HICON GCL_HICON +#define GCLP_HICONSM GCL_HICONSM +#define SetClassLongPtr(a,b,c) SetClassLong(a,b,c) +#define GetClassLongPtr(a,b) GetClassLong(a,b) +#endif + + +#ifdef __GNUC__ +// for structures that contain doubles, or doubles in structures that are after stuff of questionable alignment (for OSX/linux) + #define WDL_FIXALIGN __attribute__ ((aligned (8))) +// usage: void func(int a, const char *fmt, ...) WDL_VARARG_WARN(printf,2,3); // note: if member function, this pointer is counted as well, so as member function that would be 3,4 + #define WDL_VARARG_WARN(x,n,s) __attribute__ ((format (x,n,s))) + #define WDL_STATICFUNC_UNUSED __attribute__((unused)) + +#else + #define WDL_FIXALIGN + #define WDL_VARARG_WARN(x,n,s) + #define WDL_STATICFUNC_UNUSED +#endif + +#ifndef WDL_WANT_NEW_EXCEPTIONS +#if defined(__cplusplus) +#include <new> +#define WDL_NEW (std::nothrow) +#endif +#else +#define WDL_NEW +#endif + + +#if !defined(max) && defined(WDL_DEFINE_MINMAX) +#define max(x,y) ((x)<(y)?(y):(x)) +#define min(x,y) ((x)<(y)?(x):(y)) +#endif + +#ifndef wdl_max +#define wdl_max(x,y) ((x)<(y)?(y):(x)) +#define wdl_min(x,y) ((x)<(y)?(x):(y)) +#define wdl_abs(x) ((x)<0 ? -(x) : (x)) +#endif + +#ifndef _WIN32 + #ifndef strnicmp + #define strnicmp(x,y,z) strncasecmp(x,y,z) + #endif + #ifndef stricmp + #define stricmp(x,y) strcasecmp(x,y) + #endif +#endif + +#ifdef WDL_BACKSLASHES_ARE_ORDINARY +#define WDL_IS_DIRCHAR(x) ((x) == '/') +#else +// for multi-platform applications it seems better to treat backslashes as directory separators even if it +// isn't supported by the underying system (for resolving filenames, etc) + #ifdef _WIN32 + #define WDL_IS_DIRCHAR(x) ((x) == '\\' || (x) == '/') + #else + #define WDL_IS_DIRCHAR(x) ((x) == '/' || (x) == '\\') + #endif +#endif + +#if defined(_WIN32) && !defined(WDL_BACKSLASHES_ARE_ORDINARY) +#define WDL_DIRCHAR '\\' +#define WDL_DIRCHAR_STR "\\" +#else +#define WDL_DIRCHAR '/' +#define WDL_DIRCHAR_STR "/" +#endif + +#if defined(_WIN32) || defined(__APPLE__) + // on __APPLE__ we should ideally check the filesystem for case-sensitivity, assuming a case-insensitive-only match + #define wdl_filename_cmp(x,y) stricmp(x,y) + #define wdl_filename_cmpn(x,y,n) strnicmp(x,y,n) +#else + #define wdl_filename_cmp(x,y) strcmp(x,y) + #define wdl_filename_cmpn(x,y,n) strncmp(x,y,n) +#endif + +#if defined(__GNUC__) || defined(__INTEL_COMPILER) + #define WDL_likely(x) (__builtin_expect(!!(x),1)) + #define WDL_unlikely(x) (__builtin_expect(!!(x),0)) +#else + #define WDL_likely(x) (!!(x)) + #define WDL_unlikely(x) (!!(x)) +#endif + +#if defined(_DEBUG) || defined(DEBUG) +#include <assert.h> +#define WDL_ASSERT(x) assert(x) +#define WDL_NORMALLY(x) (assert(x),1) +#define WDL_NOT_NORMALLY(x) (assert(!(x)),0) +#else +#define WDL_ASSERT(x) +#define WDL_NORMALLY(x) WDL_likely(x) +#define WDL_NOT_NORMALLY(x) WDL_unlikely(x) +#endif + +#endif diff --git a/Src/ns-eel2/y.tab.c b/Src/ns-eel2/y.tab.c new file mode 100644 index 00000000..d6a3c294 --- /dev/null +++ b/Src/ns-eel2/y.tab.c @@ -0,0 +1,2191 @@ +/* A Bison parser, made by GNU Bison 2.3. */ + +/* Skeleton implementation for Bison's Yacc-like parsers in C + + Copyright (C) 1984, 1989, 1990, 2000, 2001, 2002, 2003, 2004, 2005, 2006 + Free Software Foundation, Inc. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. */ + +/* As a special exception, you may create a larger work that contains + part or all of the Bison parser skeleton and distribute that work + under terms of your choice, so long as that work isn't itself a + parser generator using the skeleton or a modified version thereof + as a parser skeleton. Alternatively, if you modify or redistribute + the parser skeleton itself, you may (at your option) remove this + special exception, which will cause the skeleton and the resulting + Bison output files to be licensed under the GNU General Public + License without this special exception. + + This special exception was added by the Free Software Foundation in + version 2.2 of Bison. */ + +/* C LALR(1) parser skeleton written by Richard Stallman, by + simplifying the original so-called "semantic" parser. */ + +/* All symbols defined below should begin with yy or YY, to avoid + infringing on user name space. This should be done even for local + variables, as they might otherwise be expanded by user macros. + There are some unavoidable exceptions within include files to + define necessary library symbols; they are noted "INFRINGES ON + USER NAME SPACE" below. */ + +#include "ns-eel-int.h" + +/* Identify Bison output. */ +#define YYBISON 1 + +/* Bison version. */ +#define YYBISON_VERSION "2.3" + +/* Skeleton name. */ +#define YYSKELETON_NAME "yacc.c" + +/* Pure parsers. */ +#define YYPURE 1 + +/* Using locations. */ +#define YYLSP_NEEDED 1 + +extern int nseellex(opcodeRec** output, YYLTYPE* yylloc_param, compileContext* scctx); +extern void nseelerror(YYLTYPE* pos, compileContext* ctx, const char* str); + +/* Substitute the variable and function names. */ +#define yyparse nseelparse +#define yylex nseellex +#define yyerror nseelerror +#define yylval nseellval +#define yychar nseelchar +#define yydebug nseeldebug +#define yynerrs nseelnerrs +#define yylloc nseellloc + +/* Tokens. */ +#ifndef YYTOKENTYPE +# define YYTOKENTYPE + /* Put the tokens into the symbol table, so that GDB and other debuggers + know about them. */ + enum yytokentype { + VALUE = 258, + IDENTIFIER = 259, + TOKEN_SHL = 260, + TOKEN_SHR = 261, + TOKEN_LTE = 262, + TOKEN_GTE = 263, + TOKEN_EQ = 264, + TOKEN_EQ_EXACT = 265, + TOKEN_NE = 266, + TOKEN_NE_EXACT = 267, + TOKEN_LOGICAL_AND = 268, + TOKEN_LOGICAL_OR = 269, + TOKEN_ADD_OP = 270, + TOKEN_SUB_OP = 271, + TOKEN_MOD_OP = 272, + TOKEN_OR_OP = 273, + TOKEN_AND_OP = 274, + TOKEN_XOR_OP = 275, + TOKEN_DIV_OP = 276, + TOKEN_MUL_OP = 277, + TOKEN_POW_OP = 278, + STRING_LITERAL = 279, + STRING_IDENTIFIER = 280 + }; +#endif +/* Tokens. */ +#define VALUE 258 +#define IDENTIFIER 259 +#define TOKEN_SHL 260 +#define TOKEN_SHR 261 +#define TOKEN_LTE 262 +#define TOKEN_GTE 263 +#define TOKEN_EQ 264 +#define TOKEN_EQ_EXACT 265 +#define TOKEN_NE 266 +#define TOKEN_NE_EXACT 267 +#define TOKEN_LOGICAL_AND 268 +#define TOKEN_LOGICAL_OR 269 +#define TOKEN_ADD_OP 270 +#define TOKEN_SUB_OP 271 +#define TOKEN_MOD_OP 272 +#define TOKEN_OR_OP 273 +#define TOKEN_AND_OP 274 +#define TOKEN_XOR_OP 275 +#define TOKEN_DIV_OP 276 +#define TOKEN_MUL_OP 277 +#define TOKEN_POW_OP 278 +#define STRING_LITERAL 279 +#define STRING_IDENTIFIER 280 + + + + +/* Copy the first part of user declarations. */ +#line 13 "eel2.y" + +#ifdef _WIN32 +#include <windows.h> +#endif +#include <stdlib.h> +#include <stdio.h> +#include <string.h> +#include <math.h> + +#include "y.tab.h" +#include "ns-eel-int.h" + +#define scanner context->scanner +#define YY_(x) ("") + + + +/* Enabling traces. */ +#ifndef YYDEBUG +# define YYDEBUG 0 +#endif + +/* Enabling verbose error messages. */ +#ifdef YYERROR_VERBOSE +# undef YYERROR_VERBOSE +# define YYERROR_VERBOSE 1 +#else +# define YYERROR_VERBOSE 0 +#endif + +/* Enabling the token table. */ +#ifndef YYTOKEN_TABLE +# define YYTOKEN_TABLE 0 +#endif + +#if ! defined YYSTYPE && ! defined YYSTYPE_IS_DECLARED +typedef int YYSTYPE; +# define yystype YYSTYPE /* obsolescent; will be withdrawn */ +# define YYSTYPE_IS_DECLARED 1 +# define YYSTYPE_IS_TRIVIAL 1 +#endif + +#if ! defined YYLTYPE && ! defined YYLTYPE_IS_DECLARED +typedef struct YYLTYPE +{ + int first_line; + int first_column; + int last_line; + int last_column; +} YYLTYPE; +# define yyltype YYLTYPE /* obsolescent; will be withdrawn */ +# define YYLTYPE_IS_DECLARED 1 +# define YYLTYPE_IS_TRIVIAL 1 +#endif + + +/* Copy the second part of user declarations. */ + + +/* Line 216 of yacc.c. */ +#line 193 "y.tab.c" + +#ifdef short +# undef short +#endif + +#ifdef YYTYPE_UINT8 +typedef YYTYPE_UINT8 yytype_uint8; +#else +typedef unsigned char yytype_uint8; +#endif + +#ifdef YYTYPE_INT8 +typedef YYTYPE_INT8 yytype_int8; +#elif (defined __STDC__ || defined __C99__FUNC__ \ + || defined __cplusplus || defined _MSC_VER) +typedef signed char yytype_int8; +#else +typedef short int yytype_int8; +#endif + +#ifdef YYTYPE_UINT16 +typedef YYTYPE_UINT16 yytype_uint16; +#else +typedef unsigned short int yytype_uint16; +#endif + +#ifdef YYTYPE_INT16 +typedef YYTYPE_INT16 yytype_int16; +#else +typedef short int yytype_int16; +#endif + +#ifndef YYSIZE_T +# ifdef __SIZE_TYPE__ +# define YYSIZE_T __SIZE_TYPE__ +# elif defined size_t +# define YYSIZE_T size_t +# elif ! defined YYSIZE_T && (defined __STDC__ || defined __C99__FUNC__ \ + || defined __cplusplus || defined _MSC_VER) +# include <stddef.h> /* INFRINGES ON USER NAME SPACE */ +# define YYSIZE_T size_t +# else +# define YYSIZE_T unsigned int +# endif +#endif + +#define YYSIZE_MAXIMUM ((YYSIZE_T) -1) + +#ifndef YY_ +# if defined YYENABLE_NLS && YYENABLE_NLS +# if ENABLE_NLS +# include <libintl.h> /* INFRINGES ON USER NAME SPACE */ +# define YY_(msgid) dgettext ("bison-runtime", msgid) +# endif +# endif +# ifndef YY_ +# define YY_(msgid) msgid +# endif +#endif + +/* Suppress unused-variable warnings by "using" E. */ +#if ! defined lint || defined __GNUC__ +# define YYUSE(e) ((void) (e)) +#else +# define YYUSE(e) /* empty */ +#endif + +/* Identity function, used to suppress warnings about constant conditions. */ +#ifndef lint +# define YYID(n) (n) +#else +#if (defined __STDC__ || defined __C99__FUNC__ \ + || defined __cplusplus || defined _MSC_VER) +static int +YYID (int i) +#else +static int +YYID (i) + int i; +#endif +{ + return i; +} +#endif + +#if ! defined yyoverflow || YYERROR_VERBOSE + +/* The parser invokes alloca or malloc; define the necessary symbols. */ + +# ifdef YYSTACK_USE_ALLOCA +# if YYSTACK_USE_ALLOCA +# ifdef __GNUC__ +# define YYSTACK_ALLOC __builtin_alloca +# elif defined __BUILTIN_VA_ARG_INCR +# include <alloca.h> /* INFRINGES ON USER NAME SPACE */ +# elif defined _AIX +# define YYSTACK_ALLOC __alloca +# elif defined _MSC_VER +# include <malloc.h> /* INFRINGES ON USER NAME SPACE */ +# define alloca _alloca +# else +# define YYSTACK_ALLOC alloca +# if ! defined _ALLOCA_H && ! defined _STDLIB_H && (defined __STDC__ || defined __C99__FUNC__ \ + || defined __cplusplus || defined _MSC_VER) +# include <stdlib.h> /* INFRINGES ON USER NAME SPACE */ +# ifndef _STDLIB_H +# define _STDLIB_H 1 +# endif +# endif +# endif +# endif +# endif + +# ifdef YYSTACK_ALLOC + /* Pacify GCC's `empty if-body' warning. */ +# define YYSTACK_FREE(Ptr) do { /* empty */; } while (YYID (0)) +# ifndef YYSTACK_ALLOC_MAXIMUM + /* The OS might guarantee only one guard page at the bottom of the stack, + and a page size can be as small as 4096 bytes. So we cannot safely + invoke alloca (N) if N exceeds 4096. Use a slightly smaller number + to allow for a few compiler-allocated temporary stack slots. */ +# define YYSTACK_ALLOC_MAXIMUM 4032 /* reasonable circa 2006 */ +# endif +# else +# define YYSTACK_ALLOC YYMALLOC +# define YYSTACK_FREE YYFREE +# ifndef YYSTACK_ALLOC_MAXIMUM +# define YYSTACK_ALLOC_MAXIMUM YYSIZE_MAXIMUM +# endif +# if (defined __cplusplus && ! defined _STDLIB_H \ + && ! ((defined YYMALLOC || defined malloc) \ + && (defined YYFREE || defined free))) +# include <stdlib.h> /* INFRINGES ON USER NAME SPACE */ +# ifndef _STDLIB_H +# define _STDLIB_H 1 +# endif +# endif +# ifndef YYMALLOC +# define YYMALLOC malloc +# if ! defined malloc && ! defined _STDLIB_H && (defined __STDC__ || defined __C99__FUNC__ \ + || defined __cplusplus || defined _MSC_VER) +void *malloc (YYSIZE_T); /* INFRINGES ON USER NAME SPACE */ +# endif +# endif +# ifndef YYFREE +# define YYFREE free +# if ! defined free && ! defined _STDLIB_H && (defined __STDC__ || defined __C99__FUNC__ \ + || defined __cplusplus || defined _MSC_VER) +void free (void *); /* INFRINGES ON USER NAME SPACE */ +# endif +# endif +# endif +#endif /* ! defined yyoverflow || YYERROR_VERBOSE */ + + +#if (! defined yyoverflow \ + && (! defined __cplusplus \ + || (defined YYLTYPE_IS_TRIVIAL && YYLTYPE_IS_TRIVIAL \ + && defined YYSTYPE_IS_TRIVIAL && YYSTYPE_IS_TRIVIAL))) + +/* A type that is properly aligned for any stack member. */ +union yyalloc +{ + yytype_int16 yyss; + YYSTYPE yyvs; + YYLTYPE yyls; +}; + +/* The size of the maximum gap between one aligned stack and the next. */ +# define YYSTACK_GAP_MAXIMUM (sizeof (union yyalloc) - 1) + +/* The size of an array large to enough to hold all stacks, each with + N elements. */ +# define YYSTACK_BYTES(N) \ + ((N) * (sizeof (yytype_int16) + sizeof (YYSTYPE) + sizeof (YYLTYPE)) \ + + 2 * YYSTACK_GAP_MAXIMUM) + +/* Copy COUNT objects from FROM to TO. The source and destination do + not overlap. */ +# ifndef YYCOPY +# if defined __GNUC__ && 1 < __GNUC__ +# define YYCOPY(To, From, Count) \ + __builtin_memcpy (To, From, (Count) * sizeof (*(From))) +# else +# define YYCOPY(To, From, Count) \ + do \ + { \ + YYSIZE_T yyi; \ + for (yyi = 0; yyi < (Count); yyi++) \ + (To)[yyi] = (From)[yyi]; \ + } \ + while (YYID (0)) +# endif +# endif + +/* Relocate STACK from its old location to the new one. The + local variables YYSIZE and YYSTACKSIZE give the old and new number of + elements in the stack, and YYPTR gives the new location of the + stack. Advance YYPTR to a properly aligned location for the next + stack. */ +# define YYSTACK_RELOCATE(Stack) \ + do \ + { \ + YYSIZE_T yynewbytes; \ + YYCOPY (&yyptr->Stack, Stack, yysize); \ + Stack = &yyptr->Stack; \ + yynewbytes = yystacksize * sizeof (*Stack) + YYSTACK_GAP_MAXIMUM; \ + yyptr += yynewbytes / sizeof (*yyptr); \ + } \ + while (YYID (0)) + +#endif + +/* YYFINAL -- State number of the termination state. */ +#define YYFINAL 68 +/* YYLAST -- Last index in YYTABLE. */ +#define YYLAST 141 + +/* YYNTOKENS -- Number of terminals. */ +#define YYNTOKENS 47 +/* YYNNTS -- Number of nonterminals. */ +#define YYNNTS 19 +/* YYNRULES -- Number of rules. */ +#define YYNRULES 73 +/* YYNRULES -- Number of states. */ +#define YYNSTATES 127 + +/* YYTRANSLATE(YYLEX) -- Bison symbol number corresponding to YYLEX. */ +#define YYUNDEFTOK 2 +#define YYMAXUTOK 280 + +#define YYTRANSLATE(YYX) \ + ((unsigned int) (YYX) <= YYMAXUTOK ? yytranslate[YYX] : YYUNDEFTOK) + +/* YYTRANSLATE[YYLEX] -- Bison symbol number corresponding to YYLEX. */ +static const yytype_uint8 yytranslate[] = +{ + 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 34, 2, 2, 2, 36, 39, 2, + 27, 28, 38, 32, 26, 33, 2, 37, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 45, 46, + 42, 31, 43, 44, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 29, 2, 30, 35, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 40, 2, 41, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 1, 2, 3, 4, + 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, + 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, + 25 +}; + +#if YYDEBUG +/* YYPRHS[YYN] -- Index of the first RHS symbol of rule number YYN in + YYRHS. */ +static const yytype_uint16 yyprhs[] = +{ + 0, 0, 3, 5, 9, 11, 14, 16, 20, 28, + 33, 37, 44, 53, 57, 62, 64, 66, 68, 70, + 72, 76, 80, 84, 88, 92, 96, 100, 104, 108, + 112, 116, 120, 122, 125, 128, 131, 133, 137, 139, + 143, 147, 151, 153, 157, 159, 163, 165, 169, 171, + 175, 177, 181, 185, 189, 191, 195, 199, 203, 207, + 211, 215, 219, 223, 225, 229, 233, 235, 241, 246, + 250, 252, 256, 259 +}; + +/* YYRHS -- A `-1'-separated list of the rules' RHS. */ +static const yytype_int8 yyrhs[] = +{ + 65, 0, -1, 64, -1, 64, 26, 48, -1, 24, + -1, 24, 49, -1, 4, -1, 27, 64, 28, -1, + 4, 27, 64, 28, 27, 64, 28, -1, 4, 27, + 64, 28, -1, 4, 27, 28, -1, 4, 27, 64, + 26, 64, 28, -1, 4, 27, 64, 26, 64, 26, + 48, 28, -1, 51, 29, 30, -1, 51, 29, 64, + 30, -1, 3, -1, 25, -1, 49, -1, 50, -1, + 51, -1, 50, 31, 63, -1, 50, 15, 63, -1, + 50, 16, 63, -1, 50, 17, 63, -1, 50, 18, + 63, -1, 50, 19, 63, -1, 50, 20, 63, -1, + 50, 21, 63, -1, 50, 22, 63, -1, 50, 23, + 63, -1, 25, 31, 63, -1, 25, 15, 63, -1, + 52, -1, 32, 53, -1, 33, 53, -1, 34, 53, + -1, 53, -1, 54, 35, 53, -1, 54, -1, 55, + 36, 54, -1, 55, 5, 54, -1, 55, 6, 54, + -1, 55, -1, 56, 37, 55, -1, 56, -1, 57, + 38, 56, -1, 57, -1, 58, 33, 57, -1, 58, + -1, 59, 32, 58, -1, 59, -1, 60, 39, 59, + -1, 60, 40, 59, -1, 60, 41, 59, -1, 60, + -1, 61, 42, 60, -1, 61, 43, 60, -1, 61, + 7, 60, -1, 61, 8, 60, -1, 61, 9, 60, + -1, 61, 10, 60, -1, 61, 11, 60, -1, 61, + 12, 60, -1, 61, -1, 62, 13, 61, -1, 62, + 14, 61, -1, 62, -1, 62, 44, 63, 45, 63, + -1, 62, 44, 45, 63, -1, 62, 44, 63, -1, + 63, -1, 64, 46, 63, -1, 64, 46, -1, 64, + -1 +}; + +/* YYRLINE[YYN] -- source line where rule number YYN was defined. */ +static const yytype_uint16 yyrline[] = +{ + 0, 40, 40, 41, 48, 49, 57, 67, 71, 83, + 93, 103, 114, 126, 130, 137, 138, 139, 143, 148, + 149, 153, 157, 161, 165, 169, 173, 177, 181, 185, + 189, 193, 200, 201, 205, 209, 216, 217, 224, 225, + 229, 233, 240, 241, 249, 250, 258, 259, 266, 267, + 274, 275, 279, 283, 290, 291, 295, 299, 303, 307, + 311, 315, 319, 326, 327, 331, 338, 339, 343, 347, + 355, 356, 360, 368 +}; +#endif + +#if YYDEBUG || YYERROR_VERBOSE || YYTOKEN_TABLE +/* YYTNAME[SYMBOL-NUM] -- String name of the symbol SYMBOL-NUM. + First, the terminals, then, starting at YYNTOKENS, nonterminals. */ +static const char *const yytname[] = +{ + "$end", "error", "$undefined", "VALUE", "IDENTIFIER", "TOKEN_SHL", + "TOKEN_SHR", "TOKEN_LTE", "TOKEN_GTE", "TOKEN_EQ", "TOKEN_EQ_EXACT", + "TOKEN_NE", "TOKEN_NE_EXACT", "TOKEN_LOGICAL_AND", "TOKEN_LOGICAL_OR", + "TOKEN_ADD_OP", "TOKEN_SUB_OP", "TOKEN_MOD_OP", "TOKEN_OR_OP", + "TOKEN_AND_OP", "TOKEN_XOR_OP", "TOKEN_DIV_OP", "TOKEN_MUL_OP", + "TOKEN_POW_OP", "STRING_LITERAL", "STRING_IDENTIFIER", "','", "'('", + "')'", "'['", "']'", "'='", "'+'", "'-'", "'!'", "'^'", "'%'", "'/'", + "'*'", "'&'", "'|'", "'~'", "'<'", "'>'", "'?'", "':'", "';'", "$accept", + "more_params", "string", "assignable_value", "rvalue", "assignment", + "unary_expr", "pow_expr", "mod_expr", "div_expr", "mul_expr", "sub_expr", + "add_expr", "andor_expr", "cmp_expr", "logical_and_or_expr", + "if_else_expr", "expression", "program", 0 +}; +#endif + +# ifdef YYPRINT +/* YYTOKNUM[YYLEX-NUM] -- Internal token number corresponding to + token YYLEX-NUM. */ +static const yytype_uint16 yytoknum[] = +{ + 0, 256, 257, 258, 259, 260, 261, 262, 263, 264, + 265, 266, 267, 268, 269, 270, 271, 272, 273, 274, + 275, 276, 277, 278, 279, 280, 44, 40, 41, 91, + 93, 61, 43, 45, 33, 94, 37, 47, 42, 38, + 124, 126, 60, 62, 63, 58, 59 +}; +# endif + +/* YYR1[YYN] -- Symbol number of symbol that rule YYN derives. */ +static const yytype_uint8 yyr1[] = +{ + 0, 47, 48, 48, 49, 49, 50, 50, 50, 50, + 50, 50, 50, 50, 50, 51, 51, 51, 51, 52, + 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, + 52, 52, 53, 53, 53, 53, 54, 54, 55, 55, + 55, 55, 56, 56, 57, 57, 58, 58, 59, 59, + 60, 60, 60, 60, 61, 61, 61, 61, 61, 61, + 61, 61, 61, 62, 62, 62, 63, 63, 63, 63, + 64, 64, 64, 65 +}; + +/* YYR2[YYN] -- Number of symbols composing right hand side of rule YYN. */ +static const yytype_uint8 yyr2[] = +{ + 0, 2, 1, 3, 1, 2, 1, 3, 7, 4, + 3, 6, 8, 3, 4, 1, 1, 1, 1, 1, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, + 3, 3, 1, 2, 2, 2, 1, 3, 1, 3, + 3, 3, 1, 3, 1, 3, 1, 3, 1, 3, + 1, 3, 3, 3, 1, 3, 3, 3, 3, 3, + 3, 3, 3, 1, 3, 3, 1, 5, 4, 3, + 1, 3, 2, 1 +}; + +/* YYDEFACT[STATE-NAME] -- Default rule to reduce with in state + STATE-NUM when YYTABLE doesn't specify something else to do. Zero + means the default is an error. */ +static const yytype_uint8 yydefact[] = +{ + 0, 15, 6, 4, 16, 0, 0, 0, 0, 17, + 18, 19, 32, 36, 38, 42, 44, 46, 48, 50, + 54, 63, 66, 70, 73, 0, 0, 5, 0, 0, + 0, 33, 34, 35, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 72, 1, 10, + 0, 31, 30, 7, 21, 22, 23, 24, 25, 26, + 27, 28, 29, 20, 13, 0, 37, 40, 41, 39, + 43, 45, 47, 49, 51, 52, 53, 57, 58, 59, + 60, 61, 62, 55, 56, 64, 65, 0, 69, 71, + 0, 9, 14, 68, 0, 0, 0, 67, 0, 11, + 0, 0, 2, 8, 12, 0, 3 +}; + +/* YYDEFGOTO[NTERM-NUM]. */ +static const yytype_int8 yydefgoto[] = +{ + -1, 121, 9, 10, 11, 12, 13, 14, 15, 16, + 17, 18, 19, 20, 21, 22, 23, 122, 25 +}; + +/* YYPACT[STATE-NUM] -- Index in YYTABLE of the portion describing + STATE-NUM. */ +#define YYPACT_NINF -38 +static const yytype_int8 yypact[] = +{ + 70, -38, -21, 12, -11, 70, 70, 70, 70, -38, + 102, 6, -38, -38, 50, 19, 4, 8, 14, 25, + 51, 22, 40, -38, 47, 96, 34, -38, 70, 70, + 43, -38, -38, -38, 70, 70, 70, 70, 70, 70, + 70, 70, 70, 70, 45, 70, 70, 70, 70, 70, + 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, + 70, 70, 70, 70, 70, 70, 18, 70, -38, -38, + 55, -38, -38, -38, -38, -38, -38, -38, -38, -38, + -38, -38, -38, -38, -38, 30, -38, 50, 50, 50, + 19, 4, 8, 14, 25, 25, 25, 51, 51, 51, + 51, 51, 51, 51, 51, 22, 22, 70, 53, -38, + 70, 72, -38, -38, 70, 60, 70, -38, 70, -38, + 54, 77, -23, -38, -38, 70, -38 +}; + +/* YYPGOTO[NTERM-NUM]. */ +static const yytype_int8 yypgoto[] = +{ + -38, -10, 111, -38, -38, -38, 11, 61, 79, 76, + 80, 75, 58, 78, -37, -38, -27, 0, -38 +}; + +/* YYTABLE[YYPACT[STATE-NUM]]. What to do in state STATE-NUM. If + positive, shift that token. If negative, reduce the rule which + number is the opposite. If zero, do what YYDEFACT says. + If YYTABLE_NINF, syntax error. */ +#define YYTABLE_NINF -1 +static const yytype_uint8 yytable[] = +{ + 24, 71, 72, 125, 28, 30, 26, 74, 75, 76, + 77, 78, 79, 80, 81, 82, 83, 31, 32, 33, + 29, 1, 2, 67, 46, 47, 70, 105, 106, 56, + 57, 58, 59, 60, 61, 44, 3, 1, 2, 108, + 109, 49, 3, 4, 85, 5, 50, 51, 1, 2, + 6, 7, 8, 64, 65, 48, 86, 52, 3, 4, + 112, 5, 69, 107, 62, 63, 6, 7, 8, 3, + 4, 73, 5, 1, 2, 84, 67, 6, 7, 8, + 113, 110, 123, 111, 66, 45, 118, 117, 119, 67, + 53, 54, 55, 67, 3, 4, 68, 5, 114, 116, + 67, 67, 6, 7, 8, 124, 67, 87, 88, 89, + 115, 94, 95, 96, 27, 126, 120, 34, 35, 36, + 37, 38, 39, 40, 41, 42, 91, 93, 90, 0, + 0, 92, 0, 43, 97, 98, 99, 100, 101, 102, + 103, 104 +}; + +static const yytype_int8 yycheck[] = +{ + 0, 28, 29, 26, 15, 5, 27, 34, 35, 36, + 37, 38, 39, 40, 41, 42, 43, 6, 7, 8, + 31, 3, 4, 46, 5, 6, 26, 64, 65, 7, + 8, 9, 10, 11, 12, 29, 24, 3, 4, 66, + 67, 37, 24, 25, 44, 27, 38, 33, 3, 4, + 32, 33, 34, 13, 14, 36, 45, 32, 24, 25, + 30, 27, 28, 45, 42, 43, 32, 33, 34, 24, + 25, 28, 27, 3, 4, 30, 46, 32, 33, 34, + 107, 26, 28, 28, 44, 35, 26, 114, 28, 46, + 39, 40, 41, 46, 24, 25, 0, 27, 45, 27, + 46, 46, 32, 33, 34, 28, 46, 46, 47, 48, + 110, 53, 54, 55, 3, 125, 116, 15, 16, 17, + 18, 19, 20, 21, 22, 23, 50, 52, 49, -1, + -1, 51, -1, 31, 56, 57, 58, 59, 60, 61, + 62, 63 +}; + +/* YYSTOS[STATE-NUM] -- The (internal number of the) accessing + symbol of state STATE-NUM. */ +static const yytype_uint8 yystos[] = +{ + 0, 3, 4, 24, 25, 27, 32, 33, 34, 49, + 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, + 60, 61, 62, 63, 64, 65, 27, 49, 15, 31, + 64, 53, 53, 53, 15, 16, 17, 18, 19, 20, + 21, 22, 23, 31, 29, 35, 5, 6, 36, 37, + 38, 33, 32, 39, 40, 41, 7, 8, 9, 10, + 11, 12, 42, 43, 13, 14, 44, 46, 0, 28, + 64, 63, 63, 28, 63, 63, 63, 63, 63, 63, + 63, 63, 63, 63, 30, 64, 53, 54, 54, 54, + 55, 56, 57, 58, 59, 59, 59, 60, 60, 60, + 60, 60, 60, 60, 60, 61, 61, 45, 63, 63, + 26, 28, 30, 63, 45, 64, 27, 63, 26, 28, + 64, 48, 64, 28, 28, 26, 48 +}; + +#define yyerrok (yyerrstatus = 0) +#define yyclearin (yychar = YYEMPTY) +#define YYEMPTY (-2) +#define YYEOF 0 + +#define YYACCEPT goto yyacceptlab +#define YYABORT goto yyabortlab +#define YYERROR goto yyerrorlab + + +/* Like YYERROR except do call yyerror. This remains here temporarily + to ease the transition to the new meaning of YYERROR, for GCC. + Once GCC version 2 has supplanted version 1, this can go. */ + +#define YYFAIL goto yyerrlab + +#define YYRECOVERING() (!!yyerrstatus) + +#define YYBACKUP(Token, Value) \ +do \ + if (yychar == YYEMPTY && yylen == 1) \ + { \ + yychar = (Token); \ + yylval = (Value); \ + yytoken = YYTRANSLATE (yychar); \ + YYPOPSTACK (1); \ + goto yybackup; \ + } \ + else \ + { \ + yyerror (&yylloc, context, YY_("syntax error: cannot back up")); \ + YYERROR; \ + } \ +while (YYID (0)) + + +#define YYTERROR 1 +#define YYERRCODE 256 + + +/* YYLLOC_DEFAULT -- Set CURRENT to span from RHS[1] to RHS[N]. + If N is 0, then set CURRENT to the empty location which ends + the previous symbol: RHS[0] (always defined). */ + +#define YYRHSLOC(Rhs, K) ((Rhs)[K]) +#ifndef YYLLOC_DEFAULT +# define YYLLOC_DEFAULT(Current, Rhs, N) \ + do \ + if (YYID (N)) \ + { \ + (Current).first_line = YYRHSLOC (Rhs, 1).first_line; \ + (Current).first_column = YYRHSLOC (Rhs, 1).first_column; \ + (Current).last_line = YYRHSLOC (Rhs, N).last_line; \ + (Current).last_column = YYRHSLOC (Rhs, N).last_column; \ + } \ + else \ + { \ + (Current).first_line = (Current).last_line = \ + YYRHSLOC (Rhs, 0).last_line; \ + (Current).first_column = (Current).last_column = \ + YYRHSLOC (Rhs, 0).last_column; \ + } \ + while (YYID (0)) +#endif + + +/* YY_LOCATION_PRINT -- Print the location on the stream. + This macro was not mandated originally: define only if we know + we won't break user code: when these are the locations we know. */ + +#ifndef YY_LOCATION_PRINT +# if defined YYLTYPE_IS_TRIVIAL && YYLTYPE_IS_TRIVIAL +# define YY_LOCATION_PRINT(File, Loc) \ + fprintf (File, "%d.%d-%d.%d", \ + (Loc).first_line, (Loc).first_column, \ + (Loc).last_line, (Loc).last_column) +# else +# define YY_LOCATION_PRINT(File, Loc) ((void) 0) +# endif +#endif + + +/* YYLEX -- calling `yylex' with the right arguments. */ + +#ifdef YYLEX_PARAM +# define YYLEX yylex (&yylval, &yylloc, YYLEX_PARAM) +#else +# define YYLEX yylex (&yylval, &yylloc, scanner) +#endif + +/* Enable debugging if requested. */ +#if YYDEBUG + +# ifndef YYFPRINTF +# include <stdio.h> /* INFRINGES ON USER NAME SPACE */ +# define YYFPRINTF fprintf +# endif + +# define YYDPRINTF(Args) \ +do { \ + if (yydebug) \ + YYFPRINTF Args; \ +} while (YYID (0)) + +# define YY_SYMBOL_PRINT(Title, Type, Value, Location) \ +do { \ + if (yydebug) \ + { \ + YYFPRINTF (stderr, "%s ", Title); \ + yy_symbol_print (stderr, \ + Type, Value, Location, context); \ + YYFPRINTF (stderr, "\n"); \ + } \ +} while (YYID (0)) + + +/*--------------------------------. +| Print this symbol on YYOUTPUT. | +`--------------------------------*/ + +/*ARGSUSED*/ +#if (defined __STDC__ || defined __C99__FUNC__ \ + || defined __cplusplus || defined _MSC_VER) +static void +yy_symbol_value_print (FILE *yyoutput, int yytype, YYSTYPE const * const yyvaluep, YYLTYPE const * const yylocationp, compileContext* context) +#else +static void +yy_symbol_value_print (yyoutput, yytype, yyvaluep, yylocationp, context) + FILE *yyoutput; + int yytype; + YYSTYPE const * const yyvaluep; + YYLTYPE const * const yylocationp; + compileContext* context; +#endif +{ + if (!yyvaluep) + return; + YYUSE (yylocationp); + YYUSE (context); +# ifdef YYPRINT + if (yytype < YYNTOKENS) + YYPRINT (yyoutput, yytoknum[yytype], *yyvaluep); +# else + YYUSE (yyoutput); +# endif + switch (yytype) + { + default: + break; + } +} + + +/*--------------------------------. +| Print this symbol on YYOUTPUT. | +`--------------------------------*/ + +#if (defined __STDC__ || defined __C99__FUNC__ \ + || defined __cplusplus || defined _MSC_VER) +static void +yy_symbol_print (FILE *yyoutput, int yytype, YYSTYPE const * const yyvaluep, YYLTYPE const * const yylocationp, compileContext* context) +#else +static void +yy_symbol_print (yyoutput, yytype, yyvaluep, yylocationp, context) + FILE *yyoutput; + int yytype; + YYSTYPE const * const yyvaluep; + YYLTYPE const * const yylocationp; + compileContext* context; +#endif +{ + if (yytype < YYNTOKENS) + YYFPRINTF (yyoutput, "token %s (", yytname[yytype]); + else + YYFPRINTF (yyoutput, "nterm %s (", yytname[yytype]); + + YY_LOCATION_PRINT (yyoutput, *yylocationp); + YYFPRINTF (yyoutput, ": "); + yy_symbol_value_print (yyoutput, yytype, yyvaluep, yylocationp, context); + YYFPRINTF (yyoutput, ")"); +} + +/*------------------------------------------------------------------. +| yy_stack_print -- Print the state stack from its BOTTOM up to its | +| TOP (included). | +`------------------------------------------------------------------*/ + +#if (defined __STDC__ || defined __C99__FUNC__ \ + || defined __cplusplus || defined _MSC_VER) +static void +yy_stack_print (yytype_int16 *bottom, yytype_int16 *top) +#else +static void +yy_stack_print (bottom, top) + yytype_int16 *bottom; + yytype_int16 *top; +#endif +{ + YYFPRINTF (stderr, "Stack now"); + for (; bottom <= top; ++bottom) + YYFPRINTF (stderr, " %d", *bottom); + YYFPRINTF (stderr, "\n"); +} + +# define YY_STACK_PRINT(Bottom, Top) \ +do { \ + if (yydebug) \ + yy_stack_print ((Bottom), (Top)); \ +} while (YYID (0)) + + +/*------------------------------------------------. +| Report that the YYRULE is going to be reduced. | +`------------------------------------------------*/ + +#if (defined __STDC__ || defined __C99__FUNC__ \ + || defined __cplusplus || defined _MSC_VER) +static void +yy_reduce_print (YYSTYPE *yyvsp, YYLTYPE *yylsp, int yyrule, compileContext* context) +#else +static void +yy_reduce_print (yyvsp, yylsp, yyrule, context) + YYSTYPE *yyvsp; + YYLTYPE *yylsp; + int yyrule; + compileContext* context; +#endif +{ + int yynrhs = yyr2[yyrule]; + int yyi; + unsigned long int yylno = yyrline[yyrule]; + YYFPRINTF (stderr, "Reducing stack by rule %d (line %lu):\n", + yyrule - 1, yylno); + /* The symbols being reduced. */ + for (yyi = 0; yyi < yynrhs; yyi++) + { + fprintf (stderr, " $%d = ", yyi + 1); + yy_symbol_print (stderr, yyrhs[yyprhs[yyrule] + yyi], + &(yyvsp[(yyi + 1) - (yynrhs)]) + , &(yylsp[(yyi + 1) - (yynrhs)]) , context); + fprintf (stderr, "\n"); + } +} + +# define YY_REDUCE_PRINT(Rule) \ +do { \ + if (yydebug) \ + yy_reduce_print (yyvsp, yylsp, Rule, context); \ +} while (YYID (0)) + +/* Nonzero means print parse trace. It is left uninitialized so that + multiple parsers can coexist. */ +int yydebug; +#else /* !YYDEBUG */ +# define YYDPRINTF(Args) +# define YY_SYMBOL_PRINT(Title, Type, Value, Location) +# define YY_STACK_PRINT(Bottom, Top) +# define YY_REDUCE_PRINT(Rule) +#endif /* !YYDEBUG */ + + +/* YYINITDEPTH -- initial size of the parser's stacks. */ +#ifndef YYINITDEPTH +# define YYINITDEPTH 200 +#endif + +/* YYMAXDEPTH -- maximum size the stacks can grow to (effective only + if the built-in stack extension method is used). + + Do not make this value too large; the results are undefined if + YYSTACK_ALLOC_MAXIMUM < YYSTACK_BYTES (YYMAXDEPTH) + evaluated with infinite-precision integer arithmetic. */ + +#ifndef YYMAXDEPTH +# define YYMAXDEPTH 10000 +#endif + + + +#if YYERROR_VERBOSE + +# ifndef yystrlen +# if defined __GLIBC__ && defined _STRING_H +# define yystrlen strlen +# else +/* Return the length of YYSTR. */ +#if (defined __STDC__ || defined __C99__FUNC__ \ + || defined __cplusplus || defined _MSC_VER) +static YYSIZE_T +yystrlen (const char *yystr) +#else +static YYSIZE_T +yystrlen (yystr) + const char *yystr; +#endif +{ + YYSIZE_T yylen; + for (yylen = 0; yystr[yylen]; yylen++) + continue; + return yylen; +} +# endif +# endif + +# ifndef yystpcpy +# if defined __GLIBC__ && defined _STRING_H && defined _GNU_SOURCE +# define yystpcpy stpcpy +# else +/* Copy YYSRC to YYDEST, returning the address of the terminating '\0' in + YYDEST. */ +#if (defined __STDC__ || defined __C99__FUNC__ \ + || defined __cplusplus || defined _MSC_VER) +static char * +yystpcpy (char *yydest, const char *yysrc) +#else +static char * +yystpcpy (yydest, yysrc) + char *yydest; + const char *yysrc; +#endif +{ + char *yyd = yydest; + const char *yys = yysrc; + + while ((*yyd++ = *yys++) != '\0') + continue; + + return yyd - 1; +} +# endif +# endif + +# ifndef yytnamerr +/* Copy to YYRES the contents of YYSTR after stripping away unnecessary + quotes and backslashes, so that it's suitable for yyerror. The + heuristic is that double-quoting is unnecessary unless the string + contains an apostrophe, a comma, or backslash (other than + backslash-backslash). YYSTR is taken from yytname. If YYRES is + null, do not copy; instead, return the length of what the result + would have been. */ +static YYSIZE_T +yytnamerr (char *yyres, const char *yystr) +{ + if (*yystr == '"') + { + YYSIZE_T yyn = 0; + char const *yyp = yystr; + + for (;;) + switch (*++yyp) + { + case '\'': + case ',': + goto do_not_strip_quotes; + + case '\\': + if (*++yyp != '\\') + goto do_not_strip_quotes; + /* Fall through. */ + default: + if (yyres) + yyres[yyn] = *yyp; + yyn++; + break; + + case '"': + if (yyres) + yyres[yyn] = '\0'; + return yyn; + } + do_not_strip_quotes: ; + } + + if (! yyres) + return yystrlen (yystr); + + return yystpcpy (yyres, yystr) - yyres; +} +# endif + +/* Copy into YYRESULT an error message about the unexpected token + YYCHAR while in state YYSTATE. Return the number of bytes copied, + including the terminating null byte. If YYRESULT is null, do not + copy anything; just return the number of bytes that would be + copied. As a special case, return 0 if an ordinary "syntax error" + message will do. Return YYSIZE_MAXIMUM if overflow occurs during + size calculation. */ +static YYSIZE_T +yysyntax_error (char *yyresult, int yystate, int yychar) +{ + int yyn = yypact[yystate]; + + if (! (YYPACT_NINF < yyn && yyn <= YYLAST)) + return 0; + else + { + int yytype = YYTRANSLATE (yychar); + YYSIZE_T yysize0 = yytnamerr (0, yytname[yytype]); + YYSIZE_T yysize = yysize0; + YYSIZE_T yysize1; + int yysize_overflow = 0; + enum { YYERROR_VERBOSE_ARGS_MAXIMUM = 5 }; + char const *yyarg[YYERROR_VERBOSE_ARGS_MAXIMUM]; + int yyx; + +# if 0 + /* This is so xgettext sees the translatable formats that are + constructed on the fly. */ + YY_("syntax error, unexpected %s"); + YY_("syntax error, unexpected %s, expecting %s"); + YY_("syntax error, unexpected %s, expecting %s or %s"); + YY_("syntax error, unexpected %s, expecting %s or %s or %s"); + YY_("syntax error, unexpected %s, expecting %s or %s or %s or %s"); +# endif + char *yyfmt; + char const *yyf; + static char const yyunexpected[] = "syntax error, unexpected %s"; + static char const yyexpecting[] = ", expecting %s"; + static char const yyor[] = " or %s"; + char yyformat[sizeof yyunexpected + + sizeof yyexpecting - 1 + + ((YYERROR_VERBOSE_ARGS_MAXIMUM - 2) + * (sizeof yyor - 1))]; + char const *yyprefix = yyexpecting; + + /* Start YYX at -YYN if negative to avoid negative indexes in + YYCHECK. */ + int yyxbegin = yyn < 0 ? -yyn : 0; + + /* Stay within bounds of both yycheck and yytname. */ + int yychecklim = YYLAST - yyn + 1; + int yyxend = yychecklim < YYNTOKENS ? yychecklim : YYNTOKENS; + int yycount = 1; + + yyarg[0] = yytname[yytype]; + yyfmt = yystpcpy (yyformat, yyunexpected); + + for (yyx = yyxbegin; yyx < yyxend; ++yyx) + if (yycheck[yyx + yyn] == yyx && yyx != YYTERROR) + { + if (yycount == YYERROR_VERBOSE_ARGS_MAXIMUM) + { + yycount = 1; + yysize = yysize0; + yyformat[sizeof yyunexpected - 1] = '\0'; + break; + } + yyarg[yycount++] = yytname[yyx]; + yysize1 = yysize + yytnamerr (0, yytname[yyx]); + yysize_overflow |= (yysize1 < yysize); + yysize = yysize1; + yyfmt = yystpcpy (yyfmt, yyprefix); + yyprefix = yyor; + } + + yyf = YY_(yyformat); + yysize1 = yysize + yystrlen (yyf); + yysize_overflow |= (yysize1 < yysize); + yysize = yysize1; + + if (yysize_overflow) + return YYSIZE_MAXIMUM; + + if (yyresult) + { + /* Avoid sprintf, as that infringes on the user's name space. + Don't have undefined behavior even if the translation + produced a string with the wrong number of "%s"s. */ + char *yyp = yyresult; + int yyi = 0; + while ((*yyp = *yyf) != '\0') + { + if (*yyp == '%' && yyf[1] == 's' && yyi < yycount) + { + yyp += yytnamerr (yyp, yyarg[yyi++]); + yyf += 2; + } + else + { + yyp++; + yyf++; + } + } + } + return yysize; + } +} +#endif /* YYERROR_VERBOSE */ + + +/*-----------------------------------------------. +| Release the memory associated to this symbol. | +`-----------------------------------------------*/ + +/*ARGSUSED*/ +#if (defined __STDC__ || defined __C99__FUNC__ \ + || defined __cplusplus || defined _MSC_VER) +static void +yydestruct (const char *yymsg, int yytype, YYSTYPE *yyvaluep, YYLTYPE *yylocationp, compileContext* context) +#else +static void +yydestruct (yymsg, yytype, yyvaluep, yylocationp, context) + const char *yymsg; + int yytype; + YYSTYPE *yyvaluep; + YYLTYPE *yylocationp; + compileContext* context; +#endif +{ + YYUSE (yyvaluep); + YYUSE (yylocationp); + YYUSE (context); + + if (!yymsg) + yymsg = "Deleting"; + YY_SYMBOL_PRINT (yymsg, yytype, yyvaluep, yylocationp); + + switch (yytype) + { + case 3: /* "VALUE" */ +#line 8 "eel2.y" + { + #define yydestruct(a,b,c,d,e) +}; +#line 1222 "y.tab.c" + break; + + default: + break; + } +} + + +/* Prevent warnings from -Wmissing-prototypes. */ + +#ifdef YYPARSE_PARAM +#if defined __STDC__ || defined __cplusplus +int yyparse (void *YYPARSE_PARAM); +#else +int yyparse (); +#endif +#else /* ! YYPARSE_PARAM */ +#if defined __STDC__ || defined __cplusplus +int yyparse (compileContext* context); +#else +int yyparse (); +#endif +#endif /* ! YYPARSE_PARAM */ + + + + + + +/*----------. +| yyparse. | +`----------*/ + +#ifdef YYPARSE_PARAM +#if (defined __STDC__ || defined __C99__FUNC__ \ + || defined __cplusplus || defined _MSC_VER) +int +yyparse (void *YYPARSE_PARAM) +#else +int +yyparse (YYPARSE_PARAM) + void *YYPARSE_PARAM; +#endif +#else /* ! YYPARSE_PARAM */ +#if (defined __STDC__ || defined __C99__FUNC__ \ + || defined __cplusplus || defined _MSC_VER) +int +yyparse (compileContext* context) +#else +int +yyparse (context) + compileContext* context; +#endif +#endif +{ + /* The look-ahead symbol. */ +int yychar; + +/* The semantic value of the look-ahead symbol. */ +YYSTYPE yylval; + +/* Number of syntax errors so far. */ +int yynerrs; +/* Location data for the look-ahead symbol. */ +YYLTYPE yylloc; + + int yystate; + int yyn; + int yyresult; + /* Number of tokens to shift before error messages enabled. */ + int yyerrstatus; + /* Look-ahead token as an internal (translated) token number. */ + int yytoken = 0; +#if YYERROR_VERBOSE + /* Buffer for error messages, and its allocated size. */ + char yymsgbuf[128]; + char *yymsg = yymsgbuf; + YYSIZE_T yymsg_alloc = sizeof yymsgbuf; +#endif + + /* Three stacks and their tools: + `yyss': related to states, + `yyvs': related to semantic values, + `yyls': related to locations. + + Refer to the stacks thru separate pointers, to allow yyoverflow + to reallocate them elsewhere. */ + + /* The state stack. */ + yytype_int16 yyssa[YYINITDEPTH]; + yytype_int16 *yyss = yyssa; + yytype_int16 *yyssp; + + /* The semantic value stack. */ + YYSTYPE yyvsa[YYINITDEPTH]; + YYSTYPE *yyvs = yyvsa; + YYSTYPE *yyvsp; + + /* The location stack. */ + YYLTYPE yylsa[YYINITDEPTH]; + YYLTYPE *yyls = yylsa; + YYLTYPE *yylsp; + /* The locations where the error started and ended. */ + YYLTYPE yyerror_range[2]; + +#define YYPOPSTACK(N) (yyvsp -= (N), yyssp -= (N), yylsp -= (N)) + + YYSIZE_T yystacksize = YYINITDEPTH; + + /* The variables used to return semantic value and location from the + action routines. */ + YYSTYPE yyval; + YYLTYPE yyloc; + + /* The number of symbols on the RHS of the reduced rule. + Keep to zero when no symbol should be popped. */ + int yylen = 0; + + YYDPRINTF ((stderr, "Starting parse\n")); + + yystate = 0; + yyerrstatus = 0; + yynerrs = 0; + yychar = YYEMPTY; /* Cause a token to be read. */ + + /* Initialize stack pointers. + Waste one element of value and location stack + so that they stay on the same level as the state stack. + The wasted elements are never initialized. */ + + yyssp = yyss; + yyvsp = yyvs; + yylsp = yyls; +#if defined YYLTYPE_IS_TRIVIAL && YYLTYPE_IS_TRIVIAL + /* Initialize the default location before parsing starts. */ + yylloc.first_line = yylloc.last_line = 1; + yylloc.first_column = yylloc.last_column = 0; +#endif + + goto yysetstate; + +/*------------------------------------------------------------. +| yynewstate -- Push a new state, which is found in yystate. | +`------------------------------------------------------------*/ + yynewstate: + /* In all cases, when you get here, the value and location stacks + have just been pushed. So pushing a state here evens the stacks. */ + yyssp++; + + yysetstate: + *yyssp = yystate; + + if (yyss + yystacksize - 1 <= yyssp) + { + /* Get the current used size of the three stacks, in elements. */ + YYSIZE_T yysize = yyssp - yyss + 1; + +#ifdef yyoverflow + { + /* Give user a chance to reallocate the stack. Use copies of + these so that the &'s don't force the real ones into + memory. */ + YYSTYPE *yyvs1 = yyvs; + yytype_int16 *yyss1 = yyss; + YYLTYPE *yyls1 = yyls; + + /* Each stack pointer address is followed by the size of the + data in use in that stack, in bytes. This used to be a + conditional around just the two extra args, but that might + be undefined if yyoverflow is a macro. */ + yyoverflow (YY_("memory exhausted"), + &yyss1, yysize * sizeof (*yyssp), + &yyvs1, yysize * sizeof (*yyvsp), + &yyls1, yysize * sizeof (*yylsp), + &yystacksize); + yyls = yyls1; + yyss = yyss1; + yyvs = yyvs1; + } +#else /* no yyoverflow */ +# ifndef YYSTACK_RELOCATE + goto yyexhaustedlab; +# else + /* Extend the stack our own way. */ + if (YYMAXDEPTH <= yystacksize) + goto yyexhaustedlab; + yystacksize *= 2; + if (YYMAXDEPTH < yystacksize) + yystacksize = YYMAXDEPTH; + + { + yytype_int16 *yyss1 = yyss; + union yyalloc *yyptr = + (union yyalloc *) YYSTACK_ALLOC (YYSTACK_BYTES (yystacksize)); + if (! yyptr) + goto yyexhaustedlab; + YYSTACK_RELOCATE (yyss); + YYSTACK_RELOCATE (yyvs); + YYSTACK_RELOCATE (yyls); +# undef YYSTACK_RELOCATE + if (yyss1 != yyssa) + YYSTACK_FREE (yyss1); + } +# endif +#endif /* no yyoverflow */ + + yyssp = yyss + yysize - 1; + yyvsp = yyvs + yysize - 1; + yylsp = yyls + yysize - 1; + + YYDPRINTF ((stderr, "Stack size increased to %lu\n", + (unsigned long int) yystacksize)); + + if (yyss + yystacksize - 1 <= yyssp) + YYABORT; + } + + YYDPRINTF ((stderr, "Entering state %d\n", yystate)); + + goto yybackup; + +/*-----------. +| yybackup. | +`-----------*/ +yybackup: + + /* Do appropriate processing given the current state. Read a + look-ahead token if we need one and don't already have one. */ + + /* First try to decide what to do without reference to look-ahead token. */ + yyn = yypact[yystate]; + if (yyn == YYPACT_NINF) + goto yydefault; + + /* Not known => get a look-ahead token if don't already have one. */ + + /* YYCHAR is either YYEMPTY or YYEOF or a valid look-ahead symbol. */ + if (yychar == YYEMPTY) + { + YYDPRINTF ((stderr, "Reading a token: ")); + yychar = YYLEX; + } + + if (yychar <= YYEOF) + { + yychar = yytoken = YYEOF; + YYDPRINTF ((stderr, "Now at end of input.\n")); + } + else + { + yytoken = YYTRANSLATE (yychar); + YY_SYMBOL_PRINT ("Next token is", yytoken, &yylval, &yylloc); + } + + /* If the proper action on seeing token YYTOKEN is to reduce or to + detect an error, take that action. */ + yyn += yytoken; + if (yyn < 0 || YYLAST < yyn || yycheck[yyn] != yytoken) + goto yydefault; + yyn = yytable[yyn]; + if (yyn <= 0) + { + if (yyn == 0 || yyn == YYTABLE_NINF) + goto yyerrlab; + yyn = -yyn; + goto yyreduce; + } + + if (yyn == YYFINAL) + YYACCEPT; + + /* Count tokens shifted since error; after three, turn off error + status. */ + if (yyerrstatus) + yyerrstatus--; + + /* Shift the look-ahead token. */ + YY_SYMBOL_PRINT ("Shifting", yytoken, &yylval, &yylloc); + + /* Discard the shifted token unless it is eof. */ + if (yychar != YYEOF) + yychar = YYEMPTY; + + yystate = yyn; + *++yyvsp = yylval; + *++yylsp = yylloc; + goto yynewstate; + + +/*-----------------------------------------------------------. +| yydefault -- do the default action for the current state. | +`-----------------------------------------------------------*/ +yydefault: + yyn = yydefact[yystate]; + if (yyn == 0) + goto yyerrlab; + goto yyreduce; + + +/*-----------------------------. +| yyreduce -- Do a reduction. | +`-----------------------------*/ +yyreduce: + /* yyn is the number of a rule to reduce with. */ + yylen = yyr2[yyn]; + + /* If YYLEN is nonzero, implement the default value of the action: + `$$ = $1'. + + Otherwise, the following line sets YYVAL to garbage. + This behavior is undocumented and Bison + users should not rely upon it. Assigning to YYVAL + unconditionally makes the parser a bit smaller, and it avoids a + GCC warning that YYVAL may be used uninitialized. */ + yyval = yyvsp[1-yylen]; + + /* Default location. */ + YYLLOC_DEFAULT (yyloc, (yylsp - yylen), yylen); + YY_REDUCE_PRINT (yyn); + switch (yyn) + { + case 3: +#line 42 "eel2.y" + { + (yyval) = nseel_createMoreParametersOpcode(context,(yyvsp[(1) - (3)]),(yyvsp[(3) - (3)])); + } + break; + + case 5: +#line 50 "eel2.y" + { + ((struct eelStringSegmentRec *)(yyvsp[(1) - (2)]))->_next = (struct eelStringSegmentRec *)(yyvsp[(2) - (2)]); + (yyval) = (yyvsp[(1) - (2)]); + } + break; + + case 6: +#line 58 "eel2.y" + { + if (!((yyval) = nseel_resolve_named_symbol(context, (yyvsp[(1) - (1)]), -1, NULL))) /* convert from purely named to namespace-relative, etc */ + { + yyerror(&yyloc, context, ""); + YYERROR; + } + } + break; + + case 7: +#line 68 "eel2.y" + { + (yyval) = (yyvsp[(2) - (3)]); + } + break; + + case 8: +#line 72 "eel2.y" + { + int err; + if (!((yyval) = nseel_setCompiledFunctionCallParameters(context,(yyvsp[(1) - (7)]), (yyvsp[(3) - (7)]), 0, 0, (yyvsp[(6) - (7)]), &err))) + { + if (err == -1) yyerror(&yylsp[-2], context, ""); + else if (err == 0) yyerror(&yylsp[-6], context, ""); + else yyerror(&yylsp[-3], context, ""); // parameter count wrong + + YYERROR; + } + } + break; + + case 9: +#line 84 "eel2.y" + { + int err; + if (!((yyval) = nseel_setCompiledFunctionCallParameters(context,(yyvsp[(1) - (4)]), (yyvsp[(3) - (4)]), 0, 0, 0, &err))) + { + if (err == 0) yyerror(&yylsp[-3], context, ""); + else yyerror(&yylsp[0], context, ""); // parameter count wrong + YYERROR; + } + } + break; + + case 10: +#line 94 "eel2.y" + { + int err; + if (!((yyval) = nseel_setCompiledFunctionCallParameters(context,(yyvsp[(1) - (3)]), nseel_createCompiledValue(context,0.0), 0, 0, 0,&err))) + { + if (err == 0) yyerror(&yylsp[-2], context, ""); // function not found + else yyerror(&yylsp[0], context, ""); // parameter count wrong + YYERROR; + } + } + break; + + case 11: +#line 104 "eel2.y" + { + int err; + if (!((yyval) = nseel_setCompiledFunctionCallParameters(context,(yyvsp[(1) - (6)]), (yyvsp[(3) - (6)]), (yyvsp[(5) - (6)]), 0, 0,&err))) + { + if (err == 0) yyerror(&yylsp[-5], context, ""); + else if (err == 2) yyerror(&yylsp[0], context, ""); // needs more than 2 parameters + else yyerror(&yylsp[-2], context, ""); // less than 2 + YYERROR; + } + } + break; + + case 12: +#line 115 "eel2.y" + { + int err; + if (!((yyval) = nseel_setCompiledFunctionCallParameters(context,(yyvsp[(1) - (8)]), (yyvsp[(3) - (8)]), (yyvsp[(5) - (8)]), (yyvsp[(7) - (8)]), 0, &err))) + { + if (err == 0) yyerror(&yylsp[-7], context, ""); + else if (err==2) yyerror(&yylsp[0], context, ""); // needs more parameters + else if (err==4) yyerror(&yylsp[-4], context, ""); // needs single parameter + else yyerror(&yylsp[-2], context, ""); // less parm + YYERROR; + } + } + break; + + case 13: +#line 127 "eel2.y" + { + (yyval) = nseel_createMemoryAccess(context,(yyvsp[(1) - (3)]),0); + } + break; + + case 14: +#line 131 "eel2.y" + { + (yyval) = nseel_createMemoryAccess(context,(yyvsp[(1) - (4)]),(yyvsp[(3) - (4)])); + } + break; + + case 17: +#line 140 "eel2.y" + { + (yyval) = nseel_eelMakeOpcodeFromStringSegments(context,(struct eelStringSegmentRec *)(yyvsp[(1) - (1)])); + } + break; + + case 20: +#line 150 "eel2.y" + { + (yyval) = nseel_createSimpleCompiledFunction(context,FN_ASSIGN,2,(yyvsp[(1) - (3)]),(yyvsp[(3) - (3)])); + } + break; + + case 21: +#line 154 "eel2.y" + { + (yyval) = nseel_createSimpleCompiledFunction(context,FN_ADD_OP,2,(yyvsp[(1) - (3)]),(yyvsp[(3) - (3)])); + } + break; + + case 22: +#line 158 "eel2.y" + { + (yyval) = nseel_createSimpleCompiledFunction(context,FN_SUB_OP,2,(yyvsp[(1) - (3)]),(yyvsp[(3) - (3)])); + } + break; + + case 23: +#line 162 "eel2.y" + { + (yyval) = nseel_createSimpleCompiledFunction(context,FN_MOD_OP,2,(yyvsp[(1) - (3)]),(yyvsp[(3) - (3)])); + } + break; + + case 24: +#line 166 "eel2.y" + { + (yyval) = nseel_createSimpleCompiledFunction(context,FN_OR_OP,2,(yyvsp[(1) - (3)]),(yyvsp[(3) - (3)])); + } + break; + + case 25: +#line 170 "eel2.y" + { + (yyval) = nseel_createSimpleCompiledFunction(context,FN_AND_OP,2,(yyvsp[(1) - (3)]),(yyvsp[(3) - (3)])); + } + break; + + case 26: +#line 174 "eel2.y" + { + (yyval) = nseel_createSimpleCompiledFunction(context,FN_XOR_OP,2,(yyvsp[(1) - (3)]),(yyvsp[(3) - (3)])); + } + break; + + case 27: +#line 178 "eel2.y" + { + (yyval) = nseel_createSimpleCompiledFunction(context,FN_DIV_OP,2,(yyvsp[(1) - (3)]),(yyvsp[(3) - (3)])); + } + break; + + case 28: +#line 182 "eel2.y" + { + (yyval) = nseel_createSimpleCompiledFunction(context,FN_MUL_OP,2,(yyvsp[(1) - (3)]),(yyvsp[(3) - (3)])); + } + break; + + case 29: +#line 186 "eel2.y" + { + (yyval) = nseel_createSimpleCompiledFunction(context,FN_POW_OP,2,(yyvsp[(1) - (3)]),(yyvsp[(3) - (3)])); + } + break; + + case 30: +#line 190 "eel2.y" + { + (yyval) = nseel_createFunctionByName(context,"strcpy",2,(yyvsp[(1) - (3)]),(yyvsp[(3) - (3)]),NULL); + } + break; + + case 31: +#line 194 "eel2.y" + { + (yyval) = nseel_createFunctionByName(context,"strcat",2,(yyvsp[(1) - (3)]),(yyvsp[(3) - (3)]),NULL); + } + break; + + case 33: +#line 202 "eel2.y" + { + (yyval) = (yyvsp[(2) - (2)]); + } + break; + + case 34: +#line 206 "eel2.y" + { + (yyval) = nseel_createSimpleCompiledFunction(context,FN_UMINUS,1,(yyvsp[(2) - (2)]),0); + } + break; + + case 35: +#line 210 "eel2.y" + { + (yyval) = nseel_createSimpleCompiledFunction(context,FN_NOT,1,(yyvsp[(2) - (2)]),0); + } + break; + + case 37: +#line 218 "eel2.y" + { + (yyval) = nseel_createSimpleCompiledFunction(context,FN_POW,2,(yyvsp[(1) - (3)]),(yyvsp[(3) - (3)])); + } + break; + + case 39: +#line 226 "eel2.y" + { + (yyval) = nseel_createSimpleCompiledFunction(context,FN_MOD,2,(yyvsp[(1) - (3)]),(yyvsp[(3) - (3)])); + } + break; + + case 40: +#line 230 "eel2.y" + { + (yyval) = nseel_createSimpleCompiledFunction(context,FN_SHL,2,(yyvsp[(1) - (3)]),(yyvsp[(3) - (3)])); + } + break; + + case 41: +#line 234 "eel2.y" + { + (yyval) = nseel_createSimpleCompiledFunction(context,FN_SHR,2,(yyvsp[(1) - (3)]),(yyvsp[(3) - (3)])); + } + break; + + case 43: +#line 242 "eel2.y" + { + (yyval) = nseel_createSimpleCompiledFunction(context,FN_DIVIDE,2,(yyvsp[(1) - (3)]),(yyvsp[(3) - (3)])); + } + break; + + case 45: +#line 251 "eel2.y" + { + (yyval) = nseel_createSimpleCompiledFunction(context,FN_MULTIPLY,2,(yyvsp[(1) - (3)]),(yyvsp[(3) - (3)])); + } + break; + + case 47: +#line 260 "eel2.y" + { + (yyval) = nseel_createSimpleCompiledFunction(context,FN_SUB,2,(yyvsp[(1) - (3)]),(yyvsp[(3) - (3)])); + } + break; + + case 49: +#line 268 "eel2.y" + { + (yyval) = nseel_createSimpleCompiledFunction(context,FN_ADD,2,(yyvsp[(1) - (3)]),(yyvsp[(3) - (3)])); + } + break; + + case 51: +#line 276 "eel2.y" + { + (yyval) = nseel_createSimpleCompiledFunction(context,FN_AND,2,(yyvsp[(1) - (3)]),(yyvsp[(3) - (3)])); + } + break; + + case 52: +#line 280 "eel2.y" + { + (yyval) = nseel_createSimpleCompiledFunction(context,FN_OR,2,(yyvsp[(1) - (3)]),(yyvsp[(3) - (3)])); + } + break; + + case 53: +#line 284 "eel2.y" + { + (yyval) = nseel_createSimpleCompiledFunction(context,FN_XOR,2,(yyvsp[(1) - (3)]),(yyvsp[(3) - (3)])); + } + break; + + case 55: +#line 292 "eel2.y" + { + (yyval) = nseel_createSimpleCompiledFunction(context,FN_LT,2,(yyvsp[(1) - (3)]),(yyvsp[(3) - (3)])); + } + break; + + case 56: +#line 296 "eel2.y" + { + (yyval) = nseel_createSimpleCompiledFunction(context,FN_GT,2,(yyvsp[(1) - (3)]),(yyvsp[(3) - (3)])); + } + break; + + case 57: +#line 300 "eel2.y" + { + (yyval) = nseel_createSimpleCompiledFunction(context,FN_LTE,2,(yyvsp[(1) - (3)]),(yyvsp[(3) - (3)])); + } + break; + + case 58: +#line 304 "eel2.y" + { + (yyval) = nseel_createSimpleCompiledFunction(context,FN_GTE,2,(yyvsp[(1) - (3)]),(yyvsp[(3) - (3)])); + } + break; + + case 59: +#line 308 "eel2.y" + { + (yyval) = nseel_createSimpleCompiledFunction(context,FN_EQ,2,(yyvsp[(1) - (3)]),(yyvsp[(3) - (3)])); + } + break; + + case 60: +#line 312 "eel2.y" + { + (yyval) = nseel_createSimpleCompiledFunction(context,FN_EQ_EXACT,2,(yyvsp[(1) - (3)]),(yyvsp[(3) - (3)])); + } + break; + + case 61: +#line 316 "eel2.y" + { + (yyval) = nseel_createSimpleCompiledFunction(context,FN_NE,2,(yyvsp[(1) - (3)]),(yyvsp[(3) - (3)])); + } + break; + + case 62: +#line 320 "eel2.y" + { + (yyval) = nseel_createSimpleCompiledFunction(context,FN_NE_EXACT,2,(yyvsp[(1) - (3)]),(yyvsp[(3) - (3)])); + } + break; + + case 64: +#line 328 "eel2.y" + { + (yyval) = nseel_createSimpleCompiledFunction(context,FN_LOGICAL_AND,2,(yyvsp[(1) - (3)]),(yyvsp[(3) - (3)])); + } + break; + + case 65: +#line 332 "eel2.y" + { + (yyval) = nseel_createSimpleCompiledFunction(context,FN_LOGICAL_OR,2,(yyvsp[(1) - (3)]),(yyvsp[(3) - (3)])); + } + break; + + case 67: +#line 340 "eel2.y" + { + (yyval) = nseel_createIfElse(context, (yyvsp[(1) - (5)]), (yyvsp[(3) - (5)]), (yyvsp[(5) - (5)])); + } + break; + + case 68: +#line 344 "eel2.y" + { + (yyval) = nseel_createIfElse(context, (yyvsp[(1) - (4)]), 0, (yyvsp[(4) - (4)])); + } + break; + + case 69: +#line 348 "eel2.y" + { + (yyval) = nseel_createIfElse(context, (yyvsp[(1) - (3)]), (yyvsp[(3) - (3)]), 0); + } + break; + + case 71: +#line 357 "eel2.y" + { + (yyval) = nseel_createSimpleCompiledFunction(context,FN_JOIN_STATEMENTS,2,(yyvsp[(1) - (3)]),(yyvsp[(3) - (3)])); + } + break; + + case 72: +#line 361 "eel2.y" + { + (yyval) = (yyvsp[(1) - (2)]); + } + break; + + case 73: +#line 369 "eel2.y" + { + if ((yylsp[(1) - (1)]).first_line) { } + context->result = (yyvsp[(1) - (1)]); + } + break; + + +/* Line 1267 of yacc.c. */ +#line 1965 "y.tab.c" + default: break; + } + YY_SYMBOL_PRINT ("-> $$ =", yyr1[yyn], &yyval, &yyloc); + + YYPOPSTACK (yylen); + yylen = 0; + YY_STACK_PRINT (yyss, yyssp); + + *++yyvsp = yyval; + *++yylsp = yyloc; + + /* Now `shift' the result of the reduction. Determine what state + that goes to, based on the state we popped back to and the rule + number reduced by. */ + + yyn = yyr1[yyn]; + + yystate = yypgoto[yyn - YYNTOKENS] + *yyssp; + if (0 <= yystate && yystate <= YYLAST && yycheck[yystate] == *yyssp) + yystate = yytable[yystate]; + else + yystate = yydefgoto[yyn - YYNTOKENS]; + + goto yynewstate; + + +/*------------------------------------. +| yyerrlab -- here on detecting error | +`------------------------------------*/ +yyerrlab: + /* If not already recovering from an error, report this error. */ + if (!yyerrstatus) + { + ++yynerrs; +#if ! YYERROR_VERBOSE + yyerror (&yylloc, context, YY_("syntax error")); +#else + { + YYSIZE_T yysize = yysyntax_error (0, yystate, yychar); + if (yymsg_alloc < yysize && yymsg_alloc < YYSTACK_ALLOC_MAXIMUM) + { + YYSIZE_T yyalloc = 2 * yysize; + if (! (yysize <= yyalloc && yyalloc <= YYSTACK_ALLOC_MAXIMUM)) + yyalloc = YYSTACK_ALLOC_MAXIMUM; + if (yymsg != yymsgbuf) + YYSTACK_FREE (yymsg); + yymsg = (char *) YYSTACK_ALLOC (yyalloc); + if (yymsg) + yymsg_alloc = yyalloc; + else + { + yymsg = yymsgbuf; + yymsg_alloc = sizeof yymsgbuf; + } + } + + if (0 < yysize && yysize <= yymsg_alloc) + { + (void) yysyntax_error (yymsg, yystate, yychar); + yyerror (&yylloc, context, yymsg); + } + else + { + yyerror (&yylloc, context, YY_("syntax error")); + if (yysize != 0) + goto yyexhaustedlab; + } + } +#endif + } + + yyerror_range[0] = yylloc; + + if (yyerrstatus == 3) + { + /* If just tried and failed to reuse look-ahead token after an + error, discard it. */ + + if (yychar <= YYEOF) + { + /* Return failure if at end of input. */ + if (yychar == YYEOF) + YYABORT; + } + else + { + yydestruct ("Error: discarding", + yytoken, &yylval, &yylloc, context); + yychar = YYEMPTY; + } + } + + /* Else will try to reuse look-ahead token after shifting the error + token. */ + goto yyerrlab1; + + +/*---------------------------------------------------. +| yyerrorlab -- error raised explicitly by YYERROR. | +`---------------------------------------------------*/ +yyerrorlab: + + /* Pacify compilers like GCC when the user code never invokes + YYERROR and the label yyerrorlab therefore never appears in user + code. */ + if (/*CONSTCOND*/ 0) + goto yyerrorlab; + + yyerror_range[0] = yylsp[1-yylen]; + /* Do not reclaim the symbols of the rule which action triggered + this YYERROR. */ + YYPOPSTACK (yylen); + yylen = 0; + YY_STACK_PRINT (yyss, yyssp); + yystate = *yyssp; + goto yyerrlab1; + + +/*-------------------------------------------------------------. +| yyerrlab1 -- common code for both syntax error and YYERROR. | +`-------------------------------------------------------------*/ +yyerrlab1: + yyerrstatus = 3; /* Each real token shifted decrements this. */ + + for (;;) + { + yyn = yypact[yystate]; + if (yyn != YYPACT_NINF) + { + yyn += YYTERROR; + if (0 <= yyn && yyn <= YYLAST && yycheck[yyn] == YYTERROR) + { + yyn = yytable[yyn]; + if (0 < yyn) + break; + } + } + + /* Pop the current state because it cannot handle the error token. */ + if (yyssp == yyss) + YYABORT; + + yyerror_range[0] = *yylsp; + yydestruct ("Error: popping", + yystos[yystate], yyvsp, yylsp, context); + YYPOPSTACK (1); + yystate = *yyssp; + YY_STACK_PRINT (yyss, yyssp); + } + + if (yyn == YYFINAL) + YYACCEPT; + + *++yyvsp = yylval; + + yyerror_range[1] = yylloc; + /* Using YYLLOC is tempting, but would change the location of + the look-ahead. YYLOC is available though. */ + YYLLOC_DEFAULT (yyloc, (yyerror_range - 1), 2); + *++yylsp = yyloc; + + /* Shift the error token. */ + YY_SYMBOL_PRINT ("Shifting", yystos[yyn], yyvsp, yylsp); + + yystate = yyn; + goto yynewstate; + + +/*-------------------------------------. +| yyacceptlab -- YYACCEPT comes here. | +`-------------------------------------*/ +yyacceptlab: + yyresult = 0; + goto yyreturn; + +/*-----------------------------------. +| yyabortlab -- YYABORT comes here. | +`-----------------------------------*/ +yyabortlab: + yyresult = 1; + goto yyreturn; + +#ifndef yyoverflow +/*-------------------------------------------------. +| yyexhaustedlab -- memory exhaustion comes here. | +`-------------------------------------------------*/ +yyexhaustedlab: + yyerror (&yylloc, context, YY_("memory exhausted")); + yyresult = 2; + /* Fall through. */ +#endif + +yyreturn: + if (yychar != YYEOF && yychar != YYEMPTY) + yydestruct ("Cleanup: discarding lookahead", + yytoken, &yylval, &yylloc, context); + /* Do not reclaim the symbols of the rule which action triggered + this YYABORT or YYACCEPT. */ + YYPOPSTACK (yylen); + YY_STACK_PRINT (yyss, yyssp); + while (yyssp != yyss) + { + yydestruct ("Cleanup: popping", + yystos[*yyssp], yyvsp, yylsp, context); + YYPOPSTACK (1); + } +#ifndef yyoverflow + if (yyss != yyssa) + YYSTACK_FREE (yyss); +#endif +#if YYERROR_VERBOSE + if (yymsg != yymsgbuf) + YYSTACK_FREE (yymsg); +#endif + /* Make sure YYID is used. */ + return YYID (yyresult); +} + + +#line 376 "eel2.y" + + diff --git a/Src/ns-eel2/y.tab.h b/Src/ns-eel2/y.tab.h new file mode 100644 index 00000000..c02dacef --- /dev/null +++ b/Src/ns-eel2/y.tab.h @@ -0,0 +1,117 @@ +/* A Bison parser, made by GNU Bison 2.3. */ + +/* Skeleton interface for Bison's Yacc-like parsers in C + + Copyright (C) 1984, 1989, 1990, 2000, 2001, 2002, 2003, 2004, 2005, 2006 + Free Software Foundation, Inc. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. */ + +/* As a special exception, you may create a larger work that contains + part or all of the Bison parser skeleton and distribute that work + under terms of your choice, so long as that work isn't itself a + parser generator using the skeleton or a modified version thereof + as a parser skeleton. Alternatively, if you modify or redistribute + the parser skeleton itself, you may (at your option) remove this + special exception, which will cause the skeleton and the resulting + Bison output files to be licensed under the GNU General Public + License without this special exception. + + This special exception was added by the Free Software Foundation in + version 2.2 of Bison. */ + +/* Tokens. */ +#ifndef YYTOKENTYPE +# define YYTOKENTYPE + /* Put the tokens into the symbol table, so that GDB and other debuggers + know about them. */ + enum yytokentype { + VALUE = 258, + IDENTIFIER = 259, + TOKEN_SHL = 260, + TOKEN_SHR = 261, + TOKEN_LTE = 262, + TOKEN_GTE = 263, + TOKEN_EQ = 264, + TOKEN_EQ_EXACT = 265, + TOKEN_NE = 266, + TOKEN_NE_EXACT = 267, + TOKEN_LOGICAL_AND = 268, + TOKEN_LOGICAL_OR = 269, + TOKEN_ADD_OP = 270, + TOKEN_SUB_OP = 271, + TOKEN_MOD_OP = 272, + TOKEN_OR_OP = 273, + TOKEN_AND_OP = 274, + TOKEN_XOR_OP = 275, + TOKEN_DIV_OP = 276, + TOKEN_MUL_OP = 277, + TOKEN_POW_OP = 278, + STRING_LITERAL = 279, + STRING_IDENTIFIER = 280 + }; +#endif +/* Tokens. */ +#define VALUE 258 +#define IDENTIFIER 259 +#define TOKEN_SHL 260 +#define TOKEN_SHR 261 +#define TOKEN_LTE 262 +#define TOKEN_GTE 263 +#define TOKEN_EQ 264 +#define TOKEN_EQ_EXACT 265 +#define TOKEN_NE 266 +#define TOKEN_NE_EXACT 267 +#define TOKEN_LOGICAL_AND 268 +#define TOKEN_LOGICAL_OR 269 +#define TOKEN_ADD_OP 270 +#define TOKEN_SUB_OP 271 +#define TOKEN_MOD_OP 272 +#define TOKEN_OR_OP 273 +#define TOKEN_AND_OP 274 +#define TOKEN_XOR_OP 275 +#define TOKEN_DIV_OP 276 +#define TOKEN_MUL_OP 277 +#define TOKEN_POW_OP 278 +#define STRING_LITERAL 279 +#define STRING_IDENTIFIER 280 + + + + +#if ! defined YYSTYPE && ! defined YYSTYPE_IS_DECLARED +typedef int YYSTYPE; +# define yystype YYSTYPE /* obsolescent; will be withdrawn */ +# define YYSTYPE_IS_DECLARED 1 +# define YYSTYPE_IS_TRIVIAL 1 +#endif + + + +#if ! defined YYLTYPE && ! defined YYLTYPE_IS_DECLARED +typedef struct YYLTYPE +{ + int first_line; + int first_column; + int last_line; + int last_column; +} YYLTYPE; +# define yyltype YYLTYPE /* obsolescent; will be withdrawn */ +# define YYLTYPE_IS_DECLARED 1 +# define YYLTYPE_IS_TRIVIAL 1 +#endif + + |