// 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. , Op_Cond (sizeof(2)) // 2. , Op_Skip (sizeof(3)) // 3. // 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(); }