From 4f750c0dcc50055a5314857e299e252570c81998 Mon Sep 17 00:00:00 2001 From: David Neto Date: Thu, 13 Oct 2016 15:17:11 -0400 Subject: [PATCH] Extract EmitNumericLiteral from disassembler Test with disassembly of numeric literals. --- source/CMakeLists.txt | 2 + source/disassemble.cpp | 45 ++-------------------- source/parsed_operand.cpp | 75 ++++++++++++++++++++++++++++++++++++ source/parsed_operand.h | 32 +++++++++++++++ test/binary_to_text_test.cpp | 33 ++++++++++++++++ 5 files changed, 145 insertions(+), 42 deletions(-) create mode 100644 source/parsed_operand.cpp create mode 100644 source/parsed_operand.h diff --git a/source/CMakeLists.txt b/source/CMakeLists.txt index 0c6ff93da..78202d3a7 100644 --- a/source/CMakeLists.txt +++ b/source/CMakeLists.txt @@ -126,6 +126,7 @@ set(SPIRV_SOURCES ${CMAKE_CURRENT_SOURCE_DIR}/name_mapper.h ${CMAKE_CURRENT_SOURCE_DIR}/opcode.h ${CMAKE_CURRENT_SOURCE_DIR}/operand.h + ${CMAKE_CURRENT_SOURCE_DIR}/parsed_operand.h ${CMAKE_CURRENT_SOURCE_DIR}/print.h ${CMAKE_CURRENT_SOURCE_DIR}/spirv_constant.h ${CMAKE_CURRENT_SOURCE_DIR}/spirv_definition.h @@ -147,6 +148,7 @@ set(SPIRV_SOURCES ${CMAKE_CURRENT_SOURCE_DIR}/name_mapper.cpp ${CMAKE_CURRENT_SOURCE_DIR}/opcode.cpp ${CMAKE_CURRENT_SOURCE_DIR}/operand.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/parsed_operand.cpp ${CMAKE_CURRENT_SOURCE_DIR}/print.cpp ${CMAKE_CURRENT_SOURCE_DIR}/software_version.cpp ${CMAKE_CURRENT_SOURCE_DIR}/spirv_endian.cpp diff --git a/source/disassemble.cpp b/source/disassemble.cpp index 267ed1724..cbec78adc 100644 --- a/source/disassemble.cpp +++ b/source/disassemble.cpp @@ -28,6 +28,7 @@ #include "ext_inst.h" #include "name_mapper.h" #include "opcode.h" +#include "parsed_operand.h" #include "print.h" #include "spirv-tools/libspirv.h" #include "spirv_constant.h" @@ -229,48 +230,8 @@ void Disassembler::EmitOperand(const spv_parsed_instruction_t& inst, case SPV_OPERAND_TYPE_LITERAL_INTEGER: case SPV_OPERAND_TYPE_TYPED_LITERAL_NUMBER: { SetRed(); - if (operand.num_words == 1) { - switch (operand.number_kind) { - case SPV_NUMBER_SIGNED_INT: - stream_ << int32_t(word); - break; - case SPV_NUMBER_UNSIGNED_INT: - stream_ << word; - break; - case SPV_NUMBER_FLOATING: - if (operand.number_bit_width == 16) { - stream_ << spvutils::FloatProxy( - uint16_t(word & 0xFFFF)); - } else { - // Assume 32-bit floats. - stream_ << spvutils::FloatProxy(word); - } - break; - default: - assert(false && "Unreachable"); - } - } else if (operand.num_words == 2) { - // Multi-word numbers are presented with lower order words first. - uint64_t bits = - uint64_t(word) | (uint64_t(inst.words[operand.offset + 1]) << 32); - switch (operand.number_kind) { - case SPV_NUMBER_SIGNED_INT: - stream_ << int64_t(bits); - break; - case SPV_NUMBER_UNSIGNED_INT: - stream_ << bits; - break; - case SPV_NUMBER_FLOATING: - // Assume only 64-bit floats. - stream_ << spvutils::FloatProxy(bits); - break; - default: - assert(false && "Unreachable"); - } - } else { - // TODO(dneto): Support more than 64-bits at a time. - assert(false && "Unhandled"); - } + libspirv::EmitNumericLiteral(&stream_, inst, operand); + ResetColor(); } break; case SPV_OPERAND_TYPE_LITERAL_STRING: { stream_ << "\""; diff --git a/source/parsed_operand.cpp b/source/parsed_operand.cpp new file mode 100644 index 000000000..6f3ffe8d5 --- /dev/null +++ b/source/parsed_operand.cpp @@ -0,0 +1,75 @@ +// Copyright (c) 2016 Google Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// This file contains utility functions for spv_parsed_operand_t. + +#include "parsed_operand.h" + +#include +#include "util/hex_float.h" + +namespace libspirv { + +void EmitNumericLiteral(std::ostream* out, const spv_parsed_instruction_t& inst, + const spv_parsed_operand_t& operand) { + assert(operand.type == SPV_OPERAND_TYPE_LITERAL_INTEGER || + operand.type == SPV_OPERAND_TYPE_TYPED_LITERAL_NUMBER); + assert(1 <= operand.num_words); + assert(operand.num_words <= 2); + + const uint32_t word = inst.words[operand.offset]; + if (operand.num_words == 1) { + switch (operand.number_kind) { + case SPV_NUMBER_SIGNED_INT: + *out << int32_t(word); + break; + case SPV_NUMBER_UNSIGNED_INT: + *out << word; + break; + case SPV_NUMBER_FLOATING: + if (operand.number_bit_width == 16) { + *out << spvutils::FloatProxy( + uint16_t(word & 0xFFFF)); + } else { + // Assume 32-bit floats. + *out << spvutils::FloatProxy(word); + } + break; + default: + assert(false && "Unreachable"); + } + } else if (operand.num_words == 2) { + // Multi-word numbers are presented with lower order words first. + uint64_t bits = + uint64_t(word) | (uint64_t(inst.words[operand.offset + 1]) << 32); + switch (operand.number_kind) { + case SPV_NUMBER_SIGNED_INT: + *out << int64_t(bits); + break; + case SPV_NUMBER_UNSIGNED_INT: + *out << bits; + break; + case SPV_NUMBER_FLOATING: + // Assume only 64-bit floats. + *out << spvutils::FloatProxy(bits); + break; + default: + assert(false && "Unreachable"); + } + } else { + // TODO(dneto): Support more than 64-bits at a time. + assert(false && "Unhandled"); + } +} +} // namespace libspirv diff --git a/source/parsed_operand.h b/source/parsed_operand.h new file mode 100644 index 000000000..8c2fd85ce --- /dev/null +++ b/source/parsed_operand.h @@ -0,0 +1,32 @@ +// Copyright (c) 2016 Google Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#ifndef LIBSPIRV_PARSED_OPERAND_H_ +#define LIBSPIRV_PARSED_OPERAND_H_ + +#include +#include "spirv-tools/libspirv.h" + +namespace libspirv { + +// Emits the numeric literal representation of the given instruction operand +// to the stream. The operand must be of numeric type. If integral it may +// be up to 64 bits wide. If floating point, then it must be 16, 32, or 64 +// bits wide. +void EmitNumericLiteral(std::ostream* out, const spv_parsed_instruction_t& inst, + const spv_parsed_operand_t& operand); + +} // namespace libspirv + +#endif // LIBSPIRV_BINARY_H_ diff --git a/test/binary_to_text_test.cpp b/test/binary_to_text_test.cpp index 78f9aff28..9b97b3d30 100644 --- a/test/binary_to_text_test.cpp +++ b/test/binary_to_text_test.cpp @@ -235,6 +235,39 @@ TEST_P(RoundTripInstructionsTest, Sample) { Eq(get<1>(GetParam()))); } +INSTANTIATE_TEST_CASE_P( + NumericLiterals, RoundTripInstructionsTest, + // This test is independent of environment, so just test the one. + Combine(::testing::Values(SPV_ENV_UNIVERSAL_1_0), + ::testing::ValuesIn(std::vector{ + "%1 = OpTypeInt 12 0\n%2 = OpConstant %1 1867\n", + "%1 = OpTypeInt 12 1\n%2 = OpConstant %1 1867\n", + "%1 = OpTypeInt 12 1\n%2 = OpConstant %1 -1867\n", + "%1 = OpTypeInt 32 0\n%2 = OpConstant %1 1867\n", + "%1 = OpTypeInt 32 1\n%2 = OpConstant %1 1867\n", + "%1 = OpTypeInt 32 1\n%2 = OpConstant %1 -1867\n", + "%1 = OpTypeInt 64 0\n%2 = OpConstant %1 18446744073709551615\n", + "%1 = OpTypeInt 64 1\n%2 = OpConstant %1 9223372036854775807\n", + "%1 = OpTypeInt 64 1\n%2 = OpConstant %1 -9223372036854775808\n", + // 16-bit floats print as hex floats. + "%1 = OpTypeFloat 16\n%2 = OpConstant %1 0x1.ff4p+16\n", + "%1 = OpTypeFloat 16\n%2 = OpConstant %1 -0x1.d2cp-10\n", + // 32-bit floats + "%1 = OpTypeFloat 32\n%2 = OpConstant %1 -3.275\n", + "%1 = OpTypeFloat 32\n%2 = OpConstant %1 0x1.8p+128\n", // NaN + "%1 = OpTypeFloat 32\n%2 = OpConstant %1 -0x1.0002p+128\n", // NaN + "%1 = OpTypeFloat 32\n%2 = OpConstant %1 0x1p+128\n", // Inf + "%1 = OpTypeFloat 32\n%2 = OpConstant %1 -0x1p+128\n", // -Inf + // 64-bit floats + "%1 = OpTypeFloat 64\n%2 = OpConstant %1 -3.275\n", + "%1 = OpTypeFloat 64\n%2 = OpConstant %1 0x1.ffffffffffffap-1023\n", // small normal + "%1 = OpTypeFloat 64\n%2 = OpConstant %1 -0x1.ffffffffffffap-1023\n", + "%1 = OpTypeFloat 64\n%2 = OpConstant %1 0x1.8p+1024\n", // NaN + "%1 = OpTypeFloat 64\n%2 = OpConstant %1 -0x1.0002p+1024\n", // NaN + "%1 = OpTypeFloat 64\n%2 = OpConstant %1 0x1p+1024\n", // Inf + "%1 = OpTypeFloat 64\n%2 = OpConstant %1 -0x1p+1024\n", // -Inf + })), ); + INSTANTIATE_TEST_CASE_P( MemoryAccessMasks, RoundTripInstructionsTest, Combine(::testing::Values(SPV_ENV_UNIVERSAL_1_0, SPV_ENV_UNIVERSAL_1_1),