@@ -340,29 +340,92 @@ spv_result_t ValidateExecutionMode(ValidationState_t& _,
340
340
341
341
const auto mode = inst->GetOperandAs <spv::ExecutionMode>(1 );
342
342
if (inst->opcode () == spv::Op::OpExecutionModeId) {
343
+ bool valid_mode = false ;
344
+ switch (mode) {
345
+ case spv::ExecutionMode::SubgroupsPerWorkgroupId:
346
+ case spv::ExecutionMode::LocalSizeHintId:
347
+ case spv::ExecutionMode::LocalSizeId:
348
+ case spv::ExecutionMode::FPFastMathDefault:
349
+ valid_mode = true ;
350
+ break ;
351
+ default :
352
+ valid_mode = false ;
353
+ break ;
354
+ }
355
+ if (!valid_mode) {
356
+ return _.diag (SPV_ERROR_INVALID_ID, inst)
357
+ << " OpExecutionModeId is only valid when the Mode operand is an "
358
+ " execution mode that takes Extra Operands that are id "
359
+ " operands." ;
360
+ }
361
+
343
362
size_t operand_count = inst->operands ().size ();
344
363
for (size_t i = 2 ; i < operand_count; ++i) {
345
- const auto operand_id = inst->GetOperandAs <uint32_t >(2 );
364
+ const auto operand_id = inst->GetOperandAs <uint32_t >(i );
346
365
const auto * operand_inst = _.FindDef (operand_id);
347
- if (mode == spv::ExecutionMode::SubgroupsPerWorkgroupId ||
348
- mode == spv::ExecutionMode::LocalSizeHintId ||
349
- mode == spv::ExecutionMode::LocalSizeId) {
350
- if (!spvOpcodeIsConstant (operand_inst->opcode ())) {
351
- return _.diag (SPV_ERROR_INVALID_ID, inst)
352
- << " For OpExecutionModeId all Extra Operand ids must be "
353
- " constant "
354
- " instructions." ;
355
- }
356
- } else {
357
- return _.diag (SPV_ERROR_INVALID_ID, inst)
358
- << " OpExecutionModeId is only valid when the Mode operand is an "
359
- " execution mode that takes Extra Operands that are id "
360
- " operands." ;
366
+ switch (mode) {
367
+ case spv::ExecutionMode::SubgroupsPerWorkgroupId:
368
+ case spv::ExecutionMode::LocalSizeHintId:
369
+ case spv::ExecutionMode::LocalSizeId:
370
+ if (!spvOpcodeIsConstant (operand_inst->opcode ())) {
371
+ return _.diag (SPV_ERROR_INVALID_ID, inst)
372
+ << " For OpExecutionModeId all Extra Operand ids must be "
373
+ " constant instructions." ;
374
+ }
375
+ break ;
376
+ case spv::ExecutionMode::FPFastMathDefault:
377
+ if (i == 2 ) {
378
+ if (!_.IsFloatScalarType (operand_id)) {
379
+ return _.diag (SPV_ERROR_INVALID_ID, inst)
380
+ << " The Target Type operand must be a floating-point "
381
+ " scalar type" ;
382
+ }
383
+ } else {
384
+ bool is_int32 = false ;
385
+ bool is_const = false ;
386
+ uint32_t value = 0 ;
387
+ std::tie (is_int32, is_const, value) =
388
+ _.EvalInt32IfConst (operand_id);
389
+ if (is_int32 && is_const) {
390
+ // Valid values include up to 0x00040000 (AllowTransform).
391
+ uint32_t invalid_mask = 0xfff80000 ;
392
+ if ((invalid_mask & value) != 0 ) {
393
+ return _.diag (SPV_ERROR_INVALID_ID, inst)
394
+ << " The Fast Math Default operand is an invalid bitmask "
395
+ " value" ;
396
+ }
397
+ if (value &
398
+ static_cast <uint32_t >(spv::FPFastMathModeMask::Fast)) {
399
+ return _.diag (SPV_ERROR_INVALID_ID, inst)
400
+ << " The Fast Math Default operand must not include Fast" ;
401
+ }
402
+ const auto reassoc_contract =
403
+ spv::FPFastMathModeMask::AllowContract |
404
+ spv::FPFastMathModeMask::AllowReassoc;
405
+ if ((value & static_cast <uint32_t >(
406
+ spv::FPFastMathModeMask::AllowTransform)) != 0 &&
407
+ ((value & static_cast <uint32_t >(reassoc_contract)) !=
408
+ static_cast <uint32_t >(reassoc_contract))) {
409
+ return _.diag (SPV_ERROR_INVALID_ID, inst)
410
+ << " The Fast Math Default operand must include "
411
+ " AllowContract and AllowReassoc when AllowTransform "
412
+ " is specified" ;
413
+ }
414
+ } else {
415
+ return _.diag (SPV_ERROR_INVALID_ID, inst)
416
+ << " The Fast Math Default operand must be a "
417
+ " non-specialization constant" ;
418
+ }
419
+ }
420
+ break ;
421
+ default :
422
+ break ;
361
423
}
362
424
}
363
425
} else if (mode == spv::ExecutionMode::SubgroupsPerWorkgroupId ||
364
426
mode == spv::ExecutionMode::LocalSizeHintId ||
365
- mode == spv::ExecutionMode::LocalSizeId) {
427
+ mode == spv::ExecutionMode::LocalSizeId ||
428
+ mode == spv::ExecutionMode::FPFastMathDefault) {
366
429
return _.diag (SPV_ERROR_INVALID_DATA, inst)
367
430
<< " OpExecutionMode is only valid when the Mode operand is an "
368
431
" execution mode that takes no Extra Operands, or takes Extra "
@@ -579,6 +642,20 @@ spv_result_t ValidateExecutionMode(ValidationState_t& _,
579
642
break ;
580
643
}
581
644
645
+ if (mode == spv::ExecutionMode::FPFastMathDefault) {
646
+ const auto * modes = _.GetExecutionModes (entry_point_id);
647
+ if (modes && modes->count (spv::ExecutionMode::ContractionOff)) {
648
+ return _.diag (SPV_ERROR_INVALID_DATA, inst)
649
+ << " FPFastMathDefault and ContractionOff execution modes cannot "
650
+ " be applied to the same entry point" ;
651
+ }
652
+ if (modes && modes->count (spv::ExecutionMode::SignedZeroInfNanPreserve)) {
653
+ return _.diag (SPV_ERROR_INVALID_DATA, inst)
654
+ << " FPFastMathDefault and SignedZeroInfNanPreserve execution "
655
+ " modes cannot be applied to the same entry point" ;
656
+ }
657
+ }
658
+
582
659
if (spvIsVulkanEnv (_.context ()->target_env )) {
583
660
if (mode == spv::ExecutionMode::OriginLowerLeft) {
584
661
return _.diag (SPV_ERROR_INVALID_DATA, inst)
@@ -636,6 +713,70 @@ spv_result_t ValidateMemoryModel(ValidationState_t& _,
636
713
637
714
} // namespace
638
715
716
+ spv_result_t ValidateFloatControls2 (ValidationState_t& _) {
717
+ std::unordered_set<uint32_t > fp_fast_math_default_entry_points;
718
+ for (auto entry_point : _.entry_points ()) {
719
+ const auto * exec_modes = _.GetExecutionModes (entry_point);
720
+ if (exec_modes &&
721
+ exec_modes->count (spv::ExecutionMode::FPFastMathDefault)) {
722
+ fp_fast_math_default_entry_points.insert (entry_point);
723
+ }
724
+ }
725
+
726
+ std::vector<std::pair<const Instruction*, spv::Decoration>> worklist;
727
+ for (const auto & inst : _.ordered_instructions ()) {
728
+ if (inst.opcode () != spv::Op::OpDecorate) {
729
+ continue ;
730
+ }
731
+
732
+ const auto decoration = inst.GetOperandAs <spv::Decoration>(1 );
733
+ const auto target_id = inst.GetOperandAs <uint32_t >(0 );
734
+ const auto target = _.FindDef (target_id);
735
+ if (decoration == spv::Decoration::NoContraction) {
736
+ worklist.push_back (std::make_pair (target, decoration));
737
+ } else if (decoration == spv::Decoration::FPFastMathMode) {
738
+ auto mask = inst.GetOperandAs <spv::FPFastMathModeMask>(2 );
739
+ if ((mask & spv::FPFastMathModeMask::Fast) !=
740
+ spv::FPFastMathModeMask::MaskNone) {
741
+ worklist.push_back (std::make_pair (target, decoration));
742
+ }
743
+ }
744
+ }
745
+
746
+ std::unordered_set<const Instruction*> visited;
747
+ while (!worklist.empty ()) {
748
+ const auto inst = worklist.back ().first ;
749
+ const auto decoration = worklist.back ().second ;
750
+ worklist.pop_back ();
751
+
752
+ if (!visited.insert (inst).second ) {
753
+ continue ;
754
+ }
755
+
756
+ const auto function = inst->function ();
757
+ if (function) {
758
+ const auto & entry_points = _.FunctionEntryPoints (function->id ());
759
+ for (auto entry_point : entry_points) {
760
+ if (fp_fast_math_default_entry_points.count (entry_point)) {
761
+ const std::string dec = decoration == spv::Decoration::NoContraction
762
+ ? " NoContraction"
763
+ : " FPFastMathMode Fast" ;
764
+ return _.diag (SPV_ERROR_INVALID_DATA, inst)
765
+ << dec
766
+ << " cannot be used by an entry point with the "
767
+ " FPFastMathDefault execution mode" ;
768
+ }
769
+ }
770
+ } else {
771
+ for (const auto & pair : inst->uses ()) {
772
+ worklist.push_back (std::make_pair (pair.first , decoration));
773
+ }
774
+ }
775
+ }
776
+
777
+ return SPV_SUCCESS;
778
+ }
779
+
639
780
spv_result_t ModeSettingPass (ValidationState_t& _, const Instruction* inst) {
640
781
switch (inst->opcode ()) {
641
782
case spv::Op::OpEntryPoint:
0 commit comments