mirror of
https://github.com/Ed94/raddebugger.git
synced 2026-08-08 23:08:08 +00:00
checkpoint on rdi_from_dwarf pass, start addressing O(N lg N) hashing problem for type content, use sibling tags, etc.; remove test inputs from data/, just rely on local folder (filled via data server)
This commit is contained in:
@@ -1,8 +0,0 @@
|
|||||||
// Copyright (c) Epic Games Tools
|
|
||||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
|
||||||
|
|
||||||
bias = (bias^x)&7;
|
|
||||||
x -= bias;
|
|
||||||
x *= 2;
|
|
||||||
x *= x;
|
|
||||||
x += bias;
|
|
||||||
@@ -1,126 +0,0 @@
|
|||||||
// Copyright (c) Epic Games Tools
|
|
||||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Program to run in debugger organized to provide tests for
|
|
||||||
* single threaded stepping, breakpoints, evaluation.
|
|
||||||
*/
|
|
||||||
|
|
||||||
////////////////////////////////
|
|
||||||
// NOTE(allen): Complex Types
|
|
||||||
|
|
||||||
#include <complex.h>
|
|
||||||
|
|
||||||
void
|
|
||||||
c_type_coverage_eval_tests(void){
|
|
||||||
#if _WIN32
|
|
||||||
_Fcomplex x = _FCbuild(0.f, 1.f);
|
|
||||||
_Dcomplex y = _Cbuild(0.f, -1.f);
|
|
||||||
|
|
||||||
#else
|
|
||||||
float complex x = 0.f + 1.f*I;
|
|
||||||
double complex y = 0.0 - 1.0*I;
|
|
||||||
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
////////////////////////////////
|
|
||||||
// NOTE(allen): Reuse Type Names From Another Module
|
|
||||||
|
|
||||||
#include <stdint.h>
|
|
||||||
|
|
||||||
typedef struct Basics{
|
|
||||||
double a;
|
|
||||||
float b;
|
|
||||||
unsigned long long c;
|
|
||||||
long long d;
|
|
||||||
unsigned int e;
|
|
||||||
int f;
|
|
||||||
unsigned short g;
|
|
||||||
short h;
|
|
||||||
unsigned char i;
|
|
||||||
char j;
|
|
||||||
|
|
||||||
int z;
|
|
||||||
} Basics;
|
|
||||||
|
|
||||||
typedef struct Basics_Stdint{
|
|
||||||
double x1;
|
|
||||||
float x2;
|
|
||||||
uint64_t x3;
|
|
||||||
int64_t x4;
|
|
||||||
uint32_t x5;
|
|
||||||
int32_t x6;
|
|
||||||
uint16_t x7;
|
|
||||||
int16_t x8;
|
|
||||||
uint8_t x9;
|
|
||||||
int8_t x0;
|
|
||||||
} Basics_Stdint;
|
|
||||||
|
|
||||||
typedef struct Pair{
|
|
||||||
int i;
|
|
||||||
float f;
|
|
||||||
} Pair;
|
|
||||||
|
|
||||||
void
|
|
||||||
c_versions_of_same_types(void){
|
|
||||||
Basics basics = { 1.5f, 1.50000000000001, -1, 1, -2, 2, -4, 4, -8, 8, };
|
|
||||||
Basics_Stdint basics_stdint = { 1.5f, 1.50000000000001, -1, 1, -2, 2, -4, 4, -8, 8, };
|
|
||||||
Pair memory_[] = {
|
|
||||||
{100, 1.f},
|
|
||||||
{101, 2.f},
|
|
||||||
{102, 4.f},
|
|
||||||
{103, 8.f},
|
|
||||||
{104, 16.f},
|
|
||||||
{105, 32.f},
|
|
||||||
};
|
|
||||||
|
|
||||||
int x = memory_[3].i + basics.f;
|
|
||||||
}
|
|
||||||
|
|
||||||
////////////////////////////////
|
|
||||||
//~ NOTE(rjf): Bitfields
|
|
||||||
|
|
||||||
typedef struct TypeWithBitfield TypeWithBitfield;
|
|
||||||
struct TypeWithBitfield
|
|
||||||
{
|
|
||||||
int v : 14;
|
|
||||||
int w : 4;
|
|
||||||
int x : 32;
|
|
||||||
int y : 4;
|
|
||||||
int z : 10;
|
|
||||||
};
|
|
||||||
|
|
||||||
typedef struct BitfieldType64 BitfieldType64;
|
|
||||||
struct BitfieldType64
|
|
||||||
{
|
|
||||||
uint64_t size : 63;
|
|
||||||
uint64_t is_free : 1;
|
|
||||||
};
|
|
||||||
|
|
||||||
static int mut_xarray[4] = {100, 101, 102, 103};
|
|
||||||
static float mut_farray[4] = {100.5f, 101.5f, 102.5f, 103.5f};
|
|
||||||
|
|
||||||
void
|
|
||||||
c_type_with_bitfield_usage(void)
|
|
||||||
{
|
|
||||||
TypeWithBitfield b = {0};
|
|
||||||
b.v = 100;
|
|
||||||
b.w = 6;
|
|
||||||
b.x = 434512;
|
|
||||||
b.y = 7;
|
|
||||||
b.z = 12;
|
|
||||||
int x = (b.v + b.x);
|
|
||||||
int y = (b.y - b.z);
|
|
||||||
int z = (b.w) + 5;
|
|
||||||
BitfieldType64 b64 = {0};
|
|
||||||
b64.size = 524288;
|
|
||||||
b64.is_free = 1;
|
|
||||||
int abc = mut_xarray[0];
|
|
||||||
mut_xarray[0] += 1;
|
|
||||||
abc += mut_xarray[0];
|
|
||||||
abc += mut_xarray[1];
|
|
||||||
abc += mut_xarray[2];
|
|
||||||
float f = mut_farray[0] + mut_farray[1] + mut_farray[2] + mut_farray[3];
|
|
||||||
int w = 0;
|
|
||||||
}
|
|
||||||
@@ -1,10 +0,0 @@
|
|||||||
// Copyright (c) Epic Games Tools
|
|
||||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Program to run in debugger organized to provide tests for
|
|
||||||
* single threaded stepping, breakpoints, evaluation.
|
|
||||||
*/
|
|
||||||
|
|
||||||
void c_type_coverage_eval_tests(void);
|
|
||||||
void c_type_with_bitfield_usage(void);
|
|
||||||
@@ -1,64 +0,0 @@
|
|||||||
// Copyright (c) Epic Games Tools
|
|
||||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
|
||||||
|
|
||||||
/*
|
|
||||||
** Make sure we have an inlined function
|
|
||||||
*/
|
|
||||||
|
|
||||||
#if defined(_MSC_VER)
|
|
||||||
# define FORCE_INLINE __forceinline
|
|
||||||
#elif defined(__clang__) || defined(__GNUC__)
|
|
||||||
# define FORCE_INLINE __attribute__((always_inline))
|
|
||||||
#else
|
|
||||||
# error need force inline for this compiler
|
|
||||||
#endif
|
|
||||||
|
|
||||||
////////////////////////////////
|
|
||||||
// NOTE(allen): Inline Stepping
|
|
||||||
|
|
||||||
unsigned int fixed_frac_bits = 5;
|
|
||||||
static unsigned int bias = 7;
|
|
||||||
|
|
||||||
static FORCE_INLINE unsigned int
|
|
||||||
fixed_mul(unsigned int a, unsigned int b){
|
|
||||||
unsigned int c = (((a - bias)*(b - bias)) >> fixed_frac_bits) + bias;
|
|
||||||
return(c);
|
|
||||||
}
|
|
||||||
|
|
||||||
static FORCE_INLINE unsigned int
|
|
||||||
multi_file_inlinesite(unsigned int x){
|
|
||||||
// force compiler to generate annotations for code that's inside another file
|
|
||||||
#include "inline_body.cpp"
|
|
||||||
return x >> fixed_frac_bits;
|
|
||||||
}
|
|
||||||
|
|
||||||
static unsigned int test_value = 0;
|
|
||||||
|
|
||||||
unsigned int
|
|
||||||
inline_stepping_tests(void){
|
|
||||||
bias = 15;
|
|
||||||
|
|
||||||
// NOTE(nick): Interesting that CL does not generate inline site symbols in order of apperance here unlike clang.
|
|
||||||
|
|
||||||
// CL:
|
|
||||||
// BinaryAnnotations: CodeLengthAndCodeOffset d 0
|
|
||||||
// BinaryAnnotation Length: 4 bytes (1 bytes padding)
|
|
||||||
//
|
|
||||||
// Clang:
|
|
||||||
// BinaryAnnotations: LineOffset 1 CodeLength d
|
|
||||||
// BinaryAnnotation Length: 4 bytes (0 bytes padding)
|
|
||||||
unsigned int x = fixed_mul(5001, 7121);
|
|
||||||
|
|
||||||
// CL:
|
|
||||||
// BinaryAnnotations: CodeOffsetAndLineOffset d File 0 CodeOffsetAndLineOffset 22 LineOffset 1e
|
|
||||||
// CodeLengthAndCodeOffset 2 3
|
|
||||||
// BinaryAnnotation Length: 12 bytes (1 bytes padding)
|
|
||||||
//
|
|
||||||
// Clang:
|
|
||||||
// BinaryAnnotations: File 18 LineOffset ffffffe6 CodeOffset d CodeOffsetAndLineOffset 22
|
|
||||||
// File 0 LineOffset 1e CodeOffset 3 CodeLength 2
|
|
||||||
// BinaryAnnotation Length: 16 bytes (0 bytes padding)
|
|
||||||
unsigned int z = multi_file_inlinesite(x);
|
|
||||||
return(z);
|
|
||||||
}
|
|
||||||
|
|
||||||
File diff suppressed because it is too large
Load Diff
@@ -1,3 +0,0 @@
|
|||||||
version https://git-lfs.github.com/spec/v1
|
|
||||||
oid sha256:e2b10fe04ef539796a329790987f781e645707a737e32db863f3e49a1766bf5a
|
|
||||||
size 4763648
|
|
||||||
@@ -1,3 +0,0 @@
|
|||||||
version https://git-lfs.github.com/spec/v1
|
|
||||||
oid sha256:446e9b14f298e3824edccf61d857108d6100a3c1a3a5dcd7fa7d52fe5a1d6a8d
|
|
||||||
size 2768548
|
|
||||||
@@ -1,3 +0,0 @@
|
|||||||
version https://git-lfs.github.com/spec/v1
|
|
||||||
oid sha256:7ac765d8dfa6d3a3830b3efc76d8b52f6dd201004e9fead477138ac7b4d1015a
|
|
||||||
size 264704
|
|
||||||
@@ -1,60 +0,0 @@
|
|||||||
// Copyright (c) Epic Games Tools
|
|
||||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
|
||||||
|
|
||||||
#if _WIN32
|
|
||||||
#define export_function extern "C" __declspec(dllexport)
|
|
||||||
#else
|
|
||||||
#define export_function extern "C"
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#if _WIN32
|
|
||||||
# define thread_var __declspec(thread)
|
|
||||||
#else
|
|
||||||
# define thread_var __thread
|
|
||||||
#endif
|
|
||||||
|
|
||||||
typedef struct OnlyInModule OnlyInModule;
|
|
||||||
struct OnlyInModule
|
|
||||||
{
|
|
||||||
int x;
|
|
||||||
int y;
|
|
||||||
int z;
|
|
||||||
char *name;
|
|
||||||
};
|
|
||||||
|
|
||||||
typedef struct Basics Basics;
|
|
||||||
struct Basics
|
|
||||||
{
|
|
||||||
int a;
|
|
||||||
int b;
|
|
||||||
int c;
|
|
||||||
int d;
|
|
||||||
};
|
|
||||||
|
|
||||||
static OnlyInModule only_in_module_global =
|
|
||||||
{
|
|
||||||
1, 2, 3, "foobar",
|
|
||||||
};
|
|
||||||
|
|
||||||
thread_var float tls_a = 1.015625f;
|
|
||||||
thread_var int tls_b = -100;
|
|
||||||
|
|
||||||
export_function void
|
|
||||||
dll_tls_eval_test(void)
|
|
||||||
{
|
|
||||||
tls_a *= 1.5f;
|
|
||||||
tls_b *= -2;
|
|
||||||
only_in_module_global.x += 1;
|
|
||||||
only_in_module_global.y += 2;
|
|
||||||
only_in_module_global.z += 3;
|
|
||||||
}
|
|
||||||
|
|
||||||
export_function void
|
|
||||||
dll_type_eval_tests(void)
|
|
||||||
{
|
|
||||||
Basics basics1 = {1, 2, 3, 4};
|
|
||||||
Basics basics2 = {4, 5, 6, 7};
|
|
||||||
OnlyInModule only_in_module = {123, 456, 789, "this type is only in the module!"};
|
|
||||||
int x = 0;
|
|
||||||
(void)x;
|
|
||||||
}
|
|
||||||
Binary file not shown.
@@ -1,3 +0,0 @@
|
|||||||
version https://git-lfs.github.com/spec/v1
|
|
||||||
oid sha256:bc2f8b6f96c6bea013dbebcd6f6d84c0f015a361a62bf9158785687402b84311
|
|
||||||
size 6942720
|
|
||||||
@@ -1,3 +0,0 @@
|
|||||||
version https://git-lfs.github.com/spec/v1
|
|
||||||
oid sha256:73c47bf20d8d12057fa9e4d12873620f6c860b1bc5d4f831b4925f03e9f7c0b4
|
|
||||||
size 5518096
|
|
||||||
@@ -1,119 +0,0 @@
|
|||||||
// Copyright (c) Epic Games Tools
|
|
||||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
|
||||||
|
|
||||||
static int important_s32 = 0;
|
|
||||||
static float important_f32 = 0;
|
|
||||||
|
|
||||||
#if _WIN32
|
|
||||||
#include <Windows.h>
|
|
||||||
#endif
|
|
||||||
|
|
||||||
static void
|
|
||||||
do_something_with_intermediate_values(void)
|
|
||||||
{
|
|
||||||
static int another_important_s32 = 0;
|
|
||||||
static float another_important_f32 = 0;
|
|
||||||
|
|
||||||
another_important_s32 = (int)important_f32;
|
|
||||||
another_important_f32 = (float)important_s32;
|
|
||||||
|
|
||||||
#if _WIN32
|
|
||||||
char buffer[256] = "Hello, World!\n";
|
|
||||||
buffer[0] += important_s32 + another_important_s32;
|
|
||||||
buffer[1] += (int)another_important_f32 * important_f32;
|
|
||||||
OutputDebugStringA(buffer);
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
store_important_s32(int *ptr)
|
|
||||||
{
|
|
||||||
important_s32 = *ptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
store_important_f32(float *ptr)
|
|
||||||
{
|
|
||||||
important_f32 = *ptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
optimized_build_eval_tests(void)
|
|
||||||
{
|
|
||||||
int simple_sum = 0;
|
|
||||||
for(int i = 0; i < 10000; i += 1)
|
|
||||||
{
|
|
||||||
simple_sum += i;
|
|
||||||
}
|
|
||||||
store_important_s32(&simple_sum);
|
|
||||||
|
|
||||||
do_something_with_intermediate_values();
|
|
||||||
|
|
||||||
static struct {float x, y;} vec2s[] =
|
|
||||||
{
|
|
||||||
{ 10.f, 76.f },
|
|
||||||
{ 40.f, 50.f },
|
|
||||||
{ -230.f, 20.f },
|
|
||||||
{ 27.f, 27.f },
|
|
||||||
{ 57.f, -57.f },
|
|
||||||
{ -37.f, 97.f },
|
|
||||||
{ 99.f, 67.f },
|
|
||||||
{ 99.f, 37.f },
|
|
||||||
{ 99.f, 57.f },
|
|
||||||
};
|
|
||||||
{
|
|
||||||
struct{float x, y;}sum = {0};
|
|
||||||
int count = sizeof(vec2s)/sizeof(vec2s[0]);
|
|
||||||
for(int i = 0; i < count; i += 1)
|
|
||||||
{
|
|
||||||
sum.x += vec2s[i].x;
|
|
||||||
sum.y += vec2s[i].y;
|
|
||||||
}
|
|
||||||
struct{float x, y;}avg = {sum.x/count, sum.y/count};
|
|
||||||
float f32 = avg.x * avg.y;
|
|
||||||
store_important_f32(&f32);
|
|
||||||
}
|
|
||||||
|
|
||||||
do_something_with_intermediate_values();
|
|
||||||
|
|
||||||
int factorial = 1;
|
|
||||||
for(int i = 10; i > 0; i -= 1)
|
|
||||||
{
|
|
||||||
factorial *= i;
|
|
||||||
}
|
|
||||||
store_important_s32(&factorial);
|
|
||||||
|
|
||||||
do_something_with_intermediate_values();
|
|
||||||
}
|
|
||||||
|
|
||||||
////////////////////////////////
|
|
||||||
// NOTE(allen): Struct Parameters Eval
|
|
||||||
|
|
||||||
struct OptimizedBasics{
|
|
||||||
char a;
|
|
||||||
unsigned char b;
|
|
||||||
short c;
|
|
||||||
unsigned short d;
|
|
||||||
int e;
|
|
||||||
unsigned int f;
|
|
||||||
long long g;
|
|
||||||
unsigned long long h;
|
|
||||||
float i;
|
|
||||||
double j;
|
|
||||||
};
|
|
||||||
|
|
||||||
static void
|
|
||||||
optimized_struct_parameter_helper(int *ptr, OptimizedBasics basics)
|
|
||||||
{
|
|
||||||
basics.a += *ptr;
|
|
||||||
basics.a += 1;
|
|
||||||
basics.a += 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
optimized_struct_parameters_eval_tests(void)
|
|
||||||
{
|
|
||||||
int x = 10;
|
|
||||||
OptimizedBasics basics = {-1, 1, -2, 2, -4, 4, -8, 8, 1.5f, 1.50000000000001};
|
|
||||||
optimized_struct_parameter_helper(&x, basics);
|
|
||||||
}
|
|
||||||
@@ -930,6 +930,7 @@ d2r_convert(Arena *arena, D2R_ConvertParams *params)
|
|||||||
//- rjf: find all offsets of top-level tag trees across all units
|
//- rjf: find all offsets of top-level tag trees across all units
|
||||||
//
|
//
|
||||||
U64Array *unit_info_root_tag_offs = 0;
|
U64Array *unit_info_root_tag_offs = 0;
|
||||||
|
U64 *unit_tag_counts__first_pass = 0; // only includes roots + any descendants of roots who *don't* have a 'sibling' attribute
|
||||||
U64 total_root_tag_count = 0;
|
U64 total_root_tag_count = 0;
|
||||||
U64 *total_root_tag_count_ptr = &total_root_tag_count;
|
U64 *total_root_tag_count_ptr = &total_root_tag_count;
|
||||||
lane_sync_u64(&total_root_tag_count_ptr, 0);
|
lane_sync_u64(&total_root_tag_count_ptr, 0);
|
||||||
@@ -938,8 +939,10 @@ d2r_convert(Arena *arena, D2R_ConvertParams *params)
|
|||||||
if(lane_idx() == 0)
|
if(lane_idx() == 0)
|
||||||
{
|
{
|
||||||
unit_info_root_tag_offs = push_array(scratch.arena, U64Array, unit_count);
|
unit_info_root_tag_offs = push_array(scratch.arena, U64Array, unit_count);
|
||||||
|
unit_tag_counts__first_pass = push_array(scratch.arena, U64, unit_count);
|
||||||
}
|
}
|
||||||
lane_sync_u64(&unit_info_root_tag_offs, 0);
|
lane_sync_u64(&unit_info_root_tag_offs, 0);
|
||||||
|
lane_sync_u64(&unit_tag_counts__first_pass, 0);
|
||||||
typedef struct D2R_UnitTagTreeOffChunkNode D2R_UnitTagTreeOffChunkNode;
|
typedef struct D2R_UnitTagTreeOffChunkNode D2R_UnitTagTreeOffChunkNode;
|
||||||
struct D2R_UnitTagTreeOffChunkNode
|
struct D2R_UnitTagTreeOffChunkNode
|
||||||
{
|
{
|
||||||
@@ -1001,6 +1004,7 @@ d2r_convert(Arena *arena, D2R_ConvertParams *params)
|
|||||||
//- rjf: reading the next tag
|
//- rjf: reading the next tag
|
||||||
DW2_Tag tag = {0};
|
DW2_Tag tag = {0};
|
||||||
off += dw2_read_tag(scratch3.arena, raw, unit_parse_ctx, raw->sec[DW_SectionKind_Info].data, off, &tag);
|
off += dw2_read_tag(scratch3.arena, raw, unit_parse_ctx, raw->sec[DW_SectionKind_Info].data, off, &tag);
|
||||||
|
unit_tag_counts__first_pass[unit_idx] += 1;
|
||||||
|
|
||||||
//- rjf: look for sibling attribute fast path
|
//- rjf: look for sibling attribute fast path
|
||||||
DW2_Attrib *sibling_attrib = dw2_attrib_from_kind(&tag, DW_AttribKind_Sibling);
|
DW2_Attrib *sibling_attrib = dw2_attrib_from_kind(&tag, DW_AttribKind_Sibling);
|
||||||
@@ -1104,6 +1108,190 @@ d2r_convert(Arena *arena, D2R_ConvertParams *params)
|
|||||||
lane_sync_u64(&sub_unit_works_count, 0);
|
lane_sync_u64(&sub_unit_works_count, 0);
|
||||||
lane_sync_u64(&sub_unit_works, 0);
|
lane_sync_u64(&sub_unit_works, 0);
|
||||||
|
|
||||||
|
////////////////////////////
|
||||||
|
//- rjf: predict the total number of tags in all units
|
||||||
|
//
|
||||||
|
U64 total_tag_count_estimate = 1;
|
||||||
|
{
|
||||||
|
U64 tag_size_estimate = 32;
|
||||||
|
for EachIndex(unit_idx, unit_count)
|
||||||
|
{
|
||||||
|
total_tag_count_estimate += dim_1u64(unit_info_tag_ranges[unit_idx]) / tag_size_estimate;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////
|
||||||
|
//- rjf: hash all tags / attributes related to type info in all works,
|
||||||
|
// for combining into type content hashes later. type content hashes
|
||||||
|
// require combining a tree of several tag hashes - this just does the
|
||||||
|
// tag hash portion.
|
||||||
|
//
|
||||||
|
// record into (off -> hash) map.
|
||||||
|
//
|
||||||
|
U64 tag_hash_slots_count = total_tag_count_estimate/8 + 1;
|
||||||
|
D2R_TagHashNode **tag_hash_slots = 0;
|
||||||
|
if(lane_idx() == 0)
|
||||||
|
{
|
||||||
|
tag_hash_slots = push_array(scratch.arena, D2R_TagHashNode *, tag_hash_slots_count);
|
||||||
|
}
|
||||||
|
lane_sync_u64(&tag_hash_slots, 0);
|
||||||
|
ProfScope("hash all tags / attributes related to type info in all works, for combining into type content hashes later")
|
||||||
|
{
|
||||||
|
U64 work_take_idx_ = 0;
|
||||||
|
U64 *work_take_idx_ptr = &work_take_idx_;
|
||||||
|
lane_sync_u64(&work_take_idx_ptr, 0);
|
||||||
|
for(;;)
|
||||||
|
{
|
||||||
|
//- rjf: take next work
|
||||||
|
U64 work_idx = ins_atomic_u64_inc_eval(work_take_idx_ptr) - 1;
|
||||||
|
if(work_idx >= sub_unit_works_count)
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
ProfBegin("hash work");
|
||||||
|
|
||||||
|
//- rjf: unpack work
|
||||||
|
U64 unit_idx = sub_unit_works[work_idx].unit_idx;
|
||||||
|
Rng1U64 unit_root_tag_idx_range = sub_unit_works[work_idx].root_tag_idx_range;
|
||||||
|
|
||||||
|
//- rjf: unpack unit info
|
||||||
|
DW2_ParseCtx *unit_parse_ctx = &unit_parse_ctxs[unit_idx];
|
||||||
|
Rng1U64 unit_info_tag_range = unit_info_tag_ranges[unit_idx];
|
||||||
|
|
||||||
|
//- rjf: hash all relevant tags
|
||||||
|
for(U64 root_tag_idx = unit_root_tag_idx_range.min;
|
||||||
|
root_tag_idx < unit_root_tag_idx_range.max;
|
||||||
|
root_tag_idx += 1)
|
||||||
|
{
|
||||||
|
U64 root_tag_start_off = unit_info_root_tag_offs[unit_idx].v[root_tag_idx];
|
||||||
|
S64 depth = 0;
|
||||||
|
for(U64 off = root_tag_start_off; contains_1u64(unit_info_tag_range, off) && (depth > 0 || off == root_tag_start_off);)
|
||||||
|
{
|
||||||
|
Temp tag_scratch = scratch_begin(&scratch.arena, 1);
|
||||||
|
U64 start_off = off;
|
||||||
|
|
||||||
|
// rjf: read tag
|
||||||
|
DW2_Tag tag = {0};
|
||||||
|
off += dw2_read_tag(tag_scratch.arena, raw, unit_parse_ctx, raw->sec[DW_SectionKind_Info].data, off, &tag);
|
||||||
|
|
||||||
|
// rjf: determine if we need this tag's hash
|
||||||
|
B32 need_tag_hash = (tag.kind == DW_TagKind_ArrayType ||
|
||||||
|
tag.kind == DW_TagKind_ClassType ||
|
||||||
|
tag.kind == DW_TagKind_EnumerationType ||
|
||||||
|
tag.kind == DW_TagKind_PointerType ||
|
||||||
|
tag.kind == DW_TagKind_ReferenceType ||
|
||||||
|
tag.kind == DW_TagKind_StringType ||
|
||||||
|
tag.kind == DW_TagKind_StructureType ||
|
||||||
|
tag.kind == DW_TagKind_SubroutineType ||
|
||||||
|
tag.kind == DW_TagKind_SubProgram ||
|
||||||
|
tag.kind == DW_TagKind_Typedef ||
|
||||||
|
tag.kind == DW_TagKind_UnionType ||
|
||||||
|
tag.kind == DW_TagKind_PtrToMemberType ||
|
||||||
|
tag.kind == DW_TagKind_SetType ||
|
||||||
|
tag.kind == DW_TagKind_BaseType ||
|
||||||
|
tag.kind == DW_TagKind_ConstType ||
|
||||||
|
tag.kind == DW_TagKind_FileType ||
|
||||||
|
tag.kind == DW_TagKind_PackedType ||
|
||||||
|
tag.kind == DW_TagKind_VolatileType ||
|
||||||
|
tag.kind == DW_TagKind_RestrictType ||
|
||||||
|
tag.kind == DW_TagKind_InterfaceType ||
|
||||||
|
tag.kind == DW_TagKind_UnspecifiedType ||
|
||||||
|
tag.kind == DW_TagKind_SharedType ||
|
||||||
|
tag.kind == DW_TagKind_RValueReferenceType ||
|
||||||
|
tag.kind == DW_TagKind_CoarrayType ||
|
||||||
|
tag.kind == DW_TagKind_DynamicType ||
|
||||||
|
tag.kind == DW_TagKind_AtomicType ||
|
||||||
|
tag.kind == DW_TagKind_ImmutableType ||
|
||||||
|
tag.kind == DW_TagKind_Namespace);
|
||||||
|
|
||||||
|
// rjf: hash <:= tag kind
|
||||||
|
U64 hash = 0;
|
||||||
|
if(need_tag_hash)
|
||||||
|
{
|
||||||
|
hash = u64_hash_from_seed_str8(hash, str8_struct(&tag.kind));
|
||||||
|
}
|
||||||
|
|
||||||
|
// rjf: hash <:= non-reference attributes
|
||||||
|
if(need_tag_hash) for(DW2_AttribNode *n = tag.attribs.first; n != 0; n = n->next)
|
||||||
|
{
|
||||||
|
if(n->v.val.kind != DW_FormKind_RefAddr &&
|
||||||
|
n->v.val.kind != DW_FormKind_Ref1 &&
|
||||||
|
n->v.val.kind != DW_FormKind_Ref2 &&
|
||||||
|
n->v.val.kind != DW_FormKind_Ref4 &&
|
||||||
|
n->v.val.kind != DW_FormKind_Ref8 &&
|
||||||
|
n->v.val.kind != DW_FormKind_RefUData &&
|
||||||
|
n->v.val.kind != DW_FormKind_RefSup4 &&
|
||||||
|
n->v.val.kind != DW_FormKind_RefSig8 &&
|
||||||
|
((tag.kind != DW_TagKind_SubProgram &&
|
||||||
|
tag.kind != DW_TagKind_FormalParameter) ||
|
||||||
|
(n->v.attrib_kind != DW_AttribKind_Name &&
|
||||||
|
n->v.attrib_kind != DW_AttribKind_DeclFile &&
|
||||||
|
n->v.attrib_kind != DW_AttribKind_DeclLine &&
|
||||||
|
n->v.attrib_kind != DW_AttribKind_Prototyped &&
|
||||||
|
n->v.attrib_kind != DW_AttribKind_External &&
|
||||||
|
n->v.attrib_kind != DW_AttribKind_FrameBase &&
|
||||||
|
n->v.attrib_kind != DW_AttribKind_Location &&
|
||||||
|
n->v.attrib_kind != DW_AttribKind_LowPc &&
|
||||||
|
n->v.attrib_kind != DW_AttribKind_HighPc)))
|
||||||
|
{
|
||||||
|
hash = u64_hash_from_seed_str8(hash, str8_struct(&n->v.val.kind));
|
||||||
|
if(n->v.val.string.size != 0)
|
||||||
|
{
|
||||||
|
hash = u64_hash_from_seed_str8(hash, n->v.val.string);
|
||||||
|
}
|
||||||
|
else if(n->v.val.addr != 0)
|
||||||
|
{
|
||||||
|
hash = u64_hash_from_seed_str8(hash, str8_struct(&n->v.val.addr));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
hash = u64_hash_from_seed_str8(hash, str8_struct(&n->v.val.u128));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// rjf: store
|
||||||
|
if(need_tag_hash)
|
||||||
|
{
|
||||||
|
U64 off_hash = u64_hash_from_str8(str8_struct(&start_off));
|
||||||
|
U64 slot_idx = off_hash%tag_hash_slots_count;
|
||||||
|
D2R_TagHashNode *n = push_array(scratch.arena, D2R_TagHashNode, 1);
|
||||||
|
n->info_off = start_off;
|
||||||
|
n->hash = hash;
|
||||||
|
for(B32 inserted = 0; !inserted;)
|
||||||
|
{
|
||||||
|
U64 slot_head_val = (U64)ins_atomic_u64_eval(&tag_hash_slots[slot_idx]);
|
||||||
|
n->next = (D2R_TagHashNode *)slot_head_val;
|
||||||
|
if(slot_head_val == ins_atomic_u64_eval_cond_assign(&tag_hash_slots[slot_idx], (U64)n, slot_head_val))
|
||||||
|
{
|
||||||
|
inserted = 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// rjf: tree nav
|
||||||
|
if(tag.has_children)
|
||||||
|
{
|
||||||
|
depth += 1;
|
||||||
|
}
|
||||||
|
if(tag.kind == DW_TagKind_Null)
|
||||||
|
{
|
||||||
|
depth -= 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
scratch_end(tag_scratch);
|
||||||
|
if(off == start_off)
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ProfEnd();
|
||||||
|
}
|
||||||
|
lane_sync();
|
||||||
|
}
|
||||||
|
|
||||||
////////////////////////////
|
////////////////////////////
|
||||||
//- rjf: build built-in types
|
//- rjf: build built-in types
|
||||||
//
|
//
|
||||||
@@ -1128,18 +1316,6 @@ d2r_convert(Arena *arena, D2R_ConvertParams *params)
|
|||||||
lane_sync_u64(&builtin_type_from_kind_map, 0);
|
lane_sync_u64(&builtin_type_from_kind_map, 0);
|
||||||
#define d2r_type_from_builtin_kind(k) ((RDI_TypeKind_FirstBuiltIn <= (k) && (k) <= RDI_TypeKind_LastBuiltIn) ? builtin_type_from_kind_map[k - RDI_TypeKind_FirstBuiltIn] : builtin_type_from_kind_map[RDI_TypeKind_Void])
|
#define d2r_type_from_builtin_kind(k) ((RDI_TypeKind_FirstBuiltIn <= (k) && (k) <= RDI_TypeKind_LastBuiltIn) ? builtin_type_from_kind_map[k - RDI_TypeKind_FirstBuiltIn] : builtin_type_from_kind_map[RDI_TypeKind_Void])
|
||||||
|
|
||||||
////////////////////////////
|
|
||||||
//- rjf: predict the total number of tags in all units
|
|
||||||
//
|
|
||||||
U64 total_tag_count_estimate = 1;
|
|
||||||
{
|
|
||||||
U64 tag_size_estimate = 32;
|
|
||||||
for EachIndex(unit_idx, unit_count)
|
|
||||||
{
|
|
||||||
total_tag_count_estimate += dim_1u64(unit_info_tag_ranges[unit_idx]) / tag_size_estimate;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
////////////////////////////
|
////////////////////////////
|
||||||
//- rjf: gather all unique, to-be-deduplicated tags across all units (types, namespaces)
|
//- rjf: gather all unique, to-be-deduplicated tags across all units (types, namespaces)
|
||||||
//
|
//
|
||||||
@@ -1245,11 +1421,14 @@ d2r_convert(Arena *arena, D2R_ConvertParams *params)
|
|||||||
// functions are not deduplicated, and even if types defined
|
// functions are not deduplicated, and even if types defined
|
||||||
// within many functions match structurally, we consider them
|
// within many functions match structurally, we consider them
|
||||||
// unique, given that they have different definition sites &
|
// unique, given that they have different definition sites &
|
||||||
// names (fully qualified) still.
|
// names (fully qualified) still. (technically, if two UDTs
|
||||||
|
// match structurally, we could even dedup members - so two
|
||||||
|
// UDT records, w/ different decl sites/names/etc., but point
|
||||||
|
// at the same members)
|
||||||
//
|
//
|
||||||
// (2) namespaced by a type - we do *not* want to deduplicate. the
|
// (2) namespaced by a type - we *do* want to deduplicate. the
|
||||||
// root-level type will already be deduplicated, so we'll only
|
// root-level type will be deduplicated, but children are
|
||||||
// produce it once, and that'll catch all sub-types etc.
|
// fragmentary - see (3).
|
||||||
//
|
//
|
||||||
// (3) namespaced by a namespace - we *do* want to deduplicate. the
|
// (3) namespaced by a namespace - we *do* want to deduplicate. the
|
||||||
// children of a namespace are functionally top-level, and even
|
// children of a namespace are functionally top-level, and even
|
||||||
@@ -1257,8 +1436,12 @@ d2r_convert(Arena *arena, D2R_ConvertParams *params)
|
|||||||
// debug info for each unit will contain fragmentary parts of it,
|
// debug info for each unit will contain fragmentary parts of it,
|
||||||
// since presumably unused pieces of the namespace will be stripped.
|
// since presumably unused pieces of the namespace will be stripped.
|
||||||
// thus, we need to visit namespace children as if they're top-level.
|
// thus, we need to visit namespace children as if they're top-level.
|
||||||
|
//
|
||||||
B32 children_should_be_deduped = 0;
|
B32 children_should_be_deduped = 0;
|
||||||
if(tag.kind == DW_TagKind_Namespace)
|
if(tag.kind == DW_TagKind_Namespace ||
|
||||||
|
tag.kind == DW_TagKind_ClassType ||
|
||||||
|
tag.kind == DW_TagKind_StructureType ||
|
||||||
|
tag.kind == DW_TagKind_UnionType)
|
||||||
{
|
{
|
||||||
children_should_be_deduped = 1;
|
children_should_be_deduped = 1;
|
||||||
}
|
}
|
||||||
@@ -1381,7 +1564,10 @@ d2r_convert(Arena *arena, D2R_ConvertParams *params)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//- rjf: hash all tags we need to deduplicate & gather
|
//- rjf: produce tree hash for all tags we need to deduplicate & gather
|
||||||
|
//
|
||||||
|
// the tree hash is formed by combining the tag hashes for all dependency tags
|
||||||
|
//
|
||||||
U64 total_tag_count_this_work = 0;
|
U64 total_tag_count_this_work = 0;
|
||||||
for(D2R_TagNode *tag_n = first_tag_to_dedup; tag_n != 0; tag_n = tag_n->next)
|
for(D2R_TagNode *tag_n = first_tag_to_dedup; tag_n != 0; tag_n = tag_n->next)
|
||||||
{
|
{
|
||||||
@@ -1412,14 +1598,31 @@ d2r_convert(Arena *arena, D2R_ConvertParams *params)
|
|||||||
{
|
{
|
||||||
next = 0;
|
next = 0;
|
||||||
U64 t_off = t->off;
|
U64 t_off = t->off;
|
||||||
|
U64 off_hash = u64_hash_from_str8(str8_struct(&t->off));
|
||||||
|
|
||||||
// rjf: record this task in our seen task table
|
// rjf: record this task in our seen task table
|
||||||
{
|
{
|
||||||
U64 off_hash = u64_hash_from_str8(str8_struct(&t->off));
|
|
||||||
U64 slot_idx = off_hash%seen_task_slots_count;
|
U64 slot_idx = off_hash%seen_task_slots_count;
|
||||||
SLLStackPush(seen_task_slots[slot_idx], t);
|
SLLStackPush(seen_task_slots[slot_idx], t);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// rjf: find tag hash for this task
|
||||||
|
U64 tag_hash = 0;
|
||||||
|
{
|
||||||
|
U64 slot_idx = off_hash%tag_hash_slots_count;
|
||||||
|
for(D2R_TagHashNode *n = tag_hash_slots[slot_idx]; n != 0; n = n->next)
|
||||||
|
{
|
||||||
|
if(n->info_off == t_off)
|
||||||
|
{
|
||||||
|
tag_hash = n->hash;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// rjf: combine tag hash into tree hash
|
||||||
|
hash = u64_hash_from_seed_str8(hash, str8_struct(&tag_hash));
|
||||||
|
|
||||||
// rjf: unpack unit
|
// rjf: unpack unit
|
||||||
Rng1U64 unit_info_tag_range = unit_info_tag_ranges[t->unit_idx];
|
Rng1U64 unit_info_tag_range = unit_info_tag_ranges[t->unit_idx];
|
||||||
DW2_ParseCtx *unit_parse_ctx = &unit_parse_ctxs[t->unit_idx];
|
DW2_ParseCtx *unit_parse_ctx = &unit_parse_ctxs[t->unit_idx];
|
||||||
|
|||||||
@@ -4,6 +4,17 @@
|
|||||||
#ifndef RDI_FROM_DWARF_H
|
#ifndef RDI_FROM_DWARF_H
|
||||||
#define RDI_FROM_DWARF_H
|
#define RDI_FROM_DWARF_H
|
||||||
|
|
||||||
|
////////////////////////////////
|
||||||
|
//~ rjf: Tag Hash Cache Types
|
||||||
|
|
||||||
|
typedef struct D2R_TagHashNode D2R_TagHashNode;
|
||||||
|
struct D2R_TagHashNode
|
||||||
|
{
|
||||||
|
D2R_TagHashNode *next;
|
||||||
|
U64 info_off;
|
||||||
|
U64 hash;
|
||||||
|
};
|
||||||
|
|
||||||
////////////////////////////////
|
////////////////////////////////
|
||||||
//~ rjf: Unique Tag Tree Deduplication Types
|
//~ rjf: Unique Tag Tree Deduplication Types
|
||||||
|
|
||||||
|
|||||||
@@ -120,7 +120,7 @@ t_delete_dir(String8 path)
|
|||||||
|
|
||||||
if (info.props.flags & FilePropertyFlag_IsFolder) {
|
if (info.props.flags & FilePropertyFlag_IsFolder) {
|
||||||
t_delete_dir(str8f(scratch.arena, "%S/%S", path, info.name));
|
t_delete_dir(str8f(scratch.arena, "%S/%S", path, info.name));
|
||||||
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1254,7 +1254,7 @@ t_entry_point(CmdLine *cmdline)
|
|||||||
|
|
||||||
for EachIndex(i, target_indices.count) {
|
for EachIndex(i, target_indices.count) {
|
||||||
if (i == 0) { PrintHeader("Tests"); }
|
if (i == 0) { PrintHeader("Tests"); }
|
||||||
|
|
||||||
U64 target_idx = target_indices.v[i];
|
U64 target_idx = target_indices.v[i];
|
||||||
TestInfo *test = g_sorted_test_infos[target_idx];
|
TestInfo *test = g_sorted_test_infos[target_idx];
|
||||||
|
|
||||||
@@ -1279,7 +1279,7 @@ t_entry_point(CmdLine *cmdline)
|
|||||||
{
|
{
|
||||||
String8 binary_dir_path = get_process_info()->binary_path;
|
String8 binary_dir_path = get_process_info()->binary_path;
|
||||||
String8 root_dir_path = str8_chop_last_slash(binary_dir_path);
|
String8 root_dir_path = str8_chop_last_slash(binary_dir_path);
|
||||||
g_input_data_dir = str8f(scratch.arena, "%S/data/test_inputs", root_dir_path);
|
g_input_data_dir = str8f(scratch.arena, "%S/local/test_inputs", root_dir_path);
|
||||||
}
|
}
|
||||||
|
|
||||||
// setup output directory
|
// setup output directory
|
||||||
@@ -1392,10 +1392,10 @@ t_entry_point(CmdLine *cmdline)
|
|||||||
for EachElement(i, slowest) {
|
for EachElement(i, slowest) {
|
||||||
Slowest s = slowest[i];
|
Slowest s = slowest[i];
|
||||||
if (s.target_idx >= test_infos_count) { break; }
|
if (s.target_idx >= test_infos_count) { break; }
|
||||||
|
|
||||||
TestInfo *test_info = g_sorted_test_infos[s.target_idx];
|
TestInfo *test_info = g_sorted_test_infos[s.target_idx];
|
||||||
String8 elapsed_time = string_from_elapsed_time(scratch.arena, date_time_from_micro_seconds(s.d));
|
String8 elapsed_time = string_from_elapsed_time(scratch.arena, date_time_from_micro_seconds(s.d));
|
||||||
|
|
||||||
fprintf(stderr, " %.*s %.*s/ %.*s %.*s %.*s\n",
|
fprintf(stderr, " %.*s %.*s/ %.*s %.*s %.*s\n",
|
||||||
str8_varg(test_info->layer),
|
str8_varg(test_info->layer),
|
||||||
(int)(layer_max - test_info->layer.size), spaces,
|
(int)(layer_max - test_info->layer.size), spaces,
|
||||||
|
|||||||
Reference in New Issue
Block a user