feat: add power scaling factor to plot generation in plot.py

The plot.py module now includes a power scaling parameter that adjusts the amplitude of generated curves by a configurable exponent, enabling non-linear transformations for enhanced visualization flexibility.
This commit is contained in:
2025-12-04 05:14:22 +00:00
parent e768ed066c
commit ed69521892
18 changed files with 930 additions and 236 deletions
+35 -4
View File
@@ -1,6 +1,7 @@
#define _POSIX_C_SOURCE 200809L
#include "ir.h"
#include "../runtime/labeltable.h"
#include "../utils/safe_alloc.h"
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
@@ -23,8 +24,10 @@ void rava_instruction_list_destroy(RavaInstructionList_t *list) {
void rava_instruction_list_add(RavaInstructionList_t *list, RavaInstruction_t instr) {
if (list->count >= list->capacity) {
list->capacity *= 2;
list->instructions = realloc(list->instructions,
sizeof(RavaInstruction_t) * list->capacity);
RavaInstruction_t *new_instrs = rava_safe_realloc(list->instructions,
sizeof(RavaInstruction_t) * list->capacity);
if (!new_instrs) return;
list->instructions = new_instrs;
}
list->instructions[list->count++] = instr;
}
@@ -89,7 +92,9 @@ void rava_class_destroy(RavaClass_t *class) {
void rava_class_add_method(RavaClass_t *class, RavaMethod_t *method) {
if (class->method_count >= class->method_capacity) {
size_t new_capacity = class->method_capacity == 0 ? 4 : class->method_capacity * 2;
class->methods = realloc(class->methods, sizeof(RavaMethod_t*) * new_capacity);
RavaMethod_t **new_methods = rava_safe_realloc(class->methods, sizeof(RavaMethod_t*) * new_capacity);
if (!new_methods) return;
class->methods = new_methods;
class->method_capacity = new_capacity;
}
uint32_t h = _method_hash(method->name);
@@ -117,7 +122,9 @@ void rava_program_destroy(RavaProgram_t *program) {
void rava_program_add_class(RavaProgram_t *program, RavaClass_t *class) {
if (program->class_count >= program->class_capacity) {
size_t new_capacity = program->class_capacity == 0 ? 4 : program->class_capacity * 2;
program->classes = realloc(program->classes, sizeof(RavaClass_t*) * new_capacity);
RavaClass_t **new_classes = rava_safe_realloc(program->classes, sizeof(RavaClass_t*) * new_capacity);
if (!new_classes) return;
program->classes = new_classes;
program->class_capacity = new_capacity;
}
program->classes[program->class_count++] = class;
@@ -181,6 +188,26 @@ static void _compute_max_stack(RavaMethod_t *method) {
method->max_stack = max_depth + 16;
}
static void _mark_simple_methods(RavaMethod_t *method) {
if (!method || !method->instructions) return;
method->is_leaf = true;
method->is_simple = (method->instructions->count < 20);
for (size_t i = 0; i < method->instructions->count; i++) {
RavaOpCode_e op = method->instructions->instructions[i].opcode;
if (op == RAVA_OP_CALL || op == RAVA_OP_CALL_STATIC ||
op == RAVA_OP_CALL_RECURSIVE || op == RAVA_OP_CALL_VIRTUAL) {
method->is_leaf = false;
method->is_simple = false;
}
if (op == RAVA_OP_JUMP || op == RAVA_OP_JUMP_IF_TRUE ||
op == RAVA_OP_JUMP_IF_FALSE) {
method->is_simple = false;
}
}
}
void rava_program_prebuild_label_tables(RavaProgram_t *program) {
if (!program) return;
for (size_t i = 0; i < program->class_count; i++) {
@@ -193,6 +220,7 @@ void rava_program_prebuild_label_tables(RavaProgram_t *program) {
if (method->max_stack == 0) {
_compute_max_stack(method);
}
_mark_simple_methods(method);
}
}
}
@@ -222,6 +250,7 @@ static const char* _rava_opcode_name(RavaOpCode_e opcode) {
case RAVA_OP_CALL: return "CALL";
case RAVA_OP_CALL_STATIC: return "CALL_STATIC";
case RAVA_OP_CALL_RECURSIVE: return "CALL_RECURSIVE";
case RAVA_OP_CALL_INLINE: return "CALL_INLINE";
case RAVA_OP_RETURN: return "RETURN";
case RAVA_OP_RETURN_VOID: return "RETURN_VOID";
case RAVA_OP_NEW: return "NEW";
@@ -229,7 +258,9 @@ static const char* _rava_opcode_name(RavaOpCode_e opcode) {
case RAVA_OP_NEW_ARRAY_OF_ARRAYS: return "NEW_ARRAY_OF_ARRAYS";
case RAVA_OP_ARRAY_LENGTH: return "ARRAY_LENGTH";
case RAVA_OP_LOAD_ARRAY: return "LOAD_ARRAY";
case RAVA_OP_LOAD_ARRAY_UNCHECKED: return "LOAD_ARRAY_UNCHECKED";
case RAVA_OP_STORE_ARRAY: return "STORE_ARRAY";
case RAVA_OP_STORE_ARRAY_UNCHECKED: return "STORE_ARRAY_UNCHECKED";
case RAVA_OP_POP: return "POP";
case RAVA_OP_DUP: return "DUP";
case RAVA_OP_PRINT: return "PRINT";
+5
View File
@@ -17,11 +17,13 @@ typedef enum {
RAVA_OP_LOAD_FIELD,
RAVA_OP_LOAD_STATIC,
RAVA_OP_LOAD_ARRAY,
RAVA_OP_LOAD_ARRAY_UNCHECKED,
RAVA_OP_STORE_LOCAL,
RAVA_OP_STORE_FIELD,
RAVA_OP_STORE_STATIC,
RAVA_OP_STORE_ARRAY,
RAVA_OP_STORE_ARRAY_UNCHECKED,
RAVA_OP_ADD,
RAVA_OP_SUB,
@@ -54,6 +56,7 @@ typedef enum {
RAVA_OP_CALL,
RAVA_OP_CALL_STATIC,
RAVA_OP_CALL_RECURSIVE,
RAVA_OP_CALL_INLINE,
RAVA_OP_CALL_VIRTUAL,
RAVA_OP_CALL_SUPER,
RAVA_OP_CALL_NATIVE,
@@ -196,6 +199,8 @@ typedef struct {
int max_stack;
RavaInstructionList_t *instructions;
struct LabelTable_s *label_table;
bool is_leaf;
bool is_simple;
} RavaMethod_t;
#define RAVA_METHOD_HASH_SIZE 16
+96 -8
View File
@@ -245,7 +245,20 @@ static void _rava_ir_gen_expression(RavaIRGenerator_t *gen, RavaASTNode_t *expr)
_rava_ir_gen_expression(gen, expr->data.assign.target->data.array_access.array);
_rava_ir_gen_expression(gen, expr->data.assign.target->data.array_access.index);
_rava_ir_gen_expression(gen, expr->data.assign.value);
instr.opcode = RAVA_OP_STORE_ARRAY;
bool use_unchecked = false;
if (gen->loop_context && gen->loop_context->has_bounds_check) {
RavaASTNode_t *index_node = expr->data.assign.target->data.array_access.index;
if (index_node->type == RAVA_AST_IDENTIFIER_EXPR) {
const char *index_name = index_node->data.identifier.name;
if (gen->loop_context->loop_var_name &&
strcmp(index_name, gen->loop_context->loop_var_name) == 0) {
use_unchecked = true;
}
}
}
instr.opcode = use_unchecked ? RAVA_OP_STORE_ARRAY_UNCHECKED : RAVA_OP_STORE_ARRAY;
_rava_ir_emit(gen, instr);
} else if (expr->data.assign.target->type == RAVA_AST_MEMBER_ACCESS_EXPR) {
RavaASTNode_t *target_member = expr->data.assign.target;
@@ -302,12 +315,25 @@ static void _rava_ir_gen_expression(RavaIRGenerator_t *gen, RavaASTNode_t *expr)
_rava_ir_emit(gen, instr);
break;
case RAVA_AST_ARRAY_ACCESS_EXPR:
case RAVA_AST_ARRAY_ACCESS_EXPR: {
_rava_ir_gen_expression(gen, expr->data.array_access.array);
_rava_ir_gen_expression(gen, expr->data.array_access.index);
instr.opcode = RAVA_OP_LOAD_ARRAY;
bool use_unchecked = false;
if (gen->loop_context && gen->loop_context->has_bounds_check) {
if (expr->data.array_access.index->type == RAVA_AST_IDENTIFIER_EXPR) {
const char *index_name = expr->data.array_access.index->data.identifier.name;
if (gen->loop_context->loop_var_name &&
strcmp(index_name, gen->loop_context->loop_var_name) == 0) {
use_unchecked = true;
}
}
}
instr.opcode = use_unchecked ? RAVA_OP_LOAD_ARRAY_UNCHECKED : RAVA_OP_LOAD_ARRAY;
_rava_ir_emit(gen, instr);
break;
}
case RAVA_AST_NEW_EXPR:
if (expr->data.new_expr.type && expr->data.new_expr.type->data.type.is_array) {
@@ -886,7 +912,14 @@ static void _rava_ir_gen_statement(RavaIRGenerator_t *gen, RavaASTNode_t *stmt)
int start_label = rava_instruction_list_new_label(gen->current_method->instructions);
int end_label = rava_instruction_list_new_label(gen->current_method->instructions);
RavaLoopContext_t loop_ctx = { .break_label = end_label, .continue_label = start_label, .parent = gen->loop_context };
RavaLoopContext_t loop_ctx = {
.break_label = end_label,
.continue_label = start_label,
.parent = gen->loop_context,
.loop_var_name = NULL,
.loop_var_index = -1,
.has_bounds_check = false
};
gen->loop_context = &loop_ctx;
instr.opcode = RAVA_OP_LABEL;
@@ -917,7 +950,14 @@ static void _rava_ir_gen_statement(RavaIRGenerator_t *gen, RavaASTNode_t *stmt)
int start_label = rava_instruction_list_new_label(gen->current_method->instructions);
int end_label = rava_instruction_list_new_label(gen->current_method->instructions);
RavaLoopContext_t loop_ctx = { .break_label = end_label, .continue_label = start_label, .parent = gen->loop_context };
RavaLoopContext_t loop_ctx = {
.break_label = end_label,
.continue_label = start_label,
.parent = gen->loop_context,
.loop_var_name = NULL,
.loop_var_index = -1,
.has_bounds_check = false
};
gen->loop_context = &loop_ctx;
instr.opcode = RAVA_OP_LABEL;
@@ -941,6 +981,33 @@ static void _rava_ir_gen_statement(RavaIRGenerator_t *gen, RavaASTNode_t *stmt)
}
case RAVA_AST_FOR_STMT: {
char *loop_var_name = NULL;
int loop_var_index = -1;
bool has_bounds_check = false;
if (stmt->data.for_stmt.init && stmt->data.for_stmt.init->type == RAVA_AST_VAR_DECL) {
RavaASTNode_t *var_decl = stmt->data.for_stmt.init;
loop_var_name = var_decl->data.var_decl.name;
loop_var_index = (int)gen->next_local;
if (var_decl->data.var_decl.initializer &&
var_decl->data.var_decl.initializer->type == RAVA_AST_LITERAL_EXPR &&
var_decl->data.var_decl.initializer->data.literal.value.int_value == 0) {
if (stmt->data.for_stmt.condition &&
stmt->data.for_stmt.condition->type == RAVA_AST_BINARY_EXPR &&
(stmt->data.for_stmt.condition->data.binary.op == RAVA_BINOP_LT ||
stmt->data.for_stmt.condition->data.binary.op == RAVA_BINOP_LE)) {
RavaASTNode_t *left = stmt->data.for_stmt.condition->data.binary.left;
if (left->type == RAVA_AST_IDENTIFIER_EXPR &&
strcmp(left->data.identifier.name, loop_var_name) == 0) {
has_bounds_check = true;
}
}
}
}
if (stmt->data.for_stmt.init) {
if (stmt->data.for_stmt.init->type == RAVA_AST_VAR_DECL) {
_rava_ir_gen_statement(gen, stmt->data.for_stmt.init);
@@ -955,7 +1022,14 @@ static void _rava_ir_gen_statement(RavaIRGenerator_t *gen, RavaASTNode_t *stmt)
int continue_label = rava_instruction_list_new_label(gen->current_method->instructions);
int end_label = rava_instruction_list_new_label(gen->current_method->instructions);
RavaLoopContext_t loop_ctx = { .break_label = end_label, .continue_label = continue_label, .parent = gen->loop_context };
RavaLoopContext_t loop_ctx = {
.break_label = end_label,
.continue_label = continue_label,
.parent = gen->loop_context,
.loop_var_name = loop_var_name,
.loop_var_index = loop_var_index,
.has_bounds_check = has_bounds_check
};
gen->loop_context = &loop_ctx;
instr.opcode = RAVA_OP_LABEL;
@@ -1012,7 +1086,14 @@ static void _rava_ir_gen_statement(RavaIRGenerator_t *gen, RavaASTNode_t *stmt)
int continue_label = rava_instruction_list_new_label(gen->current_method->instructions);
int end_label = rava_instruction_list_new_label(gen->current_method->instructions);
RavaLoopContext_t loop_ctx = { .break_label = end_label, .continue_label = continue_label, .parent = gen->loop_context };
RavaLoopContext_t loop_ctx = {
.break_label = end_label,
.continue_label = continue_label,
.parent = gen->loop_context,
.loop_var_name = NULL,
.loop_var_index = (int)idx_local,
.has_bounds_check = true
};
gen->loop_context = &loop_ctx;
instr.opcode = RAVA_OP_LABEL;
@@ -1113,7 +1194,14 @@ static void _rava_ir_gen_statement(RavaIRGenerator_t *gen, RavaASTNode_t *stmt)
case RAVA_AST_SWITCH_STMT: {
int end_label = rava_instruction_list_new_label(gen->current_method->instructions);
RavaLoopContext_t switch_ctx = { .break_label = end_label, .continue_label = -1, .parent = gen->loop_context };
RavaLoopContext_t switch_ctx = {
.break_label = end_label,
.continue_label = -1,
.parent = gen->loop_context,
.loop_var_name = NULL,
.loop_var_index = -1,
.has_bounds_check = false
};
gen->loop_context = &switch_ctx;
size_t case_count = stmt->children_count;
+3
View File
@@ -15,6 +15,9 @@ typedef struct RavaLoopContext_t {
int break_label;
int continue_label;
struct RavaLoopContext_t *parent;
char *loop_var_name;
int loop_var_index;
bool has_bounds_check;
} RavaLoopContext_t;
typedef struct {