Preserve float values during encoding and decoding roundtrip.

This commit is contained in:
Lei Zhang 2015-09-09 10:36:48 -04:00 committed by David Neto
parent cfeac48a37
commit 610c525865
5 changed files with 116 additions and 26 deletions

View File

@ -96,6 +96,7 @@ include_directories(
set(SPIRV_SOURCES
${CMAKE_CURRENT_SOURCE_DIR}/include/libspirv/libspirv.h
${CMAKE_CURRENT_SOURCE_DIR}/include/utils/bitwisecast.h
${CMAKE_CURRENT_SOURCE_DIR}/source/binary.h
${CMAKE_CURRENT_SOURCE_DIR}/source/diagnostic.h
${CMAKE_CURRENT_SOURCE_DIR}/source/opcode.h

View File

@ -0,0 +1,41 @@
// Copyright (c) 2015 The Khronos Group Inc.
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and/or associated documentation files (the
// "Materials"), to deal in the Materials without restriction, including
// without limitation the rights to use, copy, modify, merge, publish,
// distribute, sublicense, and/or sell copies of the Materials, and to
// permit persons to whom the Materials are furnished to do so, subject to
// the following conditions:
//
// The above copyright notice and this permission notice shall be included
// in all copies or substantial portions of the Materials.
//
// MODIFICATIONS TO THIS FILE MAY MEAN IT NO LONGER ACCURATELY REFLECTS
// KHRONOS STANDARDS. THE UNMODIFIED, NORMATIVE VERSIONS OF KHRONOS
// SPECIFICATIONS AND HEADER INFORMATION ARE LOCATED AT
// https://www.khronos.org/registry/
//
// THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
// MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS.
#include <cstring>
namespace spvutils {
// Performs a bitwise copy of source to the destination type Dest.
template <typename Dest, typename Src>
Dest BitwiseCast(Src source) {
Dest dest;
static_assert(sizeof(source) == sizeof(dest),
"BitwiseCast: Source and destination must have the same size");
std::memcpy(&dest, &source, sizeof(dest));
return dest;
}
} // namespace spvutils

View File

@ -25,6 +25,8 @@
// MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS.
#include <libspirv/libspirv.h>
#include <utils/bitwisecast.h>
#include "binary.h"
#include "diagnostic.h"
#include "ext_inst.h"
@ -41,6 +43,8 @@
#include <vector>
#include <unordered_map>
using spvutils::BitwiseCast;
// Structures
struct spv_named_id_table_t {
@ -434,13 +438,13 @@ spv_result_t spvTextEncodeOperand(
return SPV_ERROR_INVALID_TEXT);
switch (literal.type) {
case SPV_LITERAL_TYPE_INT_32:
spvCheck(spvBinaryEncodeU32((uint32_t)literal.value.i32, pInst,
position, pDiagnostic),
spvCheck(spvBinaryEncodeU32(BitwiseCast<uint32_t>(literal.value.i32),
pInst, position, pDiagnostic),
return SPV_ERROR_INVALID_TEXT);
break;
case SPV_LITERAL_TYPE_INT_64: {
spvCheck(spvBinaryEncodeU64((uint64_t)literal.value.i64, pInst,
position, pDiagnostic),
spvCheck(spvBinaryEncodeU64(BitwiseCast<uint64_t>(literal.value.i64),
pInst, position, pDiagnostic),
return SPV_ERROR_INVALID_TEXT);
} break;
case SPV_LITERAL_TYPE_UINT_32: {
@ -449,18 +453,18 @@ spv_result_t spvTextEncodeOperand(
return SPV_ERROR_INVALID_TEXT);
} break;
case SPV_LITERAL_TYPE_UINT_64: {
spvCheck(spvBinaryEncodeU64((uint64_t)literal.value.u64, pInst,
position, pDiagnostic),
spvCheck(spvBinaryEncodeU64(BitwiseCast<uint64_t>(literal.value.u64),
pInst, position, pDiagnostic),
return SPV_ERROR_INVALID_TEXT);
} break;
case SPV_LITERAL_TYPE_FLOAT_32: {
spvCheck(spvBinaryEncodeU32((uint32_t)literal.value.f, pInst,
position, pDiagnostic),
spvCheck(spvBinaryEncodeU32(BitwiseCast<uint32_t>(literal.value.f),
pInst, position, pDiagnostic),
return SPV_ERROR_INVALID_TEXT);
} break;
case SPV_LITERAL_TYPE_FLOAT_64: {
spvCheck(spvBinaryEncodeU64((uint64_t)literal.value.d, pInst,
position, pDiagnostic),
spvCheck(spvBinaryEncodeU64(BitwiseCast<uint64_t>(literal.value.d),
pInst, position, pDiagnostic),
return SPV_ERROR_INVALID_TEXT);
} break;
case SPV_LITERAL_TYPE_STRING: {

View File

@ -93,6 +93,35 @@ class TextToBinaryTestBase : public T {
return diagnostic->error;
}
// Encodes SPIR-V text into binary and then decodes the binary. Returns the
// decoded text.
std::string EncodeAndDecodeSuccessfully(const std::string& text_string) {
SetText(text_string);
DestroyBinary();
spv_result_t error = spvTextToBinary(&text, opcodeTable, operandTable,
extInstTable, &binary, &diagnostic);
if (error) {
spvDiagnosticPrint(diagnostic);
spvDiagnosticDestroy(diagnostic);
}
EXPECT_EQ(SPV_SUCCESS, error);
spv_text decoded_text;
error =
spvBinaryToText(binary, SPV_BINARY_TO_TEXT_OPTION_NONE, opcodeTable,
operandTable, extInstTable, &decoded_text, &diagnostic);
if (error) {
spvDiagnosticPrint(diagnostic);
spvDiagnosticDestroy(diagnostic);
}
EXPECT_EQ(SPV_SUCCESS, error);
const std::string decoded_string = decoded_text->str;
spvTextDestroy(decoded_text);
return decoded_string;
}
void SetText(const std::string& code) {
textString = code;
text.str = textString.c_str();

View File

@ -24,6 +24,7 @@
// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
// MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS.
#include <utils/bitwisecast.h>
#include "TestFixture.h"
#include "UnitSPIRV.h"
#include <algorithm>
@ -33,6 +34,7 @@
namespace {
using spvutils::BitwiseCast;
using test_fixture::TextToBinaryTest;
union char_word_t {
@ -403,23 +405,36 @@ TEST_F(TextToBinaryTest, BadSwitchTruncatedCase) {
EXPECT_STREQ("Expected operand, found next instruction instead.", diagnostic->error);
}
using TextToBinaryFloatValueTest =
test_fixture::TextToBinaryTestBase<::testing::TestWithParam<float>>;
using TextToBinaryFloatValueTest = test_fixture::TextToBinaryTestBase<
::testing::TestWithParam<std::pair<std::string, uint32_t>>>;
// TODO(dneto): Fix float parsing.
TEST_P(TextToBinaryFloatValueTest, DISABLED_NormalValues) {
std::stringstream input;
input <<
R"(OpTypeFloat %float 32
%constval = OpConstant %float )"
<< GetParam();
const SpirvVector code = CompileSuccessfully(input.str());
EXPECT_EQ(code[6], GetParam());
TEST_P(TextToBinaryFloatValueTest, NormalValues) {
const std::string assembly = "%1 = OpTypeFloat 32\n%2 = OpConstant %1 ";
const std::string input_string = assembly + GetParam().first;
const std::string expected_string =
"; SPIR-V\n; Version: 99\n; Generator: Khronos\n; "
"Bound: 3\n; Schema: 0\n" +
assembly + std::to_string(GetParam().second) + "\n";
const std::string decoded_string = EncodeAndDecodeSuccessfully(input_string);
EXPECT_EQ(expected_string, decoded_string);
}
INSTANTIATE_TEST_CASE_P(float, TextToBinaryFloatValueTest,
::testing::ValuesIn(std::vector<float>{1.5, 0.0,
-2.5}));
INSTANTIATE_TEST_CASE_P(
FloatValues, TextToBinaryFloatValueTest,
::testing::ValuesIn(std::vector<std::pair<std::string, uint32_t>>{
{"0.0", 0x00000000}, // +0
{"!0x00000001", 0x00000001}, // +denorm
{"!0x00800000", 0x00800000}, // +norm
{"1.5", 0x3fc00000},
{"!0x7f800000", 0x7f800000}, // +inf
{"!0x7f800001", 0x7f800001}, // NaN
{"-0.0", 0x80000000}, // -0
{"!0x80000001", 0x80000001}, // -denorm
{"!0x80800000", 0x80800000}, // -norm
{"-2.5", 0xc0200000},
{"!0xff800000", 0xff800000}, // -inf
{"!0xff800001", 0xff800001}, // NaN
}));
} // anonymous namespace