[spirv] Legalization: validate with relaxed logical pointer (#975)

We still want to make sure that the generated raw SPIR-V does not
have other validation errors except for allocating variables
containing pointers and returning pointers.
This commit is contained in:
Lei Zhang 2018-01-08 14:08:48 -05:00 коммит произвёл GitHub
Родитель 415e190a8b
Коммит 02bc6fae08
Не найден ключ, соответствующий данной подписи
Идентификатор ключа GPG: 4AEE18F83AFDEB23
10 изменённых файлов: 55 добавлений и 45 удалений

2
external/SPIRV-Tools поставляемый

@ -1 +1 @@
Subproject commit 3fbbd3c772c53930417b4cc7db949c6e52b6b2a2
Subproject commit a82a0ea886f59f1987f339b05cca71cc248adc78

Просмотреть файл

@ -249,7 +249,8 @@ bool spirvToolsOptimize(std::vector<uint32_t> *module, std::string *messages) {
return optimizer.Run(module->data(), module->size(), module);
}
bool spirvToolsValidate(std::vector<uint32_t> *module, std::string *messages) {
bool spirvToolsValidate(std::vector<uint32_t> *module, std::string *messages,
bool relaxLogicalPointer) {
spvtools::SpirvTools tools(SPV_ENV_VULKAN_1_0);
tools.SetMessageConsumer(
@ -257,7 +258,10 @@ bool spirvToolsValidate(std::vector<uint32_t> *module, std::string *messages) {
const spv_position_t & /*position*/,
const char *message) { *messages += message; });
return tools.Validate(module->data(), module->size());
spvtools::ValidatorOptions options;
options.SetRelaxLogicalPointer(relaxLogicalPointer);
return tools.Validate(module->data(), module->size(), options);
}
/// Translates atomic HLSL opcodes into the equivalent SPIR-V opcode.
@ -395,8 +399,8 @@ SPIRVEmitter::SPIRVEmitter(CompilerInstance &ci,
seenPushConstantAt(), needsLegalization(false) {
if (shaderModel.GetKind() == hlsl::ShaderModel::Kind::Invalid)
emitError("unknown shader module: %0", {}) << shaderModel.GetName();
if (options.invertY &&
!(shaderModel.IsVS() || shaderModel.IsDS() || shaderModel.IsGS()))
if (options.invertY && !shaderModel.IsVS() && !shaderModel.IsDS() &&
!shaderModel.IsGS())
emitError("-fvk-invert-y can only be used in VS/DS/GS", {});
}
@ -488,7 +492,8 @@ void SPIRVEmitter::HandleTranslationUnit(ASTContext &context) {
// Validate the generated SPIR-V code
if (!spirvOptions.disableValidation) {
std::string messages;
if (!spirvToolsValidate(&m, &messages)) {
if (!spirvToolsValidate(&m, &messages,
declIdMapper.requiresLegalization())) {
emitFatalError("generated SPIR-V is invalid: %0", {}) << messages;
emitNote("please file a bug report on "
"https://github.com/Microsoft/DirectXShaderCompiler/issues "

Просмотреть файл

@ -131,15 +131,15 @@ float4 main() : SV_Target {
// CHECK: [[ptr1:%\d+]] = OpLoad %_ptr_Uniform_type_RWByteAddressBuffer %localRWBABuffer
// CHECK: [[ptr2:%\d+]] = OpAccessChain %_ptr_Uniform_uint [[ptr1]] %uint_0 {{%\d+}}
// CHECK-NEXT: OpStore [[ptr2]] {{%\d+}}
localRWBABuffer.Store(13, byte2);
localRWBABuffer.Store2(13, byte2);
// CHECK: [[ptr1:%\d+]] = OpLoad %_ptr_Uniform_type_RWByteAddressBuffer %localRWBABuffer
// CHECK: [[ptr2:%\d+]] = OpAccessChain %_ptr_Uniform_uint [[ptr1]] %uint_0 {{%\d+}}
// CHECK-NEXT: OpStore [[ptr2]] {{%\d+}}
localRWBABuffer.Store(14, byte3);
localRWBABuffer.Store3(14, byte3);
// CHECK: [[ptr1:%\d+]] = OpLoad %_ptr_Uniform_type_RWByteAddressBuffer %localRWBABuffer
// CHECK: [[ptr2:%\d+]] = OpAccessChain %_ptr_Uniform_uint [[ptr1]] %uint_0 {{%\d+}}
// CHECK-NEXT: OpStore [[ptr2]] {{%\d+}}
localRWBABuffer.Store(15, byte4);
localRWBABuffer.Store4(15, byte4);
// CHECK: [[ptr1:%\d+]] = OpLoad %_ptr_Uniform_type_RWByteAddressBuffer %localRWBABuffer
// CHECK: [[ptr2:%\d+]] = OpAccessChain %_ptr_Uniform_uint [[ptr1]] %uint_0 {{%\d+}}
localRWBABuffer.InterlockedAdd(dest, value, origin);

Просмотреть файл

@ -52,7 +52,8 @@ float4 main(in float4 pos : SV_Position) : SV_Target
S buffer3;
buffer3 = retStuff();
// The underlying struct type has the same layout. Can write out as a whole.
// TODO: The underlying struct type has the same layout but %type_TextureBuffer_S
// has an additional BufferBlock decoration. So this causes an validation error.
// CHECK: [[ptr:%\d+]] = OpAccessChain %_ptr_Uniform_S %myASBuffer %uint_0 {{%\d+}}
// CHECK-NEXT: [[val:%\d+]] = OpLoad %type_TextureBuffer_S %myTBuffer
// CHECK-NEXT: OpStore [[ptr]] [[val]]

Просмотреть файл

@ -49,7 +49,7 @@ TEST_F(FileTest, MatrixTypesMajornessZpr) {
runFileTest("type.matrix.majorness.zpr.hlsl");
}
TEST_F(FileTest, MatrixTypesMajorness) {
runFileTest("type.matrix.majorness.hlsl", FileTest::Expect::Warning);
runFileTest("type.matrix.majorness.hlsl", Expect::Warning);
}
TEST_F(FileTest, StructTypes) { runFileTest("type.struct.hlsl"); }
TEST_F(FileTest, ClassTypes) { runFileTest("type.class.hlsl"); }
@ -90,7 +90,7 @@ TEST_F(FileTest, 16BitDisabledScalarConstants) {
}
TEST_F(FileTest, 16BitEnabledScalarConstants) {
// TODO: Fix spirv-val to make sure it respects the 16-bit extension.
runFileTest("constant.scalar.16bit.enabled.hlsl", FileTest::Expect::Success,
runFileTest("constant.scalar.16bit.enabled.hlsl", Expect::Success,
/*runValidation*/ false);
}
TEST_F(FileTest, 64BitScalarConstants) {
@ -110,10 +110,10 @@ TEST_F(FileTest, VarInitMatrix1x1) { runFileTest("var.init.matrix.1x1.hlsl"); }
TEST_F(FileTest, VarInitStruct) { runFileTest("var.init.struct.hlsl"); }
TEST_F(FileTest, VarInitArray) { runFileTest("var.init.array.hlsl"); }
TEST_F(FileTest, VarInitCbuffer) {
runFileTest("var.init.cbuffer.hlsl", FileTest::Expect::Warning);
runFileTest("var.init.cbuffer.hlsl", Expect::Warning);
}
TEST_F(FileTest, VarInitTbuffer) {
runFileTest("var.init.tbuffer.hlsl", FileTest::Expect::Warning);
runFileTest("var.init.tbuffer.hlsl", Expect::Warning);
}
TEST_F(FileTest, VarInitOpaque) { runFileTest("var.init.opaque.hlsl"); }
TEST_F(FileTest, VarInitCrossStorageClass) {
@ -563,7 +563,7 @@ TEST_F(FileTest, SemanticArbitraryAlphaLocation) {
runFileTest("semantic.arbitrary.location.alpha.hlsl");
}
TEST_F(FileTest, SemanticDuplication) {
runFileTest("semantic.duplication.hlsl", FileTest::Expect::Failure);
runFileTest("semantic.duplication.hlsl", Expect::Failure);
}
TEST_F(FileTest, SemanticOnStruct) { runFileTest("semantic.on-struct.hlsl"); }
@ -931,7 +931,7 @@ TEST_F(FileTest, PrimitiveTriangleAdjGS) {
runFileTest("primitive.triangleadj.gs.hlsl");
}
TEST_F(FileTest, PrimitiveErrorGS) {
runFileTest("primitive.error.gs.hlsl", FileTest::Expect::Failure);
runFileTest("primitive.error.gs.hlsl", Expect::Failure);
}
// SPIR-V specific
@ -980,48 +980,43 @@ TEST_F(FileTest, SpirvInterpolation) {
runFileTest("spirv.interpolation.hlsl");
}
TEST_F(FileTest, SpirvInterpolationError) {
runFileTest("spirv.interpolation.error.hlsl", FileTest::Expect::Failure);
runFileTest("spirv.interpolation.error.hlsl", Expect::Failure);
}
TEST_F(FileTest, SpirvLegalizationOpaqueStruct) {
runFileTest("spirv.legal.opaque-struct.hlsl", Expect::Success,
// The generated SPIR-V needs legalization.
/*runValidation=*/false);
/*runValidation=*/true, /*relaxLogicalPointer=*/true);
}
TEST_F(FileTest, SpirvLegalizationStructuredBufferUsage) {
runFileTest("spirv.legal.sbuffer.usage.hlsl", Expect::Success,
// The generated SPIR-V needs legalization.
/*runValidation=*/false);
/*runValidation=*/true, /*relaxLogicalPointer=*/true);
}
TEST_F(FileTest, SpirvLegalizationStructuredBufferMethods) {
runFileTest("spirv.legal.sbuffer.methods.hlsl", Expect::Success,
// The generated SPIR-V needs legalization.
/*runValidation=*/false);
/*runValidation=*/true, /*relaxLogicalPointer=*/true);
}
TEST_F(FileTest, SpirvLegalizationStructuredBufferCounter) {
runFileTest("spirv.legal.sbuffer.counter.hlsl", Expect::Success,
// The generated SPIR-V needs legalization.
/*runValidation=*/false);
/*runValidation=*/true, /*relaxLogicalPointer=*/true);
}
TEST_F(FileTest, SpirvLegalizationStructuredBufferInStruct) {
runFileTest("spirv.legal.sbuffer.struct.hlsl", Expect::Success,
// The generated SPIR-V needs legalization.
/*runValidation=*/false);
/*runValidation=*/true, /*relaxLogicalPointer=*/true);
}
TEST_F(FileTest, SpirvLegalizationConstantBuffer) {
runFileTest("spirv.legal.cbuffer.hlsl");
}
TEST_F(FileTest, SpirvLegalizationTextureBuffer) {
runFileTest("spirv.legal.tbuffer.hlsl", Expect::Success,
// The generated SPIR-V needs legalization.
// TODO: fix the different type error for OpStore
/*runValidation=*/false);
}
TEST_F(FileTest, VulkanAttributeErrors) {
runFileTest("vk.attribute.error.hlsl", FileTest::Expect::Failure);
runFileTest("vk.attribute.error.hlsl", Expect::Failure);
}
TEST_F(FileTest, VulkanAttributeInvalidUsages) {
runFileTest("vk.attribute.invalid.hlsl", FileTest::Expect::Failure);
runFileTest("vk.attribute.invalid.hlsl", Expect::Failure);
}
TEST_F(FileTest, VulkanCLOptionIgnoreUnusedResources) {
@ -1047,13 +1042,13 @@ TEST_F(FileTest, VulkanLocationInputImplicitOutputExplicit) {
runFileTest("vk.location.exp-out.hlsl");
}
TEST_F(FileTest, VulkanLocationTooLarge) {
runFileTest("vk.location.large.hlsl", FileTest::Expect::Failure);
runFileTest("vk.location.large.hlsl", Expect::Failure);
}
TEST_F(FileTest, VulkanLocationReassigned) {
runFileTest("vk.location.reassign.hlsl", FileTest::Expect::Failure);
runFileTest("vk.location.reassign.hlsl", Expect::Failure);
}
TEST_F(FileTest, VulkanLocationPartiallyAssigned) {
runFileTest("vk.location.mixed.hlsl", FileTest::Expect::Failure);
runFileTest("vk.location.mixed.hlsl", Expect::Failure);
}
TEST_F(FileTest, VulkanExplicitBinding) {
@ -1074,13 +1069,13 @@ TEST_F(FileTest, VulkanRegisterBindingShift) {
runFileTest("vk.binding.cl.hlsl");
}
TEST_F(FileTest, VulkanExplicitBindingReassigned) {
runFileTest("vk.binding.explicit.error.hlsl", FileTest::Expect::Warning);
runFileTest("vk.binding.explicit.error.hlsl", Expect::Warning);
}
TEST_F(FileTest, VulkanRegisterBindingReassigned) {
runFileTest("vk.binding.register.error.hlsl", FileTest::Expect::Warning);
runFileTest("vk.binding.register.error.hlsl", Expect::Warning);
}
TEST_F(FileTest, VulkanRegisterBindingShiftReassigned) {
runFileTest("vk.binding.cl.error.hlsl", FileTest::Expect::Warning);
runFileTest("vk.binding.cl.error.hlsl", Expect::Warning);
}
TEST_F(FileTest, VulkanStructuredBufferCounter) {
// [[vk::counter_binding()]] for RWStructuredBuffer, AppendStructuredBuffer,
@ -1093,7 +1088,7 @@ TEST_F(FileTest, VulkanPushConstantOffset) {
runFileTest("vk.push-constant.offset.hlsl");
}
TEST_F(FileTest, VulkanMultiplePushConstant) {
runFileTest("vk.push-constant.multiple.hlsl", FileTest::Expect::Failure);
runFileTest("vk.push-constant.multiple.hlsl", Expect::Failure);
}
TEST_F(FileTest, VulkanLayoutCBufferStd140) {

Просмотреть файл

@ -61,7 +61,10 @@ bool FileTest::parseInputFile() {
}
void FileTest::runFileTest(llvm::StringRef filename, Expect expect,
bool runValidation) {
bool runValidation, bool relaxLogicalPointer) {
if (relaxLogicalPointer)
assert(runValidation);
inputFilePath = utils::getAbsPathOfInputDataFile(filename);
// Parse the input file.
@ -125,7 +128,8 @@ void FileTest::runFileTest(llvm::StringRef filename, Expect expect,
// Run SPIR-V validation for successful compilations
if (runValidation && expect != Expect::Failure) {
EXPECT_TRUE(utils::validateSpirvBinary(generatedBinary));
EXPECT_TRUE(
utils::validateSpirvBinary(generatedBinary, relaxLogicalPointer));
}
}

Просмотреть файл

@ -27,7 +27,7 @@ public:
/// \brief Runs a File Test! (See class description for more info)
void runFileTest(llvm::StringRef path, Expect expect = Expect::Success,
bool runValidation = true);
bool runValidation = true, bool relaxLogicalPointer = false);
private:
/// \brief Reads in the given input file.

Просмотреть файл

@ -32,12 +32,15 @@ bool disassembleSpirvBinary(std::vector<uint32_t> &binary,
return spirvTools.Disassemble(binary, generatedSpirvAsm, options);
}
bool validateSpirvBinary(std::vector<uint32_t> &binary) {
bool validateSpirvBinary(std::vector<uint32_t> &binary,
bool relaxLogicalPointer) {
spvtools::ValidatorOptions options;
options.SetRelaxLogicalPointer(relaxLogicalPointer);
spvtools::SpirvTools spirvTools(SPV_ENV_VULKAN_1_0);
spirvTools.SetMessageConsumer(
[](spv_message_level_t, const char *, const spv_position_t &,
const char *message) { fprintf(stdout, "%s\n", message); });
return spirvTools.Validate(binary);
return spirvTools.Validate(binary.data(), binary.size(), options);
}
bool processRunCommandArgs(const llvm::StringRef runCommandLine,

Просмотреть файл

@ -32,7 +32,8 @@ bool disassembleSpirvBinary(std::vector<uint32_t> &binary,
/// \brief Runs the SPIR-V Tools validation on the given SPIR-V binary.
/// Returns true if validation is successful; false otherwise.
bool validateSpirvBinary(std::vector<uint32_t> &binary);
bool validateSpirvBinary(std::vector<uint32_t> &binary,
bool relaxLogicalPointer);
/// \brief Parses the Target Profile and Entry Point from the Run command
/// Returns the target profile, entry point, and the rest via arguments.

Просмотреть файл

@ -107,7 +107,8 @@ void WholeFileTest::runWholeFileTest(llvm::StringRef filename,
// Run SPIR-V validation if requested.
if (runSpirvValidation) {
EXPECT_TRUE(utils::validateSpirvBinary(generatedBinary));
EXPECT_TRUE(utils::validateSpirvBinary(generatedBinary,
/*relaxLogicalPointer=*/false));
}
}