d2r2: function type info; fix reg+off location info for signed offsets, function type deduplicating / construction / referencing, etc.

This commit is contained in:
Ryan Fleury
2026-04-29 15:50:31 -07:00
parent 9a923e9bf9
commit 230b004742
6 changed files with 368 additions and 52 deletions
+1 -1
View File
@@ -1121,7 +1121,7 @@ typedef RDI_U64 RDI_Location;
#define RDI_Location_RegOffShift 32 #define RDI_Location_RegOffShift 32
#define rdi_kind_from_location(l) ((((l) & RDI_Location_KindMask) >> RDI_Location_KindShift)) #define rdi_kind_from_location(l) ((((l) & RDI_Location_KindMask) >> RDI_Location_KindShift))
#define rdi_regcode_from_location(l) ((rdi_kind_from_location(l) == RDI_LocationKind_AddrRegPlusOff || rdi_kind_from_location(l) == RDI_LocationKind_AddrAddrRegPlusOff || rdi_kind_from_location(l) == RDI_LocationKind_ValReg) ? (((l) & RDI_Location_RegCodeMask) >> RDI_Location_RegCodeShift) : 0) #define rdi_regcode_from_location(l) ((rdi_kind_from_location(l) == RDI_LocationKind_AddrRegPlusOff || rdi_kind_from_location(l) == RDI_LocationKind_AddrAddrRegPlusOff || rdi_kind_from_location(l) == RDI_LocationKind_ValReg) ? (((l) & RDI_Location_RegCodeMask) >> RDI_Location_RegCodeShift) : 0)
#define rdi_regoff_from_location(l) (RDI_S64)((rdi_kind_from_location(l) == RDI_LocationKind_AddrRegPlusOff || rdi_kind_from_location(l) == RDI_LocationKind_AddrAddrRegPlusOff) ? (((l) & RDI_Location_RegOffMask) >> RDI_Location_RegOffShift) : 0) #define rdi_regoff_from_location(l) (RDI_S64)(RDI_S32)(RDI_S16)((rdi_kind_from_location(l) == RDI_LocationKind_AddrRegPlusOff || rdi_kind_from_location(l) == RDI_LocationKind_AddrAddrRegPlusOff) ? (((l) & RDI_Location_RegOffMask) >> RDI_Location_RegOffShift) : 0)
#define rdi_voff_from_location(l) (rdi_kind_from_location(l) == RDI_LocationKind_ModuleOff ? (((l) & RDI_Location_OffMask) >> RDI_Location_OffShift) : 0) #define rdi_voff_from_location(l) (rdi_kind_from_location(l) == RDI_LocationKind_ModuleOff ? (((l) & RDI_Location_OffMask) >> RDI_Location_OffShift) : 0)
#define rdi_toff_from_location(l) (rdi_kind_from_location(l) == RDI_LocationKind_TLSOff ? (((l) & RDI_Location_OffMask) >> RDI_Location_OffShift) : 0) #define rdi_toff_from_location(l) (rdi_kind_from_location(l) == RDI_LocationKind_TLSOff ? (((l) & RDI_Location_OffMask) >> RDI_Location_OffShift) : 0)
#define rdi_constant_data_off_from_location(l) (rdi_kind_from_location(l) == RDI_LocationKind_ConstantDataOff ? (((l) & RDI_Location_OffMask) >> RDI_Location_OffShift) : 0) #define rdi_constant_data_off_from_location(l) (rdi_kind_from_location(l) == RDI_LocationKind_ConstantDataOff ? (((l) & RDI_Location_OffMask) >> RDI_Location_OffShift) : 0)
+2 -2
View File
@@ -956,8 +956,8 @@ rb_thread_entry_point(void *p)
{ {
bake_params = push_array(arena, RDIM_BakeParams, 1); bake_params = push_array(arena, RDIM_BakeParams, 1);
rdim_bake_params_concat_in_place(bake_params, &pdb_bake_params); rdim_bake_params_concat_in_place(bake_params, &pdb_bake_params);
rdim_bake_params_concat_in_place(bake_params, &dwarf_bake_params); // rdim_bake_params_concat_in_place(bake_params, &dwarf_bake_params);
// rdim_bake_params_concat_in_place(bake_params, &dwarf_bake_params_2); rdim_bake_params_concat_in_place(bake_params, &dwarf_bake_params_2);
for EachNode(n, RDIM_BakeParamsNode, first_rdi_bake_params) for EachNode(n, RDIM_BakeParamsNode, first_rdi_bake_params)
{ {
rdim_bake_params_concat_in_place(bake_params, &n->v); rdim_bake_params_concat_in_place(bake_params, &n->v);
+3 -3
View File
@@ -44,9 +44,9 @@
// [x] container can also be a unit, so you can also go from procedure/global/tvar -> unit // [x] container can also be a unit, so you can also go from procedure/global/tvar -> unit
// [x] *OR*, because we can guarantee that the units themselves will be sorted from lowest -> highest in all symbol tables, we can simply binary search the unit table (small) with a symbol's index to find its corresponding unit. that way, no need to duplicate e.g. namespaces and so on across units. and actually, we have to do this, because containers can be types, and those cannot be unit-locked. // [x] *OR*, because we can guarantee that the units themselves will be sorted from lowest -> highest in all symbol tables, we can simply binary search the unit table (small) with a symbol's index to find its corresponding unit. that way, no need to duplicate e.g. namespaces and so on across units. and actually, we have to do this, because containers can be types, and those cannot be unit-locked.
// //
// [ ] symbols only store their *partly-qualified name*, e.g. `x` for A::B::C::x // [x] symbols only store their *partly-qualified name*, e.g. `x` for A::B::C::x
// [ ] default name maps look up *partly-qualified names* // [x] default name maps look up *partly-qualified names*
// [ ] to match a *fully qualified name*, there needs to be a second kind of different lookup - instead of string-matching, we need to match against the *fully qualified names*. the maps must be built by hashing the *fully qualified name*, but redirecting to the symbol with the *partially qualified name*. this is to allow fully-qualified lookups, but avoid storing fully-qualified names. // [x] to match a *fully qualified name*, there needs to be a second kind of different lookup - instead of string-matching, we need to match against the *fully qualified names*. the maps must be built by hashing the *fully qualified name*, but redirecting to the symbol with the *partially qualified name*. this is to allow fully-qualified lookups, but avoid storing fully-qualified names.
// //
//- urgent fixes //- urgent fixes
// [ ] (use msvc assert as an example) show fastfail exception info (code, name, etc.) - comes from ExceptionInformation @fastfail // [ ] (use msvc assert as an example) show fastfail exception info (code, name, etc.) - comes from ExceptionInformation @fastfail
+1 -1
View File
@@ -1116,7 +1116,7 @@ RDI_LocationSetElementMemberTable:
`#define RDI_Location_RegOffShift 32`; `#define RDI_Location_RegOffShift 32`;
`#define rdi_kind_from_location(l) ((((l) & RDI_Location_KindMask) >> RDI_Location_KindShift))`; `#define rdi_kind_from_location(l) ((((l) & RDI_Location_KindMask) >> RDI_Location_KindShift))`;
`#define rdi_regcode_from_location(l) ((rdi_kind_from_location(l) == RDI_LocationKind_AddrRegPlusOff || rdi_kind_from_location(l) == RDI_LocationKind_AddrAddrRegPlusOff || rdi_kind_from_location(l) == RDI_LocationKind_ValReg) ? (((l) & RDI_Location_RegCodeMask) >> RDI_Location_RegCodeShift) : 0)`; `#define rdi_regcode_from_location(l) ((rdi_kind_from_location(l) == RDI_LocationKind_AddrRegPlusOff || rdi_kind_from_location(l) == RDI_LocationKind_AddrAddrRegPlusOff || rdi_kind_from_location(l) == RDI_LocationKind_ValReg) ? (((l) & RDI_Location_RegCodeMask) >> RDI_Location_RegCodeShift) : 0)`;
`#define rdi_regoff_from_location(l) (RDI_S64)((rdi_kind_from_location(l) == RDI_LocationKind_AddrRegPlusOff || rdi_kind_from_location(l) == RDI_LocationKind_AddrAddrRegPlusOff) ? (((l) & RDI_Location_RegOffMask) >> RDI_Location_RegOffShift) : 0)`; `#define rdi_regoff_from_location(l) (RDI_S64)(RDI_S32)(RDI_S16)((rdi_kind_from_location(l) == RDI_LocationKind_AddrRegPlusOff || rdi_kind_from_location(l) == RDI_LocationKind_AddrAddrRegPlusOff) ? (((l) & RDI_Location_RegOffMask) >> RDI_Location_RegOffShift) : 0)`;
`#define rdi_voff_from_location(l) (rdi_kind_from_location(l) == RDI_LocationKind_ModuleOff ? (((l) & RDI_Location_OffMask) >> RDI_Location_OffShift) : 0)`; `#define rdi_voff_from_location(l) (rdi_kind_from_location(l) == RDI_LocationKind_ModuleOff ? (((l) & RDI_Location_OffMask) >> RDI_Location_OffShift) : 0)`;
`#define rdi_toff_from_location(l) (rdi_kind_from_location(l) == RDI_LocationKind_TLSOff ? (((l) & RDI_Location_OffMask) >> RDI_Location_OffShift) : 0)`; `#define rdi_toff_from_location(l) (rdi_kind_from_location(l) == RDI_LocationKind_TLSOff ? (((l) & RDI_Location_OffMask) >> RDI_Location_OffShift) : 0)`;
`#define rdi_constant_data_off_from_location(l) (rdi_kind_from_location(l) == RDI_LocationKind_ConstantDataOff ? (((l) & RDI_Location_OffMask) >> RDI_Location_OffShift) : 0)`; `#define rdi_constant_data_off_from_location(l) (rdi_kind_from_location(l) == RDI_LocationKind_ConstantDataOff ? (((l) & RDI_Location_OffMask) >> RDI_Location_OffShift) : 0)`;
+1 -1
View File
@@ -1073,7 +1073,7 @@ lane_sync(); if(flags & (1ull<<(kind))) ProfScope(rdi_name_title_from_dump_subse
S64 reg_off = rdi_regoff_from_location(location); S64 reg_off = rdi_regoff_from_location(location);
String8 reg_code_string = rdi_string_from_reg_code(scratch.arena, tli->arch, reg_code); String8 reg_code_string = rdi_string_from_reg_code(scratch.arena, tli->arch, reg_code);
dumpf(" reg: %S\n", reg_code_string); dumpf(" reg: %S\n", reg_code_string);
dumpf(" reg_off: 0x%I64x\n", reg_off); dumpf(" reg_off: %I64d (0x%x)\n", reg_off, (U16)reg_off);
}break; }break;
case RDI_LocationKind_ValReg: case RDI_LocationKind_ValReg:
{ {
+360 -44
View File
@@ -1377,6 +1377,10 @@ d2r2_convert(Arena *arena, D2R2_ConvertParams *params)
DW2_Tag tag = {0}; DW2_Tag tag = {0};
t_off += dw2_read_tag(scratch2.arena, unit_parse_ctx, raw->sec[DW_Section_Info].data, t_off, &tag); t_off += dw2_read_tag(scratch2.arena, unit_parse_ctx, raw->sec[DW_Section_Info].data, t_off, &tag);
// rjf: determine if tag should be skipped
B32 should_skip_tag = (tag.kind == DW_TagKind_LexicalBlock ||
tag.kind == DW_TagKind_Variable);
// rjf: record top-level info about this tag tree // rjf: record top-level info about this tag tree
if(t_start_off == t->off && t == &start_task) if(t_start_off == t->off && t == &start_task)
{ {
@@ -1388,6 +1392,7 @@ d2r2_convert(Arena *arena, D2R2_ConvertParams *params)
tag.kind == DW_TagKind_StringType || tag.kind == DW_TagKind_StringType ||
tag.kind == DW_TagKind_StructureType || tag.kind == DW_TagKind_StructureType ||
tag.kind == DW_TagKind_SubroutineType || tag.kind == DW_TagKind_SubroutineType ||
tag.kind == DW_TagKind_SubProgram ||
tag.kind == DW_TagKind_Typedef || tag.kind == DW_TagKind_Typedef ||
tag.kind == DW_TagKind_UnionType || tag.kind == DW_TagKind_UnionType ||
tag.kind == DW_TagKind_PtrToMemberType || tag.kind == DW_TagKind_PtrToMemberType ||
@@ -1409,7 +1414,7 @@ d2r2_convert(Arena *arena, D2R2_ConvertParams *params)
} }
// rjf: is type -> combine tag's content into hash // rjf: is type -> combine tag's content into hash
if(is_type_tag_tree) if(!should_skip_tag && is_type_tag_tree)
{ {
// rjf: combine tag's kind // rjf: combine tag's kind
hash = u64_hash_from_seed_str8(hash, str8_struct(&tag.kind)); hash = u64_hash_from_seed_str8(hash, str8_struct(&tag.kind));
@@ -1427,7 +1432,18 @@ d2r2_convert(Arena *arena, D2R2_ConvertParams *params)
n->v.val.kind != DW_Form_Ref8 && n->v.val.kind != DW_Form_Ref8 &&
n->v.val.kind != DW_Form_RefUData && n->v.val.kind != DW_Form_RefUData &&
n->v.val.kind != DW_Form_RefSup4 && n->v.val.kind != DW_Form_RefSup4 &&
n->v.val.kind != DW_Form_RefSig8) n->v.val.kind != DW_Form_RefSig8 &&
((tag.kind != DW_TagKind_SubProgram &&
tag.kind != DW_TagKind_FormalParameter) ||
(n->v.attrib_kind != DW_AttribKind_Name &&
n->v.attrib_kind != DW_AttribKind_DeclFile &&
n->v.attrib_kind != DW_AttribKind_DeclLine &&
n->v.attrib_kind != DW_AttribKind_Prototyped &&
n->v.attrib_kind != DW_AttribKind_External &&
n->v.attrib_kind != DW_AttribKind_FrameBase &&
n->v.attrib_kind != DW_AttribKind_Location &&
n->v.attrib_kind != DW_AttribKind_LowPc &&
n->v.attrib_kind != DW_AttribKind_HighPc)))
{ {
hash = u64_hash_from_seed_str8(hash, str8_struct(&n->v.val.kind)); hash = u64_hash_from_seed_str8(hash, str8_struct(&n->v.val.kind));
hash = u64_hash_from_seed_str8(hash, str8_struct(&n->v.val.u128)); hash = u64_hash_from_seed_str8(hash, str8_struct(&n->v.val.u128));
@@ -1638,26 +1654,40 @@ d2r2_convert(Arena *arena, D2R2_ConvertParams *params)
TypeDepChain *next; TypeDepChain *next;
U64 type_idx; U64 type_idx;
}; };
TypeDepChain **type_dep_chains = 0;
U64 *type_dep_chains_counts = 0; U64 *type_dep_chains_counts = 0;
ProfScope("gather per-type dependency chains") ProfScope("gather per-type dependency chains")
{ {
if(lane_idx() == 0) if(lane_idx() == 0)
{ {
type_dep_chains = push_array(scratch.arena, TypeDepChain *, type_count);
type_dep_chains_counts = push_array(scratch.arena, U64, type_count); type_dep_chains_counts = push_array(scratch.arena, U64, type_count);
} }
lane_sync_u64(&type_dep_chains, 0);
lane_sync_u64(&type_dep_chains_counts, 0); lane_sync_u64(&type_dep_chains_counts, 0);
Rng1U64 range = lane_range(type_count); Rng1U64 range = lane_range(type_count);
for EachInRange(root_type_idx, range) for EachInRange(root_type_idx, range)
{ {
for(U64 hash = type_tag_nodes[root_type_idx]->hash, next_hash = 0; typedef struct TypeChainTask TypeChainTask;
hash != 0; struct TypeChainTask
hash = next_hash) {
TypeChainTask *next;
U64 hash;
};
TypeChainTask start_task = {0, type_tag_nodes[root_type_idx]->hash};
TypeChainTask *top_task = &start_task;
TypeChainTask *free_task = 0;
TypeChainTask *last_t = 0;
for(TypeChainTask *t = top_task; t != 0; (last_t = t, t = t->next))
{ {
Temp scratch2 = scratch_begin(&scratch.arena, 1); Temp scratch2 = scratch_begin(&scratch.arena, 1);
// rjf: recycle old tasks
if(last_t != 0)
{
SLLStackPush(free_task, last_t);
}
// rjf: unpack task
U64 hash = t->hash;
// rjf: hash -> unique type tag node // rjf: hash -> unique type tag node
UniqueTypeTagNode *type_tag_node = 0; UniqueTypeTagNode *type_tag_node = 0;
{ {
@@ -1681,12 +1711,9 @@ d2r2_convert(Arena *arena, D2R2_ConvertParams *params)
unit_idx = type_tag_node->unit_idx; unit_idx = type_tag_node->unit_idx;
} }
// rjf: record this type in the dependency chain // rjf: record this type in the dependency chain count
if(type_tag_node != 0) if(type_tag_node != 0)
{ {
TypeDepChain *c = push_array(scratch.arena, TypeDepChain, 1);
c->type_idx = type_tag_node->order_idx;
SLLStackPush(type_dep_chains[root_type_idx], c);
type_dep_chains_counts[root_type_idx] += 1; type_dep_chains_counts[root_type_idx] += 1;
} }
@@ -1695,12 +1722,20 @@ d2r2_convert(Arena *arena, D2R2_ConvertParams *params)
Rng1U64 unit_info_tag_range = unit_info_tag_ranges[unit_idx]; Rng1U64 unit_info_tag_range = unit_info_tag_ranges[unit_idx];
// rjf: parse this type's tag // rjf: parse this type's tag
U64 read_off = info_off;
DW2_Tag tag = {0}; DW2_Tag tag = {0};
dw2_read_tag(scratch2.arena, unit_parse_ctx, raw->sec[DW_Section_Info].data, info_off, &tag); read_off += dw2_read_tag(scratch2.arena, unit_parse_ctx, raw->sec[DW_Section_Info].data, read_off, &tag);
// rjf: find direct type, if one exists // rjf: find direct types from this type tag
U64 direct_type_info_off = 0; typedef struct DirectTypeNode DirectTypeNode;
U64 direct_type_unit_idx = 0; struct DirectTypeNode
{
DirectTypeNode *next;
U64 info_off;
U64 unit_idx;
};
DirectTypeNode *first_direct_type = 0;
DirectTypeNode *last_direct_type = 0;
switch(tag.kind) switch(tag.kind)
{ {
default:{}break; default:{}break;
@@ -1713,39 +1748,115 @@ d2r2_convert(Arena *arena, D2R2_ConvertParams *params)
case DW_TagKind_ArrayType: case DW_TagKind_ArrayType:
case DW_TagKind_SubrangeType: case DW_TagKind_SubrangeType:
case DW_TagKind_Typedef: case DW_TagKind_Typedef:
case DW_TagKind_SubProgram:
case DW_TagKind_SubroutineType:
{ {
DW2_Attrib *direct_type_attrib = dw2_attrib_from_kind(&tag, DW_AttribKind_Type); // rjf: gather direct type
direct_type_info_off = dw2_reference_info_off_from_form_val(unit_parse_ctx, &direct_type_attrib->val);
direct_type_unit_idx = unit_idx;
if(!contains_1u64(unit_info_tag_range, direct_type_info_off))
{ {
Rng1U64Array unit_info_tag_ranges_array = {unit_info_tag_ranges, unit_count}; DW2_Attrib *direct_type_attrib = dw2_attrib_from_kind(&tag, DW_AttribKind_Type);
U64 new_unit_num = rng1u64_array_num_from_value__binary_search(&unit_info_tag_ranges_array, direct_type_info_off); U64 direct_type_info_off = dw2_reference_info_off_from_form_val(unit_parse_ctx, &direct_type_attrib->val);
if(0 < new_unit_num && new_unit_num <= unit_count) U64 direct_type_unit_idx = unit_idx;
if(!contains_1u64(unit_info_tag_range, direct_type_info_off))
{ {
direct_type_unit_idx = new_unit_num-1; Rng1U64Array unit_info_tag_ranges_array = {unit_info_tag_ranges, unit_count};
U64 new_unit_num = rng1u64_array_num_from_value__binary_search(&unit_info_tag_ranges_array, direct_type_info_off);
if(0 < new_unit_num && new_unit_num <= unit_count)
{
direct_type_unit_idx = new_unit_num-1;
}
}
DirectTypeNode *n = push_array(scratch2.arena, DirectTypeNode, 1);
n->info_off = direct_type_info_off;
n->unit_idx = direct_type_unit_idx;
SLLQueuePush(first_direct_type, last_direct_type, n);
}
// rjf: functions -> gather parameters
if(tag.has_children && (tag.kind == DW_TagKind_SubProgram || tag.kind == DW_TagKind_SubroutineType))
{
S64 depth = 1;
for(;depth > 0 && contains_1u64(unit_info_tag_range, read_off);)
{
U64 start_read_off = read_off;
// rjf: read child tag
DW2_Tag child_tag = {0};
read_off += dw2_read_tag(scratch2.arena, unit_parse_ctx, raw->sec[DW_Section_Info].data, read_off, &child_tag);
// rjf: formal parameters -> gather direct types
if(child_tag.kind == DW_TagKind_FormalParameter)
{
DW2_Attrib *direct_type_attrib = dw2_attrib_from_kind(&child_tag, DW_AttribKind_Type);
U64 direct_type_info_off = dw2_reference_info_off_from_form_val(unit_parse_ctx, &direct_type_attrib->val);
U64 direct_type_unit_idx = unit_idx;
if(!contains_1u64(unit_info_tag_range, direct_type_info_off))
{
Rng1U64Array unit_info_tag_ranges_array = {unit_info_tag_ranges, unit_count};
U64 new_unit_num = rng1u64_array_num_from_value__binary_search(&unit_info_tag_ranges_array, direct_type_info_off);
if(0 < new_unit_num && new_unit_num <= unit_count)
{
direct_type_unit_idx = new_unit_num-1;
}
}
DirectTypeNode *n = push_array(scratch2.arena, DirectTypeNode, 1);
n->info_off = direct_type_info_off;
n->unit_idx = direct_type_unit_idx;
SLLQueuePush(first_direct_type, last_direct_type, n);
}
// rjf: tree navigations
if(tag.has_children)
{
depth += 1;
}
if(tag.kind == DW_TagKind_Null)
{
depth -= 1;
}
if(read_off == start_read_off)
{
break;
}
} }
} }
}break; }break;
} }
// rjf: look up hash for direct type // rjf: for each dependency type, look up their hash, + spawn new tasks for them
U64 direct_type_hash = 0; for EachNode(n, DirectTypeNode, first_direct_type)
{ {
U64 off_hash = u64_hash_from_str8(str8_struct(&direct_type_info_off)); U64 direct_type_info_off = n->info_off;
U64 off_slot_idx = off_hash%unit_type_maps[direct_type_unit_idx].slots_count; U64 direct_type_unit_idx = n->unit_idx;
for(UnitTypeNode *n = unit_type_maps[direct_type_unit_idx].slots[off_slot_idx]; n != 0; n = n->next)
// rjf: direct type info offset -> hash
U64 direct_type_hash = 0;
{ {
if(n->src_info_off == direct_type_info_off) U64 off_hash = u64_hash_from_str8(str8_struct(&direct_type_info_off));
U64 off_slot_idx = off_hash%unit_type_maps[direct_type_unit_idx].slots_count;
for(UnitTypeNode *n = unit_type_maps[direct_type_unit_idx].slots[off_slot_idx]; n != 0; n = n->next)
{ {
direct_type_hash = n->dst_hash; if(n->src_info_off == direct_type_info_off)
break; {
direct_type_hash = n->dst_hash;
break;
}
} }
} }
}
// rjf: iterate to direct type's hash // rjf: spawn task
next_hash = direct_type_hash; TypeChainTask *new_task = free_task;
if(new_task != 0)
{
SLLStackPop(free_task);
}
else
{
new_task = push_array(scratch.arena, TypeChainTask, 1);
}
new_task->hash = direct_type_hash;
t->next = new_task;
}
scratch_end(scratch2); scratch_end(scratch2);
} }
@@ -1940,9 +2051,116 @@ d2r2_convert(Arena *arena, D2R2_ConvertParams *params)
dst_type->direct_type = direct_type; dst_type->direct_type = direct_type;
dst_type->byte_size = (direct_type != 0 ? direct_type->byte_size : bitsize/8); dst_type->byte_size = (direct_type != 0 ? direct_type->byte_size : bitsize/8);
}break; }break;
case DW_TagKind_SubProgram:
case DW_TagKind_SubroutineType: case DW_TagKind_SubroutineType:
{ {
// rjf: build type
dst_type = rdim_type_chunk_list_push(arena, &lane_types, lane_types_chunk_count);
dst_type->kind = RDI_TypeKind_Function;
dst_type->name = name;
dst_type->direct_type = direct_type;
dst_type->byte_size = arch_addr_size;
// rjf: gather all parameter types
typedef struct ParamNode ParamNode;
struct ParamNode
{
ParamNode *next;
U64 type_unit_idx;
U64 type_info_off;
};
ParamNode *first_param = 0;
ParamNode *last_param = 0;
U64 param_count = 0;
{
U64 tag_children_off = info_off + tag_info_size;
S64 depth = 1;
for(U64 off = tag_children_off; depth > 0 && contains_1u64(unit_info_tag_range, off);)
{
U64 start_off = off;
// rjf: read child tag
DW2_Tag child_tag = {0};
off += dw2_read_tag(scratch2.arena, unit_parse_ctx, raw->sec[DW_Section_Info].data, off, &child_tag);
// rjf: gather parameters
if(child_tag.kind == DW_TagKind_FormalParameter)
{
DW2_Attrib *type_attrib = dw2_attrib_from_kind(&child_tag, DW_AttribKind_Type);
ParamNode *n = push_array(scratch2.arena, ParamNode, 1);
n->type_info_off = dw2_reference_info_off_from_form_val(unit_parse_ctx, &direct_type_attrib->val);
n->type_unit_idx = unit_idx;
SLLQueuePush(first_param, last_param, n);
if(!contains_1u64(unit_info_tag_range, n->type_info_off))
{
Rng1U64Array unit_info_tag_ranges_array = {unit_info_tag_ranges, unit_count};
U64 new_unit_num = rng1u64_array_num_from_value__binary_search(&unit_info_tag_ranges_array, n->type_info_off);
n->type_unit_idx = (new_unit_num > 0 ? new_unit_num-1 : unit_idx);
}
param_count += 1;
}
// rjf: navigate tree
if(child_tag.kind == DW_TagKind_Null)
{
depth -= 1;
}
if(child_tag.has_children)
{
depth += 1;
}
if(off == start_off)
{
break;
}
}
}
// rjf: tighten parameter types
dst_type->count = (RDI_U32)param_count; // TODO(rjf): @u64_to_u32
dst_type->param_types = push_array(arena, RDIM_Type *, dst_type->count);
{
U64 param_idx = 0;
for(ParamNode *n = first_param; n != 0; n = n->next, param_idx += 1)
{
U64 param_type_info_off = n->type_info_off;
U64 param_type_unit_idx = n->type_unit_idx;
// rjf: map info_off/unit_idx -> hash
U64 param_type_hash = 0;
{
UnitTypeMap *direct_type_unit_type_map = &unit_type_maps[param_type_unit_idx];
U64 info_off_hash = u64_hash_from_str8(str8_struct(&param_type_info_off));
U64 info_off_slot_idx = info_off_hash%direct_type_unit_type_map->slots_count;
for(UnitTypeNode *n = direct_type_unit_type_map->slots[info_off_slot_idx]; n != 0; n = n->next)
{
if(n->src_info_off == param_type_info_off)
{
param_type_hash = n->dst_hash;
break;
}
}
}
// rjf: map hash -> type
RDIM_Type *param_type = 0;
{
U64 unique_type_tag_slot_idx = param_type_hash%unique_type_tag_slots_count;
for(UniqueTypeTagNode *n = unique_type_tag_slots[unique_type_tag_slot_idx]; n != 0; n = n->next)
{
if(n->hash == param_type_hash)
{
param_type = type_from_idx_map[n->order_idx];
break;
}
}
}
// rjf: store
dst_type->param_types[param_idx] = param_type;
}
}
}break; }break;
case DW_TagKind_Typedef: case DW_TagKind_Typedef:
{ {
@@ -2458,14 +2676,23 @@ d2r2_convert(Arena *arena, D2R2_ConvertParams *params)
RDIM_Type *type = 0; RDIM_Type *type = 0;
if(type_attrib != &dw2_attrib_nil) if(type_attrib != &dw2_attrib_nil)
{ {
// rjf: attrib -> (info_off, unit_idx) // rjf: functions need to get their type info from themselves; the type attrib
U64 type_info_off = dw2_reference_info_off_from_form_val(unit_parse_ctx, &type_attrib->val); // only references the return type. so, in that case, we'll use the procedure's
// own info offset / unit index, rather than the type attribute's.
U64 type_info_off = start_off;
U64 type_unit_idx = unit_idx; U64 type_unit_idx = unit_idx;
if(!contains_1u64(unit_info_tag_range, type_info_off))
// rjf: attrib -> (info_off, unit_idx)
if(tag.kind != DW_TagKind_SubProgram)
{ {
Rng1U64Array unit_info_tag_ranges_array = {unit_info_tag_ranges, unit_count}; type_info_off = dw2_reference_info_off_from_form_val(unit_parse_ctx, &type_attrib->val);
U64 new_unit_num = rng1u64_array_num_from_value__binary_search(&unit_info_tag_ranges_array, type_info_off); type_unit_idx = unit_idx;
type_unit_idx = (new_unit_num > 0 ? new_unit_num-1 : unit_idx); if(!contains_1u64(unit_info_tag_range, type_info_off))
{
Rng1U64Array unit_info_tag_ranges_array = {unit_info_tag_ranges, unit_count};
U64 new_unit_num = rng1u64_array_num_from_value__binary_search(&unit_info_tag_ranges_array, type_info_off);
type_unit_idx = (new_unit_num > 0 ? new_unit_num-1 : unit_idx);
}
} }
// rjf: (info_off, unit_idx) -> hash // rjf: (info_off, unit_idx) -> hash
@@ -3137,6 +3364,93 @@ d2r2_convert(Arena *arena, D2R2_ConvertParams *params)
{ {
loc.kind = val_stack_top && val_stack_top->v.is_addr ? RDI_LocationKind_AddrBytecodeStream : RDI_LocationKind_ValBytecodeStream; loc.kind = val_stack_top && val_stack_top->v.is_addr ? RDI_LocationKind_AddrBytecodeStream : RDI_LocationKind_ValBytecodeStream;
loc.bytecode = dst_bytecode; loc.bytecode = dst_bytecode;
// rjf: gather first few bytecodes for pattern matching
RDI_EvalOp beginning_ops[5] = {0};
RDIM_EvalBytecodeOp *beginning_nodes[5] = {0};
{
U64 idx = 0;
for EachNode(n, RDIM_EvalBytecodeOp, dst_bytecode.first_op)
{
if(idx >= ArrayCount(beginning_ops))
{
break;
}
beginning_ops[idx] = n->op;
beginning_nodes[idx] = n;
idx += 1;
}
}
// rjf: match simple register offsets
if(loc.kind == RDI_LocationKind_AddrBytecodeStream &&
beginning_ops[0] == RDI_EvalOp_RegRead &&
(beginning_ops[1] == RDI_EvalOp_ConstU8 ||
beginning_ops[1] == RDI_EvalOp_ConstU16) &&
beginning_ops[2] == RDI_EvalOp_TruncSigned &&
beginning_ops[3] == RDI_EvalOp_Add &&
beginning_ops[4] == RDI_EvalOp_Stop)
{
U8 rdi_reg_code = (beginning_nodes[0]->p&0x0000FF)>>0;
U8 byte_size = (beginning_nodes[0]->p&0x00FF00)>>8;
U8 byte_off = (beginning_nodes[0]->p&0xFF0000)>>16;
if(byte_off == 0 && byte_size == unit_parse_ctx->addr_size)
{
loc.kind = RDI_LocationKind_AddrRegPlusOff;
loc.reg_code = rdi_reg_code;
loc.offset = beginning_nodes[1]->p;
}
}
// rjf: match simple module offsets
if(beginning_ops[0] == RDI_EvalOp_ModuleOff && beginning_ops[1] == RDI_EvalOp_Stop)
{
U64 voff = beginning_nodes[0]->p;
loc.kind = RDI_LocationKind_ModuleOff;
loc.offset = voff;
}
else if(((beginning_ops[0] == RDI_EvalOp_ModuleOff &&
(beginning_ops[1] == RDI_EvalOp_ConstU8 ||
beginning_ops[1] == RDI_EvalOp_ConstU16 ||
beginning_ops[1] == RDI_EvalOp_ConstU32 ||
beginning_ops[1] == RDI_EvalOp_ConstU64)) ||
(beginning_ops[1] == RDI_EvalOp_ModuleOff &&
(beginning_ops[0] == RDI_EvalOp_ConstU8 ||
beginning_ops[0] == RDI_EvalOp_ConstU16 ||
beginning_ops[0] == RDI_EvalOp_ConstU32 ||
beginning_ops[0] == RDI_EvalOp_ConstU64))) &&
beginning_ops[2] == RDI_EvalOp_Add &&
beginning_ops[3] == RDI_EvalOp_Stop)
{
U64 voff = beginning_nodes[0]->p + beginning_nodes[1]->p;
loc.kind = RDI_LocationKind_ModuleOff;
loc.offset = voff;
}
// rjf: match simple TLS offsets
if(beginning_ops[0] == RDI_EvalOp_TLSOff && beginning_ops[1] == RDI_EvalOp_Stop)
{
U64 toff = beginning_nodes[0]->p;
loc.kind = RDI_LocationKind_TLSOff;
loc.offset = toff;
}
else if(((beginning_ops[0] == RDI_EvalOp_TLSOff &&
(beginning_ops[1] == RDI_EvalOp_ConstU8 ||
beginning_ops[1] == RDI_EvalOp_ConstU16 ||
beginning_ops[1] == RDI_EvalOp_ConstU32 ||
beginning_ops[1] == RDI_EvalOp_ConstU64)) ||
(beginning_ops[1] == RDI_EvalOp_TLSOff &&
(beginning_ops[0] == RDI_EvalOp_ConstU8 ||
beginning_ops[0] == RDI_EvalOp_ConstU16 ||
beginning_ops[0] == RDI_EvalOp_ConstU32 ||
beginning_ops[0] == RDI_EvalOp_ConstU64))) &&
beginning_ops[2] == RDI_EvalOp_Add &&
beginning_ops[3] == RDI_EvalOp_Stop)
{
U64 toff = beginning_nodes[0]->p + beginning_nodes[1]->p;
loc.kind = RDI_LocationKind_TLSOff;
loc.offset = toff;
}
} }
//- rjf: collect //- rjf: collect
@@ -3174,9 +3488,11 @@ d2r2_convert(Arena *arena, D2R2_ConvertParams *params)
{ {
RDIM_Scope *root_scope = rdim_scope_chunk_list_push(arena, &dst_unit->scopes, chunk_count); RDIM_Scope *root_scope = rdim_scope_chunk_list_push(arena, &dst_unit->scopes, chunk_count);
RDIM_Symbol *procedure = rdim_symbol_chunk_list_push(arena, &dst_unit->procedures, chunk_count); RDIM_Symbol *procedure = rdim_symbol_chunk_list_push(arena, &dst_unit->procedures, chunk_count);
procedure->name = name; procedure->name = name;
procedure->link_name = link_name; procedure->link_name = link_name;
procedure->root_scope = root_scope; procedure->type = type;
procedure->root_scope = root_scope;
procedure->location_cases = framebase_location_cases;
root_scope->symbol = procedure; root_scope->symbol = procedure;
root_scope->voff_ranges = ranges; root_scope->voff_ranges = ranges;
dst_unit->scopes.scope_voff_count += 2; dst_unit->scopes.scope_voff_count += 2;