SPV_EXT_physical_storage_buffer (#2267)
diff --git a/DEPS b/DEPS
index f7bac6d..5668c66 100644
--- a/DEPS
+++ b/DEPS
@@ -11,7 +11,7 @@
'googletest_revision': '98a0d007d7092b72eea0e501bb9ad17908a1a036',
'testing_revision': '340252637e2e7c72c0901dcbeeacfff419e19b59',
're2_revision': '6cf8ccd82dbaab2668e9b13596c68183c9ecd13f',
- 'spirv_headers_revision': 'd5b2e1255f706ce1f88812217e9a554f299848af',
+ 'spirv_headers_revision': '79b6681aadcb53c27d1052e5f8a0e82a981dbf2f',
}
deps = {
diff --git a/source/operand.cpp b/source/operand.cpp
index 923074e..00dc53d 100644
--- a/source/operand.cpp
+++ b/source/operand.cpp
@@ -481,6 +481,9 @@
case SpvOpTypeForwardPointer:
out = [](unsigned index) { return index == 0; };
break;
+ case SpvOpTypeArray:
+ out = [](unsigned index) { return index == 1; };
+ break;
default:
out = [](unsigned) { return false; };
break;
diff --git a/source/val/validate_atomics.cpp b/source/val/validate_atomics.cpp
index 6bfd06d..38c7053 100644
--- a/source/val/validate_atomics.cpp
+++ b/source/val/validate_atomics.cpp
@@ -127,6 +127,7 @@
case SpvStorageClassAtomicCounter:
case SpvStorageClassImage:
case SpvStorageClassStorageBuffer:
+ case SpvStorageClassPhysicalStorageBufferEXT:
break;
default:
if (spvIsOpenCLEnv(_.context()->target_env)) {
diff --git a/source/val/validate_conversion.cpp b/source/val/validate_conversion.cpp
index b51eec9..73da582 100644
--- a/source/val/validate_conversion.cpp
+++ b/source/val/validate_conversion.cpp
@@ -217,6 +217,23 @@
if (!_.IsPointerType(input_type))
return _.diag(SPV_ERROR_INVALID_DATA, inst)
<< "Expected input to be a pointer: " << spvOpcodeString(opcode);
+
+ if (_.addressing_model() == SpvAddressingModelLogical)
+ return _.diag(SPV_ERROR_INVALID_DATA, inst)
+ << "Logical addressing not supported: "
+ << spvOpcodeString(opcode);
+
+ if (_.addressing_model() ==
+ SpvAddressingModelPhysicalStorageBuffer64EXT) {
+ uint32_t input_storage_class = 0;
+ uint32_t input_data_type = 0;
+ _.GetPointerTypeInfo(input_type, &input_data_type,
+ &input_storage_class);
+ if (input_storage_class != SpvStorageClassPhysicalStorageBufferEXT)
+ return _.diag(SPV_ERROR_INVALID_DATA, inst)
+ << "Pointer storage class must be PhysicalStorageBufferEXT: "
+ << spvOpcodeString(opcode);
+ }
break;
}
@@ -251,6 +268,23 @@
if (!input_type || !_.IsIntScalarType(input_type))
return _.diag(SPV_ERROR_INVALID_DATA, inst)
<< "Expected int scalar as input: " << spvOpcodeString(opcode);
+
+ if (_.addressing_model() == SpvAddressingModelLogical)
+ return _.diag(SPV_ERROR_INVALID_DATA, inst)
+ << "Logical addressing not supported: "
+ << spvOpcodeString(opcode);
+
+ if (_.addressing_model() ==
+ SpvAddressingModelPhysicalStorageBuffer64EXT) {
+ uint32_t result_storage_class = 0;
+ uint32_t result_data_type = 0;
+ _.GetPointerTypeInfo(result_type, &result_data_type,
+ &result_storage_class);
+ if (result_storage_class != SpvStorageClassPhysicalStorageBufferEXT)
+ return _.diag(SPV_ERROR_INVALID_DATA, inst)
+ << "Pointer storage class must be PhysicalStorageBufferEXT: "
+ << spvOpcodeString(opcode);
+ }
break;
}
diff --git a/source/val/validate_decorations.cpp b/source/val/validate_decorations.cpp
index 582d11c..730b7ad 100644
--- a/source/val/validate_decorations.cpp
+++ b/source/val/validate_decorations.cpp
@@ -218,6 +218,9 @@
if (roundUp) baseAlignment = align(baseAlignment, 16u);
break;
}
+ case SpvOpTypePointer:
+ baseAlignment = vstate.pointer_size_and_alignment();
+ break;
default:
assert(0);
break;
@@ -254,6 +257,8 @@
}
return max_member_alignment;
} break;
+ case SpvOpTypePointer:
+ return vstate.pointer_size_and_alignment();
default:
assert(0);
break;
@@ -331,6 +336,8 @@
const auto& constraint = constraints[std::make_pair(lastMember, lastIdx)];
return offset + getSize(lastMember, constraint, constraints, vstate);
}
+ case SpvOpTypePointer:
+ return vstate.pointer_size_and_alignment();
default:
assert(0);
return 0;
@@ -847,7 +854,9 @@
}
}
- if (uniform || push_constant || storage_buffer) {
+ const bool phys_storage_buffer =
+ storageClass == SpvStorageClassPhysicalStorageBufferEXT;
+ if (uniform || push_constant || storage_buffer || phys_storage_buffer) {
const auto ptrInst = vstate.FindDef(words[1]);
assert(SpvOpTypePointer == ptrInst->opcode());
const auto id = ptrInst->words()[3];
@@ -899,9 +908,9 @@
const bool blockDeco = SpvDecorationBlock == dec.dec_type();
const bool bufferDeco = SpvDecorationBufferBlock == dec.dec_type();
const bool blockRules = uniform && blockDeco;
- const bool bufferRules = (uniform && bufferDeco) ||
- (push_constant && blockDeco) ||
- (storage_buffer && blockDeco);
+ const bool bufferRules =
+ (uniform && bufferDeco) || (push_constant && blockDeco) ||
+ ((storage_buffer || phys_storage_buffer) && blockDeco);
if (blockRules || bufferRules) {
const char* deco_str = blockDeco ? "Block" : "BufferBlock";
spv_result_t recursive_status = SPV_SUCCESS;
@@ -1127,12 +1136,13 @@
if (storage != SpvStorageClassStorageBuffer &&
storage != SpvStorageClassUniform &&
storage != SpvStorageClassPushConstant &&
- storage != SpvStorageClassInput && storage != SpvStorageClassOutput) {
+ storage != SpvStorageClassInput && storage != SpvStorageClassOutput &&
+ storage != SpvStorageClassPhysicalStorageBufferEXT) {
return vstate.diag(SPV_ERROR_INVALID_ID, &inst)
<< "FPRoundingMode decoration can be applied only to the "
"Object operand of an OpStore in the StorageBuffer, "
- "Uniform, PushConstant, Input, or Output Storage "
- "Classes.";
+ "PhysicalStorageBufferEXT, Uniform, PushConstant, Input, or "
+ "Output Storage Classes.";
}
}
return SPV_SUCCESS;
diff --git a/source/val/validate_function.cpp b/source/val/validate_function.cpp
index 39f00fe..de41b27 100644
--- a/source/val/validate_function.cpp
+++ b/source/val/validate_function.cpp
@@ -111,6 +111,79 @@
<< "' does not match the OpTypeFunction parameter "
"type of the same index.";
}
+
+ // Validate that PhysicalStorageBufferEXT have one of Restrict, Aliased,
+ // RestrictPointerEXT, or AliasedPointerEXT.
+ auto param_nonarray_type_id = param_type->id();
+ while (_.GetIdOpcode(param_nonarray_type_id) == SpvOpTypeArray) {
+ param_nonarray_type_id =
+ _.FindDef(param_nonarray_type_id)->GetOperandAs<uint32_t>(1u);
+ }
+ if (_.GetIdOpcode(param_nonarray_type_id) == SpvOpTypePointer) {
+ auto param_nonarray_type = _.FindDef(param_nonarray_type_id);
+ if (param_nonarray_type->GetOperandAs<uint32_t>(1u) ==
+ SpvStorageClassPhysicalStorageBufferEXT) {
+ // check for Aliased or Restrict
+ const auto& decorations = _.id_decorations(inst->id());
+
+ bool foundAliased = std::any_of(
+ decorations.begin(), decorations.end(), [](const Decoration& d) {
+ return SpvDecorationAliased == d.dec_type();
+ });
+
+ bool foundRestrict = std::any_of(
+ decorations.begin(), decorations.end(), [](const Decoration& d) {
+ return SpvDecorationRestrict == d.dec_type();
+ });
+
+ if (!foundAliased && !foundRestrict) {
+ return _.diag(SPV_ERROR_INVALID_ID, inst)
+ << "OpFunctionParameter " << inst->id()
+ << ": expected Aliased or Restrict for PhysicalStorageBufferEXT "
+ "pointer.";
+ }
+ if (foundAliased && foundRestrict) {
+ return _.diag(SPV_ERROR_INVALID_ID, inst)
+ << "OpFunctionParameter " << inst->id()
+ << ": can't specify both Aliased and Restrict for "
+ "PhysicalStorageBufferEXT pointer.";
+ }
+ } else {
+ const auto pointee_type_id =
+ param_nonarray_type->GetOperandAs<uint32_t>(2);
+ const auto pointee_type = _.FindDef(pointee_type_id);
+ if (SpvOpTypePointer == pointee_type->opcode() &&
+ pointee_type->GetOperandAs<uint32_t>(1u) ==
+ SpvStorageClassPhysicalStorageBufferEXT) {
+ // check for AliasedPointerEXT/RestrictPointerEXT
+ const auto& decorations = _.id_decorations(inst->id());
+
+ bool foundAliased = std::any_of(
+ decorations.begin(), decorations.end(), [](const Decoration& d) {
+ return SpvDecorationAliasedPointerEXT == d.dec_type();
+ });
+
+ bool foundRestrict = std::any_of(
+ decorations.begin(), decorations.end(), [](const Decoration& d) {
+ return SpvDecorationRestrictPointerEXT == d.dec_type();
+ });
+
+ if (!foundAliased && !foundRestrict) {
+ return _.diag(SPV_ERROR_INVALID_ID, inst)
+ << "OpFunctionParameter " << inst->id()
+ << ": expected AliasedPointerEXT or RestrictPointerEXT for "
+ "PhysicalStorageBufferEXT pointer.";
+ }
+ if (foundAliased && foundRestrict) {
+ return _.diag(SPV_ERROR_INVALID_ID, inst)
+ << "OpFunctionParameter " << inst->id()
+ << ": can't specify both AliasedPointerEXT and "
+ "RestrictPointerEXT for PhysicalStorageBufferEXT pointer.";
+ }
+ }
+ }
+ }
+
return SPV_SUCCESS;
}
diff --git a/source/val/validate_logicals.cpp b/source/val/validate_logicals.cpp
index 9c637c4..a25460b 100644
--- a/source/val/validate_logicals.cpp
+++ b/source/val/validate_logicals.cpp
@@ -154,7 +154,8 @@
const SpvOp type_opcode = type_inst->opcode();
switch (type_opcode) {
case SpvOpTypePointer: {
- if (!_.features().variable_pointers &&
+ if (_.addressing_model() == SpvAddressingModelLogical &&
+ !_.features().variable_pointers &&
!_.features().variable_pointers_storage_buffer)
return _.diag(SPV_ERROR_INVALID_DATA, inst)
<< "Using pointers with OpSelect requires capability "
diff --git a/source/val/validate_memory.cpp b/source/val/validate_memory.cpp
index d1a6442..3fe1085 100644
--- a/source/val/validate_memory.cpp
+++ b/source/val/validate_memory.cpp
@@ -277,7 +277,20 @@
}
spv_result_t CheckMemoryAccess(ValidationState_t& _, const Instruction* inst,
- uint32_t mask) {
+ uint32_t index) {
+ SpvStorageClass dst_sc, src_sc;
+ std::tie(dst_sc, src_sc) = GetStorageClass(_, inst);
+ if (inst->operands().size() <= index) {
+ if (src_sc == SpvStorageClassPhysicalStorageBufferEXT ||
+ dst_sc == SpvStorageClassPhysicalStorageBufferEXT) {
+ return _.diag(SPV_ERROR_INVALID_ID, inst) << "Memory accesses with "
+ "PhysicalStorageBufferEXT "
+ "must use Aligned.";
+ }
+ return SPV_SUCCESS;
+ }
+
+ uint32_t mask = inst->GetOperandAs<uint32_t>(index);
if (mask & SpvMemoryAccessMakePointerAvailableKHRMask) {
if (inst->opcode() == SpvOpLoad) {
return _.diag(SPV_ERROR_INVALID_ID, inst)
@@ -314,13 +327,12 @@
}
if (mask & SpvMemoryAccessNonPrivatePointerKHRMask) {
- SpvStorageClass dst_sc, src_sc;
- std::tie(dst_sc, src_sc) = GetStorageClass(_, inst);
if (dst_sc != SpvStorageClassUniform &&
dst_sc != SpvStorageClassWorkgroup &&
dst_sc != SpvStorageClassCrossWorkgroup &&
dst_sc != SpvStorageClassGeneric && dst_sc != SpvStorageClassImage &&
- dst_sc != SpvStorageClassStorageBuffer) {
+ dst_sc != SpvStorageClassStorageBuffer &&
+ dst_sc != SpvStorageClassPhysicalStorageBufferEXT) {
return _.diag(SPV_ERROR_INVALID_ID, inst)
<< "NonPrivatePointerKHR requires a pointer in Uniform, "
"Workgroup, CrossWorkgroup, Generic, Image or StorageBuffer "
@@ -330,7 +342,8 @@
src_sc != SpvStorageClassWorkgroup &&
src_sc != SpvStorageClassCrossWorkgroup &&
src_sc != SpvStorageClassGeneric && src_sc != SpvStorageClassImage &&
- src_sc != SpvStorageClassStorageBuffer) {
+ src_sc != SpvStorageClassStorageBuffer &&
+ src_sc != SpvStorageClassPhysicalStorageBufferEXT) {
return _.diag(SPV_ERROR_INVALID_ID, inst)
<< "NonPrivatePointerKHR requires a pointer in Uniform, "
"Workgroup, CrossWorkgroup, Generic, Image or StorageBuffer "
@@ -338,6 +351,15 @@
}
}
+ if (!(mask & SpvMemoryAccessAlignedMask)) {
+ if (src_sc == SpvStorageClassPhysicalStorageBufferEXT ||
+ dst_sc == SpvStorageClassPhysicalStorageBufferEXT) {
+ return _.diag(SPV_ERROR_INVALID_ID, inst) << "Memory accesses with "
+ "PhysicalStorageBufferEXT "
+ "must use Aligned.";
+ }
+ }
+
return SPV_SUCCESS;
}
@@ -414,7 +436,7 @@
}
// Variable pointer related restrictions.
- auto pointee = _.FindDef(result_type->word(3));
+ const auto pointee = _.FindDef(result_type->word(3));
if (_.addressing_model() == SpvAddressingModelLogical &&
!_.options()->relax_logical_pointer) {
// VariablePointersStorageBuffer is implied by VariablePointers.
@@ -507,6 +529,46 @@
}
}
+ if (storage_class == SpvStorageClassPhysicalStorageBufferEXT) {
+ return _.diag(SPV_ERROR_INVALID_ID, inst)
+ << "PhysicalStorageBufferEXT must not be used with OpVariable.";
+ }
+
+ auto pointee_base = pointee;
+ while (pointee_base->opcode() == SpvOpTypeArray) {
+ pointee_base = _.FindDef(pointee_base->GetOperandAs<uint32_t>(1u));
+ }
+ if (pointee_base->opcode() == SpvOpTypePointer) {
+ if (pointee_base->GetOperandAs<uint32_t>(1u) ==
+ SpvStorageClassPhysicalStorageBufferEXT) {
+ // check for AliasedPointerEXT/RestrictPointerEXT
+ const auto& decorations = _.id_decorations(inst->id());
+
+ bool foundAliased = std::any_of(
+ decorations.begin(), decorations.end(), [](const Decoration& d) {
+ return SpvDecorationAliasedPointerEXT == d.dec_type();
+ });
+
+ bool foundRestrict = std::any_of(
+ decorations.begin(), decorations.end(), [](const Decoration& d) {
+ return SpvDecorationRestrictPointerEXT == d.dec_type();
+ });
+
+ if (!foundAliased && !foundRestrict) {
+ return _.diag(SPV_ERROR_INVALID_ID, inst)
+ << "OpVariable " << inst->id()
+ << ": expected AliasedPointerEXT or RestrictPointerEXT for "
+ "PhysicalStorageBufferEXT pointer.";
+ }
+ if (foundAliased && foundRestrict) {
+ return _.diag(SPV_ERROR_INVALID_ID, inst)
+ << "OpVariable " << inst->id()
+ << ": can't specify both AliasedPointerEXT and "
+ "RestrictPointerEXT for PhysicalStorageBufferEXT pointer.";
+ }
+ }
+ }
+
return SPV_SUCCESS;
}
@@ -550,11 +612,7 @@
<< "'s type.";
}
- if (inst->operands().size() > 3) {
- if (auto error =
- CheckMemoryAccess(_, inst, inst->GetOperandAs<uint32_t>(3)))
- return error;
- }
+ if (auto error = CheckMemoryAccess(_, inst, 3)) return error;
return SPV_SUCCESS;
}
@@ -642,11 +700,7 @@
}
}
- if (inst->operands().size() > 2) {
- if (auto error =
- CheckMemoryAccess(_, inst, inst->GetOperandAs<uint32_t>(2)))
- return error;
- }
+ if (auto error = CheckMemoryAccess(_, inst, 2)) return error;
return SPV_SUCCESS;
}
@@ -710,11 +764,7 @@
<< _.getIdName(source_type->id()) << "'s type.";
}
- if (inst->operands().size() > 2) {
- if (auto error =
- CheckMemoryAccess(_, inst, inst->GetOperandAs<uint32_t>(2)))
- return error;
- }
+ if (auto error = CheckMemoryAccess(_, inst, 2)) return error;
} else {
const auto size_id = inst->GetOperandAs<uint32_t>(2);
const auto size = _.FindDef(size_id);
@@ -758,11 +808,7 @@
break;
}
- if (inst->operands().size() > 3) {
- if (auto error =
- CheckMemoryAccess(_, inst, inst->GetOperandAs<uint32_t>(3)))
- return error;
- }
+ if (auto error = CheckMemoryAccess(_, inst, 3)) return error;
}
return SPV_SUCCESS;
}
diff --git a/source/val/validation_state.cpp b/source/val/validation_state.cpp
index a10186f..a07cab9 100644
--- a/source/val/validation_state.cpp
+++ b/source/val/validation_state.cpp
@@ -171,6 +171,7 @@
grammar_(ctx),
addressing_model_(SpvAddressingModelMax),
memory_model_(SpvMemoryModelMax),
+ pointer_size_and_alignment_(0),
in_function_(false),
num_of_warnings_(0),
max_num_of_warnings_(max_warnings) {
@@ -435,6 +436,17 @@
void ValidationState_t::set_addressing_model(SpvAddressingModel am) {
addressing_model_ = am;
+ switch (am) {
+ case SpvAddressingModelPhysical32:
+ pointer_size_and_alignment_ = 4;
+ break;
+ default:
+ // fall through
+ case SpvAddressingModelPhysical64:
+ case SpvAddressingModelPhysicalStorageBuffer64EXT:
+ pointer_size_and_alignment_ = 8;
+ break;
+ }
}
SpvAddressingModel ValidationState_t::addressing_model() const {
diff --git a/source/val/validation_state.h b/source/val/validation_state.h
index 85229f2..f292aca 100644
--- a/source/val/validation_state.h
+++ b/source/val/validation_state.h
@@ -339,6 +339,11 @@
/// Returns the addressing model of this module, or Logical if uninitialized.
SpvAddressingModel addressing_model() const;
+ /// Returns the addressing model of this module, or Logical if uninitialized.
+ uint32_t pointer_size_and_alignment() const {
+ return pointer_size_and_alignment_;
+ }
+
/// Sets the memory model of this module.
void set_memory_model(SpvMemoryModel mm);
@@ -656,6 +661,9 @@
SpvAddressingModel addressing_model_;
SpvMemoryModel memory_model_;
+ // pointer size derived from addressing model. Assumes all storage classes
+ // have the same pointer size (for physical pointer types).
+ uint32_t pointer_size_and_alignment_;
/// NOTE: See correspoding getter functions
bool in_function_;
diff --git a/test/val/val_conversion_test.cpp b/test/val/val_conversion_test.cpp
index 4161c74..5e4ad49 100644
--- a/test/val/val_conversion_test.cpp
+++ b/test/val/val_conversion_test.cpp
@@ -1302,6 +1302,118 @@
"type"));
}
+TEST_F(ValidateConversion, ConvertUToPtrPSBSuccess) {
+ const std::string body = R"(
+OpCapability PhysicalStorageBufferAddressesEXT
+OpCapability Int64
+OpCapability Shader
+OpExtension "SPV_EXT_physical_storage_buffer"
+OpMemoryModel PhysicalStorageBuffer64EXT GLSL450
+OpEntryPoint Fragment %main "main"
+OpExecutionMode %main OriginUpperLeft
+%uint64 = OpTypeInt 64 0
+%u64_1 = OpConstant %uint64 1
+%ptr = OpTypePointer PhysicalStorageBufferEXT %uint64
+%void = OpTypeVoid
+%voidfn = OpTypeFunction %void
+%main = OpFunction %void None %voidfn
+%entry = OpLabel
+%val1 = OpConvertUToPtr %ptr %u64_1
+OpReturn
+OpFunctionEnd
+)";
+
+ CompileSuccessfully(body.c_str());
+ ASSERT_EQ(SPV_SUCCESS, ValidateInstructions());
+}
+
+TEST_F(ValidateConversion, ConvertUToPtrPSBStorageClass) {
+ const std::string body = R"(
+OpCapability PhysicalStorageBufferAddressesEXT
+OpCapability Int64
+OpCapability Shader
+OpExtension "SPV_EXT_physical_storage_buffer"
+OpMemoryModel PhysicalStorageBuffer64EXT GLSL450
+OpEntryPoint Fragment %main "main"
+OpExecutionMode %main OriginUpperLeft
+%uint64 = OpTypeInt 64 0
+%u64_1 = OpConstant %uint64 1
+%ptr = OpTypePointer Function %uint64
+%void = OpTypeVoid
+%voidfn = OpTypeFunction %void
+%main = OpFunction %void None %voidfn
+%entry = OpLabel
+%val1 = OpConvertUToPtr %ptr %u64_1
+%val2 = OpConvertPtrToU %uint64 %val1
+OpReturn
+OpFunctionEnd
+)";
+
+ CompileSuccessfully(body.c_str());
+ ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
+ EXPECT_THAT(getDiagnosticString(),
+ HasSubstr("Pointer storage class must be "
+ "PhysicalStorageBufferEXT: ConvertUToPtr"));
+}
+
+TEST_F(ValidateConversion, ConvertPtrToUPSBSuccess) {
+ const std::string body = R"(
+OpCapability PhysicalStorageBufferAddressesEXT
+OpCapability Int64
+OpCapability Shader
+OpExtension "SPV_EXT_physical_storage_buffer"
+OpMemoryModel PhysicalStorageBuffer64EXT GLSL450
+OpEntryPoint Fragment %main "main"
+OpExecutionMode %main OriginUpperLeft
+OpDecorate %val1 RestrictPointerEXT
+%uint64 = OpTypeInt 64 0
+%u64_1 = OpConstant %uint64 1
+%ptr = OpTypePointer PhysicalStorageBufferEXT %uint64
+%pptr_f = OpTypePointer Function %ptr
+%void = OpTypeVoid
+%voidfn = OpTypeFunction %void
+%main = OpFunction %void None %voidfn
+%entry = OpLabel
+%val1 = OpVariable %pptr_f Function
+%val2 = OpLoad %ptr %val1
+%val3 = OpConvertPtrToU %uint64 %val2
+OpReturn
+OpFunctionEnd
+)";
+
+ CompileSuccessfully(body.c_str());
+ ASSERT_EQ(SPV_SUCCESS, ValidateInstructions());
+}
+
+TEST_F(ValidateConversion, ConvertPtrToUPSBStorageClass) {
+ const std::string body = R"(
+OpCapability PhysicalStorageBufferAddressesEXT
+OpCapability Int64
+OpCapability Shader
+OpExtension "SPV_EXT_physical_storage_buffer"
+OpMemoryModel PhysicalStorageBuffer64EXT GLSL450
+OpEntryPoint Fragment %main "main"
+OpExecutionMode %main OriginUpperLeft
+%uint64 = OpTypeInt 64 0
+%u64_1 = OpConstant %uint64 1
+%ptr = OpTypePointer Function %uint64
+%void = OpTypeVoid
+%voidfn = OpTypeFunction %void
+%main = OpFunction %void None %voidfn
+%entry = OpLabel
+%val1 = OpVariable %ptr Function
+%val2 = OpConvertPtrToU %uint64 %val1
+OpReturn
+OpFunctionEnd
+)";
+
+ CompileSuccessfully(body.c_str());
+ ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
+ EXPECT_THAT(getDiagnosticString(),
+ HasSubstr("Pointer storage class must be "
+ "PhysicalStorageBufferEXT: ConvertPtrToU"));
+}
+
} // namespace
} // namespace val
} // namespace spvtools
diff --git a/test/val/val_decoration_test.cpp b/test/val/val_decoration_test.cpp
index 3a4320d..2f824c4 100644
--- a/test/val/val_decoration_test.cpp
+++ b/test/val/val_decoration_test.cpp
@@ -4345,11 +4345,11 @@
CompileSuccessfully(spirv);
EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateAndRetrieveValidationState());
- EXPECT_THAT(
- getDiagnosticString(),
- HasSubstr("FPRoundingMode decoration can be applied only to the "
- "Object operand of an OpStore in the StorageBuffer, Uniform, "
- "PushConstant, Input, or Output Storage Classes."));
+ EXPECT_THAT(getDiagnosticString(),
+ HasSubstr("FPRoundingMode decoration can be applied only to the "
+ "Object operand of an OpStore in the StorageBuffer, "
+ "PhysicalStorageBufferEXT, Uniform, "
+ "PushConstant, Input, or Output Storage Classes."));
}
TEST_F(ValidateDecorations, FPRoundingModeMultipleOpStoreGood) {
@@ -4810,6 +4810,223 @@
"ID '2' decorated with both BufferBlock and Block is not allowed."));
}
+TEST_F(ValidateDecorations, PSBAliasedRestrictPointerSuccess) {
+ const std::string body = R"(
+OpCapability PhysicalStorageBufferAddressesEXT
+OpCapability Int64
+OpCapability Shader
+OpExtension "SPV_EXT_physical_storage_buffer"
+OpMemoryModel PhysicalStorageBuffer64EXT GLSL450
+OpEntryPoint Fragment %main "main"
+OpExecutionMode %main OriginUpperLeft
+OpDecorate %val1 RestrictPointerEXT
+%uint64 = OpTypeInt 64 0
+%ptr = OpTypePointer PhysicalStorageBufferEXT %uint64
+%pptr_f = OpTypePointer Function %ptr
+%void = OpTypeVoid
+%voidfn = OpTypeFunction %void
+%main = OpFunction %void None %voidfn
+%entry = OpLabel
+%val1 = OpVariable %pptr_f Function
+OpReturn
+OpFunctionEnd
+)";
+
+ CompileSuccessfully(body.c_str());
+ ASSERT_EQ(SPV_SUCCESS, ValidateInstructions());
+}
+
+TEST_F(ValidateDecorations, PSBAliasedRestrictPointerMissing) {
+ const std::string body = R"(
+OpCapability PhysicalStorageBufferAddressesEXT
+OpCapability Int64
+OpCapability Shader
+OpExtension "SPV_EXT_physical_storage_buffer"
+OpMemoryModel PhysicalStorageBuffer64EXT GLSL450
+OpEntryPoint Fragment %main "main"
+OpExecutionMode %main OriginUpperLeft
+%uint64 = OpTypeInt 64 0
+%ptr = OpTypePointer PhysicalStorageBufferEXT %uint64
+%pptr_f = OpTypePointer Function %ptr
+%void = OpTypeVoid
+%voidfn = OpTypeFunction %void
+%main = OpFunction %void None %voidfn
+%entry = OpLabel
+%val1 = OpVariable %pptr_f Function
+OpReturn
+OpFunctionEnd
+)";
+
+ CompileSuccessfully(body.c_str());
+ ASSERT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions());
+ EXPECT_THAT(getDiagnosticString(),
+ HasSubstr("expected AliasedPointerEXT or RestrictPointerEXT for "
+ "PhysicalStorageBufferEXT pointer"));
+}
+
+TEST_F(ValidateDecorations, PSBAliasedRestrictPointerBoth) {
+ const std::string body = R"(
+OpCapability PhysicalStorageBufferAddressesEXT
+OpCapability Int64
+OpCapability Shader
+OpExtension "SPV_EXT_physical_storage_buffer"
+OpMemoryModel PhysicalStorageBuffer64EXT GLSL450
+OpEntryPoint Fragment %main "main"
+OpExecutionMode %main OriginUpperLeft
+OpDecorate %val1 RestrictPointerEXT
+OpDecorate %val1 AliasedPointerEXT
+%uint64 = OpTypeInt 64 0
+%ptr = OpTypePointer PhysicalStorageBufferEXT %uint64
+%pptr_f = OpTypePointer Function %ptr
+%void = OpTypeVoid
+%voidfn = OpTypeFunction %void
+%main = OpFunction %void None %voidfn
+%entry = OpLabel
+%val1 = OpVariable %pptr_f Function
+OpReturn
+OpFunctionEnd
+)";
+
+ CompileSuccessfully(body.c_str());
+ ASSERT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions());
+ EXPECT_THAT(
+ getDiagnosticString(),
+ HasSubstr("can't specify both AliasedPointerEXT and RestrictPointerEXT "
+ "for PhysicalStorageBufferEXT pointer"));
+}
+
+TEST_F(ValidateDecorations, PSBAliasedRestrictFunctionParamSuccess) {
+ const std::string body = R"(
+OpCapability PhysicalStorageBufferAddressesEXT
+OpCapability Int64
+OpCapability Shader
+OpExtension "SPV_EXT_physical_storage_buffer"
+OpMemoryModel PhysicalStorageBuffer64EXT GLSL450
+OpEntryPoint Fragment %main "main"
+OpExecutionMode %main OriginUpperLeft
+OpDecorate %fparam Restrict
+%uint64 = OpTypeInt 64 0
+%ptr = OpTypePointer PhysicalStorageBufferEXT %uint64
+%void = OpTypeVoid
+%voidfn = OpTypeFunction %void
+%fnptr = OpTypeFunction %void %ptr
+%main = OpFunction %void None %voidfn
+%entry = OpLabel
+OpReturn
+OpFunctionEnd
+%fn = OpFunction %void None %fnptr
+%fparam = OpFunctionParameter %ptr
+%lab = OpLabel
+OpReturn
+OpFunctionEnd
+)";
+
+ CompileSuccessfully(body.c_str());
+ ASSERT_EQ(SPV_SUCCESS, ValidateInstructions());
+}
+
+TEST_F(ValidateDecorations, PSBAliasedRestrictFunctionParamMissing) {
+ const std::string body = R"(
+OpCapability PhysicalStorageBufferAddressesEXT
+OpCapability Int64
+OpCapability Shader
+OpExtension "SPV_EXT_physical_storage_buffer"
+OpMemoryModel PhysicalStorageBuffer64EXT GLSL450
+OpEntryPoint Fragment %main "main"
+OpExecutionMode %main OriginUpperLeft
+%uint64 = OpTypeInt 64 0
+%ptr = OpTypePointer PhysicalStorageBufferEXT %uint64
+%void = OpTypeVoid
+%voidfn = OpTypeFunction %void
+%fnptr = OpTypeFunction %void %ptr
+%main = OpFunction %void None %voidfn
+%entry = OpLabel
+OpReturn
+OpFunctionEnd
+%fn = OpFunction %void None %fnptr
+%fparam = OpFunctionParameter %ptr
+%lab = OpLabel
+OpReturn
+OpFunctionEnd
+)";
+
+ CompileSuccessfully(body.c_str());
+ ASSERT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions());
+ EXPECT_THAT(
+ getDiagnosticString(),
+ HasSubstr(
+ "expected Aliased or Restrict for PhysicalStorageBufferEXT pointer"));
+}
+
+TEST_F(ValidateDecorations, PSBAliasedRestrictFunctionParamBoth) {
+ const std::string body = R"(
+OpCapability PhysicalStorageBufferAddressesEXT
+OpCapability Int64
+OpCapability Shader
+OpExtension "SPV_EXT_physical_storage_buffer"
+OpMemoryModel PhysicalStorageBuffer64EXT GLSL450
+OpEntryPoint Fragment %main "main"
+OpExecutionMode %main OriginUpperLeft
+OpDecorate %fparam Restrict
+OpDecorate %fparam Aliased
+%uint64 = OpTypeInt 64 0
+%ptr = OpTypePointer PhysicalStorageBufferEXT %uint64
+%void = OpTypeVoid
+%voidfn = OpTypeFunction %void
+%fnptr = OpTypeFunction %void %ptr
+%main = OpFunction %void None %voidfn
+%entry = OpLabel
+OpReturn
+OpFunctionEnd
+%fn = OpFunction %void None %fnptr
+%fparam = OpFunctionParameter %ptr
+%lab = OpLabel
+OpReturn
+OpFunctionEnd
+)";
+
+ CompileSuccessfully(body.c_str());
+ ASSERT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions());
+ EXPECT_THAT(getDiagnosticString(),
+ HasSubstr("can't specify both Aliased and Restrict for "
+ "PhysicalStorageBufferEXT pointer"));
+}
+
+TEST_F(ValidateDecorations, PSBFPRoundingModeSuccess) {
+ std::string spirv = R"(
+OpCapability PhysicalStorageBufferAddressesEXT
+OpCapability Shader
+OpCapability Linkage
+OpCapability StorageBuffer16BitAccess
+OpExtension "SPV_EXT_physical_storage_buffer"
+OpExtension "SPV_KHR_storage_buffer_storage_class"
+OpExtension "SPV_KHR_variable_pointers"
+OpExtension "SPV_KHR_16bit_storage"
+OpMemoryModel PhysicalStorageBuffer64EXT GLSL450
+OpEntryPoint GLCompute %main "main"
+OpDecorate %_ FPRoundingMode RTE
+OpDecorate %half_ptr_var AliasedPointerEXT
+%half = OpTypeFloat 16
+%float = OpTypeFloat 32
+%float_1_25 = OpConstant %float 1.25
+%half_ptr = OpTypePointer PhysicalStorageBufferEXT %half
+%half_pptr_f = OpTypePointer Function %half_ptr
+%void = OpTypeVoid
+%func = OpTypeFunction %void
+%main = OpFunction %void None %func
+%main_entry = OpLabel
+%half_ptr_var = OpVariable %half_pptr_f Function
+%val1 = OpLoad %half_ptr %half_ptr_var
+%_ = OpFConvert %half %float_1_25
+OpStore %val1 %_ Aligned 2
+OpReturn
+OpFunctionEnd
+ )";
+
+ CompileSuccessfully(spirv);
+ EXPECT_EQ(SPV_SUCCESS, ValidateAndRetrieveValidationState());
+}
+
} // namespace
} // namespace val
} // namespace spvtools
diff --git a/test/val/val_logicals_test.cpp b/test/val/val_logicals_test.cpp
index f457887..da8e7d9 100644
--- a/test/val/val_logicals_test.cpp
+++ b/test/val/val_logicals_test.cpp
@@ -919,6 +919,36 @@
"width: SGreaterThan"));
}
+TEST_F(ValidateLogicals, PSBSelectSuccess) {
+ const std::string body = R"(
+OpCapability PhysicalStorageBufferAddressesEXT
+OpCapability Int64
+OpCapability Shader
+OpExtension "SPV_EXT_physical_storage_buffer"
+OpMemoryModel PhysicalStorageBuffer64EXT GLSL450
+OpEntryPoint Fragment %main "main"
+OpExecutionMode %main OriginUpperLeft
+OpDecorate %val1 AliasedPointerEXT
+%uint64 = OpTypeInt 64 0
+%bool = OpTypeBool
+%true = OpConstantTrue %bool
+%ptr = OpTypePointer PhysicalStorageBufferEXT %uint64
+%pptr_f = OpTypePointer Function %ptr
+%void = OpTypeVoid
+%voidfn = OpTypeFunction %void
+%main = OpFunction %void None %voidfn
+%entry = OpLabel
+%val1 = OpVariable %pptr_f Function
+%val2 = OpLoad %ptr %val1
+%val3 = OpSelect %ptr %true %val2 %val2
+OpReturn
+OpFunctionEnd
+)";
+
+ CompileSuccessfully(body.c_str());
+ ASSERT_EQ(SPV_SUCCESS, ValidateInstructions());
+}
+
} // namespace
} // namespace val
} // namespace spvtools
diff --git a/test/val/val_memory_test.cpp b/test/val/val_memory_test.cpp
index a5e5f91..3e42496 100644
--- a/test/val/val_memory_test.cpp
+++ b/test/val/val_memory_test.cpp
@@ -1537,6 +1537,156 @@
HasSubstr("Operand 1[%incorrect] requires a type"));
}
+TEST_F(ValidateMemory, PSBLoadAlignedSuccess) {
+ const std::string body = R"(
+OpCapability PhysicalStorageBufferAddressesEXT
+OpCapability Int64
+OpCapability Shader
+OpExtension "SPV_EXT_physical_storage_buffer"
+OpMemoryModel PhysicalStorageBuffer64EXT GLSL450
+OpEntryPoint Fragment %main "main"
+OpExecutionMode %main OriginUpperLeft
+OpDecorate %val1 AliasedPointerEXT
+%uint64 = OpTypeInt 64 0
+%ptr = OpTypePointer PhysicalStorageBufferEXT %uint64
+%pptr_f = OpTypePointer Function %ptr
+%void = OpTypeVoid
+%voidfn = OpTypeFunction %void
+%main = OpFunction %void None %voidfn
+%entry = OpLabel
+%val1 = OpVariable %pptr_f Function
+%val2 = OpLoad %ptr %val1
+%val3 = OpLoad %uint64 %val2 Aligned 8
+OpReturn
+OpFunctionEnd
+)";
+
+ CompileSuccessfully(body.c_str());
+ ASSERT_EQ(SPV_SUCCESS, ValidateInstructions());
+}
+
+TEST_F(ValidateMemory, PSBLoadAlignedMissing) {
+ const std::string body = R"(
+OpCapability PhysicalStorageBufferAddressesEXT
+OpCapability Int64
+OpCapability Shader
+OpExtension "SPV_EXT_physical_storage_buffer"
+OpMemoryModel PhysicalStorageBuffer64EXT GLSL450
+OpEntryPoint Fragment %main "main"
+OpExecutionMode %main OriginUpperLeft
+OpDecorate %val1 AliasedPointerEXT
+%uint64 = OpTypeInt 64 0
+%ptr = OpTypePointer PhysicalStorageBufferEXT %uint64
+%pptr_f = OpTypePointer Function %ptr
+%void = OpTypeVoid
+%voidfn = OpTypeFunction %void
+%main = OpFunction %void None %voidfn
+%entry = OpLabel
+%val1 = OpVariable %pptr_f Function
+%val2 = OpLoad %ptr %val1
+%val3 = OpLoad %uint64 %val2
+OpReturn
+OpFunctionEnd
+)";
+
+ CompileSuccessfully(body.c_str());
+ ASSERT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions());
+ EXPECT_THAT(
+ getDiagnosticString(),
+ HasSubstr(
+ "Memory accesses with PhysicalStorageBufferEXT must use Aligned"));
+}
+
+TEST_F(ValidateMemory, PSBStoreAlignedSuccess) {
+ const std::string body = R"(
+OpCapability PhysicalStorageBufferAddressesEXT
+OpCapability Int64
+OpCapability Shader
+OpExtension "SPV_EXT_physical_storage_buffer"
+OpMemoryModel PhysicalStorageBuffer64EXT GLSL450
+OpEntryPoint Fragment %main "main"
+OpExecutionMode %main OriginUpperLeft
+OpDecorate %val1 AliasedPointerEXT
+%uint64 = OpTypeInt 64 0
+%u64_1 = OpConstant %uint64 1
+%ptr = OpTypePointer PhysicalStorageBufferEXT %uint64
+%pptr_f = OpTypePointer Function %ptr
+%void = OpTypeVoid
+%voidfn = OpTypeFunction %void
+%main = OpFunction %void None %voidfn
+%entry = OpLabel
+%val1 = OpVariable %pptr_f Function
+%val2 = OpLoad %ptr %val1
+OpStore %val2 %u64_1 Aligned 8
+OpReturn
+OpFunctionEnd
+)";
+
+ CompileSuccessfully(body.c_str());
+ ASSERT_EQ(SPV_SUCCESS, ValidateInstructions());
+}
+
+TEST_F(ValidateMemory, PSBStoreAlignedMissing) {
+ const std::string body = R"(
+OpCapability PhysicalStorageBufferAddressesEXT
+OpCapability Int64
+OpCapability Shader
+OpExtension "SPV_EXT_physical_storage_buffer"
+OpMemoryModel PhysicalStorageBuffer64EXT GLSL450
+OpEntryPoint Fragment %main "main"
+OpExecutionMode %main OriginUpperLeft
+OpDecorate %val1 AliasedPointerEXT
+%uint64 = OpTypeInt 64 0
+%u64_1 = OpConstant %uint64 1
+%ptr = OpTypePointer PhysicalStorageBufferEXT %uint64
+%pptr_f = OpTypePointer Function %ptr
+%void = OpTypeVoid
+%voidfn = OpTypeFunction %void
+%main = OpFunction %void None %voidfn
+%entry = OpLabel
+%val1 = OpVariable %pptr_f Function
+%val2 = OpLoad %ptr %val1
+OpStore %val2 %u64_1 None
+OpReturn
+OpFunctionEnd
+)";
+
+ CompileSuccessfully(body.c_str());
+ ASSERT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions());
+ EXPECT_THAT(
+ getDiagnosticString(),
+ HasSubstr(
+ "Memory accesses with PhysicalStorageBufferEXT must use Aligned"));
+}
+
+TEST_F(ValidateMemory, PSBVariable) {
+ const std::string body = R"(
+OpCapability PhysicalStorageBufferAddressesEXT
+OpCapability Int64
+OpCapability Shader
+OpExtension "SPV_EXT_physical_storage_buffer"
+OpMemoryModel PhysicalStorageBuffer64EXT GLSL450
+OpEntryPoint Fragment %main "main"
+OpExecutionMode %main OriginUpperLeft
+OpDecorate %val1 AliasedPointerEXT
+%uint64 = OpTypeInt 64 0
+%ptr = OpTypePointer PhysicalStorageBufferEXT %uint64
+%val1 = OpVariable %ptr PhysicalStorageBufferEXT
+%void = OpTypeVoid
+%voidfn = OpTypeFunction %void
+%main = OpFunction %void None %voidfn
+%entry = OpLabel
+OpReturn
+OpFunctionEnd
+)";
+
+ CompileSuccessfully(body.c_str());
+ ASSERT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions());
+ EXPECT_THAT(
+ getDiagnosticString(),
+ HasSubstr("PhysicalStorageBufferEXT must not be used with OpVariable"));
+}
+
} // namespace
} // namespace val
} // namespace spvtools