manually allocate parent scope array

~0.11% performance improvement for safe prim tests
This commit is contained in:
dzaima 2021-07-01 22:57:59 +03:00
parent a6c4f8c84d
commit bad72186de
2 changed files with 52 additions and 41 deletions

View File

@ -445,30 +445,42 @@ static u32 readBytes4(u8* d) {
}
#endif
typedef B JITFn(B* cStack, Scope** pscs, Scope* sc);
typedef B JITFn(B* cStack, Scope* sc);
static inline i32 maxi32(i32 a, i32 b) { return a>b?a:b; }
Nvm_res m_nvm(Body* body) {
ALLOC_ASM(64);
#if ASM_TEST
asm_test();
#endif
Reg r_ENV = 15;
Reg r_PSCS = 14;
Reg r_CS = 3;
Reg r_SC = 12;
PUSH(R_BP);
PUSH(r_ENV);
PUSH(r_PSCS); // Scope* pscs[]
PUSH(r_CS); // starting gStack
PUSH(r_SC); // Scope* sc
MOV(r_CS , R_A0);
MOV(r_PSCS, R_A1);
MOV(r_SC , R_A2);
Reg r_CS = R_P0;
Reg r_SC = R_P1;
Reg r_ENV = R_P2;
u64 pushAm = 0;
PUSH(R_BP ); pushAm++; // idk, rbp; todo make gdb happy
PUSH(r_ENV); pushAm++; // env pointer for quick bytecode pos updating
PUSH(r_CS ); pushAm++; // starting gStack
PUSH(r_SC ); pushAm++; // Scope* sc
u64 lsz = 0; // local variable used up space
#define ALLOCL(NAME,N) u64 NAME##Off = lsz; lsz+= (N)
ALLOCL(pscs, (body->maxPSC+1)*8);
while (((lsz+pushAm*8)&0xf) != 8) lsz++; // lazy way to make sure we're properly aligned
SUBi(R_SP, lsz);
MOV(r_CS, R_A0);
MOV(r_SC, R_A1);
MOV8rp(r_ENV, (u64)&envCurr - 4);
#define VAR(OFF,N) (OFF##Off + (N))
#define VAR8(OFF,N) VAR(OFF,(N)*8)
ADDi(R_A4, 0x12);
MOV8mro(R_SP, R_A1, VAR8(pscs,0));
for (i32 i = 1; i < body->maxPSC+1; i++) {
MOV8rmo(R_A2, R_A2, offsetof(Scope, psc));
MOV8mro(r_PSCS, R_A2, i*8);
MOV8rmo(R_A1, R_A1, offsetof(Scope, psc));
MOV8mro(R_SP, R_A1, VAR8(pscs,i));
}
ADDi(R_A4, 0x34);
if ((u64)i_RETD > I32_MAX || (u64)&gStack > I32_MAX || (u64)&envEnd > I32_MAX) thrM("JIT: Refusing to run with CBQN code outside of the 32-bit address range");
#define CCALL(F) { u64 f=(u64)(F); if(f>I32_MAX)thrM("JIT: Function address too large for call"); CALLi(f-4); }
u32* origBC = body->bc;
@ -494,7 +506,7 @@ Nvm_res m_nvm(Body* body) {
#endif
#define TOPp MOV(R_A0,R_RES)
#define TOPs if (depth) { u8 t = SPOS(R_A3, 0, 0); MOV8mr(t, R_RES); }
#define LSC(R,D) { if(D) MOV8rmo(R,r_PSCS,D*8); else MOV(R,r_SC); }
#define LSC(R,D) { if(D) MOV8rmo(R,R_SP,VAR8(pscs,D)); else MOV(R,r_SC); }
#define INCV(R) INC4mo(R, offsetof(Value,refc)); // ADD4mi(R_A3, 1); CCALL(i_INC);
#ifdef __BMI2__ // TODO move to runtime detection maybe
#define INCB(R,T,U) IMM(T,0xfffffffffffffull);ADD(T,R);IMM(U,0x7fffffffffffeull);CMP(T,U);{JA(lI);MOVi1l(U,0x30);BZHI(U,R,U);INCV(U);LBL1(lI);}
@ -561,9 +573,9 @@ Nvm_res m_nvm(Body* body) {
case EXTO: TOPs; { u64 d=*bc++; IMM(R_A0,*bc++); LSC(R_A1,d); IMM(R_A2,off); INV(3,1,i_EXTO); } break; // (u32 p, Scope* sc, u32* bc, S)
case LOCU: TOPs; { u64 d=*bc++; IMM(R_A0,*bc++); LSC(R_A1,d); CCALL(i_LOCU); } break; // (u32 p, Scope* sc, S)
case EXTU: TOPs; { u64 d=*bc++; IMM(R_A0,*bc++); LSC(R_A1,d); CCALL(i_EXTU); } break; // (u32 p, Scope* sc, S)
case SETN: TOPp; MOV(R_A1,r_PSCS); IMM(R_A2,off); INV(3,0,i_SETN); break; // (B, Scope** pscs, u32* bc, S)
case SETU: TOPp; MOV(R_A1,r_PSCS); IMM(R_A2,off); INV(3,0,i_SETU); break; // (B, Scope** pscs, u32* bc, S)
case SETM: TOPp; MOV(R_A1,r_PSCS); IMM(R_A2,off); INV(3,0,i_SETM); break; // (B, Scope** pscs, u32* bc, S)
case SETN: TOPp; LEAi(R_A1,R_SP,VAR8(pscs,0)); IMM(R_A2,off); INV(3,0,i_SETN); break; // (B, Scope** pscs, u32* bc, S)
case SETU: TOPp; LEAi(R_A1,R_SP,VAR8(pscs,0)); IMM(R_A2,off); INV(3,0,i_SETU); break; // (B, Scope** pscs, u32* bc, S)
case SETM: TOPp; LEAi(R_A1,R_SP,VAR8(pscs,0)); IMM(R_A2,off); INV(3,0,i_SETM); break; // (B, Scope** pscs, u32* bc, S)
case SETNi:TOPp; { u64 d=*bc++; u64 p=*bc++; LSC(R_A1,d); IMM(R_A2,p); IMM(R_A3,off); INV(4,0,i_SETNi); break; } // (B, Scope* sc, u32 p, u32* bc, S)
case SETUi:TOPp; { u64 d=*bc++; u64 p=*bc++; LSC(R_A1,d); IMM(R_A2,p); IMM(R_A3,off); INV(4,0,i_SETUi); break; } // (B, Scope* sc, u32 p, u32* bc, S)
case SETMi:TOPp; { u64 d=*bc++; u64 p=*bc++; LSC(R_A1,d); IMM(R_A2,p); IMM(R_A3,off); INV(4,0,i_SETMi); break; } // (B, Scope* sc, u32 p, u32* bc, S)
@ -588,13 +600,16 @@ Nvm_res m_nvm(Body* body) {
if (ret) break;
}
freeOpt(optRes);
ADDi(R_SP, lsz);
POP(r_SC);
POP(r_CS);
POP(r_PSCS);
POP(r_ENV);
POP(R_BP);
RET();
#undef CCALL
#undef VAR8
#undef VAR
#undef ALLOCL
GET_ASM();
u64 sz = ASM_SIZE;
u8* binEx = nvm_alloc(sz);
@ -619,14 +634,10 @@ Nvm_res m_nvm(Body* body) {
return (Nvm_res){.p = binEx, .refs = optRes.refs};
}
B evalJIT(Body* b, Scope* sc, u8* ptr) { // doesn't consume
u32* bc = b->bc;
pushEnv(sc, bc);
pushEnv(sc, b->bc);
gsReserve(b->maxStack);
Scope* pscs[b->maxPSC+1];
pscs[0] = sc;
// B* sp = gStack;
B r = ((JITFn*)ptr)(gStack, pscs, sc);
B r = ((JITFn*)ptr)(gStack, sc);
// if (sp!=gStack) thrM("uh oh");
popEnv();

View File

@ -20,16 +20,16 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
#include "../utils/talloc.h"
// V - volatile (overwritten by calls)
// 0 rax result
// 1 rcx arg 3
// 2 rdx arg 2
// 3 rbx V
// 4 rsp V stack
// 5 rbp V base
// 6 rsi arg 1
// 7 rdi arg 0
// 8 r8 arg 4
// 9 r9 arg 5
// 0 rax V result
// 1 rcx V arg 3
// 2 rdx V arg 2
// 3 rbx
// 4 rsp stack
// 5 rbp base
// 6 rsi V arg 1
// 7 rdi V arg 0
// 8 r8 V arg 4
// 9 r9 V arg 5
// . r10 V
// . r11 V
// . r12
@ -54,11 +54,11 @@ typedef u8 Reg;
#define R_V0 10
#define R_V1 11
// non-volatile/callee-saved/preserved registers
#define R_P0 3 // rbx
#define R_P1 12 // r12
#define R_P2 13 // r13
#define R_P3 14 // r14
#define R_P4 15 // r15
#define R_P0 3 // rbx
#define R_P1 14 // r14
#define R_P2 15 // r15
#define R_P3 13 // r13
#define R_P4 12 // r12
#define ALLOC_ASM_ARR(N) TStack* b_o = (TStack*)mm_allocN(sizeof(TStack)+(N), t_temp); b_o->size=0; b_o->cap=(N)