Skip to content

Commit 0a9a11a

Browse files
Add Access Flags for DescriptorBinding
1 parent 764da20 commit 0a9a11a

Some content is hidden

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

48 files changed

+299
-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: 162 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

@@ -685,6 +703,7 @@ static void DestroyParser(SpvReflectPrvParser* p_parser)
685703
SafeFree(p_parser->functions[i].callees);
686704
SafeFree(p_parser->functions[i].callee_ptrs);
687705
SafeFree(p_parser->functions[i].accessed_ptrs);
706+
SafeFree(p_parser->functions[i].accessed_variable_ptrs);
688707
}
689708

690709
// Free access chains
@@ -1160,6 +1179,7 @@ static SpvReflectResult ParseFunction(
11601179
p_func->callee_count = 0;
11611180
p_func->accessed_ptr_count = 0;
11621181

1182+
// First get count to know how much to allocate
11631183
for (size_t i = first_label_index; i < p_parser->node_count; ++i) {
11641184
SpvReflectPrvNode* p_node = &(p_parser->nodes[i]);
11651185
if (p_node->op == SpvOpFunctionEnd) {
@@ -1207,10 +1227,17 @@ static SpvReflectResult ParseFunction(
12071227
if (IsNull(p_func->accessed_ptrs)) {
12081228
return SPV_REFLECT_RESULT_ERROR_ALLOC_FAILED;
12091229
}
1230+
1231+
p_func->accessed_variable_ptrs = (SpvReflectPrvAccessedVariable*)calloc(
1232+
p_func->accessed_ptr_count, sizeof(*(p_func->accessed_variable_ptrs)));
1233+
if (IsNull(p_func->accessed_variable_ptrs)) {
1234+
return SPV_REFLECT_RESULT_ERROR_ALLOC_FAILED;
1235+
}
12101236
}
12111237

12121238
p_func->callee_count = 0;
12131239
p_func->accessed_ptr_count = 0;
1240+
// Now have allocation, fill in values
12141241
for (size_t i = first_label_index; i < p_parser->node_count; ++i) {
12151242
SpvReflectPrvNode* p_node = &(p_parser->nodes[i]);
12161243
if (p_node->op == SpvOpFunctionEnd) {
@@ -1221,26 +1248,73 @@ static SpvReflectResult ParseFunction(
12211248
CHECKED_READU32(p_parser, p_node->word_offset + 3,
12221249
p_func->callees[p_func->callee_count]);
12231250
(++p_func->callee_count);
1224-
}
1225-
break;
1226-
case SpvOpLoad:
1251+
} break;
12271252
case SpvOpAccessChain:
12281253
case SpvOpInBoundsAccessChain:
12291254
case SpvOpPtrAccessChain:
12301255
case SpvOpArrayLength:
12311256
case SpvOpGenericPtrMemSemantics:
1232-
case SpvOpInBoundsPtrAccessChain:
1257+
case SpvOpInBoundsPtrAccessChain: {
1258+
CHECKED_READU32(p_parser, p_node->word_offset + 3,
1259+
p_func->accessed_ptrs[p_func->accessed_ptr_count]);
1260+
1261+
CHECKED_READU32(
1262+
p_parser, p_node->word_offset + 3,
1263+
p_func->accessed_variable_ptrs[p_func->accessed_ptr_count]
1264+
.variable_ptr);
1265+
// Need to track Result ID as not sure there has been any memory access
1266+
// through here yet
1267+
CHECKED_READU32(
1268+
p_parser, p_node->word_offset + 2,
1269+
p_func->accessed_variable_ptrs[p_func->accessed_ptr_count]
1270+
.result_id);
1271+
(++p_func->accessed_ptr_count);
1272+
} break;
1273+
case SpvOpLoad: {
1274+
CHECKED_READU32(p_parser, p_node->word_offset + 3,
1275+
p_func->accessed_ptrs[p_func->accessed_ptr_count]);
1276+
1277+
CHECKED_READU32(
1278+
p_parser, p_node->word_offset + 3,
1279+
p_func->accessed_variable_ptrs[p_func->accessed_ptr_count]
1280+
.variable_ptr);
1281+
CHECKED_READU32(
1282+
p_parser, p_node->word_offset + 2,
1283+
p_func->accessed_variable_ptrs[p_func->accessed_ptr_count]
1284+
.result_id);
1285+
p_func->accessed_variable_ptrs[p_func->accessed_ptr_count]
1286+
.access_flags = SPV_REFLECT_ACCESS_READ;
1287+
(++p_func->accessed_ptr_count);
1288+
} break;
12331289
case SpvOpImageTexelPointer:
12341290
{
12351291
CHECKED_READU32(p_parser, p_node->word_offset + 3,
12361292
p_func->accessed_ptrs[p_func->accessed_ptr_count]);
1293+
1294+
CHECKED_READU32(
1295+
p_parser, p_node->word_offset + 3,
1296+
p_func->accessed_variable_ptrs[p_func->accessed_ptr_count]
1297+
.variable_ptr);
1298+
CHECKED_READU32(
1299+
p_parser, p_node->word_offset + 2,
1300+
p_func->accessed_variable_ptrs[p_func->accessed_ptr_count]
1301+
.result_id);
1302+
p_func->accessed_variable_ptrs[p_func->accessed_ptr_count]
1303+
.access_flags = SPV_REFLECT_ACCESS_ATOMIC;
12371304
(++p_func->accessed_ptr_count);
12381305
}
12391306
break;
12401307
case SpvOpStore:
12411308
{
12421309
CHECKED_READU32(p_parser, p_node->word_offset + 2,
12431310
p_func->accessed_ptrs[p_func->accessed_ptr_count]);
1311+
1312+
CHECKED_READU32(
1313+
p_parser, p_node->word_offset + 2,
1314+
p_func->accessed_variable_ptrs[p_func->accessed_ptr_count]
1315+
.variable_ptr);
1316+
p_func->accessed_variable_ptrs[p_func->accessed_ptr_count]
1317+
.access_flags = SPV_REFLECT_ACCESS_WRITE;
12441318
(++p_func->accessed_ptr_count);
12451319
}
12461320
break;
@@ -1259,6 +1333,64 @@ static SpvReflectResult ParseFunction(
12591333
}
12601334
}
12611335

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

@@ -3317,24 +3450,35 @@ static SpvReflectResult ParseStaticallyUsedResources(
33173450
called_function_count = DedupSortedUint32(p_called_functions, called_function_count);
33183451

33193452
uint32_t used_variable_count = 0;
3453+
uint32_t used_acessed_count = 0;
33203454
for (size_t i = 0, j = 0; i < called_function_count; ++i) {
33213455
// No need to bounds check j because a missing ID issue would have been
33223456
// found during TraverseCallGraph
33233457
while (p_parser->functions[j].id != p_called_functions[i]) {
33243458
++j;
33253459
}
33263460
used_variable_count += p_parser->functions[j].accessed_ptr_count;
3461+
used_acessed_count += p_parser->functions[j].accessed_variable_ptr_count;
33273462
}
33283463
uint32_t* used_variables = NULL;
3464+
SpvReflectPrvAccessedVariable* used_accesses = NULL;
33293465
if (used_variable_count > 0) {
33303466
used_variables = (uint32_t*)calloc(used_variable_count,
33313467
sizeof(*used_variables));
33323468
if (IsNull(used_variables)) {
33333469
SafeFree(p_called_functions);
33343470
return SPV_REFLECT_RESULT_ERROR_ALLOC_FAILED;
33353471
}
3472+
3473+
used_accesses = (SpvReflectPrvAccessedVariable*)calloc(
3474+
used_acessed_count, sizeof(SpvReflectPrvAccessedVariable));
3475+
if (IsNull(used_accesses)) {
3476+
SafeFree(p_called_functions);
3477+
return SPV_REFLECT_RESULT_ERROR_ALLOC_FAILED;
3478+
}
33363479
}
33373480
used_variable_count = 0;
3481+
used_acessed_count = 0;
33383482
for (size_t i = 0, j = 0; i < called_function_count; ++i) {
33393483
while (p_parser->functions[j].id != p_called_functions[i]) {
33403484
++j;
@@ -3344,6 +3488,12 @@ static SpvReflectResult ParseStaticallyUsedResources(
33443488
p_parser->functions[j].accessed_ptrs,
33453489
p_parser->functions[j].accessed_ptr_count * sizeof(*used_variables));
33463490
used_variable_count += p_parser->functions[j].accessed_ptr_count;
3491+
3492+
memcpy(&used_accesses[used_acessed_count],
3493+
p_parser->functions[j].accessed_variable_ptrs,
3494+
p_parser->functions[j].accessed_variable_ptr_count *
3495+
sizeof(SpvReflectPrvAccessedVariable));
3496+
used_acessed_count += p_parser->functions[j].accessed_variable_ptr_count;
33473497
}
33483498
SafeFree(p_called_functions);
33493499

@@ -3375,18 +3525,18 @@ static SpvReflectResult ParseStaticallyUsedResources(
33753525
&p_entry->used_push_constants,
33763526
&used_push_constant_count);
33773527

3378-
for (uint32_t j = 0; j < p_module->descriptor_binding_count; ++j) {
3379-
SpvReflectDescriptorBinding* p_binding = &p_module->descriptor_bindings[j];
3380-
bool found = SearchSortedUint32(
3381-
used_variables,
3382-
used_variable_count,
3383-
p_binding->spirv_id);
3384-
if (found) {
3385-
p_binding->accessed = 1;
3528+
for (uint32_t i = 0; i < p_module->descriptor_binding_count; ++i) {
3529+
SpvReflectDescriptorBinding* p_binding = &p_module->descriptor_bindings[i];
3530+
for (uint32_t j = 0; j < used_acessed_count; j++) {
3531+
if (used_accesses[j].variable_ptr == p_binding->spirv_id) {
3532+
p_binding->accessed = 1;
3533+
p_binding->access_flags |= used_accesses[j].access_flags;
3534+
}
33863535
}
33873536
}
33883537

33893538
SafeFree(used_variables);
3539+
SafeFree(used_accesses);
33903540
if (result0 != SPV_REFLECT_RESULT_SUCCESS) {
33913541
return result0;
33923542
}

spirv_reflect.h

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -262,6 +262,23 @@ 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+
// OpAtomicLoad/OpAtomicStore are only marked as ATOMIC
276+
// Operations in spec are defined as "load, store, and atomic"
277+
SPV_REFLECT_ACCESS_ATOMIC = 0x00000004,
278+
} SpvReflectAccessFlagBits;
279+
280+
typedef uint32_t SpvReflectAccessFlags;
281+
265282
/*! @enum SpvReflectGenerator
266283
267284
*/
@@ -440,6 +457,7 @@ typedef struct SpvReflectDescriptorBinding {
440457
SpvReflectBindingArrayTraits array;
441458
uint32_t count;
442459
uint32_t accessed;
460+
SpvReflectAccessFlags access_flags;
443461
uint32_t uav_counter_id;
444462
struct SpvReflectDescriptorBinding* uav_counter_binding;
445463

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)