// Copyright (c) Epic Games Tools // Licensed under the MIT license (https://opensource.org/license/mit/) #include "lib_rdi_make/rdi_make.c" internal RDIM_DataModel rdim_data_model_from_os_arch(OperatingSystem os, RDI_Arch arch) { RDIM_DataModel data_model = RDIM_DataModel_Null; #define Case(os_name, arch_name, model_name) if(os == OperatingSystem_##os_name && arch == Arch_##arch_name) { data_model = RDIM_DataModel_##model_name; } Case(Windows, x86, LLP64); Case(Windows, x64, LLP64); Case(Linux, x86, ILP32); Case(Linux, x64, LLP64); Case(Mac, x64, LP64); #undef Case return data_model; } internal RDIM_TopLevelInfo rdim_make_top_level_info(String8 image_name, Arch arch, U64 exe_hash, RDIM_BinarySectionList sections) { // convert arch RDI_Arch arch_rdi = RDI_Arch_NULL; switch(arch) { default:{}break; case Arch_x64:{arch_rdi = RDI_Arch_X64;}break; case Arch_x86:{NotImplemented;}break; } // find max VOFF U64 exe_voff_max = 0; for EachNode(sect_n, RDIM_BinarySectionNode, sections.first) { exe_voff_max = Max(exe_voff_max, sect_n->v.voff_opl); } // fill out top level info RDIM_TopLevelInfo top_level_info = {0}; top_level_info.arch = arch_rdi; top_level_info.exe_hash = exe_hash; top_level_info.voff_max = exe_voff_max; top_level_info.producer_name = str8_lit(BUILD_TITLE_STRING_LITERAL); return top_level_info; } internal RDIM_BakeParams rdim_loose_from_rdi(Arena *arena, RDIM_SubsetFlags subset_flags, RDI_Parsed *rdi) { //- rjf: setup bake params RDIM_BakeParams *bp = 0; if(lane_idx() == 0) { bp = push_array(arena, RDIM_BakeParams, 1); bp->subset_flags = subset_flags; } lane_sync_u64(&bp, 0); //- rjf: convert top level info if(lane_idx() == 0) { RDI_TopLevelInfo *tli = rdi_element_from_name_idx(rdi, TopLevelInfo, 0); bp->top_level_info.arch = tli->arch; bp->top_level_info.exe_name.str = rdi_string_from_idx(rdi, tli->exe_name_string_idx, &bp->top_level_info.exe_name.size); bp->top_level_info.exe_hash = tli->exe_hash; bp->top_level_info.voff_max = tli->voff_max; bp->top_level_info.guid = tli->guid; bp->top_level_info.producer_name.str = rdi_string_from_idx(rdi, tli->producer_name_string_idx, &bp->top_level_info.producer_name.size); } lane_sync(); //- rjf: convert binary sections if(lane_idx() == 0) { U64 count = 0; RDI_BinarySection *v = rdi_table_from_name(rdi, BinarySections, &count); for EachIndex(idx, count) { RDIM_BinarySection *bsec = rdim_binary_section_list_push(arena, &bp->binary_sections); bsec->name.str = rdi_string_from_idx(rdi, v[idx].name_string_idx, &bsec->name.size); bsec->flags = v[idx].flags; bsec->voff_first = v[idx].voff_first; bsec->voff_opl = v[idx].voff_opl; bsec->foff_first = v[idx].foff_first; bsec->foff_opl = v[idx].foff_opl; } } lane_sync(); //- rjf: bucket voff ranges by unit idx RDIM_Rng1U64ChunkList *unit_ranges = 0; if(lane_idx() == 0) { U64 units_count = 0; rdi_table_from_name(rdi, Units, &units_count); U64 unit_vmap_count = 0; RDI_VMapEntry *unit_vmap = rdi_table_from_name(rdi, UnitVMap, &unit_vmap_count); unit_ranges = push_array(arena, RDIM_Rng1U64ChunkList, units_count); if(unit_vmap_count > 0) { for EachIndex(idx, unit_vmap_count-1) { RDIM_Rng1U64 rng = {unit_vmap[idx].voff, unit_vmap[idx+1].voff}; rdim_rng1u64_chunk_list_push(arena, &unit_ranges[unit_vmap[idx].idx], 256, rng); } } } lane_sync_u64(&unit_ranges, 0); //- rjf: convert src files RDIM_SrcFileChunkList *src_files = 0; RDIM_SrcFile **src_file_from_idx_table = 0; { U64 src_file_count = 0; RDI_SourceFile *src_file_v = rdi_table_from_name(rdi, SourceFiles, &src_file_count); RDIM_SrcFileChunkList *lane_srcfiles = 0; if(lane_idx() == 0) { src_files = push_array(arena, RDIM_SrcFileChunkList, 1); src_file_from_idx_table = push_array(arena, RDIM_SrcFile *, src_file_count); lane_srcfiles = push_array(arena, RDIM_SrcFileChunkList, lane_count()); } lane_sync_u64(&lane_srcfiles, 0); { Rng1U64 range = lane_range(src_file_count); for EachInRange(idx, range) { RDI_SourceFile *src = &src_file_v[idx]; RDIM_SrcFile *dst = rdim_src_file_chunk_list_push(arena, &lane_srcfiles[lane_idx()], dim_1u64(range)); // rjf: get checksum String8 checksum = {0}; switch(src->checksum_kind) { default:{}break; case RDI_ChecksumKind_MD5: {checksum = str8(rdi_element_from_name_idx(rdi, MD5Checksums, src->checksum_idx)->u8, sizeof(RDI_MD5));}break; case RDI_ChecksumKind_SHA1: {checksum = str8(rdi_element_from_name_idx(rdi, SHA1Checksums, src->checksum_idx)->u8, sizeof(RDI_SHA1));}break; case RDI_ChecksumKind_SHA256: {checksum = str8(rdi_element_from_name_idx(rdi, SHA256Checksums, src->checksum_idx)->u8, sizeof(RDI_SHA256));}break; case RDI_ChecksumKind_Timestamp:{checksum = str8((U8 *)rdi_element_from_name_idx(rdi, Timestamps, src->checksum_idx), sizeof(RDI_U64));}break; } // rjf: fill basics dst->path = str8_from_rdi_path_node_idx(arena, rdi, PathStyle_Relative, src->file_path_node_idx); dst->checksum_kind = src->checksum_kind; dst->checksum = checksum; src_file_from_idx_table[idx] = dst; } } lane_sync(); if(lane_idx() == 0) { for EachIndex(lidx, lane_count()) { rdim_src_file_chunk_list_concat_in_place(src_files, &lane_srcfiles[lidx]); } } } lane_sync(); //- rjf: convert units RDIM_UnitChunkList *units = 0; RDIM_LineTableChunkList *line_tables = 0; { RDIM_UnitChunkList *lane_units = 0; RDIM_LineTableChunkList *lane_linetables = 0; if(lane_idx() == 0) { lane_units = push_array(arena, RDIM_UnitChunkList, lane_count()); lane_linetables = push_array(arena, RDIM_LineTableChunkList, lane_count()); units = push_array(arena, RDIM_UnitChunkList, 1); line_tables = push_array(arena, RDIM_LineTableChunkList, 1); } lane_sync_u64(&lane_units, 0); lane_sync_u64(&lane_linetables, 0); lane_sync_u64(&units, 0); lane_sync_u64(&line_tables, 0); U64 count = 0; RDI_Unit *v = rdi_table_from_name(rdi, Units, &count); U64 unit_take_idx_ = 0; U64 *unit_take_idx_ptr = &unit_take_idx_; lane_sync_u64(&unit_take_idx_ptr, 0); for(;;) { U64 unit_idx = ins_atomic_u64_inc_eval(unit_take_idx_ptr)-1; if(unit_idx >= count) { break; } RDI_Unit *src = &v[unit_idx]; // rjf: convert flat top parts RDIM_Unit *dst = rdim_unit_chunk_list_push(arena, &lane_units[lane_idx()], 64); dst->unit_name = str8_from_rdi_string_idx(rdi, src->unit_name_string_idx); dst->compiler_name = str8_from_rdi_string_idx(rdi, src->compiler_name_string_idx); dst->source_file = str8_from_rdi_path_node_idx(arena, rdi, PathStyle_Relative, src->source_file_path_node); dst->object_file = str8_from_rdi_path_node_idx(arena, rdi, PathStyle_Relative, src->object_file_path_node); dst->archive_file = str8_from_rdi_path_node_idx(arena, rdi, PathStyle_Relative, src->archive_file_path_node); dst->build_path = str8_from_rdi_path_node_idx(arena, rdi, PathStyle_Relative, src->build_path_node); dst->language = src->language; dst->voff_ranges = unit_ranges[unit_idx]; // rjf: convert line table dst->line_table = rdim_line_table_chunk_list_push(arena, &lane_linetables[lane_idx()], 64); { RDI_LineTable *src_lt_unparsed = rdi_element_from_name_idx(rdi, LineTables, src->line_table_idx); RDI_ParsedLineTable src_lt = {0}; rdi_parsed_from_line_table(rdi, src_lt_unparsed, &src_lt); RDIM_LineTable *dst_lt = dst->line_table; { RDIM_SrcFile *seq_src_file = 0; U64 seq_start_idx = 0; for(U64 line_idx = 0; line_idx <= src_lt.count; line_idx += 1) { // rjf: get next src file RDIM_SrcFile *next_src_file = 0; if(line_idx < src_lt.count) { next_src_file = src_file_from_idx_table[src_lt.lines[line_idx].file_idx]; } // rjf: next file doesn't match current sequence? -> complete sequence if(next_src_file != seq_src_file && seq_src_file != 0) { U64 seq_line_count = (line_idx - seq_start_idx); U32 *seq_line_nums = push_array(arena, U32, seq_line_count); for(U64 line_idx_2 = seq_start_idx; line_idx_2 < line_idx; line_idx_2 += 1) { seq_line_nums[line_idx_2] = src_lt.lines[line_idx_2].line_num; } rdim_line_table_push_sequence(arena, &lane_linetables[lane_idx()], dst_lt, seq_src_file, src_lt.voffs + seq_start_idx, seq_line_nums, 0, // TODO(rjf): column support seq_line_count); } // rjf: start next sequence if(next_src_file != seq_src_file) { seq_src_file = next_src_file; seq_start_idx = line_idx; } } } } } lane_sync(); if(lane_idx() == 0) { for EachIndex(l_idx, lane_count()) { rdim_unit_chunk_list_concat_in_place(units, &lane_units[l_idx]); } for EachIndex(l_idx, lane_count()) { rdim_line_table_chunk_list_concat_in_place(line_tables, &lane_linetables[l_idx]); } } } lane_sync(); // TODO(rjf): convert types // TODO(rjf): convert udts // TODO(rjf): convert locations // TODO(rjf): convert global variables // TODO(rjf): convert thread variables // TODO(rjf): convert constants // TODO(rjf): convert procedures // TODO(rjf): convert scopes // TODO(rjf): convert inline sites // TODO(rjf): package & return RDIM_BakeParams result = bp[0]; return result; } internal RDIM_BakeResults rdim_bake(Arena *arena, RDIM_BakeParams *params) { Temp scratch = scratch_begin(&arena, 1); ////////////////////////////////////////////////////////////// //- rjf: @rdim_bake_stage form joined symbol lists, from all units // typedef struct UnitSymbolRanges UnitSymbolRanges; struct UnitSymbolRanges { U64 procedures_first_idx; U64 procedures_count; U64 global_variables_first_idx; U64 global_variables_count; U64 thread_variables_first_idx; U64 thread_variables_count; U64 constants_first_idx; U64 constants_count; }; RDIM_SymbolChunkList *all_global_variables = 0; RDIM_SymbolChunkList *all_thread_variables = 0; RDIM_SymbolChunkList *all_constants = 0; RDIM_SymbolChunkList *all_procedures = 0; RDIM_ScopeChunkList *all_scopes = 0; RDIM_InlineSiteChunkList *all_inline_sites = 0; UnitSymbolRanges *unit_symbol_ranges = 0; if(lane_idx() == 0) { all_global_variables = push_array(scratch.arena, RDIM_SymbolChunkList, 1); all_thread_variables = push_array(scratch.arena, RDIM_SymbolChunkList, 1); all_constants = push_array(scratch.arena, RDIM_SymbolChunkList, 1); all_procedures = push_array(scratch.arena, RDIM_SymbolChunkList, 1); all_scopes = push_array(scratch.arena, RDIM_ScopeChunkList, 1); all_inline_sites = push_array(scratch.arena, RDIM_InlineSiteChunkList, 1); unit_symbol_ranges = push_array(scratch.arena, UnitSymbolRanges, params->units.total_count); U64 unit_idx = 0; for EachNode(unit_n, RDIM_UnitChunkNode, params->units.first) { for EachIndex(unit_n_idx, unit_n->count) { RDIM_Unit *unit = &unit_n->v[unit_n_idx]; unit_symbol_ranges[unit_idx].procedures_first_idx = all_procedures->total_count + 1; unit_symbol_ranges[unit_idx].procedures_count = unit->procedures.total_count; unit_symbol_ranges[unit_idx].global_variables_first_idx = all_global_variables->total_count + 1; unit_symbol_ranges[unit_idx].global_variables_count = unit->global_variables.total_count; unit_symbol_ranges[unit_idx].thread_variables_first_idx = all_thread_variables->total_count + 1; unit_symbol_ranges[unit_idx].thread_variables_count = unit->thread_variables.total_count; unit_symbol_ranges[unit_idx].constants_first_idx = all_constants->total_count + 1; unit_symbol_ranges[unit_idx].constants_count = unit->constants.total_count; rdim_symbol_chunk_list_concat_in_place(all_global_variables, &unit->global_variables); rdim_symbol_chunk_list_concat_in_place(all_thread_variables, &unit->thread_variables); rdim_symbol_chunk_list_concat_in_place(all_constants, &unit->constants); rdim_symbol_chunk_list_concat_in_place(all_procedures, &unit->procedures); rdim_scope_chunk_list_concat_in_place(all_scopes, &unit->scopes); rdim_inline_site_chunk_list_concat_in_place(all_inline_sites, &unit->inline_sites); unit_idx += 1; } } } lane_sync_u64(&all_global_variables, 0); lane_sync_u64(&all_thread_variables, 0); lane_sync_u64(&all_constants, 0); lane_sync_u64(&all_procedures, 0); lane_sync_u64(&all_scopes, 0); lane_sync_u64(&all_inline_sites, 0); lane_sync_u64(&unit_symbol_ranges, 0); ////////////////////////////////////////////////////////////// //- rjf: @rdim_bake_stage bake vmaps // RDIM_BakeVMap *baked_scope_vmap = 0; RDIM_BakeVMap *baked_unit_vmap = 0; RDIM_BakeVMap *baked_global_vmap = 0; if(lane_idx() == 0) { baked_scope_vmap = push_array(scratch.arena, RDIM_BakeVMap, 1); baked_unit_vmap = push_array(scratch.arena, RDIM_BakeVMap, 1); baked_global_vmap = push_array(scratch.arena, RDIM_BakeVMap, 1); } lane_sync_u64(&baked_scope_vmap, 0); lane_sync_u64(&baked_unit_vmap, 0); lane_sync_u64(&baked_global_vmap, 0); ProfScope("bake vmaps") { Temp scratch = scratch_begin(&arena, 1); #pragma pack(push, 1) typedef struct VMapRecord VMapRecord; struct VMapRecord { union { struct { U32 negative_size; U64 voff; }; U8 digits[12]; } key; U32 idx; }; #pragma pack(pop) //////////////////////////// //- rjf: gather unsorted scope vmap records // VMapRecord *scope_vmap_records = 0; U64 scope_vmap_records_count = 0; ProfScope("gather unsorted scope vmap records") { //- rjf: calculate per-lane-chunk counts U64 *lane_chunk_range_counts = 0; if(lane_idx() == 0) { lane_chunk_range_counts = push_array(scratch.arena, U64, all_scopes->chunk_count * lane_count()); } lane_sync_u64(&lane_chunk_range_counts, 0); { U64 chunk_idx = 0; for EachNode(n, RDIM_ScopeChunkNode, all_scopes->first) { U64 slot_idx = lane_idx()*all_scopes->chunk_count + chunk_idx; Rng1U64 range = lane_range(n->count); for EachInRange(n_idx, range) { lane_chunk_range_counts[slot_idx] += n->v[n_idx].voff_ranges.count; } chunk_idx += 1; } } lane_sync(); //- rjf: calculate per-lane-chunk offsets U64 *lane_chunk_range_offs = 0; U64 total_range_count = 0; if(lane_idx() == 0) { lane_chunk_range_offs = push_array(scratch.arena, U64, all_scopes->chunk_count * lane_count()); U64 off = 0; U64 chunk_idx = 0; for EachNode(n, RDIM_ScopeChunkNode, all_scopes->first) { for EachIndex(l_idx, lane_count()) { U64 slot_idx = l_idx*all_scopes->chunk_count + chunk_idx; lane_chunk_range_offs[slot_idx] = off; off += lane_chunk_range_counts[slot_idx]; } chunk_idx += 1; } total_range_count = off; } lane_sync_u64(&lane_chunk_range_offs, 0); lane_sync_u64(&total_range_count, 0); //- rjf: allocate records if(lane_idx() == 0) { scope_vmap_records_count = total_range_count; scope_vmap_records = push_array_no_zero(scratch.arena, VMapRecord, scope_vmap_records_count); } lane_sync_u64(&scope_vmap_records, 0); lane_sync_u64(&scope_vmap_records_count, 0); //- rjf: fill records { U64 chunk_idx = 0; for EachNode(n, RDIM_ScopeChunkNode, all_scopes->first) { U64 slot_idx = lane_idx()*all_scopes->chunk_count + chunk_idx; U64 off = lane_chunk_range_offs[slot_idx]; Rng1U64 range = lane_range(n->count); for EachInRange(n_idx, range) { RDI_U32 scope_idx = (RDI_U32)rdim_idx_from_scope(&n->v[n_idx]); // TODO(rjf): @u64_to_u32 for EachNode(rng_n, RDIM_Rng1U64Node, n->v[n_idx].voff_ranges.first) { scope_vmap_records[off].key.voff = rng_n->v.min; scope_vmap_records[off].key.negative_size = -(RDI_U32)(rng_n->v.max - rng_n->v.min); scope_vmap_records[off].idx = scope_idx; off += 1; } } chunk_idx += 1; } } } lane_sync(); //////////////////////////// //- rjf: gather unsorted global vmap records // VMapRecord *global_vmap_records = 0; U64 global_vmap_records_count = 0; ProfScope("gather unsorted global vmap records") { //- rjf: calculate per-lane-chunk counts U64 *lane_chunk_range_counts = 0; if(lane_idx() == 0) { lane_chunk_range_counts = push_array(scratch.arena, U64, all_global_variables->chunk_count * lane_count()); } lane_sync_u64(&lane_chunk_range_counts, 0); { U64 chunk_idx = 0; for EachNode(n, RDIM_SymbolChunkNode, all_global_variables->first) { U64 slot_idx = lane_idx()*all_global_variables->chunk_count + chunk_idx; Rng1U64 range = lane_range(n->count); for EachInRange(n_idx, range) { if(n->v[n_idx].location_cases.count == 1 && n->v[n_idx].location_cases.first->location.kind == RDI_LocationKind_ModuleOff) { lane_chunk_range_counts[slot_idx] += 1; } } chunk_idx += 1; } } lane_sync(); //- rjf: calculate per-lane-chunk offsets U64 *lane_chunk_range_offs = 0; U64 total_range_count = 0; if(lane_idx() == 0) { lane_chunk_range_offs = push_array(scratch.arena, U64, all_global_variables->chunk_count * lane_count()); U64 off = 0; U64 chunk_idx = 0; for EachNode(n, RDIM_SymbolChunkNode, all_global_variables->first) { for EachIndex(l_idx, lane_count()) { U64 slot_idx = l_idx*all_global_variables->chunk_count + chunk_idx; lane_chunk_range_offs[slot_idx] = off; off += lane_chunk_range_counts[slot_idx]; } chunk_idx += 1; } total_range_count = off; } lane_sync_u64(&lane_chunk_range_offs, 0); lane_sync_u64(&total_range_count, 0); //- rjf: allocate records if(lane_idx() == 0) { global_vmap_records_count = total_range_count; global_vmap_records = push_array_no_zero(scratch.arena, VMapRecord, global_vmap_records_count); } lane_sync_u64(&global_vmap_records, 0); lane_sync_u64(&global_vmap_records_count, 0); //- rjf: fill records { U64 chunk_idx = 0; for EachNode(n, RDIM_SymbolChunkNode, all_global_variables->first) { U64 slot_idx = lane_idx()*all_global_variables->chunk_count + chunk_idx; U64 off = lane_chunk_range_offs[slot_idx]; Rng1U64 range = lane_range(n->count); for EachInRange(n_idx, range) { if(n->v[n_idx].location_cases.count == 1 && n->v[n_idx].location_cases.first->location.kind == RDI_LocationKind_ModuleOff) { RDI_U32 global_idx = (RDI_U32)rdim_idx_from_symbol(&n->v[n_idx]); // TODO(rjf): @u64_to_u32 RDI_U32 global_size = (RDI_U32)(n->v[n_idx].type ? n->v[n_idx].type->byte_size : 1); RDI_U64 global_voff = n->v[n_idx].location_cases.first->location.offset; global_vmap_records[off].key.voff = global_voff; global_vmap_records[off].key.negative_size = -global_size; global_vmap_records[off].idx = global_idx; off += 1; } } chunk_idx += 1; } } } lane_sync(); //////////////////////////// //- rjf: gather unsorted unit vmap records // VMapRecord *unit_vmap_records = 0; U64 unit_vmap_records_count = 0; ProfScope("gather unsorted unit vmap records") { //- rjf: calculate per-lane-chunk counts U64 *lane_chunk_range_counts = 0; if(lane_idx() == 0) { lane_chunk_range_counts = push_array(scratch.arena, U64, params->units.chunk_count * lane_count()); } lane_sync_u64(&lane_chunk_range_counts, 0); { U64 chunk_idx = 0; for EachNode(n, RDIM_UnitChunkNode, params->units.first) { U64 slot_idx = lane_idx()*params->units.chunk_count + chunk_idx; Rng1U64 range = lane_range(n->count); for EachInRange(n_idx, range) { lane_chunk_range_counts[slot_idx] += n->v[n_idx].voff_ranges.total_count; } chunk_idx += 1; } } lane_sync(); //- rjf: calculate per-lane-chunk offsets U64 *lane_chunk_range_offs = 0; U64 total_range_count = 0; if(lane_idx() == 0) { lane_chunk_range_offs = push_array(scratch.arena, U64, params->units.chunk_count * lane_count()); U64 off = 0; U64 chunk_idx = 0; for EachNode(n, RDIM_UnitChunkNode, params->units.first) { for EachIndex(l_idx, lane_count()) { U64 slot_idx = l_idx*params->units.chunk_count + chunk_idx; lane_chunk_range_offs[slot_idx] = off; off += lane_chunk_range_counts[slot_idx]; } chunk_idx += 1; } total_range_count = off; } lane_sync_u64(&lane_chunk_range_offs, 0); lane_sync_u64(&total_range_count, 0); //- rjf: allocate records if(lane_idx() == 0) { unit_vmap_records_count = total_range_count; unit_vmap_records = push_array_no_zero(scratch.arena, VMapRecord, unit_vmap_records_count); } lane_sync_u64(&unit_vmap_records, 0); lane_sync_u64(&unit_vmap_records_count, 0); //- rjf: fill records { U64 chunk_idx = 0; for EachNode(n, RDIM_UnitChunkNode, params->units.first) { U64 slot_idx = lane_idx()*params->units.chunk_count + chunk_idx; U64 off = lane_chunk_range_offs[slot_idx]; Rng1U64 range = lane_range(n->count); for EachInRange(n_idx, range) { RDI_U32 unit_idx = (RDI_U32)rdim_idx_from_unit(&n->v[n_idx]); // TODO(rjf): @u64_to_u32 for EachNode(rng_n, RDIM_Rng1U64ChunkNode, n->v[n_idx].voff_ranges.first) { for EachIndex(rng_n_idx, rng_n->count) { unit_vmap_records[off].key.voff = rng_n->v[rng_n_idx].min; unit_vmap_records[off].key.negative_size = -(RDI_U32)(rng_n->v[rng_n_idx].max - rng_n->v[rng_n_idx].min); unit_vmap_records[off].idx = unit_idx; off += 1; } } } chunk_idx += 1; } } } lane_sync(); //////////////////////////// //- rjf: sort & bake all vmaps // struct { String8 name; VMapRecord *records; U64 records_count; RDI_VMapEntry **vmap_out; U32 *vmap_count_out; } vmap_tasks[] = { {str8_lit_comp("scopes"), scope_vmap_records, scope_vmap_records_count, &baked_scope_vmap->vmap, &baked_scope_vmap->count}, {str8_lit_comp("globals"), global_vmap_records, global_vmap_records_count, &baked_global_vmap->vmap, &baked_global_vmap->count}, {str8_lit_comp("units"), unit_vmap_records, unit_vmap_records_count, &baked_unit_vmap->vmap, &baked_unit_vmap->count}, }; ProfScope("sort & bake all vmaps") { for EachElement(vmap_task_idx, vmap_tasks) ProfScope("sort & bake vmap for %.*s", str8_varg(vmap_tasks[vmap_task_idx].name)) { VMapRecord *records = vmap_tasks[vmap_task_idx].records; U64 records_count = vmap_tasks[vmap_task_idx].records_count; //////////////////////// //- rjf: sort // ProfScope("sort") { //- rjf: set up constants U64 bytes_per_digit = 1; U64 num_possible_values_per_digit = 1<<(bytes_per_digit*8); U64 digits_count = sizeof(((VMapRecord *)0)->key)/bytes_per_digit; //- rjf: set up swap buffer / lane counters VMapRecord *records__swap = 0; U32 **lane_digit_counts = 0; U32 **lane_digit_offs = 0; if(lane_idx() == 0) { records__swap = push_array_no_zero(scratch.arena, VMapRecord, records_count); lane_digit_counts = push_array_no_zero(scratch.arena, U32 *, lane_count()); lane_digit_offs = push_array_no_zero(scratch.arena, U32 *, lane_count()); } lane_sync_u64(&records__swap, 0); lane_sync_u64(&lane_digit_counts, 0); lane_sync_u64(&lane_digit_offs, 0); lane_digit_counts[lane_idx()] = push_array_no_zero(scratch.arena, U32, num_possible_values_per_digit); lane_digit_offs[lane_idx()] = push_array_no_zero(scratch.arena, U32, num_possible_values_per_digit); //- rjf: do all sort passes { VMapRecord *src = records; VMapRecord *dst = records__swap; for EachIndex(digit_idx, digits_count) { // rjf: count digit value occurrences per-lane { U32 *digit_counts = lane_digit_counts[lane_idx()]; MemoryZero(digit_counts, sizeof(digit_counts[0])*num_possible_values_per_digit); Rng1U64 range = lane_range(records_count); for EachInRange(idx, range) { VMapRecord *rec = &src[idx]; U16 digit_value = (U16)rec->key.digits[digit_idx]; digit_counts[digit_value] += 1; } } lane_sync(); // rjf: compute thread * digit value *relative* offset table { Rng1U64 range = lane_range(num_possible_values_per_digit); for EachInRange(value_idx, range) { U64 layout_off = 0; for EachIndex(lane_idx, lane_count()) { lane_digit_offs[lane_idx][value_idx] = layout_off; layout_off += lane_digit_counts[lane_idx][value_idx]; } } } lane_sync(); // rjf: convert relative offsets -> absolute offsets if(lane_idx() == 0) { U64 last_off = 0; U64 num_of_nonzero_digit = 0; for EachIndex(value_idx, num_possible_values_per_digit) { for EachIndex(lane_idx, lane_count()) { lane_digit_offs[lane_idx][value_idx] += last_off; } last_off = lane_digit_offs[lane_count()-1][value_idx] + lane_digit_counts[lane_count()-1][value_idx]; } // NOTE(rjf): required that: (last_off == element_count) } lane_sync(); // rjf: move { U32 *lane_digit_offsets = lane_digit_offs[lane_idx()]; Rng1U64 range = lane_range(records_count); for EachInRange(idx, range) { VMapRecord *src_rec = &src[idx]; U16 digit_value = (U16)src_rec->key.digits[digit_idx]; U64 dst_off = lane_digit_offsets[digit_value]; lane_digit_offsets[digit_value] += 1; MemoryCopyStruct(&dst[dst_off], src_rec); } } lane_sync(); // rjf: swap source with destination for next pass Swap(VMapRecord *, src, dst); } } } lane_sync(); //////////////////////// //- rjf: bake // RDI_VMapEntry *vmap = 0; RDI_U64 vmap_count = 0; { //- rjf: allocate vmap RDI_U64 vmap_count__cap = records_count*2 + 1; if(lane_idx() == 0) { vmap = push_array(arena, RDI_VMapEntry, vmap_count__cap); } lane_sync_u64(&vmap, 0); //- rjf: bake if(lane_idx() == 0) { typedef struct RangeNode RangeNode; struct RangeNode { RangeNode *next; Rng1U64 voff_range; U64 idx; }; RDI_VMapEntry *vmap_ptr = vmap; RDI_VMapEntry *vmap_opl = vmap + vmap_count__cap; RangeNode *top_range = 0; RangeNode *free_range = 0; U64 last_recorded_voff = 0; for(U64 record_idx = 0; record_idx <= records_count; record_idx += 1) { // rjf: get next voff range and index Rng1U64 voff_range = r1u64(max_U64, max_U64); U64 idx = 0; if(record_idx < records_count) { VMapRecord *record = &records[record_idx]; voff_range = r1u64(record->key.voff, record->key.voff + -record->key.negative_size); idx = (U64)record->idx; } // rjf: pop nodes we've advanced past { for(RangeNode *n = top_range, *next = 0; n != 0; n = next) { next = n->next; if(n->voff_range.max <= voff_range.min) { SLLStackPop(top_range); SLLStackPush(free_range, n); if(n->voff_range.max != last_recorded_voff) { vmap_ptr += 1; } vmap_ptr->voff = n->voff_range.max; vmap_ptr->idx = next ? next->idx : 0; last_recorded_voff = vmap_ptr->voff; } else { break; } } } // rjf: push this node if(record_idx < records_count) { RangeNode *r = free_range; if(r) { SLLStackPop(free_range); } else { r = push_array(scratch.arena, RangeNode, 1); } SLLStackPush(top_range, r); r->voff_range = voff_range; r->idx = idx; if(voff_range.min != last_recorded_voff) { vmap_ptr += 1; } vmap_ptr->voff = voff_range.min; vmap_ptr->idx = idx; last_recorded_voff = voff_range.min; } } if(last_recorded_voff != 0) { vmap_ptr += 1; } vmap_count = (vmap_ptr - vmap); } lane_sync_u64(&vmap_count, 0); } lane_sync(); //////////////////////// //- rjf: store // if(lane_idx() == 0) { vmap_tasks[vmap_task_idx].vmap_out[0] = vmap; vmap_tasks[vmap_task_idx].vmap_count_out[0] = vmap_count; } } } lane_sync(); scratch_end(scratch); } lane_sync(); ////////////////////////////////////////////////////////////// //- rjf: @rdim_bake_stage build interned path tree // RDIM_BakePathTree *path_tree = 0; if(lane_idx() == 0) ProfScope("build interned path tree") { //- rjf: set up tree path_tree = rdim_push_array(arena, RDIM_BakePathTree, 1); rdim_bake_path_tree_insert(arena, path_tree, rdim_str8_lit("")); //- rjf: bake unit file paths RDIM_ProfScope("bake unit file paths") { for(RDIM_UnitChunkNode *n = params->units.first; n != 0; n = n->next) { for(RDI_U64 idx = 0; idx < n->count; idx += 1) { rdim_bake_path_tree_insert(arena, path_tree, n->v[idx].source_file); rdim_bake_path_tree_insert(arena, path_tree, n->v[idx].object_file); rdim_bake_path_tree_insert(arena, path_tree, n->v[idx].archive_file); rdim_bake_path_tree_insert(arena, path_tree, n->v[idx].build_path); } } } //- rjf: bake source file paths RDIM_ProfScope("bake source file paths") { for(RDIM_SrcFileChunkNode *n = params->src_files.first; n != 0; n = n->next) { for(RDI_U64 idx = 0; idx < n->count; idx += 1) { RDIM_BakePathNode *node = rdim_bake_path_tree_insert(arena, path_tree, n->v[idx].path); node->src_file = &n->v[idx]; } } } } lane_sync_u64(&path_tree, 0); ////////////////////////////////////////////////////////////// //- rjf: @rdim_bake_stage gather all unsorted, joined, line table info; & sort // typedef struct BakedLineTables BakedLineTables; struct BakedLineTables { RDI_LineTable *line_tables; RDI_U64 line_tables_count; RDI_U64 *line_table_voffs; RDI_U64 line_table_voffs_count; RDI_Line *line_table_lines; RDI_U64 line_table_lines_count; RDI_Column *line_table_columns; RDI_U64 line_table_columns_count; }; U64 line_tables_count = 0; RDIM_LineTable **src_line_tables = 0; RDIM_UnsortedJoinedLineTable *unsorted_joined_line_tables = 0; RDIM_SortKey **sorted_line_table_keys = 0; BakedLineTables *baked_line_tables = 0; ProfScope("gather all unsorted, joined, line table info; & sort") { //- rjf: set up outputs ProfScope("set up outputs") { // rjf: calculate header info if(lane_idx() == 0) { line_tables_count = params->line_tables.total_count; src_line_tables = push_array(arena, RDIM_LineTable *, line_tables_count); ProfScope("flatten chunk list") { U64 joined_idx = 0; for(RDIM_LineTableChunkNode *n = params->line_tables.first; n != 0; n = n->next) { for EachIndex(idx, n->count) { src_line_tables[joined_idx] = &n->v[idx]; joined_idx += 1; } } } baked_line_tables = push_array(scratch.arena, BakedLineTables, 1); baked_line_tables->line_tables_count = params->line_tables.total_count + 1; baked_line_tables->line_table_voffs_count = params->line_tables.total_line_count + 2*params->line_tables.total_seq_count; baked_line_tables->line_table_lines_count = params->line_tables.total_line_count + params->line_tables.total_seq_count; baked_line_tables->line_table_columns_count= 1; } lane_sync_u64(&line_tables_count, 0); lane_sync_u64(&src_line_tables, 0); lane_sync_u64(&baked_line_tables, 0); // rjf: allocate outputs ProfScope("allocate outputs") { if(lane_idx() == lane_from_task_idx(0)) { unsorted_joined_line_tables = push_array(arena, RDIM_UnsortedJoinedLineTable, line_tables_count); } if(lane_idx() == lane_from_task_idx(1)) { sorted_line_table_keys = push_array(arena, RDIM_SortKey *, line_tables_count); } if(lane_idx() == lane_from_task_idx(2)) { baked_line_tables->line_tables = push_array(arena, RDI_LineTable, baked_line_tables->line_tables_count); ProfScope("lay out line tables") { U64 voffs_base_idx = 0; U64 lines_base_idx = 0; U64 cols_base_idx = 0; for EachIndex(idx, line_tables_count) { U64 final_idx = idx+1; // NOTE(rjf): +1, to reserve [0] for nil RDIM_LineTable *src = src_line_tables[idx]; RDI_LineTable *dst = &baked_line_tables->line_tables[final_idx]; dst->voffs_base_idx = voffs_base_idx; // TODO(rjf): @u64_to_u32 dst->lines_base_idx = lines_base_idx; // TODO(rjf): @u64_to_u32 dst->cols_base_idx = cols_base_idx; // TODO(rjf): @u64_to_u32 dst->lines_count = src->line_count + src->seq_count; // TODO(rjf): @u64_to_u32 voffs_base_idx += src->line_count + 2*src->seq_count; lines_base_idx += src->line_count + 1*src->seq_count; } } } if(lane_idx() == lane_from_task_idx(3)) { baked_line_tables->line_table_voffs = push_array(arena, RDI_U64, baked_line_tables->line_table_voffs_count); } if(lane_idx() == lane_from_task_idx(4)) { baked_line_tables->line_table_lines = push_array(arena, RDI_Line, baked_line_tables->line_table_lines_count); } if(lane_idx() == lane_from_task_idx(5)) { baked_line_tables->line_table_columns = push_array(arena, RDI_Column, baked_line_tables->line_table_columns_count); } } } lane_sync_u64(&unsorted_joined_line_tables, lane_from_task_idx(0)); lane_sync_u64(&sorted_line_table_keys, lane_from_task_idx(1)); //- rjf: wide bake ProfScope("wide bake") { U64 *line_table_block_take_counter = push_array(scratch.arena, U64, 1); lane_sync_u64(&line_table_block_take_counter, 0); U64 line_table_block_size = 4096; U64 line_table_block_count = (line_tables_count + line_table_block_size - 1) / line_table_block_size; for(;;) { U64 line_table_block_num = ins_atomic_u64_inc_eval(line_table_block_take_counter); if(0 == line_table_block_num || line_table_block_count < line_table_block_num) { break; } U64 line_table_block_idx = line_table_block_num-1; Rng1U64 line_table_range = r1u64(line_table_block_idx*line_table_block_size, (line_table_block_idx+1)*line_table_block_size); line_table_range.max = Min(line_tables_count, line_table_range.max); for EachInRange(line_table_idx, line_table_range) { RDIM_LineTable *src = src_line_tables[line_table_idx]; RDIM_UnsortedJoinedLineTable *dst = &unsorted_joined_line_tables[line_table_idx]; //- rjf: gather dst->line_count = src->line_count; dst->seq_count = src->seq_count; dst->key_count = dst->line_count + dst->seq_count; dst->line_keys = rdim_push_array_no_zero(arena, RDIM_SortKey, dst->key_count); dst->line_recs = rdim_push_array_no_zero(arena, RDIM_LineRec, dst->line_count); { RDIM_SortKey *key_ptr = dst->line_keys; RDIM_LineRec *rec_ptr = dst->line_recs; for(RDIM_LineSequenceNode *seq_n = src->first_seq; seq_n != 0; seq_n = seq_n->next) { RDIM_LineSequence *seq = &seq_n->v; for(RDI_U64 line_idx = 0; line_idx < seq->line_count; line_idx += 1) { key_ptr->key = seq->voffs[line_idx]; key_ptr->val = rec_ptr; key_ptr += 1; rec_ptr->file_id = (RDI_U32)rdim_idx_from_src_file(seq->src_file); // TODO(rjf): @u64_to_u32 rec_ptr->line_num = seq->line_nums[line_idx]; if(seq->col_nums != 0) { rec_ptr->col_first = seq->col_nums[line_idx*2]; rec_ptr->col_opl = seq->col_nums[line_idx*2 + 1]; } rec_ptr += 1; } key_ptr->key = seq->voffs[seq->line_count]; key_ptr->val = 0; key_ptr += 1; } } //- rjf: sort sorted_line_table_keys[line_table_idx] = rdim_sort_key_array(arena, unsorted_joined_line_tables[line_table_idx].line_keys, unsorted_joined_line_tables[line_table_idx].key_count); //- rjf: fill RDIM_SortKey *sorted_line_keys = sorted_line_table_keys[line_table_idx]; U64 sorted_line_keys_count = unsorted_joined_line_tables[line_table_idx].key_count; RDI_LineTable *dst_line_table = &baked_line_tables->line_tables[line_table_idx+1]; U64 *arranged_voffs = baked_line_tables->line_table_voffs + dst_line_table->voffs_base_idx; RDI_Line *arranged_lines = baked_line_tables->line_table_lines + dst_line_table->lines_base_idx; RDI_Column *arranged_cols = baked_line_tables->line_table_columns + dst_line_table->cols_base_idx; if(sorted_line_keys_count > 0) { for EachIndex(idx, sorted_line_keys_count) { arranged_voffs[idx] = sorted_line_keys[idx].key; } arranged_voffs[sorted_line_keys_count] = ~0ull; for EachIndex(idx, sorted_line_keys_count) { RDIM_LineRec *rec = (RDIM_LineRec*)sorted_line_keys[idx].val; if(rec != 0) { arranged_lines[idx].file_idx = rec->file_id; arranged_lines[idx].line_num = rec->line_num; } else { arranged_lines[idx].file_idx = 0; arranged_lines[idx].line_num = 0; } } } } } } } lane_sync(); ////////////////////////////////////////////////////////////// //- rjf: @rdim_bake_stage build string map // RDIM_BakeStringMapTight *bake_strings = 0; ProfScope("build string map") { Temp scratch2 = scratch_begin(&scratch.arena, 1); //- rjf: set up per-lane outputs RDIM_BakeStringMapTopology *top = 0; RDIM_BakeStringMapLoose **lane_maps__loose = 0; RDIM_BakeStringMapLoose *map__loose = 0; if(lane_idx() == 0) ProfScope("set up per-lane outputs") { bake_strings = push_array(scratch.arena, RDIM_BakeStringMapTight, 1); top = push_array(scratch2.arena, RDIM_BakeStringMapTopology, 1); top->slots_count = (64 + all_procedures->total_count*1 + all_global_variables->total_count*1 + all_thread_variables->total_count*1 + params->types.total_count/2); lane_maps__loose = push_array(scratch2.arena, RDIM_BakeStringMapLoose *, lane_count()); map__loose = rdim_bake_string_map_loose_make(scratch2.arena, top); } lane_sync_u64(&bake_strings, 0); lane_sync_u64(&top, 0); lane_sync_u64(&lane_maps__loose, 0); lane_sync_u64(&map__loose, 0); //- rjf: set up this lane's map ProfScope("set up this lane's map") { lane_maps__loose[lane_idx()] = rdim_bake_string_map_loose_make(scratch2.arena, top); } RDIM_BakeStringMapLoose *lane_map = lane_maps__loose[lane_idx()]; //- rjf: push all strings into this lane's map ProfScope("push all strings into this lane's map") { // rjf: push small top-level strings if(lane_idx() == 0) ProfScope("push small top-level strings") { rdim_bake_string_map_loose_insert(arena, top, lane_map, 1, params->top_level_info.exe_name); rdim_bake_string_map_loose_insert(arena, top, lane_map, 1, params->top_level_info.producer_name); for(RDIM_BinarySectionNode *n = params->binary_sections.first; n != 0; n = n->next) { rdim_bake_string_map_loose_insert(arena, top, lane_map, 1, n->v.name); } for(RDIM_BakePathNode *n = path_tree->first; n != 0; n = n->next_order) { rdim_bake_string_map_loose_insert(arena, top, lane_map, 1, n->name); } } // rjf: push strings from source files ProfScope("src files") { for EachNode(n, RDIM_SrcFileChunkNode, params->src_files.first) { Rng1U64 range = lane_range(n->count); for EachInRange(n_idx, range) { RDIM_String8 normalized_path = rdim_normalize_path_str8(arena, n->v[n_idx].path); rdim_bake_string_map_loose_insert(arena, top, lane_map, 1, normalized_path); } } } // rjf: push strings from units ProfScope("units") { for EachNode(n, RDIM_UnitChunkNode, params->units.first) { Rng1U64 range = lane_range(n->count); for EachInRange(n_idx, range) { rdim_bake_string_map_loose_insert(arena, top, lane_map, 4, n->v[n_idx].unit_name); rdim_bake_string_map_loose_insert(arena, top, lane_map, 4, n->v[n_idx].compiler_name); rdim_bake_string_map_loose_insert(arena, top, lane_map, 4, n->v[n_idx].source_file); rdim_bake_string_map_loose_insert(arena, top, lane_map, 4, n->v[n_idx].object_file); rdim_bake_string_map_loose_insert(arena, top, lane_map, 4, n->v[n_idx].archive_file); rdim_bake_string_map_loose_insert(arena, top, lane_map, 4, n->v[n_idx].build_path); } } } // rjf: push strings from namespaces ProfScope("namespaces") { for EachNode(n, RDIM_NamespaceChunkNode, params->namespaces.first) { Rng1U64 range = lane_range(n->count); for EachInRange(n_idx, range) { rdim_bake_string_map_loose_insert(arena, top, lane_map, 4, n->v[n_idx].name); } } } // rjf: push strings from types ProfScope("types") { for EachNode(n, RDIM_TypeChunkNode, params->types.first) { Rng1U64 range = lane_range(n->count); for EachInRange(n_idx, range) { rdim_bake_string_map_loose_insert(arena, top, lane_map, 4, n->v[n_idx].name); } } } // rjf: push strings from udts ProfScope("udts") { for EachNode(n, RDIM_UDTChunkNode, params->udts.first) { Rng1U64 range = lane_range(n->count); for EachInRange(idx, range) { for EachNode(mem, RDIM_UDTMember, n->v[idx].first_member) { rdim_bake_string_map_loose_insert(arena, top, lane_map, 4, mem->name); } for EachNode(enum_val, RDIM_UDTEnumVal, n->v[idx].first_enum_val) { rdim_bake_string_map_loose_insert(arena, top, lane_map, 4, enum_val->name); } } } } // rjf: push strings from symbols RDIM_SymbolChunkList *symbol_lists[] = { all_global_variables, all_thread_variables, all_procedures, all_constants, }; ProfScope("symbols") { for EachElement(list_idx, symbol_lists) { for EachNode(n, RDIM_SymbolChunkNode, symbol_lists[list_idx]->first) { Rng1U64 range = lane_range(n->count); for EachInRange(n_idx, range) { rdim_bake_string_map_loose_insert(arena, top, lane_map, 4, n->v[n_idx].name); rdim_bake_string_map_loose_insert(arena, top, lane_map, 4, n->v[n_idx].link_name); } } } } //- rjf: push strings from inline sites ProfScope("inline sites") { for EachNode(n, RDIM_InlineSiteChunkNode, all_inline_sites->first) { Rng1U64 range = lane_range(n->count); for EachInRange(n_idx, range) { rdim_bake_string_map_loose_insert(arena, top, lane_map, 4, n->v[n_idx].name); } } } //- rjf: push strings from scopes ProfScope("scopes") { for EachNode(n, RDIM_ScopeChunkNode, all_scopes->first) { Rng1U64 range = lane_range(n->count); for EachInRange(n_idx, range) { for EachNode(local_n, RDIM_SymbolChunkNode, n->v[n_idx].locals.first) { for EachIndex(local_n_idx, local_n->count) { rdim_bake_string_map_loose_insert(arena, top, lane_map, 4, local_n->v[local_n_idx].name); } } } } } } lane_sync(); //- rjf: join ProfScope("join") { Rng1U64 slot_range = lane_range(top->slots_count); for EachInRange(slot_idx, slot_range) { for EachIndex(src_lane_idx, lane_count()) { RDIM_BakeStringMapLoose *src_map = lane_maps__loose[src_lane_idx]; RDIM_BakeStringMapLoose *dst_map = map__loose; if(dst_map->slots[slot_idx] == 0 && src_map->slots[slot_idx] != 0) { dst_map->slots[slot_idx] = src_map->slots[slot_idx]; } else if(dst_map->slots[slot_idx] != 0 && src_map->slots[slot_idx] != 0) { rdim_bake_string_chunk_list_concat_in_place(dst_map->slots[slot_idx], src_map->slots[slot_idx]); } } } } lane_sync(); //- rjf: sort ProfScope("sort") { RDIM_BakeStringMapLoose *map = map__loose; Rng1U64 slot_range = lane_range(top->slots_count); for EachInRange(slot_idx, slot_range) { if(map->slots[slot_idx] != 0) { *map->slots[slot_idx] = rdim_bake_string_chunk_list_sorted_from_unsorted(arena, map->slots[slot_idx]); } } } lane_sync(); //- rjf: tighten string table ProfScope("tighten string table") { RDIM_BakeStringMapLoose *map = map__loose; if(lane_idx() == 0) ProfScope("calc base indices, set up tight map") { RDIM_BakeStringMapBaseIndices bake_string_map_base_indices = rdim_bake_string_map_base_indices_from_map_loose(arena, top, map); bake_strings->slots_count = top->slots_count; bake_strings->slots = rdim_push_array(arena, RDIM_BakeStringChunkList, bake_strings->slots_count); bake_strings->slots_base_idxs = bake_string_map_base_indices.slots_base_idxs; bake_strings->total_count = bake_strings->slots_base_idxs[bake_strings->slots_count]; } lane_sync(); ProfScope("fill tight map") { Rng1U64 slot_range = lane_range(bake_strings->slots_count); for EachInRange(idx, slot_range) { if(map->slots[idx] != 0) { rdim_memcpy_struct(&bake_strings->slots[idx], map->slots[idx]); } } } } lane_sync(); scratch_end(scratch2); } ////////////////////////////////////////////////////////////// //- rjf: @rdim_bake_stage build name maps // B32 name_maps_need_build[RDI_NameMapKind_COUNT] = {0}; { name_maps_need_build[RDI_NameMapKind_GlobalVariables] = !!(params->subset_flags & RDIM_SubsetFlag_GlobalVariableNameMap); name_maps_need_build[RDI_NameMapKind_ThreadVariables] = !!(params->subset_flags & RDIM_SubsetFlag_ThreadVariableNameMap); name_maps_need_build[RDI_NameMapKind_Constants] = !!(params->subset_flags & RDIM_SubsetFlag_ConstantNameMap); name_maps_need_build[RDI_NameMapKind_Procedures] = !!(params->subset_flags & RDIM_SubsetFlag_ProcedureNameMap); name_maps_need_build[RDI_NameMapKind_Types] = !!(params->subset_flags & RDIM_SubsetFlag_TypeNameMap); name_maps_need_build[RDI_NameMapKind_LinkNameProcedures] = !!(params->subset_flags & RDIM_SubsetFlag_LinkNameProcedureNameMap); name_maps_need_build[RDI_NameMapKind_NormalSourcePaths] = !!(params->subset_flags & RDIM_SubsetFlag_NormalSourcePathNameMap); } RDIM_BakeNameMapTopology *bake_name_maps_tops = 0; RDIM_BakeNameMap **bake_name_maps = 0; ProfScope("build name maps") { Temp scratch = scratch_begin(&arena, 1); //- rjf: set up RDIM_BakeNameMap ***lane_maps = 0; if(lane_idx() == 0) { bake_name_maps_tops = push_array(arena, RDIM_BakeNameMapTopology, RDI_NameMapKind_COUNT); bake_name_maps = push_array(arena, RDIM_BakeNameMap *, RDI_NameMapKind_COUNT); lane_maps = push_array(scratch.arena, RDIM_BakeNameMap **, RDI_NameMapKind_COUNT); for EachNonZeroEnumVal(RDI_NameMapKind, k) { U64 slot_count = 0; switch((RDI_NameMapKindEnum)k) { case RDI_NameMapKind_NULL: case RDI_NameMapKind_COUNT: {}break; #define Case(name, total_count) case RDI_NameMapKind_##name:{slot_count = ((total_count) + (total_count)/4);}break Case(GlobalVariables, all_global_variables->total_count); Case(ThreadVariables, all_thread_variables->total_count); Case(Constants, all_constants->total_count); Case(Procedures, all_procedures->total_count); Case(LinkNameProcedures, all_procedures->total_count); Case(Types, params->types.total_count); Case(NormalSourcePaths, params->src_files.total_count); #undef Case } lane_maps[k] = push_array(arena, RDIM_BakeNameMap *, lane_count()); bake_name_maps_tops[k].slots_count = slot_count; } } lane_sync_u64(&bake_name_maps_tops, 0); lane_sync_u64(&bake_name_maps, 0); lane_sync_u64(&lane_maps, 0); //- rjf: wide build for EachNonZeroEnumVal(RDI_NameMapKind, k) ProfScope("name map build %.*s", str8_varg(rdi_string_from_name_map_kind(k))) { if(!name_maps_need_build[k]) { continue; } RDIM_BakeNameMapTopology *top = &bake_name_maps_tops[k]; lane_maps[k][lane_idx()] = rdim_bake_name_map_make(scratch.arena, top); RDIM_BakeNameMap *map = lane_maps[k][lane_idx()]; B32 link_names = 0; RDIM_SymbolChunkList *symbols = 0; switch((RDI_NameMapKindEnum)k) { case RDI_NameMapKind_NULL: case RDI_NameMapKind_COUNT: {}break; case RDI_NameMapKind_GlobalVariables: {symbols = all_global_variables;}goto symbol_name_map_build; case RDI_NameMapKind_ThreadVariables: {symbols = all_thread_variables;}goto symbol_name_map_build; case RDI_NameMapKind_Constants: {symbols = all_constants;}goto symbol_name_map_build; case RDI_NameMapKind_Procedures: {symbols = all_procedures;}goto symbol_name_map_build; case RDI_NameMapKind_LinkNameProcedures:{symbols = all_procedures; link_names = 1;}goto symbol_name_map_build; symbol_name_map_build:; { for EachNode(n, RDIM_SymbolChunkNode, symbols->first) { Rng1U64 n_range = lane_range(n->count); for EachInRange(n_idx, n_range) { RDIM_Symbol *symbol = &n->v[n_idx]; rdim_bake_name_map_insert(scratch.arena, top, map, 4, link_names ? symbol->link_name : symbol->name, rdim_idx_from_symbol(symbol)); } } }break; case RDI_NameMapKind_Types: { RDIM_TypeChunkList *types = ¶ms->types; for EachNode(n, RDIM_TypeChunkNode, types->first) { Rng1U64 n_range = lane_range(n->count); for EachInRange(n_idx, n_range) { RDIM_Type *type = &n->v[n_idx]; rdim_bake_name_map_insert(scratch.arena, top, map, 4, type->name, rdim_idx_from_type(type)); } } }break; case RDI_NameMapKind_NormalSourcePaths: { RDIM_SrcFileChunkList *src_files = ¶ms->src_files; for EachNode(n, RDIM_SrcFileChunkNode, src_files->first) { Rng1U64 n_range = lane_range(n->count); for EachInRange(n_idx, n_range) { RDIM_SrcFile *src_file = &n->v[n_idx]; RDIM_String8 normalized_path = rdim_normalize_path_str8(arena, src_file->path); rdim_bake_name_map_insert(scratch.arena, top, map, 4, normalized_path, rdim_idx_from_src_file(src_file)); } } }break; } } lane_sync(); //- rjf: join & sort if(lane_idx() == 0) { for EachNonZeroEnumVal(RDI_NameMapKind, k) { if(!name_maps_need_build[k]) { continue; } bake_name_maps[k] = rdim_bake_name_map_make(arena, &bake_name_maps_tops[k]); } } lane_sync(); for EachNonZeroEnumVal(RDI_NameMapKind, k) ProfScope("name map join & sort %.*s", str8_varg(rdi_string_from_name_map_kind(k))) { if(!name_maps_need_build[k]) { continue; } RDIM_BakeNameMapTopology *top = &bake_name_maps_tops[k]; RDIM_BakeNameMap *map = bake_name_maps[k]; //- rjf: join ProfScope("join") { Rng1U64 slot_range = lane_range(top->slots_count); for EachInRange(slot_idx, slot_range) { for EachIndex(src_lane_idx, lane_count()) { RDIM_BakeNameMap *src_map = lane_maps[k][src_lane_idx]; RDIM_BakeNameMap *dst_map = map; if(dst_map->slots[slot_idx] == 0 && src_map->slots[slot_idx] != 0) { dst_map->slots[slot_idx] = src_map->slots[slot_idx]; } else if(dst_map->slots[slot_idx] != 0 && src_map->slots[slot_idx] != 0) { rdim_bake_name_chunk_list_concat_in_place(dst_map->slots[slot_idx], src_map->slots[slot_idx]); } } } } //- rjf: sort ProfScope("sort") { Rng1U64 slot_range = lane_range(top->slots_count); for EachInRange(slot_idx, slot_range) { if(map->slots[slot_idx] != 0) { RDIM_BakeNameChunkList *scratch_og_unsorted = map->slots[slot_idx]; map->slots[slot_idx] = push_array(arena, RDIM_BakeNameChunkList, 1); *map->slots[slot_idx] = rdim_bake_name_chunk_list_sorted_from_unsorted(arena, scratch_og_unsorted); } } } } lane_sync(); scratch_end(scratch); } lane_sync(); ////////////////////////////////////////////////////////////// //- rjf: @rdim_bake_stage build index runs // RDIM_BakeIdxRunMap *bake_idx_runs = 0; if(lane_idx() == 0) { bake_idx_runs = push_array(scratch.arena, RDIM_BakeIdxRunMap, 1); } lane_sync_u64(&bake_idx_runs, 0); B32 need_index_runs = (!!(params->subset_flags & RDIM_SubsetFlag_NameMaps) || !!(params->subset_flags & RDIM_SubsetFlag_Types)); if(need_index_runs) ProfScope("build index runs") { Temp scratch = scratch_begin(&arena, 1); //- rjf: set up per-lane outputs RDIM_BakeIdxRunMapTopology *top = 0; RDIM_BakeIdxRunMapLoose **lane_maps__loose = 0; RDIM_BakeIdxRunMapLoose *map__loose = 0; if(lane_idx() == 0) ProfScope("set up per-lane outputs") { top = push_array(scratch.arena, RDIM_BakeIdxRunMapTopology, 1); top->slots_count = 64 + ((all_procedures->total_count + all_global_variables->total_count + all_thread_variables->total_count + params->udts.total_count) * 3) / 4; lane_maps__loose = push_array(scratch.arena, RDIM_BakeIdxRunMapLoose *, lane_count()); map__loose = rdim_bake_idx_run_map_loose_make(scratch.arena, top); } lane_sync_u64(&top, 0); lane_sync_u64(&lane_maps__loose, 0); lane_sync_u64(&map__loose, 0); //- rjf: set up this lane's map ProfScope("set up this lane's map") { lane_maps__loose[lane_idx()] = rdim_bake_idx_run_map_loose_make(scratch.arena, top); } RDIM_BakeIdxRunMapLoose *lane_map = lane_maps__loose[lane_idx()]; //- rjf: wide fill of all index runs ProfScope("fill all lane index run maps") { //- rjf: bake runs of function-type parameter lists ProfScope("bake runs of function-type parameter lists") { for EachNode(n, RDIM_TypeChunkNode, params->types.first) { Rng1U64 range = lane_range(n->count); ProfScope("[%I64u, %I64u)", range.min, range.max) for EachInRange(n_idx, range) { RDIM_Type *type = &n->v[n_idx]; if(type->count == 0) { continue; } if(type->kind == RDI_TypeKind_Function || type->kind == RDI_TypeKind_Method) { RDI_U32 param_idx_run_count = type->count; RDI_U32 *param_idx_run = rdim_push_array_no_zero(arena, RDI_U32, param_idx_run_count); for(RDI_U32 idx = 0; idx < param_idx_run_count; idx += 1) { param_idx_run[idx] = (RDI_U32)rdim_idx_from_type(type->param_types[idx]); // TODO(rjf): @u64_to_u32 } rdim_bake_idx_run_map_loose_insert(scratch.arena, top, lane_map, 4, param_idx_run, param_idx_run_count); } } } } //- rjf: bake runs of name map match lists for EachNonZeroEnumVal(RDI_NameMapKind, k) ProfScope("bake runs of name map match lists (%.*s)", str8_varg(rdi_string_from_name_map_kind(k))) { if(!name_maps_need_build[k]) { continue; } RDIM_BakeNameMapTopology *name_map_top = &bake_name_maps_tops[k]; RDIM_BakeNameMap *name_map = bake_name_maps[k]; Rng1U64 slot_idx_range = lane_range(name_map_top->slots_count); for EachInRange(slot_idx, slot_idx_range) { RDIM_BakeNameChunkList *slot = name_map->slots[slot_idx]; if(slot != 0) { typedef struct IdxRunNode IdxRunNode; struct IdxRunNode { IdxRunNode *next; RDI_U64 idx; }; IdxRunNode *first_idx_run_node = 0; IdxRunNode *last_idx_run_node = 0; U64 active_idx_count = 0; String8 active_string = {0}; RDIM_BakeNameChunkNode *n = slot->first; U64 n_idx = 0; for(;;) { // rjf: advance chunk if(n != 0 && n_idx >= n->count) { n = n->next; n_idx = 0; } // rjf: grab next element String8 string = {0}; U64 idx = 0; if(n != 0) { string = n->v[n_idx].string; idx = n->v[n_idx].idx; } // rjf: next element hash doesn't match the active? -> push index run, clear active list, start new list if(!str8_match(string, active_string, 0)) { if(active_idx_count > 1) { RDI_U64 idxs_count = active_idx_count; RDI_U32 *idxs = rdim_push_array(arena, RDI_U32, idxs_count); { U64 write_idx = 0; for EachNode(idx_run_n, IdxRunNode, first_idx_run_node) { idxs[write_idx] = (RDI_U32)idx_run_n->idx; // TODO(rjf): @u64_to_u32 write_idx += 1; } } rdim_bake_idx_run_map_loose_insert(scratch.arena, top, lane_map, 4, idxs, idxs_count); } active_string = string; first_idx_run_node = 0; last_idx_run_node = 0; active_idx_count = 0; } // rjf: new element matches the active list -> push if(active_string.size != 0 && str8_match(string, active_string, 0)) { IdxRunNode *idx_run_n = push_array(scratch.arena, IdxRunNode, 1); idx_run_n->idx = idx; SLLQueuePush(first_idx_run_node, last_idx_run_node, idx_run_n); active_idx_count += 1; } // rjf: advance index n_idx += 1; // rjf: end on zero node if(n == 0) { break; } } } } } } lane_sync(); //- rjf: join ProfScope("join") { Rng1U64 slot_range = lane_range(top->slots_count); for EachInRange(slot_idx, slot_range) { for EachIndex(src_lane_idx, lane_count()) { RDIM_BakeIdxRunMapLoose *src_map = lane_maps__loose[src_lane_idx]; RDIM_BakeIdxRunMapLoose *dst_map = map__loose; dst_map->slots_idx_counts[slot_idx] += src_map->slots_idx_counts[slot_idx]; if(dst_map->slots[slot_idx] == 0 && src_map->slots[slot_idx] != 0) { dst_map->slots[slot_idx] = src_map->slots[slot_idx]; } else if(dst_map->slots[slot_idx] != 0 && src_map->slots[slot_idx] != 0) { rdim_bake_idx_run_chunk_list_concat_in_place(dst_map->slots[slot_idx], src_map->slots[slot_idx]); } } } } lane_sync(); //- rjf: sort ProfScope("sort") { RDIM_BakeIdxRunMapLoose *map = map__loose; Rng1U64 slot_range = lane_range(top->slots_count); for EachInRange(slot_idx, slot_range) { if(map->slots[slot_idx] != 0) { *map->slots[slot_idx] = rdim_bake_idx_run_chunk_list_sorted_from_unsorted(arena, map->slots[slot_idx]); map->slots_idx_counts[slot_idx] = 0; for EachNode(n, RDIM_BakeIdxRunChunkNode, map->slots[slot_idx]->first) { for EachIndex(idx, n->count) { map->slots_idx_counts[slot_idx] += n->v[idx].count; } } } } } lane_sync(); //- rjf: tighten idx run table ProfScope("tighten idx run table") { RDIM_BakeIdxRunMapLoose *map = map__loose; if(lane_idx() == 0) ProfScope("calc base indices, set up tight map") { bake_idx_runs->slots_count = top->slots_count; bake_idx_runs->slots = rdim_push_array(arena, RDIM_BakeIdxRunChunkList, bake_idx_runs->slots_count); bake_idx_runs->slots_base_idxs = rdim_push_array(arena, RDI_U64, bake_idx_runs->slots_count+1); RDI_U64 encoding_idx_off = 0; for(RDI_U64 slot_idx = 0; slot_idx < top->slots_count; slot_idx += 1) { bake_idx_runs->slots_base_idxs[slot_idx] = encoding_idx_off; if(map->slots[slot_idx] != 0) { encoding_idx_off += map->slots_idx_counts[slot_idx]; } } bake_idx_runs->slots_base_idxs[top->slots_count] = encoding_idx_off; } lane_sync(); ProfScope("fill tight map") { Rng1U64 slot_range = lane_range(bake_idx_runs->slots_count); for EachInRange(idx, slot_range) { if(map->slots[idx] != 0) { rdim_memcpy_struct(&bake_idx_runs->slots[idx], map->slots[idx]); } } } } lane_sync(); scratch_end(scratch); } lane_sync(); ////////////////////////////////////////////////////////////// //- rjf: @rdim_bake_stage bake strings // typedef struct BakedStrings BakedStrings; struct BakedStrings { RDI_U32 *string_offs; RDI_U64 string_offs_count; RDI_U8 *string_data; RDI_U64 string_data_size; }; BakedStrings *baked_strings = 0; ProfScope("bake strings") { // rjf: set up if(lane_idx() == 0) ProfScope("set up; lay out strings") { baked_strings = push_array(scratch.arena, BakedStrings, 1); baked_strings->string_offs_count = bake_strings->total_count + 1; baked_strings->string_offs = rdim_push_array(arena, RDI_U32, baked_strings->string_offs_count); RDI_U64 off_cursor = 0; for EachIndex(slot_idx, bake_strings->slots_count) { for EachNode(n, RDIM_BakeStringChunkNode, bake_strings->slots[slot_idx].first) { for EachIndex(n_idx, n->count) { RDIM_BakeString *src = &n->v[n_idx]; U64 dst_idx = bake_strings->slots_base_idxs[slot_idx] + n->base_idx + n_idx + 1; baked_strings->string_offs[dst_idx] = off_cursor; off_cursor += src->string.size; } } } baked_strings->string_data_size = off_cursor; baked_strings->string_data = rdim_push_array(arena, RDI_U8, baked_strings->string_data_size); } lane_sync_u64(&baked_strings, 0); // rjf: wide fill string data ProfScope("wide fill") { Rng1U64 slot_idx_range = lane_range(bake_strings->slots_count); for EachInRange(slot_idx, slot_idx_range) { for EachNode(n, RDIM_BakeStringChunkNode, bake_strings->slots[slot_idx].first) { for EachIndex(n_idx, n->count) { RDIM_BakeString *src = &n->v[n_idx]; U64 dst_idx = bake_strings->slots_base_idxs[slot_idx] + n->base_idx + n_idx + 1; U64 dst_off = baked_strings->string_offs[dst_idx]; rdim_memcpy(baked_strings->string_data + dst_off, src->string.str, src->string.size); } } } } } lane_sync(); ////////////////////////////////////////////////////////////// //- rjf: @rdim_bake_stage bake idx runs // typedef struct BakedIdxRuns BakedIdxRuns; struct BakedIdxRuns { RDI_U32 *idx_runs; RDI_U64 idx_count; }; BakedIdxRuns *baked_idx_runs = 0; if(lane_idx() == 0) { baked_idx_runs = push_array(scratch.arena, BakedIdxRuns, 1); } lane_sync_u64(&baked_idx_runs, 0); if(need_index_runs) ProfScope("bake idx runs") { // rjf: set up if(lane_idx() == 0) { baked_idx_runs->idx_count = bake_idx_runs->slots_base_idxs[bake_idx_runs->slots_count]; baked_idx_runs->idx_runs = push_array(arena, RDI_U32, baked_idx_runs->idx_count); } lane_sync(); // rjf: wide fill { Rng1U64 range = lane_range(bake_idx_runs->slots_count); for EachInRange(slot_idx, range) { RDI_U64 off = bake_idx_runs->slots_base_idxs[slot_idx]; for EachNode(n, RDIM_BakeIdxRunChunkNode, bake_idx_runs->slots[slot_idx].first) { StaticAssert(sizeof(baked_idx_runs->idx_runs[0]) == sizeof(n->v[0].idxes[0]), idx_run_size_check); for EachIndex(n_idx, n->count) { rdim_memcpy(baked_idx_runs->idx_runs + off, n->v[n_idx].idxes, sizeof(n->v[n_idx].idxes[0]) * n->v[n_idx].count); off += n->v[n_idx].count; } } } } } lane_sync(); ////////////////////////////////////////////////////////////// //- rjf: @rdim_bake_stage bake name maps // typedef struct BakedNameMaps BakedNameMaps; struct BakedNameMaps { RDI_NameMap *name_maps; RDI_U64 name_maps_count; RDI_NameMapBucket *buckets; RDI_U64 buckets_count; RDI_NameMapNode *nodes; RDI_U64 nodes_count; }; BakedNameMaps *baked_name_maps = 0; ProfScope("bake name maps") { // rjf: count unique names in all name maps; lay out baked nodes U64 **lane_name_map_node_counts = 0; // [RDI_NameMapKind_COUNT][..] U64 **lane_name_map_node_offs = 0; // [RDI_NameMapKind_COUNT][..] U64 *name_map_node_counts = 0; // [RDI_NameMapKind_COUNT] U64 total_name_map_node_count = 0; ProfScope("count unique names in all name maps; lay out baked nodes") { if(lane_idx() == 0) { lane_name_map_node_counts = push_array(scratch.arena, U64 *, RDI_NameMapKind_COUNT); lane_name_map_node_offs = push_array(scratch.arena, U64 *, RDI_NameMapKind_COUNT); name_map_node_counts = push_array(scratch.arena, U64, RDI_NameMapKind_COUNT); for EachNonZeroEnumVal(RDI_NameMapKind, k) { lane_name_map_node_counts[k] = push_array(scratch.arena, U64, lane_count()); lane_name_map_node_offs[k] = push_array(scratch.arena, U64, lane_count()); } } lane_sync_u64(&lane_name_map_node_counts, 0); lane_sync_u64(&lane_name_map_node_offs, 0); lane_sync_u64(&name_map_node_counts, 0); for EachNonZeroEnumVal(RDI_NameMapKind, k) { if(!name_maps_need_build[k]) { continue; } RDIM_BakeNameMapTopology *top = &bake_name_maps_tops[k]; RDIM_BakeNameMap *map = bake_name_maps[k]; Rng1U64 range = lane_range(top->slots_count); for EachInRange(idx, range) { if(map->slots[idx] != 0) { U64 total_unique_name_count = 0; U64 last_hash = 0; for EachNode(n, RDIM_BakeNameChunkNode, map->slots[idx]->first) { for EachIndex(n_idx, n->count) { if(n->v[n_idx].hash != last_hash) { total_unique_name_count += 1; last_hash = n->v[n_idx].hash; } } } lane_name_map_node_counts[k][lane_idx()] += total_unique_name_count; } } } lane_sync(); if(lane_idx() == 0) { for EachNonZeroEnumVal(RDI_NameMapKind, k) { RDI_U64 node_off = 0; for EachIndex(l_idx, lane_count()) { name_map_node_counts[k] += lane_name_map_node_counts[k][l_idx]; lane_name_map_node_offs[k][l_idx] = node_off; node_off += lane_name_map_node_counts[k][l_idx]; } total_name_map_node_count += name_map_node_counts[k]; } } lane_sync_u64(&total_name_map_node_count, 0); } lane_sync(); // rjf: setup ProfScope("setup") if(lane_idx() == 0) { baked_name_maps = push_array(scratch.arena, BakedNameMaps, 1); baked_name_maps->name_maps_count = RDI_NameMapKind_COUNT; baked_name_maps->name_maps = push_array(arena, RDI_NameMap, baked_name_maps->name_maps_count); RDI_U32 bucket_off = 0; RDI_U32 node_off = 0; for EachNonZeroEnumVal(RDI_NameMapKind, k) { baked_name_maps->name_maps[k].bucket_base_idx = bucket_off; baked_name_maps->name_maps[k].node_base_idx = node_off; baked_name_maps->name_maps[k].bucket_count = (RDI_U32)bake_name_maps_tops[k].slots_count; // TODO(rjf): @u64_to_u32 baked_name_maps->name_maps[k].node_count = (RDI_U32)name_map_node_counts[k]; // TODO(rjf): @u64_to_u32 bucket_off += baked_name_maps->name_maps[k].bucket_count; node_off += baked_name_maps->name_maps[k].node_count; } baked_name_maps->buckets_count = bucket_off; baked_name_maps->buckets = push_array(arena, RDI_NameMapBucket, baked_name_maps->buckets_count); baked_name_maps->nodes_count = total_name_map_node_count; baked_name_maps->nodes = push_array(arena, RDI_NameMapNode, baked_name_maps->nodes_count); } lane_sync_u64(&baked_name_maps, 0); // rjf: wide fill baked name maps ProfScope("wide fill baked name maps") { for EachNonZeroEnumVal(RDI_NameMapKind, k) ProfScope("wide fill (%.*s)", str8_varg(rdi_string_from_name_map_kind(k))) { if(!name_maps_need_build[k]) { continue; } RDI_U64 write_node_off = lane_name_map_node_offs[k][lane_idx()]; RDIM_BakeNameMapTopology *top = &bake_name_maps_tops[k]; U64 slots_count = top->slots_count; RDIM_BakeNameMap *src_map = bake_name_maps[k]; RDI_NameMap *dst_map = &baked_name_maps->name_maps[k]; RDI_NameMapBucket *dst_buckets = baked_name_maps->buckets + dst_map->bucket_base_idx; RDI_NameMapNode *dst_nodes = baked_name_maps->nodes + dst_map->node_base_idx; Rng1U64 slot_range = lane_range(slots_count); for EachInRange(slot_idx, slot_range) { RDIM_BakeNameChunkList *src_slot = src_map->slots[slot_idx]; if(src_slot == 0) { continue; } RDI_NameMapBucket *dst_bucket = &dst_buckets[slot_idx]; dst_bucket->first_node = write_node_off; { Temp scratch2 = scratch_begin(&scratch.arena, 1); typedef struct IdxRunNode IdxRunNode; struct IdxRunNode { IdxRunNode *next; RDI_U64 idx; }; IdxRunNode *first_idx_run_node = 0; IdxRunNode *last_idx_run_node = 0; U64 active_idx_count = 0; String8 active_string = {0}; RDIM_BakeNameChunkNode *n = src_slot->first; U64 n_idx = 0; for(;;) { // rjf: advance chunk if(n != 0 && n_idx >= n->count) { n = n->next; n_idx = 0; } // rjf: grab next element U64 idx = 0; String8 string = {0}; if(n != 0) { idx = n->v[n_idx].idx; string = n->v[n_idx].string; } // rjf: next element doesn't match the active list? -> push index run, clear active list, start new list if(!str8_match(active_string, string, 0)) { // rjf: has active run -> flatten & serialize if(active_string.size != 0) { // rjf: flatten idxes RDI_U64 idxs_count = active_idx_count; RDI_U32 *idxs = rdim_push_array(scratch2.arena, RDI_U32, idxs_count); { U64 write_idx = 0; for EachNode(idx_run_n, IdxRunNode, first_idx_run_node) { idxs[write_idx] = (RDI_U32)idx_run_n->idx; // TODO(rjf): @u64_to_u32 write_idx += 1; } } // rjf: serialize node RDI_NameMapNode *dst_node = &dst_nodes[write_node_off]; dst_node->string_idx = rdim_bake_idx_from_string(bake_strings, active_string); dst_node->match_count = idxs_count; if(dst_node->match_count == 1) { dst_node->match_idx_or_idx_run_first = idxs[0]; } else if(dst_node->match_count > 1) { dst_node->match_idx_or_idx_run_first = rdim_bake_idx_from_idx_run(bake_idx_runs, idxs, idxs_count); } dst_bucket->node_count += 1; write_node_off += 1; } // rjf: start new list active_string = string; first_idx_run_node = 0; last_idx_run_node = 0; active_idx_count = 0; temp_end(scratch2); } // rjf: hash matches the active list -> push if(active_string.size != 0 && str8_match(active_string, string, 0)) { IdxRunNode *idx_run_n = push_array(scratch2.arena, IdxRunNode, 1); idx_run_n->idx = idx; SLLQueuePush(first_idx_run_node, last_idx_run_node, idx_run_n); active_idx_count += 1; } // rjf: advance index n_idx += 1; // rjf: end on zero node if(n == 0) { break; } } scratch_end(scratch2); } } } } } lane_sync(); ////////////////////////////////////////////////////////////// //- rjf: @rdim_bake_stage gather line-bucketed src line map data // RDIM_BakeSrcLineMap *bake_src_line_maps = 0; ProfScope("gather line-bucketed src line map data") { if(lane_idx() == 0) { bake_src_line_maps = push_array(scratch.arena, RDIM_BakeSrcLineMap, params->src_files.total_count); } lane_sync_u64(&bake_src_line_maps, 0); { for EachNode(n, RDIM_SrcFileChunkNode, params->src_files.first) { Rng1U64 range = lane_range(n->count); for EachInRange(n_idx, range) { U64 file_idx = n->base_idx + n_idx; RDIM_BakeSrcLineMap *map = &bake_src_line_maps[file_idx]; // rjf: set up map map->slots_count = Max(n->v[n_idx].total_line_count, 1); map->slots = push_array(arena, RDIM_BakeSrcLineMapSlot, map->slots_count); // rjf: gather line-bucketed info for EachNode(frag, RDIM_SrcFileLineMapFragment, n->v[n_idx].first_line_map_fragment) { RDIM_LineSequence *seq = frag->seq; for EachIndex(idx, seq->line_count) { RDI_U32 line_num = seq->line_nums[idx]; RDI_U64 voff_first = seq->voffs[idx]; RDI_U64 voff_opl = seq->voffs[idx+1]; RDI_U64 slot_idx = line_num%map->slots_count; // rjf: find existing line node RDIM_BakeSrcLineMapNode *line_node = 0; { for EachNode(line_n, RDIM_BakeSrcLineMapNode, map->slots[slot_idx].first) { if(line_n->line_num == line_num) { line_node = line_n; break; } } } // rjf: construct new node if unseen if(line_node == 0) { line_node = push_array(arena, RDIM_BakeSrcLineMapNode, 1); SLLQueuePush(map->slots[slot_idx].first, map->slots[slot_idx].last, line_node); line_node->line_num = line_num; map->line_count += 1; } // rjf: push this voff range RDIM_Rng1U64 voff_range = {voff_first, voff_opl}; rdim_rng1u64_list_push(arena, &line_node->voff_ranges, voff_range); map->voff_range_count += 1; } } } } } } lane_sync(); ////////////////////////////////////////////////////////////// //- rjf: @rdim_bake_stage sort line-bucketed src line map data // RDIM_SortKey **bake_src_line_map_keys = 0; ProfScope("sort line-bucketed src line map data") { U64 *map_take_idx = push_array(scratch.arena, U64, 1); U64 map_count = params->src_files.total_count; if(lane_idx() == 0) { bake_src_line_map_keys = push_array(arena, RDIM_SortKey *, map_count); } lane_sync_u64(&bake_src_line_map_keys, 0); lane_sync_u64(&map_take_idx, 0); for(;;) { U64 map_num = ins_atomic_u64_inc_eval(map_take_idx); if(map_num < 1 || map_count < map_num) { break; } U64 map_idx = map_num-1; RDIM_BakeSrcLineMap *map = &bake_src_line_maps[map_idx]; // rjf: gather keys bake_src_line_map_keys[map_idx] = push_array_no_zero(arena, RDIM_SortKey, map->line_count); RDIM_SortKey *keys = bake_src_line_map_keys[map_idx]; { U64 key_idx = 0; for EachIndex(slot_idx, map->slots_count) { for EachNode(n, RDIM_BakeSrcLineMapNode, map->slots[slot_idx].first) { keys[key_idx].key = n->line_num; keys[key_idx].val = n; key_idx += 1; } } } // rjf: sort keys { radsort(keys, map->line_count, rdim_sort_key_is_before); } } } ////////////////////////////////////////////////////////////// //- rjf: @rdim_bake_stage compute src file / src file line map layout // typedef struct SrcMapLayout SrcMapLayout; struct SrcMapLayout { RDI_U64 *lane_chunk_src_file_num_counts; // [lane_count * src_file_chunk_count] RDI_U64 *lane_chunk_src_file_voff_counts; // [lane_count * src_file_chunk_count] RDI_U64 *lane_chunk_src_file_map_counts; // [lane_count * src_file_chunk_count] RDI_U64 *lane_chunk_src_file_num_offs; // [lane_count * src_file_chunk_count] RDI_U64 *lane_chunk_src_file_voff_offs; // [lane_count * src_file_chunk_count] RDI_U64 *lane_chunk_src_file_map_offs; // [lane_count * src_file_chunk_count] RDI_U64 *lane_chunk_src_file_checksum_counts[RDI_ChecksumKind_COUNT]; // [lane_count * src_file_chunk_count] RDI_U64 *lane_chunk_src_file_checksum_offs[RDI_ChecksumKind_COUNT]; // [lane_count * src_file_chunk_count] U64 total_checksum_counts[RDI_ChecksumKind_COUNT]; RDI_U64 total_src_map_line_count; RDI_U64 total_src_map_voff_count; }; SrcMapLayout *src_map_layout = 0; ProfScope("compute src file / src file line map layout") { // rjf: set up if(lane_idx() == 0) { src_map_layout = push_array(scratch.arena, SrcMapLayout, 1); src_map_layout->lane_chunk_src_file_num_counts = push_array(arena, U64, lane_count()*params->src_files.chunk_count); src_map_layout->lane_chunk_src_file_voff_counts = push_array(arena, U64, lane_count()*params->src_files.chunk_count); src_map_layout->lane_chunk_src_file_map_counts = push_array(arena, U64, lane_count()*params->src_files.chunk_count); src_map_layout->lane_chunk_src_file_num_offs = push_array(arena, U64, lane_count()*params->src_files.chunk_count); src_map_layout->lane_chunk_src_file_voff_offs = push_array(arena, U64, lane_count()*params->src_files.chunk_count); src_map_layout->lane_chunk_src_file_map_offs = push_array(arena, U64, lane_count()*params->src_files.chunk_count); for EachEnumVal(RDI_ChecksumKind, k) { src_map_layout->lane_chunk_src_file_checksum_counts[k] = push_array(arena, U64, lane_count()*params->src_files.chunk_count); src_map_layout->lane_chunk_src_file_checksum_offs[k] = push_array(arena, U64, lane_count()*params->src_files.chunk_count); } } lane_sync_u64(&src_map_layout, 0); // rjf: wide count { U64 chunk_idx = 0; for EachNode(n, RDIM_SrcFileChunkNode, params->src_files.first) { Rng1U64 range = lane_range(n->count); U64 slot_idx = lane_idx()*params->src_files.chunk_count + chunk_idx; for EachInRange(idx, range) { RDIM_BakeSrcLineMap *map = &bake_src_line_maps[n->base_idx + idx]; src_map_layout->lane_chunk_src_file_num_counts[slot_idx] += map->line_count; src_map_layout->lane_chunk_src_file_voff_counts[slot_idx] += map->voff_range_count; src_map_layout->lane_chunk_src_file_map_counts[slot_idx] += !!map->line_count; RDI_ChecksumKind k = n->v[idx].checksum_kind; String8 val = n->v[idx].checksum; if(RDI_ChecksumKind_NULL < k && k < RDI_ChecksumKind_COUNT && val.size != 0) { src_map_layout->lane_chunk_src_file_checksum_counts[k][slot_idx] += 1; } } chunk_idx += 1; } } lane_sync(); // rjf: layout if(lane_idx() == 0) { U64 chunk_idx = 0; U64 num_layout_off = 0; U64 voff_layout_off = 0; U64 map_layout_off = 1; U64 checksum_layout_offs[RDI_ChecksumKind_COUNT] = {0}; for EachNode(n, RDIM_SrcFileChunkNode, params->src_files.first) { for EachIndex(l_idx, lane_count()) { U64 slot_idx = l_idx*params->src_files.chunk_count + chunk_idx; src_map_layout->lane_chunk_src_file_num_offs[slot_idx] = num_layout_off; src_map_layout->lane_chunk_src_file_voff_offs[slot_idx] = voff_layout_off; src_map_layout->lane_chunk_src_file_map_offs[slot_idx] = map_layout_off; num_layout_off += src_map_layout->lane_chunk_src_file_num_counts[slot_idx]; voff_layout_off += src_map_layout->lane_chunk_src_file_voff_counts[slot_idx]; map_layout_off += src_map_layout->lane_chunk_src_file_map_counts[slot_idx]; for EachEnumVal(RDI_ChecksumKind, k) { src_map_layout->lane_chunk_src_file_checksum_offs[k][slot_idx] = checksum_layout_offs[k]; checksum_layout_offs[k] += src_map_layout->lane_chunk_src_file_checksum_counts[k][slot_idx]; } } chunk_idx += 1; } src_map_layout->total_src_map_line_count = num_layout_off; src_map_layout->total_src_map_voff_count = voff_layout_off; for EachEnumVal(RDI_ChecksumKind, k) { src_map_layout->total_checksum_counts[k] = checksum_layout_offs[k]; } } } lane_sync(); ////////////////////////////////////////////////////////////// //- rjf: @rdim_bake_stage bake src files // typedef struct BakedSrcFiles BakedSrcFiles; struct BakedSrcFiles { RDI_SourceFile *source_files; RDI_U64 source_files_count; RDI_SourceLineMap *source_line_maps; RDI_U64 source_line_maps_count; RDI_U32 *source_line_map_nums; RDI_U32 *source_line_map_rngs; RDI_U64 *source_line_map_voffs; RDI_U64 source_line_map_nums_count; RDI_U64 source_line_map_rngs_count; RDI_U64 source_line_map_voffs_count; }; BakedSrcFiles *baked_src_files = 0; ProfScope("bake src files") { //- rjf: set up if(lane_idx() == 0) { baked_src_files = push_array(scratch.arena, BakedSrcFiles, 1); baked_src_files->source_files_count = params->src_files.total_count+1; baked_src_files->source_files = push_array(arena, RDI_SourceFile, baked_src_files->source_files_count); baked_src_files->source_line_maps_count = params->src_files.source_line_map_count+1; baked_src_files->source_line_maps = push_array(arena, RDI_SourceLineMap, baked_src_files->source_line_maps_count); baked_src_files->source_line_map_nums_count = src_map_layout->total_src_map_line_count; baked_src_files->source_line_map_nums = push_array(arena, RDI_U32, baked_src_files->source_line_map_nums_count); baked_src_files->source_line_map_rngs_count = src_map_layout->total_src_map_line_count + baked_src_files->source_line_maps_count; baked_src_files->source_line_map_rngs = push_array(arena, RDI_U32, baked_src_files->source_line_map_rngs_count); baked_src_files->source_line_map_voffs_count = src_map_layout->total_src_map_voff_count; baked_src_files->source_line_map_voffs = push_array(arena, RDI_U64, baked_src_files->source_line_map_voffs_count); } lane_sync_u64(&baked_src_files, 0); //- rjf: bake U64 chunk_idx = 0; for EachNode(n, RDIM_SrcFileChunkNode, params->src_files.first) { Rng1U64 range = lane_range(n->count); U64 slot_idx = lane_idx()*params->src_files.chunk_count + chunk_idx; U64 dst_num_off = src_map_layout->lane_chunk_src_file_num_offs[slot_idx]; U64 dst_map_off = src_map_layout->lane_chunk_src_file_map_offs[slot_idx]; U64 dst_voff_off = src_map_layout->lane_chunk_src_file_voff_offs[slot_idx]; U64 dst_rng_off = dst_num_off + dst_map_off; U64 dst_checksums_off[RDI_ChecksumKind_COUNT] = {0}; for EachEnumVal(RDI_ChecksumKind, k) { dst_checksums_off[k] = 1 + src_map_layout->lane_chunk_src_file_checksum_offs[k][slot_idx]; } for EachInRange(idx, range) { RDIM_BakeSrcLineMap *map = &bake_src_line_maps[n->base_idx + idx]; RDIM_SortKey *sorted_map_keys = bake_src_line_map_keys[n->base_idx + idx]; RDIM_SrcFile *src = &n->v[idx]; RDI_SourceFile *dst = &baked_src_files->source_files[n->base_idx + idx + 1]; RDI_SourceLineMap *dst_map = &baked_src_files->source_line_maps[dst_map_off]; RDI_U32 *dst_nums = &baked_src_files->source_line_map_nums[dst_num_off]; RDI_U32 *dst_rngs = &baked_src_files->source_line_map_rngs[dst_rng_off]; RDI_U64 *dst_voffs = &baked_src_files->source_line_map_voffs[dst_voff_off]; //- rjf: fill file info Temp scratch2 = scratch_begin(&scratch.arena, 1); String8 normalized_path = rdim_normalize_path_str8(scratch2.arena, src->path); B32 has_checksum = (RDI_ChecksumKind_NULL < src->checksum_kind && src->checksum_kind < RDI_ChecksumKind_COUNT && src->checksum.size != 0); dst->file_path_node_idx = rdim_bake_path_node_idx_from_string(path_tree, src->path); dst->normal_full_path_string_idx = rdim_bake_idx_from_string(bake_strings, normalized_path); dst->source_line_map_idx = src->total_line_count ? dst_map_off : 0; dst->checksum_kind = src->checksum_kind; dst->checksum_idx = has_checksum ? dst_checksums_off[dst->checksum_kind] : 0; scratch_end(scratch2); //- rjf: advance checksum offset for this kind if(has_checksum) { dst_checksums_off[dst->checksum_kind] += 1; } //- rjf: fill map info if(src->total_line_count != 0) { dst_map->line_count = (RDI_U32)map->line_count; // TODO(rjf): @u64_to_u32 dst_map->voff_count = (RDI_U32)map->voff_range_count; // TODO(rjf): @u64_to_u32 dst_map->line_map_nums_base_idx = (RDI_U32)dst_num_off; // TODO(rjf): @u64_to_u32 dst_map->line_map_range_base_idx = (RDI_U32)dst_rng_off; // TODO(rjf): @u64_to_u32 dst_map->line_map_voff_base_idx = (RDI_U32)dst_voff_off; // TODO(rjf): @u64_to_u32 dst_map_off += 1; } //- rjf: fill nums/ranges/voffs info if(src->total_line_count != 0) { U64 *dst_voff_ptr = dst_voffs; for EachIndex(line_num_idx, map->line_count) { dst_nums[line_num_idx] = (RDI_U32)sorted_map_keys[line_num_idx].key; // TODO(rjf): @u64_to_u32 dst_rngs[line_num_idx] = (RDI_U32)(dst_voff_ptr - dst_voffs); // TODO(rjf): @u64_to_u32 RDIM_BakeSrcLineMapNode *node = (RDIM_BakeSrcLineMapNode *)sorted_map_keys[line_num_idx].val; for EachNode(rng_n, RDIM_Rng1U64Node, node->voff_ranges.first) { dst_voff_ptr[0] = rng_n->v.min; dst_voff_ptr += 1; } } dst_rngs[map->line_count] = (RDI_U32)map->voff_range_count; // TODO(rjf): @u64_to_u32 dst_num_off += map->line_count; dst_rng_off += map->line_count+1; dst_voff_off += map->voff_range_count; } } chunk_idx += 1; } } ////////////////////////////////////////////////////////////// //- rjf: @rdim_bake_stage bake checksums // typedef struct BakedChecksums BakedChecksums; struct BakedChecksums { RDI_MD5 *md5s; RDI_U64 md5s_count; RDI_SHA1 *sha1s; RDI_U64 sha1s_count; RDI_SHA256 *sha256s; RDI_U64 sha256s_count; RDI_U64 *timestamps; RDI_U64 timestamps_count; }; BakedChecksums *baked_checksums = 0; ProfScope("bake checksums") { // rjf: allocate if(lane_idx() == 0) { baked_checksums = push_array(scratch.arena, BakedChecksums, 1); baked_checksums->md5s_count = src_map_layout->total_checksum_counts[RDI_ChecksumKind_MD5] + 1; baked_checksums->sha1s_count = src_map_layout->total_checksum_counts[RDI_ChecksumKind_SHA1] + 1; baked_checksums->sha256s_count = src_map_layout->total_checksum_counts[RDI_ChecksumKind_SHA256] + 1; baked_checksums->timestamps_count = src_map_layout->total_checksum_counts[RDI_ChecksumKind_Timestamp] + 1; baked_checksums->md5s = push_array(arena, RDI_MD5, baked_checksums->md5s_count); baked_checksums->sha1s = push_array(arena, RDI_SHA1, baked_checksums->sha1s_count); baked_checksums->sha256s = push_array(arena, RDI_SHA256, baked_checksums->sha256s_count); baked_checksums->timestamps = push_array(arena, RDI_U64, baked_checksums->timestamps_count); } lane_sync_u64(&baked_checksums, 0); // rjf: fill { U64 chunk_idx = 0; for EachNode(n, RDIM_SrcFileChunkNode, params->src_files.first) { Rng1U64 range = lane_range(n->count); U64 slot_idx = lane_idx()*params->src_files.chunk_count + chunk_idx; U64 dst_offs[RDI_ChecksumKind_COUNT] = {0}; for EachEnumVal(RDI_ChecksumKind, k) { dst_offs[k] = 1 + src_map_layout->lane_chunk_src_file_checksum_offs[k][slot_idx]; } for EachInRange(n_idx, range) { RDI_ChecksumKind k = n->v[n_idx].checksum_kind; String8 val = n->v[n_idx].checksum; if(RDI_ChecksumKind_NULL < k && k < RDI_ChecksumKind_COUNT && val.size != 0) { switch((RDI_ChecksumKindEnum)k) { case RDI_ChecksumKind_NULL: case RDI_ChecksumKind_COUNT: {}break; #define Case(name, table_name) case RDI_ChecksumKind_##name:{MemoryCopy(&baked_checksums->table_name[dst_offs[k]], val.str, Min(val.size, sizeof(baked_checksums->table_name[0])));}break Case(MD5, md5s); Case(SHA1, sha1s); Case(SHA256, sha256s); Case(Timestamp, timestamps); #undef Case } dst_offs[k] += 1; } } chunk_idx += 1; } } } lane_sync(); ////////////////////////////////////////////////////////////// //- rjf: @rdim_bake_stage bake namespaces // typedef struct BakedNamespaces BakedNamespaces; struct BakedNamespaces { RDI_Namespace *namespaces; RDI_U64 namespaces_count; }; BakedNamespaces *baked_namespaces = 0; ProfScope("bake namespaces") { // rjf: allocate if(lane_idx() == 0) { baked_namespaces = push_array(scratch.arena, BakedNamespaces, 1); baked_namespaces->namespaces_count = params->namespaces.total_count + 1; baked_namespaces->namespaces = push_array(arena, RDI_Namespace, baked_namespaces->namespaces_count); } lane_sync_u64(&baked_namespaces, 0); // rjf: fill for EachNode(n, RDIM_NamespaceChunkNode, params->namespaces.first) { Rng1U64 range = lane_range(n->count); for EachInRange(n_idx, range) { U64 dst_idx = n->base_idx + n_idx + 1; RDIM_Namespace *src = &n->v[n_idx]; RDI_Namespace *dst = &baked_namespaces->namespaces[dst_idx]; dst->name_string_idx = rdim_bake_idx_from_string(bake_strings, src->name); if(src->parent_namespace != 0) { dst->container_flags |= RDI_ContainerKind_Namespace; dst->container_idx = rdim_idx_from_namespace(src->parent_namespace); } else if(src->parent_scope != 0) { dst->container_flags |= RDI_ContainerKind_Scope; dst->container_idx = rdim_idx_from_scope(src->parent_scope); } else if(src->parent_type != 0 && src->parent_type->udt != 0) { dst->container_flags |= RDI_ContainerKind_Type; dst->container_idx = rdim_idx_from_udt(src->parent_type->udt); } } } } lane_sync(); ////////////////////////////////////////////////////////////// //- rjf: @rdim_bake_stage compute lane UDT member/enum-val layouts // typedef struct MemberLayout MemberLayout; struct MemberLayout { RDI_U64 *member_chunk_lane_counts; // [lane_count * udt_chunk_count] RDI_U64 *member_chunk_lane_offs; // [lane_count * udt_chunk_count] RDI_U64 *enum_val_chunk_lane_counts; // [lane_count * udt_chunk_count] RDI_U64 *enum_val_chunk_lane_offs; // [lane_count * udt_chunk_count] }; MemberLayout *mem_layout = 0; ProfScope("compute lane UDT member/enum-val layouts") { // rjf: allocate if(lane_idx() == 0) { mem_layout = push_array(scratch.arena, MemberLayout, 1); mem_layout->member_chunk_lane_counts = push_array(arena, U64, lane_count() * params->udts.chunk_count); mem_layout->member_chunk_lane_offs = push_array(arena, U64, lane_count() * params->udts.chunk_count); mem_layout->enum_val_chunk_lane_counts = push_array(arena, U64, lane_count() * params->udts.chunk_count); mem_layout->enum_val_chunk_lane_offs = push_array(arena, U64, lane_count() * params->udts.chunk_count); } lane_sync_u64(&mem_layout, 0); // rjf: count { U64 chunk_idx = 0; for EachNode(n, RDIM_UDTChunkNode, params->udts.first) { Rng1U64 range = lane_range(n->count); for EachInRange(idx, range) { U64 slot_idx = lane_idx()*params->udts.chunk_count + chunk_idx; mem_layout->member_chunk_lane_counts[slot_idx] += n->v[idx].member_count; mem_layout->enum_val_chunk_lane_counts[slot_idx] += n->v[idx].enum_val_count; } chunk_idx += 1; } } lane_sync(); // rjf: layout if(lane_idx() == 0) { U64 member_layout_off = 1; U64 enum_val_layout_off = 1; U64 chunk_idx = 0; for EachNode(n, RDIM_UDTChunkNode, params->udts.first) { for EachIndex(l_idx, lane_count()) { U64 slot_idx = l_idx*params->udts.chunk_count + chunk_idx; mem_layout->member_chunk_lane_offs[slot_idx] = member_layout_off; mem_layout->enum_val_chunk_lane_offs[slot_idx] = enum_val_layout_off; member_layout_off += mem_layout->member_chunk_lane_counts[slot_idx]; enum_val_layout_off += mem_layout->enum_val_chunk_lane_counts[slot_idx]; } chunk_idx += 1; } } } lane_sync(); ////////////////////////////////////////////////////////////// //- rjf: @rdim_bake_stage bake UDTs // typedef struct BakedUDTs BakedUDTs; struct BakedUDTs { RDI_UDT *udts; RDI_U64 udts_count; RDI_Member *members; RDI_U64 members_count; RDI_EnumMember *enum_members; RDI_U64 enum_members_count; }; BakedUDTs *baked_udts = 0; ProfScope("bake UDTs") { //- rjf: set up ProfScope("set up") { if(lane_idx() == 0) { baked_udts = push_array(scratch.arena, BakedUDTs, 1); } lane_sync_u64(&baked_udts, 0); if(lane_idx() == lane_from_task_idx(0)) { baked_udts->udts_count = params->udts.total_count+1; baked_udts->udts = push_array(arena, RDI_UDT, baked_udts->udts_count); } if(lane_idx() == lane_from_task_idx(1)) { baked_udts->members_count = params->udts.total_member_count+1; baked_udts->members = push_array(arena, RDI_Member, baked_udts->members_count); } if(lane_idx() == lane_from_task_idx(2)) { baked_udts->enum_members_count = params->udts.total_enum_val_count+1; baked_udts->enum_members = push_array(arena, RDI_EnumMember, baked_udts->enum_members_count); } } lane_sync(); //- rjf: bake UDTs ProfScope("bake UDTs") { U64 chunk_idx = 0; for EachNode(n, RDIM_UDTChunkNode, params->udts.first) { Rng1U64 range = lane_range(n->count); U64 layout_slot_idx = lane_idx()*params->udts.chunk_count + chunk_idx; U64 member_layout_off = mem_layout->member_chunk_lane_offs[layout_slot_idx]; U64 enum_val_layout_off = mem_layout->enum_val_chunk_lane_offs[layout_slot_idx]; for EachInRange(n_idx, range) { RDIM_UDT *src_udt = &n->v[n_idx]; RDI_UDT *dst_udt = &baked_udts->udts[n->base_idx + n_idx + 1]; //- rjf: fill basics dst_udt->self_type_idx = (RDI_U32)rdim_idx_from_type(src_udt->self_type); // TODO(rjf): @u64_to_u32 dst_udt->file_idx = (RDI_U32)rdim_idx_from_src_file(src_udt->src_file); // TODO(rjf): @u64_to_u32 dst_udt->line = src_udt->line; dst_udt->col = src_udt->col; //- rjf: fill container info if(src_udt->container_scope != 0) { dst_udt->container_flags |= (RDI_ContainerKind_Scope & (RDI_U32)RDI_ContainerFlag_KindMask); dst_udt->container_idx = (RDI_U32)rdim_idx_from_scope(src_udt->container_scope); // TODO(rjf): @u64_to_u32 } else if(src_udt->container_namespace != 0) { dst_udt->container_flags |= (RDI_ContainerKind_Namespace & (RDI_U32)RDI_ContainerFlag_KindMask); dst_udt->container_idx = (RDI_U32)rdim_idx_from_namespace(src_udt->container_namespace); // TODO(rjf): @u64_to_u32 } else if(src_udt->container_type != 0) { dst_udt->container_flags |= (RDI_ContainerKind_Type & (RDI_U32)RDI_ContainerFlag_KindMask); dst_udt->container_idx = (RDI_U32)rdim_idx_from_udt(src_udt->container_type->udt); // TODO(rjf): @u64_to_u32 } //- rjf: fill member info if(src_udt->first_member != 0) { U64 member_off_first = member_layout_off; for EachNode(src_member, RDIM_UDTMember, src_udt->first_member) { RDI_Member *dst_member = &baked_udts->members[member_layout_off]; dst_member->kind = src_member->kind; dst_member->name_string_idx = rdim_bake_idx_from_string(bake_strings, src_member->name); dst_member->type_idx = (RDI_U32)rdim_idx_from_type(src_member->type); // TODO(rjf): @u64_to_u32 dst_member->off = src_member->off; member_layout_off += 1; } U64 member_off_opl = member_layout_off; dst_udt->member_first = (RDI_U32)member_off_first; // TODO(rjf): @u64_to_u32 dst_udt->member_count = (RDI_U32)(member_off_opl - member_off_first); // TODO(rjf): @u64_to_u32 } //- rjf: fill enum val info else if(src_udt->first_enum_val != 0) { U64 enum_val_off_first = enum_val_layout_off; for EachNode(src_enum_val, RDIM_UDTEnumVal, src_udt->first_enum_val) { RDI_EnumMember *dst_member = &baked_udts->enum_members[enum_val_layout_off]; dst_member->name_string_idx = rdim_bake_idx_from_string(bake_strings, src_enum_val->name); dst_member->val = src_enum_val->val; enum_val_layout_off += 1; } U64 enum_val_off_opl = enum_val_layout_off; dst_udt->flags |= RDI_UDTFlag_EnumMembers; dst_udt->member_first = (RDI_U32)enum_val_off_first; // TODO(rjf): @u64_to_u32 dst_udt->member_count = (RDI_U32)(enum_val_off_opl - enum_val_off_first); // TODO(rjf): @u64_to_u32 } } chunk_idx += 1; } } } lane_sync(); ////////////////////////////////////////////////////////////// //- rjf: @rdim_bake_stage compute layout for scope sub-lists (locals / voffs) // typedef struct ScopeLayout ScopeLayout; struct ScopeLayout { RDI_U64 *scope_local_chunk_lane_counts; // [lane_count * scope_chunk_count] RDI_U64 *scope_local_chunk_lane_offs; // [lane_count * scope_chunk_count] RDI_U64 *scope_voff_chunk_lane_counts; // [lane_count * scope_chunk_count] RDI_U64 *scope_voff_chunk_lane_offs; // [lane_count * scope_chunk_count] U64 total_local_count; }; ScopeLayout *scope_layout = 0; ProfScope("compute layout for scope sub-lists (locals / voffs)") { // rjf: set up if(lane_idx() == 0) { scope_layout = push_array(scratch.arena, ScopeLayout, 1); scope_layout->scope_local_chunk_lane_counts = push_array(arena, RDI_U64, lane_count() * all_scopes->chunk_count); scope_layout->scope_local_chunk_lane_offs = push_array(arena, RDI_U64, lane_count() * all_scopes->chunk_count); scope_layout->scope_voff_chunk_lane_counts = push_array(arena, RDI_U64, lane_count() * all_scopes->chunk_count); scope_layout->scope_voff_chunk_lane_offs = push_array(arena, RDI_U64, lane_count() * all_scopes->chunk_count); } lane_sync_u64(&scope_layout, 0); // rjf: count per-lane-chunk { U64 chunk_idx = 0; for EachNode(n, RDIM_ScopeChunkNode, all_scopes->first) { U64 num_locals_in_this_lane_and_node = 0; U64 num_voffs_in_this_lane_and_node = 0; Rng1U64 range = lane_range(n->count); for EachInRange(n_idx, range) { num_locals_in_this_lane_and_node += n->v[n_idx].locals.total_count; num_voffs_in_this_lane_and_node += n->v[n_idx].voff_ranges.count*2; } scope_layout->scope_local_chunk_lane_counts[lane_idx()*all_scopes->chunk_count + chunk_idx] = num_locals_in_this_lane_and_node; scope_layout->scope_voff_chunk_lane_counts[lane_idx()*all_scopes->chunk_count + chunk_idx] = num_voffs_in_this_lane_and_node; chunk_idx += 1; } } lane_sync(); // rjf: lay out each lane's range if(lane_idx() == 0) { U64 local_layout_off = 1; U64 voff_layout_off = 1; U64 chunk_idx = 0; for EachNode(n, RDIM_ScopeChunkNode, all_scopes->first) { for EachIndex(l_idx, lane_count()) { U64 slot_idx = l_idx*all_scopes->chunk_count + chunk_idx; scope_layout->scope_local_chunk_lane_offs[slot_idx] = local_layout_off; scope_layout->scope_voff_chunk_lane_offs[slot_idx] = voff_layout_off; local_layout_off += scope_layout->scope_local_chunk_lane_counts[slot_idx]; voff_layout_off += scope_layout->scope_voff_chunk_lane_counts[slot_idx]; } chunk_idx += 1; } scope_layout->total_local_count = local_layout_off; } lane_sync(); } lane_sync(); ////////////////////////////////////////////////////////////// //- rjf: @rdim_bake_stage bake scopes, gather locals // typedef struct BakedScopes BakedScopes; struct BakedScopes { RDI_Scope *scopes; RDI_U64 scopes_count; RDI_U64 *scope_voffs; RDI_U64 scope_voffs_count; RDIM_SymbolChunkNode arranged_locals_chunk; }; BakedScopes *baked_scopes = 0; ProfScope("bake scopes") { //- rjf: setup outputs if(lane_idx() == 0) { baked_scopes = push_array(scratch.arena, BakedScopes, 1); } lane_sync_u64(&baked_scopes, 0); if(lane_idx() == lane_from_task_idx(0)) { baked_scopes->scopes_count = all_scopes->total_count+1; baked_scopes->scopes = push_array(arena, RDI_Scope, baked_scopes->scopes_count); } if(lane_idx() == lane_from_task_idx(1)) { baked_scopes->scope_voffs_count = all_scopes->scope_voff_count+1; baked_scopes->scope_voffs = push_array(arena, RDI_U64, baked_scopes->scope_voffs_count); } if(lane_idx() == lane_from_task_idx(2)) { baked_scopes->arranged_locals_chunk.count = scope_layout->total_local_count - 1; baked_scopes->arranged_locals_chunk.cap = baked_scopes->arranged_locals_chunk.count; baked_scopes->arranged_locals_chunk.base_idx = 0; baked_scopes->arranged_locals_chunk.v = push_array(scratch.arena, RDIM_Symbol, baked_scopes->arranged_locals_chunk.count); } lane_sync(); //- rjf: wide fill { U64 chunk_idx = 0; for EachNode(n, RDIM_ScopeChunkNode, all_scopes->first) { Rng1U64 range = lane_range(n->count); U64 scope_chunk_lane_slot_idx = lane_idx()*all_scopes->chunk_count + chunk_idx; U64 chunk_local_off = scope_layout->scope_local_chunk_lane_offs[scope_chunk_lane_slot_idx]; U64 chunk_voff_off = scope_layout->scope_voff_chunk_lane_offs[scope_chunk_lane_slot_idx]; for EachInRange(n_idx, range) { U64 dst_idx = 1 + n->base_idx + n_idx; RDIM_Scope *src_scope = &n->v[n_idx]; RDI_Scope *dst_scope = &baked_scopes->scopes[dst_idx]; //- rjf: fill voff ranges U64 voff_idx_first = chunk_voff_off; for EachNode(rng_n, RDIM_Rng1U64Node, src_scope->voff_ranges.first) { baked_scopes->scope_voffs[chunk_voff_off+0] = rng_n->v.min; baked_scopes->scope_voffs[chunk_voff_off+1] = rng_n->v.max; chunk_voff_off += 2; } U64 voff_idx_opl = chunk_voff_off; //- rjf: fill locals U64 local_idx_first = chunk_local_off; for EachNode(src_local_n, RDIM_SymbolChunkNode, src_scope->locals.first) { for EachIndex(src_local_idx, src_local_n->count) { RDIM_Symbol *src_local = &src_local_n->v[src_local_idx]; RDIM_Symbol *dst_local = &baked_scopes->arranged_locals_chunk.v[chunk_local_off - 1]; dst_local->chunk = &baked_scopes->arranged_locals_chunk; dst_local->is_extern = src_local->is_extern; dst_local->is_param = src_local->is_param; dst_local->name = src_local->name; dst_local->link_name = src_local->link_name; dst_local->type = src_local->type; dst_local->container_scope = src_scope; dst_local->root_scope = src_local->root_scope; dst_local->location_cases = src_local->location_cases; chunk_local_off += 1; } } U64 local_idx_opl = chunk_local_off; //- rjf: fill scope dst_scope->proc_idx = (RDI_U32)rdim_idx_from_symbol(src_scope->symbol); // TODO(rjf): @u64_to_u32 dst_scope->parent_scope_idx = (RDI_U32)rdim_idx_from_scope(src_scope->parent_scope); // TODO(rjf): @u64_to_u32 dst_scope->first_child_scope_idx = (RDI_U32)rdim_idx_from_scope(src_scope->first_child); // TODO(rjf): @u64_to_u32 dst_scope->next_sibling_scope_idx = (RDI_U32)rdim_idx_from_scope(src_scope->next_sibling); // TODO(rjf): @u64_to_u32 dst_scope->voff_range_first = (RDI_U32)voff_idx_first; // TODO(rjf): @u64_to_u32 dst_scope->voff_range_opl = (RDI_U32)voff_idx_opl; // TODO(rjf): @u64_to_u32 dst_scope->local_first = (RDI_U32)local_idx_first; // TODO(rjf): @u64_to_u32 dst_scope->local_count = (RDI_U32)(local_idx_opl - local_idx_first); // TODO(rjf): @u64_to_u32 dst_scope->inline_site_idx = (RDI_U32)rdim_idx_from_inline_site(src_scope->inline_site); // TODO(rjf): @u64_to_u32 } chunk_idx += 1; } } } lane_sync(); ////////////////////////////////////////////////////////////// //- rjf: @rdim_bake_stage form local chunk list for all arranged locals // RDIM_SymbolChunkList *all_locals = 0; if(lane_idx() == 0) { all_locals = push_array(scratch.arena, RDIM_SymbolChunkList, 1); all_locals[0].first = all_locals[0].last = &baked_scopes->arranged_locals_chunk; all_locals[0].chunk_count = 1; all_locals[0].total_count = baked_scopes->arranged_locals_chunk.count; } lane_sync_u64(&all_locals, 0); ////////////////////////////////////////////////////////////// //- rjf: @rdim_bake_stage bake units, types, inline sites // RDI_Unit *baked_units = 0; U64 baked_units_count = 0; RDI_TypeNode *baked_type_nodes = 0; U64 baked_type_nodes_count = 0; RDI_InlineSite *baked_inline_sites = 0; RDI_U64 baked_inline_sites_count = 0; { //- rjf: setup outputs if(lane_idx() == lane_from_task_idx(0)) { baked_units_count = params->units.total_count+1; baked_units = push_array(arena, RDI_Unit, baked_units_count); } if(lane_idx() == lane_from_task_idx(1)) { baked_type_nodes_count = params->types.total_count+1; baked_type_nodes = push_array(arena, RDI_TypeNode, baked_type_nodes_count); } if(lane_idx() == lane_from_task_idx(2)) { baked_inline_sites_count = all_inline_sites->total_count+1; baked_inline_sites = push_array(arena, RDI_InlineSite, baked_inline_sites_count); } lane_sync_u64(&baked_units, lane_from_task_idx(0)); lane_sync_u64(&baked_units_count, lane_from_task_idx(0)); lane_sync_u64(&baked_type_nodes, lane_from_task_idx(1)); lane_sync_u64(&baked_type_nodes_count, lane_from_task_idx(1)); lane_sync_u64(&baked_inline_sites, lane_from_task_idx(2)); lane_sync_u64(&baked_inline_sites_count, lane_from_task_idx(2)); //- rjf: bake units ProfScope("bake units") { U64 base_unit_idx = 0; for EachNode(n, RDIM_UnitChunkNode, params->units.first) { Rng1U64 range = lane_range(n->count); for EachInRange(n_idx, range) { U64 unit_idx = base_unit_idx + n_idx; UnitSymbolRanges *symbol_ranges = &unit_symbol_ranges[unit_idx]; RDIM_Unit *src = &n->v[n_idx]; RDI_Unit *dst = &baked_units[n->base_idx + n_idx + 1]; dst->unit_name_string_idx = rdim_bake_idx_from_string(bake_strings, src->unit_name); dst->compiler_name_string_idx = rdim_bake_idx_from_string(bake_strings, src->compiler_name); dst->source_file_path_node = rdim_bake_path_node_idx_from_string(path_tree, src->source_file); dst->object_file_path_node = rdim_bake_path_node_idx_from_string(path_tree, src->object_file); dst->archive_file_path_node = rdim_bake_path_node_idx_from_string(path_tree, src->archive_file); dst->build_path_node = rdim_bake_path_node_idx_from_string(path_tree, src->build_path); dst->language = src->language; dst->line_table_idx = (RDI_U32)rdim_idx_from_line_table(src->line_table); // TODO(rjf): @u64_to_u32 dst->procedures_first_idx = (RDI_U32)symbol_ranges->procedures_first_idx; // TODO(rjf): @u64_to_u32 dst->procedures_count = (RDI_U32)symbol_ranges->procedures_count; // TODO(rjf): @u64_to_u32 dst->global_variables_first_idx = (RDI_U32)symbol_ranges->global_variables_first_idx; // TODO(rjf): @u64_to_u32 dst->global_variables_count = (RDI_U32)symbol_ranges->global_variables_count; // TODO(rjf): @u64_to_u32 dst->thread_variables_first_idx = (RDI_U32)symbol_ranges->thread_variables_first_idx; // TODO(rjf): @u64_to_u32 dst->thread_variables_count = (RDI_U32)symbol_ranges->thread_variables_count; // TODO(rjf): @u64_to_u32 dst->constants_first_idx = (RDI_U32)symbol_ranges->constants_first_idx; // TODO(rjf): @u64_to_u32 dst->constants_count = (RDI_U32)symbol_ranges->constants_count; // TODO(rjf): @u64_to_u32 } base_unit_idx += n->count; } } //- rjf: bake type nodes ProfScope("bake type nodes") { for EachNode(n, RDIM_TypeChunkNode, params->types.first) { Rng1U64 range = lane_range(n->count); for EachInRange(n_idx, range) { RDIM_Type *src = &n->v[n_idx]; RDI_TypeNode *dst = &baked_type_nodes[n->base_idx + n_idx + 1]; //- rjf: fill shared type node info dst->kind = src->kind; dst->flags = (RDI_U16)src->flags; // TODO(rjf): @u32_to_u16 dst->byte_size = src->byte_size; //- rjf: fill built-in-only type node info if(RDI_TypeKind_FirstBuiltIn <= dst->kind && dst->kind <= RDI_TypeKind_LastBuiltIn) { dst->built_in.name_string_idx = rdim_bake_idx_from_string(bake_strings, src->name); } //- rjf: fill array sizes else if(dst->kind == RDI_TypeKind_Array) { U64 direct_byte_size = 1; if(src->direct_type && src->direct_type->byte_size > 0) { direct_byte_size = src->direct_type->byte_size; } dst->constructed.direct_type_idx = (RDI_U32)rdim_idx_from_type(src->direct_type); dst->constructed.count = src->byte_size / direct_byte_size; } //- rjf: fill constructed type node info else if(RDI_TypeKind_FirstConstructed <= dst->kind && dst->kind <= RDI_TypeKind_LastConstructed) { dst->constructed.direct_type_idx = (RDI_U32)rdim_idx_from_type(src->direct_type); // TODO(rjf): @u64_to_u32 dst->constructed.count = src->count; if(dst->kind == RDI_TypeKind_Function || dst->kind == RDI_TypeKind_Method) { RDI_U32 param_idx_run_count = src->count; RDI_U32 *param_idx_run = rdim_push_array_no_zero(arena, RDI_U32, param_idx_run_count); for(RDI_U32 idx = 0; idx < param_idx_run_count; idx += 1) { param_idx_run[idx] = (RDI_U32)rdim_idx_from_type(src->param_types[idx]); // TODO(rjf): @u64_to_u32 } dst->constructed.param_idx_run_first = rdim_bake_idx_from_idx_run(bake_idx_runs, param_idx_run, param_idx_run_count); } else if(dst->kind == RDI_TypeKind_MemberPtr) { // TODO(rjf): member pointers not currently supported. } } //- rjf: fill user-defined-type info else if(RDI_TypeKind_FirstUserDefined <= dst->kind && dst->kind <= RDI_TypeKind_LastUserDefined) { dst->user_defined.name_string_idx = rdim_bake_idx_from_string(bake_strings, src->name); dst->user_defined.udt_idx = (RDI_U32)rdim_idx_from_udt(src->udt); // TODO(rjf): @u64_to_u32 dst->user_defined.direct_type_idx = (RDI_U32)rdim_idx_from_type(src->direct_type); // TODO(rjf): @u64_to_u32 } //- rjf: fill bitfield info else if(dst->kind == RDI_TypeKind_Bitfield) { dst->bitfield.direct_type_idx = (RDI_U32)rdim_idx_from_type(src->direct_type); // TODO(rjf): @u64_to_u32 dst->bitfield.off = src->off; dst->bitfield.size = src->count; } } } } //- rjf: bake inline sites ProfScope("bake inline sites") { for EachNode(n, RDIM_InlineSiteChunkNode, all_inline_sites->first) { Rng1U64 range = lane_range(n->count); for EachInRange(n_idx, range) { RDI_InlineSite *dst = &baked_inline_sites[n->base_idx + n_idx + 1]; RDIM_InlineSite *src = &n->v[n_idx]; dst->name_string_idx = rdim_bake_idx_from_string(bake_strings, src->name); dst->type_idx = (RDI_U32)rdim_idx_from_type(src->type); // TODO(rjf): @u64_to_u32 dst->owner_type_idx = (RDI_U32)rdim_idx_from_type(src->owner); // TODO(rjf): @u64_to_u32 dst->line_table_idx = (RDI_U32)rdim_idx_from_line_table(src->line_table); // TODO(rjf): @u64_to_u32 } } } } lane_sync(); ////////////////////////////// //- rjf: gather all lists which form symbol tables // RDI_Symbol *baked_global_variables = 0; U64 baked_global_variables_count = 0; RDI_Symbol *baked_thread_variables = 0; U64 baked_thread_variables_count = 0; RDI_Symbol *baked_procedures = 0; U64 baked_procedures_count = 0; RDI_Symbol *baked_constants = 0; U64 baked_constants_count = 0; RDI_Symbol *baked_locals = 0; U64 baked_locals_count = 0; struct { RDIM_SymbolChunkList *symbols; RDI_Symbol **baked_symbols_out; U64 *baked_symbols_count_out; } symbol_table_lists[] = { {all_global_variables, &baked_global_variables, &baked_global_variables_count}, {all_thread_variables, &baked_thread_variables, &baked_thread_variables_count}, {all_procedures, &baked_procedures, &baked_procedures_count}, {all_constants, &baked_constants, &baked_constants_count}, {all_locals, &baked_locals, &baked_locals_count}, }; ////////////////////////////////////////////////////////////// //- rjf: @rdim_bake_stage bake symbols (NEW) // RDI_U8 *baked_location_bytecode_data = 0; RDI_U8 *baked_location_constant_data = 0; RDI_LocationSetElement *baked_location_set_elements = 0; U64 baked_location_bytecode_data_size = 0; U64 baked_location_constant_data_size = 0; U64 baked_location_set_elements_count = 0; ProfScope("bake symbols") { //////////////////////////// //- rjf: count chunks // U64 chunk_count = 0; for EachElement(symbol_table_list_idx, symbol_table_lists) { chunk_count += symbol_table_lists[symbol_table_list_idx].symbols->chunk_count; } //////////////////////////// //- rjf: count indirected location data - bytecode, constants, set elements // U64 *lane_chunk_bytecode_data_counts = 0; U64 *lane_chunk_constant_data_counts = 0; U64 *lane_chunk_set_element_counts = 0; if(lane_idx() == 0) { lane_chunk_bytecode_data_counts = push_array(scratch.arena, U64, lane_count() * chunk_count); lane_chunk_constant_data_counts = push_array(scratch.arena, U64, lane_count() * chunk_count); lane_chunk_set_element_counts = push_array(scratch.arena, U64, lane_count() * chunk_count); } lane_sync_u64(&lane_chunk_bytecode_data_counts, 0); lane_sync_u64(&lane_chunk_constant_data_counts, 0); lane_sync_u64(&lane_chunk_set_element_counts, 0); ProfScope("count indirected location data") { U64 chunk_idx = 0; for EachElement(symbol_table_list_idx, symbol_table_lists) { RDIM_SymbolChunkList *src_symbols = symbol_table_lists[symbol_table_list_idx].symbols; for EachNode(n, RDIM_SymbolChunkNode, src_symbols->first) { U64 slot_idx = lane_idx()*chunk_count + chunk_idx; Rng1U64 range = lane_range(n->count); for EachInRange(n_idx, range) { RDIM_Symbol *s = &n->v[n_idx]; if(s->location_cases.count > 1) { lane_chunk_set_element_counts[slot_idx] += s->location_cases.count; } for EachNode(case_n, RDIM_LocationCase, s->location_cases.first) { lane_chunk_constant_data_counts[slot_idx] += case_n->location.value_data.size; lane_chunk_bytecode_data_counts[slot_idx] += case_n->location.bytecode.encoded_size + 1; // NOTE(rjf): +1 for the `stop` op } } chunk_idx += 1; } } } lane_sync(); //////////////////////////// //- rjf: lay out indirected location data // U64 *lane_chunk_bytecode_data_offs = 0; U64 *lane_chunk_constant_data_offs = 0; U64 *lane_chunk_set_element_offs = 0; U64 total_bytecode_data_count = 0; U64 total_constant_data_count = 0; U64 total_set_element_count = 0; ProfScope("lay out indirected location data") { if(lane_idx() == 0) { U64 bytecode_data_off = 0; U64 constant_data_off = 0; U64 set_element_off = 0; lane_chunk_bytecode_data_offs = push_array(scratch.arena, U64, lane_count() * chunk_count); lane_chunk_constant_data_offs = push_array(scratch.arena, U64, lane_count() * chunk_count); lane_chunk_set_element_offs = push_array(scratch.arena, U64, lane_count() * chunk_count); for EachIndex(chunk_idx, chunk_count) { for EachIndex(l_idx, lane_count()) { U64 slot_idx = l_idx*chunk_count + chunk_idx; lane_chunk_bytecode_data_offs[slot_idx] = bytecode_data_off; lane_chunk_constant_data_offs[slot_idx] = constant_data_off; lane_chunk_set_element_offs[slot_idx] = set_element_off; bytecode_data_off += lane_chunk_bytecode_data_counts[slot_idx]; constant_data_off += lane_chunk_constant_data_counts[slot_idx]; set_element_off += lane_chunk_set_element_counts[slot_idx]; } } total_bytecode_data_count = bytecode_data_off; total_constant_data_count = constant_data_off; total_set_element_count = set_element_off; } lane_sync_u64(&lane_chunk_bytecode_data_offs, 0); lane_sync_u64(&lane_chunk_constant_data_offs, 0); lane_sync_u64(&lane_chunk_set_element_offs, 0); lane_sync_u64(&total_bytecode_data_count, 0); lane_sync_u64(&total_constant_data_count, 0); lane_sync_u64(&total_set_element_count, 0); } //////////////////////////// //- rjf: set up location outputs // RDI_U8 *loc_bytecode_data = 0; RDI_U8 *loc_constant_data = 0; RDI_LocationSetElement *loc_set_elements = 0; if(lane_idx() == 0) { loc_bytecode_data = push_array(arena, RDI_U8, total_bytecode_data_count); loc_constant_data = push_array(arena, RDI_U8, total_constant_data_count); loc_set_elements = push_array(arena, RDI_LocationSetElement, total_set_element_count); } lane_sync_u64(&loc_bytecode_data, 0); lane_sync_u64(&loc_constant_data, 0); lane_sync_u64(&loc_set_elements, 0); baked_location_bytecode_data = loc_bytecode_data; baked_location_bytecode_data_size = total_bytecode_data_count; baked_location_constant_data = loc_constant_data; baked_location_constant_data_size = total_constant_data_count; baked_location_set_elements = loc_set_elements; baked_location_set_elements_count = total_set_element_count; //////////////////////////// //- rjf: bake flat symbol tables // ProfScope("bake flat symbol tables") { U64 chunk_idx = 0; for EachElement(symbol_table_list_idx, symbol_table_lists) { ProfBegin("table %I64u", symbol_table_list_idx); RDIM_SymbolChunkList *src_symbols = symbol_table_lists[symbol_table_list_idx].symbols; U64 dst_symbols_count = src_symbols->total_count + 1; RDI_Symbol *dst_symbols = 0; if(lane_idx() == 0) { dst_symbols = push_array(arena, RDI_Symbol, dst_symbols_count); } lane_sync_u64(&dst_symbols, 0); symbol_table_lists[symbol_table_list_idx].baked_symbols_out[0] = dst_symbols; symbol_table_lists[symbol_table_list_idx].baked_symbols_count_out[0] = dst_symbols_count; for EachNode(n, RDIM_SymbolChunkNode, src_symbols->first) { U64 slot_idx = lane_idx()*chunk_count + chunk_idx; U64 dst_bytecode_off = lane_chunk_bytecode_data_offs[slot_idx]; U64 dst_constant_off = lane_chunk_constant_data_offs[slot_idx]; U64 dst_set_element_idx = lane_chunk_set_element_offs[slot_idx]; Rng1U64 range = lane_range(n->count); for EachInRange(n_idx, range) { RDIM_Symbol *src = &n->v[n_idx]; RDI_Symbol *dst = &dst_symbols[n->base_idx + n_idx + 1]; // rjf: fill basics dst->name_string_idx = rdim_bake_idx_from_string(bake_strings, src->name); dst->type_idx = (RDI_U32)rdim_idx_from_type(src->type); // TODO(rjf): @u64_to_u32 dst->root_scope_idx = (RDI_U32)rdim_idx_from_scope(src->root_scope); // TODO(rjf): @u64_to_u32 dst->link_name_string_idx = rdim_bake_idx_from_string(bake_strings, src->link_name); if (src->is_param) { dst->symbol_flags |= RDI_SymbolFlag_IsParam; } // rjf: fill container info if(src->is_extern) { dst->container_flags |= RDI_ContainerFlag_External; } if(src->container_scope != 0) { dst->container_flags |= RDI_ContainerKind_Scope; dst->container_idx = rdim_idx_from_scope(src->container_scope); } else if(src->container_type != 0) { dst->container_flags |= RDI_ContainerKind_Type; dst->container_idx = rdim_idx_from_udt(src->container_type->udt); } else if(src->container_namespace != 0) { dst->container_flags |= RDI_ContainerKind_Namespace; dst->container_idx = rdim_idx_from_namespace(src->container_namespace); } // rjf: fill location set info, if applicable - get set elements to fill RDI_LocationSetElement *dst_loc_set_elements = loc_set_elements + dst_set_element_idx; U64 dst_loc_set_elements_count = 0; if(src->location_cases.count > 1) { dst->location |= (((U64)RDI_LocationKind_Set) << RDI_Location_KindShift); dst->location |= ((src->location_cases.count << RDI_Location_SetCountShift) & RDI_Location_SetCountMask); dst->location |= ((dst_set_element_idx << RDI_Location_SetFirstIndexShift) & RDI_Location_SetFirstIndexMask); dst_loc_set_elements_count = src->location_cases.count; dst_set_element_idx += dst_loc_set_elements_count; } // rjf: fill virtual offset ranges of location set elements if(src->location_cases.count > 1) { U64 loc_set_element_idx = 0; for EachNode(c, RDIM_LocationCase, src->location_cases.first) { dst_loc_set_elements[loc_set_element_idx].voff_first = c->voff_range.min; dst_loc_set_elements[loc_set_element_idx].voff_opl = c->voff_range.max; loc_set_element_idx += 1; } } // rjf: fill location(s) RDI_Location *dst_loc_first = &dst->location; U64 dst_loc_count = 1; if(dst_loc_set_elements_count > 0) { dst_loc_first = &dst_loc_set_elements[0].location; dst_loc_count = dst_loc_set_elements_count; } { RDI_Location *dst_loc = dst_loc_first; for EachNode(c, RDIM_LocationCase, src->location_cases.first) { RDIM_Location *src_loc = &c->location; dst_loc[0] |= ((U64)src_loc->kind << RDI_Location_KindShift) & RDI_Location_KindMask; switch(src_loc->kind) { default:{}break; case RDI_LocationKind_AddrRegPlusOff: case RDI_LocationKind_AddrAddrRegPlusOff: { dst_loc[0] |= ((U64)src_loc->reg_code << RDI_Location_RegCodeShift) & RDI_Location_RegCodeMask; dst_loc[0] |= ((U64)src_loc->offset << RDI_Location_RegOffShift) & RDI_Location_RegOffMask; }break; case RDI_LocationKind_ValReg: { dst_loc[0] |= ((U64)src_loc->reg_code << RDI_Location_RegCodeShift) & RDI_Location_RegCodeMask; }break; case RDI_LocationKind_AddrBytecodeStream: case RDI_LocationKind_ValBytecodeStream: { dst_loc[0] |= ((U64)dst_bytecode_off << RDI_Location_OffShift) & RDI_Location_OffMask; for EachNode(op_node, RDIM_EvalBytecodeOp, src_loc->bytecode.first_op) { MemoryCopy(loc_bytecode_data + dst_bytecode_off, &op_node->op, 1); dst_bytecode_off += 1; MemoryCopy(loc_bytecode_data + dst_bytecode_off, &op_node->p, op_node->p_size); dst_bytecode_off += op_node->p_size; } loc_bytecode_data[dst_bytecode_off] = 0; dst_bytecode_off += 1; }break; case RDI_LocationKind_ModuleOff: case RDI_LocationKind_TLSOff: { dst_loc[0] |= ((U64)src_loc->offset << RDI_Location_OffShift) & RDI_Location_OffMask; }break; case RDI_LocationKind_ConstantDataOff: { dst_loc[0] |= ((U64)dst_constant_off << RDI_Location_OffShift) & RDI_Location_OffMask; MemoryCopy(loc_constant_data + dst_constant_off, src_loc->value_data.str, src_loc->value_data.size); dst_constant_off += src_loc->value_data.size; }break; } if(c->next != 0) { dst_loc = &(CastFromMember(RDI_LocationSetElement, location, dst_loc) + 1)->location; } } } } chunk_idx += 1; } ProfEnd(); } } } lane_sync(); ////////////////////////////////////////////////////////////// //- rjf: @rdim_bake_stage bake file paths // typedef struct BakedFilePaths BakedFilePaths; struct BakedFilePaths { RDI_FilePathNode *nodes; RDI_U64 nodes_count; }; BakedFilePaths *baked_file_paths = 0; RDIM_BakePathNode **baked_file_path_src_nodes = 0; ProfScope("bake file paths") { // rjf: set up if(lane_idx() == 0) { baked_file_paths = push_array(scratch.arena, BakedFilePaths, 1); baked_file_paths->nodes_count = path_tree->count; baked_file_paths->nodes = push_array(arena, RDI_FilePathNode, baked_file_paths->nodes_count); baked_file_path_src_nodes = push_array(arena, RDIM_BakePathNode *, baked_file_paths->nodes_count); { U64 idx = 0; for(RDIM_BakePathNode *n = path_tree->first; n != 0; n = n->next_order) { baked_file_path_src_nodes[idx] = n; idx += 1; } } } lane_sync_u64(&baked_file_paths, 0); lane_sync_u64(&baked_file_path_src_nodes, 0); // rjf: fill { Rng1U64 range = lane_range(baked_file_paths->nodes_count); for EachInRange(idx, range) { RDIM_BakePathNode *src = baked_file_path_src_nodes[idx]; RDI_FilePathNode *dst = &baked_file_paths->nodes[idx]; dst->name_string_idx = rdim_bake_idx_from_string(bake_strings, src->name); dst->source_file_idx = rdim_idx_from_src_file(src->src_file); if(src->parent != 0) { dst->parent_path_node = src->parent->idx; } if(src->first_child != 0) { dst->first_child = src->first_child->idx; } if(src->next_sibling != 0) { dst->next_sibling = src->next_sibling->idx; } } } } lane_sync(); ////////////////////////////////////////////////////////////// //- rjf: @rdim_bake_stage do small final baking tasks // RDI_TopLevelInfo *baked_top_level_info = 0; RDI_BinarySection *baked_binary_sections = 0; U64 baked_binary_sections_count = 0; ProfScope("do small final baking tasks") { if(lane_idx() == lane_from_task_idx(0)) ProfScope("bake top level info") { baked_top_level_info = push_array(arena, RDI_TopLevelInfo, 1); baked_top_level_info->arch = params->top_level_info.arch; baked_top_level_info->exe_name_string_idx = rdim_bake_idx_from_string(bake_strings, params->top_level_info.exe_name); baked_top_level_info->exe_hash = params->top_level_info.exe_hash; baked_top_level_info->voff_max = params->top_level_info.voff_max; baked_top_level_info->guid = params->top_level_info.guid; baked_top_level_info->producer_name_string_idx = rdim_bake_idx_from_string(bake_strings, params->top_level_info.producer_name); } if(lane_idx() == lane_from_task_idx(1)) ProfScope("bake binary sections") { RDIM_BinarySectionList *src = ¶ms->binary_sections; RDI_BinarySection *dst_base = rdim_push_array(arena, RDI_BinarySection, src->count+1); U64 dst_idx = 1; for(RDIM_BinarySectionNode *src_n = src->first; src_n != 0; src_n = src_n->next, dst_idx += 1) { RDIM_BinarySection *src = &src_n->v; RDI_BinarySection *dst = &dst_base[dst_idx]; dst->name_string_idx = rdim_bake_idx_from_string(bake_strings, src->name); dst->flags = src->flags; dst->voff_first = src->voff_first; dst->voff_opl = src->voff_opl; dst->foff_first = src->foff_first; dst->foff_opl = src->foff_opl; } baked_binary_sections = dst_base; baked_binary_sections_count = dst_idx; } } lane_sync_u64(&baked_top_level_info, lane_from_task_idx(0)); lane_sync_u64(&baked_binary_sections, lane_from_task_idx(1)); lane_sync_u64(&baked_binary_sections_count, lane_from_task_idx(1)); ////////////////////////////////////////////////////////////// //- rjf: @rdim_bake_stage package results // RDIM_BakeResults result = {0}; { #define Map(kind, ptr, count) result.section_bundle.sections[RDI_SectionKind_##kind] = rdim_serialized_section_make_unpacked_array((ptr), (count)) Map(TopLevelInfo, baked_top_level_info, 1); Map(StringData, baked_strings->string_data, baked_strings->string_data_size); Map(StringTable, baked_strings->string_offs, baked_strings->string_offs_count); Map(IndexRuns, baked_idx_runs->idx_runs, baked_idx_runs->idx_count); Map(BinarySections, baked_binary_sections, baked_binary_sections_count); Map(FilePathNodes, baked_file_paths->nodes, baked_file_paths->nodes_count); Map(SourceFiles, baked_src_files->source_files, baked_src_files->source_files_count); Map(LineTables, baked_line_tables->line_tables, baked_line_tables->line_tables_count); Map(LineInfoVOffs, baked_line_tables->line_table_voffs, baked_line_tables->line_table_voffs_count); Map(LineInfoLines, baked_line_tables->line_table_lines, baked_line_tables->line_table_lines_count); Map(LineInfoColumns, baked_line_tables->line_table_columns, baked_line_tables->line_table_columns_count); Map(SourceLineMaps, baked_src_files->source_line_maps, baked_src_files->source_line_maps_count); Map(SourceLineMapNumbers, baked_src_files->source_line_map_nums, baked_src_files->source_line_map_nums_count); Map(SourceLineMapRanges, baked_src_files->source_line_map_rngs, baked_src_files->source_line_map_rngs_count); Map(SourceLineMapVOffs, baked_src_files->source_line_map_voffs, baked_src_files->source_line_map_voffs_count); Map(Units, baked_units, baked_units_count); Map(UnitVMap, baked_unit_vmap->vmap, baked_unit_vmap->count); Map(Namespaces, baked_namespaces->namespaces, baked_namespaces->namespaces_count); Map(TypeNodes, baked_type_nodes, baked_type_nodes_count); Map(UDTs, baked_udts->udts, baked_udts->udts_count); Map(Members, baked_udts->members, baked_udts->members_count); Map(EnumMembers, baked_udts->enum_members, baked_udts->enum_members_count); Map(Scopes, baked_scopes->scopes, baked_scopes->scopes_count); Map(ScopeVOffData, baked_scopes->scope_voffs, baked_scopes->scope_voffs_count); Map(ScopeVMap, baked_scope_vmap->vmap, baked_scope_vmap->count); Map(InlineSites, baked_inline_sites, baked_inline_sites_count); Map(GlobalVariables, baked_global_variables, baked_global_variables_count); Map(GlobalVMap, baked_global_vmap->vmap, baked_global_vmap->count); Map(ThreadVariables, baked_thread_variables, baked_thread_variables_count); Map(Constants, baked_constants, baked_constants_count); Map(Procedures, baked_procedures, baked_procedures_count); Map(LocalVariables, baked_locals, baked_locals_count); Map(LocationsBytecodeData, baked_location_bytecode_data, baked_location_bytecode_data_size); Map(LocationsConstantData, baked_location_constant_data, baked_location_constant_data_size); Map(LocationsSetElements, baked_location_set_elements, baked_location_set_elements_count); Map(MD5Checksums, baked_checksums->md5s, baked_checksums->md5s_count); Map(SHA1Checksums, baked_checksums->sha1s, baked_checksums->sha1s_count); Map(SHA256Checksums, baked_checksums->sha256s, baked_checksums->sha256s_count); Map(Timestamps, baked_checksums->timestamps, baked_checksums->timestamps_count); Map(NameMaps, baked_name_maps->name_maps, baked_name_maps->name_maps_count); Map(NameMapBuckets, baked_name_maps->buckets, baked_name_maps->buckets_count); Map(NameMapNodes, baked_name_maps->nodes, baked_name_maps->nodes_count); #undef Map } lane_sync(); scratch_end(scratch); return result; } internal RDIM_SerializedSectionBundle rdim_compress(Arena *arena, RDIM_SerializedSectionBundle *in) { Temp scratch = scratch_begin(&arena, 1); RDIM_SerializedSectionBundle out_ = {0}; RDIM_SerializedSectionBundle *out = &out_; lane_sync_u64(&out, 0); //- rjf: set up compression context rr_lzb_simple_context ctx = {0}; ctx.m_tableSizeBits = 14; ctx.m_hashTable = push_array(scratch.arena, U16, 1<sections[k]; RDIM_SerializedSection *dst = &out->sections[k]; MemoryCopyStruct(dst, src); if(src->encoded_size != 0) { MemoryZero(ctx.m_hashTable, sizeof(U16)*(1<data = push_array_no_zero(arena, U8, src->encoded_size); dst->encoded_size = rr_lzb_simple_encode_veryfast(&ctx, src->data, src->encoded_size, dst->data); dst->unpacked_size = src->encoded_size; dst->encoding = RDI_SectionEncoding_LZB; } } lane_sync(); scratch_end(scratch); return *out; }