mirror of
https://github.com/Ed94/raddebugger.git
synced 2026-06-13 07:32:23 -07:00
1635 lines
56 KiB
C
1635 lines
56 KiB
C
// Copyright (c) 2024 Epic Games Tools
|
|
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
|
|
|
////////////////////////////////
|
|
//~ allen: EVAL Bytecode Helpers
|
|
|
|
internal String8
|
|
eval_bytecode_from_oplist(Arena *arena, EVAL_OpList *list){
|
|
ProfBeginFunction();
|
|
// allocate output
|
|
U64 size = list->encoded_size;
|
|
U8 *str = push_array_no_zero(arena, U8, size);
|
|
|
|
// iterate loose op nodes
|
|
U8 *ptr = str;
|
|
U8 *opl = str + size;
|
|
for (EVAL_Op *op = list->first_op;
|
|
op != 0;
|
|
op = op->next){
|
|
U32 opcode = op->opcode;
|
|
|
|
switch (opcode){
|
|
default:
|
|
{
|
|
// compute bytecode advance
|
|
U8 ctrlbits = raddbgi_eval_opcode_ctrlbits[opcode];
|
|
U64 extra_byte_count = RADDBGI_DECODEN_FROM_CTRLBITS(ctrlbits);
|
|
|
|
U8 *next_ptr = ptr + 1 + extra_byte_count;
|
|
Assert(next_ptr <= opl);
|
|
|
|
// fill bytecode
|
|
ptr[0] = opcode;
|
|
MemoryCopy(ptr + 1, &op->p, extra_byte_count);
|
|
|
|
// advance output pointer
|
|
ptr = next_ptr;
|
|
}break;
|
|
|
|
case EVAL_IRExtKind_Bytecode:
|
|
{
|
|
// compute bytecode advance
|
|
U64 size = op->bytecode.size;
|
|
U8 *next_ptr = ptr + size;
|
|
Assert(next_ptr <= opl);
|
|
|
|
// fill bytecode
|
|
MemoryCopy(ptr, op->bytecode.str, size);
|
|
|
|
// advance output pointer
|
|
ptr = next_ptr;
|
|
}break;
|
|
}
|
|
}
|
|
|
|
// fill result
|
|
String8 result = {0};
|
|
result.size = size;
|
|
result.str = str;
|
|
ProfEnd();
|
|
return(result);
|
|
}
|
|
|
|
internal void
|
|
eval_oplist_push_op(Arena *arena, EVAL_OpList *list, RADDBGI_EvalOp opcode, U64 p){
|
|
U8 ctrlbits = raddbgi_eval_opcode_ctrlbits[opcode];
|
|
U32 p_size = RADDBGI_DECODEN_FROM_CTRLBITS(ctrlbits);
|
|
|
|
EVAL_Op *node = push_array_no_zero(arena, EVAL_Op, 1);
|
|
node->opcode = opcode;
|
|
node->p = p;
|
|
|
|
SLLQueuePush(list->first_op, list->last_op, node);
|
|
list->op_count += 1;
|
|
list->encoded_size += 1 + p_size;
|
|
}
|
|
|
|
internal void
|
|
eval_oplist_push_uconst(Arena *arena, EVAL_OpList *list, U64 x){
|
|
if (x <= 0xFF){
|
|
eval_oplist_push_op(arena, list, RADDBGI_EvalOp_ConstU8, x);
|
|
}
|
|
else if (x <= 0xFFFF){
|
|
eval_oplist_push_op(arena, list, RADDBGI_EvalOp_ConstU16, x);
|
|
}
|
|
else if (x <= 0xFFFFFFFF){
|
|
eval_oplist_push_op(arena, list, RADDBGI_EvalOp_ConstU32, x);
|
|
}
|
|
else{
|
|
eval_oplist_push_op(arena, list, RADDBGI_EvalOp_ConstU64, x);
|
|
}
|
|
}
|
|
|
|
internal void
|
|
eval_oplist_push_sconst(Arena *arena, EVAL_OpList *list, S64 x){
|
|
if (-0x80 <= x && x <= 0x7F){
|
|
eval_oplist_push_op(arena, list, RADDBGI_EvalOp_ConstU8, (U64)x);
|
|
eval_oplist_push_op(arena, list, RADDBGI_EvalOp_TruncSigned, 8);
|
|
}
|
|
else if (-0x8000 <= x && x <= 0x7FFF){
|
|
eval_oplist_push_op(arena, list, RADDBGI_EvalOp_ConstU16, (U64)x);
|
|
eval_oplist_push_op(arena, list, RADDBGI_EvalOp_TruncSigned, 16);
|
|
}
|
|
else if (-0x80000000ll <= x && x <= 0x7FFFFFFFll){
|
|
eval_oplist_push_op(arena, list, RADDBGI_EvalOp_ConstU32, (U64)x);
|
|
eval_oplist_push_op(arena, list, RADDBGI_EvalOp_TruncSigned, 32);
|
|
}
|
|
else{
|
|
eval_oplist_push_op(arena, list, RADDBGI_EvalOp_ConstU64, (U64)x);
|
|
}
|
|
}
|
|
|
|
internal void
|
|
eval_oplist_push_bytecode(Arena *arena, EVAL_OpList *list, String8 bytecode){
|
|
EVAL_Op *node = push_array_no_zero(arena, EVAL_Op, 1);
|
|
node->opcode = EVAL_IRExtKind_Bytecode;
|
|
node->bytecode = bytecode;
|
|
SLLQueuePush(list->first_op, list->last_op, node);
|
|
list->op_count += 1;
|
|
list->encoded_size += bytecode.size;
|
|
}
|
|
|
|
internal void
|
|
eval_oplist_concat_in_place(EVAL_OpList *left_dst, EVAL_OpList *right_destroyed){
|
|
if (right_destroyed->first_op != 0){
|
|
if (left_dst->first_op == 0){
|
|
MemoryCopyStruct(left_dst, right_destroyed);
|
|
}
|
|
else{
|
|
left_dst->last_op = right_destroyed->last_op;
|
|
left_dst->op_count += right_destroyed->op_count;
|
|
left_dst->encoded_size += right_destroyed->encoded_size;
|
|
}
|
|
MemoryZeroStruct(right_destroyed);
|
|
}
|
|
}
|
|
|
|
////////////////////////////////
|
|
//~ allen: EVAL Expression Info Functions
|
|
|
|
internal RADDBGI_EvalOp
|
|
eval_opcode_from_expr_kind(EVAL_ExprKind kind){
|
|
RADDBGI_EvalOp result = RADDBGI_EvalOp_Stop;
|
|
switch (kind){
|
|
case EVAL_ExprKind_Neg: result = RADDBGI_EvalOp_Neg; break;
|
|
case EVAL_ExprKind_LogNot: result = RADDBGI_EvalOp_LogNot; break;
|
|
case EVAL_ExprKind_BitNot: result = RADDBGI_EvalOp_BitNot; break;
|
|
case EVAL_ExprKind_Mul: result = RADDBGI_EvalOp_Mul; break;
|
|
case EVAL_ExprKind_Div: result = RADDBGI_EvalOp_Div; break;
|
|
case EVAL_ExprKind_Mod: result = RADDBGI_EvalOp_Mod; break;
|
|
case EVAL_ExprKind_Add: result = RADDBGI_EvalOp_Add; break;
|
|
case EVAL_ExprKind_Sub: result = RADDBGI_EvalOp_Sub; break;
|
|
case EVAL_ExprKind_LShift: result = RADDBGI_EvalOp_LShift; break;
|
|
case EVAL_ExprKind_RShift: result = RADDBGI_EvalOp_RShift; break;
|
|
case EVAL_ExprKind_Less: result = RADDBGI_EvalOp_Less; break;
|
|
case EVAL_ExprKind_LsEq: result = RADDBGI_EvalOp_LsEq; break;
|
|
case EVAL_ExprKind_Grtr: result = RADDBGI_EvalOp_Grtr; break;
|
|
case EVAL_ExprKind_GrEq: result = RADDBGI_EvalOp_GrEq; break;
|
|
case EVAL_ExprKind_EqEq: result = RADDBGI_EvalOp_EqEq; break;
|
|
case EVAL_ExprKind_NtEq: result = RADDBGI_EvalOp_NtEq; break;
|
|
case EVAL_ExprKind_BitAnd: result = RADDBGI_EvalOp_BitAnd; break;
|
|
case EVAL_ExprKind_BitXor: result = RADDBGI_EvalOp_BitXor; break;
|
|
case EVAL_ExprKind_BitOr: result = RADDBGI_EvalOp_BitOr; break;
|
|
case EVAL_ExprKind_LogAnd: result = RADDBGI_EvalOp_LogAnd; break;
|
|
case EVAL_ExprKind_LogOr: result = RADDBGI_EvalOp_LogOr; break;
|
|
}
|
|
return(result);
|
|
}
|
|
|
|
internal B32
|
|
eval_expr_kind_is_comparison(EVAL_ExprKind kind){
|
|
B32 result = 0;
|
|
switch (kind){
|
|
case EVAL_ExprKind_EqEq:
|
|
case EVAL_ExprKind_NtEq:
|
|
case EVAL_ExprKind_Less:
|
|
case EVAL_ExprKind_Grtr:
|
|
case EVAL_ExprKind_LsEq:
|
|
case EVAL_ExprKind_GrEq:
|
|
{
|
|
result = 1;
|
|
}break;
|
|
}
|
|
return(result);
|
|
}
|
|
|
|
////////////////////////////////
|
|
//~ allen: EVAL Expression Constructors
|
|
|
|
internal EVAL_Expr*
|
|
eval_expr(Arena *arena, EVAL_ExprKind kind, void *location,
|
|
EVAL_Expr *c0, EVAL_Expr *c1, EVAL_Expr *c2){
|
|
EVAL_Expr *result = push_array(arena, EVAL_Expr, 1);
|
|
result->kind = kind;
|
|
result->location = location;
|
|
result->children[0] = c0;
|
|
result->children[1] = c1;
|
|
result->children[2] = c2;
|
|
return(result);
|
|
}
|
|
|
|
internal EVAL_Expr*
|
|
eval_expr_u64(Arena *arena, void *location, U64 u64){
|
|
EVAL_Expr *result = push_array(arena, EVAL_Expr, 1);
|
|
result->kind = EVAL_ExprKind_LeafU64;
|
|
result->location = location;
|
|
result->u64 = u64;
|
|
return(result);
|
|
}
|
|
|
|
internal EVAL_Expr*
|
|
eval_expr_f64(Arena *arena, void *location, F64 f64){
|
|
EVAL_Expr *result = push_array(arena, EVAL_Expr, 1);
|
|
result->kind = EVAL_ExprKind_LeafF64;
|
|
result->location = location;
|
|
result->f64 = f64;
|
|
return(result);
|
|
}
|
|
|
|
internal EVAL_Expr*
|
|
eval_expr_f32(Arena *arena, void *location, F32 f32){
|
|
EVAL_Expr *result = push_array(arena, EVAL_Expr, 1);
|
|
result->kind = EVAL_ExprKind_LeafF32;
|
|
result->location = location;
|
|
result->f32 = f32;
|
|
return(result);
|
|
}
|
|
|
|
internal EVAL_Expr*
|
|
eval_expr_child_and_u64(Arena *arena, EVAL_ExprKind kind, void *location,
|
|
EVAL_Expr *child, U64 u64){
|
|
EVAL_Expr *result = push_array(arena, EVAL_Expr, 1);
|
|
result->kind = kind;
|
|
result->location = location;
|
|
result->child_and_constant.child = child;
|
|
result->child_and_constant.u64 = u64;
|
|
return(result);
|
|
}
|
|
|
|
internal EVAL_Expr*
|
|
eval_expr_leaf_member(Arena *arena, void *location, String8 name){
|
|
EVAL_Expr *result = push_array(arena, EVAL_Expr, 1);
|
|
result->location = location;
|
|
result->kind = EVAL_ExprKind_LeafMember;
|
|
result->name = name;
|
|
return(result);
|
|
}
|
|
|
|
internal EVAL_Expr*
|
|
eval_expr_leaf_ident(Arena *arena, void *location, String8 name)
|
|
{
|
|
EVAL_Expr *result = push_array(arena, EVAL_Expr, 1);
|
|
result->location = location;
|
|
result->kind = EVAL_ExprKind_LeafIdent;
|
|
result->name = name;
|
|
return(result);
|
|
}
|
|
|
|
internal EVAL_Expr*
|
|
eval_expr_leaf_bytecode(Arena *arena, void *location, TG_Key type_key, String8 bytecode, EVAL_EvalMode mode){
|
|
EVAL_Expr *result = push_array(arena, EVAL_Expr, 1);
|
|
result->location = location;
|
|
result->kind = EVAL_ExprKind_LeafBytecode;
|
|
result->type_key = type_key;
|
|
result->bytecode = bytecode;
|
|
result->mode = mode;
|
|
return(result);
|
|
}
|
|
|
|
internal EVAL_Expr*
|
|
eval_expr_leaf_op_list(Arena *arena, void *location, TG_Key type_key, EVAL_OpList *ops, EVAL_EvalMode mode){
|
|
String8 bytecode = eval_bytecode_from_oplist(arena, ops);
|
|
EVAL_Expr *result = eval_expr_leaf_bytecode(arena, location, type_key, bytecode, mode);
|
|
return(result);
|
|
}
|
|
|
|
internal EVAL_Expr*
|
|
eval_expr_leaf_type(Arena *arena, void *location, TG_Key type_key){
|
|
EVAL_Expr *result = push_array(arena, EVAL_Expr, 1);
|
|
result->location = location;
|
|
result->kind = EVAL_ExprKind_TypeIdent;
|
|
result->type_key = type_key;
|
|
return(result);
|
|
}
|
|
|
|
////////////////////////////////
|
|
//~ allen: EVAL Type Information Transformers
|
|
|
|
internal RADDBGI_EvalTypeGroup
|
|
eval_type_group_from_kind(TG_Kind kind){
|
|
RADDBGI_EvalTypeGroup result = 0;
|
|
switch (kind){
|
|
default:{}break;
|
|
|
|
case TG_Kind_Null: case TG_Kind_Void:
|
|
case TG_Kind_F16: case TG_Kind_F32PP: case TG_Kind_F48:
|
|
case TG_Kind_F80: case TG_Kind_F128:
|
|
case TG_Kind_ComplexF32: case TG_Kind_ComplexF64:
|
|
case TG_Kind_ComplexF80: case TG_Kind_ComplexF128:
|
|
case TG_Kind_Modifier: case TG_Kind_Array:
|
|
case TG_Kind_Struct: case TG_Kind_Class: case TG_Kind_Union:
|
|
case TG_Kind_Enum: case TG_Kind_Alias:
|
|
case TG_Kind_IncompleteStruct: case TG_Kind_IncompleteClass:
|
|
case TG_Kind_IncompleteUnion: case TG_Kind_IncompleteEnum:
|
|
case TG_Kind_Bitfield: case TG_Kind_Variadic:
|
|
result = RADDBGI_EvalTypeGroup_Other; break;
|
|
|
|
case TG_Kind_Handle:
|
|
case TG_Kind_UChar8: case TG_Kind_UChar16: case TG_Kind_UChar32:
|
|
case TG_Kind_U8: case TG_Kind_U16: case TG_Kind_U32:
|
|
case TG_Kind_U64: case TG_Kind_U128: case TG_Kind_U256:
|
|
case TG_Kind_U512:
|
|
case TG_Kind_Ptr: case TG_Kind_LRef: case TG_Kind_RRef:
|
|
case TG_Kind_Function: case TG_Kind_Method: case TG_Kind_MemberPtr:
|
|
result = RADDBGI_EvalTypeGroup_U; break;
|
|
|
|
case TG_Kind_Char8: case TG_Kind_Char16: case TG_Kind_Char32:
|
|
case TG_Kind_S8: case TG_Kind_S16: case TG_Kind_S32:
|
|
case TG_Kind_S64: case TG_Kind_S128: case TG_Kind_S256:
|
|
case TG_Kind_S512:
|
|
case TG_Kind_Bool:
|
|
result = RADDBGI_EvalTypeGroup_S; break;
|
|
|
|
case TG_Kind_F32:
|
|
result = RADDBGI_EvalTypeGroup_F32; break;
|
|
|
|
case TG_Kind_F64:
|
|
result = RADDBGI_EvalTypeGroup_F64; break;
|
|
}
|
|
return(result);
|
|
}
|
|
|
|
internal TG_Key
|
|
eval_type_unwrap_enum(TG_Graph *graph, RADDBGI_Parsed *rdbg, TG_Key key)
|
|
{
|
|
TG_Key result = key;
|
|
for(B32 good = 1; good;)
|
|
{
|
|
TG_Kind kind = tg_kind_from_key(key);
|
|
if(kind == TG_Kind_Enum)
|
|
{
|
|
result = tg_direct_from_graph_raddbgi_key(graph, rdbg, result);
|
|
}
|
|
else
|
|
{
|
|
good = 0;
|
|
}
|
|
}
|
|
return result;
|
|
}
|
|
|
|
internal TG_Key
|
|
eval_type_promote(TG_Graph *graph, RADDBGI_Parsed *rdbg, TG_Key key){
|
|
TG_Key result = key;
|
|
TG_Kind kind = tg_kind_from_key(key);
|
|
if(kind == TG_Kind_Bool ||
|
|
kind == TG_Kind_S8 ||
|
|
kind == TG_Kind_S16 ||
|
|
kind == TG_Kind_U8 ||
|
|
kind == TG_Kind_U16)
|
|
{
|
|
result = tg_key_basic(TG_Kind_S32);
|
|
}
|
|
return result;
|
|
}
|
|
|
|
internal TG_Key
|
|
eval_type_coerce(TG_Graph *graph, RADDBGI_Parsed *rdbg, TG_Key l, TG_Key r){
|
|
Assert(eval_kind_is_basic_or_enum(tg_kind_from_key(l)) &&
|
|
eval_kind_is_basic_or_enum(tg_kind_from_key(r)));
|
|
|
|
// replace enums with corresponding ints
|
|
TG_Key lt = eval_type_unwrap_enum(graph, rdbg, l);
|
|
TG_Key rt = eval_type_unwrap_enum(graph, rdbg, r);
|
|
|
|
// first promote each
|
|
TG_Key lp = eval_type_promote(graph, rdbg, lt);
|
|
TG_Key rp = eval_type_promote(graph, rdbg, rt);
|
|
TG_Kind lk = tg_kind_from_key(lp);
|
|
TG_Kind rk = tg_kind_from_key(rp);
|
|
|
|
TG_Key result = l;
|
|
return(result);
|
|
}
|
|
|
|
internal B32
|
|
eval_type_match(TG_Graph *graph, RADDBGI_Parsed *rdbg, TG_Key l, TG_Key r){
|
|
B32 result = 0;
|
|
|
|
// unwrap
|
|
TG_Key lu = tg_unwrapped_from_graph_raddbgi_key(graph, rdbg, l);
|
|
TG_Key ru = tg_unwrapped_from_graph_raddbgi_key(graph, rdbg, r);
|
|
|
|
if (tg_key_match(lu, ru)){
|
|
result = 1;
|
|
}
|
|
else{
|
|
TG_Kind luk = tg_kind_from_key(lu);
|
|
TG_Kind ruk = tg_kind_from_key(ru);
|
|
if (luk == ruk){
|
|
switch (luk){
|
|
default:
|
|
{
|
|
result = 1;
|
|
}break;
|
|
|
|
case TG_Kind_Ptr:
|
|
case TG_Kind_LRef:
|
|
case TG_Kind_RRef:
|
|
{
|
|
TG_Key lud = tg_direct_from_graph_raddbgi_key(graph, rdbg, lu);
|
|
TG_Key rud = tg_direct_from_graph_raddbgi_key(graph, rdbg, ru);
|
|
if (eval_type_match(graph, rdbg, lud, rud)){
|
|
result = 1;
|
|
}
|
|
}break;
|
|
|
|
case TG_Kind_MemberPtr:
|
|
{
|
|
TG_Key lud = tg_direct_from_graph_raddbgi_key(graph, rdbg, lu);
|
|
TG_Key rud = tg_direct_from_graph_raddbgi_key(graph, rdbg, ru);
|
|
TG_Key luo = tg_owner_from_graph_raddbgi_key(graph, rdbg, lu);
|
|
TG_Key ruo = tg_owner_from_graph_raddbgi_key(graph, rdbg, ru);
|
|
if (eval_type_match(graph, rdbg, lud, rud) &&
|
|
eval_type_match(graph, rdbg, luo, ruo)){
|
|
result = 1;
|
|
}
|
|
}break;
|
|
|
|
case TG_Kind_Array:
|
|
{
|
|
Temp scratch = scratch_begin(0, 0);
|
|
TG_Type *lt = tg_type_from_graph_raddbgi_key(scratch.arena, graph, rdbg, l);
|
|
TG_Type *rt = tg_type_from_graph_raddbgi_key(scratch.arena, graph, rdbg, r);
|
|
if(lt->count == rt->count && eval_type_match(graph, rdbg, lt->direct_type_key, rt->direct_type_key))
|
|
{
|
|
result = 1;
|
|
}
|
|
scratch_end(scratch);
|
|
}break;
|
|
|
|
case TG_Kind_Function:
|
|
{
|
|
Temp scratch = scratch_begin(0, 0);
|
|
TG_Type *lt = tg_type_from_graph_raddbgi_key(scratch.arena, graph, rdbg, l);
|
|
TG_Type *rt = tg_type_from_graph_raddbgi_key(scratch.arena, graph, rdbg, r);
|
|
if (lt->count == rt->count && eval_type_match(graph, rdbg, lt->direct_type_key, rt->direct_type_key))
|
|
{
|
|
B32 params_match = 1;
|
|
TG_Key *lp = lt->param_type_keys;
|
|
TG_Key *rp = rt->param_type_keys;
|
|
U64 count = lt->count;
|
|
for(U64 i = 0; i < count; i += 1, lp += 1, rp += 1)
|
|
{
|
|
if(!eval_type_match(graph, rdbg, *lp, *rp))
|
|
{
|
|
params_match = 0;
|
|
break;
|
|
}
|
|
}
|
|
result = params_match;
|
|
}
|
|
scratch_end(scratch);
|
|
}break;
|
|
|
|
case TG_Kind_Method:
|
|
{
|
|
Temp scratch = scratch_begin(0, 0);
|
|
TG_Type *lt = tg_type_from_graph_raddbgi_key(scratch.arena, graph, rdbg, l);
|
|
TG_Type *rt = tg_type_from_graph_raddbgi_key(scratch.arena, graph, rdbg, r);
|
|
if (lt->count == rt->count &&
|
|
eval_type_match(graph, rdbg, lt->direct_type_key, rt->direct_type_key) &&
|
|
eval_type_match(graph, rdbg, lt->owner_type_key, rt->owner_type_key))
|
|
{
|
|
B32 params_match = 1;
|
|
TG_Key *lp = lt->param_type_keys;
|
|
TG_Key *rp = rt->param_type_keys;
|
|
U64 count = lt->count;
|
|
for(U64 i = 0; i < count; i += 1, lp += 1, rp += 1)
|
|
{
|
|
if(!eval_type_match(graph, rdbg, *lp, *rp))
|
|
{
|
|
params_match = 0;
|
|
break;
|
|
}
|
|
}
|
|
result = params_match;
|
|
}
|
|
scratch_end(scratch);
|
|
}break;
|
|
}
|
|
}
|
|
}
|
|
|
|
return(result);
|
|
}
|
|
|
|
internal B32
|
|
eval_kind_is_integer(TG_Kind kind){
|
|
B32 result = (TG_Kind_FirstInteger <= kind && kind <= TG_Kind_LastInteger);
|
|
return(result);
|
|
}
|
|
|
|
internal B32
|
|
eval_kind_is_signed(TG_Kind kind){
|
|
B32 result = ((TG_Kind_FirstSigned1 <= kind && kind <= TG_Kind_LastSigned1) ||
|
|
(TG_Kind_FirstSigned2 <= kind && kind <= TG_Kind_LastSigned2));
|
|
return(result);
|
|
}
|
|
|
|
internal B32
|
|
eval_kind_is_basic_or_enum(TG_Kind kind){
|
|
B32 result = ((TG_Kind_FirstBasic <= kind && kind <= TG_Kind_LastBasic) ||
|
|
kind == TG_Kind_Enum);
|
|
return(result);
|
|
}
|
|
|
|
|
|
////////////////////////////////
|
|
//~ allen: EVAL IR-Tree Constructors
|
|
|
|
internal EVAL_IRTree*
|
|
eval_irtree_const_u(Arena *arena, U64 v){
|
|
// choose encoding op
|
|
RADDBGI_EvalOp op = RADDBGI_EvalOp_ConstU64;
|
|
if (v < 0x100){
|
|
op = RADDBGI_EvalOp_ConstU8;
|
|
}
|
|
else if (v < 0x10000){
|
|
op = RADDBGI_EvalOp_ConstU16;
|
|
}
|
|
else if (v < 0x100000000){
|
|
op = RADDBGI_EvalOp_ConstU32;
|
|
}
|
|
|
|
// make the tree node
|
|
EVAL_IRTree *result = push_array(arena, EVAL_IRTree, 1);
|
|
result->op = op;
|
|
result->p = v;
|
|
return(result);
|
|
}
|
|
|
|
internal EVAL_IRTree*
|
|
eval_irtree_unary_op(Arena *arena, RADDBGI_EvalOp op,
|
|
RADDBGI_EvalTypeGroup group, EVAL_IRTree *c){
|
|
EVAL_IRTree *result = push_array(arena, EVAL_IRTree, 1);
|
|
result->op = op;
|
|
result->p = group;
|
|
result->children[0] = c;
|
|
return(result);
|
|
}
|
|
|
|
internal EVAL_IRTree*
|
|
eval_irtree_binary_op(Arena *arena, RADDBGI_EvalOp op, RADDBGI_EvalTypeGroup group,
|
|
EVAL_IRTree *l, EVAL_IRTree *r){
|
|
EVAL_IRTree *result = push_array(arena, EVAL_IRTree, 1);
|
|
result->op = op;
|
|
result->p = group;
|
|
result->children[0] = l;
|
|
result->children[1] = r;
|
|
return(result);
|
|
}
|
|
|
|
internal EVAL_IRTree*
|
|
eval_irtree_binary_op_u(Arena *arena, RADDBGI_EvalOp op, EVAL_IRTree *l, EVAL_IRTree *r){
|
|
EVAL_IRTree *result = eval_irtree_binary_op(arena, op, RADDBGI_EvalTypeGroup_U, l, r);
|
|
return(result);
|
|
}
|
|
|
|
internal EVAL_IRTree*
|
|
eval_irtree_conditional(Arena *arena, EVAL_IRTree *c, EVAL_IRTree *l, EVAL_IRTree *r){
|
|
EVAL_IRTree *result = push_array(arena, EVAL_IRTree, 1);
|
|
result->op = RADDBGI_EvalOp_Cond;
|
|
result->children[0] = c;
|
|
result->children[1] = l;
|
|
result->children[2] = r;
|
|
return(result);
|
|
}
|
|
|
|
internal EVAL_IRTree*
|
|
eval_irtree_bytecode_no_copy(Arena *arena, String8 bytecode){
|
|
EVAL_IRTree *result = push_array(arena, EVAL_IRTree, 1);
|
|
result->op = EVAL_IRExtKind_Bytecode;
|
|
result->bytecode = bytecode;
|
|
return(result);
|
|
}
|
|
|
|
////////////////////////////////
|
|
//~ allen: EVAL IR-Tree High Level Helpers
|
|
|
|
internal EVAL_IRTree*
|
|
eval_irtree_mem_read_type(Arena *arena, TG_Graph *graph, RADDBGI_Parsed *rdbg, EVAL_IRTree *c, TG_Key type_key){
|
|
U64 byte_size = tg_byte_size_from_graph_raddbgi_key(graph, rdbg, type_key);
|
|
EVAL_IRTree *result = &eval_irtree_nil;
|
|
if (0 < byte_size && byte_size <= 8){
|
|
// build the read node
|
|
EVAL_IRTree *read_node = push_array(arena, EVAL_IRTree, 1);
|
|
read_node->op = RADDBGI_EvalOp_MemRead;
|
|
read_node->p = byte_size;
|
|
read_node->children[0] = c;
|
|
|
|
// build a signed trunc node if needed
|
|
U64 bit_size = byte_size << 3;
|
|
EVAL_IRTree *with_trunc = read_node;
|
|
TG_Kind kind = tg_kind_from_key(type_key);
|
|
if (bit_size < 64 && eval_kind_is_signed(kind)){
|
|
with_trunc = push_array(arena, EVAL_IRTree, 1);
|
|
with_trunc->op = RADDBGI_EvalOp_TruncSigned;
|
|
with_trunc->p = bit_size;
|
|
with_trunc->children[0] = read_node;
|
|
}
|
|
|
|
// set result
|
|
result = with_trunc;
|
|
}
|
|
else{
|
|
// TODO: unexpected path
|
|
}
|
|
return(result);
|
|
}
|
|
|
|
internal EVAL_IRTree*
|
|
eval_irtree_convert_lo(Arena *arena, EVAL_IRTree *c, RADDBGI_EvalTypeGroup out, RADDBGI_EvalTypeGroup in){
|
|
EVAL_IRTree *result = push_array(arena, EVAL_IRTree, 1);
|
|
result->op = RADDBGI_EvalOp_Convert;
|
|
result->p = in | (out << 8);
|
|
result->children[0] = c;
|
|
return(result);
|
|
}
|
|
|
|
internal EVAL_IRTree*
|
|
eval_irtree_trunc(Arena *arena, TG_Graph *graph, RADDBGI_Parsed *rdbg, EVAL_IRTree *c, TG_Key type_key){
|
|
EVAL_IRTree *result = c;
|
|
U64 byte_size = tg_byte_size_from_graph_raddbgi_key(graph, rdbg, type_key);
|
|
if (byte_size < 64){
|
|
RADDBGI_EvalOp op = RADDBGI_EvalOp_Trunc;
|
|
TG_Kind kind = tg_kind_from_key(type_key);
|
|
if (eval_kind_is_signed(kind)){
|
|
op = RADDBGI_EvalOp_TruncSigned;
|
|
}
|
|
U64 bit_size = byte_size << 3;
|
|
result = push_array(arena, EVAL_IRTree, 1);
|
|
result->op = op;
|
|
result->p = bit_size;
|
|
result->children[0] = c;
|
|
}
|
|
return(result);
|
|
}
|
|
|
|
internal EVAL_IRTree*
|
|
eval_irtree_convert_hi(Arena *arena, TG_Graph *graph, RADDBGI_Parsed *rdbg, EVAL_IRTree *c, TG_Key out, TG_Key in){
|
|
EVAL_IRTree *result = c;
|
|
TG_Kind in_kind = tg_kind_from_key(in);
|
|
TG_Kind out_kind = tg_kind_from_key(out);
|
|
U8 in_group = eval_type_group_from_kind(in_kind);
|
|
U8 out_group = eval_type_group_from_kind(out_kind);
|
|
U32 conversion_rule = raddbgi_eval_conversion_rule(in_group, out_group);
|
|
if(conversion_rule == RADDBGI_EvalConversionKind_Legal)
|
|
{
|
|
result = eval_irtree_convert_lo(arena, result, out_group, in_group);
|
|
}
|
|
U64 in_byte_size = tg_byte_size_from_graph_raddbgi_key(graph, rdbg, in);
|
|
U64 out_byte_size = tg_byte_size_from_graph_raddbgi_key(graph, rdbg, out);
|
|
if(out_byte_size < in_byte_size && eval_kind_is_integer(out_kind))
|
|
{
|
|
result = eval_irtree_trunc(arena, graph, rdbg, result, out);
|
|
}
|
|
return(result);
|
|
}
|
|
|
|
internal EVAL_IRTree*
|
|
eval_irtree_resolve_to_value(Arena *arena, TG_Graph *graph, RADDBGI_Parsed *rdbg, EVAL_EvalMode from_mode,
|
|
EVAL_IRTree *tree, TG_Key type_key){
|
|
EVAL_IRTree *result = tree;
|
|
switch (from_mode){
|
|
default:{}break;
|
|
case EVAL_EvalMode_Addr:
|
|
{
|
|
result = eval_irtree_mem_read_type(arena, graph, rdbg, tree, type_key);
|
|
}break;
|
|
case EVAL_EvalMode_Reg:
|
|
{
|
|
result = eval_irtree_unary_op(arena, RADDBGI_EvalOp_RegReadDyn, RADDBGI_EvalTypeGroup_U, tree);
|
|
}break;
|
|
}
|
|
return(result);
|
|
}
|
|
|
|
////////////////////////////////
|
|
//~ allen: EVAL Compiler Phases
|
|
|
|
internal void
|
|
eval_push_leaf_ident_exprs_from_expr__in_place(Arena *arena, EVAL_String2ExprMap *map, EVAL_Expr *expr, EVAL_ErrorList *eout)
|
|
{
|
|
switch(expr->kind)
|
|
{
|
|
default:
|
|
{
|
|
U64 children_count = eval_expr_kind_child_counts[expr->kind];
|
|
for(U64 idx = 0; idx < children_count; idx += 1)
|
|
{
|
|
eval_push_leaf_ident_exprs_from_expr__in_place(arena, map, expr->children[idx], eout);
|
|
}
|
|
}break;
|
|
case EVAL_ExprKind_Define:
|
|
{
|
|
EVAL_Expr *exprl = expr->children[0];
|
|
EVAL_Expr *exprr = expr->children[1];
|
|
if(exprl->kind == EVAL_ExprKind_LeafIdent)
|
|
{
|
|
eval_string2expr_map_insert(arena, map, exprl->name, exprr);
|
|
}
|
|
}break;
|
|
}
|
|
}
|
|
|
|
internal TG_Key
|
|
eval_type_from_type_expr(Arena *arena, TG_Graph *graph, RADDBGI_Parsed *rdbg, EVAL_Expr *expr, EVAL_ErrorList *eout){
|
|
TG_Key result = zero_struct;
|
|
|
|
EVAL_ExprKind kind = expr->kind;
|
|
switch (kind){
|
|
default:
|
|
{
|
|
eval_errorf(arena, eout, EVAL_ErrorKind_MalformedInput, expr->location, "Expected type expression.");
|
|
}break;
|
|
|
|
case EVAL_ExprKind_TypeIdent:
|
|
{
|
|
result = expr->type_key;
|
|
}break;
|
|
|
|
case EVAL_ExprKind_Ptr:
|
|
{
|
|
TG_Key direct_type_key = eval_type_from_type_expr(arena, graph, rdbg, expr->children[0], eout);
|
|
result = tg_cons_type_make(graph, TG_Kind_Ptr, direct_type_key, 0);
|
|
}break;
|
|
|
|
case EVAL_ExprKind_Array:
|
|
{
|
|
EVAL_Expr *child_expr = expr->child_and_constant.child;
|
|
TG_Key direct_type_key = eval_type_from_type_expr(arena, graph, rdbg, child_expr, eout);
|
|
result = tg_cons_type_make(graph, TG_Kind_Array, direct_type_key, expr->child_and_constant.u64);
|
|
}break;
|
|
|
|
case EVAL_ExprKind_Func:
|
|
{
|
|
// TODO(rjf): old type graph code is below:
|
|
#if 0
|
|
TG_Type *ret_type = eval_type_from_type_expr(arena, graph, expr->children[0], eout);
|
|
// TODO(allen): decision: do we do the extra work to preserve full function type info?
|
|
result = tg_type_func(graph, ret_type, 0, 0);
|
|
#endif
|
|
}break;
|
|
}
|
|
|
|
return(result);
|
|
}
|
|
|
|
internal EVAL_IRTreeAndType
|
|
eval_irtree_and_type_from_expr(Arena *arena, TG_Graph *graph, RADDBGI_Parsed *rdbg, EVAL_String2ExprMap *leaf_ident_expr_map, EVAL_Expr *expr, EVAL_ErrorList *eout)
|
|
{
|
|
ProfBeginFunction();
|
|
EVAL_IRTreeAndType result = {0};
|
|
result.tree = &eval_irtree_nil;
|
|
|
|
EVAL_ExprKind kind = expr->kind;
|
|
switch(kind)
|
|
{
|
|
default:
|
|
{
|
|
eval_errorf(arena, eout, EVAL_ErrorKind_MalformedInput, expr->location, "(internal) Undefined expression kind (%u).", kind);
|
|
}break;
|
|
|
|
case EVAL_ExprKind_ArrayIndex:
|
|
{
|
|
EVAL_Expr *exprl = expr->children[0];
|
|
EVAL_Expr *exprr = expr->children[1];
|
|
|
|
EVAL_IRTreeAndType l = eval_irtree_and_type_from_expr(arena, graph, rdbg, leaf_ident_expr_map, exprl, eout);
|
|
EVAL_IRTreeAndType r = eval_irtree_and_type_from_expr(arena, graph, rdbg, leaf_ident_expr_map, exprr, eout);
|
|
|
|
if (l.tree->op != 0 && r.tree->op != 0){
|
|
TG_Key l_restype = tg_unwrapped_from_graph_raddbgi_key(graph, rdbg, l.type_key);
|
|
TG_Key r_restype = tg_unwrapped_from_graph_raddbgi_key(graph, rdbg, r.type_key);
|
|
TG_Kind l_restype_kind = tg_kind_from_key(l_restype);
|
|
TG_Kind r_restype_kind = tg_kind_from_key(r_restype);
|
|
|
|
// analyze situation
|
|
B32 can_generate = 0;
|
|
B32 l_resolve = 0;
|
|
TG_Key direct_type = zero_struct;
|
|
U64 direct_type_size = 0;
|
|
if (!eval_kind_is_integer(r_restype_kind)){
|
|
eval_errorf(arena, eout, EVAL_ErrorKind_MalformedInput, exprr->location, "Cannot index with this type.");
|
|
}
|
|
else{
|
|
direct_type = tg_unwrapped_direct_from_graph_raddbgi_key(graph, rdbg, l_restype);
|
|
direct_type_size = tg_byte_size_from_graph_raddbgi_key(graph, rdbg, direct_type);
|
|
if (l_restype_kind == TG_Kind_Ptr){
|
|
if (direct_type_size == 0){
|
|
eval_errorf(arena, eout, EVAL_ErrorKind_MalformedInput, exprr->location, "Cannot index into pointers of zero-sized types.");
|
|
}
|
|
else{
|
|
can_generate = 1;
|
|
if (l.mode != EVAL_EvalMode_Value){
|
|
l_resolve = 1;
|
|
}
|
|
}
|
|
}
|
|
else if (l_restype_kind == TG_Kind_Array){
|
|
if (l.mode == EVAL_EvalMode_Addr){
|
|
if (direct_type_size == 0){
|
|
eval_errorf(arena, eout, EVAL_ErrorKind_MalformedInput, exprl->location, "Cannot index into arrays of zero-sized types.");
|
|
}
|
|
else{
|
|
can_generate = 1;
|
|
}
|
|
}
|
|
else{
|
|
eval_errorf(arena, eout, EVAL_ErrorKind_MalformedInput, exprl->location, "(Not supported) Cannot index into array without base address.");
|
|
}
|
|
}
|
|
else{
|
|
eval_errorf(arena, eout, EVAL_ErrorKind_MalformedInput, exprl->location, "Cannot index into this type.");
|
|
}
|
|
}
|
|
|
|
// generate ir tree
|
|
if (can_generate){
|
|
// how to compute the index
|
|
EVAL_IRTree *index_tree = eval_irtree_resolve_to_value(arena, graph, rdbg, r.mode, r.tree, r_restype);
|
|
if (direct_type_size > 1){
|
|
EVAL_IRTree *const_tree = eval_irtree_const_u(arena, direct_type_size);
|
|
index_tree = eval_irtree_binary_op_u(arena, RADDBGI_EvalOp_Mul, index_tree, const_tree);
|
|
}
|
|
|
|
// how to compute the base address
|
|
EVAL_IRTree *base_tree = l.tree;
|
|
if (l_resolve){
|
|
base_tree = eval_irtree_resolve_to_value(arena, graph, rdbg, l.mode, base_tree, l_restype);
|
|
}
|
|
|
|
// how to compute the final address
|
|
EVAL_IRTree *new_tree = eval_irtree_binary_op_u(arena, RADDBGI_EvalOp_Add, index_tree, base_tree);
|
|
|
|
// fill result
|
|
result.tree = new_tree;
|
|
result.type_key = direct_type;
|
|
result.mode = EVAL_EvalMode_Addr;
|
|
}
|
|
}
|
|
}break;
|
|
|
|
case EVAL_ExprKind_MemberAccess:
|
|
{
|
|
EVAL_Expr *exprl = expr->children[0];
|
|
EVAL_Expr *exprr = expr->children[1];
|
|
|
|
EVAL_IRTreeAndType l = eval_irtree_and_type_from_expr(arena, graph, rdbg, leaf_ident_expr_map, exprl, eout);
|
|
|
|
if (l.tree->op != 0 && !tg_key_match(tg_key_zero(), l.type_key)){
|
|
TG_Key l_restype = tg_unwrapped_from_graph_raddbgi_key(graph, rdbg, l.type_key);
|
|
TG_Kind l_restype_kind = tg_kind_from_key(l_restype);
|
|
|
|
// determine which type to use
|
|
TG_Key check_type_key = l_restype;
|
|
TG_Kind check_type_kind = l_restype_kind;
|
|
if (l_restype_kind == TG_Kind_Ptr || l_restype_kind == TG_Kind_LRef || l_restype_kind == TG_Kind_RRef){
|
|
check_type_key = tg_unwrapped_direct_from_graph_raddbgi_key(graph, rdbg, l_restype);
|
|
check_type_kind = tg_kind_from_key(check_type_key);
|
|
}
|
|
|
|
// switch to handle
|
|
switch(check_type_kind)
|
|
{
|
|
default:
|
|
{
|
|
eval_errorf(arena, eout, EVAL_ErrorKind_MalformedInput, exprl->location, "Cannot perform member access on this type.");
|
|
}break;
|
|
|
|
case TG_Kind_Struct:
|
|
case TG_Kind_Class:
|
|
case TG_Kind_Union:
|
|
{
|
|
// analyze situation
|
|
B32 can_generate = 0;
|
|
TG_Key r_type = zero_struct;
|
|
U32 r_off = 0;
|
|
B32 l_resolve = 0;
|
|
|
|
// determine how to treat left
|
|
B32 l_good = 0;
|
|
if (l_restype_kind == TG_Kind_Ptr || l_restype_kind == TG_Kind_LRef || l_restype_kind == TG_Kind_RRef){
|
|
l_good = 1;
|
|
l_resolve = 1;
|
|
}
|
|
else{
|
|
if (l.mode == EVAL_EvalMode_Addr){
|
|
l_good = 1;
|
|
}
|
|
else if(l.mode == EVAL_EvalMode_Reg)
|
|
{
|
|
l_good = 1;
|
|
}
|
|
else{
|
|
eval_errorf(arena, eout, EVAL_ErrorKind_MalformedInput, exprl->location,
|
|
"(Not supported) Cannot access member without a base address or register location.");
|
|
}
|
|
}
|
|
|
|
// right must be identifier
|
|
B32 r_good = 0;
|
|
if (exprr->kind == EVAL_ExprKind_LeafMember){
|
|
r_good = 1;
|
|
}
|
|
else{
|
|
eval_errorf(arena, eout, EVAL_ErrorKind_MalformedInput, exprr->location,
|
|
"(internal) Expected a leaf member in member access.");
|
|
}
|
|
|
|
if (l_good && r_good){
|
|
Temp scratch = scratch_begin(&arena, 1);
|
|
TG_MemberArray check_type_members = tg_data_members_from_graph_raddbgi_key(scratch.arena, graph, rdbg, check_type_key);
|
|
|
|
// lookup member
|
|
String8 member_name = exprr->name;
|
|
TG_Member *match = 0;
|
|
for(U64 member_idx = 0; member_idx < check_type_members.count; member_idx += 1)
|
|
{
|
|
TG_Member *member = &check_type_members.v[member_idx];
|
|
if(str8_match(member->name, member_name, 0))
|
|
{
|
|
match = member;
|
|
break;
|
|
}
|
|
}
|
|
|
|
// extract member info
|
|
if (match != 0){
|
|
can_generate = 1;
|
|
r_type = match->type_key;
|
|
r_off = match->off;
|
|
}
|
|
else{
|
|
eval_errorf(arena, eout, EVAL_ErrorKind_MalformedInput, exprr->location, "Could not find a member named '%S' in type.", member_name);
|
|
}
|
|
|
|
scratch_end(scratch);
|
|
}
|
|
|
|
// generate ir tree
|
|
if (can_generate){
|
|
EVAL_IRTree *new_tree = l.tree;
|
|
if (l_resolve){
|
|
new_tree = eval_irtree_resolve_to_value(arena, graph, rdbg, l.mode, new_tree, l_restype);
|
|
}
|
|
if (r_off != 0){
|
|
EVAL_IRTree *const_tree = eval_irtree_const_u(arena, r_off);
|
|
new_tree = eval_irtree_binary_op_u(arena, RADDBGI_EvalOp_Add, new_tree, const_tree);
|
|
}
|
|
|
|
// fill result
|
|
result.tree = new_tree;
|
|
result.type_key = r_type;
|
|
result.mode = l.mode;
|
|
}
|
|
}break;
|
|
}
|
|
|
|
}
|
|
}break;
|
|
|
|
case EVAL_ExprKind_Deref:
|
|
{
|
|
EVAL_Expr *exprc = expr->children[0];
|
|
|
|
EVAL_IRTreeAndType c = eval_irtree_and_type_from_expr(arena, graph, rdbg, leaf_ident_expr_map, exprc, eout);
|
|
|
|
if (c.tree->op != 0){
|
|
TG_Key c_restype = tg_unwrapped_from_graph_raddbgi_key(graph, rdbg, c.type_key);
|
|
TG_Kind c_restype_kind = tg_kind_from_key(c_restype);
|
|
TG_Key c_restype_direct = tg_unwrapped_direct_from_graph_raddbgi_key(graph, rdbg, c_restype);
|
|
U64 c_restype_direct_size = tg_byte_size_from_graph_raddbgi_key(graph, rdbg, c_restype_direct);
|
|
|
|
// analyze situation
|
|
B32 can_generate = 0;
|
|
B32 c_resolve = 0;
|
|
if (c_restype_kind == TG_Kind_Ptr ||
|
|
c_restype_kind == TG_Kind_LRef ||
|
|
c_restype_kind == TG_Kind_RRef){
|
|
if (c_restype_direct_size == 0){
|
|
eval_errorf(arena, eout, EVAL_ErrorKind_MalformedInput, exprc->location, "Cannot dereference pointers of zero-sized types.");
|
|
}
|
|
else{
|
|
can_generate = 1;
|
|
c_resolve = 1;
|
|
}
|
|
}
|
|
else if (c_restype_kind == TG_Kind_Array){
|
|
if (c.mode == EVAL_EvalMode_Addr){
|
|
if (c_restype_direct_size == 0){
|
|
eval_errorf(arena, eout, EVAL_ErrorKind_MalformedInput, exprc->location, "Cannot dereference arrays of zero-sized types.");
|
|
}
|
|
else{
|
|
can_generate = 1;
|
|
}
|
|
}
|
|
else{
|
|
eval_errorf(arena, eout, EVAL_ErrorKind_MalformedInput, exprc->location, "(Not supported) Cannot dereference array without base address.");
|
|
}
|
|
}
|
|
else{
|
|
eval_errorf(arena, eout, EVAL_ErrorKind_MalformedInput, exprc->location, "Cannot dereference this type.");
|
|
}
|
|
|
|
// generate ir tree
|
|
if (can_generate){
|
|
EVAL_IRTree *new_tree = c.tree;
|
|
if (c_resolve){
|
|
new_tree = eval_irtree_resolve_to_value(arena, graph, rdbg, c.mode, c.tree, c_restype);
|
|
}
|
|
|
|
// fill result
|
|
result.tree = new_tree;
|
|
result.type_key = c_restype_direct;
|
|
result.mode = EVAL_EvalMode_Addr;
|
|
}
|
|
}
|
|
}break;
|
|
|
|
case EVAL_ExprKind_Address:
|
|
{
|
|
EVAL_Expr *exprc = expr->children[0];
|
|
EVAL_IRTreeAndType c = eval_irtree_and_type_from_expr(arena, graph, rdbg, leaf_ident_expr_map, exprc, eout);
|
|
if(c.tree->op != 0 && !tg_key_match(c.type_key, tg_key_zero()))
|
|
{
|
|
TG_Key c_restype = tg_unwrapped_from_graph_raddbgi_key(graph, rdbg, c.type_key);
|
|
TG_Kind c_restype_kind = tg_kind_from_key(c_restype);
|
|
|
|
// analyze situation
|
|
B32 can_generate = 0;
|
|
if(c.mode == EVAL_EvalMode_Addr)
|
|
{
|
|
can_generate = 1;
|
|
}
|
|
|
|
// generate ir tree
|
|
if(can_generate)
|
|
{
|
|
EVAL_IRTree *new_tree = c.tree;
|
|
TG_Key ptr_type = tg_cons_type_make(graph, TG_Kind_Ptr, c_restype, 0);
|
|
|
|
// fill result
|
|
result.tree = new_tree;
|
|
result.type_key = ptr_type;
|
|
result.mode = EVAL_EvalMode_Value;
|
|
}
|
|
}
|
|
}break;
|
|
|
|
case EVAL_ExprKind_Cast:
|
|
{
|
|
EVAL_Expr *exprl = expr->children[0];
|
|
EVAL_Expr *exprr = expr->children[1];
|
|
|
|
TG_Key cast_type_key = eval_type_from_type_expr(arena, graph, rdbg, exprl, eout);
|
|
TG_Kind cast_type_kind = tg_kind_from_key(cast_type_key);
|
|
EVAL_IRTreeAndType c = eval_irtree_and_type_from_expr(arena, graph, rdbg, leaf_ident_expr_map, exprr, eout);
|
|
|
|
if(cast_type_kind != TG_Kind_Null && c.tree->op != 0)
|
|
{
|
|
TG_Key c_restype = tg_unwrapped_from_graph_raddbgi_key(graph, rdbg, c.type_key);
|
|
TG_Kind c_restype_kind = tg_kind_from_key(c_restype);
|
|
U64 c_restype_byte_size = tg_byte_size_from_graph_raddbgi_key(graph, rdbg, c_restype);
|
|
U64 cast_type_byte_size = tg_byte_size_from_graph_raddbgi_key(graph, rdbg, cast_type_key);
|
|
|
|
// analyze situation
|
|
U8 in_group = eval_type_group_from_kind(c_restype_kind);
|
|
U8 out_group = eval_type_group_from_kind(cast_type_kind);
|
|
RADDBGI_EvalConversionKind conversion_rule = raddbgi_eval_conversion_rule(in_group, out_group);
|
|
|
|
// generate tree
|
|
switch(conversion_rule)
|
|
{
|
|
case RADDBGI_EvalConversionKind_Noop:
|
|
case RADDBGI_EvalConversionKind_Legal:
|
|
{
|
|
EVAL_IRTree *in_tree = eval_irtree_resolve_to_value(arena, graph, rdbg, c.mode, c.tree, c_restype);
|
|
|
|
EVAL_IRTree *new_tree = in_tree;
|
|
if (conversion_rule == RADDBGI_EvalConversionKind_Legal){
|
|
new_tree = eval_irtree_convert_lo(arena, in_tree, out_group, in_group);
|
|
}
|
|
if (cast_type_byte_size < c_restype_byte_size && eval_kind_is_integer(cast_type_kind)){
|
|
new_tree = eval_irtree_trunc(arena, graph, rdbg, in_tree, cast_type_key);
|
|
}
|
|
|
|
result.tree = new_tree;
|
|
result.type_key = cast_type_key;
|
|
result.mode = EVAL_EvalMode_Value;
|
|
}break;
|
|
|
|
default:
|
|
{
|
|
String8 text = str8_lit("(internal) unknown conversion rule");
|
|
if (conversion_rule < RADDBGI_EvalConversionKind_COUNT){
|
|
text.str = raddbgi_eval_conversion_message(conversion_rule, &text.size);
|
|
}
|
|
eval_error(arena, eout, EVAL_ErrorKind_MalformedInput, expr->location, text);
|
|
}break;
|
|
}
|
|
}
|
|
}break;
|
|
|
|
case EVAL_ExprKind_Sizeof:
|
|
{
|
|
EVAL_Expr *exprc = expr->children[0];
|
|
|
|
// analyze situation
|
|
TG_Key type_key = zero_struct;
|
|
switch (exprc->kind){
|
|
// size of type expression
|
|
case EVAL_ExprKind_TypeIdent:
|
|
case EVAL_ExprKind_Ptr:
|
|
case EVAL_ExprKind_Array:
|
|
case EVAL_ExprKind_Func:
|
|
{
|
|
type_key = eval_type_from_type_expr(arena, graph, rdbg, exprc, eout);
|
|
}break;
|
|
|
|
// size of value expression
|
|
default:
|
|
{
|
|
EVAL_IRTreeAndType c = eval_irtree_and_type_from_expr(arena, graph, rdbg, leaf_ident_expr_map, exprc, eout);
|
|
type_key = c.type_key;
|
|
}break;
|
|
}
|
|
B32 can_generate = 0;
|
|
U64 size = 0;
|
|
TG_Kind type_kind = tg_kind_from_key(type_key);
|
|
if (type_kind != TG_Kind_Null){
|
|
can_generate = 1;
|
|
size = tg_byte_size_from_graph_raddbgi_key(graph, rdbg, type_key);
|
|
}
|
|
|
|
// generate ir tree
|
|
if(can_generate)
|
|
{
|
|
EVAL_IRTree *new_tree = eval_irtree_const_u(arena, size);
|
|
result.tree = new_tree;
|
|
result.type_key = tg_key_basic(TG_Kind_U64);
|
|
result.mode = EVAL_EvalMode_Value;
|
|
}
|
|
}break;
|
|
|
|
case EVAL_ExprKind_Neg:
|
|
case EVAL_ExprKind_LogNot:
|
|
case EVAL_ExprKind_BitNot:
|
|
{
|
|
EVAL_Expr *exprc = expr->children[0];
|
|
|
|
EVAL_IRTreeAndType c = eval_irtree_and_type_from_expr(arena, graph, rdbg, leaf_ident_expr_map, exprc, eout);
|
|
if (c.tree->op != 0){
|
|
TG_Key c_restype = tg_unwrapped_from_graph_raddbgi_key(graph, rdbg, c.type_key);
|
|
TG_Key p_type = eval_type_promote(graph, rdbg, c_restype);
|
|
TG_Kind c_restype_kind = tg_kind_from_key(c_restype);
|
|
|
|
// analyze situation
|
|
B32 can_generate = 0;
|
|
RADDBGI_EvalOp op = eval_opcode_from_expr_kind(kind);
|
|
U8 c_group = eval_type_group_from_kind(c_restype_kind);
|
|
if (!raddbgi_eval_opcode_type_compatible(op, c_group)){
|
|
eval_errorf(arena, eout, EVAL_ErrorKind_MalformedInput, expr->location, "Cannot use this operator on this type.");
|
|
}
|
|
else{
|
|
can_generate = 1;
|
|
}
|
|
|
|
// generate ir tree
|
|
if (can_generate){
|
|
EVAL_IRTree *in_tree = eval_irtree_resolve_to_value(arena, graph, rdbg, c.mode, c.tree, c_restype);
|
|
in_tree = eval_irtree_convert_hi(arena, graph, rdbg, in_tree, p_type, c_restype);
|
|
|
|
EVAL_IRTree *new_tree = eval_irtree_unary_op(arena, op, c_group, in_tree);
|
|
|
|
result.tree = new_tree;
|
|
result.type_key = p_type;
|
|
result.mode = EVAL_EvalMode_Value;
|
|
}
|
|
}
|
|
}break;
|
|
|
|
case EVAL_ExprKind_Mul:
|
|
case EVAL_ExprKind_Div:
|
|
case EVAL_ExprKind_Mod:
|
|
case EVAL_ExprKind_Add:
|
|
case EVAL_ExprKind_Sub:
|
|
case EVAL_ExprKind_LShift:
|
|
case EVAL_ExprKind_RShift:
|
|
case EVAL_ExprKind_Less:
|
|
case EVAL_ExprKind_LsEq:
|
|
case EVAL_ExprKind_Grtr:
|
|
case EVAL_ExprKind_GrEq:
|
|
case EVAL_ExprKind_EqEq:
|
|
case EVAL_ExprKind_NtEq:
|
|
case EVAL_ExprKind_BitAnd:
|
|
case EVAL_ExprKind_BitXor:
|
|
case EVAL_ExprKind_BitOr:
|
|
case EVAL_ExprKind_LogAnd:
|
|
case EVAL_ExprKind_LogOr:
|
|
{
|
|
//- setup & dispatch
|
|
EVAL_Expr *exprl = expr->children[0];
|
|
EVAL_Expr *exprr = expr->children[1];
|
|
|
|
EVAL_IRTreeAndType l = eval_irtree_and_type_from_expr(arena, graph, rdbg, leaf_ident_expr_map, exprl, eout);
|
|
EVAL_IRTreeAndType r = eval_irtree_and_type_from_expr(arena, graph, rdbg, leaf_ident_expr_map, exprr, eout);
|
|
|
|
if (l.tree->op != 0 && r.tree->op != 0){
|
|
TG_Key l_restype = tg_unwrapped_from_graph_raddbgi_key(graph, rdbg, l.type_key);
|
|
TG_Key r_restype = tg_unwrapped_from_graph_raddbgi_key(graph, rdbg, r.type_key);
|
|
TG_Kind l_restype_kind = tg_kind_from_key(l_restype);
|
|
TG_Kind r_restype_kind = tg_kind_from_key(r_restype);
|
|
|
|
//- rjf: decay register types to basics
|
|
if(l_restype.kind == TG_KeyKind_Reg)
|
|
{
|
|
l_restype = tg_key_basic(TG_Kind_U64);
|
|
l_restype_kind = tg_kind_from_key(l_restype);
|
|
}
|
|
if(r_restype.kind == TG_KeyKind_Reg)
|
|
{
|
|
r_restype = tg_key_basic(TG_Kind_U64);
|
|
r_restype_kind = tg_kind_from_key(r_restype);
|
|
}
|
|
|
|
RADDBGI_EvalOp op = eval_opcode_from_expr_kind(kind);
|
|
|
|
//- pointer decay
|
|
B32 l_is_pointer = (l_restype_kind == TG_Kind_Ptr);
|
|
B32 l_is_decay = (l_restype_kind == TG_Kind_Array && l.mode == EVAL_EvalMode_Addr);
|
|
B32 l_is_pointer_like = (l_is_pointer || l_is_decay);
|
|
|
|
B32 r_is_pointer = (r_restype_kind == TG_Kind_Ptr);
|
|
B32 r_is_decay = (r_restype_kind == TG_Kind_Array && r.mode == EVAL_EvalMode_Addr);
|
|
B32 r_is_pointer_like = (r_is_pointer || r_is_decay);
|
|
|
|
//- determine arithmetic path
|
|
#define EVAL_ArithPath_Normal 0
|
|
#define EVAL_ArithPath_PtrAdd 1
|
|
#define EVAL_ArithPath_PtrSub 2
|
|
|
|
B32 ptr_arithmetic_mul_rptr = 0;
|
|
U32 arith_path = EVAL_ArithPath_Normal;
|
|
if (kind == EVAL_ExprKind_Add){
|
|
if (l_is_pointer_like && eval_kind_is_integer(r_restype_kind)){
|
|
arith_path = EVAL_ArithPath_PtrAdd;
|
|
}
|
|
if (l_is_pointer_like && eval_kind_is_integer(l_restype_kind)){
|
|
arith_path = EVAL_ArithPath_PtrAdd;
|
|
ptr_arithmetic_mul_rptr = 1;
|
|
}
|
|
}
|
|
else if (kind == EVAL_ExprKind_Sub){
|
|
if (l_is_pointer_like && eval_kind_is_integer(r_restype_kind)){
|
|
arith_path = EVAL_ArithPath_PtrAdd;
|
|
}
|
|
if (l_is_pointer_like && r_is_pointer_like){
|
|
TG_Key l_restype_direct = tg_unwrapped_direct_from_graph_raddbgi_key(graph, rdbg, l_restype);
|
|
TG_Key r_restype_direct = tg_unwrapped_direct_from_graph_raddbgi_key(graph, rdbg, r_restype);
|
|
U64 l_restype_direct_byte_size = tg_byte_size_from_graph_raddbgi_key(graph, rdbg, l_restype_direct);
|
|
U64 r_restype_direct_byte_size = tg_byte_size_from_graph_raddbgi_key(graph, rdbg, r_restype_direct);
|
|
if (l_restype_direct_byte_size == r_restype_direct_byte_size){
|
|
arith_path = EVAL_ArithPath_PtrSub;
|
|
}
|
|
}
|
|
}
|
|
|
|
//- specific arithmetic handlers
|
|
|
|
switch (arith_path){
|
|
case EVAL_ArithPath_Normal:
|
|
{
|
|
// analyze situation
|
|
B32 is_comparison = eval_expr_kind_is_comparison(kind);
|
|
B32 both_basic = (eval_kind_is_basic_or_enum(l_restype_kind) &&
|
|
eval_kind_is_basic_or_enum(r_restype_kind));
|
|
|
|
TG_Key cv_type_key = zero_struct;
|
|
if (both_basic){
|
|
cv_type_key = eval_type_coerce(graph, rdbg, l_restype, r_restype);
|
|
}
|
|
else if (is_comparison && eval_type_match(graph, rdbg, l_restype, r_restype)){
|
|
cv_type_key = l_restype;
|
|
}
|
|
|
|
TG_Kind cv_type_kind = tg_kind_from_key(cv_type_key);
|
|
U8 cv_group = eval_type_group_from_kind(cv_type_kind);
|
|
|
|
B32 can_generate = 0;
|
|
if (raddbgi_eval_opcode_type_compatible(op, cv_group)){
|
|
can_generate = 1;
|
|
}
|
|
else{
|
|
eval_errorf(arena, eout, EVAL_ErrorKind_MalformedInput, expr->location, "Cannot use this operator on this type.");
|
|
}
|
|
|
|
// generate ir tree
|
|
if (can_generate){
|
|
TG_Key final_type_key = cv_type_key;
|
|
if (is_comparison){
|
|
final_type_key = tg_key_basic(TG_Kind_Bool);
|
|
}
|
|
|
|
EVAL_IRTree *l_tree = eval_irtree_resolve_to_value(arena, graph, rdbg, l.mode, l.tree, l_restype);
|
|
l_tree = eval_irtree_convert_hi(arena, graph, rdbg, l_tree, cv_type_key, l_restype);
|
|
|
|
EVAL_IRTree *r_tree = eval_irtree_resolve_to_value(arena, graph, rdbg, r.mode, r.tree, r_restype);
|
|
r_tree = eval_irtree_convert_hi(arena, graph, rdbg, r_tree, cv_type_key, r_restype);
|
|
|
|
EVAL_IRTree *new_tree = eval_irtree_binary_op(arena, op, cv_group, l_tree, r_tree);
|
|
|
|
result.tree = new_tree;
|
|
result.type_key = final_type_key;
|
|
result.mode = EVAL_EvalMode_Value;
|
|
}
|
|
}break;
|
|
|
|
case EVAL_ArithPath_PtrAdd:
|
|
{
|
|
// setup which side is the pointer
|
|
EVAL_IRTreeAndType *ptr = &l;
|
|
EVAL_IRTreeAndType *integer = &r;
|
|
B32 ptr_is_decay = l_is_decay;
|
|
if (ptr_arithmetic_mul_rptr){
|
|
ptr = &r;
|
|
integer = &l;
|
|
ptr_is_decay = r_is_decay;
|
|
}
|
|
|
|
TG_Key direct = tg_unwrapped_direct_from_graph_raddbgi_key(graph, rdbg, ptr->type_key);
|
|
U64 direct_type_size = tg_byte_size_from_graph_raddbgi_key(graph, rdbg, direct);
|
|
|
|
// generate ir tree
|
|
EVAL_IRTree *ptr_tree = ptr->tree;
|
|
if (!ptr_is_decay){
|
|
ptr_tree = eval_irtree_resolve_to_value(arena, graph, rdbg, ptr->mode, ptr_tree, ptr->type_key);
|
|
}
|
|
|
|
EVAL_IRTree *integer_tree = eval_irtree_resolve_to_value(arena, graph, rdbg, integer->mode, integer->tree, integer->type_key);
|
|
if (direct_type_size > 1){
|
|
EVAL_IRTree *const_tree = eval_irtree_const_u(arena, direct_type_size);
|
|
integer_tree = eval_irtree_binary_op_u(arena, RADDBGI_EvalOp_Mul, integer_tree, const_tree);
|
|
}
|
|
|
|
TG_Key ptr_type = ptr->type_key;
|
|
if (ptr_is_decay){
|
|
ptr_type = tg_cons_type_make(graph, TG_Kind_Ptr, direct, 0);
|
|
}
|
|
|
|
EVAL_IRTree *new_tree = eval_irtree_binary_op(arena, op, RADDBGI_EvalTypeGroup_U, ptr_tree, integer_tree);
|
|
|
|
result.tree = new_tree;
|
|
result.type_key = ptr_type;
|
|
result.mode = EVAL_EvalMode_Value;
|
|
}break;
|
|
|
|
case EVAL_ArithPath_PtrSub:
|
|
{
|
|
TG_Key direct = tg_unwrapped_direct_from_graph_raddbgi_key(graph, rdbg, l_restype);
|
|
U64 direct_type_size = tg_byte_size_from_graph_raddbgi_key(graph, rdbg, direct);
|
|
|
|
// generate ir tree
|
|
EVAL_IRTree *l_tree = l.tree;
|
|
if (!l_is_decay){
|
|
l_tree = eval_irtree_resolve_to_value(arena, graph, rdbg, l.mode, l.tree, l_restype);
|
|
}
|
|
|
|
EVAL_IRTree *r_tree = r.tree;
|
|
if (!r_is_decay){
|
|
r_tree = eval_irtree_resolve_to_value(arena, graph, rdbg, r.mode, r.tree, r_restype);
|
|
}
|
|
|
|
EVAL_IRTree *op_tree = eval_irtree_binary_op(arena, op, RADDBGI_EvalTypeGroup_U, l_tree, r_tree);
|
|
|
|
EVAL_IRTree *new_tree = op_tree;
|
|
if (direct_type_size > 1){
|
|
EVAL_IRTree *const_tree = eval_irtree_const_u(arena, direct_type_size);
|
|
new_tree = eval_irtree_binary_op(arena, RADDBGI_EvalOp_Div, RADDBGI_EvalTypeGroup_U, new_tree, const_tree);
|
|
}
|
|
|
|
result.tree = new_tree;
|
|
result.type_key = tg_key_basic(TG_Kind_U64);
|
|
result.mode = EVAL_EvalMode_Value;
|
|
}break;
|
|
}
|
|
}
|
|
}break;
|
|
|
|
case EVAL_ExprKind_Ternary:
|
|
{
|
|
EVAL_Expr *exprc = expr->children[0];
|
|
EVAL_Expr *exprl = expr->children[1];
|
|
EVAL_Expr *exprr = expr->children[2];
|
|
|
|
EVAL_IRTreeAndType c = eval_irtree_and_type_from_expr(arena, graph, rdbg, leaf_ident_expr_map, exprc, eout);
|
|
EVAL_IRTreeAndType l = eval_irtree_and_type_from_expr(arena, graph, rdbg, leaf_ident_expr_map, exprl, eout);
|
|
EVAL_IRTreeAndType r = eval_irtree_and_type_from_expr(arena, graph, rdbg, leaf_ident_expr_map, exprr, eout);
|
|
|
|
if (l.tree->op != 0 && r.tree->op != 0 && c.tree->op != 0){
|
|
|
|
TG_Key c_restype = tg_unwrapped_from_graph_raddbgi_key(graph, rdbg, c.type_key);
|
|
TG_Key l_restype = tg_unwrapped_from_graph_raddbgi_key(graph, rdbg, l.type_key);
|
|
TG_Key r_restype = tg_unwrapped_from_graph_raddbgi_key(graph, rdbg, r.type_key);
|
|
TG_Kind c_restype_kind = tg_kind_from_key(c_restype);
|
|
TG_Kind l_restype_kind = tg_kind_from_key(l_restype);
|
|
TG_Kind r_restype_kind = tg_kind_from_key(r_restype);
|
|
|
|
// analyze situation
|
|
B32 can_generate = 0;
|
|
TG_Key final_type = zero_struct;
|
|
if (eval_kind_is_integer(c_restype_kind)){
|
|
eval_errorf(arena, eout, EVAL_ErrorKind_MalformedInput, expr->location, "Conditional term must be an integer type.");
|
|
}
|
|
else{
|
|
if (eval_kind_is_basic_or_enum(l_restype_kind) &&
|
|
eval_kind_is_basic_or_enum(r_restype_kind)){
|
|
can_generate = 1;
|
|
final_type = eval_type_coerce(graph, rdbg, l_restype, r_restype);
|
|
}
|
|
else{
|
|
if (eval_type_match(graph, rdbg, l_restype, r_restype)){
|
|
if (l_restype_kind == TG_Kind_Ptr){
|
|
can_generate = 1;
|
|
final_type = l_restype;
|
|
}
|
|
else{
|
|
eval_errorf(arena, eout, EVAL_ErrorKind_MalformedInput, expr->location, "(Not supported) Conditional value not basic type or pointer.");
|
|
}
|
|
}
|
|
else{
|
|
eval_errorf(arena, eout, EVAL_ErrorKind_MalformedInput, expr->location, "Left and right terms must have matching types.");
|
|
}
|
|
}
|
|
}
|
|
|
|
// generate ir tree
|
|
if (can_generate){
|
|
EVAL_IRTree *c_tree = eval_irtree_resolve_to_value(arena, graph, rdbg, c.mode, c.tree, c_restype);
|
|
|
|
EVAL_IRTree *l_tree = eval_irtree_resolve_to_value(arena, graph, rdbg, l.mode, l.tree, l_restype);
|
|
l_tree = eval_irtree_convert_hi(arena, graph, rdbg, l_tree, final_type, l_restype);
|
|
|
|
EVAL_IRTree *r_tree = eval_irtree_resolve_to_value(arena, graph, rdbg, r.mode, r.tree, r_restype);
|
|
r_tree = eval_irtree_convert_hi(arena, graph, rdbg, r_tree, final_type, r_restype);
|
|
|
|
EVAL_IRTree *new_tree = eval_irtree_conditional(arena, c_tree, l_tree, r_tree);
|
|
|
|
result.tree = new_tree;
|
|
result.type_key = final_type;
|
|
result.mode = EVAL_EvalMode_Value;
|
|
}
|
|
}
|
|
}break;
|
|
|
|
case EVAL_ExprKind_LeafBytecode:
|
|
{
|
|
EVAL_IRTree *new_tree = eval_irtree_bytecode_no_copy(arena, expr->bytecode);
|
|
TG_Key final_type_key = expr->type_key;
|
|
EVAL_EvalMode mode = expr->mode;
|
|
|
|
result.tree = new_tree;
|
|
result.type_key = final_type_key;
|
|
result.mode = mode;
|
|
}break;
|
|
|
|
case EVAL_ExprKind_LeafMember:
|
|
{
|
|
eval_errorf(arena, eout, EVAL_ErrorKind_MalformedInput, expr->location, "(internal) Leaf member not expected here.");
|
|
}break;
|
|
|
|
case EVAL_ExprKind_LeafU64:
|
|
{
|
|
U64 val = expr->u64;
|
|
EVAL_IRTree *new_tree = eval_irtree_const_u(arena, val);
|
|
|
|
TG_Key type_key = zero_struct;
|
|
if (val <= max_S32){
|
|
type_key = tg_key_basic(TG_Kind_S32);
|
|
}
|
|
else if (val <= max_S64){
|
|
type_key = tg_key_basic(TG_Kind_S64);
|
|
}
|
|
else{
|
|
type_key = tg_key_basic(TG_Kind_U64);
|
|
}
|
|
|
|
result.tree = new_tree;
|
|
result.type_key = type_key;
|
|
result.mode = EVAL_EvalMode_Value;
|
|
}break;
|
|
|
|
case EVAL_ExprKind_LeafF64:
|
|
{
|
|
U64 val = expr->u64;
|
|
EVAL_IRTree *new_tree = eval_irtree_const_u(arena, val);
|
|
|
|
result.tree = new_tree;
|
|
result.type_key = tg_key_basic(TG_Kind_F64);
|
|
result.mode = EVAL_EvalMode_Value;
|
|
}break;
|
|
|
|
case EVAL_ExprKind_LeafF32:
|
|
{
|
|
U32 val = expr->u32;
|
|
EVAL_IRTree *new_tree = eval_irtree_const_u(arena, val);
|
|
|
|
result.tree = new_tree;
|
|
result.type_key = tg_key_basic(TG_Kind_F32);
|
|
result.mode = EVAL_EvalMode_Value;
|
|
}break;
|
|
|
|
case EVAL_ExprKind_TypeIdent:
|
|
{
|
|
result.tree = &eval_irtree_nil;
|
|
result.type_key = expr->type_key;
|
|
result.mode = EVAL_EvalMode_NULL;
|
|
}break;
|
|
case EVAL_ExprKind_Ptr:
|
|
case EVAL_ExprKind_Array:
|
|
case EVAL_ExprKind_Func:
|
|
{
|
|
eval_errorf(arena, eout, EVAL_ErrorKind_MalformedInput, expr->location, "Type expression not expected.");
|
|
}break;
|
|
|
|
case EVAL_ExprKind_Define:
|
|
{
|
|
if(expr->children[0]->kind != EVAL_ExprKind_LeafIdent)
|
|
{
|
|
eval_errorf(arena, eout, EVAL_ErrorKind_MalformedInput, expr->location, "Left side of assignment must be an identifier.");
|
|
}
|
|
result = eval_irtree_and_type_from_expr(arena, graph, rdbg, leaf_ident_expr_map, expr->children[1], eout);
|
|
}break;
|
|
case EVAL_ExprKind_LeafIdent:
|
|
{
|
|
String8 name = expr->name;
|
|
EVAL_Expr *leaf_ident_expr = eval_expr_from_string(leaf_ident_expr_map, name);
|
|
if(leaf_ident_expr == &eval_expr_nil)
|
|
{
|
|
eval_errorf(arena, eout, EVAL_ErrorKind_ResolutionFailure, expr->location, "\"%S\" could not be found.", name);
|
|
}
|
|
else
|
|
{
|
|
eval_string2expr_map_inc_poison(leaf_ident_expr_map, name);
|
|
result = eval_irtree_and_type_from_expr(arena, graph, rdbg, leaf_ident_expr_map, leaf_ident_expr, eout);
|
|
eval_string2expr_map_dec_poison(leaf_ident_expr_map, name);
|
|
}
|
|
}break;
|
|
}
|
|
|
|
ProfEnd();
|
|
return(result);
|
|
}
|
|
|
|
internal void
|
|
eval_oplist_from_irtree(Arena *arena, EVAL_IRTree *tree, EVAL_OpList *out){
|
|
ProfBeginFunction();
|
|
U32 op = tree->op;
|
|
switch (op){
|
|
case RADDBGI_EvalOp_Stop:
|
|
case RADDBGI_EvalOp_Skip:
|
|
{
|
|
// TODO: error - invalid ir-tree op
|
|
}break;
|
|
|
|
case EVAL_IRExtKind_Bytecode:
|
|
{
|
|
eval_oplist_push_bytecode(arena, out, tree->bytecode);
|
|
}break;
|
|
|
|
case RADDBGI_EvalOp_Cond:
|
|
{
|
|
// split out each of the children
|
|
EVAL_OpList prt_cond = {0};
|
|
eval_oplist_from_irtree(arena, tree->children[0], &prt_cond);
|
|
|
|
EVAL_OpList prt_left = {0};
|
|
eval_oplist_from_irtree(arena, tree->children[1], &prt_left);
|
|
|
|
EVAL_OpList prt_right = {0};
|
|
eval_oplist_from_irtree(arena, tree->children[2], &prt_right);
|
|
|
|
// put together like so:
|
|
// 1. <prt_cond> , Op_Cond (sizeof(2))
|
|
// 2. <prt_right>, Op_Skip (sizeof(3))
|
|
// 3. <ptr_left>
|
|
// 4.
|
|
|
|
// modify prt_right in place to create step 2
|
|
eval_oplist_push_op(arena, &prt_right, RADDBGI_EvalOp_Skip, prt_left.encoded_size);
|
|
|
|
// merge 1 into out
|
|
eval_oplist_concat_in_place(out, &prt_cond);
|
|
eval_oplist_push_op(arena, out, RADDBGI_EvalOp_Cond, prt_right.encoded_size);
|
|
|
|
// merge 2 into out
|
|
eval_oplist_concat_in_place(out, &prt_right);
|
|
|
|
// merge 3 into out
|
|
eval_oplist_concat_in_place(out, &prt_left);
|
|
}break;
|
|
|
|
default:
|
|
{
|
|
if (op >= RADDBGI_EvalOp_COUNT){
|
|
// TODO: error - invalid ir-tree op
|
|
}
|
|
else{
|
|
// handle all children
|
|
U8 ctrlbits = raddbgi_eval_opcode_ctrlbits[op];
|
|
U64 child_count = RADDBGI_POPN_FROM_CTRLBITS(ctrlbits);
|
|
EVAL_IRTree**child = tree->children;
|
|
for (U64 i = 0; i < child_count; i += 1, child += 1){
|
|
eval_oplist_from_irtree(arena, *child, out);
|
|
}
|
|
|
|
// emit op to compute this node
|
|
eval_oplist_push_op(arena, out, (RADDBGI_EvalOp)tree->op, tree->p);
|
|
}
|
|
}break;
|
|
}
|
|
ProfEnd();
|
|
}
|