1
0
mirror of https://github.com/janet-lang/janet synced 2024-06-17 18:59:56 +00:00

Add recursion to the pruning optimization.

This commit is contained in:
Calvin Rose 2023-05-29 18:05:14 -05:00
parent 4782a76bca
commit fcca9bbab3

View File

@ -177,18 +177,22 @@ void janet_bytecode_remove_noops(JanetFuncDef *def) {
* noops. Input is assumed valid bytecode. */ * noops. Input is assumed valid bytecode. */
void janet_bytecode_movopt(JanetFuncDef *def) { void janet_bytecode_movopt(JanetFuncDef *def) {
JanetcRegisterAllocator ra; JanetcRegisterAllocator ra;
janetc_regalloc_init(&ra); int recur = 1;
/* Look for slots that have writes but no reads (and aren't in the closure bitset). */ /* Iterate this until no more instructions can be removed. */
if (def->closure_bitset != NULL) { while (recur) {
for (int32_t i = 0; i < def->slotcount; i++) { janetc_regalloc_init(&ra);
int32_t index = i >> 5;
uint32_t mask = 1U << (((uint32_t) i) & 31); /* Look for slots that have writes but no reads (and aren't in the closure bitset). */
if (def->closure_bitset[index] & mask) { if (def->closure_bitset != NULL) {
janetc_regalloc_touch(&ra, i); for (int32_t i = 0; i < def->slotcount; i++) {
int32_t index = i >> 5;
uint32_t mask = 1U << (((uint32_t) i) & 31);
if (def->closure_bitset[index] & mask) {
janetc_regalloc_touch(&ra, i);
}
} }
} }
}
#define AA ((instr >> 8) & 0xFF) #define AA ((instr >> 8) & 0xFF)
#define BB ((instr >> 16) & 0xFF) #define BB ((instr >> 16) & 0xFF)
@ -196,188 +200,193 @@ void janet_bytecode_movopt(JanetFuncDef *def) {
#define DD (instr >> 8) #define DD (instr >> 8)
#define EE (instr >> 16) #define EE (instr >> 16)
/* Check reads and writes */ /* Check reads and writes */
for (int32_t i = 0; i < def->bytecode_length; i++) { for (int32_t i = 0; i < def->bytecode_length; i++) {
uint32_t instr = def->bytecode[i]; uint32_t instr = def->bytecode[i];
switch (instr & 0x7F) { switch (instr & 0x7F) {
/* Group instructions my how they read from slots */ /* Group instructions my how they read from slots */
/* No reads or writes */ /* No reads or writes */
default: default:
janet_assert(0, "unhandled instruction"); janet_assert(0, "unhandled instruction");
case JOP_JUMP: case JOP_JUMP:
case JOP_NOOP: case JOP_NOOP:
case JOP_RETURN_NIL: case JOP_RETURN_NIL:
/* Write A */ /* Write A */
case JOP_LOAD_INTEGER: case JOP_LOAD_INTEGER:
case JOP_LOAD_CONSTANT: case JOP_LOAD_CONSTANT:
case JOP_LOAD_UPVALUE: case JOP_LOAD_UPVALUE:
case JOP_CLOSURE: case JOP_CLOSURE:
/* Write D */ /* Write D */
case JOP_LOAD_NIL: case JOP_LOAD_NIL:
case JOP_LOAD_TRUE: case JOP_LOAD_TRUE:
case JOP_LOAD_FALSE: case JOP_LOAD_FALSE:
case JOP_LOAD_SELF: case JOP_LOAD_SELF:
case JOP_MAKE_ARRAY: case JOP_MAKE_ARRAY:
case JOP_MAKE_BUFFER: case JOP_MAKE_BUFFER:
case JOP_MAKE_STRING: case JOP_MAKE_STRING:
case JOP_MAKE_STRUCT: case JOP_MAKE_STRUCT:
case JOP_MAKE_TABLE: case JOP_MAKE_TABLE:
case JOP_MAKE_TUPLE: case JOP_MAKE_TUPLE:
case JOP_MAKE_BRACKET_TUPLE: case JOP_MAKE_BRACKET_TUPLE:
break; break;
/* Read A */ /* Read A */
case JOP_ERROR: case JOP_ERROR:
case JOP_TYPECHECK: case JOP_TYPECHECK:
case JOP_JUMP_IF: case JOP_JUMP_IF:
case JOP_JUMP_IF_NOT: case JOP_JUMP_IF_NOT:
case JOP_JUMP_IF_NIL: case JOP_JUMP_IF_NIL:
case JOP_JUMP_IF_NOT_NIL: case JOP_JUMP_IF_NOT_NIL:
case JOP_SET_UPVALUE: case JOP_SET_UPVALUE:
/* Write E, Read A */ /* Write E, Read A */
case JOP_MOVE_FAR: case JOP_MOVE_FAR:
janetc_regalloc_touch(&ra, AA); janetc_regalloc_touch(&ra, AA);
break; break;
/* Read B */ /* Read B */
case JOP_SIGNAL: case JOP_SIGNAL:
/* Write A, Read B */ /* Write A, Read B */
case JOP_ADD_IMMEDIATE: case JOP_ADD_IMMEDIATE:
case JOP_MULTIPLY_IMMEDIATE: case JOP_MULTIPLY_IMMEDIATE:
case JOP_DIVIDE_IMMEDIATE: case JOP_DIVIDE_IMMEDIATE:
case JOP_SHIFT_LEFT_IMMEDIATE: case JOP_SHIFT_LEFT_IMMEDIATE:
case JOP_SHIFT_RIGHT_IMMEDIATE: case JOP_SHIFT_RIGHT_IMMEDIATE:
case JOP_SHIFT_RIGHT_UNSIGNED_IMMEDIATE: case JOP_SHIFT_RIGHT_UNSIGNED_IMMEDIATE:
case JOP_GREATER_THAN_IMMEDIATE: case JOP_GREATER_THAN_IMMEDIATE:
case JOP_LESS_THAN_IMMEDIATE: case JOP_LESS_THAN_IMMEDIATE:
case JOP_EQUALS_IMMEDIATE: case JOP_EQUALS_IMMEDIATE:
case JOP_NOT_EQUALS_IMMEDIATE: case JOP_NOT_EQUALS_IMMEDIATE:
case JOP_GET_INDEX: case JOP_GET_INDEX:
janetc_regalloc_touch(&ra, BB); janetc_regalloc_touch(&ra, BB);
break; break;
/* Read D */ /* Read D */
case JOP_RETURN: case JOP_RETURN:
case JOP_PUSH: case JOP_PUSH:
case JOP_PUSH_ARRAY: case JOP_PUSH_ARRAY:
case JOP_TAILCALL: case JOP_TAILCALL:
janetc_regalloc_touch(&ra, DD); janetc_regalloc_touch(&ra, DD);
break; break;
/* Write A, Read E */ /* Write A, Read E */
case JOP_MOVE_NEAR: case JOP_MOVE_NEAR:
case JOP_LENGTH: case JOP_LENGTH:
case JOP_BNOT: case JOP_BNOT:
case JOP_CALL: case JOP_CALL:
janetc_regalloc_touch(&ra, EE); janetc_regalloc_touch(&ra, EE);
break; break;
/* Read A, B */ /* Read A, B */
case JOP_PUT_INDEX: case JOP_PUT_INDEX:
janetc_regalloc_touch(&ra, AA); janetc_regalloc_touch(&ra, AA);
janetc_regalloc_touch(&ra, BB); janetc_regalloc_touch(&ra, BB);
break; break;
/* Read A, E */ /* Read A, E */
case JOP_PUSH_2: case JOP_PUSH_2:
janetc_regalloc_touch(&ra, AA); janetc_regalloc_touch(&ra, AA);
janetc_regalloc_touch(&ra, EE); janetc_regalloc_touch(&ra, EE);
break; break;
/* Read B, C */ /* Read B, C */
case JOP_PROPAGATE: case JOP_PROPAGATE:
/* Write A, Read B and C */ /* Write A, Read B and C */
case JOP_BAND: case JOP_BAND:
case JOP_BOR: case JOP_BOR:
case JOP_BXOR: case JOP_BXOR:
case JOP_ADD: case JOP_ADD:
case JOP_SUBTRACT: case JOP_SUBTRACT:
case JOP_MULTIPLY: case JOP_MULTIPLY:
case JOP_DIVIDE: case JOP_DIVIDE:
case JOP_MODULO: case JOP_MODULO:
case JOP_REMAINDER: case JOP_REMAINDER:
case JOP_SHIFT_LEFT: case JOP_SHIFT_LEFT:
case JOP_SHIFT_RIGHT: case JOP_SHIFT_RIGHT:
case JOP_SHIFT_RIGHT_UNSIGNED: case JOP_SHIFT_RIGHT_UNSIGNED:
case JOP_GREATER_THAN: case JOP_GREATER_THAN:
case JOP_LESS_THAN: case JOP_LESS_THAN:
case JOP_EQUALS: case JOP_EQUALS:
case JOP_COMPARE: case JOP_COMPARE:
case JOP_IN: case JOP_IN:
case JOP_GET: case JOP_GET:
case JOP_GREATER_THAN_EQUAL: case JOP_GREATER_THAN_EQUAL:
case JOP_LESS_THAN_EQUAL: case JOP_LESS_THAN_EQUAL:
case JOP_NOT_EQUALS: case JOP_NOT_EQUALS:
case JOP_CANCEL: case JOP_CANCEL:
case JOP_RESUME: case JOP_RESUME:
case JOP_NEXT: case JOP_NEXT:
janetc_regalloc_touch(&ra, BB); janetc_regalloc_touch(&ra, BB);
janetc_regalloc_touch(&ra, CC); janetc_regalloc_touch(&ra, CC);
break; break;
/* Read A, B, C */ /* Read A, B, C */
case JOP_PUT: case JOP_PUT:
case JOP_PUSH_3: case JOP_PUSH_3:
janetc_regalloc_touch(&ra, AA); janetc_regalloc_touch(&ra, AA);
janetc_regalloc_touch(&ra, BB); janetc_regalloc_touch(&ra, BB);
janetc_regalloc_touch(&ra, CC); janetc_regalloc_touch(&ra, CC);
break; break;
}
} }
}
/* Iterate and set noops on instructions that make writes that no one ever reads. /* Iterate and set noops on instructions that make writes that no one ever reads.
* Only set noops for instructions with no side effects - moves, loads, etc. that can't * Only set noops for instructions with no side effects - moves, loads, etc. that can't
* raise errors (outside of systemic errors like oom or stack overflow). */ * raise errors (outside of systemic errors like oom or stack overflow). */
for (int32_t i = 0; i < def->bytecode_length; i++) { recur = 0;
uint32_t instr = def->bytecode[i]; for (int32_t i = 0; i < def->bytecode_length; i++) {
switch (instr & 0x7F) { uint32_t instr = def->bytecode[i];
default: switch (instr & 0x7F) {
default:
break;
/* Write D */
case JOP_LOAD_NIL:
case JOP_LOAD_TRUE:
case JOP_LOAD_FALSE:
case JOP_LOAD_SELF:
case JOP_MAKE_ARRAY:
case JOP_MAKE_TUPLE:
case JOP_MAKE_BRACKET_TUPLE: {
if (!janetc_regalloc_check(&ra, DD)) {
def->bytecode[i] = JOP_NOOP;
recur = 1;
}
}
break; break;
/* Write D */ /* Write E, Read A */
case JOP_LOAD_NIL: case JOP_MOVE_FAR: {
case JOP_LOAD_TRUE: if (!janetc_regalloc_check(&ra, EE)) {
case JOP_LOAD_FALSE: def->bytecode[i] = JOP_NOOP;
case JOP_LOAD_SELF: recur = 1;
case JOP_MAKE_ARRAY: }
case JOP_MAKE_TUPLE:
case JOP_MAKE_BRACKET_TUPLE: {
if (!janetc_regalloc_check(&ra, DD)) {
def->bytecode[i] = JOP_NOOP;
} }
} break;
break; /* Write A, Read E */
/* Write E, Read A */ case JOP_MOVE_NEAR:
case JOP_MOVE_FAR: { /* Write A, Read B */
if (!janetc_regalloc_check(&ra, EE)) { case JOP_GET_INDEX:
def->bytecode[i] = JOP_NOOP; /* Write A */
case JOP_LOAD_INTEGER:
case JOP_LOAD_CONSTANT:
case JOP_LOAD_UPVALUE:
case JOP_CLOSURE: {
if (!janetc_regalloc_check(&ra, AA)) {
def->bytecode[i] = JOP_NOOP;
recur = 1;
}
} }
break;
} }
break;
/* Write A, Read E */
case JOP_MOVE_NEAR:
/* Write A, Read B */
case JOP_GET_INDEX:
/* Write A */
case JOP_LOAD_INTEGER:
case JOP_LOAD_CONSTANT:
case JOP_LOAD_UPVALUE:
case JOP_CLOSURE: {
if (!janetc_regalloc_check(&ra, AA)) {
def->bytecode[i] = JOP_NOOP;
}
}
break;
} }
}
janetc_regalloc_deinit(&ra); janetc_regalloc_deinit(&ra);
#undef AA #undef AA
#undef BB #undef BB
#undef CC #undef CC
#undef DD #undef DD
#undef EE #undef EE
}
} }
/* Verify some bytecode */ /* Verify some bytecode */