2025-12-02 06:54:32 +01:00
|
|
|
#include "superinst.h"
|
2025-12-04 06:14:22 +01:00
|
|
|
#include "fastframe.h"
|
2025-12-02 06:54:32 +01:00
|
|
|
#include <string.h>
|
|
|
|
|
|
|
|
|
|
static void optimize_inc_dec_local(RavaInstruction_t *instrs, size_t count) {
|
|
|
|
|
for (size_t i = 0; i + 3 < count; i++) {
|
|
|
|
|
if (instrs[i].opcode == RAVA_OP_LOAD_LOCAL &&
|
|
|
|
|
instrs[i+1].opcode == RAVA_OP_LOAD_CONST &&
|
|
|
|
|
instrs[i+1].operand.int_value == 1 &&
|
|
|
|
|
instrs[i+2].opcode == RAVA_OP_ADD &&
|
|
|
|
|
instrs[i+3].opcode == RAVA_OP_STORE_LOCAL &&
|
|
|
|
|
instrs[i].operand.var.index == instrs[i+3].operand.var.index) {
|
|
|
|
|
|
|
|
|
|
instrs[i].opcode = RAVA_OP_INC_LOCAL;
|
|
|
|
|
instrs[i+1].opcode = RAVA_OP_NOP;
|
|
|
|
|
instrs[i+2].opcode = RAVA_OP_NOP;
|
|
|
|
|
instrs[i+3].opcode = RAVA_OP_NOP;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (instrs[i].opcode == RAVA_OP_LOAD_LOCAL &&
|
|
|
|
|
instrs[i+1].opcode == RAVA_OP_LOAD_CONST &&
|
|
|
|
|
instrs[i+1].operand.int_value == 1 &&
|
|
|
|
|
instrs[i+2].opcode == RAVA_OP_SUB &&
|
|
|
|
|
instrs[i+3].opcode == RAVA_OP_STORE_LOCAL &&
|
|
|
|
|
instrs[i].operand.var.index == instrs[i+3].operand.var.index) {
|
|
|
|
|
|
|
|
|
|
instrs[i].opcode = RAVA_OP_DEC_LOCAL;
|
|
|
|
|
instrs[i+1].opcode = RAVA_OP_NOP;
|
|
|
|
|
instrs[i+2].opcode = RAVA_OP_NOP;
|
|
|
|
|
instrs[i+3].opcode = RAVA_OP_NOP;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void optimize_loop_comparison(RavaInstruction_t *instrs, size_t count) {
|
|
|
|
|
for (size_t i = 0; i + 3 < count; i++) {
|
|
|
|
|
if (instrs[i].opcode == RAVA_OP_LOAD_LOCAL &&
|
|
|
|
|
instrs[i+1].opcode == RAVA_OP_LOAD_CONST &&
|
|
|
|
|
instrs[i+2].opcode == RAVA_OP_LT &&
|
|
|
|
|
instrs[i+3].opcode == RAVA_OP_JUMP_IF_FALSE) {
|
|
|
|
|
|
|
|
|
|
int local_idx = instrs[i].operand.var.index;
|
|
|
|
|
int64_t const_val = instrs[i+1].operand.int_value;
|
|
|
|
|
int label = instrs[i+3].operand.label_id;
|
|
|
|
|
|
|
|
|
|
instrs[i].opcode = RAVA_OP_LOAD_LOCAL_CONST_LT_JUMPFALSE;
|
|
|
|
|
instrs[i].operand.super.local_index = local_idx;
|
|
|
|
|
instrs[i].operand.super.const_value = const_val;
|
|
|
|
|
instrs[i].operand.super.label_id = label;
|
|
|
|
|
|
|
|
|
|
instrs[i+1].opcode = RAVA_OP_NOP;
|
|
|
|
|
instrs[i+2].opcode = RAVA_OP_NOP;
|
|
|
|
|
instrs[i+3].opcode = RAVA_OP_NOP;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (instrs[i].opcode == RAVA_OP_LOAD_LOCAL &&
|
|
|
|
|
instrs[i+1].opcode == RAVA_OP_LOAD_CONST &&
|
|
|
|
|
instrs[i+2].opcode == RAVA_OP_LE &&
|
|
|
|
|
instrs[i+3].opcode == RAVA_OP_JUMP_IF_FALSE) {
|
|
|
|
|
|
|
|
|
|
int local_idx = instrs[i].operand.var.index;
|
|
|
|
|
int64_t const_val = instrs[i+1].operand.int_value;
|
|
|
|
|
int label = instrs[i+3].operand.label_id;
|
|
|
|
|
|
|
|
|
|
instrs[i].opcode = RAVA_OP_LOAD_LOCAL_CONST_LE_JUMPFALSE;
|
|
|
|
|
instrs[i].operand.super.local_index = local_idx;
|
|
|
|
|
instrs[i].operand.super.const_value = const_val;
|
|
|
|
|
instrs[i].operand.super.label_id = label;
|
|
|
|
|
|
|
|
|
|
instrs[i+1].opcode = RAVA_OP_NOP;
|
|
|
|
|
instrs[i+2].opcode = RAVA_OP_NOP;
|
|
|
|
|
instrs[i+3].opcode = RAVA_OP_NOP;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void optimize_two_locals(RavaInstruction_t *instrs, size_t count) {
|
|
|
|
|
for (size_t i = 0; i + 1 < count; i++) {
|
|
|
|
|
if (instrs[i].opcode == RAVA_OP_LOAD_LOCAL &&
|
|
|
|
|
instrs[i+1].opcode == RAVA_OP_LOAD_LOCAL) {
|
|
|
|
|
|
|
|
|
|
int idx1 = instrs[i].operand.var.index;
|
|
|
|
|
int idx2 = instrs[i+1].operand.var.index;
|
|
|
|
|
|
|
|
|
|
instrs[i].opcode = RAVA_OP_LOAD_TWO_LOCALS;
|
|
|
|
|
instrs[i].operand.two_locals.index1 = idx1;
|
|
|
|
|
instrs[i].operand.two_locals.index2 = idx2;
|
|
|
|
|
|
|
|
|
|
instrs[i+1].opcode = RAVA_OP_NOP;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void optimize_add_local_to_local(RavaInstruction_t *instrs, size_t count) {
|
|
|
|
|
for (size_t i = 0; i + 3 < count; i++) {
|
|
|
|
|
if (instrs[i].opcode == RAVA_OP_LOAD_LOCAL &&
|
|
|
|
|
instrs[i+1].opcode == RAVA_OP_LOAD_LOCAL &&
|
|
|
|
|
instrs[i+2].opcode == RAVA_OP_ADD &&
|
|
|
|
|
instrs[i+3].opcode == RAVA_OP_STORE_LOCAL &&
|
|
|
|
|
instrs[i].operand.var.index == instrs[i+3].operand.var.index) {
|
|
|
|
|
|
|
|
|
|
int dest_idx = instrs[i].operand.var.index;
|
|
|
|
|
int src_idx = instrs[i+1].operand.var.index;
|
|
|
|
|
|
|
|
|
|
instrs[i].opcode = RAVA_OP_ADD_LOCAL_TO_LOCAL;
|
|
|
|
|
instrs[i].operand.add_locals.dest_index = dest_idx;
|
|
|
|
|
instrs[i].operand.add_locals.src_index = src_idx;
|
|
|
|
|
|
|
|
|
|
instrs[i+1].opcode = RAVA_OP_NOP;
|
|
|
|
|
instrs[i+2].opcode = RAVA_OP_NOP;
|
|
|
|
|
instrs[i+3].opcode = RAVA_OP_NOP;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void optimize_local_lt_local_jump(RavaInstruction_t *instrs, size_t count) {
|
|
|
|
|
for (size_t i = 0; i + 3 < count; i++) {
|
|
|
|
|
if (instrs[i].opcode == RAVA_OP_LOAD_LOCAL &&
|
|
|
|
|
instrs[i+1].opcode == RAVA_OP_LOAD_LOCAL &&
|
|
|
|
|
instrs[i+2].opcode == RAVA_OP_LT &&
|
|
|
|
|
instrs[i+3].opcode == RAVA_OP_JUMP_IF_FALSE) {
|
|
|
|
|
|
|
|
|
|
int local1 = instrs[i].operand.var.index;
|
|
|
|
|
int local2 = instrs[i+1].operand.var.index;
|
|
|
|
|
int label = instrs[i+3].operand.label_id;
|
|
|
|
|
|
|
|
|
|
instrs[i].opcode = RAVA_OP_LOAD_LOCAL_LT_LOCAL_JUMPFALSE;
|
|
|
|
|
instrs[i].operand.cmp_locals.local1 = local1;
|
|
|
|
|
instrs[i].operand.cmp_locals.local2 = local2;
|
|
|
|
|
instrs[i].operand.cmp_locals.label_id = label;
|
|
|
|
|
|
|
|
|
|
instrs[i+1].opcode = RAVA_OP_NOP;
|
|
|
|
|
instrs[i+2].opcode = RAVA_OP_NOP;
|
|
|
|
|
instrs[i+3].opcode = RAVA_OP_NOP;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2025-12-04 06:14:22 +01:00
|
|
|
static int is_power_of_two(int64_t n) {
|
|
|
|
|
return n > 0 && (n & (n - 1)) == 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static int log2_int(int64_t n) {
|
|
|
|
|
int result = 0;
|
|
|
|
|
while (n > 1) {
|
|
|
|
|
n >>= 1;
|
|
|
|
|
result++;
|
|
|
|
|
}
|
|
|
|
|
return result;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void optimize_strength_reduction(RavaInstruction_t *instrs, size_t count) {
|
|
|
|
|
for (size_t i = 0; i + 2 < count; i++) {
|
|
|
|
|
if (instrs[i+1].opcode == RAVA_OP_LOAD_CONST) {
|
|
|
|
|
int64_t const_val = instrs[i+1].operand.int_value;
|
|
|
|
|
|
|
|
|
|
if (instrs[i+2].opcode == RAVA_OP_MUL && is_power_of_two(const_val)) {
|
|
|
|
|
int shift_amount = log2_int(const_val);
|
|
|
|
|
instrs[i+1].operand.int_value = shift_amount;
|
|
|
|
|
instrs[i+2].opcode = RAVA_OP_SHL;
|
|
|
|
|
}
|
|
|
|
|
else if (instrs[i+2].opcode == RAVA_OP_DIV && is_power_of_two(const_val)) {
|
|
|
|
|
int shift_amount = log2_int(const_val);
|
|
|
|
|
instrs[i+1].operand.int_value = shift_amount;
|
|
|
|
|
instrs[i+2].opcode = RAVA_OP_SHR;
|
|
|
|
|
}
|
|
|
|
|
else if (instrs[i+2].opcode == RAVA_OP_MOD && const_val == 2) {
|
|
|
|
|
instrs[i+1].operand.int_value = 1;
|
|
|
|
|
instrs[i+2].opcode = RAVA_OP_AND;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void optimize_constant_folding(RavaInstruction_t *instrs, size_t count) {
|
|
|
|
|
for (size_t i = 0; i + 2 < count; i++) {
|
|
|
|
|
if (instrs[i].opcode == RAVA_OP_LOAD_CONST &&
|
|
|
|
|
instrs[i+1].opcode == RAVA_OP_LOAD_CONST) {
|
|
|
|
|
|
|
|
|
|
int64_t val1 = instrs[i].operand.int_value;
|
|
|
|
|
int64_t val2 = instrs[i+1].operand.int_value;
|
|
|
|
|
int64_t result = 0;
|
|
|
|
|
int can_fold = 1;
|
|
|
|
|
|
|
|
|
|
switch (instrs[i+2].opcode) {
|
|
|
|
|
case RAVA_OP_ADD:
|
|
|
|
|
result = val1 + val2;
|
|
|
|
|
break;
|
|
|
|
|
case RAVA_OP_SUB:
|
|
|
|
|
result = val1 - val2;
|
|
|
|
|
break;
|
|
|
|
|
case RAVA_OP_MUL:
|
|
|
|
|
result = val1 * val2;
|
|
|
|
|
break;
|
|
|
|
|
case RAVA_OP_DIV:
|
|
|
|
|
if (val2 != 0) {
|
|
|
|
|
result = val1 / val2;
|
|
|
|
|
} else {
|
|
|
|
|
can_fold = 0;
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
case RAVA_OP_MOD:
|
|
|
|
|
if (val2 != 0) {
|
|
|
|
|
result = val1 % val2;
|
|
|
|
|
} else {
|
|
|
|
|
can_fold = 0;
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
case RAVA_OP_AND:
|
|
|
|
|
result = val1 & val2;
|
|
|
|
|
break;
|
|
|
|
|
case RAVA_OP_OR:
|
|
|
|
|
result = val1 | val2;
|
|
|
|
|
break;
|
|
|
|
|
case RAVA_OP_XOR:
|
|
|
|
|
result = val1 ^ val2;
|
|
|
|
|
break;
|
|
|
|
|
case RAVA_OP_SHL:
|
|
|
|
|
result = val1 << val2;
|
|
|
|
|
break;
|
|
|
|
|
case RAVA_OP_SHR:
|
|
|
|
|
result = val1 >> val2;
|
|
|
|
|
break;
|
|
|
|
|
case RAVA_OP_EQ:
|
|
|
|
|
result = val1 == val2;
|
|
|
|
|
break;
|
|
|
|
|
case RAVA_OP_NE:
|
|
|
|
|
result = val1 != val2;
|
|
|
|
|
break;
|
|
|
|
|
case RAVA_OP_LT:
|
|
|
|
|
result = val1 < val2;
|
|
|
|
|
break;
|
|
|
|
|
case RAVA_OP_LE:
|
|
|
|
|
result = val1 <= val2;
|
|
|
|
|
break;
|
|
|
|
|
case RAVA_OP_GT:
|
|
|
|
|
result = val1 > val2;
|
|
|
|
|
break;
|
|
|
|
|
case RAVA_OP_GE:
|
|
|
|
|
result = val1 >= val2;
|
|
|
|
|
break;
|
|
|
|
|
default:
|
|
|
|
|
can_fold = 0;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (can_fold) {
|
|
|
|
|
instrs[i].operand.int_value = result;
|
|
|
|
|
instrs[i+1].opcode = RAVA_OP_NOP;
|
|
|
|
|
instrs[i+2].opcode = RAVA_OP_NOP;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void optimize_inline_calls(RavaInstruction_t *instrs, size_t count) {
|
|
|
|
|
for (size_t i = 0; i < count; i++) {
|
|
|
|
|
if (instrs[i].opcode == RAVA_OP_CALL_STATIC ||
|
|
|
|
|
instrs[i].opcode == RAVA_OP_CALL_RECURSIVE) {
|
|
|
|
|
|
|
|
|
|
RavaMethod_t *target = (RavaMethod_t*)instrs[i].operand.call.cached_method;
|
|
|
|
|
if (target && target->is_simple && target->is_leaf &&
|
|
|
|
|
target->local_count <= RAVA_INLINE_FRAME_LOCALS &&
|
|
|
|
|
target->max_stack <= RAVA_INLINE_FRAME_STACK) {
|
|
|
|
|
|
|
|
|
|
instrs[i].opcode = RAVA_OP_CALL_INLINE;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2025-12-02 06:54:32 +01:00
|
|
|
void rava_optimize_superinstructions(RavaMethod_t* method) {
|
|
|
|
|
if (!method || !method->instructions) return;
|
|
|
|
|
|
|
|
|
|
RavaInstruction_t *instrs = method->instructions->instructions;
|
|
|
|
|
size_t count = method->instructions->count;
|
|
|
|
|
|
2025-12-04 06:14:22 +01:00
|
|
|
optimize_constant_folding(instrs, count);
|
|
|
|
|
optimize_inline_calls(instrs, count);
|
|
|
|
|
optimize_strength_reduction(instrs, count);
|
2025-12-02 06:54:32 +01:00
|
|
|
optimize_add_local_to_local(instrs, count);
|
|
|
|
|
optimize_local_lt_local_jump(instrs, count);
|
|
|
|
|
optimize_inc_dec_local(instrs, count);
|
|
|
|
|
optimize_loop_comparison(instrs, count);
|
|
|
|
|
optimize_two_locals(instrs, count);
|
|
|
|
|
}
|