Skip to content

Commit 62309a3

Browse files
Add Access Flags for DescriptorBinding
1 parent 3f46812 commit 62309a3

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

49 files changed

+302
-12
lines changed

common/output_stream.cpp

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -696,6 +696,28 @@ std::string ToStringDecorationFlags(
696696
return sstream.str();
697697
}
698698

699+
std::string ToStringAccessFlags(SpvReflectAccessFlags access_flags) {
700+
if (access_flags == SPV_REFLECT_ACCESS_NONE) {
701+
return "NONE";
702+
}
703+
704+
#define PRINT_AND_CLEAR_ACCESS_FLAG(stream, flags, bit) \
705+
if (((flags) & (SPV_REFLECT_ACCESS_##bit)) == (SPV_REFLECT_ACCESS_##bit)) { \
706+
stream << #bit << " "; \
707+
flags ^= SPV_REFLECT_ACCESS_##bit; \
708+
}
709+
std::stringstream sstream;
710+
PRINT_AND_CLEAR_ACCESS_FLAG(sstream, access_flags, READ);
711+
PRINT_AND_CLEAR_ACCESS_FLAG(sstream, access_flags, WRITE);
712+
PRINT_AND_CLEAR_ACCESS_FLAG(sstream, access_flags, ATOMIC);
713+
#undef PRINT_AND_CLEAR_ACCESS_FLAG
714+
if (access_flags != 0) {
715+
// Unhandled SpvReflectAccessFlags bit
716+
sstream << "???";
717+
}
718+
return sstream.str();
719+
}
720+
699721
std::string ToStringFormat(SpvReflectFormat fmt) {
700722
switch (fmt) {
701723
case SPV_REFLECT_FORMAT_UNDEFINED:
@@ -1921,6 +1943,9 @@ void SpvReflectToYaml::WriteDescriptorBinding(
19211943

19221944
// uint32_t accessed;
19231945
os << t1 << "accessed: " << db.accessed << std::endl;
1946+
// SpvReflectAccessFlags access_flags;
1947+
os << t1 << "access_flags: " << AsHexString(db.access_flags) << " # "
1948+
<< ToStringAccessFlags(db.access_flags) << std::endl;
19241949

19251950
// uint32_t uav_counter_id;
19261951
os << t1 << "uav_counter_id: " << db.uav_counter_id << std::endl;

spirv_reflect.c

Lines changed: 165 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -177,6 +177,22 @@ typedef struct SpvReflectPrvString {
177177
} SpvReflectPrvString;
178178
// clang-format on
179179

180+
// clang-format off
181+
// There are a limit set of instructions that can touch an OpVariable,
182+
// these are represented here with how it was accessed
183+
// Examples:
184+
// OpImageRead -> OpLoad -> OpVariable
185+
// OpImageWrite -> OpLoad -> OpVariable
186+
// OpStore -> OpAccessChain -> OpVariable
187+
// OpAtomicIAdd -> OpAccessChain -> OpVariable
188+
// OpAtomicLoad -> OpImageTexelPointer -> OpVariable
189+
typedef struct SpvReflectPrvAccessedVariable {
190+
uint32_t result_id;
191+
uint32_t variable_ptr;
192+
SpvReflectAccessFlags access_flags;
193+
} SpvReflectPrvAccessedVariable;
194+
// clang-format on
195+
180196
// clang-format off
181197
typedef struct SpvReflectPrvFunction {
182198
uint32_t id;
@@ -185,6 +201,8 @@ typedef struct SpvReflectPrvFunction {
185201
struct SpvReflectPrvFunction** callee_ptrs;
186202
uint32_t accessed_ptr_count;
187203
uint32_t* accessed_ptrs;
204+
uint32_t accessed_variable_ptr_count;
205+
SpvReflectPrvAccessedVariable* accessed_variable_ptrs;
188206
} SpvReflectPrvFunction;
189207
// clang-format on
190208

@@ -691,6 +709,7 @@ static void DestroyParser(SpvReflectPrvParser* p_parser)
691709
SafeFree(p_parser->functions[i].callees);
692710
SafeFree(p_parser->functions[i].callee_ptrs);
693711
SafeFree(p_parser->functions[i].accessed_ptrs);
712+
SafeFree(p_parser->functions[i].accessed_variable_ptrs);
694713
}
695714

696715
// Free access chains
@@ -1166,6 +1185,7 @@ static SpvReflectResult ParseFunction(
11661185
p_func->callee_count = 0;
11671186
p_func->accessed_ptr_count = 0;
11681187

1188+
// First get count to know how much to allocate
11691189
for (size_t i = first_label_index; i < p_parser->node_count; ++i) {
11701190
SpvReflectPrvNode* p_node = &(p_parser->nodes[i]);
11711191
if (p_node->op == SpvOpFunctionEnd) {
@@ -1213,10 +1233,17 @@ static SpvReflectResult ParseFunction(
12131233
if (IsNull(p_func->accessed_ptrs)) {
12141234
return SPV_REFLECT_RESULT_ERROR_ALLOC_FAILED;
12151235
}
1236+
1237+
p_func->accessed_variable_ptrs = (SpvReflectPrvAccessedVariable*)calloc(
1238+
p_func->accessed_ptr_count, sizeof(*(p_func->accessed_variable_ptrs)));
1239+
if (IsNull(p_func->accessed_variable_ptrs)) {
1240+
return SPV_REFLECT_RESULT_ERROR_ALLOC_FAILED;
1241+
}
12161242
}
12171243

12181244
p_func->callee_count = 0;
12191245
p_func->accessed_ptr_count = 0;
1246+
// Now have allocation, fill in values
12201247
for (size_t i = first_label_index; i < p_parser->node_count; ++i) {
12211248
SpvReflectPrvNode* p_node = &(p_parser->nodes[i]);
12221249
if (p_node->op == SpvOpFunctionEnd) {
@@ -1227,26 +1254,74 @@ static SpvReflectResult ParseFunction(
12271254
CHECKED_READU32(p_parser, p_node->word_offset + 3,
12281255
p_func->callees[p_func->callee_count]);
12291256
(++p_func->callee_count);
1230-
}
1231-
break;
1232-
case SpvOpLoad:
1257+
} break;
12331258
case SpvOpAccessChain:
12341259
case SpvOpInBoundsAccessChain:
12351260
case SpvOpPtrAccessChain:
12361261
case SpvOpArrayLength:
12371262
case SpvOpGenericPtrMemSemantics:
1238-
case SpvOpInBoundsPtrAccessChain:
1263+
case SpvOpInBoundsPtrAccessChain: {
1264+
CHECKED_READU32(p_parser, p_node->word_offset + 3,
1265+
p_func->accessed_ptrs[p_func->accessed_ptr_count]);
1266+
1267+
CHECKED_READU32(
1268+
p_parser, p_node->word_offset + 3,
1269+
p_func->accessed_variable_ptrs[p_func->accessed_ptr_count]
1270+
.variable_ptr);
1271+
// Need to track Result ID as not sure there has been any memory access
1272+
// through here yet
1273+
CHECKED_READU32(
1274+
p_parser, p_node->word_offset + 2,
1275+
p_func->accessed_variable_ptrs[p_func->accessed_ptr_count]
1276+
.result_id);
1277+
(++p_func->accessed_ptr_count);
1278+
} break;
1279+
case SpvOpLoad: {
1280+
CHECKED_READU32(p_parser, p_node->word_offset + 3,
1281+
p_func->accessed_ptrs[p_func->accessed_ptr_count]);
1282+
1283+
CHECKED_READU32(
1284+
p_parser, p_node->word_offset + 3,
1285+
p_func->accessed_variable_ptrs[p_func->accessed_ptr_count]
1286+
.variable_ptr);
1287+
CHECKED_READU32(
1288+
p_parser, p_node->word_offset + 2,
1289+
p_func->accessed_variable_ptrs[p_func->accessed_ptr_count]
1290+
.result_id);
1291+
p_func->accessed_variable_ptrs[p_func->accessed_ptr_count]
1292+
.access_flags = SPV_REFLECT_ACCESS_READ;
1293+
(++p_func->accessed_ptr_count);
1294+
} break;
12391295
case SpvOpImageTexelPointer:
12401296
{
12411297
CHECKED_READU32(p_parser, p_node->word_offset + 3,
12421298
p_func->accessed_ptrs[p_func->accessed_ptr_count]);
1299+
1300+
CHECKED_READU32(
1301+
p_parser, p_node->word_offset + 3,
1302+
p_func->accessed_variable_ptrs[p_func->accessed_ptr_count]
1303+
.variable_ptr);
1304+
CHECKED_READU32(
1305+
p_parser, p_node->word_offset + 2,
1306+
p_func->accessed_variable_ptrs[p_func->accessed_ptr_count]
1307+
.result_id);
1308+
p_func->accessed_variable_ptrs[p_func->accessed_ptr_count]
1309+
.access_flags = SPV_REFLECT_ACCESS_ATOMIC |
1310+
SPV_REFLECT_ACCESS_READ | SPV_REFLECT_ACCESS_WRITE;
12431311
(++p_func->accessed_ptr_count);
12441312
}
12451313
break;
12461314
case SpvOpStore:
12471315
{
12481316
CHECKED_READU32(p_parser, p_node->word_offset + 2,
12491317
p_func->accessed_ptrs[p_func->accessed_ptr_count]);
1318+
1319+
CHECKED_READU32(
1320+
p_parser, p_node->word_offset + 2,
1321+
p_func->accessed_variable_ptrs[p_func->accessed_ptr_count]
1322+
.variable_ptr);
1323+
p_func->accessed_variable_ptrs[p_func->accessed_ptr_count]
1324+
.access_flags = SPV_REFLECT_ACCESS_WRITE;
12501325
(++p_func->accessed_ptr_count);
12511326
}
12521327
break;
@@ -1265,6 +1340,66 @@ static SpvReflectResult ParseFunction(
12651340
}
12661341
}
12671342

1343+
// Apply the SpvReflectAccessFlags to all things touching an OpVariable
1344+
for (size_t i = first_label_index; i < p_parser->node_count; ++i) {
1345+
SpvReflectPrvNode* p_node = &(p_parser->nodes[i]);
1346+
if (p_node->op == SpvOpFunctionEnd) {
1347+
break;
1348+
}
1349+
// These are memory accesses instruction
1350+
uint32_t memory_access_ptr = 0;
1351+
SpvReflectAccessFlags memory_access_type = SPV_REFLECT_ACCESS_NONE;
1352+
switch (p_node->op) {
1353+
case SpvOpLoad: {
1354+
CHECKED_READU32(p_parser, p_node->word_offset + 3, memory_access_ptr);
1355+
memory_access_type = SPV_REFLECT_ACCESS_READ;
1356+
} break;
1357+
case SpvOpImageWrite:
1358+
case SpvOpStore: {
1359+
CHECKED_READU32(p_parser, p_node->word_offset + 1, memory_access_ptr);
1360+
memory_access_type = SPV_REFLECT_ACCESS_WRITE;
1361+
} break;
1362+
case SpvOpImageTexelPointer:
1363+
case SpvOpAtomicLoad:
1364+
case SpvOpAtomicExchange:
1365+
case SpvOpAtomicCompareExchange:
1366+
case SpvOpAtomicIIncrement:
1367+
case SpvOpAtomicIDecrement:
1368+
case SpvOpAtomicIAdd:
1369+
case SpvOpAtomicISub:
1370+
case SpvOpAtomicSMin:
1371+
case SpvOpAtomicUMin:
1372+
case SpvOpAtomicSMax:
1373+
case SpvOpAtomicUMax:
1374+
case SpvOpAtomicAnd:
1375+
case SpvOpAtomicOr:
1376+
case SpvOpAtomicXor:
1377+
case SpvOpAtomicFMinEXT:
1378+
case SpvOpAtomicFMaxEXT:
1379+
case SpvOpAtomicFAddEXT: {
1380+
CHECKED_READU32(p_parser, p_node->word_offset + 3, memory_access_ptr);
1381+
memory_access_type = SPV_REFLECT_ACCESS_ATOMIC |
1382+
SPV_REFLECT_ACCESS_READ | SPV_REFLECT_ACCESS_WRITE;
1383+
} break;
1384+
case SpvOpAtomicStore: {
1385+
CHECKED_READU32(p_parser, p_node->word_offset + 1, memory_access_ptr);
1386+
memory_access_type = SPV_REFLECT_ACCESS_ATOMIC |
1387+
SPV_REFLECT_ACCESS_READ | SPV_REFLECT_ACCESS_WRITE;
1388+
} break;
1389+
default:
1390+
break;
1391+
}
1392+
1393+
if (memory_access_ptr == 0) {
1394+
continue;
1395+
}
1396+
for (uint32_t k = 0; k < p_func->accessed_ptr_count; k++) {
1397+
if (p_func->accessed_variable_ptrs[k].result_id == memory_access_ptr) {
1398+
p_func->accessed_variable_ptrs[k].access_flags |= memory_access_type;
1399+
}
1400+
}
1401+
}
1402+
12681403
if (p_func->callee_count > 0) {
12691404
qsort(p_func->callees, p_func->callee_count,
12701405
sizeof(*(p_func->callees)), SortCompareUint32);
@@ -1276,6 +1411,7 @@ static SpvReflectResult ParseFunction(
12761411
qsort(p_func->accessed_ptrs, p_func->accessed_ptr_count,
12771412
sizeof(*(p_func->accessed_ptrs)), SortCompareUint32);
12781413
}
1414+
p_func->accessed_variable_ptr_count = p_func->accessed_ptr_count;
12791415
p_func->accessed_ptr_count = (uint32_t)DedupSortedUint32(p_func->accessed_ptrs,
12801416
p_func->accessed_ptr_count);
12811417

@@ -3323,24 +3459,35 @@ static SpvReflectResult ParseStaticallyUsedResources(
33233459
called_function_count = DedupSortedUint32(p_called_functions, called_function_count);
33243460

33253461
uint32_t used_variable_count = 0;
3462+
uint32_t used_acessed_count = 0;
33263463
for (size_t i = 0, j = 0; i < called_function_count; ++i) {
33273464
// No need to bounds check j because a missing ID issue would have been
33283465
// found during TraverseCallGraph
33293466
while (p_parser->functions[j].id != p_called_functions[i]) {
33303467
++j;
33313468
}
33323469
used_variable_count += p_parser->functions[j].accessed_ptr_count;
3470+
used_acessed_count += p_parser->functions[j].accessed_variable_ptr_count;
33333471
}
33343472
uint32_t* used_variables = NULL;
3473+
SpvReflectPrvAccessedVariable* used_accesses = NULL;
33353474
if (used_variable_count > 0) {
33363475
used_variables = (uint32_t*)calloc(used_variable_count,
33373476
sizeof(*used_variables));
33383477
if (IsNull(used_variables)) {
33393478
SafeFree(p_called_functions);
33403479
return SPV_REFLECT_RESULT_ERROR_ALLOC_FAILED;
33413480
}
3481+
3482+
used_accesses = (SpvReflectPrvAccessedVariable*)calloc(
3483+
used_acessed_count, sizeof(SpvReflectPrvAccessedVariable));
3484+
if (IsNull(used_accesses)) {
3485+
SafeFree(p_called_functions);
3486+
return SPV_REFLECT_RESULT_ERROR_ALLOC_FAILED;
3487+
}
33423488
}
33433489
used_variable_count = 0;
3490+
used_acessed_count = 0;
33443491
for (size_t i = 0, j = 0; i < called_function_count; ++i) {
33453492
while (p_parser->functions[j].id != p_called_functions[i]) {
33463493
++j;
@@ -3350,6 +3497,12 @@ static SpvReflectResult ParseStaticallyUsedResources(
33503497
p_parser->functions[j].accessed_ptrs,
33513498
p_parser->functions[j].accessed_ptr_count * sizeof(*used_variables));
33523499
used_variable_count += p_parser->functions[j].accessed_ptr_count;
3500+
3501+
memcpy(&used_accesses[used_acessed_count],
3502+
p_parser->functions[j].accessed_variable_ptrs,
3503+
p_parser->functions[j].accessed_variable_ptr_count *
3504+
sizeof(SpvReflectPrvAccessedVariable));
3505+
used_acessed_count += p_parser->functions[j].accessed_variable_ptr_count;
33533506
}
33543507
SafeFree(p_called_functions);
33553508

@@ -3381,18 +3534,18 @@ static SpvReflectResult ParseStaticallyUsedResources(
33813534
&p_entry->used_push_constants,
33823535
&used_push_constant_count);
33833536

3384-
for (uint32_t j = 0; j < p_module->descriptor_binding_count; ++j) {
3385-
SpvReflectDescriptorBinding* p_binding = &p_module->descriptor_bindings[j];
3386-
bool found = SearchSortedUint32(
3387-
used_variables,
3388-
used_variable_count,
3389-
p_binding->spirv_id);
3390-
if (found) {
3391-
p_binding->accessed = 1;
3537+
for (uint32_t i = 0; i < p_module->descriptor_binding_count; ++i) {
3538+
SpvReflectDescriptorBinding* p_binding = &p_module->descriptor_bindings[i];
3539+
for (uint32_t j = 0; j < used_acessed_count; j++) {
3540+
if (used_accesses[j].variable_ptr == p_binding->spirv_id) {
3541+
p_binding->accessed = 1;
3542+
p_binding->access_flags |= used_accesses[j].access_flags;
3543+
}
33923544
}
33933545
}
33943546

33953547
SafeFree(used_variables);
3548+
SafeFree(used_accesses);
33963549
if (result0 != SPV_REFLECT_RESULT_SUCCESS) {
33973550
return result0;
33983551
}

spirv_reflect.h

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -262,6 +262,22 @@ typedef enum SpvReflectShaderStageFlagBits {
262262

263263
} SpvReflectShaderStageFlagBits;
264264

265+
/*! @enum SpvReflectAccessBits
266+
267+
NOTE: A variable may be "accessed" but still have SPV_REFLECT_ACCESS_NONE
268+
Example is if there is a OpAccessChain, but then it is never used
269+
270+
*/
271+
typedef enum SpvReflectAccessFlagBits {
272+
SPV_REFLECT_ACCESS_NONE = 0x00000000,
273+
SPV_REFLECT_ACCESS_READ = 0x00000001,
274+
SPV_REFLECT_ACCESS_WRITE = 0x00000002,
275+
// Atomic will always also be marked as READ and WRITE
276+
SPV_REFLECT_ACCESS_ATOMIC = 0x00000004,
277+
} SpvReflectAccessFlagBits;
278+
279+
typedef uint32_t SpvReflectAccessFlags;
280+
265281
/*! @enum SpvReflectGenerator
266282
267283
*/
@@ -440,6 +456,7 @@ typedef struct SpvReflectDescriptorBinding {
440456
SpvReflectBindingArrayTraits array;
441457
uint32_t count;
442458
uint32_t accessed;
459+
SpvReflectAccessFlags access_flags;
443460
uint32_t uav_counter_id;
444461
struct SpvReflectDescriptorBinding* uav_counter_binding;
445462

tests/access_chains/array_length_from_access_chain.spv.yaml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -115,6 +115,7 @@ all_descriptor_bindings:
115115
block: *bv2 #
116116
array: { dims_count: 0, dims: [] }
117117
accessed: 1
118+
access_flags: 0x00000000 # NONE
118119
uav_counter_id: 4294967295
119120
uav_counter_binding:
120121
type_description: *td2

tests/cbuffer_unused/cbuffer_unused_001.spv.yaml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3309,6 +3309,7 @@ all_descriptor_bindings:
33093309
block: *bv63 # "MyParams"
33103310
array: { dims_count: 0, dims: [] }
33113311
accessed: 1
3312+
access_flags: 0x00000001 # READ
33123313
uav_counter_id: 4294967295
33133314
uav_counter_binding:
33143315
type_description: *td63
@@ -3325,6 +3326,7 @@ all_descriptor_bindings:
33253326
block: *bv95 # "MyParams2"
33263327
array: { dims_count: 0, dims: [] }
33273328
accessed: 1
3329+
access_flags: 0x00000001 # READ
33283330
uav_counter_id: 4294967295
33293331
uav_counter_binding:
33303332
type_description: *td95

tests/entry_exec_mode/comp_local_size.spv.yaml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,7 @@ all_descriptor_bindings:
8181
block: *bv1 # ""
8282
array: { dims_count: 0, dims: [] }
8383
accessed: 1
84+
access_flags: 0x00000003 # READ WRITE
8485
uav_counter_id: 4294967295
8586
uav_counter_binding:
8687
type_description: *td1

0 commit comments

Comments
 (0)