feat: implement Phase 4d const-fold transform for select AST
Adds sel_const_fold_pass() — a single-pass bottom-up const-fold that
runs after the Phase 4c flatten loop in parse_select():
4d-1 EQ/NE with either operand SEL_ANY → SEL_TRUE / SEL_FALSE
(checks both child slots — commutativity sort makes SEL_ANY
position non-deterministic after makeSelectNode interning)
4d-2 Identity laws: TRUE&&X→X, X&&TRUE→X, FALSE||X→X, X||FALSE→X
4d-3 Annihilation laws: FALSE&&X→FALSE, TRUE||X→TRUE (symmetric)
4d-4 Complement laws: !TRUE→FALSE, !FALSE→TRUE
Memory semantics:
level==0 (API server): frees orphaned nodes via free_select_node /
sel_free_tree; OOM from makeSelectNode returns original node safely
level>0 (CSE/scheduler): never manually frees; annihilation folds
return the already-interned left/right singleton directly (no
redundant makeSelectNode call); OOM guard unconditional so CSE
mode also degrades gracefully instead of returning NULL
9 new TDD tests added to test_select.c (RED→GREEN verified).
All 166 tests pass (157 prior + 9 Phase 4d).
This commit is contained in:
parent
c2ad96a5e0
commit
b38babb7d6
9 changed files with 3248 additions and 5 deletions
|
|
@ -2,14 +2,121 @@
|
|||
|
||||
#define _RESREQ_H_ 1
|
||||
|
||||
#include <stdatomic.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "kvmgr.h"
|
||||
#include "xlist.h"
|
||||
#include "xvec.h"
|
||||
|
||||
/* ──────────────────────────────────────────────────────────────────────────
|
||||
* Select-expression AST (Phase 3-4 implementation)
|
||||
* ────────────────────────────────────────────────────────────────────────── */
|
||||
|
||||
typedef enum {
|
||||
SEL_AND, /* && — commutative binary */
|
||||
SEL_OR, /* || — commutative binary */
|
||||
SEL_NOT, /* ! — unary */
|
||||
SEL_GT, /* > — numeric only */
|
||||
SEL_LT, /* < — numeric only */
|
||||
SEL_GE, /* >= — numeric only */
|
||||
SEL_LE, /* <= — numeric only */
|
||||
SEL_EQ, /* == — commutative, all types */
|
||||
SEL_NE, /* != — commutative, all types */
|
||||
SEL_RESNAME, /* leaf: resource variable */
|
||||
SEL_NUM, /* leaf: numeric literal */
|
||||
SEL_STR, /* leaf: string literal (xstring-interned) */
|
||||
SEL_ANY, /* leaf: 'any' keyword — eliminated by const-fold */
|
||||
SEL_TRUE, /* leaf: const true — produced by const-fold only */
|
||||
SEL_FALSE, /* leaf: const false — produced by const-fold only */
|
||||
} sel_node_type_t;
|
||||
|
||||
typedef enum {
|
||||
RES_TYPE_NUMERIC = 0, /* float — supports all comparison operators */
|
||||
RES_TYPE_STRING, /* char* — supports == != only */
|
||||
RES_TYPE_BOOL, /* int — standalone boolean use */
|
||||
} res_type_t;
|
||||
|
||||
typedef struct xce_select_node_ xce_select_node_t;
|
||||
struct xce_select_node_ {
|
||||
sel_node_type_t type;
|
||||
uint32_t hashcode;
|
||||
uint32_t node_id;
|
||||
unsigned gc_mark;
|
||||
union {
|
||||
struct {
|
||||
xce_select_node_t *left, *right;
|
||||
} binop; /* AND / OR / GT / LT / GE / LE / EQ / NE */
|
||||
xce_select_node_t* operand; /* NOT */
|
||||
struct {
|
||||
int res_idx;
|
||||
res_type_t res_type;
|
||||
} resname;
|
||||
double numval; /* SEL_NUM */
|
||||
char* strval; /* SEL_STR — xstring-interned */
|
||||
} u;
|
||||
};
|
||||
|
||||
/* Evaluation context forward declarations */
|
||||
typedef struct select_eval_ctx_ select_eval_ctx_t;
|
||||
typedef struct host_eval_ctx_ host_eval_ctx_t;
|
||||
|
||||
/* Scheduler job forward declaration for GC API */
|
||||
typedef struct xce_sched_job_ xce_sched_job_t;
|
||||
|
||||
/* makeSelectNode — intern or allocate a select AST node.
|
||||
* Returns NULL on OOM or intern-table cap exceeded. */
|
||||
extern xce_select_node_t* makeSelectNode(sel_node_type_t type,
|
||||
uintptr_t op1, uintptr_t op2);
|
||||
|
||||
/* Optimization level — set once at process startup.
|
||||
* 0 = disabled (API server); >0 = CSE+memoization (scheduler). */
|
||||
extern void sel_optimize_set(int level);
|
||||
extern int sel_get_optimize_level(void);
|
||||
|
||||
/* Intern table lifecycle */
|
||||
extern void sel_node_table_init(void);
|
||||
extern void sel_node_table_fini(void);
|
||||
|
||||
/* Test-only reset (requires #define UNIT_TEST before this header) */
|
||||
#ifdef UNIT_TEST
|
||||
extern void sel_optimize_test_reset(void);
|
||||
#endif
|
||||
|
||||
/* Evaluation APIs */
|
||||
extern int eval_select(const xce_select_node_t* node, select_eval_ctx_t* ctx);
|
||||
extern int eval_select_simple(const xce_select_node_t* root,
|
||||
const host_eval_ctx_t* host);
|
||||
|
||||
/* Eval context lifecycle */
|
||||
extern void select_eval_ctx_init(select_eval_ctx_t* ctx,
|
||||
const host_eval_ctx_t* host);
|
||||
extern void select_eval_ctx_reset(select_eval_ctx_t* ctx,
|
||||
const host_eval_ctx_t* host);
|
||||
extern void select_eval_ctx_fini(select_eval_ctx_t* ctx);
|
||||
|
||||
/* Mark-and-sweep GC between scheduling sessions */
|
||||
extern void gc_sweep_select_nodes(const xce_sched_job_t** live_jobs,
|
||||
size_t njobs);
|
||||
extern void recompact_node_ids(void);
|
||||
|
||||
/* Flatten AND/OR right-associative chains to left-associative form.
|
||||
* Returns the new root (may differ from the input root).
|
||||
* Sets *changed to 1 if any re-association took place, leaves it unchanged
|
||||
* otherwise (callers must initialise *changed to 0 before the first call).
|
||||
* In level==0 mode: frees orphaned intermediate nodes (NOT their re-parented
|
||||
* children). In CSE mode (level > 0): no explicit freeing — GC owns nodes. */
|
||||
extern xce_select_node_t* sel_flatten_pass(xce_select_node_t* root,
|
||||
int* changed);
|
||||
|
||||
/* Single-pass const-fold transform (Phase 4d).
|
||||
* In level==0: may return a new allocation; frees consumed subtrees.
|
||||
* In CSE mode (level > 0): returns an interned singleton; GC owns nodes. */
|
||||
extern xce_select_node_t* sel_const_fold_pass(xce_select_node_t* node);
|
||||
|
||||
typedef struct xce_resreq_select_ xce_select_t;
|
||||
typedef struct xce_resreq_rusages_ xce_rusages_t;
|
||||
typedef struct xce_resreq_span_ xce_span_t;
|
||||
|
|
@ -34,6 +141,23 @@ typedef struct {
|
|||
xce_resreq_data_t data;
|
||||
} section_context_t;
|
||||
|
||||
/* Maximum allowed select expression length and nesting depth */
|
||||
#define SELECT_MAX_INPUT_LEN 8192
|
||||
#define SELECT_MAX_DEPTH 64
|
||||
|
||||
/* Parse context for xce_select.peg — auxil struct for packcc-generated parser */
|
||||
typedef struct select_context_t_ select_context_t;
|
||||
struct select_context_t_ {
|
||||
var resmgr; /* resource manager for name resolution */
|
||||
const char* input;
|
||||
int pos;
|
||||
int err_pos;
|
||||
int has_error;
|
||||
char errmsg[256]; /* fixed-size — no alloc/free in grammar actions */
|
||||
int depth; /* current nesting depth — guard vs SELECT_MAX_DEPTH */
|
||||
xce_select_node_t* root; /* result root set by grammar top-level action */
|
||||
};
|
||||
|
||||
typedef enum {
|
||||
PER_TASK = 0,
|
||||
PER_JOB,
|
||||
|
|
@ -64,7 +188,9 @@ typedef struct {
|
|||
int decay_flag;
|
||||
} rusage_value_t;
|
||||
|
||||
struct xce_resreq_select_ { };
|
||||
struct xce_resreq_select_ {
|
||||
xce_select_node_t* root;
|
||||
};
|
||||
|
||||
struct xce_resreq_span_ { };
|
||||
|
||||
|
|
@ -106,6 +232,7 @@ typedef struct {
|
|||
} xce_resreq_t;
|
||||
|
||||
typedef struct {
|
||||
var resmgr;
|
||||
const char* input;
|
||||
int pos;
|
||||
int err_pos;
|
||||
|
|
@ -118,13 +245,25 @@ typedef struct {
|
|||
int resreq_fact_count;
|
||||
} resreq_context_t;
|
||||
|
||||
extern res_type_t valtype_to_res_type(int v);
|
||||
|
||||
/* Single comparison point for string-valued resources.
|
||||
* Returns 1 if a == b, 0 otherwise. Named for future wildcard extension. */
|
||||
static inline int xce_str_match(const char* a, const char* b)
|
||||
{
|
||||
return strcmp(a, b) == 0;
|
||||
}
|
||||
|
||||
extern void kill_select(xce_select_t*);
|
||||
extern void sel_free_tree(xce_select_node_t*);
|
||||
extern void kill_section_ctx(section_context_t*);
|
||||
extern void kill_resreq_data(xce_resreq_data_t*);
|
||||
extern int parse_section(xce_resreq_data_t*, char*, char**);
|
||||
extern int parse_rusage(xlist_t*, char*, char**);
|
||||
extern void kill_rusage_value(rusage_value_t*);
|
||||
extern int parse_resreq_primary(xce_primary_resreq_t*, char*, char**);
|
||||
extern int parse_resreq(xce_resreq_t*, char*, char**);
|
||||
extern int parse_resreq_primary(xce_primary_resreq_t*, char*, var, char**);
|
||||
extern void kill_primary_resreq(xce_primary_resreq_t*);
|
||||
extern int parse_resreq(xce_resreq_t*, char*, var, char**);
|
||||
extern void kill_resreq(xce_resreq_t*);
|
||||
extern int format_resreq(char**, xce_resreq_t*);
|
||||
extern int calc_wanted_global_resvals(xvec_idval_t*, var, xlist_t*,
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue